From: Laurent Pinchart <laurent.pinchart@ideasonboard.com> To: linux-fbdev@vger.kernel.org, dri-devel@lists.freedesktop.org Cc: linux-media@vger.kernel.org, Archit Taneja <archit@ti.com>, Benjamin Gaignard <benjamin.gaignard@linaro.org>, Bryan Wu <bryan.wu@canonical.com>, Inki Dae <inki.dae@samsung.com>, Jesse Barker <jesse.barker@linaro.org>, Kyungmin Park <kyungmin.park@samsung.com>, Marcus Lorentzon <marcus.xm.lorentzon@stericsson.com>, Maxime Ripard <maxime.ripard@free-electrons.com>, Philipp Zabel <p.zabel@pengutronix.de>, Ragesh Radhakrishnan <ragesh.r@linaro.org>, Rob Clark <rob.clark@linaro.org>, Sascha Hauer <s.hauer@pengutronix.de>, Sebastien Guiriec <s-guiriec@ti.com>, Sumit Semwal <sumit.semwal@linaro.org>, Thomas Petazzoni <thomas.petazzoni@free-electrons.com>, Tom Gall <tom.gall@linaro.org>, Tomi Valkeinen <tomi.valkeinen@ti.com>, Vikas Sajjan <vikas.sajjan@linaro.org> Subject: [RFC v2 4/5] video: panel: Add R61505 panel support Date: Thu, 22 Nov 2012 22:45:35 +0100 [thread overview] Message-ID: <1353620736-6517-5-git-send-email-laurent.pinchart@ideasonboard.com> (raw) In-Reply-To: <1353620736-6517-1-git-send-email-laurent.pinchart@ideasonboard.com> From: Laurent Pinchart <laurent.pinchart+renesas@ideasonboard.com> The R61505 is a SYS-80 bus panel controller from Renesas. Signed-off-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com> --- drivers/video/display/Kconfig | 9 + drivers/video/display/Makefile | 1 + drivers/video/display/panel-r61505.c | 554 ++++++++++++++++++++++++++++++++++ include/video/panel-r61505.h | 27 ++ 4 files changed, 591 insertions(+), 0 deletions(-) create mode 100644 drivers/video/display/panel-r61505.c create mode 100644 include/video/panel-r61505.h diff --git a/drivers/video/display/Kconfig b/drivers/video/display/Kconfig index b04c8be..c88999c 100644 --- a/drivers/video/display/Kconfig +++ b/drivers/video/display/Kconfig @@ -18,4 +18,13 @@ config DISPLAY_PANEL_DPI If you are in doubt, say N. +config DISPLAY_PANEL_R61505 + tristate "Renesas R61505-based Display Panel" + select DISPLAY_MIPI_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_CORE diff --git a/drivers/video/display/Makefile b/drivers/video/display/Makefile index 00ef1c2..4c68465 100644 --- a/drivers/video/display/Makefile +++ b/drivers/video/display/Makefile @@ -1,3 +1,4 @@ obj-$(CONFIG_DISPLAY_CORE) += display-core.o obj-$(CONFIG_DISPLAY_MIPI_DBI) += mipi-dbi-bus.o obj-$(CONFIG_DISPLAY_PANEL_DPI) += panel-dpi.o +obj-$(CONFIG_DISPLAY_PANEL_R61505) += panel-r61505.o diff --git a/drivers/video/display/panel-r61505.c b/drivers/video/display/panel-r61505.c new file mode 100644 index 0000000..d72d324 --- /dev/null +++ b/drivers/video/display/panel-r61505.c @@ -0,0 +1,554 @@ +/* + * 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 <linux/slab.h> + +#include <video/display.h> +#include <video/mipi-dbi-bus.h> +#include <video/panel-r61505.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 display_entity entity; + struct mipi_dbi_device *dbi; + const struct panel_r61505_platform_data *pdata; +}; + +#define to_panel(p) container_of(p, struct r61505, entity) + +/* ----------------------------------------------------------------------------- + * Read, write and reset + */ + +static void r61505_write(struct r61505 *panel, u16 reg, u16 data) +{ + u8 buffer[2] = { data >> 8, data & 0xff }; + + mipi_dbi_write_command(panel->dbi, reg); + mipi_dbi_write_data(panel->dbi, buffer, 2); +} + +static u16 r61505_read(struct r61505 *panel, u16 reg) +{ + u8 buffer[2]; + int ret; + + mipi_dbi_write_command(panel->dbi, reg); + ret = mipi_dbi_read_data(panel->dbi, buffer, 2); + if (ret < 0) + return ret; + + return (buffer[0] << 8) | buffer[1]; +} + +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 hactive = panel->pdata->mode->hactive; + unsigned long vactive = panel->pdata->mode->vactive; + 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((hactive / 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 - (vactive - 1)); + r61505_write(panel, R61505_WINDOW_HORZ_END, 239); + r61505_write(panel, R61505_WINDOW_VERT_START, 0); + r61505_write(panel, R61505_WINDOW_VERT_END, hactive - 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 < (hactive * 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 const struct display_entity_interface_params r61505_dbi_params = { + .type = DISPLAY_ENTITY_INTERFACE_DBI, + .p.dbi = { + .type = MIPI_DBI_INTERFACE_TYPE_B, + .cs_setup = 1, + .wr_setup = 0, + .wr_cycle = 10, + .wr_hold = 9, + .rd_setup = 14, + .rd_latch = 24, + .rd_cycle = 52, + .rd_hold = 24, + }, +}; + +static int r61505_set_state(struct display_entity *entity, + enum display_entity_state state) +{ + struct r61505 *panel = to_panel(entity); + + switch (state) { + case DISPLAY_ENTITY_STATE_OFF: + r61505_disable_panel(panel); + break; + + case DISPLAY_ENTITY_STATE_STANDBY: + if (entity->state == DISPLAY_ENTITY_STATE_OFF) + r61505_enable_panel(panel); + else + r61505_display_off(panel); + break; + + case DISPLAY_ENTITY_STATE_ON: + if (entity->state == DISPLAY_ENTITY_STATE_OFF) + r61505_enable_panel(panel); + + r61505_display_on(panel); + break; + } + + return 0; +} + +static int r61505_update(struct display_entity *entity) +{ + struct r61505 *panel = to_panel(entity); + + mipi_dbi_write_command(panel->dbi, R61505_RAM_DATA); + usleep_range(100000, 101000); + + display_entity_set_stream(entity->source, + DISPLAY_ENTITY_STREAM_SINGLE_SHOT); + return 0; +} + +static int r61505_get_modes(struct display_entity *entity, + const struct videomode **modes) +{ + struct r61505 *panel = to_panel(entity); + + *modes = panel->pdata->mode; + return 1; +} + +static int r61505_get_size(struct display_entity *entity, + unsigned int *width, unsigned int *height) +{ + struct r61505 *panel = to_panel(entity); + + *width = panel->pdata->width; + *height = panel->pdata->height; + return 0; +} + +static int r61505_get_params(struct display_entity *entity, + struct display_entity_interface_params *params) +{ + *params = r61505_dbi_params; + return 0; +} + +static const struct display_entity_control_ops r61505_control_ops = { + .set_state = r61505_set_state, + .update = r61505_update, + .get_modes = r61505_get_modes, + .get_size = r61505_get_size, + .get_params = r61505_get_params, +}; + +static void r61505_release(struct display_entity *entity) +{ + struct r61505 *panel = to_panel(entity); + + kfree(panel); +} + +static int r61505_remove(struct mipi_dbi_device *dev) +{ + struct r61505 *panel = mipi_dbi_get_drvdata(dev); + + mipi_dbi_set_drvdata(dev, NULL); + display_entity_unregister(&panel->entity); + + return 0; +} + +static int __devinit r61505_probe(struct mipi_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; + + dev->flags = MIPI_DBI_FLAG_ALIGN_LEFT; + dev->bus_width = pdata->bus_width; + mipi_dbi_set_data_width(dev, 16); + + 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->entity.dev = &dev->dev; + panel->entity.release = r61505_release; + panel->entity.ops.ctrl = &r61505_control_ops; + + ret = display_entity_register(&panel->entity); + if (ret < 0) { + kfree(panel); + return ret; + } + + mipi_dbi_set_drvdata(dev, panel); + + return 0; +} + +static const struct dev_pm_ops r61505_dev_pm_ops = { +}; + +static struct mipi_dbi_driver r61505_driver = { + .probe = r61505_probe, + .remove = r61505_remove, + .driver = { + .name = "panel_r61505", + .owner = THIS_MODULE, + .pm = &r61505_dev_pm_ops, + }, +}; + +module_mipi_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..fe4a368 --- /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/videomode.h> + +struct panel_r61505_platform_data { + unsigned long width; /* Panel width in mm */ + unsigned long height; /* Panel height in mm */ + const struct videomode *mode; + + unsigned int bus_width; + 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 Cc: linux-media@vger.kernel.org, Archit Taneja <archit@ti.com>, Benjamin Gaignard <benjamin.gaignard@linaro.org>, Bryan Wu <bryan.wu@canonical.com>, Inki Dae <inki.dae@samsung.com>, Jesse Barker <jesse.barker@linaro.org>, Kyungmin Park <kyungmin.park@samsung.com>, Marcus Lorentzon <marcus.xm.lorentzon@stericsson.com>, Maxime Ripard <maxime.ripard@free-electrons.com>, Philipp Zabel <p.zabel@pengutronix.de>, Ragesh Radhakrishnan <ragesh.r@linaro.org>, Rob Clark <rob.clark@linaro.org>, Sascha Hauer <s.hauer@pengutronix.de>, Sebastien Guiriec <s-guiriec@ti.com>, Sumit Semwal <sumit.semwal@linaro.org>, Thomas Petazzoni <thomas.petazzoni@free-electrons.com>, Tom Gall <tom.gall@linaro.org>, Tomi Valkeinen <tomi.valkeinen@ti.com>, Vikas Sajjan <vikas.sajjan@linaro.org> Subject: [RFC v2 4/5] video: panel: Add R61505 panel support Date: Thu, 22 Nov 2012 21:45:35 +0000 [thread overview] Message-ID: <1353620736-6517-5-git-send-email-laurent.pinchart@ideasonboard.com> (raw) In-Reply-To: <1353620736-6517-1-git-send-email-laurent.pinchart@ideasonboard.com> From: Laurent Pinchart <laurent.pinchart+renesas@ideasonboard.com> The R61505 is a SYS-80 bus panel controller from Renesas. Signed-off-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com> --- drivers/video/display/Kconfig | 9 + drivers/video/display/Makefile | 1 + drivers/video/display/panel-r61505.c | 554 ++++++++++++++++++++++++++++++++++ include/video/panel-r61505.h | 27 ++ 4 files changed, 591 insertions(+), 0 deletions(-) create mode 100644 drivers/video/display/panel-r61505.c create mode 100644 include/video/panel-r61505.h diff --git a/drivers/video/display/Kconfig b/drivers/video/display/Kconfig index b04c8be..c88999c 100644 --- a/drivers/video/display/Kconfig +++ b/drivers/video/display/Kconfig @@ -18,4 +18,13 @@ config DISPLAY_PANEL_DPI If you are in doubt, say N. +config DISPLAY_PANEL_R61505 + tristate "Renesas R61505-based Display Panel" + select DISPLAY_MIPI_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_CORE diff --git a/drivers/video/display/Makefile b/drivers/video/display/Makefile index 00ef1c2..4c68465 100644 --- a/drivers/video/display/Makefile +++ b/drivers/video/display/Makefile @@ -1,3 +1,4 @@ obj-$(CONFIG_DISPLAY_CORE) += display-core.o obj-$(CONFIG_DISPLAY_MIPI_DBI) += mipi-dbi-bus.o obj-$(CONFIG_DISPLAY_PANEL_DPI) += panel-dpi.o +obj-$(CONFIG_DISPLAY_PANEL_R61505) += panel-r61505.o diff --git a/drivers/video/display/panel-r61505.c b/drivers/video/display/panel-r61505.c new file mode 100644 index 0000000..d72d324 --- /dev/null +++ b/drivers/video/display/panel-r61505.c @@ -0,0 +1,554 @@ +/* + * 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 <linux/slab.h> + +#include <video/display.h> +#include <video/mipi-dbi-bus.h> +#include <video/panel-r61505.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 display_entity entity; + struct mipi_dbi_device *dbi; + const struct panel_r61505_platform_data *pdata; +}; + +#define to_panel(p) container_of(p, struct r61505, entity) + +/* ----------------------------------------------------------------------------- + * Read, write and reset + */ + +static void r61505_write(struct r61505 *panel, u16 reg, u16 data) +{ + u8 buffer[2] = { data >> 8, data & 0xff }; + + mipi_dbi_write_command(panel->dbi, reg); + mipi_dbi_write_data(panel->dbi, buffer, 2); +} + +static u16 r61505_read(struct r61505 *panel, u16 reg) +{ + u8 buffer[2]; + int ret; + + mipi_dbi_write_command(panel->dbi, reg); + ret = mipi_dbi_read_data(panel->dbi, buffer, 2); + if (ret < 0) + return ret; + + return (buffer[0] << 8) | buffer[1]; +} + +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 hactive = panel->pdata->mode->hactive; + unsigned long vactive = panel->pdata->mode->vactive; + 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((hactive / 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 - (vactive - 1)); + r61505_write(panel, R61505_WINDOW_HORZ_END, 239); + r61505_write(panel, R61505_WINDOW_VERT_START, 0); + r61505_write(panel, R61505_WINDOW_VERT_END, hactive - 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 < (hactive * 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 const struct display_entity_interface_params r61505_dbi_params = { + .type = DISPLAY_ENTITY_INTERFACE_DBI, + .p.dbi = { + .type = MIPI_DBI_INTERFACE_TYPE_B, + .cs_setup = 1, + .wr_setup = 0, + .wr_cycle = 10, + .wr_hold = 9, + .rd_setup = 14, + .rd_latch = 24, + .rd_cycle = 52, + .rd_hold = 24, + }, +}; + +static int r61505_set_state(struct display_entity *entity, + enum display_entity_state state) +{ + struct r61505 *panel = to_panel(entity); + + switch (state) { + case DISPLAY_ENTITY_STATE_OFF: + r61505_disable_panel(panel); + break; + + case DISPLAY_ENTITY_STATE_STANDBY: + if (entity->state = DISPLAY_ENTITY_STATE_OFF) + r61505_enable_panel(panel); + else + r61505_display_off(panel); + break; + + case DISPLAY_ENTITY_STATE_ON: + if (entity->state = DISPLAY_ENTITY_STATE_OFF) + r61505_enable_panel(panel); + + r61505_display_on(panel); + break; + } + + return 0; +} + +static int r61505_update(struct display_entity *entity) +{ + struct r61505 *panel = to_panel(entity); + + mipi_dbi_write_command(panel->dbi, R61505_RAM_DATA); + usleep_range(100000, 101000); + + display_entity_set_stream(entity->source, + DISPLAY_ENTITY_STREAM_SINGLE_SHOT); + return 0; +} + +static int r61505_get_modes(struct display_entity *entity, + const struct videomode **modes) +{ + struct r61505 *panel = to_panel(entity); + + *modes = panel->pdata->mode; + return 1; +} + +static int r61505_get_size(struct display_entity *entity, + unsigned int *width, unsigned int *height) +{ + struct r61505 *panel = to_panel(entity); + + *width = panel->pdata->width; + *height = panel->pdata->height; + return 0; +} + +static int r61505_get_params(struct display_entity *entity, + struct display_entity_interface_params *params) +{ + *params = r61505_dbi_params; + return 0; +} + +static const struct display_entity_control_ops r61505_control_ops = { + .set_state = r61505_set_state, + .update = r61505_update, + .get_modes = r61505_get_modes, + .get_size = r61505_get_size, + .get_params = r61505_get_params, +}; + +static void r61505_release(struct display_entity *entity) +{ + struct r61505 *panel = to_panel(entity); + + kfree(panel); +} + +static int r61505_remove(struct mipi_dbi_device *dev) +{ + struct r61505 *panel = mipi_dbi_get_drvdata(dev); + + mipi_dbi_set_drvdata(dev, NULL); + display_entity_unregister(&panel->entity); + + return 0; +} + +static int __devinit r61505_probe(struct mipi_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; + + dev->flags = MIPI_DBI_FLAG_ALIGN_LEFT; + dev->bus_width = pdata->bus_width; + mipi_dbi_set_data_width(dev, 16); + + 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->entity.dev = &dev->dev; + panel->entity.release = r61505_release; + panel->entity.ops.ctrl = &r61505_control_ops; + + ret = display_entity_register(&panel->entity); + if (ret < 0) { + kfree(panel); + return ret; + } + + mipi_dbi_set_drvdata(dev, panel); + + return 0; +} + +static const struct dev_pm_ops r61505_dev_pm_ops = { +}; + +static struct mipi_dbi_driver r61505_driver = { + .probe = r61505_probe, + .remove = r61505_remove, + .driver = { + .name = "panel_r61505", + .owner = THIS_MODULE, + .pm = &r61505_dev_pm_ops, + }, +}; + +module_mipi_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..fe4a368 --- /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/videomode.h> + +struct panel_r61505_platform_data { + unsigned long width; /* Panel width in mm */ + unsigned long height; /* Panel height in mm */ + const struct videomode *mode; + + unsigned int bus_width; + int reset; /* Reset GPIO */ +}; + +#endif /* __PANEL_R61505_H__ */ -- 1.7.8.6
next prev parent reply other threads:[~2012-11-22 21:44 UTC|newest] Thread overview: 172+ messages / expand[flat|nested] mbox.gz Atom feed top 2012-11-22 21:45 [RFC v2 0/5] Common Display Framework Laurent Pinchart 2012-11-22 21:45 ` Laurent Pinchart 2012-11-22 21:45 ` [RFC v2 1/5] video: Add generic display entity core Laurent Pinchart 2012-11-22 21:45 ` Laurent Pinchart 2012-11-27 13:07 ` Tomi Valkeinen 2012-11-27 13:07 ` Tomi Valkeinen 2012-11-27 13:07 ` Tomi Valkeinen 2012-11-22 21:45 ` [RFC v2 2/5] video: panel: Add DPI panel support Laurent Pinchart 2012-11-22 21:45 ` Laurent Pinchart 2012-11-27 13:02 ` Tomi Valkeinen 2012-11-27 13:02 ` Tomi Valkeinen 2012-11-27 13:02 ` Tomi Valkeinen 2012-11-30 9:26 ` Philipp Zabel 2012-11-30 9:26 ` Philipp Zabel 2012-11-22 21:45 ` [RFC v2 3/5] video: display: Add MIPI DBI bus support Laurent Pinchart 2012-11-22 21:45 ` Laurent Pinchart 2012-11-30 12:02 ` Tomi Valkeinen 2012-11-30 12:02 ` Tomi Valkeinen 2012-11-30 12:02 ` Tomi Valkeinen 2012-11-22 21:45 ` Laurent Pinchart [this message] 2012-11-22 21:45 ` [RFC v2 4/5] video: panel: Add R61505 panel support Laurent Pinchart 2012-11-22 21:45 ` [RFC v2 5/5] video: panel: Add R61517 " Laurent Pinchart 2012-11-22 21:45 ` Laurent Pinchart 2012-11-23 14:51 ` [RFC v2 0/5] Common Display Framework Tomi Valkeinen 2012-11-23 14:51 ` Tomi Valkeinen 2012-11-23 14:51 ` Tomi Valkeinen 2012-12-17 14:36 ` Laurent Pinchart 2012-12-17 14:36 ` Laurent Pinchart 2012-12-17 15:29 ` Tomi Valkeinen 2012-12-17 15:29 ` Tomi Valkeinen 2012-12-17 15:29 ` Tomi Valkeinen 2012-12-17 23:18 ` Laurent Pinchart 2012-12-17 23:18 ` Laurent Pinchart 2012-12-17 16:53 ` Jani Nikula 2012-12-17 16:53 ` Jani Nikula 2012-12-17 22:19 ` Laurent Pinchart 2012-12-17 22:19 ` Laurent Pinchart 2012-12-19 14:57 ` Jani Nikula 2012-12-19 14:57 ` Jani Nikula 2012-12-19 15:07 ` Tomi Valkeinen 2012-12-19 15:07 ` Tomi Valkeinen 2012-12-19 15:07 ` Tomi Valkeinen 2012-12-24 17:31 ` Laurent Pinchart 2012-12-24 17:31 ` Laurent Pinchart 2012-12-19 15:26 ` Rob Clark 2012-12-19 15:26 ` Rob Clark 2012-12-19 15:37 ` Tomi Valkeinen 2012-12-19 15:37 ` Tomi Valkeinen 2012-12-19 16:05 ` Rob Clark 2012-12-19 16:05 ` Rob Clark 2012-12-19 16:05 ` Rob Clark 2012-12-24 17:40 ` Laurent Pinchart 2012-12-24 17:40 ` Laurent Pinchart 2012-12-24 17:35 ` Laurent Pinchart 2012-12-24 17:35 ` Laurent Pinchart 2012-12-27 16:10 ` Rob Clark 2012-12-27 16:10 ` Rob Clark 2012-12-24 17:27 ` Laurent Pinchart 2012-12-24 17:27 ` Laurent Pinchart 2012-12-27 16:04 ` Rob Clark 2012-12-27 16:04 ` Rob Clark 2012-12-27 19:19 ` Sascha Hauer 2012-12-27 19:19 ` Sascha Hauer 2012-11-23 19:56 ` Thierry Reding 2012-11-23 19:56 ` Thierry Reding 2012-11-24 7:15 ` Tomi Valkeinen 2012-11-24 7:15 ` Tomi Valkeinen 2012-11-24 7:15 ` Tomi Valkeinen 2012-11-26 14:47 ` Alan Cox 2012-12-17 15:15 ` Laurent Pinchart 2012-12-17 15:15 ` Laurent Pinchart 2012-11-26 7:53 ` Philipp Zabel 2012-11-26 7:53 ` Philipp Zabel 2012-12-17 14:58 ` Laurent Pinchart 2012-12-17 14:58 ` Laurent Pinchart 2012-11-23 21:41 ` Sascha Hauer 2012-11-23 21:41 ` Sascha Hauer 2012-12-17 15:02 ` Laurent Pinchart 2012-12-17 15:02 ` Laurent Pinchart [not found] ` <CAD025yS5rGMbiRBdDxv=YLP6_fsQndAkr+3t29_mNhcvow_SwA@mail.gmail.com> [not found] ` <3133576.BkqAl7V01U@avalon> 2012-12-18 3:01 ` Vikas Sajjan 2012-12-18 6:13 ` Vikas Sajjan 2012-12-18 6:25 ` Vikas Sajjan 2012-12-21 10:00 ` Tomasz Figa 2012-12-21 10:00 ` Tomasz Figa 2012-12-24 14:12 ` Laurent Pinchart 2012-12-24 14:12 ` Laurent Pinchart 2012-12-27 14:43 ` Tomasz Figa 2012-12-27 14:43 ` Tomasz Figa 2012-12-27 14:43 ` Tomasz Figa 2012-12-28 3:26 ` Vikas Sajjan 2012-12-28 3:38 ` Vikas Sajjan 2013-01-08 8:18 ` Laurent Pinchart 2013-01-08 8:18 ` Laurent Pinchart 2013-01-08 10:12 ` Marcus Lorentzon 2013-01-08 10:12 ` Marcus Lorentzon 2013-01-08 16:36 ` Tomasz Figa 2013-01-08 16:36 ` Tomasz Figa 2013-01-08 17:08 ` Marcus Lorentzon 2013-01-08 17:08 ` Marcus Lorentzon 2013-02-01 23:35 ` Laurent Pinchart 2013-02-01 23:35 ` Laurent Pinchart 2013-02-04 10:05 ` Marcus Lorentzon 2013-02-04 10:05 ` Marcus Lorentzon 2013-02-06 9:52 ` Archit Taneja 2013-02-06 9:52 ` Archit Taneja 2013-02-08 10:51 ` Tomi Valkeinen 2013-02-08 10:51 ` Tomi Valkeinen 2013-02-08 12:43 ` Marcus Lorentzon 2013-02-08 12:43 ` Marcus Lorentzon 2013-02-01 23:37 ` Laurent Pinchart 2013-02-01 23:37 ` Laurent Pinchart 2012-12-24 12:59 ` Laurent Pinchart 2012-12-24 13:00 ` Laurent Pinchart 2012-12-18 5:04 ` Dave Airlie 2012-12-18 5:04 ` Dave Airlie 2012-12-18 5:04 ` Dave Airlie 2012-12-18 6:21 ` Rob Clark 2012-12-18 6:21 ` Rob Clark 2012-12-18 8:30 ` Daniel Vetter 2012-12-18 8:30 ` Daniel Vetter 2012-12-18 9:38 ` Inki Dae 2012-12-19 20:13 ` Stéphane Marchesin 2012-12-19 20:13 ` Stéphane Marchesin 2012-12-24 14:08 ` Laurent Pinchart 2012-12-24 14:08 ` Laurent Pinchart 2012-12-24 13:39 ` Laurent Pinchart 2012-12-24 13:39 ` Laurent Pinchart 2012-12-18 10:59 ` Sylwester Nawrocki 2012-12-18 10:59 ` Sylwester Nawrocki 2012-12-24 17:19 ` Laurent Pinchart 2012-12-24 17:19 ` Laurent Pinchart 2012-12-19 20:05 ` Stéphane Marchesin 2012-12-19 20:05 ` Stéphane Marchesin 2012-12-24 13:37 ` Laurent Pinchart 2012-12-24 13:37 ` Laurent Pinchart 2012-12-27 15:54 ` Rob Clark 2012-12-27 15:54 ` Rob Clark 2012-12-27 19:18 ` Sascha Hauer 2012-12-27 19:18 ` Sascha Hauer 2012-12-27 19:57 ` Rob Clark 2012-12-27 19:57 ` Rob Clark 2012-12-28 0:04 ` Sascha Hauer 2012-12-28 0:04 ` Sascha Hauer 2013-01-08 8:33 ` Laurent Pinchart 2013-01-08 8:33 ` Laurent Pinchart 2013-01-08 8:25 ` Laurent Pinchart 2013-01-08 8:25 ` Laurent Pinchart 2013-01-08 16:13 ` Rob Clark 2013-01-08 16:13 ` Rob Clark 2013-01-09 8:23 ` Rahul Sharma 2013-01-09 8:35 ` Rahul Sharma 2013-01-09 8:23 ` Rahul Sharma 2013-02-01 23:42 ` Laurent Pinchart 2013-02-01 23:42 ` Laurent Pinchart 2013-02-02 10:08 ` Rob Clark 2013-02-02 10:08 ` Rob Clark 2012-12-18 10:39 ` Marcus Lorentzon 2012-12-18 10:39 ` Marcus Lorentzon 2012-12-18 10:39 ` Marcus Lorentzon 2012-12-24 17:09 ` Laurent Pinchart 2012-12-24 17:09 ` Laurent Pinchart 2012-12-24 17:09 ` Laurent Pinchart 2012-12-27 15:57 ` Rob Clark 2012-12-27 15:57 ` Rob Clark 2012-12-27 15:57 ` Rob Clark 2013-01-06 17:46 ` Daniel Vetter 2013-01-06 17:46 ` Daniel Vetter 2013-01-06 17:46 ` Daniel Vetter 2013-01-08 8:41 ` Laurent Pinchart 2013-01-08 8:41 ` Laurent Pinchart 2012-12-24 13:24 ` Laurent Pinchart 2012-12-24 13:24 ` 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=1353620736-6517-5-git-send-email-laurent.pinchart@ideasonboard.com \ --to=laurent.pinchart@ideasonboard.com \ --cc=archit@ti.com \ --cc=benjamin.gaignard@linaro.org \ --cc=bryan.wu@canonical.com \ --cc=dri-devel@lists.freedesktop.org \ --cc=inki.dae@samsung.com \ --cc=jesse.barker@linaro.org \ --cc=kyungmin.park@samsung.com \ --cc=linux-fbdev@vger.kernel.org \ --cc=linux-media@vger.kernel.org \ --cc=marcus.xm.lorentzon@stericsson.com \ --cc=maxime.ripard@free-electrons.com \ --cc=p.zabel@pengutronix.de \ --cc=ragesh.r@linaro.org \ --cc=rob.clark@linaro.org \ --cc=s-guiriec@ti.com \ --cc=s.hauer@pengutronix.de \ --cc=sumit.semwal@linaro.org \ --cc=thomas.petazzoni@free-electrons.com \ --cc=tom.gall@linaro.org \ --cc=tomi.valkeinen@ti.com \ --cc=vikas.sajjan@linaro.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: linkBe 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.