/** @file tgpio.c @date 2010/1/4 @author 오재경 freefrug@falinux.com FALinux.Co.,Ltd. @brief gpio 를 드라이버없이 mmap를 이용하여 제어한다. Ver 0.6.0 am3874 포함, GP0테스트 완료 Ver 0.5.0 s5pv210 포함, 테스트 완료 pull-up, pull-dn 설정변경 Ver 0.4.0 tmmap.c 를 사용하지 않고 famap.c 를 사용하는것으로 수정 Ver 0.3.0 ixp420 테스트 완료 Ver 0.2.1 s3c6410, pxa270 테스트 완료 Ver 0.2.0 pxa270 완료 pxa255 완료(테스트 안됨) Ver 0.1.0 s3c6410 완료 s3c2440 완료(테스트 안됨) @modify @todo 다음과 같은 MCU 들도 지원하여야 한다. .. @bug @remark @warning */ //---------------------------------------------------------------------------- #include #include #include #include #include #include #include #include #include #include #include #include static const char desc[] = "tgpio ver 0.7.0"; /// am3874 gpio 관리 static am3x_gpio_register_t am3874_gpio_register[MCU_AM3874_GPIO_GRP_CNT] = { [0] = { .phys = MCU_AM3874_GPIO0_PHYS, // 0 5 .pin_ctrl = { 2,8,9,10,11, 12,13,0,15,16, 156,157,158,159,160, 161,162,163,164,165, 166,167,52,53,54, 55,56,57,58,59, 60,61 }, }, [1] = { .phys = MCU_AM3874_GPIO1_PHYS, .pin_ctrl = { 68,69,74,75,76, 77,80,62,63,64, 65,140,141,0,0, 121,85,86,87,113, 114,115,116,0,0, 0,88,0,0,0, 0,0 }, }, [2] = { .phys = MCU_AM3874_GPIO2_PHYS, .pin_ctrl = { 135,136,137,138,139, 0,0,142,143,144, 145,146,147,148,149, 150,151,152,153,154, 155,179,180,181,188, 189,196,197,204,205, 206,207 }, }, [3] = { .phys = MCU_AM3874_GPIO3_PHYS, .pin_ctrl = { 208,209,210,211,212, 213,214,215,216,217, 218,219,220,221,222, 223,224,225,226,227, 0,0,0,0,0, 0,0,0,0,0, 0,0 }, }, }; /// s5pv210 gpio 그룹 인덱스 static int s5pv210_reg_idx_table[] = { // A B C D E F G H I J 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, // GPA0 ... GPJ0 10, -1, 11, 12, 13, 14, 17, 20, -1, 23, // GPA1 ... GPJ1 -1, -1, -1, -1, -1, 15, 18, 21, -1, 24, // GPA2 ... GPJ2 -1, -1, -1, -1, -1, 16, 19, 22, -1, 25, // GPA3 ... GPJ3 -1, -1, -1, -1, -1, -1, -1, -1, -1, 26 // GPA4 ... GPJ4 }; /// s5pv210 gpio 레지스터 어프셋과 정보 static s3c_gpio_register_t s5pv210_gpio_register[27] = { [0] = {/* GPA0 */ .gpcnt = 8, .con_mask_bitcnt = 4, .ofs_con = 0x0, .ofs_dat = 0x4, .ofs_pup = 0x8, }, [10] = {/* GPA1 */ .gpcnt = 4, .con_mask_bitcnt = 4, .ofs_con = 0x20, .ofs_dat = 0x24, .ofs_pup = 0x28, }, [1] = {/* GPB0 */ .gpcnt = 8, .con_mask_bitcnt = 4, .ofs_con = 0x40, .ofs_dat = 0x44, .ofs_pup = 0x48, }, [2] = {/* GPC0 */ .gpcnt = 5, .con_mask_bitcnt = 4, .ofs_con = 0x60, .ofs_dat = 0x64, .ofs_pup = 0x68, }, [11] = {/* GPC1 */ .gpcnt = 5, .con_mask_bitcnt = 4, .ofs_con = 0x80, .ofs_dat = 0x84, .ofs_pup = 0x88, }, [3] = {/* GPD0 */ .gpcnt = 4, .con_mask_bitcnt = 4, .ofs_con = 0xa0, .ofs_dat = 0xa4, .ofs_pup = 0xa8, }, [12] = {/* GPD1 */ .gpcnt = 6, .con_mask_bitcnt = 4, .ofs_con = 0xc0, .ofs_dat = 0xc4, .ofs_pup = 0xc8, }, [4] = {/* GPE0 */ .gpcnt = 8, .con_mask_bitcnt = 4, .ofs_con = 0xe0, .ofs_dat = 0xe4, .ofs_pup = 0xe8, }, [13] = {/* GPE1 */ .gpcnt = 5, .con_mask_bitcnt = 4, .ofs_con = 0x100, .ofs_dat = 0x104, .ofs_pup = 0x108, }, [5] = {/* GPF0 */ .gpcnt = 8, .con_mask_bitcnt = 4, .ofs_con = 0x120, .ofs_dat = 0x124, .ofs_pup = 0x128, }, [14] = {/* GPF1 */ .gpcnt = 8, .con_mask_bitcnt = 4, .ofs_con = 0x140, .ofs_dat = 0x144, .ofs_pup = 0x148, }, [15] = {/* GPF2 */ .gpcnt = 8, .con_mask_bitcnt = 4, .ofs_con = 0x160, .ofs_dat = 0x164, .ofs_pup = 0x168, }, [16] = {/* GPF3 */ .gpcnt = 8, .con_mask_bitcnt = 4, .ofs_con = 0x180, .ofs_dat = 0x184, .ofs_pup = 0x188, }, [6] = {/* GPG0 */ .gpcnt = 7, .con_mask_bitcnt = 4, .ofs_con = 0x1a0, .ofs_dat = 0x1a4, .ofs_pup = 0x1a8, }, [17] = {/* GPG1 */ .gpcnt = 7, .con_mask_bitcnt = 4, .ofs_con = 0x1c0, .ofs_dat = 0x1c4, .ofs_pup = 0x1c8, }, [18] = {/* GPG2 */ .gpcnt = 7, .con_mask_bitcnt = 4, .ofs_con = 0x1e0, .ofs_dat = 0x1e4, .ofs_pup = 0x1e8, }, [19] = {/* GPG3 */ .gpcnt = 7, .con_mask_bitcnt = 4, .ofs_con = 0x200, .ofs_dat = 0x204, .ofs_pup = 0x208, }, [7] = {/* GPH0 */ .gpcnt = 8, .con_mask_bitcnt = 4, .ofs_con = 0xc00, .ofs_dat = 0xc04, .ofs_pup = 0xc08, }, [20] = {/* GPH1 */ .gpcnt = 8, .con_mask_bitcnt = 4, .ofs_con = 0xc20, .ofs_dat = 0xc24, .ofs_pup = 0xc28, }, [21] = {/* GPH2 */ .gpcnt = 8, .con_mask_bitcnt = 4, .ofs_con = 0xc40, .ofs_dat = 0xc44, .ofs_pup = 0xc48, }, [22] = {/* GPH3 */ .gpcnt = 8, .con_mask_bitcnt = 4, .ofs_con = 0xc60, .ofs_dat = 0xc64, .ofs_pup = 0xc68, }, [8] = {/* GPI0 */ .gpcnt = 0, .con_mask_bitcnt = 4, .ofs_con = 0x220, .ofs_dat = 0x224, .ofs_pup = 0x228, }, [9] = {/* GPJ0 */ .gpcnt = 8, .con_mask_bitcnt = 4, .ofs_con = 0x240, .ofs_dat = 0x244, .ofs_pup = 0x248, }, [23] = {/* GPJ1 */ .gpcnt = 6, .con_mask_bitcnt = 4, .ofs_con = 0x260, .ofs_dat = 0x264, .ofs_pup = 0x268, }, [24] = {/* GPJ2 */ .gpcnt = 8, .con_mask_bitcnt = 4, .ofs_con = 0x280, .ofs_dat = 0x284, .ofs_pup = 0x288, }, [25] = {/* GPJ3 */ .gpcnt = 8, .con_mask_bitcnt = 4, .ofs_con = 0x2a0, .ofs_dat = 0x2a4, .ofs_pup = 0x2a8, }, [26] = {/* GPJ4 */ .gpcnt = 5, .con_mask_bitcnt = 4, .ofs_con = 0x2c0, .ofs_dat = 0x2c4, .ofs_pup = 0x2c8, }, }; /// s3c6410 레지스터 어프셋과 정보 static s3c_gpio_register_t s3c6410_gpio_register['q'-'a'+1] = { ['a'-'a'] = { .gpcnt = 8, .con_mask_bitcnt = 4, .ofs_con = 0x0, .ofs_dat = 0x4, .ofs_pup = 0x8, }, ['b'-'a'] = { .gpcnt = 7, .con_mask_bitcnt = 4, .ofs_con = 0x20, .ofs_dat = 0x24, .ofs_pup = 0x28, }, ['c'-'a'] = { .gpcnt = 8, .con_mask_bitcnt = 4, .ofs_con = 0x40, .ofs_dat = 0x44, .ofs_pup = 0x48, }, ['d'-'a'] = { .gpcnt = 5, .con_mask_bitcnt = 4, .ofs_con = 0x60, .ofs_dat = 0x64, .ofs_pup = 0x68, }, ['e'-'a'] = { .gpcnt = 5, .con_mask_bitcnt = 4, .ofs_con = 0x80, .ofs_dat = 0x84, .ofs_pup = 0x88, }, ['f'-'a'] = { .gpcnt = 16, .con_mask_bitcnt = 2, .ofs_con = 0xa0, .ofs_dat = 0xa4, .ofs_pup = 0xa8, }, ['g'-'a'] = { .gpcnt = 7, .con_mask_bitcnt = 4, .ofs_con = 0xc0, .ofs_dat = 0xc4, .ofs_pup = 0xc8, }, ['h'-'a'] = { .gpcnt = 10, .con_mask_bitcnt = 4, .ofs_con = 0xe0, .ofs_dat = 0xe8, .ofs_pup = 0xec, }, ['i'-'a'] = { .gpcnt = 16, .con_mask_bitcnt = 2, .ofs_con = 0x100, .ofs_dat = 0x104, .ofs_pup = 0x108, }, ['j'-'a'] = { .gpcnt = 12, .con_mask_bitcnt = 2, .ofs_con = 0x120, .ofs_dat = 0x124, .ofs_pup = 0x128, }, ['k'-'a'] = { .gpcnt = 16, .con_mask_bitcnt = 4, .ofs_con = 0x800, .ofs_dat = 0x808, .ofs_pup = 0x80c, }, ['l'-'a'] = { .gpcnt = 15, .con_mask_bitcnt = 4, .ofs_con = 0x810, .ofs_dat = 0x818, .ofs_pup = 0x81c, }, ['m'-'a'] = { .gpcnt = 6, .con_mask_bitcnt = 4, .ofs_con = 0x820, .ofs_dat = 0x824, .ofs_pup = 0x828, }, ['n'-'a'] = { .gpcnt = 16, .con_mask_bitcnt = 2, .ofs_con = 0x830, .ofs_dat = 0x834, .ofs_pup = 0x838, }, ['o'-'a'] = { .gpcnt = 16, .con_mask_bitcnt = 2, .ofs_con = 0x140, .ofs_dat = 0x144, .ofs_pup = 0x148, }, ['p'-'a'] = { .gpcnt = 15, .con_mask_bitcnt = 2, .ofs_con = 0x160, .ofs_dat = 0x164, .ofs_pup = 0x168, }, ['q'-'a'] = { .gpcnt = 9, .con_mask_bitcnt = 2, .ofs_con = 0x180, .ofs_dat = 0x184, .ofs_pup = 0x188, } }; /// s3c2440 레지스터 어프셋과 정보 static s3c_gpio_register_t s3c2440_gpio_register['j'-'a'+1] = { ['a'-'a'] = { .gpcnt = 16, .con_mask_bitcnt = 2, .ofs_con = 0x0, .ofs_dat = 0x4, .ofs_pup = 0x8, }, ['b'-'a'] = { .gpcnt = 16, .con_mask_bitcnt = 2, .ofs_con = 0x10, .ofs_dat = 0x14, .ofs_pup = 0x18, }, ['c'-'a'] = { .gpcnt = 16, .con_mask_bitcnt = 2, .ofs_con = 0x20, .ofs_dat = 0x24, .ofs_pup = 0x28, }, ['d'-'a'] = { .gpcnt = 16, .con_mask_bitcnt = 2, .ofs_con = 0x30, .ofs_dat = 0x34, .ofs_pup = 0x38, }, ['e'-'a'] = { .gpcnt = 16, .con_mask_bitcnt = 2, .ofs_con = 0x40, .ofs_dat = 0x44, .ofs_pup = 0x48, }, ['f'-'a'] = { .gpcnt = 16, .con_mask_bitcnt = 2, .ofs_con = 0x50, .ofs_dat = 0x54, .ofs_pup = 0x58, }, ['g'-'a'] = { .gpcnt = 16, .con_mask_bitcnt = 2, .ofs_con = 0x60, .ofs_dat = 0x64, .ofs_pup = 0x68, }, ['h'-'a'] = { .gpcnt = 16, .con_mask_bitcnt = 2, .ofs_con = 0x70, .ofs_dat = 0x74, .ofs_pup = 0x78, }, ['i'-'a'] = { .gpcnt = 0, .con_mask_bitcnt = 2, .ofs_con = 0, .ofs_dat = 0, .ofs_pup = 0, }, ['j'-'a'] = { .gpcnt = 13, .con_mask_bitcnt = 2, .ofs_con = 0xd0, .ofs_dat = 0xd4, .ofs_pup = 0xd8, } }; /// pxa 관련 정보 static pxa_gpio_info_t pxa270_info = { .gpcnt = 128, }; static pxa_gpio_info_t pxa255_info = { .gpcnt = 96, }; static mcu_gpio_fops_t mcu_gpio; //static mmap_alloc_t map_gpio; /// mmap 관리 구조체 (0.7.0 부터 삭제) //------------------------------------------------------------------------------ /** @brief gpio fops 포인터 얻기 @return gpio fops 포인터 *///---------------------------------------------------------------------------- mcu_gpio_fops_t *get_gpio_fops( void ) { return &mcu_gpio; } //------------------------------------------------------------------------------ /** @brief gpio 관련된 레지스터를 mmap 을 통해 할다받는다. @param phys_base 물리주소 @param phys_size 물리주소 크기 @return 할당받은 가상 메모리 주소 *///---------------------------------------------------------------------------- static unsigned long malloc_gpio( unsigned long phys_base, unsigned long phys_size ) { return (unsigned long)fa_mmap_alloc( &mcu_gpio.map_info, phys_base, phys_size ); } //------------------------------------------------------------------------------ /** @brief 기본적인 gpio close() 함수 *///---------------------------------------------------------------------------- static void def_gpio_close( void ) { if ( mcu_gpio.mmap_base ) { fa_mmap_free( &mcu_gpio.map_info ); mcu_gpio.mmap_base = 0; } } //------------------------------------------------------------------------------ /** @brief am3x gpio 번호가 정확한지 확인한다. @param grp 0~3 @param gp_nr gp_nr 번호 *///---------------------------------------------------------------------------- static int am3x_valid_gpio( char grp, int gp_nr ) { grp -= '0'; if ( grp >= MCU_AM3874_GPIO_GRP_CNT ) { printf( " gpio error : invalid gp_grp [%d (0~%d)]\n", grp, MCU_AM3874_GPIO_GRP_CNT-1 ); return -1; } if ( gp_nr >= 32 ) { printf( " gpio error : invalid gp_nr [%d (0~31)]\n", gp_nr ); return -1; } return 0; } //------------------------------------------------------------------------------ /** @brief am3x gpio 입력 포트 주소를 얻는다. @param grp 0~3 @param gp_nr gp_nr 번호 *///---------------------------------------------------------------------------- static unsigned long am3x_get_input_port ( char grp, int gp_nr ) { am3x_gpio_register_t *gp = (am3x_gpio_register_t *)(mcu_gpio.private) + (grp - '0'); if ( 0 > am3x_valid_gpio( grp, gp_nr ) ) return 0; return gp->mmap_base + MCU_AM3874_GPIO_DATAIN; } //------------------------------------------------------------------------------ /** @brief am3x gpio 출력 포트 주소를 얻는다. @param grp 0~3 @param gp_nr gp_nr 번호 *///---------------------------------------------------------------------------- static unsigned long am3x_get_output_port( char grp, int gp_nr ) { am3x_gpio_register_t *gp = (am3x_gpio_register_t *)(mcu_gpio.private) + (grp - '0'); if ( 0 > am3x_valid_gpio( grp, gp_nr ) ) return 0; return gp->mmap_base + MCU_AM3874_GPIO_DATAOUT; } //------------------------------------------------------------------------------ /** @brief am3x gpio 입력 설정 @param grp 0~3 @param gp_nr gp_nr 번호 @param pull_up pull_up *///---------------------------------------------------------------------------- static void am3x_gpio_dir_input( char grp, int gp_nr, gpio_pulled_t pull_up ) { am3x_gpio_register_t *gp = (am3x_gpio_register_t *)(mcu_gpio.private) + (grp - '0'); unsigned long pin, rval; if ( 0 > am3x_valid_gpio( grp, gp_nr ) ) return; pin = gp->pin_ctrl[gp_nr]; if ( 0 == pin ) { printf( " gpio error : unable used for gpio [GP%c.%d]\n", grp, gp_nr ); return; } // pin ctrl rval = MCU_AM3874_PIN_MUX_GPIO | MCU_AM3874_PIN_MUX_IEN; switch( pull_up ) { case GPIO_PULL_UP : rval |= MCU_AM3874_PIN_MUX_IPD; break; case GPIO_PULL_DN : rval |= MCU_AM3874_PIN_MUX_IPU; break; default : rval |= MCU_AM3874_PIN_MUX_IPDIS; break; } AM3874_PIN_CTRL(mcu_gpio.mmap_base, pin) = rval; // gpio ctrl AM3874_GPIO_CTRL( gp->mmap_base ) |= (0x1); // enable // gpio oe AM3874_GPIO_OE( gp->mmap_base ) |= (1< am3x_valid_gpio( grp, gp_nr ) ) return; pin = gp->pin_ctrl[gp_nr]; if ( 0 == pin ) { printf( " gpio error : unable used for gpio [GP%c.%d]\n", grp, gp_nr ); return; } //printf( "grp-%c phys=%lx pin=%d\n", grp, gp->phys, pin ); // gpio ctrl AM3874_GPIO_CTRL( gp->mmap_base ) |= (0x1); // enable // gpio data out { rval = AM3874_GPIO_DATAOUT( gp->mmap_base ); rval &= ~(1<mmap_base ) = rval; } // gpio oe AM3874_GPIO_OE( gp->mmap_base ) &= ~(1< am3x_valid_gpio( grp, gp_nr ) ) return -1; rval = AM3874_GPIO_DATAIN( gp->mmap_base ); return ( rval & (1< am3x_valid_gpio( grp, gp_nr ) ) return; // gpio data out { rval = AM3874_GPIO_DATAOUT( gp->mmap_base ); rval &= ~(1<mmap_base ) = rval; } } //------------------------------------------------------------------------------ /** @brief 기본적인 gpio close() 함수 *///---------------------------------------------------------------------------- static void am3x_gpio_close( void ) { int lp; am3x_gpio_register_t *gp = (am3x_gpio_register_t *)mcu_gpio.private; for( lp=0; lpmap_gpio ); } // pin mux if ( mcu_gpio.mmap_base ) { fa_mmap_free( &mcu_gpio.map_info ); mcu_gpio.mmap_base = 0; } } //------------------------------------------------------------------------------ /** @brief am3x gpio 초기화 @param mcu_nr mcu 번호 *///---------------------------------------------------------------------------- static void am3x_gpio_open( int mcu_nr ) { mcu_gpio.mcu_nr = mcu_nr; // pin mux mmap mcu_gpio.mmap_base = malloc_gpio( MCU_AM3874_PIN_MUX_PHYS, MCU_AM3874_PIN_MUX_SIZE ); // gpio mmap { int lp; am3x_gpio_register_t *gp = am3874_gpio_register; for( lp=0; lpmmap_base = (unsigned long)fa_mmap_alloc( &gp->map_gpio, gp->phys, MCU_AM3874_MMAP_GPIO_SIZE ); } } mcu_gpio.close = am3x_gpio_close ; mcu_gpio.dir_input = am3x_gpio_dir_input ; mcu_gpio.dir_output = am3x_gpio_dir_output; mcu_gpio.input = am3x_gpio_input ; mcu_gpio.output = am3x_gpio_output ; mcu_gpio.get_input_port = am3x_get_input_port ; mcu_gpio.get_output_port = am3x_get_output_port; mcu_gpio.private = (void *)am3874_gpio_register; } //------------------------------------------------------------------------------ /** @brief s3c gpio 번호를 검사하여 해당하는 포이터를 돌려준다. *///---------------------------------------------------------------------------- static s3c_gpio_register_t *s3c_find_reg( char grp, int gp_nr ) { s3c_gpio_register_t *reg; unsigned long offset; offset = 0; if ( ( grp < mcu_gpio.grp_begin ) || ( grp > mcu_gpio.grp_end ) ) { printf( " gpio error : invalid group [%c]\n", grp ); return NULL; } switch( mcu_gpio.mcu_nr ) { case 210 : { offset = (grp - 'a') + (gp_nr / GP_NR_GRP)*(mcu_gpio.grp_end - mcu_gpio.grp_begin + 1); if ( offset >= sizeof(s5pv210_reg_idx_table)/sizeof(int) ) { printf( " gpio error : invalid gp_grp ro gp_nr [%c%d-%d]\n", grp, gp_nr/GP_NR_GRP, gp_nr%GP_NR_GRP ); return NULL; } offset = s5pv210_reg_idx_table[ offset ]; //if ( offset < 0 ) //{ // printf( " gpio error : invalid gp_grp ro gp_nr [%c%d-%d]\n", grp, gp_nr/GP_NR_GRP, gp_nr%GP_NR_GRP ); // return NULL; //} //printf( " offset=%d\n", offset ); gp_nr %= GP_NR_GRP; } break; default : offset = (grp - 'a'); break; } reg = (s3c_gpio_register_t *)(mcu_gpio.private) + offset; if ( ( 0 > gp_nr ) || ( reg->gpcnt <= gp_nr ) ) { printf( " gpio error : invalid gp_nr [%d (0~%d)]\n", gp_nr, reg->gpcnt-1 ); return NULL; } return reg; } //------------------------------------------------------------------------------ /** @brief s3c gpio 입력 설정 @param grp gpio 그룹문자 'a' ... 'z' @param gp_nr gp_nr 번호 @param pull_up pull_up 내부 풀업 활성화 유무 *///---------------------------------------------------------------------------- static void s3c_gpio_dir_input( char grp, int gp_nr, gpio_pulled_t pull_up ) { volatile unsigned long *reg_con; volatile unsigned long *reg_pup; volatile unsigned long rval; s3c_gpio_register_t *reg; reg = s3c_find_reg( grp, gp_nr ); gp_nr %= GP_NR_GRP; if ( NULL == reg ) return; reg_con = (unsigned long *)(mcu_gpio.mmap_base + reg->ofs_con ); reg_pup = (unsigned long *)(mcu_gpio.mmap_base + reg->ofs_pup ); // pull-up 설정 { rval = *(reg_pup); rval &= ~(0x3<<(gp_nr*2)); switch( pull_up ) { case GPIO_PULL_UP : rval |= (0x2<<(gp_nr*2)); break; case GPIO_PULL_DN : rval |= (0x1<<(gp_nr*2)); break; case GPIO_PULL_NONE : break; } *(reg_pup) = rval; } // 입력 설정 { unsigned long and_mask, orr_mask; if ( reg->con_mask_bitcnt == 4 ) { reg_con += (gp_nr/8); and_mask = ~( 0xf << ( (gp_nr%8 )*4 ) ); orr_mask = ( 0x0 << ( (gp_nr%8 )*4 ) ); } else { and_mask = ~( 0x3 << ( (gp_nr%16)*2 ) ); orr_mask = ( 0x0 << ( (gp_nr%16)*2 ) ); } rval = *(reg_con); rval &= and_mask; rval |= orr_mask; *(reg_con) = rval; } } //------------------------------------------------------------------------------ /** @brief s3c gpio 출력 설정 @param grp gpio 그룹 @param gp_nr gpio 번호 @param gp_val gpio 초기 출력값 *///---------------------------------------------------------------------------- static void s3c_gpio_dir_output( char grp, int gp_nr, int gp_val ) { volatile unsigned long *reg_con; volatile unsigned long *reg_dat; volatile unsigned long *reg_pup; volatile unsigned long rval; s3c_gpio_register_t *reg; reg = s3c_find_reg( grp, gp_nr ); gp_nr %= GP_NR_GRP; if ( NULL == reg ) return; reg_con = (unsigned long *)(mcu_gpio.mmap_base + reg->ofs_con ); reg_dat = (unsigned long *)(mcu_gpio.mmap_base + reg->ofs_dat ); reg_pup = (unsigned long *)(mcu_gpio.mmap_base + reg->ofs_pup ); // pull-up 설정 { rval = *(reg_pup); rval &= ~(0x3<<(gp_nr*2)); // pull-up disable *(reg_pup) = rval; } // 출력 { rval = *(reg_dat); rval &= ~(1<con_mask_bitcnt == 4 ) { reg_con += (gp_nr/8); and_mask = ~( 0xf << ( (gp_nr%8 )*4 ) ); orr_mask = ( 0x1 << ( (gp_nr%8 )*4 ) ); } else { and_mask = ~( 0x3 << ( (gp_nr%16)*2 ) ); orr_mask = ( 0x1 << ( (gp_nr%16)*2 ) ); } rval = *(reg_con); rval &= and_mask; rval |= orr_mask; *(reg_con) = rval; } } //------------------------------------------------------------------------------ /** @brief s3c gpio 입력 @param grp gpio 그룹 @param gp_nr gpio 번호 *///---------------------------------------------------------------------------- static int s3c_gpio_input( char grp, int gp_nr ) { volatile unsigned long *reg_dat; s3c_gpio_register_t *reg; reg = s3c_find_reg( grp, gp_nr ); gp_nr %= GP_NR_GRP; if ( NULL == reg ) return -1; reg_dat = (unsigned long *)(mcu_gpio.mmap_base + reg->ofs_dat ); return *(reg_dat) & (1<< gp_nr) ? 1 : 0; } //------------------------------------------------------------------------------ /** @brief s3c gpio 출력 @param grp gpio 그룹 @param gp_nr gpio 번호 @param gpio_val gpio 초기 출력값 *///---------------------------------------------------------------------------- static void s3c_gpio_output( char grp, int gp_nr, int gp_val ) { volatile unsigned long *reg_dat; volatile unsigned long rval; s3c_gpio_register_t *reg; reg = s3c_find_reg( grp, gp_nr ); gp_nr %= GP_NR_GRP; if ( NULL == reg ) return; reg_dat = (unsigned long *)(mcu_gpio.mmap_base + reg->ofs_dat ); // 출력 rval = *(reg_dat); rval &= ~(1<ofs_dat ); } //------------------------------------------------------------------------------ /** @brief s3c gpio 초기화 @param mcu_nr mcu 번호 *///---------------------------------------------------------------------------- static void s3c_gpio_open( int mcu_nr ) { mcu_gpio.mcu_nr = mcu_nr; switch( mcu_nr ) { case 210 : // S5PV210 { mcu_gpio.grp_begin = 'a'; mcu_gpio.grp_end = 'j'; mcu_gpio.phys_base = MCU_S5PV210_MMAP_GPIO_PHYS; mcu_gpio.phys_size = MCU_S5PV210_MMAP_GPIO_SIZE; mcu_gpio.private = (void *)s5pv210_gpio_register; mcu_gpio.get_output_port = s3c_get_data_port; mcu_gpio.get_input_port = s3c_get_data_port; } break; case 6410 : { mcu_gpio.grp_begin = 'a'; mcu_gpio.grp_end = 'a' + sizeof(s3c6410_gpio_register)/sizeof(s3c_gpio_register_t); mcu_gpio.phys_base = MCU_S3C6410_MMAP_GPIO_PHYS; mcu_gpio.phys_size = MCU_S3C6410_MMAP_GPIO_SIZE; mcu_gpio.private = (void *)s3c6410_gpio_register; mcu_gpio.get_output_port = s3c_get_data_port; mcu_gpio.get_input_port = s3c_get_data_port; } break; default : { mcu_gpio.grp_begin = 'a'; mcu_gpio.grp_end = 'a' + sizeof(s3c2440_gpio_register)/sizeof(s3c_gpio_register_t); mcu_gpio.phys_base = MCU_S3C2440_MMAP_GPIO_PHYS; mcu_gpio.phys_size = MCU_S3C2440_MMAP_GPIO_SIZE; mcu_gpio.private = (void *)s3c2440_gpio_register; } break; } mcu_gpio.mmap_base = malloc_gpio( mcu_gpio.phys_base, mcu_gpio.phys_size ); mcu_gpio.close = def_gpio_close ; mcu_gpio.dir_input = s3c_gpio_dir_input ; mcu_gpio.dir_output = s3c_gpio_dir_output; mcu_gpio.input = s3c_gpio_input ; mcu_gpio.output = s3c_gpio_output ; } //------------------------------------------------------------------------------ /** @brief pxa gpio 입력 설정 @param grp gpio 사용하지 않는다. @param gp_nr gp_nr 번호 @param pull_up pull_up 사용하지 않는다. *///---------------------------------------------------------------------------- static void pxa_gpio_dir_input( char grp, int gp_nr, gpio_pulled_t pull_up ) { pxa_gpio_info_t *info; grp = grp; pull_up = pull_up; info = (pxa_gpio_info_t *)(mcu_gpio.private); if ( info->gpcnt <= gp_nr ) { printf( " gpio error : invalid gp_nr [%d (0~%d)]\n", gp_nr, info->gpcnt-1 ); return; } // gpio in/out 설정 PXA_GPIO_INOUT( gp_nr ); // 입력 설정 PXA_DIR_IN( gp_nr ); } //------------------------------------------------------------------------------ /** @brief pxa gpio 출력 설정 @param grp 사용하지 않는다. @param gp_nr gpio 번호 @param gp_val gpio 초기 출력값 *///---------------------------------------------------------------------------- static void pxa_gpio_dir_output( char grp, int gp_nr, int gp_val ) { pxa_gpio_info_t *info; grp = grp; info = (pxa_gpio_info_t *)(mcu_gpio.private); if ( info->gpcnt <= gp_nr ) { printf( " gpio error : invalid gp_nr [%d (0~%d)]\n", gp_nr, info->gpcnt-1 ); return; } // gpio in/out 설정 PXA_GPIO_INOUT( gp_nr ); // 출력 if (gp_val & 0x1) { PXA_OUT_SET(gp_nr); } else { PXA_OUT_CLR(gp_nr); } // 출력 설정 PXA_DIR_OUT( gp_nr ); } //------------------------------------------------------------------------------ /** @brief pxa gpio 입력 @param grp 사용하지 않는다. @param gp_nr gpio 번호 *///---------------------------------------------------------------------------- static int pxa_gpio_input( char grp, int gp_nr ) { pxa_gpio_info_t *info; grp = grp; info = (pxa_gpio_info_t *)(mcu_gpio.private); if ( info->gpcnt <= gp_nr ) { printf( " gpio error : invalid gp_nr [%d (0~%d)]\n", gp_nr, info->gpcnt-1 ); return -1; } return PXA_IN_DAT( gp_nr ) ? 1:0; } //------------------------------------------------------------------------------ /** @brief pxa gpio 출력 @param grp 사용하지 않는다. @param gp_nr gpio 번호 @param gpio_val gpio 초기 출력값 *///---------------------------------------------------------------------------- static void pxa_gpio_output( char grp, int gp_nr, int gp_val ) { pxa_gpio_info_t *info; grp = grp; info = (pxa_gpio_info_t *)(mcu_gpio.private); if ( info->gpcnt <= gp_nr ) { printf( " gpio error : invalid gp_nr [%d (0~%d)]\n", gp_nr, info->gpcnt-1 ); return; } if (gp_val & 0x1) { PXA_OUT_SET(gp_nr); } else { PXA_OUT_CLR(gp_nr); } } //------------------------------------------------------------------------------ /** @brief pxa gpio 초기화 @param mcu_nr mcu 번호 *///---------------------------------------------------------------------------- static void pxa_gpio_open( int mcu_nr ) { mcu_gpio.mcu_nr = mcu_nr; if ( 270 == mcu_nr ) { mcu_gpio.phys_base = MCU_PXA270_MMAP_GPIO_PHYS; mcu_gpio.phys_size = MCU_PXA270_MMAP_GPIO_SIZE; mcu_gpio.private = (void *)&pxa270_info; } else { mcu_gpio.phys_base = MCU_PXA255_MMAP_GPIO_PHYS; mcu_gpio.phys_size = MCU_PXA255_MMAP_GPIO_SIZE; mcu_gpio.private = (void *)&pxa255_info; } mcu_gpio.mmap_base = malloc_gpio( mcu_gpio.phys_base, mcu_gpio.phys_size ); mcu_gpio.close = def_gpio_close ; mcu_gpio.dir_input = pxa_gpio_dir_input ; mcu_gpio.dir_output = pxa_gpio_dir_output; mcu_gpio.input = pxa_gpio_input ; mcu_gpio.output = pxa_gpio_output ; } //------------------------------------------------------------------------------ /** @brief ixp gpio 입력 설정 @param grp gpio 사용하지 않는다. @param gp_nr gp_nr 번호 @param pull_up pull_up 사용하지 않는다. *///---------------------------------------------------------------------------- static void ixp_gpio_dir_input( char grp, int gp_nr, gpio_pulled_t pull_up ) { grp = grp; pull_up = pull_up; if ( ( 0 <= gp_nr ) && ( gp_nr <= 15 ) ) { IXP4XX_GPIO_GPOER |= (1<