Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-or-later
0002 /*
0003  * ST Thermal Sensor Driver for memory mapped sensors.
0004  * Author: Ajit Pal Singh <ajitpal.singh@st.com>
0005  *
0006  * Copyright (C) 2003-2014 STMicroelectronics (R&D) Limited
0007  */
0008 
0009 #include <linux/of.h>
0010 #include <linux/module.h>
0011 
0012 #include "st_thermal.h"
0013 
0014 #define STIH416_MPE_CONF            0x0
0015 #define STIH416_MPE_STATUS          0x4
0016 #define STIH416_MPE_INT_THRESH          0x8
0017 #define STIH416_MPE_INT_EN          0xC
0018 
0019 /* Power control bits for the memory mapped thermal sensor */
0020 #define THERMAL_PDN             BIT(4)
0021 #define THERMAL_SRSTN               BIT(10)
0022 
0023 static const struct reg_field st_mmap_thermal_regfields[MAX_REGFIELDS] = {
0024     /*
0025      * According to the STIH416 MPE temp sensor data sheet -
0026      * the PDN (Power Down Bit) and SRSTN (Soft Reset Bit) need to be
0027      * written simultaneously for powering on and off the temperature
0028      * sensor. regmap_update_bits() will be used to update the register.
0029      */
0030     [INT_THRESH_HI] = REG_FIELD(STIH416_MPE_INT_THRESH,     0,  7),
0031     [DCORRECT]  = REG_FIELD(STIH416_MPE_CONF,       5,  9),
0032     [OVERFLOW]  = REG_FIELD(STIH416_MPE_STATUS,     9,  9),
0033     [DATA]      = REG_FIELD(STIH416_MPE_STATUS,     11, 18),
0034     [INT_ENABLE]    = REG_FIELD(STIH416_MPE_INT_EN,     0,  0),
0035 };
0036 
0037 static irqreturn_t st_mmap_thermal_trip_handler(int irq, void *sdata)
0038 {
0039     struct st_thermal_sensor *sensor = sdata;
0040 
0041     thermal_zone_device_update(sensor->thermal_dev,
0042                    THERMAL_EVENT_UNSPECIFIED);
0043 
0044     return IRQ_HANDLED;
0045 }
0046 
0047 /* Private ops for the Memory Mapped based thermal sensors */
0048 static int st_mmap_power_ctrl(struct st_thermal_sensor *sensor,
0049                   enum st_thermal_power_state power_state)
0050 {
0051     const unsigned int mask = (THERMAL_PDN | THERMAL_SRSTN);
0052     const unsigned int val = power_state ? mask : 0;
0053 
0054     return regmap_update_bits(sensor->regmap, STIH416_MPE_CONF, mask, val);
0055 }
0056 
0057 static int st_mmap_alloc_regfields(struct st_thermal_sensor *sensor)
0058 {
0059     struct device *dev = sensor->dev;
0060     struct regmap *regmap = sensor->regmap;
0061     const struct reg_field *reg_fields = sensor->cdata->reg_fields;
0062 
0063     sensor->int_thresh_hi = devm_regmap_field_alloc(dev, regmap,
0064                         reg_fields[INT_THRESH_HI]);
0065     sensor->int_enable = devm_regmap_field_alloc(dev, regmap,
0066                         reg_fields[INT_ENABLE]);
0067 
0068     if (IS_ERR(sensor->int_thresh_hi) || IS_ERR(sensor->int_enable)) {
0069         dev_err(dev, "failed to alloc mmap regfields\n");
0070         return -EINVAL;
0071     }
0072 
0073     return 0;
0074 }
0075 
0076 static int st_mmap_enable_irq(struct st_thermal_sensor *sensor)
0077 {
0078     int ret;
0079 
0080     /* Set upper critical threshold */
0081     ret = regmap_field_write(sensor->int_thresh_hi,
0082                  sensor->cdata->crit_temp -
0083                  sensor->cdata->temp_adjust_val);
0084     if (ret)
0085         return ret;
0086 
0087     return regmap_field_write(sensor->int_enable, 1);
0088 }
0089 
0090 static int st_mmap_register_enable_irq(struct st_thermal_sensor *sensor)
0091 {
0092     struct device *dev = sensor->dev;
0093     struct platform_device *pdev = to_platform_device(dev);
0094     int ret;
0095 
0096     sensor->irq = platform_get_irq(pdev, 0);
0097     if (sensor->irq < 0)
0098         return sensor->irq;
0099 
0100     ret = devm_request_threaded_irq(dev, sensor->irq,
0101                     NULL, st_mmap_thermal_trip_handler,
0102                     IRQF_TRIGGER_RISING | IRQF_ONESHOT,
0103                     dev->driver->name, sensor);
0104     if (ret) {
0105         dev_err(dev, "failed to register IRQ %d\n", sensor->irq);
0106         return ret;
0107     }
0108 
0109     return st_mmap_enable_irq(sensor);
0110 }
0111 
0112 static const struct regmap_config st_416mpe_regmap_config = {
0113     .reg_bits = 32,
0114     .val_bits = 32,
0115     .reg_stride = 4,
0116 };
0117 
0118 static int st_mmap_regmap_init(struct st_thermal_sensor *sensor)
0119 {
0120     struct device *dev = sensor->dev;
0121     struct platform_device *pdev = to_platform_device(dev);
0122 
0123     sensor->mmio_base = devm_platform_get_and_ioremap_resource(pdev, 0, NULL);
0124     if (IS_ERR(sensor->mmio_base))
0125         return PTR_ERR(sensor->mmio_base);
0126 
0127     sensor->regmap = devm_regmap_init_mmio(dev, sensor->mmio_base,
0128                 &st_416mpe_regmap_config);
0129     if (IS_ERR(sensor->regmap)) {
0130         dev_err(dev, "failed to initialise regmap\n");
0131         return PTR_ERR(sensor->regmap);
0132     }
0133 
0134     return 0;
0135 }
0136 
0137 static const struct st_thermal_sensor_ops st_mmap_sensor_ops = {
0138     .power_ctrl     = st_mmap_power_ctrl,
0139     .alloc_regfields    = st_mmap_alloc_regfields,
0140     .regmap_init        = st_mmap_regmap_init,
0141     .register_enable_irq    = st_mmap_register_enable_irq,
0142     .enable_irq     = st_mmap_enable_irq,
0143 };
0144 
0145 /* Compatible device data stih416 mpe thermal sensor */
0146 static const struct st_thermal_compat_data st_416mpe_cdata = {
0147     .reg_fields     = st_mmap_thermal_regfields,
0148     .ops            = &st_mmap_sensor_ops,
0149     .calibration_val    = 14,
0150     .temp_adjust_val    = -95,
0151     .crit_temp      = 120,
0152 };
0153 
0154 /* Compatible device data stih407 thermal sensor */
0155 static const struct st_thermal_compat_data st_407_cdata = {
0156     .reg_fields     = st_mmap_thermal_regfields,
0157     .ops            = &st_mmap_sensor_ops,
0158     .calibration_val    = 16,
0159     .temp_adjust_val    = -95,
0160     .crit_temp      = 120,
0161 };
0162 
0163 static const struct of_device_id st_mmap_thermal_of_match[] = {
0164     { .compatible = "st,stih416-mpe-thermal", .data = &st_416mpe_cdata },
0165     { .compatible = "st,stih407-thermal",     .data = &st_407_cdata },
0166     { /* sentinel */ }
0167 };
0168 MODULE_DEVICE_TABLE(of, st_mmap_thermal_of_match);
0169 
0170 static int st_mmap_probe(struct platform_device *pdev)
0171 {
0172     return st_thermal_register(pdev,  st_mmap_thermal_of_match);
0173 }
0174 
0175 static int st_mmap_remove(struct platform_device *pdev)
0176 {
0177     return st_thermal_unregister(pdev);
0178 }
0179 
0180 static struct platform_driver st_mmap_thermal_driver = {
0181     .driver = {
0182         .name   = "st_thermal_mmap",
0183         .pm     = &st_thermal_pm_ops,
0184         .of_match_table = st_mmap_thermal_of_match,
0185     },
0186     .probe      = st_mmap_probe,
0187     .remove     = st_mmap_remove,
0188 };
0189 
0190 module_platform_driver(st_mmap_thermal_driver);
0191 
0192 MODULE_AUTHOR("STMicroelectronics (R&D) Limited <ajitpal.singh@st.com>");
0193 MODULE_DESCRIPTION("STMicroelectronics STi SoC Thermal Sensor Driver");
0194 MODULE_LICENSE("GPL v2");