battery: change sysfw nodes according to the artik driver
[platform/hal/backend/artik/device-artik.git] / hw / battery / battery.c
1 /*
2  * device-node
3  *
4  * Copyright (c) 2016 Samsung Electronics Co., Ltd.
5  *
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
9  *
10  *     http://www.apache.org/licenses/LICENSE-2.0
11  *
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.
17  */
18
19
20 #include <stdio.h>
21 #include <stdlib.h>
22 #include <string.h>
23 #include <errno.h>
24 #include <linux/limits.h>
25 #include <dirent.h>
26
27 #include <hw/battery.h>
28 #include "../shared.h"
29 #include "../udev.h"
30
31 #define BATTERY_ROOT_PATH "/sys/class/power_supply"
32
33 static struct uevent_data {
34         BatteryUpdated updated_cb;
35         void *data;
36 } udata = { 0, };
37
38 static int get_power_source(char **src)
39 {
40         int ret, val;
41
42         if (!src)
43                 return -EINVAL;
44
45         ret = sys_get_int(BATTERY_ROOT_PATH"/rk-ac/online", &val);
46         if (ret >= 0 && val > 0) {
47                 *src = POWER_SOURCE_AC;
48                 return 0;
49         }
50
51         *src = POWER_SOURCE_NONE;
52
53         return 0;
54 }
55
56 static void remove_not_string(char *str)
57 {
58         char *t = str;
59
60         while(*t != '\0') {
61                 if (*t == '\r' ||
62                         *t == '\n' ||
63                         *t == '\x0a')
64                         *t = '\0';
65                 else
66                         t++;
67         }
68 }
69
70 static void uevent_delivered(struct udev_device *dev)
71 {
72         struct battery_info info;
73         char *val;
74         int ret;
75
76         _I("POWER_SUPPLY uevent is delivered");
77
78         if (!udata.updated_cb) {
79                 _E("POWER_SUPPLY callback is NULL");
80                 return;
81         }
82
83         val = (char *)udev_device_get_property_value(dev, "POWER_SUPPLY_NAME");
84         if (!val)
85                 return;
86         info.name = val;
87
88         val = (char *)udev_device_get_property_value(dev, "POWER_SUPPLY_STATUS");
89         if (!val)
90                 return;
91         info.status = val;
92
93         val = (char *)udev_device_get_property_value(dev, "POWER_SUPPLY_HEALTH");
94         if (!val)
95                 return;
96         info.health = val;
97
98         val = (char *)udev_device_get_property_value(dev, "POWER_SUPPLY_PRESENT");
99         if (!val)
100                 return;
101         info.present = atoi(val);
102
103         val = (char *)udev_device_get_property_value(dev, "POWER_SUPPLY_ONLINE");
104         if (val)
105                 info.online = atoi(val);
106         else
107                 info.online = info.present;
108
109         val = (char *)udev_device_get_property_value(dev, "POWER_SUPPLY_CAPACITY");
110         if (!val)
111                 return;
112         info.capacity = atoi(val);
113
114         ret = get_power_source(&val);
115         if (ret < 0)
116                 return;
117         info.power_source = val;
118
119         val = (char *)udev_device_get_property_value(dev, "POWER_SUPPLY_CURRENT_NOW");
120         if (val)
121                 info.current_now = atoi(val); /* uA */
122         else {
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 */
125                 else
126                         info.current_now = -1000; /* current discharging from the battery */
127         }
128
129         val = (char *)udev_device_get_property_value(dev, "POWER_SUPPLY_CURRENT_AVG");
130         if (val)
131                 info.current_average = atoi(val); /* uA */
132         else
133                 info.current_average = info.current_now;
134
135         udata.updated_cb(&info, udata.data);
136 }
137
138 static struct uevent_handler uh = {
139         .subsystem = "power_supply",
140         .uevent_func = uevent_delivered,
141 };
142
143 static int battery_register_changed_event(
144                 BatteryUpdated updated_cb, void *data)
145 {
146         int ret;
147
148         ret = uevent_control_kernel_start();
149         if (ret < 0) {
150                 _E("Failed to register uevent handler (%d)", ret);
151                 return ret;
152         }
153
154         ret = register_kernel_event_control(&uh);
155         if (ret < 0)
156                 _E("Failed to register kernel event control (%d)", ret);
157
158         if (udata.updated_cb == NULL) {
159                 udata.updated_cb = updated_cb;
160                 udata.data = data;
161         } else
162                 _E("update callback is already registered");
163
164         return ret;
165 }
166
167 static void battery_unregister_changed_event(
168                 BatteryUpdated updated_cb)
169 {
170         unregister_kernel_event_control(&uh);
171         uevent_control_kernel_stop();
172         udata.updated_cb = NULL;
173         udata.data = NULL;
174 }
175
176 static int battery_get_current_state(
177                 BatteryUpdated updated_cb, void *data)
178 {
179         int ret, val;
180         struct battery_info info;
181         char *path;
182         char status[32];
183         char health[32];
184         char *power_source;
185
186         if (!updated_cb)
187                 return -EINVAL;
188
189         info.name = BATTERY_HARDWARE_DEVICE_ID;
190
191         path = BATTERY_ROOT_PATH"/rk-bat/status";
192         ret = sys_get_str(path, status, sizeof(status));
193         if (ret < 0) {
194                 _E("Failed to get value of (%s, %d)", path, ret);
195                 return ret;
196         }
197         remove_not_string(status);
198         info.status = status;
199
200         path = BATTERY_ROOT_PATH"/rk-bat/health";
201         ret = sys_get_str(path, health, sizeof(health));
202         if (ret < 0) {
203                 _E("Failed to get value of (%s, %d)", path, ret);
204                 return ret;
205         }
206         remove_not_string(health);
207         info.health = health;
208
209         ret = get_power_source(&power_source);
210         if (ret < 0) {
211                 _E("Failed to get power source (%d)", ret);
212                 return ret;
213         }
214         remove_not_string(power_source);
215         info.power_source = power_source;
216
217         path = BATTERY_ROOT_PATH"/rk-bat/present";
218         ret = sys_get_int(path, &val);
219         if (ret < 0) {
220                 _E("Failed to get value of (%s, %d)", path, ret);
221                 return ret;
222         }
223         info.present = val;
224
225         path = BATTERY_ROOT_PATH"/rk-bat/online";
226         ret = sys_get_int(path, &val);
227         if (ret == 0)
228                 info.online = val;
229         else
230                 info.online = info.present;
231
232         path = BATTERY_ROOT_PATH"/rk-bat/capacity";
233         ret = sys_get_int(path, &val);
234         if (ret < 0) {
235                 _E("Failed to get value of (%s, %d)", path, ret);
236                 return ret;
237         }
238         info.capacity = val;
239
240         path = BATTERY_ROOT_PATH"/rk-bat/current_now";
241         ret = sys_get_int(path, &val);
242         if (ret == 0)
243                 info.current_now = val;
244         else {
245                 if (strncmp(power_source, POWER_SOURCE_NONE, sizeof(POWER_SOURCE_NONE)))
246                         info.current_now = 1000; /* current entering the battery from charge source */
247                 else
248                         info.current_now = -1000; /* current discharging from the battery */
249         }
250
251         path = BATTERY_ROOT_PATH"/rk-bat/current_avg";
252         ret = sys_get_int(path, &val);
253         if (ret == 0)
254                 info.current_average = val;
255         else
256                 info.current_average = info.current_now;
257
258         updated_cb(&info, data);
259
260         return 0;
261 }
262
263 static int battery_open(struct hw_info *info,
264                 const char *id, struct hw_common **common)
265 {
266         struct battery_device *battery_dev;
267
268         if (!info || !common)
269                 return -EINVAL;
270
271         battery_dev = calloc(1, sizeof(struct battery_device));
272         if (!battery_dev)
273                 return -ENOMEM;
274
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;
282
283         *common = (struct hw_common *)battery_dev;
284         return 0;
285 }
286
287 static int battery_close(struct hw_common *common)
288 {
289         if (!common)
290                 return -EINVAL;
291
292         free(common);
293         return 0;
294 }
295
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,
301         .name = "battery",
302         .open = battery_open,
303         .close = battery_close,
304 };