0001
0002
0003
0004
0005
0006
0007
0008
0009
0010 #include <dt-bindings/interrupt-controller/irq-st.h>
0011 #include <linux/err.h>
0012 #include <linux/mfd/syscon.h>
0013 #include <linux/of_device.h>
0014 #include <linux/platform_device.h>
0015 #include <linux/regmap.h>
0016 #include <linux/slab.h>
0017
0018 #define STIH415_SYSCFG_642 0x0a8
0019 #define STIH416_SYSCFG_7543 0x87c
0020 #define STIH407_SYSCFG_5102 0x198
0021 #define STID127_SYSCFG_734 0x088
0022
0023 #define ST_A9_IRQ_MASK 0x001FFFFF
0024 #define ST_A9_IRQ_MAX_CHANS 2
0025
0026 #define ST_A9_IRQ_EN_CTI_0 BIT(0)
0027 #define ST_A9_IRQ_EN_CTI_1 BIT(1)
0028 #define ST_A9_IRQ_EN_PMU_0 BIT(2)
0029 #define ST_A9_IRQ_EN_PMU_1 BIT(3)
0030 #define ST_A9_IRQ_EN_PL310_L2 BIT(4)
0031 #define ST_A9_IRQ_EN_EXT_0 BIT(5)
0032 #define ST_A9_IRQ_EN_EXT_1 BIT(6)
0033 #define ST_A9_IRQ_EN_EXT_2 BIT(7)
0034
0035 #define ST_A9_FIQ_N_SEL(dev, chan) (dev << (8 + (chan * 3)))
0036 #define ST_A9_IRQ_N_SEL(dev, chan) (dev << (14 + (chan * 3)))
0037 #define ST_A9_EXTIRQ_INV_SEL(dev) (dev << 20)
0038
0039 struct st_irq_syscfg {
0040 struct regmap *regmap;
0041 unsigned int syscfg;
0042 unsigned int config;
0043 bool ext_inverted;
0044 };
0045
0046 static const struct of_device_id st_irq_syscfg_match[] = {
0047 {
0048 .compatible = "st,stih415-irq-syscfg",
0049 .data = (void *)STIH415_SYSCFG_642,
0050 },
0051 {
0052 .compatible = "st,stih416-irq-syscfg",
0053 .data = (void *)STIH416_SYSCFG_7543,
0054 },
0055 {
0056 .compatible = "st,stih407-irq-syscfg",
0057 .data = (void *)STIH407_SYSCFG_5102,
0058 },
0059 {
0060 .compatible = "st,stid127-irq-syscfg",
0061 .data = (void *)STID127_SYSCFG_734,
0062 },
0063 {}
0064 };
0065
0066 static int st_irq_xlate(struct platform_device *pdev,
0067 int device, int channel, bool irq)
0068 {
0069 struct st_irq_syscfg *ddata = dev_get_drvdata(&pdev->dev);
0070
0071
0072 switch (device) {
0073 case ST_IRQ_SYSCFG_EXT_0:
0074 ddata->config |= ST_A9_IRQ_EN_EXT_0;
0075 break;
0076 case ST_IRQ_SYSCFG_EXT_1:
0077 ddata->config |= ST_A9_IRQ_EN_EXT_1;
0078 break;
0079 case ST_IRQ_SYSCFG_EXT_2:
0080 ddata->config |= ST_A9_IRQ_EN_EXT_2;
0081 break;
0082 case ST_IRQ_SYSCFG_CTI_0:
0083 ddata->config |= ST_A9_IRQ_EN_CTI_0;
0084 break;
0085 case ST_IRQ_SYSCFG_CTI_1:
0086 ddata->config |= ST_A9_IRQ_EN_CTI_1;
0087 break;
0088 case ST_IRQ_SYSCFG_PMU_0:
0089 ddata->config |= ST_A9_IRQ_EN_PMU_0;
0090 break;
0091 case ST_IRQ_SYSCFG_PMU_1:
0092 ddata->config |= ST_A9_IRQ_EN_PMU_1;
0093 break;
0094 case ST_IRQ_SYSCFG_pl310_L2:
0095 ddata->config |= ST_A9_IRQ_EN_PL310_L2;
0096 break;
0097 case ST_IRQ_SYSCFG_DISABLED:
0098 return 0;
0099 default:
0100 dev_err(&pdev->dev, "Unrecognised device %d\n", device);
0101 return -EINVAL;
0102 }
0103
0104
0105 ddata->config |= irq ?
0106 ST_A9_IRQ_N_SEL(device, channel) :
0107 ST_A9_FIQ_N_SEL(device, channel);
0108
0109 return 0;
0110 }
0111
0112 static int st_irq_syscfg_enable(struct platform_device *pdev)
0113 {
0114 struct device_node *np = pdev->dev.of_node;
0115 struct st_irq_syscfg *ddata = dev_get_drvdata(&pdev->dev);
0116 int channels, ret, i;
0117 u32 device, invert;
0118
0119 channels = of_property_count_u32_elems(np, "st,irq-device");
0120 if (channels != ST_A9_IRQ_MAX_CHANS) {
0121 dev_err(&pdev->dev, "st,enable-irq-device must have 2 elems\n");
0122 return -EINVAL;
0123 }
0124
0125 channels = of_property_count_u32_elems(np, "st,fiq-device");
0126 if (channels != ST_A9_IRQ_MAX_CHANS) {
0127 dev_err(&pdev->dev, "st,enable-fiq-device must have 2 elems\n");
0128 return -EINVAL;
0129 }
0130
0131 for (i = 0; i < ST_A9_IRQ_MAX_CHANS; i++) {
0132 of_property_read_u32_index(np, "st,irq-device", i, &device);
0133
0134 ret = st_irq_xlate(pdev, device, i, true);
0135 if (ret)
0136 return ret;
0137
0138 of_property_read_u32_index(np, "st,fiq-device", i, &device);
0139
0140 ret = st_irq_xlate(pdev, device, i, false);
0141 if (ret)
0142 return ret;
0143 }
0144
0145
0146 of_property_read_u32(np, "st,invert-ext", &invert);
0147 ddata->config |= ST_A9_EXTIRQ_INV_SEL(invert);
0148
0149 return regmap_update_bits(ddata->regmap, ddata->syscfg,
0150 ST_A9_IRQ_MASK, ddata->config);
0151 }
0152
0153 static int st_irq_syscfg_probe(struct platform_device *pdev)
0154 {
0155 struct device_node *np = pdev->dev.of_node;
0156 const struct of_device_id *match;
0157 struct st_irq_syscfg *ddata;
0158
0159 ddata = devm_kzalloc(&pdev->dev, sizeof(*ddata), GFP_KERNEL);
0160 if (!ddata)
0161 return -ENOMEM;
0162
0163 match = of_match_device(st_irq_syscfg_match, &pdev->dev);
0164 if (!match)
0165 return -ENODEV;
0166
0167 ddata->syscfg = (unsigned int)match->data;
0168
0169 ddata->regmap = syscon_regmap_lookup_by_phandle(np, "st,syscfg");
0170 if (IS_ERR(ddata->regmap)) {
0171 dev_err(&pdev->dev, "syscfg phandle missing\n");
0172 return PTR_ERR(ddata->regmap);
0173 }
0174
0175 dev_set_drvdata(&pdev->dev, ddata);
0176
0177 return st_irq_syscfg_enable(pdev);
0178 }
0179
0180 static int __maybe_unused st_irq_syscfg_resume(struct device *dev)
0181 {
0182 struct st_irq_syscfg *ddata = dev_get_drvdata(dev);
0183
0184 return regmap_update_bits(ddata->regmap, ddata->syscfg,
0185 ST_A9_IRQ_MASK, ddata->config);
0186 }
0187
0188 static SIMPLE_DEV_PM_OPS(st_irq_syscfg_pm_ops, NULL, st_irq_syscfg_resume);
0189
0190 static struct platform_driver st_irq_syscfg_driver = {
0191 .driver = {
0192 .name = "st_irq_syscfg",
0193 .pm = &st_irq_syscfg_pm_ops,
0194 .of_match_table = st_irq_syscfg_match,
0195 },
0196 .probe = st_irq_syscfg_probe,
0197 };
0198
0199 static int __init st_irq_syscfg_init(void)
0200 {
0201 return platform_driver_register(&st_irq_syscfg_driver);
0202 }
0203 core_initcall(st_irq_syscfg_init);