bl: add bl_extern driver

PD#148374: bl: add bl_extern driver

Change-Id: I8019ab4c2d55c37e14f7b266166408fd5a5a58e3
Signed-off-by: Weiming Liu <weiming.liu@amlogic.com>
This commit is contained in:
Weiming Liu
2017-08-01 13:52:23 +08:00
parent 17866ccad8
commit f652dec4de
16 changed files with 849 additions and 1098 deletions

View File

@@ -14034,3 +14034,11 @@ M: Alex Deng <alex.deng@amlogic.com>
F: arch/arm64/boot/dts/amlogic/axg_s400_v03.dts
F: arch/arm64/boot/dts/amlogic/axg_s420_v03.dts
AMLOGIC BL_EXTERN driver
M: Weiming Liu <weiming.liu@amlogic.com>
F: drivers/amlogic/media/vout/backlight/bl_extern/bl_extern.dts
F: drivers/amlogic/media/vout/backlight/bl_extern/bl_extern.h
F: drivers/amlogic/media/vout/backlight/bl_extern/mipi_lt070me05.c
F: drivers/amlogic/media/vout/backlight/bl_extern/aml_bl_extern.dts
F: drivers/amlogic/media/vout/backlight/bl_extern/mipi_LT070ME05.c
F: drivers/amlogic/media/vout/backlight/bl_extern/pmu_aml1218.c

View File

@@ -138,7 +138,8 @@
/* level_attr: max, min, mid, mid_mapping */
bl_level_attr = <255 10 128 102>;
bl_ctrl_method = <1>; /* 1=pwm, 2=pwm_combo, 3=extern */
/* 1=pwm, 2=pwm_combo, 3=ldim, 4=extern */
bl_ctrl_method = <1>;
/* power_attr:
* en_gpio_index, on_value, off_value,
* on_delay(ms), off_delay(ms)
@@ -159,6 +160,22 @@
*/
bl_pwm_power = <0 0 10 10>;
};
backlight_1{
index = <1>;
bl_name = "bl_extern";
bl_level_default_uboot_kernel = <100 100>;
/* level_attr: max, min, mid, mid_mapping */
bl_level_attr = <255 10 128 102>;
/* 1=pwm, 2=pwm_combo, 3=ldim, 4=extern */
bl_ctrl_method = <4>;
/* power_attr:
* en_gpio_index, on_value, off_value,
* on_delay(ms), off_delay(ms)
*/
bl_power_attr = <1 1 0 200 200>;
bl_extern_index = <1>;
};
};
bl_pwm_conf:bl_pwm_conf{
@@ -167,5 +184,33 @@
pwms = <&pwm_ab MESON_PWM_1 30040 0>;
};
};
bl_extern{
compatible = "amlogic, bl_extern";
dev_name = "bl_extern";
status = "disabled";
extern_0{
index = <0>;
extern_name = "i2c_lp8556";
/*bl_extern_driver type: 0=i2c, 1=spi, 2=mipi*/
type = <0>;
i2c_address = <0x2c>; /** 7bit i2c address */
i2c_bus = "i2c_bus_c";
dim_max_min = <255 10>;
};
extern_1{
index = <1>;
extern_name = "mipi_lt070me05";
/*bl_extern_driver type: 0=i2c, 1=spi, 2=mipi*/
type = <2>;
dim_max_min = <255 10>;
};
};
};/* end of panel */

View File

@@ -235,6 +235,9 @@ CONFIG_AMLOGIC_LCD_TABLET=y
CONFIG_AMLOGIC_LCD_EXTERN=y
CONFIG_AMLOGIC_LCD_EXTERN_MIPI_KD080D13=y
CONFIG_AMLOGIC_BACKLIGHT=y
CONFIG_AMLOGIC_BL_EXTERN=y
CONFIG_AMLOGIC_BL_EXTERN_I2C_LP8556=y
CONFIG_AMLOGIC_BL_EXTERN_MIPI_LT070ME05=y
CONFIG_AMLOGIC_VOUT_SERVE=y
CONFIG_AMLOGIC_MEDIA_FB=y
CONFIG_AMLOGIC_MEDIA_FB_OSD_SYNC_FENCE=y

View File

