blob: 7f7158300894bdd2247cff2685c4edfcb1e97349 [file] [log] [blame]
/*
* drivers/display/lcd/bl_extern/bl_extern.c
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the named License,
* or any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
*/
#include <common.h>
#include <malloc.h>
#include <asm/arch/gpio.h>
#ifdef CONFIG_OF_LIBFDT
#include <libfdt.h>
#endif
#ifdef CONFIG_SYS_I2C_AML
#include <aml_i2c.h>
#endif
#include <amlogic/aml_lcd.h>
#include <amlogic/aml_bl_extern.h>
#include "bl_extern.h"
#include "../aml_lcd_common.h"
unsigned int bl_extern_brightness;
static struct aml_bl_extern_driver_s bl_extern_driver;
static int bl_extern_set_level(unsigned int level)
{
bl_extern_brightness = level & 0xff;
if (bl_extern_driver.device_bri_update)
bl_extern_driver.device_bri_update(level);
return 0;
}
static int bl_extern_power_on(void)
{
int ret = 0;
BLEX("%s\n", __func__);
if (bl_extern_driver.device_power_on)
bl_extern_driver.device_power_on();
/* restore bl level */
bl_extern_set_level(bl_extern_brightness);
return ret;
}
static int bl_extern_power_off(void)
{
int ret = 0;
BLEX("%s\n", __func__);
if (bl_extern_driver.device_power_off)
bl_extern_driver.device_power_off();
return ret;
}
static struct aml_bl_extern_driver_s bl_extern_driver = {
.power_on = bl_extern_power_on,
.power_off = bl_extern_power_off,
.set_level = bl_extern_set_level,
.config_print = NULL,
.device_power_on = NULL,
.device_power_off = NULL,
.device_bri_update = NULL,
.config = NULL,
};
struct aml_bl_extern_driver_s *aml_bl_extern_get_driver(void)
{
return &bl_extern_driver;
}
static void bl_extern_config_print(void)
{
struct aml_bl_extern_driver_s *bl_extern = aml_bl_extern_get_driver();
BLEX("%s:\n", __func__);
switch (bl_extern->config->type) {
case BL_EXTERN_I2C:
printf("index: %d\n"
"name: %s\n"
"type: i2c(%d)\n"
"i2c_addr: 0x%02x\n"
"i2c_bus: %d\n"
"dim_min: %d\n"
"dim_max: %d\n",
bl_extern->config->index,
bl_extern->config->name,
bl_extern->config->type,
bl_extern->config->i2c_addr,
bl_extern->config->i2c_bus,
bl_extern->config->dim_min,
bl_extern->config->dim_max);
break;
case BL_EXTERN_SPI:
break;
case BL_EXTERN_MIPI:
printf("index: %d\n"
"name: %s\n"
"type: mipi(%d)\n"
"dim_min: %d\n"
"dim_max: %d\n",
bl_extern->config->index,
bl_extern->config->name,
bl_extern->config->type,
bl_extern->config->dim_min,
bl_extern->config->dim_max);
break;
default:
break;
}
}
#ifdef CONFIG_OF_LIBFDT
#ifdef CONFIG_SYS_I2C_AML
static unsigned char bl_extern_get_i2c_bus_str(const char *str)
{
unsigned char i2c_bus;
if (strncmp(str, "i2c_bus_ao", 10) == 0)
i2c_bus = AML_I2C_MASTER_AO;
else if (strncmp(str, "i2c_bus_a", 9) == 0)
i2c_bus = AML_I2C_MASTER_A;
else if (strncmp(str, "i2c_bus_b", 9) == 0)
i2c_bus = AML_I2C_MASTER_B;
else if (strncmp(str, "i2c_bus_c", 9) == 0)
i2c_bus = AML_I2C_MASTER_C;
else if (strncmp(str, "i2c_bus_d", 9) == 0)
i2c_bus = AML_I2C_MASTER_D;
else {
i2c_bus = BL_EXTERN_I2C_BUS_INVALID;
BLEXERR("invalid i2c_bus: %s\n", str);
}
return i2c_bus;
}
#endif
static int bl_extern_config_from_dts(char *dtaddr, int index)
{
int ret = 0;
int parent_offset, child_offset;
char propname[30];
char *propdata;
struct aml_bl_extern_driver_s *bl_extern = aml_bl_extern_get_driver();
unsigned char bl_ext_i2c_bus = BL_EXTERN_I2C_BUS_INVALID;
parent_offset = fdt_path_offset(dtaddr, "/bl_extern");
if (parent_offset < 0) {
BLEXERR("bl: not find /backlight node %s\n", fdt_strerror(parent_offset));
return -1;
}
propdata = (char *)fdt_getprop(dtaddr, parent_offset, "status", NULL);
if (propdata == NULL) {
BLEXERR("bl: not find status, default to disabled\n");
return -1;
} else {
if (strncmp(propdata, "okay", 2)) {
BLEX("bl: status disabled\n");
return -1;
}
}
propdata = (char *)fdt_getprop(dtaddr, parent_offset, "i2c_bus", NULL);
if (propdata == NULL)
bl_ext_i2c_bus = BL_EXTERN_I2C_BUS_INVALID;
else
bl_ext_i2c_bus = bl_extern_get_i2c_bus_str(propdata);
sprintf(propname,"/bl_extern/extern_%d", index);
child_offset = fdt_path_offset(dtaddr, propname);
if (child_offset < 0) {
BLEXERR("bl: not find %s node: %s\n", propname, fdt_strerror(child_offset));
return -1;
}
propdata = (char *)fdt_getprop(dtaddr, child_offset, "index", NULL);
if (propdata == NULL) {
BLEXERR("get index failed, exit\n");
return -1;
} else {
if (be32_to_cpup((u32*)propdata) != index) {
BLEXERR("index not match, exit\n");
return -1;
} else {
bl_extern->config->index = be32_to_cpup((u32*)propdata);
}
}
propdata = (char *)fdt_getprop(dtaddr, child_offset, "extern_name", NULL);
if (propdata == NULL) {
BLEXERR("failed to get extern_name\n");
sprintf(bl_extern->config->name, "extern_%d", index);
} else {
strcpy(bl_extern->config->name, propdata);
}
propdata = (char *)fdt_getprop(dtaddr, child_offset, "type", NULL);
if (propdata == NULL) {
bl_extern->config->type = BL_EXTERN_MAX;
BLEXERR("get type failed, exit\n");
return -1;
} else {
bl_extern->config->type = be32_to_cpup((u32*)propdata);
}
propdata = (char *)fdt_getprop(dtaddr, child_offset, "dim_max_min", NULL);
if (propdata == NULL) {
BLEXERR("failed to get bl_level_attr\n");
} else {
bl_extern->config->dim_max = be32_to_cpup((u32*)propdata);
bl_extern->config->dim_min = be32_to_cpup((((u32*)propdata)+1));
}
switch (bl_extern->config->type) {
case BL_EXTERN_I2C:
#ifdef CONFIG_SYS_I2C_AML
propdata = (char *)fdt_getprop(dtaddr, child_offset, "i2c_address", NULL);
if (propdata == NULL) {
BLEXERR("get %s i2c_address failed, exit\n", bl_extern->config->name);
bl_extern->config->i2c_addr = 0xff;
return -1;
} else {
bl_extern->config->i2c_addr = (unsigned char)(be32_to_cpup((u32*)propdata));
}
if (bl_ext_i2c_bus == BL_EXTERN_I2C_BUS_INVALID) { /* compatible for kernel3.14 */
propdata = (char *)fdt_getprop(dtaddr, child_offset, "i2c_bus", NULL);
if (propdata == NULL) {
BLEXERR("get %s i2c_bus failed, exit\n", bl_extern->config->name);
bl_extern->config->i2c_bus = BL_EXTERN_I2C_BUS_INVALID;
return -1;
} else {
bl_extern->config->i2c_bus = bl_extern_get_i2c_bus_str(propdata);
}
} else {
bl_extern->config->i2c_bus = bl_ext_i2c_bus;
}
if (lcd_debug_print_flag)
BLEX("%s: i2c_bus= %d\n", bl_extern->config->name, bl_extern->config->i2c_bus);
#else
BLEXERR("system has no i2c support\n");
#endif
break;
case BL_EXTERN_SPI:
break;
case BL_EXTERN_MIPI:
break;
default:
break;
}
return ret;
}
#endif
static int bl_extern_add_driver(void)
{
int ret = 0;
struct bl_extern_config_s *extconf = bl_extern_driver.config;
if (strcmp(extconf->name, "i2c_lp8556") == 0) {
#ifdef CONFIG_SYS_I2C_AML
#ifdef CONFIG_AML_BL_EXTERN_I2C_LP8556
ret = i2c_lp8556_probe();
#endif
#endif
goto bl_extern_add_driver_next;
} else if (strcmp(extconf->name, "mipi_lt070me05") == 0) {
#ifdef CONFIG_AML_BL_EXTERN_MIPI_IT070ME05
ret = mipi_lt070me05_probe();
#endif
goto bl_extern_add_driver_next;
} else {
BLEXERR("invalid device name: %s\n", extconf->name);
ret = -1;
}
bl_extern_add_driver_next:
if (ret) {
BLEXERR("add device driver failed %s(%d)\n",
extconf->name, extconf->index);
} else {
BLEX("add device driver %s(%d)\n",
extconf->name, extconf->index);
}
return ret;
}
int aml_bl_extern_device_load(char *dtaddr, int index)
{
int ret = 0;
bl_extern_driver.config = &bl_extern_config_dtf;
if (dtaddr) {
if (lcd_debug_print_flag)
BLEX("load bl_extern_config from dts\n");
bl_extern_config_from_dts(dtaddr, index);
}
bl_extern_add_driver();
bl_extern_driver.config_print = bl_extern_config_print;
BLEX("%s OK\n", __func__);
return ret;
}