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 access the i2c bus in interrupt context. ...
details: https://anonhg.NetBSD.org/src/rev/2d0db1860afc
branches: trunk
changeset: 744910:2d0db1860afc
user: thorpej <thorpej%NetBSD.org@localhost>
date: Sun Feb 16 20:32:29 2020 +0000
description:
Don't access the i2c bus in interrupt context. Instead, mask the
interrupt and process it on a work queue.
diffstat:
sys/dev/i2c/axppmic.c | 194 ++++++++++++++++++++++++++++++++-----------------
1 files changed, 125 insertions(+), 69 deletions(-)
diffs (truncated from 406 to 300 lines):
diff -r 3499b9e12e37 -r 2d0db1860afc sys/dev/i2c/axppmic.c
--- a/sys/dev/i2c/axppmic.c Sun Feb 16 20:29:36 2020 +0000
+++ b/sys/dev/i2c/axppmic.c Sun Feb 16 20:32:29 2020 +0000
@@ -1,4 +1,4 @@
-/* $NetBSD: axppmic.c,v 1.28 2019/12/23 14:34:23 thorpej Exp $ */
+/* $NetBSD: axppmic.c,v 1.29 2020/02/16 20:32:29 thorpej Exp $ */
/*-
* Copyright (c) 2014-2018 Jared McNeill <jmcneill%invisible.ca@localhost>
@@ -27,7 +27,7 @@
*/
#include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: axppmic.c,v 1.28 2019/12/23 14:34:23 thorpej Exp $");
+__KERNEL_RCSID(0, "$NetBSD: axppmic.c,v 1.29 2020/02/16 20:32:29 thorpej Exp $");
#include <sys/param.h>
#include <sys/systm.h>
@@ -36,6 +36,7 @@
#include <sys/conf.h>
#include <sys/bus.h>
#include <sys/kmem.h>
+#include <sys/workqueue.h>
#include <dev/i2c/i2cvar.h>
@@ -366,6 +367,13 @@
i2c_addr_t sc_addr;
int sc_phandle;
+ void *sc_ih;
+ struct workqueue *sc_wq;
+
+ kmutex_t sc_intr_lock;
+ struct work sc_work;
+ bool sc_work_scheduled;
+
const struct axppmic_config *sc_conf;
struct sysmon_pswitch sc_smpsw;
@@ -481,7 +489,6 @@
static int
axppmic_set_voltage(i2c_tag_t tag, i2c_addr_t addr, const struct axppmic_ctrl *c, u_int min, u_int max)
{
- const int flags = 0;
u_int vol, reg_val;
int nstep, error;
uint8_t val;
@@ -512,13 +519,13 @@
if (vol > max)
return EINVAL;
- iic_acquire_bus(tag, flags);
- if ((error = axppmic_read(tag, addr, c->c_voltage_reg, &val, flags)) == 0) {
+ iic_acquire_bus(tag, 0);
+ if ((error = axppmic_read(tag, addr, c->c_voltage_reg, &val, 0)) == 0) {
val &= ~c->c_voltage_mask;
val |= __SHIFTIN(reg_val, c->c_voltage_mask);
- error = axppmic_write(tag, addr, c->c_voltage_reg, val, flags);
+ error = axppmic_write(tag, addr, c->c_voltage_reg, val, 0);
}
- iic_release_bus(tag, flags);
+ iic_release_bus(tag, 0);
return error;
}
@@ -526,16 +533,15 @@
static int
axppmic_get_voltage(i2c_tag_t tag, i2c_addr_t addr, const struct axppmic_ctrl *c, u_int *pvol)
{
- const int flags = 0;
int reg_val, error;
uint8_t val;
if (!c->c_voltage_mask)
return EINVAL;
- iic_acquire_bus(tag, flags);
- error = axppmic_read(tag, addr, c->c_voltage_reg, &val, flags);
- iic_release_bus(tag, flags);
+ iic_acquire_bus(tag, 0);
+ error = axppmic_read(tag, addr, c->c_voltage_reg, &val, 0);
+ iic_release_bus(tag, 0);
if (error)
return error;
@@ -561,11 +567,11 @@
delay(1000000);
- error = iic_acquire_bus(sc->sc_i2c, I2C_F_POLL);
+ error = iic_acquire_bus(sc->sc_i2c, 0);
if (error == 0) {
error = axppmic_write(sc->sc_i2c, sc->sc_addr,
- AXP_POWER_DISABLE_REG, AXP_POWER_DISABLE_CTRL, I2C_F_POLL);
- iic_release_bus(sc->sc_i2c, I2C_F_POLL);
+ AXP_POWER_DISABLE_REG, AXP_POWER_DISABLE_CTRL, 0);
+ iic_release_bus(sc->sc_i2c, 0);
}
if (error) {
device_printf(dev, "WARNING: unable to power off, error %d\n",
@@ -590,7 +596,6 @@
{
struct axppmic_softc *sc = sme->sme_cookie;
const struct axppmic_config *c = sc->sc_conf;
- const int flags = I2C_F_POLL;
uint8_t val, lo, hi;
e->state = ENVSYS_SINVALID;
@@ -601,19 +606,19 @@
switch (e->private) {
case AXP_SENSOR_ACIN_PRESENT:
- if (axppmic_read(sc->sc_i2c, sc->sc_addr, AXP_POWER_SOURCE_REG, &val, flags) == 0) {
+ if (axppmic_read(sc->sc_i2c, sc->sc_addr, AXP_POWER_SOURCE_REG, &val, 0) == 0) {
e->state = ENVSYS_SVALID;
e->value_cur = !!(val & AXP_POWER_SOURCE_ACIN_PRESENT);
}
break;
case AXP_SENSOR_VBUS_PRESENT:
- if (axppmic_read(sc->sc_i2c, sc->sc_addr, AXP_POWER_SOURCE_REG, &val, flags) == 0) {
+ if (axppmic_read(sc->sc_i2c, sc->sc_addr, AXP_POWER_SOURCE_REG, &val, 0) == 0) {
e->state = ENVSYS_SVALID;
e->value_cur = !!(val & AXP_POWER_SOURCE_VBUS_PRESENT);
}
break;
case AXP_SENSOR_BATT_PRESENT:
- if (axppmic_read(sc->sc_i2c, sc->sc_addr, AXP_POWER_MODE_REG, &val, flags) == 0) {
+ if (axppmic_read(sc->sc_i2c, sc->sc_addr, AXP_POWER_MODE_REG, &val, 0) == 0) {
if (val & AXP_POWER_MODE_BATT_VALID) {
e->state = ENVSYS_SVALID;
e->value_cur = !!(val & AXP_POWER_MODE_BATT_PRESENT);
@@ -621,14 +626,14 @@
}
break;
case AXP_SENSOR_BATT_CHARGING:
- if (axppmic_read(sc->sc_i2c, sc->sc_addr, AXP_POWER_MODE_REG, &val, flags) == 0) {
+ if (axppmic_read(sc->sc_i2c, sc->sc_addr, AXP_POWER_MODE_REG, &val, 0) == 0) {
e->state = ENVSYS_SVALID;
e->value_cur = !!(val & AXP_POWER_MODE_BATT_CHARGING);
}
break;
case AXP_SENSOR_BATT_CHARGE_STATE:
if (battery_present &&
- axppmic_read(sc->sc_i2c, sc->sc_addr, AXP_BATT_CAP_REG, &val, flags) == 0 &&
+ axppmic_read(sc->sc_i2c, sc->sc_addr, AXP_BATT_CAP_REG, &val, 0) == 0 &&
(val & AXP_BATT_CAP_VALID) != 0) {
const u_int batt_val = __SHIFTOUT(val, AXP_BATT_CAP_PERCENT);
if (batt_val <= sc->sc_shut_thres) {
@@ -645,7 +650,7 @@
break;
case AXP_SENSOR_BATT_CAPACITY_PERCENT:
if (battery_present &&
- axppmic_read(sc->sc_i2c, sc->sc_addr, AXP_BATT_CAP_REG, &val, flags) == 0 &&
+ axppmic_read(sc->sc_i2c, sc->sc_addr, AXP_BATT_CAP_REG, &val, 0) == 0 &&
(val & AXP_BATT_CAP_VALID) != 0) {
e->state = ENVSYS_SVALID;
e->value_cur = __SHIFTOUT(val, AXP_BATT_CAP_PERCENT);
@@ -653,44 +658,44 @@
break;
case AXP_SENSOR_BATT_VOLTAGE:
if (battery_present &&
- axppmic_read(sc->sc_i2c, sc->sc_addr, AXP_BATSENSE_HI_REG, &hi, flags) == 0 &&
- axppmic_read(sc->sc_i2c, sc->sc_addr, AXP_BATSENSE_LO_REG, &lo, flags) == 0) {
+ axppmic_read(sc->sc_i2c, sc->sc_addr, AXP_BATSENSE_HI_REG, &hi, 0) == 0 &&
+ axppmic_read(sc->sc_i2c, sc->sc_addr, AXP_BATSENSE_LO_REG, &lo, 0) == 0) {
e->state = ENVSYS_SVALID;
e->value_cur = AXP_ADC_RAW(hi, lo) * c->batsense_step;
}
break;
case AXP_SENSOR_BATT_CHARGE_CURRENT:
if (battery_present &&
- axppmic_read(sc->sc_i2c, sc->sc_addr, AXP_POWER_SOURCE_REG, &val, flags) == 0 &&
+ axppmic_read(sc->sc_i2c, sc->sc_addr, AXP_POWER_SOURCE_REG, &val, 0) == 0 &&
(val & AXP_POWER_SOURCE_CHARGE_DIRECTION) != 0 &&
- axppmic_read(sc->sc_i2c, sc->sc_addr, AXP_BATTCHG_HI_REG, &hi, flags) == 0 &&
- axppmic_read(sc->sc_i2c, sc->sc_addr, AXP_BATTCHG_LO_REG, &lo, flags) == 0) {
+ axppmic_read(sc->sc_i2c, sc->sc_addr, AXP_BATTCHG_HI_REG, &hi, 0) == 0 &&
+ axppmic_read(sc->sc_i2c, sc->sc_addr, AXP_BATTCHG_LO_REG, &lo, 0) == 0) {
e->state = ENVSYS_SVALID;
e->value_cur = AXP_ADC_RAW(hi, lo) * c->charge_step;
}
break;
case AXP_SENSOR_BATT_DISCHARGE_CURRENT:
if (battery_present &&
- axppmic_read(sc->sc_i2c, sc->sc_addr, AXP_POWER_SOURCE_REG, &val, flags) == 0 &&
+ axppmic_read(sc->sc_i2c, sc->sc_addr, AXP_POWER_SOURCE_REG, &val, 0) == 0 &&
(val & AXP_POWER_SOURCE_CHARGE_DIRECTION) == 0 &&
- axppmic_read(sc->sc_i2c, sc->sc_addr, AXP_BATTDISCHG_HI_REG, &hi, flags) == 0 &&
- axppmic_read(sc->sc_i2c, sc->sc_addr, AXP_BATTDISCHG_LO_REG, &lo, flags) == 0) {
+ axppmic_read(sc->sc_i2c, sc->sc_addr, AXP_BATTDISCHG_HI_REG, &hi, 0) == 0 &&
+ axppmic_read(sc->sc_i2c, sc->sc_addr, AXP_BATTDISCHG_LO_REG, &lo, 0) == 0) {
e->state = ENVSYS_SVALID;
e->value_cur = AXP_ADC_RAW(hi, lo) * c->discharge_step;
}
break;
case AXP_SENSOR_BATT_MAXIMUM_CAPACITY:
if (battery_present &&
- axppmic_read(sc->sc_i2c, sc->sc_addr, AXP_BATT_MAX_CAP_HI_REG, &hi, flags) == 0 &&
- axppmic_read(sc->sc_i2c, sc->sc_addr, AXP_BATT_MAX_CAP_LO_REG, &lo, flags) == 0) {
+ axppmic_read(sc->sc_i2c, sc->sc_addr, AXP_BATT_MAX_CAP_HI_REG, &hi, 0) == 0 &&
+ axppmic_read(sc->sc_i2c, sc->sc_addr, AXP_BATT_MAX_CAP_LO_REG, &lo, 0) == 0) {
e->state = (hi & AXP_BATT_MAX_CAP_VALID) ? ENVSYS_SVALID : ENVSYS_SINVALID;
e->value_cur = AXP_COULOMB_RAW(hi, lo) * c->maxcap_step;
}
break;
case AXP_SENSOR_BATT_CURRENT_CAPACITY:
if (battery_present &&
- axppmic_read(sc->sc_i2c, sc->sc_addr, AXP_BATT_COULOMB_HI_REG, &hi, flags) == 0 &&
- axppmic_read(sc->sc_i2c, sc->sc_addr, AXP_BATT_COULOMB_LO_REG, &lo, flags) == 0) {
+ axppmic_read(sc->sc_i2c, sc->sc_addr, AXP_BATT_COULOMB_HI_REG, &hi, 0) == 0 &&
+ axppmic_read(sc->sc_i2c, sc->sc_addr, AXP_BATT_COULOMB_LO_REG, &lo, 0) == 0) {
e->state = (hi & AXP_BATT_COULOMB_VALID) ? ENVSYS_SVALID : ENVSYS_SINVALID;
e->value_cur = AXP_COULOMB_RAW(hi, lo) * c->coulomb_step;
}
@@ -702,7 +707,6 @@
axppmic_sensor_refresh(struct sysmon_envsys *sme, envsys_data_t *e)
{
struct axppmic_softc *sc = sme->sme_cookie;
- const int flags = I2C_F_POLL;
switch (e->private) {
case AXP_SENSOR_BATT_CAPACITY_PERCENT:
@@ -710,16 +714,16 @@
case AXP_SENSOR_BATT_CHARGE_CURRENT:
case AXP_SENSOR_BATT_DISCHARGE_CURRENT:
/* Always update battery capacity and ADCs */
- iic_acquire_bus(sc->sc_i2c, flags);
+ iic_acquire_bus(sc->sc_i2c, 0);
axppmic_sensor_update(sme, e);
- iic_release_bus(sc->sc_i2c, flags);
+ iic_release_bus(sc->sc_i2c, 0);
break;
default:
/* Refresh if the sensor is not in valid state */
if (e->state != ENVSYS_SVALID) {
- iic_acquire_bus(sc->sc_i2c, flags);
+ iic_acquire_bus(sc->sc_i2c, 0);
axppmic_sensor_update(sme, e);
- iic_release_bus(sc->sc_i2c, flags);
+ iic_release_bus(sc->sc_i2c, 0);
}
break;
}
@@ -728,15 +732,42 @@
static int
axppmic_intr(void *priv)
{
- struct axppmic_softc *sc = priv;
- const struct axppmic_config *c = sc->sc_conf;
- const int flags = I2C_F_POLL;
+ struct axppmic_softc * const sc = priv;
+
+ mutex_enter(&sc->sc_intr_lock);
+
+ fdtbus_intr_mask(sc->sc_phandle, sc->sc_ih);
+
+ /* Interrupt is always masked when work is scheduled! */
+ KASSERT(!sc->sc_work_scheduled);
+ sc->sc_work_scheduled = true;
+ workqueue_enqueue(sc->sc_wq, &sc->sc_work, NULL);
+
+ mutex_exit(&sc->sc_intr_lock);
+
+ return 1;
+}
+
+static void
+axppmic_work(struct work *work, void *arg)
+{
+ struct axppmic_softc * const sc =
+ container_of(work, struct axppmic_softc, sc_work);
+ const struct axppmic_config * const c = sc->sc_conf;
+ const int flags = 0;
uint8_t stat;
u_int n;
+ KASSERT(sc->sc_work_scheduled);
+
iic_acquire_bus(sc->sc_i2c, flags);
for (n = 1; n <= c->irq_regs; n++) {
if (axppmic_read(sc->sc_i2c, sc->sc_addr, AXP_IRQ_STATUS_REG(n), &stat, flags) == 0) {
+ if (stat != 0) {
+ axppmic_write(sc->sc_i2c, sc->sc_addr,
+ AXP_IRQ_STATUS_REG(n), stat, flags);
+ }
+
if (n == c->poklirq.reg && (stat & c->poklirq.mask) != 0)
sysmon_task_queue_sched(0, axppmic_task_shut, sc);
if (n == c->acinirq.reg && (stat & c->acinirq.mask) != 0)
@@ -749,15 +780,14 @@
axppmic_sensor_update(sc->sc_sme, &sc->sc_sensor[AXP_SENSOR_BATT_CHARGING]);
if (n == c->chargestirq.reg && (stat & c->chargestirq.mask) != 0)
axppmic_sensor_update(sc->sc_sme, &sc->sc_sensor[AXP_SENSOR_BATT_CHARGE_STATE]);
-
- if (stat != 0)
- axppmic_write(sc->sc_i2c, sc->sc_addr,
- AXP_IRQ_STATUS_REG(n), stat, flags);
}
}
Home |
Main Index |
Thread Index |
Old Index