1 /* 2 * Copyright (C) 2016 Texas Instruments 3 * Author: Jyri Sarha <jsarha@ti.com> 4 * 5 * This program is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 as published by 7 * the Free Software Foundation. 8 * 9 */ 10 11 #include <linux/module.h> 12 #include <linux/of_graph.h> 13 #include <linux/platform_device.h> 14 #include <linux/i2c.h> 15 16 #include <drm/drmP.h> 17 #include <drm/drm_atomic_helper.h> 18 #include <drm/drm_crtc.h> 19 #include <drm/drm_crtc_helper.h> 20 21 struct tfp410 { 22 struct drm_bridge bridge; 23 struct drm_connector connector; 24 25 struct i2c_adapter *ddc; 26 27 struct device *dev; 28 }; 29 30 static inline struct tfp410 * 31 drm_bridge_to_tfp410(struct drm_bridge *bridge) 32 { 33 return container_of(bridge, struct tfp410, bridge); 34 } 35 36 static inline struct tfp410 * 37 drm_connector_to_tfp410(struct drm_connector *connector) 38 { 39 return container_of(connector, struct tfp410, connector); 40 } 41 42 static int tfp410_get_modes(struct drm_connector *connector) 43 { 44 struct tfp410 *dvi = drm_connector_to_tfp410(connector); 45 struct edid *edid; 46 int ret; 47 48 if (!dvi->ddc) 49 goto fallback; 50 51 edid = drm_get_edid(connector, dvi->ddc); 52 if (!edid) { 53 DRM_INFO("EDID read failed. Fallback to standard modes\n"); 54 goto fallback; 55 } 56 57 drm_mode_connector_update_edid_property(connector, edid); 58 59 return drm_add_edid_modes(connector, edid); 60 fallback: 61 /* No EDID, fallback on the XGA standard modes */ 62 ret = drm_add_modes_noedid(connector, 1920, 1200); 63 64 /* And prefer a mode pretty much anything can handle */ 65 drm_set_preferred_mode(connector, 1024, 768); 66 67 return ret; 68 } 69 70 static const struct drm_connector_helper_funcs tfp410_con_helper_funcs = { 71 .get_modes = tfp410_get_modes, 72 }; 73 74 static enum drm_connector_status 75 tfp410_connector_detect(struct drm_connector *connector, bool force) 76 { 77 struct tfp410 *dvi = drm_connector_to_tfp410(connector); 78 79 if (dvi->ddc) { 80 if (drm_probe_ddc(dvi->ddc)) 81 return connector_status_connected; 82 else 83 return connector_status_disconnected; 84 } 85 86 return connector_status_unknown; 87 } 88 89 static const struct drm_connector_funcs tfp410_con_funcs = { 90 .dpms = drm_atomic_helper_connector_dpms, 91 .detect = tfp410_connector_detect, 92 .fill_modes = drm_helper_probe_single_connector_modes, 93 .destroy = drm_connector_cleanup, 94 .reset = drm_atomic_helper_connector_reset, 95 .atomic_duplicate_state = drm_atomic_helper_connector_duplicate_state, 96 .atomic_destroy_state = drm_atomic_helper_connector_destroy_state, 97 }; 98 99 static int tfp410_attach(struct drm_bridge *bridge) 100 { 101 struct tfp410 *dvi = drm_bridge_to_tfp410(bridge); 102 int ret; 103 104 if (!bridge->encoder) { 105 dev_err(dvi->dev, "Missing encoder\n"); 106 return -ENODEV; 107 } 108 109 drm_connector_helper_add(&dvi->connector, 110 &tfp410_con_helper_funcs); 111 ret = drm_connector_init(bridge->dev, &dvi->connector, 112 &tfp410_con_funcs, DRM_MODE_CONNECTOR_HDMIA); 113 if (ret) { 114 dev_err(dvi->dev, "drm_connector_init() failed: %d\n", ret); 115 return ret; 116 } 117 118 drm_mode_connector_attach_encoder(&dvi->connector, 119 bridge->encoder); 120 121 return 0; 122 } 123 124 static const struct drm_bridge_funcs tfp410_bridge_funcs = { 125 .attach = tfp410_attach, 126 }; 127 128 static int tfp410_get_connector_ddc(struct tfp410 *dvi) 129 { 130 struct device_node *ep = NULL, *connector_node = NULL; 131 struct device_node *ddc_phandle = NULL; 132 int ret = 0; 133 134 /* port@1 is the connector node */ 135 ep = of_graph_get_endpoint_by_regs(dvi->dev->of_node, 1, -1); 136 if (!ep) 137 goto fail; 138 139 connector_node = of_graph_get_remote_port_parent(ep); 140 if (!connector_node) 141 goto fail; 142 143 ddc_phandle = of_parse_phandle(connector_node, "ddc-i2c-bus", 0); 144 if (!ddc_phandle) 145 goto fail; 146 147 dvi->ddc = of_get_i2c_adapter_by_node(ddc_phandle); 148 if (dvi->ddc) 149 dev_info(dvi->dev, "Connector's ddc i2c bus found\n"); 150 else 151 ret = -EPROBE_DEFER; 152 153 fail: 154 of_node_put(ep); 155 of_node_put(connector_node); 156 of_node_put(ddc_phandle); 157 return ret; 158 } 159 160 static int tfp410_init(struct device *dev) 161 { 162 struct tfp410 *dvi; 163 int ret; 164 165 if (!dev->of_node) { 166 dev_err(dev, "device-tree data is missing\n"); 167 return -ENXIO; 168 } 169 170 dvi = devm_kzalloc(dev, sizeof(*dvi), GFP_KERNEL); 171 if (!dvi) 172 return -ENOMEM; 173 dev_set_drvdata(dev, dvi); 174 175 dvi->bridge.funcs = &tfp410_bridge_funcs; 176 dvi->bridge.of_node = dev->of_node; 177 dvi->dev = dev; 178 179 ret = tfp410_get_connector_ddc(dvi); 180 if (ret) 181 goto fail; 182 183 ret = drm_bridge_add(&dvi->bridge); 184 if (ret) { 185 dev_err(dev, "drm_bridge_add() failed: %d\n", ret); 186 goto fail; 187 } 188 189 return 0; 190 fail: 191 i2c_put_adapter(dvi->ddc); 192 return ret; 193 } 194 195 static int tfp410_fini(struct device *dev) 196 { 197 struct tfp410 *dvi = dev_get_drvdata(dev); 198 199 drm_bridge_remove(&dvi->bridge); 200 201 if (dvi->ddc) 202 i2c_put_adapter(dvi->ddc); 203 204 return 0; 205 } 206 207 static int tfp410_probe(struct platform_device *pdev) 208 { 209 return tfp410_init(&pdev->dev); 210 } 211 212 static int tfp410_remove(struct platform_device *pdev) 213 { 214 return tfp410_fini(&pdev->dev); 215 } 216 217 static const struct of_device_id tfp410_match[] = { 218 { .compatible = "ti,tfp410" }, 219 {}, 220 }; 221 MODULE_DEVICE_TABLE(of, tfp410_match); 222 223 struct platform_driver tfp410_platform_driver = { 224 .probe = tfp410_probe, 225 .remove = tfp410_remove, 226 .driver = { 227 .name = "tfp410-bridge", 228 .of_match_table = tfp410_match, 229 }, 230 }; 231 232 #if IS_ENABLED(CONFIG_I2C) 233 /* There is currently no i2c functionality. */ 234 static int tfp410_i2c_probe(struct i2c_client *client, 235 const struct i2c_device_id *id) 236 { 237 int reg; 238 239 if (!client->dev.of_node || 240 of_property_read_u32(client->dev.of_node, "reg", ®)) { 241 dev_err(&client->dev, 242 "Can't get i2c reg property from device-tree\n"); 243 return -ENXIO; 244 } 245 246 return tfp410_init(&client->dev); 247 } 248 249 static int tfp410_i2c_remove(struct i2c_client *client) 250 { 251 return tfp410_fini(&client->dev); 252 } 253 254 static const struct i2c_device_id tfp410_i2c_ids[] = { 255 { "tfp410", 0 }, 256 { } 257 }; 258 MODULE_DEVICE_TABLE(i2c, tfp410_i2c_ids); 259 260 static struct i2c_driver tfp410_i2c_driver = { 261 .driver = { 262 .name = "tfp410", 263 .of_match_table = of_match_ptr(tfp410_match), 264 }, 265 .id_table = tfp410_i2c_ids, 266 .probe = tfp410_i2c_probe, 267 .remove = tfp410_i2c_remove, 268 }; 269 #endif /* IS_ENABLED(CONFIG_I2C) */ 270 271 static struct { 272 uint i2c:1; 273 uint platform:1; 274 } tfp410_registered_driver; 275 276 static int __init tfp410_module_init(void) 277 { 278 int ret; 279 280 #if IS_ENABLED(CONFIG_I2C) 281 ret = i2c_add_driver(&tfp410_i2c_driver); 282 if (ret) 283 pr_err("%s: registering i2c driver failed: %d", 284 __func__, ret); 285 else 286 tfp410_registered_driver.i2c = 1; 287 #endif 288 289 ret = platform_driver_register(&tfp410_platform_driver); 290 if (ret) 291 pr_err("%s: registering platform driver failed: %d", 292 __func__, ret); 293 else 294 tfp410_registered_driver.platform = 1; 295 296 if (tfp410_registered_driver.i2c || 297 tfp410_registered_driver.platform) 298 return 0; 299 300 return ret; 301 } 302 module_init(tfp410_module_init); 303 304 static void __exit tfp410_module_exit(void) 305 { 306 #if IS_ENABLED(CONFIG_I2C) 307 if (tfp410_registered_driver.i2c) 308 i2c_del_driver(&tfp410_i2c_driver); 309 #endif 310 if (tfp410_registered_driver.platform) 311 platform_driver_unregister(&tfp410_platform_driver); 312 } 313 module_exit(tfp410_module_exit); 314 315 MODULE_AUTHOR("Jyri Sarha <jsarha@ti.com>"); 316 MODULE_DESCRIPTION("TI TFP410 DVI bridge driver"); 317 MODULE_LICENSE("GPL"); 318