Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0
0002 /*
0003  * Thermal sensor driver for Allwinner SOC
0004  * Copyright (C) 2019 Yangtao Li
0005  *
0006  * Based on the work of Icenowy Zheng <icenowy@aosc.io>
0007  * Based on the work of Ondrej Jirman <megous@megous.com>
0008  * Based on the work of Josef Gajdusek <atx@atx.name>
0009  */
0010 
0011 #include <linux/bitmap.h>
0012 #include <linux/clk.h>
0013 #include <linux/device.h>
0014 #include <linux/interrupt.h>
0015 #include <linux/module.h>
0016 #include <linux/nvmem-consumer.h>
0017 #include <linux/of_device.h>
0018 #include <linux/platform_device.h>
0019 #include <linux/regmap.h>
0020 #include <linux/reset.h>
0021 #include <linux/slab.h>
0022 #include <linux/thermal.h>
0023 
0024 #include "thermal_hwmon.h"
0025 
0026 #define MAX_SENSOR_NUM  4
0027 
0028 #define FT_TEMP_MASK                GENMASK(11, 0)
0029 #define TEMP_CALIB_MASK             GENMASK(11, 0)
0030 #define CALIBRATE_DEFAULT           0x800
0031 
0032 #define SUN8I_THS_CTRL0             0x00
0033 #define SUN8I_THS_CTRL2             0x40
0034 #define SUN8I_THS_IC                0x44
0035 #define SUN8I_THS_IS                0x48
0036 #define SUN8I_THS_MFC               0x70
0037 #define SUN8I_THS_TEMP_CALIB            0x74
0038 #define SUN8I_THS_TEMP_DATA         0x80
0039 
0040 #define SUN50I_THS_CTRL0            0x00
0041 #define SUN50I_H6_THS_ENABLE            0x04
0042 #define SUN50I_H6_THS_PC            0x08
0043 #define SUN50I_H6_THS_DIC           0x10
0044 #define SUN50I_H6_THS_DIS           0x20
0045 #define SUN50I_H6_THS_MFC           0x30
0046 #define SUN50I_H6_THS_TEMP_CALIB        0xa0
0047 #define SUN50I_H6_THS_TEMP_DATA         0xc0
0048 
0049 #define SUN8I_THS_CTRL0_T_ACQ0(x)       (GENMASK(15, 0) & (x))
0050 #define SUN8I_THS_CTRL2_T_ACQ1(x)       ((GENMASK(15, 0) & (x)) << 16)
0051 #define SUN8I_THS_DATA_IRQ_STS(x)       BIT(x + 8)
0052 
0053 #define SUN50I_THS_CTRL0_T_ACQ(x)       ((GENMASK(15, 0) & (x)) << 16)
0054 #define SUN50I_THS_FILTER_EN            BIT(2)
0055 #define SUN50I_THS_FILTER_TYPE(x)       (GENMASK(1, 0) & (x))
0056 #define SUN50I_H6_THS_PC_TEMP_PERIOD(x)     ((GENMASK(19, 0) & (x)) << 12)
0057 #define SUN50I_H6_THS_DATA_IRQ_STS(x)       BIT(x)
0058 
0059 /* millidegree celsius */
0060 
0061 struct tsensor {
0062     struct ths_device       *tmdev;
0063     struct thermal_zone_device  *tzd;
0064     int             id;
0065 };
0066 
0067 struct ths_thermal_chip {
0068     bool            has_mod_clk;
0069     bool            has_bus_clk_reset;
0070     int     sensor_num;
0071     int     offset;
0072     int     scale;
0073     int     ft_deviation;
0074     int     temp_data_base;
0075     int     (*calibrate)(struct ths_device *tmdev,
0076                      u16 *caldata, int callen);
0077     int     (*init)(struct ths_device *tmdev);
0078     unsigned long   (*irq_ack)(struct ths_device *tmdev);
0079     int     (*calc_temp)(struct ths_device *tmdev,
0080                      int id, int reg);
0081 };
0082 
0083 struct ths_device {
0084     const struct ths_thermal_chip       *chip;
0085     struct device               *dev;
0086     struct regmap               *regmap;
0087     struct reset_control            *reset;
0088     struct clk              *bus_clk;
0089     struct clk                              *mod_clk;
0090     struct tsensor              sensor[MAX_SENSOR_NUM];
0091 };
0092 
0093 /* Temp Unit: millidegree Celsius */
0094 static int sun8i_ths_calc_temp(struct ths_device *tmdev,
0095                    int id, int reg)
0096 {
0097     return tmdev->chip->offset - (reg * tmdev->chip->scale / 10);
0098 }
0099 
0100 static int sun50i_h5_calc_temp(struct ths_device *tmdev,
0101                    int id, int reg)
0102 {
0103     if (reg >= 0x500)
0104         return -1191 * reg / 10 + 223000;
0105     else if (!id)
0106         return -1452 * reg / 10 + 259000;
0107     else
0108         return -1590 * reg / 10 + 276000;
0109 }
0110 
0111 static int sun8i_ths_get_temp(void *data, int *temp)
0112 {
0113     struct tsensor *s = data;
0114     struct ths_device *tmdev = s->tmdev;
0115     int val = 0;
0116 
0117     regmap_read(tmdev->regmap, tmdev->chip->temp_data_base +
0118             0x4 * s->id, &val);
0119 
0120     /* ths have no data yet */
0121     if (!val)
0122         return -EAGAIN;
0123 
0124     *temp = tmdev->chip->calc_temp(tmdev, s->id, val);
0125     /*
0126      * According to the original sdk, there are some platforms(rarely)
0127      * that add a fixed offset value after calculating the temperature
0128      * value. We can't simply put it on the formula for calculating the
0129      * temperature above, because the formula for calculating the
0130      * temperature above is also used when the sensor is calibrated. If
0131      * do this, the correct calibration formula is hard to know.
0132      */
0133     *temp += tmdev->chip->ft_deviation;
0134 
0135     return 0;
0136 }
0137 
0138 static const struct thermal_zone_of_device_ops ths_ops = {
0139     .get_temp = sun8i_ths_get_temp,
0140 };
0141 
0142 static const struct regmap_config config = {
0143     .reg_bits = 32,
0144     .val_bits = 32,
0145     .reg_stride = 4,
0146     .fast_io = true,
0147     .max_register = 0xfc,
0148 };
0149 
0150 static unsigned long sun8i_h3_irq_ack(struct ths_device *tmdev)
0151 {
0152     unsigned long irq_bitmap = 0;
0153     int i, state;
0154 
0155     regmap_read(tmdev->regmap, SUN8I_THS_IS, &state);
0156 
0157     for (i = 0; i < tmdev->chip->sensor_num; i++) {
0158         if (state & SUN8I_THS_DATA_IRQ_STS(i)) {
0159             regmap_write(tmdev->regmap, SUN8I_THS_IS,
0160                      SUN8I_THS_DATA_IRQ_STS(i));
0161             bitmap_set(&irq_bitmap, i, 1);
0162         }
0163     }
0164 
0165     return irq_bitmap;
0166 }
0167 
0168 static unsigned long sun50i_h6_irq_ack(struct ths_device *tmdev)
0169 {
0170     unsigned long irq_bitmap = 0;
0171     int i, state;
0172 
0173     regmap_read(tmdev->regmap, SUN50I_H6_THS_DIS, &state);
0174 
0175     for (i = 0; i < tmdev->chip->sensor_num; i++) {
0176         if (state & SUN50I_H6_THS_DATA_IRQ_STS(i)) {
0177             regmap_write(tmdev->regmap, SUN50I_H6_THS_DIS,
0178                      SUN50I_H6_THS_DATA_IRQ_STS(i));
0179             bitmap_set(&irq_bitmap, i, 1);
0180         }
0181     }
0182 
0183     return irq_bitmap;
0184 }
0185 
0186 static irqreturn_t sun8i_irq_thread(int irq, void *data)
0187 {
0188     struct ths_device *tmdev = data;
0189     unsigned long irq_bitmap = tmdev->chip->irq_ack(tmdev);
0190     int i;
0191 
0192     for_each_set_bit(i, &irq_bitmap, tmdev->chip->sensor_num) {
0193         thermal_zone_device_update(tmdev->sensor[i].tzd,
0194                        THERMAL_EVENT_UNSPECIFIED);
0195     }
0196 
0197     return IRQ_HANDLED;
0198 }
0199 
0200 static int sun8i_h3_ths_calibrate(struct ths_device *tmdev,
0201                   u16 *caldata, int callen)
0202 {
0203     int i;
0204 
0205     if (!caldata[0] || callen < 2 * tmdev->chip->sensor_num)
0206         return -EINVAL;
0207 
0208     for (i = 0; i < tmdev->chip->sensor_num; i++) {
0209         int offset = (i % 2) << 4;
0210 
0211         regmap_update_bits(tmdev->regmap,
0212                    SUN8I_THS_TEMP_CALIB + (4 * (i >> 1)),
0213                    0xfff << offset,
0214                    caldata[i] << offset);
0215     }
0216 
0217     return 0;
0218 }
0219 
0220 static int sun50i_h6_ths_calibrate(struct ths_device *tmdev,
0221                    u16 *caldata, int callen)
0222 {
0223     struct device *dev = tmdev->dev;
0224     int i, ft_temp;
0225 
0226     if (!caldata[0] || callen < 2 + 2 * tmdev->chip->sensor_num)
0227         return -EINVAL;
0228 
0229     /*
0230      * efuse layout:
0231      *
0232      *  0   11  16   32
0233      *  +-------+-------+-------+
0234      *  |temp|  |sensor0|sensor1|
0235      *  +-------+-------+-------+
0236      *
0237      * The calibration data on the H6 is the ambient temperature and
0238      * sensor values that are filled during the factory test stage.
0239      *
0240      * The unit of stored FT temperature is 0.1 degree celsius.
0241      *
0242      * We need to calculate a delta between measured and caluclated
0243      * register values and this will become a calibration offset.
0244      */
0245     ft_temp = (caldata[0] & FT_TEMP_MASK) * 100;
0246 
0247     for (i = 0; i < tmdev->chip->sensor_num; i++) {
0248         int sensor_reg = caldata[i + 1] & TEMP_CALIB_MASK;
0249         int cdata, offset;
0250         int sensor_temp = tmdev->chip->calc_temp(tmdev, i, sensor_reg);
0251 
0252         /*
0253          * Calibration data is CALIBRATE_DEFAULT - (calculated
0254          * temperature from sensor reading at factory temperature
0255          * minus actual factory temperature) * 14.88 (scale from
0256          * temperature to register values)
0257          */
0258         cdata = CALIBRATE_DEFAULT -
0259             ((sensor_temp - ft_temp) * 10 / tmdev->chip->scale);
0260         if (cdata & ~TEMP_CALIB_MASK) {
0261             /*
0262              * Calibration value more than 12-bit, but calibration
0263              * register is 12-bit. In this case, ths hardware can
0264              * still work without calibration, although the data
0265              * won't be so accurate.
0266              */
0267             dev_warn(dev, "sensor%d is not calibrated.\n", i);
0268             continue;
0269         }
0270 
0271         offset = (i % 2) * 16;
0272         regmap_update_bits(tmdev->regmap,
0273                    SUN50I_H6_THS_TEMP_CALIB + (i / 2 * 4),
0274                    0xfff << offset,
0275                    cdata << offset);
0276     }
0277 
0278     return 0;
0279 }
0280 
0281 static int sun8i_ths_calibrate(struct ths_device *tmdev)
0282 {
0283     struct nvmem_cell *calcell;
0284     struct device *dev = tmdev->dev;
0285     u16 *caldata;
0286     size_t callen;
0287     int ret = 0;
0288 
0289     calcell = devm_nvmem_cell_get(dev, "calibration");
0290     if (IS_ERR(calcell)) {
0291         if (PTR_ERR(calcell) == -EPROBE_DEFER)
0292             return -EPROBE_DEFER;
0293         /*
0294          * Even if the external calibration data stored in sid is
0295          * not accessible, the THS hardware can still work, although
0296          * the data won't be so accurate.
0297          *
0298          * The default value of calibration register is 0x800 for
0299          * every sensor, and the calibration value is usually 0x7xx
0300          * or 0x8xx, so they won't be away from the default value
0301          * for a lot.
0302          *
0303          * So here we do not return error if the calibration data is
0304          * not available, except the probe needs deferring.
0305          */
0306         goto out;
0307     }
0308 
0309     caldata = nvmem_cell_read(calcell, &callen);
0310     if (IS_ERR(caldata)) {
0311         ret = PTR_ERR(caldata);
0312         goto out;
0313     }
0314 
0315     tmdev->chip->calibrate(tmdev, caldata, callen);
0316 
0317     kfree(caldata);
0318 out:
0319     return ret;
0320 }
0321 
0322 static int sun8i_ths_resource_init(struct ths_device *tmdev)
0323 {
0324     struct device *dev = tmdev->dev;
0325     struct platform_device *pdev = to_platform_device(dev);
0326     void __iomem *base;
0327     int ret;
0328 
0329     base = devm_platform_ioremap_resource(pdev, 0);
0330     if (IS_ERR(base))
0331         return PTR_ERR(base);
0332 
0333     tmdev->regmap = devm_regmap_init_mmio(dev, base, &config);
0334     if (IS_ERR(tmdev->regmap))
0335         return PTR_ERR(tmdev->regmap);
0336 
0337     if (tmdev->chip->has_bus_clk_reset) {
0338         tmdev->reset = devm_reset_control_get(dev, NULL);
0339         if (IS_ERR(tmdev->reset))
0340             return PTR_ERR(tmdev->reset);
0341 
0342         tmdev->bus_clk = devm_clk_get(&pdev->dev, "bus");
0343         if (IS_ERR(tmdev->bus_clk))
0344             return PTR_ERR(tmdev->bus_clk);
0345     }
0346 
0347     if (tmdev->chip->has_mod_clk) {
0348         tmdev->mod_clk = devm_clk_get(&pdev->dev, "mod");
0349         if (IS_ERR(tmdev->mod_clk))
0350             return PTR_ERR(tmdev->mod_clk);
0351     }
0352 
0353     ret = reset_control_deassert(tmdev->reset);
0354     if (ret)
0355         return ret;
0356 
0357     ret = clk_prepare_enable(tmdev->bus_clk);
0358     if (ret)
0359         goto assert_reset;
0360 
0361     ret = clk_set_rate(tmdev->mod_clk, 24000000);
0362     if (ret)
0363         goto bus_disable;
0364 
0365     ret = clk_prepare_enable(tmdev->mod_clk);
0366     if (ret)
0367         goto bus_disable;
0368 
0369     ret = sun8i_ths_calibrate(tmdev);
0370     if (ret)
0371         goto mod_disable;
0372 
0373     return 0;
0374 
0375 mod_disable:
0376     clk_disable_unprepare(tmdev->mod_clk);
0377 bus_disable:
0378     clk_disable_unprepare(tmdev->bus_clk);
0379 assert_reset:
0380     reset_control_assert(tmdev->reset);
0381 
0382     return ret;
0383 }
0384 
0385 static int sun8i_h3_thermal_init(struct ths_device *tmdev)
0386 {
0387     int val;
0388 
0389     /* average over 4 samples */
0390     regmap_write(tmdev->regmap, SUN8I_THS_MFC,
0391              SUN50I_THS_FILTER_EN |
0392              SUN50I_THS_FILTER_TYPE(1));
0393     /*
0394      * clkin = 24MHz
0395      * filter_samples = 4
0396      * period = 0.25s
0397      *
0398      * x = period * clkin / 4096 / filter_samples - 1
0399      *   = 365
0400      */
0401     val = GENMASK(7 + tmdev->chip->sensor_num, 8);
0402     regmap_write(tmdev->regmap, SUN8I_THS_IC,
0403              SUN50I_H6_THS_PC_TEMP_PERIOD(365) | val);
0404     /*
0405      * T_acq = 20us
0406      * clkin = 24MHz
0407      *
0408      * x = T_acq * clkin - 1
0409      *   = 479
0410      */
0411     regmap_write(tmdev->regmap, SUN8I_THS_CTRL0,
0412              SUN8I_THS_CTRL0_T_ACQ0(479));
0413     val = GENMASK(tmdev->chip->sensor_num - 1, 0);
0414     regmap_write(tmdev->regmap, SUN8I_THS_CTRL2,
0415              SUN8I_THS_CTRL2_T_ACQ1(479) | val);
0416 
0417     return 0;
0418 }
0419 
0420 /*
0421  * Without this undocumented value, the returned temperatures would
0422  * be higher than real ones by about 20C.
0423  */
0424 #define SUN50I_H6_CTRL0_UNK 0x0000002f
0425 
0426 static int sun50i_h6_thermal_init(struct ths_device *tmdev)
0427 {
0428     int val;
0429 
0430     /*
0431      * T_acq = 20us
0432      * clkin = 24MHz
0433      *
0434      * x = T_acq * clkin - 1
0435      *   = 479
0436      */
0437     regmap_write(tmdev->regmap, SUN50I_THS_CTRL0,
0438              SUN50I_H6_CTRL0_UNK | SUN50I_THS_CTRL0_T_ACQ(479));
0439     /* average over 4 samples */
0440     regmap_write(tmdev->regmap, SUN50I_H6_THS_MFC,
0441              SUN50I_THS_FILTER_EN |
0442              SUN50I_THS_FILTER_TYPE(1));
0443     /*
0444      * clkin = 24MHz
0445      * filter_samples = 4
0446      * period = 0.25s
0447      *
0448      * x = period * clkin / 4096 / filter_samples - 1
0449      *   = 365
0450      */
0451     regmap_write(tmdev->regmap, SUN50I_H6_THS_PC,
0452              SUN50I_H6_THS_PC_TEMP_PERIOD(365));
0453     /* enable sensor */
0454     val = GENMASK(tmdev->chip->sensor_num - 1, 0);
0455     regmap_write(tmdev->regmap, SUN50I_H6_THS_ENABLE, val);
0456     /* thermal data interrupt enable */
0457     val = GENMASK(tmdev->chip->sensor_num - 1, 0);
0458     regmap_write(tmdev->regmap, SUN50I_H6_THS_DIC, val);
0459 
0460     return 0;
0461 }
0462 
0463 static int sun8i_ths_register(struct ths_device *tmdev)
0464 {
0465     int i;
0466 
0467     for (i = 0; i < tmdev->chip->sensor_num; i++) {
0468         tmdev->sensor[i].tmdev = tmdev;
0469         tmdev->sensor[i].id = i;
0470         tmdev->sensor[i].tzd =
0471             devm_thermal_zone_of_sensor_register(tmdev->dev,
0472                                  i,
0473                                  &tmdev->sensor[i],
0474                                  &ths_ops);
0475         if (IS_ERR(tmdev->sensor[i].tzd))
0476             return PTR_ERR(tmdev->sensor[i].tzd);
0477 
0478         if (devm_thermal_add_hwmon_sysfs(tmdev->sensor[i].tzd))
0479             dev_warn(tmdev->dev,
0480                  "Failed to add hwmon sysfs attributes\n");
0481     }
0482 
0483     return 0;
0484 }
0485 
0486 static int sun8i_ths_probe(struct platform_device *pdev)
0487 {
0488     struct ths_device *tmdev;
0489     struct device *dev = &pdev->dev;
0490     int ret, irq;
0491 
0492     tmdev = devm_kzalloc(dev, sizeof(*tmdev), GFP_KERNEL);
0493     if (!tmdev)
0494         return -ENOMEM;
0495 
0496     tmdev->dev = dev;
0497     tmdev->chip = of_device_get_match_data(&pdev->dev);
0498     if (!tmdev->chip)
0499         return -EINVAL;
0500 
0501     platform_set_drvdata(pdev, tmdev);
0502 
0503     ret = sun8i_ths_resource_init(tmdev);
0504     if (ret)
0505         return ret;
0506 
0507     irq = platform_get_irq(pdev, 0);
0508     if (irq < 0)
0509         return irq;
0510 
0511     ret = tmdev->chip->init(tmdev);
0512     if (ret)
0513         return ret;
0514 
0515     ret = sun8i_ths_register(tmdev);
0516     if (ret)
0517         return ret;
0518 
0519     /*
0520      * Avoid entering the interrupt handler, the thermal device is not
0521      * registered yet, we deffer the registration of the interrupt to
0522      * the end.
0523      */
0524     ret = devm_request_threaded_irq(dev, irq, NULL,
0525                     sun8i_irq_thread,
0526                     IRQF_ONESHOT, "ths", tmdev);
0527     if (ret)
0528         return ret;
0529 
0530     return 0;
0531 }
0532 
0533 static int sun8i_ths_remove(struct platform_device *pdev)
0534 {
0535     struct ths_device *tmdev = platform_get_drvdata(pdev);
0536 
0537     clk_disable_unprepare(tmdev->mod_clk);
0538     clk_disable_unprepare(tmdev->bus_clk);
0539     reset_control_assert(tmdev->reset);
0540 
0541     return 0;
0542 }
0543 
0544 static const struct ths_thermal_chip sun8i_a83t_ths = {
0545     .sensor_num = 3,
0546     .scale = 705,
0547     .offset = 191668,
0548     .temp_data_base = SUN8I_THS_TEMP_DATA,
0549     .calibrate = sun8i_h3_ths_calibrate,
0550     .init = sun8i_h3_thermal_init,
0551     .irq_ack = sun8i_h3_irq_ack,
0552     .calc_temp = sun8i_ths_calc_temp,
0553 };
0554 
0555 static const struct ths_thermal_chip sun8i_h3_ths = {
0556     .sensor_num = 1,
0557     .scale = 1211,
0558     .offset = 217000,
0559     .has_mod_clk = true,
0560     .has_bus_clk_reset = true,
0561     .temp_data_base = SUN8I_THS_TEMP_DATA,
0562     .calibrate = sun8i_h3_ths_calibrate,
0563     .init = sun8i_h3_thermal_init,
0564     .irq_ack = sun8i_h3_irq_ack,
0565     .calc_temp = sun8i_ths_calc_temp,
0566 };
0567 
0568 static const struct ths_thermal_chip sun8i_r40_ths = {
0569     .sensor_num = 2,
0570     .offset = 251086,
0571     .scale = 1130,
0572     .has_mod_clk = true,
0573     .has_bus_clk_reset = true,
0574     .temp_data_base = SUN8I_THS_TEMP_DATA,
0575     .calibrate = sun8i_h3_ths_calibrate,
0576     .init = sun8i_h3_thermal_init,
0577     .irq_ack = sun8i_h3_irq_ack,
0578     .calc_temp = sun8i_ths_calc_temp,
0579 };
0580 
0581 static const struct ths_thermal_chip sun50i_a64_ths = {
0582     .sensor_num = 3,
0583     .offset = 260890,
0584     .scale = 1170,
0585     .has_mod_clk = true,
0586     .has_bus_clk_reset = true,
0587     .temp_data_base = SUN8I_THS_TEMP_DATA,
0588     .calibrate = sun8i_h3_ths_calibrate,
0589     .init = sun8i_h3_thermal_init,
0590     .irq_ack = sun8i_h3_irq_ack,
0591     .calc_temp = sun8i_ths_calc_temp,
0592 };
0593 
0594 static const struct ths_thermal_chip sun50i_a100_ths = {
0595     .sensor_num = 3,
0596     .has_bus_clk_reset = true,
0597     .ft_deviation = 8000,
0598     .offset = 187744,
0599     .scale = 672,
0600     .temp_data_base = SUN50I_H6_THS_TEMP_DATA,
0601     .calibrate = sun50i_h6_ths_calibrate,
0602     .init = sun50i_h6_thermal_init,
0603     .irq_ack = sun50i_h6_irq_ack,
0604     .calc_temp = sun8i_ths_calc_temp,
0605 };
0606 
0607 static const struct ths_thermal_chip sun50i_h5_ths = {
0608     .sensor_num = 2,
0609     .has_mod_clk = true,
0610     .has_bus_clk_reset = true,
0611     .temp_data_base = SUN8I_THS_TEMP_DATA,
0612     .calibrate = sun8i_h3_ths_calibrate,
0613     .init = sun8i_h3_thermal_init,
0614     .irq_ack = sun8i_h3_irq_ack,
0615     .calc_temp = sun50i_h5_calc_temp,
0616 };
0617 
0618 static const struct ths_thermal_chip sun50i_h6_ths = {
0619     .sensor_num = 2,
0620     .has_bus_clk_reset = true,
0621     .ft_deviation = 7000,
0622     .offset = 187744,
0623     .scale = 672,
0624     .temp_data_base = SUN50I_H6_THS_TEMP_DATA,
0625     .calibrate = sun50i_h6_ths_calibrate,
0626     .init = sun50i_h6_thermal_init,
0627     .irq_ack = sun50i_h6_irq_ack,
0628     .calc_temp = sun8i_ths_calc_temp,
0629 };
0630 
0631 static const struct of_device_id of_ths_match[] = {
0632     { .compatible = "allwinner,sun8i-a83t-ths", .data = &sun8i_a83t_ths },
0633     { .compatible = "allwinner,sun8i-h3-ths", .data = &sun8i_h3_ths },
0634     { .compatible = "allwinner,sun8i-r40-ths", .data = &sun8i_r40_ths },
0635     { .compatible = "allwinner,sun50i-a64-ths", .data = &sun50i_a64_ths },
0636     { .compatible = "allwinner,sun50i-a100-ths", .data = &sun50i_a100_ths },
0637     { .compatible = "allwinner,sun50i-h5-ths", .data = &sun50i_h5_ths },
0638     { .compatible = "allwinner,sun50i-h6-ths", .data = &sun50i_h6_ths },
0639     { /* sentinel */ },
0640 };
0641 MODULE_DEVICE_TABLE(of, of_ths_match);
0642 
0643 static struct platform_driver ths_driver = {
0644     .probe = sun8i_ths_probe,
0645     .remove = sun8i_ths_remove,
0646     .driver = {
0647         .name = "sun8i-thermal",
0648         .of_match_table = of_ths_match,
0649     },
0650 };
0651 module_platform_driver(ths_driver);
0652 
0653 MODULE_DESCRIPTION("Thermal sensor driver for Allwinner SOC");
0654 MODULE_LICENSE("GPL v2");