Skip to content

Commit

Permalink
i2c-s3c2410: Add HDMIPHY quirk for S3C2440
Browse files Browse the repository at this point in the history
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@samsung.com>
Signed-off-by: Karol Lewandowski <k.lewandowsk@samsung.com>
Tested-by: Tomasz Stanislawski <t.stanislaws@samsung.com>
Signed-off-by: Kyungmin Park <kyungmin.park@samsung.com>
Signed-off-by: Wolfram Sang <w.sang@pengutronix.de>
  • Loading branch information
Karol Lewandowski authored and Wolfram Sang committed May 12, 2012
1 parent 2745249 commit ec39ef8
Show file tree
Hide file tree
Showing 2 changed files with 36 additions and 2 deletions.
8 changes: 6 additions & 2 deletions Documentation/devicetree/bindings/i2c/samsung-i2c.txt
Original file line number Diff line number Diff line change
Expand Up @@ -6,14 +6,18 @@ Required properties:
- compatible: value should be either of the following.
(a) "samsung, s3c2410-i2c", for i2c compatible with s3c2410 i2c.
(b) "samsung, s3c2440-i2c", for i2c compatible with s3c2440 i2c.
(c) "samsung, s3c2440-hdmiphy-i2c", for s3c2440-like i2c used
inside HDMIPHY block found on several samsung SoCs
- reg: physical base address of the controller and length of memory mapped
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 for "samsung,s3c2440-hdmiphy-i2c" whose input/output
lines are permanently wired to the respective client
- 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
Expand Down
30 changes: 30 additions & 0 deletions drivers/i2c/busses/i2c-s3c2410.c
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,8 @@

/* 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 {
Expand Down Expand Up @@ -93,6 +95,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);
Expand All @@ -101,6 +106,8 @@ MODULE_DEVICE_TABLE(platform, s3c24xx_driver_ids);
static const struct of_device_id s3c24xx_i2c_match[] = {
{ .compatible = "samsung,s3c2410-i2c", .data = (void *)0 },
{ .compatible = "samsung,s3c2440-i2c", .data = (void *)QUIRK_S3C2440 },
{ .compatible = "samsung,s3c2440-hdmiphy-i2c",
.data = (void *)(QUIRK_S3C2440 | QUIRK_HDMIPHY | QUIRK_NO_GPIO) },
{},
};
MODULE_DEVICE_TABLE(of, s3c24xx_i2c_match);
Expand Down Expand Up @@ -483,6 +490,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);

Expand All @@ -492,6 +506,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;
}

Expand Down Expand Up @@ -773,6 +796,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)) {
Expand All @@ -797,6 +823,10 @@ static int s3c24xx_i2c_parse_dt_gpio(struct s3c24xx_i2c *i2c)
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]);
}
Expand Down

0 comments on commit ec39ef8

Please sign in to comment.