bcm2835_bsc.c revision 1.1.4.2 1 /* $NetBSD: bcm2835_bsc.c,v 1.1.4.2 2013/02/13 01:36:14 riz Exp $ */
2
3 /*
4 * Copyright (c) 2012 Jonathan A. Kollasch
5 * All rights reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
17 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
18 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
19 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
20 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
21 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
22 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
23 * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
24 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
25 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
26 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 */
28
29 #include <sys/cdefs.h>
30 __KERNEL_RCSID(0, "$NetBSD: bcm2835_bsc.c,v 1.1.4.2 2013/02/13 01:36:14 riz Exp $");
31
32 #include <sys/param.h>
33 #include <sys/device.h>
34 #include <sys/systm.h>
35 #include <sys/mutex.h>
36 #include <sys/bus.h>
37 #include <sys/intr.h>
38
39 #include <dev/i2c/i2cvar.h>
40
41 #include <arm/broadcom/bcm_amba.h>
42 #include <arm/broadcom/bcm2835reg.h>
43 #include <arm/broadcom/bcm2835_bscreg.h>
44 #include <arm/broadcom/bcm2835_gpio_subr.h>
45
46 #if defined(_KERNEL_OPT)
47 #include "opt_kernhist.h"
48 #endif
49 #include <sys/kernhist.h>
50
51 KERNHIST_DECL(bsciichist);
52
53 struct bsciic_softc {
54 device_t sc_dev;
55 bus_space_tag_t sc_iot;
56 bus_space_handle_t sc_ioh;
57 bus_size_t sc_ios;
58 struct i2c_controller sc_i2c;
59 kmutex_t sc_buslock;
60 void *sc_inth;
61 };
62
63 static int bsciic_match(device_t, cfdata_t, void *);
64 static void bsciic_attach(device_t, device_t, void *);
65
66 void bsciic_dump_regs(struct bsciic_softc * const);
67
68 static int bsciic_acquire_bus(void *, int);
69 static void bsciic_release_bus(void *, int);
70 static int bsciic_exec(void *, i2c_op_t, i2c_addr_t, const void *, size_t,
71 void *, size_t, int);
72
73 CFATTACH_DECL_NEW(bsciic, sizeof(struct bsciic_softc),
74 bsciic_match, bsciic_attach, NULL, NULL);
75
76 static int
77 bsciic_match(device_t parent, cfdata_t match, void *aux)
78 {
79 struct amba_attach_args * const aaa = aux;
80
81 if (strcmp(aaa->aaa_name, "bcmbsc") != 0)
82 return 0;
83
84 return 1;
85 }
86
87 static void
88 bsciic_attach(device_t parent, device_t self, void *aux)
89 {
90 struct bsciic_softc * const sc = device_private(self);
91 struct amba_attach_args * const aaa = aux;
92 struct i2cbus_attach_args iba;
93 u_int bscunit = ~0;
94
95 switch (aaa->aaa_addr) {
96 case BCM2835_BSC0_BASE:
97 bscunit = 0;
98 break;
99 case BCM2835_BSC1_BASE:
100 bscunit = 1;
101 break;
102 }
103
104 aprint_naive("\n");
105 aprint_normal(": BSC%u\n", bscunit);
106
107 KERNHIST_INIT(bsciichist, 512);
108
109 sc->sc_dev = self;
110
111 mutex_init(&sc->sc_buslock, MUTEX_DEFAULT, IPL_NONE);
112
113 sc->sc_iot = aaa->aaa_iot;
114 if (bus_space_map(aaa->aaa_iot, aaa->aaa_addr, aaa->aaa_size, 0,
115 &sc->sc_ioh) != 0) {
116 aprint_error_dev(sc->sc_dev, "unable to map device\n");
117 return;
118 }
119 sc->sc_ios = aaa->aaa_size;
120
121 switch (aaa->aaa_addr) {
122 case BCM2835_BSC0_BASE:
123 /* SDA0 on GPIO0, SCL0 on GPIO1 */
124 bcm2835gpio_function_select(0, BCM2835_GPIO_ALT0);
125 bcm2835gpio_function_select(1, BCM2835_GPIO_ALT0);
126 break;
127 case BCM2835_BSC1_BASE:
128 /* SDA1 on GPIO2, SCL1 on GPIO3 */
129 bcm2835gpio_function_select(2, BCM2835_GPIO_ALT0);
130 bcm2835gpio_function_select(3, BCM2835_GPIO_ALT0);
131 break;
132 }
133
134 /* clear FIFO, disable controller */
135 bus_space_write_4(sc->sc_iot, sc->sc_ioh, BSC_C, BSC_C_CLEAR_CLEAR);
136 bus_space_write_4(sc->sc_iot, sc->sc_ioh, BSC_S, BSC_S_CLKT |
137 BSC_S_ERR | BSC_S_DONE);
138 bus_space_write_4(sc->sc_iot, sc->sc_ioh, BSC_DIV,
139 __SHIFTIN(250000000/100000, BSC_DIV_CDIV)); // XXX may not be this
140
141 sc->sc_i2c.ic_cookie = sc;
142 sc->sc_i2c.ic_acquire_bus = bsciic_acquire_bus;
143 sc->sc_i2c.ic_release_bus = bsciic_release_bus;
144 sc->sc_i2c.ic_exec = bsciic_exec;
145
146 memset(&iba, 0, sizeof(iba));
147
148 iba.iba_tag = &sc->sc_i2c;
149 iba.iba_type = 0;
150 config_found_ia(self, "i2cbus", &iba, iicbus_print);
151 }
152
153 void
154 bsciic_dump_regs(struct bsciic_softc * const sc)
155 {
156 KERNHIST_FUNC(__func__);
157 KERNHIST_CALLED(bsciichist);
158
159 KERNHIST_LOG(bsciichist, "C %08x S %08x D %08x A %08x",
160 bus_space_read_4(sc->sc_iot, sc->sc_ioh, BSC_C),
161 bus_space_read_4(sc->sc_iot, sc->sc_ioh, BSC_S),
162 bus_space_read_4(sc->sc_iot, sc->sc_ioh, BSC_DLEN),
163 bus_space_read_4(sc->sc_iot, sc->sc_ioh, BSC_A)
164 );
165 }
166
167 static int
168 bsciic_acquire_bus(void *v, int flags)
169 {
170 struct bsciic_softc * const sc = v;
171 uint32_t s;
172
173 mutex_enter(&sc->sc_buslock);
174
175 bus_space_write_4(sc->sc_iot, sc->sc_ioh, BSC_S, BSC_S_CLKT |
176 BSC_S_ERR | BSC_S_DONE);
177 bus_space_write_4(sc->sc_iot, sc->sc_ioh, BSC_C, BSC_C_I2CEN |
178 BSC_C_CLEAR_CLEAR);
179 s = bus_space_read_4(sc->sc_iot, sc->sc_ioh, BSC_S);
180 KASSERT((s & BSC_S_TA) == 0);
181
182 return 0;
183 }
184
185 static void
186 bsciic_release_bus(void *v, int flags)
187 {
188 struct bsciic_softc * const sc = v;
189
190 bus_space_write_4(sc->sc_iot, sc->sc_ioh, BSC_C, BSC_C_CLEAR_CLEAR);
191
192 mutex_exit(&sc->sc_buslock);
193 }
194
195 static int
196 bsciic_exec(void *v, i2c_op_t op, i2c_addr_t addr, const void *cmdbuf,
197 size_t cmdlen, void *databuf, size_t datalen, int flags)
198 {
199 KERNHIST_FUNC(__func__); KERNHIST_CALLED(bsciichist);
200 struct bsciic_softc * const sc = v;
201 uint32_t c, s, dlen, a;
202 uint32_t j;
203 uint8_t *buf;
204 size_t len;
205 size_t pos;
206 int error = 0;
207 const bool isread = I2C_OP_READ_P(op);
208
209 flags |= I2C_F_POLL;
210
211 #if 0
212 device_printf(sc->sc_dev, "exec: op %d, addr 0x%x, cmdbuf %p, "
213 "cmdlen %zu, databuf %p, datalen %zu, flags 0x%x\n",
214 op, addr, cmdbuf, cmdlen, databuf, datalen, flags);
215 #endif
216
217 a = __SHIFTIN(addr, BSC_A_ADDR);
218 c = BSC_C_I2CEN | BSC_C_CLEAR_CLEAR;
219 #if notyet
220 c |= BSC_C_INTR | BSC_C_INTT | BSC_C_INTD;
221 #endif
222
223 buf = __UNCONST(cmdbuf);
224 len = cmdlen;
225
226 if (isread)
227 dlen = cmdlen;
228 else
229 dlen = cmdlen + datalen;
230 dlen = __SHIFTIN(dlen, BSC_DLEN_DLEN);
231
232 s = bus_space_read_4(sc->sc_iot, sc->sc_ioh, BSC_S);
233 if ((s & BSC_S_TA) != 0)
234 bsciic_dump_regs(sc);
235 KASSERT((s & BSC_S_TA) == 0);
236 bus_space_write_4(sc->sc_iot, sc->sc_ioh, BSC_DLEN, dlen);
237 bus_space_write_4(sc->sc_iot, sc->sc_ioh, BSC_A, a);
238 bus_space_write_4(sc->sc_iot, sc->sc_ioh, BSC_C, c | BSC_C_ST);
239
240 do {
241 s = bus_space_read_4(sc->sc_iot, sc->sc_ioh, BSC_S);
242 } while ((s & BSC_S_TA) == 0);
243
244 flood_again:
245 KERNHIST_LOG(bsciichist, "flood top %p %zu", buf, len, 0, 0);
246 j = 10000000;
247 for (pos = 0; pos < len; ) {
248 if (--j == 0)
249 return -1;
250 s = bus_space_read_4(sc->sc_iot, sc->sc_ioh, BSC_S);
251 KERNHIST_LOG(bsciichist, "w s %08x", s, 0, 0, 0);
252 if ((s & BSC_S_CLKT) != 0) {
253 error = EIO;
254 goto done;
255 }
256 if ((s & BSC_S_ERR) != 0) {
257 error = EIO;
258 goto done;
259 }
260 if ((s & BSC_S_DONE) != 0)
261 break;
262 if ((s & BSC_S_TXD) == 0)
263 continue;
264 bus_space_write_4(sc->sc_iot, sc->sc_ioh, BSC_FIFO, buf[pos]);
265 KERNHIST_LOG(bsciichist, "w %p %p %02x", buf, &buf[pos],
266 buf[pos], 0);
267 pos++;
268 }
269 KERNHIST_LOG(bsciichist, "flood bot %p %zu", buf, len, 0, 0);
270
271 if (buf == cmdbuf && !isread) {
272 buf = databuf;
273 len = datalen;
274 goto flood_again;
275 }
276
277 do {
278 s = bus_space_read_4(sc->sc_iot, sc->sc_ioh, BSC_S);
279 } while ((s & BSC_S_TA) != 0);
280
281 s = bus_space_read_4(sc->sc_iot, sc->sc_ioh, BSC_S);
282 s &= BSC_S_CLKT|BSC_S_ERR|BSC_S_DONE;
283 KASSERT((s & BSC_S_DONE) != 0);
284 if (s != 0)
285 bus_space_write_4(sc->sc_iot, sc->sc_ioh, BSC_S, s);
286
287 if (!isread)
288 goto done;
289
290 c |= BSC_C_READ;
291
292 buf = databuf;
293 len = datalen;
294 dlen = datalen;
295
296 dlen = __SHIFTIN(dlen, BSC_DLEN_DLEN);
297 KASSERT(dlen >= 1);
298 bus_space_write_4(sc->sc_iot, sc->sc_ioh, BSC_DLEN, dlen);
299 bus_space_write_4(sc->sc_iot, sc->sc_ioh, BSC_A, a);
300 bus_space_write_4(sc->sc_iot, sc->sc_ioh, BSC_C, c | BSC_C_ST);
301
302 do {
303 s = bus_space_read_4(sc->sc_iot, sc->sc_ioh, BSC_S);
304 } while ((s & BSC_S_TA) == 0);
305
306 KERNHIST_LOG(bsciichist, "drain top %p %zu", buf, len, 0, 0);
307 j = 10000000;
308 for (pos = 0; pos < len; ) {
309 if (--j == 0)
310 return -1;
311 s = bus_space_read_4(sc->sc_iot, sc->sc_ioh, BSC_S);
312 KERNHIST_LOG(bsciichist, "r s %08x", s, 0, 0, 0);
313 if ((s & BSC_S_CLKT) != 0) {
314 error = EIO;
315 goto done;
316 }
317 if ((s & BSC_S_ERR) != 0) {
318 error = EIO;
319 goto done;
320 }
321 if ((s & BSC_S_DONE) != 0)
322 break;
323 if ((s & BSC_S_RXD) == 0)
324 continue;
325 j = 10000000;
326 buf[pos] = bus_space_read_4(sc->sc_iot, sc->sc_ioh, BSC_FIFO);
327 KERNHIST_LOG(bsciichist, "r %p %p %02x", buf, &buf[pos],
328 buf[pos], 0);
329 pos++;
330 }
331 KERNHIST_LOG(bsciichist, "drain bot %p %zu", buf, len, 0, 0);
332
333 do {
334 s = bus_space_read_4(sc->sc_iot, sc->sc_ioh, BSC_S);
335 } while ((s & BSC_S_TA) != 0);
336
337 s = bus_space_read_4(sc->sc_iot, sc->sc_ioh, BSC_S);
338 s &= BSC_S_CLKT|BSC_S_ERR|BSC_S_DONE;
339 KASSERT((s & BSC_S_DONE) != 0);
340 if (s != 0)
341 bus_space_write_4(sc->sc_iot, sc->sc_ioh, BSC_S, s);
342
343 done:
344 bsciic_dump_regs(sc);
345
346 bus_space_write_4(sc->sc_iot, sc->sc_ioh, BSC_DLEN, 0);
347
348 do {
349 s = bus_space_read_4(sc->sc_iot, sc->sc_ioh, BSC_S);
350 } while ((s & BSC_S_TA) != 0);
351
352 bsciic_dump_regs(sc);
353
354 s = bus_space_read_4(sc->sc_iot, sc->sc_ioh, BSC_S);
355 s &= BSC_S_CLKT|BSC_S_ERR|BSC_S_DONE;
356 if (s != 0)
357 bus_space_write_4(sc->sc_iot, sc->sc_ioh, BSC_S, s);
358
359 bsciic_dump_regs(sc);
360
361 return error;
362 }
363