138774Snsouch/*- 238774Snsouch * Copyright (c) 1998 Nicolas Souchu 338774Snsouch * All rights reserved. 438774Snsouch * 538774Snsouch * Redistribution and use in source and binary forms, with or without 638774Snsouch * modification, are permitted provided that the following conditions 738774Snsouch * are met: 838774Snsouch * 1. Redistributions of source code must retain the above copyright 938774Snsouch * notice, this list of conditions and the following disclaimer. 1038774Snsouch * 2. Redistributions in binary form must reproduce the above copyright 1138774Snsouch * notice, this list of conditions and the following disclaimer in the 1238774Snsouch * documentation and/or other materials provided with the distribution. 1338774Snsouch * 1438774Snsouch * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 1538774Snsouch * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 1638774Snsouch * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 1738774Snsouch * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 1838774Snsouch * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 1938774Snsouch * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 2038774Snsouch * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 2138774Snsouch * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 2238774Snsouch * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 2338774Snsouch * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 2438774Snsouch * SUCH DAMAGE. 2538774Snsouch */ 26119418Sobrien 27119418Sobrien#include <sys/cdefs.h> 28119418Sobrien__FBSDID("$FreeBSD: stable/11/sys/dev/iicbus/iiconf.c 350031 2019-07-16 15:02:28Z avg $"); 29119418Sobrien 3038774Snsouch#include <sys/param.h> 3138774Snsouch#include <sys/systm.h> 32181304Sjhb#include <sys/lock.h> 33167855Simp#include <sys/malloc.h> 3438774Snsouch#include <sys/module.h> 35181304Sjhb#include <sys/mutex.h> 3638774Snsouch#include <sys/bus.h> 3738774Snsouch 3838774Snsouch#include <dev/iicbus/iiconf.h> 3938774Snsouch#include <dev/iicbus/iicbus.h> 4038774Snsouch#include "iicbus_if.h" 4138774Snsouch 4238774Snsouch/* 43289095Sian * Translate IIC_Exxxxx status values to vaguely-equivelent errno values. 44289095Sian */ 45289095Sianint 46289095Sianiic2errno(int iic_status) 47289095Sian{ 48289095Sian switch (iic_status) { 49289095Sian case IIC_NOERR: return (0); 50289095Sian case IIC_EBUSERR: return (EALREADY); 51289095Sian case IIC_ENOACK: return (EIO); 52289095Sian case IIC_ETIMEOUT: return (ETIMEDOUT); 53289095Sian case IIC_EBUSBSY: return (EWOULDBLOCK); 54289095Sian case IIC_ESTATUS: return (EPROTO); 55289095Sian case IIC_EUNDERFLOW: return (EIO); 56289095Sian case IIC_EOVERFLOW: return (EOVERFLOW); 57289095Sian case IIC_ENOTSUPP: return (EOPNOTSUPP); 58289095Sian case IIC_ENOADDR: return (EADDRNOTAVAIL); 59289095Sian case IIC_ERESOURCE: return (ENOMEM); 60289095Sian default: return (EIO); 61289095Sian } 62289095Sian} 63289095Sian 64289095Sian/* 6538774Snsouch * iicbus_intr() 6638774Snsouch */ 6738774Snsouchvoid 6838774Snsouchiicbus_intr(device_t bus, int event, char *buf) 6938774Snsouch{ 7038774Snsouch struct iicbus_softc *sc = (struct iicbus_softc *)device_get_softc(bus); 7138774Snsouch 7238774Snsouch /* call owner's intr routine */ 7338774Snsouch if (sc->owner) 7438774Snsouch IICBUS_INTR(sc->owner, event, buf); 7538774Snsouch 7638774Snsouch return; 7738774Snsouch} 7838774Snsouch 7940782Snsouchstatic int 8040782Snsouchiicbus_poll(struct iicbus_softc *sc, int how) 8140782Snsouch{ 8240782Snsouch int error; 8340782Snsouch 84181304Sjhb IICBUS_ASSERT_LOCKED(sc); 85331497Sian switch (how & IIC_INTRWAIT) { 86181304Sjhb case IIC_WAIT | IIC_INTR: 87181304Sjhb error = mtx_sleep(sc, &sc->lock, IICPRI|PCATCH, "iicreq", 0); 8840782Snsouch break; 8940782Snsouch 90181304Sjhb case IIC_WAIT | IIC_NOINTR: 91181304Sjhb error = mtx_sleep(sc, &sc->lock, IICPRI, "iicreq", 0); 9240782Snsouch break; 9340782Snsouch 9440782Snsouch default: 95289098Sian return (IIC_EBUSBSY); 9640782Snsouch } 9740782Snsouch 9840782Snsouch return (error); 9940782Snsouch} 10040782Snsouch 10138774Snsouch/* 10238774Snsouch * iicbus_request_bus() 10338774Snsouch * 10438774Snsouch * Allocate the device to perform transfers. 10538774Snsouch * 10638774Snsouch * how : IIC_WAIT or IIC_DONTWAIT 10738774Snsouch */ 10838774Snsouchint 10938774Snsouchiicbus_request_bus(device_t bus, device_t dev, int how) 11038774Snsouch{ 11138774Snsouch struct iicbus_softc *sc = (struct iicbus_softc *)device_get_softc(bus); 112181304Sjhb int error = 0; 11338774Snsouch 114181304Sjhb IICBUS_LOCK(sc); 11540782Snsouch 116331497Sian for (;;) { 117331497Sian if (sc->owner == NULL) 118331497Sian break; 119331497Sian if ((how & IIC_RECURSIVE) && sc->owner == dev) 120331497Sian break; 121331497Sian if ((error = iicbus_poll(sc, how)) != 0) 122331497Sian break; 123331497Sian } 12438774Snsouch 125281828Sjah if (error == 0) { 126323446Sian ++sc->owncount; 127323446Sian if (sc->owner == NULL) { 128323446Sian sc->owner = dev; 129323446Sian /* 130323446Sian * Drop the lock around the call to the bus driver, it 131323446Sian * should be allowed to sleep in the IIC_WAIT case. 132323446Sian * Drivers might also need to grab locks that would 133323446Sian * cause a LOR if our lock is held. 134323446Sian */ 135323446Sian IICBUS_UNLOCK(sc); 136323446Sian /* Ask the underlying layers if the request is ok */ 137323446Sian error = IICBUS_CALLBACK(device_get_parent(bus), 138323446Sian IIC_REQUEST_BUS, (caddr_t)&how); 139323446Sian IICBUS_LOCK(sc); 140323446Sian 141323446Sian if (error != 0) { 142323446Sian sc->owner = NULL; 143323446Sian sc->owncount = 0; 144323446Sian wakeup_one(sc); 145323446Sian } 14638774Snsouch } 147281828Sjah } 14843976Snsouch 149181304Sjhb IICBUS_UNLOCK(sc); 15038774Snsouch 15138774Snsouch return (error); 15238774Snsouch} 15338774Snsouch 15438774Snsouch/* 15538774Snsouch * iicbus_release_bus() 15638774Snsouch * 15738774Snsouch * Release the device allocated with iicbus_request_dev() 15838774Snsouch */ 15938774Snsouchint 16038774Snsouchiicbus_release_bus(device_t bus, device_t dev) 16138774Snsouch{ 16238774Snsouch struct iicbus_softc *sc = (struct iicbus_softc *)device_get_softc(bus); 16338774Snsouch 164181304Sjhb IICBUS_LOCK(sc); 165181304Sjhb 16638774Snsouch if (sc->owner != dev) { 167181304Sjhb IICBUS_UNLOCK(sc); 168289098Sian return (IIC_EBUSBSY); 16938774Snsouch } 17038774Snsouch 171323446Sian if (--sc->owncount == 0) { 172323446Sian /* Drop the lock while informing the low-level driver. */ 173323446Sian IICBUS_UNLOCK(sc); 174323446Sian IICBUS_CALLBACK(device_get_parent(bus), IIC_RELEASE_BUS, NULL); 175281828Sjah IICBUS_LOCK(sc); 176281828Sjah sc->owner = NULL; 177281828Sjah wakeup_one(sc); 178281828Sjah } 179323446Sian IICBUS_UNLOCK(sc); 180323446Sian return (0); 18138774Snsouch} 18238774Snsouch 18338774Snsouch/* 18442442Snsouch * iicbus_started() 18542442Snsouch * 18642442Snsouch * Test if the iicbus is started by the controller 18742442Snsouch */ 18842442Snsouchint 18942442Snsouchiicbus_started(device_t bus) 19042442Snsouch{ 19142442Snsouch struct iicbus_softc *sc = (struct iicbus_softc *)device_get_softc(bus); 19242442Snsouch 19342442Snsouch return (sc->started); 19442442Snsouch} 19542442Snsouch 19642442Snsouch/* 19742442Snsouch * iicbus_start() 19842442Snsouch * 19942442Snsouch * Send start condition to the slave addressed by 'slave' 20042442Snsouch */ 20142442Snsouchint 20242442Snsouchiicbus_start(device_t bus, u_char slave, int timeout) 20342442Snsouch{ 20442442Snsouch struct iicbus_softc *sc = (struct iicbus_softc *)device_get_softc(bus); 20542442Snsouch int error = 0; 20642442Snsouch 20742442Snsouch if (sc->started) 208289097Sian return (IIC_ESTATUS); /* protocol error, bus already started */ 20942442Snsouch 21042442Snsouch if (!(error = IICBUS_START(device_get_parent(bus), slave, timeout))) 21142442Snsouch sc->started = slave; 21242442Snsouch else 21342442Snsouch sc->started = 0; 21442442Snsouch 21542442Snsouch return (error); 21642442Snsouch} 21742442Snsouch 21842442Snsouch/* 21943347Sroger * iicbus_repeated_start() 22043347Sroger * 22143347Sroger * Send start condition to the slave addressed by 'slave' 22243347Sroger */ 22343347Srogerint 22443347Srogeriicbus_repeated_start(device_t bus, u_char slave, int timeout) 22543347Sroger{ 22643347Sroger struct iicbus_softc *sc = (struct iicbus_softc *)device_get_softc(bus); 22743347Sroger int error = 0; 22843347Sroger 22943347Sroger if (!sc->started) 230289097Sian return (IIC_ESTATUS); /* protocol error, bus not started */ 23143347Sroger 23243714Sroger if (!(error = IICBUS_REPEATED_START(device_get_parent(bus), slave, timeout))) 23343347Sroger sc->started = slave; 23443347Sroger else 23543347Sroger sc->started = 0; 23643347Sroger 23743347Sroger return (error); 23843347Sroger} 23943347Sroger 24043347Sroger/* 24142442Snsouch * iicbus_stop() 24242442Snsouch * 24342442Snsouch * Send stop condition to the bus 24442442Snsouch */ 24542442Snsouchint 24642442Snsouchiicbus_stop(device_t bus) 24742442Snsouch{ 24842442Snsouch struct iicbus_softc *sc = (struct iicbus_softc *)device_get_softc(bus); 24942442Snsouch int error = 0; 25042442Snsouch 25142442Snsouch if (!sc->started) 252289097Sian return (IIC_ESTATUS); /* protocol error, bus not started */ 25342442Snsouch 25442442Snsouch error = IICBUS_STOP(device_get_parent(bus)); 25542442Snsouch 25642442Snsouch /* refuse any further access */ 25742442Snsouch sc->started = 0; 25842442Snsouch 25942442Snsouch return (error); 26042442Snsouch} 26142442Snsouch 26242442Snsouch/* 26342442Snsouch * iicbus_write() 26442442Snsouch * 26542442Snsouch * Write a block of data to the slave previously started by 26642442Snsouch * iicbus_start() call 26742442Snsouch */ 26842442Snsouchint 269164901Simpiicbus_write(device_t bus, const char *buf, int len, int *sent, int timeout) 27042442Snsouch{ 27142442Snsouch struct iicbus_softc *sc = (struct iicbus_softc *)device_get_softc(bus); 27242442Snsouch 273228257Sadrian /* a slave must have been started for writing */ 274228257Sadrian if (sc->started == 0 || (sc->strict != 0 && (sc->started & LSB) != 0)) 275289097Sian return (IIC_ESTATUS); 27642442Snsouch 27742442Snsouch return (IICBUS_WRITE(device_get_parent(bus), buf, len, sent, timeout)); 27842442Snsouch} 27942442Snsouch 28042442Snsouch/* 28142442Snsouch * iicbus_read() 28242442Snsouch * 28342442Snsouch * Read a block of data from the slave previously started by 28442442Snsouch * iicbus_read() call 28542442Snsouch */ 28642442Snsouchint 28742442Snsouchiicbus_read(device_t bus, char *buf, int len, int *read, int last, int delay) 28842442Snsouch{ 28942442Snsouch struct iicbus_softc *sc = (struct iicbus_softc *)device_get_softc(bus); 29042442Snsouch 291228257Sadrian /* a slave must have been started for reading */ 292228257Sadrian if (sc->started == 0 || (sc->strict != 0 && (sc->started & LSB) == 0)) 293289097Sian return (IIC_ESTATUS); 29442442Snsouch 29542442Snsouch return (IICBUS_READ(device_get_parent(bus), buf, len, read, last, delay)); 29642442Snsouch} 29742442Snsouch 29842442Snsouch/* 29943347Sroger * iicbus_write_byte() 30043347Sroger * 30143347Sroger * Write a byte to the slave previously started by iicbus_start() call 30243347Sroger */ 30343347Srogerint 30443347Srogeriicbus_write_byte(device_t bus, char byte, int timeout) 30543347Sroger{ 306289097Sian struct iicbus_softc *sc = device_get_softc(bus); 30743347Sroger char data = byte; 30843347Sroger int sent; 30943347Sroger 310289097Sian /* a slave must have been started for writing */ 311289097Sian if (sc->started == 0 || (sc->strict != 0 && (sc->started & LSB) != 0)) 312289097Sian return (IIC_ESTATUS); 313289097Sian 31443347Sroger return (iicbus_write(bus, &data, 1, &sent, timeout)); 31543347Sroger} 31643347Sroger 31743347Sroger/* 31843347Sroger * iicbus_read_byte() 31943347Sroger * 32043347Sroger * Read a byte from the slave previously started by iicbus_start() call 32143347Sroger */ 32243347Srogerint 32343347Srogeriicbus_read_byte(device_t bus, char *byte, int timeout) 32443347Sroger{ 325289097Sian struct iicbus_softc *sc = device_get_softc(bus); 32643347Sroger int read; 32743347Sroger 328289097Sian /* a slave must have been started for reading */ 329289097Sian if (sc->started == 0 || (sc->strict != 0 && (sc->started & LSB) == 0)) 330289097Sian return (IIC_ESTATUS); 331289097Sian 33243347Sroger return (iicbus_read(bus, byte, 1, &read, IIC_LAST_READ, timeout)); 33343347Sroger} 33443347Sroger 33543347Sroger/* 33638774Snsouch * iicbus_block_write() 33738774Snsouch * 33838774Snsouch * Write a block of data to slave ; start/stop protocol managed 33938774Snsouch */ 34038774Snsouchint 34138774Snsouchiicbus_block_write(device_t bus, u_char slave, char *buf, int len, int *sent) 34238774Snsouch{ 34338774Snsouch u_char addr = slave & ~LSB; 34438774Snsouch int error; 34538774Snsouch 34640782Snsouch if ((error = iicbus_start(bus, addr, 0))) 34738774Snsouch return (error); 34838774Snsouch 34940782Snsouch error = iicbus_write(bus, buf, len, sent, 0); 35038774Snsouch 35138774Snsouch iicbus_stop(bus); 35238774Snsouch 35338774Snsouch return (error); 35438774Snsouch} 35538774Snsouch 35638774Snsouch/* 35738774Snsouch * iicbus_block_read() 35838774Snsouch * 35938774Snsouch * Read a block of data from slave ; start/stop protocol managed 36038774Snsouch */ 36138774Snsouchint 36238774Snsouchiicbus_block_read(device_t bus, u_char slave, char *buf, int len, int *read) 36338774Snsouch{ 36438774Snsouch u_char addr = slave | LSB; 36538774Snsouch int error; 36638774Snsouch 36740782Snsouch if ((error = iicbus_start(bus, addr, 0))) 36838774Snsouch return (error); 36938774Snsouch 37040782Snsouch error = iicbus_read(bus, buf, len, read, IIC_LAST_READ, 0); 37138774Snsouch 37240782Snsouch iicbus_stop(bus); 37338774Snsouch 37438774Snsouch return (error); 37538774Snsouch} 376160372Simp 377160372Simp/* 378181304Sjhb * iicbus_transfer() 379160372Simp * 380160372Simp * Do an aribtrary number of transfers on the iicbus. We pass these 381160372Simp * raw requests to the bridge driver. If the bridge driver supports 382160372Simp * them directly, then it manages all the details. If not, it can use 383160372Simp * the helper function iicbus_transfer_gen() which will do the 384160372Simp * transfers at a low level. 385160372Simp * 386160372Simp * Pointers passed in as part of iic_msg must be kernel pointers. 387160372Simp * Callers that have user addresses to manage must do so on their own. 388160372Simp */ 389160372Simpint 390160372Simpiicbus_transfer(device_t bus, struct iic_msg *msgs, uint32_t nmsgs) 391160372Simp{ 392289097Sian 393160372Simp return (IICBUS_TRANSFER(device_get_parent(bus), msgs, nmsgs)); 394160372Simp} 395160372Simp 396289726Sianint 397289726Sianiicbus_transfer_excl(device_t dev, struct iic_msg *msgs, uint32_t nmsgs, 398289726Sian int how) 399289726Sian{ 400289726Sian device_t bus; 401289726Sian int error; 402289726Sian 403289726Sian bus = device_get_parent(dev); 404289726Sian error = iicbus_request_bus(bus, dev, how); 405289726Sian if (error == 0) 406289726Sian error = IICBUS_TRANSFER(bus, msgs, nmsgs); 407289726Sian iicbus_release_bus(bus, dev); 408289726Sian return (error); 409289726Sian} 410289726Sian 411160372Simp/* 412160372Simp * Generic version of iicbus_transfer that calls the appropriate 413160372Simp * routines to accomplish this. See note above about acceptable 414160372Simp * buffer addresses. 415160372Simp */ 416160372Simpint 417167855Simpiicbus_transfer_gen(device_t dev, struct iic_msg *msgs, uint32_t nmsgs) 418160372Simp{ 419214999Snwhitehorn int i, error, lenread, lenwrote, nkid, rpstart, addr; 420167855Simp device_t *children, bus; 421350031Savg bool started; 422160372Simp 423182034Simp if ((error = device_get_children(dev, &children, &nkid)) != 0) 424289097Sian return (IIC_ERESOURCE); 425182034Simp if (nkid != 1) { 426182034Simp free(children, M_TEMP); 427289097Sian return (IIC_ENOTSUPP); 428182034Simp } 429167855Simp bus = children[0]; 430214999Snwhitehorn rpstart = 0; 431167855Simp free(children, M_TEMP); 432323419Sian started = false; 433160372Simp for (i = 0, error = 0; i < nmsgs && error == 0; i++) { 434214999Snwhitehorn addr = msgs[i].slave; 435160372Simp if (msgs[i].flags & IIC_M_RD) 436214999Snwhitehorn addr |= LSB; 437160372Simp else 438214999Snwhitehorn addr &= ~LSB; 439214999Snwhitehorn 440214999Snwhitehorn if (!(msgs[i].flags & IIC_M_NOSTART)) { 441214999Snwhitehorn if (rpstart) 442214999Snwhitehorn error = iicbus_repeated_start(bus, addr, 0); 443214999Snwhitehorn else 444214999Snwhitehorn error = iicbus_start(bus, addr, 0); 445323419Sian if (error != 0) 446323419Sian break; 447323419Sian started = true; 448214999Snwhitehorn } 449214999Snwhitehorn 450214999Snwhitehorn if (msgs[i].flags & IIC_M_RD) 451214999Snwhitehorn error = iicbus_read(bus, msgs[i].buf, msgs[i].len, 452214999Snwhitehorn &lenread, IIC_LAST_READ, 0); 453214999Snwhitehorn else 454214999Snwhitehorn error = iicbus_write(bus, msgs[i].buf, msgs[i].len, 455214999Snwhitehorn &lenwrote, 0); 456289084Sian if (error != 0) 457289084Sian break; 458214999Snwhitehorn 459350031Savg if (!(msgs[i].flags & IIC_M_NOSTOP)) { 460214999Snwhitehorn rpstart = 0; 461214999Snwhitehorn iicbus_stop(bus); 462350031Savg } else { 463350031Savg rpstart = 1; /* Next message gets repeated start */ 464214999Snwhitehorn } 465160372Simp } 466323419Sian if (error != 0 && started) 467289084Sian iicbus_stop(bus); 468160372Simp return (error); 469160372Simp} 470323446Sian 471323446Sianint 472323446Sianiicdev_readfrom(device_t slavedev, uint8_t regaddr, void *buffer, 473323446Sian uint16_t buflen, int waithow) 474323446Sian{ 475323446Sian struct iic_msg msgs[2]; 476323446Sian uint8_t slaveaddr; 477323446Sian 478323446Sian /* 479323446Sian * Two transfers back to back with a repeat-start between them; first we 480323446Sian * write the address-within-device, then we read from the device. 481323446Sian */ 482323446Sian slaveaddr = iicbus_get_addr(slavedev); 483323446Sian 484323446Sian msgs[0].slave = slaveaddr; 485323446Sian msgs[0].flags = IIC_M_WR | IIC_M_NOSTOP; 486323446Sian msgs[0].len = 1; 487323446Sian msgs[0].buf = ®addr; 488323446Sian 489323446Sian msgs[1].slave = slaveaddr; 490323446Sian msgs[1].flags = IIC_M_RD; 491323446Sian msgs[1].len = buflen; 492323446Sian msgs[1].buf = buffer; 493323446Sian 494323446Sian return (iicbus_transfer_excl(slavedev, msgs, nitems(msgs), waithow)); 495323446Sian} 496323446Sian 497323446Sianint iicdev_writeto(device_t slavedev, uint8_t regaddr, void *buffer, 498323446Sian uint16_t buflen, int waithow) 499323446Sian{ 500323446Sian struct iic_msg msgs[2]; 501323446Sian uint8_t slaveaddr; 502323446Sian 503323446Sian /* 504323446Sian * Two transfers back to back with no stop or start between them; first 505323446Sian * we write the address then we write the data to that address, all in a 506323446Sian * single transfer from two scattered buffers. 507323446Sian */ 508323446Sian slaveaddr = iicbus_get_addr(slavedev); 509323446Sian 510323446Sian msgs[0].slave = slaveaddr; 511323446Sian msgs[0].flags = IIC_M_WR | IIC_M_NOSTOP; 512323446Sian msgs[0].len = 1; 513323446Sian msgs[0].buf = ®addr; 514323446Sian 515323446Sian msgs[1].slave = slaveaddr; 516323446Sian msgs[1].flags = IIC_M_WR | IIC_M_NOSTART; 517323446Sian msgs[1].len = buflen; 518323446Sian msgs[1].buf = buffer; 519323446Sian 520323446Sian return (iicbus_transfer_excl(slavedev, msgs, nitems(msgs), waithow)); 521323446Sian} 522