From: Laurent Pinchart <laurent.pinchart+renesas@ideasonboard.com> To: dri-devel@lists.freedesktop.org, linux-fbdev@vger.kernel.org, linux-media@vger.kernel.org Subject: [PATCH/RFC v3 10/19] video: panel: Add R61505 panel support Date: Sat, 10 Aug 2013 01:03:09 +0200 [thread overview] Message-ID: <1376089398-13322-11-git-send-email-laurent.pinchart+renesas@ideasonboard.com> (raw) In-Reply-To: <1376089398-13322-1-git-send-email-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 | 10 + drivers/video/display/Makefile | 1 + drivers/video/display/panel-r61505.c | 567 +++++++++++++++++++++++++++++++++++ include/video/panel-r61505.h | 27 ++ 4 files changed, 605 insertions(+) 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 bce09d6..76729ef 100644 --- a/drivers/video/display/Kconfig +++ b/drivers/video/display/Kconfig @@ -19,4 +19,14 @@ config DISPLAY_PANEL_DPI If you are in doubt, say N. To compile this driver as a module, choose M here; the module will be called panel-dpi. +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. To compile this driver as a module, choose + M here; the module will be called panel-r61505. + endif # DISPLAY_CORE diff --git a/drivers/video/display/Makefile b/drivers/video/display/Makefile index 31c017b..db8a4c3 100644 --- a/drivers/video/display/Makefile +++ b/drivers/video/display/Makefile @@ -3,3 +3,4 @@ display-y := display-core.o \ obj-$(CONFIG_DISPLAY_CORE) += display.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..c86177e --- /dev/null +++ b/drivers/video/display/panel-r61505.c @@ -0,0 +1,567 @@ +/* + * 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> +#include <video/videomode.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; +}; + +static inline struct r61505 *to_panel(struct display_entity *e) +{ + return container_of(e, 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); + struct media_pad *source; + + mipi_dbi_write_command(panel->dbi, R61505_RAM_DATA); + usleep_range(100000, 101000); + + source = media_entity_remote_pad(&entity->entity.pads[0]); + if (source == NULL) + return -EPIPE; + + display_entity_set_stream(to_display_entity(source->entity), + source->index, + DISPLAY_ENTITY_STREAM_SINGLE_SHOT); + return 0; +} + +static int r61505_get_modes(struct display_entity *entity, unsigned int port, + 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, unsigned int port, + 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 const struct display_entity_ops r61505_ops = { + .ctrl = &r61505_control_ops, +}; + +static int r61505_remove(struct mipi_dbi_device *dev) +{ + struct r61505 *panel = mipi_dbi_get_drvdata(dev); + + display_entity_remove(&panel->entity); + display_entity_cleanup(&panel->entity); + + return 0; +} + +static int 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 = devm_kzalloc(&dev->dev, 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) + return -ENODEV; + + panel->entity.dev = &dev->dev; + panel->entity.ops = &r61505_ops; + + ret = display_entity_init(&panel->entity, 1, 0); + if (ret < 0) + return ret; + + ret = display_entity_add(&panel->entity); + if (ret < 0) + return ret; + + mipi_dbi_set_drvdata(dev, panel); + + return 0; +} + +static const struct dev_pm_ops r61505_dev_pm_ops = { +}; + +static struct mipi_dbi_device_id r61505_id_table[] = { + { "panel-r61505", 0 }, + { }, +}; +MODULE_DEVICE_TABLE(mipi_dbi, r61505_id_table); + +static struct mipi_dbi_driver r61505_driver = { + .probe = r61505_probe, + .remove = r61505_remove, + .id_table = r61505_id_table, + .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..ee71f29 --- /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__ + +struct videomode; + +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.8.1.5
WARNING: multiple messages have this Message-ID (diff)
From: Laurent Pinchart <laurent.pinchart+renesas@ideasonboard.com> To: dri-devel@lists.freedesktop.org, linux-fbdev@vger.kernel.org, linux-media@vger.kernel.org Subject: [PATCH/RFC v3 10/19] video: panel: Add R61505 panel support Date: Fri, 09 Aug 2013 23:03:09 +0000 [thread overview] Message-ID: <1376089398-13322-11-git-send-email-laurent.pinchart+renesas@ideasonboard.com> (raw) In-Reply-To: <1376089398-13322-1-git-send-email-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 | 10 + drivers/video/display/Makefile | 1 + drivers/video/display/panel-r61505.c | 567 +++++++++++++++++++++++++++++++++++ include/video/panel-r61505.h | 27 ++ 4 files changed, 605 insertions(+) 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 bce09d6..76729ef 100644 --- a/drivers/video/display/Kconfig +++ b/drivers/video/display/Kconfig @@ -19,4 +19,14 @@ config DISPLAY_PANEL_DPI If you are in doubt, say N. To compile this driver as a module, choose M here; the module will be called panel-dpi. +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. To compile this driver as a module, choose + M here; the module will be called panel-r61505. + endif # DISPLAY_CORE diff --git a/drivers/video/display/Makefile b/drivers/video/display/Makefile index 31c017b..db8a4c3 100644 --- a/drivers/video/display/Makefile +++ b/drivers/video/display/Makefile @@ -3,3 +3,4 @@ display-y := display-core.o \ obj-$(CONFIG_DISPLAY_CORE) += display.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..c86177e --- /dev/null +++ b/drivers/video/display/panel-r61505.c @@ -0,0 +1,567 @@ +/* + * 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> +#include <video/videomode.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; +}; + +static inline struct r61505 *to_panel(struct display_entity *e) +{ + return container_of(e, 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); + struct media_pad *source; + + mipi_dbi_write_command(panel->dbi, R61505_RAM_DATA); + usleep_range(100000, 101000); + + source = media_entity_remote_pad(&entity->entity.pads[0]); + if (source = NULL) + return -EPIPE; + + display_entity_set_stream(to_display_entity(source->entity), + source->index, + DISPLAY_ENTITY_STREAM_SINGLE_SHOT); + return 0; +} + +static int r61505_get_modes(struct display_entity *entity, unsigned int port, + 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, unsigned int port, + 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 const struct display_entity_ops r61505_ops = { + .ctrl = &r61505_control_ops, +}; + +static int r61505_remove(struct mipi_dbi_device *dev) +{ + struct r61505 *panel = mipi_dbi_get_drvdata(dev); + + display_entity_remove(&panel->entity); + display_entity_cleanup(&panel->entity); + + return 0; +} + +static int 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 = devm_kzalloc(&dev->dev, 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) + return -ENODEV; + + panel->entity.dev = &dev->dev; + panel->entity.ops = &r61505_ops; + + ret = display_entity_init(&panel->entity, 1, 0); + if (ret < 0) + return ret; + + ret = display_entity_add(&panel->entity); + if (ret < 0) + return ret; + + mipi_dbi_set_drvdata(dev, panel); + + return 0; +} + +static const struct dev_pm_ops r61505_dev_pm_ops = { +}; + +static struct mipi_dbi_device_id r61505_id_table[] = { + { "panel-r61505", 0 }, + { }, +}; +MODULE_DEVICE_TABLE(mipi_dbi, r61505_id_table); + +static struct mipi_dbi_driver r61505_driver = { + .probe = r61505_probe, + .remove = r61505_remove, + .id_table = r61505_id_table, + .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..ee71f29 --- /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__ + +struct videomode; + +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.8.1.5
next prev parent reply other threads:[~2013-08-09 23:02 UTC|newest] Thread overview: 53+ messages / expand[flat|nested] mbox.gz Atom feed top 2013-08-09 23:02 [PATCH/RFC v3 00/19] Common Display Framework Laurent Pinchart 2013-08-09 23:02 ` Laurent Pinchart 2013-08-09 23:03 ` [PATCH/RFC v3 01/19] OMAPDSS: panels: Rename Kconfig options to OMAP2_DISPLAY_* Laurent Pinchart 2013-08-09 23:03 ` Laurent Pinchart 2013-08-09 23:03 ` [PATCH/RFC v3 02/19] video: Add Common Display Framework core Laurent Pinchart 2013-08-09 23:03 ` Laurent Pinchart 2013-08-09 23:03 ` [PATCH/RFC v3 03/19] video: display: Add video and stream control operations Laurent Pinchart 2013-08-09 23:03 ` Laurent Pinchart 2013-08-09 23:03 ` [PATCH/RFC v3 04/19] video: display: Add display entity notifier Laurent Pinchart 2013-08-09 23:03 ` Laurent Pinchart 2013-08-09 23:03 ` [PATCH/RFC v3 05/19] video: display: Graph helpers Laurent Pinchart 2013-08-09 23:03 ` Laurent Pinchart 2013-08-09 23:03 ` [PATCH/RFC v3 06/19] video: display: OF support Laurent Pinchart 2013-08-09 23:03 ` Laurent Pinchart 2013-08-27 9:30 ` Philipp Zabel 2013-08-27 9:30 ` Philipp Zabel 2013-08-30 0:47 ` Laurent Pinchart 2013-08-30 0:47 ` Laurent Pinchart 2013-09-04 14:21 ` Philipp Zabel 2013-09-04 14:21 ` Philipp Zabel 2013-09-11 11:33 ` Laurent Pinchart 2013-09-11 11:33 ` Laurent Pinchart 2013-09-11 13:14 ` Philipp Zabel 2013-09-11 13:14 ` Philipp Zabel 2013-09-11 13:48 ` Hans Verkuil 2013-09-11 13:48 ` Hans Verkuil 2013-08-09 23:03 ` [PATCH/RFC v3 07/19] video: display: Add pixel coding definitions Laurent Pinchart 2013-08-09 23:03 ` Laurent Pinchart 2013-08-09 23:03 ` [PATCH/RFC v3 08/19] video: display: Add MIPI DBI bus support Laurent Pinchart 2013-08-09 23:03 ` Laurent Pinchart 2013-08-09 23:03 ` [PATCH/RFC v3 09/19] video: panel: Add DPI panel support Laurent Pinchart 2013-08-09 23:03 ` Laurent Pinchart 2013-08-09 23:03 ` Laurent Pinchart [this message] 2013-08-09 23:03 ` [PATCH/RFC v3 10/19] video: panel: Add R61505 " Laurent Pinchart 2013-08-09 23:03 ` [PATCH/RFC v3 11/19] video: panel: Add R61517 " Laurent Pinchart 2013-08-09 23:03 ` Laurent Pinchart 2013-08-09 23:03 ` [PATCH/RFC v3 12/19] video: display: Add VGA Digital to Analog Converter support Laurent Pinchart 2013-08-09 23:03 ` Laurent Pinchart 2013-08-09 23:03 ` [PATCH/RFC v3 13/19] video: display: Add VGA connector support Laurent Pinchart 2013-08-09 23:03 ` Laurent Pinchart 2013-08-09 23:03 ` [PATCH/RFC v3 14/19] ARM: shmobile: r8a7790: Add DU clocks for DT Laurent Pinchart 2013-08-09 23:03 ` Laurent Pinchart 2013-08-09 23:03 ` [PATCH/RFC v3 15/19] ARM: shmobile: r8a7790: Add DU device node to device tree Laurent Pinchart 2013-08-09 23:03 ` Laurent Pinchart 2013-08-09 23:03 ` [PATCH/RFC v3 16/19] ARM: shmobile: marzen: Port DU platform data to CDF Laurent Pinchart 2013-08-09 23:03 ` Laurent Pinchart 2013-08-09 23:03 ` [PATCH/RFC v3 17/19] ARM: shmobile: lager: " Laurent Pinchart 2013-08-09 23:03 ` Laurent Pinchart 2013-08-09 23:03 ` [PATCH/RFC v3 18/19] ARM: shmobile: lager-reference: Add display device nodes to device tree Laurent Pinchart 2013-08-09 23:03 ` Laurent Pinchart 2013-08-09 23:03 ` [PATCH/RFC v3 19/19] drm/rcar-du: Port to the Common Display Framework Laurent Pinchart 2013-08-09 23:03 ` Laurent Pinchart -- strict thread matches above, loose matches on Subject: below -- 2013-08-09 17:14 [PATCH/RFC v3 00/19] " Laurent Pinchart 2013-08-09 17:15 ` [PATCH/RFC v3 10/19] video: panel: Add R61505 panel support 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=1376089398-13322-11-git-send-email-laurent.pinchart+renesas@ideasonboard.com \ --to=laurent.pinchart+renesas@ideasonboard.com \ --cc=dri-devel@lists.freedesktop.org \ --cc=linux-fbdev@vger.kernel.org \ --cc=linux-media@vger.kernel.org \ /path/to/YOUR_REPLY https://kernel.org/pub/software/scm/git/docs/git-send-email.html * If your mail client supports setting the In-Reply-To header via mailto: links, try the mailto: 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.