Signed-off-by: Patrick Jackson --- 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 --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 + * Copyright © 2004 Szabolcs Gyurko + * Copyright © 2003 Ian Molton + * + * 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__ */ -- 1.7.4.1