forked from Minki/linux
pinctrl: ssbi-gpio: convert to hierarchical IRQ helpers in gpio core
Now that the GPIO core has support for hierarchical IRQ chips, convert Qualcomm's ssbi-gpio over to use these new helpers to reduce duplicated code across drivers. Signed-off-by: Brian Masney <masneyb@onstation.org> Link: https://lore.kernel.org/r/20190914111010.24384-1-masneyb@onstation.org Signed-off-by: Linus Walleij <linus.walleij@linaro.org>
This commit is contained in:
parent
be4c60b563
commit
ae436fe810
@ -152,6 +152,7 @@ config PINCTRL_QCOM_SSBI_PMIC
|
||||
select PINMUX
|
||||
select PINCONF
|
||||
select GENERIC_PINCONF
|
||||
select GPIOLIB_IRQCHIP
|
||||
select IRQ_DOMAIN_HIERARCHY
|
||||
help
|
||||
This is the pinctrl, pinmux, pinconf and gpiolib driver for the
|
||||
|
@ -56,7 +56,6 @@
|
||||
/**
|
||||
* struct pm8xxx_pin_data - dynamic configuration for a pin
|
||||
* @reg: address of the control register
|
||||
* @irq: IRQ from the PMIC interrupt controller
|
||||
* @power_source: logical selected voltage source, mapping in static data
|
||||
* is used translate to register values
|
||||
* @mode: operating mode for the pin (input/output)
|
||||
@ -72,7 +71,6 @@
|
||||
*/
|
||||
struct pm8xxx_pin_data {
|
||||
unsigned reg;
|
||||
int irq;
|
||||
u8 power_source;
|
||||
u8 mode;
|
||||
bool open_drain;
|
||||
@ -93,9 +91,6 @@ struct pm8xxx_gpio {
|
||||
|
||||
struct pinctrl_desc desc;
|
||||
unsigned npins;
|
||||
|
||||
struct fwnode_handle *fwnode;
|
||||
struct irq_domain *domain;
|
||||
};
|
||||
|
||||
static const struct pinconf_generic_params pm8xxx_gpio_bindings[] = {
|
||||
@ -491,13 +486,16 @@ static int pm8xxx_gpio_get(struct gpio_chip *chip, unsigned offset)
|
||||
{
|
||||
struct pm8xxx_gpio *pctrl = gpiochip_get_data(chip);
|
||||
struct pm8xxx_pin_data *pin = pctrl->desc.pins[offset].drv_data;
|
||||
int ret, irq;
|
||||
bool state;
|
||||
int ret;
|
||||
|
||||
if (pin->mode == PM8XXX_GPIO_MODE_OUTPUT) {
|
||||
ret = pin->output_value;
|
||||
} else if (pin->irq >= 0) {
|
||||
ret = irq_get_irqchip_state(pin->irq, IRQCHIP_STATE_LINE_LEVEL, &state);
|
||||
if (pin->mode == PM8XXX_GPIO_MODE_OUTPUT)
|
||||
return pin->output_value;
|
||||
|
||||
irq = chip->to_irq(chip, offset);
|
||||
if (irq >= 0) {
|
||||
ret = irq_get_irqchip_state(irq, IRQCHIP_STATE_LINE_LEVEL,
|
||||
&state);
|
||||
if (!ret)
|
||||
ret = !!state;
|
||||
} else
|
||||
@ -535,37 +533,6 @@ static int pm8xxx_gpio_of_xlate(struct gpio_chip *chip,
|
||||
}
|
||||
|
||||
|
||||
static int pm8xxx_gpio_to_irq(struct gpio_chip *chip, unsigned offset)
|
||||
{
|
||||
struct pm8xxx_gpio *pctrl = gpiochip_get_data(chip);
|
||||
struct pm8xxx_pin_data *pin = pctrl->desc.pins[offset].drv_data;
|
||||
struct irq_fwspec fwspec;
|
||||
int ret;
|
||||
|
||||
fwspec.fwnode = pctrl->fwnode;
|
||||
fwspec.param_count = 2;
|
||||
fwspec.param[0] = offset + PM8XXX_GPIO_PHYSICAL_OFFSET;
|
||||
fwspec.param[1] = IRQ_TYPE_EDGE_RISING;
|
||||
|
||||
ret = irq_create_fwspec_mapping(&fwspec);
|
||||
|
||||
/*
|
||||
* Cache the IRQ since pm8xxx_gpio_get() needs this to get determine the
|
||||
* line level.
|
||||
*/
|
||||
pin->irq = ret;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void pm8xxx_gpio_free(struct gpio_chip *chip, unsigned int offset)
|
||||
{
|
||||
struct pm8xxx_gpio *pctrl = gpiochip_get_data(chip);
|
||||
struct pm8xxx_pin_data *pin = pctrl->desc.pins[offset].drv_data;
|
||||
|
||||
pin->irq = -1;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_DEBUG_FS
|
||||
#include <linux/seq_file.h>
|
||||
|
||||
@ -624,13 +591,11 @@ static void pm8xxx_gpio_dbg_show(struct seq_file *s, struct gpio_chip *chip)
|
||||
#endif
|
||||
|
||||
static const struct gpio_chip pm8xxx_gpio_template = {
|
||||
.free = pm8xxx_gpio_free,
|
||||
.direction_input = pm8xxx_gpio_direction_input,
|
||||
.direction_output = pm8xxx_gpio_direction_output,
|
||||
.get = pm8xxx_gpio_get,
|
||||
.set = pm8xxx_gpio_set,
|
||||
.of_xlate = pm8xxx_gpio_of_xlate,
|
||||
.to_irq = pm8xxx_gpio_to_irq,
|
||||
.dbg_show = pm8xxx_gpio_dbg_show,
|
||||
.owner = THIS_MODULE,
|
||||
};
|
||||
@ -712,42 +677,23 @@ static int pm8xxx_domain_translate(struct irq_domain *domain,
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int pm8xxx_domain_alloc(struct irq_domain *domain, unsigned int virq,
|
||||
unsigned int nr_irqs, void *data)
|
||||
static unsigned int pm8xxx_child_offset_to_irq(struct gpio_chip *chip,
|
||||
unsigned int offset)
|
||||
{
|
||||
struct pm8xxx_gpio *pctrl = container_of(domain->host_data,
|
||||
struct pm8xxx_gpio, chip);
|
||||
struct irq_fwspec *fwspec = data;
|
||||
struct irq_fwspec parent_fwspec;
|
||||
irq_hw_number_t hwirq;
|
||||
unsigned int type;
|
||||
int ret, i;
|
||||
|
||||
ret = pm8xxx_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,
|
||||
&pm8xxx_irq_chip, pctrl, handle_level_irq,
|
||||
NULL, NULL);
|
||||
|
||||
parent_fwspec.fwnode = domain->parent->fwnode;
|
||||
parent_fwspec.param_count = 2;
|
||||
parent_fwspec.param[0] = hwirq + 0xc0;
|
||||
parent_fwspec.param[1] = fwspec->param[1];
|
||||
|
||||
return irq_domain_alloc_irqs_parent(domain, virq, nr_irqs,
|
||||
&parent_fwspec);
|
||||
return offset + PM8XXX_GPIO_PHYSICAL_OFFSET;
|
||||
}
|
||||
|
||||
static const struct irq_domain_ops pm8xxx_domain_ops = {
|
||||
.activate = gpiochip_irq_domain_activate,
|
||||
.alloc = pm8xxx_domain_alloc,
|
||||
.deactivate = gpiochip_irq_domain_deactivate,
|
||||
.free = irq_domain_free_irqs_common,
|
||||
.translate = pm8xxx_domain_translate,
|
||||
};
|
||||
static int pm8xxx_child_to_parent_hwirq(struct gpio_chip *chip,
|
||||
unsigned int child_hwirq,
|
||||
unsigned int child_type,
|
||||
unsigned int *parent_hwirq,
|
||||
unsigned int *parent_type)
|
||||
{
|
||||
*parent_hwirq = child_hwirq + 0xc0;
|
||||
*parent_type = child_type;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct of_device_id pm8xxx_gpio_of_match[] = {
|
||||
{ .compatible = "qcom,pm8018-gpio", .data = (void *) 6 },
|
||||
@ -765,6 +711,7 @@ static int pm8xxx_gpio_probe(struct platform_device *pdev)
|
||||
struct irq_domain *parent_domain;
|
||||
struct device_node *parent_node;
|
||||
struct pinctrl_pin_desc *pins;
|
||||
struct gpio_irq_chip *girq;
|
||||
struct pm8xxx_gpio *pctrl;
|
||||
int ret, i;
|
||||
|
||||
@ -800,7 +747,6 @@ static int pm8xxx_gpio_probe(struct platform_device *pdev)
|
||||
|
||||
for (i = 0; i < pctrl->desc.npins; i++) {
|
||||
pin_data[i].reg = SSBI_REG_ADDR_GPIO(i);
|
||||
pin_data[i].irq = -1;
|
||||
|
||||
ret = pm8xxx_pin_populate(pctrl, &pin_data[i]);
|
||||
if (ret)
|
||||
@ -841,19 +787,21 @@ static int pm8xxx_gpio_probe(struct platform_device *pdev)
|
||||
if (!parent_domain)
|
||||
return -ENXIO;
|
||||
|
||||
pctrl->fwnode = of_node_to_fwnode(pctrl->dev->of_node);
|
||||
pctrl->domain = irq_domain_create_hierarchy(parent_domain, 0,
|
||||
pctrl->chip.ngpio,
|
||||
pctrl->fwnode,
|
||||
&pm8xxx_domain_ops,
|
||||
&pctrl->chip);
|
||||
if (!pctrl->domain)
|
||||
return -ENODEV;
|
||||
girq = &pctrl->chip.irq;
|
||||
girq->chip = &pm8xxx_irq_chip;
|
||||
girq->default_type = IRQ_TYPE_NONE;
|
||||
girq->handler = handle_level_irq;
|
||||
girq->fwnode = of_node_to_fwnode(pctrl->dev->of_node);
|
||||
girq->parent_domain = parent_domain;
|
||||
girq->child_to_parent_hwirq = pm8xxx_child_to_parent_hwirq;
|
||||
girq->populate_parent_fwspec = gpiochip_populate_parent_fwspec_fourcell;
|
||||
girq->child_offset_to_irq = pm8xxx_child_offset_to_irq;
|
||||
girq->child_irq_domain_ops.translate = pm8xxx_domain_translate;
|
||||
|
||||
ret = gpiochip_add_data(&pctrl->chip, pctrl);
|
||||
if (ret) {
|
||||
dev_err(&pdev->dev, "failed register gpiochip\n");
|
||||
goto err_chip_add_data;
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*
|
||||
@ -883,8 +831,6 @@ static int pm8xxx_gpio_probe(struct platform_device *pdev)
|
||||
|
||||
unregister_gpiochip:
|
||||
gpiochip_remove(&pctrl->chip);
|
||||
err_chip_add_data:
|
||||
irq_domain_remove(pctrl->domain);
|
||||
|
||||
return ret;
|
||||
}
|
||||
@ -894,7 +840,6 @@ static int pm8xxx_gpio_remove(struct platform_device *pdev)
|
||||
struct pm8xxx_gpio *pctrl = platform_get_drvdata(pdev);
|
||||
|
||||
gpiochip_remove(&pctrl->chip);
|
||||
irq_domain_remove(pctrl->domain);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user