bxtwc_tmu.c (3779B)
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 27struct wcove_tmu { 28 int irq; 29 struct device *dev; 30 struct regmap *regmap; 31}; 32 33static 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 48static 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 92static int 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 return 0; 105} 106 107#ifdef CONFIG_PM_SLEEP 108static int bxtwc_tmu_suspend(struct device *dev) 109{ 110 struct wcove_tmu *wctmu = dev_get_drvdata(dev); 111 112 enable_irq_wake(wctmu->irq); 113 return 0; 114} 115 116static int bxtwc_tmu_resume(struct device *dev) 117{ 118 struct wcove_tmu *wctmu = dev_get_drvdata(dev); 119 120 disable_irq_wake(wctmu->irq); 121 return 0; 122} 123#endif 124 125static SIMPLE_DEV_PM_OPS(bxtwc_tmu_pm_ops, bxtwc_tmu_suspend, bxtwc_tmu_resume); 126 127static const struct platform_device_id bxt_wcove_tmu_id_table[] = { 128 { .name = "bxt_wcove_tmu" }, 129 {}, 130}; 131MODULE_DEVICE_TABLE(platform, bxt_wcove_tmu_id_table); 132 133static struct platform_driver bxt_wcove_tmu_driver = { 134 .probe = bxt_wcove_tmu_probe, 135 .remove = bxt_wcove_tmu_remove, 136 .driver = { 137 .name = "bxt_wcove_tmu", 138 .pm = &bxtwc_tmu_pm_ops, 139 }, 140 .id_table = bxt_wcove_tmu_id_table, 141}; 142 143module_platform_driver(bxt_wcove_tmu_driver); 144 145MODULE_LICENSE("GPL v2"); 146MODULE_AUTHOR("Nilesh Bacchewar <nilesh.bacchewar@intel.com>"); 147MODULE_DESCRIPTION("BXT Whiskey Cove TMU Driver");