blob: 03847d6ab4995c382c04e2d0f0551dc863a22ea5 [file] [log] [blame]
/* Copyright (C) 2007-2013 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 "hw/hw.h"
#include "hw/sysbus.h"
#include "qemu/error-report.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,
};
const uint32_t POWER_SUPPLY_STATUS_CHARGING = 1;
const uint32_t POWER_SUPPLY_HEALTH_GOOD = 1;
#define TYPE_GOLDFISH_BATTERY "goldfish_battery"
#define GOLDFISH_BATTERY(obj) OBJECT_CHECK(struct goldfish_battery_state, (obj), TYPE_GOLDFISH_BATTERY)
struct goldfish_battery_state {
SysBusDevice parent;
MemoryRegion iomem;
qemu_irq irq;
// IRQs
uint32_t int_status;
// irq enable mask for int_status
uint32_t int_enable;
uint32_t ac_online;
uint32_t status;
uint32_t health;
uint32_t present;
uint32_t capacity;
};
/* update this each time you update the battery_state struct */
#define BATTERY_STATE_SAVE_VERSION 1
static const VMStateDescription goldfish_battery_vmsd = {
.name = "goldfish_battery",
.version_id = BATTERY_STATE_SAVE_VERSION,
.minimum_version_id = BATTERY_STATE_SAVE_VERSION,
.minimum_version_id_old = BATTERY_STATE_SAVE_VERSION,
.fields = (VMStateField[]) {
VMSTATE_UINT32(int_status, struct goldfish_battery_state),
VMSTATE_UINT32(int_enable, struct goldfish_battery_state),
VMSTATE_UINT32(ac_online, struct goldfish_battery_state),
VMSTATE_UINT32(status, struct goldfish_battery_state),
VMSTATE_UINT32(health, struct goldfish_battery_state),
VMSTATE_UINT32(present, struct goldfish_battery_state),
VMSTATE_UINT32(capacity, struct goldfish_battery_state),
VMSTATE_END_OF_LIST()
}
};
static uint64_t goldfish_battery_read(void *opaque, hwaddr offset, unsigned size)
{
uint64_t ret;
struct goldfish_battery_state *s = opaque;
switch(offset) {
case BATTERY_INT_STATUS:
// return current buffer status flags
ret = s->int_status & s->int_enable;
if (ret) {
qemu_irq_lower(s->irq);
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:
error_report ("goldfish_battery_read: Bad offset " TARGET_FMT_plx,
offset);
return 0;
}
}
static void goldfish_battery_write(void *opaque, hwaddr offset, uint64_t val,
unsigned size)
{
struct goldfish_battery_state *s = opaque;
switch(offset) {
case BATTERY_INT_ENABLE:
/* enable interrupts */
s->int_enable = val;
break;
default:
error_report ("goldfish_audio_write: Bad offset " TARGET_FMT_plx,
offset);
}
}
static const MemoryRegionOps goldfish_battery_iomem_ops = {
.read = goldfish_battery_read,
.write = goldfish_battery_write,
.endianness = DEVICE_NATIVE_ENDIAN,
.impl.min_access_size = 4,
.impl.max_access_size = 4,
};
static void goldfish_battery_realize(DeviceState *dev, Error **errp)
{
SysBusDevice *sbdev = SYS_BUS_DEVICE(dev);
struct goldfish_battery_state *s = GOLDFISH_BATTERY(dev);
memory_region_init_io(&s->iomem, OBJECT(s), &goldfish_battery_iomem_ops, s,
"goldfish_battery", 0x1000);
sysbus_init_mmio(sbdev, &s->iomem);
sysbus_init_irq(sbdev, &s->irq);
// default values for the battery
s->ac_online = 1;
s->status = POWER_SUPPLY_STATUS_CHARGING;
s->health = POWER_SUPPLY_HEALTH_GOOD;
s->present = 1; // battery is present
s->capacity = 50; // 50% charged
}
static void goldfish_battery_class_init(ObjectClass *klass, void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
dc->realize = goldfish_battery_realize;
dc->vmsd = &goldfish_battery_vmsd;
dc->desc = "goldfish battery";
}
static const TypeInfo goldfish_audio_info = {
.name = TYPE_GOLDFISH_BATTERY,
.parent = TYPE_SYS_BUS_DEVICE,
.instance_size = sizeof(struct goldfish_battery_state),
.class_init = goldfish_battery_class_init,
};
static void goldfish_audio_register(void)
{
type_register_static(&goldfish_audio_info);
}
type_init(goldfish_audio_register);