RE: [Resending - PATCH 2/3] Triton BCI driver for OMAP3430

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



Hi, 

Some comments inlined below.

>-----Original Message-----
>From: Madhusudhan Chikkature<madhu.cr@xxxxxx>
>
>ARM: OMAP: Triton Battery Charger Interface
>
>This patch provides a OMAP Triton battery charger interface 
>driver to moniter
>the battery
>through power class subsystem.
>
>Signed-off-by: Madhusudhan Chikkature<madhu.cr@xxxxxx>
>---
> drivers/power/Kconfig               |    8
> drivers/power/Makefile              |    1
> drivers/power/twl4030_bci_battery.c | 1139 
>++++++++++++++++++++++++++++++++++++
> 3 files changed, 1148 insertions(+)
>
>Index: linux-omap-2.6/drivers/power/Kconfig
>===================================================================
>--- linux-omap-2.6.orig/drivers/power/Kconfig	2008-06-16 
>16:46:52.000000000 +0530
>+++ linux-omap-2.6/drivers/power/Kconfig	2008-06-27 
>16:01:08.000000000 +0530
>@@ -70,4 +70,12 @@ config BATTERY_BQ27200
> 	help
> 	  Say Y here to enable support for batteries with 
>BQ27200(I2C) chip.
>
>+config TWL4030_BCI_BATTERY
>+	tristate "OMAP TWL4030 BCI Battery driver"
>+	depends on (MACH_OMAP_2430SDP || MACH_OMAP_3430SDP) && 
>TWL4030_CORE
>+	default y
>+	help
>+	  Support for OMAP TWL4030 BCI Battery driver.
>+	  This driver can give support for TWL4030 Battery 
>Charge Interface.
>+
> endif # POWER_SUPPLY
>Index: linux-omap-2.6/drivers/power/Makefile
>===================================================================
>--- linux-omap-2.6.orig/drivers/power/Makefile	2008-06-16 
>16:46:52.000000000 +0530
>+++ linux-omap-2.6/drivers/power/Makefile	2008-06-27 
>15:53:29.000000000 +0530
>@@ -21,3 +21,4 @@ obj-$(CONFIG_BATTERY_DS2760)	+= ds2760_b
> obj-$(CONFIG_BATTERY_PMU)	+= pmu_battery.o
> obj-$(CONFIG_BATTERY_OLPC)	+= olpc_battery.o
> obj-$(CONFIG_BATTERY_BQ27x00)   += bq27x00_battery.o
>+obj-$(CONFIG_TWL4030_BCI_BATTERY)	+= twl4030_bci_battery.o
>Index: linux-omap-2.6/drivers/power/twl4030_bci_battery.c
>===================================================================
>--- /dev/null	1970-01-01 00:00:00.000000000 +0000
>+++ linux-omap-2.6/drivers/power/twl4030_bci_battery.c	2008-07-03
>16:10:11.000000000 +0530
>@@ -0,0 +1,1139 @@
>+/*
>+ * linux/drivers/power/twl4030_bci_battery.c
>+ *
>+ * OMAP2430/3430 BCI battery driver for Linux
>+ *
>+ * Copyright (C) 2008 Texas Instruments, Inc.
>+ * Author: Texas Instruments, Inc.
>+ *
>+ * This package is free software; you can redistribute it 
>and/or modify
>+ * it under the terms of the GNU General Public License version 2 as
>+ * published by the Free Software Foundation.
>+ *
>+ * THIS PACKAGE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
>+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
>+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
>+ */
>+
>+#include <linux/init.h>
>+#include <linux/module.h>
>+#include <linux/device.h>
>+#include <linux/interrupt.h>
>+#include <linux/delay.h>
>+#include <linux/platform_device.h>
>+#include <linux/i2c/twl4030.h>
>+#include <linux/power_supply.h>
>+
>+#define T2_BATTERY_VOLT		0x04
>+#define T2_BATTERY_TEMP		0x06
>+#define T2_BATTERY_CUR		0x08
>+
>+/* charger constants */
>+#define NO_PW_CONN		0
>+#define AC_PW_CONN		0x01
>+#define USB_PW_CONN		0x02
>+
>+/* TWL4030_MODULE_USB */
>+#define REG_POWER_CTRL		0x0AC
>+#define OTG_EN			0x020
>+#define REG_PHY_CLK_CTRL	0x0FE
>+#define REG_PHY_CLK_CTRL_STS	0x0FF
>+#define PHY_DPLL_CLK		0x01
>+
>+#define REG_BCICTL1 		0x023
>+#define REG_BCICTL2 		0x024
>+#define CGAIN			0x020
>+#define ITHEN			0x010
>+#define ITHSENS			0x007
>+
>+/* Boot BCI flag bits */
>+#define BCIAUTOWEN		0x020
>+#define CONFIG_DONE		0x010
>+#define BCIAUTOUSB		0x002
>+#define BCIAUTOAC		0x001
>+#define BCIMSTAT_MASK		0x03F
>+
>+/* Boot BCI register */
>+#define REG_BOOT_BCI		0x007
>+#define REG_CTRL1		0x00
>+#define MADC_ON			0x01
>+#define REG_SW1SELECT_MSB	0x07
>+#define SW1_CH9_SEL		0x02
>+#define REG_CTRL_SW1		0x012
>+#define SW1_TRIGGER		0x020
>+#define EOC_SW1			0x002
>+#define REG_GPCH9		0x049
>+#define REG_STS_HW_CONDITIONS	0x0F
>+#define STS_VBUS		0x080
>+#define STS_CHG			0x02
>+#define REG_BCIMSTATEC		0x02
>+#define REG_BCIMFSTS4		0x010
>+#define REG_BCIMFSTS2		0x00E
>+#define REG_BCIMFSTS3 		0x00F
>+#define REG_BCIMFSTS1		0x001
>+#define USBFASTMCHG		0x004
>+#define BATSTSPCHG		0x004
>+#define BATSTSMCHG		0x040
>+#define VBATOV4			0x020
>+#define VBATOV3			0x010
>+#define VBATOV2			0x008
>+#define VBATOV1			0x004
>+#define MADC_LSB_MASK		0xC0
>+#define REG_BB_CFG		0x012
>+#define BBCHEN			0x010
>+
>+/* Power supply charge interrupt */
>+#define REG_PWR_ISR1		0x00
>+#define REG_PWR_IMR1		0x01
>+#define REG_PWR_EDR1		0x05
>+#define REG_PWR_SIH_CTRL	0x007
>+
>+#define USB_PRES		0x004
>+#define CHG_PRES		0x002
>+
>+#define USB_PRES_RISING		0x020
>+#define USB_PRES_FALLING	0x010
>+#define CHG_PRES_RISING		0x008
>+#define CHG_PRES_FALLING	0x004
>+#define AC_STATEC		0x20
>+#define COR			0x004
>+
>+/* interrupt status registers */
>+#define REG_BCIISR1A 		0x0
>+#define REG_BCIISR2A 		0x01
>+
>+/* Interrupt flags bits BCIISR1 */
>+#define BATSTS_ISR1		0x080
>+#define VBATLVL_ISR1		0x001
>+
>+/* Interrupt mask registers for int1*/
>+#define REG_BCIIMR1A		0x002
>+#define REG_BCIIMR2A		0x003
>+
>+ /* Interrupt masks for BCIIMR1 */
>+#define BATSTS_IMR1		0x080
>+#define VBATLVL_IMR1		0x001
>+
>+/* Interrupt edge detection register */
>+#define REG_BCIEDR1		0x00A
>+#define REG_BCIEDR2		0x00B
>+#define REG_BCIEDR3		0x00C
>+
>+/* BCIEDR2 */
>+#define	BATSTS_EDRRISIN		0x080
>+#define BATSTS_EDRFALLING	0x040
>+
>+/* BCIEDR3 */
>+#define	VBATLVL_EDRRISIN	0x02
>+
>+/* Step size and prescaler ratio */
>+#define TEMP_STEP_SIZE		147
>+#define TEMP_PSR_R		100
>+
>+#define VOLT_STEP_SIZE		588
>+#define VOLT_PSR_R		100
>+
>+#define CURR_STEP_SIZE		147
>+#define CURR_PSR_R1		44
>+#define CURR_PSR_R2		80
>+
>+#define BK_VOLT_STEP_SIZE	441
>+#define BK_VOLT_PSR_R		100
>+
>+#define ENABLE		1
>+#define DISABLE		1
>+
>+static int twl4030_bci_battery_probe(struct platform_device *dev);
>+static int twl4030_bci_battery_remove(struct platform_device *dev);
>+#ifdef CONFIG_PM
>+static int twl4030_bci_battery_suspend(struct platform_device *dev,
>+					pm_message_t state);
>+static int twl4030_bci_battery_resume(struct platform_device *dev);
>+#endif
>+
>+struct twl4030_bci_device_info {
>+	struct device		*dev;
>+
>+	unsigned long		update_time;
>+	int			voltage_uV;
>+	int			bk_voltage_uV;
>+	int			current_uA;
>+	int			temp_C;
>+	int			charge_rsoc;
>+	int			charge_status;
>+
>+	struct power_supply	bat;
>+	struct power_supply	bk_bat;
>+	struct delayed_work	twl4030_bci_monitor_work;
>+	struct delayed_work	twl4030_bk_bci_monitor_work;
>+};
>+
>+static struct platform_driver twl4030_bci_battery_driver = {
>+	.probe =	twl4030_bci_battery_probe,
>+	.remove =	twl4030_bci_battery_remove,
>+#ifdef CONFIG_PM
>+	.suspend =	twl4030_bci_battery_suspend,
>+	.resume =	twl4030_bci_battery_resume,
>+#endif
>+	.driver = {
>+		.name = "twl4030-bci-battery",
>+	},
>+};
>+
>+static int usb_charger_flag;
>+static int LVL_1, LVL_2, LVL_3, LVL_4;
>+
>+static int twl4030madc_sw1_trigger(void);
>+static int read_bci_val(u8 reg_1);
>+static inline int clear_n_set(u8 mod_no, u8 clear, u8 set, u8 reg);
>+static int twl4030charger_presence(void);
>+
>+/*
>+ * Twl4030 battery temperature lookup table.
>+ */
>+const int twl4030battery_temp_tbl [] =
>+{
>+/* 0 C*/
>+27100,
>+26000, 24900, 23900, 22900, 22000, 21100, 20300, 19400, 18700, 17900,
>+17200, 16500, 15900, 15300, 14700, 14100, 13600, 13100, 12600, 12100,
>+11600, 11200, 10800, 10400, 10000, 9630,   9280,   8950,   
>8620,   8310,
>+8020,   7730,   7460,   7200,   6950,   6710,   6470,   6250, 
>  6040,   5830,
>+5640,   5450,   5260,   5090,   4920,   4760,   4600,   4450, 
>  4310,   4170,
>+4040,   3910,   3790,   3670,   3550
>+};

