Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

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>

authored by

Hans Verkuil and committed by
Mauro Carvalho Chehab
7e86efa2 98f29073

+33 -9
+1
drivers/media/platform/Kconfig
··· 588 588 depends on PREEMPT || COMPILE_TEST 589 589 select CEC_CORE 590 590 select CEC_PIN 591 + select CEC_NOTIFIER 591 592 select GPIOLIB 592 593 help 593 594 This is a generic GPIO-based CEC driver.
+32 -9
drivers/media/platform/cec-gpio/cec-gpio.c
··· 8 8 #include <linux/delay.h> 9 9 #include <linux/platform_device.h> 10 10 #include <linux/gpio/consumer.h> 11 + #include <media/cec-notifier.h> 11 12 #include <media/cec-pin.h> 12 13 13 14 struct cec_gpio { 14 15 struct cec_adapter *adap; 16 + struct cec_notifier *notifier; 15 17 struct device *dev; 16 18 17 19 struct gpio_desc *cec_gpio; ··· 175 173 static int cec_gpio_probe(struct platform_device *pdev) 176 174 { 177 175 struct device *dev = &pdev->dev; 176 + struct device *hdmi_dev; 178 177 struct cec_gpio *cec; 178 + u32 caps = CEC_CAP_DEFAULTS | CEC_CAP_MONITOR_ALL | CEC_CAP_MONITOR_PIN; 179 179 int ret; 180 + 181 + hdmi_dev = cec_notifier_parse_hdmi_phandle(dev); 182 + if (PTR_ERR(hdmi_dev) == -EPROBE_DEFER) 183 + return PTR_ERR(hdmi_dev); 184 + if (IS_ERR(hdmi_dev)) 185 + caps |= CEC_CAP_PHYS_ADDR; 180 186 181 187 cec = devm_kzalloc(dev, sizeof(*cec), GFP_KERNEL); 182 188 if (!cec) ··· 206 196 return PTR_ERR(cec->v5_gpio); 207 197 208 198 cec->adap = cec_pin_allocate_adapter(&cec_gpio_pin_ops, 209 - cec, pdev->name, CEC_CAP_DEFAULTS | CEC_CAP_PHYS_ADDR | 210 - CEC_CAP_MONITOR_ALL | CEC_CAP_MONITOR_PIN); 199 + cec, pdev->name, caps); 211 200 if (IS_ERR(cec->adap)) 212 201 return PTR_ERR(cec->adap); 213 202 ··· 214 205 IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING, 215 206 cec->adap->name, cec); 216 207 if (ret) 217 - return ret; 208 + goto del_adap; 218 209 219 210 cec_gpio_disable_irq(cec->adap); 220 211 ··· 227 218 IRQF_TRIGGER_FALLING | IRQF_TRIGGER_RISING, 228 219 "hpd-gpio", cec); 229 220 if (ret) 230 - return ret; 221 + goto del_adap; 231 222 } 232 223 233 224 if (cec->v5_gpio) { ··· 239 230 IRQF_TRIGGER_FALLING | IRQF_TRIGGER_RISING, 240 231 "v5-gpio", cec); 241 232 if (ret) 242 - return ret; 233 + goto del_adap; 234 + } 235 + 236 + if (!IS_ERR(hdmi_dev)) { 237 + cec->notifier = cec_notifier_cec_adap_register(hdmi_dev, NULL, 238 + cec->adap); 239 + if (!cec->notifier) { 240 + ret = -ENOMEM; 241 + goto del_adap; 242 + } 243 243 } 244 244 245 245 ret = cec_register_adapter(cec->adap, &pdev->dev); 246 - if (ret) { 247 - cec_delete_adapter(cec->adap); 248 - return ret; 249 - } 246 + if (ret) 247 + goto unreg_notifier; 250 248 251 249 platform_set_drvdata(pdev, cec); 252 250 return 0; 251 + 252 + unreg_notifier: 253 + cec_notifier_cec_adap_unregister(cec->notifier); 254 + del_adap: 255 + cec_delete_adapter(cec->adap); 256 + return ret; 253 257 } 254 258 255 259 static int cec_gpio_remove(struct platform_device *pdev) 256 260 { 257 261 struct cec_gpio *cec = platform_get_drvdata(pdev); 258 262 263 + cec_notifier_cec_adap_unregister(cec->notifier); 259 264 cec_unregister_adapter(cec->adap); 260 265 return 0; 261 266 }