diff options
| author | 2019-09-19 08:15:53 -0300 | |
|---|---|---|
| committer | 2019-10-01 17:21:14 -0300 | |
| commit | 7e86efa2ff03db92067b2f6f4fa3f1f8b8da7c76 (patch) | |
| tree | d09c07d18c292ae7d86ccd5c1eba3a89e3f6505b /drivers/media/platform/cec-gpio/cec-gpio.c | |
| parent | media: cec: document CEC_ADAP_G_CONNECTOR_INFO and capability (diff) | |
| download | linux-dev-7e86efa2ff03db92067b2f6f4fa3f1f8b8da7c76.tar.xz linux-dev-7e86efa2ff03db92067b2f6f4fa3f1f8b8da7c76.zip  | |
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: Hans Verkuil <hverkuil-cisco@xs4all.nl>
Signed-off-by: Mauro Carvalho Chehab <mchehab+samsung@kernel.org>
Diffstat (limited to 'drivers/media/platform/cec-gpio/cec-gpio.c')
| -rw-r--r-- | drivers/media/platform/cec-gpio/cec-gpio.c | 41 | 
1 files changed, 32 insertions, 9 deletions
diff --git a/drivers/media/platform/cec-gpio/cec-gpio.c b/drivers/media/platform/cec-gpio/cec-gpio.c index 5b17d3a31896..7be91e712c4a 100644 --- a/drivers/media/platform/cec-gpio/cec-gpio.c +++ b/drivers/media/platform/cec-gpio/cec-gpio.c @@ -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;  }  | 
