Skip to content

Commit

Permalink
pinctrl/gpio: Take MUX usage into account
Browse files Browse the repository at this point in the history
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>
  • Loading branch information
Stefan Wahren authored and Linus Walleij committed Aug 23, 2019
1 parent 2dc889a commit 472a61e
Show file tree
Hide file tree
Showing 5 changed files with 68 additions and 1 deletion.
3 changes: 2 additions & 1 deletion drivers/gpio/gpiolib.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
28 changes: 28 additions & 0 deletions drivers/pinctrl/core.c
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
24 changes: 24 additions & 0 deletions drivers/pinctrl/pinmux.c
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
8 changes: 8 additions & 0 deletions drivers/pinctrl/pinmux.h
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down Expand Up @@ -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)
Expand Down
6 changes: 6 additions & 0 deletions include/linux/pinctrl/consumer.h
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down Expand Up @@ -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;
Expand Down

0 comments on commit 472a61e

Please sign in to comment.