Initial apm/sensor driver for the PiJuice HAT UPS, to feedback battery
authormglocker <mglocker@openbsd.org>
Sun, 23 Oct 2022 18:43:00 +0000 (18:43 +0000)
committermglocker <mglocker@openbsd.org>
Sun, 23 Oct 2022 18:43:00 +0000 (18:43 +0000)
status information.

ok deraadt@

share/man/man4/Makefile
share/man/man4/iic.4
share/man/man4/pijuice.4 [new file with mode: 0644]
sys/arch/arm64/conf/GENERIC
sys/dev/i2c/files.i2c
sys/dev/i2c/pijuice.c [new file with mode: 0644]

index b6d6cbe..0a356bc 100644 (file)
@@ -1,4 +1,4 @@
-#      $OpenBSD: Makefile,v 1.820 2022/09/12 17:30:32 kettenis Exp $
+#      $OpenBSD: Makefile,v 1.821 2022/10/23 18:43:00 mglocker Exp $
 
 MAN=   aac.4 abcrtc.4 abl.4 ac97.4 acphy.4 acrtc.4 \
        acpi.4 acpiac.4 acpials.4 acpiasus.4 acpibat.4 \
@@ -68,7 +68,7 @@ MAN=  aac.4 abcrtc.4 abl.4 ac97.4 acphy.4 acrtc.4 \
        pcfadc.4 pcfiic.4 pcfrtc.4 pchgpio.4 pciide.4 pckbc.4 pckbd.4 \
        pcmcia.4 pcn.4 pcppi.4 pcscp.4 pcxrtc.4 pcyrtc.4 \
        pf.4 pflog.4 pflow.4 pfsync.4 \
-       pgt.4 piixpm.4 pinctrl.4 pipex.4 plgpio.4 plrtc.4 pluart.4 \
+       pgt.4 piixpm.4 pijuice.4 pinctrl.4 pipex.4 plgpio.4 plrtc.4 pluart.4 \
        pms.4 ppb.4 ppp.4 pppoe.4 pppx.4 psci.4 pty.4 puc.4 pvbus.4 \
        pvclock.4 pwdog.4 pwmbl.4 pwmfan.4 pwmreg.4 \
        qla.4 qle.4 qlw.4 qsphy.4 \
index 513cc7b..c884a8c 100644 (file)
@@ -1,4 +1,4 @@
-.\"    $OpenBSD: iic.4,v 1.128 2022/09/13 05:48:54 jmc Exp $
+.\"    $OpenBSD: iic.4,v 1.129 2022/10/23 18:43:00 mglocker Exp $
 .\"
 .\" Copyright (c) 2004, 2006 Alexander Yurchenko <grange@openbsd.org>
 .\"
@@ -14,7 +14,7 @@
 .\" ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
 .\" OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 .\"
-.Dd $Mdocdate: September 13 2022 $
+.Dd $Mdocdate: October 23 2022 $
 .Dt IIC 4
 .Os
 .Sh NAME
@@ -244,6 +244,8 @@ NXP PCF8523 real-time clock
 NXP PCF8563 real-time clock
 .It Xr pcyrtc 4
 NXP PCF85063A/TP real-time clock
+.It Xr pijuice 4
+PiJuice HAT UPS
 .It Xr ricohrtc 4
 Ricoh RS5C372 real-time clock
 .It Xr rkpmic 4
