Add an iicbus_reset() method to bcm2835_bsc. While it is generally not
used for kernel devices it is used by i2c(8). This fix the 'error: Device not configured' when i2c(8) tries to reset the controller, as an example: # i2c -r Resetting I2C controller on /dev/iic0: error: Device not configured For now use conservative settings for default i2c speeds. MFC after: 1 week
This commit is contained in:
parent
f53389946d
commit
e50c624155
Notes:
svn2git
2020-12-20 02:59:44 +00:00
svn path=/head/; revision=273610
@ -210,6 +210,8 @@ static void
|
||||
bcm_bsc_reset(struct bcm_bsc_softc *sc)
|
||||
{
|
||||
|
||||
/* Enable the BSC Controller, disable interrupts. */
|
||||
BCM_BSC_WRITE(sc, BCM_BSC_CTRL, BCM_BSC_CTRL_I2CEN);
|
||||
/* Clear pending interrupts. */
|
||||
BCM_BSC_WRITE(sc, BCM_BSC_STATUS, BCM_BSC_STATUS_CLKT |
|
||||
BCM_BSC_STATUS_ERR | BCM_BSC_STATUS_DONE);
|
||||
@ -302,7 +304,6 @@ bcm_bsc_attach(device_t dev)
|
||||
|
||||
/* Enable the BSC controller. Flush the FIFO. */
|
||||
BCM_BSC_LOCK(sc);
|
||||
BCM_BSC_WRITE(sc, BCM_BSC_CTRL, BCM_BSC_CTRL_I2CEN);
|
||||
bcm_bsc_reset(sc);
|
||||
BCM_BSC_UNLOCK(sc);
|
||||
|
||||
@ -351,9 +352,8 @@ bcm_bsc_intr(void *arg)
|
||||
/* Check for errors. */
|
||||
if (status & (BCM_BSC_STATUS_CLKT | BCM_BSC_STATUS_ERR)) {
|
||||
/* Disable interrupts. */
|
||||
BCM_BSC_WRITE(sc, BCM_BSC_CTRL, BCM_BSC_CTRL_I2CEN);
|
||||
sc->sc_flags |= BCM_I2C_ERROR;
|
||||
bcm_bsc_reset(sc);
|
||||
sc->sc_flags |= BCM_I2C_ERROR;
|
||||
wakeup(sc->sc_dev);
|
||||
BCM_BSC_UNLOCK(sc);
|
||||
return;
|
||||
@ -375,7 +375,6 @@ bcm_bsc_intr(void *arg)
|
||||
|
||||
if (status & BCM_BSC_STATUS_DONE) {
|
||||
/* Disable interrupts. */
|
||||
BCM_BSC_WRITE(sc, BCM_BSC_CTRL, BCM_BSC_CTRL_I2CEN);
|
||||
bcm_bsc_reset(sc);
|
||||
wakeup(sc->sc_dev);
|
||||
}
|
||||
@ -459,6 +458,38 @@ bcm_bsc_transfer(device_t dev, struct iic_msg *msgs, uint32_t nmsgs)
|
||||
return (err);
|
||||
}
|
||||
|
||||
static int
|
||||
bcm_bsc_iicbus_reset(device_t dev, u_char speed, u_char addr, u_char *oldaddr)
|
||||
{
|
||||
struct bcm_bsc_softc *sc;
|
||||
uint32_t freq;
|
||||
|
||||
sc = device_get_softc(dev);
|
||||
BCM_BSC_LOCK(sc);
|
||||
bcm_bsc_reset(sc);
|
||||
freq = 0;
|
||||
switch (speed) {
|
||||
case IIC_SLOW:
|
||||
freq = BCM_BSC_SLOW;
|
||||
break;
|
||||
case IIC_FAST:
|
||||
freq = BCM_BSC_FAST;
|
||||
break;
|
||||
case IIC_FASTEST:
|
||||
freq = BCM_BSC_FASTEST;
|
||||
break;
|
||||
case IIC_UNKNOWN:
|
||||
default:
|
||||
/* Reuse last frequency. */
|
||||
break;
|
||||
}
|
||||
if (freq != 0)
|
||||
BCM_BSC_WRITE(sc, BCM_BSC_CLOCK, BCM_BSC_CORE_CLK / freq);
|
||||
BCM_BSC_UNLOCK(sc);
|
||||
|
||||
return (IIC_ENOADDR);
|
||||
}
|
||||
|
||||
static phandle_t
|
||||
bcm_bsc_get_node(device_t bus, device_t dev)
|
||||
{
|
||||
@ -474,6 +505,7 @@ static device_method_t bcm_bsc_methods[] = {
|
||||
DEVMETHOD(device_detach, bcm_bsc_detach),
|
||||
|
||||
/* iicbus interface */
|
||||
DEVMETHOD(iicbus_reset, bcm_bsc_iicbus_reset),
|
||||
DEVMETHOD(iicbus_callback, iicbus_null_callback),
|
||||
DEVMETHOD(iicbus_transfer, bcm_bsc_transfer),
|
||||
|
||||
|
@ -56,6 +56,10 @@ struct bcm_bsc_softc {
|
||||
#define BCM_I2C_READ 0x02
|
||||
#define BCM_I2C_ERROR 0x04
|
||||
|
||||
#define BCM_BSC_SLOW 10000 /* 10 kHz. */
|
||||
#define BCM_BSC_FAST 50000 /* 50 kHz. */
|
||||
#define BCM_BSC_FASTEST 100000 /* 100 kHz. */
|
||||
|
||||
#define BCM_BSC_WRITE(_sc, _off, _val) \
|
||||
bus_space_write_4(_sc->sc_bst, _sc->sc_bsh, _off, _val)
|
||||
#define BCM_BSC_READ(_sc, _off) \
|
||||
|
Loading…
Reference in New Issue
Block a user