747 lines
16 KiB
C
747 lines
16 KiB
C
|
/* #define DEBUG */
|
||
|
|
||
|
#include <linux/module.h>
|
||
|
#include <linux/delay.h>
|
||
|
#include <linux/slab.h>
|
||
|
#include <linux/gpio.h>
|
||
|
#include <linux/spi/spi.h>
|
||
|
#include <linux/backlight.h>
|
||
|
#include <linux/fb.h>
|
||
|
|
||
|
#include <video/omapdss.h>
|
||
|
#include <video/omap-panel-n8x0.h>
|
||
|
|
||
|
#define BLIZZARD_REV_CODE 0x00
|
||
|
#define BLIZZARD_CONFIG 0x02
|
||
|
#define BLIZZARD_PLL_DIV 0x04
|
||
|
#define BLIZZARD_PLL_LOCK_RANGE 0x06
|
||
|
#define BLIZZARD_PLL_CLOCK_SYNTH_0 0x08
|
||
|
#define BLIZZARD_PLL_CLOCK_SYNTH_1 0x0a
|
||
|
#define BLIZZARD_PLL_MODE 0x0c
|
||
|
#define BLIZZARD_CLK_SRC 0x0e
|
||
|
#define BLIZZARD_MEM_BANK0_ACTIVATE 0x10
|
||
|
#define BLIZZARD_MEM_BANK0_STATUS 0x14
|
||
|
#define BLIZZARD_PANEL_CONFIGURATION 0x28
|
||
|
#define BLIZZARD_HDISP 0x2a
|
||
|
#define BLIZZARD_HNDP 0x2c
|
||
|
#define BLIZZARD_VDISP0 0x2e
|
||
|
#define BLIZZARD_VDISP1 0x30
|
||
|
#define BLIZZARD_VNDP 0x32
|
||
|
#define BLIZZARD_HSW 0x34
|
||
|
#define BLIZZARD_VSW 0x38
|
||
|
#define BLIZZARD_DISPLAY_MODE 0x68
|
||
|
#define BLIZZARD_INPUT_WIN_X_START_0 0x6c
|
||
|
#define BLIZZARD_DATA_SOURCE_SELECT 0x8e
|
||
|
#define BLIZZARD_DISP_MEM_DATA_PORT 0x90
|
||
|
#define BLIZZARD_DISP_MEM_READ_ADDR0 0x92
|
||
|
#define BLIZZARD_POWER_SAVE 0xE6
|
||
|
#define BLIZZARD_NDISP_CTRL_STATUS 0xE8
|
||
|
|
||
|
/* Data source select */
|
||
|
/* For S1D13745 */
|
||
|
#define BLIZZARD_SRC_WRITE_LCD_BACKGROUND 0x00
|
||
|
#define BLIZZARD_SRC_WRITE_LCD_DESTRUCTIVE 0x01
|
||
|
#define BLIZZARD_SRC_WRITE_OVERLAY_ENABLE 0x04
|
||
|
#define BLIZZARD_SRC_DISABLE_OVERLAY 0x05
|
||
|
/* For S1D13744 */
|
||
|
#define BLIZZARD_SRC_WRITE_LCD 0x00
|
||
|
#define BLIZZARD_SRC_BLT_LCD 0x06
|
||
|
|
||
|
#define BLIZZARD_COLOR_RGB565 0x01
|
||
|
#define BLIZZARD_COLOR_YUV420 0x09
|
||
|
|
||
|
#define BLIZZARD_VERSION_S1D13745 0x01 /* Hailstorm */
|
||
|
#define BLIZZARD_VERSION_S1D13744 0x02 /* Blizzard */
|
||
|
|
||
|
#define MIPID_CMD_READ_DISP_ID 0x04
|
||
|
#define MIPID_CMD_READ_RED 0x06
|
||
|
#define MIPID_CMD_READ_GREEN 0x07
|
||
|
#define MIPID_CMD_READ_BLUE 0x08
|
||
|
#define MIPID_CMD_READ_DISP_STATUS 0x09
|
||
|
#define MIPID_CMD_RDDSDR 0x0F
|
||
|
#define MIPID_CMD_SLEEP_IN 0x10
|
||
|
#define MIPID_CMD_SLEEP_OUT 0x11
|
||
|
#define MIPID_CMD_DISP_OFF 0x28
|
||
|
#define MIPID_CMD_DISP_ON 0x29
|
||
|
|
||
|
static struct panel_drv_data {
|
||
|
struct mutex lock;
|
||
|
|
||
|
struct omap_dss_device *dssdev;
|
||
|
struct spi_device *spidev;
|
||
|
struct backlight_device *bldev;
|
||
|
|
||
|
int blizzard_ver;
|
||
|
} s_drv_data;
|
||
|
|
||
|
|
||
|
static inline
|
||
|
struct panel_n8x0_data *get_board_data(const struct omap_dss_device *dssdev)
|
||
|
{
|
||
|
return dssdev->data;
|
||
|
}
|
||
|
|
||
|
static inline
|
||
|
struct panel_drv_data *get_drv_data(const struct omap_dss_device *dssdev)
|
||
|
{
|
||
|
return &s_drv_data;
|
||
|
}
|
||
|
|
||
|
|
||
|
static inline void blizzard_cmd(u8 cmd)
|
||
|
{
|
||
|
omap_rfbi_write_command(&cmd, 1);
|
||
|
}
|
||
|
|
||
|
static inline void blizzard_write(u8 cmd, const u8 *buf, int len)
|
||
|
{
|
||
|
omap_rfbi_write_command(&cmd, 1);
|
||
|
omap_rfbi_write_data(buf, len);
|
||
|
}
|
||
|
|
||
|
static inline void blizzard_read(u8 cmd, u8 *buf, int len)
|
||
|
{
|
||
|
omap_rfbi_write_command(&cmd, 1);
|
||
|
omap_rfbi_read_data(buf, len);
|
||
|
}
|
||
|
|
||
|
static u8 blizzard_read_reg(u8 cmd)
|
||
|
{
|
||
|
u8 data;
|
||
|
blizzard_read(cmd, &data, 1);
|
||
|
return data;
|
||
|
}
|
||
|
|
||
|
static void blizzard_ctrl_setup_update(struct omap_dss_device *dssdev,
|
||
|
int x, int y, int w, int h)
|
||
|
{
|
||
|
struct panel_drv_data *ddata = get_drv_data(dssdev);
|
||
|
u8 tmp[18];
|
||
|
int x_end, y_end;
|
||
|
|
||
|
x_end = x + w - 1;
|
||
|
y_end = y + h - 1;
|
||
|
|
||
|
tmp[0] = x;
|
||
|
tmp[1] = x >> 8;
|
||
|
tmp[2] = y;
|
||
|
tmp[3] = y >> 8;
|
||
|
tmp[4] = x_end;
|
||
|
tmp[5] = x_end >> 8;
|
||
|
tmp[6] = y_end;
|
||
|
tmp[7] = y_end >> 8;
|
||
|
|
||
|
/* scaling? */
|
||
|
tmp[8] = x;
|
||
|
tmp[9] = x >> 8;
|
||
|
tmp[10] = y;
|
||
|
tmp[11] = y >> 8;
|
||
|
tmp[12] = x_end;
|
||
|
tmp[13] = x_end >> 8;
|
||
|
tmp[14] = y_end;
|
||
|
tmp[15] = y_end >> 8;
|
||
|
|
||
|
tmp[16] = BLIZZARD_COLOR_RGB565;
|
||
|
|
||
|
if (ddata->blizzard_ver == BLIZZARD_VERSION_S1D13745)
|
||
|
tmp[17] = BLIZZARD_SRC_WRITE_LCD_BACKGROUND;
|
||
|
else
|
||
|
tmp[17] = ddata->blizzard_ver == BLIZZARD_VERSION_S1D13744 ?
|
||
|
BLIZZARD_SRC_WRITE_LCD :
|
||
|
BLIZZARD_SRC_WRITE_LCD_DESTRUCTIVE;
|
||
|
|
||
|
omap_rfbi_configure(dssdev, 16, 8);
|
||
|
|
||
|
blizzard_write(BLIZZARD_INPUT_WIN_X_START_0, tmp, 18);
|
||
|
|
||
|
omap_rfbi_configure(dssdev, 16, 16);
|
||
|
}
|
||
|
|
||
|
static void mipid_transfer(struct spi_device *spi, int cmd, const u8 *wbuf,
|
||
|
int wlen, u8 *rbuf, int rlen)
|
||
|
{
|
||
|
struct spi_message m;
|
||
|
struct spi_transfer *x, xfer[4];
|
||
|
u16 w;
|
||
|
int r;
|
||
|
|
||
|
spi_message_init(&m);
|
||
|
|
||
|
memset(xfer, 0, sizeof(xfer));
|
||
|
x = &xfer[0];
|
||
|
|
||
|
cmd &= 0xff;
|
||
|
x->tx_buf = &cmd;
|
||
|
x->bits_per_word = 9;
|
||
|
x->len = 2;
|
||
|
spi_message_add_tail(x, &m);
|
||
|
|
||
|
if (wlen) {
|
||
|
x++;
|
||
|
x->tx_buf = wbuf;
|
||
|
x->len = wlen;
|
||
|
x->bits_per_word = 9;
|
||
|
spi_message_add_tail(x, &m);
|
||
|
}
|
||
|
|
||
|
if (rlen) {
|
||
|
x++;
|
||
|
x->rx_buf = &w;
|
||
|
x->len = 1;
|
||
|
spi_message_add_tail(x, &m);
|
||
|
|
||
|
if (rlen > 1) {
|
||
|
/* Arrange for the extra clock before the first
|
||
|
* data bit.
|
||
|
*/
|
||
|
x->bits_per_word = 9;
|
||
|
x->len = 2;
|
||
|
|
||
|
x++;
|
||
|
x->rx_buf = &rbuf[1];
|
||
|
x->len = rlen - 1;
|
||
|
spi_message_add_tail(x, &m);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
r = spi_sync(spi, &m);
|
||
|
if (r < 0)
|
||
|
dev_dbg(&spi->dev, "spi_sync %d\n", r);
|
||
|
|
||
|
if (rlen)
|
||
|
rbuf[0] = w & 0xff;
|
||
|
}
|
||
|
|
||
|
static inline void mipid_cmd(struct spi_device *spi, int cmd)
|
||
|
{
|
||
|
mipid_transfer(spi, cmd, NULL, 0, NULL, 0);
|
||
|
}
|
||
|
|
||
|
static inline void mipid_write(struct spi_device *spi,
|
||
|
int reg, const u8 *buf, int len)
|
||
|
{
|
||
|
mipid_transfer(spi, reg, buf, len, NULL, 0);
|
||
|
}
|
||
|
|
||
|
static inline void mipid_read(struct spi_device *spi,
|
||
|
int reg, u8 *buf, int len)
|
||
|
{
|
||
|
mipid_transfer(spi, reg, NULL, 0, buf, len);
|
||
|
}
|
||
|
|
||
|
static void set_data_lines(struct spi_device *spi, int data_lines)
|
||
|
{
|
||
|
u16 par;
|
||
|
|
||
|
switch (data_lines) {
|
||
|
case 16:
|
||
|
par = 0x150;
|
||
|
break;
|
||
|
case 18:
|
||
|
par = 0x160;
|
||
|
break;
|
||
|
case 24:
|
||
|
par = 0x170;
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
mipid_write(spi, 0x3a, (u8 *)&par, 2);
|
||
|
}
|
||
|
|
||
|
static void send_init_string(struct spi_device *spi)
|
||
|
{
|
||
|
u16 initpar[] = { 0x0102, 0x0100, 0x0100 };
|
||
|
mipid_write(spi, 0xc2, (u8 *)initpar, sizeof(initpar));
|
||
|
}
|
||
|
|
||
|
static void send_display_on(struct spi_device *spi)
|
||
|
{
|
||
|
mipid_cmd(spi, MIPID_CMD_DISP_ON);
|
||
|
}
|
||
|
|
||
|
static void send_display_off(struct spi_device *spi)
|
||
|
{
|
||
|
mipid_cmd(spi, MIPID_CMD_DISP_OFF);
|
||
|
}
|
||
|
|
||
|
static void send_sleep_out(struct spi_device *spi)
|
||
|
{
|
||
|
mipid_cmd(spi, MIPID_CMD_SLEEP_OUT);
|
||
|
msleep(120);
|
||
|
}
|
||
|
|
||
|
static void send_sleep_in(struct spi_device *spi)
|
||
|
{
|
||
|
mipid_cmd(spi, MIPID_CMD_SLEEP_IN);
|
||
|
msleep(50);
|
||
|
}
|
||
|
|
||
|
static int n8x0_panel_power_on(struct omap_dss_device *dssdev)
|
||
|
{
|
||
|
int r;
|
||
|
struct panel_n8x0_data *bdata = get_board_data(dssdev);
|
||
|
struct panel_drv_data *ddata = get_drv_data(dssdev);
|
||
|
struct spi_device *spi = ddata->spidev;
|
||
|
u8 rev, conf;
|
||
|
u8 display_id[3];
|
||
|
const char *panel_name;
|
||
|
|
||
|
if (dssdev->state == OMAP_DSS_DISPLAY_ACTIVE)
|
||
|
return 0;
|
||
|
|
||
|
gpio_direction_output(bdata->ctrl_pwrdown, 1);
|
||
|
|
||
|
if (bdata->platform_enable) {
|
||
|
r = bdata->platform_enable(dssdev);
|
||
|
if (r)
|
||
|
goto err_plat_en;
|
||
|
}
|
||
|
|
||
|
r = omapdss_rfbi_display_enable(dssdev);
|
||
|
if (r)
|
||
|
goto err_rfbi_en;
|
||
|
|
||
|
rev = blizzard_read_reg(BLIZZARD_REV_CODE);
|
||
|
conf = blizzard_read_reg(BLIZZARD_CONFIG);
|
||
|
|
||
|
switch (rev & 0xfc) {
|
||
|
case 0x9c:
|
||
|
ddata->blizzard_ver = BLIZZARD_VERSION_S1D13744;
|
||
|
dev_info(&dssdev->dev, "s1d13744 LCD controller rev %d "
|
||
|
"initialized (CNF pins %x)\n", rev & 0x03, conf & 0x07);
|
||
|
break;
|
||
|
case 0xa4:
|
||
|
ddata->blizzard_ver = BLIZZARD_VERSION_S1D13745;
|
||
|
dev_info(&dssdev->dev, "s1d13745 LCD controller rev %d "
|
||
|
"initialized (CNF pins %x)\n", rev & 0x03, conf & 0x07);
|
||
|
break;
|
||
|
default:
|
||
|
dev_err(&dssdev->dev, "invalid s1d1374x revision %02x\n", rev);
|
||
|
r = -ENODEV;
|
||
|
goto err_inv_chip;
|
||
|
}
|
||
|
|
||
|
/* panel */
|
||
|
|
||
|
gpio_direction_output(bdata->panel_reset, 1);
|
||
|
|
||
|
mipid_read(spi, MIPID_CMD_READ_DISP_ID, display_id, 3);
|
||
|
dev_dbg(&spi->dev, "MIPI display ID: %02x%02x%02x\n",
|
||
|
display_id[0], display_id[1], display_id[2]);
|
||
|
|
||
|
switch (display_id[0]) {
|
||
|
case 0x45:
|
||
|
panel_name = "lph8923";
|
||
|
break;
|
||
|
case 0x83:
|
||
|
panel_name = "ls041y3";
|
||
|
break;
|
||
|
default:
|
||
|
dev_err(&dssdev->dev, "invalid display ID 0x%x\n",
|
||
|
display_id[0]);
|
||
|
r = -ENODEV;
|
||
|
goto err_inv_panel;
|
||
|
}
|
||
|
|
||
|
dev_info(&dssdev->dev, "%s rev %02x LCD detected\n",
|
||
|
panel_name, display_id[1]);
|
||
|
|
||
|
send_sleep_out(spi);
|
||
|
send_init_string(spi);
|
||
|
set_data_lines(spi, 24);
|
||
|
send_display_on(spi);
|
||
|
|
||
|
return 0;
|
||
|
|
||
|
err_inv_panel:
|
||
|
/*
|
||
|
* HACK: we should turn off the panel here, but there is some problem
|
||
|
* with the initialization sequence, and we fail to init the panel if we
|
||
|
* have turned it off
|
||
|
*/
|
||
|
/* gpio_direction_output(bdata->panel_reset, 0); */
|
||
|
err_inv_chip:
|
||
|
omapdss_rfbi_display_disable(dssdev);
|
||
|
err_rfbi_en:
|
||
|
if (bdata->platform_disable)
|
||
|
bdata->platform_disable(dssdev);
|
||
|
err_plat_en:
|
||
|
gpio_direction_output(bdata->ctrl_pwrdown, 0);
|
||
|
return r;
|
||
|
}
|
||
|
|
||
|
static void n8x0_panel_power_off(struct omap_dss_device *dssdev)
|
||
|
{
|
||
|
struct panel_n8x0_data *bdata = get_board_data(dssdev);
|
||
|
struct panel_drv_data *ddata = get_drv_data(dssdev);
|
||
|
struct spi_device *spi = ddata->spidev;
|
||
|
|
||
|
if (dssdev->state != OMAP_DSS_DISPLAY_ACTIVE)
|
||
|
return;
|
||
|
|
||
|
send_display_off(spi);
|
||
|
send_sleep_in(spi);
|
||
|
|
||
|
if (bdata->platform_disable)
|
||
|
bdata->platform_disable(dssdev);
|
||
|
|
||
|
/*
|
||
|
* HACK: we should turn off the panel here, but there is some problem
|
||
|
* with the initialization sequence, and we fail to init the panel if we
|
||
|
* have turned it off
|
||
|
*/
|
||
|
/* gpio_direction_output(bdata->panel_reset, 0); */
|
||
|
gpio_direction_output(bdata->ctrl_pwrdown, 0);
|
||
|
omapdss_rfbi_display_disable(dssdev);
|
||
|
}
|
||
|
|
||
|
static const struct rfbi_timings n8x0_panel_timings = {
|
||
|
.cs_on_time = 0,
|
||
|
|
||
|
.we_on_time = 9000,
|
||
|
.we_off_time = 18000,
|
||
|
.we_cycle_time = 36000,
|
||
|
|
||
|
.re_on_time = 9000,
|
||
|
.re_off_time = 27000,
|
||
|
.re_cycle_time = 36000,
|
||
|
|
||
|
.access_time = 27000,
|
||
|
.cs_off_time = 36000,
|
||
|
|
||
|
.cs_pulse_width = 0,
|
||
|
};
|
||
|
|
||
|
static int n8x0_bl_update_status(struct backlight_device *dev)
|
||
|
{
|
||
|
struct omap_dss_device *dssdev = dev_get_drvdata(&dev->dev);
|
||
|
struct panel_n8x0_data *bdata = get_board_data(dssdev);
|
||
|
struct panel_drv_data *ddata = get_drv_data(dssdev);
|
||
|
int r;
|
||
|
int level;
|
||
|
|
||
|
mutex_lock(&ddata->lock);
|
||
|
|
||
|
if (dev->props.fb_blank == FB_BLANK_UNBLANK &&
|
||
|
dev->props.power == FB_BLANK_UNBLANK)
|
||
|
level = dev->props.brightness;
|
||
|
else
|
||
|
level = 0;
|
||
|
|
||
|
dev_dbg(&dssdev->dev, "update brightness to %d\n", level);
|
||
|
|
||
|
if (!bdata->set_backlight)
|
||
|
r = -EINVAL;
|
||
|
else
|
||
|
r = bdata->set_backlight(dssdev, level);
|
||
|
|
||
|
mutex_unlock(&ddata->lock);
|
||
|
|
||
|
return r;
|
||
|
}
|
||
|
|
||
|
static int n8x0_bl_get_intensity(struct backlight_device *dev)
|
||
|
{
|
||
|
if (dev->props.fb_blank == FB_BLANK_UNBLANK &&
|
||
|
dev->props.power == FB_BLANK_UNBLANK)
|
||
|
return dev->props.brightness;
|
||
|
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
static const struct backlight_ops n8x0_bl_ops = {
|
||
|
.get_brightness = n8x0_bl_get_intensity,
|
||
|
.update_status = n8x0_bl_update_status,
|
||
|
};
|
||
|
|
||
|
static int n8x0_panel_probe(struct omap_dss_device *dssdev)
|
||
|
{
|
||
|
struct panel_n8x0_data *bdata = get_board_data(dssdev);
|
||
|
struct panel_drv_data *ddata;
|
||
|
struct backlight_device *bldev;
|
||
|
struct backlight_properties props;
|
||
|
int r;
|
||
|
|
||
|
dev_dbg(&dssdev->dev, "probe\n");
|
||
|
|
||
|
if (!bdata)
|
||
|
return -EINVAL;
|
||
|
|
||
|
s_drv_data.dssdev = dssdev;
|
||
|
|
||
|
ddata = &s_drv_data;
|
||
|
|
||
|
mutex_init(&ddata->lock);
|
||
|
|
||
|
dssdev->panel.config = OMAP_DSS_LCD_TFT;
|
||
|
dssdev->panel.timings.x_res = 800;
|
||
|
dssdev->panel.timings.y_res = 480;
|
||
|
dssdev->ctrl.pixel_size = 16;
|
||
|
dssdev->ctrl.rfbi_timings = n8x0_panel_timings;
|
||
|
|
||
|
memset(&props, 0, sizeof(props));
|
||
|
props.max_brightness = 127;
|
||
|
props.type = BACKLIGHT_PLATFORM;
|
||
|
bldev = backlight_device_register(dev_name(&dssdev->dev), &dssdev->dev,
|
||
|
dssdev, &n8x0_bl_ops, &props);
|
||
|
if (IS_ERR(bldev)) {
|
||
|
r = PTR_ERR(bldev);
|
||
|
dev_err(&dssdev->dev, "register backlight failed\n");
|
||
|
return r;
|
||
|
}
|
||
|
|
||
|
ddata->bldev = bldev;
|
||
|
|
||
|
bldev->props.fb_blank = FB_BLANK_UNBLANK;
|
||
|
bldev->props.power = FB_BLANK_UNBLANK;
|
||
|
bldev->props.brightness = 127;
|
||
|
|
||
|
n8x0_bl_update_status(bldev);
|
||
|
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
static void n8x0_panel_remove(struct omap_dss_device *dssdev)
|
||
|
{
|
||
|
struct panel_drv_data *ddata = get_drv_data(dssdev);
|
||
|
struct backlight_device *bldev;
|
||
|
|
||
|
dev_dbg(&dssdev->dev, "remove\n");
|
||
|
|
||
|
bldev = ddata->bldev;
|
||
|
bldev->props.power = FB_BLANK_POWERDOWN;
|
||
|
n8x0_bl_update_status(bldev);
|
||
|
backlight_device_unregister(bldev);
|
||
|
|
||
|
dev_set_drvdata(&dssdev->dev, NULL);
|
||
|
}
|
||
|
|
||
|
static int n8x0_panel_enable(struct omap_dss_device *dssdev)
|
||
|
{
|
||
|
struct panel_drv_data *ddata = get_drv_data(dssdev);
|
||
|
int r;
|
||
|
|
||
|
dev_dbg(&dssdev->dev, "enable\n");
|
||
|
|
||
|
mutex_lock(&ddata->lock);
|
||
|
|
||
|
rfbi_bus_lock();
|
||
|
|
||
|
r = n8x0_panel_power_on(dssdev);
|
||
|
|
||
|
rfbi_bus_unlock();
|
||
|
|
||
|
if (r) {
|
||
|
mutex_unlock(&ddata->lock);
|
||
|
return r;
|
||
|
}
|
||
|
|
||
|
dssdev->state = OMAP_DSS_DISPLAY_ACTIVE;
|
||
|
|
||
|
mutex_unlock(&ddata->lock);
|
||
|
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
static void n8x0_panel_disable(struct omap_dss_device *dssdev)
|
||
|
{
|
||
|
struct panel_drv_data *ddata = get_drv_data(dssdev);
|
||
|
|
||
|
dev_dbg(&dssdev->dev, "disable\n");
|
||
|
|
||
|
mutex_lock(&ddata->lock);
|
||
|
|
||
|
rfbi_bus_lock();
|
||
|
|
||
|
n8x0_panel_power_off(dssdev);
|
||
|
|
||
|
rfbi_bus_unlock();
|
||
|
|
||
|
dssdev->state = OMAP_DSS_DISPLAY_DISABLED;
|
||
|
|
||
|
mutex_unlock(&ddata->lock);
|
||
|
}
|
||
|
|
||
|
static int n8x0_panel_suspend(struct omap_dss_device *dssdev)
|
||
|
{
|
||
|
struct panel_drv_data *ddata = get_drv_data(dssdev);
|
||
|
|
||
|
dev_dbg(&dssdev->dev, "suspend\n");
|
||
|
|
||
|
mutex_lock(&ddata->lock);
|
||
|
|
||
|
rfbi_bus_lock();
|
||
|
|
||
|
n8x0_panel_power_off(dssdev);
|
||
|
|
||
|
rfbi_bus_unlock();
|
||
|
|
||
|
dssdev->state = OMAP_DSS_DISPLAY_SUSPENDED;
|
||
|
|
||
|
mutex_unlock(&ddata->lock);
|
||
|
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
static int n8x0_panel_resume(struct omap_dss_device *dssdev)
|
||
|
{
|
||
|
struct panel_drv_data *ddata = get_drv_data(dssdev);
|
||
|
int r;
|
||
|
|
||
|
dev_dbg(&dssdev->dev, "resume\n");
|
||
|
|
||
|
mutex_lock(&ddata->lock);
|
||
|
|
||
|
rfbi_bus_lock();
|
||
|
|
||
|
r = n8x0_panel_power_on(dssdev);
|
||
|
|
||
|
rfbi_bus_unlock();
|
||
|
|
||
|
if (r) {
|
||
|
mutex_unlock(&ddata->lock);
|
||
|
return r;
|
||
|
}
|
||
|
|
||
|
dssdev->state = OMAP_DSS_DISPLAY_ACTIVE;
|
||
|
|
||
|
mutex_unlock(&ddata->lock);
|
||
|
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
static void n8x0_panel_get_timings(struct omap_dss_device *dssdev,
|
||
|
struct omap_video_timings *timings)
|
||
|
{
|
||
|
*timings = dssdev->panel.timings;
|
||
|
}
|
||
|
|
||
|
static void n8x0_panel_get_resolution(struct omap_dss_device *dssdev,
|
||
|
u16 *xres, u16 *yres)
|
||
|
{
|
||
|
*xres = dssdev->panel.timings.x_res;
|
||
|
*yres = dssdev->panel.timings.y_res;
|
||
|
}
|
||
|
|
||
|
static void update_done(void *data)
|
||
|
{
|
||
|
rfbi_bus_unlock();
|
||
|
}
|
||
|
|
||
|
static int n8x0_panel_update(struct omap_dss_device *dssdev,
|
||
|
u16 x, u16 y, u16 w, u16 h)
|
||
|
{
|
||
|
struct panel_drv_data *ddata = get_drv_data(dssdev);
|
||
|
|
||
|
dev_dbg(&dssdev->dev, "update\n");
|
||
|
|
||
|
mutex_lock(&ddata->lock);
|
||
|
rfbi_bus_lock();
|
||
|
|
||
|
omap_rfbi_prepare_update(dssdev, &x, &y, &w, &h);
|
||
|
|
||
|
blizzard_ctrl_setup_update(dssdev, x, y, w, h);
|
||
|
|
||
|
omap_rfbi_update(dssdev, x, y, w, h, update_done, NULL);
|
||
|
|
||
|
mutex_unlock(&ddata->lock);
|
||
|
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
static int n8x0_panel_sync(struct omap_dss_device *dssdev)
|
||
|
{
|
||
|
struct panel_drv_data *ddata = get_drv_data(dssdev);
|
||
|
|
||
|
dev_dbg(&dssdev->dev, "sync\n");
|
||
|
|
||
|
mutex_lock(&ddata->lock);
|
||
|
rfbi_bus_lock();
|
||
|
rfbi_bus_unlock();
|
||
|
mutex_unlock(&ddata->lock);
|
||
|
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
static struct omap_dss_driver n8x0_panel_driver = {
|
||
|
.probe = n8x0_panel_probe,
|
||
|
.remove = n8x0_panel_remove,
|
||
|
|
||
|
.enable = n8x0_panel_enable,
|
||
|
.disable = n8x0_panel_disable,
|
||
|
.suspend = n8x0_panel_suspend,
|
||
|
.resume = n8x0_panel_resume,
|
||
|
|
||
|
.update = n8x0_panel_update,
|
||
|
.sync = n8x0_panel_sync,
|
||
|
|
||
|
.get_resolution = n8x0_panel_get_resolution,
|
||
|
.get_recommended_bpp = omapdss_default_get_recommended_bpp,
|
||
|
|
||
|
.get_timings = n8x0_panel_get_timings,
|
||
|
|
||
|
.driver = {
|
||
|
.name = "n8x0_panel",
|
||
|
.owner = THIS_MODULE,
|
||
|
},
|
||
|
};
|
||
|
|
||
|
/* PANEL */
|
||
|
|
||
|
static int mipid_spi_probe(struct spi_device *spi)
|
||
|
{
|
||
|
dev_dbg(&spi->dev, "mipid_spi_probe\n");
|
||
|
|
||
|
spi->mode = SPI_MODE_0;
|
||
|
|
||
|
s_drv_data.spidev = spi;
|
||
|
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
static int mipid_spi_remove(struct spi_device *spi)
|
||
|
{
|
||
|
dev_dbg(&spi->dev, "mipid_spi_remove\n");
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
static struct spi_driver mipid_spi_driver = {
|
||
|
.driver = {
|
||
|
.name = "lcd_mipid",
|
||
|
.owner = THIS_MODULE,
|
||
|
},
|
||
|
.probe = mipid_spi_probe,
|
||
|
.remove = __devexit_p(mipid_spi_remove),
|
||
|
};
|
||
|
|
||
|
static int __init n8x0_panel_drv_init(void)
|
||
|
{
|
||
|
int r;
|
||
|
|
||
|
r = spi_register_driver(&mipid_spi_driver);
|
||
|
if (r) {
|
||
|
pr_err("n8x0_panel: spi driver registration failed\n");
|
||
|
return r;
|
||
|
}
|
||
|
|
||
|
r = omap_dss_register_driver(&n8x0_panel_driver);
|
||
|
if (r) {
|
||
|
pr_err("n8x0_panel: dss driver registration failed\n");
|
||
|
spi_unregister_driver(&mipid_spi_driver);
|
||
|
return r;
|
||
|
}
|
||
|
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
static void __exit n8x0_panel_drv_exit(void)
|
||
|
{
|
||
|
spi_unregister_driver(&mipid_spi_driver);
|
||
|
|
||
|
omap_dss_unregister_driver(&n8x0_panel_driver);
|
||
|
}
|
||
|
|
||
|
module_init(n8x0_panel_drv_init);
|
||
|
module_exit(n8x0_panel_drv_exit);
|
||
|
MODULE_LICENSE("GPL");
|