brintos

brintos / linux-shallow public Read only

0
0
Text · 14.0 KiB · ffd9886 Raw
593 lines · c
1// SPDX-License-Identifier: GPL-2.02/*3 * Copyright (C) STMicroelectronics 2018 - All Rights Reserved4 * Author: David Hernandez Sanchez <david.hernandezsanchez@st.com> for5 * STMicroelectronics.6 */7 8#include <linux/clk.h>9#include <linux/clk-provider.h>10#include <linux/delay.h>11#include <linux/err.h>12#include <linux/interrupt.h>13#include <linux/io.h>14#include <linux/iopoll.h>15#include <linux/module.h>16#include <linux/of.h>17#include <linux/platform_device.h>18#include <linux/thermal.h>19 20#include "../thermal_hwmon.h"21 22/* DTS register offsets */23#define DTS_CFGR1_OFFSET	0x024#define DTS_T0VALR1_OFFSET	0x825#define DTS_RAMPVALR_OFFSET	0X1026#define DTS_ITR1_OFFSET		0x1427#define DTS_DR_OFFSET		0x1C28#define DTS_SR_OFFSET		0x2029#define DTS_ITENR_OFFSET	0x2430#define DTS_ICIFR_OFFSET	0x2831 32/* DTS_CFGR1 register mask definitions */33#define HSREF_CLK_DIV_MASK	GENMASK(30, 24)34#define TS1_SMP_TIME_MASK	GENMASK(19, 16)35#define TS1_INTRIG_SEL_MASK	GENMASK(11, 8)36 37/* DTS_T0VALR1 register mask definitions */38#define TS1_T0_MASK		GENMASK(17, 16)39#define TS1_FMT0_MASK		GENMASK(15, 0)40 41/* DTS_RAMPVALR register mask definitions */42#define TS1_RAMP_COEFF_MASK	GENMASK(15, 0)43 44/* DTS_ITR1 register mask definitions */45#define TS1_HITTHD_MASK		GENMASK(31, 16)46#define TS1_LITTHD_MASK		GENMASK(15, 0)47 48/* DTS_DR register mask definitions */49#define TS1_MFREQ_MASK		GENMASK(15, 0)50 51/* DTS_ITENR register mask definitions */52#define ITENR_MASK		(GENMASK(2, 0) | GENMASK(6, 4))53 54/* DTS_ICIFR register mask definitions */55#define ICIFR_MASK		(GENMASK(2, 0) | GENMASK(6, 4))56 57/* Less significant bit position definitions */58#define TS1_T0_POS		1659#define TS1_HITTHD_POS		1660#define TS1_LITTHD_POS		061#define HSREF_CLK_DIV_POS	2462 63/* DTS_CFGR1 bit definitions */64#define TS1_EN			BIT(0)65#define TS1_START		BIT(4)66#define REFCLK_SEL		BIT(20)67#define REFCLK_LSE		REFCLK_SEL68#define Q_MEAS_OPT		BIT(21)69#define CALIBRATION_CONTROL	Q_MEAS_OPT70 71/* DTS_SR bit definitions */72#define TS_RDY			BIT(15)73/* Bit definitions below are common for DTS_SR, DTS_ITENR and DTS_CIFR */74#define HIGH_THRESHOLD		BIT(2)75#define LOW_THRESHOLD		BIT(1)76 77/* Constants */78#define ADJUST			10079#define ONE_MHZ			100000080#define POLL_TIMEOUT		500081#define STARTUP_TIME		4082#define TS1_T0_VAL0		30000  /* 30 celsius */83#define TS1_T0_VAL1		130000 /* 130 celsius */84#define NO_HW_TRIG		085#define SAMPLING_TIME		1586 87struct stm_thermal_sensor {88	struct device *dev;89	struct thermal_zone_device *th_dev;90	enum thermal_device_mode mode;91	struct clk *clk;92	unsigned int low_temp_enabled;93	unsigned int high_temp_enabled;94	int irq;95	void __iomem *base;96	int t0, fmt0, ramp_coeff;97};98 99static int stm_enable_irq(struct stm_thermal_sensor *sensor)100{101	u32 value;102 103	dev_dbg(sensor->dev, "low:%d high:%d\n", sensor->low_temp_enabled,104		sensor->high_temp_enabled);105 106	/* Disable IT generation for low and high thresholds */107	value = readl_relaxed(sensor->base + DTS_ITENR_OFFSET);108	value &= ~(LOW_THRESHOLD | HIGH_THRESHOLD);109 110	if (sensor->low_temp_enabled)111		value |= HIGH_THRESHOLD;112 113	if (sensor->high_temp_enabled)114		value |= LOW_THRESHOLD;115 116	/* Enable interrupts */117	writel_relaxed(value, sensor->base + DTS_ITENR_OFFSET);118 119	return 0;120}121 122static irqreturn_t stm_thermal_irq_handler(int irq, void *sdata)123{124	struct stm_thermal_sensor *sensor = sdata;125 126	dev_dbg(sensor->dev, "sr:%d\n",127		readl_relaxed(sensor->base + DTS_SR_OFFSET));128 129	thermal_zone_device_update(sensor->th_dev, THERMAL_EVENT_UNSPECIFIED);130 131	stm_enable_irq(sensor);132 133	/* Acknoledge all DTS irqs */134	writel_relaxed(ICIFR_MASK, sensor->base + DTS_ICIFR_OFFSET);135 136	return IRQ_HANDLED;137}138 139static int stm_sensor_power_on(struct stm_thermal_sensor *sensor)140{141	int ret;142	u32 value;143 144	/* Enable sensor */145	value = readl_relaxed(sensor->base + DTS_CFGR1_OFFSET);146	value |= TS1_EN;147	writel_relaxed(value, sensor->base + DTS_CFGR1_OFFSET);148 149	/*150	 * The DTS block can be enabled by setting TSx_EN bit in151	 * DTS_CFGRx register. It requires a startup time of152	 * 40μs. Use 5 ms as arbitrary timeout.153	 */154	ret = readl_poll_timeout(sensor->base + DTS_SR_OFFSET,155				 value, (value & TS_RDY),156				 STARTUP_TIME, POLL_TIMEOUT);157	if (ret)158		return ret;159 160	/* Start continuous measuring */161	value = readl_relaxed(sensor->base +162			      DTS_CFGR1_OFFSET);163	value |= TS1_START;164	writel_relaxed(value, sensor->base +165		       DTS_CFGR1_OFFSET);166 167	sensor->mode = THERMAL_DEVICE_ENABLED;168 169	return 0;170}171 172static int stm_sensor_power_off(struct stm_thermal_sensor *sensor)173{174	u32 value;175 176	sensor->mode = THERMAL_DEVICE_DISABLED;177 178	/* Stop measuring */179	value = readl_relaxed(sensor->base + DTS_CFGR1_OFFSET);180	value &= ~TS1_START;181	writel_relaxed(value, sensor->base + DTS_CFGR1_OFFSET);182 183	/* Ensure stop is taken into account */184	usleep_range(STARTUP_TIME, POLL_TIMEOUT);185 186	/* Disable sensor */187	value = readl_relaxed(sensor->base + DTS_CFGR1_OFFSET);188	value &= ~TS1_EN;189	writel_relaxed(value, sensor->base + DTS_CFGR1_OFFSET);190 191	/* Ensure disable is taken into account */192	return readl_poll_timeout(sensor->base + DTS_SR_OFFSET, value,193				  !(value & TS_RDY),194				  STARTUP_TIME, POLL_TIMEOUT);195}196 197static int stm_thermal_calibration(struct stm_thermal_sensor *sensor)198{199	u32 value, clk_freq;200	u32 prescaler;201 202	/* Figure out prescaler value for PCLK during calibration */203	clk_freq = clk_get_rate(sensor->clk);204	if (!clk_freq)205		return -EINVAL;206 207	prescaler = 0;208	clk_freq /= ONE_MHZ;209	if (clk_freq) {210		while (prescaler <= clk_freq)211			prescaler++;212	}213 214	value = readl_relaxed(sensor->base + DTS_CFGR1_OFFSET);215 216	/* Clear prescaler */217	value &= ~HSREF_CLK_DIV_MASK;218 219	/* Set prescaler. pclk_freq/prescaler < 1MHz */220	value |= (prescaler << HSREF_CLK_DIV_POS);221 222	/* Select PCLK as reference clock */223	value &= ~REFCLK_SEL;224 225	/* Set maximal sampling time for better precision */226	value |= TS1_SMP_TIME_MASK;227 228	/* Measure with calibration */229	value &= ~CALIBRATION_CONTROL;230 231	/* select trigger */232	value &= ~TS1_INTRIG_SEL_MASK;233	value |= NO_HW_TRIG;234 235	writel_relaxed(value, sensor->base + DTS_CFGR1_OFFSET);236 237	return 0;238}239 240/* Fill in DTS structure with factory sensor values */241static int stm_thermal_read_factory_settings(struct stm_thermal_sensor *sensor)242{243	/* Retrieve engineering calibration temperature */244	sensor->t0 = readl_relaxed(sensor->base + DTS_T0VALR1_OFFSET) &245					TS1_T0_MASK;246	if (!sensor->t0)247		sensor->t0 = TS1_T0_VAL0;248	else249		sensor->t0 = TS1_T0_VAL1;250 251	/* Retrieve fmt0 and put it on Hz */252	sensor->fmt0 = ADJUST * (readl_relaxed(sensor->base +253				 DTS_T0VALR1_OFFSET) & TS1_FMT0_MASK);254 255	/* Retrieve ramp coefficient */256	sensor->ramp_coeff = readl_relaxed(sensor->base + DTS_RAMPVALR_OFFSET) &257					   TS1_RAMP_COEFF_MASK;258 259	if (!sensor->fmt0 || !sensor->ramp_coeff) {260		dev_err(sensor->dev, "%s: wrong setting\n", __func__);261		return -EINVAL;262	}263 264	dev_dbg(sensor->dev, "%s: T0 = %doC, FMT0 = %dHz, RAMP_COEFF = %dHz/oC",265		__func__, sensor->t0, sensor->fmt0, sensor->ramp_coeff);266 267	return 0;268}269 270static int stm_thermal_calculate_threshold(struct stm_thermal_sensor *sensor,271					   int temp, u32 *th)272{273	int freqM;274 275	/* Figure out the CLK_PTAT frequency for a given temperature */276	freqM = ((temp - sensor->t0) * sensor->ramp_coeff) / 1000 +277		sensor->fmt0;278 279	/* Figure out the threshold sample number */280	*th = clk_get_rate(sensor->clk) * SAMPLING_TIME / freqM;281	if (!*th)282		return -EINVAL;283 284	dev_dbg(sensor->dev, "freqM=%d Hz, threshold=0x%x", freqM, *th);285 286	return 0;287}288 289/* Disable temperature interrupt */290static int stm_disable_irq(struct stm_thermal_sensor *sensor)291{292	u32 value;293 294	/* Disable IT generation */295	value = readl_relaxed(sensor->base + DTS_ITENR_OFFSET);296	value &= ~ITENR_MASK;297	writel_relaxed(value, sensor->base + DTS_ITENR_OFFSET);298 299	return 0;300}301 302static int stm_thermal_set_trips(struct thermal_zone_device *tz, int low, int high)303{304	struct stm_thermal_sensor *sensor = thermal_zone_device_priv(tz);305	u32 itr1, th;306	int ret;307 308	dev_dbg(sensor->dev, "set trips %d <--> %d\n", low, high);309 310	/* Erase threshold content */311	itr1 = readl_relaxed(sensor->base + DTS_ITR1_OFFSET);312	itr1 &= ~(TS1_LITTHD_MASK | TS1_HITTHD_MASK);313 314	/*315	 * Disable low-temp if "low" is too small. As per thermal framework316	 * API, we use -INT_MAX rather than INT_MIN.317	 */318 319	if (low > -INT_MAX) {320		sensor->low_temp_enabled = 1;321		/* add 0.5 of hysteresis due to measurement error */322		ret = stm_thermal_calculate_threshold(sensor, low - 500, &th);323		if (ret)324			return ret;325 326		itr1 |= (TS1_HITTHD_MASK  & (th << TS1_HITTHD_POS));327	} else {328		sensor->low_temp_enabled = 0;329	}330 331	/* Disable high-temp if "high" is too big. */332	if (high < INT_MAX) {333		sensor->high_temp_enabled = 1;334		ret = stm_thermal_calculate_threshold(sensor, high, &th);335		if (ret)336			return ret;337 338		itr1 |= (TS1_LITTHD_MASK  & (th << TS1_LITTHD_POS));339	} else {340		sensor->high_temp_enabled = 0;341	}342 343	/* Write new threshod values*/344	writel_relaxed(itr1, sensor->base + DTS_ITR1_OFFSET);345 346	return 0;347}348 349/* Callback to get temperature from HW */350static int stm_thermal_get_temp(struct thermal_zone_device *tz, int *temp)351{352	struct stm_thermal_sensor *sensor = thermal_zone_device_priv(tz);353	u32 periods;354	int freqM, ret;355 356	if (sensor->mode != THERMAL_DEVICE_ENABLED)357		return -EAGAIN;358 359	/* Retrieve the number of periods sampled */360	ret = readl_relaxed_poll_timeout(sensor->base + DTS_DR_OFFSET, periods,361					 (periods & TS1_MFREQ_MASK),362					 STARTUP_TIME, POLL_TIMEOUT);363	if (ret)364		return ret;365 366	/* Figure out the CLK_PTAT frequency */367	freqM = (clk_get_rate(sensor->clk) * SAMPLING_TIME) / periods;368	if (!freqM)369		return -EINVAL;370 371	/* Figure out the temperature in mili celsius */372	*temp = (freqM - sensor->fmt0) * 1000 / sensor->ramp_coeff + sensor->t0;373 374	return 0;375}376 377/* Registers DTS irq to be visible by GIC */378static int stm_register_irq(struct stm_thermal_sensor *sensor)379{380	struct device *dev = sensor->dev;381	struct platform_device *pdev = to_platform_device(dev);382	int ret;383 384	sensor->irq = platform_get_irq(pdev, 0);385	if (sensor->irq < 0)386		return sensor->irq;387 388	ret = devm_request_threaded_irq(dev, sensor->irq,389					NULL,390					stm_thermal_irq_handler,391					IRQF_ONESHOT,392					dev->driver->name, sensor);393	if (ret) {394		dev_err(dev, "%s: Failed to register IRQ %d\n", __func__,395			sensor->irq);396		return ret;397	}398 399	dev_dbg(dev, "%s: thermal IRQ registered", __func__);400 401	return 0;402}403 404static int stm_thermal_sensor_off(struct stm_thermal_sensor *sensor)405{406	int ret;407 408	stm_disable_irq(sensor);409 410	ret = stm_sensor_power_off(sensor);411	if (ret)412		return ret;413 414	clk_disable_unprepare(sensor->clk);415 416	return 0;417}418 419static int stm_thermal_prepare(struct stm_thermal_sensor *sensor)420{421	int ret;422 423	ret = clk_prepare_enable(sensor->clk);424	if (ret)425		return ret;426 427	ret = stm_thermal_read_factory_settings(sensor);428	if (ret)429		goto thermal_unprepare;430 431	ret = stm_thermal_calibration(sensor);432	if (ret)433		goto thermal_unprepare;434 435	return 0;436 437thermal_unprepare:438	clk_disable_unprepare(sensor->clk);439 440	return ret;441}442 443static int stm_thermal_suspend(struct device *dev)444{445	struct stm_thermal_sensor *sensor = dev_get_drvdata(dev);446 447	return stm_thermal_sensor_off(sensor);448}449 450static int stm_thermal_resume(struct device *dev)451{452	int ret;453	struct stm_thermal_sensor *sensor = dev_get_drvdata(dev);454 455	ret = stm_thermal_prepare(sensor);456	if (ret)457		return ret;458 459	ret = stm_sensor_power_on(sensor);460	if (ret)461		return ret;462 463	thermal_zone_device_update(sensor->th_dev, THERMAL_EVENT_UNSPECIFIED);464	stm_enable_irq(sensor);465 466	return 0;467}468 469static DEFINE_SIMPLE_DEV_PM_OPS(stm_thermal_pm_ops,470				stm_thermal_suspend, stm_thermal_resume);471 472static const struct thermal_zone_device_ops stm_tz_ops = {473	.get_temp	= stm_thermal_get_temp,474	.set_trips	= stm_thermal_set_trips,475};476 477static const struct of_device_id stm_thermal_of_match[] = {478		{ .compatible = "st,stm32-thermal"},479	{ /* sentinel */ }480};481MODULE_DEVICE_TABLE(of, stm_thermal_of_match);482 483static int stm_thermal_probe(struct platform_device *pdev)484{485	struct stm_thermal_sensor *sensor;486	void __iomem *base;487	int ret;488 489	if (!pdev->dev.of_node) {490		dev_err(&pdev->dev, "%s: device tree node not found\n",491			__func__);492		return -EINVAL;493	}494 495	sensor = devm_kzalloc(&pdev->dev, sizeof(*sensor), GFP_KERNEL);496	if (!sensor)497		return -ENOMEM;498 499	platform_set_drvdata(pdev, sensor);500 501	sensor->dev = &pdev->dev;502 503	base = devm_platform_get_and_ioremap_resource(pdev, 0, NULL);504	if (IS_ERR(base))505		return PTR_ERR(base);506 507	/* Populate sensor */508	sensor->base = base;509 510	sensor->clk = devm_clk_get(&pdev->dev, "pclk");511	if (IS_ERR(sensor->clk)) {512		dev_err(&pdev->dev, "%s: failed to fetch PCLK clock\n",513			__func__);514		return PTR_ERR(sensor->clk);515	}516 517	stm_disable_irq(sensor);518 519	/* Clear irq flags */520	writel_relaxed(ICIFR_MASK, sensor->base + DTS_ICIFR_OFFSET);521 522	/* Configure and enable HW sensor */523	ret = stm_thermal_prepare(sensor);524	if (ret) {525		dev_err(&pdev->dev, "Error prepare sensor: %d\n", ret);526		return ret;527	}528 529	ret = stm_sensor_power_on(sensor);530	if (ret) {531		dev_err(&pdev->dev, "Error power on sensor: %d\n", ret);532		return ret;533	}534 535	sensor->th_dev = devm_thermal_of_zone_register(&pdev->dev, 0,536						       sensor,537						       &stm_tz_ops);538 539	if (IS_ERR(sensor->th_dev)) {540		dev_err(&pdev->dev, "%s: thermal zone sensor registering KO\n",541			__func__);542		ret = PTR_ERR(sensor->th_dev);543		return ret;544	}545 546	/* Register IRQ into GIC */547	ret = stm_register_irq(sensor);548	if (ret)549		goto err_tz;550 551	stm_enable_irq(sensor);552 553	/*554	 * Thermal_zone doesn't enable hwmon as default,555	 * enable it here556	 */557	ret = thermal_add_hwmon_sysfs(sensor->th_dev);558	if (ret)559		goto err_tz;560 561	dev_info(&pdev->dev, "%s: Driver initialized successfully\n",562		 __func__);563 564	return 0;565 566err_tz:567	return ret;568}569 570static void stm_thermal_remove(struct platform_device *pdev)571{572	struct stm_thermal_sensor *sensor = platform_get_drvdata(pdev);573 574	stm_thermal_sensor_off(sensor);575	thermal_remove_hwmon_sysfs(sensor->th_dev);576}577 578static struct platform_driver stm_thermal_driver = {579	.driver = {580		.name	= "stm_thermal",581		.pm     = pm_sleep_ptr(&stm_thermal_pm_ops),582		.of_match_table = stm_thermal_of_match,583	},584	.probe		= stm_thermal_probe,585	.remove_new	= stm_thermal_remove,586};587module_platform_driver(stm_thermal_driver);588 589MODULE_DESCRIPTION("STMicroelectronics STM32 Thermal Sensor Driver");590MODULE_AUTHOR("David Hernandez Sanchez <david.hernandezsanchez@st.com>");591MODULE_LICENSE("GPL v2");592MODULE_ALIAS("platform:stm_thermal");593