summaryrefslogtreecommitdiffstats
path: root/sys/arm
diff options
context:
space:
mode:
authorloos <loos@FreeBSD.org>2015-01-09 02:30:30 +0000
committerloos <loos@FreeBSD.org>2015-01-09 02:30:30 +0000
commit7e00152384da1c3e775cf3cc30d49a8fce6bf2d0 (patch)
tree6b9ddfde1b30c5432846ba295af67385291f5d82 /sys/arm
parent2b55fce49f93314345fff2d2bf9af96c8445a8d8 (diff)
downloadFreeBSD-src-7e00152384da1c3e775cf3cc30d49a8fce6bf2d0.zip
FreeBSD-src-7e00152384da1c3e775cf3cc30d49a8fce6bf2d0.tar.gz
MFC r273610:
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: # i2c -r Resetting I2C controller on /dev/iic0: error: Device not configured For now use conservative settings for default i2c speeds.
Diffstat (limited to 'sys/arm')
-rw-r--r--sys/arm/broadcom/bcm2835/bcm2835_bsc.c40
-rw-r--r--sys/arm/broadcom/bcm2835/bcm2835_bscvar.h4
2 files changed, 40 insertions, 4 deletions
diff --git a/sys/arm/broadcom/bcm2835/bcm2835_bsc.c b/sys/arm/broadcom/bcm2835/bcm2835_bsc.c
index f8e9801..58fa09e 100644
--- a/sys/arm/broadcom/bcm2835/bcm2835_bsc.c
+++ b/sys/arm/broadcom/bcm2835/bcm2835_bsc.c
@@ -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),
diff --git a/sys/arm/broadcom/bcm2835/bcm2835_bscvar.h b/sys/arm/broadcom/bcm2835/bcm2835_bscvar.h
index 3fef35b..9a902d47 100644
--- a/sys/arm/broadcom/bcm2835/bcm2835_bscvar.h
+++ b/sys/arm/broadcom/bcm2835/bcm2835_bscvar.h
@@ -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) \
OpenPOWER on IntegriCloud