iiconf.c revision 323419
1/*- 2 * Copyright (c) 1998 Nicolas Souchu 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * 1. Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * 2. Redistributions in binary form must reproduce the above copyright 11 * notice, this list of conditions and the following disclaimer in the 12 * documentation and/or other materials provided with the distribution. 13 * 14 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 15 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 18 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24 * SUCH DAMAGE. 25 */ 26 27#include <sys/cdefs.h> 28__FBSDID("$FreeBSD: stable/11/sys/dev/iicbus/iiconf.c 323419 2017-09-11 02:50:24Z ian $"); 29 30#include <sys/param.h> 31#include <sys/systm.h> 32#include <sys/lock.h> 33#include <sys/malloc.h> 34#include <sys/module.h> 35#include <sys/mutex.h> 36#include <sys/bus.h> 37 38#include <dev/iicbus/iiconf.h> 39#include <dev/iicbus/iicbus.h> 40#include "iicbus_if.h" 41 42/* 43 * Translate IIC_Exxxxx status values to vaguely-equivelent errno values. 44 */ 45int 46iic2errno(int iic_status) 47{ 48 switch (iic_status) { 49 case IIC_NOERR: return (0); 50 case IIC_EBUSERR: return (EALREADY); 51 case IIC_ENOACK: return (EIO); 52 case IIC_ETIMEOUT: return (ETIMEDOUT); 53 case IIC_EBUSBSY: return (EWOULDBLOCK); 54 case IIC_ESTATUS: return (EPROTO); 55 case IIC_EUNDERFLOW: return (EIO); 56 case IIC_EOVERFLOW: return (EOVERFLOW); 57 case IIC_ENOTSUPP: return (EOPNOTSUPP); 58 case IIC_ENOADDR: return (EADDRNOTAVAIL); 59 case IIC_ERESOURCE: return (ENOMEM); 60 default: return (EIO); 61 } 62} 63 64/* 65 * iicbus_intr() 66 */ 67void 68iicbus_intr(device_t bus, int event, char *buf) 69{ 70 struct iicbus_softc *sc = (struct iicbus_softc *)device_get_softc(bus); 71 72 /* call owner's intr routine */ 73 if (sc->owner) 74 IICBUS_INTR(sc->owner, event, buf); 75 76 return; 77} 78 79static int 80iicbus_poll(struct iicbus_softc *sc, int how) 81{ 82 int error; 83 84 IICBUS_ASSERT_LOCKED(sc); 85 switch (how) { 86 case IIC_WAIT | IIC_INTR: 87 error = mtx_sleep(sc, &sc->lock, IICPRI|PCATCH, "iicreq", 0); 88 break; 89 90 case IIC_WAIT | IIC_NOINTR: 91 error = mtx_sleep(sc, &sc->lock, IICPRI, "iicreq", 0); 92 break; 93 94 default: 95 return (IIC_EBUSBSY); 96 } 97 98 return (error); 99} 100 101/* 102 * iicbus_request_bus() 103 * 104 * Allocate the device to perform transfers. 105 * 106 * how : IIC_WAIT or IIC_DONTWAIT 107 */ 108int 109iicbus_request_bus(device_t bus, device_t dev, int how) 110{ 111 struct iicbus_softc *sc = (struct iicbus_softc *)device_get_softc(bus); 112 int error = 0; 113 114 IICBUS_LOCK(sc); 115 116 while ((error == 0) && (sc->owner != NULL)) 117 error = iicbus_poll(sc, how); 118 119 if (error == 0) { 120 sc->owner = dev; 121 /* 122 * Drop the lock around the call to the bus driver. 123 * This call should be allowed to sleep in the IIC_WAIT case. 124 * Drivers might also need to grab locks that would cause LOR 125 * if our lock is held. 126 */ 127 IICBUS_UNLOCK(sc); 128 /* Ask the underlying layers if the request is ok */ 129 error = IICBUS_CALLBACK(device_get_parent(bus), 130 IIC_REQUEST_BUS, (caddr_t)&how); 131 IICBUS_LOCK(sc); 132 133 if (error != 0) { 134 sc->owner = NULL; 135 wakeup_one(sc); 136 } 137 } 138 139 IICBUS_UNLOCK(sc); 140 141 return (error); 142} 143 144/* 145 * iicbus_release_bus() 146 * 147 * Release the device allocated with iicbus_request_dev() 148 */ 149int 150iicbus_release_bus(device_t bus, device_t dev) 151{ 152 struct iicbus_softc *sc = (struct iicbus_softc *)device_get_softc(bus); 153 int error; 154 155 IICBUS_LOCK(sc); 156 157 if (sc->owner != dev) { 158 IICBUS_UNLOCK(sc); 159 return (IIC_EBUSBSY); 160 } 161 162 /* 163 * Drop the lock around the call to the bus driver. 164 * This call should be allowed to sleep in the IIC_WAIT case. 165 * Drivers might also need to grab locks that would cause LOR 166 * if our lock is held. 167 */ 168 IICBUS_UNLOCK(sc); 169 /* Ask the underlying layers if the release is ok */ 170 error = IICBUS_CALLBACK(device_get_parent(bus), IIC_RELEASE_BUS, NULL); 171 172 if (error == 0) { 173 IICBUS_LOCK(sc); 174 sc->owner = NULL; 175 176 /* wakeup a waiting thread */ 177 wakeup_one(sc); 178 IICBUS_UNLOCK(sc); 179 } 180 181 return (error); 182} 183 184/* 185 * iicbus_started() 186 * 187 * Test if the iicbus is started by the controller 188 */ 189int 190iicbus_started(device_t bus) 191{ 192 struct iicbus_softc *sc = (struct iicbus_softc *)device_get_softc(bus); 193 194 return (sc->started); 195} 196 197/* 198 * iicbus_start() 199 * 200 * Send start condition to the slave addressed by 'slave' 201 */ 202int 203iicbus_start(device_t bus, u_char slave, int timeout) 204{ 205 struct iicbus_softc *sc = (struct iicbus_softc *)device_get_softc(bus); 206 int error = 0; 207 208 if (sc->started) 209 return (IIC_ESTATUS); /* protocol error, bus already started */ 210 211 if (!(error = IICBUS_START(device_get_parent(bus), slave, timeout))) 212 sc->started = slave; 213 else 214 sc->started = 0; 215 216 return (error); 217} 218 219/* 220 * iicbus_repeated_start() 221 * 222 * Send start condition to the slave addressed by 'slave' 223 */ 224int 225iicbus_repeated_start(device_t bus, u_char slave, int timeout) 226{ 227 struct iicbus_softc *sc = (struct iicbus_softc *)device_get_softc(bus); 228 int error = 0; 229 230 if (!sc->started) 231 return (IIC_ESTATUS); /* protocol error, bus not started */ 232 233 if (!(error = IICBUS_REPEATED_START(device_get_parent(bus), slave, timeout))) 234 sc->started = slave; 235 else 236 sc->started = 0; 237 238 return (error); 239} 240 241/* 242 * iicbus_stop() 243 * 244 * Send stop condition to the bus 245 */ 246int 247iicbus_stop(device_t bus) 248{ 249 struct iicbus_softc *sc = (struct iicbus_softc *)device_get_softc(bus); 250 int error = 0; 251 252 if (!sc->started) 253 return (IIC_ESTATUS); /* protocol error, bus not started */ 254 255 error = IICBUS_STOP(device_get_parent(bus)); 256 257 /* refuse any further access */ 258 sc->started = 0; 259 260 return (error); 261} 262 263/* 264 * iicbus_write() 265 * 266 * Write a block of data to the slave previously started by 267 * iicbus_start() call 268 */ 269int 270iicbus_write(device_t bus, const char *buf, int len, int *sent, int timeout) 271{ 272 struct iicbus_softc *sc = (struct iicbus_softc *)device_get_softc(bus); 273 274 /* a slave must have been started for writing */ 275 if (sc->started == 0 || (sc->strict != 0 && (sc->started & LSB) != 0)) 276 return (IIC_ESTATUS); 277 278 return (IICBUS_WRITE(device_get_parent(bus), buf, len, sent, timeout)); 279} 280 281/* 282 * iicbus_read() 283 * 284 * Read a block of data from the slave previously started by 285 * iicbus_read() call 286 */ 287int 288iicbus_read(device_t bus, char *buf, int len, int *read, int last, int delay) 289{ 290 struct iicbus_softc *sc = (struct iicbus_softc *)device_get_softc(bus); 291 292 /* a slave must have been started for reading */ 293 if (sc->started == 0 || (sc->strict != 0 && (sc->started & LSB) == 0)) 294 return (IIC_ESTATUS); 295 296 return (IICBUS_READ(device_get_parent(bus), buf, len, read, last, delay)); 297} 298 299/* 300 * iicbus_write_byte() 301 * 302 * Write a byte to the slave previously started by iicbus_start() call 303 */ 304int 305iicbus_write_byte(device_t bus, char byte, int timeout) 306{ 307 struct iicbus_softc *sc = device_get_softc(bus); 308 char data = byte; 309 int sent; 310 311 /* a slave must have been started for writing */ 312 if (sc->started == 0 || (sc->strict != 0 && (sc->started & LSB) != 0)) 313 return (IIC_ESTATUS); 314 315 return (iicbus_write(bus, &data, 1, &sent, timeout)); 316} 317 318/* 319 * iicbus_read_byte() 320 * 321 * Read a byte from the slave previously started by iicbus_start() call 322 */ 323int 324iicbus_read_byte(device_t bus, char *byte, int timeout) 325{ 326 struct iicbus_softc *sc = device_get_softc(bus); 327 int read; 328 329 /* a slave must have been started for reading */ 330 if (sc->started == 0 || (sc->strict != 0 && (sc->started & LSB) == 0)) 331 return (IIC_ESTATUS); 332 333 return (iicbus_read(bus, byte, 1, &read, IIC_LAST_READ, timeout)); 334} 335 336/* 337 * iicbus_block_write() 338 * 339 * Write a block of data to slave ; start/stop protocol managed 340 */ 341int 342iicbus_block_write(device_t bus, u_char slave, char *buf, int len, int *sent) 343{ 344 u_char addr = slave & ~LSB; 345 int error; 346 347 if ((error = iicbus_start(bus, addr, 0))) 348 return (error); 349 350 error = iicbus_write(bus, buf, len, sent, 0); 351 352 iicbus_stop(bus); 353 354 return (error); 355} 356 357/* 358 * iicbus_block_read() 359 * 360 * Read a block of data from slave ; start/stop protocol managed 361 */ 362int 363iicbus_block_read(device_t bus, u_char slave, char *buf, int len, int *read) 364{ 365 u_char addr = slave | LSB; 366 int error; 367 368 if ((error = iicbus_start(bus, addr, 0))) 369 return (error); 370 371 error = iicbus_read(bus, buf, len, read, IIC_LAST_READ, 0); 372 373 iicbus_stop(bus); 374 375 return (error); 376} 377 378/* 379 * iicbus_transfer() 380 * 381 * Do an aribtrary number of transfers on the iicbus. We pass these 382 * raw requests to the bridge driver. If the bridge driver supports 383 * them directly, then it manages all the details. If not, it can use 384 * the helper function iicbus_transfer_gen() which will do the 385 * transfers at a low level. 386 * 387 * Pointers passed in as part of iic_msg must be kernel pointers. 388 * Callers that have user addresses to manage must do so on their own. 389 */ 390int 391iicbus_transfer(device_t bus, struct iic_msg *msgs, uint32_t nmsgs) 392{ 393 394 return (IICBUS_TRANSFER(device_get_parent(bus), msgs, nmsgs)); 395} 396 397int 398iicbus_transfer_excl(device_t dev, struct iic_msg *msgs, uint32_t nmsgs, 399 int how) 400{ 401 device_t bus; 402 int error; 403 404 bus = device_get_parent(dev); 405 error = iicbus_request_bus(bus, dev, how); 406 if (error == 0) 407 error = IICBUS_TRANSFER(bus, msgs, nmsgs); 408 iicbus_release_bus(bus, dev); 409 return (error); 410} 411 412/* 413 * Generic version of iicbus_transfer that calls the appropriate 414 * routines to accomplish this. See note above about acceptable 415 * buffer addresses. 416 */ 417int 418iicbus_transfer_gen(device_t dev, struct iic_msg *msgs, uint32_t nmsgs) 419{ 420 int i, error, lenread, lenwrote, nkid, rpstart, addr; 421 device_t *children, bus; 422 bool nostop, started; 423 424 if ((error = device_get_children(dev, &children, &nkid)) != 0) 425 return (IIC_ERESOURCE); 426 if (nkid != 1) { 427 free(children, M_TEMP); 428 return (IIC_ENOTSUPP); 429 } 430 bus = children[0]; 431 rpstart = 0; 432 free(children, M_TEMP); 433 nostop = iicbus_get_nostop(dev); 434 started = false; 435 for (i = 0, error = 0; i < nmsgs && error == 0; i++) { 436 addr = msgs[i].slave; 437 if (msgs[i].flags & IIC_M_RD) 438 addr |= LSB; 439 else 440 addr &= ~LSB; 441 442 if (!(msgs[i].flags & IIC_M_NOSTART)) { 443 if (rpstart) 444 error = iicbus_repeated_start(bus, addr, 0); 445 else 446 error = iicbus_start(bus, addr, 0); 447 if (error != 0) 448 break; 449 started = true; 450 } 451 452 if (msgs[i].flags & IIC_M_RD) 453 error = iicbus_read(bus, msgs[i].buf, msgs[i].len, 454 &lenread, IIC_LAST_READ, 0); 455 else 456 error = iicbus_write(bus, msgs[i].buf, msgs[i].len, 457 &lenwrote, 0); 458 if (error != 0) 459 break; 460 461 if ((msgs[i].flags & IIC_M_NOSTOP) != 0 || 462 (nostop && i + 1 < nmsgs)) { 463 rpstart = 1; /* Next message gets repeated start */ 464 } else { 465 rpstart = 0; 466 iicbus_stop(bus); 467 } 468 } 469 if (error != 0 && started) 470 iicbus_stop(bus); 471 return (error); 472} 473