Skip to contentSkip to conversation

irqchip: Add driver for Cirrus Logic Madera codecs

PATCH Superseded Richard Fitzgerald 2 participants 3 messages Sep 14, 2018

Subsystems (2)
lore
Share & tools
lore

Richard Fitzgerald

author maintainer
#0 lore raw

PATCH v13 1/1 irqchip: Add driver for Cirrus Logic Madera codecs

The Cirrus Logic Madera codecs (Cirrus Logic CS47L35/85/90/91 and WM1840) are highly complex devices containing up to 7 programmable DSPs and many other internal sources of interrupts plus a number of GPIOs that can be used as interrupt inputs. The large number (>150) of internal interrupt sources are managed by an on-board interrupt controller.

This driver provides the handling for the interrupt controller. As the codec is accessed via regmap, we can make use of the generic IRQ functionality from regmap to do most of the work. Only around half of the possible interrupt source are currently of interest from the driver so only this subset is defined. Others can be added in future if needed.

The KConfig options are not user-configurable because this driver is mandatory so is automatically included when the parent MFD driver is selected.

---
Only difference from v11 is the copyright headers

---
 MAINTAINERS                        |   2 +
 drivers/irqchip/Kconfig            |   3 +
 drivers/irqchip/Makefile           |   1 +
 drivers/irqchip/irq-madera.c       | 256 +++++++++++++++++++++++++++++++++++++
 include/linux/irqchip/irq-madera.h | 132 +++++++++++++++++++
 5 files changed, 394 insertions(+)
 create mode 100644 drivers/irqchip/irq-madera.c
 create mode 100644 include/linux/irqchip/irq-madera.h
MAINTAINERS +2 -0
index bb65f0c1861c..faff2f72ab29 100644
@@ -3595,8 +3595,10 @@ W:	https://github.com/CirrusLogic/linux-drivers/wiki
 S:	Supported
 F:	Documentation/devicetree/bindings/mfd/madera.txt
 F:	Documentation/devicetree/bindings/pinctrl/cirrus,madera-pinctrl.txt
+F:	include/linux/irqchip/irq-madera*
 F:	include/linux/mfd/madera/*
 F:	drivers/gpio/gpio-madera*
+F:	drivers/irqchip/irq-madera*
 F:	drivers/mfd/madera*
 F:	drivers/mfd/cs47l*
 F:	drivers/pinctrl/cirrus/*
drivers/irqchip/Kconfig +3 -0
index 383e7b70221d..0afe6bdd2074 100644
@@ -150,6 +150,9 @@ config IMGPDC_IRQ
 	select GENERIC_IRQ_CHIP
 	select IRQ_DOMAIN
 
+config MADERA_IRQ
+	tristate
+
 config IRQ_MIPS_CPU
 	bool
 	select GENERIC_IRQ_CHIP
drivers/irqchip/Makefile +1 -0
index fbd1ec8070ef..97838212d8e4 100644
@@ -88,3 +88,4 @@ obj-$(CONFIG_GOLDFISH_PIC) 		+= irq-goldfish-pic.o
 obj-$(CONFIG_NDS32)			+= irq-ativic32.o
 obj-$(CONFIG_QCOM_PDC)			+= qcom-pdc.o
 obj-$(CONFIG_SIFIVE_PLIC)		+= irq-sifive-plic.o
+obj-$(CONFIG_MADERA_IRQ)		+= irq-madera.o
drivers/irqchip/irq-madera.c new file +256 -0

256 lines not on this page · raw message

include/linux/irqchip/irq-madera.h new file +132 -0

132 lines not on this page · raw message

Signature · 1 line
2.11.0
#1 lore raw
Quoted 31 lines · Richard Fitzgerald

The Cirrus Logic Madera codecs (Cirrus Logic CS47L35/85/90/91 and WM1840) are highly complex devices containing up to 7 programmable DSPs and many other internal sources of interrupts plus a number of GPIOs that can be used as interrupt inputs. The large number (>150) of internal interrupt sources are managed by an on-board interrupt controller.

This driver provides the handling for the interrupt controller. As the codec is accessed via regmap, we can make use of the generic IRQ functionality from regmap to do most of the work. Only around half of the possible interrupt source are currently of interest from the driver so only this subset is defined. Others can be added in future if needed.

The KConfig options are not user-configurable because this driver is mandatory so is automatically included when the parent MFD driver is selected.

---
Only difference from v11 is the copyright headers

---
 MAINTAINERS                        |   2 +
 drivers/irqchip/Kconfig            |   3 +
 drivers/irqchip/Makefile           |   1 +
 drivers/irqchip/irq-madera.c       | 256 +++++++++++++++++++++++++++++++++++++
 include/linux/irqchip/irq-madera.h | 132 +++++++++++++++++++
 5 files changed, 394 insertions(+)
 create mode 100644 drivers/irqchip/irq-madera.c
 create mode 100644 include/linux/irqchip/irq-madera.h

[...]

Quoted 5 lines
drivers/irqchip/irq-madera.c new file +0 -0
new file mode 100644
index 000000000000..e9256dee1a45

[...]

Quoted 28 lines
drivers/irqchip/irq-madera.c new file +28 -0
+static int madera_irq_probe(struct platform_device *pdev)
+{
+	struct madera *madera = dev_get_drvdata(pdev->dev.parent);
+	struct irq_data *irq_data;
+	unsigned int irq_flags = 0;
+	int ret;
+
+	dev_dbg(&pdev->dev, "probe\n");
+
+	/*
+	 * Read the flags from the interrupt controller if not specified
+	 * by pdata
+	 */
+	irq_flags = madera->pdata.irq_flags;
+	if (!irq_flags) {
+		irq_data = irq_get_irq_data(madera->irq);
+		if (!irq_data) {
+			dev_err(&pdev->dev, "Invalid IRQ: %d\n", madera->irq);
+			return -EINVAL;
+		}
+
+		irq_flags = irqd_get_trigger_type(irq_data);
+
+		/* Codec defaults to trigger low, use this if no flags given */
+		if (irq_flags == IRQ_TYPE_NONE)
+			irq_flags = IRQF_TRIGGER_LOW;
+	}
+

