aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorNithish Mahalingam <nithish.mahalingam@intel.com>2010-06-17 13:12:36 -0400
committerAnton Vorontsov <cbouatmailru@gmail.com>2010-06-17 13:52:25 -0400
commit6721081b6b911a067fe6ca3d6f5534c4a11a9e59 (patch)
treebe39a6945e3debbb9e773fc9b99294ecc4e3e5b8
parenteb9650d6d989f24f21232a055d8fd45f1a9dcf99 (diff)
Intel MID platform battery driver
The PMIC Battery driver provides battery charging and battery gauge functionality on Intel MID platforms. This provides the basic functions. There are some USB drivers to merge before the selection of charging between the different USB power levels can be enabled. Moved to a platform device by Alek Du. Signed-off-by: Nithish Mahalingam <nithish.mahalingam@intel.com> Signed-off-by: Alan Cox <alan@linux.intel.com> Signed-off-by: Anton Vorontsov <cbouatmailru@gmail.com>
-rw-r--r--drivers/power/Kconfig7
-rw-r--r--drivers/power/Makefile1
-rw-r--r--drivers/power/intel_mid_battery.c799
3 files changed, 807 insertions, 0 deletions
diff --git a/drivers/power/Kconfig b/drivers/power/Kconfig
index 8e9ba177d817..6eae8211197f 100644
--- a/drivers/power/Kconfig
+++ b/drivers/power/Kconfig
@@ -142,4 +142,11 @@ config CHARGER_PCF50633
142 help 142 help
143 Say Y to include support for NXP PCF50633 Main Battery Charger. 143 Say Y to include support for NXP PCF50633 Main Battery Charger.
144 144
145config BATTERY_INTEL_MID
146 tristate "Battery driver for Intel MID platforms"
147 depends on INTEL_SCU_IPC && SPI
148 help
149 Say Y here to enable the battery driver on Intel MID
150 platforms.
151
145endif # POWER_SUPPLY 152endif # POWER_SUPPLY
diff --git a/drivers/power/Makefile b/drivers/power/Makefile
index 00050809a6c7..2b9a81d41b4d 100644
--- a/drivers/power/Makefile
+++ b/drivers/power/Makefile
@@ -34,3 +34,4 @@ obj-$(CONFIG_BATTERY_DA9030) += da9030_battery.o
34obj-$(CONFIG_BATTERY_MAX17040) += max17040_battery.o 34obj-$(CONFIG_BATTERY_MAX17040) += max17040_battery.o
35obj-$(CONFIG_BATTERY_Z2) += z2_battery.o 35obj-$(CONFIG_BATTERY_Z2) += z2_battery.o
36obj-$(CONFIG_CHARGER_PCF50633) += pcf50633-charger.o 36obj-$(CONFIG_CHARGER_PCF50633) += pcf50633-charger.o
37obj-$(CONFIG_BATTERY_INTEL_MID) += intel_mid_battery.o
diff --git a/drivers/power/intel_mid_battery.c b/drivers/power/intel_mid_battery.c
new file mode 100644
index 000000000000..46730f579d7f
--- /dev/null
+++ b/drivers/power/intel_mid_battery.c
@@ -0,0 +1,799 @@
1/*
2 * intel_mid_battery.c - Intel MID PMIC Battery Driver
3 *
4 * Copyright (C) 2009 Intel Corporation
5 *
6 * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
7 *
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; version 2 of the License.
11 *
12 * This program is distributed in the hope that it will be useful, but
13 * WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License along
18 * with this program; if not, write to the Free Software Foundation, Inc.,
19 * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
20 *
21 * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
22 * Author: Nithish Mahalingam <nithish.mahalingam@intel.com>
23 */
24
25#include <linux/module.h>
26#include <linux/init.h>
27#include <linux/err.h>
28#include <linux/interrupt.h>
29#include <linux/workqueue.h>
30#include <linux/jiffies.h>
31#include <linux/param.h>
32#include <linux/device.h>
33#include <linux/spi/spi.h>
34#include <linux/platform_device.h>
35#include <linux/power_supply.h>
36
37#include <asm/intel_scu_ipc.h>
38
39#define DRIVER_NAME "pmic_battery"
40
41/*********************************************************************
42 * Generic defines
43 *********************************************************************/
44
45static int debug;
46module_param(debug, int, 0444);
47MODULE_PARM_DESC(debug, "Flag to enable PMIC Battery debug messages.");
48
49#define PMIC_BATT_DRV_INFO_UPDATED 1
50#define PMIC_BATT_PRESENT 1
51#define PMIC_BATT_NOT_PRESENT 0
52#define PMIC_USB_PRESENT PMIC_BATT_PRESENT
53#define PMIC_USB_NOT_PRESENT PMIC_BATT_NOT_PRESENT
54
55/* pmic battery register related */
56#define PMIC_BATT_CHR_SCHRGINT_ADDR 0xD2
57#define PMIC_BATT_CHR_SBATOVP_MASK (1 << 1)
58#define PMIC_BATT_CHR_STEMP_MASK (1 << 2)
59#define PMIC_BATT_CHR_SCOMP_MASK (1 << 3)
60#define PMIC_BATT_CHR_SUSBDET_MASK (1 << 4)
61#define PMIC_BATT_CHR_SBATDET_MASK (1 << 5)
62#define PMIC_BATT_CHR_SDCLMT_MASK (1 << 6)
63#define PMIC_BATT_CHR_SUSBOVP_MASK (1 << 7)
64#define PMIC_BATT_CHR_EXCPT_MASK 0xC6
65#define PMIC_BATT_ADC_ACCCHRG_MASK (1 << 31)
66#define PMIC_BATT_ADC_ACCCHRGVAL_MASK 0x7FFFFFFF
67
68/* pmic ipc related */
69#define PMIC_BATT_CHR_IPC_FCHRG_SUBID 0x4
70#define PMIC_BATT_CHR_IPC_TCHRG_SUBID 0x6
71
72/* types of battery charging */
73enum batt_charge_type {
74 BATT_USBOTG_500MA_CHARGE,
75 BATT_USBOTG_TRICKLE_CHARGE,
76};
77
78/* valid battery events */
79enum batt_event {
80 BATT_EVENT_BATOVP_EXCPT,
81 BATT_EVENT_USBOVP_EXCPT,
82 BATT_EVENT_TEMP_EXCPT,
83 BATT_EVENT_DCLMT_EXCPT,
84 BATT_EVENT_EXCPT
85};
86
87
88/*********************************************************************
89 * Battery properties
90 *********************************************************************/
91
92/*
93 * pmic battery info
94 */
95struct pmic_power_module_info {
96 bool is_dev_info_updated;
97 struct device *dev;
98 /* pmic battery data */
99 unsigned long update_time; /* jiffies when data read */
100 unsigned int usb_is_present;
101 unsigned int batt_is_present;
102 unsigned int batt_health;
103 unsigned int usb_health;
104 unsigned int batt_status;
105 unsigned int batt_charge_now; /* in mAS */
106 unsigned int batt_prev_charge_full; /* in mAS */
107 unsigned int batt_charge_rate; /* in units per second */
108
109 struct power_supply usb;
110 struct power_supply batt;
111 int irq; /* GPE_ID or IRQ# */
112 struct workqueue_struct *monitor_wqueue;
113 struct delayed_work monitor_battery;
114 struct work_struct handler;
115};
116
117static unsigned int delay_time = 2000; /* in ms */
118
119/*
120 * pmic ac properties
121 */
122static enum power_supply_property pmic_usb_props[] = {
123 POWER_SUPPLY_PROP_PRESENT,
124 POWER_SUPPLY_PROP_HEALTH,
125};
126
127/*
128 * pmic battery properties
129 */
130static enum power_supply_property pmic_battery_props[] = {
131 POWER_SUPPLY_PROP_STATUS,
132 POWER_SUPPLY_PROP_HEALTH,
133 POWER_SUPPLY_PROP_PRESENT,
134 POWER_SUPPLY_PROP_CHARGE_NOW,
135 POWER_SUPPLY_PROP_CHARGE_FULL,
136};
137
138
139/*
140 * Glue functions for talking to the IPC
141 */
142
143struct battery_property {
144 u32 capacity; /* Charger capacity */
145 u8 crnt; /* Quick charge current value*/
146 u8 volt; /* Fine adjustment of constant charge voltage */
147 u8 prot; /* CHRGPROT register value */
148 u8 prot2; /* CHRGPROT1 register value */
149 u8 timer; /* Charging timer */
150};
151
152#define IPCMSG_BATTERY 0xEF
153
154/* Battery coulomb counter accumulator commands */
155#define IPC_CMD_CC_WR 0 /* Update coulomb counter value */
156#define IPC_CMD_CC_RD 1 /* Read coulomb counter value */
157#define IPC_CMD_BATTERY_PROPERTY 2 /* Read Battery property */
158
159/**
160 * pmic_scu_ipc_battery_cc_read - read battery cc
161 * @value: battery coulomb counter read
162 *
163 * Reads the battery couloumb counter value, returns 0 on success, or
164 * an error code
165 *
166 * This function may sleep. Locking for SCU accesses is handled for
167 * the caller.
168 */
169static int pmic_scu_ipc_battery_cc_read(u32 *value)
170{
171 return intel_scu_ipc_command(IPC_CMD_CC_RD, IPCMSG_BATTERY,
172 NULL, 0, value, 1);
173}
174
175/**
176 * pmic_scu_ipc_battery_property_get - fetch properties
177 * @prop: battery properties
178 *
179 * Retrieve the battery properties from the power management
180 *
181 * This function may sleep. Locking for SCU accesses is handled for
182 * the caller.
183 */
184static int pmic_scu_ipc_battery_property_get(struct battery_property *prop)
185{
186 u32 data[3];
187 u8 *p = (u8 *)&data[1];
188 int err = intel_scu_ipc_command(IPC_CMD_BATTERY_PROPERTY,
189 IPCMSG_BATTERY, NULL, 0, data, 3);
190
191 prop->capacity = data[0];
192 prop->crnt = *p++;
193 prop->volt = *p++;
194 prop->prot = *p++;
195 prop->prot2 = *p++;
196 prop->timer = *p++;
197
198 return err;
199}
200
201/**
202 * pmic_scu_ipc_set_charger - set charger
203 * @charger: charger to select
204 *
205 * Switch the charging mode for the SCU
206 */
207
208static int pmic_scu_ipc_set_charger(int charger)
209{
210 return intel_scu_ipc_simple_command(charger, IPCMSG_BATTERY);
211}
212
213/**
214 * pmic_battery_log_event - log battery events
215 * @event: battery event to be logged
216 * Context: can sleep
217 *
218 * There are multiple battery events which may be of interest to users;
219 * this battery function logs the different battery events onto the
220 * kernel log messages.
221 */
222static void pmic_battery_log_event(enum batt_event event)
223{
224 printk(KERN_WARNING "pmic-battery: ");
225 switch (event) {
226 case BATT_EVENT_BATOVP_EXCPT:
227 printk(KERN_CONT "battery overvoltage condition\n");
228 break;
229 case BATT_EVENT_USBOVP_EXCPT:
230 printk(KERN_CONT "usb charger overvoltage condition\n");
231 break;
232 case BATT_EVENT_TEMP_EXCPT:
233 printk(KERN_CONT "high battery temperature condition\n");
234 break;
235 case BATT_EVENT_DCLMT_EXCPT:
236 printk(KERN_CONT "over battery charge current condition\n");
237 break;
238 default:
239 printk(KERN_CONT "charger/battery exception %d\n", event);
240 break;
241 }
242}
243
244/**
245 * pmic_battery_read_status - read battery status information
246 * @pbi: device info structure to update the read information
247 * Context: can sleep
248 *
249 * PMIC power source information need to be updated based on the data read
250 * from the PMIC battery registers.
251 *
252 */
253static void pmic_battery_read_status(struct pmic_power_module_info *pbi)
254{
255 unsigned int update_time_intrvl;
256 unsigned int chrg_val;
257 u32 ccval;
258 u8 r8;
259 struct battery_property batt_prop;
260 int batt_present = 0;
261 int usb_present = 0;
262 int batt_exception = 0;
263
264 /* make sure the last batt_status read happened delay_time before */
265 if (pbi->update_time && time_before(jiffies, pbi->update_time +
266 msecs_to_jiffies(delay_time)))
267 return;
268
269 update_time_intrvl = jiffies_to_msecs(jiffies - pbi->update_time);
270 pbi->update_time = jiffies;
271
272 /* read coulomb counter registers and schrgint register */
273 if (pmic_scu_ipc_battery_cc_read(&ccval)) {
274 dev_warn(pbi->dev, "%s(): ipc config cmd failed\n",
275 __func__);
276 return;
277 }
278
279 if (intel_scu_ipc_ioread8(PMIC_BATT_CHR_SCHRGINT_ADDR, &r8)) {
280 dev_warn(pbi->dev, "%s(): ipc pmic read failed\n",
281 __func__);
282 return;
283 }
284
285 /*
286 * set pmic_power_module_info members based on pmic register values
287 * read.
288 */
289
290 /* set batt_is_present */
291 if (r8 & PMIC_BATT_CHR_SBATDET_MASK) {
292 pbi->batt_is_present = PMIC_BATT_PRESENT;
293 batt_present = 1;
294 } else {
295 pbi->batt_is_present = PMIC_BATT_NOT_PRESENT;
296 pbi->batt_health = POWER_SUPPLY_HEALTH_UNKNOWN;
297 pbi->batt_status = POWER_SUPPLY_STATUS_UNKNOWN;
298 }
299
300 /* set batt_health */
301 if (batt_present) {
302 if (r8 & PMIC_BATT_CHR_SBATOVP_MASK) {
303 pbi->batt_health = POWER_SUPPLY_HEALTH_OVERVOLTAGE;
304 pbi->batt_status = POWER_SUPPLY_STATUS_NOT_CHARGING;
305 pmic_battery_log_event(BATT_EVENT_BATOVP_EXCPT);
306 batt_exception = 1;
307 } else if (r8 & PMIC_BATT_CHR_SDCLMT_MASK) {
308 pbi->batt_health = POWER_SUPPLY_HEALTH_OVERVOLTAGE;
309 pbi->batt_status = POWER_SUPPLY_STATUS_NOT_CHARGING;
310 pmic_battery_log_event(BATT_EVENT_DCLMT_EXCPT);
311 batt_exception = 1;
312 } else if (r8 & PMIC_BATT_CHR_STEMP_MASK) {
313 pbi->batt_health = POWER_SUPPLY_HEALTH_OVERHEAT;
314 pbi->batt_status = POWER_SUPPLY_STATUS_NOT_CHARGING;
315 pmic_battery_log_event(BATT_EVENT_TEMP_EXCPT);
316 batt_exception = 1;
317 } else {
318 pbi->batt_health = POWER_SUPPLY_HEALTH_GOOD;
319 }
320 }
321
322 /* set usb_is_present */
323 if (r8 & PMIC_BATT_CHR_SUSBDET_MASK) {
324 pbi->usb_is_present = PMIC_USB_PRESENT;
325 usb_present = 1;
326 } else {
327 pbi->usb_is_present = PMIC_USB_NOT_PRESENT;
328 pbi->usb_health = POWER_SUPPLY_HEALTH_UNKNOWN;
329 }
330
331 if (usb_present) {
332 if (r8 & PMIC_BATT_CHR_SUSBOVP_MASK) {
333 pbi->usb_health = POWER_SUPPLY_HEALTH_OVERVOLTAGE;
334 pmic_battery_log_event(BATT_EVENT_USBOVP_EXCPT);
335 } else {
336 pbi->usb_health = POWER_SUPPLY_HEALTH_GOOD;
337 }
338 }
339
340 chrg_val = ccval & PMIC_BATT_ADC_ACCCHRGVAL_MASK;
341
342 /* set batt_prev_charge_full to battery capacity the first time */
343 if (!pbi->is_dev_info_updated) {
344 if (pmic_scu_ipc_battery_property_get(&batt_prop)) {
345 dev_warn(pbi->dev, "%s(): ipc config cmd failed\n",
346 __func__);
347 return;
348 }
349 pbi->batt_prev_charge_full = batt_prop.capacity;
350 }
351
352 /* set batt_status */
353 if (batt_present && !batt_exception) {
354 if (r8 & PMIC_BATT_CHR_SCOMP_MASK) {
355 pbi->batt_status = POWER_SUPPLY_STATUS_FULL;
356 pbi->batt_prev_charge_full = chrg_val;
357 } else if (ccval & PMIC_BATT_ADC_ACCCHRG_MASK) {
358 pbi->batt_status = POWER_SUPPLY_STATUS_DISCHARGING;
359 } else {
360 pbi->batt_status = POWER_SUPPLY_STATUS_CHARGING;
361 }
362 }
363
364 /* set batt_charge_rate */
365 if (pbi->is_dev_info_updated && batt_present && !batt_exception) {
366 if (pbi->batt_status == POWER_SUPPLY_STATUS_DISCHARGING) {
367 if (pbi->batt_charge_now - chrg_val) {
368 pbi->batt_charge_rate = ((pbi->batt_charge_now -
369 chrg_val) * 1000 * 60) /
370 update_time_intrvl;
371 }
372 } else if (pbi->batt_status == POWER_SUPPLY_STATUS_CHARGING) {
373 if (chrg_val - pbi->batt_charge_now) {
374 pbi->batt_charge_rate = ((chrg_val -
375 pbi->batt_charge_now) * 1000 * 60) /
376 update_time_intrvl;
377 }
378 } else
379 pbi->batt_charge_rate = 0;
380 } else {
381 pbi->batt_charge_rate = -1;
382 }
383
384 /* batt_charge_now */
385 if (batt_present && !batt_exception)
386 pbi->batt_charge_now = chrg_val;
387 else
388 pbi->batt_charge_now = -1;
389
390 pbi->is_dev_info_updated = PMIC_BATT_DRV_INFO_UPDATED;
391}
392
393/**
394 * pmic_usb_get_property - usb power source get property
395 * @psy: usb power supply context
396 * @psp: usb power source property
397 * @val: usb power source property value
398 * Context: can sleep
399 *
400 * PMIC usb power source property needs to be provided to power_supply
401 * subsytem for it to provide the information to users.
402 */
403static int pmic_usb_get_property(struct power_supply *psy,
404 enum power_supply_property psp,
405 union power_supply_propval *val)
406{
407 struct pmic_power_module_info *pbi = container_of(psy,
408 struct pmic_power_module_info, usb);
409
410 /* update pmic_power_module_info members */
411 pmic_battery_read_status(pbi);
412
413 switch (psp) {
414 case POWER_SUPPLY_PROP_PRESENT:
415 val->intval = pbi->usb_is_present;
416 break;
417 case POWER_SUPPLY_PROP_HEALTH:
418 val->intval = pbi->usb_health;
419 break;
420 default:
421 return -EINVAL;
422 }
423
424 return 0;
425}
426
427static inline unsigned long mAStouAh(unsigned long v)
428{
429 /* seconds to hours, mA to µA */
430 return v * 3600 * 1000;
431}
432
433/**
434 * pmic_battery_get_property - battery power source get property
435 * @psy: battery power supply context
436 * @psp: battery power source property
437 * @val: battery power source property value
438 * Context: can sleep
439 *
440 * PMIC battery power source property needs to be provided to power_supply
441 * subsytem for it to provide the information to users.
442 */
443static int pmic_battery_get_property(struct power_supply *psy,
444 enum power_supply_property psp,
445 union power_supply_propval *val)
446{
447 struct pmic_power_module_info *pbi = container_of(psy,
448 struct pmic_power_module_info, batt);
449
450 /* update pmic_power_module_info members */
451 pmic_battery_read_status(pbi);
452
453 switch (psp) {
454 case POWER_SUPPLY_PROP_STATUS:
455 val->intval = pbi->batt_status;
456 break;
457 case POWER_SUPPLY_PROP_HEALTH:
458 val->intval = pbi->batt_health;
459 break;
460 case POWER_SUPPLY_PROP_PRESENT:
461 val->intval = pbi->batt_is_present;
462 break;
463 case POWER_SUPPLY_PROP_CHARGE_NOW:
464 val->intval = mAStouAh(pbi->batt_charge_now);
465 break;
466 case POWER_SUPPLY_PROP_CHARGE_FULL:
467 val->intval = mAStouAh(pbi->batt_prev_charge_full);
468 break;
469 default:
470 return -EINVAL;
471 }
472
473 return 0;
474}
475
476/**
477 * pmic_battery_monitor - monitor battery status
478 * @work: work structure
479 * Context: can sleep
480 *
481 * PMIC battery status needs to be monitored for any change
482 * and information needs to be frequently updated.
483 */
484static void pmic_battery_monitor(struct work_struct *work)
485{
486 struct pmic_power_module_info *pbi = container_of(work,
487 struct pmic_power_module_info, monitor_battery.work);
488
489 /* update pmic_power_module_info members */
490 pmic_battery_read_status(pbi);
491 queue_delayed_work(pbi->monitor_wqueue, &pbi->monitor_battery, HZ * 10);
492}
493
494/**
495 * pmic_battery_set_charger - set battery charger
496 * @pbi: device info structure
497 * @chrg: charge mode to set battery charger in
498 * Context: can sleep
499 *
500 * PMIC battery charger needs to be enabled based on the usb charge
501 * capabilities connected to the platform.
502 */
503static int pmic_battery_set_charger(struct pmic_power_module_info *pbi,
504 enum batt_charge_type chrg)
505{
506 int retval;
507
508 /* set usblmt bits and chrgcntl register bits appropriately */
509 switch (chrg) {
510 case BATT_USBOTG_500MA_CHARGE:
511 retval = pmic_scu_ipc_set_charger(PMIC_BATT_CHR_IPC_FCHRG_SUBID);
512 break;
513 case BATT_USBOTG_TRICKLE_CHARGE:
514 retval = pmic_scu_ipc_set_charger(PMIC_BATT_CHR_IPC_TCHRG_SUBID);
515 break;
516 default:
517 dev_warn(pbi->dev, "%s(): out of range usb charger "
518 "charge detected\n", __func__);
519 return -EINVAL;
520 }
521
522 if (retval) {
523 dev_warn(pbi->dev, "%s(): ipc pmic read failed\n",
524 __func__);
525 return retval;;
526 }
527
528 return 0;
529}
530
531/**
532 * pmic_battery_interrupt_handler - pmic battery interrupt handler
533 * Context: interrupt context
534 *
535 * PMIC battery interrupt handler which will be called with either
536 * battery full condition occurs or usb otg & battery connect
537 * condition occurs.
538 */
539static irqreturn_t pmic_battery_interrupt_handler(int id, void *dev)
540{
541 struct pmic_power_module_info *pbi = dev;
542
543 schedule_work(&pbi->handler);
544
545 return IRQ_HANDLED;
546}
547
548/**
549 * pmic_battery_handle_intrpt - pmic battery service interrupt
550 * @work: work structure
551 * Context: can sleep
552 *
553 * PMIC battery needs to either update the battery status as full
554 * if it detects battery full condition caused the interrupt or needs
555 * to enable battery charger if it detects usb and battery detect
556 * caused the source of interrupt.
557 */
558static void pmic_battery_handle_intrpt(struct work_struct *work)
559{
560 struct pmic_power_module_info *pbi = container_of(work,
561 struct pmic_power_module_info, handler);
562 enum batt_charge_type chrg;
563 u8 r8;
564
565 if (intel_scu_ipc_ioread8(PMIC_BATT_CHR_SCHRGINT_ADDR, &r8)) {
566 dev_warn(pbi->dev, "%s(): ipc pmic read failed\n",
567 __func__);
568 return;
569 }
570 /* find the cause of the interrupt */
571 if (r8 & PMIC_BATT_CHR_SBATDET_MASK) {
572 pbi->batt_is_present = PMIC_BATT_PRESENT;
573 } else {
574 pbi->batt_is_present = PMIC_BATT_NOT_PRESENT;
575 pbi->batt_health = POWER_SUPPLY_HEALTH_UNKNOWN;
576 pbi->batt_status = POWER_SUPPLY_STATUS_UNKNOWN;
577 return;
578 }
579
580 if (r8 & PMIC_BATT_CHR_EXCPT_MASK) {
581 pbi->batt_health = POWER_SUPPLY_HEALTH_UNKNOWN;
582 pbi->batt_status = POWER_SUPPLY_STATUS_NOT_CHARGING;
583 pbi->usb_health = POWER_SUPPLY_HEALTH_UNKNOWN;
584 pmic_battery_log_event(BATT_EVENT_EXCPT);
585 return;
586 } else {
587 pbi->batt_health = POWER_SUPPLY_HEALTH_GOOD;
588 pbi->usb_health = POWER_SUPPLY_HEALTH_GOOD;
589 }
590
591 if (r8 & PMIC_BATT_CHR_SCOMP_MASK) {
592 u32 ccval;
593 pbi->batt_status = POWER_SUPPLY_STATUS_FULL;
594
595 if (pmic_scu_ipc_battery_cc_read(&ccval)) {
596 dev_warn(pbi->dev, "%s(): ipc config cmd "
597 "failed\n", __func__);
598 return;
599 }
600 pbi->batt_prev_charge_full = ccval &
601 PMIC_BATT_ADC_ACCCHRGVAL_MASK;
602 return;
603 }
604
605 if (r8 & PMIC_BATT_CHR_SUSBDET_MASK) {
606 pbi->usb_is_present = PMIC_USB_PRESENT;
607 } else {
608 pbi->usb_is_present = PMIC_USB_NOT_PRESENT;
609 pbi->usb_health = POWER_SUPPLY_HEALTH_UNKNOWN;
610 return;
611 }
612
613 /* setup battery charging */
614
615#if 0
616 /* check usb otg power capability and set charger accordingly */
617 retval = langwell_udc_maxpower(&power);
618 if (retval) {
619 dev_warn(pbi->dev,
620 "%s(): usb otg power query failed with error code %d\n",
621 __func__, retval);
622 return;
623 }
624
625 if (power >= 500)
626 chrg = BATT_USBOTG_500MA_CHARGE;
627 else
628#endif
629 chrg = BATT_USBOTG_TRICKLE_CHARGE;
630
631 /* enable battery charging */
632 if (pmic_battery_set_charger(pbi, chrg)) {
633 dev_warn(pbi->dev,
634 "%s(): failed to set up battery charging\n", __func__);
635 return;
636 }
637
638 dev_dbg(pbi->dev,
639 "pmic-battery: %s() - setting up battery charger successful\n",
640 __func__);
641}
642
643/**
644 * pmic_battery_probe - pmic battery initialize
645 * @irq: pmic battery device irq
646 * @dev: pmic battery device structure
647 * Context: can sleep
648 *
649 * PMIC battery initializes its internal data structue and other
650 * infrastructure components for it to work as expected.
651 */
652static __devinit int probe(int irq, struct device *dev)
653{
654 int retval = 0;
655 struct pmic_power_module_info *pbi;
656
657 dev_dbg(dev, "pmic-battery: found pmic battery device\n");
658
659 pbi = kzalloc(sizeof(*pbi), GFP_KERNEL);
660 if (!pbi) {
661 dev_err(dev, "%s(): memory allocation failed\n",
662 __func__);
663 return -ENOMEM;
664 }
665
666 pbi->dev = dev;
667 pbi->irq = irq;
668 dev_set_drvdata(dev, pbi);
669
670 /* initialize all required framework before enabling interrupts */
671 INIT_WORK(&pbi->handler, pmic_battery_handle_intrpt);
672 INIT_DELAYED_WORK(&pbi->monitor_battery, pmic_battery_monitor);
673 pbi->monitor_wqueue =
674 create_singlethread_workqueue(dev_name(dev));
675 if (!pbi->monitor_wqueue) {
676 dev_err(dev, "%s(): wqueue init failed\n", __func__);
677 retval = -ESRCH;
678 goto wqueue_failed;
679 }
680
681 /* register interrupt */
682 retval = request_irq(pbi->irq, pmic_battery_interrupt_handler,
683 0, DRIVER_NAME, pbi);
684 if (retval) {
685 dev_err(dev, "%s(): cannot get IRQ\n", __func__);
686 goto requestirq_failed;
687 }
688
689 /* register pmic-batt with power supply subsystem */
690 pbi->batt.name = "pmic-batt";
691 pbi->batt.type = POWER_SUPPLY_TYPE_BATTERY;
692 pbi->batt.properties = pmic_battery_props;
693 pbi->batt.num_properties = ARRAY_SIZE(pmic_battery_props);
694 pbi->batt.get_property = pmic_battery_get_property;
695 retval = power_supply_register(dev, &pbi->batt);
696 if (retval) {
697 dev_err(dev,
698 "%s(): failed to register pmic battery device with power supply subsystem\n",
699 __func__);
700 goto power_reg_failed;
701 }
702
703 dev_dbg(dev, "pmic-battery: %s() - pmic battery device "
704 "registration with power supply subsystem successful\n",
705 __func__);
706
707 queue_delayed_work(pbi->monitor_wqueue, &pbi->monitor_battery, HZ * 1);
708
709 /* register pmic-usb with power supply subsystem */
710 pbi->usb.name = "pmic-usb";
711 pbi->usb.type = POWER_SUPPLY_TYPE_USB;
712 pbi->usb.properties = pmic_usb_props;
713 pbi->usb.num_properties = ARRAY_SIZE(pmic_usb_props);
714 pbi->usb.get_property = pmic_usb_get_property;
715 retval = power_supply_register(dev, &pbi->usb);
716 if (retval) {
717 dev_err(dev,
718 "%s(): failed to register pmic usb device with power supply subsystem\n",
719 __func__);
720 goto power_reg_failed_1;
721 }
722
723 if (debug)
724 printk(KERN_INFO "pmic-battery: %s() - pmic usb device "
725 "registration with power supply subsystem successful\n",
726 __func__);
727
728 return retval;
729
730power_reg_failed_1:
731 power_supply_unregister(&pbi->batt);
732power_reg_failed:
733 cancel_rearming_delayed_workqueue(pbi->monitor_wqueue,
734 &pbi->monitor_battery);
735requestirq_failed:
736 destroy_workqueue(pbi->monitor_wqueue);
737wqueue_failed:
738 kfree(pbi);
739
740 return retval;
741}
742
743static int __devinit platform_pmic_battery_probe(struct platform_device *pdev)
744{
745 return probe(pdev->id, &pdev->dev);
746}
747
748/**
749 * pmic_battery_remove - pmic battery finalize
750 * @dev: pmic battery device structure
751 * Context: can sleep
752 *
753 * PMIC battery finalizes its internal data structue and other
754 * infrastructure components that it initialized in
755 * pmic_battery_probe.
756 */
757
758static int __devexit platform_pmic_battery_remove(struct platform_device *pdev)
759{
760 struct pmic_power_module_info *pbi = dev_get_drvdata(&pdev->dev);
761
762 free_irq(pbi->irq, pbi);
763 cancel_rearming_delayed_workqueue(pbi->monitor_wqueue,
764 &pbi->monitor_battery);
765 destroy_workqueue(pbi->monitor_wqueue);
766
767 power_supply_unregister(&pbi->usb);
768 power_supply_unregister(&pbi->batt);
769
770 flush_scheduled_work();
771 kfree(pbi);
772 return 0;
773}
774
775static struct platform_driver platform_pmic_battery_driver = {
776 .driver = {
777 .name = DRIVER_NAME,
778 .owner = THIS_MODULE,
779 },
780 .probe = platform_pmic_battery_probe,
781 .remove = __devexit_p(platform_pmic_battery_remove),
782};
783
784static int __init platform_pmic_battery_module_init(void)
785{
786 return platform_driver_register(&platform_pmic_battery_driver);
787}
788
789static void __exit platform_pmic_battery_module_exit(void)
790{
791 platform_driver_unregister(&platform_pmic_battery_driver);
792}
793
794module_init(platform_pmic_battery_module_init);
795module_exit(platform_pmic_battery_module_exit);
796
797MODULE_AUTHOR("Nithish Mahalingam <nithish.mahalingam@intel.com>");
798MODULE_DESCRIPTION("Intel Moorestown PMIC Battery Driver");
799MODULE_LICENSE("GPL");