• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2022 Unionman Technology Co., Ltd.
3  *
4  * This program is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU General Public License
6  * as published by the Free Software Foundation; either version 2
7  * of the License, or (at your option) any later version.
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program; if not, write to the Free Software
16  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
17  */
18 
19 #include <linux/debugfs.h>
20 #include <linux/delay.h>
21 #include <linux/gpio/consumer.h>
22 #include <linux/media-bus-format.h>
23 #include <linux/mod_devicetable.h>
24 #include <linux/module.h>
25 #include <linux/of_device.h>
26 #include <linux/regulator/consumer.h>
27 
28 #include <video/display_timing.h>
29 #include <video/mipi_display.h>
30 
31 #include <drm/drm_mipi_dsi.h>
32 #include <drm/drm_modes.h>
33 #include <drm/drm_panel.h>
34 
35 #include <linux/backlight.h>
36 #include <linux/device/class.h>
37 
38 #define DRV_NAME "panel-chipone-icn6211"
39 
40 struct icn6211 {
41     struct device *dev;
42     struct drm_panel panel;
43     struct gpio_desc *reset_gpio;
44     bool prepared;
45     bool enabled;
46     const struct icn6211_panel_desc *desc;
47 };
48 
49 struct icn6211_panel_desc {
50     const struct drm_display_mode *mode;
51     unsigned int lanes;
52     unsigned long mode_flags;
53     enum mipi_dsi_pixel_format format;
54     int (*init_sequence)(struct icn6211 *ctx);
55 };
56 
57 /* I2C registers. */
58 #define REG_ID 0x80
59 #define REG_PORTA 0x81
60 #define REG_PORTA_HF BIT(2)
61 #define REG_PORTA_VF BIT(3)
62 #define REG_PORTB 0x82
63 #define REG_POWERON 0x85
64 #define REG_PWM 0x86
65 
66 #define HACTIVE_LI 0x20
67 #define VACTIVE_LI 0x21
68 #define VACTIVE_HACTIVE_HI 0x22
69 #define HFP_LI 0x23
70 #define HSYNC_LI 0x24
71 #define HBP_LI 0x25
72 #define HFP_HSW_HBP_HI 0x26
73 #define VFP 0x27
74 #define VSYNC 0x28
75 #define VBP 0x29
76 
77 /* DSI D-PHY Layer Registers */
78 #define D0W_DPHYCONTTX 0x0004
79 #define CLW_DPHYCONTRX 0x0020
80 #define D0W_DPHYCONTRX 0x0024
81 #define D1W_DPHYCONTRX 0x0028
82 #define COM_DPHYCONTRX 0x0038
83 #define CLW_CNTRL 0x0040
84 #define D0W_CNTRL 0x0044
85 #define D1W_CNTRL 0x0048
86 #define DFTMODE_CNTRL 0x0054
87 
88 /* DSI PPI Layer Registers */
89 #define PPI_STARTPPI 0x0104
90 #define PPI_BUSYPPI 0x0108
91 #define PPI_LINEINITCNT 0x0110
92 #define PPI_LPTXTIMECNT 0x0114
93 #define PPI_CLS_ATMR 0x0140
94 #define PPI_D0S_ATMR 0x0144
95 #define PPI_D1S_ATMR 0x0148
96 #define PPI_D0S_CLRSIPOCOUNT 0x0164
97 #define PPI_D1S_CLRSIPOCOUNT 0x0168
98 #define CLS_PRE 0x0180
99 #define D0S_PRE 0x0184
100 #define D1S_PRE 0x0188
101 #define CLS_PREP 0x01A0
102 #define D0S_PREP 0x01A4
103 #define D1S_PREP 0x01A8
104 #define CLS_ZERO 0x01C0
105 #define D0S_ZERO 0x01C4
106 #define D1S_ZERO 0x01C8
107 #define PPI_CLRFLG 0x01E0
108 #define PPI_CLRSIPO 0x01E4
109 #define HSTIMEOUT 0x01F0
110 #define HSTIMEOUTENABLE 0x01F4
111 
112 /* DSI Protocol Layer Registers */
113 #define DSI_STARTDSI 0x0204
114 #define DSI_BUSYDSI 0x0208
115 #define DSI_LANEENABLE 0x0210
116 #define DSI_LANEENABLE_CLOCK BIT(0)
117 #define DSI_LANEENABLE_D0 BIT(1)
118 #define DSI_LANEENABLE_D1 BIT(2)
119 
120 #define DSI_LANESTATUS0 0x0214
121 #define DSI_LANESTATUS1 0x0218
122 #define DSI_INTSTATUS 0x0220
123 #define DSI_INTMASK 0x0224
124 #define DSI_INTCLR 0x0228
125 #define DSI_LPTXTO 0x0230
126 #define DSI_MODE 0x0260
127 #define DSI_PAYLOAD0 0x0268
128 #define DSI_PAYLOAD1 0x026C
129 #define DSI_SHORTPKTDAT 0x0270
130 #define DSI_SHORTPKTREQ 0x0274
131 #define DSI_BTASTA 0x0278
132 #define DSI_BTACLR 0x027C
133 
134 /* DSI General Registers */
135 #define DSIERRCNT 0x0300
136 #define DSISIGMOD 0x0304
137 
138 /* DSI Application Layer Registers */
139 #define APLCTRL 0x0400
140 #define APLSTAT 0x0404
141 #define APLERR 0x0408
142 #define PWRMOD 0x040C
143 #define RDPKTLN 0x0410
144 #define PXLFMT 0x0414
145 #define MEMWRCMD 0x0418
146 
147 /* LCDC/DPI Host Registers */
148 #define LCDCTRL 0x0420
149 #define HSR 0x0424
150 #define HDISPR 0x0428
151 #define VSR 0x042C
152 #define VDISPR 0x0430
153 #define VFUEN 0x0434
154 
155 /* DBI-B Host Registers */
156 #define DBIBCTRL 0x0440
157 
158 /* SPI Master Registers */
159 #define SPICMR 0x0450
160 #define SPITCR 0x0454
161 
162 /* System Controller Registers */
163 #define SYSSTAT 0x0460
164 #define SYSCTRL 0x0464
165 #define SYSPLL1 0x0468
166 #define SYSPLL2 0x046C
167 #define SYSPLL3 0x0470
168 #define SYSPMCTRL 0x047C
169 
170 #define BRIGHTNESS_DEVICE_NAME "icn6211"
171 #define BRIGHTNESS_CLASS_NAME "brightness"
172 
173 #define ICN6211_DSI(dsi, seq...)                                                                                       \
174     do {                                                                                                               \
175         const u8 d[] = {seq};                                                                                          \
176         mipi_dsi_generic_write(dsi, d, ARRAY_SIZE(d));                                                                 \
177     }while (0)
178 
179 struct panel_icn6211_i2c {
180     int brightness;
181     struct i2c_client *i2c;
182 };
183 
184 static struct panel_icn6211_i2c *icn6211_i2c = NULL;
185 static bool panel_icn6211_enable = false;
186 
panel_icn6211_i2c_read(struct panel_icn6211_i2c * ts,u8 reg)187 static int panel_icn6211_i2c_read(struct panel_icn6211_i2c *ts, u8 reg)
188 {
189     return i2c_smbus_read_byte_data(ts->i2c, reg);
190 }
191 
panel_icn6211_i2c_write(struct panel_icn6211_i2c * ts,u8 reg,u8 val)192 static void panel_icn6211_i2c_write(struct panel_icn6211_i2c *ts, u8 reg, u8 val)
193 {
194     int ret;
195 
196     ret = i2c_smbus_write_byte_data(ts->i2c, reg, val);
197     if (ret)
198         dev_err(&ts->i2c->dev, "I2C write failed: %d\n", ret);
199 }
200 
panel_icn6211_dsi_write(struct mipi_dsi_device * dsi,u16 reg,u32 val)201 static int panel_icn6211_dsi_write(struct mipi_dsi_device *dsi, u16 reg, u32 val)
202 {
203     u8 msg[] = {
204         reg, reg >> 8L, val, val >> 8L, val >> 16L, val >> 24L,
205     };
206 
207     mipi_dsi_generic_write(dsi, msg, sizeof(msg));
208 
209     return 0;
210 }
211 
panel_to_icn6211(struct drm_panel * panel)212 static inline struct icn6211 *panel_to_icn6211(struct drm_panel *panel)
213 {
214     return container_of(panel, struct icn6211, panel);
215 }
216 
217 static const struct drm_display_mode icn6211_mode = {
218     .clock = 28344600L / 1000L,
219     .hdisplay = 800L,
220     .hsync_start = 800L + 16L,
221     .hsync_end = 800L + 16L + 1,
222     .htotal = 800L + 16L + 1 + 88L,
223     .vdisplay = 480L,
224     .vsync_start = 480L + 7L,
225     .vsync_end = 480L + 7L + 3L,
226     .vtotal = 480L + 7L + 3L + 32L,
227     .width_mm = 105L,
228     .height_mm = 67L,
229 };
230 
231 struct icn6211_panel_desc icn6211_panel_desc = {
232     .mode = &icn6211_mode,
233     .lanes = 1,
234     .mode_flags = (MIPI_DSI_MODE_VIDEO | MIPI_DSI_MODE_VIDEO_BURST | MIPI_DSI_MODE_LPM),
235     .format = MIPI_DSI_FMT_RGB888,
236 };
237 
icn6211_enable(struct drm_panel * panel)238 static int icn6211_enable(struct drm_panel *panel)
239 {
240     struct icn6211 *ctx = panel_to_icn6211(panel);
241     struct mipi_dsi_device *dsi = to_mipi_dsi_device(ctx->dev);
242     int i;
243 
244     if (!panel_icn6211_enable) {
245         return -1;
246     }
247 
248     if (ctx->enabled) {
249         dev_info(ctx->dev, "panel enabled\n");
250         return 0;
251     }
252 
253     dev_info(ctx->dev, "panel enable\n");
254 
255     panel_icn6211_i2c_write(icn6211_i2c, REG_POWERON, 1);
256 
257     /* Wait for nPWRDWN to go low to indicate poweron is done. */
258     for (i = 0; i < 100L; i++) {
259         if (panel_icn6211_i2c_read(icn6211_i2c, REG_PORTB) & 1)
260             break;
261     }
262 
263     panel_icn6211_dsi_write(dsi, DSI_LANEENABLE, DSI_LANEENABLE_CLOCK | DSI_LANEENABLE_D0);
264     panel_icn6211_dsi_write(dsi, PPI_D0S_CLRSIPOCOUNT, 0x05);
265     panel_icn6211_dsi_write(dsi, PPI_D1S_CLRSIPOCOUNT, 0x05);
266     panel_icn6211_dsi_write(dsi, PPI_D0S_ATMR, 0x00);
267     panel_icn6211_dsi_write(dsi, PPI_D1S_ATMR, 0x00);
268     panel_icn6211_dsi_write(dsi, PPI_LPTXTIMECNT, 0x03);
269 
270     panel_icn6211_dsi_write(dsi, SPICMR, 0x00);
271     panel_icn6211_dsi_write(dsi, LCDCTRL, 0x00100150);
272     panel_icn6211_dsi_write(dsi, SYSCTRL, 0x040f);
273     msleep(100L);
274 
275     panel_icn6211_dsi_write(dsi, PPI_STARTPPI, 0x01);
276     panel_icn6211_dsi_write(dsi, DSI_STARTDSI, 0x01);
277     msleep(100L);
278 
279     /* Turn on the backlight. */
280     panel_icn6211_i2c_write(icn6211_i2c, REG_PWM, 255L);
281     icn6211_i2c->brightness = 255L;
282 
283     /* Default to the same orientation as the closed source
284      * firmware used for the panel.
285      */
286     panel_icn6211_i2c_write(icn6211_i2c, REG_PORTA, BIT(2L));
287 
288     ctx->enabled = true;
289 
290     return 0;
291 }
292 
icn6211_disable(struct drm_panel * panel)293 static int icn6211_disable(struct drm_panel *panel)
294 {
295     struct icn6211 *ctx = panel_to_icn6211(panel);
296 
297     if (!panel_icn6211_enable) {
298         return -1;
299     }
300 
301     dev_info(ctx->dev, "panel disable\n");
302 
303     panel_icn6211_i2c_write(icn6211_i2c, REG_PWM, 0);
304     panel_icn6211_i2c_write(icn6211_i2c, REG_POWERON, 0);
305 
306     ctx->enabled = false;
307 
308     return 0;
309 }
310 
icn6211_unprepare(struct drm_panel * panel)311 static int icn6211_unprepare(struct drm_panel *panel)
312 {
313     if (!panel_icn6211_enable)
314         return 0;
315 
316     struct icn6211 *ctx = panel_to_icn6211(panel);
317 
318     if (!ctx->prepared)
319         return 0;
320 
321     if (ctx->reset_gpio != NULL)
322         gpiod_set_value_cansleep(ctx->reset_gpio, 0);
323 
324     ctx->prepared = false;
325 
326     return 0;
327 }
328 
icn6211_prepare(struct drm_panel * panel)329 static int icn6211_prepare(struct drm_panel *panel)
330 {
331     int ret;
332     struct icn6211 *ctx = panel_to_icn6211(panel);
333     struct mipi_dsi_device *dsi = to_mipi_dsi_device(ctx->dev);
334 
335     if (!panel_icn6211_enable) {
336         return -1;
337     }
338 
339     if (ctx->prepared)
340         return 0;
341 
342     ret = mipi_dsi_turn_on_peripheral(dsi);
343     if (ret < 0) {
344         dev_err(panel->dev, "failed to turn on peripheral: %d\n", ret);
345         return ret;
346     }
347 
348     ctx->prepared = true;
349 
350     return 0;
351 }
352 
icn6211_get_modes(struct drm_panel * panel,struct drm_connector * connector)353 static int icn6211_get_modes(struct drm_panel *panel, struct drm_connector *connector)
354 {
355     struct icn6211 *ctx = panel_to_icn6211(panel);
356     struct drm_display_mode *mode;
357     static const u32 bus_format = MEDIA_BUS_FMT_RGB888_1X24;
358 
359     if (!panel_icn6211_enable) {
360         connector->status = connector_status_disconnected;
361         return 0;
362     }
363 
364     mode = drm_mode_duplicate(connector->dev, ctx->desc->mode);
365     if (!mode) {
366         dev_err(ctx->dev, "Failed to add mode %ux%u@%u\n", ctx->desc->mode->hdisplay, ctx->desc->mode->vdisplay,
367                 drm_mode_vrefresh(ctx->desc->mode));
368         return -ENOMEM;
369     }
370 
371     drm_mode_set_name(mode);
372 
373     mode->type = DRM_MODE_TYPE_DRIVER | DRM_MODE_TYPE_PREFERRED;
374     connector->display_info.bpc = 8L;
375     connector->display_info.width_mm = mode->width_mm;
376     connector->display_info.height_mm = mode->height_mm;
377     drm_mode_probed_add(connector, mode);
378 
379     drm_display_info_set_bus_formats(&connector->display_info, &bus_format, 1);
380 
381     return 1;
382 }
383 
384 static const struct drm_panel_funcs icn6211_drm_funcs = {
385     .disable = icn6211_disable,
386     .unprepare = icn6211_unprepare,
387     .prepare = icn6211_prepare,
388     .enable = icn6211_enable,
389     .get_modes = icn6211_get_modes,
390 };
391 
icn6211_probe(struct mipi_dsi_device * dsi)392 static int icn6211_probe(struct mipi_dsi_device *dsi)
393 {
394     struct device *dev = &dsi->dev;
395     struct icn6211 *ctx;
396     int ret;
397 
398     ctx = devm_kzalloc(dev, sizeof(*ctx), GFP_KERNEL);
399     if (!ctx)
400         return -ENOMEM;
401 
402     mipi_dsi_set_drvdata(dsi, ctx);
403 
404     ctx->dev = dev;
405     ctx->desc = of_device_get_match_data(dev);
406 
407     dsi->mode_flags = ctx->desc->mode_flags;
408     dsi->format = ctx->desc->format;
409     dsi->lanes = ctx->desc->lanes;
410 
411     drm_panel_init(&ctx->panel, dev, &icn6211_drm_funcs, DRM_MODE_CONNECTOR_DSI);
412 
413     drm_panel_add(&ctx->panel);
414 
415     ret = mipi_dsi_attach(dsi);
416     if (ret < 0) {
417         dev_err(dev, "mipi_dsi_attach failed (%d). Is host ready?\n", ret);
418         drm_panel_remove(&ctx->panel);
419         return ret;
420     }
421 
422     dev_info(dev, "%ux%u@%u %ubpp dsi %ulanes\n", ctx->desc->mode->hdisplay, ctx->desc->mode->vdisplay,
423              drm_mode_vrefresh(ctx->desc->mode), mipi_dsi_pixel_format_to_bpp(dsi->format), dsi->lanes);
424 
425     return 0;
426 }
427 
icn6211_shutdown(struct mipi_dsi_device * dsi)428 static void icn6211_shutdown(struct mipi_dsi_device *dsi)
429 {
430     struct icn6211 *ctx = mipi_dsi_get_drvdata(dsi);
431     int ret;
432 
433     ret = drm_panel_unprepare(&ctx->panel);
434     if (ret < 0)
435         dev_err(&dsi->dev, "Failed to unprepare panel: %d\n", ret);
436 
437     ret = drm_panel_disable(&ctx->panel);
438     if (ret < 0)
439         dev_err(&dsi->dev, "Failed to disable panel: %d\n", ret);
440 }
441 
icn6211_remove(struct mipi_dsi_device * dsi)442 static int icn6211_remove(struct mipi_dsi_device *dsi)
443 {
444     struct icn6211 *ctx = mipi_dsi_get_drvdata(dsi);
445     int ret;
446 
447     icn6211_shutdown(dsi);
448 
449     ret = mipi_dsi_detach(dsi);
450     if (ret < 0)
451         dev_err(&dsi->dev, "Failed to detach from DSI host: %d\n", ret);
452 
453     drm_panel_remove(&ctx->panel);
454 
455     return 0;
456 }
457 
458 static const struct of_device_id icn6211_of_match[] = {{.compatible = "chipone,icn6211", .data = &icn6211_panel_desc},
459                                                        {}};
460 MODULE_DEVICE_TABLE(of, icn6211_of_match);
461 
462 static struct mipi_dsi_driver icn6211_panel_driver = {
463     .probe = icn6211_probe,
464     .remove = icn6211_remove,
465     .shutdown = icn6211_shutdown,
466     .driver =
467         {
468             .name = DRV_NAME,
469             .of_match_table = icn6211_of_match,
470         },
471 };
472 module_mipi_dsi_driver(icn6211_panel_driver);
473 
brightness_show(struct class * cla,struct class_attribute * attr,char * buf)474 static ssize_t brightness_show(struct class *cla, struct class_attribute *attr, char *buf)
475 {
476     int brightness = 0;
477 
478     if (panel_icn6211_enable) {
479         brightness = icn6211_i2c->brightness;
480     }
481 
482     if ((brightness >= 0) && (brightness <= 255L)) {
483         brightness = (brightness * 100L) / 255L;
484     } else {
485         brightness = 100L;
486     }
487 
488     return snprintf(buf, 8L, "%d\n", brightness);
489 }
490 
brightness_store(struct class * cla,struct class_attribute * attr,const char * buf,size_t count)491 static ssize_t brightness_store(struct class *cla, struct class_attribute *attr, const char *buf, size_t count)
492 {
493     int brightness;
494 
495     brightness = simple_strtoul(buf, NULL, 10L);
496     if ((brightness >= 0) && (brightness <= 100L)) {
497         brightness = (brightness * 255L) / 100L;
498     } else {
499         brightness = 255L;
500     }
501 
502     if (panel_icn6211_enable) {
503         if (brightness == 0) {
504             if (icn6211_i2c->brightness != 0) {
505                 panel_icn6211_i2c_write(icn6211_i2c, REG_PWM, 0);
506                 panel_icn6211_i2c_write(icn6211_i2c, REG_POWERON, 0);
507             }
508         } else {
509             if (icn6211_i2c->brightness == 0) {
510                 panel_icn6211_i2c_write(icn6211_i2c, REG_POWERON, 1);
511                 udelay(120L);
512             }
513 
514             panel_icn6211_i2c_write(icn6211_i2c, REG_PWM, brightness);
515             panel_icn6211_i2c_write(icn6211_i2c, REG_PORTA, BIT(2L));
516         }
517 
518         icn6211_i2c->brightness = brightness;
519     }
520 
521     return count;
522 }
523 
524 static CLASS_ATTR_RW(brightness);
525 
526 static struct attribute *icn6211_class_attrs[] = {&class_attr_brightness.attr, NULL};
527 ATTRIBUTE_GROUPS(icn6211_class);
528 
529 static struct class icn6211_class = {
530     .name = BRIGHTNESS_CLASS_NAME,
531     .class_groups = icn6211_class_groups,
532 };
533 
panel_icn6211_i2c_probe(struct i2c_client * i2c,const struct i2c_device_id * id)534 static int panel_icn6211_i2c_probe(struct i2c_client *i2c, const struct i2c_device_id *id)
535 {
536     struct device *dev = &i2c->dev;
537     struct device *brightness_dev;
538     int ret;
539     int ver;
540 
541     icn6211_i2c = devm_kzalloc(dev, sizeof(*icn6211_i2c), GFP_KERNEL);
542     if (!icn6211_i2c) {
543         dev_err(dev, "devm_kzalloc failed!\n");
544         return -ENOMEM;
545     }
546 
547     i2c_set_clientdata(i2c, icn6211_i2c);
548 
549     icn6211_i2c->i2c = i2c;
550     panel_icn6211_enable = false;
551 
552     ver = panel_icn6211_i2c_read(icn6211_i2c, 0x80);
553     if (ver < 0) {
554         dev_err(dev, "I2C read failed: %d\n", ver);
555         return -ENODEV;
556     }
557 
558     dev_info(dev, "icn6211 reg id 0x%x\n", ver);
559 
560     switch (ver) {
561         case 0xde: /* ver 1 */
562         case 0xc3: /* ver 2 */
563             break;
564         default:
565             dev_err(dev, "Unknown firmware revision: 0x%02x\n", ver);
566             return -ENODEV;
567     }
568 
569     /* Turn off at boot, so we can cleanly sequence powering on. */
570     panel_icn6211_enable = true;
571     panel_icn6211_i2c_write(icn6211_i2c, REG_POWERON, 0);
572 
573     ret = class_register(&icn6211_class);
574     if (ret < 0) {
575         dev_warn(dev, "register icn6211 class fail! %d\n", ret);
576     }
577 
578     brightness_dev = device_create(&icn6211_class, NULL, 0, NULL, BRIGHTNESS_DEVICE_NAME);
579     if (IS_ERR_OR_NULL(brightness_dev)) {
580         dev_err(dev, "create brightness device error\n");
581         class_unregister(&icn6211_class);
582     }
583 
584     return 0;
585 }
586 
panel_icn6211_i2c_remove(struct i2c_client * i2c)587 static int panel_icn6211_i2c_remove(struct i2c_client *i2c)
588 {
589     return 0;
590 }
591 
592 static const struct of_device_id panel_icn6211_i2c_of_ids[] = {
593     {.compatible = "chipone,icn6211-i2c"}, {} /* sentinel */
594 };
595 MODULE_DEVICE_TABLE(of, panel_icn6211_i2c_of_ids);
596 
597 static struct i2c_driver panel_icn6211_i2c_driver = {
598     .driver =
599         {
600             .name = "panel-icn6211-i2c",
601             .of_match_table = panel_icn6211_i2c_of_ids,
602         },
603     .probe = panel_icn6211_i2c_probe,
604     .remove = panel_icn6211_i2c_remove,
605 };
606 
panel_icn6211_i2c_init(void)607 static int __init panel_icn6211_i2c_init(void)
608 {
609     return i2c_add_driver(&panel_icn6211_i2c_driver);
610 }
611 module_init(panel_icn6211_i2c_init);
612 
panel_icn6211_i2c_exit(void)613 static void __exit panel_icn6211_i2c_exit(void)
614 {
615     i2c_del_driver(&panel_icn6211_i2c_driver);
616 }
617 module_exit(panel_icn6211_i2c_exit);
618 
619 MODULE_AUTHOR("AlgoIdeas <yu19881234@163.com>");
620 MODULE_DESCRIPTION("DRM driver for chipone icn6211 based MIPI DSI panels");
621 MODULE_LICENSE("GPL v2");
622