diff options
Diffstat (limited to 'meta-moblin/packages/linux/linux-moblin-2.6.33.2/linux-2.6.34-moorestown-pmic-battery-driver.patch')
-rw-r--r-- | meta-moblin/packages/linux/linux-moblin-2.6.33.2/linux-2.6.34-moorestown-pmic-battery-driver.patch | 849 |
1 files changed, 0 insertions, 849 deletions
diff --git a/meta-moblin/packages/linux/linux-moblin-2.6.33.2/linux-2.6.34-moorestown-pmic-battery-driver.patch b/meta-moblin/packages/linux/linux-moblin-2.6.33.2/linux-2.6.34-moorestown-pmic-battery-driver.patch deleted file mode 100644 index 1e098a78e..000000000 --- a/meta-moblin/packages/linux/linux-moblin-2.6.33.2/linux-2.6.34-moorestown-pmic-battery-driver.patch +++ /dev/null @@ -1,849 +0,0 @@ -From 10551a86fa76709587b48a644caeb78dd07690be Mon Sep 17 00:00:00 2001 -From: Nithish Mahalingam <nithish.mahalingam@intel.com> -Date: Tue, 29 Dec 2009 22:42:48 +0530 -Subject: [PATCH 068/104] Adding Intel Moorestown PMIC Battery Driver - -PMIC Battery driver provides battery charging and battery gauge functionality -on Intel Moorestown platform. - -Signed-off-by: Nithish Mahalingam <nithish.mahalingam@intel.com> ---- - drivers/power/Kconfig | 7 + - drivers/power/Makefile | 1 + - drivers/power/pmic_battery.c | 799 ++++++++++++++++++++++++++++++++++++++++++ - 3 files changed, 807 insertions(+), 0 deletions(-) - create mode 100644 drivers/power/pmic_battery.c - -diff --git a/drivers/power/Kconfig b/drivers/power/Kconfig -index d4b3d67..6936bc8 100644 ---- a/drivers/power/Kconfig -+++ b/drivers/power/Kconfig -@@ -124,4 +124,11 @@ config CHARGER_PCF50633 - help - Say Y to include support for NXP PCF50633 Main Battery Charger. - -+config BATTERY_MRSTPMIC -+ tristate "PMIC battery driver for Intel Moorestown platform" -+ depends on SPI_MRST && LNW_IPC && USB_GADGET_LANGWELL -+ help -+ Say Y here to enable battery driver on Intel Moorestown -+ platform. -+ - endif # POWER_SUPPLY -diff --git a/drivers/power/Makefile b/drivers/power/Makefile -index 573597c..97af4b4 100644 ---- a/drivers/power/Makefile -+++ b/drivers/power/Makefile -@@ -31,3 +31,4 @@ obj-$(CONFIG_BATTERY_BQ27x00) += bq27x00_battery.o - obj-$(CONFIG_BATTERY_DA9030) += da9030_battery.o - obj-$(CONFIG_BATTERY_MAX17040) += max17040_battery.o - obj-$(CONFIG_CHARGER_PCF50633) += pcf50633-charger.o -+obj-$(CONFIG_BATTERY_MRSTPMIC) += pmic_battery.o -diff --git a/drivers/power/pmic_battery.c b/drivers/power/pmic_battery.c -new file mode 100644 -index 0000000..6e3c46a ---- /dev/null -+++ b/drivers/power/pmic_battery.c -@@ -0,0 +1,799 @@ -+/* -+ * pmic_battery.c - Intel Moorestown PMIC Battery Driver -+ * -+ * Copyright (C) 2009 Intel Corporation -+ * -+ * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License as published by -+ * the Free Software Foundation; version 2 of the License. -+ * -+ * This program is distributed in the hope that it will be useful, but -+ * WITHOUT ANY WARRANTY; without even the implied warranty of -+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -+ * General Public License for more details. -+ * -+ * You should have received a copy of the GNU General Public License along -+ * with this program; if not, write to the Free Software Foundation, Inc., -+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. -+ * -+ * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -+ * Author: Nithish Mahalingam <nithish.mahalingam@intel.com> -+ */ -+ -+#include <linux/module.h> -+#include <linux/init.h> -+#include <linux/err.h> -+#include <linux/interrupt.h> -+#include <linux/workqueue.h> -+#include <linux/jiffies.h> -+#include <linux/param.h> -+#include <linux/device.h> -+#include <linux/spi/spi.h> -+#include <linux/power_supply.h> -+ -+#include <asm/ipc_defs.h> -+#include <linux/usb/langwell_udc.h> -+ -+ -+MODULE_AUTHOR("Nithish Mahalingam <nithish.mahalingam@intel.com>"); -+MODULE_DESCRIPTION("Intel Moorestown PMIC Battery Driver"); -+MODULE_LICENSE("GPL"); -+ -+#define DRIVER_NAME "pmic_battery" -+ -+/********************************************************************* -+ * Generic defines -+ *********************************************************************/ -+ -+static int pmicbatteryDebug; -+module_param(pmicbatteryDebug, int, 0444); -+MODULE_PARM_DESC(pmicbatteryDebug, -+ "Flag to enable PMIC Battery debug messages."); -+ -+#define PMIC_BATT_DEBUG (pmicbatteryDebug) -+ -+#define PMIC_BATT_DRV_INFO_UPDATED 1 -+#define PMIC_BATT_PRESENT 1 -+#define PMIC_BATT_NOT_PRESENT 0 -+#define PMIC_USB_PRESENT PMIC_BATT_PRESENT -+#define PMIC_USB_NOT_PRESENT PMIC_BATT_NOT_PRESENT -+ -+/* pmic battery register related */ -+#define PMIC_BATT_CHR_SCHRGINT_ADDR 0xD2 -+#define PMIC_BATT_CHR_SBATOVP_MASK (1 << 1) -+#define PMIC_BATT_CHR_STEMP_MASK (1 << 2) -+#define PMIC_BATT_CHR_SCOMP_MASK (1 << 3) -+#define PMIC_BATT_CHR_SUSBDET_MASK (1 << 4) -+#define PMIC_BATT_CHR_SBATDET_MASK (1 << 5) -+#define PMIC_BATT_CHR_SDCLMT_MASK (1 << 6) -+#define PMIC_BATT_CHR_SUSBOVP_MASK (1 << 7) -+#define PMIC_BATT_CHR_EXCPT_MASK 0xC6 -+#define PMIC_BATT_ADC_ACCCHRG_MASK (1 << 31) -+#define PMIC_BATT_ADC_ACCCHRGVAL_MASK 0x7FFFFFFF -+ -+/* pmic ipc related */ -+#define PMIC_BATT_CHR_IPC_CMDID 0xEF -+#define PMIC_BATT_CHR_IPC_FCHRG_SUBID 0x4 -+#define PMIC_BATT_CHR_IPC_TCHRG_SUBID 0x6 -+ -+/* internal return values */ -+#define BATTSUCCESS 0 -+#define EBATTFAIL 1 -+#define EBATTERR 2 -+ -+/* types of battery charging */ -+enum batt_charge_type { -+ BATT_USBOTG_500MA_CHARGE, -+ BATT_USBOTG_TRICKLE_CHARGE, -+}; -+ -+/* valid battery events */ -+enum batt_event { -+ BATT_EVENT_BATOVP_EXCPT, -+ BATT_EVENT_USBOVP_EXCPT, -+ BATT_EVENT_TEMP_EXCPT, -+ BATT_EVENT_DCLMT_EXCPT, -+ BATT_EVENT_EXCPT -+}; -+ -+/* battery cca value */ -+struct batt_cca_data { -+ signed int cca_val; -+}; -+ -+/* battery property structure */ -+struct batt_prop_data { -+ unsigned int batt_capacity; -+ char batt_chrg_crnt; -+ char batt_chrg_volt; -+ char batt_chrg_prot; -+ char batt_chrg_prot2; -+ char batt_chrg_timer; -+} __attribute__((packed)); -+ -+ -+/********************************************************************* -+ * Battery properties -+ *********************************************************************/ -+ -+/* -+ * pmic battery info -+ */ -+struct pmic_power_module_info { -+ bool is_dev_info_updated; -+ struct spi_device *spi; -+ /* pmic battery data */ -+ unsigned long update_time; /* jiffies when data read */ -+ unsigned int usb_is_present; -+ unsigned int batt_is_present; -+ unsigned int batt_health; -+ unsigned int usb_health; -+ unsigned int batt_status; -+ unsigned int batt_charge_now; /* in mAS */ -+ unsigned int batt_prev_charge_full; /* in mAS */ -+ unsigned int batt_charge_rate; /* in units per second */ -+ -+ struct power_supply usb; -+ struct power_supply batt; -+ int irq; /* GPE_ID or IRQ# */ -+ struct workqueue_struct *monitor_wqueue; -+ struct delayed_work monitor_battery; -+ struct work_struct handler; -+}; -+ -+static unsigned int delay_time = 2000; /* in ms */ -+ -+/* -+ * pmic ac properties -+ */ -+static enum power_supply_property pmic_usb_props[] = { -+ POWER_SUPPLY_PROP_PRESENT, -+ POWER_SUPPLY_PROP_HEALTH, -+}; -+ -+/* -+ * pmic battery properties -+ */ -+static enum power_supply_property pmic_battery_props[] = { -+ POWER_SUPPLY_PROP_STATUS, -+ POWER_SUPPLY_PROP_HEALTH, -+ POWER_SUPPLY_PROP_PRESENT, -+ POWER_SUPPLY_PROP_CHARGE_NOW, -+ POWER_SUPPLY_PROP_CHARGE_FULL, -+ POWER_SUPPLY_PROP_CHARGE_AVG, -+}; -+ -+ -+/** -+ * pmic_battery_log_event - log battery events -+ * @event: battery event to be logged -+ * Context: can sleep -+ * -+ * There are multiple battery events which may be of interest to users; -+ * this battery function logs the different battery events onto the -+ * kernel log messages. -+ */ -+static void pmic_battery_log_event(enum batt_event event) -+{ -+ switch (event) { -+ case BATT_EVENT_BATOVP_EXCPT: -+ printk(KERN_WARNING "pmic-battery: battery overvoltage " -+ "condition detected\n"); -+ break; -+ case BATT_EVENT_USBOVP_EXCPT: -+ printk(KERN_WARNING "pmic-battery: usb charger overvoltage " -+ "condition detected\n"); -+ break; -+ case BATT_EVENT_TEMP_EXCPT: -+ printk(KERN_WARNING "pmic-battery: high battery temperature " -+ "condition detected\n"); -+ break; -+ case BATT_EVENT_DCLMT_EXCPT: -+ printk(KERN_WARNING "pmic-battery: over battery charge " -+ " current condition detected\n"); -+ break; -+ default: -+ printk(KERN_WARNING "pmic-battery: charger/battery " -+ " exception detected\n"); -+ break; -+ } -+} -+ -+/** -+ * pmic_battery_read_status - read battery status information -+ * @pbi: device info structure to update the read information -+ * Context: can sleep -+ * -+ * PMIC power source information need to be updated based on the data read -+ * from the PMIC battery registers. -+ * -+ */ -+static void pmic_battery_read_status(struct pmic_power_module_info *pbi) -+{ -+ unsigned int update_time_intrvl = 0; -+ unsigned int chrg_val = 0; -+ struct ipc_pmic_reg_data pmic_batt_reg = {0}; -+ struct ipc_cmd_type pmic_batt_cmd = {0}; -+ struct batt_cca_data ccval = {0}; -+ struct batt_prop_data batt_prop = {0}; -+ int batt_present = 0; -+ int usb_present = 0; -+ int batt_exception = 0; -+ -+ /* make sure the last batt_status read happened delay_time before */ -+ if (pbi->update_time && time_before(jiffies, pbi->update_time + -+ msecs_to_jiffies(delay_time))) -+ return; -+ -+ update_time_intrvl = jiffies_to_msecs(jiffies - pbi->update_time); -+ pbi->update_time = jiffies; -+ -+ /* read coulomb counter registers and schrgint register */ -+ -+ pmic_batt_cmd.ioc = TRUE; -+ pmic_batt_cmd.cmd = IPC_BATT_CCA_READ; -+ if (ipc_config_cmd(pmic_batt_cmd, sizeof(struct batt_cca_data), -+ &ccval)) { -+ dev_warn(&pbi->spi->dev, "%s(): ipc config cmd failed\n", -+ __func__); -+ return; -+ } -+ -+ pmic_batt_reg.ioc = TRUE; -+ pmic_batt_reg.pmic_reg_data[0].register_address = -+ PMIC_BATT_CHR_SCHRGINT_ADDR; -+ pmic_batt_reg.num_entries = 1; -+ -+ if (ipc_pmic_register_read(&pmic_batt_reg)) { -+ dev_warn(&pbi->spi->dev, "%s(): ipc pmic read failed\n", -+ __func__); -+ return; -+ } -+ -+ /* -+ * set pmic_power_module_info members based on pmic register values -+ * read. -+ */ -+ -+ /* set batt_is_present */ -+ if (pmic_batt_reg.pmic_reg_data[0].value & -+ PMIC_BATT_CHR_SBATDET_MASK) { -+ pbi->batt_is_present = PMIC_BATT_PRESENT; -+ batt_present = 1; -+ } else { -+ pbi->batt_is_present = PMIC_BATT_NOT_PRESENT; -+ pbi->batt_health = POWER_SUPPLY_HEALTH_UNKNOWN; -+ pbi->batt_status = POWER_SUPPLY_STATUS_UNKNOWN; -+ } -+ -+ /* set batt_health */ -+ if (batt_present) { -+ if (pmic_batt_reg.pmic_reg_data[0].value & -+ PMIC_BATT_CHR_SBATOVP_MASK) { -+ pbi->batt_health = POWER_SUPPLY_HEALTH_OVERVOLTAGE; -+ pbi->batt_status = POWER_SUPPLY_STATUS_NOT_CHARGING; -+ pmic_battery_log_event(BATT_EVENT_BATOVP_EXCPT); -+ batt_exception = 1; -+ } else if (pmic_batt_reg.pmic_reg_data[0].value & -+ PMIC_BATT_CHR_SDCLMT_MASK) { -+ pbi->batt_health = POWER_SUPPLY_HEALTH_OVERVOLTAGE; -+ pbi->batt_status = POWER_SUPPLY_STATUS_NOT_CHARGING; -+ pmic_battery_log_event(BATT_EVENT_DCLMT_EXCPT); -+ batt_exception = 1; -+ } else if (pmic_batt_reg.pmic_reg_data[0].value & -+ PMIC_BATT_CHR_STEMP_MASK) { -+ pbi->batt_health = POWER_SUPPLY_HEALTH_OVERHEAT; -+ pbi->batt_status = POWER_SUPPLY_STATUS_NOT_CHARGING; -+ pmic_battery_log_event(BATT_EVENT_TEMP_EXCPT); -+ batt_exception = 1; -+ } else { -+ pbi->batt_health = POWER_SUPPLY_HEALTH_GOOD; -+ } -+ } -+ -+ /* set usb_is_present */ -+ if (pmic_batt_reg.pmic_reg_data[0].value & -+ PMIC_BATT_CHR_SUSBDET_MASK) { -+ pbi->usb_is_present = PMIC_USB_PRESENT; -+ usb_present = 1; -+ } else { -+ pbi->usb_is_present = PMIC_USB_NOT_PRESENT; -+ pbi->usb_health = POWER_SUPPLY_HEALTH_UNKNOWN; -+ } -+ -+ if (usb_present) { -+ if (pmic_batt_reg.pmic_reg_data[0].value & -+ PMIC_BATT_CHR_SUSBOVP_MASK) { -+ pbi->usb_health = POWER_SUPPLY_HEALTH_OVERVOLTAGE; -+ pmic_battery_log_event(BATT_EVENT_USBOVP_EXCPT); -+ } else { -+ pbi->usb_health = POWER_SUPPLY_HEALTH_GOOD; -+ } -+ } -+ -+ chrg_val = ccval.cca_val & PMIC_BATT_ADC_ACCCHRGVAL_MASK; -+ -+ /* set batt_prev_charge_full to battery capacity the first time */ -+ if (!pbi->is_dev_info_updated) { -+ pmic_batt_cmd.ioc = TRUE; -+ pmic_batt_cmd.cmd = IPC_BATT_GET_PROP; -+ if (ipc_config_cmd(pmic_batt_cmd, -+ sizeof(struct batt_prop_data), &batt_prop)) { -+ dev_warn(&pbi->spi->dev, "%s(): ipc config cmd " -+ "failed\n", __func__); -+ return; -+ } -+ pbi->batt_prev_charge_full = batt_prop.batt_capacity; -+ } -+ -+ /* set batt_status */ -+ if ((batt_present) && (!batt_exception)) { -+ if (pmic_batt_reg.pmic_reg_data[0].value & -+ PMIC_BATT_CHR_SCOMP_MASK) { -+ pbi->batt_status = POWER_SUPPLY_STATUS_FULL; -+ pbi->batt_prev_charge_full = chrg_val; -+ } else if (ccval.cca_val & PMIC_BATT_ADC_ACCCHRG_MASK) { -+ pbi->batt_status = POWER_SUPPLY_STATUS_DISCHARGING; -+ } else { -+ pbi->batt_status = POWER_SUPPLY_STATUS_CHARGING; -+ } -+ } -+ -+ /* set batt_charge_rate */ -+ if ((pbi->is_dev_info_updated) && (batt_present) && (!batt_exception)) { -+ if (pbi->batt_status == POWER_SUPPLY_STATUS_DISCHARGING) { -+ if (pbi->batt_charge_now - chrg_val) { -+ pbi->batt_charge_rate = ((pbi->batt_charge_now - -+ chrg_val) * 1000 * 60) / -+ update_time_intrvl; -+ } -+ } else if (pbi->batt_status == POWER_SUPPLY_STATUS_CHARGING) { -+ if (chrg_val - pbi->batt_charge_now) { -+ pbi->batt_charge_rate = ((chrg_val - -+ pbi->batt_charge_now) * 1000 * 60) / -+ update_time_intrvl; -+ } -+ } else -+ pbi->batt_charge_rate = 0; -+ } else { -+ pbi->batt_charge_rate = -1; -+ } -+ -+ /* batt_charge_now */ -+ if ((batt_present) && (!batt_exception)) -+ pbi->batt_charge_now = chrg_val; -+ else -+ pbi->batt_charge_now = -1; -+ -+ pbi->is_dev_info_updated = PMIC_BATT_DRV_INFO_UPDATED; -+} -+ -+/** -+ * pmic_usb_get_property - usb power source get property -+ * @psy: usb power supply context -+ * @psp: usb power source property -+ * @val: usb power source property value -+ * Context: can sleep -+ * -+ * PMIC usb power source property needs to be provided to power_supply -+ * subsytem for it to provide the information to users. -+ */ -+static int pmic_usb_get_property(struct power_supply *psy, -+ enum power_supply_property psp, -+ union power_supply_propval *val) -+{ -+ struct pmic_power_module_info *pbi = container_of(psy, -+ struct pmic_power_module_info, usb); -+ -+ /* update pmic_power_module_info members */ -+ pmic_battery_read_status(pbi); -+ -+ switch (psp) { -+ case POWER_SUPPLY_PROP_PRESENT: -+ val->intval = pbi->usb_is_present; -+ break; -+ case POWER_SUPPLY_PROP_HEALTH: -+ val->intval = pbi->usb_health; -+ break; -+ default: -+ return -EINVAL; -+ } -+ -+ return 0; -+} -+ -+/** -+ * pmic_battery_get_property - battery power source get property -+ * @psy: battery power supply context -+ * @psp: battery power source property -+ * @val: battery power source property value -+ * Context: can sleep -+ * -+ * PMIC battery power source property needs to be provided to power_supply -+ * subsytem for it to provide the information to users. -+ */ -+static int pmic_battery_get_property(struct power_supply *psy, -+ enum power_supply_property psp, -+ union power_supply_propval *val) -+{ -+ struct pmic_power_module_info *pbi = container_of(psy, -+ struct pmic_power_module_info, batt); -+ -+ /* update pmic_power_module_info members */ -+ pmic_battery_read_status(pbi); -+ -+ switch (psp) { -+ case POWER_SUPPLY_PROP_STATUS: -+ val->intval = pbi->batt_status; -+ break; -+ case POWER_SUPPLY_PROP_HEALTH: -+ val->intval = pbi->batt_health; -+ break; -+ case POWER_SUPPLY_PROP_PRESENT: -+ val->intval = pbi->batt_is_present; -+ break; -+ case POWER_SUPPLY_PROP_CHARGE_NOW: -+ val->intval = pbi->batt_charge_now; -+ break; -+ case POWER_SUPPLY_PROP_CHARGE_FULL: -+ val->intval = pbi->batt_prev_charge_full; -+ break; -+ case POWER_SUPPLY_PROP_CHARGE_AVG: -+ val->intval = pbi->batt_charge_rate; -+ break; -+ default: -+ return -EINVAL; -+ } -+ -+ return 0; -+} -+ -+/** -+ * pmic_battery_monitor - monitor battery status -+ * @work: work structure -+ * Context: can sleep -+ * -+ * PMIC battery status needs to be monitored for any change -+ * and information needs to be frequently updated. -+ */ -+static void pmic_battery_monitor(struct work_struct *work) -+{ -+ struct pmic_power_module_info *pbi = container_of(work, -+ struct pmic_power_module_info, monitor_battery.work); -+ -+ /* update pmic_power_module_info members */ -+ pmic_battery_read_status(pbi); -+ queue_delayed_work(pbi->monitor_wqueue, &pbi->monitor_battery, HZ * 10); -+} -+ -+/** -+ * pmic_battery_set_charger - set battery charger -+ * @pbi: device info structure -+ * @chrg: charge mode to set battery charger in -+ * Context: can sleep -+ * -+ * PMIC battery charger needs to be enabled based on the usb charge -+ * capabilities connected to the platform. -+ */ -+static int pmic_battery_set_charger(struct pmic_power_module_info *pbi, -+ enum batt_charge_type chrg) -+{ -+ int retval; -+ -+ /* set usblmt bits and chrgcntl register bits appropriately */ -+ switch (chrg) { -+ case BATT_USBOTG_500MA_CHARGE: -+ retval = lnw_ipc_single_cmd(PMIC_BATT_CHR_IPC_CMDID, -+ PMIC_BATT_CHR_IPC_FCHRG_SUBID, 0, 0); -+ break; -+ case BATT_USBOTG_TRICKLE_CHARGE: -+ retval = lnw_ipc_single_cmd(PMIC_BATT_CHR_IPC_CMDID, -+ PMIC_BATT_CHR_IPC_TCHRG_SUBID, 0, 0); -+ break; -+ default: -+ dev_warn(&pbi->spi->dev, "%s(): out of range usb charger " -+ "charge detected\n", __func__); -+ return -EBATTFAIL; -+ } -+ -+ if (retval) { -+ dev_warn(&pbi->spi->dev, "%s(): ipc pmic read failed\n", -+ __func__); -+ return -EBATTFAIL; -+ } -+ -+ return BATTSUCCESS; -+} -+ -+/** -+ * pmic_battery_interrupt_handler - pmic battery interrupt handler -+ * Context: interrupt context -+ * -+ * PMIC battery interrupt handler which will be called with either -+ * battery full condition occurs or usb otg & battery connect -+ * condition occurs. -+ */ -+static irqreturn_t pmic_battery_interrupt_handler(int id, void *dev) -+{ -+ struct pmic_power_module_info *pbi = -+ (struct pmic_power_module_info *)dev; -+ -+ schedule_work(&pbi->handler); -+ -+ return IRQ_HANDLED; -+} -+ -+/** -+ * pmic_battery_handle_intrpt - pmic battery service interrupt -+ * @work: work structure -+ * Context: can sleep -+ * -+ * PMIC battery needs to either update the battery status as full -+ * if it detects battery full condition caused the interrupt or needs -+ * to enable battery charger if it detects usb and battery detect -+ * caused the source of interrupt. -+ */ -+static void pmic_battery_handle_intrpt(struct work_struct *work) -+{ -+ struct ipc_pmic_reg_data pmic_batt_reg = {0}; -+ struct pmic_power_module_info *pbi = container_of(work, -+ struct pmic_power_module_info, handler); -+ int power = 0; -+ enum batt_charge_type chrg; -+ int retval = 0; -+ -+ /* check if pmic_power_module_info is initialized */ -+ if (!pbi) -+ return; -+ -+ /* read schrgint register to interpret cause of interrupt */ -+ pmic_batt_reg.ioc = TRUE; -+ pmic_batt_reg.pmic_reg_data[0].register_address = -+ PMIC_BATT_CHR_SCHRGINT_ADDR; -+ pmic_batt_reg.num_entries = 1; -+ -+ if (ipc_pmic_register_read(&pmic_batt_reg)) { -+ dev_warn(&pbi->spi->dev, "%s(): ipc pmic read failed\n", -+ __func__); -+ return; -+ } -+ -+ /* find the cause of the interrupt */ -+ -+ if (pmic_batt_reg.pmic_reg_data[0].value & PMIC_BATT_CHR_SBATDET_MASK) { -+ pbi->batt_is_present = PMIC_BATT_PRESENT; -+ } else { -+ pbi->batt_is_present = PMIC_BATT_NOT_PRESENT; -+ pbi->batt_health = POWER_SUPPLY_HEALTH_UNKNOWN; -+ pbi->batt_status = POWER_SUPPLY_STATUS_UNKNOWN; -+ return; -+ } -+ -+ if (pmic_batt_reg.pmic_reg_data[0].value & -+ PMIC_BATT_CHR_EXCPT_MASK) { -+ pbi->batt_health = POWER_SUPPLY_HEALTH_UNKNOWN; -+ pbi->batt_status = POWER_SUPPLY_STATUS_NOT_CHARGING; -+ pbi->usb_health = POWER_SUPPLY_HEALTH_UNKNOWN; -+ pmic_battery_log_event(BATT_EVENT_EXCPT); -+ return; -+ } else { -+ pbi->batt_health = POWER_SUPPLY_HEALTH_GOOD; -+ pbi->usb_health = POWER_SUPPLY_HEALTH_GOOD; -+ } -+ -+ if (pmic_batt_reg.pmic_reg_data[0].value & PMIC_BATT_CHR_SCOMP_MASK) { -+ struct ipc_cmd_type pmic_batt_cmd = {0}; -+ struct batt_cca_data ccval = {0}; -+ -+ pbi->batt_status = POWER_SUPPLY_STATUS_FULL; -+ pmic_batt_cmd.ioc = TRUE; -+ pmic_batt_cmd.cmd = IPC_BATT_CCA_READ; -+ if (ipc_config_cmd(pmic_batt_cmd, -+ sizeof(struct batt_cca_data), &ccval)) { -+ dev_warn(&pbi->spi->dev, "%s(): ipc config cmd " -+ "failed\n", __func__); -+ return; -+ } -+ pbi->batt_prev_charge_full = ccval.cca_val & -+ PMIC_BATT_ADC_ACCCHRGVAL_MASK; -+ return; -+ } -+ -+ if (pmic_batt_reg.pmic_reg_data[0].value & PMIC_BATT_CHR_SUSBDET_MASK) { -+ pbi->usb_is_present = PMIC_USB_PRESENT; -+ } else { -+ pbi->usb_is_present = PMIC_USB_NOT_PRESENT; -+ pbi->usb_health = POWER_SUPPLY_HEALTH_UNKNOWN; -+ return; -+ } -+ -+ /* setup battery charging */ -+ -+ /* check usb otg power capability and set charger accordingly */ -+ retval = langwell_udc_maxpower(&power); -+ if (retval) { -+ dev_warn(&pbi->spi->dev, "%s(): usb otg power query failed " -+ "with error code %d\n", __func__, retval); -+ return; -+ } -+ -+ if (power >= 500) -+ chrg = BATT_USBOTG_500MA_CHARGE; -+ else -+ chrg = BATT_USBOTG_TRICKLE_CHARGE; -+ -+ /* enable battery charging */ -+ if (pmic_battery_set_charger(pbi, chrg)) { -+ dev_warn(&pbi->spi->dev, "%s(): failed to setup battery " -+ "charging\n", __func__); -+ return; -+ } -+ -+ if (PMIC_BATT_DEBUG) -+ printk(KERN_INFO "pmic-battery: %s() - setting up battery " -+ "charger successful\n", __func__); -+} -+ -+/** -+ * pmic_battery_probe - pmic battery initialize -+ * @spi: pmic battery spi structure -+ * Context: can sleep -+ * -+ * PMIC battery initializes its internal data structue and other -+ * infrastructure components for it to work as expected. -+ */ -+static int pmic_battery_probe(struct spi_device *spi) -+{ -+ int retval = 0; -+ struct pmic_power_module_info *pbi = 0; -+ -+ if (PMIC_BATT_DEBUG) -+ printk(KERN_INFO "pmic-battery: %s() - found pmic battery " -+ "device\n", __func__); -+ -+ pbi = kzalloc(sizeof(*pbi), GFP_KERNEL); -+ if (!pbi) { -+ dev_err(&spi->dev, "%s(): memory allocation failed\n", -+ __func__); -+ return -ENOMEM; -+ } -+ -+ pbi->spi = spi; -+ pbi->irq = spi->irq; -+ dev_set_drvdata(&spi->dev, pbi); -+ -+ /* initialize all required framework before enabling interrupts */ -+ INIT_WORK(&pbi->handler, (void *)pmic_battery_handle_intrpt); -+ INIT_DELAYED_WORK(&pbi->monitor_battery, pmic_battery_monitor); -+ pbi->monitor_wqueue = -+ create_singlethread_workqueue(dev_name(&spi->dev)); -+ if (!pbi->monitor_wqueue) { -+ dev_err(&spi->dev, "%s(): wqueue init failed\n", __func__); -+ retval = -ESRCH; -+ goto wqueue_failed; -+ } -+ -+ /* register interrupt */ -+ retval = request_irq(pbi->irq, pmic_battery_interrupt_handler, -+ 0, DRIVER_NAME, pbi); -+ if (retval) { -+ dev_err(&spi->dev, "%s(): cannot get IRQ\n", __func__); -+ goto requestirq_failed; -+ } -+ -+ /* register pmic-batt with power supply subsystem */ -+ pbi->batt.name = "pmic-batt"; -+ pbi->batt.type = POWER_SUPPLY_TYPE_BATTERY; -+ pbi->batt.properties = pmic_battery_props; -+ pbi->batt.num_properties = ARRAY_SIZE(pmic_battery_props); -+ pbi->batt.get_property = pmic_battery_get_property; -+ retval = power_supply_register(&spi->dev, &pbi->batt); -+ if (retval) { -+ dev_err(&spi->dev, "%s(): failed to register pmic battery " -+ "device with power supply subsystem\n", -+ __func__); -+ goto power_reg_failed; -+ } -+ -+ if (PMIC_BATT_DEBUG) -+ printk(KERN_INFO "pmic-battery: %s() - pmic battery device " -+ "registration with power supply subsystem " -+ "successful\n", __func__); -+ -+ queue_delayed_work(pbi->monitor_wqueue, &pbi->monitor_battery, HZ * 1); -+ -+ /* register pmic-usb with power supply subsystem */ -+ pbi->usb.name = "pmic-usb"; -+ pbi->usb.type = POWER_SUPPLY_TYPE_USB; -+ pbi->usb.properties = pmic_usb_props; -+ pbi->usb.num_properties = ARRAY_SIZE(pmic_usb_props); -+ pbi->usb.get_property = pmic_usb_get_property; -+ retval = power_supply_register(&spi->dev, &pbi->usb); -+ if (retval) { -+ dev_err(&spi->dev, "%s(): failed to register pmic usb " -+ "device with power supply subsystem\n", -+ __func__); -+ goto power_reg_failed_1; -+ } -+ -+ if (PMIC_BATT_DEBUG) -+ printk(KERN_INFO "pmic-battery: %s() - pmic usb device " -+ "registration with power supply subsystem successful\n", -+ __func__); -+ -+ return retval; -+ -+power_reg_failed_1: -+ power_supply_unregister(&pbi->batt); -+power_reg_failed: -+ cancel_rearming_delayed_workqueue(pbi->monitor_wqueue, -+ &pbi->monitor_battery); -+requestirq_failed: -+ destroy_workqueue(pbi->monitor_wqueue); -+wqueue_failed: -+ kfree(pbi); -+ -+ return retval; -+} -+ -+/** -+ * pmic_battery_remove - pmic battery finalize -+ * @spi: pmic battery spi device structure -+ * Context: can sleep -+ * -+ * PMIC battery finalizes its internal data structue and other -+ * infrastructure components that it initialized in -+ * pmic_battery_probe. -+ */ -+static int pmic_battery_remove(struct spi_device *spi) -+{ -+ struct pmic_power_module_info *pbi = dev_get_drvdata(&spi->dev); -+ -+ if (pbi) { -+ free_irq(pbi->irq, pbi); -+ -+ cancel_rearming_delayed_workqueue(pbi->monitor_wqueue, -+ &pbi->monitor_battery); -+ destroy_workqueue(pbi->monitor_wqueue); -+ -+ power_supply_unregister(&pbi->usb); -+ power_supply_unregister(&pbi->batt); -+ -+ flush_scheduled_work(); -+ -+ kfree(pbi); -+ } -+ -+ return 0; -+} -+ -+ -+/********************************************************************* -+ * Driver initialisation and finalization -+ *********************************************************************/ -+ -+static struct spi_driver pmic_battery_driver = { -+ .driver = { -+ .name = DRIVER_NAME, -+ .bus = &spi_bus_type, -+ .owner = THIS_MODULE, -+ }, -+ .probe = pmic_battery_probe, -+ .remove = __devexit_p(pmic_battery_remove), -+}; -+ -+ -+static int __init pmic_battery_module_init(void) -+{ -+ return spi_register_driver(&pmic_battery_driver); -+} -+ -+static void __exit pmic_battery_module_exit(void) -+{ -+ spi_unregister_driver(&pmic_battery_driver); -+} -+ -+module_init(pmic_battery_module_init); -+module_exit(pmic_battery_module_exit); --- -1.6.2.5 - |