[PATCH 4/4 v1] RFT: gpio: uniphier: Switch to GPIOLIB_IRQCHIP

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



Use the new infrastructure for hierarchical irqchips in
gpiolib.

I have no chance to test or debug this so I need
help.

Cc: Masahiro Yamada <yamada.masahiro@xxxxxxxxxxxxx>
Cc: Thierry Reding <treding@xxxxxxxxxx>
Cc: Brian Masney <masneyb@xxxxxxxxxxxxx>
Signed-off-by: Linus Walleij <linus.walleij@xxxxxxxxxx>
---
 drivers/gpio/Kconfig         |   1 +
 drivers/gpio/gpio-uniphier.c | 172 +++++++++--------------------------
 2 files changed, 45 insertions(+), 128 deletions(-)

diff --git a/drivers/gpio/Kconfig b/drivers/gpio/Kconfig
index ee34716a39aa..806d642498a6 100644
--- a/drivers/gpio/Kconfig
+++ b/drivers/gpio/Kconfig
@@ -552,6 +552,7 @@ config GPIO_UNIPHIER
 	tristate "UniPhier GPIO support"
 	depends on ARCH_UNIPHIER || COMPILE_TEST
 	depends on OF_GPIO
+	select GPIOLIB_IRQCHIP
 	select IRQ_DOMAIN_HIERARCHY
 	help
 	  Say yes here to support UniPhier GPIOs.
diff --git a/drivers/gpio/gpio-uniphier.c b/drivers/gpio/gpio-uniphier.c
index 93cdcc41e9fb..e960836b9c01 100644
--- a/drivers/gpio/gpio-uniphier.c
+++ b/drivers/gpio/gpio-uniphier.c
@@ -6,7 +6,6 @@
 #include <linux/bits.h>
 #include <linux/gpio/driver.h>
 #include <linux/irq.h>
-#include <linux/irqdomain.h>
 #include <linux/module.h>
 #include <linux/of.h>
 #include <linux/of_device.h>
@@ -30,7 +29,6 @@
 struct uniphier_gpio_priv {
 	struct gpio_chip chip;
 	struct irq_chip irq_chip;
-	struct irq_domain *domain;
 	void __iomem *regs;
 	spinlock_t lock;
 	u32 saved_vals[0];
@@ -162,49 +160,33 @@ static void uniphier_gpio_set_multiple(struct gpio_chip *chip,
 	}
 }
 
-static int uniphier_gpio_to_irq(struct gpio_chip *chip, unsigned int offset)
+static void uniphier_gpio_irq_mask(struct irq_data *d)
 {
-	struct irq_fwspec fwspec;
-
-	if (offset < UNIPHIER_GPIO_IRQ_OFFSET)
-		return -ENXIO;
-
-	fwspec.fwnode = of_node_to_fwnode(chip->parent->of_node);
-	fwspec.param_count = 2;
-	fwspec.param[0] = offset - UNIPHIER_GPIO_IRQ_OFFSET;
-	/*
-	 * IRQ_TYPE_NONE is rejected by the parent irq domain. Set LEVEL_HIGH
-	 * temporarily. Anyway, ->irq_set_type() will override it later.
-	 */
-	fwspec.param[1] = IRQ_TYPE_LEVEL_HIGH;
-
-	return irq_create_fwspec_mapping(&fwspec);
-}
-
-static void uniphier_gpio_irq_mask(struct irq_data *data)
-{
-	struct uniphier_gpio_priv *priv = data->chip_data;
-	u32 mask = BIT(data->hwirq);
+	struct gpio_chip *gc = irq_data_get_irq_chip_data(d);
+	struct uniphier_gpio_priv *priv = gpiochip_get_data(gc);
+	u32 mask = BIT(d->hwirq);
 
 	uniphier_gpio_reg_update(priv, UNIPHIER_GPIO_IRQ_EN, mask, 0);
 
-	return irq_chip_mask_parent(data);
+	return irq_chip_mask_parent(d);
 }
 
-static void uniphier_gpio_irq_unmask(struct irq_data *data)
+static void uniphier_gpio_irq_unmask(struct irq_data *d)
 {
-	struct uniphier_gpio_priv *priv = data->chip_data;
-	u32 mask = BIT(data->hwirq);
+	struct gpio_chip *gc = irq_data_get_irq_chip_data(d);
+	struct uniphier_gpio_priv *priv = gpiochip_get_data(gc);
+	u32 mask = BIT(d->hwirq);
 
 	uniphier_gpio_reg_update(priv, UNIPHIER_GPIO_IRQ_EN, mask, mask);
 
-	return irq_chip_unmask_parent(data);
+	return irq_chip_unmask_parent(d);
 }
 