@@ -996,7 +996,7 @@ static void aml_bl_set_level(unsigned int level)
bl_set_level_ldim(level);
break;
#endif
#ifdef CONFIG_AML_BL_TABLET_EXTERN
#ifdef CONFIG_AMLOGIC_BL_EXTERN
case BL_CTRL_EXTERN:
bl_set_level_extern(level);
break;
@@ -1524,8 +1524,18 @@ static int aml_bl_config_load_from_dts(struct bl_config_s *bconf,
case BL_CTRL_LOCAL_DIMING:
break;
#endif
#ifdef CONFIG_AMLOGIC_BL_EXTERN
case BL_CTRL_EXTERN:
/* get bl_extern_index from dts */
ret = of_property_read_u32(child, "bl_extern_index", &bl_para[0]);
if (ret)
BLERR("failed to get bl_extern_index\n");
else {
bconf->bl_extern_index = bl_para[0];
BLPR("get bl_extern_index = %d\n", bconf->bl_extern_index);
}
break;
#endif
default:
break;
}
@@ -1908,6 +1918,12 @@ static int aml_bl_config_load(struct bl_config_s *bconf,
aml_ldim_probe(pdev);
break;
#endif
#ifdef CONFIG_AMLOGIC_BL_EXTERN
case BL_CTRL_EXTERN:
aml_bl_extern_device_load(bconf->bl_extern_index);
break;
#endif
default:
break;
}
@@ -2139,6 +2155,10 @@ static ssize_t bl_status_read(struct class *class,
#ifdef CONFIG_AMLOGIC_LOCAL_DIMMING
struct aml_ldim_driver_s *ldim_drv = aml_ldim_get_driver();
#endif
#ifdef CONFIG_AMLOGIC_BL_EXTERN
struct aml_bl_extern_driver_s *bl_extern = aml_bl_extern_get_driver();
#endif
ssize_t len = 0;
len = sprintf(buf, "read backlight status:\n"
@@ -2223,8 +2243,12 @@ static ssize_t bl_status_read(struct class *class,
ldim_drv->config_print();
break;
#endif
#ifdef CONFIG_AMLOGIC_BL_EXTERN
case BL_CTRL_EXTERN:
if (bl_extern->config_print)
bl_extern->config_print();
break;
#endif
default:
len += sprintf(buf+len, "wrong backlight control method\n");
break;

View File

@@ -8,17 +8,6 @@ config AMLOGIC_BL_EXTERN
such as i2c or mipi initial
According to choose the corresponding bl_extern inside index bl_extern driver
config AMLOGIC_BL_EXTERN_PMU_AML1218
bool "Amlogic backlight pmu aml1218"
depends on AMLOGIC_BL_EXTERN
default n
help
pmu aml1218 backlight controller support.
Once the backlight power on, according to the timing requirements,
through the aml1218 to write data to the backlight,
make its initialization
config AMLOGIC_BL_EXTERN_I2C_LP8556
bool "Amlogic backlight i2c lp8556"
depends on AMLOGIC_BL_EXTERN
@@ -30,7 +19,7 @@ config AMLOGIC_BL_EXTERN_I2C_LP8556
make its initialization
config AMLOGIC_BL_EXTERN_MIPI_LT070ME05
bool "Amlogic backlight mipi LT070ME05"
bool "Amlogic backlight mipi lt070me05"
depends on AMLOGIC_BL_EXTERN
default n
help

View File

@@ -1,6 +1,5 @@
obj-$(CONFIG_AMLOGIC_BL_EXTERN) += bl_extern.o
obj-$(CONFIG_AMLOGIC_BL_EXTERN_I2C_LP8556) += i2c_lp8556.o
obj-$(CONFIG_AMLOGIC_BL_EXTERN_PMU_AML1218) += pmu_aml1218.o
obj-$(CONFIG_AMLOGIC_BL_EXTERN_MIPI_LT070ME05) += mipi_LT070ME05.o
obj-$(CONFIG_AMLOGIC_BL_EXTERN_MIPI_LT070ME05) += mipi_lt070me05.o

View File

@@ -1,59 +0,0 @@
/*
* drivers/amlogic/media/vout/backlight/bl_extern/aml_bl_extern.dts
*
* Copyright (C) 2017 Amlogic, Inc. All rights reserved.
*
* 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 License, or
* (at your option) 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.
*
*/
bl_extern_pmu_aml1218{
compatible = "amlogic, bl_pmu_aml1218";
dev_name ="bl_pmu_aml1218";
status = "disabled"; /** "disabled" or "okay" */
GPIODV_28-gpios = <&gpio GPIODV_28 0>;
gpio_enable_on_off = "GPIODV_28","1","0";
/* gpio("n"for none),
* on/off(1=output high, 0=output low, 2=input)
*/
type = <2>; /** bl_extern_driver type: 0=i2c, 1=spi, 2=other */
dim_max_min = <0x1 0x1b>;
};
bl_extern_i2c_lp8556{
compatible = "amlogic, bl_i2c_lp8556";
dev_name ="bl_i2c_lp8556";
status = "disabled"; /** "disabled" or "okay" */
GPIODV_28-gpios = <&gpio GPIODV_28 0>;
gpio_enable_on_off = "GPIODV_28","1","0";
/* gpio("n"for none),
* on/off(1=output high, 0=output low, 2=input)
*/
type = <0>; /** bl_extern_driver type: 0=i2c, 1=spi, 2=other */
i2c_address = <0x2c>; /** 7bit i2c address */
i2c_bus = "i2c_bus_b";
dim_max_min = <255 10>;
};
bl_extern_mipi_LT070ME05{
compatible = "amlogic, bl_mipi_LT070ME05";
dev_name ="bl_mipi_LT070ME056";
status = "disabled"; /** "disabled" or "okay" */
GPIODV_28-gpios = <&gpio GPIODV_28 0>;
gpio_enable_on_off = "GPIODV_28","1","0";
/* gpio("n"for none),
* on/off(1=output high, 0=output low, 2=input)
*/
type = <2>; /** bl_extern_driver type: 0=i2c, 1=spi, 2=other */
dim_max_min = <255 10>;
};

View File

@@ -26,209 +26,373 @@
#include <linux/slab.h>
#include <linux/of.h>
#include <linux/amlogic/media/vout/lcd/aml_bl_extern.h>
#include <linux/amlogic/media/vout/lcd/lcd_vout.h>
#include <linux/amlogic/media/vout/lcd/lcd_unifykey.h>
#include <linux/amlogic/media/vout/lcd/aml_bl.h>
#include "bl_extern.h"
#ifdef BL_EXT_DEBUG_INFO
#define DBG_PRINT(...) pr_info(__VA_ARGS__)
#else
#define DBG_PRINT(...)
#endif
unsigned int bl_extern_brightness;
static struct aml_bl_extern_driver_s bl_extern_driver;
static struct aml_bl_extern_driver_t bl_ext_driver = {
.type = BL_EXTERN_MAX,
.name = NULL,
.power_on = NULL,
.power_off = NULL,
.set_level = NULL,
};
struct aml_bl_extern_driver_t *aml_bl_extern_get_driver(void)
static int bl_extern_set_level(unsigned int level)
{
return &bl_ext_driver;
}
bl_extern_brightness = level & 0xff;
int bl_extern_driver_check(void)
{
struct aml_bl_extern_driver_t *bl_ext;
if (bl_extern_driver.device_bri_update)
bl_extern_driver.device_bri_update(level);
bl_ext = aml_bl_extern_get_driver();
if (bl_ext) {
if (bl_ext->type < BL_EXTERN_MAX) {
pr_err("[warning]: bl_extern has already exist (%s)\n",
bl_ext->name);
return -1;
}
} else {
pr_err("get bl_extern_driver failed\n");
}
return 0;
}
int get_bl_extern_dt_data(struct device dev, struct bl_extern_config_t *pdata)
static int bl_extern_power_on(void)
{
int ret;
struct device_node *of_node = dev.of_node;
u32 bl_para[2];
const char *str;
struct gpio_desc *bl_extern_gpio;
int ret = 0;
ret = of_property_read_string(of_node, "dev_name",
(const char **)&pdata->name);
if (ret) {
pdata->name = "aml_bl_extern";
pr_err("warning: get dev_name failed\n");
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 = {
.index = BL_EXTERN_INDEX_INVALID,
.name = "none",
.type = BL_EXTERN_MAX,
.i2c_addr = 0xff,
.i2c_bus = BL_EXTERN_I2C_BUS_MAX,
.dim_min = 10,
.dim_max = 255,
},
};
struct aml_bl_extern_driver_s *aml_bl_extern_get_driver(void)
{
return &bl_extern_driver;
}
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 = AML_I2C_MASTER_A;
BLEXERR("invalid i2c_bus: %s\n", str);
}
ret = of_property_read_u32(of_node, "type", &pdata->type);
if (ret) {
pdata->type = BL_EXTERN_MAX;
pr_err("%s warning: get type failed, exit\n", pdata->name);
return -1;
}
pdata->gpio_used = 0;
ret = of_property_read_string_index(of_node,
"gpio_enable_on_off", 0, &str);
if (ret) {
pr_warn("%s warning: get gpio_enable failed\n", pdata->name);
} else {
if (strncmp(str, "G", 1) == 0) {
pdata->gpio_used = 1;
bl_extern_gpio = gpiod_get(&dev, str);
if (bl_extern_gpio) {
pr_warn("%s warning:failed to alloc gpio (%s)\n",
pdata->name, str);
}
pdata->gpio = bl_extern_gpio;
}
DBG_PRINT("%s: gpio_enable %s\n",
pdata->name, ((pdata->gpio_used) ? str:"none"));
}
ret = of_property_read_string_index(of_node,
"gpio_enable_on_off", 1, &str);
if (ret) {
pr_warn("%s warning: get gpio_enable_on failed\n", pdata->name);
} else {
if (strncmp(str, "2", 1) == 0)
pdata->gpio_on = LCD_POWER_GPIO_INPUT;
else if (strncmp(str, "0", 1) == 0)
pdata->gpio_on = LCD_POWER_GPIO_OUTPUT_LOW;
else
pdata->gpio_on = LCD_POWER_GPIO_OUTPUT_HIGH;
}
ret = of_property_read_string_index(of_node,
"gpio_enable_on_off", 2, &str);
if (ret) {
pr_warn("%s warning:get gpio_enable_off failed\n", pdata->name);
} else {
if (strncmp(str, "2", 1) == 0)
pdata->gpio_off = LCD_POWER_GPIO_INPUT;
else if (strncmp(str, "1", 1) == 0)
pdata->gpio_off = LCD_POWER_GPIO_OUTPUT_HIGH;
else
pdata->gpio_off = LCD_POWER_GPIO_OUTPUT_LOW;
}
DBG_PRINT("%s: gpio_on = %d,", pdata->name, pdata->gpio_on);
DBG_PRINT("gpio_off = %d\n", pdata->gpio_off);
switch (pdata->type) {
return i2c_bus;
}
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:
ret = of_property_read_u32(of_node, "i2c_address",
&pdata->i2c_addr);
if (ret) {
pr_warn("%s warning: get i2c_address failed\n",
pdata->name);
pdata->i2c_addr = 0;
}
DBG_PRINT("%s: i2c_address=", pdata->name);
DBG_PRINT("0x%02x\n", pdata->i2c_addr);
ret = of_property_read_string(of_node, "i2c_bus", &str);
if (ret) {
pr_warn("%s warning: get i2c_bus failed,", pdata->name);
pr_warn("use default i2c bus\n");
pdata->i2c_bus = AML_I2C_MASTER_A;
} else {
if (strncmp(str, "i2c_bus_a", 9) == 0)
pdata->i2c_bus = AML_I2C_MASTER_A;
else if (strncmp(str, "i2c_bus_b", 9) == 0)
pdata->i2c_bus = AML_I2C_MASTER_B;
else if (strncmp(str, "i2c_bus_c", 9) == 0)
pdata->i2c_bus = AML_I2C_MASTER_C;
else if (strncmp(str, "i2c_bus_d", 9) == 0)
pdata->i2c_bus = AML_I2C_MASTER_D;
else if (strncmp(str, "i2c_bus_ao", 10) == 0)
pdata->i2c_bus = AML_I2C_MASTER_AO;
else
pdata->i2c_bus = AML_I2C_MASTER_A;
}
DBG_PRINT("%s: i2c_bus=%s[%d]\n", pdata->name,
str, pdata->i2c_bus);
pr_info("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:
ret = of_property_read_string(of_node, "gpio_spi_cs", &str);
if (ret) {
pr_warn("%s warning: get spi gpio_spi_cs failed\n",
pdata->name);
pdata->spi_cs = NULL;
} else {
bl_extern_gpio = gpiod_get(&dev, str);
if (bl_extern_gpio) {
pdata->spi_cs = bl_extern_gpio;
DBG_PRINT("spi_cs gpio = %s\n", str);
} else {
pr_warn("%s warning:failed to alloc gpio (%s)\n",
pdata->name, str);
pdata->spi_cs = NULL;
}
}
ret = of_property_read_string(of_node, "gpio_spi_clk", &str);
if (ret) {
pr_warn("%s warning: get spi gpio_spi_clk failed\n",
pdata->name);
pdata->spi_clk = NULL;
} else {
bl_extern_gpio = gpiod_get(&dev, str);
if (bl_extern_gpio) {
pdata->spi_clk = bl_extern_gpio;
DBG_PRINT("spi_cs gpio = %s\n", str);
} else {
pdata->spi_clk = NULL;
pr_warn("%s warning:failed to alloc gpio (%s)\n",
pdata->name, str);
}
}
ret = of_property_read_string(of_node, "gpio_spi_data", &str);
if (ret) {
pr_warn("%s warning: get spi gpio_spi_data failed\n",
pdata->name);
pdata->spi_data = NULL;
} else {
bl_extern_gpio = gpiod_get(&dev, str);
if (bl_extern_gpio) {
pdata->spi_data = bl_extern_gpio;
DBG_PRINT("spi_cs gpio = %s\n", str);
} else {
pdata->spi_data = NULL;
pr_warn("%s warning:failed to alloc gpio (%s)\n",
pdata->name, str);
}
}
break;
case BL_EXTERN_OTHER:
case BL_EXTERN_MIPI:
pr_info("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;
}
ret = of_property_read_u32_array(of_node, "dim_max_min",
&bl_para[0], 2);
if (ret) {
pr_warn("%s warning: get dim_max_min failed\n", pdata->name);
pdata->dim_max = 0;
pdata->dim_min = 0;
} else {
pdata->dim_max = bl_para[0];
pdata->dim_min = bl_para[1];
}
static int bl_extern_config_from_dts(struct device_node *np, int index)
{
char be_propname[20];
struct device_node *child;
const char *str;
unsigned int temp[5], val;
int ret = 0;
struct aml_bl_extern_driver_s *bl_extern = aml_bl_extern_get_driver();
/* get device config */
sprintf(be_propname, "extern_%d", index);
BLEX("load: %s\n", be_propname);
child = of_get_child_by_name(np, be_propname);
if (child == NULL) {
BLEXERR("failed to get %s\n", be_propname);
return -1;
}
ret = of_property_read_u32_array(child, "index", &temp[0], 1);
if (ret)
BLEXERR("failed to get index, exit\n");
else {
if (temp[0] == index)
bl_extern->config.index = temp[0];
else {
BLEXERR("index not match, exit\n");
return -1;
}
}
ret = of_property_read_string(child, "extern_name", &str);
if (ret) {
BLEXERR("failed to get bl_extern_name\n");
str = "bl_extern_name";
}
strcpy(bl_extern->config.name, str);
ret = of_property_read_u32(child, "type", &val);
if (ret) {
BLEXERR("failed to get type\n");
} else {
bl_extern->config.type = val;
BLEX("type: %d\n", bl_extern->config.type);
}
if (bl_extern->config.type >= BL_EXTERN_MAX) {
BLEXERR("type num is out of support\n");
return -1;
}
ret = of_property_read_u32_array(child, "dim_max_min", &temp[0], 2);
if (ret) {
BLEXERR("failed to get dim_max_min\n");
bl_extern->config.dim_max = 255;
bl_extern->config.dim_min = 10;
} else {
bl_extern->config.dim_max = temp[0];
bl_extern->config.dim_min = temp[1];
}
switch (bl_extern->config.type) {
case BL_EXTERN_I2C:
ret = of_property_read_u32(child, "i2c_address", &val);
if (ret) {
BLEXERR("failed to get i2c_address\n");
} else {
bl_extern->config.i2c_addr = (unsigned char)val;
}
if (lcd_debug_print_flag) {
BLEX("%s i2c_address=0x%02x\n",
bl_extern->config.name,
bl_extern->config.i2c_addr);
}
ret = of_property_read_string(child, "i2c_bus", &str);
if (ret) {
BLEXERR("failed to get i2c_bus\n");
} else {
bl_extern->config.i2c_bus =
bl_extern_get_i2c_bus_str(str);
}
if (lcd_debug_print_flag) {
BLEX("%s i2c_bus=%s[%d]\n",
bl_extern->config.name, str,
bl_extern->config.i2c_bus);
}
break;
case BL_EXTERN_SPI:
break;
case BL_EXTERN_MIPI:
break;
default:
break;
}
DBG_PRINT("%s dim_min = %d, dim_max = %d\n", pdata->name,
pdata->dim_min, pdata->dim_max);
return 0;
}
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_AMLOGIC_BL_EXTERN_I2C_LP8556
ret = i2c_lp8556_probe();
#endif
goto bl_extern_add_driver_next;
} else if (strcmp(extconf->name, "mipi_lt070me05") == 0) {
#ifdef CONFIG_AMLOGIC_BL_EXTERN_MIPI_LT070ME05
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;
}
static int bl_extern_remove_driver(void)
{
int ret = 0;
struct bl_extern_config_s *extconf = &bl_extern_driver.config;
if (strcmp(extconf->name, "i2c_lp8556") == 0) {
#ifdef CONFIG_AMLOGIC_BL_EXTERN_I2C_LP8556
ret = i2c_lp8556_remove();
#endif
goto bl_extern_remove_driver_next;
} else if (strcmp(extconf->name, "mipi_lt070me05") == 0) {
#ifdef CONFIG_AMLOGIC_BL_EXTERN_MIPI_LT070ME05
ret = mipi_lt070me05_remove();
#endif
goto bl_extern_remove_driver_next;
} else {
BLEXERR("invalid device name: %s\n", extconf->name);
ret = -1;
}
bl_extern_remove_driver_next:
if (ret) {
BLEXERR("remove device driver failed %s(%d)\n",
extconf->name, extconf->index);
} else {
BLEX("remove device driver %s(%d)\n",
extconf->name, extconf->index);
}
return ret;
}
int aml_bl_extern_device_load(int index)
{
int ret = 0;
bl_extern_config_from_dts(bl_extern_driver.dev->of_node,
index);
bl_extern_add_driver();
bl_extern_driver.config_print = bl_extern_config_print;
BLEX("%s OK\n", __func__);
return ret;
}
int aml_bl_extern_probe(struct platform_device *pdev)
{
int ret = 0;
bl_extern_driver.dev = &pdev->dev;
BLEX("%s OK\n", __func__);
return ret;
}
static int aml_bl_extern_remove(struct platform_device *pdev)
{
int ret = 0;
bl_extern_remove_driver();
BLEX("%s OK\n", __func__);
return ret;
}
#ifdef CONFIG_OF
static const struct of_device_id aml_bl_extern_dt_match[] = {
{
.compatible = "amlogic, bl_extern",
},
{},
};
#endif
static struct platform_driver aml_bl_extern_driver = {
.probe = aml_bl_extern_probe,
.remove = aml_bl_extern_remove,
.driver = {
.name = "bl_extern",
.owner = THIS_MODULE,
#ifdef CONFIG_OF
.of_match_table = aml_bl_extern_dt_match,
#endif
},
};
static int __init aml_bl_extern_init(void)
{
int ret;
if (lcd_debug_print_flag)
BLEX("%s\n", __func__);
ret = platform_driver_register(&aml_bl_extern_driver);
if (ret) {
BLEXERR("driver register failed\n");
return -ENODEV;
}
return ret;
}
static void __exit aml_bl_extern_exit(void)
{
platform_driver_unregister(&aml_bl_extern_driver);
}
module_init(aml_bl_extern_init);
module_exit(aml_bl_extern_exit);
MODULE_AUTHOR("AMLOGIC");
MODULE_DESCRIPTION("bl extern driver");
MODULE_LICENSE("GPL");

View File

@@ -0,0 +1,40 @@
/*
* drivers/amlogic/media/vout/backlight/bl_extern/bl_extern.dts
*
* Copyright (C) 2017 Amlogic, Inc. All rights reserved.
*
* 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 License, or
* (at your option) 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.
*
*/
bl_extern{
compatible = "amlogic, bl_extern";
dev_name = "bl_extern";
status = "okay";
extern_0{
index = <0>;
extern_name = "i2c_lp8556";
type = <1>; /** bl_extern_driver type: 1=i2c, 2=spi, 3=mipi */
i2c_address = <0x2c>; /** 7bit i2c address */
i2c_bus = "i2c_bus_d";
dim_max_min = <255 10>;
};
extern_1{
index = <1>;
extern_name = "mipi_lt070me05";
type = <3>; /** bl_extern_driver type: 1=i2c, 2=spi, 3=mipi */
dim_max_min = <255 10>;
};
};

View File

@@ -0,0 +1,43 @@
/*
* drivers/amlogic/media/vout/backlight/bl_extern/bl_extern.h
*
* Copyright (C) 2017 Amlogic, Inc. All rights reserved.
*
* 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 License, or
* (at your option) 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.
*
*/
#ifndef _BL_EXTERN_H_
#define _BL_EXTERN_H_
#include <linux/of.h>
#include <linux/platform_device.h>
#include <linux/amlogic/aml_gpio_consumer.h>
#include <linux/pinctrl/consumer.h>
#include <linux/amlogic/media/vout/lcd/lcd_vout.h>
#define BLEX(fmt, args...) pr_info("bl extern: "fmt"", ## args)
#define BLEXERR(fmt, args...) pr_err("bl extern: error: "fmt"", ## args)
#define BL_EXTERN_DRIVER "bl_extern"
#ifdef CONFIG_AMLOGIC_BL_EXTERN_I2C_LP8556
extern int i2c_lp8556_probe(void);
extern int i2c_lp8556_remove(void);
#endif
#ifdef CONFIG_AMLOGIC_BL_EXTERN_MIPI_LT070ME05
extern int mipi_lt070me05_probe(void);
extern int mipi_lt070me05_remove(void);
#endif
#endif

View File

@@ -16,53 +16,49 @@
*/
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/module.h>
#include <linux/interrupt.h>
#include <linux/platform_device.h>
#include <linux/slab.h>
#include <linux/jiffies.h>
#include <linux/i2c.h>
#include <linux/amlogic/i2c-amlogic.h>
#include <linux/miscdevice.h>
#include <linux/mutex.h>
#include <linux/mm.h>
#include <linux/device.h>
#include <linux/fs.h>
#include <linux/clk.h>
#include <linux/delay.h>
#include <linux/sysctl.h>
#include <linux/uaccess.h>
#include <linux/slab.h>
#include <linux/of.h>
#include <linux/amlogic/media/vout/lcd/aml_bl_extern.h>
static struct bl_extern_config_t *bl_ext_config;
static struct i2c_client *aml_lp8556_i2c_client;
#include <linux/amlogic/media/vout/lcd/aml_bl.h>
#include "bl_extern.h"
#ifdef BL_EXT_DEBUG_INFO
#define DBG_PRINT(...) pr_info(__VA_ARGS__)
#else
#define DBG_PRINT(...)
#endif
#define BL_EXTERN_INDEX 0
#define BL_EXTERN_NAME "i2c_lp8556"
#define BL_EXTERN_TYPE BL_EXTERN_I2C
#define BL_EXTERN_NAME "bl_i2c_lp8556"
static unsigned int bl_status = 1;
static unsigned int bl_level;
#define BL_EXTERN_CMD_SIZE 4
static unsigned char i2c_init_table[][2] = {
{0xa1, 0x76}, /* hight bit(8~11)(0~0X66e set backlight) */
{0xa0, 0x66}, /* low bit(0~7) 20mA */
{0x16, 0x1F}, /* 5channel LED enable 0x1F */
{0xa9, 0xA0}, /* VBOOST_MAX 25V */
{0x9e, 0x12},
{0xa2, 0x23},
{0x01, 0x05}, /* 0x03 pwm+I2c set brightness,0x5 I2c set brightness */
{0xff, 0xff}, /* ending flag */
static unsigned int bl_status;
static struct i2c_client *i2c_lp8556_client;
static unsigned char init_on_table[] = {
0x00, 0xa1, 0x76, 0x00,//hight bit(8~11)(0~0X66e set backlight)
0x00, 0xa0, 0x66, 0x00,//low bit(0~7) 20mA
0x00, 0x16, 0x1F, 0x00,// 5channel LED enable 0x1F
0x00, 0xa9, 0xA0, 0x00,//VBOOST_MAX 25V
0x00, 0x9e, 0x12, 0x00,
0x00, 0xa2, 0x23, 0x00,
/*0x03 pwm+I2c set brightness,0x5 I2c set brightness*/
0x00, 0x01, 0x05, 0x00,
0xff, 0x00, 0x00, 0x00, //ending
};
static int aml_i2c_write(struct i2c_client *i2client,
unsigned char *buff, unsigned int len)
static unsigned char init_off_table[] = {
0xff, 0x00, 0x00, 0x00, //ending
};
static int i2c_lp8556_write(struct i2c_client *i2client,
unsigned char *buff, unsigned int len)
{
int res = 0;
int ret = 0;
struct i2c_msg msg[] = {
{
.addr = i2client->addr,
@@ -72,61 +68,93 @@ static int aml_i2c_write(struct i2c_client *i2client,
}
};
res = i2c_transfer(i2client->adapter, msg, 1);
if (res < 0)
pr_err("%s: i2c transfer failed [addr 0x%02x]\n",
__func__, i2client->addr);
ret = i2c_transfer(i2client->adapter, msg, 1);
if (ret < 0)
BLEXERR("i2c write failed [addr 0x%02x]\n", i2client->addr);
return res;
return ret;
}
#if 0
static int aml_i2c_read(struct i2c_client *i2client,
unsigned char *buff, unsigned int len)
static int i2c_lp8556_power_cmd(unsigned char *init_table)
{
int res = 0;
struct i2c_msg msgs[] = {
{
.addr = i2client->addr,
.flags = 0,
.len = 1,
.buf = buff,
},
{
.addr = i2client->addr,
.flags = I2C_M_RD,
.len = len,
.buf = buff,
}
};
res = i2c_transfer(i2client->adapter, msgs, 2);
if (res < 0)
pr_err("%s: i2c transfer failed [addr 0x%02x]\n",
__func__, i2client->addr);
return res;
}
#endif
int i = 0, len;
int ret = 0;
struct aml_bl_extern_driver_s *bl_extern = aml_bl_extern_get_driver();
static int bl_extern_set_level(unsigned int level)
len = BL_EXTERN_CMD_SIZE;
while (i <= BL_EXTERN_INIT_TABLE_MAX) {
if (init_table[i] == BL_EXTERN_INIT_END) {
break;
} else if (init_table[i] == BL_EXTERN_INIT_NONE) {
/* do nothing, only for delay */
} else if (init_table[i] == BL_EXTERN_INIT_CMD) {
ret = i2c_lp8556_write(i2c_lp8556_client,
&init_table[i+1], (len-2));
} else {
BLEXERR("%s(%d: %s): power_type %d is invalid\n",
__func__, bl_extern->config.index,
bl_extern->config.name, bl_extern->config.type);
}
if (init_table[i+len-1] > 0)
mdelay(init_table[i+len-1]);
i += len;
}
return ret;
}
static int i2c_lp8556_power_ctrl(int flag)
{
int ret = 0;
struct aml_bl_extern_driver_s *bl_extern = aml_bl_extern_get_driver();
if (flag)
ret = i2c_lp8556_power_cmd(init_on_table);
else
ret = i2c_lp8556_power_cmd(init_off_table);
BLEX("%s(%d: %s): %d\n",
__func__, bl_extern->config.index,
bl_extern->config.name, flag);
return ret;
}
static int i2c_lp8556_power_on(void)
{
int ret;
bl_status = 1;
ret = i2c_lp8556_power_ctrl(1);
return ret;
}
static int i2c_lp8556_power_off(void)
{
int ret;
bl_status = 0;
ret = i2c_lp8556_power_ctrl(0);
return ret;
}
static int i2c_lp8556_set_level(unsigned int level)
{
unsigned char tData[3];
int ret = 0;
struct aml_bl_drv_s *bl_drv = aml_bl_get_driver();
struct aml_bl_extern_driver_s *bl_extern = aml_bl_extern_get_driver();
unsigned int level_max, level_min;
unsigned int dim_max, dim_min;
bl_level = level;
if (bl_ext_config == NULL) {
pr_err("no %s driver\n", BL_EXTERN_NAME);
return -1;
}
if (bl_drv == NULL)
return -1;
level_max = bl_drv->bconf->level_max;
level_min = bl_drv->bconf->level_min;
dim_max = bl_ext_config->dim_max;
dim_min = bl_ext_config->dim_min;
dim_max = bl_extern->config.dim_max;
dim_min = bl_extern->config.dim_min;
level = dim_min - ((level - level_min) * (dim_min - dim_max)) /
(level_max - level_min);
level &= 0xff;
@@ -134,237 +162,119 @@ static int bl_extern_set_level(unsigned int level)
if (bl_status) {
tData[0] = 0x0;
tData[1] = level;
ret = aml_i2c_write(aml_lp8556_i2c_client, tData, 2);
ret = i2c_lp8556_write(i2c_lp8556_client, tData, 2);
}
return ret;
}
static int bl_extern_power_on(void)
static int i2c_lp8556_update(void)
{
unsigned char tData[3];
int i = 0, ending_flag = 0;
int ret = 0;
struct aml_bl_extern_driver_s *bl_extern = aml_bl_extern_get_driver();
if (bl_ext_config->gpio) {
if (bl_ext_config->gpio_on == 2) {
bl_gpio_input(bl_ext_config->gpio);
} else {
bl_gpio_output(bl_ext_config->gpio,
bl_ext_config->gpio_on);
}
if (bl_extern == NULL) {
BLEXERR("%s driver is null\n", BL_EXTERN_NAME);
return -1;
}
while (ending_flag == 0) {
if (i2c_init_table[i][0] == 0xff) {
if (i2c_init_table[i][1] == 0xff)
ending_flag = 1;
else
mdelay(i2c_init_table[i][1]);
} else {
tData[0] = i2c_init_table[i][0];
tData[1] = i2c_init_table[i][1];
ret = aml_i2c_write(aml_lp8556_i2c_client, tData, 2);
}
i++;
if (bl_extern->config.type == BL_EXTERN_MAX) {
bl_extern->config.index = BL_EXTERN_INDEX;
bl_extern->config.type = BL_EXTERN_TYPE;
strcpy(bl_extern->config.name, BL_EXTERN_NAME);
}
bl_status = 1;
bl_extern_set_level(bl_level);
BLPR("%s\n", __func__);
return ret;
}
static int bl_extern_power_off(void)
{
bl_status = 0;
if (bl_ext_config->gpio) {
if (bl_ext_config->gpio_off == 2) {
bl_gpio_input(bl_ext_config->gpio);
} else {
bl_gpio_output(bl_ext_config->gpio,
bl_ext_config->gpio_off);
}
}
BLPR("%s\n", __func__);
bl_extern->device_power_on = i2c_lp8556_power_on;
bl_extern->device_power_off = i2c_lp8556_power_off;
bl_extern->device_bri_update = i2c_lp8556_set_level;
return 0;
}
static int get_bl_extern_config(struct device dev,
struct bl_extern_config_t *bl_ext_cfg)
{
int ret = 0;
struct aml_bl_extern_driver_t *bl_ext;
ret = get_bl_extern_dt_data(dev, bl_ext_cfg);
if (ret) {
BLPR("error %s: failed to get dt data\n", BL_EXTERN_NAME);
return ret;
}
if (bl_ext_cfg->dim_min > 0xff)
bl_ext_cfg->dim_min = 0xff;
if (bl_ext_cfg->dim_max > 0xff)
bl_ext_cfg->dim_max = 0xff;
bl_ext = aml_bl_extern_get_driver();
if (bl_ext) {
bl_ext->type = bl_ext_cfg->type;
bl_ext->name = bl_ext_cfg->name;
bl_ext->power_on = bl_extern_power_on;
bl_ext->power_off = bl_extern_power_off;
bl_ext->set_level = bl_extern_set_level;
} else {
BLPR("error %s get bl_extern_driver failed\n",
bl_ext_cfg->name);
ret = -1;
}
return ret;
}
static int aml_lp8556_i2c_probe(struct i2c_client *client,
static int bl_extern_i2c_lp8556_probe(struct i2c_client *client,
const struct i2c_device_id *id)
{
if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C))
BLPR("error %s: functionality check failed\n",
__func__);
else
aml_lp8556_i2c_client = client;
BLPR("%s OK\n", __func__);
if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C))
BLEXERR("%s: functionality check failed\n", __func__);
else
i2c_lp8556_client = client;
BLEX("%s OK\n", __func__);
return 0;
}
static int aml_lp8556_i2c_remove(struct i2c_client *client)
static int bl_extern_i2c_lp8556_remove(struct i2c_client *client)
{
return 0;
}
static const struct i2c_device_id aml_lp8556_i2c_id[] = {
static const struct i2c_device_id bl_extern_i2c_lp8556_id[] = {
{BL_EXTERN_NAME, 0},
{ }
};
static struct i2c_driver aml_lp8556_i2c_driver = {
.probe = aml_lp8556_i2c_probe,
.remove = aml_lp8556_i2c_remove,
.id_table = aml_lp8556_i2c_id,
static struct i2c_driver i2c_lp8556_driver = {
.probe = bl_extern_i2c_lp8556_probe,
.remove = bl_extern_i2c_lp8556_remove,
.id_table = bl_extern_i2c_lp8556_id,
.driver = {
.name = BL_EXTERN_NAME,
.owner = THIS_MODULE,
},
};
static int aml_lp8556_probe(struct platform_device *pdev)
int i2c_lp8556_probe(void)
{
int ret = 0;
struct i2c_board_info i2c_info;
struct i2c_adapter *adapter;
struct i2c_client *i2c_client;
int ret = 0;
if (bl_extern_driver_check())
return -1;
if (bl_ext_config == NULL)
bl_ext_config = kzalloc(sizeof(*bl_ext_config), GFP_KERNEL);
if (bl_ext_config == NULL) {
BLPR("error %s probe: failed to alloc data\n", BL_EXTERN_NAME);
return -1;
}
pdev->dev.platform_data = bl_ext_config;
ret = get_bl_extern_config(pdev->dev, bl_ext_config);
if (ret)
goto bl_extern_probe_failed;
struct aml_bl_extern_driver_s *bl_extern = aml_bl_extern_get_driver();
memset(&i2c_info, 0, sizeof(i2c_info));
adapter = i2c_get_adapter(bl_ext_config->i2c_bus);
adapter = i2c_get_adapter(bl_extern->config.i2c_bus);
if (!adapter) {
BLPR("error %s£ºfailed get i2c adapter\n", BL_EXTERN_NAME);
goto bl_extern_probe_failed;
BLEXERR("%s failed to get i2c adapter\n",
bl_extern->config.name);
return -1;
}
strncpy(i2c_info.type, bl_ext_config->name, I2C_NAME_SIZE);
i2c_info.addr = bl_ext_config->i2c_addr;
i2c_info.platform_data = bl_ext_config;
strncpy(i2c_info.type, bl_extern->config.name, I2C_NAME_SIZE);
i2c_info.addr = bl_extern->config.i2c_addr;
i2c_info.platform_data = &bl_extern->config;
i2c_info.flags = 0;
if (i2c_info.addr > 0x7f)
i2c_info.flags = 0x10;
if (i2c_info.addr > 0x7f) {
BLEXERR("%s invalid i2c address: 0x%02x\n",
bl_extern->config.name, bl_extern->config.i2c_addr);
return -1;
}
i2c_client = i2c_new_device(adapter, &i2c_info);
if (!i2c_client) {
BLPR("error %s :failed new i2c device\n", BL_EXTERN_NAME);
goto bl_extern_probe_failed;
} else{
DBG_PRINT("error %s: new i2c device succeed\n",
((struct bl_extern_data_t *)(bl_ext_config))->name);
}
if (!aml_lp8556_i2c_client) {
ret = i2c_add_driver(&aml_lp8556_i2c_driver);
if (ret) {
BLPR("error %s probe: add i2c_driver failed\n",
BL_EXTERN_NAME);
goto bl_extern_probe_failed;
BLEXERR("%s failed to new i2c device\n",
bl_extern->config.name);
} else {
if (lcd_debug_print_flag) {
BLEX("%s new i2c device succeed\n",
bl_extern->config.name);
}
}
BLPR("%s ok\n", __func__);
if (!i2c_lp8556_client) {
ret = i2c_add_driver(&i2c_lp8556_driver);
if (ret) {
BLEXERR("%s add i2c_driver failed\n",
bl_extern->config.name);
return -1;
}
}
ret = i2c_lp8556_update();
BLEX("%s: %d\n", __func__, ret);
return ret;
bl_extern_probe_failed:
kfree(bl_ext_config);
bl_ext_config = NULL;
return -1;
}
static int aml_lp8556_remove(struct platform_device *pdev)
int i2c_lp8556_remove(void)
{
kfree(pdev->dev.platform_data);
return 0;
}
#ifdef CONFIG_USE_OF
static const struct of_device_id aml_lp8556_dt_match[] = {
{
.compatible = "amlogic, bl_i2c_lp8556",
},
{},
};
#else
#define aml_lp8556_dt_match NULL
#endif
static struct platform_driver aml_lp8556_driver = {
.probe = aml_lp8556_probe,
.remove = aml_lp8556_remove,
.driver = {
.name = BL_EXTERN_NAME,
.owner = THIS_MODULE,
#ifdef CONFIG_USE_OF
.of_match_table = aml_lp8556_dt_match,
#endif
},
};
static int __init aml_lp8556_init(void)
{
int ret;
BLPR("%s\n", __func__);
ret = platform_driver_register(&aml_lp8556_driver);
if (ret) {
BLPR("error %s failed to register bl extern driver\n",
__func__);
return -ENODEV;
}
return ret;
}
static void __exit aml_lp8556_exit(void)
{
platform_driver_unregister(&aml_lp8556_driver);
}
module_init(aml_lp8556_init);
module_exit(aml_lp8556_exit);
MODULE_AUTHOR("AMLOGIC");
MODULE_DESCRIPTION("BL Extern driver for LP8556");
MODULE_LICENSE("GPL");

View File

@@ -1,221 +0,0 @@
/*
* drivers/amlogic/media/vout/backlight/bl_extern/mipi_LT070ME05.c
*
* Copyright (C) 2017 Amlogic, Inc. All rights reserved.
*
* 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 License, or
* (at your option) 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 <linux/kernel.h>
#include <linux/init.h>
#include <linux/module.h>
#include <linux/platform_device.h>
#include <linux/slab.h>
#include <linux/jiffies.h>
#include <linux/miscdevice.h>
#include <linux/mutex.h>
#include <linux/mm.h>
#include <linux/device.h>
#include <linux/fs.h>
#include <linux/delay.h>
#include <linux/sysctl.h>
#include <linux/uaccess.h>
#include <linux/amlogic/media/vout/lcd/aml_bl_extern.h>
#ifdef CONFIG_LCD_IF_MIPI_VALID
static struct bl_extern_config_t *bl_ext_config;
#ifdef BL_EXT_DEBUG_INFO
#define DBG_PRINT(...) pr_info(__VA_ARGS__)
#else
#define DBG_PRINT(...)
#endif
#define BL_EXTERN_NAME "bl_mipi_LT070ME05"
static unsigned int bl_status = 1;
static unsigned int bl_level;
/******************** mipi command ********************
* format: data_type, num, data....
* special: data_type=0xff, num<0xff means delay ms, num=0xff means ending.
*/
static int bl_extern_set_level(unsigned int level)
{
unsigned char payload[] = {0x15, 2, 0x51, 0xe6, 0xff, 0xff};
bl_level = level;
if (bl_ext_config == NULL) {
pr_err("no %s driver\n", BL_EXTERN_NAME);
return -1;
}
get_bl_ext_level(bl_ext_config);
level = bl_ext_config->dim_min -
((level - bl_ext_config->level_min) *
(bl_ext_config->dim_min - bl_ext_config->dim_max)) /
(bl_ext_config->level_max - bl_ext_config->level_min);
level &= 0xff;
if (bl_status) {
payload[3] = level;
dsi_write_cmd(payload);
}
return 0;
}
static int bl_extern_power_on(void)
{
if (bl_ext_config->gpio_used > 0) {
if (bl_ext_config->gpio_on == 2) {
bl_extern_gpio_input(bl_ext_config->gpio);
} else {
bl_extern_gpio_output(bl_ext_config->gpio,
bl_ext_config->gpio_on);
}
}
bl_status = 1;
bl_extern_set_level(bl_level);
pr_info("%s\n", __func__);
return 0;
}
static int bl_extern_power_off(void)
{
if (bl_ext_config->gpio_used > 0) {
if (bl_ext_config->gpio_off == 2) {
bl_extern_gpio_input(bl_ext_config->gpio);
} else {
bl_extern_gpio_output(bl_ext_config->gpio,
bl_ext_config->gpio_off);
}
}
pr_info("%s\n", __func__);
return 0;
}
static int get_bl_extern_config(struct device dev,
struct bl_extern_config_t *bl_ext_cfg)
{
int ret = 0;
struct aml_bl_extern_driver_t *bl_ext;
ret = get_bl_extern_dt_data(dev, bl_ext_cfg);
if (ret) {
pr_err("[error] %s: failed to get dt data\n", BL_EXTERN_NAME);
return ret;
}
if (bl_ext_cfg->dim_min > 0xff)
bl_ext_cfg->dim_min = 0xff;
if (bl_ext_cfg->dim_max > 0xff)
bl_ext_cfg->dim_max = 0xff;
bl_ext = aml_bl_extern_get_driver();
if (bl_ext) {
bl_ext->type = bl_ext_cfg->type;
bl_ext->name = bl_ext_cfg->name;
bl_ext->power_on = bl_extern_power_on;
bl_ext->power_off = bl_extern_power_off;
bl_ext->set_level = bl_extern_set_level;
} else {
pr_err("[error] %s get bl_extern_driver failed\n",
bl_ext_cfg->name);
ret = -1;
}
return ret;
}
static int aml_LT070ME05_probe(struct platform_device *pdev)
{
int ret = 0;
if (bl_extern_driver_check())
return -1;
if (bl_ext_config == NULL)
bl_ext_config = kzalloc(sizeof(*bl_ext_config), GFP_KERNEL);
if (bl_ext_config == NULL) {
pr_err("[error] %s probe: failed to alloc data\n",
BL_EXTERN_NAME);
return -1;
}
pdev->dev.platform_data = bl_ext_config;
ret = get_bl_extern_config(pdev->dev, bl_ext_config);
if (ret)
goto bl_extern_probe_failed;
pr_info("%s ok\n", __func__);
return ret;
bl_extern_probe_failed:
kfree(bl_ext_config);
bl_ext_config = NULL;
return -1;
}
static int aml_LT070ME05_remove(struct platform_device *pdev)
{
kfree(pdev->dev.platform_data);
return 0;
}
#ifdef CONFIG_USE_OF
static const struct of_device_id aml_LT070ME05_dt_match[] = {
{
.compatible = "amlogic, bl_mipi_LT070ME05",
},
{},
};
#else
#define aml_LT070ME05_dt_match NULL
#endif
static struct platform_driver aml_LT070ME05_driver = {
.probe = aml_LT070ME05_probe,
.remove = aml_LT070ME05_remove,
.driver = {
.name = BL_EXTERN_NAME,
.owner = THIS_MODULE,
#ifdef CONFIG_USE_OF
.of_match_table = aml_LT070ME05_dt_match,
#endif
},
};
static int __init aml_LT070ME05_init(void)
{
int ret;
DBG_PRINT("%s\n", __func__);
ret = platform_driver_register(&aml_LT070ME05_driver);
if (ret) {
pr_err("[error] %s failed to register bl extern driver\n",
__func__);
return -ENODEV;
}
return ret;
}
static void __exit aml_LT070ME05_exit(void)
{
platform_driver_unregister(&aml_LT070ME05_driver);
}
rootfs_initcall(aml_LT070ME05_init);
module_exit(aml_LT070ME05_exit);
MODULE_AUTHOR("AMLOGIC");
MODULE_DESCRIPTION("BL Extern driver for LT070ME05");
MODULE_LICENSE("GPL");
#endif

View File

@@ -0,0 +1,123 @@
/*
* drivers/amlogic/media/vout/backlight/bl_extern/mipi_lt070me05.c
*
* Copyright (C) 2017 Amlogic, Inc. All rights reserved.
*
* 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 License, or
* (at your option) 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 <linux/kernel.h>
#include <linux/module.h>
#include <linux/interrupt.h>
#include <linux/platform_device.h>
#include <linux/i2c.h>
#include <linux/amlogic/i2c-amlogic.h>
#include <linux/clk.h>
#include <linux/delay.h>
#include <linux/slab.h>
#include <linux/of.h>
#include <linux/amlogic/media/vout/lcd/aml_bl_extern.h>
#include <linux/amlogic/media/vout/lcd/aml_bl.h>
#include "bl_extern.h"
#define BL_EXTERN_INDEX 1
#define BL_EXTERN_NAME "mipi_lt070me05"
#define BL_EXTERN_TYPE BL_EXTERN_MIPI
static unsigned int bl_status;
static int mipi_lt070me05_power_on(void)
{
bl_status = 1;
return 0;
}
static int mipi_lt070me05_power_off(void)
{
bl_status = 0;
return 0;
}
/******************** mipi command ********************
*format: data_type, num, data....
*special: data_type=0xff, num<0xff means delay ms, num=0xff means ending.
*/
static int mipi_lt070me05_set_level(unsigned int level)
{
unsigned char payload[] = {0x15, 2, 0x51, 0xe6, 0xff, 0xff};
struct aml_bl_drv_s *bl_drv = aml_bl_get_driver();
struct aml_bl_extern_driver_s *bl_extern = aml_bl_extern_get_driver();
unsigned int level_max, level_min;
unsigned int dim_max, dim_min;
if (bl_drv == NULL)
return -1;
level_max = bl_drv->bconf->level_max;
level_min = bl_drv->bconf->level_min;
dim_max = bl_extern->config.dim_max;
dim_min = bl_extern->config.dim_min;
level = dim_min - ((level - level_min) * (dim_min - dim_max)) /
(level_max - level_min);
level &= 0xff;
if (bl_status) {
payload[3] = level;
#ifdef CONFIG_AMLOGIC_LCD_TABLET
dsi_write_cmd(&payload[0]);
#endif
}
return 0;
}
static int mipi_lt070me05_update(void)
{
struct aml_bl_extern_driver_s *bl_extern = aml_bl_extern_get_driver();
if (bl_extern == NULL) {
BLEXERR("%s driver is null\n", BL_EXTERN_NAME);
return -1;
}
if (bl_extern->config.type == BL_EXTERN_MAX) {
bl_extern->config.index = BL_EXTERN_INDEX;
bl_extern->config.type = BL_EXTERN_TYPE;
strcpy(bl_extern->config.name, BL_EXTERN_NAME);
}
bl_extern->device_power_on = mipi_lt070me05_power_on;
bl_extern->device_power_off = mipi_lt070me05_power_off;
bl_extern->device_bri_update = mipi_lt070me05_set_level;
return 0;
}
int mipi_lt070me05_probe(void)
{
int ret = 0;
ret = mipi_lt070me05_update();
BLEX("%s: %d\n", __func__, ret);
return ret;
}
int mipi_lt070me05_remove(void)
{
return 0;
}

View File

@@ -1,328 +0,0 @@
/*
* drivers/amlogic/media/vout/backlight/bl_extern/pmu_aml1218.c
*
* Copyright (C) 2017 Amlogic, Inc. All rights reserved.
*
* 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 License, or
* (at your option) 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 <linux/kernel.h>
#include <linux/init.h>
#include <linux/module.h>
#include <linux/platform_device.h>
#include <linux/slab.h>
#include <linux/jiffies.h>
#include <linux/i2c.h>
#include <linux/amlogic/i2c-amlogic.h>
#include <linux/miscdevice.h>
#include <linux/mutex.h>
#include <linux/mm.h>
#include <linux/device.h>
#include <linux/fs.h>
#include <linux/delay.h>
#include <linux/sysctl.h>
#include <linux/uaccess.h>
#include <linux/amlogic/media/vout/lcd/aml_bl_extern.h>
#ifdef CONFIG_AMLOGIC_BOARD_HAS_PMU
#include <linux/amlogic/aml_pmu_common.h>
#endif
static struct bl_extern_config_t *bl_ext_config;
#ifdef BL_EXT_DEBUG_INFO
#define DBG_PRINT(...) pr_info(__VA_ARGS__)
#else
#define DBG_PRINT(...)
#endif
#define BL_EXTERN_NAME "bl_pmu_aml1218"
static int bl_extern_set_level(unsigned int level)
{
#ifdef CONFIG_AMLOGIC_BOARD_HAS_PMU
struct aml_pmu_driver *pmu_driver;
unsigned char temp;
#endif
int ret = 0;
if (bl_ext_config == NULL) {
pr_err("no %s driver\n", BL_EXTERN_NAME);
return -1;
}
get_bl_ext_level(bl_ext_config);
level = bl_ext_config->dim_min -
((level - bl_ext_config->level_min) *
(bl_ext_config->dim_min - bl_ext_config->dim_max)) /
(bl_ext_config->level_max - bl_ext_config->level_min);
level &= 0x1f;
#ifdef CONFIG_AMLOGIC_BOARD_HAS_PMU
pmu_driver = aml_pmu_get_driver();
if (pmu_driver == NULL) {
pr_err("no pmu driver\n");
} else {
if ((pmu_driver->pmu_reg_write) && (pmu_driver->pmu_reg_read)) {
ret = pmu_driver->pmu_reg_read(0x005f, &temp);
temp &= ~(0x3f << 2);
temp |= (level << 2);
ret = pmu_driver->pmu_reg_write(0x005f, temp);
} else {
pr_err("no pmu_reg_read/write\n");
return -1;
}
}
#endif
return ret;
}
static int bl_extern_power_on(void)
{
#ifdef CONFIG_AMLOGIC_BOARD_HAS_PMU
struct aml_pmu_driver *pmu_driver;
unsigned char temp;
#endif
int ret = 0;
#ifdef CONFIG_AMLOGIC_BOARD_HAS_PMU
pmu_driver = aml_pmu_get_driver();
if (pmu_driver == NULL) {
pr_err("no pmu driver\n");
} else {
if ((pmu_driver->pmu_reg_write) && (pmu_driver->pmu_reg_read)) {
ret = pmu_driver->pmu_reg_read(0x005e, &temp);
temp |= (1 << 7);
ret = pmu_driver->pmu_reg_write(0x005e, temp);
} else {
pr_err("no pmu_reg_read/write\n");
return -1;
}
}
#endif
if (bl_ext_config->gpio_used > 0) {
if (bl_ext_config->gpio_on == 2)
bl_extern_gpio_input(bl_ext_config->gpio);
else
bl_extern_gpio_output(bl_ext_config->gpio,
bl_ext_config->gpio_on);
}
pr_info("%s\n", __func__);
return ret;
}
static int bl_extern_power_off(void)
{
#ifdef CONFIG_AMLOGIC_BOARD_HAS_PMU
struct aml_pmu_driver *pmu_driver;
unsigned char temp;
#endif
int ret = 0;
if (bl_ext_config->gpio_used > 0) {
if (bl_ext_config->gpio_off == 2)
bl_extern_gpio_input(bl_ext_config->gpio);
else
bl_extern_gpio_output(bl_ext_config->gpio,
bl_ext_config->gpio_off);
}
#ifdef CONFIG_AMLOGIC_BOARD_HAS_PMU
pmu_driver = aml_pmu_get_driver();
if (pmu_driver == NULL) {
pr_err("no pmu driver\n");
} else {
if ((pmu_driver->pmu_reg_write) && (pmu_driver->pmu_reg_read)) {
ret = pmu_driver->pmu_reg_read(0x005e, &temp);
temp &= ~(1 << 7);
ret = pmu_driver->pmu_reg_write(0x005e, temp);
} else {
pr_err("no pmu_reg_read/write\n");
return -1;
}
}
#endif
pr_info("%s\n", __func__);
return ret;
}
static ssize_t bl_extern_debug(struct class *class,
struct class_attribute *attr, const char *buf, size_t count)
{
#ifdef CONFIG_AMLOGIC_BOARD_HAS_PMU
struct aml_pmu_driver *pmu_driver;
unsigned char temp;
unsigned int t[2];
#endif
int ret = 0;
#ifdef CONFIG_AMLOGIC_BOARD_HAS_PMU
pmu_driver = aml_pmu_get_driver();
if (pmu_driver == NULL) {
pr_err("no pmu driver\n");
return -EINVAL;
}
switch (buf[0]) {
case 'r':
ret = sscanf(buf, "r %x", &t[0]);
if ((pmu_driver->pmu_reg_write) && (pmu_driver->pmu_reg_read)) {
ret = pmu_driver->pmu_reg_read(t[0], &temp);
pr_info("read pmu reg: 0x%x=0x%x\n", t[0], temp);
}
break;
case 'w':
ret = sscanf(buf, "w %x %x", &t[0], &t[1]);
if ((pmu_driver->pmu_reg_write) && (pmu_driver->pmu_reg_read)) {
ret = pmu_driver->pmu_reg_write(t[0], t[1]);
ret = pmu_driver->pmu_reg_read(t[0], &temp);
pr_info("write pmu reg 0x%x: 0x%x, readback: 0x%x\n",
t[0], t[1], temp);
}
break;
default:
pr_err("wrong format of command.\n");
break;
}
#endif
if (ret != 1 || ret != 2)
return -EINVAL;
return count;
}
static struct class_attribute bl_extern_debug_class_attrs[] = {
__ATTR(debug, 0644, NULL, bl_extern_debug),
__ATTR_NULL
};
static struct class bl_extern_debug_class = {
.name = "bl_ext",
.class_attrs = bl_extern_debug_class_attrs,
};
static int get_bl_extern_config(struct device dev,
struct bl_extern_config_t *bl_ext_cfg)
{
int ret = 0;
struct aml_bl_extern_driver_t *bl_ext;
ret = get_bl_extern_dt_data(dev, bl_ext_cfg);
if (ret) {
pr_err("[error] %s: failed to get dt data\n", BL_EXTERN_NAME);
return ret;
}
if (bl_ext_cfg->dim_min > 0x1f)
bl_ext_cfg->dim_min = 0x1f;
if (bl_ext_cfg->dim_max > 0x1f)
bl_ext_cfg->dim_max = 0x1f;
bl_ext = aml_bl_extern_get_driver();
if (bl_ext) {
bl_ext->type = bl_ext_cfg->type;
bl_ext->name = bl_ext_cfg->name;
bl_ext->power_on = bl_extern_power_on;
bl_ext->power_off = bl_extern_power_off;
bl_ext->set_level = bl_extern_set_level;
} else {
pr_err("[error] %s get bl_extern_driver failed\n",
bl_ext_cfg->name);
ret = -1;
}
return ret;
}
static int aml_aml1218_probe(struct platform_device *pdev)
{
int ret = 0;
if (bl_extern_driver_check())
return -1;
if (bl_ext_config == NULL)
bl_ext_config = kzalloc(sizeof(*bl_ext_config), GFP_KERNEL);
if (bl_ext_config == NULL) {
pr_err("[error] %s probe: failed to alloc data\n",
BL_EXTERN_NAME);
return -1;
}
pdev->dev.platform_data = bl_ext_config;
ret = get_bl_extern_config(pdev->dev, bl_ext_config);
if (ret)
goto bl_extern_probe_failed;
ret = class_register(&bl_extern_debug_class);
if (ret)
pr_err("class register bl_extern_debug_class fail!\n");
pr_err("%s ok\n", __func__);
return ret;
bl_extern_probe_failed:
kfree(bl_ext_config);
bl_ext_config = NULL;
return -1;
}
static int aml_aml1218_remove(struct platform_device *pdev)
{
kfree(pdev->dev.platform_data);
return 0;
}
#ifdef CONFIG_USE_OF
static const struct of_device_id aml_aml1218_dt_match[] = {
{
.compatible = "amlogic, bl_pmu_aml1218",
},
{},
};
#else
#define aml_aml1218_dt_match NULL
#endif
static struct platform_driver aml_aml1218_driver = {
.probe = aml_aml1218_probe,
.remove = aml_aml1218_remove,
.driver = {
.name = BL_EXTERN_NAME,
.owner = THIS_MODULE,
#ifdef CONFIG_USE_OF
.of_match_table = aml_aml1218_dt_match,
#endif
},
};
static int __init aml_aml1218_init(void)
{
int ret;
DBG_PRINT("%s\n", __func__);
ret = platform_driver_register(&aml_aml1218_driver);
if (ret) {
pr_err("[error] %s failed to register bl extern driver\n",
__func__);
return -ENODEV;
}
return ret;
}
static void __exit aml_aml1218_exit(void)
{
platform_driver_unregister(&aml_aml1218_driver);
}
rootfs_initcall(aml_aml1218_init);
module_exit(aml_aml1218_exit);
MODULE_AUTHOR("AMLOGIC");
MODULE_DESCRIPTION("BL Extern driver for aml1218");
MODULE_LICENSE("GPL");

View File

@@ -20,6 +20,8 @@
#include <linux/workqueue.h>
#include <linux/amlogic/aml_gpio_consumer.h>
#include <linux/pinctrl/consumer.h>
#include <linux/pwm.h>
#include <linux/amlogic/pwm_meson.h>
#define BLPR(fmt, args...) pr_info("bl: "fmt"", ## args)
#define BLERR(fmt, args...) pr_err("bl error: "fmt"", ## args)
@@ -147,6 +149,7 @@ struct bl_config_s {
struct bl_gpio_s bl_gpio[BL_GPIO_NUM_MAX];
struct pinctrl *pin;
unsigned int pinmux_flag;
unsigned int bl_extern_index;
};
#define BL_INDEX_DEFAULT 0

View File

@@ -15,62 +15,70 @@
*
*/
#ifndef __AMLOGIC_BL_EXTERN_H_
#define __AMLOGIC_BL_EXTERN_H_
#include <linux/amlogic/aml_gpio_consumer.h>
#include <linux/pinctrl/consumer.h>
#ifndef _INC_AML_BL_EXTERN_H_
#define _INC_AML_BL_EXTERN_H_
enum bl_extern_type_e {
BL_EXTERN_I2C = 0,
BL_EXTERN_SPI,
BL_EXTERN_OTHER,
BL_EXTERN_MIPI,
BL_EXTERN_MAX,
};
struct bl_extern_config_s {
const char *name;
enum bl_extern_type_e type;
struct gpio_desc *gpio;
unsigned char gpio_on;
unsigned char gpio_off;
enum bl_extern_i2c_bus_e {
BL_EXTERN_I2C_BUS_AO = 0,
BL_EXTERN_I2C_BUS_A,
BL_EXTERN_I2C_BUS_B,
BL_EXTERN_I2C_BUS_C,
BL_EXTERN_I2C_BUS_D,
BL_EXTERN_I2C_BUS_MAX,
};
#define BL_EXTERN_I2C_BUS_INVALID 0xff
int i2c_addr;
int i2c_bus;
struct gpio_desc *spi_cs;
struct gpio_desc *spi_clk;
struct gpio_desc *spi_data;
#define BL_EXTERN_SPI_CLK_FREQ_DFT 10000 /* default 10k */
#define BL_EXTERN_INIT_TABLE_MAX 500
#define BL_EXTERN_INIT_CMD 0x00
#define BL_EXTERN_INIT_NONE 0xf0
#define BL_EXTERN_INIT_END 0xff
#define BL_EXTERN_DYNAMIC_LEN 0xff
#define BL_EXTERN_GPIO_NUM_MAX 6
#define BL_EXTERN_INDEX_INVALID 0xff
#define BL_EXTERN_NAME_LEN_MAX 30
struct bl_extern_config_s {
unsigned char index;
char name[BL_EXTERN_NAME_LEN_MAX];
enum bl_extern_type_e type;
unsigned char i2c_addr;
unsigned char i2c_bus;
unsigned int dim_min;
unsigned int dim_max;
/* unsigned int level_min; */
/* unsigned int level_max; */
};
/*******global API******/
struct aml_bl_extern_driver_t {
const char *name;
enum bl_extern_type_e type;
/* global API */
#define BL_EXT_DRIVER_MAX 10
struct aml_bl_extern_driver_s {
int (*power_on)(void);
int (*power_off)(void);
int (*set_level)(unsigned int level);
void (*config_print)(void);
int (*device_power_on)(void);
int (*device_power_off)(void);
int (*device_bri_update)(unsigned int level);
struct bl_extern_config_s config;
struct device *dev;
};
#define BL_EXTERN_DRIVER "bl_extern"
extern struct aml_bl_extern_driver_s *aml_bl_extern_get_driver(void);
extern int aml_bl_extern_device_load(int index);
#ifdef CONFIG_AMLOGIC_LCD_TABLET
extern int dsi_write_cmd(unsigned char *payload);
#endif
#define bl_extern_gpio_free(gpio) gpiod_free(gpio, BL_EXTERN_DRIVER)
#define bl_extern_gpio_input(gpio) gpiod_direction_input(gpio)
#define bl_extern_gpio_output(gpio, val) gpiod_direction_output(gpio, val)
#define bl_extern_gpio_get_value(gpio) gpiod_get_value(gpio)
#define bl_extern_gpio_set_value(gpio, val) gpiod_set_value(gpio, val)
extern struct aml_bl_extern_driver_t *aml_bl_extern_get_driver(void);
extern int bl_extern_driver_check(void);
extern int get_bl_extern_dt_data(struct device dev,
struct bl_extern_config_s *pdata);
extern void get_bl_ext_level(struct bl_extern_config_s *bl_ext_cfg);
#endif