linux/drivers/video/fbdev/omap2/omapfb/displays/connector-hdmi.c
<<
>>
Prefs
   1/*
   2 * HDMI Connector driver
   3 *
   4 * Copyright (C) 2013 Texas Instruments
   5 * Author: Tomi Valkeinen <tomi.valkeinen@ti.com>
   6 *
   7 * This program is free software; you can redistribute it and/or modify it
   8 * under the terms of the GNU General Public License version 2 as published by
   9 * the Free Software Foundation.
  10 */
  11
  12#include <linux/slab.h>
  13#include <linux/module.h>
  14#include <linux/platform_device.h>
  15#include <linux/of.h>
  16#include <linux/of_gpio.h>
  17
  18#include <drm/drm_edid.h>
  19
  20#include <video/omapdss.h>
  21#include <video/omap-panel-data.h>
  22
  23static const struct omap_video_timings hdmic_default_timings = {
  24        .x_res          = 640,
  25        .y_res          = 480,
  26        .pixelclock     = 25175000,
  27        .hsw            = 96,
  28        .hfp            = 16,
  29        .hbp            = 48,
  30        .vsw            = 2,
  31        .vfp            = 11,
  32        .vbp            = 31,
  33
  34        .vsync_level    = OMAPDSS_SIG_ACTIVE_LOW,
  35        .hsync_level    = OMAPDSS_SIG_ACTIVE_LOW,
  36
  37        .interlace      = false,
  38};
  39
  40struct panel_drv_data {
  41        struct omap_dss_device dssdev;
  42        struct omap_dss_device *in;
  43
  44        struct device *dev;
  45
  46        struct omap_video_timings timings;
  47
  48        int hpd_gpio;
  49};
  50
  51#define to_panel_data(x) container_of(x, struct panel_drv_data, dssdev)
  52
  53static int hdmic_connect(struct omap_dss_device *dssdev)
  54{
  55        struct panel_drv_data *ddata = to_panel_data(dssdev);
  56        struct omap_dss_device *in = ddata->in;
  57        int r;
  58
  59        dev_dbg(ddata->dev, "connect\n");
  60
  61        if (omapdss_device_is_connected(dssdev))
  62                return 0;
  63
  64        r = in->ops.hdmi->connect(in, dssdev);
  65        if (r)
  66                return r;
  67
  68        return 0;
  69}
  70
  71static void hdmic_disconnect(struct omap_dss_device *dssdev)
  72{
  73        struct panel_drv_data *ddata = to_panel_data(dssdev);
  74        struct omap_dss_device *in = ddata->in;
  75
  76        dev_dbg(ddata->dev, "disconnect\n");
  77
  78        if (!omapdss_device_is_connected(dssdev))
  79                return;
  80
  81        in->ops.hdmi->disconnect(in, dssdev);
  82}
  83
  84static int hdmic_enable(struct omap_dss_device *dssdev)
  85{
  86        struct panel_drv_data *ddata = to_panel_data(dssdev);
  87        struct omap_dss_device *in = ddata->in;
  88        int r;
  89
  90        dev_dbg(ddata->dev, "enable\n");
  91
  92        if (!omapdss_device_is_connected(dssdev))
  93                return -ENODEV;
  94
  95        if (omapdss_device_is_enabled(dssdev))
  96                return 0;
  97
  98        in->ops.hdmi->set_timings(in, &ddata->timings);
  99
 100        r = in->ops.hdmi->enable(in);
 101        if (r)
 102                return r;
 103
 104        dssdev->state = OMAP_DSS_DISPLAY_ACTIVE;
 105
 106        return r;
 107}
 108
 109static void hdmic_disable(struct omap_dss_device *dssdev)
 110{
 111        struct panel_drv_data *ddata = to_panel_data(dssdev);
 112        struct omap_dss_device *in = ddata->in;
 113
 114        dev_dbg(ddata->dev, "disable\n");
 115
 116        if (!omapdss_device_is_enabled(dssdev))
 117                return;
 118
 119        in->ops.hdmi->disable(in);
 120
 121        dssdev->state = OMAP_DSS_DISPLAY_DISABLED;
 122}
 123
 124static void hdmic_set_timings(struct omap_dss_device *dssdev,
 125                struct omap_video_timings *timings)
 126{
 127        struct panel_drv_data *ddata = to_panel_data(dssdev);
 128        struct omap_dss_device *in = ddata->in;
 129
 130        ddata->timings = *timings;
 131        dssdev->panel.timings = *timings;
 132
 133        in->ops.hdmi->set_timings(in, timings);
 134}
 135
 136static void hdmic_get_timings(struct omap_dss_device *dssdev,
 137                struct omap_video_timings *timings)
 138{
 139        struct panel_drv_data *ddata = to_panel_data(dssdev);
 140
 141        *timings = ddata->timings;
 142}
 143
 144static int hdmic_check_timings(struct omap_dss_device *dssdev,
 145                struct omap_video_timings *timings)
 146{
 147        struct panel_drv_data *ddata = to_panel_data(dssdev);
 148        struct omap_dss_device *in = ddata->in;
 149
 150        return in->ops.hdmi->check_timings(in, timings);
 151}
 152
 153static int hdmic_read_edid(struct omap_dss_device *dssdev,
 154                u8 *edid, int len)
 155{
 156        struct panel_drv_data *ddata = to_panel_data(dssdev);
 157        struct omap_dss_device *in = ddata->in;
 158
 159        return in->ops.hdmi->read_edid(in, edid, len);
 160}
 161
 162static bool hdmic_detect(struct omap_dss_device *dssdev)
 163{
 164        struct panel_drv_data *ddata = to_panel_data(dssdev);
 165        struct omap_dss_device *in = ddata->in;
 166
 167        if (gpio_is_valid(ddata->hpd_gpio))
 168                return gpio_get_value_cansleep(ddata->hpd_gpio);
 169        else
 170                return in->ops.hdmi->detect(in);
 171}
 172
 173static int hdmic_set_hdmi_mode(struct omap_dss_device *dssdev, bool hdmi_mode)
 174{
 175        struct panel_drv_data *ddata = to_panel_data(dssdev);
 176        struct omap_dss_device *in = ddata->in;
 177
 178        return in->ops.hdmi->set_hdmi_mode(in, hdmi_mode);
 179}
 180
 181static int hdmic_set_infoframe(struct omap_dss_device *dssdev,
 182                const struct hdmi_avi_infoframe *avi)
 183{
 184        struct panel_drv_data *ddata = to_panel_data(dssdev);
 185        struct omap_dss_device *in = ddata->in;
 186
 187        return in->ops.hdmi->set_infoframe(in, avi);
 188}
 189
 190static struct omap_dss_driver hdmic_driver = {
 191        .connect                = hdmic_connect,
 192        .disconnect             = hdmic_disconnect,
 193
 194        .enable                 = hdmic_enable,
 195        .disable                = hdmic_disable,
 196
 197        .set_timings            = hdmic_set_timings,
 198        .get_timings            = hdmic_get_timings,
 199        .check_timings          = hdmic_check_timings,
 200
 201        .get_resolution         = omapdss_default_get_resolution,
 202
 203        .read_edid              = hdmic_read_edid,
 204        .detect                 = hdmic_detect,
 205        .set_hdmi_mode          = hdmic_set_hdmi_mode,
 206        .set_hdmi_infoframe     = hdmic_set_infoframe,
 207};
 208
 209static int hdmic_probe_pdata(struct platform_device *pdev)
 210{
 211        struct panel_drv_data *ddata = platform_get_drvdata(pdev);
 212        struct connector_hdmi_platform_data *pdata;
 213        struct omap_dss_device *in, *dssdev;
 214
 215        pdata = dev_get_platdata(&pdev->dev);
 216
 217        ddata->hpd_gpio = -ENODEV;
 218
 219        in = omap_dss_find_output(pdata->source);
 220        if (in == NULL) {
 221                dev_err(&pdev->dev, "Failed to find video source\n");
 222                return -EPROBE_DEFER;
 223        }
 224
 225        ddata->in = in;
 226
 227        dssdev = &ddata->dssdev;
 228        dssdev->name = pdata->name;
 229
 230        return 0;
 231}
 232
 233static int hdmic_probe_of(struct platform_device *pdev)
 234{
 235        struct panel_drv_data *ddata = platform_get_drvdata(pdev);
 236        struct device_node *node = pdev->dev.of_node;
 237        struct omap_dss_device *in;
 238        int gpio;
 239
 240        /* HPD GPIO */
 241        gpio = of_get_named_gpio(node, "hpd-gpios", 0);
 242        if (gpio_is_valid(gpio))
 243                ddata->hpd_gpio = gpio;
 244        else
 245                ddata->hpd_gpio = -ENODEV;
 246
 247        in = omapdss_of_find_source_for_first_ep(node);
 248        if (IS_ERR(in)) {
 249                dev_err(&pdev->dev, "failed to find video source\n");
 250                return PTR_ERR(in);
 251        }
 252
 253        ddata->in = in;
 254
 255        return 0;
 256}
 257
 258static int hdmic_probe(struct platform_device *pdev)
 259{
 260        struct panel_drv_data *ddata;
 261        struct omap_dss_device *dssdev;
 262        int r;
 263
 264        ddata = devm_kzalloc(&pdev->dev, sizeof(*ddata), GFP_KERNEL);
 265        if (!ddata)
 266                return -ENOMEM;
 267
 268        platform_set_drvdata(pdev, ddata);
 269        ddata->dev = &pdev->dev;
 270
 271        if (dev_get_platdata(&pdev->dev)) {
 272                r = hdmic_probe_pdata(pdev);
 273                if (r)
 274                        return r;
 275        } else if (pdev->dev.of_node) {
 276                r = hdmic_probe_of(pdev);
 277                if (r)
 278                        return r;
 279        } else {
 280                return -ENODEV;
 281        }
 282
 283        if (gpio_is_valid(ddata->hpd_gpio)) {
 284                r = devm_gpio_request_one(&pdev->dev, ddata->hpd_gpio,
 285                                GPIOF_DIR_IN, "hdmi_hpd");
 286                if (r)
 287                        goto err_reg;
 288        }
 289
 290        ddata->timings = hdmic_default_timings;
 291
 292        dssdev = &ddata->dssdev;
 293        dssdev->driver = &hdmic_driver;
 294        dssdev->dev = &pdev->dev;
 295        dssdev->type = OMAP_DISPLAY_TYPE_HDMI;
 296        dssdev->owner = THIS_MODULE;
 297        dssdev->panel.timings = hdmic_default_timings;
 298
 299        r = omapdss_register_display(dssdev);
 300        if (r) {
 301                dev_err(&pdev->dev, "Failed to register panel\n");
 302                goto err_reg;
 303        }
 304
 305        return 0;
 306err_reg:
 307        omap_dss_put_device(ddata->in);
 308        return r;
 309}
 310
 311static int __exit hdmic_remove(struct platform_device *pdev)
 312{
 313        struct panel_drv_data *ddata = platform_get_drvdata(pdev);
 314        struct omap_dss_device *dssdev = &ddata->dssdev;
 315        struct omap_dss_device *in = ddata->in;
 316
 317        omapdss_unregister_display(&ddata->dssdev);
 318
 319        hdmic_disable(dssdev);
 320        hdmic_disconnect(dssdev);
 321
 322        omap_dss_put_device(in);
 323
 324        return 0;
 325}
 326
 327static const struct of_device_id hdmic_of_match[] = {
 328        { .compatible = "omapdss,hdmi-connector", },
 329        {},
 330};
 331
 332MODULE_DEVICE_TABLE(of, hdmic_of_match);
 333
 334static struct platform_driver hdmi_connector_driver = {
 335        .probe  = hdmic_probe,
 336        .remove = __exit_p(hdmic_remove),
 337        .driver = {
 338                .name   = "connector-hdmi",
 339                .of_match_table = hdmic_of_match,
 340                .suppress_bind_attrs = true,
 341        },
 342};
 343
 344module_platform_driver(hdmi_connector_driver);
 345
 346MODULE_AUTHOR("Tomi Valkeinen <tomi.valkeinen@ti.com>");
 347MODULE_DESCRIPTION("HDMI Connector driver");
 348MODULE_LICENSE("GPL");
 349