diff mbox

[09/11] Goldfish: Added battery device.

Message ID CAKspZ_vrGjKArTrAfC++U9Oif4s=t2at7YBHwtEs1Uzi4wPj_Q@mail.gmail.com
State New
Headers show

Commit Message

Patrick Jackson Aug. 22, 2011, 9:39 a.m. UTC
Signed-off-by: Patrick Jackson <PatrickSJackson@gmail.com>
---
 Makefile.target       |    1 +
 hw/android_arm.c      |    1 +
 hw/goldfish_battery.c |  247
+++++++++++++++++++++++++++++++++++++++++++++++++
 hw/goldfish_device.h  |    3 +
 hw/power_supply.h     |  109 ++++++++++++++++++++++
 5 files changed, 361 insertions(+), 0 deletions(-)
 create mode 100644 hw/goldfish_battery.c
 create mode 100644 hw/power_supply.h
diff mbox

Patch

diff --git a/Makefile.target b/Makefile.target
index b44f1be..593594b 100644
--- a/Makefile.target
+++ b/Makefile.target
@@ -362,6 +362,7 @@  obj-arm-y += strongarm.o
 obj-arm-y += collie.o
 obj-arm-y += android_arm.o goldfish_device.o goldfish_interrupt.o
goldfish_timer.o
 obj-arm-y += goldfish_tty.o goldfish_nand.o goldfish_fb.o goldfish_memlog.o
+obj-arm-y += goldfish_battery.o

 obj-sh4-y = shix.o r2d.o sh7750.o sh7750_regnames.o tc58128.o
 obj-sh4-y += sh_timer.o sh_serial.o sh_intc.o sh_pci.o sm501.o
