All of lore.kernel.org
 help / color / mirror / Atom feed
From: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
To: linux-fbdev@vger.kernel.org, dri-devel@lists.freedesktop.org,
	linux-leds@vger.kernel.org
Cc: linux-media@vger.kernel.org, Bryan Wu <bryan.wu@canonical.com>,
	Richard Purdie <rpurdie@rpsys.net>,
	Tomi Valkeinen <tomi.valkeinen@ti.com>,
	Marcus Lorentzon <marcus.lorentzon@linaro.org>,
	Sumit Semwal <sumit.semwal@ti.com>, Archit Taneja <archit@ti.com>,
	Sebastien Guiriec <s-guiriec@ti.com>,
	Inki Dae <inki.dae@samsung.com>,
	Kyungmin Park <kyungmin.park@samsung.com>
Subject: [RFC 4/5] video: panel: Add R61505 panel support
Date: Fri, 17 Aug 2012 02:49:42 +0200	[thread overview]
Message-ID: <1345164583-18924-5-git-send-email-laurent.pinchart@ideasonboard.com> (raw)
In-Reply-To: <1345164583-18924-1-git-send-email-laurent.pinchart@ideasonboard.com>

The R61505 is a SYS-80 bus panel controller from Renesas.

Signed-off-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
---
 drivers/video/panel/Kconfig        |    9 +
 drivers/video/panel/Makefile       |    1 +
 drivers/video/panel/panel-r61505.c |  520 ++++++++++++++++++++++++++++++++++++
 include/video/panel-r61505.h       |   27 ++
 4 files changed, 557 insertions(+), 0 deletions(-)
 create mode 100644 drivers/video/panel/panel-r61505.c
 create mode 100644 include/video/panel-r61505.h

diff --git a/drivers/video/panel/Kconfig b/drivers/video/panel/Kconfig
index fd0b3cf..12d7712 100644
--- a/drivers/video/panel/Kconfig
+++ b/drivers/video/panel/Kconfig
@@ -16,4 +16,13 @@ config DISPLAY_PANEL_DBI
 	tristate
 	default n
 
+config DISPLAY_PANEL_R61505
+	tristate "Renesas R61505-based Display Panel"
+	select DISPLAY_PANEL_DBI
+	---help---
+	  Support panels based on the Renesas R61505 panel controller.
+	  Those panels are controlled through a MIPI DBI interface.
+
+	  If you are in doubt, say N.
+
 endif # DISPLAY_PANEL
diff --git a/drivers/video/panel/Makefile b/drivers/video/panel/Makefile
index 2ab0520..e4fb9fe 100644
--- a/drivers/video/panel/Makefile
+++ b/drivers/video/panel/Makefile
@@ -1,3 +1,4 @@
 obj-$(CONFIG_DISPLAY_PANEL) += panel.o
 obj-$(CONFIG_DISPLAY_PANEL_DUMMY) += panel-dummy.o
 obj-$(CONFIG_DISPLAY_PANEL_DBI) += panel-dbi.o
