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