linux/drivers/platform/x86/intel_bxtwc_tmu.c
<<
>>
Prefs
   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");
 148