diff --git a/arch/arm/mach-pxa/Makefile b/arch/arm/mach-pxa/Makefile
index 3509756..ca3d9df 100644
--- a/arch/arm/mach-pxa/Makefile
+++ b/arch/arm/mach-pxa/Makefile
@@ -20,7 +20,7 @@ obj-$(CONFIG_PXA_SHARP_C7xx)	+= corgi.o corgi_ssp.o corgi_lcd.o sharpsl_pm.o cor
 obj-$(CONFIG_PXA_SHARP_Cxx00)	+= spitz.o corgi_ssp.o corgi_lcd.o sharpsl_pm.o spitz_pm.o
 obj-$(CONFIG_MACH_AKITA)	+= akita-ioexp.o
 obj-$(CONFIG_MACH_POODLE)	+= poodle.o corgi_ssp.o
-obj-$(CONFIG_MACH_TOSA)		+= tosa.o
+obj-$(CONFIG_MACH_TOSA)		+= tosa.o tosa_power.o
 obj-$(CONFIG_MACH_EM_X270)	+= em-x270.o
 
 ifeq ($(CONFIG_MACH_ZYLONITE),y)
diff --git a/arch/arm/mach-pxa/tosa_power.c b/arch/arm/mach-pxa/tosa_power.c
new file mode 100644
index 0000000..3ea14aa
--- /dev/null
+++ b/arch/arm/mach-pxa/tosa_power.c
@@ -0,0 +1,74 @@
+/*
+ * Battery and Power Management code for the Sharp SL-6000x
+ *
+ * Copyright (c) 2005 Dirk Opfer
+ * Copyright (c) 2008 Dmitry Baryshkov
+ *
+ * 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/kernel.h>
+#include <linux/module.h>
+#include <linux/power_supply.h>
+#include <linux/pda_power.h>
+#include <linux/platform_device.h>
+#include <linux/interrupt.h>
+
+#include <asm/arch/tosa.h>
+#include <asm/gpio.h>
+
+static int tosa_power_ac_online(void)
+{
+	return gpio_get_value(TOSA_GPIO_AC_IN) == 0;
+}
+
+static struct pda_power_pdata tosa_power_data = {
+	.is_ac_online		= tosa_power_ac_online,
+};
+
+static struct resource tosa_power_resource[] = {
+	{
+		.name		= "ac",
+		.start		= gpio_to_irq(TOSA_GPIO_AC_IN),
+		.end		= gpio_to_irq(TOSA_GPIO_AC_IN),
+		.flags		= IORESOURCE_IRQ |
+				  IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING,
+	},
+};
+
+static struct platform_device tosa_power_device = {
+	.name			= "pda-power",
+	.id			= -1,
+	.dev.platform_data	= &tosa_power_data,
+	.resource		= tosa_power_resource,
+	.num_resources		= ARRAY_SIZE(tosa_power_resource),
+};
+
+static int __init tosa_power_init(void)
+{
+	int ret = gpio_request(TOSA_GPIO_AC_IN, "ac");
+	if (ret)
+		goto err_gpio_req;
+
+	ret = gpio_direction_input(TOSA_GPIO_AC_IN);
+	if (ret)
+		goto err_gpio_in;
+
+	return platform_device_register(&tosa_power_device);
+
+err_gpio_in:
+	gpio_free(TOSA_GPIO_AC_IN);
+err_gpio_req:
+	return ret;
+}
+
+static void __exit tosa_power_exit(void)
+{
+	platform_device_unregister(&tosa_power_device);
+	gpio_free(TOSA_GPIO_AC_IN);
+}
+
+module_init(tosa_power_init);
+module_exit(tosa_power_exit);
diff --git a/drivers/leds/leds-tosa.c b/drivers/leds/leds-tosa.c
index fb2416a..b4498b5 100644
--- a/drivers/leds/leds-tosa.c
+++ b/drivers/leds/leds-tosa.c
@@ -46,7 +46,7 @@ static void tosaled_green_set(struct led_classdev *led_cdev,
 
 static struct led_classdev tosa_amber_led = {
 	.name			= "tosa:amber",
-	.default_trigger	= "sharpsl-charge",
+	.default_trigger	= "main-battery-charging",
 	.brightness_set		= tosaled_amber_set,
 };
 
diff --git a/drivers/power/Kconfig b/drivers/power/Kconfig
index 58c806e..e3a9c37 100644
--- a/drivers/power/Kconfig
+++ b/drivers/power/Kconfig
@@ -49,4 +49,11 @@ config BATTERY_OLPC
 	help
 	  Say Y to enable support for the battery on the OLPC laptop.
 
+config BATTERY_TOSA
+	tristate "Sharp SL-6000 (tosa) battery"
+	depends on MACH_TOSA && MFD_TC6393XB
+	help
+	  Say Y to enable support for the battery on the Sharp Zaurus
+	  SL-6000 (tosa) models.
+
 endif # POWER_SUPPLY
diff --git a/drivers/power/Makefile b/drivers/power/Makefile
index 6413ded..1e408fa 100644
--- a/drivers/power/Makefile
+++ b/drivers/power/Makefile
@@ -20,3 +20,4 @@ obj-$(CONFIG_APM_POWER)		+= apm_power.o
 obj-$(CONFIG_BATTERY_DS2760)	+= ds2760_battery.o
 obj-$(CONFIG_BATTERY_PMU)	+= pmu_battery.o
 obj-$(CONFIG_BATTERY_OLPC)	+= olpc_battery.o
+obj-$(CONFIG_BATTERY_TOSA)	+= tosa_battery.o
diff --git a/drivers/power/tosa_battery.c b/drivers/power/tosa_battery.c
new file mode 100644
index 0000000..58e1f4e
--- /dev/null
+++ b/drivers/power/tosa_battery.c
@@ -0,0 +1,328 @@
+/*
+ * Battery and Power Management code for the Sharp SL-6000x
+ *
+ * Copyright (c) 2005 Dirk Opfer
+ * Copyright (c) 2008 Dmitry Baryshkov
+ *
+ * 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/kernel.h>
+#include <linux/module.h>
+#include <linux/power_supply.h>
+#include <linux/wm97xx.h>
+#include <linux/delay.h>
+#include <linux/spinlock.h>
+#include <linux/interrupt.h>
+
+#include <asm/mach-types.h>
+#include <asm/gpio.h>
+#include <asm/arch/tosa.h>
+
+#define BAT_TO_VOLTS(v)		((v) * 1000000 / 414)
+#define BU_TO_VOLTS(v)		((v) * 1000000 / 1266)
+/*
+ * It's pretty strange value, but that's roughly what I get from
+ * zaurus maintainer menu
+ */
+#define BAT_TO_TEMP(t)		((t) * 10000/2000)
+
+static DEFINE_MUTEX(bat_lock); /* protects gpio pins */
+static DEFINE_MUTEX(work_lock); /* protects data */
+
+static struct power_supply tosa_bat_main;
+static int status = POWER_SUPPLY_STATUS_UNKNOWN;
+static struct work_struct bat_work;
+static int full_chrg = -1;
+
+
+static enum power_supply_property tosa_bat_main_props[] = {
+	POWER_SUPPLY_PROP_STATUS,
+	POWER_SUPPLY_PROP_TECHNOLOGY,
+	POWER_SUPPLY_PROP_VOLTAGE_NOW,
+	POWER_SUPPLY_PROP_VOLTAGE_MAX,
+//	POWER_SUPPLY_PROP_VOLTAGE_MAX_DESIGN,
+	POWER_SUPPLY_PROP_VOLTAGE_MIN_DESIGN,
+	POWER_SUPPLY_PROP_TEMP,
+};
+
+static enum power_supply_property tosa_bat_bu_props[] = {
+	POWER_SUPPLY_PROP_STATUS,
+	POWER_SUPPLY_PROP_TECHNOLOGY,
+	POWER_SUPPLY_PROP_VOLTAGE_NOW,
+	POWER_SUPPLY_PROP_VOLTAGE_MAX_DESIGN,
+};
+
+static unsigned long tosa_read_bat(struct power_supply *psy)
+{
+	unsigned long value = 0;
+	mutex_lock(&bat_lock);
+	gpio_set_value(TOSA_TC6393XB_BAT1_V_ON, 0);
+	gpio_set_value(TOSA_TC6393XB_BAT_SW_ON, 0);
+	gpio_set_value(TOSA_TC6393XB_BAT0_V_ON, 1);
+	mdelay(5);
+	value = wm97xx_read_aux_adc(psy->dev->parent->driver_data, WM97XX_AUX_ID3);
+	gpio_set_value(TOSA_TC6393XB_BAT0_V_ON, 0);
+	mutex_unlock(&bat_lock);
+	return value;
+}
+
+static unsigned long tosa_read_temp(struct power_supply *psy)
+{
+	unsigned long value = 0;
+	mutex_lock(&bat_lock);
+	gpio_set_value(TOSA_TC6393XB_BAT1_TH_ON, 1);
+	gpio_set_value(TOSA_TC6393XB_BAT0_TH_ON, 0);
+	mdelay(5);
+	value = wm97xx_read_aux_adc(psy->dev->parent->driver_data, WM97XX_AUX_ID2);
+	gpio_set_value(TOSA_TC6393XB_BAT1_TH_ON, 0);
+	mutex_unlock(&bat_lock);
+	return value;
+}
+
+static unsigned long tosa_read_bu(struct power_supply *psy)
+{
+	unsigned long value = 0;
+	mutex_lock(&bat_lock);
+	gpio_set_value(TOSA_TC6393XB_BU_CHRG_ON, 1);
+	mdelay(5);
+	value = wm97xx_read_aux_adc(psy->dev->parent->driver_data, WM97XX_AUX_ID4);
+	gpio_set_value(TOSA_TC6393XB_BU_CHRG_ON, 0);
+	mutex_unlock(&bat_lock);
+	return value;
+}
+
+static int tosa_bat_get_property(struct power_supply *psy,
+			    enum power_supply_property psp,
+			    union power_supply_propval *val)
+{
+	int ret = 0;
+	switch (psp) {
+	case POWER_SUPPLY_PROP_STATUS:
+		val->intval = status;
+		break;
+	case POWER_SUPPLY_PROP_TECHNOLOGY:
+		val->intval = POWER_SUPPLY_TECHNOLOGY_LIPO;
+		break;
+	case POWER_SUPPLY_PROP_VOLTAGE_NOW:
+		val->intval = BAT_TO_VOLTS(tosa_read_bat(psy));
+		break;
+	case POWER_SUPPLY_PROP_VOLTAGE_MAX:
+		if (full_chrg == -1)
+			val->intval = -1;
+		else
+			val->intval = BAT_TO_VOLTS(full_chrg);
+		break;
+	case POWER_SUPPLY_PROP_VOLTAGE_MIN_DESIGN:
+		val->intval = BAT_TO_VOLTS(1551);
+		break;
+	case POWER_SUPPLY_PROP_TEMP:
+		val->intval = BAT_TO_TEMP(tosa_read_temp(psy));
+		break;
+	default:
+		ret = -EINVAL;
+		break;
+	}
+	return ret;
+}
+
+static int tosa_bu_get_property(struct power_supply *psy,
+			    enum power_supply_property psp,
+			    union power_supply_propval *val)
+{
+	int ret = 0;
+	switch (psp) {
+	case POWER_SUPPLY_PROP_STATUS:
+		val->intval = POWER_SUPPLY_STATUS_UNKNOWN;
+		break;
+	case POWER_SUPPLY_PROP_TECHNOLOGY:
+		val->intval = POWER_SUPPLY_TECHNOLOGY_LiMn;
+		break;
+	case POWER_SUPPLY_PROP_VOLTAGE_MAX_DESIGN:
+		val->intval = 3 * 1000000; /* 3 V */
+		break;
+	case POWER_SUPPLY_PROP_VOLTAGE_NOW:
+		/* I think so */
+		val->intval = BU_TO_VOLTS(tosa_read_bu(psy));
+		break;
+	default:
+		ret = -EINVAL;
+		break;
+	}
+	return ret;
+}
+
+static void tosa_bat_external_power_changed(struct power_supply *psy)
+{
+	schedule_work(&bat_work);
+}
+
+static irqreturn_t tosa_bat_full_isr(int irq, void *data)
+{
+	printk(KERN_ERR "bat_full irq: %d\n", gpio_get_value(irq_to_gpio(irq)));
+	schedule_work(&bat_work);
+	return IRQ_HANDLED;
+}
+
+static void tosa_bat_work(struct work_struct *work)
+{
+	int old = status;
+	struct power_supply *psy = &tosa_bat_main;
+
+	mutex_lock(&work_lock);
+	if (power_supply_am_i_supplied(psy)) {
+		if (gpio_get_value(TOSA_GPIO_BAT0_CRG)) {
+			printk(KERN_ERR "full\n");
+
+			if (old == POWER_SUPPLY_STATUS_CHARGING || full_chrg == -1)
+				full_chrg = tosa_read_bat(psy);
+
+			gpio_set_value(TOSA_TC6393XB_CHARGE_OFF, 1);
+			status = POWER_SUPPLY_STATUS_FULL;
+		} else {
+			printk(KERN_ERR "charge\n");
+			gpio_set_value(TOSA_TC6393XB_CHARGE_OFF, 0);
+			status = POWER_SUPPLY_STATUS_CHARGING;
+		}
+	} else {
+		printk(KERN_ERR "discharge\n");
+		gpio_set_value(TOSA_TC6393XB_CHARGE_OFF, 1);
+		status = POWER_SUPPLY_STATUS_DISCHARGING;
+	}
+
+	if (old != status)
+		power_supply_changed(psy);
+	mutex_unlock(&work_lock);
+}
+
+
+static struct power_supply tosa_bat_main = {
+	.name		= "main-battery",
+	.type		= POWER_SUPPLY_TYPE_BATTERY,
+	.properties	= tosa_bat_main_props,
+	.num_properties	= ARRAY_SIZE(tosa_bat_main_props),
+	.get_property	= tosa_bat_get_property,
+	.external_power_changed = tosa_bat_external_power_changed,
+	.use_for_apm	= 1,
+};
+
+static struct power_supply tosa_bat_bu = {
+	.name		= "backup-battery",
+	.type		= POWER_SUPPLY_TYPE_BATTERY,
+	.properties	= tosa_bat_bu_props,
+	.num_properties	= ARRAY_SIZE(tosa_bat_bu_props),
+	.get_property	= tosa_bu_get_property,
+//	.external_power_changed = tosa_bat_external_power_changed,
+};
+
+static struct {
+	int gpio;
+	char *name;
+	bool output;
+	int value;
+} gpios[] = {
+	{ TOSA_TC6393XB_CHARGE_OFF,	"main charge off",	1, 1 },
+	{ TOSA_TC6393XB_CHARGE_OFF_JC,	"jacket charge off",	1, 1 },
+	{ TOSA_TC6393XB_BAT_SW_ON,	"battery switch",	1, 0 },
+	{ TOSA_TC6393XB_BAT0_V_ON,	"main battery",		1, 0 },
+	{ TOSA_TC6393XB_BAT1_V_ON,	"jacket battery",	1, 0 },
+	{ TOSA_TC6393XB_BAT0_TH_ON,	"main battery temp",	1, 0 },
+	{ TOSA_TC6393XB_BAT1_TH_ON,	"jacket battery temp",	1, 0 },
+	{ TOSA_TC6393XB_BU_CHRG_ON,	"backup battery",	1, 0 },
+	{ TOSA_GPIO_BAT0_CRG,		"main battery full",	0, 0 },
+};
+
+static int __devinit tosa_bat_probe(struct device *dev)
+{
+	int ret;
+	int i;
+
+	if (!machine_is_tosa())
+		return -ENODEV;
+
+	for (i = 0; i < ARRAY_SIZE(gpios); i++) {
+		ret = gpio_request(gpios[i].gpio, gpios[i].name);
+		if (ret) {
+			i --;
+			goto err_gpio;
+		}
+
+		if (gpios[i].output)
+			ret = gpio_direction_output(gpios[i].gpio,
+					gpios[i].value);
+		else
+			ret = gpio_direction_input(gpios[i].gpio);
+
+		if (ret)
+			goto err_gpio;
+	}
+
+	INIT_WORK(&bat_work, tosa_bat_work);
+
+	ret = power_supply_register(dev, &tosa_bat_main);
+	if (ret)
+		goto err_psy_reg_main;
+	ret = power_supply_register(dev, &tosa_bat_bu);
+	if (ret)
+		goto err_psy_reg_bu;
+
+	ret = request_irq(gpio_to_irq(TOSA_GPIO_BAT0_CRG),
+				tosa_bat_full_isr, IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING,
+				"main full", NULL);
+	if (!ret) {
+		schedule_work(&bat_work);
+		return 0;
+	}
+
+err_psy_reg_bu:
+	power_supply_unregister(&tosa_bat_bu);
+err_psy_reg_main:
+	power_supply_unregister(&tosa_bat_main);
+
+	i --;
+err_gpio:
+	for (; i >= 0; i --)
+		gpio_free(gpios[i].gpio);
+
+	return ret;
+}
+
+static int __devexit tosa_bat_remove(struct device *dev)
+{
+	int i;
+
+	power_supply_unregister(&tosa_bat_bu);
+	power_supply_unregister(&tosa_bat_main);
+
+	for (i = ARRAY_SIZE(gpios) - 1; i >= 0; i --)
+		gpio_free(gpios[i].gpio);
+
+	return 0;
+}
+
+static struct device_driver tosa_bat_driver = {
+	.name		= "wm97xx-battery",
+	.bus		= &wm97xx_bus_type,
+	.owner		= THIS_MODULE,
+	.probe		= tosa_bat_probe,
+	.remove		= __devexit_p(tosa_bat_remove),
+};
+
+static int __init tosa_bat_init(void)
+{
+	return driver_register(&tosa_bat_driver);
+}
+
+static void __exit tosa_bat_exit(void)
+{
+	driver_unregister(&tosa_bat_driver);
+}
+
+module_init(tosa_bat_init);
+module_exit(tosa_bat_exit);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Dmitry Baryshkov");
+MODULE_DESCRIPTION("Tosa battery driver");
