Openwrt/target/linux/s3c24xx/patches-2.6.24/1324-gta01-battery-driver.patch.patch

327 lines
10 KiB
Diff

From 8aefbe43a7864e611dca9821daec3e10009e7171 Mon Sep 17 00:00:00 2001
From: Mike Westerhof <mwester@dls.net>
Date: Thu, 13 Nov 2008 20:50:55 +0000
Subject: [PATCH] gta01-battery-driver.patch
Adds a simple pass-through battery driver module for the GTA01.
This will simplify user-space by providing the same sysfs API
on both GTA01 and GTA02, and is a first step towards eliminating
the need for APM emulation.
Signed-off-by: Mike Westerhof <mwester@dls.net>
---
arch/arm/configs/gta02-moredrivers-defconfig | 1 +
defconfig-gta01 | 1 +
defconfig-gta02 | 1 +
drivers/i2c/chips/pcf50606.c | 96 +++++++++++++++++++++++++
drivers/power/Kconfig | 6 ++
drivers/power/Makefile | 1 +
drivers/power/gta01_battery.c | 97 ++++++++++++++++++++++++++
7 files changed, 203 insertions(+), 0 deletions(-)
create mode 100644 drivers/power/gta01_battery.c
diff --git a/arch/arm/configs/gta02-moredrivers-defconfig b/arch/arm/configs/gta02-moredrivers-defconfig
index 113eaec..5e1547e 100644
--- a/arch/arm/configs/gta02-moredrivers-defconfig
+++ b/arch/arm/configs/gta02-moredrivers-defconfig
@@ -1060,6 +1060,7 @@ CONFIG_POWER_SUPPLY_DEBUG=y
CONFIG_PDA_POWER=y
CONFIG_APM_POWER=y
# CONFIG_BATTERY_DS2760 is not set
+# CONFIG_BATTERY_GTA01 is not set
CONFIG_BATTERY_BQ27000_HDQ=y
CONFIG_GTA02_HDQ=y
CONFIG_HWMON=y
diff --git a/defconfig-gta01 b/defconfig-gta01
index cecb57f..e2e4330 100644
--- a/defconfig-gta01
+++ b/defconfig-gta01
@@ -1021,6 +1021,7 @@ CONFIG_POWER_SUPPLY=y
# CONFIG_PDA_POWER is not set
# CONFIG_APM_POWER is not set
# CONFIG_BATTERY_DS2760 is not set
+CONFIG_BATTERY_GTA01=y
CONFIG_BATTERY_BQ27000_HDQ=y
CONFIG_GTA02_HDQ=y
# CONFIG_HWMON is not set
diff --git a/defconfig-gta02 b/defconfig-gta02
index 619f7f2..2a6e398 100644
--- a/defconfig-gta02
+++ b/defconfig-gta02
@@ -1021,6 +1021,7 @@ CONFIG_POWER_SUPPLY=y
# CONFIG_PDA_POWER is not set
CONFIG_APM_POWER=y
# CONFIG_BATTERY_DS2760 is not set
+# CONFIG_BATTERY_GTA01 is not set
CONFIG_BATTERY_BQ27000_HDQ=y
CONFIG_GTA02_HDQ=y
# CONFIG_HWMON is not set
diff --git a/drivers/i2c/chips/pcf50606.c b/drivers/i2c/chips/pcf50606.c
index 706ce6d..f585013 100644
--- a/drivers/i2c/chips/pcf50606.c
+++ b/drivers/i2c/chips/pcf50606.c
@@ -50,6 +50,7 @@
#include <linux/platform_device.h>
#include <linux/pcf50606.h>
#include <linux/apm-emulation.h>
+#include <linux/power_supply.h>
#include <asm/mach-types.h>
#include <asm/arch/gta01.h>
@@ -141,6 +142,12 @@ struct pcf50606_data {
static struct i2c_driver pcf50606_driver;
+/* This global is set by the pcf50606 driver to the correct callback
+ * for the gta01 battery driver. */
+int (*pmu_bat_get_property)(struct power_supply *, enum power_supply_property,
+ union power_supply_propval *);
+EXPORT_SYMBOL(pmu_bat_get_property);
+
/* This is an ugly construct on how to access the (currently single/global)
* pcf50606 handle from other code in the kernel. I didn't really come up with
* a more decent method of dynamically resolving this */
@@ -1270,6 +1277,92 @@ static void pcf50606_get_power_status(struct apm_power_info *info)
}
/***********************************************************************
+ * Battery driver interface
+ ***********************************************************************/
+static int pcf50606_bat_get_property(struct power_supply *psy,
+ enum power_supply_property psp,
+ union power_supply_propval *val)
+{
+ u_int16_t adc, adc_adcin1;
+ u_int8_t mbcc1, chgmod;
+ struct pcf50606_data *pcf = pcf50606_global;
+ int ret = 0;
+
+ switch (psp) {
+
+ case POWER_SUPPLY_PROP_STATUS:
+ if (!(reg_read(pcf, PCF50606_REG_OOCS) & PCF50606_OOCS_EXTON)) {
+ /* No charger, clearly we're discharging then */
+ val->intval = POWER_SUPPLY_STATUS_DISCHARGING;
+ } else {
+
+ /* We have a charger present, get charge mode */
+ mbcc1 = reg_read(pcf, PCF50606_REG_MBCC1);
+ chgmod = (mbcc1 & PCF50606_MBCC1_CHGMOD_MASK);
+ switch (chgmod) {
+
+ /* TODO: How to determine POWER_SUPPLY_STATUS_FULL? */
+
+ case PCF50606_MBCC1_CHGMOD_QUAL:
+ case PCF50606_MBCC1_CHGMOD_PRE:
+ case PCF50606_MBCC1_CHGMOD_IDLE:
+ val->intval = POWER_SUPPLY_STATUS_NOT_CHARGING;
+ break;
+
+ case PCF50606_MBCC1_CHGMOD_TRICKLE:
+ case PCF50606_MBCC1_CHGMOD_FAST_CCCV:
+ case PCF50606_MBCC1_CHGMOD_FAST_NOCC:
+ case PCF50606_MBCC1_CHGMOD_FAST_NOCV:
+ case PCF50606_MBCC1_CHGMOD_FAST_SW:
+ val->intval = POWER_SUPPLY_STATUS_CHARGING;
+ break;
+
+ default:
+ val->intval = POWER_SUPPLY_STATUS_UNKNOWN;
+ break;
+
+ }
+ }
+
+ case POWER_SUPPLY_PROP_PRESENT:
+ val->intval = 1; /* Must be, or the magic smoke comes out */
+ break;
+
+ case POWER_SUPPLY_PROP_ONLINE:
+ val->intval = !!(reg_read(pcf, PCF50606_REG_OOCS) &
+ PCF50606_OOCS_EXTON);
+ break;
+
+ case POWER_SUPPLY_PROP_VOLTAGE_NOW:
+ adc = adc_read(pcf, PCF50606_ADCMUX_BATVOLT_RES, NULL);
+ /* (adc * 6000000) / 1024 == (adc * 46875) / 8 */
+ val->intval = (adc * 46875) / 8;
+ break;
+
+ case POWER_SUPPLY_PROP_CURRENT_NOW:
+ adc = adc_read(pcf, PCF50606_ADCMUX_BATVOLT_ADCIN1,
+ &adc_adcin1);
+ val->intval = adc_to_chg_milliamps(pcf, adc_adcin1, adc) * 1000;
+ break;
+
+ case POWER_SUPPLY_PROP_TEMP:
+ adc = adc_read(pcf, PCF50606_ADCMUX_BATTEMP, NULL);
+ val->intval = rntc_to_temp(adc_to_rntc(pcf, adc)) * 10;
+ break;
+
+ case POWER_SUPPLY_PROP_CAPACITY:
+ val->intval = battvolt_scale(pcf50606_battvolt(pcf));
+ break;
+
+ default:
+ ret = -EINVAL;
+ break;
+ }
+
+ return ret;
+}
+
+/***********************************************************************
* RTC
***********************************************************************/
@@ -1900,6 +1993,7 @@ static int pcf50606_detect(struct i2c_adapter *adapter, int address, int kind)
}
apm_get_power_status = pcf50606_get_power_status;
+ pmu_bat_get_property = pcf50606_bat_get_property;
#ifdef CONFIG_MACH_NEO1973_GTA01
if (machine_is_neo1973_gta01()) {
@@ -1962,6 +2056,8 @@ static int pcf50606_detach_client(struct i2c_client *client)
struct pcf50606_data *pcf = i2c_get_clientdata(client);
apm_get_power_status = NULL;
+ pmu_bat_get_property = NULL;
+
input_unregister_device(pcf->input_dev);
if (pcf->pdata->used_features & PCF50606_FEAT_PWM_BL)
diff --git a/drivers/power/Kconfig b/drivers/power/Kconfig
index 8c50ecb..470e08c 100644
--- a/drivers/power/Kconfig
+++ b/drivers/power/Kconfig
@@ -62,5 +62,11 @@ config GTA02_HDQ
on the Neo Freerunner. You probably want to select
at least BATTERY_BQ27000_HDQ as well
+config BATTERY_GTA01
+ tristate "Neo GTA01 battery"
+ depends on MACH_NEO1973_GTA01
+ help
+ Say Y to enable support for the battery on the Neo GTA01
+
endif # POWER_SUPPLY
diff --git a/drivers/power/Makefile b/drivers/power/Makefile
index d7e87ad..2013e89 100644
--- a/drivers/power/Makefile
+++ b/drivers/power/Makefile
@@ -21,5 +21,6 @@ obj-$(CONFIG_BATTERY_DS2760) += ds2760_battery.o
obj-$(CONFIG_BATTERY_PMU) += pmu_battery.o
obj-$(CONFIG_BATTERY_OLPC) += olpc_battery.o
obj-$(CONFIG_BATTERY_BQ27000_HDQ) += bq27000_battery.o
+obj-$(CONFIG_BATTERY_GTA01) += gta01_battery.o
obj-$(CONFIG_GTA02_HDQ) += gta02_hdq.o
diff --git a/drivers/power/gta01_battery.c b/drivers/power/gta01_battery.c
new file mode 100644
index 0000000..5acb45c
--- /dev/null
+++ b/drivers/power/gta01_battery.c
@@ -0,0 +1,97 @@
+/*
+ * Battery driver for the Openmoko GTA01 device, using the pcf50606 chip.
+ *
+ * This is nothing more than a write-thru interface to the real logic,
+ * which is part of the pcf50606.c multifunction chip driver.
+ * Copyright © 2008 Mike Westerhof <mwester@dls.net>
+ *
+ *
+ * Portions liberally borrowed from olpc_battery.c, copyright below:
+ * Copyright © 2006 David Woodhouse <dwmw2@infradead.org>
+ *
+ * This program 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.
+ */
+
+#include <linux/module.h>
+#include <linux/err.h>
+#include <linux/platform_device.h>
+#include <linux/power_supply.h>
+#include <linux/jiffies.h>
+#include <linux/sched.h>
+
+/*********************************************************************
+ * This global is set by the pcf50606 driver to the correct callback
+ *********************************************************************/
+
+extern int (*pmu_bat_get_property)(struct power_supply *,
+ enum power_supply_property,
+ union power_supply_propval *);
+
+
+/*********************************************************************
+ * Battery properties
+ *********************************************************************/
+static int gta01_bat_get_property(struct power_supply *psy,
+ enum power_supply_property psp,
+ union power_supply_propval *val)
+{
+ if (pmu_bat_get_property)
+ return (pmu_bat_get_property)(psy, psp, val);
+ else
+ return -ENODEV;
+}
+
+static enum power_supply_property gta01_bat_props[] = {
+ POWER_SUPPLY_PROP_STATUS,
+ POWER_SUPPLY_PROP_PRESENT,
+ POWER_SUPPLY_PROP_ONLINE,
+ POWER_SUPPLY_PROP_VOLTAGE_NOW,
+ POWER_SUPPLY_PROP_CURRENT_NOW,
+ POWER_SUPPLY_PROP_TEMP,
+ POWER_SUPPLY_PROP_CAPACITY,
+};
+
+/*********************************************************************
+ * Initialisation
+ *********************************************************************/
+
+static struct platform_device *bat_pdev;
+
+static struct power_supply gta01_bat = {
+ .properties = gta01_bat_props,
+ .num_properties = ARRAY_SIZE(gta01_bat_props),
+ .get_property = gta01_bat_get_property,
+ .use_for_apm = 0, /* pcf50606 driver has its own apm driver */
+};
+
+static int __init gta01_bat_init(void)
+{
+ int ret;
+
+ bat_pdev = platform_device_register_simple("gta01-battery", 0, NULL, 0);
+ if (IS_ERR(bat_pdev))
+ return PTR_ERR(bat_pdev);
+
+ gta01_bat.name = bat_pdev->name;
+
+ ret = power_supply_register(&bat_pdev->dev, &gta01_bat);
+ if (ret)
+ platform_device_unregister(bat_pdev);
+
+ return ret;
+}
+
+static void __exit gta01_bat_exit(void)
+{
+ power_supply_unregister(&gta01_bat);
+ platform_device_unregister(bat_pdev);
+}
+
+module_init(gta01_bat_init);
+module_exit(gta01_bat_exit);
+
+MODULE_AUTHOR("Mike Westerhof <mwester@dls.net>");
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("Battery driver for GTA01");
--
1.5.6.5