diff --git a/share/man/man4/pijuice.4 b/share/man/man4/pijuice.4
new file mode 100644 (file)
index 0000000..8c7d22b
--- /dev/null
@@ -0,0 +1,52 @@
+.\"    $OpenBSD: pijuice.4,v 1.1 2022/10/23 18:43:00 mglocker Exp $
+.\"
+.\" Copyright (c) 2022 Marcus Glocker <mglocker@openbsd.org>
+.\"
+.\" Permission to use, copy, modify, and distribute this software for any
+.\" purpose with or without fee is hereby granted, provided that the above
+.\" copyright notice and this permission notice appear in all copies.
+.\"
+.\" THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+.\" WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+.\" MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+.\" ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+.\" WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+.\" ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+.\" OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+.\"
+.Dd $Mdocdate: October 23 2022 $
+.Dt PIJUICE 4
+.Os
+.Sh NAME
+.Nm pijuice
+.Nd PiJuice HAT UPS
+.Sh SYNOPSIS
+.Cd "pijuice* at iic?"
+.Sh DESCRIPTION
+The
+.Nm
+driver provides support for the PiJuice HAT.
+It is a uninterruptible power supply for the Raspberry Pi's.
+The integrated STM32F030CCT6 micro controller provides access through the I2C
+bus to several battery status values.
+.Sh SEE ALSO
+.Xr apm 8 ,
+.Xr iic 4 ,
+.Xr intro 4 ,
+.Xr maxrtc 4 ,
+.Xr sysctl 8
+.Sh HISTORY
+The
+.Nm
+driver first appeared in
+.Ox 7.3 .
+.Sh AUTHORS
+.An -nosplit
+The
+.Nm
+driver was written by
+.An Marcus Glocker Aq Mt mglocker@openbsd.org .
+.Sh CAVEATS
+The PiJuice HAT EEPROM currently doesn't contain the device tree information
+to match and attach this device.  It requires a custom device tree blob overlay
+which gets loaded during the bootstrapping process.
index bc88d2c..c1f21df 100644 (file)
@@ -1,4 +1,4 @@
-# $OpenBSD: GENERIC,v 1.239 2022/09/12 20:31:53 kettenis Exp $
+# $OpenBSD: GENERIC,v 1.240 2022/10/23 18:43:00 mglocker Exp $
 #
 # GENERIC machine description file
 #
@@ -536,6 +536,7 @@ rkpmic*             at iic?                 # RK808 PMIC
 sypwr*         at iic?                 # SY8106A regulator
 tascodec*      at iic?                 # TAS2770 audio codec
 tcpci*         at iic?                 # USB Type-C controller
+pijuice*       at iic?                 # PiJuice HAT
 
 # GPIO "pin bus" drivers
 gpioiic*       at gpio?                # I2C bus bit-banging
index 7af95e1..b2b3a89 100644 (file)
@@ -1,4 +1,4 @@
-# $OpenBSD: files.i2c,v 1.69 2021/11/22 20:20:20 kettenis Exp $
+# $OpenBSD: files.i2c,v 1.70 2022/10/23 18:43:00 mglocker Exp $
 #      $NetBSD: files.i2c,v 1.3 2003/10/20 16:24:10 briggs Exp $
 
 define i2c {[addr = -1], [size = -1]}
@@ -263,3 +263,8 @@ file        dev/i2c/m41t8x.c                        mfokrtc
 device titmp
 attach titmp at i2c
 file   dev/i2c/tmp451.c                        titmp
