Merge remote-tracking branch 'origin/develop-3.10-next' into develop-3.10
[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 struct device_attribute display_attrs[] = {
193         __ATTR(name, S_IRUGO, display_show_name, NULL),
194         __ATTR(type, S_IRUGO, display_show_type, NULL),
195         __ATTR(enable, 0664, display_show_enable, display_store_enable),
196         __ATTR(connect, S_IRUGO, display_show_connect, NULL),
197         __ATTR(modes, S_IRUGO, display_show_modes, NULL),
198         __ATTR(mode, 0664, display_show_mode, display_store_mode),
199         __ATTR(scale, 0664, display_show_scale, display_store_scale),
200         __ATTR_NULL
201 };
202
203 static int display_suspend(struct device *dev, pm_message_t state)
204 {
205         struct rk_display_device *dsp = dev_get_drvdata(dev);
206
207         mutex_lock(&dsp->lock);
208         if (likely(dsp->driver->suspend))
209                 dsp->driver->suspend(dsp, state);
210         mutex_unlock(&dsp->lock);
211         return 0;
212 };
213
214 static int display_resume(struct device *dev)
215 {
216         struct rk_display_device *dsp = dev_get_drvdata(dev);
217
218         mutex_lock(&dsp->lock);
219         if (likely(dsp->driver->resume))
220                 dsp->driver->resume(dsp);
221         mutex_unlock(&dsp->lock);
222         return 0;
223 };
224
225 void rk_display_device_enable(struct rk_display_device *ddev)
226 {
227 //#ifndef CONFIG_DISPLAY_AUTO_SWITCH    
228 //      return;
229 //#else
230         struct list_head *pos, *head = &display_device_list;
231         struct rk_display_device *dev = NULL, *dev_enabled = NULL, *dev_enable = NULL;
232         int enable = 0,connect;
233         
234         list_for_each(pos, head) {
235                 dev = list_entry(pos, struct rk_display_device, list);
236                 enable = dev->ops->getenable(dev);
237                 connect = dev->ops->getstatus(dev);
238                 if(connect)
239                         dev_enable = dev;
240                 if(enable == 1)
241                         dev_enabled = dev;
242         }
243         // If no device is connected, enable highest priority device.
244         if(dev_enable == NULL) {
245                 dev->ops->setenable(dev, 1);
246                 return;
247         }
248         
249         if(dev_enable == dev_enabled) {
250                 if(dev_enable != ddev)
251                         ddev->ops->setenable(ddev, 0);
252         }
253         else {
254                 if(dev_enabled)
255                         dev_enabled->ops->setenable(dev_enabled, 0);
256                 dev_enable->ops->setenable(dev_enable, 1);
257         }
258                 
259
260 //#endif
261 }
262 EXPORT_SYMBOL(rk_display_device_enable);
263
264 void rk_display_device_enable_other(struct rk_display_device *ddev)
265 {
266 #ifndef CONFIG_DISPLAY_AUTO_SWITCH      
267         return;
268 #else
269         struct list_head *pos, *head = &display_device_list;
270         struct rk_display_device *dev;  
271         int connect = 0;
272         
273         list_for_each_prev(pos, head) {
274                 dev = list_entry(pos, struct rk_display_device, list);
275                 if(dev != ddev)
276                 {
277                         connect = dev->ops->getstatus(dev);
278                         if(connect)
279                         {
280                                 dev->ops->setenable(dev, 1);
281                                 return;
282                         }
283                 }
284         }
285 #endif
286 }
287 EXPORT_SYMBOL(rk_display_device_enable_other);
288
289 void rk_display_device_disable_other(struct rk_display_device *ddev)
290 {
291 #ifndef CONFIG_DISPLAY_AUTO_SWITCH
292         return;
293 #else
294         struct list_head *pos, *head = &display_device_list;
295         struct rk_display_device *dev;  
296         int enable = 0;
297         
298         list_for_each(pos, head) {
299                 dev = list_entry(pos, struct rk_display_device, list);
300                 if(dev != ddev)
301                 {
302                         enable = dev->ops->getenable(dev);
303                         if(enable)
304                                 dev->ops->setenable(dev, 0);
305                 }
306         }
307         ddev->ops->setenable(ddev, 1);
308 #endif
309 }
310 EXPORT_SYMBOL(rk_display_device_disable_other);
311
312 void rk_display_device_select(int priority)
313 {
314         struct list_head *pos, *head = &display_device_list;
315         struct rk_display_device *dev;
316         int enable, found = 0;
317         
318         list_for_each(pos, head) {
319                 dev = list_entry(pos, struct rk_display_device, list);
320                 if(dev->priority == priority)
321                         found = 1;
322         }
323         
324         if(!found)
325         {
326                 printk("[%s] select display interface %d not exist\n", __FUNCTION__, priority);
327                 return;
328         }
329         
330         list_for_each(pos, head) {
331                 dev = list_entry(pos, struct rk_display_device, list);
332                 enable = dev->ops->getenable(dev);
333                 if(dev->priority == priority)
334                 {
335                         if(!enable)     
336                                 dev->ops->setenable(dev, 1);
337                 }
338                 else if(enable) 
339                         dev->ops->setenable(dev, 0);
340         }
341 }
342 EXPORT_SYMBOL(rk_display_device_select);
343 static struct mutex allocated_dsp_lock;
344 static DEFINE_IDR(allocated_dsp);
345 static struct class *display_class;
346
347 struct rk_display_device *rk_display_device_register(struct rk_display_driver *driver,
348                                                 struct device *parent, void *devdata)
349 {
350         struct rk_display_device *new_dev = NULL;
351         int ret = -EINVAL;
352
353         if (unlikely(!driver))
354                 return ERR_PTR(ret);
355
356         new_dev = kzalloc(sizeof(struct rk_display_device), GFP_KERNEL);
357         if (likely(new_dev) && unlikely(driver->probe(new_dev, devdata))) {
358                 // Reserve the index for this display
359                 mutex_lock(&allocated_dsp_lock);
360                 new_dev->idx = idr_alloc(&allocated_dsp, new_dev, 0, 0, GFP_KERNEL);
361                 mutex_unlock(&allocated_dsp_lock);
362
363                 if (new_dev->idx >= 0) {
364                         new_dev->dev = device_create(display_class, parent,
365                                                      MKDEV(0, 0), new_dev,
366                                                      "%s", new_dev->type);
367                         if (!IS_ERR(new_dev->dev)) {
368                                 new_dev->parent = parent;
369                                 new_dev->driver = driver;
370                                 if(parent)
371                                         new_dev->dev->driver = parent->driver;
372                                 mutex_init(&new_dev->lock);
373                                 // Add new device to display device list.
374                                 {
375                                         struct list_head *pos, *head = &display_device_list;
376                                         struct rk_display_device *dev;
377                                         
378                                         list_for_each(pos, head) {
379                                                 dev = list_entry(pos, struct rk_display_device, list);
380                                                 if(dev->priority > new_dev->priority)
381                                                         break;
382                                         }
383                                         list_add_tail(&new_dev->list, pos);
384                                 }
385                                 return new_dev;
386                         }
387                         mutex_lock(&allocated_dsp_lock);
388                         idr_remove(&allocated_dsp, new_dev->idx);
389                         mutex_unlock(&allocated_dsp_lock);
390                         ret = -EINVAL;
391                 }
392         }
393         kfree(new_dev);
394         return ERR_PTR(ret);
395 }
396 EXPORT_SYMBOL(rk_display_device_register);
397
398 void rk_display_device_unregister(struct rk_display_device *ddev)
399 {
400         if (!ddev)
401                 return;
402         // Free device
403         mutex_lock(&ddev->lock);
404         device_unregister(ddev->dev);
405         mutex_unlock(&ddev->lock);
406         // Mark device index as avaliable
407         mutex_lock(&allocated_dsp_lock);
408         idr_remove(&allocated_dsp, ddev->idx);
409         mutex_unlock(&allocated_dsp_lock);
410         list_del(&ddev->list);
411         kfree(ddev);
412 }
413 EXPORT_SYMBOL(rk_display_device_unregister);
414
415 static int __init rk_display_class_init(void)
416 {
417         display_class = class_create(THIS_MODULE, "display");
418         if (IS_ERR(display_class)) {
419                 printk(KERN_ERR "Failed to create display class\n");
420                 display_class = NULL;
421                 return -EINVAL;
422         }
423         display_class->dev_attrs = display_attrs;
424         display_class->suspend = display_suspend;
425         display_class->resume = display_resume;
426         mutex_init(&allocated_dsp_lock);
427         INIT_LIST_HEAD(&display_device_list);
428         return 0;
429 }
430
431 static void __exit rk_display_class_exit(void)
432 {
433         class_destroy(display_class);
434 }
435
436 subsys_initcall(rk_display_class_init);
437 module_exit(rk_display_class_exit);
438
439
440 MODULE_AUTHOR("zhengyang@rock-chips.com");
441 MODULE_DESCRIPTION("Driver for rk display device");
442 MODULE_LICENSE("GPL");