video: rockchip: hdmi: sync to develop-3.10
[firefly-linux-kernel-4.4.55.git] / drivers / video / rockchip / hdmi / rockchip-hdmiv1 / rockchip_hdmiv1.c
1 #include <linux/module.h>
2 #include <linux/kernel.h>
3 #include <linux/errno.h>
4 #include <linux/string.h>
5 #include <linux/mm.h>
6 #include <linux/slab.h>
7 #include <linux/delay.h>
8 #include <linux/device.h>
9 #include <linux/init.h>
10 #include <linux/dma-mapping.h>
11 #include <linux/interrupt.h>
12 #include <linux/platform_device.h>
13 #include <linux/clk.h>
14 #include <linux/uaccess.h>
15
16 #include <linux/of_gpio.h>
17 #include <linux/rk_fb.h>
18
19 #if defined(CONFIG_DEBUG_FS)
20 #include <linux/fs.h>
21 #include <linux/debugfs.h>
22 #include <linux/seq_file.h>
23 #endif
24
25 #include "rockchip_hdmiv1.h"
26 #include "rockchip_hdmiv1_hw.h"
27
28 static struct hdmi_dev *hdmi_dev;
29
30 #if defined(CONFIG_DEBUG_FS)
31 static int rockchip_hdmiv1_reg_show(struct seq_file *s, void *v)
32 {
33         int i = 0;
34         u32 val = 0;
35
36         seq_puts(s, "\n\n>>>rk3036_ctl reg");
37         for (i = 0; i < 16; i++)
38                 seq_printf(s, " %2x", i);
39
40         seq_puts(s,
41                  "\n-----------------------------------------------------------------");
42
43         for (i = 0; i <= PHY_PRE_DIV_RATIO; i++) {
44                 hdmi_readl(hdmi_dev, i, &val);
45                 if (i % 16 == 0)
46                         seq_printf(s, "\n>>>rk3036_ctl %2x:", i);
47                 seq_printf(s, " %02x", val);
48         }
49         seq_puts(s,
50                  "\n-----------------------------------------------------------------\n");
51
52         return 0;
53 }
54
55 static ssize_t rockchip_hdmiv1_reg_write(struct file *file,
56                                          const char __user *buf,
57                                          size_t count,
58                                          loff_t *ppos)
59 {
60         u32 reg;
61         u32 val;
62         char kbuf[25];
63         static int ret;
64         struct hdmi *hdmi_drv =  hdmi_dev->hdmi;
65
66         if (copy_from_user(kbuf, buf, count))
67                 return -EFAULT;
68         ret = sscanf(kbuf, "%x%x", &reg, &val);
69         if ((reg < 0) || (reg > 0xed)) {
70                 dev_info(hdmi_drv->dev, "it is no hdmi reg\n");
71                 return count;
72         }
73         dev_info(hdmi_drv->dev, "/**********rk3036 reg config******/");
74         dev_info(hdmi_drv->dev, "\n reg=%x val=%x\n", reg, val);
75         hdmi_writel(hdmi_dev, reg, val);
76
77         return count;
78 }
79
80 static int rockchip_hdmiv1_reg_open(struct inode *inode, struct file *file)
81 {
82         return single_open(file, rockchip_hdmiv1_reg_show, NULL);
83 }
84
85 static const struct file_operations rockchip_hdmiv1_reg_fops = {
86         .owner = THIS_MODULE,
87         .open = rockchip_hdmiv1_reg_open,
88         .read = seq_read,
89         .write = rockchip_hdmiv1_reg_write,
90         .llseek = seq_lseek,
91         .release = single_release,
92 };
93 #endif
94
95 static int rockchip_hdmiv1_clk_enable(struct hdmi_dev *hdmi_dev)
96 {
97         struct hdmi *hdmi_drv;
98
99         hdmi_drv =  hdmi_dev->hdmi;
100         if (!hdmi_dev->clk_on) {
101                 if (hdmi_dev->soctype == HDMI_SOC_RK312X)
102                         clk_prepare_enable(hdmi_dev->pd);
103
104                 clk_prepare_enable(hdmi_dev->hclk);
105                 spin_lock(&hdmi_dev->reg_lock);
106                 hdmi_dev->clk_on = 1;
107                 spin_unlock(&hdmi_dev->reg_lock);
108         }
109
110         return 0;
111 }
112
113 static int rockchip_hdmiv1_clk_disable(struct hdmi_dev *hdmi_dev)
114 {
115         struct hdmi *hdmi_drv;
116
117         hdmi_drv =  hdmi_dev->hdmi;
118         if (hdmi_dev->clk_on) {
119                 spin_lock(&hdmi_dev->reg_lock);
120                 hdmi_dev->clk_on = 0;
121                 spin_unlock(&hdmi_dev->reg_lock);
122                 if (hdmi_dev->soctype == HDMI_SOC_RK312X)
123                         clk_disable_unprepare(hdmi_dev->pd);
124                 clk_disable_unprepare(hdmi_dev->hclk);
125         }
126
127         return 0;
128 }
129
130 static void rockchip_hdmiv1_early_suspend(void)
131 {
132         struct hdmi *hdmi_drv =  hdmi_dev->hdmi;
133
134         dev_info(hdmi_drv->dev, "hdmi suspend\n");
135         hdmi_submit_work(hdmi_drv,
136                          HDMI_SUSPEND_CTL, 0, 1);
137         mutex_lock(&hdmi_drv->lock);
138         if (hdmi_dev->irq)
139                 disable_irq(hdmi_dev->irq);
140         mutex_unlock(&hdmi_drv->lock);
141         rockchip_hdmiv1_clk_disable(hdmi_dev);
142 }
143
144 static void rockchip_hdmiv1_early_resume(void)
145 {
146         struct hdmi *hdmi_drv =  hdmi_dev->hdmi;
147
148         dev_info(hdmi_drv->dev, "hdmi resume\n");
149         mutex_lock(&hdmi_drv->lock);
150         rockchip_hdmiv1_clk_enable(hdmi_dev);
151         rockchip_hdmiv1_initial(hdmi_drv);
152         if (hdmi_drv->enable && hdmi_dev->irq) {
153                 rockchip_hdmiv1_irq(hdmi_drv);
154                 enable_irq(hdmi_dev->irq);
155         }
156         mutex_unlock(&hdmi_drv->lock);
157         hdmi_submit_work(hdmi_drv, HDMI_RESUME_CTL, 0, 0);
158 }
159
160 static int rockchip_hdmiv1_fb_event_notify(struct notifier_block *self,
161                                            unsigned long action,
162                                            void *data)
163 {
164         struct fb_event *event = data;
165         int blank_mode = *((int *)event->data);
166
167         if (action == FB_EARLY_EVENT_BLANK) {
168                 switch (blank_mode) {
169                 case FB_BLANK_UNBLANK:
170                         break;
171                 default:
172                         if (!hdmi_dev->hdmi->sleep)
173                                 rockchip_hdmiv1_early_suspend();
174                         break;
175                 }
176         } else if (action == FB_EVENT_BLANK) {
177                 switch (blank_mode) {
178                 case FB_BLANK_UNBLANK:
179                         if (hdmi_dev->hdmi->sleep)
180                                 rockchip_hdmiv1_early_resume();
181                         break;
182                 default:
183                         break;
184                 }
185         }
186
187         return NOTIFY_OK;
188 }
189
190 static struct notifier_block rockchip_hdmiv1_fb_notifier = {
191         .notifier_call = rockchip_hdmiv1_fb_event_notify,
192 };
193
194 static irqreturn_t rockchip_hdmiv1_irq_func(int irq, void *dev_id)
195 {
196         struct hdmi *hdmi_drv = hdmi_dev->hdmi;
197
198         rockchip_hdmiv1_irq(hdmi_drv);
199
200         return IRQ_HANDLED;
201 }
202
203 static struct hdmi_property rockchip_hdmiv1_property = {
204         .videosrc = DISPLAY_SOURCE_LCDC0,
205         .display = DISPLAY_MAIN,
206 };
207 static struct hdmi_ops rockchip_hdmiv1_ops;
208
209 #if defined(CONFIG_OF)
210 static const struct of_device_id rockchip_hdmiv1_dt_ids[] = {
211         {.compatible = "rockchip,rk3036-hdmi"},
212         {.compatible = "rockchip,rk312x-hdmi"},
213         {}
214 };
215
216 static int rockchip_hdmiv1_parse_dt(struct hdmi_dev *hdmi_dev)
217 {
218         int val = 0;
219         struct device_node *np = hdmi_dev->dev->of_node;
220         const struct of_device_id *match;
221
222         match = of_match_node(rockchip_hdmiv1_dt_ids, np);
223         if (!match)
224                 return PTR_ERR(match);
225
226         if (!strcmp(match->compatible, "rockchip,rk3036-hdmi")) {
227                 hdmi_dev->soctype = HDMI_SOC_RK3036;
228         } else if (!strcmp(match->compatible, "rockchip,rk312x-hdmi")) {
229                 hdmi_dev->soctype = HDMI_SOC_RK312X;
230         } else {
231                 pr_err("It is not a valid rockchip soc!");
232                 return -ENOMEM;
233         }
234
235         if (!of_property_read_u32(np, "rockchip,hdmi_video_source", &val))
236                 rockchip_hdmiv1_property.videosrc = val;
237
238         if (!of_property_read_u32(np, "rockchip,hdmi_audio_source", &val))
239                 hdmi_dev->audiosrc = val;
240
241         if (!of_property_read_u32(np, "rockchip,cec_enable", &val) &&
242             (val == 1)) {
243                 pr_debug("hdmi support cec\n");
244                 rockchip_hdmiv1_property.feature |= SUPPORT_CEC;
245         }
246         if (!of_property_read_u32(np, "rockchip,hdcp_enable", &val) &&
247             (val == 1)) {
248                 pr_debug("hdmi support hdcp\n");
249                 rockchip_hdmiv1_property.feature |= SUPPORT_HDCP;
250         }
251         if (!of_property_read_u32(np, "rockchip,defaultmode", &val) &&
252             (val > 0)) {
253                 pr_debug("default mode is %d\n", val);
254                 rockchip_hdmiv1_property.defaultmode = val;
255         } else {
256                 rockchip_hdmiv1_property.defaultmode =
257                                                 HDMI_VIDEO_DEFAULT_MODE;
258         }
259
260         return 0;
261 }
262 MODULE_DEVICE_TABLE(of, rockchip_hdmiv1_dt_ids);
263 #endif
264
265
266 static int rockchip_hdmiv1_probe(struct platform_device *pdev)
267 {
268         int ret;
269         struct resource *res;
270
271         hdmi_dev = devm_kzalloc(&pdev->dev,
272                                 sizeof(struct hdmi_dev),
273                                 GFP_KERNEL);
274         if (!hdmi_dev) {
275                 dev_err(hdmi_dev->dev, ">>rk_hdmi kmalloc fail!");
276                 return -ENOMEM;
277         }
278         hdmi_dev->dev = &pdev->dev;
279         platform_set_drvdata(pdev, hdmi_dev);
280         spin_lock_init(&hdmi_dev->reg_lock);
281         rockchip_hdmiv1_parse_dt(hdmi_dev);
282         /* request and remap iomem */
283         res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
284         if (!res) {
285                 dev_err(hdmi_dev->dev, "Unable to get register resource\n");
286                 ret = -ENXIO;
287                 goto failed;
288         }
289         hdmi_dev->regbase_phy = res->start;
290         hdmi_dev->regsize_phy = resource_size(res);
291         hdmi_dev->regbase = devm_ioremap_resource(&pdev->dev, res);
292         if (IS_ERR(hdmi_dev->regbase)) {
293                 ret = PTR_ERR(hdmi_dev->regbase);
294                 dev_err(hdmi_dev->dev, "cannot ioremap registers,err=%d\n",
295                         ret);
296                 goto failed;
297         }
298         if (hdmi_dev->soctype == HDMI_SOC_RK312X) {
299                 hdmi_dev->pd = devm_clk_get(hdmi_dev->dev, "pd_hdmi");
300                 if (IS_ERR(hdmi_dev->pd)) {
301                         dev_err(hdmi_dev->hdmi->dev, "Unable to get hdmi pd\n");
302                         ret = -ENXIO;
303                         goto failed;
304                 }
305         }
306         hdmi_dev->hclk = devm_clk_get(hdmi_dev->dev, "pclk_hdmi");
307         if (IS_ERR(hdmi_dev->hclk)) {
308                 dev_err(hdmi_dev->hdmi->dev, "Unable to get hdmi hclk\n");
309                 ret = -ENXIO;
310                 goto failed;
311         }
312         /* enable clk */
313         rockchip_hdmiv1_clk_enable(hdmi_dev);
314         hdmi_dev->hclk_rate = clk_get_rate(hdmi_dev->hclk);
315
316         rockchip_hdmiv1_dev_init_ops(&rockchip_hdmiv1_ops);
317         rockchip_hdmiv1_property.name = (char *)pdev->name;
318         rockchip_hdmiv1_property.priv = hdmi_dev;
319         if (rk_fb_get_display_policy() == DISPLAY_POLICY_BOX)
320                 rockchip_hdmiv1_property.feature |= SUPPORT_1080I |
321                                                     SUPPORT_480I_576I;
322         hdmi_dev->hdmi = rockchip_hdmi_register(&rockchip_hdmiv1_property,
323                                                 &rockchip_hdmiv1_ops);
324         if (hdmi_dev->hdmi == NULL) {
325                 dev_err(&pdev->dev, "register hdmi device failed\n");
326                 ret = -ENOMEM;
327                 goto failed;
328         }
329         hdmi_dev->hdmi->dev = &pdev->dev;
330
331         fb_register_client(&rockchip_hdmiv1_fb_notifier);
332         rockchip_hdmiv1_initial(hdmi_dev->hdmi);
333
334         rk_display_device_enable(hdmi_dev->hdmi->ddev);
335         hdmi_submit_work(hdmi_dev->hdmi, HDMI_HPD_CHANGE, 0, 1);
336
337 #if defined(CONFIG_DEBUG_FS)
338         hdmi_dev->debugfs_dir = debugfs_create_dir("rockchip_hdmiv1", NULL);
339         if (IS_ERR(hdmi_dev->debugfs_dir)) {
340                 dev_err(hdmi_dev->hdmi->dev,
341                         "failed to create debugfs dir for hdmi!\n");
342         } else {
343                 debugfs_create_file("hdmi", S_IRUSR,
344                                     hdmi_dev->debugfs_dir, hdmi_dev->hdmi,
345                                     &rockchip_hdmiv1_reg_fops);
346         }
347 #endif
348
349         /* get the IRQ */
350         hdmi_dev->irq = platform_get_irq(pdev, 0);
351         if (hdmi_dev->irq <= 0) {
352                 dev_err(hdmi_dev->hdmi->dev, "failed to get hdmi irq resource (%d).\n",
353                         hdmi_dev->irq);
354                 hdmi_dev->irq = 0;
355         } else {
356                 /* request the IRQ */
357                 ret = devm_request_irq(hdmi_dev->hdmi->dev,
358                                        hdmi_dev->irq,
359                                        rockchip_hdmiv1_irq_func,
360                                        IRQF_TRIGGER_HIGH | IRQF_DISABLED,
361                                        dev_name(hdmi_dev->hdmi->dev),
362                                        hdmi_dev->hdmi);
363                 if (ret) {
364                         dev_err(hdmi_dev->hdmi->dev, "hdmi request_irq failed (%d)\n",
365                                 ret);
366                         goto failed1;
367                 }
368         }
369         dev_info(hdmi_dev->hdmi->dev, "hdmi probe success.\n");
370         return 0;
371
372 failed1:
373         rockchip_hdmi_unregister(hdmi_dev->hdmi);
374 failed:
375         kfree(hdmi_dev);
376         hdmi_dev = NULL;
377         dev_err(&pdev->dev, "rk3288 hdmi probe error.\n");
378         return ret;
379 }
380
381 static int rockchip_hdmiv1_remove(struct platform_device *pdev)
382 {
383         struct hdmi *hdmi_drv = NULL;
384
385         hdmi_drv = hdmi_dev->hdmi;
386         rockchip_hdmi_unregister(hdmi_drv);
387         return 0;
388 }
389
390 static void rockchip_hdmiv1_shutdown(struct platform_device *pdev)
391 {
392         struct hdmi_dev *hdmi_dev = platform_get_drvdata(pdev);
393         struct hdmi *hdmi_drv = NULL;
394
395         if (hdmi_dev) {
396                 hdmi_drv = hdmi_dev->hdmi;
397 #ifdef CONFIG_HAS_EARLYSUSPEND
398                 unregister_early_suspend(&hdmi_drv->early_suspend);
399 #endif
400                 mutex_lock(&hdmi_drv->lock);
401                 hdmi_drv->sleep = 1;
402                 if (!hdmi_drv->enable) {
403                         mutex_unlock(&hdmi_drv->lock);
404                         return;
405                 }
406                 if (hdmi_dev->irq)
407                         disable_irq(hdmi_dev->irq);
408                 mutex_unlock(&hdmi_drv->lock);
409                 if (hdmi_drv->hotplug == HDMI_HPD_ACTIVED)
410                         hdmi_drv->ops->setmute(hdmi_drv,
411                                                HDMI_VIDEO_MUTE |
412                                                HDMI_AUDIO_MUTE);
413                 rockchip_hdmiv1_clk_disable(hdmi_dev);
414         }
415         dev_info(hdmi_drv->dev, "rk hdmi shut down.\n");
416 }
417
418
419 static struct platform_driver rockchip_hdmiv1_driver = {
420         .probe = rockchip_hdmiv1_probe,
421         .remove = rockchip_hdmiv1_remove,
422         .driver = {
423                 .name = "rk-hdmi",
424                 .owner = THIS_MODULE,
425                 #if defined(CONFIG_OF)
426                 .of_match_table = of_match_ptr(rockchip_hdmiv1_dt_ids),
427                 #endif
428         },
429         .shutdown = rockchip_hdmiv1_shutdown,
430 };
431
432 static int __init rockchip_hdmiv1_init(void)
433 {
434         return platform_driver_register(&rockchip_hdmiv1_driver);
435 }
436
437 static void __exit rockchip_hdmiv1_exit(void)
438 {
439         platform_driver_unregister(&rockchip_hdmiv1_driver);
440 }
441
442 module_init(rockchip_hdmiv1_init);
443 module_exit(rockchip_hdmiv1_exit);