summaryrefslogtreecommitdiffstats
path: root/drivers/i2c/busses/i2c-riic.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/i2c/busses/i2c-riic.c')
-rw-r--r--drivers/i2c/busses/i2c-riic.c125
1 files changed, 89 insertions, 36 deletions
diff --git a/drivers/i2c/busses/i2c-riic.c b/drivers/i2c/busses/i2c-riic.c
index e43ff483c5..f608b1838c 100644
--- a/drivers/i2c/busses/i2c-riic.c
+++ b/drivers/i2c/busses/i2c-riic.c
@@ -46,18 +46,6 @@
#include <linux/pm_runtime.h>
#include <linux/reset.h>
-#define RIIC_ICCR1 0x00
-#define RIIC_ICCR2 0x04
-#define RIIC_ICMR1 0x08
-#define RIIC_ICMR3 0x10
-#define RIIC_ICSER 0x18
-#define RIIC_ICIER 0x1c
-#define RIIC_ICSR2 0x24
-#define RIIC_ICBRL 0x34
-#define RIIC_ICBRH 0x38
-#define RIIC_ICDRT 0x3c
-#define RIIC_ICDRR 0x40
-
#define ICCR1_ICE 0x80
#define ICCR1_IICRST 0x40
#define ICCR1_SOWP 0x10
@@ -87,6 +75,25 @@
#define RIIC_INIT_MSG -1
+enum riic_reg_list {
+ RIIC_ICCR1 = 0,
+ RIIC_ICCR2,
+ RIIC_ICMR1,
+ RIIC_ICMR3,
+ RIIC_ICSER,
+ RIIC_ICIER,
+ RIIC_ICSR2,
+ RIIC_ICBRL,
+ RIIC_ICBRH,
+ RIIC_ICDRT,
+ RIIC_ICDRR,
+ RIIC_REG_END,
+};
+
+struct riic_of_data {
+ u8 regs[RIIC_REG_END];
+};
+
struct riic_dev {
void __iomem *base;
u8 *buf;
@@ -94,6 +101,7 @@ struct riic_dev {
int bytes_left;
int err;
int is_last;
+ const struct riic_of_data *info;
struct completion msg_done;
struct i2c_adapter adapter;
struct clk *clk;
@@ -105,9 +113,19 @@ struct riic_irq_desc {
char *name;
};
+static inline void riic_writeb(struct riic_dev *riic, u8 val, u8 offset)
+{
+ writeb(val, riic->base + riic->info->regs[offset]);
+}
+
+static inline u8 riic_readb(struct riic_dev *riic, u8 offset)
+{
+ return readb(riic->base + riic->info->regs[offset]);
+}
+
static inline void riic_clear_set_bit(struct riic_dev *riic, u8 clear, u8 set, u8 reg)
{
- writeb((readb(riic->base + reg) & ~clear) | set, riic->base + reg);
+ riic_writeb(riic, (riic_readb(riic, reg) & ~clear) | set, reg);
}
static int riic_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[], int num)
@@ -119,7 +137,7 @@ static int riic_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[], int num)
pm_runtime_get_sync(adap->dev.parent);
- if (readb(riic->base + RIIC_ICCR2) & ICCR2_BBSY) {
+ if (riic_readb(riic, RIIC_ICCR2) & ICCR2_BBSY) {
riic->err = -EBUSY;
goto out;
}
@@ -127,7 +145,7 @@ static int riic_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[], int num)
reinit_completion(&riic->msg_done);
riic->err = 0;
- writeb(0, riic->base + RIIC_ICSR2);
+ riic_writeb(riic, 0, RIIC_ICSR2);
for (i = 0, start_bit = ICCR2_ST; i < num; i++) {
riic->bytes_left = RIIC_INIT_MSG;
@@ -135,9 +153,9 @@ static int riic_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[], int num)
riic->msg = &msgs[i];
riic->is_last = (i == num - 1);
- writeb(ICIER_NAKIE | ICIER_TIE, riic->base + RIIC_ICIER);
+ riic_writeb(riic, ICIER_NAKIE | ICIER_TIE, RIIC_ICIER);
- writeb(start_bit, riic->base + RIIC_ICCR2);
+ riic_writeb(riic, start_bit, RIIC_ICCR2);
time_left = wait_for_completion_timeout(&riic->msg_done, riic->adapter.timeout);
if (time_left == 0)
@@ -191,7 +209,7 @@ static irqreturn_t riic_tdre_isr(int irq, void *data)
* value could be moved to the shadow shift register right away. So
* this must be after updates to ICIER (where we want to disable TIE)!
*/
- writeb(val, riic->base + RIIC_ICDRT);
+ riic_writeb(riic, val, RIIC_ICDRT);
return IRQ_HANDLED;
}
@@ -200,9 +218,9 @@ static irqreturn_t riic_tend_isr(int irq, void *data)
{
struct riic_dev *riic = data;
- if (readb(riic->base + RIIC_ICSR2) & ICSR2_NACKF) {
+ if (riic_readb(riic, RIIC_ICSR2) & ICSR2_NACKF) {
/* We got a NACKIE */
- readb(riic->base + RIIC_ICDRR); /* dummy read */
+ riic_readb(riic, RIIC_ICDRR); /* dummy read */
riic_clear_set_bit(riic, ICSR2_NACKF, 0, RIIC_ICSR2);
riic->err = -ENXIO;
} else if (riic->bytes_left) {
@@ -211,7 +229,7 @@ static irqreturn_t riic_tend_isr(int irq, void *data)
if (riic->is_last || riic->err) {
riic_clear_set_bit(riic, ICIER_TEIE, ICIER_SPIE, RIIC_ICIER);
- writeb(ICCR2_SP, riic->base + RIIC_ICCR2);
+ riic_writeb(riic, ICCR2_SP, RIIC_ICCR2);
} else {
/* Transfer is complete, but do not send STOP */
riic_clear_set_bit(riic, ICIER_TEIE, 0, RIIC_ICIER);
@@ -230,7 +248,7 @@ static irqreturn_t riic_rdrf_isr(int irq, void *data)
if (riic->bytes_left == RIIC_INIT_MSG) {
riic->bytes_left = riic->msg->len;
- readb(riic->base + RIIC_ICDRR); /* dummy read */
+ riic_readb(riic, RIIC_ICDRR); /* dummy read */
return IRQ_HANDLED;
}
@@ -238,7 +256,7 @@ static irqreturn_t riic_rdrf_isr(int irq, void *data)
/* STOP must come before we set ACKBT! */
if (riic->is_last) {
riic_clear_set_bit(riic, 0, ICIER_SPIE, RIIC_ICIER);
- writeb(ICCR2_SP, riic->base + RIIC_ICCR2);
+ riic_writeb(riic, ICCR2_SP, RIIC_ICCR2);
}
riic_clear_set_bit(riic, 0, ICMR3_ACKBT, RIIC_ICMR3);
@@ -248,7 +266,7 @@ static irqreturn_t riic_rdrf_isr(int irq, void *data)
}
/* Reading acks the RIE interrupt */
- *riic->buf = readb(riic->base + RIIC_ICDRR);
+ *riic->buf = riic_readb(riic, RIIC_ICDRR);
riic->buf++;
riic->bytes_left--;
@@ -260,10 +278,10 @@ static irqreturn_t riic_stop_isr(int irq, void *data)
struct riic_dev *riic = data;
/* read back registers to confirm writes have fully propagated */
- writeb(0, riic->base + RIIC_ICSR2);
- readb(riic->base + RIIC_ICSR2);
- writeb(0, riic->base + RIIC_ICIER);
- readb(riic->base + RIIC_ICIER);
+ riic_writeb(riic, 0, RIIC_ICSR2);
+ riic_readb(riic, RIIC_ICSR2);
+ riic_writeb(riic, 0, RIIC_ICIER);
+ riic_readb(riic, RIIC_ICIER);
complete(&riic->msg_done);
@@ -365,15 +383,15 @@ static int riic_init_hw(struct riic_dev *riic, struct i2c_timings *t)
t->scl_rise_ns / (1000000000 / rate), cks, brl, brh);
/* Changing the order of accessing IICRST and ICE may break things! */
- writeb(ICCR1_IICRST | ICCR1_SOWP, riic->base + RIIC_ICCR1);
+ riic_writeb(riic, ICCR1_IICRST | ICCR1_SOWP, RIIC_ICCR1);
riic_clear_set_bit(riic, 0, ICCR1_ICE, RIIC_ICCR1);
- writeb(ICMR1_CKS(cks), riic->base + RIIC_ICMR1);
- writeb(brh | ICBR_RESERVED, riic->base + RIIC_ICBRH);
- writeb(brl | ICBR_RESERVED, riic->base + RIIC_ICBRL);
+ riic_writeb(riic, ICMR1_CKS(cks), RIIC_ICMR1);
+ riic_writeb(riic, brh | ICBR_RESERVED, RIIC_ICBRH);
+ riic_writeb(riic, brl | ICBR_RESERVED, RIIC_ICBRL);
- writeb(0, riic->base + RIIC_ICSER);
- writeb(ICMR3_ACKWP | ICMR3_RDRFS, riic->base + RIIC_ICMR3);
+ riic_writeb(riic, 0, RIIC_ICSER);
+ riic_writeb(riic, ICMR3_ACKWP | ICMR3_RDRFS, RIIC_ICMR3);
riic_clear_set_bit(riic, ICCR1_IICRST, 0, RIIC_ICCR1);
@@ -443,6 +461,8 @@ static int riic_i2c_probe(struct platform_device *pdev)
}
}
+ riic->info = of_device_get_match_data(&pdev->dev);
+
adap = &riic->adapter;
i2c_set_adapdata(adap, riic);
strscpy(adap->name, "Renesas RIIC adapter", sizeof(adap->name));
@@ -481,14 +501,47 @@ static void riic_i2c_remove(struct platform_device *pdev)
struct riic_dev *riic = platform_get_drvdata(pdev);
pm_runtime_get_sync(&pdev->dev);
- writeb(0, riic->base + RIIC_ICIER);
+ riic_writeb(riic, 0, RIIC_ICIER);
pm_runtime_put(&pdev->dev);
i2c_del_adapter(&riic->adapter);
pm_runtime_disable(&pdev->dev);
}
+static const struct riic_of_data riic_rz_a_info = {
+ .regs = {
+ [RIIC_ICCR1] = 0x00,
+ [RIIC_ICCR2] = 0x04,
+ [RIIC_ICMR1] = 0x08,
+ [RIIC_ICMR3] = 0x10,
+ [RIIC_ICSER] = 0x18,
+ [RIIC_ICIER] = 0x1c,
+ [RIIC_ICSR2] = 0x24,
+ [RIIC_ICBRL] = 0x34,
+ [RIIC_ICBRH] = 0x38,
+ [RIIC_ICDRT] = 0x3c,
+ [RIIC_ICDRR] = 0x40,
+ },
+};
+
+static const struct riic_of_data riic_rz_v2h_info = {
+ .regs = {
+ [RIIC_ICCR1] = 0x00,
+ [RIIC_ICCR2] = 0x01,
+ [RIIC_ICMR1] = 0x02,
+ [RIIC_ICMR3] = 0x04,
+ [RIIC_ICSER] = 0x06,
+ [RIIC_ICIER] = 0x07,
+ [RIIC_ICSR2] = 0x09,
+ [RIIC_ICBRL] = 0x10,
+ [RIIC_ICBRH] = 0x11,
+ [RIIC_ICDRT] = 0x12,
+ [RIIC_ICDRR] = 0x13,
+ },
+};
+
static const struct of_device_id riic_i2c_dt_ids[] = {
- { .compatible = "renesas,riic-rz", },
+ { .compatible = "renesas,riic-rz", .data = &riic_rz_a_info },
+ { .compatible = "renesas,riic-r9a09g057", .data = &riic_rz_v2h_info },
{ /* Sentinel */ },
};