diff options
| author | Daniel Silverstone <dsilvers@simtec.co.uk> | 2009-03-13 09:53:46 -0400 |
|---|---|---|
| committer | Ben Dooks <ben-linux@fluff.org> | 2009-04-07 05:18:33 -0400 |
| commit | c564e6ae6c5aa6e3995ff87ed4a32b4788ad5109 (patch) | |
| tree | b773106104d9897d945709d3bff8a56ff6586da8 | |
| parent | a192f7153bb33151f83440cd9c0442233a064bf1 (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.c | 3 | ||||
| -rw-r--r-- | arch/arm/mach-s3c2410/mach-n30.c | 3 | ||||
| -rw-r--r-- | arch/arm/mach-s3c2412/mach-jive.c | 3 | ||||
| -rw-r--r-- | arch/arm/plat-s3c/dev-i2c0.c | 5 | ||||
| -rw-r--r-- | arch/arm/plat-s3c/dev-i2c1.c | 5 | ||||
| -rw-r--r-- | arch/arm/plat-s3c/include/plat/iic.h | 33 | ||||
| -rw-r--r-- | drivers/i2c/busses/i2c-s3c2410.c | 50 |
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 = { | |||
| 409 | static struct s3c2410_platform_i2c __initdata bast_i2c_info = { | 409 | static 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 = { | |||
| 340 | static struct s3c2410_platform_i2c n30_i2ccfg = { | 340 | static 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 | ||
| 455 | static struct s3c2410_platform_i2c jive_i2c_cfg __initdata = { | 455 | static 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 = { | |||
| 50 | static struct s3c2410_platform_i2c default_i2c_data0 __initdata = { | 50 | static 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 | */ | ||
| 23 | struct s3c2410_platform_i2c { | 30 | struct 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 | |||
| 598 | static 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); |
