diff options
-rw-r--r-- | drivers/i2c/busses/Kconfig | 7 | ||||
-rw-r--r-- | drivers/i2c/busses/Makefile | 1 | ||||
-rw-r--r-- | drivers/i2c/busses/i2c-pxa-pci.c | 176 | ||||
-rw-r--r-- | drivers/i2c/busses/i2c-pxa.c | 27 |
4 files changed, 206 insertions, 5 deletions
diff --git a/drivers/i2c/busses/Kconfig b/drivers/i2c/busses/Kconfig index 230601e8853f..b6e53c277276 100644 --- a/drivers/i2c/busses/Kconfig +++ b/drivers/i2c/busses/Kconfig | |||
@@ -546,15 +546,18 @@ config I2C_PUV3 | |||
546 | 546 | ||
547 | config I2C_PXA | 547 | config I2C_PXA |
548 | tristate "Intel PXA2XX I2C adapter" | 548 | tristate "Intel PXA2XX I2C adapter" |
549 | depends on ARCH_PXA || ARCH_MMP | 549 | depends on ARCH_PXA || ARCH_MMP || (X86_32 && PCI && OF) |
550 | help | 550 | help |
551 | If you have devices in the PXA I2C bus, say yes to this option. | 551 | If you have devices in the PXA I2C bus, say yes to this option. |
552 | This driver can also be built as a module. If so, the module | 552 | This driver can also be built as a module. If so, the module |
553 | will be called i2c-pxa. | 553 | will be called i2c-pxa. |
554 | 554 | ||
555 | config I2C_PXA_PCI | ||
556 | def_bool I2C_PXA && X86_32 && PCI && OF | ||
557 | |||
555 | config I2C_PXA_SLAVE | 558 | config I2C_PXA_SLAVE |
556 | bool "Intel PXA2XX I2C Slave comms support" | 559 | bool "Intel PXA2XX I2C Slave comms support" |
557 | depends on I2C_PXA | 560 | depends on I2C_PXA && !X86_32 |
558 | help | 561 | help |
559 | Support I2C slave mode communications on the PXA I2C bus. This | 562 | Support I2C slave mode communications on the PXA I2C bus. This |
560 | is necessary for systems where the PXA may be a target on the | 563 | is necessary for systems where the PXA may be a target on the |
diff --git a/drivers/i2c/busses/Makefile b/drivers/i2c/busses/Makefile index 3878c959d4fa..1dd554e51440 100644 --- a/drivers/i2c/busses/Makefile +++ b/drivers/i2c/busses/Makefile | |||
@@ -54,6 +54,7 @@ obj-$(CONFIG_I2C_PMCMSP) += i2c-pmcmsp.o | |||
54 | obj-$(CONFIG_I2C_PNX) += i2c-pnx.o | 54 | obj-$(CONFIG_I2C_PNX) += i2c-pnx.o |
55 | obj-$(CONFIG_I2C_PUV3) += i2c-puv3.o | 55 | obj-$(CONFIG_I2C_PUV3) += i2c-puv3.o |
56 | obj-$(CONFIG_I2C_PXA) += i2c-pxa.o | 56 | obj-$(CONFIG_I2C_PXA) += i2c-pxa.o |
57 | obj-$(CONFIG_I2C_PXA_PCI) += i2c-pxa-pci.o | ||
57 | obj-$(CONFIG_I2C_S3C2410) += i2c-s3c2410.o | 58 | obj-$(CONFIG_I2C_S3C2410) += i2c-s3c2410.o |
58 | obj-$(CONFIG_I2C_S6000) += i2c-s6000.o | 59 | obj-$(CONFIG_I2C_S6000) += i2c-s6000.o |
59 | obj-$(CONFIG_I2C_SH7760) += i2c-sh7760.o | 60 | obj-$(CONFIG_I2C_SH7760) += i2c-sh7760.o |
diff --git a/drivers/i2c/busses/i2c-pxa-pci.c b/drivers/i2c/busses/i2c-pxa-pci.c new file mode 100644 index 000000000000..6659d269b841 --- /dev/null +++ b/drivers/i2c/busses/i2c-pxa-pci.c | |||
@@ -0,0 +1,176 @@ | |||
1 | /* | ||
2 | * The CE4100's I2C device is more or less the same one as found on PXA. | ||
3 | * It does not support slave mode, the register slightly moved. This PCI | ||
4 | * device provides three bars, every contains a single I2C controller. | ||
5 | */ | ||
6 | #include <linux/pci.h> | ||
7 | #include <linux/platform_device.h> | ||
8 | #include <linux/i2c/pxa-i2c.h> | ||
9 | #include <linux/of.h> | ||
10 | #include <linux/of_device.h> | ||
11 | #include <linux/of_address.h> | ||
12 | |||
13 | #define CE4100_PCI_I2C_DEVS 3 | ||
14 | |||
15 | struct ce4100_devices { | ||
16 | struct platform_device *pdev[CE4100_PCI_I2C_DEVS]; | ||
17 | }; | ||
18 | |||
19 | static struct platform_device *add_i2c_device(struct pci_dev *dev, int bar) | ||
20 | { | ||
21 | struct platform_device *pdev; | ||
22 | struct i2c_pxa_platform_data pdata; | ||
23 | struct resource res[2]; | ||
24 | struct device_node *child; | ||
25 | static int devnum; | ||
26 | int ret; | ||
27 | |||
28 | memset(&pdata, 0, sizeof(struct i2c_pxa_platform_data)); | ||
29 | memset(&res, 0, sizeof(res)); | ||
30 | |||
31 | res[0].flags = IORESOURCE_MEM; | ||
32 | res[0].start = pci_resource_start(dev, bar); | ||
33 | res[0].end = pci_resource_end(dev, bar); | ||
34 | |||
35 | res[1].flags = IORESOURCE_IRQ; | ||
36 | res[1].start = dev->irq; | ||
37 | res[1].end = dev->irq; | ||
38 | |||
39 | for_each_child_of_node(dev->dev.of_node, child) { | ||
40 | const void *prop; | ||
41 | struct resource r; | ||
42 | int ret; | ||
43 | |||
44 | ret = of_address_to_resource(child, 0, &r); | ||
45 | if (ret < 0) | ||
46 | continue; | ||
47 | if (r.start != res[0].start) | ||
48 | continue; | ||
49 | if (r.end != res[0].end) | ||
50 | continue; | ||
51 | if (r.flags != res[0].flags) | ||
52 | continue; | ||
53 | |||
54 | prop = of_get_property(child, "fast-mode", NULL); | ||
55 | if (prop) | ||
56 | pdata.fast_mode = 1; | ||
57 | |||
58 | break; | ||
59 | } | ||
60 | |||
61 | if (!child) { | ||
62 | dev_err(&dev->dev, "failed to match a DT node for bar %d.\n", | ||
63 | bar); | ||
64 | ret = -EINVAL; | ||
65 | goto out; | ||
66 | } | ||
67 | |||
68 | pdev = platform_device_alloc("ce4100-i2c", devnum); | ||
69 | if (!pdev) { | ||
70 | of_node_put(child); | ||
71 | ret = -ENOMEM; | ||
72 | goto out; | ||
73 | } | ||
74 | pdev->dev.parent = &dev->dev; | ||
75 | pdev->dev.of_node = child; | ||
76 | |||
77 | ret = platform_device_add_resources(pdev, res, ARRAY_SIZE(res)); | ||
78 | if (ret) | ||
79 | goto err; | ||
80 | |||
81 | ret = platform_device_add_data(pdev, &pdata, sizeof(pdata)); | ||
82 | if (ret) | ||
83 | goto err; | ||
84 | |||
85 | ret = platform_device_add(pdev); | ||
86 | if (ret) | ||
87 | goto err; | ||
88 | devnum++; | ||
89 | return pdev; | ||
90 | err: | ||
91 | platform_device_put(pdev); | ||
92 | out: | ||
93 | return ERR_PTR(ret); | ||
94 | } | ||
95 | |||
96 | static int __devinit ce4100_i2c_probe(struct pci_dev *dev, | ||
97 | const struct pci_device_id *ent) | ||
98 | { | ||
99 | int ret; | ||
100 | int i; | ||
101 | struct ce4100_devices *sds; | ||
102 | |||
103 | ret = pci_enable_device_mem(dev); | ||
104 | if (ret) | ||
105 | return ret; | ||
106 | |||
107 | if (!dev->dev.of_node) { | ||
108 | dev_err(&dev->dev, "Missing device tree node.\n"); | ||
109 | return -EINVAL; | ||
110 | } | ||
111 | sds = kzalloc(sizeof(*sds), GFP_KERNEL); | ||
112 | if (!sds) | ||
113 | goto err_mem; | ||
114 | |||
115 | for (i = 0; i < ARRAY_SIZE(sds->pdev); i++) { | ||
116 | sds->pdev[i] = add_i2c_device(dev, i); | ||
117 | if (IS_ERR(sds->pdev[i])) { | ||
118 | while (--i >= 0) | ||
119 | platform_device_unregister(sds->pdev[i]); | ||
120 | goto err_dev_add; | ||
121 | } | ||
122 | } | ||
123 | pci_set_drvdata(dev, sds); | ||
124 | return 0; | ||
125 | |||
126 | err_dev_add: | ||
127 | pci_set_drvdata(dev, NULL); | ||
128 | kfree(sds); | ||
129 | err_mem: | ||
130 | pci_disable_device(dev); | ||
131 | return ret; | ||
132 | } | ||
133 | |||
134 | static void __devexit ce4100_i2c_remove(struct pci_dev *dev) | ||
135 | { | ||
136 | struct ce4100_devices *sds; | ||
137 | unsigned int i; | ||
138 | |||
139 | sds = pci_get_drvdata(dev); | ||
140 | pci_set_drvdata(dev, NULL); | ||
141 | |||
142 | for (i = 0; i < ARRAY_SIZE(sds->pdev); i++) | ||
143 | platform_device_unregister(sds->pdev[i]); | ||
144 | |||
145 | pci_disable_device(dev); | ||
146 | kfree(sds); | ||
147 | } | ||
148 | |||
149 | static struct pci_device_id ce4100_i2c_devices[] __devinitdata = { | ||
150 | { PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x2e68)}, | ||
151 | { }, | ||
152 | }; | ||
153 | MODULE_DEVICE_TABLE(pci, ce4100_i2c_devices); | ||
154 | |||
155 | static struct pci_driver ce4100_i2c_driver = { | ||
156 | .name = "ce4100_i2c", | ||
157 | .id_table = ce4100_i2c_devices, | ||
158 | .probe = ce4100_i2c_probe, | ||
159 | .remove = __devexit_p(ce4100_i2c_remove), | ||
160 | }; | ||
161 | |||
162 | static int __init ce4100_i2c_init(void) | ||
163 | { | ||
164 | return pci_register_driver(&ce4100_i2c_driver); | ||
165 | } | ||
166 | module_init(ce4100_i2c_init); | ||
167 | |||
168 | static void __exit ce4100_i2c_exit(void) | ||
169 | { | ||
170 | pci_unregister_driver(&ce4100_i2c_driver); | ||
171 | } | ||
172 | module_exit(ce4100_i2c_exit); | ||
173 | |||
174 | MODULE_DESCRIPTION("CE4100 PCI-I2C glue code for PXA's driver"); | ||
175 | MODULE_LICENSE("GPL v2"); | ||
176 | MODULE_AUTHOR("Sebastian Andrzej Siewior <bigeasy@linutronix.de>"); | ||
diff --git a/drivers/i2c/busses/i2c-pxa.c b/drivers/i2c/busses/i2c-pxa.c index fc2a90ed14cc..ab59b7e492ed 100644 --- a/drivers/i2c/busses/i2c-pxa.c +++ b/drivers/i2c/busses/i2c-pxa.c | |||
@@ -38,6 +38,13 @@ | |||
38 | 38 | ||
39 | #include <asm/irq.h> | 39 | #include <asm/irq.h> |
40 | 40 | ||
41 | #ifndef CONFIG_HAVE_CLK | ||
42 | #define clk_get(dev, id) NULL | ||
43 | #define clk_put(clk) do { } while (0) | ||
44 | #define clk_disable(clk) do { } while (0) | ||
45 | #define clk_enable(clk) do { } while (0) | ||
46 | #endif | ||
47 | |||
41 | struct pxa_reg_layout { | 48 | struct pxa_reg_layout { |
42 | u32 ibmr; | 49 | u32 ibmr; |
43 | u32 idbr; | 50 | u32 idbr; |
@@ -49,6 +56,7 @@ struct pxa_reg_layout { | |||
49 | enum pxa_i2c_types { | 56 | enum pxa_i2c_types { |
50 | REGS_PXA2XX, | 57 | REGS_PXA2XX, |
51 | REGS_PXA3XX, | 58 | REGS_PXA3XX, |
59 | REGS_CE4100, | ||
52 | }; | 60 | }; |
53 | 61 | ||
54 | /* | 62 | /* |
@@ -69,11 +77,19 @@ static struct pxa_reg_layout pxa_reg_layout[] = { | |||
69 | .isr = 0x18, | 77 | .isr = 0x18, |
70 | .isar = 0x20, | 78 | .isar = 0x20, |
71 | }, | 79 | }, |
80 | [REGS_CE4100] = { | ||
81 | .ibmr = 0x14, | ||
82 | .idbr = 0x0c, | ||
83 | .icr = 0x00, | ||
84 | .isr = 0x04, | ||
85 | /* no isar register */ | ||
86 | }, | ||
72 | }; | 87 | }; |
73 | 88 | ||
74 | static const struct platform_device_id i2c_pxa_id_table[] = { | 89 | static const struct platform_device_id i2c_pxa_id_table[] = { |
75 | { "pxa2xx-i2c", REGS_PXA2XX }, | 90 | { "pxa2xx-i2c", REGS_PXA2XX }, |
76 | { "pxa3xx-pwri2c", REGS_PXA3XX }, | 91 | { "pxa3xx-pwri2c", REGS_PXA3XX }, |
92 | { "ce4100-i2c", REGS_CE4100 }, | ||
77 | { }, | 93 | { }, |
78 | }; | 94 | }; |
79 | MODULE_DEVICE_TABLE(platform, i2c_pxa_id_table); | 95 | MODULE_DEVICE_TABLE(platform, i2c_pxa_id_table); |
@@ -442,7 +458,8 @@ static void i2c_pxa_reset(struct pxa_i2c *i2c) | |||
442 | writel(I2C_ISR_INIT, _ISR(i2c)); | 458 | writel(I2C_ISR_INIT, _ISR(i2c)); |
443 | writel(readl(_ICR(i2c)) & ~ICR_UR, _ICR(i2c)); | 459 | writel(readl(_ICR(i2c)) & ~ICR_UR, _ICR(i2c)); |
444 | 460 | ||
445 | writel(i2c->slave_addr, _ISAR(i2c)); | 461 | if (i2c->reg_isar) |
462 | writel(i2c->slave_addr, _ISAR(i2c)); | ||
446 | 463 | ||
447 | /* set control register values */ | 464 | /* set control register values */ |
448 | writel(I2C_ICR_INIT | (i2c->fast_mode ? ICR_FM : 0), _ICR(i2c)); | 465 | writel(I2C_ICR_INIT | (i2c->fast_mode ? ICR_FM : 0), _ICR(i2c)); |
@@ -1074,7 +1091,8 @@ static int i2c_pxa_probe(struct platform_device *dev) | |||
1074 | i2c->reg_idbr = i2c->reg_base + pxa_reg_layout[i2c_type].idbr; | 1091 | i2c->reg_idbr = i2c->reg_base + pxa_reg_layout[i2c_type].idbr; |
1075 | i2c->reg_icr = i2c->reg_base + pxa_reg_layout[i2c_type].icr; | 1092 | i2c->reg_icr = i2c->reg_base + pxa_reg_layout[i2c_type].icr; |
1076 | i2c->reg_isr = i2c->reg_base + pxa_reg_layout[i2c_type].isr; | 1093 | i2c->reg_isr = i2c->reg_base + pxa_reg_layout[i2c_type].isr; |
1077 | i2c->reg_isar = i2c->reg_base + pxa_reg_layout[i2c_type].isar; | 1094 | if (i2c_type != REGS_CE4100) |
1095 | i2c->reg_isar = i2c->reg_base + pxa_reg_layout[i2c_type].isar; | ||
1078 | 1096 | ||
1079 | i2c->iobase = res->start; | 1097 | i2c->iobase = res->start; |
1080 | i2c->iosize = resource_size(res); | 1098 | i2c->iosize = resource_size(res); |
@@ -1113,7 +1131,10 @@ static int i2c_pxa_probe(struct platform_device *dev) | |||
1113 | i2c->adap.algo_data = i2c; | 1131 | i2c->adap.algo_data = i2c; |
1114 | i2c->adap.dev.parent = &dev->dev; | 1132 | i2c->adap.dev.parent = &dev->dev; |
1115 | 1133 | ||
1116 | ret = i2c_add_numbered_adapter(&i2c->adap); | 1134 | if (i2c_type == REGS_CE4100) |
1135 | ret = i2c_add_adapter(&i2c->adap); | ||
1136 | else | ||
1137 | ret = i2c_add_numbered_adapter(&i2c->adap); | ||
1117 | if (ret < 0) { | 1138 | if (ret < 0) { |
1118 | printk(KERN_INFO "I2C: Failed to add bus\n"); | 1139 | printk(KERN_INFO "I2C: Failed to add bus\n"); |
1119 | goto eadapt; | 1140 | goto eadapt; |