+obj-$(CONFIG_DISPLAY_PANEL_R61505) += panel-r61505.o
diff --git a/drivers/video/panel/panel-r61505.c b/drivers/video/panel/panel-r61505.c
new file mode 100644
index 0000000..e09455e
--- /dev/null
+++ b/drivers/video/panel/panel-r61505.c
@@ -0,0 +1,520 @@
+/*
+ * Renesas R61505-based Display Panels
+ *
+ * Copyright (C) 2012 Renesas Solutions Corp.
+ * Based on SuperH MigoR Quarter VGA LCD Panel
+ * Copyright (C) 2008 Magnus Damm
+ * Based on lcd_powertip.c from Kenati Technologies Pvt Ltd.
+ * Copyright (c) 2007 Ujjwal Pande
+ *
+ * Contacts: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/delay.h>
+#include <linux/err.h>
+#include <linux/gpio.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+
+#include <video/panel-r61505.h>
+#include <video/panel-dbi.h>
+
+#define R61505_DEVICE_CODE			0x0000
+#define R61505_DEVICE_CODE_VALUE		0x1505
+#define R61505_DRIVER_OUTPUT_CONTROL		0x0001
+#define R61505_DRIVER_OUTPUT_CONTROL_SM		(1 << 10)
+#define R61505_DRIVER_OUTPUT_CONTROL_SS		(1 << 8)
+#define R61505_LCD_WAVEFORM			0x0002
+#define R61505_LCD_WAVEFORM_BC0			(1 << 9)
+#define R61505_LCD_WAVEFORM_EOR			(1 << 8)
+#define R61505_ENTRY_MODE			0x0003
+#define R61505_ENTRY_MODE_TRIREG		(1 << 15)
+#define R61505_ENTRY_MODE_DFM			(1 << 14)
+#define R61505_ENTRY_MODE_BGR			(1 << 12)
+#define R61505_ENTRY_MODE_HWM			(1 << 9)
+#define R61505_ENTRY_MODE_ORG			(1 << 7)
+#define R61505_ENTRY_MODE_ID1			(1 << 5)
+#define R61505_ENTRY_MODE_ID0			(1 << 4)
+#define R61505_ENTRY_MODE_AM			(1 << 3)
+#define R61505_RESIZE_CONTROL			0x0004
+#define R61505_RESIZE_CONTROL_RCV(n)		(((n) & 3) << 8)
+#define R61505_RESIZE_CONTROL_RCH(n)		(((n) & 3) << 4)
+#define R61505_RESIZE_CONTROL_RSZ_4		(3 << 0)
+#define R61505_RESIZE_CONTROL_RSZ_2		(1 << 0)
+#define R61505_RESIZE_CONTROL_RSZ_1		(0 << 0)
+#define R61505_DISPLAY_CONTROL1			0x0007
+#define R61505_DISPLAY_CONTROL1_PTDE1		(1 << 13)
+#define R61505_DISPLAY_CONTROL1_PTDE0		(1 << 12)
+#define R61505_DISPLAY_CONTROL1_BASEE		(1 << 8)
+#define R61505_DISPLAY_CONTROL1_VON		(1 << 6)
+#define R61505_DISPLAY_CONTROL1_GON		(1 << 5)
+#define R61505_DISPLAY_CONTROL1_DTE		(1 << 4)
+#define R61505_DISPLAY_CONTROL1_COL		(1 << 3)
+#define R61505_DISPLAY_CONTROL1_D1		(1 << 1)
+#define R61505_DISPLAY_CONTROL1_D0		(1 << 0)
+#define R61505_DISPLAY_CONTROL2			0x0008
+#define R61505_DISPLAY_CONTROL2_FP(n)		(((n) & 0xf) << 8)
+#define R61505_DISPLAY_CONTROL2_BP(n)		(((n) & 0xf) << 0)
+#define R61505_DISPLAY_CONTROL3			0x0009
+#define R61505_DISPLAY_CONTROL3_PTS(n)		(((n) & 7) << 8)
+#define R61505_DISPLAY_CONTROL3_PTG(n)		(((n) & 3) << 3)
+#define R61505_DISPLAY_CONTROL3_ICS(n)		(((n) & 0xf) << 0)
+#define R61505_DISPLAY_CONTROL4			0x000a
+#define R61505_DISPLAY_CONTROL4_FMARKOE		(1 << 3)
+#define R61505_DISPLAY_CONTROL4_FMI_6		(5 << 0)
+#define R61505_DISPLAY_CONTROL4_FMI_4		(3 << 0)
+#define R61505_DISPLAY_CONTROL4_FMI_2		(1 << 0)
+#define R61505_DISPLAY_CONTROL4_FMI_1		(0 << 0)
+#define R61505_EXT_DISPLAY_IF_CONTROL1		0x000c
+#define R61505_EXT_DISPLAY_IF_CONTROL1_ENC(n)	(((n) & 7) << 12)
+#define R61505_EXT_DISPLAY_IF_CONTROL1_RM	(1 << 8)
+#define R61505_EXT_DISPLAY_IF_CONTROL1_DM_VSYNC	(2 << 4)
+#define R61505_EXT_DISPLAY_IF_CONTROL1_DM_RGB	(1 << 4)
+#define R61505_EXT_DISPLAY_IF_CONTROL1_DM_ICLK	(0 << 4)
+#define R61505_EXT_DISPLAY_IF_CONTROL1_RIM_6	(2 << 0)
+#define R61505_EXT_DISPLAY_IF_CONTROL1_RIM_16	(1 << 0)
+#define R61505_EXT_DISPLAY_IF_CONTROL1_RIM_18	(0 << 0)
+#define R61505_FRAME_MARKER_CONTROL		0x000d
+#define R61505_FRAME_MARKER_CONTROL_FMP(n)	(((n) & 0x1ff) << 0)
+#define R61505_EXT_DISPLAY_IF_CONTROL2		0x000f
+#define R61505_POWER_CONTROL1			0x0010
+#define R61505_POWER_CONTROL1_SAP		(1 << 12)
+#define R61505_POWER_CONTROL1_BT(n)		(((n) & 0xf) << 8)
+#define R61505_POWER_CONTROL1_APE		(1 << 7)
+#define R61505_POWER_CONTROL1_AP_100		(3 << 4)
+#define R61505_POWER_CONTROL1_AP_075		(2 << 4)
+#define R61505_POWER_CONTROL1_AP_050		(1 << 4)
+#define R61505_POWER_CONTROL1_AP_HALT		(0 << 4)
+#define R61505_POWER_CONTROL1_DSTB		(1 << 2)
+#define R61505_POWER_CONTROL1_SLP		(1 << 1)
+#define R61505_POWER_CONTROL2			0x0011
+#define R61505_POWER_CONTROL2_DC1_HALT		(6 << 8)
+#define R61505_POWER_CONTROL2_DC1_FOSC_256	(4 << 8)
+#define R61505_POWER_CONTROL2_DC1_FOSC_128	(3 << 8)
+#define R61505_POWER_CONTROL2_DC1_FOSC_64	(2 << 8)
+#define R61505_POWER_CONTROL2_DC1_FOSC_32	(1 << 8)
+#define R61505_POWER_CONTROL2_DC1_FOSC_16	(0 << 8)
+#define R61505_POWER_CONTROL2_DC0_HALT		(6 << 4)
+#define R61505_POWER_CONTROL2_DC0_FOSC_16	(4 << 4)
+#define R61505_POWER_CONTROL2_DC0_FOSC_8	(3 << 4)
+#define R61505_POWER_CONTROL2_DC0_FOSC_4	(2 << 4)
+#define R61505_POWER_CONTROL2_DC0_FOSC_2	(1 << 4)
+#define R61505_POWER_CONTROL2_DC0_FOSC		(0 << 4)
+#define R61505_POWER_CONTROL2_VC_100		(7 << 0)
+#define R61505_POWER_CONTROL2_VC_076		(4 << 0)
+#define R61505_POWER_CONTROL2_VC_089		(1 << 0)
+#define R61505_POWER_CONTROL2_VC_094		(0 << 0)
+#define R61505_POWER_CONTROL3			0x0012
+#define R61505_POWER_CONTROL3_VCMR		(1 << 8)
+#define R61505_POWER_CONTROL3_PSON		(1 << 5)
+#define R61505_POWER_CONTROL3_PON		(1 << 4)
+#define R61505_POWER_CONTROL3_VRH(n)		(((n) & 0xf) << 0)
+#define R61505_POWER_CONTROL4			0x0013
+#define R61505_POWER_CONTROL4_VDV(n)		(((n) & 0xf) << 8)
+#define R61505_POWER_CONTROL5			0x0015
+#define R61505_POWER_CONTROL5_BLDM		(1 << 12)
+#define R61505_POWER_CONTROL6			0x0017
+#define R61505_POWER_CONTROL6_PSE		(1 << 0)
+#define R61505_RAM_ADDR_HORZ			0x0020
+#define R61505_RAM_ADDR_VERT			0x0021
+#define R61505_RAM_DATA				0x0022
+#define R61505_POWER_CONTROL7			0x0029
+#define R61505_POWER_CONTROL7_VCM1(n)		(((n) & 0x1f) << 0)
+#define R61505_GAMMA_CONTROL1			0x0030
+#define R61505_GAMMA_CONTROL2			0x0031
+#define R61505_GAMMA_CONTROL3			0x0032
+#define R61505_GAMMA_CONTROL4			0x0033
+#define R61505_GAMMA_CONTROL5			0x0034
+#define R61505_GAMMA_CONTROL6			0x0035
+#define R61505_GAMMA_CONTROL7			0x0036
+#define R61505_GAMMA_CONTROL8			0x0037
+#define R61505_GAMMA_CONTROL9			0x0038
+#define R61505_GAMMA_CONTROL10			0x0039
+#define R61505_GAMMA_CONTROL11			0x003a
+#define R61505_GAMMA_CONTROL12			0x003b
+#define R61505_GAMMA_CONTROL13			0x003c
+#define R61505_GAMMA_CONTROL14			0x003d
+#define R61505_WINDOW_HORZ_START		0x0050
+#define R61505_WINDOW_HORZ_END			0x0051
+#define R61505_WINDOW_VERT_START		0x0052
+#define R61505_WINDOW_VERT_END			0x0053
+#define R61505_DRIVER_OUTPUT_CONTROL2		0x0060
+#define R61505_DRIVER_OUTPUT_CONTROL2_GS	(1 << 15)
+#define R61505_DRIVER_OUTPUT_CONTROL2_NL(n)	(((n) & 0x3f) << 8)
+#define R61505_DRIVER_OUTPUT_CONTROL2_SCN(n)	(((n) & 0x3f) << 0)
+#define R61505_BASE_IMG_DISPLAY_CONTROL		0x0061
+#define R61505_BASE_IMG_DISPLAY_CONTROL_NDL	(1 << 2)
+#define R61505_BASE_IMG_DISPLAY_CONTROL_VLE	(1 << 1)
+#define R61505_BASE_IMG_DISPLAY_CONTROL_REV	(1 << 0)
+#define R61505_VERTICAL_SCROLL_CONTROL		0x006a
+#define R61505_PANEL_IF_CONTROL1		0x0090
+#define R61505_PANEL_IF_CONTROL1_DIVI(n)	(((n) & 3) << 8)
+#define R61505_PANEL_IF_CONTROL1_RTNI(n)	(((n) & 0x1f) << 0)
+#define R61505_PANEL_IF_CONTROL2		0x0092
+#define R61505_PANEL_IF_CONTROL2_NOWI(n)	(((n) & 7) << 8)
+#define R61505_PANEL_IF_CONTROL3		0x0093
+#define R61505_PANEL_IF_CONTROL3_MCP(n)		(((n) & 7) << 8)
+#define R61505_PANEL_IF_CONTROL4		0x0095
+#define R61505_PANEL_IF_CONTROL5		0x0097
+#define R61505_PANEL_IF_CONTROL6		0x0098
+#define R61505_OSCILLATION_CONTROL		0x00a4
+#define R61505_OSCILLATION_CONTROL_CALB		(1 << 0)
+
+struct r61505 {
+	struct panel panel;
+	struct panel_dbi_device *dbi;
+	const struct panel_r61505_platform_data *pdata;
+};
+
+#define to_panel(p)	container_of(p, struct r61505, panel)
+
+/* -----------------------------------------------------------------------------
+ * Read, write and reset
+ */
+
+/* DB0-DB7 are connected to D1-D8, and DB8-DB15 to D10-D17 */
+
+static unsigned long adjust_reg18(u16 data)
+{
+	return (((data << 1) | 0x00000001) & 0x000001ff) |
+	       (((data << 2) | 0x00000200) & 0x0003fe00);
+}
+
+static void r61505_write_command(struct r61505 *panel, u16 reg)
+{
+	panel_dbi_write_command(panel->dbi, adjust_reg18(reg));
+}
+
+static void r61505_write(struct r61505 *panel, u16 reg, u16 data)
+{
+	panel_dbi_write_command(panel->dbi, adjust_reg18(reg));
+	panel_dbi_write_data(panel->dbi, adjust_reg18(data));
+}
+
+static u16 r61505_read(struct r61505 *panel, u16 reg)
+{
+	unsigned long data;
+
+	panel_dbi_write_command(panel->dbi, adjust_reg18(reg));
+	data = panel_dbi_read_data(panel->dbi);
+
+	return ((data >> 1) & 0xff) | ((data >> 2) & 0xff00);
+}
+
+static void r61505_write_array(struct r61505 *panel,
+				 const u16 *data, unsigned int len)
+{
+	unsigned int i;
+
+	for (i = 0; i < len; i += 2)
+		r61505_write(panel, data[i], data[i + 1]);
+}
+
+static void r61505_reset(struct r61505 *panel)
+{
+	if (panel->pdata->reset < 0)
+		return;
+
+	gpio_set_value(panel->pdata->reset, 0);
+	usleep_range(2000, 2500);
+	gpio_set_value(panel->pdata->reset, 1);
+	usleep_range(1000, 1500);
+}
+
+/* -----------------------------------------------------------------------------
+ * Configuration
+ */
+
+static const unsigned short sync_data[] = {
+	0x0000, 0x0000,
+	0x0000, 0x0000,
+	0x0000, 0x0000,
+	0x0000, 0x0000,
+};
+
+static const unsigned short magic0_data[] = {
+	R61505_DISPLAY_CONTROL2, R61505_DISPLAY_CONTROL2_FP(8) |
+				 R61505_DISPLAY_CONTROL2_BP(8),
+	R61505_PANEL_IF_CONTROL1, R61505_PANEL_IF_CONTROL1_RTNI(26),
+	R61505_DISPLAY_CONTROL1, R61505_DISPLAY_CONTROL1_D0,
+	R61505_POWER_CONTROL6, R61505_POWER_CONTROL6_PSE,
+	0x0019, 0x0000,
+	R61505_POWER_CONTROL1, R61505_POWER_CONTROL1_SAP |
+			       R61505_POWER_CONTROL1_BT(7) |
+			       R61505_POWER_CONTROL1_APE |
+			       R61505_POWER_CONTROL1_AP_100,
+	R61505_POWER_CONTROL2, R61505_POWER_CONTROL2_DC1_FOSC_32 |
+			       R61505_POWER_CONTROL2_DC0_FOSC_2 | 6,
+	R61505_POWER_CONTROL3, R61505_POWER_CONTROL3_VCMR | 0x80 |
+			       R61505_POWER_CONTROL3_PON |
+			       R61505_POWER_CONTROL3_VRH(8),
+	R61505_POWER_CONTROL4, 0x1000 | R61505_POWER_CONTROL4_VDV(4),
+	R61505_POWER_CONTROL7, R61505_POWER_CONTROL7_VCM1(12),
+	R61505_POWER_CONTROL3, R61505_POWER_CONTROL3_VCMR | 0x80 |
+			       R61505_POWER_CONTROL3_PSON |
+			       R61505_POWER_CONTROL3_PON |
+			       R61505_POWER_CONTROL3_VRH(8),
+};
+
+static const unsigned short magic1_data[] = {
+	R61505_GAMMA_CONTROL1, 0x0307,
+	R61505_GAMMA_CONTROL2, 0x0303,
+	R61505_GAMMA_CONTROL3, 0x0603,
+	R61505_GAMMA_CONTROL4, 0x0202,
+	R61505_GAMMA_CONTROL5, 0x0202,
+	R61505_GAMMA_CONTROL6, 0x0202,
+	R61505_GAMMA_CONTROL7, 0x1f1f,
+	R61505_GAMMA_CONTROL8, 0x0303,
+	R61505_GAMMA_CONTROL9, 0x0303,
+	R61505_GAMMA_CONTROL10, 0x0603,
+	R61505_GAMMA_CONTROL11, 0x0202,
+	R61505_GAMMA_CONTROL12, 0x0102,
+	R61505_GAMMA_CONTROL13, 0x0204,
+	R61505_GAMMA_CONTROL14, 0x0000,
+	R61505_DRIVER_OUTPUT_CONTROL, R61505_DRIVER_OUTPUT_CONTROL_SS,
+	R61505_LCD_WAVEFORM, R61505_LCD_WAVEFORM_BC0 |
+			     R61505_LCD_WAVEFORM_EOR,
+	R61505_ENTRY_MODE, R61505_ENTRY_MODE_DFM |
+			   R61505_ENTRY_MODE_BGR |
+			   R61505_ENTRY_MODE_ID1 |
+			   R61505_ENTRY_MODE_AM,
+	R61505_RAM_ADDR_HORZ, 239,
+	R61505_RAM_ADDR_VERT, 0,
+	R61505_RESIZE_CONTROL, R61505_RESIZE_CONTROL_RCV(0) |
+			       R61505_RESIZE_CONTROL_RCH(0) |
+			       R61505_RESIZE_CONTROL_RSZ_1,
+	R61505_DISPLAY_CONTROL3, R61505_DISPLAY_CONTROL3_PTS(0) |
+				 R61505_DISPLAY_CONTROL3_PTG(0) |
+				 R61505_DISPLAY_CONTROL3_ICS(0),
+	R61505_DISPLAY_CONTROL4, R61505_DISPLAY_CONTROL4_FMARKOE |
+				 R61505_DISPLAY_CONTROL4_FMI_1,
+	R61505_EXT_DISPLAY_IF_CONTROL1, R61505_EXT_DISPLAY_IF_CONTROL1_ENC(0) |
+					R61505_EXT_DISPLAY_IF_CONTROL1_DM_ICLK |
+					R61505_EXT_DISPLAY_IF_CONTROL1_RIM_18,
+	R61505_FRAME_MARKER_CONTROL, R61505_FRAME_MARKER_CONTROL_FMP(0),
+	R61505_POWER_CONTROL5, 0x8000,
+};
+
+static const unsigned short magic2_data[] = {
+	R61505_BASE_IMG_DISPLAY_CONTROL, R61505_BASE_IMG_DISPLAY_CONTROL_REV,
+	R61505_PANEL_IF_CONTROL2, R61505_PANEL_IF_CONTROL2_NOWI(1),
+	R61505_PANEL_IF_CONTROL3, R61505_PANEL_IF_CONTROL3_MCP(1),
+	R61505_DISPLAY_CONTROL1, R61505_DISPLAY_CONTROL1_GON |
+				 R61505_DISPLAY_CONTROL1_D0,
+};
+
+static const unsigned short magic3_data[] = {
+	R61505_POWER_CONTROL1, R61505_POWER_CONTROL1_SAP |
+			       R61505_POWER_CONTROL1_BT(6) |
+			       R61505_POWER_CONTROL1_APE |
+			       R61505_POWER_CONTROL1_AP_100,
+	R61505_POWER_CONTROL2, R61505_POWER_CONTROL2_DC1_FOSC_32 |
+			       R61505_POWER_CONTROL2_DC0_FOSC_2 |
+			       R61505_POWER_CONTROL2_VC_089,
+	R61505_DISPLAY_CONTROL1, R61505_DISPLAY_CONTROL1_VON |
+				 R61505_DISPLAY_CONTROL1_GON |
+				 R61505_DISPLAY_CONTROL1_D0,
+};
+
+static void r61505_enable_panel(struct r61505 *panel)
+{
+	unsigned long xres = panel->pdata->mode->xres;
+	unsigned long yres = panel->pdata->mode->yres;
+	unsigned int i;
+
+	r61505_write_array(panel, sync_data, ARRAY_SIZE(sync_data));
+
+	r61505_write(panel, R61505_OSCILLATION_CONTROL,
+		     R61505_OSCILLATION_CONTROL_CALB);
+	usleep_range(10000, 11000);
+
+	r61505_write(panel, R61505_DRIVER_OUTPUT_CONTROL2,
+		     R61505_DRIVER_OUTPUT_CONTROL2_NL((xres / 8) - 1));
+	r61505_write_array(panel, magic0_data, ARRAY_SIZE(magic0_data));
+	usleep_range(100000, 101000);
+
+	r61505_write_array(panel, magic1_data, ARRAY_SIZE(magic1_data));
+
+	r61505_write(panel, R61505_WINDOW_HORZ_START, 239 - (yres - 1));
+	r61505_write(panel, R61505_WINDOW_HORZ_END, 239);
+	r61505_write(panel, R61505_WINDOW_VERT_START, 0);
+	r61505_write(panel, R61505_WINDOW_VERT_END, xres - 1);
+
+	r61505_write_array(panel, magic2_data, ARRAY_SIZE(magic2_data));
+	usleep_range(10000, 11000);
+
+	r61505_write_array(panel, magic3_data, ARRAY_SIZE(magic3_data));
+	usleep_range(40000, 41000);
+
+	/* Clear GRAM to avoid displaying garbage. */
+	r61505_write(panel, R61505_RAM_ADDR_HORZ, 0);
+	r61505_write(panel, R61505_RAM_ADDR_VERT, 0);
+
+	for (i = 0; i < (xres * 256); i++) /* yes, 256 words per line */
+		r61505_write(panel, R61505_RAM_DATA, 0);
+
+	r61505_write(panel, R61505_RAM_ADDR_HORZ, 0);
+	r61505_write(panel, R61505_RAM_ADDR_VERT, 0);
+}
+
+static void r61505_disable_panel(struct r61505 *panel)
+{
+	r61505_reset(panel);
+}
+
+static void r61505_display_on(struct r61505 *panel)
+{
+	r61505_write(panel, R61505_DISPLAY_CONTROL1,
+		     R61505_DISPLAY_CONTROL1_BASEE |
+		     R61505_DISPLAY_CONTROL1_VON |
+		     R61505_DISPLAY_CONTROL1_GON |
+		     R61505_DISPLAY_CONTROL1_DTE |
+		     R61505_DISPLAY_CONTROL1_D1 |
+		     R61505_DISPLAY_CONTROL1_D0);
+	usleep_range(40000, 41000);
+}
+
+static void r61505_display_off(struct r61505 *panel)
+{
+	r61505_write(panel, R61505_DISPLAY_CONTROL1,
+		     R61505_DISPLAY_CONTROL1_VON |
+		     R61505_DISPLAY_CONTROL1_GON |
+		     R61505_DISPLAY_CONTROL1_D0);
+}
+
+/* -----------------------------------------------------------------------------
+ * Panel operations
+ */
+
+static int r61505_enable(struct panel *p, enum panel_enable_mode enable)
+{
+	struct r61505 *panel = to_panel(p);
+
+	switch (enable) {
+	case PANEL_ENABLE_OFF:
+		r61505_disable_panel(panel);
+		break;
+
+	case PANEL_ENABLE_BLANK:
+		if (p->enable == PANEL_ENABLE_OFF)
+			r61505_enable_panel(panel);
+		else
+			r61505_display_off(panel);
+		break;
+
+	case PANEL_ENABLE_ON:
+		if (p->enable == PANEL_ENABLE_OFF)
+			r61505_enable_panel(panel);
+
+		r61505_display_on(panel);
+		break;
+	}
+
+	return 0;
+}
+
+static int r61505_start_transfer(struct panel *p)
+{
+	struct r61505 *panel = to_panel(p);
+
+	r61505_write_command(panel, R61505_RAM_DATA);
+	usleep_range(100000, 101000);
+
+	return 0;
+}
+
+static int r61505_get_modes(struct panel *p, const struct fb_videomode **modes)
+{
+	struct r61505 *panel = to_panel(p);
+
+	*modes = panel->pdata->mode;
+	return 1;
+}
+
+static const struct panel_ops r61505_ops = {
+	.enable = r61505_enable,
+	.start_transfer = r61505_start_transfer,
+	.get_modes = r61505_get_modes,
+};
+
+static void r61505_release(struct panel *p)
+{
+	struct r61505 *panel = to_panel(p);
+
+	kfree(panel);
+}
+
+static int r61505_remove(struct panel_dbi_device *dev)
+{
+	struct r61505 *panel = panel_dbi_get_drvdata(dev);
+
+	panel_dbi_set_drvdata(dev, NULL);
+	panel_unregister(&panel->panel);
+
+	return 0;
+}
+
+static int __devinit r61505_probe(struct panel_dbi_device *dev)
+{
+	const struct panel_r61505_platform_data *pdata = dev->dev.platform_data;
+	struct r61505 *panel;
+	int ret;
+
+	if (pdata == NULL)
+		return -ENODEV;
+
+	panel = kzalloc(sizeof(*panel), GFP_KERNEL);
+	if (panel == NULL)
+		return -ENOMEM;
+
+	panel->pdata = pdata;
+	panel->dbi = dev;
+
+	r61505_reset(panel);
+	r61505_write_array(panel, sync_data, ARRAY_SIZE(sync_data));
+
+	if (r61505_read(panel, 0) != R61505_DEVICE_CODE_VALUE) {
+		kfree(panel);
+		return -ENODEV;
+	}
+
+	panel->panel.dev = &dev->dev;
+	panel->panel.release = r61505_release;
+	panel->panel.ops = &r61505_ops;
+	panel->panel.width = pdata->width;
+	panel->panel.height = pdata->height;
+
+	ret = panel_register(&panel->panel);
+	if (ret < 0) {
+		kfree(panel);
+		return ret;
+	}
+
+	panel_dbi_set_drvdata(dev, panel);
+
+	return 0;
+}
+
+static const struct dev_pm_ops r61505_dev_pm_ops = {
+};
+
+static struct panel_dbi_driver r61505_driver = {
+	.probe = r61505_probe,
+	.remove = r61505_remove,
+	.driver = {
+		.name = "panel_r61505",
+		.owner = THIS_MODULE,
+		.pm = &r61505_dev_pm_ops,
+	},
+};
+
+module_panel_dbi_driver(r61505_driver);
+
+MODULE_AUTHOR("Laurent Pinchart <laurent.pinchart@ideasonboard.com>");
+MODULE_DESCRIPTION("Renesas R61505-based Display Panel");
+MODULE_LICENSE("GPL");
diff --git a/include/video/panel-r61505.h b/include/video/panel-r61505.h
new file mode 100644
index 0000000..90b3d62
--- /dev/null
+++ b/include/video/panel-r61505.h
@@ -0,0 +1,27 @@
+/*
+ * Renesas R61505-based Display Panels
+ *
+ * Copyright (C) 2012 Renesas Solutions Corp.
+ *
+ * Contacts: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#ifndef __PANEL_R61505_H__
+#define __PANEL_R61505_H__
+
+#include <linux/fb.h>
+#include <video/panel.h>
+
+struct panel_r61505_platform_data {
+	unsigned long width;		/* Panel width in mm */
+	unsigned long height;		/* Panel height in mm */
+	const struct fb_videomode *mode;
+
+	int reset;			/* Reset GPIO */
+};
+
+#endif /* __PANEL_R61505_H__ */
-- 
1.7.8.6


