diff mbox series

[07/10] irqchip/cs42l43: Add support for the cs42l43 IRQs

Message ID 20230512122838.243002-8-ckeepax@opensource.cirrus.com
State New
Headers show
Series Add cs42l43 PC focused SoundWire CODEC | expand

Commit Message

Charles Keepax May 12, 2023, 12:28 p.m. UTC
The CS42L43 is an audio CODEC with integrated MIPI SoundWire interface
(Version 1.2.1 compliant), I2C, SPI, and I2S/TDM interfaces designed
for portable applications. It provides a high dynamic range, stereo
DAC for headphone output, two integrated Class D amplifiers for
loudspeakers, and two ADCs for wired headset microphone input or
stereo line input. PDM inputs are provided for digital microphones.

The IRQ chip provides IRQ functionality both to other parts of the
cs42l43 device and to external devices that wish to use its IRQs.

Signed-off-by: Charles Keepax <ckeepax@opensource.cirrus.com>
---
 MAINTAINERS                     |   2 +
 drivers/irqchip/Kconfig         |   9 ++
 drivers/irqchip/Makefile        |   1 +
 drivers/irqchip/irq-cs42l43.c   | 170 ++++++++++++++++++++++++++++++++
 include/linux/irqchip/cs42l43.h |  61 ++++++++++++
 5 files changed, 243 insertions(+)
 create mode 100644 drivers/irqchip/irq-cs42l43.c
 create mode 100644 include/linux/irqchip/cs42l43.h

Comments

Marc Zyngier May 12, 2023, 3:10 p.m. UTC | #1
On Fri, 12 May 2023 13:28:35 +0100,
Charles Keepax <ckeepax@opensource.cirrus.com> wrote:
> 
> The CS42L43 is an audio CODEC with integrated MIPI SoundWire interface
> (Version 1.2.1 compliant), I2C, SPI, and I2S/TDM interfaces designed
> for portable applications. It provides a high dynamic range, stereo
> DAC for headphone output, two integrated Class D amplifiers for
> loudspeakers, and two ADCs for wired headset microphone input or
> stereo line input. PDM inputs are provided for digital microphones.
> 
> The IRQ chip provides IRQ functionality both to other parts of the
> cs42l43 device and to external devices that wish to use its IRQs.

Sorry, but this isn't much of an interrupt controller driver. A modern
interrupt controller driver is firmware-driven (DT or ACPI, pick your
poison), uses irq domains, and uses the irqchip API.

This is just a another variant of the board-file theme, which has
nothing to do with the irqchip subsystem.

	M.
Krzysztof Kozlowski May 12, 2023, 3:27 p.m. UTC | #2
On 12/05/2023 14:28, Charles Keepax wrote:
> The CS42L43 is an audio CODEC with integrated MIPI SoundWire interface
> (Version 1.2.1 compliant), I2C, SPI, and I2S/TDM interfaces designed
> for portable applications. It provides a high dynamic range, stereo
> DAC for headphone output, two integrated Class D amplifiers for
> loudspeakers, and two ADCs for wired headset microphone input or
> stereo line input. PDM inputs are provided for digital microphones.
> 
> The IRQ chip provides IRQ functionality both to other parts of the
> cs42l43 device and to external devices that wish to use its IRQs.
> 
> Signed-off-by: Charles Keepax <ckeepax@opensource.cirrus.com>

Thank you for your patch. There is something to discuss/improve.

> +
> +static struct platform_driver cs42l43_irq_driver = {
> +	.driver = {
> +		.name	= "cs42l43-irq",
> +	},
> +
> +	.probe		= cs42l43_irq_probe,
> +	.remove		= cs42l43_irq_remove,
> +};
> +module_platform_driver(cs42l43_irq_driver);
> +
> +MODULE_DESCRIPTION("CS42L43 IRQ Driver");
> +MODULE_AUTHOR("Charles Keepax <ckeepax@opensource.cirrus.com>");
> +MODULE_LICENSE("GPL");
> +MODULE_ALIAS("platform:cs42l43-irq");

You miss the ID table. Don't add aliases for missing ID entries. They do
not scale and it is not their purpose.

