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