1 1.42 thorpej /* $NetBSD: ki2c.c,v 1.42 2025/09/21 13:56:36 thorpej Exp $ */ 2 1.1 grant /* Id: ki2c.c,v 1.7 2002/10/05 09:56:05 tsubai Exp */ 3 1.1 grant 4 1.1 grant /*- 5 1.1 grant * Copyright (c) 2001 Tsubai Masanari. All rights reserved. 6 1.1 grant * 7 1.1 grant * Redistribution and use in source and binary forms, with or without 8 1.1 grant * modification, are permitted provided that the following conditions 9 1.1 grant * are met: 10 1.1 grant * 1. Redistributions of source code must retain the above copyright 11 1.1 grant * notice, this list of conditions and the following disclaimer. 12 1.1 grant * 2. Redistributions in binary form must reproduce the above copyright 13 1.1 grant * notice, this list of conditions and the following disclaimer in the 14 1.1 grant * documentation and/or other materials provided with the distribution. 15 1.1 grant * 3. The name of the author may not be used to endorse or promote products 16 1.1 grant * derived from this software without specific prior written permission. 17 1.1 grant * 18 1.1 grant * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 19 1.1 grant * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 20 1.1 grant * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 21 1.1 grant * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 22 1.1 grant * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 23 1.1 grant * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 24 1.1 grant * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 25 1.1 grant * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 26 1.1 grant * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 27 1.1 grant * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 28 1.1 grant */ 29 1.1 grant 30 1.1 grant #include <sys/param.h> 31 1.1 grant #include <sys/device.h> 32 1.1 grant #include <sys/systm.h> 33 1.11 ad #include <sys/mutex.h> 34 1.1 grant 35 1.1 grant #include <dev/ofw/openfirm.h> 36 1.1 grant #include <machine/autoconf.h> 37 1.37 macallan #include <powerpc/pic/picvar.h> 38 1.1 grant 39 1.29 macallan #include "opt_ki2c.h" 40 1.3 macallan #include <macppc/dev/ki2cvar.h> 41 1.1 grant 42 1.20 macallan #ifdef KI2C_DEBUG 43 1.20 macallan #define DPRINTF printf 44 1.20 macallan #else 45 1.20 macallan #define DPRINTF while (0) printf 46 1.20 macallan #endif 47 1.20 macallan 48 1.33 mlelstv #define KI2C_EXEC_MAX_CMDLEN 32 49 1.33 mlelstv #define KI2C_EXEC_MAX_BUFLEN 32 50 1.33 mlelstv 51 1.17 matt int ki2c_match(device_t, cfdata_t, void *); 52 1.17 matt void ki2c_attach(device_t, device_t, void *); 53 1.21 macallan inline uint8_t ki2c_readreg(struct ki2c_softc *, int); 54 1.21 macallan inline void ki2c_writereg(struct ki2c_softc *, int, uint8_t); 55 1.1 grant u_int ki2c_getmode(struct ki2c_softc *); 56 1.1 grant void ki2c_setmode(struct ki2c_softc *, u_int); 57 1.1 grant u_int ki2c_getspeed(struct ki2c_softc *); 58 1.1 grant void ki2c_setspeed(struct ki2c_softc *, u_int); 59 1.35 macallan int ki2c_intr(void *); 60 1.1 grant int ki2c_poll(struct ki2c_softc *, int); 61 1.1 grant int ki2c_start(struct ki2c_softc *, int, int, void *, int); 62 1.1 grant int ki2c_read(struct ki2c_softc *, int, int, void *, int); 63 1.3 macallan int ki2c_write(struct ki2c_softc *, int, int, void *, int); 64 1.3 macallan 65 1.3 macallan /* I2C glue */ 66 1.3 macallan static int ki2c_i2c_exec(void *, i2c_op_t, i2c_addr_t, const void *, size_t, 67 1.3 macallan void *, size_t, int); 68 1.3 macallan 69 1.1 grant 70 1.18 macallan CFATTACH_DECL_NEW(ki2c, sizeof(struct ki2c_softc), ki2c_match, ki2c_attach, 71 1.9 dogcow NULL, NULL); 72 1.1 grant 73 1.1 grant int 74 1.17 matt ki2c_match(device_t parent, cfdata_t match, void *aux) 75 1.1 grant { 76 1.1 grant struct confargs *ca = aux; 77 1.1 grant 78 1.1 grant if (strcmp(ca->ca_name, "i2c") == 0) 79 1.1 grant return 1; 80 1.1 grant 81 1.1 grant return 0; 82 1.1 grant } 83 1.1 grant 84 1.1 grant void 85 1.17 matt ki2c_attach(device_t parent, device_t self, void *aux) 86 1.1 grant { 87 1.17 matt struct ki2c_softc *sc = device_private(self); 88 1.1 grant struct confargs *ca = aux; 89 1.39 macallan int node = ca->ca_node, root; 90 1.42 thorpej uint32_t addr, channel, intr[2]; 91 1.28 macallan int rate, child, /*namelen,*/ i2cbus[2] = {0, 0}; 92 1.20 macallan prop_dictionary_t dict = device_properties(self); 93 1.20 macallan prop_array_t cfg; 94 1.42 thorpej int devs, intrparent; 95 1.42 thorpej char compat[256]; 96 1.22 macallan prop_dictionary_t dev; 97 1.22 macallan prop_data_t data; 98 1.39 macallan char name[32], intr_xname[32], model[32]; 99 1.38 macallan uint32_t picbase; 100 1.18 macallan 101 1.18 macallan sc->sc_dev = self; 102 1.21 macallan sc->sc_tag = ca->ca_tag; 103 1.1 grant ca->ca_reg[0] += ca->ca_baseaddr; 104 1.1 grant 105 1.39 macallan root = OF_finddevice("/"); 106 1.39 macallan model[0] = 0; 107 1.39 macallan OF_getprop(root, "model", model, 32); 108 1.39 macallan DPRINTF("model %s\n", model); 109 1.1 grant if (OF_getprop(node, "AAPL,i2c-rate", &rate, 4) != 4) { 110 1.20 macallan aprint_error(": cannot get i2c-rate\n"); 111 1.1 grant return; 112 1.1 grant } 113 1.20 macallan if (OF_getprop(node, "AAPL,address", &addr, 4) != 4) { 114 1.20 macallan aprint_error(": unable to find i2c address\n"); 115 1.1 grant return; 116 1.1 grant } 117 1.21 macallan if (bus_space_map(sc->sc_tag, addr, PAGE_SIZE, 0, &sc->sc_bh) != 0) { 118 1.21 macallan aprint_error_dev(sc->sc_dev, "failed to map registers\n"); 119 1.21 macallan return; 120 1.21 macallan } 121 1.21 macallan 122 1.1 grant if (OF_getprop(node, "AAPL,address-step", &sc->sc_regstep, 4) != 4) { 123 1.20 macallan aprint_error(": unable to find i2c address step\n"); 124 1.1 grant return; 125 1.1 grant } 126 1.1 grant 127 1.35 macallan if(OF_getprop(node, "interrupts", intr, 8) != 8) { 128 1.35 macallan aprint_error(": can't find interrupt\n"); 129 1.35 macallan return; 130 1.35 macallan } 131 1.35 macallan 132 1.37 macallan /* 133 1.37 macallan * on some G5 we have two openpics, one in mac-io, one in /u3 134 1.37 macallan * in order to get interrupts we need to know which one we're 135 1.37 macallan * connected to 136 1.37 macallan */ 137 1.37 macallan sc->sc_poll = 0; 138 1.37 macallan 139 1.37 macallan if(OF_getprop(node, "interrupt-parent", &intrparent, 4) == 4) { 140 1.38 macallan uint32_t preg[8]; 141 1.37 macallan struct pic_ops *pic; 142 1.37 macallan 143 1.37 macallan sc->sc_poll = 1; 144 1.37 macallan if(OF_getprop(intrparent, "reg", preg, 8) > 4) { 145 1.37 macallan /* now look for a pic with that base... */ 146 1.38 macallan picbase = preg[0]; 147 1.38 macallan if ((picbase & 0x80000000) == 0) { 148 1.38 macallan /* some OF versions have the openpic's reg as 149 1.38 macallan * an offset into mac-io just to be annoying */ 150 1.38 macallan int mio = OF_parent(intrparent); 151 1.38 macallan if (OF_getprop(mio, "ranges", preg, 20) == 20) 152 1.38 macallan picbase += preg[3]; 153 1.38 macallan } 154 1.38 macallan DPRINTF("PIC base %08x\n", picbase); 155 1.38 macallan pic = find_pic_by_cookie((void *)picbase); 156 1.37 macallan if (pic != NULL) { 157 1.37 macallan sc->sc_poll = 0; 158 1.37 macallan intr[0] += pic->pic_intrbase; 159 1.37 macallan } 160 1.37 macallan } 161 1.37 macallan } 162 1.37 macallan 163 1.37 macallan if (sc->sc_poll) { 164 1.37 macallan aprint_normal(" polling"); 165 1.37 macallan } else aprint_normal(" irq %d", intr[0]); 166 1.35 macallan 167 1.1 grant printf("\n"); 168 1.1 grant 169 1.1 grant ki2c_writereg(sc, STATUS, 0); 170 1.1 grant ki2c_writereg(sc, ISR, 0); 171 1.1 grant ki2c_writereg(sc, IER, 0); 172 1.1 grant 173 1.1 grant ki2c_setmode(sc, I2C_STDSUBMODE); 174 1.1 grant ki2c_setspeed(sc, I2C_100kHz); /* XXX rate */ 175 1.3 macallan 176 1.3 macallan ki2c_writereg(sc, IER,I2C_INT_DATA|I2C_INT_ADDR|I2C_INT_STOP); 177 1.3 macallan 178 1.20 macallan cfg = prop_array_create(); 179 1.20 macallan prop_dictionary_set(dict, "i2c-child-devices", cfg); 180 1.20 macallan prop_object_release(cfg); 181 1.20 macallan 182 1.4 macallan /* 183 1.4 macallan * newer OF puts I2C devices under 'i2c-bus' instead of attaching them 184 1.4 macallan * directly to the ki2c node so we just check if we have a child named 185 1.25 macallan * 'i2c-bus' and if so we attach its children, not ours 186 1.25 macallan * 187 1.25 macallan * XXX 188 1.25 macallan * should probably check for multiple i2c-bus children 189 1.4 macallan */ 190 1.28 macallan 191 1.28 macallan int found_busnode = 0; 192 1.25 macallan channel = 0; 193 1.4 macallan child = OF_child(node); 194 1.28 macallan while (child != 0) { 195 1.4 macallan OF_getprop(child, "name", name, sizeof(name)); 196 1.25 macallan if (strcmp(name, "i2c-bus") == 0) { 197 1.25 macallan OF_getprop(child, "reg", &channel, sizeof(channel)); 198 1.28 macallan i2cbus[channel] = child; 199 1.25 macallan DPRINTF("found channel %x\n", channel); 200 1.28 macallan found_busnode = 1; 201 1.25 macallan } 202 1.4 macallan child = OF_peer(child); 203 1.4 macallan } 204 1.28 macallan if (found_busnode == 0) 205 1.28 macallan i2cbus[0] = node; 206 1.22 macallan 207 1.28 macallan for (channel = 0; channel < 2; channel++) { 208 1.41 thorpej devhandle_t child_devhandle; 209 1.41 thorpej 210 1.28 macallan devs = OF_child(i2cbus[channel]); 211 1.28 macallan while (devs != 0) { 212 1.28 macallan if (OF_getprop(devs, "name", name, 32) <= 0) 213 1.22 macallan goto skip; 214 1.28 macallan if (OF_getprop(devs, "compatible", compat, 256) <= 0) { 215 1.28 macallan /* some i2c device nodes don't have 'compatible' */ 216 1.28 macallan memset(compat, 0, 256); 217 1.28 macallan strncpy(compat, name, 256); 218 1.28 macallan } 219 1.28 macallan if (OF_getprop(devs, "reg", &addr, 4) <= 0) 220 1.28 macallan if (OF_getprop(devs, "i2c-address", &addr, 4) <= 0) 221 1.28 macallan goto skip; 222 1.28 macallan addr |= channel << 8; 223 1.28 macallan addr = addr >> 1; 224 1.28 macallan DPRINTF("-> %s@%x\n", name, addr); 225 1.28 macallan dev = prop_dictionary_create(); 226 1.30 macallan prop_dictionary_set_string(dev, "name", name); 227 1.30 macallan data = prop_data_create_copy(compat, strlen(compat)+1); 228 1.28 macallan prop_dictionary_set(dev, "compatible", data); 229 1.28 macallan prop_object_release(data); 230 1.28 macallan prop_dictionary_set_uint32(dev, "addr", addr); 231 1.41 thorpej child_devhandle = 232 1.41 thorpej devhandle_from_of(devhandle_invalid(), devs); 233 1.41 thorpej prop_dictionary_set_data(dev, "devhandle", 234 1.41 thorpej &child_devhandle, sizeof(child_devhandle)); 235 1.41 thorpej 236 1.28 macallan prop_array_add(cfg, dev); 237 1.28 macallan prop_object_release(dev); 238 1.28 macallan skip: 239 1.28 macallan devs = OF_peer(devs); 240 1.26 macallan } 241 1.3 macallan } 242 1.3 macallan 243 1.35 macallan cv_init(&sc->sc_todev, device_xname(self)); 244 1.35 macallan mutex_init(&sc->sc_todevmtx, MUTEX_DEFAULT, IPL_NONE); 245 1.35 macallan 246 1.37 macallan if(sc->sc_poll == 0) { 247 1.37 macallan snprintf(intr_xname, sizeof(intr_xname), "%s intr", device_xname(self)); 248 1.37 macallan intr_establish_xname(intr[0], (intr[1] & 1) ? IST_LEVEL : IST_EDGE, 249 1.37 macallan IPL_BIO, ki2c_intr, sc, intr_xname); 250 1.35 macallan 251 1.37 macallan ki2c_writereg(sc, IER, I2C_INT_DATA | I2C_INT_ADDR| I2C_INT_STOP); 252 1.37 macallan } 253 1.35 macallan 254 1.22 macallan /* fill in the i2c tag */ 255 1.27 thorpej iic_tag_init(&sc->sc_i2c); 256 1.22 macallan sc->sc_i2c.ic_cookie = sc; 257 1.22 macallan sc->sc_i2c.ic_exec = ki2c_i2c_exec; 258 1.3 macallan 259 1.40 thorpej iicbus_attach(sc->sc_dev, &sc->sc_i2c); 260 1.1 grant } 261 1.1 grant 262 1.21 macallan uint8_t 263 1.14 dsl ki2c_readreg(struct ki2c_softc *sc, int reg) 264 1.1 grant { 265 1.1 grant 266 1.21 macallan return bus_space_read_1(sc->sc_tag, sc->sc_bh, sc->sc_regstep * reg); 267 1.1 grant } 268 1.1 grant 269 1.1 grant void 270 1.21 macallan ki2c_writereg(struct ki2c_softc *sc, int reg, uint8_t val) 271 1.1 grant { 272 1.21 macallan 273 1.21 macallan bus_space_write_1(sc->sc_tag, sc->sc_bh, reg * sc->sc_regstep, val); 274 1.1 grant delay(10); 275 1.1 grant } 276 1.1 grant 277 1.1 grant u_int 278 1.14 dsl ki2c_getmode(struct ki2c_softc *sc) 279 1.1 grant { 280 1.1 grant return ki2c_readreg(sc, MODE) & I2C_MODE; 281 1.1 grant } 282 1.1 grant 283 1.1 grant void 284 1.14 dsl ki2c_setmode(struct ki2c_softc *sc, u_int mode) 285 1.1 grant { 286 1.25 macallan ki2c_writereg(sc, MODE, mode); 287 1.1 grant } 288 1.1 grant 289 1.1 grant u_int 290 1.14 dsl ki2c_getspeed(struct ki2c_softc *sc) 291 1.1 grant { 292 1.1 grant return ki2c_readreg(sc, MODE) & I2C_SPEED; 293 1.1 grant } 294 1.1 grant 295 1.1 grant void 296 1.14 dsl ki2c_setspeed(struct ki2c_softc *sc, u_int speed) 297 1.1 grant { 298 1.1 grant u_int x; 299 1.1 grant 300 1.1 grant KASSERT((speed & ~I2C_SPEED) == 0); 301 1.1 grant x = ki2c_readreg(sc, MODE); 302 1.1 grant x &= ~I2C_SPEED; 303 1.1 grant x |= speed; 304 1.1 grant ki2c_writereg(sc, MODE, x); 305 1.1 grant } 306 1.1 grant 307 1.1 grant int 308 1.35 macallan ki2c_intr(void *cookie) 309 1.1 grant { 310 1.35 macallan struct ki2c_softc *sc = cookie; 311 1.1 grant u_int isr, x; 312 1.1 grant isr = ki2c_readreg(sc, ISR); 313 1.1 grant if (isr & I2C_INT_ADDR) { 314 1.1 grant #if 0 315 1.1 grant if ((ki2c_readreg(sc, STATUS) & I2C_ST_LASTAAK) == 0) { 316 1.1 grant /* No slave responded. */ 317 1.1 grant sc->sc_flags |= I2C_ERROR; 318 1.1 grant goto out; 319 1.1 grant } 320 1.1 grant #endif 321 1.1 grant 322 1.1 grant if (sc->sc_flags & I2C_READING) { 323 1.1 grant if (sc->sc_resid > 1) { 324 1.1 grant x = ki2c_readreg(sc, CONTROL); 325 1.1 grant x |= I2C_CT_AAK; 326 1.1 grant ki2c_writereg(sc, CONTROL, x); 327 1.1 grant } 328 1.1 grant } else { 329 1.1 grant ki2c_writereg(sc, DATA, *sc->sc_data++); 330 1.1 grant sc->sc_resid--; 331 1.1 grant } 332 1.1 grant } 333 1.1 grant 334 1.1 grant if (isr & I2C_INT_DATA) { 335 1.1 grant if (sc->sc_flags & I2C_READING) { 336 1.1 grant *sc->sc_data++ = ki2c_readreg(sc, DATA); 337 1.1 grant sc->sc_resid--; 338 1.1 grant 339 1.1 grant if (sc->sc_resid == 0) { /* Completed */ 340 1.1 grant ki2c_writereg(sc, CONTROL, 0); 341 1.1 grant goto out; 342 1.1 grant } 343 1.1 grant } else { 344 1.1 grant #if 0 345 1.1 grant if ((ki2c_readreg(sc, STATUS) & I2C_ST_LASTAAK) == 0) { 346 1.1 grant /* No slave responded. */ 347 1.1 grant sc->sc_flags |= I2C_ERROR; 348 1.1 grant goto out; 349 1.1 grant } 350 1.1 grant #endif 351 1.1 grant 352 1.1 grant if (sc->sc_resid == 0) { 353 1.1 grant x = ki2c_readreg(sc, CONTROL) | I2C_CT_STOP; 354 1.1 grant ki2c_writereg(sc, CONTROL, x); 355 1.1 grant } else { 356 1.1 grant ki2c_writereg(sc, DATA, *sc->sc_data++); 357 1.1 grant sc->sc_resid--; 358 1.1 grant } 359 1.1 grant } 360 1.1 grant } 361 1.1 grant 362 1.1 grant out: 363 1.1 grant if (isr & I2C_INT_STOP) { 364 1.1 grant ki2c_writereg(sc, CONTROL, 0); 365 1.1 grant sc->sc_flags &= ~I2C_BUSY; 366 1.35 macallan cv_signal(&sc->sc_todev); 367 1.1 grant } 368 1.1 grant 369 1.1 grant ki2c_writereg(sc, ISR, isr); 370 1.1 grant 371 1.1 grant return 1; 372 1.1 grant } 373 1.1 grant 374 1.1 grant int 375 1.14 dsl ki2c_poll(struct ki2c_softc *sc, int timo) 376 1.1 grant { 377 1.37 macallan int bail = 0; 378 1.1 grant while (sc->sc_flags & I2C_BUSY) { 379 1.37 macallan if ((cold) || (bail > 10) || (sc->sc_poll)) { 380 1.35 macallan if (ki2c_readreg(sc, ISR)) 381 1.35 macallan ki2c_intr(sc); 382 1.35 macallan timo -= 10; 383 1.35 macallan if (timo < 0) { 384 1.35 macallan DPRINTF("i2c_poll: timeout\n"); 385 1.35 macallan return -1; 386 1.35 macallan } 387 1.35 macallan delay(10); 388 1.35 macallan } else { 389 1.35 macallan mutex_enter(&sc->sc_todevmtx); 390 1.37 macallan cv_timedwait_sig(&sc->sc_todev, &sc->sc_todevmtx, hz/10); 391 1.35 macallan mutex_exit(&sc->sc_todevmtx); 392 1.37 macallan bail++; 393 1.1 grant } 394 1.1 grant } 395 1.1 grant return 0; 396 1.1 grant } 397 1.1 grant 398 1.1 grant int 399 1.15 dsl ki2c_start(struct ki2c_softc *sc, int addr, int subaddr, void *data, int len) 400 1.1 grant { 401 1.1 grant int rw = (sc->sc_flags & I2C_READING) ? 1 : 0; 402 1.1 grant int timo, x; 403 1.1 grant 404 1.1 grant KASSERT((addr & 1) == 0); 405 1.1 grant 406 1.1 grant sc->sc_data = data; 407 1.1 grant sc->sc_resid = len; 408 1.1 grant sc->sc_flags |= I2C_BUSY; 409 1.1 grant 410 1.1 grant timo = 1000 + len * 200; 411 1.1 grant 412 1.1 grant /* XXX TAS3001 sometimes takes 50ms to finish writing registers. */ 413 1.1 grant /* if (addr == 0x68) */ 414 1.1 grant timo += 100000; 415 1.1 grant 416 1.1 grant ki2c_writereg(sc, ADDR, addr | rw); 417 1.1 grant ki2c_writereg(sc, SUBADDR, subaddr); 418 1.1 grant 419 1.1 grant x = ki2c_readreg(sc, CONTROL) | I2C_CT_ADDR; 420 1.1 grant ki2c_writereg(sc, CONTROL, x); 421 1.1 grant 422 1.1 grant if (ki2c_poll(sc, timo)) 423 1.1 grant return -1; 424 1.1 grant if (sc->sc_flags & I2C_ERROR) { 425 1.20 macallan DPRINTF("I2C_ERROR\n"); 426 1.1 grant return -1; 427 1.1 grant } 428 1.1 grant return 0; 429 1.1 grant } 430 1.1 grant 431 1.1 grant int 432 1.15 dsl ki2c_read(struct ki2c_softc *sc, int addr, int subaddr, void *data, int len) 433 1.1 grant { 434 1.1 grant sc->sc_flags = I2C_READING; 435 1.20 macallan DPRINTF("ki2c_read: %02x %d\n", addr, len); 436 1.1 grant return ki2c_start(sc, addr, subaddr, data, len); 437 1.1 grant } 438 1.1 grant 439 1.1 grant int 440 1.15 dsl ki2c_write(struct ki2c_softc *sc, int addr, int subaddr, void *data, int len) 441 1.1 grant { 442 1.1 grant sc->sc_flags = 0; 443 1.20 macallan DPRINTF("ki2c_write: %02x %d\n",addr,len); 444 1.3 macallan return ki2c_start(sc, addr, subaddr, data, len); 445 1.3 macallan } 446 1.3 macallan 447 1.3 macallan int 448 1.3 macallan ki2c_i2c_exec(void *cookie, i2c_op_t op, i2c_addr_t addr, const void *vcmd, 449 1.3 macallan size_t cmdlen, void *vbuf, size_t buflen, int flags) 450 1.3 macallan { 451 1.3 macallan struct ki2c_softc *sc = cookie; 452 1.12 pgoyette int i; 453 1.12 pgoyette size_t w_len; 454 1.12 pgoyette uint8_t *wp; 455 1.33 mlelstv uint8_t wrbuf[KI2C_EXEC_MAX_CMDLEN + KI2C_EXEC_MAX_CMDLEN]; 456 1.25 macallan uint8_t channel; 457 1.12 pgoyette 458 1.12 pgoyette /* 459 1.12 pgoyette * We don't have any idea if the ki2c controller can execute 460 1.12 pgoyette * i2c quick_{read,write} operations, so if someone tries one, 461 1.12 pgoyette * return an error. 462 1.12 pgoyette */ 463 1.12 pgoyette if (cmdlen == 0 && buflen == 0) 464 1.12 pgoyette return -1; 465 1.12 pgoyette 466 1.33 mlelstv /* 467 1.33 mlelstv * Transaction could be much larger now. Bail if it exceeds our 468 1.33 mlelstv * small combining buffer, we don't expect such devices. 469 1.33 mlelstv */ 470 1.33 mlelstv if (cmdlen + buflen > sizeof(wrbuf)) 471 1.33 mlelstv return -1; 472 1.33 mlelstv 473 1.25 macallan channel = (addr & 0xf80) ? 0x10 : 0x00; 474 1.25 macallan addr &= 0x7f; 475 1.25 macallan 476 1.25 macallan 477 1.3 macallan /* we handle the subaddress stuff ourselves */ 478 1.25 macallan ki2c_setmode(sc, channel | I2C_STDMODE); 479 1.28 macallan ki2c_setspeed(sc, I2C_50kHz); 480 1.3 macallan 481 1.12 pgoyette /* Write-buffer defaults to vcmd */ 482 1.12 pgoyette wp = (uint8_t *)(__UNCONST(vcmd)); 483 1.12 pgoyette w_len = cmdlen; 484 1.12 pgoyette 485 1.12 pgoyette /* 486 1.12 pgoyette * Concatenate vcmd and vbuf for write operations 487 1.12 pgoyette * 488 1.12 pgoyette * Drivers written specifically for ki2c might already do this, 489 1.12 pgoyette * but "generic" i2c drivers still provide separate arguments 490 1.12 pgoyette * for the cmd and buf parts of iic_smbus_write_{byte,word}. 491 1.12 pgoyette */ 492 1.12 pgoyette if (I2C_OP_WRITE_P(op) && buflen != 0) { 493 1.12 pgoyette if (cmdlen == 0) { 494 1.12 pgoyette wp = (uint8_t *)vbuf; 495 1.12 pgoyette w_len = buflen; 496 1.12 pgoyette } else { 497 1.12 pgoyette KASSERT((cmdlen + buflen) <= sizeof(wrbuf)); 498 1.12 pgoyette wp = (uint8_t *)(__UNCONST(vcmd)); 499 1.12 pgoyette w_len = 0; 500 1.12 pgoyette for (i = 0; i < cmdlen; i++) 501 1.12 pgoyette wrbuf[w_len++] = *wp++; 502 1.12 pgoyette wp = (uint8_t *)vbuf; 503 1.12 pgoyette for (i = 0; i < buflen; i++) 504 1.12 pgoyette wrbuf[w_len++] = *wp++; 505 1.12 pgoyette wp = wrbuf; 506 1.12 pgoyette } 507 1.12 pgoyette } 508 1.12 pgoyette 509 1.22 macallan if (w_len > 0) 510 1.22 macallan if (ki2c_write(sc, addr << 1, 0, wp, w_len) !=0 ) 511 1.22 macallan return -1; 512 1.10 garbled 513 1.10 garbled if (I2C_OP_READ_P(op)) { 514 1.20 macallan if (ki2c_read(sc, addr << 1, 0, vbuf, buflen) !=0 ) 515 1.3 macallan return -1; 516 1.3 macallan } 517 1.3 macallan return 0; 518 1.1 grant } 519