I pushed a couple of the patches from the series, so here's what's left. I figured it was time for a resend at this point.
Eric Anholt (3): drm/vc4: Move the DSI clock divider workaround closer to the clock call. dt-bindings: Document the Raspberry Pi Touchscreen nodes. drm/panel: Add support for the Raspberry Pi 7" Touchscreen.
.../panel/raspberrypi,7inch-touchscreen.txt | 49 ++ drivers/gpu/drm/panel/Kconfig | 8 + drivers/gpu/drm/panel/Makefile | 1 + .../gpu/drm/panel/panel-raspberrypi-touchscreen.c | 517 +++++++++++++++++++++ drivers/gpu/drm/vc4/vc4_dsi.c | 12 +- 5 files changed, 581 insertions(+), 6 deletions(-) create mode 100644 Documentation/devicetree/bindings/display/panel/raspberrypi,7inch-touchscreen.txt create mode 100644 drivers/gpu/drm/panel/panel-raspberrypi-touchscreen.c
We want the adjusted_mode->clock to be the actual clock we're expecting to program, so that consumers see the right values for clock and vrefresh.
Signed-off-by: Eric Anholt eric@anholt.net --- drivers/gpu/drm/vc4/vc4_dsi.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-)
diff --git a/drivers/gpu/drm/vc4/vc4_dsi.c b/drivers/gpu/drm/vc4/vc4_dsi.c index 925c726ac694..554605af344e 100644 --- a/drivers/gpu/drm/vc4/vc4_dsi.c +++ b/drivers/gpu/drm/vc4/vc4_dsi.c @@ -859,11 +859,7 @@ static bool vc4_dsi_encoder_mode_fixup(struct drm_encoder *encoder, pll_clock = parent_rate / divider; pixel_clock_hz = pll_clock / dsi->divider;
- /* Round up the clk_set_rate() request slightly, since - * PLLD_DSI1 is an integer divider and its rate selection will - * never round up. - */ - adjusted_mode->clock = pixel_clock_hz / 1000 + 1; + adjusted_mode->clock = pixel_clock_hz / 1000;
/* Given the new pixel clock, adjust HFP to keep vrefresh the same. */ adjusted_mode->htotal = adjusted_mode->clock * mode->htotal / @@ -901,7 +897,11 @@ static void vc4_dsi_encoder_enable(struct drm_encoder *encoder) vc4_dsi_dump_regs(dsi); }
- phy_clock = pixel_clock_hz * dsi->divider; + /* Round up the clk_set_rate() request slightly, since + * PLLD_DSI1 is an integer divider and its rate selection will + * never round up. + */ + phy_clock = (pixel_clock_hz + 1000) * dsi->divider; ret = clk_set_rate(dsi->pll_phy_clock, phy_clock); if (ret) { dev_err(&dsi->pdev->dev,
On Wed, Sep 27, 2017 at 12:36:52PM -0700, Eric Anholt wrote:
We want the adjusted_mode->clock to be the actual clock we're expecting to program, so that consumers see the right values for clock and vrefresh.
Signed-off-by: Eric Anholt eric@anholt.net
drivers/gpu/drm/vc4/vc4_dsi.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-)
Do you want me to apply this to drm-misc-next along with the touchscreen panel driver?
Thierry
Thierry Reding thierry.reding@gmail.com writes:
[ Unknown signature status ] On Wed, Sep 27, 2017 at 12:36:52PM -0700, Eric Anholt wrote:
We want the adjusted_mode->clock to be the actual clock we're expecting to program, so that consumers see the right values for clock and vrefresh.
Signed-off-by: Eric Anholt eric@anholt.net
drivers/gpu/drm/vc4/vc4_dsi.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-)
Do you want me to apply this to drm-misc-next along with the touchscreen panel driver?
drm-misc-next procedure trends toward the submitter applies the patch once they get review, if they have the commit rights. However, I'm happy either way as long as I can get the code in.
This doesn't yet cover input, but the driver does get the display working when the firmware is disabled from talking to our I2C lines.
Signed-off-by: Eric Anholt eric@anholt.net Acked-by: Rob Herring robh@kernel.org --- .../panel/raspberrypi,7inch-touchscreen.txt | 49 ++++++++++++++++++++++ 1 file changed, 49 insertions(+) create mode 100644 Documentation/devicetree/bindings/display/panel/raspberrypi,7inch-touchscreen.txt
diff --git a/Documentation/devicetree/bindings/display/panel/raspberrypi,7inch-touchscreen.txt b/Documentation/devicetree/bindings/display/panel/raspberrypi,7inch-touchscreen.txt new file mode 100644 index 000000000000..e9e19c059260 --- /dev/null +++ b/Documentation/devicetree/bindings/display/panel/raspberrypi,7inch-touchscreen.txt @@ -0,0 +1,49 @@ +This binding covers the official 7" (800x480) Raspberry Pi touchscreen +panel. + +This DSI panel contains: + +- TC358762 DSI->DPI bridge +- Atmel microcontroller on I2C for power sequencing the DSI bridge and + controlling backlight +- Touchscreen controller on I2C for touch input + +and this binding covers the DSI display parts but not its touch input. + +Required properties: +- compatible: Must be "raspberrypi,7inch-touchscreen-panel" +- reg: Must be "45" +- port: See panel-common.txt + +Example: + +dsi1: dsi@7e700000 { + #address-cells = <1>; + #size-cells = <0>; + <...> + + port { + dsi_out_port: endpoint { + remote-endpoint = <&panel_dsi_port>; + }; + }; +}; + +i2c_dsi: i2c { + compatible = "i2c-gpio"; + #address-cells = <1>; + #size-cells = <0>; + gpios = <&gpio 28 0 + &gpio 29 0>; + + lcd@45 { + compatible = "raspberrypi,7inch-touchscreen-panel"; + reg = <0x45>; + + port { + panel_dsi_port: endpoint { + remote-endpoint = <&dsi_out_port>; + }; + }; + }; +};
This driver communicates with the Atmel microcontroller for sequencing the poweron of the TC358762 DSI-DPI bridge and controlling the backlight PWM.
v2: Set the same default orientation as the closed source firmware used, which is the best for viewing angle. v3: Rewrite as an i2c client driver after bridge driver rejection. v4: Finish probe without the DSI host, using the new delayed registration, and attach to the host during mipi_dsi_driver probe. v5: Rework to drop the "probe without DSI host" mode again, now that vc4 will create the host early on.
Signed-off-by: Eric Anholt eric@anholt.net --- drivers/gpu/drm/panel/Kconfig | 8 + drivers/gpu/drm/panel/Makefile | 1 + .../gpu/drm/panel/panel-raspberrypi-touchscreen.c | 517 +++++++++++++++++++++ 3 files changed, 526 insertions(+) create mode 100644 drivers/gpu/drm/panel/panel-raspberrypi-touchscreen.c
diff --git a/drivers/gpu/drm/panel/Kconfig b/drivers/gpu/drm/panel/Kconfig index 718d8ce15b1f..726f3fb3312d 100644 --- a/drivers/gpu/drm/panel/Kconfig +++ b/drivers/gpu/drm/panel/Kconfig @@ -82,6 +82,14 @@ config DRM_PANEL_PANASONIC_VVX10F034N00 WUXGA (1920x1200) Novatek NT1397-based DSI panel as found in some Xperia Z2 tablets
+config DRM_PANEL_RASPBERRYPI_TOUCHSCREEN + tristate "Raspberry Pi 7-inch touchscreen panel" + depends on DRM_MIPI_DSI + help + Say Y here if you want to enable support for the Raspberry + Pi 7" Touchscreen. To compile this driver as a module, + choose M here. + config DRM_PANEL_SAMSUNG_S6E3HA2 tristate "Samsung S6E3HA2 DSI video mode panel" depends on OF diff --git a/drivers/gpu/drm/panel/Makefile b/drivers/gpu/drm/panel/Makefile index c8483fdd5b9b..77ede3467324 100644 --- a/drivers/gpu/drm/panel/Makefile +++ b/drivers/gpu/drm/panel/Makefile @@ -5,6 +5,7 @@ obj-$(CONFIG_DRM_PANEL_JDI_LT070ME05000) += panel-jdi-lt070me05000.o obj-$(CONFIG_DRM_PANEL_LG_LG4573) += panel-lg-lg4573.o obj-$(CONFIG_DRM_PANEL_ORISETECH_OTM8009A) += panel-orisetech-otm8009a.o obj-$(CONFIG_DRM_PANEL_PANASONIC_VVX10F034N00) += panel-panasonic-vvx10f034n00.o +obj-$(CONFIG_DRM_PANEL_RASPBERRYPI_TOUCHSCREEN) += panel-raspberrypi-touchscreen.o obj-$(CONFIG_DRM_PANEL_SAMSUNG_LD9040) += panel-samsung-ld9040.o obj-$(CONFIG_DRM_PANEL_SAMSUNG_S6E3HA2) += panel-samsung-s6e3ha2.o obj-$(CONFIG_DRM_PANEL_SAMSUNG_S6E63J0X03) += panel-samsung-s6e63j0x03.o diff --git a/drivers/gpu/drm/panel/panel-raspberrypi-touchscreen.c b/drivers/gpu/drm/panel/panel-raspberrypi-touchscreen.c new file mode 100644 index 000000000000..4237a0cbcdcc --- /dev/null +++ b/drivers/gpu/drm/panel/panel-raspberrypi-touchscreen.c @@ -0,0 +1,517 @@ +/* + * Copyright © 2016-2017 Broadcom + * + * 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. + * + * Portions of this file (derived from panel-simple.c) are: + * + * Copyright (C) 2013, NVIDIA Corporation. All rights reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sub license, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the + * next paragraph) shall be included in all copies or substantial portions + * of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + */ + +/** + * Raspberry Pi 7" touchscreen panel driver. + * + * The 7" touchscreen consists of a DPI LCD panel, a Toshiba + * TC358762XBG DSI-DPI bridge, and an I2C-connected Atmel ATTINY88-MUR + * controlling power management, the LCD PWM, and initial register + * setup of the Tohsiba. + * + * This driver controls the TC358762 and ATTINY88, presenting a DSI + * device with a drm_panel. + */ + +#include <linux/delay.h> +#include <linux/err.h> +#include <linux/fb.h> +#include <linux/gpio.h> +#include <linux/gpio/consumer.h> +#include <linux/i2c.h> +#include <linux/module.h> +#include <linux/of.h> +#include <linux/of_device.h> +#include <linux/of_graph.h> +#include <linux/pm.h> + +#include <drm/drm_panel.h> +#include <drm/drmP.h> +#include <drm/drm_crtc.h> +#include <drm/drm_mipi_dsi.h> +#include <drm/drm_panel.h> + +#define RPI_DSI_DRIVER_NAME "rpi-ts-dsi" + +/* I2C registers of the Atmel microcontroller. */ +enum REG_ADDR { + REG_ID = 0x80, + REG_PORTA, /* BIT(2) for horizontal flip, BIT(3) for vertical flip */ + REG_PORTB, + REG_PORTC, + REG_PORTD, + REG_POWERON, + REG_PWM, + REG_DDRA, + REG_DDRB, + REG_DDRC, + REG_DDRD, + REG_TEST, + REG_WR_ADDRL, + REG_WR_ADDRH, + REG_READH, + REG_READL, + REG_WRITEH, + REG_WRITEL, + REG_ID2, +}; + +/* We only turn the PWM on or off, without varying values. */ +#define RPI_TOUCHSCREEN_MAX_BRIGHTNESS 1 + +/* DSI D-PHY Layer Registers */ +#define D0W_DPHYCONTTX 0x0004 +#define CLW_DPHYCONTRX 0x0020 +#define D0W_DPHYCONTRX 0x0024 +#define D1W_DPHYCONTRX 0x0028 +#define COM_DPHYCONTRX 0x0038 +#define CLW_CNTRL 0x0040 +#define D0W_CNTRL 0x0044 +#define D1W_CNTRL 0x0048 +#define DFTMODE_CNTRL 0x0054 + +/* DSI PPI Layer Registers */ +#define PPI_STARTPPI 0x0104 +#define PPI_BUSYPPI 0x0108 +#define PPI_LINEINITCNT 0x0110 +#define PPI_LPTXTIMECNT 0x0114 +#define PPI_CLS_ATMR 0x0140 +#define PPI_D0S_ATMR 0x0144 +#define PPI_D1S_ATMR 0x0148 +#define PPI_D0S_CLRSIPOCOUNT 0x0164 +#define PPI_D1S_CLRSIPOCOUNT 0x0168 +#define CLS_PRE 0x0180 +#define D0S_PRE 0x0184 +#define D1S_PRE 0x0188 +#define CLS_PREP 0x01A0 +#define D0S_PREP 0x01A4 +#define D1S_PREP 0x01A8 +#define CLS_ZERO 0x01C0 +#define D0S_ZERO 0x01C4 +#define D1S_ZERO 0x01C8 +#define PPI_CLRFLG 0x01E0 +#define PPI_CLRSIPO 0x01E4 +#define HSTIMEOUT 0x01F0 +#define HSTIMEOUTENABLE 0x01F4 + +/* DSI Protocol Layer Registers */ +#define DSI_STARTDSI 0x0204 +#define DSI_BUSYDSI 0x0208 +#define DSI_LANEENABLE 0x0210 +# define DSI_LANEENABLE_CLOCK BIT(0) +# define DSI_LANEENABLE_D0 BIT(1) +# define DSI_LANEENABLE_D1 BIT(2) + +#define DSI_LANESTATUS0 0x0214 +#define DSI_LANESTATUS1 0x0218 +#define DSI_INTSTATUS 0x0220 +#define DSI_INTMASK 0x0224 +#define DSI_INTCLR 0x0228 +#define DSI_LPTXTO 0x0230 +#define DSI_MODE 0x0260 +#define DSI_PAYLOAD0 0x0268 +#define DSI_PAYLOAD1 0x026C +#define DSI_SHORTPKTDAT 0x0270 +#define DSI_SHORTPKTREQ 0x0274 +#define DSI_BTASTA 0x0278 +#define DSI_BTACLR 0x027C + +/* DSI General Registers */ +#define DSIERRCNT 0x0300 +#define DSISIGMOD 0x0304 + +/* DSI Application Layer Registers */ +#define APLCTRL 0x0400 +#define APLSTAT 0x0404 +#define APLERR 0x0408 +#define PWRMOD 0x040C +#define RDPKTLN 0x0410 +#define PXLFMT 0x0414 +#define MEMWRCMD 0x0418 + +/* LCDC/DPI Host Registers */ +#define LCDCTRL 0x0420 +#define HSR 0x0424 +#define HDISPR 0x0428 +#define VSR 0x042C +#define VDISPR 0x0430 +#define VFUEN 0x0434 + +/* DBI-B Host Registers */ +#define DBIBCTRL 0x0440 + +/* SPI Master Registers */ +#define SPICMR 0x0450 +#define SPITCR 0x0454 + +/* System Controller Registers */ +#define SYSSTAT 0x0460 +#define SYSCTRL 0x0464 +#define SYSPLL1 0x0468 +#define SYSPLL2 0x046C +#define SYSPLL3 0x0470 +#define SYSPMCTRL 0x047C + +/* GPIO Registers */ +#define GPIOC 0x0480 +#define GPIOO 0x0484 +#define GPIOI 0x0488 + +/* I2C Registers */ +#define I2CCLKCTRL 0x0490 + +/* Chip/Rev Registers */ +#define IDREG 0x04A0 + +/* Debug Registers */ +#define WCMDQUEUE 0x0500 +#define RCMDQUEUE 0x0504 + +struct rpi_touchscreen { + struct drm_panel base; + struct mipi_dsi_device *dsi; + struct i2c_client *i2c; +}; + +static const struct drm_display_mode rpi_touchscreen_modes[] = { + { + /* Modeline comes from the Raspberry Pi firmware, with HFP=1 + * plugged in and clock re-computed from that. + */ + .clock = 25979400 / 1000, + .hdisplay = 800, + .hsync_start = 800 + 1, + .hsync_end = 800 + 1 + 2, + .htotal = 800 + 1 + 2 + 46, + .vdisplay = 480, + .vsync_start = 480 + 7, + .vsync_end = 480 + 7 + 2, + .vtotal = 480 + 7 + 2 + 21, + .vrefresh = 60, + }, +}; + +static struct rpi_touchscreen *panel_to_ts(struct drm_panel *panel) +{ + return container_of(panel, struct rpi_touchscreen, base); +} + +static u8 rpi_touchscreen_i2c_read(struct rpi_touchscreen *ts, u8 reg) +{ + return i2c_smbus_read_byte_data(ts->i2c, reg); +} + +static void rpi_touchscreen_i2c_write(struct rpi_touchscreen *ts, + u8 reg, u8 val) +{ + int ret; + + ret = i2c_smbus_write_byte_data(ts->i2c, reg, val); + if (ret) + dev_err(&ts->dsi->dev, "I2C write failed: %d\n", ret); +} + +static int rpi_touchscreen_write(struct rpi_touchscreen *ts, u16 reg, u32 val) +{ +#if 0 + /* The firmware uses LP DSI transactions like this to bring up + * the hardware, which should be faster than using I2C to then + * pass to the Toshiba. However, I was unable to get it to + * work. + */ + u8 msg[] = { + reg, + reg >> 8, + val, + val >> 8, + val >> 16, + val >> 24, + }; + + mipi_dsi_dcs_write_buffer(ts->dsi, msg, sizeof(msg)); +#else + rpi_touchscreen_i2c_write(ts, REG_WR_ADDRH, reg >> 8); + rpi_touchscreen_i2c_write(ts, REG_WR_ADDRL, reg); + rpi_touchscreen_i2c_write(ts, REG_WRITEH, val >> 8); + rpi_touchscreen_i2c_write(ts, REG_WRITEL, val); +#endif + + return 0; +} + +static int rpi_touchscreen_disable(struct drm_panel *panel) +{ + struct rpi_touchscreen *ts = panel_to_ts(panel); + + rpi_touchscreen_i2c_write(ts, REG_PWM, 0); + + rpi_touchscreen_i2c_write(ts, REG_POWERON, 0); + udelay(1); + + return 0; +} + +static int rpi_touchscreen_noop(struct drm_panel *panel) +{ + return 0; +} + +static int rpi_touchscreen_enable(struct drm_panel *panel) +{ + struct rpi_touchscreen *ts = panel_to_ts(panel); + int i; + + rpi_touchscreen_i2c_write(ts, REG_POWERON, 1); + /* Wait for nPWRDWN to go low to indicate poweron is done. */ + for (i = 0; i < 100; i++) { + if (rpi_touchscreen_i2c_read(ts, REG_PORTB) & 1) + break; + } + + rpi_touchscreen_write(ts, DSI_LANEENABLE, + DSI_LANEENABLE_CLOCK | + DSI_LANEENABLE_D0); + rpi_touchscreen_write(ts, PPI_D0S_CLRSIPOCOUNT, 0x05); + rpi_touchscreen_write(ts, PPI_D1S_CLRSIPOCOUNT, 0x05); + rpi_touchscreen_write(ts, PPI_D0S_ATMR, 0x00); + rpi_touchscreen_write(ts, PPI_D1S_ATMR, 0x00); + rpi_touchscreen_write(ts, PPI_LPTXTIMECNT, 0x03); + + rpi_touchscreen_write(ts, SPICMR, 0x00); + rpi_touchscreen_write(ts, LCDCTRL, 0x00100150); + rpi_touchscreen_write(ts, SYSCTRL, 0x040f); + msleep(100); + + rpi_touchscreen_write(ts, PPI_STARTPPI, 0x01); + rpi_touchscreen_write(ts, DSI_STARTDSI, 0x01); + msleep(100); + + /* Turn on the backlight. */ + rpi_touchscreen_i2c_write(ts, REG_PWM, 255); + + /* Default to the same orientation as the closed source + * firmware used for the panel. Runtime rotation + * configuration will be supported using VC4's plane + * orientation bits. + */ + rpi_touchscreen_i2c_write(ts, REG_PORTA, BIT(2)); + + return 0; +} + +static int rpi_touchscreen_get_modes(struct drm_panel *panel) +{ + struct drm_connector *connector = panel->connector; + struct drm_device *drm = panel->drm; + unsigned int i, num = 0; + static const u32 bus_format = MEDIA_BUS_FMT_RGB888_1X24; + + for (i = 0; i < ARRAY_SIZE(rpi_touchscreen_modes); i++) { + const struct drm_display_mode *m = &rpi_touchscreen_modes[i]; + struct drm_display_mode *mode; + + mode = drm_mode_duplicate(drm, m); + if (!mode) { + dev_err(drm->dev, "failed to add mode %ux%u@%u\n", + m->hdisplay, m->vdisplay, m->vrefresh); + continue; + } + + mode->type |= DRM_MODE_TYPE_DRIVER; + + if (i == 0) + mode->type |= DRM_MODE_TYPE_PREFERRED; + + drm_mode_set_name(mode); + + drm_mode_probed_add(connector, mode); + num++; + } + + connector->display_info.bpc = 8; + connector->display_info.width_mm = 154; + connector->display_info.height_mm = 86; + drm_display_info_set_bus_formats(&connector->display_info, + &bus_format, 1); + + return num; +} + +static const struct drm_panel_funcs rpi_touchscreen_funcs = { + .disable = rpi_touchscreen_disable, + .unprepare = rpi_touchscreen_noop, + .prepare = rpi_touchscreen_noop, + .enable = rpi_touchscreen_enable, + .get_modes = rpi_touchscreen_get_modes, +}; + +static int rpi_touchscreen_probe(struct i2c_client *i2c, + const struct i2c_device_id *id) +{ + struct device *dev = &i2c->dev; + struct rpi_touchscreen *ts; + struct device_node *endpoint, *dsi_host_node; + struct mipi_dsi_host *host; + int ret, ver; + struct mipi_dsi_device_info info = { + .type = RPI_DSI_DRIVER_NAME, + .channel = 0, + .node = NULL, + }; + + ts = devm_kzalloc(dev, sizeof(*ts), GFP_KERNEL); + if (!ts) + return -ENOMEM; + + i2c_set_clientdata(i2c, ts); + + ts->i2c = i2c; + + ver = rpi_touchscreen_i2c_read(ts, REG_ID); + if (ver < 0) { + dev_err(dev, "Atmel I2C read failed: %d\n", ver); + return -ENODEV; + } + + switch (ver) { + case 0xde: /* ver 1 */ + case 0xc3: /* ver 2 */ + break; + default: + dev_err(dev, "Unknown Atmel firmware revision: 0x%02x\n", ver); + return -ENODEV; + } + + /* Turn off at boot, so we can cleanly sequence powering on. */ + rpi_touchscreen_i2c_write(ts, REG_POWERON, 0); + + /* Look up the DSI host. It needs to probe before we do. */ + endpoint = of_graph_get_next_endpoint(dev->of_node, NULL); + dsi_host_node = of_graph_get_remote_port_parent(endpoint); + host = of_find_mipi_dsi_host_by_node(dsi_host_node); + of_node_put(dsi_host_node); + if (!host) { + of_node_put(endpoint); + return -EPROBE_DEFER; + } + + info.node = of_graph_get_remote_port(endpoint); + of_node_put(endpoint); + + ts->dsi = mipi_dsi_device_register_full(host, &info); + if (IS_ERR(ts->dsi)) { + dev_err(dev, "DSI device registration failed: %ld\n", + PTR_ERR(ts->dsi)); + return PTR_ERR(ts->dsi); + } + + ts->base.dev = dev; + ts->base.funcs = &rpi_touchscreen_funcs; + + /* This appears last, as it's what will unblock the DSI host + * driver's component bind function. + */ + ret = drm_panel_add(&ts->base); + if (ret) + return ret; + + return 0; +} + +static int rpi_touchscreen_remove(struct i2c_client *i2c) +{ + struct rpi_touchscreen *ts = i2c_get_clientdata(i2c); + + mipi_dsi_detach(ts->dsi); + + drm_panel_remove(&ts->base); + + mipi_dsi_device_unregister(ts->dsi); + kfree(ts->dsi); + + return 0; +} + +static int rpi_touchscreen_dsi_probe(struct mipi_dsi_device *dsi) +{ + int ret; + + dsi->mode_flags = (MIPI_DSI_MODE_VIDEO | + MIPI_DSI_MODE_VIDEO_SYNC_PULSE | + MIPI_DSI_MODE_LPM); + dsi->format = MIPI_DSI_FMT_RGB888; + dsi->lanes = 1; + + ret = mipi_dsi_attach(dsi); + + if (ret) + dev_err(&dsi->dev, "failed to attach dsi to host: %d\n", ret); + + return ret; +} + +static struct mipi_dsi_driver rpi_touchscreen_dsi_driver = { + .driver.name = RPI_DSI_DRIVER_NAME, + .probe = rpi_touchscreen_dsi_probe, +}; + +static const struct of_device_id rpi_touchscreen_of_ids[] = { + { .compatible = "raspberrypi,7inch-touchscreen-panel" }, + { } /* sentinel */ +}; +MODULE_DEVICE_TABLE(of, rpi_touchscreen_of_ids); + +static struct i2c_driver rpi_touchscreen_driver = { + .driver = { + .name = "rpi_touchscreen", + .of_match_table = rpi_touchscreen_of_ids, + }, + .probe = rpi_touchscreen_probe, + .remove = rpi_touchscreen_remove, +}; + +static int __init rpi_touchscreen_init(void) +{ + mipi_dsi_driver_register(&rpi_touchscreen_dsi_driver); + return i2c_add_driver(&rpi_touchscreen_driver); +} +module_init(rpi_touchscreen_init); + +static void __exit rpi_touchscreen_exit(void) +{ + i2c_del_driver(&rpi_touchscreen_driver); + mipi_dsi_driver_unregister(&rpi_touchscreen_dsi_driver); +} +module_exit(rpi_touchscreen_exit); + +MODULE_AUTHOR("Eric Anholt eric@anholt.net"); +MODULE_DESCRIPTION("Raspberry Pi 7-inch touchscreen driver"); +MODULE_LICENSE("GPL v2");
On 09/28/2017 01:06 AM, Eric Anholt wrote:
This driver communicates with the Atmel microcontroller for sequencing the poweron of the TC358762 DSI-DPI bridge and controlling the backlight PWM.
v2: Set the same default orientation as the closed source firmware used, which is the best for viewing angle. v3: Rewrite as an i2c client driver after bridge driver rejection. v4: Finish probe without the DSI host, using the new delayed registration, and attach to the host during mipi_dsi_driver probe. v5: Rework to drop the "probe without DSI host" mode again, now that vc4 will create the host early on.
Reviewed-by: Archit Taneja architt@codeaurora.org
Signed-off-by: Eric Anholt eric@anholt.net
drivers/gpu/drm/panel/Kconfig | 8 + drivers/gpu/drm/panel/Makefile | 1 + .../gpu/drm/panel/panel-raspberrypi-touchscreen.c | 517 +++++++++++++++++++++ 3 files changed, 526 insertions(+) create mode 100644 drivers/gpu/drm/panel/panel-raspberrypi-touchscreen.c
diff --git a/drivers/gpu/drm/panel/Kconfig b/drivers/gpu/drm/panel/Kconfig index 718d8ce15b1f..726f3fb3312d 100644 --- a/drivers/gpu/drm/panel/Kconfig +++ b/drivers/gpu/drm/panel/Kconfig @@ -82,6 +82,14 @@ config DRM_PANEL_PANASONIC_VVX10F034N00 WUXGA (1920x1200) Novatek NT1397-based DSI panel as found in some Xperia Z2 tablets
+config DRM_PANEL_RASPBERRYPI_TOUCHSCREEN
- tristate "Raspberry Pi 7-inch touchscreen panel"
- depends on DRM_MIPI_DSI
- help
Say Y here if you want to enable support for the Raspberry
Pi 7" Touchscreen. To compile this driver as a module,
choose M here.
- config DRM_PANEL_SAMSUNG_S6E3HA2 tristate "Samsung S6E3HA2 DSI video mode panel" depends on OF
diff --git a/drivers/gpu/drm/panel/Makefile b/drivers/gpu/drm/panel/Makefile index c8483fdd5b9b..77ede3467324 100644 --- a/drivers/gpu/drm/panel/Makefile +++ b/drivers/gpu/drm/panel/Makefile @@ -5,6 +5,7 @@ obj-$(CONFIG_DRM_PANEL_JDI_LT070ME05000) += panel-jdi-lt070me05000.o obj-$(CONFIG_DRM_PANEL_LG_LG4573) += panel-lg-lg4573.o obj-$(CONFIG_DRM_PANEL_ORISETECH_OTM8009A) += panel-orisetech-otm8009a.o obj-$(CONFIG_DRM_PANEL_PANASONIC_VVX10F034N00) += panel-panasonic-vvx10f034n00.o +obj-$(CONFIG_DRM_PANEL_RASPBERRYPI_TOUCHSCREEN) += panel-raspberrypi-touchscreen.o obj-$(CONFIG_DRM_PANEL_SAMSUNG_LD9040) += panel-samsung-ld9040.o obj-$(CONFIG_DRM_PANEL_SAMSUNG_S6E3HA2) += panel-samsung-s6e3ha2.o obj-$(CONFIG_DRM_PANEL_SAMSUNG_S6E63J0X03) += panel-samsung-s6e63j0x03.o diff --git a/drivers/gpu/drm/panel/panel-raspberrypi-touchscreen.c b/drivers/gpu/drm/panel/panel-raspberrypi-touchscreen.c new file mode 100644 index 000000000000..4237a0cbcdcc --- /dev/null +++ b/drivers/gpu/drm/panel/panel-raspberrypi-touchscreen.c @@ -0,0 +1,517 @@ +/*
- Copyright © 2016-2017 Broadcom
- 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.
- Portions of this file (derived from panel-simple.c) are:
- Copyright (C) 2013, NVIDIA Corporation. All rights reserved.
- Permission is hereby granted, free of charge, to any person obtaining a
- copy of this software and associated documentation files (the "Software"),
- to deal in the Software without restriction, including without limitation
- the rights to use, copy, modify, merge, publish, distribute, sub license,
- and/or sell copies of the Software, and to permit persons to whom the
- Software is furnished to do so, subject to the following conditions:
- The above copyright notice and this permission notice (including the
- next paragraph) shall be included in all copies or substantial portions
- of the Software.
- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
- THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
- FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
- DEALINGS IN THE SOFTWARE.
- */
+/**
- Raspberry Pi 7" touchscreen panel driver.
- The 7" touchscreen consists of a DPI LCD panel, a Toshiba
- TC358762XBG DSI-DPI bridge, and an I2C-connected Atmel ATTINY88-MUR
- controlling power management, the LCD PWM, and initial register
- setup of the Tohsiba.
- This driver controls the TC358762 and ATTINY88, presenting a DSI
- device with a drm_panel.
- */
+#include <linux/delay.h> +#include <linux/err.h> +#include <linux/fb.h> +#include <linux/gpio.h> +#include <linux/gpio/consumer.h> +#include <linux/i2c.h> +#include <linux/module.h> +#include <linux/of.h> +#include <linux/of_device.h> +#include <linux/of_graph.h> +#include <linux/pm.h>
+#include <drm/drm_panel.h> +#include <drm/drmP.h> +#include <drm/drm_crtc.h> +#include <drm/drm_mipi_dsi.h> +#include <drm/drm_panel.h>
+#define RPI_DSI_DRIVER_NAME "rpi-ts-dsi"
+/* I2C registers of the Atmel microcontroller. */ +enum REG_ADDR {
- REG_ID = 0x80,
- REG_PORTA, /* BIT(2) for horizontal flip, BIT(3) for vertical flip */
- REG_PORTB,
- REG_PORTC,
- REG_PORTD,
- REG_POWERON,
- REG_PWM,
- REG_DDRA,
- REG_DDRB,
- REG_DDRC,
- REG_DDRD,
- REG_TEST,
- REG_WR_ADDRL,
- REG_WR_ADDRH,
- REG_READH,
- REG_READL,
- REG_WRITEH,
- REG_WRITEL,
- REG_ID2,
+};
+/* We only turn the PWM on or off, without varying values. */ +#define RPI_TOUCHSCREEN_MAX_BRIGHTNESS 1
+/* DSI D-PHY Layer Registers */ +#define D0W_DPHYCONTTX 0x0004 +#define CLW_DPHYCONTRX 0x0020 +#define D0W_DPHYCONTRX 0x0024 +#define D1W_DPHYCONTRX 0x0028 +#define COM_DPHYCONTRX 0x0038 +#define CLW_CNTRL 0x0040 +#define D0W_CNTRL 0x0044 +#define D1W_CNTRL 0x0048 +#define DFTMODE_CNTRL 0x0054
+/* DSI PPI Layer Registers */ +#define PPI_STARTPPI 0x0104 +#define PPI_BUSYPPI 0x0108 +#define PPI_LINEINITCNT 0x0110 +#define PPI_LPTXTIMECNT 0x0114 +#define PPI_CLS_ATMR 0x0140 +#define PPI_D0S_ATMR 0x0144 +#define PPI_D1S_ATMR 0x0148 +#define PPI_D0S_CLRSIPOCOUNT 0x0164 +#define PPI_D1S_CLRSIPOCOUNT 0x0168 +#define CLS_PRE 0x0180 +#define D0S_PRE 0x0184 +#define D1S_PRE 0x0188 +#define CLS_PREP 0x01A0 +#define D0S_PREP 0x01A4 +#define D1S_PREP 0x01A8 +#define CLS_ZERO 0x01C0 +#define D0S_ZERO 0x01C4 +#define D1S_ZERO 0x01C8 +#define PPI_CLRFLG 0x01E0 +#define PPI_CLRSIPO 0x01E4 +#define HSTIMEOUT 0x01F0 +#define HSTIMEOUTENABLE 0x01F4
+/* DSI Protocol Layer Registers */ +#define DSI_STARTDSI 0x0204 +#define DSI_BUSYDSI 0x0208 +#define DSI_LANEENABLE 0x0210 +# define DSI_LANEENABLE_CLOCK BIT(0) +# define DSI_LANEENABLE_D0 BIT(1) +# define DSI_LANEENABLE_D1 BIT(2)
+#define DSI_LANESTATUS0 0x0214 +#define DSI_LANESTATUS1 0x0218 +#define DSI_INTSTATUS 0x0220 +#define DSI_INTMASK 0x0224 +#define DSI_INTCLR 0x0228 +#define DSI_LPTXTO 0x0230 +#define DSI_MODE 0x0260 +#define DSI_PAYLOAD0 0x0268 +#define DSI_PAYLOAD1 0x026C +#define DSI_SHORTPKTDAT 0x0270 +#define DSI_SHORTPKTREQ 0x0274 +#define DSI_BTASTA 0x0278 +#define DSI_BTACLR 0x027C
+/* DSI General Registers */ +#define DSIERRCNT 0x0300 +#define DSISIGMOD 0x0304
+/* DSI Application Layer Registers */ +#define APLCTRL 0x0400 +#define APLSTAT 0x0404 +#define APLERR 0x0408 +#define PWRMOD 0x040C +#define RDPKTLN 0x0410 +#define PXLFMT 0x0414 +#define MEMWRCMD 0x0418
+/* LCDC/DPI Host Registers */ +#define LCDCTRL 0x0420 +#define HSR 0x0424 +#define HDISPR 0x0428 +#define VSR 0x042C +#define VDISPR 0x0430 +#define VFUEN 0x0434
+/* DBI-B Host Registers */ +#define DBIBCTRL 0x0440
+/* SPI Master Registers */ +#define SPICMR 0x0450 +#define SPITCR 0x0454
+/* System Controller Registers */ +#define SYSSTAT 0x0460 +#define SYSCTRL 0x0464 +#define SYSPLL1 0x0468 +#define SYSPLL2 0x046C +#define SYSPLL3 0x0470 +#define SYSPMCTRL 0x047C
+/* GPIO Registers */ +#define GPIOC 0x0480 +#define GPIOO 0x0484 +#define GPIOI 0x0488
+/* I2C Registers */ +#define I2CCLKCTRL 0x0490
+/* Chip/Rev Registers */ +#define IDREG 0x04A0
+/* Debug Registers */ +#define WCMDQUEUE 0x0500 +#define RCMDQUEUE 0x0504
+struct rpi_touchscreen {
- struct drm_panel base;
- struct mipi_dsi_device *dsi;
- struct i2c_client *i2c;
+};
+static const struct drm_display_mode rpi_touchscreen_modes[] = {
- {
/* Modeline comes from the Raspberry Pi firmware, with HFP=1
* plugged in and clock re-computed from that.
*/
.clock = 25979400 / 1000,
.hdisplay = 800,
.hsync_start = 800 + 1,
.hsync_end = 800 + 1 + 2,
.htotal = 800 + 1 + 2 + 46,
.vdisplay = 480,
.vsync_start = 480 + 7,
.vsync_end = 480 + 7 + 2,
.vtotal = 480 + 7 + 2 + 21,
.vrefresh = 60,
- },
+};
+static struct rpi_touchscreen *panel_to_ts(struct drm_panel *panel) +{
- return container_of(panel, struct rpi_touchscreen, base);
+}
+static u8 rpi_touchscreen_i2c_read(struct rpi_touchscreen *ts, u8 reg) +{
- return i2c_smbus_read_byte_data(ts->i2c, reg);
+}
+static void rpi_touchscreen_i2c_write(struct rpi_touchscreen *ts,
u8 reg, u8 val)
+{
- int ret;
- ret = i2c_smbus_write_byte_data(ts->i2c, reg, val);
- if (ret)
dev_err(&ts->dsi->dev, "I2C write failed: %d\n", ret);
+}
+static int rpi_touchscreen_write(struct rpi_touchscreen *ts, u16 reg, u32 val) +{ +#if 0
- /* The firmware uses LP DSI transactions like this to bring up
* the hardware, which should be faster than using I2C to then
* pass to the Toshiba. However, I was unable to get it to
* work.
*/
- u8 msg[] = {
reg,
reg >> 8,
val,
val >> 8,
val >> 16,
val >> 24,
- };
- mipi_dsi_dcs_write_buffer(ts->dsi, msg, sizeof(msg));
+#else
- rpi_touchscreen_i2c_write(ts, REG_WR_ADDRH, reg >> 8);
- rpi_touchscreen_i2c_write(ts, REG_WR_ADDRL, reg);
- rpi_touchscreen_i2c_write(ts, REG_WRITEH, val >> 8);
- rpi_touchscreen_i2c_write(ts, REG_WRITEL, val);
+#endif
- return 0;
+}
+static int rpi_touchscreen_disable(struct drm_panel *panel) +{
- struct rpi_touchscreen *ts = panel_to_ts(panel);
- rpi_touchscreen_i2c_write(ts, REG_PWM, 0);
- rpi_touchscreen_i2c_write(ts, REG_POWERON, 0);
- udelay(1);
- return 0;
+}
+static int rpi_touchscreen_noop(struct drm_panel *panel) +{
- return 0;
+}
+static int rpi_touchscreen_enable(struct drm_panel *panel) +{
- struct rpi_touchscreen *ts = panel_to_ts(panel);
- int i;
- rpi_touchscreen_i2c_write(ts, REG_POWERON, 1);
- /* Wait for nPWRDWN to go low to indicate poweron is done. */
- for (i = 0; i < 100; i++) {
if (rpi_touchscreen_i2c_read(ts, REG_PORTB) & 1)
break;
- }
- rpi_touchscreen_write(ts, DSI_LANEENABLE,
DSI_LANEENABLE_CLOCK |
DSI_LANEENABLE_D0);
- rpi_touchscreen_write(ts, PPI_D0S_CLRSIPOCOUNT, 0x05);
- rpi_touchscreen_write(ts, PPI_D1S_CLRSIPOCOUNT, 0x05);
- rpi_touchscreen_write(ts, PPI_D0S_ATMR, 0x00);
- rpi_touchscreen_write(ts, PPI_D1S_ATMR, 0x00);
- rpi_touchscreen_write(ts, PPI_LPTXTIMECNT, 0x03);
- rpi_touchscreen_write(ts, SPICMR, 0x00);
- rpi_touchscreen_write(ts, LCDCTRL, 0x00100150);
- rpi_touchscreen_write(ts, SYSCTRL, 0x040f);
- msleep(100);
- rpi_touchscreen_write(ts, PPI_STARTPPI, 0x01);
- rpi_touchscreen_write(ts, DSI_STARTDSI, 0x01);
- msleep(100);
- /* Turn on the backlight. */
- rpi_touchscreen_i2c_write(ts, REG_PWM, 255);
- /* Default to the same orientation as the closed source
* firmware used for the panel. Runtime rotation
* configuration will be supported using VC4's plane
* orientation bits.
*/
- rpi_touchscreen_i2c_write(ts, REG_PORTA, BIT(2));
- return 0;
+}
+static int rpi_touchscreen_get_modes(struct drm_panel *panel) +{
- struct drm_connector *connector = panel->connector;
- struct drm_device *drm = panel->drm;
- unsigned int i, num = 0;
- static const u32 bus_format = MEDIA_BUS_FMT_RGB888_1X24;
- for (i = 0; i < ARRAY_SIZE(rpi_touchscreen_modes); i++) {
const struct drm_display_mode *m = &rpi_touchscreen_modes[i];
struct drm_display_mode *mode;
mode = drm_mode_duplicate(drm, m);
if (!mode) {
dev_err(drm->dev, "failed to add mode %ux%u@%u\n",
m->hdisplay, m->vdisplay, m->vrefresh);
continue;
}
mode->type |= DRM_MODE_TYPE_DRIVER;
if (i == 0)
mode->type |= DRM_MODE_TYPE_PREFERRED;
drm_mode_set_name(mode);
drm_mode_probed_add(connector, mode);
num++;
- }
- connector->display_info.bpc = 8;
- connector->display_info.width_mm = 154;
- connector->display_info.height_mm = 86;
- drm_display_info_set_bus_formats(&connector->display_info,
&bus_format, 1);
- return num;
+}
+static const struct drm_panel_funcs rpi_touchscreen_funcs = {
- .disable = rpi_touchscreen_disable,
- .unprepare = rpi_touchscreen_noop,
- .prepare = rpi_touchscreen_noop,
- .enable = rpi_touchscreen_enable,
- .get_modes = rpi_touchscreen_get_modes,
+};
+static int rpi_touchscreen_probe(struct i2c_client *i2c,
const struct i2c_device_id *id)
+{
- struct device *dev = &i2c->dev;
- struct rpi_touchscreen *ts;
- struct device_node *endpoint, *dsi_host_node;
- struct mipi_dsi_host *host;
- int ret, ver;
- struct mipi_dsi_device_info info = {
.type = RPI_DSI_DRIVER_NAME,
.channel = 0,
.node = NULL,
- };
- ts = devm_kzalloc(dev, sizeof(*ts), GFP_KERNEL);
- if (!ts)
return -ENOMEM;
- i2c_set_clientdata(i2c, ts);
- ts->i2c = i2c;
- ver = rpi_touchscreen_i2c_read(ts, REG_ID);
- if (ver < 0) {
dev_err(dev, "Atmel I2C read failed: %d\n", ver);
return -ENODEV;
- }
- switch (ver) {
- case 0xde: /* ver 1 */
- case 0xc3: /* ver 2 */
break;
- default:
dev_err(dev, "Unknown Atmel firmware revision: 0x%02x\n", ver);
return -ENODEV;
- }
- /* Turn off at boot, so we can cleanly sequence powering on. */
- rpi_touchscreen_i2c_write(ts, REG_POWERON, 0);
- /* Look up the DSI host. It needs to probe before we do. */
- endpoint = of_graph_get_next_endpoint(dev->of_node, NULL);
- dsi_host_node = of_graph_get_remote_port_parent(endpoint);
- host = of_find_mipi_dsi_host_by_node(dsi_host_node);
- of_node_put(dsi_host_node);
- if (!host) {
of_node_put(endpoint);
return -EPROBE_DEFER;
- }
- info.node = of_graph_get_remote_port(endpoint);
- of_node_put(endpoint);
- ts->dsi = mipi_dsi_device_register_full(host, &info);
- if (IS_ERR(ts->dsi)) {
dev_err(dev, "DSI device registration failed: %ld\n",
PTR_ERR(ts->dsi));
return PTR_ERR(ts->dsi);
- }
- ts->base.dev = dev;
- ts->base.funcs = &rpi_touchscreen_funcs;
- /* This appears last, as it's what will unblock the DSI host
* driver's component bind function.
*/
- ret = drm_panel_add(&ts->base);
- if (ret)
return ret;
- return 0;
+}
+static int rpi_touchscreen_remove(struct i2c_client *i2c) +{
- struct rpi_touchscreen *ts = i2c_get_clientdata(i2c);
- mipi_dsi_detach(ts->dsi);
- drm_panel_remove(&ts->base);
- mipi_dsi_device_unregister(ts->dsi);
- kfree(ts->dsi);
- return 0;
+}
+static int rpi_touchscreen_dsi_probe(struct mipi_dsi_device *dsi) +{
- int ret;
- dsi->mode_flags = (MIPI_DSI_MODE_VIDEO |
MIPI_DSI_MODE_VIDEO_SYNC_PULSE |
MIPI_DSI_MODE_LPM);
- dsi->format = MIPI_DSI_FMT_RGB888;
- dsi->lanes = 1;
- ret = mipi_dsi_attach(dsi);
- if (ret)
dev_err(&dsi->dev, "failed to attach dsi to host: %d\n", ret);
- return ret;
+}
+static struct mipi_dsi_driver rpi_touchscreen_dsi_driver = {
- .driver.name = RPI_DSI_DRIVER_NAME,
- .probe = rpi_touchscreen_dsi_probe,
+};
+static const struct of_device_id rpi_touchscreen_of_ids[] = {
- { .compatible = "raspberrypi,7inch-touchscreen-panel" },
- { } /* sentinel */
+}; +MODULE_DEVICE_TABLE(of, rpi_touchscreen_of_ids);
+static struct i2c_driver rpi_touchscreen_driver = {
- .driver = {
.name = "rpi_touchscreen",
.of_match_table = rpi_touchscreen_of_ids,
- },
- .probe = rpi_touchscreen_probe,
- .remove = rpi_touchscreen_remove,
+};
+static int __init rpi_touchscreen_init(void) +{
- mipi_dsi_driver_register(&rpi_touchscreen_dsi_driver);
- return i2c_add_driver(&rpi_touchscreen_driver);
+} +module_init(rpi_touchscreen_init);
+static void __exit rpi_touchscreen_exit(void) +{
- i2c_del_driver(&rpi_touchscreen_driver);
- mipi_dsi_driver_unregister(&rpi_touchscreen_dsi_driver);
+} +module_exit(rpi_touchscreen_exit);
+MODULE_AUTHOR("Eric Anholt eric@anholt.net"); +MODULE_DESCRIPTION("Raspberry Pi 7-inch touchscreen driver"); +MODULE_LICENSE("GPL v2");
On Wed, Sep 27, 2017 at 12:36:54PM -0700, Eric Anholt wrote: [...]
diff --git a/drivers/gpu/drm/panel/panel-raspberrypi-touchscreen.c b/drivers/gpu/drm/panel/panel-raspberrypi-touchscreen.c
[...]
+/* We only turn the PWM on or off, without varying values. */ +#define RPI_TOUCHSCREEN_MAX_BRIGHTNESS 1
This seems to be unused now.
Otherwise:
Acked-by: Thierry Reding treding@nvidia.com
dri-devel@lists.freedesktop.org