Commit d7631e43 authored by Linus Torvalds's avatar Linus Torvalds

Merge tag 'gpio-fixes-for-v5.11-rc5' of git://git.kernel.org/pub/scm/linux/kernel/git/brgl/linux

Pull gpio fixes from Bartosz Golaszewski:

 - rework the character device code to avoid a frame size warning

 - fix printk format issues in gpio-tools

 - warn on redefinition of the to_irq callback in core gpiolib code

 - fix PWM period calculation in gpio-mvebu

 - make gpio-sifive Kconfig entry consistent with other drivers

 - fix a build issue in gpio-tegra

* tag 'gpio-fixes-for-v5.11-rc5' of git://git.kernel.org/pub/scm/linux/kernel/git/brgl/linux:
  gpio: tegra: Add missing dependencies
  gpio: sifive: select IRQ_DOMAIN_HIERARCHY rather than depend on it
  gpio: mvebu: fix pwm .get_state period calculation
  gpiolib: add a warning on gpiochip->to_irq defined
  tools: gpio: fix %llu warning in gpio-watch.c
  tools: gpio: fix %llu warning in gpio-event-mon.c
  gpiolib: cdev: fix frame size warning in gpio_ioctl()
parents 63858ac3 298d75c9
...@@ -521,7 +521,8 @@ config GPIO_SAMA5D2_PIOBU ...@@ -521,7 +521,8 @@ config GPIO_SAMA5D2_PIOBU
config GPIO_SIFIVE config GPIO_SIFIVE
bool "SiFive GPIO support" bool "SiFive GPIO support"
depends on OF_GPIO && IRQ_DOMAIN_HIERARCHY depends on OF_GPIO
select IRQ_DOMAIN_HIERARCHY
select GPIO_GENERIC select GPIO_GENERIC
select GPIOLIB_IRQCHIP select GPIOLIB_IRQCHIP
select REGMAP_MMIO select REGMAP_MMIO
...@@ -597,6 +598,8 @@ config GPIO_TEGRA ...@@ -597,6 +598,8 @@ config GPIO_TEGRA
default ARCH_TEGRA default ARCH_TEGRA
depends on ARCH_TEGRA || COMPILE_TEST depends on ARCH_TEGRA || COMPILE_TEST
depends on OF_GPIO depends on OF_GPIO
select GPIOLIB_IRQCHIP
select IRQ_DOMAIN_HIERARCHY
help help
Say yes here to support GPIO pins on NVIDIA Tegra SoCs. Say yes here to support GPIO pins on NVIDIA Tegra SoCs.
......
...@@ -676,20 +676,17 @@ static void mvebu_pwm_get_state(struct pwm_chip *chip, ...@@ -676,20 +676,17 @@ static void mvebu_pwm_get_state(struct pwm_chip *chip,
else else
state->duty_cycle = 1; state->duty_cycle = 1;
val = (unsigned long long) u; /* on duration */
regmap_read(mvpwm->regs, mvebu_pwmreg_blink_off_duration(mvpwm), &u); regmap_read(mvpwm->regs, mvebu_pwmreg_blink_off_duration(mvpwm), &u);
val = (unsigned long long) u * NSEC_PER_SEC; val += (unsigned long long) u; /* period = on + off duration */
val *= NSEC_PER_SEC;
do_div(val, mvpwm->clk_rate); do_div(val, mvpwm->clk_rate);
if (val < state->duty_cycle) {
state->period = 1;
} else {
val -= state->duty_cycle;
if (val > UINT_MAX) if (val > UINT_MAX)
state->period = UINT_MAX; state->period = UINT_MAX;
else if (val) else if (val)
state->period = val; state->period = val;
else else
state->period = 1; state->period = 1;
}
regmap_read(mvchip->regs, GPIO_BLINK_EN_OFF + mvchip->offset, &u); regmap_read(mvchip->regs, GPIO_BLINK_EN_OFF + mvchip->offset, &u);
if (u) if (u)
......
...@@ -1979,6 +1979,21 @@ struct gpio_chardev_data { ...@@ -1979,6 +1979,21 @@ struct gpio_chardev_data {
#endif #endif
}; };
static int chipinfo_get(struct gpio_chardev_data *cdev, void __user *ip)
{
struct gpio_device *gdev = cdev->gdev;
struct gpiochip_info chipinfo;
memset(&chipinfo, 0, sizeof(chipinfo));
strscpy(chipinfo.name, dev_name(&gdev->dev), sizeof(chipinfo.name));
strscpy(chipinfo.label, gdev->label, sizeof(chipinfo.label));
chipinfo.lines = gdev->ngpio;
if (copy_to_user(ip, &chipinfo, sizeof(chipinfo)))
return -EFAULT;
return 0;
}
#ifdef CONFIG_GPIO_CDEV_V1 #ifdef CONFIG_GPIO_CDEV_V1
/* /*
* returns 0 if the versions match, else the previously selected ABI version * returns 0 if the versions match, else the previously selected ABI version
...@@ -1993,6 +2008,41 @@ static int lineinfo_ensure_abi_version(struct gpio_chardev_data *cdata, ...@@ -1993,6 +2008,41 @@ static int lineinfo_ensure_abi_version(struct gpio_chardev_data *cdata,
return abiv; return abiv;
} }
static int lineinfo_get_v1(struct gpio_chardev_data *cdev, void __user *ip,
bool watch)
{
struct gpio_desc *desc;
struct gpioline_info lineinfo;
struct gpio_v2_line_info lineinfo_v2;
if (copy_from_user(&lineinfo, ip, sizeof(lineinfo)))
return -EFAULT;
/* this doubles as a range check on line_offset */
desc = gpiochip_get_desc(cdev->gdev->chip, lineinfo.line_offset);
if (IS_ERR(desc))
return PTR_ERR(desc);
if (watch) {
if (lineinfo_ensure_abi_version(cdev, 1))
return -EPERM;
if (test_and_set_bit(lineinfo.line_offset, cdev->watched_lines))
return -EBUSY;
}
gpio_desc_to_lineinfo(desc, &lineinfo_v2);
gpio_v2_line_info_to_v1(&lineinfo_v2, &lineinfo);
if (copy_to_user(ip, &lineinfo, sizeof(lineinfo))) {
if (watch)
clear_bit(lineinfo.line_offset, cdev->watched_lines);
return -EFAULT;
}
return 0;
}
#endif #endif
static int lineinfo_get(struct gpio_chardev_data *cdev, void __user *ip, static int lineinfo_get(struct gpio_chardev_data *cdev, void __user *ip,
...@@ -2030,6 +2080,22 @@ static int lineinfo_get(struct gpio_chardev_data *cdev, void __user *ip, ...@@ -2030,6 +2080,22 @@ static int lineinfo_get(struct gpio_chardev_data *cdev, void __user *ip,
return 0; return 0;
} }
static int lineinfo_unwatch(struct gpio_chardev_data *cdev, void __user *ip)
{
__u32 offset;
if (copy_from_user(&offset, ip, sizeof(offset)))
return -EFAULT;
if (offset >= cdev->gdev->ngpio)
return -EINVAL;
if (!test_and_clear_bit(offset, cdev->watched_lines))
return -EBUSY;
return 0;
}
/* /*
* gpio_ioctl() - ioctl handler for the GPIO chardev * gpio_ioctl() - ioctl handler for the GPIO chardev
*/ */
...@@ -2037,80 +2103,24 @@ static long gpio_ioctl(struct file *file, unsigned int cmd, unsigned long arg) ...@@ -2037,80 +2103,24 @@ static long gpio_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
{ {
struct gpio_chardev_data *cdev = file->private_data; struct gpio_chardev_data *cdev = file->private_data;
struct gpio_device *gdev = cdev->gdev; struct gpio_device *gdev = cdev->gdev;
struct gpio_chip *gc = gdev->chip;
void __user *ip = (void __user *)arg; void __user *ip = (void __user *)arg;
__u32 offset;
/* We fail any subsequent ioctl():s when the chip is gone */ /* We fail any subsequent ioctl():s when the chip is gone */
if (!gc) if (!gdev->chip)
return -ENODEV; return -ENODEV;
/* Fill in the struct and pass to userspace */ /* Fill in the struct and pass to userspace */
if (cmd == GPIO_GET_CHIPINFO_IOCTL) { if (cmd == GPIO_GET_CHIPINFO_IOCTL) {
struct gpiochip_info chipinfo; return chipinfo_get(cdev, ip);
memset(&chipinfo, 0, sizeof(chipinfo));
strscpy(chipinfo.name, dev_name(&gdev->dev),
sizeof(chipinfo.name));
strscpy(chipinfo.label, gdev->label,
sizeof(chipinfo.label));
chipinfo.lines = gdev->ngpio;
if (copy_to_user(ip, &chipinfo, sizeof(chipinfo)))
return -EFAULT;
return 0;
#ifdef CONFIG_GPIO_CDEV_V1 #ifdef CONFIG_GPIO_CDEV_V1
} else if (cmd == GPIO_GET_LINEINFO_IOCTL) {
struct gpio_desc *desc;
struct gpioline_info lineinfo;
struct gpio_v2_line_info lineinfo_v2;
if (copy_from_user(&lineinfo, ip, sizeof(lineinfo)))
return -EFAULT;
/* this doubles as a range check on line_offset */
desc = gpiochip_get_desc(gc, lineinfo.line_offset);
if (IS_ERR(desc))
return PTR_ERR(desc);
gpio_desc_to_lineinfo(desc, &lineinfo_v2);
gpio_v2_line_info_to_v1(&lineinfo_v2, &lineinfo);
if (copy_to_user(ip, &lineinfo, sizeof(lineinfo)))
return -EFAULT;
return 0;
} else if (cmd == GPIO_GET_LINEHANDLE_IOCTL) { } else if (cmd == GPIO_GET_LINEHANDLE_IOCTL) {
return linehandle_create(gdev, ip); return linehandle_create(gdev, ip);
} else if (cmd == GPIO_GET_LINEEVENT_IOCTL) { } else if (cmd == GPIO_GET_LINEEVENT_IOCTL) {
return lineevent_create(gdev, ip); return lineevent_create(gdev, ip);
} else if (cmd == GPIO_GET_LINEINFO_WATCH_IOCTL) { } else if (cmd == GPIO_GET_LINEINFO_IOCTL ||
struct gpio_desc *desc; cmd == GPIO_GET_LINEINFO_WATCH_IOCTL) {
struct gpioline_info lineinfo; return lineinfo_get_v1(cdev, ip,
struct gpio_v2_line_info lineinfo_v2; cmd == GPIO_GET_LINEINFO_WATCH_IOCTL);
if (copy_from_user(&lineinfo, ip, sizeof(lineinfo)))
return -EFAULT;
/* this doubles as a range check on line_offset */
desc = gpiochip_get_desc(gc, lineinfo.line_offset);
if (IS_ERR(desc))
return PTR_ERR(desc);
if (lineinfo_ensure_abi_version(cdev, 1))
return -EPERM;
if (test_and_set_bit(lineinfo.line_offset, cdev->watched_lines))
return -EBUSY;
gpio_desc_to_lineinfo(desc, &lineinfo_v2);
gpio_v2_line_info_to_v1(&lineinfo_v2, &lineinfo);
if (copy_to_user(ip, &lineinfo, sizeof(lineinfo))) {
clear_bit(lineinfo.line_offset, cdev->watched_lines);
return -EFAULT;
}
return 0;
#endif /* CONFIG_GPIO_CDEV_V1 */ #endif /* CONFIG_GPIO_CDEV_V1 */
} else if (cmd == GPIO_V2_GET_LINEINFO_IOCTL || } else if (cmd == GPIO_V2_GET_LINEINFO_IOCTL ||
cmd == GPIO_V2_GET_LINEINFO_WATCH_IOCTL) { cmd == GPIO_V2_GET_LINEINFO_WATCH_IOCTL) {
...@@ -2119,16 +2129,7 @@ static long gpio_ioctl(struct file *file, unsigned int cmd, unsigned long arg) ...@@ -2119,16 +2129,7 @@ static long gpio_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
} else if (cmd == GPIO_V2_GET_LINE_IOCTL) { } else if (cmd == GPIO_V2_GET_LINE_IOCTL) {
return linereq_create(gdev, ip); return linereq_create(gdev, ip);
} else if (cmd == GPIO_GET_LINEINFO_UNWATCH_IOCTL) { } else if (cmd == GPIO_GET_LINEINFO_UNWATCH_IOCTL) {
if (copy_from_user(&offset, ip, sizeof(offset))) return lineinfo_unwatch(cdev, ip);
return -EFAULT;
if (offset >= cdev->gdev->ngpio)
return -EINVAL;
if (!test_and_clear_bit(offset, cdev->watched_lines))
return -EBUSY;
return 0;
} }
return -EINVAL; return -EINVAL;
} }
......
...@@ -1489,6 +1489,9 @@ static int gpiochip_add_irqchip(struct gpio_chip *gc, ...@@ -1489,6 +1489,9 @@ static int gpiochip_add_irqchip(struct gpio_chip *gc,
type = IRQ_TYPE_NONE; type = IRQ_TYPE_NONE;
} }
if (gc->to_irq)
chip_warn(gc, "to_irq is redefined in %s and you shouldn't rely on it\n", __func__);
gc->to_irq = gpiochip_to_irq; gc->to_irq = gpiochip_to_irq;
gc->irq.default_type = type; gc->irq.default_type = type;
gc->irq.lock_key = lock_key; gc->irq.lock_key = lock_key;
......
...@@ -107,8 +107,8 @@ int monitor_device(const char *device_name, ...@@ -107,8 +107,8 @@ int monitor_device(const char *device_name,
ret = -EIO; ret = -EIO;
break; break;
} }
fprintf(stdout, "GPIO EVENT at %llu on line %d (%d|%d) ", fprintf(stdout, "GPIO EVENT at %" PRIu64 " on line %d (%d|%d) ",
event.timestamp_ns, event.offset, event.line_seqno, (uint64_t)event.timestamp_ns, event.offset, event.line_seqno,
event.seqno); event.seqno);
switch (event.id) { switch (event.id) {
case GPIO_V2_LINE_EVENT_RISING_EDGE: case GPIO_V2_LINE_EVENT_RISING_EDGE:
......
...@@ -10,6 +10,7 @@ ...@@ -10,6 +10,7 @@
#include <ctype.h> #include <ctype.h>
#include <errno.h> #include <errno.h>
#include <fcntl.h> #include <fcntl.h>
#include <inttypes.h>
#include <linux/gpio.h> #include <linux/gpio.h>
#include <poll.h> #include <poll.h>
#include <stdbool.h> #include <stdbool.h>
...@@ -86,8 +87,8 @@ int main(int argc, char **argv) ...@@ -86,8 +87,8 @@ int main(int argc, char **argv)
return EXIT_FAILURE; return EXIT_FAILURE;
} }
printf("line %u: %s at %llu\n", printf("line %u: %s at %" PRIu64 "\n",
chg.info.offset, event, chg.timestamp_ns); chg.info.offset, event, (uint64_t)chg.timestamp_ns);
} }
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment