Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

at v5.5-rc1 300 lines 7.4 kB view raw
1// SPDX-License-Identifier: GPL-2.0-or-later 2/* 3 * Copyright (C) 2015-2016 Free Electrons 4 * Copyright (C) 2015-2016 NextThing Co 5 * 6 * Maxime Ripard <maxime.ripard@free-electrons.com> 7 */ 8 9#include <linux/module.h> 10#include <linux/of_device.h> 11#include <linux/of_graph.h> 12#include <linux/regulator/consumer.h> 13 14#include <drm/drm_atomic_helper.h> 15#include <drm/drm_bridge.h> 16#include <drm/drm_crtc.h> 17#include <drm/drm_print.h> 18#include <drm/drm_probe_helper.h> 19 20struct dumb_vga { 21 struct drm_bridge bridge; 22 struct drm_connector connector; 23 24 struct i2c_adapter *ddc; 25 struct regulator *vdd; 26}; 27 28static inline struct dumb_vga * 29drm_bridge_to_dumb_vga(struct drm_bridge *bridge) 30{ 31 return container_of(bridge, struct dumb_vga, bridge); 32} 33 34static inline struct dumb_vga * 35drm_connector_to_dumb_vga(struct drm_connector *connector) 36{ 37 return container_of(connector, struct dumb_vga, connector); 38} 39 40static int dumb_vga_get_modes(struct drm_connector *connector) 41{ 42 struct dumb_vga *vga = drm_connector_to_dumb_vga(connector); 43 struct edid *edid; 44 int ret; 45 46 if (!vga->ddc) 47 goto fallback; 48 49 edid = drm_get_edid(connector, vga->ddc); 50 if (!edid) { 51 DRM_INFO("EDID readout failed, falling back to standard modes\n"); 52 goto fallback; 53 } 54 55 drm_connector_update_edid_property(connector, edid); 56 ret = drm_add_edid_modes(connector, edid); 57 kfree(edid); 58 return ret; 59 60fallback: 61 /* 62 * In case we cannot retrieve the EDIDs (broken or missing i2c 63 * bus), fallback on the XGA standards 64 */ 65 ret = drm_add_modes_noedid(connector, 1920, 1200); 66 67 /* And prefer a mode pretty much anyone can handle */ 68 drm_set_preferred_mode(connector, 1024, 768); 69 70 return ret; 71} 72 73static const struct drm_connector_helper_funcs dumb_vga_con_helper_funcs = { 74 .get_modes = dumb_vga_get_modes, 75}; 76 77static enum drm_connector_status 78dumb_vga_connector_detect(struct drm_connector *connector, bool force) 79{ 80 struct dumb_vga *vga = drm_connector_to_dumb_vga(connector); 81 82 /* 83 * Even if we have an I2C bus, we can't assume that the cable 84 * is disconnected if drm_probe_ddc fails. Some cables don't 85 * wire the DDC pins, or the I2C bus might not be working at 86 * all. 87 */ 88 if (vga->ddc && drm_probe_ddc(vga->ddc)) 89 return connector_status_connected; 90 91 return connector_status_unknown; 92} 93 94static const struct drm_connector_funcs dumb_vga_con_funcs = { 95 .detect = dumb_vga_connector_detect, 96 .fill_modes = drm_helper_probe_single_connector_modes, 97 .destroy = drm_connector_cleanup, 98 .reset = drm_atomic_helper_connector_reset, 99 .atomic_duplicate_state = drm_atomic_helper_connector_duplicate_state, 100 .atomic_destroy_state = drm_atomic_helper_connector_destroy_state, 101}; 102 103static int dumb_vga_attach(struct drm_bridge *bridge) 104{ 105 struct dumb_vga *vga = drm_bridge_to_dumb_vga(bridge); 106 int ret; 107 108 if (!bridge->encoder) { 109 DRM_ERROR("Missing encoder\n"); 110 return -ENODEV; 111 } 112 113 drm_connector_helper_add(&vga->connector, 114 &dumb_vga_con_helper_funcs); 115 ret = drm_connector_init_with_ddc(bridge->dev, &vga->connector, 116 &dumb_vga_con_funcs, 117 DRM_MODE_CONNECTOR_VGA, 118 vga->ddc); 119 if (ret) { 120 DRM_ERROR("Failed to initialize connector\n"); 121 return ret; 122 } 123 124 drm_connector_attach_encoder(&vga->connector, 125 bridge->encoder); 126 127 return 0; 128} 129 130static void dumb_vga_enable(struct drm_bridge *bridge) 131{ 132 struct dumb_vga *vga = drm_bridge_to_dumb_vga(bridge); 133 int ret = 0; 134 135 if (vga->vdd) 136 ret = regulator_enable(vga->vdd); 137 138 if (ret) 139 DRM_ERROR("Failed to enable vdd regulator: %d\n", ret); 140} 141 142static void dumb_vga_disable(struct drm_bridge *bridge) 143{ 144 struct dumb_vga *vga = drm_bridge_to_dumb_vga(bridge); 145 146 if (vga->vdd) 147 regulator_disable(vga->vdd); 148} 149 150static const struct drm_bridge_funcs dumb_vga_bridge_funcs = { 151 .attach = dumb_vga_attach, 152 .enable = dumb_vga_enable, 153 .disable = dumb_vga_disable, 154}; 155 156static struct i2c_adapter *dumb_vga_retrieve_ddc(struct device *dev) 157{ 158 struct device_node *phandle, *remote; 159 struct i2c_adapter *ddc; 160 161 remote = of_graph_get_remote_node(dev->of_node, 1, -1); 162 if (!remote) 163 return ERR_PTR(-EINVAL); 164 165 phandle = of_parse_phandle(remote, "ddc-i2c-bus", 0); 166 of_node_put(remote); 167 if (!phandle) 168 return ERR_PTR(-ENODEV); 169 170 ddc = of_get_i2c_adapter_by_node(phandle); 171 of_node_put(phandle); 172 if (!ddc) 173 return ERR_PTR(-EPROBE_DEFER); 174 175 return ddc; 176} 177 178static int dumb_vga_probe(struct platform_device *pdev) 179{ 180 struct dumb_vga *vga; 181 182 vga = devm_kzalloc(&pdev->dev, sizeof(*vga), GFP_KERNEL); 183 if (!vga) 184 return -ENOMEM; 185 platform_set_drvdata(pdev, vga); 186 187 vga->vdd = devm_regulator_get_optional(&pdev->dev, "vdd"); 188 if (IS_ERR(vga->vdd)) { 189 int ret = PTR_ERR(vga->vdd); 190 if (ret == -EPROBE_DEFER) 191 return -EPROBE_DEFER; 192 vga->vdd = NULL; 193 dev_dbg(&pdev->dev, "No vdd regulator found: %d\n", ret); 194 } 195 196 vga->ddc = dumb_vga_retrieve_ddc(&pdev->dev); 197 if (IS_ERR(vga->ddc)) { 198 if (PTR_ERR(vga->ddc) == -ENODEV) { 199 dev_dbg(&pdev->dev, 200 "No i2c bus specified. Disabling EDID readout\n"); 201 vga->ddc = NULL; 202 } else { 203 dev_err(&pdev->dev, "Couldn't retrieve i2c bus\n"); 204 return PTR_ERR(vga->ddc); 205 } 206 } 207 208 vga->bridge.funcs = &dumb_vga_bridge_funcs; 209 vga->bridge.of_node = pdev->dev.of_node; 210 vga->bridge.timings = of_device_get_match_data(&pdev->dev); 211 212 drm_bridge_add(&vga->bridge); 213 214 return 0; 215} 216 217static int dumb_vga_remove(struct platform_device *pdev) 218{ 219 struct dumb_vga *vga = platform_get_drvdata(pdev); 220 221 drm_bridge_remove(&vga->bridge); 222 223 if (vga->ddc) 224 i2c_put_adapter(vga->ddc); 225 226 return 0; 227} 228 229/* 230 * We assume the ADV7123 DAC is the "default" for historical reasons 231 * Information taken from the ADV7123 datasheet, revision D. 232 * NOTE: the ADV7123EP seems to have other timings and need a new timings 233 * set if used. 234 */ 235static const struct drm_bridge_timings default_dac_timings = { 236 /* Timing specifications, datasheet page 7 */ 237 .input_bus_flags = DRM_BUS_FLAG_PIXDATA_SAMPLE_POSEDGE, 238 .setup_time_ps = 500, 239 .hold_time_ps = 1500, 240}; 241 242/* 243 * Information taken from the THS8134, THS8134A, THS8134B datasheet named 244 * "SLVS205D", dated May 1990, revised March 2000. 245 */ 246static const struct drm_bridge_timings ti_ths8134_dac_timings = { 247 /* From timing diagram, datasheet page 9 */ 248 .input_bus_flags = DRM_BUS_FLAG_PIXDATA_SAMPLE_POSEDGE, 249 /* From datasheet, page 12 */ 250 .setup_time_ps = 3000, 251 /* I guess this means latched input */ 252 .hold_time_ps = 0, 253}; 254 255/* 256 * Information taken from the THS8135 datasheet named "SLAS343B", dated 257 * May 2001, revised April 2013. 258 */ 259static const struct drm_bridge_timings ti_ths8135_dac_timings = { 260 /* From timing diagram, datasheet page 14 */ 261 .input_bus_flags = DRM_BUS_FLAG_PIXDATA_SAMPLE_POSEDGE, 262 /* From datasheet, page 16 */ 263 .setup_time_ps = 2000, 264 .hold_time_ps = 500, 265}; 266 267static const struct of_device_id dumb_vga_match[] = { 268 { 269 .compatible = "dumb-vga-dac", 270 .data = NULL, 271 }, 272 { 273 .compatible = "adi,adv7123", 274 .data = &default_dac_timings, 275 }, 276 { 277 .compatible = "ti,ths8135", 278 .data = &ti_ths8135_dac_timings, 279 }, 280 { 281 .compatible = "ti,ths8134", 282 .data = &ti_ths8134_dac_timings, 283 }, 284 {}, 285}; 286MODULE_DEVICE_TABLE(of, dumb_vga_match); 287 288static struct platform_driver dumb_vga_driver = { 289 .probe = dumb_vga_probe, 290 .remove = dumb_vga_remove, 291 .driver = { 292 .name = "dumb-vga-dac", 293 .of_match_table = dumb_vga_match, 294 }, 295}; 296module_platform_driver(dumb_vga_driver); 297 298MODULE_AUTHOR("Maxime Ripard <maxime.ripard@free-electrons.com>"); 299MODULE_DESCRIPTION("Dumb VGA DAC bridge driver"); 300MODULE_LICENSE("GPL");