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