meson_i2c.c revision 1.5 1 /* $NetBSD: meson_i2c.c,v 1.5 2025/09/16 11:55:16 thorpej Exp $ */
2
3 /*-
4 * Copyright (c) 2025 The NetBSD Foundation, Inc.
5 * All rights reserved.
6 *
7 * Written by Vincent Defert for The NetBSD Foundation, Inc.
8 *
9 * Redistribution and use in source and binary forms, with or without
10 * modification, are permitted provided that the following conditions
11 * are met:
12 * 1. Redistributions of source code must retain the above copyright
13 * notice, this list of conditions and the following disclaimer.
14 * 2. Redistributions in binary form must reproduce the above copyright
15 * notice, this list of conditions and the following disclaimer in the
16 * documentation and/or other materials provided with the distribution.
17 *
18 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
19 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
20 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
21 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
22 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
23 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
24 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
25 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
26 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
27 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
28 * POSSIBILITY OF SUCH DAMAGE.
29 */
30
31 #include <sys/cdefs.h>
32 __KERNEL_RCSID(1, "$NetBSD: meson_i2c.c,v 1.5 2025/09/16 11:55:16 thorpej Exp $");
33
34 #include <sys/param.h>
35 #include <sys/bus.h>
36 #include <sys/device.h>
37 #include <sys/intr.h>
38 #include <sys/systm.h>
39 #include <sys/time.h>
40 #include <sys/kmem.h>
41 #include <sys/mutex.h>
42 #include <sys/condvar.h>
43 #include <dev/i2c/i2cvar.h>
44 #include <dev/fdt/fdtvar.h>
45
46 #define MESONI2C_CTRL_REG 0x00
47 #define MESONI2C_CTRL_START __BIT(0)
48 #define MESONI2C_CTRL_ACK_IGNORE __BIT(1)
49 #define MESONI2C_CTRL_STATUS __BIT(2)
50 #define MESONI2C_CTRL_ERROR __BIT(3)
51 #define MESONI2C_CTRL_READ_DATA_SHIFT 8
52 #define MESONI2C_CTRL_READ_DATA_MASK __BITS(11, MESONI2C_CTRL_READ_DATA_SHIFT)
53 #define MESONI2C_CTRL_CLKDIV_SHIFT 12
54 #define MESONI2C_CTRL_CLKDIV_MASK __BITS(21, MESONI2C_CTRL_CLKDIV_SHIFT)
55 #define MESONI2C_CTRL_CLKDIVEXT_SHIFT 28
56 #define MESONI2C_CTRL_CLKDIVEXT_MASK __BITS(29, MESONI2C_CTRL_CLKDIVEXT_SHIFT)
57
58 #define MESONI2C_SLAVE_ADDR_REG 0x04
59 #define MESONI2C_SLAVE_ADDR_MASK __BITS(7, 0)
60 #define MESONI2C_SLAVE_SDA_FILTER_MASK __BITS(10, 8)
61 #define MESONI2C_SLAVE_SCL_FILTER_MASK __BITS(13, 11)
62 #define MESONI2C_SLAVE_SCL_LOW_SHIFT 16
63 #define MESONI2C_SLAVE_SCL_LOW_MASK __BITS(27, MESONI2C_SLAVE_SCL_LOW_SHIFT)
64 #define MESONI2C_SLAVE_SCL_LOW_EN __BIT(28)
65
66 #define MESONI2C_TOKEN_LIST_REG0 0x08
67 #define MESONI2C_TOKEN_LIST_REG1 0x0c
68 #define MESONI2C_TOKEN_WDATA_REG0 0x10
69 #define MESONI2C_TOKEN_WDATA_REG1 0x14
70 #define MESONI2C_TOKEN_RDATA_REG0 0x18
71 #define MESONI2C_TOKEN_RDATA_REG1 0x1c
72
73 #define MESONI2C_TOKEN_BITS 4
74 #define MESONI2C_TOKEN_MASK ((1 << MESONI2C_TOKEN_BITS) - 1)
75 #define MESONI2C_TOKEN_REG_HALF (32 / MESONI2C_TOKEN_BITS)
76 #define MESONI2C_TOKEN_REG_FULL (64 / MESONI2C_TOKEN_BITS)
77
78 #define MESONI2C_DATA_BITS 8
79 #define MESONI2C_DATA_MASK ((1 << MESONI2C_DATA_BITS) - 1)
80 #define MESONI2C_DATA_REG_HALF (32 / MESONI2C_DATA_BITS)
81 #define MESONI2C_DATA_REG_FULL (64 / MESONI2C_DATA_BITS)
82
83 #define I2C_TIMEOUT_MS 1000
84 #define FILTER_DELAY 15
85
86 enum mesoni2c_token {
87 TOKEN_END = 0,
88 TOKEN_START,
89 TOKEN_SLAVE_ADDR_WRITE,
90 TOKEN_SLAVE_ADDR_READ,
91 TOKEN_DATA,
92 TOKEN_DATA_LAST,
93 TOKEN_STOP,
94 };
95
96 enum mesoni2c_type {
97 TYPE_MESON6,
98 TYPE_GXBB,
99 TYPE_AXG,
100 };
101
102 struct mesoni2c_softc {
103 device_t sc_dev;
104 bus_space_tag_t sc_bst;
105 bus_space_handle_t sc_bsh;
106 struct clk *sc_clk;
107 u_int sc_clkfreq;
108 struct i2c_controller sc_ic;
109 kcondvar_t sc_cv;
110 kmutex_t sc_mtx;
111 void *sc_ih;
112
113 u_int sc_token_index;
114 u_int sc_wdata_index;
115 u_int sc_rdata_index;
116
117 const uint8_t *sc_cmdbuf;
118 size_t sc_cmdlen;
119 uint8_t *sc_databuf;
120 size_t sc_datalen;
121 i2c_op_t sc_op;
122
123 size_t sc_curlen;
124 i2c_op_t sc_curop;
125 int sc_sendingCmd;
126 int sc_error;
127 };
128
129 static void mesoni2c_set_mask(struct mesoni2c_softc *sc, bus_size_t reg, uint32_t mask, uint32_t value);
130 static void mesoni2c_reset_state(struct mesoni2c_softc *sc);
131 static int mesoni2c_push_token(struct mesoni2c_softc *sc, enum mesoni2c_token token);
132 static void mesoni2c_write_byte(struct mesoni2c_softc *sc, uint8_t data);
133 static uint8_t mesoni2c_get_byte(struct mesoni2c_softc *sc);
134 static void mesoni2c_prepare_xfer(struct mesoni2c_softc *sc, i2c_op_t op);
135 static void mesoni2c_partial_xfer(struct mesoni2c_softc *sc);
136 static int mesoni2c_exec(void *priv, i2c_op_t op, i2c_addr_t addr, const void *cmdbuf, size_t cmdlen, void *buf, size_t buflen, int flags);
137 static int mesoni2c_intr(void *arg);
138 static void mesoni2c_set_clock_div_meson6(struct mesoni2c_softc *sc);
139 static void mesoni2c_set_clock_div_gxbb_axg(struct mesoni2c_softc *sc);
140 static int mesoni2c_match(device_t parent, cfdata_t cf, void *aux);
141 static void mesoni2c_attach(device_t parent, device_t self, void *aux);
142
143 CFATTACH_DECL_NEW(meson_i2c, sizeof(struct mesoni2c_softc),
144 mesoni2c_match, mesoni2c_attach, NULL, NULL);
145
146 static const struct device_compatible_entry compat_data[] = {
147 { .compat = "amlogic,meson6-i2c", .value = TYPE_MESON6 },
148 { .compat = "amlogic,meson-gxbb-i2c", .value = TYPE_GXBB },
149 { .compat = "amlogic,meson-axg-i2c", .value = TYPE_AXG },
150 DEVICE_COMPAT_EOL
151 };
152
153 #define RD4(sc, reg) \
154 bus_space_read_4((sc)->sc_bst, (sc)->sc_bsh, (reg))
155
156 #define WR4(sc, reg, val) \
157 bus_space_write_4((sc)->sc_bst, (sc)->sc_bsh, (reg), (val))
158
159 static void
160 mesoni2c_set_mask(struct mesoni2c_softc *sc, bus_size_t reg, uint32_t mask,
161 uint32_t value)
162 {
163 uint32_t data = RD4(sc, reg);
164 data &= ~mask;
165 data |= value & mask;
166 WR4(sc, reg, data);
167 }
168
169 static void
170 mesoni2c_reset_state(struct mesoni2c_softc *sc)
171 {
172 sc->sc_token_index = 0;
173 sc->sc_wdata_index = 0;
174 sc->sc_rdata_index = 0;
175 }
176
177 static int
178 mesoni2c_push_token(struct mesoni2c_softc *sc, enum mesoni2c_token token)
179 {
180 bus_size_t reg;
181 u_int pos;
182
183 if (sc->sc_token_index >= MESONI2C_TOKEN_REG_HALF) {
184 reg = MESONI2C_TOKEN_LIST_REG1;
185 pos = sc->sc_token_index - MESONI2C_TOKEN_REG_HALF;
186 } else {
187 reg = MESONI2C_TOKEN_LIST_REG0;
188 pos = sc->sc_token_index;
189 }
190
191 sc->sc_token_index++;
192 pos *= MESONI2C_TOKEN_BITS;
193 mesoni2c_set_mask(sc, reg, MESONI2C_TOKEN_MASK << pos, token << pos);
194
195 return sc->sc_token_index == MESONI2C_TOKEN_REG_FULL;
196 }
197
198 static void
199 mesoni2c_write_byte(struct mesoni2c_softc *sc, uint8_t data)
200 {
201 bus_size_t reg;
202 u_int pos;
203
204 if (sc->sc_wdata_index >= MESONI2C_DATA_REG_HALF) {
205 reg = MESONI2C_TOKEN_WDATA_REG1;
206 pos = sc->sc_wdata_index - MESONI2C_DATA_REG_HALF;
207 } else {
208 reg = MESONI2C_TOKEN_WDATA_REG0;
209 pos = sc->sc_wdata_index;
210 }
211
212 sc->sc_wdata_index++;
213 pos *= MESONI2C_DATA_BITS;
214 mesoni2c_set_mask(sc, reg, MESONI2C_DATA_MASK << pos, ((uint32_t) data) << pos);
215 mesoni2c_push_token(sc, TOKEN_DATA);
216 }
217
218 static uint8_t
219 mesoni2c_get_byte(struct mesoni2c_softc *sc)
220 {
221 bus_size_t reg;
222 u_int pos;
223
224 if (sc->sc_rdata_index >= MESONI2C_DATA_REG_HALF) {
225 reg = MESONI2C_TOKEN_RDATA_REG1;
226 pos = sc->sc_rdata_index - MESONI2C_DATA_REG_HALF;
227 } else {
228 reg = MESONI2C_TOKEN_RDATA_REG0;
229 pos = sc->sc_rdata_index;
230 }
231
232 sc->sc_rdata_index++;
233 pos *= MESONI2C_DATA_BITS;
234
235 return (RD4(sc, reg) >> pos) & MESONI2C_DATA_MASK;
236 }
237
238 static void
239 mesoni2c_prepare_xfer(struct mesoni2c_softc *sc, i2c_op_t op)
240 {
241 mesoni2c_reset_state(sc);
242 mesoni2c_push_token(sc, TOKEN_START);
243 mesoni2c_push_token(sc, I2C_OP_WRITE_P(op) ? TOKEN_SLAVE_ADDR_WRITE : TOKEN_SLAVE_ADDR_READ);
244 }
245
246 static void
247 mesoni2c_partial_xfer(struct mesoni2c_softc *sc)
248 {
249 int dataBufferFree = MESONI2C_DATA_REG_FULL;
250
251 while (sc->sc_curlen && dataBufferFree) {
252 sc->sc_curlen--;
253 dataBufferFree--;
254
255 if (I2C_OP_WRITE_P(sc->sc_curop)) {
256 if (sc->sc_sendingCmd) {
257 uint8_t c = *(sc->sc_cmdbuf++);
258 mesoni2c_write_byte(sc, c);
259 } else {
260 mesoni2c_write_byte(sc, *(sc->sc_databuf++));
261 }
262 } else {
263 mesoni2c_push_token(sc, sc->sc_curlen ? TOKEN_DATA : TOKEN_DATA_LAST);
264 }
265 }
266
267 if (sc->sc_curlen == 0 && I2C_OP_STOP_P(sc->sc_curop)) {
268 mesoni2c_push_token(sc, TOKEN_STOP);
269 }
270
271 mesoni2c_push_token(sc, TOKEN_END);
272
273 mesoni2c_set_mask(sc, MESONI2C_CTRL_REG, MESONI2C_CTRL_START, 0);
274 mesoni2c_set_mask(sc, MESONI2C_CTRL_REG, MESONI2C_CTRL_START, 1);
275 }
276
277 static int
278 mesoni2c_exec(void *priv, i2c_op_t op, i2c_addr_t addr, const void *cmdbuf,
279 size_t cmdlen, void *databuf, size_t datalen, int flags)
280 {
281 struct mesoni2c_softc * const sc = priv;
282
283 mutex_enter(&sc->sc_mtx);
284
285 sc->sc_cmdbuf = cmdbuf;
286 sc->sc_cmdlen = cmdlen;
287 sc->sc_databuf = databuf;
288 sc->sc_datalen = datalen;
289 sc->sc_op = op;
290 sc->sc_error = 0;
291
292 mesoni2c_set_mask(sc, MESONI2C_SLAVE_ADDR_REG, MESONI2C_SLAVE_ADDR_MASK, addr << 1);
293
294 if (cmdlen) {
295 sc->sc_curlen = cmdlen;
296 sc->sc_curop = datalen ? I2C_OP_WRITE : op;
297 sc->sc_sendingCmd = 1;
298 } else {
299 sc->sc_curlen = datalen;
300 sc->sc_curop = op;
301 sc->sc_sendingCmd = 0;
302 }
303
304 mesoni2c_prepare_xfer(sc, sc->sc_curop);
305 mesoni2c_partial_xfer(sc);
306
307 if (cv_timedwait(&sc->sc_cv, &sc->sc_mtx, mstohz(I2C_TIMEOUT_MS)) == EWOULDBLOCK) {
308 sc->sc_error = EIO;
309 }
310
311 mutex_exit(&sc->sc_mtx);
312
313 return sc->sc_error;
314 }
315
316 static int
317 mesoni2c_intr(void *arg)
318 {
319 struct mesoni2c_softc *sc = arg;
320 int done = 0;
321
322 mutex_enter(&sc->sc_mtx);
323
324 if (RD4(sc, MESONI2C_CTRL_REG) & MESONI2C_CTRL_ERROR) {
325 /*
326 * The ERROR bit is set when the ACK_IGNORE bit is cleared
327 * in MESONI2C_CTRL_REG and the device didn't respond with
328 * an ACK. In this case, the I2C controller automatically
329 * generates a STOP condition.
330 */
331 sc->sc_error = EIO;
332 done = 1;
333 } else {
334 if (I2C_OP_READ_P(sc->sc_curop)) {
335 /* Read data bytes */
336 u_int count = (RD4(sc, MESONI2C_CTRL_REG) & MESONI2C_CTRL_READ_DATA_MASK)
337 >> MESONI2C_CTRL_READ_DATA_SHIFT;
338
339 while (count--) {
340 *(sc->sc_databuf++) = mesoni2c_get_byte(sc);
341 }
342 }
343
344 if (sc->sc_curlen) {
345 /* Continue transfer */
346 mesoni2c_reset_state(sc);
347 mesoni2c_partial_xfer(sc);
348 } else {
349 if (sc->sc_sendingCmd && sc->sc_datalen) {
350 /*
351 * We've just finished transfering the command
352 * bytes, we must now transfer the data.
353 */
354 sc->sc_curlen = sc->sc_datalen;
355 sc->sc_curop = sc->sc_op;
356 sc->sc_sendingCmd = 0;
357
358 if (I2C_OP_READ_P(sc->sc_curop)) {
359 mesoni2c_prepare_xfer(sc, sc->sc_curop);
360 } else {
361 mesoni2c_reset_state(sc);
362 }
363
364 mesoni2c_partial_xfer(sc);
365 } else {
366 done = 1;
367 }
368 }
369 }
370
371 if (done) {
372 /* Tell mesoni2c_exec() we're done. */
373 cv_broadcast(&sc->sc_cv);
374 }
375
376 mutex_exit(&sc->sc_mtx);
377
378 return 1;
379 }
380
381 static void
382 mesoni2c_set_clock_div_meson6(struct mesoni2c_softc *sc)
383 {
384 u_int rate = clk_get_rate(sc->sc_clk);
385 u_int div = howmany(rate, sc->sc_clkfreq) - FILTER_DELAY;
386 div = howmany(div, 4);
387
388 /* Set prescaler */
389 mesoni2c_set_mask(sc, MESONI2C_CTRL_REG, MESONI2C_CTRL_CLKDIV_MASK, (div & __BITS(9, 0)) << MESONI2C_CTRL_CLKDIV_SHIFT);
390 mesoni2c_set_mask(sc, MESONI2C_CTRL_REG, MESONI2C_CTRL_CLKDIVEXT_MASK, (div >> 10) << MESONI2C_CTRL_CLKDIVEXT_SHIFT);
391
392 /* Disable HIGH/LOW mode */
393 mesoni2c_set_mask(sc, MESONI2C_SLAVE_ADDR_REG, MESONI2C_SLAVE_SCL_LOW_EN, 0);
394 }
395
396 static void
397 mesoni2c_set_clock_div_gxbb_axg(struct mesoni2c_softc *sc)
398 {
399 u_int rate = clk_get_rate(sc->sc_clk);
400 u_int divh, divl;
401
402 /*
403 * According to I2C-BUS Spec 2.1, in FAST-MODE, the minimum
404 * LOW period is 1.3uS, and minimum HIGH is least 0.6us.
405 * For
406 * 400000 freq, the period is 2.5us. To keep within the specs,
407 * give 40% of period to HIGH and 60% to LOW. This means HIGH
408 * at 1.0us and LOW 1.5us.
409 * The same applies for Fast-mode plus, where LOW is 0.5us and
410 * HIGH is 0.26us.
411 * Duty = H/(H + L) = 2/5
412 */
413 if (sc->sc_clkfreq <= 100000) {
414 divh = howmany(rate, sc->sc_clkfreq);
415 divl = howmany(divh, 4);
416 divh = howmany(divh, 2) - FILTER_DELAY;
417 } else {
418 divh = howmany(rate * 2, sc->sc_clkfreq * 5) - FILTER_DELAY;
419 divl = howmany(rate * 3, sc->sc_clkfreq * 5 * 2);
420 }
421
422 /* Set prescaler */
423 mesoni2c_set_mask(sc, MESONI2C_CTRL_REG, MESONI2C_CTRL_CLKDIV_MASK, (divh & __BITS(9, 0)) << MESONI2C_CTRL_CLKDIV_SHIFT);
424 mesoni2c_set_mask(sc, MESONI2C_CTRL_REG, MESONI2C_CTRL_CLKDIVEXT_MASK, (divh >> 10) << MESONI2C_CTRL_CLKDIVEXT_SHIFT);
425
426 /* Set SCL low delay */
427 mesoni2c_set_mask(sc, MESONI2C_SLAVE_ADDR_REG, MESONI2C_SLAVE_SCL_LOW_MASK, divl << MESONI2C_SLAVE_SCL_LOW_SHIFT);
428
429 /* Enable HIGH/LOW mode */
430 mesoni2c_set_mask(sc, MESONI2C_SLAVE_ADDR_REG, MESONI2C_SLAVE_SCL_LOW_EN, MESONI2C_SLAVE_SCL_LOW_EN);
431 }
432
433 static int
434 mesoni2c_match(device_t parent, cfdata_t cf, void *aux)
435 {
436 struct fdt_attach_args * const faa = aux;
437
438 return of_compatible_match(faa->faa_phandle, compat_data);
439 }
440
441 static void
442 mesoni2c_attach(device_t parent, device_t self, void *aux)
443 {
444 struct mesoni2c_softc * const sc = device_private(self);
445 struct fdt_attach_args * const faa = aux;
446 const int phandle = faa->faa_phandle;
447 bus_addr_t addr;
448 bus_size_t size;
449 char intrstr[128];
450
451 if (fdtbus_get_reg(phandle, 0, &addr, &size) != 0) {
452 aprint_error_dev(self, "couldn't get registers\n");
453 return;
454 }
455
456 sc->sc_clk = fdtbus_clock_get_index(phandle, 0);
457
458 if (sc->sc_clk == NULL || clk_enable(sc->sc_clk) != 0) {
459 aprint_error_dev(self, "couldn't enable clock\n");
460 return;
461 }
462
463 sc->sc_dev = self;
464 sc->sc_bst = faa->faa_bst;
465
466 if (bus_space_map(sc->sc_bst, addr, size, 0, &sc->sc_bsh) != 0) {
467 aprint_error_dev(self, "couldn't map registers\n");
468 return;
469 }
470
471 fdtbus_clock_assign(phandle);
472
473 if (of_getprop_uint32(phandle, "clock-frequency", &sc->sc_clkfreq)) {
474 sc->sc_clkfreq = 100000;
475 } else {
476 if (sc->sc_clkfreq < 100000) {
477 sc->sc_clkfreq = 100000;
478 } else if (sc->sc_clkfreq > 400000) {
479 sc->sc_clkfreq = 400000;
480 }
481 }
482
483 aprint_naive("\n");
484 aprint_normal(": Meson I2C (%u Hz)\n", sc->sc_clkfreq);
485
486 enum mesoni2c_type type = of_compatible_lookup(phandle, compat_data)->value;
487
488 switch (type) {
489 case TYPE_MESON6:
490 mesoni2c_set_clock_div_meson6(sc);
491 break;
492
493 case TYPE_GXBB:
494 case TYPE_AXG:
495 mesoni2c_set_clock_div_gxbb_axg(sc);
496 break;
497 }
498
499 mutex_init(&sc->sc_mtx, MUTEX_DEFAULT, IPL_VM);
500 cv_init(&sc->sc_cv, "mesoniic");
501
502 if (!fdtbus_intr_str(phandle, 0, intrstr, sizeof(intrstr))) {
503 aprint_error_dev(self, "failed to decode interrupt\n");
504 return;
505 }
506
507 sc->sc_ih = fdtbus_intr_establish_xname(phandle, 0, IPL_VM, 0,
508 mesoni2c_intr, sc, device_xname(self));
509
510 if (sc->sc_ih == NULL) {
511 aprint_error_dev(self, "couldn't establish interrupt\n");
512 return;
513 }
514
515 aprint_normal_dev(self, "interrupting on %s\n", intrstr);
516
517 iic_tag_init(&sc->sc_ic);
518 sc->sc_ic.ic_cookie = sc;
519 sc->sc_ic.ic_exec = mesoni2c_exec;
520
521 iicbus_attach(self, &sc->sc_ic);
522 }
523