1 1.10 thorpej /* $NetBSD: jziic.c,v 1.10 2025/09/15 13:23:02 thorpej Exp $ */ 2 1.1 macallan 3 1.1 macallan /*- 4 1.1 macallan * Copyright (c) 2015 Michael Lorenz 5 1.1 macallan * All rights reserved. 6 1.1 macallan * 7 1.1 macallan * Redistribution and use in source and binary forms, with or without 8 1.1 macallan * modification, are permitted provided that the following conditions 9 1.1 macallan * are met: 10 1.1 macallan * 1. Redistributions of source code must retain the above copyright 11 1.1 macallan * notice, this list of conditions and the following disclaimer. 12 1.1 macallan * 2. Redistributions in binary form must reproduce the above copyright 13 1.1 macallan * notice, this list of conditions and the following disclaimer in the 14 1.1 macallan * documentation and/or other materials provided with the distribution. 15 1.1 macallan * 16 1.1 macallan * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 17 1.1 macallan * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 18 1.1 macallan * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 19 1.1 macallan * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 20 1.1 macallan * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 21 1.1 macallan * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 22 1.1 macallan * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 23 1.1 macallan * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 24 1.1 macallan * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 25 1.1 macallan * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 26 1.1 macallan * POSSIBILITY OF SUCH DAMAGE. 27 1.1 macallan */ 28 1.1 macallan 29 1.1 macallan #include <sys/cdefs.h> 30 1.10 thorpej __KERNEL_RCSID(0, "$NetBSD: jziic.c,v 1.10 2025/09/15 13:23:02 thorpej Exp $"); 31 1.1 macallan 32 1.1 macallan /* 33 1.1 macallan * a preliminary driver for JZ4780's on-chip SMBus controllers 34 1.1 macallan * - needs more error handling and interrupt support 35 1.4 skrll * - transfers can't be more than the chip's FIFO, supposedly 16 bytes per 36 1.1 macallan * direction 37 1.1 macallan * so, good enough for RTCs but not much else yet 38 1.1 macallan */ 39 1.1 macallan 40 1.1 macallan #include <sys/param.h> 41 1.1 macallan #include <sys/systm.h> 42 1.2 macallan #include <sys/kernel.h> 43 1.1 macallan #include <sys/device.h> 44 1.1 macallan #include <sys/mutex.h> 45 1.1 macallan #include <sys/bus.h> 46 1.1 macallan #include <sys/mutex.h> 47 1.2 macallan #include <sys/condvar.h> 48 1.1 macallan 49 1.1 macallan #include <mips/ingenic/ingenic_var.h> 50 1.1 macallan #include <mips/ingenic/ingenic_regs.h> 51 1.1 macallan 52 1.1 macallan #include <dev/i2c/i2cvar.h> 53 1.1 macallan 54 1.1 macallan #include "opt_ingenic.h" 55 1.1 macallan 56 1.1 macallan #ifdef JZIIC_DEBUG 57 1.1 macallan #define DPRINTF aprint_error 58 1.2 macallan #define STATIC /* */ 59 1.1 macallan #else 60 1.1 macallan #define DPRINTF while (0) printf 61 1.2 macallan #define STATIC static 62 1.1 macallan #endif 63 1.2 macallan 64 1.2 macallan STATIC int jziic_match(device_t, struct cfdata *, void *); 65 1.2 macallan STATIC void jziic_attach(device_t, device_t, void *); 66 1.1 macallan 67 1.1 macallan struct jziic_softc { 68 1.1 macallan device_t sc_dev; 69 1.1 macallan bus_space_tag_t sc_memt; 70 1.1 macallan bus_space_handle_t sc_memh; 71 1.1 macallan struct i2c_controller sc_i2c; 72 1.6 thorpej kmutex_t sc_cvlock; 73 1.1 macallan uint32_t sc_pclk; 74 1.2 macallan /* stuff used for interrupt-driven transfers */ 75 1.2 macallan const uint8_t *sc_cmd; 76 1.2 macallan uint8_t *sc_buf; 77 1.2 macallan uint32_t sc_cmdlen, sc_buflen; 78 1.2 macallan uint32_t sc_cmdptr, sc_bufptr, sc_rds; 79 1.2 macallan uint32_t sc_abort; 80 1.2 macallan kcondvar_t sc_ping; 81 1.2 macallan uint8_t sc_txbuf[256]; 82 1.2 macallan boolean_t sc_reading; 83 1.1 macallan }; 84 1.1 macallan 85 1.1 macallan CFATTACH_DECL_NEW(jziic, sizeof(struct jziic_softc), 86 1.1 macallan jziic_match, jziic_attach, NULL, NULL); 87 1.1 macallan 88 1.2 macallan STATIC int jziic_enable(struct jziic_softc *); 89 1.2 macallan STATIC void jziic_disable(struct jziic_softc *); 90 1.2 macallan STATIC int jziic_wait(struct jziic_softc *); 91 1.2 macallan STATIC void jziic_set_speed(struct jziic_softc *); 92 1.2 macallan STATIC int jziic_i2c_exec(void *, i2c_op_t, i2c_addr_t, const void *, size_t, 93 1.1 macallan void *, size_t, int); 94 1.2 macallan STATIC int jziic_i2c_exec_poll(struct jziic_softc *, i2c_op_t, i2c_addr_t, 95 1.2 macallan const void *, size_t, void *, size_t, int); 96 1.2 macallan STATIC int jziic_i2c_exec_intr(struct jziic_softc *, i2c_op_t, i2c_addr_t, 97 1.2 macallan const void *, size_t, void *, size_t, int); 98 1.2 macallan 99 1.2 macallan STATIC int jziic_intr(void *); 100 1.1 macallan 101 1.1 macallan 102 1.1 macallan /* ARGSUSED */ 103 1.2 macallan STATIC int 104 1.1 macallan jziic_match(device_t parent, struct cfdata *match, void *aux) 105 1.1 macallan { 106 1.1 macallan struct apbus_attach_args *aa = aux; 107 1.1 macallan 108 1.1 macallan if (strcmp(aa->aa_name, "jziic") != 0) 109 1.1 macallan return 0; 110 1.1 macallan 111 1.1 macallan return 1; 112 1.1 macallan } 113 1.1 macallan 114 1.1 macallan /* ARGSUSED */ 115 1.2 macallan STATIC void 116 1.1 macallan jziic_attach(device_t parent, device_t self, void *aux) 117 1.1 macallan { 118 1.1 macallan struct jziic_softc *sc = device_private(self); 119 1.1 macallan struct apbus_attach_args *aa = aux; 120 1.1 macallan int error; 121 1.2 macallan void *ih; 122 1.1 macallan #ifdef JZIIC_DEBUG 123 1.1 macallan int i; 124 1.1 macallan uint8_t in[1] = {0}, out[16]; 125 1.1 macallan #endif 126 1.1 macallan 127 1.1 macallan sc->sc_dev = self; 128 1.1 macallan sc->sc_pclk = aa->aa_pclk; 129 1.1 macallan sc->sc_memt = aa->aa_bst; 130 1.1 macallan 131 1.1 macallan error = bus_space_map(aa->aa_bst, aa->aa_addr, 0x100, 0, &sc->sc_memh); 132 1.1 macallan if (error) { 133 1.1 macallan aprint_error_dev(self, 134 1.1 macallan "can't map registers for %s: %d\n", aa->aa_name, error); 135 1.1 macallan return; 136 1.1 macallan } 137 1.1 macallan 138 1.2 macallan mutex_init(&sc->sc_cvlock, MUTEX_DEFAULT, IPL_NONE); 139 1.2 macallan cv_init(&sc->sc_ping, device_xname(self)); 140 1.1 macallan 141 1.1 macallan aprint_naive(": SMBus controller\n"); 142 1.1 macallan aprint_normal(": SMBus controller\n"); 143 1.1 macallan 144 1.2 macallan ih = evbmips_intr_establish(aa->aa_irq, jziic_intr, sc); 145 1.1 macallan 146 1.1 macallan if (ih == NULL) { 147 1.1 macallan aprint_error_dev(self, "failed to establish interrupt %d\n", 148 1.1 macallan aa->aa_irq); 149 1.1 macallan goto fail; 150 1.1 macallan } 151 1.1 macallan 152 1.1 macallan #ifdef JZIIC_DEBUG 153 1.1 macallan if (jziic_i2c_exec(sc, I2C_OP_READ_WITH_STOP, 0x51, in, 1, out, 9, 0) 154 1.1 macallan >= 0) { 155 1.1 macallan for (i = 0; i < 9; i++) 156 1.1 macallan printf(" %02x", out[i]); 157 1.1 macallan printf("\n"); 158 1.1 macallan delay(1000000); 159 1.1 macallan jziic_i2c_exec(sc, I2C_OP_READ_WITH_STOP, 160 1.1 macallan 0x51, in, 1, out, 9, 0); 161 1.1 macallan for (i = 0; i < 9; i++) 162 1.1 macallan printf(" %02x", out[i]); 163 1.1 macallan printf("\n"); 164 1.1 macallan delay(1000000); 165 1.1 macallan jziic_i2c_exec(sc, I2C_OP_READ_WITH_STOP, 166 1.1 macallan 0x51, in, 1, out, 9, 0); 167 1.1 macallan for (i = 0; i < 9; i++) 168 1.1 macallan printf(" %02x", out[i]); 169 1.1 macallan printf("\n"); 170 1.1 macallan } 171 1.1 macallan #endif 172 1.1 macallan 173 1.1 macallan /* fill in the i2c tag */ 174 1.6 thorpej iic_tag_init(&sc->sc_i2c); 175 1.1 macallan sc->sc_i2c.ic_cookie = sc; 176 1.1 macallan sc->sc_i2c.ic_exec = jziic_i2c_exec; 177 1.1 macallan 178 1.10 thorpej iicbus_attach(sc->sc_dev, &sc->sc_i2c); 179 1.1 macallan 180 1.1 macallan return; 181 1.1 macallan 182 1.1 macallan fail: 183 1.1 macallan if (ih) { 184 1.1 macallan evbmips_intr_disestablish(ih); 185 1.1 macallan } 186 1.1 macallan bus_space_unmap(sc->sc_memt, sc->sc_memh, 0x100); 187 1.1 macallan } 188 1.1 macallan 189 1.2 macallan STATIC int 190 1.1 macallan jziic_enable(struct jziic_softc *sc) 191 1.1 macallan { 192 1.1 macallan int bail = 100000; 193 1.1 macallan uint32_t reg; 194 1.1 macallan 195 1.1 macallan bus_space_write_4(sc->sc_memt, sc->sc_memh, JZ_SMBENB, JZ_ENABLE); 196 1.1 macallan reg = bus_space_read_4(sc->sc_memt, sc->sc_memh, JZ_SMBENBST); 197 1.1 macallan DPRINTF("status: %02x\n", reg); 198 1.1 macallan while ((bail > 0) && (reg == 0)) { 199 1.1 macallan bail--; 200 1.1 macallan reg = bus_space_read_4(sc->sc_memt, sc->sc_memh, JZ_SMBENBST); 201 1.1 macallan } 202 1.1 macallan DPRINTF("bail: %d\n", bail); 203 1.1 macallan return (reg != 0); 204 1.1 macallan } 205 1.1 macallan 206 1.2 macallan STATIC void 207 1.1 macallan jziic_disable(struct jziic_softc *sc) 208 1.1 macallan { 209 1.1 macallan int bail = 100000; 210 1.1 macallan uint32_t reg; 211 1.1 macallan 212 1.1 macallan bus_space_write_4(sc->sc_memt, sc->sc_memh, JZ_SMBENB, 0); 213 1.1 macallan reg = bus_space_read_4(sc->sc_memt, sc->sc_memh, JZ_SMBENBST); 214 1.1 macallan DPRINTF("status: %02x\n", reg); 215 1.1 macallan while ((bail > 0) && (reg != 0)) { 216 1.1 macallan bail--; 217 1.1 macallan reg = bus_space_read_4(sc->sc_memt, sc->sc_memh, JZ_SMBENBST); 218 1.1 macallan } 219 1.1 macallan DPRINTF("bail: %d\n", bail); 220 1.1 macallan } 221 1.1 macallan 222 1.2 macallan STATIC int 223 1.1 macallan jziic_wait(struct jziic_softc *sc) 224 1.1 macallan { 225 1.1 macallan uint32_t reg; 226 1.1 macallan int bail = 10000; 227 1.1 macallan reg = bus_space_read_4(sc->sc_memt, sc->sc_memh, JZ_SMBST); 228 1.1 macallan while ((reg & JZ_MSTACT) && (bail > 0)) { 229 1.1 macallan delay(100); 230 1.1 macallan reg = bus_space_read_4(sc->sc_memt, sc->sc_memh, JZ_SMBST); 231 1.1 macallan bail--; 232 1.4 skrll } 233 1.1 macallan return ((reg & JZ_MSTACT) == 0); 234 1.1 macallan } 235 1.1 macallan 236 1.2 macallan STATIC void 237 1.2 macallan jziic_set_speed(struct jziic_softc *sc) 238 1.1 macallan { 239 1.1 macallan int ticks, hcnt, lcnt, hold, setup; 240 1.1 macallan 241 1.1 macallan /* PCLK ticks per SMBus cycle */ 242 1.1 macallan ticks = sc->sc_pclk / 100; /* assuming 100kHz for now */ 243 1.1 macallan hcnt = (ticks * 40 / (40 + 47)) - 8; 244 1.1 macallan lcnt = (ticks * 47 / (40 + 47)) - 1; 245 1.1 macallan hold = sc->sc_pclk * 4 / 10000 - 1; /* ... * 400 / 1000000 ... */ 246 1.5 riastrad hold = uimax(1, hold); 247 1.1 macallan hold |= JZ_HDENB; 248 1.1 macallan setup = sc->sc_pclk * 3 / 10000 + 1; /* ... * 300 / 1000000 ... */ 249 1.1 macallan DPRINTF("hcnt %d lcnt %d hold %d\n", hcnt, lcnt, hold); 250 1.1 macallan bus_space_write_4(sc->sc_memt, sc->sc_memh, JZ_SMBSHCNT, hcnt); 251 1.1 macallan bus_space_write_4(sc->sc_memt, sc->sc_memh, JZ_SMBSLCNT, lcnt); 252 1.1 macallan bus_space_write_4(sc->sc_memt, sc->sc_memh, JZ_SMBSDAHD, hold); 253 1.1 macallan bus_space_write_4(sc->sc_memt, sc->sc_memh, JZ_SMBSDASU, setup); 254 1.1 macallan bus_space_write_4(sc->sc_memt, sc->sc_memh, JZ_SMBCON, 255 1.1 macallan JZ_SLVDIS | JZ_STPHLD | JZ_REST | JZ_SPD_100KB | JZ_MD); 256 1.1 macallan (void)bus_space_read_4(sc->sc_memt, sc->sc_memh, JZ_SMBCINT); 257 1.2 macallan } 258 1.2 macallan 259 1.2 macallan STATIC int 260 1.2 macallan jziic_i2c_exec(void *cookie, i2c_op_t op, i2c_addr_t addr, const void *vcmd, 261 1.2 macallan size_t cmdlen, void *vbuf, size_t buflen, int flags) 262 1.2 macallan { 263 1.2 macallan struct jziic_softc *sc = cookie; 264 1.2 macallan 265 1.7 thorpej if (flags & I2C_F_POLL) { 266 1.2 macallan return jziic_i2c_exec_poll(sc, op, addr, vcmd, cmdlen, vbuf, 267 1.2 macallan buflen, flags); 268 1.2 macallan } else { 269 1.2 macallan #ifdef JZIIC_DEBUG 270 1.2 macallan uint8_t *b = vbuf; 271 1.2 macallan int i, ret; 272 1.2 macallan 273 1.2 macallan memset(vbuf, 0, buflen); 274 1.2 macallan jziic_i2c_exec_intr(sc, op, addr, vcmd, cmdlen, vbuf, 275 1.2 macallan buflen, flags); 276 1.2 macallan for (i = 0; i < buflen; i++) { 277 1.2 macallan printf(" %02x", b[i]); 278 1.2 macallan } 279 1.2 macallan printf("\n"); 280 1.2 macallan ret = jziic_i2c_exec_poll(sc, op, addr, vcmd, cmdlen, vbuf, 281 1.2 macallan buflen, flags); 282 1.2 macallan for (i = 0; i < buflen; i++) { 283 1.2 macallan printf(" %02x", b[i]); 284 1.2 macallan } 285 1.2 macallan printf("\n"); 286 1.2 macallan return ret; 287 1.2 macallan #else 288 1.2 macallan return jziic_i2c_exec_intr(sc, op, addr, vcmd, cmdlen, vbuf, 289 1.2 macallan buflen, flags); 290 1.2 macallan #endif 291 1.2 macallan } 292 1.2 macallan } 293 1.2 macallan 294 1.2 macallan STATIC int 295 1.2 macallan jziic_i2c_exec_poll(struct jziic_softc *sc, i2c_op_t op, i2c_addr_t addr, 296 1.2 macallan const void *vcmd, size_t cmdlen, void *vbuf, size_t buflen, int flags) 297 1.2 macallan { 298 1.2 macallan int i, bail = 10000, ret = 0; 299 1.2 macallan uint32_t abort; 300 1.2 macallan uint8_t *rx, data; 301 1.2 macallan const uint8_t *tx; 302 1.2 macallan 303 1.2 macallan tx = vcmd; 304 1.2 macallan rx = vbuf; 305 1.2 macallan 306 1.2 macallan DPRINTF("%s: 0x%02x %d %d\n", __func__, addr, cmdlen, buflen); 307 1.2 macallan 308 1.2 macallan jziic_disable(sc); 309 1.2 macallan 310 1.2 macallan /* we're polling, so disable interrupts */ 311 1.2 macallan bus_space_write_4(sc->sc_memt, sc->sc_memh, JZ_SMBINTM, 0); 312 1.2 macallan 313 1.2 macallan jziic_set_speed(sc); 314 1.1 macallan jziic_wait(sc); 315 1.1 macallan /* try to talk... */ 316 1.1 macallan 317 1.1 macallan if (!jziic_enable(sc)) { 318 1.1 macallan ret = -1; 319 1.1 macallan goto bork; 320 1.1 macallan } 321 1.2 macallan bus_space_write_4(sc->sc_memt, sc->sc_memh, JZ_SMBINTM, 0); 322 1.1 macallan 323 1.1 macallan bus_space_write_4(sc->sc_memt, sc->sc_memh, JZ_SMBTAR, addr); 324 1.1 macallan jziic_wait(sc); 325 1.1 macallan DPRINTF("st: %02x\n", 326 1.1 macallan bus_space_read_4(sc->sc_memt, sc->sc_memh, JZ_SMBST)); 327 1.1 macallan DPRINTF("wr int: %02x\n", 328 1.1 macallan bus_space_read_4(sc->sc_memt, sc->sc_memh, JZ_SMBINTST)); 329 1.1 macallan abort = bus_space_read_4(sc->sc_memt, sc->sc_memh, JZ_SMBABTSRC); 330 1.1 macallan DPRINTF("abort: %02x\n", abort); 331 1.1 macallan if ((abort != 0)) { 332 1.1 macallan ret = -1; 333 1.1 macallan goto bork; 334 1.1 macallan } 335 1.1 macallan 336 1.1 macallan do { 337 1.1 macallan bail--; 338 1.1 macallan delay(100); 339 1.1 macallan } while (((bus_space_read_4(sc->sc_memt, sc->sc_memh, JZ_SMBST) & 340 1.1 macallan JZ_TFE) == 0) && (bail > 0)); 341 1.1 macallan 342 1.1 macallan if (cmdlen != 0) { 343 1.1 macallan for (i = 0; i < cmdlen; i++) { 344 1.1 macallan bus_space_write_4(sc->sc_memt, sc->sc_memh, 345 1.1 macallan JZ_SMBDC, *tx); 346 1.1 macallan tx++; 347 1.1 macallan } 348 1.1 macallan } 349 1.1 macallan 350 1.1 macallan if (I2C_OP_READ_P(op)) { 351 1.1 macallan /* now read */ 352 1.1 macallan for (i = 0; i < (buflen + 1); i++) { 353 1.1 macallan bus_space_write_4(sc->sc_memt, sc->sc_memh, 354 1.1 macallan JZ_SMBDC, JZ_CMD); 355 1.1 macallan } 356 1.1 macallan wbflush(); 357 1.1 macallan DPRINTF("rd st: %02x\n", 358 1.1 macallan bus_space_read_4(sc->sc_memt, sc->sc_memh, JZ_SMBST)); 359 1.1 macallan DPRINTF("rd int: %02x\n", 360 1.1 macallan bus_space_read_4(sc->sc_memt, sc->sc_memh, JZ_SMBINTST)); 361 1.1 macallan DPRINTF("abort: %02x\n", 362 1.1 macallan bus_space_read_4(sc->sc_memt, sc->sc_memh, JZ_SMBABTSRC)); 363 1.1 macallan for (i = 0; i < buflen; i++) { 364 1.1 macallan bail = 10000; 365 1.1 macallan while (((bus_space_read_4(sc->sc_memt, sc->sc_memh, 366 1.1 macallan JZ_SMBST) & JZ_RFNE) == 0) && (bail > 0)) { 367 1.1 macallan bail--; 368 1.1 macallan delay(100); 369 1.4 skrll } 370 1.1 macallan if (bail == 0) { 371 1.1 macallan ret = -1; 372 1.1 macallan goto bork; 373 1.1 macallan } 374 1.1 macallan data = bus_space_read_4(sc->sc_memt, sc->sc_memh, 375 1.1 macallan JZ_SMBDC); 376 1.1 macallan DPRINTF("rd st: %02x %d\n", 377 1.1 macallan bus_space_read_4(sc->sc_memt, sc->sc_memh, JZ_SMBST), 378 1.1 macallan bail); 379 1.1 macallan DPRINTF("rd int: %02x\n", 380 1.1 macallan bus_space_read_4(sc->sc_memt, sc->sc_memh, 381 1.1 macallan JZ_SMBINTST)); 382 1.1 macallan DPRINTF("abort: %02x\n", abort); 383 1.1 macallan DPRINTF("rd data: %02x\n", data); 384 1.1 macallan *rx = data; 385 1.1 macallan rx++; 386 1.1 macallan } 387 1.1 macallan } else { 388 1.1 macallan tx = vbuf; 389 1.1 macallan for (i = 0; i < buflen; i++) { 390 1.1 macallan DPRINTF("wr data: %02x\n", *tx); 391 1.1 macallan bus_space_write_4(sc->sc_memt, sc->sc_memh, 392 1.1 macallan JZ_SMBDC, *tx); 393 1.1 macallan wbflush(); 394 1.1 macallan tx++; 395 1.1 macallan } 396 1.1 macallan jziic_wait(sc); 397 1.1 macallan abort = bus_space_read_4(sc->sc_memt, sc->sc_memh, 398 1.1 macallan JZ_SMBABTSRC); 399 1.1 macallan DPRINTF("abort: %02x\n", abort); 400 1.1 macallan if ((abort != 0)) { 401 1.1 macallan ret = -1; 402 1.1 macallan goto bork; 403 1.1 macallan } 404 1.1 macallan 405 1.1 macallan DPRINTF("st: %02x %d\n", 406 1.1 macallan bus_space_read_4(sc->sc_memt, sc->sc_memh, JZ_SMBST), bail); 407 1.1 macallan DPRINTF("wr int: %02x\n", 408 1.1 macallan bus_space_read_4(sc->sc_memt, sc->sc_memh, JZ_SMBINTST)); 409 1.1 macallan } 410 1.1 macallan bus_space_write_4(sc->sc_memt, sc->sc_memh, JZ_SMBCON, 411 1.1 macallan JZ_SLVDIS | JZ_REST | JZ_SPD_100KB | JZ_MD); 412 1.1 macallan bork: 413 1.1 macallan jziic_disable(sc); 414 1.1 macallan return ret; 415 1.1 macallan } 416 1.2 macallan 417 1.2 macallan STATIC int 418 1.2 macallan jziic_i2c_exec_intr(struct jziic_softc *sc, i2c_op_t op, i2c_addr_t addr, 419 1.2 macallan const void *vcmd, size_t cmdlen, void *vbuf, size_t buflen, int flags) 420 1.2 macallan { 421 1.2 macallan int i, ret = 0, bail; 422 1.2 macallan 423 1.2 macallan DPRINTF("%s: 0x%02x %d %d\n", __func__, addr, cmdlen, buflen); 424 1.2 macallan 425 1.2 macallan jziic_disable(sc); 426 1.2 macallan bus_space_write_4(sc->sc_memt, sc->sc_memh, JZ_SMBINTM, 0); 427 1.2 macallan 428 1.2 macallan mutex_enter(&sc->sc_cvlock); 429 1.2 macallan 430 1.2 macallan sc->sc_reading = FALSE; 431 1.2 macallan 432 1.2 macallan if (I2C_OP_READ_P(op)) { 433 1.2 macallan sc->sc_cmd = vcmd; 434 1.2 macallan sc->sc_cmdlen = cmdlen; 435 1.2 macallan sc->sc_buf = vbuf; 436 1.2 macallan sc->sc_buflen = buflen; 437 1.2 macallan memset(vbuf, 0, buflen); 438 1.2 macallan } else { 439 1.2 macallan if ((cmdlen + buflen) > 256) 440 1.2 macallan return -1; 441 1.2 macallan memcpy(sc->sc_txbuf, vcmd, cmdlen); 442 1.2 macallan memcpy(sc->sc_txbuf + cmdlen, vbuf, buflen); 443 1.2 macallan sc->sc_cmd = sc->sc_txbuf; 444 1.2 macallan sc->sc_cmdlen = cmdlen + buflen; 445 1.2 macallan sc->sc_buf = NULL; 446 1.2 macallan sc->sc_buflen = 0; 447 1.2 macallan } 448 1.2 macallan sc->sc_cmdptr = 0; 449 1.2 macallan sc->sc_bufptr = 0; 450 1.2 macallan sc->sc_rds = 0; 451 1.2 macallan sc->sc_abort = 0; 452 1.2 macallan 453 1.2 macallan jziic_set_speed(sc); 454 1.2 macallan jziic_wait(sc); 455 1.2 macallan 456 1.2 macallan /* set FIFO levels */ 457 1.2 macallan bus_space_write_4(sc->sc_memt, sc->sc_memh, JZ_SMBTXTL, 4); 458 1.2 macallan bus_space_write_4(sc->sc_memt, sc->sc_memh, JZ_SMBRXTL, 0 459 1.2 macallan /*min(7, max(0, buflen - 2 ))*/); 460 1.2 macallan 461 1.2 macallan /* try to talk... */ 462 1.2 macallan 463 1.2 macallan if (!jziic_enable(sc)) { 464 1.2 macallan ret = -1; 465 1.2 macallan goto bork; 466 1.2 macallan } 467 1.2 macallan bus_space_write_4(sc->sc_memt, sc->sc_memh, JZ_SMBINTM, 0); 468 1.2 macallan 469 1.2 macallan bus_space_write_4(sc->sc_memt, sc->sc_memh, JZ_SMBTAR, addr); 470 1.2 macallan jziic_wait(sc); 471 1.2 macallan bus_space_write_4(sc->sc_memt, sc->sc_memh, JZ_SMBCINT, JZ_CLEARALL); 472 1.2 macallan bus_space_write_4(sc->sc_memt, sc->sc_memh, JZ_SMBINTM, 473 1.2 macallan JZ_TXABT | JZ_TXEMP); 474 1.2 macallan 475 1.2 macallan bail = 100 * sc->sc_cmdlen; 476 1.2 macallan while ((sc->sc_cmdptr < sc->sc_cmdlen) && (bail > 0)) { 477 1.2 macallan cv_timedwait(&sc->sc_ping, &sc->sc_cvlock, 1); 478 1.2 macallan if (sc->sc_abort) { 479 1.2 macallan /* we received an abort interrupt -> bailout */ 480 1.2 macallan DPRINTF("abort: %x\n", sc->sc_abort); 481 1.2 macallan ret = -1; 482 1.2 macallan goto bork; 483 1.2 macallan } 484 1.2 macallan bail--; 485 1.2 macallan } 486 1.2 macallan 487 1.2 macallan if (sc->sc_cmdptr < sc->sc_cmdlen) { 488 1.2 macallan /* we didn't send everything? */ 489 1.2 macallan DPRINTF("sent %d of %d\n", sc->sc_cmdptr, sc->sc_cmdlen); 490 1.2 macallan ret = -1; 491 1.2 macallan goto bork; 492 1.2 macallan } 493 1.2 macallan 494 1.2 macallan if (I2C_OP_READ_P(op)) { 495 1.2 macallan /* now read */ 496 1.2 macallan sc->sc_reading = TRUE; 497 1.2 macallan bus_space_write_4(sc->sc_memt, sc->sc_memh, JZ_SMBINTM, 498 1.2 macallan JZ_TXABT | JZ_RXFL | JZ_TXEMP); 499 1.2 macallan 500 1.5 riastrad for (i = 0; i < uimin((buflen + 1), 4); i++) { 501 1.2 macallan bus_space_write_4(sc->sc_memt, sc->sc_memh, 502 1.2 macallan JZ_SMBDC, JZ_CMD); 503 1.2 macallan wbflush(); 504 1.2 macallan } 505 1.2 macallan sc->sc_rds = i; 506 1.2 macallan 507 1.2 macallan bail = 10 * sc->sc_buflen; /* 10 ticks per byte should be ok */ 508 1.2 macallan while ((sc->sc_bufptr < sc->sc_buflen) && (bail > 0)) { 509 1.4 skrll cv_timedwait(&sc->sc_ping, &sc->sc_cvlock, 1); 510 1.2 macallan if (sc->sc_abort) { 511 1.2 macallan /* we received an abort interrupt -> bailout */ 512 1.2 macallan DPRINTF("rx abort: %x\n", sc->sc_abort); 513 1.2 macallan ret = -1; 514 1.2 macallan goto bork; 515 1.2 macallan } 516 1.2 macallan bail--; 517 1.2 macallan } 518 1.2 macallan 519 1.2 macallan if (sc->sc_bufptr < sc->sc_buflen) { 520 1.2 macallan /* we didn't get everything? */ 521 1.2 macallan DPRINTF("rcvd %d of %d\n", sc->sc_bufptr, sc->sc_buflen); 522 1.2 macallan ret = -1; 523 1.2 macallan goto bork; 524 1.2 macallan } 525 1.2 macallan } 526 1.2 macallan bus_space_write_4(sc->sc_memt, sc->sc_memh, JZ_SMBCON, 527 1.2 macallan JZ_SLVDIS | JZ_REST | JZ_SPD_100KB | JZ_MD); 528 1.2 macallan bork: 529 1.2 macallan bus_space_write_4(sc->sc_memt, sc->sc_memh, JZ_SMBINTM, 0); 530 1.2 macallan jziic_disable(sc); 531 1.2 macallan mutex_exit(&sc->sc_cvlock); 532 1.2 macallan return ret; 533 1.2 macallan } 534 1.2 macallan 535 1.2 macallan STATIC int 536 1.2 macallan jziic_intr(void *cookie) 537 1.2 macallan { 538 1.2 macallan struct jziic_softc *sc = cookie; 539 1.2 macallan uint32_t stat, data, rstat; 540 1.2 macallan int i; 541 1.2 macallan 542 1.2 macallan stat = bus_space_read_4(sc->sc_memt, sc->sc_memh, JZ_SMBINTST); 543 1.2 macallan if (stat & JZ_TXEMP) { 544 1.2 macallan if (sc->sc_reading) { 545 1.2 macallan if (sc->sc_rds < (sc->sc_buflen + 1)) { 546 1.2 macallan for (i = 0; 547 1.5 riastrad i < uimin(4, (sc->sc_buflen + 1) - 548 1.2 macallan sc->sc_rds); 549 1.2 macallan i++) { 550 1.2 macallan bus_space_write_4( sc->sc_memt, 551 1.2 macallan sc->sc_memh, 552 1.2 macallan JZ_SMBDC, JZ_CMD); 553 1.2 macallan wbflush(); 554 1.2 macallan } 555 1.2 macallan sc->sc_rds += i; 556 1.2 macallan } else { 557 1.2 macallan /* we're done, so turn TX FIFO interrupt off */ 558 1.2 macallan bus_space_write_4(sc->sc_memt, sc->sc_memh, 559 1.2 macallan JZ_SMBINTM, 560 1.2 macallan JZ_TXABT | JZ_RXFL); 561 1.2 macallan } 562 1.4 skrll } else { 563 1.2 macallan rstat = bus_space_read_4(sc->sc_memt, sc->sc_memh, 564 1.2 macallan JZ_SMBST); 565 1.4 skrll while ((rstat & JZ_TFNF) && 566 1.2 macallan (sc->sc_cmdptr < sc->sc_cmdlen)) { 567 1.2 macallan data = *sc->sc_cmd; 568 1.2 macallan sc->sc_cmd++; 569 1.2 macallan sc->sc_cmdptr++; 570 1.2 macallan bus_space_write_4(sc->sc_memt, sc->sc_memh, 571 1.2 macallan JZ_SMBDC, data & 0xff); 572 1.2 macallan rstat = bus_space_read_4(sc->sc_memt, sc->sc_memh, 573 1.2 macallan JZ_SMBST); 574 1.2 macallan }; 575 1.2 macallan /* no need to clear this one */ 576 1.2 macallan if (sc->sc_cmdptr >= sc->sc_cmdlen) { 577 1.2 macallan cv_signal(&sc->sc_ping); 578 1.2 macallan bus_space_write_4(sc->sc_memt, sc->sc_memh, 579 1.2 macallan JZ_SMBINTM, JZ_TXABT); 580 1.2 macallan } 581 1.4 skrll } 582 1.2 macallan } 583 1.2 macallan if (stat & JZ_RXFL) { 584 1.2 macallan rstat = bus_space_read_4(sc->sc_memt, sc->sc_memh, JZ_SMBST); 585 1.2 macallan while ((rstat & JZ_RFNE) && (sc->sc_bufptr < sc->sc_buflen)) { 586 1.2 macallan data = bus_space_read_4(sc->sc_memt, sc->sc_memh, 587 1.2 macallan JZ_SMBDC); 588 1.2 macallan *sc->sc_buf = (uint8_t)(data & 0xff); 589 1.2 macallan sc->sc_buf++; 590 1.2 macallan sc->sc_bufptr++; 591 1.2 macallan rstat = bus_space_read_4(sc->sc_memt, sc->sc_memh, 592 1.2 macallan JZ_SMBST); 593 1.2 macallan } 594 1.2 macallan if (sc->sc_bufptr >= sc->sc_buflen) 595 1.2 macallan cv_signal(&sc->sc_ping); 596 1.2 macallan } 597 1.2 macallan if (stat & JZ_TXABT) { 598 1.2 macallan sc->sc_abort = bus_space_read_4(sc->sc_memt, sc->sc_memh, 599 1.2 macallan JZ_SMBABTSRC); 600 1.2 macallan cv_signal(&sc->sc_ping); 601 1.2 macallan bus_space_write_4(sc->sc_memt, sc->sc_memh, JZ_SMBCINT, 602 1.2 macallan JZ_CLEARALL); 603 1.2 macallan bus_space_write_4(sc->sc_memt, sc->sc_memh, JZ_SMBINTM, 0); 604 1.2 macallan } 605 1.2 macallan return 0; 606 1.2 macallan } 607