From: Tomi Valkeinen <tomi.valkeinen@nokia.com>
To: linux-fbdev-devel@lists.sourceforge.net
Cc: linux-omap@vger.kernel.org
Subject: [PATCH 12/12] DSS: Hacked N810 support
Date: Mon, 12 Jan 2009 13:48:38 +0200 [thread overview]
Message-ID: <20090112114838.1003.90392.stgit@tubuntu> (raw)
In-Reply-To: <20090112114718.1003.23643.stgit@tubuntu>
Signed-off-by: Tomi Valkeinen <tomi.valkeinen@nokia.com>
---
arch/arm/mach-omap2/board-n800.c | 214 ++++++++++++++---
drivers/video/omap2/Kconfig | 10 +
drivers/video/omap2/Makefile | 3
drivers/video/omap2/ctrl-blizzard.c | 279 ++++++++++++++++++++++
drivers/video/omap2/panel-n800.c | 437 +++++++++++++++++++++++++++++++++++
5 files changed, 905 insertions(+), 38 deletions(-)
create mode 100644 drivers/video/omap2/ctrl-blizzard.c
create mode 100644 drivers/video/omap2/panel-n800.c
diff --git a/arch/arm/mach-omap2/board-n800.c b/arch/arm/mach-omap2/board-n800.c
index b38b295..ffa5aad 100644
--- a/arch/arm/mach-omap2/board-n800.c
+++ b/arch/arm/mach-omap2/board-n800.c
@@ -40,6 +40,7 @@
#include <mach/gpio-switch.h>
#include <mach/omapfb.h>
#include <mach/blizzard.h>
+#include <mach/display.h>
#include <../drivers/cbus/tahvo.h>
#include <../drivers/media/video/tcm825x.h>
@@ -156,23 +157,175 @@ static struct omap_uart_config n800_uart_config __initdata = {
#include "../../../drivers/cbus/retu.h"
-static struct omap_fbmem_config n800_fbmem0_config __initdata = {
- .size = 752 * 1024,
+static struct omap_tmp105_config n800_tmp105_config __initdata = {
+ .tmp105_irq_pin = 125,
+ .set_power = n800_tmp105_set_power,
};
-static struct omap_fbmem_config n800_fbmem1_config __initdata = {
- .size = 752 * 1024,
-};
-static struct omap_fbmem_config n800_fbmem2_config __initdata = {
- .size = 752 * 1024,
+
+
+/* DISPLAY */
+static struct {
+ struct clk *sys_ck;
+} blizzard;
+
+static int blizzard_get_clocks(void)
+{
+ blizzard.sys_ck = clk_get(0, "osc_ck");
+ if (IS_ERR(blizzard.sys_ck)) {
+ printk(KERN_ERR "can't get Blizzard clock\n");
+ return PTR_ERR(blizzard.sys_ck);
+ }
+ return 0;
+}
+
+static unsigned long blizzard_get_clock_rate(void)
+{
+ return clk_get_rate(blizzard.sys_ck);
+}
+
+static int n800_pn800_enable(struct omap_display *display)
+{
+ if (display->hw_config.panel_reset_gpio != -1) {
+ printk("enabling panel gpio\n");
+ gpio_direction_output(display->hw_config.panel_reset_gpio, 1);
+ }
+
+ return 0;
+}
+
+static void n800_pn800_disable(struct omap_display *display)
+{
+ if (display->hw_config.panel_reset_gpio != -1) {
+ printk("disabling panel gpio\n");
+ gpio_direction_output(display->hw_config.panel_reset_gpio, 0);
+ msleep(120);
+ }
+}
+
+static int n800_blizzard_enable(struct omap_display *display)
+{
+ printk("enabling bliz powers\n");
+
+ /* Vcore to 1.475V */
+ tahvo_set_clear_reg_bits(0x07, 0, 0xf);
+ msleep(10);
+
+ clk_enable(blizzard.sys_ck);
+
+ if (display->hw_config.ctrl_reset_gpio != -1)
+ gpio_direction_output(display->hw_config.ctrl_reset_gpio, 1);
+
+ printk("osc_ck %lu\n", blizzard_get_clock_rate());
+
+ return 0;
+}
+
+static void n800_blizzard_disable(struct omap_display *display)
+{
+ printk("disabling bliz powers\n");
+
+ if (display->hw_config.ctrl_reset_gpio != -1)
+ gpio_direction_output(display->hw_config.ctrl_reset_gpio, 0);
+
+ clk_disable(blizzard.sys_ck);
+
+ /* Vcore to 1.005V */
+ tahvo_set_clear_reg_bits(0x07, 0xf, 0);
+}
+
+static int n800_set_backlight_level(struct omap_display *display, int level)
+{
+ return 0;
+}
+
+static struct omap_display_data n800_dsi_display_data = {
+ .type = OMAP_DISPLAY_TYPE_DBI,
+ .name = "lcd",
+ .ctrl_name = "ctrl-blizzard",
+ .panel_name = "panel-pn800",
+ .panel_reset_gpio = -1,
+ .ctrl_reset_gpio = N800_BLIZZARD_POWERDOWN_GPIO,
+ .panel_enable = n800_pn800_enable,
+ .panel_disable = n800_pn800_disable,
+ .ctrl_enable = n800_blizzard_enable,
+ .ctrl_disable = n800_blizzard_disable,
+ .set_backlight = n800_set_backlight_level,
+ .u.rfbi = {
+ .channel = 0,
+ /* 8 for cmd mode, 16 for pixel data. ctrl-blizzard handles switching */
+ .data_lines = 8,
+ },
+ .priv = 0, // XXX used for panel datalines
+};
+static struct omap_dss_platform_data n800_dss_data = {
+ .num_displays = 1,
+ .displays = {
+ &n800_dsi_display_data,
+ },
};
-static struct omap_tmp105_config n800_tmp105_config __initdata = {
- .tmp105_irq_pin = 125,
- .set_power = n800_tmp105_set_power,
+static struct platform_device n800_dss_device = {
+ .name = "omap-dss",
+ .id = -1,
+ .dev = {
+ .platform_data = &n800_dss_data,
+ },
};
+static void __init n800_display_init(void)
+{
+ int r;
+ const struct omap_lcd_config *conf;
+
+ conf = omap_get_config(OMAP_TAG_LCD, struct omap_lcd_config);
+ if (conf != NULL) {
+ n800_dsi_display_data.panel_reset_gpio = conf->nreset_gpio;
+ n800_dsi_display_data.priv = (void*)(u32)conf->data_lines; // XXX
+ //printk("\n\nTULI %d\n\n", conf->data_lines);
+ } else {
+ printk("\n\nEI TULLU MIOTÄÄÄ\n\n");
+ }
+
+ blizzard_get_clocks();
+ clk_enable(blizzard.sys_ck); // XXX always enable
+
+ //omapfb_set_ctrl_platform_data(&n800_blizzard_data);
+ //
+ if (n800_dsi_display_data.ctrl_reset_gpio != -1) {
+ r = gpio_request(n800_dsi_display_data.ctrl_reset_gpio,
+ "Blizzard pd");
+ if (r < 0) {
+ n800_dsi_display_data.ctrl_reset_gpio = -1;
+ printk(KERN_ERR "Unable to get Blizzard GPIO\n");
+ } else {
+ gpio_direction_output(n800_dsi_display_data.ctrl_reset_gpio,
+ 1);
+ // XXX always enable
+ }
+ }
+
+ if (n800_dsi_display_data.panel_reset_gpio != -1) {
+ r = gpio_request(n800_dsi_display_data.panel_reset_gpio,
+ "panel reset");
+ if (r < 0) {
+ n800_dsi_display_data.panel_reset_gpio = -1;
+ printk(KERN_ERR "Unable to get pn800 GPIO\n");
+ } else {
+ gpio_direction_output(n800_dsi_display_data.panel_reset_gpio,
+ 1);
+ // XXX always enable
+ }
+ }
+}
+
+/* DISPLAY END */
+
+
+
+
+
static void mipid_shutdown(struct mipid_platform_data *pdata)
{
if (pdata->nreset_gpio != -1) {
@@ -186,6 +339,7 @@ static struct mipid_platform_data n800_mipid_platform_data = {
.shutdown = mipid_shutdown,
};
+#if 0
static void __init mipid_dev_init(void)
{
const struct omap_lcd_config *conf;
@@ -196,26 +350,9 @@ static void __init mipid_dev_init(void)
n800_mipid_platform_data.data_lines = conf->data_lines;
}
}
+#endif
-static struct {
- struct clk *sys_ck;
-} blizzard;
-
-static int blizzard_get_clocks(void)
-{
- blizzard.sys_ck = clk_get(0, "osc_ck");
- if (IS_ERR(blizzard.sys_ck)) {
- printk(KERN_ERR "can't get Blizzard clock\n");
- return PTR_ERR(blizzard.sys_ck);
- }
- return 0;
-}
-
-static unsigned long blizzard_get_clock_rate(struct device *dev)
-{
- return clk_get_rate(blizzard.sys_ck);
-}
-
+#if 0
static void blizzard_enable_clocks(int enable)
{
if (enable)
@@ -260,14 +397,12 @@ static void __init blizzard_dev_init(void)
gpio_direction_output(N800_BLIZZARD_POWERDOWN_GPIO, 1);
blizzard_get_clocks();
- omapfb_set_ctrl_platform_data(&n800_blizzard_data);
+ //omapfb_set_ctrl_platform_data(&n800_blizzard_data);
}
+#endif
static struct omap_board_config_kernel n800_config[] __initdata = {
{ OMAP_TAG_UART, &n800_uart_config },
- { OMAP_TAG_FBMEM, &n800_fbmem0_config },
- { OMAP_TAG_FBMEM, &n800_fbmem1_config },
- { OMAP_TAG_FBMEM, &n800_fbmem2_config },
{ OMAP_TAG_TMP105, &n800_tmp105_config },
};
@@ -374,7 +509,7 @@ static struct omap2_mcspi_device_config tsc2005_mcspi_config = {
static struct spi_board_info n800_spi_board_info[] __initdata = {
{
- .modalias = "lcd_mipid",
+ .modalias = "panel-n800",
.bus_num = 1,
.chip_select = 1,
.max_speed_hz = 4000000,
@@ -399,7 +534,7 @@ static struct spi_board_info n800_spi_board_info[] __initdata = {
static struct spi_board_info n810_spi_board_info[] __initdata = {
{
- .modalias = "lcd_mipid",
+ .modalias = "panel-n800",
.bus_num = 1,
.chip_select = 1,
.max_speed_hz = 4000000,
@@ -567,6 +702,7 @@ static struct platform_device *n800_devices[] __initdata = {
#if defined(CONFIG_CBUS_RETU) && defined(CONFIG_LEDS_OMAP_PWM)
&n800_keypad_led_device,
#endif
+ &n800_dss_device,
};
#ifdef CONFIG_MENELAUS
@@ -689,9 +825,10 @@ void __init nokia_n800_common_init(void)
if (machine_is_nokia_n810())
i2c_register_board_info(2, n810_i2c_board_info_2,
ARRAY_SIZE(n810_i2c_board_info_2));
-
- mipid_dev_init();
- blizzard_dev_init();
+
+ //mipid_dev_init();
+ //blizzard_dev_init();
+ n800_display_init();
}
static void __init nokia_n800_init(void)
@@ -712,6 +849,7 @@ void __init nokia_n800_map_io(void)
omap_board_config_size = ARRAY_SIZE(n800_config);
omap2_set_globals_242x();
+ omap2_set_sdram_vram(800 * 480 * 2 * 3, 0);
omap2_map_common_io();
}
diff --git a/drivers/video/omap2/Kconfig b/drivers/video/omap2/Kconfig
index b54c955..4e9211e 100644
--- a/drivers/video/omap2/Kconfig
+++ b/drivers/video/omap2/Kconfig
@@ -49,4 +49,14 @@ config PANEL_SHARP_LS037V7DW01
help
LCD Panel used in TI's SDP3430 and EVM boards
+config PANEL_N800
+ tristate "panel n800"
+ help
+ N800 LCD
+
+config CTRL_BLIZZARD
+ tristate "blizzard ctrl"
+ help
+ Blizzard Ctrl
+
endmenu
diff --git a/drivers/video/omap2/Makefile b/drivers/video/omap2/Makefile
index fe6858e..7727f9c 100644
--- a/drivers/video/omap2/Makefile
+++ b/drivers/video/omap2/Makefile
@@ -3,3 +3,6 @@ omapfb-y := omapfb-main.o omapfb-sysfs.o omapfb-ioctl.o
obj-$(CONFIG_PANEL_GENERIC) += panel-generic.o
obj-$(CONFIG_PANEL_SHARP_LS037V7DW01) += panel-sharp-ls037v7dw01.o
+
+obj-$(CONFIG_CTRL_BLIZZARD) += ctrl-blizzard.o
+obj-$(CONFIG_PANEL_N800) += panel-n800.o
diff --git a/drivers/video/omap2/ctrl-blizzard.c b/drivers/video/omap2/ctrl-blizzard.c
new file mode 100644
index 0000000..e1e5569
--- /dev/null
+++ b/drivers/video/omap2/ctrl-blizzard.c
@@ -0,0 +1,279 @@
+
+//#define DEBUG
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/clk.h>
+#include <linux/delay.h>
+#include <linux/err.h>
+
+#include <mach/display.h>
+#include <mach/dma.h>
+
+#ifdef DEBUG
+#define DBG(format, ...) printk(KERN_DEBUG "Blizzard: " format, ## __VA_ARGS__)
+#else
+#define DBG(format, ...)
+#endif
+
+#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 BLIZZARD_AUTO_UPDATE_TIME (HZ / 20)
+
+
+
+static struct {
+ int version;
+} blizzard;
+
+
+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 int blizzard_ctrl_init(struct omap_display *display)
+{
+ DBG("blizzard_ctrl_init\n");
+
+ return 0;
+}
+
+
+static int blizzard_ctrl_enable(struct omap_display *display)
+{
+ int r = 0;
+ u8 rev, conf;
+
+ DBG("blizzard_ctrl_enable\n");
+
+ if (display->hw_config.ctrl_enable) {
+ r = display->hw_config.ctrl_enable(display);
+ if (r)
+ return r;
+ }
+
+ msleep(100);
+
+ rev = blizzard_read_reg(BLIZZARD_CLK_SRC);
+ printk("CLK_SRC %x\n", rev);
+
+ rev = blizzard_read_reg(BLIZZARD_PLL_DIV);
+ printk("PLLDIV %x\n", rev);
+
+ rev = blizzard_read_reg(BLIZZARD_REV_CODE);
+ conf = blizzard_read_reg(BLIZZARD_CONFIG);
+
+ printk("rev %x, conf %x\n", rev, conf);
+
+ switch (rev & 0xfc) {
+ case 0x9c:
+ blizzard.version = BLIZZARD_VERSION_S1D13744;
+ pr_info("omapfb: s1d13744 LCD controller rev %d "
+ "initialized (CNF pins %x)\n", rev & 0x03, conf & 0x07);
+ break;
+ case 0xa4:
+ blizzard.version = BLIZZARD_VERSION_S1D13745;
+ pr_info("omapfb: s1d13745 LCD controller rev %d "
+ "initialized (CNF pins %x)\n", rev & 0x03, conf & 0x07);
+ break;
+ default:
+ printk("invalid s1d1374x revision %02x\n",
+ rev);
+ r = -ENODEV;
+ }
+
+ return r;
+}
+
+static void blizzard_ctrl_disable(struct omap_display *display)
+{
+ DBG("blizzard_ctrl_disable\n");
+
+ if (display->hw_config.ctrl_disable)
+ display->hw_config.ctrl_disable(display);
+}
+
+int rfbi_configure(int rfbi_module, int bpp, int lines);
+
+static void blizzard_ctrl_setup_update(struct omap_display *display,
+ int x, int y, int w, int h)
+{
+ u8 tmp[18];
+ int x_end, y_end;
+
+ DBG("blizzard_ctrl_setup_update\n");
+
+ 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; //color_mode;
+
+ if (blizzard.version == BLIZZARD_VERSION_S1D13745)
+ tmp[17] = BLIZZARD_SRC_WRITE_LCD_BACKGROUND;
+ else
+ tmp[17] = blizzard.version == BLIZZARD_VERSION_S1D13744 ?
+ BLIZZARD_SRC_WRITE_LCD :
+ BLIZZARD_SRC_WRITE_LCD_DESTRUCTIVE;
+
+ rfbi_configure(display->hw_config.u.rfbi.channel,
+ 16,
+ 8);
+
+ blizzard_write(BLIZZARD_INPUT_WIN_X_START_0, tmp, 18);
+
+ rfbi_configure(display->hw_config.u.rfbi.channel,
+ 16,
+ 16);
+}
+
+static int blizzard_ctrl_enable_te(struct omap_display *display, int enable)
+{
+ return 0;
+}
+
+static int blizzard_ctrl_rotate(struct omap_display *display, int rotate)
+{
+ return 0;
+}
+
+static int blizzard_ctrl_mirror(struct omap_display *display, int enable)
+{
+ return 0;
+}
+
+static int blizzard_run_test(struct omap_display *display, int test_num)
+{
+ return 0;
+}
+
+static struct omap_ctrl blizzard_ctrl = {
+ .owner = THIS_MODULE,
+ .name = "ctrl-blizzard",
+ .init = blizzard_ctrl_init,
+ .enable = blizzard_ctrl_enable,
+ .disable = blizzard_ctrl_disable,
+ .setup_update = blizzard_ctrl_setup_update,
+ .enable_te = blizzard_ctrl_enable_te,
+ .rotate = blizzard_ctrl_rotate,
+ .mirror = blizzard_ctrl_mirror,
+ .run_test = blizzard_run_test,
+ .pixel_size = 16,
+
+ .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 __init blizzard_init(void)
+{
+ DBG("blizzard_init\n");
+ omap_dss_register_ctrl(&blizzard_ctrl);
+ return 0;
+}
+
+static void __exit blizzard_exit(void)
+{
+ DBG("blizzard_exit\n");
+
+ omap_dss_unregister_ctrl(&blizzard_ctrl);
+}
+
+module_init(blizzard_init);
+module_exit(blizzard_exit);
+
+MODULE_AUTHOR("Tomi Valkeinen <tomi.valkeinen@nokia.com>");
+MODULE_DESCRIPTION("Blizzard Driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/video/omap2/panel-n800.c b/drivers/video/omap2/panel-n800.c
new file mode 100644
index 0000000..3ae0a16
--- /dev/null
+++ b/drivers/video/omap2/panel-n800.c
@@ -0,0 +1,437 @@
+
+/*#define DEBUG*/
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/clk.h>
+#include <linux/platform_device.h>
+#include <linux/delay.h>
+#include <linux/spi/spi.h>
+#include <linux/jiffies.h>
+#include <linux/sched.h>
+#include <linux/backlight.h>
+#include <linux/fb.h>
+
+#include <mach/display.h>
+#include <mach/dma.h>
+
+#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
+
+#define MIPID_VER_LPH8923 3
+#define MIPID_VER_LS041Y3 4
+
+#define MIPID_ESD_CHECK_PERIOD msecs_to_jiffies(5000)
+
+#ifdef DEBUG
+#define DBG(format, ...) printk(KERN_DEBUG "PN800: " format, ## __VA_ARGS__)
+#else
+#define DBG(format, ...)
+#endif
+
+struct pn800_device {
+ struct backlight_device *bl_dev;
+ int enabled;
+ int model;
+ int revision;
+ u8 display_id[3];
+ unsigned int saved_bklight_level;
+ unsigned long hw_guard_end; /* next value of jiffies
+ when we can issue the
+ next sleep in/out command */
+ unsigned long hw_guard_wait; /* max guard time in jiffies */
+
+ struct spi_device *spi;
+ struct mutex mutex;
+ struct omap_panel panel;
+ struct omap_display *display;
+};
+
+
+static void pn800_transfer(struct pn800_device *md, 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;
+
+ BUG_ON(md->spi == NULL);
+
+ 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(md->spi, &m);
+ if (r < 0)
+ dev_dbg(&md->spi->dev, "spi_sync %d\n", r);
+
+ if (rlen)
+ rbuf[0] = w & 0xff;
+}
+
+static inline void pn800_cmd(struct pn800_device *md, int cmd)
+{
+ pn800_transfer(md, cmd, NULL, 0, NULL, 0);
+}
+
+static inline void pn800_write(struct pn800_device *md,
+ int reg, const u8 *buf, int len)
+{
+ pn800_transfer(md, reg, buf, len, NULL, 0);
+}
+
+static inline void pn800_read(struct pn800_device *md,
+ int reg, u8 *buf, int len)
+{
+ pn800_transfer(md, reg, NULL, 0, buf, len);
+}
+
+static void set_data_lines(struct pn800_device *md, int data_lines)
+{
+ u16 par;
+
+ switch (data_lines) {
+ case 16:
+ par = 0x150;
+ break;
+ case 18:
+ par = 0x160;
+ break;
+ case 24:
+ par = 0x170;
+ break;
+ }
+ pn800_write(md, 0x3a, (u8 *)&par, 2);
+}
+
+static void send_init_string(struct pn800_device *md)
+{
+ u16 initpar[] = { 0x0102, 0x0100, 0x0100 };
+ int data_lines;
+
+ pn800_write(md, 0xc2, (u8 *)initpar, sizeof(initpar));
+
+ data_lines = (int)md->display->hw_config.priv; // XXX
+
+ set_data_lines(md, data_lines);
+}
+
+static void hw_guard_start(struct pn800_device *md, int guard_msec)
+{
+ md->hw_guard_wait = msecs_to_jiffies(guard_msec);
+ md->hw_guard_end = jiffies + md->hw_guard_wait;
+}
+
+static void hw_guard_wait(struct pn800_device *md)
+{
+ unsigned long wait = md->hw_guard_end - jiffies;
+
+ if ((long)wait > 0 && wait <= md->hw_guard_wait) {
+ set_current_state(TASK_UNINTERRUPTIBLE);
+ schedule_timeout(wait);
+ }
+}
+
+static void set_sleep_mode(struct pn800_device *md, int on)
+{
+ int cmd, sleep_time = 50;
+
+ if (on)
+ cmd = MIPID_CMD_SLEEP_IN;
+ else
+ cmd = MIPID_CMD_SLEEP_OUT;
+ hw_guard_wait(md);
+ pn800_cmd(md, cmd);
+ hw_guard_start(md, 120);
+ /*
+ * When we enable the panel, it seems we _have_ to sleep
+ * 120 ms before sending the init string. When disabling the
+ * panel we'll sleep for the duration of 2 frames, so that the
+ * controller can still provide the PCLK,HS,VS signals. */
+ if (!on)
+ sleep_time = 120;
+ msleep(sleep_time);
+}
+
+static void set_display_state(struct pn800_device *md, int enabled)
+{
+ int cmd = enabled ? MIPID_CMD_DISP_ON : MIPID_CMD_DISP_OFF;
+
+ pn800_cmd(md, cmd);
+}
+
+static int panel_enabled(struct pn800_device *md)
+{
+ u32 disp_status;
+ int enabled;
+
+ pn800_read(md, MIPID_CMD_READ_DISP_STATUS, (u8 *)&disp_status, 4);
+ disp_status = __be32_to_cpu(disp_status);
+ enabled = (disp_status & (1 << 17)) && (disp_status & (1 << 10));
+ dev_dbg(&md->spi->dev,
+ "LCD panel %s enabled by bootloader (status 0x%04x)\n",
+ enabled ? "" : "not ", disp_status);
+ DBG("status %#08x\n", disp_status);
+ return enabled;
+}
+
+static int panel_detect(struct pn800_device *md)
+{
+ pn800_read(md, MIPID_CMD_READ_DISP_ID, md->display_id, 3);
+ dev_dbg(&md->spi->dev, "MIPI display ID: %02x%02x%02x\n",
+ md->display_id[0], md->display_id[1], md->display_id[2]);
+
+ switch (md->display_id[0]) {
+ case 0x45:
+ md->model = MIPID_VER_LPH8923;
+ md->panel.name = "lph8923";
+ break;
+ case 0x83:
+ md->model = MIPID_VER_LS041Y3;
+ md->panel.name = "ls041y3";
+ //md->esd_check = ls041y3_esd_check;
+ break;
+ default:
+ md->panel.name = "unknown";
+ dev_err(&md->spi->dev, "invalid display ID\n");
+ return -ENODEV;
+ }
+
+ md->revision = md->display_id[1];
+ pr_info("omapfb: %s rev %02x LCD detected\n",
+ md->panel.name, md->revision);
+
+ return 0;
+}
+
+
+
+static int pn800_panel_enable(struct omap_display *display)
+{
+ int r;
+ struct pn800_device *md =
+ (struct pn800_device *)display->panel->priv;
+
+ DBG("pn800_panel_enable\n");
+
+ mutex_lock(&md->mutex);
+
+ if (display->hw_config.panel_enable)
+ display->hw_config.panel_enable(display);
+
+ msleep(50); // wait for power up
+
+ r = panel_detect(md);
+ if (r) {
+ mutex_unlock(&md->mutex);
+ return r;
+ }
+
+ md->enabled = panel_enabled(md);
+
+ if (md->enabled) {
+ DBG("panel already enabled\n");
+ ; /*pn800_esd_start_check(md);*/
+ } else {
+ ; /*md->saved_bklight_level = pn800_get_bklight_level(panel);*/
+ }
+
+
+ if (md->enabled) {
+ mutex_unlock(&md->mutex);
+ return 0;
+ }
+
+ set_sleep_mode(md, 0);
+ md->enabled = 1;
+ send_init_string(md);
+ set_display_state(md, 1);
+ //mipid_set_bklight_level(panel, md->saved_bklight_level);
+ //mipid_esd_start_check(md);
+
+ mutex_unlock(&md->mutex);
+ return 0;
+}
+
+static void pn800_panel_disable(struct omap_display *display)
+{
+ struct pn800_device *md =
+ (struct pn800_device *)display->panel->priv;
+
+ DBG("pn800_panel_disable\n");
+
+ mutex_lock(&md->mutex);
+
+ if (!md->enabled) {
+ mutex_unlock(&md->mutex);
+ return;
+ }
+ /*md->saved_bklight_level = pn800_get_bklight_level(panel);*/
+ /*pn800_set_bklight_level(panel, 0);*/
+
+ set_display_state(md, 0);
+ set_sleep_mode(md, 1);
+ md->enabled = 0;
+
+
+ if (display->hw_config.panel_disable)
+ display->hw_config.panel_disable(display);
+
+ mutex_unlock(&md->mutex);
+}
+
+static int pn800_panel_init(struct omap_display *display)
+{
+ struct pn800_device *md =
+ (struct pn800_device *)display->panel->priv;
+
+ DBG("pn800_panel_init\n");
+
+ mutex_init(&md->mutex);
+ md->display = display;
+
+ return 0;
+}
+
+static int pn800_run_test(struct omap_display *display, int test_num)
+{
+ return 0;
+}
+
+static struct omap_panel pn800_panel = {
+ .owner = THIS_MODULE,
+ .name = "panel-pn800",
+ .init = pn800_panel_init,
+ /*.remove = pn800_cleanup,*/
+ .enable = pn800_panel_enable,
+ .disable = pn800_panel_disable,
+ //.set_mode = pn800_set_mode,
+ .run_test = pn800_run_test,
+
+ .timings = {
+ .x_res = 800,
+ .y_res = 480,
+
+ .pixel_clock = 21940,
+ .hsw = 50,
+ .hfp = 20,
+ .hbp = 15,
+
+ .vsw = 2,
+ .vfp = 1,
+ .vbp = 3,
+ },
+ .config = OMAP_DSS_LCD_TFT,
+
+ .bpp = 16,
+};
+
+static int pn800_spi_probe(struct spi_device *spi)
+{
+ struct pn800_device *md;
+
+ DBG("pn800_spi_probe\n");
+
+ md = kzalloc(sizeof(*md), GFP_KERNEL);
+ if (md == NULL) {
+ dev_err(&spi->dev, "out of memory\n");
+ return -ENOMEM;
+ }
+
+ spi->mode = SPI_MODE_0;
+ md->spi = spi;
+ dev_set_drvdata(&spi->dev, md);
+ md->panel = pn800_panel;
+ pn800_panel.priv = md;
+
+ omap_dss_register_panel(&pn800_panel);
+
+ return 0;
+}
+
+static int pn800_spi_remove(struct spi_device *spi)
+{
+ struct pn800_device *md = dev_get_drvdata(&spi->dev);
+
+ DBG("pn800_spi_remove\n");
+
+ omap_dss_unregister_panel(&pn800_panel);
+
+ /*pn800_disable(&md->panel);*/
+ kfree(md);
+
+ return 0;
+}
+
+static struct spi_driver pn800_spi_driver = {
+ .driver = {
+ .name = "panel-n800",
+ .bus = &spi_bus_type,
+ .owner = THIS_MODULE,
+ },
+ .probe = pn800_spi_probe,
+ .remove = __devexit_p(pn800_spi_remove),
+};
+
+static int __init pn800_init(void)
+{
+ DBG("pn800_init\n");
+ return spi_register_driver(&pn800_spi_driver);
+}
+
+static void __exit pn800_exit(void)
+{
+ DBG("pn800_exit\n");
+ spi_unregister_driver(&pn800_spi_driver);
+}
+
+module_init(pn800_init);
+module_exit(pn800_exit);
+
+MODULE_AUTHOR("Tomi Valkeinen <tomi.valkeinen@nokia.com>");
+MODULE_DESCRIPTION("N800 LCD Driver");
+MODULE_LICENSE("GPL");
--
To unsubscribe from this list: send the line "unsubscribe linux-omap" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
next prev parent reply other threads:[~2009-01-12 11:48 UTC|newest]
Thread overview: 23+ messages / expand[flat|nested] mbox.gz Atom feed top
2009-01-12 11:47 [PATCH 00/12] DSS: Series description Tomi Valkeinen
2009-01-12 11:47 ` [PATCH 01/12] DSS: Documentation for DSS2 Tomi Valkeinen
2009-01-12 11:47 ` [PATCH 02/12] DSS: Display subsystem for OMAP2/3 Tomi Valkeinen
2009-01-12 13:02 ` [Linux-fbdev-devel] " Tony Lindgren
2009-01-12 13:06 ` Shah, Hardik
2009-01-12 13:17 ` Tony Lindgren
2009-01-12 11:47 ` [PATCH 03/12] DSS: RFBI support Tomi Valkeinen
2009-01-12 13:03 ` Tony Lindgren
2009-01-12 11:47 ` [PATCH 04/12] DSS: VENC support Tomi Valkeinen
2009-01-12 11:47 ` [PATCH 05/12] DSS: DSI support Tomi Valkeinen
2009-01-12 11:47 ` [PATCH 06/12] DSS: OMAPFB: fb driver for new display subsystem Tomi Valkeinen
2009-01-12 11:48 ` [PATCH 07/12] DSS: Add generic DVI panel Tomi Valkeinen
2009-01-12 11:48 ` [PATCH 08/12] DSS: support for Beagle Board Tomi Valkeinen
2009-01-13 11:14 ` David Brownell
2009-01-13 11:37 ` Tomi Valkeinen
2009-01-12 11:48 ` [PATCH 09/12] DSS: Sharp LS037V7DW01 LCD Panel driver Tomi Valkeinen
2009-01-12 11:48 ` [PATCH 10/12] DSS: Support for OMAP3 SDP board Tomi Valkeinen
2009-01-13 11:15 ` David Brownell
2009-01-12 11:48 ` [PATCH 11/12] DSS: Support for OMAP3 EVM board Tomi Valkeinen
2009-01-12 11:48 ` Tomi Valkeinen [this message]
2009-01-12 13:44 ` [PATCH 00/12] DSS: Series description Koen Kooi
2009-01-12 14:52 ` Hiremath, Vaibhav
2009-01-12 15:39 ` Koen Kooi
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20090112114838.1003.90392.stgit@tubuntu \
--to=tomi.valkeinen@nokia.com \
--cc=linux-fbdev-devel@lists.sourceforge.net \
--cc=linux-omap@vger.kernel.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.