Linux Audio

Check our new training course

Loading...
v6.2
  1// SPDX-License-Identifier: GPL-2.0-only
  2/*
  3 * Ilitek ILI9322 TFT LCD drm_panel driver.
  4 *
  5 * This panel can be configured to support:
  6 * - 8-bit serial RGB interface
  7 * - 24-bit parallel RGB interface
  8 * - 8-bit ITU-R BT.601 interface
  9 * - 8-bit ITU-R BT.656 interface
 10 * - Up to 320RGBx240 dots resolution TFT LCD displays
 11 * - Scaling, brightness and contrast
 12 *
 13 * The scaling means that the display accepts a 640x480 or 720x480
 14 * input and rescales it to fit to the 320x240 display. So what we
 15 * present to the system is something else than what comes out on the
 16 * actual display.
 17 *
 18 * Copyright (C) 2017 Linus Walleij <linus.walleij@linaro.org>
 19 * Derived from drivers/drm/gpu/panel/panel-samsung-ld9040.c
 20 */
 21
 22#include <linux/bitops.h>
 23#include <linux/gpio/consumer.h>
 24#include <linux/module.h>
 25#include <linux/of_device.h>
 26#include <linux/regmap.h>
 27#include <linux/regulator/consumer.h>
 28#include <linux/spi/spi.h>
 29
 30#include <video/mipi_display.h>
 31#include <video/of_videomode.h>
 32#include <video/videomode.h>
 33
 34#include <drm/drm_modes.h>
 35#include <drm/drm_panel.h>
 
 36
 37#define ILI9322_CHIP_ID			0x00
 38#define ILI9322_CHIP_ID_MAGIC		0x96
 39
 40/*
 41 * Voltage on the communication interface, from 0.7 (0x00)
 42 * to 1.32 (0x1f) times the VREG1OUT voltage in 2% increments.
 43 * 1.00 (0x0f) is the default.
 44 */
 45#define ILI9322_VCOM_AMP		0x01
 46
 47/*
 48 * High voltage on the communication signals, from 0.37 (0x00) to
 49 * 1.0 (0x3f) times the VREGOUT1 voltage in 1% increments.
 50 * 0.83 (0x2e) is the default.
 51 */
 52#define ILI9322_VCOM_HIGH		0x02
 53
 54/*
 55 * VREG1 voltage regulator from 3.6V (0x00) to 6.0V (0x18) in 0.1V
 56 * increments. 5.4V (0x12) is the default. This is the reference
 57 * voltage for the VCOM levels and the greyscale level.
 58 */
 59#define ILI9322_VREG1_VOLTAGE		0x03
 60
 61/* Describes the incoming signal */
 62#define ILI9322_ENTRY			0x06
 63/* 0 = right-to-left, 1 = left-to-right (default), horizontal flip */
 64#define ILI9322_ENTRY_HDIR		BIT(0)
 65/* 0 = down-to-up, 1 = up-to-down (default), vertical flip  */
 66#define ILI9322_ENTRY_VDIR		BIT(1)
 67/* NTSC, PAL or autodetect */
 68#define ILI9322_ENTRY_NTSC		(0 << 2)
 69#define ILI9322_ENTRY_PAL		(1 << 2)
 70#define ILI9322_ENTRY_AUTODETECT	(3 << 2)
 71/* Input format */
 72#define ILI9322_ENTRY_SERIAL_RGB_THROUGH (0 << 4)
 73#define ILI9322_ENTRY_SERIAL_RGB_ALIGNED (1 << 4)
 74#define ILI9322_ENTRY_SERIAL_RGB_DUMMY_320X240 (2 << 4)
 75#define ILI9322_ENTRY_SERIAL_RGB_DUMMY_360X240 (3 << 4)
 76#define ILI9322_ENTRY_DISABLE_1		(4 << 4)
 77#define ILI9322_ENTRY_PARALLEL_RGB_THROUGH (5 << 4)
 78#define ILI9322_ENTRY_PARALLEL_RGB_ALIGNED (6 << 4)
 79#define ILI9322_ENTRY_YUV_640Y_320CBCR_25_54_MHZ (7 << 4)
 80#define ILI9322_ENTRY_YUV_720Y_360CBCR_27_MHZ (8 << 4)
 81#define ILI9322_ENTRY_DISABLE_2		(9 << 4)
 82#define ILI9322_ENTRY_ITU_R_BT_656_720X360 (10 << 4)
 83#define ILI9322_ENTRY_ITU_R_BT_656_640X320 (11 << 4)
 84
 85/* Power control */
 86#define ILI9322_POW_CTRL		0x07
 87#define ILI9322_POW_CTRL_STB		BIT(0) /* 0 = standby, 1 = normal */
 88#define ILI9322_POW_CTRL_VGL		BIT(1) /* 0 = off, 1 = on  */
 89#define ILI9322_POW_CTRL_VGH		BIT(2) /* 0 = off, 1 = on  */
 90#define ILI9322_POW_CTRL_DDVDH		BIT(3) /* 0 = off, 1 = on  */
 91#define ILI9322_POW_CTRL_VCOM		BIT(4) /* 0 = off, 1 = on  */
 92#define ILI9322_POW_CTRL_VCL		BIT(5) /* 0 = off, 1 = on  */
 93#define ILI9322_POW_CTRL_AUTO		BIT(6) /* 0 = interactive, 1 = auto */
 94#define ILI9322_POW_CTRL_STANDBY	(ILI9322_POW_CTRL_VGL | \
 95					 ILI9322_POW_CTRL_VGH | \
 96					 ILI9322_POW_CTRL_DDVDH | \
 97					 ILI9322_POW_CTRL_VCL | \
 98					 ILI9322_POW_CTRL_AUTO | \
 99					 BIT(7))
