Commit 7e86efa2 authored by Hans Verkuil's avatar Hans Verkuil Committed by Mauro Carvalho Chehab
Browse files

media: cec-gpio: add notifier support



Add support for cec-notifier to the cec-gpio driver.

This makes it possible to associate the CEC gpio pin with an HDMI
connector. This feature was always documented in the cec-gpio bindings:

Documentation/devicetree/bindings/media/cec-gpio.txt

But support for the hdmi-phandle property was never actually implemented in
this driver.

This patch adds support for this property.

It also fixes a few incorrect error returns in the probe() function, which
skipped the call to cec_delete_adapter().

Tested on a Raspberry Pi 3B with a modified vc4 driver.

Signed-off-by: default avatarHans Verkuil <hverkuil-cisco@xs4all.nl>
Signed-off-by: default avatarMauro Carvalho Chehab <mchehab+samsung@kernel.org>
parent 98f29073
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -588,6 +588,7 @@ config CEC_GPIO
	depends on PREEMPT || COMPILE_TEST
	select CEC_CORE
	select CEC_PIN
	select CEC_NOTIFIER
	select GPIOLIB
	help
	  This is a generic GPIO-based CEC driver.
+32 −9
Original line number Diff line number Diff line
@@ -8,10 +8,12 @@
#include <linux/delay.h>
#include <linux/platform_device.h>
#include <linux/gpio/consumer.h>
#include <media/cec-notifier.h>
#include <media/cec-pin.h>

struct cec_gpio {
	struct cec_adapter	*adap;
	struct cec_notifier	*notifier;
	struct device		*dev;

	struct gpio_desc	*cec_gpio;
@@ -173,9 +175,17 @@ static const struct cec_pin_ops cec_gpio_pin_ops = {
static int cec_gpio_probe(struct platform_device *pdev)
{
	struct device *dev = &pdev->dev;
	struct device *hdmi_dev;
	struct cec_gpio *cec;
	u32 caps = CEC_CAP_DEFAULTS | CEC_CAP_MONITOR_ALL | CEC_CAP_MONITOR_PIN;
	int ret;

	hdmi_dev = cec_notifier_parse_hdmi_phandle(dev);
	if (PTR_ERR(hdmi_dev) == -EPROBE_DEFER)
		return PTR_ERR(hdmi_dev);
	if (IS_ERR(hdmi_dev))
		caps |= CEC_CAP_PHYS_ADDR;

	cec = devm_kzalloc(dev, sizeof(*cec), GFP_KERNEL);
	if (!cec)
		return -ENOMEM;
@@ -196,8 +206,7 @@ static int cec_gpio_probe(struct platform_device *pdev)
		return PTR_ERR(cec->v5_gpio);

	cec->adap = cec_pin_allocate_adapter(&cec_gpio_pin_ops,
		cec, pdev->name, CEC_CAP_DEFAULTS | CEC_CAP_PHYS_ADDR |
				 CEC_CAP_MONITOR_ALL | CEC_CAP_MONITOR_PIN);
					     cec, pdev->name, caps);
	if (IS_ERR(cec->adap))
		return PTR_ERR(cec->adap);

@@ -205,7 +214,7 @@ static int cec_gpio_probe(struct platform_device *pdev)
			       IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING,
			       cec->adap->name, cec);
	if (ret)
		return ret;
		goto del_adap;

	cec_gpio_disable_irq(cec->adap);

@@ -218,7 +227,7 @@ static int cec_gpio_probe(struct platform_device *pdev)
			IRQF_TRIGGER_FALLING | IRQF_TRIGGER_RISING,
			"hpd-gpio", cec);
		if (ret)
			return ret;
			goto del_adap;
	}

	if (cec->v5_gpio) {
@@ -230,23 +239,37 @@ static int cec_gpio_probe(struct platform_device *pdev)
			IRQF_TRIGGER_FALLING | IRQF_TRIGGER_RISING,
			"v5-gpio", cec);
		if (ret)
			return ret;
			goto del_adap;
	}

	ret = cec_register_adapter(cec->adap, &pdev->dev);
	if (ret) {
		cec_delete_adapter(cec->adap);
		return ret;
	if (!IS_ERR(hdmi_dev)) {
		cec->notifier = cec_notifier_cec_adap_register(hdmi_dev, NULL,
							       cec->adap);
		if (!cec->notifier) {
			ret = -ENOMEM;
			goto del_adap;
		}
	}

	ret = cec_register_adapter(cec->adap, &pdev->dev);
	if (ret)
		goto unreg_notifier;

	platform_set_drvdata(pdev, cec);
	return 0;

unreg_notifier:
	cec_notifier_cec_adap_unregister(cec->notifier);
del_adap:
	cec_delete_adapter(cec->adap);
	return ret;
}

static int cec_gpio_remove(struct platform_device *pdev)
{
	struct cec_gpio *cec = platform_get_drvdata(pdev);

	cec_notifier_cec_adap_unregister(cec->notifier);
	cec_unregister_adapter(cec->adap);
	return 0;
}