690 lines
16 KiB
C
690 lines
16 KiB
C
/* Copyright (c) 2010-2012, 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.
|
|
*
|
|
*/
|
|
|
|
#ifdef CONFIG_SPI_QUP
|
|
#include <linux/spi/spi.h>
|
|
#endif
|
|
#include <linux/leds.h>
|
|
#include "msm_fb.h"
|
|
#include "mipi_dsi.h"
|
|
#include "mipi_novatek.h"
|
|
#include "mdp4.h"
|
|
|
|
|
|
static struct mipi_dsi_panel_platform_data *mipi_novatek_pdata;
|
|
|
|
static struct dsi_buf novatek_tx_buf;
|
|
static struct dsi_buf novatek_rx_buf;
|
|
static int mipi_novatek_lcd_init(void);
|
|
|
|
static int wled_trigger_initialized;
|
|
|
|
#define MIPI_DSI_NOVATEK_SPI_DEVICE_NAME "dsi_novatek_3d_panel_spi"
|
|
#define HPCI_FPGA_READ_CMD 0x84
|
|
#define HPCI_FPGA_WRITE_CMD 0x04
|
|
|
|
#ifdef CONFIG_SPI_QUP
|
|
static struct spi_device *panel_3d_spi_client;
|
|
|
|
static void novatek_fpga_write(uint8 addr, uint16 value)
|
|
{
|
|
char tx_buf[32];
|
|
int rc;
|
|
struct spi_message m;
|
|
struct spi_transfer t;
|
|
u8 data[4] = {0x0, 0x0, 0x0, 0x0};
|
|
|
|
if (!panel_3d_spi_client) {
|
|
pr_err("%s panel_3d_spi_client is NULL\n", __func__);
|
|
return;
|
|
}
|
|
data[0] = HPCI_FPGA_WRITE_CMD;
|
|
data[1] = addr;
|
|
data[2] = ((value >> 8) & 0xFF);
|
|
data[3] = (value & 0xFF);
|
|
|
|
memset(&t, 0, sizeof t);
|
|
memset(tx_buf, 0, sizeof tx_buf);
|
|
t.tx_buf = data;
|
|
t.len = 4;
|
|
spi_setup(panel_3d_spi_client);
|
|
spi_message_init(&m);
|
|
spi_message_add_tail(&t, &m);
|
|
|
|
rc = spi_sync(panel_3d_spi_client, &m);
|
|
if (rc)
|
|
pr_err("%s: SPI transfer failed\n", __func__);
|
|
|
|
return;
|
|
}
|
|
|
|
static void novatek_fpga_read(uint8 addr)
|
|
{
|
|
char tx_buf[32];
|
|
int rc;
|
|
struct spi_message m;
|
|
struct spi_transfer t;
|
|
struct spi_transfer rx;
|
|
char rx_value[2];
|
|
u8 data[4] = {0x0, 0x0};
|
|
|
|
if (!panel_3d_spi_client) {
|
|
pr_err("%s panel_3d_spi_client is NULL\n", __func__);
|
|
return;
|
|
}
|
|
|
|
data[0] = HPCI_FPGA_READ_CMD;
|
|
data[1] = addr;
|
|
|
|
memset(&t, 0, sizeof t);
|
|
memset(tx_buf, 0, sizeof tx_buf);
|
|
memset(&rx, 0, sizeof rx);
|
|
memset(rx_value, 0, sizeof rx_value);
|
|
t.tx_buf = data;
|
|
t.len = 2;
|
|
rx.rx_buf = rx_value;
|
|
rx.len = 2;
|
|
spi_setup(panel_3d_spi_client);
|
|
spi_message_init(&m);
|
|
spi_message_add_tail(&t, &m);
|
|
spi_message_add_tail(&rx, &m);
|
|
|
|
rc = spi_sync(panel_3d_spi_client, &m);
|
|
if (rc)
|
|
pr_err("%s: SPI transfer failed\n", __func__);
|
|
else
|
|
pr_info("%s: rx_value = 0x%x, 0x%x\n", __func__,
|
|
rx_value[0], rx_value[1]);
|
|
|
|
return;
|
|
}
|
|
|
|
static int __devinit panel_3d_spi_probe(struct spi_device *spi)
|
|
{
|
|
panel_3d_spi_client = spi;
|
|
return 0;
|
|
}
|
|
static int __devexit panel_3d_spi_remove(struct spi_device *spi)
|
|
{
|
|
panel_3d_spi_client = NULL;
|
|
return 0;
|
|
}
|
|
static struct spi_driver panel_3d_spi_driver = {
|
|
.probe = panel_3d_spi_probe,
|
|
.remove = __devexit_p(panel_3d_spi_remove),
|
|
.driver = {
|
|
.name = "dsi_novatek_3d_panel_spi",
|
|
.owner = THIS_MODULE,
|
|
}
|
|
};
|
|
|
|
#else
|
|
|
|
static void novatek_fpga_write(uint8 addr, uint16 value)
|
|
{
|
|
return;
|
|
}
|
|
|
|
static void novatek_fpga_read(uint8 addr)
|
|
{
|
|
return;
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
/* novatek blue panel */
|
|
|
|
#ifdef NOVETAK_COMMANDS_UNUSED
|
|
static char display_config_cmd_mode1[] = {
|
|
/* TYPE_DCS_LWRITE */
|
|
0x2A, 0x00, 0x00, 0x01,
|
|
0x3F, 0xFF, 0xFF, 0xFF
|
|
};
|
|
|
|
static char display_config_cmd_mode2[] = {
|
|
/* DTYPE_DCS_LWRITE */
|
|
0x2B, 0x00, 0x00, 0x01,
|
|
0xDF, 0xFF, 0xFF, 0xFF
|
|
};
|
|
|
|
static char display_config_cmd_mode3_666[] = {
|
|
/* DTYPE_DCS_WRITE1 */
|
|
0x3A, 0x66, 0x15, 0x80 /* 666 Packed (18-bits) */
|
|
};
|
|
|
|
static char display_config_cmd_mode3_565[] = {
|
|
/* DTYPE_DCS_WRITE1 */
|
|
0x3A, 0x55, 0x15, 0x80 /* 565 mode */
|
|
};
|
|
|
|
static char display_config_321[] = {
|
|
/* DTYPE_DCS_WRITE1 */
|
|
0x66, 0x2e, 0x15, 0x00 /* Reg 0x66 : 2E */
|
|
};
|
|
|
|
static char display_config_323[] = {
|
|
/* DTYPE_DCS_WRITE */
|
|
0x13, 0x00, 0x05, 0x00 /* Reg 0x13 < Set for Normal Mode> */
|
|
};
|
|
|
|
static char display_config_2lan[] = {
|
|
/* DTYPE_DCS_WRITE */
|
|
0x61, 0x01, 0x02, 0xff /* Reg 0x61 : 01,02 < Set for 2 Data Lane > */
|
|
};
|
|
|
|
static char display_config_exit_sleep[] = {
|
|
/* DTYPE_DCS_WRITE */
|
|
0x11, 0x00, 0x05, 0x80 /* Reg 0x11 < exit sleep mode> */
|
|
};
|
|
|
|
static char display_config_TE_ON[] = {
|
|
/* DTYPE_DCS_WRITE1 */
|
|
0x35, 0x00, 0x15, 0x80
|
|
};
|
|
|
|
static char display_config_39H[] = {
|
|
/* DTYPE_DCS_WRITE */
|
|
0x39, 0x00, 0x05, 0x80
|
|
};
|
|
|
|
static char display_config_set_tear_scanline[] = {
|
|
/* DTYPE_DCS_LWRITE */
|
|
0x44, 0x00, 0x00, 0xff
|
|
};
|
|
|
|
static char display_config_set_twolane[] = {
|
|
/* DTYPE_DCS_WRITE1 */
|
|
0xae, 0x03, 0x15, 0x80
|
|
};
|
|
|
|
static char display_config_set_threelane[] = {
|
|
/* DTYPE_DCS_WRITE1 */
|
|
0xae, 0x05, 0x15, 0x80
|
|
};
|
|
|
|
#else
|
|
|
|
static char sw_reset[2] = {0x01, 0x00}; /* DTYPE_DCS_WRITE */
|
|
static char enter_sleep[2] = {0x10, 0x00}; /* DTYPE_DCS_WRITE */
|
|
static char exit_sleep[2] = {0x11, 0x00}; /* DTYPE_DCS_WRITE */
|
|
static char display_off[2] = {0x28, 0x00}; /* DTYPE_DCS_WRITE */
|
|
static char display_on[2] = {0x29, 0x00}; /* DTYPE_DCS_WRITE */
|
|
|
|
|
|
|
|
static char rgb_888[2] = {0x3A, 0x77}; /* DTYPE_DCS_WRITE1 */
|
|
|
|
#if defined(NOVATEK_TWO_LANE)
|
|
static char set_num_of_lanes[2] = {0xae, 0x03}; /* DTYPE_DCS_WRITE1 */
|
|
#else /* 1 lane */
|
|
static char set_num_of_lanes[2] = {0xae, 0x01}; /* DTYPE_DCS_WRITE1 */
|
|
#endif
|
|
/* commands by Novatke */
|
|
static char novatek_f4[2] = {0xf4, 0x55}; /* DTYPE_DCS_WRITE1 */
|
|
static char novatek_8c[16] = { /* DTYPE_DCS_LWRITE */
|
|
0x8C, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
0x00, 0x08, 0x08, 0x00, 0x30, 0xC0, 0xB7, 0x37};
|
|
static char novatek_ff[2] = {0xff, 0x55 }; /* DTYPE_DCS_WRITE1 */
|
|
|
|
static char set_width[5] = { /* DTYPE_DCS_LWRITE */
|
|
0x2A, 0x00, 0x00, 0x02, 0x1B}; /* 540 - 1 */
|
|
static char set_height[5] = { /* DTYPE_DCS_LWRITE */
|
|
0x2B, 0x00, 0x00, 0x03, 0xBF}; /* 960 - 1 */
|
|
#endif
|
|
|
|
static char led_pwm2[2] = {0x53, 0x24}; /* DTYPE_DCS_WRITE1 */
|
|
static char led_pwm3[2] = {0x55, 0x00}; /* DTYPE_DCS_WRITE1 */
|
|
|
|
static struct dsi_cmd_desc novatek_video_on_cmds[] = {
|
|
{DTYPE_DCS_WRITE, 1, 0, 0, 50,
|
|
sizeof(sw_reset), sw_reset},
|
|
{DTYPE_DCS_WRITE, 1, 0, 0, 10,
|
|
sizeof(exit_sleep), exit_sleep},
|
|
{DTYPE_DCS_WRITE, 1, 0, 0, 10,
|
|
sizeof(display_on), display_on},
|
|
{DTYPE_DCS_WRITE1, 1, 0, 0, 10,
|
|
sizeof(set_num_of_lanes), set_num_of_lanes},
|
|
{DTYPE_DCS_WRITE1, 1, 0, 0, 10,
|
|
sizeof(rgb_888), rgb_888},
|
|
{DTYPE_DCS_WRITE1, 1, 0, 0, 10,
|
|
sizeof(led_pwm2), led_pwm2},
|
|
{DTYPE_DCS_WRITE1, 1, 0, 0, 10,
|
|
sizeof(led_pwm3), led_pwm3},
|
|
};
|
|
|
|
static struct dsi_cmd_desc novatek_cmd_on_cmds[] = {
|
|
{DTYPE_DCS_WRITE, 1, 0, 0, 50,
|
|
sizeof(sw_reset), sw_reset},
|
|
{DTYPE_DCS_WRITE, 1, 0, 0, 10,
|
|
sizeof(exit_sleep), exit_sleep},
|
|
{DTYPE_DCS_WRITE, 1, 0, 0, 10,
|
|
sizeof(display_on), display_on},
|
|
{DTYPE_DCS_WRITE1, 1, 0, 0, 50,
|
|
sizeof(novatek_f4), novatek_f4},
|
|
{DTYPE_DCS_LWRITE, 1, 0, 0, 50,
|
|
sizeof(novatek_8c), novatek_8c},
|
|
{DTYPE_DCS_WRITE1, 1, 0, 0, 50,
|
|
sizeof(novatek_ff), novatek_ff},
|
|
{DTYPE_DCS_WRITE1, 1, 0, 0, 10,
|
|
sizeof(set_num_of_lanes), set_num_of_lanes},
|
|
{DTYPE_DCS_LWRITE, 1, 0, 0, 50,
|
|
sizeof(set_width), set_width},
|
|
{DTYPE_DCS_LWRITE, 1, 0, 0, 50,
|
|
sizeof(set_height), set_height},
|
|
{DTYPE_DCS_WRITE1, 1, 0, 0, 10,
|
|
sizeof(rgb_888), rgb_888},
|
|
{DTYPE_DCS_WRITE1, 1, 0, 0, 1,
|
|
sizeof(led_pwm2), led_pwm2},
|
|
{DTYPE_DCS_WRITE1, 1, 0, 0, 1,
|
|
sizeof(led_pwm3), led_pwm3},
|
|
};
|
|
|
|
static struct dsi_cmd_desc novatek_display_off_cmds[] = {
|
|
{DTYPE_DCS_WRITE, 1, 0, 0, 10,
|
|
sizeof(display_off), display_off},
|
|
{DTYPE_DCS_WRITE, 1, 0, 0, 120,
|
|
sizeof(enter_sleep), enter_sleep}
|
|
};
|
|
|
|
static char manufacture_id[2] = {0x04, 0x00}; /* DTYPE_DCS_READ */
|
|
|
|
static struct dsi_cmd_desc novatek_manufacture_id_cmd = {
|
|
DTYPE_DCS_READ, 1, 0, 1, 5, sizeof(manufacture_id), manufacture_id};
|
|
|
|
static u32 manu_id;
|
|
|
|
static void mipi_novatek_manufacture_cb(u32 data)
|
|
{
|
|
manu_id = data;
|
|
pr_info("%s: manufacture_id=%x\n", __func__, manu_id);
|
|
}
|
|
|
|
static uint32 mipi_novatek_manufacture_id(struct msm_fb_data_type *mfd)
|
|
{
|
|
struct dcs_cmd_req cmdreq;
|
|
|
|
memset(&cmdreq, 0, sizeof(cmdreq));
|
|
cmdreq.cmds = &novatek_manufacture_id_cmd;
|
|
cmdreq.cmds_cnt = 1;
|
|
cmdreq.flags = CMD_REQ_RX | CMD_REQ_COMMIT;
|
|
cmdreq.rlen = 3;
|
|
cmdreq.rbuf = NULL;
|
|
cmdreq.cb = mipi_novatek_manufacture_cb; /* call back */
|
|
mipi_dsi_cmdlist_put(&cmdreq);
|
|
/*
|
|
* blocked here, untill call back called
|
|
*/
|
|
|
|
return manu_id;
|
|
}
|
|
|
|
static int fpga_addr;
|
|
static int fpga_access_mode;
|
|
static bool support_3d;
|
|
|
|
static void mipi_novatek_3d_init(int addr, int mode)
|
|
{
|
|
fpga_addr = addr;
|
|
fpga_access_mode = mode;
|
|
}
|
|
|
|
static void mipi_dsi_enable_3d_barrier(int mode)
|
|
{
|
|
void __iomem *fpga_ptr;
|
|
uint32_t ptr_value = 0;
|
|
|
|
if (!fpga_addr && support_3d) {
|
|
pr_err("%s: fpga_addr not set. Failed to enable 3D barrier\n",
|
|
__func__);
|
|
return;
|
|
}
|
|
|
|
if (fpga_access_mode == FPGA_SPI_INTF) {
|
|
if (mode == LANDSCAPE)
|
|
novatek_fpga_write(fpga_addr, 1);
|
|
else if (mode == PORTRAIT)
|
|
novatek_fpga_write(fpga_addr, 3);
|
|
else
|
|
novatek_fpga_write(fpga_addr, 0);
|
|
|
|
mb();
|
|
novatek_fpga_read(fpga_addr);
|
|
} else if (fpga_access_mode == FPGA_EBI2_INTF) {
|
|
fpga_ptr = ioremap_nocache(fpga_addr, sizeof(uint32_t));
|
|
if (!fpga_ptr) {
|
|
pr_err("%s: FPGA ioremap failed."
|
|
"Failed to enable 3D barrier\n",
|
|
__func__);
|
|
return;
|
|
}
|
|
|
|
ptr_value = readl_relaxed(fpga_ptr);
|
|
if (mode == LANDSCAPE)
|
|
writel_relaxed(((0xFFFF0000 & ptr_value) | 1),
|
|
fpga_ptr);
|
|
else if (mode == PORTRAIT)
|
|
writel_relaxed(((0xFFFF0000 & ptr_value) | 3),
|
|
fpga_ptr);
|
|
else
|
|
writel_relaxed((0xFFFF0000 & ptr_value),
|
|
fpga_ptr);
|
|
|
|
mb();
|
|
iounmap(fpga_ptr);
|
|
} else
|
|
pr_err("%s: 3D barrier not configured correctly\n",
|
|
__func__);
|
|
}
|
|
|
|
static int mipi_novatek_lcd_on(struct platform_device *pdev)
|
|
{
|
|
struct msm_fb_data_type *mfd;
|
|
struct mipi_panel_info *mipi;
|
|
struct msm_panel_info *pinfo;
|
|
struct dcs_cmd_req cmdreq;
|
|
|
|
mfd = platform_get_drvdata(pdev);
|
|
if (!mfd)
|
|
return -ENODEV;
|
|
if (mfd->key != MFD_KEY)
|
|
return -EINVAL;
|
|
|
|
pinfo = &mfd->panel_info;
|
|
if (pinfo->is_3d_panel)
|
|
support_3d = TRUE;
|
|
|
|
mipi = &mfd->panel_info.mipi;
|
|
|
|
if (mipi->mode == DSI_VIDEO_MODE) {
|
|
cmdreq.cmds = novatek_video_on_cmds;
|
|
cmdreq.cmds_cnt = ARRAY_SIZE(novatek_video_on_cmds);
|
|
cmdreq.flags = CMD_REQ_COMMIT;
|
|
cmdreq.rlen = 0;
|
|
cmdreq.cb = NULL;
|
|
mipi_dsi_cmdlist_put(&cmdreq);
|
|
} else {
|
|
cmdreq.cmds = novatek_cmd_on_cmds;
|
|
cmdreq.cmds_cnt = ARRAY_SIZE(novatek_cmd_on_cmds);
|
|
cmdreq.flags = CMD_REQ_COMMIT;
|
|
cmdreq.rlen = 0;
|
|
cmdreq.cb = NULL;
|
|
mipi_dsi_cmdlist_put(&cmdreq);
|
|
|
|
/* clean up ack_err_status */
|
|
mipi_dsi_cmd_bta_sw_trigger();
|
|
mipi_novatek_manufacture_id(mfd);
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
static int mipi_novatek_lcd_off(struct platform_device *pdev)
|
|
{
|
|
struct msm_fb_data_type *mfd;
|
|
struct dcs_cmd_req cmdreq;
|
|
|
|
mfd = platform_get_drvdata(pdev);
|
|
|
|
if (!mfd)
|
|
return -ENODEV;
|
|
if (mfd->key != MFD_KEY)
|
|
return -EINVAL;
|
|
|
|
cmdreq.cmds = novatek_display_off_cmds;
|
|
cmdreq.cmds_cnt = ARRAY_SIZE(novatek_display_off_cmds);
|
|
cmdreq.flags = CMD_REQ_COMMIT;
|
|
cmdreq.rlen = 0;
|
|
cmdreq.cb = NULL;
|
|
|
|
mipi_dsi_cmdlist_put(&cmdreq);
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int mipi_novatek_lcd_late_init(struct platform_device *pdev)
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
DEFINE_LED_TRIGGER(bkl_led_trigger);
|
|
|
|
static char led_pwm1[2] = {0x51, 0x0}; /* DTYPE_DCS_WRITE1 */
|
|
static struct dsi_cmd_desc backlight_cmd = {
|
|
DTYPE_DCS_LWRITE, 1, 0, 0, 1, sizeof(led_pwm1), led_pwm1};
|
|
|
|
|
|
static void mipi_novatek_set_backlight(struct msm_fb_data_type *mfd)
|
|
{
|
|
struct dcs_cmd_req cmdreq;
|
|
|
|
if (mipi_novatek_pdata &&
|
|
mipi_novatek_pdata->gpio_set_backlight) {
|
|
mipi_novatek_pdata->gpio_set_backlight(mfd->bl_level);
|
|
return;
|
|
}
|
|
|
|
if ((mipi_novatek_pdata->enable_wled_bl_ctrl)
|
|
&& (wled_trigger_initialized)) {
|
|
led_trigger_event(bkl_led_trigger, mfd->bl_level);
|
|
return;
|
|
}
|
|
|
|
led_pwm1[1] = (unsigned char)mfd->bl_level;
|
|
|
|
cmdreq.cmds = &backlight_cmd;
|
|
cmdreq.cmds_cnt = 1;
|
|
cmdreq.flags = CMD_REQ_COMMIT | CMD_CLK_CTRL;
|
|
cmdreq.rlen = 0;
|
|
cmdreq.cb = NULL;
|
|
|
|
mipi_dsi_cmdlist_put(&cmdreq);
|
|
}
|
|
|
|
static int mipi_dsi_3d_barrier_sysfs_register(struct device *dev);
|
|
static int barrier_mode;
|
|
|
|
static int __devinit mipi_novatek_lcd_probe(struct platform_device *pdev)
|
|
{
|
|
struct msm_fb_data_type *mfd;
|
|
struct mipi_panel_info *mipi;
|
|
struct platform_device *current_pdev;
|
|
static struct mipi_dsi_phy_ctrl *phy_settings;
|
|
static char dlane_swap;
|
|
|
|
if (pdev->id == 0) {
|
|
mipi_novatek_pdata = pdev->dev.platform_data;
|
|
|
|
if (mipi_novatek_pdata
|
|
&& mipi_novatek_pdata->phy_ctrl_settings) {
|
|
phy_settings = (mipi_novatek_pdata->phy_ctrl_settings);
|
|
}
|
|
|
|
if (mipi_novatek_pdata
|
|
&& mipi_novatek_pdata->dlane_swap) {
|
|
dlane_swap = (mipi_novatek_pdata->dlane_swap);
|
|
}
|
|
|
|
if (mipi_novatek_pdata
|
|
&& mipi_novatek_pdata->fpga_3d_config_addr)
|
|
mipi_novatek_3d_init(mipi_novatek_pdata
|
|
->fpga_3d_config_addr, mipi_novatek_pdata->fpga_ctrl_mode);
|
|
|
|
/* create sysfs to control 3D barrier for the Sharp panel */
|
|
if (mipi_dsi_3d_barrier_sysfs_register(&pdev->dev)) {
|
|
pr_err("%s: Failed to register 3d Barrier sysfs\n",
|
|
__func__);
|
|
return -ENODEV;
|
|
}
|
|
barrier_mode = 0;
|
|
|
|
return 0;
|
|
}
|
|
|
|
current_pdev = msm_fb_add_device(pdev);
|
|
|
|
if (current_pdev) {
|
|
mfd = platform_get_drvdata(current_pdev);
|
|
if (!mfd)
|
|
return -ENODEV;
|
|
if (mfd->key != MFD_KEY)
|
|
return -EINVAL;
|
|
|
|
mipi = &mfd->panel_info.mipi;
|
|
|
|
if (phy_settings != NULL)
|
|
mipi->dsi_phy_db = phy_settings;
|
|
|
|
if (dlane_swap)
|
|
mipi->dlane_swap = dlane_swap;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
static struct platform_driver this_driver = {
|
|
.probe = mipi_novatek_lcd_probe,
|
|
.driver = {
|
|
.name = "mipi_novatek",
|
|
},
|
|
};
|
|
|
|
static struct msm_fb_panel_data novatek_panel_data = {
|
|
.on = mipi_novatek_lcd_on,
|
|
.off = mipi_novatek_lcd_off,
|
|
.late_init = mipi_novatek_lcd_late_init,
|
|
.set_backlight = mipi_novatek_set_backlight,
|
|
};
|
|
|
|
static ssize_t mipi_dsi_3d_barrier_read(struct device *dev,
|
|
struct device_attribute *attr,
|
|
char *buf)
|
|
{
|
|
return snprintf((char *)buf, sizeof(buf), "%u\n", barrier_mode);
|
|
}
|
|
|
|
static ssize_t mipi_dsi_3d_barrier_write(struct device *dev,
|
|
struct device_attribute *attr,
|
|
const char *buf,
|
|
size_t count)
|
|
{
|
|
int ret = -1;
|
|
u32 data = 0;
|
|
|
|
if (sscanf((char *)buf, "%u", &data) != 1) {
|
|
dev_err(dev, "%s\n", __func__);
|
|
ret = -EINVAL;
|
|
} else {
|
|
barrier_mode = data;
|
|
if (data == 1)
|
|
mipi_dsi_enable_3d_barrier(LANDSCAPE);
|
|
else if (data == 2)
|
|
mipi_dsi_enable_3d_barrier(PORTRAIT);
|
|
else
|
|
mipi_dsi_enable_3d_barrier(0);
|
|
}
|
|
|
|
return count;
|
|
}
|
|
|
|
static struct device_attribute mipi_dsi_3d_barrier_attributes[] = {
|
|
__ATTR(enable_3d_barrier, 0664, mipi_dsi_3d_barrier_read,
|
|
mipi_dsi_3d_barrier_write),
|
|
};
|
|
|
|
static int mipi_dsi_3d_barrier_sysfs_register(struct device *dev)
|
|
{
|
|
int i;
|
|
|
|
for (i = 0; i < ARRAY_SIZE(mipi_dsi_3d_barrier_attributes); i++)
|
|
if (device_create_file(dev, mipi_dsi_3d_barrier_attributes + i))
|
|
goto error;
|
|
|
|
return 0;
|
|
|
|
error:
|
|
for (; i >= 0 ; i--)
|
|
device_remove_file(dev, mipi_dsi_3d_barrier_attributes + i);
|
|
pr_err("%s: Unable to create interface\n", __func__);
|
|
|
|
return -ENODEV;
|
|
}
|
|
|
|
static int ch_used[3];
|
|
|
|
int mipi_novatek_device_register(struct msm_panel_info *pinfo,
|
|
u32 channel, u32 panel)
|
|
{
|
|
struct platform_device *pdev = NULL;
|
|
int ret;
|
|
|
|
if ((channel >= 3) || ch_used[channel])
|
|
return -ENODEV;
|
|
|
|
ch_used[channel] = TRUE;
|
|
|
|
ret = mipi_novatek_lcd_init();
|
|
if (ret) {
|
|
pr_err("mipi_novatek_lcd_init() failed with ret %u\n", ret);
|
|
return ret;
|
|
}
|
|
|
|
pdev = platform_device_alloc("mipi_novatek", (panel << 8)|channel);
|
|
if (!pdev)
|
|
return -ENOMEM;
|
|
|
|
novatek_panel_data.panel_info = *pinfo;
|
|
|
|
ret = platform_device_add_data(pdev, &novatek_panel_data,
|
|
sizeof(novatek_panel_data));
|
|
if (ret) {
|
|
printk(KERN_ERR
|
|
"%s: platform_device_add_data failed!\n", __func__);
|
|
goto err_device_put;
|
|
}
|
|
|
|
ret = platform_device_add(pdev);
|
|
if (ret) {
|
|
printk(KERN_ERR
|
|
"%s: platform_device_register failed!\n", __func__);
|
|
goto err_device_put;
|
|
}
|
|
|
|
return 0;
|
|
|
|
err_device_put:
|
|
platform_device_put(pdev);
|
|
return ret;
|
|
}
|
|
|
|
static int mipi_novatek_lcd_init(void)
|
|
{
|
|
#ifdef CONFIG_SPI_QUP
|
|
int ret;
|
|
ret = spi_register_driver(&panel_3d_spi_driver);
|
|
|
|
if (ret) {
|
|
pr_err("%s: spi register failed: rc=%d\n", __func__, ret);
|
|
platform_driver_unregister(&this_driver);
|
|
} else
|
|
pr_info("%s: SUCCESS (SPI)\n", __func__);
|
|
#endif
|
|
|
|
led_trigger_register_simple("bkl_trigger", &bkl_led_trigger);
|
|
pr_info("%s: SUCCESS (WLED TRIGGER)\n", __func__);
|
|
wled_trigger_initialized = 1;
|
|
|
|
mipi_dsi_buf_alloc(&novatek_tx_buf, DSI_BUF_SIZE);
|
|
mipi_dsi_buf_alloc(&novatek_rx_buf, DSI_BUF_SIZE);
|
|
|
|
return platform_driver_register(&this_driver);
|
|
}
|