1 // SPDX-License-Identifier: GPL-2.0 2 /* 3 * Intel BXT Whiskey Cove PMIC TMU driver 4 * 5 * Copyright (C) 2016 Intel Corporation. All rights reserved. 6 * 7 * This driver adds TMU (Time Management Unit) support for Intel BXT platform. 8 * It enables the alarm wake-up functionality in the TMU unit of Whiskey Cove 9 * PMIC. 10 */ 11 12 #include <linux/module.h> 13 #include <linux/mod_devicetable.h> 14 #include <linux/interrupt.h> 15 #include <linux/platform_device.h> 16 #include <linux/mfd/intel_soc_pmic.h> 17 18 #define BXTWC_TMUIRQ 0x4fb6 19 #define BXTWC_MIRQLVL1 0x4e0e 20 #define BXTWC_MTMUIRQ_REG 0x4fb7 21 #define BXTWC_MIRQLVL1_MTMU BIT(1) 22 #define BXTWC_TMU_WK_ALRM BIT(1) 23 #define BXTWC_TMU_SYS_ALRM BIT(2) 24 #define BXTWC_TMU_ALRM_MASK (BXTWC_TMU_WK_ALRM | BXTWC_TMU_SYS_ALRM) 25 #define BXTWC_TMU_ALRM_IRQ (BXTWC_TMU_WK_ALRM | BXTWC_TMU_SYS_ALRM) 26 27 struct wcove_tmu { 28 int irq; 29 struct device *dev; 30 struct regmap *regmap; 31 }; 32 33 static irqreturn_t bxt_wcove_tmu_irq_handler(int irq, void *data) 34 { 35 struct wcove_tmu *wctmu = data; 36 unsigned int tmu_irq; 37 38 /* Read TMU interrupt reg */ 39 regmap_read(wctmu->regmap, BXTWC_TMUIRQ, &tmu_irq); 40 if (tmu_irq & BXTWC_TMU_ALRM_IRQ) { 41 /* clear TMU irq */ 42 regmap_write(wctmu->regmap, BXTWC_TMUIRQ, tmu_irq); 43 return IRQ_HANDLED; 44 } 45 return IRQ_NONE; 46 } 47 48 static int bxt_wcove_tmu_probe(struct platform_device *pdev) 49 { 50 struct intel_soc_pmic *pmic = dev_get_drvdata(pdev->dev.parent); 51 struct regmap_irq_chip_data *regmap_irq_chip; 52 struct wcove_tmu *wctmu; 53 int ret, virq, irq; 54 55 wctmu = devm_kzalloc(&pdev->dev, sizeof(*wctmu), GFP_KERNEL); 56 if (!wctmu) 57 return -ENOMEM; 58 59 wctmu->dev = &pdev->dev; 60 wctmu->regmap = pmic->regmap; 61 62 irq = platform_get_irq(pdev, 0); 63 if (irq < 0) 64 return irq; 65 66 regmap_irq_chip = pmic->irq_chip_data_tmu; 67 virq = regmap_irq_get_virq(regmap_irq_chip, irq); 68 if (virq < 0) { 69 dev_err(&pdev->dev, 70 "failed to get virtual interrupt=%d\n", irq); 71 return virq; 72 } 73 74 ret = devm_request_threaded_irq(&pdev->dev, virq, 75 NULL, bxt_wcove_tmu_irq_handler, 76 IRQF_ONESHOT, "bxt_wcove_tmu", wctmu); 77 if (ret) { 78 dev_err(&pdev->dev, "request irq failed: %d,virq: %d\n", 79 ret, virq); 80 return ret; 81 } 82 wctmu->irq = virq; 83 84 /* Unmask TMU second level Wake & System alarm */ 85 regmap_update_bits(wctmu->regmap, BXTWC_MTMUIRQ_REG, 86 BXTWC_TMU_ALRM_MASK, 0); 87 88 platform_set_drvdata(pdev, wctmu); 89 return 0; 90 } 91 92 static void bxt_wcove_tmu_remove(struct platform_device *pdev) 93 { 94 struct wcove_tmu *wctmu = platform_get_drvdata(pdev); 95 unsigned int val; 96 97 /* Mask TMU interrupts */ 98 regmap_read(wctmu->regmap, BXTWC_MIRQLVL1, &val); 99 regmap_write(wctmu->regmap, BXTWC_MIRQLVL1, 100 val | BXTWC_MIRQLVL1_MTMU); 101 regmap_read(wctmu->regmap, BXTWC_MTMUIRQ_REG, &val); 102 regmap_write(wctmu->regmap, BXTWC_MTMUIRQ_REG, 103 val | BXTWC_TMU_ALRM_MASK); 104 } 105 106 #ifdef CONFIG_PM_SLEEP 107 static int bxtwc_tmu_suspend(struct device *dev) 108 { 109 struct wcove_tmu *wctmu = dev_get_drvdata(dev); 110 111 enable_irq_wake(wctmu->irq); 112 return 0; 113 } 114 115 static int bxtwc_tmu_resume(struct device *dev) 116 { 117 struct wcove_tmu *wctmu = dev_get_drvdata(dev); 118 119 disable_irq_wake(wctmu->irq); 120 return 0; 121 } 122 #endif 123 124 static SIMPLE_DEV_PM_OPS(bxtwc_tmu_pm_ops, bxtwc_tmu_suspend, bxtwc_tmu_resume); 125 126 static const struct platform_device_id bxt_wcove_tmu_id_table[] = { 127 { .name = "bxt_wcove_tmu" }, 128 {}, 129 }; 130 MODULE_DEVICE_TABLE(platform, bxt_wcove_tmu_id_table); 131 132 static struct platform_driver bxt_wcove_tmu_driver = { 133 .probe = bxt_wcove_tmu_probe, 134 .remove_new = bxt_wcove_tmu_remove, 135 .driver = { 136 .name = "bxt_wcove_tmu", 137 .pm = &bxtwc_tmu_pm_ops, 138 }, 139 .id_table = bxt_wcove_tmu_id_table, 140 }; 141 142 module_platform_driver(bxt_wcove_tmu_driver); 143 144 MODULE_LICENSE("GPL v2"); 145 MODULE_AUTHOR("Nilesh Bacchewar <nilesh.bacchewar@intel.com>"); 146 MODULE_DESCRIPTION("BXT Whiskey Cove TMU Driver"); 147