> diff --git a/include/linux/irqchip/cs42l43.h b/include/linux/irqchip/cs42l43.h
> new file mode 100644
> index 0000000000000..99ce0dbc96a77
> --- /dev/null
> +++ b/include/linux/irqchip/cs42l43.h
> @@ -0,0 +1,61 @@
> +/* SPDX-License-Identifier: GPL-2.0 */
> +/*
> + * CS42L43 IRQ driver external data
> + *
> + * Copyright (C) 2022-2023 Cirrus Logic, Inc. and
> + *                         Cirrus Logic International Semiconductor Ltd.
> + */
> +
> +#ifndef CS42L43_IRQ_EXT_H
> +#define CS42L43_IRQ_EXT_H
> +
> +enum cs42l43_irq_numbers {
> +	CS42L43_PLL_LOST_LOCK,
> +	CS42L43_PLL_READY,
> +

Are these really used by other subsystems? Your IRQ handling should be
anyway next to the driver.

Best regards,
Krzysztof
Charles Keepax May 12, 2023, 3:39 p.m. UTC | #3
On Fri, May 12, 2023 at 04:10:05PM +0100, Marc Zyngier wrote:
> On Fri, 12 May 2023 13:28:35 +0100,
> Charles Keepax <ckeepax@opensource.cirrus.com> wrote:
> > 
> > The CS42L43 is an audio CODEC with integrated MIPI SoundWire interface
> > (Version 1.2.1 compliant), I2C, SPI, and I2S/TDM interfaces designed
> > for portable applications. It provides a high dynamic range, stereo
> > DAC for headphone output, two integrated Class D amplifiers for
> > loudspeakers, and two ADCs for wired headset microphone input or
> > stereo line input. PDM inputs are provided for digital microphones.
> > 
> > The IRQ chip provides IRQ functionality both to other parts of the
> > cs42l43 device and to external devices that wish to use its IRQs.
> 
> Sorry, but this isn't much of an interrupt controller driver. A modern
> interrupt controller driver is firmware-driven (DT or ACPI, pick your
> poison), uses irq domains, and uses the irqchip API.
> 

Apologies but I really need a little help clarifying the issues
here. I am totally happy to fix things up but might need a couple
pointers.

1) uses the irqchip API / uses irq domains

The driver does use both the irqchip API and domains, what
part of the IRQ API are we not using that we should be?

The driver registers an irq domain using
irq_domain_create_linear.  It requests its parent IRQ using
request_threaded_irq. It passes IRQs onto the devices requesting
IRQs from it using handle_nested_irq and irq_find_mapping.

Is the objection here that regmap is making these calls for us,
rather than them being hard coded into this driver?

2) driver is firmware-driven (DT or ACPI, pick your poison)

The irq chip has representation in firmware, in fact we have
tested this on both ACPI and DT. Other devices can request
IRQs from it through firmware, same as they can for any other
IRQ chip.

Is the objection here the table mapping the register fields that
are provided as an IRQ on the device?

Thanks kindly for your review and help,
Charles
Charles Keepax May 12, 2023, 4:42 p.m. UTC | #4
On Fri, May 12, 2023 at 05:07:45PM +0100, Marc Zyngier wrote:
> On Fri, 12 May 2023 16:39:33 +0100,
> Charles Keepax <ckeepax@opensource.cirrus.com> wrote:
> > On Fri, May 12, 2023 at 04:10:05PM +0100, Marc Zyngier wrote:
> > > On Fri, 12 May 2023 13:28:35 +0100,
> > > Charles Keepax <ckeepax@opensource.cirrus.com> wrote:
> > Is the objection here that regmap is making these calls for us,
> > rather than them being hard coded into this driver?
> 
> That's one of the reasons. Look at the existing irqchip drivers: they
> have nothing in common with yours. The regmap irqchip abstraction may
> be convenient for what you are doing, but the result isn't really an
> irqchip driver. It is something that is a small bit of a larger device
> and not an interrupt controller driver on its own. The irqchip
> subsystem is there for "first class" interrupt controllers.
> 

Thank you this is helpful. This device has GPIOs that other
devices might want to use for IRQs, so the chip is capable
of providing IRQ services to other devices in the system not
just itself. This is commonly used where external boosted
amps have their IRQs hooked up to the CODEC.

I guess if Mark doesn't mind I think the only internal bit of the
device that uses the IRQs is the CODEC driver so I could move the
IRQ handling in there, it does seem a little odd to me, but I
guess I don't have any problems with it.

