diff options
Diffstat (limited to 'drivers/i2c/busses')
-rw-r--r-- | drivers/i2c/busses/i2c-bfin-twi.c | 35 | ||||
-rw-r--r-- | drivers/i2c/busses/i2c-gpio.c | 9 | ||||
-rw-r--r-- | drivers/i2c/busses/i2c-s3c2410.c | 129 |
3 files changed, 144 insertions, 29 deletions
diff --git a/drivers/i2c/busses/i2c-bfin-twi.c b/drivers/i2c/busses/i2c-bfin-twi.c index 48d084bdf7c8..3c855ff2992f 100644 --- a/drivers/i2c/busses/i2c-bfin-twi.c +++ b/drivers/i2c/busses/i2c-bfin-twi.c | |||
@@ -49,6 +49,8 @@ struct bfin_twi_iface { | |||
49 | struct i2c_msg *pmsg; | 49 | struct i2c_msg *pmsg; |
50 | int msg_num; | 50 | int msg_num; |
51 | int cur_msg; | 51 | int cur_msg; |
52 | u16 saved_clkdiv; | ||
53 | u16 saved_control; | ||
52 | void __iomem *regs_base; | 54 | void __iomem *regs_base; |
53 | }; | 55 | }; |
54 | 56 | ||
@@ -565,32 +567,43 @@ static u32 bfin_twi_functionality(struct i2c_adapter *adap) | |||
565 | I2C_FUNC_I2C; | 567 | I2C_FUNC_I2C; |
566 | } | 568 | } |
567 | 569 | ||
568 | |||
569 | static struct i2c_algorithm bfin_twi_algorithm = { | 570 | static struct i2c_algorithm bfin_twi_algorithm = { |
570 | .master_xfer = bfin_twi_master_xfer, | 571 | .master_xfer = bfin_twi_master_xfer, |
571 | .smbus_xfer = bfin_twi_smbus_xfer, | 572 | .smbus_xfer = bfin_twi_smbus_xfer, |
572 | .functionality = bfin_twi_functionality, | 573 | .functionality = bfin_twi_functionality, |
573 | }; | 574 | }; |
574 | 575 | ||
575 | 576 | static int i2c_bfin_twi_suspend(struct platform_device *pdev, pm_message_t state) | |
576 | static int i2c_bfin_twi_suspend(struct platform_device *dev, pm_message_t state) | ||
577 | { | 577 | { |
578 | struct bfin_twi_iface *iface = platform_get_drvdata(dev); | 578 | struct bfin_twi_iface *iface = platform_get_drvdata(pdev); |
579 | |||
580 | iface->saved_clkdiv = read_CLKDIV(iface); | ||
581 | iface->saved_control = read_CONTROL(iface); | ||
582 | |||
583 | free_irq(iface->irq, iface); | ||
579 | 584 | ||
580 | /* Disable TWI */ | 585 | /* Disable TWI */ |
581 | write_CONTROL(iface, read_CONTROL(iface) & ~TWI_ENA); | 586 | write_CONTROL(iface, iface->saved_control & ~TWI_ENA); |
582 | SSYNC(); | ||
583 | 587 | ||
584 | return 0; | 588 | return 0; |
585 | } | 589 | } |
586 | 590 | ||
587 | static int i2c_bfin_twi_resume(struct platform_device *dev) | 591 | static int i2c_bfin_twi_resume(struct platform_device *pdev) |
588 | { | 592 | { |
589 | struct bfin_twi_iface *iface = platform_get_drvdata(dev); | 593 | struct bfin_twi_iface *iface = platform_get_drvdata(pdev); |
590 | 594 | ||
591 | /* Enable TWI */ | 595 | int rc = request_irq(iface->irq, bfin_twi_interrupt_entry, |
592 | write_CONTROL(iface, read_CONTROL(iface) | TWI_ENA); | 596 | IRQF_DISABLED, pdev->name, iface); |
593 | SSYNC(); | 597 | if (rc) { |
598 | dev_err(&pdev->dev, "Can't get IRQ %d !\n", iface->irq); | ||
599 | return -ENODEV; | ||
600 | } | ||
601 | |||
602 | /* Resume TWI interface clock as specified */ | ||
603 | write_CLKDIV(iface, iface->saved_clkdiv); | ||
604 | |||
605 | /* Resume TWI */ | ||
606 | write_CONTROL(iface, iface->saved_control); | ||
594 | 607 | ||
595 | return 0; | 608 | return 0; |
596 | } | 609 | } |
diff --git a/drivers/i2c/busses/i2c-gpio.c b/drivers/i2c/busses/i2c-gpio.c index 79b455a1f090..32104eac8d3d 100644 --- a/drivers/i2c/busses/i2c-gpio.c +++ b/drivers/i2c/busses/i2c-gpio.c | |||
@@ -77,7 +77,7 @@ static int i2c_gpio_getscl(void *data) | |||
77 | return gpio_get_value(pdata->scl_pin); | 77 | return gpio_get_value(pdata->scl_pin); |
78 | } | 78 | } |
79 | 79 | ||
80 | static int __init i2c_gpio_probe(struct platform_device *pdev) | 80 | static int __devinit i2c_gpio_probe(struct platform_device *pdev) |
81 | { | 81 | { |
82 | struct i2c_gpio_platform_data *pdata; | 82 | struct i2c_gpio_platform_data *pdata; |
83 | struct i2c_algo_bit_data *bit_data; | 83 | struct i2c_algo_bit_data *bit_data; |
@@ -174,7 +174,7 @@ err_alloc_adap: | |||
174 | return ret; | 174 | return ret; |
175 | } | 175 | } |
176 | 176 | ||
177 | static int __exit i2c_gpio_remove(struct platform_device *pdev) | 177 | static int __devexit i2c_gpio_remove(struct platform_device *pdev) |
178 | { | 178 | { |
179 | struct i2c_gpio_platform_data *pdata; | 179 | struct i2c_gpio_platform_data *pdata; |
180 | struct i2c_adapter *adap; | 180 | struct i2c_adapter *adap; |
@@ -196,14 +196,15 @@ static struct platform_driver i2c_gpio_driver = { | |||
196 | .name = "i2c-gpio", | 196 | .name = "i2c-gpio", |
197 | .owner = THIS_MODULE, | 197 | .owner = THIS_MODULE, |
198 | }, | 198 | }, |
199 | .remove = __exit_p(i2c_gpio_remove), | 199 | .probe = i2c_gpio_probe, |
200 | .remove = __devexit_p(i2c_gpio_remove), | ||
200 | }; | 201 | }; |
201 | 202 | ||
202 | static int __init i2c_gpio_init(void) | 203 | static int __init i2c_gpio_init(void) |
203 | { | 204 | { |
204 | int ret; | 205 | int ret; |
205 | 206 | ||
206 | ret = platform_driver_probe(&i2c_gpio_driver, i2c_gpio_probe); | 207 | ret = platform_driver_register(&i2c_gpio_driver); |
207 | if (ret) | 208 | if (ret) |
208 | printk(KERN_ERR "i2c-gpio: probe failed: %d\n", ret); | 209 | printk(KERN_ERR "i2c-gpio: probe failed: %d\n", ret); |
209 | 210 | ||
diff --git a/drivers/i2c/busses/i2c-s3c2410.c b/drivers/i2c/busses/i2c-s3c2410.c index 598b9cbd3a05..b216bfbea78c 100644 --- a/drivers/i2c/busses/i2c-s3c2410.c +++ b/drivers/i2c/busses/i2c-s3c2410.c | |||
@@ -33,6 +33,7 @@ | |||
33 | #include <linux/err.h> | 33 | #include <linux/err.h> |
34 | #include <linux/platform_device.h> | 34 | #include <linux/platform_device.h> |
35 | #include <linux/clk.h> | 35 | #include <linux/clk.h> |
36 | #include <linux/cpufreq.h> | ||
36 | 37 | ||
37 | #include <asm/arch/hardware.h> | 38 | #include <asm/arch/hardware.h> |
38 | #include <asm/irq.h> | 39 | #include <asm/irq.h> |
@@ -64,6 +65,7 @@ struct s3c24xx_i2c { | |||
64 | unsigned int tx_setup; | 65 | unsigned int tx_setup; |
65 | 66 | ||
66 | enum s3c24xx_i2c_state state; | 67 | enum s3c24xx_i2c_state state; |
68 | unsigned long clkrate; | ||
67 | 69 | ||
68 | void __iomem *regs; | 70 | void __iomem *regs; |
69 | struct clk *clk; | 71 | struct clk *clk; |
@@ -71,6 +73,10 @@ struct s3c24xx_i2c { | |||
71 | struct resource *irq; | 73 | struct resource *irq; |
72 | struct resource *ioarea; | 74 | struct resource *ioarea; |
73 | struct i2c_adapter adap; | 75 | struct i2c_adapter adap; |
76 | |||
77 | #ifdef CONFIG_CPU_FREQ | ||
78 | struct notifier_block freq_transition; | ||
79 | #endif | ||
74 | }; | 80 | }; |
75 | 81 | ||
76 | /* default platform data to use if not supplied in the platform_device | 82 | /* default platform data to use if not supplied in the platform_device |
@@ -501,6 +507,9 @@ static int s3c24xx_i2c_doxfer(struct s3c24xx_i2c *i2c, struct i2c_msg *msgs, int | |||
501 | unsigned long timeout; | 507 | unsigned long timeout; |
502 | int ret; | 508 | int ret; |
503 | 509 | ||
510 | if (!readl(i2c->regs + S3C2410_IICCON) & S3C2410_IICCON_IRQEN) | ||
511 | return -EIO; | ||
512 | |||
504 | ret = s3c24xx_i2c_set_master(i2c); | 513 | ret = s3c24xx_i2c_set_master(i2c); |
505 | if (ret != 0) { | 514 | if (ret != 0) { |
506 | dev_err(i2c->dev, "cannot get bus (error %d)\n", ret); | 515 | dev_err(i2c->dev, "cannot get bus (error %d)\n", ret); |
@@ -636,27 +645,28 @@ static inline int freq_acceptable(unsigned int freq, unsigned int wanted) | |||
636 | return (diff >= -2 && diff <= 2); | 645 | return (diff >= -2 && diff <= 2); |
637 | } | 646 | } |
638 | 647 | ||
639 | /* s3c24xx_i2c_getdivisor | 648 | /* s3c24xx_i2c_clockrate |
640 | * | 649 | * |
641 | * work out a divisor for the user requested frequency setting, | 650 | * work out a divisor for the user requested frequency setting, |
642 | * either by the requested frequency, or scanning the acceptable | 651 | * either by the requested frequency, or scanning the acceptable |
643 | * range of frequencies until something is found | 652 | * range of frequencies until something is found |
644 | */ | 653 | */ |
645 | 654 | ||
646 | static int s3c24xx_i2c_getdivisor(struct s3c24xx_i2c *i2c, | 655 | static int s3c24xx_i2c_clockrate(struct s3c24xx_i2c *i2c, unsigned int *got) |
647 | struct s3c2410_platform_i2c *pdata, | ||
648 | unsigned long *iicon, | ||
649 | unsigned int *got) | ||
650 | { | 656 | { |
657 | struct s3c2410_platform_i2c *pdata; | ||
651 | unsigned long clkin = clk_get_rate(i2c->clk); | 658 | unsigned long clkin = clk_get_rate(i2c->clk); |
652 | |||
653 | unsigned int divs, div1; | 659 | unsigned int divs, div1; |
660 | u32 iiccon; | ||
654 | int freq; | 661 | int freq; |
655 | int start, end; | 662 | int start, end; |
656 | 663 | ||
664 | i2c->clkrate = clkin; | ||
665 | |||
666 | pdata = s3c24xx_i2c_get_platformdata(i2c->adap.dev.parent); | ||
657 | clkin /= 1000; /* clkin now in KHz */ | 667 | clkin /= 1000; /* clkin now in KHz */ |
658 | 668 | ||
659 | dev_dbg(i2c->dev, "pdata %p, freq %lu %lu..%lu\n", | 669 | dev_dbg(i2c->dev, "pdata %p, freq %lu %lu..%lu\n", |
660 | pdata, pdata->bus_freq, pdata->min_freq, pdata->max_freq); | 670 | pdata, pdata->bus_freq, pdata->min_freq, pdata->max_freq); |
661 | 671 | ||
662 | if (pdata->bus_freq != 0) { | 672 | if (pdata->bus_freq != 0) { |
@@ -688,11 +698,79 @@ static int s3c24xx_i2c_getdivisor(struct s3c24xx_i2c *i2c, | |||
688 | 698 | ||
689 | found: | 699 | found: |
690 | *got = freq; | 700 | *got = freq; |
691 | *iicon |= (divs-1); | 701 | |
692 | *iicon |= (div1 == 512) ? S3C2410_IICCON_TXDIV_512 : 0; | 702 | iiccon = readl(i2c->regs + S3C2410_IICCON); |
703 | iiccon &= ~(S3C2410_IICCON_SCALEMASK | S3C2410_IICCON_TXDIV_512); | ||
704 | iiccon |= (divs-1); | ||
705 | |||
706 | if (div1 == 512) | ||
707 | iiccon |= S3C2410_IICCON_TXDIV_512; | ||
708 | |||
709 | writel(iiccon, i2c->regs + S3C2410_IICCON); | ||
710 | |||
711 | return 0; | ||
712 | } | ||
713 | |||
714 | #ifdef CONFIG_CPU_FREQ | ||
715 | |||
716 | #define freq_to_i2c(_n) container_of(_n, struct s3c24xx_i2c, freq_transition) | ||
717 | |||
718 | static int s3c24xx_i2c_cpufreq_transition(struct notifier_block *nb, | ||
719 | unsigned long val, void *data) | ||
720 | { | ||
721 | struct s3c24xx_i2c *i2c = freq_to_i2c(nb); | ||
722 | unsigned long flags; | ||
723 | unsigned int got; | ||
724 | int delta_f; | ||
725 | int ret; | ||
726 | |||
727 | delta_f = clk_get_rate(i2c->clk) - i2c->clkrate; | ||
728 | |||
729 | /* if we're post-change and the input clock has slowed down | ||
730 | * or at pre-change and the clock is about to speed up, then | ||
731 | * adjust our clock rate. <0 is slow, >0 speedup. | ||
732 | */ | ||
733 | |||
734 | if ((val == CPUFREQ_POSTCHANGE && delta_f < 0) || | ||
735 | (val == CPUFREQ_PRECHANGE && delta_f > 0)) { | ||
736 | spin_lock_irqsave(&i2c->lock, flags); | ||
737 | ret = s3c24xx_i2c_clockrate(i2c, &got); | ||
738 | spin_unlock_irqrestore(&i2c->lock, flags); | ||
739 | |||
740 | if (ret < 0) | ||
741 | dev_err(i2c->dev, "cannot find frequency\n"); | ||
742 | else | ||
743 | dev_info(i2c->dev, "setting freq %d\n", got); | ||
744 | } | ||
745 | |||
746 | return 0; | ||
747 | } | ||
748 | |||
749 | static inline int s3c24xx_i2c_register_cpufreq(struct s3c24xx_i2c *i2c) | ||
750 | { | ||
751 | i2c->freq_transition.notifier_call = s3c24xx_i2c_cpufreq_transition; | ||
752 | |||
753 | return cpufreq_register_notifier(&i2c->freq_transition, | ||
754 | CPUFREQ_TRANSITION_NOTIFIER); | ||
755 | } | ||
756 | |||
757 | static inline void s3c24xx_i2c_deregister_cpufreq(struct s3c24xx_i2c *i2c) | ||
758 | { | ||
759 | cpufreq_unregister_notifier(&i2c->freq_transition, | ||
760 | CPUFREQ_TRANSITION_NOTIFIER); | ||
761 | } | ||
762 | |||
763 | #else | ||
764 | static inline int s3c24xx_i2c_register_cpufreq(struct s3c24xx_i2c *i2c) | ||
765 | { | ||
693 | return 0; | 766 | return 0; |
694 | } | 767 | } |
695 | 768 | ||
769 | static inline void s3c24xx_i2c_deregister_cpufreq(struct s3c24xx_i2c *i2c) | ||
770 | { | ||
771 | } | ||
772 | #endif | ||
773 | |||
696 | /* s3c24xx_i2c_init | 774 | /* s3c24xx_i2c_init |
697 | * | 775 | * |
698 | * initialise the controller, set the IO lines and frequency | 776 | * initialise the controller, set the IO lines and frequency |
@@ -719,9 +797,12 @@ static int s3c24xx_i2c_init(struct s3c24xx_i2c *i2c) | |||
719 | 797 | ||
720 | dev_info(i2c->dev, "slave address 0x%02x\n", pdata->slave_addr); | 798 | dev_info(i2c->dev, "slave address 0x%02x\n", pdata->slave_addr); |
721 | 799 | ||
800 | writel(iicon, i2c->regs + S3C2410_IICCON); | ||
801 | |||
722 | /* we need to work out the divisors for the clock... */ | 802 | /* we need to work out the divisors for the clock... */ |
723 | 803 | ||
724 | if (s3c24xx_i2c_getdivisor(i2c, pdata, &iicon, &freq) != 0) { | 804 | if (s3c24xx_i2c_clockrate(i2c, &freq) != 0) { |
805 | writel(0, i2c->regs + S3C2410_IICCON); | ||
725 | dev_err(i2c->dev, "cannot meet bus frequency required\n"); | 806 | dev_err(i2c->dev, "cannot meet bus frequency required\n"); |
726 | return -EINVAL; | 807 | return -EINVAL; |
727 | } | 808 | } |
@@ -730,8 +811,6 @@ static int s3c24xx_i2c_init(struct s3c24xx_i2c *i2c) | |||
730 | 811 | ||
731 | dev_info(i2c->dev, "bus frequency set to %d KHz\n", freq); | 812 | dev_info(i2c->dev, "bus frequency set to %d KHz\n", freq); |
732 | dev_dbg(i2c->dev, "S3C2410_IICCON=0x%02lx\n", iicon); | 813 | dev_dbg(i2c->dev, "S3C2410_IICCON=0x%02lx\n", iicon); |
733 | |||
734 | writel(iicon, i2c->regs + S3C2410_IICCON); | ||
735 | 814 | ||
736 | /* check for s3c2440 i2c controller */ | 815 | /* check for s3c2440 i2c controller */ |
737 | 816 | ||
@@ -752,9 +831,12 @@ static int s3c24xx_i2c_init(struct s3c24xx_i2c *i2c) | |||
752 | static int s3c24xx_i2c_probe(struct platform_device *pdev) | 831 | static int s3c24xx_i2c_probe(struct platform_device *pdev) |
753 | { | 832 | { |
754 | struct s3c24xx_i2c *i2c = &s3c24xx_i2c; | 833 | struct s3c24xx_i2c *i2c = &s3c24xx_i2c; |
834 | struct s3c2410_platform_i2c *pdata; | ||
755 | struct resource *res; | 835 | struct resource *res; |
756 | int ret; | 836 | int ret; |
757 | 837 | ||
838 | pdata = s3c24xx_i2c_get_platformdata(&pdev->dev); | ||
839 | |||
758 | /* find the clock and enable it */ | 840 | /* find the clock and enable it */ |
759 | 841 | ||
760 | i2c->dev = &pdev->dev; | 842 | i2c->dev = &pdev->dev; |
@@ -832,17 +914,34 @@ static int s3c24xx_i2c_probe(struct platform_device *pdev) | |||
832 | dev_dbg(&pdev->dev, "irq resource %p (%lu)\n", res, | 914 | dev_dbg(&pdev->dev, "irq resource %p (%lu)\n", res, |
833 | (unsigned long)res->start); | 915 | (unsigned long)res->start); |
834 | 916 | ||
835 | ret = i2c_add_adapter(&i2c->adap); | 917 | ret = s3c24xx_i2c_register_cpufreq(i2c); |
836 | if (ret < 0) { | 918 | if (ret < 0) { |
837 | dev_err(&pdev->dev, "failed to add bus to i2c core\n"); | 919 | dev_err(&pdev->dev, "failed to register cpufreq notifier\n"); |
838 | goto err_irq; | 920 | goto err_irq; |
839 | } | 921 | } |
840 | 922 | ||
923 | /* Note, previous versions of the driver used i2c_add_adapter() | ||
924 | * to add the bus at any number. We now pass the bus number via | ||
925 | * the platform data, so if unset it will now default to always | ||
926 | * being bus 0. | ||
927 | */ | ||
928 | |||
929 | i2c->adap.nr = pdata->bus_num; | ||
930 | |||
931 | ret = i2c_add_numbered_adapter(&i2c->adap); | ||
932 | if (ret < 0) { | ||
933 | dev_err(&pdev->dev, "failed to add bus to i2c core\n"); | ||
934 | goto err_cpufreq; | ||
935 | } | ||
936 | |||
841 | platform_set_drvdata(pdev, i2c); | 937 | platform_set_drvdata(pdev, i2c); |
842 | 938 | ||
843 | dev_info(&pdev->dev, "%s: S3C I2C adapter\n", i2c->adap.dev.bus_id); | 939 | dev_info(&pdev->dev, "%s: S3C I2C adapter\n", i2c->adap.dev.bus_id); |
844 | return 0; | 940 | return 0; |
845 | 941 | ||
942 | err_cpufreq: | ||
943 | s3c24xx_i2c_deregister_cpufreq(i2c); | ||
944 | |||
846 | err_irq: | 945 | err_irq: |
847 | free_irq(i2c->irq->start, i2c); | 946 | free_irq(i2c->irq->start, i2c); |
848 | 947 | ||
@@ -870,6 +969,8 @@ static int s3c24xx_i2c_remove(struct platform_device *pdev) | |||
870 | { | 969 | { |
871 | struct s3c24xx_i2c *i2c = platform_get_drvdata(pdev); | 970 | struct s3c24xx_i2c *i2c = platform_get_drvdata(pdev); |
872 | 971 | ||
972 | s3c24xx_i2c_deregister_cpufreq(i2c); | ||
973 | |||
873 | i2c_del_adapter(&i2c->adap); | 974 | i2c_del_adapter(&i2c->adap); |
874 | free_irq(i2c->irq->start, i2c); | 975 | free_irq(i2c->irq->start, i2c); |
875 | 976 | ||