WARNING: multiple messages have this Message-ID (diff)
From: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
To: linux-fbdev@vger.kernel.org, dri-devel@lists.freedesktop.org,
	linux-leds@vger.kernel.org
Cc: linux-media@vger.kernel.org, Bryan Wu <bryan.wu@canonical.com>,
	Richard Purdie <rpurdie@rpsys.net>,
	Tomi Valkeinen <tomi.valkeinen@ti.com>,
	Marcus Lorentzon <marcus.lorentzon@linaro.org>,
	Sumit Semwal <sumit.semwal@ti.com>, Archit Taneja <archit@ti.com>,
	Sebastien Guiriec <s-guiriec@ti.com>,
	Inki Dae <inki.dae@samsung.com>,
	Kyungmin Park <kyungmin.park@samsung.com>
Subject: [RFC 4/5] video: panel: Add R61505 panel support
Date: Fri, 17 Aug 2012 00:49:42 +0000	[thread overview]
Message-ID: <1345164583-18924-5-git-send-email-laurent.pinchart@ideasonboard.com> (raw)
In-Reply-To: <1345164583-18924-1-git-send-email-laurent.pinchart@ideasonboard.com>

The R61505 is a SYS-80 bus panel controller from Renesas.

Signed-off-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
---
 drivers/video/panel/Kconfig        |    9 +
 drivers/video/panel/Makefile       |    1 +
 drivers/video/panel/panel-r61505.c |  520 ++++++++++++++++++++++++++++++++++++
 include/video/panel-r61505.h       |   27 ++
 4 files changed, 557 insertions(+), 0 deletions(-)
 create mode 100644 drivers/video/panel/panel-r61505.c
 create mode 100644 include/video/panel-r61505.h