-static int uniphier_gpio_irq_set_type(struct irq_data *data, unsigned int type)
+static int uniphier_gpio_irq_set_type(struct irq_data *d, unsigned int type)
 {
-	struct uniphier_gpio_priv *priv = data->chip_data;
-	u32 mask = BIT(data->hwirq);
+	struct gpio_chip *gc = irq_data_get_irq_chip_data(d);
+	struct uniphier_gpio_priv *priv = gpiochip_get_data(gc);
+	u32 mask = BIT(d->hwirq);
 	u32 val = 0;
 
 	if (type == IRQ_TYPE_EDGE_BOTH) {
@@ -216,7 +198,7 @@ static int uniphier_gpio_irq_set_type(struct irq_data *data, unsigned int type)
 	/* To enable both edge detection, the noise filter must be enabled. */
 	uniphier_gpio_reg_update(priv, UNIPHIER_GPIO_IRQ_FLT_EN, mask, val);
 
-	return irq_chip_set_type_parent(data, type);
+	return irq_chip_set_type_parent(d, type);
 }
 
 static int uniphier_gpio_irq_get_parent_hwirq(struct uniphier_gpio_priv *priv,
@@ -245,82 +227,6 @@ static int uniphier_gpio_irq_get_parent_hwirq(struct uniphier_gpio_priv *priv,
 	return -ENOENT;
 }
 
-static int uniphier_gpio_irq_domain_translate(struct irq_domain *domain,
-					      struct irq_fwspec *fwspec,
-					      unsigned long *out_hwirq,
-					      unsigned int *out_type)
-{
-	if (WARN_ON(fwspec->param_count < 2))
-		return -EINVAL;
-
-	*out_hwirq = fwspec->param[0];
-	*out_type = fwspec->param[1] & IRQ_TYPE_SENSE_MASK;
-
-	return 0;
-}
-
-static int uniphier_gpio_irq_domain_alloc(struct irq_domain *domain,
-					  unsigned int virq,
-					  unsigned int nr_irqs, void *arg)
-{
-	struct uniphier_gpio_priv *priv = domain->host_data;
-	struct irq_fwspec parent_fwspec;
-	irq_hw_number_t hwirq;
-	unsigned int type;
-	int ret;
-
-	if (WARN_ON(nr_irqs != 1))
-		return -EINVAL;
-
-	ret = uniphier_gpio_irq_domain_translate(domain, arg, &hwirq, &type);
-	if (ret)
-		return ret;
-
-	ret = uniphier_gpio_irq_get_parent_hwirq(priv, hwirq);
-	if (ret < 0)
-		return ret;
-
-	/* parent is UniPhier AIDET */
-	parent_fwspec.fwnode = domain->parent->fwnode;
-	parent_fwspec.param_count = 2;
-	parent_fwspec.param[0] = ret;
-	parent_fwspec.param[1] = (type == IRQ_TYPE_EDGE_BOTH) ?
-						IRQ_TYPE_EDGE_FALLING : type;
-
-	ret = irq_domain_set_hwirq_and_chip(domain, virq, hwirq,
-					    &priv->irq_chip, priv);
-	if (ret)
-		return ret;
-
-	return irq_domain_alloc_irqs_parent(domain, virq, 1, &parent_fwspec);
-}
-
-static int uniphier_gpio_irq_domain_activate(struct irq_domain *domain,
-					     struct irq_data *data, bool early)
-{
-	struct uniphier_gpio_priv *priv = domain->host_data;
-	struct gpio_chip *chip = &priv->chip;
-
-	return gpiochip_lock_as_irq(chip, data->hwirq + UNIPHIER_GPIO_IRQ_OFFSET);
-}
-
-static void uniphier_gpio_irq_domain_deactivate(struct irq_domain *domain,
-						struct irq_data *data)
-{
-	struct uniphier_gpio_priv *priv = domain->host_data;
-	struct gpio_chip *chip = &priv->chip;
-
-	gpiochip_unlock_as_irq(chip, data->hwirq + UNIPHIER_GPIO_IRQ_OFFSET);
-}
-
-static const struct irq_domain_ops uniphier_gpio_irq_domain_ops = {
-	.alloc = uniphier_gpio_irq_domain_alloc,
-	.free = irq_domain_free_irqs_common,
-	.activate = uniphier_gpio_irq_domain_activate,
-	.deactivate = uniphier_gpio_irq_domain_deactivate,
-	.translate = uniphier_gpio_irq_domain_translate,
-};
-
 static void uniphier_gpio_hw_init(struct uniphier_gpio_priv *priv)
 {
 	/*
@@ -338,6 +244,26 @@ static unsigned int uniphier_gpio_get_nbanks(unsigned int ngpio)
 	return DIV_ROUND_UP(ngpio, UNIPHIER_GPIO_LINES_PER_BANK);
 }
 
+static int uniphier_gpio_child_to_parent_hwirq(struct gpio_chip *gc,
+					       unsigned int child,
+					       unsigned int child_type,
+					       unsigned int *parent,
+					       unsigned int *parent_type)
+{
+	struct uniphier_gpio_priv *priv = gpiochip_get_data(gc);
+	int ret;
+
+	ret = uniphier_gpio_irq_get_parent_hwirq(priv, child);
+	if (ret < 0)
+		return ret;
+	*parent = ret;
+	if (child_type == IRQ_TYPE_EDGE_BOTH)
+		*parent_type = IRQ_TYPE_EDGE_FALLING;
+	else
+		*parent_type = child_type;
+	return 0;
+}
+
 static int uniphier_gpio_probe(struct platform_device *pdev)
 {
 	struct device *dev = &pdev->dev;
@@ -345,6 +271,7 @@ static int uniphier_gpio_probe(struct platform_device *pdev)
 	struct irq_domain *parent_domain;
 	struct uniphier_gpio_priv *priv;
 	struct gpio_chip *chip;
+	struct gpio_irq_chip *girq;
 	struct irq_chip *irq_chip;
 	unsigned int nregs;
 	u32 ngpios;
@@ -386,7 +313,6 @@ static int uniphier_gpio_probe(struct platform_device *pdev)
 	chip->get = uniphier_gpio_get;
 	chip->set = uniphier_gpio_set;
 	chip->set_multiple = uniphier_gpio_set_multiple;
-	chip->to_irq = uniphier_gpio_to_irq;
 	chip->base = -1;
 	chip->ngpio = ngpios;
 
@@ -398,34 +324,25 @@ static int uniphier_gpio_probe(struct platform_device *pdev)
 	irq_chip->irq_set_affinity = irq_chip_set_affinity_parent;
 	irq_chip->irq_set_type = uniphier_gpio_irq_set_type;
 
+	girq = &chip->irq;
+	girq->chip = irq_chip;
+	girq->fwnode = of_node_to_fwnode(dev->of_node);
+	girq->parent_domain = parent_domain;
+	girq->child_to_parent_hwirq = uniphier_gpio_child_to_parent_hwirq;
+	girq->handler = handle_bad_irq;
+	girq->default_type = IRQ_TYPE_NONE;
+
 	uniphier_gpio_hw_init(priv);
 
 	ret = devm_gpiochip_add_data(dev, chip, priv);
 	if (ret)
 		return ret;
 
-	priv->domain = irq_domain_create_hierarchy(
-					parent_domain, 0,
-					UNIPHIER_GPIO_IRQ_MAX_NUM,
-					of_node_to_fwnode(dev->of_node),
-					&uniphier_gpio_irq_domain_ops, priv);
-	if (!priv->domain)
-		return -ENOMEM;
-
 	platform_set_drvdata(pdev, priv);
 
 	return 0;
 }
 
-static int uniphier_gpio_remove(struct platform_device *pdev)
-{
-	struct uniphier_gpio_priv *priv = platform_get_drvdata(pdev);
-
-	irq_domain_remove(priv->domain);
-
-	return 0;
-}
-
 static int __maybe_unused uniphier_gpio_suspend(struct device *dev)
 {
 	struct uniphier_gpio_priv *priv = dev_get_drvdata(dev);
@@ -485,7 +402,6 @@ MODULE_DEVICE_TABLE(of, uniphier_gpio_match);
 
 static struct platform_driver uniphier_gpio_driver = {
 	.probe = uniphier_gpio_probe,
-	.remove = uniphier_gpio_remove,
 	.driver = {
 		.name = "uniphier-gpio",
 		.of_match_table = uniphier_gpio_match,
-- 
2.21.0




[Index of Archives]     [Linux SPI]     [Linux Kernel]     [Linux ARM (vger)]     [Linux ARM MSM]     [Linux Omap]     [Linux Arm]     [Linux Tegra]     [Fedora ARM]     [Linux for Samsung SOC]     [eCos]     [Linux Fastboot]     [Gcc Help]     [Git]     [DCCP]     [IETF Announce]     [Security]     [Linux MIPS]     [Yosemite Campsites]

  Powered by Linux