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