linux/drivers/gpu/drm/bridge/ti-tfp410.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0-only
   2/*
   3 * Copyright (C) 2016 Texas Instruments
   4 * Author: Jyri Sarha <jsarha@ti.com>
   5 */
   6
   7#include <linux/delay.h>
   8#include <linux/fwnode.h>
   9#include <linux/gpio/consumer.h>
  10#include <linux/i2c.h>
  11#include <linux/irq.h>
  12#include <linux/module.h>
  13#include <linux/of_graph.h>
  14#include <linux/platform_device.h>
  15
  16#include <drm/drm_atomic_helper.h>
  17#include <drm/drm_crtc.h>
  18#include <drm/drm_print.h>
  19#include <drm/drm_probe_helper.h>
  20
  21#define HOTPLUG_DEBOUNCE_MS             1100
  22
  23struct tfp410 {
  24        struct drm_bridge       bridge;
  25        struct drm_connector    connector;
  26        unsigned int            connector_type;
  27
  28        u32                     bus_format;
  29        struct i2c_adapter      *ddc;
  30        struct gpio_desc        *hpd;
  31        int                     hpd_irq;
  32        struct delayed_work     hpd_work;
  33        struct gpio_desc        *powerdown;
  34
  35        struct drm_bridge_timings timings;
  36
  37        struct device *dev;
  38};
  39
  40static inline struct tfp410 *
  41drm_bridge_to_tfp410(struct drm_bridge *bridge)
  42{
  43        return container_of(bridge, struct tfp410, bridge);
  44}
  45
  46static inline struct tfp410 *
  47drm_connector_to_tfp410(struct drm_connector *connector)
  48{
  49        return container_of(connector, struct tfp410, connector);
  50}
  51
  52static int tfp410_get_modes(struct drm_connector *connector)
  53{
  54        struct tfp410 *dvi = drm_connector_to_tfp410(connector);
  55        struct edid *edid;
  56        int ret;
  57
  58        if (!dvi->ddc)
  59                goto fallback;
  60
  61        edid = drm_get_edid(connector, dvi->ddc);
  62        if (!edid) {
  63                DRM_INFO("EDID read failed. Fallback to standard modes\n");
  64                goto fallback;
  65        }
  66
  67        drm_connector_update_edid_property(connector, edid);
  68
  69        ret = drm_add_edid_modes(connector, edid);
  70
  71        kfree(edid);
  72
  73        return ret;
  74
  75fallback:
  76        /* No EDID, fallback on the XGA standard modes */
  77        ret = drm_add_modes_noedid(connector, 1920, 1200);
  78
  79        /* And prefer a mode pretty much anything can handle */
  80        drm_set_preferred_mode(connector, 1024, 768);
  81
  82        return ret;
  83}
  84
  85static const struct drm_connector_helper_funcs tfp410_con_helper_funcs = {
  86        .get_modes      = tfp410_get_modes,
  87};
  88
  89static enum drm_connector_status
  90tfp410_connector_detect(struct drm_connector *connector, bool force)
  91{
  92        struct tfp410 *dvi = drm_connector_to_tfp410(connector);
  93
  94        if (dvi->hpd) {
  95                if (gpiod_get_value_cansleep(dvi->hpd))
  96                        return connector_status_connected;
  97                else
  98                        return connector_status_disconnected;
  99        }
 100
 101        if (dvi->ddc) {
 102                if (drm_probe_ddc(dvi->ddc))
 103                        return connector_status_connected;
 104                else
 105                        return connector_status_disconnected;
 106        }
 107
 108        return connector_status_unknown;
 109}
 110
 111static const struct drm_connector_funcs tfp410_con_funcs = {
 112        .detect                 = tfp410_connector_detect,
 113        .fill_modes             = drm_helper_probe_single_connector_modes,
 114        .destroy                = drm_connector_cleanup,
 115        .reset                  = drm_atomic_helper_connector_reset,
 116        .atomic_duplicate_state = drm_atomic_helper_connector_duplicate_state,
 117        .atomic_destroy_state   = drm_atomic_helper_connector_destroy_state,
 118};
 119
 120static int tfp410_attach(struct drm_bridge *bridge)
 121{
 122        struct tfp410 *dvi = drm_bridge_to_tfp410(bridge);
 123        int ret;
 124
 125        if (!bridge->encoder) {
 126                dev_err(dvi->dev, "Missing encoder\n");
 127                return -ENODEV;
 128        }
 129
 130        if (dvi->hpd_irq >= 0)
 131                dvi->connector.polled = DRM_CONNECTOR_POLL_HPD;
 132        else
 133                dvi->connector.polled = DRM_CONNECTOR_POLL_CONNECT | DRM_CONNECTOR_POLL_DISCONNECT;
 134
 135        drm_connector_helper_add(&dvi->connector,
 136                                 &tfp410_con_helper_funcs);
 137        ret = drm_connector_init(bridge->dev, &dvi->connector,
 138                                 &tfp410_con_funcs, dvi->connector_type);
 139        if (ret) {
 140                dev_err(dvi->dev, "drm_connector_init() failed: %d\n", ret);
 141                return ret;
 142        }
 143
 144        drm_display_info_set_bus_formats(&dvi->connector.display_info,
 145                                         &dvi->bus_format, 1);
 146
 147        drm_connector_attach_encoder(&dvi->connector,
 148                                          bridge->encoder);
 149
 150        return 0;
 151}
 152
 153static void tfp410_enable(struct drm_bridge *bridge)
 154{
 155        struct tfp410 *dvi = drm_bridge_to_tfp410(bridge);
 156
 157        gpiod_set_value_cansleep(dvi->powerdown, 0);
 158}
 159
 160static void tfp410_disable(struct drm_bridge *bridge)
 161{
 162        struct tfp410 *dvi = drm_bridge_to_tfp410(bridge);
 163
 164        gpiod_set_value_cansleep(dvi->powerdown, 1);
 165}
 166
 167static const struct drm_bridge_funcs tfp410_bridge_funcs = {
 168        .attach         = tfp410_attach,
 169        .enable         = tfp410_enable,
 170        .disable        = tfp410_disable,
 171};
 172
 173static void tfp410_hpd_work_func(struct work_struct *work)
 174{
 175        struct tfp410 *dvi;
 176
 177        dvi = container_of(work, struct tfp410, hpd_work.work);
 178
 179        if (dvi->bridge.dev)
 180                drm_helper_hpd_irq_event(dvi->bridge.dev);
 181}
 182
 183static irqreturn_t tfp410_hpd_irq_thread(int irq, void *arg)
 184{
 185        struct tfp410 *dvi = arg;
 186
 187        mod_delayed_work(system_wq, &dvi->hpd_work,
 188                        msecs_to_jiffies(HOTPLUG_DEBOUNCE_MS));
 189
 190        return IRQ_HANDLED;
 191}
 192
 193static const struct drm_bridge_timings tfp410_default_timings = {
 194        .input_bus_flags = DRM_BUS_FLAG_PIXDATA_SAMPLE_POSEDGE
 195                         | DRM_BUS_FLAG_DE_HIGH,
 196        .setup_time_ps = 1200,
 197        .hold_time_ps = 1300,
 198};
 199
 200static int tfp410_parse_timings(struct tfp410 *dvi, bool i2c)
 201{
 202        struct drm_bridge_timings *timings = &dvi->timings;
 203        struct device_node *ep;
 204        u32 pclk_sample = 0;
 205        u32 bus_width = 24;
 206        s32 deskew = 0;
 207
 208        /* Start with defaults. */
 209        *timings = tfp410_default_timings;
 210
 211        if (i2c)
 212                /*
 213                 * In I2C mode timings are configured through the I2C interface.
 214                 * As the driver doesn't support I2C configuration yet, we just
 215                 * go with the defaults (BSEL=1, DSEL=1, DKEN=0, EDGE=1).
 216                 */
 217                return 0;
 218
 219        /*
 220         * In non-I2C mode, timings are configured through the BSEL, DSEL, DKEN
 221         * and EDGE pins. They are specified in DT through endpoint properties
 222         * and vendor-specific properties.
 223         */
 224        ep = of_graph_get_endpoint_by_regs(dvi->dev->of_node, 0, 0);
 225        if (!ep)
 226                return -EINVAL;
 227
 228        /* Get the sampling edge from the endpoint. */
 229        of_property_read_u32(ep, "pclk-sample", &pclk_sample);
 230        of_property_read_u32(ep, "bus-width", &bus_width);
 231        of_node_put(ep);
 232
 233        timings->input_bus_flags = DRM_BUS_FLAG_DE_HIGH;
 234
 235        switch (pclk_sample) {
 236        case 0:
 237                timings->input_bus_flags |= DRM_BUS_FLAG_PIXDATA_SAMPLE_NEGEDGE
 238                                         |  DRM_BUS_FLAG_SYNC_SAMPLE_NEGEDGE;
 239                break;
 240        case 1:
 241                timings->input_bus_flags |= DRM_BUS_FLAG_PIXDATA_SAMPLE_POSEDGE
 242                                         |  DRM_BUS_FLAG_SYNC_SAMPLE_POSEDGE;
 243                break;
 244        default:
 245                return -EINVAL;
 246        }
 247
 248        switch (bus_width) {
 249        case 12:
 250                dvi->bus_format = MEDIA_BUS_FMT_RGB888_2X12_LE;
 251                break;
 252        case 24:
 253                dvi->bus_format = MEDIA_BUS_FMT_RGB888_1X24;
 254                break;
 255        default:
 256                return -EINVAL;
 257        }
 258
 259        /* Get the setup and hold time from vendor-specific properties. */
 260        of_property_read_u32(dvi->dev->of_node, "ti,deskew", (u32 *)&deskew);
 261        if (deskew < -4 || deskew > 3)
 262                return -EINVAL;
 263
 264        timings->setup_time_ps = min(0, 1200 - 350 * deskew);
 265        timings->hold_time_ps = min(0, 1300 + 350 * deskew);
 266
 267        return 0;
 268}
 269
 270static int tfp410_get_connector_properties(struct tfp410 *dvi)
 271{
 272        struct device_node *connector_node, *ddc_phandle;
 273        int ret = 0;
 274
 275        /* port@1 is the connector node */
 276        connector_node = of_graph_get_remote_node(dvi->dev->of_node, 1, -1);
 277        if (!connector_node)
 278                return -ENODEV;
 279
 280        if (of_device_is_compatible(connector_node, "hdmi-connector"))
 281                dvi->connector_type = DRM_MODE_CONNECTOR_HDMIA;
 282        else
 283                dvi->connector_type = DRM_MODE_CONNECTOR_DVID;
 284
 285        dvi->hpd = fwnode_get_named_gpiod(&connector_node->fwnode,
 286                                        "hpd-gpios", 0, GPIOD_IN, "hpd");
 287        if (IS_ERR(dvi->hpd)) {
 288                ret = PTR_ERR(dvi->hpd);
 289                dvi->hpd = NULL;
 290                if (ret == -ENOENT)
 291                        ret = 0;
 292                else
 293                        goto fail;
 294        }
 295
 296        ddc_phandle = of_parse_phandle(connector_node, "ddc-i2c-bus", 0);
 297        if (!ddc_phandle)
 298                goto fail;
 299
 300        dvi->ddc = of_get_i2c_adapter_by_node(ddc_phandle);
 301        if (dvi->ddc)
 302                dev_info(dvi->dev, "Connector's ddc i2c bus found\n");
 303        else
 304                ret = -EPROBE_DEFER;
 305
 306        of_node_put(ddc_phandle);
 307
 308fail:
 309        of_node_put(connector_node);
 310        return ret;
 311}
 312
 313static int tfp410_init(struct device *dev, bool i2c)
 314{
 315        struct tfp410 *dvi;
 316        int ret;
 317
 318        if (!dev->of_node) {
 319                dev_err(dev, "device-tree data is missing\n");
 320                return -ENXIO;
 321        }
 322
 323        dvi = devm_kzalloc(dev, sizeof(*dvi), GFP_KERNEL);
 324        if (!dvi)
 325                return -ENOMEM;
 326        dev_set_drvdata(dev, dvi);
 327
 328        dvi->bridge.funcs = &tfp410_bridge_funcs;
 329        dvi->bridge.of_node = dev->of_node;
 330        dvi->bridge.timings = &dvi->timings;
 331        dvi->dev = dev;
 332
 333        ret = tfp410_parse_timings(dvi, i2c);
 334        if (ret)
 335                goto fail;
 336
 337        ret = tfp410_get_connector_properties(dvi);
 338        if (ret)
 339                goto fail;
 340
 341        dvi->powerdown = devm_gpiod_get_optional(dev, "powerdown",
 342                                                 GPIOD_OUT_HIGH);
 343        if (IS_ERR(dvi->powerdown)) {
 344                dev_err(dev, "failed to parse powerdown gpio\n");
 345                return PTR_ERR(dvi->powerdown);
 346        }
 347
 348        if (dvi->hpd)
 349                dvi->hpd_irq = gpiod_to_irq(dvi->hpd);
 350        else
 351                dvi->hpd_irq = -ENXIO;
 352
 353        if (dvi->hpd_irq >= 0) {
 354                INIT_DELAYED_WORK(&dvi->hpd_work, tfp410_hpd_work_func);
 355
 356                ret = devm_request_threaded_irq(dev, dvi->hpd_irq,
 357                        NULL, tfp410_hpd_irq_thread, IRQF_TRIGGER_RISING |
 358                        IRQF_TRIGGER_FALLING | IRQF_ONESHOT,
 359                        "hdmi-hpd", dvi);
 360                if (ret) {
 361                        DRM_ERROR("failed to register hpd interrupt\n");
 362                        goto fail;
 363                }
 364        }
 365
 366        drm_bridge_add(&dvi->bridge);
 367
 368        return 0;
 369fail:
 370        i2c_put_adapter(dvi->ddc);
 371        if (dvi->hpd)
 372                gpiod_put(dvi->hpd);
 373        return ret;
 374}
 375
 376static int tfp410_fini(struct device *dev)
 377{
 378        struct tfp410 *dvi = dev_get_drvdata(dev);
 379
 380        if (dvi->hpd_irq >= 0)
 381                cancel_delayed_work_sync(&dvi->hpd_work);
 382
 383        drm_bridge_remove(&dvi->bridge);
 384
 385        if (dvi->ddc)
 386                i2c_put_adapter(dvi->ddc);
 387        if (dvi->hpd)
 388                gpiod_put(dvi->hpd);
 389
 390        return 0;
 391}
 392
 393static int tfp410_probe(struct platform_device *pdev)
 394{
 395        return tfp410_init(&pdev->dev, false);
 396}
 397
 398static int tfp410_remove(struct platform_device *pdev)
 399{
 400        return tfp410_fini(&pdev->dev);
 401}
 402
 403static const struct of_device_id tfp410_match[] = {
 404        { .compatible = "ti,tfp410" },
 405        {},
 406};
 407MODULE_DEVICE_TABLE(of, tfp410_match);
 408
 409static struct platform_driver tfp410_platform_driver = {
 410        .probe  = tfp410_probe,
 411        .remove = tfp410_remove,
 412        .driver = {
 413                .name           = "tfp410-bridge",
 414                .of_match_table = tfp410_match,
 415        },
 416};
 417
 418#if IS_ENABLED(CONFIG_I2C)
 419/* There is currently no i2c functionality. */
 420static int tfp410_i2c_probe(struct i2c_client *client,
 421                            const struct i2c_device_id *id)
 422{
 423        int reg;
 424
 425        if (!client->dev.of_node ||
 426            of_property_read_u32(client->dev.of_node, "reg", &reg)) {
 427                dev_err(&client->dev,
 428                        "Can't get i2c reg property from device-tree\n");
 429                return -ENXIO;
 430        }
 431
 432        return tfp410_init(&client->dev, true);
 433}
 434
 435static int tfp410_i2c_remove(struct i2c_client *client)
 436{
 437        return tfp410_fini(&client->dev);
 438}
 439
 440static const struct i2c_device_id tfp410_i2c_ids[] = {
 441        { "tfp410", 0 },
 442        { }
 443};
 444MODULE_DEVICE_TABLE(i2c, tfp410_i2c_ids);
 445
 446static struct i2c_driver tfp410_i2c_driver = {
 447        .driver = {
 448                .name   = "tfp410",
 449                .of_match_table = of_match_ptr(tfp410_match),
 450        },
 451        .id_table       = tfp410_i2c_ids,
 452        .probe          = tfp410_i2c_probe,
 453        .remove         = tfp410_i2c_remove,
 454};
 455#endif /* IS_ENABLED(CONFIG_I2C) */
 456
 457static struct {
 458        uint i2c:1;
 459        uint platform:1;
 460}  tfp410_registered_driver;
 461
 462static int __init tfp410_module_init(void)
 463{
 464        int ret;
 465
 466#if IS_ENABLED(CONFIG_I2C)
 467        ret = i2c_add_driver(&tfp410_i2c_driver);
 468        if (ret)
 469                pr_err("%s: registering i2c driver failed: %d",
 470                       __func__, ret);
 471        else
 472                tfp410_registered_driver.i2c = 1;
 473#endif
 474
 475        ret = platform_driver_register(&tfp410_platform_driver);
 476        if (ret)
 477                pr_err("%s: registering platform driver failed: %d",
 478                       __func__, ret);
 479        else
 480                tfp410_registered_driver.platform = 1;
 481
 482        if (tfp410_registered_driver.i2c ||
 483            tfp410_registered_driver.platform)
 484                return 0;
 485
 486        return ret;
 487}
 488module_init(tfp410_module_init);
 489
 490static void __exit tfp410_module_exit(void)
 491{
 492#if IS_ENABLED(CONFIG_I2C)
 493        if (tfp410_registered_driver.i2c)
 494                i2c_del_driver(&tfp410_i2c_driver);
 495#endif
 496        if (tfp410_registered_driver.platform)
 497                platform_driver_unregister(&tfp410_platform_driver);
 498}
 499module_exit(tfp410_module_exit);
 500
 501MODULE_AUTHOR("Jyri Sarha <jsarha@ti.com>");
 502MODULE_DESCRIPTION("TI TFP410 DVI bridge driver");
 503MODULE_LICENSE("GPL");
 504