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