brintos

brintos / linux-shallow public Read only

0
0
Text · 6.4 KiB · e3df731 Raw
287 lines · c
1// SPDX-License-Identifier: GPL-2.0-only2/*3 * HDMI Connector driver4 *5 * Copyright (C) 2013 Texas Instruments6 * 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	else162		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");287