From mboxrd@z Thu Jan 1 00:00:00 1970 From: Jason Cooper Subject: Re: [PATCH 2/6] irqchip: Supply new driver for STi based devices Date: Mon, 18 Aug 2014 08:32:08 -0400 Message-ID: <20140818123208.GR12769@titan.lakedaemon.net> References: <1406642744-22589-1-git-send-email-lee.jones@linaro.org> <1406642744-22589-3-git-send-email-lee.jones@linaro.org> Mime-Version: 1.0 Content-Type: text/plain; charset=utf-8 Content-Transfer-Encoding: QUOTED-PRINTABLE Return-path: Content-Disposition: inline In-Reply-To: <1406642744-22589-3-git-send-email-lee.jones-QSEj5FYQhm4dnm+yROfE0A@public.gmane.org> Sender: devicetree-owner-u79uwXL29TY76Z2rM5mHXA@public.gmane.org To: Lee Jones Cc: linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r@public.gmane.org, linux-kernel-u79uwXL29TY76Z2rM5mHXA@public.gmane.org, kernel-F5mvAk5X5gdBDgjK7y7TUQ@public.gmane.org, tglx-hfZtesqFncYOwBW4kG4KsQ@public.gmane.org, devicetree-u79uwXL29TY76Z2rM5mHXA@public.gmane.org List-Id: devicetree@vger.kernel.org On Tue, Jul 29, 2014 at 03:05:40PM +0100, Lee Jones wrote: > This driver is used to enable System Configuration Register controlle= d > External, CTI (Core Sight), PMU (Performance Management), and PL310 L= 2 > Cache IRQs prior to use. >=20 > Signed-off-by: Lee Jones > --- > drivers/irqchip/Kconfig | 7 ++ > drivers/irqchip/Makefile | 1 + > drivers/irqchip/irq-st.c | 206 +++++++++++++++++++++++++++++++++++++= ++++++++++ > 3 files changed, 214 insertions(+) > create mode 100644 drivers/irqchip/irq-st.c >=20 > diff --git a/drivers/irqchip/Kconfig b/drivers/irqchip/Kconfig > index bbb746e..7252de9 100644 > --- a/drivers/irqchip/Kconfig > +++ b/drivers/irqchip/Kconfig > @@ -91,3 +91,10 @@ config IRQ_CROSSBAR > The primary irqchip invokes the crossbar's callback which inturn = allocates > a free irq and configures the IP. Thus the peripheral interrupts = are > routed to one of the free irqchip interrupt lines. > + > +config ST_IRQCHIP > + bool > + select REGMAP > + select MFD_SYSCON > + help > + Enables SysCfg Controlled IRQs on STi based platforms. Now that I have my head above water (a bit) wrt irqchip, I really don't like the hot mess that this file has become... > diff --git a/drivers/irqchip/Makefile b/drivers/irqchip/Makefile > index 62a13e5..f859c14 100644 > --- a/drivers/irqchip/Makefile > +++ b/drivers/irqchip/Makefile > @@ -30,3 +30,4 @@ obj-$(CONFIG_XTENSA) +=3D irq-xtensa-pic.o > obj-$(CONFIG_XTENSA_MX) +=3D irq-xtensa-mx.o > obj-$(CONFIG_IRQ_CROSSBAR) +=3D irq-crossbar.o > obj-$(CONFIG_BRCMSTB_L2_IRQ) +=3D irq-brcmstb-l2.o > +obj-$(CONFIG_ST_IRQCHIP) +=3D irq-st.o > diff --git a/drivers/irqchip/irq-st.c b/drivers/irqchip/irq-st.c > new file mode 100644 > index 0000000..f31126f > --- /dev/null > +++ b/drivers/irqchip/irq-st.c > @@ -0,0 +1,206 @@ > +/* > + * drivers/irqchip/irq-st.c > + * > + * Copyright (C) 2014 STMicroelectronics =E2=80=93 All Rights Reser= ved > + * > + * Author: Lee Jones > + * > + * This is a re-write of Christophe Kerello's PMU driver. > + * > + * This program is free software; you can redistribute it and/or mod= ify > + * it under the terms of the GNU General Public License version 2 as > + * published by the Free Software Foundation. > + */ > + > +#include > +#include > +#include > +#include > +#include > +#include > +#include > + > +#define STIH415_SYSCFG_642 0x0a8 > +#define STIH416_SYSCFG_7543 0x87c > +#define STIH407_SYSCFG_5102 0x198 > +#define STID127_SYSCFG_734 0x088 > + > +#define ST_A9_IRQ_MASK 0x001FFFFF > +#define ST_A9_IRQ_MAX_CHANS 2 > + > +#define ST_A9_IRQ_EN_CTI_0 BIT(0) > +#define ST_A9_IRQ_EN_CTI_1 BIT(1) > +#define ST_A9_IRQ_EN_PMU_0 BIT(2) > +#define ST_A9_IRQ_EN_PMU_1 BIT(3) > +#define ST_A9_IRQ_EN_pl310_L2 BIT(4) PL310 > +#define ST_A9_IRQ_EN_EXT_0 BIT(5) > +#define ST_A9_IRQ_EN_EXT_1 BIT(6) > +#define ST_A9_IRQ_EN_EXT_2 BIT(7) > + > +#define ST_A9_FIQ_N_SEL(dev, chan) (dev << (8 + (chan * 3))) > +#define ST_A9_IRQ_N_SEL(dev, chan) (dev << (14 + (chan * 3))) > +#define ST_A9_EXTIRQ_INV_SEL(dev) (dev << 20) > + > +struct st_irq_syscfg { > + struct regmap *regmap; > + unsigned int syscfg; > + unsigned int result; result seems odd here. It sounds like you're storing a return value, when in fact, it looks like you are using it to determine whether or no= t to invert... Perhaps a different variable name here? > + bool ext_inverted; > +}; > + > +static const struct of_device_id st_irq_syscfg_match[] =3D { > + { > + .compatible =3D "st,stih415-irq-syscfg", > + .data =3D (void *)STIH415_SYSCFG_642, > + }, > + { > + .compatible =3D "st,stih416-irq-syscfg", > + .data =3D (void *)STIH416_SYSCFG_7543, > + }, > + { > + .compatible =3D "st,stih407-irq-syscfg", > + .data =3D (void *)STIH407_SYSCFG_5102, > + }, > + { > + .compatible =3D "st,stid127-irq-syscfg", > + .data =3D (void *)STID127_SYSCFG_734, > + }, > + {} > +}; > + > +static int st_irq_xlate(struct platform_device *pdev, > + int device, int channel, bool irq) > +{ > + struct st_irq_syscfg *ddata =3D dev_get_drvdata(&pdev->dev); > + > + /* Set the device enable bit. */ > + switch (device) { > + case ST_IRQ_SYSCFG_EXT_0 : > + ddata->result |=3D ST_A9_IRQ_EN_EXT_0; > + break; > + case ST_IRQ_SYSCFG_EXT_1 : > + ddata->result |=3D ST_A9_IRQ_EN_EXT_1; > + break; > + case ST_IRQ_SYSCFG_EXT_2 : > + ddata->result |=3D ST_A9_IRQ_EN_EXT_2; > + break; > + case ST_IRQ_SYSCFG_CTI_0 : > + ddata->result |=3D ST_A9_IRQ_EN_CTI_0; > + break; > + case ST_IRQ_SYSCFG_CTI_1 : > + ddata->result |=3D ST_A9_IRQ_EN_CTI_1; > + break; > + case ST_IRQ_SYSCFG_PMU_0 : > + ddata->result |=3D ST_A9_IRQ_EN_PMU_0; > + break; > + case ST_IRQ_SYSCFG_PMU_1 : > + ddata->result |=3D ST_A9_IRQ_EN_PMU_1; > + break; > + case ST_IRQ_SYSCFG_pl310_L2 : > + ddata->result |=3D ST_A9_IRQ_EN_pl310_L2; > + break; > + case ST_IRQ_SYSCFG_DISABLED : > + return 0; > + default : > + dev_err(&pdev->dev, "Unrecognised device %d\n", device); dev_dbg > + return -EINVAL; > + } > + > + /* Select IRQ/FIQ channel for device. */ > + ddata->result |=3D irq ? > + ST_A9_IRQ_N_SEL(device, channel) : > + ST_A9_FIQ_N_SEL(device, channel); > + > + return 0; > +} > + > +static int st_irq_syscfg_enable(struct platform_device *pdev) > +{ > + struct device_node *np =3D pdev->dev.of_node; > + struct st_irq_syscfg *ddata =3D dev_get_drvdata(&pdev->dev); > + int channels, ret, i; > + u32 device, invert; > + > + channels =3D of_property_count_u32_elems(np, "st,irq-device"); > + if (channels !=3D ST_A9_IRQ_MAX_CHANS) { > + dev_err(&pdev->dev, "st,enable-irq-device must have 2 elems\n"); > + return -EINVAL; > + } > + > + channels =3D of_property_count_u32_elems(np, "st,fiq-device"); > + if (channels !=3D ST_A9_IRQ_MAX_CHANS) { > + dev_err(&pdev->dev, "st,enable-fiq-device must have 2 elems\n"); > + return -EINVAL; > + } I would drop these two blocks, > + > + for (i =3D 0; i < channels; i++) { then use ST_A9_IRQ_MAX_CHANS here > + of_property_read_u32_index(np,"st,irq-device", i, &device); and dev_dbg() if of_property_read_u32_index() returns an error > + > + ret =3D st_irq_xlate(pdev, device, i, true); > + if (ret) > + return ret; > + > + of_property_read_u32_index(np,"st,fiq-device", i, &device); for both of these. > + > + ret =3D st_irq_xlate(pdev, device, i, false); > + if (ret) > + return ret; > + } > + > + /* External IRQs may be inverted. */ > + of_property_read_u32(np, "st,invert-ext", &invert); > + ddata->result |=3D ST_A9_EXTIRQ_INV_SEL(invert); > + > + return regmap_update_bits(ddata->regmap, ddata->syscfg, > + ST_A9_IRQ_MASK, ddata->result); > +} > + > +int st_irq_syscfg_probe(struct platform_device *pdev) > +{ > + struct device_node *np =3D pdev->dev.of_node; > + const struct of_device_id *match; > + struct st_irq_syscfg *ddata; > + > + match =3D of_match_device(st_irq_syscfg_match, &pdev->dev); > + if (!np) if (!match) ? > + return -ENODEV; > + > + ddata =3D devm_kzalloc(&pdev->dev, sizeof(*ddata), GFP_KERNEL); > + if (!ddata) > + return -ENOMEM; > + > + ddata->regmap =3D syscon_regmap_lookup_by_phandle(np, "st,syscfg"); > + if (IS_ERR(ddata->regmap)) { > + dev_err(&pdev->dev, "syscfg phandle missing\n"); dev_dbg > + return PTR_ERR(ddata->regmap); > + } > + > + dev_set_drvdata(&pdev->dev, ddata); > + > + return st_irq_syscfg_enable(pdev); > +} > + > +static int st_irq_syscfg_resume(struct device *dev) > +{ > + struct st_irq_syscfg *ddata =3D dev_get_drvdata(dev); > + > + return regmap_update_bits(ddata->regmap, ddata->syscfg, > + ST_A9_IRQ_MASK, ddata->result); > +} > + > +static SIMPLE_DEV_PM_OPS(st_irq_syscfg_pm_ops, NULL, st_irq_syscfg_r= esume); > + > +static struct platform_driver st_irq_syscfg_driver =3D { > + .driver =3D { > + .name =3D "st_irq_syscfg", > + .pm =3D &st_irq_syscfg_pm_ops, > + .of_match_table =3D st_irq_syscfg_match, > + }, > + .probe =3D st_irq_syscfg_probe, > +}; > + > +static int __init st_irq_syscfg_init(void) > +{ > + return platform_driver_register(&st_irq_syscfg_driver); > +} > +core_initcall(st_irq_syscfg_init); thx, Jason. -- To unsubscribe from this list: send the line "unsubscribe devicetree" i= n the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org More majordomo info at http://vger.kernel.org/majordomo-info.html