From: <christopher.spinrath@rwth-aachen.de> To: architt@codeaurora.org, airlied@linux.ie, shawnguo@kernel.org, kernel@pengutronix.de Cc: mark.rutland@arm.com, devicetree@vger.kernel.org, christopher.spinrath@rwth-aachen.de, linux@armlinux.org.uk, dri-devel@lists.freedesktop.org, robh+dt@kernel.org, grinberg@compulab.co.il, fabio.estevam@nxp.com, linux-arm-kernel@lists.infradead.org Subject: [PATCH 1/2] drm/bridge: ti-tfp410: support hpd via gpio Date: Mon, 6 Mar 2017 22:40:43 +0100 [thread overview] Message-ID: <2e47786ab3d04078ae70d0c4064f7c4d@rwthex-s1-b.rwth-ad.de> (raw) From: Christopher Spinrath <christopher.spinrath@rwth-aachen.de> On some boards the hpd pin of a hdmi connector is wired up to a gpio pin. Since in the DRM world the tfp410 driver is responsible for handling the connector, add support for hpd gpios in this very driver. Signed-off-by: Christopher Spinrath <christopher.spinrath@rwth-aachen.de> --- drivers/gpu/drm/bridge/ti-tfp410.c | 72 ++++++++++++++++++++++++++++++++++++-- 1 file changed, 70 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/bridge/ti-tfp410.c b/drivers/gpu/drm/bridge/ti-tfp410.c index b054ea3..77c3390 100644 --- a/drivers/gpu/drm/bridge/ti-tfp410.c +++ b/drivers/gpu/drm/bridge/ti-tfp410.c @@ -8,6 +8,10 @@ * */ +#include <linux/delay.h> +#include <linux/fwnode.h> +#include <linux/gpio/consumer.h> +#include <linux/irq.h> #include <linux/module.h> #include <linux/of_graph.h> #include <linux/platform_device.h> @@ -18,11 +22,15 @@ #include <drm/drm_crtc.h> #include <drm/drm_crtc_helper.h> +#define HOTPLUG_DEBOUNCE_MS 1100 + struct tfp410 { struct drm_bridge bridge; struct drm_connector connector; struct i2c_adapter *ddc; + struct gpio_desc *hpd; + struct delayed_work hpd_work; struct device *dev; }; @@ -76,6 +84,13 @@ tfp410_connector_detect(struct drm_connector *connector, bool force) { struct tfp410 *dvi = drm_connector_to_tfp410(connector); + if (dvi->hpd) { + if (gpiod_get_value_cansleep(dvi->hpd)) + return connector_status_connected; + else + return connector_status_disconnected; + } + if (dvi->ddc) { if (drm_probe_ddc(dvi->ddc)) return connector_status_connected; @@ -106,6 +121,9 @@ static int tfp410_attach(struct drm_bridge *bridge) return -ENODEV; } + if (dvi->hpd) + dvi->connector.polled = DRM_CONNECTOR_POLL_HPD; + drm_connector_helper_add(&dvi->connector, &tfp410_con_helper_funcs); ret = drm_connector_init(bridge->dev, &dvi->connector, @@ -125,7 +143,27 @@ static const struct drm_bridge_funcs tfp410_bridge_funcs = { .attach = tfp410_attach, }; -static int tfp410_get_connector_ddc(struct tfp410 *dvi) +static void tfp410_hpd_work_func(struct work_struct *work) +{ + struct tfp410 *dvi; + + dvi = container_of(work, struct tfp410, hpd_work.work); + + if (dvi->bridge.dev) + drm_helper_hpd_irq_event(dvi->bridge.dev); +} + +static irqreturn_t tfp410_hpd_irq_thread(int irq, void *arg) +{ + struct tfp410 *dvi = arg; + + mod_delayed_work(system_wq, &dvi->hpd_work, + msecs_to_jiffies(HOTPLUG_DEBOUNCE_MS)); + + return IRQ_HANDLED; +} + +static int tfp410_get_connector_properties(struct tfp410 *dvi) { struct device_node *ep = NULL, *connector_node = NULL; struct device_node *ddc_phandle = NULL; @@ -140,6 +178,17 @@ static int tfp410_get_connector_ddc(struct tfp410 *dvi) if (!connector_node) goto fail; + dvi->hpd = fwnode_get_named_gpiod(&connector_node->fwnode, + "hpd-gpios", 0, GPIOD_IN, "hpd"); + if (IS_ERR(dvi->hpd)) { + ret = PTR_ERR(dvi->hpd); + dvi->hpd = NULL; + if (ret == -ENOENT) + ret = 0; + else + goto fail; + } + ddc_phandle = of_parse_phandle(connector_node, "ddc-i2c-bus", 0); if (!ddc_phandle) goto fail; @@ -176,10 +225,23 @@ static int tfp410_init(struct device *dev) dvi->bridge.of_node = dev->of_node; dvi->dev = dev; - ret = tfp410_get_connector_ddc(dvi); + ret = tfp410_get_connector_properties(dvi); if (ret) goto fail; + if (dvi->hpd) { + INIT_DELAYED_WORK(&dvi->hpd_work, tfp410_hpd_work_func); + + ret = devm_request_threaded_irq(dev, gpiod_to_irq(dvi->hpd), + NULL, tfp410_hpd_irq_thread, IRQF_TRIGGER_RISING | + IRQF_TRIGGER_FALLING | IRQF_ONESHOT, + "hdmi-hpd", dvi); + if (ret) { + DRM_ERROR("failed to register hpd interrupt\n"); + goto fail; + } + } + ret = drm_bridge_add(&dvi->bridge); if (ret) { dev_err(dev, "drm_bridge_add() failed: %d\n", ret); @@ -189,6 +251,8 @@ static int tfp410_init(struct device *dev) return 0; fail: i2c_put_adapter(dvi->ddc); + if (dvi->hpd) + gpiod_put(dvi->hpd); return ret; } @@ -196,10 +260,14 @@ static int tfp410_fini(struct device *dev) { struct tfp410 *dvi = dev_get_drvdata(dev); + cancel_delayed_work_sync(&dvi->hpd_work); + drm_bridge_remove(&dvi->bridge); if (dvi->ddc) i2c_put_adapter(dvi->ddc); + if (dvi->hpd) + gpiod_put(dvi->hpd); return 0; } -- 2.10.2
WARNING: multiple messages have this Message-ID (diff)
From: christopher.spinrath@rwth-aachen.de (christopher.spinrath at rwth-aachen.de) To: linux-arm-kernel@lists.infradead.org Subject: [PATCH 1/2] drm/bridge: ti-tfp410: support hpd via gpio Date: Mon, 6 Mar 2017 22:40:43 +0100 [thread overview] Message-ID: <2e47786ab3d04078ae70d0c4064f7c4d@rwthex-s1-b.rwth-ad.de> (raw) From: Christopher Spinrath <christopher.spinrath@rwth-aachen.de> On some boards the hpd pin of a hdmi connector is wired up to a gpio pin. Since in the DRM world the tfp410 driver is responsible for handling the connector, add support for hpd gpios in this very driver. Signed-off-by: Christopher Spinrath <christopher.spinrath@rwth-aachen.de> --- drivers/gpu/drm/bridge/ti-tfp410.c | 72 ++++++++++++++++++++++++++++++++++++-- 1 file changed, 70 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/bridge/ti-tfp410.c b/drivers/gpu/drm/bridge/ti-tfp410.c index b054ea3..77c3390 100644 --- a/drivers/gpu/drm/bridge/ti-tfp410.c +++ b/drivers/gpu/drm/bridge/ti-tfp410.c @@ -8,6 +8,10 @@ * */ +#include <linux/delay.h> +#include <linux/fwnode.h> +#include <linux/gpio/consumer.h> +#include <linux/irq.h> #include <linux/module.h> #include <linux/of_graph.h> #include <linux/platform_device.h> @@ -18,11 +22,15 @@ #include <drm/drm_crtc.h> #include <drm/drm_crtc_helper.h> +#define HOTPLUG_DEBOUNCE_MS 1100 + struct tfp410 { struct drm_bridge bridge; struct drm_connector connector; struct i2c_adapter *ddc; + struct gpio_desc *hpd; + struct delayed_work hpd_work; struct device *dev; }; @@ -76,6 +84,13 @@ tfp410_connector_detect(struct drm_connector *connector, bool force) { struct tfp410 *dvi = drm_connector_to_tfp410(connector); + if (dvi->hpd) { + if (gpiod_get_value_cansleep(dvi->hpd)) + return connector_status_connected; + else + return connector_status_disconnected; + } + if (dvi->ddc) { if (drm_probe_ddc(dvi->ddc)) return connector_status_connected; @@ -106,6 +121,9 @@ static int tfp410_attach(struct drm_bridge *bridge) return -ENODEV; } + if (dvi->hpd) + dvi->connector.polled = DRM_CONNECTOR_POLL_HPD; + drm_connector_helper_add(&dvi->connector, &tfp410_con_helper_funcs); ret = drm_connector_init(bridge->dev, &dvi->connector, @@ -125,7 +143,27 @@ static const struct drm_bridge_funcs tfp410_bridge_funcs = { .attach = tfp410_attach, }; -static int tfp410_get_connector_ddc(struct tfp410 *dvi) +static void tfp410_hpd_work_func(struct work_struct *work) +{ + struct tfp410 *dvi; + + dvi = container_of(work, struct tfp410, hpd_work.work); + + if (dvi->bridge.dev) + drm_helper_hpd_irq_event(dvi->bridge.dev); +} + +static irqreturn_t tfp410_hpd_irq_thread(int irq, void *arg) +{ + struct tfp410 *dvi = arg; + + mod_delayed_work(system_wq, &dvi->hpd_work, + msecs_to_jiffies(HOTPLUG_DEBOUNCE_MS)); + + return IRQ_HANDLED; +} + +static int tfp410_get_connector_properties(struct tfp410 *dvi) { struct device_node *ep = NULL, *connector_node = NULL; struct device_node *ddc_phandle = NULL; @@ -140,6 +178,17 @@ static int tfp410_get_connector_ddc(struct tfp410 *dvi) if (!connector_node) goto fail; + dvi->hpd = fwnode_get_named_gpiod(&connector_node->fwnode, + "hpd-gpios", 0, GPIOD_IN, "hpd"); + if (IS_ERR(dvi->hpd)) { + ret = PTR_ERR(dvi->hpd); + dvi->hpd = NULL; + if (ret == -ENOENT) + ret = 0; + else + goto fail; + } + ddc_phandle = of_parse_phandle(connector_node, "ddc-i2c-bus", 0); if (!ddc_phandle) goto fail; @@ -176,10 +225,23 @@ static int tfp410_init(struct device *dev) dvi->bridge.of_node = dev->of_node; dvi->dev = dev; - ret = tfp410_get_connector_ddc(dvi); + ret = tfp410_get_connector_properties(dvi); if (ret) goto fail; + if (dvi->hpd) { + INIT_DELAYED_WORK(&dvi->hpd_work, tfp410_hpd_work_func); + + ret = devm_request_threaded_irq(dev, gpiod_to_irq(dvi->hpd), + NULL, tfp410_hpd_irq_thread, IRQF_TRIGGER_RISING | + IRQF_TRIGGER_FALLING | IRQF_ONESHOT, + "hdmi-hpd", dvi); + if (ret) { + DRM_ERROR("failed to register hpd interrupt\n"); + goto fail; + } + } + ret = drm_bridge_add(&dvi->bridge); if (ret) { dev_err(dev, "drm_bridge_add() failed: %d\n", ret); @@ -189,6 +251,8 @@ static int tfp410_init(struct device *dev) return 0; fail: i2c_put_adapter(dvi->ddc); + if (dvi->hpd) + gpiod_put(dvi->hpd); return ret; } @@ -196,10 +260,14 @@ static int tfp410_fini(struct device *dev) { struct tfp410 *dvi = dev_get_drvdata(dev); + cancel_delayed_work_sync(&dvi->hpd_work); + drm_bridge_remove(&dvi->bridge); if (dvi->ddc) i2c_put_adapter(dvi->ddc); + if (dvi->hpd) + gpiod_put(dvi->hpd); return 0; } -- 2.10.2
next reply other threads:[~2017-03-06 21:40 UTC|newest] Thread overview: 14+ messages / expand[flat|nested] mbox.gz Atom feed top 2017-03-06 21:40 christopher.spinrath [this message] 2017-03-06 21:40 ` [PATCH 1/2] drm/bridge: ti-tfp410: support hpd via gpio christopher.spinrath at rwth-aachen.de 2017-03-06 21:46 ` Fabio Estevam 2017-03-06 21:46 ` Fabio Estevam [not found] ` <093b4e9c0ae6413499e5bf8ec309fa41@rwthex-s1-b.rwth-ad.de> [not found] ` <093b4e9c0ae6413499e5bf8ec309fa41-gtPewvpZjL8umhiu9RXYRl5UTUQ924AY@public.gmane.org> 2017-03-06 21:51 ` Christopher Spinrath 2017-03-06 21:51 ` Christopher Spinrath 2017-03-27 5:58 ` Archit Taneja 2017-03-27 5:58 ` Archit Taneja 2017-03-28 13:32 ` Jyri Sarha 2017-03-28 13:32 ` Jyri Sarha 2017-03-30 9:49 ` Archit Taneja 2017-03-30 9:49 ` Archit Taneja [not found] ` <e63e628794b044c2a615091697622d50@rwthex-w1-b.rwth-ad.de> [not found] ` <e63e628794b044c2a615091697622d50-cBaz+nnMw18umhiu9RXYRl5UTUQ924AY@public.gmane.org> 2017-03-30 21:51 ` Christopher Spinrath 2017-03-30 21:51 ` Christopher Spinrath
Reply instructions: You may reply publicly to this message via plain-text email using any one of the following methods: * Save the following mbox file, import it into your mail client, and reply-to-all from there: mbox Avoid top-posting and favor interleaved quoting: https://en.wikipedia.org/wiki/Posting_style#Interleaved_style * Reply using the --to, --cc, and --in-reply-to switches of git-send-email(1): git send-email \ --in-reply-to=2e47786ab3d04078ae70d0c4064f7c4d@rwthex-s1-b.rwth-ad.de \ --to=christopher.spinrath@rwth-aachen.de \ --cc=airlied@linux.ie \ --cc=architt@codeaurora.org \ --cc=devicetree@vger.kernel.org \ --cc=dri-devel@lists.freedesktop.org \ --cc=fabio.estevam@nxp.com \ --cc=grinberg@compulab.co.il \ --cc=kernel@pengutronix.de \ --cc=linux-arm-kernel@lists.infradead.org \ --cc=linux@armlinux.org.uk \ --cc=mark.rutland@arm.com \ --cc=robh+dt@kernel.org \ --cc=shawnguo@kernel.org \ /path/to/YOUR_REPLY https://kernel.org/pub/software/scm/git/docs/git-send-email.html * If your mail client supports setting the In-Reply-To header via mailto: links, try the mailto: linkBe sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes, see mirroring instructions on how to clone and mirror all data and code used by this external index.