xref: /openbsd/sys/dev/fdt/ociic.c (revision 6c4b29ed)
1 /*	$OpenBSD: ociic.c,v 1.2 2021/06/23 13:39:12 kettenis Exp $	*/
2 /*
3  * Copyright (c) 2021 Mark Kettenis <kettenis@openbsd.org>
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/systm.h>
20 #include <sys/device.h>
21 
22 #include <machine/intr.h>
23 #include <machine/bus.h>
24 #include <machine/fdt.h>
25 
26 #define _I2C_PRIVATE
27 #include <dev/i2c/i2cvar.h>
28 
29 #include <dev/ofw/openfirm.h>
30 #include <dev/ofw/ofw_clock.h>
31 #include <dev/ofw/ofw_pinctrl.h>
32 #include <dev/ofw/fdt.h>
33 
34 /* Registers */
35 #define I2C_PRER_LO	0x0000
36 #define I2C_PRER_HI	0x0004
37 #define I2C_CTR		0x0008
38 #define  I2C_CTR_EN	(1 << 7)
39 #define  I2C_CTR_IEN	(1 << 6)
40 #define I2C_TXR		0x000C
41 #define I2C_RXR		0x000C
42 #define I2C_CR		0x0010
43 #define  I2C_CR_STA	(1 << 7)
44 #define  I2C_CR_STO	(1 << 6)
45 #define  I2C_CR_RD	(1 << 5)
46 #define  I2C_CR_WR	(1 << 4)
47 #define  I2C_CR_NACK	(1 << 3)
48 #define  I2C_CR_IACK	(1 << 0)
49 #define I2C_SR		0x0010
50 #define  I2C_SR_RXNACK	(1 << 7)
51 #define  I2C_SR_BUSY	(1 << 6)
52 #define  I2C_SR_AL	(1 << 5)
53 #define  I2C_SR_TIP	(1 << 1)
54 #define  I2C_SR_IF	(1 << 0)
55 
56 struct ociic_softc {
57 	struct device		sc_dev;
58 	bus_space_tag_t		sc_iot;
59 	bus_space_handle_t	sc_ioh;
60 
61 	int			sc_node;
62 	struct i2c_controller	sc_ic;
63 };
64 
65 static inline uint8_t
66 ociic_read(struct ociic_softc *sc, bus_size_t reg)
67 {
68 	return bus_space_read_1(sc->sc_iot, sc->sc_ioh, reg);
69 }
70 
71 static inline void
72 ociic_write(struct ociic_softc *sc, bus_size_t reg, uint8_t value)
73 {
74 	bus_space_write_1(sc->sc_iot, sc->sc_ioh, reg, value);
75 }
76 
77 static inline void
78 ociic_set(struct ociic_softc *sc, bus_size_t reg, uint8_t bits)
79 {
80 	ociic_write(sc, reg, ociic_read(sc, reg) | bits);
81 }
82 
83 static inline void
84 ociic_clr(struct ociic_softc *sc, bus_size_t reg, uint8_t bits)
85 {
86 	ociic_write(sc, reg, ociic_read(sc, reg) & ~bits);
87 }
88 
89 int ociic_match(struct device *, void *, void *);
90 void ociic_attach(struct device *, struct device *, void *);
91 
92 struct cfattach	ociic_ca = {
93 	sizeof (struct ociic_softc), ociic_match, ociic_attach
94 };
95 
96 struct cfdriver ociic_cd = {
97 	NULL, "ociic", DV_DULL
98 };
99 
100 int	ociic_acquire_bus(void *, int);
101 void	ociic_release_bus(void *, int);
102 int	ociic_exec(void *, i2c_op_t, i2c_addr_t, const void *, size_t,
103 	    void *, size_t, int);
104 
105 void	ociic_bus_scan(struct device *, struct i2cbus_attach_args *, void *);
106 
107 int
108 ociic_match(struct device *parent, void *match, void *aux)
109 {
110 	struct fdt_attach_args *faa = aux;
111 
112 	return OF_is_compatible(faa->fa_node, "sifive,i2c0");
113 }
114 
115 void
116 ociic_attach(struct device *parent, struct device *self, void *aux)
117 {
118 	struct ociic_softc *sc = (struct ociic_softc *)self;
119 	struct fdt_attach_args *faa = aux;
120 	struct i2cbus_attach_args iba;
121 	uint32_t clock_speed, bus_speed;
122 	uint32_t div;
123 
124 	if (faa->fa_nreg < 1) {
125 		printf(": no registers\n");
126 		return;
127 	}
128 
129 	sc->sc_iot = faa->fa_iot;
130 	sc->sc_node = faa->fa_node;
131 
132 	if (bus_space_map(sc->sc_iot, faa->fa_reg[0].addr,
133 	    faa->fa_reg[0].size, 0, &sc->sc_ioh)) {
134 		printf(": can't map registers\n");
135 		return;
136 	}
137 
138 	printf("\n");
139 
140 	pinctrl_byname(sc->sc_node, "default");
141 	clock_enable_all(sc->sc_node);
142 
143 	ociic_clr(sc, I2C_CTR, I2C_CTR_EN);
144 
145 	clock_speed = clock_get_frequency(sc->sc_node, NULL);
146 	bus_speed = OF_getpropint(sc->sc_node, "clock-frequency", 100000);
147 
148 	if (clock_speed > 0) {
149 		div = (clock_speed / (5 * bus_speed));
150 		if (div > 0)
151 			div -= 1;
152 		if (div > 0xffff)
153 			div = 0xffff;
154 
155 		ociic_write(sc, I2C_PRER_LO, div & 0xff);
156 		ociic_write(sc, I2C_PRER_HI, div >> 8);
157 	}
158 
159 	sc->sc_ic.ic_cookie = sc;
160 	sc->sc_ic.ic_acquire_bus = ociic_acquire_bus;
161 	sc->sc_ic.ic_release_bus = ociic_release_bus;
162 	sc->sc_ic.ic_exec = ociic_exec;
163 
164 	/* Configure its children */
165 	memset(&iba, 0, sizeof(iba));
166 	iba.iba_name = "iic";
167 	iba.iba_tag = &sc->sc_ic;
168 	iba.iba_bus_scan = ociic_bus_scan;
169 	iba.iba_bus_scan_arg = &sc->sc_node;
170 
171 	config_found(&sc->sc_dev, &iba, iicbus_print);
172 }
173 
174 int
175 ociic_acquire_bus(void *cookie, int flags)
176 {
177 	struct ociic_softc *sc = cookie;
178 
179 	ociic_set(sc, I2C_CTR, I2C_CTR_EN);
180 	return 0;
181 }
182 
183 void
184 ociic_release_bus(void *cookie, int flags)
185 {
186 	struct ociic_softc *sc = cookie;
187 
188 	ociic_clr(sc, I2C_CTR, I2C_CTR_EN);
189 }
190 
191 int
192 ociic_unbusy(struct ociic_softc *sc)
193 {
194 	uint8_t stat;
195 	int timo;
196 
197 	for (timo = 50000; timo > 0; timo--) {
198 		stat = ociic_read(sc, I2C_SR);
199 		if ((stat & I2C_SR_BUSY) == 0)
200 			break;
201 		delay(10);
202 	}
203 	if (timo == 0) {
204 		ociic_write(sc, I2C_CR, I2C_CR_STO);
205 		return ETIMEDOUT;
206 	}
207 
208 	return 0;
209 }
210 
211 int
212 ociic_wait(struct ociic_softc *sc, int ack)
213 {
214 	uint8_t stat;
215 	int timo;
216 
217 	for (timo = 50000; timo > 0; timo--) {
218 		stat = ociic_read(sc, I2C_SR);
219 		if ((stat & I2C_SR_TIP) == 0)
220 			break;
221 		if ((stat & I2C_SR_AL))
222 			break;
223 		delay(10);
224 	}
225 	if (timo == 0) {
226 		ociic_write(sc, I2C_CR, I2C_CR_STO);
227 		return ETIMEDOUT;
228 	}
229 
230 	if (stat & I2C_SR_AL) {
231 		ociic_write(sc, I2C_CR, I2C_CR_STO);
232 		return EIO;
233 	}
234 	if (ack && (stat & I2C_SR_RXNACK)) {
235 		ociic_write(sc, I2C_CR, I2C_CR_STO);
236 		return EIO;
237 	}
238 
239 	return 0;
240 }
241 
242 int
243 ociic_exec(void *cookie, i2c_op_t op, i2c_addr_t addr, const void *cmd,
244     size_t cmdlen, void *buf, size_t buflen, int flags)
245 {
246 	struct ociic_softc *sc = cookie;
247 	int error, i;
248 
249 	error = ociic_unbusy(sc);
250 	if (error)
251 		return error;
252 
253 	if (cmdlen > 0) {
254 		ociic_write(sc, I2C_TXR, addr << 1);
255 		ociic_write(sc, I2C_CR, I2C_CR_STA | I2C_CR_WR);
256 		error = ociic_wait(sc, 1);
257 		if (error)
258 			return error;
259 
260 		for (i = 0; i < cmdlen; i++) {
261 			ociic_write(sc, I2C_TXR, ((uint8_t *)cmd)[i]);
262 			ociic_write(sc, I2C_CR, I2C_CR_WR);
263 			error = ociic_wait(sc, 1);
264 			if (error)
265 				return error;
266 		}
267 	}
268 
269 	if (I2C_OP_READ_P(op)) {
270 		ociic_write(sc, I2C_TXR, addr << 1 | 1);
271 		ociic_write(sc, I2C_CR, I2C_CR_STA | I2C_CR_WR);
272 		error = ociic_wait(sc, 1);
273 		if (error)
274 			return error;
275 
276 		for (i = 0; i < buflen; i++) {
277 			ociic_write(sc, I2C_CR, I2C_CR_RD |
278 			    (i == (buflen - 1) ? I2C_CR_NACK : 0));
279 			error = ociic_wait(sc, 0);
280 			if (error)
281 				return error;
282 			((uint8_t *)buf)[i] = ociic_read(sc, I2C_RXR);
283 		}
284 	} else {
285 		if (cmdlen == 0) {
286 			ociic_write(sc, I2C_TXR, addr << 1);
287 			ociic_write(sc, I2C_CR, I2C_CR_STA | I2C_CR_WR);
288 		}
289 
290 		for (i = 0; i < buflen; i++) {
291 			ociic_write(sc, I2C_TXR, ((uint8_t *)buf)[i]);
292 			ociic_write(sc, I2C_CR, I2C_CR_WR);
293 			error = ociic_wait(sc, 1);
294 			if (error)
295 				return error;
296 		}
297 	}
298 
299 	if (I2C_OP_STOP_P(op))
300 		ociic_write(sc, I2C_CR, I2C_CR_STO);
301 
302 	return 0;
303 }
304 
305 void
306 ociic_bus_scan(struct device *self, struct i2cbus_attach_args *iba, void *arg)
307 {
308 	int iba_node = *(int *)arg;
309 	struct i2c_attach_args ia;
310 	char name[32], status[32];
311 	uint32_t reg[1];
312 	int node;
313 
314 	for (node = OF_child(iba_node); node; node = OF_peer(node)) {
315 		memset(name, 0, sizeof(name));
316 		memset(status, 0, sizeof(status));
317 		memset(reg, 0, sizeof(reg));
318 
319 		if (OF_getprop(node, "compatible", name, sizeof(name)) == -1)
320 			continue;
321 		if (name[0] == '\0')
322 			continue;
323 
324 		if (OF_getprop(node, "status", status, sizeof(status)) > 0 &&
325 		    strcmp(status, "disabled") == 0)
326 			continue;
327 
328 		if (OF_getprop(node, "reg", &reg, sizeof(reg)) != sizeof(reg))
329 			continue;
330 
331 		memset(&ia, 0, sizeof(ia));
332 		ia.ia_tag = iba->iba_tag;
333 		ia.ia_addr = bemtoh32(&reg[0]);
334 		ia.ia_name = name;
335 		ia.ia_cookie = &node;
336 		config_found(self, &ia, iic_print);
337 	}
338 }
339