Source-Changes-HG archive
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]
[src/trunk]: src/sys/dev/i2c - Don't use I2C_F_POLL.
details: https://anonhg.NetBSD.org/src/rev/87d787bec596
branches: trunk
changeset: 847481:87d787bec596
user: thorpej <thorpej%NetBSD.org@localhost>
date: Mon Dec 23 20:38:08 2019 +0000
description:
- Don't use I2C_F_POLL.
- Don't access the i2c from hard interrupt context. Instead, schedule a
soft interrupt to do the real work. (No need to mask the interrupt
source, since this device has an edge-sensitive interrupt per the DT
info; will need to be revisited if there's ever a flavor that uses a
level-sensitive interrupt).
- Split out the i2c bus acquire / release from the register read / write
functions, allowing us to batch several i2c transactions under a single
acquire / release cycle.
diffstat:
sys/dev/i2c/tcakp.c | 104 ++++++++++++++++++++++++++++++++++++++++++---------
1 files changed, 85 insertions(+), 19 deletions(-)
diffs (230 lines):
diff -r fd95ee10d58f -r 87d787bec596 sys/dev/i2c/tcakp.c
--- a/sys/dev/i2c/tcakp.c Mon Dec 23 20:17:33 2019 +0000
+++ b/sys/dev/i2c/tcakp.c Mon Dec 23 20:38:08 2019 +0000
@@ -1,4 +1,4 @@
-/* $NetBSD: tcakp.c,v 1.10 2018/10/17 16:56:40 jmcneill Exp $ */
+/* $NetBSD: tcakp.c,v 1.11 2019/12/23 20:38:08 thorpej Exp $ */
/*-
* Copyright (c) 2017 Jared McNeill <jmcneill%invisible.ca@localhost>
@@ -29,7 +29,7 @@
#include "opt_fdt.h"
#include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: tcakp.c,v 1.10 2018/10/17 16:56:40 jmcneill Exp $");
+__KERNEL_RCSID(0, "$NetBSD: tcakp.c,v 1.11 2019/12/23 20:38:08 thorpej Exp $");
#include <sys/param.h>
#include <sys/systm.h>
@@ -99,6 +99,7 @@
uint16_t sc_keymap[128];
void *sc_ih;
+ void *sc_sih;
int sc_enabled;
device_t sc_wskbddev;
@@ -107,6 +108,9 @@
static int tcakp_match(device_t, cfdata_t, void *);
static void tcakp_attach(device_t, device_t, void *);
+static int tcakp_i2c_lock(struct tcakp_softc *);
+static void tcakp_i2c_unlock(struct tcakp_softc *);
+
static int tcakp_read(struct tcakp_softc *, uint8_t, uint8_t *);
static int tcakp_write(struct tcakp_softc *, uint8_t, uint8_t);
@@ -137,8 +141,28 @@
tcakp_intr(void *priv)
{
struct tcakp_softc * const sc = priv;
+
+ /*
+ * Schedule our soft interrupt handler. We can't access the i2c
+ * from hard interrupt context, so just go ahead and claim the
+ * interrupt.
+ *
+ * XXX If we ever end up with an instance that uses
+ * level-sensitive interrupts, we will need to mask
+ * the interrupt source.
+ */
+ softint_schedule(sc->sc_sih);
+ return 1;
+}
+
+static void
+tcakp_softintr(void *priv)
+{
+ struct tcakp_softc * const sc = priv;
uint8_t stat, ev;
- int ret = 0;
+
+ if (tcakp_i2c_lock(sc) != 0)
+ return;
tcakp_read(sc, TCA_INT_STAT, &stat);
if (stat & INT_STAT_K_INT) {
@@ -147,6 +171,8 @@
const bool pressed = __SHIFTOUT(ev, TCA_EVENT_STATE);
const uint8_t code = __SHIFTOUT(ev, TCA_EVENT_CODE);
+ tcakp_i2c_unlock(sc);
+
/* Translate raw code to keymap index */
const u_int index = tcakp_decode(sc, code);
@@ -157,13 +183,13 @@
if (sc->sc_wskbddev)
wskbd_input(sc->sc_wskbddev, type, key);
+ if (tcakp_i2c_lock(sc) != 0)
+ return;
tcakp_read(sc, TCA_EVENT('A'), &ev);
}
- ret = 1;
}
tcakp_write(sc, TCA_INT_STAT, stat);
-
- return ret;
+ tcakp_i2c_unlock(sc);
}
static int
@@ -171,6 +197,7 @@
{
uint32_t mask;
uint8_t val;
+ int error;
if (sc->sc_rows == 0 || sc->sc_cols == 0) {
aprint_error_dev(sc->sc_dev, "not configured\n");
@@ -180,6 +207,10 @@
mask = __BITS(sc->sc_rows - 1, 0);
mask += __BITS(sc->sc_cols - 1, 0) << 8;
+ error = tcakp_i2c_lock(sc);
+ if (error)
+ return error;
+
/* Lock the keyboard */
tcakp_write(sc, TCA_KEY_LCK_EC, KEY_LCK_EC_K_LCK_EN);
/* Select keyboard mode */
@@ -196,6 +227,8 @@
tcakp_read(sc, TCA_INT_STAT, &val);
tcakp_write(sc, TCA_INT_STAT, val);
+ tcakp_i2c_unlock(sc);
+
return 0;
}
@@ -234,6 +267,11 @@
tcakp_enable(void *v, int on)
{
struct tcakp_softc * const sc = v;
+ int error;
+
+ error = tcakp_i2c_lock(sc);
+ if (error)
+ return error;
if (on) {
/* Disable key lock */
@@ -243,6 +281,7 @@
tcakp_write(sc, TCA_KEY_LCK_EC, KEY_LCK_EC_K_LCK_EN);
}
+ tcakp_i2c_unlock(sc);
return 0;
}
@@ -276,6 +315,8 @@
struct tcakp_softc * const sc = v;
uint8_t ev = 0;
+ /* XXX i2c bus acquire */
+
do {
tcakp_read(sc, TCA_EVENT('A'), &ev);
} while (ev == 0);
@@ -287,6 +328,8 @@
*type = pressed ? WSCONS_EVENT_KEY_DOWN :
WSCONS_EVENT_KEY_UP;
*data = sc->sc_keymap[index];
+
+ /* XXX i2c bus release */
}
static void
@@ -345,6 +388,21 @@
#ifdef FDT
sc->sc_ih = fdtbus_intr_establish(sc->sc_phandle, 0, IPL_VM, 0,
tcakp_intr, sc);
+ /*
+ * XXX This is an edge-sensitive interrupt, but we'd like to
+ * be able to check at run-time just to be sure.
+ */
+ if (sc->sc_ih == NULL) {
+ aprint_error_dev(sc->sc_dev, "unable to establish interrupt\n");
+ return;
+ }
+
+ sc->sc_sih = softint_establish(SOFTINT_SERIAL, tcakp_softintr, sc);
+ if (sc->sc_sih == NULL) {
+ aprint_error_dev(sc->sc_dev,
+ "unable to establish soft interupt\n");
+ return;
+ }
tcakp_configure_fdt(sc);
#endif
@@ -362,28 +420,36 @@
}
static int
-tcakp_read(struct tcakp_softc *sc, uint8_t reg, uint8_t *val)
+tcakp_i2c_lock(struct tcakp_softc *sc)
{
int error;
- iic_acquire_bus(sc->sc_i2c, I2C_F_POLL);
- error = iic_exec(sc->sc_i2c, I2C_OP_READ_WITH_STOP, sc->sc_addr,
- ®, 1, val, 1, I2C_F_POLL);
- iic_release_bus(sc->sc_i2c, I2C_F_POLL);
+ error = iic_acquire_bus(sc->sc_i2c, 0);
+ if (error) {
+ aprint_error_dev(sc->sc_dev,
+ "unable to acquire bus lock (%d)\n", error);
+ }
+ return error;
+}
- return error;
+static void
+tcakp_i2c_unlock(struct tcakp_softc *sc)
+{
+ iic_release_bus(sc->sc_i2c, 0);
+}
+
+static int
+tcakp_read(struct tcakp_softc *sc, uint8_t reg, uint8_t *val)
+{
+ return iic_exec(sc->sc_i2c, I2C_OP_READ_WITH_STOP, sc->sc_addr,
+ ®, 1, val, 1, 0);
}
static int
tcakp_write(struct tcakp_softc *sc, uint8_t reg, uint8_t val)
{
uint8_t buf[2] = { reg, val };
- int error;
- iic_acquire_bus(sc->sc_i2c, I2C_F_POLL);
- error = iic_exec(sc->sc_i2c, I2C_OP_WRITE_WITH_STOP, sc->sc_addr,
- NULL, 0, buf, 2, I2C_F_POLL);
- iic_release_bus(sc->sc_i2c, I2C_F_POLL);
-
- return error;
+ return iic_exec(sc->sc_i2c, I2C_OP_WRITE_WITH_STOP,
+ sc->sc_addr, NULL, 0, buf, 2, 0);
}
Home |
Main Index |
Thread Index |
Old Index