root/drivers/video/fbdev/omap2/omapfb/displays/connector-dvi.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. dvic_connect
  2. dvic_disconnect
  3. dvic_enable
  4. dvic_disable
  5. dvic_set_timings
  6. dvic_get_timings
  7. dvic_check_timings
  8. dvic_ddc_read
  9. dvic_read_edid
  10. dvic_detect
  11. dvic_probe_of
  12. dvic_probe
  13. dvic_remove

   1 // SPDX-License-Identifier: GPL-2.0-only
   2 /*
   3  * Generic DVI Connector driver
   4  *
   5  * Copyright (C) 2013 Texas Instruments
   6  * Author: Tomi Valkeinen <tomi.valkeinen@ti.com>
   7  */
   8 
   9 #include <linux/i2c.h>
  10 #include <linux/module.h>
  11 #include <linux/platform_device.h>
  12 #include <linux/slab.h>
  13 
  14 #include <drm/drm_edid.h>
  15 
  16 #include <video/omapfb_dss.h>
  17 
  18 static const struct omap_video_timings dvic_default_timings = {
  19         .x_res          = 640,
  20         .y_res          = 480,
  21 
  22         .pixelclock     = 23500000,
  23 
  24         .hfp            = 48,
  25         .hsw            = 32,
  26         .hbp            = 80,
  27 
  28         .vfp            = 3,
  29         .vsw            = 4,
  30         .vbp            = 7,
  31 
  32         .vsync_level    = OMAPDSS_SIG_ACTIVE_HIGH,
  33         .hsync_level    = OMAPDSS_SIG_ACTIVE_HIGH,
  34         .data_pclk_edge = OMAPDSS_DRIVE_SIG_RISING_EDGE,
  35         .de_level       = OMAPDSS_SIG_ACTIVE_HIGH,
  36         .sync_pclk_edge = OMAPDSS_DRIVE_SIG_FALLING_EDGE,
  37 };
  38 
  39 struct panel_drv_data {
  40         struct omap_dss_device dssdev;
  41         struct omap_dss_device *in;
  42 
  43         struct omap_video_timings timings;
  44 
  45         struct i2c_adapter *i2c_adapter;
  46 };
  47 
  48 #define to_panel_data(x) container_of(x, struct panel_drv_data, dssdev)
  49 
  50 static int dvic_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         int r;
  55 
  56         if (omapdss_device_is_connected(dssdev))
  57                 return 0;
  58 
  59         r = in->ops.dvi->connect(in, dssdev);
  60         if (r)
  61                 return r;
  62 
  63         return 0;
  64 }
  65 
  66 static void dvic_disconnect(struct omap_dss_device *dssdev)
  67 {
  68         struct panel_drv_data *ddata = to_panel_data(dssdev);
  69         struct omap_dss_device *in = ddata->in;
  70 
  71         if (!omapdss_device_is_connected(dssdev))
  72                 return;
  73 
  74         in->ops.dvi->disconnect(in, dssdev);
  75 }
  76 
  77 static int dvic_enable(struct omap_dss_device *dssdev)
  78 {
  79         struct panel_drv_data *ddata = to_panel_data(dssdev);
  80         struct omap_dss_device *in = ddata->in;
  81         int r;
  82 
  83         if (!omapdss_device_is_connected(dssdev))
  84                 return -ENODEV;
  85 
  86         if (omapdss_device_is_enabled(dssdev))
  87                 return 0;
  88 
  89         in->ops.dvi->set_timings(in, &ddata->timings);
  90 
  91         r = in->ops.dvi->enable(in);
  92         if (r)
  93                 return r;
  94 
  95         dssdev->state = OMAP_DSS_DISPLAY_ACTIVE;
  96 
  97         return 0;
  98 }
  99 
 100 static void dvic_disable(struct omap_dss_device *dssdev)
 101 {
 102         struct panel_drv_data *ddata = to_panel_data(dssdev);
 103         struct omap_dss_device *in = ddata->in;
 104 
 105         if (!omapdss_device_is_enabled(dssdev))
 106                 return;
 107 
 108         in->ops.dvi->disable(in);
 109 
 110         dssdev->state = OMAP_DSS_DISPLAY_DISABLED;
 111 }
 112 
 113 static void dvic_set_timings(struct omap_dss_device *dssdev,
 114                 struct omap_video_timings *timings)
 115 {
 116         struct panel_drv_data *ddata = to_panel_data(dssdev);
 117         struct omap_dss_device *in = ddata->in;
 118 
 119         ddata->timings = *timings;
 120         dssdev->panel.timings = *timings;
 121 
 122         in->ops.dvi->set_timings(in, timings);
 123 }
 124 
 125 static void dvic_get_timings(struct omap_dss_device *dssdev,
 126                 struct omap_video_timings *timings)
 127 {
 128         struct panel_drv_data *ddata = to_panel_data(dssdev);
 129 
 130         *timings = ddata->timings;
 131 }
 132 
 133 static int dvic_check_timings(struct omap_dss_device *dssdev,
 134                 struct omap_video_timings *timings)
 135 {
 136         struct panel_drv_data *ddata = to_panel_data(dssdev);
 137         struct omap_dss_device *in = ddata->in;
 138 
 139         return in->ops.dvi->check_timings(in, timings);
 140 }
 141 
 142 static int dvic_ddc_read(struct i2c_adapter *adapter,
 143                 unsigned char *buf, u16 count, u8 offset)
 144 {
 145         int r, retries;
 146 
 147         for (retries = 3; retries > 0; retries--) {
 148                 struct i2c_msg msgs[] = {
 149                         {
 150                                 .addr   = DDC_ADDR,
 151                                 .flags  = 0,
 152                                 .len    = 1,
 153                                 .buf    = &offset,
 154                         }, {
 155                                 .addr   = DDC_ADDR,
 156                                 .flags  = I2C_M_RD,
 157                                 .len    = count,
 158                                 .buf    = buf,
 159                         }
 160                 };
 161 
 162                 r = i2c_transfer(adapter, msgs, 2);
 163                 if (r == 2)
 164                         return 0;
 165 
 166                 if (r != -EAGAIN)
 167                         break;
 168         }
 169 
 170         return r < 0 ? r : -EIO;
 171 }
 172 
 173 static int dvic_read_edid(struct omap_dss_device *dssdev,
 174                 u8 *edid, int len)
 175 {
 176         struct panel_drv_data *ddata = to_panel_data(dssdev);
 177         int r, l, bytes_read;
 178 
 179         if (!ddata->i2c_adapter)
 180                 return -ENODEV;
 181 
 182         l = min(EDID_LENGTH, len);
 183         r = dvic_ddc_read(ddata->i2c_adapter, edid, l, 0);
 184         if (r)
 185                 return r;
 186 
 187         bytes_read = l;
 188 
 189         /* if there are extensions, read second block */
 190         if (len > EDID_LENGTH && edid[0x7e] > 0) {
 191                 l = min(EDID_LENGTH, len - EDID_LENGTH);
 192 
 193                 r = dvic_ddc_read(ddata->i2c_adapter, edid + EDID_LENGTH,
 194                                 l, EDID_LENGTH);
 195                 if (r)
 196                         return r;
 197 
 198                 bytes_read += l;
 199         }
 200 
 201         return bytes_read;
 202 }
 203 
 204 static bool dvic_detect(struct omap_dss_device *dssdev)
 205 {
 206         struct panel_drv_data *ddata = to_panel_data(dssdev);
 207         unsigned char out;
 208         int r;
 209 
 210         if (!ddata->i2c_adapter)
 211                 return true;
 212 
 213         r = dvic_ddc_read(ddata->i2c_adapter, &out, 1, 0);
 214 
 215         return r == 0;
 216 }
 217 
 218 static struct omap_dss_driver dvic_driver = {
 219         .connect        = dvic_connect,
 220         .disconnect     = dvic_disconnect,
 221 
 222         .enable         = dvic_enable,
 223         .disable        = dvic_disable,
 224 
 225         .set_timings    = dvic_set_timings,
 226         .get_timings    = dvic_get_timings,
 227         .check_timings  = dvic_check_timings,
 228 
 229         .get_resolution = omapdss_default_get_resolution,
 230 
 231         .read_edid      = dvic_read_edid,
 232         .detect         = dvic_detect,
 233 };
 234 
 235 static int dvic_probe_of(struct platform_device *pdev)
 236 {
 237         struct panel_drv_data *ddata = platform_get_drvdata(pdev);
 238         struct device_node *node = pdev->dev.of_node;
 239         struct omap_dss_device *in;
 240         struct device_node *adapter_node;
 241         struct i2c_adapter *adapter;
 242 
 243         in = omapdss_of_find_source_for_first_ep(node);
 244         if (IS_ERR(in)) {
 245                 dev_err(&pdev->dev, "failed to find video source\n");
 246                 return PTR_ERR(in);
 247         }
 248 
 249         ddata->in = in;
 250 
 251         adapter_node = of_parse_phandle(node, "ddc-i2c-bus", 0);
 252         if (adapter_node) {
 253                 adapter = of_get_i2c_adapter_by_node(adapter_node);
 254                 if (adapter == NULL) {
 255                         dev_err(&pdev->dev, "failed to parse ddc-i2c-bus\n");
 256                         omap_dss_put_device(ddata->in);
 257                         return -EPROBE_DEFER;
 258                 }
 259 
 260                 ddata->i2c_adapter = adapter;
 261         }
 262 
 263         return 0;
 264 }
 265 
 266 static int dvic_probe(struct platform_device *pdev)
 267 {
 268         struct panel_drv_data *ddata;
 269         struct omap_dss_device *dssdev;
 270         int r;
 271 
 272         if (!pdev->dev.of_node)
 273                 return -ENODEV;
 274 
 275         ddata = devm_kzalloc(&pdev->dev, sizeof(*ddata), GFP_KERNEL);
 276         if (!ddata)
 277                 return -ENOMEM;
 278 
 279         platform_set_drvdata(pdev, ddata);
 280 
 281         r = dvic_probe_of(pdev);
 282         if (r)
 283                 return r;
 284 
 285         ddata->timings = dvic_default_timings;
 286 
 287         dssdev = &ddata->dssdev;
 288         dssdev->driver = &dvic_driver;
 289         dssdev->dev = &pdev->dev;
 290         dssdev->type = OMAP_DISPLAY_TYPE_DVI;
 291         dssdev->owner = THIS_MODULE;
 292         dssdev->panel.timings = dvic_default_timings;
 293 
 294         r = omapdss_register_display(dssdev);
 295         if (r) {
 296                 dev_err(&pdev->dev, "Failed to register panel\n");
 297                 goto err_reg;
 298         }
 299 
 300         return 0;
 301 
 302 err_reg:
 303         omap_dss_put_device(ddata->in);
 304 
 305         i2c_put_adapter(ddata->i2c_adapter);
 306 
 307         return r;
 308 }
 309 
 310 static int __exit dvic_remove(struct platform_device *pdev)
 311 {
 312         struct panel_drv_data *ddata = platform_get_drvdata(pdev);
 313         struct omap_dss_device *dssdev = &ddata->dssdev;
 314         struct omap_dss_device *in = ddata->in;
 315 
 316         omapdss_unregister_display(&ddata->dssdev);
 317 
 318         dvic_disable(dssdev);
 319         dvic_disconnect(dssdev);
 320 
 321         omap_dss_put_device(in);
 322 
 323         i2c_put_adapter(ddata->i2c_adapter);
 324 
 325         return 0;
 326 }
 327 
 328 static const struct of_device_id dvic_of_match[] = {
 329         { .compatible = "omapdss,dvi-connector", },
 330         {},
 331 };
 332 
 333 MODULE_DEVICE_TABLE(of, dvic_of_match);
 334 
 335 static struct platform_driver dvi_connector_driver = {
 336         .probe  = dvic_probe,
 337         .remove = __exit_p(dvic_remove),
 338         .driver = {
 339                 .name   = "connector-dvi",
 340                 .of_match_table = dvic_of_match,
 341                 .suppress_bind_attrs = true,
 342         },
 343 };
 344 
 345 module_platform_driver(dvi_connector_driver);
 346 
 347 MODULE_AUTHOR("Tomi Valkeinen <tomi.valkeinen@ti.com>");
 348 MODULE_DESCRIPTION("Generic DVI Connector driver");
 349 MODULE_LICENSE("GPL");

/* [<][>][^][v][top][bottom][index][help] */