> > Is the objection here the table mapping the register fields that
> > are provided as an IRQ on the device?
> 
> I'm referring to this sort of construct:
> 
> +	CS42L43_IRQ_REG(HP_STARTUP_DONE,			MSM),
> +	CS42L43_IRQ_REG(HP_SHUTDOWN_DONE,			MSM),
> +	CS42L43_IRQ_REG(HSDET_DONE,				MSM),
> +	CS42L43_IRQ_REG(TIPSENSE_UNPLUG_DB,			MSM),
> +	CS42L43_IRQ_REG(TIPSENSE_PLUG_DB,			MSM),
> +	CS42L43_IRQ_REG(RINGSENSE_UNPLUG_DB,			MSM),
> +	CS42L43_IRQ_REG(RINGSENSE_PLUG_DB,			MSM),
> +	CS42L43_IRQ_REG(TIPSENSE_UNPLUG_PDET,			MSM),
> +	CS42L43_IRQ_REG(TIPSENSE_PLUG_PDET,			MSM),
> +	CS42L43_IRQ_REG(RINGSENSE_UNPLUG_PDET,			MSM),
> +	CS42L43_IRQ_REG(RINGSENSE_PLUG_PDET,			MSM),
> 
> Why isn't this described in firmware tables?

So we probably could do that for device tree systems, but getting
this into ACPI I think will be exceedingly difficult, and that is
likely the primary market for the device.

> Why doesn't it need to be
> carried as part of the driver? Is "CLASS_D_AMP" something an interrupt
> controller driver should care about?

Ah ok so I think I am starting to understand, if I might
paraphrase, your main objection here is that many of the IRQs are
fixed purpose signals originating inside the chip itself, rather
than external lines that can be hooked up for generic purposes.

I guess most "first class" IRQ controllers have a lot more
generic IRQs than they do fixed purpose ones. Where as we only
have the 3 GPIOs as generic purpose IRQ lines.

Thanks,
Charles
Lee Jones May 16, 2023, 10:09 a.m. UTC | #5
On Tue, 16 May 2023, Marc Zyngier wrote:

> On Mon, 15 May 2023 12:25:54 +0100,
> Lee Jones <lee@kernel.org> wrote:
> > 
> > On Fri, 12 May 2023, Marc Zyngier wrote:
> > 
> > > On Fri, 12 May 2023 16:39:33 +0100,
> > > Charles Keepax <ckeepax@opensource.cirrus.com> wrote:
> > > > 
> > > > On Fri, May 12, 2023 at 04:10:05PM +0100, Marc Zyngier wrote:
> > > > > On Fri, 12 May 2023 13:28:35 +0100,
> > > > > Charles Keepax <ckeepax@opensource.cirrus.com> wrote:
> > > > > > 
> > > > > > The CS42L43 is an audio CODEC with integrated MIPI SoundWire interface
> > > > > > (Version 1.2.1 compliant), I2C, SPI, and I2S/TDM interfaces designed
> > > > > > for portable applications. It provides a high dynamic range, stereo
> > > > > > DAC for headphone output, two integrated Class D amplifiers for
> > > > > > loudspeakers, and two ADCs for wired headset microphone input or
> > > > > > stereo line input. PDM inputs are provided for digital microphones.
> > > > > > 
> > > > > > The IRQ chip provides IRQ functionality both to other parts of the
> > > > > > cs42l43 device and to external devices that wish to use its IRQs.
> > > > > 
> > > > > Sorry, but this isn't much of an interrupt controller driver. A modern
> > > > > interrupt controller driver is firmware-driven (DT or ACPI, pick your
> > > > > poison), uses irq domains, and uses the irqchip API.
> > > > > 
> > > > 
> > > > Apologies but I really need a little help clarifying the issues
> > > > here. I am totally happy to fix things up but might need a couple
> > > > pointers.
> > > > 
> > > > 1) uses the irqchip API / uses irq domains
> > > > 
> > > > The driver does use both the irqchip API and domains, what
> > > > part of the IRQ API are we not using that we should be?
> > > > 
> > > > The driver registers an irq domain using
> > > > irq_domain_create_linear.  It requests its parent IRQ using
> > > > request_threaded_irq. It passes IRQs onto the devices requesting
> > > > IRQs from it using handle_nested_irq and irq_find_mapping.
> > > > 
> > > > Is the objection here that regmap is making these calls for us,
> > > > rather than them being hard coded into this driver?
> > > 
> > > That's one of the reasons. Look at the existing irqchip drivers: they
> > > have nothing in common with yours. The regmap irqchip abstraction may
> > > be convenient for what you are doing, but the result isn't really an
> > > irqchip driver. It is something that is a small bit of a larger device
> > > and not an interrupt controller driver on its own. The irqchip
> > > subsystem is there for "first class" interrupt controllers.
> > 
> > I'm not aware of another subsystem that deals with !IRQChip level IRQ
> > controllers.  Where do simple or "second class" interrupt controllers
> > go?
> 
> This isn't an interrupt controller. This is internal signalling, local
> to a single component that has been artificially broken into discrete
> bits, including an interrupt controller. The only *real* interrupts
> here are the GPIOs.
> 
> I'm happy to see an interrupt controller for the GPIOs. But the rest
> is just internal muck that doesn't really belong here. Where should it

