Linux Audio

Check our new training course

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