From: Anton Vorontsov <cbou@mail.ru>
To: Greg KH <gregkh@suse.de>
Cc: linux-kernel@vger.kernel.org, kernel-discuss@handhelds.org,
David Woodhouse <dwmw2@infradead.org>
Subject: [PATCH 8/8] One Laptop Per Child power/battery driver
Date: Fri, 4 May 2007 01:33:03 +0400 [thread overview]
Message-ID: <20070503213303.GH20067@zarina> (raw)
This probably should be marked as BROKEN because, according
to David Woodhouse, EC-acccess method will change. Plus currently
it lacks mutexes. So this driver is just for reference. Converted
from the battery-2.6 repository, 1:1.
But nevertheless it should work.
Signed-off-by: Anton Vorontsov <cbou@mail.ru>
---
drivers/power/Kconfig | 6 +
drivers/power/Makefile | 1 +
drivers/power/olpc_battery.c | 300 ++++++++++++++++++++++++++++++++++++++++++
3 files changed, 307 insertions(+), 0 deletions(-)
create mode 100644 drivers/power/olpc_battery.c
diff --git a/drivers/power/Kconfig b/drivers/power/Kconfig
index 051724f..3ac79c3 100644
--- a/drivers/power/Kconfig
+++ b/drivers/power/Kconfig
@@ -42,4 +42,10 @@ config BATTERY_PMU
Say Y here to expose battery information on Apple machines
through the generic battery class.
+config BATTERY_OLPC
+ tristate "One Laptop Per Child battery"
+ depends on X86_32
+ help
+ Say Y to enable support for the battery on the $100 laptop.
+
endif # POWER_SUPPLY
diff --git a/drivers/power/Makefile b/drivers/power/Makefile
index 0ebdc6d..62b58ca 100644
--- a/drivers/power/Makefile
+++ b/drivers/power/Makefile
@@ -19,3 +19,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
diff --git a/drivers/power/olpc_battery.c b/drivers/power/olpc_battery.c
new file mode 100644
index 0000000..40f76bb
--- /dev/null
+++ b/drivers/power/olpc_battery.c
@@ -0,0 +1,300 @@
+/*
+ * Battery driver for One Laptop Per Child ($100 laptop) board.
+ *
+ * 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 <asm/io.h>
+
+#define wBAT_VOLTAGE 0xf900 /* *9.76/32, mV */
+#define wBAT_CURRENT 0xf902 /* *15.625/120, mA */
+#define wBAT_TEMP 0xf906 /* *256/1000, б╟C */
+#define wAMB_TEMP 0xf908 /* *256/1000, б╟C */
+#define SOC 0xf910 /* percentage */
+#define sMBAT_STATUS 0xfaa4
+#define sBAT_PRESENT 1
+#define sBAT_FULL 2
+#define sBAT_DESTROY 4 /* what is this exactly? */
+#define sBAT_LOW 32
+#define sBAT_DISCHG 64
+#define sMCHARGE_STATUS 0xfaa5
+#define sBAT_CHARGE 1
+#define sBAT_OVERTEMP 4
+#define sBAT_NiMH 8
+#define sPOWER_FLAG 0xfa40
+#define ADAPTER_IN 1
+
+/*********************************************************************
+ * EC locking and access
+ *********************************************************************/
+
+static int lock_ec(void)
+{
+ unsigned long timeo = jiffies + HZ / 20;
+
+ while (1) {
+ unsigned char lock = inb(0x6c) & 0x80;
+ if (!lock)
+ return 0;
+ if (time_after(jiffies, timeo)) {
+ printk(KERN_ERR "olpc_battery: failed to lock EC for "
+ "battery access\n");
+ return 1;
+ }
+ yield();
+ }
+}
+
+static void unlock_ec(void)
+{
+ outb(0xff, 0x6c);
+ return;
+}
+
+static unsigned char read_ec_byte(unsigned short adr)
+{
+ outb(adr >> 8, 0x381);
+ outb(adr, 0x382);
+ return inb(0x383);
+}
+
+static unsigned short read_ec_word(unsigned short adr)
+{
+ return (read_ec_byte(adr) << 8) | read_ec_byte(adr + 1);
+}
+
+/*********************************************************************
+ * Power
+ *********************************************************************/
+
+static int olpc_ac_get_prop(struct power_supply *psy,
+ enum power_supply_property psp,
+ union power_supply_propval *val)
+{
+ int ret = 0;
+
+ if (lock_ec())
+ return -EIO;
+
+ switch (psp) {
+ case POWER_SUPPLY_PROP_ONLINE:
+ if (!(read_ec_byte(sMBAT_STATUS) & sBAT_PRESENT)) {
+ ret = -ENODEV;
+ goto out;
+ }
+ val->intval = !!(read_ec_byte(sPOWER_FLAG) & ADAPTER_IN);
+ break;
+ default:
+ ret = -EINVAL;
+ break;
+ }
+out:
+ unlock_ec();
+ return ret;
+}
+
+static enum power_supply_property olpc_ac_props[] = {
+ POWER_SUPPLY_PROP_ONLINE,
+};
+
+static struct power_supply olpc_ac = {
+ .name = "olpc-ac",
+ .type = POWER_SUPPLY_TYPE_AC,
+ .properties = olpc_ac_props,
+ .num_properties = ARRAY_SIZE(olpc_ac_props),
+ .get_property = olpc_ac_get_prop,
+};
+
+/*********************************************************************
+ * Battery properties
+ *********************************************************************/
+
+static int olpc_bat_get_property(struct power_supply *psy,
+ enum power_supply_property psp,
+ union power_supply_propval *val)
+{
+ int ret = 0;
+
+ if (lock_ec())
+ return -EIO;
+
+ switch (psp) {
+ case POWER_SUPPLY_PROP_STATUS:
+ {
+ int status = POWER_SUPPLY_STATUS_UNKNOWN;
+
+ val->intval = read_ec_byte(sMBAT_STATUS);
+
+ if (!(val->intval & sBAT_PRESENT)) {
+ ret = -ENODEV;
+ goto out;
+ }
+
+ if (val->intval & sBAT_DISCHG)
+ status = POWER_SUPPLY_STATUS_DISCHARGING;
+ else if (val->intval & sBAT_FULL)
+ status = POWER_SUPPLY_STATUS_FULL;
+
+ val->intval = read_ec_byte(sMCHARGE_STATUS);
+ if (val->intval & sBAT_CHARGE)
+ status = POWER_SUPPLY_STATUS_CHARGING;
+
+ val->intval = status;
+ break;
+ }
+ case POWER_SUPPLY_PROP_PRESENT:
+ val->intval = !!(read_ec_byte(sMBAT_STATUS) & sBAT_PRESENT);
+ break;
+ case POWER_SUPPLY_PROP_HEALTH:
+ val->intval = read_ec_byte(sMCHARGE_STATUS);
+ if (val->intval & sBAT_OVERTEMP)
+ val->intval = POWER_SUPPLY_HEALTH_OVERHEAT;
+ else
+ val->intval = POWER_SUPPLY_HEALTH_GOOD;
+ break;
+ case POWER_SUPPLY_PROP_TECHNOLOGY:
+ val->intval = read_ec_byte(sMCHARGE_STATUS);
+ if (val->intval & sBAT_NiMH)
+ val->intval = POWER_SUPPLY_TECHNOLOGY_NIMH;
+ else
+ val->intval = POWER_SUPPLY_TECHNOLOGY_UNKNOWN;
+ break;
+ case POWER_SUPPLY_PROP_VOLTAGE_AVG:
+ val->intval = read_ec_byte(wBAT_VOLTAGE) * 9760L / 32;
+ break;
+ case POWER_SUPPLY_PROP_CURRENT_AVG:
+ val->intval = read_ec_byte(wBAT_CURRENT) * 15625L / 120;
+ break;
+ case POWER_SUPPLY_PROP_CAPACITY:
+ val->intval = read_ec_byte(SOC);
+ break;
+ case POWER_SUPPLY_PROP_CAPACITY_LEVEL:
+ val->intval = read_ec_byte(sMBAT_STATUS);
+ if (val->intval & sBAT_FULL)
+ val->intval = POWER_SUPPLY_CAPACITY_LEVEL_FULL;
+ else if (val->intval & sBAT_LOW)
+ val->intval = POWER_SUPPLY_CAPACITY_LEVEL_LOW;
+ else
+ val->intval = POWER_SUPPLY_CAPACITY_LEVEL_NORMAL;
+ break;
+ case POWER_SUPPLY_PROP_TEMP:
+ val->intval = read_ec_byte(wBAT_TEMP) * 256 / 100;
+ break;
+ case POWER_SUPPLY_PROP_TEMP_AMBIENT:
+ val->intval = read_ec_byte(wAMB_TEMP) * 256 / 100;
+ break;
+ default:
+ ret = -EINVAL;
+ break;
+ }
+
+out:
+ unlock_ec();
+ return ret;
+}
+
+static enum power_supply_property olpc_bat_props[] = {
+ POWER_SUPPLY_PROP_STATUS,
+ POWER_SUPPLY_PROP_PRESENT,
+ POWER_SUPPLY_PROP_HEALTH,
+ POWER_SUPPLY_PROP_TECHNOLOGY,
+ POWER_SUPPLY_PROP_VOLTAGE_AVG,
+ POWER_SUPPLY_PROP_CURRENT_AVG,
+ POWER_SUPPLY_PROP_CAPACITY,
+ POWER_SUPPLY_PROP_CAPACITY_LEVEL,
+ POWER_SUPPLY_PROP_TEMP,
+ POWER_SUPPLY_PROP_TEMP_AMBIENT,
+};
+
+/*********************************************************************
+ * Initialisation
+ *********************************************************************/
+
+static struct platform_device *bat_pdev;
+
+static struct power_supply olpc_bat = {
+ .properties = olpc_bat_props,
+ .num_properties = ARRAY_SIZE(olpc_bat_props),
+ .get_property = olpc_bat_get_property,
+ .use_for_apm = 1,
+};
+
+static int __init olpc_bat_init(void)
+{
+ int ret = 0;
+ unsigned short tmp;
+
+ if (!request_region(0x380, 4, "olpc-battery")) {
+ ret = -EIO;
+ goto region_failed;
+ }
+
+ if (lock_ec()) {
+ ret = -EIO;
+ goto lock_failed;
+ }
+
+ tmp = read_ec_word(0xfe92);
+ unlock_ec();
+
+ if (tmp != 0x380) {
+ /* Doesn't look like OLPC EC */
+ ret = -ENODEV;
+ goto not_olpc_ec;
+ }
+
+ bat_pdev = platform_device_register_simple("olpc-battery", 0, NULL, 0);
+ if (IS_ERR(bat_pdev)) {
+ ret = PTR_ERR(bat_pdev);
+ goto pdev_failed;
+ }
+
+ ret = power_supply_register(&bat_pdev->dev, &olpc_ac);
+ if (ret)
+ goto ac_failed;
+
+ olpc_bat.name = bat_pdev->name;
+
+ ret = power_supply_register(&bat_pdev->dev, &olpc_bat);
+ if (ret)
+ goto battery_failed;
+
+ goto success;
+
+battery_failed:
+ power_supply_unregister(&olpc_ac);
+ac_failed:
+ platform_device_unregister(bat_pdev);
+pdev_failed:
+not_olpc_ec:
+lock_failed:
+ release_region(0x380, 4);
+region_failed:
+success:
+ return ret;
+}
+
+static void __exit olpc_bat_exit(void)
+{
+ power_supply_unregister(&olpc_bat);
+ power_supply_unregister(&olpc_ac);
+ platform_device_unregister(bat_pdev);
+ release_region(0x380, 4);
+ return;
+}
+
+module_init(olpc_bat_init);
+module_exit(olpc_bat_exit);
+
+MODULE_AUTHOR("David Woodhouse <dwmw2@infradead.org>");
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("Battery driver for One Laptop Per Child "
+ "($100 laptop) board.");
--
1.5.1.1-dirty
next reply other threads:[~2007-05-03 21:36 UTC|newest]
Thread overview: 35+ messages / expand[flat|nested] mbox.gz Atom feed top
2007-05-03 21:33 Anton Vorontsov [this message]
2007-05-07 14:04 ` [PATCH 8/8] One Laptop Per Child power/battery driver Pavel Machek
2007-05-07 14:12 ` Anton Vorontsov
2007-05-07 15:10 ` David Woodhouse
2007-05-07 19:49 ` Pavel Machek
2007-05-07 19:51 ` David Woodhouse
2007-05-07 20:38 ` Pavel Machek
2007-05-07 21:43 ` Alan Cox
2007-05-08 5:39 ` Willy Tarreau
2007-05-07 20:04 ` Satyam Sharma
2007-05-08 17:45 ` Maciej W. Rozycki
2007-05-08 17:52 ` Stephen Clark
2007-05-08 17:52 ` David Woodhouse
2007-05-09 14:23 ` Maciej W. Rozycki
2007-05-09 14:46 ` David Woodhouse
2007-05-09 20:33 ` Pavel Machek
2007-05-11 12:43 ` David Woodhouse
2007-05-11 13:21 ` Pavel Machek
2007-05-12 21:11 ` Adrian Bunk
2007-05-12 23:20 ` Pavel Machek
2007-05-13 4:45 ` David Woodhouse
2007-05-13 16:40 ` Krzysztof Halasa
2007-05-11 13:21 ` Alan Cox
2007-05-11 13:45 ` Satyam Sharma
2007-05-12 16:35 ` Pete Zaitcev
2007-05-13 5:39 ` David Woodhouse
2007-05-13 6:03 ` Pete Zaitcev
2007-05-13 6:21 ` David Woodhouse
2007-05-07 21:23 ` Alan Cox
2007-05-07 21:55 ` Dmitry Torokhov
2007-05-07 22:02 ` Alan Cox
2007-05-08 12:18 ` Stephen Clark
2007-05-12 17:03 ` Pete Zaitcev
2007-05-12 19:27 ` Alan Cox
2007-05-12 19:31 ` Russell King
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20070503213303.GH20067@zarina \
--to=cbou@mail.ru \
--cc=dwmw2@infradead.org \
--cc=gregkh@suse.de \
--cc=kernel-discuss@handhelds.org \
--cc=linux-kernel@vger.kernel.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
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.