summaryrefslogtreecommitdiffstats
path: root/drivers/gpio/gpiolib.c
diff options
context:
space:
mode:
authorMika Westerberg2017-01-23 13:34:34 +0100
committerLinus Walleij2017-01-26 15:27:37 +0100
commit2956b5d94a76b596fa5057c2b3ca915cb27d7652 (patch)
tree3a1dbce1201ef4923a4124f63eb209026e8fba7e /drivers/gpio/gpiolib.c
parentpinctrl: Allow configuration of pins from gpiolib based drivers (diff)
downloadkernel-qcow2-linux-2956b5d94a76b596fa5057c2b3ca915cb27d7652.tar.gz
kernel-qcow2-linux-2956b5d94a76b596fa5057c2b3ca915cb27d7652.tar.xz
kernel-qcow2-linux-2956b5d94a76b596fa5057c2b3ca915cb27d7652.zip
pinctrl / gpio: Introduce .set_config() callback for GPIO chips
Currently we already have two pin configuration related callbacks available for GPIO chips .set_single_ended() and .set_debounce(). In future we expect to have even more, which does not scale well if we need to add yet another callback to the GPIO chip structure for each possible configuration parameter. Better solution is to reuse what we already have available in the generic pinconf. To support this, we introduce a new .set_config() callback for GPIO chips. The callback takes a single packed pin configuration value as parameter. This can then be extended easily beyond what is currently supported by just adding new types to the generic pinconf enum. If the GPIO driver is backed up by a pinctrl driver the GPIO driver can just assign gpiochip_generic_config() (introduced in this patch) to .set_config and that will take care configuration requests are directed to the pinctrl driver. We then convert the existing drivers over .set_config() and finally remove the .set_single_ended() and .set_debounce() callbacks. Suggested-by: Linus Walleij <linus.walleij@linaro.org> Signed-off-by: Mika Westerberg <mika.westerberg@linux.intel.com> Reviewed-by: Andy Shevchenko <andriy.shevchenko@linux.intel.com> Signed-off-by: Linus Walleij <linus.walleij@linaro.org>
Diffstat (limited to 'drivers/gpio/gpiolib.c')
-rw-r--r--drivers/gpio/gpiolib.c56
1 files changed, 36 insertions, 20 deletions
diff --git a/drivers/gpio/gpiolib.c b/drivers/gpio/gpiolib.c
index f4c26c7826cd..b1659860be1a 100644
--- a/drivers/gpio/gpiolib.c
+++ b/drivers/gpio/gpiolib.c
@@ -1876,6 +1876,19 @@ void gpiochip_generic_free(struct gpio_chip *chip, unsigned offset)
}
EXPORT_SYMBOL_GPL(gpiochip_generic_free);
+/**
+ * gpiochip_generic_config() - apply configuration for a pin
+ * @chip: the gpiochip owning the GPIO
+ * @offset: the offset of the GPIO to apply the configuration
+ * @config: the configuration to be applied
+ */
+int gpiochip_generic_config(struct gpio_chip *chip, unsigned offset,
+ unsigned long config)
+{
+ return pinctrl_gpio_set_config(chip->gpiodev->base + offset, config);
+}
+EXPORT_SYMBOL_GPL(gpiochip_generic_config);
+
#ifdef CONFIG_PINCTRL
/**
@@ -2264,6 +2277,14 @@ int gpiod_direction_input(struct gpio_desc *desc)
}
EXPORT_SYMBOL_GPL(gpiod_direction_input);
+static int gpio_set_drive_single_ended(struct gpio_chip *gc, unsigned offset,
+ enum pin_config_param mode)
+{
+ unsigned long config = { PIN_CONF_PACKED(mode, 0) };
+
+ return gc->set_config ? gc->set_config(gc, offset, config) : -ENOTSUPP;
+}
+
static int _gpiod_direction_output_raw(struct gpio_desc *desc, int value)
{
struct gpio_chip *gc = desc->gdev->chip;
@@ -2280,32 +2301,25 @@ static int _gpiod_direction_output_raw(struct gpio_desc *desc, int value)
if (test_bit(FLAG_OPEN_DRAIN, &desc->flags)) {
/* First see if we can enable open drain in hardware */
- if (gc->set_single_ended) {
- ret = gc->set_single_ended(gc, gpio_chip_hwgpio(desc),
- LINE_MODE_OPEN_DRAIN);
- if (!ret)
- goto set_output_value;
- }
+ ret = gpio_set_drive_single_ended(gc, gpio_chip_hwgpio(desc),
+ PIN_CONFIG_DRIVE_OPEN_DRAIN);
+ if (!ret)
+ goto set_output_value;
/* Emulate open drain by not actively driving the line high */
if (val)
return gpiod_direction_input(desc);
}
else if (test_bit(FLAG_OPEN_SOURCE, &desc->flags)) {
- if (gc->set_single_ended) {
- ret = gc->set_single_ended(gc, gpio_chip_hwgpio(desc),
- LINE_MODE_OPEN_SOURCE);
- if (!ret)
- goto set_output_value;
- }
+ ret = gpio_set_drive_single_ended(gc, gpio_chip_hwgpio(desc),
+ PIN_CONFIG_DRIVE_OPEN_SOURCE);
+ if (!ret)
+ goto set_output_value;
/* Emulate open source by not actively driving the line low */
if (!val)
return gpiod_direction_input(desc);
} else {
- /* Make sure to disable open drain/source hardware, if any */
- if (gc->set_single_ended)
- gc->set_single_ended(gc,
- gpio_chip_hwgpio(desc),
- LINE_MODE_PUSH_PULL);
+ gpio_set_drive_single_ended(gc, gpio_chip_hwgpio(desc),
+ PIN_CONFIG_DRIVE_PUSH_PULL);
}
set_output_value:
@@ -2376,17 +2390,19 @@ EXPORT_SYMBOL_GPL(gpiod_direction_output);
int gpiod_set_debounce(struct gpio_desc *desc, unsigned debounce)
{
struct gpio_chip *chip;
+ unsigned long config;
VALIDATE_DESC(desc);
chip = desc->gdev->chip;
- if (!chip->set || !chip->set_debounce) {
+ if (!chip->set || !chip->set_config) {
gpiod_dbg(desc,
- "%s: missing set() or set_debounce() operations\n",
+ "%s: missing set() or set_config() operations\n",
__func__);
return -ENOTSUPP;
}
- return chip->set_debounce(chip, gpio_chip_hwgpio(desc), debounce);
+ config = pinconf_to_config_packed(PIN_CONFIG_INPUT_DEBOUNCE, debounce);
+ return chip->set_config(chip, gpio_chip_hwgpio(desc), config);
}
EXPORT_SYMBOL_GPL(gpiod_set_debounce);