summaryrefslogtreecommitdiff
path: root/drivers/gpio/gpio-regmap.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/gpio/gpio-regmap.c')
-rw-r--r--drivers/gpio/gpio-regmap.c37
1 files changed, 33 insertions, 4 deletions
diff --git a/drivers/gpio/gpio-regmap.c b/drivers/gpio/gpio-regmap.c
index 9ae4a41a2427..b3b4e77ec147 100644
--- a/drivers/gpio/gpio-regmap.c
+++ b/drivers/gpio/gpio-regmap.c
@@ -31,6 +31,7 @@ struct gpio_regmap {
unsigned int reg_clr_base;
unsigned int reg_dir_in_base;
unsigned int reg_dir_out_base;
+ unsigned long *fixed_direction_mask;
unsigned long *fixed_direction_output;
#ifdef CONFIG_REGMAP_IRQ
@@ -138,6 +139,20 @@ static int gpio_regmap_set_with_clear(struct gpio_chip *chip,
return regmap_write(gpio->regmap, reg, mask);
}
+static bool gpio_regmap_fixed_direction(struct gpio_regmap *gpio,
+ unsigned int offset)
+{
+ if (!gpio->fixed_direction_output)
+ return false;
+
+ /* In this case only some GPIOs are fixed as input/output */
+ if (gpio->fixed_direction_mask &&
+ !test_bit(offset, gpio->fixed_direction_mask))
+ return false;
+
+ return true;
+}
+
static int gpio_regmap_get_direction(struct gpio_chip *chip,
unsigned int offset)
{
@@ -145,7 +160,7 @@ static int gpio_regmap_get_direction(struct gpio_chip *chip,
unsigned int base, val, reg, mask;
int invert, ret;
- if (gpio->fixed_direction_output) {
+ if (gpio_regmap_fixed_direction(gpio, offset)) {
if (test_bit(offset, gpio->fixed_direction_output))
return GPIO_LINE_DIRECTION_OUT;
else
@@ -302,12 +317,23 @@ struct gpio_regmap *gpio_regmap_register(const struct gpio_regmap_config *config
goto err_free_gpio;
}
+ if (config->fixed_direction_mask) {
+ gpio->fixed_direction_mask = bitmap_alloc(chip->ngpio,
+ GFP_KERNEL);
+ if (!gpio->fixed_direction_mask) {
+ ret = -ENOMEM;
+ goto err_free_gpio;
+ }
+ bitmap_copy(gpio->fixed_direction_mask,
+ config->fixed_direction_mask, chip->ngpio);
+ }
+
if (config->fixed_direction_output) {
gpio->fixed_direction_output = bitmap_alloc(chip->ngpio,
GFP_KERNEL);
if (!gpio->fixed_direction_output) {
ret = -ENOMEM;
- goto err_free_gpio;
+ goto err_free_bitmap_dirmask;
}
bitmap_copy(gpio->fixed_direction_output,
config->fixed_direction_output, chip->ngpio);
@@ -329,7 +355,7 @@ struct gpio_regmap *gpio_regmap_register(const struct gpio_regmap_config *config
ret = gpiochip_add_data(chip, gpio);
if (ret < 0)
- goto err_free_bitmap;
+ goto err_free_bitmap_output;
#ifdef CONFIG_REGMAP_IRQ
if (config->regmap_irq_chip) {
@@ -355,8 +381,10 @@ struct gpio_regmap *gpio_regmap_register(const struct gpio_regmap_config *config
err_remove_gpiochip:
gpiochip_remove(chip);
-err_free_bitmap:
+err_free_bitmap_output:
bitmap_free(gpio->fixed_direction_output);
+err_free_bitmap_dirmask:
+ bitmap_free(gpio->fixed_direction_mask);
err_free_gpio:
kfree(gpio);
return ERR_PTR(ret);
@@ -376,6 +404,7 @@ void gpio_regmap_unregister(struct gpio_regmap *gpio)
gpiochip_remove(&gpio->gpio_chip);
bitmap_free(gpio->fixed_direction_output);
+ bitmap_free(gpio->fixed_direction_mask);
kfree(gpio);
}
EXPORT_SYMBOL_GPL(gpio_regmap_unregister);