Created
February 16, 2014 18:14
-
-
Save axsddlr/9038365 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* Copyright (c) 2012-2013, The Linux Foundation. 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 version 2 and | |
* only version 2 as published by the Free Software Foundation. | |
* | |
* 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/module.h> | |
#include <linux/interrupt.h> | |
#include <linux/of.h> | |
#include <linux/of_gpio.h> | |
#include <linux/gpio.h> | |
#include <linux/qpnp/pin.h> | |
#include <linux/delay.h> | |
#include <linux/slab.h> | |
#include <linux/leds.h> | |
#include <linux/pwm.h> | |
#include <linux/err.h> | |
#if defined(CONFIG_MACH_LGE) | |
#include <linux/syscore_ops.h> | |
#endif | |
#ifdef CONFIG_LGE_SUPPORT_LCD_MAKER_ID | |
#include <mach/board_lge.h> | |
#include <linux/qpnp/qpnp-adc.h> | |
#include <linux/err.h> | |
#endif | |
#include "mdss_dsi.h" | |
#include <asm/system_info.h> | |
#define DT_CMD_HDR 6 | |
#ifdef CONFIG_LGE_LCD_TUNING | |
#define TUNING_REGSIZE 400 | |
#endif | |
#define GAMMA_COMPAT 11 | |
#if defined(CONFIG_MACH_LGE) | |
#if defined(CONFIG_OLED_SUPPORT) | |
#include "mdss_mdp.h" | |
#include "mdss_fb.h" | |
extern struct msm_fb_data_type *mfd_base; | |
#else | |
#include "mdss_mdp.h" | |
#include "mdss_fb.h" | |
extern struct msm_fb_data_type *mfd_base; | |
static struct dsi_panel_cmds lge_ief_on_cmds; | |
static struct dsi_panel_cmds lge_ief_off_cmds; | |
#endif | |
#endif | |
//Basic color preset | |
int color_preset = 0; | |
module_param(color_preset, int, 0755); | |
static bool mdss_panel_flip_ud = false; | |
static int mdss_panel_id = PANEL_QCOM; | |
#ifdef CONFIG_LGE_LCD_TUNING | |
/* LGE_CHANGE_S | |
* Add code to apply tuning method for LCD | |
* 2012-12-03, [email protected] | |
*/ | |
extern int num_cmds; | |
extern int tun_len; | |
extern char init_buf[TUNING_REGSIZE]; | |
extern struct dsi_cmd_desc *tun_dsi_panel_on_cmds; | |
extern u32 tun_porch_value[6]; | |
struct mipi_panel_info *mipi; | |
static struct dsi_cmd_desc *dsi_panel_on_cmds; | |
static struct dsi_cmd_desc *dsi_panel_off_cmds; | |
static int num_of_on_cmds; | |
static int num_of_off_cmds; | |
static char *on_cmds, *off_cmds; | |
#endif /* CONFIG_LGE_LCD_TUNING */ | |
DEFINE_LED_TRIGGER(bl_led_trigger); | |
#if defined(CONFIG_BACKLIGHT_LM3630) | |
extern void lm3630_lcd_backlight_set_level(int level); | |
#endif /* CONFIG_BACKLIGHT_LMXXXX */ | |
//#if defined(CONFIG_MACH_LGE) | |
//struct mdss_panel_data *pdata_base; | |
//extern int mdss_dsi_panel_power_on(struct mdss_panel_data *pdata, int enable); | |
//#endif | |
#if defined(CONFIG_OLED_SUPPORT) | |
extern int mdss_dsi_off(struct mdss_panel_data *pdata); | |
#endif | |
static struct mdss_dsi_phy_ctrl phy_params; | |
static struct mdss_panel_common_pdata *local_pdata; | |
static struct work_struct send_cmds_work; | |
struct mdss_panel_data *cmds_panel_data; | |
static struct platform_driver this_driver; | |
struct kobject *module_kobj; | |
#ifdef CONFIG_LGE_SUPPORT_LCD_MAKER_ID | |
int g_mvol_for_lcd; | |
static lcd_vol_maker_tbl_type lcd_maker_table[LCD_MAKER_MAX] = { | |
{LCD_RENESAS_LGD, 0, 900}, | |
{LCD_RENESAS_JDI, 901, 1800}, | |
}; | |
static lcd_maker_id get_lcd_maker_by_voltage(int mvol) | |
{ | |
lcd_maker_id lcd_maker = LCD_MAKER_MAX; | |
int i = 0; | |
for(i = 0; i < LCD_MAKER_MAX; i++){ | |
if (lcd_maker_table[i].min_mvol <= mvol && | |
mvol <= lcd_maker_table[i].max_mvol) { | |
lcd_maker = lcd_maker_table[i].maker_id; | |
break; | |
} | |
} | |
g_mvol_for_lcd = mvol; | |
return lcd_maker; | |
} | |
lcd_maker_id get_panel_maker_id(void) | |
{ | |
struct qpnp_vadc_result result; | |
lcd_maker_id maker_id = LCD_MAKER_MAX; | |
int rc; | |
int acc_read_value = 0; | |
rc = qpnp_vadc_read(P_MUX5_1_1, &result); | |
if (rc < 0) { | |
if (rc == -ETIMEDOUT) { | |
acc_read_value = 0; | |
} | |
pr_err("%s : adc read " | |
"error - %d\n", __func__, rc); | |
} | |
acc_read_value = (int)result.physical / 1000; | |
pr_debug("%s: acc_read_value - %d\n", __func__, | |
(int)result.physical); | |
maker_id = get_lcd_maker_by_voltage(acc_read_value); | |
return maker_id; | |
} | |
EXPORT_SYMBOL(get_panel_maker_id); | |
static ssize_t panel_maker_id_show(struct device *dev, | |
struct device_attribute *attr, char *buf) | |
{ | |
return sprintf(buf, "%d\n", get_panel_maker_id()); | |
} | |
static DEVICE_ATTR(panel_maker_id, 0444, panel_maker_id_show, NULL); | |
#endif | |
#if defined(CONFIG_OLED_SUPPORT) && defined(CONFIG_LGE_OLED_IMG_TUNING) | |
#include "mdss_mdp.h" | |
#define IMG_TUNE_COUNT 6 | |
static int img_tune_mode = 1; // Default value : cm0(standard) + plc 60% | |
struct img_tune_cmds_desc { | |
struct dsi_panel_cmds img_tune_cmds[IMG_TUNE_COUNT]; | |
}; | |
static char *img_tune_dt[] = { | |
"lge,img-tune-cmds-cm0", | |
"lge,img-tune-cmds-ce-cm0-plc60", | |
"lge,img-tune-cmds-cm1", | |
"lge,img-tune-cmds-ce-cm1-plc60", | |
"lge,img-tune-cmds-cm2", | |
"lge,img-tune-cmds-ce-cm2-plc60", | |
}; | |
static struct img_tune_cmds_desc *img_tune_cmds_set; | |
static int bl_tune_mode = 1; // Default value : use the blmap | |
#endif | |
void mdss_dsi_panel_pwm_cfg(struct mdss_dsi_ctrl_pdata *ctrl) | |
{ | |
int ret; | |
if (!gpio_is_valid(ctrl->pwm_pmic_gpio)) { | |
pr_err("%s: pwm_pmic_gpio=%d Invalid\n", __func__, | |
ctrl->pwm_pmic_gpio); | |
ctrl->pwm_pmic_gpio = -1; | |
return; | |
} | |
ret = gpio_request(ctrl->pwm_pmic_gpio, "disp_pwm"); | |
if (ret) { | |
pr_err("%s: pwm_pmic_gpio=%d request failed\n", __func__, | |
ctrl->pwm_pmic_gpio); | |
ctrl->pwm_pmic_gpio = -1; | |
return; | |
} | |
ctrl->pwm_bl = pwm_request(ctrl->pwm_lpg_chan, "lcd-bklt"); | |
if (ctrl->pwm_bl == NULL || IS_ERR(ctrl->pwm_bl)) { | |
pr_err("%s: lpg_chan=%d pwm request failed", __func__, | |
ctrl->pwm_lpg_chan); | |
gpio_free(ctrl->pwm_pmic_gpio); | |
ctrl->pwm_pmic_gpio = -1; | |
} | |
} | |
static void mdss_dsi_panel_bklt_pwm(struct mdss_dsi_ctrl_pdata *ctrl, int level) | |
{ | |
int ret; | |
u32 duty; | |
if (ctrl->pwm_bl == NULL) { | |
pr_err("%s: no PWM\n", __func__); | |
return; | |
} | |
duty = level * ctrl->pwm_period; | |
duty /= ctrl->bklt_max; | |
pr_debug("%s: bklt_ctrl=%d pwm_period=%d pwm_gpio=%d pwm_lpg_chan=%d\n", | |
__func__, ctrl->bklt_ctrl, ctrl->pwm_period, | |
ctrl->pwm_pmic_gpio, ctrl->pwm_lpg_chan); | |
pr_debug("%s: ndx=%d level=%d duty=%d\n", __func__, | |
ctrl->ndx, level, duty); | |
ret = pwm_config(ctrl->pwm_bl, duty, ctrl->pwm_period); | |
if (ret) { | |
pr_err("%s: pwm_config() failed err=%d.\n", __func__, ret); | |
return; | |
} | |
ret = pwm_enable(ctrl->pwm_bl); | |
if (ret) | |
pr_err("%s: pwm_enable() failed err=%d\n", __func__, ret); | |
} | |
static char dcs_cmd[2] = {0x54, 0x00}; /* DTYPE_DCS_READ */ | |
static struct dsi_cmd_desc dcs_read_cmd = { | |
{DTYPE_DCS_READ, 1, 0, 1, 5, sizeof(dcs_cmd)}, | |
dcs_cmd | |
}; | |
static void dcs_read_cb(u32 data) | |
{ | |
pr_info("%s: data=0x%x\n", __func__, ntohl(data)); | |
} | |
u32 mdss_dsi_dcs_read(struct mdss_dsi_ctrl_pdata *ctrl, | |
char cmd0, char cmd1) | |
{ | |
struct dcs_cmd_req cmdreq; | |
dcs_cmd[0] = cmd0; | |
dcs_cmd[1] = cmd1; | |
memset(&cmdreq, 0, sizeof(cmdreq)); | |
cmdreq.cmds = &dcs_read_cmd; | |
cmdreq.cmds_cnt = 1; | |
cmdreq.flags = CMD_REQ_RX | CMD_REQ_COMMIT; | |
cmdreq.rlen = 1; | |
cmdreq.cb = dcs_read_cb; /* call back */ | |
mdss_dsi_cmdlist_put(ctrl, &cmdreq); | |
/* | |
* blocked here, until call back called | |
*/ | |
return 0; | |
} | |
static void mdss_dsi_panel_cmds_send(struct mdss_dsi_ctrl_pdata *ctrl, | |
struct dsi_panel_cmds *pcmds) | |
{ | |
struct dcs_cmd_req cmdreq; | |
memset(&cmdreq, 0, sizeof(cmdreq)); | |
cmdreq.cmds = pcmds->cmds; | |
cmdreq.cmds_cnt = pcmds->cmd_cnt; | |
cmdreq.flags = CMD_REQ_COMMIT; | |
cmdreq.rlen = 0; | |
cmdreq.cb = NULL; | |
mdss_dsi_cmdlist_put(ctrl, &cmdreq); | |
} | |
static char led_pwm1[2] = {0x51, 0x0}; /* DTYPE_DCS_WRITE1 */ | |
static struct dsi_cmd_desc backlight_cmd = { | |
{DTYPE_DCS_WRITE1, 1, 0, 0, 0, sizeof(led_pwm1)}, | |
led_pwm1 | |
}; | |
static void mdss_dsi_panel_bklt_dcs(struct mdss_dsi_ctrl_pdata *ctrl, int level) | |
{ | |
struct dcs_cmd_req cmdreq; | |
pr_debug("%s: level=%d\n", __func__, level); | |
#ifdef CONFIG_OLED_SUPPORT | |
if (bl_tune_mode) | |
led_pwm1[1] = (unsigned char)ctrl->panel_data.panel_info.blmap[level]; | |
else | |
led_pwm1[1] = (unsigned char)level; | |
pr_info("[Zee][OLED] %s: level=%d, blmap=%d\n", __func__, level, led_pwm1[1]); | |
#else | |
led_pwm1[1] = (unsigned char)level; | |
#endif | |
memset(&cmdreq, 0, sizeof(cmdreq)); | |
cmdreq.cmds = &backlight_cmd; | |
cmdreq.cmds_cnt = 1; | |
cmdreq.flags = CMD_REQ_COMMIT | CMD_CLK_CTRL; | |
cmdreq.rlen = 0; | |
cmdreq.cb = NULL; | |
mdss_dsi_cmdlist_put(ctrl, &cmdreq); | |
} | |
void mdss_dsi_panel_reset(struct mdss_panel_data *pdata, int enable) | |
{ | |
struct mdss_dsi_ctrl_pdata *ctrl_pdata = NULL; | |
if (pdata == NULL) { | |
pr_err("%s: Invalid input data\n", __func__); | |
return; | |
} | |
ctrl_pdata = container_of(pdata, struct mdss_dsi_ctrl_pdata, | |
panel_data); | |
#ifndef CONFIG_MACH_LGE | |
/* LGE_CHANGE_S | |
* power sequence for LGD_FHD panel | |
* 2013-04-05, [email protected] | |
*/ | |
if (!gpio_is_valid(ctrl_pdata->disp_en_gpio)) { | |
pr_debug("%s:%d, reset line not configured\n", | |
__func__, __LINE__); | |
} | |
#endif | |
if (!gpio_is_valid(ctrl_pdata->rst_gpio)) { | |
pr_debug("%s:%d, reset line not configured\n", | |
__func__, __LINE__); | |
return; | |
} | |
pr_debug("%s: enable = %d\n", __func__, enable); | |
if (enable) { | |
#ifdef CONFIG_OLED_SUPPORT | |
gpio_set_value((ctrl_pdata->rst_gpio), 1); | |
#else // CONFIG_OLED_SUPPORT | |
#ifdef CONFIG_MACH_LGE | |
gpio_set_value((ctrl_pdata->rst_gpio), 1); | |
msleep(5); | |
#else | |
gpio_set_value((ctrl_pdata->rst_gpio), 1); | |
msleep(20); | |
gpio_set_value((ctrl_pdata->rst_gpio), 0); | |
udelay(200); | |
gpio_set_value((ctrl_pdata->rst_gpio), 1); | |
msleep(20); | |
#endif | |
#endif | |
#ifndef CONFIG_MACH_LGE | |
/* maintain qmc's original code */ | |
if (gpio_is_valid(ctrl_pdata->disp_en_gpio)) | |
gpio_set_value((ctrl_pdata->disp_en_gpio), 1); | |
#endif | |
if (ctrl_pdata->ctrl_state & CTRL_STATE_PANEL_INIT) { | |
pr_debug("%s: Panel Not properly turned OFF\n", | |
__func__); | |
ctrl_pdata->ctrl_state &= ~CTRL_STATE_PANEL_INIT; | |
pr_debug("%s: Reset panel done\n", __func__); | |
} | |
} else { | |
gpio_set_value((ctrl_pdata->rst_gpio), 0); | |
#ifndef CONFIG_MACH_LGE | |
/* LGE_CHANGE_S | |
* power sequence for LGD_FHD panel | |
* 2013-04-05, [email protected] | |
*/ | |
if (gpio_is_valid(ctrl_pdata->disp_en_gpio)) | |
gpio_set_value((ctrl_pdata->disp_en_gpio), 0); | |
#endif | |
} | |
} | |
static void mdss_dsi_panel_bl_ctrl(struct mdss_panel_data *pdata, | |
u32 bl_level) | |
{ | |
struct mdss_dsi_ctrl_pdata *ctrl_pdata = NULL; | |
#ifdef CONFIG_OLED_SUPPORT | |
struct mipi_panel_info *mipi; | |
mipi = &pdata->panel_info.mipi; | |
#endif | |
if (pdata == NULL) { | |
pr_err("%s: Invalid input data\n", __func__); | |
return; | |
} | |
ctrl_pdata = container_of(pdata, struct mdss_dsi_ctrl_pdata, | |
panel_data); | |
switch (ctrl_pdata->bklt_ctrl) { | |
case BL_WLED: | |
#if defined(CONFIG_BACKLIGHT_LM3630) | |
lm3630_lcd_backlight_set_level(bl_level); | |
#else | |
led_trigger_event(bl_led_trigger, bl_level); | |
#endif | |
break; | |
case BL_PWM: | |
mdss_dsi_panel_bklt_pwm(ctrl_pdata, bl_level); | |
break; | |
case BL_DCS_CMD: | |
#ifdef CONFIG_OLED_SUPPORT | |
if (mipi->mode == DSI_VIDEO_MODE) { | |
if (bl_level > 0xFF) bl_level = 0xFF; | |
} else { | |
pr_err("%s:%d, CMD MODE NOT SUPPORTED", __func__, __LINE__); | |
return; | |
} | |
#endif | |
mdss_dsi_panel_bklt_dcs(ctrl_pdata, bl_level); | |
break; | |
default: | |
pr_err("%s: Unknown bl_ctrl configuration\n", | |
__func__); | |
break; | |
} | |
} | |
static int mdss_dsi_panel_on(struct mdss_panel_data *pdata) | |
{ | |
struct mipi_panel_info *mipi; | |
struct mdss_dsi_ctrl_pdata *ctrl = NULL; | |
if (pdata == NULL) { | |
pr_err("%s: Invalid input data\n", __func__); | |
return -EINVAL; | |
} | |
ctrl = container_of(pdata, struct mdss_dsi_ctrl_pdata, | |
panel_data); | |
#if defined(CONFIG_MACH_LGE) | |
if(pdata_base == NULL) | |
pdata_base = pdata; | |
#endif | |
mipi = &pdata->panel_info.mipi; | |
#ifdef CONFIG_LGE_SUPPORT_LCD_MAKER_ID | |
pr_info("%s: ctrl=%p ndx=%d maker=%d\n", __func__, ctrl, ctrl->ndx, get_panel_maker_id()); | |
#else | |
pr_info("%s: ctrl=%p ndx=%d\n", __func__, ctrl, ctrl->ndx); | |
#endif | |
//Basic color preset | |
if (color_preset == 1) | |
local_pdata->on_cmds.cmds[1].payload[0] = 0x77; | |
else | |
local_pdata->on_cmds.cmds[1].payload[0] = 0xFF; | |
if (local_pdata->on_cmds.cmd_cnt) | |
mdss_dsi_panel_cmds_send(ctrl, &local_pdata->on_cmds); | |
#endif | |
pr_debug("%s:-\n", __func__); | |
return 0; | |
} | |
static int mdss_dsi_panel_off(struct mdss_panel_data *pdata) | |
{ | |
struct mipi_panel_info *mipi; | |
struct mdss_dsi_ctrl_pdata *ctrl = NULL; | |
if (pdata == NULL) { | |
pr_err("%s: Invalid input data\n", __func__); | |
return -EINVAL; | |
} | |
ctrl = container_of(pdata, struct mdss_dsi_ctrl_pdata, | |
panel_data); | |
pr_info("%s: ctrl=%p ndx=%d\n", __func__, ctrl, ctrl->ndx); | |
mipi = &pdata->panel_info.mipi; | |
#if defined(CONFIG_MACH_LGE) | |
if (!gpio_get_value(ctrl->disp_en_gpio)) // we should remove the semi-colon | |
return 0; | |
#endif | |
if (ctrl->off_cmds.cmd_cnt) | |
mdss_dsi_panel_cmds_send(ctrl, &ctrl->off_cmds); | |
pr_debug("%s:-\n", __func__); | |
#ifdef CONFIG_OLED_SUPPORT | |
pr_info("[Zee][OLED] %s success\n", __func__); | |
#endif | |
return 0; | |
} | |
#if defined(CONFIG_MACH_LGE) && !(defined(CONFIG_MACH_MSM8974_Z_KR) || defined(CONFIG_MACH_MSM8974_Z_US) || defined(CONFIG_MACH_MSM8974_Z_KDDI)) | |
int mdss_dsi_panel_ief_off(void) | |
{ | |
struct mdss_dsi_ctrl_pdata *ctrl = NULL; | |
if (pdata_base == NULL || mfd_base == NULL) { | |
pr_err("%s: Invalid input data\n", __func__); | |
return -EINVAL; | |
} | |
if (mfd_base->panel_power_on == 0) { | |
pr_err("%s: Panel is off\n", __func__); | |
return -EPERM; | |
} | |
ctrl = container_of(pdata_base, struct mdss_dsi_ctrl_pdata, panel_data); | |
if(lge_ief_off_cmds.cmd_cnt){ | |
pr_info("sending IEF_OFF code\n"); | |
mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_ON, false); | |
mdss_dsi_panel_cmds_send(ctrl, &lge_ief_off_cmds); | |
mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_OFF, false); | |
} | |
return 0; | |
} | |
EXPORT_SYMBOL(mdss_dsi_panel_ief_off); | |
int mdss_dsi_panel_ief_on(void) | |
{ | |
struct mdss_dsi_ctrl_pdata *ctrl = NULL; | |
if (pdata_base == NULL || mfd_base == NULL) { | |
pr_err("%s: Invalid input data\n", __func__); | |
return -EINVAL; | |
} | |
if (mfd_base->panel_power_on == 0) { | |
pr_err("%s: Panel is off\n", __func__); | |
return -EPERM; | |
} | |
ctrl = container_of(pdata_base, struct mdss_dsi_ctrl_pdata, panel_data); | |
if(lge_ief_on_cmds.cmd_cnt){ | |
pr_info("sending IEF_ON code\n"); | |
mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_ON, false); | |
mdss_dsi_panel_cmds_send(ctrl, &lge_ief_on_cmds); | |
mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_OFF, false); | |
} | |
return 0; | |
} | |
EXPORT_SYMBOL(mdss_dsi_panel_ief_on); | |
static ssize_t ief_on_off(struct device *dev, | |
struct device_attribute *attr, | |
const char *buf, size_t count) | |
{ | |
int on_off; | |
if (!count) | |
return -EINVAL; | |
on_off = simple_strtoul(buf, NULL, 10); | |
pr_debug("[LCD][DEBUG] %s, %d", __func__, on_off); | |
if (on_off == 0) | |
mdss_dsi_panel_ief_off(); | |
else | |
mdss_dsi_panel_ief_on(); | |
return count; | |
} | |
DEVICE_ATTR(ief_on_off, 0644, NULL, ief_on_off); | |
#endif | |
#if defined(CONFIG_OLED_SUPPORT) && defined(CONFIG_LGE_OLED_IMG_TUNING) | |
int mdss_dsi_panel_img_tune_apply(unsigned int screen_mode) | |
{ | |
struct mdss_dsi_ctrl_pdata *ctrl = NULL; | |
if (pdata_base == NULL) { | |
pr_err("%s: Invalid input data.\n", __func__); | |
return -EINVAL; | |
} | |
ctrl = container_of(pdata_base, struct mdss_dsi_ctrl_pdata, | |
panel_data); | |
if (pdata_base->panel_info.panel_power_on == 0) { | |
pr_err("%s: panel off state. This screen mode will not be applied.\n", __func__); | |
return -EINVAL; | |
} | |
/* | |
if (ctrl->ctrl_state != (CTRL_STATE_PANEL_INIT | CTRL_STATE_MDP_ACTIVE)) { | |
pr_err("%s: panel is not 'on' state(cur=%d). The screen mode will be applied next time.\n", __func__, ctrl->ctrl_state); | |
return -EINVAL; | |
} | |
*/ | |
if ((screen_mode < 0) || (screen_mode > IMG_TUNE_COUNT)) { | |
pr_err("%s: invalid input data(%d). Retry(0-5).\n", __func__, screen_mode); | |
return -EINVAL; | |
} | |
if (screen_mode == IMG_TUNE_COUNT) { | |
pr_info("%s: send the screen mode on(%d) from kernel.\n", __func__, img_tune_mode); | |
} else { | |
img_tune_mode = screen_mode; | |
pr_info("%s: send the screen mode on(%d) from user.\n", __func__, img_tune_mode); | |
} | |
if(img_tune_cmds_set->img_tune_cmds[img_tune_mode].cmd_cnt) { | |
mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_ON, false); | |
// 0 : CM0 / 1 : CM0 + PLC 60% / 2 : CM1 / 3 : CM1 + PLC 60% / 4 : CM2 / 5 : CM2 + PLC 60% | |
mdss_dsi_panel_cmds_send(ctrl, &img_tune_cmds_set->img_tune_cmds[img_tune_mode]); | |
mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_OFF, false); | |
} | |
return 0; | |
} | |
EXPORT_SYMBOL(mdss_dsi_panel_img_tune_apply); | |
static ssize_t img_tune_mode_get(struct device *dev, | |
struct device_attribute *attr, char *buf) | |
{ | |
return sprintf(buf, "%d\n", img_tune_mode); | |
} | |
static ssize_t img_tune_mode_set(struct device *dev, | |
struct device_attribute *attr, const char *buf, size_t size) | |
{ | |
unsigned int param; | |
ssize_t ret = strnlen(buf, PAGE_SIZE); | |
sscanf(buf, "%x", ¶m); | |
mdss_dsi_panel_img_tune_apply(param); | |
return ret; | |
} | |
static ssize_t bl_tune_mode_get(struct device *dev, | |
struct device_attribute *attr, char *buf) | |
{ | |
return sprintf(buf, "%d\n", bl_tune_mode); | |
} | |
static ssize_t bl_tune_mode_set(struct device *dev, | |
struct device_attribute *attr, const char *buf, size_t size) | |
{ | |
unsigned int param; | |
ssize_t ret = strnlen(buf, PAGE_SIZE); | |
sscanf(buf, "%x", ¶m); | |
bl_tune_mode = param; | |
return ret; | |
} | |
static ssize_t mipi_dsi_read_set(struct device *dev, | |
struct device_attribute *attr, const char *buf, size_t size) | |
{ | |
unsigned int reg_addr; | |
ssize_t ret = strnlen(buf, PAGE_SIZE); | |
struct mdss_dsi_ctrl_pdata *ctrl = NULL; | |
if (pdata_base == NULL) { | |
pr_err("%s: Invalid input data\n", __func__); | |
return -EINVAL; | |
} | |
ctrl = container_of(pdata_base, struct mdss_dsi_ctrl_pdata, | |
panel_data); | |
sscanf(buf, "%x", ®_addr); | |
mdss_dsi_dcs_read(ctrl, (char)reg_addr, 0x00); | |
return ret; | |
} | |
static struct device_attribute panel_tuning_device_attrs[] = { | |
__ATTR(img_tune_mode, 0644, img_tune_mode_get, img_tune_mode_set), | |
__ATTR(bl_tune_mode, 0644, bl_tune_mode_get, bl_tune_mode_set), | |
__ATTR(mipi_dsi_read, 0644 , NULL, mipi_dsi_read_set), | |
}; | |
#endif | |
static int mdss_dsi_parse_dcs_cmds(struct device_node *np, | |
struct dsi_panel_cmds *pcmds, char *cmd_key, char *link_key) | |
{ | |
const char *data; | |
int blen = 0, len; | |
char *buf, *bp; | |
struct dsi_ctrl_hdr *dchdr; | |
int i, cnt; | |
data = of_get_property(np, cmd_key, &blen); | |
if (!data) { | |
pr_err("%s: failed, key=%s\n", __func__, cmd_key); | |
return -ENOMEM; | |
} | |
buf = kzalloc(sizeof(char) * blen, GFP_KERNEL); | |
if (!buf) | |
return -ENOMEM; | |
memcpy(buf, data, blen); | |
/* scan dcs commands */ | |
bp = buf; | |
len = blen; | |
cnt = 0; | |
while (len > sizeof(*dchdr)) { | |
dchdr = (struct dsi_ctrl_hdr *)bp; | |
dchdr->dlen = ntohs(dchdr->dlen); | |
if (dchdr->dlen > len) { | |
pr_err("%s: dtsi cmd=%x error, len=%d", | |
__func__, dchdr->dtype, dchdr->dlen); | |
return -ENOMEM; | |
} | |
bp += sizeof(*dchdr); | |
len -= sizeof(*dchdr); | |
bp += dchdr->dlen; | |
len -= dchdr->dlen; | |
cnt++; | |
} | |
if (len != 0) { | |
pr_err("%s: dcs_cmd=%x len=%d error!", | |
__func__, buf[0], blen); | |
kfree(buf); | |
return -ENOMEM; | |
} | |
pcmds->cmds = kzalloc(cnt * sizeof(struct dsi_cmd_desc), | |
GFP_KERNEL); | |
if (!pcmds->cmds) | |
return -ENOMEM; | |
pcmds->cmd_cnt = cnt; | |
pcmds->buf = buf; | |
pcmds->blen = blen; | |
bp = buf; | |
len = blen; | |
for (i = 0; i < cnt; i++) { | |
dchdr = (struct dsi_ctrl_hdr *)bp; | |
len -= sizeof(*dchdr); | |
bp += sizeof(*dchdr); | |
pcmds->cmds[i].dchdr = *dchdr; | |
pcmds->cmds[i].payload = bp; | |
bp += dchdr->dlen; | |
len -= dchdr->dlen; | |
} | |
pcmds->link_state = DSI_LP_MODE; /* default */ | |
data = of_get_property(np, link_key, NULL); | |
if (!strncmp(data, "DSI_HS_MODE", 11)) | |
pcmds->link_state = DSI_HS_MODE; | |
pr_debug("%s: dcs_cmd=%x len=%d, cmd_cnt=%d link_state=%d\n", __func__, | |
pcmds->buf[0], pcmds->blen, pcmds->cmd_cnt, pcmds->link_state); | |
return 0; | |
} | |
#if defined(CONFIG_MACH_LGE) | |
/* [email protected] | |
* In the normal case, when the device turnned off, lcd off function doesn't work. | |
* But, It's need to turn off the panel device in order to prevent flicking issue. | |
* So, Add lcd turn off function when the device shut down. | |
*/ | |
static void mdss_dsi_panel_shutdown(void) | |
{ | |
if (mfd_base == NULL) { | |
pr_err("%s: Invalid input data\n", __func__); | |
return; | |
} | |
#ifdef CONFIG_OLED_SUPPORT | |
mfd_base->fbi->fbops->fb_blank(FB_BLANK_POWERDOWN, mfd_base->fbi); | |
pr_info("[Zee][OLED] %s success\n", __func__); | |
#else | |
pr_info("%s - start panel shutdown in order to prevent s/w flickering\n", __func__); | |
lm3630_lcd_backlight_set_level(0); | |
mfd_base->fbi->fbops->fb_blank(FB_BLANK_POWERDOWN, mfd_base->fbi); | |
pr_info("%s complete\n", __func__); | |
#endif | |
} | |
#endif | |
static int mdss_panel_parse_dt(struct platform_device *pdev, | |
struct mdss_panel_common_pdata *panel_data) | |
{ | |
struct device_node *np = pdev->dev.of_node; | |
u32 res[6], tmp; | |
u32 fbc_res[7]; | |
int rc, i, len; | |
const char *data; | |
static const char *bl_ctrl_type, *pdest; | |
bool fbc_enabled = false; | |
#ifdef CONFIG_OLED_SUPPORT | |
u32 *array; | |
#endif | |
rc = of_property_read_u32_array(np, "qcom,mdss-pan-res", res, 2); | |
if (rc) { | |
pr_err("%s:%d, panel resolution not specified\n", | |
__func__, __LINE__); | |
return -EINVAL; | |
} | |
panel_data->panel_info.xres = (!rc ? res[0] : 640); | |
panel_data->panel_info.yres = (!rc ? res[1] : 480); | |
rc = of_property_read_u32_array(np, "qcom,mdss-pan-active-res", res, 2); | |
if (rc == 0) { | |
panel_data->panel_info.lcdc.xres_pad = | |
panel_data->panel_info.xres - res[0]; | |
panel_data->panel_info.lcdc.yres_pad = | |
panel_data->panel_info.yres - res[1]; | |
} | |
#ifdef CONFIG_OLED_SUPPORT | |
rc = of_property_read_u32_array(np, "qcom,mdss-pan-margin-res", res, 2); | |
if (rc == 0) { | |
panel_data->panel_info.lcdc.xres_margin= | |
res[0] - panel_data->panel_info.xres; | |
panel_data->panel_info.lcdc.yres_margin= | |
res[1] - panel_data->panel_info.yres; | |
} | |
#endif | |
rc = of_property_read_u32(np, "qcom,mdss-pan-bpp", &tmp); | |
if (rc) { | |
pr_err("%s:%d, panel bpp not specified\n", | |
__func__, __LINE__); | |
return -EINVAL; | |
} | |
panel_data->panel_info.bpp = (!rc ? tmp : 24); | |
rc = of_property_read_u32(np, "qcom,mdss-pan-width", &tmp); | |
if (rc) | |
pr_warn("%s:%d, panel width not specified\n", | |
__func__, __LINE__); | |
panel_data->panel_info.width = (!rc ? tmp : 0); | |
rc = of_property_read_u32(np, "qcom,mdss-pan-height", &tmp); | |
if (rc) | |
pr_warn("%s:%d, panel height not specified\n", | |
__func__, __LINE__); | |
panel_data->panel_info.height = (!rc ? tmp : 0); | |
pdest = of_get_property(pdev->dev.of_node, | |
"qcom,mdss-pan-dest", NULL); | |
if (strlen(pdest) != 9) { | |
pr_err("%s: Unknown pdest specified\n", __func__); | |
return -EINVAL; | |
} | |
if (!strncmp(pdest, "display_1", 9)) | |
panel_data->panel_info.pdest = DISPLAY_1; | |
else if (!strncmp(pdest, "display_2", 9)) | |
panel_data->panel_info.pdest = DISPLAY_2; | |
else { | |
pr_debug("%s: pdest not specified. Set Default\n", | |
__func__); | |
panel_data->panel_info.pdest = DISPLAY_1; | |
} | |
rc = of_property_read_u32_array(np, | |
"qcom,mdss-pan-porch-values", res, 6); | |
#ifdef CONFIG_LGE_LCD_TUNING | |
memcpy(tun_porch_value, res, sizeof(tun_porch_value)); | |
#endif | |
panel_data->panel_info.lcdc.h_back_porch = (!rc ? res[0] : 6); | |
panel_data->panel_info.lcdc.h_pulse_width = (!rc ? res[1] : 2); | |
panel_data->panel_info.lcdc.h_front_porch = (!rc ? res[2] : 6); | |
panel_data->panel_info.lcdc.v_back_porch = (!rc ? res[3] : 6); | |
panel_data->panel_info.lcdc.v_pulse_width = (!rc ? res[4] : 2); | |
panel_data->panel_info.lcdc.v_front_porch = (!rc ? res[5] : 6); | |
rc = of_property_read_u32(np, | |
"qcom,mdss-pan-underflow-clr", &tmp); | |
panel_data->panel_info.lcdc.underflow_clr = (!rc ? tmp : 0xff); | |
bl_ctrl_type = of_get_property(pdev->dev.of_node, | |
"qcom,mdss-pan-bl-ctrl", NULL); | |
if ((bl_ctrl_type) && (!strncmp(bl_ctrl_type, "bl_ctrl_wled", 12))) { | |
led_trigger_register_simple("bkl-trigger", &bl_led_trigger); | |
pr_debug("%s: SUCCESS-> WLED TRIGGER register\n", __func__); | |
panel_data->panel_info.bklt_ctrl = BL_WLED; | |
} else if (!strncmp(bl_ctrl_type, "bl_ctrl_pwm", 11)) { | |
panel_data->panel_info.bklt_ctrl = BL_PWM; | |
rc = of_property_read_u32(np, "qcom,pwm-period", &tmp); | |
if (rc) { | |
pr_err("%s:%d, Error, panel pwm_period\n", | |
__func__, __LINE__); | |
return -EINVAL; | |
} | |
panel_data->panel_info.pwm_period = tmp; | |
rc = of_property_read_u32(np, "qcom,pwm-lpg-channel", &tmp); | |
if (rc) { | |
pr_err("%s:%d, Error, dsi lpg channel\n", | |
__func__, __LINE__); | |
return -EINVAL; | |
} | |
panel_data->panel_info.pwm_lpg_chan = tmp; | |
tmp = of_get_named_gpio(np, "qcom,pwm-pmic-gpio", 0); | |
panel_data->panel_info.pwm_pmic_gpio = tmp; | |
} else if (!strncmp(bl_ctrl_type, "bl_ctrl_dcs", 11)) { | |
panel_data->panel_info.bklt_ctrl = BL_DCS_CMD; | |
#ifdef CONFIG_OLED_SUPPORT | |
}else if((bl_ctrl_type) && (!strncmp(bl_ctrl_type, "bl_ctrl_oled", 12))) { | |
panel_data->panel_info.bklt_ctrl = BL_DCS_CMD; | |
#endif | |
} else { | |
pr_debug("%s: Unknown backlight control\n", __func__); | |
panel_data->panel_info.bklt_ctrl = UNKNOWN_CTRL; | |
} | |
rc = of_property_read_u32_array(np, | |
"qcom,mdss-pan-bl-levels", res, 2); | |
panel_data->panel_info.bl_min = (!rc ? res[0] : 0); | |
panel_data->panel_info.bl_max = (!rc ? res[1] : 255); | |
#ifdef CONFIG_OLED_SUPPORT | |
rc = of_property_read_u32(np, "qcom,blmap_size", | |
&panel_data->panel_info.blmap_size); | |
if (panel_data->panel_info.blmap_size) { | |
array = kzalloc(sizeof(u32) * panel_data->panel_info.blmap_size, GFP_KERNEL); | |
if (!array) | |
return -ENOMEM; | |
rc = of_property_read_u32_array(np, "qcom,blmap", array, panel_data->panel_info.blmap_size); | |
if (rc) { | |
pr_err("%s:%d, uable to read backlight map\n",__func__, __LINE__); | |
return -EINVAL; | |
} | |
panel_data->panel_info.blmap = kzalloc(sizeof(char) * panel_data->panel_info.blmap_size, GFP_KERNEL); | |
if (!panel_data->panel_info.blmap) | |
return -ENOMEM; | |
for (i = 0; i < panel_data->panel_info.blmap_size; i++ ) | |
panel_data->panel_info.blmap[i] = (char)array[i]; | |
if (array) | |
kfree(array); | |
} else { | |
panel_data->panel_info.blmap = NULL; | |
} | |
#endif | |
rc = of_property_read_u32(np, "qcom,mdss-pan-dsi-mode", &tmp); | |
panel_data->panel_info.mipi.mode = (!rc ? tmp : DSI_VIDEO_MODE); | |
rc = of_property_read_u32(np, "qcom,mdss-vsync-enable", &tmp); | |
panel_data->panel_info.mipi.vsync_enable = (!rc ? tmp : 0); | |
rc = of_property_read_u32(np, "qcom,mdss-hw-vsync-mode", &tmp); | |
panel_data->panel_info.mipi.hw_vsync_mode = (!rc ? tmp : 0); | |
rc = of_property_read_u32(np, | |
"qcom,mdss-pan-dsi-h-pulse-mode", &tmp); | |
panel_data->panel_info.mipi.pulse_mode_hsa_he = (!rc ? tmp : false); | |
rc = of_property_read_u32_array(np, | |
"qcom,mdss-pan-dsi-h-power-stop", res, 3); | |
panel_data->panel_info.mipi.hbp_power_stop = (!rc ? res[0] : false); | |
panel_data->panel_info.mipi.hsa_power_stop = (!rc ? res[1] : false); | |
panel_data->panel_info.mipi.hfp_power_stop = (!rc ? res[2] : false); | |
rc = of_property_read_u32_array(np, | |
"qcom,mdss-pan-dsi-bllp-power-stop", res, 2); | |
panel_data->panel_info.mipi.bllp_power_stop = | |
(!rc ? res[0] : false); | |
panel_data->panel_info.mipi.eof_bllp_power_stop = | |
(!rc ? res[1] : false); | |
rc = of_property_read_u32(np, | |
"qcom,mdss-pan-dsi-traffic-mode", &tmp); | |
panel_data->panel_info.mipi.traffic_mode = | |
(!rc ? tmp : DSI_NON_BURST_SYNCH_PULSE); | |
rc = of_property_read_u32(np, | |
"qcom,mdss-pan-insert-dcs-cmd", &tmp); | |
panel_data->panel_info.mipi.insert_dcs_cmd = | |
(!rc ? tmp : 1); | |
rc = of_property_read_u32(np, | |
"qcom,mdss-pan-wr-mem-continue", &tmp); | |
panel_data->panel_info.mipi.wr_mem_continue = | |
(!rc ? tmp : 0x3c); | |
rc = of_property_read_u32(np, | |
"qcom,mdss-pan-wr-mem-start", &tmp); | |
panel_data->panel_info.mipi.wr_mem_start = | |
(!rc ? tmp : 0x2c); | |
rc = of_property_read_u32(np, | |
"qcom,mdss-pan-te-sel", &tmp); | |
panel_data->panel_info.mipi.te_sel = | |
(!rc ? tmp : 1); | |
rc = of_property_read_u32(np, | |
"qcom,mdss-pan-dsi-dst-format", &tmp); | |
panel_data->panel_info.mipi.dst_format = | |
(!rc ? tmp : DSI_VIDEO_DST_FORMAT_RGB888); | |
rc = of_property_read_u32(np, "qcom,mdss-pan-dsi-vc", &tmp); | |
panel_data->panel_info.mipi.vc = (!rc ? tmp : 0); | |
rc = of_property_read_u32(np, "qcom,mdss-pan-dsi-rgb-swap", &tmp); | |
panel_data->panel_info.mipi.rgb_swap = (!rc ? tmp : DSI_RGB_SWAP_RGB); | |
rc = of_property_read_u32_array(np, | |
"qcom,mdss-pan-dsi-data-lanes", res, 4); | |
panel_data->panel_info.mipi.data_lane0 = (!rc ? res[0] : true); | |
panel_data->panel_info.mipi.data_lane1 = (!rc ? res[1] : false); | |
panel_data->panel_info.mipi.data_lane2 = (!rc ? res[2] : false); | |
panel_data->panel_info.mipi.data_lane3 = (!rc ? res[3] : false); | |
rc = of_property_read_u32(np, "qcom,mdss-pan-dsi-dlane-swap", &tmp); | |
panel_data->panel_info.mipi.dlane_swap = (!rc ? tmp : 0); | |
rc = of_property_read_u32_array(np, "qcom,mdss-pan-dsi-t-clk", res, 2); | |
panel_data->panel_info.mipi.t_clk_pre = (!rc ? res[0] : 0x24); | |
panel_data->panel_info.mipi.t_clk_post = (!rc ? res[1] : 0x03); | |
rc = of_property_read_u32(np, "qcom,mdss-pan-dsi-stream", &tmp); | |
panel_data->panel_info.mipi.stream = (!rc ? tmp : 0); | |
rc = of_property_read_u32(np, "qcom,mdss-pan-dsi-mdp-tr", &tmp); | |
panel_data->panel_info.mipi.mdp_trigger = | |
(!rc ? tmp : DSI_CMD_TRIGGER_SW); | |
if (panel_data->panel_info.mipi.mdp_trigger > 6) { | |
pr_err("%s:%d, Invalid mdp trigger. Forcing to sw trigger", | |
__func__, __LINE__); | |
panel_data->panel_info.mipi.mdp_trigger = | |
DSI_CMD_TRIGGER_SW; | |
} | |
rc = of_property_read_u32(np, "qcom,mdss-pan-dsi-dma-tr", &tmp); | |
panel_data->panel_info.mipi.dma_trigger = | |
(!rc ? tmp : DSI_CMD_TRIGGER_SW); | |
if (panel_data->panel_info.mipi.dma_trigger > 6) { | |
pr_err("%s:%d, Invalid dma trigger. Forcing to sw trigger", | |
__func__, __LINE__); | |
panel_data->panel_info.mipi.dma_trigger = | |
DSI_CMD_TRIGGER_SW; | |
} | |
rc = of_property_read_u32(np, "qcom,mdss-pan-dsi-frame-rate", &tmp); | |
panel_data->panel_info.mipi.frame_rate = (!rc ? tmp : 60); | |
rc = of_property_read_u32(np, "qcom,mdss-pan-clk-rate", &tmp); | |
panel_data->panel_info.clk_rate = (!rc ? tmp : 0); | |
data = of_get_property(np, "qcom,panel-phy-regulatorSettings", &len); | |
if ((!data) || (len != 7)) { | |
pr_err("%s:%d, Unable to read Phy regulator settings", | |
__func__, __LINE__); | |
goto error; | |
} | |
for (i = 0; i < len; i++) | |
phy_params.regulator[i] = data[i]; | |
data = of_get_property(np, "qcom,panel-phy-timingSettings", &len); | |
if ((!data) || (len != 12)) { | |
pr_err("%s:%d, Unable to read Phy timing settings", | |
__func__, __LINE__); | |
goto error; | |
} | |
for (i = 0; i < len; i++) | |
phy_params.timing[i] = data[i]; | |
data = of_get_property(np, "qcom,panel-phy-strengthCtrl", &len); | |
if ((!data) || (len != 2)) { | |
pr_err("%s:%d, Unable to read Phy Strength ctrl settings", | |
__func__, __LINE__); | |
goto error; | |
} | |
phy_params.strength[0] = data[0]; | |
phy_params.strength[1] = data[1]; | |
data = of_get_property(np, "qcom,panel-phy-bistCtrl", &len); | |
if ((!data) || (len != 6)) { | |
pr_err("%s:%d, Unable to read Phy Bist Ctrl settings", | |
__func__, __LINE__); | |
goto error; | |
} | |
for (i = 0; i < len; i++) | |
phy_params.bistCtrl[i] = data[i]; | |
data = of_get_property(np, "qcom,panel-phy-laneConfig", &len); | |
if ((!data) || (len != 45)) { | |
pr_err("%s:%d, Unable to read Phy lane configure settings", | |
__func__, __LINE__); | |
goto error; | |
} | |
for (i = 0; i < len; i++) | |
phy_params.laneCfg[i] = data[i]; | |
panel_data->panel_info.mipi.dsi_phy_db = &phy_params; | |
fbc_enabled = of_property_read_bool(np, | |
"qcom,fbc-enabled"); | |
if (fbc_enabled) { | |
pr_debug("%s:%d FBC panel enabled.\n", __func__, __LINE__); | |
panel_data->panel_info.fbc.enabled = 1; | |
rc = of_property_read_u32_array(np, | |
"qcom,fbc-mode", fbc_res, 7); | |
panel_data->panel_info.fbc.target_bpp = | |
(!rc ? fbc_res[0] : panel_data->panel_info.bpp); | |
panel_data->panel_info.fbc.comp_mode = (!rc ? fbc_res[1] : 0); | |
panel_data->panel_info.fbc.qerr_enable = | |
(!rc ? fbc_res[2] : 0); | |
panel_data->panel_info.fbc.cd_bias = (!rc ? fbc_res[3] : 0); | |
panel_data->panel_info.fbc.pat_enable = (!rc ? fbc_res[4] : 0); | |
panel_data->panel_info.fbc.vlc_enable = (!rc ? fbc_res[5] : 0); | |
panel_data->panel_info.fbc.bflc_enable = | |
(!rc ? fbc_res[6] : 0); | |
rc = of_property_read_u32_array(np, | |
"qcom,fbc-budget-ctl", fbc_res, 3); | |
panel_data->panel_info.fbc.line_x_budget = | |
(!rc ? fbc_res[0] : 0); | |
panel_data->panel_info.fbc.block_x_budget = | |
(!rc ? fbc_res[1] : 0); | |
panel_data->panel_info.fbc.block_budget = | |
(!rc ? fbc_res[2] : 0); | |
rc = of_property_read_u32_array(np, | |
"qcom,fbc-lossy-mode", fbc_res, 4); | |
panel_data->panel_info.fbc.lossless_mode_thd = | |
(!rc ? fbc_res[0] : 0); | |
panel_data->panel_info.fbc.lossy_mode_thd = | |
(!rc ? fbc_res[1] : 0); | |
panel_data->panel_info.fbc.lossy_rgb_thd = | |
(!rc ? fbc_res[2] : 0); | |
panel_data->panel_info.fbc.lossy_mode_idx = | |
(!rc ? fbc_res[3] : 0); | |
} else { | |
pr_debug("%s:%d Panel does not support FBC.\n", | |
__func__, __LINE__); | |
panel_data->panel_info.fbc.enabled = 0; | |
panel_data->panel_info.fbc.target_bpp = | |
panel_data->panel_info.bpp; | |
} | |
mdss_dsi_parse_dcs_cmds(np, &panel_data->on_cmds, | |
"qcom,panel-on-cmds", "qcom,on-cmds-dsi-state"); | |
mdss_dsi_parse_dcs_cmds(np, &panel_data->off_cmds, | |
"qcom,panel-off-cmds", "qcom,off-cmds-dsi-state"); | |
#if defined(CONFIG_MACH_LGE) && !(defined(CONFIG_MACH_MSM8974_Z_KR) || defined(CONFIG_MACH_MSM8974_Z_US) || defined(CONFIG_MACH_MSM8974_Z_KDDI)) | |
mdss_dsi_parse_dcs_cmds(np, &lge_ief_on_cmds, "qcom,panel-ief-on-cmds", "qcom,ief-on-dsi-state"); | |
mdss_dsi_parse_dcs_cmds(np, &lge_ief_off_cmds, "qcom,panel-ief-off-cmds", "qcom,ief-off-dsi-state"); | |
#endif | |
#if defined(CONFIG_OLED_SUPPORT) && defined(CONFIG_LGE_OLED_IMG_TUNING) | |
img_tune_cmds_set = kzalloc(sizeof(struct img_tune_cmds_desc), GFP_KERNEL); | |
for(i = 0; i < IMG_TUNE_COUNT; i++) | |
mdss_dsi_parse_dcs_cmds(np, &img_tune_cmds_set->img_tune_cmds[i], | |
img_tune_dt[i], "qcom,on-cmds-dsi-state"); | |
#endif | |
return 0; | |
error: | |
return -EINVAL; | |
} | |
#if defined(CONFIG_MACH_LGE) | |
struct syscore_ops panel_syscore_ops = { | |
.shutdown = mdss_dsi_panel_shutdown, | |
}; | |
#endif | |
static int read_local_on_cmds(char *buf, size_t cmd) | |
{ | |
int i, len = 0; | |
int dlen; | |
if (system_rev != GAMMA_COMPAT) { | |
pr_err("Incompatible hardware revision: %d\n", system_rev); | |
return -EINVAL; | |
} | |
dlen = local_pdata->on_cmds.cmds[cmd].dchdr.dlen - 1; | |
if (!dlen) | |
return -ENOMEM; | |
/* don't print first and last bits */ | |
for (i = 1; i < dlen; i++) | |
len += sprintf(buf + len, "%d ", | |
local_pdata->on_cmds.cmds[cmd].payload[i]); | |
len += sprintf(buf + len, "\n"); | |
return len; | |
} | |
static unsigned int cnt; | |
static int write_local_on_cmds(struct device *dev, const char *buf, | |
size_t cmd) | |
{ | |
int i, rc = 0; | |
int dlen; | |
unsigned int val; | |
char tmp[3]; | |
struct mdss_dsi_ctrl_pdata *ctrl = NULL; | |
struct mdss_panel_common_pdata *prev_local_data; | |
if (cnt) { | |
cnt = 0; | |
return -EINVAL; | |
} | |
if (system_rev != GAMMA_COMPAT) { | |
pr_err("Incompatible hardware revision: %d\n", system_rev); | |
return -EINVAL; | |
} | |
if (cmds_panel_data == NULL) { | |
pr_err("%s: Invalid input data\n", __func__); | |
return -EINVAL; | |
} | |
ctrl = container_of(cmds_panel_data, struct mdss_dsi_ctrl_pdata, | |
panel_data); | |
/* | |
* Last bit is not written because it's either fixed at 0x00 for | |
* RGB or a duplicate of the previous bit for the white point. | |
*/ | |
dlen = local_pdata->on_cmds.cmds[cmd].dchdr.dlen - 1; | |
if (!dlen) | |
return -EINVAL; | |
prev_local_data = local_pdata; | |
for (i = 1; i < dlen; i++) { | |
rc = sscanf(buf, "%u", &val); | |
if (rc != 1) | |
return -EINVAL; | |
if (val > 255) { | |
pr_err("%s: Invalid input data %u (0-255)\n", __func__, val); | |
local_pdata = prev_local_data; | |
return -EINVAL; | |
} | |
local_pdata->on_cmds.cmds[cmd].payload[i] = val; | |
/* white point value must be duplicated */ | |
if (cmd == 5) | |
local_pdata->on_cmds.cmds[cmd].payload[i + 1] = val; | |
sscanf(buf, "%s", tmp); | |
buf += strlen(tmp) + 1; | |
cnt = strlen(tmp); | |
} | |
pr_info("%s\n", __func__); | |
return rc; | |
} | |
static void send_local_on_cmds(struct work_struct *work) | |
{ | |
struct mdss_dsi_ctrl_pdata *ctrl = NULL; | |
if (cmds_panel_data == NULL) { | |
pr_err("%s: Invalid input data\n", __func__); | |
return; | |
} | |
ctrl = container_of(cmds_panel_data, struct mdss_dsi_ctrl_pdata, | |
panel_data); | |
if (local_pdata->on_cmds.cmd_cnt) | |
mdss_dsi_panel_cmds_send(ctrl, &local_pdata->on_cmds); | |
pr_info("%s\n", __func__); | |
} | |
/************************** sysfs interface ************************/ | |
static ssize_t write_kgamma_send(struct device *dev, | |
struct device_attribute *attr, | |
const char *buf, size_t count) | |
{ | |
if (!cmds_panel_data->panel_info.panel_power_on) { | |
pr_err("%s: Panel off, failed to send commands\n", __func__); | |
return -EPERM; | |
} | |
schedule_work(&send_cmds_work); | |
return count; | |
} | |
static DEVICE_ATTR(kgamma_send, 0644, NULL, write_kgamma_send); | |
#define read_one(file_name, cmd) \ | |
static ssize_t read_##file_name \ | |
(struct device *dev, struct device_attribute *attr, char *buf) \ | |
{ \ | |
return read_local_on_cmds(buf, cmd); \ | |
} | |
read_one(kgamma_w, 5); | |
read_one(kgamma_rp, 7); | |
read_one(kgamma_rn, 9); | |
read_one(kgamma_gp, 11); | |
read_one(kgamma_gn, 13); | |
read_one(kgamma_bp, 15); | |
read_one(kgamma_bn, 17); | |
#define write_one(file_name, cmd) \ | |
static ssize_t write_##file_name \ | |
(struct device *dev, struct device_attribute *attr, \ | |
const char *buf, size_t count) \ | |
{ \ | |
return write_local_on_cmds(dev, buf, cmd); \ | |
} | |
write_one(kgamma_w, 5); | |
write_one(kgamma_rp, 7); | |
write_one(kgamma_rn, 9); | |
write_one(kgamma_gp, 11); | |
write_one(kgamma_gn, 13); | |
write_one(kgamma_bp, 15); | |
write_one(kgamma_bn, 17); | |
#define define_one_rw(_name) \ | |
static DEVICE_ATTR(_name, 0644, read_##_name, write_##_name); | |
define_one_rw(kgamma_w); | |
define_one_rw(kgamma_rp); | |
define_one_rw(kgamma_rn); | |
define_one_rw(kgamma_gp); | |
define_one_rw(kgamma_gn); | |
define_one_rw(kgamma_bp); | |
define_one_rw(kgamma_bn); | |
static struct attribute *dsi_panel_attributes[] = { | |
&dev_attr_kgamma_w.attr, | |
&dev_attr_kgamma_rp.attr, | |
&dev_attr_kgamma_rn.attr, | |
&dev_attr_kgamma_gp.attr, | |
&dev_attr_kgamma_gn.attr, | |
&dev_attr_kgamma_bp.attr, | |
&dev_attr_kgamma_bn.attr, | |
&dev_attr_kgamma_send.attr, | |
NULL | |
}; | |
static struct attribute_group dsi_panel_attribute_group = { | |
.attrs = dsi_panel_attributes, | |
}; | |
/**************************** sysfs end **************************/ | |
static int __devinit mdss_dsi_panel_probe(struct platform_device *pdev) | |
{ | |
int rc = 0; | |
static struct mdss_panel_common_pdata vendor_pdata; | |
static const char *panel_name; | |
const char *driver_name = this_driver.driver.name; | |
#ifdef CONFIG_LGE_SUPPORT_LCD_MAKER_ID | |
struct class *panel; | |
struct device *panel_sysfs_dev; | |
#endif | |
pr_debug("%s:%d, debug info id=%d", __func__, __LINE__, pdev->id); | |
if (!pdev->dev.of_node) | |
return -ENODEV; | |
#if defined(CONFIG_MACH_LGE) | |
register_syscore_ops(&panel_syscore_ops); | |
#endif | |
panel_name = of_get_property(pdev->dev.of_node, "label", NULL); | |
if (!panel_name) | |
pr_info("%s:%d, panel name not specified\n", | |
__func__, __LINE__); | |
else | |
pr_info("%s: Panel Name = %s\n", __func__, panel_name); | |
rc = mdss_panel_parse_dt(pdev, &vendor_pdata); | |
if (rc) | |
return rc; | |
vendor_pdata.on = mdss_dsi_panel_on; | |
vendor_pdata.off = mdss_dsi_panel_off; | |
vendor_pdata.bl_fnc = mdss_dsi_panel_bl_ctrl; | |
rc = dsi_panel_device_register(pdev, &vendor_pdata); | |
if (rc) | |
return rc; | |
INIT_WORK(&send_cmds_work, send_local_on_cmds); | |
local_pdata = &vendor_pdata; | |
if (!local_pdata) | |
return -EINVAL; | |
#ifdef CONFIG_DEBUG_FS | |
debug_fs_init(&vendor_pdata); | |
#endif | |
module_kobj = kobject_create_and_add(driver_name, &module_kset->kobj); | |
if (!module_kobj) { | |
pr_err("%s: kobject create failed\n", driver_name); | |
return -ENOMEM; | |
} | |
rc = sysfs_create_group(module_kobj, &dsi_panel_attribute_group); | |
if (rc) | |
pr_err("%s: sysfs create failed: %d\n", panel_name, rc); | |
return rc; | |
} | |
static const struct of_device_id mdss_dsi_panel_match[] = { | |
{.compatible = "qcom,mdss-dsi-panel"}, | |
{} | |
}; | |
static struct platform_driver this_driver = { | |
.probe = mdss_dsi_panel_probe, | |
.driver = { | |
.name = "dsi_panel", | |
.of_match_table = mdss_dsi_panel_match, | |
}, | |
}; | |
static int __init mdss_dsi_panel_init(void) | |
{ | |
return platform_driver_register(&this_driver); | |
} | |
module_init(mdss_dsi_panel_init); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment