shared: Replace device_notifier_type with the libsyscommon
[platform/core/system/deviced.git] / src / display / display-backlight.c
1 /*
2  * deviced
3  *
4  * Copyright (c) 2023 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 #include <math.h>
20
21 #include <hal/device/hal-display.h>
22
23 #include "shared/device-notifier.h"
24 #include "shared/log.h"
25 #include "power/power-suspend.h"
26 #include "core.h"
27 #include "device-interface.h"
28 #include "display.h"
29 #include "display-state-transition.h"
30 #include "display-backlight.h"
31 #include "display-panel.h"
32 #include "display-plugin.h"
33
34 #define DUMP_MODE_WAITING_TIME          600000  /* milisecond */
35 #define LCD_PHASED_DELAY                10000   /* microsecond */
36
37 static int default_brightness;
38 static int custom_brightness;
39 static bool g_custom_status;
40 static int force_brightness;
41 static guint release_timer;
42
43 /* FIXME: This function is for temporary use, should be fixed after plugin refactoring */
44 int display_backlight_get_max_brightness(int *max_brightness)
45 {
46         static int max = -1;
47         int ret = 0;
48
49         if (!max_brightness)
50                 return -EINVAL;
51
52         if (max > 0) {
53                 *max_brightness = max;
54                 return 0;
55         }
56
57         if (!display_is_hal_backend_available()) {
58                 _E("There is no HAL for display.");
59                 return -ENOENT;
60         }
61
62         ret = hal_device_display_get_max_brightness(&max);
63         if (ret == -ENODEV) {
64                 _W("Get max brightness is not supported.");
65                 *max_brightness = DEFAULT_DISPLAY_MAX_BRIGHTNESS;
66                 return 0;
67         } else if (ret < 0) {
68                 _E("Failed to get max brightness: %d", ret);
69         }
70
71         return ret;
72 }
73
74 /* FIXME: This function is for temporary use, should be fixed after plugin refactoring */
75 int display_backlight_get_normalized_brightness(int raw_brightness,
76         int *normalized_brightness)
77 {
78         int quotient, remainder;
79         int max, ret;
80
81         if (!normalized_brightness)
82                 return -EINVAL;
83
84         ret = display_backlight_get_max_brightness(&max);
85         if (ret < 0) {
86                 _E("Failed to get max brightness.");
87                 return ret;
88         }
89
90         /**
91          * Thus the brightness value need to be calculated using real brightness.
92          *    ex) Let's suppose that the maximum brightness of driver is 255.
93          *      case 1) When the user sets the brightness to 41,
94          *              real brightness is
95          *                 41 * 255 / 100 = 104.55 = 104 (rounded off)
96          *      case 2) When the user gets the brightness,
97          *              the driver returns the brightness 104.
98          *              Thus the brightness to users is
99          *                 104 * 100 / 255 = 40.7843.... = 41 (rounded up)
100          */
101         quotient = raw_brightness * 100 / max;
102         remainder = raw_brightness * 100 % max;
103         if (remainder > 0)
104                 quotient++;
105
106         *normalized_brightness = quotient;
107         return 0;
108 }
109
110 int display_backlight_set_brightness(int brightness)
111 {
112         int max_brightness, ret;
113         int default_brightness, force_brightness;
114
115         display_backlight_get_default_brightness(&default_brightness);
116         display_backlight_get_force_brightness(&force_brightness);
117
118         ret = display_plugin_backlight_set_brightness(brightness);
119         if (ret == 0)
120                 return 0;
121
122         if (!display_is_hal_backend_available()) {
123                 _E("There is no display device.");
124                 return -ENOENT;
125         }
126
127         ret = display_backlight_get_max_brightness(&max_brightness);
128         if (ret < 0) {
129                 _E("Failed to get max brightness.");
130                 return ret;
131         }
132
133         if (force_brightness > 0 && brightness != PM_DIM_BRIGHTNESS) {
134                 _I("brightness(%d), force brightness(%d)", brightness, force_brightness);
135                 brightness = force_brightness;
136         }
137
138         if (get_pm_status_flag() & DIM_MASK)
139                 brightness = PM_DIM_BRIGHTNESS;
140
141         /* Maximum Brightness to users is 100.
142          * Thus real brightness need to be calculated */
143         brightness = brightness * max_brightness / 100;
144
145         _I("set brightness %d (default:%d)", brightness, default_brightness);
146         syscommon_notifier_emit_notify(DEVICED_NOTIFIER_DISPLAY_BRIGHTNESS, (void *)&brightness);
147
148         return hal_device_display_set_brightness(brightness);
149 }
150
151 int display_backlight_get_brightness(int *brightness)
152 {
153         int brt = 0, ret = 0;
154
155         ret = display_plugin_backlight_get_brightness(brightness);
156         if (ret == 0)
157                 return 0;
158
159         if (!display_is_hal_backend_available()) {
160                 _E("There is no display device.");
161                 return -ENOENT;
162         }
163
164         ret = hal_device_display_get_brightness(&brt);
165         if (ret < 0) {
166                 if (ret == -ENODEV)
167                         _E("Get brightness is not supported.");
168                 else
169                         _E("Failed to get brightness: %d", ret);
170
171                 return ret;
172         }
173
174         ret = display_backlight_get_normalized_brightness(brt, brightness);
175         if (ret < 0) {
176                 _E("Failed to get normalized brightness.");
177                 return ret;
178         }
179
180         return 0;
181 }
182
183 void display_backlight_change_brightness(int start, int end, int step)
184 {
185         int diff, val;
186         int ret = -1;
187         int prev;
188
189         ret = display_plugin_backlight_transit_brightness(start, end, step);
190         if (ret == 0)
191                 return;
192
193         if (display_dimstay_check())
194                 return;
195
196         ret = display_backlight_get_brightness(&prev);
197         if (ret < 0) {
198                 _E("Failed to get brightness: %d", ret);
199                 return;
200         }
201
202         if (prev == end)
203                 return;
204
205         if (get_pm_status_flag() & DIM_MASK)
206                 end = PM_DIM_BRIGHTNESS;
207
208         _I("start %d end %d step %d", start, end, step);
209
210         if (!display_is_hal_backend_available()) {
211                 ret = hal_device_display_set_multi_brightness(end, step, LCD_PHASED_DELAY);
212                 if (ret != -ENODEV) {
213                         if (ret < 0)
214                                 _E("Failed to set_multi_brightness (%d)", ret);
215
216                         display_backlight_set_brightness(end);
217
218                         return;
219                 }
220         }
221
222         diff = end - start;
223
224         if (abs(diff) < step)
225                 val = (diff > 0 ? 1 : -1);
226         else
227                 val = (int)ceil((double)diff / step);
228
229         while (start != end) {
230                 if (val == 0)
231                         break;
232
233                 start += val;
234                 if ((val > 0 && start > end) || (val < 0 && start < end))
235                         start = end;
236
237                 display_backlight_set_brightness_with_delay(start, LCD_PHASED_DELAY);
238         }
239 }
240
241 /* FIXME: display_backlight_get_brightness is duplicated, this code structure should be changed */
242 /* It was operated only AOD enter & leave. */
243 int display_backlight_change_brightness_by_dpms_state(enum dpms_state state)
244 {
245         int brt, val;
246         int start, end;
247         int default_brightness;
248         int ret;
249
250         assert(g_display_plugin.config);
251
252         display_backlight_get_default_brightness(&default_brightness);
253
254         ret = display_plugin_backlight_transit_state((int) state);
255         if (ret == 0)
256                 return 0;
257
258         display_backlight_get_brightness(&brt);
259
260         if (state == DPMS_OFF) {
261                 start = brt;
262                 end = g_display_plugin.config->aod_enter_level;
263
264                 /*
265                  * The value of display_backlight_get_brightness is system brightness.
266                  * But when device is LBM, the value is not same with real brightness.
267                  * So it should be read exactly value for transit smooth effect
268                  */
269                 display_backlight_get_brightness(&val);
270
271                 if (val > g_display_plugin.config->aod_enter_level)
272                         display_backlight_change_brightness(start, end, g_display_plugin.config->brightness_change_step);
273         } else {
274                 /* prevent transit effect when another effect is already executed */
275                 if (brt != g_display_plugin.config->aod_enter_level) {
276                         _W("effect is already executed brt(%d) aod_level(%d)",
277                                         brt, g_display_plugin.config->aod_enter_level);
278                         return 0;
279                 }
280
281                 start = g_display_plugin.config->aod_enter_level;
282                 end = default_brightness;
283                 display_backlight_change_brightness(start, end, g_display_plugin.config->brightness_change_step);
284         }
285
286         return 0;
287 }
288
289 int display_backlight_set_default_brightness(int brightness)
290 {
291         if (brightness < PM_MIN_BRIGHTNESS || brightness > PM_MAX_BRIGHTNESS) {
292                 if (g_display_plugin.config)
293                         brightness = g_display_plugin.config->pm_default_brightness;
294                 else
295                         return -EPERM;
296         }
297
298         default_brightness = brightness;
299         return 0;
300 }
301
302 /* FIXME: default_brightness value should be initialized by vconf_get_int */
303 int display_backlight_get_default_brightness(int *brightness)
304 {
305         *brightness = default_brightness;
306         return 0;
307 }
308
309 int display_backlight_set_brightness_by_dim_brightness(void)
310 {
311         int ret = 0;
312
313         ret = display_backlight_set_brightness(PM_DIM_BRIGHTNESS);
314
315 #ifdef ENABLE_PM_LOG
316         enum deviced_display_state current;
317
318         if (display_state_get_current(&current) < 0)
319                 return ret;
320
321         if (!ret)
322                 pm_history_save(PM_LOG_LCD_DIM, current);
323         else
324                 pm_history_save(PM_LOG_LCD_DIM_FAIL, current);
325 #endif
326         return ret;
327 }
328
329 int display_backlight_update_by_default_brightness(void)
330 {
331         int ret = 0;
332         int default_brightness;
333         bool custom_status;
334
335         display_backlight_get_custom_status(&custom_status);
336         if (custom_status) {
337                 _I("Custom brightness mode, no update brightness");
338                 return 0;
339         }
340
341         if (display_dimstay_check()) {
342                 ret = display_backlight_set_brightness_by_dim_brightness();
343         } else {
344                 display_backlight_get_default_brightness(&default_brightness);
345                 ret = display_backlight_set_brightness(default_brightness);
346         }
347
348         return ret;
349 }
350
351 /* FIXME: This custom_brightness policy can be changed, after plugin refactoring */
352 void display_backlight_set_custom_brightness(int brightness)
353 {
354         custom_brightness = brightness;
355 }
356
357 int display_backlight_update_by_custom_brightness(void)
358 {
359         int ret = 0;
360
361         if (custom_brightness < PM_MIN_BRIGHTNESS || custom_brightness > PM_MAX_BRIGHTNESS)
362                 return -EINVAL;
363
364         if (display_dimstay_check()) {
365                 ret = display_backlight_set_brightness_by_dim_brightness();
366         } else {
367                 _I("Custom brightness restored! %d", custom_brightness);
368                 ret = display_backlight_set_brightness(custom_brightness);
369         }
370
371         return ret;
372 }
373
374 /* FIXME: This custom_status policy can be changed, after plugin refactoting*/
375 void display_backlight_set_custom_status(bool on)
376 {
377         g_custom_status = on;
378 }
379
380 /* FIXME: This custom_status policy can be changed, after plugin refactoting*/
381 void display_backlight_get_custom_status(bool *on)
382 {
383         *on = g_custom_status;
384 }
385
386 /* FIXME: This function is not tested */
387 int display_backlight_get_brightness_by_light_sensor(float lmax, float lmin,
388                                                         float light, int *brightness)
389 {
390         int raw_brightness, ret = 0;
391
392         if (!display_is_hal_backend_available())
393                 return -ENOTSUP;
394
395         ret = hal_device_display_get_auto_brightness(lmax, lmin, light, &raw_brightness);
396         if (ret < 0) {
397                 if (ret == -ENODEV)
398                         _E("Get auto brightness is not supported.");
399                 else
400                         _E("Failed to get brightness by light sensor: %d", ret);
401                 return ret;
402         }
403
404         ret = display_backlight_get_normalized_brightness(raw_brightness, brightness);
405         if (ret < 0) {
406                 _E("Failed to get normalized brightness.");
407                 return ret;
408         }
409
410         return 0;
411 }
412
413 static gboolean blink_cb(gpointer data)
414 {
415         static bool flag;
416
417         display_backlight_set_brightness(flag ? PM_MAX_BRIGHTNESS : PM_MIN_BRIGHTNESS);
418         flag = !flag;
419
420         return G_SOURCE_CONTINUE;
421 }
422
423 void display_backlight_set_blink(int timeout)
424 {
425         static guint blink_timer;
426
427         if (blink_timer) {
428                 g_source_remove(blink_timer);
429                 blink_timer = 0;
430         }
431
432         if (timeout < 0) {
433                 _W("timeout value is invalid %d", timeout);
434                 return;
435         }
436
437         if (timeout == 0) {
438                 display_backlight_update_by_default_brightness();
439                 return;
440         }
441
442         blink_timer = g_timeout_add(timeout, blink_cb, NULL);
443 }
444
445 static gboolean release_blink_cb(gpointer data)
446 {
447         display_backlight_set_blink(0);
448
449         release_timer = 0;
450         return G_SOURCE_REMOVE;
451 }
452
453 void display_backlight_unset_blink(void)
454 {
455         if (release_timer) {
456                 g_source_remove(release_timer);
457                 release_timer = 0;
458         }
459
460         release_timer = g_timeout_add(DUMP_MODE_WAITING_TIME, release_blink_cb, NULL);
461 }
462
463 int display_backlight_set_brightness_with_delay(int brightness, int delay)
464 {
465         int ret = -1;
466
467         if (delay > 0)
468                 usleep(delay);
469
470         /* Update device brightness */
471         ret = display_backlight_set_brightness(brightness);
472         _I("Set brightness(%d): %d", brightness, ret);
473
474         return ret;
475 }
476
477 /* FIXME: This function is only used for wearable plugin */
478 int display_backlight_set_force_brightness(int brightness)
479 {
480         if (brightness < PM_DIM_BRIGHTNESS ||  brightness > PM_MAX_BRIGHTNESS)
481                 return -EINVAL;
482
483         force_brightness = brightness;
484
485         return 0;
486 }
487
488 /* FIXME: This function is only used for wearable plugin */
489 void display_backlight_get_force_brightness(int *brightness)
490 {
491         *brightness = force_brightness;
492 }