]> Git Repo - J-linux.git/blob - drivers/gpu/drm/omapdrm/dss/hdmi4.c
Merge remote-tracking branch 'spi/for-5.14' into spi-linus
[J-linux.git] / drivers / gpu / drm / omapdrm / dss / hdmi4.c
1 // SPDX-License-Identifier: GPL-2.0-only
2 /*
3  * HDMI interface DSS driver for TI's OMAP4 family of SoCs.
4  *
5  * Copyright (C) 2010-2011 Texas Instruments Incorporated - https://www.ti.com/
6  * Authors: Yong Zhi
7  *      Mythri pk <[email protected]>
8  */
9
10 #define DSS_SUBSYS_NAME "HDMI"
11
12 #include <linux/kernel.h>
13 #include <linux/module.h>
14 #include <linux/err.h>
15 #include <linux/io.h>
16 #include <linux/interrupt.h>
17 #include <linux/mutex.h>
18 #include <linux/delay.h>
19 #include <linux/string.h>
20 #include <linux/platform_device.h>
21 #include <linux/pm_runtime.h>
22 #include <linux/clk.h>
23 #include <linux/regulator/consumer.h>
24 #include <linux/component.h>
25 #include <linux/of.h>
26 #include <linux/of_graph.h>
27 #include <sound/omap-hdmi-audio.h>
28 #include <media/cec.h>
29
30 #include <drm/drm_atomic.h>
31 #include <drm/drm_atomic_state_helper.h>
32
33 #include "omapdss.h"
34 #include "hdmi4_core.h"
35 #include "hdmi4_cec.h"
36 #include "dss.h"
37 #include "hdmi.h"
38
39 static int hdmi_runtime_get(struct omap_hdmi *hdmi)
40 {
41         int r;
42
43         DSSDBG("hdmi_runtime_get\n");
44
45         r = pm_runtime_get_sync(&hdmi->pdev->dev);
46         if (WARN_ON(r < 0)) {
47                 pm_runtime_put_noidle(&hdmi->pdev->dev);
48                 return r;
49         }
50         return 0;
51 }
52
53 static void hdmi_runtime_put(struct omap_hdmi *hdmi)
54 {
55         int r;
56
57         DSSDBG("hdmi_runtime_put\n");
58
59         r = pm_runtime_put_sync(&hdmi->pdev->dev);
60         WARN_ON(r < 0 && r != -ENOSYS);
61 }
62
63 static irqreturn_t hdmi_irq_handler(int irq, void *data)
64 {
65         struct omap_hdmi *hdmi = data;
66         struct hdmi_wp_data *wp = &hdmi->wp;
67         u32 irqstatus;
68
69         irqstatus = hdmi_wp_get_irqstatus(wp);
70         hdmi_wp_set_irqstatus(wp, irqstatus);
71
72         if ((irqstatus & HDMI_IRQ_LINK_CONNECT) &&
73                         irqstatus & HDMI_IRQ_LINK_DISCONNECT) {
74                 /*
75                  * If we get both connect and disconnect interrupts at the same
76                  * time, turn off the PHY, clear interrupts, and restart, which
77                  * raises connect interrupt if a cable is connected, or nothing
78                  * if cable is not connected.
79                  */
80                 hdmi_wp_set_phy_pwr(wp, HDMI_PHYPWRCMD_OFF);
81
82                 hdmi_wp_set_irqstatus(wp, HDMI_IRQ_LINK_CONNECT |
83                                 HDMI_IRQ_LINK_DISCONNECT);
84
85                 hdmi_wp_set_phy_pwr(wp, HDMI_PHYPWRCMD_LDOON);
86         } else if (irqstatus & HDMI_IRQ_LINK_CONNECT) {
87                 hdmi_wp_set_phy_pwr(wp, HDMI_PHYPWRCMD_TXON);
88         } else if (irqstatus & HDMI_IRQ_LINK_DISCONNECT) {
89                 hdmi_wp_set_phy_pwr(wp, HDMI_PHYPWRCMD_LDOON);
90         }
91         if (irqstatus & HDMI_IRQ_CORE) {
92                 u32 intr4 = hdmi_read_reg(hdmi->core.base, HDMI_CORE_SYS_INTR4);
93
94                 hdmi_write_reg(hdmi->core.base, HDMI_CORE_SYS_INTR4, intr4);
95                 if (intr4 & 8)
96                         hdmi4_cec_irq(&hdmi->core);
97         }
98
99         return IRQ_HANDLED;
100 }
101
102 static int hdmi_power_on_core(struct omap_hdmi *hdmi)
103 {
104         int r;
105
106         if (hdmi->core.core_pwr_cnt++)
107                 return 0;
108
109         r = regulator_enable(hdmi->vdda_reg);
110         if (r)
111                 goto err_reg_enable;
112
113         r = hdmi_runtime_get(hdmi);
114         if (r)
115                 goto err_runtime_get;
116
117         hdmi4_core_powerdown_disable(&hdmi->core);
118
119         /* Make selection of HDMI in DSS */
120         dss_select_hdmi_venc_clk_source(hdmi->dss, DSS_HDMI_M_PCLK);
121
122         hdmi->core_enabled = true;
123
124         return 0;
125
126 err_runtime_get:
127         regulator_disable(hdmi->vdda_reg);
128 err_reg_enable:
129         hdmi->core.core_pwr_cnt--;
130
131         return r;
132 }
133
134 static void hdmi_power_off_core(struct omap_hdmi *hdmi)
135 {
136         if (--hdmi->core.core_pwr_cnt)
137                 return;
138
139         hdmi->core_enabled = false;
140
141         hdmi_runtime_put(hdmi);
142         regulator_disable(hdmi->vdda_reg);
143 }
144
145 static int hdmi_power_on_full(struct omap_hdmi *hdmi)
146 {
147         int r;
148         const struct videomode *vm;
149         struct hdmi_wp_data *wp = &hdmi->wp;
150         struct dss_pll_clock_info hdmi_cinfo = { 0 };
151         unsigned int pc;
152
153         r = hdmi_power_on_core(hdmi);
154         if (r)
155                 return r;
156
157         /* disable and clear irqs */
158         hdmi_wp_clear_irqenable(wp, ~HDMI_IRQ_CORE);
159         hdmi_wp_set_irqstatus(wp, ~HDMI_IRQ_CORE);
160
161         vm = &hdmi->cfg.vm;
162
163         DSSDBG("hdmi_power_on hactive= %d vactive = %d\n", vm->hactive,
164                vm->vactive);
165
166         pc = vm->pixelclock;
167         if (vm->flags & DISPLAY_FLAGS_DOUBLECLK)
168                 pc *= 2;
169
170         /* DSS_HDMI_TCLK is bitclk / 10 */
171         pc *= 10;
172
173         dss_pll_calc_b(&hdmi->pll.pll, clk_get_rate(hdmi->pll.pll.clkin),
174                 pc, &hdmi_cinfo);
175
176         r = dss_pll_enable(&hdmi->pll.pll);
177         if (r) {
178                 DSSERR("Failed to enable PLL\n");
179                 goto err_pll_enable;
180         }
181
182         r = dss_pll_set_config(&hdmi->pll.pll, &hdmi_cinfo);
183         if (r) {
184                 DSSERR("Failed to configure PLL\n");
185                 goto err_pll_cfg;
186         }
187
188         r = hdmi_phy_configure(&hdmi->phy, hdmi_cinfo.clkdco,
189                 hdmi_cinfo.clkout[0]);
190         if (r) {
191                 DSSDBG("Failed to configure PHY\n");
192                 goto err_phy_cfg;
193         }
194
195         r = hdmi_wp_set_phy_pwr(wp, HDMI_PHYPWRCMD_LDOON);
196         if (r)
197                 goto err_phy_pwr;
198
199         hdmi4_configure(&hdmi->core, &hdmi->wp, &hdmi->cfg);
200
201         r = dss_mgr_enable(&hdmi->output);
202         if (r)
203                 goto err_mgr_enable;
204
205         r = hdmi_wp_video_start(&hdmi->wp);
206         if (r)
207                 goto err_vid_enable;
208
209         hdmi_wp_set_irqenable(wp,
210                 HDMI_IRQ_LINK_CONNECT | HDMI_IRQ_LINK_DISCONNECT);
211
212         return 0;
213
214 err_vid_enable:
215         dss_mgr_disable(&hdmi->output);
216 err_mgr_enable:
217         hdmi_wp_set_phy_pwr(&hdmi->wp, HDMI_PHYPWRCMD_OFF);
218 err_phy_pwr:
219 err_phy_cfg:
220 err_pll_cfg:
221         dss_pll_disable(&hdmi->pll.pll);
222 err_pll_enable:
223         hdmi_power_off_core(hdmi);
224         return -EIO;
225 }
226
227 static void hdmi_power_off_full(struct omap_hdmi *hdmi)
228 {
229         hdmi_wp_clear_irqenable(&hdmi->wp, ~HDMI_IRQ_CORE);
230
231         hdmi_wp_video_stop(&hdmi->wp);
232
233         dss_mgr_disable(&hdmi->output);
234
235         hdmi_wp_set_phy_pwr(&hdmi->wp, HDMI_PHYPWRCMD_OFF);
236
237         dss_pll_disable(&hdmi->pll.pll);
238
239         hdmi_power_off_core(hdmi);
240 }
241
242 static int hdmi_dump_regs(struct seq_file *s, void *p)
243 {
244         struct omap_hdmi *hdmi = s->private;
245
246         mutex_lock(&hdmi->lock);
247
248         if (hdmi_runtime_get(hdmi)) {
249                 mutex_unlock(&hdmi->lock);
250                 return 0;
251         }
252
253         hdmi_wp_dump(&hdmi->wp, s);
254         hdmi_pll_dump(&hdmi->pll, s);
255         hdmi_phy_dump(&hdmi->phy, s);
256         hdmi4_core_dump(&hdmi->core, s);
257
258         hdmi_runtime_put(hdmi);
259         mutex_unlock(&hdmi->lock);
260         return 0;
261 }
262
263 static void hdmi_start_audio_stream(struct omap_hdmi *hd)
264 {
265         hdmi_wp_audio_enable(&hd->wp, true);
266         hdmi4_audio_start(&hd->core, &hd->wp);
267 }
268
269 static void hdmi_stop_audio_stream(struct omap_hdmi *hd)
270 {
271         hdmi4_audio_stop(&hd->core, &hd->wp);
272         hdmi_wp_audio_enable(&hd->wp, false);
273 }
274
275 int hdmi4_core_enable(struct hdmi_core_data *core)
276 {
277         struct omap_hdmi *hdmi = container_of(core, struct omap_hdmi, core);
278         int r = 0;
279
280         DSSDBG("ENTER omapdss_hdmi4_core_enable\n");
281
282         mutex_lock(&hdmi->lock);
283
284         r = hdmi_power_on_core(hdmi);
285         if (r) {
286                 DSSERR("failed to power on device\n");
287                 goto err0;
288         }
289
290         mutex_unlock(&hdmi->lock);
291         return 0;
292
293 err0:
294         mutex_unlock(&hdmi->lock);
295         return r;
296 }
297
298 void hdmi4_core_disable(struct hdmi_core_data *core)
299 {
300         struct omap_hdmi *hdmi = container_of(core, struct omap_hdmi, core);
301
302         DSSDBG("Enter omapdss_hdmi4_core_disable\n");
303
304         mutex_lock(&hdmi->lock);
305
306         hdmi_power_off_core(hdmi);
307
308         mutex_unlock(&hdmi->lock);
309 }
310
311 /* -----------------------------------------------------------------------------
312  * DRM Bridge Operations
313  */
314
315 static int hdmi4_bridge_attach(struct drm_bridge *bridge,
316                                enum drm_bridge_attach_flags flags)
317 {
318         struct omap_hdmi *hdmi = drm_bridge_to_hdmi(bridge);
319
320         if (!(flags & DRM_BRIDGE_ATTACH_NO_CONNECTOR))
321                 return -EINVAL;
322
323         return drm_bridge_attach(bridge->encoder, hdmi->output.next_bridge,
324                                  bridge, flags);
325 }
326
327 static void hdmi4_bridge_mode_set(struct drm_bridge *bridge,
328                                   const struct drm_display_mode *mode,
329                                   const struct drm_display_mode *adjusted_mode)
330 {
331         struct omap_hdmi *hdmi = drm_bridge_to_hdmi(bridge);
332
333         mutex_lock(&hdmi->lock);
334
335         drm_display_mode_to_videomode(adjusted_mode, &hdmi->cfg.vm);
336
337         dispc_set_tv_pclk(hdmi->dss->dispc, adjusted_mode->clock * 1000);
338
339         mutex_unlock(&hdmi->lock);
340 }
341
342 static void hdmi4_bridge_enable(struct drm_bridge *bridge,
343                                 struct drm_bridge_state *bridge_state)
344 {
345         struct omap_hdmi *hdmi = drm_bridge_to_hdmi(bridge);
346         struct drm_atomic_state *state = bridge_state->base.state;
347         struct drm_connector_state *conn_state;
348         struct drm_connector *connector;
349         struct drm_crtc_state *crtc_state;
350         unsigned long flags;
351         int ret;
352
353         /*
354          * None of these should fail, as the bridge can't be enabled without a
355          * valid CRTC to connector path with fully populated new states.
356          */
357         connector = drm_atomic_get_new_connector_for_encoder(state,
358                                                              bridge->encoder);
359         if (WARN_ON(!connector))
360                 return;
361         conn_state = drm_atomic_get_new_connector_state(state, connector);
362         if (WARN_ON(!conn_state))
363                 return;
364         crtc_state = drm_atomic_get_new_crtc_state(state, conn_state->crtc);
365         if (WARN_ON(!crtc_state))
366                 return;
367
368         hdmi->cfg.hdmi_dvi_mode = connector->display_info.is_hdmi
369                                 ? HDMI_HDMI : HDMI_DVI;
370
371         if (connector->display_info.is_hdmi) {
372                 const struct drm_display_mode *mode;
373                 struct hdmi_avi_infoframe avi;
374
375                 mode = &crtc_state->adjusted_mode;
376                 ret = drm_hdmi_avi_infoframe_from_display_mode(&avi, connector,
377                                                                mode);
378                 if (ret == 0)
379                         hdmi->cfg.infoframe = avi;
380         }
381
382         mutex_lock(&hdmi->lock);
383
384         ret = hdmi_power_on_full(hdmi);
385         if (ret) {
386                 DSSERR("failed to power on device\n");
387                 goto done;
388         }
389
390         if (hdmi->audio_configured) {
391                 ret = hdmi4_audio_config(&hdmi->core, &hdmi->wp,
392                                          &hdmi->audio_config,
393                                          hdmi->cfg.vm.pixelclock);
394                 if (ret) {
395                         DSSERR("Error restoring audio configuration: %d", ret);
396                         hdmi->audio_abort_cb(&hdmi->pdev->dev);
397                         hdmi->audio_configured = false;
398                 }
399         }
400
401         spin_lock_irqsave(&hdmi->audio_playing_lock, flags);
402         if (hdmi->audio_configured && hdmi->audio_playing)
403                 hdmi_start_audio_stream(hdmi);
404         hdmi->display_enabled = true;
405         spin_unlock_irqrestore(&hdmi->audio_playing_lock, flags);
406
407 done:
408         mutex_unlock(&hdmi->lock);
409 }
410
411 static void hdmi4_bridge_disable(struct drm_bridge *bridge,
412                                  struct drm_bridge_state *bridge_state)
413 {
414         struct omap_hdmi *hdmi = drm_bridge_to_hdmi(bridge);
415         unsigned long flags;
416
417         mutex_lock(&hdmi->lock);
418
419         spin_lock_irqsave(&hdmi->audio_playing_lock, flags);
420         hdmi_stop_audio_stream(hdmi);
421         hdmi->display_enabled = false;
422         spin_unlock_irqrestore(&hdmi->audio_playing_lock, flags);
423
424         hdmi_power_off_full(hdmi);
425
426         mutex_unlock(&hdmi->lock);
427 }
428
429 static void hdmi4_bridge_hpd_notify(struct drm_bridge *bridge,
430                                     enum drm_connector_status status)
431 {
432         struct omap_hdmi *hdmi = drm_bridge_to_hdmi(bridge);
433
434         if (status == connector_status_disconnected)
435                 hdmi4_cec_set_phys_addr(&hdmi->core, CEC_PHYS_ADDR_INVALID);
436 }
437
438 static struct edid *hdmi4_bridge_get_edid(struct drm_bridge *bridge,
439                                           struct drm_connector *connector)
440 {
441         struct omap_hdmi *hdmi = drm_bridge_to_hdmi(bridge);
442         struct edid *edid = NULL;
443         unsigned int cec_addr;
444         bool need_enable;
445         int r;
446
447         need_enable = hdmi->core_enabled == false;
448
449         if (need_enable) {
450                 r = hdmi4_core_enable(&hdmi->core);
451                 if (r)
452                         return NULL;
453         }
454
455         mutex_lock(&hdmi->lock);
456         r = hdmi_runtime_get(hdmi);
457         BUG_ON(r);
458
459         r = hdmi4_core_ddc_init(&hdmi->core);
460         if (r)
461                 goto done;
462
463         edid = drm_do_get_edid(connector, hdmi4_core_ddc_read, &hdmi->core);
464
465 done:
466         hdmi_runtime_put(hdmi);
467         mutex_unlock(&hdmi->lock);
468
469         if (edid && edid->extensions) {
470                 unsigned int len = (edid->extensions + 1) * EDID_LENGTH;
471
472                 cec_addr = cec_get_edid_phys_addr((u8 *)edid, len, NULL);
473         } else {
474                 cec_addr = CEC_PHYS_ADDR_INVALID;
475         }
476
477         hdmi4_cec_set_phys_addr(&hdmi->core, cec_addr);
478
479         if (need_enable)
480                 hdmi4_core_disable(&hdmi->core);
481
482         return edid;
483 }
484
485 static const struct drm_bridge_funcs hdmi4_bridge_funcs = {
486         .attach = hdmi4_bridge_attach,
487         .mode_set = hdmi4_bridge_mode_set,
488         .atomic_duplicate_state = drm_atomic_helper_bridge_duplicate_state,
489         .atomic_destroy_state = drm_atomic_helper_bridge_destroy_state,
490         .atomic_reset = drm_atomic_helper_bridge_reset,
491         .atomic_enable = hdmi4_bridge_enable,
492         .atomic_disable = hdmi4_bridge_disable,
493         .hpd_notify = hdmi4_bridge_hpd_notify,
494         .get_edid = hdmi4_bridge_get_edid,
495 };
496
497 static void hdmi4_bridge_init(struct omap_hdmi *hdmi)
498 {
499         hdmi->bridge.funcs = &hdmi4_bridge_funcs;
500         hdmi->bridge.of_node = hdmi->pdev->dev.of_node;
501         hdmi->bridge.ops = DRM_BRIDGE_OP_EDID;
502         hdmi->bridge.type = DRM_MODE_CONNECTOR_HDMIA;
503
504         drm_bridge_add(&hdmi->bridge);
505 }
506
507 static void hdmi4_bridge_cleanup(struct omap_hdmi *hdmi)
508 {
509         drm_bridge_remove(&hdmi->bridge);
510 }
511
512 /* -----------------------------------------------------------------------------
513  * Audio Callbacks
514  */
515
516 static int hdmi_audio_startup(struct device *dev,
517                               void (*abort_cb)(struct device *dev))
518 {
519         struct omap_hdmi *hd = dev_get_drvdata(dev);
520
521         mutex_lock(&hd->lock);
522
523         WARN_ON(hd->audio_abort_cb != NULL);
524
525         hd->audio_abort_cb = abort_cb;
526
527         mutex_unlock(&hd->lock);
528
529         return 0;
530 }
531
532 static int hdmi_audio_shutdown(struct device *dev)
533 {
534         struct omap_hdmi *hd = dev_get_drvdata(dev);
535
536         mutex_lock(&hd->lock);
537         hd->audio_abort_cb = NULL;
538         hd->audio_configured = false;
539         hd->audio_playing = false;
540         mutex_unlock(&hd->lock);
541
542         return 0;
543 }
544
545 static int hdmi_audio_start(struct device *dev)
546 {
547         struct omap_hdmi *hd = dev_get_drvdata(dev);
548         unsigned long flags;
549
550         spin_lock_irqsave(&hd->audio_playing_lock, flags);
551
552         if (hd->display_enabled) {
553                 if (!hdmi_mode_has_audio(&hd->cfg))
554                         DSSERR("%s: Video mode does not support audio\n",
555                                __func__);
556                 hdmi_start_audio_stream(hd);
557         }
558         hd->audio_playing = true;
559
560         spin_unlock_irqrestore(&hd->audio_playing_lock, flags);
561         return 0;
562 }
563
564 static void hdmi_audio_stop(struct device *dev)
565 {
566         struct omap_hdmi *hd = dev_get_drvdata(dev);
567         unsigned long flags;
568
569         WARN_ON(!hdmi_mode_has_audio(&hd->cfg));
570
571         spin_lock_irqsave(&hd->audio_playing_lock, flags);
572
573         if (hd->display_enabled)
574                 hdmi_stop_audio_stream(hd);
575         hd->audio_playing = false;
576
577         spin_unlock_irqrestore(&hd->audio_playing_lock, flags);
578 }
579
580 static int hdmi_audio_config(struct device *dev,
581                              struct omap_dss_audio *dss_audio)
582 {
583         struct omap_hdmi *hd = dev_get_drvdata(dev);
584         int ret = 0;
585
586         mutex_lock(&hd->lock);
587
588         if (hd->display_enabled) {
589                 ret = hdmi4_audio_config(&hd->core, &hd->wp, dss_audio,
590                                          hd->cfg.vm.pixelclock);
591                 if (ret)
592                         goto out;
593         }
594
595         hd->audio_configured = true;
596         hd->audio_config = *dss_audio;
597 out:
598         mutex_unlock(&hd->lock);
599
600         return ret;
601 }
602
603 static const struct omap_hdmi_audio_ops hdmi_audio_ops = {
604         .audio_startup = hdmi_audio_startup,
605         .audio_shutdown = hdmi_audio_shutdown,
606         .audio_start = hdmi_audio_start,
607         .audio_stop = hdmi_audio_stop,
608         .audio_config = hdmi_audio_config,
609 };
610
611 static int hdmi_audio_register(struct omap_hdmi *hdmi)
612 {
613         struct omap_hdmi_audio_pdata pdata = {
614                 .dev = &hdmi->pdev->dev,
615                 .version = 4,
616                 .audio_dma_addr = hdmi_wp_get_audio_dma_addr(&hdmi->wp),
617                 .ops = &hdmi_audio_ops,
618         };
619
620         hdmi->audio_pdev = platform_device_register_data(
621                 &hdmi->pdev->dev, "omap-hdmi-audio", PLATFORM_DEVID_AUTO,
622                 &pdata, sizeof(pdata));
623
624         if (IS_ERR(hdmi->audio_pdev))
625                 return PTR_ERR(hdmi->audio_pdev);
626
627         return 0;
628 }
629
630 /* -----------------------------------------------------------------------------
631  * Component Bind & Unbind
632  */
633
634 static int hdmi4_bind(struct device *dev, struct device *master, void *data)
635 {
636         struct dss_device *dss = dss_get_device(master);
637         struct omap_hdmi *hdmi = dev_get_drvdata(dev);
638         int r;
639
640         hdmi->dss = dss;
641
642         r = hdmi_runtime_get(hdmi);
643         if (r)
644                 return r;
645
646         r = hdmi_pll_init(dss, hdmi->pdev, &hdmi->pll, &hdmi->wp);
647         if (r)
648                 goto err_runtime_put;
649
650         r = hdmi4_cec_init(hdmi->pdev, &hdmi->core, &hdmi->wp);
651         if (r)
652                 goto err_pll_uninit;
653
654         r = hdmi_audio_register(hdmi);
655         if (r) {
656                 DSSERR("Registering HDMI audio failed\n");
657                 goto err_cec_uninit;
658         }
659
660         hdmi->debugfs = dss_debugfs_create_file(dss, "hdmi", hdmi_dump_regs,
661                                                hdmi);
662
663         hdmi_runtime_put(hdmi);
664
665         return 0;
666
667 err_cec_uninit:
668         hdmi4_cec_uninit(&hdmi->core);
669 err_pll_uninit:
670         hdmi_pll_uninit(&hdmi->pll);
671 err_runtime_put:
672         hdmi_runtime_put(hdmi);
673         return r;
674 }
675
676 static void hdmi4_unbind(struct device *dev, struct device *master, void *data)
677 {
678         struct omap_hdmi *hdmi = dev_get_drvdata(dev);
679
680         dss_debugfs_remove_file(hdmi->debugfs);
681
682         if (hdmi->audio_pdev)
683                 platform_device_unregister(hdmi->audio_pdev);
684
685         hdmi4_cec_uninit(&hdmi->core);
686         hdmi_pll_uninit(&hdmi->pll);
687 }
688
689 static const struct component_ops hdmi4_component_ops = {
690         .bind   = hdmi4_bind,
691         .unbind = hdmi4_unbind,
692 };
693
694 /* -----------------------------------------------------------------------------
695  * Probe & Remove, Suspend & Resume
696  */
697
698 static int hdmi4_init_output(struct omap_hdmi *hdmi)
699 {
700         struct omap_dss_device *out = &hdmi->output;
701         int r;
702
703         hdmi4_bridge_init(hdmi);
704
705         out->dev = &hdmi->pdev->dev;
706         out->id = OMAP_DSS_OUTPUT_HDMI;
707         out->type = OMAP_DISPLAY_TYPE_HDMI;
708         out->name = "hdmi.0";
709         out->dispc_channel = OMAP_DSS_CHANNEL_DIGIT;
710         out->of_port = 0;
711
712         r = omapdss_device_init_output(out, &hdmi->bridge);
713         if (r < 0) {
714                 hdmi4_bridge_cleanup(hdmi);
715                 return r;
716         }
717
718         omapdss_device_register(out);
719
720         return 0;
721 }
722
723 static void hdmi4_uninit_output(struct omap_hdmi *hdmi)
724 {
725         struct omap_dss_device *out = &hdmi->output;
726
727         omapdss_device_unregister(out);
728         omapdss_device_cleanup_output(out);
729
730         hdmi4_bridge_cleanup(hdmi);
731 }
732
733 static int hdmi4_probe_of(struct omap_hdmi *hdmi)
734 {
735         struct platform_device *pdev = hdmi->pdev;
736         struct device_node *node = pdev->dev.of_node;
737         struct device_node *ep;
738         int r;
739
740         ep = of_graph_get_endpoint_by_regs(node, 0, 0);
741         if (!ep)
742                 return 0;
743
744         r = hdmi_parse_lanes_of(pdev, ep, &hdmi->phy);
745         of_node_put(ep);
746         return r;
747 }
748
749 static int hdmi4_probe(struct platform_device *pdev)
750 {
751         struct omap_hdmi *hdmi;
752         int irq;
753         int r;
754
755         hdmi = kzalloc(sizeof(*hdmi), GFP_KERNEL);
756         if (!hdmi)
757                 return -ENOMEM;
758
759         hdmi->pdev = pdev;
760
761         dev_set_drvdata(&pdev->dev, hdmi);
762
763         mutex_init(&hdmi->lock);
764         spin_lock_init(&hdmi->audio_playing_lock);
765
766         r = hdmi4_probe_of(hdmi);
767         if (r)
768                 goto err_free;
769
770         r = hdmi_wp_init(pdev, &hdmi->wp, 4);
771         if (r)
772                 goto err_free;
773
774         r = hdmi_phy_init(pdev, &hdmi->phy, 4);
775         if (r)
776                 goto err_free;
777
778         r = hdmi4_core_init(pdev, &hdmi->core);
779         if (r)
780                 goto err_free;
781
782         irq = platform_get_irq(pdev, 0);
783         if (irq < 0) {
784                 DSSERR("platform_get_irq failed\n");
785                 r = -ENODEV;
786                 goto err_free;
787         }
788
789         r = devm_request_threaded_irq(&pdev->dev, irq,
790                         NULL, hdmi_irq_handler,
791                         IRQF_ONESHOT, "OMAP HDMI", hdmi);
792         if (r) {
793                 DSSERR("HDMI IRQ request failed\n");
794                 goto err_free;
795         }
796
797         hdmi->vdda_reg = devm_regulator_get(&pdev->dev, "vdda");
798         if (IS_ERR(hdmi->vdda_reg)) {
799                 r = PTR_ERR(hdmi->vdda_reg);
800                 if (r != -EPROBE_DEFER)
801                         DSSERR("can't get VDDA regulator\n");
802                 goto err_free;
803         }
804
805         pm_runtime_enable(&pdev->dev);
806
807         r = hdmi4_init_output(hdmi);
808         if (r)
809                 goto err_pm_disable;
810
811         r = component_add(&pdev->dev, &hdmi4_component_ops);
812         if (r)
813                 goto err_uninit_output;
814
815         return 0;
816
817 err_uninit_output:
818         hdmi4_uninit_output(hdmi);
819 err_pm_disable:
820         pm_runtime_disable(&pdev->dev);
821 err_free:
822         kfree(hdmi);
823         return r;
824 }
825
826 static int hdmi4_remove(struct platform_device *pdev)
827 {
828         struct omap_hdmi *hdmi = platform_get_drvdata(pdev);
829
830         component_del(&pdev->dev, &hdmi4_component_ops);
831
832         hdmi4_uninit_output(hdmi);
833
834         pm_runtime_disable(&pdev->dev);
835
836         kfree(hdmi);
837         return 0;
838 }
839
840 static const struct of_device_id hdmi_of_match[] = {
841         { .compatible = "ti,omap4-hdmi", },
842         {},
843 };
844
845 struct platform_driver omapdss_hdmi4hw_driver = {
846         .probe          = hdmi4_probe,
847         .remove         = hdmi4_remove,
848         .driver         = {
849                 .name   = "omapdss_hdmi",
850                 .of_match_table = hdmi_of_match,
851                 .suppress_bind_attrs = true,
852         },
853 };
This page took 0.081416 seconds and 4 git commands to generate.