diff options
Diffstat (limited to 'drivers/i2c')
-rw-r--r-- | drivers/i2c/busses/Kconfig | 9 | ||||
-rw-r--r-- | drivers/i2c/busses/Makefile | 1 | ||||
-rw-r--r-- | drivers/i2c/busses/i2c-designware.c | 624 |
3 files changed, 634 insertions, 0 deletions
diff --git a/drivers/i2c/busses/Kconfig b/drivers/i2c/busses/Kconfig index 3c259ee7ddda..aa87b6a3bbef 100644 --- a/drivers/i2c/busses/Kconfig +++ b/drivers/i2c/busses/Kconfig | |||
@@ -326,6 +326,15 @@ config I2C_DAVINCI | |||
326 | devices such as DaVinci NIC. | 326 | devices such as DaVinci NIC. |
327 | For details please see http://www.ti.com/davinci | 327 | For details please see http://www.ti.com/davinci |
328 | 328 | ||
329 | config I2C_DESIGNWARE | ||
330 | tristate "Synopsys DesignWare" | ||
331 | help | ||
332 | If you say yes to this option, support will be included for the | ||
333 | Synopsys DesignWare I2C adapter. Only master mode is supported. | ||
334 | |||
335 | This driver can also be built as a module. If so, the module | ||
336 | will be called i2c-designware. | ||
337 | |||
329 | config I2C_GPIO | 338 | config I2C_GPIO |
330 | tristate "GPIO-based bitbanging I2C" | 339 | tristate "GPIO-based bitbanging I2C" |
331 | depends on GENERIC_GPIO | 340 | depends on GENERIC_GPIO |
diff --git a/drivers/i2c/busses/Makefile b/drivers/i2c/busses/Makefile index edeabf003106..e654263bfc01 100644 --- a/drivers/i2c/busses/Makefile +++ b/drivers/i2c/busses/Makefile | |||
@@ -30,6 +30,7 @@ obj-$(CONFIG_I2C_AU1550) += i2c-au1550.o | |||
30 | obj-$(CONFIG_I2C_BLACKFIN_TWI) += i2c-bfin-twi.o | 30 | obj-$(CONFIG_I2C_BLACKFIN_TWI) += i2c-bfin-twi.o |
31 | obj-$(CONFIG_I2C_CPM) += i2c-cpm.o | 31 | obj-$(CONFIG_I2C_CPM) += i2c-cpm.o |
32 | obj-$(CONFIG_I2C_DAVINCI) += i2c-davinci.o | 32 | obj-$(CONFIG_I2C_DAVINCI) += i2c-davinci.o |
33 | obj-$(CONFIG_I2C_DESIGNWARE) += i2c-designware.o | ||
33 | obj-$(CONFIG_I2C_GPIO) += i2c-gpio.o | 34 | obj-$(CONFIG_I2C_GPIO) += i2c-gpio.o |
34 | obj-$(CONFIG_I2C_HIGHLANDER) += i2c-highlander.o | 35 | obj-$(CONFIG_I2C_HIGHLANDER) += i2c-highlander.o |
35 | obj-$(CONFIG_I2C_IBM_IIC) += i2c-ibm_iic.o | 36 | obj-$(CONFIG_I2C_IBM_IIC) += i2c-ibm_iic.o |
diff --git a/drivers/i2c/busses/i2c-designware.c b/drivers/i2c/busses/i2c-designware.c new file mode 100644 index 000000000000..b444762e9b9f --- /dev/null +++ b/drivers/i2c/busses/i2c-designware.c | |||
@@ -0,0 +1,624 @@ | |||
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 | * | ||
10 | * ---------------------------------------------------------------------------- | ||
11 | * | ||
12 | * This program is free software; you can redistribute it and/or modify | ||
13 | * it under the terms of the GNU General Public License as published by | ||
14 | * the Free Software Foundation; either version 2 of the License, or | ||
15 | * (at your option) any later version. | ||
16 | * | ||
17 | * This program is distributed in the hope that it will be useful, | ||
18 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
19 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
20 | * GNU General Public License for more details. | ||
21 | * | ||
22 | * You should have received a copy of the GNU General Public License | ||
23 | * along with this program; if not, write to the Free Software | ||
24 | * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | ||
25 | * ---------------------------------------------------------------------------- | ||
26 | * | ||
27 | */ | ||
28 | #include <linux/kernel.h> | ||
29 | #include <linux/module.h> | ||
30 | #include <linux/delay.h> | ||
31 | #include <linux/i2c.h> | ||
32 | #include <linux/clk.h> | ||
33 | #include <linux/errno.h> | ||
34 | #include <linux/sched.h> | ||
35 | #include <linux/err.h> | ||
36 | #include <linux/interrupt.h> | ||
37 | #include <linux/platform_device.h> | ||
38 | #include <linux/io.h> | ||
39 | |||
40 | /* | ||
41 | * Registers offset | ||
42 | */ | ||
43 | #define DW_IC_CON 0x0 | ||
44 | #define DW_IC_TAR 0x4 | ||
45 | #define DW_IC_DATA_CMD 0x10 | ||
46 | #define DW_IC_SS_SCL_HCNT 0x14 | ||
47 | #define DW_IC_SS_SCL_LCNT 0x18 | ||
48 | #define DW_IC_FS_SCL_HCNT 0x1c | ||
49 | #define DW_IC_FS_SCL_LCNT 0x20 | ||
50 | #define DW_IC_INTR_STAT 0x2c | ||
51 | #define DW_IC_INTR_MASK 0x30 | ||
52 | #define DW_IC_CLR_INTR 0x40 | ||
53 | #define DW_IC_ENABLE 0x6c | ||
54 | #define DW_IC_STATUS 0x70 | ||
55 | #define DW_IC_TXFLR 0x74 | ||
56 | #define DW_IC_RXFLR 0x78 | ||
57 | #define DW_IC_COMP_PARAM_1 0xf4 | ||
58 | #define DW_IC_TX_ABRT_SOURCE 0x80 | ||
59 | |||
60 | #define DW_IC_CON_MASTER 0x1 | ||
61 | #define DW_IC_CON_SPEED_STD 0x2 | ||
62 | #define DW_IC_CON_SPEED_FAST 0x4 | ||
63 | #define DW_IC_CON_10BITADDR_MASTER 0x10 | ||
64 | #define DW_IC_CON_RESTART_EN 0x20 | ||
65 | #define DW_IC_CON_SLAVE_DISABLE 0x40 | ||
66 | |||
67 | #define DW_IC_INTR_TX_EMPTY 0x10 | ||
68 | #define DW_IC_INTR_TX_ABRT 0x40 | ||
69 | #define DW_IC_INTR_STOP_DET 0x200 | ||
70 | |||
71 | #define DW_IC_STATUS_ACTIVITY 0x1 | ||
72 | |||
73 | #define DW_IC_ERR_TX_ABRT 0x1 | ||
74 | |||
75 | /* | ||
76 | * status codes | ||
77 | */ | ||
78 | #define STATUS_IDLE 0x0 | ||
79 | #define STATUS_WRITE_IN_PROGRESS 0x1 | ||
80 | #define STATUS_READ_IN_PROGRESS 0x2 | ||
81 | |||
82 | #define TIMEOUT 20 /* ms */ | ||
83 | |||
84 | /* | ||
85 | * hardware abort codes from the DW_IC_TX_ABRT_SOURCE register | ||
86 | * | ||
87 | * only expected abort codes are listed here | ||
88 | * refer to the datasheet for the full list | ||
89 | */ | ||
90 | #define ABRT_7B_ADDR_NOACK 0 | ||
91 | #define ABRT_10ADDR1_NOACK 1 | ||
92 | #define ABRT_10ADDR2_NOACK 2 | ||
93 | #define ABRT_TXDATA_NOACK 3 | ||
94 | #define ABRT_GCALL_NOACK 4 | ||
95 | #define ABRT_GCALL_READ 5 | ||
96 | #define ABRT_SBYTE_ACKDET 7 | ||
97 | #define ABRT_SBYTE_NORSTRT 9 | ||
98 | #define ABRT_10B_RD_NORSTRT 10 | ||
99 | #define ARB_MASTER_DIS 11 | ||
100 | #define ARB_LOST 12 | ||
101 | |||
102 | static char *abort_sources[] = { | ||
103 | [ABRT_7B_ADDR_NOACK] = | ||
104 | "slave address not acknowledged (7bit mode)", | ||
105 | [ABRT_10ADDR1_NOACK] = | ||
106 | "first address byte not acknowledged (10bit mode)", | ||
107 | [ABRT_10ADDR2_NOACK] = | ||
108 | "second address byte not acknowledged (10bit mode)", | ||
109 | [ABRT_TXDATA_NOACK] = | ||
110 | "data not acknowledged", | ||
111 | [ABRT_GCALL_NOACK] = | ||
112 | "no acknowledgement for a general call", | ||
113 | [ABRT_GCALL_READ] = | ||
114 | "read after general call", | ||
115 | [ABRT_SBYTE_ACKDET] = | ||
116 | "start byte acknowledged", | ||
117 | [ABRT_SBYTE_NORSTRT] = | ||
118 | "trying to send start byte when restart is disabled", | ||
119 | [ABRT_10B_RD_NORSTRT] = | ||
120 | "trying to read when restart is disabled (10bit mode)", | ||
121 | [ARB_MASTER_DIS] = | ||
122 | "trying to use disabled adapter", | ||
123 | [ARB_LOST] = | ||
124 | "lost arbitration", | ||
125 | }; | ||
126 | |||
127 | /** | ||
128 | * struct dw_i2c_dev - private i2c-designware data | ||
129 | * @dev: driver model device node | ||
130 | * @base: IO registers pointer | ||
131 | * @cmd_complete: tx completion indicator | ||
132 | * @pump_msg: continue in progress transfers | ||
133 | * @lock: protect this struct and IO registers | ||
134 | * @clk: input reference clock | ||
135 | * @cmd_err: run time hadware error code | ||
136 | * @msgs: points to an array of messages currently being transfered | ||
137 | * @msgs_num: the number of elements in msgs | ||
138 | * @msg_write_idx: the element index of the current tx message in the msgs | ||
139 | * array | ||
140 | * @tx_buf_len: the length of the current tx buffer | ||
141 | * @tx_buf: the current tx buffer | ||
142 | * @msg_read_idx: the element index of the current rx message in the msgs | ||
143 | * array | ||
144 | * @rx_buf_len: the length of the current rx buffer | ||
145 | * @rx_buf: the current rx buffer | ||
146 | * @msg_err: error status of the current transfer | ||
147 | * @status: i2c master status, one of STATUS_* | ||
148 | * @abort_source: copy of the TX_ABRT_SOURCE register | ||
149 | * @irq: interrupt number for the i2c master | ||
150 | * @adapter: i2c subsystem adapter node | ||
151 | * @tx_fifo_depth: depth of the hardware tx fifo | ||
152 | * @rx_fifo_depth: depth of the hardware rx fifo | ||
153 | */ | ||
154 | struct dw_i2c_dev { | ||
155 | struct device *dev; | ||
156 | void __iomem *base; | ||
157 | struct completion cmd_complete; | ||
158 | struct tasklet_struct pump_msg; | ||
159 | struct mutex lock; | ||
160 | struct clk *clk; | ||
161 | int cmd_err; | ||
162 | struct i2c_msg *msgs; | ||
163 | int msgs_num; | ||
164 | int msg_write_idx; | ||
165 | u16 tx_buf_len; | ||
166 | u8 *tx_buf; | ||
167 | int msg_read_idx; | ||
168 | u16 rx_buf_len; | ||
169 | u8 *rx_buf; | ||
170 | int msg_err; | ||
171 | unsigned int status; | ||
172 | u16 abort_source; | ||
173 | int irq; | ||
174 | struct i2c_adapter adapter; | ||
175 | unsigned int tx_fifo_depth; | ||
176 | unsigned int rx_fifo_depth; | ||
177 | }; | ||
178 | |||
179 | /** | ||
180 | * i2c_dw_init() - initialize the designware i2c master hardware | ||
181 | * @dev: device private data | ||
182 | * | ||
183 | * This functions configures and enables the I2C master. | ||
184 | * This function is called during I2C init function, and in case of timeout at | ||
185 | * run time. | ||
186 | */ | ||
187 | static void i2c_dw_init(struct dw_i2c_dev *dev) | ||
188 | { | ||
189 | u32 input_clock_khz = clk_get_rate(dev->clk) / 1000; | ||
190 | u16 ic_con; | ||
191 | |||
192 | /* Disable the adapter */ | ||
193 | writeb(0, dev->base + DW_IC_ENABLE); | ||
194 | |||
195 | /* set standard and fast speed deviders for high/low periods */ | ||
196 | writew((input_clock_khz * 40 / 10000)+1, /* std speed high, 4us */ | ||
197 | dev->base + DW_IC_SS_SCL_HCNT); | ||
198 | writew((input_clock_khz * 47 / 10000)+1, /* std speed low, 4.7us */ | ||
199 | dev->base + DW_IC_SS_SCL_LCNT); | ||
200 | writew((input_clock_khz * 6 / 10000)+1, /* fast speed high, 0.6us */ | ||
201 | dev->base + DW_IC_FS_SCL_HCNT); | ||
202 | writew((input_clock_khz * 13 / 10000)+1, /* fast speed low, 1.3us */ | ||
203 | dev->base + DW_IC_FS_SCL_LCNT); | ||
204 | |||
205 | /* configure the i2c master */ | ||
206 | ic_con = DW_IC_CON_MASTER | DW_IC_CON_SLAVE_DISABLE | | ||
207 | DW_IC_CON_RESTART_EN | DW_IC_CON_SPEED_FAST; | ||
208 | writew(ic_con, dev->base + DW_IC_CON); | ||
209 | } | ||
210 | |||
211 | /* | ||
212 | * Waiting for bus not busy | ||
213 | */ | ||
214 | static int i2c_dw_wait_bus_not_busy(struct dw_i2c_dev *dev) | ||
215 | { | ||
216 | int timeout = TIMEOUT; | ||
217 | |||
218 | while (readb(dev->base + DW_IC_STATUS) & DW_IC_STATUS_ACTIVITY) { | ||
219 | if (timeout <= 0) { | ||
220 | dev_warn(dev->dev, "timeout waiting for bus ready\n"); | ||
221 | return -ETIMEDOUT; | ||
222 | } | ||
223 | timeout--; | ||
224 | mdelay(1); | ||
225 | } | ||
226 | |||
227 | return 0; | ||
228 | } | ||
229 | |||
230 | /* | ||
231 | * Initiate low level master read/write transaction. | ||
232 | * This function is called from i2c_dw_xfer when starting a transfer. | ||
233 | * This function is also called from dw_i2c_pump_msg to continue a transfer | ||
234 | * that is longer than the size of the TX FIFO. | ||
235 | */ | ||
236 | static void | ||
237 | i2c_dw_xfer_msg(struct i2c_adapter *adap) | ||
238 | { | ||
239 | struct dw_i2c_dev *dev = i2c_get_adapdata(adap); | ||
240 | struct i2c_msg *msgs = dev->msgs; | ||
241 | int num = dev->msgs_num; | ||
242 | u16 ic_con, intr_mask; | ||
243 | int tx_limit = dev->tx_fifo_depth - readb(dev->base + DW_IC_TXFLR); | ||
244 | int rx_limit = dev->rx_fifo_depth - readb(dev->base + DW_IC_RXFLR); | ||
245 | u16 addr = msgs[dev->msg_write_idx].addr; | ||
246 | u16 buf_len = dev->tx_buf_len; | ||
247 | |||
248 | if (!(dev->status & STATUS_WRITE_IN_PROGRESS)) { | ||
249 | /* Disable the adapter */ | ||
250 | writeb(0, dev->base + DW_IC_ENABLE); | ||
251 | |||
252 | /* set the slave (target) address */ | ||
253 | writew(msgs[dev->msg_write_idx].addr, dev->base + DW_IC_TAR); | ||
254 | |||
255 | /* if the slave address is ten bit address, enable 10BITADDR */ | ||
256 | ic_con = readw(dev->base + DW_IC_CON); | ||
257 | if (msgs[dev->msg_write_idx].flags & I2C_M_TEN) | ||
258 | ic_con |= DW_IC_CON_10BITADDR_MASTER; | ||
259 | else | ||
260 | ic_con &= ~DW_IC_CON_10BITADDR_MASTER; | ||
261 | writew(ic_con, dev->base + DW_IC_CON); | ||
262 | |||
263 | /* Enable the adapter */ | ||
264 | writeb(1, dev->base + DW_IC_ENABLE); | ||
265 | } | ||
266 | |||
267 | for (; dev->msg_write_idx < num; dev->msg_write_idx++) { | ||
268 | /* if target address has changed, we need to | ||
269 | * reprogram the target address in the i2c | ||
270 | * adapter when we are done with this transfer | ||
271 | */ | ||
272 | if (msgs[dev->msg_write_idx].addr != addr) | ||
273 | return; | ||
274 | |||
275 | if (msgs[dev->msg_write_idx].len == 0) { | ||
276 | dev_err(dev->dev, | ||
277 | "%s: invalid message length\n", __func__); | ||
278 | dev->msg_err = -EINVAL; | ||
279 | return; | ||
280 | } | ||
281 | |||
282 | if (!(dev->status & STATUS_WRITE_IN_PROGRESS)) { | ||
283 | /* new i2c_msg */ | ||
284 | dev->tx_buf = msgs[dev->msg_write_idx].buf; | ||
285 | buf_len = msgs[dev->msg_write_idx].len; | ||
286 | } | ||
287 | |||
288 | while (buf_len > 0 && tx_limit > 0 && rx_limit > 0) { | ||
289 | if (msgs[dev->msg_write_idx].flags & I2C_M_RD) { | ||
290 | writew(0x100, dev->base + DW_IC_DATA_CMD); | ||
291 | rx_limit--; | ||
292 | } else | ||
293 | writew(*(dev->tx_buf++), | ||
294 | dev->base + DW_IC_DATA_CMD); | ||
295 | tx_limit--; buf_len--; | ||
296 | } | ||
297 | } | ||
298 | |||
299 | intr_mask = DW_IC_INTR_STOP_DET | DW_IC_INTR_TX_ABRT; | ||
300 | if (buf_len > 0) { /* more bytes to be written */ | ||
301 | intr_mask |= DW_IC_INTR_TX_EMPTY; | ||
302 | dev->status |= STATUS_WRITE_IN_PROGRESS; | ||
303 | } else | ||
304 | dev->status &= ~STATUS_WRITE_IN_PROGRESS; | ||
305 | writew(intr_mask, dev->base + DW_IC_INTR_MASK); | ||
306 | |||
307 | dev->tx_buf_len = buf_len; | ||
308 | } | ||
309 | |||
310 | static void | ||
311 | i2c_dw_read(struct i2c_adapter *adap) | ||
312 | { | ||
313 | struct dw_i2c_dev *dev = i2c_get_adapdata(adap); | ||
314 | struct i2c_msg *msgs = dev->msgs; | ||
315 | int num = dev->msgs_num; | ||
316 | u16 addr = msgs[dev->msg_read_idx].addr; | ||
317 | int rx_valid = readw(dev->base + DW_IC_RXFLR); | ||
318 | |||
319 | for (; dev->msg_read_idx < num; dev->msg_read_idx++) { | ||
320 | u16 len; | ||
321 | u8 *buf; | ||
322 | |||
323 | if (!(msgs[dev->msg_read_idx].flags & I2C_M_RD)) | ||
324 | continue; | ||
325 | |||
326 | /* different i2c client, reprogram the i2c adapter */ | ||
327 | if (msgs[dev->msg_read_idx].addr != addr) | ||
328 | return; | ||
329 | |||
330 | if (!(dev->status & STATUS_READ_IN_PROGRESS)) { | ||
331 | len = msgs[dev->msg_read_idx].len; | ||
332 | buf = msgs[dev->msg_read_idx].buf; | ||
333 | } else { | ||
334 | len = dev->rx_buf_len; | ||
335 | buf = dev->rx_buf; | ||
336 | } | ||
337 | |||
338 | for (; len > 0 && rx_valid > 0; len--, rx_valid--) | ||
339 | *buf++ = readb(dev->base + DW_IC_DATA_CMD); | ||
340 | |||
341 | if (len > 0) { | ||
342 | dev->status |= STATUS_READ_IN_PROGRESS; | ||
343 | dev->rx_buf_len = len; | ||
344 | dev->rx_buf = buf; | ||
345 | return; | ||
346 | } else | ||
347 | dev->status &= ~STATUS_READ_IN_PROGRESS; | ||
348 | } | ||
349 | } | ||
350 | |||
351 | /* | ||
352 | * Prepare controller for a transaction and call i2c_dw_xfer_msg | ||
353 | */ | ||
354 | static int | ||
355 | i2c_dw_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[], int num) | ||
356 | { | ||
357 | struct dw_i2c_dev *dev = i2c_get_adapdata(adap); | ||
358 | int ret; | ||
359 | |||
360 | dev_dbg(dev->dev, "%s: msgs: %d\n", __func__, num); | ||
361 | |||
362 | mutex_lock(&dev->lock); | ||
363 | |||
364 | INIT_COMPLETION(dev->cmd_complete); | ||
365 | dev->msgs = msgs; | ||
366 | dev->msgs_num = num; | ||
367 | dev->cmd_err = 0; | ||
368 | dev->msg_write_idx = 0; | ||
369 | dev->msg_read_idx = 0; | ||
370 | dev->msg_err = 0; | ||
371 | dev->status = STATUS_IDLE; | ||
372 | |||
373 | ret = i2c_dw_wait_bus_not_busy(dev); | ||
374 | if (ret < 0) | ||
375 | goto done; | ||
376 | |||
377 | /* start the transfers */ | ||
378 | i2c_dw_xfer_msg(adap); | ||
379 | |||
380 | /* wait for tx to complete */ | ||
381 | ret = wait_for_completion_interruptible_timeout(&dev->cmd_complete, HZ); | ||
382 | if (ret == 0) { | ||
383 | dev_err(dev->dev, "controller timed out\n"); | ||
384 | i2c_dw_init(dev); | ||
385 | ret = -ETIMEDOUT; | ||
386 | goto done; | ||
387 | } else if (ret < 0) | ||
388 | goto done; | ||
389 | |||
390 | if (dev->msg_err) { | ||
391 | ret = dev->msg_err; | ||
392 | goto done; | ||
393 | } | ||
394 | |||
395 | /* no error */ | ||
396 | if (likely(!dev->cmd_err)) { | ||
397 | /* read rx fifo, and disable the adapter */ | ||
398 | do { | ||
399 | i2c_dw_read(adap); | ||
400 | } while (dev->status & STATUS_READ_IN_PROGRESS); | ||
401 | writeb(0, dev->base + DW_IC_ENABLE); | ||
402 | ret = num; | ||
403 | goto done; | ||
404 | } | ||
405 | |||
406 | /* We have an error */ | ||
407 | if (dev->cmd_err == DW_IC_ERR_TX_ABRT) { | ||
408 | unsigned long abort_source = dev->abort_source; | ||
409 | int i; | ||
410 | |||
411 | for_each_bit(i, &abort_source, ARRAY_SIZE(abort_sources)) { | ||
412 | dev_err(dev->dev, "%s: %s\n", __func__, abort_sources[i]); | ||
413 | } | ||
414 | } | ||
415 | ret = -EIO; | ||
416 | |||
417 | done: | ||
418 | mutex_unlock(&dev->lock); | ||
419 | |||
420 | return ret; | ||
421 | } | ||
422 | |||
423 | static u32 i2c_dw_func(struct i2c_adapter *adap) | ||
424 | { | ||
425 | return I2C_FUNC_I2C | I2C_FUNC_10BIT_ADDR; | ||
426 | } | ||
427 | |||
428 | static void dw_i2c_pump_msg(unsigned long data) | ||
429 | { | ||
430 | struct dw_i2c_dev *dev = (struct dw_i2c_dev *) data; | ||
431 | u16 intr_mask; | ||
432 | |||
433 | i2c_dw_read(&dev->adapter); | ||
434 | i2c_dw_xfer_msg(&dev->adapter); | ||
435 | |||
436 | intr_mask = DW_IC_INTR_STOP_DET | DW_IC_INTR_TX_ABRT; | ||
437 | if (dev->status & STATUS_WRITE_IN_PROGRESS) | ||
438 | intr_mask |= DW_IC_INTR_TX_EMPTY; | ||
439 | writew(intr_mask, dev->base + DW_IC_INTR_MASK); | ||
440 | } | ||
441 | |||
442 | /* | ||
443 | * Interrupt service routine. This gets called whenever an I2C interrupt | ||
444 | * occurs. | ||
445 | */ | ||
446 | static irqreturn_t i2c_dw_isr(int this_irq, void *dev_id) | ||
447 | { | ||
448 | struct dw_i2c_dev *dev = dev_id; | ||
449 | u16 stat; | ||
450 | |||
451 | stat = readw(dev->base + DW_IC_INTR_STAT); | ||
452 | dev_dbg(dev->dev, "%s: stat=0x%x\n", __func__, stat); | ||
453 | if (stat & DW_IC_INTR_TX_ABRT) { | ||
454 | dev->abort_source = readw(dev->base + DW_IC_TX_ABRT_SOURCE); | ||
455 | dev->cmd_err |= DW_IC_ERR_TX_ABRT; | ||
456 | dev->status = STATUS_IDLE; | ||
457 | } else if (stat & DW_IC_INTR_TX_EMPTY) | ||
458 | tasklet_schedule(&dev->pump_msg); | ||
459 | |||
460 | readb(dev->base + DW_IC_CLR_INTR); /* clear interrupts */ | ||
461 | writew(0, dev->base + DW_IC_INTR_MASK); /* disable interrupts */ | ||
462 | if (stat & (DW_IC_INTR_TX_ABRT | DW_IC_INTR_STOP_DET)) | ||
463 | complete(&dev->cmd_complete); | ||
464 | |||
465 | return IRQ_HANDLED; | ||
466 | } | ||
467 | |||
468 | static struct i2c_algorithm i2c_dw_algo = { | ||
469 | .master_xfer = i2c_dw_xfer, | ||
470 | .functionality = i2c_dw_func, | ||
471 | }; | ||
472 | |||
473 | static int __devinit dw_i2c_probe(struct platform_device *pdev) | ||
474 | { | ||
475 | struct dw_i2c_dev *dev; | ||
476 | struct i2c_adapter *adap; | ||
477 | struct resource *mem, *irq, *ioarea; | ||
478 | int r; | ||
479 | |||
480 | /* NOTE: driver uses the static register mapping */ | ||
481 | mem = platform_get_resource(pdev, IORESOURCE_MEM, 0); | ||
482 | if (!mem) { | ||
483 | dev_err(&pdev->dev, "no mem resource?\n"); | ||
484 | return -EINVAL; | ||
485 | } | ||
486 | |||
487 | irq = platform_get_resource(pdev, IORESOURCE_IRQ, 0); | ||
488 | if (!irq) { | ||
489 | dev_err(&pdev->dev, "no irq resource?\n"); | ||
490 | return -EINVAL; | ||
491 | } | ||
492 | |||
493 | ioarea = request_mem_region(mem->start, resource_size(mem), | ||
494 | pdev->name); | ||
495 | if (!ioarea) { | ||
496 | dev_err(&pdev->dev, "I2C region already claimed\n"); | ||
497 | return -EBUSY; | ||
498 | } | ||
499 | |||
500 | dev = kzalloc(sizeof(struct dw_i2c_dev), GFP_KERNEL); | ||
501 | if (!dev) { | ||
502 | r = -ENOMEM; | ||
503 | goto err_release_region; | ||
504 | } | ||
505 | |||
506 | init_completion(&dev->cmd_complete); | ||
507 | tasklet_init(&dev->pump_msg, dw_i2c_pump_msg, (unsigned long) dev); | ||
508 | mutex_init(&dev->lock); | ||
509 | dev->dev = get_device(&pdev->dev); | ||
510 | dev->irq = irq->start; | ||
511 | platform_set_drvdata(pdev, dev); | ||
512 | |||
513 | dev->clk = clk_get(&pdev->dev, NULL); | ||
514 | if (IS_ERR(dev->clk)) { | ||
515 | r = -ENODEV; | ||
516 | goto err_free_mem; | ||
517 | } | ||
518 | clk_enable(dev->clk); | ||
519 | |||
520 | dev->base = ioremap(mem->start, resource_size(mem)); | ||
521 | if (dev->base == NULL) { | ||
522 | dev_err(&pdev->dev, "failure mapping io resources\n"); | ||
523 | r = -EBUSY; | ||
524 | goto err_unuse_clocks; | ||
525 | } | ||
526 | { | ||
527 | u32 param1 = readl(dev->base + DW_IC_COMP_PARAM_1); | ||
528 | |||
529 | dev->tx_fifo_depth = ((param1 >> 16) & 0xff) + 1; | ||
530 | dev->rx_fifo_depth = ((param1 >> 8) & 0xff) + 1; | ||
531 | } | ||
532 | i2c_dw_init(dev); | ||
533 | |||
534 | writew(0, dev->base + DW_IC_INTR_MASK); /* disable IRQ */ | ||
535 | r = request_irq(dev->irq, i2c_dw_isr, 0, pdev->name, dev); | ||
536 | if (r) { | ||
537 | dev_err(&pdev->dev, "failure requesting irq %i\n", dev->irq); | ||
538 | goto err_iounmap; | ||
539 | } | ||
540 | |||
541 | adap = &dev->adapter; | ||
542 | i2c_set_adapdata(adap, dev); | ||
543 | adap->owner = THIS_MODULE; | ||
544 | adap->class = I2C_CLASS_HWMON; | ||
545 | strlcpy(adap->name, "Synopsys DesignWare I2C adapter", | ||
546 | sizeof(adap->name)); | ||
547 | adap->algo = &i2c_dw_algo; | ||
548 | adap->dev.parent = &pdev->dev; | ||
549 | |||
550 | adap->nr = pdev->id; | ||
551 | r = i2c_add_numbered_adapter(adap); | ||
552 | if (r) { | ||
553 | dev_err(&pdev->dev, "failure adding adapter\n"); | ||
554 | goto err_free_irq; | ||
555 | } | ||
556 | |||
557 | return 0; | ||
558 | |||
559 | err_free_irq: | ||
560 | free_irq(dev->irq, dev); | ||
561 | err_iounmap: | ||
562 | iounmap(dev->base); | ||
563 | err_unuse_clocks: | ||
564 | clk_disable(dev->clk); | ||
565 | clk_put(dev->clk); | ||
566 | dev->clk = NULL; | ||
567 | err_free_mem: | ||
568 | platform_set_drvdata(pdev, NULL); | ||
569 | put_device(&pdev->dev); | ||
570 | kfree(dev); | ||
571 | err_release_region: | ||
572 | release_mem_region(mem->start, resource_size(mem)); | ||
573 | |||
574 | return r; | ||
575 | } | ||
576 | |||
577 | static int __devexit dw_i2c_remove(struct platform_device *pdev) | ||
578 | { | ||
579 | struct dw_i2c_dev *dev = platform_get_drvdata(pdev); | ||
580 | struct resource *mem; | ||
581 | |||
582 | platform_set_drvdata(pdev, NULL); | ||
583 | i2c_del_adapter(&dev->adapter); | ||
584 | put_device(&pdev->dev); | ||
585 | |||
586 | clk_disable(dev->clk); | ||
587 | clk_put(dev->clk); | ||
588 | dev->clk = NULL; | ||
589 | |||
590 | writeb(0, dev->base + DW_IC_ENABLE); | ||
591 | free_irq(dev->irq, dev); | ||
592 | kfree(dev); | ||
593 | |||
594 | mem = platform_get_resource(pdev, IORESOURCE_MEM, 0); | ||
595 | release_mem_region(mem->start, resource_size(mem)); | ||
596 | return 0; | ||
597 | } | ||
598 | |||
599 | /* work with hotplug and coldplug */ | ||
600 | MODULE_ALIAS("platform:i2c_designware"); | ||
601 | |||
602 | static struct platform_driver dw_i2c_driver = { | ||
603 | .remove = __devexit_p(dw_i2c_remove), | ||
604 | .driver = { | ||
605 | .name = "i2c_designware", | ||
606 | .owner = THIS_MODULE, | ||
607 | }, | ||
608 | }; | ||
609 | |||
610 | static int __init dw_i2c_init_driver(void) | ||
611 | { | ||
612 | return platform_driver_probe(&dw_i2c_driver, dw_i2c_probe); | ||
613 | } | ||
614 | module_init(dw_i2c_init_driver); | ||
615 | |||
616 | static void __exit dw_i2c_exit_driver(void) | ||
617 | { | ||
618 | platform_driver_unregister(&dw_i2c_driver); | ||
619 | } | ||
620 | module_exit(dw_i2c_exit_driver); | ||
621 | |||
622 | MODULE_AUTHOR("Baruch Siach <baruch@tkos.co.il>"); | ||
623 | MODULE_DESCRIPTION("Synopsys DesignWare I2C bus adapter"); | ||
624 | MODULE_LICENSE("GPL"); | ||