Linux Kernel  3.7.1
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
intel_mid_battery.c
Go to the documentation of this file.
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 <[email protected]>
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 
45 static int debug;
46 module_param(debug, int, 0444);
47 MODULE_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 0x86
65 
66 #define PMIC_BATT_ADC_ACCCHRG_MASK (1 << 31)
67 #define PMIC_BATT_ADC_ACCCHRGVAL_MASK 0x7FFFFFFF
68 
69 /* pmic ipc related */
70 #define PMIC_BATT_CHR_IPC_FCHRG_SUBID 0x4
71 #define PMIC_BATT_CHR_IPC_TCHRG_SUBID 0x6
72 
73 /* types of battery charging */
77 };
78 
79 /* valid battery events */
80 enum batt_event {
86 };
87 
88 
89 /*********************************************************************
90  * Battery properties
91  *********************************************************************/
92 
93 /*
94  * pmic battery info
95  */
98  struct device *dev;
99  /* pmic battery data */
100  unsigned long update_time; /* jiffies when data read */
101  unsigned int usb_is_present;
102  unsigned int batt_is_present;
103  unsigned int batt_health;
104  unsigned int usb_health;
105  unsigned int batt_status;
106  unsigned int batt_charge_now; /* in mAS */
107  unsigned int batt_prev_charge_full; /* in mAS */
108  unsigned int batt_charge_rate; /* in units per second */
109 
112  int irq; /* GPE_ID or IRQ# */
116 };
117 
118 static unsigned int delay_time = 2000; /* in ms */
119 
120 /*
121  * pmic ac properties
122  */
123 static enum power_supply_property pmic_usb_props[] = {
126 };
127 
128 /*
129  * pmic battery properties
130  */
131 static enum power_supply_property pmic_battery_props[] = {
137 };
138 
139 
140 /*
141  * Glue functions for talking to the IPC
142  */
143 
145  u32 capacity; /* Charger capacity */
146  u8 crnt; /* Quick charge current value*/
147  u8 volt; /* Fine adjustment of constant charge voltage */
148  u8 prot; /* CHRGPROT register value */
149  u8 prot2; /* CHRGPROT1 register value */
150  u8 timer; /* Charging timer */
151 };
152 
153 #define IPCMSG_BATTERY 0xEF
154 
155 /* Battery coulomb counter accumulator commands */
156 #define IPC_CMD_CC_WR 0 /* Update coulomb counter value */
157 #define IPC_CMD_CC_RD 1 /* Read coulomb counter value */
158 #define IPC_CMD_BATTERY_PROPERTY 2 /* Read Battery property */
159 
170 static int pmic_scu_ipc_battery_cc_read(u32 *value)
171 {
173  NULL, 0, value, 1);
174 }
175 
185 static int pmic_scu_ipc_battery_property_get(struct battery_property *prop)
186 {
187  u32 data[3];
188  u8 *p = (u8 *)&data[1];
190  IPC_CMD_BATTERY_PROPERTY, NULL, 0, data, 3);
191 
192  prop->capacity = data[0];
193  prop->crnt = *p++;
194  prop->volt = *p++;
195  prop->prot = *p++;
196  prop->prot2 = *p++;
197  prop->timer = *p++;
198 
199  return err;
200 }
201 
209 static int pmic_scu_ipc_set_charger(int charger)
210 {
212 }
213 
223 static void pmic_battery_log_event(enum batt_event event)
224 {
225  printk(KERN_WARNING "pmic-battery: ");
226  switch (event) {
228  printk(KERN_CONT "battery overvoltage condition\n");
229  break;
231  printk(KERN_CONT "usb charger overvoltage condition\n");
232  break;
234  printk(KERN_CONT "high battery temperature condition\n");
235  break;
237  printk(KERN_CONT "over battery charge current condition\n");
238  break;
239  default:
240  printk(KERN_CONT "charger/battery exception %d\n", event);
241  break;
242  }
243 }
244 
254 static void pmic_battery_read_status(struct pmic_power_module_info *pbi)
255 {
256  unsigned int update_time_intrvl;
257  unsigned int chrg_val;
258  u32 ccval;
259  u8 r8;
260  struct battery_property batt_prop;
261  int batt_present = 0;
262  int usb_present = 0;
263  int batt_exception = 0;
264 
265  /* make sure the last batt_status read happened delay_time before */
266  if (pbi->update_time && time_before(jiffies, pbi->update_time +
267  msecs_to_jiffies(delay_time)))
268  return;
269 
270  update_time_intrvl = jiffies_to_msecs(jiffies - pbi->update_time);
271  pbi->update_time = jiffies;
272 
273  /* read coulomb counter registers and schrgint register */
274  if (pmic_scu_ipc_battery_cc_read(&ccval)) {
275  dev_warn(pbi->dev, "%s(): ipc config cmd failed\n",
276  __func__);
277  return;
278  }
279 
281  dev_warn(pbi->dev, "%s(): ipc pmic read failed\n",
282  __func__);
283  return;
284  }
285 
286  /*
287  * set pmic_power_module_info members based on pmic register values
288  * read.
289  */
290 
291  /* set batt_is_present */
292  if (r8 & PMIC_BATT_CHR_SBATDET_MASK) {
294  batt_present = 1;
295  } else {
299  }
300 
301  /* set batt_health */
302  if (batt_present) {
303  if (r8 & PMIC_BATT_CHR_SBATOVP_MASK) {
306  pmic_battery_log_event(BATT_EVENT_BATOVP_EXCPT);
307  batt_exception = 1;
308  } else if (r8 & PMIC_BATT_CHR_STEMP_MASK) {
311  pmic_battery_log_event(BATT_EVENT_TEMP_EXCPT);
312  batt_exception = 1;
313  } else {
315  if (r8 & PMIC_BATT_CHR_SDCLMT_MASK) {
316  /* PMIC will change charging current automatically */
317  pmic_battery_log_event(BATT_EVENT_DCLMT_EXCPT);
318  }
319  }
320  }
321 
322  /* set usb_is_present */
323  if (r8 & PMIC_BATT_CHR_SUSBDET_MASK) {
325  usb_present = 1;
326  } else {
329  }
330 
331  if (usb_present) {
332  if (r8 & PMIC_BATT_CHR_SUSBOVP_MASK) {
334  pmic_battery_log_event(BATT_EVENT_USBOVP_EXCPT);
335  } else {
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) {
356  pbi->batt_prev_charge_full = chrg_val;
357  } else if (ccval & PMIC_BATT_ADC_ACCCHRG_MASK) {
359  } else {
361  }
362  }
363 
364  /* set batt_charge_rate */
365  if (pbi->is_dev_info_updated && batt_present && !batt_exception) {
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 
391 }
392 
403 static 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) {
415  val->intval = pbi->usb_is_present;
416  break;
418  val->intval = pbi->usb_health;
419  break;
420  default:
421  return -EINVAL;
422  }
423 
424  return 0;
425 }
426 
427 static inline unsigned long mAStouAh(unsigned long v)
428 {
429  /* seconds to hours, mA to µA */
430  return (v * 1000) / 3600;
431 }
432 
443 static 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) {
455  val->intval = pbi->batt_status;
456  break;
458  val->intval = pbi->batt_health;
459  break;
461  val->intval = pbi->batt_is_present;
462  break;
464  val->intval = mAStouAh(pbi->batt_charge_now);
465  break;
467  val->intval = mAStouAh(pbi->batt_prev_charge_full);
468  break;
469  default:
470  return -EINVAL;
471  }
472 
473  return 0;
474 }
475 
484 static void pmic_battery_monitor(struct work_struct *work)
485 {
486  struct pmic_power_module_info *pbi = container_of(work,
488 
489  /* update pmic_power_module_info members */
490  pmic_battery_read_status(pbi);
492 }
493 
503 static 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) {
511  retval = pmic_scu_ipc_set_charger(PMIC_BATT_CHR_IPC_FCHRG_SUBID);
512  break;
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 
539 static 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 
558 static void pmic_battery_handle_intrpt(struct work_struct *work)
559 {
560  struct pmic_power_module_info *pbi = container_of(work,
562  enum batt_charge_type chrg;
563  u8 r8;
564 
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) {
573  } else {
577  return;
578  }
579 
580  if (r8 & PMIC_BATT_CHR_EXCPT_MASK) {
584  pmic_battery_log_event(BATT_EVENT_EXCPT);
585  return;
586  } else {
589  }
590 
591  if (r8 & PMIC_BATT_CHR_SCOMP_MASK) {
592  u32 ccval;
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 &
602  return;
603  }
604 
605  if (r8 & PMIC_BATT_CHR_SUSBDET_MASK) {
607  } else {
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)
627  else
628 #endif
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 
652 static __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 
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 
730 power_reg_failed_1:
732 power_reg_failed:
734 requestirq_failed:
736 wqueue_failed:
737  kfree(pbi);
738 
739  return retval;
740 }
741 
742 static int __devinit platform_pmic_battery_probe(struct platform_device *pdev)
743 {
744  return probe(pdev->id, &pdev->dev);
745 }
746 
757 static int __devexit platform_pmic_battery_remove(struct platform_device *pdev)
758 {
759  struct pmic_power_module_info *pbi = dev_get_drvdata(&pdev->dev);
760 
761  free_irq(pbi->irq, pbi);
764 
767 
768  cancel_work_sync(&pbi->handler);
769  kfree(pbi);
770  return 0;
771 }
772 
773 static struct platform_driver platform_pmic_battery_driver = {
774  .driver = {
775  .name = DRIVER_NAME,
776  .owner = THIS_MODULE,
777  },
778  .probe = platform_pmic_battery_probe,
779  .remove = __devexit_p(platform_pmic_battery_remove),
780 };
781 
782 module_platform_driver(platform_pmic_battery_driver);
783 
784 MODULE_AUTHOR("Nithish Mahalingam <[email protected]>");
785 MODULE_DESCRIPTION("Intel Moorestown PMIC Battery Driver");
786 MODULE_LICENSE("GPL");