Linux Audio

Check our new training course

Loading...
Note: File does not exist in v3.1.
  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");