diff --git a/drivers/video/panel/Kconfig b/drivers/video/panel/Kconfig
index fd0b3cf..12d7712 100644
--- a/drivers/video/panel/Kconfig
+++ b/drivers/video/panel/Kconfig
@@ -16,4 +16,13 @@ config DISPLAY_PANEL_DBI
 	tristate
 	default n
 
+config DISPLAY_PANEL_R61505
+	tristate "Renesas R61505-based Display Panel"
+	select DISPLAY_PANEL_DBI
+	---help---
+	  Support panels based on the Renesas R61505 panel controller.
+	  Those panels are controlled through a MIPI DBI interface.
+
+	  If you are in doubt, say N.
+
 endif # DISPLAY_PANEL
diff --git a/drivers/video/panel/Makefile b/drivers/video/panel/Makefile
index 2ab0520..e4fb9fe 100644
--- a/drivers/video/panel/Makefile
+++ b/drivers/video/panel/Makefile
@@ -1,3 +1,4 @@
 obj-$(CONFIG_DISPLAY_PANEL) += panel.o
 obj-$(CONFIG_DISPLAY_PANEL_DUMMY) += panel-dummy.o
 obj-$(CONFIG_DISPLAY_PANEL_DBI) += panel-dbi.o
+obj-$(CONFIG_DISPLAY_PANEL_R61505) += panel-r61505.o
diff --git a/drivers/video/panel/panel-r61505.c b/drivers/video/panel/panel-r61505.c
new file mode 100644
index 0000000..e09455e
--- /dev/null
+++ b/drivers/video/panel/panel-r61505.c
@@ -0,0 +1,520 @@
+/*
+ * Renesas R61505-based Display Panels
+ *
+ * Copyright (C) 2012 Renesas Solutions Corp.
+ * Based on SuperH MigoR Quarter VGA LCD Panel
+ * Copyright (C) 2008 Magnus Damm
+ * Based on lcd_powertip.c from Kenati Technologies Pvt Ltd.
+ * Copyright (c) 2007 Ujjwal Pande
+ *
+ * Contacts: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/delay.h>
+#include <linux/err.h>
+#include <linux/gpio.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+
+#include <video/panel-r61505.h>
+#include <video/panel-dbi.h>
+
+#define R61505_DEVICE_CODE			0x0000
+#define R61505_DEVICE_CODE_VALUE		0x1505
+#define R61505_DRIVER_OUTPUT_CONTROL		0x0001
+#define R61505_DRIVER_OUTPUT_CONTROL_SM		(1 << 10)
+#define R61505_DRIVER_OUTPUT_CONTROL_SS		(1 << 8)
+#define R61505_LCD_WAVEFORM			0x0002
+#define R61505_LCD_WAVEFORM_BC0			(1 << 9)
+#define R61505_LCD_WAVEFORM_EOR			(1 << 8)
+#define R61505_ENTRY_MODE			0x0003
+#define R61505_ENTRY_MODE_TRIREG		(1 << 15)
+#define R61505_ENTRY_MODE_DFM			(1 << 14)
+#define R61505_ENTRY_MODE_BGR			(1 << 12)
+#define R61505_ENTRY_MODE_HWM			(1 << 9)
+#define R61505_ENTRY_MODE_ORG			(1 << 7)
+#define R61505_ENTRY_MODE_ID1			(1 << 5)
+#define R61505_ENTRY_MODE_ID0			(1 << 4)
+#define R61505_ENTRY_MODE_AM			(1 << 3)
+#define R61505_RESIZE_CONTROL			0x0004
+#define R61505_RESIZE_CONTROL_RCV(n)		(((n) & 3) << 8)
+#define R61505_RESIZE_CONTROL_RCH(n)		(((n) & 3) << 4)
+#define R61505_RESIZE_CONTROL_RSZ_4		(3 << 0)
+#define R61505_RESIZE_CONTROL_RSZ_2		(1 << 0)
+#define R61505_RESIZE_CONTROL_RSZ_1		(0 << 0)
+#define R61505_DISPLAY_CONTROL1			0x0007
+#define R61505_DISPLAY_CONTROL1_PTDE1		(1 << 13)
+#define R61505_DISPLAY_CONTROL1_PTDE0		(1 << 12)
+#define R61505_DISPLAY_CONTROL1_BASEE		(1 << 8)
+#define R61505_DISPLAY_CONTROL1_VON		(1 << 6)
+#define R61505_DISPLAY_CONTROL1_GON		(1 << 5)
+#define R61505_DISPLAY_CONTROL1_DTE		(1 << 4)
+#define R61505_DISPLAY_CONTROL1_COL		(1 << 3)
+#define R61505_DISPLAY_CONTROL1_D1		(1 << 1)
+#define R61505_DISPLAY_CONTROL1_D0		(1 << 0)
+#define R61505_DISPLAY_CONTROL2			0x0008
+#define R61505_DISPLAY_CONTROL2_FP(n)		(((n) & 0xf) << 8)
+#define R61505_DISPLAY_CONTROL2_BP(n)		(((n) & 0xf) << 0)
+#define R61505_DISPLAY_CONTROL3			0x0009
+#define R61505_DISPLAY_CONTROL3_PTS(n)		(((n) & 7) << 8)
+#define R61505_DISPLAY_CONTROL3_PTG(n)		(((n) & 3) << 3)
+#define R61505_DISPLAY_CONTROL3_ICS(n)		(((n) & 0xf) << 0)
+#define R61505_DISPLAY_CONTROL4			0x000a
+#define R61505_DISPLAY_CONTROL4_FMARKOE		(1 << 3)
+#define R61505_DISPLAY_CONTROL4_FMI_6		(5 << 0)
+#define R61505_DISPLAY_CONTROL4_FMI_4		(3 << 0)
+#define R61505_DISPLAY_CONTROL4_FMI_2		(1 << 0)
+#define R61505_DISPLAY_CONTROL4_FMI_1		(0 << 0)
+#define R61505_EXT_DISPLAY_IF_CONTROL1		0x000c
+#define R61505_EXT_DISPLAY_IF_CONTROL1_ENC(n)	(((n) & 7) << 12)
+#define R61505_EXT_DISPLAY_IF_CONTROL1_RM	(1 << 8)
+#define R61505_EXT_DISPLAY_IF_CONTROL1_DM_VSYNC	(2 << 4)
+#define R61505_EXT_DISPLAY_IF_CONTROL1_DM_RGB	(1 << 4)
+#define R61505_EXT_DISPLAY_IF_CONTROL1_DM_ICLK	(0 << 4)
+#define R61505_EXT_DISPLAY_IF_CONTROL1_RIM_6	(2 << 0)
+#define R61505_EXT_DISPLAY_IF_CONTROL1_RIM_16	(1 << 0)
+#define R61505_EXT_DISPLAY_IF_CONTROL1_RIM_18	(0 << 0)
+#define R61505_FRAME_MARKER_CONTROL		0x000d
+#define R61505_FRAME_MARKER_CONTROL_FMP(n)	(((n) & 0x1ff) << 0)
+#define R61505_EXT_DISPLAY_IF_CONTROL2		0x000f
+#define R61505_POWER_CONTROL1			0x0010
+#define R61505_POWER_CONTROL1_SAP		(1 << 12)
+#define R61505_POWER_CONTROL1_BT(n)		(((n) & 0xf) << 8)
+#define R61505_POWER_CONTROL1_APE		(1 << 7)
+#define R61505_POWER_CONTROL1_AP_100		(3 << 4)
+#define R61505_POWER_CONTROL1_AP_075		(2 << 4)
+#define R61505_POWER_CONTROL1_AP_050		(1 << 4)
+#define R61505_POWER_CONTROL1_AP_HALT		(0 << 4)
+#define R61505_POWER_CONTROL1_DSTB		(1 << 2)
+#define R61505_POWER_CONTROL1_SLP		(1 << 1)
+#define R61505_POWER_CONTROL2			0x0011
+#define R61505_POWER_CONTROL2_DC1_HALT		(6 << 8)
+#define R61505_POWER_CONTROL2_DC1_FOSC_256	(4 << 8)
+#define R61505_POWER_CONTROL2_DC1_FOSC_128	(3 << 8)
+#define R61505_POWER_CONTROL2_DC1_FOSC_64	(2 << 8)
+#define R61505_POWER_CONTROL2_DC1_FOSC_32	(1 << 8)
+#define R61505_POWER_CONTROL2_DC1_FOSC_16	(0 << 8)
+#define R61505_POWER_CONTROL2_DC0_HALT		(6 << 4)
+#define R61505_POWER_CONTROL2_DC0_FOSC_16	(4 << 4)
+#define R61505_POWER_CONTROL2_DC0_FOSC_8	(3 << 4)
+#define R61505_POWER_CONTROL2_DC0_FOSC_4	(2 << 4)
+#define R61505_POWER_CONTROL2_DC0_FOSC_2	(1 << 4)
+#define R61505_POWER_CONTROL2_DC0_FOSC		(0 << 4)
+#define R61505_POWER_CONTROL2_VC_100		(7 << 0)
+#define R61505_POWER_CONTROL2_VC_076		(4 << 0)
+#define R61505_POWER_CONTROL2_VC_089		(1 << 0)
+#define R61505_POWER_CONTROL2_VC_094		(0 << 0)
+#define R61505_POWER_CONTROL3			0x0012
+#define R61505_POWER_CONTROL3_VCMR		(1 << 8)
+#define R61505_POWER_CONTROL3_PSON		(1 << 5)
+#define R61505_POWER_CONTROL3_PON		(1 << 4)
+#define R61505_POWER_CONTROL3_VRH(n)		(((n) & 0xf) << 0)
+#define R61505_POWER_CONTROL4			0x0013
+#define R61505_POWER_CONTROL4_VDV(n)		(((n) & 0xf) << 8)
+#define R61505_POWER_CONTROL5			0x0015
+#define R61505_POWER_CONTROL5_BLDM		(1 << 12)
+#define R61505_POWER_CONTROL6			0x0017
+#define R61505_POWER_CONTROL6_PSE		(1 << 0)
+#define R61505_RAM_ADDR_HORZ			0x0020
+#define R61505_RAM_ADDR_VERT			0x0021
+#define R61505_RAM_DATA				0x0022
+#define R61505_POWER_CONTROL7			0x0029
+#define R61505_POWER_CONTROL7_VCM1(n)		(((n) & 0x1f) << 0)
+#define R61505_GAMMA_CONTROL1			0x0030
+#define R61505_GAMMA_CONTROL2			0x0031
+#define R61505_GAMMA_CONTROL3			0x0032
+#define R61505_GAMMA_CONTROL4			0x0033
+#define R61505_GAMMA_CONTROL5			0x0034
+#define R61505_GAMMA_CONTROL6			0x0035
+#define R61505_GAMMA_CONTROL7			0x0036
+#define R61505_GAMMA_CONTROL8			0x0037
+#define R61505_GAMMA_CONTROL9			0x0038
+#define R61505_GAMMA_CONTROL10			0x0039
+#define R61505_GAMMA_CONTROL11			0x003a
+#define R61505_GAMMA_CONTROL12			0x003b
+#define R61505_GAMMA_CONTROL13			0x003c
+#define R61505_GAMMA_CONTROL14			0x003d
+#define R61505_WINDOW_HORZ_START		0x0050
+#define R61505_WINDOW_HORZ_END			0x0051
+#define R61505_WINDOW_VERT_START		0x0052
+#define R61505_WINDOW_VERT_END			0x0053
+#define R61505_DRIVER_OUTPUT_CONTROL2		0x0060
+#define R61505_DRIVER_OUTPUT_CONTROL2_GS	(1 << 15)
+#define R61505_DRIVER_OUTPUT_CONTROL2_NL(n)	(((n) & 0x3f) << 8)
+#define R61505_DRIVER_OUTPUT_CONTROL2_SCN(n)	(((n) & 0x3f) << 0)
+#define R61505_BASE_IMG_DISPLAY_CONTROL		0x0061
+#define R61505_BASE_IMG_DISPLAY_CONTROL_NDL	(1 << 2)
+#define R61505_BASE_IMG_DISPLAY_CONTROL_VLE	(1 << 1)
+#define R61505_BASE_IMG_DISPLAY_CONTROL_REV	(1 << 0)
+#define R61505_VERTICAL_SCROLL_CONTROL		0x006a
+#define R61505_PANEL_IF_CONTROL1		0x0090
+#define R61505_PANEL_IF_CONTROL1_DIVI(n)	(((n) & 3) << 8)
+#define R61505_PANEL_IF_CONTROL1_RTNI(n)	(((n) & 0x1f) << 0)
+#define R61505_PANEL_IF_CONTROL2		0x0092
+#define R61505_PANEL_IF_CONTROL2_NOWI(n)	(((n) & 7) << 8)
+#define R61505_PANEL_IF_CONTROL3		0x0093
+#define R61505_PANEL_IF_CONTROL3_MCP(n)		(((n) & 7) << 8)
+#define R61505_PANEL_IF_CONTROL4		0x0095
+#define R61505_PANEL_IF_CONTROL5		0x0097
+#define R61505_PANEL_IF_CONTROL6		0x0098
+#define R61505_OSCILLATION_CONTROL		0x00a4
+#define R61505_OSCILLATION_CONTROL_CALB		(1 << 0)
+
+struct r61505 {
+	struct panel panel;
+	struct panel_dbi_device *dbi;
+	const struct panel_r61505_platform_data *pdata;
+};
+
+#define to_panel(p)	container_of(p, struct r61505, panel)
+
+/* -----------------------------------------------------------------------------
+ * Read, write and reset
+ */
+
+/* DB0-DB7 are connected to D1-D8, and DB8-DB15 to D10-D17 */
+
+static unsigned long adjust_reg18(u16 data)
+{
+	return (((data << 1) | 0x00000001) & 0x000001ff) |
+	       (((data << 2) | 0x00000200) & 0x0003fe00);
+}
+
+static void r61505_write_command(struct r61505 *panel, u16 reg)
+{
+	panel_dbi_write_command(panel->dbi, adjust_reg18(reg));
+}
+
+static void r61505_write(struct r61505 *panel, u16 reg, u16 data)
+{
+	panel_dbi_write_command(panel->dbi, adjust_reg18(reg));
+	panel_dbi_write_data(panel->dbi, adjust_reg18(data));
+}
+
+static u16 r61505_read(struct r61505 *panel, u16 reg)
+{
+	unsigned long data;
+
+	panel_dbi_write_command(panel->dbi, adjust_reg18(reg));
+	data = panel_dbi_read_data(panel->dbi);
+
+	return ((data >> 1) & 0xff) | ((data >> 2) & 0xff00);
+}
+
+static void r61505_write_array(struct r61505 *panel,
+				 const u16 *data, unsigned int len)
+{
+	unsigned int i;
+
+	for (i = 0; i < len; i += 2)
+		r61505_write(panel, data[i], data[i + 1]);
+}
+
+static void r61505_reset(struct r61505 *panel)
+{
+	if (panel->pdata->reset < 0)
+		return;
+
+	gpio_set_value(panel->pdata->reset, 0);
+	usleep_range(2000, 2500);
+	gpio_set_value(panel->pdata->reset, 1);
+	usleep_range(1000, 1500);
+}
+
+/* -----------------------------------------------------------------------------
+ * Configuration
+ */
+
+static const unsigned short sync_data[] = {
+	0x0000, 0x0000,
+	0x0000, 0x0000,
+	0x0000, 0x0000,
+	0x0000, 0x0000,
+};
+
+static const unsigned short magic0_data[] = {
+	R61505_DISPLAY_CONTROL2, R61505_DISPLAY_CONTROL2_FP(8) |
+				 R61505_DISPLAY_CONTROL2_BP(8),
+	R61505_PANEL_IF_CONTROL1, R61505_PANEL_IF_CONTROL1_RTNI(26),
+	R61505_DISPLAY_CONTROL1, R61505_DISPLAY_CONTROL1_D0,
+	R61505_POWER_CONTROL6, R61505_POWER_CONTROL6_PSE,
+	0x0019, 0x0000,
+	R61505_POWER_CONTROL1, R61505_POWER_CONTROL1_SAP |
+			       R61505_POWER_CONTROL1_BT(7) |
+			       R61505_POWER_CONTROL1_APE |
+			       R61505_POWER_CONTROL1_AP_100,
+	R61505_POWER_CONTROL2, R61505_POWER_CONTROL2_DC1_FOSC_32 |
+			       R61505_POWER_CONTROL2_DC0_FOSC_2 | 6,
+	R61505_POWER_CONTROL3, R61505_POWER_CONTROL3_VCMR | 0x80 |
+			       R61505_POWER_CONTROL3_PON |
+			       R61505_POWER_CONTROL3_VRH(8),
+	R61505_POWER_CONTROL4, 0x1000 | R61505_POWER_CONTROL4_VDV(4),
+	R61505_POWER_CONTROL7, R61505_POWER_CONTROL7_VCM1(12),
+	R61505_POWER_CONTROL3, R61505_POWER_CONTROL3_VCMR | 0x80 |
+			       R61505_POWER_CONTROL3_PSON |
+			       R61505_POWER_CONTROL3_PON |
+			       R61505_POWER_CONTROL3_VRH(8),
+};
+
+static const unsigned short magic1_data[] = {
+	R61505_GAMMA_CONTROL1, 0x0307,
+	R61505_GAMMA_CONTROL2, 0x0303,
+	R61505_GAMMA_CONTROL3, 0x0603,
+	R61505_GAMMA_CONTROL4, 0x0202,
+	R61505_GAMMA_CONTROL5, 0x0202,
+	R61505_GAMMA_CONTROL6, 0x0202,
+	R61505_GAMMA_CONTROL7, 0x1f1f,
+	R61505_GAMMA_CONTROL8, 0x0303,
+	R61505_GAMMA_CONTROL9, 0x0303,
+	R61505_GAMMA_CONTROL10, 0x0603,
+	R61505_GAMMA_CONTROL11, 0x0202,
+	R61505_GAMMA_CONTROL12, 0x0102,
+	R61505_GAMMA_CONTROL13, 0x0204,
+	R61505_GAMMA_CONTROL14, 0x0000,
+	R61505_DRIVER_OUTPUT_CONTROL, R61505_DRIVER_OUTPUT_CONTROL_SS,
+	R61505_LCD_WAVEFORM, R61505_LCD_WAVEFORM_BC0 |
+			     R61505_LCD_WAVEFORM_EOR,
+	R61505_ENTRY_MODE, R61505_ENTRY_MODE_DFM |
+			   R61505_ENTRY_MODE_BGR |
+			   R61505_ENTRY_MODE_ID1 |
+			   R61505_ENTRY_MODE_AM,
+	R61505_RAM_ADDR_HORZ, 239,
+	R61505_RAM_ADDR_VERT, 0,
+	R61505_RESIZE_CONTROL, R61505_RESIZE_CONTROL_RCV(0) |
+			       R61505_RESIZE_CONTROL_RCH(0) |
+			       R61505_RESIZE_CONTROL_RSZ_1,
+	R61505_DISPLAY_CONTROL3, R61505_DISPLAY_CONTROL3_PTS(0) |
+				 R61505_DISPLAY_CONTROL3_PTG(0) |
+				 R61505_DISPLAY_CONTROL3_ICS(0),
+	R61505_DISPLAY_CONTROL4, R61505_DISPLAY_CONTROL4_FMARKOE |
+				 R61505_DISPLAY_CONTROL4_FMI_1,
+	R61505_EXT_DISPLAY_IF_CONTROL1, R61505_EXT_DISPLAY_IF_CONTROL1_ENC(0) |
+					R61505_EXT_DISPLAY_IF_CONTROL1_DM_ICLK |
+					R61505_EXT_DISPLAY_IF_CONTROL1_RIM_18,
+	R61505_FRAME_MARKER_CONTROL, R61505_FRAME_MARKER_CONTROL_FMP(0),
+	R61505_POWER_CONTROL5, 0x8000,
+};
+
+static const unsigned short magic2_data[] = {
+	R61505_BASE_IMG_DISPLAY_CONTROL, R61505_BASE_IMG_DISPLAY_CONTROL_REV,
+	R61505_PANEL_IF_CONTROL2, R61505_PANEL_IF_CONTROL2_NOWI(1),
+	R61505_PANEL_IF_CONTROL3, R61505_PANEL_IF_CONTROL3_MCP(1),
+	R61505_DISPLAY_CONTROL1, R61505_DISPLAY_CONTROL1_GON |
+				 R61505_DISPLAY_CONTROL1_D0,
+};
+
+static const unsigned short magic3_data[] = {
+	R61505_POWER_CONTROL1, R61505_POWER_CONTROL1_SAP |
+			       R61505_POWER_CONTROL1_BT(6) |
+			       R61505_POWER_CONTROL1_APE |
+			       R61505_POWER_CONTROL1_AP_100,
+	R61505_POWER_CONTROL2, R61505_POWER_CONTROL2_DC1_FOSC_32 |
+			       R61505_POWER_CONTROL2_DC0_FOSC_2 |
+			       R61505_POWER_CONTROL2_VC_089,
+	R61505_DISPLAY_CONTROL1, R61505_DISPLAY_CONTROL1_VON |
+				 R61505_DISPLAY_CONTROL1_GON |
+				 R61505_DISPLAY_CONTROL1_D0,
+};
+
+static void r61505_enable_panel(struct r61505 *panel)
+{
+	unsigned long xres = panel->pdata->mode->xres;
+	unsigned long yres = panel->pdata->mode->yres;
+	unsigned int i;
+
+	r61505_write_array(panel, sync_data, ARRAY_SIZE(sync_data));
+
+	r61505_write(panel, R61505_OSCILLATION_CONTROL,
+		     R61505_OSCILLATION_CONTROL_CALB);
+	usleep_range(10000, 11000);
+
+	r61505_write(panel, R61505_DRIVER_OUTPUT_CONTROL2,
+		     R61505_DRIVER_OUTPUT_CONTROL2_NL((xres / 8) - 1));
+	r61505_write_array(panel, magic0_data, ARRAY_SIZE(magic0_data));
+	usleep_range(100000, 101000);
+
+	r61505_write_array(panel, magic1_data, ARRAY_SIZE(magic1_data));
+
+	r61505_write(panel, R61505_WINDOW_HORZ_START, 239 - (yres - 1));
+	r61505_write(panel, R61505_WINDOW_HORZ_END, 239);
+	r61505_write(panel, R61505_WINDOW_VERT_START, 0);
+	r61505_write(panel, R61505_WINDOW_VERT_END, xres - 1);
+
+	r61505_write_array(panel, magic2_data, ARRAY_SIZE(magic2_data));
+	usleep_range(10000, 11000);
+
+	r61505_write_array(panel, magic3_data, ARRAY_SIZE(magic3_data));
+	usleep_range(40000, 41000);
+
+	/* Clear GRAM to avoid displaying garbage. */
+	r61505_write(panel, R61505_RAM_ADDR_HORZ, 0);
+	r61505_write(panel, R61505_RAM_ADDR_VERT, 0);
+
+	for (i = 0; i < (xres * 256); i++) /* yes, 256 words per line */
+		r61505_write(panel, R61505_RAM_DATA, 0);
+
+	r61505_write(panel, R61505_RAM_ADDR_HORZ, 0);
+	r61505_write(panel, R61505_RAM_ADDR_VERT, 0);
+}
+
+static void r61505_disable_panel(struct r61505 *panel)
+{
+	r61505_reset(panel);
+}
+
+static void r61505_display_on(struct r61505 *panel)
+{
+	r61505_write(panel, R61505_DISPLAY_CONTROL1,
+		     R61505_DISPLAY_CONTROL1_BASEE |
+		     R61505_DISPLAY_CONTROL1_VON |
+		     R61505_DISPLAY_CONTROL1_GON |
+		     R61505_DISPLAY_CONTROL1_DTE |
+		     R61505_DISPLAY_CONTROL1_D1 |
+		     R61505_DISPLAY_CONTROL1_D0);
+	usleep_range(40000, 41000);
+}
+
+static void r61505_display_off(struct r61505 *panel)
+{
+	r61505_write(panel, R61505_DISPLAY_CONTROL1,
+		     R61505_DISPLAY_CONTROL1_VON |
+		     R61505_DISPLAY_CONTROL1_GON |
+		     R61505_DISPLAY_CONTROL1_D0);
+}
+
+/* -----------------------------------------------------------------------------
+ * Panel operations
+ */
+
+static int r61505_enable(struct panel *p, enum panel_enable_mode enable)
+{
+	struct r61505 *panel = to_panel(p);
+
+	switch (enable) {
+	case PANEL_ENABLE_OFF:
+		r61505_disable_panel(panel);
+		break;
+
+	case PANEL_ENABLE_BLANK:
+		if (p->enable = PANEL_ENABLE_OFF)
+			r61505_enable_panel(panel);
+		else
+			r61505_display_off(panel);
+		break;
+
+	case PANEL_ENABLE_ON:
+		if (p->enable = PANEL_ENABLE_OFF)
+			r61505_enable_panel(panel);
+
+		r61505_display_on(panel);
+		break;
+	}
+
+	return 0;
+}
+
+static int r61505_start_transfer(struct panel *p)
+{
+	struct r61505 *panel = to_panel(p);
+
+	r61505_write_command(panel, R61505_RAM_DATA);
+	usleep_range(100000, 101000);
+
+	return 0;
+}
+
+static int r61505_get_modes(struct panel *p, const struct fb_videomode **modes)
+{
+	struct r61505 *panel = to_panel(p);
+
+	*modes = panel->pdata->mode;
+	return 1;
+}
+
+static const struct panel_ops r61505_ops = {
+	.enable = r61505_enable,
+	.start_transfer = r61505_start_transfer,
+	.get_modes = r61505_get_modes,
+};
+
+static void r61505_release(struct panel *p)
+{
+	struct r61505 *panel = to_panel(p);
+
+	kfree(panel);
+}
+
+static int r61505_remove(struct panel_dbi_device *dev)
+{
+	struct r61505 *panel = panel_dbi_get_drvdata(dev);
+
+	panel_dbi_set_drvdata(dev, NULL);
+	panel_unregister(&panel->panel);
+
+	return 0;
+}
+
+static int __devinit r61505_probe(struct panel_dbi_device *dev)
+{
+	const struct panel_r61505_platform_data *pdata = dev->dev.platform_data;
+	struct r61505 *panel;
+	int ret;
+
+	if (pdata = NULL)
+		return -ENODEV;
+
+	panel = kzalloc(sizeof(*panel), GFP_KERNEL);
+	if (panel = NULL)
+		return -ENOMEM;
+
+	panel->pdata = pdata;
+	panel->dbi = dev;
+
+	r61505_reset(panel);
+	r61505_write_array(panel, sync_data, ARRAY_SIZE(sync_data));
+
+	if (r61505_read(panel, 0) != R61505_DEVICE_CODE_VALUE) {
+		kfree(panel);
+		return -ENODEV;
+	}
+
+	panel->panel.dev = &dev->dev;
+	panel->panel.release = r61505_release;
+	panel->panel.ops = &r61505_ops;
+	panel->panel.width = pdata->width;
+	panel->panel.height = pdata->height;
+
+	ret = panel_register(&panel->panel);
+	if (ret < 0) {
+		kfree(panel);
+		return ret;
+	}
+
+	panel_dbi_set_drvdata(dev, panel);
+
+	return 0;
+}
+
+static const struct dev_pm_ops r61505_dev_pm_ops = {
+};
+
+static struct panel_dbi_driver r61505_driver = {
+	.probe = r61505_probe,
+	.remove = r61505_remove,
+	.driver = {
+		.name = "panel_r61505",
+		.owner = THIS_MODULE,
+		.pm = &r61505_dev_pm_ops,
+	},
+};
+
+module_panel_dbi_driver(r61505_driver);
+
+MODULE_AUTHOR("Laurent Pinchart <laurent.pinchart@ideasonboard.com>");
+MODULE_DESCRIPTION("Renesas R61505-based Display Panel");
+MODULE_LICENSE("GPL");
diff --git a/include/video/panel-r61505.h b/include/video/panel-r61505.h
new file mode 100644
index 0000000..90b3d62
--- /dev/null
+++ b/include/video/panel-r61505.h
@@ -0,0 +1,27 @@
+/*
+ * Renesas R61505-based Display Panels
+ *
+ * Copyright (C) 2012 Renesas Solutions Corp.
+ *
+ * Contacts: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#ifndef __PANEL_R61505_H__
+#define __PANEL_R61505_H__
+
+#include <linux/fb.h>
+#include <video/panel.h>
+
+struct panel_r61505_platform_data {
+	unsigned long width;		/* Panel width in mm */
+	unsigned long height;		/* Panel height in mm */
+	const struct fb_videomode *mode;
+
+	int reset;			/* Reset GPIO */
+};
+
+#endif /* __PANEL_R61505_H__ */
-- 
1.7.8.6


  parent reply	other threads:[~2012-08-17  0:49 UTC|newest]

