aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/thermal
diff options
context:
space:
mode:
authorAndrew Lunn <andrew@lunn.ch>2013-02-06 01:35:26 -0500
committerZhang Rui <rui.zhang@intel.com>2013-02-08 07:26:02 -0500
commit74ffa64c23616706381c30064a47888382bba30f (patch)
tree9d97a2a194cc3444535e2decc9ff4fb2d6a53d46 /drivers/thermal
parent7060aa36645c51d1205ef0e0cbf7b564f1f52f36 (diff)
Thermal: Dove: Add Themal sensor support for Dove.
The Marvell Dove SoC has a thermal sensor. Add a driver using the thermal framework. Signed-off-by: Andrew Lunn <andrew@lunn.ch> Signed-off-by: Sebastian Hesselbarth <sebastian.hesselbarth@gmail.com> Signed-off-by: Zhang Rui <rui.zhang@intel.com>
Diffstat (limited to 'drivers/thermal')
-rw-r--r--drivers/thermal/Kconfig8
-rw-r--r--drivers/thermal/Makefile1
-rw-r--r--drivers/thermal/dove_thermal.c209
3 files changed, 218 insertions, 0 deletions
diff --git a/drivers/thermal/Kconfig b/drivers/thermal/Kconfig
index 5070fbee24ef..24d913aa1003 100644
--- a/drivers/thermal/Kconfig
+++ b/drivers/thermal/Kconfig
@@ -126,6 +126,14 @@ config EXYNOS_THERMAL_EMUL
126 device directory to support emulation mode. With emulation mode sysfs 126 device directory to support emulation mode. With emulation mode sysfs
127 node, you can manually input temperature to TMU for simulation purpose. 127 node, you can manually input temperature to TMU for simulation purpose.
128 128
129config DOVE_THERMAL
130 tristate "Temperature sensor on Marvell Dove SoCs"
131 depends on ARCH_DOVE
132 depends on OF
133 help
134 Support for the Dove thermal sensor driver in the Linux thermal
135 framework.
136
129config DB8500_THERMAL 137config DB8500_THERMAL
130 bool "DB8500 thermal management" 138 bool "DB8500 thermal management"
131 depends on ARCH_U8500 139 depends on ARCH_U8500
diff --git a/drivers/thermal/Makefile b/drivers/thermal/Makefile
index b32c35de67e7..f5c01cce7768 100644
--- a/drivers/thermal/Makefile
+++ b/drivers/thermal/Makefile
@@ -17,6 +17,7 @@ obj-$(CONFIG_SPEAR_THERMAL) += spear_thermal.o
17obj-$(CONFIG_RCAR_THERMAL) += rcar_thermal.o 17obj-$(CONFIG_RCAR_THERMAL) += rcar_thermal.o
18obj-$(CONFIG_KIRKWOOD_THERMAL) += kirkwood_thermal.o 18obj-$(CONFIG_KIRKWOOD_THERMAL) += kirkwood_thermal.o
19obj-$(CONFIG_EXYNOS_THERMAL) += exynos_thermal.o 19obj-$(CONFIG_EXYNOS_THERMAL) += exynos_thermal.o
20obj-$(CONFIG_DOVE_THERMAL) += dove_thermal.o
20obj-$(CONFIG_DB8500_THERMAL) += db8500_thermal.o 21obj-$(CONFIG_DB8500_THERMAL) += db8500_thermal.o
21obj-$(CONFIG_DB8500_CPUFREQ_COOLING) += db8500_cpufreq_cooling.o 22obj-$(CONFIG_DB8500_CPUFREQ_COOLING) += db8500_cpufreq_cooling.o
22obj-$(CONFIG_INTEL_POWERCLAMP) += intel_powerclamp.o 23obj-$(CONFIG_INTEL_POWERCLAMP) += intel_powerclamp.o
diff --git a/drivers/thermal/dove_thermal.c b/drivers/thermal/dove_thermal.c
new file mode 100644
index 000000000000..7b0bfa0e7a9c
--- /dev/null
+++ b/drivers/thermal/dove_thermal.c
@@ -0,0 +1,209 @@
1/*
2 * Dove thermal sensor driver
3 *
4 * Copyright (C) 2013 Andrew Lunn <andrew@lunn.ch>
5 *
6 * This software is licensed under the terms of the GNU General Public
7 * License version 2, as published by the Free Software Foundation, and
8 * may be copied, distributed, and modified under those terms.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 */
16#include <linux/device.h>
17#include <linux/err.h>
18#include <linux/io.h>
19#include <linux/kernel.h>
20#include <linux/of.h>
21#include <linux/module.h>
22#include <linux/platform_device.h>
23#include <linux/thermal.h>
24
25#define DOVE_THERMAL_TEMP_OFFSET 1
26#define DOVE_THERMAL_TEMP_MASK 0x1FF
27
28/* Dove Thermal Manager Control and Status Register */
29#define PMU_TM_DISABLE_OFFS 0
30#define PMU_TM_DISABLE_MASK (0x1 << PMU_TM_DISABLE_OFFS)
31
32/* Dove Theraml Diode Control 0 Register */
33#define PMU_TDC0_SW_RST_MASK (0x1 << 1)
34#define PMU_TDC0_SEL_VCAL_OFFS 5
35#define PMU_TDC0_SEL_VCAL_MASK (0x3 << PMU_TDC0_SEL_VCAL_OFFS)
36#define PMU_TDC0_REF_CAL_CNT_OFFS 11
37#define PMU_TDC0_REF_CAL_CNT_MASK (0x1FF << PMU_TDC0_REF_CAL_CNT_OFFS)
38#define PMU_TDC0_AVG_NUM_OFFS 25
39#define PMU_TDC0_AVG_NUM_MASK (0x7 << PMU_TDC0_AVG_NUM_OFFS)
40
41/* Dove Thermal Diode Control 1 Register */
42#define PMU_TEMP_DIOD_CTRL1_REG 0x04
43#define PMU_TDC1_TEMP_VALID_MASK (0x1 << 10)
44
45/* Dove Thermal Sensor Dev Structure */
46struct dove_thermal_priv {
47 void __iomem *sensor;
48 void __iomem *control;
49};
50
51static int dove_init_sensor(const struct dove_thermal_priv *priv)
52{
53 u32 reg;
54 u32 i;
55
56 /* Configure the Diode Control Register #0 */
57 reg = readl_relaxed(priv->control);
58
59 /* Use average of 2 */
60 reg &= ~PMU_TDC0_AVG_NUM_MASK;
61 reg |= (0x1 << PMU_TDC0_AVG_NUM_OFFS);
62
63 /* Reference calibration value */
64 reg &= ~PMU_TDC0_REF_CAL_CNT_MASK;
65 reg |= (0x0F1 << PMU_TDC0_REF_CAL_CNT_OFFS);
66
67 /* Set the high level reference for calibration */
68 reg &= ~PMU_TDC0_SEL_VCAL_MASK;
69 reg |= (0x2 << PMU_TDC0_SEL_VCAL_OFFS);
70 writel(reg, priv->control);
71
72 /* Reset the sensor */
73 reg = readl_relaxed(priv->control);
74 writel((reg | PMU_TDC0_SW_RST_MASK), priv->control);
75 writel(reg, priv->control);
76
77 /* Enable the sensor */
78 reg = readl_relaxed(priv->sensor);
79 reg &= ~PMU_TM_DISABLE_MASK;
80 writel(reg, priv->sensor);
81
82 /* Poll the sensor for the first reading */
83 for (i = 0; i < 1000000; i++) {
84 reg = readl_relaxed(priv->sensor);
85 if (reg & DOVE_THERMAL_TEMP_MASK)
86 break;
87 }
88
89 if (i == 1000000)
90 return -EIO;
91
92 return 0;
93}
94
95static int dove_get_temp(struct thermal_zone_device *thermal,
96 unsigned long *temp)
97{
98 unsigned long reg;
99 struct dove_thermal_priv *priv = thermal->devdata;
100
101 /* Valid check */
102 reg = readl_relaxed(priv->control + PMU_TEMP_DIOD_CTRL1_REG);
103 if ((reg & PMU_TDC1_TEMP_VALID_MASK) == 0x0) {
104 dev_err(&thermal->device,
105 "Temperature sensor reading not valid\n");
106 return -EIO;
107 }
108
109 /*
110 * Calculate temperature. See Section 8.10.1 of 88AP510,
111 * Documentation/arm/Marvell/README
112 */
113 reg = readl_relaxed(priv->sensor);
114 reg = (reg >> DOVE_THERMAL_TEMP_OFFSET) & DOVE_THERMAL_TEMP_MASK;
115 *temp = ((2281638UL - (7298*reg)) / 10);
116
117 return 0;
118}
119
120static struct thermal_zone_device_ops ops = {
121 .get_temp = dove_get_temp,
122};
123
124static const struct of_device_id dove_thermal_id_table[] = {
125 { .compatible = "marvell,dove-thermal" },
126 {}
127};
128
129static int dove_thermal_probe(struct platform_device *pdev)
130{
131 struct thermal_zone_device *thermal = NULL;
132 struct dove_thermal_priv *priv;
133 struct resource *res;
134 int ret;
135
136 res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
137 if (!res) {
138 dev_err(&pdev->dev, "Failed to get platform resource\n");
139 return -ENODEV;
140 }
141
142 priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL);
143 if (!priv)
144 return -ENOMEM;
145
146 priv->sensor = devm_request_and_ioremap(&pdev->dev, res);
147 if (!priv->sensor) {
148 dev_err(&pdev->dev, "Failed to request_ioremap memory\n");
149 return -EADDRNOTAVAIL;
150 }
151
152 res = platform_get_resource(pdev, IORESOURCE_MEM, 1);
153 if (!res) {
154 dev_err(&pdev->dev, "Failed to get platform resource\n");
155 return -ENODEV;
156 }
157 priv->control = devm_request_and_ioremap(&pdev->dev, res);
158 if (!priv->control) {
159 dev_err(&pdev->dev, "Failed to request_ioremap memory\n");
160 return -EADDRNOTAVAIL;
161 }
162
163 ret = dove_init_sensor(priv);
164 if (ret) {
165 dev_err(&pdev->dev, "Failed to initialize sensor\n");
166 return ret;
167 }
168
169 thermal = thermal_zone_device_register("dove_thermal", 0, 0,
170 priv, &ops, NULL, 0, 0);
171 if (IS_ERR(thermal)) {
172 dev_err(&pdev->dev,
173 "Failed to register thermal zone device\n");
174 return PTR_ERR(thermal);
175 }
176
177 platform_set_drvdata(pdev, thermal);
178
179 return 0;
180}
181
182static int dove_thermal_exit(struct platform_device *pdev)
183{
184 struct thermal_zone_device *dove_thermal =
185 platform_get_drvdata(pdev);
186
187 thermal_zone_device_unregister(dove_thermal);
188 platform_set_drvdata(pdev, NULL);
189
190 return 0;
191}
192
193MODULE_DEVICE_TABLE(of, dove_thermal_id_table);
194
195static struct platform_driver dove_thermal_driver = {
196 .probe = dove_thermal_probe,
197 .remove = dove_thermal_exit,
198 .driver = {
199 .name = "dove_thermal",
200 .owner = THIS_MODULE,
201 .of_match_table = of_match_ptr(dove_thermal_id_table),
202 },
203};
204
205module_platform_driver(dove_thermal_driver);
206
207MODULE_AUTHOR("Andrew Lunn <andrew@lunn.ch>");
208MODULE_DESCRIPTION("Dove thermal driver");
209MODULE_LICENSE("GPL");