Merge branch 'develop-3.10-next' of 10.10.10.29:rk/kernel into develop-3.10-next
[firefly-linux-kernel-4.4.55.git] / drivers / video / rockchip / hdmi / rockchip-hdmi-sysfs.c
1 #include <linux/ctype.h>
2 #include <linux/string.h>
3 #include <linux/display-sys.h>
4 #include <linux/interrupt.h>
5 #include "rockchip-hdmi.h"
6
7 static int hdmi_get_enable(struct rk_display_device *device)
8 {
9         struct hdmi *hdmi = device->priv_data;
10         int enable;
11
12         enable = hdmi->enable;
13         return enable;
14 }
15
16 static int hdmi_set_enable(struct rk_display_device *device, int enable)
17 {
18         struct hdmi *hdmi = device->priv_data;
19
20         if (enable == 0)
21                 hdmi_submit_work(hdmi, HDMI_DISABLE_CTL, 0, NULL);
22         else
23                 hdmi_submit_work(hdmi, HDMI_ENABLE_CTL, 0, NULL);
24         return 0;
25 }
26
27 static int hdmi_get_status(struct rk_display_device *device)
28 {
29         struct hdmi *hdmi = device->priv_data;
30
31         if (hdmi->hotplug == HDMI_HPD_ACTIVED)
32                 return 1;
33         else
34                 return 0;
35 }
36
37 static int hdmi_get_modelist(struct rk_display_device *device,
38                              struct list_head **modelist)
39 {
40         struct hdmi *hdmi = device->priv_data;
41
42         mutex_lock(&hdmi->lock);
43         *modelist = &hdmi->edid.modelist;
44         mutex_unlock(&hdmi->lock);
45         return 0;
46 }
47
48 static int hdmi_set_mode(struct rk_display_device *device,
49                          struct fb_videomode *mode)
50 {
51         struct hdmi *hdmi = device->priv_data;
52         struct display_modelist *display_modelist =
53                         container_of(mode, struct display_modelist, mode);
54         int vic = 0;
55
56         if (mode == NULL) {
57                 hdmi->autoset = 1;
58                 vic = hdmi_find_best_mode(hdmi, 0);
59         } else {
60                 hdmi->autoset = 0;
61                 vic = display_modelist->vic;
62         }
63
64         if (vic && hdmi->vic != vic) {
65                 hdmi->vic = vic;
66                 if (hdmi->hotplug == HDMI_HPD_ACTIVED)
67                         hdmi_submit_work(hdmi, HDMI_SET_VIDEO, 0, NULL);
68         }
69         return 0;
70 }
71
72 static int hdmi_get_mode(struct rk_display_device *device,
73                          struct fb_videomode *mode)
74 {
75         struct hdmi *hdmi = device->priv_data;
76         struct fb_videomode *vmode;
77
78         if (mode == NULL)
79                 return -1;
80
81         if (hdmi->vic) {
82                 vmode = (struct fb_videomode *)
83                         hdmi_vic_to_videomode(hdmi->vic);
84                 if (unlikely(vmode == NULL))
85                         return -1;
86                 *mode = *vmode;
87                 if (hdmi->vic & HDMI_VIDEO_YUV420)
88                         mode->flag = 1;
89         } else {
90                 memset(mode, 0, sizeof(struct fb_videomode));
91         }
92         return 0;
93 }
94
95 static int hdmi_set_3dmode(struct rk_display_device *device, int mode)
96 {
97         struct hdmi *hdmi = device->priv_data;
98         struct list_head *modelist, *pos;
99         struct display_modelist *display_modelist = NULL;
100
101         if (!hdmi)
102                 return -1;
103         mutex_lock(&hdmi->lock);
104         modelist = &hdmi->edid.modelist;
105         list_for_each(pos, modelist) {
106                 display_modelist =
107                         list_entry(pos, struct display_modelist, list);
108                 if (hdmi->vic == display_modelist->vic)
109                         break;
110                 else
111                         display_modelist = NULL;
112         }
113         mutex_unlock(&hdmi->lock);
114         if (!display_modelist)
115                 return -1;
116
117         if ((mode != HDMI_3D_NONE) &&
118             ((display_modelist->format_3d & (1 << mode)) == 0))
119                 return -1;
120
121         if (hdmi->mode_3d != mode) {
122                 hdmi->mode_3d = mode;
123                 if (hdmi->hotplug == HDMI_HPD_ACTIVED)
124                         hdmi_submit_work(hdmi, HDMI_SET_3D, 0, NULL);
125         }
126         return 0;
127 }
128
129 static int hdmi_get_3dmode(struct rk_display_device *device)
130 {
131         struct hdmi *hdmi = device->priv_data;
132
133         if (!hdmi)
134                 return -1;
135         else
136                 return hdmi->mode_3d;
137 }
138
139 /*CEA 861-E: Audio Coding Type
140   sync width enum hdmi_audio_type
141 */
142 static const char * const audioformatstr[] = {
143         "",
144         "LPCM",         /*HDMI_AUDIO_LPCM = 1,*/
145         "AC3",          /*HDMI_AUDIO_AC3,*/
146         "MPEG1",        /*HDMI_AUDIO_MPEG1,*/
147         "MP3",          /*HDMI_AUDIO_MP3,*/
148         "MPEG2",        /*HDMI_AUDIO_MPEG2,*/
149         "AAC-LC",       /*HDMI_AUDIO_AAC_LC, AAC*/
150         "DTS",          /*HDMI_AUDIO_DTS,*/
151         "ATARC",        /*HDMI_AUDIO_ATARC,*/
152         "DSD",          /*HDMI_AUDIO_DSD, One bit Audio */
153         "E-AC3",        /*HDMI_AUDIO_E_AC3,*/
154         "DTS-HD",       /*HDMI_AUDIO_DTS_HD,*/
155         "MLP",          /*HDMI_AUDIO_MLP,*/
156         "DST",          /*HDMI_AUDIO_DST,*/
157         "WMA-PRO",      /*HDMI_AUDIO_WMA_PRO*/
158 };
159
160 static int hdmi_get_edidaudioinfo(struct rk_display_device *device,
161                                   char *audioinfo, int len)
162 {
163         struct hdmi *hdmi = device->priv_data;
164         int i = 0, size = 0;
165         struct hdmi_audio *audio;
166
167         if (!hdmi)
168                 return -1;
169
170         memset(audioinfo, 0x00, len);
171         mutex_lock(&hdmi->lock);
172         /*printk("hdmi:edid: audio_num: %d\n", hdmi->edid.audio_num);*/
173         for (i = 0; i < hdmi->edid.audio_num; i++) {
174                 audio = &(hdmi->edid.audio[i]);
175                 if (audio->type < 1 || audio->type > HDMI_AUDIO_WMA_PRO) {
176                         pr_info("audio type: unsupported.");
177                         continue;
178                 }
179                 size = strlen(audioformatstr[audio->type]);
180                 memcpy(audioinfo, audioformatstr[audio->type], size);
181                 audioinfo[size] = ',';
182                 audioinfo += (size+1);
183         }
184         mutex_unlock(&hdmi->lock);
185         return 0;
186 }
187
188 static int hdmi_get_color(struct rk_display_device *device, char *buf)
189 {
190         struct hdmi *hdmi = device->priv_data;
191         int i, mode;
192
193         mutex_lock(&hdmi->lock);
194         mode = (1 << HDMI_COLOR_RGB_0_255);
195         if (hdmi->edid.sink_hdmi) {
196                 mode |= (1 << HDMI_COLOR_RGB_16_235);
197                 if (hdmi->edid.ycbcr422)
198                         mode |= (1 << HDMI_COLOR_YCBCR422);
199                 if (hdmi->edid.ycbcr444)
200                         mode |= (1 << HDMI_COLOR_YCBCR444);
201         }
202         i = snprintf(buf, PAGE_SIZE,
203                      "Supported Color Mode: %d\n", mode);
204         i += snprintf(buf + i, PAGE_SIZE - i,
205                       "Current Color Mode: %d\n", hdmi->colormode);
206
207         mode = (1 << 1); /* 24 bit*/
208         if (hdmi->edid.deepcolor & HDMI_DEEP_COLOR_30BITS &&
209             hdmi->property->feature & SUPPORT_DEEP_10BIT)
210                 mode |= (1 << HDMI_DEEP_COLOR_30BITS);
211         if (hdmi->edid.deepcolor & HDMI_DEEP_COLOR_36BITS &&
212             hdmi->property->feature & SUPPORT_DEEP_12BIT)
213                 mode |= (1 << HDMI_DEEP_COLOR_36BITS);
214         if (hdmi->edid.deepcolor & HDMI_DEEP_COLOR_48BITS &&
215             hdmi->property->feature & SUPPORT_DEEP_16BIT)
216                 mode |= (1 << HDMI_DEEP_COLOR_48BITS);
217         i += snprintf(buf + i, PAGE_SIZE - i,
218                       "Supported Color Depth: %d\n", mode);
219         i += snprintf(buf + i, PAGE_SIZE - i,
220                       "Current Color Depth: %d\n", hdmi->colordepth);
221         mutex_unlock(&hdmi->lock);
222         return i;
223 }
224
225 static int hdmi_set_color(struct rk_display_device *device,
226                           const char *buf, int len)
227 {
228         struct hdmi *hdmi = device->priv_data;
229         int value;
230
231         if (!strncmp(buf, "mode", 4)) {
232                 if (sscanf(buf, "mode=%d", &value) == -1)
233                         return -1;
234                 pr_debug("current mode is %d input mode is %d\n",
235                          hdmi->colormode, value);
236                 if (hdmi->colormode != value)
237                         hdmi->colormode = value;
238         } else if (!strncmp(buf, "depth", 5)) {
239                 if (sscanf(buf, "depth=%d", &value) == -1)
240                         return -1;
241                 pr_debug("current depth is %d input mode is %d\n",
242                          hdmi->colordepth, value);
243                 if (hdmi->colordepth != value)
244                         hdmi->colordepth = value;
245         } else {
246                 pr_err("%s unkown event\n", __func__);
247                 return -1;
248         }
249         if (hdmi->hotplug == HDMI_HPD_ACTIVED)
250                 hdmi_submit_work(hdmi, HDMI_SET_COLOR, 0, NULL);
251         return 0;
252 }
253
254 static int hdmi_set_scale(struct rk_display_device *device, int direction,
255                           int value)
256 {
257         struct hdmi *hdmi = device->priv_data;
258
259         if (!hdmi || value < 0 || value > 100)
260                 return -1;
261
262         if (!hdmi->hotplug)
263                 return 0;
264
265         if (direction == DISPLAY_SCALE_X)
266                 hdmi->xscale = value;
267         else if (direction == DISPLAY_SCALE_Y)
268                 hdmi->yscale = value;
269         else
270                 return -1;
271         rk_fb_disp_scale(hdmi->xscale, hdmi->yscale, hdmi->lcdc->id);
272         return 0;
273 }
274
275 static int hdmi_get_scale(struct rk_display_device *device, int direction)
276 {
277         struct hdmi *hdmi = device->priv_data;
278
279         if (!hdmi)
280                 return -1;
281
282         if (direction == DISPLAY_SCALE_X)
283                 return hdmi->xscale;
284         else if (direction == DISPLAY_SCALE_Y)
285                 return hdmi->yscale;
286         else
287                 return -1;
288 }
289
290 static int hdmi_get_monspecs(struct rk_display_device *device,
291                              struct fb_monspecs *monspecs)
292 {
293         struct hdmi *hdmi = device->priv_data;
294
295         if (!hdmi)
296                 return -1;
297
298         mutex_lock(&hdmi->lock);
299         if (hdmi->edid.specs)
300                 *monspecs = *(hdmi->edid.specs);
301         mutex_unlock(&hdmi->lock);
302         return 0;
303 }
304
305 static struct rk_display_ops hdmi_display_ops = {
306         .setenable = hdmi_set_enable,
307         .getenable = hdmi_get_enable,
308         .getstatus = hdmi_get_status,
309         .getmodelist = hdmi_get_modelist,
310         .setmode = hdmi_set_mode,
311         .getmode = hdmi_get_mode,
312         .set3dmode = hdmi_set_3dmode,
313         .get3dmode = hdmi_get_3dmode,
314         .getedidaudioinfo = hdmi_get_edidaudioinfo,
315         .setcolor = hdmi_set_color,
316         .getcolor = hdmi_get_color,
317         .getmonspecs = hdmi_get_monspecs,
318         .setscale = hdmi_set_scale,
319         .getscale = hdmi_get_scale,
320 };
321
322 static int hdmi_display_probe(struct rk_display_device *device, void *devdata)
323 {
324         struct hdmi *hdmi = devdata;
325
326         device->owner = THIS_MODULE;
327         strcpy(device->type, "HDMI");
328         device->priority = DISPLAY_PRIORITY_HDMI;
329         device->name = hdmi->property->name;
330         device->property = hdmi->property->display;
331         device->priv_data = devdata;
332         device->ops = &hdmi_display_ops;
333         return 1;
334 }
335
336 static struct rk_display_driver display_hdmi = {
337         .probe = hdmi_display_probe,
338 };
339
340 struct rk_display_device *hdmi_register_display_sysfs(struct hdmi *hdmi,
341                                                       struct device *parent)
342 {
343         return rk_display_device_register(&display_hdmi, parent, hdmi);
344 }
345
346 void hdmi_unregister_display_sysfs(struct hdmi *hdmi)
347 {
348         if (hdmi->ddev)
349                 rk_display_device_unregister(hdmi->ddev);
350 }