aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/i2c
diff options
context:
space:
mode:
authorGregory CLEMENT <gregory.clement@free-electrons.com>2013-08-22 10:19:05 -0400
committerWolfram Sang <wsa@the-dreams.de>2013-08-23 04:15:50 -0400
commit930ab3d403ae43f19d7e6d972139e02c9b8a5ec6 (patch)
treec226401ac39c24436681b8df47c80f9d897ff989 /drivers/i2c
parent874e955b171f0505e2371c1ca80a2188efdc217d (diff)
i2c: mv64xxx: Add I2C Transaction Generator support
The I2C Transaction Generator offloads CPU from managing I2C transfer step by step. This feature is currently only available on Armada XP, so usage of this mechanism is activated through device tree. Based on the work of Piotr Ziecik and rewrote to use the new way of handling multiples i2c messages. Signed-off-by: Piotr Ziecik <kosmo@semihalf.com> Signed-off-by: Gregory CLEMENT <gregory.clement@free-electrons.com> Signed-off-by: Wolfram Sang <wsa@the-dreams.de>
Diffstat (limited to 'drivers/i2c')
-rw-r--r--drivers/i2c/busses/i2c-mv64xxx.c193
1 files changed, 182 insertions, 11 deletions
diff --git a/drivers/i2c/busses/i2c-mv64xxx.c b/drivers/i2c/busses/i2c-mv64xxx.c
index 9cc361d19941..2404c4e0f35c 100644
--- a/drivers/i2c/busses/i2c-mv64xxx.c
+++ b/drivers/i2c/busses/i2c-mv64xxx.c
@@ -55,6 +55,32 @@
55#define MV64XXX_I2C_STATUS_MAST_RD_ADDR_2_NO_ACK 0xe8 55#define MV64XXX_I2C_STATUS_MAST_RD_ADDR_2_NO_ACK 0xe8
56#define MV64XXX_I2C_STATUS_NO_STATUS 0xf8 56#define MV64XXX_I2C_STATUS_NO_STATUS 0xf8
57 57
58/* Register defines (I2C bridge) */
59#define MV64XXX_I2C_REG_TX_DATA_LO 0xc0
60#define MV64XXX_I2C_REG_TX_DATA_HI 0xc4
61#define MV64XXX_I2C_REG_RX_DATA_LO 0xc8
62#define MV64XXX_I2C_REG_RX_DATA_HI 0xcc
63#define MV64XXX_I2C_REG_BRIDGE_CONTROL 0xd0
64#define MV64XXX_I2C_REG_BRIDGE_STATUS 0xd4
65#define MV64XXX_I2C_REG_BRIDGE_INTR_CAUSE 0xd8
66#define MV64XXX_I2C_REG_BRIDGE_INTR_MASK 0xdC
67#define MV64XXX_I2C_REG_BRIDGE_TIMING 0xe0
68
69/* Bridge Control values */
70#define MV64XXX_I2C_BRIDGE_CONTROL_WR 0x00000001
71#define MV64XXX_I2C_BRIDGE_CONTROL_RD 0x00000002
72#define MV64XXX_I2C_BRIDGE_CONTROL_ADDR_SHIFT 2
73#define MV64XXX_I2C_BRIDGE_CONTROL_ADDR_EXT 0x00001000
74#define MV64XXX_I2C_BRIDGE_CONTROL_TX_SIZE_SHIFT 13
75#define MV64XXX_I2C_BRIDGE_CONTROL_RX_SIZE_SHIFT 16
76#define MV64XXX_I2C_BRIDGE_CONTROL_ENABLE 0x00080000
77
78/* Bridge Status values */
79#define MV64XXX_I2C_BRIDGE_STATUS_ERROR 0x00000001
80#define MV64XXX_I2C_STATUS_OFFLOAD_ERROR 0xf0000001
81#define MV64XXX_I2C_STATUS_OFFLOAD_OK 0xf0000000
82
83
58/* Driver states */ 84/* Driver states */
59enum { 85enum {
60 MV64XXX_I2C_STATE_INVALID, 86 MV64XXX_I2C_STATE_INVALID,
@@ -71,14 +97,17 @@ enum {
71enum { 97enum {
72 MV64XXX_I2C_ACTION_INVALID, 98 MV64XXX_I2C_ACTION_INVALID,
73 MV64XXX_I2C_ACTION_CONTINUE, 99 MV64XXX_I2C_ACTION_CONTINUE,
100 MV64XXX_I2C_ACTION_OFFLOAD_SEND_START,
74 MV64XXX_I2C_ACTION_SEND_START, 101 MV64XXX_I2C_ACTION_SEND_START,
75 MV64XXX_I2C_ACTION_SEND_RESTART, 102 MV64XXX_I2C_ACTION_SEND_RESTART,
103 MV64XXX_I2C_ACTION_OFFLOAD_RESTART,
76 MV64XXX_I2C_ACTION_SEND_ADDR_1, 104 MV64XXX_I2C_ACTION_SEND_ADDR_1,
77 MV64XXX_I2C_ACTION_SEND_ADDR_2, 105 MV64XXX_I2C_ACTION_SEND_ADDR_2,
78 MV64XXX_I2C_ACTION_SEND_DATA, 106 MV64XXX_I2C_ACTION_SEND_DATA,
79 MV64XXX_I2C_ACTION_RCV_DATA, 107 MV64XXX_I2C_ACTION_RCV_DATA,
80 MV64XXX_I2C_ACTION_RCV_DATA_STOP, 108 MV64XXX_I2C_ACTION_RCV_DATA_STOP,
81 MV64XXX_I2C_ACTION_SEND_STOP, 109 MV64XXX_I2C_ACTION_SEND_STOP,
110 MV64XXX_I2C_ACTION_OFFLOAD_SEND_STOP,
82}; 111};
83 112
84struct mv64xxx_i2c_regs { 113struct mv64xxx_i2c_regs {
@@ -117,6 +146,7 @@ struct mv64xxx_i2c_data {
117 spinlock_t lock; 146 spinlock_t lock;
118 struct i2c_msg *msg; 147 struct i2c_msg *msg;
119 struct i2c_adapter adapter; 148 struct i2c_adapter adapter;
149 bool offload_enabled;
120}; 150};
121 151
122static struct mv64xxx_i2c_regs mv64xxx_i2c_regs_mv64xxx = { 152static struct mv64xxx_i2c_regs mv64xxx_i2c_regs_mv64xxx = {
@@ -165,6 +195,77 @@ mv64xxx_i2c_prepare_for_io(struct mv64xxx_i2c_data *drv_data,
165 } 195 }
166} 196}
167 197
198static int mv64xxx_i2c_offload_msg(struct mv64xxx_i2c_data *drv_data)
199{
200 unsigned long data_reg_hi = 0;
201 unsigned long data_reg_lo = 0;
202 unsigned long ctrl_reg;
203 struct i2c_msg *msg = drv_data->msgs;
204
205 drv_data->msg = msg;
206 drv_data->byte_posn = 0;
207 drv_data->bytes_left = msg->len;
208 drv_data->aborting = 0;
209 drv_data->rc = 0;
210 /* Only regular transactions can be offloaded */
211 if ((msg->flags & ~(I2C_M_TEN | I2C_M_RD)) != 0)
212 return -EINVAL;
213
214 /* Only 1-8 byte transfers can be offloaded */
215 if (msg->len < 1 || msg->len > 8)
216 return -EINVAL;
217
218 /* Build transaction */
219 ctrl_reg = MV64XXX_I2C_BRIDGE_CONTROL_ENABLE |
220 (msg->addr << MV64XXX_I2C_BRIDGE_CONTROL_ADDR_SHIFT);
221
222 if ((msg->flags & I2C_M_TEN) != 0)
223 ctrl_reg |= MV64XXX_I2C_BRIDGE_CONTROL_ADDR_EXT;
224
225 if ((msg->flags & I2C_M_RD) == 0) {
226 u8 local_buf[8] = { 0 };
227
228 memcpy(local_buf, msg->buf, msg->len);
229 data_reg_lo = cpu_to_le32(*((u32 *)local_buf));
230 data_reg_hi = cpu_to_le32(*((u32 *)(local_buf+4)));
231
232 ctrl_reg |= MV64XXX_I2C_BRIDGE_CONTROL_WR |
233 (msg->len - 1) << MV64XXX_I2C_BRIDGE_CONTROL_TX_SIZE_SHIFT;
234
235 writel_relaxed(data_reg_lo,
236 drv_data->reg_base + MV64XXX_I2C_REG_TX_DATA_LO);
237 writel_relaxed(data_reg_hi,
238 drv_data->reg_base + MV64XXX_I2C_REG_TX_DATA_HI);
239
240 } else {
241 ctrl_reg |= MV64XXX_I2C_BRIDGE_CONTROL_RD |
242 (msg->len - 1) << MV64XXX_I2C_BRIDGE_CONTROL_RX_SIZE_SHIFT;
243 }
244
245 /* Execute transaction */
246 writel(ctrl_reg, drv_data->reg_base + MV64XXX_I2C_REG_BRIDGE_CONTROL);
247
248 return 0;
249}
250
251static void
252mv64xxx_i2c_update_offload_data(struct mv64xxx_i2c_data *drv_data)
253{
254 struct i2c_msg *msg = drv_data->msg;
255
256 if (msg->flags & I2C_M_RD) {
257 u32 data_reg_lo = readl(drv_data->reg_base +
258 MV64XXX_I2C_REG_RX_DATA_LO);
259 u32 data_reg_hi = readl(drv_data->reg_base +
260 MV64XXX_I2C_REG_RX_DATA_HI);
261 u8 local_buf[8] = { 0 };
262
263 *((u32 *)local_buf) = le32_to_cpu(data_reg_lo);
264 *((u32 *)(local_buf+4)) = le32_to_cpu(data_reg_hi);
265 memcpy(msg->buf, local_buf, msg->len);
266 }
267
268}
168/* 269/*
169 ***************************************************************************** 270 *****************************************************************************
170 * 271 *
@@ -177,6 +278,15 @@ mv64xxx_i2c_prepare_for_io(struct mv64xxx_i2c_data *drv_data,
177static void 278static void
178mv64xxx_i2c_hw_init(struct mv64xxx_i2c_data *drv_data) 279mv64xxx_i2c_hw_init(struct mv64xxx_i2c_data *drv_data)
179{ 280{
281 if (drv_data->offload_enabled) {
282 writel(0, drv_data->reg_base + MV64XXX_I2C_REG_BRIDGE_CONTROL);
283 writel(0, drv_data->reg_base + MV64XXX_I2C_REG_BRIDGE_TIMING);
284 writel(0, drv_data->reg_base +
285 MV64XXX_I2C_REG_BRIDGE_INTR_CAUSE);
286 writel(0, drv_data->reg_base +
287 MV64XXX_I2C_REG_BRIDGE_INTR_MASK);
288 }
289
180 writel(0, drv_data->reg_base + drv_data->reg_offsets.soft_reset); 290 writel(0, drv_data->reg_base + drv_data->reg_offsets.soft_reset);
181 writel(MV64XXX_I2C_BAUD_DIV_M(drv_data->freq_m) | MV64XXX_I2C_BAUD_DIV_N(drv_data->freq_n), 291 writel(MV64XXX_I2C_BAUD_DIV_M(drv_data->freq_m) | MV64XXX_I2C_BAUD_DIV_N(drv_data->freq_n),
182 drv_data->reg_base + drv_data->reg_offsets.clock); 292 drv_data->reg_base + drv_data->reg_offsets.clock);
@@ -283,6 +393,16 @@ mv64xxx_i2c_fsm(struct mv64xxx_i2c_data *drv_data, u32 status)
283 drv_data->rc = -ENXIO; 393 drv_data->rc = -ENXIO;
284 break; 394 break;
285 395
396 case MV64XXX_I2C_STATUS_OFFLOAD_OK:
397 if (drv_data->send_stop || drv_data->aborting) {
398 drv_data->action = MV64XXX_I2C_ACTION_OFFLOAD_SEND_STOP;
399 drv_data->state = MV64XXX_I2C_STATE_IDLE;
400 } else {
401 drv_data->action = MV64XXX_I2C_ACTION_OFFLOAD_RESTART;
402 drv_data->state = MV64XXX_I2C_STATE_WAITING_FOR_RESTART;
403 }
404 break;
405
286 default: 406 default:
287 dev_err(&drv_data->adapter.dev, 407 dev_err(&drv_data->adapter.dev,
288 "mv64xxx_i2c_fsm: Ctlr Error -- state: 0x%x, " 408 "mv64xxx_i2c_fsm: Ctlr Error -- state: 0x%x, "
@@ -299,20 +419,27 @@ static void
299mv64xxx_i2c_do_action(struct mv64xxx_i2c_data *drv_data) 419mv64xxx_i2c_do_action(struct mv64xxx_i2c_data *drv_data)
300{ 420{
301 switch(drv_data->action) { 421 switch(drv_data->action) {
422 case MV64XXX_I2C_ACTION_OFFLOAD_RESTART:
423 mv64xxx_i2c_update_offload_data(drv_data);
424 writel(0, drv_data->reg_base + MV64XXX_I2C_REG_BRIDGE_CONTROL);
425 writel(0, drv_data->reg_base +
426 MV64XXX_I2C_REG_BRIDGE_INTR_CAUSE);
427 /* FALLTHRU */
302 case MV64XXX_I2C_ACTION_SEND_RESTART: 428 case MV64XXX_I2C_ACTION_SEND_RESTART:
303 /* We should only get here if we have further messages */ 429 /* We should only get here if we have further messages */
304 BUG_ON(drv_data->num_msgs == 0); 430 BUG_ON(drv_data->num_msgs == 0);
305 431
306 drv_data->cntl_bits |= MV64XXX_I2C_REG_CONTROL_START;
307 writel(drv_data->cntl_bits,
308 drv_data->reg_base + drv_data->reg_offsets.control);
309
310 drv_data->msgs++; 432 drv_data->msgs++;
311 drv_data->num_msgs--; 433 drv_data->num_msgs--;
434 if (!(drv_data->offload_enabled &&
435 mv64xxx_i2c_offload_msg(drv_data))) {
436 drv_data->cntl_bits |= MV64XXX_I2C_REG_CONTROL_START;
437 writel(drv_data->cntl_bits,
438 drv_data->reg_base + drv_data->reg_offsets.control);
312 439
313 /* Setup for the next message */ 440 /* Setup for the next message */
314 mv64xxx_i2c_prepare_for_io(drv_data, drv_data->msgs); 441 mv64xxx_i2c_prepare_for_io(drv_data, drv_data->msgs);
315 442 }
316 /* 443 /*
317 * We're never at the start of the message here, and by this 444 * We're never at the start of the message here, and by this
318 * time it's already too late to do any protocol mangling. 445 * time it's already too late to do any protocol mangling.
@@ -326,6 +453,12 @@ mv64xxx_i2c_do_action(struct mv64xxx_i2c_data *drv_data)
326 drv_data->reg_base + drv_data->reg_offsets.control); 453 drv_data->reg_base + drv_data->reg_offsets.control);
327 break; 454 break;
328 455
456 case MV64XXX_I2C_ACTION_OFFLOAD_SEND_START:
457 if (!mv64xxx_i2c_offload_msg(drv_data))
458 break;
459 else
460 drv_data->action = MV64XXX_I2C_ACTION_SEND_START;
461 /* FALLTHRU */
329 case MV64XXX_I2C_ACTION_SEND_START: 462 case MV64XXX_I2C_ACTION_SEND_START:
330 writel(drv_data->cntl_bits | MV64XXX_I2C_REG_CONTROL_START, 463 writel(drv_data->cntl_bits | MV64XXX_I2C_REG_CONTROL_START,
331 drv_data->reg_base + drv_data->reg_offsets.control); 464 drv_data->reg_base + drv_data->reg_offsets.control);
@@ -375,6 +508,7 @@ mv64xxx_i2c_do_action(struct mv64xxx_i2c_data *drv_data)
375 "mv64xxx_i2c_do_action: Invalid action: %d\n", 508 "mv64xxx_i2c_do_action: Invalid action: %d\n",
376 drv_data->action); 509 drv_data->action);
377 drv_data->rc = -EIO; 510 drv_data->rc = -EIO;
511
378 /* FALLTHRU */ 512 /* FALLTHRU */
379 case MV64XXX_I2C_ACTION_SEND_STOP: 513 case MV64XXX_I2C_ACTION_SEND_STOP:
380 drv_data->cntl_bits &= ~MV64XXX_I2C_REG_CONTROL_INTEN; 514 drv_data->cntl_bits &= ~MV64XXX_I2C_REG_CONTROL_INTEN;
@@ -383,6 +517,15 @@ mv64xxx_i2c_do_action(struct mv64xxx_i2c_data *drv_data)
383 drv_data->block = 0; 517 drv_data->block = 0;
384 wake_up(&drv_data->waitq); 518 wake_up(&drv_data->waitq);
385 break; 519 break;
520
521 case MV64XXX_I2C_ACTION_OFFLOAD_SEND_STOP:
522 mv64xxx_i2c_update_offload_data(drv_data);
523 writel(0, drv_data->reg_base + MV64XXX_I2C_REG_BRIDGE_CONTROL);
524 writel(0, drv_data->reg_base +
525 MV64XXX_I2C_REG_BRIDGE_INTR_CAUSE);
526 drv_data->block = 0;
527 wake_up(&drv_data->waitq);
528 break;
386 } 529 }
387} 530}
388 531
@@ -395,6 +538,21 @@ mv64xxx_i2c_intr(int irq, void *dev_id)
395 irqreturn_t rc = IRQ_NONE; 538 irqreturn_t rc = IRQ_NONE;
396 539
397 spin_lock_irqsave(&drv_data->lock, flags); 540 spin_lock_irqsave(&drv_data->lock, flags);
541
542 if (drv_data->offload_enabled) {
543 while (readl(drv_data->reg_base +
544 MV64XXX_I2C_REG_BRIDGE_INTR_CAUSE)) {
545 int reg_status = readl(drv_data->reg_base +
546 MV64XXX_I2C_REG_BRIDGE_STATUS);
547 if (reg_status & MV64XXX_I2C_BRIDGE_STATUS_ERROR)
548 status = MV64XXX_I2C_STATUS_OFFLOAD_ERROR;
549 else
550 status = MV64XXX_I2C_STATUS_OFFLOAD_OK;
551 mv64xxx_i2c_fsm(drv_data, status);
552 mv64xxx_i2c_do_action(drv_data);
553 rc = IRQ_HANDLED;
554 }
555 }
398 while (readl(drv_data->reg_base + drv_data->reg_offsets.control) & 556 while (readl(drv_data->reg_base + drv_data->reg_offsets.control) &
399 MV64XXX_I2C_REG_CONTROL_IFLG) { 557 MV64XXX_I2C_REG_CONTROL_IFLG) {
400 status = readl(drv_data->reg_base + drv_data->reg_offsets.status); 558 status = readl(drv_data->reg_base + drv_data->reg_offsets.status);
@@ -459,11 +617,15 @@ mv64xxx_i2c_execute_msg(struct mv64xxx_i2c_data *drv_data, struct i2c_msg *msg,
459 unsigned long flags; 617 unsigned long flags;
460 618
461 spin_lock_irqsave(&drv_data->lock, flags); 619 spin_lock_irqsave(&drv_data->lock, flags);
462 mv64xxx_i2c_prepare_for_io(drv_data, msg); 620 if (drv_data->offload_enabled) {
463 621 drv_data->action = MV64XXX_I2C_ACTION_OFFLOAD_SEND_START;
464 drv_data->action = MV64XXX_I2C_ACTION_SEND_START; 622 drv_data->state = MV64XXX_I2C_STATE_WAITING_FOR_START_COND;
465 drv_data->state = MV64XXX_I2C_STATE_WAITING_FOR_START_COND; 623 } else {
624 mv64xxx_i2c_prepare_for_io(drv_data, msg);
466 625
626 drv_data->action = MV64XXX_I2C_ACTION_SEND_START;
627 drv_data->state = MV64XXX_I2C_STATE_WAITING_FOR_START_COND;
628 }
467 drv_data->send_stop = is_last; 629 drv_data->send_stop = is_last;
468 drv_data->block = 1; 630 drv_data->block = 1;
469 mv64xxx_i2c_do_action(drv_data); 631 mv64xxx_i2c_do_action(drv_data);
@@ -521,6 +683,7 @@ static const struct i2c_algorithm mv64xxx_i2c_algo = {
521static const struct of_device_id mv64xxx_i2c_of_match_table[] = { 683static const struct of_device_id mv64xxx_i2c_of_match_table[] = {
522 { .compatible = "allwinner,sun4i-i2c", .data = &mv64xxx_i2c_regs_sun4i}, 684 { .compatible = "allwinner,sun4i-i2c", .data = &mv64xxx_i2c_regs_sun4i},
523 { .compatible = "marvell,mv64xxx-i2c", .data = &mv64xxx_i2c_regs_mv64xxx}, 685 { .compatible = "marvell,mv64xxx-i2c", .data = &mv64xxx_i2c_regs_mv64xxx},
686 { .compatible = "marvell,mv78230-i2c", .data = &mv64xxx_i2c_regs_mv64xxx},
524 {} 687 {}
525}; 688};
526MODULE_DEVICE_TABLE(of, mv64xxx_i2c_of_match_table); 689MODULE_DEVICE_TABLE(of, mv64xxx_i2c_of_match_table);
@@ -601,6 +764,13 @@ mv64xxx_of_config(struct mv64xxx_i2c_data *drv_data,
601 764
602 memcpy(&drv_data->reg_offsets, device->data, sizeof(drv_data->reg_offsets)); 765 memcpy(&drv_data->reg_offsets, device->data, sizeof(drv_data->reg_offsets));
603 766
767 /*
768 * For controllers embedded in new SoCs activate the
769 * Transaction Generator support.
770 */
771 if (of_device_is_compatible(np, "marvell,mv78230-i2c"))
772 drv_data->offload_enabled = true;
773
604out: 774out:
605 return rc; 775 return rc;
606#endif 776#endif
@@ -654,6 +824,7 @@ mv64xxx_i2c_probe(struct platform_device *pd)
654 drv_data->freq_n = pdata->freq_n; 824 drv_data->freq_n = pdata->freq_n;
655 drv_data->irq = platform_get_irq(pd, 0); 825 drv_data->irq = platform_get_irq(pd, 0);
656 drv_data->adapter.timeout = msecs_to_jiffies(pdata->timeout); 826 drv_data->adapter.timeout = msecs_to_jiffies(pdata->timeout);
827 drv_data->offload_enabled = false;
657 memcpy(&drv_data->reg_offsets, &mv64xxx_i2c_regs_mv64xxx, sizeof(drv_data->reg_offsets)); 828 memcpy(&drv_data->reg_offsets, &mv64xxx_i2c_regs_mv64xxx, sizeof(drv_data->reg_offsets));
658 } else if (pd->dev.of_node) { 829 } else if (pd->dev.of_node) {
659 rc = mv64xxx_of_config(drv_data, &pd->dev); 830 rc = mv64xxx_of_config(drv_data, &pd->dev);