Source-Changes-HG archive

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]

[src/trunk]: src/sys/dev/i2c Add support for poweroff and the power on-off ke...



details:   https://anonhg.NetBSD.org/src/rev/79b019744fa9
branches:  trunk
changeset: 322436:79b019744fa9
user:      jmcneill <jmcneill%NetBSD.org@localhost>
date:      Thu May 03 02:10:17 2018 +0000

description:
Add support for poweroff and the power on-off key (POK).

diffstat:

 sys/dev/i2c/axp806.c  |  98 +++++++++++++++++++++++++++++++++++++++++++-------
 sys/dev/i2c/files.i2c |   4 +-
 2 files changed, 86 insertions(+), 16 deletions(-)

diffs (216 lines):

diff -r 3d2c7593ebdf -r 79b019744fa9 sys/dev/i2c/axp806.c
--- a/sys/dev/i2c/axp806.c      Thu May 03 02:08:52 2018 +0000
+++ b/sys/dev/i2c/axp806.c      Thu May 03 02:10:17 2018 +0000
@@ -1,4 +1,4 @@
-/* $NetBSD: axp806.c,v 1.2 2018/05/03 01:15:49 jmcneill Exp $ */
+/* $NetBSD: axp806.c,v 1.3 2018/05/03 02:10:17 jmcneill Exp $ */
 
 /*-
  * Copyright (c) 2014-2018 Jared McNeill <jmcneill%invisible.ca@localhost>
@@ -27,7 +27,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: axp806.c,v 1.2 2018/05/03 01:15:49 jmcneill Exp $");
+__KERNEL_RCSID(0, "$NetBSD: axp806.c,v 1.3 2018/05/03 02:10:17 jmcneill Exp $");
 
 #include <sys/param.h>
 #include <sys/systm.h>
@@ -39,6 +39,9 @@
 
 #include <dev/i2c/i2cvar.h>
 
+#include <dev/sysmon/sysmonvar.h>
+#include <dev/sysmon/sysmon_taskq.h>
+
 #include <dev/fdt/fdtvar.h>
 
 #define AXP_STARTUP_SOURCE_REG 0x00
@@ -71,12 +74,14 @@
 #define AXP_CLDO3_CTRL_REG     0x26
 #define AXP_POWER_WAKE_CTRL_REG        0x31
 #define AXP_POWER_DISABLE_REG  0x32
+#define         AXP_POWER_DISABLE_CTRL __BIT(7)
 #define AXP_WAKEUP_PINFUNC_REG 0x35
 #define AXP_POK_SETTING_REG    0x36
-#define AXP_MODE_SEL_REG       0x3e
+#define AXP_MODE_SEL_REG       0axp806_power_funcsx3e
 #define AXP_SPECIAL_CTRL_REG   0x3f
 #define AXP_IRQ_ENABLE1_REG    0x40
 #define AXP_IRQ_ENABLE2_REG    0x41
+#define         AXP_IRQ2_POKSIRQ       __BIT(1)
 #define AXP_IRQ_STATUS1_REG    0x48
 #define AXP_IRQ_STATUS2_REG    0x49
 #define AXP_VREF_TEMP_WARN_REG 0xf3
@@ -153,6 +158,8 @@
        i2c_tag_t       sc_i2c;
        i2c_addr_t      sc_addr;
        int             sc_phandle;
+
+       struct sysmon_pswitch sc_smpsw;
 };
 
 struct axp806reg_softc {
@@ -176,17 +183,15 @@
 };
 
 static int
-axp806_read(i2c_tag_t tag, i2c_addr_t addr, uint8_t reg, uint8_t *val)
+axp806_read(i2c_tag_t tag, i2c_addr_t addr, uint8_t reg, uint8_t *val, int flags)
 {
-       return iic_smbus_read_byte(tag, addr, reg, val,
-           cold ? I2C_F_POLL : 0);
+       return iic_smbus_read_byte(tag, addr, reg, val, flags);
 }
 
 static int
-axp806_write(i2c_tag_t tag, i2c_addr_t addr, uint8_t reg, uint8_t val)
+axp806_write(i2c_tag_t tag, i2c_addr_t addr, uint8_t reg, uint8_t val, int flags)
 {
-       return iic_smbus_write_byte(tag, addr, reg, val,
-           cold ? I2C_F_POLL : 0);
+       return iic_smbus_write_byte(tag, addr, reg, val, flags);
 }
 
 static int
@@ -220,10 +225,10 @@
                return EINVAL;
 
        iic_acquire_bus(tag, flags);
-       if ((error = axp806_read(tag, addr, c->c_voltage_reg, &val)) == 0) {
+       if ((error = axp806_read(tag, addr, c->c_voltage_reg, &val, flags)) == 0) {
                val &= ~c->c_voltage_mask;
                val |= __SHIFTIN(reg_val, c->c_voltage_mask);
-               error = axp806_write(tag, addr, c->c_voltage_reg, val);
+               error = axp806_write(tag, addr, c->c_voltage_reg, val, flags);
        }
        iic_release_bus(tag, flags);
 
@@ -241,7 +246,7 @@
                return EINVAL;
 
        iic_acquire_bus(tag, flags);
-       error = axp806_read(tag, addr, c->c_voltage_reg, &val);
+       error = axp806_read(tag, addr, c->c_voltage_reg, &val, flags);
        iic_release_bus(tag, flags);
        if (error)
                return error;
@@ -257,6 +262,52 @@
        return 0;
 }
 
+static void
+axp806_power_poweroff(device_t dev)
+{
+       struct axp806_softc *sc = device_private(dev);
+
+       delay(1000000);
+
+       iic_acquire_bus(sc->sc_i2c, I2C_F_POLL);
+       axp806_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);
+}
+
+static struct fdtbus_power_controller_func axp806_power_funcs = {
+       .poweroff = axp806_power_poweroff,
+};
+
+static void
+axp806_task_shut(void *priv)
+{
+       struct axp806_softc *sc = priv;
+
+       sysmon_pswitch_event(&sc->sc_smpsw, PSWITCH_EVENT_PRESSED);
+}
+
+static int
+axp806_intr(void *priv)
+{
+       struct axp806_softc *sc = priv;
+       const int flags = I2C_F_POLL;
+       uint8_t stat1, stat2;
+
+       iic_acquire_bus(sc->sc_i2c, flags);
+       if (axp806_read(sc->sc_i2c, sc->sc_addr, AXP_IRQ_STATUS1_REG, &stat1, flags) == 0) {
+               axp806_write(sc->sc_i2c, sc->sc_addr, AXP_IRQ_STATUS1_REG, stat1, flags);
+       }
+       if (axp806_read(sc->sc_i2c, sc->sc_addr, AXP_IRQ_STATUS2_REG, &stat2, flags) == 0) {
+               if (stat2 & AXP_IRQ2_POKSIRQ)
+                       sysmon_task_queue_sched(0, axp806_task_shut, sc);
+
+               axp806_write(sc->sc_i2c, sc->sc_addr, AXP_IRQ_STATUS2_REG, stat2, flags);
+       }
+       iic_release_bus(sc->sc_i2c, flags);
+
+       return 1;
+}
+
 static int
 axp806_match(device_t parent, cfdata_t match, void *aux)
 {
@@ -275,6 +326,7 @@
        struct axp806reg_attach_args aaa;
        struct i2c_attach_args *ia = aux;
        int phandle, child, i;
+       void *ih;
 
        sc->sc_dev = self;
        sc->sc_i2c = ia->ia_tag;
@@ -284,6 +336,24 @@
        aprint_naive("\n");
        aprint_normal(": PMIC\n");
 
+       sc->sc_smpsw.smpsw_name = device_xname(self);
+       sc->sc_smpsw.smpsw_type = PSWITCH_TYPE_POWER;
+       sysmon_pswitch_register(&sc->sc_smpsw);
+
+       iic_acquire_bus(sc->sc_i2c, I2C_F_POLL);
+       axp806_write(sc->sc_i2c, sc->sc_addr, AXP_IRQ_ENABLE1_REG, 0x00, I2C_F_POLL);
+       axp806_write(sc->sc_i2c, sc->sc_addr, AXP_IRQ_ENABLE2_REG, AXP_IRQ2_POKSIRQ, I2C_F_POLL);
+       iic_release_bus(sc->sc_i2c, I2C_F_POLL);
+
+       ih = fdtbus_intr_establish(sc->sc_phandle, 0, IPL_VM, FDT_INTR_MPSAFE,
+           axp806_intr, sc);
+       if (ih == NULL) {
+               aprint_error_dev(self, "WARNING: couldn't establish interrupt handler\n");
+       }
+
+       fdtbus_register_power_controller(sc->sc_dev, sc->sc_phandle,
+           &axp806_power_funcs);
+
        phandle = of_find_firstchild_byname(sc->sc_phandle, "regulators");
        if (phandle <= 0)
                return;
@@ -325,12 +395,12 @@
                return EINVAL;
 
        iic_acquire_bus(sc->sc_i2c, flags);
-       if ((error = axp806_read(sc->sc_i2c, sc->sc_addr, c->c_enable_reg, &val)) == 0) {
+       if ((error = axp806_read(sc->sc_i2c, sc->sc_addr, c->c_enable_reg, &val, flags)) == 0) {
                if (enable)
                        val |= c->c_enable_mask;
                else
                        val &= ~c->c_enable_mask;
-               error = axp806_write(sc->sc_i2c, sc->sc_addr, c->c_enable_reg, val);
+               error = axp806_write(sc->sc_i2c, sc->sc_addr, c->c_enable_reg, val, flags);
        }
        iic_release_bus(sc->sc_i2c, flags);
 
diff -r 3d2c7593ebdf -r 79b019744fa9 sys/dev/i2c/files.i2c
--- a/sys/dev/i2c/files.i2c     Thu May 03 02:08:52 2018 +0000
+++ b/sys/dev/i2c/files.i2c     Thu May 03 02:10:17 2018 +0000
@@ -1,4 +1,4 @@
-#      $NetBSD: files.i2c,v 1.88 2018/05/03 01:15:49 jmcneill Exp $
+#      $NetBSD: files.i2c,v 1.89 2018/05/03 02:10:17 jmcneill Exp $
 
 obsolete defflag       opt_i2cbus.h            I2C_SCAN
 define i2cbus { }
@@ -233,7 +233,7 @@
 file   dev/i2c/axp22x.c                        axp22x
 
 # AXP806 Power Management Unit
-device axp806pmic { }
+device axp806pmic { }: sysmon_taskq
 device axp806reg: axp806pmic
 attach axp806pmic at iic
 attach axp806reg at axp806pmic



Home | Main Index | Thread Index | Old Index