[PATCH] Bugfix for i2c-s3c2410

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



I2C: Rework i2c-s3c2410 frequency calculator to be much simpler.

The platform data for the i2c-s3c2410 driver used to allow a min,
max and desired frequency for the I2C bus. This patch reduces it
to simply a desired frequency ceiling and corrects all the uses
of the platform data appropriately.

This means, for example, that on a system with a 66MHz fclk, a
request for 100KHz will achieve 65KHz which is safe and
acceptable, rather than 378KHz which it would have achieved
without this change.

Signed-off-by: Simtec Linux Team <linux@xxxxxxxxxxxx>
Signed-off-by: Daniel Silverstone <dsilvers@xxxxxxxxxxxx>

---
 arch/arm/mach-s3c2410/mach-bast.c    |    3 --
 arch/arm/mach-s3c2410/mach-n30.c     |    3 --
 arch/arm/mach-s3c2412/mach-jive.c    |    3 --
 arch/arm/plat-s3c/dev-i2c0.c         |    5 +--
 arch/arm/plat-s3c/dev-i2c1.c         |    5 +--
 arch/arm/plat-s3c/include/plat/iic.h |   33 +++++++++++++----------
 drivers/i2c/busses/i2c-s3c2410.c     |   50 +++++++----------------------------
 7 files changed, 36 insertions(+), 66 deletions(-)

Index: b/drivers/i2c/busses/i2c-s3c2410.c
===================================================================
--- a/drivers/i2c/busses/i2c-s3c2410.c	2009-02-12 09:58:30.866611025 +0000
+++ b/drivers/i2c/busses/i2c-s3c2410.c	2009-02-12 10:24:29.530615073 +0000
@@ -1,6 +1,6 @@
 /* linux/drivers/i2c/busses/i2c-s3c2410.c
  *
- * Copyright (C) 2004,2005 Simtec Electronics
+ * Copyright (C) 2004,2005,2009 Simtec Electronics
  *	Ben Dooks <ben@xxxxxxxxxxxx>
  *
  * S3C2410 I2C Controller
@@ -590,18 +590,6 @@ static int s3c24xx_i2c_calcdivisor(unsig
 	return clkin / (calc_divs * calc_div1);
 }
 
-/* freq_acceptable
- *
- * test wether a frequency is within the acceptable range of error
-*/
-
-static inline int freq_acceptable(unsigned int freq, unsigned int wanted)
-{
-	int diff = freq - wanted;
-
-	return diff >= -2 && diff <= 2;
-}
-
 /* s3c24xx_i2c_clockrate
  *
  * work out a divisor for the user requested frequency setting,
@@ -614,44 +602,26 @@ static int s3c24xx_i2c_clockrate(struct 
 	struct s3c2410_platform_i2c *pdata = i2c->dev->platform_data;
 	unsigned long clkin = clk_get_rate(i2c->clk);
 	unsigned int divs, div1;
+	unsigned long target_frequency;
 	u32 iiccon;
 	int freq;
-	int start, end;
 
 	i2c->clkrate = clkin;
 	clkin /= 1000;		/* clkin now in KHz */
 
-	dev_dbg(i2c->dev, "pdata %p, freq %lu %lu..%lu\n",
-		 pdata, pdata->bus_freq, pdata->min_freq, pdata->max_freq);
+	dev_dbg(i2c->dev, "pdata desired frequency %lu\n", pdata->frequency);
 
-	if (pdata->bus_freq != 0) {
-		freq = s3c24xx_i2c_calcdivisor(clkin, pdata->bus_freq/1000,
-					       &div1, &divs);
-		if (freq_acceptable(freq, pdata->bus_freq/1000))
-			goto found;
-	}
-
-	/* ok, we may have to search for something suitable... */
-
-	start = (pdata->max_freq == 0) ? pdata->bus_freq : pdata->max_freq;
-	end = pdata->min_freq;
-
-	start /= 1000;
-	end /= 1000;
+	target_frequency = pdata->frequency ? pdata->frequency : 100000;
 
