xlr_i2c.c revision 241844
1198160Srrs/*- 2198160Srrs * Copyright (c) 2003-2009 RMI Corporation 3198160Srrs * All rights reserved. 4198160Srrs * 5198160Srrs * Redistribution and use in source and binary forms, with or without 6198160Srrs * modification, are permitted provided that the following conditions 7198160Srrs * are met: 8198160Srrs * 1. Redistributions of source code must retain the above copyright 9198160Srrs * notice, this list of conditions and the following disclaimer. 10198160Srrs * 2. Redistributions in binary form must reproduce the above copyright 11198160Srrs * notice, this list of conditions and the following disclaimer in the 12198160Srrs * documentation and/or other materials provided with the distribution. 13198160Srrs * 3. Neither the name of RMI Corporation, nor the names of its contributors, 14198160Srrs * may be used to endorse or promote products derived from this software 15198160Srrs * without specific prior written permission. 16198160Srrs * 17198160Srrs * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 18198160Srrs * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 19198160Srrs * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 20198160Srrs * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 21198160Srrs * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 22198160Srrs * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 23198160Srrs * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 24198160Srrs * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 25198160Srrs * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 26198160Srrs * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 27198160Srrs * SUCH DAMAGE. 28198160Srrs * 29198160Srrs * RMI_BSD */ 30198160Srrs 31198160Srrs#include <sys/cdefs.h> 32202173Simp__FBSDID("$FreeBSD: head/sys/mips/rmi/xlr_i2c.c 241844 2012-10-22 03:00:37Z eadler $"); 33198160Srrs 34198160Srrs/* 35198160Srrs * I2C driver for the Palm-BK3220 I2C Host adapter on the RMI XLR. 36198160Srrs */ 37198160Srrs 38198160Srrs#include <sys/param.h> 39198160Srrs#include <sys/systm.h> 40198160Srrs#include <sys/kernel.h> 41216390Sjchandra#include <sys/lock.h> 42198160Srrs#include <sys/module.h> 43216390Sjchandra#include <sys/mutex.h> 44198625Srrs#include <sys/bus.h> 45198160Srrs#include <sys/rman.h> 46198160Srrs 47198160Srrs 48198160Srrs#include <dev/iicbus/iiconf.h> 49198160Srrs#include <dev/iicbus/iicbus.h> 50198160Srrs 51216390Sjchandra#include <mips/rmi/board.h> 52198607Srrs#include <mips/rmi/iomap.h> 53198160Srrs#include <mips/include/resource.h> 54198160Srrs 55198160Srrs#include "iicbus_if.h" 56198160Srrs 57216390Sjchandra/* XLR I2C REGISTERS */ 58216390Sjchandra#define XLR_I2C_CFG 0x00 59216390Sjchandra#define XLR_I2C_CLKDIV 0x01 60216390Sjchandra#define XLR_I2C_DEVADDR 0x02 61216390Sjchandra#define XLR_I2C_ADDR 0x03 62216390Sjchandra#define XLR_I2C_DATAOUT 0x04 63216390Sjchandra#define XLR_I2C_DATAIN 0x05 64216390Sjchandra#define XLR_I2C_STATUS 0x06 65216390Sjchandra#define XLR_I2C_STARTXFR 0x07 66216390Sjchandra#define XLR_I2C_BYTECNT 0x08 67216390Sjchandra#define XLR_I2C_HDSTATIM 0x09 68198160Srrs 69216390Sjchandra/* XLR I2C REGISTERS FLAGS */ 70216390Sjchandra#define XLR_I2C_BUS_BUSY 0x01 71216390Sjchandra#define XLR_I2C_SDOEMPTY 0x02 72216390Sjchandra#define XLR_I2C_RXRDY 0x04 73216390Sjchandra#define XLR_I2C_ACK_ERR 0x08 74216390Sjchandra#define XLR_I2C_ARB_STARTERR 0x30 75198160Srrs 76216390Sjchandra/* Register Programming Values!! Change as required */ 77216390Sjchandra#define XLR_I2C_CFG_ADDR 0xF8 /* 8-Bit dev Addr + POR Values */ 78216390Sjchandra#define XLR_I2C_CFG_NOADDR 0xFA /* 8-Bit reg Addr + POR Values : No dev addr */ 79216390Sjchandra#define XLR_I2C_STARTXFR_ND 0x02 /* No data , only addr */ 80216390Sjchandra#define XLR_I2C_STARTXFR_RD 0x01 /* Read */ 81216390Sjchandra#define XLR_I2C_STARTXFR_WR 0x00 /* Write */ 82216390Sjchandra#define XLR_I2C_CLKDIV_DEF 0x14A /* 0x00000052 */ 83216390Sjchandra#define XLR_I2C_HDSTATIM_DEF 0x107 /* 0x00000000 */ 84198160Srrs 85216390Sjchandra#define MAXTIME 0x10000 86216390Sjchandra#define ARIZONA_I2C_BUS 1 87198160Srrs 88198160Srrsstatic devclass_t xlr_i2c_devclass; 89198160Srrs 90198160Srrs/* 91198160Srrs * Device methods 92198160Srrs */ 93198160Srrsstatic int xlr_i2c_probe(device_t); 94198160Srrsstatic int xlr_i2c_attach(device_t); 95198160Srrsstatic int xlr_i2c_detach(device_t); 96198160Srrs 97198160Srrsstatic int xlr_i2c_start(device_t dev, u_char slave, int timeout); 98198160Srrsstatic int xlr_i2c_stop(device_t dev); 99198625Srrsstatic int xlr_i2c_read(device_t dev, char *buf, int len, int *read, int last, int delay); 100216390Sjchandrastatic int xlr_i2c_write(device_t dev, const char *buf, int len, int *sent, int timeout); 101216390Sjchandrastatic int xlr_i2c_callback(device_t dev, int index, caddr_t data); 102216390Sjchandrastatic int xlr_i2c_repeated_start(device_t dev, u_char slave, int timeout); 103216390Sjchandrastatic int xlr_i2c_transfer(device_t bus, struct iic_msg *msgs, uint32_t nmsgs); 104198160Srrs 105198625Srrsstruct xlr_i2c_softc { 106216390Sjchandra device_t dev; /* Self */ 107198625Srrs struct resource *mem_res; /* Memory resource */ 108198625Srrs volatile int flags; 109198625Srrs int sc_started; 110216390Sjchandra uint8_t i2cdev_addr; 111216390Sjchandra xlr_reg_t *iobase_i2c_regs; 112198625Srrs device_t iicbus; 113216390Sjchandra struct mtx sc_mtx; 114198160Srrs}; 115198160Srrs 116216390Sjchandrastatic void 117216390Sjchandraset_i2c_base(device_t dev) 118216390Sjchandra{ 119216390Sjchandra struct xlr_i2c_softc *sc; 120198160Srrs 121216390Sjchandra sc = device_get_softc(dev); 122216390Sjchandra if (device_get_unit(dev) == 0) 123216390Sjchandra sc->iobase_i2c_regs = xlr_io_mmio(XLR_IO_I2C_0_OFFSET); 124198625Srrs else 125216390Sjchandra sc->iobase_i2c_regs = xlr_io_mmio(XLR_IO_I2C_1_OFFSET); 126198160Srrs} 127198160Srrs 128198625Srrsstatic void 129216390Sjchandraxlr_i2c_dev_write(device_t dev, int reg, int value) 130198160Srrs{ 131216390Sjchandra struct xlr_i2c_softc *sc; 132216390Sjchandra 133216390Sjchandra sc = device_get_softc(dev); 134216390Sjchandra xlr_write_reg(sc->iobase_i2c_regs, reg, value); 135198625Srrs return; 136198160Srrs} 137198160Srrs 138198160Srrs 139198625Srrsstatic int 140216390Sjchandraxlr_i2c_dev_read(device_t dev, int reg) 141198160Srrs{ 142198625Srrs uint32_t val; 143216390Sjchandra struct xlr_i2c_softc *sc; 144198625Srrs 145216390Sjchandra sc = device_get_softc(dev); 146216390Sjchandra val = xlr_read_reg(sc->iobase_i2c_regs, reg); 147198625Srrs return ((int)val); 148198160Srrs} 149198160Srrs 150198160Srrs 151198160Srrsstatic int 152198160Srrsxlr_i2c_probe(device_t dev) 153198160Srrs{ 154216390Sjchandra device_set_desc(dev, "XLR/XLS I2C bus controller"); 155198160Srrs 156198160Srrs return (0); 157198160Srrs} 158198160Srrs 159198160Srrs 160198160Srrs/* 161198160Srrs * We add all the devices which we know about. 162198160Srrs * The generic attach routine will attach them if they are alive. 163198160Srrs */ 164198160Srrsstatic int 165198160Srrsxlr_i2c_attach(device_t dev) 166198160Srrs{ 167216390Sjchandra int rid; 168198625Srrs struct xlr_i2c_softc *sc; 169216390Sjchandra device_t tmpd; 170198160Srrs 171216390Sjchandra if(device_get_unit(dev)!=ARIZONA_I2C_BUS) { 172216390Sjchandra device_printf(dev, "unused iicbus instance\n"); 173216390Sjchandra return 0; 174216390Sjchandra } 175216390Sjchandra 176198625Srrs sc = device_get_softc(dev); 177216390Sjchandra set_i2c_base(dev); 178216390Sjchandra 179216390Sjchandra mtx_init(&sc->sc_mtx, "xlr_i2c", "xlr_i2c", MTX_DEF); 180216390Sjchandra 181216390Sjchandra sc->mem_res = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &rid, RF_ACTIVE); 182198625Srrs if (sc->mem_res == NULL) { 183198625Srrs printf("not able to allocate the bus resource\n"); 184198625Srrs } 185216390Sjchandra if ((sc->iicbus = device_add_child(dev, "iicbus", -1)) == NULL) { 186198625Srrs printf("could not allocate iicbus instance\n"); 187216390Sjchandra return -1; 188216390Sjchandra } 189216390Sjchandra if(xlr_board_info.xlr_i2c_device[I2C_RTC].enabled == 1) { 190216390Sjchandra tmpd = device_add_child(sc->iicbus, "ds1374u", 0); 191216390Sjchandra device_set_ivars(tmpd, &xlr_board_info.xlr_i2c_device[I2C_RTC]); 192216390Sjchandra } 193216390Sjchandra if(xlr_board_info.xlr_i2c_device[I2C_THERMAL].enabled == 1) { 194216390Sjchandra tmpd = device_add_child(sc->iicbus, "max6657", 0); 195216390Sjchandra device_set_ivars(tmpd, &xlr_board_info.xlr_i2c_device[I2C_THERMAL]); 196216390Sjchandra } 197216390Sjchandra if(xlr_board_info.xlr_i2c_device[I2C_EEPROM].enabled == 1) { 198216390Sjchandra tmpd = device_add_child(sc->iicbus, "at24co2n", 0); 199216390Sjchandra device_set_ivars(tmpd, &xlr_board_info.xlr_i2c_device[I2C_EEPROM]); 200216390Sjchandra } 201198160Srrs 202198160Srrs bus_generic_attach(dev); 203198160Srrs 204198625Srrs return (0); 205198160Srrs} 206198625Srrs 207198160Srrsstatic int 208198160Srrsxlr_i2c_detach(device_t dev) 209198160Srrs{ 210198160Srrs bus_generic_detach(dev); 211198625Srrs 212198160Srrs return (0); 213198160Srrs} 214198160Srrs 215198625Srrsstatic int 216198625Srrsxlr_i2c_start(device_t dev, u_char slave, int timeout) 217198160Srrs{ 218198625Srrs int error = 0; 219198625Srrs struct xlr_i2c_softc *sc; 220198160Srrs 221198625Srrs sc = device_get_softc(dev); 222216390Sjchandra mtx_lock(&sc->sc_mtx); 223198625Srrs sc->sc_started = 1; 224216390Sjchandra sc->i2cdev_addr = (slave >> 1); 225198625Srrs return error; 226198160Srrs 227198160Srrs} 228198160Srrs 229198625Srrsstatic int 230198625Srrsxlr_i2c_stop(device_t dev) 231198160Srrs{ 232198625Srrs int error = 0; 233216390Sjchandra struct xlr_i2c_softc *sc; 234198160Srrs 235216390Sjchandra sc = device_get_softc(dev); 236216390Sjchandra mtx_unlock(&sc->sc_mtx); 237198625Srrs return error; 238198160Srrs 239198160Srrs} 240198160Srrs 241198625Srrsstatic int 242198625Srrsxlr_i2c_read(device_t dev, char *buf, int len, int *read, int last, 243198625Srrs int delay) 244198160Srrs{ 245216390Sjchandra volatile uint32_t i2c_status = 0; 246216390Sjchandra int pos=0; 247216390Sjchandra int timeout = 0; 248216390Sjchandra 249216390Sjchandra xlr_i2c_dev_write(dev, XLR_I2C_CFG, XLR_I2C_CFG_NOADDR); 250216390Sjchandra xlr_i2c_dev_write(dev, XLR_I2C_BYTECNT, len); 251198160Srrs 252216390Sjchandraretry: 253216390Sjchandra xlr_i2c_dev_write(dev, XLR_I2C_STARTXFR, XLR_I2C_STARTXFR_RD); 254198160Srrs 255216390Sjchandra timeout = 0; 256216390Sjchandra while(1) { 257216390Sjchandra if(timeout++ > MAXTIME) 258216390Sjchandra return -1; 259216390Sjchandra 260216390Sjchandra i2c_status = xlr_i2c_dev_read(dev, XLR_I2C_STATUS); 261216390Sjchandra if (i2c_status & XLR_I2C_RXRDY) 262216390Sjchandra buf[pos++] = (uint8_t) xlr_i2c_dev_read(dev, XLR_I2C_DATAIN); 263216390Sjchandra 264216390Sjchandra /* ACKERR -- bail */ 265216390Sjchandra if (i2c_status & XLR_I2C_ACK_ERR) 266216390Sjchandra return -1; /* ACK_ERROR */ 267216390Sjchandra 268216390Sjchandra /* LOST ARB or STARTERR -- repeat */ 269216390Sjchandra if (i2c_status & XLR_I2C_ARB_STARTERR) 270216390Sjchandra goto retry; 271216390Sjchandra 272216390Sjchandra /* Wait for busy bit to go away */ 273216390Sjchandra if (i2c_status & XLR_I2C_BUS_BUSY) 274216390Sjchandra continue; 275216390Sjchandra 276216390Sjchandra if (pos == len) 277216390Sjchandra break; 278216390Sjchandra } 279216390Sjchandra *read = pos; 280216390Sjchandra return 0; 281216390Sjchandra 282198160Srrs} 283198160Srrs 284198625Srrsstatic int 285216390Sjchandraxlr_i2c_write(device_t dev, const char *buf, int len, int *sent, int timeout /* us */ ) 286198160Srrs{ 287216390Sjchandra volatile uint32_t i2c_status = 0x00; 288216390Sjchandra uint8_t devaddr, addr; 289216390Sjchandra struct xlr_i2c_softc *sc; 290216390Sjchandra int pos; 291198160Srrs 292216390Sjchandra sc = device_get_softc(dev); 293198160Srrs 294216390Sjchandra /* the first byte of write is addr (of register in device) */ 295216390Sjchandra addr = buf[0]; 296216390Sjchandra devaddr = sc->i2cdev_addr; 297216390Sjchandra xlr_i2c_dev_write(dev, XLR_I2C_ADDR, addr); 298216390Sjchandra xlr_i2c_dev_write(dev, XLR_I2C_DEVADDR, devaddr); 299216390Sjchandra xlr_i2c_dev_write(dev, XLR_I2C_CFG, XLR_I2C_CFG_ADDR); 300216390Sjchandra xlr_i2c_dev_write(dev, XLR_I2C_BYTECNT, len - 1); 301216390Sjchandra 302216390Sjchandraretry: 303216390Sjchandra pos = 1; 304216390Sjchandra if (len == 1) /* there is no data only address */ 305216390Sjchandra xlr_i2c_dev_write(dev, XLR_I2C_STARTXFR, XLR_I2C_STARTXFR_ND); 306216390Sjchandra else { 307216390Sjchandra xlr_i2c_dev_write(dev, XLR_I2C_STARTXFR, XLR_I2C_STARTXFR_WR); 308216390Sjchandra xlr_i2c_dev_write(dev, XLR_I2C_DATAOUT, buf[pos]); 309198625Srrs } 310198160Srrs 311216390Sjchandra while (1) { 312216390Sjchandra i2c_status = xlr_i2c_dev_read(dev, XLR_I2C_STATUS); 313216390Sjchandra 314216390Sjchandra /* sdo empty send next byte */ 315216390Sjchandra if (i2c_status & XLR_I2C_SDOEMPTY) { 316216390Sjchandra pos++; 317216390Sjchandra xlr_i2c_dev_write(dev, XLR_I2C_DATAOUT, buf[pos]); 318216390Sjchandra } 319198160Srrs 320216390Sjchandra /* LOST ARB or STARTERR -- repeat */ 321216390Sjchandra if (i2c_status & XLR_I2C_ARB_STARTERR) 322216390Sjchandra goto retry; 323198160Srrs 324216390Sjchandra /* ACKERR -- bail */ 325216390Sjchandra if (i2c_status & XLR_I2C_ACK_ERR) { 326216390Sjchandra printf("ACK ERR : exiting\n "); 327216390Sjchandra return -1; 328216390Sjchandra } 329216390Sjchandra 330216390Sjchandra /* busy try again */ 331216390Sjchandra if (i2c_status & XLR_I2C_BUS_BUSY) 332216390Sjchandra continue; 333198625Srrs 334216390Sjchandra if (pos >= len) 335241844Seadler break; 336216390Sjchandra } 337216390Sjchandra *sent = len - 1; 338216390Sjchandra return 0; 339198160Srrs} 340198160Srrs 341216390Sjchandra 342216390Sjchandra 343198160Srrsstatic int 344216390Sjchandraxlr_i2c_callback(device_t dev, int index, caddr_t data) 345198160Srrs{ 346198625Srrs return 0; 347198160Srrs} 348198160Srrs 349198160Srrsstatic int 350198160Srrsxlr_i2c_repeated_start(device_t dev, u_char slave, int timeout) 351198160Srrs{ 352198625Srrs return 0; 353198160Srrs} 354198160Srrs 355216390Sjchandra/* 356216390Sjchandra * I2C bus transfer for RMI boards and devices. 357216390Sjchandra * Generic version of iicbus_transfer that calls the appropriate 358216390Sjchandra * routines to accomplish this. See note above about acceptable 359216390Sjchandra * buffer addresses. 360216390Sjchandra */ 361216390Sjchandraint 362216390Sjchandraxlr_i2c_transfer(device_t bus, struct iic_msg *msgs, uint32_t nmsgs) 363216390Sjchandra{ 364216390Sjchandra int i, error, lenread, lenwrote; 365216390Sjchandra u_char addr; 366216390Sjchandra 367216390Sjchandra addr = msgs[0].slave | LSB; 368216390Sjchandra error = xlr_i2c_start(bus, addr, 0); 369216390Sjchandra for (i = 0, error = 0; i < nmsgs && error == 0; i++) { 370216390Sjchandra if (msgs[i].flags & IIC_M_RD) { 371216390Sjchandra error = xlr_i2c_read((bus), msgs[i].buf, msgs[i].len, &lenread, IIC_LAST_READ, 0); 372216390Sjchandra } 373216390Sjchandra else { 374216390Sjchandra error = xlr_i2c_write((bus), msgs[i].buf, msgs[i].len, &lenwrote, 0); 375216390Sjchandra } 376216390Sjchandra } 377216390Sjchandra error = xlr_i2c_stop(bus); 378216390Sjchandra return (error); 379216390Sjchandra} 380198160Srrs 381216390Sjchandra 382198160Srrsstatic device_method_t xlr_i2c_methods[] = { 383198625Srrs /* device interface */ 384198625Srrs DEVMETHOD(device_probe, xlr_i2c_probe), 385198625Srrs DEVMETHOD(device_attach, xlr_i2c_attach), 386198625Srrs DEVMETHOD(device_detach, xlr_i2c_detach), 387198160Srrs 388198625Srrs /* iicbus interface */ 389198625Srrs DEVMETHOD(iicbus_callback, xlr_i2c_callback), 390198625Srrs DEVMETHOD(iicbus_repeated_start, xlr_i2c_repeated_start), 391198625Srrs DEVMETHOD(iicbus_start, xlr_i2c_start), 392198625Srrs DEVMETHOD(iicbus_stop, xlr_i2c_stop), 393198625Srrs DEVMETHOD(iicbus_write, xlr_i2c_write), 394198625Srrs DEVMETHOD(iicbus_read, xlr_i2c_read), 395216390Sjchandra DEVMETHOD(iicbus_transfer, xlr_i2c_transfer), 396198625Srrs {0, 0} 397198160Srrs}; 398198160Srrs 399198160Srrsstatic driver_t xlr_i2c_driver = { 400198625Srrs "xlr_i2c", 401198625Srrs xlr_i2c_methods, 402198625Srrs sizeof(struct xlr_i2c_softc), 403198160Srrs}; 404198160Srrs 405198160SrrsDRIVER_MODULE(xlr_i2c, iodi, xlr_i2c_driver, xlr_i2c_devclass, 0, 0); 406216390SjchandraDRIVER_MODULE(iicbus, xlr_i2c, iicbus_driver, iicbus_devclass, 0, 0); 407