summaryrefslogtreecommitdiff
path: root/drivers/pinctrl/pinctrl-abx500.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/pinctrl/pinctrl-abx500.c')
-rw-r--r--drivers/pinctrl/pinctrl-abx500.c481
1 files changed, 417 insertions, 64 deletions
diff --git a/drivers/pinctrl/pinctrl-abx500.c b/drivers/pinctrl/pinctrl-abx500.c
index 6d4532702f80..1d3f988c2c8b 100644
--- a/drivers/pinctrl/pinctrl-abx500.c
+++ b/drivers/pinctrl/pinctrl-abx500.c
@@ -30,8 +30,11 @@
#include <linux/pinctrl/pinmux.h>
#include <linux/pinctrl/pinconf.h>
#include <linux/pinctrl/pinconf-generic.h>
+#include <linux/pinctrl/machine.h>
#include "pinctrl-abx500.h"
+#include "core.h"
+#include "pinconf.h"
/*
* The AB9540 and AB8540 GPIO support are extended versions
@@ -93,13 +96,15 @@
#define AB8540_GPIOX_VBAT_START 51
#define AB8540_GPIOX_VBAT_END 54
+#define ABX500_GPIO_INPUT 0
+#define ABX500_GPIO_OUTPUT 1
+
struct abx500_pinctrl {
struct device *dev;
struct pinctrl_dev *pctldev;
struct abx500_pinctrl_soc_data *soc;
struct gpio_chip chip;
struct ab8500 *parent;
- struct mutex lock;
struct abx500_gpio_irq_cluster *irq_cluster;
int irq_cluster_size;
};
@@ -129,8 +134,8 @@ static int abx500_gpio_get_bit(struct gpio_chip *chip, u8 reg,
if (ret < 0)
dev_err(pct->dev,
- "%s read reg =%x, offset=%x failed\n",
- __func__, reg, offset);
+ "%s read reg =%x, offset=%x failed (%d)\n",
+ __func__, reg, offset, ret);
return ret;
}
@@ -146,7 +151,8 @@ static int abx500_gpio_set_bits(struct gpio_chip *chip, u8 reg,
ret = abx500_mask_and_set_register_interruptible(pct->dev,
AB8500_MISC, reg, BIT(pos), val << pos);
if (ret < 0)
- dev_err(pct->dev, "%s write failed\n", __func__);
+ dev_err(pct->dev, "%s write reg, %x offset %x failed (%d)\n",
+ __func__, reg, offset, ret);
return ret;
}
@@ -160,12 +166,24 @@ static int abx500_gpio_get(struct gpio_chip *chip, unsigned offset)
{
struct abx500_pinctrl *pct = to_abx500_pinctrl(chip);
bool bit;
+ bool is_out;
+ u8 gpio_offset = offset - 1;
int ret;
- ret = abx500_gpio_get_bit(chip, AB8500_GPIO_IN1_REG,
- offset, &bit);
+ ret = abx500_gpio_get_bit(chip, AB8500_GPIO_DIR1_REG,
+ gpio_offset, &is_out);
+ if (ret < 0)
+ goto out;
+
+ if (is_out)
+ ret = abx500_gpio_get_bit(chip, AB8500_GPIO_OUT1_REG,
+ gpio_offset, &bit);
+ else
+ ret = abx500_gpio_get_bit(chip, AB8500_GPIO_IN1_REG,
+ gpio_offset, &bit);
+out:
if (ret < 0) {
- dev_err(pct->dev, "%s failed\n", __func__);
+ dev_err(pct->dev, "%s failed (%d)\n", __func__, ret);
return ret;
}
@@ -179,13 +197,14 @@ static void abx500_gpio_set(struct gpio_chip *chip, unsigned offset, int val)
ret = abx500_gpio_set_bits(chip, AB8500_GPIO_OUT1_REG, offset, val);
if (ret < 0)
- dev_err(pct->dev, "%s write failed\n", __func__);
+ dev_err(pct->dev, "%s write failed (%d)\n", __func__, ret);
}
-static int abx500_config_pull_updown(struct abx500_pinctrl *pct,
- int offset, enum abx500_gpio_pull_updown val)
+static int abx500_get_pull_updown(struct abx500_pinctrl *pct, int offset,
+ enum abx500_gpio_pull_updown *pull_updown)
{
u8 pos;
+ u8 val;
int ret;
struct pullud *pullud;
@@ -204,7 +223,41 @@ static int abx500_config_pull_updown(struct abx500_pinctrl *pct,
goto out;
}
- pos = offset << 1;
+ ret = abx500_get_register_interruptible(pct->dev,
+ AB8500_MISC, AB8540_GPIO_PULL_UPDOWN_REG, &val);
+
+ pos = (offset - pullud->first_pin) << 1;
+ *pull_updown = (val >> pos) & AB8540_GPIO_PULL_UPDOWN_MASK;
+
+out:
+ if (ret < 0)
+ dev_err(pct->dev, "%s failed (%d)\n", __func__, ret);
+
+ return ret;
+}
+
+static int abx500_set_pull_updown(struct abx500_pinctrl *pct,
+ int offset, enum abx500_gpio_pull_updown val)
+{
+ u8 pos;
+ int ret;
+ struct pullud *pullud;
+
+ if (!pct->soc->pullud) {
+ dev_err(pct->dev, "%s AB chip doesn't support pull up/down feature",
+ __func__);
+ ret = -EPERM;
+ goto out;
+ }
+
+ pullud = pct->soc->pullud;
+
+ if ((offset < pullud->first_pin)
+ || (offset > pullud->last_pin)) {
+ ret = -EINVAL;
+ goto out;
+ }
+ pos = (offset - pullud->first_pin) << 1;
ret = abx500_mask_and_set_register_interruptible(pct->dev,
AB8500_MISC, AB8540_GPIO_PULL_UPDOWN_REG,
@@ -217,33 +270,51 @@ out:
return ret;
}
+static bool abx500_pullud_supported(struct gpio_chip *chip, unsigned gpio)
+{
+ struct abx500_pinctrl *pct = to_abx500_pinctrl(chip);
+ struct pullud *pullud = pct->soc->pullud;
+
+ return (pullud &&
+ gpio >= pullud->first_pin &&
+ gpio <= pullud->last_pin);
+}
+
static int abx500_gpio_direction_output(struct gpio_chip *chip,
unsigned offset,
int val)
{
struct abx500_pinctrl *pct = to_abx500_pinctrl(chip);
- struct pullud *pullud = pct->soc->pullud;
unsigned gpio;
int ret;
/* set direction as output */
- ret = abx500_gpio_set_bits(chip, AB8500_GPIO_DIR1_REG, offset, 1);
+ ret = abx500_gpio_set_bits(chip,
+ AB8500_GPIO_DIR1_REG,
+ offset,
+ ABX500_GPIO_OUTPUT);
if (ret < 0)
- return ret;
+ goto out;
/* disable pull down */
- ret = abx500_gpio_set_bits(chip, AB8500_GPIO_PUD1_REG, offset, 1);
+ ret = abx500_gpio_set_bits(chip,
+ AB8500_GPIO_PUD1_REG,
+ offset,
+ ABX500_GPIO_PULL_NONE);
if (ret < 0)
- return ret;
+ goto out;
/* if supported, disable both pull down and pull up */
gpio = offset + 1;
- if (pullud && gpio >= pullud->first_pin && gpio <= pullud->last_pin) {
- ret = abx500_config_pull_updown(pct,
+ if (abx500_pullud_supported(chip, gpio)) {
+ ret = abx500_set_pull_updown(pct,
gpio,
ABX500_GPIO_PULL_NONE);
- if (ret < 0)
- return ret;
+ }
+out:
+ if (ret < 0) {
+ dev_err(pct->dev, "%s failed (%d)\n", __func__, ret);
+ return ret;
}
/* set the output as 1 or 0 */
@@ -253,7 +324,10 @@ static int abx500_gpio_direction_output(struct gpio_chip *chip,
static int abx500_gpio_direction_input(struct gpio_chip *chip, unsigned offset)
{
/* set the register as input */
- return abx500_gpio_set_bits(chip, AB8500_GPIO_DIR1_REG, offset, 0);
+ return abx500_gpio_set_bits(chip,
+ AB8500_GPIO_DIR1_REG,
+ offset,
+ ABX500_GPIO_INPUT);
}
static int abx500_gpio_to_irq(struct gpio_chip *chip, unsigned offset)
@@ -338,10 +412,16 @@ static int abx500_set_mode(struct pinctrl_dev *pctldev, struct gpio_chip *chip,
if (af.alt_bit1 != UNUSED) {
ret = abx500_gpio_set_bits(chip, AB8500_GPIO_SEL1_REG,
offset, 0);
+ if (ret < 0)
+ goto out;
+
ret = abx500_gpio_set_bits(chip,
AB8500_GPIO_ALTFUN_REG,
af.alt_bit1,
!!(af.alta_val && BIT(0)));
+ if (ret < 0)
+ goto out;
+
if (af.alt_bit2 != UNUSED)
ret = abx500_gpio_set_bits(chip,
AB8500_GPIO_ALTFUN_REG,
@@ -355,8 +435,14 @@ static int abx500_set_mode(struct pinctrl_dev *pctldev, struct gpio_chip *chip,
case ABX500_ALT_B:
ret = abx500_gpio_set_bits(chip, AB8500_GPIO_SEL1_REG,
offset, 0);
+ if (ret < 0)
+ goto out;
+
ret = abx500_gpio_set_bits(chip, AB8500_GPIO_ALTFUN_REG,
af.alt_bit1, !!(af.altb_val && BIT(0)));
+ if (ret < 0)
+ goto out;
+
if (af.alt_bit2 != UNUSED)
ret = abx500_gpio_set_bits(chip,
AB8500_GPIO_ALTFUN_REG,
@@ -367,8 +453,14 @@ static int abx500_set_mode(struct pinctrl_dev *pctldev, struct gpio_chip *chip,
case ABX500_ALT_C:
ret = abx500_gpio_set_bits(chip, AB8500_GPIO_SEL1_REG,
offset, 0);
+ if (ret < 0)
+ goto out;
+
ret = abx500_gpio_set_bits(chip, AB8500_GPIO_ALTFUN_REG,
af.alt_bit2, !!(af.altc_val && BIT(0)));
+ if (ret < 0)
+ goto out;
+
ret = abx500_gpio_set_bits(chip, AB8500_GPIO_ALTFUN_REG,
af.alt_bit2, !!(af.altc_val && BIT(1)));
break;
@@ -378,11 +470,14 @@ static int abx500_set_mode(struct pinctrl_dev *pctldev, struct gpio_chip *chip,
return -EINVAL;
}
+out:
+ if (ret < 0)
+ dev_err(pct->dev, "%s failed (%d)\n", __func__, ret);
return ret;
}
-static u8 abx500_get_mode(struct pinctrl_dev *pctldev, struct gpio_chip *chip,
+static int abx500_get_mode(struct pinctrl_dev *pctldev, struct gpio_chip *chip,
unsigned gpio)
{
u8 mode;
@@ -393,6 +488,7 @@ static u8 abx500_get_mode(struct pinctrl_dev *pctldev, struct gpio_chip *chip,
struct alternate_functions af = pct->soc->alternate_functions[gpio];
/* on ABx5xx, there is no GPIO0, so adjust the offset */
unsigned offset = gpio - 1;
+ int ret;
/*
* if gpiosel_bit is set to unused,
@@ -402,8 +498,11 @@ static u8 abx500_get_mode(struct pinctrl_dev *pctldev, struct gpio_chip *chip,
return ABX500_DEFAULT;
/* read GpioSelx register */
- abx500_gpio_get_bit(chip, AB8500_GPIO_SEL1_REG + (offset / 8),
+ ret = abx500_gpio_get_bit(chip, AB8500_GPIO_SEL1_REG + (offset / 8),
af.gpiosel_bit, &bit_mode);
+ if (ret < 0)
+ goto out;
+
mode = bit_mode;
/* sanity check */
@@ -435,14 +534,19 @@ static u8 abx500_get_mode(struct pinctrl_dev *pctldev, struct gpio_chip *chip,
* pin use the AlternatFunction register
* read alt_bit1 value
*/
- abx500_gpio_get_bit(chip, AB8500_GPIO_ALTFUN_REG,
+ ret = abx500_gpio_get_bit(chip, AB8500_GPIO_ALTFUN_REG,
af.alt_bit1, &alt_bit1);
+ if (ret < 0)
+ goto out;
- if (af.alt_bit2 != UNUSED)
+ if (af.alt_bit2 != UNUSED) {
/* read alt_bit2 value */
- abx500_gpio_get_bit(chip, AB8500_GPIO_ALTFUN_REG, af.alt_bit2,
+ ret = abx500_gpio_get_bit(chip, AB8500_GPIO_ALTFUN_REG,
+ af.alt_bit2,
&alt_bit2);
- else
+ if (ret < 0)
+ goto out;
+ } else
alt_bit2 = 0;
mode = (alt_bit2 << 1) + alt_bit1;
@@ -452,6 +556,10 @@ static u8 abx500_get_mode(struct pinctrl_dev *pctldev, struct gpio_chip *chip,
return ABX500_ALT_B;
else
return ABX500_ALT_C;
+
+out:
+ dev_err(pct->dev, "%s failed (%d)\n", __func__, ret);
+ return ret;
}
#ifdef CONFIG_DEBUG_FS
@@ -463,11 +571,14 @@ static void abx500_gpio_dbg_show_one(struct seq_file *s,
struct gpio_chip *chip,
unsigned offset, unsigned gpio)
{
+ struct abx500_pinctrl *pct = pinctrl_dev_get_drvdata(pctldev);
const char *label = gpiochip_is_requested(chip, offset - 1);
u8 gpio_offset = offset - 1;
int mode = -1;
bool is_out;
- bool pull;
+ bool pd;
+ enum abx500_gpio_pull_updown pud = 0;
+ int ret;
const char *modes[] = {
[ABX500_DEFAULT] = "default",
@@ -476,21 +587,48 @@ static void abx500_gpio_dbg_show_one(struct seq_file *s,
[ABX500_ALT_C] = "altC",
};
- abx500_gpio_get_bit(chip, AB8500_GPIO_DIR1_REG, gpio_offset, &is_out);
- abx500_gpio_get_bit(chip, AB8500_GPIO_PUD1_REG, gpio_offset, &pull);
+ const char *pull_up_down[] = {
+ [ABX500_GPIO_PULL_DOWN] = "pull down",
+ [ABX500_GPIO_PULL_NONE] = "pull none",
+ [ABX500_GPIO_PULL_NONE + 1] = "pull none",
+ [ABX500_GPIO_PULL_UP] = "pull up",
+ };
+
+ ret = abx500_gpio_get_bit(chip, AB8500_GPIO_DIR1_REG,
+ gpio_offset, &is_out);
+ if (ret < 0)
+ goto out;
+
+ seq_printf(s, " gpio-%-3d (%-20.20s) %-3s",
+ gpio, label ?: "(none)",
+ is_out ? "out" : "in ");
+
+ if (!is_out) {
+ if (abx500_pullud_supported(chip, offset)) {
+ ret = abx500_get_pull_updown(pct, offset, &pud);
+ if (ret < 0)
+ goto out;
+
+ seq_printf(s, " %-9s", pull_up_down[pud]);
+ } else {
+ ret = abx500_gpio_get_bit(chip, AB8500_GPIO_PUD1_REG,
+ gpio_offset, &pd);
+ if (ret < 0)
+ goto out;
+
+ seq_printf(s, " %-9s", pull_up_down[pd]);
+ }
+ } else
+ seq_printf(s, " %-9s", chip->get(chip, offset) ? "hi" : "lo");
if (pctldev)
mode = abx500_get_mode(pctldev, chip, offset);
- seq_printf(s, " gpio-%-3d (%-20.20s) %-3s %-9s %s",
- gpio, label ?: "(none)",
- is_out ? "out" : "in ",
- is_out ?
- (chip->get
- ? (chip->get(chip, offset) ? "hi" : "lo")
- : "? ")
- : (pull ? "pull up" : "pull down"),
- (mode < 0) ? "unknown" : modes[mode]);
+ seq_printf(s, " %s", (mode < 0) ? "unknown" : modes[mode]);
+
+out:
+ if (ret < 0)
+ dev_err(pct->dev, "%s failed (%d)\n", __func__, ret);
}
static void abx500_gpio_dbg_show(struct seq_file *s, struct gpio_chip *chip)
@@ -594,6 +732,9 @@ static int abx500_pmx_enable(struct pinctrl_dev *pctldev, unsigned function,
ret = abx500_set_mode(pctldev, chip, g->pins[i], g->altsetting);
}
+ if (ret < 0)
+ dev_err(pct->dev, "%s failed (%d)\n", __func__, ret);
+
return ret;
}
@@ -642,10 +783,8 @@ static int abx500_gpio_request_enable(struct pinctrl_dev *pctldev,
ret = abx500_set_mode(pct->pctldev, &pct->chip,
offset, p->altfunc);
- if (ret < 0) {
+ if (ret < 0)
dev_err(pct->dev, "%s setting altfunc failed\n", __func__);
- return ret;
- }
return ret;
}
@@ -704,11 +843,193 @@ static void abx500_pin_dbg_show(struct pinctrl_dev *pctldev,
chip->base + offset - 1);
}
+static void abx500_dt_free_map(struct pinctrl_dev *pctldev,
+ struct pinctrl_map *map, unsigned num_maps)
+{
+ int i;
+
+ for (i = 0; i < num_maps; i++)
+ if (map[i].type == PIN_MAP_TYPE_CONFIGS_PIN)
+ kfree(map[i].data.configs.configs);
+ kfree(map);
+}
+
+static int abx500_dt_reserve_map(struct pinctrl_map **map,
+ unsigned *reserved_maps,
+ unsigned *num_maps,
+ unsigned reserve)
+{
+ unsigned old_num = *reserved_maps;
+ unsigned new_num = *num_maps + reserve;
+ struct pinctrl_map *new_map;
+
+ if (old_num >= new_num)
+ return 0;
+
+ new_map = krealloc(*map, sizeof(*new_map) * new_num, GFP_KERNEL);
+ if (!new_map)
+ return -ENOMEM;
+
+ memset(new_map + old_num, 0, (new_num - old_num) * sizeof(*new_map));
+
+ *map = new_map;
+ *reserved_maps = new_num;
+
+ return 0;
+}
+
+static int abx500_dt_add_map_mux(struct pinctrl_map **map,
+ unsigned *reserved_maps,
+ unsigned *num_maps, const char *group,
+ const char *function)
+{
+ if (*num_maps == *reserved_maps)
+ return -ENOSPC;
+
+ (*map)[*num_maps].type = PIN_MAP_TYPE_MUX_GROUP;
+ (*map)[*num_maps].data.mux.group = group;
+ (*map)[*num_maps].data.mux.function = function;
+ (*num_maps)++;
+
+ return 0;
+}
+
+static int abx500_dt_add_map_configs(struct pinctrl_map **map,
+ unsigned *reserved_maps,
+ unsigned *num_maps, const char *group,
+ unsigned long *configs, unsigned num_configs)
+{
+ unsigned long *dup_configs;
+
+ if (*num_maps == *reserved_maps)
+ return -ENOSPC;
+
+ dup_configs = kmemdup(configs, num_configs * sizeof(*dup_configs),
+ GFP_KERNEL);
+ if (!dup_configs)
+ return -ENOMEM;
+
+ (*map)[*num_maps].type = PIN_MAP_TYPE_CONFIGS_PIN;
+
+ (*map)[*num_maps].data.configs.group_or_pin = group;
+ (*map)[*num_maps].data.configs.configs = dup_configs;
+ (*map)[*num_maps].data.configs.num_configs = num_configs;
+ (*num_maps)++;
+
+ return 0;
+}
+
+static const char *abx500_find_pin_name(struct pinctrl_dev *pctldev,
+ const char *pin_name)
+{
+ int i, pin_number;
+ struct abx500_pinctrl *npct = pinctrl_dev_get_drvdata(pctldev);
+
+ if (sscanf((char *)pin_name, "GPIO%d", &pin_number) == 1)
+ for (i = 0; i < npct->soc->npins; i++)
+ if (npct->soc->pins[i].number == pin_number)
+ return npct->soc->pins[i].name;
+ return NULL;
+}
+
+static int abx500_dt_subnode_to_map(struct pinctrl_dev *pctldev,
+ struct device_node *np,
+ struct pinctrl_map **map,
+ unsigned *reserved_maps,
+ unsigned *num_maps)
+{
+ int ret;
+ const char *function = NULL;
+ unsigned long *configs;
+ unsigned int nconfigs = 0;
+ bool has_config = 0;
+ unsigned reserve = 0;
+ struct property *prop;
+ const char *group, *gpio_name;
+ struct device_node *np_config;
+
+ ret = of_property_read_string(np, "ste,function", &function);
+ if (ret >= 0)
+ reserve = 1;
+
+ ret = pinconf_generic_parse_dt_config(np, &configs, &nconfigs);
+ if (nconfigs)
+ has_config = 1;
+
+ np_config = of_parse_phandle(np, "ste,config", 0);
+ if (np_config) {
+ ret = pinconf_generic_parse_dt_config(np_config, &configs,
+ &nconfigs);
+ if (ret)
+ goto exit;
+ has_config |= nconfigs;
+ }
+
+ ret = of_property_count_strings(np, "ste,pins");
+ if (ret < 0)
+ goto exit;
+
+ if (has_config)
+ reserve++;
+
+ reserve *= ret;
+
+ ret = abx500_dt_reserve_map(map, reserved_maps, num_maps, reserve);
+ if (ret < 0)
+ goto exit;
+
+ of_property_for_each_string(np, "ste,pins", prop, group) {
+ if (function) {
+ ret = abx500_dt_add_map_mux(map, reserved_maps,
+ num_maps, group, function);
+ if (ret < 0)
+ goto exit;
+ }
+ if (has_config) {
+ gpio_name = abx500_find_pin_name(pctldev, group);
+
+ ret = abx500_dt_add_map_configs(map, reserved_maps,
+ num_maps, gpio_name, configs, 1);
+ if (ret < 0)
+ goto exit;
+ }
+
+ }
+exit:
+ return ret;
+}
+
+static int abx500_dt_node_to_map(struct pinctrl_dev *pctldev,
+ struct device_node *np_config,
+ struct pinctrl_map **map, unsigned *num_maps)
+{
+ unsigned reserved_maps;
+ struct device_node *np;
+ int ret;
+
+ reserved_maps = 0;
+ *map = NULL;
+ *num_maps = 0;
+
+ for_each_child_of_node(np_config, np) {
+ ret = abx500_dt_subnode_to_map(pctldev, np, map,
+ &reserved_maps, num_maps);
+ if (ret < 0) {
+ abx500_dt_free_map(pctldev, *map, *num_maps);
+ return ret;
+ }
+ }
+
+ return 0;
+}
+
static const struct pinctrl_ops abx500_pinctrl_ops = {
.get_groups_count = abx500_get_groups_cnt,
.get_group_name = abx500_get_group_name,
.get_group_pins = abx500_get_group_pins,
.pin_dbg_show = abx500_pin_dbg_show,
+ .dt_node_to_map = abx500_dt_node_to_map,
+ .dt_free_map = abx500_dt_free_map,
};
static int abx500_pin_config_get(struct pinctrl_dev *pctldev,
@@ -723,10 +1044,9 @@ static int abx500_pin_config_set(struct pinctrl_dev *pctldev,
unsigned long config)
{
struct abx500_pinctrl *pct = pinctrl_dev_get_drvdata(pctldev);
- struct pullud *pullud = pct->soc->pullud;
struct gpio_chip *chip = &pct->chip;
unsigned offset;
- int ret;
+ int ret = -EINVAL;
enum pin_config_param param = pinconf_to_config_param(config);
enum pin_config_param argument = pinconf_to_config_argument(config);
@@ -739,41 +1059,83 @@ static int abx500_pin_config_set(struct pinctrl_dev *pctldev,
offset = pin - 1;
switch (param) {
- case PIN_CONFIG_BIAS_PULL_DOWN:
+ case PIN_CONFIG_BIAS_DISABLE:
+ ret = abx500_gpio_direction_input(chip, offset);
+ if (ret < 0)
+ goto out;
/*
- * if argument = 1 set the pull down
- * else clear the pull down
+ * Some chips only support pull down, while some actually
+ * support both pull up and pull down. Such chips have
+ * a "pullud" range specified for the pins that support
+ * both features. If the pin is not within that range, we
+ * fall back to the old bit set that only support pull down.
*/
+ if (abx500_pullud_supported(chip, pin))
+ ret = abx500_set_pull_updown(pct,
+ pin,
+ ABX500_GPIO_PULL_NONE);
+ else
+ /* Chip only supports pull down */
+ ret = abx500_gpio_set_bits(chip, AB8500_GPIO_PUD1_REG,
+ offset, ABX500_GPIO_PULL_NONE);
+ break;
+
+ case PIN_CONFIG_BIAS_PULL_DOWN:
ret = abx500_gpio_direction_input(chip, offset);
+ if (ret < 0)
+ goto out;
/*
+ * if argument = 1 set the pull down
+ * else clear the pull down
* Some chips only support pull down, while some actually
* support both pull up and pull down. Such chips have
* a "pullud" range specified for the pins that support
* both features. If the pin is not within that range, we
* fall back to the old bit set that only support pull down.
*/
- if (pullud &&
- pin >= pullud->first_pin &&
- pin <= pullud->last_pin)
- ret = abx500_config_pull_updown(pct,
+ if (abx500_pullud_supported(chip, pin))
+ ret = abx500_set_pull_updown(pct,
pin,
argument ? ABX500_GPIO_PULL_DOWN : ABX500_GPIO_PULL_NONE);
else
/* Chip only supports pull down */
ret = abx500_gpio_set_bits(chip, AB8500_GPIO_PUD1_REG,
- offset, argument ? 0 : 1);
+ offset,
+ argument ? ABX500_GPIO_PULL_DOWN : ABX500_GPIO_PULL_NONE);
+ break;
+
+ case PIN_CONFIG_BIAS_PULL_UP:
+ ret = abx500_gpio_direction_input(chip, offset);
+ if (ret < 0)
+ goto out;
+ /*
+ * if argument = 1 set the pull up
+ * else clear the pull up
+ */
+ ret = abx500_gpio_direction_input(chip, offset);
+ /*
+ * Some chips only support pull down, while some actually
+ * support both pull up and pull down. Such chips have
+ * a "pullud" range specified for the pins that support
+ * both features. If the pin is not within that range, do
+ * nothing
+ */
+ if (abx500_pullud_supported(chip, pin))
+ ret = abx500_set_pull_updown(pct,
+ pin,
+ argument ? ABX500_GPIO_PULL_UP : ABX500_GPIO_PULL_NONE);
break;
case PIN_CONFIG_OUTPUT:
ret = abx500_gpio_direction_output(chip, offset, argument);
-
break;
default:
dev_err(chip->dev, "illegal configuration requested\n");
-
- return -EINVAL;
}
+out:
+ if (ret < 0)
+ dev_err(pct->dev, "%s failed (%d)\n", __func__, ret);
return ret;
}
@@ -881,9 +1243,6 @@ static int abx500_gpio_probe(struct platform_device *pdev)
id = (unsigned long)match->data;
}
- /* initialize the lock */
- mutex_init(&pct->lock);
-
/* Poke in other ASIC variants here */
switch (id) {
case PINCTRL_AB8500:
@@ -900,13 +1259,11 @@ static int abx500_gpio_probe(struct platform_device *pdev)
break;
default:
dev_err(&pdev->dev, "Unsupported pinctrl sub driver (%d)\n", id);
- mutex_destroy(&pct->lock);
return -EINVAL;
}
if (!pct->soc) {
dev_err(&pdev->dev, "Invalid SOC data\n");
- mutex_destroy(&pct->lock);
return -EINVAL;
}
@@ -917,7 +1274,6 @@ static int abx500_gpio_probe(struct platform_device *pdev)
ret = gpiochip_add(&pct->chip);
if (ret) {
dev_err(&pdev->dev, "unable to add gpiochip: %d\n", ret);
- mutex_destroy(&pct->lock);
return ret;
}
dev_info(&pdev->dev, "added gpiochip\n");
@@ -954,7 +1310,6 @@ out_rem_chip:
if (err)
dev_info(&pdev->dev, "failed to remove gpiochip\n");
- mutex_destroy(&pct->lock);
return ret;
}
@@ -974,8 +1329,6 @@ static int abx500_gpio_remove(struct platform_device *pdev)
return ret;
}
- mutex_destroy(&pct->lock);
-
return 0;
}