Commit d7631e43 authored by Linus Torvalds's avatar Linus Torvalds
Browse files

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
Loading
Loading
Loading
Loading
+4 −1
Original line number Diff line number Diff line
@@ -521,7 +521,8 @@ config GPIO_SAMA5D2_PIOBU

config GPIO_SIFIVE
	bool "SiFive GPIO support"
	depends on OF_GPIO && IRQ_DOMAIN_HIERARCHY
	depends on OF_GPIO
	select IRQ_DOMAIN_HIERARCHY
	select GPIO_GENERIC
	select GPIOLIB_IRQCHIP
	select REGMAP_MMIO
@@ -597,6 +598,8 @@ config GPIO_TEGRA
	default ARCH_TEGRA
	depends on ARCH_TEGRA || COMPILE_TEST
	depends on OF_GPIO
	select GPIOLIB_IRQCHIP
	select IRQ_DOMAIN_HIERARCHY
	help
	  Say yes here to support GPIO pins on NVIDIA Tegra SoCs.

+8 −11
Original line number Diff line number Diff line
@@ -676,20 +676,17 @@ static void mvebu_pwm_get_state(struct pwm_chip *chip,
	else
		state->duty_cycle = 1;

	val = (unsigned long long) u; /* on duration */
	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);
	if (val < state->duty_cycle) {
		state->period = 1;
	} else {
		val -= state->duty_cycle;
	if (val > UINT_MAX)
		state->period = UINT_MAX;
	else if (val)
		state->period = val;
	else
		state->period = 1;
	}

	regmap_read(mvchip->regs, GPIO_BLINK_EN_OFF + mvchip->offset, &u);
	if (u)
+73 −72
Original line number Diff line number Diff line
@@ -1979,6 +1979,21 @@ struct gpio_chardev_data {
#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
/*
 * 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,

	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

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;
}

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
 */
@@ -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_device *gdev = cdev->gdev;
	struct gpio_chip *gc = gdev->chip;
	void __user *ip = (void __user *)arg;
	__u32 offset;

	/* We fail any subsequent ioctl():s when the chip is gone */
	if (!gc)
	if (!gdev->chip)
		return -ENODEV;

	/* Fill in the struct and pass to userspace */
	if (cmd == GPIO_GET_CHIPINFO_IOCTL) {
		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;
		return chipinfo_get(cdev, ip);
#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) {
		return linehandle_create(gdev, ip);
	} else if (cmd == GPIO_GET_LINEEVENT_IOCTL) {
		return lineevent_create(gdev, ip);
	} else if (cmd == GPIO_GET_LINEINFO_WATCH_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);

		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;
	} else if (cmd == GPIO_GET_LINEINFO_IOCTL ||
		   cmd == GPIO_GET_LINEINFO_WATCH_IOCTL) {
		return lineinfo_get_v1(cdev, ip,
				       cmd == GPIO_GET_LINEINFO_WATCH_IOCTL);
#endif /* CONFIG_GPIO_CDEV_V1 */
	} else if (cmd == GPIO_V2_GET_LINEINFO_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)
	} else if (cmd == GPIO_V2_GET_LINE_IOCTL) {
		return linereq_create(gdev, ip);
	} else if (cmd == GPIO_GET_LINEINFO_UNWATCH_IOCTL) {
		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;
		return lineinfo_unwatch(cdev, ip);
	}
	return -EINVAL;
}
+3 −0
Original line number Diff line number Diff line
@@ -1489,6 +1489,9 @@ static int gpiochip_add_irqchip(struct gpio_chip *gc,
		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->irq.default_type = type;
	gc->irq.lock_key = lock_key;
+2 −2
Original line number Diff line number Diff line
@@ -107,8 +107,8 @@ int monitor_device(const char *device_name,
			ret = -EIO;
			break;
		}
		fprintf(stdout, "GPIO EVENT at %llu on line %d (%d|%d) ",
			event.timestamp_ns, event.offset, event.line_seqno,
		fprintf(stdout, "GPIO EVENT at %" PRIu64 " on line %d (%d|%d) ",
			(uint64_t)event.timestamp_ns, event.offset, event.line_seqno,
			event.seqno);
		switch (event.id) {
		case GPIO_V2_LINE_EVENT_RISING_EDGE:
Loading