+
+# PiJuice
+device pijuice
+attach pijuice at i2c
+file   dev/i2c/pijuice.c                       pijuice
diff --git a/sys/dev/i2c/pijuice.c b/sys/dev/i2c/pijuice.c
new file mode 100644 (file)
index 0000000..393e7f5
--- /dev/null
@@ -0,0 +1,408 @@
+/*     $OpenBSD: pijuice.c,v 1.1 2022/10/23 18:43:00 mglocker Exp $ */
+
+/*
+ * Copyright (c) 2022 Marcus Glocker <mglocker@openbsd.org>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/device.h>
+#include <sys/sensors.h>
+
+#include <machine/apmvar.h>
+
+#include <dev/i2c/i2cvar.h>
+
+#include "apm.h"
+
+#ifdef PIJUICE_DEBUG
+#define DPRINTF(x)     printf x
+#else
+#define DPRINTF(x)
+#endif
+
+/* I2C Status commands. */
+#define PIJUICE_CMD_STATUS                             0x40
+#define PIJUICE_CMD_FAULT_EVENT                                0x44
+#define PIJUICE_CMD_CHARGE_LEVEL                       0x41
+#define PIJUICE_CMD_BUTTON_EVENT                       0x45
+#define PIJUICE_CMD_BATTERY_TEMP                       0x47
+#define PIJUICE_CMD_BATTERY_VOLTAGE                    0x49
+#define PIJUICE_CMD_BATTERY_CURRENT                    0x4b
+#define PIJUICE_CMD_IO_VOLTAGE                         0x4d
+#define PIJUICE_CMD_IO_CURRENT                         0x4f
+#define PIJUICE_CMD_LED_STATE                          0x66
+#define PIJUICE_CMD_LED_BLINK                          0x68
+#define PIJUICE_CMD_IO_PIN_ACCESS                      0x75
+
+/* I2C Config commands. */
+#define PIJUICE_CMD_CHARGING_CONFIG                    0x51
+#define PIJUICE_CMD_BATTERY_PROFILE_ID                 0x52
+#define PIJUICE_CMD_BATTERY_PROFILE                    0x53
+#define PIJUICE_CMD_BATTERY_EXT_PROFILE                        0x54
+#define PIJUICE_CMD_BATTERY_TEMP_SENSE_CONFIG          0x5d
+#define PIJUICE_CMD_POWER_INPUTS_CONFIG                        0x5e
+#define PIJUICE_CMD_RUN_PIN_CONFIG                     0x5f
+#define PIJUICE_CMD_POWER_REGULATOR_CONFIG             0x60
+#define PIJUICE_CMD_LED_CONFIG                         0x6a
+#define PIJUICE_CMD_BUTTON_CONFIG                      0x6e
+#define PIJUICE_CMD_IO_CONFIG                          0x72
+#define PIJUICE_CMD_I2C_ADDRESS                                0x7c
+#define PIJUICE_CMD_ID_EEPROM_WRITE_PROTECT_CTRL       0x7e
+#define PIJUICE_CMD_ID_EEPROM_ADDRESS                  0x7f
+#define PIJUICE_CMD_RESET_TO_DEFAULT                   0xf0
+#define PIJUICE_CMD_FIRMWARE_VERSION                   0xfd
+
+/* Sensors. */
+#define PIJUICE_NSENSORS       3
+enum pijuice_sensors {
+       PIJUICE_SENSOR_CHARGE,  /* 0 */
+       PIJUICE_SENSOR_TEMP,    /* 1 */
+       PIJUICE_SENSOR_VOLTAGE, /* 2 */
+};
+
+struct pijuice_softc {
+       struct device           sc_dev;
+       i2c_tag_t               sc_tag;
+       int                     sc_addr;
+
+       struct ksensor          sc_sensor[PIJUICE_NSENSORS];
+       struct ksensordev       sc_sensordev;
+};
+
+struct pijuice_softc *pijuice_sc;
+
+int    pijuice_match(struct device *, void *, void *);
+void   pijuice_attach(struct device *, struct device *, void *);
+int    pijuice_read(struct pijuice_softc *, uint8_t *, uint8_t,
+           uint8_t *, uint8_t);
+int    pijuice_write(struct pijuice_softc *, uint8_t *, uint8_t);
+int    pijuice_get_fw_version(struct pijuice_softc *, const int, char *);
+int    pijuice_get_bcl(struct pijuice_softc *, uint8_t *);
+int    pijuice_get_status(struct pijuice_softc *, uint8_t *);
+int    pijuice_get_temp(struct pijuice_softc *sc, uint8_t *);
+int    pijuice_get_voltage(struct pijuice_softc *sc, uint16_t *);
+void   pijuice_refresh_sensors(void *);
+int    pijuice_apminfo(struct apm_power_info *);
+
+const struct cfattach pijuice_ca = {
+       sizeof(struct pijuice_softc), pijuice_match, pijuice_attach
+};
+
+struct cfdriver pijuice_cd = {
+       NULL, "pijuice", DV_DULL
+};
+
+int
+pijuice_match(struct device *parent, void *v, void *arg)
+{
+       struct i2c_attach_args *ia = arg;
+
+       if (strcmp(ia->ia_name, "pisupply,pijuice") == 0)
+               return 1;
+
+       return 0;
+}
+
+void
+pijuice_attach(struct device *parent, struct device *self, void *arg)
+{
+       struct pijuice_softc *sc = (struct pijuice_softc *)self;
+       struct i2c_attach_args *ia = arg;
+       char fw_version[8];
+       int i;
+
+       pijuice_sc = sc;
+
+       sc->sc_tag = ia->ia_tag;
+       sc->sc_addr = ia->ia_addr;
+
+       /* Setup sensor framework. */
+       strlcpy(sc->sc_sensor[PIJUICE_SENSOR_CHARGE].desc, "battery charge",
+           sizeof(sc->sc_sensor[PIJUICE_SENSOR_CHARGE].desc));
+       sc->sc_sensor[PIJUICE_SENSOR_CHARGE].type = SENSOR_PERCENT;
+
+       strlcpy(sc->sc_sensor[PIJUICE_SENSOR_TEMP].desc, "battery temperature",
+           sizeof(sc->sc_sensor[PIJUICE_SENSOR_TEMP].desc));
+       sc->sc_sensor[PIJUICE_SENSOR_TEMP].type = SENSOR_TEMP;
+
+       strlcpy(sc->sc_sensor[PIJUICE_SENSOR_VOLTAGE].desc, "battery voltage",
+           sizeof(sc->sc_sensor[PIJUICE_SENSOR_VOLTAGE].desc));
+       sc->sc_sensor[PIJUICE_SENSOR_VOLTAGE].type = SENSOR_VOLTS_DC;
+
+       strlcpy(sc->sc_sensordev.xname, sc->sc_dev.dv_xname,
+           sizeof(sc->sc_sensordev.xname));
+       for (i = 0; i < PIJUICE_NSENSORS; i++)
+               sensor_attach(&sc->sc_sensordev, &sc->sc_sensor[i]);
+       sensordev_install(&sc->sc_sensordev);
+
+       if (sensor_task_register(sc, pijuice_refresh_sensors, 5) == NULL) {
+               printf(": unable to register update task\n");
+               return;
+       }
+
+       /* Print device firmware version. */
+       if (pijuice_get_fw_version(sc, sizeof(fw_version), fw_version) == -1) {
+               printf(": can't get firmware version\n");
+               return;
+       }
+       printf(": firmware version %s\n", fw_version);
+
+#if NAPM > 0
+       apm_setinfohook(pijuice_apminfo);
+#endif
+}
+
+int
+pijuice_read(struct pijuice_softc *sc, uint8_t *cmd, uint8_t cmd_len,
+    uint8_t *data, uint8_t data_len)
+{
+       int error;
+
+       iic_acquire_bus(sc->sc_tag, I2C_F_POLL);
+       error = iic_exec(sc->sc_tag, I2C_OP_READ_WITH_STOP, sc->sc_addr,
+           cmd, cmd_len, data, data_len, I2C_F_POLL);
+       iic_release_bus(sc->sc_tag, I2C_F_POLL);
+
+       return error;
+}
+
+int
+pijuice_write(struct pijuice_softc *sc, uint8_t *data, uint8_t data_len)
+{
+       int error;
+
+       iic_acquire_bus(sc->sc_tag, I2C_F_POLL);
+       error = iic_exec(sc->sc_tag, I2C_OP_WRITE_WITH_STOP, sc->sc_addr,
+           NULL, 0, data, data_len, I2C_F_POLL);
+       iic_release_bus(sc->sc_tag, I2C_F_POLL);
+
+       return error;
+}
+
+/*
+ * Get firmware version.
+ */
+int
+pijuice_get_fw_version(struct pijuice_softc *sc, const int fw_version_size,
+    char *fw_version)
+{
+       uint8_t cmd;
+       uint8_t data[2];
+       uint8_t fw_version_minor, fw_version_major;
+
+       cmd = PIJUICE_CMD_FIRMWARE_VERSION;
+       memset(data, 0, sizeof(data));
+       if (pijuice_read(sc, &cmd, sizeof(cmd), data, sizeof(data)))
+               return -1;
+
+       fw_version_major = data[0] >> 4;
+       fw_version_minor = (data[0] << 4 & 0xf0) >> 4;
+       snprintf(fw_version, fw_version_size, "%d.%d",
+           fw_version_major, fw_version_minor);
+
+       return 0;
+}
+
+/*
+ * Get battery charge level.
+ */
+int
+pijuice_get_bcl(struct pijuice_softc *sc, uint8_t *bcl)
+{
+       uint8_t cmd;
+       uint8_t data;
+
+       cmd = PIJUICE_CMD_CHARGE_LEVEL;
+       data = 0;
+       if (pijuice_read(sc, &cmd, sizeof(cmd), &data, sizeof(data)))
+               return -1;
+
+       *bcl = data;
+
+       return 0;
+}
+
+/*
+ * Get AC and Battery status.
+ *
+ */
+#define PIJUICE_STATUS_FAULT_MASK(status)      ((status >> 0) & 0x01)
+#define PIJUICE_STATUS_BUTTON_MASK(status)     ((status >> 0) & 0x02)
+#define PIJUICE_STATUS_BATT_MASK(status)       ((status >> 2) & 0x03)
+#define   PIJUICE_STATUS_BATT_NORMAL           0
+#define   PIJUICE_STATUS_BATT_CHARGE_AC                1
+#define   PIJUICE_STATUS_BATT_CHARGE_5V                2
+#define   PIJUICE_STATUS_BATT_ABSENT           3
+#define PIJUICE_STATUS_AC_MASK(status)         ((status >> 4) & 0x03)
+#define   PIJUICE_STATUS_AC_ABSENT             0
+#define   PIJUICE_STATUS_AC_BAD                        1
+#define   PIJUICE_STATUS_AC_WEAK               2
+#define   PIJUICE_STATUS_AC_PRESENT            3
+#define PIJUICE_STATUS_AC_IN_MASK(status)      ((status >> 6) & 0x03)
+int
+pijuice_get_status(struct pijuice_softc *sc, uint8_t *status)
+{
+       uint8_t cmd;
+       uint8_t data;
+
+       cmd = PIJUICE_CMD_STATUS;
+       data = 0;
+       if (pijuice_read(sc, &cmd, sizeof(cmd), &data, sizeof(data)))
+               return -1;
+
+       *status = data;
+
+       return 0;
+}
+
+/*
+ * Get battery temperature.
+ */
+int
+pijuice_get_temp(struct pijuice_softc *sc, uint8_t *temp)
+{
+       uint8_t cmd;
+       uint8_t data[2];
+
+       cmd = PIJUICE_CMD_BATTERY_TEMP;
+       memset(data, 0, sizeof(data));
+       if (pijuice_read(sc, &cmd, sizeof(cmd), data, sizeof(data)))
+               return -1;
+
+       *temp = (uint8_t)data[0];
+       if (data[0] & (1 << 7)) {
+               /* Minus degree. */
+               *temp = *temp - (1 << 8);
+       }
+
+       return 0;
+}
+
+/*
+ * Get battery voltage.
+ */
+int
+pijuice_get_voltage(struct pijuice_softc *sc, uint16_t *voltage)
+{
+       uint8_t cmd;
+       uint8_t data[2];
+
+       cmd = PIJUICE_CMD_BATTERY_VOLTAGE;
+       memset(data, 0, sizeof(data));
+       if (pijuice_read(sc, &cmd, sizeof(cmd), data, sizeof(data)))
+               return -1;
+
+       *voltage = (uint16_t)(data[1] << 8) | data[0];
+
+       return 0;
+}
+
+void
+pijuice_refresh_sensors(void *arg)
+{
+       struct pijuice_softc *sc = arg;
+       uint8_t val8;
+       uint16_t val16;
+       int i;
+
+       for (i = 0; i < PIJUICE_NSENSORS; i++)
+               sc->sc_sensor[i].flags |= SENSOR_FINVALID;
+
+       if (pijuice_get_bcl(sc, &val8) == 0) {
+               DPRINTF(("%s: Battery Charge Level=%d\n", __func__, val8));
+
+               sc->sc_sensor[0].value = val8 * 1000;
+               sc->sc_sensor[0].flags &= ~SENSOR_FINVALID;
+       }
+
+       if (pijuice_get_temp(sc, &val8) == 0) {
+               DPRINTF(("%s: Battery Temperature=%d\n", __func__, val8));
+
+               sc->sc_sensor[PIJUICE_SENSOR_TEMP].value =
+                   273150000 + 1000000 * val8;
+               sc->sc_sensor[PIJUICE_SENSOR_TEMP].flags &= ~SENSOR_FINVALID;
+       }
+
+       if (pijuice_get_voltage(sc, &val16) == 0) {
+               DPRINTF(("%s: Battery Voltage=%d\n", __func__, val16));
+
+               sc->sc_sensor[PIJUICE_SENSOR_VOLTAGE].value = val16 * 1000;
+               sc->sc_sensor[PIJUICE_SENSOR_VOLTAGE].flags &= ~SENSOR_FINVALID;
+       }
+}
+
+#if NAPM > 0
+int
+pijuice_apminfo(struct apm_power_info *info)
+{
+       struct pijuice_softc *sc = pijuice_sc;
+       uint8_t val8;
+
+       info->battery_state = APM_BATT_UNKNOWN;
+       info->ac_state = APM_AC_UNKNOWN;
+       info->battery_life = 0;
+       info->minutes_left = -1;
+
+       if (pijuice_get_bcl(sc, &val8) == 0) {
+               DPRINTF(("%s: Battery Charge Level=%d\n", __func__, val8));
+
+               info->battery_life = val8;
+               /* On "normal load" we suck 1% battery in 30 sconds. */
+               info->minutes_left = (val8 * 30) / 60;
+       }
+
+       if (pijuice_get_status(sc, &val8) == 0) {
+               DPRINTF(("%s: Battery Status=%d\n",
+                   __func__, PIJUICE_STATUS_BATT_MASK(val8)));
+
+               switch (PIJUICE_STATUS_BATT_MASK(val8)) {
+               case PIJUICE_STATUS_BATT_NORMAL:
+                       if (info->battery_life > 50)
+                               info->battery_state = APM_BATT_HIGH;
+                       else if (info->battery_life > 25)
+                               info->battery_state = APM_BATT_LOW;
+                       else
+                               info->battery_state = APM_BATT_CRITICAL;
+                       break;
+               case PIJUICE_STATUS_BATT_CHARGE_AC:
+               case PIJUICE_STATUS_BATT_CHARGE_5V:
+                       info->battery_state = APM_BATT_CHARGING;
+                       break;
+               case PIJUICE_STATUS_BATT_ABSENT:
+                       info->battery_state = APM_BATTERY_ABSENT;
+                       break;
+               }
+
+               DPRINTF(("%s: AC Status=%d\n",
+                   __func__, PIJUICE_STATUS_AC_MASK(val8)));
+
+               switch (PIJUICE_STATUS_AC_MASK(val8)) {
+               case PIJUICE_STATUS_AC_ABSENT:
+                       info->ac_state = APM_AC_OFF;
+                       break;
+               case PIJUICE_STATUS_AC_BAD:
+               case PIJUICE_STATUS_AC_WEAK:
+                       info->ac_state = APM_AC_BACKUP;
+                       break;
+               case PIJUICE_STATUS_AC_PRESENT:
+                       info->ac_state = APM_AC_ON;
+                       break;
+                }
+       }
+
+        return 0;
+}
+#endif