xref: /openbsd/sys/dev/fdt/bcm2835_bsc.c (revision 471aeecf)
1 /*	$OpenBSD: bcm2835_bsc.c,v 1.4 2022/04/06 18:59:28 naddy Exp $	*/
2 /*
3  * Copyright (c) 2020 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_misc.h>
32 #include <dev/ofw/ofw_pinctrl.h>
33 #include <dev/ofw/fdt.h>
34 
35 /* Registers. */
36 #define BSC_C		0x00
37 #define  BSC_C_I2CEN	(1 << 15)
38 #define  BSC_C_INTR	(1 << 10)
39 #define  BSC_C_INTT	(1 << 9)
40 #define  BSC_C_INTD	(1 << 8)
41 #define  BSC_C_ST	(1 << 7)
42 #define  BSC_C_CLEAR	(0x3 << 4)
43 #define  BSC_C_READ	(1 << 0)
44 #define BSC_S		0x04
45 #define  BSC_S_CLKT	(1 << 9)
46 #define  BSC_S_ERR	(1 << 8)
47 #define  BSC_S_RXF	(1 << 7)
48 #define  BSC_S_TXE	(1 << 6)
49 #define  BSC_S_RXD	(1 << 5)
50 #define  BSC_S_TXD	(1 << 4)
51 #define  BSC_S_RXR	(1 << 3)
52 #define  BSC_S_TXW	(1 << 2)
53 #define  BSC_S_DONE	(1 << 1)
54 #define  BSC_S_TA	(1 << 0)
55 #define BSC_DLEN	0x08
56 #define BSC_A		0x0c
57 #define BSC_FIFO	0x10
58 #define BSC_DIV		0x14
59 #define BSC_DEL		0x18
60 #define  BSC_DEL_FEDL_SHIFT	16
61 #define  BSC_DEL_REDL_SHIFT	0
62 #define BSC_CLKT	0x1c
63 
64 #define HREAD4(sc, reg)							\
65 	(bus_space_read_4((sc)->sc_iot, (sc)->sc_ioh, (reg)))
66 #define HWRITE4(sc, reg, val)						\
67 	bus_space_write_4((sc)->sc_iot, (sc)->sc_ioh, (reg), (val))
68 
69 struct bcmbsc_softc {
70 	struct device		sc_dev;
71 	bus_space_tag_t		sc_iot;
72 	bus_space_handle_t	sc_ioh;
73 
74 	int			sc_node;
75 	struct i2c_controller	sc_ic;
76 	struct i2c_bus		sc_ib;
77 };
78 
79 int	bcmbsc_match(struct device *, void *, void *);
80 void	bcmbsc_attach(struct device *, struct device *, void *);
81 
82 const struct cfattach bcmbsc_ca = {
83 	sizeof (struct bcmbsc_softc), bcmbsc_match, bcmbsc_attach
84 };
85 
86 struct cfdriver bcmbsc_cd = {
87 	NULL, "bcmbsc", DV_DULL
88 };
89 
90 int	bcmbsc_acquire_bus(void *, int);
91 void	bcmbsc_release_bus(void *, int);
92 int	bcmbsc_exec(void *, i2c_op_t, i2c_addr_t, const void *, size_t,
93 	    void *, size_t, int);
94 
95 void	bcmbsc_bus_scan(struct device *, struct i2cbus_attach_args *, void *);
96 
97 int
bcmbsc_match(struct device * parent,void * match,void * aux)98 bcmbsc_match(struct device *parent, void *match, void *aux)
99 {
100 	struct fdt_attach_args *faa = aux;
101 
102 	return OF_is_compatible(faa->fa_node, "brcm,bcm2835-i2c");
103 }
104 
105 void
bcmbsc_attach(struct device * parent,struct device * self,void * aux)106 bcmbsc_attach(struct device *parent, struct device *self, void *aux)
107 {
108 	struct bcmbsc_softc *sc = (struct bcmbsc_softc *)self;
109 	struct fdt_attach_args *faa = aux;
110 	struct i2cbus_attach_args iba;
111 	uint32_t clock_speed, bus_speed;
112 	uint32_t div, fedl, redl;
113 
114 	if (faa->fa_nreg < 1) {
115 		printf(": no registers\n");
116 		return;
117 	}
118 
119 	sc->sc_iot = faa->fa_iot;
120 	sc->sc_node = faa->fa_node;
121 
122 	if (bus_space_map(sc->sc_iot, faa->fa_reg[0].addr,
123 	    faa->fa_reg[0].size, 0, &sc->sc_ioh)) {
124 		printf(": can't map registers\n");
125 		return;
126 	}
127 
128 	printf("\n");
129 
130 	pinctrl_byname(sc->sc_node, "default");
131 
132 	clock_enable_all(sc->sc_node);
133 
134 	clock_speed = clock_get_frequency(sc->sc_node, NULL);
135 	bus_speed = OF_getpropint(sc->sc_node, "clock-frequency", 100000);
136 
137 	div = clock_speed / bus_speed;
138 	if (div & 1)
139 		div++;
140 	fedl = MAX(div / 16, 1);
141 	redl = MAX(div / 4, 1);
142 	HWRITE4(sc, BSC_DIV, div);
143 	HWRITE4(sc, BSC_DEL, (fedl << BSC_DEL_FEDL_SHIFT) |
144 	    (redl << BSC_DEL_REDL_SHIFT));
145 
146 	sc->sc_ic.ic_cookie = sc;
147 	sc->sc_ic.ic_acquire_bus = bcmbsc_acquire_bus;
148 	sc->sc_ic.ic_release_bus = bcmbsc_release_bus;
149 	sc->sc_ic.ic_exec = bcmbsc_exec;
150 
151 	/* Configure its children */
152 	memset(&iba, 0, sizeof(iba));
153 	iba.iba_name = "iic";
154 	iba.iba_tag = &sc->sc_ic;
155 	iba.iba_bus_scan = bcmbsc_bus_scan;
156 	iba.iba_bus_scan_arg = &sc->sc_node;
157 
158 	config_found(&sc->sc_dev, &iba, iicbus_print);
159 
160 	sc->sc_ib.ib_node = sc->sc_node;
161 	sc->sc_ib.ib_ic = &sc->sc_ic;
162 	i2c_register(&sc->sc_ib);
163 }
164 
165 int
bcmbsc_acquire_bus(void * cookie,int flags)166 bcmbsc_acquire_bus(void *cookie, int flags)
167 {
168 	struct bcmbsc_softc *sc = cookie;
169 
170 	HWRITE4(sc, BSC_S, HREAD4(sc, BSC_S));
171 	HWRITE4(sc, BSC_C, BSC_C_I2CEN | BSC_C_CLEAR);
172 	return 0;
173 }
174 
175 void
bcmbsc_release_bus(void * cookie,int flags)176 bcmbsc_release_bus(void *cookie, int flags)
177 {
178 	struct bcmbsc_softc *sc = cookie;
179 
180 	HWRITE4(sc, BSC_C, BSC_C_CLEAR);
181 }
182 
183 int
bcmbsc_wait(struct bcmbsc_softc * sc,uint32_t mask,uint32_t value)184 bcmbsc_wait(struct bcmbsc_softc *sc, uint32_t mask, uint32_t value)
185 {
186 	uint32_t stat;
187 	int timo;
188 
189 	for (timo = 10000; timo > 0; timo--) {
190 		stat = HREAD4(sc, BSC_S);
191 		if ((stat & mask) == value)
192 			return 0;
193 		if (stat & BSC_S_CLKT)
194 			return ETIMEDOUT;
195 		if (stat & BSC_S_ERR)
196 			return EIO;
197 		delay(1);
198 	}
199 
200 	return ETIMEDOUT;
201 }
202 
203 int
bcmbsc_read(struct bcmbsc_softc * sc,uint8_t * buf,size_t buflen)204 bcmbsc_read(struct bcmbsc_softc *sc, uint8_t *buf, size_t buflen)
205 {
206 	int i, error;
207 
208 	for (i = 0; i < buflen; i++) {
209 		error = bcmbsc_wait(sc, BSC_S_RXD, BSC_S_RXD);
210 		if (error)
211 			return error;
212 		buf[i] = HREAD4(sc, BSC_FIFO);
213 	}
214 
215 	return 0;
216 }
217 
218 int
bcmbsc_write(struct bcmbsc_softc * sc,const uint8_t * buf,size_t buflen)219 bcmbsc_write(struct bcmbsc_softc *sc, const uint8_t *buf, size_t buflen)
220 {
221 	int i, error;
222 
223 	for (i = 0; i < buflen; i++) {
224 		error = bcmbsc_wait(sc, BSC_S_TXD, BSC_S_TXD);
225 		if (error)
226 			return error;
227 		HWRITE4(sc, BSC_FIFO, buf[i]);
228 	}
229 
230 	return 0;
231 }
232 
233 int
bcmbsc_exec(void * cookie,i2c_op_t op,i2c_addr_t addr,const void * cmd,size_t cmdlen,void * buf,size_t buflen,int flags)234 bcmbsc_exec(void *cookie, i2c_op_t op, i2c_addr_t addr, const void *cmd,
235     size_t cmdlen, void *buf, size_t buflen, int flags)
236 {
237 	struct bcmbsc_softc *sc = cookie;
238 	uint32_t ctrl = BSC_C_I2CEN | BSC_C_ST;
239 	int error;
240 
241 	if (cmdlen + buflen > 65535)
242 		return EINVAL;
243 
244 	HWRITE4(sc, BSC_A, addr);
245 
246 	if (I2C_OP_READ_P(op))
247 		HWRITE4(sc, BSC_DLEN, cmdlen);
248 	else
249 		HWRITE4(sc, BSC_DLEN, cmdlen + buflen);
250 
251 	if (cmdlen > 0) {
252 		HWRITE4(sc, BSC_C, ctrl);
253 		error = bcmbsc_write(sc, cmd, cmdlen);
254 		if (error)
255 			return error;
256 		if (I2C_OP_READ_P(op))
257 			bcmbsc_wait(sc, BSC_S_DONE, BSC_S_DONE);
258 	}
259 
260 	if (I2C_OP_READ_P(op)) {
261 		HWRITE4(sc, BSC_DLEN, buflen);
262 		HWRITE4(sc, BSC_C, ctrl | BSC_C_READ);
263 		error = bcmbsc_read(sc, buf, buflen);
264 		if (error)
265 			return error;
266 	} else {
267 		if (cmdlen == 0)
268 			HWRITE4(sc, BSC_C, ctrl);
269 		error = bcmbsc_write(sc, buf, buflen);
270 		if (error)
271 			return error;
272 	}
273 
274 	return bcmbsc_wait(sc, BSC_S_DONE | BSC_S_TA, BSC_S_DONE);
275 }
276 
277 void
bcmbsc_bus_scan(struct device * self,struct i2cbus_attach_args * iba,void * arg)278 bcmbsc_bus_scan(struct device *self, struct i2cbus_attach_args *iba, void *arg)
279 {
280 	int iba_node = *(int *)arg;
281 	struct i2c_attach_args ia;
282 	char name[32], status[32];
283 	uint32_t reg[1];
284 	int node;
285 
286 	for (node = OF_child(iba_node); node; node = OF_peer(node)) {
287 		memset(name, 0, sizeof(name));
288 		memset(status, 0, sizeof(status));
289 		memset(reg, 0, sizeof(reg));
290 
291 		if (OF_getprop(node, "compatible", name, sizeof(name)) == -1)
292 			continue;
293 		if (name[0] == '\0')
294 			continue;
295 
296 		if (OF_getprop(node, "status", status, sizeof(status)) > 0 &&
297 		    strcmp(status, "disabled") == 0)
298 			continue;
299 
300 		if (OF_getprop(node, "reg", &reg, sizeof(reg)) != sizeof(reg))
301 			continue;
302 
303 		memset(&ia, 0, sizeof(ia));
304 		ia.ia_tag = iba->iba_tag;
305 		ia.ia_addr = bemtoh32(&reg[0]);
306 		ia.ia_name = name;
307 		ia.ia_cookie = &node;
308 		config_found(self, &ia, iic_print);
309 	}
310 }
311