1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
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
45
46
47
48#define ILI9322_VCOM_AMP 0x01
49
50
51
52
53
54
55#define ILI9322_VCOM_HIGH 0x02
56
57
58
59
60
61
62#define ILI9322_VREG1_VOLTAGE 0x03
63
64
65#define ILI9322_ENTRY 0x06
66
67#define ILI9322_ENTRY_HDIR BIT(0)
68
69#define ILI9322_ENTRY_VDIR BIT(1)
70
71#define ILI9322_ENTRY_NTSC (0 << 2)
72#define ILI9322_ENTRY_PAL (1 << 2)
73#define ILI9322_ENTRY_AUTODETECT (3 << 2)
74
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
89#define ILI9322_POW_CTRL 0x07
90#define ILI9322_POW_CTRL_STB BIT(0)
91#define ILI9322_POW_CTRL_VGL BIT(1)
92#define ILI9322_POW_CTRL_VGH BIT(2)
93#define ILI9322_POW_CTRL_DDVDH BIT(3)
94#define ILI9322_POW_CTRL_VCOM BIT(4)
95#define ILI9322_POW_CTRL_VCL BIT(5)
96#define ILI9322_POW_CTRL_AUTO BIT(6)
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
107#define ILI9322_VBP 0x08
108
109
110#define ILI9322_HBP 0x09
111
112
113
114
115
116
117#define ILI9322_POL 0x0a
118#define ILI9322_POL_DCLK BIT(0)
119#define ILI9322_POL_HSYNC BIT(1)
120#define ILI9322_POL_VSYNC BIT(2)
121#define ILI9322_POL_DE BIT(3)
122
123
124
125
126
127
128#define ILI9322_POL_YCBCR_MODE BIT(4)
129
130#define ILI9322_POL_FORMULA BIT(5)
131
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)
140
141#define ILI9322_GLOBAL_RESET 0x04
142#define ILI9322_GLOBAL_RESET_ASSERT 0x00
143
144
145
146
147
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
160
161
162
163
164
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
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
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
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
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
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
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
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
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
410
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
441
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
452 reg = (ili->input << 4);
453
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
475
476static int ili9322_power_on(struct ili9322 *ili)
477{
478 int ret;
479
480
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
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
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
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
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
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
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
704
705
706 mode->type = DRM_MODE_TYPE_DRIVER | DRM_MODE_TYPE_PREFERRED;
707
708
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;
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
753
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
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
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
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;
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";
839 ili->supplies[1].supply = "iovcc";
840 ili->supplies[2].supply = "vci";
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
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
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
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");
963