3 * Samsung Mobile Battery Driver
5 * Copyright (C) 2012 Samsung Electronics
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License version 2 as
10 * published by the Free Software Foundation.
13 #include <linux/slab.h>
14 #include <linux/errno.h>
17 #include <linux/power_supply.h>
19 enum battery_data_type
{
20 BATTERY_DATA_TYPE_NONE
= 0,
21 BATTERY_DATA_TYPE_INFO
,
22 BATTERY_DATA_TYPE_VALUE
,
23 BATTERY_DATA_TYPE_STRING
,
26 enum battery_data_flag
{
27 BATTERY_DATA_FLAG_NONE
= 0,
28 BATTERY_DATA_FLAG_ADD
,
29 BATTERY_DATA_FLAG_REMOVE
,
30 BATTERY_DATA_FLAG_EDIT
,
33 #define CHECK_ERROR_DATA(logical_test, return_value, error_value, action) { \
35 return_value = error_value; \
36 pr_err("%s: error!!! (ret = %d)\n", __func__, error_value); \
43 #define NODE_NAME_SIZE 32
44 #define PROPERTY_SIZE 68
45 #define MAX_VALUE_SIZE (5 * 1024)
47 struct battery_data_info
{
57 char node_name
[NODE_NAME_SIZE
];
58 char property
[PROPERTY_SIZE
];
62 struct battery_property
{
63 struct property
*property
;
70 struct battery_property
*next
;
74 char name
[NODE_NAME_SIZE
];
75 struct device_node
*np
;
76 struct battery_node
*next
;
77 struct battery_property
*start_prop
;
80 static struct battery_node
*get_battery_node(
81 struct battery_node
**start_node
, char *name
)
83 struct battery_node
*batt_node
= NULL
;
84 struct battery_node
*temp_node
= NULL
;
87 pr_err("%s: name is invalid!!\n", __func__
);
91 batt_node
= *start_node
;
93 if (!strcmp(batt_node
->name
, name
)) {
96 temp_node
= batt_node
;
97 batt_node
= batt_node
->next
;
101 batt_node
= kzalloc(sizeof(struct battery_node
), GFP_KERNEL
);
103 pr_err("%s: nomem!!\n", __func__
);
106 batt_node
->np
= of_find_node_by_name(NULL
, name
);
107 if (IS_ERR_OR_NULL(batt_node
->np
)) {
108 pr_err("%s: failed to find node(name=%s)\n", __func__
, name
);
112 strcpy(batt_node
->name
, name
);
114 temp_node
->next
= batt_node
;
115 batt_node
->start_prop
= NULL
;
116 if (*start_node
== NULL
) *start_node
= batt_node
;
117 pr_info("%s: add battery_node(name = %s)\n", __func__
, name
);
121 static int add_battery_property( struct battery_node
*batt_node
,
122 struct battery_property
*batt_prop
)
124 struct battery_property
*start_prop
= NULL
;
125 struct battery_property
*temp_prop
= NULL
;
127 if (!batt_node
|| !batt_prop
) {
131 start_prop
= batt_node
->start_prop
;
133 if (!strcmp(start_prop
->property
->name
, batt_prop
->property
->name
)) {
136 temp_prop
= start_prop
;
137 start_prop
= start_prop
->next
;
142 batt_node
->start_prop
= batt_prop
;
144 temp_prop
->next
= batt_prop
;
149 static void change_battery_pdata(
150 struct battery_node
*start_node
, bool is_valid
)
152 struct battery_node
*temp_node
= NULL
;
154 temp_node
= start_node
;
155 pr_info("%s: start update(%d)\n", __func__
, is_valid
);
156 while (is_valid
&& temp_node
) {
157 struct battery_property
*batt_prop
= NULL
;
158 struct power_supply
*psy
= NULL
;
159 union power_supply_propval value
;
161 batt_prop
= temp_node
->start_prop
;
163 if (batt_prop
->flag
!= BATTERY_DATA_FLAG_REMOVE
) {
164 batt_prop
->property
->value
= batt_prop
->new_value
;
165 batt_prop
->property
->length
= batt_prop
->new_length
;
167 batt_prop
= batt_prop
->next
;
170 psy
= power_supply_get_by_name(start_node
->name
);
173 psy
->set_property(psy
, POWER_SUPPLY_PROP_POWER_DESIGN
, &value
);
176 temp_node
= temp_node
->next
;
179 pr_info("%s: release battery pdata\n", __func__
);
181 struct battery_property
*temp_batt_prop
= NULL
;
182 struct battery_property
*batt_prop
= NULL
;
184 batt_prop
= start_node
->start_prop
;
186 switch (batt_prop
->flag
) {
187 case BATTERY_DATA_FLAG_REMOVE
:
188 pr_debug("%s: re-set property(ret=%d, flag=%d, name=%s)\n",
189 __func__
, of_add_property(start_node
->np
, batt_prop
->property
),
190 batt_prop
->flag
, batt_prop
->property
->name
);
192 case BATTERY_DATA_FLAG_EDIT
:
193 pr_debug("%s: re-set property(type=%d, flag=%d, name=%s)\n",
194 __func__
, batt_prop
->type
,
195 batt_prop
->flag
, batt_prop
->property
->name
);
197 kfree(batt_prop
->new_value
);
199 /* In normal case, String type should not free. */
200 if (batt_prop
->type
!= BATTERY_DATA_TYPE_STRING
) {
201 batt_prop
->property
->value
= batt_prop
->old_value
;
202 batt_prop
->property
->length
= batt_prop
->old_length
;
203 kfree(batt_prop
->new_value
);
207 case BATTERY_DATA_FLAG_ADD
:
208 pr_debug("%s: re-set property(ret=%d, flag=%d, name=%s)\n",
209 __func__
, of_remove_property(start_node
->np
, batt_prop
->property
),
210 batt_prop
->flag
, batt_prop
->property
->name
);
211 if (batt_prop
->new_value
&& (!is_valid
|| batt_prop
->type
!= BATTERY_DATA_TYPE_STRING
)) {
212 kfree(batt_prop
->new_value
);
214 kfree(batt_prop
->property
->name
);
215 kfree(batt_prop
->property
);
219 temp_batt_prop
= batt_prop
;
220 batt_prop
= batt_prop
->next
;
221 kfree(temp_batt_prop
);
224 temp_node
= start_node
;
225 start_node
= start_node
->next
;
230 static int sec_battery_check_info(struct file
*fp
,
231 struct battery_data_info
*batt_info
)
233 struct device_node
*np
;
234 struct battery_data batt_data
;
235 int dt_version
, hw_rev
, hw_rev_end
;
236 int ret
= 0, read_size
;
238 read_size
= fp
->f_op
->read(fp
, (char*)&batt_data
, sizeof(struct battery_data
), &fp
->f_pos
);
239 CHECK_ERROR_DATA((read_size
<= 0), ret
, (-ENODATA
), goto finish_check_info
);
240 CHECK_ERROR_DATA((batt_data
.type
!= BATTERY_DATA_TYPE_INFO
), ret
, (-EINVAL
), goto finish_check_info
);
242 read_size
= fp
->f_op
->read(fp
, (char*)batt_info
, sizeof(struct battery_data_info
), &fp
->f_pos
);
243 CHECK_ERROR_DATA((read_size
<= 0 || read_size
!= batt_data
.length
), ret
, (-ENODATA
), goto finish_check_info
);
245 (batt_info
->version
< 0 || batt_info
->hw_rev
< 0 || batt_info
->prop_count
<= 0) ||
246 (batt_info
->value_length
< 0 || batt_info
->value_length
> MAX_VALUE_SIZE
),
247 ret
, (-EINVAL
), goto finish_check_info
);
249 np
= of_find_node_by_name(NULL
, batt_data
.node_name
);
250 ret
= of_property_read_u32(np
, "battery,batt_data_version", &dt_version
);
252 pr_info("%s : batt_data_version is Empty\n", __func__
);
256 np
= of_find_all_nodes(NULL
);
257 ret
= of_property_read_u32(np
, "model_info-hw_rev", &hw_rev
);
259 pr_info("%s: model_info-hw_rev is Empty\n", __func__
);
262 ret
= of_property_read_u32(np
, "model_info-hw_rev_end", &hw_rev_end
);
264 pr_info("%s: model_info-hw_rev_end is Empty\n", __func__
);
268 ret
= (batt_info
->version
< dt_version
) ? -1 :
269 ((batt_info
->hw_rev
> hw_rev_end
|| batt_info
->hw_rev
< hw_rev
) ? -2 : 0);
271 pr_info("%s: check info(ret=%d), version(%d <-> %d), hw_rev(%d ~ %d <-> %d), prop_count(%d), value_length(%d)\n",
273 dt_version
, batt_info
->version
,
274 hw_rev
, hw_rev_end
, batt_info
->hw_rev
,
275 batt_info
->prop_count
, batt_info
->value_length
);
281 static int sec_battery_check_none(struct file
*fp
)
283 struct battery_data batt_data
;
284 int ret
= 0, read_size
;
286 read_size
= fp
->f_op
->read(fp
, (char*)&batt_data
, sizeof(struct battery_data
), &fp
->f_pos
);
287 CHECK_ERROR_DATA((read_size
<= 0), ret
, (-ENODATA
), goto finish_check_none
);
289 if (batt_data
.type
!= BATTERY_DATA_TYPE_NONE
) {
290 pr_info("%s: invalid type(%d)\n", __func__
, batt_data
.type
);
298 static char *sec_battery_check_value(struct file
*fp
,
299 struct battery_data_info
*batt_info
, struct battery_data
*batt_data
)
301 char *temp_buf
= NULL
;
304 if (batt_data
->length
< 0 || batt_data
->length
> batt_info
->value_length
) {
305 pr_info("%s: length(%d) of data is invalid\n", __func__
, batt_data
->length
);
307 } else if (batt_data
->length
== 0) {
308 pr_info("%s: skip alloc buffer(length=%d)\n", __func__
, batt_data
->length
);
312 temp_buf
= kzalloc(batt_data
->length
, GFP_KERNEL
);
314 read_size
= fp
->f_op
->read(fp
, temp_buf
, batt_data
->length
, &fp
->f_pos
);
315 if (read_size
<= 0) {
316 pr_info("%s: failed to read value\n", __func__
);
325 int sec_battery_update_data(const char* file_path
)
327 struct battery_node
*batt_node
= NULL
;
328 struct battery_node
*temp_node
= NULL
;
329 struct property
*batt_property
= NULL
;
330 struct battery_data_info batt_info
;
331 struct battery_property
*batt_prop
;
332 struct battery_data batt_data
;
333 struct file
* fp
= NULL
;
334 char *temp_buf
= NULL
;
335 int length
, read_size
;
338 fp
= filp_open(file_path
, O_RDONLY
, 0);
339 CHECK_ERROR_DATA(IS_ERR(fp
), ret
, (int)(PTR_ERR(fp
)), goto err_filp_open
);
341 ret
= sec_battery_check_info(fp
, &batt_info
);
342 CHECK_ERROR_DATA((ret
), ret
, (-EINVAL
), goto skip_check_data
);
344 while (batt_info
.prop_count
-- > 0) {
345 read_size
= fp
->f_op
->read(fp
, (char*)&batt_data
, sizeof(struct battery_data
), &fp
->f_pos
);
346 CHECK_ERROR_DATA((read_size
<= 0), ret
, (-ENODATA
), goto finish_update_data
);
347 pr_debug("%s: read batt_data(type=%d, flag=%d, node_name=%s, property=%s, length=%d)\n",
348 __func__
, batt_data
.type
, batt_data
.flag
, batt_data
.node_name
, batt_data
.property
, batt_data
.length
);
350 temp_node
= get_battery_node(&batt_node
, batt_data
.node_name
);
351 CHECK_ERROR_DATA((!temp_node
), ret
, (-ENODEV
), goto finish_update_data
);
353 batt_prop
= kzalloc(sizeof(struct battery_property
), GFP_KERNEL
);
354 CHECK_ERROR_DATA((!batt_prop
), ret
, (-ENOMEM
), goto finish_update_data
);
356 batt_property
= of_find_property(temp_node
->np
, batt_data
.property
, &length
);
357 switch (batt_data
.flag
) {
358 case BATTERY_DATA_FLAG_ADD
:
359 if (IS_ERR_OR_NULL(batt_property
)) {
360 temp_buf
= sec_battery_check_value(fp
, &batt_info
, &batt_data
);
361 CHECK_ERROR_DATA((!temp_buf
&& batt_data
.length
!= 0), ret
, (-ENOMEM
),
362 {kfree(batt_prop
); goto finish_update_data
;});
364 batt_property
= kzalloc(sizeof(struct property
), GFP_KERNEL
);
365 CHECK_ERROR_DATA((!batt_property
), ret
, (-ENOMEM
),
366 {kfree(batt_prop
); kfree(temp_buf
); goto finish_update_data
;});
368 batt_property
->name
= kzalloc(PROPERTY_SIZE
, GFP_KERNEL
);
369 CHECK_ERROR_DATA((!batt_property
->name
), ret
, (-ENOMEM
),
370 {kfree(batt_prop
); kfree(temp_buf
); kfree(batt_property
); goto finish_update_data
;});
372 memcpy(batt_property
->name
, batt_data
.property
, PROPERTY_SIZE
);
373 ret
= of_add_property(temp_node
->np
, batt_property
);
374 CHECK_ERROR_DATA((ret
), ret
, ret
,
375 {kfree(batt_prop
); kfree(temp_buf
); kfree(batt_property
->name
); kfree(batt_property
); goto finish_update_data
;});
377 pr_info("%s: invalid data(name=%s, property=%s, flag=%d)\n",
378 __func__
, batt_data
.node_name
, batt_data
.property
, batt_data
.flag
);
381 goto finish_update_data
;
384 case BATTERY_DATA_FLAG_EDIT
:
385 if (!IS_ERR_OR_NULL(batt_property
)) {
386 temp_buf
= sec_battery_check_value(fp
, &batt_info
, &batt_data
);
387 CHECK_ERROR_DATA((!temp_buf
), ret
, (-ENOMEM
),
388 {kfree(batt_prop
); goto finish_update_data
;});
390 pr_info("%s: invalid data(name=%s, property=%s, flag=%d)\n",
391 __func__
, batt_data
.node_name
, batt_data
.property
, batt_data
.flag
);
394 goto finish_update_data
;
397 case BATTERY_DATA_FLAG_REMOVE
:
398 if (!IS_ERR_OR_NULL(batt_property
)) {
401 ret
= of_remove_property(temp_node
->np
, batt_property
);
402 CHECK_ERROR_DATA((ret
), ret
, ret
, {kfree(batt_prop
); goto finish_update_data
;});
404 pr_info("%s: invalid data(name=%s, property=%s, flag=%d)\n",
405 __func__
, batt_data
.node_name
, batt_data
.property
, batt_data
.flag
);
408 goto finish_update_data
;
412 pr_info("%s: invalid flag(%d)\n", __func__
, batt_data
.flag
);
415 goto finish_update_data
;
418 batt_prop
->property
= batt_property
;
419 batt_prop
->type
= batt_data
.type
;
420 batt_prop
->flag
= batt_data
.flag
;
421 batt_prop
->new_value
= temp_buf
;
422 batt_prop
->old_value
= batt_property
->value
;
423 batt_prop
->new_length
= batt_data
.length
;
424 batt_prop
->old_length
= batt_property
->length
;
425 add_battery_property(temp_node
, batt_prop
);
427 ret
= sec_battery_check_none(fp
);
430 change_battery_pdata(batt_node
, (ret
== 0));
432 filp_close(fp
, NULL
);