leds: qpnp-wled: add support for brightness mapping
Currently, WLED driver is being passed with a 12 bit brightness level by the clients and they're set in the hardware registers. Add support for brightness mapping by providing a 256 entry table where each entry can take a 12 bit brightness level value. This will be mapped internally for controlling different brightness regions in an user preferred way. Change-Id: I7adf97918a311bf54b02b383defeb59685aa0d00 Signed-off-by: Subbaraman Narayanamurthy <subbaram@codeaurora.org>
This commit is contained in:
parent
4f8f073776
commit
a1e681aaf6
2 changed files with 101 additions and 4 deletions
|
@ -80,6 +80,10 @@ Optional properties for WLED:
|
|||
or disabled.
|
||||
- qcom,auto-calibration-enable : A boolean property which enables auto-calibration
|
||||
of the WLED sink configuration.
|
||||
- qcom,wled-brightness-map : Array of brightness map codes of size 256.
|
||||
These codes will be mapped to the brightness
|
||||
level requested in the scale of 0-4095. Code
|
||||
entry is of 16 bit size.
|
||||
|
||||
Optional properties if 'qcom,disp-type-amoled' is mentioned in DT:
|
||||
- qcom,loop-comp-res-kohm : control to select the compensation resistor in kohm. default is 320.
|
||||
|
@ -123,4 +127,5 @@ Example:
|
|||
qcom,en-phase-stag;
|
||||
qcom,led-strings-list = [00 01 02 03];
|
||||
qcom,en-ext-pfet-sc-pro;
|
||||
qcom,wled-brightness-map = /bits/ 16 <0 . . 4095>;
|
||||
};
|
||||
|
|
|
@ -210,6 +210,7 @@
|
|||
#define QPNP_WLED_SEC_ACCESS_REG(b) (b + 0xD0)
|
||||
#define QPNP_WLED_SEC_UNLOCK 0xA5
|
||||
|
||||
#define NUM_DDIC_CODES 256
|
||||
#define QPNP_WLED_MAX_STRINGS 4
|
||||
#define QPNP_PM660_WLED_MAX_STRINGS 3
|
||||
#define WLED_MAX_LEVEL_4095 4095
|
||||
|
@ -340,6 +341,10 @@ static struct wled_vref_setting vref_setting_pmi8998 = {
|
|||
* @ ramp_ms - delay between ramp steps in ms
|
||||
* @ ramp_step - ramp step size
|
||||
* @ cons_sync_write_delay_us - delay between two consecutive writes to SYNC
|
||||
* @ auto_calibration_ovp_count - OVP fault irq count to run auto calibration
|
||||
* @ max_strings - Number of strings supported in WLED peripheral
|
||||
* @ prev_level - Previous brightness level
|
||||
* @ brt_map_table - Brightness map table
|
||||
* @ strings - supported list of strings
|
||||
* @ num_strings - number of strings
|
||||
* @ loop_auto_gm_thresh - the clamping level for auto gm
|
||||
|
@ -353,6 +358,12 @@ static struct wled_vref_setting vref_setting_pmi8998 = {
|
|||
* @ en_cabc - enable or disable cabc
|
||||
* @ disp_type_amoled - type of display: LCD/AMOLED
|
||||
* @ en_ext_pfet_sc_pro - enable sc protection on external pfet
|
||||
* @ prev_state - previous state of WLED
|
||||
* @ ovp_irq_disabled - OVP interrupt disable status
|
||||
* @ auto_calib_enabled - Flag to enable auto calibration feature
|
||||
* @ auto_calib_done - Flag to indicate auto calibration is done
|
||||
* @ module_dis_perm - Flat to keep module permanently disabled
|
||||
* @ start_ovp_fault_time - Time when the OVP fault first occurred
|
||||
*/
|
||||
struct qpnp_wled {
|
||||
struct led_classdev cdev;
|
||||
|
@ -388,6 +399,8 @@ struct qpnp_wled {
|
|||
u16 cons_sync_write_delay_us;
|
||||
u16 auto_calibration_ovp_count;
|
||||
u16 max_strings;
|
||||
u16 prev_level;
|
||||
u16 *brt_map_table;
|
||||
u8 strings[QPNP_WLED_MAX_STRINGS];
|
||||
u8 num_strings;
|
||||
u8 loop_auto_gm_thresh;
|
||||
|
@ -573,6 +586,33 @@ static int qpnp_wled_set_level(struct qpnp_wled *wled, int level)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int qpnp_wled_set_map_level(struct qpnp_wled *wled, int level)
|
||||
{
|
||||
int rc, i;
|
||||
|
||||
if (level < wled->prev_level) {
|
||||
for (i = wled->prev_level; i >= level; i--) {
|
||||
rc = qpnp_wled_set_level(wled, wled->brt_map_table[i]);
|
||||
if (rc < 0) {
|
||||
pr_err("set brightness level failed, rc:%d\n",
|
||||
rc);
|
||||
return rc;
|
||||
}
|
||||
}
|
||||
} else if (level > wled->prev_level) {
|
||||
for (i = wled->prev_level; i <= level; i++) {
|
||||
rc = qpnp_wled_set_level(wled, wled->brt_map_table[i]);
|
||||
if (rc < 0) {
|
||||
pr_err("set brightness level failed, rc:%d\n",
|
||||
rc);
|
||||
return rc;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int qpnp_wled_psm_config(struct qpnp_wled *wled, bool enable)
|
||||
{
|
||||
int rc;
|
||||
|
@ -942,15 +982,30 @@ static struct device_attribute qpnp_wled_attrs[] = {
|
|||
static void qpnp_wled_work(struct work_struct *work)
|
||||
{
|
||||
struct qpnp_wled *wled;
|
||||
int level, rc;
|
||||
int level, level_255, rc;
|
||||
|
||||
wled = container_of(work, struct qpnp_wled, work);
|
||||
|
||||
mutex_lock(&wled->lock);
|
||||
level = wled->cdev.brightness;
|
||||
|
||||
mutex_lock(&wled->lock);
|
||||
if (wled->brt_map_table) {
|
||||
/*
|
||||
* Change the 12 bit level to 8 bit level and use the mapped
|
||||
* values for 12 bit level from brightness map table.
|
||||
*/
|
||||
level_255 = DIV_ROUND_CLOSEST(level, 16);
|
||||
if (level_255 > 255)
|
||||
level_255 = 255;
|
||||
|
||||
if (level) {
|
||||
pr_debug("level: %d level_255: %d\n", level, level_255);
|
||||
rc = qpnp_wled_set_map_level(wled, level_255);
|
||||
if (rc) {
|
||||
dev_err(&wled->pdev->dev, "wled set level failed\n");
|
||||
goto unlock_mutex;
|
||||
}
|
||||
wled->prev_level = level_255;
|
||||
} else if (level) {
|
||||
rc = qpnp_wled_set_level(wled, level);
|
||||
if (rc) {
|
||||
dev_err(&wled->pdev->dev, "wled set level failed\n");
|
||||
|
@ -2115,7 +2170,7 @@ static int qpnp_wled_parse_dt(struct qpnp_wled *wled)
|
|||
struct property *prop;
|
||||
const char *temp_str;
|
||||
u32 temp_val;
|
||||
int rc, i;
|
||||
int rc, i, size;
|
||||
u8 *strings;
|
||||
|
||||
wled->cdev.name = "wled";
|
||||
|
@ -2134,6 +2189,43 @@ static int qpnp_wled_parse_dt(struct qpnp_wled *wled)
|
|||
return rc;
|
||||
}
|
||||
|
||||
if (of_find_property(pdev->dev.of_node, "qcom,wled-brightness-map",
|
||||
NULL)) {
|
||||
size = of_property_count_elems_of_size(pdev->dev.of_node,
|
||||
"qcom,wled-brightness-map", sizeof(u16));
|
||||
if (size != NUM_DDIC_CODES) {
|
||||
pr_err("Invalid WLED brightness map size:%d\n", size);
|
||||
return rc;
|
||||
}
|
||||
|
||||
wled->brt_map_table = devm_kcalloc(&pdev->dev, NUM_DDIC_CODES,
|
||||
sizeof(u16), GFP_KERNEL);
|
||||
if (!wled->brt_map_table)
|
||||
return -ENOMEM;
|
||||
|
||||
rc = of_property_read_u16_array(pdev->dev.of_node,
|
||||
"qcom,wled-brightness-map", wled->brt_map_table,
|
||||
NUM_DDIC_CODES);
|
||||
if (rc < 0) {
|
||||
pr_err("Error in reading WLED brightness map, rc=%d\n",
|
||||
rc);
|
||||
return rc;
|
||||
}
|
||||
|
||||
for (i = 0; i < NUM_DDIC_CODES; i++) {
|
||||
if (wled->brt_map_table[i] > WLED_MAX_LEVEL_4095) {
|
||||
pr_err("WLED brightness map not in range\n");
|
||||
return -EDOM;
|
||||
}
|
||||
|
||||
if ((i > 1) && wled->brt_map_table[i]
|
||||
< wled->brt_map_table[i - 1]) {
|
||||
pr_err("WLED brightness map not in ascending order?\n");
|
||||
return -EDOM;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
wled->disp_type_amoled = of_property_read_bool(pdev->dev.of_node,
|
||||
"qcom,disp-type-amoled");
|
||||
if (wled->disp_type_amoled) {
|
||||
|
|
Loading…
Add table
Reference in a new issue