This series are based on 5.0-rc1 and provide six patches to support
mt7629 and mt8183 IC.
Main changes compared to v2:
--update commit message
--add Reviewed-by from Rob Herring, Nicolas and Sean
Main changes compared to v1:
--remove useless dt-binding for mt7629
--split a patch into two(2/6 3/6)
--muti-user feature was dropped
qii wang (6):
dt-bindings: i2c: Add Mediatek MT7629 i2c binding
i2c: mediatek: speeds is replaced by macros definitions
i2c: mediatek: remove completion_done()
i2c: mediatek: Add offsets array for new i2c registers
dt-bindings: i2c: Add Mediatek MT8183 i2c binding
i2c: mediatek: Add i2c support for MediaTek MT8183
Documentation/devicetree/bindings/i2c/i2c-mtk.txt | 7 +-
drivers/i2c/busses/i2c-mt65xx.c | 288 ++++++++++++++++-----
2 files changed, 227 insertions(+), 68 deletions(-)
--
1.7.9.5
New i2c registers would have different offsets, so we use different
offsets array to distinguish different i2c registers version.
Signed-off-by: qii wang <[email protected]>
Reviewed-by: Sean Wang <[email protected]>
Reviewed-by: Nicolas Boichat <[email protected]>
---
drivers/i2c/busses/i2c-mt65xx.c | 163 +++++++++++++++++++++++++--------------
1 file changed, 104 insertions(+), 59 deletions(-)
diff --git a/drivers/i2c/busses/i2c-mt65xx.c b/drivers/i2c/busses/i2c-mt65xx.c
index 660de1e..428ac99 100644
--- a/drivers/i2c/busses/i2c-mt65xx.c
+++ b/drivers/i2c/busses/i2c-mt65xx.c
@@ -106,34 +106,62 @@ enum mtk_trans_op {
};
enum I2C_REGS_OFFSET {
- OFFSET_DATA_PORT = 0x0,
- OFFSET_SLAVE_ADDR = 0x04,
- OFFSET_INTR_MASK = 0x08,
- OFFSET_INTR_STAT = 0x0c,
- OFFSET_CONTROL = 0x10,
- OFFSET_TRANSFER_LEN = 0x14,
- OFFSET_TRANSAC_LEN = 0x18,
- OFFSET_DELAY_LEN = 0x1c,
- OFFSET_TIMING = 0x20,
- OFFSET_START = 0x24,
- OFFSET_EXT_CONF = 0x28,
- OFFSET_FIFO_STAT = 0x30,
- OFFSET_FIFO_THRESH = 0x34,
- OFFSET_FIFO_ADDR_CLR = 0x38,
- OFFSET_IO_CONFIG = 0x40,
- OFFSET_RSV_DEBUG = 0x44,
- OFFSET_HS = 0x48,
- OFFSET_SOFTRESET = 0x50,
- OFFSET_DCM_EN = 0x54,
- OFFSET_PATH_DIR = 0x60,
- OFFSET_DEBUGSTAT = 0x64,
- OFFSET_DEBUGCTRL = 0x68,
- OFFSET_TRANSFER_LEN_AUX = 0x6c,
- OFFSET_CLOCK_DIV = 0x70,
+ OFFSET_DATA_PORT,
+ OFFSET_SLAVE_ADDR,
+ OFFSET_INTR_MASK,
+ OFFSET_INTR_STAT,
+ OFFSET_CONTROL,
+ OFFSET_TRANSFER_LEN,
+ OFFSET_TRANSAC_LEN,
+ OFFSET_DELAY_LEN,
+ OFFSET_TIMING,
+ OFFSET_START,
+ OFFSET_EXT_CONF,
+ OFFSET_FIFO_STAT,
+ OFFSET_FIFO_THRESH,
+ OFFSET_FIFO_ADDR_CLR,
+ OFFSET_IO_CONFIG,
+ OFFSET_RSV_DEBUG,
+ OFFSET_HS,
+ OFFSET_SOFTRESET,
+ OFFSET_DCM_EN,
+ OFFSET_PATH_DIR,
+ OFFSET_DEBUGSTAT,
+ OFFSET_DEBUGCTRL,
+ OFFSET_TRANSFER_LEN_AUX,
+ OFFSET_CLOCK_DIV,
+};
+
+static const u16 mt_i2c_regs_v1[] = {
+ [OFFSET_DATA_PORT] = 0x0,
+ [OFFSET_SLAVE_ADDR] = 0x4,
+ [OFFSET_INTR_MASK] = 0x8,
+ [OFFSET_INTR_STAT] = 0xc,
+ [OFFSET_CONTROL] = 0x10,
+ [OFFSET_TRANSFER_LEN] = 0x14,
+ [OFFSET_TRANSAC_LEN] = 0x18,
+ [OFFSET_DELAY_LEN] = 0x1c,
+ [OFFSET_TIMING] = 0x20,
+ [OFFSET_START] = 0x24,
+ [OFFSET_EXT_CONF] = 0x28,
+ [OFFSET_FIFO_STAT] = 0x30,
+ [OFFSET_FIFO_THRESH] = 0x34,
+ [OFFSET_FIFO_ADDR_CLR] = 0x38,
+ [OFFSET_IO_CONFIG] = 0x40,
+ [OFFSET_RSV_DEBUG] = 0x44,
+ [OFFSET_HS] = 0x48,
+ [OFFSET_SOFTRESET] = 0x50,
+ [OFFSET_DCM_EN] = 0x54,
+ [OFFSET_PATH_DIR] = 0x60,
+ [OFFSET_DEBUGSTAT] = 0x64,
+ [OFFSET_DEBUGCTRL] = 0x68,
+ [OFFSET_TRANSFER_LEN_AUX] = 0x6c,
+ [OFFSET_CLOCK_DIV] = 0x70,
};
struct mtk_i2c_compatible {
const struct i2c_adapter_quirks *quirks;
+ const u16 *regs;
unsigned char pmic_i2c: 1;
unsigned char dcm: 1;
unsigned char auto_restart: 1;
@@ -181,6 +209,7 @@ struct mtk_i2c {
};
static const struct mtk_i2c_compatible mt2712_compat = {
+ .regs = mt_i2c_regs_v1,
.pmic_i2c = 0,
.dcm = 1,
.auto_restart = 1,
@@ -191,6 +220,7 @@ struct mtk_i2c {
static const struct mtk_i2c_compatible mt6577_compat = {
.quirks = &mt6577_i2c_quirks,
+ .regs = mt_i2c_regs_v1,
.pmic_i2c = 0,
.dcm = 1,
.auto_restart = 0,
@@ -201,6 +231,7 @@ struct mtk_i2c {
static const struct mtk_i2c_compatible mt6589_compat = {
.quirks = &mt6577_i2c_quirks,
+ .regs = mt_i2c_regs_v1,
.pmic_i2c = 1,
.dcm = 0,
.auto_restart = 0,
@@ -211,6 +242,7 @@ struct mtk_i2c {
static const struct mtk_i2c_compatible mt7622_compat = {
.quirks = &mt7622_i2c_quirks,
+ .regs = mt_i2c_regs_v1,
.pmic_i2c = 0,
.dcm = 1,
.auto_restart = 1,
@@ -220,6 +252,7 @@ struct mtk_i2c {
};
static const struct mtk_i2c_compatible mt8173_compat = {
+ .regs = mt_i2c_regs_v1,
.pmic_i2c = 0,
.dcm = 1,
.auto_restart = 1,
@@ -238,6 +271,17 @@ struct mtk_i2c {
};
MODULE_DEVICE_TABLE(of, mtk_i2c_of_match);
+static u16 mtk_i2c_readw(struct mtk_i2c *i2c, enum I2C_REGS_OFFSET reg)
+{
+ return readw(i2c->base + i2c->dev_comp->regs[reg]);
+}
+
+static void mtk_i2c_writew(struct mtk_i2c *i2c, u16 val,
+ enum I2C_REGS_OFFSET reg)
+{
+ writew(val, i2c->base + i2c->dev_comp->regs[reg]);
+}
+
static int mtk_i2c_clock_enable(struct mtk_i2c *i2c)
{
int ret;
@@ -278,31 +322,31 @@ static void mtk_i2c_init_hw(struct mtk_i2c *i2c)
{
u16 control_reg;
- writew(I2C_SOFT_RST, i2c->base + OFFSET_SOFTRESET);
+ mtk_i2c_writew(i2c, I2C_SOFT_RST, OFFSET_SOFTRESET);
/* Set ioconfig */
if (i2c->use_push_pull)
- writew(I2C_IO_CONFIG_PUSH_PULL, i2c->base + OFFSET_IO_CONFIG);
+ mtk_i2c_writew(i2c, I2C_IO_CONFIG_PUSH_PULL, OFFSET_IO_CONFIG);
else
- writew(I2C_IO_CONFIG_OPEN_DRAIN, i2c->base + OFFSET_IO_CONFIG);
+ mtk_i2c_writew(i2c, I2C_IO_CONFIG_OPEN_DRAIN, OFFSET_IO_CONFIG);
if (i2c->dev_comp->dcm)
- writew(I2C_DCM_DISABLE, i2c->base + OFFSET_DCM_EN);
+ mtk_i2c_writew(i2c, I2C_DCM_DISABLE, OFFSET_DCM_EN);
if (i2c->dev_comp->timing_adjust)
- writew(I2C_DEFAULT_CLK_DIV - 1, i2c->base + OFFSET_CLOCK_DIV);
+ mtk_i2c_writew(i2c, I2C_DEFAULT_CLK_DIV - 1, OFFSET_CLOCK_DIV);
- writew(i2c->timing_reg, i2c->base + OFFSET_TIMING);
- writew(i2c->high_speed_reg, i2c->base + OFFSET_HS);
+ mtk_i2c_writew(i2c, i2c->timing_reg, OFFSET_TIMING);
+ mtk_i2c_writew(i2c, i2c->high_speed_reg, OFFSET_HS);
/* If use i2c pin from PMIC mt6397 side, need set PATH_DIR first */
if (i2c->have_pmic)
- writew(I2C_CONTROL_WRAPPER, i2c->base + OFFSET_PATH_DIR);
+ mtk_i2c_writew(i2c, I2C_CONTROL_WRAPPER, OFFSET_PATH_DIR);
control_reg = I2C_CONTROL_ACKERR_DET_EN |
I2C_CONTROL_CLK_EXT_EN | I2C_CONTROL_DMA_EN;
- writew(control_reg, i2c->base + OFFSET_CONTROL);
- writew(I2C_DELAY_LEN, i2c->base + OFFSET_DELAY_LEN);
+ mtk_i2c_writew(i2c, control_reg, OFFSET_CONTROL);
+ mtk_i2c_writew(i2c, I2C_DELAY_LEN, OFFSET_DELAY_LEN);
writel(I2C_DMA_HARD_RST, i2c->pdmabase + OFFSET_RST);
udelay(50);
@@ -454,7 +498,7 @@ static int mtk_i2c_do_transfer(struct mtk_i2c *i2c, struct i2c_msg *msgs,
reinit_completion(&i2c->msg_complete);
- control_reg = readw(i2c->base + OFFSET_CONTROL) &
+ control_reg = mtk_i2c_readw(i2c, OFFSET_CONTROL) &
~(I2C_CONTROL_DIR_CHANGE | I2C_CONTROL_RS);
if ((i2c->speed_hz > MAX_FS_MODE_SPEED) || (left_num >= 1))
control_reg |= I2C_CONTROL_RS;
@@ -462,40 +506,41 @@ static int mtk_i2c_do_transfer(struct mtk_i2c *i2c, struct i2c_msg *msgs,
if (i2c->op == I2C_MASTER_WRRD)
control_reg |= I2C_CONTROL_DIR_CHANGE | I2C_CONTROL_RS;
- writew(control_reg, i2c->base + OFFSET_CONTROL);
+ mtk_i2c_writew(i2c, control_reg, OFFSET_CONTROL);
/* set start condition */
if (i2c->speed_hz <= I2C_DEFAULT_SPEED)
- writew(I2C_ST_START_CON, i2c->base + OFFSET_EXT_CONF);
+ mtk_i2c_writew(i2c, I2C_ST_START_CON, OFFSET_EXT_CONF);
else
- writew(I2C_FS_START_CON, i2c->base + OFFSET_EXT_CONF);
+ mtk_i2c_writew(i2c, I2C_FS_START_CON, OFFSET_EXT_CONF);
addr_reg = i2c_8bit_addr_from_msg(msgs);
- writew(addr_reg, i2c->base + OFFSET_SLAVE_ADDR);
+ mtk_i2c_writew(i2c, addr_reg, OFFSET_SLAVE_ADDR);
/* Clear interrupt status */
- writew(restart_flag | I2C_HS_NACKERR | I2C_ACKERR |
- I2C_TRANSAC_COMP, i2c->base + OFFSET_INTR_STAT);
- writew(I2C_FIFO_ADDR_CLR, i2c->base + OFFSET_FIFO_ADDR_CLR);
+ mtk_i2c_writew(i2c, restart_flag | I2C_HS_NACKERR | I2C_ACKERR |
+ I2C_TRANSAC_COMP, OFFSET_INTR_STAT);
+
+ mtk_i2c_writew(i2c, I2C_FIFO_ADDR_CLR, OFFSET_FIFO_ADDR_CLR);
/* Enable interrupt */
- writew(restart_flag | I2C_HS_NACKERR | I2C_ACKERR |
- I2C_TRANSAC_COMP, i2c->base + OFFSET_INTR_MASK);
+ mtk_i2c_writew(i2c, restart_flag | I2C_HS_NACKERR | I2C_ACKERR |
+ I2C_TRANSAC_COMP, OFFSET_INTR_MASK);
/* Set transfer and transaction len */
if (i2c->op == I2C_MASTER_WRRD) {
if (i2c->dev_comp->aux_len_reg) {
- writew(msgs->len, i2c->base + OFFSET_TRANSFER_LEN);
- writew((msgs + 1)->len, i2c->base +
- OFFSET_TRANSFER_LEN_AUX);
+ mtk_i2c_writew(i2c, msgs->len, OFFSET_TRANSFER_LEN);
+ mtk_i2c_writew(i2c, (msgs + 1)->len,
+ OFFSET_TRANSFER_LEN_AUX);
} else {
- writew(msgs->len | ((msgs + 1)->len) << 8,
- i2c->base + OFFSET_TRANSFER_LEN);
+ mtk_i2c_writew(i2c, msgs->len | ((msgs + 1)->len) << 8,
+ OFFSET_TRANSFER_LEN);
}
- writew(I2C_WRRD_TRANAC_VALUE, i2c->base + OFFSET_TRANSAC_LEN);
+ mtk_i2c_writew(i2c, I2C_WRRD_TRANAC_VALUE, OFFSET_TRANSAC_LEN);
} else {
- writew(msgs->len, i2c->base + OFFSET_TRANSFER_LEN);
- writew(num, i2c->base + OFFSET_TRANSAC_LEN);
+ mtk_i2c_writew(i2c, msgs->len, OFFSET_TRANSFER_LEN);
+ mtk_i2c_writew(i2c, num, OFFSET_TRANSAC_LEN);
}
/* Prepare buffer data to start transfer */
@@ -607,14 +652,14 @@ static int mtk_i2c_do_transfer(struct mtk_i2c *i2c, struct i2c_msg *msgs,
if (left_num >= 1)
start_reg |= I2C_RS_MUL_CNFG;
}
- writew(start_reg, i2c->base + OFFSET_START);
+ mtk_i2c_writew(i2c, start_reg, OFFSET_START);
ret = wait_for_completion_timeout(&i2c->msg_complete,
i2c->adap.timeout);
/* Clear interrupt mask */
- writew(~(restart_flag | I2C_HS_NACKERR | I2C_ACKERR |
- I2C_TRANSAC_COMP), i2c->base + OFFSET_INTR_MASK);
+ mtk_i2c_writew(i2c, ~(restart_flag | I2C_HS_NACKERR | I2C_ACKERR |
+ I2C_TRANSAC_COMP), OFFSET_INTR_MASK);
if (i2c->op == I2C_MASTER_WR) {
dma_unmap_single(i2c->dev, wpaddr,
@@ -724,8 +769,8 @@ static irqreturn_t mtk_i2c_irq(int irqno, void *dev_id)
if (i2c->auto_restart)
restart_flag = I2C_RS_TRANSFER;
- intr_stat = readw(i2c->base + OFFSET_INTR_STAT);
- writew(intr_stat, i2c->base + OFFSET_INTR_STAT);
+ intr_stat = mtk_i2c_readw(i2c, OFFSET_INTR_STAT);
+ mtk_i2c_writew(i2c, intr_stat, OFFSET_INTR_STAT);
/*
* when occurs ack error, i2c controller generate two interrupts
@@ -737,8 +782,8 @@ static irqreturn_t mtk_i2c_irq(int irqno, void *dev_id)
if (i2c->ignore_restart_irq && (i2c->irq_stat & restart_flag)) {
i2c->ignore_restart_irq = false;
i2c->irq_stat = 0;
- writew(I2C_RS_MUL_CNFG | I2C_RS_MUL_TRIG | I2C_TRANSAC_START,
- i2c->base + OFFSET_START);
+ mtk_i2c_writew(i2c, I2C_RS_MUL_CNFG | I2C_RS_MUL_TRIG |
+ I2C_TRANSAC_START, OFFSET_START);
} else {
if (i2c->irq_stat & (I2C_TRANSAC_COMP | restart_flag))
complete(&i2c->msg_complete);
--
1.7.9.5
Completion_done() is useless when we don't use its return value,
so we remove it.
Signed-off-by: qii wang <[email protected]>
---
drivers/i2c/busses/i2c-mt65xx.c | 2 --
1 file changed, 2 deletions(-)
diff --git a/drivers/i2c/busses/i2c-mt65xx.c b/drivers/i2c/busses/i2c-mt65xx.c
index 7396449..660de1e 100644
--- a/drivers/i2c/busses/i2c-mt65xx.c
+++ b/drivers/i2c/busses/i2c-mt65xx.c
@@ -642,8 +642,6 @@ static int mtk_i2c_do_transfer(struct mtk_i2c *i2c, struct i2c_msg *msgs,
return -ETIMEDOUT;
}
- completion_done(&i2c->msg_complete);
-
if (i2c->irq_stat & (I2C_HS_NACKERR | I2C_ACKERR)) {
dev_dbg(i2c->dev, "addr: %x, transfer ACK error\n", msgs->addr);
mtk_i2c_init_hw(i2c);
--
1.7.9.5
Different speeds have been defined by macros,
so we use macros definitions.
Signed-off-by: qii wang <[email protected]>
Reviewed-by: Nicolas Boichat <[email protected]>
---
drivers/i2c/busses/i2c-mt65xx.c | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/drivers/i2c/busses/i2c-mt65xx.c b/drivers/i2c/busses/i2c-mt65xx.c
index a74ef76..7396449 100644
--- a/drivers/i2c/busses/i2c-mt65xx.c
+++ b/drivers/i2c/busses/i2c-mt65xx.c
@@ -456,7 +456,7 @@ static int mtk_i2c_do_transfer(struct mtk_i2c *i2c, struct i2c_msg *msgs,
control_reg = readw(i2c->base + OFFSET_CONTROL) &
~(I2C_CONTROL_DIR_CHANGE | I2C_CONTROL_RS);
- if ((i2c->speed_hz > 400000) || (left_num >= 1))
+ if ((i2c->speed_hz > MAX_FS_MODE_SPEED) || (left_num >= 1))
control_reg |= I2C_CONTROL_RS;
if (i2c->op == I2C_MASTER_WRRD)
@@ -465,7 +465,7 @@ static int mtk_i2c_do_transfer(struct mtk_i2c *i2c, struct i2c_msg *msgs,
writew(control_reg, i2c->base + OFFSET_CONTROL);
/* set start condition */
- if (i2c->speed_hz <= 100000)
+ if (i2c->speed_hz <= I2C_DEFAULT_SPEED)
writew(I2C_ST_START_CON, i2c->base + OFFSET_EXT_CONF);
else
writew(I2C_FS_START_CON, i2c->base + OFFSET_EXT_CONF);
--
1.7.9.5
Add MT8183 i2c binding to binding file. Compare to 2712 i2c
controller, MT8183 has different registers, offsets, clock,
and share i3c controller.
Signed-off-by: qii wang <[email protected]>
Reviewed-by: Rob Herring <[email protected]>
---
Documentation/devicetree/bindings/i2c/i2c-mtk.txt | 6 ++++--
1 file changed, 4 insertions(+), 2 deletions(-)
diff --git a/Documentation/devicetree/bindings/i2c/i2c-mtk.txt b/Documentation/devicetree/bindings/i2c/i2c-mtk.txt
index ee4c324..0d29a5b 100644
--- a/Documentation/devicetree/bindings/i2c/i2c-mtk.txt
+++ b/Documentation/devicetree/bindings/i2c/i2c-mtk.txt
@@ -12,14 +12,15 @@ Required properties:
"mediatek,mt7623-i2c", "mediatek,mt6577-i2c": for MediaTek MT7623
"mediatek,mt7629-i2c", "mediatek,mt2712-i2c": for MediaTek MT7629
"mediatek,mt8173-i2c": for MediaTek MT8173
+ "mediatek,mt8183-i2c": for MediaTek MT8183
- reg: physical base address of the controller and dma base, length of memory
mapped region.
- interrupts: interrupt number to the cpu.
- clock-div: the fixed value for frequency divider of clock source in i2c
module. Each IC may be different.
- clocks: clock name from clock manager
- - clock-names: Must include "main" and "dma", if enable have-pmic need include
- "pmic" extra.
+ - clock-names: Must include "main" and "dma", "arb" is optional, if enable
+ have-pmic need include "pmic" extra.
Optional properties:
- clock-frequency: Frequency in Hz of the bus when transfer, the default value
@@ -27,6 +28,7 @@ Optional properties:
- mediatek,have-pmic: platform can control i2c form special pmic side.
Only mt6589 and mt8135 support this feature.
- mediatek,use-push-pull: IO config use push-pull mode.
+ - mediatek,share-i3c: i3c controller can share i2c function.
Example:
--
1.7.9.5
Add i2c compatible for MT8183. Compare to 2712 i2c controller, MT8183 has
different registers, offsets, clock, and share i3c controller.
Signed-off-by: qii wang <[email protected]>
---
drivers/i2c/busses/i2c-mt65xx.c | 127 ++++++++++++++++++++++++++++++++++++---
1 file changed, 120 insertions(+), 7 deletions(-)
diff --git a/drivers/i2c/busses/i2c-mt65xx.c b/drivers/i2c/busses/i2c-mt65xx.c
index 428ac99..19f0770 100644
--- a/drivers/i2c/busses/i2c-mt65xx.c
+++ b/drivers/i2c/busses/i2c-mt65xx.c
@@ -35,17 +35,21 @@
#include <linux/slab.h>
#define I2C_RS_TRANSFER (1 << 4)
+#define I2C_ARB_LOST (1 << 3)
#define I2C_HS_NACKERR (1 << 2)
#define I2C_ACKERR (1 << 1)
#define I2C_TRANSAC_COMP (1 << 0)
#define I2C_TRANSAC_START (1 << 0)
#define I2C_RS_MUL_CNFG (1 << 15)
#define I2C_RS_MUL_TRIG (1 << 14)
+#define I2C_HS_TIME_EN (1 << 7)
#define I2C_DCM_DISABLE 0x0000
#define I2C_IO_CONFIG_OPEN_DRAIN 0x0003
#define I2C_IO_CONFIG_PUSH_PULL 0x0000
#define I2C_SOFT_RST 0x0001
#define I2C_FIFO_ADDR_CLR 0x0001
+#define I2C_FIFO_ADDR_CLRH 0x0002
+#define I2C_HFIFO_DATA 0x8208
#define I2C_DELAY_LEN 0x0002
#define I2C_ST_START_CON 0x8001
#define I2C_FS_START_CON 0x1800
@@ -76,6 +80,8 @@
#define I2C_CONTROL_DIR_CHANGE (0x1 << 4)
#define I2C_CONTROL_ACKERR_DET_EN (0x1 << 5)
#define I2C_CONTROL_TRANSFER_LEN_CHANGE (0x1 << 6)
+#define I2C_CONTROL_DMAACK_EN (0x1 << 8)
+#define I2C_CONTROL_ASYNC_MODE (0x1 << 9)
#define I2C_CONTROL_WRAPPER (0x1 << 0)
#define I2C_DRV_NAME "i2c-mt65xx"
@@ -130,6 +136,15 @@ enum I2C_REGS_OFFSET {
OFFSET_DEBUGCTRL,
OFFSET_TRANSFER_LEN_AUX,
OFFSET_CLOCK_DIV,
+ /* MT8183 only regs */
+ OFFSET_LTIMING,
+ OFFSET_DATA_TIMING,
+ OFFSET_MCU_INTR,
+ OFFSET_HW_TIMEOUT,
+ OFFSET_HFIFO_DATA,
+ OFFSET_HFIFO_STAT,
+ OFFSET_MULTI_DMA,
+ OFFSET_ROLLBACK,
};
static const u16 mt_i2c_regs_v1[] = {
@@ -159,6 +174,39 @@ enum I2C_REGS_OFFSET {
[OFFSET_CLOCK_DIV] = 0x70,
};
+static const u16 mt_i2c_regs_v2[] = {
+ [OFFSET_DATA_PORT] = 0x0,
+ [OFFSET_SLAVE_ADDR] = 0x4,
+ [OFFSET_INTR_MASK] = 0x8,
+ [OFFSET_INTR_STAT] = 0xc,
+ [OFFSET_CONTROL] = 0x10,
+ [OFFSET_TRANSFER_LEN] = 0x14,
+ [OFFSET_TRANSAC_LEN] = 0x18,
+ [OFFSET_DELAY_LEN] = 0x1c,
+ [OFFSET_TIMING] = 0x20,
+ [OFFSET_START] = 0x24,
+ [OFFSET_EXT_CONF] = 0x28,
+ [OFFSET_LTIMING] = 0x2c,
+ [OFFSET_HS] = 0x30,
+ [OFFSET_IO_CONFIG] = 0x34,
+ [OFFSET_FIFO_ADDR_CLR] = 0x38,
+ [OFFSET_DATA_TIMING] = 0x3c,
+ [OFFSET_MCU_INTR] = 0x40,
+ [OFFSET_TRANSFER_LEN_AUX] = 0x44,
+ [OFFSET_CLOCK_DIV] = 0x48,
+ [OFFSET_HW_TIMEOUT] = 0x4c,
+ [OFFSET_SOFTRESET] = 0x50,
+ [OFFSET_HFIFO_DATA] = 0x70,
+ [OFFSET_DEBUGSTAT] = 0xe0,
+ [OFFSET_DEBUGCTRL] = 0xe8,
+ [OFFSET_FIFO_STAT] = 0xf4,
+ [OFFSET_FIFO_THRESH] = 0xf8,
+ [OFFSET_HFIFO_STAT] = 0xfc,
+ [OFFSET_DCM_EN] = 0xf88,
+ [OFFSET_MULTI_DMA] = 0xf8c,
+ [OFFSET_ROLLBACK] = 0xf98,
+};
+
struct mtk_i2c_compatible {
const struct i2c_adapter_quirks *quirks;
const u16 *regs;
@@ -168,6 +216,7 @@ struct mtk_i2c_compatible {
unsigned char aux_len_reg: 1;
unsigned char support_33bits: 1;
unsigned char timing_adjust: 1;
+ unsigned char dma_sync: 1;
};
struct mtk_i2c {
@@ -181,8 +230,10 @@ struct mtk_i2c {
struct clk *clk_main; /* main clock for i2c bus */
struct clk *clk_dma; /* DMA clock for i2c via DMA */
struct clk *clk_pmic; /* PMIC clock for i2c from PMIC */
+ struct clk *clk_arb; /* Arbitrator clock for i2c */
bool have_pmic; /* can use i2c pins from PMIC */
bool use_push_pull; /* IO config push-pull mode */
+ bool share_i3c; /* share i3c IP */
u16 irq_stat; /* interrupt status */
unsigned int clk_src_div;
@@ -190,6 +241,7 @@ struct mtk_i2c {
enum mtk_trans_op op;
u16 timing_reg;
u16 high_speed_reg;
+ u16 ltiming_reg;
unsigned char auto_restart;
bool ignore_restart_irq;
const struct mtk_i2c_compatible *dev_comp;
@@ -216,6 +268,7 @@ struct mtk_i2c {
.aux_len_reg = 1,
.support_33bits = 1,
.timing_adjust = 1,
+ .dma_sync = 0,
};
static const struct mtk_i2c_compatible mt6577_compat = {
@@ -227,6 +280,7 @@ struct mtk_i2c {
.aux_len_reg = 0,
.support_33bits = 0,
.timing_adjust = 0,
+ .dma_sync = 0,
};
static const struct mtk_i2c_compatible mt6589_compat = {
@@ -238,6 +292,7 @@ struct mtk_i2c {
.aux_len_reg = 0,
.support_33bits = 0,
.timing_adjust = 0,
+ .dma_sync = 0,
};
static const struct mtk_i2c_compatible mt7622_compat = {
@@ -249,6 +304,7 @@ struct mtk_i2c {
.aux_len_reg = 1,
.support_33bits = 0,
.timing_adjust = 0,
+ .dma_sync = 0,
};
static const struct mtk_i2c_compatible mt8173_compat = {
@@ -259,6 +315,18 @@ struct mtk_i2c {
.aux_len_reg = 1,
.support_33bits = 1,
.timing_adjust = 0,
+ .dma_sync = 0,
+};
+
+static const struct mtk_i2c_compatible mt8183_compat = {
+ .regs = mt_i2c_regs_v2,
+ .pmic_i2c = 0,
+ .dcm = 0,
+ .auto_restart = 1,
+ .aux_len_reg = 1,
+ .support_33bits = 1,
+ .timing_adjust = 1,
+ .dma_sync = 1,
};
static const struct of_device_id mtk_i2c_of_match[] = {
@@ -267,6 +335,7 @@ struct mtk_i2c {
{ .compatible = "mediatek,mt6589-i2c", .data = &mt6589_compat },
{ .compatible = "mediatek,mt7622-i2c", .data = &mt7622_compat },
{ .compatible = "mediatek,mt8173-i2c", .data = &mt8173_compat },
+ { .compatible = "mediatek,mt8183-i2c", .data = &mt8183_compat },
{}
};
MODULE_DEVICE_TABLE(of, mtk_i2c_of_match);
@@ -299,8 +368,18 @@ static int mtk_i2c_clock_enable(struct mtk_i2c *i2c)
if (ret)
goto err_pmic;
}
+
+ if (i2c->clk_arb) {
+ ret = clk_prepare_enable(i2c->clk_arb);
+ if (ret)
+ goto err_arb;
+ }
+
return 0;
+err_arb:
+ if (i2c->have_pmic)
+ clk_disable_unprepare(i2c->clk_pmic);
err_pmic:
clk_disable_unprepare(i2c->clk_main);
err_main:
@@ -311,6 +390,9 @@ static int mtk_i2c_clock_enable(struct mtk_i2c *i2c)
static void mtk_i2c_clock_disable(struct mtk_i2c *i2c)
{
+ if (i2c->clk_arb)
+ clk_disable_unprepare(i2c->clk_arb);
+
if (i2c->have_pmic)
clk_disable_unprepare(i2c->clk_pmic);
@@ -333,11 +415,19 @@ static void mtk_i2c_init_hw(struct mtk_i2c *i2c)
if (i2c->dev_comp->dcm)
mtk_i2c_writew(i2c, I2C_DCM_DISABLE, OFFSET_DCM_EN);
- if (i2c->dev_comp->timing_adjust)
+ if (i2c->dev_comp->timing_adjust && i2c->share_i3c) {
+ mtk_i2c_writew(i2c, (I2C_DEFAULT_CLK_DIV - 1) |
+ (I2C_DEFAULT_CLK_DIV - 1) << 8,
+ OFFSET_CLOCK_DIV);
+ i2c->high_speed_reg |= I2C_HS_TIME_EN;
+ } else {
mtk_i2c_writew(i2c, I2C_DEFAULT_CLK_DIV - 1, OFFSET_CLOCK_DIV);
+ }
mtk_i2c_writew(i2c, i2c->timing_reg, OFFSET_TIMING);
mtk_i2c_writew(i2c, i2c->high_speed_reg, OFFSET_HS);
+ if (i2c->dev_comp->regs == mt_i2c_regs_v2)
+ mtk_i2c_writew(i2c, i2c->ltiming_reg, OFFSET_LTIMING);
/* If use i2c pin from PMIC mt6397 side, need set PATH_DIR first */
if (i2c->have_pmic)
@@ -345,6 +435,9 @@ static void mtk_i2c_init_hw(struct mtk_i2c *i2c)
control_reg = I2C_CONTROL_ACKERR_DET_EN |
I2C_CONTROL_CLK_EXT_EN | I2C_CONTROL_DMA_EN;
+ if (i2c->dev_comp->dma_sync)
+ control_reg |= I2C_CONTROL_DMAACK_EN | I2C_CONTROL_ASYNC_MODE;
+
mtk_i2c_writew(i2c, control_reg, OFFSET_CONTROL);
mtk_i2c_writew(i2c, I2C_DELAY_LEN, OFFSET_DELAY_LEN);
@@ -434,6 +527,8 @@ static int mtk_i2c_set_speed(struct mtk_i2c *i2c, unsigned int parent_clk)
unsigned int clk_src;
unsigned int step_cnt;
unsigned int sample_cnt;
+ unsigned int l_step_cnt;
+ unsigned int l_sample_cnt;
unsigned int target_speed;
int ret;
@@ -443,11 +538,11 @@ static int mtk_i2c_set_speed(struct mtk_i2c *i2c, unsigned int parent_clk)
if (target_speed > MAX_FS_MODE_SPEED) {
/* Set master code speed register */
ret = mtk_i2c_calculate_speed(i2c, clk_src, MAX_FS_MODE_SPEED,
- &step_cnt, &sample_cnt);
+ &l_step_cnt, &l_sample_cnt);
if (ret < 0)
return ret;
- i2c->timing_reg = (sample_cnt << 8) | step_cnt;
+ i2c->timing_reg = (l_sample_cnt << 8) | l_step_cnt;
/* Set the high speed mode register */
ret = mtk_i2c_calculate_speed(i2c, clk_src, target_speed,
@@ -457,6 +552,8 @@ static int mtk_i2c_set_speed(struct mtk_i2c *i2c, unsigned int parent_clk)
i2c->high_speed_reg = I2C_TIME_DEFAULT_VALUE |
(sample_cnt << 12) | (step_cnt << 8);
+ i2c->ltiming_reg = (l_sample_cnt << 6) | l_step_cnt |
+ (sample_cnt << 12) | (step_cnt << 9);
} else {
ret = mtk_i2c_calculate_speed(i2c, clk_src, target_speed,
&step_cnt, &sample_cnt);
@@ -467,6 +564,8 @@ static int mtk_i2c_set_speed(struct mtk_i2c *i2c, unsigned int parent_clk)
/* Disable the high speed transaction */
i2c->high_speed_reg = I2C_TIME_CLR_VALUE;
+
+ i2c->ltiming_reg = (sample_cnt << 6) | step_cnt;
}
return 0;
@@ -483,6 +582,7 @@ static int mtk_i2c_do_transfer(struct mtk_i2c *i2c, struct i2c_msg *msgs,
u16 addr_reg;
u16 start_reg;
u16 control_reg;
+ u16 fifo_clr_reg = I2C_FIFO_ADDR_CLR;
u16 restart_flag = 0;
u32 reg_4g_mode;
u8 *dma_rd_buf = NULL;
@@ -519,13 +619,21 @@ static int mtk_i2c_do_transfer(struct mtk_i2c *i2c, struct i2c_msg *msgs,
/* Clear interrupt status */
mtk_i2c_writew(i2c, restart_flag | I2C_HS_NACKERR | I2C_ACKERR |
- I2C_TRANSAC_COMP, OFFSET_INTR_STAT);
+ I2C_ARB_LOST | I2C_TRANSAC_COMP,
+ OFFSET_INTR_STAT);
+
+ if (i2c->share_i3c)
+ fifo_clr_reg |= I2C_FIFO_ADDR_CLRH;
- mtk_i2c_writew(i2c, I2C_FIFO_ADDR_CLR, OFFSET_FIFO_ADDR_CLR);
+ mtk_i2c_writew(i2c, fifo_clr_reg, OFFSET_FIFO_ADDR_CLR);
+
+ if ((i2c->speed_hz > MAX_FS_MODE_SPEED) && i2c->share_i3c)
+ mtk_i2c_writew(i2c, I2C_HFIFO_DATA, OFFSET_HFIFO_DATA);
/* Enable interrupt */
mtk_i2c_writew(i2c, restart_flag | I2C_HS_NACKERR | I2C_ACKERR |
- I2C_TRANSAC_COMP, OFFSET_INTR_MASK);
+ I2C_ARB_LOST | I2C_TRANSAC_COMP,
+ OFFSET_INTR_MASK);
/* Set transfer and transaction len */
if (i2c->op == I2C_MASTER_WRRD) {
@@ -659,7 +767,7 @@ static int mtk_i2c_do_transfer(struct mtk_i2c *i2c, struct i2c_msg *msgs,
/* Clear interrupt mask */
mtk_i2c_writew(i2c, ~(restart_flag | I2C_HS_NACKERR | I2C_ACKERR |
- I2C_TRANSAC_COMP), OFFSET_INTR_MASK);
+ I2C_ARB_LOST | I2C_TRANSAC_COMP), OFFSET_INTR_MASK);
if (i2c->op == I2C_MASTER_WR) {
dma_unmap_single(i2c->dev, wpaddr,
@@ -817,6 +925,7 @@ static int mtk_i2c_parse_dt(struct device_node *np, struct mtk_i2c *i2c)
if (i2c->clk_src_div == 0)
return -EINVAL;
+ i2c->share_i3c = of_property_read_bool(np, "mediatek,share-i3c");
i2c->have_pmic = of_property_read_bool(np, "mediatek,have-pmic");
i2c->use_push_pull =
of_property_read_bool(np, "mediatek,use-push-pull");
@@ -884,6 +993,10 @@ static int mtk_i2c_probe(struct platform_device *pdev)
return PTR_ERR(i2c->clk_dma);
}
+ i2c->clk_arb = devm_clk_get(&pdev->dev, "arb");
+ if (IS_ERR(i2c->clk_arb))
+ i2c->clk_arb = NULL;
+
clk = i2c->clk_main;
if (i2c->have_pmic) {
i2c->clk_pmic = devm_clk_get(&pdev->dev, "pmic");
--
1.7.9.5
Add MT7629 i2c binding to binding file.
Signed-off-by: qii wang <[email protected]>
Reviewed-by: Rob Herring <[email protected]>
---
Documentation/devicetree/bindings/i2c/i2c-mtk.txt | 1 +
1 file changed, 1 insertion(+)
diff --git a/Documentation/devicetree/bindings/i2c/i2c-mtk.txt b/Documentation/devicetree/bindings/i2c/i2c-mtk.txt
index e199695..ee4c324 100644
--- a/Documentation/devicetree/bindings/i2c/i2c-mtk.txt
+++ b/Documentation/devicetree/bindings/i2c/i2c-mtk.txt
@@ -10,6 +10,7 @@ Required properties:
"mediatek,mt6589-i2c": for MediaTek MT6589
"mediatek,mt7622-i2c": for MediaTek MT7622
"mediatek,mt7623-i2c", "mediatek,mt6577-i2c": for MediaTek MT7623
+ "mediatek,mt7629-i2c", "mediatek,mt2712-i2c": for MediaTek MT7629
"mediatek,mt8173-i2c": for MediaTek MT8173
- reg: physical base address of the controller and dma base, length of memory
mapped region.
--
1.7.9.5
On Mon, Jan 21, 2019 at 03:59:29PM +0800, qii wang wrote:
> Add MT7629 i2c binding to binding file.
>
> Signed-off-by: qii wang <[email protected]>
> Reviewed-by: Rob Herring <[email protected]>
Applied to for-next, thanks!
On Mon, Jan 21, 2019 at 03:59:30PM +0800, qii wang wrote:
> Different speeds have been defined by macros,
> so we use macros definitions.
>
> Signed-off-by: qii wang <[email protected]>
> Reviewed-by: Nicolas Boichat <[email protected]>
Applied to for-next, thanks!
On Mon, Jan 21, 2019 at 03:59:31PM +0800, qii wang wrote:
> Completion_done() is useless when we don't use its return value,
> so we remove it.
>
> Signed-off-by: qii wang <[email protected]>
Applied to for-next, thanks!
> + - mediatek,share-i3c: i3c controller can share i2c function.
I am not happy with this binding. There must be a better way of using
the I3C controller in I2C mode. I think it would be easier to tell if we
had an I3C driver to see how it implements I2C fallback there. Is the
I3C driver on the way?
On Tue, 2019-02-05 at 14:16 +0100, Wolfram Sang wrote:
> > + - mediatek,share-i3c: i3c controller can share i2c function.
>
> I am not happy with this binding. There must be a better way of using
> the I3C controller in I2C mode. I think it would be easier to tell if we
> had an I3C driver to see how it implements I2C fallback there. Is the
> I3C driver on the way?
>
I am very sorry for the late reply due to the Chinese New Year holiday.
After confirmation, for I2C mode in I3C controller, we will push an I3C
driver to implement I2C fallback there later, and we will remove
"mediatek,share-i3c" for i2c controller driver in the next patch.
On Thu, Feb 14, 2019 at 09:54:28AM +0800, Qii Wang wrote:
> On Tue, 2019-02-05 at 14:16 +0100, Wolfram Sang wrote:
> > > + - mediatek,share-i3c: i3c controller can share i2c function.
> >
> > I am not happy with this binding. There must be a better way of using
> > the I3C controller in I2C mode. I think it would be easier to tell if we
> > had an I3C driver to see how it implements I2C fallback there. Is the
> > I3C driver on the way?
> >
>
> I am very sorry for the late reply due to the Chinese New Year holiday.
No worries. I hope you enjoyed the holidays!
> After confirmation, for I2C mode in I3C controller, we will push an I3C
> driver to implement I2C fallback there later, and we will remove
> "mediatek,share-i3c" for i2c controller driver in the next patch.
The problem with DT bindings is that you need to support them forever
once you introduced them. Because there might be old device trees on
boards out there which need the property. So, I don't like the idea of
having a temporary binding which is meant to be removed anyway. My take
is that you should just send out the I3C driver which will handle the
I2C support then.
Adding Rob to CC in case he has a different opinion.
On Fri, 2019-02-15 at 10:02 +0100, Wolfram Sang wrote:
> On Thu, Feb 14, 2019 at 09:54:28AM +0800, Qii Wang wrote:
> > On Tue, 2019-02-05 at 14:16 +0100, Wolfram Sang wrote:
> > > > + - mediatek,share-i3c: i3c controller can share i2c function.
> > >
> > > I am not happy with this binding. There must be a better way of using
> > > the I3C controller in I2C mode. I think it would be easier to tell if we
> > > had an I3C driver to see how it implements I2C fallback there. Is the
> > > I3C driver on the way?
> > >
> >
> > I am very sorry for the late reply due to the Chinese New Year holiday.
>
> No worries. I hope you enjoyed the holidays!
>
> > After confirmation, for I2C mode in I3C controller, we will push an I3C
> > driver to implement I2C fallback there later, and we will remove
> > "mediatek,share-i3c" for i2c controller driver in the next patch.
>
> The problem with DT bindings is that you need to support them forever
> once you introduced them. Because there might be old device trees on
> boards out there which need the property. So, I don't like the idea of
> having a temporary binding which is meant to be removed anyway. My take
> is that you should just send out the I3C driver which will handle the
> I2C support then.
>
> Adding Rob to CC in case he has a different opinion.
>
Maybe you think that MT8183 SoC only has the I3C controllers. Actually,
there are I2C and I3C controllers on MT8183 SoC. We will remove
"mediatek,share-i3c" for I2C controller driver, so these patches are
just to support the I2C controllers on MT8183 SoC. For the I3C
controller we will send some new patches which are based on i3c
framework directories(kernel/drivers/i3c), not based on
i2c-mt65xx.c.
> Maybe you think that MT8183 SoC only has the I3C controllers. Actually,
> there are I2C and I3C controllers on MT8183 SoC. We will remove
> "mediatek,share-i3c" for I2C controller driver, so these patches are
> just to support the I2C controllers on MT8183 SoC. For the I3C
> controller we will send some new patches which are based on i3c
> framework directories(kernel/drivers/i3c), not based on
> i2c-mt65xx.c.
Sounds perfect to me. If it turns out that the I3C driver can share
things with the I2C driver, we can discuss it then. But unless we have
an I3C driver and know for sure, the above strategy seems good to me.
On Sat, 2019-02-16 at 13:29 +0100, Wolfram Sang wrote:
> > Maybe you think that MT8183 SoC only has the I3C controllers. Actually,
> > there are I2C and I3C controllers on MT8183 SoC. We will remove
> > "mediatek,share-i3c" for I2C controller driver, so these patches are
> > just to support the I2C controllers on MT8183 SoC. For the I3C
> > controller we will send some new patches which are based on i3c
> > framework directories(kernel/drivers/i3c), not based on
> > i2c-mt65xx.c.
>
> Sounds perfect to me. If it turns out that the I3C driver can share
> things with the I2C driver, we can discuss it then. But unless we have
> an I3C driver and know for sure, the above strategy seems good to me.
>
Can I push the V4 patches of I2C controller driver now? or you just want
an I3C driver that is compatible with the I2C controller?
According to our plan, I2C controller will use
i2c-mt65xx.c(kernel/drivers/i2c/busses/)and I3C controller will use
i3c-xxx.c(kernel/drivers/i3c/master/)
> > > Maybe you think that MT8183 SoC only has the I3C controllers. Actually,
> > > there are I2C and I3C controllers on MT8183 SoC. We will remove
> > > "mediatek,share-i3c" for I2C controller driver, so these patches are
> > > just to support the I2C controllers on MT8183 SoC. For the I3C
> > > controller we will send some new patches which are based on i3c
> > > framework directories(kernel/drivers/i3c), not based on
> > > i2c-mt65xx.c.
> >
> > Sounds perfect to me. If it turns out that the I3C driver can share
> > things with the I2C driver, we can discuss it then. But unless we have
> > an I3C driver and know for sure, the above strategy seems good to me.
> >
>
> Can I push the V4 patches of I2C controller driver now? or you just want
> an I3C driver that is compatible with the I2C controller?
If the V4 series does not use the "mediatek,share-i3c" binding anymore,
please resend it. From what I recall, it should be OK then.
> According to our plan, I2C controller will use
> i2c-mt65xx.c(kernel/drivers/i2c/busses/)and I3C controller will use
> i3c-xxx.c(kernel/drivers/i3c/master/)
Sounds OK from what I understood. The I2C fallback from I3C will be
interesting.