Skip to content

Commit a06b80e

Browse files
Hans HuAndi Shyti
authored andcommitted
i2c: add zhaoxin i2c controller driver
Add Zhaoxin I2C controller driver. It provides the access to the i2c busses, which connects to the touchpad, eeprom, I2S, etc. Zhaoxin I2C controller has two separate busses, so may accommodate up to two I2C adapters. Those adapters are listed in the ACPI namespace with the IIC1D17 HID, and probed by a platform driver. The driver works with IRQ mode, and supports basic I2C features. Flags I2C_AQ_NO_ZERO_LEN and I2C_AQ_COMB_WRITE_THEN_READ are used to limit the unsupported access. Acked-by: Wolfram Sang <wsa+renesas@sang-engineering.com> Signed-off-by: Hans Hu <hanshu-oc@zhaoxin.com> Signed-off-by: Andi Shyti <andi.shyti@kernel.org>
1 parent b06204c commit a06b80e

6 files changed

Lines changed: 353 additions & 5 deletions

File tree

MAINTAINERS

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10258,6 +10258,14 @@ L: linux-i2c@vger.kernel.org
1025810258
F: Documentation/i2c/busses/i2c-ismt.rst
1025910259
F: drivers/i2c/busses/i2c-ismt.c
1026010260

10261+
I2C/SMBUS ZHAOXIN DRIVER
10262+
M: Hans Hu <hanshu@zhaoxin.com>
10263+
L: linux-i2c@vger.kernel.org
10264+
S: Maintained
10265+
W: https://www.zhaoxin.com
10266+
F: drivers/i2c/busses/i2c-viai2c-common.c
10267+
F: drivers/i2c/busses/i2c-viai2c-zhaoxin.c
10268+
1026110269
I2C/SMBUS STUB DRIVER
1026210270
M: Jean Delvare <jdelvare@suse.com>
1026310271
L: linux-i2c@vger.kernel.org

drivers/i2c/busses/Kconfig

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -344,6 +344,16 @@ config I2C_VIAPRO
344344

345345
if ACPI
346346

347+
config I2C_ZHAOXIN
348+
tristate "Zhaoxin I2C Interface"
349+
depends on PCI || COMPILE_TEST
350+
help
351+
If you say yes to this option, support will be included for the
352+
ZHAOXIN I2C interface
353+
354+
This driver can also be built as a module. If so, the module
355+
will be called i2c-zhaoxin.
356+
347357
comment "ACPI drivers"
348358

349359
config I2C_SCMI

drivers/i2c/busses/Makefile

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,8 @@ obj-$(CONFIG_I2C_SIS630) += i2c-sis630.o
2929
obj-$(CONFIG_I2C_SIS96X) += i2c-sis96x.o
3030
obj-$(CONFIG_I2C_VIA) += i2c-via.o
3131
obj-$(CONFIG_I2C_VIAPRO) += i2c-viapro.o
32+
i2c-zhaoxin-objs := i2c-viai2c-zhaoxin.o i2c-viai2c-common.o
33+
obj-$(CONFIG_I2C_ZHAOXIN) += i2c-zhaoxin.o
3234

3335
# Mac SMBus host controller drivers
3436
obj-$(CONFIG_I2C_HYDRA) += i2c-hydra.o

drivers/i2c/busses/i2c-viai2c-common.c

Lines changed: 26 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -60,7 +60,7 @@ static int viai2c_write(struct viai2c *i2c, struct i2c_msg *pmsg, int last)
6060
return i2c->ret;
6161
}
6262

