File Index
Files and directories
Sign in
FILE

connector-hdmi.c

File preview with syntax highlighting.

linux-6.19.14/drivers/video/fbdev/omap2/omapfb/displays/connector-hdmi.c C
  1// SPDX-License-Identifier: GPL-2.0-only
  2/*
  3 * HDMI Connector driver
  4 *
  5 * Copyright (C) 2013 Texas Instruments
  6 * Author: Tomi Valkeinen <tomi.valkeinen@ti.com>
  7 */
  8
  9#include <linux/err.h>
 10#include <linux/gpio/consumer.h>
 11#include <linux/slab.h>
 12#include <linux/module.h>
 13#include <linux/platform_device.h>
 14#include <linux/of.h>
 15
 16#include <drm/drm_edid.h>
 17
 18#include <video/omapfb_dss.h>
 19
 20static const struct omap_video_timings hdmic_default_timings = {
 21	.x_res		= 640,
 22	.y_res		= 480,
 23	.pixelclock	= 25175000,
 24	.hsw		= 96,
 25	.hfp		= 16,
 26	.hbp		= 48,
 27	.vsw		= 2,
 28	.vfp		= 11,
 29	.vbp		= 31,
 30
 31	.vsync_level	= OMAPDSS_SIG_ACTIVE_LOW,
 32	.hsync_level	= OMAPDSS_SIG_ACTIVE_LOW,
 33
 34	.interlace	= false,
 35};
 36
 37struct panel_drv_data {
 38	struct omap_dss_device dssdev;
 39	struct omap_dss_device *in;
 40
 41	struct device *dev;
 42
 43	struct omap_video_timings timings;
 44
 45	struct gpio_desc *hpd_gpio;
 46};
 47
 48#define to_panel_data(x) container_of(x, struct panel_drv_data, dssdev)
 49
 50static int hdmic_connect(struct omap_dss_device *dssdev)
 51{
 52	struct panel_drv_data *ddata = to_panel_data(dssdev);
 53	struct omap_dss_device *in = ddata->in;
 54
 55	dev_dbg(ddata->dev, "connect\n");
 56
 57	if (omapdss_device_is_connected(dssdev))
 58		return 0;
 59
 60	return in->ops.hdmi->connect(in, dssdev);
 61}
 62
 63static void hdmic_disconnect(struct omap_dss_device *dssdev)
 64{
 65	struct panel_drv_data *ddata = to_panel_data(dssdev);
 66	struct omap_dss_device *in = ddata->in;
 67
 68	dev_dbg(ddata->dev, "disconnect\n");
 69
 70	if (!omapdss_device_is_connected(dssdev))
 71		return;
 72
 73	in->ops.hdmi->disconnect(in, dssdev);
 74}
 75
 76static int hdmic_enable(struct omap_dss_device *dssdev)
 77{
 78	struct panel_drv_data *ddata = to_panel_data(dssdev);
 79	struct omap_dss_device *in = ddata->in;
 80	int r;
 81
 82	dev_dbg(ddata->dev, "enable\n");
 83
 84	if (!omapdss_device_is_connected(dssdev))
 85		return -ENODEV;
 86
 87	if (omapdss_device_is_enabled(dssdev))
 88		return 0;
 89
 90	in->ops.hdmi->set_timings(in, &ddata->timings);
 91
 92	r = in->ops.hdmi->enable(in);
 93	if (r)
 94		return r;
 95
 96	dssdev->state = OMAP_DSS_DISPLAY_ACTIVE;
 97
 98	return r;
 99}
