xref: /openbsd-src/sys/dev/ic/imxiic.c (revision 46035553bfdd96e63c94e32da0210227ec2e3cf1)
1 /* $OpenBSD: imxiic.c,v 1.1 2020/11/17 14:30:13 patrick 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
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
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
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 		sc->frequency = sc->sc_clk_div[i].val;
125 	}
126 
127 	HWRITE1(sc, I2C_IFDR, sc->frequency);
128 }
129 
130 int
131 imxiic_wait_state(struct imxiic_softc *sc, uint32_t mask, uint32_t value)
132 {
133 	uint32_t state;
134 	int timeout;
135 	for (timeout = 1000; timeout > 0; timeout--) {
136 		if (((state = HREAD1(sc, I2C_I2SR)) & mask) == value)
137 			return 0;
138 		delay(10);
139 	}
140 	return ETIMEDOUT;
141 }
142 
143 int
144 imxiic_read(struct imxiic_softc *sc, int addr, const void *cmd, int cmdlen,
145     void *data, int len)
146 {
147 	int i;
148 
149 	if (cmdlen > 0) {
150 		if (imxiic_write(sc, addr, cmd, cmdlen, NULL, 0))
151 			return (EIO);
152 
153 		HSET1(sc, I2C_I2CR, I2C_I2CR_RSTA);
154 		delay(1);
155 		if (imxiic_wait_state(sc, I2C_I2SR_IBB, I2C_I2SR_IBB))
156 			return (EIO);
157 	}
158 
159 	imxiic_clear_iodone(sc);
160 	HWRITE1(sc, I2C_I2DR, (addr << 1) | 1);
161 
162 	if (imxiic_wait_state(sc, I2C_I2SR_IIF, I2C_I2SR_IIF))
163 		return (EIO);
164 	imxiic_clear_iodone(sc);
165 	if (HREAD1(sc, I2C_I2SR) & I2C_I2SR_RXAK)
166 		return (EIO);
167 
168 	HCLR1(sc, I2C_I2CR, I2C_I2CR_MTX);
169 	if (len - 1)
170 		HCLR1(sc, I2C_I2CR, I2C_I2CR_TXAK);
171 
172 	/* dummy read */
173 	HREAD1(sc, I2C_I2DR);
174 
175 	for (i = 0; i < len; i++) {
176 		if (imxiic_wait_state(sc, I2C_I2SR_IIF, I2C_I2SR_IIF))
177 			return (EIO);
178 		imxiic_clear_iodone(sc);
179 
180 		if (i == (len - 1)) {
181 			HCLR1(sc, I2C_I2CR, I2C_I2CR_MSTA | I2C_I2CR_MTX);
182 			imxiic_wait_state(sc, I2C_I2SR_IBB, 0);
183 			sc->stopped = 1;
184 		} else if (i == (len - 2)) {
185 			HSET1(sc, I2C_I2CR, I2C_I2CR_TXAK);
186 		}
187 		((uint8_t*)data)[i] = HREAD1(sc, I2C_I2DR);
188 	}
189 
190 	return 0;
191 }
192 
193 int
194 imxiic_write(struct imxiic_softc *sc, int addr, const void *cmd, int cmdlen,
195     const void *data, int len)
196 {
197 	int i;
198 
199 	imxiic_clear_iodone(sc);
200 	HWRITE1(sc, I2C_I2DR, addr << 1);
201 
202 	if (imxiic_wait_state(sc, I2C_I2SR_IIF, I2C_I2SR_IIF))
203 		return (EIO);
204 	imxiic_clear_iodone(sc);
205 	if (HREAD1(sc, I2C_I2SR) & I2C_I2SR_RXAK)
206 		return (EIO);
207 
208 	for (i = 0; i < cmdlen; i++) {
209 		HWRITE1(sc, I2C_I2DR, ((uint8_t*)cmd)[i]);
210 		if (imxiic_wait_state(sc, I2C_I2SR_IIF, I2C_I2SR_IIF))
211 			return (EIO);
212 		imxiic_clear_iodone(sc);
213 		if (HREAD1(sc, I2C_I2SR) & I2C_I2SR_RXAK)
214 			return (EIO);
215 	}
216 
217 	for (i = 0; i < len; i++) {
218 		HWRITE1(sc, I2C_I2DR, ((uint8_t*)data)[i]);
219 		if (imxiic_wait_state(sc, I2C_I2SR_IIF, I2C_I2SR_IIF))
220 			return (EIO);
221 		imxiic_clear_iodone(sc);
222 		if (HREAD1(sc, I2C_I2SR) & I2C_I2SR_RXAK)
223 			return (EIO);
224 	}
225 	return 0;
226 }
227 
228 int
229 imxiic_i2c_acquire_bus(void *cookie, int flags)
230 {
231 	struct imxiic_softc *sc = cookie;
232 
233 	rw_enter(&sc->sc_buslock, RW_WRITE);
234 
235 	/* set speed */
236 	imxiic_setspeed(sc, sc->sc_bitrate);
237 
238 	/* enable the controller */
239 	imxiic_enable(sc, 1);
240 
241 	/* wait for it to be stable */
242 	delay(50);
243 
244 	return 0;
245 }
246 
247 void
248 imxiic_i2c_release_bus(void *cookie, int flags)
249 {
250 	struct imxiic_softc *sc = cookie;
251 
252 	imxiic_enable(sc, 0);
253 
254 	rw_exit(&sc->sc_buslock);
255 }
256 
257 int
258 imxiic_i2c_exec(void *cookie, i2c_op_t op, i2c_addr_t addr,
259     const void *cmdbuf, size_t cmdlen, void *buf, size_t len, int flags)
260 {
261 	struct imxiic_softc *sc = cookie;
262 	int ret = 0;
263 
264 	if (!I2C_OP_STOP_P(op))
265 		return EINVAL;
266 
267 	/* start transaction */
268 	HSET1(sc, I2C_I2CR, I2C_I2CR_MSTA);
269 
270 	if (imxiic_wait_state(sc, I2C_I2SR_IBB, I2C_I2SR_IBB)) {
271 		ret = EIO;
272 		goto fail;
273 	}
274 
275 	sc->stopped = 0;
276 
277 	HSET1(sc, I2C_I2CR, I2C_I2CR_IIEN | I2C_I2CR_MTX | I2C_I2CR_TXAK);
278 
279 	if (I2C_OP_READ_P(op)) {
280 		ret = imxiic_read(sc, addr, cmdbuf, cmdlen, buf, len);
281 	} else {
282 		ret = imxiic_write(sc, addr, cmdbuf, cmdlen, buf, len);
283 	}
284 
285 fail:
286 	if (!sc->stopped) {
287 		HCLR1(sc, I2C_I2CR, I2C_I2CR_MSTA | I2C_I2CR_MTX);
288 		imxiic_wait_state(sc, I2C_I2SR_IBB, 0);
289 		sc->stopped = 1;
290 	}
291 
292 	return ret;
293 }
294 
295 uint8_t
296 imxiic_read_1(struct imxiic_softc *sc, int reg)
297 {
298 	reg <<= sc->sc_reg_shift;
299 
300 	return bus_space_read_1(sc->sc_iot, sc->sc_ioh, reg);
301 }
302 
303 void
304 imxiic_write_1(struct imxiic_softc *sc, int reg, uint8_t val)
305 {
306 	reg <<= sc->sc_reg_shift;
307 
308 	bus_space_write_1(sc->sc_iot, sc->sc_ioh, reg, val);
309 }
310