jziic.c revision 1.1
1/* $NetBSD: jziic.c,v 1.1 2015/04/04 12:28:52 macallan Exp $ */ 2 3/*- 4 * Copyright (c) 2015 Michael Lorenz 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 NETBSD FOUNDATION, INC. 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 FOUNDATION OR CONTRIBUTORS 20 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 21 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 22 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 23 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 24 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 25 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 26 * POSSIBILITY OF SUCH DAMAGE. 27 */ 28 29#include <sys/cdefs.h> 30__KERNEL_RCSID(0, "$NetBSD: jziic.c,v 1.1 2015/04/04 12:28:52 macallan Exp $"); 31 32/* 33 * a preliminary driver for JZ4780's on-chip SMBus controllers 34 * - needs more error handling and interrupt support 35 * - transfers can't be more than the chip's FIFO, supposedly 16 bytes per 36 * direction 37 * so, good enough for RTCs but not much else yet 38 */ 39 40#include <sys/param.h> 41#include <sys/systm.h> 42#include <sys/device.h> 43#include <sys/mutex.h> 44#include <sys/bus.h> 45#include <sys/mutex.h> 46 47#include <mips/ingenic/ingenic_var.h> 48#include <mips/ingenic/ingenic_regs.h> 49 50#include <dev/i2c/i2cvar.h> 51 52#include "opt_ingenic.h" 53 54#ifdef JZIIC_DEBUG 55#define DPRINTF aprint_error 56#else 57#define DPRINTF while (0) printf 58#endif 59static int jziic_match(device_t, struct cfdata *, void *); 60static void jziic_attach(device_t, device_t, void *); 61 62struct jziic_softc { 63 device_t sc_dev; 64 bus_space_tag_t sc_memt; 65 bus_space_handle_t sc_memh; 66 struct i2c_controller sc_i2c; 67 kmutex_t sc_buslock; 68 uint32_t sc_pclk; 69}; 70 71CFATTACH_DECL_NEW(jziic, sizeof(struct jziic_softc), 72 jziic_match, jziic_attach, NULL, NULL); 73 74static int jziic_enable(struct jziic_softc *); 75static void jziic_disable(struct jziic_softc *); 76static int jziic_i2c_acquire_bus(void *, int); 77static void jziic_i2c_release_bus(void *, int); 78static int jziic_i2c_exec(void *, i2c_op_t, i2c_addr_t, const void *, size_t, 79 void *, size_t, int); 80 81 82/* ARGSUSED */ 83static int 84jziic_match(device_t parent, struct cfdata *match, void *aux) 85{ 86 struct apbus_attach_args *aa = aux; 87 88 if (strcmp(aa->aa_name, "jziic") != 0) 89 return 0; 90 91 return 1; 92} 93 94/* ARGSUSED */ 95static void 96jziic_attach(device_t parent, device_t self, void *aux) 97{ 98 struct jziic_softc *sc = device_private(self); 99 struct apbus_attach_args *aa = aux; 100 struct i2cbus_attach_args iba; 101 int error; 102#ifdef JZIIC_DEBUG 103 int i; 104 uint8_t in[1] = {0}, out[16]; 105#endif 106 107 sc->sc_dev = self; 108 sc->sc_pclk = aa->aa_pclk; 109 sc->sc_memt = aa->aa_bst; 110 111 error = bus_space_map(aa->aa_bst, aa->aa_addr, 0x100, 0, &sc->sc_memh); 112 if (error) { 113 aprint_error_dev(self, 114 "can't map registers for %s: %d\n", aa->aa_name, error); 115 return; 116 } 117 118 mutex_init(&sc->sc_buslock, MUTEX_DEFAULT, IPL_NONE); 119 120 aprint_naive(": SMBus controller\n"); 121 aprint_normal(": SMBus controller\n"); 122 123#if notyet 124 ih = evbmips_intr_establish(aa->aa_irq, ohci_intr, sc); 125 126 if (ih == NULL) { 127 aprint_error_dev(self, "failed to establish interrupt %d\n", 128 aa->aa_irq); 129 goto fail; 130 } 131#endif 132 133#ifdef JZIIC_DEBUG 134 if (jziic_i2c_exec(sc, I2C_OP_READ_WITH_STOP, 0x51, in, 1, out, 9, 0) 135 >= 0) { 136 for (i = 0; i < 9; i++) 137 printf(" %02x", out[i]); 138 printf("\n"); 139 delay(1000000); 140 jziic_i2c_exec(sc, I2C_OP_READ_WITH_STOP, 141 0x51, in, 1, out, 9, 0); 142 for (i = 0; i < 9; i++) 143 printf(" %02x", out[i]); 144 printf("\n"); 145 delay(1000000); 146 jziic_i2c_exec(sc, I2C_OP_READ_WITH_STOP, 147 0x51, in, 1, out, 9, 0); 148 for (i = 0; i < 9; i++) 149 printf(" %02x", out[i]); 150 printf("\n"); 151 } 152#endif 153 154 /* fill in the i2c tag */ 155 sc->sc_i2c.ic_cookie = sc; 156 sc->sc_i2c.ic_acquire_bus = jziic_i2c_acquire_bus; 157 sc->sc_i2c.ic_release_bus = jziic_i2c_release_bus; 158 sc->sc_i2c.ic_send_start = NULL; 159 sc->sc_i2c.ic_send_stop = NULL; 160 sc->sc_i2c.ic_initiate_xfer = NULL; 161 sc->sc_i2c.ic_read_byte = NULL; 162 sc->sc_i2c.ic_write_byte = NULL; 163 sc->sc_i2c.ic_exec = jziic_i2c_exec; 164 165 iba.iba_tag = &sc->sc_i2c; 166 (void) config_found_ia(sc->sc_dev, "i2cbus", &iba, iicbus_print); 167 168 169 return; 170 171#if notyet 172fail: 173 if (ih) { 174 evbmips_intr_disestablish(ih); 175 } 176 bus_space_unmap(sc->sc_memt, sc->sc_memh, 0x100); 177#endif 178} 179 180static int 181jziic_enable(struct jziic_softc *sc) 182{ 183 int bail = 100000; 184 uint32_t reg; 185 186 bus_space_write_4(sc->sc_memt, sc->sc_memh, JZ_SMBENB, JZ_ENABLE); 187 reg = bus_space_read_4(sc->sc_memt, sc->sc_memh, JZ_SMBENBST); 188 DPRINTF("status: %02x\n", reg); 189 while ((bail > 0) && (reg == 0)) { 190 bail--; 191 reg = bus_space_read_4(sc->sc_memt, sc->sc_memh, JZ_SMBENBST); 192 } 193 DPRINTF("bail: %d\n", bail); 194 return (reg != 0); 195} 196 197static void 198jziic_disable(struct jziic_softc *sc) 199{ 200 int bail = 100000; 201 uint32_t reg; 202 203 bus_space_write_4(sc->sc_memt, sc->sc_memh, JZ_SMBENB, 0); 204 reg = bus_space_read_4(sc->sc_memt, sc->sc_memh, JZ_SMBENBST); 205 DPRINTF("status: %02x\n", reg); 206 while ((bail > 0) && (reg != 0)) { 207 bail--; 208 reg = bus_space_read_4(sc->sc_memt, sc->sc_memh, JZ_SMBENBST); 209 } 210 DPRINTF("bail: %d\n", bail); 211} 212 213static int 214jziic_i2c_acquire_bus(void *cookie, int flags) 215{ 216 struct jziic_softc *sc = cookie; 217 218 mutex_enter(&sc->sc_buslock); 219 return 0; 220} 221 222static void 223jziic_i2c_release_bus(void *cookie, int flags) 224{ 225 struct jziic_softc *sc = cookie; 226 227 mutex_exit(&sc->sc_buslock); 228} 229 230static int 231jziic_wait(struct jziic_softc *sc) 232{ 233 uint32_t reg; 234 int bail = 10000; 235 reg = bus_space_read_4(sc->sc_memt, sc->sc_memh, JZ_SMBST); 236 while ((reg & JZ_MSTACT) && (bail > 0)) { 237 delay(100); 238 reg = bus_space_read_4(sc->sc_memt, sc->sc_memh, JZ_SMBST); 239 bail--; 240 } 241 return ((reg & JZ_MSTACT) == 0); 242} 243 244int 245jziic_i2c_exec(void *cookie, i2c_op_t op, i2c_addr_t addr, const void *vcmd, 246 size_t cmdlen, void *vbuf, size_t buflen, int flags) 247{ 248 struct jziic_softc *sc = cookie; 249 int ticks, hcnt, lcnt, hold, setup; 250 int i, bail = 10000, ret = 0; 251 uint32_t abort; 252 uint8_t *rx, data; 253 const uint8_t *tx; 254 255 tx = vcmd; 256 rx = vbuf; 257 258 DPRINTF("%s: 0x%02x %d %d\n", __func__, addr, cmdlen, buflen); 259 260 jziic_disable(sc); 261 262 /* set speed and such */ 263 264 /* PCLK ticks per SMBus cycle */ 265 ticks = sc->sc_pclk / 100; /* assuming 100kHz for now */ 266 hcnt = (ticks * 40 / (40 + 47)) - 8; 267 lcnt = (ticks * 47 / (40 + 47)) - 1; 268 hold = sc->sc_pclk * 4 / 10000 - 1; /* ... * 400 / 1000000 ... */ 269 hold = max(1, hold); 270 hold |= JZ_HDENB; 271 setup = sc->sc_pclk * 3 / 10000 + 1; /* ... * 300 / 1000000 ... */ 272 DPRINTF("hcnt %d lcnt %d hold %d\n", hcnt, lcnt, hold); 273 bus_space_write_4(sc->sc_memt, sc->sc_memh, JZ_SMBSHCNT, hcnt); 274 bus_space_write_4(sc->sc_memt, sc->sc_memh, JZ_SMBSLCNT, lcnt); 275 bus_space_write_4(sc->sc_memt, sc->sc_memh, JZ_SMBSDAHD, hold); 276 bus_space_write_4(sc->sc_memt, sc->sc_memh, JZ_SMBSDASU, setup); 277 bus_space_write_4(sc->sc_memt, sc->sc_memh, JZ_SMBCON, 278 JZ_SLVDIS | JZ_STPHLD | JZ_REST | JZ_SPD_100KB | JZ_MD); 279 (void)bus_space_read_4(sc->sc_memt, sc->sc_memh, JZ_SMBCINT); 280 jziic_wait(sc); 281 /* try to talk... */ 282 283 if (!jziic_enable(sc)) { 284 ret = -1; 285 goto bork; 286 } 287 288 bus_space_write_4(sc->sc_memt, sc->sc_memh, JZ_SMBTAR, addr); 289 jziic_wait(sc); 290 DPRINTF("st: %02x\n", 291 bus_space_read_4(sc->sc_memt, sc->sc_memh, JZ_SMBST)); 292 DPRINTF("wr int: %02x\n", 293 bus_space_read_4(sc->sc_memt, sc->sc_memh, JZ_SMBINTST)); 294 abort = bus_space_read_4(sc->sc_memt, sc->sc_memh, JZ_SMBABTSRC); 295 DPRINTF("abort: %02x\n", abort); 296 if ((abort != 0)) { 297 ret = -1; 298 goto bork; 299 } 300 301 do { 302 bail--; 303 delay(100); 304 } while (((bus_space_read_4(sc->sc_memt, sc->sc_memh, JZ_SMBST) & 305 JZ_TFE) == 0) && (bail > 0)); 306 307 if (cmdlen != 0) { 308 for (i = 0; i < cmdlen; i++) { 309 bus_space_write_4(sc->sc_memt, sc->sc_memh, 310 JZ_SMBDC, *tx); 311 tx++; 312 } 313 } 314 315 if (I2C_OP_READ_P(op)) { 316 /* now read */ 317 for (i = 0; i < (buflen + 1); i++) { 318 bus_space_write_4(sc->sc_memt, sc->sc_memh, 319 JZ_SMBDC, JZ_CMD); 320 } 321 wbflush(); 322 DPRINTF("rd st: %02x\n", 323 bus_space_read_4(sc->sc_memt, sc->sc_memh, JZ_SMBST)); 324 DPRINTF("rd int: %02x\n", 325 bus_space_read_4(sc->sc_memt, sc->sc_memh, JZ_SMBINTST)); 326 DPRINTF("abort: %02x\n", 327 bus_space_read_4(sc->sc_memt, sc->sc_memh, JZ_SMBABTSRC)); 328 for (i = 0; i < buflen; i++) { 329 bail = 10000; 330 while (((bus_space_read_4(sc->sc_memt, sc->sc_memh, 331 JZ_SMBST) & JZ_RFNE) == 0) && (bail > 0)) { 332 bail--; 333 delay(100); 334 } 335 if (bail == 0) { 336 ret = -1; 337 goto bork; 338 } 339 data = bus_space_read_4(sc->sc_memt, sc->sc_memh, 340 JZ_SMBDC); 341 DPRINTF("rd st: %02x %d\n", 342 bus_space_read_4(sc->sc_memt, sc->sc_memh, JZ_SMBST), 343 bail); 344 DPRINTF("rd int: %02x\n", 345 bus_space_read_4(sc->sc_memt, sc->sc_memh, 346 JZ_SMBINTST)); 347 DPRINTF("abort: %02x\n", abort); 348 DPRINTF("rd data: %02x\n", data); 349 *rx = data; 350 rx++; 351 } 352 } else { 353 tx = vbuf; 354 for (i = 0; i < buflen; i++) { 355 DPRINTF("wr data: %02x\n", *tx); 356 bus_space_write_4(sc->sc_memt, sc->sc_memh, 357 JZ_SMBDC, *tx); 358 wbflush(); 359 tx++; 360 } 361 jziic_wait(sc); 362 abort = bus_space_read_4(sc->sc_memt, sc->sc_memh, 363 JZ_SMBABTSRC); 364 DPRINTF("abort: %02x\n", abort); 365 if ((abort != 0)) { 366 ret = -1; 367 goto bork; 368 } 369 370 DPRINTF("st: %02x %d\n", 371 bus_space_read_4(sc->sc_memt, sc->sc_memh, JZ_SMBST), bail); 372 DPRINTF("wr int: %02x\n", 373 bus_space_read_4(sc->sc_memt, sc->sc_memh, JZ_SMBINTST)); 374 } 375 bus_space_write_4(sc->sc_memt, sc->sc_memh, JZ_SMBCON, 376 JZ_SLVDIS | JZ_REST | JZ_SPD_100KB | JZ_MD); 377bork: 378 jziic_disable(sc); 379 return ret; 380} 381