0001
0002
0003
0004
0005
0006
0007
0008
0009 #include <linux/module.h>
0010 #include <linux/interrupt.h>
0011 #include <linux/irq.h>
0012 #include <linux/irqdomain.h>
0013 #include <linux/pm_runtime.h>
0014 #include <linux/regmap.h>
0015 #include <linux/slab.h>
0016 #include <linux/of.h>
0017 #include <linux/of_device.h>
0018 #include <linux/of_irq.h>
0019 #include <linux/irqchip/irq-madera.h>
0020 #include <linux/mfd/madera/core.h>
0021 #include <linux/mfd/madera/pdata.h>
0022 #include <linux/mfd/madera/registers.h>
0023
0024 #define MADERA_IRQ(_irq, _reg) \
0025 [MADERA_IRQ_ ## _irq] = { \
0026 .reg_offset = (_reg) - MADERA_IRQ1_STATUS_2, \
0027 .mask = MADERA_ ## _irq ## _EINT1 \
0028 }
0029
0030
0031 static const struct regmap_irq madera_irqs[MADERA_NUM_IRQ] = {
0032 MADERA_IRQ(FLL1_LOCK, MADERA_IRQ1_STATUS_2),
0033 MADERA_IRQ(FLL2_LOCK, MADERA_IRQ1_STATUS_2),
0034 MADERA_IRQ(FLL3_LOCK, MADERA_IRQ1_STATUS_2),
0035 MADERA_IRQ(FLLAO_LOCK, MADERA_IRQ1_STATUS_2),
0036
0037 MADERA_IRQ(MICDET1, MADERA_IRQ1_STATUS_6),
0038 MADERA_IRQ(MICDET2, MADERA_IRQ1_STATUS_6),
0039 MADERA_IRQ(HPDET, MADERA_IRQ1_STATUS_6),
0040
0041 MADERA_IRQ(MICD_CLAMP_RISE, MADERA_IRQ1_STATUS_7),
0042 MADERA_IRQ(MICD_CLAMP_FALL, MADERA_IRQ1_STATUS_7),
0043 MADERA_IRQ(JD1_RISE, MADERA_IRQ1_STATUS_7),
0044 MADERA_IRQ(JD1_FALL, MADERA_IRQ1_STATUS_7),
0045
0046 MADERA_IRQ(ASRC2_IN1_LOCK, MADERA_IRQ1_STATUS_9),
0047 MADERA_IRQ(ASRC2_IN2_LOCK, MADERA_IRQ1_STATUS_9),
0048 MADERA_IRQ(ASRC1_IN1_LOCK, MADERA_IRQ1_STATUS_9),
0049 MADERA_IRQ(ASRC1_IN2_LOCK, MADERA_IRQ1_STATUS_9),
0050 MADERA_IRQ(DRC2_SIG_DET, MADERA_IRQ1_STATUS_9),
0051 MADERA_IRQ(DRC1_SIG_DET, MADERA_IRQ1_STATUS_9),
0052
0053 MADERA_IRQ(DSP_IRQ1, MADERA_IRQ1_STATUS_11),
0054 MADERA_IRQ(DSP_IRQ2, MADERA_IRQ1_STATUS_11),
0055 MADERA_IRQ(DSP_IRQ3, MADERA_IRQ1_STATUS_11),
0056 MADERA_IRQ(DSP_IRQ4, MADERA_IRQ1_STATUS_11),
0057 MADERA_IRQ(DSP_IRQ5, MADERA_IRQ1_STATUS_11),
0058 MADERA_IRQ(DSP_IRQ6, MADERA_IRQ1_STATUS_11),
0059 MADERA_IRQ(DSP_IRQ7, MADERA_IRQ1_STATUS_11),
0060 MADERA_IRQ(DSP_IRQ8, MADERA_IRQ1_STATUS_11),
0061 MADERA_IRQ(DSP_IRQ9, MADERA_IRQ1_STATUS_11),
0062 MADERA_IRQ(DSP_IRQ10, MADERA_IRQ1_STATUS_11),
0063 MADERA_IRQ(DSP_IRQ11, MADERA_IRQ1_STATUS_11),
0064 MADERA_IRQ(DSP_IRQ12, MADERA_IRQ1_STATUS_11),
0065 MADERA_IRQ(DSP_IRQ13, MADERA_IRQ1_STATUS_11),
0066 MADERA_IRQ(DSP_IRQ14, MADERA_IRQ1_STATUS_11),
0067 MADERA_IRQ(DSP_IRQ15, MADERA_IRQ1_STATUS_11),
0068 MADERA_IRQ(DSP_IRQ16, MADERA_IRQ1_STATUS_11),
0069
0070 MADERA_IRQ(HP3R_SC, MADERA_IRQ1_STATUS_12),
0071 MADERA_IRQ(HP3L_SC, MADERA_IRQ1_STATUS_12),
0072 MADERA_IRQ(HP2R_SC, MADERA_IRQ1_STATUS_12),
0073 MADERA_IRQ(HP2L_SC, MADERA_IRQ1_STATUS_12),
0074 MADERA_IRQ(HP1R_SC, MADERA_IRQ1_STATUS_12),
0075 MADERA_IRQ(HP1L_SC, MADERA_IRQ1_STATUS_12),
0076
0077 MADERA_IRQ(SPK_OVERHEAT_WARN, MADERA_IRQ1_STATUS_15),
0078 MADERA_IRQ(SPK_OVERHEAT, MADERA_IRQ1_STATUS_15),
0079
0080 MADERA_IRQ(DSP1_BUS_ERR, MADERA_IRQ1_STATUS_33),
0081 MADERA_IRQ(DSP2_BUS_ERR, MADERA_IRQ1_STATUS_33),
0082 MADERA_IRQ(DSP3_BUS_ERR, MADERA_IRQ1_STATUS_33),
0083 MADERA_IRQ(DSP4_BUS_ERR, MADERA_IRQ1_STATUS_33),
0084 MADERA_IRQ(DSP5_BUS_ERR, MADERA_IRQ1_STATUS_33),
0085 MADERA_IRQ(DSP6_BUS_ERR, MADERA_IRQ1_STATUS_33),
0086 MADERA_IRQ(DSP7_BUS_ERR, MADERA_IRQ1_STATUS_33),
0087 };
0088
0089 static const struct regmap_irq_chip madera_irq_chip = {
0090 .name = "madera IRQ",
0091 .status_base = MADERA_IRQ1_STATUS_2,
0092 .mask_base = MADERA_IRQ1_MASK_2,
0093 .ack_base = MADERA_IRQ1_STATUS_2,
0094 .runtime_pm = true,
0095 .num_regs = 32,
0096 .irqs = madera_irqs,
0097 .num_irqs = ARRAY_SIZE(madera_irqs),
0098 };
0099
0100 #ifdef CONFIG_PM_SLEEP
0101 static int madera_suspend(struct device *dev)
0102 {
0103 struct madera *madera = dev_get_drvdata(dev->parent);
0104
0105 dev_dbg(madera->irq_dev, "Suspend, disabling IRQ\n");
0106
0107
0108
0109
0110
0111
0112 disable_irq(madera->irq);
0113
0114 return 0;
0115 }
0116
0117 static int madera_suspend_noirq(struct device *dev)
0118 {
0119 struct madera *madera = dev_get_drvdata(dev->parent);
0120
0121 dev_dbg(madera->irq_dev, "No IRQ suspend, reenabling IRQ\n");
0122
0123
0124 enable_irq(madera->irq);
0125
0126 return 0;
0127 }
0128
0129 static int madera_resume_noirq(struct device *dev)
0130 {
0131 struct madera *madera = dev_get_drvdata(dev->parent);
0132
0133 dev_dbg(madera->irq_dev, "No IRQ resume, disabling IRQ\n");
0134
0135
0136
0137
0138
0139 disable_irq(madera->irq);
0140
0141 return 0;
0142 }
0143
0144 static int madera_resume(struct device *dev)
0145 {
0146 struct madera *madera = dev_get_drvdata(dev->parent);
0147
0148 dev_dbg(madera->irq_dev, "Resume, reenabling IRQ\n");
0149
0150
0151 enable_irq(madera->irq);
0152
0153 return 0;
0154 }
0155 #endif
0156
0157 static const struct dev_pm_ops madera_irq_pm_ops = {
0158 SET_SYSTEM_SLEEP_PM_OPS(madera_suspend, madera_resume)
0159 SET_NOIRQ_SYSTEM_SLEEP_PM_OPS(madera_suspend_noirq,
0160 madera_resume_noirq)
0161 };
0162
0163 static int madera_irq_probe(struct platform_device *pdev)
0164 {
0165 struct madera *madera = dev_get_drvdata(pdev->dev.parent);
0166 struct irq_data *irq_data;
0167 unsigned int irq_flags = 0;
0168 int ret;
0169
0170 dev_dbg(&pdev->dev, "probe\n");
0171
0172
0173
0174
0175
0176 irq_flags = madera->pdata.irq_flags;
0177 if (!irq_flags) {
0178 irq_data = irq_get_irq_data(madera->irq);
0179 if (!irq_data) {
0180 dev_err(&pdev->dev, "Invalid IRQ: %d\n", madera->irq);
0181 return -EINVAL;
0182 }
0183
0184 irq_flags = irqd_get_trigger_type(irq_data);
0185
0186
0187 if (irq_flags == IRQ_TYPE_NONE)
0188 irq_flags = IRQF_TRIGGER_LOW;
0189 }
0190
0191 if (irq_flags & (IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING)) {
0192 dev_err(&pdev->dev, "Host interrupt not level-triggered\n");
0193 return -EINVAL;
0194 }
0195
0196
0197
0198
0199
0200 if (irq_flags & IRQF_TRIGGER_HIGH) {
0201 ret = regmap_update_bits(madera->regmap, MADERA_IRQ1_CTRL,
0202 MADERA_IRQ_POL_MASK, 0);
0203 if (ret) {
0204 dev_err(&pdev->dev,
0205 "Failed to set IRQ polarity: %d\n", ret);
0206 return ret;
0207 }
0208 }
0209
0210
0211
0212
0213
0214 ret = regmap_add_irq_chip(madera->regmap, madera->irq, IRQF_ONESHOT, 0,
0215 &madera_irq_chip, &madera->irq_data);
0216 if (ret) {
0217 dev_err(&pdev->dev, "add_irq_chip failed: %d\n", ret);
0218 return ret;
0219 }
0220
0221
0222 madera->irq_dev = &pdev->dev;
0223
0224 return 0;
0225 }
0226
0227 static int madera_irq_remove(struct platform_device *pdev)
0228 {
0229 struct madera *madera = dev_get_drvdata(pdev->dev.parent);
0230
0231
0232
0233
0234
0235 madera->irq_dev = NULL;
0236 regmap_del_irq_chip(madera->irq, madera->irq_data);
0237
0238 return 0;
0239 }
0240
0241 static struct platform_driver madera_irq_driver = {
0242 .probe = &madera_irq_probe,
0243 .remove = &madera_irq_remove,
0244 .driver = {
0245 .name = "madera-irq",
0246 .pm = &madera_irq_pm_ops,
0247 }
0248 };
0249 module_platform_driver(madera_irq_driver);
0250
0251 MODULE_SOFTDEP("pre: madera");
0252 MODULE_DESCRIPTION("Madera IRQ driver");
0253 MODULE_AUTHOR("Richard Fitzgerald <rf@opensource.cirrus.com>");
0254 MODULE_LICENSE("GPL v2");