linux/drivers/power/pmu_battery.c
<<
>>
Prefs
   1/*
   2 * Battery class driver for Apple PMU
   3 *
   4 *      Copyright © 2006  David Woodhouse <dwmw2@infradead.org>
   5 *
   6 * This program is free software; you can redistribute it and/or modify
   7 * it under the terms of the GNU General Public License version 2 as
   8 * published by the Free Software Foundation.
   9 */
  10
  11#include <linux/module.h>
  12#include <linux/platform_device.h>
  13#include <linux/err.h>
  14#include <linux/power_supply.h>
  15#include <linux/adb.h>
  16#include <linux/pmu.h>
  17#include <linux/slab.h>
  18
  19static struct pmu_battery_dev {
  20        struct power_supply bat;
  21        struct pmu_battery_info *pbi;
  22        char name[16];
  23        int propval;
  24} *pbats[PMU_MAX_BATTERIES];
  25
  26#define to_pmu_battery_dev(x) container_of(x, struct pmu_battery_dev, bat)
  27
  28/*********************************************************************
  29 *              Power
  30 *********************************************************************/
  31
  32static int pmu_get_ac_prop(struct power_supply *psy,
  33                           enum power_supply_property psp,
  34                           union power_supply_propval *val)
  35{
  36        switch (psp) {
  37        case POWER_SUPPLY_PROP_ONLINE:
  38                val->intval = (!!(pmu_power_flags & PMU_PWR_AC_PRESENT)) ||
  39                              (pmu_battery_count == 0);
  40                break;
  41        default:
  42                return -EINVAL;
  43        }
  44
  45        return 0;
  46}
  47
  48static enum power_supply_property pmu_ac_props[] = {
  49        POWER_SUPPLY_PROP_ONLINE,
  50};
  51
  52static struct power_supply pmu_ac = {
  53        .name = "pmu-ac",
  54        .type = POWER_SUPPLY_TYPE_MAINS,
  55        .properties = pmu_ac_props,
  56        .num_properties = ARRAY_SIZE(pmu_ac_props),
  57        .get_property = pmu_get_ac_prop,
  58};
  59
  60/*********************************************************************
  61 *              Battery properties
  62 *********************************************************************/
  63
  64static char *pmu_batt_types[] = {
  65        "Smart", "Comet", "Hooper", "Unknown"
  66};
  67
  68static char *pmu_bat_get_model_name(struct pmu_battery_info *pbi)
  69{
  70        switch (pbi->flags & PMU_BATT_TYPE_MASK) {
  71        case PMU_BATT_TYPE_SMART:
  72                return pmu_batt_types[0];
  73        case PMU_BATT_TYPE_COMET:
  74                return pmu_batt_types[1];
  75        case PMU_BATT_TYPE_HOOPER:
  76                return pmu_batt_types[2];
  77        default: break;
  78        }
  79        return pmu_batt_types[3];
  80}
  81
  82static int pmu_bat_get_property(struct power_supply *psy,
  83                                enum power_supply_property psp,
  84                                union power_supply_propval *val)
  85{
  86        struct pmu_battery_dev *pbat = to_pmu_battery_dev(psy);
  87        struct pmu_battery_info *pbi = pbat->pbi;
  88
  89        switch (psp) {
  90        case POWER_SUPPLY_PROP_STATUS:
  91                if (pbi->flags & PMU_BATT_CHARGING)
  92                        val->intval = POWER_SUPPLY_STATUS_CHARGING;
  93                else if (pmu_power_flags & PMU_PWR_AC_PRESENT)
  94                        val->intval = POWER_SUPPLY_STATUS_FULL;
  95                else
  96                        val->intval = POWER_SUPPLY_STATUS_DISCHARGING;
  97                break;
  98        case POWER_SUPPLY_PROP_PRESENT:
  99                val->intval = !!(pbi->flags & PMU_BATT_PRESENT);
 100                break;
 101        case POWER_SUPPLY_PROP_MODEL_NAME:
 102                val->strval = pmu_bat_get_model_name(pbi);
 103                break;
 104        case POWER_SUPPLY_PROP_ENERGY_AVG:
 105                val->intval = pbi->charge     * 1000; /* mWh -> µWh */
 106                break;
 107        case POWER_SUPPLY_PROP_ENERGY_FULL:
 108                val->intval = pbi->max_charge * 1000; /* mWh -> µWh */
 109                break;
 110        case POWER_SUPPLY_PROP_CURRENT_AVG:
 111                val->intval = pbi->amperage   * 1000; /* mA -> µA */
 112                break;
 113        case POWER_SUPPLY_PROP_VOLTAGE_AVG:
 114                val->intval = pbi->voltage    * 1000; /* mV -> µV */
 115                break;
 116        case POWER_SUPPLY_PROP_TIME_TO_EMPTY_AVG:
 117                val->intval = pbi->time_remaining;
 118                break;
 119        default:
 120                return -EINVAL;
 121        }
 122
 123        return 0;
 124}
 125
 126static enum power_supply_property pmu_bat_props[] = {
 127        POWER_SUPPLY_PROP_STATUS,
 128        POWER_SUPPLY_PROP_PRESENT,
 129        POWER_SUPPLY_PROP_MODEL_NAME,
 130        POWER_SUPPLY_PROP_ENERGY_AVG,
 131        POWER_SUPPLY_PROP_ENERGY_FULL,
 132        POWER_SUPPLY_PROP_CURRENT_AVG,
 133        POWER_SUPPLY_PROP_VOLTAGE_AVG,
 134        POWER_SUPPLY_PROP_TIME_TO_EMPTY_AVG,
 135};
 136
 137/*********************************************************************
 138 *              Initialisation
 139 *********************************************************************/
 140
 141static struct platform_device *bat_pdev;
 142
 143static int __init pmu_bat_init(void)
 144{
 145        int ret;
 146        int i;
 147
 148        bat_pdev = platform_device_register_simple("pmu-battery",
 149                                                   0, NULL, 0);
 150        if (IS_ERR(bat_pdev)) {
 151                ret = PTR_ERR(bat_pdev);
 152                goto pdev_register_failed;
 153        }
 154
 155        ret = power_supply_register(&bat_pdev->dev, &pmu_ac);
 156        if (ret)
 157                goto ac_register_failed;
 158
 159        for (i = 0; i < pmu_battery_count; i++) {
 160                struct pmu_battery_dev *pbat = kzalloc(sizeof(*pbat),
 161                                                       GFP_KERNEL);
 162                if (!pbat)
 163                        break;
 164
 165                sprintf(pbat->name, "PMU_battery_%d", i);
 166                pbat->bat.name = pbat->name;
 167                pbat->bat.properties = pmu_bat_props;
 168                pbat->bat.num_properties = ARRAY_SIZE(pmu_bat_props);
 169                pbat->bat.get_property = pmu_bat_get_property;
 170                pbat->pbi = &pmu_batteries[i];
 171
 172                ret = power_supply_register(&bat_pdev->dev, &pbat->bat);
 173                if (ret) {
 174                        kfree(pbat);
 175                        goto battery_register_failed;
 176                }
 177                pbats[i] = pbat;
 178        }
 179
 180        goto success;
 181
 182battery_register_failed:
 183        while (i--) {
 184                if (!pbats[i])
 185                        continue;
 186                power_supply_unregister(&pbats[i]->bat);
 187                kfree(pbats[i]);
 188        }
 189        power_supply_unregister(&pmu_ac);
 190ac_register_failed:
 191        platform_device_unregister(bat_pdev);
 192pdev_register_failed:
 193success:
 194        return ret;
 195}
 196
 197static void __exit pmu_bat_exit(void)
 198{
 199        int i;
 200
 201        for (i = 0; i < PMU_MAX_BATTERIES; i++) {
 202                if (!pbats[i])
 203                        continue;
 204                power_supply_unregister(&pbats[i]->bat);
 205                kfree(pbats[i]);
 206        }
 207        power_supply_unregister(&pmu_ac);
 208        platform_device_unregister(bat_pdev);
 209}
 210
 211module_init(pmu_bat_init);
 212module_exit(pmu_bat_exit);
 213
 214MODULE_AUTHOR("David Woodhouse <dwmw2@infradead.org>");
 215MODULE_LICENSE("GPL");
 216MODULE_DESCRIPTION("PMU battery driver");
 217
lxr.linux.no kindly hosted by Redpill Linpro AS, provider of Linux consulting and operations services since 1995.