100#define ILI9322_POW_CTRL_DEFAULT	(ILI9322_POW_CTRL_STANDBY | \
101					 ILI9322_POW_CTRL_STB)
102
103/* Vertical back porch bits 0..5 */
104#define ILI9322_VBP			0x08
105
106/* Horizontal back porch, 8 bits */
107#define ILI9322_HBP			0x09
108
109/*
110 * Polarity settings:
111 * 1 = positive polarity
112 * 0 = negative polarity
113 */
114#define ILI9322_POL			0x0a
115#define ILI9322_POL_DCLK		BIT(0) /* 1 default */
116#define ILI9322_POL_HSYNC		BIT(1) /* 0 default */
117#define ILI9322_POL_VSYNC		BIT(2) /* 0 default */
118#define ILI9322_POL_DE			BIT(3) /* 1 default */
119/*
120 * 0 means YCBCR are ordered Cb0,Y0,Cr0,Y1,Cb2,Y2,Cr2,Y3 (default)
121 *   in RGB mode this means RGB comes in RGBRGB
122 * 1 means YCBCR are ordered Cr0,Y0,Cb0,Y1,Cr2,Y2,Cb2,Y3
123 *   in RGB mode this means RGB comes in BGRBGR
124 */
125#define ILI9322_POL_YCBCR_MODE		BIT(4)
126/* Formula A for YCbCR->RGB = 0, Formula B = 1 */
127#define ILI9322_POL_FORMULA		BIT(5)
128/* Reverse polarity: 0 = 0..255, 1 = 255..0 */
129#define ILI9322_POL_REV			BIT(6)
130
131#define ILI9322_IF_CTRL			0x0b
132#define ILI9322_IF_CTRL_HSYNC_VSYNC	0x00
133#define ILI9322_IF_CTRL_HSYNC_VSYNC_DE	BIT(2)
134#define ILI9322_IF_CTRL_DE_ONLY		BIT(3)
135#define ILI9322_IF_CTRL_SYNC_DISABLED	(BIT(2) | BIT(3))
136#define ILI9322_IF_CTRL_LINE_INVERSION	BIT(0) /* Not set means frame inv */
137
138#define ILI9322_GLOBAL_RESET		0x04
139#define ILI9322_GLOBAL_RESET_ASSERT	0x00 /* bit 0 = 0 -> reset */
140
141/*
142 * 4+4 bits of negative and positive gamma correction
143 * Upper nybble, bits 4-7 are negative gamma
144 * Lower nybble, bits 0-3 are positive gamma
145 */
146#define ILI9322_GAMMA_1			0x10
147#define ILI9322_GAMMA_2			0x11
148#define ILI9322_GAMMA_3			0x12
149#define ILI9322_GAMMA_4			0x13
150#define ILI9322_GAMMA_5			0x14
151#define ILI9322_GAMMA_6			0x15
152#define ILI9322_GAMMA_7			0x16
153#define ILI9322_GAMMA_8			0x17
154
155/*
156 * enum ili9322_input - the format of the incoming signal to the panel
157 *
158 * The panel can be connected to various input streams and four of them can
159 * be selected by electronic straps on the display. However it is possible
160 * to select another mode or override the electronic default with this
161 * setting.
162 */
163enum ili9322_input {
164	ILI9322_INPUT_SRGB_THROUGH = 0x0,
165	ILI9322_INPUT_SRGB_ALIGNED = 0x1,
166	ILI9322_INPUT_SRGB_DUMMY_320X240 = 0x2,
167	ILI9322_INPUT_SRGB_DUMMY_360X240 = 0x3,
168	ILI9322_INPUT_DISABLED_1 = 0x4,
169	ILI9322_INPUT_PRGB_THROUGH = 0x5,
170	ILI9322_INPUT_PRGB_ALIGNED = 0x6,
171	ILI9322_INPUT_YUV_640X320_YCBCR = 0x7,
172	ILI9322_INPUT_YUV_720X360_YCBCR = 0x8,
173	ILI9322_INPUT_DISABLED_2 = 0x9,
174	ILI9322_INPUT_ITU_R_BT656_720X360_YCBCR = 0xa,
175	ILI9322_INPUT_ITU_R_BT656_640X320_YCBCR = 0xb,
176	ILI9322_INPUT_UNKNOWN = 0xc,
177};
178
179static const char * const ili9322_inputs[] = {
180	"8 bit serial RGB through",
181	"8 bit serial RGB aligned",
182	"8 bit serial RGB dummy 320x240",
183	"8 bit serial RGB dummy 360x240",
184	"disabled 1",
185	"24 bit parallel RGB through",
186	"24 bit parallel RGB aligned",
187	"24 bit YUV 640Y 320CbCr",
188	"24 bit YUV 720Y 360CbCr",
189	"disabled 2",
190	"8 bit ITU-R BT.656 720Y 360CbCr",
191	"8 bit ITU-R BT.656 640Y 320CbCr",
192};
193
194/**
195 * struct ili9322_config - the system specific ILI9322 configuration
196 * @width_mm: physical panel width [mm]
197 * @height_mm: physical panel height [mm]
198 * @flip_horizontal: flip the image horizontally (right-to-left scan)
199 * (only in RGB and YUV modes)
200 * @flip_vertical: flip the image vertically (down-to-up scan)
201 * (only in RGB and YUV modes)
202 * @input: the input/entry type used in this system, if this is set to
203 * ILI9322_INPUT_UNKNOWN the driver will try to figure it out by probing
204 * the hardware
205 * @vreg1out_mv: the output in microvolts for the VREGOUT1 regulator used
206 * to drive the physical display. Valid ranges are 3600 thru 6000 in 100
207 * microvolt increments. If not specified, hardware defaults will be
208 * used (4.5V).
209 * @vcom_high_percent: the percentage of VREGOUT1 used for the peak
210 * voltage on the communications link. Valid ranges are 37 thru 100
211 * percent. If not specified, hardware defaults will be used (91%).
212 * @vcom_amplitude_percent: the percentage of VREGOUT1 used for the
213 * peak-to-peak amplitude of the communcation signals to the physical
214 * display. Valid ranges are 70 thru 132 percent in increments if two
215 * percent. Odd percentages will be truncated. If not specified, hardware
216 * defaults will be used (114%).
217 * @dclk_active_high: data/pixel clock active high, data will be clocked
218 * in on the rising edge of the DCLK (this is usually the case).
219 * @syncmode: The synchronization mode, what sync signals are emitted.
220 * See the enum for details.
221 * @de_active_high: DE (data entry) is active high
222 * @hsync_active_high: HSYNC is active high
223 * @vsync_active_high: VSYNC is active high
224 * @gamma_corr_pos: a set of 8 nybbles describing positive
225 * gamma correction for voltages V1 thru V8. Valid range 0..15
226 * @gamma_corr_neg: a set of 8 nybbles describing negative
227 * gamma correction for voltages V1 thru V8. Valid range 0..15
228 *
229 * These adjust what grayscale voltage will be output for input data V1 = 0,
230 * V2 = 16, V3 = 48, V4 = 96, V5 = 160, V6 = 208, V7 = 240 and V8 = 255.
231 * The curve is shaped like this:
232 *
233 *  ^
234 *  |                                                        V8
235 *  |                                                   V7
236 *  |                                          V6
237 *  |                               V5
238 *  |                    V4
239 *  |            V3
240 *  |     V2
241 *  | V1
242 *  +----------------------------------------------------------->
243 *    0   16     48      96         160        208      240  255
244 *
245 * The negative and postive gamma values adjust the V1 thru V8 up/down
246 * according to the datasheet specifications. This is a property of the
247 * physical display connected to the display controller and may vary.
248 * If defined, both arrays must be supplied in full. If the properties
249 * are not supplied, hardware defaults will be used.
250 */
251struct ili9322_config {
252	u32 width_mm;
253	u32 height_mm;
254	bool flip_horizontal;
255	bool flip_vertical;
256	enum ili9322_input input;
257	u32 vreg1out_mv;
258	u32 vcom_high_percent;
259	u32 vcom_amplitude_percent;
260	bool dclk_active_high;
261	bool de_active_high;
262	bool hsync_active_high;
263	bool vsync_active_high;
264	u8 syncmode;
265	u8 gamma_corr_pos[8];
266	u8 gamma_corr_neg[8];
267};
268
269struct ili9322 {
270	struct device *dev;
271	const struct ili9322_config *conf;
272	struct drm_panel panel;
273	struct regmap *regmap;
274	struct regulator_bulk_data supplies[3];
275	struct gpio_desc *reset_gpio;
276	enum ili9322_input input;
277	struct videomode vm;
278	u8 gamma[8];
279	u8 vreg1out;
280	u8 vcom_high;
281	u8 vcom_amplitude;
282};
283
284static inline struct ili9322 *panel_to_ili9322(struct drm_panel *panel)
285{
286	return container_of(panel, struct ili9322, panel);
287}
288
289static int ili9322_regmap_spi_write(void *context, const void *data,
290				    size_t count)
291{
292	struct device *dev = context;
293	struct spi_device *spi = to_spi_device(dev);
294	u8 buf[2];
295
296	/* Clear bit 7 to write */
297	memcpy(buf, data, 2);
298	buf[0] &= ~0x80;
299
300	dev_dbg(dev, "WRITE: %02x %02x\n", buf[0], buf[1]);
301	return spi_write_then_read(spi, buf, 2, NULL, 0);
302}
303
304static int ili9322_regmap_spi_read(void *context, const void *reg,
305				   size_t reg_size, void *val, size_t val_size)
306{
307	struct device *dev = context;
308	struct spi_device *spi = to_spi_device(dev);
309	u8 buf[1];
310
311	/* Set bit 7 to 1 to read */
312	memcpy(buf, reg, 1);
313	dev_dbg(dev, "READ: %02x reg size = %zu, val size = %zu\n",
314		buf[0], reg_size, val_size);
315	buf[0] |= 0x80;
316
317	return spi_write_then_read(spi, buf, 1, val, 1);
318}
319
320static struct regmap_bus ili9322_regmap_bus = {
321	.write = ili9322_regmap_spi_write,
322	.read = ili9322_regmap_spi_read,
323	.reg_format_endian_default = REGMAP_ENDIAN_BIG,
324	.val_format_endian_default = REGMAP_ENDIAN_BIG,
325};
326
327static bool ili9322_volatile_reg(struct device *dev, unsigned int reg)
328{
329	return false;
330}
331
332static bool ili9322_writeable_reg(struct device *dev, unsigned int reg)
333{
334	/* Just register 0 is read-only */
335	if (reg == 0x00)
336		return false;
337	return true;
338}
339
340static const struct regmap_config ili9322_regmap_config = {
341	.reg_bits = 8,
342	.val_bits = 8,
343	.max_register = 0x44,
344	.cache_type = REGCACHE_RBTREE,
345	.volatile_reg = ili9322_volatile_reg,
346	.writeable_reg = ili9322_writeable_reg,
347};
348
349static int ili9322_init(struct drm_panel *panel, struct ili9322 *ili)
350{
351	u8 reg;
352	int ret;
353	int i;
354
355	/* Reset display */
356	ret = regmap_write(ili->regmap, ILI9322_GLOBAL_RESET,
357			   ILI9322_GLOBAL_RESET_ASSERT);
358	if (ret) {
359		dev_err(ili->dev, "can't issue GRESET (%d)\n", ret);
360		return ret;
361	}
362
363	/* Set up the main voltage regulator */
364	if (ili->vreg1out != U8_MAX) {
365		ret = regmap_write(ili->regmap, ILI9322_VREG1_VOLTAGE,
366				   ili->vreg1out);
367		if (ret) {
368			dev_err(ili->dev, "can't set up VREG1OUT (%d)\n", ret);
369			return ret;
370		}
371	}
372
373	if (ili->vcom_amplitude != U8_MAX) {
374		ret = regmap_write(ili->regmap, ILI9322_VCOM_AMP,
375				   ili->vcom_amplitude);
376		if (ret) {
377			dev_err(ili->dev,
378				"can't set up VCOM amplitude (%d)\n", ret);
379			return ret;
380		}
381	}
382
383	if (ili->vcom_high != U8_MAX) {
384		ret = regmap_write(ili->regmap, ILI9322_VCOM_HIGH,
385				   ili->vcom_high);
386		if (ret) {
387			dev_err(ili->dev, "can't set up VCOM high (%d)\n", ret);
388			return ret;
389		}
390	}
391
392	/* Set up gamma correction */
393	for (i = 0; i < ARRAY_SIZE(ili->gamma); i++) {
394		ret = regmap_write(ili->regmap, ILI9322_GAMMA_1 + i,
395				   ili->gamma[i]);
396		if (ret) {
397			dev_err(ili->dev,
398				"can't write gamma V%d to 0x%02x (%d)\n",
399				i + 1, ILI9322_GAMMA_1 + i, ret);
400			return ret;
401		}
402	}
403
404	/*
405	 * Polarity and inverted color order for RGB input.
406	 * None of this applies in the BT.656 mode.
407	 */
408	reg = 0;
409	if (ili->conf->dclk_active_high)
410		reg = ILI9322_POL_DCLK;
411	if (ili->conf->de_active_high)
412		reg |= ILI9322_POL_DE;
413	if (ili->conf->hsync_active_high)
414		reg |= ILI9322_POL_HSYNC;
415	if (ili->conf->vsync_active_high)
416		reg |= ILI9322_POL_VSYNC;
417	ret = regmap_write(ili->regmap, ILI9322_POL, reg);
418	if (ret) {
419		dev_err(ili->dev, "can't write POL register (%d)\n", ret);
420		return ret;
421	}
422
423	/*
424	 * Set up interface control.
425	 * This is not used in the BT.656 mode (no H/Vsync or DE signals).
426	 */
427	reg = ili->conf->syncmode;
428	reg |= ILI9322_IF_CTRL_LINE_INVERSION;
429	ret = regmap_write(ili->regmap, ILI9322_IF_CTRL, reg);
430	if (ret) {
431		dev_err(ili->dev, "can't write IF CTRL register (%d)\n", ret);
432		return ret;
433	}
434
435	/* Set up the input mode */
436	reg = (ili->input << 4);
437	/* These are inverted, setting to 1 is the default, clearing flips */
438	if (!ili->conf->flip_horizontal)
439		reg |= ILI9322_ENTRY_HDIR;
440	if (!ili->conf->flip_vertical)
441		reg |= ILI9322_ENTRY_VDIR;
442	reg |= ILI9322_ENTRY_AUTODETECT;
443	ret = regmap_write(ili->regmap, ILI9322_ENTRY, reg);
444	if (ret) {
445		dev_err(ili->dev, "can't write ENTRY reg (%d)\n", ret);
446		return ret;
447	}
448	dev_info(ili->dev, "display is in %s mode, syncmode %02x\n",
449		 ili9322_inputs[ili->input],
450		 ili->conf->syncmode);
451
452	dev_info(ili->dev, "initialized display\n");
453
454	return 0;
455}
456
457/*
458 * This power-on sequence if from the datasheet, page 57.
459 */
460static int ili9322_power_on(struct ili9322 *ili)
461{
462	int ret;
463
464	/* Assert RESET */
465	gpiod_set_value(ili->reset_gpio, 1);
466
467	ret = regulator_bulk_enable(ARRAY_SIZE(ili->supplies), ili->supplies);
468	if (ret < 0) {
469		dev_err(ili->dev, "unable to enable regulators\n");
470		return ret;
471	}
472	msleep(20);
473
474	/* De-assert RESET */
475	gpiod_set_value(ili->reset_gpio, 0);
476
477	msleep(10);
478
479	return 0;
480}
481
482static int ili9322_power_off(struct ili9322 *ili)
483{
484	return regulator_bulk_disable(ARRAY_SIZE(ili->supplies), ili->supplies);
485}
486
487static int ili9322_disable(struct drm_panel *panel)
488{
489	struct ili9322 *ili = panel_to_ili9322(panel);
490	int ret;
491
492	ret = regmap_write(ili->regmap, ILI9322_POW_CTRL,
493			   ILI9322_POW_CTRL_STANDBY);
494	if (ret) {
495		dev_err(ili->dev, "unable to go to standby mode\n");
496		return ret;
497	}
498
499	return 0;
500}
501
502static int ili9322_unprepare(struct drm_panel *panel)
503{
504	struct ili9322 *ili = panel_to_ili9322(panel);
505
506	return ili9322_power_off(ili);
507}
508
509static int ili9322_prepare(struct drm_panel *panel)
510{
511	struct ili9322 *ili = panel_to_ili9322(panel);
512	int ret;
513
514	ret = ili9322_power_on(ili);
515	if (ret < 0)
516		return ret;
517
518	ret = ili9322_init(panel, ili);
519	if (ret < 0)
520		ili9322_unprepare(panel);
521
522	return ret;
523}
524
525static int ili9322_enable(struct drm_panel *panel)
526{
527	struct ili9322 *ili = panel_to_ili9322(panel);
528	int ret;
529
530	ret = regmap_write(ili->regmap, ILI9322_POW_CTRL,
531			   ILI9322_POW_CTRL_DEFAULT);
532	if (ret) {
533		dev_err(ili->dev, "unable to enable panel\n");
534		return ret;
535	}
536
537	return 0;
538}
539
540/* Serial RGB modes */
541static const struct drm_display_mode srgb_320x240_mode = {
542	.clock = 24535,
543	.hdisplay = 320,
544	.hsync_start = 320 + 359,
545	.hsync_end = 320 + 359 + 1,
546	.htotal = 320 + 359 + 1 + 241,
547	.vdisplay = 240,
548	.vsync_start = 240 + 4,
549	.vsync_end = 240 + 4 + 1,
550	.vtotal = 262,
 
551	.flags = 0,
552};
553
554static const struct drm_display_mode srgb_360x240_mode = {
555	.clock = 27000,
556	.hdisplay = 360,
557	.hsync_start = 360 + 35,
558	.hsync_end = 360 + 35 + 1,
559	.htotal = 360 + 35 + 1 + 241,
560	.vdisplay = 240,
561	.vsync_start = 240 + 21,
562	.vsync_end = 240 + 21 + 1,
563	.vtotal = 262,
 
564	.flags = 0,
565};
566
567/* This is the only mode listed for parallel RGB in the datasheet */
568static const struct drm_display_mode prgb_320x240_mode = {
569	.clock = 64000,
570	.hdisplay = 320,
571	.hsync_start = 320 + 38,
572	.hsync_end = 320 + 38 + 1,
573	.htotal = 320 + 38 + 1 + 50,
574	.vdisplay = 240,
575	.vsync_start = 240 + 4,
576	.vsync_end = 240 + 4 + 1,
577	.vtotal = 262,
 
578	.flags = 0,
579};
580
581/* YUV modes */
582static const struct drm_display_mode yuv_640x320_mode = {
583	.clock = 24540,
584	.hdisplay = 640,
585	.hsync_start = 640 + 252,
586	.hsync_end = 640 + 252 + 1,
587	.htotal = 640 + 252 + 1 + 28,
588	.vdisplay = 320,
589	.vsync_start = 320 + 4,
590	.vsync_end = 320 + 4 + 1,
591	.vtotal = 320 + 4 + 1 + 18,
 
592	.flags = 0,
593};
594
595static const struct drm_display_mode yuv_720x360_mode = {
596	.clock = 27000,
597	.hdisplay = 720,
598	.hsync_start = 720 + 252,
599	.hsync_end = 720 + 252 + 1,
600	.htotal = 720 + 252 + 1 + 24,
601	.vdisplay = 360,
602	.vsync_start = 360 + 4,
603	.vsync_end = 360 + 4 + 1,
604	.vtotal = 360 + 4 + 1 + 18,
 
605	.flags = 0,
606};
607
608/* BT.656 VGA mode, 640x480 */
609static const struct drm_display_mode itu_r_bt_656_640_mode = {
610	.clock = 24540,
611	.hdisplay = 640,
612	.hsync_start = 640 + 3,
613	.hsync_end = 640 + 3 + 1,
614	.htotal = 640 + 3 + 1 + 272,
615	.vdisplay = 480,
616	.vsync_start = 480 + 4,
617	.vsync_end = 480 + 4 + 1,
618	.vtotal = 500,
 
619	.flags = 0,
620};
621
622/* BT.656 D1 mode 720x480 */
623static const struct drm_display_mode itu_r_bt_656_720_mode = {
624	.clock = 27000,
625	.hdisplay = 720,
626	.hsync_start = 720 + 3,
627	.hsync_end = 720 + 3 + 1,
628	.htotal = 720 + 3 + 1 + 272,
629	.vdisplay = 480,
630	.vsync_start = 480 + 4,
631	.vsync_end = 480 + 4 + 1,
632	.vtotal = 500,
 
633	.flags = 0,
634};
635
636static int ili9322_get_modes(struct drm_panel *panel,
637			     struct drm_connector *connector)
638{
 
639	struct ili9322 *ili = panel_to_ili9322(panel);
640	struct drm_device *drm = connector->dev;
641	struct drm_display_mode *mode;
642	struct drm_display_info *info;
643
644	info = &connector->display_info;
645	info->width_mm = ili->conf->width_mm;
646	info->height_mm = ili->conf->height_mm;
647	if (ili->conf->dclk_active_high)
648		info->bus_flags |= DRM_BUS_FLAG_PIXDATA_DRIVE_POSEDGE;
649	else
650		info->bus_flags |= DRM_BUS_FLAG_PIXDATA_DRIVE_NEGEDGE;
651
652	if (ili->conf->de_active_high)
653		info->bus_flags |= DRM_BUS_FLAG_DE_HIGH;
654	else
655		info->bus_flags |= DRM_BUS_FLAG_DE_LOW;
656
657	switch (ili->input) {
658	case ILI9322_INPUT_SRGB_DUMMY_320X240:
659		mode = drm_mode_duplicate(drm, &srgb_320x240_mode);
660		break;
661	case ILI9322_INPUT_SRGB_DUMMY_360X240:
662		mode = drm_mode_duplicate(drm, &srgb_360x240_mode);
663		break;
664	case ILI9322_INPUT_PRGB_THROUGH:
665	case ILI9322_INPUT_PRGB_ALIGNED:
666		mode = drm_mode_duplicate(drm, &prgb_320x240_mode);
667		break;
668	case ILI9322_INPUT_YUV_640X320_YCBCR:
669		mode = drm_mode_duplicate(drm, &yuv_640x320_mode);
670		break;
671	case ILI9322_INPUT_YUV_720X360_YCBCR:
672		mode = drm_mode_duplicate(drm, &yuv_720x360_mode);
673		break;
674	case ILI9322_INPUT_ITU_R_BT656_720X360_YCBCR:
675		mode = drm_mode_duplicate(drm, &itu_r_bt_656_720_mode);
676		break;
677	case ILI9322_INPUT_ITU_R_BT656_640X320_YCBCR:
678		mode = drm_mode_duplicate(drm, &itu_r_bt_656_640_mode);
679		break;
680	default:
681		mode = NULL;
682		break;
683	}
684	if (!mode) {
685		dev_err(panel->dev, "bad mode or failed to add mode\n");
686		return -EINVAL;
687	}
688	drm_mode_set_name(mode);
689	/*
690	 * This is the preferred mode because most people are going
691	 * to want to use the display with VGA type graphics.
692	 */
693	mode->type = DRM_MODE_TYPE_DRIVER | DRM_MODE_TYPE_PREFERRED;
694
695	/* Set up the polarity */
696	if (ili->conf->hsync_active_high)
697		mode->flags |= DRM_MODE_FLAG_PHSYNC;
698	else
699		mode->flags |= DRM_MODE_FLAG_NHSYNC;
700	if (ili->conf->vsync_active_high)
701		mode->flags |= DRM_MODE_FLAG_PVSYNC;
702	else
703		mode->flags |= DRM_MODE_FLAG_NVSYNC;
704
705	mode->width_mm = ili->conf->width_mm;
706	mode->height_mm = ili->conf->height_mm;
707	drm_mode_probed_add(connector, mode);
708
709	return 1; /* Number of modes */
710}
711
712static const struct drm_panel_funcs ili9322_drm_funcs = {
713	.disable = ili9322_disable,
714	.unprepare = ili9322_unprepare,
715	.prepare = ili9322_prepare,
716	.enable = ili9322_enable,
717	.get_modes = ili9322_get_modes,
718};
719
720static int ili9322_probe(struct spi_device *spi)
721{
722	struct device *dev = &spi->dev;
723	struct ili9322 *ili;
724	const struct regmap_config *regmap_config;
725	u8 gamma;
726	u32 val;
727	int ret;
728	int i;
729
730	ili = devm_kzalloc(dev, sizeof(struct ili9322), GFP_KERNEL);
731	if (!ili)
732		return -ENOMEM;
733
734	spi_set_drvdata(spi, ili);
735
736	ili->dev = dev;
737
738	/*
739	 * Every new incarnation of this display must have a unique
740	 * data entry for the system in this driver.
741	 */
742	ili->conf = of_device_get_match_data(dev);
743	if (!ili->conf) {
744		dev_err(dev, "missing device configuration\n");
745		return -ENODEV;
746	}
747
748	val = ili->conf->vreg1out_mv;
749	if (!val) {
750		/* Default HW value, do not touch (should be 4.5V) */
751		ili->vreg1out = U8_MAX;
752	} else {
753		if (val < 3600) {
754			dev_err(dev, "too low VREG1OUT\n");
755			return -EINVAL;
756		}
757		if (val > 6000) {
758			dev_err(dev, "too high VREG1OUT\n");
759			return -EINVAL;
760		}
761		if ((val % 100) != 0) {
762			dev_err(dev, "VREG1OUT is no even 100 microvolt\n");
763			return -EINVAL;
764		}
765		val -= 3600;
766		val /= 100;
767		dev_dbg(dev, "VREG1OUT = 0x%02x\n", val);
768		ili->vreg1out = val;
769	}
770
771	val = ili->conf->vcom_high_percent;
772	if (!val) {
773		/* Default HW value, do not touch (should be 91%) */
774		ili->vcom_high = U8_MAX;
775	} else {
776		if (val < 37) {
777			dev_err(dev, "too low VCOM high\n");
778			return -EINVAL;
779		}
780		if (val > 100) {
781			dev_err(dev, "too high VCOM high\n");
782			return -EINVAL;
783		}
784		val -= 37;
785		dev_dbg(dev, "VCOM high = 0x%02x\n", val);
786		ili->vcom_high = val;
787	}
788
789	val = ili->conf->vcom_amplitude_percent;
790	if (!val) {
791		/* Default HW value, do not touch (should be 114%) */
792		ili->vcom_high = U8_MAX;
793	} else {
794		if (val < 70) {
795			dev_err(dev, "too low VCOM amplitude\n");
796			return -EINVAL;
797		}
798		if (val > 132) {
799			dev_err(dev, "too high VCOM amplitude\n");
800			return -EINVAL;
801		}
802		val -= 70;
803		val >>= 1; /* Increments of 2% */
804		dev_dbg(dev, "VCOM amplitude = 0x%02x\n", val);
805		ili->vcom_amplitude = val;
806	}
807
808	for (i = 0; i < ARRAY_SIZE(ili->gamma); i++) {
809		val = ili->conf->gamma_corr_neg[i];
810		if (val > 15) {
811			dev_err(dev, "negative gamma %u > 15, capping\n", val);
812			val = 15;
813		}
814		gamma = val << 4;
815		val = ili->conf->gamma_corr_pos[i];
816		if (val > 15) {
817			dev_err(dev, "positive gamma %u > 15, capping\n", val);
818			val = 15;
819		}
820		gamma |= val;
821		ili->gamma[i] = gamma;
822		dev_dbg(dev, "gamma V%d: 0x%02x\n", i + 1, gamma);
823	}
824
825	ili->supplies[0].supply = "vcc"; /* 2.7-3.6 V */
826	ili->supplies[1].supply = "iovcc"; /* 1.65-3.6V */
827	ili->supplies[2].supply = "vci"; /* 2.7-3.6V */
828	ret = devm_regulator_bulk_get(dev, ARRAY_SIZE(ili->supplies),
829				      ili->supplies);
830	if (ret < 0)
831		return ret;
832	ret = regulator_set_voltage(ili->supplies[0].consumer,
833				    2700000, 3600000);
834	if (ret)
835		return ret;
836	ret = regulator_set_voltage(ili->supplies[1].consumer,
837				    1650000, 3600000);
838	if (ret)
839		return ret;
840	ret = regulator_set_voltage(ili->supplies[2].consumer,
841				    2700000, 3600000);
842	if (ret)
843		return ret;
844
845	ili->reset_gpio = devm_gpiod_get_optional(dev, "reset", GPIOD_OUT_HIGH);
846	if (IS_ERR(ili->reset_gpio)) {
847		dev_err(dev, "failed to get RESET GPIO\n");
848		return PTR_ERR(ili->reset_gpio);
849	}
850
851	spi->bits_per_word = 8;
852	ret = spi_setup(spi);
853	if (ret < 0) {
854		dev_err(dev, "spi setup failed.\n");
855		return ret;
856	}
857	regmap_config = &ili9322_regmap_config;
858	ili->regmap = devm_regmap_init(dev, &ili9322_regmap_bus, dev,
859				       regmap_config);
860	if (IS_ERR(ili->regmap)) {
861		dev_err(dev, "failed to allocate register map\n");
862		return PTR_ERR(ili->regmap);
863	}
864
865	ret = regmap_read(ili->regmap, ILI9322_CHIP_ID, &val);
866	if (ret) {
867		dev_err(dev, "can't get chip ID (%d)\n", ret);
868		return ret;
869	}
870	if (val != ILI9322_CHIP_ID_MAGIC) {
871		dev_err(dev, "chip ID 0x%0x2, expected 0x%02x\n", val,
872			ILI9322_CHIP_ID_MAGIC);
873		return -ENODEV;
874	}
875
876	/* Probe the system to find the display setting */
877	if (ili->conf->input == ILI9322_INPUT_UNKNOWN) {
878		ret = regmap_read(ili->regmap, ILI9322_ENTRY, &val);
879		if (ret) {
880			dev_err(dev, "can't get entry setting (%d)\n", ret);
881			return ret;
882		}
883		/* Input enum corresponds to HW setting */
884		ili->input = (val >> 4) & 0x0f;
885		if (ili->input >= ILI9322_INPUT_UNKNOWN)
886			ili->input = ILI9322_INPUT_UNKNOWN;
887	} else {
888		ili->input = ili->conf->input;
889	}
890
891	drm_panel_init(&ili->panel, dev, &ili9322_drm_funcs,
892		       DRM_MODE_CONNECTOR_DPI);
 
893
894	drm_panel_add(&ili->panel);
895
896	return 0;
897}
898
899static void ili9322_remove(struct spi_device *spi)
900{
901	struct ili9322 *ili = spi_get_drvdata(spi);
902
903	ili9322_power_off(ili);
904	drm_panel_remove(&ili->panel);
 
 
905}
906
907/*
908 * The D-Link DIR-685 panel is marked LM918A01-1A SY-B4-091116-E0199
909 */
910static const struct ili9322_config ili9322_dir_685 = {
911	.width_mm = 65,
912	.height_mm = 50,
913	.input = ILI9322_INPUT_ITU_R_BT656_640X320_YCBCR,
914	.vreg1out_mv = 4600,
915	.vcom_high_percent = 91,
916	.vcom_amplitude_percent = 114,
917	.syncmode = ILI9322_IF_CTRL_SYNC_DISABLED,
918	.dclk_active_high = true,
919	.gamma_corr_neg = { 0xa, 0x5, 0x7, 0x7, 0x7, 0x5, 0x1, 0x6 },
920	.gamma_corr_pos = { 0x7, 0x7, 0x3, 0x2, 0x3, 0x5, 0x7, 0x2 },
921};
922
923static const struct of_device_id ili9322_of_match[] = {
924	{
925		.compatible = "dlink,dir-685-panel",
926		.data = &ili9322_dir_685,
927	},
928	{
929		.compatible = "ilitek,ili9322",
930		.data = NULL,
931	},
932	{ }
933};
934MODULE_DEVICE_TABLE(of, ili9322_of_match);
935
936static struct spi_driver ili9322_driver = {
937	.probe = ili9322_probe,
938	.remove = ili9322_remove,
939	.driver = {
940		.name = "panel-ilitek-ili9322",
941		.of_match_table = ili9322_of_match,
942	},
943};
944module_spi_driver(ili9322_driver);
945
946MODULE_AUTHOR("Linus Walleij <linus.walleij@linaro.org>");
947MODULE_DESCRIPTION("ILI9322 LCD panel driver");
948MODULE_LICENSE("GPL v2");
v5.4
  1// SPDX-License-Identifier: GPL-2.0-only
  2/*
  3 * Ilitek ILI9322 TFT LCD drm_panel driver.
  4 *
  5 * This panel can be configured to support:
  6 * - 8-bit serial RGB interface
  7 * - 24-bit parallel RGB interface
  8 * - 8-bit ITU-R BT.601 interface
  9 * - 8-bit ITU-R BT.656 interface
 10 * - Up to 320RGBx240 dots resolution TFT LCD displays
 11 * - Scaling, brightness and contrast
 12 *
 13 * The scaling means that the display accepts a 640x480 or 720x480
 14 * input and rescales it to fit to the 320x240 display. So what we
 15 * present to the system is something else than what comes out on the
 16 * actual display.
 17 *
 18 * Copyright (C) 2017 Linus Walleij <linus.walleij@linaro.org>
 19 * Derived from drivers/drm/gpu/panel/panel-samsung-ld9040.c
 20 */
 21
 22#include <linux/bitops.h>
 23#include <linux/gpio/consumer.h>
 24#include <linux/module.h>
 25#include <linux/of_device.h>
 26#include <linux/regmap.h>
 27#include <linux/regulator/consumer.h>
 28#include <linux/spi/spi.h>
 29
 30#include <video/mipi_display.h>
 31#include <video/of_videomode.h>
 32#include <video/videomode.h>
 33
 34#include <drm/drm_modes.h>
 35#include <drm/drm_panel.h>
 36#include <drm/drm_print.h>
 37
 38#define ILI9322_CHIP_ID			0x00
 39#define ILI9322_CHIP_ID_MAGIC		0x96
 40
 41/*
 42 * Voltage on the communication interface, from 0.7 (0x00)
 43 * to 1.32 (0x1f) times the VREG1OUT voltage in 2% increments.
 44 * 1.00 (0x0f) is the default.
 45 */
 46#define ILI9322_VCOM_AMP		0x01
 47
 48/*
 49 * High voltage on the communication signals, from 0.37 (0x00) to
 50 * 1.0 (0x3f) times the VREGOUT1 voltage in 1% increments.
 51 * 0.83 (0x2e) is the default.
 52 */
 53#define ILI9322_VCOM_HIGH		0x02
 54
 55/*
 56 * VREG1 voltage regulator from 3.6V (0x00) to 6.0V (0x18) in 0.1V
 57 * increments. 5.4V (0x12) is the default. This is the reference
 58 * voltage for the VCOM levels and the greyscale level.
 59 */
 60#define ILI9322_VREG1_VOLTAGE		0x03
 61
 62/* Describes the incoming signal */
 63#define ILI9322_ENTRY			0x06
 64/* 0 = right-to-left, 1 = left-to-right (default), horizontal flip */
 65#define ILI9322_ENTRY_HDIR		BIT(0)
 66/* 0 = down-to-up, 1 = up-to-down (default), vertical flip  */
 67#define ILI9322_ENTRY_VDIR		BIT(1)
 68/* NTSC, PAL or autodetect */
 69#define ILI9322_ENTRY_NTSC		(0 << 2)
 70#define ILI9322_ENTRY_PAL		(1 << 2)
 71#define ILI9322_ENTRY_AUTODETECT	(3 << 2)
 72/* Input format */
 73#define ILI9322_ENTRY_SERIAL_RGB_THROUGH (0 << 4)
 74#define ILI9322_ENTRY_SERIAL_RGB_ALIGNED (1 << 4)
 75#define ILI9322_ENTRY_SERIAL_RGB_DUMMY_320X240 (2 << 4)
 76#define ILI9322_ENTRY_SERIAL_RGB_DUMMY_360X240 (3 << 4)
 77#define ILI9322_ENTRY_DISABLE_1		(4 << 4)
 78#define ILI9322_ENTRY_PARALLEL_RGB_THROUGH (5 << 4)
 79#define ILI9322_ENTRY_PARALLEL_RGB_ALIGNED (6 << 4)
 80#define ILI9322_ENTRY_YUV_640Y_320CBCR_25_54_MHZ (7 << 4)
 81#define ILI9322_ENTRY_YUV_720Y_360CBCR_27_MHZ (8 << 4)
 82#define ILI9322_ENTRY_DISABLE_2		(9 << 4)
 83#define ILI9322_ENTRY_ITU_R_BT_656_720X360 (10 << 4)
 84#define ILI9322_ENTRY_ITU_R_BT_656_640X320 (11 << 4)
 85
 86/* Power control */
 87#define ILI9322_POW_CTRL		0x07
 88#define ILI9322_POW_CTRL_STB		BIT(0) /* 0 = standby, 1 = normal */
 89#define ILI9322_POW_CTRL_VGL		BIT(1) /* 0 = off, 1 = on  */
 90#define ILI9322_POW_CTRL_VGH		BIT(2) /* 0 = off, 1 = on  */
 91#define ILI9322_POW_CTRL_DDVDH		BIT(3) /* 0 = off, 1 = on  */
 92#define ILI9322_POW_CTRL_VCOM		BIT(4) /* 0 = off, 1 = on  */
 93#define ILI9322_POW_CTRL_VCL		BIT(5) /* 0 = off, 1 = on  */
 94#define ILI9322_POW_CTRL_AUTO		BIT(6) /* 0 = interactive, 1 = auto */
 95#define ILI9322_POW_CTRL_STANDBY	(ILI9322_POW_CTRL_VGL | \
 96					 ILI9322_POW_CTRL_VGH | \
 97					 ILI9322_POW_CTRL_DDVDH | \
 98					 ILI9322_POW_CTRL_VCL | \
 99					 ILI9322_POW_CTRL_AUTO | \
