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"
36 #include "power/power-suspend.h"
38 #include "shared/devices.h"
39 #include "shared/common.h"
40 #include "shared/device-notifier.h"
42 #include "device-interface.h"
45 #include "display/display-dpms.h"
46 #include "display/display.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 MAX_WHITE_BALANCE_GAIN 2047
59 #define MAX_WHITE_BALANCE_OFFSET 2047
60 #define DEFAULT_WHITE_BALANCE_GAIN 1024
61 #define DEFAULT_WHITE_BALANCE_OFFSET 0
63 #define DISPLAY_HAL_LIB_PATH "/usr/lib/libdisplay-hal.so"
65 #define GESTURE_STR "gesture"
66 #define POWERKEY_STR "powerkey"
67 #define EVENT_STR "event"
68 #define TOUCH_STR "touch"
69 #define TIMEOUT_STR "timeout"
70 #define PROXIMITY_STR "proximity"
71 #define PALM_STR "palm"
72 #define UNKNOWN_STR "unknown"
74 #define FREEZER_VITAL_WAKEUP_CGROUP "/sys/fs/cgroup/freezer/vital_wakeup/freezer.state"
76 static struct _backlight_ops backlight_ops;
77 static struct _display_white_balance_ops display_white_balance_ops;
78 static bool custom_status;
79 static int custom_brightness;
80 static int force_brightness;
81 static int default_brightness;
82 static int dpms_running_state = DPMS_SETTING_DONE;
83 static bool display_dev_available = false;
84 static guint release_timer;
85 static struct display_config *display_conf;
87 inline struct _backlight_ops *get_var_backlight_ops(void)
89 return &backlight_ops;
92 inline struct _display_white_balance_ops *get_var_display_white_balance_ops(void)
94 return &display_white_balance_ops;
97 bool display_dev_ready(void)
99 return display_dev_available;
102 void dpms_set_running_state(int val)
104 dpms_running_state = val;
107 static int bl_onoff(int on, enum device_flags flags)
113 pm_history_save(PM_LOG_LCD_ON_COMPLETE, get_pm_cur_state());
114 else if (on == DPMS_OFF || on == DPMS_FORCE_OFF)
115 pm_history_save(PM_LOG_LCD_OFF_COMPLETE, get_pm_cur_state());
117 pm_history_save(PM_LOG_LCD_CONTROL_FAIL, on);
123 static int bl_brt(int brightness, int delay)
130 /* Update device brightness */
131 ret = backlight_ops.set_brightness(brightness);
133 _I("Set brightness(%d): %d", brightness, ret);
138 static int get_lcd_power_node(void)
141 enum display_state val;
143 ret = hal_device_display_get_state(&val);
147 if (val == DISPLAY_ON && ambient_get_state())
150 if (dpms_running_state != DPMS_SETTING_DONE)
151 return dpms_running_state;
156 case DISPLAY_STANDBY:
158 case DISPLAY_SUSPEND:
167 bool display_dimstay_check(void)
169 if (get_pm_status_flag() & DIM_FLAG)
172 if ((get_pm_status_flag() & PWRSV_FLAG) && !(get_pm_status_flag() & BRTCH_FLAG))
178 static void change_brightness(int start, int end, int step)
184 if (display_dimstay_check())
187 ret = backlight_ops.get_brightness(&prev);
189 _E("Failed to get brightness: %d", ret);
196 if (get_pm_status_flag() & DIM_MASK)
199 _I("start %d end %d step %d", start, end, step);
201 if (display_dev_available) {
202 ret = hal_device_display_set_multi_brightness(end, step, LCD_PHASED_DELAY);
203 if (ret != -ENODEV) {
205 _E("Failed to set_multi_brightness (%d)", ret);
207 backlight_ops.set_brightness(end);
215 if (abs(diff) < step)
216 val = (diff > 0 ? 1 : -1);
218 val = (int)ceil((double)diff / step);
220 while (start != end) {
224 if ((val > 0 && start > end) ||
225 (val < 0 && start < end))
228 bl_brt(start, LCD_PHASED_DELAY);
232 static int backlight_on(enum device_flags flags)
237 _I("[DPMS XLIB Backlight] LCD on %#x cnt:%d", flags, cnt);
240 ret = bl_onoff(DPMS_ON, flags);
242 pm_history_save(PM_LOG_LCD_ON, get_pm_cur_state());
248 static int backlight_off(enum device_flags flags)
251 static int cnt, ambient_cnt;
253 if (flags & AMBIENT_MODE) {
254 _I("[DPMS XLIB Backlight] LCD suspend %#x cnt:%d", flags, ambient_cnt);
260 _I("[DPMS XLIB Backlight] LCD off %#x cnt:%d", flags, cnt);
263 if (flags & LCD_PHASED_TRANSIT_MODE)
264 backlight_ops.transit_brt(default_brightness,
265 LCD_PHASED_MIN_BRIGHTNESS, LCD_PHASED_CHANGE_STEP);
267 if (flags & FORCE_OFF_MODE)
268 ret = bl_onoff(DPMS_FORCE_OFF, flags);
270 ret = bl_onoff(DPMS_OFF, flags);
273 pm_history_save(PM_LOG_LCD_OFF, get_pm_cur_state());
279 static int backlight_dim(void)
283 ret = backlight_ops.set_brightness(PM_DIM_BRIGHTNESS);
286 pm_history_save(PM_LOG_LCD_DIM, get_pm_cur_state());
288 pm_history_save(PM_LOG_LCD_DIM_FAIL, get_pm_cur_state());
293 static int set_custom_status(bool on)
299 static bool get_custom_status(void)
301 return custom_status;
304 static int save_custom_brightness(void)
308 ret = backlight_ops.get_brightness(&brightness);
310 custom_brightness = brightness;
315 static int custom_backlight_update(void)
319 if (custom_brightness < PM_MIN_BRIGHTNESS ||
320 custom_brightness > PM_MAX_BRIGHTNESS)
323 if (display_dimstay_check())
324 ret = backlight_dim();
326 _I("custom brightness restored! %d", custom_brightness);
327 ret = backlight_ops.set_brightness(custom_brightness);
333 static int set_force_brightness(int level)
335 if (level < 0 || level > PM_MAX_BRIGHTNESS)
338 force_brightness = level;
343 static int backlight_update(void)
348 if (get_custom_status()) {
349 _I("custom brightness mode! brt no updated");
352 if (display_dimstay_check())
353 ret = backlight_dim();
355 brt = backlight_ops.get_default_brt();
356 ret = backlight_ops.set_brightness(brt);
361 static int backlight_standby(int force)
365 if ((dpms_get_cached_state() == DPMS_ON) || force) {
367 ret = bl_onoff(DPMS_STANDBY, 0);
373 static int set_default_brt(int level)
375 if (level < PM_MIN_BRIGHTNESS || level > PM_MAX_BRIGHTNESS)
376 level = display_conf->pm_default_brightness;
378 default_brightness = level;
383 static int get_default_brt(void)
385 return default_brightness;
388 static int get_max_brightness(void)
396 if (!display_dev_available) {
397 _E("There is no HAL for display.");
401 ret = hal_device_display_get_max_brightness(&max);
403 if (ret == -ENODEV) {
404 _E("Get max brightness is not supported.");
405 max = DEFAULT_DISPLAY_MAX_BRIGHTNESS;
408 _E("Failed to get max brightness: %d", ret);
416 static int set_brightness(int val)
420 if (!display_dev_available) {
421 _E("There is no display device.");
425 max = get_max_brightness();
427 _E("Failed to get max brightness.");
431 if (force_brightness > 0 && val != PM_DIM_BRIGHTNESS) {
432 _I("brightness(%d), force brightness(%d)",
433 val, force_brightness);
434 val = force_brightness;
437 if (get_pm_status_flag() & DIM_MASK)
440 /* Maximum Brightness to users is 100.
441 * Thus real brightness need to be calculated */
442 val = val * max / 100;
444 _I("set brightness %d (default:%d)", val, default_brightness);
445 device_notify(DEVICE_NOTIFIER_DISPLAY_BRIGHTNESS, (void *)&val);
447 return hal_device_display_set_brightness(val);
450 static int get_brt_normalized(int brt_raw)
452 int quotient, remainder;
455 max = get_max_brightness();
457 _E("Failed to get max brightness.");
461 /* Maximum Brightness to users is 100.
462 * Thus the brightness value need to be calculated using real brightness.
463 * ex) Let's suppose that the maximum brightness of driver is 255.
464 * case 1) When the user sets the brightness to 41,
466 * 41 * 255 / 100 = 104.55 = 104 (rounded off)
467 * case 2) When the user gets the brightness,
468 * the driver returns the brightness 104.
469 * Thus the brightness to users is
470 * 104 * 100 / 255 = 40.7843.... = 41 (rounded up)
472 quotient = brt_raw * 100 / max;
473 remainder = brt_raw * 100 % max;
480 static int get_brightness(int *val)
484 if (!display_dev_available) {
485 _E("There is no display device.");
489 ret = hal_device_display_get_brightness(&brt);
492 _E("Get brightness is not supported.");
494 _E("Failed to get brightness: %d", ret);
499 *val = get_brt_normalized(brt);
503 static int get_brightness_by_light_sensor(float lmax, float lmin, float light, int *brt)
508 if (!display_dev_available)
511 ret = hal_device_display_get_auto_brightness(lmax, lmin, light, &brt_raw);
514 _E("Get auto brightness is not supported.");
516 _E("Failed to get brightness by light sensor: %d", ret);
521 *brt = get_brt_normalized(brt_raw);
525 static int get_image_effect(enum display_image_effect *effect)
528 enum display_image_effect val;
530 if (!display_dev_available) {
531 _E("There is no display device.");
535 ret = hal_device_display_get_image_effect(&val);
538 _E("Get image effect is not supported.");
540 _E("Failed to get image effect: %d", ret);
550 static int set_image_effect(enum display_image_effect effect)
554 if (!display_dev_available) {
555 _E("There is no display device.");
559 ret = hal_device_display_set_image_effect(effect);
562 _E("Set image effect is not supported.");
564 _E("Failed to set image effect: %d", ret);
572 static int get_panel_mode(enum display_panel_mode *mode)
575 enum display_panel_mode val;
577 if (!display_dev_available) {
578 _E("There is no display device.");
582 ret = hal_device_display_get_panel_mode(&val);
585 _E("Get panel mode is not supported.");
587 _E("Failed to get panel mode(%d)", ret);
597 static int set_panel_mode(enum display_panel_mode mode)
601 if (!display_dev_available) {
602 _E("There is no display device.");
606 ret = hal_device_display_set_panel_mode(mode);
609 _E("Set panel mode is not supported.");
611 _E("Failed to set panel mode(%d)", ret);
619 static int get_frame_rate(int *rate)
624 if (!display_dev_available)
627 return hal_device_display_get_frame_rate(rate);
630 static int set_frame_rate(int rate)
633 static int fmin = -1, fmax = -1;
635 if (!display_dev_available)
639 ret = hal_device_display_get_min_frame_rate(&fmin);
641 _E("Failed to get min frate rate: %d", ret);
645 if ((ret != -ENODEV) && (rate < fmin)) {
646 _E("Invalid rate(%d). (Valid rate: %d <= rate)", rate, fmin);
651 ret = hal_device_display_get_max_frame_rate(&fmax);
653 _E("Failed to get max frate rate: %d", ret);
657 if ((ret != -ENODEV) && (rate > fmax)) {
658 _E("Invalid rate(%d). (Valid rate: rate <= %d)", rate, fmax);
662 return hal_device_display_set_frame_rate(rate);
665 /* It was operated only AOD enter & leave */
666 static int backlight_transit_state(int state)
671 backlight_ops.get_brightness(&brt);
673 if (state == DPMS_OFF) {
675 end = display_conf->aod_enter_level;
678 * The value of backlight_ops.get_brightness is system brightness.
679 * But when device is LBM, the value is not same with real brightness.
680 * So it should be read exactly value for transit smooth effect
682 get_brightness(&val);
684 if (val > display_conf->aod_enter_level)
685 backlight_ops.transit_brt(start, end, display_conf->brightness_change_step);
687 /* prevent transit effect when another effect is already executed */
688 if (brt != display_conf->aod_enter_level) {
689 _W("effect is already executed brt(%d) aod_level(%d)",
690 brt, display_conf->aod_enter_level);
694 start = display_conf->aod_enter_level;
695 end = default_brightness;
696 backlight_ops.transit_brt(start, end, display_conf->brightness_change_step);
702 static gboolean blink_cb(gpointer data)
706 set_brightness(flag ? PM_MAX_BRIGHTNESS : PM_MIN_BRIGHTNESS);
710 return G_SOURCE_CONTINUE;
713 static void blink(int timeout)
718 g_source_remove(timer);
723 _E("timeout value is invalid %d", timeout);
732 timer = g_timeout_add(timeout, blink_cb, NULL);
735 static gboolean release_blink_cb(gpointer data)
740 return G_SOURCE_REMOVE;
743 static void release_blink(void)
746 g_source_remove(release_timer);
750 release_timer = g_timeout_add(DUMP_MODE_WAITING_TIME, release_blink_cb, NULL);
753 static int set_white_balance(enum hal_display_white_balance white_balance_type, int value)
757 if (!display_dev_available) {
758 _E("There is no display device.");
762 switch (white_balance_type) {
763 case HAL_DISPLAY_WHITE_BALANCE_R_GAIN:
764 case HAL_DISPLAY_WHITE_BALANCE_G_GAIN:
765 case HAL_DISPLAY_WHITE_BALANCE_B_GAIN:
766 if (value > MAX_WHITE_BALANCE_GAIN)
767 value = DEFAULT_WHITE_BALANCE_GAIN;
769 case HAL_DISPLAY_WHITE_BALANCE_R_OFFSET:
770 case HAL_DISPLAY_WHITE_BALANCE_G_OFFSET:
771 case HAL_DISPLAY_WHITE_BALANCE_B_OFFSET:
772 if (value > MAX_WHITE_BALANCE_OFFSET)
773 value = DEFAULT_WHITE_BALANCE_OFFSET;
776 _E("Unknown white balance type");
780 ret = hal_device_display_set_white_balance(white_balance_type, value);
783 _E("Set white balance is not supported.");
785 _E("Failed to set white balance value.");
791 static int get_white_balance(enum hal_display_white_balance white_balance_type, int* value)
795 if (!display_dev_available) {
796 _E("There is no display device.");
800 switch (white_balance_type) {
801 case HAL_DISPLAY_WHITE_BALANCE_R_GAIN:
802 case HAL_DISPLAY_WHITE_BALANCE_G_GAIN:
803 case HAL_DISPLAY_WHITE_BALANCE_B_GAIN:
804 case HAL_DISPLAY_WHITE_BALANCE_R_OFFSET:
805 case HAL_DISPLAY_WHITE_BALANCE_G_OFFSET:
806 case HAL_DISPLAY_WHITE_BALANCE_B_OFFSET:
809 _E("Unknown white balance type");
813 ret = hal_device_display_get_white_balance(white_balance_type, value);
816 _E("Get white balance is not supported.");
818 _E("Failed to get white balance value.");
824 static void restore_brightness_func(void)
826 backlight_ops.set_brightness = set_brightness;
827 backlight_ops.get_brightness = get_brightness;
828 backlight_ops.transit_brt = change_brightness;
831 static struct _backlight_ops backlight_ops = {
832 .off = backlight_off,
833 .dim = backlight_dim,
835 .update = backlight_update,
836 .standby = backlight_standby,
837 .set_default_brt = set_default_brt,
838 .get_default_brt = get_default_brt,
839 .get_lcd_power = dpms_get_cached_state,
840 .get_lcd_power_node = get_lcd_power_node,
841 .set_custom_status = set_custom_status,
842 .get_custom_status = get_custom_status,
843 .save_custom_brightness = save_custom_brightness,
844 .custom_update = custom_backlight_update,
845 .set_force_brightness = set_force_brightness,
846 .set_brightness = set_brightness,
847 .get_brightness = get_brightness,
848 .restore_brightness_func = restore_brightness_func,
849 .get_brightness_by_light_sensor = get_brightness_by_light_sensor,
850 .get_image_effect = get_image_effect,
851 .set_image_effect = set_image_effect,
852 .get_panel_mode = get_panel_mode,
853 .set_panel_mode = set_panel_mode,
854 .get_frame_rate = get_frame_rate,
855 .set_frame_rate = set_frame_rate,
856 .transit_state = backlight_transit_state,
857 .transit_brt = change_brightness,
859 .release_blink = release_blink,
862 static struct _display_white_balance_ops display_white_balance_ops = {
863 .set_white_balance = set_white_balance,
864 .get_white_balance = get_white_balance,
867 int display_service_load(void)
871 if (display_dev_available)
874 r = hal_device_display_get_backend();
876 _E("There is no HAL for display.");
877 display_dev_available = false;
881 display_dev_available = true;
882 _D("Display device structure load success.");
886 int display_service_free(void)
888 display_dev_available = false;
889 return hal_device_display_put_backend();
892 /* Dummy. Do not consider detached display state */
893 int is_lcdon_blocked(void)
895 return LCDON_BLOCK_NONE;
898 int init_sysfs(unsigned int flags)
900 register_notifier(DEVICE_NOTIFIER_VITAL_STATE, vital_state_changed);
907 const struct device_ops *ops = NULL;
913 ops = find_device("touchscreen");
914 if (!check_default(ops))
915 ops->start(NORMAL_MODE);
917 ops = find_device("touchkey");
918 if (!check_default(ops))
919 ops->start(NORMAL_MODE);
921 unregister_notifier(DEVICE_NOTIFIER_VITAL_STATE, vital_state_changed);
926 static void __CONSTRUCTOR__ initialize(void)
928 display_conf = get_var_display_config();
930 _E("Failed to get display configuration variable.");