diff --git a/hw/android_arm.c b/hw/android_arm.c
index f617a45..3fffc93 100644
--- a/hw/android_arm.c
+++ b/hw/android_arm.c
@@ -67,6 +67,7 @@  static void android_arm_init_(ram_addr_t ram_size,

     goldfish_fb_create(gbus, 0);
     goldfish_memlog_create(gbus, 0xff006000);
+    goldfish_battery_create(gbus);
     goldfish_nand_create(gbus);

     info.ram_size        = ram_size;
diff --git a/hw/goldfish_battery.c b/hw/goldfish_battery.c
new file mode 100644
index 0000000..685b4aa
--- /dev/null
+++ b/hw/goldfish_battery.c
@@ -0,0 +1,247 @@ 
+/* Copyright (C) 2007-2008 The Android Open Source Project
+**
+** This software is licensed under the terms of the GNU General Public
+** License version 2, as published by the Free Software Foundation, and
+** may be copied, distributed, and modified under those terms.
+**
+** This program is distributed in the hope that it will be useful,
+** but WITHOUT ANY WARRANTY; without even the implied warranty of
+** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+** GNU General Public License for more details.
+*/
+#include "goldfish_device.h"
+#include "power_supply.h"
+
+
+enum {
+ /* status register */
+ BATTERY_INT_STATUS     = 0x00,
+ /* set this to enable IRQ */
+ BATTERY_INT_ENABLE     = 0x04,
+
+ BATTERY_AC_ONLINE       = 0x08,
+ BATTERY_STATUS          = 0x0C,
+ BATTERY_HEALTH          = 0x10,
+ BATTERY_PRESENT         = 0x14,
+ BATTERY_CAPACITY        = 0x18,
+
+ BATTERY_STATUS_CHANGED = 1U << 0,
+ AC_STATUS_CHANGED    = 1U << 1,
+ BATTERY_INT_MASK        = BATTERY_STATUS_CHANGED | AC_STATUS_CHANGED,
+};
+
+
+typedef struct GoldfishBatteryDevice {
+    GoldfishDevice dev;
+    // IRQs
+    uint32_t int_status;
+    // irq enable mask for int_status
+    uint32_t int_enable;
+
+    int ac_online;
+    int status;
+    int health;
+    int present;
+    int capacity;
+} GoldfishBatteryDevice;
+
+static uint32_t goldfish_battery_read(void *opaque, target_phys_addr_t
offset)
+{
+    uint32_t ret;
+    GoldfishBatteryDevice *s = (GoldfishBatteryDevice *)opaque;
+
+    switch(offset) {
+        case BATTERY_INT_STATUS:
+            // return current buffer status flags
+            ret = s->int_status & s->int_enable;
+            if (ret) {
+                goldfish_device_set_irq(&s->dev, 0, 0);
+                s->int_status = 0;
+            }
+            return ret;
+
+ case BATTERY_INT_ENABLE:
+     return s->int_enable;
+ case BATTERY_AC_ONLINE:
+     return s->ac_online;
+ case BATTERY_STATUS:
+     return s->status;
+ case BATTERY_HEALTH:
+     return s->health;
+ case BATTERY_PRESENT:
+     return s->present;
+ case BATTERY_CAPACITY:
+     return s->capacity;
+
+        default:
+            cpu_abort (cpu_single_env, "goldfish_battery_read: Bad offset
%x\n", offset);
+            return 0;
+    }
+}
+
+static void goldfish_battery_write(void *opaque, target_phys_addr_t offset,
uint32_t val)
+{
+    GoldfishBatteryDevice *s = (GoldfishBatteryDevice *)opaque;
+
+    switch(offset) {
+        case BATTERY_INT_ENABLE:
+            /* enable interrupts */
+            s->int_enable = val;
+//            s->int_status = (AUDIO_INT_WRITE_BUFFER_1_EMPTY |
AUDIO_INT_WRITE_BUFFER_2_EMPTY);
+//            goldfish_device_set_irq(&s->dev, 0, (s->int_status &
s->int_enable));
+            break;
+
+        default:
+            cpu_abort (cpu_single_env, "goldfish_audio_write: Bad offset
%x\n", offset);
+    }
+}
+
+static CPUReadMemoryFunc *goldfish_battery_readfn[] = {
+    goldfish_battery_read,
+    goldfish_battery_read,
+    goldfish_battery_read
+};
+
+static CPUWriteMemoryFunc *goldfish_battery_writefn[] = {
+    goldfish_battery_write,
+    goldfish_battery_write,
+    goldfish_battery_write
+};
+
+void goldfish_battery_set_prop(void *opaque, int ac, int property, int
value)
+{
+    int new_status = (ac ? AC_STATUS_CHANGED : BATTERY_STATUS_CHANGED);
+    GoldfishBatteryDevice *s = (GoldfishBatteryDevice *)opaque;
+
+    if (ac) {
+        switch (property) {
+            case POWER_SUPPLY_PROP_ONLINE:
+                s->ac_online = value;
+                break;
+        }
+    } else {
+         switch (property) {
+            case POWER_SUPPLY_PROP_STATUS:
+                s->status = value;
+                break;
+            case POWER_SUPPLY_PROP_HEALTH:
+                s->health = value;
+                break;
+            case POWER_SUPPLY_PROP_PRESENT:
+                s->present = value;
+                break;
+            case POWER_SUPPLY_PROP_CAPACITY:
+                s->capacity = value;
+                break;
+        }
+    }
+
+    if (new_status != s->int_status) {
+        s->int_status |= new_status;
+        goldfish_device_set_irq(&s->dev, 0, (s->int_status &
s->int_enable));
+    }
+}
+
+void goldfish_battery_display(void *opaque, void (* callback)(void *data,
const char* string), void *data)
+{
+    GoldfishBatteryDevice *s = (GoldfishBatteryDevice *)opaque;
+    char          buffer[100];
+    const char*   value;
+
+    sprintf(buffer, "AC: %s\r\n", (s->ac_online ? "online" : "offline"));
+    callback(data, buffer);
+
+    switch (s->status) {
+     case POWER_SUPPLY_STATUS_CHARGING:
+         value = "Charging";
+         break;
+     case POWER_SUPPLY_STATUS_DISCHARGING:
+         value = "Discharging";
+         break;
+     case POWER_SUPPLY_STATUS_NOT_CHARGING:
+         value = "Not charging";
+         break;
+     case POWER_SUPPLY_STATUS_FULL:
+         value = "Full";
+         break;
+        default:
+         value = "Unknown";
+         break;
+    }
+    sprintf(buffer, "status: %s\r\n", value);
+    callback(data, buffer);
+
+    switch (s->health) {
+     case POWER_SUPPLY_HEALTH_GOOD:
+         value = "Good";
+         break;
+     case POWER_SUPPLY_HEALTH_OVERHEAT:
+         value = "Overhead";
+         break;
+     case POWER_SUPPLY_HEALTH_DEAD:
+         value = "Dead";
+         break;
+     case POWER_SUPPLY_HEALTH_OVERVOLTAGE:
+         value = "Overvoltage";
+         break;
+     case POWER_SUPPLY_HEALTH_UNSPEC_FAILURE:
+         value = "Unspecified failure";
+         break;
+        default:
+         value = "Unknown";
+         break;
+    }
+    sprintf(buffer, "health: %s\r\n", value);
+    callback(data, buffer);
+
+    sprintf(buffer, "present: %s\r\n", (s->present ? "true" : "false"));
+    callback(data, buffer);
+
+    sprintf(buffer, "capacity: %d\r\n", s->capacity);
+    callback(data, buffer);
+}
+
+static int goldfish_battery_init(GoldfishDevice *dev)
+{
+    return 0;
+}
+
+DeviceState *goldfish_battery_create(GoldfishBus *gbus)
+{
+    DeviceState *dev;
+    char *name = (char *)"goldfish-battery";
+
+    dev = qdev_create(&gbus->bus, name);
+    qdev_prop_set_string(dev, "name", name);
+    qdev_init_nofail(dev);
+
+    return dev;
+}
+
+static GoldfishDeviceInfo goldfish_battery_info = {
+    .init = goldfish_battery_init,
+    .readfn = goldfish_battery_readfn,
+    .writefn = goldfish_battery_writefn,
+    .qdev.name  = "goldfish-battery",
+    .qdev.size  = sizeof(GoldfishBatteryDevice),
+    .qdev.props = (Property[]) {
+        DEFINE_PROP_UINT32("base", GoldfishDevice, base, 0),
+        DEFINE_PROP_UINT32("id", GoldfishDevice, id, 0),
+        DEFINE_PROP_UINT32("size", GoldfishDevice, size, 0x1000),
+        DEFINE_PROP_UINT32("irq", GoldfishDevice, irq, 0),
+        DEFINE_PROP_UINT32("irq_count", GoldfishDevice, irq_count, 1),
+        DEFINE_PROP_INT32("ac_online", GoldfishBatteryDevice, ac_online,
1),
+        DEFINE_PROP_INT32("status", GoldfishBatteryDevice, status,
POWER_SUPPLY_STATUS_CHARGING),
+        DEFINE_PROP_INT32("health", GoldfishBatteryDevice, health,
POWER_SUPPLY_HEALTH_GOOD),
+        DEFINE_PROP_INT32("present", GoldfishBatteryDevice, present, 1),
 // battery is present
+        DEFINE_PROP_INT32("capacity", GoldfishBatteryDevice, capacity, 50),
// 50% charged
+        DEFINE_PROP_STRING("name", GoldfishDevice, name),
+        DEFINE_PROP_END_OF_LIST(),
+    },
+};
+
+static void goldfish_battery_register(void)
+{
+    goldfish_bus_register_withprop(&goldfish_battery_info);
+}
+device_init(goldfish_battery_register);
diff --git a/hw/goldfish_device.h b/hw/goldfish_device.h
index a6e7415..19af64a 100644
--- a/hw/goldfish_device.h
+++ b/hw/goldfish_device.h
@@ -49,12 +49,15 @@  DeviceState *goldfish_tty_create(GoldfishBus *gbus,
CharDriverState *cs, int id,
 DeviceState *goldfish_nand_create(GoldfishBus *gbus);
 DeviceState *goldfish_fb_create(GoldfishBus *gbus, int id);
 DeviceState *goldfish_memlog_create(GoldfishBus *gbus, uint32_t base);
+DeviceState *goldfish_battery_create(GoldfishBus *gbus);

 /* Global functions provided by Goldfish devices */
 void goldfish_bus_register_withprop(GoldfishDeviceInfo *info);
 int goldfish_add_device_no_io(GoldfishDevice *dev);
 void goldfish_device_init(DeviceState *dev, uint32_t base, uint32_t irq);
 void goldfish_device_set_irq(GoldfishDevice *dev, int irq, int level);
+void goldfish_battery_set_prop(void *opaque, int ac, int property, int
value);
+void goldfish_battery_display(void *opaque, void (* callback)(void *data,
const char* string), void *data);

 /** TEMP FILE SUPPORT
  **
diff --git a/hw/power_supply.h b/hw/power_supply.h
new file mode 100644
index 0000000..02733b8
--- /dev/null
+++ b/hw/power_supply.h
@@ -0,0 +1,109 @@ 
+/*
+ *  Universal power supply monitor class
+ *
+ *  Copyright © 2007  Anton Vorontsov <cbou@mail.ru>
+ *  Copyright © 2004  Szabolcs Gyurko
+ *  Copyright © 2003  Ian Molton <spyro@f2s.com>
+ *
+ *  Modified: 2004, Oct     Szabolcs Gyurko
+ *
+ *  You may use this code as per GPL version 2
+ */
+
+#ifndef __POWER_SUPPLY_H__
+#define __POWER_SUPPLY_H__
+
+/*
+ * All voltages, currents, charges, energies, time and temperatures in uV,
+ * µA, µAh, µWh, seconds and tenths of degree Celsius unless otherwise
+ * stated. It's driver's job to convert its raw values to units in which
+ * this class operates.
+ */
+
+/*
+ * For systems where the charger determines the maximum battery capacity
+ * the min and max fields should be used to present these values to user
+ * space. Unused/unknown fields will not appear in sysfs.
+ */
+
+enum {
+ POWER_SUPPLY_STATUS_UNKNOWN = 0,
+ POWER_SUPPLY_STATUS_CHARGING,
+ POWER_SUPPLY_STATUS_DISCHARGING,
+ POWER_SUPPLY_STATUS_NOT_CHARGING,
+ POWER_SUPPLY_STATUS_FULL,
+};
+
+enum {
+ POWER_SUPPLY_HEALTH_UNKNOWN = 0,
+ POWER_SUPPLY_HEALTH_GOOD,
+ POWER_SUPPLY_HEALTH_OVERHEAT,
+ POWER_SUPPLY_HEALTH_DEAD,
+ POWER_SUPPLY_HEALTH_OVERVOLTAGE,
+ POWER_SUPPLY_HEALTH_UNSPEC_FAILURE,
+};
+
+enum {
+ POWER_SUPPLY_TECHNOLOGY_UNKNOWN = 0,
+ POWER_SUPPLY_TECHNOLOGY_NiMH,
+ POWER_SUPPLY_TECHNOLOGY_LION,
+ POWER_SUPPLY_TECHNOLOGY_LIPO,
+ POWER_SUPPLY_TECHNOLOGY_LiFe,
+ POWER_SUPPLY_TECHNOLOGY_NiCd,
+};
+
+enum {
+ POWER_SUPPLY_CAPACITY_LEVEL_UNKNOWN = 0,
+ POWER_SUPPLY_CAPACITY_LEVEL_CRITICAL,
+ POWER_SUPPLY_CAPACITY_LEVEL_LOW,
+ POWER_SUPPLY_CAPACITY_LEVEL_NORMAL,
+ POWER_SUPPLY_CAPACITY_LEVEL_HIGH,
+ POWER_SUPPLY_CAPACITY_LEVEL_FULL,
+};
+
+enum power_supply_property {
+ /* Properties of type `int' */
+ POWER_SUPPLY_PROP_STATUS = 0,
+ POWER_SUPPLY_PROP_HEALTH,
+ POWER_SUPPLY_PROP_PRESENT,
+ POWER_SUPPLY_PROP_ONLINE,
+ POWER_SUPPLY_PROP_TECHNOLOGY,
+ POWER_SUPPLY_PROP_VOLTAGE_MAX_DESIGN,
+ POWER_SUPPLY_PROP_VOLTAGE_MIN_DESIGN,
+ POWER_SUPPLY_PROP_VOLTAGE_NOW,
+ POWER_SUPPLY_PROP_VOLTAGE_AVG,
+ POWER_SUPPLY_PROP_CURRENT_NOW,
+ POWER_SUPPLY_PROP_CURRENT_AVG,
+ POWER_SUPPLY_PROP_CHARGE_FULL_DESIGN,
+ POWER_SUPPLY_PROP_CHARGE_EMPTY_DESIGN,
+ POWER_SUPPLY_PROP_CHARGE_FULL,
+ POWER_SUPPLY_PROP_CHARGE_EMPTY,
+ POWER_SUPPLY_PROP_CHARGE_NOW,
+ POWER_SUPPLY_PROP_CHARGE_AVG,
+ POWER_SUPPLY_PROP_ENERGY_FULL_DESIGN,
+ POWER_SUPPLY_PROP_ENERGY_EMPTY_DESIGN,
+ POWER_SUPPLY_PROP_ENERGY_FULL,
+ POWER_SUPPLY_PROP_ENERGY_EMPTY,
+ POWER_SUPPLY_PROP_ENERGY_NOW,
+ POWER_SUPPLY_PROP_ENERGY_AVG,
+ POWER_SUPPLY_PROP_CAPACITY, /* in percents! */
+ POWER_SUPPLY_PROP_CAPACITY_LEVEL,
+ POWER_SUPPLY_PROP_TEMP,
+ POWER_SUPPLY_PROP_TEMP_AMBIENT,
+ POWER_SUPPLY_PROP_TIME_TO_EMPTY_NOW,
+ POWER_SUPPLY_PROP_TIME_TO_EMPTY_AVG,
+ POWER_SUPPLY_PROP_TIME_TO_FULL_NOW,
+ POWER_SUPPLY_PROP_TIME_TO_FULL_AVG,
+ /* Properties of type `const char *' */
+ POWER_SUPPLY_PROP_MODEL_NAME,
+ POWER_SUPPLY_PROP_MANUFACTURER,
+};
+
+enum power_supply_type {
+ POWER_SUPPLY_TYPE_BATTERY = 0,
+ POWER_SUPPLY_TYPE_UPS,
+ POWER_SUPPLY_TYPE_MAINS,
+ POWER_SUPPLY_TYPE_USB,
+};
+
+#endif /* __POWER_SUPPLY_H__ */