diff options
author | Wolfram Sang <wsa+renesas@sang-engineering.com> | 2014-11-18 11:04:55 -0500 |
---|---|---|
committer | Wolfram Sang <wsa@the-dreams.de> | 2014-12-11 16:25:55 -0500 |
commit | de20d1857dd6b1a289d3b0476d6af36d12000d7e (patch) | |
tree | 984b59c97ade8ca0ea2a3842fcc2e64a13ff04b1 /drivers/i2c | |
parent | 389be323cfac383e4d71dfeeaa1b0c3aec722a5f (diff) |
i2c: rcar: add slave support
The first I2C slave provider using the new generic interface.
Signed-off-by: Wolfram Sang <wsa+renesas@sang-engineering.com>
Signed-off-by: Wolfram Sang <wsa@the-dreams.de>
Diffstat (limited to 'drivers/i2c')
-rw-r--r-- | drivers/i2c/busses/i2c-rcar.c | 124 |
1 files changed, 115 insertions, 9 deletions
diff --git a/drivers/i2c/busses/i2c-rcar.c b/drivers/i2c/busses/i2c-rcar.c index d826e82dd997..835057741aa6 100644 --- a/drivers/i2c/busses/i2c-rcar.c +++ b/drivers/i2c/busses/i2c-rcar.c | |||
@@ -48,6 +48,12 @@ | |||
48 | #define ICMAR 0x20 /* master address */ | 48 | #define ICMAR 0x20 /* master address */ |
49 | #define ICRXTX 0x24 /* data port */ | 49 | #define ICRXTX 0x24 /* data port */ |
50 | 50 | ||
51 | /* ICSCR */ | ||
52 | #define SDBS (1 << 3) /* slave data buffer select */ | ||
53 | #define SIE (1 << 2) /* slave interface enable */ | ||
54 | #define GCAE (1 << 1) /* general call address enable */ | ||
55 | #define FNA (1 << 0) /* forced non acknowledgment */ | ||
56 | |||
51 | /* ICMCR */ | 57 | /* ICMCR */ |
52 | #define MDBS (1 << 7) /* non-fifo mode switch */ | 58 | #define MDBS (1 << 7) /* non-fifo mode switch */ |
53 | #define FSCL (1 << 6) /* override SCL pin */ | 59 | #define FSCL (1 << 6) /* override SCL pin */ |
@@ -58,6 +64,15 @@ | |||
58 | #define FSB (1 << 1) /* force stop bit */ | 64 | #define FSB (1 << 1) /* force stop bit */ |
59 | #define ESG (1 << 0) /* en startbit gen */ | 65 | #define ESG (1 << 0) /* en startbit gen */ |
60 | 66 | ||
67 | /* ICSSR (also for ICSIER) */ | ||
68 | #define GCAR (1 << 6) /* general call received */ | ||
69 | #define STM (1 << 5) /* slave transmit mode */ | ||
70 | #define SSR (1 << 4) /* stop received */ | ||
71 | #define SDE (1 << 3) /* slave data empty */ | ||
72 | #define SDT (1 << 2) /* slave data transmitted */ | ||
73 | #define SDR (1 << 1) /* slave data received */ | ||
74 | #define SAR (1 << 0) /* slave addr received */ | ||
75 | |||
61 | /* ICMSR (also for ICMIE) */ | 76 | /* ICMSR (also for ICMIE) */ |
62 | #define MNR (1 << 6) /* nack received */ | 77 | #define MNR (1 << 6) /* nack received */ |
63 | #define MAL (1 << 5) /* arbitration lost */ | 78 | #define MAL (1 << 5) /* arbitration lost */ |
@@ -103,6 +118,7 @@ struct rcar_i2c_priv { | |||
103 | u32 icccr; | 118 | u32 icccr; |
104 | u32 flags; | 119 | u32 flags; |
105 | enum rcar_i2c_type devtype; | 120 | enum rcar_i2c_type devtype; |
121 | struct i2c_client *slave; | ||
106 | }; | 122 | }; |
107 | 123 | ||
108 | #define rcar_i2c_priv_to_dev(p) ((p)->adap.dev.parent) | 124 | #define rcar_i2c_priv_to_dev(p) ((p)->adap.dev.parent) |
@@ -126,15 +142,6 @@ static u32 rcar_i2c_read(struct rcar_i2c_priv *priv, int reg) | |||
126 | 142 | ||
127 | static void rcar_i2c_init(struct rcar_i2c_priv *priv) | 143 | static void rcar_i2c_init(struct rcar_i2c_priv *priv) |
128 | { | 144 | { |
129 | /* | ||
130 | * reset slave mode. | ||
131 | * slave mode is not used on this driver | ||
132 | */ | ||
133 | rcar_i2c_write(priv, ICSIER, 0); | ||
134 | rcar_i2c_write(priv, ICSAR, 0); | ||
135 | rcar_i2c_write(priv, ICSCR, 0); | ||
136 | rcar_i2c_write(priv, ICSSR, 0); | ||
137 | |||
138 | /* reset master mode */ | 145 | /* reset master mode */ |
139 | rcar_i2c_write(priv, ICMIER, 0); | 146 | rcar_i2c_write(priv, ICMIER, 0); |
140 | rcar_i2c_write(priv, ICMCR, 0); | 147 | rcar_i2c_write(priv, ICMCR, 0); |
@@ -360,6 +367,63 @@ static int rcar_i2c_irq_recv(struct rcar_i2c_priv *priv, u32 msr) | |||
360 | return 0; | 367 | return 0; |
361 | } | 368 | } |
362 | 369 | ||
370 | static bool rcar_i2c_slave_irq(struct rcar_i2c_priv *priv) | ||
371 | { | ||
372 | u32 ssr_raw, ssr_filtered; | ||
373 | u8 value; | ||
374 | |||
375 | ssr_raw = rcar_i2c_read(priv, ICSSR) & 0xff; | ||
376 | ssr_filtered = ssr_raw & rcar_i2c_read(priv, ICSIER); | ||
377 | |||
378 | if (!ssr_filtered) | ||
379 | return false; | ||
380 | |||
381 | /* address detected */ | ||
382 | if (ssr_filtered & SAR) { | ||
383 | /* read or write request */ | ||
384 | if (ssr_raw & STM) { | ||
385 | i2c_slave_event(priv->slave, I2C_SLAVE_REQ_READ_START, &value); | ||
386 | rcar_i2c_write(priv, ICRXTX, value); | ||
387 | rcar_i2c_write(priv, ICSIER, SDE | SSR | SAR); | ||
388 | } else { | ||
389 | i2c_slave_event(priv->slave, I2C_SLAVE_REQ_WRITE_START, &value); | ||
390 | rcar_i2c_read(priv, ICRXTX); /* dummy read */ | ||
391 | rcar_i2c_write(priv, ICSIER, SDR | SSR | SAR); | ||
392 | } | ||
393 | |||
394 | rcar_i2c_write(priv, ICSSR, ~SAR & 0xff); | ||
395 | } | ||
396 | |||
397 | /* master sent stop */ | ||
398 | if (ssr_filtered & SSR) { | ||
399 | i2c_slave_event(priv->slave, I2C_SLAVE_STOP, &value); | ||
400 | rcar_i2c_write(priv, ICSIER, SAR | SSR); | ||
401 | rcar_i2c_write(priv, ICSSR, ~SSR & 0xff); | ||
402 | } | ||
403 | |||
404 | /* master wants to write to us */ | ||
405 | if (ssr_filtered & SDR) { | ||
406 | int ret; | ||
407 | |||
408 | value = rcar_i2c_read(priv, ICRXTX); | ||
409 | ret = i2c_slave_event(priv->slave, I2C_SLAVE_REQ_WRITE_END, &value); | ||
410 | /* Send NACK in case of error */ | ||
411 | rcar_i2c_write(priv, ICSCR, SIE | SDBS | (ret < 0 ? FNA : 0)); | ||
412 | i2c_slave_event(priv->slave, I2C_SLAVE_REQ_WRITE_START, &value); | ||
413 | rcar_i2c_write(priv, ICSSR, ~SDR & 0xff); | ||
414 | } | ||
415 | |||
416 | /* master wants to read from us */ | ||
417 | if (ssr_filtered & SDE) { | ||
418 | i2c_slave_event(priv->slave, I2C_SLAVE_REQ_READ_END, &value); | ||
419 | i2c_slave_event(priv->slave, I2C_SLAVE_REQ_READ_START, &value); | ||
420 | rcar_i2c_write(priv, ICRXTX, value); | ||
421 | rcar_i2c_write(priv, ICSSR, ~SDE & 0xff); | ||
422 | } | ||
423 | |||
424 | return true; | ||
425 | } | ||
426 | |||
363 | static irqreturn_t rcar_i2c_irq(int irq, void *ptr) | 427 | static irqreturn_t rcar_i2c_irq(int irq, void *ptr) |
364 | { | 428 | { |
365 | struct rcar_i2c_priv *priv = ptr; | 429 | struct rcar_i2c_priv *priv = ptr; |
@@ -369,6 +433,9 @@ static irqreturn_t rcar_i2c_irq(int irq, void *ptr) | |||
369 | /*-------------- spin lock -----------------*/ | 433 | /*-------------- spin lock -----------------*/ |
370 | spin_lock(&priv->lock); | 434 | spin_lock(&priv->lock); |
371 | 435 | ||
436 | if (rcar_i2c_slave_irq(priv)) | ||
437 | goto exit; | ||
438 | |||
372 | msr = rcar_i2c_read(priv, ICMSR); | 439 | msr = rcar_i2c_read(priv, ICMSR); |
373 | 440 | ||
374 | /* Only handle interrupts that are currently enabled */ | 441 | /* Only handle interrupts that are currently enabled */ |
@@ -499,6 +566,43 @@ out: | |||
499 | return ret; | 566 | return ret; |
500 | } | 567 | } |
501 | 568 | ||
569 | static int rcar_reg_slave(struct i2c_client *slave) | ||
570 | { | ||
571 | struct rcar_i2c_priv *priv = i2c_get_adapdata(slave->adapter); | ||
572 | |||
573 | if (priv->slave) | ||
574 | return -EBUSY; | ||
575 | |||
576 | if (slave->flags & I2C_CLIENT_TEN) | ||
577 | return -EAFNOSUPPORT; | ||
578 | |||
579 | pm_runtime_forbid(rcar_i2c_priv_to_dev(priv)); | ||
580 | |||
581 | priv->slave = slave; | ||
582 | rcar_i2c_write(priv, ICSAR, slave->addr); | ||
583 | rcar_i2c_write(priv, ICSSR, 0); | ||
584 | rcar_i2c_write(priv, ICSIER, SAR | SSR); | ||
585 | rcar_i2c_write(priv, ICSCR, SIE | SDBS); | ||
586 | |||
587 | return 0; | ||
588 | } | ||
589 | |||
590 | static int rcar_unreg_slave(struct i2c_client *slave) | ||
591 | { | ||
592 | struct rcar_i2c_priv *priv = i2c_get_adapdata(slave->adapter); | ||
593 | |||
594 | WARN_ON(!priv->slave); | ||
595 | |||
596 | rcar_i2c_write(priv, ICSIER, 0); | ||
597 | rcar_i2c_write(priv, ICSCR, 0); | ||
598 | |||
599 | priv->slave = NULL; | ||
600 | |||
601 | pm_runtime_allow(rcar_i2c_priv_to_dev(priv)); | ||
602 | |||
603 | return 0; | ||
604 | } | ||
605 | |||
502 | static u32 rcar_i2c_func(struct i2c_adapter *adap) | 606 | static u32 rcar_i2c_func(struct i2c_adapter *adap) |
503 | { | 607 | { |
504 | /* This HW can't do SMBUS_QUICK and NOSTART */ | 608 | /* This HW can't do SMBUS_QUICK and NOSTART */ |
@@ -508,6 +612,8 @@ static u32 rcar_i2c_func(struct i2c_adapter *adap) | |||
508 | static const struct i2c_algorithm rcar_i2c_algo = { | 612 | static const struct i2c_algorithm rcar_i2c_algo = { |
509 | .master_xfer = rcar_i2c_master_xfer, | 613 | .master_xfer = rcar_i2c_master_xfer, |
510 | .functionality = rcar_i2c_func, | 614 | .functionality = rcar_i2c_func, |
615 | .reg_slave = rcar_reg_slave, | ||
616 | .unreg_slave = rcar_unreg_slave, | ||
511 | }; | 617 | }; |
512 | 618 | ||
513 | static const struct of_device_id rcar_i2c_dt_ids[] = { | 619 | static const struct of_device_id rcar_i2c_dt_ids[] = { |