fixup! pinctrl: add pinctrl/GPIO driver for Apple SoCs
Signed-off-by: Marc Zyngier <maz@kernel.org>
diff --git a/drivers/pinctrl/pinctrl-apple-gpio.c b/drivers/pinctrl/pinctrl-apple-gpio.c
index df93eb1..aa53346 100644
--- a/drivers/pinctrl/pinctrl-apple-gpio.c
+++ b/drivers/pinctrl/pinctrl-apple-gpio.c
@@ -26,22 +26,16 @@
#include "core.h"
#include "pinmux.h"
-struct apple_gpio_irq_data {
- struct apple_gpio_pinctrl *pctl;
- int irqgrp;
-};
-
struct apple_gpio_pinctrl {
struct device *dev;
struct pinctrl_dev *pctldev;
void __iomem *base;
struct regmap *map;
- unsigned int nirqgrps;
struct pinctrl_desc pinctrl_desc;
struct gpio_chip gpio_chip;
- struct irq_chip irq_chip;
+ u8 irqgrps[0];
};
#define REG_GPIO(x) (4 * (x))
@@ -73,14 +67,14 @@
.val_bits = 32,
.reg_stride = 4,
.cache_type = REGCACHE_FLAT,
- .max_register = 512 * sizeof(uint32_t),
+ .max_register = 512 * sizeof(u32),
.num_reg_defaults_raw = 512,
.use_relaxed_mmio = true
};
// No locking needed to mask/unmask IRQs as the interrupt mode is per pin-register.
static void apple_gpio_set_reg(struct apple_gpio_pinctrl *pctl,
- unsigned int pin, uint32_t mask, uint32_t value)
+ unsigned int pin, u32 mask, u32 value)
{
regmap_update_bits(pctl->map, REG_GPIO(pin), mask, value);
}
@@ -88,7 +82,7 @@
static uint32_t apple_gpio_get_reg(struct apple_gpio_pinctrl *pctl,
unsigned int pin)
{
- uint32_t val = 0;
+ unsigned int val = 0;
regmap_read(pctl->map, REG_GPIO(pin), &val);
return val;
@@ -119,7 +113,7 @@
dev_err(pctl->dev,
"missing or empty pinmux property in node %pOFn.\n",
node);
- return -EINVAL;
+ return ret;
}
num_pins = ret;
@@ -153,12 +147,10 @@
}
free_map:
- if (ret < 0) {
+ if (ret < 0)
pinctrl_utils_free_map(pctldev, *map, *num_maps);
- return ret;
- }
- return 0;
+ return ret;
}
static const struct pinctrl_ops apple_gpio_pinctrl_ops = {
@@ -200,8 +192,7 @@
unsigned int reg = apple_gpio_get_reg(pctl, offset);
return (FIELD_GET(REG_GPIOx_MODE, reg) == REG_GPIOx_OUT) ?
- GPIO_LINE_DIRECTION_OUT :
- GPIO_LINE_DIRECTION_IN;
+ GPIO_LINE_DIRECTION_OUT : GPIO_LINE_DIRECTION_IN;
}
static int apple_gpio_gpio_get(struct gpio_chip *chip, unsigned offset)
@@ -209,7 +200,10 @@
struct apple_gpio_pinctrl *pctl = gpiochip_get_data(chip);
unsigned int reg = apple_gpio_get_reg(pctl, offset);
- // If this is an input GPIO, read the actual value (not the cached regmap value)
+ /*
+ * If this is an input GPIO, read the actual value (not the
+ * cached regmap value)
+ */
if (FIELD_GET(REG_GPIOx_MODE, reg) != REG_GPIOx_OUT)
reg = readl_relaxed(pctl->base + REG_GPIO(offset));
@@ -295,8 +289,6 @@
gpiochip_get_data(irq_data_get_irq_chip_data(data));
int irqtype = apple_gpio_irq_type(irqd_get_trigger_type(data));
- if (WARN_ON(irqtype < 0))
- return;
apple_gpio_set_reg(pctl, data->hwirq, REG_GPIOx_MODE,
FIELD_PREP(REG_GPIOx_MODE, irqtype));
}
@@ -325,8 +317,6 @@
if (irqtype < 0)
return irqtype;
- irqd_set_trigger_type(data, type);
-
apple_gpio_set_reg(pctl, data->hwirq, REG_GPIOx_MODE,
FIELD_PREP(REG_GPIOx_MODE, irqtype));
@@ -339,38 +329,45 @@
static void apple_gpio_gpio_irq_handler(struct irq_desc *desc)
{
- struct apple_gpio_irq_data *data = irq_desc_get_handler_data(desc);
- struct apple_gpio_pinctrl *pctl = data->pctl;
- struct gpio_chip *gc = &pctl->gpio_chip;
struct irq_chip *chip = irq_desc_get_chip(desc);
- unsigned int irqgrp = data->irqgrp;
+ u8 *grpp = irq_desc_get_handler_data(desc);
+ struct apple_gpio_pinctrl *pctl;
unsigned int pinh, pinl;
unsigned long pending;
+ struct gpio_chip *gc;
+
+ pctl = container_of(grpp - *grpp, typeof(*pctl), irqgrps[0]);
+ gc = &pctl->gpio_chip;
chained_irq_enter(chip, desc);
for (pinh = 0; pinh < gc->ngpio; pinh += 32) {
- pending = readl(pctl->base + REG_IRQ(irqgrp, pinh));
+ pending = readl_relaxed(pctl->base + REG_IRQ(*grpp, pinh));
for_each_set_bit(pinl, &pending, 32)
generic_handle_domain_irq(gc->irq.domain, pinh + pinl);
}
chained_irq_exit(chip, desc);
}
+static struct irq_chip apple_gpio_irqchip = {
+ .name = "Apple-GPIO",
+ .irq_startup = apple_gpio_gpio_irq_startup,
+ .irq_ack = apple_gpio_gpio_irq_ack,
+ .irq_mask = apple_gpio_gpio_irq_mask,
+ .irq_unmask = apple_gpio_gpio_irq_unmask,
+ .irq_set_type = apple_gpio_gpio_irq_set_type,
+};
+
/* Probe & register */
static int apple_gpio_gpio_register(struct apple_gpio_pinctrl *pctl)
{
- struct device_node *node = pctl->dev->of_node;
- struct gpio_irq_chip *girq;
- struct apple_gpio_irq_data **irq_data;
- int i;
+ struct gpio_irq_chip *girq = &pctl->gpio_chip.irq;
+ void **irq_data = NULL;
int ret;
- if (!of_find_property(node, "gpio-controller", NULL)) {
- dev_err(pctl->dev,
- "Apple GPIO must have 'gpio-controller' property.\n");
- return -ENODEV;
- }
+ if (!of_property_read_bool(pctl->dev->of_node, "gpio-controller"))
+ return dev_err_probe(pctl->dev, -ENODEV,
+ "No gpio-controller property\n");
pctl->gpio_chip.label = dev_name(pctl->dev);
pctl->gpio_chip.request = gpiochip_generic_request;
@@ -383,68 +380,45 @@
pctl->gpio_chip.base = -1;
pctl->gpio_chip.ngpio = pctl->pinctrl_desc.npins;
pctl->gpio_chip.parent = pctl->dev;
- pctl->gpio_chip.of_node = node;
+ pctl->gpio_chip.of_node = pctl->dev->of_node;
- if (of_property_read_bool(node, "interrupt-controller")) {
- ret = platform_irq_count(to_platform_device(pctl->dev));
- if (ret < 0)
- return ret;
+ if (girq->num_parents) {
+ int i;
- pctl->nirqgrps = ret;
-
- pctl->irq_chip.name = "Apple-GPIO";
- pctl->irq_chip.irq_startup = apple_gpio_gpio_irq_startup;
- pctl->irq_chip.irq_ack = apple_gpio_gpio_irq_ack;
- pctl->irq_chip.irq_mask = apple_gpio_gpio_irq_mask;
- pctl->irq_chip.irq_unmask = apple_gpio_gpio_irq_unmask;
- pctl->irq_chip.irq_set_type = apple_gpio_gpio_irq_set_type;
-
- girq = &pctl->gpio_chip.irq;
- girq->chip = &pctl->irq_chip;
+ girq->chip = &apple_gpio_irqchip;
girq->parent_handler = apple_gpio_gpio_irq_handler;
- girq->num_parents = pctl->nirqgrps;
- girq->parents = kmalloc_array(
- pctl->nirqgrps, sizeof(*girq->parents), GFP_KERNEL);
- if (!girq->parents)
- return -ENOMEM;
+ girq->parents = kmalloc_array(girq->num_parents,
+ sizeof(*girq->parents),
+ GFP_KERNEL);
+ irq_data = kmalloc_array(girq->num_parents, sizeof(*irq_data),
+ GFP_KERNEL);
+ if (!girq->parents || !irq_data) {
+ ret = -ENOMEM;
+ goto out;
+ }
- for (i = 0; i < pctl->nirqgrps; i++) {
+ for (i = 0; i < girq->num_parents; i++) {
ret = platform_get_irq(to_platform_device(pctl->dev),
i);
- if (ret < 0) {
- return dev_err_probe(pctl->dev, ret,
- "Failed to map IRQ %d\n",
- i);
- }
+ if (ret < 0)
+ goto out;
+
girq->parents[i] = ret;
+ pctl->irqgrps[i] = i;
+ irq_data[i] = &pctl->irqgrps[i];
}
- irq_data = kmalloc_array(pctl->nirqgrps, sizeof(*irq_data),
- GFP_KERNEL);
- if (!irq_data) {
- kfree(girq->parents);
- return -ENOMEM;
- }
- for (i = 0; i < pctl->nirqgrps; i++) {
- irq_data[i] = devm_kzalloc(
- pctl->dev, sizeof(*irq_data[i]), GFP_KERNEL);
- irq_data[i]->pctl = pctl;
- irq_data[i]->irqgrp = i;
- }
-
- girq->parent_handler_data_array = (void **)irq_data;
+ girq->parent_handler_data_array = irq_data;
girq->per_parent_data = true;
girq->default_type = IRQ_TYPE_NONE;
girq->handler = handle_level_irq;
}
ret = devm_gpiochip_add_data(pctl->dev, &pctl->gpio_chip, pctl);
-
- if (of_property_read_bool(node, "interrupt-controller")) {
- kfree(girq->parents);
- kfree(irq_data);
- }
+out:
+ kfree(girq->parents);
+ kfree(irq_data);
return ret;
}
@@ -456,48 +430,48 @@
unsigned int npins;
const char **pin_names;
unsigned int *pin_nums;
- unsigned int i;
+ unsigned int i, nirqs = 0;
int res;
- pctl = devm_kzalloc(&pdev->dev, sizeof(*pctl), GFP_KERNEL);
+ if (of_property_read_bool(pdev->dev.of_node, "interrupt-controller")) {
+ res = platform_irq_count(pdev);
+ if (res > 0)
+ nirqs = res;
+ }
+
+ pctl = devm_kzalloc(&pdev->dev, struct_size(pctl, irqgrps, nirqs),
+ GFP_KERNEL);
if (!pctl)
return -ENOMEM;
pctl->dev = &pdev->dev;
+ pctl->gpio_chip.irq.num_parents = nirqs;
dev_set_drvdata(&pdev->dev, pctl);
- if (of_property_read_u32(pdev->dev.of_node, "apple,npins", &npins)) {
- dev_err(&pdev->dev, "apple,npins property not found\n");
- return -EINVAL;
- }
+ if (of_property_read_u32(pdev->dev.of_node, "apple,npins", &npins))
+ return dev_err_probe(&pdev->dev, -EINVAL,
+ "apple,npins property not found\n");
pins = devm_kmalloc_array(&pdev->dev, npins, sizeof(pins[0]),
GFP_KERNEL);
- if (!pins)
- return -ENOMEM;
pin_names = devm_kmalloc_array(&pdev->dev, npins, sizeof(pin_names[0]),
GFP_KERNEL);
- if (!pin_names)
- return -ENOMEM;
pin_nums = devm_kmalloc_array(&pdev->dev, npins, sizeof(pin_nums[0]),
GFP_KERNEL);
- if (!pin_nums)
+ if (!pins || !pin_names || !pin_nums)
return -ENOMEM;
pctl->base = devm_platform_ioremap_resource(pdev, 0);
if (IS_ERR(pctl->base))
return PTR_ERR(pctl->base);
- pctl->map =
- devm_regmap_init_mmio(&pdev->dev, pctl->base, ®map_config);
- if (IS_ERR(pctl->map)) {
- dev_err(&pdev->dev, "Failed to create regmap\n");
- return PTR_ERR(pctl->map);
- }
+ pctl->map = devm_regmap_init_mmio(&pdev->dev, pctl->base, ®map_config);
+ if (IS_ERR(pctl->map))
+ return dev_err_probe(&pdev->dev, PTR_ERR(pctl->map),
+ "Failed to create regmap\n");
for (i = 0; i < npins; i++) {
pins[i].number = i;
- pins[i].name =
- devm_kasprintf(&pdev->dev, GFP_KERNEL, "PIN%u", i);
+ pins[i].name = devm_kasprintf(&pdev->dev, GFP_KERNEL, "PIN%u", i);
pins[i].drv_data = pctl;
pin_names[i] = pins[i].name;
pin_nums[i] = i;
@@ -509,35 +483,30 @@
pctl->pinctrl_desc.pctlops = &apple_gpio_pinctrl_ops;
pctl->pinctrl_desc.pmxops = &apple_gpio_pinmux_ops;
- pctl->pctldev =
- devm_pinctrl_register(&pdev->dev, &pctl->pinctrl_desc, pctl);
- if (IS_ERR(pctl->pctldev)) {
- dev_err(&pdev->dev, "Failed to register pinctrl device.\n");
- return PTR_ERR(pctl->pctldev);
- }
+ pctl->pctldev = devm_pinctrl_register(&pdev->dev, &pctl->pinctrl_desc, pctl);
+ if (IS_ERR(pctl->pctldev))
+ return dev_err_probe(&pdev->dev, PTR_ERR(pctl->pctldev),
+ "Failed to register pinctrl device.\n");
for (i = 0; i < npins; i++) {
res = pinctrl_generic_add_group(pctl->pctldev, pins[i].name,
pin_nums + i, 1, pctl);
- if (res < 0) {
- dev_err(pctl->dev, "Failed to register group.");
- return res;
- }
+ if (res < 0)
+ return dev_err_probe(pctl->dev, res,
+ "Failed to register group");
}
res = pinmux_generic_add_function(pctl->pctldev, "gpio", pin_names,
npins, pctl);
- if (res < 0) {
- dev_err(pctl->dev, "Failed to register function.");
- return res;
- }
+ if (res < 0)
+ return dev_err_probe(pctl->dev, res,
+ "Failed to register function.");
res = pinmux_generic_add_function(pctl->pctldev, "periph", pin_names,
npins, pctl);
- if (res < 0) {
- dev_err(pctl->dev, "Failed to register function.");
- return res;
- }
+ if (res < 0)
+ return dev_err_probe(pctl->dev, res,
+ "Failed to register function.");
return apple_gpio_gpio_register(pctl);
}