]> git.kernelconcepts.de Git - karo-tx-linux.git/blob - drivers/power/pmu_battery.c
Merge branch 'timers-urgent-for-linus' of git://git.kernel.org/pub/scm/linux/kernel...
[karo-tx-linux.git] / drivers / power / pmu_battery.c
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
19 static struct pmu_battery_dev {
20         struct power_supply *bat;
21         struct power_supply_desc bat_desc;
22         struct pmu_battery_info *pbi;
23         char name[16];
24         int propval;
25 } *pbats[PMU_MAX_BATTERIES];
26
27 #define to_pmu_battery_dev(x) power_supply_get_drvdata(x)
28
29 /*********************************************************************
30  *              Power
31  *********************************************************************/
32
33 static int pmu_get_ac_prop(struct power_supply *psy,
34                            enum power_supply_property psp,
35                            union power_supply_propval *val)
36 {
37         switch (psp) {
38         case POWER_SUPPLY_PROP_ONLINE:
39                 val->intval = (!!(pmu_power_flags & PMU_PWR_AC_PRESENT)) ||
40                               (pmu_battery_count == 0);
41                 break;
42         default:
43                 return -EINVAL;
44         }
45
46         return 0;
47 }
48
49 static enum power_supply_property pmu_ac_props[] = {
50         POWER_SUPPLY_PROP_ONLINE,
51 };
52
53 static const struct power_supply_desc pmu_ac_desc = {
54         .name = "pmu-ac",
55         .type = POWER_SUPPLY_TYPE_MAINS,
56         .properties = pmu_ac_props,
57         .num_properties = ARRAY_SIZE(pmu_ac_props),
58         .get_property = pmu_get_ac_prop,
59 };
60
61 static struct power_supply *pmu_ac;
62
63 /*********************************************************************
64  *              Battery properties
65  *********************************************************************/
66
67 static char *pmu_batt_types[] = {
68         "Smart", "Comet", "Hooper", "Unknown"
69 };
70
71 static char *pmu_bat_get_model_name(struct pmu_battery_info *pbi)
72 {
73         switch (pbi->flags & PMU_BATT_TYPE_MASK) {
74         case PMU_BATT_TYPE_SMART:
75                 return pmu_batt_types[0];
76         case PMU_BATT_TYPE_COMET:
77                 return pmu_batt_types[1];
78         case PMU_BATT_TYPE_HOOPER:
79                 return pmu_batt_types[2];
80         default: break;
81         }
82         return pmu_batt_types[3];
83 }
84
85 static int pmu_bat_get_property(struct power_supply *psy,
86                                 enum power_supply_property psp,
87                                 union power_supply_propval *val)
88 {
89         struct pmu_battery_dev *pbat = to_pmu_battery_dev(psy);
90         struct pmu_battery_info *pbi = pbat->pbi;
91
92         switch (psp) {
93         case POWER_SUPPLY_PROP_STATUS:
94                 if (pbi->flags & PMU_BATT_CHARGING)
95                         val->intval = POWER_SUPPLY_STATUS_CHARGING;
96                 else if (pmu_power_flags & PMU_PWR_AC_PRESENT)
97                         val->intval = POWER_SUPPLY_STATUS_FULL;
98                 else
99                         val->intval = POWER_SUPPLY_STATUS_DISCHARGING;
100                 break;
101         case POWER_SUPPLY_PROP_PRESENT:
102                 val->intval = !!(pbi->flags & PMU_BATT_PRESENT);
103                 break;
104         case POWER_SUPPLY_PROP_MODEL_NAME:
105                 val->strval = pmu_bat_get_model_name(pbi);
106                 break;
107         case POWER_SUPPLY_PROP_ENERGY_AVG:
108                 val->intval = pbi->charge     * 1000; /* mWh -> µWh */
109                 break;
110         case POWER_SUPPLY_PROP_ENERGY_FULL:
111                 val->intval = pbi->max_charge * 1000; /* mWh -> µWh */
112                 break;
113         case POWER_SUPPLY_PROP_CURRENT_AVG:
114                 val->intval = pbi->amperage   * 1000; /* mA -> µA */
115                 break;
116         case POWER_SUPPLY_PROP_VOLTAGE_AVG:
117                 val->intval = pbi->voltage    * 1000; /* mV -> µV */
118                 break;
119         case POWER_SUPPLY_PROP_TIME_TO_EMPTY_AVG:
120                 val->intval = pbi->time_remaining;
121                 break;
122         default:
123                 return -EINVAL;
124         }
125
126         return 0;
127 }
128
129 static enum power_supply_property pmu_bat_props[] = {
130         POWER_SUPPLY_PROP_STATUS,
131         POWER_SUPPLY_PROP_PRESENT,
132         POWER_SUPPLY_PROP_MODEL_NAME,
133         POWER_SUPPLY_PROP_ENERGY_AVG,
134         POWER_SUPPLY_PROP_ENERGY_FULL,
135         POWER_SUPPLY_PROP_CURRENT_AVG,
136         POWER_SUPPLY_PROP_VOLTAGE_AVG,
137         POWER_SUPPLY_PROP_TIME_TO_EMPTY_AVG,
138 };
139
140 /*********************************************************************
141  *              Initialisation
142  *********************************************************************/
143
144 static struct platform_device *bat_pdev;
145
146 static int __init pmu_bat_init(void)
147 {
148         int ret = 0;
149         int i;
150
151         bat_pdev = platform_device_register_simple("pmu-battery",
152                                                    0, NULL, 0);
153         if (IS_ERR(bat_pdev)) {
154                 ret = PTR_ERR(bat_pdev);
155                 goto pdev_register_failed;
156         }
157
158         pmu_ac = power_supply_register(&bat_pdev->dev, &pmu_ac_desc, NULL);
159         if (IS_ERR(pmu_ac)) {
160                 ret = PTR_ERR(pmu_ac);
161                 goto ac_register_failed;
162         }
163
164         for (i = 0; i < pmu_battery_count; i++) {
165                 struct power_supply_config psy_cfg = {};
166                 struct pmu_battery_dev *pbat = kzalloc(sizeof(*pbat),
167                                                        GFP_KERNEL);
168                 if (!pbat)
169                         break;
170
171                 sprintf(pbat->name, "PMU_battery_%d", i);
172                 pbat->bat_desc.name = pbat->name;
173                 pbat->bat_desc.properties = pmu_bat_props;
174                 pbat->bat_desc.num_properties = ARRAY_SIZE(pmu_bat_props);
175                 pbat->bat_desc.get_property = pmu_bat_get_property;
176                 pbat->pbi = &pmu_batteries[i];
177                 psy_cfg.drv_data = pbat;
178
179                 pbat->bat = power_supply_register(&bat_pdev->dev,
180                                                   &pbat->bat_desc,
181                                                   &psy_cfg);
182                 if (IS_ERR(pbat->bat)) {
183                         ret = PTR_ERR(pbat->bat);
184                         kfree(pbat);
185                         goto battery_register_failed;
186                 }
187                 pbats[i] = pbat;
188         }
189
190         goto success;
191
192 battery_register_failed:
193         while (i--) {
194                 if (!pbats[i])
195                         continue;
196                 power_supply_unregister(pbats[i]->bat);
197                 kfree(pbats[i]);
198         }
199         power_supply_unregister(pmu_ac);
200 ac_register_failed:
201         platform_device_unregister(bat_pdev);
202 pdev_register_failed:
203 success:
204         return ret;
205 }
206
207 static void __exit pmu_bat_exit(void)
208 {
209         int i;
210
211         for (i = 0; i < PMU_MAX_BATTERIES; i++) {
212                 if (!pbats[i])
213                         continue;
214                 power_supply_unregister(pbats[i]->bat);
215                 kfree(pbats[i]);
216         }
217         power_supply_unregister(pmu_ac);
218         platform_device_unregister(bat_pdev);
219 }
220
221 module_init(pmu_bat_init);
222 module_exit(pmu_bat_exit);
223
224 MODULE_AUTHOR("David Woodhouse <dwmw2@infradead.org>");
225 MODULE_LICENSE("GPL");
226 MODULE_DESCRIPTION("PMU battery driver");