63-
static int viai2c_read(struct viai2c *i2c, struct i2c_msg *pmsg)
63+
static int viai2c_read(struct viai2c *i2c, struct i2c_msg *pmsg, bool first)
6464
{
6565
u16 val, tcr_val = i2c->tcr;
6666

@@ -81,7 +81,8 @@ static int viai2c_read(struct viai2c *i2c, struct i2c_msg *pmsg)
8181

8282
writew(tcr_val, i2c->base + VIAI2C_REG_TCR);
8383

84-
if (i2c->platform == VIAI2C_PLAT_WMT && (pmsg->flags & I2C_M_NOSTART)) {
84+
if ((i2c->platform == VIAI2C_PLAT_WMT && (pmsg->flags & I2C_M_NOSTART)) ||
85+
(i2c->platform == VIAI2C_PLAT_ZHAOXIN && !first)) {
8586
val = readw(i2c->base + VIAI2C_REG_CR);
8687
val |= VIAI2C_CR_CPU_RDY;
8788
writew(val, i2c->base + VIAI2C_REG_CR);
@@ -100,6 +101,7 @@ int viai2c_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[], int num)
100101
int ret = 0;
101102
struct viai2c *i2c = i2c_get_adapdata(adap);
102103

104+
i2c->mode = VIAI2C_BYTE_MODE;
103105
for (i = 0; ret >= 0 && i < num; i++) {
104106
pmsg = &msgs[i];
105107
if (i2c->platform == VIAI2C_PLAT_WMT && !(pmsg->flags & I2C_M_NOSTART)) {
@@ -112,7 +114,7 @@ int viai2c_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[], int num)
112114
i2c->xfered_len = 0;
113115

114116
if (pmsg->flags & I2C_M_RD)
115-
ret = viai2c_read(i2c, pmsg);
117+
ret = viai2c_read(i2c, pmsg, i == 0);
116118
else
117119
ret = viai2c_write(i2c, pmsg, (i + 1) == num);
118120
}
@@ -157,6 +159,8 @@ static int viai2c_irq_xfer(struct viai2c *i2c)
157159
if ((i2c->xfered_len + 1) == msg->len) {
158160
if (i2c->platform == VIAI2C_PLAT_WMT && !i2c->last)
159161
writew(VIAI2C_CR_ENABLE, base + VIAI2C_REG_CR);
162+
else if (i2c->platform == VIAI2C_PLAT_ZHAOXIN && i2c->last)
163+
writeb(VIAI2C_CR_TX_END, base + VIAI2C_REG_CR);
160164
} else {
161165
writew(msg->buf[i2c->xfered_len + 1] & 0xFF, base + VIAI2C_REG_CDR);
162166
writew(VIAI2C_CR_CPU_RDY | VIAI2C_CR_ENABLE, base + VIAI2C_REG_CR);
@@ -168,13 +172,21 @@ static int viai2c_irq_xfer(struct viai2c *i2c)
168172
return i2c->xfered_len == msg->len;
169173
}
170174

175+
int __weak viai2c_fifo_irq_xfer(struct viai2c *i2c, bool irq)
176+
{
177+
return 0;
178+
}
179+
171180
static irqreturn_t viai2c_isr(int irq, void *data)
172181
{
173182
struct viai2c *i2c = data;
174183
u8 status;
175184

176185
/* save the status and write-clear it */
177186
status = readw(i2c->base + VIAI2C_REG_ISR);
187+
if (!status && i2c->platform == VIAI2C_PLAT_ZHAOXIN)
188+
return IRQ_NONE;
189+
178190
writew(status, i2c->base + VIAI2C_REG_ISR);
179191

180192
i2c->ret = 0;
@@ -184,8 +196,12 @@ static irqreturn_t viai2c_isr(int irq, void *data)
184196
if (i2c->platform == VIAI2C_PLAT_WMT && (status & VIAI2C_ISR_SCL_TIMEOUT))
185197
i2c->ret = -ETIMEDOUT;
186198

187-
if (!i2c->ret)
188-
i2c->ret = viai2c_irq_xfer(i2c);
199+
if (!i2c->ret) {
200+
if (i2c->mode == VIAI2C_BYTE_MODE)
201+
i2c->ret = viai2c_irq_xfer(i2c);
202+
else
203+
i2c->ret = viai2c_fifo_irq_xfer(i2c, true);
204+
}
189205

190206
/* All the data has been successfully transferred or error occurred */
191207
if (i2c->ret)
@@ -214,6 +230,11 @@ int viai2c_init(struct platform_device *pdev, struct viai2c **pi2c, int plat)
214230
i2c->irq = irq_of_parse_and_map(np, 0);
215231
if (!i2c->irq)
216232
return -EINVAL;
233+
} else if (plat == VIAI2C_PLAT_ZHAOXIN) {
234+
irq_flags = IRQF_SHARED;
235+
i2c->irq = platform_get_irq(pdev, 0);
236+
if (i2c->irq < 0)
237+
return i2c->irq;
217238
} else {
218239
return dev_err_probe(&pdev->dev, -EINVAL, "wrong platform type\n");
219240
}

drivers/i2c/busses/i2c-viai2c-common.h

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,12 @@
5252

5353
enum {
5454
VIAI2C_PLAT_WMT,
55+
VIAI2C_PLAT_ZHAOXIN
56+
};
57+
58+
enum {
59+
VIAI2C_BYTE_MODE,
60+
VIAI2C_FIFO_MODE
5561
};
5662

5763
struct viai2c {
@@ -66,11 +72,14 @@ struct viai2c {
6672
struct i2c_msg *msg;
6773
int ret;
6874
bool last;
75+
unsigned int mode;
6976
unsigned int platform;
77+
void *pltfm_priv;
7078
};
7179

7280
int viai2c_wait_bus_not_busy(struct viai2c *i2c);
7381
int viai2c_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[], int num);
7482
int viai2c_init(struct platform_device *pdev, struct viai2c **pi2c, int plat);
83+
int viai2c_fifo_irq_xfer(struct viai2c *i2c, bool irq);
7584

7685
#endif

0 commit comments

Comments
 (0)