* [RFC/PATCH 1/2] Triton Battery charger interface driver for OMAP3430
@ 2008-06-20 12:03 x0070977
2008-06-23 8:49 ` Felipe Balbi
0 siblings, 1 reply; 6+ messages in thread
From: x0070977 @ 2008-06-20 12:03 UTC (permalink / raw)
To: linux-omap
From: Madhusudhan Chikkature <madhu.cr@ti.com>
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@ti.com>
---
arch/arm/mach-omap2/devices.c | 17
drivers/power/Kconfig | 8
drivers/power/Makefile | 1
drivers/power/twl4030_bci_battery.c | 1144 ++++++++++++++++++++++++++++++++++++
4 files changed, 1170 insertions(+)
Index: linux-omap-2.6/arch/arm/mach-omap2/devices.c
===================================================================
--- linux-omap-2.6.orig/arch/arm/mach-omap2/devices.c 2008-06-20
15:39:56.000000000 +0530
+++ linux-omap-2.6/arch/arm/mach-omap2/devices.c 2008-06-20 15:42:05.000000000
+0530
@@ -358,6 +358,22 @@
static inline void omap_hdq_init(void) {}
#endif
+#ifdef CONFIG_TWL4030_BCI_BATTERY
+static struct platform_device omap_bci_battery_device = {
+ .name = "twl4030-bci-battery",
+ .id = 1,
+ .num_resources = 0,
+ .resource = NULL,
+};
+
+static inline void omap_bci_battery_init(void)
+{
+ (void) platform_device_register(&omap_bci_battery_device);
+}
+#else
+static inline void omap_bci_battery_init(void) {}
+#endif
+
/*-------------------------------------------------------------------------*/
static int __init omap2_init_devices(void)
@@ -369,6 +385,7 @@
omap_init_mbox();
omap_init_mcspi();
omap_hdq_init();
+ omap_bci_battery_init();
omap_init_sti();
omap_init_sha1_md5();
Index: linux-omap-2.6/drivers/power/Kconfig
===================================================================
--- linux-omap-2.6.orig/drivers/power/Kconfig 2008-06-20 15:39:56.000000000 +0530
+++ linux-omap-2.6/drivers/power/Kconfig 2008-06-20 15:42:05.000000000 +0530
@@ -70,4 +70,12 @@
help
Say Y here to enable support for batteries with BQ27200(I2C) chip.
+config TWL4030_BCI_BATTERY
+ bool "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-20 15:39:56.000000000 +0530
+++ linux-omap-2.6/drivers/power/Makefile 2008-06-20 15:42:05.000000000 +0530
@@ -21,3 +21,4 @@
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-06-20
15:42:05.000000000 +0530
@@ -0,0 +1,1144 @@
+/*
+ * 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
+};
+
+/*
+ * 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 =
+ (struct twl4030_bci_device_info *)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)
+{
+ 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)
+{
+ 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)
+{
+ 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)
+{
+ 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)
+{
+ 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();
+ return;
+}
+
+static void twl4030_bk_bci_battery_work(struct delayed_work *work)
+{
+ struct twl4030_bci_device_info *di = container_of(work,
+ struct twl4030_bci_device_info, twl4030_bk_bci_monitor_work);
+
+ twl4030_bk_bci_battery_read_status(di);
+ schedule_delayed_work(&di->twl4030_bk_bci_monitor_work, 500);
+ return;
+}
+
+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();
+
+ return;
+}
+
+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;
+
+ return;
+}
+
+static void twl4030_bci_battery_work(struct delayed_work *work)
+{
+ struct twl4030_bci_device_info *di = container_of(work,
+ struct twl4030_bci_device_info, twl4030_bci_monitor_work);
+
+ twl4030_bci_battery_update_status(di);
+ schedule_delayed_work(&di->twl4030_bci_monitor_work, 100);
+ return;
+}
+
+
+#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(&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(&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");
^ permalink raw reply [flat|nested] 6+ messages in thread
* Re: [RFC/PATCH 1/2] Triton Battery charger interface driver for OMAP3430
2008-06-20 12:03 [RFC/PATCH 1/2] Triton Battery charger interface driver for OMAP3430 x0070977
@ 2008-06-23 8:49 ` Felipe Balbi
2008-06-23 13:34 ` Madhusudhan Chikkature
0 siblings, 1 reply; 6+ messages in thread
From: Felipe Balbi @ 2008-06-23 8:49 UTC (permalink / raw)
To: x0070977; +Cc: linux-omap
On Fri, 20 Jun 2008 17:33:41 +0530 (IST), x0070977@dbdmail.itg.ti.com
wrote:
> Index: linux-omap-2.6/arch/arm/mach-omap2/devices.c
> ===================================================================
> --- linux-omap-2.6.orig/arch/arm/mach-omap2/devices.c 2008-06-20
> 15:39:56.000000000 +0530
> +++ linux-omap-2.6/arch/arm/mach-omap2/devices.c 2008-06-20
> 15:42:05.000000000
> +0530
> @@ -358,6 +358,22 @@
> static inline void omap_hdq_init(void) {}
> #endif
>
> +#ifdef CONFIG_TWL4030_BCI_BATTERY
> +static struct platform_device omap_bci_battery_device = {
> + .name = "twl4030-bci-battery",
> + .id = 1,
> + .num_resources = 0,
> + .resource = NULL,
if you pass the struct resources you can use __raw_{read,write} which
would simplify a lot for you, but if you really don't want it, you
don't have to initialize it to NULL. Just because it's static, it's
enough for it to get NULLed.
> +};
> +
> +static inline void omap_bci_battery_init(void)
> +{
> + (void) platform_device_register(&omap_bci_battery_device);
> +}
> +#else
> +static inline void omap_bci_battery_init(void) {}
> +#endif
> +
How about creating a special battery.c for this just like usb-musb.c,
usb-ehci.c
and hsmmc.c, so it's easier to reuse it and add such support only for
boards that
has twl4030.
It would be useful for omap multiboot, I suppose.
>
>
/*-------------------------------------------------------------------------*/
>
> static int __init omap2_init_devices(void)
> @@ -369,6 +385,7 @@
> omap_init_mbox();
> omap_init_mcspi();
> omap_hdq_init();
> + omap_bci_battery_init();
And this would be added to board-files.
> omap_init_sti();
> omap_init_sha1_md5();
>
> Index: linux-omap-2.6/drivers/power/Kconfig
> ===================================================================
> --- linux-omap-2.6.orig/drivers/power/Kconfig 2008-06-20
> 15:39:56.000000000 +0530
> +++ linux-omap-2.6/drivers/power/Kconfig 2008-06-20 15:42:05.000000000
> +0530
> @@ -70,4 +70,12 @@
> help
> Say Y here to enable support for batteries with BQ27200(I2C) chip.
>
> +config TWL4030_BCI_BATTERY
> + bool "OMAP TWL4030 BCI Battery driver"
I'm pretty sure this can be tristate. Did you try that ?
> +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",
> + },
how about tabifying these for better alignment ?
> +
> +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
> +};
> +
> +/*
> + * 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 =
> + (struct twl4030_bci_device_info *)dev_id;
unneeded cast, please remove.
> +
> + 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)
> +{
> + 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)
> +{
> + 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)
> +{
> + 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)
> +{
> + 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)
> +{
> + 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();
> + return;
unneeded return;
> +}
> +
> +static void twl4030_bk_bci_battery_work(struct delayed_work *work)
here you should pass a struct work_struct
> +{
> + struct twl4030_bci_device_info *di = container_of(work,
> + struct twl4030_bci_device_info, twl4030_bk_bci_monitor_work);
and this should be
twl4030_bk_bci_monitor_work.work
> +
> + twl4030_bk_bci_battery_read_status(di);
> + schedule_delayed_work(&di->twl4030_bk_bci_monitor_work, 500);
> + return;
unneeded return;
> +}
> +
> +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();
> +
> + return;
unneeded return;
> +}
> +
> +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;
> +
> + return;
unneeded return;
> +}
> +
> +static void twl4030_bci_battery_work(struct delayed_work *work)
> +{
> + struct twl4030_bci_device_info *di = container_of(work,
> + struct twl4030_bci_device_info, twl4030_bci_monitor_work);
> +
> + twl4030_bci_battery_update_status(di);
> + schedule_delayed_work(&di->twl4030_bci_monitor_work, 100);
> + return;
unneeded return;
> +}
> +
> +
> +#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(&di->twl4030_bci_monitor_work,
> + twl4030_bci_battery_work);
INIT_DELAYED_WORK_DEFERRABLE()???
> + 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(&di->twl4030_bk_bci_monitor_work,
> + twl4030_bk_bci_battery_work);
INIT_DELAYED_WORK_DEFERRABLE()???
> + 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");
missing MODULE_AUTHOR()
and MODULE_ALIAS("platform:twl4030-bci-battery");
--
Best Regards,
Felipe Balbi
http://felipebalbi.com
me@felipebalbi.com
^ permalink raw reply [flat|nested] 6+ messages in thread
* Re: [RFC/PATCH 1/2] Triton Battery charger interface driver for OMAP3430
2008-06-23 8:49 ` Felipe Balbi
@ 2008-06-23 13:34 ` Madhusudhan Chikkature
2008-06-23 14:53 ` Felipe Balbi
0 siblings, 1 reply; 6+ messages in thread
From: Madhusudhan Chikkature @ 2008-06-23 13:34 UTC (permalink / raw)
To: ext Felipe Balbi; +Cc: linux-omap
Hi Felipe,
Thanks for the comments. I will fix them and resend the patch.I have some clarification inlined for some of the comments.
Best regards,
Madhu
----- Original Message -----
From: "Felipe Balbi" <me@felipebalbi.com>
To: <x0070977@dbdmail.itg.ti.com>
Cc: <linux-omap@vger.kernel.org>
Sent: Monday, June 23, 2008 2:19 PM
Subject: Re: [RFC/PATCH 1/2] Triton Battery charger interface driver for OMAP3430
>
>
> On Fri, 20 Jun 2008 17:33:41 +0530 (IST), x0070977@dbdmail.itg.ti.com
> wrote:
>
>> Index: linux-omap-2.6/arch/arm/mach-omap2/devices.c
>> ===================================================================
>> --- linux-omap-2.6.orig/arch/arm/mach-omap2/devices.c 2008-06-20
>> 15:39:56.000000000 +0530
>> +++ linux-omap-2.6/arch/arm/mach-omap2/devices.c 2008-06-20
>> 15:42:05.000000000
>> +0530
>> @@ -358,6 +358,22 @@
>> static inline void omap_hdq_init(void) {}
>> #endif
>>
>> +#ifdef CONFIG_TWL4030_BCI_BATTERY
>> +static struct platform_device omap_bci_battery_device = {
>> + .name = "twl4030-bci-battery",
>> + .id = 1,
>> + .num_resources = 0,
>> + .resource = NULL,
>
> if you pass the struct resources you can use __raw_{read,write} which
> would simplify a lot for you, but if you really don't want it, you
> don't have to initialize it to NULL. Just because it's static, it's
> enough for it to get NULLed.
The battery driver uses twl4030_i2c_read_u8 and twl4030_i2c_write_u8 as low level interface(I2C) with
standard twl4030.h defines. So no point of _raw(read,write) and BASE address getting initialized through resource structure. Right?.
I agree with your second point of no need to explicitely setting it to NULL though.
>
>> +};
>> +
>> +static inline void omap_bci_battery_init(void)
>> +{
>> + (void) platform_device_register(&omap_bci_battery_device);
>> +}
>> +#else
>> +static inline void omap_bci_battery_init(void) {}
>> +#endif
>> +
>
> How about creating a special battery.c for this just like usb-musb.c,
> usb-ehci.c
> and hsmmc.c, so it's easier to reuse it and add such support only for
> boards that
> has twl4030.
>
> It would be useful for omap multiboot, I suppose.
I had put these under devices.c as there is not much board level configurations for BCI unlike hsmmc.
I guess I can add a simple board file for battery that way it can used based on TWL4030 if it is a good idea.
>
>>
>>
> /*-------------------------------------------------------------------------*/
>>
>> static int __init omap2_init_devices(void)
>> @@ -369,6 +385,7 @@
>> omap_init_mbox();
>> omap_init_mcspi();
>> omap_hdq_init();
>> + omap_bci_battery_init();
>
> And this would be added to board-files.
Agreed considering the above point.
>
>> omap_init_sti();
>> omap_init_sha1_md5();
>>
>> Index: linux-omap-2.6/drivers/power/Kconfig
>> ===================================================================
>> --- linux-omap-2.6.orig/drivers/power/Kconfig 2008-06-20
>> 15:39:56.000000000 +0530
>> +++ linux-omap-2.6/drivers/power/Kconfig 2008-06-20 15:42:05.000000000
>> +0530
>> @@ -70,4 +70,12 @@
>> help
>> Say Y here to enable support for batteries with BQ27200(I2C) chip.
>>
>> +config TWL4030_BCI_BATTERY
>> + bool "OMAP TWL4030 BCI Battery driver"
>
> I'm pretty sure this can be tristate. Did you try that ?
I agree. I can make it tristate.
>
>
>> +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",
>> + },
>
> how about tabifying these for better alignment ?
Okay.
>
>> +
>> +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
>> +};
>> +
>> +/*
>> + * 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 =
>> + (struct twl4030_bci_device_info *)dev_id;
>
> unneeded cast, please remove.
Okay.
>
>> +
>> + 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)
>> +{
>> + 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)
>> +{
>> + 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)
>> +{
>> + 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)
>> +{
>> + 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)
>> +{
>> + 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();
>> + return;
>
> unneeded return;
Okay.
>
>> +}
>> +
>> +static void twl4030_bk_bci_battery_work(struct delayed_work *work)
>
> here you should pass a struct work_struct
>
>> +{
>> + struct twl4030_bci_device_info *di = container_of(work,
>> + struct twl4030_bci_device_info, twl4030_bk_bci_monitor_work);
>
> and this should be
> twl4030_bk_bci_monitor_work.work
>
>> +
>> + twl4030_bk_bci_battery_read_status(di);
>> + schedule_delayed_work(&di->twl4030_bk_bci_monitor_work, 500);
>> + return;
>
> unneeded return;
Okay.
>
>> +}
>> +
>> +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();
>> +
>> + return;
>
> unneeded return;
Okay
>
>> +}
>> +
>> +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;
>> +
>> + return;
>
> unneeded return;
Okay
>
>> +}
>> +
>> +static void twl4030_bci_battery_work(struct delayed_work *work)
>> +{
>> + struct twl4030_bci_device_info *di = container_of(work,
>> + struct twl4030_bci_device_info, twl4030_bci_monitor_work);
>> +
>> + twl4030_bci_battery_update_status(di);
>> + schedule_delayed_work(&di->twl4030_bci_monitor_work, 100);
>> + return;
>
> unneeded return;
Okay
>
>> +}
>> +
>> +
>> +#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(&di->twl4030_bci_monitor_work,
>> + twl4030_bci_battery_work);
>
> INIT_DELAYED_WORK_DEFERRABLE()???
Do you mean INIT_DELAYED_WORK_DEFERRABLE() is a better choice here??
>
>> + 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(&di->twl4030_bk_bci_monitor_work,
>> + twl4030_bk_bci_battery_work);
>
> INIT_DELAYED_WORK_DEFERRABLE()???
>
>> + 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");
>
> missing MODULE_AUTHOR()
> and MODULE_ALIAS("platform:twl4030-bci-battery");
Okay
>
> --
> Best Regards,
>
> Felipe Balbi
> http://felipebalbi.com
> me@felipebalbi.com
>
>
^ permalink raw reply [flat|nested] 6+ messages in thread
* Re: [RFC/PATCH 1/2] Triton Battery charger interface driver for OMAP3430
2008-06-23 13:34 ` Madhusudhan Chikkature
@ 2008-06-23 14:53 ` Felipe Balbi
2008-06-24 7:50 ` Tony Lindgren
0 siblings, 1 reply; 6+ messages in thread
From: Felipe Balbi @ 2008-06-23 14:53 UTC (permalink / raw)
To: Madhusudhan Chikkature, Tony Lindgren, jouni.hogander; +Cc: linux-omap
Hi,
On Mon, 23 Jun 2008 19:04:51 +0530, "Madhusudhan Chikkature"
<madhu.cr@ti.com> wrote:
>> On Fri, 20 Jun 2008 17:33:41 +0530 (IST), x0070977@dbdmail.itg.ti.com
>> wrote:
>>
>>> Index: linux-omap-2.6/arch/arm/mach-omap2/devices.c
>>> ===================================================================
>>> --- linux-omap-2.6.orig/arch/arm/mach-omap2/devices.c 2008-06-20
>>> 15:39:56.000000000 +0530
>>> +++ linux-omap-2.6/arch/arm/mach-omap2/devices.c 2008-06-20
>>> 15:42:05.000000000
>>> +0530
>>> @@ -358,6 +358,22 @@
>>> static inline void omap_hdq_init(void) {}
>>> #endif
>>>
>>> +#ifdef CONFIG_TWL4030_BCI_BATTERY
>>> +static struct platform_device omap_bci_battery_device = {
>>> + .name = "twl4030-bci-battery",
>>> + .id = 1,
>>> + .num_resources = 0,
>>> + .resource = NULL,
>>
>> if you pass the struct resources you can use __raw_{read,write} which
>> would simplify a lot for you, but if you really don't want it, you
>> don't have to initialize it to NULL. Just because it's static, it's
>> enough for it to get NULLed.
> The battery driver uses twl4030_i2c_read_u8 and twl4030_i2c_write_u8 as
> low level interface(I2C) with
> standard twl4030.h defines. So no point of _raw(read,write) and BASE
> address getting initialized through resource structure. Right?.
> I agree with your second point of no need to explicitely setting it to
> NULL though.
The idea was to actually get rid of the i2c transfers and use
__raw_read/write
instead, but I suppose it's ok to use i2c transfers
>>> +};
>>> +
>>> +static inline void omap_bci_battery_init(void)
>>> +{
>>> + (void) platform_device_register(&omap_bci_battery_device);
>>> +}
>>> +#else
>>> +static inline void omap_bci_battery_init(void) {}
>>> +#endif
>>> +
don't remember if I said on last mail, but this ifdef should be in
a header file. Maybe include/linux/i2c/twl4030.h
>> How about creating a special battery.c for this just like usb-musb.c,
>> usb-ehci.c
>> and hsmmc.c, so it's easier to reuse it and add such support only for
>> boards that
>> has twl4030.
>>
>> It would be useful for omap multiboot, I suppose.
> I had put these under devices.c as there is not much board level
> configurations for BCI unlike hsmmc.
> I guess I can add a simple board file for battery that way it can used
> based on TWL4030 if it is a good idea.
I would like to hear from Tony and the others what do they think?
would it be worthy adding an extra file for bci ??
Tony, comments?
>> INIT_DELAYED_WORK_DEFERRABLE()???
> Do you mean INIT_DELAYED_WORK_DEFERRABLE() is a better choice here??
Yes, as it could be deferred on suspend/resume. I think INIT_DELAYED_WORK
also blocks dynamic pm ?!?
Maybe Jouni could clarify this one better. Jouni, any comments?
--
Best Regards,
Felipe Balbi
http://felipebalbi.com
me@felipebalbi.com
^ permalink raw reply [flat|nested] 6+ messages in thread
* Re: [RFC/PATCH 1/2] Triton Battery charger interface driver for OMAP3430
2008-06-23 14:53 ` Felipe Balbi
@ 2008-06-24 7:50 ` Tony Lindgren
2008-06-24 8:07 ` [RFC/PATCH 1/2] Triton Battery charger interface driver forOMAP3430 Madhusudhan Chikkature
0 siblings, 1 reply; 6+ messages in thread
From: Tony Lindgren @ 2008-06-24 7:50 UTC (permalink / raw)
To: Felipe Balbi; +Cc: Madhusudhan Chikkature, jouni.hogander, linux-omap
* Felipe Balbi <me@felipebalbi.com> [080623 17:53]:
> Hi,
>
> On Mon, 23 Jun 2008 19:04:51 +0530, "Madhusudhan Chikkature"
> <madhu.cr@ti.com> wrote:
>
> >> On Fri, 20 Jun 2008 17:33:41 +0530 (IST), x0070977@dbdmail.itg.ti.com
> >> wrote:
> >>
> >>> Index: linux-omap-2.6/arch/arm/mach-omap2/devices.c
> >>> ===================================================================
> >>> --- linux-omap-2.6.orig/arch/arm/mach-omap2/devices.c 2008-06-20
> >>> 15:39:56.000000000 +0530
> >>> +++ linux-omap-2.6/arch/arm/mach-omap2/devices.c 2008-06-20
> >>> 15:42:05.000000000
> >>> +0530
> >>> @@ -358,6 +358,22 @@
> >>> static inline void omap_hdq_init(void) {}
> >>> #endif
> >>>
> >>> +#ifdef CONFIG_TWL4030_BCI_BATTERY
> >>> +static struct platform_device omap_bci_battery_device = {
> >>> + .name = "twl4030-bci-battery",
> >>> + .id = 1,
> >>> + .num_resources = 0,
> >>> + .resource = NULL,
> >>
> >> if you pass the struct resources you can use __raw_{read,write} which
> >> would simplify a lot for you, but if you really don't want it, you
> >> don't have to initialize it to NULL. Just because it's static, it's
> >> enough for it to get NULLed.
> > The battery driver uses twl4030_i2c_read_u8 and twl4030_i2c_write_u8 as
> > low level interface(I2C) with
> > standard twl4030.h defines. So no point of _raw(read,write) and BASE
> > address getting initialized through resource structure. Right?.
> > I agree with your second point of no need to explicitely setting it to
> > NULL though.
>
> The idea was to actually get rid of the i2c transfers and use
> __raw_read/write
> instead, but I suppose it's ok to use i2c transfers
Hmm, I guess the only way to access twl4030 is via i2c :) So
__raw_read/write would not work for the twl4030 registers.
> >>> +};
> >>> +
> >>> +static inline void omap_bci_battery_init(void)
> >>> +{
> >>> + (void) platform_device_register(&omap_bci_battery_device);
> >>> +}
> >>> +#else
> >>> +static inline void omap_bci_battery_init(void) {}
> >>> +#endif
> >>> +
>
> don't remember if I said on last mail, but this ifdef should be in
> a header file. Maybe include/linux/i2c/twl4030.h
>
> >> How about creating a special battery.c for this just like usb-musb.c,
> >> usb-ehci.c
> >> and hsmmc.c, so it's easier to reuse it and add such support only for
> >> boards that
> >> has twl4030.
> >>
> >> It would be useful for omap multiboot, I suppose.
> > I had put these under devices.c as there is not much board level
> > configurations for BCI unlike hsmmc.
> > I guess I can add a simple board file for battery that way it can used
> > based on TWL4030 if it is a good idea.
>
> I would like to hear from Tony and the others what do they think?
> would it be worthy adding an extra file for bci ??
>
> Tony, comments?
Well I guess some people are not using the bci, so it could be a
separate module.
> >> INIT_DELAYED_WORK_DEFERRABLE()???
> > Do you mean INIT_DELAYED_WORK_DEFERRABLE() is a better choice here??
>
> Yes, as it could be deferred on suspend/resume. I think INIT_DELAYED_WORK
> also blocks dynamic pm ?!?
>
> Maybe Jouni could clarify this one better. Jouni, any comments?
>
>
> --
> Best Regards,
>
> Felipe Balbi
> http://felipebalbi.com
> me@felipebalbi.com
>
^ permalink raw reply [flat|nested] 6+ messages in thread
* Re: [RFC/PATCH 1/2] Triton Battery charger interface driver forOMAP3430
2008-06-24 7:50 ` Tony Lindgren
@ 2008-06-24 8:07 ` Madhusudhan Chikkature
0 siblings, 0 replies; 6+ messages in thread
From: Madhusudhan Chikkature @ 2008-06-24 8:07 UTC (permalink / raw)
To: Tony Lindgren, Felipe Balbi; +Cc: jouni.hogander, linux-omap
----- Original Message -----
From: "Tony Lindgren" <tony@atomide.com>
To: "Felipe Balbi" <me@felipebalbi.com>
Cc: "Madhusudhan Chikkature" <madhu.cr@ti.com>; <jouni.hogander@nokia.com>; <linux-omap@vger.kernel.org>
Sent: Tuesday, June 24, 2008 1:20 PM
Subject: Re: [RFC/PATCH 1/2] Triton Battery charger interface driver forOMAP3430
>* Felipe Balbi <me@felipebalbi.com> [080623 17:53]:
>> Hi,
>>
>> On Mon, 23 Jun 2008 19:04:51 +0530, "Madhusudhan Chikkature"
>> <madhu.cr@ti.com> wrote:
>>
>> >> On Fri, 20 Jun 2008 17:33:41 +0530 (IST), x0070977@dbdmail.itg.ti.com
>> >> wrote:
>> >>
>> >>> Index: linux-omap-2.6/arch/arm/mach-omap2/devices.c
>> >>> ===================================================================
>> >>> --- linux-omap-2.6.orig/arch/arm/mach-omap2/devices.c 2008-06-20
>> >>> 15:39:56.000000000 +0530
>> >>> +++ linux-omap-2.6/arch/arm/mach-omap2/devices.c 2008-06-20
>> >>> 15:42:05.000000000
>> >>> +0530
>> >>> @@ -358,6 +358,22 @@
>> >>> static inline void omap_hdq_init(void) {}
>> >>> #endif
>> >>>
>> >>> +#ifdef CONFIG_TWL4030_BCI_BATTERY
>> >>> +static struct platform_device omap_bci_battery_device = {
>> >>> + .name = "twl4030-bci-battery",
>> >>> + .id = 1,
>> >>> + .num_resources = 0,
>> >>> + .resource = NULL,
>> >>
>> >> if you pass the struct resources you can use __raw_{read,write} which
>> >> would simplify a lot for you, but if you really don't want it, you
>> >> don't have to initialize it to NULL. Just because it's static, it's
>> >> enough for it to get NULLed.
>> > The battery driver uses twl4030_i2c_read_u8 and twl4030_i2c_write_u8 as
>> > low level interface(I2C) with
>> > standard twl4030.h defines. So no point of _raw(read,write) and BASE
>> > address getting initialized through resource structure. Right?.
>> > I agree with your second point of no need to explicitely setting it to
>> > NULL though.
>>
>> The idea was to actually get rid of the i2c transfers and use
>> __raw_read/write
>> instead, but I suppose it's ok to use i2c transfers
>
> Hmm, I guess the only way to access twl4030 is via i2c :) So
> __raw_read/write would not work for the twl4030 registers.
>
>
>> >>> +};
>> >>> +
>> >>> +static inline void omap_bci_battery_init(void)
>> >>> +{
>> >>> + (void) platform_device_register(&omap_bci_battery_device);
>> >>> +}
>> >>> +#else
>> >>> +static inline void omap_bci_battery_init(void) {}
>> >>> +#endif
>> >>> +
>>
>> don't remember if I said on last mail, but this ifdef should be in
>> a header file. Maybe include/linux/i2c/twl4030.h
>>
>> >> How about creating a special battery.c for this just like usb-musb.c,
>> >> usb-ehci.c
>> >> and hsmmc.c, so it's easier to reuse it and add such support only for
>> >> boards that
>> >> has twl4030.
>> >>
>> >> It would be useful for omap multiboot, I suppose.
>> > I had put these under devices.c as there is not much board level
>> > configurations for BCI unlike hsmmc.
>> > I guess I can add a simple board file for battery that way it can used
>> > based on TWL4030 if it is a good idea.
>>
>> I would like to hear from Tony and the others what do they think?
>> would it be worthy adding an extra file for bci ??
>>
>> Tony, comments?
>
> Well I guess some people are not using the bci, so it could be a
> separate module.
Okay. I will add a seperate file for BCI.
Regards,
Madhu
>
>
>> >> INIT_DELAYED_WORK_DEFERRABLE()???
>> > Do you mean INIT_DELAYED_WORK_DEFERRABLE() is a better choice here??
>>
>> Yes, as it could be deferred on suspend/resume. I think INIT_DELAYED_WORK
>> also blocks dynamic pm ?!?
>>
>> Maybe Jouni could clarify this one better. Jouni, any comments?
>>
>>
>> --
>> Best Regards,
>>
>> Felipe Balbi
>> http://felipebalbi.com
>> me@felipebalbi.com
>>
>
^ permalink raw reply [flat|nested] 6+ messages in thread
end of thread, other threads:[~2008-06-24 8:09 UTC | newest]
Thread overview: 6+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2008-06-20 12:03 [RFC/PATCH 1/2] Triton Battery charger interface driver for OMAP3430 x0070977
2008-06-23 8:49 ` Felipe Balbi
2008-06-23 13:34 ` Madhusudhan Chikkature
2008-06-23 14:53 ` Felipe Balbi
2008-06-24 7:50 ` Tony Lindgren
2008-06-24 8:07 ` [RFC/PATCH 1/2] Triton Battery charger interface driver forOMAP3430 Madhusudhan Chikkature
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.