Please mention the thermistor name/code (and possibly a reference to the
spec)
which gives these temperature characteristics. How about boards with
other 
thermistors than this? Negative temperatures?

>+
>+/*
>+ * Report and clear the charger presence event.
>+ */
>+static inline int twl4030charger_presence_evt(void)
>+{
>+	int ret;
>+	u8 chg_sts, set = 0, clear = 0;
>+
>+	/* read charger power supply status */
>+	ret = twl4030_i2c_read_u8(TWL4030_MODULE_PM_MASTER, &chg_sts,
>+		REG_STS_HW_CONDITIONS);
>+	if (ret)
>+		return IRQ_NONE;
>+
>+	/* If the AC charger have been connected */
>+	if (chg_sts & STS_CHG) {
>+		/* configuring falling edge detection for CHG_PRES */
>+		set = CHG_PRES_FALLING;
>+		clear = CHG_PRES_RISING;
>+	}
>+	/* If the AC charger have been disconnected */
>+	else {
>+		/* configuring rising edge detection for CHG_PRES */
>+		set = CHG_PRES_RISING;
>+		clear = CHG_PRES_FALLING;
>+	}
>+
>+	/* Update the interrupt edge detection register */
>+	clear_n_set(TWL4030_MODULE_INT, clear, set, REG_PWR_EDR1);
>+
>+	return 0;
>+}
>+
>+/*
>+ * Interrupt service routine
>+ *
>+ * Attends to TWL 4030 power module interruptions events, specifically
>+ * USB_PRES (USB charger presence) CHG_PRES (AC charger 
>presence) events
>+ *
>+ */
>+static irqreturn_t twl4030charger_interrupt(int irq, void *dev_id)
>+{
>+	struct twl4030_bci_device_info *di = dev_id;
>+
>+	twl4030charger_presence_evt();
>+	power_supply_changed(&di->bat);
>+
>+	return IRQ_HANDLED;
>+}
>+
>+/*
>+ * This function handles the twl4030 battery presence interrupt
>+ */
>+static int twl4030battery_presence_evt(void)
>+{
>+	int ret;
>+	u8 batstsmchg, batstspchg;
>+
>+	/* check for the battery presence in main charge*/
>+	ret = twl4030_i2c_read_u8(TWL4030_MODULE_MAIN_CHARGE,
>+			&batstsmchg, REG_BCIMFSTS3);
>+	if (ret)
>+		return ret;
>+
>+	/* check for the battery presence in precharge */
>+	ret = twl4030_i2c_read_u8(TWL4030_MODULE_PRECHARGE,
>+			&batstspchg, REG_BCIMFSTS1);
>+	if (ret)
>+		return ret;
>+
>+	/*
>+	 * REVISIT: Physically inserting/removing the batt
>+	 * does not seem to generate an int on 3430ES2 SDP.
>+	 */
>+
>+	/* In case of the battery insertion event */
>+	if ((batstspchg & BATSTSPCHG) || (batstsmchg & BATSTSMCHG)) {
>+		ret = clear_n_set(TWL4030_MODULE_INTERRUPTS, 
>BATSTS_EDRRISIN,
>+			BATSTS_EDRFALLING, REG_BCIEDR2);
>+		if (ret)
>+			return ret;
>+	}
>+
>+	/* In case of the battery removal event */
>+	else {
>+		ret = clear_n_set(TWL4030_MODULE_INTERRUPTS, 
>BATSTS_EDRFALLING,
>+			BATSTS_EDRRISIN, REG_BCIEDR2);
>+		if (ret)
>+			return ret;
>+	}
>+
>+	return 0;
>+}
>+
>+/*
>+ * This function handles the twl4030 battery voltage level interrupt.
>+ */
>+static int twl4030battery_level_evt(void)
>+{
>+	int ret;
>+	u8 mfst;
>+
>+	/* checking for threshold event */
>+	ret = twl4030_i2c_read_u8(TWL4030_MODULE_MAIN_CHARGE,
>+			&mfst, REG_BCIMFSTS2);
>+	if (ret)
>+		return ret;
>+
>+	if (mfst & VBATOV4) {
>+		LVL_4 = 1;
>+		LVL_3 = LVL_2 = LVL_1 = 0;
>+	} else if (mfst & VBATOV3) {
>+		LVL_3 = 1;
>+		LVL_4 = LVL_2 = LVL_1 = 0;
>+	} else if (mfst & VBATOV2) {
>+		LVL_2 = 1;
>+		LVL_4 = LVL_3 = LVL_1 = 0;
>+	} else {
>+		LVL_1 = 1;
>+		LVL_4 = LVL_3 = LVL_2 = 0;
>+	}
>+
>+	return 0;
>+}
>+
>+/*
>+ * Interrupt service routine
>+ *
>+ * Attends to BCI interruptions events,
>+ * specifically BATSTS (battery connection and removal)
>+ * VBATOV (main battery voltage threshold) events
>+ *
>+ */
>+static irqreturn_t twl4030battery_interrupt(int irq, void *dev_id)
>+{
>+	int ret;
>+	u8 isr1a_val, isr2a_val, clear_2a, clear_1a;
>+
>+	ret = twl4030_i2c_read_u8(TWL4030_MODULE_INTERRUPTS, &isr1a_val,
>+				REG_BCIISR1A);
>+	if (ret)
>+		return IRQ_NONE;
>+
>+	ret = twl4030_i2c_read_u8(TWL4030_MODULE_INTERRUPTS, &isr2a_val,
>+				REG_BCIISR2A);
>+	if (ret)
>+		return IRQ_NONE;
>+
>+	clear_2a = (isr2a_val & VBATLVL_ISR1)? (VBATLVL_ISR1): 0;
>+	clear_1a = (isr1a_val & BATSTS_ISR1)? (BATSTS_ISR1): 0;
>+
>+	/* cleaning BCI interrupt status flags */
>+	ret = twl4030_i2c_write_u8(TWL4030_MODULE_INTERRUPTS,
>+			clear_1a , REG_BCIISR1A);
>+	if (ret)
>+		return IRQ_NONE;
>+
>+	ret = twl4030_i2c_write_u8(TWL4030_MODULE_INTERRUPTS,
>+			clear_2a , REG_BCIISR2A);
>+	if (ret)
>+		return IRQ_NONE;
>+
>+	/* battery connetion or removal event */
>+	if (isr1a_val & BATSTS_ISR1)
>+		twl4030battery_presence_evt();
>+	/* battery voltage threshold event*/
>+	else if (isr2a_val & VBATLVL_ISR1)
>+		twl4030battery_level_evt();
>+	else
>+		return IRQ_NONE;
>+
>+	return IRQ_HANDLED;
>+}
>+
>+/*
>+ * Enable/Disable hardware battery level event notifications.
>+ */
>+static int twl4030battery_hw_level_en(int enable)
>+{
>+	int ret;
>+
>+	if (enable) {
>+		/* unmask VBATOV interrupt for INT1 */
>+		ret = clear_n_set(TWL4030_MODULE_INTERRUPTS, 
>VBATLVL_IMR1,
>+			0, REG_BCIIMR2A);
>+		if (ret)
>+			return ret;
>+
>+		/* configuring interrupt edge detection for VBATOv */
>+		ret = clear_n_set(TWL4030_MODULE_INTERRUPTS, 0,
>+			VBATLVL_EDRRISIN, REG_BCIEDR3);
>+		if (ret)
>+			return ret;
>+	} else {
>+		/* mask VBATOV interrupt for INT1 */
>+		ret = clear_n_set(TWL4030_MODULE_INTERRUPTS, 0,
>+			VBATLVL_IMR1, REG_BCIIMR2A);
>+		if (ret)
>+			return ret;
>+	}
>+
>+	return 0;
>+}
>+
>+/*
>+ * Enable/disable hardware battery presence event notifications.
>+ */
>+static int twl4030battery_hw_presence_en(int enable)
>+{
>+	int ret;
>+
>+	if (enable) {
>+		/* unmask BATSTS interrupt for INT1 */
>+		ret = clear_n_set(TWL4030_MODULE_INTERRUPTS, 
>BATSTS_IMR1,
>+			0, REG_BCIIMR1A);
>+		if (ret)
>+			return ret;
>+
>+		/* configuring interrupt edge for BATSTS */
>+		ret = clear_n_set(TWL4030_MODULE_INTERRUPTS, 0,
>+			BATSTS_EDRRISIN | BATSTS_EDRFALLING, 
>REG_BCIEDR2);
>+		if (ret)
>+			return ret;
>+	} else {
>+		/* mask BATSTS interrupt for INT1 */
>+		ret = clear_n_set(TWL4030_MODULE_INTERRUPTS, 0,
>+			BATSTS_IMR1, REG_BCIIMR1A);
>+		if (ret)
>+			return ret;
>+	}
>+
>+	return 0;
>+}
>+
>+/*
>+ * Enable/Disable AC Charge funtionality.
>+ */
>+static int twl4030charger_ac_en(int enable)
>+{
>+	int ret;
>+
>+	if (enable) {
>+		/* forcing the field BCIAUTOAC (BOOT_BCI[0) to 1 */
>+		ret = clear_n_set(TWL4030_MODULE_PM_MASTER, 0,
>+			(CONFIG_DONE | BCIAUTOWEN | BCIAUTOAC),
>+			REG_BOOT_BCI);
>+		if (ret)
>+			return ret;
>+	} else {
>+		/* forcing the field BCIAUTOAC (BOOT_BCI[0) to 0*/
>+		ret = clear_n_set(TWL4030_MODULE_PM_MASTER, BCIAUTOAC,
>+			(CONFIG_DONE | BCIAUTOWEN),
>+			REG_BOOT_BCI);
>+		if (ret)
>+			return ret;
>+	}
>+	return 0;
>+}
>+
>+/*
>+ * Enable/Disable USB Charge funtionality.
>+ */
>+int twl4030charger_usb_en(int enable)
>+{
>+	u8 value;
>+	int ret;
>+	unsigned long timeout;
>+
>+	if (enable) {
>+		/* Check for USB charger conneted */
>+		ret = twl4030charger_presence();
>+		if (ret < 0)
>+			return ret;
>+
>+		if (!(ret & USB_PW_CONN))
>+			return -ENXIO;
>+
>+		/* forcing the field BCIAUTOUSB (BOOT_BCI[1]) to 1 */
>+		ret = clear_n_set(TWL4030_MODULE_PM_MASTER, 0,
>+			(CONFIG_DONE | BCIAUTOWEN | BCIAUTOUSB),
>+			REG_BOOT_BCI);
>+		if (ret)
>+			return ret;
>+
>+		ret = clear_n_set(TWL4030_MODULE_USB, 0, PHY_DPLL_CLK,
>+			REG_PHY_CLK_CTRL);
>+		if (ret)
>+			return ret;
>+
>+		value = 0;
>+		timeout = jiffies + msecs_to_jiffies(50);
>+
>+		while ((!(value & PHY_DPLL_CLK)) &&
>+			time_before(jiffies, timeout)) {
>+			udelay(10);
>+			ret = 
>twl4030_i2c_read_u8(TWL4030_MODULE_USB, &value,
>+				REG_PHY_CLK_CTRL_STS);
>+			if (ret)
>+				return ret;
>+		}
>+
>+		/* OTG_EN (POWER_CTRL[5]) to 1 */
>+		ret = clear_n_set(TWL4030_MODULE_USB, 0, OTG_EN,
>+			REG_POWER_CTRL);
>+		if (ret)
>+			return ret;
>+
>+		mdelay(50);
>+
>+		/* forcing USBFASTMCHG(BCIMFSTS4[2]) to 1 */
>+		ret = clear_n_set(TWL4030_MODULE_MAIN_CHARGE, 0,
>+			USBFASTMCHG, REG_BCIMFSTS4);
>+		if (ret)
>+			return ret;
>+	} else {
>+		twl4030charger_presence();
>+		ret = clear_n_set(TWL4030_MODULE_PM_MASTER, BCIAUTOUSB,
>+			(CONFIG_DONE | BCIAUTOWEN), REG_BOOT_BCI);
>+		if (ret)
>+			return ret;
>+	}
>+
>+	return 0;
>+}
>+
>+/*
>+ * Return battery temperature
>+ * Or < 0 on failure.
>+ */
>+static int twl4030battery_temperature(void)
>+{
>+	u8 val;
>+	int temp, curr, volt, res, ret;
>+
>+	/* Getting and calculating the thermistor voltage */
>+	ret = read_bci_val(T2_BATTERY_TEMP);
>+	if (ret < 0)
>+		return ret;
>+
>+	volt = (ret * TEMP_STEP_SIZE) / TEMP_PSR_R;
>+
>+	/* Getting and calculating the supply current in micro ampers */
>+	ret = twl4030_i2c_read_u8(TWL4030_MODULE_MAIN_CHARGE, &val,
>+		 REG_BCICTL2);
>+	if (ret)
>+		return 0;
>+
>+	curr = ((val & ITHSENS) + 1) * 10;
>+
>+	/* Getting and calculating the thermistor resistance in ohms*/
>+	res = volt * 1000 / curr;
>+
>+	/*calculating temperature*/
>+	for (temp = 55; temp >= 0; temp--) {
>+		int actual = twl4030battery_temp_tbl [temp];
>+		if ((actual - res) >= 0)
>+			break;
>+	}
>+
>+	return temp + 1;
>+}
>+
>+/*
>+ * Return battery voltage
>+ * Or < 0 on failure.
>+ */
>+static int twl4030battery_voltage(void)
>+{

perhaps use twl4030-madc driver?

>+	int volt = read_bci_val(T2_BATTERY_VOLT);
>+
>+	return (volt * VOLT_STEP_SIZE) / VOLT_PSR_R;
>+}
>+
>+/*
>+ * Return the battery current
>+ * Or < 0 on failure.
>+ */
>+static int twl4030battery_current(void)
>+{

check twl4030-madc.

>+	int ret, curr = read_bci_val(T2_BATTERY_CUR);
>+	u8 val;
>+
>+	ret = twl4030_i2c_read_u8(TWL4030_MODULE_MAIN_CHARGE, &val,
>+		REG_BCICTL1);
>+	if (ret)
>+		return ret;
>+
>+	if (val & CGAIN) /* slope of 0.44 mV/mA */
>+		return (curr * CURR_STEP_SIZE) / CURR_PSR_R1;
>+	else /* slope of 0.88 mV/mA */
>+		return (curr * CURR_STEP_SIZE) / CURR_PSR_R2;
>+}
>+
>+/*
>+ * Return the battery backup voltage
>+ * Or < 0 on failure.
>+ */
>+static int twl4030backupbatt_voltage(void)
>+{
>

check twl4030-madc.

+	int ret, temp;
>+	u8 volt;
>+
>+	/* trigger MADC convertion */
>+	twl4030madc_sw1_trigger();
>+
>+	ret = twl4030_i2c_read_u8(TWL4030_MODULE_MADC, &volt,
>+			REG_GPCH9 + 1);
>+	if (ret)
>+		return ret;
>+
>+	temp = ((int) volt) << 2;
>+
>+	ret = twl4030_i2c_read_u8(TWL4030_MODULE_MADC, &volt,
>+		REG_GPCH9);
>+	if (ret)
>+		return ret;
>+
>+	temp = temp + ((int) ((volt & MADC_LSB_MASK) >> 6));
>+
>+	return  (temp * BK_VOLT_STEP_SIZE) / BK_VOLT_PSR_R;
>+}
>+
>+/*
>+ * Returns an integer value, that means,
>+ * NO_PW_CONN  no power supply is connected
>+ * AC_PW_CONN  if the AC power supply is connected
>+ * USB_PW_CONN  if the USB power supply is connected
>+ * AC_PW_CONN + USB_PW_CONN if USB and AC power supplies are 
>both connected
>+ *
>+ * Or < 0 on failure.
>+ */
>+static int twl4030charger_presence(void)
>+{
>+	int ret;
>+	u8 hwsts;
>+
>+	ret = twl4030_i2c_read_u8(TWL4030_MODULE_PM_MASTER, &hwsts,
>+		REG_STS_HW_CONDITIONS);
>+	if (ret) {
>+		pr_err("BATTERY DRIVER: error reading 
>STS_HW_CONDITIONS \n");
>+		return ret;
>+	}
>+
>+	ret = (hwsts & STS_CHG)? AC_PW_CONN: NO_PW_CONN;
>+	ret += (hwsts & STS_VBUS)? USB_PW_CONN: NO_PW_CONN;
>+
>+	if (ret & USB_PW_CONN)
>+		usb_charger_flag = 1;
>+	else
>+		usb_charger_flag = 0;
>+
>+	return ret;
>+
>+}
>+
>+/*
>+ * Returns the main charge FSM status
>+ * Or < 0 on failure.
>+ */
>+static int twl4030bci_status(void)
>+{
>+	int ret;
>+	u8 status;
>+
>+	ret = twl4030_i2c_read_u8(TWL4030_MODULE_MAIN_CHARGE,
>+		&status, REG_BCIMSTATEC);
>+	if (ret) {
>+		pr_err("BATTERY DRIVER: error reading BCIMSTATEC \n");
>+		return ret;
>+	}
>+
>+	return (int) (status & BCIMSTAT_MASK);
>+}
>+
>+static int read_bci_val(u8 reg)
>+{

check twl4030-madc.

>+	int ret, temp;
>+	u8 val;
>+
>+	/* reading MSB */
>+	ret = twl4030_i2c_read_u8(TWL4030_MODULE_MAIN_CHARGE, &val,
>+		reg + 1);
>+	if (ret)
>+		return ret;
>+
>+	temp = ((int)(val & 0x03)) << 8;
>+
>+	/* reading LSB */
>+	ret = twl4030_i2c_read_u8(TWL4030_MODULE_MAIN_CHARGE, &val,
>+		reg);
>+	if (ret)
>+		return ret;
>+
>+	return temp | val;
>+}
>+
>+/*
>+ * Triggers the sw1 request for the twl4030 module to measure 
>the sw1 selected
>+ * channels
>+ */
>+static int twl4030madc_sw1_trigger(void)
>+{

check twl4030-madc.

>+	u8 val;
>+	int ret;
>+
>+	/* Triggering SW1 MADC convertion */
>+	ret = twl4030_i2c_read_u8(TWL4030_MODULE_MADC, &val,
>+		REG_CTRL_SW1);
>+	if (ret)
>+		return ret;
>+
>+	val |= SW1_TRIGGER;
>+
>+	ret = twl4030_i2c_write_u8(TWL4030_MODULE_MADC, val,
>+		REG_CTRL_SW1);
>+	if (ret)
>+		return ret;
>+
>+	/* Waiting until the SW1 conversion ends*/
>+	val = 0;
>+
>+	while (!(val & EOC_SW1)) {
>+		ret = twl4030_i2c_read_u8(TWL4030_MODULE_MADC, &val,
>+			REG_CTRL_SW1);
>+		if (ret)
>+			return ret;
>+		mdelay(10);
>+	}
>+
>+	return 0;
>+}
>+
>+/*
>+ * Settup the twl4030 MADC module to measure the backup
>+ * battery voltage.
>+ */
>+static int twl4030backupbatt_voltage_setup(void)
>+{
>+	int ret;
>+
>+	/* turning adc_on */
>+	ret = twl4030_i2c_write_u8(TWL4030_MODULE_MADC, MADC_ON,
>+		REG_CTRL1);
>+	if (ret)
>+		return ret;
>+
>+	/*setting MDC channel 9 to trigger by SW1*/
>+	ret = clear_n_set(TWL4030_MODULE_MADC, 0, SW1_CH9_SEL,
>+		REG_SW1SELECT_MSB);
>+	if (ret)
>+		return ret;
>+
>+	/* Starting backup batery charge */
>+	ret = clear_n_set(TWL4030_MODULE_PM_RECEIVER, 0, BBCHEN,
>+		REG_BB_CFG);
>+	if (ret)
>+		return ret;
>+
>+	return 0;
>+}
>+
>+/*
>+ * Settup the twl4030 BCI and MADC module to measure battery
>+ * temperature
>+ */
>+static int twl4030battery_temp_setup(void)
>+{
>+	int ret;
>+
>+	/* Enabling thermistor current */
>+	ret = clear_n_set(TWL4030_MODULE_MAIN_CHARGE, 0, ITHEN,
>+		REG_BCICTL1);
>+	if (ret)
>+		return ret;
>+
>+	return 0;
>+}
>+
>+/*
>+ * Sets and clears bits on an given register on a given module
>+ */
>+static inline int clear_n_set(u8 mod_no, u8 clear, u8 set, u8 reg)
>+{
>+	int ret;
>+	u8 val = 0;
>+
>+	/* Gets the initial register value */
>+	ret = twl4030_i2c_read_u8(mod_no, &val, reg);
>+	if (ret)
>+		return ret;
>+
>+	/* Clearing all those bits to clear */
>+	val &= ~(clear);
>+
>+	/* Setting all those bits to set */
>+	val |= set;
>+
>+	/* Update the register */
>+	ret = twl4030_i2c_write_u8(mod_no, val, reg);
>+	if (ret)
>+		return ret;
>+
>+	return 0;
>+}
>+
>+static enum power_supply_property twl4030_bci_battery_props[] = {
>+	POWER_SUPPLY_PROP_STATUS,
>+	POWER_SUPPLY_PROP_ONLINE,
>+	POWER_SUPPLY_PROP_VOLTAGE_NOW,
>+	POWER_SUPPLY_PROP_CURRENT_NOW,
>+	POWER_SUPPLY_PROP_CAPACITY,
>+	POWER_SUPPLY_PROP_TEMP,
>+};
>+
>+static enum power_supply_property twl4030_bk_bci_battery_props[] = {
>+	POWER_SUPPLY_PROP_VOLTAGE_NOW,
>+};
>+
>+static void
>+twl4030_bk_bci_battery_read_status(struct twl4030_bci_device_info *di)
>+{
>+	di->bk_voltage_uV = twl4030backupbatt_voltage();
>+}
>+
>+static void twl4030_bk_bci_battery_work(struct work_struct *work)
>+{
>+	struct twl4030_bci_device_info *di = container_of(work,
>+		struct twl4030_bci_device_info,
>+		twl4030_bk_bci_monitor_work.work);
>+
>+	twl4030_bk_bci_battery_read_status(di);
>+	schedule_delayed_work(&di->twl4030_bk_bci_monitor_work, 500);
>+}
>+
>+static void twl4030_bci_battery_read_status(struct 
>twl4030_bci_device_info *di)
>+{
>+	di->temp_C = twl4030battery_temperature();
>+	di->voltage_uV = twl4030battery_voltage();
>+	di->current_uA = twl4030battery_current();
>+}
>+
>+static void
>+twl4030_bci_battery_update_status(struct twl4030_bci_device_info *di)
>+{
>+	twl4030_bci_battery_read_status(di);
>+	di->charge_status = POWER_SUPPLY_STATUS_UNKNOWN;
>+
>+	if (power_supply_am_i_supplied(&di->bat))
>+		di->charge_status = POWER_SUPPLY_STATUS_CHARGING;
>+	else
>+		di->charge_status = POWER_SUPPLY_STATUS_DISCHARGING;
>+}
>+
>+static void twl4030_bci_battery_work(struct work_struct *work)
>+{
>+	struct twl4030_bci_device_info *di = container_of(work,
>+		struct twl4030_bci_device_info, 
>twl4030_bci_monitor_work.work);
>+
>+	twl4030_bci_battery_update_status(di);
>+	schedule_delayed_work(&di->twl4030_bci_monitor_work, 100);
>+}
>+
>+
>+#define to_twl4030_bci_device_info(x) container_of((x), \
>+			struct twl4030_bci_device_info, bat);
>+
>+static void twl4030_bci_battery_external_power_changed(struct 
>power_supply *psy)
>+{
>+	struct twl4030_bci_device_info *di = 
>to_twl4030_bci_device_info(psy);
>+
>+	cancel_delayed_work(&di->twl4030_bci_monitor_work);
>+	schedule_delayed_work(&di->twl4030_bci_monitor_work, 0);
>+}
>+
>+#define to_twl4030_bk_bci_device_info(x) container_of((x), \
>+		struct twl4030_bci_device_info, bk_bat);
>+
>+static int twl4030_bk_bci_battery_get_property(struct 
>power_supply *psy,
>+					enum power_supply_property psp,
>+					union power_supply_propval *val)
>+{
>+	struct twl4030_bci_device_info *di = 
>to_twl4030_bk_bci_device_info(psy);
>+
>+	switch (psp) {
>+	case POWER_SUPPLY_PROP_VOLTAGE_NOW:
>+		val->intval = di->bk_voltage_uV;
>+		break;
>+	default:
>+		return -EINVAL;
>+	}
>+
>+	return 0;
>+}
>+
>+static int twl4030_bci_battery_get_property(struct power_supply *psy,
>+					enum power_supply_property psp,
>+					union power_supply_propval *val)
>+{
>+	struct twl4030_bci_device_info *di = 
>to_twl4030_bci_device_info(psy);
>+	int status = 0;
>+
>+	switch (psp) {
>+	case POWER_SUPPLY_PROP_STATUS:
>+		val->intval = di->charge_status;
>+		return 0;
>+	default:
>+		break;
>+	}
>+
>+	switch (psp) {
>+	case POWER_SUPPLY_PROP_VOLTAGE_NOW:
>+		val->intval = di->voltage_uV;
>+		break;
>+	case POWER_SUPPLY_PROP_CURRENT_NOW:
>+		val->intval = di->current_uA;
>+		break;
>+	case POWER_SUPPLY_PROP_TEMP:
>+		val->intval = di->temp_C;
>+		break;
>+	case POWER_SUPPLY_PROP_ONLINE:
>+		status = twl4030bci_status();
>+		if ((status & AC_STATEC) == AC_STATEC)
>+			val->intval = POWER_SUPPLY_TYPE_MAINS;
>+		else if (usb_charger_flag)
>+			val->intval = POWER_SUPPLY_TYPE_USB;
>+		else
>+			val->intval = 0;
>+		break;
>+	case POWER_SUPPLY_PROP_CAPACITY:
>+		/*
>+		 * need to get the correct percentage value per the
>+		 * battery characteristics. Approx values for now.
>+		 */
>+		if (di->voltage_uV < 2894 || LVL_1) {
>+			val->intval = 5;
>+			LVL_1 = 0;
>+		} else if ((di->voltage_uV < 3451 && 
>di->voltage_uV > 2894)
>+			|| LVL_2) {
>+			val->intval = 20;
>+			LVL_2 = 0;
>+		} else if ((di->voltage_uV < 3902 && 
>di->voltage_uV > 3451)
>+			|| LVL_3) {
>+			val->intval = 50;
>+			LVL_3 = 0;
>+		} else if ((di->voltage_uV < 3949 && 
>di->voltage_uV > 3902)
>+			|| LVL_4) {
>+			val->intval = 75;
>+			LVL_4 = 0;
>+		} else if (di->voltage_uV > 3949)
>+			val->intval = 90;
>+		break;
>+	default:
>+		return -EINVAL;
>+	}
>+	return 0;
>+}
>+
>+static char *twl4030_bci_supplied_to[] = {
>+	"twl4030_bci_battery",
>+};
>+
>+static int twl4030_bci_battery_probe(struct  platform_device *dev)
>+{
>+	struct twl4030_bci_device_info *di;
>+	int ret;
>+
>+	di = kzalloc(sizeof(*di), GFP_KERNEL);
>+	if (!di)
>+		return -ENOMEM;
>+
>+	platform_set_drvdata(dev, di);
>+
>+	di->dev = &dev->dev;
>+	di->bat.name = "twl4030_bci_battery";
>+	di->bat.supplied_to = twl4030_bci_supplied_to;
>+	di->bat.num_supplicants = ARRAY_SIZE(twl4030_bci_supplied_to);
>+	di->bat.type = POWER_SUPPLY_TYPE_BATTERY;
>+	di->bat.properties = twl4030_bci_battery_props;
>+	di->bat.num_properties = ARRAY_SIZE(twl4030_bci_battery_props);
>+	di->bat.get_property = twl4030_bci_battery_get_property;
>+	di->bat.external_power_changed =
>+			twl4030_bci_battery_external_power_changed;
>+
>+	di->charge_status = POWER_SUPPLY_STATUS_UNKNOWN;
>+
>+	di->bk_bat.name = "twl4030_bci_bk_battery";
>+	di->bk_bat.type = POWER_SUPPLY_TYPE_BATTERY;
>+	di->bk_bat.properties = twl4030_bk_bci_battery_props;
>+	di->bk_bat.num_properties = 
>ARRAY_SIZE(twl4030_bk_bci_battery_props);
>+	di->bk_bat.get_property = twl4030_bk_bci_battery_get_property;
>+	di->bk_bat.external_power_changed = NULL;
>+
>+	twl4030charger_ac_en(ENABLE);
>+	twl4030charger_usb_en(ENABLE);
>+	twl4030battery_hw_level_en(ENABLE);
>+	twl4030battery_hw_presence_en(ENABLE);
>+
>+	/* settings for temperature sensing */
>+	ret = twl4030battery_temp_setup();
>+	if (ret)
>+		goto temp_setup_fail;
>+
>+	/* enabling GPCH09 for read back battery voltage */
>+	ret = twl4030backupbatt_voltage_setup();
>+	if (ret)
>+		goto voltage_setup_fail;
>+
>+	/* request BCI interruption */
>+	ret = request_irq(TWL4030_MODIRQ_BCI, twl4030battery_interrupt,
>+		IRQF_DISABLED, dev->name, NULL);
>+	if (ret) {
>+		pr_err("BATTERY DRIVER: (BCI) IRQ%d is not free.\n",
>+			TWL4030_MODIRQ_PWR);
>+		goto batt_irq_fail;
>+	}
>+
>+	/* request Power interruption */
>+	ret = request_irq(TWL4030_PWRIRQ_CHG_PRES, 
>twl4030charger_interrupt,
>+		0, dev->name, di);
>+
>+	if (ret) {
>+		pr_err("BATTERY DRIVER: (POWER) IRQ%d is not free.\n",
>+			TWL4030_MODIRQ_PWR);
>+		goto chg_irq_fail;
>+	}
>+
>+	ret = power_supply_register(&dev->dev, &di->bat);
>+	if (ret) {
>+		pr_err("BATTERY DRIVER: failed to register main 
>battery\n");
>+		goto batt_failed;
>+	}
>+
>+	INIT_DELAYED_WORK_DEFERRABLE(&di->twl4030_bci_monitor_work,
>+				twl4030_bci_battery_work);
>+	schedule_delayed_work(&di->twl4030_bci_monitor_work, 0);
>+
>+	ret = power_supply_register(&dev->dev, &di->bk_bat);
>+	if (ret) {
>+		pr_err("BATTERY DRIVER: failed to register 
>backup battery\n");
>+		goto bk_batt_failed;
>+	}
>+
>+	INIT_DELAYED_WORK_DEFERRABLE(&di->twl4030_bk_bci_monitor_work,
>+				twl4030_bk_bci_battery_work);
>+	schedule_delayed_work(&di->twl4030_bk_bci_monitor_work, 500);
>+
>+	return 0;
>+
>+bk_batt_failed:
>+	power_supply_unregister(&di->bat);
>+batt_failed:
>+	free_irq(TWL4030_MODIRQ_PWR, di);
>+chg_irq_fail:
>+prev_setup_err:
>+	free_irq(TWL4030_MODIRQ_BCI, NULL);
>+batt_irq_fail:
>+voltage_setup_fail:
>+temp_setup_fail:
>+	twl4030charger_ac_en(DISABLE);
>+	twl4030charger_usb_en(DISABLE);
>+	twl4030battery_hw_level_en(DISABLE);
>+	twl4030battery_hw_presence_en(DISABLE);
>+	kfree(di);
>+
>+	return ret;
>+}
>+
>+static int twl4030_bci_battery_remove(struct  platform_device *dev)
>+{
>+	struct twl4030_bci_device_info *di = platform_get_drvdata(dev);
>+
>+	twl4030charger_ac_en(DISABLE);
>+	twl4030charger_usb_en(DISABLE);
>+	twl4030battery_hw_level_en(DISABLE);
>+	twl4030battery_hw_presence_en(DISABLE);
>+
>+	free_irq(TWL4030_MODIRQ_BCI, NULL);
>+	free_irq(TWL4030_MODIRQ_PWR, di);
>+
>+	flush_scheduled_work();
>+	power_supply_unregister(&di->bat);
>+	power_supply_unregister(&di->bk_bat);
>+	platform_set_drvdata(dev, NULL);
>+	kfree(di);
>+
>+	return 0;
>+}
>+
>+#ifdef CONFIG_PM
>+static int twl4030_bci_battery_suspend(struct platform_device *dev,
>+	pm_message_t state)
>+{
>+	struct twl4030_bci_device_info *di = platform_get_drvdata(dev);
>+
>+	di->charge_status = POWER_SUPPLY_STATUS_UNKNOWN;
>+	cancel_delayed_work(&di->twl4030_bci_monitor_work);
>+	cancel_delayed_work(&di->twl4030_bk_bci_monitor_work);
>+	return 0;
>+}
>+
>+static int twl4030_bci_battery_resume(struct platform_device *dev)
>+{
>+	struct twl4030_bci_device_info *di = platform_get_drvdata(dev);
>+
>+	schedule_delayed_work(&di->twl4030_bci_monitor_work, 0);
>+	schedule_delayed_work(&di->twl4030_bk_bci_monitor_work, 50);
>+	return 0;
>+}
>+#endif /* CONFIG_PM */
>+
>+/*
>+ * Battery driver module initializer function
>+ * registers battery driver structure
>+ */
>+static int __init twl4030_battery_init(void)
>+{
>+	return platform_driver_register(&twl4030_bci_battery_driver);
>+
>+}
>+
>+/*
>+ * Battery driver module exit function
>+ * unregister battery driver structure
>+ */
>+static void __exit twl4030_battery_exit(void)
>+{
>+	platform_driver_unregister(&twl4030_bci_battery_driver);
>+}
>+
>+module_init(twl4030_battery_init);
>+module_exit(twl4030_battery_exit);
>+MODULE_LICENSE("GPL");
>+MODULE_ALIAS("twl4030_bci_battery");
>+MODULE_AUTHOR("Texas Instruments Inc");
>
>
>--
>To unsubscribe from this list: send the line "unsubscribe 
>linux-omap" in
>the body of a message to majordomo@xxxxxxxxxxxxxxx
>More majordomo info at  http://vger.kernel.org/majordomo-info.html
>
--
To unsubscribe from this list: send the line "unsubscribe linux-omap" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at  http://vger.kernel.org/majordomo-info.html

[Index of Archives]     [Linux Arm (vger)]     [ARM Kernel]     [ARM MSM]     [Linux Tegra]     [Linux WPAN Networking]     [Linux Wireless Networking]     [Maemo Users]     [Linux USB Devel]     [Video for Linux]     [Linux Audio Users]     [Yosemite Trails]     [Linux Kernel]     [Linux SCSI]

  Powered by Linux