summaryrefslogtreecommitdiff
path: root/drivers/pinctrl/pinctrl-at91-pio4.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/pinctrl/pinctrl-at91-pio4.c')
-rw-r--r--drivers/pinctrl/pinctrl-at91-pio4.c165
1 files changed, 95 insertions, 70 deletions
diff --git a/drivers/pinctrl/pinctrl-at91-pio4.c b/drivers/pinctrl/pinctrl-at91-pio4.c
index fafd1f55cba7..ec5351fc282e 100644
--- a/drivers/pinctrl/pinctrl-at91-pio4.c
+++ b/drivers/pinctrl/pinctrl-at91-pio4.c
@@ -7,18 +7,22 @@
*/
#include <dt-bindings/pinctrl/at91.h>
+
#include <linux/clk.h>
#include <linux/gpio/driver.h>
+#include <linux/init.h>
#include <linux/interrupt.h>
#include <linux/io.h>
-#include <linux/init.h>
#include <linux/of.h>
#include <linux/platform_device.h>
-#include <linux/pinctrl/pinconf.h>
+#include <linux/seq_file.h>
+#include <linux/slab.h>
+
#include <linux/pinctrl/pinconf-generic.h>
+#include <linux/pinctrl/pinconf.h>
#include <linux/pinctrl/pinctrl.h>
#include <linux/pinctrl/pinmux.h>
-#include <linux/slab.h>
+
#include "core.h"
#include "pinconf.h"
#include "pinctrl-utils.h"
@@ -237,8 +241,6 @@ static void atmel_gpio_irq_unmask(struct irq_data *d)
BIT(pin->line));
}
-#ifdef CONFIG_PM_SLEEP
-
static int atmel_gpio_irq_set_wake(struct irq_data *d, unsigned int on)
{
struct atmel_pioctrl *atmel_pioctrl = irq_data_get_irq_chip_data(d);
@@ -255,9 +257,6 @@ static int atmel_gpio_irq_set_wake(struct irq_data *d, unsigned int on)
return 0;
}
-#else
-#define atmel_gpio_irq_set_wake NULL
-#endif /* CONFIG_PM_SLEEP */
static struct irq_chip atmel_gpio_irq_chip = {
.name = "GPIO",
@@ -265,7 +264,7 @@ static struct irq_chip atmel_gpio_irq_chip = {
.irq_mask = atmel_gpio_irq_mask,
.irq_unmask = atmel_gpio_irq_unmask,
.irq_set_type = atmel_gpio_irq_set_type,
- .irq_set_wake = atmel_gpio_irq_set_wake,
+ .irq_set_wake = pm_sleep_ptr(atmel_gpio_irq_set_wake),
};
static int atmel_gpio_to_irq(struct gpio_chip *chip, unsigned int offset)
@@ -391,7 +390,7 @@ static int atmel_gpio_direction_output(struct gpio_chip *chip,
return 0;
}
-static void atmel_gpio_set(struct gpio_chip *chip, unsigned int offset, int val)
+static int atmel_gpio_set(struct gpio_chip *chip, unsigned int offset, int val)
{
struct atmel_pioctrl *atmel_pioctrl = gpiochip_get_data(chip);
struct atmel_pin *pin = atmel_pioctrl->pins[offset];
@@ -399,10 +398,12 @@ static void atmel_gpio_set(struct gpio_chip *chip, unsigned int offset, int val)
atmel_gpio_write(atmel_pioctrl, pin->bank,
val ? ATMEL_PIO_SODR : ATMEL_PIO_CODR,
BIT(pin->line));
+
+ return 0;
}
-static void atmel_gpio_set_multiple(struct gpio_chip *chip, unsigned long *mask,
- unsigned long *bits)
+static int atmel_gpio_set_multiple(struct gpio_chip *chip, unsigned long *mask,
+ unsigned long *bits)
{
struct atmel_pioctrl *atmel_pioctrl = gpiochip_get_data(chip);
unsigned int bank;
@@ -432,6 +433,8 @@ static void atmel_gpio_set_multiple(struct gpio_chip *chip, unsigned long *mask,
bits[word] >>= ATMEL_PIO_NPINS_PER_BANK;
#endif
}
+
+ return 0;
}
static struct gpio_chip atmel_gpio_chip = {
@@ -610,8 +613,10 @@ static int atmel_pctl_dt_subnode_to_map(struct pinctrl_dev *pctldev,
if (ret)
goto exit;
- pinctrl_utils_add_map_mux(pctldev, map, reserved_maps, num_maps,
+ ret = pinctrl_utils_add_map_mux(pctldev, map, reserved_maps, num_maps,
group, func);
+ if (ret)
+ goto exit;
if (num_configs) {
ret = pinctrl_utils_add_map_configs(pctldev, map,
@@ -633,7 +638,6 @@ static int atmel_pctl_dt_node_to_map(struct pinctrl_dev *pctldev,
struct pinctrl_map **map,
unsigned int *num_maps)
{
- struct device_node *np;
unsigned int reserved_maps;
int ret;
@@ -649,13 +653,11 @@ static int atmel_pctl_dt_node_to_map(struct pinctrl_dev *pctldev,
ret = atmel_pctl_dt_subnode_to_map(pctldev, np_config, map,
&reserved_maps, num_maps);
if (ret) {
- for_each_child_of_node(np_config, np) {
+ for_each_child_of_node_scoped(np_config, np) {
ret = atmel_pctl_dt_subnode_to_map(pctldev, np, map,
&reserved_maps, num_maps);
- if (ret < 0) {
- of_node_put(np);
+ if (ret < 0)
break;
- }
}
}
@@ -763,6 +765,11 @@ static int atmel_conf_pin_config_group_get(struct pinctrl_dev *pctldev,
return -EINVAL;
arg = 1;
break;
+ case PIN_CONFIG_DRIVE_PUSH_PULL:
+ if (res & ATMEL_PIO_OPD_MASK)
+ return -EINVAL;
+ arg = 1;
+ break;
case PIN_CONFIG_INPUT_SCHMITT_ENABLE:
if (!(res & ATMEL_PIO_SCHMITT_MASK))
return -EINVAL;
@@ -780,6 +787,8 @@ static int atmel_conf_pin_config_group_get(struct pinctrl_dev *pctldev,
return -EINVAL;
arg = (res & ATMEL_PIO_DRVSTR_MASK) >> ATMEL_PIO_DRVSTR_OFFSET;
break;
+ case PIN_CONFIG_PERSIST_STATE:
+ return -ENOTSUPP;
default:
return -ENOTSUPP;
}
@@ -826,10 +835,10 @@ static int atmel_conf_pin_config_group_set(struct pinctrl_dev *pctldev,
conf &= (~ATMEL_PIO_PUEN_MASK);
break;
case PIN_CONFIG_DRIVE_OPEN_DRAIN:
- if (arg == 0)
- conf &= (~ATMEL_PIO_OPD_MASK);
- else
- conf |= ATMEL_PIO_OPD_MASK;
+ conf |= ATMEL_PIO_OPD_MASK;
+ break;
+ case PIN_CONFIG_DRIVE_PUSH_PULL:
+ conf &= ~ATMEL_PIO_OPD_MASK;
break;
case PIN_CONFIG_INPUT_SCHMITT_ENABLE:
if (arg == 0)
@@ -853,7 +862,7 @@ static int atmel_conf_pin_config_group_set(struct pinctrl_dev *pctldev,
conf |= ATMEL_PIO_IFSCEN_MASK;
}
break;
- case PIN_CONFIG_OUTPUT:
+ case PIN_CONFIG_LEVEL:
conf |= ATMEL_PIO_DIR_MASK;
bank = ATMEL_PIO_BANK(pin_id);
pin = ATMEL_PIO_LINE(pin_id);
@@ -888,6 +897,8 @@ static int atmel_conf_pin_config_group_set(struct pinctrl_dev *pctldev,
dev_warn(pctldev->dev, "drive strength not updated (incorrect value)\n");
}
break;
+ case PIN_CONFIG_PERSIST_STATE:
+ return -ENOTSUPP;
default:
dev_warn(pctldev->dev,
"unsupported configuration parameter: %u\n",
@@ -902,6 +913,25 @@ static int atmel_conf_pin_config_group_set(struct pinctrl_dev *pctldev,
return 0;
}
+static int atmel_conf_pin_config_set(struct pinctrl_dev *pctldev,
+ unsigned pin,
+ unsigned long *configs,
+ unsigned num_configs)
+{
+ struct atmel_group *grp = atmel_pctl_find_group_by_pin(pctldev, pin);
+
+ return atmel_conf_pin_config_group_set(pctldev, grp->pin, configs, num_configs);
+}
+
+static int atmel_conf_pin_config_get(struct pinctrl_dev *pctldev,
+ unsigned pin,
+ unsigned long *configs)
+{
+ struct atmel_group *grp = atmel_pctl_find_group_by_pin(pctldev, pin);
+
+ return atmel_conf_pin_config_group_get(pctldev, grp->pin, configs);
+}
+
static void atmel_conf_pin_config_dbg_show(struct pinctrl_dev *pctldev,
struct seq_file *s,
unsigned int pin_id)
@@ -912,10 +942,9 @@ static void atmel_conf_pin_config_dbg_show(struct pinctrl_dev *pctldev,
if (!atmel_pioctrl->pins[pin_id]->device)
return;
- if (atmel_pioctrl->pins[pin_id])
- seq_printf(s, " (%s, ioset %u) ",
- atmel_pioctrl->pins[pin_id]->device,
- atmel_pioctrl->pins[pin_id]->ioset);
+ seq_printf(s, " (%s, ioset %u) ",
+ atmel_pioctrl->pins[pin_id]->device,
+ atmel_pioctrl->pins[pin_id]->ioset);
conf = atmel_pin_config_read(pctldev, pin_id);
if (conf & ATMEL_PIO_PUEN_MASK)
@@ -926,6 +955,8 @@ static void atmel_conf_pin_config_dbg_show(struct pinctrl_dev *pctldev,
seq_printf(s, "%s ", "debounce");
if (conf & ATMEL_PIO_OPD_MASK)
seq_printf(s, "%s ", "open-drain");
+ else
+ seq_printf(s, "%s ", "push-pull");
if (conf & ATMEL_PIO_SCHMITT_MASK)
seq_printf(s, "%s ", "schmitt");
if (atmel_pioctrl->slew_rate_support && (conf & ATMEL_PIO_SR_MASK))
@@ -949,6 +980,8 @@ static const struct pinconf_ops atmel_confops = {
.pin_config_group_get = atmel_conf_pin_config_group_get,
.pin_config_group_set = atmel_conf_pin_config_group_set,
.pin_config_dbg_show = atmel_conf_pin_config_dbg_show,
+ .pin_config_set = atmel_conf_pin_config_set,
+ .pin_config_get = atmel_conf_pin_config_get,
};
static struct pinctrl_desc atmel_pinctrl_desc = {
@@ -1038,14 +1071,19 @@ static const struct of_device_id atmel_pctrl_of_match[] = {
}
};
+/*
+ * This lock class allows to tell lockdep that parent IRQ and children IRQ do
+ * not share the same class so it does not raise false positive
+ */
+static struct lock_class_key atmel_lock_key;
+static struct lock_class_key atmel_request_key;
+
static int atmel_pinctrl_probe(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
struct pinctrl_pin_desc *pin_desc;
const char **group_names;
- const struct of_device_id *match;
int i, ret;
- struct resource *res;
struct atmel_pioctrl *atmel_pioctrl;
const struct atmel_pioctrl_data *atmel_pioctrl_data;
@@ -1056,12 +1094,10 @@ static int atmel_pinctrl_probe(struct platform_device *pdev)
atmel_pioctrl->node = dev->of_node;
platform_set_drvdata(pdev, atmel_pioctrl);
- match = of_match_node(atmel_pctrl_of_match, dev->of_node);
- if (!match) {
- dev_err(dev, "unknown compatible string\n");
- return -ENODEV;
- }
- atmel_pioctrl_data = match->data;
+ atmel_pioctrl_data = device_get_match_data(dev);
+ if (!atmel_pioctrl_data)
+ return dev_err_probe(dev, -ENODEV, "Invalid device data\n");
+
atmel_pioctrl->nbanks = atmel_pioctrl_data->nbanks;
atmel_pioctrl->npins = atmel_pioctrl->nbanks * ATMEL_PIO_NPINS_PER_BANK;
/* if last bank has limited number of pins, adjust accordingly */
@@ -1075,11 +1111,9 @@ static int atmel_pinctrl_probe(struct platform_device *pdev)
if (IS_ERR(atmel_pioctrl->reg_base))
return PTR_ERR(atmel_pioctrl->reg_base);
- atmel_pioctrl->clk = devm_clk_get(dev, NULL);
- if (IS_ERR(atmel_pioctrl->clk)) {
- dev_err(dev, "failed to get clock\n");
- return PTR_ERR(atmel_pioctrl->clk);
- }
+ atmel_pioctrl->clk = devm_clk_get_enabled(dev, NULL);
+ if (IS_ERR(atmel_pioctrl->clk))
+ return dev_err_probe(dev, PTR_ERR(atmel_pioctrl->clk), "failed to get clock\n");
atmel_pioctrl->pins = devm_kcalloc(dev,
atmel_pioctrl->npins,
@@ -1126,8 +1160,10 @@ static int atmel_pinctrl_probe(struct platform_device *pdev)
pin_desc[i].number = i;
/* Pin naming convention: P(bank_name)(bank_pin_number). */
- pin_desc[i].name = kasprintf(GFP_KERNEL, "P%c%d",
- bank + 'A', line);
+ pin_desc[i].name = devm_kasprintf(&pdev->dev, GFP_KERNEL, "P%c%u",
+ bank + 'A', line);
+ if (!pin_desc[i].name)
+ return -ENOMEM;
group->name = group_names[i] = pin_desc[i].name;
group->pin = pin_desc[i].number;
@@ -1140,6 +1176,7 @@ static int atmel_pinctrl_probe(struct platform_device *pdev)
atmel_pioctrl->gpio_chip->label = dev_name(dev);
atmel_pioctrl->gpio_chip->parent = dev;
atmel_pioctrl->gpio_chip->names = atmel_pioctrl->group_names;
+ atmel_pioctrl->gpio_chip->set_config = gpiochip_generic_config;
atmel_pioctrl->pm_wakeup_sources = devm_kcalloc(dev,
atmel_pioctrl->nbanks,
@@ -1164,26 +1201,22 @@ static int atmel_pinctrl_probe(struct platform_device *pdev)
/* There is one controller but each bank has its own irq line. */
for (i = 0; i < atmel_pioctrl->nbanks; i++) {
- res = platform_get_resource(pdev, IORESOURCE_IRQ, i);
- if (!res) {
- dev_err(dev, "missing irq resource for group %c\n",
+ ret = platform_get_irq(pdev, i);
+ if (ret < 0) {
+ dev_dbg(dev, "missing irq resource for group %c\n",
'A' + i);
- return -EINVAL;
+ return ret;
}
- atmel_pioctrl->irqs[i] = res->start;
- irq_set_chained_handler_and_data(res->start,
- atmel_gpio_irq_handler, atmel_pioctrl);
- dev_dbg(dev, "bank %i: irq=%pr\n", i, res);
+ atmel_pioctrl->irqs[i] = ret;
+ irq_set_chained_handler_and_data(ret, atmel_gpio_irq_handler, atmel_pioctrl);
+ dev_dbg(dev, "bank %i: irq=%d\n", i, ret);
}
- atmel_pioctrl->irq_domain = irq_domain_add_linear(dev->of_node,
- atmel_pioctrl->gpio_chip->ngpio,
- &irq_domain_simple_ops, NULL);
- if (!atmel_pioctrl->irq_domain) {
- dev_err(dev, "can't add the irq domain\n");
- return -ENODEV;
- }
- atmel_pioctrl->irq_domain->name = "atmel gpio";
+ atmel_pioctrl->irq_domain = irq_domain_create_linear(dev_fwnode(dev),
+ atmel_pioctrl->gpio_chip->ngpio,
+ &irq_domain_simple_ops, NULL);
+ if (!atmel_pioctrl->irq_domain)
+ return dev_err_probe(dev, -ENODEV, "can't add the irq domain\n");
for (i = 0; i < atmel_pioctrl->npins; i++) {
int irq = irq_create_mapping(atmel_pioctrl->irq_domain, i);
@@ -1191,30 +1224,25 @@ static int atmel_pinctrl_probe(struct platform_device *pdev)
irq_set_chip_and_handler(irq, &atmel_gpio_irq_chip,
handle_simple_irq);
irq_set_chip_data(irq, atmel_pioctrl);
+ irq_set_lockdep_class(irq, &atmel_lock_key, &atmel_request_key);
dev_dbg(dev,
"atmel gpio irq domain: hwirq: %d, linux irq: %d\n",
i, irq);
}
- ret = clk_prepare_enable(atmel_pioctrl->clk);
- if (ret) {
- dev_err(dev, "failed to prepare and enable clock\n");
- goto clk_prepare_enable_error;
- }
-
atmel_pioctrl->pinctrl_dev = devm_pinctrl_register(&pdev->dev,
&atmel_pinctrl_desc,
atmel_pioctrl);
if (IS_ERR(atmel_pioctrl->pinctrl_dev)) {
ret = PTR_ERR(atmel_pioctrl->pinctrl_dev);
dev_err(dev, "pinctrl registration failed\n");
- goto clk_unprep;
+ goto irq_domain_remove_error;
}
ret = gpiochip_add_data(atmel_pioctrl->gpio_chip, atmel_pioctrl);
if (ret) {
dev_err(dev, "failed to add gpiochip\n");
- goto clk_unprep;
+ goto irq_domain_remove_error;
}
ret = gpiochip_add_pin_range(atmel_pioctrl->gpio_chip, dev_name(dev),
@@ -1231,10 +1259,7 @@ static int atmel_pinctrl_probe(struct platform_device *pdev)
gpiochip_add_pin_range_error:
gpiochip_remove(atmel_pioctrl->gpio_chip);
-clk_unprep:
- clk_disable_unprepare(atmel_pioctrl->clk);
-
-clk_prepare_enable_error:
+irq_domain_remove_error:
irq_domain_remove(atmel_pioctrl->irq_domain);
return ret;