in gpio-mvebu.c [1122:1310]
static int mvebu_gpio_probe(struct platform_device *pdev)
{
struct mvebu_gpio_chip *mvchip;
const struct of_device_id *match;
struct device_node *np = pdev->dev.of_node;
struct irq_chip_generic *gc;
struct irq_chip_type *ct;
unsigned int ngpios;
bool have_irqs;
int soc_variant;
int i, cpu, id;
int err;
match = of_match_device(mvebu_gpio_of_match, &pdev->dev);
if (match)
soc_variant = (unsigned long) match->data;
else
soc_variant = MVEBU_GPIO_SOC_VARIANT_ORION;
/* Some gpio controllers do not provide irq support */
err = platform_irq_count(pdev);
if (err < 0)
return err;
have_irqs = err != 0;
mvchip = devm_kzalloc(&pdev->dev, sizeof(struct mvebu_gpio_chip),
GFP_KERNEL);
if (!mvchip)
return -ENOMEM;
platform_set_drvdata(pdev, mvchip);
if (of_property_read_u32(pdev->dev.of_node, "ngpios", &ngpios)) {
dev_err(&pdev->dev, "Missing ngpios OF property\n");
return -ENODEV;
}
id = of_alias_get_id(pdev->dev.of_node, "gpio");
if (id < 0) {
dev_err(&pdev->dev, "Couldn't get OF id\n");
return id;
}
mvchip->clk = devm_clk_get(&pdev->dev, NULL);
/* Not all SoCs require a clock.*/
if (!IS_ERR(mvchip->clk))
clk_prepare_enable(mvchip->clk);
mvchip->soc_variant = soc_variant;
mvchip->chip.label = dev_name(&pdev->dev);
mvchip->chip.parent = &pdev->dev;
mvchip->chip.request = gpiochip_generic_request;
mvchip->chip.free = gpiochip_generic_free;
mvchip->chip.get_direction = mvebu_gpio_get_direction;
mvchip->chip.direction_input = mvebu_gpio_direction_input;
mvchip->chip.get = mvebu_gpio_get;
mvchip->chip.direction_output = mvebu_gpio_direction_output;
mvchip->chip.set = mvebu_gpio_set;
if (have_irqs)
mvchip->chip.to_irq = mvebu_gpio_to_irq;
mvchip->chip.base = id * MVEBU_MAX_GPIO_PER_BANK;
mvchip->chip.ngpio = ngpios;
mvchip->chip.can_sleep = false;
mvchip->chip.dbg_show = mvebu_gpio_dbg_show;
if (soc_variant == MVEBU_GPIO_SOC_VARIANT_A8K)
err = mvebu_gpio_probe_syscon(pdev, mvchip);
else
err = mvebu_gpio_probe_raw(pdev, mvchip);
if (err)
return err;
/*
* Mask and clear GPIO interrupts.
*/
switch (soc_variant) {
case MVEBU_GPIO_SOC_VARIANT_ORION:
case MVEBU_GPIO_SOC_VARIANT_A8K:
regmap_write(mvchip->regs,
GPIO_EDGE_CAUSE_OFF + mvchip->offset, 0);
regmap_write(mvchip->regs,
GPIO_EDGE_MASK_OFF + mvchip->offset, 0);
regmap_write(mvchip->regs,
GPIO_LEVEL_MASK_OFF + mvchip->offset, 0);
break;
case MVEBU_GPIO_SOC_VARIANT_MV78200:
regmap_write(mvchip->regs, GPIO_EDGE_CAUSE_OFF, 0);
for (cpu = 0; cpu < 2; cpu++) {
regmap_write(mvchip->regs,
GPIO_EDGE_MASK_MV78200_OFF(cpu), 0);
regmap_write(mvchip->regs,
GPIO_LEVEL_MASK_MV78200_OFF(cpu), 0);
}
break;
case MVEBU_GPIO_SOC_VARIANT_ARMADAXP:
regmap_write(mvchip->regs, GPIO_EDGE_CAUSE_OFF, 0);
regmap_write(mvchip->regs, GPIO_EDGE_MASK_OFF, 0);
regmap_write(mvchip->regs, GPIO_LEVEL_MASK_OFF, 0);
for (cpu = 0; cpu < 4; cpu++) {
regmap_write(mvchip->percpu_regs,
GPIO_EDGE_CAUSE_ARMADAXP_OFF(cpu), 0);
regmap_write(mvchip->percpu_regs,
GPIO_EDGE_MASK_ARMADAXP_OFF(cpu), 0);
regmap_write(mvchip->percpu_regs,
GPIO_LEVEL_MASK_ARMADAXP_OFF(cpu), 0);
}
break;
default:
BUG();
}
devm_gpiochip_add_data(&pdev->dev, &mvchip->chip, mvchip);
/* Some MVEBU SoCs have simple PWM support for GPIO lines */
if (IS_ENABLED(CONFIG_PWM)) {
err = mvebu_pwm_probe(pdev, mvchip, id);
if (err)
return err;
}
/* Some gpio controllers do not provide irq support */
if (!have_irqs)
return 0;
mvchip->domain =
irq_domain_add_linear(np, ngpios, &irq_generic_chip_ops, NULL);
if (!mvchip->domain) {
dev_err(&pdev->dev, "couldn't allocate irq domain %s (DT).\n",
mvchip->chip.label);
err = -ENODEV;
goto err_pwm;
}
err = irq_alloc_domain_generic_chips(
mvchip->domain, ngpios, 2, np->name, handle_level_irq,
IRQ_NOREQUEST | IRQ_NOPROBE | IRQ_LEVEL, 0, 0);
if (err) {
dev_err(&pdev->dev, "couldn't allocate irq chips %s (DT).\n",
mvchip->chip.label);
goto err_domain;
}
/*
* NOTE: The common accessors cannot be used because of the percpu
* access to the mask registers
*/
gc = irq_get_domain_generic_chip(mvchip->domain, 0);
gc->private = mvchip;
ct = &gc->chip_types[0];
ct->type = IRQ_TYPE_LEVEL_HIGH | IRQ_TYPE_LEVEL_LOW;
ct->chip.irq_mask = mvebu_gpio_level_irq_mask;
ct->chip.irq_unmask = mvebu_gpio_level_irq_unmask;
ct->chip.irq_set_type = mvebu_gpio_irq_set_type;
ct->chip.name = mvchip->chip.label;
ct = &gc->chip_types[1];
ct->type = IRQ_TYPE_EDGE_RISING | IRQ_TYPE_EDGE_FALLING;
ct->chip.irq_ack = mvebu_gpio_irq_ack;
ct->chip.irq_mask = mvebu_gpio_edge_irq_mask;
ct->chip.irq_unmask = mvebu_gpio_edge_irq_unmask;
ct->chip.irq_set_type = mvebu_gpio_irq_set_type;
ct->handler = handle_edge_irq;
ct->chip.name = mvchip->chip.label;
/*
* Setup the interrupt handlers. Each chip can have up to 4
* interrupt handlers, with each handler dealing with 8 GPIO
* pins.
*/
for (i = 0; i < 4; i++) {
int irq = platform_get_irq_optional(pdev, i);
if (irq < 0)
continue;
irq_set_chained_handler_and_data(irq, mvebu_gpio_irq_handler,
mvchip);
}
return 0;
err_domain:
irq_domain_remove(mvchip->domain);
err_pwm:
pwmchip_remove(&mvchip->mvpwm->chip);
return err;
}