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