2 * HDMI Connector driver
4 * Copyright (C) 2013 Texas Instruments Incorporated - http://www.ti.com/
5 * Author: Tomi Valkeinen <tomi.valkeinen@ti.com>
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.
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>
18 #include "../dss/omapdss.h"
20 struct panel_drv_data {
21 struct omap_dss_device dssdev;
22 void (*hpd_cb)(void *cb_data, enum drm_connector_status status);
24 struct mutex hpd_lock;
28 struct gpio_desc *hpd_gpio;
31 #define to_panel_data(x) container_of(x, struct panel_drv_data, dssdev)
33 static int hdmic_connect(struct omap_dss_device *src,
34 struct omap_dss_device *dst)
39 static void hdmic_disconnect(struct omap_dss_device *src,
40 struct omap_dss_device *dst)
44 static bool hdmic_detect(struct omap_dss_device *dssdev)
46 struct panel_drv_data *ddata = to_panel_data(dssdev);
48 return gpiod_get_value_cansleep(ddata->hpd_gpio);
51 static void hdmic_register_hpd_cb(struct omap_dss_device *dssdev,
52 void (*cb)(void *cb_data,
53 enum drm_connector_status status),
56 struct panel_drv_data *ddata = to_panel_data(dssdev);
58 mutex_lock(&ddata->hpd_lock);
60 ddata->hpd_cb_data = cb_data;
61 mutex_unlock(&ddata->hpd_lock);
64 static void hdmic_unregister_hpd_cb(struct omap_dss_device *dssdev)
66 struct panel_drv_data *ddata = to_panel_data(dssdev);
68 mutex_lock(&ddata->hpd_lock);
70 ddata->hpd_cb_data = NULL;
71 mutex_unlock(&ddata->hpd_lock);
74 static const struct omap_dss_device_ops hdmic_ops = {
75 .connect = hdmic_connect,
76 .disconnect = hdmic_disconnect,
78 .detect = hdmic_detect,
79 .register_hpd_cb = hdmic_register_hpd_cb,
80 .unregister_hpd_cb = hdmic_unregister_hpd_cb,
83 static irqreturn_t hdmic_hpd_isr(int irq, void *data)
85 struct panel_drv_data *ddata = data;
87 mutex_lock(&ddata->hpd_lock);
89 enum drm_connector_status status;
91 if (hdmic_detect(&ddata->dssdev))
92 status = connector_status_connected;
94 status = connector_status_disconnected;
96 ddata->hpd_cb(ddata->hpd_cb_data, status);
98 mutex_unlock(&ddata->hpd_lock);
103 static int hdmic_probe(struct platform_device *pdev)
105 struct panel_drv_data *ddata;
106 struct omap_dss_device *dssdev;
107 struct gpio_desc *gpio;
110 ddata = devm_kzalloc(&pdev->dev, sizeof(*ddata), GFP_KERNEL);
114 platform_set_drvdata(pdev, ddata);
115 ddata->dev = &pdev->dev;
117 mutex_init(&ddata->hpd_lock);
120 gpio = devm_gpiod_get_optional(&pdev->dev, "hpd", GPIOD_IN);
122 dev_err(&pdev->dev, "failed to parse HPD gpio\n");
123 return PTR_ERR(gpio);
126 ddata->hpd_gpio = gpio;
128 if (ddata->hpd_gpio) {
129 r = devm_request_threaded_irq(&pdev->dev,
130 gpiod_to_irq(ddata->hpd_gpio),
132 IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING |
139 dssdev = &ddata->dssdev;
140 dssdev->ops = &hdmic_ops;
141 dssdev->dev = &pdev->dev;
142 dssdev->type = OMAP_DISPLAY_TYPE_HDMI;
143 dssdev->display = true;
144 dssdev->owner = THIS_MODULE;
145 dssdev->of_ports = BIT(0);
146 dssdev->ops_flags = ddata->hpd_gpio
147 ? OMAP_DSS_DEVICE_OP_DETECT | OMAP_DSS_DEVICE_OP_HPD
150 omapdss_display_init(dssdev);
151 omapdss_device_register(dssdev);
156 static int __exit hdmic_remove(struct platform_device *pdev)
158 struct panel_drv_data *ddata = platform_get_drvdata(pdev);
160 omapdss_device_unregister(&ddata->dssdev);
165 static const struct of_device_id hdmic_of_match[] = {
166 { .compatible = "omapdss,hdmi-connector", },
170 MODULE_DEVICE_TABLE(of, hdmic_of_match);
172 static struct platform_driver hdmi_connector_driver = {
173 .probe = hdmic_probe,
174 .remove = __exit_p(hdmic_remove),
176 .name = "connector-hdmi",
177 .of_match_table = hdmic_of_match,
178 .suppress_bind_attrs = true,
182 module_platform_driver(hdmi_connector_driver);
184 MODULE_AUTHOR("Tomi Valkeinen <tomi.valkeinen@ti.com>");
185 MODULE_DESCRIPTION("HDMI Connector driver");
186 MODULE_LICENSE("GPL");