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

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

 



Hi Mikko,

Thanks for the comments.

I have inlined my answers.

Regards,
Madhu
----- Original Message ----- 
From: <Mikko.K.Ylinen@xxxxxxxxx>
To: <madhu.cr@xxxxxx>; <tony@xxxxxxxxxxx>
Cc: <linux-omap@xxxxxxxxxxxxxxx>; <me@xxxxxxxxxxxxxxx>
Sent: Monday, July 07, 2008 6:34 PM
Subject: RE: [Resending - PATCH 2/3] Triton BCI driver for OMAP3430


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?

The thermistor used is TH05-3H103F. The TWL4030 manual has a table which lists these characteristics. The
above values are picked up from that table. I will move this table out of the driver into the bci board specific file
bci.c. I will link the structure to platform specific data. This will provide the flexibility to support multiple boards 
if the values are changing based on the board.


>+
>+/*
>+ * 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?

We are reading the values from the MAIN CHARGE module. So we may not use the madc 
driver calls for this except the backup battery voltage. Ditto for simillar comments.

I guess I will make changes to the function which reads the backup battery voltage to not initiate
a MADC coversion. Instead use the exported function provided by the MADC driver to read the bk
battery voltage.

>+ 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.

Yes. Will use the madc exported conversion function.

+ 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.
Yes. I will use madc exported function.

>+ 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