100					 BIT(7))
101#define ILI9322_POW_CTRL_DEFAULT	(ILI9322_POW_CTRL_STANDBY | \
102					 ILI9322_POW_CTRL_STB)
103
104/* Vertical back porch bits 0..5 */
105#define ILI9322_VBP			0x08
106
107/* Horizontal back porch, 8 bits */
108#define ILI9322_HBP			0x09
109
110/*
111 * Polarity settings:
112 * 1 = positive polarity
113 * 0 = negative polarity
114 */
115#define ILI9322_POL			0x0a
116#define ILI9322_POL_DCLK		BIT(0) /* 1 default */
117#define ILI9322_POL_HSYNC		BIT(1) /* 0 default */
118#define ILI9322_POL_VSYNC		BIT(2) /* 0 default */
119#define ILI9322_POL_DE			BIT(3) /* 1 default */
120/*
121 * 0 means YCBCR are ordered Cb0,Y0,Cr0,Y1,Cb2,Y2,Cr2,Y3 (default)
122 *   in RGB mode this means RGB comes in RGBRGB
123 * 1 means YCBCR are ordered Cr0,Y0,Cb0,Y1,Cr2,Y2,Cb2,Y3
124 *   in RGB mode this means RGB comes in BGRBGR
125 */
126#define ILI9322_POL_YCBCR_MODE		BIT(4)
127/* Formula A for YCbCR->RGB = 0, Formula B = 1 */
128#define ILI9322_POL_FORMULA		BIT(5)
129/* Reverse polarity: 0 = 0..255, 1 = 255..0 */
130#define ILI9322_POL_REV			BIT(6)
131
132#define ILI9322_IF_CTRL			0x0b
133#define ILI9322_IF_CTRL_HSYNC_VSYNC	0x00
134#define ILI9322_IF_CTRL_HSYNC_VSYNC_DE	BIT(2)
135#define ILI9322_IF_CTRL_DE_ONLY		BIT(3)
136#define ILI9322_IF_CTRL_SYNC_DISABLED	(BIT(2) | BIT(3))
137#define ILI9322_IF_CTRL_LINE_INVERSION	BIT(0) /* Not set means frame inv */
138
139#define ILI9322_GLOBAL_RESET		0x04
140#define ILI9322_GLOBAL_RESET_ASSERT	0x00 /* bit 0 = 0 -> reset */
141
142/*
143 * 4+4 bits of negative and positive gamma correction
144 * Upper nybble, bits 4-7 are negative gamma
145 * Lower nybble, bits 0-3 are positive gamma
146 */
147#define ILI9322_GAMMA_1			0x10
148#define ILI9322_GAMMA_2			0x11
149#define ILI9322_GAMMA_3			0x12
150#define ILI9322_GAMMA_4			0x13
151#define ILI9322_GAMMA_5			0x14
152#define ILI9322_GAMMA_6			0x15
153#define ILI9322_GAMMA_7			0x16
154#define ILI9322_GAMMA_8			0x17
155
156/**
157 * enum ili9322_input - the format of the incoming signal to the panel
158 *
159 * The panel can be connected to various input streams and four of them can
160 * be selected by electronic straps on the display. However it is possible
161 * to select another mode or override the electronic default with this
162 * setting.
163 */
164enum ili9322_input {
165	ILI9322_INPUT_SRGB_THROUGH = 0x0,
166	ILI9322_INPUT_SRGB_ALIGNED = 0x1,
167	ILI9322_INPUT_SRGB_DUMMY_320X240 = 0x2,
168	ILI9322_INPUT_SRGB_DUMMY_360X240 = 0x3,
169	ILI9322_INPUT_DISABLED_1 = 0x4,
170	ILI9322_INPUT_PRGB_THROUGH = 0x5,
171	ILI9322_INPUT_PRGB_ALIGNED = 0x6,
172	ILI9322_INPUT_YUV_640X320_YCBCR = 0x7,
173	ILI9322_INPUT_YUV_720X360_YCBCR = 0x8,
174	ILI9322_INPUT_DISABLED_2 = 0x9,
175	ILI9322_INPUT_ITU_R_BT656_720X360_YCBCR = 0xa,
176	ILI9322_INPUT_ITU_R_BT656_640X320_YCBCR = 0xb,
177	ILI9322_INPUT_UNKNOWN = 0xc,
178};
179
180static const char * const ili9322_inputs[] = {
181	"8 bit serial RGB through",
182	"8 bit serial RGB aligned",
183	"8 bit serial RGB dummy 320x240",
184	"8 bit serial RGB dummy 360x240",
185	"disabled 1",
186	"24 bit parallel RGB through",
187	"24 bit parallel RGB aligned",
188	"24 bit YUV 640Y 320CbCr",
189	"24 bit YUV 720Y 360CbCr",
190	"disabled 2",
191	"8 bit ITU-R BT.656 720Y 360CbCr",
192	"8 bit ITU-R BT.656 640Y 320CbCr",
193};
194
195/**
196 * struct ili9322_config - the system specific ILI9322 configuration
197 * @width_mm: physical panel width [mm]
198 * @height_mm: physical panel height [mm]
199 * @flip_horizontal: flip the image horizontally (right-to-left scan)
200 * (only in RGB and YUV modes)
201 * @flip_vertical: flip the image vertically (down-to-up scan)
202 * (only in RGB and YUV modes)
203 * @input: the input/entry type used in this system, if this is set to
204 * ILI9322_INPUT_UNKNOWN the driver will try to figure it out by probing
205 * the hardware
206 * @vreg1out_mv: the output in microvolts for the VREGOUT1 regulator used
207 * to drive the physical display. Valid ranges are 3600 thru 6000 in 100
208 * microvolt increments. If not specified, hardware defaults will be
209 * used (4.5V).
210 * @vcom_high_percent: the percentage of VREGOUT1 used for the peak
211 * voltage on the communications link. Valid ranges are 37 thru 100
212 * percent. If not specified, hardware defaults will be used (91%).
213 * @vcom_amplitude_percent: the percentage of VREGOUT1 used for the
214 * peak-to-peak amplitude of the communcation signals to the physical
215 * display. Valid ranges are 70 thru 132 percent in increments if two
216 * percent. Odd percentages will be truncated. If not specified, hardware
217 * defaults will be used (114%).
218 * @dclk_active_high: data/pixel clock active high, data will be clocked
219 * in on the rising edge of the DCLK (this is usually the case).
220 * @syncmode: The synchronization mode, what sync signals are emitted.
221 * See the enum for details.
222 * @de_active_high: DE (data entry) is active high
223 * @hsync_active_high: HSYNC is active high
224 * @vsync_active_high: VSYNC is active high
225 * @gamma_corr_pos: a set of 8 nybbles describing positive
226 * gamma correction for voltages V1 thru V8. Valid range 0..15
227 * @gamma_corr_neg: a set of 8 nybbles describing negative
228 * gamma correction for voltages V1 thru V8. Valid range 0..15
229 *
230 * These adjust what grayscale voltage will be output for input data V1 = 0,
231 * V2 = 16, V3 = 48, V4 = 96, V5 = 160, V6 = 208, V7 = 240 and V8 = 255.
232 * The curve is shaped like this:
233 *
234 *  ^
235 *  |                                                        V8
236 *  |                                                   V7
237 *  |                                          V6
238 *  |                               V5
239 *  |                    V4
240 *  |            V3
241 *  |     V2
242 *  | V1
243 *  +----------------------------------------------------------->
244 *    0   16     48      96         160        208      240  255
245 *
246 * The negative and postive gamma values adjust the V1 thru V8 up/down
247 * according to the datasheet specifications. This is a property of the
248 * physical display connected to the display controller and may vary.
249 * If defined, both arrays must be supplied in full. If the properties
250 * are not supplied, hardware defaults will be used.
251 */
252struct ili9322_config {
253	u32 width_mm;
254	u32 height_mm;
255	bool flip_horizontal;
256	bool flip_vertical;
257	enum ili9322_input input;
258	u32 vreg1out_mv;
259	u32 vcom_high_percent;
260	u32 vcom_amplitude_percent;
261	bool dclk_active_high;
262	bool de_active_high;
263	bool hsync_active_high;
264	bool vsync_active_high;
265	u8 syncmode;
266	u8 gamma_corr_pos[8];
267	u8 gamma_corr_neg[8];
268};
269
270struct ili9322 {
271	struct device *dev;
272	const struct ili9322_config *conf;
273	struct drm_panel panel;
274	struct regmap *regmap;
275	struct regulator_bulk_data supplies[3];
276	struct gpio_desc *reset_gpio;
277	enum ili9322_input input;
278	struct videomode vm;
279	u8 gamma[8];
280	u8 vreg1out;
281	u8 vcom_high;
282	u8 vcom_amplitude;
283};
284
285static inline struct ili9322 *panel_to_ili9322(struct drm_panel *panel)
286{
287	return container_of(panel, struct ili9322, panel);
288}
289
290static int ili9322_regmap_spi_write(void *context, const void *data,
291				    size_t count)
292{
293	struct device *dev = context;
294	struct spi_device *spi = to_spi_device(dev);
295	u8 buf[2];
296
297	/* Clear bit 7 to write */
298	memcpy(buf, data, 2);
299	buf[0] &= ~0x80;
300
301	dev_dbg(dev, "WRITE: %02x %02x\n", buf[0], buf[1]);
302	return spi_write_then_read(spi, buf, 2, NULL, 0);
303}
304
305static int ili9322_regmap_spi_read(void *context, const void *reg,
306				   size_t reg_size, void *val, size_t val_size)
307{
308	struct device *dev = context;
309	struct spi_device *spi = to_spi_device(dev);
310	u8 buf[1];
311
312	/* Set bit 7 to 1 to read */
313	memcpy(buf, reg, 1);
314	dev_dbg(dev, "READ: %02x reg size = %zu, val size = %zu\n",
315		buf[0], reg_size, val_size);
316	buf[0] |= 0x80;
317
318	return spi_write_then_read(spi, buf, 1, val, 1);
319}
320
321static struct regmap_bus ili9322_regmap_bus = {
322	.write = ili9322_regmap_spi_write,
323	.read = ili9322_regmap_spi_read,
324	.reg_format_endian_default = REGMAP_ENDIAN_BIG,
325	.val_format_endian_default = REGMAP_ENDIAN_BIG,
326};
327
328static bool ili9322_volatile_reg(struct device *dev, unsigned int reg)
329{
330	return false;
331}
332
333static bool ili9322_writeable_reg(struct device *dev, unsigned int reg)
334{
335	/* Just register 0 is read-only */
336	if (reg == 0x00)
337		return false;
338	return true;
339}
340
341static const struct regmap_config ili9322_regmap_config = {
342	.reg_bits = 8,
343	.val_bits = 8,
344	.max_register = 0x44,
345	.cache_type = REGCACHE_RBTREE,
346	.volatile_reg = ili9322_volatile_reg,
347	.writeable_reg = ili9322_writeable_reg,
348};
349
350static int ili9322_init(struct drm_panel *panel, struct ili9322 *ili)
351{
352	u8 reg;
353	int ret;
354	int i;
355
356	/* Reset display */
357	ret = regmap_write(ili->regmap, ILI9322_GLOBAL_RESET,
358			   ILI9322_GLOBAL_RESET_ASSERT);
359	if (ret) {
360		dev_err(ili->dev, "can't issue GRESET (%d)\n", ret);
361		return ret;
362	}
363
364	/* Set up the main voltage regulator */
365	if (ili->vreg1out != U8_MAX) {
366		ret = regmap_write(ili->regmap, ILI9322_VREG1_VOLTAGE,
367				   ili->vreg1out);
368		if (ret) {
369			dev_err(ili->dev, "can't set up VREG1OUT (%d)\n", ret);
370			return ret;
371		}
372	}
373
374	if (ili->vcom_amplitude != U8_MAX) {
375		ret = regmap_write(ili->regmap, ILI9322_VCOM_AMP,
376				   ili->vcom_amplitude);
377		if (ret) {
378			dev_err(ili->dev,
379				"can't set up VCOM amplitude (%d)\n", ret);
380			return ret;
381		}
382	};
383
384	if (ili->vcom_high != U8_MAX) {
385		ret = regmap_write(ili->regmap, ILI9322_VCOM_HIGH,
386				   ili->vcom_high);
387		if (ret) {
388			dev_err(ili->dev, "can't set up VCOM high (%d)\n", ret);
389			return ret;
390		}
391	};
392
393	/* Set up gamma correction */
394	for (i = 0; i < ARRAY_SIZE(ili->gamma); i++) {
395		ret = regmap_write(ili->regmap, ILI9322_GAMMA_1 + i,
396				   ili->gamma[i]);
397		if (ret) {
398			dev_err(ili->dev,
399				"can't write gamma V%d to 0x%02x (%d)\n",
400				i + 1, ILI9322_GAMMA_1 + i, ret);
401			return ret;
402		}
403	}
404
405	/*
406	 * Polarity and inverted color order for RGB input.
407	 * None of this applies in the BT.656 mode.
408	 */
409	reg = 0;
410	if (ili->conf->dclk_active_high)
411		reg = ILI9322_POL_DCLK;
412	if (ili->conf->de_active_high)
413		reg |= ILI9322_POL_DE;
414	if (ili->conf->hsync_active_high)
415		reg |= ILI9322_POL_HSYNC;
416	if (ili->conf->vsync_active_high)
417		reg |= ILI9322_POL_VSYNC;
418	ret = regmap_write(ili->regmap, ILI9322_POL, reg);
419	if (ret) {
420		dev_err(ili->dev, "can't write POL register (%d)\n", ret);
421		return ret;
422	}
423
424	/*
425	 * Set up interface control.
426	 * This is not used in the BT.656 mode (no H/Vsync or DE signals).
427	 */
428	reg = ili->conf->syncmode;
429	reg |= ILI9322_IF_CTRL_LINE_INVERSION;
430	ret = regmap_write(ili->regmap, ILI9322_IF_CTRL, reg);
431	if (ret) {
432		dev_err(ili->dev, "can't write IF CTRL register (%d)\n", ret);
433		return ret;
434	}
435
436	/* Set up the input mode */
437	reg = (ili->input << 4);
438	/* These are inverted, setting to 1 is the default, clearing flips */
439	if (!ili->conf->flip_horizontal)
440		reg |= ILI9322_ENTRY_HDIR;
441	if (!ili->conf->flip_vertical)
442		reg |= ILI9322_ENTRY_VDIR;
443	reg |= ILI9322_ENTRY_AUTODETECT;
444	ret = regmap_write(ili->regmap, ILI9322_ENTRY, reg);
445	if (ret) {
446		dev_err(ili->dev, "can't write ENTRY reg (%d)\n", ret);
447		return ret;
448	}
449	dev_info(ili->dev, "display is in %s mode, syncmode %02x\n",
450		 ili9322_inputs[ili->input],
451		 ili->conf->syncmode);
452
453	dev_info(ili->dev, "initialized display\n");
454
455	return 0;
456}
457
458/*
459 * This power-on sequence if from the datasheet, page 57.
460 */
461static int ili9322_power_on(struct ili9322 *ili)
462{
463	int ret;
464
465	/* Assert RESET */
466	gpiod_set_value(ili->reset_gpio, 1);
467
468	ret = regulator_bulk_enable(ARRAY_SIZE(ili->supplies), ili->supplies);
469	if (ret < 0) {
470		dev_err(ili->dev, "unable to enable regulators\n");
471		return ret;
472	}
473	msleep(20);
474
475	/* De-assert RESET */
476	gpiod_set_value(ili->reset_gpio, 0);
477
478	msleep(10);
479
480	return 0;
481}
482
483static int ili9322_power_off(struct ili9322 *ili)
484{
485	return regulator_bulk_disable(ARRAY_SIZE(ili->supplies), ili->supplies);
486}
487
488static int ili9322_disable(struct drm_panel *panel)
489{
490	struct ili9322 *ili = panel_to_ili9322(panel);
491	int ret;
492
493	ret = regmap_write(ili->regmap, ILI9322_POW_CTRL,
494			   ILI9322_POW_CTRL_STANDBY);
495	if (ret) {
496		dev_err(ili->dev, "unable to go to standby mode\n");
497		return ret;
498	}
499
500	return 0;
501}
502
503static int ili9322_unprepare(struct drm_panel *panel)
504{
505	struct ili9322 *ili = panel_to_ili9322(panel);
506
507	return ili9322_power_off(ili);
508}
509
510static int ili9322_prepare(struct drm_panel *panel)
511{
512	struct ili9322 *ili = panel_to_ili9322(panel);
513	int ret;
514
515	ret = ili9322_power_on(ili);
516	if (ret < 0)
517		return ret;
518
519	ret = ili9322_init(panel, ili);
520	if (ret < 0)
521		ili9322_unprepare(panel);
522
523	return ret;
524}
525
526static int ili9322_enable(struct drm_panel *panel)
527{
528	struct ili9322 *ili = panel_to_ili9322(panel);
529	int ret;
530
531	ret = regmap_write(ili->regmap, ILI9322_POW_CTRL,
532			   ILI9322_POW_CTRL_DEFAULT);
533	if (ret) {
534		dev_err(ili->dev, "unable to enable panel\n");
535		return ret;
536	}
537
538	return 0;
539}
540
541/* Serial RGB modes */
542static const struct drm_display_mode srgb_320x240_mode = {
543	.clock = 2453500,
544	.hdisplay = 320,
545	.hsync_start = 320 + 359,
546	.hsync_end = 320 + 359 + 1,
547	.htotal = 320 + 359 + 1 + 241,
548	.vdisplay = 240,
549	.vsync_start = 240 + 4,
550	.vsync_end = 240 + 4 + 1,
551	.vtotal = 262,
552	.vrefresh = 60,
553	.flags = 0,
554};
555
556static const struct drm_display_mode srgb_360x240_mode = {
557	.clock = 2700000,
558	.hdisplay = 360,
559	.hsync_start = 360 + 35,
560	.hsync_end = 360 + 35 + 1,
561	.htotal = 360 + 35 + 1 + 241,
562	.vdisplay = 240,
563	.vsync_start = 240 + 21,
564	.vsync_end = 240 + 21 + 1,
565	.vtotal = 262,
566	.vrefresh = 60,
567	.flags = 0,
568};
569
570/* This is the only mode listed for parallel RGB in the datasheet */
571static const struct drm_display_mode prgb_320x240_mode = {
572	.clock = 6400000,
573	.hdisplay = 320,
574	.hsync_start = 320 + 38,
575	.hsync_end = 320 + 38 + 1,
576	.htotal = 320 + 38 + 1 + 50,
577	.vdisplay = 240,
578	.vsync_start = 240 + 4,
579	.vsync_end = 240 + 4 + 1,
580	.vtotal = 262,
581	.vrefresh = 60,
582	.flags = 0,
583};
584
585/* YUV modes */
586static const struct drm_display_mode yuv_640x320_mode = {
587	.clock = 2454000,
588	.hdisplay = 640,
589	.hsync_start = 640 + 252,
590	.hsync_end = 640 + 252 + 1,
591	.htotal = 640 + 252 + 1 + 28,
592	.vdisplay = 320,
593	.vsync_start = 320 + 4,
594	.vsync_end = 320 + 4 + 1,
595	.vtotal = 320 + 4 + 1 + 18,
596	.vrefresh = 60,
597	.flags = 0,
598};
599
600static const struct drm_display_mode yuv_720x360_mode = {
601	.clock = 2700000,
602	.hdisplay = 720,
603	.hsync_start = 720 + 252,
604	.hsync_end = 720 + 252 + 1,
605	.htotal = 720 + 252 + 1 + 24,
606	.vdisplay = 360,
607	.vsync_start = 360 + 4,
608	.vsync_end = 360 + 4 + 1,
609	.vtotal = 360 + 4 + 1 + 18,
610	.vrefresh = 60,
611	.flags = 0,
612};
613
614/* BT.656 VGA mode, 640x480 */
615static const struct drm_display_mode itu_r_bt_656_640_mode = {
616	.clock = 2454000,
617	.hdisplay = 640,
618	.hsync_start = 640 + 3,
619	.hsync_end = 640 + 3 + 1,
620	.htotal = 640 + 3 + 1 + 272,
621	.vdisplay = 480,
622	.vsync_start = 480 + 4,
623	.vsync_end = 480 + 4 + 1,
624	.vtotal = 500,
625	.vrefresh = 60,
626	.flags = 0,
627};
628
629/* BT.656 D1 mode 720x480 */
630static const struct drm_display_mode itu_r_bt_656_720_mode = {
631	.clock = 2700000,
632	.hdisplay = 720,
633	.hsync_start = 720 + 3,
634	.hsync_end = 720 + 3 + 1,
635	.htotal = 720 + 3 + 1 + 272,
636	.vdisplay = 480,
637	.vsync_start = 480 + 4,
638	.vsync_end = 480 + 4 + 1,
639	.vtotal = 500,
640	.vrefresh = 60,
641	.flags = 0,
642};
643
644static int ili9322_get_modes(struct drm_panel *panel)
 
