in gpio-tegra.c [656:781]
static int tegra_gpio_probe(struct platform_device *pdev)
{
struct tegra_gpio_bank *bank;
struct tegra_gpio_info *tgi;
struct gpio_irq_chip *irq;
struct device_node *np;
unsigned int i, j;
int ret;
tgi = devm_kzalloc(&pdev->dev, sizeof(*tgi), GFP_KERNEL);
if (!tgi)
return -ENODEV;
tgi->soc = of_device_get_match_data(&pdev->dev);
tgi->dev = &pdev->dev;
ret = platform_irq_count(pdev);
if (ret < 0)
return ret;
tgi->bank_count = ret;
if (!tgi->bank_count) {
dev_err(&pdev->dev, "Missing IRQ resource\n");
return -ENODEV;
}
tgi->gc.label = "tegra-gpio";
tgi->gc.request = tegra_gpio_request;
tgi->gc.free = tegra_gpio_free;
tgi->gc.direction_input = tegra_gpio_direction_input;
tgi->gc.get = tegra_gpio_get;
tgi->gc.direction_output = tegra_gpio_direction_output;
tgi->gc.set = tegra_gpio_set;
tgi->gc.get_direction = tegra_gpio_get_direction;
tgi->gc.base = 0;
tgi->gc.ngpio = tgi->bank_count * 32;
tgi->gc.parent = &pdev->dev;
tgi->gc.of_node = pdev->dev.of_node;
tgi->ic.name = "GPIO";
tgi->ic.irq_ack = tegra_gpio_irq_ack;
tgi->ic.irq_mask = tegra_gpio_irq_mask;
tgi->ic.irq_unmask = tegra_gpio_irq_unmask;
tgi->ic.irq_set_type = tegra_gpio_irq_set_type;
tgi->ic.irq_shutdown = tegra_gpio_irq_shutdown;
#ifdef CONFIG_PM_SLEEP
tgi->ic.irq_set_wake = tegra_gpio_irq_set_wake;
#endif
tgi->ic.irq_request_resources = tegra_gpio_irq_request_resources;
tgi->ic.irq_release_resources = tegra_gpio_irq_release_resources;
platform_set_drvdata(pdev, tgi);
if (tgi->soc->debounce_supported)
tgi->gc.set_config = tegra_gpio_set_config;
tgi->bank_info = devm_kcalloc(&pdev->dev, tgi->bank_count,
sizeof(*tgi->bank_info), GFP_KERNEL);
if (!tgi->bank_info)
return -ENOMEM;
tgi->irqs = devm_kcalloc(&pdev->dev, tgi->bank_count,
sizeof(*tgi->irqs), GFP_KERNEL);
if (!tgi->irqs)
return -ENOMEM;
for (i = 0; i < tgi->bank_count; i++) {
ret = platform_get_irq(pdev, i);
if (ret < 0)
return ret;
bank = &tgi->bank_info[i];
bank->bank = i;
tgi->irqs[i] = ret;
for (j = 0; j < 4; j++) {
raw_spin_lock_init(&bank->lvl_lock[j]);
spin_lock_init(&bank->dbc_lock[j]);
}
}
irq = &tgi->gc.irq;
irq->chip = &tgi->ic;
irq->fwnode = of_node_to_fwnode(pdev->dev.of_node);
irq->child_to_parent_hwirq = tegra_gpio_child_to_parent_hwirq;
irq->populate_parent_alloc_arg = tegra_gpio_populate_parent_fwspec;
irq->handler = handle_simple_irq;
irq->default_type = IRQ_TYPE_NONE;
irq->parent_handler = tegra_gpio_irq_handler;
irq->parent_handler_data = tgi;
irq->num_parents = tgi->bank_count;
irq->parents = tgi->irqs;
np = of_find_matching_node(NULL, tegra_pmc_of_match);
if (np) {
irq->parent_domain = irq_find_host(np);
of_node_put(np);
if (!irq->parent_domain)
return -EPROBE_DEFER;
tgi->ic.irq_set_affinity = tegra_gpio_irq_set_affinity;
}
tgi->regs = devm_platform_ioremap_resource(pdev, 0);
if (IS_ERR(tgi->regs))
return PTR_ERR(tgi->regs);
for (i = 0; i < tgi->bank_count; i++) {
for (j = 0; j < 4; j++) {
int gpio = tegra_gpio_compose(i, j, 0);
tegra_gpio_writel(tgi, 0x00, GPIO_INT_ENB(tgi, gpio));
}
}
ret = devm_gpiochip_add_data(&pdev->dev, &tgi->gc, tgi);
if (ret < 0)
return ret;
tegra_gpio_debuginit(tgi);
return 0;
}