• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // SPDX-License-Identifier: GPL-2.0-only
2 /*
3  * ZTE's zx2967 family thermal sensor driver
4  *
5  * Copyright (C) 2017 ZTE Ltd.
6  *
7  * Author: Baoyou Xie <baoyou.xie@linaro.org>
8  */
9 
10 #include <linux/clk.h>
11 #include <linux/device.h>
12 #include <linux/err.h>
13 #include <linux/iopoll.h>
14 #include <linux/module.h>
15 #include <linux/platform_device.h>
16 #include <linux/thermal.h>
17 
18 /* Power Mode: 0->low 1->high */
19 #define ZX2967_THERMAL_POWER_MODE	0
20 #define ZX2967_POWER_MODE_LOW		0
21 #define ZX2967_POWER_MODE_HIGH		1
22 
23 /* DCF Control Register */
24 #define ZX2967_THERMAL_DCF		0x4
25 #define ZX2967_DCF_EN			BIT(1)
26 #define ZX2967_DCF_FREEZE		BIT(0)
27 
28 /* Selection Register */
29 #define ZX2967_THERMAL_SEL		0x8
30 
31 /* Control Register */
32 #define ZX2967_THERMAL_CTRL		0x10
33 
34 #define ZX2967_THERMAL_READY		BIT(12)
35 #define ZX2967_THERMAL_TEMP_MASK	GENMASK(11, 0)
36 #define ZX2967_THERMAL_ID_MASK		0x18
37 #define ZX2967_THERMAL_ID		0x10
38 
39 #define ZX2967_GET_TEMP_TIMEOUT_US	(100 * 1024)
40 
41 /**
42  * struct zx2967_thermal_priv - zx2967 thermal sensor private structure
43  * @tzd: struct thermal_zone_device where the sensor is registered
44  * @lock: prevents read sensor in parallel
45  * @clk_topcrm: topcrm clk structure
46  * @clk_apb: apb clk structure
47  * @regs: pointer to base address of the thermal sensor
48  */
49 
50 struct zx2967_thermal_priv {
51 	struct thermal_zone_device	*tzd;
52 	struct mutex			lock;
53 	struct clk			*clk_topcrm;
54 	struct clk			*clk_apb;
55 	void __iomem			*regs;
56 	struct device			*dev;
57 };
58 
zx2967_thermal_get_temp(void * data,int * temp)59 static int zx2967_thermal_get_temp(void *data, int *temp)
60 {
61 	void __iomem *regs;
62 	struct zx2967_thermal_priv *priv = data;
63 	u32 val;
64 	int ret;
65 
66 	if (!priv->tzd)
67 		return -EAGAIN;
68 
69 	regs = priv->regs;
70 	mutex_lock(&priv->lock);
71 	writel_relaxed(ZX2967_POWER_MODE_LOW,
72 		       regs + ZX2967_THERMAL_POWER_MODE);
73 	writel_relaxed(ZX2967_DCF_EN, regs + ZX2967_THERMAL_DCF);
74 
75 	val = readl_relaxed(regs + ZX2967_THERMAL_SEL);
76 	val &= ~ZX2967_THERMAL_ID_MASK;
77 	val |= ZX2967_THERMAL_ID;
78 	writel_relaxed(val, regs + ZX2967_THERMAL_SEL);
79 
80 	/*
81 	 * Must wait for a while, surely it's a bit odd.
82 	 * otherwise temperature value we got has a few deviation, even if
83 	 * the THERMAL_READY bit is set.
84 	 */
85 	usleep_range(100, 300);
86 	ret = readx_poll_timeout(readl, regs + ZX2967_THERMAL_CTRL,
87 				 val, val & ZX2967_THERMAL_READY, 300,
88 				 ZX2967_GET_TEMP_TIMEOUT_US);
89 	if (ret) {
90 		dev_err(priv->dev, "Thermal sensor data timeout\n");
91 		goto unlock;
92 	}
93 
94 	writel_relaxed(ZX2967_DCF_FREEZE | ZX2967_DCF_EN,
95 		       regs + ZX2967_THERMAL_DCF);
96 	val = readl_relaxed(regs + ZX2967_THERMAL_CTRL)
97 			 & ZX2967_THERMAL_TEMP_MASK;
98 	writel_relaxed(ZX2967_POWER_MODE_HIGH,
99 		       regs + ZX2967_THERMAL_POWER_MODE);
100 
101 	/*
102 	 * Calculate temperature
103 	 * In dts, slope is multiplied by 1000.
104 	 */
105 	*temp = DIV_ROUND_CLOSEST(((s32)val + priv->tzd->tzp->offset) * 1000,
106 				  priv->tzd->tzp->slope);
107 
108 unlock:
109 	mutex_unlock(&priv->lock);
110 	return ret;
111 }
112 
113 static const struct thermal_zone_of_device_ops zx2967_of_thermal_ops = {
114 	.get_temp = zx2967_thermal_get_temp,
115 };
116 
zx2967_thermal_probe(struct platform_device * pdev)117 static int zx2967_thermal_probe(struct platform_device *pdev)
118 {
119 	struct zx2967_thermal_priv *priv;
120 	struct resource *res;
121 	int ret;
122 
123 	priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL);
124 	if (!priv)
125 		return -ENOMEM;
126 
127 	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
128 	priv->regs = devm_ioremap_resource(&pdev->dev, res);
129 	if (IS_ERR(priv->regs))
130 		return PTR_ERR(priv->regs);
131 
132 	priv->clk_topcrm = devm_clk_get(&pdev->dev, "topcrm");
133 	if (IS_ERR(priv->clk_topcrm)) {
134 		ret = PTR_ERR(priv->clk_topcrm);
135 		dev_err(&pdev->dev, "failed to get topcrm clock: %d\n", ret);
136 		return ret;
137 	}
138 
139 	ret = clk_prepare_enable(priv->clk_topcrm);
140 	if (ret) {
141 		dev_err(&pdev->dev, "failed to enable topcrm clock: %d\n",
142 			ret);
143 		return ret;
144 	}
145 
146 	priv->clk_apb = devm_clk_get(&pdev->dev, "apb");
147 	if (IS_ERR(priv->clk_apb)) {
148 		ret = PTR_ERR(priv->clk_apb);
149 		dev_err(&pdev->dev, "failed to get apb clock: %d\n", ret);
150 		goto disable_clk_topcrm;
151 	}
152 
153 	ret = clk_prepare_enable(priv->clk_apb);
154 	if (ret) {
155 		dev_err(&pdev->dev, "failed to enable apb clock: %d\n",
156 			ret);
157 		goto disable_clk_topcrm;
158 	}
159 
160 	mutex_init(&priv->lock);
161 	priv->tzd = thermal_zone_of_sensor_register(&pdev->dev,
162 					0, priv, &zx2967_of_thermal_ops);
163 
164 	if (IS_ERR(priv->tzd)) {
165 		ret = PTR_ERR(priv->tzd);
166 		dev_err(&pdev->dev, "failed to register sensor: %d\n", ret);
167 		goto disable_clk_all;
168 	}
169 
170 	if (priv->tzd->tzp->slope == 0) {
171 		thermal_zone_of_sensor_unregister(&pdev->dev, priv->tzd);
172 		dev_err(&pdev->dev, "coefficients of sensor is invalid\n");
173 		ret = -EINVAL;
174 		goto disable_clk_all;
175 	}
176 
177 	priv->dev = &pdev->dev;
178 	platform_set_drvdata(pdev, priv);
179 
180 	return 0;
181 
182 disable_clk_all:
183 	clk_disable_unprepare(priv->clk_apb);
184 disable_clk_topcrm:
185 	clk_disable_unprepare(priv->clk_topcrm);
186 	return ret;
187 }
188 
zx2967_thermal_exit(struct platform_device * pdev)189 static int zx2967_thermal_exit(struct platform_device *pdev)
190 {
191 	struct zx2967_thermal_priv *priv = platform_get_drvdata(pdev);
192 
193 	thermal_zone_of_sensor_unregister(&pdev->dev, priv->tzd);
194 	clk_disable_unprepare(priv->clk_topcrm);
195 	clk_disable_unprepare(priv->clk_apb);
196 
197 	return 0;
198 }
199 
200 static const struct of_device_id zx2967_thermal_id_table[] = {
201 	{ .compatible = "zte,zx296718-thermal" },
202 	{}
203 };
204 MODULE_DEVICE_TABLE(of, zx2967_thermal_id_table);
205 
206 #ifdef CONFIG_PM_SLEEP
zx2967_thermal_suspend(struct device * dev)207 static int zx2967_thermal_suspend(struct device *dev)
208 {
209 	struct zx2967_thermal_priv *priv = dev_get_drvdata(dev);
210 
211 	if (priv && priv->clk_topcrm)
212 		clk_disable_unprepare(priv->clk_topcrm);
213 
214 	if (priv && priv->clk_apb)
215 		clk_disable_unprepare(priv->clk_apb);
216 
217 	return 0;
218 }
219 
zx2967_thermal_resume(struct device * dev)220 static int zx2967_thermal_resume(struct device *dev)
221 {
222 	struct zx2967_thermal_priv *priv = dev_get_drvdata(dev);
223 	int error;
224 
225 	error = clk_prepare_enable(priv->clk_topcrm);
226 	if (error)
227 		return error;
228 
229 	error = clk_prepare_enable(priv->clk_apb);
230 	if (error) {
231 		clk_disable_unprepare(priv->clk_topcrm);
232 		return error;
233 	}
234 
235 	return 0;
236 }
237 #endif
238 
239 static SIMPLE_DEV_PM_OPS(zx2967_thermal_pm_ops,
240 			 zx2967_thermal_suspend, zx2967_thermal_resume);
241 
242 static struct platform_driver zx2967_thermal_driver = {
243 	.probe = zx2967_thermal_probe,
244 	.remove = zx2967_thermal_exit,
245 	.driver = {
246 		.name = "zx2967_thermal",
247 		.of_match_table = zx2967_thermal_id_table,
248 		.pm = &zx2967_thermal_pm_ops,
249 	},
250 };
251 module_platform_driver(zx2967_thermal_driver);
252 
253 MODULE_AUTHOR("Baoyou Xie <baoyou.xie@linaro.org>");
254 MODULE_DESCRIPTION("ZTE zx2967 thermal driver");
255 MODULE_LICENSE("GPL v2");
256