From: Lakshmi Sowjanya D <lakshmi.sowjanya.d@xxxxxxxxx> Some Intel Timed I/O devices do not implement IRQ functionality. Augment read() interface to allow polling. Add two GPIO device methods: setup_poll() and poll(): - setup_poll() configures the GPIO interface e.g. capture rising edges - poll() checks for events on the interface To implement polling, the driver must implement the two functions above and should either leave to_irq() method NULL or return irq 0. setup_poll() should configure the hardware to 'listen' for input events. poll() driver implementation must return the realtime timestamp corresponding to the event and -EAGAIN if no data is available. Co-developed-by: Christopher Hall <christopher.s.hall@xxxxxxxxx> Signed-off-by: Christopher Hall <christopher.s.hall@xxxxxxxxx> Signed-off-by: Tamal Saha <tamal.saha@xxxxxxxxx> Signed-off-by: Lakshmi Sowjanya D <lakshmi.sowjanya.d@xxxxxxxxx> Reviewed-by: Mark Gross <mgross@xxxxxxxxxxxxxxx> --- drivers/gpio/gpiolib-cdev.c | 28 ++++++++++++++++++++++++++-- include/linux/gpio/driver.h | 19 +++++++++++++++++++ 2 files changed, 45 insertions(+), 2 deletions(-) diff --git a/drivers/gpio/gpiolib-cdev.c b/drivers/gpio/gpiolib-cdev.c index c7b5446d01fd..4741bf34750b 100644 --- a/drivers/gpio/gpiolib-cdev.c +++ b/drivers/gpio/gpiolib-cdev.c @@ -1227,13 +1227,34 @@ static ssize_t linereq_read(struct file *file, loff_t *f_ps) { struct linereq *lr = file->private_data; + struct gpioevent_poll_data poll_data; struct gpio_v2_line_event le; ssize_t bytes_read = 0; - int ret; + int ret, offset; if (count < sizeof(le)) return -EINVAL; + /* Without an IRQ, we can only poll */ + offset = gpio_chip_hwgpio(lr->gdev->descs); + if (lr->lines[offset].irq == 0) { + struct gpio_v2_line_event *event; + + if (!(file->f_flags & O_NONBLOCK)) + return -ENODEV; + + ret = lr->gdev->chip->do_poll(lr->gdev->chip, offset, + lr->lines[offset].eflags, &poll_data); + if (ret) + return ret; + event = kzalloc(sizeof(*event), GFP_KERNEL); + event->timestamp_ns = poll_data.timestamp; + event->id = poll_data.id; + if (copy_to_user(buf, (void *)&event, sizeof(event))) + return -EFAULT; + return sizeof(event); + } + do { spin_lock(&lr->wait.lock); if (kfifo_is_empty(&lr->events)) { @@ -1314,6 +1335,7 @@ static int linereq_create(struct gpio_device *gdev, void __user *ip) { struct gpio_v2_line_request ulr; struct gpio_v2_line_config *lc; + unsigned int file_flags; struct linereq *lr; struct file *file; u64 flags; @@ -1411,6 +1433,8 @@ static int linereq_create(struct gpio_device *gdev, void __user *ip) goto out_free_linereq; } + file_flags = O_RDONLY | O_CLOEXEC; + blocking_notifier_call_chain(&desc->gdev->notifier, GPIO_V2_LINE_CHANGED_REQUESTED, desc); @@ -1425,7 +1449,7 @@ static int linereq_create(struct gpio_device *gdev, void __user *ip) } file = anon_inode_getfile("gpio-line", &line_fileops, lr, - O_RDONLY | O_CLOEXEC); + file_flags); if (IS_ERR(file)) { ret = PTR_ERR(file); goto out_put_unused_fd; diff --git a/include/linux/gpio/driver.h b/include/linux/gpio/driver.h index 3a268781fcec..f5b971ad40bc 100644 --- a/include/linux/gpio/driver.h +++ b/include/linux/gpio/driver.h @@ -17,6 +17,7 @@ struct device_node; struct seq_file; struct gpio_device; struct module; +struct gpioevent_poll_data; enum gpiod_flags; enum gpio_lookup_flags; @@ -304,6 +305,11 @@ struct gpio_irq_chip { * @add_pin_ranges: optional routine to initialize pin ranges, to be used when * requires special mapping of the pins that provides GPIO functionality. * It is called after adding GPIO chip and before adding IRQ chip. + * @setup_poll: optional routine for devices that don't support interrupts. + * Takes flags argument as in/out parameter, where caller requests + * event flags and driver returns accepted flags. + * @do_poll: optional routine for devices that don't support interrupts. + * Returns event specification in data parameter. * @base: identifies the first GPIO number handled by this chip; * or, if negative during registration, requests dynamic ID allocation. * DEPRECATION: providing anything non-negative and nailing the base @@ -396,6 +402,14 @@ struct gpio_chip { int (*add_pin_ranges)(struct gpio_chip *gc); + int (*setup_poll)(struct gpio_chip *chip, + unsigned int offset, + u32 *eflags); + + int (*do_poll)(struct gpio_chip *chip, + unsigned int offset, u32 eflags, + struct gpioevent_poll_data *data); + int base; u16 ngpio; const char *const *names; @@ -471,6 +485,11 @@ struct gpio_chip { #endif /* CONFIG_OF_GPIO */ }; +struct gpioevent_poll_data { + __u64 timestamp; + __u32 id; +}; + extern const char *gpiochip_is_requested(struct gpio_chip *gc, unsigned int offset); -- 2.17.1