/** @file tgpio_imx6.c @date 2013/7/22 @author 오재경 freefrug@falinux.com FALinux.Co.,Ltd. @brief gpio 를 드라이버없이 mmap를 이용하여 제어한다. Ver 0.7.0 iMX6 포함, GP0테스트 진행 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 #include extern mcu_gpio_fops_t *get_gpio_fops( void ); static mcu_gpio_fops_t *mgpio = NULL; /// imx6 gpio base static imx6_gpio_register_t imx6_gpio_register[MCU_iMX6_GPIO_GRP_CNT] = { [0] = { .phys = MCU_iMX6_GPIO1_PHYS, }, [1] = { .phys = MCU_iMX6_GPIO2_PHYS, }, [2] = { .phys = MCU_iMX6_GPIO3_PHYS, }, [3] = { .phys = MCU_iMX6_GPIO4_PHYS, }, [4] = { .phys = MCU_iMX6_GPIO5_PHYS, }, [5] = { .phys = MCU_iMX6_GPIO6_PHYS, }, [6] = { .phys = MCU_iMX6_GPIO7_PHYS, }, }; #define WRITE_MUX_CTRL( val, reg ) *(volatile unsigned long *)( reg ) = (val) #define WRITE_SEL_INPUT( val, reg ) *(volatile unsigned long *)( reg ) = (val) #define WRITE_PAD_CTRL( val, reg ) *(volatile unsigned long *)( reg ) = (val) static void imx6_gpio_output( char grp, int gp_nr, int gp_val ); //------------------------------------------------------------------------------ /** @brief configures a single pad in the iomuxer @param mmap_base @param pad *///---------------------------------------------------------------------------- static int mxc_iomux_v3_setup_pad( unsigned long base, iomux_v3_cfg_t pad ) { u32 mux_ctrl_ofs = (pad & MUX_CTRL_OFS_MASK ) >> MUX_CTRL_OFS_SHIFT ; u32 mux_mode = (pad & MUX_MODE_MASK ) >> MUX_MODE_SHIFT ; u32 sel_input_ofs = (pad & MUX_SEL_INPUT_OFS_MASK) >> MUX_SEL_INPUT_OFS_SHIFT; u32 sel_input = (pad & MUX_SEL_INPUT_MASK ) >> MUX_SEL_INPUT_SHIFT ; u32 pad_ctrl_ofs = (pad & MUX_PAD_CTRL_OFS_MASK ) >> MUX_PAD_CTRL_OFS_SHIFT ; u32 pad_ctrl = (pad & MUX_PAD_CTRL_MASK ) >> MUX_PAD_CTRL_SHIFT ; if (mux_ctrl_ofs) WRITE_MUX_CTRL(mux_mode, base + mux_ctrl_ofs); if (sel_input_ofs) WRITE_SEL_INPUT(sel_input, base + sel_input_ofs); if (!(pad_ctrl & NO_PAD_CTRL) && pad_ctrl_ofs) WRITE_PAD_CTRL(pad_ctrl, base + pad_ctrl_ofs); return 0; } // group : gpio1 ... gpio7 static iomux_v3_cfg_t imx6q_gpio_pads[7][32] = { ['1'-'1'] = { MX6Q_PAD_GPIO_0__GPIO_1_0, MX6Q_PAD_GPIO_1__GPIO_1_1, MX6Q_PAD_GPIO_2__GPIO_1_2, MX6Q_PAD_GPIO_3__GPIO_1_3, MX6Q_PAD_GPIO_4__GPIO_1_4, MX6Q_PAD_GPIO_5__GPIO_1_5, MX6Q_PAD_GPIO_6__GPIO_1_6, MX6Q_PAD_GPIO_7__GPIO_1_7, MX6Q_PAD_GPIO_8__GPIO_1_8, MX6Q_PAD_GPIO_9__GPIO_1_9, MX6Q_PAD_SD2_CLK__GPIO_1_10, MX6Q_PAD_SD2_CMD__GPIO_1_11, MX6Q_PAD_SD2_DAT3__GPIO_1_12, MX6Q_PAD_SD2_DAT2__GPIO_1_13, MX6Q_PAD_SD2_DAT1__GPIO_1_14, MX6Q_PAD_SD2_DAT0__GPIO_1_15, MX6Q_PAD_SD1_DAT0__GPIO_1_16, MX6Q_PAD_SD1_DAT1__GPIO_1_17, MX6Q_PAD_SD1_CMD__GPIO_1_18, MX6Q_PAD_SD1_DAT2__GPIO_1_19, MX6Q_PAD_SD1_CLK__GPIO_1_20, MX6Q_PAD_SD1_DAT3__GPIO_1_21, MX6Q_PAD_ENET_MDIO__GPIO_1_22, MX6Q_PAD_ENET_REF_CLK__GPIO_1_23, MX6Q_PAD_ENET_RX_ER__GPIO_1_24, MX6Q_PAD_ENET_CRS_DV__GPIO_1_25, MX6Q_PAD_ENET_RXD1__GPIO_1_26, MX6Q_PAD_ENET_RXD0__GPIO_1_27, MX6Q_PAD_ENET_TX_EN__GPIO_1_28, MX6Q_PAD_ENET_TXD1__GPIO_1_29, MX6Q_PAD_ENET_TXD0__GPIO_1_30, MX6Q_PAD_ENET_MDC__GPIO_1_31, }, ['2'-'1'] = { MX6Q_PAD_NANDF_D0__GPIO_2_0, MX6Q_PAD_NANDF_D1__GPIO_2_1, MX6Q_PAD_NANDF_D2__GPIO_2_2, MX6Q_PAD_NANDF_D3__GPIO_2_3, MX6Q_PAD_NANDF_D4__GPIO_2_4, MX6Q_PAD_NANDF_D5__GPIO_2_5, MX6Q_PAD_NANDF_D6__GPIO_2_6, MX6Q_PAD_NANDF_D7__GPIO_2_7, MX6Q_PAD_SD4_DAT0__GPIO_2_8, MX6Q_PAD_SD4_DAT1__GPIO_2_9, MX6Q_PAD_SD4_DAT2__GPIO_2_10, MX6Q_PAD_SD4_DAT3__GPIO_2_11, MX6Q_PAD_SD4_DAT4__GPIO_2_12, MX6Q_PAD_SD4_DAT5__GPIO_2_13, MX6Q_PAD_SD4_DAT6__GPIO_2_14, MX6Q_PAD_SD4_DAT7__GPIO_2_15, MX6Q_PAD_EIM_A22__GPIO_2_16, MX6Q_PAD_EIM_A21__GPIO_2_17, MX6Q_PAD_EIM_A20__GPIO_2_18, MX6Q_PAD_EIM_A19__GPIO_2_19, MX6Q_PAD_EIM_A18__GPIO_2_20, MX6Q_PAD_EIM_A17__GPIO_2_21, MX6Q_PAD_EIM_A16__GPIO_2_22, MX6Q_PAD_EIM_CS0__GPIO_2_23, MX6Q_PAD_EIM_CS1__GPIO_2_24, MX6Q_PAD_EIM_OE__GPIO_2_25, MX6Q_PAD_EIM_RW__GPIO_2_26, MX6Q_PAD_EIM_LBA__GPIO_2_27, MX6Q_PAD_EIM_EB0__GPIO_2_28, MX6Q_PAD_EIM_EB1__GPIO_2_29, MX6Q_PAD_EIM_EB2__GPIO_2_30, MX6Q_PAD_EIM_EB3__GPIO_2_31, }, ['3'-'1'] = { MX6Q_PAD_EIM_DA0__GPIO_3_0, MX6Q_PAD_EIM_DA1__GPIO_3_1, MX6Q_PAD_EIM_DA2__GPIO_3_2, MX6Q_PAD_EIM_DA3__GPIO_3_3, MX6Q_PAD_EIM_DA4__GPIO_3_4, MX6Q_PAD_EIM_DA5__GPIO_3_5, MX6Q_PAD_EIM_DA6__GPIO_3_6, MX6Q_PAD_EIM_DA7__GPIO_3_7, MX6Q_PAD_EIM_DA8__GPIO_3_8, MX6Q_PAD_EIM_DA9__GPIO_3_9, MX6Q_PAD_EIM_DA10__GPIO_3_10, MX6Q_PAD_EIM_DA11__GPIO_3_11, MX6Q_PAD_EIM_DA12__GPIO_3_12, MX6Q_PAD_EIM_DA13__GPIO_3_13, MX6Q_PAD_EIM_DA14__GPIO_3_14, MX6Q_PAD_EIM_DA15__GPIO_3_15, MX6Q_PAD_EIM_D16__GPIO_3_16, MX6Q_PAD_EIM_D17__GPIO_3_17, MX6Q_PAD_EIM_D18__GPIO_3_18, MX6Q_PAD_EIM_D19__GPIO_3_19, MX6Q_PAD_EIM_D20__GPIO_3_20, MX6Q_PAD_EIM_D21__GPIO_3_21, MX6Q_PAD_EIM_D22__GPIO_3_22, MX6Q_PAD_EIM_D23__GPIO_3_23, MX6Q_PAD_EIM_D24__GPIO_3_24, MX6Q_PAD_EIM_D25__GPIO_3_25, MX6Q_PAD_EIM_D26__GPIO_3_26, MX6Q_PAD_EIM_D27__GPIO_3_27, MX6Q_PAD_EIM_D28__GPIO_3_28, MX6Q_PAD_EIM_D29__GPIO_3_29, MX6Q_PAD_EIM_D30__GPIO_3_30, MX6Q_PAD_EIM_D31__GPIO_3_31, }, ['4'-'1'] = { 0,0,0,0,0, MX6Q_PAD_GPIO_19__GPIO_4_5, MX6Q_PAD_KEY_COL0__GPIO_4_6, MX6Q_PAD_KEY_ROW0__GPIO_4_7, MX6Q_PAD_KEY_COL1__GPIO_4_8, MX6Q_PAD_KEY_ROW1__GPIO_4_9, MX6Q_PAD_KEY_COL2__GPIO_4_10, MX6Q_PAD_KEY_ROW2__GPIO_4_11, MX6Q_PAD_KEY_COL3__GPIO_4_12, MX6Q_PAD_KEY_ROW3__GPIO_4_13, MX6Q_PAD_KEY_COL4__GPIO_4_14, MX6Q_PAD_KEY_ROW4__GPIO_4_15, MX6Q_PAD_DI0_DISP_CLK__GPIO_4_16, MX6Q_PAD_DI0_PIN15__GPIO_4_17, MX6Q_PAD_DI0_PIN2__GPIO_4_18, MX6Q_PAD_DI0_PIN3__GPIO_4_19, MX6Q_PAD_DI0_PIN4__GPIO_4_20, MX6Q_PAD_DISP0_DAT0__GPIO_4_21, MX6Q_PAD_DISP0_DAT1__GPIO_4_22, MX6Q_PAD_DISP0_DAT2__GPIO_4_23, MX6Q_PAD_DISP0_DAT3__GPIO_4_24, MX6Q_PAD_DISP0_DAT4__GPIO_4_25, MX6Q_PAD_DISP0_DAT5__GPIO_4_26, MX6Q_PAD_DISP0_DAT6__GPIO_4_27, MX6Q_PAD_DISP0_DAT7__GPIO_4_28, MX6Q_PAD_DISP0_DAT8__GPIO_4_29, MX6Q_PAD_DISP0_DAT9__GPIO_4_30, MX6Q_PAD_DISP0_DAT10__GPIO_4_31, }, ['5'-'1'] = { MX6Q_PAD_EIM_WAIT__GPIO_5_0, 0, MX6Q_PAD_EIM_A25__GPIO_5_2, 0, MX6Q_PAD_EIM_A24__GPIO_5_4, MX6Q_PAD_DISP0_DAT11__GPIO_5_5, MX6Q_PAD_DISP0_DAT12__GPIO_5_6, MX6Q_PAD_DISP0_DAT13__GPIO_5_7, MX6Q_PAD_DISP0_DAT14__GPIO_5_8, MX6Q_PAD_DISP0_DAT15__GPIO_5_9, MX6Q_PAD_DISP0_DAT16__GPIO_5_10, MX6Q_PAD_DISP0_DAT17__GPIO_5_11, MX6Q_PAD_DISP0_DAT18__GPIO_5_12, MX6Q_PAD_DISP0_DAT19__GPIO_5_13, MX6Q_PAD_DISP0_DAT20__GPIO_5_14, MX6Q_PAD_DISP0_DAT21__GPIO_5_15, MX6Q_PAD_DISP0_DAT22__GPIO_5_16, MX6Q_PAD_DISP0_DAT23__GPIO_5_17, MX6Q_PAD_CSI0_PIXCLK__GPIO_5_18, MX6Q_PAD_CSI0_MCLK__GPIO_5_19, MX6Q_PAD_CSI0_DATA_EN__GPIO_5_20, MX6Q_PAD_CSI0_VSYNC__GPIO_5_21, MX6Q_PAD_CSI0_DAT4__GPIO_5_22, MX6Q_PAD_CSI0_DAT5__GPIO_5_23, MX6Q_PAD_CSI0_DAT6__GPIO_5_24, MX6Q_PAD_CSI0_DAT7__GPIO_5_25, MX6Q_PAD_CSI0_DAT8__GPIO_5_26, MX6Q_PAD_CSI0_DAT9__GPIO_5_27, MX6Q_PAD_CSI0_DAT10__GPIO_5_28, MX6Q_PAD_CSI0_DAT11__GPIO_5_29, MX6Q_PAD_CSI0_DAT12__GPIO_5_30, MX6Q_PAD_CSI0_DAT13__GPIO_5_31, }, ['6'-'1'] = { MX6Q_PAD_CSI0_DAT14__GPIO_6_0, MX6Q_PAD_CSI0_DAT15__GPIO_6_1, MX6Q_PAD_CSI0_DAT16__GPIO_6_2, MX6Q_PAD_CSI0_DAT17__GPIO_6_3, MX6Q_PAD_CSI0_DAT18__GPIO_6_4, MX6Q_PAD_CSI0_DAT19__GPIO_6_5, MX6Q_PAD_EIM_A23__GPIO_6_6, MX6Q_PAD_NANDF_CLE__GPIO_6_7, MX6Q_PAD_NANDF_ALE__GPIO_6_8, MX6Q_PAD_NANDF_WP_B__GPIO_6_9, MX6Q_PAD_NANDF_RB0__GPIO_6_10, MX6Q_PAD_NANDF_CS0__GPIO_6_11, 0,0, MX6Q_PAD_NANDF_CS1__GPIO_6_14, MX6Q_PAD_NANDF_CS2__GPIO_6_15, MX6Q_PAD_NANDF_CS3__GPIO_6_16, MX6Q_PAD_SD3_DAT7__GPIO_6_17, MX6Q_PAD_SD3_DAT6__GPIO_6_18, MX6Q_PAD_RGMII_TXC__GPIO_6_19, MX6Q_PAD_RGMII_TD0__GPIO_6_20, MX6Q_PAD_RGMII_TD1__GPIO_6_21, MX6Q_PAD_RGMII_TD2__GPIO_6_22, MX6Q_PAD_RGMII_TD3__GPIO_6_23, MX6Q_PAD_RGMII_RX_CTL__GPIO_6_24, MX6Q_PAD_RGMII_RD0__GPIO_6_25, MX6Q_PAD_RGMII_TX_CTL__GPIO_6_26, MX6Q_PAD_RGMII_RD1__GPIO_6_27, MX6Q_PAD_RGMII_RD2__GPIO_6_28, MX6Q_PAD_RGMII_RD3__GPIO_6_29, MX6Q_PAD_RGMII_RXC__GPIO_6_30, MX6Q_PAD_EIM_BCLK__GPIO_6_31, }, ['7'-'1'] = { MX6Q_PAD_SD3_DAT5__GPIO_7_0, MX6Q_PAD_SD3_DAT4__GPIO_7_1, MX6Q_PAD_SD3_CMD__GPIO_7_2, MX6Q_PAD_SD3_CLK__GPIO_7_3, MX6Q_PAD_SD3_DAT0__GPIO_7_4, MX6Q_PAD_SD3_DAT1__GPIO_7_5, MX6Q_PAD_SD3_DAT2__GPIO_7_6, MX6Q_PAD_SD3_DAT3__GPIO_7_7, MX6Q_PAD_SD3_RST__GPIO_7_8, MX6Q_PAD_SD4_CMD__GPIO_7_9, MX6Q_PAD_SD4_CLK__GPIO_7_10, MX6Q_PAD_GPIO_16__GPIO_7_11, MX6Q_PAD_GPIO_17__GPIO_7_12, MX6Q_PAD_GPIO_18__GPIO_7_13, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, } }; //static mmap_alloc_t map_iomux; /// mmap 관리 구조체 //static unsigned long iomux_base = 0; //------------------------------------------------------------------------------ /** @brief configures a single pad in the iomuxer @param mmap_base @param pad *///---------------------------------------------------------------------------- static int mxc_iomux_setup_gpio( unsigned long iomux_base, char grp, int gp_nr, gpio_pulled_t pull_up ) { iomux_v3_cfg_t pad; //if ( 0 == iomux_base ) //{ // iomux_base = (unsigned long)fa_mmap_alloc( &map_iomux, MX6Q_IOMUXC_BASE_ADDR, MX6Q_IOMUXC_SIZE ); //} if ( ( '1' <= grp ) && ( grp <= '7' ) ) { pad = imx6q_gpio_pads[ grp-'1'][ gp_nr%32 ]; if ( 0 != pad ) { switch( pull_up ) { case GPIO_PULL_UP : pad &= ~NO_PAD_CTRL; pad |= PAD_CTL_PUS_47K_UP; break; case GPIO_PULL_DN : pad &= ~NO_PAD_CTRL; pad |= PAD_CTL_PUS_100K_DOWN; break; default : break; } mxc_iomux_v3_setup_pad( iomux_base, pad ); } else goto err_exit; } else goto err_exit; return 0; err_exit: printf( " iMX6 iomux error : invalid gpio [%c-%d]\n", grp, gp_nr ); return -1; } //------------------------------------------------------------------------------ /** @brief imx6 gpio 번호가 정확한지 확인한다. @param grp 0~3 @param gp_nr gp_nr 번호 *///---------------------------------------------------------------------------- static int imx6_valid_gpio( char grp, int gp_nr ) { grp -= '1'; if ( grp >= MCU_iMX6_GPIO_GRP_CNT ) { printf( " gpio error : invalid gp_grp [%d (0~%d)]\n", grp+1, MCU_iMX6_GPIO_GRP_CNT ); return -1; } if ( gp_nr >= 32 ) { printf( " gpio error : invalid gp_nr [%d (0~31)]\n", gp_nr ); return -1; } return 0; } //------------------------------------------------------------------------------ /** @brief imx6 gpio 입력 포트 주소를 얻는다. @param grp 0~3 @param gp_nr gp_nr 번호 *///---------------------------------------------------------------------------- static unsigned long imx6_get_dat_port ( char grp, int gp_nr ) { imx6_gpio_register_t *gp = (imx6_gpio_register_t *)(mgpio->private) + (grp - '1'); if ( 0 > imx6_valid_gpio( grp, gp_nr ) ) return 0; return gp->mmap_base + MCU_iMX6_GPIO_DAT_OFS; } //------------------------------------------------------------------------------ /** @brief imx6 gpio 입력 설정 @param grp '1'~'7' @param gp_nr gp_nr 0..31 @param pull_up pull_up *///---------------------------------------------------------------------------- static void imx6_gpio_dir_input( char grp, int gp_nr, gpio_pulled_t pull_up ) { imx6_gpio_register_t *gp = (imx6_gpio_register_t *)(mgpio->private) + (grp - '1'); if ( 0 > imx6_valid_gpio( grp, gp_nr ) ) return; // iomux mxc_iomux_setup_gpio( gp->mmap_base, grp, gp_nr, pull_up ); // gpio dir input iMX6_GPIO_DIRPORT( gp->mmap_base ) &= ~(1<private) + (grp - '1'); if ( 0 > imx6_valid_gpio( grp, gp_nr ) ) return; // iomux mxc_iomux_setup_gpio( gp->mmap_base, grp, gp_nr, GPIO_PULL_NONE ); // gpio dir output iMX6_GPIO_DIRPORT( gp->mmap_base ) |= (1<private) + (grp - '1'); unsigned long rval; if ( 0 > imx6_valid_gpio( grp, gp_nr ) ) return -1; rval = iMX6_GPIO_DATPORT( gp->mmap_base ); return ( rval & (1<private) + (grp - '1'); unsigned long rval; if ( 0 > imx6_valid_gpio( grp, gp_nr ) ) return; // gpio data out { rval = iMX6_GPIO_DATPORT( gp->mmap_base ); rval &= ~(1<mmap_base ) = rval; } } //------------------------------------------------------------------------------ /** @brief imx6 gpio close() 함수 *///---------------------------------------------------------------------------- static void imx6_gpio_close( void ) { int lp; imx6_gpio_register_t *gp = (imx6_gpio_register_t *)mgpio->private; for( lp=0; lpmap_gpio ); } // iomux 해제 if ( mgpio->mmap_base ) { fa_mmap_free( &mgpio->map_info ); mgpio->mmap_base = 0; } } //------------------------------------------------------------------------------ /** @brief imx6 gpio 초기화 @param mcu_nr mcu 번호 *///---------------------------------------------------------------------------- void imx6_gpio_open( int mcu_nr ) { mgpio = get_gpio_fops(); mgpio->mcu_nr = mcu_nr; // pin mux mmap mgpio->mmap_base = (unsigned long)fa_mmap_alloc( &mgpio->map_info, MX6Q_IOMUXC_BASE_ADDR, MX6Q_IOMUXC_SIZE ); // gpio mmap { int lp; imx6_gpio_register_t *gp = imx6_gpio_register; for( lp=0; lpmmap_base = (unsigned long)fa_mmap_alloc( &gp->map_gpio, gp->phys, MCU_iMX6_GPIO_PHYS_SIZE ); } } mgpio->close = imx6_gpio_close ; mgpio->dir_input = imx6_gpio_dir_input ; mgpio->dir_output = imx6_gpio_dir_output; mgpio->input = imx6_gpio_input ; mgpio->output = imx6_gpio_output ; mgpio->get_input_port = imx6_get_dat_port ; mgpio->get_output_port = imx6_get_dat_port ; mgpio->private = (void *)imx6_gpio_register; }