100
101static void hdmic_disable(struct omap_dss_device *dssdev)
102{
103	struct panel_drv_data *ddata = to_panel_data(dssdev);
104	struct omap_dss_device *in = ddata->in;
105
106	dev_dbg(ddata->dev, "disable\n");
107
108	if (!omapdss_device_is_enabled(dssdev))
109		return;
110
111	in->ops.hdmi->disable(in);
112
113	dssdev->state = OMAP_DSS_DISPLAY_DISABLED;
114}
115
116static void hdmic_set_timings(struct omap_dss_device *dssdev,
117		struct omap_video_timings *timings)
118{
119	struct panel_drv_data *ddata = to_panel_data(dssdev);
120	struct omap_dss_device *in = ddata->in;
121
122	ddata->timings = *timings;
123	dssdev->panel.timings = *timings;
124
125	in->ops.hdmi->set_timings(in, timings);
126}
127
128static void hdmic_get_timings(struct omap_dss_device *dssdev,
129		struct omap_video_timings *timings)
130{
131	struct panel_drv_data *ddata = to_panel_data(dssdev);
132
133	*timings = ddata->timings;
134}
135
136static int hdmic_check_timings(struct omap_dss_device *dssdev,
137		struct omap_video_timings *timings)
138{
139	struct panel_drv_data *ddata = to_panel_data(dssdev);
140	struct omap_dss_device *in = ddata->in;
141
142	return in->ops.hdmi->check_timings(in, timings);
143}
144
145static int hdmic_read_edid(struct omap_dss_device *dssdev,
146		u8 *edid, int len)
147{
148	struct panel_drv_data *ddata = to_panel_data(dssdev);
149	struct omap_dss_device *in = ddata->in;
150
151	return in->ops.hdmi->read_edid(in, edid, len);
152}
153
154static bool hdmic_detect(struct omap_dss_device *dssdev)
155{
156	struct panel_drv_data *ddata = to_panel_data(dssdev);
157	struct omap_dss_device *in = ddata->in;
158
159	if (ddata->hpd_gpio)
160		return gpiod_get_value_cansleep(ddata->hpd_gpio);
161	else
162		return in->ops.hdmi->detect(in);
163}
164
165static int hdmic_set_hdmi_mode(struct omap_dss_device *dssdev, bool hdmi_mode)
166{
167	struct panel_drv_data *ddata = to_panel_data(dssdev);
168	struct omap_dss_device *in = ddata->in;
169
170	return in->ops.hdmi->set_hdmi_mode(in, hdmi_mode);
171}
172
173static int hdmic_set_infoframe(struct omap_dss_device *dssdev,
174		const struct hdmi_avi_infoframe *avi)
175{
176	struct panel_drv_data *ddata = to_panel_data(dssdev);
177	struct omap_dss_device *in = ddata->in;
178
179	return in->ops.hdmi->set_infoframe(in, avi);
180}
181
182static struct omap_dss_driver hdmic_driver = {
183	.connect		= hdmic_connect,
184	.disconnect		= hdmic_disconnect,
185
186	.enable			= hdmic_enable,
187	.disable		= hdmic_disable,
188
189	.set_timings		= hdmic_set_timings,
190	.get_timings		= hdmic_get_timings,
191	.check_timings		= hdmic_check_timings,
192
193	.get_resolution		= omapdss_default_get_resolution,
194
195	.read_edid		= hdmic_read_edid,
196	.detect			= hdmic_detect,
197	.set_hdmi_mode		= hdmic_set_hdmi_mode,
198	.set_hdmi_infoframe	= hdmic_set_infoframe,
199};
200
201static int hdmic_probe(struct platform_device *pdev)
202{
203	struct panel_drv_data *ddata;
204	struct omap_dss_device *dssdev;
205	int r;
206
207	if (!pdev->dev.of_node)
208		return -ENODEV;
209
210	ddata = devm_kzalloc(&pdev->dev, sizeof(*ddata), GFP_KERNEL);
211	if (!ddata)
212		return -ENOMEM;
213
214	platform_set_drvdata(pdev, ddata);
215	ddata->dev = &pdev->dev;
216
217	ddata->hpd_gpio = devm_gpiod_get_optional(&pdev->dev, "hpd", GPIOD_IN);
218	r = PTR_ERR_OR_ZERO(ddata->hpd_gpio);
219	if (r)
220		return r;
221
222	gpiod_set_consumer_name(ddata->hpd_gpio, "hdmi_hpd");
223
224	ddata->in = omapdss_of_find_source_for_first_ep(pdev->dev.of_node);
225	r = PTR_ERR_OR_ZERO(ddata->in);
226	if (r) {
227		dev_err(&pdev->dev, "failed to find video source\n");
228		return r;
229	}
230
231	ddata->timings = hdmic_default_timings;
232
233	dssdev = &ddata->dssdev;
234	dssdev->driver = &hdmic_driver;
235	dssdev->dev = &pdev->dev;
236	dssdev->type = OMAP_DISPLAY_TYPE_HDMI;
237	dssdev->owner = THIS_MODULE;
238	dssdev->panel.timings = hdmic_default_timings;
239
240	r = omapdss_register_display(dssdev);
241	if (r) {
242		dev_err(&pdev->dev, "Failed to register panel\n");
243		goto err_reg;
244	}
245
246	return 0;
247err_reg:
248	omap_dss_put_device(ddata->in);
249	return r;
250}
251
252static void hdmic_remove(struct platform_device *pdev)
253{
254	struct panel_drv_data *ddata = platform_get_drvdata(pdev);
255	struct omap_dss_device *dssdev = &ddata->dssdev;
256	struct omap_dss_device *in = ddata->in;
257
258	omapdss_unregister_display(&ddata->dssdev);
259
260	hdmic_disable(dssdev);
261	hdmic_disconnect(dssdev);
262
263	omap_dss_put_device(in);
264}
265
266static const struct of_device_id hdmic_of_match[] = {
267	{ .compatible = "omapdss,hdmi-connector", },
268	{},
269};
270
271MODULE_DEVICE_TABLE(of, hdmic_of_match);
272
273static struct platform_driver hdmi_connector_driver = {
274	.probe	= hdmic_probe,
275	.remove	= hdmic_remove,
276	.driver	= {
277		.name	= "connector-hdmi",
278		.of_match_table = hdmic_of_match,
279	},
280};
281
282module_platform_driver(hdmi_connector_driver);
283
284MODULE_AUTHOR("Tomi Valkeinen <tomi.valkeinen@ti.com>");
285MODULE_DESCRIPTION("HDMI Connector driver");
286MODULE_LICENSE("GPL");
~/ Read-only file preview.