aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorNilesh Bacchewar <nilesh.bacchewar@intel.com>2016-11-07 15:11:47 -0500
committerDarren Hart <dvhart@linux.intel.com>2016-12-18 17:56:37 -0500
commit957ae5098185e763b5c06be6c3b4b6e98c048712 (patch)
treebe634c48fc0c9d6bdfacd07073269e68af1f564f
parente297046875f2c5a43684f54f0fd098249b4f293a (diff)
platform/x86: Add Whiskey Cove PMIC TMU support
This adds TMU (Time Management Unit) support for Intel BXT platform. It enables the alarm wake-up functionality in the TMU unit of Whiskey Cove PMIC. Signed-off-by: Nilesh Bacchewar <nilesh.bacchewar@intel.com> Reviewed-by: Mika Westerberg <mika.westerberg@linux.intel.com> [andy: resolve merge conflict in Kconfig] Signed-off-by: Andy Shevchenko <andriy.shevchenko@linux.intel.com>
-rw-r--r--drivers/mfd/intel_soc_pmic_bxtwc.c38
-rw-r--r--drivers/platform/x86/Kconfig9
-rw-r--r--drivers/platform/x86/Makefile1
-rw-r--r--drivers/platform/x86/intel_bxtwc_tmu.c162
-rw-r--r--include/linux/mfd/intel_soc_pmic.h1
5 files changed, 211 insertions, 0 deletions
diff --git a/drivers/mfd/intel_soc_pmic_bxtwc.c b/drivers/mfd/intel_soc_pmic_bxtwc.c
index 43e54b7e908f..92aba02042f0 100644
--- a/drivers/mfd/intel_soc_pmic_bxtwc.c
+++ b/drivers/mfd/intel_soc_pmic_bxtwc.c
@@ -42,6 +42,7 @@
42#define BXTWC_GPIOIRQ0 0x4E0B 42#define BXTWC_GPIOIRQ0 0x4E0B
43#define BXTWC_GPIOIRQ1 0x4E0C 43#define BXTWC_GPIOIRQ1 0x4E0C
44#define BXTWC_CRITIRQ 0x4E0D 44#define BXTWC_CRITIRQ 0x4E0D
45#define BXTWC_TMUIRQ 0x4FB6
45 46
46/* Interrupt MASK Registers */ 47/* Interrupt MASK Registers */
47#define BXTWC_MIRQLVL1 0x4E0E 48#define BXTWC_MIRQLVL1 0x4E0E
@@ -59,6 +60,7 @@
59#define BXTWC_MGPIO0IRQ 0x4E19 60#define BXTWC_MGPIO0IRQ 0x4E19
60#define BXTWC_MGPIO1IRQ 0x4E1A 61#define BXTWC_MGPIO1IRQ 0x4E1A
61#define BXTWC_MCRITIRQ 0x4E1B 62#define BXTWC_MCRITIRQ 0x4E1B
63#define BXTWC_MTMUIRQ 0x4FB7
62 64
63/* Whiskey Cove PMIC share same ACPI ID between different platforms */ 65/* Whiskey Cove PMIC share same ACPI ID between different platforms */
64#define BROXTON_PMIC_WC_HRV 4 66#define BROXTON_PMIC_WC_HRV 4
@@ -91,6 +93,7 @@ enum bxtwc_irqs_level2 {
91 BXTWC_GPIO0_IRQ, 93 BXTWC_GPIO0_IRQ,
92 BXTWC_GPIO1_IRQ, 94 BXTWC_GPIO1_IRQ,
93 BXTWC_CRIT_IRQ, 95 BXTWC_CRIT_IRQ,
96 BXTWC_TMU_IRQ,
94}; 97};
95 98
96static const struct regmap_irq bxtwc_regmap_irqs[] = { 99static const struct regmap_irq bxtwc_regmap_irqs[] = {
@@ -118,6 +121,10 @@ static const struct regmap_irq bxtwc_regmap_irqs_level2[] = {
118 REGMAP_IRQ_REG(BXTWC_CRIT_IRQ, 9, 0x03), 121 REGMAP_IRQ_REG(BXTWC_CRIT_IRQ, 9, 0x03),
119}; 122};
120 123
124static const struct regmap_irq bxtwc_regmap_irqs_tmu[] = {
125 REGMAP_IRQ_REG(BXTWC_TMU_IRQ, 0, 0x06),
126};
127
121static struct regmap_irq_chip bxtwc_regmap_irq_chip = { 128static struct regmap_irq_chip bxtwc_regmap_irq_chip = {
122 .name = "bxtwc_irq_chip", 129 .name = "bxtwc_irq_chip",
123 .status_base = BXTWC_IRQLVL1, 130 .status_base = BXTWC_IRQLVL1,
@@ -136,6 +143,15 @@ static struct regmap_irq_chip bxtwc_regmap_irq_chip_level2 = {
136 .num_regs = 10, 143 .num_regs = 10,
137}; 144};
138 145
146static struct regmap_irq_chip bxtwc_regmap_irq_chip_tmu = {
147 .name = "bxtwc_irq_chip_tmu",
148 .status_base = BXTWC_TMUIRQ,
149 .mask_base = BXTWC_MTMUIRQ,
150 .irqs = bxtwc_regmap_irqs_tmu,
151 .num_irqs = ARRAY_SIZE(bxtwc_regmap_irqs_tmu),
152 .num_regs = 1,
153};
154
139static struct resource gpio_resources[] = { 155static struct resource gpio_resources[] = {
140 DEFINE_RES_IRQ_NAMED(BXTWC_GPIO0_IRQ, "GPIO0"), 156 DEFINE_RES_IRQ_NAMED(BXTWC_GPIO0_IRQ, "GPIO0"),
141 DEFINE_RES_IRQ_NAMED(BXTWC_GPIO1_IRQ, "GPIO1"), 157 DEFINE_RES_IRQ_NAMED(BXTWC_GPIO1_IRQ, "GPIO1"),
@@ -164,6 +180,10 @@ static struct resource bcu_resources[] = {
164 DEFINE_RES_IRQ_NAMED(BXTWC_BCU_IRQ, "BCU"), 180 DEFINE_RES_IRQ_NAMED(BXTWC_BCU_IRQ, "BCU"),
165}; 181};
166 182
183static struct resource tmu_resources[] = {
184 DEFINE_RES_IRQ_NAMED(BXTWC_TMU_IRQ, "TMU"),
185};
186
167static struct mfd_cell bxt_wc_dev[] = { 187static struct mfd_cell bxt_wc_dev[] = {
168 { 188 {
169 .name = "bxt_wcove_gpadc", 189 .name = "bxt_wcove_gpadc",
@@ -191,6 +211,12 @@ static struct mfd_cell bxt_wc_dev[] = {
191 .resources = bcu_resources, 211 .resources = bcu_resources,
192 }, 212 },
193 { 213 {
214 .name = "bxt_wcove_tmu",
215 .num_resources = ARRAY_SIZE(tmu_resources),
216 .resources = tmu_resources,
217 },
218
219 {
194 .name = "bxt_wcove_gpio", 220 .name = "bxt_wcove_gpio",
195 .num_resources = ARRAY_SIZE(gpio_resources), 221 .num_resources = ARRAY_SIZE(gpio_resources),
196 .resources = gpio_resources, 222 .resources = gpio_resources,
@@ -400,6 +426,15 @@ static int bxtwc_probe(struct platform_device *pdev)
400 goto err_irq_chip_level2; 426 goto err_irq_chip_level2;
401 } 427 }
402 428
429 ret = regmap_add_irq_chip(pmic->regmap, pmic->irq,
430 IRQF_ONESHOT | IRQF_SHARED,
431 0, &bxtwc_regmap_irq_chip_tmu,
432 &pmic->irq_chip_data_tmu);
433 if (ret) {
434 dev_err(&pdev->dev, "Failed to add TMU IRQ chip\n");
435 goto err_irq_chip_tmu;
436 }
437
403 ret = mfd_add_devices(&pdev->dev, PLATFORM_DEVID_NONE, bxt_wc_dev, 438 ret = mfd_add_devices(&pdev->dev, PLATFORM_DEVID_NONE, bxt_wc_dev,
404 ARRAY_SIZE(bxt_wc_dev), NULL, 0, 439 ARRAY_SIZE(bxt_wc_dev), NULL, 0,
405 NULL); 440 NULL);
@@ -429,6 +464,8 @@ static int bxtwc_probe(struct platform_device *pdev)
429err_sysfs: 464err_sysfs:
430 mfd_remove_devices(&pdev->dev); 465 mfd_remove_devices(&pdev->dev);
431err_mfd: 466err_mfd:
467 regmap_del_irq_chip(pmic->irq, pmic->irq_chip_data_tmu);
468err_irq_chip_tmu:
432 regmap_del_irq_chip(pmic->irq, pmic->irq_chip_data_level2); 469 regmap_del_irq_chip(pmic->irq, pmic->irq_chip_data_level2);
433err_irq_chip_level2: 470err_irq_chip_level2:
434 regmap_del_irq_chip(pmic->irq, pmic->irq_chip_data); 471 regmap_del_irq_chip(pmic->irq, pmic->irq_chip_data);
@@ -444,6 +481,7 @@ static int bxtwc_remove(struct platform_device *pdev)
444 mfd_remove_devices(&pdev->dev); 481 mfd_remove_devices(&pdev->dev);
445 regmap_del_irq_chip(pmic->irq, pmic->irq_chip_data); 482 regmap_del_irq_chip(pmic->irq, pmic->irq_chip_data);
446 regmap_del_irq_chip(pmic->irq, pmic->irq_chip_data_level2); 483 regmap_del_irq_chip(pmic->irq, pmic->irq_chip_data_level2);
484 regmap_del_irq_chip(pmic->irq, pmic->irq_chip_data_tmu);
447 485
448 return 0; 486 return 0;
449} 487}
diff --git a/drivers/platform/x86/Kconfig b/drivers/platform/x86/Kconfig
index 493e3386fbf6..5fe8be089b8b 100644
--- a/drivers/platform/x86/Kconfig
+++ b/drivers/platform/x86/Kconfig
@@ -1017,6 +1017,15 @@ config INTEL_PMC_IPC
1017 The PMC is an ARC processor which defines IPC commands for communication 1017 The PMC is an ARC processor which defines IPC commands for communication
1018 with other entities in the CPU. 1018 with other entities in the CPU.
1019 1019
1020config INTEL_BXTWC_PMIC_TMU
1021 tristate "Intel BXT Whiskey Cove TMU Driver"
1022 depends on REGMAP
1023 depends on INTEL_SOC_PMIC && INTEL_PMC_IPC
1024 ---help---
1025 Select this driver to use Intel BXT Whiskey Cove PMIC TMU feature.
1026 This driver enables the alarm wakeup functionality in the TMU unit
1027 of Whiskey Cove PMIC.
1028
1020config SURFACE_PRO3_BUTTON 1029config SURFACE_PRO3_BUTTON
1021 tristate "Power/home/volume buttons driver for Microsoft Surface Pro 3/4 tablet" 1030 tristate "Power/home/volume buttons driver for Microsoft Surface Pro 3/4 tablet"
1022 depends on ACPI && INPUT 1031 depends on ACPI && INPUT
diff --git a/drivers/platform/x86/Makefile b/drivers/platform/x86/Makefile
index e9290290f026..d4111f0f8a78 100644
--- a/drivers/platform/x86/Makefile
+++ b/drivers/platform/x86/Makefile
@@ -69,6 +69,7 @@ obj-$(CONFIG_INTEL_PMC_IPC) += intel_pmc_ipc.o
69obj-$(CONFIG_SURFACE_PRO3_BUTTON) += surfacepro3_button.o 69obj-$(CONFIG_SURFACE_PRO3_BUTTON) += surfacepro3_button.o
70obj-$(CONFIG_SURFACE_3_BUTTON) += surface3_button.o 70obj-$(CONFIG_SURFACE_3_BUTTON) += surface3_button.o
71obj-$(CONFIG_INTEL_PUNIT_IPC) += intel_punit_ipc.o 71obj-$(CONFIG_INTEL_PUNIT_IPC) += intel_punit_ipc.o
72obj-$(CONFIG_INTEL_BXTWC_PMIC_TMU) += intel_bxtwc_tmu.o
72obj-$(CONFIG_INTEL_TELEMETRY) += intel_telemetry_core.o \ 73obj-$(CONFIG_INTEL_TELEMETRY) += intel_telemetry_core.o \
73 intel_telemetry_pltdrv.o \ 74 intel_telemetry_pltdrv.o \
74 intel_telemetry_debugfs.o 75 intel_telemetry_debugfs.o
diff --git a/drivers/platform/x86/intel_bxtwc_tmu.c b/drivers/platform/x86/intel_bxtwc_tmu.c
new file mode 100644
index 000000000000..e202abd5b0df
--- /dev/null
+++ b/drivers/platform/x86/intel_bxtwc_tmu.c
@@ -0,0 +1,162 @@
1/*
2 * intel_bxtwc_tmu.c - Intel BXT Whiskey Cove PMIC TMU driver
3 *
4 * Copyright (C) 2016 Intel Corporation. All rights reserved.
5 *
6 * This driver adds TMU (Time Management Unit) support for Intel BXT platform.
7 * It enables the alarm wake-up functionality in the TMU unit of Whiskey Cove
8 * PMIC.
9 *
10 * This program is free software; you can redistribute it and/or
11 * modify it under the terms of the GNU General Public License version
12 * 2 as published by the Free Software Foundation.
13 *
14 * This program is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU General Public License for more details.
18 *
19 */
20
21#include <linux/module.h>
22#include <linux/interrupt.h>
23#include <linux/platform_device.h>
24#include <linux/mfd/intel_soc_pmic.h>
25
26#define BXTWC_TMUIRQ 0x4fb6
27#define BXTWC_MIRQLVL1 0x4e0e
28#define BXTWC_MTMUIRQ_REG 0x4fb7
29#define BXTWC_MIRQLVL1_MTMU BIT(1)
30#define BXTWC_TMU_WK_ALRM BIT(1)
31#define BXTWC_TMU_SYS_ALRM BIT(2)
32#define BXTWC_TMU_ALRM_MASK (BXTWC_TMU_WK_ALRM | BXTWC_TMU_SYS_ALRM)
33#define BXTWC_TMU_ALRM_IRQ (BXTWC_TMU_WK_ALRM | BXTWC_TMU_SYS_ALRM)
34
35struct wcove_tmu {
36 int irq;
37 struct device *dev;
38 struct regmap *regmap;
39};
40
41static irqreturn_t bxt_wcove_tmu_irq_handler(int irq, void *data)
42{
43 struct wcove_tmu *wctmu = data;
44 unsigned int tmu_irq;
45
46 /* Read TMU interrupt reg */
47 regmap_read(wctmu->regmap, BXTWC_TMUIRQ, &tmu_irq);
48 if (tmu_irq & BXTWC_TMU_ALRM_IRQ) {
49 /* clear TMU irq */
50 regmap_write(wctmu->regmap, BXTWC_TMUIRQ, tmu_irq);
51 return IRQ_HANDLED;
52 }
53 return IRQ_NONE;
54}
55
56static int bxt_wcove_tmu_probe(struct platform_device *pdev)
57{
58 struct intel_soc_pmic *pmic = dev_get_drvdata(pdev->dev.parent);
59 struct regmap_irq_chip_data *regmap_irq_chip;
60 struct wcove_tmu *wctmu;
61 int ret, virq, irq;
62
63 wctmu = devm_kzalloc(&pdev->dev, sizeof(*wctmu), GFP_KERNEL);
64 if (!wctmu)
65 return -ENOMEM;
66
67 wctmu->dev = &pdev->dev;
68 wctmu->regmap = pmic->regmap;
69
70 irq = platform_get_irq(pdev, 0);
71
72 if (irq < 0) {
73 dev_err(&pdev->dev, "invalid irq %d\n", irq);
74 return irq;
75 }
76
77 regmap_irq_chip = pmic->irq_chip_data_tmu;
78 virq = regmap_irq_get_virq(regmap_irq_chip, irq);
79 if (virq < 0) {
80 dev_err(&pdev->dev,
81 "failed to get virtual interrupt=%d\n", irq);
82 return virq;
83 }
84
85 ret = devm_request_threaded_irq(&pdev->dev, virq,
86 NULL, bxt_wcove_tmu_irq_handler,
87 IRQF_ONESHOT, "bxt_wcove_tmu", wctmu);
88 if (ret) {
89 dev_err(&pdev->dev, "request irq failed: %d,virq: %d\n",
90 ret, virq);
91 return ret;
92 }
93 wctmu->irq = virq;
94
95 /* Enable TMU interrupts */
96 regmap_update_bits(wctmu->regmap, BXTWC_MIRQLVL1,
97 BXTWC_MIRQLVL1_MTMU, 0);
98
99 /* Unmask TMU second level Wake & System alarm */
100 regmap_update_bits(wctmu->regmap, BXTWC_MTMUIRQ_REG,
101 BXTWC_TMU_ALRM_MASK, 0);
102
103 platform_set_drvdata(pdev, wctmu);
104 return 0;
105}
106
107static int bxt_wcove_tmu_remove(struct platform_device *pdev)
108{
109 struct wcove_tmu *wctmu = platform_get_drvdata(pdev);
110 unsigned int val;
111
112 /* Mask TMU interrupts */
113 regmap_read(wctmu->regmap, BXTWC_MIRQLVL1, &val);
114 regmap_write(wctmu->regmap, BXTWC_MIRQLVL1,
115 val | BXTWC_MIRQLVL1_MTMU);
116 regmap_read(wctmu->regmap, BXTWC_MTMUIRQ_REG, &val);
117 regmap_write(wctmu->regmap, BXTWC_MTMUIRQ_REG,
118 val | BXTWC_TMU_ALRM_MASK);
119 return 0;
120}
121
122#ifdef CONFIG_PM_SLEEP
123static int bxtwc_tmu_suspend(struct device *dev)
124{
125 struct wcove_tmu *wctmu = dev_get_drvdata(dev);
126
127 enable_irq_wake(wctmu->irq);
128 return 0;
129}
130
131static int bxtwc_tmu_resume(struct device *dev)
132{
133 struct wcove_tmu *wctmu = dev_get_drvdata(dev);
134
135 disable_irq_wake(wctmu->irq);
136 return 0;
137}
138#endif
139
140static SIMPLE_DEV_PM_OPS(bxtwc_tmu_pm_ops, bxtwc_tmu_suspend, bxtwc_tmu_resume);
141
142static const struct platform_device_id bxt_wcove_tmu_id_table[] = {
143 { .name = "bxt_wcove_tmu" },
144 {},
145};
146MODULE_DEVICE_TABLE(platform, bxt_wcove_tmu_id_table);
147
148static struct platform_driver bxt_wcove_tmu_driver = {
149 .probe = bxt_wcove_tmu_probe,
150 .remove = bxt_wcove_tmu_remove,
151 .driver = {
152 .name = "bxt_wcove_tmu",
153 .pm = &bxtwc_tmu_pm_ops,
154 },
155 .id_table = bxt_wcove_tmu_id_table,
156};
157
158module_platform_driver(bxt_wcove_tmu_driver);
159
160MODULE_LICENSE("GPL v2");
161MODULE_AUTHOR("Nilesh Bacchewar <nilesh.bacchewar@intel.com>");
162MODULE_DESCRIPTION("BXT Whiskey Cove TMU Driver");
diff --git a/include/linux/mfd/intel_soc_pmic.h b/include/linux/mfd/intel_soc_pmic.h
index cf619dbeace2..956caa0628f5 100644
--- a/include/linux/mfd/intel_soc_pmic.h
+++ b/include/linux/mfd/intel_soc_pmic.h
@@ -26,6 +26,7 @@ struct intel_soc_pmic {
26 struct regmap *regmap; 26 struct regmap *regmap;
27 struct regmap_irq_chip_data *irq_chip_data; 27 struct regmap_irq_chip_data *irq_chip_data;
28 struct regmap_irq_chip_data *irq_chip_data_level2; 28 struct regmap_irq_chip_data *irq_chip_data_level2;
29 struct regmap_irq_chip_data *irq_chip_data_tmu;
29 struct device *dev; 30 struct device *dev;
30}; 31};
31 32