blob: 40136ea7a46fb1afc7c6268506bfbd3e470f8dd8 [file] [log] [blame]
Bryan Wud24ecfc2007-05-01 23:26:32 +02001/*
Mike Frysingerbd584992008-04-22 22:16:48 +02002 * Blackfin On-Chip Two Wire Interface Driver
Bryan Wud24ecfc2007-05-01 23:26:32 +02003 *
Mike Frysingerbd584992008-04-22 22:16:48 +02004 * Copyright 2005-2007 Analog Devices Inc.
Bryan Wud24ecfc2007-05-01 23:26:32 +02005 *
Mike Frysingerbd584992008-04-22 22:16:48 +02006 * Enter bugs at http://blackfin.uclinux.org/
Bryan Wud24ecfc2007-05-01 23:26:32 +02007 *
Mike Frysingerbd584992008-04-22 22:16:48 +02008 * Licensed under the GPL-2 or later.
Bryan Wud24ecfc2007-05-01 23:26:32 +02009 */
10
11#include <linux/module.h>
12#include <linux/kernel.h>
13#include <linux/init.h>
14#include <linux/i2c.h>
15#include <linux/mm.h>
16#include <linux/timer.h>
17#include <linux/spinlock.h>
18#include <linux/completion.h>
19#include <linux/interrupt.h>
20#include <linux/platform_device.h>
21
22#include <asm/blackfin.h>
Bryan Wu74d362e2008-04-22 22:16:48 +020023#include <asm/portmux.h>
Bryan Wud24ecfc2007-05-01 23:26:32 +020024#include <asm/irq.h>
25
26#define POLL_TIMEOUT (2 * HZ)
27
28/* SMBus mode*/
Sonic Zhang4dd39bb2008-04-22 22:16:47 +020029#define TWI_I2C_MODE_STANDARD 1
30#define TWI_I2C_MODE_STANDARDSUB 2
31#define TWI_I2C_MODE_COMBINED 3
32#define TWI_I2C_MODE_REPEAT 4
Bryan Wud24ecfc2007-05-01 23:26:32 +020033
34struct bfin_twi_iface {
Bryan Wud24ecfc2007-05-01 23:26:32 +020035 int irq;
36 spinlock_t lock;
37 char read_write;
38 u8 command;
39 u8 *transPtr;
40 int readNum;
41 int writeNum;
42 int cur_mode;
43 int manual_stop;
44 int result;
45 int timeout_count;
46 struct timer_list timeout_timer;
47 struct i2c_adapter adap;
48 struct completion complete;
Sonic Zhang4dd39bb2008-04-22 22:16:47 +020049 struct i2c_msg *pmsg;
50 int msg_num;
51 int cur_msg;
Michael Hennerich958585f2008-07-27 14:41:54 +080052 u16 saved_clkdiv;
53 u16 saved_control;
Bryan Wuaa3d0202008-04-22 22:16:48 +020054 void __iomem *regs_base;
Bryan Wud24ecfc2007-05-01 23:26:32 +020055};
56
Bryan Wuaa3d0202008-04-22 22:16:48 +020057
58#define DEFINE_TWI_REG(reg, off) \
59static inline u16 read_##reg(struct bfin_twi_iface *iface) \
60 { return bfin_read16(iface->regs_base + (off)); } \
61static inline void write_##reg(struct bfin_twi_iface *iface, u16 v) \
62 { bfin_write16(iface->regs_base + (off), v); }
63
64DEFINE_TWI_REG(CLKDIV, 0x00)
65DEFINE_TWI_REG(CONTROL, 0x04)
66DEFINE_TWI_REG(SLAVE_CTL, 0x08)
67DEFINE_TWI_REG(SLAVE_STAT, 0x0C)
68DEFINE_TWI_REG(SLAVE_ADDR, 0x10)
69DEFINE_TWI_REG(MASTER_CTL, 0x14)
70DEFINE_TWI_REG(MASTER_STAT, 0x18)
71DEFINE_TWI_REG(MASTER_ADDR, 0x1C)
72DEFINE_TWI_REG(INT_STAT, 0x20)
73DEFINE_TWI_REG(INT_MASK, 0x24)
74DEFINE_TWI_REG(FIFO_CTL, 0x28)
75DEFINE_TWI_REG(FIFO_STAT, 0x2C)
76DEFINE_TWI_REG(XMT_DATA8, 0x80)
77DEFINE_TWI_REG(XMT_DATA16, 0x84)
78DEFINE_TWI_REG(RCV_DATA8, 0x88)
79DEFINE_TWI_REG(RCV_DATA16, 0x8C)
Bryan Wud24ecfc2007-05-01 23:26:32 +020080
Bryan Wu74d362e2008-04-22 22:16:48 +020081static const u16 pin_req[2][3] = {
82 {P_TWI0_SCL, P_TWI0_SDA, 0},
83 {P_TWI1_SCL, P_TWI1_SDA, 0},
84};
85
Bryan Wud24ecfc2007-05-01 23:26:32 +020086static void bfin_twi_handle_interrupt(struct bfin_twi_iface *iface)
87{
Bryan Wuaa3d0202008-04-22 22:16:48 +020088 unsigned short twi_int_status = read_INT_STAT(iface);
89 unsigned short mast_stat = read_MASTER_STAT(iface);
Bryan Wud24ecfc2007-05-01 23:26:32 +020090
91 if (twi_int_status & XMTSERV) {
92 /* Transmit next data */
93 if (iface->writeNum > 0) {
Bryan Wuaa3d0202008-04-22 22:16:48 +020094 write_XMT_DATA8(iface, *(iface->transPtr++));
Bryan Wud24ecfc2007-05-01 23:26:32 +020095 iface->writeNum--;
96 }
97 /* start receive immediately after complete sending in
98 * combine mode.
99 */
Sonic Zhang4dd39bb2008-04-22 22:16:47 +0200100 else if (iface->cur_mode == TWI_I2C_MODE_COMBINED)
Bryan Wuaa3d0202008-04-22 22:16:48 +0200101 write_MASTER_CTL(iface,
102 read_MASTER_CTL(iface) | MDIR | RSTART);
Sonic Zhang4dd39bb2008-04-22 22:16:47 +0200103 else if (iface->manual_stop)
Bryan Wuaa3d0202008-04-22 22:16:48 +0200104 write_MASTER_CTL(iface,
105 read_MASTER_CTL(iface) | STOP);
Sonic Zhang4dd39bb2008-04-22 22:16:47 +0200106 else if (iface->cur_mode == TWI_I2C_MODE_REPEAT &&
Frank Shew94327d02009-05-19 07:23:49 -0400107 iface->cur_msg + 1 < iface->msg_num) {
108 if (iface->pmsg[iface->cur_msg + 1].flags & I2C_M_RD)
109 write_MASTER_CTL(iface,
110 read_MASTER_CTL(iface) | RSTART | MDIR);
111 else
112 write_MASTER_CTL(iface,
113 (read_MASTER_CTL(iface) | RSTART) & ~MDIR);
114 }
Bryan Wud24ecfc2007-05-01 23:26:32 +0200115 SSYNC();
116 /* Clear status */
Bryan Wuaa3d0202008-04-22 22:16:48 +0200117 write_INT_STAT(iface, XMTSERV);
Bryan Wud24ecfc2007-05-01 23:26:32 +0200118 SSYNC();
119 }
120 if (twi_int_status & RCVSERV) {
121 if (iface->readNum > 0) {
122 /* Receive next data */
Bryan Wuaa3d0202008-04-22 22:16:48 +0200123 *(iface->transPtr) = read_RCV_DATA8(iface);
Bryan Wud24ecfc2007-05-01 23:26:32 +0200124 if (iface->cur_mode == TWI_I2C_MODE_COMBINED) {
125 /* Change combine mode into sub mode after
126 * read first data.
127 */
128 iface->cur_mode = TWI_I2C_MODE_STANDARDSUB;
129 /* Get read number from first byte in block
130 * combine mode.
131 */
132 if (iface->readNum == 1 && iface->manual_stop)
133 iface->readNum = *iface->transPtr + 1;
134 }
135 iface->transPtr++;
136 iface->readNum--;
137 } else if (iface->manual_stop) {
Bryan Wuaa3d0202008-04-22 22:16:48 +0200138 write_MASTER_CTL(iface,
139 read_MASTER_CTL(iface) | STOP);
Bryan Wud24ecfc2007-05-01 23:26:32 +0200140 SSYNC();
Sonic Zhang4dd39bb2008-04-22 22:16:47 +0200141 } else if (iface->cur_mode == TWI_I2C_MODE_REPEAT &&
Frank Shew94327d02009-05-19 07:23:49 -0400142 iface->cur_msg + 1 < iface->msg_num) {
143 if (iface->pmsg[iface->cur_msg + 1].flags & I2C_M_RD)
144 write_MASTER_CTL(iface,
145 read_MASTER_CTL(iface) | RSTART | MDIR);
146 else
147 write_MASTER_CTL(iface,
148 (read_MASTER_CTL(iface) | RSTART) & ~MDIR);
Sonic Zhang4dd39bb2008-04-22 22:16:47 +0200149 SSYNC();
Bryan Wud24ecfc2007-05-01 23:26:32 +0200150 }
151 /* Clear interrupt source */
Bryan Wuaa3d0202008-04-22 22:16:48 +0200152 write_INT_STAT(iface, RCVSERV);
Bryan Wud24ecfc2007-05-01 23:26:32 +0200153 SSYNC();
154 }
155 if (twi_int_status & MERR) {
Bryan Wuaa3d0202008-04-22 22:16:48 +0200156 write_INT_STAT(iface, MERR);
157 write_INT_MASK(iface, 0);
158 write_MASTER_STAT(iface, 0x3e);
159 write_MASTER_CTL(iface, 0);
Bryan Wud24ecfc2007-05-01 23:26:32 +0200160 SSYNC();
Sonic Zhang4dd39bb2008-04-22 22:16:47 +0200161 iface->result = -EIO;
Bryan Wud24ecfc2007-05-01 23:26:32 +0200162 /* if both err and complete int stats are set, return proper
163 * results.
164 */
165 if (twi_int_status & MCOMP) {
Bryan Wuaa3d0202008-04-22 22:16:48 +0200166 write_INT_STAT(iface, MCOMP);
167 write_INT_MASK(iface, 0);
168 write_MASTER_CTL(iface, 0);
Bryan Wud24ecfc2007-05-01 23:26:32 +0200169 SSYNC();
170 /* If it is a quick transfer, only address bug no data,
171 * not an err, return 1.
172 */
173 if (iface->writeNum == 0 && (mast_stat & BUFRDERR))
174 iface->result = 1;
175 /* If address not acknowledged return -1,
176 * else return 0.
177 */
178 else if (!(mast_stat & ANAK))
179 iface->result = 0;
180 }
181 complete(&iface->complete);
182 return;
183 }
184 if (twi_int_status & MCOMP) {
Bryan Wuaa3d0202008-04-22 22:16:48 +0200185 write_INT_STAT(iface, MCOMP);
Bryan Wud24ecfc2007-05-01 23:26:32 +0200186 SSYNC();
187 if (iface->cur_mode == TWI_I2C_MODE_COMBINED) {
188 if (iface->readNum == 0) {
189 /* set the read number to 1 and ask for manual
190 * stop in block combine mode
191 */
192 iface->readNum = 1;
193 iface->manual_stop = 1;
Bryan Wuaa3d0202008-04-22 22:16:48 +0200194 write_MASTER_CTL(iface,
195 read_MASTER_CTL(iface) | (0xff << 6));
Bryan Wud24ecfc2007-05-01 23:26:32 +0200196 } else {
197 /* set the readd number in other
198 * combine mode.
199 */
Bryan Wuaa3d0202008-04-22 22:16:48 +0200200 write_MASTER_CTL(iface,
201 (read_MASTER_CTL(iface) &
Bryan Wud24ecfc2007-05-01 23:26:32 +0200202 (~(0xff << 6))) |
Bryan Wuaa3d0202008-04-22 22:16:48 +0200203 (iface->readNum << 6));
Bryan Wud24ecfc2007-05-01 23:26:32 +0200204 }
205 /* remove restart bit and enable master receive */
Bryan Wuaa3d0202008-04-22 22:16:48 +0200206 write_MASTER_CTL(iface,
207 read_MASTER_CTL(iface) & ~RSTART);
Bryan Wud24ecfc2007-05-01 23:26:32 +0200208 SSYNC();
Sonic Zhang4dd39bb2008-04-22 22:16:47 +0200209 } else if (iface->cur_mode == TWI_I2C_MODE_REPEAT &&
210 iface->cur_msg+1 < iface->msg_num) {
211 iface->cur_msg++;
212 iface->transPtr = iface->pmsg[iface->cur_msg].buf;
213 iface->writeNum = iface->readNum =
214 iface->pmsg[iface->cur_msg].len;
215 /* Set Transmit device address */
Bryan Wuaa3d0202008-04-22 22:16:48 +0200216 write_MASTER_ADDR(iface,
Sonic Zhang4dd39bb2008-04-22 22:16:47 +0200217 iface->pmsg[iface->cur_msg].addr);
218 if (iface->pmsg[iface->cur_msg].flags & I2C_M_RD)
219 iface->read_write = I2C_SMBUS_READ;
220 else {
221 iface->read_write = I2C_SMBUS_WRITE;
222 /* Transmit first data */
223 if (iface->writeNum > 0) {
Bryan Wuaa3d0202008-04-22 22:16:48 +0200224 write_XMT_DATA8(iface,
Sonic Zhang4dd39bb2008-04-22 22:16:47 +0200225 *(iface->transPtr++));
226 iface->writeNum--;
227 SSYNC();
228 }
229 }
230
231 if (iface->pmsg[iface->cur_msg].len <= 255)
Sonic Zhang57a8f322009-05-19 07:21:58 -0400232 write_MASTER_CTL(iface,
233 (read_MASTER_CTL(iface) &
234 (~(0xff << 6))) |
235 (iface->pmsg[iface->cur_msg].len << 6));
Sonic Zhang4dd39bb2008-04-22 22:16:47 +0200236 else {
Sonic Zhang57a8f322009-05-19 07:21:58 -0400237 write_MASTER_CTL(iface,
238 (read_MASTER_CTL(iface) |
239 (0xff << 6)));
Sonic Zhang4dd39bb2008-04-22 22:16:47 +0200240 iface->manual_stop = 1;
241 }
242 /* remove restart bit and enable master receive */
Bryan Wuaa3d0202008-04-22 22:16:48 +0200243 write_MASTER_CTL(iface,
244 read_MASTER_CTL(iface) & ~RSTART);
Sonic Zhang4dd39bb2008-04-22 22:16:47 +0200245 SSYNC();
Bryan Wud24ecfc2007-05-01 23:26:32 +0200246 } else {
247 iface->result = 1;
Bryan Wuaa3d0202008-04-22 22:16:48 +0200248 write_INT_MASK(iface, 0);
249 write_MASTER_CTL(iface, 0);
Bryan Wud24ecfc2007-05-01 23:26:32 +0200250 SSYNC();
251 complete(&iface->complete);
252 }
253 }
254}
255
256/* Interrupt handler */
257static irqreturn_t bfin_twi_interrupt_entry(int irq, void *dev_id)
258{
259 struct bfin_twi_iface *iface = dev_id;
260 unsigned long flags;
261
262 spin_lock_irqsave(&iface->lock, flags);
263 del_timer(&iface->timeout_timer);
264 bfin_twi_handle_interrupt(iface);
265 spin_unlock_irqrestore(&iface->lock, flags);
266 return IRQ_HANDLED;
267}
268
269static void bfin_twi_timeout(unsigned long data)
270{
271 struct bfin_twi_iface *iface = (struct bfin_twi_iface *)data;
272 unsigned long flags;
273
274 spin_lock_irqsave(&iface->lock, flags);
275 bfin_twi_handle_interrupt(iface);
276 if (iface->result == 0) {
277 iface->timeout_count--;
278 if (iface->timeout_count > 0) {
279 iface->timeout_timer.expires = jiffies + POLL_TIMEOUT;
280 add_timer(&iface->timeout_timer);
281 } else {
282 iface->result = -1;
283 complete(&iface->complete);
284 }
285 }
286 spin_unlock_irqrestore(&iface->lock, flags);
287}
288
289/*
290 * Generic i2c master transfer entrypoint
291 */
292static int bfin_twi_master_xfer(struct i2c_adapter *adap,
293 struct i2c_msg *msgs, int num)
294{
295 struct bfin_twi_iface *iface = adap->algo_data;
296 struct i2c_msg *pmsg;
Bryan Wud24ecfc2007-05-01 23:26:32 +0200297 int rc = 0;
298
Bryan Wuaa3d0202008-04-22 22:16:48 +0200299 if (!(read_CONTROL(iface) & TWI_ENA))
Bryan Wud24ecfc2007-05-01 23:26:32 +0200300 return -ENXIO;
301
Bryan Wuaa3d0202008-04-22 22:16:48 +0200302 while (read_MASTER_STAT(iface) & BUSBUSY)
Bryan Wud24ecfc2007-05-01 23:26:32 +0200303 yield();
Bryan Wud24ecfc2007-05-01 23:26:32 +0200304
Sonic Zhang4dd39bb2008-04-22 22:16:47 +0200305 iface->pmsg = msgs;
306 iface->msg_num = num;
307 iface->cur_msg = 0;
Bryan Wud24ecfc2007-05-01 23:26:32 +0200308
Sonic Zhang4dd39bb2008-04-22 22:16:47 +0200309 pmsg = &msgs[0];
310 if (pmsg->flags & I2C_M_TEN) {
311 dev_err(&adap->dev, "10 bits addr not supported!\n");
312 return -EINVAL;
Bryan Wud24ecfc2007-05-01 23:26:32 +0200313 }
314
Sonic Zhang4dd39bb2008-04-22 22:16:47 +0200315 iface->cur_mode = TWI_I2C_MODE_REPEAT;
316 iface->manual_stop = 0;
317 iface->transPtr = pmsg->buf;
318 iface->writeNum = iface->readNum = pmsg->len;
319 iface->result = 0;
320 iface->timeout_count = 10;
Hans Schillstromafc13b72008-04-22 22:16:48 +0200321 init_completion(&(iface->complete));
Sonic Zhang4dd39bb2008-04-22 22:16:47 +0200322 /* Set Transmit device address */
Bryan Wuaa3d0202008-04-22 22:16:48 +0200323 write_MASTER_ADDR(iface, pmsg->addr);
Sonic Zhang4dd39bb2008-04-22 22:16:47 +0200324
325 /* FIFO Initiation. Data in FIFO should be
326 * discarded before start a new operation.
327 */
Bryan Wuaa3d0202008-04-22 22:16:48 +0200328 write_FIFO_CTL(iface, 0x3);
Sonic Zhang4dd39bb2008-04-22 22:16:47 +0200329 SSYNC();
Bryan Wuaa3d0202008-04-22 22:16:48 +0200330 write_FIFO_CTL(iface, 0);
Sonic Zhang4dd39bb2008-04-22 22:16:47 +0200331 SSYNC();
332
333 if (pmsg->flags & I2C_M_RD)
334 iface->read_write = I2C_SMBUS_READ;
335 else {
336 iface->read_write = I2C_SMBUS_WRITE;
337 /* Transmit first data */
338 if (iface->writeNum > 0) {
Bryan Wuaa3d0202008-04-22 22:16:48 +0200339 write_XMT_DATA8(iface, *(iface->transPtr++));
Sonic Zhang4dd39bb2008-04-22 22:16:47 +0200340 iface->writeNum--;
341 SSYNC();
342 }
343 }
344
345 /* clear int stat */
Bryan Wuaa3d0202008-04-22 22:16:48 +0200346 write_INT_STAT(iface, MERR | MCOMP | XMTSERV | RCVSERV);
Sonic Zhang4dd39bb2008-04-22 22:16:47 +0200347
348 /* Interrupt mask . Enable XMT, RCV interrupt */
Bryan Wuaa3d0202008-04-22 22:16:48 +0200349 write_INT_MASK(iface, MCOMP | MERR | RCVSERV | XMTSERV);
Sonic Zhang4dd39bb2008-04-22 22:16:47 +0200350 SSYNC();
351
352 if (pmsg->len <= 255)
Bryan Wuaa3d0202008-04-22 22:16:48 +0200353 write_MASTER_CTL(iface, pmsg->len << 6);
Sonic Zhang4dd39bb2008-04-22 22:16:47 +0200354 else {
Bryan Wuaa3d0202008-04-22 22:16:48 +0200355 write_MASTER_CTL(iface, 0xff << 6);
Sonic Zhang4dd39bb2008-04-22 22:16:47 +0200356 iface->manual_stop = 1;
357 }
358
359 iface->timeout_timer.expires = jiffies + POLL_TIMEOUT;
360 add_timer(&iface->timeout_timer);
361
362 /* Master enable */
Bryan Wuaa3d0202008-04-22 22:16:48 +0200363 write_MASTER_CTL(iface, read_MASTER_CTL(iface) | MEN |
Sonic Zhang4dd39bb2008-04-22 22:16:47 +0200364 ((iface->read_write == I2C_SMBUS_READ) ? MDIR : 0) |
365 ((CONFIG_I2C_BLACKFIN_TWI_CLK_KHZ > 100) ? FAST : 0));
366 SSYNC();
367
368 wait_for_completion(&iface->complete);
369
370 rc = iface->result;
371
372 if (rc == 1)
373 return num;
374 else
375 return rc;
Bryan Wud24ecfc2007-05-01 23:26:32 +0200376}
377
378/*
379 * SMBus type transfer entrypoint
380 */
381
382int bfin_twi_smbus_xfer(struct i2c_adapter *adap, u16 addr,
383 unsigned short flags, char read_write,
384 u8 command, int size, union i2c_smbus_data *data)
385{
386 struct bfin_twi_iface *iface = adap->algo_data;
387 int rc = 0;
388
Bryan Wuaa3d0202008-04-22 22:16:48 +0200389 if (!(read_CONTROL(iface) & TWI_ENA))
Bryan Wud24ecfc2007-05-01 23:26:32 +0200390 return -ENXIO;
391
Bryan Wuaa3d0202008-04-22 22:16:48 +0200392 while (read_MASTER_STAT(iface) & BUSBUSY)
Bryan Wud24ecfc2007-05-01 23:26:32 +0200393 yield();
Bryan Wud24ecfc2007-05-01 23:26:32 +0200394
395 iface->writeNum = 0;
396 iface->readNum = 0;
397
398 /* Prepare datas & select mode */
399 switch (size) {
400 case I2C_SMBUS_QUICK:
401 iface->transPtr = NULL;
402 iface->cur_mode = TWI_I2C_MODE_STANDARD;
403 break;
404 case I2C_SMBUS_BYTE:
405 if (data == NULL)
406 iface->transPtr = NULL;
407 else {
408 if (read_write == I2C_SMBUS_READ)
409 iface->readNum = 1;
410 else
411 iface->writeNum = 1;
412 iface->transPtr = &data->byte;
413 }
414 iface->cur_mode = TWI_I2C_MODE_STANDARD;
415 break;
416 case I2C_SMBUS_BYTE_DATA:
417 if (read_write == I2C_SMBUS_READ) {
418 iface->readNum = 1;
419 iface->cur_mode = TWI_I2C_MODE_COMBINED;
420 } else {
421 iface->writeNum = 1;
422 iface->cur_mode = TWI_I2C_MODE_STANDARDSUB;
423 }
424 iface->transPtr = &data->byte;
425 break;
426 case I2C_SMBUS_WORD_DATA:
427 if (read_write == I2C_SMBUS_READ) {
428 iface->readNum = 2;
429 iface->cur_mode = TWI_I2C_MODE_COMBINED;
430 } else {
431 iface->writeNum = 2;
432 iface->cur_mode = TWI_I2C_MODE_STANDARDSUB;
433 }
434 iface->transPtr = (u8 *)&data->word;
435 break;
436 case I2C_SMBUS_PROC_CALL:
437 iface->writeNum = 2;
438 iface->readNum = 2;
439 iface->cur_mode = TWI_I2C_MODE_COMBINED;
440 iface->transPtr = (u8 *)&data->word;
441 break;
442 case I2C_SMBUS_BLOCK_DATA:
443 if (read_write == I2C_SMBUS_READ) {
444 iface->readNum = 0;
445 iface->cur_mode = TWI_I2C_MODE_COMBINED;
446 } else {
447 iface->writeNum = data->block[0] + 1;
448 iface->cur_mode = TWI_I2C_MODE_STANDARDSUB;
449 }
450 iface->transPtr = data->block;
451 break;
452 default:
453 return -1;
454 }
455
456 iface->result = 0;
457 iface->manual_stop = 0;
458 iface->read_write = read_write;
459 iface->command = command;
460 iface->timeout_count = 10;
Hans Schillstromafc13b72008-04-22 22:16:48 +0200461 init_completion(&(iface->complete));
Bryan Wud24ecfc2007-05-01 23:26:32 +0200462
463 /* FIFO Initiation. Data in FIFO should be discarded before
464 * start a new operation.
465 */
Bryan Wuaa3d0202008-04-22 22:16:48 +0200466 write_FIFO_CTL(iface, 0x3);
Bryan Wud24ecfc2007-05-01 23:26:32 +0200467 SSYNC();
Bryan Wuaa3d0202008-04-22 22:16:48 +0200468 write_FIFO_CTL(iface, 0);
Bryan Wud24ecfc2007-05-01 23:26:32 +0200469
470 /* clear int stat */
Bryan Wuaa3d0202008-04-22 22:16:48 +0200471 write_INT_STAT(iface, MERR | MCOMP | XMTSERV | RCVSERV);
Bryan Wud24ecfc2007-05-01 23:26:32 +0200472
473 /* Set Transmit device address */
Bryan Wuaa3d0202008-04-22 22:16:48 +0200474 write_MASTER_ADDR(iface, addr);
Bryan Wud24ecfc2007-05-01 23:26:32 +0200475 SSYNC();
476
477 iface->timeout_timer.expires = jiffies + POLL_TIMEOUT;
478 add_timer(&iface->timeout_timer);
479
480 switch (iface->cur_mode) {
481 case TWI_I2C_MODE_STANDARDSUB:
Bryan Wuaa3d0202008-04-22 22:16:48 +0200482 write_XMT_DATA8(iface, iface->command);
483 write_INT_MASK(iface, MCOMP | MERR |
Bryan Wud24ecfc2007-05-01 23:26:32 +0200484 ((iface->read_write == I2C_SMBUS_READ) ?
485 RCVSERV : XMTSERV));
486 SSYNC();
487
488 if (iface->writeNum + 1 <= 255)
Bryan Wuaa3d0202008-04-22 22:16:48 +0200489 write_MASTER_CTL(iface, (iface->writeNum + 1) << 6);
Bryan Wud24ecfc2007-05-01 23:26:32 +0200490 else {
Bryan Wuaa3d0202008-04-22 22:16:48 +0200491 write_MASTER_CTL(iface, 0xff << 6);
Bryan Wud24ecfc2007-05-01 23:26:32 +0200492 iface->manual_stop = 1;
493 }
494 /* Master enable */
Bryan Wuaa3d0202008-04-22 22:16:48 +0200495 write_MASTER_CTL(iface, read_MASTER_CTL(iface) | MEN |
Bryan Wud24ecfc2007-05-01 23:26:32 +0200496 ((CONFIG_I2C_BLACKFIN_TWI_CLK_KHZ>100) ? FAST : 0));
497 break;
498 case TWI_I2C_MODE_COMBINED:
Bryan Wuaa3d0202008-04-22 22:16:48 +0200499 write_XMT_DATA8(iface, iface->command);
500 write_INT_MASK(iface, MCOMP | MERR | RCVSERV | XMTSERV);
Bryan Wud24ecfc2007-05-01 23:26:32 +0200501 SSYNC();
502
503 if (iface->writeNum > 0)
Bryan Wuaa3d0202008-04-22 22:16:48 +0200504 write_MASTER_CTL(iface, (iface->writeNum + 1) << 6);
Bryan Wud24ecfc2007-05-01 23:26:32 +0200505 else
Bryan Wuaa3d0202008-04-22 22:16:48 +0200506 write_MASTER_CTL(iface, 0x1 << 6);
Bryan Wud24ecfc2007-05-01 23:26:32 +0200507 /* Master enable */
Bryan Wuaa3d0202008-04-22 22:16:48 +0200508 write_MASTER_CTL(iface, read_MASTER_CTL(iface) | MEN |
Bryan Wud24ecfc2007-05-01 23:26:32 +0200509 ((CONFIG_I2C_BLACKFIN_TWI_CLK_KHZ>100) ? FAST : 0));
510 break;
511 default:
Bryan Wuaa3d0202008-04-22 22:16:48 +0200512 write_MASTER_CTL(iface, 0);
Bryan Wud24ecfc2007-05-01 23:26:32 +0200513 if (size != I2C_SMBUS_QUICK) {
514 /* Don't access xmit data register when this is a
515 * read operation.
516 */
517 if (iface->read_write != I2C_SMBUS_READ) {
518 if (iface->writeNum > 0) {
Bryan Wuaa3d0202008-04-22 22:16:48 +0200519 write_XMT_DATA8(iface,
520 *(iface->transPtr++));
Bryan Wud24ecfc2007-05-01 23:26:32 +0200521 if (iface->writeNum <= 255)
Bryan Wuaa3d0202008-04-22 22:16:48 +0200522 write_MASTER_CTL(iface,
523 iface->writeNum << 6);
Bryan Wud24ecfc2007-05-01 23:26:32 +0200524 else {
Bryan Wuaa3d0202008-04-22 22:16:48 +0200525 write_MASTER_CTL(iface,
526 0xff << 6);
Bryan Wud24ecfc2007-05-01 23:26:32 +0200527 iface->manual_stop = 1;
528 }
529 iface->writeNum--;
530 } else {
Bryan Wuaa3d0202008-04-22 22:16:48 +0200531 write_XMT_DATA8(iface, iface->command);
532 write_MASTER_CTL(iface, 1 << 6);
Bryan Wud24ecfc2007-05-01 23:26:32 +0200533 }
534 } else {
535 if (iface->readNum > 0 && iface->readNum <= 255)
Bryan Wuaa3d0202008-04-22 22:16:48 +0200536 write_MASTER_CTL(iface,
537 iface->readNum << 6);
Bryan Wud24ecfc2007-05-01 23:26:32 +0200538 else if (iface->readNum > 255) {
Bryan Wuaa3d0202008-04-22 22:16:48 +0200539 write_MASTER_CTL(iface, 0xff << 6);
Bryan Wud24ecfc2007-05-01 23:26:32 +0200540 iface->manual_stop = 1;
541 } else {
542 del_timer(&iface->timeout_timer);
543 break;
544 }
545 }
546 }
Bryan Wuaa3d0202008-04-22 22:16:48 +0200547 write_INT_MASK(iface, MCOMP | MERR |
Bryan Wud24ecfc2007-05-01 23:26:32 +0200548 ((iface->read_write == I2C_SMBUS_READ) ?
549 RCVSERV : XMTSERV));
550 SSYNC();
551
552 /* Master enable */
Bryan Wuaa3d0202008-04-22 22:16:48 +0200553 write_MASTER_CTL(iface, read_MASTER_CTL(iface) | MEN |
Bryan Wud24ecfc2007-05-01 23:26:32 +0200554 ((iface->read_write == I2C_SMBUS_READ) ? MDIR : 0) |
555 ((CONFIG_I2C_BLACKFIN_TWI_CLK_KHZ > 100) ? FAST : 0));
556 break;
557 }
558 SSYNC();
559
560 wait_for_completion(&iface->complete);
561
562 rc = (iface->result >= 0) ? 0 : -1;
563
Bryan Wud24ecfc2007-05-01 23:26:32 +0200564 return rc;
565}
566
567/*
568 * Return what the adapter supports
569 */
570static u32 bfin_twi_functionality(struct i2c_adapter *adap)
571{
572 return I2C_FUNC_SMBUS_QUICK | I2C_FUNC_SMBUS_BYTE |
573 I2C_FUNC_SMBUS_BYTE_DATA | I2C_FUNC_SMBUS_WORD_DATA |
574 I2C_FUNC_SMBUS_BLOCK_DATA | I2C_FUNC_SMBUS_PROC_CALL |
575 I2C_FUNC_I2C;
576}
577
Bryan Wud24ecfc2007-05-01 23:26:32 +0200578static struct i2c_algorithm bfin_twi_algorithm = {
579 .master_xfer = bfin_twi_master_xfer,
580 .smbus_xfer = bfin_twi_smbus_xfer,
581 .functionality = bfin_twi_functionality,
582};
583
Michael Hennerich958585f2008-07-27 14:41:54 +0800584static int i2c_bfin_twi_suspend(struct platform_device *pdev, pm_message_t state)
Bryan Wud24ecfc2007-05-01 23:26:32 +0200585{
Michael Hennerich958585f2008-07-27 14:41:54 +0800586 struct bfin_twi_iface *iface = platform_get_drvdata(pdev);
587
588 iface->saved_clkdiv = read_CLKDIV(iface);
589 iface->saved_control = read_CONTROL(iface);
590
591 free_irq(iface->irq, iface);
Bryan Wud24ecfc2007-05-01 23:26:32 +0200592
593 /* Disable TWI */
Michael Hennerich958585f2008-07-27 14:41:54 +0800594 write_CONTROL(iface, iface->saved_control & ~TWI_ENA);
Bryan Wud24ecfc2007-05-01 23:26:32 +0200595
596 return 0;
597}
598
Michael Hennerich958585f2008-07-27 14:41:54 +0800599static int i2c_bfin_twi_resume(struct platform_device *pdev)
Bryan Wud24ecfc2007-05-01 23:26:32 +0200600{
Michael Hennerich958585f2008-07-27 14:41:54 +0800601 struct bfin_twi_iface *iface = platform_get_drvdata(pdev);
Bryan Wud24ecfc2007-05-01 23:26:32 +0200602
Michael Hennerich958585f2008-07-27 14:41:54 +0800603 int rc = request_irq(iface->irq, bfin_twi_interrupt_entry,
604 IRQF_DISABLED, pdev->name, iface);
605 if (rc) {
606 dev_err(&pdev->dev, "Can't get IRQ %d !\n", iface->irq);
607 return -ENODEV;
608 }
609
610 /* Resume TWI interface clock as specified */
611 write_CLKDIV(iface, iface->saved_clkdiv);
612
613 /* Resume TWI */
614 write_CONTROL(iface, iface->saved_control);
Bryan Wud24ecfc2007-05-01 23:26:32 +0200615
616 return 0;
617}
618
Bryan Wuaa3d0202008-04-22 22:16:48 +0200619static int i2c_bfin_twi_probe(struct platform_device *pdev)
Bryan Wud24ecfc2007-05-01 23:26:32 +0200620{
Bryan Wuaa3d0202008-04-22 22:16:48 +0200621 struct bfin_twi_iface *iface;
Bryan Wud24ecfc2007-05-01 23:26:32 +0200622 struct i2c_adapter *p_adap;
Bryan Wuaa3d0202008-04-22 22:16:48 +0200623 struct resource *res;
Bryan Wud24ecfc2007-05-01 23:26:32 +0200624 int rc;
Michael Hennerich9528d1c2009-05-18 08:14:41 -0400625 unsigned int clkhilow;
Bryan Wud24ecfc2007-05-01 23:26:32 +0200626
Bryan Wuaa3d0202008-04-22 22:16:48 +0200627 iface = kzalloc(sizeof(struct bfin_twi_iface), GFP_KERNEL);
628 if (!iface) {
629 dev_err(&pdev->dev, "Cannot allocate memory\n");
630 rc = -ENOMEM;
631 goto out_error_nomem;
632 }
633
Bryan Wud24ecfc2007-05-01 23:26:32 +0200634 spin_lock_init(&(iface->lock));
Bryan Wuaa3d0202008-04-22 22:16:48 +0200635
636 /* Find and map our resources */
637 res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
638 if (res == NULL) {
639 dev_err(&pdev->dev, "Cannot get IORESOURCE_MEM\n");
640 rc = -ENOENT;
641 goto out_error_get_res;
642 }
643
644 iface->regs_base = ioremap(res->start, res->end - res->start + 1);
645 if (iface->regs_base == NULL) {
646 dev_err(&pdev->dev, "Cannot map IO\n");
647 rc = -ENXIO;
648 goto out_error_ioremap;
649 }
650
651 iface->irq = platform_get_irq(pdev, 0);
652 if (iface->irq < 0) {
653 dev_err(&pdev->dev, "No IRQ specified\n");
654 rc = -ENOENT;
655 goto out_error_no_irq;
656 }
Bryan Wud24ecfc2007-05-01 23:26:32 +0200657
658 init_timer(&(iface->timeout_timer));
659 iface->timeout_timer.function = bfin_twi_timeout;
660 iface->timeout_timer.data = (unsigned long)iface;
661
662 p_adap = &iface->adap;
Bryan Wuaa3d0202008-04-22 22:16:48 +0200663 p_adap->nr = pdev->id;
664 strlcpy(p_adap->name, pdev->name, sizeof(p_adap->name));
Bryan Wud24ecfc2007-05-01 23:26:32 +0200665 p_adap->algo = &bfin_twi_algorithm;
666 p_adap->algo_data = iface;
Jean Delvaree1995f62009-01-07 14:29:16 +0100667 p_adap->class = I2C_CLASS_HWMON | I2C_CLASS_SPD;
Bryan Wuaa3d0202008-04-22 22:16:48 +0200668 p_adap->dev.parent = &pdev->dev;
Bryan Wud24ecfc2007-05-01 23:26:32 +0200669
Bryan Wu74d362e2008-04-22 22:16:48 +0200670 rc = peripheral_request_list(pin_req[pdev->id], "i2c-bfin-twi");
671 if (rc) {
672 dev_err(&pdev->dev, "Can't setup pin mux!\n");
673 goto out_error_pin_mux;
674 }
675
Bryan Wud24ecfc2007-05-01 23:26:32 +0200676 rc = request_irq(iface->irq, bfin_twi_interrupt_entry,
Bryan Wuaa3d0202008-04-22 22:16:48 +0200677 IRQF_DISABLED, pdev->name, iface);
Bryan Wud24ecfc2007-05-01 23:26:32 +0200678 if (rc) {
Bryan Wuaa3d0202008-04-22 22:16:48 +0200679 dev_err(&pdev->dev, "Can't get IRQ %d !\n", iface->irq);
680 rc = -ENODEV;
681 goto out_error_req_irq;
Bryan Wud24ecfc2007-05-01 23:26:32 +0200682 }
683
684 /* Set TWI internal clock as 10MHz */
Bryan Wuaa3d0202008-04-22 22:16:48 +0200685 write_CONTROL(iface, ((get_sclk() / 1024 / 1024 + 5) / 10) & 0x7F);
Bryan Wud24ecfc2007-05-01 23:26:32 +0200686
Michael Hennerich9528d1c2009-05-18 08:14:41 -0400687 /*
688 * We will not end up with a CLKDIV=0 because no one will specify
689 * 20kHz SCL or less in Kconfig now. (5 * 1024 / 20 = 0x100)
690 */
691 clkhilow = 5 * 1024 / CONFIG_I2C_BLACKFIN_TWI_CLK_KHZ;
692
Bryan Wud24ecfc2007-05-01 23:26:32 +0200693 /* Set Twi interface clock as specified */
Michael Hennerich9528d1c2009-05-18 08:14:41 -0400694 write_CLKDIV(iface, (clkhilow << 8) | clkhilow);
Bryan Wud24ecfc2007-05-01 23:26:32 +0200695
696 /* Enable TWI */
Bryan Wuaa3d0202008-04-22 22:16:48 +0200697 write_CONTROL(iface, read_CONTROL(iface) | TWI_ENA);
Bryan Wud24ecfc2007-05-01 23:26:32 +0200698 SSYNC();
699
Kalle Pokki991dee52008-01-27 18:14:52 +0100700 rc = i2c_add_numbered_adapter(p_adap);
Bryan Wuaa3d0202008-04-22 22:16:48 +0200701 if (rc < 0) {
702 dev_err(&pdev->dev, "Can't add i2c adapter!\n");
703 goto out_error_add_adapter;
704 }
Bryan Wud24ecfc2007-05-01 23:26:32 +0200705
Bryan Wuaa3d0202008-04-22 22:16:48 +0200706 platform_set_drvdata(pdev, iface);
707
Bryan Wufa6ad222008-04-22 22:16:48 +0200708 dev_info(&pdev->dev, "Blackfin BF5xx on-chip I2C TWI Contoller, "
709 "regs_base@%p\n", iface->regs_base);
Bryan Wuaa3d0202008-04-22 22:16:48 +0200710
711 return 0;
712
713out_error_add_adapter:
714 free_irq(iface->irq, iface);
715out_error_req_irq:
716out_error_no_irq:
Bryan Wu74d362e2008-04-22 22:16:48 +0200717 peripheral_free_list(pin_req[pdev->id]);
718out_error_pin_mux:
Bryan Wuaa3d0202008-04-22 22:16:48 +0200719 iounmap(iface->regs_base);
720out_error_ioremap:
721out_error_get_res:
722 kfree(iface);
723out_error_nomem:
Bryan Wud24ecfc2007-05-01 23:26:32 +0200724 return rc;
725}
726
727static int i2c_bfin_twi_remove(struct platform_device *pdev)
728{
729 struct bfin_twi_iface *iface = platform_get_drvdata(pdev);
730
731 platform_set_drvdata(pdev, NULL);
732
733 i2c_del_adapter(&(iface->adap));
734 free_irq(iface->irq, iface);
Bryan Wu74d362e2008-04-22 22:16:48 +0200735 peripheral_free_list(pin_req[pdev->id]);
Bryan Wuaa3d0202008-04-22 22:16:48 +0200736 iounmap(iface->regs_base);
737 kfree(iface);
Bryan Wud24ecfc2007-05-01 23:26:32 +0200738
739 return 0;
740}
741
742static struct platform_driver i2c_bfin_twi_driver = {
743 .probe = i2c_bfin_twi_probe,
744 .remove = i2c_bfin_twi_remove,
745 .suspend = i2c_bfin_twi_suspend,
746 .resume = i2c_bfin_twi_resume,
747 .driver = {
748 .name = "i2c-bfin-twi",
749 .owner = THIS_MODULE,
750 },
751};
752
753static int __init i2c_bfin_twi_init(void)
754{
Bryan Wud24ecfc2007-05-01 23:26:32 +0200755 return platform_driver_register(&i2c_bfin_twi_driver);
756}
757
758static void __exit i2c_bfin_twi_exit(void)
759{
760 platform_driver_unregister(&i2c_bfin_twi_driver);
761}
762
Bryan Wud24ecfc2007-05-01 23:26:32 +0200763module_init(i2c_bfin_twi_init);
764module_exit(i2c_bfin_twi_exit);
Bryan Wufa6ad222008-04-22 22:16:48 +0200765
766MODULE_AUTHOR("Bryan Wu, Sonic Zhang");
767MODULE_DESCRIPTION("Blackfin BF5xx on-chip I2C TWI Contoller Driver");
768MODULE_LICENSE("GPL");
Kay Sieversadd8eda2008-04-22 22:16:49 +0200769MODULE_ALIAS("platform:i2c-bfin-twi");