drivers/irqchip/irq-madera.c line 202

Quoted 10 lines
drivers/irqchip/irq-madera.c new file +10 -0
+	if (irq_flags & (IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING)) {
+		dev_err(&pdev->dev, "Host interrupt not level-triggered\n");
+		return -EINVAL;
+	}
+
+	/*
+	 * The silicon always starts at active-low, check if we need to
+	 * switch to active-high.
+	 */
+	if (irq_flags & IRQF_TRIGGER_HIGH) {

Is it safe to assume that the HW is in its reset state? What if the firmware has configured it otherwise, or if gone through kexec?

Quoted 15 lines
drivers/irqchip/irq-madera.c new file +15 -0
+		ret = regmap_update_bits(madera->regmap, MADERA_IRQ1_CTRL,
+					 MADERA_IRQ_POL_MASK, 0);
+		if (ret) {
+			dev_err(&pdev->dev,
+				"Failed to set IRQ polarity: %d\n", ret);
+			return ret;
+		}
+	}
+
+	/*
+	 * NOTE: regmap registers this against the OF node of the parent of
+	 * the regmap - that is, against the mfd driver
+	 */
+	ret = regmap_add_irq_chip(madera->regmap, madera->irq, IRQF_ONESHOT, 0,
+				  &madera_irq_chip, &madera->irq_data);

drivers/irqchip/irq-madera.c line 227

Quoted 10 lines
drivers/irqchip/irq-madera.c new file +10 -0
+	if (ret) {
+		dev_err(&pdev->dev, "add_irq_chip failed: %d\n", ret);
+		return ret;
+	}
+
+	/* Save dev in parent MFD struct so it is accessible to siblings */
+	madera->irq_dev = &pdev->dev;
+
+	return 0;
+}

Thanks,

	M.
Signature · 1 line
Jazz is not dead, it just smell funny.
author maintainer
#2 lore raw
Quoted 77 lines · Marc Zyngier
Quoted 31 lines · Richard Fitzgerald

The Cirrus Logic Madera codecs (Cirrus Logic CS47L35/85/90/91 and WM1840) are highly complex devices containing up to 7 programmable DSPs and many other internal sources of interrupts plus a number of GPIOs that can be used as interrupt inputs. The large number (>150) of internal interrupt sources are managed by an on-board interrupt controller.

