xref: /openbsd/sys/dev/ic/imxiic.c (revision 36dba039)
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