Skip to content

Instantly share code, notes, and snippets.

@invisiblek
Created January 17, 2015 01:17
Show Gist options
  • Save invisiblek/38104ccd93a81c85d1cb to your computer and use it in GitHub Desktop.
Save invisiblek/38104ccd93a81c85d1cb to your computer and use it in GitHub Desktop.
/* Copyright (c) 2012-2014, 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/qpnp/pwm.h>
#include <linux/err.h>
#include "mdss_dsi.h"
#ifdef CONFIG_VENDOR_EDIT
/* OPPO 2013-10-24 yxq Add begin for panel info */
#include <mach/device_info.h>
/* OPPO 2013-10-24 yxq Add end */
/* OPPO 2013-12-09 yxq Add begin for disable continous display for ftm, rf, wlan mode */
#include <linux/boot_mode.h>
/* OPPO 2013-12-09 yxq Add end */
/* OPPO 2014-02-11 yxq add begin for Find7s */
#include <linux/pcb_version.h>
/* OPPO 2014-02-11 yxq add end */
#endif
#ifdef VENDOR_EDIT
/* Xiaori.Yuan@Mobile Phone Software Dept.Driver, 2014/02/24 Add for ESD test */
#include <linux/switch.h>
#endif /*VENDOR_EDIT*/
#define DT_CMD_HDR 6
#ifdef VENDOR_EDIT
/* Xiaori.Yuan@Mobile Phone Software Dept.Driver, 2014/04/15 Add for find7s swap DSI port */
extern int LCD_id;
#endif /*VENDOR_EDIT*/
DEFINE_LED_TRIGGER(bl_led_trigger);
#ifdef VENDOR_EDIT
extern int lm3630_bank_a_update_status(u32 bl_level);
#endif
#ifdef VENDOR_EDIT
/* Xiaori.Yuan@Mobile Phone Software Dept.Driver, 2014/02/24 Add for ESD test*/
#define LCD_TE_GPIO 28
DEFINE_SPINLOCK(te_count_lock);
DEFINE_SPINLOCK(te_state_lock);
unsigned long flags;
static bool first_run_init=1;
static bool first_run_reset=1;
static bool cont_splash_flag;
static int te_count = 0;
static int irq_state = 1;
static int irq;
static int te_state = 0;
static struct switch_dev display_switch;
static struct delayed_work techeck_work;
static bool find7s_lcd_rsp_ic = 0;
static irqreturn_t TE_irq_thread_fn(int irq, void *dev_id)
{
spin_lock_irqsave(&te_count_lock, flags);
te_count ++;
spin_unlock_irqrestore(&te_count_lock, flags);
return IRQ_HANDLED;
}
static int operate_display_switch(void)
{
int ret = 0;
printk("%s:state=%d.\n", __func__, te_state);
spin_lock_irqsave(&te_state_lock, flags);
if(te_state)
te_state = 0;
else
te_state = 1;
spin_unlock_irqrestore(&te_state_lock, flags);
switch_set_state(&display_switch, te_state);
return ret;
}
static void techeck_work_func( struct work_struct *work )
{
if(te_count < 50)
{
pr_err("yxr: te_count<50 %s\n",__func__);
printk("yxr------%s: lcd resetting ! te_count = %d \n",__func__,te_count);
printk("irq_state=%d\n", irq_state);
operate_display_switch();
spin_lock_irqsave(&te_count_lock, flags);
te_count = 0;
spin_unlock_irqrestore(&te_count_lock, flags);
schedule_delayed_work(&techeck_work, msecs_to_jiffies(2000));
return ;
}
//pr_err("yxr %s:te_count=%d\n",__func__,te_count);
spin_lock_irqsave(&te_count_lock, flags);
te_count = 0;
spin_unlock_irqrestore(&te_count_lock, flags);
schedule_delayed_work(&techeck_work, msecs_to_jiffies(2000));
}
static ssize_t attr_mdss_dispswitch(struct device *dev,
struct device_attribute *attr, char *buf)
{
printk("ESD function test--------\n");
operate_display_switch();
return 0;
}
static struct class * mdss_lcd;
static struct device * dev_lcd;
static struct device_attribute mdss_lcd_attrs[] = {
__ATTR(dispswitch, S_IRUGO|S_IWUSR, attr_mdss_dispswitch, NULL),
__ATTR_NULL,
};
#endif /*VENDOR_EDIT*/
#ifdef VENDOR_EDIT
/* Xiaori.Yuan@Mobile Phone Software Dept.Driver, 2014/02/17 Add for set cabc */
struct dsi_panel_cmds cabc_off_sequence;
struct dsi_panel_cmds cabc_user_interface_image_sequence;
struct dsi_panel_cmds cabc_still_image_sequence;
struct dsi_panel_cmds cabc_video_image_sequence;
struct dsi_panel_cmds gamma1;
struct dsi_panel_cmds gamma2;
struct dsi_panel_cmds gamma3;
struct dsi_panel_cmds gamma4;
extern int gamma_index ;
static bool flag_lcd_off = false;
struct mdss_dsi_ctrl_pdata *panel_data;
static void mdss_dsi_panel_cmds_send(struct mdss_dsi_ctrl_pdata *ctrl,
struct dsi_panel_cmds *pcmds);
extern int set_backlight_pwm(int state);
enum
{
CABC_CLOSE = 0,
CABC_LOW_MODE,
CABC_MIDDLE_MODE,
CABC_HIGH_MODE,
};
int cabc_mode = CABC_HIGH_MODE; //defaoult mode level 3 in dtsi file
static DEFINE_MUTEX(cabc_mutex);
static char dcs_cmd_find7_0[2] = {0xb0, 0x04};
static char dcs_cmd_find7_1[20] = {0xc8, 0x01, 0x0A, 0xFD,
0x03, 0x01, 0xE8, 0x00,
0x00, 0x03, 0xFC, 0xF5,
0xA1, 0x00, 0x00, 0x01,
0xFD, 0x06, 0xFC, 0x00,};
static char dcs_cmd_find7_2[2] = {0xd6, 0x01};
static char dcs_cmd_find7_3[2] = {0xb0, 0x03};
static struct dsi_cmd_desc user_defined_find7_gamma[] = {
{{DTYPE_GEN_WRITE2, 1, 0, 1, 0, sizeof(dcs_cmd_find7_0)},dcs_cmd_find7_0},
{{DTYPE_GEN_LWRITE, 1, 0, 1, 0, sizeof(dcs_cmd_find7_1)},dcs_cmd_find7_1},
{{DTYPE_GEN_WRITE2, 1, 0, 1, 0, sizeof(dcs_cmd_find7_2)},dcs_cmd_find7_2},
{{DTYPE_GEN_WRITE2, 1, 0, 1, 0, sizeof(dcs_cmd_find7_3)},dcs_cmd_find7_3},
};
void send_user_defined_gamma(char * buf)
{
int i=0,len,limt_len,temp;
char temp_buf[100];
char * p1,*p2,*user_gamma=NULL;
struct dcs_cmd_req cmdreq;
mutex_lock(&cabc_mutex);
if(flag_lcd_off == true)
{
printk(KERN_INFO "lcd is off,don't allow to set user gamma !\n");
mutex_unlock(&cabc_mutex);
return;
}
if((get_pcb_version() < 20)||(get_pcb_version() >=30)){/*liuyan add for N3*/
user_gamma = dcs_cmd_find7_1;
limt_len = sizeof(dcs_cmd_find7_1);
}
if(user_gamma == NULL) { mutex_unlock(&cabc_mutex); return; }
p1=buf;
p2=temp_buf;
pr_err("%s \n",p1);
while(*p1!='\0'){
if(*p1==' ') {p1++;continue;}
*p2 = *p1;
p2++;
p1++;
}
*p2 ='\0';
p2=temp_buf;
len =strlen(p2);
pr_err("len = %d \n",len);
if( len/2 >limt_len){
mutex_unlock(&cabc_mutex);
pr_err("invalid gamma intput \n");
return;
}
for(i=0;i<len;i++)
{
if(*p2>='0' && *p2 <='9')
temp =*p2-'0';
else if(*p2>='a'&& *p2<='f')
temp =*p2-'a'+10;
else if(*p2>='A'&& *p2<='F')
temp =*p2-'A'+10;
if(i%2==0)
user_gamma[i/2] = temp*16;
else
user_gamma[i/2]+=temp;
p2++;
}
memset(&cmdreq, 0, sizeof(cmdreq));
cmdreq.cmds = user_defined_find7_gamma;
cmdreq.cmds_cnt = 4;
cmdreq.flags = CMD_REQ_COMMIT;
mdss_dsi_cmdlist_put(panel_data, &cmdreq);
mutex_unlock(&cabc_mutex);
return;
}
void set_gamma(int index)
{
printk("%s : %d \n",__func__,index);
//if (get_pcb_version() >= HW_VERSION__20) { /* For Find7s */
// return;
//}
mutex_lock(&cabc_mutex);
if(flag_lcd_off == true)
{
printk(KERN_INFO "lcd is off,don't allow to set gamma\n");
mutex_unlock(&cabc_mutex);
return;
}
mdss_dsi_clk_ctrl(panel_data, 1);
if(index <= 0 || index >4){
mutex_unlock(&cabc_mutex);
return;
}
switch(index)
{
case 1:
mdss_dsi_panel_cmds_send(panel_data, &gamma1);
break;
case 2:
mdss_dsi_panel_cmds_send(panel_data, &gamma2);
break;
case 3:
mdss_dsi_panel_cmds_send(panel_data, &gamma3);
break;
case 4:
mdss_dsi_panel_cmds_send(panel_data, &gamma4);
break;
}
mdss_dsi_clk_ctrl(panel_data, 0);
mutex_unlock(&cabc_mutex);
}
void set_resume_gamma(int index)
{
printk("%s : %d \n",__func__,index);
//if (get_pcb_version() >= HW_VERSION__20) { /* For Find7s */
// return;
//}
if(index <= 1 || index >4){
return;
}
switch(index)
{
case 1:
mdss_dsi_panel_cmds_send(panel_data, &gamma1);
break;
case 2:
mdss_dsi_panel_cmds_send(panel_data, &gamma2);
break;
case 3:
mdss_dsi_panel_cmds_send(panel_data, &gamma3);
break;
case 4:
mdss_dsi_panel_cmds_send(panel_data, &gamma4);
break;
default:
pr_err("%s : invalid gamma index %d yxr \n",__func__,index);
break;
}
}
int set_cabc(int level)
{
int ret = 0;
if ((get_pcb_version() >= HW_VERSION__20)&&(get_pcb_version() <HW_VERSION__30)) { /* For Find7s ,liuyan add for N3*/
return 0;
}
printk("%s : %d \n",__func__,level);
mutex_lock(&cabc_mutex);
if(flag_lcd_off == true)
{
printk(KERN_INFO "lcd is off,don't allow to set cabc\n");
cabc_mode = level;
mutex_unlock(&cabc_mutex);
return 0;
}
mdss_dsi_clk_ctrl(panel_data, 1);
switch(level)
{
case 0:
set_backlight_pwm(0);
mdss_dsi_panel_cmds_send(panel_data, &cabc_off_sequence);
cabc_mode = CABC_CLOSE;
break;
case 1:
mdss_dsi_panel_cmds_send(panel_data, &cabc_user_interface_image_sequence);
cabc_mode = CABC_LOW_MODE;
set_backlight_pwm(1);
break;
case 2:
mdss_dsi_panel_cmds_send(panel_data, &cabc_still_image_sequence);
cabc_mode = CABC_MIDDLE_MODE;
set_backlight_pwm(1);
break;
case 3:
mdss_dsi_panel_cmds_send(panel_data, &cabc_video_image_sequence);
cabc_mode = CABC_HIGH_MODE;
set_backlight_pwm(1);
break;
default:
pr_err("%s Leavel %d is not supported!\n",__func__,level);
ret = -1;
break;
}
mdss_dsi_clk_ctrl(panel_data, 0);
mutex_unlock(&cabc_mutex);
return ret;
}
static int set_cabc_resume_mode(int mode)
{
int ret;
if ((get_pcb_version() >= HW_VERSION__20)&&(get_pcb_version() < HW_VERSION__30)) { /* For Find7s ,liuyan add for N3*/
return 0;
}
printk("%s : %d yxr \n",__func__,mode);
switch(mode)
{
case 0:
set_backlight_pwm(0);
mdss_dsi_panel_cmds_send(panel_data, &cabc_off_sequence);
break;
case 1:
mdss_dsi_panel_cmds_send(panel_data, &cabc_user_interface_image_sequence);
set_backlight_pwm(1);
break;
case 2:
mdss_dsi_panel_cmds_send(panel_data, &cabc_still_image_sequence);
set_backlight_pwm(1);
break;
case 3:
mdss_dsi_panel_cmds_send(panel_data, &cabc_video_image_sequence);
set_backlight_pwm(1);
break;
default:
pr_err("%s %d is not supported!\n",__func__,mode);
ret = -1;
break;
}
return ret;
}
#endif /*VENDOR_EDIT*/
void mdss_dsi_panel_pwm_cfg(struct mdss_dsi_ctrl_pdata *ctrl)
{
ctrl->pwm_bl = pwm_request(ctrl->pwm_lpg_chan, "lcd-bklt");
if (ctrl->pwm_bl == NULL || IS_ERR(ctrl->pwm_bl)) {
pr_err("%s: Error: lpg_chan=%d pwm request failed",
__func__, ctrl->pwm_lpg_chan);
}
}
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;
}
if (level == 0) {
if (ctrl->pwm_enabled)
pwm_disable(ctrl->pwm_bl);
ctrl->pwm_enabled = 0;
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);
if (ctrl->pwm_enabled) {
pwm_disable(ctrl->pwm_bl);
ctrl->pwm_enabled = 0;
}
ret = pwm_config_us(ctrl->pwm_bl, duty, ctrl->pwm_period);
if (ret) {
pr_err("%s: pwm_config_us() 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);
ctrl->pwm_enabled = 1;
}
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
};
u32 mdss_dsi_panel_cmd_read(struct mdss_dsi_ctrl_pdata *ctrl, char cmd0,
char cmd1, void (*fxn)(int), char *rbuf, int len)
{
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 = len;
cmdreq.rbuf = rbuf;
cmdreq.cb = fxn; /* 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;
/*Panel ON/Off commands should be sent in DSI Low Power Mode*/
if (pcmds->link_state == DSI_LP_MODE)
cmdreq.flags |= CMD_REQ_LP_MODE;
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, 1, 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);
led_pwm1[1] = (unsigned char)level;
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);
}
#ifndef CONFIG_VENDOR_EDIT
/* [email protected], 2014/01/10 Modify for rewrite reset function */
static int mdss_dsi_request_gpios(struct mdss_dsi_ctrl_pdata *ctrl_pdata)
{
int rc = 0;
if (gpio_is_valid(ctrl_pdata->disp_en_gpio)) {
rc = gpio_request(ctrl_pdata->disp_en_gpio,
"disp_enable");
if (rc) {
pr_err("request disp_en gpio failed, rc=%d\n",
rc);
goto disp_en_gpio_err;
}
}
rc = gpio_request(ctrl_pdata->rst_gpio, "disp_rst_n");
if (rc) {
pr_err("request reset gpio failed, rc=%d\n",
rc);
goto rst_gpio_err;
}
if (gpio_is_valid(ctrl_pdata->mode_gpio)) {
rc = gpio_request(ctrl_pdata->mode_gpio, "panel_mode");
if (rc) {
pr_err("request panel mode gpio failed,rc=%d\n",
rc);
goto mode_gpio_err;
}
}
return rc;
mode_gpio_err:
gpio_free(ctrl_pdata->rst_gpio);
rst_gpio_err:
if (gpio_is_valid(ctrl_pdata->disp_en_gpio))
gpio_free(ctrl_pdata->disp_en_gpio);
disp_en_gpio_err:
return rc;
}
int mdss_dsi_panel_reset(struct mdss_panel_data *pdata, int enable)
{
struct mdss_dsi_ctrl_pdata *ctrl_pdata = NULL;
struct mdss_panel_info *pinfo = NULL;
int i, rc = 0;
if (pdata == NULL) {
pr_err("%s: Invalid input data\n", __func__);
return -EINVAL;
}
ctrl_pdata = container_of(pdata, struct mdss_dsi_ctrl_pdata,
panel_data);
if (!gpio_is_valid(ctrl_pdata->disp_en_gpio)) {
pr_debug("%s:%d, reset line not configured\n",
__func__, __LINE__);
}
if (!gpio_is_valid(ctrl_pdata->rst_gpio)) {
pr_debug("%s:%d, reset line not configured\n",
__func__, __LINE__);
return rc;
}
pr_debug("%s: enable = %d\n", __func__, enable);
pinfo = &(ctrl_pdata->panel_data.panel_info);
if (enable) {
rc = mdss_dsi_request_gpios(ctrl_pdata);
if (rc) {
pr_err("gpio request failed\n");
return rc;
}
if (!pinfo->panel_power_on) {
if (gpio_is_valid(ctrl_pdata->disp_en_gpio))
gpio_set_value((ctrl_pdata->disp_en_gpio), 1);
for (i = 0; i < pdata->panel_info.rst_seq_len; ++i) {
gpio_set_value((ctrl_pdata->rst_gpio),
pdata->panel_info.rst_seq[i]);
if (pdata->panel_info.rst_seq[++i])
usleep(pinfo->rst_seq[i] * 1000);
}
}
if (gpio_is_valid(ctrl_pdata->mode_gpio)) {
if (pinfo->mode_gpio_state == MODE_GPIO_HIGH)
gpio_set_value((ctrl_pdata->mode_gpio), 1);
else if (pinfo->mode_gpio_state == MODE_GPIO_LOW)
gpio_set_value((ctrl_pdata->mode_gpio), 0);
}
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 {
if (gpio_is_valid(ctrl_pdata->disp_en_gpio)) {
gpio_set_value((ctrl_pdata->disp_en_gpio), 0);
gpio_free(ctrl_pdata->disp_en_gpio);
}
gpio_set_value((ctrl_pdata->rst_gpio), 0);
gpio_free(ctrl_pdata->rst_gpio);
if (gpio_is_valid(ctrl_pdata->mode_gpio))
gpio_free(ctrl_pdata->mode_gpio);
}
return rc;
}
#else
int 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 0;
}
ctrl_pdata = container_of(pdata, struct mdss_dsi_ctrl_pdata,
panel_data);
if (!gpio_is_valid(ctrl_pdata->disp_en_gpio)) {
pr_debug("%s:%d, reset line not configured\n",
__func__, __LINE__);
}
if (!gpio_is_valid(ctrl_pdata->rst_gpio)) {
pr_debug("%s:%d, reset line not configured\n",
__func__, __LINE__);
return 0;
}
pr_err("%s: disp_en_gpio = %d ,gpio76 = %d,rst_gpio=%d ,and pannel index=%d\n", __func__, \
ctrl_pdata->disp_en_gpio,ctrl_pdata->disp_en_gpio76,ctrl_pdata->rst_gpio,ctrl_pdata->index);
pr_err("%s: enable = %d\n", __func__, enable);
if ((get_pcb_version() < HW_VERSION__20)||(get_pcb_version() >= HW_VERSION__30)) { /* For Single DSI: Find7 ,liuyan add for N3*/
if (enable) {
//pr_err("%s:lcd power up\n", __func__);
gpio_set_value((ctrl_pdata->rst_gpio), 0);
gpio_direction_output(58,0);
#ifdef VENDOR_EDIT
/* [email protected], 2014/08/10 Add for 14021 lcd enable */
if(get_pcb_version() >= HW_VERSION__30)
gpio_direction_output(ctrl_pdata->disp_en_gpio76,0);
#endif /*CONFIG_VENDOR_EDIT*/
mdelay(2);
// wmb();
if (gpio_is_valid(ctrl_pdata->disp_en_gpio))
gpio_set_value((ctrl_pdata->disp_en_gpio), 1);
gpio_direction_output(58,1);
#ifdef VENDOR_EDIT
/* [email protected], 2014/08/10 Add for 14021 lcd enable */
if(get_pcb_version() >= HW_VERSION__30)
gpio_direction_output(ctrl_pdata->disp_en_gpio76,1);
#endif /*CONFIG_VENDOR_EDIT*/
// wmb();
mdelay(2);
gpio_set_value((ctrl_pdata->rst_gpio), 1);
mdelay(10);
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);
if (gpio_is_valid(ctrl_pdata->disp_en_gpio))
gpio_direction_output((ctrl_pdata->disp_en_gpio), 0);
gpio_direction_output(58,0);
#ifdef VENDOR_EDIT
/* [email protected], 2014/08/10 Add for 14021 lcd enable */
if(get_pcb_version() >= HW_VERSION__30)
gpio_set_value(ctrl_pdata->disp_en_gpio76,0);
#endif /*CONFIG_VENDOR_EDIT*/
}
} else { /* For Dual DSI: Find7S */
if(ctrl_pdata->index==1 && get_boot_mode()!= MSM_BOOT_MODE__FACTORY){ /* For Find7S DSI 1 */
if (enable) {
//pr_err("%s:lcd virtual power up\n", __func__);
if (ctrl_pdata->ctrl_state & CTRL_STATE_PANEL_INIT) {
pr_err("%s: Panel Not properly turned OFF\n", __func__);
ctrl_pdata->ctrl_state &= ~CTRL_STATE_PANEL_INIT;
pr_err("%s: Reset panel done\n", __func__);
}
}
} else { /* For DSI 0 */
if (enable) {
if(find7s_lcd_rsp_ic == 1){
pr_err("%s rsp ic reset\n",__func__);
gpio_set_value((ctrl_pdata->rst_gpio), 0);
gpio_direction_output(58,0);
gpio_direction_output(46,0);
mdelay(2);
if (gpio_is_valid(ctrl_pdata->disp_en_gpio))
gpio_set_value((ctrl_pdata->disp_en_gpio), 1);
gpio_direction_output(58,1);
mdelay(5);
gpio_direction_output(46,1);
mdelay(2);
gpio_set_value((ctrl_pdata->rst_gpio), 1);
mdelay(10);
}else{
pr_err("%s ntk ic reset\n",__func__);
gpio_direction_output(62,0); /* GPIO_62 ---> 0 */
gpio_set_value((ctrl_pdata->rst_gpio), 1); /* GPIO_19 ---> 1 */
mdelay(5);
gpio_set_value((ctrl_pdata->rst_gpio), 0); /* GPIO_19 ---> 0 */
mdelay(10);
gpio_set_value((ctrl_pdata->rst_gpio), 1); /* GPIO_19 ---> 1 */
mdelay(10);
if (gpio_is_valid(ctrl_pdata->disp_en_gpio))
gpio_set_value((ctrl_pdata->disp_en_gpio), 1);
gpio_direction_output((ctrl_pdata->disp_en_gpio),1); /* GPIO_58 --->1 */
mdelay(2);
gpio_direction_output(46,1);
}
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), 1); /* GPIO_19 ---> 1 */
mdelay(110);
gpio_set_value((ctrl_pdata->rst_gpio), 0); /* GPIO_19 ---> 0 */
mdelay(10);
//gpio_set_value((ctrl_pdata->rst_gpio), 1); /* GPIO_19 --->1 */
//mdelay(10);
gpio_direction_output(46,0); //add for find7s enable display -5v
mdelay(2);
if (gpio_is_valid(ctrl_pdata->disp_en_gpio))
gpio_set_value((ctrl_pdata->disp_en_gpio), 0);
gpio_direction_output((ctrl_pdata->disp_en_gpio),0); /* GPIO_58 ---> 0 */
mdelay(10);
gpio_direction_output(62,0); /* GPIO_62 ---> 0 */
}
}
}
//pr_err("%s: gpio 19=%d", __func__,gpio_get_value(ctrl_pdata->rst_gpio));
//pr_err("%s:---\n", __func__);
return 0;
}
//yanghai modify end
#endif
static char caset[] = {0x2a, 0x00, 0x00, 0x03, 0x00}; /* DTYPE_DCS_LWRITE */
static char paset[] = {0x2b, 0x00, 0x00, 0x05, 0x00}; /* DTYPE_DCS_LWRITE */
static struct dsi_cmd_desc partial_update_enable_cmd[] = {
{{DTYPE_DCS_LWRITE, 1, 0, 0, 1, sizeof(caset)}, caset},
{{DTYPE_DCS_LWRITE, 1, 0, 0, 1, sizeof(paset)}, paset},
};
static int mdss_dsi_panel_partial_update(struct mdss_panel_data *pdata)
{
struct mipi_panel_info *mipi;
struct mdss_dsi_ctrl_pdata *ctrl = NULL;
struct dcs_cmd_req cmdreq;
int rc = 0;
if (pdata == NULL) {
pr_err("%s: Invalid input data\n", __func__);
return -EINVAL;
}
ctrl = container_of(pdata, struct mdss_dsi_ctrl_pdata,
panel_data);
mipi = &pdata->panel_info.mipi;
pr_debug("%s: ctrl=%p ndx=%d\n", __func__, ctrl, ctrl->ndx);
caset[1] = (((pdata->panel_info.roi_x) & 0xFF00) >> 8);
caset[2] = (((pdata->panel_info.roi_x) & 0xFF));
caset[3] = (((pdata->panel_info.roi_x - 1 + pdata->panel_info.roi_w)
& 0xFF00) >> 8);
caset[4] = (((pdata->panel_info.roi_x - 1 + pdata->panel_info.roi_w)
& 0xFF));
partial_update_enable_cmd[0].payload = caset;
paset[1] = (((pdata->panel_info.roi_y) & 0xFF00) >> 8);
paset[2] = (((pdata->panel_info.roi_y) & 0xFF));
paset[3] = (((pdata->panel_info.roi_y - 1 + pdata->panel_info.roi_h)
& 0xFF00) >> 8);
paset[4] = (((pdata->panel_info.roi_y - 1 + pdata->panel_info.roi_h)
& 0xFF));
partial_update_enable_cmd[1].payload = paset;
pr_debug("%s: enabling partial update\n", __func__);
memset(&cmdreq, 0, sizeof(cmdreq));
cmdreq.cmds = partial_update_enable_cmd;
cmdreq.cmds_cnt = 2;
cmdreq.flags = CMD_REQ_COMMIT | CMD_CLK_CTRL;
cmdreq.rlen = 0;
cmdreq.cb = NULL;
mdss_dsi_cmdlist_put(ctrl, &cmdreq);
return rc;
}
static struct mdss_dsi_ctrl_pdata *get_rctrl_data(struct mdss_panel_data *pdata)
{
if (!pdata || !pdata->next) {
pr_err("%s: Invalid panel data\n", __func__);
return NULL;
}
return container_of(pdata->next, struct mdss_dsi_ctrl_pdata,
panel_data);
}
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_VENDOR_EDIT
/*liuyan 2014-8-21 merge*/
lm3630_bank_a_update_status(bl_level);
return;
#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);
/*
* Some backlight controllers specify a minimum duty cycle
* for the backlight brightness. If the brightness is less
* than it, the controller can malfunction.
*/
if ((bl_level < pdata->panel_info.bl_min) && (bl_level != 0))
bl_level = pdata->panel_info.bl_min;
switch (ctrl_pdata->bklt_ctrl) {
case BL_WLED:
led_trigger_event(bl_led_trigger, bl_level);
break;
case BL_PWM:
mdss_dsi_panel_bklt_pwm(ctrl_pdata, bl_level);
break;
case BL_DCS_CMD:
mdss_dsi_panel_bklt_dcs(ctrl_pdata, bl_level);
if (ctrl_pdata->shared_pdata.broadcast_enable &&
ctrl_pdata->ndx == DSI_CTRL_0) {
struct mdss_dsi_ctrl_pdata *rctrl_pdata = NULL;
rctrl_pdata = get_rctrl_data(pdata);
if (!rctrl_pdata) {
pr_err("%s: Right ctrl data NULL\n", __func__);
return;
}
mdss_dsi_panel_bklt_dcs(rctrl_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);
mipi = &pdata->panel_info.mipi;
pr_err("%s: gpio 58=%d,pannel index=%d\n", __func__,gpio_get_value(58),ctrl->index);
#ifdef VENDOR_EDIT
/* [email protected], 2014/08/10 Add for print 14021 lcd enable pin */
if(get_pcb_version() >= HW_VERSION__30)
pr_err("%s: gpio 76=%d\n", __func__,gpio_get_value(ctrl->disp_en_gpio76));
#endif /*CONFIG_VENDOR_EDIT*/
pr_debug("%s: ctrl=%p ndx=%d\n", __func__, ctrl, ctrl->ndx);
if (ctrl->on_cmds.cmd_cnt){
//yang hai and
if( (ctrl->index==0 && LCD_id < 4) || (ctrl->index==1 && (LCD_id ==4 || ((get_pcb_version()>=22)&&(get_pcb_version()<30))))){ /*liuyan add 30 for N3*/
//yanghai and end
mdss_dsi_panel_cmds_send(ctrl, &ctrl->on_cmds);
pr_err("%s: send cmd successfully\n", __func__);
set_resume_gamma(gamma_index);
//set_resume_gamma(2);
}
}
//yanghai test
//if(ctrl->index==0){
//if(0){
//mdss_dsi_dcs_read(ctrl,0x52, 0x00);
// mdss_dsi_dcs_read(ctrl,0x54, 0x00);
// mdss_dsi_dcs_read(ctrl,0x56, 0x00);
//}
//yanghai test end
#ifdef VENDOR_EDIT
/* Xiaori.Yuan@Mobile Phone Software Dept.Driver, 2014/02/17 Add for set cabc */
if(ctrl->index==0){
set_backlight_pwm(1);
if(cabc_mode != CABC_HIGH_MODE){
set_cabc_resume_mode(cabc_mode);
}
mutex_lock(&cabc_mutex);
flag_lcd_off = false;
mutex_unlock(&cabc_mutex);
}
#endif /*VENDOR_EDIT*/
#ifdef VENDOR_EDIT
/* Xiaori.Yuan@Mobile Phone Software Dept.Driver, 2014/02/25 Add for ESD test */
if(ctrl->index==0 && get_boot_mode() != MSM_BOOT_MODE__FACTORY){
if(first_run_reset==1 && !cont_splash_flag){
first_run_reset=0;
}
else{
spin_lock_irqsave(&te_count_lock, flags);
te_count = 0;
spin_unlock_irqrestore(&te_count_lock, flags);
irq_state++;
enable_irq(irq);
schedule_delayed_work(&techeck_work, msecs_to_jiffies(5000));
}
}
#endif /*VENDOR_EDIT*/
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;
}
#ifdef CONFIG_VENDOR_EDIT
/*liuyan 2014-8-21 merge*/
mutex_lock(&cabc_mutex);
flag_lcd_off = true;
mutex_unlock(&cabc_mutex);
#endif
ctrl = container_of(pdata, struct mdss_dsi_ctrl_pdata,
panel_data);
pr_debug("%s: ctrl=%p ndx=%d\n", __func__, ctrl, ctrl->ndx);
mipi = &pdata->panel_info.mipi;
#ifndef CONFIG_VENDOR_EDIT
/*liuyan 2014-8-21 merge*/
if (ctrl->off_cmds.cmd_cnt)
mdss_dsi_panel_cmds_send(ctrl, &ctrl->off_cmds);
#else
if (ctrl->off_cmds.cmd_cnt){
if(ctrl->index==0){
if(LCD_id == 4 || ((get_pcb_version()>=22)&&(get_pcb_version()< 30)))/*liuyan add 30 for N3*/
mdss_dsi_panel_cmds_send(panel_data, &ctrl->off_cmds);
else
mdss_dsi_panel_cmds_send(ctrl, &ctrl->off_cmds);
}
}
#ifdef VENDOR_EDIT
/* Xiaori.Yuan@Mobile Phone Software Dept.Driver, 2014/02/25 Add for ESD test */
if(ctrl->index==0 && get_boot_mode() != MSM_BOOT_MODE__FACTORY){
cancel_delayed_work_sync(&techeck_work);
mdelay(6);
irq_state--;
disable_irq(irq);
}
#endif /*VENDOR_EDIT*/
#endif
pr_debug("%s:-\n", __func__);
return 0;
}
static void mdss_dsi_parse_lane_swap(struct device_node *np, char *dlane_swap)
{
const char *data;
*dlane_swap = DSI_LANE_MAP_0123;
data = of_get_property(np, "qcom,mdss-dsi-lane-map", NULL);
if (data) {
if (!strcmp(data, "lane_map_3012"))
*dlane_swap = DSI_LANE_MAP_3012;
else if (!strcmp(data, "lane_map_2301"))
*dlane_swap = DSI_LANE_MAP_2301;
else if (!strcmp(data, "lane_map_1230"))
*dlane_swap = DSI_LANE_MAP_1230;
else if (!strcmp(data, "lane_map_0321"))
*dlane_swap = DSI_LANE_MAP_0321;
else if (!strcmp(data, "lane_map_1032"))
*dlane_swap = DSI_LANE_MAP_1032;
else if (!strcmp(data, "lane_map_2103"))
*dlane_swap = DSI_LANE_MAP_2103;
else if (!strcmp(data, "lane_map_3210"))
*dlane_swap = DSI_LANE_MAP_3210;
}
}
static void mdss_dsi_parse_trigger(struct device_node *np, char *trigger,
char *trigger_key)
{
const char *data;
*trigger = DSI_CMD_TRIGGER_SW;
data = of_get_property(np, trigger_key, NULL);
if (data) {
if (!strcmp(data, "none"))
*trigger = DSI_CMD_TRIGGER_NONE;
else if (!strcmp(data, "trigger_te"))
*trigger = DSI_CMD_TRIGGER_TE;
else if (!strcmp(data, "trigger_sw_seof"))
*trigger = DSI_CMD_TRIGGER_SW_SEOF;
else if (!strcmp(data, "trigger_sw_te"))
*trigger = DSI_CMD_TRIGGER_SW_TE;
}
}
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);
goto exit_free;
}
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);
goto exit_free;
}
pcmds->cmds = kzalloc(cnt * sizeof(struct dsi_cmd_desc),
GFP_KERNEL);
if (!pcmds->cmds)
goto exit_free;
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;
}
data = of_get_property(np, link_key, NULL);
if (data && !strcmp(data, "dsi_hs_mode"))
pcmds->link_state = DSI_HS_MODE;
else
pcmds->link_state = DSI_LP_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;
exit_free:
kfree(buf);
return -ENOMEM;
}
static int mdss_panel_dt_get_dst_fmt(u32 bpp, char mipi_mode, u32 pixel_packing,
char *dst_format)
{
int rc = 0;
switch (bpp) {
case 3:
*dst_format = DSI_CMD_DST_FORMAT_RGB111;
break;
case 8:
*dst_format = DSI_CMD_DST_FORMAT_RGB332;
break;
case 12:
*dst_format = DSI_CMD_DST_FORMAT_RGB444;
break;
case 16:
switch (mipi_mode) {
case DSI_VIDEO_MODE:
*dst_format = DSI_VIDEO_DST_FORMAT_RGB565;
break;
case DSI_CMD_MODE:
*dst_format = DSI_CMD_DST_FORMAT_RGB565;
break;
default:
*dst_format = DSI_VIDEO_DST_FORMAT_RGB565;
break;
}
break;
case 18:
switch (mipi_mode) {
case DSI_VIDEO_MODE:
if (pixel_packing == 0)
*dst_format = DSI_VIDEO_DST_FORMAT_RGB666;
else
*dst_format = DSI_VIDEO_DST_FORMAT_RGB666_LOOSE;
break;
case DSI_CMD_MODE:
*dst_format = DSI_CMD_DST_FORMAT_RGB666;
break;
default:
if (pixel_packing == 0)
*dst_format = DSI_VIDEO_DST_FORMAT_RGB666;
else
*dst_format = DSI_VIDEO_DST_FORMAT_RGB666_LOOSE;
break;
}
break;
case 24:
switch (mipi_mode) {
case DSI_VIDEO_MODE:
*dst_format = DSI_VIDEO_DST_FORMAT_RGB888;
break;
case DSI_CMD_MODE:
*dst_format = DSI_CMD_DST_FORMAT_RGB888;
break;
default:
*dst_format = DSI_VIDEO_DST_FORMAT_RGB888;
break;
}
break;
default:
rc = -EINVAL;
break;
}
return rc;
}
static int mdss_dsi_parse_fbc_params(struct device_node *np,
struct mdss_panel_info *panel_info)
{
int rc, fbc_enabled = 0;
u32 tmp;
fbc_enabled = of_property_read_bool(np, "qcom,mdss-dsi-fbc-enable");
if (fbc_enabled) {
pr_debug("%s:%d FBC panel enabled.\n", __func__, __LINE__);
panel_info->fbc.enabled = 1;
rc = of_property_read_u32(np, "qcom,mdss-dsi-fbc-bpp", &tmp);
panel_info->fbc.target_bpp = (!rc ? tmp : panel_info->bpp);
rc = of_property_read_u32(np, "qcom,mdss-dsi-fbc-packing",
&tmp);
panel_info->fbc.comp_mode = (!rc ? tmp : 0);
panel_info->fbc.qerr_enable = of_property_read_bool(np,
"qcom,mdss-dsi-fbc-quant-error");
rc = of_property_read_u32(np, "qcom,mdss-dsi-fbc-bias", &tmp);
panel_info->fbc.cd_bias = (!rc ? tmp : 0);
panel_info->fbc.pat_enable = of_property_read_bool(np,
"qcom,mdss-dsi-fbc-pat-mode");
panel_info->fbc.vlc_enable = of_property_read_bool(np,
"qcom,mdss-dsi-fbc-vlc-mode");
panel_info->fbc.bflc_enable = of_property_read_bool(np,
"qcom,mdss-dsi-fbc-bflc-mode");
rc = of_property_read_u32(np, "qcom,mdss-dsi-fbc-h-line-budget",
&tmp);
panel_info->fbc.line_x_budget = (!rc ? tmp : 0);
rc = of_property_read_u32(np, "qcom,mdss-dsi-fbc-budget-ctrl",
&tmp);
panel_info->fbc.block_x_budget = (!rc ? tmp : 0);
rc = of_property_read_u32(np, "qcom,mdss-dsi-fbc-block-budget",
&tmp);
panel_info->fbc.block_budget = (!rc ? tmp : 0);
rc = of_property_read_u32(np,
"qcom,mdss-dsi-fbc-lossless-threshold", &tmp);
panel_info->fbc.lossless_mode_thd = (!rc ? tmp : 0);
rc = of_property_read_u32(np,
"qcom,mdss-dsi-fbc-lossy-threshold", &tmp);
panel_info->fbc.lossy_mode_thd = (!rc ? tmp : 0);
rc = of_property_read_u32(np, "qcom,mdss-dsi-fbc-rgb-threshold",
&tmp);
panel_info->fbc.lossy_rgb_thd = (!rc ? tmp : 0);
rc = of_property_read_u32(np,
"qcom,mdss-dsi-fbc-lossy-mode-idx", &tmp);
panel_info->fbc.lossy_mode_idx = (!rc ? tmp : 0);
} else {
pr_debug("%s:%d Panel does not support FBC.\n",
__func__, __LINE__);
panel_info->fbc.enabled = 0;
panel_info->fbc.target_bpp =
panel_info->bpp;
}
return 0;
}
static int mdss_dsi_parse_reset_seq(struct device_node *np,
u32 rst_seq[MDSS_DSI_RST_SEQ_LEN], u32 *rst_len,
const char *name)
{
int num = 0, i;
int rc;
struct property *data;
u32 tmp[MDSS_DSI_RST_SEQ_LEN];
*rst_len = 0;
data = of_find_property(np, name, &num);
num /= sizeof(u32);
if (!data || !num || num > MDSS_DSI_RST_SEQ_LEN || num % 2) {
pr_debug("%s:%d, error reading %s, length found = %d\n",
__func__, __LINE__, name, num);
} else {
rc = of_property_read_u32_array(np, name, tmp, num);
if (rc)
pr_debug("%s:%d, error reading %s, rc = %d\n",
__func__, __LINE__, name, rc);
else {
for (i = 0; i < num; ++i)
rst_seq[i] = tmp[i];
*rst_len = num;
}
}
return 0;
}
static int mdss_panel_parse_dt(struct device_node *np,
struct mdss_dsi_ctrl_pdata *ctrl_pdata)
{
u32 tmp;
int rc, i, len;
const char *data;
static const char *pdest;
struct mdss_panel_info *pinfo = &(ctrl_pdata->panel_data.panel_info);
rc = of_property_read_u32(np, "qcom,mdss-dsi-panel-width", &tmp);
if (rc) {
pr_err("%s:%d, panel width not specified\n",
__func__, __LINE__);
return -EINVAL;
}
pinfo->xres = (!rc ? tmp : 640);
rc = of_property_read_u32(np, "qcom,mdss-dsi-panel-height", &tmp);
if (rc) {
pr_err("%s:%d, panel height not specified\n",
__func__, __LINE__);
return -EINVAL;
}
pinfo->yres = (!rc ? tmp : 480);
rc = of_property_read_u32(np,
"qcom,mdss-pan-physical-width-dimension", &tmp);
pinfo->physical_width = (!rc ? tmp : 0);
rc = of_property_read_u32(np,
"qcom,mdss-pan-physical-height-dimension", &tmp);
pinfo->physical_height = (!rc ? tmp : 0);
rc = of_property_read_u32(np, "qcom,mdss-dsi-h-left-border", &tmp);
pinfo->lcdc.xres_pad = (!rc ? tmp : 0);
rc = of_property_read_u32(np, "qcom,mdss-dsi-h-right-border", &tmp);
if (!rc)
pinfo->lcdc.xres_pad += tmp;
rc = of_property_read_u32(np, "qcom,mdss-dsi-v-top-border", &tmp);
pinfo->lcdc.yres_pad = (!rc ? tmp : 0);
rc = of_property_read_u32(np, "qcom,mdss-dsi-v-bottom-border", &tmp);
if (!rc)
pinfo->lcdc.yres_pad += tmp;
rc = of_property_read_u32(np, "qcom,mdss-dsi-bpp", &tmp);
if (rc) {
pr_err("%s:%d, bpp not specified\n", __func__, __LINE__);
return -EINVAL;
}
pinfo->bpp = (!rc ? tmp : 24);
pinfo->mipi.mode = DSI_VIDEO_MODE;
data = of_get_property(np, "qcom,mdss-dsi-panel-type", NULL);
if (data && !strncmp(data, "dsi_cmd_mode", 12))
pinfo->mipi.mode = DSI_CMD_MODE;
tmp = 0;
data = of_get_property(np, "qcom,mdss-dsi-pixel-packing", NULL);
if (data && !strcmp(data, "loose"))
tmp = 1;
rc = mdss_panel_dt_get_dst_fmt(pinfo->bpp,
pinfo->mipi.mode, tmp,
&(pinfo->mipi.dst_format));
if (rc) {
pr_debug("%s: problem determining dst format. Set Default\n",
__func__);
pinfo->mipi.dst_format =
DSI_VIDEO_DST_FORMAT_RGB888;
}
pdest = of_get_property(np,
"qcom,mdss-dsi-panel-destination", NULL);
if (pdest) {
if (strlen(pdest) != 9) {
pr_err("%s: Unknown pdest specified\n", __func__);
return -EINVAL;
}
if (!strcmp(pdest, "display_1"))
pinfo->pdest = DISPLAY_1;
else if (!strcmp(pdest, "display_2"))
pinfo->pdest = DISPLAY_2;
else {
pr_debug("%s: pdest not specified. Set Default\n",
__func__);
pinfo->pdest = DISPLAY_1;
}
} else {
pr_err("%s: pdest not specified\n", __func__);
return -EINVAL;
}
rc = of_property_read_u32(np, "qcom,mdss-dsi-h-front-porch", &tmp);
pinfo->lcdc.h_front_porch = (!rc ? tmp : 6);
rc = of_property_read_u32(np, "qcom,mdss-dsi-h-back-porch", &tmp);
pinfo->lcdc.h_back_porch = (!rc ? tmp : 6);
rc = of_property_read_u32(np, "qcom,mdss-dsi-h-pulse-width", &tmp);
pinfo->lcdc.h_pulse_width = (!rc ? tmp : 2);
rc = of_property_read_u32(np, "qcom,mdss-dsi-h-sync-skew", &tmp);
pinfo->lcdc.hsync_skew = (!rc ? tmp : 0);
rc = of_property_read_u32(np, "qcom,mdss-dsi-v-back-porch", &tmp);
pinfo->lcdc.v_back_porch = (!rc ? tmp : 6);
rc = of_property_read_u32(np, "qcom,mdss-dsi-v-front-porch", &tmp);
pinfo->lcdc.v_front_porch = (!rc ? tmp : 6);
rc = of_property_read_u32(np, "qcom,mdss-dsi-v-pulse-width", &tmp);
pinfo->lcdc.v_pulse_width = (!rc ? tmp : 2);
rc = of_property_read_u32(np,
"qcom,mdss-dsi-underflow-color", &tmp);
pinfo->lcdc.underflow_clr = (!rc ? tmp : 0xff);
rc = of_property_read_u32(np,
"qcom,mdss-dsi-border-color", &tmp);
pinfo->lcdc.border_clr = (!rc ? tmp : 0);
pinfo->bklt_ctrl = UNKNOWN_CTRL;
data = of_get_property(np, "qcom,mdss-dsi-bl-pmic-control-type", NULL);
if (data) {
if (!strncmp(data, "bl_ctrl_wled", 12)) {
led_trigger_register_simple("bkl-trigger",
&bl_led_trigger);
pr_debug("%s: SUCCESS-> WLED TRIGGER register\n",
__func__);
ctrl_pdata->bklt_ctrl = BL_WLED;
} else if (!strncmp(data, "bl_ctrl_pwm", 11)) {
ctrl_pdata->bklt_ctrl = BL_PWM;
rc = of_property_read_u32(np,
"qcom,mdss-dsi-bl-pmic-pwm-frequency", &tmp);
if (rc) {
pr_err("%s:%d, Error, panel pwm_period\n",
__func__, __LINE__);
return -EINVAL;
}
ctrl_pdata->pwm_period = tmp;
rc = of_property_read_u32(np,
"qcom,mdss-dsi-bl-pmic-bank-select", &tmp);
if (rc) {
pr_err("%s:%d, Error, dsi lpg channel\n",
__func__, __LINE__);
return -EINVAL;
}
ctrl_pdata->pwm_lpg_chan = tmp;
tmp = of_get_named_gpio(np,
"qcom,mdss-dsi-pwm-gpio", 0);
ctrl_pdata->pwm_pmic_gpio = tmp;
} else if (!strncmp(data, "bl_ctrl_dcs", 11)) {
ctrl_pdata->bklt_ctrl = BL_DCS_CMD;
}
}
rc = of_property_read_u32(np, "qcom,mdss-brightness-max-level", &tmp);
pinfo->brightness_max = (!rc ? tmp : MDSS_MAX_BL_BRIGHTNESS);
rc = of_property_read_u32(np, "qcom,mdss-dsi-bl-min-level", &tmp);
pinfo->bl_min = (!rc ? tmp : 0);
rc = of_property_read_u32(np, "qcom,mdss-dsi-bl-max-level", &tmp);
pinfo->bl_max = (!rc ? tmp : 255);
ctrl_pdata->bklt_max = pinfo->bl_max;
rc = of_property_read_u32(np, "qcom,mdss-dsi-interleave-mode", &tmp);
pinfo->mipi.interleave_mode = (!rc ? tmp : 0);
pinfo->mipi.vsync_enable = of_property_read_bool(np,
"qcom,mdss-dsi-te-check-enable");
pinfo->mipi.hw_vsync_mode = of_property_read_bool(np,
"qcom,mdss-dsi-te-using-te-pin");
rc = of_property_read_u32(np,
"qcom,mdss-dsi-h-sync-pulse", &tmp);
pinfo->mipi.pulse_mode_hsa_he = (!rc ? tmp : false);
pinfo->mipi.hfp_power_stop = of_property_read_bool(np,
"qcom,mdss-dsi-hfp-power-mode");
pinfo->mipi.hsa_power_stop = of_property_read_bool(np,
"qcom,mdss-dsi-hsa-power-mode");
pinfo->mipi.hbp_power_stop = of_property_read_bool(np,
"qcom,mdss-dsi-hbp-power-mode");
pinfo->mipi.bllp_power_stop = of_property_read_bool(np,
"qcom,mdss-dsi-bllp-power-mode");
pinfo->mipi.eof_bllp_power_stop = of_property_read_bool(
np, "qcom,mdss-dsi-bllp-eof-power-mode");
pinfo->mipi.traffic_mode = DSI_NON_BURST_SYNCH_PULSE;
data = of_get_property(np, "qcom,mdss-dsi-traffic-mode", NULL);
if (data) {
if (!strcmp(data, "non_burst_sync_event"))
pinfo->mipi.traffic_mode = DSI_NON_BURST_SYNCH_EVENT;
else if (!strcmp(data, "burst_mode"))
pinfo->mipi.traffic_mode = DSI_BURST_MODE;
}
rc = of_property_read_u32(np,
"qcom,mdss-dsi-te-dcs-command", &tmp);
pinfo->mipi.insert_dcs_cmd =
(!rc ? tmp : 1);
rc = of_property_read_u32(np,
"qcom,mdss-dsi-wr-mem-continue", &tmp);
pinfo->mipi.wr_mem_continue =
(!rc ? tmp : 0x3c);
rc = of_property_read_u32(np,
"qcom,mdss-dsi-wr-mem-start", &tmp);
pinfo->mipi.wr_mem_start =
(!rc ? tmp : 0x2c);
rc = of_property_read_u32(np,
"qcom,mdss-dsi-te-pin-select", &tmp);
pinfo->mipi.te_sel =
(!rc ? tmp : 1);
rc = of_property_read_u32(np, "qcom,mdss-dsi-virtual-channel-id", &tmp);
pinfo->mipi.vc = (!rc ? tmp : 0);
pinfo->mipi.rgb_swap = DSI_RGB_SWAP_RGB;
data = of_get_property(np, "qcom,mdss-dsi-color-order", NULL);
if (data) {
if (!strcmp(data, "rgb_swap_rbg"))
pinfo->mipi.rgb_swap = DSI_RGB_SWAP_RBG;
else if (!strcmp(data, "rgb_swap_bgr"))
pinfo->mipi.rgb_swap = DSI_RGB_SWAP_BGR;
else if (!strcmp(data, "rgb_swap_brg"))
pinfo->mipi.rgb_swap = DSI_RGB_SWAP_BRG;
else if (!strcmp(data, "rgb_swap_grb"))
pinfo->mipi.rgb_swap = DSI_RGB_SWAP_GRB;
else if (!strcmp(data, "rgb_swap_gbr"))
pinfo->mipi.rgb_swap = DSI_RGB_SWAP_GBR;
}
pinfo->mipi.data_lane0 = of_property_read_bool(np,
"qcom,mdss-dsi-lane-0-state");
pinfo->mipi.data_lane1 = of_property_read_bool(np,
"qcom,mdss-dsi-lane-1-state");
pinfo->mipi.data_lane2 = of_property_read_bool(np,
"qcom,mdss-dsi-lane-2-state");
pinfo->mipi.data_lane3 = of_property_read_bool(np,
"qcom,mdss-dsi-lane-3-state");
rc = of_property_read_u32(np, "qcom,mdss-dsi-t-clk-pre", &tmp);
pinfo->mipi.t_clk_pre = (!rc ? tmp : 0x24);
rc = of_property_read_u32(np, "qcom,mdss-dsi-t-clk-post", &tmp);
pinfo->mipi.t_clk_post = (!rc ? tmp : 0x03);
pinfo->mipi.rx_eot_ignore = of_property_read_bool(np,
"qcom,mdss-dsi-rx-eot-ignore");
pinfo->mipi.tx_eot_append = of_property_read_bool(np,
"qcom,mdss-dsi-tx-eot-append");
rc = of_property_read_u32(np, "qcom,mdss-dsi-stream", &tmp);
pinfo->mipi.stream = (!rc ? tmp : 0);
data = of_get_property(np, "qcom,mdss-dsi-panel-mode-gpio-state", NULL);
if (data) {
if (!strcmp(data, "high"))
pinfo->mode_gpio_state = MODE_GPIO_HIGH;
else if (!strcmp(data, "low"))
pinfo->mode_gpio_state = MODE_GPIO_LOW;
} else {
pinfo->mode_gpio_state = MODE_GPIO_NOT_VALID;
}
rc = of_property_read_u32(np, "qcom,mdss-dsi-panel-framerate", &tmp);
pinfo->mipi.frame_rate = (!rc ? tmp : 60);
rc = of_property_read_u32(np, "qcom,mdss-dsi-panel-clockrate", &tmp);
pinfo->clk_rate = (!rc ? tmp : 0);
data = of_get_property(np, "qcom,mdss-dsi-panel-timings", &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++)
pinfo->mipi.dsi_phy_db.timing[i] = data[i];
pinfo->mipi.lp11_init = of_property_read_bool(np,
"qcom,mdss-dsi-lp11-init");
rc = of_property_read_u32(np, "qcom,mdss-dsi-init-delay-us", &tmp);
pinfo->mipi.init_delay = (!rc ? tmp : 0);
mdss_dsi_parse_fbc_params(np, pinfo);
mdss_dsi_parse_trigger(np, &(pinfo->mipi.mdp_trigger),
"qcom,mdss-dsi-mdp-trigger");
mdss_dsi_parse_trigger(np, &(pinfo->mipi.dma_trigger),
"qcom,mdss-dsi-dma-trigger");
mdss_dsi_parse_lane_swap(np, &(pinfo->mipi.dlane_swap));
mdss_dsi_parse_reset_seq(np, pinfo->rst_seq, &(pinfo->rst_seq_len),
"qcom,mdss-dsi-reset-sequence");
mdss_dsi_parse_dcs_cmds(np, &ctrl_pdata->on_cmds,
"qcom,mdss-dsi-on-command", "qcom,mdss-dsi-on-command-state");
mdss_dsi_parse_dcs_cmds(np, &ctrl_pdata->off_cmds,
"qcom,mdss-dsi-off-command", "qcom,mdss-dsi-off-command-state");
#ifdef VENDOR_EDIT
/* Xiaori.Yuan@Mobile Phone Software Dept.Driver, 2014/02/17 Add for set cabc */
mdss_dsi_parse_dcs_cmds(np, &cabc_off_sequence,
"qcom,mdss-dsi-cabc-off-command", "qcom,mdss-dsi-off-command-state");
mdss_dsi_parse_dcs_cmds(np, &cabc_user_interface_image_sequence,
"qcom,mdss-dsi-cabc-ui-command", "qcom,mdss-dsi-off-command-state");
mdss_dsi_parse_dcs_cmds(np, &cabc_still_image_sequence,
"qcom,mdss-dsi-cabc-still-image-command", "qcom,mdss-dsi-off-command-state");
mdss_dsi_parse_dcs_cmds(np, &cabc_video_image_sequence,
"qcom,mdss-dsi-cabc-video-command", "qcom,mdss-dsi-off-command-state");
mdss_dsi_parse_dcs_cmds(np, &gamma1,
"qcom,mdss-dsi-gamma1", "qcom,mdss-dsi-off-command-state");
mdss_dsi_parse_dcs_cmds(np, &gamma2,
"qcom,mdss-dsi-gamma2", "qcom,mdss-dsi-off-command-state");
mdss_dsi_parse_dcs_cmds(np, &gamma3,
"qcom,mdss-dsi-gamma3", "qcom,mdss-dsi-off-command-state");
mdss_dsi_parse_dcs_cmds(np, &gamma4,
"qcom,mdss-dsi-gamma4", "qcom,mdss-dsi-off-command-state");
#endif /*VENDOR_EDIT*/
return 0;
error:
return -EINVAL;
}
int mdss_dsi_panel_init(struct device_node *node,
struct mdss_dsi_ctrl_pdata *ctrl_pdata,
bool cmd_cfg_cont_splash)
{
int rc = 0;
static const char *panel_name;
bool cont_splash_enabled;
bool partial_update_enabled;
#ifdef VENDOR_EDIT
/* OPPO 2013-10-24 yxq Add begin for panel info */
static const char *panel_manufacture;
static const char *panel_version;
/* OPPO 2013-10-24 yxq Add end */
#endif
#ifdef VENDOR_EDIT
/* Xiaori.Yuan@Mobile Phone Software Dept.Driver, 2014/02/17 Add for set cabc */
if((first_run_init == 1 && LCD_id < 4) || LCD_id == 4 || ((get_pcb_version()>=22)&&(get_pcb_version()<30)))/*liuyan add 30 for N3*/
panel_data = ctrl_pdata;
#endif /*VENDOR_EDIT*/
if (!node) {
pr_err("%s: no panel node\n", __func__);
return -ENODEV;
}
pr_debug("%s:%d\n", __func__, __LINE__);
panel_name = of_get_property(node, "qcom,mdss-dsi-panel-name", 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);
#ifdef VENDOR_EDIT
/* OPPO 2013-10-24 yxq Add begin for panel info */
/*it just need to do one time*/
if(first_run_init==1){
panel_manufacture = of_get_property(node, "qcom,mdss-dsi-panel-manufacture", NULL);
if (!panel_manufacture)
pr_info("%s:%d, panel manufacture not specified\n", __func__, __LINE__);
else
pr_info("%s: Panel Manufacture = %s\n", __func__, panel_manufacture);
panel_version = of_get_property(node, "qcom,mdss-dsi-panel-version", NULL);
if (!panel_version)
pr_info("%s:%d, panel version not specified\n", __func__, __LINE__);
else
pr_info("%s: Panel Version = %s\n", __func__, panel_version);
register_device_proc("lcd", (char *)panel_version, (char *)panel_manufacture);
}
/* OPPO 2013-10-24 yxq Add end */
#endif
#ifdef VENDOR_EDIT
/* Xiaori.Yuan@Mobile Phone Software Dept.Driver, 2014/02/22 Add for ESD test*/
if (first_run_init==1 && get_boot_mode() != MSM_BOOT_MODE__FACTORY){ //for find7s
first_run_init=0;
irq = gpio_to_irq(LCD_TE_GPIO); //gpio 28 has configed in mdss_dsi.c
rc = request_threaded_irq(irq, NULL, TE_irq_thread_fn,
IRQF_TRIGGER_RISING, "LCD_TE",NULL);
if (rc < 0) {
pr_err("Unable to register IRQ handler\n");
return -ENODEV;
}
INIT_DELAYED_WORK(&techeck_work, techeck_work_func );
schedule_delayed_work(&techeck_work, msecs_to_jiffies(20000));
display_switch.name = "dispswitch";
rc = switch_dev_register(&display_switch);
if (rc)
{
pr_err("Unable to register display switch device\n");
return rc;
}
/*dir: /sys/class/mdss_lcd/lcd_control*/
mdss_lcd = class_create(THIS_MODULE,"mdss_lcd");
mdss_lcd->dev_attrs = mdss_lcd_attrs;
device_create(mdss_lcd,dev_lcd,0,NULL,"lcd_control");
if(strstr(panel_name,"rsp 1440p video mode dsi panel")){
pr_err("this is rsp 1440p video mode dsi panel yxr\n");
find7s_lcd_rsp_ic = 1;
}else if(strstr(panel_name,"rsp 1440p cmd mode dsi panel")){
pr_err("this is rsp 1440p cmd mode dsi panel yxr\n");
find7s_lcd_rsp_ic = 1;
}
}
#endif /*VENDOR_EDIT*/
rc = mdss_panel_parse_dt(node, ctrl_pdata);
if (rc) {
pr_err("%s:%d panel dt parse failed\n", __func__, __LINE__);
return rc;
}
if (cmd_cfg_cont_splash)
cont_splash_enabled = of_property_read_bool(node,
"qcom,cont-splash-enabled");
else
cont_splash_enabled = false;
/* OPPO 2013-12-09 yxq Add begin for disable continous display for ftm, rf, wlan mode */
#ifdef VENDOR_EDIT
if ((MSM_BOOT_MODE__FACTORY == get_boot_mode()) ||
(MSM_BOOT_MODE__RF == get_boot_mode()) ||
(MSM_BOOT_MODE__WLAN == get_boot_mode()) ||
(MSM_BOOT_MODE__MOS == get_boot_mode())) {
cont_splash_enabled = false;
}
#endif
/* OPPO 2013-12-09 yxq Add end */
#ifdef VENDOR_EDIT
/* Xiaori.Yuan@Mobile Phone Software Dept.Driver, 2014/02/25 Add for ESD test */
cont_splash_flag = cont_splash_enabled;
#endif /*VENDOR_EDIT*/
if (!cont_splash_enabled) {
pr_info("%s:%d Continuous splash flag not found.\n",
__func__, __LINE__);
ctrl_pdata->panel_data.panel_info.cont_splash_enabled = 0;
} else {
pr_info("%s:%d Continuous splash flag enabled.\n",
__func__, __LINE__);
ctrl_pdata->panel_data.panel_info.cont_splash_enabled = 1;
}
partial_update_enabled = of_property_read_bool(node,
"qcom,partial-update-enabled");
if (partial_update_enabled) {
pr_info("%s:%d Partial update enabled.\n", __func__, __LINE__);
ctrl_pdata->panel_data.panel_info.partial_update_enabled = 1;
ctrl_pdata->partial_update_fnc = mdss_dsi_panel_partial_update;
} else {
pr_info("%s:%d Partial update disabled.\n", __func__, __LINE__);
ctrl_pdata->panel_data.panel_info.partial_update_enabled = 0;
ctrl_pdata->partial_update_fnc = NULL;
}
ctrl_pdata->on = mdss_dsi_panel_on;
ctrl_pdata->off = mdss_dsi_panel_off;
ctrl_pdata->panel_data.set_backlight = mdss_dsi_panel_bl_ctrl;
return 0;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment