This patch adds support for s3c2440 I2C bus controller dedicated HDMIPHY device on Exynos4 platform. Some quirks are introduced due to differences between HDMIPHY and other I2C controllers on Exynos4. These differences are: - no GPIOs, HDMIPHY is inside the SoC and the controller is connected internally - due to unknown reason (probably HW bug in HDMIPHY and/or the controller) a transfer fails to finish. The controller hangs after sending the last byte, the workaround for this bug is resetting the controller after each transfer Signed-off-by: Tomasz Stanislawski <t.stanislaws@xxxxxxxxxxx> Signed-off-by: Karol Lewandowski <k.lewandowsk@xxxxxxxxxxx> Tested-by: Tomasz Stanislawski <t.stanislaws@xxxxxxxxxxx> Signed-off-by: Kyungmin Park <kyungmin.park@xxxxxxxxxxx> --- .../devicetree/bindings/i2c/samsung-i2c.txt | 11 +++++- drivers/i2c/busses/i2c-s3c2410.c | 35 ++++++++++++++++++++ 2 files changed, 44 insertions(+), 2 deletions(-) diff --git a/Documentation/devicetree/bindings/i2c/samsung-i2c.txt b/Documentation/devicetree/bindings/i2c/samsung-i2c.txt index 38832c7..c6670f9 100644 --- a/Documentation/devicetree/bindings/i2c/samsung-i2c.txt +++ b/Documentation/devicetree/bindings/i2c/samsung-i2c.txt @@ -10,14 +10,21 @@ Required properties: region. - interrupts: interrupt number to the cpu. - samsung,i2c-sda-delay: Delay (in ns) applied to data line (SDA) edges. - - gpios: The order of the gpios should be the following: <SDA, SCL>. - The gpio specifier depends on the gpio controller. Optional properties: + - gpios: The order of the gpios should be the following: <SDA, SCL>. + The gpio specifier depends on the gpio controller. Required in all cases + except when "samsung,i2c-no-gpio" is also specified. + - samsung,i2c-no-gpio: input/output lines of the controller are + permanently wired to the respective client, there are no gpio + lines that need to be configured to enable this controller - samsung,i2c-slave-addr: Slave address in multi-master enviroment. If not specified, default value is 0. - samsung,i2c-max-bus-freq: Desired frequency in Hz of the bus. If not specified, the default value in Hz is 100000. + - samsung,i2c-quirk-hdmiphy: Quirk for HDMI PHY block found on + Exynos4 platform - reduce timeout and reset controller after each + transfer Example: diff --git a/drivers/i2c/busses/i2c-s3c2410.c b/drivers/i2c/busses/i2c-s3c2410.c index f7b6a14..e50f523 100644 --- a/drivers/i2c/busses/i2c-s3c2410.c +++ b/drivers/i2c/busses/i2c-s3c2410.c @@ -50,6 +50,8 @@ static const struct of_device_id s3c24xx_i2c_match[]; /* Treat S3C2410 as baseline hardware, anything else is supported via quirks */ #define QUIRK_S3C2440 (1 << 0) +#define QUIRK_HDMIPHY (1 << 1) +#define QUIRK_NO_GPIO (1 << 2) /* i2c controller state */ enum s3c24xx_i2c_state { @@ -469,6 +471,13 @@ static int s3c24xx_i2c_set_master(struct s3c24xx_i2c *i2c) unsigned long iicstat; int timeout = 400; + /* the timeout for HDMIPHY is reduced to 10 ms because + * the hangup is expected to happen, so waiting 400 ms + * causes only unnecessary system hangup + */ + if (i2c->quirks & QUIRK_HDMIPHY) + timeout = 10; + while (timeout-- > 0) { iicstat = readl(i2c->regs + S3C2410_IICSTAT); @@ -478,6 +487,15 @@ static int s3c24xx_i2c_set_master(struct s3c24xx_i2c *i2c) msleep(1); } + /* hang-up of bus dedicated for HDMIPHY occurred, resetting */ + if (i2c->quirks & QUIRK_HDMIPHY) { + writel(0, i2c->regs + S3C2410_IICCON); + writel(0, i2c->regs + S3C2410_IICSTAT); + writel(0, i2c->regs + S3C2410_IICDS); + + return 0; + } + return -ETIMEDOUT; } @@ -759,6 +777,9 @@ static int s3c24xx_i2c_parse_dt_gpio(struct s3c24xx_i2c *i2c) { int idx, gpio, ret; + if (i2c->quirks & QUIRK_NO_GPIO) + return 0; + for (idx = 0; idx < 2; idx++) { gpio = of_get_gpio(i2c->dev->of_node, idx); if (!gpio_is_valid(gpio)) { @@ -783,6 +804,10 @@ free_gpio: static void s3c24xx_i2c_dt_gpio_free(struct s3c24xx_i2c *i2c) { unsigned int idx; + + if (i2c->quirks & QUIRK_NO_GPIO) + return; + for (idx = 0; idx < 2; idx++) gpio_free(i2c->gpios[idx]); } @@ -859,6 +884,13 @@ s3c24xx_i2c_parse_dt(struct device_node *np, struct s3c24xx_i2c *i2c) return; pdata->bus_num = -1; /* i2c bus number is dynamically assigned */ + + if (of_get_property(np, "samsung,i2c-quirk-hdmiphy", NULL)) + i2c->quirks |= QUIRK_HDMIPHY; + + if (of_get_property(np, "samsung,i2c-no-gpio", NULL)) + i2c->quirks |= QUIRK_NO_GPIO; + of_property_read_u32(np, "samsung,i2c-sda-delay", &pdata->sda_delay); of_property_read_u32(np, "samsung,i2c-slave-addr", &pdata->slave_addr); of_property_read_u32(np, "samsung,i2c-max-bus-freq", @@ -1116,6 +1148,9 @@ static struct platform_device_id s3c24xx_driver_ids[] = { }, { .name = "s3c2440-i2c", .driver_data = QUIRK_S3C2440, + }, { + .name = "s3c2440-hdmiphy-i2c", + .driver_data = QUIRK_S3C2440 | QUIRK_HDMIPHY | QUIRK_NO_GPIO, }, { }, }; MODULE_DEVICE_TABLE(platform, s3c24xx_driver_ids); -- 1.7.9 -- To unsubscribe from this list: send the line "unsubscribe linux-i2c" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html