linux/drivers/gpu/drm/tilcdc/tilcdc_tfp410.c
<<
>>
Prefs
   1/*
   2 * Copyright (C) 2012 Texas Instruments
   3 * Author: Rob Clark <robdclark@gmail.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 * This program is distributed in the hope that it will be useful, but WITHOUT
  10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  11 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
  12 * more details.
  13 *
  14 * You should have received a copy of the GNU General Public License along with
  15 * this program.  If not, see <http://www.gnu.org/licenses/>.
  16 */
  17
  18#include <linux/i2c.h>
  19#include <linux/gpio.h>
  20#include <linux/of_gpio.h>
  21#include <linux/pinctrl/pinmux.h>
  22#include <linux/pinctrl/consumer.h>
  23#include <drm/drm_atomic_helper.h>
  24
  25#include "tilcdc_drv.h"
  26#include "tilcdc_tfp410.h"
  27
  28struct tfp410_module {
  29        struct tilcdc_module base;
  30        struct i2c_adapter *i2c;
  31        int gpio;
  32};
  33#define to_tfp410_module(x) container_of(x, struct tfp410_module, base)
  34
  35
  36static const struct tilcdc_panel_info dvi_info = {
  37                .ac_bias                = 255,
  38                .ac_bias_intrpt         = 0,
  39                .dma_burst_sz           = 16,
  40                .bpp                    = 16,
  41                .fdd                    = 0x80,
  42                .tft_alt_mode           = 0,
  43                .sync_edge              = 0,
  44                .sync_ctrl              = 1,
  45                .raster_order           = 0,
  46};
  47
  48/*
  49 * Encoder:
  50 */
  51
  52struct tfp410_encoder {
  53        struct drm_encoder base;
  54        struct tfp410_module *mod;
  55        int dpms;
  56};
  57#define to_tfp410_encoder(x) container_of(x, struct tfp410_encoder, base)
  58
  59static void tfp410_encoder_dpms(struct drm_encoder *encoder, int mode)
  60{
  61        struct tfp410_encoder *tfp410_encoder = to_tfp410_encoder(encoder);
  62
  63        if (tfp410_encoder->dpms == mode)
  64                return;
  65
  66        if (mode == DRM_MODE_DPMS_ON) {
  67                DBG("Power on");
  68                gpio_direction_output(tfp410_encoder->mod->gpio, 1);
  69        } else {
  70                DBG("Power off");
  71                gpio_direction_output(tfp410_encoder->mod->gpio, 0);
  72        }
  73
  74        tfp410_encoder->dpms = mode;
  75}
  76
  77static void tfp410_encoder_prepare(struct drm_encoder *encoder)
  78{
  79        tfp410_encoder_dpms(encoder, DRM_MODE_DPMS_OFF);
  80}
  81
  82static void tfp410_encoder_commit(struct drm_encoder *encoder)
  83{
  84        tfp410_encoder_dpms(encoder, DRM_MODE_DPMS_ON);
  85}
  86
  87static void tfp410_encoder_mode_set(struct drm_encoder *encoder,
  88                struct drm_display_mode *mode,
  89                struct drm_display_mode *adjusted_mode)
  90{
  91        /* nothing needed */
  92}
  93
  94static const struct drm_encoder_funcs tfp410_encoder_funcs = {
  95                .destroy        = drm_encoder_cleanup,
  96};
  97
  98static const struct drm_encoder_helper_funcs tfp410_encoder_helper_funcs = {
  99                .dpms           = tfp410_encoder_dpms,
 100                .prepare        = tfp410_encoder_prepare,
 101                .commit         = tfp410_encoder_commit,
 102                .mode_set       = tfp410_encoder_mode_set,
 103};
 104
 105static struct drm_encoder *tfp410_encoder_create(struct drm_device *dev,
 106                struct tfp410_module *mod)
 107{
 108        struct tfp410_encoder *tfp410_encoder;
 109        struct drm_encoder *encoder;
 110        int ret;
 111
 112        tfp410_encoder = devm_kzalloc(dev->dev, sizeof(*tfp410_encoder),
 113                                      GFP_KERNEL);
 114        if (!tfp410_encoder) {
 115                dev_err(dev->dev, "allocation failed\n");
 116                return NULL;
 117        }
 118
 119        tfp410_encoder->dpms = DRM_MODE_DPMS_OFF;
 120        tfp410_encoder->mod = mod;
 121
 122        encoder = &tfp410_encoder->base;
 123        encoder->possible_crtcs = 1;
 124
 125        ret = drm_encoder_init(dev, encoder, &tfp410_encoder_funcs,
 126                        DRM_MODE_ENCODER_TMDS, NULL);
 127        if (ret < 0)
 128                goto fail;
 129
 130        drm_encoder_helper_add(encoder, &tfp410_encoder_helper_funcs);
 131
 132        return encoder;
 133
 134fail:
 135        drm_encoder_cleanup(encoder);
 136        return NULL;
 137}
 138
 139/*
 140 * Connector:
 141 */
 142
 143struct tfp410_connector {
 144        struct drm_connector base;
 145
 146        struct drm_encoder *encoder;  /* our connected encoder */
 147        struct tfp410_module *mod;
 148};
 149#define to_tfp410_connector(x) container_of(x, struct tfp410_connector, base)
 150
 151
 152static void tfp410_connector_destroy(struct drm_connector *connector)
 153{
 154        drm_connector_unregister(connector);
 155        drm_connector_cleanup(connector);
 156}
 157
 158static enum drm_connector_status tfp410_connector_detect(
 159                struct drm_connector *connector,
 160                bool force)
 161{
 162        struct tfp410_connector *tfp410_connector = to_tfp410_connector(connector);
 163
 164        if (drm_probe_ddc(tfp410_connector->mod->i2c))
 165                return connector_status_connected;
 166
 167        return connector_status_unknown;
 168}
 169
 170static int tfp410_connector_get_modes(struct drm_connector *connector)
 171{
 172        struct tfp410_connector *tfp410_connector = to_tfp410_connector(connector);
 173        struct edid *edid;
 174        int ret = 0;
 175
 176        edid = drm_get_edid(connector, tfp410_connector->mod->i2c);
 177
 178        drm_mode_connector_update_edid_property(connector, edid);
 179
 180        if (edid) {
 181                ret = drm_add_edid_modes(connector, edid);
 182                kfree(edid);
 183        }
 184
 185        return ret;
 186}
 187
 188static int tfp410_connector_mode_valid(struct drm_connector *connector,
 189                  struct drm_display_mode *mode)
 190{
 191        struct tilcdc_drm_private *priv = connector->dev->dev_private;
 192        /* our only constraints are what the crtc can generate: */
 193        return tilcdc_crtc_mode_valid(priv->crtc, mode);
 194}
 195
 196static struct drm_encoder *tfp410_connector_best_encoder(
 197                struct drm_connector *connector)
 198{
 199        struct tfp410_connector *tfp410_connector = to_tfp410_connector(connector);
 200        return tfp410_connector->encoder;
 201}
 202
 203static const struct drm_connector_funcs tfp410_connector_funcs = {
 204        .destroy            = tfp410_connector_destroy,
 205        .dpms               = drm_atomic_helper_connector_dpms,
 206        .detect             = tfp410_connector_detect,
 207        .fill_modes         = drm_helper_probe_single_connector_modes,
 208        .reset              = drm_atomic_helper_connector_reset,
 209        .atomic_duplicate_state = drm_atomic_helper_connector_duplicate_state,
 210        .atomic_destroy_state = drm_atomic_helper_connector_destroy_state,
 211};
 212
 213static const struct drm_connector_helper_funcs tfp410_connector_helper_funcs = {
 214        .get_modes          = tfp410_connector_get_modes,
 215        .mode_valid         = tfp410_connector_mode_valid,
 216        .best_encoder       = tfp410_connector_best_encoder,
 217};
 218
 219static struct drm_connector *tfp410_connector_create(struct drm_device *dev,
 220                struct tfp410_module *mod, struct drm_encoder *encoder)
 221{
 222        struct tfp410_connector *tfp410_connector;
 223        struct drm_connector *connector;
 224        int ret;
 225
 226        tfp410_connector = devm_kzalloc(dev->dev, sizeof(*tfp410_connector),
 227                                        GFP_KERNEL);
 228        if (!tfp410_connector) {
 229                dev_err(dev->dev, "allocation failed\n");
 230                return NULL;
 231        }
 232
 233        tfp410_connector->encoder = encoder;
 234        tfp410_connector->mod = mod;
 235
 236        connector = &tfp410_connector->base;
 237
 238        drm_connector_init(dev, connector, &tfp410_connector_funcs,
 239                        DRM_MODE_CONNECTOR_DVID);
 240        drm_connector_helper_add(connector, &tfp410_connector_helper_funcs);
 241
 242        connector->polled = DRM_CONNECTOR_POLL_CONNECT |
 243                        DRM_CONNECTOR_POLL_DISCONNECT;
 244
 245        connector->interlace_allowed = 0;
 246        connector->doublescan_allowed = 0;
 247
 248        ret = drm_mode_connector_attach_encoder(connector, encoder);
 249        if (ret)
 250                goto fail;
 251
 252        return connector;
 253
 254fail:
 255        tfp410_connector_destroy(connector);
 256        return NULL;
 257}
 258
 259/*
 260 * Module:
 261 */
 262
 263static int tfp410_modeset_init(struct tilcdc_module *mod, struct drm_device *dev)
 264{
 265        struct tfp410_module *tfp410_mod = to_tfp410_module(mod);
 266        struct tilcdc_drm_private *priv = dev->dev_private;
 267        struct drm_encoder *encoder;
 268        struct drm_connector *connector;
 269
 270        encoder = tfp410_encoder_create(dev, tfp410_mod);
 271        if (!encoder)
 272                return -ENOMEM;
 273
 274        connector = tfp410_connector_create(dev, tfp410_mod, encoder);
 275        if (!connector)
 276                return -ENOMEM;
 277
 278        priv->encoders[priv->num_encoders++] = encoder;
 279        priv->connectors[priv->num_connectors++] = connector;
 280
 281        tilcdc_crtc_set_panel_info(priv->crtc, &dvi_info);
 282        return 0;
 283}
 284
 285static const struct tilcdc_module_ops tfp410_module_ops = {
 286                .modeset_init = tfp410_modeset_init,
 287};
 288
 289/*
 290 * Device:
 291 */
 292
 293static struct of_device_id tfp410_of_match[];
 294
 295static int tfp410_probe(struct platform_device *pdev)
 296{
 297        struct device_node *node = pdev->dev.of_node;
 298        struct device_node *i2c_node;
 299        struct tfp410_module *tfp410_mod;
 300        struct tilcdc_module *mod;
 301        struct pinctrl *pinctrl;
 302        uint32_t i2c_phandle;
 303        int ret = -EINVAL;
 304
 305        /* bail out early if no DT data: */
 306        if (!node) {
 307                dev_err(&pdev->dev, "device-tree data is missing\n");
 308                return -ENXIO;
 309        }
 310
 311        tfp410_mod = devm_kzalloc(&pdev->dev, sizeof(*tfp410_mod), GFP_KERNEL);
 312        if (!tfp410_mod)
 313                return -ENOMEM;
 314
 315        mod = &tfp410_mod->base;
 316        pdev->dev.platform_data = mod;
 317
 318        tilcdc_module_init(mod, "tfp410", &tfp410_module_ops);
 319
 320        pinctrl = devm_pinctrl_get_select_default(&pdev->dev);
 321        if (IS_ERR(pinctrl))
 322                dev_warn(&pdev->dev, "pins are not configured\n");
 323
 324        if (of_property_read_u32(node, "i2c", &i2c_phandle)) {
 325                dev_err(&pdev->dev, "could not get i2c bus phandle\n");
 326                goto fail;
 327        }
 328
 329        i2c_node = of_find_node_by_phandle(i2c_phandle);
 330        if (!i2c_node) {
 331                dev_err(&pdev->dev, "could not get i2c bus node\n");
 332                goto fail;
 333        }
 334
 335        tfp410_mod->i2c = of_find_i2c_adapter_by_node(i2c_node);
 336        if (!tfp410_mod->i2c) {
 337                dev_err(&pdev->dev, "could not get i2c\n");
 338                of_node_put(i2c_node);
 339                goto fail;
 340        }
 341
 342        of_node_put(i2c_node);
 343
 344        tfp410_mod->gpio = of_get_named_gpio_flags(node, "powerdn-gpio",
 345                        0, NULL);
 346        if (tfp410_mod->gpio < 0) {
 347                dev_warn(&pdev->dev, "No power down GPIO\n");
 348        } else {
 349                ret = gpio_request(tfp410_mod->gpio, "DVI_PDn");
 350                if (ret) {
 351                        dev_err(&pdev->dev, "could not get DVI_PDn gpio\n");
 352                        goto fail_adapter;
 353                }
 354        }
 355
 356        return 0;
 357
 358fail_adapter:
 359        i2c_put_adapter(tfp410_mod->i2c);
 360
 361fail:
 362        tilcdc_module_cleanup(mod);
 363        return ret;
 364}
 365
 366static int tfp410_remove(struct platform_device *pdev)
 367{
 368        struct tilcdc_module *mod = dev_get_platdata(&pdev->dev);
 369        struct tfp410_module *tfp410_mod = to_tfp410_module(mod);
 370
 371        i2c_put_adapter(tfp410_mod->i2c);
 372        gpio_free(tfp410_mod->gpio);
 373
 374        tilcdc_module_cleanup(mod);
 375
 376        return 0;
 377}
 378
 379static struct of_device_id tfp410_of_match[] = {
 380                { .compatible = "ti,tilcdc,tfp410", },
 381                { },
 382};
 383
 384struct platform_driver tfp410_driver = {
 385        .probe = tfp410_probe,
 386        .remove = tfp410_remove,
 387        .driver = {
 388                .owner = THIS_MODULE,
 389                .name = "tfp410",
 390                .of_match_table = tfp410_of_match,
 391        },
 392};
 393
 394int __init tilcdc_tfp410_init(void)
 395{
 396        return platform_driver_register(&tfp410_driver);
 397}
 398
 399void __exit tilcdc_tfp410_fini(void)
 400{
 401        platform_driver_unregister(&tfp410_driver);
 402}
 403