You should have been a poet! =;-)

> go? Together with the rest of the stuff that manages the block as a
> whole. Which looks like the MFD subsystem to me.

Very well.  Let's see this "muck" in a patch please!
Charles Keepax May 16, 2023, 10:41 a.m. UTC | #6
On Tue, May 16, 2023 at 11:09:36AM +0100, Lee Jones wrote:
> On Tue, 16 May 2023, Marc Zyngier wrote:
> > On Mon, 15 May 2023 12:25:54 +0100,
> > Lee Jones <lee@kernel.org> wrote:
> > > On Fri, 12 May 2023, Marc Zyngier wrote:
> > > > On Fri, 12 May 2023 16:39:33 +0100,
> > > > Charles Keepax <ckeepax@opensource.cirrus.com> wrote:
> > > I'm not aware of another subsystem that deals with !IRQChip level IRQ
> > > controllers.  Where do simple or "second class" interrupt controllers
> > > go?
> > 
> > This isn't an interrupt controller. This is internal signalling, local
> > to a single component that has been artificially broken into discrete
> > bits, including an interrupt controller. The only *real* interrupts
> > here are the GPIOs.
> > 

I would question this statement a little, they are fixed function
IRQs sure but they are still real interrupts. These are lines which
receive a signal and on an edge they set a stick status bit, which
causes another signal to generate an edge, they have registers
which let you mask events, if it walks like a duck and all. The
only difference between this and a "real" interrupt is whether the
chip designer or the board designer was the person who decided
where the wire was connected.

> > I'm happy to see an interrupt controller for the GPIOs. But the rest
> > is just internal muck that doesn't really belong here. Where should it

Internal-ish, granted many of them are primarily useful to the
device itself. But it is very easy to construct situations where
say knowing the speaker thermals are high, or that a jack has
been inserted are useful outside of the CODEC driver itself.

> > go? Together with the rest of the stuff that manages the block as a
> > whole. Which looks like the MFD subsystem to me.
> 
> Very well.  Let's see this "muck" in a patch please!

Groovy I will do a re-spin moving the IRQ stuff to the MFD and
lets see where we get to.

Thank you all for your help in reviewing this so far.

Thanks,
Charles
diff mbox series

Patch

diff --git a/MAINTAINERS b/MAINTAINERS
index 8d2076941ff36..13945ee6cdcfe 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -4928,8 +4928,10 @@  L:	patches@opensource.cirrus.com
 S:	Maintained
 F:	Documentation/devicetree/bindings/mfd/cirrus,cs*
 F:	Documentation/devicetree/bindings/sound/cirrus,cs*
+F:	drivers/irqchip/irq-cs42l43*
 F:	drivers/mfd/cs42l43*
 F:	include/dt-bindings/sound/cs*
+F:	include/linux/irqchip/cs42l43*
 F:	include/linux/mfd/cs42l43*
 F:	include/sound/cs*
 F:	sound/pci/hda/cs*
diff --git a/drivers/irqchip/Kconfig b/drivers/irqchip/Kconfig
index 09e422da482ff..05f58015749e3 100644
--- a/drivers/irqchip/Kconfig
+++ b/drivers/irqchip/Kconfig
@@ -138,6 +138,15 @@  config BRCMSTB_L2_IRQ
 	select GENERIC_IRQ_CHIP
 	select IRQ_DOMAIN
 
+config IRQ_CS42L43
+	tristate "Cirrus Logic CS42L43 IRQ Controller"
+	depends on MFD_CS42L43
+	select REGMAP_IRQ
+	help
+	  Select this to support the IRQ functions of the Cirrus Logic
+	  CS42L43 PC CODEC, note the IRQs are required for most other
+	  functions of the device.
+
 config DAVINCI_CP_INTC
 	bool
 	select GENERIC_IRQ_CHIP
