4 * Copyright (c) 2012 - 2013 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.
26 #include <sys/types.h>
34 #include "display-ops.h"
35 #include "device-node.h"
36 #include "proc/proc-handler.h"
38 #define DISP_FORCE_SHIFT 12
39 #define DISP_FORCE_CMD(prop, force) (((force) << DISP_FORCE_SHIFT) | prop)
41 #define SAMPLING_INTERVAL 1 /* 1 sec */
42 #define MAX_SAMPLING_COUNT 3
44 #define DEFAULT_AUTOMATIC_BRT 5
45 #define MAX_AUTOMATIC_COUNT 11
46 #define AUTOMATIC_DEVIDE_VAL 10
47 #define AUTOMATIC_DELAY_TIME 0.5 /* 0.5 sec */
48 #define MAX_NORMAL_LUX 10000
50 #define RADIAN_VALUE (57.2957)
51 #define ROTATION_90 90
52 #define WORKING_ANGLE_MIN 0
53 #define WORKING_ANGLE_MAX 20
55 #define ISVALID_AUTOMATIC_INDEX(index) (index >= 0 && index < MAX_AUTOMATIC_COUNT)
57 static int (*_default_action) (int);
58 static Ecore_Timer *alc_timeout_id = 0;
59 static Ecore_Timer *update_timeout;
60 static int light_handle = -1;
61 static int accel_handle = -1;
62 static int fault_count = 0;
63 static int automatic_brt = DEFAULT_AUTOMATIC_BRT;
64 static int min_brightness = PM_MIN_BRIGHTNESS;
65 static char *min_brightness_name = 0;
66 static int last_autobrightness = 0;
67 static int value_table[MAX_AUTOMATIC_COUNT];
69 static bool update_working_position(void)
73 float x, y, z, pitch, realg;
75 ret = sf_get_data(accel_handle, ACCELEROMETER_BASE_DATA_SET, &data);
77 _E("Fail to get accelerometer data! %d", ret);
85 realg = (float)sqrt((x * x) + (y * y) + (z * z));
86 pitch = ROTATION_90 - abs((int) (asin(z / realg) * RADIAN_VALUE));
88 _D("accel data [%f, %f, %f] - %f", x, y, z, pitch);
90 if (pitch >= WORKING_ANGLE_MIN && pitch <= WORKING_ANGLE_MAX)
95 static int get_siop_brightness(int value)
99 cmd = DISP_CMD(PROP_DISPLAY_MAX_BRIGHTNESS, DEFAULT_DISPLAY);
100 ret = device_get_property(DEVICE_TYPE_DISPLAY, cmd, &brt);
101 if (ret >= 0 && value > brt)
107 static void alc_set_brightness(int setting, int value, int lux)
110 int position, cmd, tmp_value = 0;
112 cmd = DISP_CMD(PROP_DISPLAY_BRIGHTNESS, DEFAULT_DISPLAY);
113 if (device_get_property(DEVICE_TYPE_DISPLAY, cmd, &tmp_value) < 0) {
114 _E("Fail to get display brightness!");
118 if (value < min_brightness)
119 value = min_brightness;
121 if (cur_siop_level() != 0)
122 value = get_siop_brightness(value);
124 if (tmp_value != value) {
125 if (!setting && min_brightness == PM_MIN_BRIGHTNESS) {
126 position = update_working_position();
127 if (!position && (old > lux)) {
128 _D("It's not working position, "
129 "LCD isn't getting dark!");
135 diff = value - tmp_value;
136 if (abs(diff) < display_conf.brightness_change_step)
137 step = (diff > 0 ? 1 : -1);
139 step = (int)ceil(diff /
140 (float)display_conf.brightness_change_step);
143 while (tmp_value != value) {
144 if (step == 0) break;
147 if ((step > 0 && tmp_value > value) ||
148 (step < 0 && tmp_value < value))
151 backlight_ops.set_default_brt(tmp_value);
152 backlight_ops.update();
153 last_autobrightness = tmp_value;
155 _I("load light data:%d lux,auto brt %d,min brightness %d,"
156 "brightness %d", lux, automatic_brt, min_brightness, value);
161 static bool check_brightness_changed(int value)
164 static int values[MAX_SAMPLING_COUNT], count = 0;
166 if (count >= MAX_SAMPLING_COUNT || count < 0)
169 values[count++] = value;
171 for (i = 0; i < MAX_SAMPLING_COUNT - 1; i++)
172 if (values[i] != values[i+1])
177 static void set_brightness_direct(void)
180 sensor_data_t light_data;
182 if (pm_cur_state != S_NORMAL || !get_hallic_open())
185 /* direct update if it's previous value */
186 if (last_autobrightness > 0) {
187 backlight_ops.set_default_brt(last_autobrightness);
188 backlight_ops.update();
192 /* get lux value from light sensor */
193 ret = sf_get_data(light_handle, LIGHT_LUX_DATA_SET, &light_data);
194 if (ret < 0 || (int)light_data.values[0] < 0)
197 /* get brightness by lux */
198 cmd = DISP_FORCE_CMD(PROP_DISPLAY_BRIGHTNESS_BY_LUX, true);
199 cmd = DISP_CMD(cmd, (int)light_data.values[0]);
200 ret = device_get_property(DEVICE_TYPE_DISPLAY, cmd, value_table);
204 /* get auto brightness level from value table*/
205 value = (ISVALID_AUTOMATIC_INDEX(automatic_brt) ?
206 value_table[automatic_brt] : value_table[DEFAULT_AUTOMATIC_BRT]);
208 /* update brightness actually */
209 backlight_ops.set_default_brt(value);
210 backlight_ops.update();
211 last_autobrightness = value;
214 static bool check_hbm(int lux)
216 int ret, old_state, new_state;
218 ret = device_get_property(DEVICE_TYPE_DISPLAY,
219 PROP_DISPLAY_HBM_CONTROL, &old_state);
221 _E("Failed to get HBM state!");
226 new_state = (lux <= MAX_NORMAL_LUX ? 0 : 1);
228 new_state = (lux >= display_conf.hbm_lux_threshold ? 1 : 0);
230 if (old_state != new_state) {
231 _D("hbm is %s", (new_state ? "on" : "off"));
232 ret = device_set_property(DEVICE_TYPE_DISPLAY,
233 PROP_DISPLAY_HBM_CONTROL, new_state);
235 _E("Failed to set HBM state!");
237 * Brightness is changed directly
238 * when hbm state is changed from on to off
241 set_brightness_direct();
244 return (new_state ? true : false);
247 static bool alc_update_brt(bool setting)
253 sensor_data_t light_data;
255 ret = sf_get_data(light_handle, LIGHT_LUX_DATA_SET, &light_data);
256 if (ret < 0 || (int)light_data.values[0] < 0) {
259 int force = (setting ? 1 : 0);
260 cmd = DISP_FORCE_CMD(PROP_DISPLAY_BRIGHTNESS_BY_LUX, force);
261 cmd = DISP_CMD(cmd, (int)light_data.values[0]);
262 ret = device_get_property(DEVICE_TYPE_DISPLAY, cmd, value_table);
264 value = (ISVALID_AUTOMATIC_INDEX(automatic_brt) ?
265 value_table[automatic_brt] : value_table[DEFAULT_AUTOMATIC_BRT]);
267 if (ret < 0 || value < PM_MIN_BRIGHTNESS ||
268 value > PM_MAX_BRIGHTNESS) {
269 _E("fail to load light data : %d lux, %d",
270 (int)light_data.values[0], value);
275 /* Check HBM (High Brightness Mode) */
276 if (check_hbm((int)light_data.values[0]))
279 if (!check_brightness_changed(value) && !setting)
282 alc_set_brightness(setting, value, (int)light_data.values[0]);
286 if ((fault_count > MAX_FAULT) && !(pm_status_flag & PWROFF_FLAG)) {
287 if (alc_timeout_id > 0)
288 ecore_timer_del(alc_timeout_id);
289 alc_timeout_id = NULL;
290 vconf_set_int(VCONFKEY_SETAPPL_BRIGHTNESS_AUTOMATIC_INT,
291 SETTING_BRIGHTNESS_AUTOMATIC_OFF);
292 _E("Fault counts is over %d, disable automatic brightness",
299 static bool alc_handler(void* data)
301 if (pm_cur_state != S_NORMAL || !get_hallic_open()){
302 if (alc_timeout_id > 0)
303 ecore_timer_del(alc_timeout_id);
304 alc_timeout_id = NULL;
308 if (alc_update_brt(false) == EINA_FALSE)
311 if (alc_timeout_id != 0)
317 static int alc_action(int timeout)
319 /* sampling timer add */
320 if (alc_timeout_id == 0 && !(pm_status_flag & PWRSV_FLAG)) {
321 display_info.update_auto_brightness(true);
324 ecore_timer_add(display_conf.lightsensor_interval,
325 (Ecore_Task_Cb)alc_handler, NULL);
328 if (_default_action != NULL)
329 return _default_action(timeout);
331 /* unreachable code */
335 static int connect_sfsvc(void)
339 _I("connect with sensor fw");
341 light_handle = sf_connect(LIGHT_SENSOR);
342 if (light_handle < 0) {
343 _E("light sensor attach fail");
346 sf_state = sf_start(light_handle, 0);
348 _E("light sensor attach fail");
349 sf_disconnect(light_handle);
353 /* accelerometer sensor */
354 accel_handle = sf_connect(ACCELEROMETER_SENSOR);
355 if (accel_handle < 0) {
356 _E("accelerometer sensor attach fail");
359 sf_state = sf_start(accel_handle, 0);
361 _E("accelerometer sensor attach fail");
362 sf_disconnect(accel_handle);
371 if (light_handle >= 0) {
372 sf_stop(light_handle);
373 sf_disconnect(light_handle);
376 if (accel_handle >= 0) {
377 sf_stop(accel_handle);
378 sf_disconnect(accel_handle);
384 static int disconnect_sfsvc(void)
386 _I("disconnect with sensor fw");
388 if(light_handle >= 0) {
389 sf_stop(light_handle);
390 sf_disconnect(light_handle);
393 /* accelerometer sensor*/
394 if(accel_handle >= 0) {
395 sf_stop(accel_handle);
396 sf_disconnect(accel_handle);
400 if (_default_action != NULL) {
401 states[S_NORMAL].action = _default_action;
402 _default_action = NULL;
404 if (alc_timeout_id > 0) {
405 ecore_timer_del(alc_timeout_id);
406 alc_timeout_id = NULL;
412 static inline void set_brtch_state(void)
414 if (pm_status_flag & PWRSV_FLAG) {
415 pm_status_flag |= BRTCH_FLAG;
416 vconf_set_bool(VCONFKEY_PM_BRIGHTNESS_CHANGED_IN_LPM, true);
417 _D("brightness changed in low battery,"
418 "escape dim state (light)");
422 static int set_autobrightness_state(int status)
426 int default_brt = -1;
429 if (status == SETTING_BRIGHTNESS_AUTOMATIC_ON) {
430 if(connect_sfsvc() < 0)
433 /* escape dim state if it's in low battery.*/
436 /* change alc action func */
437 if (_default_action == NULL)
438 _default_action = states[S_NORMAL].action;
439 states[S_NORMAL].action = alc_action;
441 set_brightness_direct();
443 ecore_timer_add(display_conf.lightsensor_interval,
444 (Ecore_Task_Cb)alc_handler, NULL);
445 } else if (status == SETTING_BRIGHTNESS_AUTOMATIC_PAUSE) {
446 _I("auto brightness paused!");
448 backlight_ops.hbm_off();
451 backlight_ops.hbm_off();
452 /* escape dim state if it's in low battery.*/
455 ret = get_setting_brightness(&default_brt);
456 if (ret != 0 || (default_brt < PM_MIN_BRIGHTNESS || default_brt > PM_MAX_BRIGHTNESS)) {
457 _I("fail to read vconf value for brightness");
458 brt = PM_DEFAULT_BRIGHTNESS;
459 if(default_brt < PM_MIN_BRIGHTNESS || default_brt > PM_MAX_BRIGHTNESS)
460 vconf_set_int(VCONFKEY_SETAPPL_LCD_BRIGHTNESS, brt);
464 backlight_ops.set_default_brt(default_brt);
465 backlight_ops.update();
471 static void set_alc_function(keynode_t *key_nodes, void *data)
475 if (key_nodes == NULL) {
476 _E("wrong parameter, key_nodes is null");
480 status = vconf_keynode_get_int(key_nodes);
483 case SETTING_BRIGHTNESS_AUTOMATIC_OFF:
484 case SETTING_BRIGHTNESS_AUTOMATIC_ON:
485 case SETTING_BRIGHTNESS_AUTOMATIC_PAUSE:
486 ret = set_autobrightness_state(status);
487 _D("set auto brightness : %d", ret);
490 _E("invalid value! %d", status);
494 static bool check_sfsvc(void* data)
496 /* this function will return opposite value for re-callback in fail */
500 _I("register sfsvc");
502 vconf_get_int(VCONFKEY_SETAPPL_BRIGHTNESS_AUTOMATIC_INT, &vconf_auto);
503 if (vconf_auto == SETTING_BRIGHTNESS_AUTOMATIC_ON) {
504 if(connect_sfsvc() < 0)
507 /* change alc action func */
508 if (_default_action == NULL)
509 _default_action = states[S_NORMAL].action;
510 states[S_NORMAL].action = alc_action;
512 ecore_timer_add(display_conf.lightsensor_interval,
513 (Ecore_Task_Cb)alc_handler, NULL);
514 if (alc_timeout_id > 0)
519 _I("change vconf value before registering sfsvc");
523 static void set_alc_automatic_brt(keynode_t *key_nodes, void *data)
525 if (key_nodes == NULL) {
526 _E("wrong parameter, key_nodes is null");
529 automatic_brt = vconf_keynode_get_int(key_nodes) / AUTOMATIC_DEVIDE_VAL;
530 _D("automatic brt : %d", automatic_brt);
532 alc_update_brt(true);
535 static Eina_Bool update_handler(void* data)
539 update_timeout = NULL;
541 if (pm_cur_state != S_NORMAL)
544 if (!get_hallic_open())
547 ret = vconf_get_int(VCONFKEY_SETAPPL_BRIGHTNESS_AUTOMATIC_INT, &on);
548 if (ret < 0 || on != SETTING_BRIGHTNESS_AUTOMATIC_ON)
551 _D("auto brightness is working!");
553 sf_change_sensor_option(light_handle, 1);
554 alc_update_brt(true);
555 sf_change_sensor_option(light_handle, 0);
560 static void update_auto_brightness(bool update)
562 if (update_timeout) {
563 ecore_timer_del(update_timeout);
564 update_timeout = NULL;
568 update_timeout = ecore_timer_add(AUTOMATIC_DELAY_TIME,
569 update_handler, NULL);
573 static int prepare_lsensor(void *data)
579 ret = vconf_get_int(VCONFKEY_SETAPPL_BRIGHTNESS_AUTOMATIC_INT, &status);
581 if (ret == 0 && status == SETTING_BRIGHTNESS_AUTOMATIC_ON)
582 set_autobrightness_state(status);
584 /* add auto_brt_setting change handler */
585 vconf_notify_key_changed(VCONFKEY_SETAPPL_BRIGHTNESS_AUTOMATIC_INT,
586 set_alc_function, NULL);
588 vconf_get_int(VCONFKEY_SETAPPL_LCD_AUTOMATIC_BRIGHTNESS, &brt);
589 if (brt < PM_MIN_BRIGHTNESS || brt > PM_MAX_BRIGHTNESS) {
590 _E("Failed to get automatic brightness!");
592 automatic_brt = brt / AUTOMATIC_DEVIDE_VAL;
593 _I("automatic brt init success %d", automatic_brt);
596 vconf_notify_key_changed(VCONFKEY_SETAPPL_LCD_AUTOMATIC_BRIGHTNESS,
597 set_alc_automatic_brt, NULL);
602 static inline void update_brightness_direct(void)
606 ret = vconf_get_int(VCONFKEY_SETAPPL_BRIGHTNESS_AUTOMATIC_INT, &status);
607 if (ret == 0 && status == SETTING_BRIGHTNESS_AUTOMATIC_ON)
608 alc_update_brt(true);
611 static int set_autobrightness_min(int val, char *name)
616 if (val < PM_MIN_BRIGHTNESS || val > PM_MAX_BRIGHTNESS)
619 min_brightness = val;
621 if (min_brightness_name) {
622 free(min_brightness_name);
623 min_brightness_name = 0;
625 min_brightness_name = strndup(name, strlen(name));
627 update_brightness_direct();
629 _I("auto brightness min value changed! (%d, %s)",
630 min_brightness, min_brightness_name);
635 static int reset_autobrightness_min(char *name, enum watch_id id)
640 if (!min_brightness_name)
643 if (strcmp(name, min_brightness_name))
646 _I("change to default %d -> %d, %s", min_brightness,
647 PM_MIN_BRIGHTNESS, min_brightness_name);
648 min_brightness = PM_MIN_BRIGHTNESS;
649 if (min_brightness_name) {
650 free(min_brightness_name);
651 min_brightness_name = 0;
654 update_brightness_direct();
659 static void auto_brightness_init(void *data)
661 display_info.update_auto_brightness = update_auto_brightness;
662 display_info.set_autobrightness_min = set_autobrightness_min;
663 display_info.reset_autobrightness_min = reset_autobrightness_min;
665 prepare_lsensor(NULL);
668 static void auto_brightness_exit(void *data)
670 vconf_ignore_key_changed(VCONFKEY_SETAPPL_BRIGHTNESS_AUTOMATIC_INT,
673 vconf_ignore_key_changed(VCONFKEY_SETAPPL_LCD_AUTOMATIC_BRIGHTNESS,
674 set_alc_automatic_brt);
676 set_autobrightness_state(SETTING_BRIGHTNESS_AUTOMATIC_OFF);
679 static const struct display_ops display_autobrightness_ops = {
680 .name = "auto-brightness",
681 .init = auto_brightness_init,
682 .exit = auto_brightness_exit,
685 DISPLAY_OPS_REGISTER(&display_autobrightness_ops)