1 // SPDX-License-Identifier: GPL-2.0-only
3 * Ilitek ILI9322 TFT LCD drm_panel driver.
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
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
18 * Copyright (C) 2017 Linus Walleij <linus.walleij@linaro.org>
19 * Derived from drivers/drm/gpu/panel/panel-samsung-ld9040.c
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>
30 #include <video/mipi_display.h>
31 #include <video/of_videomode.h>
32 #include <video/videomode.h>
34 #include <drm/drm_modes.h>
35 #include <drm/drm_panel.h>
36 #include <drm/drm_print.h>
38 #define ILI9322_CHIP_ID 0x00
39 #define ILI9322_CHIP_ID_MAGIC 0x96
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.
46 #define ILI9322_VCOM_AMP 0x01
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.
53 #define ILI9322_VCOM_HIGH 0x02
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.
60 #define ILI9322_VREG1_VOLTAGE 0x03
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)
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)
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 | \
101 #define ILI9322_POW_CTRL_DEFAULT (ILI9322_POW_CTRL_STANDBY | \
102 ILI9322_POW_CTRL_STB)
104 /* Vertical back porch bits 0..5 */
105 #define ILI9322_VBP 0x08
107 /* Horizontal back porch, 8 bits */
108 #define ILI9322_HBP 0x09
112 * 1 = positive polarity
113 * 0 = negative polarity
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 */
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
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)
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 */
139 #define ILI9322_GLOBAL_RESET 0x04
140 #define ILI9322_GLOBAL_RESET_ASSERT 0x00 /* bit 0 = 0 -> reset */
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
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
157 * enum ili9322_input - the format of the incoming signal to the panel
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
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,
180 static 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",
186 "24 bit parallel RGB through",
187 "24 bit parallel RGB aligned",
188 "24 bit YUV 640Y 320CbCr",
189 "24 bit YUV 720Y 360CbCr",
191 "8 bit ITU-R BT.656 720Y 360CbCr",
192 "8 bit ITU-R BT.656 640Y 320CbCr",
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
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
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
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:
243 * +----------------------------------------------------------->
244 * 0 16 48 96 160 208 240 255
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.
252 struct ili9322_config
{
255 bool flip_horizontal
;
257 enum ili9322_input input
;
259 u32 vcom_high_percent
;
260 u32 vcom_amplitude_percent
;
261 bool dclk_active_high
;
263 bool hsync_active_high
;
264 bool vsync_active_high
;
266 u8 gamma_corr_pos
[8];
267 u8 gamma_corr_neg
[8];
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
;
285 static inline struct ili9322
*panel_to_ili9322(struct drm_panel
*panel
)
287 return container_of(panel
, struct ili9322
, panel
);
290 static int ili9322_regmap_spi_write(void *context
, const void *data
,
293 struct device
*dev
= context
;
294 struct spi_device
*spi
= to_spi_device(dev
);
297 /* Clear bit 7 to write */
298 memcpy(buf
, data
, 2);
301 dev_dbg(dev
, "WRITE: %02x %02x\n", buf
[0], buf
[1]);
302 return spi_write_then_read(spi
, buf
, 2, NULL
, 0);
305 static int ili9322_regmap_spi_read(void *context
, const void *reg
,
306 size_t reg_size
, void *val
, size_t val_size
)
308 struct device
*dev
= context
;
309 struct spi_device
*spi
= to_spi_device(dev
);
312 /* Set bit 7 to 1 to read */
314 dev_dbg(dev
, "READ: %02x reg size = %zu, val size = %zu\n",
315 buf
[0], reg_size
, val_size
);
318 return spi_write_then_read(spi
, buf
, 1, val
, 1);
321 static 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
,
328 static bool ili9322_volatile_reg(struct device
*dev
, unsigned int reg
)
333 static bool ili9322_writeable_reg(struct device
*dev
, unsigned int reg
)
335 /* Just register 0 is read-only */
341 static const struct regmap_config ili9322_regmap_config
= {
344 .max_register
= 0x44,
345 .cache_type
= REGCACHE_RBTREE
,
346 .volatile_reg
= ili9322_volatile_reg
,
347 .writeable_reg
= ili9322_writeable_reg
,
350 static int ili9322_init(struct drm_panel
*panel
, struct ili9322
*ili
)
357 ret
= regmap_write(ili
->regmap
, ILI9322_GLOBAL_RESET
,
358 ILI9322_GLOBAL_RESET_ASSERT
);
360 dev_err(ili
->dev
, "can't issue GRESET (%d)\n", ret
);
364 /* Set up the main voltage regulator */
365 if (ili
->vreg1out
!= U8_MAX
) {
366 ret
= regmap_write(ili
->regmap
, ILI9322_VREG1_VOLTAGE
,
369 dev_err(ili
->dev
, "can't set up VREG1OUT (%d)\n", ret
);
374 if (ili
->vcom_amplitude
!= U8_MAX
) {
375 ret
= regmap_write(ili
->regmap
, ILI9322_VCOM_AMP
,
376 ili
->vcom_amplitude
);
379 "can't set up VCOM amplitude (%d)\n", ret
);
384 if (ili
->vcom_high
!= U8_MAX
) {
385 ret
= regmap_write(ili
->regmap
, ILI9322_VCOM_HIGH
,
388 dev_err(ili
->dev
, "can't set up VCOM high (%d)\n", ret
);
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
,
399 "can't write gamma V%d to 0x%02x (%d)\n",
400 i
+ 1, ILI9322_GAMMA_1
+ i
, ret
);
406 * Polarity and inverted color order for RGB input.
407 * None of this applies in the BT.656 mode.
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
);
420 dev_err(ili
->dev
, "can't write POL register (%d)\n", ret
);
425 * Set up interface control.
426 * This is not used in the BT.656 mode (no H/Vsync or DE signals).
428 reg
= ili
->conf
->syncmode
;
429 reg
|= ILI9322_IF_CTRL_LINE_INVERSION
;
430 ret
= regmap_write(ili
->regmap
, ILI9322_IF_CTRL
, reg
);
432 dev_err(ili
->dev
, "can't write IF CTRL register (%d)\n", ret
);
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
);
446 dev_err(ili
->dev
, "can't write ENTRY reg (%d)\n", ret
);
449 dev_info(ili
->dev
, "display is in %s mode, syncmode %02x\n",
450 ili9322_inputs
[ili
->input
],
451 ili
->conf
->syncmode
);
453 dev_info(ili
->dev
, "initialized display\n");
459 * This power-on sequence if from the datasheet, page 57.
461 static int ili9322_power_on(struct ili9322
*ili
)
466 gpiod_set_value(ili
->reset_gpio
, 1);
468 ret
= regulator_bulk_enable(ARRAY_SIZE(ili
->supplies
), ili
->supplies
);
470 dev_err(ili
->dev
, "unable to enable regulators\n");
475 /* De-assert RESET */
476 gpiod_set_value(ili
->reset_gpio
, 0);
483 static int ili9322_power_off(struct ili9322
*ili
)
485 return regulator_bulk_disable(ARRAY_SIZE(ili
->supplies
), ili
->supplies
);
488 static int ili9322_disable(struct drm_panel
*panel
)
490 struct ili9322
*ili
= panel_to_ili9322(panel
);
493 ret
= regmap_write(ili
->regmap
, ILI9322_POW_CTRL
,
494 ILI9322_POW_CTRL_STANDBY
);
496 dev_err(ili
->dev
, "unable to go to standby mode\n");
503 static int ili9322_unprepare(struct drm_panel
*panel
)
505 struct ili9322
*ili
= panel_to_ili9322(panel
);
507 return ili9322_power_off(ili
);
510 static int ili9322_prepare(struct drm_panel
*panel
)
512 struct ili9322
*ili
= panel_to_ili9322(panel
);
515 ret
= ili9322_power_on(ili
);
519 ret
= ili9322_init(panel
, ili
);
521 ili9322_unprepare(panel
);
526 static int ili9322_enable(struct drm_panel
*panel
)
528 struct ili9322
*ili
= panel_to_ili9322(panel
);
531 ret
= regmap_write(ili
->regmap
, ILI9322_POW_CTRL
,
532 ILI9322_POW_CTRL_DEFAULT
);
534 dev_err(ili
->dev
, "unable to enable panel\n");
541 /* Serial RGB modes */
542 static const struct drm_display_mode srgb_320x240_mode
= {
545 .hsync_start
= 320 + 359,
546 .hsync_end
= 320 + 359 + 1,
547 .htotal
= 320 + 359 + 1 + 241,
549 .vsync_start
= 240 + 4,
550 .vsync_end
= 240 + 4 + 1,
556 static const struct drm_display_mode srgb_360x240_mode
= {
559 .hsync_start
= 360 + 35,
560 .hsync_end
= 360 + 35 + 1,
561 .htotal
= 360 + 35 + 1 + 241,
563 .vsync_start
= 240 + 21,
564 .vsync_end
= 240 + 21 + 1,
570 /* This is the only mode listed for parallel RGB in the datasheet */
571 static const struct drm_display_mode prgb_320x240_mode
= {
574 .hsync_start
= 320 + 38,
575 .hsync_end
= 320 + 38 + 1,
576 .htotal
= 320 + 38 + 1 + 50,
578 .vsync_start
= 240 + 4,
579 .vsync_end
= 240 + 4 + 1,
586 static const struct drm_display_mode yuv_640x320_mode
= {
589 .hsync_start
= 640 + 252,
590 .hsync_end
= 640 + 252 + 1,
591 .htotal
= 640 + 252 + 1 + 28,
593 .vsync_start
= 320 + 4,
594 .vsync_end
= 320 + 4 + 1,
595 .vtotal
= 320 + 4 + 1 + 18,
600 static const struct drm_display_mode yuv_720x360_mode
= {
603 .hsync_start
= 720 + 252,
604 .hsync_end
= 720 + 252 + 1,
605 .htotal
= 720 + 252 + 1 + 24,
607 .vsync_start
= 360 + 4,
608 .vsync_end
= 360 + 4 + 1,
609 .vtotal
= 360 + 4 + 1 + 18,
614 /* BT.656 VGA mode, 640x480 */
615 static const struct drm_display_mode itu_r_bt_656_640_mode
= {
618 .hsync_start
= 640 + 3,
619 .hsync_end
= 640 + 3 + 1,
620 .htotal
= 640 + 3 + 1 + 272,
622 .vsync_start
= 480 + 4,
623 .vsync_end
= 480 + 4 + 1,
629 /* BT.656 D1 mode 720x480 */
630 static const struct drm_display_mode itu_r_bt_656_720_mode
= {
633 .hsync_start
= 720 + 3,
634 .hsync_end
= 720 + 3 + 1,
635 .htotal
= 720 + 3 + 1 + 272,
637 .vsync_start
= 480 + 4,
638 .vsync_end
= 480 + 4 + 1,
644 static int ili9322_get_modes(struct drm_panel
*panel
,
645 struct drm_connector
*connector
)
647 struct ili9322
*ili
= panel_to_ili9322(panel
);
648 struct drm_device
*drm
= connector
->dev
;
649 struct drm_display_mode
*mode
;
650 struct drm_display_info
*info
;
652 info
= &connector
->display_info
;
653 info
->width_mm
= ili
->conf
->width_mm
;
654 info
->height_mm
= ili
->conf
->height_mm
;
655 if (ili
->conf
->dclk_active_high
)
656 info
->bus_flags
|= DRM_BUS_FLAG_PIXDATA_DRIVE_POSEDGE
;
658 info
->bus_flags
|= DRM_BUS_FLAG_PIXDATA_DRIVE_NEGEDGE
;
660 if (ili
->conf
->de_active_high
)
661 info
->bus_flags
|= DRM_BUS_FLAG_DE_HIGH
;
663 info
->bus_flags
|= DRM_BUS_FLAG_DE_LOW
;
665 switch (ili
->input
) {
666 case ILI9322_INPUT_SRGB_DUMMY_320X240
:
667 mode
= drm_mode_duplicate(drm
, &srgb_320x240_mode
);
669 case ILI9322_INPUT_SRGB_DUMMY_360X240
:
670 mode
= drm_mode_duplicate(drm
, &srgb_360x240_mode
);
672 case ILI9322_INPUT_PRGB_THROUGH
:
673 case ILI9322_INPUT_PRGB_ALIGNED
:
674 mode
= drm_mode_duplicate(drm
, &prgb_320x240_mode
);
676 case ILI9322_INPUT_YUV_640X320_YCBCR
:
677 mode
= drm_mode_duplicate(drm
, &yuv_640x320_mode
);
679 case ILI9322_INPUT_YUV_720X360_YCBCR
:
680 mode
= drm_mode_duplicate(drm
, &yuv_720x360_mode
);
682 case ILI9322_INPUT_ITU_R_BT656_720X360_YCBCR
:
683 mode
= drm_mode_duplicate(drm
, &itu_r_bt_656_720_mode
);
685 case ILI9322_INPUT_ITU_R_BT656_640X320_YCBCR
:
686 mode
= drm_mode_duplicate(drm
, &itu_r_bt_656_640_mode
);
693 DRM_ERROR("bad mode or failed to add mode\n");
696 drm_mode_set_name(mode
);
698 * This is the preferred mode because most people are going
699 * to want to use the display with VGA type graphics.
701 mode
->type
= DRM_MODE_TYPE_DRIVER
| DRM_MODE_TYPE_PREFERRED
;
703 /* Set up the polarity */
704 if (ili
->conf
->hsync_active_high
)
705 mode
->flags
|= DRM_MODE_FLAG_PHSYNC
;
707 mode
->flags
|= DRM_MODE_FLAG_NHSYNC
;
708 if (ili
->conf
->vsync_active_high
)
709 mode
->flags
|= DRM_MODE_FLAG_PVSYNC
;
711 mode
->flags
|= DRM_MODE_FLAG_NVSYNC
;
713 mode
->width_mm
= ili
->conf
->width_mm
;
714 mode
->height_mm
= ili
->conf
->height_mm
;
715 drm_mode_probed_add(connector
, mode
);
717 return 1; /* Number of modes */
720 static const struct drm_panel_funcs ili9322_drm_funcs
= {
721 .disable
= ili9322_disable
,
722 .unprepare
= ili9322_unprepare
,
723 .prepare
= ili9322_prepare
,
724 .enable
= ili9322_enable
,
725 .get_modes
= ili9322_get_modes
,
728 static int ili9322_probe(struct spi_device
*spi
)
730 struct device
*dev
= &spi
->dev
;
732 const struct regmap_config
*regmap_config
;
738 ili
= devm_kzalloc(dev
, sizeof(struct ili9322
), GFP_KERNEL
);
742 spi_set_drvdata(spi
, ili
);
747 * Every new incarnation of this display must have a unique
748 * data entry for the system in this driver.
750 ili
->conf
= of_device_get_match_data(dev
);
752 dev_err(dev
, "missing device configuration\n");
756 val
= ili
->conf
->vreg1out_mv
;
758 /* Default HW value, do not touch (should be 4.5V) */
759 ili
->vreg1out
= U8_MAX
;
762 dev_err(dev
, "too low VREG1OUT\n");
766 dev_err(dev
, "too high VREG1OUT\n");
769 if ((val
% 100) != 0) {
770 dev_err(dev
, "VREG1OUT is no even 100 microvolt\n");
775 dev_dbg(dev
, "VREG1OUT = 0x%02x\n", val
);
779 val
= ili
->conf
->vcom_high_percent
;
781 /* Default HW value, do not touch (should be 91%) */
782 ili
->vcom_high
= U8_MAX
;
785 dev_err(dev
, "too low VCOM high\n");
789 dev_err(dev
, "too high VCOM high\n");
793 dev_dbg(dev
, "VCOM high = 0x%02x\n", val
);
794 ili
->vcom_high
= val
;
797 val
= ili
->conf
->vcom_amplitude_percent
;
799 /* Default HW value, do not touch (should be 114%) */
800 ili
->vcom_high
= U8_MAX
;
803 dev_err(dev
, "too low VCOM amplitude\n");
807 dev_err(dev
, "too high VCOM amplitude\n");
811 val
>>= 1; /* Increments of 2% */
812 dev_dbg(dev
, "VCOM amplitude = 0x%02x\n", val
);
813 ili
->vcom_amplitude
= val
;
816 for (i
= 0; i
< ARRAY_SIZE(ili
->gamma
); i
++) {
817 val
= ili
->conf
->gamma_corr_neg
[i
];
819 dev_err(dev
, "negative gamma %u > 15, capping\n", val
);
823 val
= ili
->conf
->gamma_corr_pos
[i
];
825 dev_err(dev
, "positive gamma %u > 15, capping\n", val
);
829 ili
->gamma
[i
] = gamma
;
830 dev_dbg(dev
, "gamma V%d: 0x%02x\n", i
+ 1, gamma
);
833 ili
->supplies
[0].supply
= "vcc"; /* 2.7-3.6 V */
834 ili
->supplies
[1].supply
= "iovcc"; /* 1.65-3.6V */
835 ili
->supplies
[2].supply
= "vci"; /* 2.7-3.6V */
836 ret
= devm_regulator_bulk_get(dev
, ARRAY_SIZE(ili
->supplies
),
840 ret
= regulator_set_voltage(ili
->supplies
[0].consumer
,
844 ret
= regulator_set_voltage(ili
->supplies
[1].consumer
,
848 ret
= regulator_set_voltage(ili
->supplies
[2].consumer
,
853 ili
->reset_gpio
= devm_gpiod_get_optional(dev
, "reset", GPIOD_OUT_HIGH
);
854 if (IS_ERR(ili
->reset_gpio
)) {
855 dev_err(dev
, "failed to get RESET GPIO\n");
856 return PTR_ERR(ili
->reset_gpio
);
859 spi
->bits_per_word
= 8;
860 ret
= spi_setup(spi
);
862 dev_err(dev
, "spi setup failed.\n");
865 regmap_config
= &ili9322_regmap_config
;
866 ili
->regmap
= devm_regmap_init(dev
, &ili9322_regmap_bus
, dev
,
868 if (IS_ERR(ili
->regmap
)) {
869 dev_err(dev
, "failed to allocate register map\n");
870 return PTR_ERR(ili
->regmap
);
873 ret
= regmap_read(ili
->regmap
, ILI9322_CHIP_ID
, &val
);
875 dev_err(dev
, "can't get chip ID (%d)\n", ret
);
878 if (val
!= ILI9322_CHIP_ID_MAGIC
) {
879 dev_err(dev
, "chip ID 0x%0x2, expected 0x%02x\n", val
,
880 ILI9322_CHIP_ID_MAGIC
);
884 /* Probe the system to find the display setting */
885 if (ili
->conf
->input
== ILI9322_INPUT_UNKNOWN
) {
886 ret
= regmap_read(ili
->regmap
, ILI9322_ENTRY
, &val
);
888 dev_err(dev
, "can't get entry setting (%d)\n", ret
);
891 /* Input enum corresponds to HW setting */
892 ili
->input
= (val
>> 4) & 0x0f;
893 if (ili
->input
>= ILI9322_INPUT_UNKNOWN
)
894 ili
->input
= ILI9322_INPUT_UNKNOWN
;
896 ili
->input
= ili
->conf
->input
;
899 drm_panel_init(&ili
->panel
, dev
, &ili9322_drm_funcs
,
900 DRM_MODE_CONNECTOR_DPI
);
902 return drm_panel_add(&ili
->panel
);
905 static int ili9322_remove(struct spi_device
*spi
)
907 struct ili9322
*ili
= spi_get_drvdata(spi
);
909 ili9322_power_off(ili
);
910 drm_panel_remove(&ili
->panel
);
916 * The D-Link DIR-685 panel is marked LM918A01-1A SY-B4-091116-E0199
918 static const struct ili9322_config ili9322_dir_685
= {
921 .input
= ILI9322_INPUT_ITU_R_BT656_640X320_YCBCR
,
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 },
931 static const struct of_device_id ili9322_of_match
[] = {
933 .compatible
= "dlink,dir-685-panel",
934 .data
= &ili9322_dir_685
,
937 .compatible
= "ilitek,ili9322",
942 MODULE_DEVICE_TABLE(of
, ili9322_of_match
);
944 static struct spi_driver ili9322_driver
= {
945 .probe
= ili9322_probe
,
946 .remove
= ili9322_remove
,
948 .name
= "panel-ilitek-ili9322",
949 .of_match_table
= ili9322_of_match
,
952 module_spi_driver(ili9322_driver
);
954 MODULE_AUTHOR("Linus Walleij <linus.walleij@linaro.org>");
955 MODULE_DESCRIPTION("ILI9322 LCD panel driver");
956 MODULE_LICENSE("GPL v2");