Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0
0002 /*
0003  * TPD12S015 HDMI ESD protection & level shifter chip driver
0004  *
0005  * Copyright (C) 2019 Texas Instruments Incorporated
0006  *
0007  * Based on the omapdrm-specific encoder-opa362 driver
0008  *
0009  * Copyright (C) 2013 Texas Instruments Incorporated
0010  * Author: Tomi Valkeinen <tomi.valkeinen@ti.com>
0011  */
0012 
0013 #include <linux/delay.h>
0014 #include <linux/gpio/consumer.h>
0015 #include <linux/interrupt.h>
0016 #include <linux/module.h>
0017 #include <linux/mutex.h>
0018 #include <linux/of.h>
0019 #include <linux/of_graph.h>
0020 #include <linux/platform_device.h>
0021 
0022 #include <drm/drm_bridge.h>
0023 
0024 struct tpd12s015_device {
0025     struct drm_bridge bridge;
0026 
0027     struct gpio_desc *ct_cp_hpd_gpio;
0028     struct gpio_desc *ls_oe_gpio;
0029     struct gpio_desc *hpd_gpio;
0030     int hpd_irq;
0031 
0032     struct drm_bridge *next_bridge;
0033 };
0034 
0035 static inline struct tpd12s015_device *to_tpd12s015(struct drm_bridge *bridge)
0036 {
0037     return container_of(bridge, struct tpd12s015_device, bridge);
0038 }
0039 
0040 static int tpd12s015_attach(struct drm_bridge *bridge,
0041                 enum drm_bridge_attach_flags flags)
0042 {
0043     struct tpd12s015_device *tpd = to_tpd12s015(bridge);
0044     int ret;
0045 
0046     if (!(flags & DRM_BRIDGE_ATTACH_NO_CONNECTOR))
0047         return -EINVAL;
0048 
0049     ret = drm_bridge_attach(bridge->encoder, tpd->next_bridge,
0050                 bridge, flags);
0051     if (ret < 0)
0052         return ret;
0053 
0054     gpiod_set_value_cansleep(tpd->ls_oe_gpio, 1);
0055 
0056     /* DC-DC converter needs at max 300us to get to 90% of 5V. */
0057     usleep_range(300, 1000);
0058 
0059     return 0;
0060 }
0061 
0062 static void tpd12s015_detach(struct drm_bridge *bridge)
0063 {
0064     struct tpd12s015_device *tpd = to_tpd12s015(bridge);
0065 
0066     gpiod_set_value_cansleep(tpd->ls_oe_gpio, 0);
0067 }
0068 
0069 static enum drm_connector_status tpd12s015_detect(struct drm_bridge *bridge)
0070 {
0071     struct tpd12s015_device *tpd = to_tpd12s015(bridge);
0072 
0073     if (gpiod_get_value_cansleep(tpd->hpd_gpio))
0074         return connector_status_connected;
0075     else
0076         return connector_status_disconnected;
0077 }
0078 
0079 static void tpd12s015_hpd_enable(struct drm_bridge *bridge)
0080 {
0081     struct tpd12s015_device *tpd = to_tpd12s015(bridge);
0082 
0083     gpiod_set_value_cansleep(tpd->ct_cp_hpd_gpio, 1);
0084 }
0085 
0086 static void tpd12s015_hpd_disable(struct drm_bridge *bridge)
0087 {
0088     struct tpd12s015_device *tpd = to_tpd12s015(bridge);
0089 
0090     gpiod_set_value_cansleep(tpd->ct_cp_hpd_gpio, 0);
0091 }
0092 
0093 static const struct drm_bridge_funcs tpd12s015_bridge_funcs = {
0094     .attach         = tpd12s015_attach,
0095     .detach         = tpd12s015_detach,
0096     .detect         = tpd12s015_detect,
0097     .hpd_enable     = tpd12s015_hpd_enable,
0098     .hpd_disable        = tpd12s015_hpd_disable,
0099 };
0100 
0101 static irqreturn_t tpd12s015_hpd_isr(int irq, void *data)
0102 {
0103     struct tpd12s015_device *tpd = data;
0104     struct drm_bridge *bridge = &tpd->bridge;
0105 
0106     drm_bridge_hpd_notify(bridge, tpd12s015_detect(bridge));
0107 
0108     return IRQ_HANDLED;
0109 }
0110 
0111 static int tpd12s015_probe(struct platform_device *pdev)
0112 {
0113     struct tpd12s015_device *tpd;
0114     struct device_node *node;
0115     struct gpio_desc *gpio;
0116     int ret;
0117 
0118     tpd = devm_kzalloc(&pdev->dev, sizeof(*tpd), GFP_KERNEL);
0119     if (!tpd)
0120         return -ENOMEM;
0121 
0122     platform_set_drvdata(pdev, tpd);
0123 
0124     tpd->bridge.funcs = &tpd12s015_bridge_funcs;
0125     tpd->bridge.of_node = pdev->dev.of_node;
0126     tpd->bridge.type = DRM_MODE_CONNECTOR_HDMIA;
0127     tpd->bridge.ops = DRM_BRIDGE_OP_DETECT;
0128 
0129     /* Get the next bridge, connected to port@1. */
0130     node = of_graph_get_remote_node(pdev->dev.of_node, 1, -1);
0131     if (!node)
0132         return -ENODEV;
0133 
0134     tpd->next_bridge = of_drm_find_bridge(node);
0135     of_node_put(node);
0136 
0137     if (!tpd->next_bridge)
0138         return -EPROBE_DEFER;
0139 
0140     /* Get the control and HPD GPIOs. */
0141     gpio = devm_gpiod_get_index_optional(&pdev->dev, NULL, 0,
0142                          GPIOD_OUT_LOW);
0143     if (IS_ERR(gpio))
0144         return PTR_ERR(gpio);
0145 
0146     tpd->ct_cp_hpd_gpio = gpio;
0147 
0148     gpio = devm_gpiod_get_index_optional(&pdev->dev, NULL, 1,
0149                          GPIOD_OUT_LOW);
0150     if (IS_ERR(gpio))
0151         return PTR_ERR(gpio);
0152 
0153     tpd->ls_oe_gpio = gpio;
0154 
0155     gpio = devm_gpiod_get_index(&pdev->dev, NULL, 2, GPIOD_IN);
0156     if (IS_ERR(gpio))
0157         return PTR_ERR(gpio);
0158 
0159     tpd->hpd_gpio = gpio;
0160 
0161     /* Register the IRQ if the HPD GPIO is IRQ-capable. */
0162     tpd->hpd_irq = gpiod_to_irq(tpd->hpd_gpio);
0163     if (tpd->hpd_irq >= 0) {
0164         ret = devm_request_threaded_irq(&pdev->dev, tpd->hpd_irq, NULL,
0165                         tpd12s015_hpd_isr,
0166                         IRQF_TRIGGER_RISING |
0167                         IRQF_TRIGGER_FALLING |
0168                         IRQF_ONESHOT,
0169                         "tpd12s015 hpd", tpd);
0170         if (ret)
0171             return ret;
0172 
0173         tpd->bridge.ops |= DRM_BRIDGE_OP_HPD;
0174     }
0175 
0176     /* Register the DRM bridge. */
0177     drm_bridge_add(&tpd->bridge);
0178 
0179     return 0;
0180 }
0181 
0182 static int __exit tpd12s015_remove(struct platform_device *pdev)
0183 {
0184     struct tpd12s015_device *tpd = platform_get_drvdata(pdev);
0185 
0186     drm_bridge_remove(&tpd->bridge);
0187 
0188     return 0;
0189 }
0190 
0191 static const struct of_device_id tpd12s015_of_match[] = {
0192     { .compatible = "ti,tpd12s015", },
0193     {},
0194 };
0195 
0196 MODULE_DEVICE_TABLE(of, tpd12s015_of_match);
0197 
0198 static struct platform_driver tpd12s015_driver = {
0199     .probe  = tpd12s015_probe,
0200     .remove = __exit_p(tpd12s015_remove),
0201     .driver = {
0202         .name   = "tpd12s015",
0203         .of_match_table = tpd12s015_of_match,
0204     },
0205 };
0206 
0207 module_platform_driver(tpd12s015_driver);
0208 
0209 MODULE_AUTHOR("Tomi Valkeinen <tomi.valkeinen@ti.com>");
0210 MODULE_DESCRIPTION("TPD12S015 HDMI level shifter and ESD protection driver");
0211 MODULE_LICENSE("GPL");