From patchwork Mon Apr 25 20:20:27 2011 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: John Stultz X-Patchwork-Id: 1174 Return-Path: Delivered-To: unknown Received: from imap.gmail.com (74.125.159.109) by localhost6.localdomain6 with IMAP4-SSL; 08 Jun 2011 14:49:52 -0000 Delivered-To: patches@linaro.org Received: by 10.224.2.73 with SMTP id 9cs48728qai; Mon, 25 Apr 2011 13:20:45 -0700 (PDT) Received: by 10.236.76.232 with SMTP id b68mr4684626yhe.223.1303762845363; Mon, 25 Apr 2011 13:20:45 -0700 (PDT) Received: from e9.ny.us.ibm.com (e9.ny.us.ibm.com [32.97.182.139]) by mx.google.com with ESMTPS id o67si5164615yhl.35.2011.04.25.13.20.43 (version=TLSv1/SSLv3 cipher=OTHER); Mon, 25 Apr 2011 13:20:44 -0700 (PDT) Received-SPF: pass (google.com: domain of jstultz@us.ibm.com designates 32.97.182.139 as permitted sender) client-ip=32.97.182.139; Authentication-Results: mx.google.com; spf=pass (google.com: domain of jstultz@us.ibm.com designates 32.97.182.139 as permitted sender) smtp.mail=jstultz@us.ibm.com Received: from d01relay06.pok.ibm.com (d01relay06.pok.ibm.com [9.56.227.116]) by e9.ny.us.ibm.com (8.14.4/8.13.1) with ESMTP id p3PJqGKx007596; Mon, 25 Apr 2011 15:52:16 -0400 Received: from d01av01.pok.ibm.com (d01av01.pok.ibm.com [9.56.224.215]) by d01relay06.pok.ibm.com (8.13.8/8.13.8/NCO v10.0) with ESMTP id p3PKKgGI1155088; Mon, 25 Apr 2011 16:20:43 -0400 Received: from d01av01.pok.ibm.com (loopback [127.0.0.1]) by d01av01.pok.ibm.com (8.14.4/8.13.1/NCO v10.0 AVout) with ESMTP id p3PKKg4Q021438; Mon, 25 Apr 2011 16:20:42 -0400 Received: from kernel.beaverton.ibm.com (kernel.beaverton.ibm.com [9.47.67.96]) by d01av01.pok.ibm.com (8.14.4/8.13.1/NCO v10.0 AVin) with ESMTP id p3PKKf8t021398; Mon, 25 Apr 2011 16:20:42 -0400 Received: by kernel.beaverton.ibm.com (Postfix, from userid 1056) id 7D7E41E750D; Mon, 25 Apr 2011 13:20:41 -0700 (PDT) From: John Stultz To: LKML Cc: Masashi YOKOTA , Anton Vorontsov , Akihiro MAEDA , John Stultz Subject: [PATCH 1/3][RFC] power: Add virtual battery driver Date: Mon, 25 Apr 2011 13:20:27 -0700 Message-Id: <1303762829-18000-2-git-send-email-john.stultz@linaro.org> X-Mailer: git-send-email 1.7.3.2.146.gca209 In-Reply-To: <1303762829-18000-1-git-send-email-john.stultz@linaro.org> References: <1303762829-18000-1-git-send-email-john.stultz@linaro.org> From: Masashi YOKOTA This patch adds virtual battery driver by Masashi YOKOTA. The original driver download can be found here: http://downloads.pylone.jp/src/virtual_battery/virtual_battery-0.0.1.tar.bz2 CC: Anton Vorontsov Signed-off-by: Akihiro MAEDA [john.stultz: reworded commit log] Signed-off-by: John Stultz --- drivers/power/Kconfig | 5 + drivers/power/Makefile | 1 + drivers/power/virtual_battery.c | 349 +++++++++++++++++++++++++++++++++++++++ 3 files changed, 355 insertions(+), 0 deletions(-) create mode 100644 drivers/power/virtual_battery.c diff --git a/drivers/power/Kconfig b/drivers/power/Kconfig index 52a462f..c599f0c 100644 --- a/drivers/power/Kconfig +++ b/drivers/power/Kconfig @@ -219,4 +219,9 @@ config CHARGER_GPIO This driver can be build as a module. If so, the module will be called gpio-charger. +config BATTERY_VIRTUAL + tristate "Virtual Battery Driver" + help + Say Y to include support for Virtual Battery. + endif # POWER_SUPPLY diff --git a/drivers/power/Makefile b/drivers/power/Makefile index 8385bfa..6ea09c9 100644 --- a/drivers/power/Makefile +++ b/drivers/power/Makefile @@ -34,3 +34,4 @@ obj-$(CONFIG_BATTERY_INTEL_MID) += intel_mid_battery.o obj-$(CONFIG_CHARGER_ISP1704) += isp1704_charger.o obj-$(CONFIG_CHARGER_TWL4030) += twl4030_charger.o obj-$(CONFIG_CHARGER_GPIO) += gpio-charger.o +obj-$(CONFIG_BATTERY_VIRTUAL) += virtual_battery.o diff --git a/drivers/power/virtual_battery.c b/drivers/power/virtual_battery.c new file mode 100644 index 0000000..4ae79d4 --- /dev/null +++ b/drivers/power/virtual_battery.c @@ -0,0 +1,349 @@ +/* + * drivers/power/virtual_battery.c + * + * Virtual battery driver + * + * Copyright (C) 2008 Pylone, Inc. + * Author: Masashi YOKOTA + * + * This software is licensed under the terms of the GNU General Public + * License version 2, as published by the Free Software Foundation, and + * may be copied, distributed, and modified under those terms. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + + +/* module parameters */ +static int ac_status = 1; /* online */ +static int battery_status = POWER_SUPPLY_STATUS_CHARGING; +static int battery_health = POWER_SUPPLY_HEALTH_GOOD; +static int battery_present = 1; /* true */ +static int battery_technology = POWER_SUPPLY_TECHNOLOGY_LION; +static int battery_capacity = 50; + + +static struct platform_device *bat_pdev; + +static enum power_supply_property virtual_ac_props[] = { + POWER_SUPPLY_PROP_ONLINE, +}; + +static enum power_supply_property virtual_battery_props[] = { + POWER_SUPPLY_PROP_STATUS, + POWER_SUPPLY_PROP_HEALTH, + POWER_SUPPLY_PROP_PRESENT, + POWER_SUPPLY_PROP_TECHNOLOGY, + POWER_SUPPLY_PROP_CAPACITY, +}; + +static int virtual_ac_get_property(struct power_supply *psy, + enum power_supply_property psp, + union power_supply_propval *val) +{ + int ret = 0; + + dev_dbg(&bat_pdev->dev, "%s: psp=%d\n", __func__, psp); + switch (psp) { + case POWER_SUPPLY_PROP_ONLINE: + val->intval = ac_status; + break; + default: + ret = -EINVAL; + break; + } + return ret; +} + +static int virtual_battery_get_property(struct power_supply *psy, + enum power_supply_property psp, + union power_supply_propval *val) +{ + int ret = 0; + + dev_dbg(&bat_pdev->dev, "%s: psp=%d\n", __func__, psp); + switch (psp) { + case POWER_SUPPLY_PROP_STATUS: + val->intval = battery_status; + break; + case POWER_SUPPLY_PROP_HEALTH: + val->intval = battery_health; + break; + case POWER_SUPPLY_PROP_PRESENT: + val->intval = battery_present; + break; + case POWER_SUPPLY_PROP_TECHNOLOGY: + val->intval = battery_technology; + break; + case POWER_SUPPLY_PROP_CAPACITY: + val->intval = battery_capacity; + break; default: ret = -EINVAL; + break; + } + + return ret; +} + +static struct power_supply power_supply_ac = { + .properties = virtual_ac_props, + .num_properties = ARRAY_SIZE(virtual_ac_props), + .get_property = virtual_ac_get_property, + .name = "ac", + .type = POWER_SUPPLY_TYPE_MAINS, +}; + +static struct power_supply power_supply_bat = { + .properties = virtual_battery_props, + .num_properties = ARRAY_SIZE(virtual_battery_props), + .get_property = virtual_battery_get_property, + .name = "battery", + .type = POWER_SUPPLY_TYPE_BATTERY, +}; + + +struct battery_property_map { + int value; + char const * key; +}; + +static struct battery_property_map map_ac_online[] = { + { 0, "on" }, + { 1, "off" }, + { -1, NULL }, +}; + +static struct battery_property_map map_status[] = { + { POWER_SUPPLY_STATUS_CHARGING, "charging" }, + { POWER_SUPPLY_STATUS_DISCHARGING, "discharging" }, + { POWER_SUPPLY_STATUS_NOT_CHARGING, "not-charging" }, + { POWER_SUPPLY_STATUS_FULL, "full" }, + { -1, NULL }, +}; + +static struct battery_property_map map_health[] = { + { POWER_SUPPLY_HEALTH_GOOD, "good" }, + { POWER_SUPPLY_HEALTH_OVERHEAT, "overheat" }, + { POWER_SUPPLY_HEALTH_DEAD, "dead" }, + { POWER_SUPPLY_HEALTH_OVERVOLTAGE, "overvoltage" }, + { POWER_SUPPLY_HEALTH_UNSPEC_FAILURE, "failure" }, + { -1, NULL }, +}; + +static struct battery_property_map map_present[] = { + { 0, "false" }, + { 1, "true" }, + { -1, NULL }, +}; + +static struct battery_property_map map_technology[] = { + { POWER_SUPPLY_TECHNOLOGY_NiMH, "NiMH" }, + { POWER_SUPPLY_TECHNOLOGY_LION, "LION" }, + { POWER_SUPPLY_TECHNOLOGY_LIPO, "LIPO" }, + { POWER_SUPPLY_TECHNOLOGY_LiFe, "LiFe" }, + { POWER_SUPPLY_TECHNOLOGY_NiCd, "NiCd" }, + { POWER_SUPPLY_TECHNOLOGY_LiMn, "LiMn" }, + { -1, NULL }, +}; + + +static int map_get_value(struct battery_property_map * map, const char * key, int def_val) +{ + char buf[4096]; + int cr; + + strcpy(buf, key); + cr = strlen(buf) - 1; + if (buf[cr] == '\n') + buf[cr] = '\0'; + + while (map->key) { + if (strcasecmp(map->key, buf) == 0) + return map->value; + map++; + } + + return def_val; +} + + +static const char * map_get_key(struct battery_property_map * map, int value, const char * def_key) +{ + while (map->key) { + if (map->value == value) + return map->key; + map++; + } + + return def_key; +} + +static int param_set_ac_status(const char *key, struct kernel_param *kp) +{ + dev_dbg(&bat_pdev->dev, "%s: name=%s, key=%s\n", __func__, kp->name, key); + ac_status = map_get_value( map_ac_online, key, ac_status); + power_supply_changed(&power_supply_ac); + return 0; +} + +static int param_get_ac_status(char *buffer, struct kernel_param *kp) +{ + dev_dbg(&bat_pdev->dev, "%s: name=%s\n", __func__, kp->name); + strcpy(buffer, map_get_key( map_ac_online, ac_status, "unknown")); + return strlen(buffer); +} + +static int param_set_battery_status(const char *key, struct kernel_param *kp) +{ + dev_dbg(&bat_pdev->dev, "%s: name=%s, key=%s.\n", __func__, kp->name, key); + battery_status = map_get_value( map_status, key, battery_status); + power_supply_changed(&power_supply_bat); + return 0; +} + +static int param_get_battery_status(char *buffer, struct kernel_param *kp) +{ + dev_dbg(&bat_pdev->dev, "%s: name=%s\n", __func__, kp->name); + strcpy(buffer, map_get_key( map_status, battery_status, "unknown")); + return strlen(buffer); +} + +static int param_set_battery_health(const char *key, struct kernel_param *kp) +{ + dev_dbg(&bat_pdev->dev, "%s: name=%s, key=%s\n", __func__, kp->name, key); + battery_health = map_get_value( map_health, key, battery_health); + power_supply_changed(&power_supply_bat); + return 0; +} + +static int param_get_battery_health(char *buffer, struct kernel_param *kp) +{ + dev_dbg(&bat_pdev->dev, "%s: name=%s\n", __func__, kp->name); + strcpy(buffer, map_get_key( map_health, battery_health, "unknown")); + return strlen(buffer); +} + +static int param_set_battery_present(const char *key, struct kernel_param *kp) +{ + dev_dbg(&bat_pdev->dev, "%s: name=%s, key=%s\n", __func__, kp->name, key); + battery_present = map_get_value( map_present, key, battery_present); + power_supply_changed(&power_supply_ac); + return 0; +} + +static int param_get_battery_present(char *buffer, struct kernel_param *kp) +{ + dev_dbg(&bat_pdev->dev, "%s: name=%s\n", __func__, kp->name); + strcpy(buffer, map_get_key( map_present, battery_present, "unknown")); + return strlen(buffer); +} + +static int param_set_battery_technology(const char *key, struct kernel_param *kp) +{ + dev_dbg(&bat_pdev->dev, "%s: name=%s, key=%s\n", __func__, kp->name, key); + battery_technology = map_get_value( map_technology, key, battery_technology); + power_supply_changed(&power_supply_bat); + return 0; +} + +static int param_get_battery_technology(char *buffer, struct kernel_param *kp) +{ + dev_dbg(&bat_pdev->dev, "%s: name=%s\n", __func__, kp->name); + strcpy(buffer, map_get_key( map_technology, battery_technology, "unknown")); + return strlen(buffer); +} + +static int param_set_battery_capacity(const char *key, struct kernel_param *kp) +{ + int tmp; + + dev_dbg(&bat_pdev->dev, "%s: name=%s, key=%s\n", __func__, kp->name, key); + + if (1 != sscanf(key, "%d", &tmp)) + return -EINVAL; + + battery_capacity = tmp; + power_supply_changed(&power_supply_bat); + return 0; +} + +#define param_get_battery_capacity param_get_int + +static int __init virtual_battery_init(void) +{ + int ret; + + bat_pdev = platform_device_register_simple(KBUILD_BASENAME, 0, NULL, 0); + if (IS_ERR(bat_pdev)) + return PTR_ERR(bat_pdev); + + ret = power_supply_register(&bat_pdev->dev, &power_supply_ac); + if (ret) + goto err_battery_failed; + + ret = power_supply_register(&bat_pdev->dev, &power_supply_bat); + if (ret) + goto err_ac_failed; + + printk(KERN_INFO KBUILD_BASENAME": registered \n"); + return 0; + + err_battery_failed: + power_supply_unregister(&power_supply_ac); + err_ac_failed: + return ret; +} + +static void __exit virtual_battery_exit(void) +{ + power_supply_unregister(&power_supply_ac); + power_supply_unregister(&power_supply_bat); + platform_device_unregister(bat_pdev); + printk(KERN_INFO KBUILD_BASENAME": unregistered \n"); +} + +module_init(virtual_battery_init); +module_exit(virtual_battery_exit); + +#define param_check_ac_status(name, p) __param_check(name, p, void); +#define param_check_battery_status(name, p) __param_check(name, p, void); +#define param_check_battery_present(name, p) __param_check(name, p, void); +#define param_check_battery_technology(name, p) __param_check(name, p, void); +#define param_check_battery_health(name, p) __param_check(name, p, void); +#define param_check_battery_capacity(name, p) __param_check(name, p, void); + +module_param(ac_status, ac_status, 0644); +MODULE_PARM_DESC(ac_status, "AC charging state "); + +module_param(battery_status, battery_status, 0644); +MODULE_PARM_DESC(battery_status, "battery status "); + +module_param(battery_present, battery_present, 0644); +MODULE_PARM_DESC(battery_present, "battery presence state "); + +module_param(battery_technology, battery_technology, 0644); +MODULE_PARM_DESC(battery_technology, "battery technology "); + +module_param(battery_health, battery_health, 0644); +MODULE_PARM_DESC(battery_health, "battery health state "); + +module_param(battery_capacity, battery_capacity, 0644); +MODULE_PARM_DESC(battery_capacity, "battery capacity (percentage)"); + + +MODULE_AUTHOR("Masashi YOKOTA "); +MODULE_LICENSE("GPL"); +MODULE_DESCRIPTION("Virtual battery driver"); +MODULE_ALIAS("platform:"KBUILD_BASENAME);