linux/drivers/video/omap2/displays-new/encoder-tfp410.c
<<
>>
Prefs
   1/*
   2 * TFP410 DPI-to-DVI encoder 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.h>
  13#include <linux/module.h>
  14#include <linux/platform_device.h>
  15#include <linux/slab.h>
  16
  17#include <video/omapdss.h>
  18#include <video/omap-panel-data.h>
  19
  20struct panel_drv_data {
  21        struct omap_dss_device dssdev;
  22        struct omap_dss_device *in;
  23
  24        int pd_gpio;
  25        int data_lines;
  26
  27        struct omap_video_timings timings;
  28};
  29
  30#define to_panel_data(x) container_of(x, struct panel_drv_data, dssdev)
  31
  32static int tfp410_connect(struct omap_dss_device *dssdev,
  33                struct omap_dss_device *dst)
  34{
  35        struct panel_drv_data *ddata = to_panel_data(dssdev);
  36        struct omap_dss_device *in = ddata->in;
  37        int r;
  38
  39        if (omapdss_device_is_connected(dssdev))
  40                return -EBUSY;
  41
  42        r = in->ops.dpi->connect(in, dssdev);
  43        if (r)
  44                return r;
  45
  46        dst->src = dssdev;
  47        dssdev->dst = dst;
  48
  49        return 0;
  50}
  51
  52static void tfp410_disconnect(struct omap_dss_device *dssdev,
  53                struct omap_dss_device *dst)
  54{
  55        struct panel_drv_data *ddata = to_panel_data(dssdev);
  56        struct omap_dss_device *in = ddata->in;
  57
  58        WARN_ON(!omapdss_device_is_connected(dssdev));
  59        if (!omapdss_device_is_connected(dssdev))
  60                return;
  61
  62        WARN_ON(dst != dssdev->dst);
  63        if (dst != dssdev->dst)
  64                return;
  65
  66        dst->src = NULL;
  67        dssdev->dst = NULL;
  68
  69        in->ops.dpi->disconnect(in, &ddata->dssdev);
  70}
  71
  72static int tfp410_enable(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        int r;
  77
  78        if (!omapdss_device_is_connected(dssdev))
  79                return -ENODEV;
  80
  81        if (omapdss_device_is_enabled(dssdev))
  82                return 0;
  83
  84        in->ops.dpi->set_timings(in, &ddata->timings);
  85        in->ops.dpi->set_data_lines(in, ddata->data_lines);
  86
  87        r = in->ops.dpi->enable(in);
  88        if (r)
  89                return r;
  90
  91        if (gpio_is_valid(ddata->pd_gpio))
  92                gpio_set_value_cansleep(ddata->pd_gpio, 1);
  93
  94        dssdev->state = OMAP_DSS_DISPLAY_ACTIVE;
  95
  96        return 0;
  97}
  98
  99static void tfp410_disable(struct omap_dss_device *dssdev)
 100{
 101        struct panel_drv_data *ddata = to_panel_data(dssdev);
 102        struct omap_dss_device *in = ddata->in;
 103
 104        if (!omapdss_device_is_enabled(dssdev))
 105                return;
 106
 107        if (gpio_is_valid(ddata->pd_gpio))
 108                gpio_set_value_cansleep(ddata->pd_gpio, 0);
 109
 110        in->ops.dpi->disable(in);
 111
 112        dssdev->state = OMAP_DSS_DISPLAY_DISABLED;
 113}
 114
 115static void tfp410_set_timings(struct omap_dss_device *dssdev,
 116                struct omap_video_timings *timings)
 117{
 118        struct panel_drv_data *ddata = to_panel_data(dssdev);
 119        struct omap_dss_device *in = ddata->in;
 120
 121        ddata->timings = *timings;
 122        dssdev->panel.timings = *timings;
 123
 124        in->ops.dpi->set_timings(in, timings);
 125}
 126
 127static void tfp410_get_timings(struct omap_dss_device *dssdev,
 128                struct omap_video_timings *timings)
 129{
 130        struct panel_drv_data *ddata = to_panel_data(dssdev);
 131
 132        *timings = ddata->timings;
 133}
 134
 135static int tfp410_check_timings(struct omap_dss_device *dssdev,
 136                struct omap_video_timings *timings)
 137{
 138        struct panel_drv_data *ddata = to_panel_data(dssdev);
 139        struct omap_dss_device *in = ddata->in;
 140
 141        return in->ops.dpi->check_timings(in, timings);
 142}
 143
 144static const struct omapdss_dvi_ops tfp410_dvi_ops = {
 145        .connect        = tfp410_connect,
 146        .disconnect     = tfp410_disconnect,
 147
 148        .enable         = tfp410_enable,
 149        .disable        = tfp410_disable,
 150
 151        .check_timings  = tfp410_check_timings,
 152        .set_timings    = tfp410_set_timings,
 153        .get_timings    = tfp410_get_timings,
 154};
 155
 156static int tfp410_probe_pdata(struct platform_device *pdev)
 157{
 158        struct panel_drv_data *ddata = platform_get_drvdata(pdev);
 159        struct encoder_tfp410_platform_data *pdata;
 160        struct omap_dss_device *dssdev, *in;
 161
 162        pdata = dev_get_platdata(&pdev->dev);
 163
 164        ddata->pd_gpio = pdata->power_down_gpio;
 165
 166        ddata->data_lines = pdata->data_lines;
 167
 168        in = omap_dss_find_output(pdata->source);
 169        if (in == NULL) {
 170                dev_err(&pdev->dev, "Failed to find video source\n");
 171                return -ENODEV;
 172        }
 173
 174        ddata->in = in;
 175
 176        dssdev = &ddata->dssdev;
 177        dssdev->name = pdata->name;
 178
 179        return 0;
 180}
 181
 182static int tfp410_probe(struct platform_device *pdev)
 183{
 184        struct panel_drv_data *ddata;
 185        struct omap_dss_device *dssdev;
 186        int r;
 187
 188        ddata = devm_kzalloc(&pdev->dev, sizeof(*ddata), GFP_KERNEL);
 189        if (!ddata)
 190                return -ENOMEM;
 191
 192        platform_set_drvdata(pdev, ddata);
 193
 194        if (dev_get_platdata(&pdev->dev)) {
 195                r = tfp410_probe_pdata(pdev);
 196                if (r)
 197                        return r;
 198        } else {
 199                return -ENODEV;
 200        }
 201
 202        if (gpio_is_valid(ddata->pd_gpio)) {
 203                r = devm_gpio_request_one(&pdev->dev, ddata->pd_gpio,
 204                                GPIOF_OUT_INIT_LOW, "tfp410 PD");
 205                if (r) {
 206                        dev_err(&pdev->dev, "Failed to request PD GPIO %d\n",
 207                                        ddata->pd_gpio);
 208                        goto err_gpio;
 209                }
 210        }
 211
 212        dssdev = &ddata->dssdev;
 213        dssdev->ops.dvi = &tfp410_dvi_ops;
 214        dssdev->dev = &pdev->dev;
 215        dssdev->type = OMAP_DISPLAY_TYPE_DPI;
 216        dssdev->output_type = OMAP_DISPLAY_TYPE_DVI;
 217        dssdev->owner = THIS_MODULE;
 218        dssdev->phy.dpi.data_lines = ddata->data_lines;
 219
 220        r = omapdss_register_output(dssdev);
 221        if (r) {
 222                dev_err(&pdev->dev, "Failed to register output\n");
 223                goto err_reg;
 224        }
 225
 226        return 0;
 227err_reg:
 228err_gpio:
 229        omap_dss_put_device(ddata->in);
 230        return r;
 231}
 232
 233static int __exit tfp410_remove(struct platform_device *pdev)
 234{
 235        struct panel_drv_data *ddata = platform_get_drvdata(pdev);
 236        struct omap_dss_device *dssdev = &ddata->dssdev;
 237        struct omap_dss_device *in = ddata->in;
 238
 239        omapdss_unregister_output(&ddata->dssdev);
 240
 241        WARN_ON(omapdss_device_is_enabled(dssdev));
 242        if (omapdss_device_is_enabled(dssdev))
 243                tfp410_disable(dssdev);
 244
 245        WARN_ON(omapdss_device_is_connected(dssdev));
 246        if (omapdss_device_is_connected(dssdev))
 247                tfp410_disconnect(dssdev, dssdev->dst);
 248
 249        omap_dss_put_device(in);
 250
 251        return 0;
 252}
 253
 254static struct platform_driver tfp410_driver = {
 255        .probe  = tfp410_probe,
 256        .remove = __exit_p(tfp410_remove),
 257        .driver = {
 258                .name   = "tfp410",
 259                .owner  = THIS_MODULE,
 260        },
 261};
 262
 263module_platform_driver(tfp410_driver);
 264
 265MODULE_AUTHOR("Tomi Valkeinen <tomi.valkeinen@ti.com>");
 266MODULE_DESCRIPTION("TFP410 DPI to DVI encoder driver");
 267MODULE_LICENSE("GPL");
 268