4 * Copyright (c) 2012 - 2015 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.
23 #include <sys/types.h>
33 #include <hal/device/hal-display.h>
35 #include "ambient-mode.h"
37 #include "shared/devices.h"
38 #include "shared/common.h"
39 #include "shared/device-notifier.h"
41 #include "device-interface.h"
44 #include "display/display-dpms.h"
45 #include "display/display.h"
46 #include "power/power-suspend.h"
47 #include "display/display-lock.h"
52 #define LCD_PHASED_MIN_BRIGHTNESS 1
53 #define LCD_PHASED_MAX_BRIGHTNESS 100
54 #define LCD_PHASED_CHANGE_STEP 5
55 #define LCD_PHASED_DELAY 10000 /* microsecond */
56 #define DUMP_MODE_WAITING_TIME 600000 /* milisecond */
58 #define DISPLAY_HAL_LIB_PATH "/usr/lib/libdisplay-hal.so"
60 #define GESTURE_STR "gesture"
61 #define POWERKEY_STR "powerkey"
62 #define EVENT_STR "event"
63 #define TOUCH_STR "touch"
64 #define TIMEOUT_STR "timeout"
65 #define PROXIMITY_STR "proximity"
66 #define PALM_STR "palm"
67 #define UNKNOWN_STR "unknown"
69 #define FREEZER_VITAL_WAKEUP_CGROUP "/sys/fs/cgroup/freezer/vital_wakeup/freezer.state"
71 static struct _backlight_ops backlight_ops;
72 static bool custom_status;
73 static int custom_brightness;
74 static int force_brightness;
75 static int default_brightness;
76 static int dpms_running_state = DPMS_SETTING_DONE;
77 static bool display_dev_available = false;
78 static guint release_timer;
79 static struct display_config *display_conf;
81 inline struct _backlight_ops *get_var_backlight_ops(void)
83 return &backlight_ops;
86 bool display_dev_ready(void)
88 return display_dev_available;
91 void dpms_set_running_state(int val)
93 dpms_running_state = val;
96 static int bl_onoff(int on, enum device_flags flags)
102 pm_history_save(PM_LOG_LCD_ON_COMPLETE, get_pm_cur_state());
103 else if (on == DPMS_OFF || on == DPMS_FORCE_OFF)
104 pm_history_save(PM_LOG_LCD_OFF_COMPLETE, get_pm_cur_state());
106 pm_history_save(PM_LOG_LCD_CONTROL_FAIL, on);
112 static int bl_brt(int brightness, int delay)
119 /* Update device brightness */
120 ret = backlight_ops.set_brightness(brightness);
122 _I("Set brightness(%d): %d", brightness, ret);
127 static int get_lcd_power_node(void)
130 enum display_state val;
132 ret = hal_device_display_get_state(&val);
136 if (val == DISPLAY_ON && ambient_get_state())
139 if (dpms_running_state != DPMS_SETTING_DONE)
140 return dpms_running_state;
145 case DISPLAY_STANDBY:
147 case DISPLAY_SUSPEND:
156 bool display_dimstay_check(void)
158 if (get_pm_status_flag() & DIM_FLAG)
161 if ((get_pm_status_flag() & PWRSV_FLAG) && !(get_pm_status_flag() & BRTCH_FLAG))
167 static void change_brightness(int start, int end, int step)
173 if (display_dimstay_check())
176 ret = backlight_ops.get_brightness(&prev);
178 _E("Failed to get brightness: %d", ret);
185 if (get_pm_status_flag() & DIM_MASK)
188 _I("start %d end %d step %d", start, end, step);
190 if (display_dev_available) {
191 ret = hal_device_display_set_multi_brightness(end, step, LCD_PHASED_DELAY);
192 if (ret != -ENODEV) {
194 _E("Failed to set_multi_brightness (%d)", ret);
196 backlight_ops.set_brightness(end);
204 if (abs(diff) < step)
205 val = (diff > 0 ? 1 : -1);
207 val = (int)ceil((double)diff / step);
209 while (start != end) {
213 if ((val > 0 && start > end) ||
214 (val < 0 && start < end))
217 bl_brt(start, LCD_PHASED_DELAY);
221 static int backlight_on(enum device_flags flags)
226 _I("[DPMS XLIB Backlight] LCD on %#x cnt:%d", flags, cnt);
229 ret = bl_onoff(DPMS_ON, flags);
231 pm_history_save(PM_LOG_LCD_ON, get_pm_cur_state());
237 static int backlight_off(enum device_flags flags)
240 static int cnt, ambient_cnt;
242 if (flags & AMBIENT_MODE) {
243 _I("[DPMS XLIB Backlight] LCD suspend %#x cnt:%d", flags, ambient_cnt);
249 _I("[DPMS XLIB Backlight] LCD off %#x cnt:%d", flags, cnt);
252 if (flags & LCD_PHASED_TRANSIT_MODE)
253 backlight_ops.transit_brt(default_brightness,
254 LCD_PHASED_MIN_BRIGHTNESS, LCD_PHASED_CHANGE_STEP);
256 if (flags & FORCE_OFF_MODE)
257 ret = bl_onoff(DPMS_FORCE_OFF, flags);
259 ret = bl_onoff(DPMS_OFF, flags);
262 pm_history_save(PM_LOG_LCD_OFF, get_pm_cur_state());
268 static int backlight_dim(void)
272 ret = backlight_ops.set_brightness(PM_DIM_BRIGHTNESS);
275 pm_history_save(PM_LOG_LCD_DIM, get_pm_cur_state());
277 pm_history_save(PM_LOG_LCD_DIM_FAIL, get_pm_cur_state());
282 static int set_custom_status(bool on)
288 static bool get_custom_status(void)
290 return custom_status;
293 static int save_custom_brightness(void)
297 ret = backlight_ops.get_brightness(&brightness);
299 custom_brightness = brightness;
304 static int custom_backlight_update(void)
308 if (custom_brightness < PM_MIN_BRIGHTNESS ||
309 custom_brightness > PM_MAX_BRIGHTNESS)
312 if (display_dimstay_check())
313 ret = backlight_dim();
315 _I("custom brightness restored! %d", custom_brightness);
316 ret = backlight_ops.set_brightness(custom_brightness);
322 static int set_force_brightness(int level)
324 if (level < 0 || level > PM_MAX_BRIGHTNESS)
327 force_brightness = level;
332 static int backlight_update(void)
337 if (get_custom_status()) {
338 _I("custom brightness mode! brt no updated");
341 if (display_dimstay_check())
342 ret = backlight_dim();
344 brt = backlight_ops.get_default_brt();
345 ret = backlight_ops.set_brightness(brt);
350 static int backlight_standby(int force)
354 if ((dpms_get_cached_state() == DPMS_ON) || force) {
356 ret = bl_onoff(DPMS_STANDBY, 0);
362 static int set_default_brt(int level)
364 if (level < PM_MIN_BRIGHTNESS || level > PM_MAX_BRIGHTNESS)
365 level = display_conf->pm_default_brightness;
367 default_brightness = level;
372 static int get_default_brt(void)
374 return default_brightness;
377 static int get_max_brightness(void)
385 if (!display_dev_available) {
386 _E("There is no HAL for display device.");
390 ret = hal_device_display_get_max_brightness(&max);
392 if (ret == -ENODEV) {
393 _E("Get max brightness is not supported.");
394 max = DEFAULT_DISPLAY_MAX_BRIGHTNESS;
397 _E("Failed to get max brightness: %d", ret);
405 static int set_brightness(int val)
409 if (!display_dev_available) {
410 _E("There is no display device.");
414 max = get_max_brightness();
416 _E("Failed to get max brightness.");
420 if (force_brightness > 0 && val != PM_DIM_BRIGHTNESS) {
421 _I("brightness(%d), force brightness(%d)",
422 val, force_brightness);
423 val = force_brightness;
426 if (get_pm_status_flag() & DIM_MASK)
429 /* Maximum Brightness to users is 100.
430 * Thus real brightness need to be calculated */
431 val = val * max / 100;
433 _I("set brightness %d (default:%d)", val, default_brightness);
434 device_notify(DEVICE_NOTIFIER_DISPLAY_BRIGHTNESS, (void *)&val);
436 return hal_device_display_set_brightness(val);
439 static int get_brt_normalized(int brt_raw)
441 int quotient, remainder;
444 max = get_max_brightness();
446 _E("Failed to get max brightness.");
450 /* Maximum Brightness to users is 100.
451 * Thus the brightness value need to be calculated using real brightness.
452 * ex) Let's suppose that the maximum brightness of driver is 255.
453 * case 1) When the user sets the brightness to 41,
455 * 41 * 255 / 100 = 104.55 = 104 (rounded off)
456 * case 2) When the user gets the brightness,
457 * the driver returns the brightness 104.
458 * Thus the brightness to users is
459 * 104 * 100 / 255 = 40.7843.... = 41 (rounded up)
461 quotient = brt_raw * 100 / max;
462 remainder = brt_raw * 100 % max;
469 static int get_brightness(int *val)
473 if (!display_dev_available) {
474 _E("There is no display device.");
478 ret = hal_device_display_get_brightness(&brt);
481 _E("Get brightness is not supported.");
483 _E("Failed to get brightness: %d", ret);
488 *val = get_brt_normalized(brt);
492 static int get_brightness_by_light_sensor(float lmax, float lmin, float light, int *brt)
497 if (!display_dev_available)
500 ret = hal_device_display_get_auto_brightness(lmax, lmin, light, &brt_raw);
503 _E("Get auto brightness is not supported.");
505 _E("Failed to get brightness by light sensor: %d", ret);
510 *brt = get_brt_normalized(brt_raw);
514 static int get_image_effect(enum display_image_effect *effect)
517 enum display_image_effect val;
519 if (!display_dev_available) {
520 _E("There is no display device.");
524 ret = hal_device_display_get_image_effect(&val);
527 _E("Get image effect is not supported.");
529 _E("Failed to get image effect: %d", ret);
539 static int set_image_effect(enum display_image_effect effect)
543 if (!display_dev_available) {
544 _E("There is no display device.");
548 ret = hal_device_display_set_image_effect(effect);
551 _E("Set image effect is not supported.");
553 _E("Failed to set image effect: %d", ret);
561 static int get_panel_mode(enum display_panel_mode *mode)
564 enum display_panel_mode val;
566 if (!display_dev_available) {
567 _E("There is no display device.");
571 ret = hal_device_display_get_panel_mode(&val);
574 _E("Get panel mode is not supported.");
576 _E("Failed to get panel mode(%d)", ret);
586 static int set_panel_mode(enum display_panel_mode mode)
590 if (!display_dev_available) {
591 _E("There is no display device.");
595 ret = hal_device_display_set_panel_mode(mode);
598 _E("Set panel mode is not supported.");
600 _E("Failed to set panel mode(%d)", ret);
608 static int get_frame_rate(int *rate)
613 if (!display_dev_available)
616 return hal_device_display_get_frame_rate(rate);
619 static int set_frame_rate(int rate)
622 static int fmin = -1, fmax = -1;
624 if (!display_dev_available)
628 ret = hal_device_display_get_min_frame_rate(&fmin);
630 _E("Failed to get min frate rate: %d", ret);
634 if ((ret != -ENODEV) && (rate < fmin)) {
635 _E("Invalid rate(%d). (Valid rate: %d <= rate)", rate, fmin);
640 ret = hal_device_display_get_max_frame_rate(&fmax);
642 _E("Failed to get max frate rate: %d", ret);
646 if ((ret != -ENODEV) && (rate > fmax)) {
647 _E("Invalid rate(%d). (Valid rate: rate <= %d)", rate, fmax);
651 return hal_device_display_set_frame_rate(rate);
654 /* It was operated only AOD enter & leave */
655 static int backlight_transit_state(int state)
660 backlight_ops.get_brightness(&brt);
662 if (state == DPMS_OFF) {
664 end = display_conf->aod_enter_level;
667 * The value of backlight_ops.get_brightness is system brightness.
668 * But when device is LBM, the value is not same with real brightness.
669 * So it should be read exactly value for transit smooth effect
671 get_brightness(&val);
673 if (val > display_conf->aod_enter_level)
674 backlight_ops.transit_brt(start, end, display_conf->brightness_change_step);
676 /* prevent transit effect when another effect is already executed */
677 if (brt != display_conf->aod_enter_level) {
678 _W("effect is already executed brt(%d) aod_level(%d)",
679 brt, display_conf->aod_enter_level);
683 start = display_conf->aod_enter_level;
684 end = default_brightness;
685 backlight_ops.transit_brt(start, end, display_conf->brightness_change_step);
691 static gboolean blink_cb(gpointer data)
695 set_brightness(flag ? PM_MAX_BRIGHTNESS : PM_MIN_BRIGHTNESS);
699 return G_SOURCE_CONTINUE;
702 static void blink(int timeout)
707 g_source_remove(timer);
712 _E("timeout value is invalid %d", timeout);
721 timer = g_timeout_add(timeout, blink_cb, NULL);
724 static gboolean release_blink_cb(gpointer data)
729 return G_SOURCE_REMOVE;
732 static void release_blink(void)
735 g_source_remove(release_timer);
739 release_timer = g_timeout_add(DUMP_MODE_WAITING_TIME, release_blink_cb, NULL);
742 static void restore_brightness_func(void)
744 backlight_ops.set_brightness = set_brightness;
745 backlight_ops.get_brightness = get_brightness;
746 backlight_ops.transit_brt = change_brightness;
749 static struct _backlight_ops backlight_ops = {
750 .off = backlight_off,
751 .dim = backlight_dim,
753 .update = backlight_update,
754 .standby = backlight_standby,
755 .set_default_brt = set_default_brt,
756 .get_default_brt = get_default_brt,
757 .get_lcd_power = dpms_get_cached_state,
758 .get_lcd_power_node = get_lcd_power_node,
759 .set_custom_status = set_custom_status,
760 .get_custom_status = get_custom_status,
761 .save_custom_brightness = save_custom_brightness,
762 .custom_update = custom_backlight_update,
763 .set_force_brightness = set_force_brightness,
764 .set_brightness = set_brightness,
765 .get_brightness = get_brightness,
766 .restore_brightness_func = restore_brightness_func,
767 .get_brightness_by_light_sensor = get_brightness_by_light_sensor,
768 .get_image_effect = get_image_effect,
769 .set_image_effect = set_image_effect,
770 .get_panel_mode = get_panel_mode,
771 .set_panel_mode = set_panel_mode,
772 .get_frame_rate = get_frame_rate,
773 .set_frame_rate = set_frame_rate,
774 .transit_state = backlight_transit_state,
775 .transit_brt = change_brightness,
777 .release_blink = release_blink,
780 int display_service_load(void)
784 if (display_dev_available)
787 r = hal_device_display_get_backend();
789 _E("There is no HAL for display.");
790 display_dev_available = false;
794 display_dev_available = true;
795 _D("Display device structure load success.");
799 int display_service_free(void)
801 display_dev_available = false;
802 return hal_device_display_put_backend();
805 /* Dummy. Do not consider detached display state */
806 int is_lcdon_blocked(void)
808 return LCDON_BLOCK_NONE;
811 int init_sysfs(unsigned int flags)
813 register_notifier(DEVICE_NOTIFIER_VITAL_STATE, vital_state_changed);
820 const struct device_ops *ops = NULL;
826 ops = find_device("touchscreen");
827 if (!check_default(ops))
828 ops->start(NORMAL_MODE);
830 ops = find_device("touchkey");
831 if (!check_default(ops))
832 ops->start(NORMAL_MODE);
834 unregister_notifier(DEVICE_NOTIFIER_VITAL_STATE, vital_state_changed);
839 static void __CONSTRUCTOR__ initialize(void)
841 display_conf = get_var_display_config();
843 _E("Failed to get display configuration variable.");