[PATCHv3 4/5] cec-gpio: add HDMI CEC GPIO driver
Linus Walleij
linus.walleij at linaro.org
Thu Aug 31 08:28:49 UTC 2017
On Wed, Aug 30, 2017 at 6:10 PM, Hans Verkuil <hverkuil at xs4all.nl> wrote:
> From: Hans Verkuil <hans.verkuil at cisco.com>
>
> Add a simple HDMI CEC GPIO driver that sits on top of the cec-pin framework.
>
> While I have heard of SoCs that use the GPIO pin for CEC (apparently an
> early RockChip SoC used that), the main use-case of this driver is to
> function as a debugging tool.
>
> By connecting the CEC line to a GPIO pin on a Raspberry Pi 3 for example
> it turns it into a CEC debugger and protocol analyzer.
>
> With 'cec-ctl --monitor-pin' the CEC traffic can be analyzed.
>
> But of course it can also be used with any hardware project where the
> HDMI CEC pin is hooked up to a pull-up gpio pin.
>
> In addition this has (optional) support for tracing HPD changes if the
> HPD is connected to a GPIO.
>
> Signed-off-by: Hans Verkuil <hans.verkuil at cisco.com>
Pretty cool stuff!
> +config CEC_GPIO
> + tristate "Generic GPIO-based CEC driver"
> + depends on PREEMPT
depends on GPIOLIB
or
select GPIOLIB
your pick.
> +#include <linux/gpio.h>
This should not be needed in new code.
> +#include <linux/gpio/consumer.h>
This should be enough.
> +#include <linux/of_gpio.h>
Your should not need this either.
> +struct cec_gpio {
> + struct cec_adapter *adap;
> + struct device *dev;
> + int gpio;
> + int hpd_gpio;
Think this should be:
struct gpio_desc *gpio;
struct gpio_desc *hpd_gpio;
> + int irq;
> + int hpd_irq;
> + bool hpd_is_high;
> + ktime_t hpd_ts;
> + bool is_low;
> + bool have_irq;
> +};
> +
> +static bool cec_gpio_read(struct cec_adapter *adap)
> +{
> + struct cec_gpio *cec = cec_get_drvdata(adap);
> +
> + if (cec->is_low)
> + return false;
> + return gpio_get_value(cec->gpio);
Use descriptor accessors
gpiod_get_value()
> +static void cec_gpio_high(struct cec_adapter *adap)
> +{
> + struct cec_gpio *cec = cec_get_drvdata(adap);
> +
> + if (!cec->is_low)
> + return;
> + cec->is_low = false;
> + gpio_direction_input(cec->gpio);
Are you setting the GPIO high by setting it as input?
That sounds like you should be requesting it as
open drain in the DTS file, see
Documentation/gpio/driver.txt
for details about open drain, and use
GPIO_LINE_OPEN_DRAIN
from <dt-bindings/gpio/gpio.h>
> +static void cec_gpio_low(struct cec_adapter *adap)
> +{
> + struct cec_gpio *cec = cec_get_drvdata(adap);
> +
> + if (cec->is_low)
> + return;
> + if (WARN_ON_ONCE(cec->have_irq))
> + free_irq(cec->irq, cec);
> + cec->have_irq = false;
> + cec->is_low = true;
> + gpio_direction_output(cec->gpio, 0);
Yeah this looks like you're doing open drain.
gpiod_direction_output() etc.
> +static int cec_gpio_read_hpd(struct cec_adapter *adap)
> +{
> + struct cec_gpio *cec = cec_get_drvdata(adap);
> +
> + if (cec->hpd_gpio < 0)
> + return -ENOTTY;
> + return gpio_get_value(cec->hpd_gpio);
gpiod_get_value()
> +static int cec_gpio_probe(struct platform_device *pdev)
> +{
> + struct device *dev = &pdev->dev;
> + enum of_gpio_flags hpd_gpio_flags;
> + struct cec_gpio *cec;
> + int ret;
> +
> + cec = devm_kzalloc(dev, sizeof(*cec), GFP_KERNEL);
> + if (!cec)
> + return -ENOMEM;
> +
> + cec->gpio = of_get_named_gpio_flags(dev->of_node,
> + "cec-gpio", 0, &hpd_gpio_flags);
> + if (cec->gpio < 0)
> + return cec->gpio;
> +
> + cec->hpd_gpio = of_get_named_gpio_flags(dev->of_node,
> + "hpd-gpio", 0, &hpd_gpio_flags);
This is a proper device so don't use all this trouble.
cec->gpio = gpiod_get(dev, "cec-gpio", GPIOD_IN);
or similar (grep for examples!)
Same for hdp_gpio.
> + cec->irq = gpio_to_irq(cec->gpio);
gpiod_to_irq()
> + gpio_direction_input(cec->gpio);
This is not needed with the above IN flag.
But as said above, maybe you are looking for an open drain
output actually.
> + if (cec->hpd_gpio >= 0) {
> + cec->hpd_irq = gpio_to_irq(cec->hpd_gpio);
> + gpio_direction_input(cec->hpd_gpio);
Already done if you pass the right flag. This should be IN for sure.
Use gpiod_to_irq().
Please include me on subsequent posts, I want to try to use
descriptors as much as possible for new drivers.
Yours,
Linus Walleij
More information about the dri-devel
mailing list