Linux Audio

Check our new training course

Loading...
Note: File does not exist in v3.1.
  1// SPDX-License-Identifier: GPL-2.0
  2/*
  3 * Driver for panels based on Sitronix ST7703 controller, souch as:
  4 *
  5 * - Rocktech jh057n00900 5.5" MIPI-DSI panel
  6 *
  7 * Copyright (C) Purism SPC 2019
  8 */
  9
 10#include <linux/debugfs.h>
 11#include <linux/delay.h>
 12#include <linux/gpio/consumer.h>
 13#include <linux/media-bus-format.h>
 14#include <linux/mod_devicetable.h>
 15#include <linux/module.h>
 16#include <linux/of_device.h>
 17#include <linux/regulator/consumer.h>
 18
 19#include <video/display_timing.h>
 20#include <video/mipi_display.h>
 21
 22#include <drm/drm_mipi_dsi.h>
 23#include <drm/drm_modes.h>
 24#include <drm/drm_panel.h>
 25
 26#define DRV_NAME "panel-sitronix-st7703"
 27
 28/* Manufacturer specific Commands send via DSI */
 29#define ST7703_CMD_ALL_PIXEL_OFF 0x22
 30#define ST7703_CMD_ALL_PIXEL_ON	 0x23
 31#define ST7703_CMD_SETDISP	 0xB2
 32#define ST7703_CMD_SETRGBIF	 0xB3
 33#define ST7703_CMD_SETCYC	 0xB4
 34#define ST7703_CMD_SETBGP	 0xB5
 35#define ST7703_CMD_SETVCOM	 0xB6
 36#define ST7703_CMD_SETOTP	 0xB7
 37#define ST7703_CMD_SETPOWER_EXT	 0xB8
 38#define ST7703_CMD_SETEXTC	 0xB9
 39#define ST7703_CMD_SETMIPI	 0xBA
 40#define ST7703_CMD_SETVDC	 0xBC
 41#define ST7703_CMD_UNKNOWN_BF	 0xBF
 42#define ST7703_CMD_SETSCR	 0xC0
 43#define ST7703_CMD_SETPOWER	 0xC1
 44#define ST7703_CMD_SETPANEL	 0xCC
 45#define ST7703_CMD_UNKNOWN_C6	 0xC6
 46#define ST7703_CMD_SETGAMMA	 0xE0
 47#define ST7703_CMD_SETEQ	 0xE3
 48#define ST7703_CMD_SETGIP1	 0xE9
 49#define ST7703_CMD_SETGIP2	 0xEA
 50
 51struct st7703 {
 52	struct device *dev;
 53	struct drm_panel panel;
 54	struct gpio_desc *reset_gpio;
 55	struct regulator *vcc;
 56	struct regulator *iovcc;
 57	bool prepared;
 58
 59	struct dentry *debugfs;
 60	const struct st7703_panel_desc *desc;
 61};
 62
 63struct st7703_panel_desc {
 64	const struct drm_display_mode *mode;
 65	unsigned int lanes;
 66	unsigned long mode_flags;
 67	enum mipi_dsi_pixel_format format;
 68	int (*init_sequence)(struct st7703 *ctx);
 69};
 70
 71static inline struct st7703 *panel_to_st7703(struct drm_panel *panel)
 72{
 73	return container_of(panel, struct st7703, panel);
 74}
 75
 76#define dsi_generic_write_seq(dsi, seq...) do {				\
 77		static const u8 d[] = { seq };				\
 78		int ret;						\
 79		ret = mipi_dsi_generic_write(dsi, d, ARRAY_SIZE(d));	\
 80		if (ret < 0)						\
 81			return ret;					\
 82	} while (0)
 83
 84static int jh057n_init_sequence(struct st7703 *ctx)
 85{
 86	struct mipi_dsi_device *dsi = to_mipi_dsi_device(ctx->dev);
 87
 88	/*
 89	 * Init sequence was supplied by the panel vendor. Most of the commands
 90	 * resemble the ST7703 but the number of parameters often don't match
 91	 * so it's likely a clone.
 92	 */
 93	dsi_generic_write_seq(dsi, ST7703_CMD_SETEXTC,
 94			      0xF1, 0x12, 0x83);
 95	dsi_generic_write_seq(dsi, ST7703_CMD_SETRGBIF,
 96			      0x10, 0x10, 0x05, 0x05, 0x03, 0xFF, 0x00, 0x00,
 97			      0x00, 0x00);
 98	dsi_generic_write_seq(dsi, ST7703_CMD_SETSCR,
 99			      0x73, 0x73, 0x50, 0x50, 0x00, 0x00, 0x08, 0x70,
100			      0x00);
101	dsi_generic_write_seq(dsi, ST7703_CMD_SETVDC, 0x4E);
102	dsi_generic_write_seq(dsi, ST7703_CMD_SETPANEL, 0x0B);
103	dsi_generic_write_seq(dsi, ST7703_CMD_SETCYC, 0x80);
104	dsi_generic_write_seq(dsi, ST7703_CMD_SETDISP, 0xF0, 0x12, 0x30);
105	dsi_generic_write_seq(dsi, ST7703_CMD_SETEQ,
106			      0x07, 0x07, 0x0B, 0x0B, 0x03, 0x0B, 0x00, 0x00,
107			      0x00, 0x00, 0xFF, 0x00, 0xC0, 0x10);
108	dsi_generic_write_seq(dsi, ST7703_CMD_SETBGP, 0x08, 0x08);
109	msleep(20);
110
111	dsi_generic_write_seq(dsi, ST7703_CMD_SETVCOM, 0x3F, 0x3F);
112	dsi_generic_write_seq(dsi, ST7703_CMD_UNKNOWN_BF, 0x02, 0x11, 0x00);
113	dsi_generic_write_seq(dsi, ST7703_CMD_SETGIP1,
114			      0x82, 0x10, 0x06, 0x05, 0x9E, 0x0A, 0xA5, 0x12,
115			      0x31, 0x23, 0x37, 0x83, 0x04, 0xBC, 0x27, 0x38,
116			      0x0C, 0x00, 0x03, 0x00, 0x00, 0x00, 0x0C, 0x00,
117			      0x03, 0x00, 0x00, 0x00, 0x75, 0x75, 0x31, 0x88,
118			      0x88, 0x88, 0x88, 0x88, 0x88, 0x13, 0x88, 0x64,
119			      0x64, 0x20, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88,
120			      0x02, 0x88, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
121			      0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00);
122	dsi_generic_write_seq(dsi, ST7703_CMD_SETGIP2,
123			      0x02, 0x21, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
124			      0x00, 0x00, 0x00, 0x00, 0x02, 0x46, 0x02, 0x88,
125			      0x88, 0x88, 0x88, 0x88, 0x88, 0x64, 0x88, 0x13,
126			      0x57, 0x13, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88,
127			      0x75, 0x88, 0x23, 0x14, 0x00, 0x00, 0x02, 0x00,
128			      0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
129			      0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x0A,
130			      0xA5, 0x00, 0x00, 0x00, 0x00);
131	dsi_generic_write_seq(dsi, ST7703_CMD_SETGAMMA,
132			      0x00, 0x09, 0x0E, 0x29, 0x2D, 0x3C, 0x41, 0x37,
133			      0x07, 0x0B, 0x0D, 0x10, 0x11, 0x0F, 0x10, 0x11,
134			      0x18, 0x00, 0x09, 0x0E, 0x29, 0x2D, 0x3C, 0x41,
135			      0x37, 0x07, 0x0B, 0x0D, 0x10, 0x11, 0x0F, 0x10,
136			      0x11, 0x18);
137
138	return 0;
139}
140
141static const struct drm_display_mode jh057n00900_mode = {
142	.hdisplay    = 720,
143	.hsync_start = 720 + 90,
144	.hsync_end   = 720 + 90 + 20,
145	.htotal	     = 720 + 90 + 20 + 20,
146	.vdisplay    = 1440,
147	.vsync_start = 1440 + 20,
148	.vsync_end   = 1440 + 20 + 4,
149	.vtotal	     = 1440 + 20 + 4 + 12,
150	.clock	     = 75276,
151	.flags	     = DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC,
152	.width_mm    = 65,
153	.height_mm   = 130,
154};
155
156static const struct st7703_panel_desc jh057n00900_panel_desc = {
157	.mode = &jh057n00900_mode,
158	.lanes = 4,
159	.mode_flags = MIPI_DSI_MODE_VIDEO |
160		MIPI_DSI_MODE_VIDEO_BURST | MIPI_DSI_MODE_VIDEO_SYNC_PULSE,
161	.format = MIPI_DSI_FMT_RGB888,
162	.init_sequence = jh057n_init_sequence,
163};
164
165#define dsi_dcs_write_seq(dsi, cmd, seq...) do {			\
166		static const u8 d[] = { seq };				\
167		int ret;						\
168		ret = mipi_dsi_dcs_write(dsi, cmd, d, ARRAY_SIZE(d));	\
169		if (ret < 0)						\
170			return ret;					\
171	} while (0)
172
173
174static int xbd599_init_sequence(struct st7703 *ctx)
175{
176	struct mipi_dsi_device *dsi = to_mipi_dsi_device(ctx->dev);
177
178	/*
179	 * Init sequence was supplied by the panel vendor.
180	 */
181
182	/* Magic sequence to unlock user commands below. */
183	dsi_dcs_write_seq(dsi, ST7703_CMD_SETEXTC, 0xF1, 0x12, 0x83);
184
185	dsi_dcs_write_seq(dsi, ST7703_CMD_SETMIPI,
186			  0x33, /* VC_main = 0, Lane_Number = 3 (4 lanes) */
187			  0x81, /* DSI_LDO_SEL = 1.7V, RTERM = 90 Ohm */
188			  0x05, /* IHSRX = x6 (Low High Speed driving ability) */
189			  0xF9, /* TX_CLK_SEL = fDSICLK/16 */
190			  0x0E, /* HFP_OSC (min. HFP number in DSI mode) */
191			  0x0E, /* HBP_OSC (min. HBP number in DSI mode) */
192			  /* The rest is undocumented in ST7703 datasheet */
193			  0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
194			  0x44, 0x25, 0x00, 0x91, 0x0a, 0x00, 0x00, 0x02,
195			  0x4F, 0x11, 0x00, 0x00, 0x37);
196
197	dsi_dcs_write_seq(dsi, ST7703_CMD_SETPOWER_EXT,
198			  0x25, /* PCCS = 2, ECP_DC_DIV = 1/4 HSYNC */
199			  0x22, /* DT = 15ms XDK_ECP = x2 */
200			  0x20, /* PFM_DC_DIV = /1 */
201			  0x03  /* ECP_SYNC_EN = 1, VGX_SYNC_EN = 1 */);
202
203	/* RGB I/F porch timing */
204	dsi_dcs_write_seq(dsi, ST7703_CMD_SETRGBIF,
205			  0x10, /* VBP_RGB_GEN */
206			  0x10, /* VFP_RGB_GEN */
207			  0x05, /* DE_BP_RGB_GEN */
208			  0x05, /* DE_FP_RGB_GEN */
209			  /* The rest is undocumented in ST7703 datasheet */
210			  0x03, 0xFF,
211			  0x00, 0x00,
212			  0x00, 0x00);
213
214	/* Source driving settings. */
215	dsi_dcs_write_seq(dsi, ST7703_CMD_SETSCR,
216			  0x73, /* N_POPON */
217			  0x73, /* N_NOPON */
218			  0x50, /* I_POPON */
219			  0x50, /* I_NOPON */
220			  0x00, /* SCR[31,24] */
221			  0xC0, /* SCR[23,16] */
222			  0x08, /* SCR[15,8] */
223			  0x70, /* SCR[7,0] */
224			  0x00  /* Undocumented */);
225
226	/* NVDDD_SEL = -1.8V, VDDD_SEL = out of range (possibly 1.9V?) */
227	dsi_dcs_write_seq(dsi, ST7703_CMD_SETVDC, 0x4E);
228
229	/*
230	 * SS_PANEL = 1 (reverse scan), GS_PANEL = 0 (normal scan)
231	 * REV_PANEL = 1 (normally black panel), BGR_PANEL = 1 (BGR)
232	 */
233	dsi_dcs_write_seq(dsi, ST7703_CMD_SETPANEL, 0x0B);
234
235	/* Zig-Zag Type C column inversion. */
236	dsi_dcs_write_seq(dsi, ST7703_CMD_SETCYC, 0x80);
237
238	/* Set display resolution. */
239	dsi_dcs_write_seq(dsi, ST7703_CMD_SETDISP,
240			  0xF0, /* NL = 240 */
241			  0x12, /* RES_V_LSB = 0, BLK_CON = VSSD,
242				 * RESO_SEL = 720RGB
243				 */
244			  0xF0  /* WHITE_GND_EN = 1 (GND),
245				 * WHITE_FRAME_SEL = 7 frames,
246				 * ISC = 0 frames
247				 */);
248
249	dsi_dcs_write_seq(dsi, ST7703_CMD_SETEQ,
250			  0x00, /* PNOEQ */
251			  0x00, /* NNOEQ */
252			  0x0B, /* PEQGND */
253			  0x0B, /* NEQGND */
254			  0x10, /* PEQVCI */
255			  0x10, /* NEQVCI */
256			  0x00, /* PEQVCI1 */
257			  0x00, /* NEQVCI1 */
258			  0x00, /* reserved */
259			  0x00, /* reserved */
260			  0xFF, /* reserved */
261			  0x00, /* reserved */
262			  0xC0, /* ESD_DET_DATA_WHITE = 1, ESD_WHITE_EN = 1 */
263			  0x10  /* SLPIN_OPTION = 1 (no need vsync after sleep-in)
264				 * VEDIO_NO_CHECK_EN = 0
265				 * ESD_WHITE_GND_EN = 0
266				 * ESD_DET_TIME_SEL = 0 frames
267				 */);
268
269	/* Undocumented command. */
270	dsi_dcs_write_seq(dsi, ST7703_CMD_UNKNOWN_C6, 0x01, 0x00, 0xFF, 0xFF, 0x00);
271
272	dsi_dcs_write_seq(dsi, ST7703_CMD_SETPOWER,
273			  0x74, /* VBTHS, VBTLS: VGH = 17V, VBL = -11V */
274			  0x00, /* FBOFF_VGH = 0, FBOFF_VGL = 0 */
275			  0x32, /* VRP  */
276			  0x32, /* VRN */
277			  0x77, /* reserved */
278			  0xF1, /* APS = 1 (small),
279				 * VGL_DET_EN = 1, VGH_DET_EN = 1,
280				 * VGL_TURBO = 1, VGH_TURBO = 1
281				 */
282			  0xFF, /* VGH1_L_DIV, VGL1_L_DIV (1.5MHz) */
283			  0xFF, /* VGH1_R_DIV, VGL1_R_DIV (1.5MHz) */
284			  0xCC, /* VGH2_L_DIV, VGL2_L_DIV (2.6MHz) */
285			  0xCC, /* VGH2_R_DIV, VGL2_R_DIV (2.6MHz) */
286			  0x77, /* VGH3_L_DIV, VGL3_L_DIV (4.5MHz) */
287			  0x77  /* VGH3_R_DIV, VGL3_R_DIV (4.5MHz) */);
288
289	/* Reference voltage. */
290	dsi_dcs_write_seq(dsi, ST7703_CMD_SETBGP,
291			  0x07, /* VREF_SEL = 4.2V */
292			  0x07  /* NVREF_SEL = 4.2V */);
293	msleep(20);
294
295	dsi_dcs_write_seq(dsi, ST7703_CMD_SETVCOM,
296			  0x2C, /* VCOMDC_F = -0.67V */
297			  0x2C  /* VCOMDC_B = -0.67V */);
298
299	/* Undocumented command. */
300	dsi_dcs_write_seq(dsi, ST7703_CMD_UNKNOWN_BF, 0x02, 0x11, 0x00);
301
302	/* This command is to set forward GIP timing. */
303	dsi_dcs_write_seq(dsi, ST7703_CMD_SETGIP1,
304			  0x82, 0x10, 0x06, 0x05, 0xA2, 0x0A, 0xA5, 0x12,
305			  0x31, 0x23, 0x37, 0x83, 0x04, 0xBC, 0x27, 0x38,
306			  0x0C, 0x00, 0x03, 0x00, 0x00, 0x00, 0x0C, 0x00,
307			  0x03, 0x00, 0x00, 0x00, 0x75, 0x75, 0x31, 0x88,
308			  0x88, 0x88, 0x88, 0x88, 0x88, 0x13, 0x88, 0x64,
309			  0x64, 0x20, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88,
310			  0x02, 0x88, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
311			  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00);
312
313	/* This command is to set backward GIP timing. */
314	dsi_dcs_write_seq(dsi, ST7703_CMD_SETGIP2,
315			  0x02, 0x21, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
316			  0x00, 0x00, 0x00, 0x00, 0x02, 0x46, 0x02, 0x88,
317			  0x88, 0x88, 0x88, 0x88, 0x88, 0x64, 0x88, 0x13,
318			  0x57, 0x13, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88,
319			  0x75, 0x88, 0x23, 0x14, 0x00, 0x00, 0x02, 0x00,
320			  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
321			  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x0A,
322			  0xA5, 0x00, 0x00, 0x00, 0x00);
323
324	/* Adjust the gamma characteristics of the panel. */
325	dsi_dcs_write_seq(dsi, ST7703_CMD_SETGAMMA,
326			  0x00, 0x09, 0x0D, 0x23, 0x27, 0x3C, 0x41, 0x35,
327			  0x07, 0x0D, 0x0E, 0x12, 0x13, 0x10, 0x12, 0x12,
328			  0x18, 0x00, 0x09, 0x0D, 0x23, 0x27, 0x3C, 0x41,
329			  0x35, 0x07, 0x0D, 0x0E, 0x12, 0x13, 0x10, 0x12,
330			  0x12, 0x18);
331
332	return 0;
333}
334
335static const struct drm_display_mode xbd599_mode = {
336	.hdisplay    = 720,
337	.hsync_start = 720 + 40,
338	.hsync_end   = 720 + 40 + 40,
339	.htotal	     = 720 + 40 + 40 + 40,
340	.vdisplay    = 1440,
341	.vsync_start = 1440 + 18,
342	.vsync_end   = 1440 + 18 + 10,
343	.vtotal	     = 1440 + 18 + 10 + 17,
344	.clock	     = 69000,
345	.flags	     = DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC,
346	.width_mm    = 68,
347	.height_mm   = 136,
348};
349
350static const struct st7703_panel_desc xbd599_desc = {
351	.mode = &xbd599_mode,
352	.lanes = 4,
353	.mode_flags = MIPI_DSI_MODE_VIDEO | MIPI_DSI_MODE_VIDEO_SYNC_PULSE,
354	.format = MIPI_DSI_FMT_RGB888,
355	.init_sequence = xbd599_init_sequence,
356};
357
358static int st7703_enable(struct drm_panel *panel)
359{
360	struct st7703 *ctx = panel_to_st7703(panel);
361	struct mipi_dsi_device *dsi = to_mipi_dsi_device(ctx->dev);
362	int ret;
363
364	ret = ctx->desc->init_sequence(ctx);
365	if (ret < 0) {
366		dev_err(ctx->dev, "Panel init sequence failed: %d\n", ret);
367		return ret;
368	}
369
370	msleep(20);
371
372	ret = mipi_dsi_dcs_exit_sleep_mode(dsi);
373	if (ret < 0) {
374		dev_err(ctx->dev, "Failed to exit sleep mode: %d\n", ret);
375		return ret;
376	}
377
378	/* Panel is operational 120 msec after reset */
379	msleep(60);
380
381	ret = mipi_dsi_dcs_set_display_on(dsi);
382	if (ret)
383		return ret;
384
385	dev_dbg(ctx->dev, "Panel init sequence done\n");
386
387	return 0;
388}
389
390static int st7703_disable(struct drm_panel *panel)
391{
392	struct st7703 *ctx = panel_to_st7703(panel);
393	struct mipi_dsi_device *dsi = to_mipi_dsi_device(ctx->dev);
394	int ret;
395
396	ret = mipi_dsi_dcs_set_display_off(dsi);
397	if (ret < 0)
398		dev_err(ctx->dev, "Failed to turn off the display: %d\n", ret);
399
400	ret = mipi_dsi_dcs_enter_sleep_mode(dsi);
401	if (ret < 0)
402		dev_err(ctx->dev, "Failed to enter sleep mode: %d\n", ret);
403
404	return 0;
405}
406
407static int st7703_unprepare(struct drm_panel *panel)
408{
409	struct st7703 *ctx = panel_to_st7703(panel);
410
411	if (!ctx->prepared)
412		return 0;
413
414	gpiod_set_value_cansleep(ctx->reset_gpio, 1);
415	regulator_disable(ctx->iovcc);
416	regulator_disable(ctx->vcc);
417	ctx->prepared = false;
418
419	return 0;
420}
421
422static int st7703_prepare(struct drm_panel *panel)
423{
424	struct st7703 *ctx = panel_to_st7703(panel);
425	int ret;
426
427	if (ctx->prepared)
428		return 0;
429
430	dev_dbg(ctx->dev, "Resetting the panel\n");
431	ret = regulator_enable(ctx->vcc);
432	if (ret < 0) {
433		dev_err(ctx->dev, "Failed to enable vcc supply: %d\n", ret);
434		return ret;
435	}
436	ret = regulator_enable(ctx->iovcc);
437	if (ret < 0) {
438		dev_err(ctx->dev, "Failed to enable iovcc supply: %d\n", ret);
439		goto disable_vcc;
440	}
441
442	gpiod_set_value_cansleep(ctx->reset_gpio, 1);
443	usleep_range(20, 40);
444	gpiod_set_value_cansleep(ctx->reset_gpio, 0);
445	msleep(20);
446
447	ctx->prepared = true;
448
449	return 0;
450
451disable_vcc:
452	regulator_disable(ctx->vcc);
453	return ret;
454}
455
456static int st7703_get_modes(struct drm_panel *panel,
457			    struct drm_connector *connector)
458{
459	struct st7703 *ctx = panel_to_st7703(panel);
460	struct drm_display_mode *mode;
461
462	mode = drm_mode_duplicate(connector->dev, ctx->desc->mode);
463	if (!mode) {
464		dev_err(ctx->dev, "Failed to add mode %ux%u@%u\n",
465			ctx->desc->mode->hdisplay, ctx->desc->mode->vdisplay,
466			drm_mode_vrefresh(ctx->desc->mode));
467		return -ENOMEM;
468	}
469
470	drm_mode_set_name(mode);
471
472	mode->type = DRM_MODE_TYPE_DRIVER | DRM_MODE_TYPE_PREFERRED;
473	connector->display_info.width_mm = mode->width_mm;
474	connector->display_info.height_mm = mode->height_mm;
475	drm_mode_probed_add(connector, mode);
476
477	return 1;
478}
479
480static const struct drm_panel_funcs st7703_drm_funcs = {
481	.disable   = st7703_disable,
482	.unprepare = st7703_unprepare,
483	.prepare   = st7703_prepare,
484	.enable	   = st7703_enable,
485	.get_modes = st7703_get_modes,
486};
487
488static int allpixelson_set(void *data, u64 val)
489{
490	struct st7703 *ctx = data;
491	struct mipi_dsi_device *dsi = to_mipi_dsi_device(ctx->dev);
492
493	dev_dbg(ctx->dev, "Setting all pixels on\n");
494	dsi_generic_write_seq(dsi, ST7703_CMD_ALL_PIXEL_ON);
495	msleep(val * 1000);
496	/* Reset the panel to get video back */
497	drm_panel_disable(&ctx->panel);
498	drm_panel_unprepare(&ctx->panel);
499	drm_panel_prepare(&ctx->panel);
500	drm_panel_enable(&ctx->panel);
501
502	return 0;
503}
504
505DEFINE_SIMPLE_ATTRIBUTE(allpixelson_fops, NULL,
506			allpixelson_set, "%llu\n");
507
508static void st7703_debugfs_init(struct st7703 *ctx)
509{
510	ctx->debugfs = debugfs_create_dir(DRV_NAME, NULL);
511
512	debugfs_create_file("allpixelson", 0600, ctx->debugfs, ctx,
513			    &allpixelson_fops);
514}
515
516static void st7703_debugfs_remove(struct st7703 *ctx)
517{
518	debugfs_remove_recursive(ctx->debugfs);
519	ctx->debugfs = NULL;
520}
521
522static int st7703_probe(struct mipi_dsi_device *dsi)
523{
524	struct device *dev = &dsi->dev;
525	struct st7703 *ctx;
526	int ret;
527
528	ctx = devm_kzalloc(dev, sizeof(*ctx), GFP_KERNEL);
529	if (!ctx)
530		return -ENOMEM;
531
532	ctx->reset_gpio = devm_gpiod_get(dev, "reset", GPIOD_OUT_LOW);
533	if (IS_ERR(ctx->reset_gpio))
534		return dev_err_probe(dev, PTR_ERR(ctx->reset_gpio), "Failed to get reset gpio\n");
535
536	mipi_dsi_set_drvdata(dsi, ctx);
537
538	ctx->dev = dev;
539	ctx->desc = of_device_get_match_data(dev);
540
541	dsi->mode_flags = ctx->desc->mode_flags;
542	dsi->format = ctx->desc->format;
543	dsi->lanes = ctx->desc->lanes;
544
545	ctx->vcc = devm_regulator_get(dev, "vcc");
546	if (IS_ERR(ctx->vcc))
547		return dev_err_probe(dev, PTR_ERR(ctx->vcc), "Failed to request vcc regulator\n");
548
549	ctx->iovcc = devm_regulator_get(dev, "iovcc");
550	if (IS_ERR(ctx->iovcc))
551		return dev_err_probe(dev, PTR_ERR(ctx->iovcc),
552				     "Failed to request iovcc regulator\n");
553
554	drm_panel_init(&ctx->panel, dev, &st7703_drm_funcs,
555		       DRM_MODE_CONNECTOR_DSI);
556
557	ret = drm_panel_of_backlight(&ctx->panel);
558	if (ret)
559		return ret;
560
561	drm_panel_add(&ctx->panel);
562
563	ret = mipi_dsi_attach(dsi);
564	if (ret < 0) {
565		dev_err(dev, "mipi_dsi_attach failed (%d). Is host ready?\n", ret);
566		drm_panel_remove(&ctx->panel);
567		return ret;
568	}
569
570	dev_info(dev, "%ux%u@%u %ubpp dsi %udl - ready\n",
571		 ctx->desc->mode->hdisplay, ctx->desc->mode->vdisplay,
572		 drm_mode_vrefresh(ctx->desc->mode),
573		 mipi_dsi_pixel_format_to_bpp(dsi->format), dsi->lanes);
574
575	st7703_debugfs_init(ctx);
576	return 0;
577}
578
579static void st7703_shutdown(struct mipi_dsi_device *dsi)
580{
581	struct st7703 *ctx = mipi_dsi_get_drvdata(dsi);
582	int ret;
583
584	ret = drm_panel_unprepare(&ctx->panel);
585	if (ret < 0)
586		dev_err(&dsi->dev, "Failed to unprepare panel: %d\n", ret);
587
588	ret = drm_panel_disable(&ctx->panel);
589	if (ret < 0)
590		dev_err(&dsi->dev, "Failed to disable panel: %d\n", ret);
591}
592
593static int st7703_remove(struct mipi_dsi_device *dsi)
594{
595	struct st7703 *ctx = mipi_dsi_get_drvdata(dsi);
596	int ret;
597
598	st7703_shutdown(dsi);
599
600	ret = mipi_dsi_detach(dsi);
601	if (ret < 0)
602		dev_err(&dsi->dev, "Failed to detach from DSI host: %d\n", ret);
603
604	drm_panel_remove(&ctx->panel);
605
606	st7703_debugfs_remove(ctx);
607
608	return 0;
609}
610
611static const struct of_device_id st7703_of_match[] = {
612	{ .compatible = "rocktech,jh057n00900", .data = &jh057n00900_panel_desc },
613	{ .compatible = "xingbangda,xbd599", .data = &xbd599_desc },
614	{ /* sentinel */ }
615};
616MODULE_DEVICE_TABLE(of, st7703_of_match);
617
618static struct mipi_dsi_driver st7703_driver = {
619	.probe	= st7703_probe,
620	.remove = st7703_remove,
621	.shutdown = st7703_shutdown,
622	.driver = {
623		.name = DRV_NAME,
624		.of_match_table = st7703_of_match,
625	},
626};
627module_mipi_dsi_driver(st7703_driver);
628
629MODULE_AUTHOR("Guido Günther <agx@sigxcpu.org>");
630MODULE_DESCRIPTION("DRM driver for Sitronix ST7703 based MIPI DSI panels");
631MODULE_LICENSE("GPL v2");