diff options
author | Tomoya MORINAGA <tomoya-linux@dsn.okisemi.com> | 2011-03-01 00:16:23 -0500 |
---|---|---|
committer | Ben Dooks <ben-linux@fluff.org> | 2011-03-01 19:36:13 -0500 |
commit | 173442f2787c88e1ed1bb62aaeb6fd9127720559 (patch) | |
tree | f939237b918ee563c61d9083b649c04a8f0c3ff1 /drivers/i2c | |
parent | 493f3358cb289ccf716c5a14fa5bb52ab75943e5 (diff) |
i2c-eg20t: support new device OKI SEMICONDUCTOR ML7213 IOH
Support new device OKI SEMICONDUCTOR ML7213 IOH.
The ML7213 which is for IVI(In-Vehicle Infotainment) is a companion
chip for the Atom E6xx series and compatible with the Intel EG20T
PCH.
Signed-off-by: Tomoya MORINAGA <tomoya-linux@dsn.okisemi.com>
Signed-off-by: Ben Dooks <ben-linux@fluff.org>
Diffstat (limited to 'drivers/i2c')
-rw-r--r-- | drivers/i2c/busses/Kconfig | 15 | ||||
-rw-r--r-- | drivers/i2c/busses/i2c-eg20t.c | 161 |
2 files changed, 108 insertions, 68 deletions
diff --git a/drivers/i2c/busses/Kconfig b/drivers/i2c/busses/Kconfig index 113505a6434e..5b592dfcbd78 100644 --- a/drivers/i2c/busses/Kconfig +++ b/drivers/i2c/busses/Kconfig | |||
@@ -639,12 +639,15 @@ config I2C_XILINX | |||
639 | will be called xilinx_i2c. | 639 | will be called xilinx_i2c. |
640 | 640 | ||
641 | config I2C_EG20T | 641 | config I2C_EG20T |
642 | tristate "PCH I2C of Intel EG20T" | 642 | tristate "Intel EG20T PCH/OKI SEMICONDUCTOR ML7213 IOH" |
643 | depends on PCI | 643 | depends on PCI |
644 | help | 644 | help |
645 | This driver is for PCH(Platform controller Hub) I2C of EG20T which | 645 | This driver is for PCH(Platform controller Hub) I2C of EG20T which |
646 | is an IOH(Input/Output Hub) for x86 embedded processor. | 646 | is an IOH(Input/Output Hub) for x86 embedded processor. |
647 | This driver can access PCH I2C bus device. | 647 | This driver can access PCH I2C bus device. |
648 | |||
649 | This driver also supports the ML7213, a companion chip for the | ||
650 | Atom E6xx series and compatible with the Intel EG20T PCH. | ||
648 | 651 | ||
649 | comment "External I2C/SMBus adapter drivers" | 652 | comment "External I2C/SMBus adapter drivers" |
650 | 653 | ||
diff --git a/drivers/i2c/busses/i2c-eg20t.c b/drivers/i2c/busses/i2c-eg20t.c index 2e067dd2ee51..c57c83734692 100644 --- a/drivers/i2c/busses/i2c-eg20t.c +++ b/drivers/i2c/busses/i2c-eg20t.c | |||
@@ -131,6 +131,13 @@ | |||
131 | #define pch_pci_dbg(pdev, fmt, arg...) \ | 131 | #define pch_pci_dbg(pdev, fmt, arg...) \ |
132 | dev_dbg(&pdev->dev, "%s :" fmt, __func__, ##arg) | 132 | dev_dbg(&pdev->dev, "%s :" fmt, __func__, ##arg) |
133 | 133 | ||
134 | /* | ||
135 | Set the number of I2C instance max | ||
136 | Intel EG20T PCH : 1ch | ||
137 | OKI SEMICONDUCTOR ML7213 IOH : 2ch | ||
138 | */ | ||
139 | #define PCH_I2C_MAX_DEV 2 | ||
140 | |||
134 | /** | 141 | /** |
135 | * struct i2c_algo_pch_data - for I2C driver functionalities | 142 | * struct i2c_algo_pch_data - for I2C driver functionalities |
136 | * @pch_adapter: stores the reference to i2c_adapter structure | 143 | * @pch_adapter: stores the reference to i2c_adapter structure |
@@ -155,12 +162,14 @@ struct i2c_algo_pch_data { | |||
155 | * @pch_data: stores a list of i2c_algo_pch_data | 162 | * @pch_data: stores a list of i2c_algo_pch_data |
156 | * @pch_i2c_suspended: specifies whether the system is suspended or not | 163 | * @pch_i2c_suspended: specifies whether the system is suspended or not |
157 | * perhaps with more lines and words. | 164 | * perhaps with more lines and words. |
165 | * @ch_num: specifies the number of i2c instance | ||
158 | * | 166 | * |
159 | * pch_data has as many elements as maximum I2C channels | 167 | * pch_data has as many elements as maximum I2C channels |
160 | */ | 168 | */ |
161 | struct adapter_info { | 169 | struct adapter_info { |
162 | struct i2c_algo_pch_data pch_data; | 170 | struct i2c_algo_pch_data pch_data[PCH_I2C_MAX_DEV]; |
163 | bool pch_i2c_suspended; | 171 | bool pch_i2c_suspended; |
172 | int ch_num; | ||
164 | }; | 173 | }; |
165 | 174 | ||
166 | 175 | ||
@@ -169,8 +178,13 @@ static int pch_clk = 50000; /* specifies I2C clock speed in KHz */ | |||
169 | static wait_queue_head_t pch_event; | 178 | static wait_queue_head_t pch_event; |
170 | static DEFINE_MUTEX(pch_mutex); | 179 | static DEFINE_MUTEX(pch_mutex); |
171 | 180 | ||
181 | /* Definition for ML7213 by OKI SEMICONDUCTOR */ | ||
182 | #define PCI_VENDOR_ID_ROHM 0x10DB | ||
183 | #define PCI_DEVICE_ID_ML7213_I2C 0x802D | ||
184 | |||
172 | static struct pci_device_id __devinitdata pch_pcidev_id[] = { | 185 | static struct pci_device_id __devinitdata pch_pcidev_id[] = { |
173 | {PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_PCH_I2C)}, | 186 | { PCI_VDEVICE(INTEL, PCI_DEVICE_ID_PCH_I2C), 1, }, |
187 | { PCI_VDEVICE(ROHM, PCI_DEVICE_ID_ML7213_I2C), 2, }, | ||
174 | {0,} | 188 | {0,} |
175 | }; | 189 | }; |
176 | 190 | ||
@@ -211,8 +225,7 @@ static void pch_i2c_init(struct i2c_algo_pch_data *adap) | |||
211 | /* Initialize I2C registers */ | 225 | /* Initialize I2C registers */ |
212 | iowrite32(0x21, p + PCH_I2CNF); | 226 | iowrite32(0x21, p + PCH_I2CNF); |
213 | 227 | ||
214 | pch_setbit(adap->pch_base_address, PCH_I2CCTL, | 228 | pch_setbit(adap->pch_base_address, PCH_I2CCTL, PCH_I2CCTL_I2CMEN); |
215 | PCH_I2CCTL_I2CMEN); | ||
216 | 229 | ||
217 | if (pch_i2c_speed != 400) | 230 | if (pch_i2c_speed != 400) |
218 | pch_i2c_speed = 100; | 231 | pch_i2c_speed = 100; |
@@ -254,7 +267,7 @@ static inline bool ktime_lt(const ktime_t cmp1, const ktime_t cmp2) | |||
254 | * @timeout: waiting time counter (us). | 267 | * @timeout: waiting time counter (us). |
255 | */ | 268 | */ |
256 | static s32 pch_i2c_wait_for_bus_idle(struct i2c_algo_pch_data *adap, | 269 | static s32 pch_i2c_wait_for_bus_idle(struct i2c_algo_pch_data *adap, |
257 | s32 timeout) | 270 | s32 timeout) |
258 | { | 271 | { |
259 | void __iomem *p = adap->pch_base_address; | 272 | void __iomem *p = adap->pch_base_address; |
260 | 273 | ||
@@ -474,8 +487,8 @@ static void pch_i2c_sendnack(struct i2c_algo_pch_data *adap) | |||
474 | * @last: specifies whether last message or not. | 487 | * @last: specifies whether last message or not. |
475 | * @first: specifies whether first message or not. | 488 | * @first: specifies whether first message or not. |
476 | */ | 489 | */ |
477 | s32 pch_i2c_readbytes(struct i2c_adapter *i2c_adap, struct i2c_msg *msgs, | 490 | static s32 pch_i2c_readbytes(struct i2c_adapter *i2c_adap, struct i2c_msg *msgs, |
478 | u32 last, u32 first) | 491 | u32 last, u32 first) |
479 | { | 492 | { |
480 | struct i2c_algo_pch_data *adap = i2c_adap->algo_data; | 493 | struct i2c_algo_pch_data *adap = i2c_adap->algo_data; |
481 | 494 | ||
@@ -568,10 +581,10 @@ s32 pch_i2c_readbytes(struct i2c_adapter *i2c_adap, struct i2c_msg *msgs, | |||
568 | } | 581 | } |
569 | 582 | ||
570 | /** | 583 | /** |
571 | * pch_i2c_cb_ch0() - Interrupt handler Call back function | 584 | * pch_i2c_cb() - Interrupt handler Call back function |
572 | * @adap: Pointer to struct i2c_algo_pch_data. | 585 | * @adap: Pointer to struct i2c_algo_pch_data. |
573 | */ | 586 | */ |
574 | static void pch_i2c_cb_ch0(struct i2c_algo_pch_data *adap) | 587 | static void pch_i2c_cb(struct i2c_algo_pch_data *adap) |
575 | { | 588 | { |
576 | u32 sts; | 589 | u32 sts; |
577 | void __iomem *p = adap->pch_base_address; | 590 | void __iomem *p = adap->pch_base_address; |
@@ -599,24 +612,30 @@ static void pch_i2c_cb_ch0(struct i2c_algo_pch_data *adap) | |||
599 | */ | 612 | */ |
600 | static irqreturn_t pch_i2c_handler(int irq, void *pData) | 613 | static irqreturn_t pch_i2c_handler(int irq, void *pData) |
601 | { | 614 | { |
602 | s32 reg_val; | 615 | u32 reg_val; |
603 | 616 | int flag; | |
604 | struct i2c_algo_pch_data *adap_data = (struct i2c_algo_pch_data *)pData; | 617 | int i; |
605 | void __iomem *p = adap_data->pch_base_address; | 618 | struct adapter_info *adap_info = pData; |
606 | u32 mode = ioread32(p + PCH_I2CMOD) & (BUFFER_MODE | EEPROM_SR_MODE); | 619 | void __iomem *p; |
607 | 620 | u32 mode; | |
608 | if (mode != NORMAL_MODE) { | 621 | |
609 | pch_err(adap_data, "I2C mode is not supported\n"); | 622 | for (i = 0, flag = 0; i < adap_info->ch_num; i++) { |
610 | return IRQ_NONE; | 623 | p = adap_info->pch_data[i].pch_base_address; |
624 | mode = ioread32(p + PCH_I2CMOD); | ||
625 | mode &= BUFFER_MODE | EEPROM_SR_MODE; | ||
626 | if (mode != NORMAL_MODE) { | ||
627 | pch_err(adap_info->pch_data, | ||
628 | "I2C-%d mode(%d) is not supported\n", mode, i); | ||
629 | continue; | ||
630 | } | ||
631 | reg_val = ioread32(p + PCH_I2CSR); | ||
632 | if (reg_val & (I2CMAL_BIT | I2CMCF_BIT | I2CMIF_BIT)) { | ||
633 | pch_i2c_cb(&adap_info->pch_data[i]); | ||
634 | flag = 1; | ||
635 | } | ||
611 | } | 636 | } |
612 | 637 | ||
613 | reg_val = ioread32(p + PCH_I2CSR); | 638 | return flag ? IRQ_HANDLED : IRQ_NONE; |
614 | if (reg_val & (I2CMAL_BIT | I2CMCF_BIT | I2CMIF_BIT)) | ||
615 | pch_i2c_cb_ch0(adap_data); | ||
616 | else | ||
617 | return IRQ_NONE; | ||
618 | |||
619 | return IRQ_HANDLED; | ||
620 | } | 639 | } |
621 | 640 | ||
622 | /** | 641 | /** |
@@ -626,7 +645,7 @@ static irqreturn_t pch_i2c_handler(int irq, void *pData) | |||
626 | * @num: number of messages. | 645 | * @num: number of messages. |
627 | */ | 646 | */ |
628 | static s32 pch_i2c_xfer(struct i2c_adapter *i2c_adap, | 647 | static s32 pch_i2c_xfer(struct i2c_adapter *i2c_adap, |
629 | struct i2c_msg *msgs, s32 num) | 648 | struct i2c_msg *msgs, s32 num) |
630 | { | 649 | { |
631 | struct i2c_msg *pmsg; | 650 | struct i2c_msg *pmsg; |
632 | u32 i = 0; | 651 | u32 i = 0; |
@@ -709,11 +728,13 @@ static void pch_i2c_disbl_int(struct i2c_algo_pch_data *adap) | |||
709 | } | 728 | } |
710 | 729 | ||
711 | static int __devinit pch_i2c_probe(struct pci_dev *pdev, | 730 | static int __devinit pch_i2c_probe(struct pci_dev *pdev, |
712 | const struct pci_device_id *id) | 731 | const struct pci_device_id *id) |
713 | { | 732 | { |
714 | void __iomem *base_addr; | 733 | void __iomem *base_addr; |
715 | s32 ret; | 734 | int ret; |
735 | int i, j; | ||
716 | struct adapter_info *adap_info; | 736 | struct adapter_info *adap_info; |
737 | struct i2c_adapter *pch_adap; | ||
717 | 738 | ||
718 | pch_pci_dbg(pdev, "Entered.\n"); | 739 | pch_pci_dbg(pdev, "Entered.\n"); |
719 | 740 | ||
@@ -743,44 +764,48 @@ static int __devinit pch_i2c_probe(struct pci_dev *pdev, | |||
743 | goto err_pci_iomap; | 764 | goto err_pci_iomap; |
744 | } | 765 | } |
745 | 766 | ||
746 | adap_info->pch_i2c_suspended = false; | 767 | /* Set the number of I2C channel instance */ |
768 | adap_info->ch_num = id->driver_data; | ||
747 | 769 | ||
748 | adap_info->pch_data.p_adapter_info = adap_info; | 770 | for (i = 0; i < adap_info->ch_num; i++) { |
771 | pch_adap = &adap_info->pch_data[i].pch_adapter; | ||
772 | adap_info->pch_i2c_suspended = false; | ||
749 | 773 | ||
750 | adap_info->pch_data.pch_adapter.owner = THIS_MODULE; | 774 | adap_info->pch_data[i].p_adapter_info = adap_info; |
751 | adap_info->pch_data.pch_adapter.class = I2C_CLASS_HWMON; | ||
752 | strcpy(adap_info->pch_data.pch_adapter.name, KBUILD_MODNAME); | ||
753 | adap_info->pch_data.pch_adapter.algo = &pch_algorithm; | ||
754 | adap_info->pch_data.pch_adapter.algo_data = | ||
755 | &adap_info->pch_data; | ||
756 | 775 | ||
757 | /* (i * 0x80) + base_addr; */ | 776 | pch_adap->owner = THIS_MODULE; |
758 | adap_info->pch_data.pch_base_address = base_addr; | 777 | pch_adap->class = I2C_CLASS_HWMON; |
778 | strcpy(pch_adap->name, KBUILD_MODNAME); | ||
779 | pch_adap->algo = &pch_algorithm; | ||
780 | pch_adap->algo_data = &adap_info->pch_data[i]; | ||
759 | 781 | ||
760 | adap_info->pch_data.pch_adapter.dev.parent = &pdev->dev; | 782 | /* base_addr + offset; */ |
783 | adap_info->pch_data[i].pch_base_address = base_addr + 0x100 * i; | ||
761 | 784 | ||
762 | ret = i2c_add_adapter(&(adap_info->pch_data.pch_adapter)); | 785 | pch_adap->dev.parent = &pdev->dev; |
763 | 786 | ||
764 | if (ret) { | 787 | ret = i2c_add_adapter(pch_adap); |
765 | pch_pci_err(pdev, "i2c_add_adapter FAILED\n"); | 788 | if (ret) { |
766 | goto err_i2c_add_adapter; | 789 | pch_pci_err(pdev, "i2c_add_adapter[ch:%d] FAILED\n", i); |
767 | } | 790 | goto err_i2c_add_adapter; |
791 | } | ||
768 | 792 | ||
769 | pch_i2c_init(&adap_info->pch_data); | 793 | pch_i2c_init(&adap_info->pch_data[i]); |
794 | } | ||
770 | ret = request_irq(pdev->irq, pch_i2c_handler, IRQF_SHARED, | 795 | ret = request_irq(pdev->irq, pch_i2c_handler, IRQF_SHARED, |
771 | KBUILD_MODNAME, &adap_info->pch_data); | 796 | KBUILD_MODNAME, adap_info); |
772 | if (ret) { | 797 | if (ret) { |
773 | pch_pci_err(pdev, "request_irq FAILED\n"); | 798 | pch_pci_err(pdev, "request_irq FAILED\n"); |
774 | goto err_request_irq; | 799 | goto err_i2c_add_adapter; |
775 | } | 800 | } |
776 | 801 | ||
777 | pci_set_drvdata(pdev, adap_info); | 802 | pci_set_drvdata(pdev, adap_info); |
778 | pch_pci_dbg(pdev, "returns %d.\n", ret); | 803 | pch_pci_dbg(pdev, "returns %d.\n", ret); |
779 | return 0; | 804 | return 0; |
780 | 805 | ||
781 | err_request_irq: | ||
782 | i2c_del_adapter(&(adap_info->pch_data.pch_adapter)); | ||
783 | err_i2c_add_adapter: | 806 | err_i2c_add_adapter: |
807 | for (j = 0; j < i; j++) | ||
808 | i2c_del_adapter(&adap_info->pch_data[j].pch_adapter); | ||
784 | pci_iounmap(pdev, base_addr); | 809 | pci_iounmap(pdev, base_addr); |
785 | err_pci_iomap: | 810 | err_pci_iomap: |
786 | pci_release_regions(pdev); | 811 | pci_release_regions(pdev); |
@@ -793,17 +818,22 @@ err_pci_enable: | |||
793 | 818 | ||
794 | static void __devexit pch_i2c_remove(struct pci_dev *pdev) | 819 | static void __devexit pch_i2c_remove(struct pci_dev *pdev) |
795 | { | 820 | { |
821 | int i; | ||
796 | struct adapter_info *adap_info = pci_get_drvdata(pdev); | 822 | struct adapter_info *adap_info = pci_get_drvdata(pdev); |
797 | 823 | ||
798 | pch_i2c_disbl_int(&adap_info->pch_data); | 824 | free_irq(pdev->irq, adap_info); |
799 | free_irq(pdev->irq, &adap_info->pch_data); | ||
800 | i2c_del_adapter(&(adap_info->pch_data.pch_adapter)); | ||
801 | 825 | ||
802 | if (adap_info->pch_data.pch_base_address) { | 826 | for (i = 0; i < adap_info->ch_num; i++) { |
803 | pci_iounmap(pdev, adap_info->pch_data.pch_base_address); | 827 | pch_i2c_disbl_int(&adap_info->pch_data[i]); |
804 | adap_info->pch_data.pch_base_address = 0; | 828 | i2c_del_adapter(&adap_info->pch_data[i].pch_adapter); |
805 | } | 829 | } |
806 | 830 | ||
831 | if (adap_info->pch_data[0].pch_base_address) | ||
832 | pci_iounmap(pdev, adap_info->pch_data[0].pch_base_address); | ||
833 | |||
834 | for (i = 0; i < adap_info->ch_num; i++) | ||
835 | adap_info->pch_data[i].pch_base_address = 0; | ||
836 | |||
807 | pci_set_drvdata(pdev, NULL); | 837 | pci_set_drvdata(pdev, NULL); |
808 | 838 | ||
809 | pci_release_regions(pdev); | 839 | pci_release_regions(pdev); |
@@ -816,17 +846,22 @@ static void __devexit pch_i2c_remove(struct pci_dev *pdev) | |||
816 | static int pch_i2c_suspend(struct pci_dev *pdev, pm_message_t state) | 846 | static int pch_i2c_suspend(struct pci_dev *pdev, pm_message_t state) |
817 | { | 847 | { |
818 | int ret; | 848 | int ret; |
849 | int i; | ||
819 | struct adapter_info *adap_info = pci_get_drvdata(pdev); | 850 | struct adapter_info *adap_info = pci_get_drvdata(pdev); |
820 | void __iomem *p = adap_info->pch_data.pch_base_address; | 851 | void __iomem *p = adap_info->pch_data[0].pch_base_address; |
821 | 852 | ||
822 | adap_info->pch_i2c_suspended = true; | 853 | adap_info->pch_i2c_suspended = true; |
823 | 854 | ||
824 | while ((adap_info->pch_data.pch_i2c_xfer_in_progress)) { | 855 | for (i = 0; i < adap_info->ch_num; i++) { |
825 | /* Wait until all channel transfers are completed */ | 856 | while ((adap_info->pch_data[i].pch_i2c_xfer_in_progress)) { |
826 | msleep(20); | 857 | /* Wait until all channel transfers are completed */ |
858 | msleep(20); | ||
859 | } | ||
827 | } | 860 | } |
861 | |||
828 | /* Disable the i2c interrupts */ | 862 | /* Disable the i2c interrupts */ |
829 | pch_i2c_disbl_int(&adap_info->pch_data); | 863 | for (i = 0; i < adap_info->ch_num; i++) |
864 | pch_i2c_disbl_int(&adap_info->pch_data[i]); | ||
830 | 865 | ||
831 | pch_pci_dbg(pdev, "I2CSR = %x I2CBUFSTA = %x I2CESRSTA = %x " | 866 | pch_pci_dbg(pdev, "I2CSR = %x I2CBUFSTA = %x I2CESRSTA = %x " |
832 | "invoked function pch_i2c_disbl_int successfully\n", | 867 | "invoked function pch_i2c_disbl_int successfully\n", |
@@ -849,6 +884,7 @@ static int pch_i2c_suspend(struct pci_dev *pdev, pm_message_t state) | |||
849 | 884 | ||
850 | static int pch_i2c_resume(struct pci_dev *pdev) | 885 | static int pch_i2c_resume(struct pci_dev *pdev) |
851 | { | 886 | { |
887 | int i; | ||
852 | struct adapter_info *adap_info = pci_get_drvdata(pdev); | 888 | struct adapter_info *adap_info = pci_get_drvdata(pdev); |
853 | 889 | ||
854 | pci_set_power_state(pdev, PCI_D0); | 890 | pci_set_power_state(pdev, PCI_D0); |
@@ -861,7 +897,8 @@ static int pch_i2c_resume(struct pci_dev *pdev) | |||
861 | 897 | ||
862 | pci_enable_wake(pdev, PCI_D3hot, 0); | 898 | pci_enable_wake(pdev, PCI_D3hot, 0); |
863 | 899 | ||
864 | pch_i2c_init(&adap_info->pch_data); | 900 | for (i = 0; i < adap_info->ch_num; i++) |
901 | pch_i2c_init(&adap_info->pch_data[i]); | ||
865 | 902 | ||
866 | adap_info->pch_i2c_suspended = false; | 903 | adap_info->pch_i2c_suspended = false; |
867 | 904 | ||
@@ -893,7 +930,7 @@ static void __exit pch_pci_exit(void) | |||
893 | } | 930 | } |
894 | module_exit(pch_pci_exit); | 931 | module_exit(pch_pci_exit); |
895 | 932 | ||
896 | MODULE_DESCRIPTION("PCH I2C PCI Driver"); | 933 | MODULE_DESCRIPTION("Intel EG20T PCH/OKI SEMICONDUCTOR ML7213 IOH I2C Driver"); |
897 | MODULE_LICENSE("GPL"); | 934 | MODULE_LICENSE("GPL"); |
898 | MODULE_AUTHOR("Tomoya MORINAGA. <tomoya-linux@dsn.okisemi.com>"); | 935 | MODULE_AUTHOR("Tomoya MORINAGA. <tomoya-linux@dsn.okisemi.com>"); |
899 | module_param(pch_i2c_speed, int, (S_IRUSR | S_IWUSR)); | 936 | module_param(pch_i2c_speed, int, (S_IRUSR | S_IWUSR)); |