1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22#include <linux/bitops.h>
23#include <linux/gpio/consumer.h>
24#include <linux/module.h>
25#include <linux/of_device.h>
26#include <linux/regmap.h>
27#include <linux/regulator/consumer.h>
28#include <linux/spi/spi.h>
29
30#include <video/mipi_display.h>
31#include <video/of_videomode.h>
32#include <video/videomode.h>
33
34#include <drm/drm_modes.h>
35#include <drm/drm_panel.h>
36
37#define ILI9322_CHIP_ID 0x00
38#define ILI9322_CHIP_ID_MAGIC 0x96
39
40
41
42
43
44
45#define ILI9322_VCOM_AMP 0x01
46
47
48
49
50
51
52#define ILI9322_VCOM_HIGH 0x02
53
54
55
56
57
58
59#define ILI9322_VREG1_VOLTAGE 0x03
60
61
62#define ILI9322_ENTRY 0x06
63
64#define ILI9322_ENTRY_HDIR BIT(0)
65
66#define ILI9322_ENTRY_VDIR BIT(1)
67
68#define ILI9322_ENTRY_NTSC (0 << 2)
69#define ILI9322_ENTRY_PAL (1 << 2)
70#define ILI9322_ENTRY_AUTODETECT (3 << 2)
71
72#define ILI9322_ENTRY_SERIAL_RGB_THROUGH (0 << 4)
73#define ILI9322_ENTRY_SERIAL_RGB_ALIGNED (1 << 4)
74#define ILI9322_ENTRY_SERIAL_RGB_DUMMY_320X240 (2 << 4)
75#define ILI9322_ENTRY_SERIAL_RGB_DUMMY_360X240 (3 << 4)
76#define ILI9322_ENTRY_DISABLE_1 (4 << 4)
77#define ILI9322_ENTRY_PARALLEL_RGB_THROUGH (5 << 4)
78#define ILI9322_ENTRY_PARALLEL_RGB_ALIGNED (6 << 4)
79#define ILI9322_ENTRY_YUV_640Y_320CBCR_25_54_MHZ (7 << 4)
80#define ILI9322_ENTRY_YUV_720Y_360CBCR_27_MHZ (8 << 4)
81#define ILI9322_ENTRY_DISABLE_2 (9 << 4)
82#define ILI9322_ENTRY_ITU_R_BT_656_720X360 (10 << 4)
83#define ILI9322_ENTRY_ITU_R_BT_656_640X320 (11 << 4)
84
85
86#define ILI9322_POW_CTRL 0x07
87#define ILI9322_POW_CTRL_STB BIT(0)
88#define ILI9322_POW_CTRL_VGL BIT(1)
89#define ILI9322_POW_CTRL_VGH BIT(2)
90#define ILI9322_POW_CTRL_DDVDH BIT(3)
91#define ILI9322_POW_CTRL_VCOM BIT(4)
92#define ILI9322_POW_CTRL_VCL BIT(5)
93#define ILI9322_POW_CTRL_AUTO BIT(6)
94#define ILI9322_POW_CTRL_STANDBY (ILI9322_POW_CTRL_VGL | \
95 ILI9322_POW_CTRL_VGH | \
96 ILI9322_POW_CTRL_DDVDH | \
97 ILI9322_POW_CTRL_VCL | \
98 ILI9322_POW_CTRL_AUTO | \
99 BIT(7))
100#define ILI9322_POW_CTRL_DEFAULT (ILI9322_POW_CTRL_STANDBY | \
101 ILI9322_POW_CTRL_STB)
102
103
104#define ILI9322_VBP 0x08
105
106
107#define ILI9322_HBP 0x09
108
109
110
111
112
113
114#define ILI9322_POL 0x0a
115#define ILI9322_POL_DCLK BIT(0)
116#define ILI9322_POL_HSYNC BIT(1)
117#define ILI9322_POL_VSYNC BIT(2)
118#define ILI9322_POL_DE BIT(3)
119
120
121
122
123
124
125#define ILI9322_POL_YCBCR_MODE BIT(4)
126
127#define ILI9322_POL_FORMULA BIT(5)
128
129#define ILI9322_POL_REV BIT(6)
130
131#define ILI9322_IF_CTRL 0x0b
132#define ILI9322_IF_CTRL_HSYNC_VSYNC 0x00
133#define ILI9322_IF_CTRL_HSYNC_VSYNC_DE BIT(2)
134#define ILI9322_IF_CTRL_DE_ONLY BIT(3)
135#define ILI9322_IF_CTRL_SYNC_DISABLED (BIT(2) | BIT(3))
136#define ILI9322_IF_CTRL_LINE_INVERSION BIT(0)
137
138#define ILI9322_GLOBAL_RESET 0x04
139#define ILI9322_GLOBAL_RESET_ASSERT 0x00
140
141
142
143
144
145
146#define ILI9322_GAMMA_1 0x10
147#define ILI9322_GAMMA_2 0x11
148#define ILI9322_GAMMA_3 0x12
149#define ILI9322_GAMMA_4 0x13
150#define ILI9322_GAMMA_5 0x14
151#define ILI9322_GAMMA_6 0x15
152#define ILI9322_GAMMA_7 0x16
153#define ILI9322_GAMMA_8 0x17
154
155
156
157
158
159
160
161
162
163enum ili9322_input {
164 ILI9322_INPUT_SRGB_THROUGH = 0x0,
165 ILI9322_INPUT_SRGB_ALIGNED = 0x1,
166 ILI9322_INPUT_SRGB_DUMMY_320X240 = 0x2,
167 ILI9322_INPUT_SRGB_DUMMY_360X240 = 0x3,
168 ILI9322_INPUT_DISABLED_1 = 0x4,
169 ILI9322_INPUT_PRGB_THROUGH = 0x5,
170 ILI9322_INPUT_PRGB_ALIGNED = 0x6,
171 ILI9322_INPUT_YUV_640X320_YCBCR = 0x7,
172 ILI9322_INPUT_YUV_720X360_YCBCR = 0x8,
173 ILI9322_INPUT_DISABLED_2 = 0x9,
174 ILI9322_INPUT_ITU_R_BT656_720X360_YCBCR = 0xa,
175 ILI9322_INPUT_ITU_R_BT656_640X320_YCBCR = 0xb,
176 ILI9322_INPUT_UNKNOWN = 0xc,
177};
178
179static const char * const ili9322_inputs[] = {
180 "8 bit serial RGB through",
181 "8 bit serial RGB aligned",
182 "8 bit serial RGB dummy 320x240",
183 "8 bit serial RGB dummy 360x240",
184 "disabled 1",
185 "24 bit parallel RGB through",
186 "24 bit parallel RGB aligned",
187 "24 bit YUV 640Y 320CbCr",
188 "24 bit YUV 720Y 360CbCr",
189 "disabled 2",
190 "8 bit ITU-R BT.656 720Y 360CbCr",
191 "8 bit ITU-R BT.656 640Y 320CbCr",
192};
193
194
195
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
251struct ili9322_config {
252 u32 width_mm;
253 u32 height_mm;
254 bool flip_horizontal;
255 bool flip_vertical;
256 enum ili9322_input input;
257 u32 vreg1out_mv;
258 u32 vcom_high_percent;
259 u32 vcom_amplitude_percent;
260 bool dclk_active_high;
261 bool de_active_high;
262 bool hsync_active_high;
263 bool vsync_active_high;
264 u8 syncmode;
265 u8 gamma_corr_pos[8];
266 u8 gamma_corr_neg[8];
267};
268
269struct ili9322 {
270 struct device *dev;
271 const struct ili9322_config *conf;
272 struct drm_panel panel;
273 struct regmap *regmap;
274 struct regulator_bulk_data supplies[3];
275 struct gpio_desc *reset_gpio;
276 enum ili9322_input input;
277 struct videomode vm;
278 u8 gamma[8];
279 u8 vreg1out;
280 u8 vcom_high;
281 u8 vcom_amplitude;
282};
283
284static inline struct ili9322 *panel_to_ili9322(struct drm_panel *panel)
285{
286 return container_of(panel, struct ili9322, panel);
287}
288
289static int ili9322_regmap_spi_write(void *context, const void *data,
290 size_t count)
291{
292 struct device *dev = context;
293 struct spi_device *spi = to_spi_device(dev);
294 u8 buf[2];
295
296
297 memcpy(buf, data, 2);
298 buf[0] &= ~0x80;
299
300 dev_dbg(dev, "WRITE: %02x %02x\n", buf[0], buf[1]);
301 return spi_write_then_read(spi, buf, 2, NULL, 0);
302}
303
304static int ili9322_regmap_spi_read(void *context, const void *reg,
305 size_t reg_size, void *val, size_t val_size)
306{
307 struct device *dev = context;
308 struct spi_device *spi = to_spi_device(dev);
309 u8 buf[1];
310
311
312 memcpy(buf, reg, 1);
313 dev_dbg(dev, "READ: %02x reg size = %zu, val size = %zu\n",
314 buf[0], reg_size, val_size);
315 buf[0] |= 0x80;
316
317 return spi_write_then_read(spi, buf, 1, val, 1);
318}
319
320static struct regmap_bus ili9322_regmap_bus = {
321 .write = ili9322_regmap_spi_write,
322 .read = ili9322_regmap_spi_read,
323 .reg_format_endian_default = REGMAP_ENDIAN_BIG,
324 .val_format_endian_default = REGMAP_ENDIAN_BIG,
325};
326
327static bool ili9322_volatile_reg(struct device *dev, unsigned int reg)
328{
329 return false;
330}
331
332static bool ili9322_writeable_reg(struct device *dev, unsigned int reg)
333{
334
335 if (reg == 0x00)
336 return false;
337 return true;
338}
339
340static const struct regmap_config ili9322_regmap_config = {
341 .reg_bits = 8,
342 .val_bits = 8,
343 .max_register = 0x44,
344 .cache_type = REGCACHE_RBTREE,
345 .volatile_reg = ili9322_volatile_reg,
346 .writeable_reg = ili9322_writeable_reg,
347};
348
349static int ili9322_init(struct drm_panel *panel, struct ili9322 *ili)
350{
351 u8 reg;
352 int ret;
353 int i;
354
355
356 ret = regmap_write(ili->regmap, ILI9322_GLOBAL_RESET,
357 ILI9322_GLOBAL_RESET_ASSERT);
358 if (ret) {
359 dev_err(ili->dev, "can't issue GRESET (%d)\n", ret);
360 return ret;
361 }
362
363
364 if (ili->vreg1out != U8_MAX) {
365 ret = regmap_write(ili->regmap, ILI9322_VREG1_VOLTAGE,
366 ili->vreg1out);
367 if (ret) {
368 dev_err(ili->dev, "can't set up VREG1OUT (%d)\n", ret);
369 return ret;
370 }
371 }
372
373 if (ili->vcom_amplitude != U8_MAX) {
374 ret = regmap_write(ili->regmap, ILI9322_VCOM_AMP,
375 ili->vcom_amplitude);
376 if (ret) {
377 dev_err(ili->dev,
378 "can't set up VCOM amplitude (%d)\n", ret);
379 return ret;
380 }
381 }
382
383 if (ili->vcom_high != U8_MAX) {
384 ret = regmap_write(ili->regmap, ILI9322_VCOM_HIGH,
385 ili->vcom_high);
386 if (ret) {
387 dev_err(ili->dev, "can't set up VCOM high (%d)\n", ret);
388 return ret;
389 }
390 }
391
392
393 for (i = 0; i < ARRAY_SIZE(ili->gamma); i++) {
394 ret = regmap_write(ili->regmap, ILI9322_GAMMA_1 + i,
395 ili->gamma[i]);
396 if (ret) {
397 dev_err(ili->dev,
398 "can't write gamma V%d to 0x%02x (%d)\n",
399 i + 1, ILI9322_GAMMA_1 + i, ret);
400 return ret;
401 }
402 }
403
404
405
406
407
408 reg = 0;
409 if (ili->conf->dclk_active_high)
410 reg = ILI9322_POL_DCLK;
411 if (ili->conf->de_active_high)
412 reg |= ILI9322_POL_DE;
413 if (ili->conf->hsync_active_high)
414 reg |= ILI9322_POL_HSYNC;
415 if (ili->conf->vsync_active_high)
416 reg |= ILI9322_POL_VSYNC;
417 ret = regmap_write(ili->regmap, ILI9322_POL, reg);
418 if (ret) {
419 dev_err(ili->dev, "can't write POL register (%d)\n", ret);
420 return ret;
421 }
422
423
424
425
426
427 reg = ili->conf->syncmode;
428 reg |= ILI9322_IF_CTRL_LINE_INVERSION;
429 ret = regmap_write(ili->regmap, ILI9322_IF_CTRL, reg);
430 if (ret) {
431 dev_err(ili->dev, "can't write IF CTRL register (%d)\n", ret);
432 return ret;
433 }
434
435
436 reg = (ili->input << 4);
437
438 if (!ili->conf->flip_horizontal)
439 reg |= ILI9322_ENTRY_HDIR;
440 if (!ili->conf->flip_vertical)
441 reg |= ILI9322_ENTRY_VDIR;
442 reg |= ILI9322_ENTRY_AUTODETECT;
443 ret = regmap_write(ili->regmap, ILI9322_ENTRY, reg);
444 if (ret) {
445 dev_err(ili->dev, "can't write ENTRY reg (%d)\n", ret);
446 return ret;
447 }
448 dev_info(ili->dev, "display is in %s mode, syncmode %02x\n",
449 ili9322_inputs[ili->input],
450 ili->conf->syncmode);
451
452 dev_info(ili->dev, "initialized display\n");
453
454 return 0;
455}
456
457
458
459
460static int ili9322_power_on(struct ili9322 *ili)
461{
462 int ret;
463
464
465 gpiod_set_value(ili->reset_gpio, 1);
466
467 ret = regulator_bulk_enable(ARRAY_SIZE(ili->supplies), ili->supplies);
468 if (ret < 0) {
469 dev_err(ili->dev, "unable to enable regulators\n");
470 return ret;
471 }
472 msleep(20);
473
474
475 gpiod_set_value(ili->reset_gpio, 0);
476
477 msleep(10);
478
479 return 0;
480}
481
482static int ili9322_power_off(struct ili9322 *ili)
483{
484 return regulator_bulk_disable(ARRAY_SIZE(ili->supplies), ili->supplies);
485}
486
487static int ili9322_disable(struct drm_panel *panel)
488{
489 struct ili9322 *ili = panel_to_ili9322(panel);
490 int ret;
491
492 ret = regmap_write(ili->regmap, ILI9322_POW_CTRL,
493 ILI9322_POW_CTRL_STANDBY);
494 if (ret) {
495 dev_err(ili->dev, "unable to go to standby mode\n");
496 return ret;
497 }
498
499 return 0;
500}
501
502static int ili9322_unprepare(struct drm_panel *panel)
503{
504 struct ili9322 *ili = panel_to_ili9322(panel);
505
506 return ili9322_power_off(ili);
507}
508
509static int ili9322_prepare(struct drm_panel *panel)
510{
511 struct ili9322 *ili = panel_to_ili9322(panel);
512 int ret;
513
514 ret = ili9322_power_on(ili);
515 if (ret < 0)
516 return ret;
517
518 ret = ili9322_init(panel, ili);
519 if (ret < 0)
520 ili9322_unprepare(panel);
521
522 return ret;
523}
524
525static int ili9322_enable(struct drm_panel *panel)
526{
527 struct ili9322 *ili = panel_to_ili9322(panel);
528 int ret;
529
530 ret = regmap_write(ili->regmap, ILI9322_POW_CTRL,
531 ILI9322_POW_CTRL_DEFAULT);
532 if (ret) {
533 dev_err(ili->dev, "unable to enable panel\n");
534 return ret;
535 }
536
537 return 0;
538}
539
540
541static const struct drm_display_mode srgb_320x240_mode = {
542 .clock = 24535,
543 .hdisplay = 320,
544 .hsync_start = 320 + 359,
545 .hsync_end = 320 + 359 + 1,
546 .htotal = 320 + 359 + 1 + 241,
547 .vdisplay = 240,
548 .vsync_start = 240 + 4,
549 .vsync_end = 240 + 4 + 1,
550 .vtotal = 262,
551 .flags = 0,
552};
553
554static const struct drm_display_mode srgb_360x240_mode = {
555 .clock = 27000,
556 .hdisplay = 360,
557 .hsync_start = 360 + 35,
558 .hsync_end = 360 + 35 + 1,
559 .htotal = 360 + 35 + 1 + 241,
560 .vdisplay = 240,
561 .vsync_start = 240 + 21,
562 .vsync_end = 240 + 21 + 1,
563 .vtotal = 262,
564 .flags = 0,
565};
566
567
568static const struct drm_display_mode prgb_320x240_mode = {
569 .clock = 64000,
570 .hdisplay = 320,
571 .hsync_start = 320 + 38,
572 .hsync_end = 320 + 38 + 1,
573 .htotal = 320 + 38 + 1 + 50,
574 .vdisplay = 240,
575 .vsync_start = 240 + 4,
576 .vsync_end = 240 + 4 + 1,
577 .vtotal = 262,
578 .flags = 0,
579};
580
581
582static const struct drm_display_mode yuv_640x320_mode = {
583 .clock = 24540,
584 .hdisplay = 640,
585 .hsync_start = 640 + 252,
586 .hsync_end = 640 + 252 + 1,
587 .htotal = 640 + 252 + 1 + 28,
588 .vdisplay = 320,
589 .vsync_start = 320 + 4,
590 .vsync_end = 320 + 4 + 1,
591 .vtotal = 320 + 4 + 1 + 18,
592 .flags = 0,
593};
594
595static const struct drm_display_mode yuv_720x360_mode = {
596 .clock = 27000,
597 .hdisplay = 720,
598 .hsync_start = 720 + 252,
599 .hsync_end = 720 + 252 + 1,
600 .htotal = 720 + 252 + 1 + 24,
601 .vdisplay = 360,
602 .vsync_start = 360 + 4,
603 .vsync_end = 360 + 4 + 1,
604 .vtotal = 360 + 4 + 1 + 18,
605 .flags = 0,
606};
607
608
609static const struct drm_display_mode itu_r_bt_656_640_mode = {
610 .clock = 24540,
611 .hdisplay = 640,
612 .hsync_start = 640 + 3,
613 .hsync_end = 640 + 3 + 1,
614 .htotal = 640 + 3 + 1 + 272,
615 .vdisplay = 480,
616 .vsync_start = 480 + 4,
617 .vsync_end = 480 + 4 + 1,
618 .vtotal = 500,
619 .flags = 0,
620};
621
622
623static const struct drm_display_mode itu_r_bt_656_720_mode = {
624 .clock = 27000,
625 .hdisplay = 720,
626 .hsync_start = 720 + 3,
627 .hsync_end = 720 + 3 + 1,
628 .htotal = 720 + 3 + 1 + 272,
629 .vdisplay = 480,
630 .vsync_start = 480 + 4,
631 .vsync_end = 480 + 4 + 1,
632 .vtotal = 500,
633 .flags = 0,
634};
635
636static int ili9322_get_modes(struct drm_panel *panel,
637 struct drm_connector *connector)
638{
639 struct ili9322 *ili = panel_to_ili9322(panel);
640 struct drm_device *drm = connector->dev;
641 struct drm_display_mode *mode;
642 struct drm_display_info *info;
643
644 info = &connector->display_info;
645 info->width_mm = ili->conf->width_mm;
646 info->height_mm = ili->conf->height_mm;
647 if (ili->conf->dclk_active_high)
648 info->bus_flags |= DRM_BUS_FLAG_PIXDATA_DRIVE_POSEDGE;
649 else
650 info->bus_flags |= DRM_BUS_FLAG_PIXDATA_DRIVE_NEGEDGE;
651
652 if (ili->conf->de_active_high)
653 info->bus_flags |= DRM_BUS_FLAG_DE_HIGH;
654 else
655 info->bus_flags |= DRM_BUS_FLAG_DE_LOW;
656
657 switch (ili->input) {
658 case ILI9322_INPUT_SRGB_DUMMY_320X240:
659 mode = drm_mode_duplicate(drm, &srgb_320x240_mode);
660 break;
661 case ILI9322_INPUT_SRGB_DUMMY_360X240:
662 mode = drm_mode_duplicate(drm, &srgb_360x240_mode);
663 break;
664 case ILI9322_INPUT_PRGB_THROUGH:
665 case ILI9322_INPUT_PRGB_ALIGNED:
666 mode = drm_mode_duplicate(drm, &prgb_320x240_mode);
667 break;
668 case ILI9322_INPUT_YUV_640X320_YCBCR:
669 mode = drm_mode_duplicate(drm, &yuv_640x320_mode);
670 break;
671 case ILI9322_INPUT_YUV_720X360_YCBCR:
672 mode = drm_mode_duplicate(drm, &yuv_720x360_mode);
673 break;
674 case ILI9322_INPUT_ITU_R_BT656_720X360_YCBCR:
675 mode = drm_mode_duplicate(drm, &itu_r_bt_656_720_mode);
676 break;
677 case ILI9322_INPUT_ITU_R_BT656_640X320_YCBCR:
678 mode = drm_mode_duplicate(drm, &itu_r_bt_656_640_mode);
679 break;
680 default:
681 mode = NULL;
682 break;
683 }
684 if (!mode) {
685 dev_err(panel->dev, "bad mode or failed to add mode\n");
686 return -EINVAL;
687 }
688 drm_mode_set_name(mode);
689
690
691
692
693 mode->type = DRM_MODE_TYPE_DRIVER | DRM_MODE_TYPE_PREFERRED;
694
695
696 if (ili->conf->hsync_active_high)
697 mode->flags |= DRM_MODE_FLAG_PHSYNC;
698 else
699 mode->flags |= DRM_MODE_FLAG_NHSYNC;
700 if (ili->conf->vsync_active_high)
701 mode->flags |= DRM_MODE_FLAG_PVSYNC;
702 else
703 mode->flags |= DRM_MODE_FLAG_NVSYNC;
704
705 mode->width_mm = ili->conf->width_mm;
706 mode->height_mm = ili->conf->height_mm;
707 drm_mode_probed_add(connector, mode);
708
709 return 1;
710}
711
712static const struct drm_panel_funcs ili9322_drm_funcs = {
713 .disable = ili9322_disable,
714 .unprepare = ili9322_unprepare,
715 .prepare = ili9322_prepare,
716 .enable = ili9322_enable,
717 .get_modes = ili9322_get_modes,
718};
719
720static int ili9322_probe(struct spi_device *spi)
721{
722 struct device *dev = &spi->dev;
723 struct ili9322 *ili;
724 const struct regmap_config *regmap_config;
725 u8 gamma;
726 u32 val;
727 int ret;
728 int i;
729
730 ili = devm_kzalloc(dev, sizeof(struct ili9322), GFP_KERNEL);
731 if (!ili)
732 return -ENOMEM;
733
734 spi_set_drvdata(spi, ili);
735
736 ili->dev = dev;
737
738
739
740
741
742 ili->conf = of_device_get_match_data(dev);
743 if (!ili->conf) {
744 dev_err(dev, "missing device configuration\n");
745 return -ENODEV;
746 }
747
748 val = ili->conf->vreg1out_mv;
749 if (!val) {
750
751 ili->vreg1out = U8_MAX;
752 } else {
753 if (val < 3600) {
754 dev_err(dev, "too low VREG1OUT\n");
755 return -EINVAL;
756 }
757 if (val > 6000) {
758 dev_err(dev, "too high VREG1OUT\n");
759 return -EINVAL;
760 }
761 if ((val % 100) != 0) {
762 dev_err(dev, "VREG1OUT is no even 100 microvolt\n");
763 return -EINVAL;
764 }
765 val -= 3600;
766 val /= 100;
767 dev_dbg(dev, "VREG1OUT = 0x%02x\n", val);
768 ili->vreg1out = val;
769 }
770
771 val = ili->conf->vcom_high_percent;
772 if (!val) {
773
774 ili->vcom_high = U8_MAX;
775 } else {
776 if (val < 37) {
777 dev_err(dev, "too low VCOM high\n");
778 return -EINVAL;
779 }
780 if (val > 100) {
781 dev_err(dev, "too high VCOM high\n");
782 return -EINVAL;
783 }
784 val -= 37;
785 dev_dbg(dev, "VCOM high = 0x%02x\n", val);
786 ili->vcom_high = val;
787 }
788
789 val = ili->conf->vcom_amplitude_percent;
790 if (!val) {
791
792 ili->vcom_high = U8_MAX;
793 } else {
794 if (val < 70) {
795 dev_err(dev, "too low VCOM amplitude\n");
796 return -EINVAL;
797 }
798 if (val > 132) {
799 dev_err(dev, "too high VCOM amplitude\n");
800 return -EINVAL;
801 }
802 val -= 70;
803 val >>= 1;
804 dev_dbg(dev, "VCOM amplitude = 0x%02x\n", val);
805 ili->vcom_amplitude = val;
806 }
807
808 for (i = 0; i < ARRAY_SIZE(ili->gamma); i++) {
809 val = ili->conf->gamma_corr_neg[i];
810 if (val > 15) {
811 dev_err(dev, "negative gamma %u > 15, capping\n", val);
812 val = 15;
813 }
814 gamma = val << 4;
815 val = ili->conf->gamma_corr_pos[i];
816 if (val > 15) {
817 dev_err(dev, "positive gamma %u > 15, capping\n", val);
818 val = 15;
819 }
820 gamma |= val;
821 ili->gamma[i] = gamma;
822 dev_dbg(dev, "gamma V%d: 0x%02x\n", i + 1, gamma);
823 }
824
825 ili->supplies[0].supply = "vcc";
826 ili->supplies[1].supply = "iovcc";
827 ili->supplies[2].supply = "vci";
828 ret = devm_regulator_bulk_get(dev, ARRAY_SIZE(ili->supplies),
829 ili->supplies);
830 if (ret < 0)
831 return ret;
832 ret = regulator_set_voltage(ili->supplies[0].consumer,
833 2700000, 3600000);
834 if (ret)
835 return ret;
836 ret = regulator_set_voltage(ili->supplies[1].consumer,
837 1650000, 3600000);
838 if (ret)
839 return ret;
840 ret = regulator_set_voltage(ili->supplies[2].consumer,
841 2700000, 3600000);
842 if (ret)
843 return ret;
844
845 ili->reset_gpio = devm_gpiod_get_optional(dev, "reset", GPIOD_OUT_HIGH);
846 if (IS_ERR(ili->reset_gpio)) {
847 dev_err(dev, "failed to get RESET GPIO\n");
848 return PTR_ERR(ili->reset_gpio);
849 }
850
851 spi->bits_per_word = 8;
852 ret = spi_setup(spi);
853 if (ret < 0) {
854 dev_err(dev, "spi setup failed.\n");
855 return ret;
856 }
857 regmap_config = &ili9322_regmap_config;
858 ili->regmap = devm_regmap_init(dev, &ili9322_regmap_bus, dev,
859 regmap_config);
860 if (IS_ERR(ili->regmap)) {
861 dev_err(dev, "failed to allocate register map\n");
862 return PTR_ERR(ili->regmap);
863 }
864
865 ret = regmap_read(ili->regmap, ILI9322_CHIP_ID, &val);
866 if (ret) {
867 dev_err(dev, "can't get chip ID (%d)\n", ret);
868 return ret;
869 }
870 if (val != ILI9322_CHIP_ID_MAGIC) {
871 dev_err(dev, "chip ID 0x%0x2, expected 0x%02x\n", val,
872 ILI9322_CHIP_ID_MAGIC);
873 return -ENODEV;
874 }
875
876
877 if (ili->conf->input == ILI9322_INPUT_UNKNOWN) {
878 ret = regmap_read(ili->regmap, ILI9322_ENTRY, &val);
879 if (ret) {
880 dev_err(dev, "can't get entry setting (%d)\n", ret);
881 return ret;
882 }
883
884 ili->input = (val >> 4) & 0x0f;
885 if (ili->input >= ILI9322_INPUT_UNKNOWN)
886 ili->input = ILI9322_INPUT_UNKNOWN;
887 } else {
888 ili->input = ili->conf->input;
889 }
890
891 drm_panel_init(&ili->panel, dev, &ili9322_drm_funcs,
892 DRM_MODE_CONNECTOR_DPI);
893
894 drm_panel_add(&ili->panel);
895
896 return 0;
897}
898
899static int ili9322_remove(struct spi_device *spi)
900{
901 struct ili9322 *ili = spi_get_drvdata(spi);
902
903 ili9322_power_off(ili);
904 drm_panel_remove(&ili->panel);
905
906 return 0;
907}
908
909
910
911
912static const struct ili9322_config ili9322_dir_685 = {
913 .width_mm = 65,
914 .height_mm = 50,
915 .input = ILI9322_INPUT_ITU_R_BT656_640X320_YCBCR,
916 .vreg1out_mv = 4600,
917 .vcom_high_percent = 91,
918 .vcom_amplitude_percent = 114,
919 .syncmode = ILI9322_IF_CTRL_SYNC_DISABLED,
920 .dclk_active_high = true,
921 .gamma_corr_neg = { 0xa, 0x5, 0x7, 0x7, 0x7, 0x5, 0x1, 0x6 },
922 .gamma_corr_pos = { 0x7, 0x7, 0x3, 0x2, 0x3, 0x5, 0x7, 0x2 },
923};
924
925static const struct of_device_id ili9322_of_match[] = {
926 {
927 .compatible = "dlink,dir-685-panel",
928 .data = &ili9322_dir_685,
929 },
930 {
931 .compatible = "ilitek,ili9322",
932 .data = NULL,
933 },
934 { }
935};
936MODULE_DEVICE_TABLE(of, ili9322_of_match);
937
938static struct spi_driver ili9322_driver = {
939 .probe = ili9322_probe,
940 .remove = ili9322_remove,
941 .driver = {
942 .name = "panel-ilitek-ili9322",
943 .of_match_table = ili9322_of_match,
944 },
945};
946module_spi_driver(ili9322_driver);
947
948MODULE_AUTHOR("Linus Walleij <linus.walleij@linaro.org>");
949MODULE_DESCRIPTION("ILI9322 LCD panel driver");
950MODULE_LICENSE("GPL v2");
951