3501d40a379ce206d852beb449680cd405930fd2
[firefly-linux-kernel-4.4.55.git] / drivers / video / display / 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 struct device_attribute display_attrs[] = {
152         __ATTR(name, S_IRUGO, display_show_name, NULL),
153         __ATTR(type, S_IRUGO, display_show_type, NULL),
154         __ATTR(enable, S_IRUGO | /*S_IWUGO*/S_IWUSR, display_show_enable, display_store_enable),
155         __ATTR(connect, S_IRUGO, display_show_connect, NULL),
156         __ATTR(modes, S_IRUGO, display_show_modes, NULL),
157         __ATTR(mode, S_IRUGO | /*S_IWUGO*/S_IWUSR, display_show_mode, display_store_mode)
158 };
159
160 static int display_suspend(struct device *dev, pm_message_t state)
161 {
162         struct rk_display_device *dsp = dev_get_drvdata(dev);
163
164         mutex_lock(&dsp->lock);
165         if (likely(dsp->driver->suspend))
166                 dsp->driver->suspend(dsp, state);
167         mutex_unlock(&dsp->lock);
168         return 0;
169 };
170
171 static int display_resume(struct device *dev)
172 {
173         struct rk_display_device *dsp = dev_get_drvdata(dev);
174
175         mutex_lock(&dsp->lock);
176         if (likely(dsp->driver->resume))
177                 dsp->driver->resume(dsp);
178         mutex_unlock(&dsp->lock);
179         return 0;
180 };
181
182 void rk_display_device_enable(struct rk_display_device *ddev)
183 {
184 #ifndef CONFIG_DISPLAY_AUTO_SWITCH      
185         return;
186 #else
187         struct list_head *pos, *head = &display_device_list;
188         struct rk_display_device *dev = NULL, *dev_enabled = NULL, *dev_enable = NULL;
189         int enable = 0,connect, has_connect = 0;
190         
191         list_for_each(pos, head) {
192                 dev = list_entry(pos, struct rk_display_device, list);
193                 enable = dev->ops->getenable(dev);
194                 connect = dev->ops->getstatus(dev);
195                 if(connect)
196                         dev_enable = dev;
197                 if(enable == 1)
198                         dev_enabled = dev;
199         }
200         // If no device is connected, enable highest priority device.
201         if(dev_enable == NULL) {
202                 dev->ops->setenable(dev, 1);
203                 return;
204         }
205         
206         if(dev_enable == dev_enabled) {
207                 if(dev_enable != ddev)
208                         ddev->ops->setenable(ddev, 0);
209         }
210         else {
211                 if(dev_enabled)
212                         dev_enabled->ops->setenable(dev_enabled, 0);
213                 dev_enable->ops->setenable(dev_enable, 1);
214         }
215                 
216
217 #endif
218 }
219 EXPORT_SYMBOL(rk_display_device_enable);
220
221 void rk_display_device_enable_other(struct rk_display_device *ddev)
222 {
223 #ifndef CONFIG_DISPLAY_AUTO_SWITCH      
224         return;
225 #else
226         struct list_head *pos, *head = &display_device_list;
227         struct rk_display_device *dev;  
228         int connect = 0;
229         
230         list_for_each_prev(pos, head) {
231                 dev = list_entry(pos, struct rk_display_device, list);
232                 if(dev != ddev)
233                 {
234                         connect = dev->ops->getstatus(dev);
235                         if(connect)
236                         {
237                                 dev->ops->setenable(dev, 1);
238                                 return;
239                         }
240                 }
241         }
242 #endif
243 }
244 EXPORT_SYMBOL(rk_display_device_enable_other);
245
246 void rk_display_device_disable_other(struct rk_display_device *ddev)
247 {
248 #ifndef CONFIG_DISPLAY_AUTO_SWITCH
249         return;
250 #else
251         struct list_head *pos, *head = &display_device_list;
252         struct rk_display_device *dev;  
253         int enable = 0;
254         
255         list_for_each(pos, head) {
256                 dev = list_entry(pos, struct rk_display_device, list);
257                 if(dev != ddev)
258                 {
259                         enable = dev->ops->getenable(dev);
260                         if(enable)
261                                 dev->ops->setenable(dev, 0);
262                 }
263         }
264         ddev->ops->setenable(ddev, 1);
265 #endif
266 }
267 EXPORT_SYMBOL(rk_display_device_disable_other);
268
269 void rk_display_device_select(int priority)
270 {
271         struct list_head *pos, *head = &display_device_list;
272         struct rk_display_device *dev;
273         int enable, found = 0;
274         
275         list_for_each(pos, head) {
276                 dev = list_entry(pos, struct rk_display_device, list);
277                 if(dev->priority == priority)
278                         found = 1;
279         }
280         
281         if(!found)
282         {
283                 printk("[%s] select display interface %d not exist\n", __FUNCTION__, priority);
284                 return;
285         }
286         
287         list_for_each(pos, head) {
288                 dev = list_entry(pos, struct rk_display_device, list);
289                 enable = dev->ops->getenable(dev);
290                 if(dev->priority == priority)
291                 {
292                         if(!enable)     
293                                 dev->ops->setenable(dev, 1);
294                 }
295                 else if(enable) 
296                         dev->ops->setenable(dev, 0);
297         }
298 }
299 EXPORT_SYMBOL(rk_display_device_select);
300 static struct mutex allocated_dsp_lock;
301 static DEFINE_IDR(allocated_dsp);
302 static struct class *display_class;
303
304 struct rk_display_device *rk_display_device_register(struct rk_display_driver *driver,
305                                                 struct device *parent, void *devdata)
306 {
307         struct rk_display_device *new_dev = NULL;
308         int ret = -EINVAL;
309
310         if (unlikely(!driver))
311                 return ERR_PTR(ret);
312
313         mutex_lock(&allocated_dsp_lock);
314         ret = idr_pre_get(&allocated_dsp, GFP_KERNEL);
315         mutex_unlock(&allocated_dsp_lock);
316         if (!ret)
317                 return ERR_PTR(ret);
318
319         new_dev = kzalloc(sizeof(struct rk_display_device), GFP_KERNEL);
320         if (likely(new_dev) && unlikely(driver->probe(new_dev, devdata))) {
321                 // Reserve the index for this display
322                 mutex_lock(&allocated_dsp_lock);
323                 ret = idr_get_new(&allocated_dsp, new_dev, &new_dev->idx);
324                 mutex_unlock(&allocated_dsp_lock);
325
326                 if (!ret) {
327                         new_dev->dev = device_create(display_class, parent,
328                                                      MKDEV(0, 0), new_dev,
329                                                      "%s", new_dev->type);
330                         if (!IS_ERR(new_dev->dev)) {
331                                 new_dev->parent = parent;
332                                 new_dev->driver = driver;
333                                 new_dev->dev->driver = parent->driver;
334                                 mutex_init(&new_dev->lock);
335                                 // Add new device to display device list.
336                                 {
337                                         struct list_head *pos, *head = &display_device_list;
338                                         struct rk_display_device *dev;
339                                         
340                                         list_for_each(pos, head) {
341                                                 dev = list_entry(pos, struct rk_display_device, list);
342                                                 if(dev->priority > new_dev->priority)
343                                                         break;
344                                         }
345                                         list_add_tail(&new_dev->list, pos);
346                                 }
347                                 return new_dev;
348                         }
349                         mutex_lock(&allocated_dsp_lock);
350                         idr_remove(&allocated_dsp, new_dev->idx);
351                         mutex_unlock(&allocated_dsp_lock);
352                         ret = -EINVAL;
353                 }
354         }
355         kfree(new_dev);
356         return ERR_PTR(ret);
357 }
358 EXPORT_SYMBOL(rk_display_device_register);
359
360 void rk_display_device_unregister(struct rk_display_device *ddev)
361 {
362         if (!ddev)
363                 return;
364         // Free device
365         mutex_lock(&ddev->lock);
366         device_unregister(ddev->dev);
367         mutex_unlock(&ddev->lock);
368         // Mark device index as avaliable
369         mutex_lock(&allocated_dsp_lock);
370         idr_remove(&allocated_dsp, ddev->idx);
371         mutex_unlock(&allocated_dsp_lock);
372         list_del(&ddev->list);
373         kfree(ddev);
374 }
375 EXPORT_SYMBOL(rk_display_device_unregister);
376
377 static int __init rk_display_class_init(void)
378 {
379         display_class = class_create(THIS_MODULE, "display");
380         if (IS_ERR(display_class)) {
381                 printk(KERN_ERR "Failed to create display class\n");
382                 display_class = NULL;
383                 return -EINVAL;
384         }
385         display_class->dev_attrs = display_attrs;
386         display_class->suspend = display_suspend;
387         display_class->resume = display_resume;
388         mutex_init(&allocated_dsp_lock);
389         INIT_LIST_HEAD(&display_device_list);
390         return 0;
391 }
392
393 static void __exit rk_display_class_exit(void)
394 {
395         class_destroy(display_class);
396 }
397
398 subsys_initcall(rk_display_class_init);
399 module_exit(rk_display_class_exit);
400
401
402 MODULE_AUTHOR("zhengyang@rock-chips.com");
403 MODULE_DESCRIPTION("Driver for rk display device");
404 MODULE_LICENSE("GPL");