blob: 6c6ffa8881c41357c354e839abb35e88f4354c49 [file] [log] [blame]
// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
/*
* Copyright (c) 2019 Amlogic, Inc. All rights reserved.
*/
#include <common.h>
#include <malloc.h>
#include <dm.h>
#include <asm/gpio.h>
#include <fdtdec.h>
#include <amlogic/media/vout/lcd/aml_lcd.h>
#ifdef CONFIG_AML_LOCAL_DIMMING
#include <amlogic/media/vout/lcd/bl_ldim.h>
#endif
#ifdef CONFIG_AML_BL_EXTERN
#include <amlogic/media/vout/lcd/bl_extern.h>
#endif
#include "lcd_bl.h"
#include "../lcd_reg.h"
#include "../lcd_common.h"
#include "../lcd_unifykey.h"
static int bl_index_lut[LCD_MAX_DRV];
static struct aml_bl_drv_s *bl_driver[LCD_MAX_DRV];
struct aml_bl_drv_s *aml_bl_get_driver(int index)
{
if (index >= LCD_MAX_DRV)
return NULL;
if (!bl_driver[index])
return NULL;
if (bl_driver[index]->config.method >= BL_CTRL_MAX)
return NULL;
return bl_driver[index];
}
static struct bl_config_s *bl_check_valid(struct aml_bl_drv_s *bdrv)
{
struct bl_config_s *bconf;
unsigned int bconf_flag = 1;
#ifdef CONFIG_AML_BL_EXTERN
struct aml_bl_extern_driver_s *bl_ext;
#endif
#ifdef CONFIG_AML_LOCAL_DIMMING
struct ldim_driver_s *ldim_drv;
#endif
if (!bdrv)
return NULL;
bconf = &bdrv->config;
switch (bconf->method) {
case BL_CTRL_PWM:
if (!bconf->bl_pwm) {
BLERR("no bl_pwm struct\n");
bconf_flag = 0;
}
break;
case BL_CTRL_PWM_COMBO:
if (!bconf->bl_pwm_combo0) {
BLERR("no bl_pwm_combo_0 struct\n");
bconf_flag = 0;
}
if (!bconf->bl_pwm_combo1) {
BLERR("no bl_pwm_combo_1 struct\n");
bconf_flag = 0;
}
break;
case BL_CTRL_GPIO:
break;
#ifdef CONFIG_AML_LOCAL_DIMMING
case BL_CTRL_LOCAL_DIMMING:
ldim_drv = ldim_get_driver();
if (!ldim_drv) {
BLERR("no ldim driver\n");
bconf = NULL;
}
break;
#endif
#ifdef CONFIG_AML_BL_EXTERN
case BL_CTRL_EXTERN:
bl_ext = aml_bl_extern_get_driver();
if (!bl_ext) {
BLERR("no bl_extern driver\n");
bconf_flag = 0;
}
break;
#endif
default:
if (lcd_debug_print_flag & LCD_DBG_PR_BL_NORMAL)
BLPR("invalid control_method: %d\n", bconf->method);
bconf_flag = 0;
break;
}
if (!bconf_flag)
bconf = NULL;
return bconf;
}
static void bl_pwm_pinmux_gpio_set(struct aml_bl_drv_s *bdrv, int pwm_index, int gpio_level)
{
struct bl_config_s *bconf;
struct bl_pwm_config_s *bl_pwm = NULL;
int gpio;
char *str;
int i;
bconf = bl_check_valid(bdrv);
if (!bconf)
return;
switch (bconf->method) {
case BL_CTRL_PWM:
bl_pwm = bconf->bl_pwm;
break;
case BL_CTRL_PWM_COMBO:
if (pwm_index == 0)
bl_pwm = bconf->bl_pwm_combo0;
else
bl_pwm = bconf->bl_pwm_combo1;
break;
default:
BLERR("%s: invalid method %d\n", __func__, bconf->method);
break;
}
if (!bl_pwm)
return;
if (lcd_debug_print_flag & LCD_DBG_PR_BL_NORMAL) {
BLPR("%s: pwm_port=0x%x, pinmux_flag=%d\n",
__func__, bl_pwm->pwm_port, bl_pwm->pinmux_flag);
}
if (bl_pwm->pinmux_flag > 0) {
i = 0;
while (i < LCD_PINMUX_NUM) {
if (bl_pwm->pinmux_set[i][0] == LCD_PINMUX_END)
break;
lcd_pinmux_clr_mask(bl_pwm->pinmux_set[i][0],
bl_pwm->pinmux_set[i][1]);
if (lcd_debug_print_flag & LCD_DBG_PR_BL_NORMAL) {
BLPR("%s: port=0x%x, pinmux_clr=%d,0x%08x\n",
__func__, bl_pwm->pwm_port,
bl_pwm->pinmux_set[i][0], bl_pwm->pinmux_set[i][1]);
}
i++;
}
bl_pwm->pinmux_flag = 0;
}
/* set gpio */
if (bl_pwm->pwm_gpio >= BL_GPIO_NUM_MAX) {
gpio = LCD_GPIO_MAX;
} else {
str = bconf->gpio_name[bl_pwm->pwm_gpio];
gpio = lcd_gpio_name_map_num(str);
}
if (gpio < LCD_GPIO_MAX)
lcd_gpio_set(gpio, gpio_level);
}
static void bl_pwm_pinmux_gpio_clr(struct aml_bl_drv_s *bdrv, unsigned int pwm_index)
{
struct bl_config_s *bconf;
struct bl_pwm_config_s *bl_pwm = NULL;
int i;
bconf = bl_check_valid(bdrv);
if (!bconf)
return;
switch (bconf->method) {
case BL_CTRL_PWM:
bl_pwm = bconf->bl_pwm;
break;
case BL_CTRL_PWM_COMBO:
if (pwm_index == 0)
bl_pwm = bconf->bl_pwm_combo0;
else
bl_pwm = bconf->bl_pwm_combo1;
break;
default:
BLERR("%s: invalid method %d\n", __func__, bconf->method);
break;
}
if (!bl_pwm)
return;
if (lcd_debug_print_flag & LCD_DBG_PR_BL_NORMAL) {
BLPR("%s: pwm_port=0x%x, pinmux_flag=%d\n",
__func__, bl_pwm->pwm_port, bl_pwm->pinmux_flag);
}
if (bl_pwm->pinmux_flag > 0)
return;
/* set pinmux */
i = 0;
while (i < LCD_PINMUX_NUM) {
if (bl_pwm->pinmux_set[i][0] == LCD_PINMUX_END)
break;
lcd_pinmux_set_mask(bl_pwm->pinmux_set[i][0],
bl_pwm->pinmux_set[i][1]);
if (lcd_debug_print_flag & LCD_DBG_PR_BL_NORMAL) {
BLPR("%s: port=0x%x, pinmux_set=%d,0x%08x\n",
__func__, bl_pwm->pwm_port,
bl_pwm->pinmux_set[i][0], bl_pwm->pinmux_set[i][1]);
}
i++;
}
bl_pwm->pinmux_flag = 1;
}
void bl_set_pwm_gpio_check(struct aml_bl_drv_s *bdrv, struct bl_pwm_config_s *bl_pwm)
{
unsigned int pwm_index, gpio_level;
pwm_index = bl_pwm->index;
/* pwm duty 100% or 0% special control */
if (bl_pwm->pwm_duty_max > 100) {
if (bl_pwm->pwm_duty == 0 || bl_pwm->pwm_duty == 255) {
switch (bl_pwm->pwm_method) {
case BL_PWM_POSITIVE:
if (bl_pwm->pwm_duty == 0)
gpio_level = 0;
else
gpio_level = 1;
break;
case BL_PWM_NEGATIVE:
if (bl_pwm->pwm_duty == 0)
gpio_level = 1;
else
gpio_level = 0;
break;
default:
BLERR("%s: port=0x%x: invalid pwm_method %d\n",
__func__, bl_pwm->pwm_port,
bl_pwm->pwm_method);
gpio_level = 0;
break;
}
if (lcd_debug_print_flag & LCD_DBG_PR_BL_NORMAL) {
BLPR("%s: pwm port=0x%x, duty=%d%%, switch to gpio %d\n",
__func__, bl_pwm->pwm_port,
bl_pwm->pwm_duty * 100 / 255, gpio_level);
}
bl_pwm_pinmux_gpio_set(bdrv, pwm_index, gpio_level);
} else {
if (lcd_debug_print_flag & LCD_DBG_PR_BL_NORMAL) {
BLPR("%s: pwm_port=0x%x set as pwm\n",
__func__, bl_pwm->pwm_port);
}
bl_pwm_pinmux_gpio_clr(bdrv, pwm_index);
}
} else {
if (bl_pwm->pwm_duty == 0 || bl_pwm->pwm_duty == 100) {
switch (bl_pwm->pwm_method) {
case BL_PWM_POSITIVE:
if (bl_pwm->pwm_duty == 0)
gpio_level = 0;
else
gpio_level = 1;
break;
case BL_PWM_NEGATIVE:
if (bl_pwm->pwm_duty == 0)
gpio_level = 1;
else
gpio_level = 0;
break;
default:
BLERR("%s: port=0x%x: invalid pwm_method %d\n",
__func__, bl_pwm->pwm_port, bl_pwm->pwm_method);
gpio_level = 0;
break;
}
if (lcd_debug_print_flag & LCD_DBG_PR_BL_NORMAL) {
BLPR("%s: pwm port=0x%x, duty=%d%%, switch to gpio %d\n",
__func__, bl_pwm->pwm_port, bl_pwm->pwm_duty,
gpio_level);
}
bl_pwm_pinmux_gpio_set(bdrv, pwm_index, gpio_level);
} else {
if (lcd_debug_print_flag & LCD_DBG_PR_BL_NORMAL) {
BLPR("%s: pwm_port=0x%x set as pwm\n",
__func__, bl_pwm->pwm_port);
}
bl_pwm_pinmux_gpio_clr(bdrv, pwm_index);
}
}
}
static void bl_pwm_pinmux_ctrl(struct aml_bl_drv_s *bdrv, int status)
{
struct bl_config_s *bconf = &bdrv->config;
int gpio;
char *str;
int i;
if (lcd_debug_print_flag & LCD_DBG_PR_BL_NORMAL)
BLPR("%s: %d\n", __func__, status);
if (status) {
/* set pinmux */
switch (bconf->method) {
case BL_CTRL_PWM:
bl_set_pwm_gpio_check(bdrv, bconf->bl_pwm);
break;
case BL_CTRL_PWM_COMBO:
bl_set_pwm_gpio_check(bdrv, bconf->bl_pwm_combo0);
bl_set_pwm_gpio_check(bdrv, bconf->bl_pwm_combo1);
break;
default:
break;
}
} else {
switch (bconf->method) {
case BL_CTRL_PWM:
i = 0;
while (i < LCD_PINMUX_NUM) {
if (bconf->bl_pwm->pinmux_set[i][0] == LCD_PINMUX_END)
break;
lcd_pinmux_clr_mask(bconf->bl_pwm->pinmux_set[i][0],
bconf->bl_pwm->pinmux_set[i][1]);
if (lcd_debug_print_flag & LCD_DBG_PR_BL_NORMAL) {
BLPR("%s: port=0x%x, pinmux_clr=%d,0x%08x\n",
__func__, bconf->bl_pwm->pwm_port,
bconf->bl_pwm->pinmux_set[i][0],
bconf->bl_pwm->pinmux_set[i][1]);
}
i++;
}
bconf->bl_pwm->pinmux_flag = 0;
if (bconf->bl_pwm->pwm_gpio >= BL_GPIO_NUM_MAX) {
gpio = LCD_GPIO_MAX;
} else {
str = bconf->gpio_name[bconf->bl_pwm->pwm_gpio];
gpio = lcd_gpio_name_map_num(str);
}
if (gpio < LCD_GPIO_MAX)
lcd_gpio_set(gpio, bconf->bl_pwm->pwm_gpio_off);
break;
case BL_CTRL_PWM_COMBO:
i = 0;
while (i < LCD_PINMUX_NUM) {
if (bconf->bl_pwm_combo0->pinmux_set[i][0] == LCD_PINMUX_END)
break;
lcd_pinmux_clr_mask(bconf->bl_pwm_combo0->pinmux_set[i][0],
bconf->bl_pwm_combo0->pinmux_set[i][1]);
if (lcd_debug_print_flag & LCD_DBG_PR_BL_NORMAL) {
BLPR("%s: port=0x%x, pinmux_clr=%d,0x%08x\n",
__func__, bconf->bl_pwm_combo0->pwm_port,
bconf->bl_pwm_combo0->pinmux_set[i][0],
bconf->bl_pwm_combo0->pinmux_set[i][1]);
}
i++;
}
i = 0;
while (i < LCD_PINMUX_NUM) {
if (bconf->bl_pwm_combo1->pinmux_set[i][0] == LCD_PINMUX_END)
break;
lcd_pinmux_clr_mask(bconf->bl_pwm_combo1->pinmux_set[i][0],
bconf->bl_pwm_combo1->pinmux_set[i][1]);
if (lcd_debug_print_flag & LCD_DBG_PR_BL_NORMAL) {
BLPR("%s: port=0x%x, pinmux_clr=%d,0x%08x\n",
__func__, bconf->bl_pwm_combo1->pwm_port,
bconf->bl_pwm_combo1->pinmux_set[i][0],
bconf->bl_pwm_combo1->pinmux_set[i][1]);
}
i++;
}
bconf->bl_pwm_combo0->pinmux_flag = 0;
bconf->bl_pwm_combo1->pinmux_flag = 0;
if (bconf->bl_pwm_combo0->pwm_gpio >= BL_GPIO_NUM_MAX) {
gpio = LCD_GPIO_MAX;
} else {
str = bconf->gpio_name[bconf->bl_pwm_combo0->pwm_gpio];
gpio = lcd_gpio_name_map_num(str);
}
if (gpio < LCD_GPIO_MAX)
lcd_gpio_set(gpio, bconf->bl_pwm_combo0->pwm_gpio_off);
if (bconf->bl_pwm_combo1->pwm_gpio >= BL_GPIO_NUM_MAX) {
gpio = LCD_GPIO_MAX;
} else {
str = bconf->gpio_name[bconf->bl_pwm_combo1->pwm_gpio];
gpio = lcd_gpio_name_map_num(str);
}
if (gpio < LCD_GPIO_MAX)
lcd_gpio_set(gpio, bconf->bl_pwm_combo1->pwm_gpio_off);
break;
default:
break;
}
}
}
static void bl_pwm_config_update(struct bl_config_s *bconf)
{
#ifdef CONFIG_AML_LOCAL_DIMMING
struct ldim_driver_s *ldim_drv;
#endif
if (!bconf) {
BLERR("bconf is null\n");
return;
}
switch (bconf->method) {
case BL_CTRL_PWM:
bl_pwm_config_init(bconf->bl_pwm);
break;
case BL_CTRL_PWM_COMBO:
bl_pwm_config_init(bconf->bl_pwm_combo0);
bl_pwm_config_init(bconf->bl_pwm_combo1);
break;
#ifdef CONFIG_AML_LOCAL_DIMMING
case BL_CTRL_LOCAL_DIMMING:
ldim_drv = ldim_get_driver();
if (!ldim_drv) {
BLERR("ldim_drv is null\n");
break;
}
if (ldim_drv->ldev_conf) {
BLERR("ldim_config is null\n");
break;
}
if (ldim_drv->ldev_conf->ldim_pwm_config.pwm_port >= BL_PWM_MAX)
break;
bl_pwm_config_init(&ldim_drv->ldev_conf->ldim_pwm_config);
if (ldim_drv->ldev_conf->analog_pwm_config.pwm_port < BL_PWM_VS)
bl_pwm_config_init(&ldim_drv->ldev_conf->analog_pwm_config);
break;
#endif
default:
break;
}
}
static void bl_set_level(struct aml_bl_drv_s *bdrv, unsigned int level)
{
struct bl_config_s *bconf;
struct bl_pwm_config_s *pwm0, *pwm1;
#ifdef CONFIG_AML_BL_EXTERN
struct aml_bl_extern_driver_s *bl_ext;
#endif
#ifdef CONFIG_AML_LOCAL_DIMMING
struct ldim_driver_s *ldim_drv;
#endif
bconf = bl_check_valid(bdrv);
if (!bconf)
return;
BLPR("set level: %u, last level: %u\n", level, bdrv->level);
/* level range check */
level = (level > bconf->level_max ? bconf->level_max :
(level < bconf->level_min ? bconf->level_min : level));
bdrv->level = level;
switch (bconf->method) {
case BL_CTRL_GPIO:
break;
case BL_CTRL_PWM:
bl_pwm_set_level(bdrv, bconf->bl_pwm, level);
break;
case BL_CTRL_PWM_COMBO:
pwm0 = bconf->bl_pwm_combo0;
pwm1 = bconf->bl_pwm_combo1;
if (level >= pwm0->level_max) {
bl_pwm_set_level(bdrv, pwm0, pwm0->level_max);
} else if ((level > pwm0->level_min) &&
(level < pwm0->level_max)) {
if (lcd_debug_print_flag & LCD_DBG_PR_BL_NORMAL)
BLPR("pwm0 region, level=%u\n", level);
bl_pwm_set_level(bdrv, pwm0, level);
} else {
bl_pwm_set_level(bdrv, pwm0, pwm0->level_min);
}
if (level >= pwm1->level_max) {
bl_pwm_set_level(bdrv, pwm1, pwm1->level_max);
} else if ((level > pwm1->level_min) &&
(level < pwm1->level_max)) {
if (lcd_debug_print_flag & LCD_DBG_PR_BL_NORMAL)
BLPR("pwm1 region, level=%u\n", level);
bl_pwm_set_level(bdrv, pwm1, level);
} else {
bl_pwm_set_level(bdrv, pwm1, pwm1->level_min);
}
break;
#ifdef CONFIG_AML_LOCAL_DIMMING
case BL_CTRL_LOCAL_DIMMING:
ldim_drv = ldim_get_driver();
if (ldim_drv->set_level)
ldim_drv->set_level(level);
else
BLERR("ldim set_level is null\n");
break;
#endif
#ifdef CONFIG_AML_BL_EXTERN
case BL_CTRL_EXTERN:
bl_ext = aml_bl_extern_get_driver();
if (bl_ext->set_level)
bl_ext->set_level(level);
else
BLERR("bl_extern set_level is null\n");
break;
#endif
default:
if (lcd_debug_print_flag & LCD_DBG_PR_BL_NORMAL)
BLERR("wrong backlight control method\n");
break;
}
}
static void bl_power_en_ctrl(struct bl_config_s *bconf, int status)
{
int gpio;
char *str;
if (bconf->en_gpio >= BL_GPIO_NUM_MAX) {
gpio = LCD_GPIO_MAX;
} else {
str = bconf->gpio_name[bconf->en_gpio];
gpio = lcd_gpio_name_map_num(str);
}
if (status) {
if (gpio < LCD_GPIO_MAX)
lcd_gpio_set(gpio, bconf->en_gpio_on);
} else {
if (gpio < LCD_GPIO_MAX)
lcd_gpio_set(gpio, bconf->en_gpio_off);
}
}
static void bl_power_ctrl(struct aml_bl_drv_s *bdrv, int status)
{
int gpio, value;
struct bl_config_s *bconf;
#ifdef CONFIG_AML_BL_EXTERN
struct aml_bl_extern_driver_s *bl_ext;
#endif
#ifdef CONFIG_AML_LOCAL_DIMMING
struct ldim_driver_s *ldim_drv;
#endif
bconf = bl_check_valid(bdrv);
if (!bconf)
return;
gpio = bconf->en_gpio;
value = status ? bconf->en_gpio_on : bconf->en_gpio_off;
if (lcd_debug_print_flag & LCD_DBG_PR_BL_NORMAL)
BLPR("status=%d gpio=%d value=%d\n", status, gpio, value);
if (status) {
/* bl_off_policy */
if (bdrv->bl_off_policy != BL_OFF_POLICY_NONE) {
BLPR("bl_off_policy=%d for bl_off\n", bdrv->bl_off_policy);
return;
}
bdrv->state = 1;
/* check if factory test */
if (bdrv->factory_bl_on_delay >= 0) {
BLPR("%s: factory test power_on_delay!\n", __func__);
if (bdrv->factory_bl_on_delay > 0)
mdelay(bdrv->factory_bl_on_delay);
} else {
if (bconf->power_on_delay > 0)
mdelay(bconf->power_on_delay);
}
switch (bconf->method) {
case BL_CTRL_GPIO:
bl_power_en_ctrl(bconf, 1);
break;
case BL_CTRL_PWM:
if (bconf->en_sequence_reverse) {
/* step 1: power on enable */
bl_power_en_ctrl(bconf, 1);
if (bconf->pwm_on_delay > 0)
mdelay(bconf->pwm_on_delay);
/* step 2: power on pwm */
bl_pwm_en(bconf->bl_pwm, 1);
bl_pwm_pinmux_ctrl(bdrv, 1);
} else {
/* step 1: power on pwm */
bl_pwm_en(bconf->bl_pwm, 1);
bl_pwm_pinmux_ctrl(bdrv, 1);
if (bconf->pwm_on_delay > 0)
mdelay(bconf->pwm_on_delay);
/* step 2: power on enable */
bl_power_en_ctrl(bconf, 1);
}
break;
case BL_CTRL_PWM_COMBO:
if (bconf->en_sequence_reverse) {
/* step 1: power on enable */
bl_power_en_ctrl(bconf, 1);
if (bconf->pwm_on_delay > 0)
mdelay(bconf->pwm_on_delay);
/* step 2: power on pwm_combo */
bl_pwm_en(bconf->bl_pwm_combo0, 1);
bl_pwm_en(bconf->bl_pwm_combo1, 1);
bl_pwm_pinmux_ctrl(bdrv, 1);
} else {
/* step 1: power on pwm_combo */
bl_pwm_en(bconf->bl_pwm_combo0, 1);
bl_pwm_en(bconf->bl_pwm_combo1, 1);
bl_pwm_pinmux_ctrl(bdrv, 1);
if (bconf->pwm_on_delay > 0)
mdelay(bconf->pwm_on_delay);
/* step 2: power on enable */
bl_power_en_ctrl(bconf, 1);
}
break;
#ifdef CONFIG_AML_LOCAL_DIMMING
case BL_CTRL_LOCAL_DIMMING:
ldim_drv = ldim_get_driver();
if (bconf->en_sequence_reverse) {
/* step 1: power on enable */
bl_power_en_ctrl(bconf, 1);
/* step 2: power on ldim */
if (ldim_drv->power_on)
ldim_drv->power_on();
else
BLERR("ldim power on is null\n");
} else {
/* step 1: power on ldim */
if (ldim_drv->power_on)
ldim_drv->power_on();
else
BLERR("ldim power on is null\n");
/* step 2: power on enable */
bl_power_en_ctrl(bconf, 1);
}
break;
#endif
#ifdef CONFIG_AML_BL_EXTERN
case BL_CTRL_EXTERN:
bl_ext = aml_bl_extern_get_driver();
if (bconf->en_sequence_reverse) {
/* step 1: power on enable */
bl_power_en_ctrl(bconf, 1);
/* step 2: power on bl_extern */
if (bl_ext->power_on)
bl_ext->power_on();
else
BLERR("bl_extern power on is null\n");
} else {
/* step 1: power on bl_extern */
if (bl_ext->power_on)
bl_ext->power_on();
else
BLERR("bl_extern power on is null\n");
/* step 2: power on enable */
bl_power_en_ctrl(bconf, 1);
}
break;
#endif
default:
if (lcd_debug_print_flag & LCD_DBG_PR_BL_NORMAL)
BLERR("wrong backlight control method\n");
break;
}
} else {
bdrv->state = 0;
switch (bconf->method) {
case BL_CTRL_GPIO:
bl_power_en_ctrl(bconf, 0);
break;
case BL_CTRL_PWM:
if (bconf->en_sequence_reverse == 1) {
/* step 1: power off pwm */
bl_pwm_pinmux_ctrl(bdrv, 0);
bl_pwm_en(bconf->bl_pwm, 0);
if (bconf->pwm_off_delay > 0)
mdelay(bconf->pwm_off_delay);
/* step 2: power off enable */
bl_power_en_ctrl(bconf, 0);
} else {
/* step 1: power off enable */
bl_power_en_ctrl(bconf, 0);
/* step 2: power off pwm */
if (bconf->pwm_off_delay > 0)
mdelay(bconf->pwm_off_delay);
bl_pwm_pinmux_ctrl(bdrv, 0);
bl_pwm_en(bconf->bl_pwm, 0);
}
break;
case BL_CTRL_PWM_COMBO:
if (bconf->en_sequence_reverse == 1) {
/* step 1: power off pwm_combo */
bl_pwm_pinmux_ctrl(bdrv, 0);
bl_pwm_en(bconf->bl_pwm_combo0, 0);
bl_pwm_en(bconf->bl_pwm_combo1, 0);
if (bconf->pwm_off_delay > 0)
mdelay(bconf->pwm_off_delay);
/* step 2: power off enable */
bl_power_en_ctrl(bconf, 0);
} else {
/* step 1: power off enable */
bl_power_en_ctrl(bconf, 0);
/* step 2: power off pwm_combo */
if (bconf->pwm_off_delay > 0)
mdelay(bconf->pwm_off_delay);
bl_pwm_pinmux_ctrl(bdrv, 0);
bl_pwm_en(bconf->bl_pwm_combo0, 0);
bl_pwm_en(bconf->bl_pwm_combo1, 0);
}
break;
#ifdef CONFIG_AML_LOCAL_DIMMING
case BL_CTRL_LOCAL_DIMMING:
ldim_drv = ldim_get_driver();
if (bconf->en_sequence_reverse == 1) {
/* step 1: power off ldim */
if (ldim_drv->power_off)
ldim_drv->power_off();
else
BLERR("ldim power off is null\n");
/* step 2: power off enable */
bl_power_en_ctrl(bconf, 0);
} else {
/* step 1: power off enable */
bl_power_en_ctrl(bconf, 0);
/* step 2: power off ldim */
if (ldim_drv->power_off)
ldim_drv->power_off();
else
BLERR("ldim power off is null\n");
}
break;
#endif
#ifdef CONFIG_AML_BL_EXTERN
case BL_CTRL_EXTERN:
bl_ext = aml_bl_extern_get_driver();
if (bconf->en_sequence_reverse == 1) {
/* step 1: power off bl_extern */
if (bl_ext->power_off)
bl_ext->power_off();
else
BLERR("bl_extern: power off is null\n");
/* step 2: power off enable */
bl_power_en_ctrl(bconf, 0);
} else {
/* step 1: power off enable */
bl_power_en_ctrl(bconf, 0);
/* step 2: power off bl_extern */
if (bl_ext->power_off)
bl_ext->power_off();
else
BLERR("bl_extern: power off is null\n");
}
break;
#endif
default:
if (lcd_debug_print_flag & LCD_DBG_PR_BL_NORMAL)
BLERR("wrong backlight control method\n");
break;
}
if (bconf->power_off_delay > 0)
mdelay(bconf->power_off_delay);
}
BLPR("%s: %d\n", __func__, status);
}
static void bl_power_init_off(struct aml_bl_drv_s *bdrv)
{
struct bl_config_s *bconf;
bconf = bl_check_valid(bdrv);
if (!bconf)
return;
if (lcd_debug_print_flag & LCD_DBG_PR_BL_NORMAL) {
BLPR("[%d]: init_off: gpio=%d value=%d\n",
bdrv->index,
bconf->en_gpio, bconf->en_gpio_off);
}
bdrv->state = 0;
switch (bconf->method) {
case BL_CTRL_PWM:
case BL_CTRL_PWM_COMBO:
bl_power_en_ctrl(bconf, 0);
bl_pwm_pinmux_ctrl(bdrv, 0);
break;
default:
bl_power_en_ctrl(bconf, 0);
break;
}
if (lcd_debug_print_flag & LCD_DBG_PR_BL_NORMAL)
BLPR("%s finish\n", __func__);
}
static void bl_config_print(struct aml_bl_drv_s *bdrv)
{
struct bl_config_s *bconf = &bdrv->config;
struct bl_pwm_config_s *bl_pwm;
#ifdef CONFIG_AML_LOCAL_DIMMING
struct ldim_driver_s *ldim_drv = ldim_get_driver();
#endif
#ifdef CONFIG_AML_BL_EXTERN
struct aml_bl_extern_driver_s *bl_extern = aml_bl_extern_get_driver();
#endif
BLPR("drv_index: %d\n", bdrv->index);
BLPR("key_valid: %d\n", bdrv->key_valid);
BLPR("state : 0x%x\n", bdrv->state);
BLPR("bl_off_policy: %d\n", bdrv->bl_off_policy);
BLPR("name: %s\n", bconf->name);
BLPR("method: %d\n", bconf->method);
BLPR("level_default = %d\n", bconf->level_default);
BLPR("level_min = %d\n", bconf->level_min);
BLPR("level_max = %d\n", bconf->level_max);
BLPR("level_mid = %d\n", bconf->level_mid);
BLPR("level_mid_mapping = %d\n", bconf->level_mid_mapping);
BLPR("en_gpio = %s(%d)\n",
bconf->gpio_name[bconf->en_gpio], bconf->en_gpio);
BLPR("en_gpio_on = %d\n", bconf->en_gpio_on);
BLPR("en_gpio_off = %d\n", bconf->en_gpio_off);
/* check if factory test */
if (bdrv->factory_bl_on_delay >= 0)
BLPR("factory test power_on_delay = %d\n", bdrv->factory_bl_on_delay);
else
BLPR("power_on_delay = %d\n", bconf->power_on_delay);
BLPR("power_off_delay = %d\n\n", bconf->power_off_delay);
switch (bconf->method) {
case BL_CTRL_PWM:
if (bconf->bl_pwm) {
bl_pwm = bconf->bl_pwm;
BLPR("pwm_index = %d\n", bl_pwm->index);
BLPR("pwm_method = %d\n", bl_pwm->pwm_method);
BLPR("pwm_port = 0x%x\n", bl_pwm->pwm_port);
if (bl_pwm->pwm_port == BL_PWM_VS) {
BLPR("pwm_freq = %d x vfreq\n", bl_pwm->pwm_freq);
BLPR("pwm_cnt = %u\n", bl_pwm->pwm_cnt);
if (bl_pwm->pwm_duty_max > 100) {
BLPR("pwm_duty = %d%%(%d)\n",
bl_pwm->pwm_duty * 100 / 255, bl_pwm->pwm_duty);
} else {
BLPR("pwm_duty = %d%%(%d)\n",
bl_pwm->pwm_duty, bl_pwm->pwm_duty);
}
BLPR("pwm_reg0 = 0x%08x\n", lcd_vcbus_read(VPU_VPU_PWM_V0));
BLPR("pwm_reg1 = 0x%08x\n", lcd_vcbus_read(VPU_VPU_PWM_V1));
BLPR("pwm_reg2 = 0x%08x\n", lcd_vcbus_read(VPU_VPU_PWM_V2));
BLPR("pwm_reg3 = 0x%08x\n", lcd_vcbus_read(VPU_VPU_PWM_V3));
} else {
BLPR("pwm_freq = %uHz\n", bl_pwm->pwm_freq);
BLPR("pwm_cnt = %u\n", bl_pwm->pwm_cnt);
BLPR("pwm_pre_div = %u\n", bl_pwm->pwm_pre_div);
if (bl_pwm->pwm_duty_max > 100) {
BLPR("pwm_duty = %d%%(%d)\n",
bl_pwm->pwm_duty * 100 / 255, bl_pwm->pwm_duty);
} else {
BLPR("pwm_duty = %d%%(%d)\n",
bl_pwm->pwm_duty, bl_pwm->pwm_duty);
}
bl_pwm_reg_print(bl_pwm);
}
BLPR("pwm_duty_max = %d\n", bl_pwm->pwm_duty_max);
BLPR("pwm_duty_min = %d\n", bl_pwm->pwm_duty_min);
BLPR("pwm_gpio = %s(%d)\n",
bconf->gpio_name[bl_pwm->pwm_gpio], bl_pwm->pwm_gpio);
BLPR("pwm_gpio_off = %d\n", bl_pwm->pwm_gpio_off);
}
BLPR("pwm_on_delay = %d\n", bconf->pwm_on_delay);
BLPR("pwm_off_delay = %d\n", bconf->pwm_off_delay);
BLPR("en_sequence_reverse = %d\n", bconf->en_sequence_reverse);
break;
case BL_CTRL_PWM_COMBO:
if (bconf->bl_pwm_combo0) {
bl_pwm = bconf->bl_pwm_combo0;
BLPR("pwm_combo0_index = %d\n", bl_pwm->index);
BLPR("pwm_combo0_method = %d\n", bl_pwm->pwm_method);
BLPR("pwm_combo0_port = 0x%x\n", bl_pwm->pwm_port);
if (bl_pwm->pwm_port == BL_PWM_VS) {
BLPR("pwm_combo0_freq = %d x vfreq\n", bl_pwm->pwm_freq);
BLPR("pwm_combo0_cnt = %u\n", bl_pwm->pwm_cnt);
if (bl_pwm->pwm_duty_max > 100)
BLPR("pwm_combo0_duty = %d%%(%d)\n",
bl_pwm->pwm_duty * 100 / 255, bl_pwm->pwm_duty);
else
BLPR("pwm_combo0_duty = %d%%(%d)\n",
bl_pwm->pwm_duty, bl_pwm->pwm_duty);
BLPR("pwm_combo0_reg0 = 0x%08x\n", lcd_vcbus_read(VPU_VPU_PWM_V0));
BLPR("pwm_combo0_reg1 = 0x%08x\n", lcd_vcbus_read(VPU_VPU_PWM_V1));
BLPR("pwm_combo0_reg2 = 0x%08x\n", lcd_vcbus_read(VPU_VPU_PWM_V2));
BLPR("pwm_combo0_reg3 = 0x%08x\n", lcd_vcbus_read(VPU_VPU_PWM_V3));
} else {
BLPR("pwm_combo0_freq = %uHz\n", bl_pwm->pwm_freq);
BLPR("pwm_combo0_cnt = %u\n", bl_pwm->pwm_cnt);
BLPR("pwm_combo0_pre_div = %u\n", bl_pwm->pwm_pre_div);
if (bl_pwm->pwm_duty_max > 100)
BLPR("pwm_combo0_duty = %d%%(%d)\n",
bl_pwm->pwm_duty * 100 / 255, bl_pwm->pwm_duty);
else
BLPR("pwm_combo0_duty = %d%%(%d)\n",
bl_pwm->pwm_duty, bl_pwm->pwm_duty);
bl_pwm_reg_print(bl_pwm);
}
BLPR("pwm_combo0_duty_max = %d\n", bl_pwm->pwm_duty_max);
BLPR("pwm_combo0_duty_min = %d\n", bl_pwm->pwm_duty_min);
BLPR("pwm_combo0_gpio = %s(%d)\n",
bconf->gpio_name[bl_pwm->pwm_gpio], bl_pwm->pwm_gpio);
BLPR("pwm_combo0_gpio_off = %d\n", bl_pwm->pwm_gpio_off);
}
if (bconf->bl_pwm_combo1) {
bl_pwm = bconf->bl_pwm_combo1;
BLPR("pwm_combo1_index = %d\n", bl_pwm->index);
BLPR("pwm_combo1_method = %d\n", bl_pwm->pwm_method);
BLPR("pwm_combo1_port = 0x%x\n", bl_pwm->pwm_port);
if (bl_pwm->pwm_port == BL_PWM_VS) {
BLPR("pwm_combo1_freq = %d x vfreq\n", bl_pwm->pwm_freq);
BLPR("pwm_combo1_cnt = %u\n", bl_pwm->pwm_cnt);
if (bl_pwm->pwm_duty_max > 100) {
BLPR("bl:pwm_combo1_duty = %d%% %d\n",
bl_pwm->pwm_duty * 100 / 255, bl_pwm->pwm_duty);
} else {
BLPR("bl:pwm_combo1_duty = %d%% %d\n",
bl_pwm->pwm_duty, bl_pwm->pwm_duty);
}
BLPR("pwm_combo1_reg0 = 0x%08x\n",
lcd_vcbus_read(VPU_VPU_PWM_V0));
BLPR("pwm_combo1_reg1 = 0x%08x\n",
lcd_vcbus_read(VPU_VPU_PWM_V1));
BLPR("pwm_combo1_reg2 = 0x%08x\n",
lcd_vcbus_read(VPU_VPU_PWM_V2));
BLPR("pwm_combo1_reg3 = 0x%08x\n",
lcd_vcbus_read(VPU_VPU_PWM_V3));
} else {
BLPR("pwm_combo1_freq = %uHz\n",
bl_pwm->pwm_freq);
BLPR("pwm_combo1_cnt = %u\n",
bl_pwm->pwm_cnt);
BLPR("pwm_combo1_pre_div = %u\n",
bl_pwm->pwm_pre_div);
if (bl_pwm->pwm_duty_max > 100) {
BLPR("pwm_combo1_duty = %d%%(%d)\n",
bl_pwm->pwm_duty * 100 / 255, bl_pwm->pwm_duty);
} else {
BLPR("pwm_combo1_duty = %d%%(%d)\n",
bl_pwm->pwm_duty, bl_pwm->pwm_duty);
}
bl_pwm_reg_print(bl_pwm);
}
BLPR("pwm_combo1_duty_max = %d\n", bl_pwm->pwm_duty_max);
BLPR("pwm_combo1_duty_min = %d\n", bl_pwm->pwm_duty_min);
BLPR("pwm_combo1_gpio = %s(%d)\n",
bconf->gpio_name[bl_pwm->pwm_gpio], bl_pwm->pwm_gpio);
BLPR("pwm_combo1_gpio_off = %d\n", bl_pwm->pwm_gpio_off);
}
BLPR("pwm_on_delay = %d\n", bconf->pwm_on_delay);
BLPR("pwm_off_delay = %d\n", bconf->pwm_off_delay);
BLPR("en_sequence_reverse = %d\n", bconf->en_sequence_reverse);
break;
#ifdef CONFIG_AML_LOCAL_DIMMING
case BL_CTRL_LOCAL_DIMMING:
if (!ldim_drv) {
BLPR("invalid local dimming driver\n");
break;
}
if (ldim_drv->config_print)
ldim_drv->config_print();
break;
#endif
#ifdef CONFIG_AML_BL_EXTERN
case BL_CTRL_EXTERN:
if (!bl_extern) {
BLPR("invalid bl extern driver\n");
break;
}
if (bl_extern->config_print)
bl_extern->config_print();
break;
#endif
default:
BLPR("invalid backlight control method\n");
break;
}
}
#ifdef CONFIG_OF_LIBFDT
static int bl_config_load_from_dts(char *dt_addr, struct aml_bl_drv_s *bdrv)
{
int parent_offset, child_offset;
char sname[20], propname[30];
char *propdata;
char *p;
const char *str;
struct bl_config_s *bconf = &bdrv->config;
struct bl_pwm_config_s *bl_pwm;
struct bl_pwm_config_s *pwm_combo0, *pwm_combo1;
if (bdrv->index == 0)
sprintf(sname, "/backlight");
else
sprintf(sname, "/backlight%d", bdrv->index);
bconf->method = BL_CTRL_MAX; /* default */
parent_offset = fdt_path_offset(dt_addr, "sname");
if (parent_offset < 0) {
BLPR("not find %s node %s\n",
sname,
fdt_strerror(parent_offset));
return -1;
}
propdata = (char *)fdt_getprop(dt_addr, parent_offset, "status", NULL);
if (!propdata) {
BLPR("not find status, default to disabled\n");
return -1;
} else {
if (strncmp(propdata, "okay", 2)) {
BLPR("status disabled\n");
return -1;
}
}
sprintf(propname,"%s/backlight_%d", sname, bconf->index);
child_offset = fdt_path_offset(dt_addr, propname);
if (child_offset < 0) {
BLERR("not find %s node: %s\n", propname, fdt_strerror(child_offset));
return -1;
}
propdata = (char *)fdt_getprop(dt_addr, child_offset, "bl_name", NULL);
if (!propdata) {
BLERR("failed to get bl_name\n");
sprintf(bconf->name, "backlight_%d", bconf->index);
} else {
strcpy(bconf->name, propdata);
}
propdata = (char *)fdt_getprop(dt_addr, child_offset,
"bl_level_default_uboot_kernel", NULL);
if (!propdata) {
BLERR("failed to get bl_level_default_uboot_kernel\n");
bconf->level_default = BL_LEVEL_DEFAULT;
} else {
bconf->level_default = be32_to_cpup((u32*)propdata);
}
propdata = (char *)fdt_getprop(dt_addr, child_offset,
"bl_level_attr", NULL);
if (!propdata) {
BLERR("failed to get bl_level_attr\n");
bconf->level_max = BL_LEVEL_MAX;
bconf->level_min = BL_LEVEL_MIN;
bconf->level_mid = BL_LEVEL_MID;
bconf->level_mid_mapping = BL_LEVEL_MID_MAPPED;
} else {
bconf->level_max = be32_to_cpup((u32 *)propdata);
bconf->level_min = be32_to_cpup((((u32 *)propdata) + 1));
bconf->level_mid = be32_to_cpup((((u32 *)propdata) + 2));
bconf->level_mid_mapping =
be32_to_cpup((((u32 *)propdata) + 3));
}
propdata = (char *)fdt_getprop(dt_addr, child_offset,
"bl_ctrl_method", NULL);
if (!propdata) {
BLERR("failed to get bl_ctrl_method\n");
bconf->method = BL_CTRL_MAX;
return -1;
} else {
bconf->method = be32_to_cpup((u32 *)propdata);
}
propdata = (char *)fdt_getprop(dt_addr, child_offset,
"bl_power_attr", NULL);
if (!propdata) {
BLERR("failed to get bl_power_attr\n");
bconf->en_gpio = BL_GPIO_NUM_MAX;
bconf->en_gpio_on = LCD_GPIO_OUTPUT_HIGH;
bconf->en_gpio_off = LCD_GPIO_OUTPUT_LOW;
bconf->power_on_delay = 100;
bconf->power_off_delay = 30;
} else {
bconf->en_gpio = be32_to_cpup((u32 *)propdata);
bconf->en_gpio_on = be32_to_cpup((((u32 *)propdata) + 1));
bconf->en_gpio_off = be32_to_cpup((((u32 *)propdata) + 2));
bconf->power_on_delay = be32_to_cpup((((u32 *)propdata) + 3));
bconf->power_off_delay = be32_to_cpup((((u32 *)propdata) + 4));
}
switch (bconf->method) {
case BL_CTRL_PWM:
if (!bconf->bl_pwm) {
bconf->bl_pwm = (struct bl_pwm_config_s *)
malloc(sizeof(struct bl_pwm_config_s));
if (!bconf->bl_pwm) {
BLERR("bl_pwm malloc error\n");
return -1;
}
}
bl_pwm = bconf->bl_pwm;
memset(bl_pwm, 0, sizeof(struct bl_pwm_config_s));
bl_pwm->index = 0;
bl_pwm->level_max = bconf->level_max;
bl_pwm->level_min = bconf->level_min;
propdata = (char *)fdt_getprop(dt_addr, child_offset,
"bl_pwm_port", NULL);
if (!propdata) {
BLERR("failed to get bl_pwm_port\n");
bl_pwm->pwm_port = BL_PWM_MAX;
} else {
bl_pwm->pwm_port = bl_pwm_str_to_num(propdata);
}
propdata = (char *)fdt_getprop(dt_addr, child_offset,
"bl_pwm_attr", NULL);
if (!propdata) {
BLERR("failed to get bl_pwm_attr\n");
bl_pwm->pwm_method = BL_PWM_POSITIVE;
if (bl_pwm->pwm_port == BL_PWM_VS)
bl_pwm->pwm_freq = BL_FREQ_VS_DEFAULT;
else
bl_pwm->pwm_freq = BL_FREQ_DEFAULT;
bl_pwm->pwm_duty_max = 80;
bl_pwm->pwm_duty_min = 20;
} else {
bl_pwm->pwm_method = be32_to_cpup((u32 *)propdata);
bl_pwm->pwm_freq =
be32_to_cpup((((u32 *)propdata) + 1));
bl_pwm->pwm_duty_max =
be32_to_cpup((((u32 *)propdata) + 2));
bl_pwm->pwm_duty_min =
be32_to_cpup((((u32 *)propdata) + 3));
}
if (bl_pwm->pwm_port == BL_PWM_VS) {
if (bl_pwm->pwm_freq > 4) {
BLERR("bl_pwm_vs wrong freq %d\n",
bl_pwm->pwm_freq);
bl_pwm->pwm_freq = BL_FREQ_VS_DEFAULT;
}
} else {
if (bl_pwm->pwm_freq > XTAL_HALF_FREQ_HZ)
bl_pwm->pwm_freq = XTAL_HALF_FREQ_HZ;
}
propdata = (char *)fdt_getprop(dt_addr, child_offset,
"bl_pwm_power", NULL);
if (!propdata) {
BLERR("failed to get bl_pwm_power\n");
bl_pwm->pwm_gpio = BL_GPIO_NUM_MAX;
bl_pwm->pwm_gpio_off = LCD_GPIO_OUTPUT_LOW;
bconf->pwm_on_delay = 10;
bconf->pwm_off_delay = 10;
} else {
bl_pwm->pwm_gpio = be32_to_cpup((u32 *)propdata);
bl_pwm->pwm_gpio_off =
be32_to_cpup((((u32 *)propdata) + 1));
bconf->pwm_on_delay =
be32_to_cpup((((u32 *)propdata) + 2));
bconf->pwm_off_delay =
be32_to_cpup((((u32 *)propdata) + 3));
}
propdata = (char *)fdt_getprop(dt_addr, child_offset,
"bl_pwm_en_sequence_reverse",
NULL);
if (!propdata) {
propdata = (char *)fdt_getprop(dt_addr, child_offset,
"en_sequence_reverse",
NULL);
if (!propdata) {
bconf->en_sequence_reverse = 0;
} else {
bconf->en_sequence_reverse =
be32_to_cpup((u32 *)propdata);
BLPR("find en_sequence_reverse: %d\n",
bconf->en_sequence_reverse);
}
} else {
bconf->en_sequence_reverse = be32_to_cpup((u32 *)propdata);
BLPR("find en_sequence_reverse: %d\n",
bconf->en_sequence_reverse);
}
bl_pwm->pwm_duty = bl_pwm->pwm_duty_min;
/* bl_pwm_config_init(bl_pwm); */
break;
case BL_CTRL_PWM_COMBO:
if (!bconf->bl_pwm_combo0) {
bconf->bl_pwm_combo0 = (struct bl_pwm_config_s *)
malloc(sizeof(struct bl_pwm_config_s));
if (!bconf->bl_pwm_combo0) {
BLERR("bl_pwm_combo0 malloc error\n");
return -1;
}
}
if (!bconf->bl_pwm_combo1) {
bconf->bl_pwm_combo1 = (struct bl_pwm_config_s *)
malloc(sizeof(struct bl_pwm_config_s));
if (!bconf->bl_pwm_combo1) {
free(bconf->bl_pwm_combo0);
BLERR("bl_pwm_combo1 struct malloc error\n");
return -1;
}
}
pwm_combo0 = bconf->bl_pwm_combo0;
pwm_combo1 = bconf->bl_pwm_combo1;
memset(pwm_combo0, 0, sizeof(struct bl_pwm_config_s));
memset(pwm_combo1, 0, sizeof(struct bl_pwm_config_s));
pwm_combo0->index = 0;
pwm_combo1->index = 1;
propdata = (char *)fdt_getprop(dt_addr, child_offset,
"bl_pwm_combo_level_mapping",
NULL);
if (!propdata) {
BLERR("failed to get bl_pwm_combo_level_mapping\n");
pwm_combo0->level_max = BL_LEVEL_MAX;
pwm_combo0->level_min = BL_LEVEL_MID;
pwm_combo1->level_max = BL_LEVEL_MID;
pwm_combo1->level_min = BL_LEVEL_MIN;
} else {
pwm_combo0->level_max = be32_to_cpup((u32 *)propdata);
pwm_combo0->level_min =
be32_to_cpup((((u32 *)propdata) + 1));
pwm_combo1->level_max =
be32_to_cpup((((u32 *)propdata) + 2));
pwm_combo1->level_min =
be32_to_cpup((((u32 *)propdata) + 3));
}
propdata = (char *)fdt_getprop(dt_addr, child_offset,
"bl_pwm_combo_port", NULL);
if (!propdata) {
BLERR("failed to get bl_pwm_combo_port\n");
pwm_combo0->pwm_port = BL_PWM_MAX;
pwm_combo1->pwm_port = BL_PWM_MAX;
} else {
p = propdata;
str = p;
pwm_combo0->pwm_port = bl_pwm_str_to_num(str);
p += strlen(p) + 1;
str = p;
pwm_combo1->pwm_port = bl_pwm_str_to_num(str);
}
propdata = (char *)fdt_getprop(dt_addr, child_offset,
"bl_pwm_combo_attr", NULL);
if (!propdata) {
BLERR("failed to get bl_pwm_combo_attr\n");
pwm_combo0->pwm_method = BL_PWM_POSITIVE;
if (pwm_combo0->pwm_port == BL_PWM_VS)
pwm_combo0->pwm_freq = BL_FREQ_VS_DEFAULT;
else
pwm_combo0->pwm_freq = BL_FREQ_DEFAULT;
pwm_combo0->pwm_duty_max = 80;
pwm_combo0->pwm_duty_min = 20;
pwm_combo1->pwm_method = BL_PWM_POSITIVE;
if (pwm_combo1->pwm_port == BL_PWM_VS)
pwm_combo1->pwm_freq = BL_FREQ_VS_DEFAULT;
else
pwm_combo1->pwm_freq = BL_FREQ_DEFAULT;
pwm_combo1->pwm_duty_max = 80;
pwm_combo1->pwm_duty_min = 20;
} else {
pwm_combo0->pwm_method = be32_to_cpup((u32 *)propdata);
pwm_combo0->pwm_freq =
be32_to_cpup((((u32 *)propdata) + 1));
pwm_combo0->pwm_duty_max =
be32_to_cpup((((u32 *)propdata) + 2));
pwm_combo0->pwm_duty_min =
be32_to_cpup((((u32 *)propdata) + 3));
pwm_combo1->pwm_method =
be32_to_cpup((((u32 *)propdata) + 4));
pwm_combo1->pwm_freq =
be32_to_cpup((((u32 *)propdata) + 5));
pwm_combo1->pwm_duty_max =
be32_to_cpup((((u32 *)propdata) + 6));
pwm_combo1->pwm_duty_min =
be32_to_cpup((((u32 *)propdata) + 7));
}
if (pwm_combo0->pwm_port == BL_PWM_VS) {
if (pwm_combo0->pwm_freq > 4) {
BLERR("bl_pwm_vs wrong freq %d\n",
pwm_combo0->pwm_freq);
pwm_combo0->pwm_freq = BL_FREQ_VS_DEFAULT;
}
} else {
if (pwm_combo0->pwm_freq > XTAL_HALF_FREQ_HZ)
pwm_combo0->pwm_freq = XTAL_HALF_FREQ_HZ;
}
if (pwm_combo1->pwm_port == BL_PWM_VS) {
if (pwm_combo1->pwm_freq > 4) {
BLERR("bl_pwm_vs wrong freq %d\n",
pwm_combo1->pwm_freq);
pwm_combo1->pwm_freq = BL_FREQ_VS_DEFAULT;
}
} else {
if (pwm_combo1->pwm_freq > XTAL_HALF_FREQ_HZ)
pwm_combo1->pwm_freq = XTAL_HALF_FREQ_HZ;
}
propdata = (char *)fdt_getprop(dt_addr, child_offset,
"bl_pwm_combo_power", NULL);
if (!propdata) {
BLERR("failed to get bl_pwm_combo_power\n");
pwm_combo0->pwm_gpio = BL_GPIO_NUM_MAX;
pwm_combo0->pwm_gpio_off = LCD_GPIO_INPUT;
pwm_combo1->pwm_gpio = BL_GPIO_NUM_MAX;
pwm_combo1->pwm_gpio_off = LCD_GPIO_INPUT;
bconf->pwm_on_delay = 10;
bconf->pwm_off_delay = 10;
} else {
pwm_combo0->pwm_gpio =
be32_to_cpup((u32 *)propdata);
pwm_combo0->pwm_gpio_off =
be32_to_cpup((((u32 *)propdata) + 1));
pwm_combo1->pwm_gpio =
be32_to_cpup((((u32 *)propdata) + 2));
pwm_combo1->pwm_gpio_off =
be32_to_cpup((((u32 *)propdata) + 3));
bconf->pwm_on_delay =
be32_to_cpup((((u32 *)propdata) + 4));
bconf->pwm_off_delay =
be32_to_cpup((((u32 *)propdata) + 5));
}
propdata = (char *)fdt_getprop(dt_addr, child_offset,
"bl_pwm_en_sequence_reverse",
NULL);
if (!propdata) {
propdata = (char *)fdt_getprop(dt_addr, child_offset,
"en_sequence_reverse",
NULL);
if (!propdata) {
bconf->en_sequence_reverse = 0;
} else {
bconf->en_sequence_reverse =
be32_to_cpup((u32 *)propdata);
BLPR("find en_sequence_reverse: %d\n",
bconf->en_sequence_reverse);
}
} else {
bconf->en_sequence_reverse =
be32_to_cpup((u32 *)propdata);
}
pwm_combo0->pwm_duty = pwm_combo0->pwm_duty_min;
pwm_combo1->pwm_duty = pwm_combo1->pwm_duty_min;
/* bl_pwm_config_init(pwm_combo0);
bl_pwm_config_init(pwm_combo1); */
break;
#ifdef CONFIG_AML_LOCAL_DIMMING
case BL_CTRL_LOCAL_DIMMING:
propdata = (char *)fdt_getprop(dt_addr, child_offset,
"en_sequence_reverse", NULL);
if (!propdata) {
bconf->en_sequence_reverse = 0;
} else {
bconf->en_sequence_reverse = be32_to_cpup((u32 *)propdata);
BLPR("find en_sequence_reverse: %d\n", bconf->en_sequence_reverse);
}
ldim_config_load_from_dts(dt_addr, child_offset);
ldim_probe(dt_addr, 0);
break;
#endif
#ifdef CONFIG_AML_BL_EXTERN
case BL_CTRL_EXTERN:
propdata = (char *)fdt_getprop(dt_addr, child_offset,
"en_sequence_reverse", NULL);
if (!propdata) {
bconf->en_sequence_reverse = 0;
} else {
bconf->en_sequence_reverse = be32_to_cpup((u32 *)propdata);
BLPR("find en_sequence_reverse: %d\n", bconf->en_sequence_reverse);
}
/* get bl_extern_index from dts */
propdata = (char *)fdt_getprop(dt_addr, child_offset,
"bl_extern_index", NULL);
if (!propdata) {
BLERR("failed to get bl_extern_index\n");
} else {
bconf->bl_extern_index = be32_to_cpup((u32 *)propdata);
BLPR("get bl_extern_index = %d\n", bconf->bl_extern_index);
}
bl_extern_device_load(dt_addr, bconf->bl_extern_index);
break;
#endif
default:
break;
}
return 0;
}
#endif
static int bl_config_load_from_unifykey(char *dt_addr, struct aml_bl_drv_s *bdrv)
{
unsigned char *para;
int key_len, len;
unsigned char *p;
const char *str;
char sname[20];
struct lcd_unifykey_header_s bl_header;
struct bl_config_s *bconf = &bdrv->config;
struct bl_pwm_config_s *bl_pwm;
struct bl_pwm_config_s *pwm_combo0, *pwm_combo1;
int ret;
key_len = LCD_UKEY_BL_SIZE;
para = (unsigned char *)malloc(sizeof(unsigned char) * key_len);
if (!para) {
BLERR("%s: Not enough memory\n", __func__);
return -1;
}
memset(para, 0, (sizeof(unsigned char) * key_len));
if (bdrv->index == 0)
sprintf(sname, "/backlight");
else
sprintf(sname, "/backlight%d", bdrv->index);
ret = lcd_unifykey_get(sname, para, &key_len);
if (ret) {
free(para);
return -1;
}
/* step 1: check header */
len = LCD_UKEY_HEAD_SIZE;
ret = lcd_unifykey_len_check(key_len, len);
if (ret) {
BLERR("unifykey header length is incorrect\n");
free(para);
return -1;
}
lcd_unifykey_header_check(para, &bl_header);
BLPR("unifykey version: 0x%04x\n", bl_header.version);
switch (bl_header.version) {
case 2:
len = 10 + 30 + 12 + 8 + 32 + 10;
break;
default:
len = 10 + 30 + 12 + 8 + 32;
break;
}
if (lcd_debug_print_flag & LCD_DBG_PR_BL_NORMAL) {
BLPR("unifykey header:\n");
BLPR("crc32 = 0x%08x\n", bl_header.crc32);
BLPR("data_len = %d\n", bl_header.data_len);
BLPR("reserved = 0x%04x\n", bl_header.reserved);
}
/* step 2: check backlight parameters */
ret = lcd_unifykey_len_check(key_len, len);
if (ret) {
BLERR("unifykey length is incorrect\n");
free(para);
return -1;
}
/* basic: 30byte */
p = para;
str = (const char *)(p + LCD_UKEY_HEAD_SIZE);
strncpy(bconf->name, str, sizeof(bconf->name) - 1);
bconf->name[sizeof(bconf->name) - 1] = '\0';
/* level: 12byte */
bconf->level_default = (*(p + LCD_UKEY_BL_LEVEL_UBOOT) |
((*(p + LCD_UKEY_BL_LEVEL_UBOOT + 1)) << 8));
bconf->level_max = (*(p + LCD_UKEY_BL_LEVEL_MAX) |
((*(p + LCD_UKEY_BL_LEVEL_MAX + 1)) << 8));
bconf->level_min = (*(p + LCD_UKEY_BL_LEVEL_MIN) |
((*(p + LCD_UKEY_BL_LEVEL_MIN + 1)) << 8));
bconf->level_mid = (*(p + LCD_UKEY_BL_LEVEL_MID) |
((*(p + LCD_UKEY_BL_LEVEL_MID + 1)) << 8));
bconf->level_mid_mapping = (*(p + LCD_UKEY_BL_LEVEL_MID_MAP) |
((*(p + LCD_UKEY_BL_LEVEL_MID_MAP + 1)) << 8));
/* method: 8byte */
bconf->method = *(p + LCD_UKEY_BL_METHOD);
bconf->en_gpio = *(p + LCD_UKEY_BL_EN_GPIO);
bconf->en_gpio_on = *(p + LCD_UKEY_BL_EN_GPIO_ON);
bconf->en_gpio_off = *(p + LCD_UKEY_BL_EN_GPIO_OFF);
bconf->power_on_delay = (*(p + LCD_UKEY_BL_ON_DELAY) |
((*(p + LCD_UKEY_BL_ON_DELAY + 1)) << 8));
bconf->power_off_delay = (*(p + LCD_UKEY_BL_OFF_DELAY) |
((*(p + LCD_UKEY_BL_OFF_DELAY + 1)) << 8));
/* pwm: 32byte */
switch (bconf->method) {
case BL_CTRL_PWM:
bconf->bl_pwm = (struct bl_pwm_config_s *)
malloc(sizeof(struct bl_pwm_config_s));
if (!bconf->bl_pwm) {
BLERR("bl_pwm struct malloc error\n");
free(para);
return -1;
}
bl_pwm = bconf->bl_pwm;
bl_pwm->index = 0;
bl_pwm->level_max = bconf->level_max;
bl_pwm->level_min = bconf->level_min;
bconf->pwm_on_delay = (*(p + LCD_UKEY_BL_PWM_ON_DELAY) |
((*(p + LCD_UKEY_BL_PWM_ON_DELAY + 1)) << 8));
bconf->pwm_off_delay = (*(p + LCD_UKEY_BL_PWM_OFF_DELAY) |
((*(p + LCD_UKEY_BL_PWM_OFF_DELAY + 1)) << 8));
bl_pwm->pwm_method = *(p + LCD_UKEY_BL_PWM_METHOD);
bl_pwm->pwm_port = *(p + LCD_UKEY_BL_PWM_PORT);
bl_pwm->pwm_freq = (*(p + LCD_UKEY_BL_PWM_FREQ) |
((*(p + LCD_UKEY_BL_PWM_FREQ + 1)) << 8) |
((*(p + LCD_UKEY_BL_PWM_FREQ + 2)) << 8) |
((*(p + LCD_UKEY_BL_PWM_FREQ + 3)) << 8));
if (bl_pwm->pwm_port == BL_PWM_VS) {
if (bl_pwm->pwm_freq > 4) {
BLERR("bl_pwm_vs wrong freq %d\n", bl_pwm->pwm_freq);
bl_pwm->pwm_freq = BL_FREQ_VS_DEFAULT;
}
} else {
if (bl_pwm->pwm_freq > XTAL_HALF_FREQ_HZ)
bl_pwm->pwm_freq = XTAL_HALF_FREQ_HZ;
}
bl_pwm->pwm_duty_max = *(p + LCD_UKEY_BL_PWM_DUTY_MAX);
bl_pwm->pwm_duty_min = *(p + LCD_UKEY_BL_PWM_DUTY_MIN);
bl_pwm->pwm_gpio = *(p + LCD_UKEY_BL_PWM_GPIO);
bl_pwm->pwm_gpio_off = *(p + LCD_UKEY_BL_PWM_GPIO_OFF);
if (bl_header.version == 2)
bconf->en_sequence_reverse =
(*(p + LCD_UKEY_BL_CUST_VAL_0) |
((*(p + LCD_UKEY_BL_CUST_VAL_0 + 1)) << 8));
else
bconf->en_sequence_reverse = 0;
bl_pwm->pwm_duty = bl_pwm->pwm_duty_min;
/* bl_pwm_config_init(bl_pwm); */
break;
case BL_CTRL_PWM_COMBO:
bconf->bl_pwm_combo0 = (struct bl_pwm_config_s *)
malloc(sizeof(struct bl_pwm_config_s));
if (!bconf->bl_pwm_combo0) {
BLERR("bl_pwm_combo0 struct malloc error\n");
free(para);
return -1;
}
bconf->bl_pwm_combo1 = (struct bl_pwm_config_s *)
malloc(sizeof(struct bl_pwm_config_s));
if (!bconf->bl_pwm_combo1) {
BLERR("bl_pwm_combo1 struct malloc error\n");
free(para);
return -1;
}
pwm_combo0 = bconf->bl_pwm_combo0;
pwm_combo1 = bconf->bl_pwm_combo1;
pwm_combo0->index = 0;
pwm_combo1->index = 1;
bconf->pwm_on_delay = (*(p + LCD_UKEY_BL_PWM_ON_DELAY) |
((*(p + LCD_UKEY_BL_PWM_ON_DELAY + 1)) << 8));
bconf->pwm_off_delay = (*(p + LCD_UKEY_BL_PWM_OFF_DELAY) |
((*(p + LCD_UKEY_BL_PWM_OFF_DELAY + 1)) << 8));
pwm_combo0->pwm_method = *(p + LCD_UKEY_BL_PWM_METHOD);
pwm_combo0->pwm_port = *(p + LCD_UKEY_BL_PWM_PORT);
pwm_combo0->pwm_freq = (*(p + LCD_UKEY_BL_PWM_FREQ) |
((*(p + LCD_UKEY_BL_PWM_FREQ + 1)) << 8) |
((*(p + LCD_UKEY_BL_PWM_FREQ + 2)) << 8) |
((*(p + LCD_UKEY_BL_PWM_FREQ + 3)) << 8));
if (pwm_combo0->pwm_port == BL_PWM_VS) {
if (pwm_combo0->pwm_freq > 4) {
BLERR("bl_pwm_vs wrong freq %d\n",
pwm_combo0->pwm_freq);
pwm_combo0->pwm_freq = BL_FREQ_VS_DEFAULT;
}
} else {
if (pwm_combo0->pwm_freq > XTAL_HALF_FREQ_HZ)
pwm_combo0->pwm_freq = XTAL_HALF_FREQ_HZ;
}
pwm_combo0->pwm_duty_max = *(p + LCD_UKEY_BL_PWM_DUTY_MAX);
pwm_combo0->pwm_duty_min = *(p + LCD_UKEY_BL_PWM_DUTY_MIN);
pwm_combo0->pwm_gpio = *(p + LCD_UKEY_BL_PWM_GPIO);
pwm_combo0->pwm_gpio_off = *(p + LCD_UKEY_BL_PWM_GPIO_OFF);
pwm_combo1->pwm_method = *(p + LCD_UKEY_BL_PWM2_METHOD);
pwm_combo1->pwm_port = *(p + LCD_UKEY_BL_PWM2_PORT);
pwm_combo1->pwm_freq = (*(p + LCD_UKEY_BL_PWM2_FREQ) |
((*(p + LCD_UKEY_BL_PWM2_FREQ + 1)) << 8) |
((*(p + LCD_UKEY_BL_PWM2_FREQ + 2)) << 8) |
((*(p + LCD_UKEY_BL_PWM2_FREQ + 3)) << 8));
if (pwm_combo1->pwm_port == BL_PWM_VS) {
if (pwm_combo1->pwm_freq > 4) {
BLERR("bl_pwm_vs wrong freq %d\n",
pwm_combo1->pwm_freq);
pwm_combo1->pwm_freq = BL_FREQ_VS_DEFAULT;
}
} else {
if (pwm_combo1->pwm_freq > XTAL_HALF_FREQ_HZ)
pwm_combo1->pwm_freq = XTAL_HALF_FREQ_HZ;
}
pwm_combo1->pwm_duty_max = *(p + LCD_UKEY_BL_PWM2_DUTY_MAX);
pwm_combo1->pwm_duty_min = *(p + LCD_UKEY_BL_PWM2_DUTY_MIN);
pwm_combo1->pwm_gpio = *(p + LCD_UKEY_BL_PWM2_GPIO);
pwm_combo1->pwm_gpio_off = *(p + LCD_UKEY_BL_PWM2_GPIO_OFF);
pwm_combo0->level_max = (*(p + LCD_UKEY_BL_PWM_LEVEL_MAX) |
((*(p + LCD_UKEY_BL_PWM_LEVEL_MAX + 1)) << 8));
pwm_combo0->level_min = (*(p + LCD_UKEY_BL_PWM_LEVEL_MIN) |
((*(p + LCD_UKEY_BL_PWM_LEVEL_MIN + 1)) << 8));
pwm_combo1->level_max = (*(p + LCD_UKEY_BL_PWM2_LEVEL_MAX) |
((*(p + LCD_UKEY_BL_PWM2_LEVEL_MAX + 1)) << 8));
pwm_combo1->level_min = (*(p + LCD_UKEY_BL_PWM2_LEVEL_MIN) |
((*(p + LCD_UKEY_BL_PWM2_LEVEL_MIN + 1)) << 8));
if (bl_header.version == 2)
bconf->en_sequence_reverse = (*(p + LCD_UKEY_BL_CUST_VAL_0) |
((*(p + LCD_UKEY_BL_CUST_VAL_0 + 1)) << 8));
else
bconf->en_sequence_reverse = 0;
pwm_combo0->pwm_duty = pwm_combo0->pwm_duty_min;
pwm_combo1->pwm_duty = pwm_combo1->pwm_duty_min;
/* bl_pwm_config_init(pwm_combo0);
bl_pwm_config_init(pwm_combo1); */
break;
#ifdef CONFIG_AML_LOCAL_DIMMING
case BL_CTRL_LOCAL_DIMMING:
if (bl_header.version == 2) {
ldim_config_load_from_unifykey(para);
} else {
BLERR("not support ldim for unifykey version: %d\n",
bl_header.version);
}
ldim_probe(dt_addr, 2);
break;
#endif
default:
break;
}
free(para);
return 0;
}
static int bl_config_load_from_bsp(struct aml_bl_drv_s *bdrv)
{
struct ext_lcd_config_s *ext_lcd = NULL;
char *panel_type, sname[20];
unsigned int i = 0, j, done;
char *str;
struct bl_config_s *bconf = &bdrv->config;
struct bl_pwm_config_s *bl_pwm;
struct bl_pwm_config_s *pwm_combo0, *pwm_combo1;
char (*bl_gpio)[LCD_CPU_GPIO_NAME_MAX];
if (!bdrv->data)
return -1;
if (bdrv->index == 0)
sprintf(sname, "panel_type");
else
sprintf(sname, "panel%d_type", bdrv->index);
panel_type = env_get(sname);
if (!panel_type) {
BLERR("no %s\n", sname);
return -1;
}
if (!bdrv->data->dft_conf[bdrv->index]) {
BLERR("no dft_conf\n");
return -1;
}
ext_lcd = bdrv->data->dft_conf[bdrv->index]->ext_lcd;
if (!ext_lcd) {
BLERR("%s: ext_lcd is NULL\n", __func__);
return -1;
}
done = 0;
for (i = 0; i < LCD_NUM_MAX; i++) {
if (strcmp(ext_lcd->panel_type, panel_type) == 0) {
done = 1;
break;
}
if (strcmp(ext_lcd->panel_type, "invalid") == 0)
break;
ext_lcd++;
}
if (done == 0) {
BLERR("can't find %s\n ", panel_type);
return -1;
}
strncpy(bconf->name, panel_type, sizeof(bconf->name) - 1);
bconf->name[sizeof(bconf->name) - 1] = '\0';
bconf->level_default = ext_lcd->level_default;
bconf->level_min = ext_lcd->level_min;
bconf->level_max = ext_lcd->level_max;
bconf->level_mid = ext_lcd->level_mid;
bconf->level_mid_mapping = ext_lcd->level_mid_mapping;
bconf->method = ext_lcd->bl_method;
if (ext_lcd->bl_en_gpio >= BL_GPIO_NUM_MAX)
bconf->en_gpio = LCD_GPIO_MAX;
else
bconf->en_gpio = ext_lcd->bl_en_gpio;
bconf->en_gpio_on = ext_lcd->bl_en_gpio_on;
bconf->en_gpio_off = ext_lcd->bl_en_gpio_off;
bconf->power_on_delay = ext_lcd->bl_power_on_delay;
bconf->power_off_delay = ext_lcd->bl_power_off_delay;
switch (bconf->method) {
case BL_CTRL_PWM:
bl_pwm = (struct bl_pwm_config_s *)malloc(sizeof(struct bl_pwm_config_s));
if (!bl_pwm) {
BLERR("bl_pwm struct malloc error\n");
return -1;
}
bconf->bl_pwm = bl_pwm;
bl_pwm->index = 0;
bl_pwm->level_max = bconf->level_max;
bl_pwm->level_min = bconf->level_min;
bl_pwm->pwm_method = ext_lcd->pwm_method;
bl_pwm->pwm_port = ext_lcd->pwm_port;
bl_pwm->pwm_freq = ext_lcd->pwm_freq;
bl_pwm->pwm_duty_max = ext_lcd->pwm_duty_max;
bl_pwm->pwm_duty_min = ext_lcd->pwm_duty_min;
bl_pwm->pwm_gpio = ext_lcd->pwm_gpio;
bl_pwm->pwm_gpio_off = ext_lcd->pwm_gpio_off;
bconf->pwm_on_delay = ext_lcd->pwm_on_delay;
bconf->pwm_off_delay = ext_lcd->pwm_off_delay;
bl_pwm->pwm_duty = bl_pwm->pwm_duty_min;
/* bl_pwm_config_init(bl_pwm); */
break;
case BL_CTRL_PWM_COMBO:
bconf->bl_pwm_combo0 = (struct bl_pwm_config_s *)
malloc(sizeof(struct bl_pwm_config_s));
if (!bconf->bl_pwm_combo0) {
BLERR("bl_pwm_combo0 struct malloc error\n");
return -1;
}
bconf->bl_pwm_combo1 = (struct bl_pwm_config_s *)
malloc(sizeof(struct bl_pwm_config_s));
if (!bconf->bl_pwm_combo1) {
BLERR("bl_pwm_combo1 struct malloc error\n");
return -1;
}
pwm_combo0 = bconf->bl_pwm_combo0;
pwm_combo1 = bconf->bl_pwm_combo1;
pwm_combo0->index = 0;
pwm_combo1->index = 1;
pwm_combo0->level_max = ext_lcd->pwm_level_max;
pwm_combo0->level_min = ext_lcd->pwm_level_min;
pwm_combo1->level_max = ext_lcd->pwm2_level_max;
pwm_combo1->level_min = ext_lcd->pwm2_level_min;
pwm_combo0->pwm_method = ext_lcd->pwm_method;
pwm_combo0->pwm_port = ext_lcd->pwm_port;
pwm_combo0->pwm_freq = ext_lcd->pwm_freq;
pwm_combo0->pwm_duty_max = ext_lcd->pwm_duty_max;
pwm_combo0->pwm_duty_min = ext_lcd->pwm_duty_min;
if (ext_lcd->pwm_gpio >= BL_GPIO_NUM_MAX) {
pwm_combo0->pwm_gpio = LCD_GPIO_MAX;
} else {
str = bconf->gpio_name[ext_lcd->pwm_gpio];
pwm_combo0->pwm_gpio = lcd_gpio_name_map_num(str);
}
pwm_combo0->pwm_gpio_off = ext_lcd->pwm_gpio_off;
pwm_combo1->pwm_method = ext_lcd->pwm2_method;
pwm_combo1->pwm_port = ext_lcd->pwm2_port;
pwm_combo1->pwm_freq = ext_lcd->pwm2_freq;
pwm_combo1->pwm_duty_max = ext_lcd->pwm2_duty_max;
pwm_combo1->pwm_duty_min = ext_lcd->pwm2_duty_min;
if (ext_lcd->pwm2_gpio >= BL_GPIO_NUM_MAX) {
pwm_combo1->pwm_gpio = LCD_GPIO_MAX;
} else {
str = bconf->gpio_name[ext_lcd->pwm2_gpio];
pwm_combo1->pwm_gpio = lcd_gpio_name_map_num(str);
}
pwm_combo1->pwm_gpio_off = ext_lcd->pwm2_gpio_off;
bconf->pwm_on_delay = ext_lcd->pwm_on_delay;
bconf->pwm_off_delay = ext_lcd->pwm_off_delay;
pwm_combo0->pwm_duty = pwm_combo0->pwm_duty_min;
pwm_combo1->pwm_duty = pwm_combo1->pwm_duty_min;
/* bl_pwm_config_init(pwm_combo0);
bl_pwm_config_init(pwm_combo1); */
break;
#ifdef CONFIG_AML_LOCAL_DIMMING
case BL_CTRL_LOCAL_DIMMING:
ldim_probe(NULL, 1);
break;
#endif
#ifdef CONFIG_AML_BL_EXTERN
case BL_CTRL_EXTERN:
bl_extern_device_load(NULL, bconf->bl_extern_index);
break;
#endif
default:
if (lcd_debug_print_flag & LCD_DBG_PR_BL_NORMAL)
BLPR("invalid backlight control method\n");
break;
}
i = 0;
bl_gpio = bdrv->data->dft_conf[bdrv->index]->bl_gpio;
if (!bl_gpio) {
LCDERR("%s: bl_gpio is null\n", __func__);
return -1;
}
while (i < BL_GPIO_NUM_MAX) {
if (strcmp(bl_gpio[i], "invalid") == 0)
break;
strcpy(bconf->gpio_name[i], bl_gpio[i]);
i++;
}
for (j = i; j < BL_GPIO_NUM_MAX; j++)
strcpy(bconf->gpio_name[j], "invalid");
return 0;
}
static const char *bl_pinmux_str[] = {
"bl_pwm_on_pin", /* 0 */
"bl_pwm_vs_on_pin", /* 1 */
"bl_pwm_combo_0_on_pin", /* 2 */
"bl_pwm_combo_1_on_pin", /* 3 */
"bl_pwm_combo_0_vs_on_pin", /* 4 */
"bl_pwm_combo_1_vs_on_pin", /* 5 */
};
static int bl_pinmux_load_from_bsp(struct aml_bl_drv_s *bdrv)
{
struct bl_config_s *bconf = &bdrv->config;
char propname[50];
struct lcd_pinmux_ctrl_s *pinmux;
unsigned int i, j;
int pinmux_index = 0, set_cnt = 0, clr_cnt = 0;
struct bl_pwm_config_s *bl_pwm;
struct bl_pwm_config_s *pwm_combo0, *pwm_combo1;
if (!bdrv->data)
return -1;
if (!bdrv->data->dft_conf[bdrv->index]) {
BLERR("%s: dft_conf is NULL\n", __func__);
return -1;
}
bconf->bl_pinmux = bdrv->data->dft_conf[bdrv->index]->bl_pinmux;
if (!bconf->bl_pinmux) {
BLERR("%s: bl_pinmux is NULL\n", __func__);
return -1;
}
switch (bconf->method) {
case BL_CTRL_PWM:
bl_pwm = bconf->bl_pwm;
if (bl_pwm->pwm_port == BL_PWM_VS)
pinmux_index = 1;
else
pinmux_index = 0;
sprintf(propname,"%s", bl_pinmux_str[pinmux_index]);
pinmux = bconf->bl_pinmux;
for (i = 0; i < LCD_PINMX_MAX; i++) {
if (!pinmux)
break;
if (!pinmux->name)
break;
if (strncmp(pinmux->name, "invalid", 7) == 0)
break;
if (strncmp(pinmux->name, propname, strlen(propname)) == 0) {
for (j = 0; j < LCD_PINMUX_NUM; j++ ) {
if (pinmux->pinmux_set[j][0] ==
LCD_PINMUX_END)
break;
bl_pwm->pinmux_set[j][0] =
pinmux->pinmux_set[j][0];
bl_pwm->pinmux_set[j][1] =
pinmux->pinmux_set[j][1];
set_cnt++;
}
for (j = 0; j < LCD_PINMUX_NUM; j++ ) {
if (pinmux->pinmux_clr[j][0] ==
LCD_PINMUX_END)
break;
bl_pwm->pinmux_clr[j][0] =
pinmux->pinmux_clr[j][0];
bl_pwm->pinmux_clr[j][1] =
pinmux->pinmux_clr[j][1];
clr_cnt++;
}
break;
}
pinmux++;
}
if (set_cnt < LCD_PINMUX_NUM) {
bl_pwm->pinmux_set[set_cnt][0] = LCD_PINMUX_END;
bl_pwm->pinmux_set[set_cnt][1] = 0x0;
}
if (clr_cnt < LCD_PINMUX_NUM) {
bl_pwm->pinmux_clr[clr_cnt][0] = LCD_PINMUX_END;
bl_pwm->pinmux_clr[clr_cnt][1] = 0x0;
}
if (lcd_debug_print_flag & LCD_DBG_PR_BL_NORMAL) {
i = 0;
while (i < LCD_PINMUX_NUM) {
if (bl_pwm->pinmux_set[i][0] == LCD_PINMUX_END)
break;
BLPR("bl_pinmux set: %d, 0x%08x\n",
bl_pwm->pinmux_set[i][0],
bl_pwm->pinmux_set[i][1]);
i++;
}
i = 0;
while (i < LCD_PINMUX_NUM) {
if (bl_pwm->pinmux_clr[i][0] == LCD_PINMUX_END)
break;
BLPR("bl_pinmux clr: %d, 0x%08x\n",
bl_pwm->pinmux_clr[i][0],
bl_pwm->pinmux_clr[i][1]);
i++;
}
}
break;
case BL_CTRL_PWM_COMBO:
pwm_combo0 = bconf->bl_pwm_combo0;
pwm_combo1 = bconf->bl_pwm_combo1;
if (pwm_combo0->pwm_port == BL_PWM_VS)
sprintf(propname, "%s", bl_pinmux_str[4]);
else
sprintf(propname, "%s", bl_pinmux_str[2]);
pinmux = bconf->bl_pinmux;
for (i = 0; i < LCD_PINMX_MAX; i++) {
if (!pinmux)
break;
if (!pinmux->name)
break;
if (strncmp(pinmux->name, "invalid", 7) == 0)
break;
if (strncmp(pinmux->name, propname,
strlen(propname)) == 0) {
for (j = 0; j < LCD_PINMUX_NUM; j++ ) {
if (pinmux->pinmux_set[j][0] ==
LCD_PINMUX_END)
break;
pwm_combo0->pinmux_set[j][0] =
pinmux->pinmux_set[j][0];
pwm_combo0->pinmux_set[j][1] =
pinmux->pinmux_set[j][1];
set_cnt++;
}
for (j = 0; j < LCD_PINMUX_NUM; j++ ) {
if (pinmux->pinmux_clr[j][0] ==
LCD_PINMUX_END)
break;
pwm_combo0->pinmux_clr[j][0] =
pinmux->pinmux_clr[j][0];
pwm_combo0->pinmux_clr[j][1] =
pinmux->pinmux_clr[j][1];
clr_cnt++;
}
break;
}
pinmux++;
}
if (set_cnt < LCD_PINMUX_NUM) {
pwm_combo0->pinmux_set[set_cnt][0] = LCD_PINMUX_END;
pwm_combo0->pinmux_set[set_cnt][1] = 0x0;
}
if (clr_cnt < LCD_PINMUX_NUM) {
pwm_combo0->pinmux_clr[clr_cnt][0] = LCD_PINMUX_END;
pwm_combo0->pinmux_clr[clr_cnt][1] = 0x0;
}
if (lcd_debug_print_flag & LCD_DBG_PR_BL_NORMAL) {
i = 0;
while (i < LCD_PINMUX_NUM) {
if (pwm_combo0->pinmux_set[i][0] ==
LCD_PINMUX_END)
break;
BLPR("pwm_combo0 pinmux_set: %d, 0x%08x\n",
pwm_combo0->pinmux_set[i][0],
pwm_combo0->pinmux_set[i][1]);
i++;
}
i = 0;
while (i < LCD_PINMUX_NUM) {
if (pwm_combo0->pinmux_clr[i][0] ==
LCD_PINMUX_END)
break;
BLPR("pwm_combo0 pinmux_clr: %d, 0x%08x\n",
pwm_combo0->pinmux_clr[i][0],
pwm_combo0->pinmux_clr[i][1]);
i++;
}
}
if (pwm_combo1->pwm_port == BL_PWM_VS)
sprintf(propname, "%s", bl_pinmux_str[5]);
else
sprintf(propname, "%s", bl_pinmux_str[3]);
pinmux = bconf->bl_pinmux;
set_cnt = 0;
clr_cnt = 0;
for (i = 0; i < LCD_PINMX_MAX; i++) {
if (!pinmux)
break;
if (!pinmux->name)
break;
if (strncmp(pinmux->name, "invalid", 7) == 0)
break;
if (strncmp(pinmux->name, propname,
strlen(propname)) == 0) {
for (j = 0; j < LCD_PINMUX_NUM; j++ ) {
if (pinmux->pinmux_set[j][0] ==
LCD_PINMUX_END)
break;
pwm_combo1->pinmux_set[j][0] =
pinmux->pinmux_set[j][0];
pwm_combo1->pinmux_set[j][1] =
pinmux->pinmux_set[j][1];
set_cnt++;
}
for (j = 0; j < LCD_PINMUX_NUM; j++ ) {
if (pinmux->pinmux_clr[j][0] ==
LCD_PINMUX_END)
break;
pwm_combo1->pinmux_clr[j][0] =
pinmux->pinmux_clr[j][0];
pwm_combo1->pinmux_clr[j][1] =
pinmux->pinmux_clr[j][1];
clr_cnt++;
}
break;
}
pinmux++;
}
if (set_cnt < LCD_PINMUX_NUM) {
pwm_combo1->pinmux_set[set_cnt][0] = LCD_PINMUX_END;
pwm_combo1->pinmux_set[set_cnt][1] = 0x0;
}
if (clr_cnt < LCD_PINMUX_NUM) {
pwm_combo1->pinmux_clr[clr_cnt][0] = LCD_PINMUX_END;
pwm_combo1->pinmux_clr[clr_cnt][1] = 0x0;
}
if (lcd_debug_print_flag & LCD_DBG_PR_BL_NORMAL) {
i = 0;
while (i < LCD_PINMUX_NUM) {
if (pwm_combo1->pinmux_set[i][0] == LCD_PINMUX_END)
break;
BLPR("pwm_combo1 pinmux_set: %d, 0x%08x\n",
pwm_combo1->pinmux_set[i][0],
pwm_combo1->pinmux_set[i][1]);
i++;
}
i = 0;
while (i < LCD_PINMUX_NUM) {
if (pwm_combo1->pinmux_clr[i][0] == LCD_PINMUX_END)
break;
BLPR("pwm_combo1 pinmux_clr: %d, 0x%08x\n",
pwm_combo1->pinmux_clr[i][0],
pwm_combo1->pinmux_clr[i][1]);
i++;
}
}
break;
default:
break;
}
return 0;
}
static int bl_config_load(char *dt_addr, int load_id, struct aml_bl_drv_s *bdrv)
{
char *bl_off_policy_str, str[30];
unsigned int temp;
int ret;
bdrv->state = 0;
/* load bl config */
if (load_id & 0x1) { /* dts */
if (load_id & 0x10) { /* unifykey */
if (lcd_debug_print_flag & LCD_DBG_PR_BL_NORMAL)
BLPR("[%d]: load config from unifykey\n", bdrv->index);
ret = bl_config_load_from_unifykey(dt_addr, bdrv);
} else { /* dts */
#ifdef CONFIG_OF_LIBFDT
if (lcd_debug_print_flag & LCD_DBG_PR_BL_NORMAL)
BLPR("[%d]: load config from dts\n", bdrv->index);
if (bdrv->config.index == 0xff) {
bdrv->config.method = BL_CTRL_MAX;
BLPR("[%d]: no backlight exist\n", bdrv->index);
return -1;
}
ret = bl_config_load_from_dts(dt_addr, bdrv);
#endif
}
} else { /* bsp */
if (load_id & 0x10) { /* unifykey */
if (lcd_debug_print_flag & LCD_DBG_PR_BL_NORMAL)
BLPR("[%d]: load config from unifykey\n", bdrv->index);
ret = bl_config_load_from_unifykey(dt_addr, bdrv);
} else { /* bsp */
if (lcd_debug_print_flag & LCD_DBG_PR_BL_NORMAL)
BLPR("[%d]: load config from bsp\n", bdrv->index);
ret = bl_config_load_from_bsp(bdrv);
}
}
if (ret) {
bdrv->config.method = BL_CTRL_MAX;
BLPR("[%d]: invalid backlight config\n", bdrv->index);
return -1;
}
bl_pinmux_load_from_bsp(bdrv);
if (lcd_debug_print_flag & LCD_DBG_PR_BL_NORMAL) {
bl_config_print(bdrv);
} else {
BLPR("[%d]: name: %s, method: %d\n",
bdrv->index, bdrv->config.name, bdrv->config.method);
}
/* get bl_off_policy */
bdrv->bl_off_policy = BL_OFF_POLICY_NONE;
if (bdrv->index == 0)
sprintf(str, "bl_off");
else
sprintf(str, "bl%d_off", bdrv->index);
bl_off_policy_str = env_get(str);
if (bl_off_policy_str) {
if (strncmp(bl_off_policy_str, "none", 2) == 0)
bdrv->bl_off_policy = BL_OFF_POLICY_NONE;
else if (strncmp(bl_off_policy_str, "always", 2) == 0)
bdrv->bl_off_policy = BL_OFF_POLICY_ALWAYS;
else if (strncmp(bl_off_policy_str, "once", 2) == 0)
bdrv->bl_off_policy = BL_OFF_POLICY_ONCE;
BLPR("[%d]: bl_off_policy: %s\n", bdrv->index, bl_off_policy_str);
}
/* get bl_level */
if (bdrv->index == 0)
sprintf(str, "bl_level");
else
sprintf(str, "bl%d_level", bdrv->index);
temp = env_get_ulong(str, 10, 0xffff);
if (temp != 0xffff) {
bdrv->config.level_default = temp;
BLPR("[%d]: bl_level: %d\n", bdrv->index, bdrv->config.level_default);
}
/* get factory_bl_on_delay */
if (bdrv->index == 0)
sprintf(str, "factory_bl_on_delay");
else
sprintf(str, "factory_bl%d_on_delay", bdrv->index);
temp = env_get_ulong(str, 10, 0xffff);
if (temp != 0xffff) {
bdrv->config.level_default = temp;
BLPR("[%d]: bl_level: %d\n", bdrv->index, bdrv->config.level_default);
}
return 0;
}
static int lcd_bl_init_load_from_dts(char *dtaddr, struct aml_bl_drv_s *bdrv)
{
#ifdef CONFIG_OF_LIBFDT
int parent_offset;
char *propdata, *p, snode[15];
const char *str;
int i, j;
int ret = 0;
if (bdrv->index == 0)
sprintf(snode, "/backlight");
else
sprintf(snode, "/backlight%d", bdrv->index);
/* check key_valid */
parent_offset = fdt_path_offset(dtaddr, snode);
if (parent_offset < 0) {
BLERR("not find %s node: %s\n", snode, fdt_strerror(parent_offset));
return -1;
}
propdata = (char *)fdt_getprop(dtaddr, parent_offset, "key_valid", NULL);
if (!propdata) {
BLERR("failed to get key_valid\n");
bdrv->key_valid = 0;
} else {
bdrv->key_valid = be32_to_cpup((u32*)propdata);
}
propdata = (char *)fdt_getprop(dtaddr, parent_offset, "status", NULL);
if (!propdata) {
BLPR("failed to get status, default to disabled\n");
return -1;
} else {
if (strncmp(propdata, "okay", 2)) {
BLPR("status disabled\n");
return -1;
}
}
/* gpio */
i = 0;
propdata = (char *)fdt_getprop(dtaddr, parent_offset, "bl_gpio_names", NULL);
if (!propdata) {
BLERR("failed to get bl_gpio_names\n");
} else {
p = propdata;
while (i < BL_GPIO_NUM_MAX) {
if (i > 0)
p += strlen(p) + 1;
str = p;
if (strlen(str) == 0)
break;
strcpy(bdrv->config.gpio_name[i], str);
if (lcd_debug_print_flag & LCD_DBG_PR_BL_NORMAL)
BLPR("i=%d, gpio=%s\n", i, bdrv->config.gpio_name[i]);
i++;
}
}
for (j = i; j < BL_GPIO_NUM_MAX; j++)
strcpy(bdrv->config.gpio_name[j], "invalid");
return ret;
#elif
return -1;
#endif
}
static int lcd_bl_init_load_from_bsp(struct aml_bl_drv_s *bdrv)
{
return 0;
}
int aml_bl_probe(char *dtaddr, int load_id)
{
struct aml_lcd_data_s *pdata = aml_lcd_get_data();
struct aml_bl_drv_s *bdrv;
int load_id_bl;
int i, ret;
if (!pdata) {
BLERR("%s: pdata is NULL\n", __func__);
return -1;
}
aml_bl_pwm_reg_config_init(pdata);
load_id_bl = load_id;
for (i = 0; i < LCD_MAX_DRV; i++) {
if (bl_index_lut[i] >= BL_INDEX_INVALID)
continue;
if (!bl_driver[i]) {
bl_driver[i] = (struct aml_bl_drv_s *)
malloc(sizeof(struct aml_bl_drv_s));
if (!bl_driver[i]) {
BLERR("%s: Not enough memory\n", __func__);
return -1;
}
}
bdrv = bl_driver[i];
memset(bdrv, 0, sizeof(struct aml_bl_drv_s));
bdrv->index = i;
bdrv->data = pdata;
/* default config */
bdrv->config.index = bl_index_lut[i];
bdrv->config.method = BL_CTRL_MAX;
bdrv->config.en_gpio = 0xff;
bdrv->config.extern_index = 0xff;
bdrv->factory_bl_on_delay = -1;
if (load_id_bl & 0x1) {
ret = lcd_bl_init_load_from_dts(dtaddr, bdrv);
if (ret) {
load_id_bl = 0x0;
ret = lcd_bl_init_load_from_bsp(bdrv);
if (ret) {
free(bl_driver[i]);
bl_driver[i] = NULL;
return -1;
}
}
} else {
ret = lcd_bl_init_load_from_bsp(bdrv);
if (ret) {
free(bl_driver[i]);
bl_driver[i] = NULL;
return -1;
}
}
if (bdrv->key_valid)
load_id_bl |= 0x10;
/* load bl config */
bl_config_load(dtaddr, load_id_bl, bdrv);
bl_power_init_off(bdrv);
}
return 0;
}
int aml_bl_remove(void)
{
int i = 0;
for (i = 0; i < LCD_MAX_DRV; i++) {
if (bl_driver[i])
free(bl_driver[i]);
bl_driver[i] = NULL;
}
return 0;
}
int aml_bl_index_add(int drv_index, int conf_index)
{
if (drv_index >= LCD_MAX_DRV) {
BLERR("%s: invalid drv_index: %d\n", __func__, drv_index);
return -1;
}
bl_index_lut[drv_index] = conf_index;
if (lcd_debug_print_flag & LCD_DBG_PR_BL_NORMAL) {
BLPR("%s: drv_index %d, config index: %d\n",
__func__, drv_index, conf_index);
}
return 0;
}
int aml_bl_index_remove(int drv_index)
{
if (drv_index >= LCD_MAX_DRV) {
BLERR("%s: invalid drv_index: %d\n", __func__, drv_index);
return -1;
}
bl_index_lut[drv_index] = BL_INDEX_INVALID;
if (lcd_debug_print_flag & LCD_DBG_PR_BL_NORMAL)
BLPR("%s: drv_index %d\n", __func__, drv_index);
return 0;
}
int aml_bl_init(void)
{
int i;
for (i = 0; i < LCD_MAX_DRV; i++) {
if (bl_driver[i])
free(bl_driver[i]);
bl_driver[i] = NULL;
bl_index_lut[i] = BL_INDEX_INVALID;
}
return 0;
}
void aml_bl_driver_enable(int index)
{
struct aml_bl_drv_s *bdrv;
bdrv = aml_bl_get_driver(index);
if (!bdrv)
return;
bl_pwm_config_update(&bdrv->config);
bl_set_level(bdrv, bdrv->config.level_default);
bl_power_ctrl(bdrv, 1);
}
void aml_bl_driver_disable(int index)
{
struct aml_bl_drv_s *bdrv;
bdrv = aml_bl_get_driver(index);
if (!bdrv)
return;
bl_power_ctrl(bdrv, 0);
}
void aml_bl_set_level(int index, unsigned int level)
{
struct aml_bl_drv_s *bdrv;
bdrv = aml_bl_get_driver(index);
if (!bdrv)
return;
bl_set_level(bdrv, level);
}
unsigned int aml_bl_get_level(int index)
{
struct aml_bl_drv_s *bdrv;
bdrv = aml_bl_get_driver(index);
if (!bdrv)
return 0;
return bdrv->level;
}
void aml_bl_config_print(int index)
{
struct aml_bl_drv_s *bdrv;
bdrv = aml_bl_get_driver(index);
if (!bdrv)
return;
bl_config_print(bdrv);
}