mirror of https://gitee.com/openkylin/linux.git
qcom: spmi-gpio: convert to hierarchical IRQ helpers in gpio core
Now that the GPIO core has support for hierarchical IRQ chips, convert Qualcomm's spmi-gpio over to use these new helpers to reduce duplicated code across drivers. This change was tested on a LG Nexus 5 (hammerhead) phone. Signed-off-by: Brian Masney <masneyb@onstation.org> Signed-off-by: Linus Walleij <linus.walleij@linaro.org> Link: https://lore.kernel.org/r/20190808123242.5359-3-linus.walleij@linaro.org
This commit is contained in:
parent
aa7d618ac6
commit
821c76c4c3
|
@ -138,6 +138,7 @@ config PINCTRL_QCOM_SPMI_PMIC
|
||||||
select PINMUX
|
select PINMUX
|
||||||
select PINCONF
|
select PINCONF
|
||||||
select GENERIC_PINCONF
|
select GENERIC_PINCONF
|
||||||
|
select GPIOLIB_IRQCHIP
|
||||||
select IRQ_DOMAIN_HIERARCHY
|
select IRQ_DOMAIN_HIERARCHY
|
||||||
help
|
help
|
||||||
This is the pinctrl, pinmux, pinconf and gpiolib driver for the
|
This is the pinctrl, pinmux, pinconf and gpiolib driver for the
|
||||||
|
|
|
@ -170,8 +170,6 @@ struct pmic_gpio_state {
|
||||||
struct regmap *map;
|
struct regmap *map;
|
||||||
struct pinctrl_dev *ctrl;
|
struct pinctrl_dev *ctrl;
|
||||||
struct gpio_chip chip;
|
struct gpio_chip chip;
|
||||||
struct fwnode_handle *fwnode;
|
|
||||||
struct irq_domain *domain;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
static const struct pinconf_generic_params pmic_gpio_bindings[] = {
|
static const struct pinconf_generic_params pmic_gpio_bindings[] = {
|
||||||
|
@ -751,23 +749,6 @@ static int pmic_gpio_of_xlate(struct gpio_chip *chip,
|
||||||
return gpio_desc->args[0] - PMIC_GPIO_PHYSICAL_OFFSET;
|
return gpio_desc->args[0] - PMIC_GPIO_PHYSICAL_OFFSET;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int pmic_gpio_to_irq(struct gpio_chip *chip, unsigned pin)
|
|
||||||
{
|
|
||||||
struct pmic_gpio_state *state = gpiochip_get_data(chip);
|
|
||||||
struct irq_fwspec fwspec;
|
|
||||||
|
|
||||||
fwspec.fwnode = state->fwnode;
|
|
||||||
fwspec.param_count = 2;
|
|
||||||
fwspec.param[0] = pin + PMIC_GPIO_PHYSICAL_OFFSET;
|
|
||||||
/*
|
|
||||||
* Set the type to a safe value temporarily. This will be overwritten
|
|
||||||
* later with the proper value by irq_set_type.
|
|
||||||
*/
|
|
||||||
fwspec.param[1] = IRQ_TYPE_EDGE_RISING;
|
|
||||||
|
|
||||||
return irq_create_fwspec_mapping(&fwspec);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void pmic_gpio_dbg_show(struct seq_file *s, struct gpio_chip *chip)
|
static void pmic_gpio_dbg_show(struct seq_file *s, struct gpio_chip *chip)
|
||||||
{
|
{
|
||||||
struct pmic_gpio_state *state = gpiochip_get_data(chip);
|
struct pmic_gpio_state *state = gpiochip_get_data(chip);
|
||||||
|
@ -787,7 +768,6 @@ static const struct gpio_chip pmic_gpio_gpio_template = {
|
||||||
.request = gpiochip_generic_request,
|
.request = gpiochip_generic_request,
|
||||||
.free = gpiochip_generic_free,
|
.free = gpiochip_generic_free,
|
||||||
.of_xlate = pmic_gpio_of_xlate,
|
.of_xlate = pmic_gpio_of_xlate,
|
||||||
.to_irq = pmic_gpio_to_irq,
|
|
||||||
.dbg_show = pmic_gpio_dbg_show,
|
.dbg_show = pmic_gpio_dbg_show,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -964,45 +944,23 @@ static int pmic_gpio_domain_translate(struct irq_domain *domain,
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int pmic_gpio_domain_alloc(struct irq_domain *domain, unsigned int virq,
|
static unsigned int pmic_gpio_child_offset_to_irq(struct gpio_chip *chip,
|
||||||
unsigned int nr_irqs, void *data)
|
unsigned int offset)
|
||||||
{
|
{
|
||||||
struct pmic_gpio_state *state = container_of(domain->host_data,
|
return offset + PMIC_GPIO_PHYSICAL_OFFSET;
|
||||||
struct pmic_gpio_state,
|
|
||||||
chip);
|
|
||||||
struct irq_fwspec *fwspec = data;
|
|
||||||
struct irq_fwspec parent_fwspec;
|
|
||||||
irq_hw_number_t hwirq;
|
|
||||||
unsigned int type;
|
|
||||||
int ret, i;
|
|
||||||
|
|
||||||
ret = pmic_gpio_domain_translate(domain, fwspec, &hwirq, &type);
|
|
||||||
if (ret)
|
|
||||||
return ret;
|
|
||||||
|
|
||||||
for (i = 0; i < nr_irqs; i++)
|
|
||||||
irq_domain_set_info(domain, virq + i, hwirq + i,
|
|
||||||
&pmic_gpio_irq_chip, state,
|
|
||||||
handle_level_irq, NULL, NULL);
|
|
||||||
|
|
||||||
parent_fwspec.fwnode = domain->parent->fwnode;
|
|
||||||
parent_fwspec.param_count = 4;
|
|
||||||
parent_fwspec.param[0] = 0;
|
|
||||||
parent_fwspec.param[1] = hwirq + 0xc0;
|
|
||||||
parent_fwspec.param[2] = 0;
|
|
||||||
parent_fwspec.param[3] = fwspec->param[1];
|
|
||||||
|
|
||||||
return irq_domain_alloc_irqs_parent(domain, virq, nr_irqs,
|
|
||||||
&parent_fwspec);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static const struct irq_domain_ops pmic_gpio_domain_ops = {
|
static int pmic_gpio_child_to_parent_hwirq(struct gpio_chip *chip,
|
||||||
.activate = gpiochip_irq_domain_activate,
|
unsigned int child_hwirq,
|
||||||
.alloc = pmic_gpio_domain_alloc,
|
unsigned int child_type,
|
||||||
.deactivate = gpiochip_irq_domain_deactivate,
|
unsigned int *parent_hwirq,
|
||||||
.free = irq_domain_free_irqs_common,
|
unsigned int *parent_type)
|
||||||
.translate = pmic_gpio_domain_translate,
|
{
|
||||||
};
|
*parent_hwirq = child_hwirq + 0xc0;
|
||||||
|
*parent_type = child_type;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
static int pmic_gpio_probe(struct platform_device *pdev)
|
static int pmic_gpio_probe(struct platform_device *pdev)
|
||||||
{
|
{
|
||||||
|
@ -1013,6 +971,7 @@ static int pmic_gpio_probe(struct platform_device *pdev)
|
||||||
struct pinctrl_desc *pctrldesc;
|
struct pinctrl_desc *pctrldesc;
|
||||||
struct pmic_gpio_pad *pad, *pads;
|
struct pmic_gpio_pad *pad, *pads;
|
||||||
struct pmic_gpio_state *state;
|
struct pmic_gpio_state *state;
|
||||||
|
struct gpio_irq_chip *girq;
|
||||||
int ret, npins, i;
|
int ret, npins, i;
|
||||||
u32 reg;
|
u32 reg;
|
||||||
|
|
||||||
|
@ -1092,19 +1051,21 @@ static int pmic_gpio_probe(struct platform_device *pdev)
|
||||||
if (!parent_domain)
|
if (!parent_domain)
|
||||||
return -ENXIO;
|
return -ENXIO;
|
||||||
|
|
||||||
state->fwnode = of_node_to_fwnode(state->dev->of_node);
|
girq = &state->chip.irq;
|
||||||
state->domain = irq_domain_create_hierarchy(parent_domain, 0,
|
girq->chip = &pmic_gpio_irq_chip;
|
||||||
state->chip.ngpio,
|
girq->default_type = IRQ_TYPE_NONE;
|
||||||
state->fwnode,
|
girq->handler = handle_level_irq;
|
||||||
&pmic_gpio_domain_ops,
|
girq->fwnode = of_node_to_fwnode(state->dev->of_node);
|
||||||
&state->chip);
|
girq->parent_domain = parent_domain;
|
||||||
if (!state->domain)
|
girq->child_to_parent_hwirq = pmic_gpio_child_to_parent_hwirq;
|
||||||
return -ENODEV;
|
girq->populate_parent_fwspec = gpiochip_populate_parent_fwspec_fourcell;
|
||||||
|
girq->child_offset_to_irq = pmic_gpio_child_offset_to_irq;
|
||||||
|
girq->child_irq_domain_ops.translate = pmic_gpio_domain_translate;
|
||||||
|
|
||||||
ret = gpiochip_add_data(&state->chip, state);
|
ret = gpiochip_add_data(&state->chip, state);
|
||||||
if (ret) {
|
if (ret) {
|
||||||
dev_err(state->dev, "can't add gpio chip\n");
|
dev_err(state->dev, "can't add gpio chip\n");
|
||||||
goto err_chip_add_data;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -1130,8 +1091,6 @@ static int pmic_gpio_probe(struct platform_device *pdev)
|
||||||
|
|
||||||
err_range:
|
err_range:
|
||||||
gpiochip_remove(&state->chip);
|
gpiochip_remove(&state->chip);
|
||||||
err_chip_add_data:
|
|
||||||
irq_domain_remove(state->domain);
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1140,7 +1099,6 @@ static int pmic_gpio_remove(struct platform_device *pdev)
|
||||||
struct pmic_gpio_state *state = platform_get_drvdata(pdev);
|
struct pmic_gpio_state *state = platform_get_drvdata(pdev);
|
||||||
|
|
||||||
gpiochip_remove(&state->chip);
|
gpiochip_remove(&state->chip);
|
||||||
irq_domain_remove(state->domain);
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue