rk_fb: sysfs: make use vmap/vunmap in pairs.
[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 display_device_list;
9
10 static ssize_t display_show_name(struct device *dev,
11                                 struct device_attribute *attr, char *buf)
12 {
13         struct rk_display_device *dsp = dev_get_drvdata(dev);
14         return snprintf(buf, PAGE_SIZE, "%s\n", dsp->name);
15 }
16
17 static ssize_t display_show_type(struct device *dev,
18                                 struct device_attribute *attr, char *buf)
19 {
20         struct rk_display_device *dsp = dev_get_drvdata(dev);
21         return snprintf(buf, PAGE_SIZE, "%s\n", dsp->type);
22 }
23
24 static ssize_t display_show_enable(struct device *dev,
25                                 struct device_attribute *attr, char *buf)
26 {
27         struct rk_display_device *dsp = dev_get_drvdata(dev);
28         int enable;
29         if(dsp->ops && dsp->ops->getenable)
30                 enable = dsp->ops->getenable(dsp);
31         else
32                 return 0;
33         return snprintf(buf, PAGE_SIZE, "%d\n", enable);
34 }
35
36 static ssize_t display_store_enable(struct device *dev, 
37                                                 struct device_attribute *attr,
38                                                 const char *buf, size_t size)
39 {
40         struct rk_display_device *dsp = dev_get_drvdata(dev);
41         int enable;
42         
43         sscanf(buf, "%d", &enable);
44         if(dsp->ops && dsp->ops->setenable)
45                 dsp->ops->setenable(dsp, enable);
46         return size;
47 }
48
49 static ssize_t display_show_connect(struct device *dev,
50                                 struct device_attribute *attr, char *buf)
51 {
52         struct rk_display_device *dsp = dev_get_drvdata(dev);
53         int connect;
54         if(dsp->ops && dsp->ops->getstatus)
55                 connect = dsp->ops->getstatus(dsp);
56         else
57                 return 0;
58         return snprintf(buf, PAGE_SIZE, "%d\n", connect);
59 }
60
61 static int mode_string(char *buf, unsigned int offset,
62                        const struct fb_videomode *mode)
63 {
64 //      char m = 'U';
65         char v = 'p';
66
67 //      if (mode->flag & FB_MODE_IS_DETAILED)
68 //              m = 'D';
69 //      if (mode->flag & FB_MODE_IS_VESA)
70 //              m = 'V';
71 //      if (mode->flag & FB_MODE_IS_STANDARD)
72 //              m = 'S';
73
74         if (mode->vmode & FB_VMODE_INTERLACED)
75                 v = 'i';
76         if (mode->vmode & FB_VMODE_DOUBLE)
77                 v = 'd';
78
79         return snprintf(&buf[offset], PAGE_SIZE - offset, "%dx%d%c-%d\n",
80                         mode->xres, mode->yres, v, mode->refresh);
81 }
82 static ssize_t display_show_modes(struct device *dev,
83                                 struct device_attribute *attr, char *buf)
84 {
85         struct rk_display_device *dsp = dev_get_drvdata(dev);
86         struct list_head *modelist, *pos;
87         struct fb_modelist *fb_modelist;
88         const struct fb_videomode *mode;
89         int i;
90         if(dsp->ops && dsp->ops->getmodelist)
91         {
92                 if(dsp->ops->getmodelist(dsp, &modelist))
93                         return -EINVAL;
94         }
95         else
96                 return 0;
97
98         i = 0;
99         list_for_each(pos, modelist) {
100                 fb_modelist = list_entry(pos, struct fb_modelist, list);
101                 mode = &fb_modelist->mode;
102                 i += mode_string(buf, i, mode);
103         }
104         return i;
105 }
106
107 static ssize_t display_show_mode(struct device *dev,
108                                 struct device_attribute *attr, char *buf)
109 {
110         struct rk_display_device *dsp = dev_get_drvdata(dev);
111         struct fb_videomode mode;
112         
113         if(dsp->ops && dsp->ops->getmode)
114                 if(dsp->ops->getmode(dsp, &mode) == 0)
115                         return mode_string(buf, 0, &mode);
116         return 0;
117 }
118
119 static ssize_t display_store_mode(struct device *dev, 
120                                                 struct device_attribute *attr,
121                                                 const char *buf, size_t count)
122 {
123         struct rk_display_device *dsp = dev_get_drvdata(dev);
124         char mstr[100];
125         struct list_head *modelist, *pos;
126         struct fb_modelist *fb_modelist;
127         struct fb_videomode *mode;     
128         size_t i;                   
129
130         if(dsp->ops && dsp->ops->getmodelist)
131         {
132                 if(dsp->ops && dsp->ops->getmodelist)
133                 {
134                         if(dsp->ops->getmodelist(dsp, &modelist))
135                                 return -EINVAL;
136                 }
137                 list_for_each(pos, modelist) {
138                         fb_modelist = list_entry(pos, struct fb_modelist, list);
139                         mode = &fb_modelist->mode;
140                         i = mode_string(mstr, 0, mode);
141                         if (strncmp(mstr, buf, max(count, i)) == 0) {
142                                 if(dsp->ops && dsp->ops->setmode)
143                                         dsp->ops->setmode(dsp, mode);
144                                 return count;
145                         }
146                 }
147         }
148         return -EINVAL;
149 }
150
151 static ssize_t display_show_scale(struct device *dev,
152                                 struct device_attribute *attr, char *buf)
153 {
154         struct rk_display_device *dsp = dev_get_drvdata(dev);
155         int xscale, yscale;
156         
157         if(dsp->ops && dsp->ops->getscale) {
158                 xscale = dsp->ops->getscale(dsp, DISPLAY_SCALE_X);
159                 yscale = dsp->ops->getscale(dsp, DISPLAY_SCALE_Y);
160                 if(xscale && yscale)
161                         return snprintf(buf, PAGE_SIZE, "xscale=%d yscale=%d\n", xscale, yscale);
162         }
163         return -EINVAL;
164 }
165
166 static ssize_t display_store_scale(struct device *dev, 
167                                                 struct device_attribute *attr,
168                                                 const char *buf, size_t count)
169 {
170         struct rk_display_device *dsp = dev_get_drvdata(dev);
171         int scale = 100;
172         
173         if(dsp->ops && dsp->ops->setscale) {
174                 if(!strncmp(buf, "xscale", 6)) {
175                         sscanf(buf, "xscale=%d", &scale);
176                         dsp->ops->setscale(dsp, DISPLAY_SCALE_X, scale);
177                 }
178                 else if(!strncmp(buf, "yscale", 6)) {
179                         sscanf(buf, "yscale=%d", &scale);
180                         dsp->ops->setscale(dsp, DISPLAY_SCALE_Y, scale);
181                 }
182                 else {
183                         sscanf(buf, "%d", &scale);
184                         dsp->ops->setscale(dsp, DISPLAY_SCALE_X, scale);
185                         dsp->ops->setscale(dsp, DISPLAY_SCALE_Y, scale);
186                 }
187                 return count;
188         }
189         return -EINVAL;
190 }
191
192 static ssize_t display_show_debug(struct device *dev,
193                                 struct device_attribute *attr, char *buf)
194 {
195         return -EINVAL;
196 }
197
198 static ssize_t display_store_debug(struct device *dev,
199                                         struct device_attribute *attr,
200                                         const char *buf, size_t count)
201 {
202         int cmd;
203         struct rk_display_device *dsp = dev_get_drvdata(dev);
204
205         if(dsp->ops && dsp->ops->setdebug) {
206                 sscanf(buf, "%d", &cmd);
207                 dsp->ops->setdebug(dsp, cmd);
208                 return count;
209         }
210         return -EINVAL;
211 }
212
213 static ssize_t display_show_sinkaudioinfo(struct device *dev,
214                                 struct device_attribute *attr, char *buf)
215 {
216         struct rk_display_device *dsp = dev_get_drvdata(dev);
217         char audioinfo[200];
218         int ret=0;
219
220         if(dsp->ops && dsp->ops->getedidaudioinfo) {
221                 ret = dsp->ops->getedidaudioinfo(dsp, audioinfo, 200);
222                 if(!ret){
223                         return snprintf(buf, PAGE_SIZE, "%s\n", audioinfo);
224                 }
225         }
226         return -EINVAL;
227 }
228
229
230
231 static ssize_t display_show_monspecs(struct device *dev,
232                                 struct device_attribute *attr, char *buf)
233 {
234         struct rk_display_device *dsp = dev_get_drvdata(dev);
235         struct fb_monspecs monspecs;
236         int ret = 0;
237         if(dsp->ops && dsp->ops->getmonspecs) {
238                 ret = dsp->ops->getmonspecs(dsp,&monspecs);
239                 if(!ret) {
240                         memcpy(buf, &monspecs, sizeof(struct fb_monspecs));
241                         return sizeof(struct fb_monspecs);//snprintf(buf, PAGE_SIZE, "%s\n", monspecs.monitor);
242                 }
243         }
244         return -EINVAL;
245 }
246
247
248 static struct device_attribute display_attrs[] = {
249         __ATTR(name, S_IRUGO, display_show_name, NULL),
250         __ATTR(type, S_IRUGO, display_show_type, NULL),
251         __ATTR(enable, 0664, display_show_enable, display_store_enable),
252         __ATTR(connect, S_IRUGO, display_show_connect, NULL),
253         __ATTR(modes, S_IRUGO, display_show_modes, NULL),
254         __ATTR(mode, 0664, display_show_mode, display_store_mode),
255         __ATTR(scale, 0664, display_show_scale, display_store_scale),
256         __ATTR(debug, 0664, display_show_debug, display_store_debug),
257         __ATTR(audioinfo, S_IRUGO, display_show_sinkaudioinfo, NULL),
258         __ATTR(monspecs, S_IRUGO, display_show_monspecs, NULL),
259         __ATTR_NULL
260 };
261
262 static int display_suspend(struct device *dev, pm_message_t state)
263 {
264         struct rk_display_device *dsp = dev_get_drvdata(dev);
265
266         mutex_lock(&dsp->lock);
267         if (likely(dsp->driver->suspend))
268                 dsp->driver->suspend(dsp, state);
269         mutex_unlock(&dsp->lock);
270         return 0;
271 };
272
273 static int display_resume(struct device *dev)
274 {
275         struct rk_display_device *dsp = dev_get_drvdata(dev);
276
277         mutex_lock(&dsp->lock);
278         if (likely(dsp->driver->resume))
279                 dsp->driver->resume(dsp);
280         mutex_unlock(&dsp->lock);
281         return 0;
282 };
283
284 void rk_display_device_enable(struct rk_display_device *ddev)
285 {
286 //#ifndef CONFIG_DISPLAY_AUTO_SWITCH    
287 //      return;
288 //#else
289         struct list_head *pos, *head = &display_device_list;
290         struct rk_display_device *dev = NULL, *dev_enabled = NULL, *dev_enable = NULL;
291         int enable = 0,connect;
292         
293         list_for_each(pos, head) {
294                 dev = list_entry(pos, struct rk_display_device, list);
295                 enable = dev->ops->getenable(dev);
296                 connect = dev->ops->getstatus(dev);
297                 if(connect)
298                         dev_enable = dev;
299                 if(enable == 1)
300                         dev_enabled = dev;
301         }
302         // If no device is connected, enable highest priority device.
303         if(dev_enable == NULL) {
304                 dev->ops->setenable(dev, 1);
305                 return;
306         }
307         
308         if(dev_enable == dev_enabled) {
309                 if(dev_enable != ddev)
310                         ddev->ops->setenable(ddev, 0);
311         }
312         else {
313                 if(dev_enabled)
314                         dev_enabled->ops->setenable(dev_enabled, 0);
315                 dev_enable->ops->setenable(dev_enable, 1);
316         }
317                 
318
319 //#endif
320 }
321 EXPORT_SYMBOL(rk_display_device_enable);
322
323 void rk_display_device_enable_other(struct rk_display_device *ddev)
324 {
325 #ifndef CONFIG_DISPLAY_AUTO_SWITCH      
326         return;
327 #else
328         struct list_head *pos, *head = &display_device_list;
329         struct rk_display_device *dev;  
330         int connect = 0;
331         
332         list_for_each_prev(pos, head) {
333                 dev = list_entry(pos, struct rk_display_device, list);
334                 if(dev != ddev)
335                 {
336                         connect = dev->ops->getstatus(dev);
337                         if(connect)
338                         {
339                                 dev->ops->setenable(dev, 1);
340                                 return;
341                         }
342                 }
343         }
344 #endif
345 }
346 EXPORT_SYMBOL(rk_display_device_enable_other);
347
348 void rk_display_device_disable_other(struct rk_display_device *ddev)
349 {
350 #ifndef CONFIG_DISPLAY_AUTO_SWITCH
351         return;
352 #else
353         struct list_head *pos, *head = &display_device_list;
354         struct rk_display_device *dev;  
355         int enable = 0;
356         
357         list_for_each(pos, head) {
358                 dev = list_entry(pos, struct rk_display_device, list);
359                 if(dev != ddev)
360                 {
361                         enable = dev->ops->getenable(dev);
362                         if(enable)
363                                 dev->ops->setenable(dev, 0);
364                 }
365         }
366         ddev->ops->setenable(ddev, 1);
367 #endif
368 }
369 EXPORT_SYMBOL(rk_display_device_disable_other);
370
371 void rk_display_device_select(int priority)
372 {
373         struct list_head *pos, *head = &display_device_list;
374         struct rk_display_device *dev;
375         int enable, found = 0;
376         
377         list_for_each(pos, head) {
378                 dev = list_entry(pos, struct rk_display_device, list);
379                 if(dev->priority == priority)
380                         found = 1;
381         }
382         
383         if(!found)
384         {
385                 printk("[%s] select display interface %d not exist\n", __FUNCTION__, priority);
386                 return;
387         }
388         
389         list_for_each(pos, head) {
390                 dev = list_entry(pos, struct rk_display_device, list);
391                 enable = dev->ops->getenable(dev);
392                 if(dev->priority == priority)
393                 {
394                         if(!enable)     
395                                 dev->ops->setenable(dev, 1);
396                 }
397                 else if(enable) 
398                         dev->ops->setenable(dev, 0);
399         }
400 }
401 EXPORT_SYMBOL(rk_display_device_select);
402 static struct mutex allocated_dsp_lock;
403 static DEFINE_IDR(allocated_dsp);
404 static struct class *display_class;
405
406 struct rk_display_device *rk_display_device_register(struct rk_display_driver *driver,
407                                                 struct device *parent, void *devdata)
408 {
409         struct rk_display_device *new_dev = NULL;
410         int ret = -EINVAL;
411
412         if (unlikely(!driver))
413                 return ERR_PTR(ret);
414
415         new_dev = kzalloc(sizeof(struct rk_display_device), GFP_KERNEL);
416         if (likely(new_dev) && unlikely(driver->probe(new_dev, devdata))) {
417                 // Reserve the index for this display
418                 mutex_lock(&allocated_dsp_lock);
419                 new_dev->idx = idr_alloc(&allocated_dsp, new_dev, 0, 0, GFP_KERNEL);
420                 mutex_unlock(&allocated_dsp_lock);
421
422                 if (new_dev->idx >= 0) {
423                         new_dev->dev = device_create(display_class, parent,
424                                                      MKDEV(0, 0), new_dev,
425                                                      "%s", new_dev->type);
426                         if (!IS_ERR(new_dev->dev)) {
427                                 new_dev->parent = parent;
428                                 new_dev->driver = driver;
429                                 if(parent)
430                                         new_dev->dev->driver = parent->driver;
431                                 mutex_init(&new_dev->lock);
432                                 // Add new device to display device list.
433                                 {
434                                         struct list_head *pos, *head = &display_device_list;
435                                         struct rk_display_device *dev;
436                                         
437                                         list_for_each(pos, head) {
438                                                 dev = list_entry(pos, struct rk_display_device, list);
439                                                 if(dev->priority > new_dev->priority)
440                                                         break;
441                                         }
442                                         list_add_tail(&new_dev->list, pos);
443                                 }
444                                 return new_dev;
445                         }
446                         mutex_lock(&allocated_dsp_lock);
447                         idr_remove(&allocated_dsp, new_dev->idx);
448                         mutex_unlock(&allocated_dsp_lock);
449                         ret = -EINVAL;
450                 }
451         }
452         kfree(new_dev);
453         return ERR_PTR(ret);
454 }
455 EXPORT_SYMBOL(rk_display_device_register);
456
457 void rk_display_device_unregister(struct rk_display_device *ddev)
458 {
459         if (!ddev)
460                 return;
461         // Free device
462         mutex_lock(&ddev->lock);
463         device_unregister(ddev->dev);
464         mutex_unlock(&ddev->lock);
465         // Mark device index as avaliable
466         mutex_lock(&allocated_dsp_lock);
467         idr_remove(&allocated_dsp, ddev->idx);
468         mutex_unlock(&allocated_dsp_lock);
469         list_del(&ddev->list);
470         kfree(ddev);
471 }
472 EXPORT_SYMBOL(rk_display_device_unregister);
473
474 static int __init rk_display_class_init(void)
475 {
476         display_class = class_create(THIS_MODULE, "display");
477         if (IS_ERR(display_class)) {
478                 printk(KERN_ERR "Failed to create display class\n");
479                 display_class = NULL;
480                 return -EINVAL;
481         }
482         display_class->dev_attrs = display_attrs;
483         display_class->suspend = display_suspend;
484         display_class->resume = display_resume;
485         mutex_init(&allocated_dsp_lock);
486         INIT_LIST_HEAD(&display_device_list);
487         return 0;
488 }
489
490 static void __exit rk_display_class_exit(void)
491 {
492         class_destroy(display_class);
493 }
494
495 subsys_initcall(rk_display_class_init);
496 module_exit(rk_display_class_exit);
497
498
499 MODULE_AUTHOR("zhengyang@rock-chips.com");
500 MODULE_DESCRIPTION("Driver for rk display device");
501 MODULE_LICENSE("GPL");