|
@@ -105,6 +105,14 @@ static const struct pinctrl_ops msm_pinctrl_ops = {
|
|
|
.dt_free_map = pinctrl_utils_free_map,
|
|
|
};
|
|
|
|
|
|
+static int msm_pinmux_request(struct pinctrl_dev *pctldev, unsigned offset)
|
|
|
+{
|
|
|
+ struct msm_pinctrl *pctrl = pinctrl_dev_get_drvdata(pctldev);
|
|
|
+ struct gpio_chip *chip = &pctrl->chip;
|
|
|
+
|
|
|
+ return gpiochip_line_is_valid(chip, offset) ? 0 : -EINVAL;
|
|
|
+}
|
|
|
+
|
|
|
static int msm_get_functions_count(struct pinctrl_dev *pctldev)
|
|
|
{
|
|
|
struct msm_pinctrl *pctrl = pinctrl_dev_get_drvdata(pctldev);
|
|
@@ -166,6 +174,7 @@ static int msm_pinmux_set_mux(struct pinctrl_dev *pctldev,
|
|
|
}
|
|
|
|
|
|
static const struct pinmux_ops msm_pinmux_ops = {
|
|
|
+ .request = msm_pinmux_request,
|
|
|
.get_functions_count = msm_get_functions_count,
|
|
|
.get_function_name = msm_get_function_name,
|
|
|
.get_function_groups = msm_get_function_groups,
|
|
@@ -506,6 +515,9 @@ static void msm_gpio_dbg_show_one(struct seq_file *s,
|
|
|
"pull up"
|
|
|
};
|
|
|
|
|
|
+ if (!gpiochip_line_is_valid(chip, offset))
|
|
|
+ return;
|
|
|
+
|
|
|
g = &pctrl->soc->groups[offset];
|
|
|
ctl_reg = readl(pctrl->regs + g->ctl_reg);
|
|
|
|
|
@@ -517,6 +529,7 @@ static void msm_gpio_dbg_show_one(struct seq_file *s,
|
|
|
seq_printf(s, " %-8s: %-3s %d", g->name, is_out ? "out" : "in", func);
|
|
|
seq_printf(s, " %dmA", msm_regval_to_drive(drive));
|
|
|
seq_printf(s, " %s", pulls[pull]);
|
|
|
+ seq_puts(s, "\n");
|
|
|
}
|
|
|
|
|
|
static void msm_gpio_dbg_show(struct seq_file *s, struct gpio_chip *chip)
|
|
@@ -524,10 +537,8 @@ static void msm_gpio_dbg_show(struct seq_file *s, struct gpio_chip *chip)
|
|
|
unsigned gpio = chip->base;
|
|
|
unsigned i;
|
|
|
|
|
|
- for (i = 0; i < chip->ngpio; i++, gpio++) {
|
|
|
+ for (i = 0; i < chip->ngpio; i++, gpio++)
|
|
|
msm_gpio_dbg_show_one(s, NULL, chip, i, gpio);
|
|
|
- seq_puts(s, "\n");
|
|
|
- }
|
|
|
}
|
|
|
|
|
|
#else
|
|
@@ -808,6 +819,46 @@ static void msm_gpio_irq_handler(struct irq_desc *desc)
|
|
|
chained_irq_exit(chip, desc);
|
|
|
}
|
|
|
|
|
|
+static int msm_gpio_init_valid_mask(struct gpio_chip *chip,
|
|
|
+ struct msm_pinctrl *pctrl)
|
|
|
+{
|
|
|
+ int ret;
|
|
|
+ unsigned int len, i;
|
|
|
+ unsigned int max_gpios = pctrl->soc->ngpios;
|
|
|
+ u16 *tmp;
|
|
|
+
|
|
|
+ /* The number of GPIOs in the ACPI tables */
|
|
|
+ len = ret = device_property_read_u16_array(pctrl->dev, "gpios", NULL, 0);
|
|
|
+ if (ret < 0)
|
|
|
+ return 0;
|
|
|
+
|
|
|
+ if (ret > max_gpios)
|
|
|
+ return -EINVAL;
|
|
|
+
|
|
|
+ tmp = kmalloc_array(len, sizeof(*tmp), GFP_KERNEL);
|
|
|
+ if (!tmp)
|
|
|
+ return -ENOMEM;
|
|
|
+
|
|
|
+ ret = device_property_read_u16_array(pctrl->dev, "gpios", tmp, len);
|
|
|
+ if (ret < 0) {
|
|
|
+ dev_err(pctrl->dev, "could not read list of GPIOs\n");
|
|
|
+ goto out;
|
|
|
+ }
|
|
|
+
|
|
|
+ bitmap_zero(chip->valid_mask, max_gpios);
|
|
|
+ for (i = 0; i < len; i++)
|
|
|
+ set_bit(tmp[i], chip->valid_mask);
|
|
|
+
|
|
|
+out:
|
|
|
+ kfree(tmp);
|
|
|
+ return ret;
|
|
|
+}
|
|
|
+
|
|
|
+static bool msm_gpio_needs_valid_mask(struct msm_pinctrl *pctrl)
|
|
|
+{
|
|
|
+ return device_property_read_u16_array(pctrl->dev, "gpios", NULL, 0) > 0;
|
|
|
+}
|
|
|
+
|
|
|
static int msm_gpio_init(struct msm_pinctrl *pctrl)
|
|
|
{
|
|
|
struct gpio_chip *chip;
|
|
@@ -824,6 +875,7 @@ static int msm_gpio_init(struct msm_pinctrl *pctrl)
|
|
|
chip->parent = pctrl->dev;
|
|
|
chip->owner = THIS_MODULE;
|
|
|
chip->of_node = pctrl->dev->of_node;
|
|
|
+ chip->need_valid_mask = msm_gpio_needs_valid_mask(pctrl);
|
|
|
|
|
|
ret = gpiochip_add_data(&pctrl->chip, pctrl);
|
|
|
if (ret) {
|
|
@@ -831,6 +883,13 @@ static int msm_gpio_init(struct msm_pinctrl *pctrl)
|
|
|
return ret;
|
|
|
}
|
|
|
|
|
|
+ ret = msm_gpio_init_valid_mask(chip, pctrl);
|
|
|
+ if (ret) {
|
|
|
+ dev_err(pctrl->dev, "Failed to setup irq valid bits\n");
|
|
|
+ gpiochip_remove(&pctrl->chip);
|
|
|
+ return ret;
|
|
|
+ }
|
|
|
+
|
|
|
ret = gpiochip_add_pin_range(&pctrl->chip, dev_name(pctrl->dev), 0, 0, chip->ngpio);
|
|
|
if (ret) {
|
|
|
dev_err(pctrl->dev, "Failed to add pin range\n");
|