^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1) // SPDX-License-Identifier: GPL-2.0-only
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3) * Copyright (C) 2014 STMicroelectronics – All Rights Reserved
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 4) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 5) * Author: Lee Jones <lee.jones@linaro.org>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 6) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 7) * This is a re-write of Christophe Kerello's PMU driver.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 8) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 9)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 10) #include <dt-bindings/interrupt-controller/irq-st.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 11) #include <linux/err.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 12) #include <linux/mfd/syscon.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 13) #include <linux/of_device.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 14) #include <linux/platform_device.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 15) #include <linux/regmap.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 16) #include <linux/slab.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 17)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 18) #define STIH415_SYSCFG_642 0x0a8
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 19) #define STIH416_SYSCFG_7543 0x87c
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 20) #define STIH407_SYSCFG_5102 0x198
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 21) #define STID127_SYSCFG_734 0x088
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 22)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 23) #define ST_A9_IRQ_MASK 0x001FFFFF
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 24) #define ST_A9_IRQ_MAX_CHANS 2
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 25)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 26) #define ST_A9_IRQ_EN_CTI_0 BIT(0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 27) #define ST_A9_IRQ_EN_CTI_1 BIT(1)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 28) #define ST_A9_IRQ_EN_PMU_0 BIT(2)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 29) #define ST_A9_IRQ_EN_PMU_1 BIT(3)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 30) #define ST_A9_IRQ_EN_PL310_L2 BIT(4)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 31) #define ST_A9_IRQ_EN_EXT_0 BIT(5)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 32) #define ST_A9_IRQ_EN_EXT_1 BIT(6)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 33) #define ST_A9_IRQ_EN_EXT_2 BIT(7)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 34)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 35) #define ST_A9_FIQ_N_SEL(dev, chan) (dev << (8 + (chan * 3)))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 36) #define ST_A9_IRQ_N_SEL(dev, chan) (dev << (14 + (chan * 3)))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 37) #define ST_A9_EXTIRQ_INV_SEL(dev) (dev << 20)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 38)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 39) struct st_irq_syscfg {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 40) struct regmap *regmap;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 41) unsigned int syscfg;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 42) unsigned int config;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 43) bool ext_inverted;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 44) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 45)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 46) static const struct of_device_id st_irq_syscfg_match[] = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 47) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 48) .compatible = "st,stih415-irq-syscfg",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 49) .data = (void *)STIH415_SYSCFG_642,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 50) },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 51) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 52) .compatible = "st,stih416-irq-syscfg",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 53) .data = (void *)STIH416_SYSCFG_7543,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 54) },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 55) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 56) .compatible = "st,stih407-irq-syscfg",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 57) .data = (void *)STIH407_SYSCFG_5102,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 58) },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 59) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 60) .compatible = "st,stid127-irq-syscfg",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 61) .data = (void *)STID127_SYSCFG_734,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 62) },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 63) {}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 64) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 65)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 66) static int st_irq_xlate(struct platform_device *pdev,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 67) int device, int channel, bool irq)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 68) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 69) struct st_irq_syscfg *ddata = dev_get_drvdata(&pdev->dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 70)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 71) /* Set the device enable bit. */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 72) switch (device) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 73) case ST_IRQ_SYSCFG_EXT_0:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 74) ddata->config |= ST_A9_IRQ_EN_EXT_0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 75) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 76) case ST_IRQ_SYSCFG_EXT_1:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 77) ddata->config |= ST_A9_IRQ_EN_EXT_1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 78) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 79) case ST_IRQ_SYSCFG_EXT_2:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 80) ddata->config |= ST_A9_IRQ_EN_EXT_2;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 81) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 82) case ST_IRQ_SYSCFG_CTI_0:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 83) ddata->config |= ST_A9_IRQ_EN_CTI_0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 84) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 85) case ST_IRQ_SYSCFG_CTI_1:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 86) ddata->config |= ST_A9_IRQ_EN_CTI_1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 87) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 88) case ST_IRQ_SYSCFG_PMU_0:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 89) ddata->config |= ST_A9_IRQ_EN_PMU_0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 90) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 91) case ST_IRQ_SYSCFG_PMU_1:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 92) ddata->config |= ST_A9_IRQ_EN_PMU_1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 93) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 94) case ST_IRQ_SYSCFG_pl310_L2:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 95) ddata->config |= ST_A9_IRQ_EN_PL310_L2;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 96) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 97) case ST_IRQ_SYSCFG_DISABLED:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 98) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 99) default:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 100) dev_err(&pdev->dev, "Unrecognised device %d\n", device);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 101) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 102) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 103)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 104) /* Select IRQ/FIQ channel for device. */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 105) ddata->config |= irq ?
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 106) ST_A9_IRQ_N_SEL(device, channel) :
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 107) ST_A9_FIQ_N_SEL(device, channel);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 108)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 109) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 110) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 111)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 112) static int st_irq_syscfg_enable(struct platform_device *pdev)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 113) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 114) struct device_node *np = pdev->dev.of_node;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 115) struct st_irq_syscfg *ddata = dev_get_drvdata(&pdev->dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 116) int channels, ret, i;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 117) u32 device, invert;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 118)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 119) channels = of_property_count_u32_elems(np, "st,irq-device");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 120) if (channels != ST_A9_IRQ_MAX_CHANS) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 121) dev_err(&pdev->dev, "st,enable-irq-device must have 2 elems\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 122) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 123) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 124)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 125) channels = of_property_count_u32_elems(np, "st,fiq-device");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 126) if (channels != ST_A9_IRQ_MAX_CHANS) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 127) dev_err(&pdev->dev, "st,enable-fiq-device must have 2 elems\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 128) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 129) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 130)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 131) for (i = 0; i < ST_A9_IRQ_MAX_CHANS; i++) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 132) of_property_read_u32_index(np, "st,irq-device", i, &device);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 133)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 134) ret = st_irq_xlate(pdev, device, i, true);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 135) if (ret)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 136) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 137)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 138) of_property_read_u32_index(np, "st,fiq-device", i, &device);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 139)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 140) ret = st_irq_xlate(pdev, device, i, false);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 141) if (ret)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 142) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 143) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 144)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 145) /* External IRQs may be inverted. */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 146) of_property_read_u32(np, "st,invert-ext", &invert);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 147) ddata->config |= ST_A9_EXTIRQ_INV_SEL(invert);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 148)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 149) return regmap_update_bits(ddata->regmap, ddata->syscfg,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 150) ST_A9_IRQ_MASK, ddata->config);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 151) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 152)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 153) static int st_irq_syscfg_probe(struct platform_device *pdev)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 154) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 155) struct device_node *np = pdev->dev.of_node;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 156) const struct of_device_id *match;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 157) struct st_irq_syscfg *ddata;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 158)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 159) ddata = devm_kzalloc(&pdev->dev, sizeof(*ddata), GFP_KERNEL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 160) if (!ddata)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 161) return -ENOMEM;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 162)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 163) match = of_match_device(st_irq_syscfg_match, &pdev->dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 164) if (!match)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 165) return -ENODEV;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 166)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 167) ddata->syscfg = (unsigned int)match->data;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 168)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 169) ddata->regmap = syscon_regmap_lookup_by_phandle(np, "st,syscfg");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 170) if (IS_ERR(ddata->regmap)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 171) dev_err(&pdev->dev, "syscfg phandle missing\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 172) return PTR_ERR(ddata->regmap);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 173) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 174)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 175) dev_set_drvdata(&pdev->dev, ddata);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 176)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 177) return st_irq_syscfg_enable(pdev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 178) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 179)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 180) static int __maybe_unused st_irq_syscfg_resume(struct device *dev)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 181) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 182) struct st_irq_syscfg *ddata = dev_get_drvdata(dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 183)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 184) return regmap_update_bits(ddata->regmap, ddata->syscfg,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 185) ST_A9_IRQ_MASK, ddata->config);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 186) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 187)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 188) static SIMPLE_DEV_PM_OPS(st_irq_syscfg_pm_ops, NULL, st_irq_syscfg_resume);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 189)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 190) static struct platform_driver st_irq_syscfg_driver = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 191) .driver = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 192) .name = "st_irq_syscfg",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 193) .pm = &st_irq_syscfg_pm_ops,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 194) .of_match_table = st_irq_syscfg_match,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 195) },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 196) .probe = st_irq_syscfg_probe,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 197) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 198)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 199) static int __init st_irq_syscfg_init(void)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 200) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 201) return platform_driver_register(&st_irq_syscfg_driver);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 202) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 203) core_initcall(st_irq_syscfg_init);