From 195c27ead448a9a6a5ae3958dc2c2a11450f84c7 Mon Sep 17 00:00:00 2001 From: Marek Vasut Date: Sat, 31 Jul 2010 13:15:24 +0200 Subject: [PATCH] PXA: Reworked spitz-battery Signed-off-by: Marek Vasut --- arch/arm/mach-pxa/Makefile | 2 +- arch/arm/mach-pxa/spitz.c | 23 ++ drivers/power/Kconfig | 7 + drivers/power/Makefile | 1 + drivers/power/spitz_battery.c | 680 +++++++++++++++++++++++++++++++++++++++++ 5 files changed, 712 insertions(+), 1 deletions(-) create mode 100644 drivers/power/spitz_battery.c diff --git a/arch/arm/mach-pxa/Makefile b/arch/arm/mach-pxa/Makefile index 85c7fb3..704fb31 100644 --- a/arch/arm/mach-pxa/Makefile +++ b/arch/arm/mach-pxa/Makefile @@ -82,7 +82,7 @@ obj-$(CONFIG_MACH_PALMZ72) += palmz72.o obj-$(CONFIG_MACH_PALMLD) += palmld.o obj-$(CONFIG_PALM_TREO) += palmtreo.o obj-$(CONFIG_PXA_SHARP_C7xx) += corgi.o sharpsl_pm.o corgi_pm.o -obj-$(CONFIG_PXA_SHARP_Cxx00) += spitz.o sharpsl_pm.o spitz_pm.o +obj-$(CONFIG_PXA_SHARP_Cxx00) += spitz.o obj-$(CONFIG_MACH_POODLE) += poodle.o obj-$(CONFIG_MACH_TOSA) += tosa.o obj-$(CONFIG_MACH_ICONTROL) += icontrol.o mxm8x10.o diff --git a/arch/arm/mach-pxa/spitz.c b/arch/arm/mach-pxa/spitz.c index a8d4e3a..6cee4aa 100644 --- a/arch/arm/mach-pxa/spitz.c +++ b/arch/arm/mach-pxa/spitz.c @@ -683,6 +683,28 @@ static inline void spitz_irda_init(void) {} #endif /****************************************************************************** + * Battery + ******************************************************************************/ +//#if defined(CONFIG_PXA_FICP) || defined(CONFIG_PXA_FICP_MODULE) +static struct platform_device spitz_batt_device = { + .name = "spitz-battery", + .id = -1, +// .dev = { +// .platform_data = &spitz_gpio_keys_platform_data, +// }, +}; + +static void __init spitz_batt_init(void) +{ + printk("%s[%i]\n", __FUNCTION__, __LINE__); + platform_device_register(&spitz_batt_device); + printk("%s[%i]\n", __FUNCTION__, __LINE__); +} +//#else +//static inline void spitz_batt_init(void) {} +//#endif + +/****************************************************************************** * Framebuffer ******************************************************************************/ #if defined(CONFIG_FB_PXA) || defined(CONFIG_FB_PXA_MODULE) @@ -966,6 +988,7 @@ static void __init spitz_init(void) spitz_nor_init(); spitz_nand_init(); spitz_i2c_init(); + spitz_batt_init(); } static void __init spitz_fixup(struct machine_desc *desc, diff --git a/drivers/power/Kconfig b/drivers/power/Kconfig index 8e9ba17..e4c538c 100644 --- a/drivers/power/Kconfig +++ b/drivers/power/Kconfig @@ -136,6 +136,13 @@ config BATTERY_Z2 help Say Y to include support for the battery on the Zipit Z2. +config BATTERY_SPITZ + tristate "Sharp Spitz/Akita/Borzoi battery driver" + depends on SENSORS_MAX1111 && (MACH_AKITA || MACH_SPITZ || MACH_BORZOI) + help + Say Y to include support for the battery in the + Sharp Spitz/Akita/Borzoi. + config CHARGER_PCF50633 tristate "NXP PCF50633 MBC" depends on MFD_PCF50633 diff --git a/drivers/power/Makefile b/drivers/power/Makefile index 0005080..3d282be 100644 --- a/drivers/power/Makefile +++ b/drivers/power/Makefile @@ -33,4 +33,5 @@ obj-$(CONFIG_BATTERY_BQ27x00) += bq27x00_battery.o obj-$(CONFIG_BATTERY_DA9030) += da9030_battery.o obj-$(CONFIG_BATTERY_MAX17040) += max17040_battery.o obj-$(CONFIG_BATTERY_Z2) += z2_battery.o +obj-$(CONFIG_BATTERY_SPITZ) += spitz_battery.o obj-$(CONFIG_CHARGER_PCF50633) += pcf50633-charger.o diff --git a/drivers/power/spitz_battery.c b/drivers/power/spitz_battery.c new file mode 100644 index 0000000..46b07f1 --- /dev/null +++ b/drivers/power/spitz_battery.c @@ -0,0 +1,680 @@ +/* + * Battery and Power Management code for the Sharp SL-Cxxxx + * + * Copyright (c) 2009 Pavel Machek + * Copyright (c) 2010 Marek Vasut + * + * 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. + * + * Li-ion batteries are angry beasts, and they like to explode. + * If angry lithium comes your way, the hw was misdesigned. + * + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +//#include +//#include + +//#include "../../arch/arm/mach-pxa/sharpsl.h" +#define SHARPSL_CHECK_BATTERY_WAIT_TIME_TEMP 10 /* 10 msec */ +#define SHARPSL_CHECK_BATTERY_WAIT_TIME_VOLT 10 /* 10 msec */ +#define SHARPSL_CHECK_BATTERY_WAIT_TIME_ACIN 10 /* 10 msec */ + +#define SHARPSL_WAIT_DISCHARGE_ON 100 /* 100 msec */ + +#define SHARPSL_BATT_VOLT 1 +#define SHARPSL_BATT_TEMP 2 +#define SHARPSL_ACIN_VOLT 3 +#define SHARPSL_STATUS_ACIN 4 +#define SHARPSL_STATUS_LOCK 5 +#define SHARPSL_STATUS_CHRGFULL 6 +#define SHARPSL_STATUS_FATAL 7 + +static int spitz_bat_status = POWER_SUPPLY_STATUS_UNKNOWN; +static int spitz_bat_charge = POWER_SUPPLY_CHARGE_TYPE_UNKNOWN; +static int spitz_bat_temp = -1; +static int spitz_bat_volt = -1; +static int spitz_ac_volt = -1; + +static DEFINE_MUTEX(bat_lock); +static DECLARE_WAIT_QUEUE_HEAD(bat_wait); +static struct task_struct *bat_thread; +static int bat_restart; + +extern int max1111_read_channel(int); + +int basic_current = 125; /* miliAmp */ +int battery_resistance = 422; /* miliOhm */ + +/* 422 seems to be suitable for very old, 1Ah battery. + 2Ah battery probably has better resistance */ + +/* Unfortunately, resistance depends on state of charge, current + * direction and temperature. + * + * Ouch, and dependency is actually _not_ too simple. It is lowest + * at 3.55V, very slowly rises at 4V (approximately linear dependency), + * and quickly rises towards 3.2V (in something exponential-looking). + * + * It is about same at 25Celsius and 40Celsius, and about 2.5x the value + * on 0Celsius, rising _very_ sharply. + * + * Li-ion should only be charged between 0 and 45 Celsius, and discharged + * between -20 and 60 celsius. + */ +/* +extern int backlight_current; + +int battery_current(void) +{ + int intensity = sharpsl_pm.machinfo->backlight_get_status ? sharpsl_pm.machinfo->backlight_get_status() : 0; + + return basic_current + backlight_current; +} + +int liion_internal_voltage(int voltage, int current_ma) +{ + return voltage + (battery_resistance * current_ma / 1000); +} + +int liion_expected_voltage(int internal_voltage, int current_ma) +{ + return internal_voltage - (battery_resistance * current_ma / 1000); +} +*/ + +/* See for example http://www.kokam.com/english/biz/rc.html for + * voltage/capacity characteristic. I assume it is going to be + * reasonably similar to li-ion used in collie. + * + */ + +/* + { 420, 100 }, + { 417, 95 }, means it will report 100% between 418 and 420 + */ +/* +struct battery_thresh battery_levels[] = { + { 3980, 100 }, + { 3900, 95 }, + { 3860, 90 }, + { 3800, 85 }, + { 3760, 80 }, + { 3720, 74 }, + { 3680, 69 }, + { 3620, 65 }, + { 3570, 59 }, + { 3560, 55 }, + { 3550, 48 }, + { 3530, 45 }, + { 3510, 39 }, + { 3490, 33 }, + { 3470, 29 }, + { 3450, 23 }, + { 3410, 16 }, + { 0, 0 }, +}; + +int get_percentage(void) +{ + int i = ARRAY_SIZE(battery_levels); + struct battery_thresh *thresh; + int voltage = liion_internal_voltage(spitz_bat_volt, battery_current()); + + thresh = battery_levels; + + while (i > 0 && (voltage > thresh[i].voltage)) + i--; + + return thresh[i].percentage; +} +*/ +static int spitz_bat_get_property(struct power_supply *psy, + enum power_supply_property psp, + union power_supply_propval *val) +{ + switch (psp) { + case POWER_SUPPLY_PROP_CHARGE_TYPE: + mutex_lock(&bat_lock); + val->intval = spitz_bat_charge; + mutex_unlock(&bat_lock); + return 0; + case POWER_SUPPLY_PROP_STATUS: + mutex_lock(&bat_lock); + val->intval = spitz_bat_status; + mutex_unlock(&bat_lock); + return 0; + case POWER_SUPPLY_PROP_TECHNOLOGY: + val->intval = POWER_SUPPLY_TECHNOLOGY_LION; + return 0; + case POWER_SUPPLY_PROP_VOLTAGE_NOW: + if (spitz_bat_volt >= 0) { + mutex_lock(&bat_lock); + val->intval = spitz_bat_volt; + mutex_unlock(&bat_lock); + return 0; + } else + return -EINVAL; +/* case POWER_SUPPLY_PROP_VOLTAGE_AVG: + val->intval = liion_internal_voltage(liion_voltage(), battery_current())*1000; + return 0;*/ + case POWER_SUPPLY_PROP_VOLTAGE_MAX_DESIGN: + val->intval = 4200000; + return 0; + case POWER_SUPPLY_PROP_VOLTAGE_MIN_DESIGN: + val->intval = 3400000; + return 0; + case POWER_SUPPLY_PROP_TEMP: + if (spitz_bat_temp >= 0) { + mutex_lock(&bat_lock); + val->intval = spitz_bat_temp; + mutex_unlock(&bat_lock); + return 0; + } else + return -EINVAL; +/* case POWER_SUPPLY_PROP_MODEL_NAME: + val->strval = "spitz-battery"; + return 0;*/ + case POWER_SUPPLY_PROP_PRESENT: + val->intval = 1; + return 0; + case POWER_SUPPLY_PROP_CHARGE_FULL_DESIGN: + val->intval = 2000000; + return 0; +/* case POWER_SUPPLY_PROP_CAPACITY: + val->intval = get_percentage(); + return 0; + case POWER_SUPPLY_PROP_CURRENT_NOW: + val->intval = battery_current() * 1000; + return 0;*/ + default: + return -EINVAL; + } + return -EINVAL; +} + +static int spitz_ac_get_property(struct power_supply *psy, + enum power_supply_property psp, + union power_supply_propval *val) +{ + switch (psp) { + case POWER_SUPPLY_PROP_STATUS: + mutex_lock(&bat_lock); + val->intval = spitz_bat_status; + mutex_unlock(&bat_lock); + return 0; + case POWER_SUPPLY_PROP_VOLTAGE_NOW: + mutex_lock(&bat_lock); + val->intval = spitz_ac_volt; + mutex_unlock(&bat_lock); + return 0; + case POWER_SUPPLY_PROP_VOLTAGE_MAX_DESIGN: + val->intval = 5250000; + return 0; + case POWER_SUPPLY_PROP_VOLTAGE_MIN_DESIGN: + val->intval = 4750000; + return 0; +// case POWER_SUPPLY_PROP_MODEL_NAME: +// val->strval = "spitz-power-supply"; +// return 0; + case POWER_SUPPLY_PROP_PRESENT: + val->intval = !gpio_get_value(SPITZ_GPIO_AC_IN); + return 0; + default: + return -EINVAL; + } + return -EINVAL; +} + +static void spitz_bat_external_power_changed(struct power_supply *bat_ps) +{ + printk("%s[%i]\n", __FUNCTION__, __LINE__); +} + +static enum power_supply_property spitz_bat_main_props[] = { + POWER_SUPPLY_PROP_STATUS, + POWER_SUPPLY_PROP_TECHNOLOGY, + POWER_SUPPLY_PROP_VOLTAGE_NOW, +// POWER_SUPPLY_PROP_VOLTAGE_AVG, + POWER_SUPPLY_PROP_VOLTAGE_MAX_DESIGN, + POWER_SUPPLY_PROP_VOLTAGE_MIN_DESIGN, + POWER_SUPPLY_PROP_TEMP, + POWER_SUPPLY_PROP_PRESENT, + POWER_SUPPLY_PROP_CHARGE_TYPE,//? +// POWER_SUPPLY_PROP_HEALTH,//? + POWER_SUPPLY_PROP_CHARGE_FULL_DESIGN,//? +// POWER_SUPPLY_PROP_CURRENT_NOW, +// POWER_SUPPLY_PROP_CAPACITY, +}; + +static struct power_supply spitz_bat_main = { + .name = "main-battery", + .type = POWER_SUPPLY_TYPE_BATTERY, + .properties = spitz_bat_main_props, + .num_properties = ARRAY_SIZE(spitz_bat_main_props), + .get_property = spitz_bat_get_property, + .external_power_changed = spitz_bat_external_power_changed, + .use_for_apm = 1, +}; + +static enum power_supply_property spitz_ac_props[] = { + POWER_SUPPLY_PROP_STATUS, + POWER_SUPPLY_PROP_VOLTAGE_NOW, + POWER_SUPPLY_PROP_VOLTAGE_MIN_DESIGN, + POWER_SUPPLY_PROP_VOLTAGE_MAX_DESIGN, + POWER_SUPPLY_PROP_PRESENT, +}; + +static struct power_supply spitz_ac = { + .name = "ac", + .type = POWER_SUPPLY_TYPE_MAINS, + .properties = spitz_ac_props, + .num_properties = ARRAY_SIZE(spitz_ac_props), + .get_property = spitz_ac_get_property, +}; + +static void spitz_bat_set_chrg(int type, int update) +{ +/* If something fails here ... + * + * ..,:*:"*:~"*;'*'.. + * .::*;;*~*:*;~:`::"'':;. + * ,'*":*';~*":*";*'''":'":. + * :;.'*.',;*~,;*';,*;*,*;;* + * ';*:*';):"=*.~.,'(*,;*'; + * '*~"` :"*';.*;. `~=*` + * (":*:*'*;') + * :"':' ';: + * .. " ""';. .. + * . :; '";;": *:: // + *__/..""".._....,..,.,.,.,.//;:;,.,..::. + * BOOM!! + */ +printk("%s[%i] %i\n", __FUNCTION__, __LINE__, type); + spitz_bat_charge = type; + switch (type) { + case POWER_SUPPLY_CHARGE_TYPE_NONE: + gpio_set_value(SPITZ_GPIO_JK_B, 0); + gpio_set_value(SPITZ_GPIO_CHRG_ON, 1); + break; + case POWER_SUPPLY_CHARGE_TYPE_TRICKLE: + gpio_set_value(SPITZ_GPIO_JK_B, 0); + gpio_set_value(SPITZ_GPIO_CHRG_ON, 0); + break; + case POWER_SUPPLY_CHARGE_TYPE_FAST: + gpio_set_value(SPITZ_GPIO_JK_B, 1); + gpio_set_value(SPITZ_GPIO_CHRG_ON, 0); + break; + default: + spitz_bat_charge = POWER_SUPPLY_CHARGE_TYPE_UNKNOWN; + break; + + } + if (update) { + power_supply_changed(&spitz_ac); + power_supply_changed(&spitz_bat_main); + } +} + +/* + * max1111 accepts channels from 0-3, however, + * it is encoded from 0-7 here in the code. + */ + +static int spitz_bat_max_sample(int channel, int delay) +{ + int i; + int ret = 0; + + for (i = 0; i < 5; i++) { + ret += max1111_read_channel(channel); + mdelay(delay); + } + + return ret / 5; +} +static int spitz_bat_get_temp(void) +{ + /* + * SHARPSL_BATT_TEMP returns: + * 121: battery finished charging in 22C room + * 141: outside at 6C + */ + int ret; + + mdelay(SHARPSL_CHECK_BATTERY_WAIT_TIME_TEMP); + gpio_set_value(SPITZ_GPIO_ADC_TEMP_ON, 1); + ret = spitz_bat_max_sample(SHARPSL_BATT_TEMP, + SHARPSL_CHECK_BATTERY_WAIT_TIME_TEMP); + gpio_set_value(SPITZ_GPIO_ADC_TEMP_ON, 0); + return ret; +} + +static inline int spitz_bat_get_volt(void) +{ + int ret; + int charge = spitz_bat_charge; + +// spitz_bat_set_chrg(POWER_SUPPLY_CHARGE_TYPE_NONE, 0); + +// gpio_set_value(SPITZ_GPIO_JK_A, 1); +// mdelay(SHARPSL_WAIT_DISCHARGE_ON); + /* XXX missing -- toggle green led by some standard mean */ + + ret = spitz_bat_max_sample(SHARPSL_BATT_VOLT, + SHARPSL_CHECK_BATTERY_WAIT_TIME_VOLT); + +// gpio_set_value(SPITZ_GPIO_JK_A, 0); + /* XXX missing -- toggle green led by some standard mean */ + +// spitz_bat_set_chrg(charge, 0); + + return ret; +} + +static inline int spitz_bat_get_acin_volt(void) +{ + return spitz_bat_max_sample(SHARPSL_ACIN_VOLT, + SHARPSL_CHECK_BATTERY_WAIT_TIME_ACIN); +} + +static int spitz_bat_thread(void *null) +{ + int ac_in, chrg_full, fatal_bat; + + set_freezable(); + + do { + ac_in = !gpio_get_value(SPITZ_GPIO_AC_IN); + chrg_full = gpio_get_value(SPITZ_GPIO_CHRG_FULL); + fatal_bat = !gpio_get_value(SPITZ_GPIO_FATAL_BAT); + + bat_restart = 0; + + printk("%s[%i] AC:%i CH:%i FB:%i\n", __FUNCTION__, __LINE__, !!ac_in, !!chrg_full, !!fatal_bat); + + mutex_lock(&bat_lock); + + if (fatal_bat) { + spitz_bat_set_chrg(POWER_SUPPLY_CHARGE_TYPE_NONE, 1); + spitz_bat_status = POWER_SUPPLY_STATUS_UNKNOWN; + printk("XXX\n"); + goto end; + } + + if (ac_in) { + if (chrg_full) { + if (spitz_bat_status != POWER_SUPPLY_STATUS_FULL) { + spitz_bat_set_chrg(POWER_SUPPLY_CHARGE_TYPE_TRICKLE, 1); + spitz_bat_status = POWER_SUPPLY_STATUS_FULL; + } + } else { + if (spitz_bat_status != POWER_SUPPLY_STATUS_CHARGING) { + spitz_bat_set_chrg(POWER_SUPPLY_CHARGE_TYPE_FAST, 1); + spitz_bat_status = POWER_SUPPLY_STATUS_CHARGING; + } + } + } else { + if (spitz_bat_status != POWER_SUPPLY_STATUS_DISCHARGING) { + spitz_bat_set_chrg(POWER_SUPPLY_CHARGE_TYPE_NONE, 1); + spitz_bat_status = POWER_SUPPLY_STATUS_DISCHARGING; + } + } + + spitz_bat_temp = spitz_bat_get_temp(); + /* + * Thanks to Stanislav B. ADC has 3.3V as reference, + * is connected to battery over 47kOhm, and to ground over 100kOhm. + */ + spitz_bat_volt = (spitz_bat_get_volt());// * 1000 * 147 * 33) / 256; + printk("SBV: %i\n", spitz_bat_volt); + spitz_bat_volt = (spitz_bat_volt * 10000 * 147 * 33) / 256; + /* + * Thanks to Stanislav B. ADC has 3.3V as reference, + * is connected to acin over 2kOhm, and to ground over 1kOhm. + */ + spitz_ac_volt = (spitz_bat_get_acin_volt());// * 3000 * 3300) / 256 + printk("SAV: %i\n", spitz_ac_volt); + spitz_ac_volt = (spitz_ac_volt * 3000 * 3300) / 256; + +end: + mutex_unlock(&bat_lock); + + wait_event_freezable_timeout(bat_wait, bat_restart || kthread_should_stop(), msecs_to_jiffies(1000)); + + printk("%s[%i] AC:%i CH:%i FB:%i [BT:%i BV:%i AV:%i\n", __FUNCTION__, __LINE__, !!ac_in, !!chrg_full, !!fatal_bat, spitz_bat_temp, spitz_bat_volt, spitz_ac_volt); + } while (!kthread_should_stop()); + + printk("%s[%i]\n", __FUNCTION__, __LINE__); + bat_thread = NULL; + + return 0; +} + +static irqreturn_t spitz_bat_ac_in_irq(int irq, void *data) +{ + printk("%s[%i] %i\n", __FUNCTION__, __LINE__, !!gpio_get_value(SPITZ_GPIO_AC_IN)); + return IRQ_HANDLED; +} + +static irqreturn_t spitz_bat_chrg_full_irq(int irq, void *data) +{ +// printk("%s[%i] %i\n", __FUNCTION__, __LINE__, !!gpio_get_value(SPITZ_GPIO_CHRG_FULL)); +// schedule_work(&bat_work); + return IRQ_HANDLED; +} + +static irqreturn_t spitz_bat_fatal_bat_irq(int irq, void *data) +{ + printk("%s[%i] %i\n", __FUNCTION__, __LINE__, !!gpio_get_value(SPITZ_GPIO_FATAL_BAT)); + pr_err("Fatal battery error!\n"); + spitz_bat_set_chrg(POWER_SUPPLY_CHARGE_TYPE_NONE, 1); + return IRQ_HANDLED; +} + +static int __devinit spitz_bat_probe(struct platform_device *pdev) +{ + int ret; + + if (!(machine_is_spitz() || machine_is_akita() + || machine_is_borzoi())) { + dev_err(&pdev->dev, + "This driver only supports Akita, Spitz and Borzoi!"); + return -ENODEV; + } + + if (pdev->id != -1) { + dev_err(&pdev->dev, + "Can't register multiple instances of this driver!"); + return -EINVAL; + } + + ret = gpio_request(SPITZ_GPIO_AC_IN, "AC IN"); + if (ret) + goto err; + ret = gpio_direction_input(SPITZ_GPIO_AC_IN); + if (ret) + goto err2; + ret = request_irq(gpio_to_irq(SPITZ_GPIO_AC_IN), + spitz_bat_ac_in_irq, IRQF_TRIGGER_RISING | + IRQF_TRIGGER_FALLING, "AC Detect", pdev); + if (ret) + goto err2; + + ret = gpio_request(SPITZ_GPIO_CHRG_FULL, "CHRG FULL"); + if (ret) + goto err3; + ret = gpio_direction_input(SPITZ_GPIO_CHRG_FULL); + if (ret) + goto err4; + ret = request_irq(gpio_to_irq(SPITZ_GPIO_CHRG_FULL), + spitz_bat_chrg_full_irq, IRQF_TRIGGER_RISING | + IRQF_TRIGGER_FALLING, "Charging complete", pdev); + if (ret) + goto err4; + + ret = gpio_request(SPITZ_GPIO_FATAL_BAT, "FATAL BAT"); + if (ret) + goto err5; + ret = gpio_direction_input(SPITZ_GPIO_FATAL_BAT); + if (ret) + goto err6; + ret = request_irq(gpio_to_irq(SPITZ_GPIO_FATAL_BAT), + spitz_bat_fatal_bat_irq, IRQF_TRIGGER_RISING | + IRQF_TRIGGER_FALLING, "Battery error", pdev); + if (ret) + goto err6; + + ret = gpio_request(SPITZ_GPIO_JK_A, "JK A"); + if (ret) + goto err7; + ret = gpio_direction_output(SPITZ_GPIO_JK_A, 0); + if (ret) + goto err8; + gpio_set_value(SPITZ_GPIO_JK_A, 0); + + ret = gpio_request(SPITZ_GPIO_JK_B, "JK B"); + if (ret) + goto err8; + ret = gpio_direction_output(SPITZ_GPIO_JK_B, 0); + if (ret) + goto err9; + + ret = gpio_request(SPITZ_GPIO_CHRG_ON, "CHRG ON"); + if (ret) + goto err9; + ret = gpio_direction_output(SPITZ_GPIO_CHRG_ON, 1); + if (ret) + goto err10; + + ret = gpio_request(SPITZ_GPIO_ADC_TEMP_ON, "TEMP MSMT"); + if (ret) + goto err10; + ret = gpio_direction_output(SPITZ_GPIO_ADC_TEMP_ON, 0); + if (ret) + goto err11; + + mutex_init(&bat_lock); + + printk("%s[%i]\n", __FUNCTION__, __LINE__); + ret = power_supply_register(&pdev->dev, &spitz_bat_main); + if (ret) + goto err11; + + ret = power_supply_register(&pdev->dev, &spitz_ac); + if (ret) + goto err12; + + bat_restart = 0; + init_waitqueue_head(&bat_wait); + bat_thread = kthread_run(spitz_bat_thread, NULL, "spitz-bat"); + + printk("%s[%i]\n", __FUNCTION__, __LINE__); + + return 0; + +err12: + power_supply_unregister(&spitz_bat_main); +err11: + gpio_free(SPITZ_GPIO_ADC_TEMP_ON); +err10: + gpio_free(SPITZ_GPIO_CHRG_ON); +err9: + gpio_free(SPITZ_GPIO_JK_B); +err8: + gpio_free(SPITZ_GPIO_JK_A); +err7: + free_irq(gpio_to_irq(SPITZ_GPIO_FATAL_BAT), pdev); +err6: + gpio_free(SPITZ_GPIO_FATAL_BAT); +err5: + free_irq(gpio_to_irq(SPITZ_GPIO_CHRG_FULL), pdev); +err4: + gpio_free(SPITZ_GPIO_CHRG_FULL); +err3: + free_irq(gpio_to_irq(SPITZ_GPIO_AC_IN), pdev); +err2: + gpio_free(SPITZ_GPIO_AC_IN); +err: + return ret; +} + +static int __devexit spitz_bat_remove(struct platform_device *pdev) +{ + kthread_stop(bat_thread); + power_supply_unregister(&spitz_ac); + power_supply_unregister(&spitz_bat_main); + gpio_free(SPITZ_GPIO_ADC_TEMP_ON); + gpio_free(SPITZ_GPIO_CHRG_ON); + gpio_free(SPITZ_GPIO_JK_B); + gpio_free(SPITZ_GPIO_JK_A); + free_irq(gpio_to_irq(SPITZ_GPIO_FATAL_BAT), pdev); + gpio_free(SPITZ_GPIO_FATAL_BAT); + free_irq(gpio_to_irq(SPITZ_GPIO_CHRG_FULL), pdev); + gpio_free(SPITZ_GPIO_CHRG_FULL); + free_irq(gpio_to_irq(SPITZ_GPIO_AC_IN), pdev); + gpio_free(SPITZ_GPIO_AC_IN); + + return 0; +} + +#ifdef CONFIG_PM +static int spitz_bat_suspend(struct device *dev) +{ + return 0; +} + +static int spitz_bat_resume(struct device *dev) +{ + wake_up(&bat_wait); + return 0; +} + +static const struct dev_pm_ops spitz_bat_pm_ops = { + .suspend = spitz_bat_suspend, + .resume = spitz_bat_resume, +}; +#endif + +static struct platform_driver spitz_bat_driver = { + .driver = { + .name = "spitz-battery", + .owner = THIS_MODULE, +#ifdef CONFIG_PM + .pm = &spitz_bat_pm_ops, +#endif + }, + .probe = spitz_bat_probe, + .remove = __devexit_p(spitz_bat_remove), +}; + +static int __init spitz_bat_init(void) +{ + return platform_driver_register(&spitz_bat_driver); +} + +static void __exit spitz_bat_exit(void) +{ + platform_driver_unregister(&spitz_bat_driver); +} + +module_init(spitz_bat_init); +module_exit(spitz_bat_exit); + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Pavel Machek"); +MODULE_DESCRIPTION("Spitz battery driver"); +MODULE_ALIAS("platform:spitz-battery"); -- 1.7.1