xref: /OK3568_Linux_fs/kernel/drivers/gpu/drm/panel/panel-raspberrypi-touchscreen.c (revision 4882a59341e53eb6f0b4789bf948001014eff981)
1*4882a593Smuzhiyun /*
2*4882a593Smuzhiyun  * Copyright © 2016-2017 Broadcom
3*4882a593Smuzhiyun  *
4*4882a593Smuzhiyun  * This program is free software; you can redistribute it and/or modify
5*4882a593Smuzhiyun  * it under the terms of the GNU General Public License version 2 as
6*4882a593Smuzhiyun  * published by the Free Software Foundation.
7*4882a593Smuzhiyun  *
8*4882a593Smuzhiyun  * Portions of this file (derived from panel-simple.c) are:
9*4882a593Smuzhiyun  *
10*4882a593Smuzhiyun  * Copyright (C) 2013, NVIDIA Corporation.  All rights reserved.
11*4882a593Smuzhiyun  *
12*4882a593Smuzhiyun  * Permission is hereby granted, free of charge, to any person obtaining a
13*4882a593Smuzhiyun  * copy of this software and associated documentation files (the "Software"),
14*4882a593Smuzhiyun  * to deal in the Software without restriction, including without limitation
15*4882a593Smuzhiyun  * the rights to use, copy, modify, merge, publish, distribute, sub license,
16*4882a593Smuzhiyun  * and/or sell copies of the Software, and to permit persons to whom the
17*4882a593Smuzhiyun  * Software is furnished to do so, subject to the following conditions:
18*4882a593Smuzhiyun  *
19*4882a593Smuzhiyun  * The above copyright notice and this permission notice (including the
20*4882a593Smuzhiyun  * next paragraph) shall be included in all copies or substantial portions
21*4882a593Smuzhiyun  * of the Software.
22*4882a593Smuzhiyun  *
23*4882a593Smuzhiyun  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
24*4882a593Smuzhiyun  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
25*4882a593Smuzhiyun  * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
26*4882a593Smuzhiyun  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
27*4882a593Smuzhiyun  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
28*4882a593Smuzhiyun  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
29*4882a593Smuzhiyun  * DEALINGS IN THE SOFTWARE.
30*4882a593Smuzhiyun  */
31*4882a593Smuzhiyun 
32*4882a593Smuzhiyun /**
33*4882a593Smuzhiyun  * Raspberry Pi 7" touchscreen panel driver.
34*4882a593Smuzhiyun  *
35*4882a593Smuzhiyun  * The 7" touchscreen consists of a DPI LCD panel, a Toshiba
36*4882a593Smuzhiyun  * TC358762XBG DSI-DPI bridge, and an I2C-connected Atmel ATTINY88-MUR
37*4882a593Smuzhiyun  * controlling power management, the LCD PWM, and initial register
38*4882a593Smuzhiyun  * setup of the Tohsiba.
39*4882a593Smuzhiyun  *
40*4882a593Smuzhiyun  * This driver controls the TC358762 and ATTINY88, presenting a DSI
41*4882a593Smuzhiyun  * device with a drm_panel.
42*4882a593Smuzhiyun  */
43*4882a593Smuzhiyun 
44*4882a593Smuzhiyun #include <linux/delay.h>
45*4882a593Smuzhiyun #include <linux/err.h>
46*4882a593Smuzhiyun #include <linux/fb.h>
47*4882a593Smuzhiyun #include <linux/i2c.h>
48*4882a593Smuzhiyun #include <linux/module.h>
49*4882a593Smuzhiyun #include <linux/of.h>
50*4882a593Smuzhiyun #include <linux/of_device.h>
51*4882a593Smuzhiyun #include <linux/of_graph.h>
52*4882a593Smuzhiyun #include <linux/pm.h>
53*4882a593Smuzhiyun 
54*4882a593Smuzhiyun #include <drm/drm_crtc.h>
55*4882a593Smuzhiyun #include <drm/drm_device.h>
56*4882a593Smuzhiyun #include <drm/drm_mipi_dsi.h>
57*4882a593Smuzhiyun #include <drm/drm_panel.h>
58*4882a593Smuzhiyun 
59*4882a593Smuzhiyun #define RPI_DSI_DRIVER_NAME "rpi-ts-dsi"
60*4882a593Smuzhiyun 
61*4882a593Smuzhiyun /* I2C registers of the Atmel microcontroller. */
62*4882a593Smuzhiyun enum REG_ADDR {
63*4882a593Smuzhiyun 	REG_ID = 0x80,
64*4882a593Smuzhiyun 	REG_PORTA, /* BIT(2) for horizontal flip, BIT(3) for vertical flip */
65*4882a593Smuzhiyun 	REG_PORTB,
66*4882a593Smuzhiyun 	REG_PORTC,
67*4882a593Smuzhiyun 	REG_PORTD,
68*4882a593Smuzhiyun 	REG_POWERON,
69*4882a593Smuzhiyun 	REG_PWM,
70*4882a593Smuzhiyun 	REG_DDRA,
71*4882a593Smuzhiyun 	REG_DDRB,
72*4882a593Smuzhiyun 	REG_DDRC,
73*4882a593Smuzhiyun 	REG_DDRD,
74*4882a593Smuzhiyun 	REG_TEST,
75*4882a593Smuzhiyun 	REG_WR_ADDRL,
76*4882a593Smuzhiyun 	REG_WR_ADDRH,
77*4882a593Smuzhiyun 	REG_READH,
78*4882a593Smuzhiyun 	REG_READL,
79*4882a593Smuzhiyun 	REG_WRITEH,
80*4882a593Smuzhiyun 	REG_WRITEL,
81*4882a593Smuzhiyun 	REG_ID2,
82*4882a593Smuzhiyun };
83*4882a593Smuzhiyun 
84*4882a593Smuzhiyun /* DSI D-PHY Layer Registers */
85*4882a593Smuzhiyun #define D0W_DPHYCONTTX		0x0004
86*4882a593Smuzhiyun #define CLW_DPHYCONTRX		0x0020
87*4882a593Smuzhiyun #define D0W_DPHYCONTRX		0x0024
88*4882a593Smuzhiyun #define D1W_DPHYCONTRX		0x0028
89*4882a593Smuzhiyun #define COM_DPHYCONTRX		0x0038
90*4882a593Smuzhiyun #define CLW_CNTRL		0x0040
91*4882a593Smuzhiyun #define D0W_CNTRL		0x0044
92*4882a593Smuzhiyun #define D1W_CNTRL		0x0048
93*4882a593Smuzhiyun #define DFTMODE_CNTRL		0x0054
94*4882a593Smuzhiyun 
95*4882a593Smuzhiyun /* DSI PPI Layer Registers */
96*4882a593Smuzhiyun #define PPI_STARTPPI		0x0104
97*4882a593Smuzhiyun #define PPI_BUSYPPI		0x0108
98*4882a593Smuzhiyun #define PPI_LINEINITCNT		0x0110
99*4882a593Smuzhiyun #define PPI_LPTXTIMECNT		0x0114
100*4882a593Smuzhiyun #define PPI_CLS_ATMR		0x0140
101*4882a593Smuzhiyun #define PPI_D0S_ATMR		0x0144
102*4882a593Smuzhiyun #define PPI_D1S_ATMR		0x0148
103*4882a593Smuzhiyun #define PPI_D0S_CLRSIPOCOUNT	0x0164
104*4882a593Smuzhiyun #define PPI_D1S_CLRSIPOCOUNT	0x0168
105*4882a593Smuzhiyun #define CLS_PRE			0x0180
106*4882a593Smuzhiyun #define D0S_PRE			0x0184
107*4882a593Smuzhiyun #define D1S_PRE			0x0188
108*4882a593Smuzhiyun #define CLS_PREP		0x01A0
109*4882a593Smuzhiyun #define D0S_PREP		0x01A4
110*4882a593Smuzhiyun #define D1S_PREP		0x01A8
111*4882a593Smuzhiyun #define CLS_ZERO		0x01C0
112*4882a593Smuzhiyun #define D0S_ZERO		0x01C4
113*4882a593Smuzhiyun #define D1S_ZERO		0x01C8
114*4882a593Smuzhiyun #define PPI_CLRFLG		0x01E0
115*4882a593Smuzhiyun #define PPI_CLRSIPO		0x01E4
116*4882a593Smuzhiyun #define HSTIMEOUT		0x01F0
117*4882a593Smuzhiyun #define HSTIMEOUTENABLE		0x01F4
118*4882a593Smuzhiyun 
119*4882a593Smuzhiyun /* DSI Protocol Layer Registers */
120*4882a593Smuzhiyun #define DSI_STARTDSI		0x0204
121*4882a593Smuzhiyun #define DSI_BUSYDSI		0x0208
122*4882a593Smuzhiyun #define DSI_LANEENABLE		0x0210
123*4882a593Smuzhiyun # define DSI_LANEENABLE_CLOCK		BIT(0)
124*4882a593Smuzhiyun # define DSI_LANEENABLE_D0		BIT(1)
125*4882a593Smuzhiyun # define DSI_LANEENABLE_D1		BIT(2)
126*4882a593Smuzhiyun 
127*4882a593Smuzhiyun #define DSI_LANESTATUS0		0x0214
128*4882a593Smuzhiyun #define DSI_LANESTATUS1		0x0218
129*4882a593Smuzhiyun #define DSI_INTSTATUS		0x0220
130*4882a593Smuzhiyun #define DSI_INTMASK		0x0224
131*4882a593Smuzhiyun #define DSI_INTCLR		0x0228
132*4882a593Smuzhiyun #define DSI_LPTXTO		0x0230
133*4882a593Smuzhiyun #define DSI_MODE		0x0260
134*4882a593Smuzhiyun #define DSI_PAYLOAD0		0x0268
135*4882a593Smuzhiyun #define DSI_PAYLOAD1		0x026C
136*4882a593Smuzhiyun #define DSI_SHORTPKTDAT		0x0270
137*4882a593Smuzhiyun #define DSI_SHORTPKTREQ		0x0274
138*4882a593Smuzhiyun #define DSI_BTASTA		0x0278
139*4882a593Smuzhiyun #define DSI_BTACLR		0x027C
140*4882a593Smuzhiyun 
141*4882a593Smuzhiyun /* DSI General Registers */
142*4882a593Smuzhiyun #define DSIERRCNT		0x0300
143*4882a593Smuzhiyun #define DSISIGMOD		0x0304
144*4882a593Smuzhiyun 
145*4882a593Smuzhiyun /* DSI Application Layer Registers */
146*4882a593Smuzhiyun #define APLCTRL			0x0400
147*4882a593Smuzhiyun #define APLSTAT			0x0404
148*4882a593Smuzhiyun #define APLERR			0x0408
149*4882a593Smuzhiyun #define PWRMOD			0x040C
150*4882a593Smuzhiyun #define RDPKTLN			0x0410
151*4882a593Smuzhiyun #define PXLFMT			0x0414
152*4882a593Smuzhiyun #define MEMWRCMD		0x0418
153*4882a593Smuzhiyun 
154*4882a593Smuzhiyun /* LCDC/DPI Host Registers */
155*4882a593Smuzhiyun #define LCDCTRL			0x0420
156*4882a593Smuzhiyun #define HSR			0x0424
157*4882a593Smuzhiyun #define HDISPR			0x0428
158*4882a593Smuzhiyun #define VSR			0x042C
159*4882a593Smuzhiyun #define VDISPR			0x0430
160*4882a593Smuzhiyun #define VFUEN			0x0434
161*4882a593Smuzhiyun 
162*4882a593Smuzhiyun /* DBI-B Host Registers */
163*4882a593Smuzhiyun #define DBIBCTRL		0x0440
164*4882a593Smuzhiyun 
165*4882a593Smuzhiyun /* SPI Master Registers */
166*4882a593Smuzhiyun #define SPICMR			0x0450
167*4882a593Smuzhiyun #define SPITCR			0x0454
168*4882a593Smuzhiyun 
169*4882a593Smuzhiyun /* System Controller Registers */
170*4882a593Smuzhiyun #define SYSSTAT			0x0460
171*4882a593Smuzhiyun #define SYSCTRL			0x0464
172*4882a593Smuzhiyun #define SYSPLL1			0x0468
173*4882a593Smuzhiyun #define SYSPLL2			0x046C
174*4882a593Smuzhiyun #define SYSPLL3			0x0470
175*4882a593Smuzhiyun #define SYSPMCTRL		0x047C
176*4882a593Smuzhiyun 
177*4882a593Smuzhiyun /* GPIO Registers */
178*4882a593Smuzhiyun #define GPIOC			0x0480
179*4882a593Smuzhiyun #define GPIOO			0x0484
180*4882a593Smuzhiyun #define GPIOI			0x0488
181*4882a593Smuzhiyun 
182*4882a593Smuzhiyun /* I2C Registers */
183*4882a593Smuzhiyun #define I2CCLKCTRL		0x0490
184*4882a593Smuzhiyun 
185*4882a593Smuzhiyun /* Chip/Rev Registers */
186*4882a593Smuzhiyun #define IDREG			0x04A0
187*4882a593Smuzhiyun 
188*4882a593Smuzhiyun /* Debug Registers */
189*4882a593Smuzhiyun #define WCMDQUEUE		0x0500
190*4882a593Smuzhiyun #define RCMDQUEUE		0x0504
191*4882a593Smuzhiyun 
192*4882a593Smuzhiyun struct rpi_touchscreen {
193*4882a593Smuzhiyun 	struct drm_panel base;
194*4882a593Smuzhiyun 	struct mipi_dsi_device *dsi;
195*4882a593Smuzhiyun 	struct i2c_client *i2c;
196*4882a593Smuzhiyun };
197*4882a593Smuzhiyun 
198*4882a593Smuzhiyun static const struct drm_display_mode rpi_touchscreen_modes[] = {
199*4882a593Smuzhiyun 	{
200*4882a593Smuzhiyun 		/* Modeline comes from the Raspberry Pi firmware, with HFP=1
201*4882a593Smuzhiyun 		 * plugged in and clock re-computed from that.
202*4882a593Smuzhiyun 		 */
203*4882a593Smuzhiyun 		.clock = 25979400 / 1000,
204*4882a593Smuzhiyun 		.hdisplay = 800,
205*4882a593Smuzhiyun 		.hsync_start = 800 + 1,
206*4882a593Smuzhiyun 		.hsync_end = 800 + 1 + 2,
207*4882a593Smuzhiyun 		.htotal = 800 + 1 + 2 + 46,
208*4882a593Smuzhiyun 		.vdisplay = 480,
209*4882a593Smuzhiyun 		.vsync_start = 480 + 7,
210*4882a593Smuzhiyun 		.vsync_end = 480 + 7 + 2,
211*4882a593Smuzhiyun 		.vtotal = 480 + 7 + 2 + 21,
212*4882a593Smuzhiyun 	},
213*4882a593Smuzhiyun };
214*4882a593Smuzhiyun 
panel_to_ts(struct drm_panel * panel)215*4882a593Smuzhiyun static struct rpi_touchscreen *panel_to_ts(struct drm_panel *panel)
216*4882a593Smuzhiyun {
217*4882a593Smuzhiyun 	return container_of(panel, struct rpi_touchscreen, base);
218*4882a593Smuzhiyun }
219*4882a593Smuzhiyun 
rpi_touchscreen_i2c_read(struct rpi_touchscreen * ts,u8 reg)220*4882a593Smuzhiyun static int rpi_touchscreen_i2c_read(struct rpi_touchscreen *ts, u8 reg)
221*4882a593Smuzhiyun {
222*4882a593Smuzhiyun 	return i2c_smbus_read_byte_data(ts->i2c, reg);
223*4882a593Smuzhiyun }
224*4882a593Smuzhiyun 
rpi_touchscreen_i2c_write(struct rpi_touchscreen * ts,u8 reg,u8 val)225*4882a593Smuzhiyun static void rpi_touchscreen_i2c_write(struct rpi_touchscreen *ts,
226*4882a593Smuzhiyun 				      u8 reg, u8 val)
227*4882a593Smuzhiyun {
228*4882a593Smuzhiyun 	int ret;
229*4882a593Smuzhiyun 
230*4882a593Smuzhiyun 	ret = i2c_smbus_write_byte_data(ts->i2c, reg, val);
231*4882a593Smuzhiyun 	if (ret)
232*4882a593Smuzhiyun 		dev_err(&ts->i2c->dev, "I2C write failed: %d\n", ret);
233*4882a593Smuzhiyun }
234*4882a593Smuzhiyun 
rpi_touchscreen_write(struct rpi_touchscreen * ts,u16 reg,u32 val)235*4882a593Smuzhiyun static int rpi_touchscreen_write(struct rpi_touchscreen *ts, u16 reg, u32 val)
236*4882a593Smuzhiyun {
237*4882a593Smuzhiyun 	u8 msg[] = {
238*4882a593Smuzhiyun 		reg,
239*4882a593Smuzhiyun 		reg >> 8,
240*4882a593Smuzhiyun 		val,
241*4882a593Smuzhiyun 		val >> 8,
242*4882a593Smuzhiyun 		val >> 16,
243*4882a593Smuzhiyun 		val >> 24,
244*4882a593Smuzhiyun 	};
245*4882a593Smuzhiyun 
246*4882a593Smuzhiyun 	mipi_dsi_generic_write(ts->dsi, msg, sizeof(msg));
247*4882a593Smuzhiyun 
248*4882a593Smuzhiyun 	return 0;
249*4882a593Smuzhiyun }
250*4882a593Smuzhiyun 
rpi_touchscreen_disable(struct drm_panel * panel)251*4882a593Smuzhiyun static int rpi_touchscreen_disable(struct drm_panel *panel)
252*4882a593Smuzhiyun {
253*4882a593Smuzhiyun 	struct rpi_touchscreen *ts = panel_to_ts(panel);
254*4882a593Smuzhiyun 
255*4882a593Smuzhiyun 	rpi_touchscreen_i2c_write(ts, REG_PWM, 0);
256*4882a593Smuzhiyun 
257*4882a593Smuzhiyun 	rpi_touchscreen_i2c_write(ts, REG_POWERON, 0);
258*4882a593Smuzhiyun 	udelay(1);
259*4882a593Smuzhiyun 
260*4882a593Smuzhiyun 	return 0;
261*4882a593Smuzhiyun }
262*4882a593Smuzhiyun 
rpi_touchscreen_noop(struct drm_panel * panel)263*4882a593Smuzhiyun static int rpi_touchscreen_noop(struct drm_panel *panel)
264*4882a593Smuzhiyun {
265*4882a593Smuzhiyun 	return 0;
266*4882a593Smuzhiyun }
267*4882a593Smuzhiyun 
rpi_touchscreen_prepare(struct drm_panel * panel)268*4882a593Smuzhiyun static int rpi_touchscreen_prepare(struct drm_panel *panel)
269*4882a593Smuzhiyun {
270*4882a593Smuzhiyun 	struct rpi_touchscreen *ts = panel_to_ts(panel);
271*4882a593Smuzhiyun 	int i;
272*4882a593Smuzhiyun 
273*4882a593Smuzhiyun 	rpi_touchscreen_i2c_write(ts, REG_POWERON, 1);
274*4882a593Smuzhiyun 	/* Wait for nPWRDWN to go low to indicate poweron is done. */
275*4882a593Smuzhiyun 	for (i = 0; i < 100; i++) {
276*4882a593Smuzhiyun 		if (rpi_touchscreen_i2c_read(ts, REG_PORTB) & 1)
277*4882a593Smuzhiyun 			break;
278*4882a593Smuzhiyun 	}
279*4882a593Smuzhiyun 
280*4882a593Smuzhiyun 	rpi_touchscreen_write(ts, DSI_LANEENABLE,
281*4882a593Smuzhiyun 			      DSI_LANEENABLE_CLOCK |
282*4882a593Smuzhiyun 			      DSI_LANEENABLE_D0);
283*4882a593Smuzhiyun 	rpi_touchscreen_write(ts, PPI_D0S_CLRSIPOCOUNT, 0x05);
284*4882a593Smuzhiyun 	rpi_touchscreen_write(ts, PPI_D1S_CLRSIPOCOUNT, 0x05);
285*4882a593Smuzhiyun 	rpi_touchscreen_write(ts, PPI_D0S_ATMR, 0x00);
286*4882a593Smuzhiyun 	rpi_touchscreen_write(ts, PPI_D1S_ATMR, 0x00);
287*4882a593Smuzhiyun 	rpi_touchscreen_write(ts, PPI_LPTXTIMECNT, 0x03);
288*4882a593Smuzhiyun 
289*4882a593Smuzhiyun 	rpi_touchscreen_write(ts, SPICMR, 0x00);
290*4882a593Smuzhiyun 	rpi_touchscreen_write(ts, LCDCTRL, 0x00100150);
291*4882a593Smuzhiyun 	rpi_touchscreen_write(ts, SYSCTRL, 0x040f);
292*4882a593Smuzhiyun 	msleep(100);
293*4882a593Smuzhiyun 
294*4882a593Smuzhiyun 	rpi_touchscreen_write(ts, PPI_STARTPPI, 0x01);
295*4882a593Smuzhiyun 	rpi_touchscreen_write(ts, DSI_STARTDSI, 0x01);
296*4882a593Smuzhiyun 	msleep(100);
297*4882a593Smuzhiyun 
298*4882a593Smuzhiyun 	return 0;
299*4882a593Smuzhiyun }
300*4882a593Smuzhiyun 
rpi_touchscreen_enable(struct drm_panel * panel)301*4882a593Smuzhiyun static int rpi_touchscreen_enable(struct drm_panel *panel)
302*4882a593Smuzhiyun {
303*4882a593Smuzhiyun 	struct rpi_touchscreen *ts = panel_to_ts(panel);
304*4882a593Smuzhiyun 
305*4882a593Smuzhiyun 	/* Turn on the backlight. */
306*4882a593Smuzhiyun 	rpi_touchscreen_i2c_write(ts, REG_PWM, 255);
307*4882a593Smuzhiyun 
308*4882a593Smuzhiyun 	/* Default to the same orientation as the closed source
309*4882a593Smuzhiyun 	 * firmware used for the panel.  Runtime rotation
310*4882a593Smuzhiyun 	 * configuration will be supported using VC4's plane
311*4882a593Smuzhiyun 	 * orientation bits.
312*4882a593Smuzhiyun 	 */
313*4882a593Smuzhiyun 	rpi_touchscreen_i2c_write(ts, REG_PORTA, BIT(2));
314*4882a593Smuzhiyun 
315*4882a593Smuzhiyun 	return 0;
316*4882a593Smuzhiyun }
317*4882a593Smuzhiyun 
rpi_touchscreen_get_modes(struct drm_panel * panel,struct drm_connector * connector)318*4882a593Smuzhiyun static int rpi_touchscreen_get_modes(struct drm_panel *panel,
319*4882a593Smuzhiyun 				     struct drm_connector *connector)
320*4882a593Smuzhiyun {
321*4882a593Smuzhiyun 	unsigned int i, num = 0;
322*4882a593Smuzhiyun 	static const u32 bus_format = MEDIA_BUS_FMT_RGB888_1X24;
323*4882a593Smuzhiyun 
324*4882a593Smuzhiyun 	for (i = 0; i < ARRAY_SIZE(rpi_touchscreen_modes); i++) {
325*4882a593Smuzhiyun 		const struct drm_display_mode *m = &rpi_touchscreen_modes[i];
326*4882a593Smuzhiyun 		struct drm_display_mode *mode;
327*4882a593Smuzhiyun 
328*4882a593Smuzhiyun 		mode = drm_mode_duplicate(connector->dev, m);
329*4882a593Smuzhiyun 		if (!mode) {
330*4882a593Smuzhiyun 			dev_err(panel->dev, "failed to add mode %ux%u@%u\n",
331*4882a593Smuzhiyun 				m->hdisplay, m->vdisplay,
332*4882a593Smuzhiyun 				drm_mode_vrefresh(m));
333*4882a593Smuzhiyun 			continue;
334*4882a593Smuzhiyun 		}
335*4882a593Smuzhiyun 
336*4882a593Smuzhiyun 		mode->type |= DRM_MODE_TYPE_DRIVER;
337*4882a593Smuzhiyun 
338*4882a593Smuzhiyun 		if (i == 0)
339*4882a593Smuzhiyun 			mode->type |= DRM_MODE_TYPE_PREFERRED;
340*4882a593Smuzhiyun 
341*4882a593Smuzhiyun 		drm_mode_set_name(mode);
342*4882a593Smuzhiyun 
343*4882a593Smuzhiyun 		drm_mode_probed_add(connector, mode);
344*4882a593Smuzhiyun 		num++;
345*4882a593Smuzhiyun 	}
346*4882a593Smuzhiyun 
347*4882a593Smuzhiyun 	connector->display_info.bpc = 8;
348*4882a593Smuzhiyun 	connector->display_info.width_mm = 154;
349*4882a593Smuzhiyun 	connector->display_info.height_mm = 86;
350*4882a593Smuzhiyun 	drm_display_info_set_bus_formats(&connector->display_info,
351*4882a593Smuzhiyun 					 &bus_format, 1);
352*4882a593Smuzhiyun 
353*4882a593Smuzhiyun 	return num;
354*4882a593Smuzhiyun }
355*4882a593Smuzhiyun 
356*4882a593Smuzhiyun static const struct drm_panel_funcs rpi_touchscreen_funcs = {
357*4882a593Smuzhiyun 	.disable = rpi_touchscreen_disable,
358*4882a593Smuzhiyun 	.unprepare = rpi_touchscreen_noop,
359*4882a593Smuzhiyun 	.prepare = rpi_touchscreen_prepare,
360*4882a593Smuzhiyun 	.enable = rpi_touchscreen_enable,
361*4882a593Smuzhiyun 	.get_modes = rpi_touchscreen_get_modes,
362*4882a593Smuzhiyun };
363*4882a593Smuzhiyun 
rpi_touchscreen_probe(struct i2c_client * i2c,const struct i2c_device_id * id)364*4882a593Smuzhiyun static int rpi_touchscreen_probe(struct i2c_client *i2c,
365*4882a593Smuzhiyun 				 const struct i2c_device_id *id)
366*4882a593Smuzhiyun {
367*4882a593Smuzhiyun 	struct device *dev = &i2c->dev;
368*4882a593Smuzhiyun 	struct rpi_touchscreen *ts;
369*4882a593Smuzhiyun 	struct device_node *endpoint, *dsi_host_node;
370*4882a593Smuzhiyun 	struct mipi_dsi_host *host;
371*4882a593Smuzhiyun 	int ver;
372*4882a593Smuzhiyun 	struct mipi_dsi_device_info info = {
373*4882a593Smuzhiyun 		.type = RPI_DSI_DRIVER_NAME,
374*4882a593Smuzhiyun 		.channel = 0,
375*4882a593Smuzhiyun 		.node = NULL,
376*4882a593Smuzhiyun 	};
377*4882a593Smuzhiyun 
378*4882a593Smuzhiyun 	ts = devm_kzalloc(dev, sizeof(*ts), GFP_KERNEL);
379*4882a593Smuzhiyun 	if (!ts)
380*4882a593Smuzhiyun 		return -ENOMEM;
381*4882a593Smuzhiyun 
382*4882a593Smuzhiyun 	i2c_set_clientdata(i2c, ts);
383*4882a593Smuzhiyun 
384*4882a593Smuzhiyun 	ts->i2c = i2c;
385*4882a593Smuzhiyun 
386*4882a593Smuzhiyun 	ver = rpi_touchscreen_i2c_read(ts, REG_ID);
387*4882a593Smuzhiyun 	if (ver < 0) {
388*4882a593Smuzhiyun 		dev_err(dev, "Atmel I2C read failed: %d\n", ver);
389*4882a593Smuzhiyun 		return -ENODEV;
390*4882a593Smuzhiyun 	}
391*4882a593Smuzhiyun 
392*4882a593Smuzhiyun 	switch (ver) {
393*4882a593Smuzhiyun 	case 0xde: /* ver 1 */
394*4882a593Smuzhiyun 	case 0xc3: /* ver 2 */
395*4882a593Smuzhiyun 		break;
396*4882a593Smuzhiyun 	default:
397*4882a593Smuzhiyun 		dev_err(dev, "Unknown Atmel firmware revision: 0x%02x\n", ver);
398*4882a593Smuzhiyun 		return -ENODEV;
399*4882a593Smuzhiyun 	}
400*4882a593Smuzhiyun 
401*4882a593Smuzhiyun 	/* Turn off at boot, so we can cleanly sequence powering on. */
402*4882a593Smuzhiyun 	rpi_touchscreen_i2c_write(ts, REG_POWERON, 0);
403*4882a593Smuzhiyun 
404*4882a593Smuzhiyun 	/* Look up the DSI host.  It needs to probe before we do. */
405*4882a593Smuzhiyun 	endpoint = of_graph_get_next_endpoint(dev->of_node, NULL);
406*4882a593Smuzhiyun 	if (!endpoint)
407*4882a593Smuzhiyun 		return -ENODEV;
408*4882a593Smuzhiyun 
409*4882a593Smuzhiyun 	dsi_host_node = of_graph_get_remote_port_parent(endpoint);
410*4882a593Smuzhiyun 	if (!dsi_host_node)
411*4882a593Smuzhiyun 		goto error;
412*4882a593Smuzhiyun 
413*4882a593Smuzhiyun 	host = of_find_mipi_dsi_host_by_node(dsi_host_node);
414*4882a593Smuzhiyun 	of_node_put(dsi_host_node);
415*4882a593Smuzhiyun 	if (!host) {
416*4882a593Smuzhiyun 		of_node_put(endpoint);
417*4882a593Smuzhiyun 		return -EPROBE_DEFER;
418*4882a593Smuzhiyun 	}
419*4882a593Smuzhiyun 
420*4882a593Smuzhiyun 	info.node = of_graph_get_remote_port(endpoint);
421*4882a593Smuzhiyun 	if (!info.node)
422*4882a593Smuzhiyun 		goto error;
423*4882a593Smuzhiyun 
424*4882a593Smuzhiyun 	of_node_put(endpoint);
425*4882a593Smuzhiyun 
426*4882a593Smuzhiyun 	ts->dsi = mipi_dsi_device_register_full(host, &info);
427*4882a593Smuzhiyun 	if (IS_ERR(ts->dsi)) {
428*4882a593Smuzhiyun 		dev_err(dev, "DSI device registration failed: %ld\n",
429*4882a593Smuzhiyun 			PTR_ERR(ts->dsi));
430*4882a593Smuzhiyun 		return PTR_ERR(ts->dsi);
431*4882a593Smuzhiyun 	}
432*4882a593Smuzhiyun 
433*4882a593Smuzhiyun 	drm_panel_init(&ts->base, dev, &rpi_touchscreen_funcs,
434*4882a593Smuzhiyun 		       DRM_MODE_CONNECTOR_DSI);
435*4882a593Smuzhiyun 
436*4882a593Smuzhiyun 	/* This appears last, as it's what will unblock the DSI host
437*4882a593Smuzhiyun 	 * driver's component bind function.
438*4882a593Smuzhiyun 	 */
439*4882a593Smuzhiyun 	drm_panel_add(&ts->base);
440*4882a593Smuzhiyun 
441*4882a593Smuzhiyun 	return 0;
442*4882a593Smuzhiyun 
443*4882a593Smuzhiyun error:
444*4882a593Smuzhiyun 	of_node_put(endpoint);
445*4882a593Smuzhiyun 	return -ENODEV;
446*4882a593Smuzhiyun }
447*4882a593Smuzhiyun 
rpi_touchscreen_remove(struct i2c_client * i2c)448*4882a593Smuzhiyun static int rpi_touchscreen_remove(struct i2c_client *i2c)
449*4882a593Smuzhiyun {
450*4882a593Smuzhiyun 	struct rpi_touchscreen *ts = i2c_get_clientdata(i2c);
451*4882a593Smuzhiyun 
452*4882a593Smuzhiyun 	mipi_dsi_detach(ts->dsi);
453*4882a593Smuzhiyun 
454*4882a593Smuzhiyun 	drm_panel_remove(&ts->base);
455*4882a593Smuzhiyun 
456*4882a593Smuzhiyun 	mipi_dsi_device_unregister(ts->dsi);
457*4882a593Smuzhiyun 
458*4882a593Smuzhiyun 	return 0;
459*4882a593Smuzhiyun }
460*4882a593Smuzhiyun 
rpi_touchscreen_dsi_probe(struct mipi_dsi_device * dsi)461*4882a593Smuzhiyun static int rpi_touchscreen_dsi_probe(struct mipi_dsi_device *dsi)
462*4882a593Smuzhiyun {
463*4882a593Smuzhiyun 	int ret;
464*4882a593Smuzhiyun 
465*4882a593Smuzhiyun 	dsi->mode_flags = (MIPI_DSI_MODE_VIDEO |
466*4882a593Smuzhiyun 			   MIPI_DSI_MODE_VIDEO_SYNC_PULSE |
467*4882a593Smuzhiyun 			   MIPI_DSI_MODE_LPM);
468*4882a593Smuzhiyun 	dsi->format = MIPI_DSI_FMT_RGB888;
469*4882a593Smuzhiyun 	dsi->lanes = 1;
470*4882a593Smuzhiyun 
471*4882a593Smuzhiyun 	ret = mipi_dsi_attach(dsi);
472*4882a593Smuzhiyun 
473*4882a593Smuzhiyun 	if (ret)
474*4882a593Smuzhiyun 		dev_err(&dsi->dev, "failed to attach dsi to host: %d\n", ret);
475*4882a593Smuzhiyun 
476*4882a593Smuzhiyun 	return ret;
477*4882a593Smuzhiyun }
478*4882a593Smuzhiyun 
479*4882a593Smuzhiyun static struct mipi_dsi_driver rpi_touchscreen_dsi_driver = {
480*4882a593Smuzhiyun 	.driver.name = RPI_DSI_DRIVER_NAME,
481*4882a593Smuzhiyun 	.probe = rpi_touchscreen_dsi_probe,
482*4882a593Smuzhiyun };
483*4882a593Smuzhiyun 
484*4882a593Smuzhiyun static const struct of_device_id rpi_touchscreen_of_ids[] = {
485*4882a593Smuzhiyun 	{ .compatible = "raspberrypi,7inch-touchscreen-panel" },
486*4882a593Smuzhiyun 	{ } /* sentinel */
487*4882a593Smuzhiyun };
488*4882a593Smuzhiyun MODULE_DEVICE_TABLE(of, rpi_touchscreen_of_ids);
489*4882a593Smuzhiyun 
490*4882a593Smuzhiyun static struct i2c_driver rpi_touchscreen_driver = {
491*4882a593Smuzhiyun 	.driver = {
492*4882a593Smuzhiyun 		.name = "rpi_touchscreen",
493*4882a593Smuzhiyun 		.of_match_table = rpi_touchscreen_of_ids,
494*4882a593Smuzhiyun 	},
495*4882a593Smuzhiyun 	.probe = rpi_touchscreen_probe,
496*4882a593Smuzhiyun 	.remove = rpi_touchscreen_remove,
497*4882a593Smuzhiyun };
498*4882a593Smuzhiyun 
rpi_touchscreen_init(void)499*4882a593Smuzhiyun static int __init rpi_touchscreen_init(void)
500*4882a593Smuzhiyun {
501*4882a593Smuzhiyun 	mipi_dsi_driver_register(&rpi_touchscreen_dsi_driver);
502*4882a593Smuzhiyun 	return i2c_add_driver(&rpi_touchscreen_driver);
503*4882a593Smuzhiyun }
504*4882a593Smuzhiyun module_init(rpi_touchscreen_init);
505*4882a593Smuzhiyun 
rpi_touchscreen_exit(void)506*4882a593Smuzhiyun static void __exit rpi_touchscreen_exit(void)
507*4882a593Smuzhiyun {
508*4882a593Smuzhiyun 	i2c_del_driver(&rpi_touchscreen_driver);
509*4882a593Smuzhiyun 	mipi_dsi_driver_unregister(&rpi_touchscreen_dsi_driver);
510*4882a593Smuzhiyun }
511*4882a593Smuzhiyun module_exit(rpi_touchscreen_exit);
512*4882a593Smuzhiyun 
513*4882a593Smuzhiyun MODULE_AUTHOR("Eric Anholt <eric@anholt.net>");
514*4882a593Smuzhiyun MODULE_DESCRIPTION("Raspberry Pi 7-inch touchscreen driver");
515*4882a593Smuzhiyun MODULE_LICENSE("GPL v2");
516