diff options
author | Haibo Chen <haibo.chen@freescale.com> | 2015-02-11 16:14:26 +0800 |
---|---|---|
committer | Haibo Chen <haibo.chen@freescale.com> | 2015-03-05 10:48:32 +0800 |
commit | 4c587b29c423ce61b2471ed20f31ff533d9d8a39 (patch) | |
tree | e01d263614cfe339e41a2b86fea1e144023a214e | |
parent | 7cbab5830d486733a691be104cbc2be494b00776 (diff) | |
download | u-boot-imx-4c587b29c423ce61b2471ed20f31ff533d9d8a39.zip u-boot-imx-4c587b29c423ce61b2471ed20f31ff533d9d8a39.tar.gz u-boot-imx-4c587b29c423ce61b2471ed20f31ff533d9d8a39.tar.bz2 |
MLK-10215 Add elan init in i.MX6SL-EVK board
EPDC board contain a elan touch screen, this screen is a i2c
slave. If this EPDC board connect to i.MX6SL-EVK board, after
uboot boot up, if we do i2c operation, like i2c probe, then
the i2c bus block. This is due to the elan touch screen i2c slave.
This device needs to do some initialization opearation before its
i2c operation, otherwise this i2c device pull down the i2c clk line,
and make the i2c bus hang. This means elan needs a special flow on
i2c before its address is acked, otherwise the i2c bus will be hang.
This patch is a workaround, it add a void function which is defined
as a weak symbol in i2c driver, and it is called before every i2c
operation. In mx6slevk, this function was overwrite to execute elan
initialization. So that, for mx6slevk board, it will initialize
elan before every i2c operation, but for other boards, it just work
as before.
Signed-off-by: Haibo Chen <haibo.chen@freescale.com>
-rw-r--r-- | arch/arm/include/asm/arch-mx6/mx6sl_pins.h | 4 | ||||
-rw-r--r-- | board/freescale/mx6slevk/mx6slevk.c | 39 | ||||
-rw-r--r-- | drivers/i2c/mxc_i2c.c | 14 |
3 files changed, 56 insertions, 1 deletions
diff --git a/arch/arm/include/asm/arch-mx6/mx6sl_pins.h b/arch/arm/include/asm/arch-mx6/mx6sl_pins.h index 90cc965..0e8419c 100644 --- a/arch/arm/include/asm/arch-mx6/mx6sl_pins.h +++ b/arch/arm/include/asm/arch-mx6/mx6sl_pins.h @@ -57,7 +57,8 @@ enum { MX6_PAD_I2C1_SDA__GPIO_3_13 = IOMUX_PAD(0x0450, 0x0160, 5, 0x0000, 0, 0), MX6_PAD_I2C1_SCL__I2C1_SCL = IOMUX_PAD(0x044C, 0x015C, 0x10, 0x071C, 2, 0), MX6_PAD_I2C1_SCL__GPIO_3_12 = IOMUX_PAD(0x044C, 0x015C, 5, 0x0000, 0, 0), - + MX6_PAD_EPDC_PWRCTRL2__GPIO_2_9 = IOMUX_PAD(0x03DC, 0x00EC, 5, 0x0000, 0, 0), + MX6_PAD_EPDC_PWRCTRL3__GPIO_2_10 = IOMUX_PAD(0x03E0, 0x00F0, 5, 0x0000, 0, 0), MX6_PAD_EPDC_PWRSTAT__GPIO_2_13 = IOMUX_PAD(0x03E8, 0x00F8, 5, 0x0000, 0, 0), MX6_PAD_EPDC_VCOM0__GPIO_2_3 = IOMUX_PAD(0x0410, 0x0120, 5, 0x0000, 0, 0), MX6_PAD_EPDC_PWRWAKEUP__GPIO_2_14 = IOMUX_PAD(0x03EC, 0x00FC, 5, 0x0000, 0, 0), @@ -116,6 +117,7 @@ enum { MX6_PAD_KEY_COL4__USB_USBOTG1_PWR = IOMUX_PAD(0x0484, 0x017C, 6, 0x0000, 0, 0), MX6_PAD_KEY_COL5__USB_USBOTG2_PWR = IOMUX_PAD(0x0488, 0x0180, 6, 0x0000, 0, 0), + MX6_PAD_KEY_COL6__GPIO_4_4 = IOMUX_PAD(0x048C, 0x0184, 5, 0x0000, 0, 0), MX6_PAD_ECSPI1_MISO__ECSPI1_MISO = IOMUX_PAD(0x0358, 0x0068, 0, 0x0684, 0, 0), MX6_PAD_ECSPI1_MOSI__ECSPI1_MOSI = IOMUX_PAD(0x035C, 0x006C, 0, 0x0688, 0, 0), MX6_PAD_ECSPI1_SCLK__ECSPI1_SCLK = IOMUX_PAD(0x0360, 0x0070, 0, 0x067C, 0, 0), diff --git a/board/freescale/mx6slevk/mx6slevk.c b/board/freescale/mx6slevk/mx6slevk.c index 9ff49b4..1c511cf 100644 --- a/board/freescale/mx6slevk/mx6slevk.c +++ b/board/freescale/mx6slevk/mx6slevk.c @@ -60,6 +60,8 @@ DECLARE_GLOBAL_DATA_PTR; PAD_CTL_DSE_40ohm | PAD_CTL_HYS | \ PAD_CTL_ODE | PAD_CTL_SRE_FAST) +#define ELAN_INTR_PAD_CTRL (PAD_CTL_PUS_47K_UP | PAD_CTL_HYS) + #define EPDC_PAD_CTRL (PAD_CTL_PKE | PAD_CTL_SPEED_MED | \ PAD_CTL_DSE_40ohm | PAD_CTL_HYS) @@ -149,6 +151,12 @@ static iomux_v3_cfg_t const fec_pads[] = { MX6_PAD_FEC_TX_CLK__GPIO_4_21 | MUX_PAD_CTRL(NO_PAD_CTRL), }; +static iomux_v3_cfg_t const elan_pads[] = { + MX6_PAD_EPDC_PWRCTRL2__GPIO_2_9 | MUX_PAD_CTRL(NO_PAD_CTRL), + MX6_PAD_EPDC_PWRCTRL3__GPIO_2_10 | MUX_PAD_CTRL(ELAN_INTR_PAD_CTRL), + MX6_PAD_KEY_COL6__GPIO_4_4 | MUX_PAD_CTRL(EPDC_PAD_CTRL), +}; + static iomux_v3_cfg_t const epdc_enable_pads[] = { MX6_PAD_EPDC_D0__EPDC_SDDO_0 | MUX_PAD_CTRL(EPDC_PAD_CTRL), MX6_PAD_EPDC_D1__EPDC_SDDO_1 | MUX_PAD_CTRL(EPDC_PAD_CTRL), @@ -853,6 +861,36 @@ int board_init(void) return 0; } +void setup_elan_pads(void) +{ +#define TOUCH_CS IMX_GPIO_NR(2, 9) +#define TOUCH_INT IMX_GPIO_NR(2, 10) +#define TOUCH_RST IMX_GPIO_NR(4, 4) + imx_iomux_v3_setup_multiple_pads(elan_pads, ARRAY_SIZE(elan_pads)); +} + +void elan_init(void) +{ + gpio_direction_input(TOUCH_INT); + gpio_direction_output(TOUCH_CS , 1); + gpio_set_value(TOUCH_CS, 0); + gpio_direction_output(TOUCH_RST , 1); + gpio_set_value(TOUCH_RST, 0); + mdelay(10); + gpio_set_value(TOUCH_RST, 1); + gpio_set_value(TOUCH_CS, 1); + mdelay(100); +} + +/* + * This function overwrite the function defined in + * drivers/i2c/mxc_i2c.c, which is a weak symbol + */ +void i2c_force_reset_slave(void) +{ + elan_init(); +} + int board_late_init(void) { int ret = 0; @@ -860,6 +898,7 @@ int board_late_init(void) #ifdef CONFIG_SYS_I2C_MXC setup_i2c(0, CONFIG_SYS_I2C_SPEED, 0x7f, &i2c_pad_info0); + setup_elan_pads(); ret = setup_pmic_voltages(); if (ret) return -1; diff --git a/drivers/i2c/mxc_i2c.c b/drivers/i2c/mxc_i2c.c index 4f73bdf..dc5d1fa 100644 --- a/drivers/i2c/mxc_i2c.c +++ b/drivers/i2c/mxc_i2c.c @@ -244,6 +244,17 @@ static void i2c_imx_stop(struct mxc_i2c_regs *i2c_regs) } /* + * Stub implementations for outer i2c slave operations + * Any board has special requirement (i.mx6slevk) can + * overwrite the function + */ +void __i2c_force_reset_slave(void) +{ +} +void i2c_force_reset_slave(void) + __attribute__((weak, alias("__i2c_force_reset_slave"))); + +/* * Send start signal, chip address and * write register address */ @@ -253,6 +264,9 @@ static int i2c_init_transfer_(struct mxc_i2c_regs *i2c_regs, unsigned int temp; int ret; + /* Reset i2c slave */ + i2c_force_reset_slave(); + /* Enable I2C controller */ #ifdef I2C_QUIRK_REG if (readb(&i2c_regs->i2cr) & I2CR_IDIS) { |