root/drivers/gpu/drm/omapdrm/displays/encoder-tpd12s015.c

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

DEFINITIONS

This source file includes following definitions.
  1. tpd_connect
  2. tpd_disconnect
  3. tpd_detect
  4. tpd_register_hpd_cb
  5. tpd_unregister_hpd_cb
  6. tpd_hpd_isr
  7. tpd_probe
  8. 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 Incorporated - http://www.ti.com/
   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/slab.h>
  13 #include <linux/platform_device.h>
  14 #include <linux/gpio/consumer.h>
  15 #include <linux/mutex.h>
  16 
  17 #include "../dss/omapdss.h"
  18 
  19 struct panel_drv_data {
  20         struct omap_dss_device dssdev;
  21         void (*hpd_cb)(void *cb_data, enum drm_connector_status status);
  22         void *hpd_cb_data;
  23         struct mutex hpd_lock;
  24 
  25         struct gpio_desc *ct_cp_hpd_gpio;
  26         struct gpio_desc *ls_oe_gpio;
  27         struct gpio_desc *hpd_gpio;
  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 *src,
  33                        struct omap_dss_device *dst)
  34 {
  35         struct panel_drv_data *ddata = to_panel_data(dst);
  36         int r;
  37 
  38         r = omapdss_device_connect(dst->dss, dst, dst->next);
  39         if (r)
  40                 return r;
  41 
  42         gpiod_set_value_cansleep(ddata->ct_cp_hpd_gpio, 1);
  43         gpiod_set_value_cansleep(ddata->ls_oe_gpio, 1);
  44 
  45         /* DC-DC converter needs at max 300us to get to 90% of 5V */
  46         udelay(300);
  47 
  48         return 0;
  49 }
  50 
  51 static void tpd_disconnect(struct omap_dss_device *src,
  52                            struct omap_dss_device *dst)
  53 {
  54         struct panel_drv_data *ddata = to_panel_data(dst);
  55 
  56         gpiod_set_value_cansleep(ddata->ct_cp_hpd_gpio, 0);
  57         gpiod_set_value_cansleep(ddata->ls_oe_gpio, 0);
  58 
  59         omapdss_device_disconnect(dst, dst->next);
  60 }
  61 
  62 static bool tpd_detect(struct omap_dss_device *dssdev)
  63 {
  64         struct panel_drv_data *ddata = to_panel_data(dssdev);
  65 
  66         return gpiod_get_value_cansleep(ddata->hpd_gpio);
  67 }
  68 
  69 static void tpd_register_hpd_cb(struct omap_dss_device *dssdev,
  70                                 void (*cb)(void *cb_data,
  71                                           enum drm_connector_status status),
  72                                 void *cb_data)
  73 {
  74         struct panel_drv_data *ddata = to_panel_data(dssdev);
  75 
  76         mutex_lock(&ddata->hpd_lock);
  77         ddata->hpd_cb = cb;
  78         ddata->hpd_cb_data = cb_data;
  79         mutex_unlock(&ddata->hpd_lock);
  80 }
  81 
  82 static void tpd_unregister_hpd_cb(struct omap_dss_device *dssdev)
  83 {
  84         struct panel_drv_data *ddata = to_panel_data(dssdev);
  85 
  86         mutex_lock(&ddata->hpd_lock);
  87         ddata->hpd_cb = NULL;
  88         ddata->hpd_cb_data = NULL;
  89         mutex_unlock(&ddata->hpd_lock);
  90 }
  91 
  92 static const struct omap_dss_device_ops tpd_ops = {
  93         .connect                = tpd_connect,
  94         .disconnect             = tpd_disconnect,
  95         .detect                 = tpd_detect,
  96         .register_hpd_cb        = tpd_register_hpd_cb,
  97         .unregister_hpd_cb      = tpd_unregister_hpd_cb,
  98 };
  99 
 100 static irqreturn_t tpd_hpd_isr(int irq, void *data)
 101 {
 102         struct panel_drv_data *ddata = data;
 103 
 104         mutex_lock(&ddata->hpd_lock);
 105         if (ddata->hpd_cb) {
 106                 enum drm_connector_status status;
 107 
 108                 if (tpd_detect(&ddata->dssdev))
 109                         status = connector_status_connected;
 110                 else
 111                         status = connector_status_disconnected;
 112 
 113                 ddata->hpd_cb(ddata->hpd_cb_data, status);
 114         }
 115         mutex_unlock(&ddata->hpd_lock);
 116 
 117         return IRQ_HANDLED;
 118 }
 119 
 120 static int tpd_probe(struct platform_device *pdev)
 121 {
 122         struct omap_dss_device *dssdev;
 123         struct panel_drv_data *ddata;
 124         int r;
 125         struct gpio_desc *gpio;
 126 
 127         ddata = devm_kzalloc(&pdev->dev, sizeof(*ddata), GFP_KERNEL);
 128         if (!ddata)
 129                 return -ENOMEM;
 130 
 131         platform_set_drvdata(pdev, ddata);
 132 
 133         gpio = devm_gpiod_get_index_optional(&pdev->dev, NULL, 0,
 134                  GPIOD_OUT_LOW);
 135         if (IS_ERR(gpio))
 136                 return PTR_ERR(gpio);
 137 
 138         ddata->ct_cp_hpd_gpio = gpio;
 139 
 140         gpio = devm_gpiod_get_index_optional(&pdev->dev, NULL, 1,
 141                  GPIOD_OUT_LOW);
 142         if (IS_ERR(gpio))
 143                 return PTR_ERR(gpio);
 144 
 145         ddata->ls_oe_gpio = gpio;
 146 
 147         gpio = devm_gpiod_get_index(&pdev->dev, NULL, 2,
 148                 GPIOD_IN);
 149         if (IS_ERR(gpio))
 150                 return PTR_ERR(gpio);
 151 
 152         ddata->hpd_gpio = gpio;
 153 
 154         mutex_init(&ddata->hpd_lock);
 155 
 156         r = devm_request_threaded_irq(&pdev->dev, gpiod_to_irq(ddata->hpd_gpio),
 157                 NULL, tpd_hpd_isr,
 158                 IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING | IRQF_ONESHOT,
 159                 "tpd12s015 hpd", ddata);
 160         if (r)
 161                 return r;
 162 
 163         dssdev = &ddata->dssdev;
 164         dssdev->ops = &tpd_ops;
 165         dssdev->dev = &pdev->dev;
 166         dssdev->type = OMAP_DISPLAY_TYPE_HDMI;
 167         dssdev->owner = THIS_MODULE;
 168         dssdev->of_ports = BIT(1) | BIT(0);
 169         dssdev->ops_flags = OMAP_DSS_DEVICE_OP_DETECT
 170                           | OMAP_DSS_DEVICE_OP_HPD;
 171 
 172         dssdev->next = omapdss_of_find_connected_device(pdev->dev.of_node, 1);
 173         if (IS_ERR(dssdev->next)) {
 174                 if (PTR_ERR(dssdev->next) != -EPROBE_DEFER)
 175                         dev_err(&pdev->dev, "failed to find video sink\n");
 176                 return PTR_ERR(dssdev->next);
 177         }
 178 
 179         omapdss_device_register(dssdev);
 180 
 181         return 0;
 182 }
 183 
 184 static int __exit tpd_remove(struct platform_device *pdev)
 185 {
 186         struct panel_drv_data *ddata = platform_get_drvdata(pdev);
 187         struct omap_dss_device *dssdev = &ddata->dssdev;
 188 
 189         if (dssdev->next)
 190                 omapdss_device_put(dssdev->next);
 191         omapdss_device_unregister(&ddata->dssdev);
 192 
 193         return 0;
 194 }
 195 
 196 static const struct of_device_id tpd_of_match[] = {
 197         { .compatible = "omapdss,ti,tpd12s015", },
 198         {},
 199 };
 200 
 201 MODULE_DEVICE_TABLE(of, tpd_of_match);
 202 
 203 static struct platform_driver tpd_driver = {
 204         .probe  = tpd_probe,
 205         .remove = __exit_p(tpd_remove),
 206         .driver = {
 207                 .name   = "tpd12s015",
 208                 .of_match_table = tpd_of_match,
 209                 .suppress_bind_attrs = true,
 210         },
 211 };
 212 
 213 module_platform_driver(tpd_driver);
 214 
 215 MODULE_AUTHOR("Tomi Valkeinen <tomi.valkeinen@ti.com>");
 216 MODULE_DESCRIPTION("TPD12S015 driver");
 217 MODULE_LICENSE("GPL");

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