645{
646	struct drm_connector *connector = panel->connector;
647	struct ili9322 *ili = panel_to_ili9322(panel);
 
648	struct drm_display_mode *mode;
649	struct drm_display_info *info;
650
651	info = &connector->display_info;
652	info->width_mm = ili->conf->width_mm;
653	info->height_mm = ili->conf->height_mm;
654	if (ili->conf->dclk_active_high)
655		info->bus_flags |= DRM_BUS_FLAG_PIXDATA_DRIVE_POSEDGE;
656	else
657		info->bus_flags |= DRM_BUS_FLAG_PIXDATA_DRIVE_NEGEDGE;
658
659	if (ili->conf->de_active_high)
660		info->bus_flags |= DRM_BUS_FLAG_DE_HIGH;
661	else
662		info->bus_flags |= DRM_BUS_FLAG_DE_LOW;
663
664	switch (ili->input) {
665	case ILI9322_INPUT_SRGB_DUMMY_320X240:
666		mode = drm_mode_duplicate(panel->drm, &srgb_320x240_mode);
667		break;
668	case ILI9322_INPUT_SRGB_DUMMY_360X240:
669		mode = drm_mode_duplicate(panel->drm, &srgb_360x240_mode);
670		break;
671	case ILI9322_INPUT_PRGB_THROUGH:
672	case ILI9322_INPUT_PRGB_ALIGNED:
673		mode = drm_mode_duplicate(panel->drm, &prgb_320x240_mode);
674		break;
675	case ILI9322_INPUT_YUV_640X320_YCBCR:
676		mode = drm_mode_duplicate(panel->drm, &yuv_640x320_mode);
677		break;
678	case ILI9322_INPUT_YUV_720X360_YCBCR:
679		mode = drm_mode_duplicate(panel->drm, &yuv_720x360_mode);
680		break;
681	case ILI9322_INPUT_ITU_R_BT656_720X360_YCBCR:
682		mode = drm_mode_duplicate(panel->drm, &itu_r_bt_656_720_mode);
683		break;
684	case ILI9322_INPUT_ITU_R_BT656_640X320_YCBCR:
685		mode = drm_mode_duplicate(panel->drm, &itu_r_bt_656_640_mode);
686		break;
687	default:
688		mode = NULL;
689		break;
690	}
691	if (!mode) {
692		DRM_ERROR("bad mode or failed to add mode\n");
693		return -EINVAL;
694	}
695	drm_mode_set_name(mode);
696	/*
697	 * This is the preferred mode because most people are going
698	 * to want to use the display with VGA type graphics.
699	 */
700	mode->type = DRM_MODE_TYPE_DRIVER | DRM_MODE_TYPE_PREFERRED;
701
702	/* Set up the polarity */
703	if (ili->conf->hsync_active_high)
704		mode->flags |= DRM_MODE_FLAG_PHSYNC;
705	else
706		mode->flags |= DRM_MODE_FLAG_NHSYNC;
707	if (ili->conf->vsync_active_high)
708		mode->flags |= DRM_MODE_FLAG_PVSYNC;
709	else
710		mode->flags |= DRM_MODE_FLAG_NVSYNC;
711
712	mode->width_mm = ili->conf->width_mm;
713	mode->height_mm = ili->conf->height_mm;
714	drm_mode_probed_add(connector, mode);
715
716	return 1; /* Number of modes */
717}
718
719static const struct drm_panel_funcs ili9322_drm_funcs = {
720	.disable = ili9322_disable,
721	.unprepare = ili9322_unprepare,
722	.prepare = ili9322_prepare,
723	.enable = ili9322_enable,
724	.get_modes = ili9322_get_modes,
725};
726
727static int ili9322_probe(struct spi_device *spi)
728{
729	struct device *dev = &spi->dev;
730	struct ili9322 *ili;
731	const struct regmap_config *regmap_config;
732	u8 gamma;
733	u32 val;
734	int ret;
735	int i;
736
737	ili = devm_kzalloc(dev, sizeof(struct ili9322), GFP_KERNEL);
738	if (!ili)
739		return -ENOMEM;
740
741	spi_set_drvdata(spi, ili);
742
743	ili->dev = dev;
744
745	/*
746	 * Every new incarnation of this display must have a unique
747	 * data entry for the system in this driver.
748	 */
749	ili->conf = of_device_get_match_data(dev);
750	if (!ili->conf) {
751		dev_err(dev, "missing device configuration\n");
752		return -ENODEV;
753	}
754
755	val = ili->conf->vreg1out_mv;
756	if (!val) {
757		/* Default HW value, do not touch (should be 4.5V) */
758		ili->vreg1out = U8_MAX;
759	} else {
760		if (val < 3600) {
761			dev_err(dev, "too low VREG1OUT\n");
762			return -EINVAL;
763		}
764		if (val > 6000) {
765			dev_err(dev, "too high VREG1OUT\n");
766			return -EINVAL;
767		}
768		if ((val % 100) != 0) {
769			dev_err(dev, "VREG1OUT is no even 100 microvolt\n");
770			return -EINVAL;
771		}
772		val -= 3600;
773		val /= 100;
774		dev_dbg(dev, "VREG1OUT = 0x%02x\n", val);
775		ili->vreg1out = val;
776	}
777
778	val = ili->conf->vcom_high_percent;
779	if (!val) {
780		/* Default HW value, do not touch (should be 91%) */
781		ili->vcom_high = U8_MAX;
782	} else {
783		if (val < 37) {
784			dev_err(dev, "too low VCOM high\n");
785			return -EINVAL;
786		}
787		if (val > 100) {
788			dev_err(dev, "too high VCOM high\n");
789			return -EINVAL;
790		}
791		val -= 37;
792		dev_dbg(dev, "VCOM high = 0x%02x\n", val);
793		ili->vcom_high = val;
794	}
795
796	val = ili->conf->vcom_amplitude_percent;
797	if (!val) {
798		/* Default HW value, do not touch (should be 114%) */
799		ili->vcom_high = U8_MAX;
800	} else {
801		if (val < 70) {
802			dev_err(dev, "too low VCOM amplitude\n");
803			return -EINVAL;
804		}
805		if (val > 132) {
806			dev_err(dev, "too high VCOM amplitude\n");
807			return -EINVAL;
808		}
809		val -= 70;
810		val >>= 1; /* Increments of 2% */
811		dev_dbg(dev, "VCOM amplitude = 0x%02x\n", val);
812		ili->vcom_amplitude = val;
813	}
814
815	for (i = 0; i < ARRAY_SIZE(ili->gamma); i++) {
816		val = ili->conf->gamma_corr_neg[i];
817		if (val > 15) {
818			dev_err(dev, "negative gamma %u > 15, capping\n", val);
819			val = 15;
820		}
821		gamma = val << 4;
822		val = ili->conf->gamma_corr_pos[i];
823		if (val > 15) {
824			dev_err(dev, "positive gamma %u > 15, capping\n", val);
825			val = 15;
826		}
827		gamma |= val;
828		ili->gamma[i] = gamma;
829		dev_dbg(dev, "gamma V%d: 0x%02x\n", i + 1, gamma);
830	}
831
832	ili->supplies[0].supply = "vcc"; /* 2.7-3.6 V */
833	ili->supplies[1].supply = "iovcc"; /* 1.65-3.6V */
834	ili->supplies[2].supply = "vci"; /* 2.7-3.6V */
835	ret = devm_regulator_bulk_get(dev, ARRAY_SIZE(ili->supplies),
836				      ili->supplies);
837	if (ret < 0)
838		return ret;
839	ret = regulator_set_voltage(ili->supplies[0].consumer,
840				    2700000, 3600000);
841	if (ret)
842		return ret;
843	ret = regulator_set_voltage(ili->supplies[1].consumer,
844				    1650000, 3600000);
845	if (ret)
846		return ret;
847	ret = regulator_set_voltage(ili->supplies[2].consumer,
848				    2700000, 3600000);
849	if (ret)
850		return ret;
851
852	ili->reset_gpio = devm_gpiod_get_optional(dev, "reset", GPIOD_OUT_HIGH);
853	if (IS_ERR(ili->reset_gpio)) {
854		dev_err(dev, "failed to get RESET GPIO\n");
855		return PTR_ERR(ili->reset_gpio);
856	}
857
858	spi->bits_per_word = 8;
859	ret = spi_setup(spi);
860	if (ret < 0) {
861		dev_err(dev, "spi setup failed.\n");
862		return ret;
863	}
864	regmap_config = &ili9322_regmap_config;
865	ili->regmap = devm_regmap_init(dev, &ili9322_regmap_bus, dev,
866				       regmap_config);
867	if (IS_ERR(ili->regmap)) {
868		dev_err(dev, "failed to allocate register map\n");
869		return PTR_ERR(ili->regmap);
870	}
871
872	ret = regmap_read(ili->regmap, ILI9322_CHIP_ID, &val);
873	if (ret) {
874		dev_err(dev, "can't get chip ID (%d)\n", ret);
875		return ret;
876	}
877	if (val != ILI9322_CHIP_ID_MAGIC) {
878		dev_err(dev, "chip ID 0x%0x2, expected 0x%02x\n", val,
879			ILI9322_CHIP_ID_MAGIC);
880		return -ENODEV;
881	}
882
883	/* Probe the system to find the display setting */
884	if (ili->conf->input == ILI9322_INPUT_UNKNOWN) {
885		ret = regmap_read(ili->regmap, ILI9322_ENTRY, &val);
886		if (ret) {
887			dev_err(dev, "can't get entry setting (%d)\n", ret);
888			return ret;
889		}
890		/* Input enum corresponds to HW setting */
891		ili->input = (val >> 4) & 0x0f;
892		if (ili->input >= ILI9322_INPUT_UNKNOWN)
893			ili->input = ILI9322_INPUT_UNKNOWN;
894	} else {
895		ili->input = ili->conf->input;
896	}
897
898	drm_panel_init(&ili->panel);
899	ili->panel.dev = dev;
900	ili->panel.funcs = &ili9322_drm_funcs;
901
902	return drm_panel_add(&ili->panel);
 
 
903}
904
905static int ili9322_remove(struct spi_device *spi)
906{
907	struct ili9322 *ili = spi_get_drvdata(spi);
908
909	ili9322_power_off(ili);
910	drm_panel_remove(&ili->panel);
911
912	return 0;
913}
914
915/*
916 * The D-Link DIR-685 panel is marked LM918A01-1A SY-B4-091116-E0199
917 */
918static const struct ili9322_config ili9322_dir_685 = {
919	.width_mm = 65,
920	.height_mm = 50,
921	.input = ILI9322_INPUT_ITU_R_BT656_640X320_YCBCR,
922	.vreg1out_mv = 4600,
923	.vcom_high_percent = 91,
924	.vcom_amplitude_percent = 114,
925	.syncmode = ILI9322_IF_CTRL_SYNC_DISABLED,
926	.dclk_active_high = true,
927	.gamma_corr_neg = { 0xa, 0x5, 0x7, 0x7, 0x7, 0x5, 0x1, 0x6 },
928	.gamma_corr_pos = { 0x7, 0x7, 0x3, 0x2, 0x3, 0x5, 0x7, 0x2 },
929};
930
931static const struct of_device_id ili9322_of_match[] = {
932	{
933		.compatible = "dlink,dir-685-panel",
934		.data = &ili9322_dir_685,
935	},
936	{
937		.compatible = "ilitek,ili9322",
938		.data = NULL,
939	},
940	{ }
941};
942MODULE_DEVICE_TABLE(of, ili9322_of_match);
943
944static struct spi_driver ili9322_driver = {
945	.probe = ili9322_probe,
946	.remove = ili9322_remove,
947	.driver = {
948		.name = "panel-ilitek-ili9322",
949		.of_match_table = ili9322_of_match,
950	},
951};
952module_spi_driver(ili9322_driver);
953
954MODULE_AUTHOR("Linus Walleij <linus.walleij@linaro.org>");
955MODULE_DESCRIPTION("ILI9322 LCD panel driver");
956MODULE_LICENSE("GPL v2");