Thread overview: 75+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2012-08-17  0:49 [RFC 0/5] Generic panel framework Laurent Pinchart
2012-08-17  0:49 ` Laurent Pinchart
2012-08-17  0:49 ` [RFC 1/5] video: Add generic display panel core Laurent Pinchart
2012-08-17  0:49   ` Laurent Pinchart
2012-09-04  9:24   ` Sascha Hauer
2012-09-04  9:24     ` Sascha Hauer
2012-09-13  1:40     ` Laurent Pinchart
2012-09-13  1:40       ` Laurent Pinchart
2012-09-13 11:29       ` Sascha Hauer
2012-09-13 11:29         ` Sascha Hauer
2012-09-13 19:32         ` Robert Schwebel
2012-09-13 19:32           ` Robert Schwebel
2012-08-17  0:49 ` [RFC 2/5] video: panel: Add dummy panel support Laurent Pinchart
2012-08-17  0:49   ` Laurent Pinchart
2012-08-17  0:49 ` [RFC 3/5] video: panel: Add MIPI DBI bus support Laurent Pinchart
2012-08-17  0:49   ` Laurent Pinchart
2012-08-17  9:03   ` Tomi Valkeinen
2012-08-17  9:03     ` Tomi Valkeinen
2012-08-17 10:02     ` Laurent Pinchart
2012-08-17 10:02       ` Laurent Pinchart
2012-08-17 10:51       ` Tomi Valkeinen
2012-08-17 10:51         ` Tomi Valkeinen
2012-08-17 12:33         ` Laurent Pinchart
2012-08-17 12:33           ` Laurent Pinchart
2012-08-17 13:06           ` Tomi Valkeinen
2012-08-17 13:06             ` Tomi Valkeinen
2012-08-17 14:06             ` Laurent Pinchart
2012-08-17 14:06               ` Laurent Pinchart
2012-08-17  0:49 ` Laurent Pinchart [this message]
2012-08-17  0:49   ` [RFC 4/5] video: panel: Add R61505 panel support Laurent Pinchart
2012-08-17  0:49 ` [RFC 5/5] video: panel: Add R61517 " Laurent Pinchart
2012-08-17  0:49   ` Laurent Pinchart
2012-08-17  1:33 ` [RFC 0/5] Generic panel framework Jingoo Han
2012-08-17  1:33   ` Jingoo Han
2012-08-17  8:38 ` Tomi Valkeinen
2012-08-17  8:38   ` Tomi Valkeinen
2012-08-17 11:10   ` Laurent Pinchart
2012-08-17 11:10     ` Laurent Pinchart
2012-08-17 11:42     ` Tomi Valkeinen
2012-08-17 11:42       ` Tomi Valkeinen
2012-08-18  1:16       ` Laurent Pinchart
2012-08-18  1:16         ` Laurent Pinchart
2012-08-18  1:16         ` Laurent Pinchart
2012-08-20 11:39         ` Tomi Valkeinen
2012-08-20 11:39           ` Tomi Valkeinen
2012-08-20 23:29           ` Laurent Pinchart
2012-08-20 23:29             ` Laurent Pinchart
2012-08-20 23:29             ` Laurent Pinchart
2012-08-21  5:49             ` Tomi Valkeinen
2012-08-21  5:49               ` Tomi Valkeinen
2012-08-21  9:23               ` Laurent Pinchart
2012-08-21  9:23                 ` Laurent Pinchart
2012-08-23  6:23                 ` Jun Nie
2012-08-23  6:23                   ` Jun Nie
2012-09-04  8:20                   ` Zhou Zhu
2012-09-04  8:20                     ` Zhou Zhu
2012-10-30 16:35                     ` Laurent Pinchart
2012-10-30 16:35                       ` Laurent Pinchart
2012-10-30 16:23                   ` Laurent Pinchart
2012-10-30 16:23                     ` Laurent Pinchart
2012-10-20 14:18   ` Inki Dae
2012-10-20 14:18     ` Inki Dae
2012-09-19 11:45 ` Tomi Valkeinen
2012-09-19 11:45   ` Tomi Valkeinen
2012-10-31 13:13   ` Laurent Pinchart
2012-10-31 13:13     ` Laurent Pinchart
2012-10-31 14:20     ` Tomi Valkeinen
2012-10-31 14:20       ` Tomi Valkeinen
2012-10-31 14:20       ` Tomi Valkeinen
2012-10-20 13:10 ` Inki Dae
2012-10-20 13:10   ` Inki Dae
2012-10-20 14:22   ` Inki Dae
2012-10-20 14:22     ` Inki Dae
2012-10-31 13:28   ` Laurent Pinchart
2012-10-31 13:28     ` Laurent Pinchart

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=1345164583-18924-5-git-send-email-laurent.pinchart@ideasonboard.com \
    --to=laurent.pinchart@ideasonboard.com \
    --cc=archit@ti.com \
    --cc=bryan.wu@canonical.com \
    --cc=dri-devel@lists.freedesktop.org \
    --cc=inki.dae@samsung.com \
    --cc=kyungmin.park@samsung.com \
    --cc=linux-fbdev@vger.kernel.org \
    --cc=linux-leds@vger.kernel.org \
    --cc=linux-media@vger.kernel.org \
    --cc=marcus.lorentzon@linaro.org \
    --cc=rpurdie@rpsys.net \
    --cc=s-guiriec@ti.com \
    --cc=sumit.semwal@ti.com \
    --cc=tomi.valkeinen@ti.com \
    /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.