FreeBSD Bugzilla – Attachment 154646 Details for
Bug 198783
I2C driver for AM335X enhancement
Home
|
New
|
Browse
|
Search
|
[?]
|
Reports
|
Help
|
New Account
|
Log In
Remember
[x]
|
Forgot Password
Login:
[x]
[patch]
patch i2c am335X
patch_i2c_am335X.diff (text/plain), 11.00 KB, created by
Emmanuel Vadot
on 2015-03-22 04:43:33 UTC
(
hide
)
Description:
patch i2c am335X
Filename:
MIME Type:
Creator:
Emmanuel Vadot
Created:
2015-03-22 04:43:33 UTC
Size:
11.00 KB
patch
obsolete
>Index: sys/arm/ti/ti_i2c.c >=================================================================== >--- sys/arm/ti/ti_i2c.c (revision 280337) >+++ sys/arm/ti/ti_i2c.c (working copy) >@@ -1,6 +1,7 @@ > /*- > * Copyright (c) 2011 Ben Gray <ben.r.gray@gmail.com>. > * Copyright (c) 2014 Luiz Otavio O Souza <loos@freebsd.org>. >+ * Copyright (c) 2015 Emmanuel Vadot <manu@megadrive.org>. > * All rights reserved. > * > * Redistribution and use in source and binary forms, with or without >@@ -74,6 +75,8 @@ > > #include "iicbus_if.h" > >+#define BUFSIZE 1024 >+ > /** > * I2C device driver context, a pointer to this is stored in the device > * driver structure. >@@ -91,11 +94,14 @@ > struct mtx sc_mtx; > > struct iic_msg* sc_buffer; >+ uint8_t sc_buffer_buf[bufsize]; > int sc_bus_inuse; > int sc_buffer_pos; >+ uint16_t sc_buffer_flags; > int sc_error; > int sc_fifo_trsh; > int sc_timeout; >+ uint8_t sc_slave_addr; > > uint16_t sc_con_reg; > uint16_t sc_rev; >@@ -158,6 +164,9 @@ > #define ti_i2c_dbg(_sc, fmt, args...) > #endif > >+static int ti_i2c_reset(struct ti_i2c_softc *sc, u_char speed); >+ >+ > /** > * ti_i2c_read_2 - reads a 16-bit value from one of the I2C registers > * @sc: I2C device context >@@ -200,38 +209,14 @@ > ti_i2c_transfer_intr(struct ti_i2c_softc* sc, uint16_t status) > { > int amount, done, i; >+ uint16_t fifo_size; > > done = 0; > amount = 0; >- /* Check for the error conditions. */ >- if (status & I2C_STAT_NACK) { >- /* No ACK from slave. */ >- ti_i2c_dbg(sc, "NACK\n"); >- ti_i2c_write_2(sc, I2C_REG_STATUS, I2C_STAT_NACK); >- sc->sc_error = ENXIO; >- } else if (status & I2C_STAT_AL) { >- /* Arbitration lost. */ >- ti_i2c_dbg(sc, "Arbitration lost\n"); >- ti_i2c_write_2(sc, I2C_REG_STATUS, I2C_STAT_AL); >- sc->sc_error = ENXIO; >- } > >- /* Check if we have finished. */ >- if (status & I2C_STAT_ARDY) { >- /* Register access ready - transaction complete basically. */ >- ti_i2c_dbg(sc, "ARDY transaction complete\n"); >- if (sc->sc_error != 0 && sc->sc_buffer->flags & IIC_M_NOSTOP) { >- ti_i2c_write_2(sc, I2C_REG_CON, >- sc->sc_con_reg | I2C_CON_STP); >- } >- ti_i2c_write_2(sc, I2C_REG_STATUS, >- I2C_STAT_ARDY | I2C_STAT_RDR | I2C_STAT_RRDY | >- I2C_STAT_XDR | I2C_STAT_XRDY); >- return (1); >- } >- > if (sc->sc_buffer->flags & IIC_M_RD) { > /* Read some data. */ >+ > if (status & I2C_STAT_RDR) { > /* > * Receive draining interrupt - last data received. >@@ -238,26 +223,23 @@ > * The set FIFO threshold wont be reached to trigger > * RRDY. > */ >- ti_i2c_dbg(sc, "Receive draining interrupt\n"); > >- /* >- * Drain the FIFO. Read the pending data in the FIFO. >- */ >- amount = sc->sc_buffer->len - sc->sc_buffer_pos; >+ fifo_size = (ti_i2c_read_2(sc, I2C_REG_BUFSTAT) & I2C_BUFSTAT_RXSTAT_MASK) >> I2C_BUFSTAT_RXSTAT_SHIFT; >+ amount = min(fifo_size, sc->sc_buffer->len - sc->sc_buffer_pos); >+ ti_i2c_dbg(sc, "Receive draining interrupt, draining %d bytes\n", amount); > } else if (status & I2C_STAT_RRDY) { > /* > * Receive data ready interrupt - FIFO has reached the > * set threshold. > */ >- ti_i2c_dbg(sc, "Receive data ready interrupt\n"); >- > amount = min(sc->sc_fifo_trsh, > sc->sc_buffer->len - sc->sc_buffer_pos); >+ ti_i2c_dbg(sc, "Receive data ready interrupt, reading %d bytes\n", amount); > } > > /* Read the bytes from the fifo. */ > for (i = 0; i < amount; i++) >- sc->sc_buffer->buf[sc->sc_buffer_pos++] = >+ sc->sc_buffer->buf[sc->sc_buffer_pos++] = > (uint8_t)(ti_i2c_read_2(sc, I2C_REG_DATA) & 0xff); > > if (status & I2C_STAT_RDR) >@@ -265,21 +247,23 @@ > if (status & I2C_STAT_RRDY) > ti_i2c_write_2(sc, I2C_REG_STATUS, I2C_STAT_RRDY); > >+ ti_i2c_dbg(sc, "%d bytes to read\n", ti_i2c_read_2(sc, I2C_REG_CNT)); >+ > } else { > /* Write some data. */ >+ > if (status & I2C_STAT_XDR) { > /* > * Transmit draining interrupt - FIFO level is below > * the set threshold and the amount of data still to > * be transferred wont reach the set FIFO threshold. >- */ >- ti_i2c_dbg(sc, "Transmit draining interrupt\n"); >- >- /* > * Drain the TX data. Write the pending data in the > * FIFO. > */ >- amount = sc->sc_buffer->len - sc->sc_buffer_pos; >+ >+ fifo_size = (ti_i2c_read_2(sc, I2C_REG_BUFSTAT) & I2C_BUFSTAT_TXSTAT_MASK) >> I2C_BUFSTAT_TXSTAT_SHIFT; >+ amount = min(fifo_size, sc->sc_buffer->len - sc->sc_buffer_pos); >+ ti_i2c_dbg(sc, "Transmit draining interrupt, draining %d bytes\n", amount); > } else if (status & I2C_STAT_XRDY) { > /* > * Transmit data ready interrupt - the FIFO level >@@ -322,7 +306,7 @@ > { > int done; > struct ti_i2c_softc *sc; >- uint16_t events, status; >+ uint16_t status; > > sc = (struct ti_i2c_softc *)arg; > >@@ -334,22 +318,46 @@ > return; > } > >- /* Save enabled interrupts. */ >- events = ti_i2c_read_2(sc, I2C_REG_IRQENABLE_SET); >+ ti_i2c_dbg(sc, "Interrupt status, %x\n", status); > >- /* We only care about enabled interrupts. */ >- status &= events; >- > done = 0; > >- if (sc->sc_buffer != NULL) >- done = ti_i2c_transfer_intr(sc, status); >- else { >- ti_i2c_dbg(sc, "Transfer interrupt without buffer\n"); >- sc->sc_error = EINVAL; >+ /* Check for the error conditions. */ >+ if (status & I2C_STAT_NACK) { >+ /* No ACK from slave. */ >+ ti_i2c_dbg(sc, "NACK\n"); >+ ti_i2c_write_2(sc, I2C_REG_STATUS, I2C_STAT_NACK); >+ sc->sc_error = ENXIO; >+ goto out; >+ } else if (status & I2C_STAT_AL) { >+ /* Arbitration lost. */ >+ ti_i2c_dbg(sc, "Arbitration lost\n"); >+ ti_i2c_write_2(sc, I2C_REG_STATUS, I2C_STAT_AL); >+ sc->sc_error = ENXIO; >+ goto out; >+ } else if (status & I2C_STAT_ARDY) { >+ /* Register access ready - transaction complete basically. */ >+ ti_i2c_dbg(sc, "ARDY transaction complete\n"); >+ if (sc->sc_error != 0 && ! sc->sc_buffer->flags & IIC_M_NOSTOP) { >+ ti_i2c_write_2(sc, I2C_REG_CON, >+ sc->sc_con_reg | I2C_CON_STP); >+ } >+ ti_i2c_write_2(sc, I2C_REG_STATUS, >+ I2C_STAT_ARDY | I2C_STAT_RDR | I2C_STAT_RRDY | >+ I2C_STAT_XDR | I2C_STAT_XRDY); > done = 1; >+ goto out; >+ } else if (status & I2C_STAT_RRDY || status & I2C_STAT_XRDY || status & I2C_STAT_RDR || status & I2C_STAT_XDR) { >+ if (sc->sc_buffer != NULL) >+ done = ti_i2c_transfer_intr(sc, status); >+ else { >+ ti_i2c_dbg(sc, "Transfer interrupt without buffer\n"); >+ sc->sc_error = EINVAL; >+ done = 1; >+ } > } > >+ out: > if (done) > /* Wakeup the process that started the transaction. */ > wakeup(sc); >@@ -359,28 +367,21 @@ > > /** > * ti_i2c_transfer - called to perform the transfer >- * @dev: i2c device handle >+ * @sc: I2C device context > * @msgs: the messages to send/receive > * @nmsgs: the number of messages in the msgs array > * > * >- * LOCKING: >- * Internally locked >- * > * RETURNS: > * 0 on function succeeded > * EINVAL if invalid message is passed as an arg > */ > static int >-ti_i2c_transfer(device_t dev, struct iic_msg *msgs, uint32_t nmsgs) >+ti_i2c_transfer(struct ti_i2c_softc *sc, struct iic_msg *msgs, uint32_t nmsgs) > { > int err, i, repstart, timeout; >- struct ti_i2c_softc *sc; > uint16_t reg; > >- sc = device_get_softc(dev); >- TI_I2C_LOCK(sc); >- > /* If the controller is busy wait until it is available. */ > while (sc->sc_bus_inuse == 1) > mtx_sleep(sc, &sc->sc_mtx, 0, "i2cbuswait", 0); >@@ -388,7 +389,7 @@ > /* Now we have control over the I2C controller. */ > sc->sc_bus_inuse = 1; > >- err = 0; >+ err = IIC_NOERR; > repstart = 0; > for (i = 0; i < nmsgs; i++) { > >@@ -436,8 +437,9 @@ > ti_i2c_write_2(sc, I2C_REG_BUF, reg); > > reg = sc->sc_con_reg | I2C_CON_STT; >- if (repstart == 0) >+ if (repstart == 0) { > reg |= I2C_CON_STP; >+ } > if ((sc->sc_buffer->flags & IIC_M_RD) == 0) > reg |= I2C_CON_TRX; > ti_i2c_write_2(sc, I2C_REG_CON, reg); >@@ -469,8 +471,6 @@ > /* Wake up the processes that are waiting for the bus. */ > wakeup(sc); > >- TI_I2C_UNLOCK(sc); >- > return (err); > } > >@@ -524,7 +524,7 @@ > sc->sc_con_reg = 0; > ti_i2c_write_2(sc, I2C_REG_CON, sc->sc_con_reg); > >- /* 2. Issue a softreset to the controller. */ >+ /* 2. Issue a softreset to the controller and enable auto-idle. */ > bus_write_2(sc->sc_mem_res, I2C_REG_SYSC, I2C_REG_SYSC_SRST); > > /* >@@ -675,6 +675,123 @@ > } > > static int >+ti_i2c_read(device_t dev, char *buf, int len, int *read, int last, int delay) >+{ >+ struct ti_i2c_softc *sc; >+ struct iic_msg msg; >+ int err; >+ >+ err = IIC_NOERR; >+ sc = device_get_softc(dev); >+ TI_I2C_LOCK(sc); >+ >+ msg.buf = buf; >+ msg.len = len; >+ msg.flags = IIC_M_RD | sc->sc_buffer_flags; >+ msg.slave = sc->sc_slave_addr; >+ >+ err = ti_i2c_transfer(sc, &msg, 1); >+ >+ *read = sc->sc_buffer_pos; >+ >+ TI_I2C_UNLOCK(sc); >+ >+ if (err) >+ return (err); >+ >+ return (IIC_NOERR); >+} >+ >+static int >+ti_i2c_write(device_t dev, const char *buf, int len, int *sent, int delay) >+{ >+ struct ti_i2c_softc *sc; >+ struct iic_msg msg; >+ int err; >+ >+ if (len > BUFSIZE) >+ return (ENODEV); >+ >+ err = IIC_NOERR; >+ sc = device_get_softc(dev); >+ TI_I2C_LOCK(sc); >+ >+ memcpy(sc->sc_buffer_buf, buf, len); >+ >+ msg.buf = sc->sc_buffer_buf; >+ msg.len = len; >+ msg.flags = sc->sc_buffer_flags; >+ msg.slave = sc->sc_slave_addr; >+ >+ err = ti_i2c_transfer(sc, &msg, 1); >+ >+ *sent = sc->sc_buffer_pos; >+ >+ TI_I2C_UNLOCK(sc); >+ >+ if (err) >+ return (err); >+ >+ return (IIC_NOERR); >+} >+ >+static int >+ti_i2c_start(device_t dev, u_char slave, int timeout) >+{ >+ struct ti_i2c_softc *sc; >+ >+ sc = device_get_softc(dev); >+ TI_I2C_LOCK(sc); >+ >+ /* Configure slave address */ >+ sc->sc_slave_addr = slave; >+ sc->sc_buffer_flags = 0; >+ >+ TI_I2C_UNLOCK(sc); >+ >+ return (IIC_NOERR); >+} >+ >+static int >+ti_i2c_repeated_start(device_t dev, u_char slave, int timeout) >+{ >+ struct ti_i2c_softc *sc; >+ >+ sc = device_get_softc(dev); >+ TI_I2C_LOCK(sc); >+ >+ /* Configure slave address */ >+ sc->sc_slave_addr = slave; >+ sc->sc_buffer_flags = IIC_M_NOSTOP; >+ >+ TI_I2C_UNLOCK(sc); >+ >+ return (IIC_NOERR); >+} >+ >+static int >+ti_i2c_stop(device_t dev) >+{ >+ return (IIC_NOERR); >+} >+ >+static int >+ti_i2c_iicbus_transfer(device_t dev, struct iic_msg *msgs, uint32_t nmsgs) >+{ >+ struct ti_i2c_softc *sc; >+ int err; >+ >+ sc = device_get_softc(dev); >+ TI_I2C_LOCK(sc); >+ err = ti_i2c_transfer(sc, msgs, nmsgs); >+ TI_I2C_UNLOCK(sc); >+ if (err) >+ return (err); >+ >+ return (IIC_ENOADDR); >+} >+ >+static int > ti_i2c_iicbus_reset(device_t dev, u_char speed, u_char addr, u_char *oldaddr) > { > struct ti_i2c_softc *sc; >@@ -790,7 +907,7 @@ > > sc = arg1; > >- /* >+ /* > * MTX_DEF lock can't be held while doing uimove in > * sysctl_handle_int > */ >@@ -882,8 +999,8 @@ > device_printf(dev, "I2C revision %d.%d FIFO size: %d bytes\n", > sc->sc_rev >> 4, sc->sc_rev & 0xf, 8 << fifosz); > >- /* Set the FIFO threshold to 5 for now. */ >- sc->sc_fifo_trsh = 5; >+ /* Set the FIFO threshold to 8 for now. */ >+ sc->sc_fifo_trsh = 8; > > /* Set I2C bus timeout */ > sc->sc_timeout = 5*hz; >@@ -959,7 +1076,12 @@ > /* iicbus interface */ > DEVMETHOD(iicbus_callback, iicbus_null_callback), > DEVMETHOD(iicbus_reset, ti_i2c_iicbus_reset), >- DEVMETHOD(iicbus_transfer, ti_i2c_transfer), >+ DEVMETHOD(iicbus_transfer, ti_i2c_iicbus_transfer), >+ DEVMETHOD(iicbus_start, ti_i2c_start), >+ DEVMETHOD(iicbus_repeated_start, ti_i2c_repeated_start), >+ DEVMETHOD(iicbus_stop, ti_i2c_stop), >+ DEVMETHOD(iicbus_read, ti_i2c_read), >+ DEVMETHOD(iicbus_write, ti_i2c_write), > > DEVMETHOD_END > };
You cannot view the attachment while viewing its details because your browser does not support IFRAMEs.
View the attachment on a separate page
.
View Attachment As Diff
View Attachment As Raw
Actions:
View
|
Diff
Attachments on
bug 198783
: 154646