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