0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012
0013
0014
0015
0016
0017
0018
0019
0020
0021 #include <linux/export.h>
0022 #include <linux/interrupt.h>
0023 #include <linux/irq.h>
0024 #include <linux/kthread.h>
0025 #include <linux/mfd/twl.h>
0026 #include <linux/platform_device.h>
0027 #include <linux/suspend.h>
0028 #include <linux/of.h>
0029 #include <linux/irqdomain.h>
0030 #include <linux/of_device.h>
0031
0032 #include "twl-core.h"
0033
0034
0035
0036
0037
0038
0039
0040
0041
0042
0043
0044 #define TWL6030_NR_IRQS 20
0045
0046 static int twl6030_interrupt_mapping[24] = {
0047 PWR_INTR_OFFSET,
0048 PWR_INTR_OFFSET,
0049 PWR_INTR_OFFSET,
0050 RTC_INTR_OFFSET,
0051 RTC_INTR_OFFSET,
0052 HOTDIE_INTR_OFFSET,
0053 SMPSLDO_INTR_OFFSET,
0054 SMPSLDO_INTR_OFFSET,
0055
0056 SMPSLDO_INTR_OFFSET,
0057 BATDETECT_INTR_OFFSET,
0058 SIMDETECT_INTR_OFFSET,
0059 MMCDETECT_INTR_OFFSET,
0060 RSV_INTR_OFFSET,
0061 MADC_INTR_OFFSET,
0062 MADC_INTR_OFFSET,
0063 GASGAUGE_INTR_OFFSET,
0064
0065 USBOTG_INTR_OFFSET,
0066 USBOTG_INTR_OFFSET,
0067 USBOTG_INTR_OFFSET,
0068 USB_PRES_INTR_OFFSET,
0069 CHARGER_INTR_OFFSET,
0070 CHARGERFAULT_INTR_OFFSET,
0071 CHARGERFAULT_INTR_OFFSET,
0072 RSV_INTR_OFFSET,
0073 };
0074
0075 static int twl6032_interrupt_mapping[24] = {
0076 PWR_INTR_OFFSET,
0077 PWR_INTR_OFFSET,
0078 PWR_INTR_OFFSET,
0079 RTC_INTR_OFFSET,
0080 RTC_INTR_OFFSET,
0081 HOTDIE_INTR_OFFSET,
0082 SMPSLDO_INTR_OFFSET,
0083 PWR_INTR_OFFSET,
0084
0085 PWR_INTR_OFFSET,
0086 BATDETECT_INTR_OFFSET,
0087 SIMDETECT_INTR_OFFSET,
0088 MMCDETECT_INTR_OFFSET,
0089 MADC_INTR_OFFSET,
0090 MADC_INTR_OFFSET,
0091 GASGAUGE_INTR_OFFSET,
0092 GASGAUGE_INTR_OFFSET,
0093
0094 USBOTG_INTR_OFFSET,
0095 USBOTG_INTR_OFFSET,
0096 USBOTG_INTR_OFFSET,
0097 USB_PRES_INTR_OFFSET,
0098 CHARGER_INTR_OFFSET,
0099 CHARGERFAULT_INTR_OFFSET,
0100 CHARGERFAULT_INTR_OFFSET,
0101 RSV_INTR_OFFSET,
0102 };
0103
0104
0105
0106 struct twl6030_irq {
0107 unsigned int irq_base;
0108 int twl_irq;
0109 bool irq_wake_enabled;
0110 atomic_t wakeirqs;
0111 struct notifier_block pm_nb;
0112 struct irq_chip irq_chip;
0113 struct irq_domain *irq_domain;
0114 const int *irq_mapping_tbl;
0115 };
0116
0117 static struct twl6030_irq *twl6030_irq;
0118
0119 static int twl6030_irq_pm_notifier(struct notifier_block *notifier,
0120 unsigned long pm_event, void *unused)
0121 {
0122 int chained_wakeups;
0123 struct twl6030_irq *pdata = container_of(notifier, struct twl6030_irq,
0124 pm_nb);
0125
0126 switch (pm_event) {
0127 case PM_SUSPEND_PREPARE:
0128 chained_wakeups = atomic_read(&pdata->wakeirqs);
0129
0130 if (chained_wakeups && !pdata->irq_wake_enabled) {
0131 if (enable_irq_wake(pdata->twl_irq))
0132 pr_err("twl6030 IRQ wake enable failed\n");
0133 else
0134 pdata->irq_wake_enabled = true;
0135 } else if (!chained_wakeups && pdata->irq_wake_enabled) {
0136 disable_irq_wake(pdata->twl_irq);
0137 pdata->irq_wake_enabled = false;
0138 }
0139
0140 disable_irq(pdata->twl_irq);
0141 break;
0142
0143 case PM_POST_SUSPEND:
0144 enable_irq(pdata->twl_irq);
0145 break;
0146
0147 default:
0148 break;
0149 }
0150
0151 return NOTIFY_DONE;
0152 }
0153
0154
0155
0156
0157
0158
0159
0160 static irqreturn_t twl6030_irq_thread(int irq, void *data)
0161 {
0162 int i, ret;
0163 union {
0164 u8 bytes[4];
0165 __le32 int_sts;
0166 } sts;
0167 u32 int_sts;
0168 struct twl6030_irq *pdata = data;
0169
0170
0171 ret = twl_i2c_read(TWL_MODULE_PIH, sts.bytes, REG_INT_STS_A, 3);
0172 if (ret) {
0173 pr_warn("twl6030_irq: I2C error %d reading PIH ISR\n", ret);
0174 return IRQ_HANDLED;
0175 }
0176
0177 sts.bytes[3] = 0;
0178
0179
0180
0181
0182
0183 if (sts.bytes[2] & 0x10)
0184 sts.bytes[2] |= 0x08;
0185
0186 int_sts = le32_to_cpu(sts.int_sts);
0187 for (i = 0; int_sts; int_sts >>= 1, i++)
0188 if (int_sts & 0x1) {
0189 int module_irq =
0190 irq_find_mapping(pdata->irq_domain,
0191 pdata->irq_mapping_tbl[i]);
0192 if (module_irq)
0193 handle_nested_irq(module_irq);
0194 else
0195 pr_err("twl6030_irq: Unmapped PIH ISR %u detected\n",
0196 i);
0197 pr_debug("twl6030_irq: PIH ISR %u, virq%u\n",
0198 i, module_irq);
0199 }
0200
0201
0202
0203
0204
0205
0206
0207
0208
0209
0210 ret = twl_i2c_write_u8(TWL_MODULE_PIH, 0x00, REG_INT_STS_A);
0211 if (ret)
0212 pr_warn("twl6030_irq: I2C error in clearing PIH ISR\n");
0213
0214 return IRQ_HANDLED;
0215 }
0216
0217
0218
0219 static int twl6030_irq_set_wake(struct irq_data *d, unsigned int on)
0220 {
0221 struct twl6030_irq *pdata = irq_data_get_irq_chip_data(d);
0222
0223 if (on)
0224 atomic_inc(&pdata->wakeirqs);
0225 else
0226 atomic_dec(&pdata->wakeirqs);
0227
0228 return 0;
0229 }
0230
0231 int twl6030_interrupt_unmask(u8 bit_mask, u8 offset)
0232 {
0233 int ret;
0234 u8 unmask_value;
0235
0236 ret = twl_i2c_read_u8(TWL_MODULE_PIH, &unmask_value,
0237 REG_INT_STS_A + offset);
0238 unmask_value &= (~(bit_mask));
0239 ret |= twl_i2c_write_u8(TWL_MODULE_PIH, unmask_value,
0240 REG_INT_STS_A + offset);
0241 return ret;
0242 }
0243 EXPORT_SYMBOL(twl6030_interrupt_unmask);
0244
0245 int twl6030_interrupt_mask(u8 bit_mask, u8 offset)
0246 {
0247 int ret;
0248 u8 mask_value;
0249
0250 ret = twl_i2c_read_u8(TWL_MODULE_PIH, &mask_value,
0251 REG_INT_STS_A + offset);
0252 mask_value |= (bit_mask);
0253 ret |= twl_i2c_write_u8(TWL_MODULE_PIH, mask_value,
0254 REG_INT_STS_A + offset);
0255 return ret;
0256 }
0257 EXPORT_SYMBOL(twl6030_interrupt_mask);
0258
0259 int twl6030_mmc_card_detect_config(void)
0260 {
0261 int ret;
0262 u8 reg_val = 0;
0263
0264
0265 twl6030_interrupt_unmask(TWL6030_MMCDETECT_INT_MASK,
0266 REG_INT_MSK_LINE_B);
0267 twl6030_interrupt_unmask(TWL6030_MMCDETECT_INT_MASK,
0268 REG_INT_MSK_STS_B);
0269
0270
0271
0272
0273 ret = twl_i2c_read_u8(TWL6030_MODULE_ID0, ®_val, TWL6030_MMCCTRL);
0274 if (ret < 0) {
0275 pr_err("twl6030: Failed to read MMCCTRL, error %d\n", ret);
0276 return ret;
0277 }
0278 reg_val &= ~VMMC_AUTO_OFF;
0279 reg_val |= SW_FC;
0280 ret = twl_i2c_write_u8(TWL6030_MODULE_ID0, reg_val, TWL6030_MMCCTRL);
0281 if (ret < 0) {
0282 pr_err("twl6030: Failed to write MMCCTRL, error %d\n", ret);
0283 return ret;
0284 }
0285
0286
0287 ret = twl_i2c_read_u8(TWL6030_MODULE_ID0, ®_val,
0288 TWL6030_CFG_INPUT_PUPD3);
0289 if (ret < 0) {
0290 pr_err("twl6030: Failed to read CFG_INPUT_PUPD3, error %d\n",
0291 ret);
0292 return ret;
0293 }
0294 reg_val &= ~(MMC_PU | MMC_PD);
0295 ret = twl_i2c_write_u8(TWL6030_MODULE_ID0, reg_val,
0296 TWL6030_CFG_INPUT_PUPD3);
0297 if (ret < 0) {
0298 pr_err("twl6030: Failed to write CFG_INPUT_PUPD3, error %d\n",
0299 ret);
0300 return ret;
0301 }
0302
0303 return irq_find_mapping(twl6030_irq->irq_domain,
0304 MMCDETECT_INTR_OFFSET);
0305 }
0306 EXPORT_SYMBOL(twl6030_mmc_card_detect_config);
0307
0308 int twl6030_mmc_card_detect(struct device *dev, int slot)
0309 {
0310 int ret = -EIO;
0311 u8 read_reg = 0;
0312 struct platform_device *pdev = to_platform_device(dev);
0313
0314 if (pdev->id) {
0315
0316
0317
0318 pr_err("Unknown MMC controller %d in %s\n", pdev->id, __func__);
0319 return ret;
0320 }
0321
0322
0323
0324
0325 ret = twl_i2c_read_u8(TWL6030_MODULE_ID0, &read_reg,
0326 TWL6030_MMCCTRL);
0327 if (ret >= 0)
0328 ret = read_reg & STS_MMC;
0329 return ret;
0330 }
0331 EXPORT_SYMBOL(twl6030_mmc_card_detect);
0332
0333 static int twl6030_irq_map(struct irq_domain *d, unsigned int virq,
0334 irq_hw_number_t hwirq)
0335 {
0336 struct twl6030_irq *pdata = d->host_data;
0337
0338 irq_set_chip_data(virq, pdata);
0339 irq_set_chip_and_handler(virq, &pdata->irq_chip, handle_simple_irq);
0340 irq_set_nested_thread(virq, true);
0341 irq_set_parent(virq, pdata->twl_irq);
0342 irq_set_noprobe(virq);
0343
0344 return 0;
0345 }
0346
0347 static void twl6030_irq_unmap(struct irq_domain *d, unsigned int virq)
0348 {
0349 irq_set_chip_and_handler(virq, NULL, NULL);
0350 irq_set_chip_data(virq, NULL);
0351 }
0352
0353 static const struct irq_domain_ops twl6030_irq_domain_ops = {
0354 .map = twl6030_irq_map,
0355 .unmap = twl6030_irq_unmap,
0356 .xlate = irq_domain_xlate_onetwocell,
0357 };
0358
0359 static const struct of_device_id twl6030_of_match[] __maybe_unused = {
0360 {.compatible = "ti,twl6030", &twl6030_interrupt_mapping},
0361 {.compatible = "ti,twl6032", &twl6032_interrupt_mapping},
0362 { },
0363 };
0364
0365 int twl6030_init_irq(struct device *dev, int irq_num)
0366 {
0367 struct device_node *node = dev->of_node;
0368 int nr_irqs;
0369 int status;
0370 u8 mask[3];
0371 const struct of_device_id *of_id;
0372
0373 of_id = of_match_device(twl6030_of_match, dev);
0374 if (!of_id || !of_id->data) {
0375 dev_err(dev, "Unknown TWL device model\n");
0376 return -EINVAL;
0377 }
0378
0379 nr_irqs = TWL6030_NR_IRQS;
0380
0381 twl6030_irq = devm_kzalloc(dev, sizeof(*twl6030_irq), GFP_KERNEL);
0382 if (!twl6030_irq)
0383 return -ENOMEM;
0384
0385 mask[0] = 0xFF;
0386 mask[1] = 0xFF;
0387 mask[2] = 0xFF;
0388
0389
0390 status = twl_i2c_write(TWL_MODULE_PIH, &mask[0], REG_INT_MSK_LINE_A, 3);
0391
0392 status |= twl_i2c_write(TWL_MODULE_PIH, &mask[0], REG_INT_MSK_STS_A, 3);
0393
0394 status |= twl_i2c_write(TWL_MODULE_PIH, &mask[0], REG_INT_STS_A, 3);
0395
0396 if (status < 0) {
0397 dev_err(dev, "I2C err writing TWL_MODULE_PIH: %d\n", status);
0398 return status;
0399 }
0400
0401
0402
0403
0404
0405 twl6030_irq->irq_chip = dummy_irq_chip;
0406 twl6030_irq->irq_chip.name = "twl6030";
0407 twl6030_irq->irq_chip.irq_set_type = NULL;
0408 twl6030_irq->irq_chip.irq_set_wake = twl6030_irq_set_wake;
0409
0410 twl6030_irq->pm_nb.notifier_call = twl6030_irq_pm_notifier;
0411 atomic_set(&twl6030_irq->wakeirqs, 0);
0412 twl6030_irq->irq_mapping_tbl = of_id->data;
0413
0414 twl6030_irq->irq_domain =
0415 irq_domain_add_linear(node, nr_irqs,
0416 &twl6030_irq_domain_ops, twl6030_irq);
0417 if (!twl6030_irq->irq_domain) {
0418 dev_err(dev, "Can't add irq_domain\n");
0419 return -ENOMEM;
0420 }
0421
0422 dev_info(dev, "PIH (irq %d) nested IRQs\n", irq_num);
0423
0424
0425 status = request_threaded_irq(irq_num, NULL, twl6030_irq_thread,
0426 IRQF_ONESHOT, "TWL6030-PIH", twl6030_irq);
0427 if (status < 0) {
0428 dev_err(dev, "could not claim irq %d: %d\n", irq_num, status);
0429 goto fail_irq;
0430 }
0431
0432 twl6030_irq->twl_irq = irq_num;
0433 register_pm_notifier(&twl6030_irq->pm_nb);
0434 return 0;
0435
0436 fail_irq:
0437 irq_domain_remove(twl6030_irq->irq_domain);
0438 return status;
0439 }
0440
0441 void twl6030_exit_irq(void)
0442 {
0443 if (twl6030_irq && twl6030_irq->twl_irq) {
0444 unregister_pm_notifier(&twl6030_irq->pm_nb);
0445 free_irq(twl6030_irq->twl_irq, NULL);
0446
0447
0448
0449
0450
0451
0452
0453
0454
0455 }
0456 }
0457