| i2c-s3c2440-shannon2.patch
|
| Files affected:
|   drivers/i2c/busses/i2c-s3c2410.c |   45 	40 +	5 -	0 !
|   1 files changed, 40 insertions(+), 5 deletions(-)
|
| Ben Dooks, Mon, 08 Nov 2004 10:54:46 +0000

diff -urN -X ../dontdiff linux-2.6.10-rc1-bk14-serial1/drivers/i2c/busses/i2c-s3c2410.c linux-2.6.10-rc1-bk14-serial1-work/drivers/i2c/busses/i2c-s3c2410.c
--- linux-2.6.10-rc1-bk14-serial1/drivers/i2c/busses/i2c-s3c2410.c	2004-11-04 17:22:46.000000000 +0000
+++ linux-2.6.10-rc1-bk14-serial1-work/drivers/i2c/busses/i2c-s3c2410.c	2004-11-08 10:03:58.000000000 +0000
@@ -72,7 +72,7 @@
 	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 @@
 	.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 @@
 {
 	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 @@
 	// 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 @@
 		    !(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 @@
 
 	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 @@
 	*divs = calc_divs;
 	*div1 = calc_div1;
 
-	return clkin / (calc_divs + calc_div1);
+	return clkin / (calc_divs * calc_div1);
 }
 
 /* freq_acceptable
@@ -683,6 +707,17 @@
 	/* 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;
 }
