Commit c564e6ae6c5aa6e3995ff87ed4a32b4788ad5109
Committed by
Ben Dooks
1 parent
a192f7153b
Exists in
master
and in
39 other branches
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>
Showing 7 changed files with 37 additions and 65 deletions Side-by-side Diff
arch/arm/mach-s3c2410/mach-bast.c
... | ... | @@ -409,8 +409,7 @@ |
409 | 409 | static struct s3c2410_platform_i2c __initdata bast_i2c_info = { |
410 | 410 | .flags = 0, |
411 | 411 | .slave_addr = 0x10, |
412 | - .bus_freq = 100*1000, | |
413 | - .max_freq = 130*1000, | |
412 | + .frequency = 100*1000, | |
414 | 413 | }; |
415 | 414 | |
416 | 415 | /* Asix AX88796 10/100 ethernet controller */ |
arch/arm/mach-s3c2410/mach-n30.c
... | ... | @@ -340,8 +340,7 @@ |
340 | 340 | static struct s3c2410_platform_i2c n30_i2ccfg = { |
341 | 341 | .flags = 0, |
342 | 342 | .slave_addr = 0x10, |
343 | - .bus_freq = 10*1000, | |
344 | - .max_freq = 10*1000, | |
343 | + .frequency = 10*1000, | |
345 | 344 | }; |
346 | 345 | |
347 | 346 | /* Lots of hardcoded stuff, but it sets up the hardware in a useful |
arch/arm/mach-s3c2412/mach-jive.c
... | ... | @@ -453,8 +453,7 @@ |
453 | 453 | /* I2C bus and device configuration. */ |
454 | 454 | |
455 | 455 | static struct s3c2410_platform_i2c jive_i2c_cfg __initdata = { |
456 | - .max_freq = 80 * 1000, | |
457 | - .bus_freq = 50 * 1000, | |
456 | + .frequency = 80 * 1000, | |
458 | 457 | .flags = S3C_IICFLG_FILTER, |
459 | 458 | .sda_delay = 2, |
460 | 459 | }; |
arch/arm/plat-s3c/dev-i2c0.c
1 | 1 | /* linux/arch/arm/plat-s3c/dev-i2c0.c |
2 | 2 | * |
3 | - * Copyright 2008 Simtec Electronics | |
3 | + * Copyright 2008,2009 Simtec Electronics | |
4 | 4 | * Ben Dooks <ben@simtec.co.uk> |
5 | 5 | * http://armlinux.simtec.co.uk/ |
6 | 6 | * |
... | ... | @@ -50,8 +50,7 @@ |
50 | 50 | static struct s3c2410_platform_i2c default_i2c_data0 __initdata = { |
51 | 51 | .flags = 0, |
52 | 52 | .slave_addr = 0x10, |
53 | - .bus_freq = 100*1000, | |
54 | - .max_freq = 400*1000, | |
53 | + .frequency = 100*1000, | |
55 | 54 | .sda_delay = 100, |
56 | 55 | }; |
57 | 56 |
arch/arm/plat-s3c/dev-i2c1.c
1 | 1 | /* linux/arch/arm/plat-s3c/dev-i2c1.c |
2 | 2 | * |
3 | - * Copyright 2008 Simtec Electronics | |
3 | + * Copyright 2008,2009 Simtec Electronics | |
4 | 4 | * Ben Dooks <ben@simtec.co.uk> |
5 | 5 | * http://armlinux.simtec.co.uk/ |
6 | 6 | * |
... | ... | @@ -47,8 +47,7 @@ |
47 | 47 | .flags = 0, |
48 | 48 | .bus_num = 1, |
49 | 49 | .slave_addr = 0x10, |
50 | - .bus_freq = 100*1000, | |
51 | - .max_freq = 400*1000, | |
50 | + .frequency = 100*1000, | |
52 | 51 | .sda_delay = 100, |
53 | 52 | }; |
54 | 53 |
arch/arm/plat-s3c/include/plat/iic.h
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 | 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 | 8 | * This program is free software; you can redistribute it and/or modify |
9 | 9 | * it under the terms of the GNU General Public License version 2 as |
10 | 10 | |
11 | 11 | |
... | ... | @@ -15,19 +15,24 @@ |
15 | 15 | |
16 | 16 | #define S3C_IICFLG_FILTER (1<<0) /* enable s3c2440 filter */ |
17 | 17 | |
18 | -/* Notes: | |
19 | - * 1) All frequencies are expressed in Hz | |
20 | - * 2) A value of zero is `do not care` | |
21 | -*/ | |
22 | - | |
18 | +/** | |
19 | + * struct s3c2410_platform_i2c - Platform data for s3c I2C. | |
20 | + * @bus_num: The bus number to use (if possible). | |
21 | + * @flags: Any flags for the I2C bus (E.g. S3C_IICFLK_FILTER). | |
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 | 30 | struct s3c2410_platform_i2c { |
24 | - int bus_num; /* bus number to use */ | |
31 | + int bus_num; | |
25 | 32 | unsigned int flags; |
26 | - unsigned int slave_addr; /* slave address for controller */ | |
27 | - unsigned long bus_freq; /* standard bus frequency */ | |
28 | - unsigned long max_freq; /* max frequency for the bus */ | |
29 | - unsigned long min_freq; /* min frequency for the bus */ | |
30 | - unsigned int sda_delay; /* pclks (s3c2440 only) */ | |
33 | + unsigned int slave_addr; | |
34 | + unsigned long frequency; | |
35 | + unsigned int sda_delay; | |
31 | 36 | |
32 | 37 | void (*cfg_gpio)(struct platform_device *dev); |
33 | 38 | }; |
drivers/i2c/busses/i2c-s3c2410.c
1 | 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 | 4 | * Ben Dooks <ben@simtec.co.uk> |
5 | 5 | * |
6 | 6 | * S3C2410 I2C Controller |
... | ... | @@ -590,18 +590,6 @@ |
590 | 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 | 593 | /* s3c24xx_i2c_clockrate |
606 | 594 | * |
607 | 595 | * work out a divisor for the user requested frequency setting, |
608 | 596 | |
609 | 597 | |
610 | 598 | |
611 | 599 | |
612 | 600 | |
613 | 601 | |
614 | 602 | |
... | ... | @@ -614,44 +602,28 @@ |
614 | 602 | struct s3c2410_platform_i2c *pdata = i2c->dev->platform_data; |
615 | 603 | unsigned long clkin = clk_get_rate(i2c->clk); |
616 | 604 | unsigned int divs, div1; |
605 | + unsigned long target_frequency; | |
617 | 606 | u32 iiccon; |
618 | 607 | int freq; |
619 | - int start, end; | |
620 | 608 | |
621 | 609 | i2c->clkrate = clkin; |
622 | 610 | clkin /= 1000; /* clkin now in KHz */ |
623 | 611 | |
624 | - dev_dbg(i2c->dev, "pdata %p, freq %lu %lu..%lu\n", | |
625 | - pdata, pdata->bus_freq, pdata->min_freq, pdata->max_freq); | |
612 | + dev_dbg(i2c->dev, "pdata desired frequency %lu\n", pdata->frequency); | |
626 | 613 | |
627 | - if (pdata->bus_freq != 0) { | |
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 | - } | |
614 | + target_frequency = pdata->frequency ? pdata->frequency : 100000; | |
633 | 615 | |
634 | - /* ok, we may have to search for something suitable... */ | |
616 | + target_frequency /= 1000; /* Target frequency now in KHz */ | |
635 | 617 | |
636 | - start = (pdata->max_freq == 0) ? pdata->bus_freq : pdata->max_freq; | |
637 | - end = pdata->min_freq; | |
618 | + freq = s3c24xx_i2c_calcdivisor(clkin, target_frequency, &div1, &divs); | |
638 | 619 | |
639 | - start /= 1000; | |
640 | - end /= 1000; | |
641 | - | |
642 | - /* search loop... */ | |
643 | - | |
644 | - for (; start > end; start--) { | |
645 | - freq = s3c24xx_i2c_calcdivisor(clkin, start, &div1, &divs); | |
646 | - if (freq_acceptable(freq, start)) | |
647 | - goto found; | |
620 | + if (freq > target_frequency) { | |
621 | + dev_err(i2c->dev, | |
622 | + "Unable to achieve desired frequency %luKHz." \ | |
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 | 627 | *got = freq; |
656 | 628 | |
657 | 629 | iiccon = readl(i2c->regs + S3C2410_IICCON); |