Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0
0002 /*
0003  * TI Bandgap temperature sensor driver for K3 SoC Family
0004  *
0005  * Copyright (C) 2020 Texas Instruments Incorporated - http://www.ti.com/
0006  */
0007 
0008 #include <linux/err.h>
0009 #include <linux/init.h>
0010 #include <linux/io.h>
0011 #include <linux/kernel.h>
0012 #include <linux/module.h>
0013 #include <linux/of.h>
0014 #include <linux/of_platform.h>
0015 #include <linux/pm_runtime.h>
0016 #include <linux/thermal.h>
0017 #include <linux/types.h>
0018 
0019 #include "thermal_hwmon.h"
0020 
0021 #define K3_VTM_DEVINFO_PWR0_OFFSET      0x4
0022 #define K3_VTM_DEVINFO_PWR0_TEMPSENS_CT_MASK    0xf0
0023 #define K3_VTM_TMPSENS0_CTRL_OFFSET 0x80
0024 #define K3_VTM_REGS_PER_TS          0x10
0025 #define K3_VTM_TS_STAT_DTEMP_MASK   0x3ff
0026 #define K3_VTM_TMPSENS_CTRL_CBIASSEL    BIT(0)
0027 #define K3_VTM_TMPSENS_CTRL_SOC     BIT(5)
0028 #define K3_VTM_TMPSENS_CTRL_CLRZ        BIT(6)
0029 #define K3_VTM_TMPSENS_CTRL_CLKON_REQ   BIT(7)
0030 
0031 #define K3_VTM_ADC_BEGIN_VAL        540
0032 #define K3_VTM_ADC_END_VAL      944
0033 
0034 static const int k3_adc_to_temp[] = {
0035     -40000, -40000, -40000, -40000, -39800, -39400, -39000, -38600, -38200,
0036     -37800, -37400, -37000, -36600, -36200, -35800, -35300, -34700, -34200,
0037     -33800, -33400, -33000, -32600, -32200, -31800, -31400, -31000, -30600,
0038     -30200, -29800, -29400, -29000, -28600, -28200, -27700, -27100, -26600,
0039     -26200, -25800, -25400, -25000, -24600, -24200, -23800, -23400, -23000,
0040     -22600, -22200, -21800, -21400, -21000, -20500, -19900, -19400, -19000,
0041     -18600, -18200, -17800, -17400, -17000, -16600, -16200, -15800, -15400,
0042     -15000, -14600, -14200, -13800, -13400, -13000, -12500, -11900, -11400,
0043     -11000, -10600, -10200, -9800, -9400, -9000, -8600, -8200, -7800, -7400,
0044     -7000, -6600, -6200, -5800, -5400, -5000, -4500, -3900, -3400, -3000,
0045     -2600, -2200, -1800, -1400, -1000, -600, -200, 200, 600, 1000, 1400,
0046     1800, 2200, 2600, 3000, 3400, 3900, 4500, 5000, 5400, 5800, 6200, 6600,
0047     7000, 7400, 7800, 8200, 8600, 9000, 9400, 9800, 10200, 10600, 11000,
0048     11400, 11800, 12200, 12700, 13300, 13800, 14200, 14600, 15000, 15400,
0049     15800, 16200, 16600, 17000, 17400, 17800, 18200, 18600, 19000, 19400,
0050     19800, 20200, 20600, 21000, 21400, 21900, 22500, 23000, 23400, 23800,
0051     24200, 24600, 25000, 25400, 25800, 26200, 26600, 27000, 27400, 27800,
0052     28200, 28600, 29000, 29400, 29800, 30200, 30600, 31000, 31400, 31900,
0053     32500, 33000, 33400, 33800, 34200, 34600, 35000, 35400, 35800, 36200,
0054     36600, 37000, 37400, 37800, 38200, 38600, 39000, 39400, 39800, 40200,
0055     40600, 41000, 41400, 41800, 42200, 42600, 43100, 43700, 44200, 44600,
0056     45000, 45400, 45800, 46200, 46600, 47000, 47400, 47800, 48200, 48600,
0057     49000, 49400, 49800, 50200, 50600, 51000, 51400, 51800, 52200, 52600,
0058     53000, 53400, 53800, 54200, 54600, 55000, 55400, 55900, 56500, 57000,
0059     57400, 57800, 58200, 58600, 59000, 59400, 59800, 60200, 60600, 61000,
0060     61400, 61800, 62200, 62600, 63000, 63400, 63800, 64200, 64600, 65000,
0061     65400, 65800, 66200, 66600, 67000, 67400, 67800, 68200, 68600, 69000,
0062     69400, 69800, 70200, 70600, 71000, 71500, 72100, 72600, 73000, 73400,
0063     73800, 74200, 74600, 75000, 75400, 75800, 76200, 76600, 77000, 77400,
0064     77800, 78200, 78600, 79000, 79400, 79800, 80200, 80600, 81000, 81400,
0065     81800, 82200, 82600, 83000, 83400, 83800, 84200, 84600, 85000, 85400,
0066     85800, 86200, 86600, 87000, 87400, 87800, 88200, 88600, 89000, 89400,
0067     89800, 90200, 90600, 91000, 91400, 91800, 92200, 92600, 93000, 93400,
0068     93800, 94200, 94600, 95000, 95400, 95800, 96200, 96600, 97000, 97500,
0069     98100, 98600, 99000, 99400, 99800, 100200, 100600, 101000, 101400,
0070     101800, 102200, 102600, 103000, 103400, 103800, 104200, 104600, 105000,
0071     105400, 105800, 106200, 106600, 107000, 107400, 107800, 108200, 108600,
0072     109000, 109400, 109800, 110200, 110600, 111000, 111400, 111800, 112200,
0073     112600, 113000, 113400, 113800, 114200, 114600, 115000, 115400, 115800,
0074     116200, 116600, 117000, 117400, 117800, 118200, 118600, 119000, 119400,
0075     119800, 120200, 120600, 121000, 121400, 121800, 122200, 122600, 123000,
0076     123400, 123800, 124200, 124600, 124900, 125000,
0077 };
0078 
0079 struct k3_bandgap {
0080     void __iomem *base;
0081     const struct k3_bandgap_data *conf;
0082 };
0083 
0084 /* common data structures */
0085 struct k3_thermal_data {
0086     struct thermal_zone_device *tzd;
0087     struct k3_bandgap *bgp;
0088     int sensor_id;
0089     u32 ctrl_offset;
0090     u32 stat_offset;
0091 };
0092 
0093 static unsigned int vtm_get_best_value(unsigned int s0, unsigned int s1,
0094                        unsigned int s2)
0095 {
0096     int d01 = abs(s0 - s1);
0097     int d02 = abs(s0 - s2);
0098     int d12 = abs(s1 - s2);
0099 
0100     if (d01 <= d02 && d01 <= d12)
0101         return (s0 + s1) / 2;
0102 
0103     if (d02 <= d01 && d02 <= d12)
0104         return (s0 + s2) / 2;
0105 
0106     return (s1 + s2) / 2;
0107 }
0108 
0109 static int k3_bgp_read_temp(struct k3_thermal_data *devdata,
0110                 int *temp)
0111 {
0112     struct k3_bandgap *bgp;
0113     unsigned int dtemp, s0, s1, s2;
0114 
0115     bgp = devdata->bgp;
0116 
0117     /*
0118      * Errata is applicable for am654 pg 1.0 silicon. There
0119      * is a variation of the order for 8-10 degree centigrade.
0120      * Work around that by getting the average of two closest
0121      * readings out of three readings everytime we want to
0122      * report temperatures.
0123      *
0124      * Errata workaround.
0125      */
0126     s0 = readl(bgp->base + devdata->stat_offset) &
0127         K3_VTM_TS_STAT_DTEMP_MASK;
0128     s1 = readl(bgp->base + devdata->stat_offset) &
0129         K3_VTM_TS_STAT_DTEMP_MASK;
0130     s2 = readl(bgp->base + devdata->stat_offset) &
0131         K3_VTM_TS_STAT_DTEMP_MASK;
0132     dtemp = vtm_get_best_value(s0, s1, s2);
0133 
0134     if (dtemp < K3_VTM_ADC_BEGIN_VAL || dtemp > K3_VTM_ADC_END_VAL)
0135         return -EINVAL;
0136 
0137     *temp = k3_adc_to_temp[dtemp - K3_VTM_ADC_BEGIN_VAL];
0138 
0139     return 0;
0140 }
0141 
0142 static int k3_thermal_get_temp(void *devdata, int *temp)
0143 {
0144     struct k3_thermal_data *data = devdata;
0145     int ret = 0;
0146 
0147     ret = k3_bgp_read_temp(data, temp);
0148     if (ret)
0149         return ret;
0150 
0151     return ret;
0152 }
0153 
0154 static const struct thermal_zone_of_device_ops k3_of_thermal_ops = {
0155     .get_temp = k3_thermal_get_temp,
0156 };
0157 
0158 static const struct of_device_id of_k3_bandgap_match[];
0159 
0160 static int k3_bandgap_probe(struct platform_device *pdev)
0161 {
0162     int ret = 0, cnt, val, id;
0163     struct resource *res;
0164     struct device *dev = &pdev->dev;
0165     struct k3_bandgap *bgp;
0166     struct k3_thermal_data *data;
0167 
0168     if (ARRAY_SIZE(k3_adc_to_temp) != (K3_VTM_ADC_END_VAL + 1 -
0169                         K3_VTM_ADC_BEGIN_VAL))
0170         return -EINVAL;
0171 
0172     bgp = devm_kzalloc(&pdev->dev, sizeof(*bgp), GFP_KERNEL);
0173     if (!bgp)
0174         return -ENOMEM;
0175 
0176     res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
0177     bgp->base = devm_ioremap_resource(dev, res);
0178     if (IS_ERR(bgp->base))
0179         return PTR_ERR(bgp->base);
0180 
0181     pm_runtime_enable(dev);
0182     ret = pm_runtime_get_sync(dev);
0183     if (ret < 0) {
0184         pm_runtime_put_noidle(dev);
0185         pm_runtime_disable(dev);
0186         return ret;
0187     }
0188 
0189     /* Get the sensor count in the VTM */
0190     val = readl(bgp->base + K3_VTM_DEVINFO_PWR0_OFFSET);
0191     cnt = val & K3_VTM_DEVINFO_PWR0_TEMPSENS_CT_MASK;
0192     cnt >>= __ffs(K3_VTM_DEVINFO_PWR0_TEMPSENS_CT_MASK);
0193 
0194     data = devm_kcalloc(dev, cnt, sizeof(*data), GFP_KERNEL);
0195     if (!data) {
0196         ret = -ENOMEM;
0197         goto err_alloc;
0198     }
0199 
0200     /* Register the thermal sensors */
0201     for (id = 0; id < cnt; id++) {
0202         data[id].sensor_id = id;
0203         data[id].bgp = bgp;
0204         data[id].ctrl_offset = K3_VTM_TMPSENS0_CTRL_OFFSET +
0205                     id * K3_VTM_REGS_PER_TS;
0206         data[id].stat_offset = data[id].ctrl_offset + 0x8;
0207 
0208         val = readl(data[id].bgp->base + data[id].ctrl_offset);
0209         val |= (K3_VTM_TMPSENS_CTRL_SOC |
0210             K3_VTM_TMPSENS_CTRL_CLRZ |
0211             K3_VTM_TMPSENS_CTRL_CLKON_REQ);
0212         val &= ~K3_VTM_TMPSENS_CTRL_CBIASSEL;
0213         writel(val, data[id].bgp->base + data[id].ctrl_offset);
0214 
0215         data[id].tzd =
0216         devm_thermal_zone_of_sensor_register(dev, id,
0217                              &data[id],
0218                              &k3_of_thermal_ops);
0219         if (IS_ERR(data[id].tzd)) {
0220             dev_err(dev, "thermal zone device is NULL\n");
0221             ret = PTR_ERR(data[id].tzd);
0222             goto err_alloc;
0223         }
0224 
0225         if (devm_thermal_add_hwmon_sysfs(data[id].tzd))
0226             dev_warn(dev, "Failed to add hwmon sysfs attributes\n");
0227     }
0228 
0229     platform_set_drvdata(pdev, bgp);
0230 
0231     return 0;
0232 
0233 err_alloc:
0234     pm_runtime_put_sync(dev);
0235     pm_runtime_disable(dev);
0236 
0237     return ret;
0238 }
0239 
0240 static int k3_bandgap_remove(struct platform_device *pdev)
0241 {
0242     pm_runtime_put_sync(&pdev->dev);
0243     pm_runtime_disable(&pdev->dev);
0244 
0245     return 0;
0246 }
0247 
0248 static const struct of_device_id of_k3_bandgap_match[] = {
0249     {
0250         .compatible = "ti,am654-vtm",
0251     },
0252     { /* sentinel */ },
0253 };
0254 MODULE_DEVICE_TABLE(of, of_k3_bandgap_match);
0255 
0256 static struct platform_driver k3_bandgap_sensor_driver = {
0257     .probe = k3_bandgap_probe,
0258     .remove = k3_bandgap_remove,
0259     .driver = {
0260         .name = "k3-soc-thermal",
0261         .of_match_table = of_k3_bandgap_match,
0262     },
0263 };
0264 
0265 module_platform_driver(k3_bandgap_sensor_driver);
0266 
0267 MODULE_DESCRIPTION("K3 bandgap temperature sensor driver");
0268 MODULE_LICENSE("GPL v2");
0269 MODULE_AUTHOR("J Keerthy <j-keerthy@ti.com>");