Merge branch 'linux-linaro-lsk-v4.4-android' of git://git.linaro.org/kernel/linux...
[firefly-linux-kernel-4.4.55.git] / drivers / video / rockchip / display-sys.c
1 #include <linux/module.h>
2 #include <linux/ctype.h>
3 #include <linux/idr.h>
4 #include <linux/err.h>
5 #include <linux/kdev_t.h>
6 #include <linux/display-sys.h>
7
8 static struct list_head main_display_device_list;
9 static struct list_head aux_display_device_list;
10
11 static ssize_t name_show(struct device *dev,
12                          struct device_attribute *attr, char *buf)
13 {
14         struct rk_display_device *dsp = dev_get_drvdata(dev);
15
16         return snprintf(buf, PAGE_SIZE, "%s\n", dsp->name);
17 }
18
19 static DEVICE_ATTR_RO(name);
20
21 static ssize_t type_show(struct device *dev,
22                          struct device_attribute *attr, char *buf)
23 {
24         struct rk_display_device *dsp = dev_get_drvdata(dev);
25
26         return snprintf(buf, PAGE_SIZE, "%s\n", dsp->type);
27 }
28
29 static DEVICE_ATTR_RO(type);
30
31 static ssize_t property_show(struct device *dev,
32                              struct device_attribute *attr, char *buf)
33 {
34         struct rk_display_device *dsp = dev_get_drvdata(dev);
35
36         return snprintf(buf, PAGE_SIZE, "%d\n", dsp->property);
37 }
38
39 static DEVICE_ATTR_RO(property);
40
41 static ssize_t enable_show(struct device *dev,
42                            struct device_attribute *attr, char *buf)
43 {
44         struct rk_display_device *dsp = dev_get_drvdata(dev);
45         int enable;
46
47         if (dsp->ops && dsp->ops->getenable)
48                 enable = dsp->ops->getenable(dsp);
49         else
50                 return 0;
51         return snprintf(buf, PAGE_SIZE, "%d\n", enable);
52 }
53
54 static ssize_t enable_store(struct device *dev,
55                             struct device_attribute *attr,
56                             const char *buf, size_t size)
57 {
58         struct rk_display_device *dsp = dev_get_drvdata(dev);
59         int enable;
60
61         if (kstrtoint(buf, 0, &enable))
62                 return size;
63         if (dsp->ops && dsp->ops->setenable)
64                 dsp->ops->setenable(dsp, enable);
65         return size;
66 }
67
68 static DEVICE_ATTR_RW(enable);
69
70 static ssize_t connect_show(struct device *dev,
71                             struct device_attribute *attr, char *buf)
72 {
73         struct rk_display_device *dsp = dev_get_drvdata(dev);
74         int connect;
75
76         if (dsp->ops && dsp->ops->getstatus)
77                 connect = dsp->ops->getstatus(dsp);
78         else
79                 return 0;
80         return snprintf(buf, PAGE_SIZE, "%d\n", connect);
81 }
82
83 static DEVICE_ATTR_RO(connect);
84
85 static int mode_string(char *buf, unsigned int offset,
86                        const struct fb_videomode *mode)
87 {
88         char v = 'p';
89
90         if (!buf || !mode) {
91                 pr_err("%s parameter error\n", __func__);
92                 return 0;
93         }
94         if (mode->xres == 0 && mode->yres == 0)
95                 return snprintf(&buf[offset], PAGE_SIZE - offset, "auto\n");
96         if (mode->vmode & FB_VMODE_INTERLACED)
97                 v = 'i';
98         if (mode->vmode & FB_VMODE_DOUBLE)
99                 v = 'd';
100         if (mode->flag)
101                 return snprintf(&buf[offset], PAGE_SIZE - offset,
102                                 "%dx%d%c-%d(YCbCr420)\n",
103                                 mode->xres, mode->yres, v, mode->refresh);
104         else
105                 return snprintf(&buf[offset], PAGE_SIZE - offset,
106                                 "%dx%d%c-%d\n",
107                                 mode->xres, mode->yres, v, mode->refresh);
108 }
109
110 static ssize_t modes_show(struct device *dev,
111                           struct device_attribute *attr, char *buf)
112 {
113         struct rk_display_device *dsp = dev_get_drvdata(dev);
114         struct list_head *modelist, *pos;
115         struct display_modelist *display_modelist;
116         const struct fb_videomode *mode;
117         int i;
118
119         mutex_lock(&dsp->lock);
120         if (dsp->ops && dsp->ops->getmodelist) {
121                 if (dsp->ops->getmodelist(dsp, &modelist)) {
122                         mutex_unlock(&dsp->lock);
123                         return -EINVAL;
124                 }
125         } else {
126                 mutex_unlock(&dsp->lock);
127                 return 0;
128         }
129         i = 0;
130         if (dsp->priority == DISPLAY_PRIORITY_HDMI)
131                 i += snprintf(buf, PAGE_SIZE, "auto\n");
132
133         list_for_each(pos, modelist) {
134                 display_modelist = list_entry(pos,
135                                               struct display_modelist,
136                                               list);
137                 mode = &display_modelist->mode;
138                 i += mode_string(buf, i, mode);
139         }
140         mutex_unlock(&dsp->lock);
141         return i;
142 }
143
144 static DEVICE_ATTR_RO(modes);
145
146 static ssize_t mode_show(struct device *dev,
147                          struct device_attribute *attr, char *buf)
148 {
149         struct rk_display_device *dsp = dev_get_drvdata(dev);
150         struct fb_videomode mode;
151
152         if (dsp->ops && dsp->ops->getmode)
153                 if (dsp->ops->getmode(dsp, &mode) == 0)
154                         return mode_string(buf, 0, &mode);
155         return 0;
156 }
157
158 static ssize_t mode_store(struct device *dev,
159                           struct device_attribute *attr,
160                           const char *buf, size_t count)
161 {
162         struct rk_display_device *dsp = dev_get_drvdata(dev);
163         char mstr[100];
164         struct list_head *modelist, *pos;
165         struct display_modelist *display_modelist;
166         struct fb_videomode *mode;
167         size_t i;
168
169         mutex_lock(&dsp->lock);
170         if (!memcmp(buf, "auto", 4)) {
171                 if (dsp->ops && dsp->ops->setmode)
172                         dsp->ops->setmode(dsp, NULL);
173                 mutex_unlock(&dsp->lock);
174                 return count;
175         }
176
177         if (dsp->ops && dsp->ops->getmodelist) {
178                 if (dsp->ops && dsp->ops->getmodelist) {
179                         if (dsp->ops->getmodelist(dsp, &modelist)) {
180                                 mutex_unlock(&dsp->lock);
181                                 return -EINVAL;
182                         }
183                 }
184                 list_for_each(pos, modelist) {
185                         display_modelist = list_entry(pos,
186                                                       struct display_modelist,
187                                                       list);
188                         mode = &display_modelist->mode;
189                         i = mode_string(mstr, 0, mode);
190                         if (strncmp(mstr, buf, max(count, i)) == 0) {
191                                 if (dsp->ops && dsp->ops->setmode)
192                                         dsp->ops->setmode(dsp, mode);
193                                 mutex_unlock(&dsp->lock);
194                                 return count;
195                         }
196                 }
197         }
198         mutex_unlock(&dsp->lock);
199         return -EINVAL;
200 }
201
202 static DEVICE_ATTR_RW(mode);
203
204 static ssize_t scale_show(struct device *dev,
205                           struct device_attribute *attr,
206                           char *buf)
207 {
208         struct rk_display_device *dsp = dev_get_drvdata(dev);
209         int xscale, yscale;
210
211         if (dsp->ops && dsp->ops->getscale) {
212                 xscale = dsp->ops->getscale(dsp, DISPLAY_SCALE_X);
213                 yscale = dsp->ops->getscale(dsp, DISPLAY_SCALE_Y);
214                 if (xscale && yscale)
215                         return snprintf(buf, PAGE_SIZE,
216                                         "xscale=%d yscale=%d\n",
217                                         xscale, yscale);
218         }
219         return -EINVAL;
220 }
221
222 static ssize_t scale_store(struct device *dev,
223                            struct device_attribute *attr,
224                            const char *buf, size_t count)
225 {
226         struct rk_display_device *dsp = dev_get_drvdata(dev);
227         int scale = 100;
228
229         if (dsp->ops && dsp->ops->setscale) {
230                 if (!strncmp(buf, "xscale", 6)) {
231                         if (!kstrtoint(buf, 0, &scale))
232                                 dsp->ops->setscale(dsp,
233                                                    DISPLAY_SCALE_X,
234                                                    scale);
235                 } else if (!strncmp(buf, "yscale", 6)) {
236                         if (!kstrtoint(buf, 0, &scale))
237                                 dsp->ops->setscale(dsp,
238                                                    DISPLAY_SCALE_Y,
239                                                    scale);
240                 } else {
241                         if (!kstrtoint(buf, 0, &scale)) {
242                                 dsp->ops->setscale(dsp,
243                                                    DISPLAY_SCALE_X,
244                                                    scale);
245                                 dsp->ops->setscale(dsp,
246                                                    DISPLAY_SCALE_Y,
247                                                    scale);
248                         }
249                 }
250                 return count;
251         }
252         return -EINVAL;
253 }
254
255 static DEVICE_ATTR_RW(scale);
256
257 static ssize_t mode3d_show(struct device *dev,
258                            struct device_attribute *attr, char *buf)
259 {
260         struct rk_display_device *dsp = dev_get_drvdata(dev);
261         struct list_head *modelist, *pos;
262         struct display_modelist *display_modelist;
263         struct fb_videomode mode;
264         int i = 0, cur_3d_mode = -1;
265         char mode_str[128];
266         int mode_strlen, format_3d;
267
268         mutex_lock(&dsp->lock);
269         if (dsp->ops && dsp->ops->getmodelist) {
270                 if (dsp->ops->getmodelist(dsp, &modelist)) {
271                         mutex_unlock(&dsp->lock);
272                         return -EINVAL;
273                 }
274         } else {
275                 mutex_unlock(&dsp->lock);
276                 return 0;
277         }
278
279         if (dsp->ops && dsp->ops->getmode) {
280                 if (dsp->ops->getmode(dsp, &mode)) {
281                         mutex_unlock(&dsp->lock);
282                         return -EINVAL;
283                 }
284         } else {
285                 mutex_unlock(&dsp->lock);
286                 return 0;
287         }
288
289         list_for_each(pos, modelist) {
290                 display_modelist = list_entry(pos,
291                                               struct display_modelist,
292                                               list);
293                 if (!fb_mode_is_equal(&mode, &display_modelist->mode))
294                         display_modelist = NULL;
295                 else
296                         break;
297         }
298         if (display_modelist)
299                 i = snprintf(buf, PAGE_SIZE, "3dmodes=%d\n",
300                              display_modelist->format_3d);
301         else
302                 i = snprintf(buf, PAGE_SIZE, "3dmodes=0\n");
303
304         if (dsp->ops && dsp->ops->get3dmode)
305                 cur_3d_mode = dsp->ops->get3dmode(dsp);
306         i += snprintf(buf + i, PAGE_SIZE - i, "cur3dmode=%d\n", cur_3d_mode);
307
308         list_for_each(pos, modelist) {
309                 display_modelist = list_entry(pos,
310                                               struct display_modelist,
311                                               list);
312                 mode_strlen = mode_string(mode_str, 0,
313                                           &display_modelist->mode);
314                 mode_str[mode_strlen - 1] = 0;
315                 format_3d = display_modelist->format_3d;
316                 i += snprintf(buf + i, PAGE_SIZE, "%s,%d\n",
317                               mode_str, format_3d);
318         }
319         mutex_unlock(&dsp->lock);
320         return i;
321 }
322
323 static ssize_t mode3d_store(struct device *dev,
324                             struct device_attribute *attr,
325                             const char *buf, size_t count)
326 {
327         struct rk_display_device *dsp = dev_get_drvdata(dev);
328         int mode;
329
330         mutex_lock(&dsp->lock);
331         if (dsp->ops && dsp->ops->set3dmode) {
332                 if (!kstrtoint(buf, 0, &mode))
333                         dsp->ops->set3dmode(dsp, mode);
334                 mutex_unlock(&dsp->lock);
335                 return count;
336         }
337         mutex_unlock(&dsp->lock);
338         return -EINVAL;
339 }
340
341 static DEVICE_ATTR_RW(mode3d);
342
343 static ssize_t color_show(struct device *dev,
344                           struct device_attribute *attr, char *buf)
345 {
346         struct rk_display_device *dsp = dev_get_drvdata(dev);
347         int ret = 0;
348
349         mutex_lock(&dsp->lock);
350         if (dsp->ops && dsp->ops->getcolor)
351                 ret = dsp->ops->getcolor(dsp, buf);
352         mutex_unlock(&dsp->lock);
353         return ret;
354 }
355
356 static ssize_t color_store(struct device *dev,
357                            struct device_attribute *attr,
358                            const char *buf, size_t count)
359 {
360         struct rk_display_device *dsp = dev_get_drvdata(dev);
361
362         mutex_lock(&dsp->lock);
363         if (dsp->ops && dsp->ops->setcolor) {
364                 if (!dsp->ops->setcolor(dsp, buf, count)) {
365                         mutex_unlock(&dsp->lock);
366                         return count;
367                 }
368         }
369         mutex_unlock(&dsp->lock);
370         return -EINVAL;
371 }
372
373 static DEVICE_ATTR_RW(color);
374
375 static ssize_t audioinfo_show(struct device *dev,
376                               struct device_attribute *attr,
377                               char *buf)
378 {
379         struct rk_display_device *dsp = dev_get_drvdata(dev);
380         char audioinfo[200];
381         int ret = 0;
382
383         mutex_lock(&dsp->lock);
384         if (dsp->ops && dsp->ops->getedidaudioinfo) {
385                 ret = dsp->ops->getedidaudioinfo(dsp, audioinfo, 200);
386                 if (!ret) {
387                         mutex_unlock(&dsp->lock);
388                         return snprintf(buf, PAGE_SIZE, "%s\n", audioinfo);
389                 }
390         }
391         mutex_unlock(&dsp->lock);
392         return -EINVAL;
393 }
394
395 static DEVICE_ATTR_RO(audioinfo);
396
397 static ssize_t monspecs_show(struct device *dev,
398                              struct device_attribute *attr, char *buf)
399 {
400         struct rk_display_device *dsp = dev_get_drvdata(dev);
401         struct fb_monspecs monspecs;
402         int ret = 0;
403
404         mutex_lock(&dsp->lock);
405         if (dsp->ops && dsp->ops->getmonspecs) {
406                 ret = dsp->ops->getmonspecs(dsp, &monspecs);
407                 if (!ret) {
408                         mutex_unlock(&dsp->lock);
409                         memcpy(buf, &monspecs, sizeof(struct fb_monspecs));
410                         return sizeof(struct fb_monspecs);
411                 }
412         }
413         mutex_unlock(&dsp->lock);
414         return -EINVAL;
415 }
416
417 static DEVICE_ATTR_RO(monspecs);
418
419 static ssize_t debug_show(struct device *dev,
420                           struct device_attribute *attr, char *buf)
421 {
422         struct rk_display_device *dsp = dev_get_drvdata(dev);
423         int ret = -EINVAL;
424
425         mutex_lock(&dsp->lock);
426         if (dsp->ops && dsp->ops->getdebug)
427                 ret = dsp->ops->getdebug(dsp, buf);
428         mutex_unlock(&dsp->lock);
429         return ret;
430 }
431
432 static ssize_t debug_store(struct device *dev,
433                            struct device_attribute *attr,
434                            const char *buf, size_t count)
435 {
436         int cmd, ret = -EINVAL;
437         struct rk_display_device *dsp = dev_get_drvdata(dev);
438
439         mutex_lock(&dsp->lock);
440         if (dsp->ops && dsp->ops->setdebug) {
441                 if (kstrtoint(buf, 0, &cmd) == 0)
442                         dsp->ops->setdebug(dsp, cmd);
443                 ret = count;
444         }
445         mutex_unlock(&dsp->lock);
446         return ret;
447 }
448
449 static DEVICE_ATTR_RW(debug);
450
451 static struct attribute *display_device_attrs[] = {
452         &dev_attr_name.attr,
453         &dev_attr_type.attr,
454         &dev_attr_property.attr,
455         &dev_attr_enable.attr,
456         &dev_attr_connect.attr,
457         &dev_attr_modes.attr,
458         &dev_attr_mode.attr,
459         &dev_attr_scale.attr,
460         &dev_attr_mode3d.attr,
461         &dev_attr_color.attr,
462         &dev_attr_audioinfo.attr,
463         &dev_attr_monspecs.attr,
464         &dev_attr_debug.attr,
465         NULL,
466 };
467
468 ATTRIBUTE_GROUPS(display_device);
469
470 static int display_suspend(struct device *dev, pm_message_t state)
471 {
472         struct rk_display_device *dsp = dev_get_drvdata(dev);
473
474         mutex_lock(&dsp->lock);
475         if (likely(dsp->driver->suspend))
476                 dsp->driver->suspend(dsp, state);
477         mutex_unlock(&dsp->lock);
478         return 0;
479 };
480
481 static int display_resume(struct device *dev)
482 {
483         struct rk_display_device *dsp = dev_get_drvdata(dev);
484
485         mutex_lock(&dsp->lock);
486         if (likely(dsp->driver->resume))
487                 dsp->driver->resume(dsp);
488         mutex_unlock(&dsp->lock);
489         return 0;
490 };
491
492 int display_add_videomode(const struct fb_videomode *mode,
493                           struct list_head *head)
494 {
495         struct list_head *pos;
496         struct display_modelist *modelist;
497         struct fb_videomode *m;
498         int found = 0;
499
500         list_for_each(pos, head) {
501                 modelist = list_entry(pos, struct display_modelist, list);
502                 m = &modelist->mode;
503                 if (fb_mode_is_equal(m, mode)) {
504                         found = 1;
505                         break;
506                 }
507         }
508         if (!found) {
509                 modelist = kmalloc(sizeof(*modelist),
510                                    GFP_KERNEL);
511
512                 if (!modelist)
513                         return -ENOMEM;
514                 modelist->mode = *mode;
515                 list_add(&modelist->list, head);
516         }
517         return 0;
518 }
519
520 void rk_display_device_enable(struct rk_display_device *ddev)
521 {
522         struct list_head *pos, *head;
523         struct rk_display_device *dev = NULL, *dev_enabled = NULL;
524         struct rk_display_device *dev_enable = NULL;
525         int enable = 0, connect;
526
527         if (ddev->property == DISPLAY_MAIN)
528                 head = &main_display_device_list;
529         else
530                 head = &aux_display_device_list;
531
532         list_for_each(pos, head) {
533                 dev = list_entry(pos, struct rk_display_device, list);
534                 enable = dev->ops->getenable(dev);
535                 connect = dev->ops->getstatus(dev);
536                 if (connect)
537                         dev_enable = dev;
538                 if (enable == 1)
539                         dev_enabled = dev;
540         }
541         /* If no device is connected, enable highest priority device. */
542         if (!dev_enable) {
543                 dev->ops->setenable(dev, 1);
544                 return;
545         }
546
547         if (dev_enable == dev_enabled) {
548                 if (dev_enable != ddev)
549                         ddev->ops->setenable(ddev, 0);
550         } else {
551                 if (dev_enabled &&
552                     dev_enabled->priority != DISPLAY_PRIORITY_HDMI)
553                         dev_enabled->ops->setenable(dev_enabled, 0);
554                 dev_enable->ops->setenable(dev_enable, 1);
555         }
556 }
557 EXPORT_SYMBOL(rk_display_device_enable);
558
559 void rk_display_device_enable_other(struct rk_display_device *ddev)
560 {
561 #ifndef CONFIG_DISPLAY_AUTO_SWITCH
562         return;
563 #else
564         struct list_head *pos, *head;
565         struct rk_display_device *dev;
566         int connect = 0;
567
568         if (ddev->property == DISPLAY_MAIN)
569                 head = &main_display_device_list;
570         else
571                 head = &aux_display_device_list;
572
573         list_for_each_prev(pos, head) {
574                 dev = list_entry(pos, struct rk_display_device, list);
575                 if (dev != ddev) {
576                         connect = dev->ops->getstatus(dev);
577                         if (connect) {
578                                 dev->ops->setenable(dev, 1);
579                                 return;
580                         }
581                 }
582         }
583 #endif
584 }
585 EXPORT_SYMBOL(rk_display_device_enable_other);
586
587 void rk_display_device_disable_other(struct rk_display_device *ddev)
588 {
589 #ifndef CONFIG_DISPLAY_AUTO_SWITCH
590         return;
591 #else
592         struct list_head *pos, *head;
593         struct rk_display_device *dev;
594         int enable = 0;
595
596         if (ddev->property == DISPLAY_MAIN)
597                 head = &main_display_device_list;
598         else
599                 head = &aux_display_device_list;
600
601         list_for_each(pos, head) {
602                 dev = list_entry(pos, struct rk_display_device, list);
603                 if (dev != ddev) {
604                         enable = dev->ops->getenable(dev);
605                         if (enable)
606                                 dev->ops->setenable(dev, 0);
607                 }
608         }
609         ddev->ops->setenable(ddev, 1);
610 #endif
611 }
612 EXPORT_SYMBOL(rk_display_device_disable_other);
613
614 void rk_display_device_select(int property, int priority)
615 {
616         struct list_head *pos, *head;
617         struct rk_display_device *dev;
618         int enable, found = 0;
619
620         if (property == DISPLAY_MAIN)
621                 head = &main_display_device_list;
622         else
623                 head = &aux_display_device_list;
624
625         list_for_each(pos, head) {
626                 dev = list_entry(pos, struct rk_display_device, list);
627                 if (dev->priority == priority)
628                         found = 1;
629         }
630
631         if (!found) {
632                 pr_err("[%s] select display interface %d not exist\n",
633                        __func__, priority);
634                 return;
635         }
636
637         list_for_each(pos, head) {
638                 dev = list_entry(pos, struct rk_display_device, list);
639                 enable = dev->ops->getenable(dev);
640                 if (dev->priority == priority) {
641                         if (!enable)
642                                 dev->ops->setenable(dev, 1);
643                 } else if (enable) {
644                         dev->ops->setenable(dev, 0);
645                 }
646         }
647 }
648 EXPORT_SYMBOL(rk_display_device_select);
649 static struct mutex allocated_dsp_lock;
650 static DEFINE_IDR(allocated_dsp);
651 static struct class *display_class;
652
653 struct rk_display_device
654         *rk_display_device_register(struct rk_display_driver *driver,
655                                     struct device *parent, void *devdata)
656 {
657         struct rk_display_device *new_dev = NULL;
658         int ret = -EINVAL;
659
660         if (unlikely(!driver))
661                 return ERR_PTR(ret);
662
663         new_dev = kzalloc(sizeof(*new_dev), GFP_KERNEL);
664         if (likely(new_dev) && unlikely(driver->probe(new_dev, devdata))) {
665                 /* Reserve the index for this display */
666                 mutex_lock(&allocated_dsp_lock);
667                 new_dev->idx = idr_alloc(&allocated_dsp, new_dev,
668                                          0, 0, GFP_KERNEL);
669                 mutex_unlock(&allocated_dsp_lock);
670
671                 if (new_dev->idx >= 0) {
672                         struct list_head *pos, *head;
673                         struct rk_display_device *dev;
674                         int i = 0;
675
676                         head = &main_display_device_list;
677                         list_for_each_entry(dev, head, list) {
678                                 if (strcmp(dev->type, new_dev->type) == 0)
679                                         i++;
680                         }
681                         head = &aux_display_device_list;
682                         list_for_each_entry(dev, head, list) {
683                                 if (strcmp(dev->type, new_dev->type) == 0)
684                                         i++;
685                         }
686                         if (i == 0)
687                                 new_dev->dev =
688                                 device_create(display_class, parent,
689                                               MKDEV(0, 0), new_dev,
690                                               "%s", new_dev->type);
691                         else
692                                 new_dev->dev =
693                                 device_create(display_class, parent,
694                                               MKDEV(0, 0), new_dev,
695                                               "%s%d", new_dev->type, i);
696
697                         if (!IS_ERR(new_dev->dev)) {
698                                 new_dev->parent = parent;
699                                 new_dev->driver = driver;
700                                 if (parent)
701                                         new_dev->dev->driver = parent->driver;
702                                 mutex_init(&new_dev->lock);
703                                 /* Add new device to display device list. */
704                                 if (new_dev->property == DISPLAY_MAIN)
705                                         head = &main_display_device_list;
706                                 else
707                                         head = &aux_display_device_list;
708
709                                 list_for_each(pos, head) {
710                                         dev =
711                                         list_entry(pos,
712                                                    struct rk_display_device,
713                                                    list);
714                                         if (dev->priority > new_dev->priority)
715                                                 break;
716                                 }
717                                 list_add_tail(&new_dev->list, pos);
718                                 return new_dev;
719                         }
720                         mutex_lock(&allocated_dsp_lock);
721                         idr_remove(&allocated_dsp, new_dev->idx);
722                         mutex_unlock(&allocated_dsp_lock);
723                         ret = -EINVAL;
724                 }
725         }
726         kfree(new_dev);
727         return ERR_PTR(ret);
728 }
729 EXPORT_SYMBOL(rk_display_device_register);
730
731 void rk_display_device_unregister(struct rk_display_device *ddev)
732 {
733         if (!ddev)
734                 return;
735         /* Free device */
736         mutex_lock(&ddev->lock);
737         device_unregister(ddev->dev);
738         mutex_unlock(&ddev->lock);
739         /* Mark device index as available */
740         mutex_lock(&allocated_dsp_lock);
741         idr_remove(&allocated_dsp, ddev->idx);
742         mutex_unlock(&allocated_dsp_lock);
743         list_del(&ddev->list);
744         kfree(ddev);
745 }
746 EXPORT_SYMBOL(rk_display_device_unregister);
747
748 static int __init rk_display_class_init(void)
749 {
750         display_class = class_create(THIS_MODULE, "display");
751         if (IS_ERR(display_class)) {
752                 pr_err("Failed to create display class\n");
753                 display_class = NULL;
754                 return -EINVAL;
755         }
756         display_class->dev_groups = display_device_groups;
757         display_class->suspend = display_suspend;
758         display_class->resume = display_resume;
759         mutex_init(&allocated_dsp_lock);
760         INIT_LIST_HEAD(&main_display_device_list);
761         INIT_LIST_HEAD(&aux_display_device_list);
762         return 0;
763 }
764
765 static void __exit rk_display_class_exit(void)
766 {
767         class_destroy(display_class);
768 }
769
770 subsys_initcall(rk_display_class_init);
771 module_exit(rk_display_class_exit);
772
773 MODULE_AUTHOR("zhengyang@rock-chips.com");
774 MODULE_DESCRIPTION("Driver for rk display device");
775 MODULE_LICENSE("GPL");