1 // SPDX-License-Identifier: GPL-2.0-or-later
2 #include <linux/of_irq.h>
3 #include "i2c-viai2c-common.h"
5 int viai2c_wait_bus_not_busy(struct viai2c
*i2c
)
9 timeout
= jiffies
+ VIAI2C_TIMEOUT
;
10 while (!(readw(i2c
->base
+ VIAI2C_REG_CSR
) & VIAI2C_CSR_READY_MASK
)) {
11 if (time_after(jiffies
, timeout
)) {
12 dev_warn(i2c
->dev
, "timeout waiting for bus ready\n");
20 EXPORT_SYMBOL_GPL(viai2c_wait_bus_not_busy
);
22 static int viai2c_write(struct viai2c
*i2c
, struct i2c_msg
*pmsg
, int last
)
24 u16 val
, tcr_val
= i2c
->tcr
;
30 * We still need to run through the while (..) once, so
31 * start at -1 and break out early from the loop
34 writew(0, i2c
->base
+ VIAI2C_REG_CDR
);
36 writew(pmsg
->buf
[0] & 0xFF, i2c
->base
+ VIAI2C_REG_CDR
);
39 if (i2c
->platform
== VIAI2C_PLAT_WMT
&& !(pmsg
->flags
& I2C_M_NOSTART
)) {
40 val
= readw(i2c
->base
+ VIAI2C_REG_CR
);
41 val
&= ~VIAI2C_CR_TX_END
;
42 val
|= VIAI2C_CR_CPU_RDY
;
43 writew(val
, i2c
->base
+ VIAI2C_REG_CR
);
46 reinit_completion(&i2c
->complete
);
48 tcr_val
|= pmsg
->addr
& VIAI2C_TCR_ADDR_MASK
;
50 writew(tcr_val
, i2c
->base
+ VIAI2C_REG_TCR
);
52 if (i2c
->platform
== VIAI2C_PLAT_WMT
&& pmsg
->flags
& I2C_M_NOSTART
) {
53 val
= readw(i2c
->base
+ VIAI2C_REG_CR
);
54 val
|= VIAI2C_CR_CPU_RDY
;
55 writew(val
, i2c
->base
+ VIAI2C_REG_CR
);
58 if (!wait_for_completion_timeout(&i2c
->complete
, VIAI2C_TIMEOUT
))
64 static int viai2c_read(struct viai2c
*i2c
, struct i2c_msg
*pmsg
, bool first
)
66 u16 val
, tcr_val
= i2c
->tcr
;
68 val
= readw(i2c
->base
+ VIAI2C_REG_CR
);
69 val
&= ~(VIAI2C_CR_TX_END
| VIAI2C_CR_RX_END
);
71 if (i2c
->platform
== VIAI2C_PLAT_WMT
&& !(pmsg
->flags
& I2C_M_NOSTART
))
72 val
|= VIAI2C_CR_CPU_RDY
;
75 val
|= VIAI2C_CR_RX_END
;
77 writew(val
, i2c
->base
+ VIAI2C_REG_CR
);
79 reinit_completion(&i2c
->complete
);
81 tcr_val
|= VIAI2C_TCR_READ
| (pmsg
->addr
& VIAI2C_TCR_ADDR_MASK
);
83 writew(tcr_val
, i2c
->base
+ VIAI2C_REG_TCR
);
85 if ((i2c
->platform
== VIAI2C_PLAT_WMT
&& (pmsg
->flags
& I2C_M_NOSTART
)) ||
86 (i2c
->platform
== VIAI2C_PLAT_ZHAOXIN
&& !first
)) {
87 val
= readw(i2c
->base
+ VIAI2C_REG_CR
);
88 val
|= VIAI2C_CR_CPU_RDY
;
89 writew(val
, i2c
->base
+ VIAI2C_REG_CR
);
92 if (!wait_for_completion_timeout(&i2c
->complete
, VIAI2C_TIMEOUT
))
98 int viai2c_xfer(struct i2c_adapter
*adap
, struct i2c_msg msgs
[], int num
)
100 struct i2c_msg
*pmsg
;
103 struct viai2c
*i2c
= i2c_get_adapdata(adap
);
105 i2c
->mode
= VIAI2C_BYTE_MODE
;
106 for (i
= 0; ret
>= 0 && i
< num
; i
++) {
108 if (i2c
->platform
== VIAI2C_PLAT_WMT
&& !(pmsg
->flags
& I2C_M_NOSTART
)) {
109 ret
= viai2c_wait_bus_not_busy(i2c
);
117 if (pmsg
->flags
& I2C_M_RD
)
118 ret
= viai2c_read(i2c
, pmsg
, i
== 0);
120 ret
= viai2c_write(i2c
, pmsg
, (i
+ 1) == num
);
123 return (ret
< 0) ? ret
: i
;
125 EXPORT_SYMBOL_GPL(viai2c_xfer
);
128 * Main process of the byte mode xfer
130 * Return value indicates whether the transfer is complete
131 * 1: all the data has been successfully transferred
132 * 0: there is still data that needs to be transferred
133 * -EIO: error occurred
135 int viai2c_irq_xfer(struct viai2c
*i2c
)
138 struct i2c_msg
*msg
= i2c
->msg
;
139 u8 read
= msg
->flags
& I2C_M_RD
;
140 void __iomem
*base
= i2c
->base
;
143 msg
->buf
[i2c
->xfered_len
] = readw(base
+ VIAI2C_REG_CDR
) >> 8;
145 val
= readw(base
+ VIAI2C_REG_CR
) | VIAI2C_CR_CPU_RDY
;
146 if (i2c
->xfered_len
== msg
->len
- 2)
147 val
|= VIAI2C_CR_RX_END
;
148 writew(val
, base
+ VIAI2C_REG_CR
);
150 val
= readw(base
+ VIAI2C_REG_CSR
);
151 if (val
& VIAI2C_CSR_RCV_NOT_ACK
)
154 /* I2C_SMBUS_QUICK */
156 val
= VIAI2C_CR_TX_END
| VIAI2C_CR_CPU_RDY
| VIAI2C_CR_ENABLE
;
157 writew(val
, base
+ VIAI2C_REG_CR
);
161 if ((i2c
->xfered_len
+ 1) == msg
->len
) {
162 if (i2c
->platform
== VIAI2C_PLAT_WMT
&& !i2c
->last
)
163 writew(VIAI2C_CR_ENABLE
, base
+ VIAI2C_REG_CR
);
164 else if (i2c
->platform
== VIAI2C_PLAT_ZHAOXIN
&& i2c
->last
)
165 writeb(VIAI2C_CR_TX_END
, base
+ VIAI2C_REG_CR
);
167 writew(msg
->buf
[i2c
->xfered_len
+ 1] & 0xFF, base
+ VIAI2C_REG_CDR
);
168 writew(VIAI2C_CR_CPU_RDY
| VIAI2C_CR_ENABLE
, base
+ VIAI2C_REG_CR
);
174 return i2c
->xfered_len
== msg
->len
;
176 EXPORT_SYMBOL_GPL(viai2c_irq_xfer
);
178 int viai2c_init(struct platform_device
*pdev
, struct viai2c
**pi2c
, int plat
)
182 i2c
= devm_kzalloc(&pdev
->dev
, sizeof(*i2c
), GFP_KERNEL
);
186 i2c
->base
= devm_platform_get_and_ioremap_resource(pdev
, 0, NULL
);
187 if (IS_ERR(i2c
->base
))
188 return PTR_ERR(i2c
->base
);
190 i2c
->platform
= plat
;
192 i2c
->dev
= &pdev
->dev
;
193 init_completion(&i2c
->complete
);
194 platform_set_drvdata(pdev
, i2c
);
199 EXPORT_SYMBOL_GPL(viai2c_init
);
201 MODULE_DESCRIPTION("Via/Wondermedia/Zhaoxin I2C controller core");
202 MODULE_AUTHOR("Tony Prisk <linux@prisktech.co.nz>");
203 MODULE_LICENSE("GPL");