diff --git a/drivers/irqchip/Makefile b/drivers/irqchip/Makefile
index ffd945fe71aa2..d00330c1b0b95 100644
--- a/drivers/irqchip/Makefile
+++ b/drivers/irqchip/Makefile
@@ -66,6 +66,7 @@  obj-$(CONFIG_BCM6345_L1_IRQ)		+= irq-bcm6345-l1.o
 obj-$(CONFIG_BCM7038_L1_IRQ)		+= irq-bcm7038-l1.o
 obj-$(CONFIG_BCM7120_L2_IRQ)		+= irq-bcm7120-l2.o
 obj-$(CONFIG_BRCMSTB_L2_IRQ)		+= irq-brcmstb-l2.o
+obj-$(CONFIG_IRQ_CS42L43)		+= irq-cs42l43.o
 obj-$(CONFIG_KEYSTONE_IRQ)		+= irq-keystone.o
 obj-$(CONFIG_MIPS_GIC)			+= irq-mips-gic.o
 obj-$(CONFIG_ARCH_MEDIATEK)		+= irq-mtk-sysirq.o irq-mtk-cirq.o
diff --git a/drivers/irqchip/irq-cs42l43.c b/drivers/irqchip/irq-cs42l43.c
new file mode 100644
index 0000000000000..fc55cbdc08647
--- /dev/null
+++ b/drivers/irqchip/irq-cs42l43.c
@@ -0,0 +1,170 @@ 
+// SPDX-License-Identifier: GPL-2.0
+//
+// CS42L43 IRQ driver
+//
+// Copyright (C) 2022-2023 Cirrus Logic, Inc. and
+//                         Cirrus Logic International Semiconductor Ltd.
+
+#include <linux/device.h>
+#include <linux/errno.h>
+#include <linux/interrupt.h>
+#include <linux/irq.h>
+#include <linux/irqchip/cs42l43.h>
+#include <linux/mfd/cs42l43.h>
+#include <linux/mfd/cs42l43-regs.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/pm_runtime.h>
+#include <linux/regmap.h>
+
+#define CS42L43_IRQ_OFFSET(reg) ((CS42L43_##reg##_INT) - CS42L43_DECIM_INT)
+
+#define CS42L43_IRQ_REG(name, reg) REGMAP_IRQ_REG(CS42L43_##name, \
+						  CS42L43_IRQ_OFFSET(reg), \
+						  CS42L43_##name##_INT_MASK)
+
+static const struct regmap_irq cs42l43_regmap_irqs[] = {
+	CS42L43_IRQ_REG(PLL_LOST_LOCK,				PLL),
+	CS42L43_IRQ_REG(PLL_READY,				PLL),
+
+	CS42L43_IRQ_REG(HP_STARTUP_DONE,			MSM),
+	CS42L43_IRQ_REG(HP_SHUTDOWN_DONE,			MSM),
+	CS42L43_IRQ_REG(HSDET_DONE,				MSM),
+	CS42L43_IRQ_REG(TIPSENSE_UNPLUG_DB,			MSM),
+	CS42L43_IRQ_REG(TIPSENSE_PLUG_DB,			MSM),
+	CS42L43_IRQ_REG(RINGSENSE_UNPLUG_DB,			MSM),
+	CS42L43_IRQ_REG(RINGSENSE_PLUG_DB,			MSM),
+	CS42L43_IRQ_REG(TIPSENSE_UNPLUG_PDET,			MSM),
+	CS42L43_IRQ_REG(TIPSENSE_PLUG_PDET,			MSM),
+	CS42L43_IRQ_REG(RINGSENSE_UNPLUG_PDET,			MSM),
+	CS42L43_IRQ_REG(RINGSENSE_PLUG_PDET,			MSM),
+
+	CS42L43_IRQ_REG(HS2_BIAS_SENSE,				ACC_DET),
+	CS42L43_IRQ_REG(HS1_BIAS_SENSE,				ACC_DET),
+	CS42L43_IRQ_REG(DC_DETECT1_FALSE,			ACC_DET),
+	CS42L43_IRQ_REG(DC_DETECT1_TRUE,			ACC_DET),
+	CS42L43_IRQ_REG(HSBIAS_CLAMPED,				ACC_DET),
+	CS42L43_IRQ_REG(HS3_4_BIAS_SENSE,			ACC_DET),
+
+	CS42L43_IRQ_REG(AMP2_CLK_STOP_FAULT,			CLASS_D_AMP),
+	CS42L43_IRQ_REG(AMP1_CLK_STOP_FAULT,			CLASS_D_AMP),
+	CS42L43_IRQ_REG(AMP2_VDDSPK_FAULT,			CLASS_D_AMP),
+	CS42L43_IRQ_REG(AMP1_VDDSPK_FAULT,			CLASS_D_AMP),
+	CS42L43_IRQ_REG(AMP2_SHUTDOWN_DONE,			CLASS_D_AMP),
+	CS42L43_IRQ_REG(AMP1_SHUTDOWN_DONE,			CLASS_D_AMP),
+	CS42L43_IRQ_REG(AMP2_STARTUP_DONE,			CLASS_D_AMP),
+	CS42L43_IRQ_REG(AMP1_STARTUP_DONE,			CLASS_D_AMP),
+	CS42L43_IRQ_REG(AMP2_THERM_SHDN,			CLASS_D_AMP),
+	CS42L43_IRQ_REG(AMP1_THERM_SHDN,			CLASS_D_AMP),
+	CS42L43_IRQ_REG(AMP2_THERM_WARN,			CLASS_D_AMP),
+	CS42L43_IRQ_REG(AMP1_THERM_WARN,			CLASS_D_AMP),
+	CS42L43_IRQ_REG(AMP2_SCDET,				CLASS_D_AMP),
+	CS42L43_IRQ_REG(AMP1_SCDET,				CLASS_D_AMP),
+
+	CS42L43_IRQ_REG(GPIO3_FALL,				GPIO),
+	CS42L43_IRQ_REG(GPIO3_RISE,				GPIO),
+	CS42L43_IRQ_REG(GPIO2_FALL,				GPIO),
+	CS42L43_IRQ_REG(GPIO2_RISE,				GPIO),
+	CS42L43_IRQ_REG(GPIO1_FALL,				GPIO),
+	CS42L43_IRQ_REG(GPIO1_RISE,				GPIO),
+
+	CS42L43_IRQ_REG(HP_ILIMIT,				HPOUT),
+	CS42L43_IRQ_REG(HP_LOADDET_DONE,			HPOUT),
+};
+
+static const struct regmap_irq_chip cs42l43_irq_chip = {
+	.name = "cs42l43",
+
+	.status_base = CS42L43_DECIM_INT,
+	.mask_base = CS42L43_DECIM_MASK,
+	.num_regs = 16,
+
+	.irqs = cs42l43_regmap_irqs,
+	.num_irqs = ARRAY_SIZE(cs42l43_regmap_irqs),
+
+	.runtime_pm = true,
+};
+
+struct cs42l43_irq {
+	struct device *dev;
+
+	struct regmap_irq_chip irq_chip;
+	struct regmap_irq_chip_data *irq_data;
+};
+
+static int cs42l43_irq_probe(struct platform_device *pdev)
+{
+	struct cs42l43 *cs42l43 = dev_get_drvdata(pdev->dev.parent);
+	struct cs42l43_irq *priv;
+	struct irq_data *irq_data;
+	unsigned long irq_flags;
+	int ret;
+
+	priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL);
+	if (!priv)
+		return -ENOMEM;
+
+	priv->dev = &pdev->dev;
+	priv->irq_chip = cs42l43_irq_chip;
+	priv->irq_chip.irq_drv_data = priv;
+
+	irq_data = irq_get_irq_data(cs42l43->irq);
+	if (!irq_data) {
+		dev_err(priv->dev, "Invalid IRQ: %d\n", cs42l43->irq);
+		return -EINVAL;
+	}
+
+	irq_flags = irqd_get_trigger_type(irq_data);
+	switch (irq_flags) {
+	case IRQF_TRIGGER_LOW:
+	case IRQF_TRIGGER_HIGH:
+	case IRQF_TRIGGER_RISING:
+	case IRQF_TRIGGER_FALLING:
+		break;
+	case IRQ_TYPE_NONE:
+	default:
+		irq_flags = IRQF_TRIGGER_LOW;
+		break;
+	}
+
+	irq_flags |= IRQF_ONESHOT;
+
+	pm_runtime_enable(priv->dev);
+	pm_runtime_idle(priv->dev);
+
+	ret = devm_regmap_add_irq_chip(priv->dev, cs42l43->regmap,
+				       cs42l43->irq, irq_flags, 0,
+				       &priv->irq_chip, &priv->irq_data);
+	if (ret) {
+		dev_err(priv->dev, "Failed to add IRQ chip: %d\n", ret);
+		pm_runtime_disable(priv->dev);
+		return ret;
+	}
+
+	dev_dbg(priv->dev, "Configured IRQ %d with flags 0x%lx\n",
+		cs42l43->irq, irq_flags);
+
+	return 0;
+}
+
+static int cs42l43_irq_remove(struct platform_device *pdev)
+{
+	pm_runtime_disable(&pdev->dev);
+
+	return 0;
+}
+
+static struct platform_driver cs42l43_irq_driver = {
+	.driver = {
+		.name	= "cs42l43-irq",
+	},
+
+	.probe		= cs42l43_irq_probe,
+	.remove		= cs42l43_irq_remove,
+};
+module_platform_driver(cs42l43_irq_driver);
+
+MODULE_DESCRIPTION("CS42L43 IRQ Driver");
+MODULE_AUTHOR("Charles Keepax <ckeepax@opensource.cirrus.com>");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:cs42l43-irq");
diff --git a/include/linux/irqchip/cs42l43.h b/include/linux/irqchip/cs42l43.h
new file mode 100644
index 0000000000000..99ce0dbc96a77
--- /dev/null
+++ b/include/linux/irqchip/cs42l43.h
@@ -0,0 +1,61 @@ 
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * CS42L43 IRQ driver external data
+ *
+ * Copyright (C) 2022-2023 Cirrus Logic, Inc. and
+ *                         Cirrus Logic International Semiconductor Ltd.
+ */
+
+#ifndef CS42L43_IRQ_EXT_H
+#define CS42L43_IRQ_EXT_H
+
+enum cs42l43_irq_numbers {
+	CS42L43_PLL_LOST_LOCK,
+	CS42L43_PLL_READY,
+
+	CS42L43_HP_STARTUP_DONE,
+	CS42L43_HP_SHUTDOWN_DONE,
+	CS42L43_HSDET_DONE,
+	CS42L43_TIPSENSE_UNPLUG_DB,
+	CS42L43_TIPSENSE_PLUG_DB,
+	CS42L43_RINGSENSE_UNPLUG_DB,
+	CS42L43_RINGSENSE_PLUG_DB,
+	CS42L43_TIPSENSE_UNPLUG_PDET,
+	CS42L43_TIPSENSE_PLUG_PDET,
+	CS42L43_RINGSENSE_UNPLUG_PDET,
+	CS42L43_RINGSENSE_PLUG_PDET,
+
+	CS42L43_HS2_BIAS_SENSE,
+	CS42L43_HS1_BIAS_SENSE,
+	CS42L43_DC_DETECT1_FALSE,
+	CS42L43_DC_DETECT1_TRUE,
+	CS42L43_HSBIAS_CLAMPED,
+	CS42L43_HS3_4_BIAS_SENSE,
+
+	CS42L43_AMP2_CLK_STOP_FAULT,
+	CS42L43_AMP1_CLK_STOP_FAULT,
+	CS42L43_AMP2_VDDSPK_FAULT,
+	CS42L43_AMP1_VDDSPK_FAULT,
+	CS42L43_AMP2_SHUTDOWN_DONE,
+	CS42L43_AMP1_SHUTDOWN_DONE,
+	CS42L43_AMP2_STARTUP_DONE,
+	CS42L43_AMP1_STARTUP_DONE,
+	CS42L43_AMP2_THERM_SHDN,
+	CS42L43_AMP1_THERM_SHDN,
+	CS42L43_AMP2_THERM_WARN,
+	CS42L43_AMP1_THERM_WARN,
+	CS42L43_AMP2_SCDET,
+	CS42L43_AMP1_SCDET,
+
+	CS42L43_GPIO3_FALL,
+	CS42L43_GPIO3_RISE,
+	CS42L43_GPIO2_FALL,
+	CS42L43_GPIO2_RISE,
+	CS42L43_GPIO1_FALL,
+	CS42L43_GPIO1_RISE,
+
+	CS42L43_HP_ILIMIT,
+	CS42L43_HP_LOADDET_DONE,
+};
+
+#endif /* CS42L43_IRQ_EXT_H */