diff options
| author | Ben Dooks <ben-linux@fluff.org> | 2004-11-08 00:45:59 -0800 |
|---|---|---|
| committer | Greg Kroah-Hartman <greg@kroah.com> | 2004-11-08 00:45:59 -0800 |
| commit | e786eacb4d5cc8722e5b891d44380975a3cbdfc4 (patch) | |
| tree | e4845c347896034c17686da10f34640b2fb1da21 | |
| parent | 80d15eb2b275e8ff4593cddab1b877f74a0872d5 (diff) | |
[PATCH] S3C2410 i2c updates
This patch integrates several fixes to the s3c2410 i2c
driver
Shannon Holland:
- write IICCON in configuration code
- add handling for s3c2410 i2c errata
- fix clock rate divisor calculation
Ben Dooks:
- s3c2440 detection
- s3c2440 IICLC register setup
- add __exit to the module exit
- remove return from exit code
Signed-off-by: Ben Dooks <ben-linux@fluff.org>
Signed-off-by: Shannon Holland <holland@loser.net>
Signed-off-by: Greg Kroah-Hartman <greg@kroah.com>
| -rw-r--r-- | drivers/i2c/busses/i2c-s3c2410.c | 68 |
1 files changed, 59 insertions, 9 deletions
diff --git a/drivers/i2c/busses/i2c-s3c2410.c b/drivers/i2c/busses/i2c-s3c2410.c index 5c1314629be5..9cb69744a71b 100644 --- a/drivers/i2c/busses/i2c-s3c2410.c +++ b/drivers/i2c/busses/i2c-s3c2410.c @@ -72,7 +72,7 @@ struct s3c24xx_i2c { struct i2c_adapter adap; }; -/* default platform data to use if not supplied in the platfrom_device +/* default platform data to use if not supplied in the platform_device */ static struct s3c2410_platform_i2c s3c24xx_i2c_default_platform = { @@ -80,8 +80,21 @@ static struct s3c2410_platform_i2c s3c24xx_i2c_default_platform = { .slave_addr = 0x10, .bus_freq = 100*1000, .max_freq = 400*1000, + .sda_delay = S3C2410_IICLC_SDA_DELAY5 | S3C2410_IICLC_FILTER_ON, }; +/* s3c24xx_i2c_is2440() + * + * return true is this is an s3c2440 +*/ + +static inline int s3c24xx_i2c_is2440(struct s3c24xx_i2c *i2c) +{ + struct platform_device *pdev = to_platform_device(i2c->dev); + + return !strcmp(pdev->name, "s3c2440-i2c"); +} + /* s3c24xx_i2c_get_platformdata * @@ -164,10 +177,9 @@ static void s3c24xx_i2c_message_start(struct s3c24xx_i2c *i2c, { unsigned int addr = (msg->addr & 0x7f) << 1; unsigned long stat; + unsigned long iiccon; - stat = readl(i2c->regs + S3C2410_IICSTAT); - stat &= ~S3C2410_IICSTAT_MODEMASK; - stat |= S3C2410_IICSTAT_START; + stat = 0; stat |= S3C2410_IICSTAT_TXRXEN; if (msg->flags & I2C_M_RD) { @@ -179,8 +191,18 @@ static void s3c24xx_i2c_message_start(struct s3c24xx_i2c *i2c, // todo - check for wether ack wanted or not s3c24xx_i2c_enable_ack(i2c); + iiccon = readl(i2c->regs + S3C2410_IICCON); + writel(stat, i2c->regs + S3C2410_IICSTAT); + dev_dbg(i2c->dev, "START: %08lx to IICSTAT, %02x to DS\n", stat, addr); writeb(addr, i2c->regs + S3C2410_IICDS); + + // delay a bit and reset iiccon before setting start (per samsung) + udelay(1); + dev_dbg(i2c->dev, "iiccon, %08lx\n", iiccon); + writel(iiccon, i2c->regs + S3C2410_IICCON); + + stat |= S3C2410_IICSTAT_START; writel(stat, i2c->regs + S3C2410_IICSTAT); } @@ -265,6 +287,7 @@ static int i2s_s3c_irq_nextbyte(struct s3c24xx_i2c *i2c, unsigned long iicstat) !(i2c->msg->flags & I2C_M_IGNORE_NAK)) { /* ack was not received... */ + dev_err(i2c->dev, "ack was not received\n" ); s3c24xx_i2c_stop(i2c, -EREMOTEIO); goto out_ack; } @@ -408,6 +431,7 @@ static irqreturn_t s3c24xx_i2c_irq(int irqno, void *dev_id, if (status & S3C2410_IICSTAT_ARBITR) { // deal with arbitration loss + dev_err(i2c->dev, "deal with arbitration loss\n"); } if (i2c->state == STATE_IDLE) { @@ -575,7 +599,7 @@ static int s3c24xx_i2c_calcdivisor(unsigned long clkin, unsigned int wanted, *divs = calc_divs; *div1 = calc_div1; - return clkin / (calc_divs + calc_div1); + return clkin / (calc_divs * calc_div1); } /* freq_acceptable @@ -683,6 +707,17 @@ static int s3c24xx_i2c_init(struct s3c24xx_i2c *i2c) /* todo - check that the i2c lines aren't being dragged anywhere */ dev_info(i2c->dev, "bus frequency set to %d KHz\n", freq); + dev_dbg(i2c->dev, "S3C2410_IICCON=0x%02lx\n", iicon); + + writel(iicon, i2c->regs + S3C2410_IICCON); + + /* check for s3c2440 i2c controller */ + + if (s3c24xx_i2c_is2440(i2c)) { + dev_dbg(i2c->dev, "S3C2440_IICLC=%08x\n", pdata->sda_delay); + + writel(pdata->sda_delay, i2c->regs + S3C2440_IICLC); + } return 0; } @@ -850,7 +885,7 @@ static int s3c24xx_i2c_resume(struct device *dev, u32 level) /* device driver for platform bus bits */ -static struct device_driver s3c24xx_i2c_driver = { +static struct device_driver s3c2410_i2c_driver = { .name = "s3c2410-i2c", .bus = &platform_bus_type, .probe = s3c24xx_i2c_probe, @@ -858,14 +893,29 @@ static struct device_driver s3c24xx_i2c_driver = { .resume = s3c24xx_i2c_resume, }; +static struct device_driver s3c2440_i2c_driver = { + .name = "s3c2440-i2c", + .bus = &platform_bus_type, + .probe = s3c24xx_i2c_probe, + .remove = s3c24xx_i2c_remove, + .resume = s3c24xx_i2c_resume, +}; + static int __init i2c_adap_s3c_init(void) { - return driver_register(&s3c24xx_i2c_driver); + int ret; + + ret = driver_register(&s3c2410_i2c_driver); + if (ret == 0) + ret = driver_register(&s3c2440_i2c_driver); + + return ret; } -static void i2c_adap_s3c_exit(void) +static void __exit i2c_adap_s3c_exit(void) { - return driver_unregister(&s3c24xx_i2c_driver); + driver_unregister(&s3c2410_i2c_driver); + driver_unregister(&s3c2440_i2c_driver); } module_init(i2c_adap_s3c_init); |
