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