123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746 |
- /* #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");
|