xref: /openbmc/linux/drivers/power/supply/test_power.c (revision 9a87ffc99ec8eb8d35eed7c4f816d75f5cc9662e)
1d2912cb1SThomas Gleixner // SPDX-License-Identifier: GPL-2.0-only
28c0984e5SSebastian Reichel /*
38c0984e5SSebastian Reichel  * Power supply driver for testing.
48c0984e5SSebastian Reichel  *
58c0984e5SSebastian Reichel  * Copyright 2010  Anton Vorontsov <cbouatmailru@gmail.com>
68c0984e5SSebastian Reichel  *
78c0984e5SSebastian Reichel  * Dynamic module parameter code from the Virtual Battery Driver
88c0984e5SSebastian Reichel  * Copyright (C) 2008 Pylone, Inc.
98c0984e5SSebastian Reichel  * By: Masashi YOKOTA <yokota@pylone.jp>
108c0984e5SSebastian Reichel  * Originally found here:
118c0984e5SSebastian Reichel  * http://downloads.pylone.jp/src/virtual_battery/virtual_battery-0.0.1.tar.bz2
128c0984e5SSebastian Reichel  */
138c0984e5SSebastian Reichel 
148c0984e5SSebastian Reichel #include <linux/kernel.h>
158c0984e5SSebastian Reichel #include <linux/module.h>
168c0984e5SSebastian Reichel #include <linux/power_supply.h>
178c0984e5SSebastian Reichel #include <linux/errno.h>
188c0984e5SSebastian Reichel #include <linux/delay.h>
191c79031fSLeon Romanovsky #include <generated/utsrelease.h>
208c0984e5SSebastian Reichel 
218c0984e5SSebastian Reichel enum test_power_id {
228c0984e5SSebastian Reichel 	TEST_AC,
238c0984e5SSebastian Reichel 	TEST_BATTERY,
248c0984e5SSebastian Reichel 	TEST_USB,
258c0984e5SSebastian Reichel 	TEST_POWER_NUM,
268c0984e5SSebastian Reichel };
278c0984e5SSebastian Reichel 
288c0984e5SSebastian Reichel static int ac_online			= 1;
298c0984e5SSebastian Reichel static int usb_online			= 1;
308c0984e5SSebastian Reichel static int battery_status		= POWER_SUPPLY_STATUS_DISCHARGING;
318c0984e5SSebastian Reichel static int battery_health		= POWER_SUPPLY_HEALTH_GOOD;
328c0984e5SSebastian Reichel static int battery_present		= 1; /* true */
338c0984e5SSebastian Reichel static int battery_technology		= POWER_SUPPLY_TECHNOLOGY_LION;
348c0984e5SSebastian Reichel static int battery_capacity		= 50;
358c0984e5SSebastian Reichel static int battery_voltage		= 3300;
364b082ac6Slecopzer@gmail.com static int battery_charge_counter	= -1000;
37c365ee56SLH Lin static int battery_current		= -1600;
388c0984e5SSebastian Reichel 
398c0984e5SSebastian Reichel static bool module_initialized;
408c0984e5SSebastian Reichel 
test_power_get_ac_property(struct power_supply * psy,enum power_supply_property psp,union power_supply_propval * val)418c0984e5SSebastian Reichel static int test_power_get_ac_property(struct power_supply *psy,
428c0984e5SSebastian Reichel 				      enum power_supply_property psp,
438c0984e5SSebastian Reichel 				      union power_supply_propval *val)
448c0984e5SSebastian Reichel {
458c0984e5SSebastian Reichel 	switch (psp) {
468c0984e5SSebastian Reichel 	case POWER_SUPPLY_PROP_ONLINE:
478c0984e5SSebastian Reichel 		val->intval = ac_online;
488c0984e5SSebastian Reichel 		break;
498c0984e5SSebastian Reichel 	default:
508c0984e5SSebastian Reichel 		return -EINVAL;
518c0984e5SSebastian Reichel 	}
528c0984e5SSebastian Reichel 	return 0;
538c0984e5SSebastian Reichel }
548c0984e5SSebastian Reichel 
test_power_get_usb_property(struct power_supply * psy,enum power_supply_property psp,union power_supply_propval * val)558c0984e5SSebastian Reichel static int test_power_get_usb_property(struct power_supply *psy,
568c0984e5SSebastian Reichel 				      enum power_supply_property psp,
578c0984e5SSebastian Reichel 				      union power_supply_propval *val)
588c0984e5SSebastian Reichel {
598c0984e5SSebastian Reichel 	switch (psp) {
608c0984e5SSebastian Reichel 	case POWER_SUPPLY_PROP_ONLINE:
618c0984e5SSebastian Reichel 		val->intval = usb_online;
628c0984e5SSebastian Reichel 		break;
638c0984e5SSebastian Reichel 	default:
648c0984e5SSebastian Reichel 		return -EINVAL;
658c0984e5SSebastian Reichel 	}
668c0984e5SSebastian Reichel 	return 0;
678c0984e5SSebastian Reichel }
688c0984e5SSebastian Reichel 
test_power_get_battery_property(struct power_supply * psy,enum power_supply_property psp,union power_supply_propval * val)698c0984e5SSebastian Reichel static int test_power_get_battery_property(struct power_supply *psy,
708c0984e5SSebastian Reichel 					   enum power_supply_property psp,
718c0984e5SSebastian Reichel 					   union power_supply_propval *val)
728c0984e5SSebastian Reichel {
738c0984e5SSebastian Reichel 	switch (psp) {
748c0984e5SSebastian Reichel 	case POWER_SUPPLY_PROP_MODEL_NAME:
758c0984e5SSebastian Reichel 		val->strval = "Test battery";
768c0984e5SSebastian Reichel 		break;
778c0984e5SSebastian Reichel 	case POWER_SUPPLY_PROP_MANUFACTURER:
788c0984e5SSebastian Reichel 		val->strval = "Linux";
798c0984e5SSebastian Reichel 		break;
808c0984e5SSebastian Reichel 	case POWER_SUPPLY_PROP_SERIAL_NUMBER:
818c0984e5SSebastian Reichel 		val->strval = UTS_RELEASE;
828c0984e5SSebastian Reichel 		break;
838c0984e5SSebastian Reichel 	case POWER_SUPPLY_PROP_STATUS:
848c0984e5SSebastian Reichel 		val->intval = battery_status;
858c0984e5SSebastian Reichel 		break;
868c0984e5SSebastian Reichel 	case POWER_SUPPLY_PROP_CHARGE_TYPE:
878c0984e5SSebastian Reichel 		val->intval = POWER_SUPPLY_CHARGE_TYPE_FAST;
888c0984e5SSebastian Reichel 		break;
898c0984e5SSebastian Reichel 	case POWER_SUPPLY_PROP_HEALTH:
908c0984e5SSebastian Reichel 		val->intval = battery_health;
918c0984e5SSebastian Reichel 		break;
928c0984e5SSebastian Reichel 	case POWER_SUPPLY_PROP_PRESENT:
938c0984e5SSebastian Reichel 		val->intval = battery_present;
948c0984e5SSebastian Reichel 		break;
958c0984e5SSebastian Reichel 	case POWER_SUPPLY_PROP_TECHNOLOGY:
968c0984e5SSebastian Reichel 		val->intval = battery_technology;
978c0984e5SSebastian Reichel 		break;
988c0984e5SSebastian Reichel 	case POWER_SUPPLY_PROP_CAPACITY_LEVEL:
998c0984e5SSebastian Reichel 		val->intval = POWER_SUPPLY_CAPACITY_LEVEL_NORMAL;
1008c0984e5SSebastian Reichel 		break;
1018c0984e5SSebastian Reichel 	case POWER_SUPPLY_PROP_CAPACITY:
1028c0984e5SSebastian Reichel 	case POWER_SUPPLY_PROP_CHARGE_NOW:
1038c0984e5SSebastian Reichel 		val->intval = battery_capacity;
1048c0984e5SSebastian Reichel 		break;
1054b082ac6Slecopzer@gmail.com 	case POWER_SUPPLY_PROP_CHARGE_COUNTER:
1064b082ac6Slecopzer@gmail.com 		val->intval = battery_charge_counter;
1074b082ac6Slecopzer@gmail.com 		break;
1088c0984e5SSebastian Reichel 	case POWER_SUPPLY_PROP_CHARGE_FULL_DESIGN:
1098c0984e5SSebastian Reichel 	case POWER_SUPPLY_PROP_CHARGE_FULL:
1108c0984e5SSebastian Reichel 		val->intval = 100;
1118c0984e5SSebastian Reichel 		break;
1128c0984e5SSebastian Reichel 	case POWER_SUPPLY_PROP_TIME_TO_EMPTY_AVG:
1138c0984e5SSebastian Reichel 	case POWER_SUPPLY_PROP_TIME_TO_FULL_NOW:
1148c0984e5SSebastian Reichel 		val->intval = 3600;
1158c0984e5SSebastian Reichel 		break;
1168c0984e5SSebastian Reichel 	case POWER_SUPPLY_PROP_TEMP:
1178c0984e5SSebastian Reichel 		val->intval = 26;
1188c0984e5SSebastian Reichel 		break;
1198c0984e5SSebastian Reichel 	case POWER_SUPPLY_PROP_VOLTAGE_NOW:
1208c0984e5SSebastian Reichel 		val->intval = battery_voltage;
1218c0984e5SSebastian Reichel 		break;
12269318b39Slecopzer@gmail.com 	case POWER_SUPPLY_PROP_CURRENT_AVG:
12369318b39Slecopzer@gmail.com 	case POWER_SUPPLY_PROP_CURRENT_NOW:
12469318b39Slecopzer@gmail.com 		val->intval = battery_current;
12569318b39Slecopzer@gmail.com 		break;
1268c0984e5SSebastian Reichel 	default:
1278c0984e5SSebastian Reichel 		pr_info("%s: some properties deliberately report errors.\n",
1288c0984e5SSebastian Reichel 			__func__);
1298c0984e5SSebastian Reichel 		return -EINVAL;
1308c0984e5SSebastian Reichel 	}
1318c0984e5SSebastian Reichel 	return 0;
1328c0984e5SSebastian Reichel }
1338c0984e5SSebastian Reichel 
1348c0984e5SSebastian Reichel static enum power_supply_property test_power_ac_props[] = {
1358c0984e5SSebastian Reichel 	POWER_SUPPLY_PROP_ONLINE,
1368c0984e5SSebastian Reichel };
1378c0984e5SSebastian Reichel 
1388c0984e5SSebastian Reichel static enum power_supply_property test_power_battery_props[] = {
1398c0984e5SSebastian Reichel 	POWER_SUPPLY_PROP_STATUS,
1408c0984e5SSebastian Reichel 	POWER_SUPPLY_PROP_CHARGE_TYPE,
1418c0984e5SSebastian Reichel 	POWER_SUPPLY_PROP_HEALTH,
1428c0984e5SSebastian Reichel 	POWER_SUPPLY_PROP_PRESENT,
1438c0984e5SSebastian Reichel 	POWER_SUPPLY_PROP_TECHNOLOGY,
1448c0984e5SSebastian Reichel 	POWER_SUPPLY_PROP_CHARGE_FULL_DESIGN,
1458c0984e5SSebastian Reichel 	POWER_SUPPLY_PROP_CHARGE_FULL,
1468c0984e5SSebastian Reichel 	POWER_SUPPLY_PROP_CHARGE_NOW,
1474b082ac6Slecopzer@gmail.com 	POWER_SUPPLY_PROP_CHARGE_COUNTER,
1488c0984e5SSebastian Reichel 	POWER_SUPPLY_PROP_CAPACITY,
1498c0984e5SSebastian Reichel 	POWER_SUPPLY_PROP_CAPACITY_LEVEL,
1508c0984e5SSebastian Reichel 	POWER_SUPPLY_PROP_TIME_TO_EMPTY_AVG,
1518c0984e5SSebastian Reichel 	POWER_SUPPLY_PROP_TIME_TO_FULL_NOW,
1528c0984e5SSebastian Reichel 	POWER_SUPPLY_PROP_MODEL_NAME,
1538c0984e5SSebastian Reichel 	POWER_SUPPLY_PROP_MANUFACTURER,
1548c0984e5SSebastian Reichel 	POWER_SUPPLY_PROP_SERIAL_NUMBER,
1558c0984e5SSebastian Reichel 	POWER_SUPPLY_PROP_TEMP,
1568c0984e5SSebastian Reichel 	POWER_SUPPLY_PROP_VOLTAGE_NOW,
15769318b39Slecopzer@gmail.com 	POWER_SUPPLY_PROP_CURRENT_AVG,
15869318b39Slecopzer@gmail.com 	POWER_SUPPLY_PROP_CURRENT_NOW,
1598c0984e5SSebastian Reichel };
1608c0984e5SSebastian Reichel 
1618c0984e5SSebastian Reichel static char *test_power_ac_supplied_to[] = {
1628c0984e5SSebastian Reichel 	"test_battery",
1638c0984e5SSebastian Reichel };
1648c0984e5SSebastian Reichel 
1658c0984e5SSebastian Reichel static struct power_supply *test_power_supplies[TEST_POWER_NUM];
1668c0984e5SSebastian Reichel 
1678c0984e5SSebastian Reichel static const struct power_supply_desc test_power_desc[] = {
1688c0984e5SSebastian Reichel 	[TEST_AC] = {
1698c0984e5SSebastian Reichel 		.name = "test_ac",
1708c0984e5SSebastian Reichel 		.type = POWER_SUPPLY_TYPE_MAINS,
1718c0984e5SSebastian Reichel 		.properties = test_power_ac_props,
1728c0984e5SSebastian Reichel 		.num_properties = ARRAY_SIZE(test_power_ac_props),
1738c0984e5SSebastian Reichel 		.get_property = test_power_get_ac_property,
1748c0984e5SSebastian Reichel 	},
1758c0984e5SSebastian Reichel 	[TEST_BATTERY] = {
1768c0984e5SSebastian Reichel 		.name = "test_battery",
1778c0984e5SSebastian Reichel 		.type = POWER_SUPPLY_TYPE_BATTERY,
1788c0984e5SSebastian Reichel 		.properties = test_power_battery_props,
1798c0984e5SSebastian Reichel 		.num_properties = ARRAY_SIZE(test_power_battery_props),
1808c0984e5SSebastian Reichel 		.get_property = test_power_get_battery_property,
1818c0984e5SSebastian Reichel 	},
1828c0984e5SSebastian Reichel 	[TEST_USB] = {
1838c0984e5SSebastian Reichel 		.name = "test_usb",
1848c0984e5SSebastian Reichel 		.type = POWER_SUPPLY_TYPE_USB,
1858c0984e5SSebastian Reichel 		.properties = test_power_ac_props,
1868c0984e5SSebastian Reichel 		.num_properties = ARRAY_SIZE(test_power_ac_props),
1878c0984e5SSebastian Reichel 		.get_property = test_power_get_usb_property,
1888c0984e5SSebastian Reichel 	},
1898c0984e5SSebastian Reichel };
1908c0984e5SSebastian Reichel 
1918c0984e5SSebastian Reichel static const struct power_supply_config test_power_configs[] = {
1928c0984e5SSebastian Reichel 	{
1938c0984e5SSebastian Reichel 		/* test_ac */
1948c0984e5SSebastian Reichel 		.supplied_to = test_power_ac_supplied_to,
1958c0984e5SSebastian Reichel 		.num_supplicants = ARRAY_SIZE(test_power_ac_supplied_to),
1968c0984e5SSebastian Reichel 	}, {
1978c0984e5SSebastian Reichel 		/* test_battery */
1988c0984e5SSebastian Reichel 	}, {
1998c0984e5SSebastian Reichel 		/* test_usb */
2008c0984e5SSebastian Reichel 		.supplied_to = test_power_ac_supplied_to,
2018c0984e5SSebastian Reichel 		.num_supplicants = ARRAY_SIZE(test_power_ac_supplied_to),
2028c0984e5SSebastian Reichel 	},
2038c0984e5SSebastian Reichel };
2048c0984e5SSebastian Reichel 
test_power_init(void)2058c0984e5SSebastian Reichel static int __init test_power_init(void)
2068c0984e5SSebastian Reichel {
2078c0984e5SSebastian Reichel 	int i;
2088c0984e5SSebastian Reichel 	int ret;
2098c0984e5SSebastian Reichel 
2108c0984e5SSebastian Reichel 	BUILD_BUG_ON(TEST_POWER_NUM != ARRAY_SIZE(test_power_supplies));
2118c0984e5SSebastian Reichel 	BUILD_BUG_ON(TEST_POWER_NUM != ARRAY_SIZE(test_power_configs));
2128c0984e5SSebastian Reichel 
2138c0984e5SSebastian Reichel 	for (i = 0; i < ARRAY_SIZE(test_power_supplies); i++) {
2148c0984e5SSebastian Reichel 		test_power_supplies[i] = power_supply_register(NULL,
2158c0984e5SSebastian Reichel 						&test_power_desc[i],
2168c0984e5SSebastian Reichel 						&test_power_configs[i]);
2178c0984e5SSebastian Reichel 		if (IS_ERR(test_power_supplies[i])) {
2188c0984e5SSebastian Reichel 			pr_err("%s: failed to register %s\n", __func__,
2198c0984e5SSebastian Reichel 				test_power_desc[i].name);
2208c0984e5SSebastian Reichel 			ret = PTR_ERR(test_power_supplies[i]);
2218c0984e5SSebastian Reichel 			goto failed;
2228c0984e5SSebastian Reichel 		}
2238c0984e5SSebastian Reichel 	}
2248c0984e5SSebastian Reichel 
2258c0984e5SSebastian Reichel 	module_initialized = true;
2268c0984e5SSebastian Reichel 	return 0;
2278c0984e5SSebastian Reichel failed:
2288c0984e5SSebastian Reichel 	while (--i >= 0)
2298c0984e5SSebastian Reichel 		power_supply_unregister(test_power_supplies[i]);
2308c0984e5SSebastian Reichel 	return ret;
2318c0984e5SSebastian Reichel }
2328c0984e5SSebastian Reichel module_init(test_power_init);
2338c0984e5SSebastian Reichel 
test_power_exit(void)2348c0984e5SSebastian Reichel static void __exit test_power_exit(void)
2358c0984e5SSebastian Reichel {
2368c0984e5SSebastian Reichel 	int i;
2378c0984e5SSebastian Reichel 
2388c0984e5SSebastian Reichel 	/* Let's see how we handle changes... */
2398c0984e5SSebastian Reichel 	ac_online = 0;
2408c0984e5SSebastian Reichel 	usb_online = 0;
2418c0984e5SSebastian Reichel 	battery_status = POWER_SUPPLY_STATUS_DISCHARGING;
2428c0984e5SSebastian Reichel 	for (i = 0; i < ARRAY_SIZE(test_power_supplies); i++)
2438c0984e5SSebastian Reichel 		power_supply_changed(test_power_supplies[i]);
2448c0984e5SSebastian Reichel 	pr_info("%s: 'changed' event sent, sleeping for 10 seconds...\n",
2458c0984e5SSebastian Reichel 		__func__);
2468c0984e5SSebastian Reichel 	ssleep(10);
2478c0984e5SSebastian Reichel 
2488c0984e5SSebastian Reichel 	for (i = 0; i < ARRAY_SIZE(test_power_supplies); i++)
2498c0984e5SSebastian Reichel 		power_supply_unregister(test_power_supplies[i]);
2508c0984e5SSebastian Reichel 
2518c0984e5SSebastian Reichel 	module_initialized = false;
2528c0984e5SSebastian Reichel }
2538c0984e5SSebastian Reichel module_exit(test_power_exit);
2548c0984e5SSebastian Reichel 
2558c0984e5SSebastian Reichel 
2568c0984e5SSebastian Reichel 
2578c0984e5SSebastian Reichel #define MAX_KEYLENGTH 256
2588c0984e5SSebastian Reichel struct battery_property_map {
2598c0984e5SSebastian Reichel 	int value;
2608c0984e5SSebastian Reichel 	char const *key;
2618c0984e5SSebastian Reichel };
2628c0984e5SSebastian Reichel 
2638c0984e5SSebastian Reichel static struct battery_property_map map_ac_online[] = {
2648c0984e5SSebastian Reichel 	{ 0,  "off"  },
2658c0984e5SSebastian Reichel 	{ 1,  "on" },
2668c0984e5SSebastian Reichel 	{ -1, NULL  },
2678c0984e5SSebastian Reichel };
2688c0984e5SSebastian Reichel 
2698c0984e5SSebastian Reichel static struct battery_property_map map_status[] = {
2708c0984e5SSebastian Reichel 	{ POWER_SUPPLY_STATUS_CHARGING,     "charging"     },
2718c0984e5SSebastian Reichel 	{ POWER_SUPPLY_STATUS_DISCHARGING,  "discharging"  },
2728c0984e5SSebastian Reichel 	{ POWER_SUPPLY_STATUS_NOT_CHARGING, "not-charging" },
2738c0984e5SSebastian Reichel 	{ POWER_SUPPLY_STATUS_FULL,         "full"         },
2748c0984e5SSebastian Reichel 	{ -1,                               NULL           },
2758c0984e5SSebastian Reichel };
2768c0984e5SSebastian Reichel 
2778c0984e5SSebastian Reichel static struct battery_property_map map_health[] = {
2788c0984e5SSebastian Reichel 	{ POWER_SUPPLY_HEALTH_GOOD,           "good"        },
2798c0984e5SSebastian Reichel 	{ POWER_SUPPLY_HEALTH_OVERHEAT,       "overheat"    },
2808c0984e5SSebastian Reichel 	{ POWER_SUPPLY_HEALTH_DEAD,           "dead"        },
2818c0984e5SSebastian Reichel 	{ POWER_SUPPLY_HEALTH_OVERVOLTAGE,    "overvoltage" },
2828c0984e5SSebastian Reichel 	{ POWER_SUPPLY_HEALTH_UNSPEC_FAILURE, "failure"     },
2838c0984e5SSebastian Reichel 	{ -1,                                 NULL          },
2848c0984e5SSebastian Reichel };
2858c0984e5SSebastian Reichel 
2868c0984e5SSebastian Reichel static struct battery_property_map map_present[] = {
2878c0984e5SSebastian Reichel 	{ 0,  "false" },
2888c0984e5SSebastian Reichel 	{ 1,  "true"  },
2898c0984e5SSebastian Reichel 	{ -1, NULL    },
2908c0984e5SSebastian Reichel };
2918c0984e5SSebastian Reichel 
2928c0984e5SSebastian Reichel static struct battery_property_map map_technology[] = {
2938c0984e5SSebastian Reichel 	{ POWER_SUPPLY_TECHNOLOGY_NiMH, "NiMH" },
2948c0984e5SSebastian Reichel 	{ POWER_SUPPLY_TECHNOLOGY_LION, "LION" },
2958c0984e5SSebastian Reichel 	{ POWER_SUPPLY_TECHNOLOGY_LIPO, "LIPO" },
2968c0984e5SSebastian Reichel 	{ POWER_SUPPLY_TECHNOLOGY_LiFe, "LiFe" },
2978c0984e5SSebastian Reichel 	{ POWER_SUPPLY_TECHNOLOGY_NiCd, "NiCd" },
2988c0984e5SSebastian Reichel 	{ POWER_SUPPLY_TECHNOLOGY_LiMn, "LiMn" },
2998c0984e5SSebastian Reichel 	{ -1,				NULL   },
3008c0984e5SSebastian Reichel };
3018c0984e5SSebastian Reichel 
3028c0984e5SSebastian Reichel 
map_get_value(struct battery_property_map * map,const char * key,int def_val)3038c0984e5SSebastian Reichel static int map_get_value(struct battery_property_map *map, const char *key,
3048c0984e5SSebastian Reichel 				int def_val)
3058c0984e5SSebastian Reichel {
3068c0984e5SSebastian Reichel 	char buf[MAX_KEYLENGTH];
3078c0984e5SSebastian Reichel 	int cr;
3088c0984e5SSebastian Reichel 
309*3639dbd7SXu Panda 	strscpy(buf, key, MAX_KEYLENGTH);
3108c0984e5SSebastian Reichel 
3118c0984e5SSebastian Reichel 	cr = strnlen(buf, MAX_KEYLENGTH) - 1;
3128c0984e5SSebastian Reichel 	if (cr < 0)
3138c0984e5SSebastian Reichel 		return def_val;
3148c0984e5SSebastian Reichel 	if (buf[cr] == '\n')
3158c0984e5SSebastian Reichel 		buf[cr] = '\0';
3168c0984e5SSebastian Reichel 
3178c0984e5SSebastian Reichel 	while (map->key) {
3188c0984e5SSebastian Reichel 		if (strncasecmp(map->key, buf, MAX_KEYLENGTH) == 0)
3198c0984e5SSebastian Reichel 			return map->value;
3208c0984e5SSebastian Reichel 		map++;
3218c0984e5SSebastian Reichel 	}
3228c0984e5SSebastian Reichel 
3238c0984e5SSebastian Reichel 	return def_val;
3248c0984e5SSebastian Reichel }
3258c0984e5SSebastian Reichel 
3268c0984e5SSebastian Reichel 
map_get_key(struct battery_property_map * map,int value,const char * def_key)3278c0984e5SSebastian Reichel static const char *map_get_key(struct battery_property_map *map, int value,
3288c0984e5SSebastian Reichel 				const char *def_key)
3298c0984e5SSebastian Reichel {
3308c0984e5SSebastian Reichel 	while (map->key) {
3318c0984e5SSebastian Reichel 		if (map->value == value)
3328c0984e5SSebastian Reichel 			return map->key;
3338c0984e5SSebastian Reichel 		map++;
3348c0984e5SSebastian Reichel 	}
3358c0984e5SSebastian Reichel 
3368c0984e5SSebastian Reichel 	return def_key;
3378c0984e5SSebastian Reichel }
3388c0984e5SSebastian Reichel 
signal_power_supply_changed(struct power_supply * psy)3398c0984e5SSebastian Reichel static inline void signal_power_supply_changed(struct power_supply *psy)
3408c0984e5SSebastian Reichel {
3418c0984e5SSebastian Reichel 	if (module_initialized)
3428c0984e5SSebastian Reichel 		power_supply_changed(psy);
3438c0984e5SSebastian Reichel }
3448c0984e5SSebastian Reichel 
param_set_ac_online(const char * key,const struct kernel_param * kp)3458c0984e5SSebastian Reichel static int param_set_ac_online(const char *key, const struct kernel_param *kp)
3468c0984e5SSebastian Reichel {
3478c0984e5SSebastian Reichel 	ac_online = map_get_value(map_ac_online, key, ac_online);
3488c0984e5SSebastian Reichel 	signal_power_supply_changed(test_power_supplies[TEST_AC]);
3498c0984e5SSebastian Reichel 	return 0;
3508c0984e5SSebastian Reichel }
3518c0984e5SSebastian Reichel 
param_get_ac_online(char * buffer,const struct kernel_param * kp)3528c0984e5SSebastian Reichel static int param_get_ac_online(char *buffer, const struct kernel_param *kp)
3538c0984e5SSebastian Reichel {
354411643e9SHarley A.W. Lorenzo 	return sprintf(buffer, "%s\n",
355411643e9SHarley A.W. Lorenzo 			map_get_key(map_ac_online, ac_online, "unknown"));
3568c0984e5SSebastian Reichel }
3578c0984e5SSebastian Reichel 
param_set_usb_online(const char * key,const struct kernel_param * kp)3588c0984e5SSebastian Reichel static int param_set_usb_online(const char *key, const struct kernel_param *kp)
3598c0984e5SSebastian Reichel {
3608c0984e5SSebastian Reichel 	usb_online = map_get_value(map_ac_online, key, usb_online);
3618c0984e5SSebastian Reichel 	signal_power_supply_changed(test_power_supplies[TEST_USB]);
3628c0984e5SSebastian Reichel 	return 0;
3638c0984e5SSebastian Reichel }
3648c0984e5SSebastian Reichel 
param_get_usb_online(char * buffer,const struct kernel_param * kp)3658c0984e5SSebastian Reichel static int param_get_usb_online(char *buffer, const struct kernel_param *kp)
3668c0984e5SSebastian Reichel {
367411643e9SHarley A.W. Lorenzo 	return sprintf(buffer, "%s\n",
368411643e9SHarley A.W. Lorenzo 			map_get_key(map_ac_online, usb_online, "unknown"));
3698c0984e5SSebastian Reichel }
3708c0984e5SSebastian Reichel 
param_set_battery_status(const char * key,const struct kernel_param * kp)3718c0984e5SSebastian Reichel static int param_set_battery_status(const char *key,
3728c0984e5SSebastian Reichel 					const struct kernel_param *kp)
3738c0984e5SSebastian Reichel {
3748c0984e5SSebastian Reichel 	battery_status = map_get_value(map_status, key, battery_status);
3758c0984e5SSebastian Reichel 	signal_power_supply_changed(test_power_supplies[TEST_BATTERY]);
3768c0984e5SSebastian Reichel 	return 0;
3778c0984e5SSebastian Reichel }
3788c0984e5SSebastian Reichel 
param_get_battery_status(char * buffer,const struct kernel_param * kp)3798c0984e5SSebastian Reichel static int param_get_battery_status(char *buffer, const struct kernel_param *kp)
3808c0984e5SSebastian Reichel {
381411643e9SHarley A.W. Lorenzo 	return sprintf(buffer, "%s\n",
382411643e9SHarley A.W. Lorenzo 			map_get_key(map_ac_online, battery_status, "unknown"));
3838c0984e5SSebastian Reichel }
3848c0984e5SSebastian Reichel 
param_set_battery_health(const char * key,const struct kernel_param * kp)3858c0984e5SSebastian Reichel static int param_set_battery_health(const char *key,
3868c0984e5SSebastian Reichel 					const struct kernel_param *kp)
3878c0984e5SSebastian Reichel {
3888c0984e5SSebastian Reichel 	battery_health = map_get_value(map_health, key, battery_health);
3898c0984e5SSebastian Reichel 	signal_power_supply_changed(test_power_supplies[TEST_BATTERY]);
3908c0984e5SSebastian Reichel 	return 0;
3918c0984e5SSebastian Reichel }
3928c0984e5SSebastian Reichel 
param_get_battery_health(char * buffer,const struct kernel_param * kp)3938c0984e5SSebastian Reichel static int param_get_battery_health(char *buffer, const struct kernel_param *kp)
3948c0984e5SSebastian Reichel {
395411643e9SHarley A.W. Lorenzo 	return sprintf(buffer, "%s\n",
396411643e9SHarley A.W. Lorenzo 			map_get_key(map_ac_online, battery_health, "unknown"));
3978c0984e5SSebastian Reichel }
3988c0984e5SSebastian Reichel 
param_set_battery_present(const char * key,const struct kernel_param * kp)3998c0984e5SSebastian Reichel static int param_set_battery_present(const char *key,
4008c0984e5SSebastian Reichel 					const struct kernel_param *kp)
4018c0984e5SSebastian Reichel {
4028c0984e5SSebastian Reichel 	battery_present = map_get_value(map_present, key, battery_present);
4038c0984e5SSebastian Reichel 	signal_power_supply_changed(test_power_supplies[TEST_AC]);
4048c0984e5SSebastian Reichel 	return 0;
4058c0984e5SSebastian Reichel }
4068c0984e5SSebastian Reichel 
param_get_battery_present(char * buffer,const struct kernel_param * kp)4078c0984e5SSebastian Reichel static int param_get_battery_present(char *buffer,
4088c0984e5SSebastian Reichel 					const struct kernel_param *kp)
4098c0984e5SSebastian Reichel {
410411643e9SHarley A.W. Lorenzo 	return sprintf(buffer, "%s\n",
411411643e9SHarley A.W. Lorenzo 			map_get_key(map_ac_online, battery_present, "unknown"));
4128c0984e5SSebastian Reichel }
4138c0984e5SSebastian Reichel 
param_set_battery_technology(const char * key,const struct kernel_param * kp)4148c0984e5SSebastian Reichel static int param_set_battery_technology(const char *key,
4158c0984e5SSebastian Reichel 					const struct kernel_param *kp)
4168c0984e5SSebastian Reichel {
4178c0984e5SSebastian Reichel 	battery_technology = map_get_value(map_technology, key,
4188c0984e5SSebastian Reichel 						battery_technology);
4198c0984e5SSebastian Reichel 	signal_power_supply_changed(test_power_supplies[TEST_BATTERY]);
4208c0984e5SSebastian Reichel 	return 0;
4218c0984e5SSebastian Reichel }
4228c0984e5SSebastian Reichel 
param_get_battery_technology(char * buffer,const struct kernel_param * kp)4238c0984e5SSebastian Reichel static int param_get_battery_technology(char *buffer,
4248c0984e5SSebastian Reichel 					const struct kernel_param *kp)
4258c0984e5SSebastian Reichel {
426411643e9SHarley A.W. Lorenzo 	return sprintf(buffer, "%s\n",
427411643e9SHarley A.W. Lorenzo 			map_get_key(map_ac_online, battery_technology,
428411643e9SHarley A.W. Lorenzo 					"unknown"));
4298c0984e5SSebastian Reichel }
4308c0984e5SSebastian Reichel 
param_set_battery_capacity(const char * key,const struct kernel_param * kp)4318c0984e5SSebastian Reichel static int param_set_battery_capacity(const char *key,
4328c0984e5SSebastian Reichel 					const struct kernel_param *kp)
4338c0984e5SSebastian Reichel {
4348c0984e5SSebastian Reichel 	int tmp;
4358c0984e5SSebastian Reichel 
4368c0984e5SSebastian Reichel 	if (1 != sscanf(key, "%d", &tmp))
4378c0984e5SSebastian Reichel 		return -EINVAL;
4388c0984e5SSebastian Reichel 
4398c0984e5SSebastian Reichel 	battery_capacity = tmp;
4408c0984e5SSebastian Reichel 	signal_power_supply_changed(test_power_supplies[TEST_BATTERY]);
4418c0984e5SSebastian Reichel 	return 0;
4428c0984e5SSebastian Reichel }
4438c0984e5SSebastian Reichel 
4448c0984e5SSebastian Reichel #define param_get_battery_capacity param_get_int
4458c0984e5SSebastian Reichel 
param_set_battery_voltage(const char * key,const struct kernel_param * kp)4468c0984e5SSebastian Reichel static int param_set_battery_voltage(const char *key,
4478c0984e5SSebastian Reichel 					const struct kernel_param *kp)
4488c0984e5SSebastian Reichel {
4498c0984e5SSebastian Reichel 	int tmp;
4508c0984e5SSebastian Reichel 
4518c0984e5SSebastian Reichel 	if (1 != sscanf(key, "%d", &tmp))
4528c0984e5SSebastian Reichel 		return -EINVAL;
4538c0984e5SSebastian Reichel 
4548c0984e5SSebastian Reichel 	battery_voltage = tmp;
4558c0984e5SSebastian Reichel 	signal_power_supply_changed(test_power_supplies[TEST_BATTERY]);
4568c0984e5SSebastian Reichel 	return 0;
4578c0984e5SSebastian Reichel }
4588c0984e5SSebastian Reichel 
4598c0984e5SSebastian Reichel #define param_get_battery_voltage param_get_int
4608c0984e5SSebastian Reichel 
param_set_battery_charge_counter(const char * key,const struct kernel_param * kp)4614b082ac6Slecopzer@gmail.com static int param_set_battery_charge_counter(const char *key,
4624b082ac6Slecopzer@gmail.com 					const struct kernel_param *kp)
4634b082ac6Slecopzer@gmail.com {
4644b082ac6Slecopzer@gmail.com 	int tmp;
4654b082ac6Slecopzer@gmail.com 
4664b082ac6Slecopzer@gmail.com 	if (1 != sscanf(key, "%d", &tmp))
4674b082ac6Slecopzer@gmail.com 		return -EINVAL;
4684b082ac6Slecopzer@gmail.com 
4694b082ac6Slecopzer@gmail.com 	battery_charge_counter = tmp;
4704b082ac6Slecopzer@gmail.com 	signal_power_supply_changed(test_power_supplies[TEST_BATTERY]);
4714b082ac6Slecopzer@gmail.com 	return 0;
4724b082ac6Slecopzer@gmail.com }
4734b082ac6Slecopzer@gmail.com 
4744b082ac6Slecopzer@gmail.com #define param_get_battery_charge_counter param_get_int
4754b082ac6Slecopzer@gmail.com 
param_set_battery_current(const char * key,const struct kernel_param * kp)47669318b39Slecopzer@gmail.com static int param_set_battery_current(const char *key,
47769318b39Slecopzer@gmail.com 					const struct kernel_param *kp)
47869318b39Slecopzer@gmail.com {
47969318b39Slecopzer@gmail.com 	int tmp;
48069318b39Slecopzer@gmail.com 
48169318b39Slecopzer@gmail.com 	if (1 != sscanf(key, "%d", &tmp))
48269318b39Slecopzer@gmail.com 		return -EINVAL;
48369318b39Slecopzer@gmail.com 
48469318b39Slecopzer@gmail.com 	battery_current = tmp;
48569318b39Slecopzer@gmail.com 	signal_power_supply_changed(test_power_supplies[TEST_BATTERY]);
48669318b39Slecopzer@gmail.com 	return 0;
48769318b39Slecopzer@gmail.com }
48869318b39Slecopzer@gmail.com 
48969318b39Slecopzer@gmail.com #define param_get_battery_current param_get_int
49069318b39Slecopzer@gmail.com 
4918c0984e5SSebastian Reichel static const struct kernel_param_ops param_ops_ac_online = {
4928c0984e5SSebastian Reichel 	.set = param_set_ac_online,
4938c0984e5SSebastian Reichel 	.get = param_get_ac_online,
4948c0984e5SSebastian Reichel };
4958c0984e5SSebastian Reichel 
4968c0984e5SSebastian Reichel static const struct kernel_param_ops param_ops_usb_online = {
4978c0984e5SSebastian Reichel 	.set = param_set_usb_online,
4988c0984e5SSebastian Reichel 	.get = param_get_usb_online,
4998c0984e5SSebastian Reichel };
5008c0984e5SSebastian Reichel 
5018c0984e5SSebastian Reichel static const struct kernel_param_ops param_ops_battery_status = {
5028c0984e5SSebastian Reichel 	.set = param_set_battery_status,
5038c0984e5SSebastian Reichel 	.get = param_get_battery_status,
5048c0984e5SSebastian Reichel };
5058c0984e5SSebastian Reichel 
5068c0984e5SSebastian Reichel static const struct kernel_param_ops param_ops_battery_present = {
5078c0984e5SSebastian Reichel 	.set = param_set_battery_present,
5088c0984e5SSebastian Reichel 	.get = param_get_battery_present,
5098c0984e5SSebastian Reichel };
5108c0984e5SSebastian Reichel 
5118c0984e5SSebastian Reichel static const struct kernel_param_ops param_ops_battery_technology = {
5128c0984e5SSebastian Reichel 	.set = param_set_battery_technology,
5138c0984e5SSebastian Reichel 	.get = param_get_battery_technology,
5148c0984e5SSebastian Reichel };
5158c0984e5SSebastian Reichel 
5168c0984e5SSebastian Reichel static const struct kernel_param_ops param_ops_battery_health = {
5178c0984e5SSebastian Reichel 	.set = param_set_battery_health,
5188c0984e5SSebastian Reichel 	.get = param_get_battery_health,
5198c0984e5SSebastian Reichel };
5208c0984e5SSebastian Reichel 
5218c0984e5SSebastian Reichel static const struct kernel_param_ops param_ops_battery_capacity = {
5228c0984e5SSebastian Reichel 	.set = param_set_battery_capacity,
5238c0984e5SSebastian Reichel 	.get = param_get_battery_capacity,
5248c0984e5SSebastian Reichel };
5258c0984e5SSebastian Reichel 
5268c0984e5SSebastian Reichel static const struct kernel_param_ops param_ops_battery_voltage = {
5278c0984e5SSebastian Reichel 	.set = param_set_battery_voltage,
5288c0984e5SSebastian Reichel 	.get = param_get_battery_voltage,
5298c0984e5SSebastian Reichel };
5308c0984e5SSebastian Reichel 
5314b082ac6Slecopzer@gmail.com static const struct kernel_param_ops param_ops_battery_charge_counter = {
5324b082ac6Slecopzer@gmail.com 	.set = param_set_battery_charge_counter,
5334b082ac6Slecopzer@gmail.com 	.get = param_get_battery_charge_counter,
5344b082ac6Slecopzer@gmail.com };
5354b082ac6Slecopzer@gmail.com 
53669318b39Slecopzer@gmail.com static const struct kernel_param_ops param_ops_battery_current = {
53769318b39Slecopzer@gmail.com 	.set = param_set_battery_current,
53869318b39Slecopzer@gmail.com 	.get = param_get_battery_current,
53969318b39Slecopzer@gmail.com };
54069318b39Slecopzer@gmail.com 
5418c0984e5SSebastian Reichel #define param_check_ac_online(name, p) __param_check(name, p, void);
5428c0984e5SSebastian Reichel #define param_check_usb_online(name, p) __param_check(name, p, void);
5438c0984e5SSebastian Reichel #define param_check_battery_status(name, p) __param_check(name, p, void);
5448c0984e5SSebastian Reichel #define param_check_battery_present(name, p) __param_check(name, p, void);
5458c0984e5SSebastian Reichel #define param_check_battery_technology(name, p) __param_check(name, p, void);
5468c0984e5SSebastian Reichel #define param_check_battery_health(name, p) __param_check(name, p, void);
5478c0984e5SSebastian Reichel #define param_check_battery_capacity(name, p) __param_check(name, p, void);
5488c0984e5SSebastian Reichel #define param_check_battery_voltage(name, p) __param_check(name, p, void);
5494b082ac6Slecopzer@gmail.com #define param_check_battery_charge_counter(name, p) __param_check(name, p, void);
55069318b39Slecopzer@gmail.com #define param_check_battery_current(name, p) __param_check(name, p, void);
5518c0984e5SSebastian Reichel 
5528c0984e5SSebastian Reichel 
5538c0984e5SSebastian Reichel module_param(ac_online, ac_online, 0644);
5548c0984e5SSebastian Reichel MODULE_PARM_DESC(ac_online, "AC charging state <on|off>");
5558c0984e5SSebastian Reichel 
5568c0984e5SSebastian Reichel module_param(usb_online, usb_online, 0644);
5578c0984e5SSebastian Reichel MODULE_PARM_DESC(usb_online, "USB charging state <on|off>");
5588c0984e5SSebastian Reichel 
5598c0984e5SSebastian Reichel module_param(battery_status, battery_status, 0644);
5608c0984e5SSebastian Reichel MODULE_PARM_DESC(battery_status,
5618c0984e5SSebastian Reichel 	"battery status <charging|discharging|not-charging|full>");
5628c0984e5SSebastian Reichel 
5638c0984e5SSebastian Reichel module_param(battery_present, battery_present, 0644);
5648c0984e5SSebastian Reichel MODULE_PARM_DESC(battery_present,
5658c0984e5SSebastian Reichel 	"battery presence state <good|overheat|dead|overvoltage|failure>");
5668c0984e5SSebastian Reichel 
5678c0984e5SSebastian Reichel module_param(battery_technology, battery_technology, 0644);
5688c0984e5SSebastian Reichel MODULE_PARM_DESC(battery_technology,
5698c0984e5SSebastian Reichel 	"battery technology <NiMH|LION|LIPO|LiFe|NiCd|LiMn>");
5708c0984e5SSebastian Reichel 
5718c0984e5SSebastian Reichel module_param(battery_health, battery_health, 0644);
5728c0984e5SSebastian Reichel MODULE_PARM_DESC(battery_health,
5738c0984e5SSebastian Reichel 	"battery health state <good|overheat|dead|overvoltage|failure>");
5748c0984e5SSebastian Reichel 
5758c0984e5SSebastian Reichel module_param(battery_capacity, battery_capacity, 0644);
5768c0984e5SSebastian Reichel MODULE_PARM_DESC(battery_capacity, "battery capacity (percentage)");
5778c0984e5SSebastian Reichel 
5788c0984e5SSebastian Reichel module_param(battery_voltage, battery_voltage, 0644);
5798c0984e5SSebastian Reichel MODULE_PARM_DESC(battery_voltage, "battery voltage (millivolts)");
5808c0984e5SSebastian Reichel 
5814b082ac6Slecopzer@gmail.com module_param(battery_charge_counter, battery_charge_counter, 0644);
5824b082ac6Slecopzer@gmail.com MODULE_PARM_DESC(battery_charge_counter,
5834b082ac6Slecopzer@gmail.com 	"battery charge counter (microampere-hours)");
5844b082ac6Slecopzer@gmail.com 
58569318b39Slecopzer@gmail.com module_param(battery_current, battery_current, 0644);
58669318b39Slecopzer@gmail.com MODULE_PARM_DESC(battery_current, "battery current (milliampere)");
58769318b39Slecopzer@gmail.com 
5888c0984e5SSebastian Reichel MODULE_DESCRIPTION("Power supply driver for testing");
5898c0984e5SSebastian Reichel MODULE_AUTHOR("Anton Vorontsov <cbouatmailru@gmail.com>");
5908c0984e5SSebastian Reichel MODULE_LICENSE("GPL");
591