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