aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/i2c/busses/i2c-s3c2410.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/i2c/busses/i2c-s3c2410.c')
-rw-r--r--drivers/i2c/busses/i2c-s3c2410.c77
1 files changed, 31 insertions, 46 deletions
diff --git a/drivers/i2c/busses/i2c-s3c2410.c b/drivers/i2c/busses/i2c-s3c2410.c
index 5b7f95641ba4..1691ef0f1ee1 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
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 }
633
634 /* ok, we may have to search for something suitable... */
635 613
636 start = (pdata->max_freq == 0) ? pdata->bus_freq : pdata->max_freq; 614 target_frequency = pdata->frequency ? pdata->frequency : 100000;
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);
@@ -663,6 +635,23 @@ static int s3c24xx_i2c_clockrate(struct s3c24xx_i2c *i2c, unsigned int *got)
663 635
664 writel(iiccon, i2c->regs + S3C2410_IICCON); 636 writel(iiccon, i2c->regs + S3C2410_IICCON);
665 637
638 if (s3c24xx_i2c_is2440(i2c)) {
639 unsigned long sda_delay;
640
641 if (pdata->sda_delay) {
642 sda_delay = (freq / 1000) * pdata->sda_delay;
643 sda_delay /= 1000000;
644 sda_delay = DIV_ROUND_UP(sda_delay, 5);
645 if (sda_delay > 3)
646 sda_delay = 3;
647 sda_delay |= S3C2410_IICLC_FILTER_ON;
648 } else
649 sda_delay = 0;
650
651 dev_dbg(i2c->dev, "IICLC=%08lx\n", sda_delay);
652 writel(sda_delay, i2c->regs + S3C2440_IICLC);
653 }
654
666 return 0; 655 return 0;
667} 656}
668 657
@@ -769,11 +758,8 @@ static int s3c24xx_i2c_init(struct s3c24xx_i2c *i2c)
769 758
770 /* check for s3c2440 i2c controller */ 759 /* check for s3c2440 i2c controller */
771 760
772 if (s3c24xx_i2c_is2440(i2c)) { 761 if (s3c24xx_i2c_is2440(i2c))
773 dev_dbg(i2c->dev, "S3C2440_IICLC=%08x\n", pdata->sda_delay); 762 writel(0x0, i2c->regs + S3C2440_IICLC);
774
775 writel(pdata->sda_delay, i2c->regs + S3C2440_IICLC);
776 }
777 763
778 return 0; 764 return 0;
779} 765}
@@ -1018,14 +1004,13 @@ static int __init i2c_adap_s3c_init(void)
1018 1004
1019 return ret; 1005 return ret;
1020} 1006}
1007subsys_initcall(i2c_adap_s3c_init);
1021 1008
1022static void __exit i2c_adap_s3c_exit(void) 1009static void __exit i2c_adap_s3c_exit(void)
1023{ 1010{
1024 platform_driver_unregister(&s3c2410_i2c_driver); 1011 platform_driver_unregister(&s3c2410_i2c_driver);
1025 platform_driver_unregister(&s3c2440_i2c_driver); 1012 platform_driver_unregister(&s3c2440_i2c_driver);
1026} 1013}
1027
1028module_init(i2c_adap_s3c_init);
1029module_exit(i2c_adap_s3c_exit); 1014module_exit(i2c_adap_s3c_exit);
1030 1015
1031MODULE_DESCRIPTION("S3C24XX I2C Bus driver"); 1016MODULE_DESCRIPTION("S3C24XX I2C Bus driver");