FILE
connector-hdmi.c
File preview with syntax highlighting.
linux-6.19.14/drivers/video/fbdev/omap2/omapfb/displays/connector-hdmi.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.