diff options
author | Hans Verkuil <hverkuil-cisco@xs4all.nl> | 2019-09-19 08:15:53 -0300 |
---|---|---|
committer | Mauro Carvalho Chehab <mchehab+samsung@kernel.org> | 2019-10-01 17:21:14 -0300 |
commit | 7e86efa2ff03db92067b2f6f4fa3f1f8b8da7c76 (patch) | |
tree | d09c07d18c292ae7d86ccd5c1eba3a89e3f6505b /drivers/media/platform | |
parent | 98f290731fe3cec04a1ca0635ad2d5d175d77276 (diff) | |
download | linux-7e86efa2ff03db92067b2f6f4fa3f1f8b8da7c76.tar.bz2 |
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')
-rw-r--r-- | drivers/media/platform/Kconfig | 1 | ||||
-rw-r--r-- | drivers/media/platform/cec-gpio/cec-gpio.c | 41 |
2 files changed, 33 insertions, 9 deletions
diff --git a/drivers/media/platform/Kconfig b/drivers/media/platform/Kconfig index f1f61419fd29..1175f122bb1d 100644 --- a/drivers/media/platform/Kconfig +++ b/drivers/media/platform/Kconfig @@ -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. 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; } |