blob: 724bcba27ae1bab624fc2688d5e91f95bcc27df1 [file] [log] [blame]
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001/* 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#include <linux/delay.h>
32
33#include "qci_battery.h"
34
35#define QCIBAT_DEFAULT_CHARGE_FULL_CAPACITY 2200 /* 2200 mAh */
36#define QCIBAT_DEFAULT_CHARGE_FULL_DESIGN 2200
37#define QCIBAT_DEFAULT_VOLTAGE_DESIGN 10800 /* 10.8 V */
38#define QCIBAT_STRING_SIZE 16
39
40/* General structure to hold the driver data */
41struct i2cbat_drv_data {
42 struct i2c_client *bi2c_client;
43 struct work_struct work;
44 unsigned int qcibat_irq;
45 unsigned int qcibat_gpio;
46 u8 battery_state;
47 u8 battery_dev_name[QCIBAT_STRING_SIZE];
48 u8 serial_number[QCIBAT_STRING_SIZE];
49 u8 manufacturer_name[QCIBAT_STRING_SIZE];
50 unsigned int charge_full;
51 unsigned int charge_full_design;
52 unsigned int voltage_full_design;
53 unsigned int energy_full;
54};
55
56static struct i2cbat_drv_data context;
57static struct mutex qci_i2c_lock;
58static struct mutex qci_transaction_lock;
59/*********************************************************************
60 * Power
61 *********************************************************************/
62
63static int get_bat_info(u8 ec_data)
64{
65 u8 byte_read;
66
67 mutex_lock(&qci_i2c_lock);
68 i2c_smbus_write_byte(context.bi2c_client, ec_data);
69 byte_read = i2c_smbus_read_byte(context.bi2c_client);
70 mutex_unlock(&qci_i2c_lock);
71 return byte_read;
72}
73
74static int qci_ac_get_prop(struct power_supply *psy,
75 enum power_supply_property psp,
76 union power_supply_propval *val)
77{
78 int ret = 0;
79 switch (psp) {
80 case POWER_SUPPLY_PROP_ONLINE:
81 if (get_bat_info(ECRAM_POWER_SOURCE) & EC_FLAG_ADAPTER_IN)
82 val->intval = EC_ADAPTER_PRESENT;
83 else
84 val->intval = EC_ADAPTER_NOT_PRESENT;
85 break;
86 default:
87 ret = -EINVAL;
88 break;
89 }
90 return ret;
91}
92
93static enum power_supply_property qci_ac_props[] = {
94 POWER_SUPPLY_PROP_ONLINE,
95};
96
97static enum power_supply_property qci_bat_props[] = {
98 POWER_SUPPLY_PROP_STATUS,
99 POWER_SUPPLY_PROP_PRESENT,
100 POWER_SUPPLY_PROP_HEALTH,
101 POWER_SUPPLY_PROP_TECHNOLOGY,
102 POWER_SUPPLY_PROP_VOLTAGE_AVG,
103 POWER_SUPPLY_PROP_CURRENT_AVG,
104 POWER_SUPPLY_PROP_CAPACITY,
105 POWER_SUPPLY_PROP_TEMP,
106 POWER_SUPPLY_PROP_CHARGE_FULL_DESIGN,
107 POWER_SUPPLY_PROP_CHARGE_FULL,
108 POWER_SUPPLY_PROP_TIME_TO_EMPTY_AVG,
109 POWER_SUPPLY_PROP_TIME_TO_FULL_AVG,
110 POWER_SUPPLY_PROP_MODEL_NAME,
111 POWER_SUPPLY_PROP_MANUFACTURER,
112 POWER_SUPPLY_PROP_SERIAL_NUMBER,
113 POWER_SUPPLY_PROP_CHARGE_COUNTER,
114 POWER_SUPPLY_PROP_ENERGY_NOW,
115 POWER_SUPPLY_PROP_ENERGY_FULL,
116 POWER_SUPPLY_PROP_ENERGY_EMPTY,
117};
118
119static int read_data_from_battery(u8 smb_cmd, u8 smb_prtcl)
120{
121 if (context.battery_state & MAIN_BATTERY_STATUS_BAT_IN) {
122 mutex_lock(&qci_i2c_lock);
123 i2c_smbus_write_byte_data(context.bi2c_client,
124 ECRAM_SMB_STS, 0);
125 i2c_smbus_write_byte_data(context.bi2c_client, ECRAM_SMB_ADDR,
126 BATTERY_SLAVE_ADDRESS);
127 i2c_smbus_write_byte_data(context.bi2c_client,
128 ECRAM_SMB_CMD, smb_cmd);
129 i2c_smbus_write_byte_data(context.bi2c_client,
130 ECRAM_SMB_PRTCL, smb_prtcl);
131 mutex_unlock(&qci_i2c_lock);
132 msleep(100);
133 return get_bat_info(ECRAM_SMB_STS);
134 } else
135 return SMBUS_DEVICE_NOACK;
136}
137
138static int qbat_get_status(union power_supply_propval *val)
139{
140 int status;
141
142 status = get_bat_info(ECRAM_BATTERY_STATUS);
143
144 if ((status & MAIN_BATTERY_STATUS_BAT_IN) == 0x0)
145 val->intval = POWER_SUPPLY_STATUS_UNKNOWN;
146 else if (status & MAIN_BATTERY_STATUS_BAT_CHARGING)
147 val->intval = POWER_SUPPLY_STATUS_CHARGING;
148 else if (status & MAIN_BATTERY_STATUS_BAT_FULL)
149 val->intval = POWER_SUPPLY_STATUS_FULL;
150 else if (status & MAIN_BATTERY_STATUS_BAT_DISCHRG)
151 val->intval = POWER_SUPPLY_STATUS_DISCHARGING;
152 else
153 val->intval = POWER_SUPPLY_STATUS_NOT_CHARGING;
154
155 return 0;
156}
157
158static int qbat_get_present(union power_supply_propval *val)
159{
160 if (context.battery_state & MAIN_BATTERY_STATUS_BAT_IN)
161 val->intval = EC_BAT_PRESENT;
162 else
163 val->intval = EC_BAT_NOT_PRESENT;
164 return 0;
165}
166
167static int qbat_get_health(union power_supply_propval *val)
168{
169 u8 health;
170
171 health = get_bat_info(ECRAM_CHARGER_ALARM);
172 if (!(context.battery_state & MAIN_BATTERY_STATUS_BAT_IN))
173 val->intval = POWER_SUPPLY_HEALTH_UNKNOWN;
174 else if (health & ALARM_OVER_TEMP)
175 val->intval = POWER_SUPPLY_HEALTH_OVERHEAT;
176 else if (health & ALARM_REMAIN_CAPACITY)
177 val->intval = POWER_SUPPLY_HEALTH_DEAD;
178 else if (health & ALARM_OVER_CHARGE)
179 val->intval = POWER_SUPPLY_HEALTH_OVERVOLTAGE;
180 else
181 val->intval = POWER_SUPPLY_HEALTH_GOOD;
182 return 0;
183}
184
185static int qbat_get_voltage_avg(union power_supply_propval *val)
186{
187 val->intval = (get_bat_info(ECRAM_BATTERY_VOLTAGE_MSB) << 8 |
188 get_bat_info(ECRAM_BATTERY_VOLTAGE_LSB)) * 1000;
189 return 0;
190}
191
192static int qbat_get_current_avg(union power_supply_propval *val)
193{
194 val->intval = (get_bat_info(ECRAM_BATTERY_CURRENT_MSB) << 8 |
195 get_bat_info(ECRAM_BATTERY_CURRENT_LSB));
196 return 0;
197}
198
199static int qbat_get_capacity(union power_supply_propval *val)
200{
201 if (!(context.battery_state & MAIN_BATTERY_STATUS_BAT_IN))
202 val->intval = 0xFF;
203 else
204 val->intval = get_bat_info(ECRAM_BATTERY_CAPACITY);
205 return 0;
206}
207
208static int qbat_get_temp_avg(union power_supply_propval *val)
209{
210 int temp;
211 int rc = 0;
212
213 if (!(context.battery_state & MAIN_BATTERY_STATUS_BAT_IN)) {
214 val->intval = 0xFFFF;
215 rc = -ENODATA;
216 } else {
217 temp = (get_bat_info(ECRAM_BATTERY_TEMP_MSB) << 8) |
218 get_bat_info(ECRAM_BATTERY_TEMP_LSB);
219 val->intval = (temp - 2730) / 10;
220 }
221 return rc;
222}
223
224static int qbat_get_charge_full_design(union power_supply_propval *val)
225{
226 val->intval = context.charge_full_design;
227 return 0;
228}
229
230static int qbat_get_charge_full(union power_supply_propval *val)
231{
232 val->intval = context.charge_full;
233 return 0;
234}
235
236static int qbat_get_charge_counter(union power_supply_propval *val)
237{
238 u16 charge = 0;
239 int rc = 0;
240
241 mutex_lock(&qci_transaction_lock);
242 if (read_data_from_battery(BATTERY_CYCLE_COUNT,
243 SMBUS_READ_WORD_PRTCL) == SMBUS_DONE) {
244 charge = get_bat_info(ECRAM_SMB_DATA1);
245 charge = charge << 8;
246 charge |= get_bat_info(ECRAM_SMB_DATA0);
247 } else
248 rc = -ENODATA;
249 mutex_unlock(&qci_transaction_lock);
250 val->intval = charge;
251 return rc;
252}
253
254static int qbat_get_time_empty_avg(union power_supply_propval *val)
255{
256 u16 avg = 0;
257 int rc = 0;
258
259 mutex_lock(&qci_transaction_lock);
260 if (read_data_from_battery(BATTERY_AVERAGE_TIME_TO_EMPTY,
261 SMBUS_READ_WORD_PRTCL) == SMBUS_DONE) {
262 avg = get_bat_info(ECRAM_SMB_DATA1);
263 avg = avg << 8;
264 avg |= get_bat_info(ECRAM_SMB_DATA0);
265 } else
266 rc = -ENODATA;
267 mutex_unlock(&qci_transaction_lock);
268 val->intval = avg;
269 return rc;
270}
271
272static int qbat_get_time_full_avg(union power_supply_propval *val)
273{
274 u16 avg = 0;
275 int rc = 0;
276
277 mutex_lock(&qci_transaction_lock);
278 if (read_data_from_battery(BATTERY_AVERAGE_TIME_TO_FULL,
279 SMBUS_READ_WORD_PRTCL) == SMBUS_DONE) {
280 avg = get_bat_info(ECRAM_SMB_DATA1);
281 avg = avg << 8;
282 avg |= get_bat_info(ECRAM_SMB_DATA0);
283 } else
284 rc = -ENODATA;
285 mutex_unlock(&qci_transaction_lock);
286 val->intval = avg;
287 return rc;
288}
289
290static int qbat_get_model_name(union power_supply_propval *val)
291{
292 unsigned char i, size;
293
294 mutex_lock(&qci_transaction_lock);
295 if (read_data_from_battery(BATTERY_DEVICE_NAME,
296 SMBUS_READ_BLOCK_PRTCL) == SMBUS_DONE) {
297 size = min(get_bat_info(ECRAM_SMB_BCNT), QCIBAT_STRING_SIZE);
298 for (i = 0; i < size; i++) {
299 context.battery_dev_name[i] =
300 get_bat_info(ECRAM_SMB_DATA_START + i);
301 }
302 val->strval = context.battery_dev_name;
303 } else
304 val->strval = "Unknown";
305 mutex_unlock(&qci_transaction_lock);
306 return 0;
307}
308
309static int qbat_get_manufacturer_name(union power_supply_propval *val)
310{
311 val->strval = context.manufacturer_name;
312 return 0;
313}
314
315static int qbat_get_serial_number(union power_supply_propval *val)
316{
317 val->strval = context.serial_number;
318 return 0;
319}
320
321static int qbat_get_technology(union power_supply_propval *val)
322{
323 val->intval = POWER_SUPPLY_TECHNOLOGY_UNKNOWN;
324 return 0;
325}
326
327static int qbat_get_energy_now(union power_supply_propval *val)
328{
329 if (!(get_bat_info(ECRAM_BATTERY_STATUS) & MAIN_BATTERY_STATUS_BAT_IN))
330 val->intval = 0;
331 else
332 val->intval = (get_bat_info(ECRAM_BATTERY_CAPACITY) *
333 context.energy_full) / 100;
334 return 0;
335}
336
337static int qbat_get_energy_full(union power_supply_propval *val)
338{
339 val->intval = context.energy_full;
340 return 0;
341}
342
343static int qbat_get_energy_empty(union power_supply_propval *val)
344{
345 val->intval = 0;
346 return 0;
347}
348
349static void qbat_init_get_charge_full(void)
350{
351 u16 charge = QCIBAT_DEFAULT_CHARGE_FULL_CAPACITY;
352
353 mutex_lock(&qci_transaction_lock);
354 if (read_data_from_battery(BATTERY_FULL_CAPACITY,
355 SMBUS_READ_WORD_PRTCL) == SMBUS_DONE) {
356 charge = get_bat_info(ECRAM_SMB_DATA1);
357 charge = charge << 8;
358 charge |= get_bat_info(ECRAM_SMB_DATA0);
359 }
360 mutex_unlock(&qci_transaction_lock);
361 context.charge_full = charge;
362}
363
364static void qbat_init_get_charge_full_design(void)
365{
366 u16 charge = QCIBAT_DEFAULT_CHARGE_FULL_DESIGN;
367
368 mutex_lock(&qci_transaction_lock);
369 if (read_data_from_battery(BATTERY_DESIGN_CAPACITY,
370 SMBUS_READ_WORD_PRTCL) == SMBUS_DONE) {
371 charge = get_bat_info(ECRAM_SMB_DATA1);
372 charge = charge << 8;
373 charge |= get_bat_info(ECRAM_SMB_DATA0);
374 }
375 mutex_unlock(&qci_transaction_lock);
376 context.charge_full_design = charge;
377}
378
379static void qbat_init_get_voltage_full_design(void)
380{
381 u16 voltage = QCIBAT_DEFAULT_VOLTAGE_DESIGN;
382
383 mutex_lock(&qci_transaction_lock);
384 if (read_data_from_battery(BATTERY_DESIGN_VOLTAGE,
385 SMBUS_READ_WORD_PRTCL) == SMBUS_DONE) {
386 voltage = get_bat_info(ECRAM_SMB_DATA1);
387 voltage = voltage << 8;
388 voltage |= get_bat_info(ECRAM_SMB_DATA0);
389 }
390 mutex_unlock(&qci_transaction_lock);
391 context.voltage_full_design = voltage;
392}
393
394static void qbat_init_get_manufacturer_name(void)
395{
396 u8 size;
397 u8 i;
398 int rc;
399
400 mutex_lock(&qci_transaction_lock);
401 rc = read_data_from_battery(BATTERY_MANUFACTURE_NAME,
402 SMBUS_READ_BLOCK_PRTCL);
403 if (rc == SMBUS_DONE) {
404 size = min(get_bat_info(ECRAM_SMB_BCNT), QCIBAT_STRING_SIZE);
405 for (i = 0; i < size; i++) {
406 context.manufacturer_name[i] =
407 get_bat_info(ECRAM_SMB_DATA_START + i);
408 }
409 } else
410 strcpy(context.manufacturer_name, "Unknown");
411 mutex_unlock(&qci_transaction_lock);
412}
413
414static void qbat_init_get_serial_number(void)
415{
416 u8 size;
417 u8 i;
418 int rc;
419
420 mutex_lock(&qci_transaction_lock);
421 rc = read_data_from_battery(BATTERY_SERIAL_NUMBER,
422 SMBUS_READ_BLOCK_PRTCL);
423 if (rc == SMBUS_DONE) {
424 size = min(get_bat_info(ECRAM_SMB_BCNT), QCIBAT_STRING_SIZE);
425 for (i = 0; i < size; i++) {
426 context.serial_number[i] =
427 get_bat_info(ECRAM_SMB_DATA_START + i);
428 }
429 } else
430 strcpy(context.serial_number, "Unknown");
431 mutex_unlock(&qci_transaction_lock);
432}
433
434static void init_battery_stats(void)
435{
436 int i;
437
438 context.battery_state = get_bat_info(ECRAM_BATTERY_STATUS);
439 if (!(context.battery_state & MAIN_BATTERY_STATUS_BAT_IN))
440 return;
441 /* EC bug? needs some initial priming */
442 for (i = 0; i < 5; i++) {
443 read_data_from_battery(BATTERY_DESIGN_CAPACITY,
444 SMBUS_READ_WORD_PRTCL);
445 }
446
447 qbat_init_get_charge_full_design();
448 qbat_init_get_charge_full();
449 qbat_init_get_voltage_full_design();
450
451 context.energy_full = context.voltage_full_design *
452 context.charge_full;
453
454 qbat_init_get_serial_number();
455 qbat_init_get_manufacturer_name();
456}
457
458/*********************************************************************
459 * Battery properties
460 *********************************************************************/
461static int qbat_get_property(struct power_supply *psy,
462 enum power_supply_property psp,
463 union power_supply_propval *val)
464{
465 int ret = 0;
466
467 switch (psp) {
468 case POWER_SUPPLY_PROP_STATUS:
469 ret = qbat_get_status(val);
470 break;
471 case POWER_SUPPLY_PROP_PRESENT:
472 ret = qbat_get_present(val);
473 break;
474 case POWER_SUPPLY_PROP_HEALTH:
475 ret = qbat_get_health(val);
476 break;
477 case POWER_SUPPLY_PROP_MANUFACTURER:
478 ret = qbat_get_manufacturer_name(val);
479 break;
480 case POWER_SUPPLY_PROP_TECHNOLOGY:
481 ret = qbat_get_technology(val);
482 break;
483 case POWER_SUPPLY_PROP_VOLTAGE_AVG:
484 ret = qbat_get_voltage_avg(val);
485 break;
486 case POWER_SUPPLY_PROP_CURRENT_AVG:
487 ret = qbat_get_current_avg(val);
488 break;
489 case POWER_SUPPLY_PROP_CAPACITY:
490 ret = qbat_get_capacity(val);
491 break;
492 case POWER_SUPPLY_PROP_TEMP:
493 ret = qbat_get_temp_avg(val);
494 break;
495 case POWER_SUPPLY_PROP_CHARGE_FULL_DESIGN:
496 ret = qbat_get_charge_full_design(val);
497 break;
498 case POWER_SUPPLY_PROP_CHARGE_FULL:
499 ret = qbat_get_charge_full(val);
500 break;
501 case POWER_SUPPLY_PROP_CHARGE_COUNTER:
502 ret = qbat_get_charge_counter(val);
503 break;
504 case POWER_SUPPLY_PROP_TIME_TO_EMPTY_AVG:
505 ret = qbat_get_time_empty_avg(val);
506 break;
507 case POWER_SUPPLY_PROP_TIME_TO_FULL_AVG:
508 ret = qbat_get_time_full_avg(val);
509 break;
510 case POWER_SUPPLY_PROP_MODEL_NAME:
511 ret = qbat_get_model_name(val);
512 break;
513 case POWER_SUPPLY_PROP_SERIAL_NUMBER:
514 ret = qbat_get_serial_number(val);
515 break;
516 case POWER_SUPPLY_PROP_ENERGY_NOW:
517 ret = qbat_get_energy_now(val);
518 break;
519 case POWER_SUPPLY_PROP_ENERGY_FULL:
520 ret = qbat_get_energy_full(val);
521 break;
522 case POWER_SUPPLY_PROP_ENERGY_EMPTY:
523 ret = qbat_get_energy_empty(val);
524 break;
525 default:
526 ret = -EINVAL;
527 break;
528 }
529
530 return ret;
531}
532
533/*********************************************************************
534 * Initialisation
535 *********************************************************************/
536
537static struct power_supply qci_ac = {
538 .name = "ac",
539 .type = POWER_SUPPLY_TYPE_MAINS,
540 .properties = qci_ac_props,
541 .num_properties = ARRAY_SIZE(qci_ac_props),
542 .get_property = qci_ac_get_prop,
543};
544
545static struct power_supply qci_bat = {
546 .name = "battery",
547 .type = POWER_SUPPLY_TYPE_BATTERY,
548 .properties = qci_bat_props,
549 .num_properties = ARRAY_SIZE(qci_bat_props),
550 .get_property = qbat_get_property,
551 .use_for_apm = 1,
552};
553
554static irqreturn_t qbat_interrupt(int irq, void *dev_id)
555{
556 struct i2cbat_drv_data *ibat_drv_data = dev_id;
557 schedule_work(&ibat_drv_data->work);
558 return IRQ_HANDLED;
559}
560
561static void qbat_work(struct work_struct *_work)
562{
563 u8 status;
564
565 status = get_bat_info(ECRAM_BATTERY_EVENTS);
566 if (status & EC_EVENT_AC) {
567 context.battery_state = get_bat_info(ECRAM_BATTERY_STATUS);
568 power_supply_changed(&qci_ac);
569 }
570
571 if (status & (EC_EVENT_BATTERY | EC_EVENT_CHARGER | EC_EVENT_TIMER)) {
572 context.battery_state = get_bat_info(ECRAM_BATTERY_STATUS);
573 power_supply_changed(&qci_bat);
574 if (status & EC_EVENT_BATTERY)
575 init_battery_stats();
576 }
577}
578
579static struct platform_device *bat_pdev;
580
581static int __init qbat_init(void)
582{
583 int err = 0;
584
585 mutex_init(&qci_i2c_lock);
586 mutex_init(&qci_transaction_lock);
587
588 context.bi2c_client = wpce_get_i2c_client();
589 if (context.bi2c_client == NULL)
590 return -1;
591
592 i2c_set_clientdata(context.bi2c_client, &context);
593 context.qcibat_gpio = context.bi2c_client->irq;
594
595 /*battery device register*/
596 bat_pdev = platform_device_register_simple("battery", 0, NULL, 0);
597 if (IS_ERR(bat_pdev))
598 return PTR_ERR(bat_pdev);
599
600 err = power_supply_register(&bat_pdev->dev, &qci_ac);
601 if (err)
602 goto ac_failed;
603
604 qci_bat.name = bat_pdev->name;
605 err = power_supply_register(&bat_pdev->dev, &qci_bat);
606 if (err)
607 goto battery_failed;
608
609 /*battery irq configure*/
610 INIT_WORK(&context.work, qbat_work);
611 err = gpio_request(context.qcibat_gpio, "qci-bat");
612 if (err) {
613 dev_err(&context.bi2c_client->dev,
614 "[BAT] err gpio request\n");
615 goto gpio_request_fail;
616 }
617 context.qcibat_irq = gpio_to_irq(context.qcibat_gpio);
618 err = request_irq(context.qcibat_irq, qbat_interrupt,
619 IRQF_TRIGGER_FALLING, BATTERY_ID_NAME, &context);
620 if (err) {
621 dev_err(&context.bi2c_client->dev,
622 "[BAT] unable to get IRQ\n");
623 goto request_irq_fail;
624 }
625
626 init_battery_stats();
627 goto success;
628
629request_irq_fail:
630 gpio_free(context.qcibat_gpio);
631
632gpio_request_fail:
633 power_supply_unregister(&qci_bat);
634
635battery_failed:
636 power_supply_unregister(&qci_ac);
637
638ac_failed:
639 platform_device_unregister(bat_pdev);
640
641 i2c_set_clientdata(context.bi2c_client, NULL);
642success:
643 return err;
644}
645
646static void __exit qbat_exit(void)
647{
648 free_irq(context.qcibat_irq, &context);
649 gpio_free(context.qcibat_gpio);
650 power_supply_unregister(&qci_bat);
651 power_supply_unregister(&qci_ac);
652 platform_device_unregister(bat_pdev);
653 i2c_set_clientdata(context.bi2c_client, NULL);
654}
655
656late_initcall(qbat_init);
657module_exit(qbat_exit);
658
659MODULE_AUTHOR("Quanta Computer Inc.");
660MODULE_DESCRIPTION("Quanta Embedded Controller I2C Battery Driver");
661MODULE_LICENSE("GPL v2");
662