This driver provides the handling for the interrupt controller. As the codec is accessed via regmap, we can make use of the generic IRQ functionality from regmap to do most of the work. Only around half of the possible interrupt source are currently of interest from the driver so only this subset is defined. Others can be added in future if needed.

The KConfig options are not user-configurable because this driver is mandatory so is automatically included when the parent MFD driver is selected.

---
Only difference from v11 is the copyright headers

---
  MAINTAINERS                        |   2 +
  drivers/irqchip/Kconfig            |   3 +
  drivers/irqchip/Makefile           |   1 +
  drivers/irqchip/irq-madera.c       | 256 +++++++++++++++++++++++++++++++++++++
  include/linux/irqchip/irq-madera.h | 132 +++++++++++++++++++
  5 files changed, 394 insertions(+)

create mode 100644 drivers/irqchip/irq-madera.c create mode 100644 include/linux/irqchip/irq-madera.h

[...]

Quoted 5 lines
drivers/irqchip/irq-madera.c new file +0 -0
new file mode 100644
index 000000000000..e9256dee1a45

[...]

Quoted 33 lines
drivers/irqchip/irq-madera.c new file +33 -0
+static int madera_irq_probe(struct platform_device *pdev)
+{
+	struct madera *madera = dev_get_drvdata(pdev->dev.parent);
+	struct irq_data *irq_data;
+	unsigned int irq_flags = 0;
+	int ret;
+
+	dev_dbg(&pdev->dev, "probe\n");
+
+	/*
+	 * Read the flags from the interrupt controller if not specified
+	 * by pdata
+	 */
+	irq_flags = madera->pdata.irq_flags;
+	if (!irq_flags) {
+		irq_data = irq_get_irq_data(madera->irq);
+		if (!irq_data) {
+			dev_err(&pdev->dev, "Invalid IRQ: %d\n", madera->irq);
+			return -EINVAL;
+		}
+
+		irq_flags = irqd_get_trigger_type(irq_data);
+
+		/* Codec defaults to trigger low, use this if no flags given */
+		if (irq_flags == IRQ_TYPE_NONE)
+			irq_flags = IRQF_TRIGGER_LOW;
+	}
+
+	if (irq_flags & (IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING)) {
+		dev_err(&pdev->dev, "Host interrupt not level-triggered\n");
+		return -EINVAL;
+	}
+
Quoted 9 lines

drivers/irqchip/irq-madera.c line 202

Quoted 5 lines
drivers/irqchip/irq-madera.c new file +5 -0
+	/*
+	 * The silicon always starts at active-low, check if we need to
+	 * switch to active-high.
+	 */
+	if (irq_flags & IRQF_TRIGGER_HIGH) {

Is it safe to assume that the HW is in its reset state? What if the firmware has configured it otherwise, or if gone through kexec?

The parent mfd probe always resets the silicon before registering the children. If this driver were to be removed and reprobed without reprobing the parent mfd, these lines of code are irrelevant because the regmap cache would still preserve the correct setting.
The DSP firmware is not allowed to change the host IRQ configuration or reset the silicon. Firmwares can only be loaded via ALSA/ASoC and the driver for that cannot complete probe until the irqchip driver has probed,

Quoted 30 lines
Quoted 15 lines
drivers/irqchip/irq-madera.c new file +15 -0
+		ret = regmap_update_bits(madera->regmap, MADERA_IRQ1_CTRL,
+					 MADERA_IRQ_POL_MASK, 0);
+		if (ret) {
+			dev_err(&pdev->dev,
+				"Failed to set IRQ polarity: %d\n", ret);
+			return ret;
+		}
+	}
+
+	/*
+	 * NOTE: regmap registers this against the OF node of the parent of
+	 * the regmap - that is, against the mfd driver
+	 */
+	ret = regmap_add_irq_chip(madera->regmap, madera->irq, IRQF_ONESHOT, 0,
+				  &madera_irq_chip, &madera->irq_data);

drivers/irqchip/irq-madera.c line 227

Quoted 10 lines
drivers/irqchip/irq-madera.c new file +10 -0
+	if (ret) {
+		dev_err(&pdev->dev, "add_irq_chip failed: %d\n", ret);
+		return ret;
+	}
+
+	/* Save dev in parent MFD struct so it is accessible to siblings */
+	madera->irq_dev = &pdev->dev;
+
+	return 0;
+}

Thanks,

	M.