drivers: video: rockchip: vcodec_dma_map_sg maybe fail
[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 ssize_t prop_show(struct device *dev,
452                          struct device_attribute *attr, char *buf)
453 {
454         struct rk_display_device *dsp = dev_get_drvdata(dev);
455         int ret = -EINVAL;
456
457         mutex_lock(&dsp->lock);
458         if (dsp->ops && dsp->ops->getvrinfo)
459                 ret = dsp->ops->getvrinfo(dsp, buf);
460         mutex_unlock(&dsp->lock);
461
462         return ret;
463 }
464
465 static DEVICE_ATTR_RO(prop);
466
467 static struct attribute *display_device_attrs[] = {
468         &dev_attr_name.attr,
469         &dev_attr_type.attr,
470         &dev_attr_property.attr,
471         &dev_attr_enable.attr,
472         &dev_attr_connect.attr,
473         &dev_attr_modes.attr,
474         &dev_attr_mode.attr,
475         &dev_attr_scale.attr,
476         &dev_attr_mode3d.attr,
477         &dev_attr_color.attr,
478         &dev_attr_audioinfo.attr,
479         &dev_attr_monspecs.attr,
480         &dev_attr_debug.attr,
481         &dev_attr_prop.attr,
482         NULL,
483 };
484
485 ATTRIBUTE_GROUPS(display_device);
486
487 static int display_suspend(struct device *dev, pm_message_t state)
488 {
489         struct rk_display_device *dsp = dev_get_drvdata(dev);
490
491         mutex_lock(&dsp->lock);
492         if (likely(dsp->driver->suspend))
493                 dsp->driver->suspend(dsp, state);
494         mutex_unlock(&dsp->lock);
495         return 0;
496 };
497
498 static int display_resume(struct device *dev)
499 {
500         struct rk_display_device *dsp = dev_get_drvdata(dev);
501
502         mutex_lock(&dsp->lock);
503         if (likely(dsp->driver->resume))
504                 dsp->driver->resume(dsp);
505         mutex_unlock(&dsp->lock);
506         return 0;
507 };
508
509 int display_add_videomode(const struct fb_videomode *mode,
510                           struct list_head *head)
511 {
512         struct list_head *pos;
513         struct display_modelist *modelist;
514         struct fb_videomode *m;
515         int found = 0;
516
517         list_for_each(pos, head) {
518                 modelist = list_entry(pos, struct display_modelist, list);
519                 m = &modelist->mode;
520                 if (fb_mode_is_equal(m, mode)) {
521                         found = 1;
522                         break;
523                 }
524         }
525         if (!found) {
526                 modelist = kmalloc(sizeof(*modelist),
527                                    GFP_KERNEL);
528
529                 if (!modelist)
530                         return -ENOMEM;
531                 modelist->mode = *mode;
532                 list_add(&modelist->list, head);
533         }
534         return 0;
535 }
536
537 void rk_display_device_enable(struct rk_display_device *ddev)
538 {
539         struct list_head *pos, *head;
540         struct rk_display_device *dev = NULL, *dev_enabled = NULL;
541         struct rk_display_device *dev_enable = NULL;
542         int enable = 0, connect;
543
544         if (ddev->property == DISPLAY_MAIN)
545                 head = &main_display_device_list;
546         else
547                 head = &aux_display_device_list;
548
549         list_for_each(pos, head) {
550                 dev = list_entry(pos, struct rk_display_device, list);
551                 enable = dev->ops->getenable(dev);
552                 connect = dev->ops->getstatus(dev);
553                 if (connect)
554                         dev_enable = dev;
555                 if (enable == 1)
556                         dev_enabled = dev;
557         }
558         /* If no device is connected, enable highest priority device. */
559         if (!dev_enable) {
560                 dev->ops->setenable(dev, 1);
561                 return;
562         }
563
564         if (dev_enable == dev_enabled) {
565                 if (dev_enable != ddev)
566                         ddev->ops->setenable(ddev, 0);
567         } else {
568                 if (dev_enabled &&
569                     dev_enabled->priority != DISPLAY_PRIORITY_HDMI)
570                         dev_enabled->ops->setenable(dev_enabled, 0);
571                 dev_enable->ops->setenable(dev_enable, 1);
572         }
573 }
574 EXPORT_SYMBOL(rk_display_device_enable);
575
576 void rk_display_device_enable_other(struct rk_display_device *ddev)
577 {
578 #ifndef CONFIG_DISPLAY_AUTO_SWITCH
579         return;
580 #else
581         struct list_head *pos, *head;
582         struct rk_display_device *dev;
583         int connect = 0;
584
585         if (ddev->property == DISPLAY_MAIN)
586                 head = &main_display_device_list;
587         else
588                 head = &aux_display_device_list;
589
590         list_for_each_prev(pos, head) {
591                 dev = list_entry(pos, struct rk_display_device, list);
592                 if (dev != ddev) {
593                         connect = dev->ops->getstatus(dev);
594                         if (connect) {
595                                 dev->ops->setenable(dev, 1);
596                                 return;
597                         }
598                 }
599         }
600 #endif
601 }
602 EXPORT_SYMBOL(rk_display_device_enable_other);
603
604 void rk_display_device_disable_other(struct rk_display_device *ddev)
605 {
606 #ifndef CONFIG_DISPLAY_AUTO_SWITCH
607         return;
608 #else
609         struct list_head *pos, *head;
610         struct rk_display_device *dev;
611         int enable = 0;
612
613         if (ddev->property == DISPLAY_MAIN)
614                 head = &main_display_device_list;
615         else
616                 head = &aux_display_device_list;
617
618         list_for_each(pos, head) {
619                 dev = list_entry(pos, struct rk_display_device, list);
620                 if (dev != ddev) {
621                         enable = dev->ops->getenable(dev);
622                         if (enable)
623                                 dev->ops->setenable(dev, 0);
624                 }
625         }
626         ddev->ops->setenable(ddev, 1);
627 #endif
628 }
629 EXPORT_SYMBOL(rk_display_device_disable_other);
630
631 void rk_display_device_select(int property, int priority)
632 {
633         struct list_head *pos, *head;
634         struct rk_display_device *dev;
635         int enable, found = 0;
636
637         if (property == DISPLAY_MAIN)
638                 head = &main_display_device_list;
639         else
640                 head = &aux_display_device_list;
641
642         list_for_each(pos, head) {
643                 dev = list_entry(pos, struct rk_display_device, list);
644                 if (dev->priority == priority)
645                         found = 1;
646         }
647
648         if (!found) {
649                 pr_err("[%s] select display interface %d not exist\n",
650                        __func__, priority);
651                 return;
652         }
653
654         list_for_each(pos, head) {
655                 dev = list_entry(pos, struct rk_display_device, list);
656                 enable = dev->ops->getenable(dev);
657                 if (dev->priority == priority) {
658                         if (!enable)
659                                 dev->ops->setenable(dev, 1);
660                 } else if (enable) {
661                         dev->ops->setenable(dev, 0);
662                 }
663         }
664 }
665 EXPORT_SYMBOL(rk_display_device_select);
666 static struct mutex allocated_dsp_lock;
667 static DEFINE_IDR(allocated_dsp);
668 static struct class *display_class;
669
670 struct rk_display_device
671         *rk_display_device_register(struct rk_display_driver *driver,
672                                     struct device *parent, void *devdata)
673 {
674         struct rk_display_device *new_dev = NULL;
675         int ret = -EINVAL;
676
677         if (unlikely(!driver))
678                 return ERR_PTR(ret);
679
680         new_dev = kzalloc(sizeof(*new_dev), GFP_KERNEL);
681         if (likely(new_dev) && unlikely(driver->probe(new_dev, devdata))) {
682                 /* Reserve the index for this display */
683                 mutex_lock(&allocated_dsp_lock);
684                 new_dev->idx = idr_alloc(&allocated_dsp, new_dev,
685                                          0, 0, GFP_KERNEL);
686                 mutex_unlock(&allocated_dsp_lock);
687
688                 if (new_dev->idx >= 0) {
689                         struct list_head *pos, *head;
690                         struct rk_display_device *dev;
691                         int i = 0;
692
693                         head = &main_display_device_list;
694                         list_for_each_entry(dev, head, list) {
695                                 if (strcmp(dev->type, new_dev->type) == 0)
696                                         i++;
697                         }
698                         head = &aux_display_device_list;
699                         list_for_each_entry(dev, head, list) {
700                                 if (strcmp(dev->type, new_dev->type) == 0)
701                                         i++;
702                         }
703                         if (i == 0)
704                                 new_dev->dev =
705                                 device_create(display_class, parent,
706                                               MKDEV(0, 0), new_dev,
707                                               "%s", new_dev->type);
708                         else
709                                 new_dev->dev =
710                                 device_create(display_class, parent,
711                                               MKDEV(0, 0), new_dev,
712                                               "%s%d", new_dev->type, i);
713
714                         if (!IS_ERR(new_dev->dev)) {
715                                 new_dev->parent = parent;
716                                 new_dev->driver = driver;
717                                 if (parent)
718                                         new_dev->dev->driver = parent->driver;
719                                 mutex_init(&new_dev->lock);
720                                 /* Add new device to display device list. */
721                                 if (new_dev->property == DISPLAY_MAIN)
722                                         head = &main_display_device_list;
723                                 else
724                                         head = &aux_display_device_list;
725
726                                 list_for_each(pos, head) {
727                                         dev =
728                                         list_entry(pos,
729                                                    struct rk_display_device,
730                                                    list);
731                                         if (dev->priority > new_dev->priority)
732                                                 break;
733                                 }
734                                 list_add_tail(&new_dev->list, pos);
735                                 return new_dev;
736                         }
737                         mutex_lock(&allocated_dsp_lock);
738                         idr_remove(&allocated_dsp, new_dev->idx);
739                         mutex_unlock(&allocated_dsp_lock);
740                         ret = -EINVAL;
741                 }
742         }
743         kfree(new_dev);
744         return ERR_PTR(ret);
745 }
746 EXPORT_SYMBOL(rk_display_device_register);
747
748 void rk_display_device_unregister(struct rk_display_device *ddev)
749 {
750         if (!ddev)
751                 return;
752         /* Free device */
753         mutex_lock(&ddev->lock);
754         device_unregister(ddev->dev);
755         mutex_unlock(&ddev->lock);
756         /* Mark device index as available */
757         mutex_lock(&allocated_dsp_lock);
758         idr_remove(&allocated_dsp, ddev->idx);
759         mutex_unlock(&allocated_dsp_lock);
760         list_del(&ddev->list);
761         kfree(ddev);
762 }
763 EXPORT_SYMBOL(rk_display_device_unregister);
764
765 static int __init rk_display_class_init(void)
766 {
767         display_class = class_create(THIS_MODULE, "display");
768         if (IS_ERR(display_class)) {
769                 pr_err("Failed to create display class\n");
770                 display_class = NULL;
771                 return -EINVAL;
772         }
773         display_class->dev_groups = display_device_groups;
774         display_class->suspend = display_suspend;
775         display_class->resume = display_resume;
776         mutex_init(&allocated_dsp_lock);
777         INIT_LIST_HEAD(&main_display_device_list);
778         INIT_LIST_HEAD(&aux_display_device_list);
779         return 0;
780 }
781
782 static void __exit rk_display_class_exit(void)
783 {
784         class_destroy(display_class);
785 }
786
787 subsys_initcall(rk_display_class_init);
788 module_exit(rk_display_class_exit);
789
790 MODULE_AUTHOR("zhengyang@rock-chips.com");
791 MODULE_DESCRIPTION("Driver for rk display device");
792 MODULE_LICENSE("GPL");