aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDaniel Silverstone <dsilvers@simtec.co.uk>2009-03-13 09:53:46 -0400
committerBen Dooks <ben-linux@fluff.org>2009-04-07 05:18:33 -0400
commitc564e6ae6c5aa6e3995ff87ed4a32b4788ad5109 (patch)
treeb773106104d9897d945709d3bff8a56ff6586da8
parenta192f7153bb33151f83440cd9c0442233a064bf1 (diff)
i2c-s3c2410: Simplify bus frequency calculation
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@simtec.co.uk> Signed-off-by: Daniel Silverstone <dsilvers@simtec.co.uk> [ben-linux@fluff.org: tidy subject and description] Signed-off-by: Ben Dooks <ben-linux@fluff.org>
-rw-r--r--arch/arm/mach-s3c2410/mach-bast.c3
-rw-r--r--arch/arm/mach-s3c2410/mach-n30.c3
-rw-r--r--arch/arm/mach-s3c2412/mach-jive.c3
-rw-r--r--arch/arm/plat-s3c/dev-i2c0.c5
-rw-r--r--arch/arm/plat-s3c/dev-i2c1.c5
-rw-r--r--arch/arm/plat-s3c/include/plat/iic.h33
-rw-r--r--drivers/i2c/busses/i2c-s3c2410.c50
7 files changed, 37 insertions, 65 deletions
diff --git a/arch/arm/mach-s3c2410/mach-bast.c b/arch/arm/mach-s3c2410/mach-bast.c
index 01bd76725b92..4389c160f7d0 100644
--- a/arch/arm/mach-s3c2410/mach-bast.c
+++ b/arch/arm/mach-s3c2410/mach-bast.c
@@ -409,8 +409,7 @@ static struct platform_device bast_sio = {
409static struct s3c2410_platform_i2c __initdata bast_i2c_info = { 409static struct s3c2410_platform_i2c __initdata bast_i2c_info = {
410 .flags = 0, 410 .flags = 0,
411 .slave_addr = 0x10, 411 .slave_addr = 0x10,
412 .bus_freq = 100*1000, 412 .frequency = 100*1000,
413 .max_freq = 130*1000,
414}; 413};
415 414
416/* Asix AX88796 10/100 ethernet controller */ 415/* Asix AX88796 10/100 ethernet controller */
diff --git a/arch/arm/mach-s3c2410/mach-n30.c b/arch/arm/mach-s3c2410/mach-n30.c
index 05a5e877b49b..2b83f8707710 100644
--- a/arch/arm/mach-s3c2410/mach-n30.c
+++ b/arch/arm/mach-s3c2410/mach-n30.c
@@ -340,8 +340,7 @@ static struct platform_device *n35_devices[] __initdata = {
340static struct s3c2410_platform_i2c n30_i2ccfg = { 340static struct s3c2410_platform_i2c n30_i2ccfg = {
341 .flags = 0, 341 .flags = 0,
342 .slave_addr = 0x10, 342 .slave_addr = 0x10,
343 .bus_freq = 10*1000, 343 .frequency = 10*1000,
344 .max_freq = 10*1000,
345}; 344};
346 345
347/* Lots of hardcoded stuff, but it sets up the hardware in a useful 346/* Lots of hardcoded stuff, but it sets up the hardware in a useful
diff --git a/arch/arm/mach-s3c2412/mach-jive.c b/arch/arm/mach-s3c2412/mach-jive.c
index 72c266aee141..332bd3263eaf 100644
--- a/arch/arm/mach-s3c2412/mach-jive.c
+++ b/arch/arm/mach-s3c2412/mach-jive.c
@@ -453,8 +453,7 @@ static struct spi_board_info __initdata jive_spi_devs[] = {
453/* I2C bus and device configuration. */ 453/* I2C bus and device configuration. */
454 454
455static struct s3c2410_platform_i2c jive_i2c_cfg __initdata = { 455static struct s3c2410_platform_i2c jive_i2c_cfg __initdata = {
456 .max_freq = 80 * 1000, 456 .frequency = 80 * 1000,
457 .bus_freq = 50 * 1000,
458 .flags = S3C_IICFLG_FILTER, 457 .flags = S3C_IICFLG_FILTER,
459 .sda_delay = 2, 458 .sda_delay = 2,
460}; 459};
diff --git a/arch/arm/plat-s3c/dev-i2c0.c b/arch/arm/plat-s3c/dev-i2c0.c
index 8eecb466ab4c..428372868fbb 100644
--- a/arch/arm/plat-s3c/dev-i2c0.c
+++ b/arch/arm/plat-s3c/dev-i2c0.c
@@ -1,6 +1,6 @@
1/* linux/arch/arm/plat-s3c/dev-i2c0.c 1/* linux/arch/arm/plat-s3c/dev-i2c0.c
2 * 2 *
3 * Copyright 2008 Simtec Electronics 3 * Copyright 2008,2009 Simtec Electronics
4 * Ben Dooks <ben@simtec.co.uk> 4 * Ben Dooks <ben@simtec.co.uk>
5 * http://armlinux.simtec.co.uk/ 5 * http://armlinux.simtec.co.uk/
6 * 6 *
@@ -50,8 +50,7 @@ struct platform_device s3c_device_i2c0 = {
50static struct s3c2410_platform_i2c default_i2c_data0 __initdata = { 50static struct s3c2410_platform_i2c default_i2c_data0 __initdata = {
51 .flags = 0, 51 .flags = 0,
52 .slave_addr = 0x10, 52 .slave_addr = 0x10,
53 .bus_freq = 100*1000, 53 .frequency = 100*1000,
54 .max_freq = 400*1000,
55 .sda_delay = 100, 54 .sda_delay = 100,
56}; 55};
57 56
diff --git a/arch/arm/plat-s3c/dev-i2c1.c b/arch/arm/plat-s3c/dev-i2c1.c
index 4536e5bb50e5..8349c462788c 100644
--- a/arch/arm/plat-s3c/dev-i2c1.c
+++ b/arch/arm/plat-s3c/dev-i2c1.c
@@ -1,6 +1,6 @@
1/* linux/arch/arm/plat-s3c/dev-i2c1.c 1/* linux/arch/arm/plat-s3c/dev-i2c1.c
2 * 2 *
3 * Copyright 2008 Simtec Electronics 3 * Copyright 2008,2009 Simtec Electronics
4 * Ben Dooks <ben@simtec.co.uk> 4 * Ben Dooks <ben@simtec.co.uk>
5 * http://armlinux.simtec.co.uk/ 5 * http://armlinux.simtec.co.uk/
6 * 6 *
@@ -47,8 +47,7 @@ static struct s3c2410_platform_i2c default_i2c_data1 __initdata = {
47 .flags = 0, 47 .flags = 0,
48 .bus_num = 1, 48 .bus_num = 1,
49 .slave_addr = 0x10, 49 .slave_addr = 0x10,
50 .bus_freq = 100*1000, 50 .frequency = 100*1000,
51 .max_freq = 400*1000,
52 .sda_delay = 100, 51 .sda_delay = 100,
53}; 52};
54 53
diff --git a/arch/arm/plat-s3c/include/plat/iic.h b/arch/arm/plat-s3c/include/plat/iic.h
index dc1dfcb9bc6c..67450f115748 100644
--- a/arch/arm/plat-s3c/include/plat/iic.h
+++ b/arch/arm/plat-s3c/include/plat/iic.h
@@ -1,9 +1,9 @@
1/* arch/arm/mach-s3c2410/include/mach/iic.h 1/* arch/arm/plat-s3c/include/plat/iic.h
2 * 2 *
3 * Copyright (c) 2004 Simtec Electronics 3 * Copyright 2004,2009 Simtec Electronics
4 * Ben Dooks <ben@simtec.co.uk> 4 * Ben Dooks <ben@simtec.co.uk>
5 * 5 *
6 * S3C2410 - I2C Controller platfrom_device info 6 * S3C - I2C Controller platform_device info
7 * 7 *
8 * This program is free software; you can redistribute it and/or modify 8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License version 2 as 9 * it under the terms of the GNU General Public License version 2 as
@@ -15,19 +15,24 @@
15 15
16#define S3C_IICFLG_FILTER (1<<0) /* enable s3c2440 filter */ 16#define S3C_IICFLG_FILTER (1<<0) /* enable s3c2440 filter */
17 17
18/* Notes: 18/**
19 * 1) All frequencies are expressed in Hz 19 * struct s3c2410_platform_i2c - Platform data for s3c I2C.
20 * 2) A value of zero is `do not care` 20 * @bus_num: The bus number to use (if possible).
21*/ 21 * @flags: Any flags for the I2C bus (E.g. S3C_IICFLK_FILTER).
22 22 * @slave_addr: The I2C address for the slave device (if enabled).
23 * @frequency: The desired frequency in Hz of the bus. This is
24 * guaranteed to not be exceeded. If the caller does
25 * not care, use zero and the driver will select a
26 * useful default.
27 * @sda_delay: The delay (in ns) applied to SDA edges.
28 * @cfg_gpio: A callback to configure the pins for I2C operation.
29 */
23struct s3c2410_platform_i2c { 30struct s3c2410_platform_i2c {
24 int bus_num; /* bus number to use */ 31 int bus_num;
25 unsigned int flags; 32 unsigned int flags;
26 unsigned int slave_addr; /* slave address for controller */ 33 unsigned int slave_addr;
27 unsigned long bus_freq; /* standard bus frequency */ 34 unsigned long frequency;
28 unsigned long max_freq; /* max frequency for the bus */ 35 unsigned int sda_delay;
29 unsigned long min_freq; /* min frequency for the bus */
30 unsigned int sda_delay; /* pclks (s3c2440 only) */
31 36
32 void (*cfg_gpio)(struct platform_device *dev); 37 void (*cfg_gpio)(struct platform_device *dev);
33}; 38};
diff --git a/drivers/i2c/busses/i2c-s3c2410.c b/drivers/i2c/busses/i2c-s3c2410.c
index 9d797561de5f..e10a59e7db6f 100644
--- a/drivers/i2c/busses/i2c-s3c2410.c
+++ b/drivers/i2c/busses/i2c-s3c2410.c
@@ -1,6 +1,6 @@
1/* linux/drivers/i2c/busses/i2c-s3c2410.c 1/* linux/drivers/i2c/busses/i2c-s3c2410.c
2 * 2 *
3 * Copyright (C) 2004,2005 Simtec Electronics 3 * Copyright (C) 2004,2005,2009 Simtec Electronics
4 * Ben Dooks <ben@simtec.co.uk> 4 * Ben Dooks <ben@simtec.co.uk>
5 * 5 *
6 * S3C2410 I2C Controller 6 * S3C2410 I2C Controller
@@ -590,18 +590,6 @@ static int s3c24xx_i2c_calcdivisor(unsigned long clkin, unsigned int wanted,
590 return clkin / (calc_divs * calc_div1); 590 return clkin / (calc_divs * calc_div1);
591} 591}
592 592
593/* freq_acceptable
594 *
595 * test wether a frequency is within the acceptable range of error
596*/
597
598static inline int freq_acceptable(unsigned int freq, unsigned int wanted)
599{
600 int diff = freq - wanted;
601
602 return diff >= -2 && diff <= 2;
603}
604
605/* s3c24xx_i2c_clockrate 593/* s3c24xx_i2c_clockrate
606 * 594 *
607 * work out a divisor for the user requested frequency setting, 595 * work out a divisor for the user requested frequency setting,
@@ -614,44 +602,28 @@ static int s3c24xx_i2c_clockrate(struct s3c24xx_i2c *i2c, unsigned int *got)
614 struct s3c2410_platform_i2c *pdata = i2c->dev->platform_data; 602 struct s3c2410_platform_i2c *pdata = i2c->dev->platform_data;
615 unsigned long clkin = clk_get_rate(i2c->clk); 603 unsigned long clkin = clk_get_rate(i2c->clk);
616 unsigned int divs, div1; 604 unsigned int divs, div1;
605 unsigned long target_frequency;
617 u32 iiccon; 606 u32 iiccon;
618 int freq; 607 int freq;
619 int start, end;
620 608
621 i2c->clkrate = clkin; 609 i2c->clkrate = clkin;
622 clkin /= 1000; /* clkin now in KHz */ 610 clkin /= 1000; /* clkin now in KHz */
623 611
624 dev_dbg(i2c->dev, "pdata %p, freq %lu %lu..%lu\n", 612 dev_dbg(i2c->dev, "pdata desired frequency %lu\n", pdata->frequency);
625 pdata, pdata->bus_freq, pdata->min_freq, pdata->max_freq);
626 613
627 if (pdata->bus_freq != 0) { 614 target_frequency = pdata->frequency ? pdata->frequency : 100000;
628 freq = s3c24xx_i2c_calcdivisor(clkin, pdata->bus_freq/1000,
629 &div1, &divs);
630 if (freq_acceptable(freq, pdata->bus_freq/1000))
631 goto found;
632 }
633
634 /* ok, we may have to search for something suitable... */
635
636 start = (pdata->max_freq == 0) ? pdata->bus_freq : pdata->max_freq;
637 end = pdata->min_freq;
638 615
639 start /= 1000; 616 target_frequency /= 1000; /* Target frequency now in KHz */
640 end /= 1000;
641 617
642 /* search loop... */ 618 freq = s3c24xx_i2c_calcdivisor(clkin, target_frequency, &div1, &divs);
643 619
644 for (; start > end; start--) { 620 if (freq > target_frequency) {
645 freq = s3c24xx_i2c_calcdivisor(clkin, start, &div1, &divs); 621 dev_err(i2c->dev,
646 if (freq_acceptable(freq, start)) 622 "Unable to achieve desired frequency %luKHz." \
647 goto found; 623 " Lowest achievable %dKHz\n", target_frequency, freq);
624 return -EINVAL;
648 } 625 }
649 626
650 /* cannot find frequency spec */
651
652 return -EINVAL;
653
654 found:
655 *got = freq; 627 *got = freq;
656 628
657 iiccon = readl(i2c->regs + S3C2410_IICCON); 629 iiccon = readl(i2c->regs + S3C2410_IICCON);