xref: /openbmc/linux/drivers/thermal/st/st_thermal_memmap.c (revision 2612e3bbc0386368a850140a6c9b990cd496a5ec)
12874c5fdSThomas Gleixner // SPDX-License-Identifier: GPL-2.0-or-later
26ea95b50SLee Jones /*
36ea95b50SLee Jones  * ST Thermal Sensor Driver for memory mapped sensors.
46ea95b50SLee Jones  * Author: Ajit Pal Singh <ajitpal.singh@st.com>
56ea95b50SLee Jones  *
66ea95b50SLee Jones  * Copyright (C) 2003-2014 STMicroelectronics (R&D) Limited
76ea95b50SLee Jones  */
86ea95b50SLee Jones 
96ea95b50SLee Jones #include <linux/of.h>
106ea95b50SLee Jones #include <linux/module.h>
116ea95b50SLee Jones 
126ea95b50SLee Jones #include "st_thermal.h"
136ea95b50SLee Jones 
146ea95b50SLee Jones #define STIH416_MPE_CONF			0x0
156ea95b50SLee Jones #define STIH416_MPE_STATUS			0x4
166ea95b50SLee Jones #define STIH416_MPE_INT_THRESH			0x8
176ea95b50SLee Jones #define STIH416_MPE_INT_EN			0xC
186ea95b50SLee Jones 
196ea95b50SLee Jones /* Power control bits for the memory mapped thermal sensor */
206ea95b50SLee Jones #define THERMAL_PDN				BIT(4)
216ea95b50SLee Jones #define THERMAL_SRSTN				BIT(10)
226ea95b50SLee Jones 
236ea95b50SLee Jones static const struct reg_field st_mmap_thermal_regfields[MAX_REGFIELDS] = {
246ea95b50SLee Jones 	/*
256ea95b50SLee Jones 	 * According to the STIH416 MPE temp sensor data sheet -
266ea95b50SLee Jones 	 * the PDN (Power Down Bit) and SRSTN (Soft Reset Bit) need to be
276ea95b50SLee Jones 	 * written simultaneously for powering on and off the temperature
286ea95b50SLee Jones 	 * sensor. regmap_update_bits() will be used to update the register.
296ea95b50SLee Jones 	 */
306ea95b50SLee Jones 	[INT_THRESH_HI]	= REG_FIELD(STIH416_MPE_INT_THRESH, 	0,  7),
316ea95b50SLee Jones 	[DCORRECT]	= REG_FIELD(STIH416_MPE_CONF,		5,  9),
326ea95b50SLee Jones 	[OVERFLOW]	= REG_FIELD(STIH416_MPE_STATUS,		9,  9),
336ea95b50SLee Jones 	[DATA]		= REG_FIELD(STIH416_MPE_STATUS,		11, 18),
346ea95b50SLee Jones 	[INT_ENABLE]	= REG_FIELD(STIH416_MPE_INT_EN,		0,  0),
356ea95b50SLee Jones };
366ea95b50SLee Jones 
st_mmap_thermal_trip_handler(int irq,void * sdata)376ea95b50SLee Jones static irqreturn_t st_mmap_thermal_trip_handler(int irq, void *sdata)
386ea95b50SLee Jones {
396ea95b50SLee Jones 	struct st_thermal_sensor *sensor = sdata;
406ea95b50SLee Jones 
410e70f466SSrinivas Pandruvada 	thermal_zone_device_update(sensor->thermal_dev,
420e70f466SSrinivas Pandruvada 				   THERMAL_EVENT_UNSPECIFIED);
436ea95b50SLee Jones 
446ea95b50SLee Jones 	return IRQ_HANDLED;
456ea95b50SLee Jones }
466ea95b50SLee Jones 
476ea95b50SLee Jones /* Private ops for the Memory Mapped based thermal sensors */
st_mmap_power_ctrl(struct st_thermal_sensor * sensor,enum st_thermal_power_state power_state)486ea95b50SLee Jones static int st_mmap_power_ctrl(struct st_thermal_sensor *sensor,
496ea95b50SLee Jones 			      enum st_thermal_power_state power_state)
506ea95b50SLee Jones {
516ea95b50SLee Jones 	const unsigned int mask = (THERMAL_PDN | THERMAL_SRSTN);
526ea95b50SLee Jones 	const unsigned int val = power_state ? mask : 0;
536ea95b50SLee Jones 
546ea95b50SLee Jones 	return regmap_update_bits(sensor->regmap, STIH416_MPE_CONF, mask, val);
556ea95b50SLee Jones }
566ea95b50SLee Jones 
st_mmap_alloc_regfields(struct st_thermal_sensor * sensor)576ea95b50SLee Jones static int st_mmap_alloc_regfields(struct st_thermal_sensor *sensor)
586ea95b50SLee Jones {
596ea95b50SLee Jones 	struct device *dev = sensor->dev;
606ea95b50SLee Jones 	struct regmap *regmap = sensor->regmap;
616ea95b50SLee Jones 	const struct reg_field *reg_fields = sensor->cdata->reg_fields;
626ea95b50SLee Jones 
636ea95b50SLee Jones 	sensor->int_thresh_hi = devm_regmap_field_alloc(dev, regmap,
646ea95b50SLee Jones 						reg_fields[INT_THRESH_HI]);
656ea95b50SLee Jones 	sensor->int_enable = devm_regmap_field_alloc(dev, regmap,
666ea95b50SLee Jones 						reg_fields[INT_ENABLE]);
676ea95b50SLee Jones 
686ea95b50SLee Jones 	if (IS_ERR(sensor->int_thresh_hi) || IS_ERR(sensor->int_enable)) {
696ea95b50SLee Jones 		dev_err(dev, "failed to alloc mmap regfields\n");
706ea95b50SLee Jones 		return -EINVAL;
716ea95b50SLee Jones 	}
726ea95b50SLee Jones 
736ea95b50SLee Jones 	return 0;
746ea95b50SLee Jones }
756ea95b50SLee Jones 
st_mmap_enable_irq(struct st_thermal_sensor * sensor)766ea95b50SLee Jones static int st_mmap_enable_irq(struct st_thermal_sensor *sensor)
776ea95b50SLee Jones {
786ea95b50SLee Jones 	int ret;
796ea95b50SLee Jones 
806ea95b50SLee Jones 	/* Set upper critical threshold */
816ea95b50SLee Jones 	ret = regmap_field_write(sensor->int_thresh_hi,
826ea95b50SLee Jones 				 sensor->cdata->crit_temp -
836ea95b50SLee Jones 				 sensor->cdata->temp_adjust_val);
846ea95b50SLee Jones 	if (ret)
856ea95b50SLee Jones 		return ret;
866ea95b50SLee Jones 
876ea95b50SLee Jones 	return regmap_field_write(sensor->int_enable, 1);
886ea95b50SLee Jones }
896ea95b50SLee Jones 
st_mmap_register_enable_irq(struct st_thermal_sensor * sensor)906ea95b50SLee Jones static int st_mmap_register_enable_irq(struct st_thermal_sensor *sensor)
916ea95b50SLee Jones {
926ea95b50SLee Jones 	struct device *dev = sensor->dev;
936ea95b50SLee Jones 	struct platform_device *pdev = to_platform_device(dev);
946ea95b50SLee Jones 	int ret;
956ea95b50SLee Jones 
966ea95b50SLee Jones 	sensor->irq = platform_get_irq(pdev, 0);
978cb775bbSMarkus Elfring 	if (sensor->irq < 0)
986ea95b50SLee Jones 		return sensor->irq;
996ea95b50SLee Jones 
1006ea95b50SLee Jones 	ret = devm_request_threaded_irq(dev, sensor->irq,
1016ea95b50SLee Jones 					NULL, st_mmap_thermal_trip_handler,
1026ea95b50SLee Jones 					IRQF_TRIGGER_RISING | IRQF_ONESHOT,
1036ea95b50SLee Jones 					dev->driver->name, sensor);
1046ea95b50SLee Jones 	if (ret) {
1056ea95b50SLee Jones 		dev_err(dev, "failed to register IRQ %d\n", sensor->irq);
1066ea95b50SLee Jones 		return ret;
1076ea95b50SLee Jones 	}
1086ea95b50SLee Jones 
1096ea95b50SLee Jones 	return st_mmap_enable_irq(sensor);
1106ea95b50SLee Jones }
1116ea95b50SLee Jones 
1126ea95b50SLee Jones static const struct regmap_config st_416mpe_regmap_config = {
1136ea95b50SLee Jones 	.reg_bits = 32,
1146ea95b50SLee Jones 	.val_bits = 32,
1156ea95b50SLee Jones 	.reg_stride = 4,
1166ea95b50SLee Jones };
1176ea95b50SLee Jones 
st_mmap_regmap_init(struct st_thermal_sensor * sensor)1186ea95b50SLee Jones static int st_mmap_regmap_init(struct st_thermal_sensor *sensor)
1196ea95b50SLee Jones {
1206ea95b50SLee Jones 	struct device *dev = sensor->dev;
1216ea95b50SLee Jones 	struct platform_device *pdev = to_platform_device(dev);
1226ea95b50SLee Jones 
123d7539260SYang Yingliang 	sensor->mmio_base = devm_platform_get_and_ioremap_resource(pdev, 0, NULL);
124d7539260SYang Yingliang 	if (IS_ERR(sensor->mmio_base))
1256ea95b50SLee Jones 		return PTR_ERR(sensor->mmio_base);
1266ea95b50SLee Jones 
1276ea95b50SLee Jones 	sensor->regmap = devm_regmap_init_mmio(dev, sensor->mmio_base,
1286ea95b50SLee Jones 				&st_416mpe_regmap_config);
1296ea95b50SLee Jones 	if (IS_ERR(sensor->regmap)) {
1306ea95b50SLee Jones 		dev_err(dev, "failed to initialise regmap\n");
1316ea95b50SLee Jones 		return PTR_ERR(sensor->regmap);
1326ea95b50SLee Jones 	}
1336ea95b50SLee Jones 
1346ea95b50SLee Jones 	return 0;
1356ea95b50SLee Jones }
1366ea95b50SLee Jones 
1376ea95b50SLee Jones static const struct st_thermal_sensor_ops st_mmap_sensor_ops = {
1386ea95b50SLee Jones 	.power_ctrl		= st_mmap_power_ctrl,
1396ea95b50SLee Jones 	.alloc_regfields	= st_mmap_alloc_regfields,
1406ea95b50SLee Jones 	.regmap_init		= st_mmap_regmap_init,
1416ea95b50SLee Jones 	.register_enable_irq	= st_mmap_register_enable_irq,
1426ea95b50SLee Jones 	.enable_irq		= st_mmap_enable_irq,
1436ea95b50SLee Jones };
1446ea95b50SLee Jones 
1456ea95b50SLee Jones /* Compatible device data stih416 mpe thermal sensor */
146541d529fSEduardo Valentin static const struct st_thermal_compat_data st_416mpe_cdata = {
1476ea95b50SLee Jones 	.reg_fields		= st_mmap_thermal_regfields,
1486ea95b50SLee Jones 	.ops			= &st_mmap_sensor_ops,
1496ea95b50SLee Jones 	.calibration_val	= 14,
1506ea95b50SLee Jones 	.temp_adjust_val	= -95,
1516ea95b50SLee Jones 	.crit_temp		= 120,
1526ea95b50SLee Jones };
1536ea95b50SLee Jones 
1546ea95b50SLee Jones /* Compatible device data stih407 thermal sensor */
155541d529fSEduardo Valentin static const struct st_thermal_compat_data st_407_cdata = {
1566ea95b50SLee Jones 	.reg_fields		= st_mmap_thermal_regfields,
1576ea95b50SLee Jones 	.ops			= &st_mmap_sensor_ops,
1586ea95b50SLee Jones 	.calibration_val	= 16,
1596ea95b50SLee Jones 	.temp_adjust_val	= -95,
1606ea95b50SLee Jones 	.crit_temp		= 120,
1616ea95b50SLee Jones };
1626ea95b50SLee Jones 
163d877a62bSFabian Frederick static const struct of_device_id st_mmap_thermal_of_match[] = {
1646ea95b50SLee Jones 	{ .compatible = "st,stih416-mpe-thermal", .data = &st_416mpe_cdata },
1656ea95b50SLee Jones 	{ .compatible = "st,stih407-thermal",     .data = &st_407_cdata },
1666ea95b50SLee Jones 	{ /* sentinel */ }
1676ea95b50SLee Jones };
1686ea95b50SLee Jones MODULE_DEVICE_TABLE(of, st_mmap_thermal_of_match);
1696ea95b50SLee Jones 
st_mmap_probe(struct platform_device * pdev)170541d529fSEduardo Valentin static int st_mmap_probe(struct platform_device *pdev)
1716ea95b50SLee Jones {
1726ea95b50SLee Jones 	return st_thermal_register(pdev,  st_mmap_thermal_of_match);
1736ea95b50SLee Jones }
1746ea95b50SLee Jones 
st_mmap_remove(struct platform_device * pdev)175*2ef95331SUwe Kleine-König static void st_mmap_remove(struct platform_device *pdev)
1766ea95b50SLee Jones {
177*2ef95331SUwe Kleine-König 	st_thermal_unregister(pdev);
1786ea95b50SLee Jones }
1796ea95b50SLee Jones 
1806ea95b50SLee Jones static struct platform_driver st_mmap_thermal_driver = {
1816ea95b50SLee Jones 	.driver = {
1826ea95b50SLee Jones 		.name	= "st_thermal_mmap",
1836ea95b50SLee Jones 		.pm     = &st_thermal_pm_ops,
1846ea95b50SLee Jones 		.of_match_table = st_mmap_thermal_of_match,
1856ea95b50SLee Jones 	},
1866ea95b50SLee Jones 	.probe		= st_mmap_probe,
187*2ef95331SUwe Kleine-König 	.remove_new	= st_mmap_remove,
1886ea95b50SLee Jones };
1896ea95b50SLee Jones 
1906ea95b50SLee Jones module_platform_driver(st_mmap_thermal_driver);
1916ea95b50SLee Jones 
1926ea95b50SLee Jones MODULE_AUTHOR("STMicroelectronics (R&D) Limited <ajitpal.singh@st.com>");
1936ea95b50SLee Jones MODULE_DESCRIPTION("STMicroelectronics STi SoC Thermal Sensor Driver");
1946ea95b50SLee Jones MODULE_LICENSE("GPL v2");
195