1 /* $OpenBSD: imxiic.c,v 1.2 2024/04/14 03:26:25 jsg Exp $ */
2 /*
3 * Copyright (c) 2013 Patrick Wildt <patrick@blueri.se>
4 *
5 * Permission to use, copy, modify, and distribute this software for any
6 * purpose with or without fee is hereby granted, provided that the above
7 * copyright notice and this permission notice appear in all copies.
8 *
9 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
10 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
11 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
12 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
13 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
14 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
15 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
16 */
17
18 #include <sys/param.h>
19 #include <sys/device.h>
20 #include <sys/kernel.h>
21 #include <sys/systm.h>
22
23 #include <machine/bus.h>
24
25 #include <dev/ic/imxiicvar.h>
26
27 /* registers */
28 #define I2C_IADR 0x00
29 #define I2C_IFDR 0x01
30 #define I2C_I2CR 0x02
31 #define I2C_I2SR 0x03
32 #define I2C_I2DR 0x04
33
34 #define I2C_I2CR_RSTA (1 << 2)
35 #define I2C_I2CR_TXAK (1 << 3)
36 #define I2C_I2CR_MTX (1 << 4)
37 #define I2C_I2CR_MSTA (1 << 5)
38 #define I2C_I2CR_IIEN (1 << 6)
39 #define I2C_I2CR_IEN (1 << 7)
40 #define I2C_I2SR_RXAK (1 << 0)
41 #define I2C_I2SR_IIF (1 << 1)
42 #define I2C_I2SR_IAL (1 << 4)
43 #define I2C_I2SR_IBB (1 << 5)
44
45 void imxiic_enable(struct imxiic_softc *, int);
46 void imxiic_clear_iodone(struct imxiic_softc *);
47 void imxiic_setspeed(struct imxiic_softc *, u_int);
48 int imxiic_wait_state(struct imxiic_softc *, uint32_t, uint32_t);
49 int imxiic_read(struct imxiic_softc *, int, const void *, int,
50 void *, int);
51 int imxiic_write(struct imxiic_softc *, int, const void *, int,
52 const void *, int);
53
54 int imxiic_i2c_acquire_bus(void *, int);
55 void imxiic_i2c_release_bus(void *, int);
56 int imxiic_i2c_exec(void *, i2c_op_t, i2c_addr_t, const void *, size_t,
57 void *, size_t, int);
58
59 uint8_t imxiic_read_1(struct imxiic_softc *, int);
60 void imxiic_write_1(struct imxiic_softc *, int, uint8_t);
61
62 #define HREAD1(sc, reg) \
63 imxiic_read_1((sc), (reg))
64 #define HWRITE1(sc, reg, val) \
65 imxiic_write_1((sc), (reg), (val))
66 #define HSET1(sc, reg, bits) \
67 HWRITE1((sc), (reg), HREAD1((sc), (reg)) | (bits))
68 #define HCLR1(sc, reg, bits) \
69 HWRITE1((sc), (reg), HREAD1((sc), (reg)) & ~(bits))
70
71 struct cfdriver imxiic_cd = {
72 NULL, "imxiic", DV_DULL
73 };
74
75 void
imxiic_enable(struct imxiic_softc * sc,int on)76 imxiic_enable(struct imxiic_softc *sc, int on)
77 {
78 /*
79 * VF610: write 1 to clear bits
80 * iMX21: write 0 to clear bits
81 */
82 if (sc->sc_type == I2C_TYPE_VF610)
83 HWRITE1(sc, I2C_I2SR, I2C_I2SR_IAL | I2C_I2SR_IIF);
84 else
85 HWRITE1(sc, I2C_I2SR, 0);
86
87 /* VF610 inverts enable bit meaning */
88 if (sc->sc_type == I2C_TYPE_VF610)
89 on = !on;
90 if (on)
91 HWRITE1(sc, I2C_I2CR, I2C_I2CR_IEN);
92 else
93 HWRITE1(sc, I2C_I2CR, 0);
94 }
95
96 void
imxiic_clear_iodone(struct imxiic_softc * sc)97 imxiic_clear_iodone(struct imxiic_softc *sc)
98 {
99 /*
100 * VF610: write bit to clear bit
101 * iMX21: clear bit, keep rest
102 */
103 if (sc->sc_type == I2C_TYPE_VF610)
104 HWRITE1(sc, I2C_I2SR, I2C_I2SR_IIF);
105 else
106 HCLR1(sc, I2C_I2SR, I2C_I2SR_IIF);
107 }
108
109 void
imxiic_setspeed(struct imxiic_softc * sc,u_int speed)110 imxiic_setspeed(struct imxiic_softc *sc, u_int speed)
111 {
112 if (!sc->frequency) {
113 uint32_t div;
114 int i;
115
116 div = (sc->sc_clkrate + speed - 1) / speed;
117 if (div < sc->sc_clk_div[0].div)
118 i = 0;
119 else if (div > sc->sc_clk_div[sc->sc_clk_ndiv - 1].div)
120 i = sc->sc_clk_ndiv - 1;
121 else
122 for (i = 0; sc->sc_clk_div[i].div < div; i++)
123 ;
124
125 sc->frequency = sc->sc_clk_div[i].val;
126 }
127
128 HWRITE1(sc, I2C_IFDR, sc->frequency);
129 }
130
131 int
imxiic_wait_state(struct imxiic_softc * sc,uint32_t mask,uint32_t value)132 imxiic_wait_state(struct imxiic_softc *sc, uint32_t mask, uint32_t value)
133 {
134 uint32_t state;
135 int timeout;
136 for (timeout = 1000; timeout > 0; timeout--) {
137 if (((state = HREAD1(sc, I2C_I2SR)) & mask) == value)
138 return 0;
139 delay(10);
140 }
141 return ETIMEDOUT;
142 }
143
144 int
imxiic_read(struct imxiic_softc * sc,int addr,const void * cmd,int cmdlen,void * data,int len)145 imxiic_read(struct imxiic_softc *sc, int addr, const void *cmd, int cmdlen,
146 void *data, int len)
147 {
148 int i;
149
150 if (cmdlen > 0) {
151 if (imxiic_write(sc, addr, cmd, cmdlen, NULL, 0))
152 return (EIO);
153
154 HSET1(sc, I2C_I2CR, I2C_I2CR_RSTA);
155 delay(1);
156 if (imxiic_wait_state(sc, I2C_I2SR_IBB, I2C_I2SR_IBB))
157 return (EIO);
158 }
159
160 imxiic_clear_iodone(sc);
161 HWRITE1(sc, I2C_I2DR, (addr << 1) | 1);
162
163 if (imxiic_wait_state(sc, I2C_I2SR_IIF, I2C_I2SR_IIF))
164 return (EIO);
165 imxiic_clear_iodone(sc);
166 if (HREAD1(sc, I2C_I2SR) & I2C_I2SR_RXAK)
167 return (EIO);
168
169 HCLR1(sc, I2C_I2CR, I2C_I2CR_MTX);
170 if (len - 1)
171 HCLR1(sc, I2C_I2CR, I2C_I2CR_TXAK);
172
173 /* dummy read */
174 HREAD1(sc, I2C_I2DR);
175
176 for (i = 0; i < len; i++) {
177 if (imxiic_wait_state(sc, I2C_I2SR_IIF, I2C_I2SR_IIF))
178 return (EIO);
179 imxiic_clear_iodone(sc);
180
181 if (i == (len - 1)) {
182 HCLR1(sc, I2C_I2CR, I2C_I2CR_MSTA | I2C_I2CR_MTX);
183 imxiic_wait_state(sc, I2C_I2SR_IBB, 0);
184 sc->stopped = 1;
185 } else if (i == (len - 2)) {
186 HSET1(sc, I2C_I2CR, I2C_I2CR_TXAK);
187 }
188 ((uint8_t*)data)[i] = HREAD1(sc, I2C_I2DR);
189 }
190
191 return 0;
192 }
193
194 int
imxiic_write(struct imxiic_softc * sc,int addr,const void * cmd,int cmdlen,const void * data,int len)195 imxiic_write(struct imxiic_softc *sc, int addr, const void *cmd, int cmdlen,
196 const void *data, int len)
197 {
198 int i;
199
200 imxiic_clear_iodone(sc);
201 HWRITE1(sc, I2C_I2DR, addr << 1);
202
203 if (imxiic_wait_state(sc, I2C_I2SR_IIF, I2C_I2SR_IIF))
204 return (EIO);
205 imxiic_clear_iodone(sc);
206 if (HREAD1(sc, I2C_I2SR) & I2C_I2SR_RXAK)
207 return (EIO);
208
209 for (i = 0; i < cmdlen; i++) {
210 HWRITE1(sc, I2C_I2DR, ((uint8_t*)cmd)[i]);
211 if (imxiic_wait_state(sc, I2C_I2SR_IIF, I2C_I2SR_IIF))
212 return (EIO);
213 imxiic_clear_iodone(sc);
214 if (HREAD1(sc, I2C_I2SR) & I2C_I2SR_RXAK)
215 return (EIO);
216 }
217
218 for (i = 0; i < len; i++) {
219 HWRITE1(sc, I2C_I2DR, ((uint8_t*)data)[i]);
220 if (imxiic_wait_state(sc, I2C_I2SR_IIF, I2C_I2SR_IIF))
221 return (EIO);
222 imxiic_clear_iodone(sc);
223 if (HREAD1(sc, I2C_I2SR) & I2C_I2SR_RXAK)
224 return (EIO);
225 }
226 return 0;
227 }
228
229 int
imxiic_i2c_acquire_bus(void * cookie,int flags)230 imxiic_i2c_acquire_bus(void *cookie, int flags)
231 {
232 struct imxiic_softc *sc = cookie;
233
234 rw_enter(&sc->sc_buslock, RW_WRITE);
235
236 /* set speed */
237 imxiic_setspeed(sc, sc->sc_bitrate);
238
239 /* enable the controller */
240 imxiic_enable(sc, 1);
241
242 /* wait for it to be stable */
243 delay(50);
244
245 return 0;
246 }
247
248 void
imxiic_i2c_release_bus(void * cookie,int flags)249 imxiic_i2c_release_bus(void *cookie, int flags)
250 {
251 struct imxiic_softc *sc = cookie;
252
253 imxiic_enable(sc, 0);
254
255 rw_exit(&sc->sc_buslock);
256 }
257
258 int
imxiic_i2c_exec(void * cookie,i2c_op_t op,i2c_addr_t addr,const void * cmdbuf,size_t cmdlen,void * buf,size_t len,int flags)259 imxiic_i2c_exec(void *cookie, i2c_op_t op, i2c_addr_t addr,
260 const void *cmdbuf, size_t cmdlen, void *buf, size_t len, int flags)
261 {
262 struct imxiic_softc *sc = cookie;
263 int ret = 0;
264
265 if (!I2C_OP_STOP_P(op))
266 return EINVAL;
267
268 /* start transaction */
269 HSET1(sc, I2C_I2CR, I2C_I2CR_MSTA);
270
271 if (imxiic_wait_state(sc, I2C_I2SR_IBB, I2C_I2SR_IBB)) {
272 ret = EIO;
273 goto fail;
274 }
275
276 sc->stopped = 0;
277
278 HSET1(sc, I2C_I2CR, I2C_I2CR_IIEN | I2C_I2CR_MTX | I2C_I2CR_TXAK);
279
280 if (I2C_OP_READ_P(op)) {
281 ret = imxiic_read(sc, addr, cmdbuf, cmdlen, buf, len);
282 } else {
283 ret = imxiic_write(sc, addr, cmdbuf, cmdlen, buf, len);
284 }
285
286 fail:
287 if (!sc->stopped) {
288 HCLR1(sc, I2C_I2CR, I2C_I2CR_MSTA | I2C_I2CR_MTX);
289 imxiic_wait_state(sc, I2C_I2SR_IBB, 0);
290 sc->stopped = 1;
291 }
292
293 return ret;
294 }
295
296 uint8_t
imxiic_read_1(struct imxiic_softc * sc,int reg)297 imxiic_read_1(struct imxiic_softc *sc, int reg)
298 {
299 reg <<= sc->sc_reg_shift;
300
301 return bus_space_read_1(sc->sc_iot, sc->sc_ioh, reg);
302 }
303
304 void
imxiic_write_1(struct imxiic_softc * sc,int reg,uint8_t val)305 imxiic_write_1(struct imxiic_softc *sc, int reg, uint8_t val)
306 {
307 reg <<= sc->sc_reg_shift;
308
309 bus_space_write_1(sc->sc_iot, sc->sc_ioh, reg, val);
310 }
311