4 * Copyright (c) 2016 Samsung Electronics Co., Ltd.
6 * Licensed under the Apache License, Version 2.0 (the License);
7 * you may not use this file except in compliance with the License.
8 * You may obtain a copy of the License at
10 * http://www.apache.org/licenses/LICENSE-2.0
12 * Unless required by applicable law or agreed to in writing, software
13 * distributed under the License is distributed on an "AS IS" BASIS,
14 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 * See the License for the specific language governing permissions and
16 * limitations under the License.
24 #include <linux/limits.h>
27 #include <hw/battery.h>
28 #include "../shared.h"
31 #define BATTERY_ROOT_PATH "/sys/class/power_supply"
33 static struct uevent_data {
34 BatteryUpdated updated_cb;
38 static int get_power_source(char **src)
45 ret = sys_get_int(BATTERY_ROOT_PATH"/rk-ac/online", &val);
46 if (ret >= 0 && val > 0) {
47 *src = POWER_SOURCE_AC;
51 *src = POWER_SOURCE_NONE;
56 static void remove_not_string(char *str)
70 static void uevent_delivered(struct udev_device *dev)
72 struct battery_info info;
76 _I("POWER_SUPPLY uevent is delivered");
78 if (!udata.updated_cb) {
79 _E("POWER_SUPPLY callback is NULL");
83 val = (char *)udev_device_get_property_value(dev, "POWER_SUPPLY_NAME");
88 val = (char *)udev_device_get_property_value(dev, "POWER_SUPPLY_STATUS");
93 val = (char *)udev_device_get_property_value(dev, "POWER_SUPPLY_HEALTH");
98 val = (char *)udev_device_get_property_value(dev, "POWER_SUPPLY_PRESENT");
101 info.present = atoi(val);
103 val = (char *)udev_device_get_property_value(dev, "POWER_SUPPLY_ONLINE");
105 info.online = atoi(val);
107 info.online = info.present;
109 val = (char *)udev_device_get_property_value(dev, "POWER_SUPPLY_CAPACITY");
112 info.capacity = atoi(val);
114 ret = get_power_source(&val);
117 info.power_source = val;
119 val = (char *)udev_device_get_property_value(dev, "POWER_SUPPLY_CURRENT_NOW");
121 info.current_now = atoi(val); /* uA */
123 if (strncmp(info.power_source, POWER_SOURCE_NONE, sizeof(POWER_SOURCE_NONE)))
124 info.current_now = 1000; /* current entering the battery from charge source */
126 info.current_now = -1000; /* current discharging from the battery */
129 val = (char *)udev_device_get_property_value(dev, "POWER_SUPPLY_CURRENT_AVG");
131 info.current_average = atoi(val); /* uA */
133 info.current_average = info.current_now;
135 udata.updated_cb(&info, udata.data);
138 static struct uevent_handler uh = {
139 .subsystem = "power_supply",
140 .uevent_func = uevent_delivered,
143 static int battery_register_changed_event(
144 BatteryUpdated updated_cb, void *data)
148 ret = uevent_control_kernel_start();
150 _E("Failed to register uevent handler (%d)", ret);
154 ret = register_kernel_event_control(&uh);
156 _E("Failed to register kernel event control (%d)", ret);
158 if (udata.updated_cb == NULL) {
159 udata.updated_cb = updated_cb;
162 _E("update callback is already registered");
167 static void battery_unregister_changed_event(
168 BatteryUpdated updated_cb)
170 unregister_kernel_event_control(&uh);
171 uevent_control_kernel_stop();
172 udata.updated_cb = NULL;
176 static int battery_get_current_state(
177 BatteryUpdated updated_cb, void *data)
180 struct battery_info info;
189 info.name = BATTERY_HARDWARE_DEVICE_ID;
191 path = BATTERY_ROOT_PATH"/rk-bat/status";
192 ret = sys_get_str(path, status, sizeof(status));
194 _E("Failed to get value of (%s, %d)", path, ret);
197 remove_not_string(status);
198 info.status = status;
200 path = BATTERY_ROOT_PATH"/rk-bat/health";
201 ret = sys_get_str(path, health, sizeof(health));
203 _E("Failed to get value of (%s, %d)", path, ret);
206 remove_not_string(health);
207 info.health = health;
209 ret = get_power_source(&power_source);
211 _E("Failed to get power source (%d)", ret);
214 remove_not_string(power_source);
215 info.power_source = power_source;
217 path = BATTERY_ROOT_PATH"/rk-bat/present";
218 ret = sys_get_int(path, &val);
220 _E("Failed to get value of (%s, %d)", path, ret);
225 path = BATTERY_ROOT_PATH"/rk-bat/online";
226 ret = sys_get_int(path, &val);
230 info.online = info.present;
232 path = BATTERY_ROOT_PATH"/rk-bat/capacity";
233 ret = sys_get_int(path, &val);
235 _E("Failed to get value of (%s, %d)", path, ret);
240 path = BATTERY_ROOT_PATH"/rk-bat/current_now";
241 ret = sys_get_int(path, &val);
243 info.current_now = val;
245 if (strncmp(power_source, POWER_SOURCE_NONE, sizeof(POWER_SOURCE_NONE)))
246 info.current_now = 1000; /* current entering the battery from charge source */
248 info.current_now = -1000; /* current discharging from the battery */
251 path = BATTERY_ROOT_PATH"/rk-bat/current_avg";
252 ret = sys_get_int(path, &val);
254 info.current_average = val;
256 info.current_average = info.current_now;
258 updated_cb(&info, data);
263 static int battery_open(struct hw_info *info,
264 const char *id, struct hw_common **common)
266 struct battery_device *battery_dev;
268 if (!info || !common)
271 battery_dev = calloc(1, sizeof(struct battery_device));
275 battery_dev->common.info = info;
276 battery_dev->register_changed_event
277 = battery_register_changed_event;
278 battery_dev->unregister_changed_event
279 = battery_unregister_changed_event;
280 battery_dev->get_current_state
281 = battery_get_current_state;
283 *common = (struct hw_common *)battery_dev;
287 static int battery_close(struct hw_common *common)
296 HARDWARE_MODULE_STRUCTURE = {
297 .magic = HARDWARE_INFO_TAG,
298 .hal_version = HARDWARE_INFO_VERSION,
299 .device_version = BATTERY_HARDWARE_DEVICE_VERSION,
300 .id = BATTERY_HARDWARE_DEVICE_ID,
302 .open = battery_open,
303 .close = battery_close,