xref: /linux/drivers/hwmon/sfctemp.c (revision 02892f90a9851f508e557b3c75e93fc178310d5f)
1 // SPDX-License-Identifier: GPL-2.0
2 /*
3  * Copyright (C) 2021 Emil Renner Berthing <kernel@esmil.dk>
4  * Copyright (C) 2021 Samin Guo <samin.guo@starfivetech.com>
5  */
6 
7 #include <linux/bits.h>
8 #include <linux/clk.h>
9 #include <linux/delay.h>
10 #include <linux/hwmon.h>
11 #include <linux/io.h>
12 #include <linux/module.h>
13 #include <linux/of.h>
14 #include <linux/platform_device.h>
15 #include <linux/reset.h>
16 
17 /*
18  * TempSensor reset. The RSTN can be de-asserted once the analog core has
19  * powered up. Trst(min 100ns)
20  * 0:reset  1:de-assert
21  */
22 #define SFCTEMP_RSTN	BIT(0)
23 
24 /*
25  * TempSensor analog core power down. The analog core will be powered up
26  * Tpu(min 50us) after PD is de-asserted. RSTN should be held low until the
27  * analog core is powered up.
28  * 0:power up  1:power down
29  */
30 #define SFCTEMP_PD	BIT(1)
31 
32 /*
33  * TempSensor start conversion enable.
34  * 0:disable  1:enable
35  */
36 #define SFCTEMP_RUN	BIT(2)
37 
38 /*
39  * TempSensor conversion value output.
40  * Temp(C)=DOUT*Y/4094 - K
41  */
42 #define SFCTEMP_DOUT_POS	16
43 #define SFCTEMP_DOUT_MSK	GENMASK(27, 16)
44 
45 /* DOUT to Celcius conversion constants */
46 #define SFCTEMP_Y1000	237500L
47 #define SFCTEMP_Z	4094L
48 #define SFCTEMP_K1000	81100L
49 
50 struct sfctemp {
51 	void __iomem *regs;
52 	struct clk *clk_sense;
53 	struct clk *clk_bus;
54 	struct reset_control *rst_sense;
55 	struct reset_control *rst_bus;
56 	bool enabled;
57 };
58 
59 static void sfctemp_power_up(struct sfctemp *sfctemp)
60 {
61 	/* make sure we're powered down first */
62 	writel(SFCTEMP_PD, sfctemp->regs);
63 	udelay(1);
64 
65 	writel(0, sfctemp->regs);
66 	/* wait t_pu(50us) + t_rst(100ns) */
67 	usleep_range(60, 200);
68 
69 	/* de-assert reset */
70 	writel(SFCTEMP_RSTN, sfctemp->regs);
71 	udelay(1); /* wait t_su(500ps) */
72 }
73 
74 static void sfctemp_power_down(struct sfctemp *sfctemp)
75 {
76 	writel(SFCTEMP_PD, sfctemp->regs);
77 }
78 
79 static void sfctemp_run(struct sfctemp *sfctemp)
80 {
81 	writel(SFCTEMP_RSTN | SFCTEMP_RUN, sfctemp->regs);
82 	udelay(1);
83 }
84 
85 static void sfctemp_stop(struct sfctemp *sfctemp)
86 {
87 	writel(SFCTEMP_RSTN, sfctemp->regs);
88 }
89 
90 static int sfctemp_enable(struct sfctemp *sfctemp)
91 {
92 	int ret;
93 
94 	if (sfctemp->enabled)
95 		return 0;
96 
97 	ret = clk_prepare_enable(sfctemp->clk_bus);
98 	if (ret)
99 		return ret;
100 	ret = reset_control_deassert(sfctemp->rst_bus);
101 	if (ret)
102 		goto err_disable_bus;
103 
104 	ret = clk_prepare_enable(sfctemp->clk_sense);
105 	if (ret)
106 		goto err_assert_bus;
107 	ret = reset_control_deassert(sfctemp->rst_sense);
108 	if (ret)
109 		goto err_disable_sense;
110 
111 	sfctemp_power_up(sfctemp);
112 	sfctemp_run(sfctemp);
113 	sfctemp->enabled = true;
114 	return 0;
115 
116 err_disable_sense:
117 	clk_disable_unprepare(sfctemp->clk_sense);
118 err_assert_bus:
119 	reset_control_assert(sfctemp->rst_bus);
120 err_disable_bus:
121 	clk_disable_unprepare(sfctemp->clk_bus);
122 	return ret;
123 }
124 
125 static int sfctemp_disable(struct sfctemp *sfctemp)
126 {
127 	if (!sfctemp->enabled)
128 		return 0;
129 
130 	sfctemp_stop(sfctemp);
131 	sfctemp_power_down(sfctemp);
132 	reset_control_assert(sfctemp->rst_sense);
133 	clk_disable_unprepare(sfctemp->clk_sense);
134 	reset_control_assert(sfctemp->rst_bus);
135 	clk_disable_unprepare(sfctemp->clk_bus);
136 	sfctemp->enabled = false;
137 	return 0;
138 }
139 
140 static void sfctemp_disable_action(void *data)
141 {
142 	sfctemp_disable(data);
143 }
144 
145 static int sfctemp_convert(struct sfctemp *sfctemp, long *val)
146 {
147 	if (!sfctemp->enabled)
148 		return -ENODATA;
149 
150 	/* calculate temperature in milli Celcius */
151 	*val = (long)((readl(sfctemp->regs) & SFCTEMP_DOUT_MSK) >> SFCTEMP_DOUT_POS)
152 		* SFCTEMP_Y1000 / SFCTEMP_Z - SFCTEMP_K1000;
153 
154 	return 0;
155 }
156 
157 static umode_t sfctemp_is_visible(const void *data, enum hwmon_sensor_types type,
158 				  u32 attr, int channel)
159 {
160 	switch (type) {
161 	case hwmon_temp:
162 		switch (attr) {
163 		case hwmon_temp_enable:
164 			return 0644;
165 		case hwmon_temp_input:
166 			return 0444;
167 		default:
168 			return 0;
169 		}
170 	default:
171 		return 0;
172 	}
173 }
174 
175 static int sfctemp_read(struct device *dev, enum hwmon_sensor_types type,
176 			u32 attr, int channel, long *val)
177 {
178 	struct sfctemp *sfctemp = dev_get_drvdata(dev);
179 
180 	switch (type) {
181 	case hwmon_temp:
182 		switch (attr) {
183 		case hwmon_temp_enable:
184 			*val = sfctemp->enabled;
185 			return 0;
186 		case hwmon_temp_input:
187 			return sfctemp_convert(sfctemp, val);
188 		default:
189 			return -EINVAL;
190 		}
191 	default:
192 		return -EINVAL;
193 	}
194 }
195 
196 static int sfctemp_write(struct device *dev, enum hwmon_sensor_types type,
197 			 u32 attr, int channel, long val)
198 {
199 	struct sfctemp *sfctemp = dev_get_drvdata(dev);
200 
201 	switch (type) {
202 	case hwmon_temp:
203 		switch (attr) {
204 		case hwmon_temp_enable:
205 			if (val == 0)
206 				return sfctemp_disable(sfctemp);
207 			if (val == 1)
208 				return sfctemp_enable(sfctemp);
209 			return -EINVAL;
210 		default:
211 			return -EINVAL;
212 		}
213 	default:
214 		return -EINVAL;
215 	}
216 }
217 
218 static const struct hwmon_channel_info *sfctemp_info[] = {
219 	HWMON_CHANNEL_INFO(chip, HWMON_C_REGISTER_TZ),
220 	HWMON_CHANNEL_INFO(temp, HWMON_T_ENABLE | HWMON_T_INPUT),
221 	NULL
222 };
223 
224 static const struct hwmon_ops sfctemp_hwmon_ops = {
225 	.is_visible = sfctemp_is_visible,
226 	.read = sfctemp_read,
227 	.write = sfctemp_write,
228 };
229 
230 static const struct hwmon_chip_info sfctemp_chip_info = {
231 	.ops = &sfctemp_hwmon_ops,
232 	.info = sfctemp_info,
233 };
234 
235 static int sfctemp_probe(struct platform_device *pdev)
236 {
237 	struct device *dev = &pdev->dev;
238 	struct device *hwmon_dev;
239 	struct sfctemp *sfctemp;
240 	int ret;
241 
242 	sfctemp = devm_kzalloc(dev, sizeof(*sfctemp), GFP_KERNEL);
243 	if (!sfctemp)
244 		return -ENOMEM;
245 
246 	dev_set_drvdata(dev, sfctemp);
247 
248 	sfctemp->regs = devm_platform_ioremap_resource(pdev, 0);
249 	if (IS_ERR(sfctemp->regs))
250 		return PTR_ERR(sfctemp->regs);
251 
252 	sfctemp->clk_sense = devm_clk_get(dev, "sense");
253 	if (IS_ERR(sfctemp->clk_sense))
254 		return dev_err_probe(dev, PTR_ERR(sfctemp->clk_sense),
255 				     "error getting sense clock\n");
256 
257 	sfctemp->clk_bus = devm_clk_get(dev, "bus");
258 	if (IS_ERR(sfctemp->clk_bus))
259 		return dev_err_probe(dev, PTR_ERR(sfctemp->clk_bus),
260 				     "error getting bus clock\n");
261 
262 	sfctemp->rst_sense = devm_reset_control_get_exclusive(dev, "sense");
263 	if (IS_ERR(sfctemp->rst_sense))
264 		return dev_err_probe(dev, PTR_ERR(sfctemp->rst_sense),
265 				     "error getting sense reset\n");
266 
267 	sfctemp->rst_bus = devm_reset_control_get_exclusive(dev, "bus");
268 	if (IS_ERR(sfctemp->rst_bus))
269 		return dev_err_probe(dev, PTR_ERR(sfctemp->rst_bus),
270 				     "error getting busreset\n");
271 
272 	ret = reset_control_assert(sfctemp->rst_sense);
273 	if (ret)
274 		return dev_err_probe(dev, ret, "error asserting sense reset\n");
275 
276 	ret = reset_control_assert(sfctemp->rst_bus);
277 	if (ret)
278 		return dev_err_probe(dev, ret, "error asserting bus reset\n");
279 
280 	ret = devm_add_action(dev, sfctemp_disable_action, sfctemp);
281 	if (ret)
282 		return ret;
283 
284 	ret = sfctemp_enable(sfctemp);
285 	if (ret)
286 		return dev_err_probe(dev, ret, "error enabling temperature sensor\n");
287 
288 	hwmon_dev = devm_hwmon_device_register_with_info(dev, "sfctemp", sfctemp,
289 							 &sfctemp_chip_info, NULL);
290 	return PTR_ERR_OR_ZERO(hwmon_dev);
291 }
292 
293 static const struct of_device_id sfctemp_of_match[] = {
294 	{ .compatible = "starfive,jh7100-temp" },
295 	{ .compatible = "starfive,jh7110-temp" },
296 	{ /* sentinel */ }
297 };
298 MODULE_DEVICE_TABLE(of, sfctemp_of_match);
299 
300 static struct platform_driver sfctemp_driver = {
301 	.probe  = sfctemp_probe,
302 	.driver = {
303 		.name = "sfctemp",
304 		.of_match_table = sfctemp_of_match,
305 	},
306 };
307 module_platform_driver(sfctemp_driver);
308 
309 MODULE_AUTHOR("Emil Renner Berthing");
310 MODULE_DESCRIPTION("StarFive JH71x0 temperature sensor driver");
311 MODULE_LICENSE("GPL");
312