]> Git Repo - linux.git/blob - drivers/gpu/drm/omapdrm/displays/connector-hdmi.c
Merge tag 'char-misc-4.21-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/gregk...
[linux.git] / drivers / gpu / drm / omapdrm / displays / connector-hdmi.c
1 /*
2  * HDMI Connector driver
3  *
4  * Copyright (C) 2013 Texas Instruments Incorporated - http://www.ti.com/
5  * Author: Tomi Valkeinen <[email protected]>
6  *
7  * This program is free software; you can redistribute it and/or modify it
8  * under the terms of the GNU General Public License version 2 as published by
9  * the Free Software Foundation.
10  */
11
12 #include <linux/gpio/consumer.h>
13 #include <linux/module.h>
14 #include <linux/mutex.h>
15 #include <linux/platform_device.h>
16 #include <linux/slab.h>
17
18 #include "../dss/omapdss.h"
19
20 struct panel_drv_data {
21         struct omap_dss_device dssdev;
22         void (*hpd_cb)(void *cb_data, enum drm_connector_status status);
23         void *hpd_cb_data;
24         struct mutex hpd_lock;
25
26         struct device *dev;
27
28         struct gpio_desc *hpd_gpio;
29 };
30
31 #define to_panel_data(x) container_of(x, struct panel_drv_data, dssdev)
32
33 static int hdmic_connect(struct omap_dss_device *src,
34                          struct omap_dss_device *dst)
35 {
36         return 0;
37 }
38
39 static void hdmic_disconnect(struct omap_dss_device *src,
40                              struct omap_dss_device *dst)
41 {
42 }
43
44 static int hdmic_enable(struct omap_dss_device *dssdev)
45 {
46         struct panel_drv_data *ddata = to_panel_data(dssdev);
47         struct omap_dss_device *src = dssdev->src;
48         int r;
49
50         dev_dbg(ddata->dev, "enable\n");
51
52         if (!omapdss_device_is_connected(dssdev))
53                 return -ENODEV;
54
55         if (omapdss_device_is_enabled(dssdev))
56                 return 0;
57
58         r = src->ops->enable(src);
59         if (r)
60                 return r;
61
62         dssdev->state = OMAP_DSS_DISPLAY_ACTIVE;
63
64         return r;
65 }
66
67 static void hdmic_disable(struct omap_dss_device *dssdev)
68 {
69         struct panel_drv_data *ddata = to_panel_data(dssdev);
70         struct omap_dss_device *src = dssdev->src;
71
72         dev_dbg(ddata->dev, "disable\n");
73
74         if (!omapdss_device_is_enabled(dssdev))
75                 return;
76
77         src->ops->disable(src);
78
79         dssdev->state = OMAP_DSS_DISPLAY_DISABLED;
80 }
81
82 static bool hdmic_detect(struct omap_dss_device *dssdev)
83 {
84         struct panel_drv_data *ddata = to_panel_data(dssdev);
85
86         return gpiod_get_value_cansleep(ddata->hpd_gpio);
87 }
88
89 static void hdmic_register_hpd_cb(struct omap_dss_device *dssdev,
90                                   void (*cb)(void *cb_data,
91                                             enum drm_connector_status status),
92                                   void *cb_data)
93 {
94         struct panel_drv_data *ddata = to_panel_data(dssdev);
95
96         mutex_lock(&ddata->hpd_lock);
97         ddata->hpd_cb = cb;
98         ddata->hpd_cb_data = cb_data;
99         mutex_unlock(&ddata->hpd_lock);
100 }
101
102 static void hdmic_unregister_hpd_cb(struct omap_dss_device *dssdev)
103 {
104         struct panel_drv_data *ddata = to_panel_data(dssdev);
105
106         mutex_lock(&ddata->hpd_lock);
107         ddata->hpd_cb = NULL;
108         ddata->hpd_cb_data = NULL;
109         mutex_unlock(&ddata->hpd_lock);
110 }
111
112 static const struct omap_dss_device_ops hdmic_ops = {
113         .connect                = hdmic_connect,
114         .disconnect             = hdmic_disconnect,
115
116         .enable                 = hdmic_enable,
117         .disable                = hdmic_disable,
118
119         .detect                 = hdmic_detect,
120         .register_hpd_cb        = hdmic_register_hpd_cb,
121         .unregister_hpd_cb      = hdmic_unregister_hpd_cb,
122 };
123
124 static irqreturn_t hdmic_hpd_isr(int irq, void *data)
125 {
126         struct panel_drv_data *ddata = data;
127
128         mutex_lock(&ddata->hpd_lock);
129         if (ddata->hpd_cb) {
130                 enum drm_connector_status status;
131
132                 if (hdmic_detect(&ddata->dssdev))
133                         status = connector_status_connected;
134                 else
135                         status = connector_status_disconnected;
136
137                 ddata->hpd_cb(ddata->hpd_cb_data, status);
138         }
139         mutex_unlock(&ddata->hpd_lock);
140
141         return IRQ_HANDLED;
142 }
143
144 static int hdmic_probe(struct platform_device *pdev)
145 {
146         struct panel_drv_data *ddata;
147         struct omap_dss_device *dssdev;
148         struct gpio_desc *gpio;
149         int r;
150
151         ddata = devm_kzalloc(&pdev->dev, sizeof(*ddata), GFP_KERNEL);
152         if (!ddata)
153                 return -ENOMEM;
154
155         platform_set_drvdata(pdev, ddata);
156         ddata->dev = &pdev->dev;
157
158         mutex_init(&ddata->hpd_lock);
159
160         /* HPD GPIO */
161         gpio = devm_gpiod_get_optional(&pdev->dev, "hpd", GPIOD_IN);
162         if (IS_ERR(gpio)) {
163                 dev_err(&pdev->dev, "failed to parse HPD gpio\n");
164                 return PTR_ERR(gpio);
165         }
166
167         ddata->hpd_gpio = gpio;
168
169         if (ddata->hpd_gpio) {
170                 r = devm_request_threaded_irq(&pdev->dev,
171                                 gpiod_to_irq(ddata->hpd_gpio),
172                                 NULL, hdmic_hpd_isr,
173                                 IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING |
174                                 IRQF_ONESHOT,
175                                 "hdmic hpd", ddata);
176                 if (r)
177                         return r;
178         }
179
180         dssdev = &ddata->dssdev;
181         dssdev->ops = &hdmic_ops;
182         dssdev->dev = &pdev->dev;
183         dssdev->type = OMAP_DISPLAY_TYPE_HDMI;
184         dssdev->owner = THIS_MODULE;
185         dssdev->of_ports = BIT(0);
186         dssdev->ops_flags = ddata->hpd_gpio
187                           ? OMAP_DSS_DEVICE_OP_DETECT | OMAP_DSS_DEVICE_OP_HPD
188                           : 0;
189
190         omapdss_display_init(dssdev);
191         omapdss_device_register(dssdev);
192
193         return 0;
194 }
195
196 static int __exit hdmic_remove(struct platform_device *pdev)
197 {
198         struct panel_drv_data *ddata = platform_get_drvdata(pdev);
199         struct omap_dss_device *dssdev = &ddata->dssdev;
200
201         omapdss_device_unregister(&ddata->dssdev);
202
203         hdmic_disable(dssdev);
204
205         return 0;
206 }
207
208 static const struct of_device_id hdmic_of_match[] = {
209         { .compatible = "omapdss,hdmi-connector", },
210         {},
211 };
212
213 MODULE_DEVICE_TABLE(of, hdmic_of_match);
214
215 static struct platform_driver hdmi_connector_driver = {
216         .probe  = hdmic_probe,
217         .remove = __exit_p(hdmic_remove),
218         .driver = {
219                 .name   = "connector-hdmi",
220                 .of_match_table = hdmic_of_match,
221                 .suppress_bind_attrs = true,
222         },
223 };
224
225 module_platform_driver(hdmi_connector_driver);
226
227 MODULE_AUTHOR("Tomi Valkeinen <[email protected]>");
228 MODULE_DESCRIPTION("HDMI Connector driver");
229 MODULE_LICENSE("GPL");
This page took 0.047167 seconds and 4 git commands to generate.