-	/* search loop... */
+	freq = s3c24xx_i2c_calcdivisor(clkin, target_frequency, &div1, &divs);
 
-	for (; start > end; start--) {
-		freq = s3c24xx_i2c_calcdivisor(clkin, start, &div1, &divs);
-		if (freq_acceptable(freq, start))
-			goto found;
+	if (freq > target_frequency) {
+		dev_err(i2c->dev,
+			"Unable to achieve desired frequency %luKHz."	\
+			" Lowest achievable %dKHz\n", target_frequency, freq);
+		return -EINVAL;
 	}
 
-	/* cannot find frequency spec */
-
-	return -EINVAL;
-
- found:
 	*got = freq;
 
 	iiccon = readl(i2c->regs + S3C2410_IICCON);
Index: b/arch/arm/plat-s3c/include/plat/iic.h
===================================================================
--- a/arch/arm/plat-s3c/include/plat/iic.h	2009-02-12 09:43:10.599030214 +0000
+++ b/arch/arm/plat-s3c/include/plat/iic.h	2009-02-12 10:24:29.502615860 +0000
@@ -1,9 +1,9 @@
-/* arch/arm/mach-s3c2410/include/mach/iic.h
+/* arch/arm/plat-s3c/include/plat/iic.h
  *
- * Copyright (c) 2004 Simtec Electronics
+ * Copyright 2004,2009 Simtec Electronics
  *	Ben Dooks <ben@xxxxxxxxxxxx>
  *
- * S3C2410 - I2C Controller platfrom_device info
+ * S3C - I2C Controller platform_device info
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 as
@@ -15,19 +15,24 @@
 
 #define S3C_IICFLG_FILTER	(1<<0)	/* enable s3c2440 filter */
 
-/* Notes:
- *	1) All frequencies are expressed in Hz
- *	2) A value of zero is `do not care`
-*/
-
+/**
+ *	struct s3c2410_platform_i2c - Platform data for s3c I2C.
+ *	@bus_num: The bus number to use (if possible).
+ *	@flags: Any flags for the I2C bus (E.g. S3C_IICFLK_FILTER).
+ *	@slave_addr: The I2C address for the slave device (if enabled).
+ *	@frequency: The desired frequency in Hz of the bus.  This is
+ *                  guaranteed to not be exceeded.  If the caller does
+ *                  not care, use zero and the driver will select a
+ *                  useful default.
+ *	@sda_delay: The delay (in ns) applied to SDA edges.
+ *	@cfg_gpio: A callback to configure the pins for I2C operation.
+ */
 struct s3c2410_platform_i2c {
-	int		bus_num;	/* bus number to use */
+	int		bus_num;
 	unsigned int	flags;
-	unsigned int	slave_addr;	/* slave address for controller */
-	unsigned long	bus_freq;	/* standard bus frequency */
-	unsigned long	max_freq;	/* max frequency for the bus */
-	unsigned long	min_freq;	/* min frequency for the bus */
-	unsigned int	sda_delay;	/* pclks (s3c2440 only) */
+	unsigned int	slave_addr;
+	unsigned long	frequency;
+	unsigned int	sda_delay;
 
 	void	(*cfg_gpio)(struct platform_device *dev);
 };
Index: b/arch/arm/plat-s3c/dev-i2c0.c
===================================================================
--- a/arch/arm/plat-s3c/dev-i2c0.c	2009-02-12 09:58:30.866611025 +0000
+++ b/arch/arm/plat-s3c/dev-i2c0.c	2009-02-12 10:24:29.450615087 +0000
@@ -1,6 +1,6 @@
 /* linux/arch/arm/plat-s3c/dev-i2c0.c
  *
- * Copyright 2008 Simtec Electronics
+ * Copyright 2008,2009 Simtec Electronics
  *	Ben Dooks <ben@xxxxxxxxxxxx>
  *	http://armlinux.simtec.co.uk/
  *
@@ -50,8 +50,7 @@ struct platform_device s3c_device_i2c0 =
 static struct s3c2410_platform_i2c default_i2c_data0 __initdata = {
 	.flags		= 0,
 	.slave_addr	= 0x10,
-	.bus_freq	= 100*1000,
-	.max_freq	= 400*1000,
+	.frequency	= 100*1000,
 	.sda_delay	= 100,
 };
 
Index: b/arch/arm/plat-s3c/dev-i2c1.c
===================================================================
--- a/arch/arm/plat-s3c/dev-i2c1.c	2009-02-12 09:58:30.910131374 +0000
+++ b/arch/arm/plat-s3c/dev-i2c1.c	2009-02-12 10:24:29.466616700 +0000
@@ -1,6 +1,6 @@
 /* linux/arch/arm/plat-s3c/dev-i2c1.c
  *
- * Copyright 2008 Simtec Electronics
+ * Copyright 2008,2009 Simtec Electronics
  *	Ben Dooks <ben@xxxxxxxxxxxx>
  *	http://armlinux.simtec.co.uk/
  *
@@ -47,8 +47,7 @@ static struct s3c2410_platform_i2c defau
 	.flags		= 0,
 	.bus_num	= 1,
 	.slave_addr	= 0x10,
-	.bus_freq	= 100*1000,
-	.max_freq	= 400*1000,
+	.frequency	= 100*1000,
 	.sda_delay	= 100,
 };
 
Index: b/arch/arm/mach-s3c2410/mach-bast.c
===================================================================
--- a/arch/arm/mach-s3c2410/mach-bast.c	2009-02-12 09:42:49.254613471 +0000
+++ b/arch/arm/mach-s3c2410/mach-bast.c	2009-02-12 10:24:29.394616021 +0000
@@ -409,8 +409,7 @@ static struct platform_device bast_sio =
 static struct s3c2410_platform_i2c __initdata bast_i2c_info = {
 	.flags		= 0,
 	.slave_addr	= 0x10,
-	.bus_freq	= 100*1000,
-	.max_freq	= 130*1000,
+	.frequency	= 100*1000,
 };
 
 /* Asix AX88796 10/100 ethernet controller */
Index: b/arch/arm/mach-s3c2410/mach-n30.c
===================================================================
--- a/arch/arm/mach-s3c2410/mach-n30.c	2009-02-12 09:42:49.842111069 +0000
+++ b/arch/arm/mach-s3c2410/mach-n30.c	2009-02-12 10:24:29.410614435 +0000
@@ -340,8 +340,7 @@ static struct platform_device *n35_devic
 static struct s3c2410_platform_i2c n30_i2ccfg = {
 	.flags		= 0,
 	.slave_addr	= 0x10,
-	.bus_freq	= 10*1000,
-	.max_freq	= 10*1000,
+	.frequency	= 10*1000,
 };
 
 /* Lots of hardcoded stuff, but it sets up the hardware in a useful
Index: b/arch/arm/mach-s3c2412/mach-jive.c
===================================================================
--- a/arch/arm/mach-s3c2412/mach-jive.c	2009-02-12 09:42:50.430341907 +0000
+++ b/arch/arm/mach-s3c2412/mach-jive.c	2009-02-12 10:24:29.430615021 +0000
@@ -453,8 +453,7 @@ static struct spi_board_info __initdata 
 /* I2C bus and device configuration. */
 
 static struct s3c2410_platform_i2c jive_i2c_cfg __initdata = {
-	.max_freq	= 80 * 1000,
-	.bus_freq	= 50 * 1000,
+	.frequency	= 80 * 1000,
 	.flags		= S3C_IICFLG_FILTER,
 	.sda_delay	= 2,
 };

-- 
Daniel Silverstone                              http://www.simtec.co.uk/
PGP mail accepted and encouraged.            Key Id: 2BC8 4016 2068 7895


--
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

[Index of Archives]     [Linux GPIO]     [Linux SPI]     [Linux Hardward Monitoring]     [LM Sensors]     [Linux USB Devel]     [Linux Media]     [Video for Linux]     [Linux Audio Users]     [Yosemite News]     [Linux Kernel]     [Linux SCSI]

  Powered by Linux