Home | History | Annotate | Download | only in hw
      1 /* Copyright (C) 2007-2008 The Android Open Source Project
      2 **
      3 ** This software is licensed under the terms of the GNU General Public
      4 ** License version 2, as published by the Free Software Foundation, and
      5 ** may be copied, distributed, and modified under those terms.
      6 **
      7 ** This program is distributed in the hope that it will be useful,
      8 ** but WITHOUT ANY WARRANTY; without even the implied warranty of
      9 ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
     10 ** GNU General Public License for more details.
     11 */
     12 #include "qemu_file.h"
     13 #include "goldfish_device.h"
     14 #include "power_supply.h"
     15 
     16 
     17 enum {
     18 	/* status register */
     19 	BATTERY_INT_STATUS	    = 0x00,
     20 	/* set this to enable IRQ */
     21 	BATTERY_INT_ENABLE	    = 0x04,
     22 
     23 	BATTERY_AC_ONLINE       = 0x08,
     24 	BATTERY_STATUS          = 0x0C,
     25 	BATTERY_HEALTH          = 0x10,
     26 	BATTERY_PRESENT         = 0x14,
     27 	BATTERY_CAPACITY        = 0x18,
     28 
     29 	BATTERY_STATUS_CHANGED	= 1U << 0,
     30 	AC_STATUS_CHANGED   	= 1U << 1,
     31 	BATTERY_INT_MASK        = BATTERY_STATUS_CHANGED | AC_STATUS_CHANGED,
     32 };
     33 
     34 
     35 struct goldfish_battery_state {
     36     struct goldfish_device dev;
     37     // IRQs
     38     uint32_t int_status;
     39     // irq enable mask for int_status
     40     uint32_t int_enable;
     41 
     42     int ac_online;
     43     int status;
     44     int health;
     45     int present;
     46     int capacity;
     47 };
     48 
     49 /* update this each time you update the battery_state struct */
     50 #define  BATTERY_STATE_SAVE_VERSION  1
     51 
     52 #define  QFIELD_STRUCT  struct goldfish_battery_state
     53 QFIELD_BEGIN(goldfish_battery_fields)
     54     QFIELD_INT32(int_status),
     55     QFIELD_INT32(int_enable),
     56     QFIELD_INT32(ac_online),
     57     QFIELD_INT32(status),
     58     QFIELD_INT32(health),
     59     QFIELD_INT32(present),
     60     QFIELD_INT32(capacity),
     61 QFIELD_END
     62 
     63 static void  goldfish_battery_save(QEMUFile*  f, void* opaque)
     64 {
     65     struct goldfish_battery_state*  s = opaque;
     66 
     67     qemu_put_struct(f, goldfish_battery_fields, s);
     68 }
     69 
     70 static int   goldfish_battery_load(QEMUFile*  f, void*  opaque, int  version_id)
     71 {
     72     struct goldfish_battery_state*  s = opaque;
     73 
     74     if (version_id != BATTERY_STATE_SAVE_VERSION)
     75         return -1;
     76 
     77     return qemu_get_struct(f, goldfish_battery_fields, s);
     78 }
     79 
     80 static struct goldfish_battery_state *battery_state;
     81 
     82 static uint32_t goldfish_battery_read(void *opaque, target_phys_addr_t offset)
     83 {
     84     uint32_t ret;
     85     struct goldfish_battery_state *s = opaque;
     86 
     87     switch(offset) {
     88         case BATTERY_INT_STATUS:
     89             // return current buffer status flags
     90             ret = s->int_status & s->int_enable;
     91             if (ret) {
     92                 goldfish_device_set_irq(&s->dev, 0, 0);
     93                 s->int_status = 0;
     94             }
     95             return ret;
     96 
     97 		case BATTERY_INT_ENABLE:
     98 		    return s->int_enable;
     99 		case BATTERY_AC_ONLINE:
    100 		    return s->ac_online;
    101 		case BATTERY_STATUS:
    102 		    return s->status;
    103 		case BATTERY_HEALTH:
    104 		    return s->health;
    105 		case BATTERY_PRESENT:
    106 		    return s->present;
    107 		case BATTERY_CAPACITY:
    108 		    return s->capacity;
    109 
    110         default:
    111             cpu_abort (cpu_single_env, "goldfish_battery_read: Bad offset %x\n", offset);
    112             return 0;
    113     }
    114 }
    115 
    116 static void goldfish_battery_write(void *opaque, target_phys_addr_t offset, uint32_t val)
    117 {
    118     struct goldfish_battery_state *s = opaque;
    119 
    120     switch(offset) {
    121         case BATTERY_INT_ENABLE:
    122             /* enable interrupts */
    123             s->int_enable = val;
    124 //            s->int_status = (AUDIO_INT_WRITE_BUFFER_1_EMPTY | AUDIO_INT_WRITE_BUFFER_2_EMPTY);
    125 //            goldfish_device_set_irq(&s->dev, 0, (s->int_status & s->int_enable));
    126             break;
    127 
    128         default:
    129             cpu_abort (cpu_single_env, "goldfish_audio_write: Bad offset %x\n", offset);
    130     }
    131 }
    132 
    133 static CPUReadMemoryFunc *goldfish_battery_readfn[] = {
    134     goldfish_battery_read,
    135     goldfish_battery_read,
    136     goldfish_battery_read
    137 };
    138 
    139 
    140 static CPUWriteMemoryFunc *goldfish_battery_writefn[] = {
    141     goldfish_battery_write,
    142     goldfish_battery_write,
    143     goldfish_battery_write
    144 };
    145 
    146 void goldfish_battery_init()
    147 {
    148     struct goldfish_battery_state *s;
    149 
    150     s = (struct goldfish_battery_state *)qemu_mallocz(sizeof(*s));
    151     s->dev.name = "goldfish-battery";
    152     s->dev.base = 0;    // will be allocated dynamically
    153     s->dev.size = 0x1000;
    154     s->dev.irq_count = 1;
    155 
    156     // default values for the battery
    157     s->ac_online = 1;
    158     s->status = POWER_SUPPLY_STATUS_CHARGING;
    159     s->health = POWER_SUPPLY_HEALTH_GOOD;
    160     s->present = 1;     // battery is present
    161     s->capacity = 50;   // 50% charged
    162 
    163     battery_state = s;
    164 
    165     goldfish_device_add(&s->dev, goldfish_battery_readfn, goldfish_battery_writefn, s);
    166 
    167     register_savevm( "battery_state", 0, BATTERY_STATE_SAVE_VERSION,
    168                      goldfish_battery_save, goldfish_battery_load, s);
    169 }
    170 
    171 void goldfish_battery_set_prop(int ac, int property, int value)
    172 {
    173     int new_status = (ac ? AC_STATUS_CHANGED : BATTERY_STATUS_CHANGED);
    174 
    175     if (ac) {
    176         switch (property) {
    177             case POWER_SUPPLY_PROP_ONLINE:
    178                 battery_state->ac_online = value;
    179                 break;
    180         }
    181     } else {
    182          switch (property) {
    183             case POWER_SUPPLY_PROP_STATUS:
    184                 battery_state->status = value;
    185                 break;
    186             case POWER_SUPPLY_PROP_HEALTH:
    187                 battery_state->health = value;
    188                 break;
    189             case POWER_SUPPLY_PROP_PRESENT:
    190                 battery_state->present = value;
    191                 break;
    192             case POWER_SUPPLY_PROP_CAPACITY:
    193                 battery_state->capacity = value;
    194                 break;
    195         }
    196     }
    197 
    198     if (new_status != battery_state->int_status) {
    199         battery_state->int_status |= new_status;
    200         goldfish_device_set_irq(&battery_state->dev, 0, (battery_state->int_status & battery_state->int_enable));
    201     }
    202 }
    203 
    204 void goldfish_battery_display(void (* callback)(void *data, const char* string), void *data)
    205 {
    206     char          buffer[100];
    207     const char*   value;
    208 
    209     sprintf(buffer, "AC: %s\r\n", (battery_state->ac_online ? "online" : "offline"));
    210     callback(data, buffer);
    211 
    212     switch (battery_state->status) {
    213 	    case POWER_SUPPLY_STATUS_CHARGING:
    214 	        value = "Charging";
    215 	        break;
    216 	    case POWER_SUPPLY_STATUS_DISCHARGING:
    217 	        value = "Discharging";
    218 	        break;
    219 	    case POWER_SUPPLY_STATUS_NOT_CHARGING:
    220 	        value = "Not charging";
    221 	        break;
    222 	    case POWER_SUPPLY_STATUS_FULL:
    223 	        value = "Full";
    224 	        break;
    225         default:
    226 	        value = "Unknown";
    227 	        break;
    228     }
    229     sprintf(buffer, "status: %s\r\n", value);
    230     callback(data, buffer);
    231 
    232     switch (battery_state->health) {
    233 	    case POWER_SUPPLY_HEALTH_GOOD:
    234 	        value = "Good";
    235 	        break;
    236 	    case POWER_SUPPLY_HEALTH_OVERHEAT:
    237 	        value = "Overhead";
    238 	        break;
    239 	    case POWER_SUPPLY_HEALTH_DEAD:
    240 	        value = "Dead";
    241 	        break;
    242 	    case POWER_SUPPLY_HEALTH_OVERVOLTAGE:
    243 	        value = "Overvoltage";
    244 	        break;
    245 	    case POWER_SUPPLY_HEALTH_UNSPEC_FAILURE:
    246 	        value = "Unspecified failure";
    247 	        break;
    248         default:
    249 	        value = "Unknown";
    250 	        break;
    251     }
    252     sprintf(buffer, "health: %s\r\n", value);
    253     callback(data, buffer);
    254 
    255     sprintf(buffer, "present: %s\r\n", (battery_state->present ? "true" : "false"));
    256     callback(data, buffer);
    257 
    258     sprintf(buffer, "capacity: %d\r\n", battery_state->capacity);
    259     callback(data, buffer);
    260 }
    261