mirror of
				https://github.com/torvalds/linux.git
				synced 2025-11-04 10:40:15 +02:00 
			
		
		
		
	pinctrl/gpio: Take MUX usage into account
The user space like gpioinfo only see the GPIO usage but not the MUX usage (e.g. I2C or SPI usage) of a pin. As a user we want to know which pin is free/safe to use. So take the MUX usage of strict pinmux controllers into account to get a more realistic view for ioctl GPIO_GET_LINEINFO_IOCTL. Signed-off-by: Stefan Wahren <stefan.wahren@i2se.com> Tested-by: Ramon Fried <rfried.dev@gmail.com> Signed-off-by: Ramon Fried <rfried.dev@gmail.com> Link: https://lore.kernel.org/r/20190814110035.13451-1-ramon.fried@linux.intel.com Acked-by: Stefan Wahren <stefan.wahren@i2se.com> Signed-off-by: Linus Walleij <linus.walleij@linaro.org>
This commit is contained in:
		
							parent
							
								
									2dc889a884
								
							
						
					
					
						commit
						472a61e777
					
				
					 5 changed files with 68 additions and 1 deletions
				
			
		| 
						 | 
				
			
			@ -1084,7 +1084,8 @@ static long gpio_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
 | 
			
		|||
		    test_bit(FLAG_IS_HOGGED, &desc->flags) ||
 | 
			
		||||
		    test_bit(FLAG_USED_AS_IRQ, &desc->flags) ||
 | 
			
		||||
		    test_bit(FLAG_EXPORT, &desc->flags) ||
 | 
			
		||||
		    test_bit(FLAG_SYSFS, &desc->flags))
 | 
			
		||||
		    test_bit(FLAG_SYSFS, &desc->flags) ||
 | 
			
		||||
		    !pinctrl_gpio_can_use_line(chip->base + lineinfo.line_offset))
 | 
			
		||||
			lineinfo.flags |= GPIOLINE_FLAG_KERNEL;
 | 
			
		||||
		if (test_bit(FLAG_IS_OUT, &desc->flags))
 | 
			
		||||
			lineinfo.flags |= GPIOLINE_FLAG_IS_OUT;
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -736,6 +736,34 @@ int pinctrl_get_group_selector(struct pinctrl_dev *pctldev,
 | 
			
		|||
	return -EINVAL;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
bool pinctrl_gpio_can_use_line(unsigned gpio)
 | 
			
		||||
{
 | 
			
		||||
	struct pinctrl_dev *pctldev;
 | 
			
		||||
	struct pinctrl_gpio_range *range;
 | 
			
		||||
	bool result;
 | 
			
		||||
	int pin;
 | 
			
		||||
 | 
			
		||||
	/*
 | 
			
		||||
	 * Try to obtain GPIO range, if it fails
 | 
			
		||||
	 * we're probably dealing with GPIO driver
 | 
			
		||||
	 * without a backing pin controller - bail out.
 | 
			
		||||
	 */
 | 
			
		||||
	if (pinctrl_get_device_gpio_range(gpio, &pctldev, &range))
 | 
			
		||||
		return true;
 | 
			
		||||
 | 
			
		||||
	mutex_lock(&pctldev->mutex);
 | 
			
		||||
 | 
			
		||||
	/* Convert to the pin controllers number space */
 | 
			
		||||
	pin = gpio_to_pin(range, gpio);
 | 
			
		||||
 | 
			
		||||
	result = pinmux_can_be_used_for_gpio(pctldev, pin);
 | 
			
		||||
 | 
			
		||||
	mutex_unlock(&pctldev->mutex);
 | 
			
		||||
 | 
			
		||||
	return result;
 | 
			
		||||
}
 | 
			
		||||
EXPORT_SYMBOL_GPL(pinctrl_gpio_can_use_line);
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * pinctrl_gpio_request() - request a single pin to be used as GPIO
 | 
			
		||||
 * @gpio: the GPIO pin number from the GPIO subsystem number space
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -70,6 +70,30 @@ int pinmux_validate_map(const struct pinctrl_map *map, int i)
 | 
			
		|||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * pinmux_can_be_used_for_gpio() - check if a specific pin
 | 
			
		||||
 *	is either muxed to a different function or used as gpio.
 | 
			
		||||
 *
 | 
			
		||||
 * @pin: the pin number in the global pin space
 | 
			
		||||
 *
 | 
			
		||||
 * Controllers not defined as strict will always return true,
 | 
			
		||||
 * menaning that the gpio can be used.
 | 
			
		||||
 */
 | 
			
		||||
bool pinmux_can_be_used_for_gpio(struct pinctrl_dev *pctldev, unsigned pin)
 | 
			
		||||
{
 | 
			
		||||
	struct pin_desc *desc = pin_desc_get(pctldev, pin);
 | 
			
		||||
	const struct pinmux_ops *ops = pctldev->desc->pmxops;
 | 
			
		||||
 | 
			
		||||
	/* Can't inspect pin, assume it can be used */
 | 
			
		||||
	if (!desc)
 | 
			
		||||
		return true;
 | 
			
		||||
 | 
			
		||||
	if (ops->strict && desc->mux_usecount)
 | 
			
		||||
		return false;
 | 
			
		||||
 | 
			
		||||
	return !(ops->strict && !!desc->gpio_owner);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * pin_request() - request a single pin to be muxed in, typically for GPIO
 | 
			
		||||
 * @pin: the pin number in the global pin space
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -15,6 +15,8 @@ int pinmux_check_ops(struct pinctrl_dev *pctldev);
 | 
			
		|||
 | 
			
		||||
int pinmux_validate_map(const struct pinctrl_map *map, int i);
 | 
			
		||||
 | 
			
		||||
bool pinmux_can_be_used_for_gpio(struct pinctrl_dev *pctldev, unsigned pin);
 | 
			
		||||
 | 
			
		||||
int pinmux_request_gpio(struct pinctrl_dev *pctldev,
 | 
			
		||||
			struct pinctrl_gpio_range *range,
 | 
			
		||||
			unsigned pin, unsigned gpio);
 | 
			
		||||
| 
						 | 
				
			
			@ -42,6 +44,12 @@ static inline int pinmux_validate_map(const struct pinctrl_map *map, int i)
 | 
			
		|||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static inline bool pinmux_can_be_used_for_gpio(struct pinctrl_dev *pctldev,
 | 
			
		||||
					       unsigned pin)
 | 
			
		||||
{
 | 
			
		||||
	return true;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static inline int pinmux_request_gpio(struct pinctrl_dev *pctldev,
 | 
			
		||||
			struct pinctrl_gpio_range *range,
 | 
			
		||||
			unsigned pin, unsigned gpio)
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -24,6 +24,7 @@ struct device;
 | 
			
		|||
#ifdef CONFIG_PINCTRL
 | 
			
		||||
 | 
			
		||||
/* External interface to pin control */
 | 
			
		||||
extern bool pinctrl_gpio_can_use_line(unsigned gpio);
 | 
			
		||||
extern int pinctrl_gpio_request(unsigned gpio);
 | 
			
		||||
extern void pinctrl_gpio_free(unsigned gpio);
 | 
			
		||||
extern int pinctrl_gpio_direction_input(unsigned gpio);
 | 
			
		||||
| 
						 | 
				
			
			@ -61,6 +62,11 @@ static inline int pinctrl_pm_select_idle_state(struct device *dev)
 | 
			
		|||
 | 
			
		||||
#else /* !CONFIG_PINCTRL */
 | 
			
		||||
 | 
			
		||||
static inline bool pinctrl_gpio_can_use_line(unsigned gpio)
 | 
			
		||||
{
 | 
			
		||||
	return true;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static inline int pinctrl_gpio_request(unsigned gpio)
 | 
			
		||||
{
 | 
			
		||||
	return 0;
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
		Reference in a new issue