tizen 2.3 release
[framework/system/deviced.git] / src / led / rgb.c
1 /*
2  * deviced
3  *
4  * Copyright (c) 2012 - 2013 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 <errno.h>
22 #include <assert.h>
23 #include <device-node.h>
24 #include <Ecore.h>
25 #include <vconf.h>
26
27 #include "deviced/dd-led.h"
28 #include "core/log.h"
29 #include "core/common.h"
30 #include "core/edbus-handler.h"
31 #include "core/devices.h"
32 #include "core/device-notifier.h"
33 #include "core/device-handler.h"
34 #include "display/core.h"
35 #include "conf.h"
36
37 #define BOOT_ANIMATION_FINISHED         1
38
39 #define LED_VALUE(high, low)            (((high)<<16)|((low)&0xFFFF))
40
41 #define BG_COLOR                0x00000000
42 #define GET_ALPHA(x)    (((x)>>24) & 0xFF)
43 #define GET_RED(x)              (((x)>>16) & 0xFF)
44 #define GET_GREEN(x)    (((x)>> 8) & 0xFF)
45 #define GET_BLUE(x)             ((x) & 0xFF)
46 #define COMBINE_RGB(r,g,b)      ((((r) & 0xFF) << 16) | (((g) & 0xFF) << 8) | ((b) & 0xFF))
47
48 #define SET_WAVE_BIT    (0x6 << 24)
49 #define DUMPMODE_WAITING_TIME    600000
50
51 enum {
52         LED_CUSTOM_DUTY_ON = 1 << 0,    /* this enum doesn't blink on led */
53         LED_CUSTOM_DEFAULT = (LED_CUSTOM_DUTY_ON),
54 };
55
56 static int charging_key;
57 static int lowbat_key;
58 static bool charging_state;
59 static bool lowbat_state;
60 static bool full_state;
61 static bool badbat_state;
62 static bool ovp_state;
63 static int rgb_blocked = false;
64 static bool rgb_dumpmode = false;
65 static Ecore_Timer *dumpmode_timer = NULL;
66 static enum state_t lcd_state = S_NORMAL;
67 static Ecore_Timer *reset_timer;
68
69 static int rgb_start(enum device_flags flags)
70 {
71         _I("rgbled device will be started");
72         rgb_blocked = false;
73         return 0;
74 }
75
76 static int rgb_stop(enum device_flags flags)
77 {
78         _I("rgbled device will be stopped");
79         rgb_blocked = true;
80         return 0;
81 }
82
83 static int led_prop(int mode, int on, int off, unsigned int color)
84 {
85         struct led_mode *led;
86
87         if (mode < 0 || mode > LED_MODE_MAX)
88                 return -EINVAL;
89
90         led = find_led_data(mode);
91         if (!led) {
92                 _E("no find data(%d)", mode);
93                 return -EINVAL;
94         }
95
96         switch (mode) {
97         case LED_MISSED_NOTI:
98         case LED_VOICE_RECORDING:
99         case LED_CUSTOM:
100                 if (on >= 0)
101                         led->data.on = on;
102                 if (off >= 0)
103                         led->data.off = off;
104                 if (color)
105                         led->data.color = color;
106                 break;
107         default:
108                 /* the others couldn't change any property */
109                 break;
110         }
111
112         _D("changed mode(%d) : state(%d), on(%d), off(%d), color(%x)",
113                         mode, led->state, led->data.on, led->data.off, led->data.color);
114         return 0;
115 }
116
117 static int led_mode(int mode, bool enable)
118 {
119         struct led_mode *led;
120
121         if (mode < 0 || mode > LED_MODE_MAX)
122                 return -EINVAL;
123
124         led = find_led_data(mode);
125         if (!led) {
126                 _E("no find data(%d)", mode);
127                 return -EINVAL;
128         }
129
130         led->state = enable;
131         return 0;
132 }
133
134 static int get_led_mode_state(int mode, bool *state)
135 {
136         struct led_mode *led;
137
138         if (mode < 0 || mode > LED_MODE_MAX)
139                 return -EINVAL;
140
141         led = find_led_data(mode);
142         if (!led) {
143                 _E("no find data(%d)", mode);
144                 return -EINVAL;
145         }
146
147         if (led->state)
148                 *state = true;
149         else
150                 *state = false;
151         return 0;
152 }
153
154 static unsigned int led_blend(unsigned int before)
155 {
156         unsigned int alpha, alpha_inv;
157         unsigned char red, grn, blu;
158
159         alpha = GET_ALPHA(before) + 1;
160         alpha_inv = 256 - alpha;
161
162         red = ((alpha * GET_RED(before) + alpha_inv * GET_RED(BG_COLOR)) >> 8);
163         grn = ((alpha * GET_GREEN(before) + alpha_inv * GET_GREEN(BG_COLOR)) >> 8);
164         blu = ((alpha * GET_BLUE(before) + alpha_inv * GET_BLUE(BG_COLOR)) >> 8);
165         return COMBINE_RGB(red, grn, blu);
166 }
167
168 static Eina_Bool timer_reset_cb(void *data);
169 static int led_mode_to_device(struct led_mode *led)
170 {
171         int val, color;
172         double time;
173
174         if (led == NULL)
175                 return 0;
176
177         if (rgb_dumpmode)
178                 return 0;
179
180         if (rgb_blocked && led->mode != LED_POWER_OFF && led->mode != LED_OFF)
181                 return 0;
182
183         if (led->data.duration > 0) {
184                 time = ((led->data.on + led->data.off) * led->data.duration) / 1000.f;
185                 if (reset_timer)
186                         ecore_timer_del(reset_timer);
187                 reset_timer = ecore_timer_add(time, timer_reset_cb, led);
188                 if (!reset_timer)
189                         _E("failed to add reset timer");
190                 _D("add reset timer (mode:%d, %lfs)", led->mode, time);
191         }
192
193         val = LED_VALUE(led->data.on, led->data.off);
194         color = led_blend(led->data.color);
195
196         /* if wave status is ON, color should be combined with WAVE_BIT */
197         if (led->data.wave)
198                 color |= SET_WAVE_BIT;
199
200         device_set_property(DEVICE_TYPE_LED, PROP_LED_COLOR, color);
201         device_set_property(DEVICE_TYPE_LED, PROP_LED_BLINK, val);
202         return 0;
203 }
204
205 static Eina_Bool timer_reset_cb(void *data)
206 {
207         struct led_mode *led = (struct led_mode*)data;
208
209         if (!led)
210                 return ECORE_CALLBACK_CANCEL;
211
212         led->state = false;
213         _D("reset timer (mode:%d)", led->mode);
214
215         /* turn off previous setting */
216         led = find_led_data(LED_OFF);
217         led_mode_to_device(led);
218
219         led = get_valid_led_data(lcd_state);
220         /* preventing duplicated requests */
221         if (led && led->mode != LED_OFF)
222                 led_mode_to_device(led);
223
224         return ECORE_CALLBACK_CANCEL;
225 }
226
227 static int led_display_changed_cb(void *data)
228 {
229         struct led_mode *led = NULL;
230         int state;
231
232         /* store last display condition */
233         lcd_state = (enum state_t)data;
234
235         /* charging error state */
236         if (badbat_state)
237                 return 0;
238
239         if (lcd_state == S_LCDOFF)
240                 state = DURING_LCD_OFF;
241         else if (lcd_state == S_NORMAL || lcd_state == S_LCDDIM)
242                 state = DURING_LCD_ON;
243         else
244                 return 0;
245
246         /* turn off previous setting */
247         led = find_led_data(LED_OFF);
248         led_mode_to_device(led);
249
250         led = get_valid_led_data(state);
251         /* preventing duplicated requests */
252         if (led && led->mode != LED_OFF)
253                 led_mode_to_device(led);
254
255         return 0;
256 }
257
258 static int led_charging_changed_cb(void *data)
259 {
260         int v = (int)data;
261
262         if (v == CHARGER_CHARGING)
263                 charging_state = true;
264         else
265                 charging_state = false;
266
267         if (charging_key)
268                 led_mode(LED_CHARGING, charging_state);
269
270         return 0;
271 }
272
273 static int led_lowbat_changed_cb(void *data)
274 {
275         lowbat_state = (bool)data;
276
277         if (lowbat_key)
278                 led_mode(LED_LOW_BATTERY, lowbat_state);
279
280         return 0;
281 }
282
283 static int led_fullbat_changed_cb(void *data)
284 {
285         full_state = (bool)data;
286
287         if (charging_key)
288                 led_mode(LED_FULLY_CHARGED, full_state);
289
290         return 0;
291 }
292
293 static int led_battery_health_changed_cb(void *data)
294 {
295         struct led_mode *led;
296         bool cur;
297
298         cur = ((int)data == HEALTH_BAD) ? true : false;
299
300         /* do not enter below scenario in case of same state */
301         if (cur == badbat_state)
302                 return 0;
303
304         badbat_state = cur;
305
306         /* set charging error mode */
307         led_mode(LED_CHARGING_ERROR, badbat_state);
308
309         /* update the led state */
310         if (badbat_state) {     /* charging error */
311                 led = find_led_data(LED_CHARGING_ERROR);
312                 led_mode_to_device(led);
313         } else {
314                 led = find_led_data(LED_OFF);
315                 led_mode_to_device(led);
316                 if (lcd_state == S_LCDOFF)
317                         led_display_changed_cb((void*)S_LCDOFF);
318         }
319
320         return 0;
321 }
322
323 static int led_battery_ovp_changed_cb(void *data)
324 {
325         int cur = (int)data;
326
327         /* do not enter below flow in case of same state */
328         if (cur == ovp_state)
329                 return 0;
330
331         ovp_state = cur;
332
333         if (ovp_state == OVP_NORMAL && lcd_state == S_LCDOFF)
334                 led_display_changed_cb((void*)S_LCDOFF);
335
336         return 0;
337 }
338
339 static void led_poweron_changed_cb(keynode_t *key, void *data)
340 {
341         int state;
342         struct led_mode *led;
343
344         state = vconf_keynode_get_int(key);
345
346         if (state != BOOT_ANIMATION_FINISHED)
347                 return;
348
349         led = find_led_data(LED_OFF);
350         led_mode_to_device(led);
351
352         vconf_ignore_key_changed(VCONFKEY_BOOT_ANIMATION_FINISHED,
353                         led_poweron_changed_cb);
354 }
355
356 static void led_poweroff_changed_cb(keynode_t *key, void *data)
357 {
358         int state;
359         struct led_mode *led;
360
361         state = vconf_keynode_get_int(key);
362
363         if (state == VCONFKEY_SYSMAN_POWER_OFF_NONE ||
364                 state == VCONFKEY_SYSMAN_POWER_OFF_POPUP)
365                 return;
366
367         led = find_led_data(LED_POWER_OFF);
368         led_mode_to_device(led);
369
370         vconf_ignore_key_changed(VCONFKEY_SYSMAN_POWER_OFF_STATUS,
371                         led_poweroff_changed_cb);
372 }
373
374 static void led_vconf_charging_cb(keynode_t *key, void *data)
375 {
376         charging_key = vconf_keynode_get_bool(key);
377
378         if (charging_key) {
379                 led_mode(LED_CHARGING, charging_state);
380                 led_mode(LED_FULLY_CHARGED, full_state);
381         } else {
382                 led_mode(LED_CHARGING, false);
383                 led_mode(LED_FULLY_CHARGED, false);
384         }
385 }
386
387 static void led_vconf_lowbat_cb(keynode_t *key, void *data)
388 {
389         lowbat_key = vconf_keynode_get_bool(key);
390
391         if (lowbat_key)
392                 led_mode(LED_LOW_BATTERY, lowbat_state);
393         else
394                 led_mode(LED_LOW_BATTERY, false);
395 }
396
397 static void led_vconf_blocking_cb(keynode_t *key, void *data)
398 {
399         rgb_blocked = vconf_keynode_get_bool(key);
400         _I("rgbled blocking mode %s", (rgb_blocked ? "started" : "stopped"));
401 }
402
403 static void led_vconf_psmode_cb(keynode_t *key, void *data)
404 {
405         int psmode;
406
407         psmode = vconf_keynode_get_int(key);
408         if (psmode == SETTING_PSMODE_EMERGENCY)
409                 rgb_stop(NORMAL_MODE);
410         else
411                 rgb_start(NORMAL_MODE);
412 }
413
414 static DBusMessage *edbus_playcustom(E_DBus_Object *obj, DBusMessage *msg)
415 {
416         DBusMessageIter iter;
417         DBusMessage *reply;
418         int cmd, val, ret;
419         int on, off;
420         unsigned int color, flags;
421
422         ret = dbus_message_get_args(msg, NULL,
423                         DBUS_TYPE_INT32, &on,
424                         DBUS_TYPE_INT32, &off,
425                         DBUS_TYPE_UINT32, &color,
426                         DBUS_TYPE_UINT32, &flags, DBUS_TYPE_INVALID);
427         if (!ret) {
428                 _I("there is no message");
429                 ret = -EINVAL;
430                 goto error;
431         }
432
433         /* not to play blink, on and off value should be zero */
434         if (!(flags & LED_CUSTOM_DUTY_ON))
435                 on = off = 0;
436
437         /* set new value in case of LED_CUSTOM value */
438         ret = led_mode(LED_CUSTOM, true);
439         ret = led_prop(LED_CUSTOM, on, off, color);
440
441         _D("play custom %d, %d, %x, %d", on, off, color, ret);
442
443 error:
444         reply = dbus_message_new_method_return(msg);
445         dbus_message_iter_init_append(reply, &iter);
446         dbus_message_iter_append_basic(&iter, DBUS_TYPE_INT32, &ret);
447         return reply;
448 }
449
450 static DBusMessage *edbus_stopcustom(E_DBus_Object *obj, DBusMessage *msg)
451 {
452         DBusMessageIter iter;
453         DBusMessage *reply;
454         int val, ret;
455         bool state;
456
457         ret = get_led_mode_state(LED_CUSTOM, &state);
458         if (ret < 0) {
459                 _E("failed to get led mode state : %d", ret);
460                 ret = -EPERM;
461                 goto error;
462         }
463
464         if (!state) {
465                 _E("not play custom led");
466                 ret = -EPERM;
467                 goto error;
468         }
469
470         /* reset default value */
471         ret = led_mode(LED_CUSTOM, false);
472         ret = led_prop(LED_CUSTOM, 500, 5000, 255);
473
474         _D("stop custom %d", ret);
475
476 error:
477         reply = dbus_message_new_method_return(msg);
478         dbus_message_iter_init_append(reply, &iter);
479         dbus_message_iter_append_basic(&iter, DBUS_TYPE_INT32, &ret);
480         return reply;
481 }
482
483 static DBusMessage *edbus_set_mode(E_DBus_Object *obj, DBusMessage *msg)
484 {
485         DBusMessageIter iter;
486         DBusMessage *reply;
487         unsigned int color;
488         int mode, val, on, off, ret;
489         struct led_mode *led;
490         bool mode_enabled = false;
491
492         ret = dbus_message_get_args(msg, NULL,
493                         DBUS_TYPE_INT32, &mode,
494                         DBUS_TYPE_INT32, &val,
495                         DBUS_TYPE_INT32, &on,
496                         DBUS_TYPE_INT32, &off,
497                         DBUS_TYPE_UINT32, &color, DBUS_TYPE_INVALID);
498         if (!ret) {
499                 _I("there is no message");
500                 ret = -EINVAL;
501                 goto error;
502         }
503
504         ret = get_led_mode_state(mode, &mode_enabled);
505         if (ret) {
506                 _I("failed to get led mode state : %d", ret);
507                 goto error;
508         }
509
510         ret = led_mode(mode, val);
511         ret = led_prop(mode, on, off, color);
512
513         /* If lcd prop has a during_lcd_on bit,
514            it should turn on/off during lcd on state */
515         led = find_led_data(mode);
516         if (led && (led->data.lcd & DURING_LCD_ON) &&
517             (lcd_state == S_NORMAL || lcd_state == S_LCDDIM)) {
518                 led = get_valid_led_data(DURING_LCD_ON);
519                 led_mode_to_device(led);
520         }
521
522         /* Exception case :
523            in case of display off condition,
524            who requests missed noti event, it should change the device value */
525         if (mode == LED_MISSED_NOTI && lcd_state == S_LCDOFF) {
526                 if (!mode_enabled || on == 0) {
527                         /* turn off previous setting */
528                         led = find_led_data(LED_OFF);
529                         led_mode_to_device(led);
530                         /* update the led state */
531                         led_display_changed_cb((void*)S_LCDOFF);
532                 }
533         }
534
535 error:
536         reply = dbus_message_new_method_return(msg);
537         dbus_message_iter_init_append(reply, &iter);
538         dbus_message_iter_append_basic(&iter, DBUS_TYPE_INT32, &ret);
539         return reply;
540 }
541
542 static void set_dumpmode(bool on)
543 {
544         struct led_mode *led;
545         int val, color;
546
547         if (on) {
548                 val = LED_VALUE(200, 100);
549                 color = led_blend(0xFFFF0000);
550                 device_set_property(DEVICE_TYPE_LED, PROP_LED_COLOR, color);
551                 device_set_property(DEVICE_TYPE_LED, PROP_LED_BLINK, val);
552                 rgb_dumpmode = true;
553                 _I("dump_mode on");
554         } else {
555                 if (dumpmode_timer) {
556                         ecore_timer_del(dumpmode_timer);
557                         dumpmode_timer = NULL;
558                 }
559                 if (rgb_dumpmode)
560                         rgb_dumpmode = false;
561                 else
562                         return;
563                 led = find_led_data(LED_OFF);
564                 led_mode_to_device(led);
565                 _I("dump_mode off");
566         }
567 }
568
569 static void dumpmode_timer_cb(void *data)
570 {
571         set_dumpmode(false);
572 }
573
574 static DBusMessage *edbus_dump_mode(E_DBus_Object *obj, DBusMessage *msg)
575 {
576         DBusMessageIter iter;
577         DBusMessage *reply;
578         int ret = 0;
579         char *on;
580
581         ret = dbus_message_get_args(msg, NULL, DBUS_TYPE_STRING, &on,
582                         DBUS_TYPE_INVALID);
583
584         if (!ret) {
585                 _E("fail to get dumpmode state %d", ret);
586                 ret = -EINVAL;
587                 goto error;
588         }
589
590         if (!strcmp(on, "on")) {
591                 set_dumpmode(true);
592                 dumpmode_timer = ecore_timer_add(DUMPMODE_WAITING_TIME,
593                                 (Ecore_Task_Cb)dumpmode_timer_cb, NULL);
594         } else if (!strcmp(on, "off")) {
595                 set_dumpmode(false);
596         } else
597                 ret = -EINVAL;
598
599 error:
600         reply = dbus_message_new_method_return(msg);
601         dbus_message_iter_init_append(reply, &iter);
602         dbus_message_iter_append_basic(&iter, DBUS_TYPE_INT32, &ret);
603
604         return reply;
605 }
606
607 static DBusMessage *edbus_print_mode(E_DBus_Object *obj, DBusMessage *msg)
608 {
609         print_all_data();
610         return dbus_message_new_method_return(msg);
611 }
612
613 static const struct edbus_method edbus_methods[] = {
614         { "playcustom",     "iiuu",  "i",  edbus_playcustom },
615         { "stopcustom",     NULL,    "i",  edbus_stopcustom },
616         { "SetMode",        "iiiiu", "i",  edbus_set_mode },
617         { "PrintMode",      NULL,    NULL, edbus_print_mode },
618         { "Dumpmode",       "s",     "i",  edbus_dump_mode },
619         /* Add methods here */
620 };
621
622 static void rgb_init(void *data)
623 {
624         int ta_connected, boot, psmode;
625         int ret;
626         struct led_mode *led;
627
628         /* init dbus interface */
629         ret = register_edbus_method(DEVICED_PATH_LED, edbus_methods, ARRAY_SIZE(edbus_methods));
630         if (ret < 0)
631                 _E("fail to init edbus method(%d)", ret);
632
633         /* get led mode data from xml */
634         get_led_data();
635
636         /* LED_OFF state must be always true */
637         led_mode(LED_OFF, true);
638
639         /* verify booting or restart */
640         ret = vconf_get_int(VCONFKEY_BOOT_ANIMATION_FINISHED, &boot);
641         if (ret != 0)
642                 boot = 0;       /* set booting state */
643
644         /* in case of restart */
645         if (boot)
646                 goto next;
647
648         /* when booting, led indicator will be work */
649         led = find_led_data(LED_POWER_OFF);
650         led_mode_to_device(led);
651         vconf_notify_key_changed(VCONFKEY_BOOT_ANIMATION_FINISHED,
652                         led_poweron_changed_cb, NULL);
653
654 next:
655         /* register power off callback */
656         vconf_notify_key_changed(VCONFKEY_SYSMAN_POWER_OFF_STATUS,
657                         led_poweroff_changed_cb, NULL);
658
659         /* register notifier for each event */
660         register_notifier(DEVICE_NOTIFIER_LCD, led_display_changed_cb);
661         register_notifier(DEVICE_NOTIFIER_BATTERY_CHARGING, led_charging_changed_cb);
662         register_notifier(DEVICE_NOTIFIER_LOWBAT, led_lowbat_changed_cb);
663         register_notifier(DEVICE_NOTIFIER_FULLBAT, led_fullbat_changed_cb);
664         register_notifier(DEVICE_NOTIFIER_BATTERY_HEALTH, led_battery_health_changed_cb);
665         register_notifier(DEVICE_NOTIFIER_BATTERY_OVP, led_battery_ovp_changed_cb);
666
667         /* initialize vconf value */
668         vconf_get_bool(VCONFKEY_SETAPPL_LED_INDICATOR_CHARGING, &charging_key);
669         vconf_get_bool(VCONFKEY_SETAPPL_LED_INDICATOR_LOW_BATT, &lowbat_key);
670
671         /* initialize led indicator blocking value */
672         vconf_get_bool(VCONFKEY_SETAPPL_BLOCKINGMODE_LED_INDICATOR, &rgb_blocked);
673
674         /* register vconf callback */
675         vconf_notify_key_changed(VCONFKEY_SETAPPL_LED_INDICATOR_CHARGING,
676                         led_vconf_charging_cb, NULL);
677         vconf_notify_key_changed(VCONFKEY_SETAPPL_LED_INDICATOR_LOW_BATT,
678                         led_vconf_lowbat_cb, NULL);
679
680         /* register led indicator blocking vconf callback */
681         vconf_notify_key_changed(VCONFKEY_SETAPPL_BLOCKINGMODE_LED_INDICATOR,
682                         led_vconf_blocking_cb, NULL);
683
684         /* check power saving state */
685         vconf_get_int(VCONFKEY_SETAPPL_PSMODE, &psmode);
686         if (psmode == SETTING_PSMODE_EMERGENCY)
687                 rgb_stop(NORMAL_MODE);
688
689         /* register power saving callback */
690         vconf_notify_key_changed(VCONFKEY_SETAPPL_PSMODE, led_vconf_psmode_cb, NULL);
691
692         ret = device_get_property(DEVICE_TYPE_POWER, PROP_POWER_CHARGE_NOW, &ta_connected);
693         if (!ret && ta_connected)
694                 led_charging_changed_cb((void*)ta_connected);
695 }
696
697 static void rgb_exit(void *data)
698 {
699         struct led_mode *led;
700
701         /* unregister vconf callback */
702         vconf_ignore_key_changed(VCONFKEY_SETAPPL_LED_INDICATOR_CHARGING,
703                         led_vconf_charging_cb);
704         vconf_ignore_key_changed(VCONFKEY_SETAPPL_LED_INDICATOR_LOW_BATT,
705                         led_vconf_lowbat_cb);
706
707         /* unregister led indicatore blocking vconf callback */
708         vconf_ignore_key_changed(VCONFKEY_SETAPPL_BLOCKINGMODE_LED_INDICATOR,
709                         led_vconf_blocking_cb);
710
711         /* unregister power saving callback */
712         vconf_ignore_key_changed(VCONFKEY_SETAPPL_PSMODE, led_vconf_psmode_cb);
713
714         /* unregister notifier for each event */
715         unregister_notifier(DEVICE_NOTIFIER_LCD, led_display_changed_cb);
716         unregister_notifier(DEVICE_NOTIFIER_BATTERY_CHARGING, led_charging_changed_cb);
717         unregister_notifier(DEVICE_NOTIFIER_LOWBAT, led_lowbat_changed_cb);
718         unregister_notifier(DEVICE_NOTIFIER_FULLBAT, led_fullbat_changed_cb);
719         unregister_notifier(DEVICE_NOTIFIER_BATTERY_HEALTH, led_battery_health_changed_cb);
720         unregister_notifier(DEVICE_NOTIFIER_BATTERY_OVP, led_battery_ovp_changed_cb);
721
722         set_dumpmode(false);
723         /* turn off led */
724         led = find_led_data(LED_OFF);
725         led_mode_to_device(led);
726
727         /* release led mode data */
728         release_led_data();
729 }
730
731 static const struct device_ops rgbled_device_ops = {
732         .priority = DEVICE_PRIORITY_NORMAL,
733         .name     = "rgbled",
734         .init     = rgb_init,
735         .exit     = rgb_exit,
736         .start    = rgb_start,
737         .stop     = rgb_stop,
738 };
739
740 DEVICE_OPS_REGISTER(&rgbled_device_ops)