File Index
Files and directories
Sign in
FILE

panel-ilitek-ili9322.c

File preview with syntax highlighting.

linux-6.19.14/drivers/gpu/drm/panel/panel-ilitek-ili9322.c C
  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.h>
 26#include <linux/platform_device.h>
 27#include <linux/regmap.h>
 28#include <linux/regulator/consumer.h>
 29#include <linux/spi/spi.h>
 30
 31#include <video/mipi_display.h>
 32#include <video/of_videomode.h>
 33#include <video/videomode.h>
 34
 35#include <drm/drm_modes.h>
 36#include <drm/drm_panel.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 const 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_writeable_reg(struct device *dev, unsigned int reg)
329{
330	/* Just register 0 is read-only */
331	if (reg == 0x00)
332		return false;
333	return true;
334}
335
336static const struct regmap_config ili9322_regmap_config = {
337	.reg_bits = 8,
338	.val_bits = 8,
339	.max_register = 0x44,
340	.cache_type = REGCACHE_MAPLE,
341	.writeable_reg = ili9322_writeable_reg,
342};
343
344static int ili9322_init(struct drm_panel *panel, struct ili9322 *ili)
345{
346	u8 reg;
347	int ret;
348	int i;
349
350	/* Reset display */
351	ret = regmap_write(ili->regmap, ILI9322_GLOBAL_RESET,
352			   ILI9322_GLOBAL_RESET_ASSERT);
353	if (ret) {
354		dev_err(ili->dev, "can't issue GRESET (%d)\n", ret);
355		return ret;
356	}
357
358	/* Set up the main voltage regulator */
359	if (ili->vreg1out != U8_MAX) {
360		ret = regmap_write(ili->regmap, ILI9322_VREG1_VOLTAGE,
361				   ili->vreg1out);
362		if (ret) {
363			dev_err(ili->dev, "can't set up VREG1OUT (%d)\n", ret);
364			return ret;
365		}
366	}
367
368	if (ili->vcom_amplitude != U8_MAX) {
369		ret = regmap_write(ili->regmap, ILI9322_VCOM_AMP,
370				   ili->vcom_amplitude);
371		if (ret) {
372			dev_err(ili->dev,
373				"can't set up VCOM amplitude (%d)\n", ret);
374			return ret;
375		}
376	}
377
378	if (ili->vcom_high != U8_MAX) {
379		ret = regmap_write(ili->regmap, ILI9322_VCOM_HIGH,
380				   ili->vcom_high);
381		if (ret) {
382			dev_err(ili->dev, "can't set up VCOM high (%d)\n", ret);
383			return ret;
384		}
385	}
386
387	/* Set up gamma correction */
388	for (i = 0; i < ARRAY_SIZE(ili->gamma); i++) {
389		ret = regmap_write(ili->regmap, ILI9322_GAMMA_1 + i,
390				   ili->gamma[i]);
391		if (ret) {
392			dev_err(ili->dev,
393				"can't write gamma V%d to 0x%02x (%d)\n",
394				i + 1, ILI9322_GAMMA_1 + i, ret);
395			return ret;
396		}
397	}
398
399	/*
400	 * Polarity and inverted color order for RGB input.
401	 * None of this applies in the BT.656 mode.
402	 */
403	reg = 0;
404	if (ili->conf->dclk_active_high)
405		reg = ILI9322_POL_DCLK;
406	if (ili->conf->de_active_high)
407		reg |= ILI9322_POL_DE;
408	if (ili->conf->hsync_active_high)
409		reg |= ILI9322_POL_HSYNC;
410	if (ili->conf->vsync_active_high)
411		reg |= ILI9322_POL_VSYNC;
412	ret = regmap_write(ili->regmap, ILI9322_POL, reg);
413	if (ret) {
414		dev_err(ili->dev, "can't write POL register (%d)\n", ret);
415		return ret;
416	}
417
418	/*
419	 * Set up interface control.
420	 * This is not used in the BT.656 mode (no H/Vsync or DE signals).
421	 */
422	reg = ili->conf->syncmode;
423	reg |= ILI9322_IF_CTRL_LINE_INVERSION;
424	ret = regmap_write(ili->regmap, ILI9322_IF_CTRL, reg);
425	if (ret) {
426		dev_err(ili->dev, "can't write IF CTRL register (%d)\n", ret);
427		return ret;
428	}
429
430	/* Set up the input mode */
431	reg = (ili->input << 4);
432	/* These are inverted, setting to 1 is the default, clearing flips */
433	if (!ili->conf->flip_horizontal)
434		reg |= ILI9322_ENTRY_HDIR;
435	if (!ili->conf->flip_vertical)
436		reg |= ILI9322_ENTRY_VDIR;
437	reg |= ILI9322_ENTRY_AUTODETECT;
438	ret = regmap_write(ili->regmap, ILI9322_ENTRY, reg);
439	if (ret) {
440		dev_err(ili->dev, "can't write ENTRY reg (%d)\n", ret);
441		return ret;
442	}
443	dev_info(ili->dev, "display is in %s mode, syncmode %02x\n",
444		 ili9322_inputs[ili->input],
445		 ili->conf->syncmode);
446
447	dev_info(ili->dev, "initialized display\n");
448
449	return 0;
450}
451
452/*
453 * This power-on sequence if from the datasheet, page 57.
454 */
455static int ili9322_power_on(struct ili9322 *ili)
456{
457	int ret;
458
459	/* Assert RESET */
460	gpiod_set_value(ili->reset_gpio, 1);
461
462	ret = regulator_bulk_enable(ARRAY_SIZE(ili->supplies), ili->supplies);
463	if (ret < 0) {
464		dev_err(ili->dev, "unable to enable regulators\n");
465		return ret;
466	}
467	msleep(20);
468
469	/* De-assert RESET */
470	gpiod_set_value(ili->reset_gpio, 0);
471
472	msleep(10);
473
474	return 0;
475}
476
477static int ili9322_power_off(struct ili9322 *ili)
478{
479	return regulator_bulk_disable(ARRAY_SIZE(ili->supplies), ili->supplies);
480}
481
482static int ili9322_disable(struct drm_panel *panel)
483{
484	struct ili9322 *ili = panel_to_ili9322(panel);
485	int ret;
486
487	ret = regmap_write(ili->regmap, ILI9322_POW_CTRL,
488			   ILI9322_POW_CTRL_STANDBY);
489	if (ret) {
490		dev_err(ili->dev, "unable to go to standby mode\n");
491		return ret;
492	}
493
494	return 0;
495}
496
497static int ili9322_unprepare(struct drm_panel *panel)
498{
499	struct ili9322 *ili = panel_to_ili9322(panel);
500
501	return ili9322_power_off(ili);
502}
503
504static int ili9322_prepare(struct drm_panel *panel)
505{
506	struct ili9322 *ili = panel_to_ili9322(panel);
507	int ret;
508
509	ret = ili9322_power_on(ili);
510	if (ret < 0)
511		return ret;
512
513	ret = ili9322_init(panel, ili);
514	if (ret < 0)
515		ili9322_unprepare(panel);
516
517	return ret;
518}
519
520static int ili9322_enable(struct drm_panel *panel)
521{
522	struct ili9322 *ili = panel_to_ili9322(panel);
523	int ret;
524
525	ret = regmap_write(ili->regmap, ILI9322_POW_CTRL,
526			   ILI9322_POW_CTRL_DEFAULT);
527	if (ret) {
528		dev_err(ili->dev, "unable to enable panel\n");
529		return ret;
530	}
531
532	return 0;
533}
534
535/* Serial RGB modes */
536static const struct drm_display_mode srgb_320x240_mode = {
537	.clock = 24535,
538	.hdisplay = 320,
539	.hsync_start = 320 + 359,
540	.hsync_end = 320 + 359 + 1,
541	.htotal = 320 + 359 + 1 + 241,
542	.vdisplay = 240,
543	.vsync_start = 240 + 4,
544	.vsync_end = 240 + 4 + 1,
545	.vtotal = 262,
546	.flags = 0,
547};
548
549static const struct drm_display_mode srgb_360x240_mode = {
550	.clock = 27000,
551	.hdisplay = 360,
552	.hsync_start = 360 + 35,
553	.hsync_end = 360 + 35 + 1,
554	.htotal = 360 + 35 + 1 + 241,
555	.vdisplay = 240,
556	.vsync_start = 240 + 21,
557	.vsync_end = 240 + 21 + 1,
558	.vtotal = 262,
559	.flags = 0,
560};
561
562/* This is the only mode listed for parallel RGB in the datasheet */
563static const struct drm_display_mode prgb_320x240_mode = {
564	.clock = 64000,
565	.hdisplay = 320,
566	.hsync_start = 320 + 38,
567	.hsync_end = 320 + 38 + 1,
568	.htotal = 320 + 38 + 1 + 50,
569	.vdisplay = 240,
570	.vsync_start = 240 + 4,
571	.vsync_end = 240 + 4 + 1,
572	.vtotal = 262,
573	.flags = 0,
574};
575
576/* YUV modes */
577static const struct drm_display_mode yuv_640x320_mode = {
578	.clock = 24540,
579	.hdisplay = 640,
580	.hsync_start = 640 + 252,
581	.hsync_end = 640 + 252 + 1,
582	.htotal = 640 + 252 + 1 + 28,
583	.vdisplay = 320,
584	.vsync_start = 320 + 4,
585	.vsync_end = 320 + 4 + 1,
586	.vtotal = 320 + 4 + 1 + 18,
587	.flags = 0,
588};
589
590static const struct drm_display_mode yuv_720x360_mode = {
591	.clock = 27000,
592	.hdisplay = 720,
593	.hsync_start = 720 + 252,
594	.hsync_end = 720 + 252 + 1,
595	.htotal = 720 + 252 + 1 + 24,
596	.vdisplay = 360,
597	.vsync_start = 360 + 4,
598	.vsync_end = 360 + 4 + 1,
599	.vtotal = 360 + 4 + 1 + 18,
600	.flags = 0,
601};
602
603/* BT.656 VGA mode, 640x480 */
604static const struct drm_display_mode itu_r_bt_656_640_mode = {
605	.clock = 24540,
606	.hdisplay = 640,
607	.hsync_start = 640 + 3,
608	.hsync_end = 640 + 3 + 1,
609	.htotal = 640 + 3 + 1 + 272,
610	.vdisplay = 480,
611	.vsync_start = 480 + 4,
612	.vsync_end = 480 + 4 + 1,
613	.vtotal = 500,
614	.flags = 0,
615};
616
617/* BT.656 D1 mode 720x480 */
618static const struct drm_display_mode itu_r_bt_656_720_mode = {
619	.clock = 27000,
620	.hdisplay = 720,
621	.hsync_start = 720 + 3,
622	.hsync_end = 720 + 3 + 1,
623	.htotal = 720 + 3 + 1 + 272,
624	.vdisplay = 480,
625	.vsync_start = 480 + 4,
626	.vsync_end = 480 + 4 + 1,
627	.vtotal = 500,
628	.flags = 0,
629};
630
631static int ili9322_get_modes(struct drm_panel *panel,
632			     struct drm_connector *connector)
633{
634	struct ili9322 *ili = panel_to_ili9322(panel);
635	struct drm_device *drm = connector->dev;
636	struct drm_display_mode *mode;
637	struct drm_display_info *info;
638
639	info = &connector->display_info;
640	info->width_mm = ili->conf->width_mm;
641	info->height_mm = ili->conf->height_mm;
642	if (ili->conf->dclk_active_high)
643		info->bus_flags |= DRM_BUS_FLAG_PIXDATA_DRIVE_POSEDGE;
644	else
645		info->bus_flags |= DRM_BUS_FLAG_PIXDATA_DRIVE_NEGEDGE;
646
647	if (ili->conf->de_active_high)
648		info->bus_flags |= DRM_BUS_FLAG_DE_HIGH;
649	else
650		info->bus_flags |= DRM_BUS_FLAG_DE_LOW;
651
652	switch (ili->input) {
653	case ILI9322_INPUT_SRGB_DUMMY_320X240:
654		mode = drm_mode_duplicate(drm, &srgb_320x240_mode);
655		break;
656	case ILI9322_INPUT_SRGB_DUMMY_360X240:
657		mode = drm_mode_duplicate(drm, &srgb_360x240_mode);
658		break;
659	case ILI9322_INPUT_PRGB_THROUGH:
660	case ILI9322_INPUT_PRGB_ALIGNED:
661		mode = drm_mode_duplicate(drm, &prgb_320x240_mode);
662		break;
663	case ILI9322_INPUT_YUV_640X320_YCBCR:
664		mode = drm_mode_duplicate(drm, &yuv_640x320_mode);
665		break;
666	case ILI9322_INPUT_YUV_720X360_YCBCR:
667		mode = drm_mode_duplicate(drm, &yuv_720x360_mode);
668		break;
669	case ILI9322_INPUT_ITU_R_BT656_720X360_YCBCR:
670		mode = drm_mode_duplicate(drm, &itu_r_bt_656_720_mode);
671		break;
672	case ILI9322_INPUT_ITU_R_BT656_640X320_YCBCR:
673		mode = drm_mode_duplicate(drm, &itu_r_bt_656_640_mode);
674		break;
675	default:
676		mode = NULL;
677		break;
678	}
679	if (!mode) {
680		dev_err(panel->dev, "bad mode or failed to add mode\n");
681		return -EINVAL;
682	}
683	drm_mode_set_name(mode);
684	/*
685	 * This is the preferred mode because most people are going
686	 * to want to use the display with VGA type graphics.
687	 */
688	mode->type = DRM_MODE_TYPE_DRIVER | DRM_MODE_TYPE_PREFERRED;
689
690	/* Set up the polarity */
691	if (ili->conf->hsync_active_high)
692		mode->flags |= DRM_MODE_FLAG_PHSYNC;
693	else
694		mode->flags |= DRM_MODE_FLAG_NHSYNC;
695	if (ili->conf->vsync_active_high)
696		mode->flags |= DRM_MODE_FLAG_PVSYNC;
697	else
698		mode->flags |= DRM_MODE_FLAG_NVSYNC;
699
700	mode->width_mm = ili->conf->width_mm;
701	mode->height_mm = ili->conf->height_mm;
702	drm_mode_probed_add(connector, mode);
703
704	return 1; /* Number of modes */
705}
706
707static const struct drm_panel_funcs ili9322_drm_funcs = {
708	.disable = ili9322_disable,
709	.unprepare = ili9322_unprepare,
710	.prepare = ili9322_prepare,
711	.enable = ili9322_enable,
712	.get_modes = ili9322_get_modes,
713};
714
715static int ili9322_probe(struct spi_device *spi)
716{
717	struct device *dev = &spi->dev;
718	struct ili9322 *ili;
719	const struct regmap_config *regmap_config;
720	u8 gamma;
721	u32 val;
722	int ret;
723	int i;
724
725	ili = devm_drm_panel_alloc(dev, struct ili9322, panel,
726				   &ili9322_drm_funcs, DRM_MODE_CONNECTOR_DPI);
727	if (IS_ERR(ili))
728		return PTR_ERR(ili);
729
730	spi_set_drvdata(spi, ili);
731
732	ili->dev = dev;
733
734	/*
735	 * Every new incarnation of this display must have a unique
736	 * data entry for the system in this driver.
737	 */
738	ili->conf = of_device_get_match_data(dev);
739	if (!ili->conf) {
740		dev_err(dev, "missing device configuration\n");
741		return -ENODEV;
742	}
743
744	val = ili->conf->vreg1out_mv;
745	if (!val) {
746		/* Default HW value, do not touch (should be 4.5V) */
747		ili->vreg1out = U8_MAX;
748	} else {
749		if (val < 3600) {
750			dev_err(dev, "too low VREG1OUT\n");
751			return -EINVAL;
752		}
753		if (val > 6000) {
754			dev_err(dev, "too high VREG1OUT\n");
755			return -EINVAL;
756		}
757		if ((val % 100) != 0) {
758			dev_err(dev, "VREG1OUT is no even 100 microvolt\n");
759			return -EINVAL;
760		}
761		val -= 3600;
762		val /= 100;
763		dev_dbg(dev, "VREG1OUT = 0x%02x\n", val);
764		ili->vreg1out = val;
765	}
766
767	val = ili->conf->vcom_high_percent;
768	if (!val) {
769		/* Default HW value, do not touch (should be 91%) */
770		ili->vcom_high = U8_MAX;
771	} else {
772		if (val < 37) {
773			dev_err(dev, "too low VCOM high\n");
774			return -EINVAL;
775		}
776		if (val > 100) {
777			dev_err(dev, "too high VCOM high\n");
778			return -EINVAL;
779		}
780		val -= 37;
781		dev_dbg(dev, "VCOM high = 0x%02x\n", val);
782		ili->vcom_high = val;
783	}
784
785	val = ili->conf->vcom_amplitude_percent;
786	if (!val) {
787		/* Default HW value, do not touch (should be 114%) */
788		ili->vcom_high = U8_MAX;
789	} else {
790		if (val < 70) {
791			dev_err(dev, "too low VCOM amplitude\n");
792			return -EINVAL;
793		}
794		if (val > 132) {
795			dev_err(dev, "too high VCOM amplitude\n");
796			return -EINVAL;
797		}
798		val -= 70;
799		val >>= 1; /* Increments of 2% */
800		dev_dbg(dev, "VCOM amplitude = 0x%02x\n", val);
801		ili->vcom_amplitude = val;
802	}
803
804	for (i = 0; i < ARRAY_SIZE(ili->gamma); i++) {
805		val = ili->conf->gamma_corr_neg[i];
806		if (val > 15) {
807			dev_err(dev, "negative gamma %u > 15, capping\n", val);
808			val = 15;
809		}
810		gamma = val << 4;
811		val = ili->conf->gamma_corr_pos[i];
812		if (val > 15) {
813			dev_err(dev, "positive gamma %u > 15, capping\n", val);
814			val = 15;
815		}
816		gamma |= val;
817		ili->gamma[i] = gamma;
818		dev_dbg(dev, "gamma V%d: 0x%02x\n", i + 1, gamma);
819	}
820
821	ili->supplies[0].supply = "vcc"; /* 2.7-3.6 V */
822	ili->supplies[1].supply = "iovcc"; /* 1.65-3.6V */
823	ili->supplies[2].supply = "vci"; /* 2.7-3.6V */
824	ret = devm_regulator_bulk_get(dev, ARRAY_SIZE(ili->supplies),
825				      ili->supplies);
826	if (ret < 0)
827		return ret;
828	ret = regulator_set_voltage(ili->supplies[0].consumer,
829				    2700000, 3600000);
830	if (ret)
831		return ret;
832	ret = regulator_set_voltage(ili->supplies[1].consumer,
833				    1650000, 3600000);
834	if (ret)
835		return ret;
836	ret = regulator_set_voltage(ili->supplies[2].consumer,
837				    2700000, 3600000);
838	if (ret)
839		return ret;
840
841	ili->reset_gpio = devm_gpiod_get_optional(dev, "reset", GPIOD_OUT_HIGH);
842	if (IS_ERR(ili->reset_gpio)) {
843		dev_err(dev, "failed to get RESET GPIO\n");
844		return PTR_ERR(ili->reset_gpio);
845	}
846
847	spi->bits_per_word = 8;
848	ret = spi_setup(spi);
849	if (ret < 0) {
850		dev_err(dev, "spi setup failed.\n");
851		return ret;
852	}
853	regmap_config = &ili9322_regmap_config;
854	ili->regmap = devm_regmap_init(dev, &ili9322_regmap_bus, dev,
855				       regmap_config);
856	if (IS_ERR(ili->regmap)) {
857		dev_err(dev, "failed to allocate register map\n");
858		return PTR_ERR(ili->regmap);
859	}
860
861	ret = regmap_read(ili->regmap, ILI9322_CHIP_ID, &val);
862	if (ret) {
863		dev_err(dev, "can't get chip ID (%d)\n", ret);
864		return ret;
865	}
866	if (val != ILI9322_CHIP_ID_MAGIC) {
867		dev_err(dev, "chip ID 0x%0x2, expected 0x%02x\n", val,
868			ILI9322_CHIP_ID_MAGIC);
869		return -ENODEV;
870	}
871
872	/* Probe the system to find the display setting */
873	if (ili->conf->input == ILI9322_INPUT_UNKNOWN) {
874		ret = regmap_read(ili->regmap, ILI9322_ENTRY, &val);
875		if (ret) {
876			dev_err(dev, "can't get entry setting (%d)\n", ret);
877			return ret;
878		}
879		/* Input enum corresponds to HW setting */
880		ili->input = (val >> 4) & 0x0f;
881		if (ili->input >= ILI9322_INPUT_UNKNOWN)
882			ili->input = ILI9322_INPUT_UNKNOWN;
883	} else {
884		ili->input = ili->conf->input;
885	}
886
887	drm_panel_add(&ili->panel);
888
889	return 0;
890}
891
892static void ili9322_remove(struct spi_device *spi)
893{
894	struct ili9322 *ili = spi_get_drvdata(spi);
895
896	ili9322_power_off(ili);
897	drm_panel_remove(&ili->panel);
898}
899
900/*
901 * The D-Link DIR-685 panel is marked LM918A01-1A SY-B4-091116-E0199
902 */
903static const struct ili9322_config ili9322_dir_685 = {
904	.width_mm = 65,
905	.height_mm = 50,
906	.input = ILI9322_INPUT_ITU_R_BT656_640X320_YCBCR,
907	.vreg1out_mv = 4600,
908	.vcom_high_percent = 91,
909	.vcom_amplitude_percent = 114,
910	.syncmode = ILI9322_IF_CTRL_SYNC_DISABLED,
911	.dclk_active_high = true,
912	.gamma_corr_neg = { 0xa, 0x5, 0x7, 0x7, 0x7, 0x5, 0x1, 0x6 },
913	.gamma_corr_pos = { 0x7, 0x7, 0x3, 0x2, 0x3, 0x5, 0x7, 0x2 },
914};
915
916static const struct of_device_id ili9322_of_match[] = {
917	{
918		.compatible = "dlink,dir-685-panel",
919		.data = &ili9322_dir_685,
920	},
921	{
922		.compatible = "ilitek,ili9322",
923		.data = NULL,
924	},
925	{ }
926};
927MODULE_DEVICE_TABLE(of, ili9322_of_match);
928
929static struct spi_driver ili9322_driver = {
930	.probe = ili9322_probe,
931	.remove = ili9322_remove,
932	.driver = {
933		.name = "panel-ilitek-ili9322",
934		.of_match_table = ili9322_of_match,
935	},
936};
937module_spi_driver(ili9322_driver);
938
939MODULE_AUTHOR("Linus Walleij <linus.walleij@linaro.org>");
940MODULE_DESCRIPTION("ILI9322 LCD panel driver");
941MODULE_LICENSE("GPL v2");
~/ Read-only file preview.