Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(21)

Side by Side Diff: drivers/power/qci_battery.c

Issue 2850001: add battery driver in st1.5 (Closed) Base URL: ssh://gitrw.chromium.org/kernel.git
Patch Set: Created 10 years, 6 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « drivers/power/qci_battery.h ('k') | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(Empty)
1 /* Quanta I2C Battery Driver
2 *
3 * Copyright (C) 2009 Quanta Computer Inc.
4 *
5 * This software is licensed under the terms of the GNU General Public
6 * License version 2, as published by the Free Software Foundation, and
7 * may be copied, distributed, and modified under those terms.
8 *
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13 *
14 */
15
16 /*
17 *
18 * The Driver with I/O communications via the I2C Interface for ST15 platform.
19 * And it is only working on the nuvoTon WPCE775x Embedded Controller.
20 *
21 */
22
23 #include <linux/module.h>
24 #include <linux/err.h>
25 #include <linux/platform_device.h>
26 #include <linux/power_supply.h>
27 #include <linux/sched.h>
28 #include <linux/gpio.h>
29 #include <linux/i2c.h>
30 #include <linux/wpce775x.h>
31
32 #include "qci_battery.h"
33
34 struct qci_bat_info {
35 u8 type_id;
36 u8 power_flag;
37 u8 ec_ver_lsb;
38 u8 ec_ver_msb;
39 u8 mbat_rsoc;
40 u8 mbat_volt_lsb;
41 u8 mbat_volt_msb;
42 u8 mbat_status;
43 u8 mbchg_status;
44 u8 mbat_temp_lsb;
45 u8 mbat_temp_msb;
46 };
47
48 /* General structure to hold the driver data */
49 struct i2cbat_drv_data {
50 struct i2c_client *bi2c_client;
51 struct work_struct work;
52 char batt_data[I2C_BAT_BUFFER_LEN+1];
53 unsigned int qcibat_irq;
54 unsigned int qcibat_gpio;
55 struct qci_bat_info bif;
56 };
57
58 static struct i2cbat_drv_data context;
59 /*********************************************************************
60 * Power
61 *********************************************************************/
62
63 static int qci_ac_get_prop(struct power_supply *psy,
64 enum power_supply_property psp,
65 union power_supply_propval *val)
66 {
67 int ret = 0;
68 switch (psp) {
69 case POWER_SUPPLY_PROP_ONLINE:
70 if (context.bif.power_flag & EC_FLAG_ADAPTER_IN)
71 val->intval = EC_ADAPTER_PRESENT;
72 else
73 val->intval = EC_ADAPTER_NOT_PRESENT;
74 break;
75 default:
76 ret = -EINVAL;
77 break;
78 }
79 return ret;
80 }
81
82 static enum power_supply_property qci_ac_props[] = {
83 POWER_SUPPLY_PROP_ONLINE,
84 };
85
86 static enum power_supply_property qci_bat_props[] = {
87 POWER_SUPPLY_PROP_STATUS,
88 POWER_SUPPLY_PROP_PRESENT,
89 POWER_SUPPLY_PROP_HEALTH,
90 POWER_SUPPLY_PROP_TECHNOLOGY,
91 POWER_SUPPLY_PROP_VOLTAGE_AVG,
92 POWER_SUPPLY_PROP_CURRENT_AVG,
93 POWER_SUPPLY_PROP_CAPACITY,
94 POWER_SUPPLY_PROP_TEMP,
95 POWER_SUPPLY_PROP_TEMP_AMBIENT,
96 POWER_SUPPLY_PROP_MANUFACTURER,
97 POWER_SUPPLY_PROP_SERIAL_NUMBER,
98 POWER_SUPPLY_PROP_CHARGE_COUNTER,
99 };
100
101 static int qbat_get_status(union power_supply_propval *val)
102 {
103 if ((context.bif.mbat_status & MAIN_BATTERY_STATUS_BAT_IN) == 0x0)
104 val->intval = POWER_SUPPLY_STATUS_UNKNOWN;
105 else if (context.bif.mbchg_status & CHG_STATUS_BAT_INCHARGE)
106 val->intval = POWER_SUPPLY_STATUS_CHARGING;
107 else if (context.bif.mbat_status & MAIN_BATTERY_STATUS_BAT_FULL)
108 val->intval = POWER_SUPPLY_STATUS_FULL;
109 else
110 val->intval = POWER_SUPPLY_STATUS_DISCHARGING;
111
112 return 0;
113 }
114
115 static int qbat_get_present(union power_supply_propval *val)
116 {
117 if (context.bif.mbat_status & MAIN_BATTERY_STATUS_BAT_IN)
118 val->intval = EC_BAT_PRESENT;
119 else
120 val->intval = EC_BAT_NOT_PRESENT;
121 return 0;
122 }
123
124 static int qbat_get_health(union power_supply_propval *val)
125 {
126 if ((context.bif.mbat_status & MAIN_BATTERY_STATUS_BAT_IN) == 0x0)
127 val->intval = POWER_SUPPLY_HEALTH_UNKNOWN;
128 else
129 val->intval = POWER_SUPPLY_HEALTH_GOOD;
130 return 0;
131 }
132
133 static int qbat_get_voltage_avg(union power_supply_propval *val)
134 {
135 val->intval = (context.bif.mbat_volt_msb << 8 |
136 context.bif.mbat_volt_lsb);
137 return 0;
138 }
139
140 static int qbat_get_capacity(union power_supply_propval *val)
141 {
142 if ((context.bif.mbat_status & MAIN_BATTERY_STATUS_BAT_IN) == 0x0)
143 val->intval = 0xFF;
144 else
145 val->intval = context.bif.mbat_rsoc;
146 return 0;
147 }
148
149 static int qbat_get_temp_avg(union power_supply_propval *val)
150 {
151 if ((context.bif.mbat_status & MAIN_BATTERY_STATUS_BAT_IN) == 0x0)
152 val->intval = 0xFFFF;
153 else
154 val->intval = ((context.bif.mbat_temp_msb << 8) |
155 context.bif.mbat_temp_lsb) - 2731;
156 return 0;
157 }
158
159 static int qbat_get_mfr(union power_supply_propval *val)
160 {
161 val->strval = "Unknown";
162 return 0;
163 }
164
165 static int qbat_get_tech(union power_supply_propval *val)
166 {
167 if ((context.bif.mbat_status & MAIN_BATTERY_STATUS_BAT_IN) == 0x0)
168 val->intval = POWER_SUPPLY_TECHNOLOGY_UNKNOWN;
169 else
170 val->intval = POWER_SUPPLY_TECHNOLOGY_LION;
171 return 0;
172 }
173
174 /*********************************************************************
175 * Battery properties
176 *********************************************************************/
177 static int qbat_get_property(struct power_supply *psy,
178 enum power_supply_property psp,
179 union power_supply_propval *val)
180 {
181 int ret = 0;
182 switch (psp) {
183 case POWER_SUPPLY_PROP_STATUS:
184 ret = qbat_get_status(val);
185 break;
186 case POWER_SUPPLY_PROP_PRESENT:
187 ret = qbat_get_present(val);
188 break;
189 case POWER_SUPPLY_PROP_HEALTH:
190 ret = qbat_get_health(val);
191 break;
192 case POWER_SUPPLY_PROP_MANUFACTURER:
193 ret = qbat_get_mfr(val);
194 break;
195 case POWER_SUPPLY_PROP_TECHNOLOGY:
196 ret = qbat_get_tech(val);
197 break;
198 case POWER_SUPPLY_PROP_VOLTAGE_AVG:
199 ret = qbat_get_voltage_avg(val);
200 break;
201 case POWER_SUPPLY_PROP_CURRENT_AVG:
202 break;
203 case POWER_SUPPLY_PROP_CAPACITY:
204 ret = qbat_get_capacity(val);
205 break;
206 case POWER_SUPPLY_PROP_TEMP:
207 ret = qbat_get_temp_avg(val);
208 break;
209 case POWER_SUPPLY_PROP_TEMP_AMBIENT:
210 ret = qbat_get_temp_avg(val);
211 break;
212 case POWER_SUPPLY_PROP_CHARGE_COUNTER:
213 break;
214 case POWER_SUPPLY_PROP_SERIAL_NUMBER:
215 break;
216 default:
217 ret = -EINVAL;
218 break;
219 }
220
221 return ret;
222 }
223
224 /*********************************************************************
225 * Initialisation
226 *********************************************************************/
227
228 static struct power_supply qci_ac = {
229 .name = "ac",
230 .type = POWER_SUPPLY_TYPE_MAINS,
231 .properties = qci_ac_props,
232 .num_properties = ARRAY_SIZE(qci_ac_props),
233 .get_property = qci_ac_get_prop,
234 };
235
236 static struct power_supply qci_bat = {
237 .name = "battery",
238 .type = POWER_SUPPLY_TYPE_BATTERY,
239 .properties = qci_bat_props,
240 .num_properties = ARRAY_SIZE(qci_bat_props),
241 .get_property = qbat_get_property,
242 .use_for_apm = 1,
243 };
244
245 static irqreturn_t qbat_interrupt(int irq, void *dev_id)
246 {
247 struct i2cbat_drv_data *ibat_drv_data = dev_id;
248 schedule_work(&ibat_drv_data->work);
249 return IRQ_HANDLED;
250 }
251
252 static int qci_get_bat_info(struct i2c_client *client, char *ec_data)
253 {
254 struct i2c_msg bat_msg;
255 bat_msg.addr = client->addr;
256 bat_msg.flags = I2C_M_RD;
257 bat_msg.len = I2C_BAT_BUFFER_LEN;
258 bat_msg.buf = ec_data;
259 return i2c_transfer(client->adapter, &bat_msg, 1);
260 }
261
262 static void qbat_work(struct work_struct *_work)
263 {
264 struct i2cbat_drv_data *ibat_drv_data =
265 container_of(_work, struct i2cbat_drv_data, work);
266 struct i2c_client *ibatclient = ibat_drv_data->bi2c_client;
267
268 qci_get_bat_info(ibatclient, ibat_drv_data->batt_data);
269 memcpy(&context.bif,
270 ibat_drv_data->batt_data,
271 sizeof(struct qci_bat_info));
272 power_supply_changed(&qci_ac);
273 power_supply_changed(&qci_bat);
274 }
275
276 static struct platform_device *bat_pdev;
277
278 static int __init qbat_init(void)
279 {
280 int err = 0;
281
282 context.bi2c_client = wpce_get_i2c_client();
283 if (context.bi2c_client == NULL)
284 return -1;
285
286 i2c_set_clientdata(context.bi2c_client, &context);
287 context.qcibat_gpio = context.bi2c_client->irq;
288
289 /*battery device register*/
290 bat_pdev = platform_device_register_simple("battery", 0, NULL, 0);
291 if (IS_ERR(bat_pdev))
292 return PTR_ERR(bat_pdev);
293
294 err = power_supply_register(&bat_pdev->dev, &qci_ac);
295 if (err)
296 goto ac_failed;
297
298 qci_bat.name = bat_pdev->name;
299 err = power_supply_register(&bat_pdev->dev, &qci_bat);
300 if (err)
301 goto battery_failed;
302
303 /*battery irq configure*/
304 INIT_WORK(&context.work, qbat_work);
305 err = gpio_request(context.qcibat_gpio, "qci-bat");
306 if (err) {
307 dev_err(&context.bi2c_client->dev,
308 "[BAT] err gpio request\n");
309 goto gpio_request_fail;
310 }
311 context.qcibat_irq = gpio_to_irq(context.qcibat_gpio);
312 err = request_irq(context.qcibat_irq, qbat_interrupt,
313 IRQF_TRIGGER_FALLING, BATTERY_ID_NAME, &context);
314 if (err) {
315 dev_err(&context.bi2c_client->dev,
316 "[BAT] unable to get IRQ\n");
317 goto request_irq_fail;
318 }
319 err = qci_get_bat_info(context.bi2c_client, context.batt_data);
320
321 goto success;
322
323 request_irq_fail:
324 gpio_free(context.qcibat_gpio);
325
326 gpio_request_fail:
327 power_supply_unregister(&qci_bat);
328
329 battery_failed:
330 power_supply_unregister(&qci_ac);
331
332 ac_failed:
333 platform_device_unregister(bat_pdev);
334
335 i2c_set_clientdata(context.bi2c_client, NULL);
336 success:
337 return err;
338 }
339
340 static void __exit qbat_exit(void)
341 {
342 free_irq(context.qcibat_irq, &context);
343 gpio_free(context.qcibat_gpio);
344 power_supply_unregister(&qci_bat);
345 power_supply_unregister(&qci_ac);
346 platform_device_unregister(bat_pdev);
347 i2c_set_clientdata(context.bi2c_client, NULL);
348 }
349
350 late_initcall(qbat_init);
351 module_exit(qbat_exit);
352
353 MODULE_AUTHOR("Quanta Computer Inc.");
354 MODULE_DESCRIPTION("Quanta Embedded Controller I2C Battery Driver");
355 MODULE_LICENSE("GPL v2");
356
OLDNEW
« no previous file with comments | « drivers/power/qci_battery.h ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698