aboutsummaryrefslogtreecommitdiffstats
path: root/drivers
diff options
context:
space:
mode:
authorDirk Brandewie <dirk.brandewie@gmail.com>2011-10-06 14:26:35 -0400
committerBen Dooks <ben-linux@fluff.org>2011-10-29 06:03:52 -0400
commitfe20ff5c7e9ca7f5369aacc7d7ca3efeda3b90fe (patch)
tree67100c5dd0fe8a212063eada32ac4ee9eca48983 /drivers
parentf3fa9f3da5621154323775ff0efdba99dcebcee4 (diff)
i2c-designware: Add support for Designware core behind PCI devices.
Signed-off-by: Dirk Brandewie <dirk.brandewie@gmail.com> Signed-off-by: Ben Dooks <ben-linux@fluff.org>
Diffstat (limited to 'drivers')
-rw-r--r--drivers/i2c/busses/Kconfig10
-rw-r--r--drivers/i2c/busses/Makefile2
-rw-r--r--drivers/i2c/busses/i2c-designware-core.h1
-rw-r--r--drivers/i2c/busses/i2c-designware-pcidrv.c316
4 files changed, 329 insertions, 0 deletions
diff --git a/drivers/i2c/busses/Kconfig b/drivers/i2c/busses/Kconfig
index e6f6e88021e5..1d7ce9c18bff 100644
--- a/drivers/i2c/busses/Kconfig
+++ b/drivers/i2c/busses/Kconfig
@@ -360,6 +360,16 @@ config I2C_DESIGNWARE_PLATFORM
360 This driver can also be built as a module. If so, the module 360 This driver can also be built as a module. If so, the module
361 will be called i2c-designware-platform. 361 will be called i2c-designware-platform.
362 362
363config I2C_DESIGNWARE_PCI
364 tristate "Synopsys DesignWare PCI"
365 depends on PCI
366 help
367 If you say yes to this option, support will be included for the
368 Synopsys DesignWare I2C adapter. Only master mode is supported.
369
370 This driver can also be built as a module. If so, the module
371 will be called i2c-designware-pci.
372
363config I2C_GPIO 373config I2C_GPIO
364 tristate "GPIO-based bitbanging I2C" 374 tristate "GPIO-based bitbanging I2C"
365 depends on GENERIC_GPIO 375 depends on GENERIC_GPIO
diff --git a/drivers/i2c/busses/Makefile b/drivers/i2c/busses/Makefile
index d7fe55fb0776..fba6da60aa0e 100644
--- a/drivers/i2c/busses/Makefile
+++ b/drivers/i2c/busses/Makefile
@@ -35,6 +35,8 @@ obj-$(CONFIG_I2C_CPM) += i2c-cpm.o
35obj-$(CONFIG_I2C_DAVINCI) += i2c-davinci.o 35obj-$(CONFIG_I2C_DAVINCI) += i2c-davinci.o
36obj-$(CONFIG_I2C_DESIGNWARE_PLATFORM) += i2c-designware-platform.o 36obj-$(CONFIG_I2C_DESIGNWARE_PLATFORM) += i2c-designware-platform.o
37i2c-designware-platform-objs := i2c-designware-platdrv.o i2c-designware-core.o 37i2c-designware-platform-objs := i2c-designware-platdrv.o i2c-designware-core.o
38obj-$(CONFIG_I2C_DESIGNWARE_PCI) += i2c-designware-pci.o
39i2c-designware-pci-objs := i2c-designware-pcidrv.o i2c-designware-core.o
38obj-$(CONFIG_I2C_GPIO) += i2c-gpio.o 40obj-$(CONFIG_I2C_GPIO) += i2c-gpio.o
39obj-$(CONFIG_I2C_HIGHLANDER) += i2c-highlander.o 41obj-$(CONFIG_I2C_HIGHLANDER) += i2c-highlander.o
40obj-$(CONFIG_I2C_IBM_IIC) += i2c-ibm_iic.o 42obj-$(CONFIG_I2C_IBM_IIC) += i2c-ibm_iic.o
diff --git a/drivers/i2c/busses/i2c-designware-core.h b/drivers/i2c/busses/i2c-designware-core.h
index dc016e2afe9c..601dd67a6c27 100644
--- a/drivers/i2c/busses/i2c-designware-core.h
+++ b/drivers/i2c/busses/i2c-designware-core.h
@@ -68,6 +68,7 @@ struct dw_i2c_dev {
68 struct mutex lock; 68 struct mutex lock;
69 struct clk *clk; 69 struct clk *clk;
70 u32 (*get_clk_rate_khz) (struct dw_i2c_dev *dev); 70 u32 (*get_clk_rate_khz) (struct dw_i2c_dev *dev);
71 struct dw_pci_controller *controller;
71 int cmd_err; 72 int cmd_err;
72 struct i2c_msg *msgs; 73 struct i2c_msg *msgs;
73 int msgs_num; 74 int msgs_num;
diff --git a/drivers/i2c/busses/i2c-designware-pcidrv.c b/drivers/i2c/busses/i2c-designware-pcidrv.c
new file mode 100644
index 000000000000..83307ef3b41f
--- /dev/null
+++ b/drivers/i2c/busses/i2c-designware-pcidrv.c
@@ -0,0 +1,316 @@
1/*
2 * Synopsys DesignWare I2C adapter driver (master only).
3 *
4 * Based on the TI DAVINCI I2C adapter driver.
5 *
6 * Copyright (C) 2006 Texas Instruments.
7 * Copyright (C) 2007 MontaVista Software Inc.
8 * Copyright (C) 2009 Provigent Ltd.
9 * Copyright (C) 2011 Intel corporation.
10 *
11 * ----------------------------------------------------------------------------
12 *
13 * This program is free software; you can redistribute it and/or modify
14 * it under the terms of the GNU General Public License as published by
15 * the Free Software Foundation; either version 2 of the License, or
16 * (at your option) any later version.
17 *
18 * This program is distributed in the hope that it will be useful,
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 * GNU General Public License for more details.
22 *
23 * You should have received a copy of the GNU General Public License
24 * along with this program; if not, write to the Free Software
25 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
26 * ----------------------------------------------------------------------------
27 *
28 */
29
30#include <linux/kernel.h>
31#include <linux/module.h>
32#include <linux/delay.h>
33#include <linux/i2c.h>
34#include <linux/errno.h>
35#include <linux/sched.h>
36#include <linux/err.h>
37#include <linux/interrupt.h>
38#include <linux/io.h>
39#include <linux/slab.h>
40#include <linux/pci.h>
41#include "i2c-designware-core.h"
42
43#define DRIVER_NAME "i2c-designware-pci"
44
45enum dw_pci_ctl_id_t {
46 moorestown_0,
47 moorestown_1,
48 moorestown_2,
49
50 medfield_0,
51 medfield_1,
52 medfield_2,
53 medfield_3,
54 medfield_4,
55 medfield_5,
56};
57
58struct dw_pci_controller {
59 u32 bus_num;
60 u32 bus_cfg;
61 u32 tx_fifo_depth;
62 u32 rx_fifo_depth;
63 u32 clk_khz;
64};
65
66#define INTEL_MID_STD_CFG (DW_IC_CON_MASTER | \
67 DW_IC_CON_SLAVE_DISABLE | \
68 DW_IC_CON_RESTART_EN)
69
70static struct dw_pci_controller dw_pci_controllers[] = {
71 [moorestown_0] = {
72 .bus_num = 0,
73 .bus_cfg = INTEL_MID_STD_CFG | DW_IC_CON_SPEED_FAST,
74 .tx_fifo_depth = 32,
75 .rx_fifo_depth = 32,
76 .clk_khz = 25000,
77 },
78 [moorestown_1] = {
79 .bus_num = 1,
80 .bus_cfg = INTEL_MID_STD_CFG | DW_IC_CON_SPEED_FAST,
81 .tx_fifo_depth = 32,
82 .rx_fifo_depth = 32,
83 .clk_khz = 25000,
84 },
85 [moorestown_2] = {
86 .bus_num = 2,
87 .bus_cfg = INTEL_MID_STD_CFG | DW_IC_CON_SPEED_FAST,
88 .tx_fifo_depth = 32,
89 .rx_fifo_depth = 32,
90 .clk_khz = 25000,
91 },
92 [medfield_0] = {
93 .bus_num = 0,
94 .bus_cfg = INTEL_MID_STD_CFG | DW_IC_CON_SPEED_FAST,
95 .tx_fifo_depth = 32,
96 .rx_fifo_depth = 32,
97 .clk_khz = 25000,
98 },
99 [medfield_1] = {
100 .bus_num = 1,
101 .bus_cfg = INTEL_MID_STD_CFG | DW_IC_CON_SPEED_FAST,
102 .tx_fifo_depth = 32,
103 .rx_fifo_depth = 32,
104 .clk_khz = 25000,
105 },
106 [medfield_2] = {
107 .bus_num = 2,
108 .bus_cfg = INTEL_MID_STD_CFG | DW_IC_CON_SPEED_FAST,
109 .tx_fifo_depth = 32,
110 .rx_fifo_depth = 32,
111 .clk_khz = 25000,
112 },
113 [medfield_3] = {
114 .bus_num = 3,
115 .bus_cfg = INTEL_MID_STD_CFG | DW_IC_CON_SPEED_STD,
116 .tx_fifo_depth = 32,
117 .rx_fifo_depth = 32,
118 .clk_khz = 25000,
119 },
120 [medfield_4] = {
121 .bus_num = 4,
122 .bus_cfg = INTEL_MID_STD_CFG | DW_IC_CON_SPEED_FAST,
123 .tx_fifo_depth = 32,
124 .rx_fifo_depth = 32,
125 .clk_khz = 25000,
126 },
127 [medfield_5] = {
128 .bus_num = 5,
129 .bus_cfg = INTEL_MID_STD_CFG | DW_IC_CON_SPEED_FAST,
130 .tx_fifo_depth = 32,
131 .rx_fifo_depth = 32,
132 .clk_khz = 25000,
133 },
134};
135static struct i2c_algorithm i2c_dw_algo = {
136 .master_xfer = i2c_dw_xfer,
137 .functionality = i2c_dw_func,
138};
139
140static u32 i2c_dw_get_clk_rate_khz(struct dw_i2c_dev *dev)
141{
142 return dev->controller->clk_khz;
143}
144
145static int __devinit i2c_dw_pci_probe(struct pci_dev *pdev,
146const struct pci_device_id *id)
147{
148 struct dw_i2c_dev *dev;
149 struct i2c_adapter *adap;
150 unsigned long start, len;
151 void __iomem *base;
152 int r;
153 struct dw_pci_controller *controller;
154
155 if (id->driver_data >= ARRAY_SIZE(dw_pci_controllers)) {
156 printk(KERN_ERR "dw_i2c_pci_probe: invalid driver data %ld\n",
157 id->driver_data);
158 return -EINVAL;
159 }
160
161 controller = &dw_pci_controllers[id->driver_data];
162
163 r = pci_enable_device(pdev);
164 if (r) {
165 dev_err(&pdev->dev, "Failed to enable I2C PCI device (%d)\n",
166 r);
167 goto exit;
168 }
169
170 /* Determine the address of the I2C area */
171 start = pci_resource_start(pdev, 0);
172 len = pci_resource_len(pdev, 0);
173 if (!start || len == 0) {
174 dev_err(&pdev->dev, "base address not set\n");
175 r = -ENODEV;
176 goto exit;
177 }
178
179 r = pci_request_region(pdev, 0, DRIVER_NAME);
180 if (r) {
181 dev_err(&pdev->dev, "failed to request I2C region "
182 "0x%lx-0x%lx\n", start,
183 (unsigned long)pci_resource_end(pdev, 0));
184 goto exit;
185 }
186
187 base = ioremap_nocache(start, len);
188 if (!base) {
189 dev_err(&pdev->dev, "I/O memory remapping failed\n");
190 r = -ENOMEM;
191 goto err_release_region;
192 }
193
194
195 dev = kzalloc(sizeof(struct dw_i2c_dev), GFP_KERNEL);
196 if (!dev) {
197 r = -ENOMEM;
198 goto err_release_region;
199 }
200
201 init_completion(&dev->cmd_complete);
202 mutex_init(&dev->lock);
203 dev->clk = NULL;
204 dev->controller = controller;
205 dev->get_clk_rate_khz = i2c_dw_get_clk_rate_khz;
206 dev->base = base;
207 dev->dev = get_device(&pdev->dev);
208 dev->functionality =
209 I2C_FUNC_I2C |
210 I2C_FUNC_SMBUS_BYTE |
211 I2C_FUNC_SMBUS_BYTE_DATA |
212 I2C_FUNC_SMBUS_WORD_DATA |
213 I2C_FUNC_SMBUS_I2C_BLOCK;
214 dev->master_cfg = controller->bus_cfg;
215
216 pci_set_drvdata(pdev, dev);
217
218 dev->tx_fifo_depth = controller->tx_fifo_depth;
219 dev->rx_fifo_depth = controller->rx_fifo_depth;
220 r = i2c_dw_init(dev);
221 if (r)
222 goto err_iounmap;
223
224 adap = &dev->adapter;
225 i2c_set_adapdata(adap, dev);
226 adap->owner = THIS_MODULE;
227 adap->class = 0;
228 adap->algo = &i2c_dw_algo;
229 adap->dev.parent = &pdev->dev;
230 adap->nr = controller->bus_num;
231 snprintf(adap->name, sizeof(adap->name), "i2c-designware-pci-%d",
232 adap->nr);
233
234 r = request_irq(pdev->irq, i2c_dw_isr, IRQF_SHARED, adap->name, dev);
235 if (r) {
236 dev_err(&pdev->dev, "failure requesting irq %i\n", dev->irq);
237 goto err_iounmap;
238 }
239
240 i2c_dw_disable_int(dev);
241 i2c_dw_clear_int(dev);
242 r = i2c_add_numbered_adapter(adap);
243 if (r) {
244 dev_err(&pdev->dev, "failure adding adapter\n");
245 goto err_free_irq;
246 }
247
248 return 0;
249
250err_free_irq:
251 free_irq(pdev->irq, dev);
252err_iounmap:
253 iounmap(dev->base);
254 pci_set_drvdata(pdev, NULL);
255 put_device(&pdev->dev);
256 kfree(dev);
257err_release_region:
258 pci_release_region(pdev, 0);
259exit:
260 return r;
261}
262
263static void __devexit i2c_dw_pci_remove(struct pci_dev *pdev)
264{
265 struct dw_i2c_dev *dev = pci_get_drvdata(pdev);
266
267 pci_set_drvdata(pdev, NULL);
268 i2c_del_adapter(&dev->adapter);
269 put_device(&pdev->dev);
270
271 free_irq(dev->irq, dev);
272 kfree(dev);
273 pci_release_region(pdev, 0);
274}
275
276/* work with hotplug and coldplug */
277MODULE_ALIAS("i2c_designware-pci");
278
279DEFINE_PCI_DEVICE_TABLE(i2_designware_pci_ids) = {
280 /* Moorestown */
281 { PCI_VDEVICE(INTEL, 0x0802), moorestown_0 },
282 { PCI_VDEVICE(INTEL, 0x0803), moorestown_1 },
283 { PCI_VDEVICE(INTEL, 0x0804), moorestown_2 },
284 /* Medfield */
285 { PCI_VDEVICE(INTEL, 0x0817), medfield_3,},
286 { PCI_VDEVICE(INTEL, 0x0818), medfield_4 },
287 { PCI_VDEVICE(INTEL, 0x0819), medfield_5 },
288 { PCI_VDEVICE(INTEL, 0x082C), medfield_0 },
289 { PCI_VDEVICE(INTEL, 0x082D), medfield_1 },
290 { PCI_VDEVICE(INTEL, 0x082E), medfield_2 },
291 { 0,}
292};
293MODULE_DEVICE_TABLE(pci, i2_designware_pci_ids);
294
295static struct pci_driver dw_i2c_driver = {
296 .name = DRIVER_NAME,
297 .id_table = i2_designware_pci_ids,
298 .probe = i2c_dw_pci_probe,
299 .remove = __devexit_p(i2c_dw_pci_remove),
300};
301
302static int __init dw_i2c_init_driver(void)
303{
304 return pci_register_driver(&dw_i2c_driver);
305}
306module_init(dw_i2c_init_driver);
307
308static void __exit dw_i2c_exit_driver(void)
309{
310 pci_unregister_driver(&dw_i2c_driver);
311}
312module_exit(dw_i2c_exit_driver);
313
314MODULE_AUTHOR("Baruch Siach <baruch@tkos.co.il>");
315MODULE_DESCRIPTION("Synopsys DesignWare PCI I2C bus adapter");
316MODULE_LICENSE("GPL");