root/drivers/video/fbdev/omap2/omapfb/displays/encoder-tpd12s015.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. tpd_connect
  2. tpd_disconnect
  3. tpd_enable
  4. tpd_disable
  5. tpd_set_timings
  6. tpd_get_timings
  7. tpd_check_timings
  8. tpd_read_edid
  9. tpd_detect
  10. tpd_set_infoframe
  11. tpd_set_hdmi_mode
  12. tpd_probe_of
  13. tpd_probe
  14. tpd_remove

   1 // SPDX-License-Identifier: GPL-2.0-only
   2 /*
   3  * TPD12S015 HDMI ESD protection & level shifter chip driver
   4  *
   5  * Copyright (C) 2013 Texas Instruments
   6  * Author: Tomi Valkeinen <tomi.valkeinen@ti.com>
   7  */
   8 
   9 #include <linux/completion.h>
  10 #include <linux/delay.h>
  11 #include <linux/module.h>
  12 #include <linux/mod_devicetable.h>
  13 #include <linux/slab.h>
  14 #include <linux/platform_device.h>
  15 #include <linux/gpio/consumer.h>
  16 
  17 #include <video/omapfb_dss.h>
  18 
  19 struct panel_drv_data {
  20         struct omap_dss_device dssdev;
  21         struct omap_dss_device *in;
  22 
  23         struct gpio_desc *ct_cp_hpd_gpio;
  24         struct gpio_desc *ls_oe_gpio;
  25         struct gpio_desc *hpd_gpio;
  26 
  27         struct omap_video_timings timings;
  28 };
  29 
  30 #define to_panel_data(x) container_of(x, struct panel_drv_data, dssdev)
  31 
  32 static int tpd_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         r = in->ops.hdmi->connect(in, dssdev);
  40         if (r)
  41                 return r;
  42 
  43         dst->src = dssdev;
  44         dssdev->dst = dst;
  45 
  46         if (ddata->ct_cp_hpd_gpio) {
  47                 gpiod_set_value_cansleep(ddata->ct_cp_hpd_gpio, 1);
  48                 /* DC-DC converter needs at max 300us to get to 90% of 5V */
  49                 udelay(300);
  50         }
  51 
  52         return 0;
  53 }
  54 
  55 static void tpd_disconnect(struct omap_dss_device *dssdev,
  56                 struct omap_dss_device *dst)
  57 {
  58         struct panel_drv_data *ddata = to_panel_data(dssdev);
  59         struct omap_dss_device *in = ddata->in;
  60 
  61         WARN_ON(dst != dssdev->dst);
  62 
  63         if (dst != dssdev->dst)
  64                 return;
  65 
  66         gpiod_set_value_cansleep(ddata->ct_cp_hpd_gpio, 0);
  67 
  68         dst->src = NULL;
  69         dssdev->dst = NULL;
  70 
  71         in->ops.hdmi->disconnect(in, &ddata->dssdev);
  72 }
  73 
  74 static int tpd_enable(struct omap_dss_device *dssdev)
  75 {
  76         struct panel_drv_data *ddata = to_panel_data(dssdev);
  77         struct omap_dss_device *in = ddata->in;
  78         int r;
  79 
  80         if (dssdev->state == OMAP_DSS_DISPLAY_ACTIVE)
  81                 return 0;
  82 
  83         in->ops.hdmi->set_timings(in, &ddata->timings);
  84 
  85         r = in->ops.hdmi->enable(in);
  86         if (r)
  87                 return r;
  88 
  89         dssdev->state = OMAP_DSS_DISPLAY_ACTIVE;
  90 
  91         return r;
  92 }
  93 
  94 static void tpd_disable(struct omap_dss_device *dssdev)
  95 {
  96         struct panel_drv_data *ddata = to_panel_data(dssdev);
  97         struct omap_dss_device *in = ddata->in;
  98 
  99         if (dssdev->state != OMAP_DSS_DISPLAY_ACTIVE)
 100                 return;
 101 
 102         in->ops.hdmi->disable(in);
 103 
 104         dssdev->state = OMAP_DSS_DISPLAY_DISABLED;
 105 }
 106 
 107 static void tpd_set_timings(struct omap_dss_device *dssdev,
 108                 struct omap_video_timings *timings)
 109 {
 110         struct panel_drv_data *ddata = to_panel_data(dssdev);
 111         struct omap_dss_device *in = ddata->in;
 112 
 113         ddata->timings = *timings;
 114         dssdev->panel.timings = *timings;
 115 
 116         in->ops.hdmi->set_timings(in, timings);
 117 }
 118 
 119 static void tpd_get_timings(struct omap_dss_device *dssdev,
 120                 struct omap_video_timings *timings)
 121 {
 122         struct panel_drv_data *ddata = to_panel_data(dssdev);
 123 
 124         *timings = ddata->timings;
 125 }
 126 
 127 static int tpd_check_timings(struct omap_dss_device *dssdev,
 128                 struct omap_video_timings *timings)
 129 {
 130         struct panel_drv_data *ddata = to_panel_data(dssdev);
 131         struct omap_dss_device *in = ddata->in;
 132         int r;
 133 
 134         r = in->ops.hdmi->check_timings(in, timings);
 135 
 136         return r;
 137 }
 138 
 139 static int tpd_read_edid(struct omap_dss_device *dssdev,
 140                 u8 *edid, int len)
 141 {
 142         struct panel_drv_data *ddata = to_panel_data(dssdev);
 143         struct omap_dss_device *in = ddata->in;
 144         int r;
 145 
 146         if (!gpiod_get_value_cansleep(ddata->hpd_gpio))
 147                 return -ENODEV;
 148 
 149         gpiod_set_value_cansleep(ddata->ls_oe_gpio, 1);
 150 
 151         r = in->ops.hdmi->read_edid(in, edid, len);
 152 
 153         gpiod_set_value_cansleep(ddata->ls_oe_gpio, 0);
 154 
 155         return r;
 156 }
 157 
 158 static bool tpd_detect(struct omap_dss_device *dssdev)
 159 {
 160         struct panel_drv_data *ddata = to_panel_data(dssdev);
 161 
 162         return gpiod_get_value_cansleep(ddata->hpd_gpio);
 163 }
 164 
 165 static int tpd_set_infoframe(struct omap_dss_device *dssdev,
 166                 const struct hdmi_avi_infoframe *avi)
 167 {
 168         struct panel_drv_data *ddata = to_panel_data(dssdev);
 169         struct omap_dss_device *in = ddata->in;
 170 
 171         return in->ops.hdmi->set_infoframe(in, avi);
 172 }
 173 
 174 static int tpd_set_hdmi_mode(struct omap_dss_device *dssdev,
 175                 bool hdmi_mode)
 176 {
 177         struct panel_drv_data *ddata = to_panel_data(dssdev);
 178         struct omap_dss_device *in = ddata->in;
 179 
 180         return in->ops.hdmi->set_hdmi_mode(in, hdmi_mode);
 181 }
 182 
 183 static const struct omapdss_hdmi_ops tpd_hdmi_ops = {
 184         .connect                = tpd_connect,
 185         .disconnect             = tpd_disconnect,
 186 
 187         .enable                 = tpd_enable,
 188         .disable                = tpd_disable,
 189 
 190         .check_timings          = tpd_check_timings,
 191         .set_timings            = tpd_set_timings,
 192         .get_timings            = tpd_get_timings,
 193 
 194         .read_edid              = tpd_read_edid,
 195         .detect                 = tpd_detect,
 196         .set_infoframe          = tpd_set_infoframe,
 197         .set_hdmi_mode          = tpd_set_hdmi_mode,
 198 };
 199 
 200 static int tpd_probe_of(struct platform_device *pdev)
 201 {
 202         struct panel_drv_data *ddata = platform_get_drvdata(pdev);
 203         struct device_node *node = pdev->dev.of_node;
 204         struct omap_dss_device *in;
 205 
 206         in = omapdss_of_find_source_for_first_ep(node);
 207         if (IS_ERR(in)) {
 208                 dev_err(&pdev->dev, "failed to find video source\n");
 209                 return PTR_ERR(in);
 210         }
 211 
 212         ddata->in = in;
 213 
 214         return 0;
 215 }
 216 
 217 static int tpd_probe(struct platform_device *pdev)
 218 {
 219         struct omap_dss_device *dssdev;
 220         struct panel_drv_data *ddata;
 221         int r;
 222         struct gpio_desc *gpio;
 223 
 224         ddata = devm_kzalloc(&pdev->dev, sizeof(*ddata), GFP_KERNEL);
 225         if (!ddata)
 226                 return -ENOMEM;
 227 
 228         platform_set_drvdata(pdev, ddata);
 229 
 230         if (pdev->dev.of_node) {
 231                 r = tpd_probe_of(pdev);
 232                 if (r)
 233                         return r;
 234         } else {
 235                 return -ENODEV;
 236         }
 237 
 238         gpio = devm_gpiod_get_index_optional(&pdev->dev, NULL, 0,
 239                 GPIOD_OUT_LOW);
 240         if (IS_ERR(gpio)) {
 241                 r = PTR_ERR(gpio);
 242                 goto err_gpio;
 243         }
 244 
 245         ddata->ct_cp_hpd_gpio = gpio;
 246 
 247         gpio = devm_gpiod_get_index_optional(&pdev->dev, NULL, 1,
 248                 GPIOD_OUT_LOW);
 249         if (IS_ERR(gpio)) {
 250                 r = PTR_ERR(gpio);
 251                 goto err_gpio;
 252         }
 253 
 254         ddata->ls_oe_gpio = gpio;
 255 
 256         gpio = devm_gpiod_get_index(&pdev->dev, NULL, 2,
 257                 GPIOD_IN);
 258         if (IS_ERR(gpio)) {
 259                 r = PTR_ERR(gpio);
 260                 goto err_gpio;
 261         }
 262 
 263         ddata->hpd_gpio = gpio;
 264 
 265         dssdev = &ddata->dssdev;
 266         dssdev->ops.hdmi = &tpd_hdmi_ops;
 267         dssdev->dev = &pdev->dev;
 268         dssdev->type = OMAP_DISPLAY_TYPE_HDMI;
 269         dssdev->output_type = OMAP_DISPLAY_TYPE_HDMI;
 270         dssdev->owner = THIS_MODULE;
 271         dssdev->port_num = 1;
 272 
 273         r = omapdss_register_output(dssdev);
 274         if (r) {
 275                 dev_err(&pdev->dev, "Failed to register output\n");
 276                 goto err_reg;
 277         }
 278 
 279         return 0;
 280 err_reg:
 281 err_gpio:
 282         omap_dss_put_device(ddata->in);
 283         return r;
 284 }
 285 
 286 static int __exit tpd_remove(struct platform_device *pdev)
 287 {
 288         struct panel_drv_data *ddata = platform_get_drvdata(pdev);
 289         struct omap_dss_device *dssdev = &ddata->dssdev;
 290         struct omap_dss_device *in = ddata->in;
 291 
 292         omapdss_unregister_output(&ddata->dssdev);
 293 
 294         WARN_ON(omapdss_device_is_enabled(dssdev));
 295         if (omapdss_device_is_enabled(dssdev))
 296                 tpd_disable(dssdev);
 297 
 298         WARN_ON(omapdss_device_is_connected(dssdev));
 299         if (omapdss_device_is_connected(dssdev))
 300                 tpd_disconnect(dssdev, dssdev->dst);
 301 
 302         omap_dss_put_device(in);
 303 
 304         return 0;
 305 }
 306 
 307 static const struct of_device_id tpd_of_match[] = {
 308         { .compatible = "omapdss,ti,tpd12s015", },
 309         {},
 310 };
 311 
 312 MODULE_DEVICE_TABLE(of, tpd_of_match);
 313 
 314 static struct platform_driver tpd_driver = {
 315         .probe  = tpd_probe,
 316         .remove = __exit_p(tpd_remove),
 317         .driver = {
 318                 .name   = "tpd12s015",
 319                 .of_match_table = tpd_of_match,
 320                 .suppress_bind_attrs = true,
 321         },
 322 };
 323 
 324 module_platform_driver(tpd_driver);
 325 
 326 MODULE_AUTHOR("Tomi Valkeinen <tomi.valkeinen@ti.com>");
 327 MODULE_DESCRIPTION("TPD12S015 driver");
 328 MODULE_LICENSE("GPL");

/* [<][>][^][v][top][bottom][index][help] */