0001
0002
0003
0004
0005
0006
0007 #include <linux/device.h>
0008 #include <linux/err.h>
0009 #include <linux/io.h>
0010 #include <linux/kernel.h>
0011 #include <linux/of.h>
0012 #include <linux/module.h>
0013 #include <linux/delay.h>
0014 #include <linux/platform_device.h>
0015 #include <linux/of_device.h>
0016 #include <linux/thermal.h>
0017 #include <linux/iopoll.h>
0018 #include <linux/mfd/syscon.h>
0019 #include <linux/regmap.h>
0020 #include <linux/interrupt.h>
0021
0022 #include "thermal_core.h"
0023
0024
0025 #define PMU_TDC0_SW_RST_MASK (0x1 << 1)
0026 #define PMU_TM_DISABLE_OFFS 0
0027 #define PMU_TM_DISABLE_MASK (0x1 << PMU_TM_DISABLE_OFFS)
0028 #define PMU_TDC0_REF_CAL_CNT_OFFS 11
0029 #define PMU_TDC0_REF_CAL_CNT_MASK (0x1ff << PMU_TDC0_REF_CAL_CNT_OFFS)
0030 #define PMU_TDC0_OTF_CAL_MASK (0x1 << 30)
0031 #define PMU_TDC0_START_CAL_MASK (0x1 << 25)
0032
0033 #define A375_UNIT_CONTROL_SHIFT 27
0034 #define A375_UNIT_CONTROL_MASK 0x7
0035 #define A375_READOUT_INVERT BIT(15)
0036 #define A375_HW_RESETn BIT(8)
0037
0038
0039 #define CONTROL0_TSEN_TC_TRIM_MASK 0x7
0040 #define CONTROL0_TSEN_TC_TRIM_VAL 0x3
0041
0042 #define CONTROL0_TSEN_START BIT(0)
0043 #define CONTROL0_TSEN_RESET BIT(1)
0044 #define CONTROL0_TSEN_ENABLE BIT(2)
0045 #define CONTROL0_TSEN_AVG_BYPASS BIT(6)
0046 #define CONTROL0_TSEN_CHAN_SHIFT 13
0047 #define CONTROL0_TSEN_CHAN_MASK 0xF
0048 #define CONTROL0_TSEN_OSR_SHIFT 24
0049 #define CONTROL0_TSEN_OSR_MAX 0x3
0050 #define CONTROL0_TSEN_MODE_SHIFT 30
0051 #define CONTROL0_TSEN_MODE_EXTERNAL 0x2
0052 #define CONTROL0_TSEN_MODE_MASK 0x3
0053
0054 #define CONTROL1_TSEN_AVG_MASK 0x7
0055 #define CONTROL1_EXT_TSEN_SW_RESET BIT(7)
0056 #define CONTROL1_EXT_TSEN_HW_RESETn BIT(8)
0057 #define CONTROL1_TSEN_INT_EN BIT(25)
0058 #define CONTROL1_TSEN_SELECT_OFF 21
0059 #define CONTROL1_TSEN_SELECT_MASK 0x3
0060
0061 #define STATUS_POLL_PERIOD_US 1000
0062 #define STATUS_POLL_TIMEOUT_US 100000
0063 #define OVERHEAT_INT_POLL_DELAY_MS 1000
0064
0065 struct armada_thermal_data;
0066
0067
0068 struct armada_thermal_priv {
0069 struct device *dev;
0070 struct regmap *syscon;
0071 char zone_name[THERMAL_NAME_LENGTH];
0072
0073 struct mutex update_lock;
0074 struct armada_thermal_data *data;
0075 struct thermal_zone_device *overheat_sensor;
0076 int interrupt_source;
0077 int current_channel;
0078 long current_threshold;
0079 long current_hysteresis;
0080 };
0081
0082 struct armada_thermal_data {
0083
0084 void (*init)(struct platform_device *pdev,
0085 struct armada_thermal_priv *priv);
0086
0087
0088 s64 coef_b;
0089 s64 coef_m;
0090 u32 coef_div;
0091 bool inverted;
0092 bool signed_sample;
0093
0094
0095 unsigned int temp_shift;
0096 unsigned int temp_mask;
0097 unsigned int thresh_shift;
0098 unsigned int hyst_shift;
0099 unsigned int hyst_mask;
0100 u32 is_valid_bit;
0101
0102
0103 unsigned int syscon_control0_off;
0104 unsigned int syscon_control1_off;
0105 unsigned int syscon_status_off;
0106 unsigned int dfx_irq_cause_off;
0107 unsigned int dfx_irq_mask_off;
0108 unsigned int dfx_overheat_irq;
0109 unsigned int dfx_server_irq_mask_off;
0110 unsigned int dfx_server_irq_en;
0111
0112
0113 unsigned int cpu_nr;
0114 };
0115
0116 struct armada_drvdata {
0117 enum drvtype {
0118 LEGACY,
0119 SYSCON
0120 } type;
0121 union {
0122 struct armada_thermal_priv *priv;
0123 struct thermal_zone_device *tz;
0124 } data;
0125 };
0126
0127
0128
0129
0130
0131
0132
0133 struct armada_thermal_sensor {
0134 struct armada_thermal_priv *priv;
0135 int id;
0136 };
0137
0138 static void armadaxp_init(struct platform_device *pdev,
0139 struct armada_thermal_priv *priv)
0140 {
0141 struct armada_thermal_data *data = priv->data;
0142 u32 reg;
0143
0144 regmap_read(priv->syscon, data->syscon_control1_off, ®);
0145 reg |= PMU_TDC0_OTF_CAL_MASK;
0146
0147
0148 reg &= ~PMU_TDC0_REF_CAL_CNT_MASK;
0149 reg |= (0xf1 << PMU_TDC0_REF_CAL_CNT_OFFS);
0150
0151
0152 reg |= PMU_TDC0_SW_RST_MASK;
0153
0154 regmap_write(priv->syscon, data->syscon_control1_off, reg);
0155
0156 reg &= ~PMU_TDC0_SW_RST_MASK;
0157 regmap_write(priv->syscon, data->syscon_control1_off, reg);
0158
0159
0160 regmap_read(priv->syscon, data->syscon_status_off, ®);
0161 reg &= ~PMU_TM_DISABLE_MASK;
0162 regmap_write(priv->syscon, data->syscon_status_off, reg);
0163 }
0164
0165 static void armada370_init(struct platform_device *pdev,
0166 struct armada_thermal_priv *priv)
0167 {
0168 struct armada_thermal_data *data = priv->data;
0169 u32 reg;
0170
0171 regmap_read(priv->syscon, data->syscon_control1_off, ®);
0172 reg |= PMU_TDC0_OTF_CAL_MASK;
0173
0174
0175 reg &= ~PMU_TDC0_REF_CAL_CNT_MASK;
0176 reg |= (0xf1 << PMU_TDC0_REF_CAL_CNT_OFFS);
0177
0178
0179 reg &= ~PMU_TDC0_START_CAL_MASK;
0180
0181 regmap_write(priv->syscon, data->syscon_control1_off, reg);
0182
0183 msleep(10);
0184 }
0185
0186 static void armada375_init(struct platform_device *pdev,
0187 struct armada_thermal_priv *priv)
0188 {
0189 struct armada_thermal_data *data = priv->data;
0190 u32 reg;
0191
0192 regmap_read(priv->syscon, data->syscon_control1_off, ®);
0193 reg &= ~(A375_UNIT_CONTROL_MASK << A375_UNIT_CONTROL_SHIFT);
0194 reg &= ~A375_READOUT_INVERT;
0195 reg &= ~A375_HW_RESETn;
0196 regmap_write(priv->syscon, data->syscon_control1_off, reg);
0197
0198 msleep(20);
0199
0200 reg |= A375_HW_RESETn;
0201 regmap_write(priv->syscon, data->syscon_control1_off, reg);
0202
0203 msleep(50);
0204 }
0205
0206 static int armada_wait_sensor_validity(struct armada_thermal_priv *priv)
0207 {
0208 u32 reg;
0209
0210 return regmap_read_poll_timeout(priv->syscon,
0211 priv->data->syscon_status_off, reg,
0212 reg & priv->data->is_valid_bit,
0213 STATUS_POLL_PERIOD_US,
0214 STATUS_POLL_TIMEOUT_US);
0215 }
0216
0217 static void armada380_init(struct platform_device *pdev,
0218 struct armada_thermal_priv *priv)
0219 {
0220 struct armada_thermal_data *data = priv->data;
0221 u32 reg;
0222
0223
0224 regmap_read(priv->syscon, data->syscon_control1_off, ®);
0225 reg |= CONTROL1_EXT_TSEN_HW_RESETn;
0226 reg &= ~CONTROL1_EXT_TSEN_SW_RESET;
0227 regmap_write(priv->syscon, data->syscon_control1_off, reg);
0228
0229
0230 regmap_read(priv->syscon, data->syscon_control0_off, ®);
0231 reg &= ~CONTROL0_TSEN_TC_TRIM_MASK;
0232 reg |= CONTROL0_TSEN_TC_TRIM_VAL;
0233 regmap_write(priv->syscon, data->syscon_control0_off, reg);
0234 }
0235
0236 static void armada_ap806_init(struct platform_device *pdev,
0237 struct armada_thermal_priv *priv)
0238 {
0239 struct armada_thermal_data *data = priv->data;
0240 u32 reg;
0241
0242 regmap_read(priv->syscon, data->syscon_control0_off, ®);
0243 reg &= ~CONTROL0_TSEN_RESET;
0244 reg |= CONTROL0_TSEN_START | CONTROL0_TSEN_ENABLE;
0245
0246
0247 reg |= CONTROL0_TSEN_OSR_MAX << CONTROL0_TSEN_OSR_SHIFT;
0248
0249
0250 reg &= ~CONTROL0_TSEN_AVG_BYPASS;
0251
0252 regmap_write(priv->syscon, data->syscon_control0_off, reg);
0253 }
0254
0255 static void armada_cp110_init(struct platform_device *pdev,
0256 struct armada_thermal_priv *priv)
0257 {
0258 struct armada_thermal_data *data = priv->data;
0259 u32 reg;
0260
0261 armada380_init(pdev, priv);
0262
0263
0264 regmap_read(priv->syscon, data->syscon_control0_off, ®);
0265 reg |= CONTROL0_TSEN_OSR_MAX << CONTROL0_TSEN_OSR_SHIFT;
0266 regmap_write(priv->syscon, data->syscon_control0_off, reg);
0267
0268
0269 regmap_read(priv->syscon, data->syscon_control1_off, ®);
0270 reg &= ~CONTROL1_TSEN_AVG_MASK;
0271 reg |= 1;
0272 regmap_write(priv->syscon, data->syscon_control1_off, reg);
0273 }
0274
0275 static bool armada_is_valid(struct armada_thermal_priv *priv)
0276 {
0277 u32 reg;
0278
0279 if (!priv->data->is_valid_bit)
0280 return true;
0281
0282 regmap_read(priv->syscon, priv->data->syscon_status_off, ®);
0283
0284 return reg & priv->data->is_valid_bit;
0285 }
0286
0287 static void armada_enable_overheat_interrupt(struct armada_thermal_priv *priv)
0288 {
0289 struct armada_thermal_data *data = priv->data;
0290 u32 reg;
0291
0292
0293 regmap_read(priv->syscon, data->dfx_irq_cause_off, ®);
0294
0295
0296 regmap_read(priv->syscon, data->dfx_irq_mask_off, ®);
0297 reg |= data->dfx_overheat_irq;
0298 regmap_write(priv->syscon, data->dfx_irq_mask_off, reg);
0299
0300
0301 regmap_read(priv->syscon, data->dfx_server_irq_mask_off, ®);
0302 reg |= data->dfx_server_irq_en;
0303 regmap_write(priv->syscon, data->dfx_server_irq_mask_off, reg);
0304
0305
0306 regmap_read(priv->syscon, data->syscon_control1_off, ®);
0307 reg |= CONTROL1_TSEN_INT_EN;
0308 regmap_write(priv->syscon, data->syscon_control1_off, reg);
0309 }
0310
0311 static void __maybe_unused
0312 armada_disable_overheat_interrupt(struct armada_thermal_priv *priv)
0313 {
0314 struct armada_thermal_data *data = priv->data;
0315 u32 reg;
0316
0317 regmap_read(priv->syscon, data->syscon_control1_off, ®);
0318 reg &= ~CONTROL1_TSEN_INT_EN;
0319 regmap_write(priv->syscon, data->syscon_control1_off, reg);
0320 }
0321
0322
0323 static int armada_select_channel(struct armada_thermal_priv *priv, int channel)
0324 {
0325 struct armada_thermal_data *data = priv->data;
0326 u32 ctrl0;
0327
0328 if (channel < 0 || channel > priv->data->cpu_nr)
0329 return -EINVAL;
0330
0331 if (priv->current_channel == channel)
0332 return 0;
0333
0334
0335 regmap_read(priv->syscon, data->syscon_control0_off, &ctrl0);
0336 ctrl0 &= ~CONTROL0_TSEN_START;
0337 regmap_write(priv->syscon, data->syscon_control0_off, ctrl0);
0338
0339
0340 ctrl0 &= ~(CONTROL0_TSEN_MODE_MASK << CONTROL0_TSEN_MODE_SHIFT);
0341
0342
0343 if (channel) {
0344
0345 ctrl0 |= CONTROL0_TSEN_MODE_EXTERNAL <<
0346 CONTROL0_TSEN_MODE_SHIFT;
0347
0348 ctrl0 &= ~(CONTROL0_TSEN_CHAN_MASK << CONTROL0_TSEN_CHAN_SHIFT);
0349 ctrl0 |= (channel - 1) << CONTROL0_TSEN_CHAN_SHIFT;
0350 }
0351
0352
0353 regmap_write(priv->syscon, data->syscon_control0_off, ctrl0);
0354 priv->current_channel = channel;
0355
0356
0357 ctrl0 |= CONTROL0_TSEN_START;
0358 regmap_write(priv->syscon, data->syscon_control0_off, ctrl0);
0359
0360
0361
0362
0363
0364
0365 if (armada_wait_sensor_validity(priv)) {
0366 dev_err(priv->dev,
0367 "Temperature sensor reading not valid\n");
0368 return -EIO;
0369 }
0370
0371 return 0;
0372 }
0373
0374 static int armada_read_sensor(struct armada_thermal_priv *priv, int *temp)
0375 {
0376 u32 reg, div;
0377 s64 sample, b, m;
0378
0379 regmap_read(priv->syscon, priv->data->syscon_status_off, ®);
0380 reg = (reg >> priv->data->temp_shift) & priv->data->temp_mask;
0381 if (priv->data->signed_sample)
0382
0383 sample = sign_extend32(reg, fls(priv->data->temp_mask) - 1);
0384 else
0385 sample = reg;
0386
0387
0388 b = priv->data->coef_b;
0389 m = priv->data->coef_m;
0390 div = priv->data->coef_div;
0391
0392 if (priv->data->inverted)
0393 *temp = div_s64((m * sample) - b, div);
0394 else
0395 *temp = div_s64(b - (m * sample), div);
0396
0397 return 0;
0398 }
0399
0400 static int armada_get_temp_legacy(struct thermal_zone_device *thermal,
0401 int *temp)
0402 {
0403 struct armada_thermal_priv *priv = thermal->devdata;
0404 int ret;
0405
0406
0407 if (!armada_is_valid(priv)) {
0408 dev_err(priv->dev,
0409 "Temperature sensor reading not valid\n");
0410 return -EIO;
0411 }
0412
0413
0414 ret = armada_read_sensor(priv, temp);
0415
0416 return ret;
0417 }
0418
0419 static struct thermal_zone_device_ops legacy_ops = {
0420 .get_temp = armada_get_temp_legacy,
0421 };
0422
0423 static int armada_get_temp(void *_sensor, int *temp)
0424 {
0425 struct armada_thermal_sensor *sensor = _sensor;
0426 struct armada_thermal_priv *priv = sensor->priv;
0427 int ret;
0428
0429 mutex_lock(&priv->update_lock);
0430
0431
0432 ret = armada_select_channel(priv, sensor->id);
0433 if (ret)
0434 goto unlock_mutex;
0435
0436
0437 ret = armada_read_sensor(priv, temp);
0438 if (ret)
0439 goto unlock_mutex;
0440
0441
0442
0443
0444
0445 ret = armada_select_channel(priv, priv->interrupt_source);
0446
0447 unlock_mutex:
0448 mutex_unlock(&priv->update_lock);
0449
0450 return ret;
0451 }
0452
0453 static const struct thermal_zone_of_device_ops of_ops = {
0454 .get_temp = armada_get_temp,
0455 };
0456
0457 static unsigned int armada_mc_to_reg_temp(struct armada_thermal_data *data,
0458 unsigned int temp_mc)
0459 {
0460 s64 b = data->coef_b;
0461 s64 m = data->coef_m;
0462 s64 div = data->coef_div;
0463 unsigned int sample;
0464
0465 if (data->inverted)
0466 sample = div_s64(((temp_mc * div) + b), m);
0467 else
0468 sample = div_s64((b - (temp_mc * div)), m);
0469
0470 return sample & data->temp_mask;
0471 }
0472
0473
0474
0475
0476
0477
0478
0479 static unsigned int hyst_levels_mc[] = {1900, 3800, 7600, 15200};
0480
0481 static unsigned int armada_mc_to_reg_hyst(struct armada_thermal_data *data,
0482 unsigned int hyst_mc)
0483 {
0484 int i;
0485
0486
0487
0488
0489
0490
0491 for (i = ARRAY_SIZE(hyst_levels_mc) - 1; i > 0; i--)
0492 if (hyst_mc >= hyst_levels_mc[i])
0493 break;
0494
0495 return i & data->hyst_mask;
0496 }
0497
0498 static void armada_set_overheat_thresholds(struct armada_thermal_priv *priv,
0499 int thresh_mc, int hyst_mc)
0500 {
0501 struct armada_thermal_data *data = priv->data;
0502 unsigned int threshold = armada_mc_to_reg_temp(data, thresh_mc);
0503 unsigned int hysteresis = armada_mc_to_reg_hyst(data, hyst_mc);
0504 u32 ctrl1;
0505
0506 regmap_read(priv->syscon, data->syscon_control1_off, &ctrl1);
0507
0508
0509 if (thresh_mc >= 0) {
0510 ctrl1 &= ~(data->temp_mask << data->thresh_shift);
0511 ctrl1 |= threshold << data->thresh_shift;
0512 priv->current_threshold = thresh_mc;
0513 }
0514
0515
0516 if (hyst_mc >= 0) {
0517 ctrl1 &= ~(data->hyst_mask << data->hyst_shift);
0518 ctrl1 |= hysteresis << data->hyst_shift;
0519 priv->current_hysteresis = hyst_mc;
0520 }
0521
0522 regmap_write(priv->syscon, data->syscon_control1_off, ctrl1);
0523 }
0524
0525 static irqreturn_t armada_overheat_isr(int irq, void *blob)
0526 {
0527
0528
0529
0530
0531 disable_irq_nosync(irq);
0532
0533 return IRQ_WAKE_THREAD;
0534 }
0535
0536 static irqreturn_t armada_overheat_isr_thread(int irq, void *blob)
0537 {
0538 struct armada_thermal_priv *priv = blob;
0539 int low_threshold = priv->current_threshold - priv->current_hysteresis;
0540 int temperature;
0541 u32 dummy;
0542 int ret;
0543
0544
0545 thermal_zone_device_update(priv->overheat_sensor,
0546 THERMAL_EVENT_UNSPECIFIED);
0547
0548
0549
0550
0551
0552
0553 do {
0554 msleep(OVERHEAT_INT_POLL_DELAY_MS);
0555 mutex_lock(&priv->update_lock);
0556 ret = armada_read_sensor(priv, &temperature);
0557 mutex_unlock(&priv->update_lock);
0558 if (ret)
0559 goto enable_irq;
0560 } while (temperature >= low_threshold);
0561
0562 regmap_read(priv->syscon, priv->data->dfx_irq_cause_off, &dummy);
0563
0564
0565 thermal_zone_device_update(priv->overheat_sensor,
0566 THERMAL_EVENT_UNSPECIFIED);
0567
0568 enable_irq:
0569 enable_irq(irq);
0570
0571 return IRQ_HANDLED;
0572 }
0573
0574 static const struct armada_thermal_data armadaxp_data = {
0575 .init = armadaxp_init,
0576 .temp_shift = 10,
0577 .temp_mask = 0x1ff,
0578 .coef_b = 3153000000ULL,
0579 .coef_m = 10000000ULL,
0580 .coef_div = 13825,
0581 .syscon_status_off = 0xb0,
0582 .syscon_control1_off = 0x2d0,
0583 };
0584
0585 static const struct armada_thermal_data armada370_data = {
0586 .init = armada370_init,
0587 .is_valid_bit = BIT(9),
0588 .temp_shift = 10,
0589 .temp_mask = 0x1ff,
0590 .coef_b = 3153000000ULL,
0591 .coef_m = 10000000ULL,
0592 .coef_div = 13825,
0593 .syscon_status_off = 0x0,
0594 .syscon_control1_off = 0x4,
0595 };
0596
0597 static const struct armada_thermal_data armada375_data = {
0598 .init = armada375_init,
0599 .is_valid_bit = BIT(10),
0600 .temp_shift = 0,
0601 .temp_mask = 0x1ff,
0602 .coef_b = 3171900000ULL,
0603 .coef_m = 10000000ULL,
0604 .coef_div = 13616,
0605 .syscon_status_off = 0x78,
0606 .syscon_control0_off = 0x7c,
0607 .syscon_control1_off = 0x80,
0608 };
0609
0610 static const struct armada_thermal_data armada380_data = {
0611 .init = armada380_init,
0612 .is_valid_bit = BIT(10),
0613 .temp_shift = 0,
0614 .temp_mask = 0x3ff,
0615 .coef_b = 1172499100ULL,
0616 .coef_m = 2000096ULL,
0617 .coef_div = 4201,
0618 .inverted = true,
0619 .syscon_control0_off = 0x70,
0620 .syscon_control1_off = 0x74,
0621 .syscon_status_off = 0x78,
0622 };
0623
0624 static const struct armada_thermal_data armada_ap806_data = {
0625 .init = armada_ap806_init,
0626 .is_valid_bit = BIT(16),
0627 .temp_shift = 0,
0628 .temp_mask = 0x3ff,
0629 .thresh_shift = 3,
0630 .hyst_shift = 19,
0631 .hyst_mask = 0x3,
0632 .coef_b = -150000LL,
0633 .coef_m = 423ULL,
0634 .coef_div = 1,
0635 .inverted = true,
0636 .signed_sample = true,
0637 .syscon_control0_off = 0x84,
0638 .syscon_control1_off = 0x88,
0639 .syscon_status_off = 0x8C,
0640 .dfx_irq_cause_off = 0x108,
0641 .dfx_irq_mask_off = 0x10C,
0642 .dfx_overheat_irq = BIT(22),
0643 .dfx_server_irq_mask_off = 0x104,
0644 .dfx_server_irq_en = BIT(1),
0645 .cpu_nr = 4,
0646 };
0647
0648 static const struct armada_thermal_data armada_cp110_data = {
0649 .init = armada_cp110_init,
0650 .is_valid_bit = BIT(10),
0651 .temp_shift = 0,
0652 .temp_mask = 0x3ff,
0653 .thresh_shift = 16,
0654 .hyst_shift = 26,
0655 .hyst_mask = 0x3,
0656 .coef_b = 1172499100ULL,
0657 .coef_m = 2000096ULL,
0658 .coef_div = 4201,
0659 .inverted = true,
0660 .syscon_control0_off = 0x70,
0661 .syscon_control1_off = 0x74,
0662 .syscon_status_off = 0x78,
0663 .dfx_irq_cause_off = 0x108,
0664 .dfx_irq_mask_off = 0x10C,
0665 .dfx_overheat_irq = BIT(20),
0666 .dfx_server_irq_mask_off = 0x104,
0667 .dfx_server_irq_en = BIT(1),
0668 };
0669
0670 static const struct of_device_id armada_thermal_id_table[] = {
0671 {
0672 .compatible = "marvell,armadaxp-thermal",
0673 .data = &armadaxp_data,
0674 },
0675 {
0676 .compatible = "marvell,armada370-thermal",
0677 .data = &armada370_data,
0678 },
0679 {
0680 .compatible = "marvell,armada375-thermal",
0681 .data = &armada375_data,
0682 },
0683 {
0684 .compatible = "marvell,armada380-thermal",
0685 .data = &armada380_data,
0686 },
0687 {
0688 .compatible = "marvell,armada-ap806-thermal",
0689 .data = &armada_ap806_data,
0690 },
0691 {
0692 .compatible = "marvell,armada-cp110-thermal",
0693 .data = &armada_cp110_data,
0694 },
0695 {
0696
0697 },
0698 };
0699 MODULE_DEVICE_TABLE(of, armada_thermal_id_table);
0700
0701 static const struct regmap_config armada_thermal_regmap_config = {
0702 .reg_bits = 32,
0703 .reg_stride = 4,
0704 .val_bits = 32,
0705 .fast_io = true,
0706 };
0707
0708 static int armada_thermal_probe_legacy(struct platform_device *pdev,
0709 struct armada_thermal_priv *priv)
0710 {
0711 struct armada_thermal_data *data = priv->data;
0712 struct resource *res;
0713 void __iomem *base;
0714
0715
0716 res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
0717 base = devm_ioremap_resource(&pdev->dev, res);
0718 if (IS_ERR(base))
0719 return PTR_ERR(base);
0720
0721
0722
0723
0724
0725
0726
0727
0728 if (((unsigned long)base & ~PAGE_MASK) < data->syscon_status_off)
0729 return -EINVAL;
0730 base -= data->syscon_status_off;
0731
0732 priv->syscon = devm_regmap_init_mmio(&pdev->dev, base,
0733 &armada_thermal_regmap_config);
0734 return PTR_ERR_OR_ZERO(priv->syscon);
0735 }
0736
0737 static int armada_thermal_probe_syscon(struct platform_device *pdev,
0738 struct armada_thermal_priv *priv)
0739 {
0740 priv->syscon = syscon_node_to_regmap(pdev->dev.parent->of_node);
0741 return PTR_ERR_OR_ZERO(priv->syscon);
0742 }
0743
0744 static void armada_set_sane_name(struct platform_device *pdev,
0745 struct armada_thermal_priv *priv)
0746 {
0747 const char *name = dev_name(&pdev->dev);
0748 char *insane_char;
0749
0750 if (strlen(name) > THERMAL_NAME_LENGTH) {
0751
0752
0753
0754
0755
0756 name = strrchr(name, ':');
0757 if (!name)
0758 name = "armada_thermal";
0759 else
0760 name++;
0761 }
0762
0763
0764 strncpy(priv->zone_name, name, THERMAL_NAME_LENGTH - 1);
0765 priv->zone_name[THERMAL_NAME_LENGTH - 1] = '\0';
0766
0767
0768 do {
0769 insane_char = strpbrk(priv->zone_name, "-");
0770 if (insane_char)
0771 *insane_char = '_';
0772 } while (insane_char);
0773 }
0774
0775
0776
0777
0778
0779
0780
0781
0782
0783 static int armada_configure_overheat_int(struct armada_thermal_priv *priv,
0784 struct thermal_zone_device *tz,
0785 int sensor_id)
0786 {
0787
0788 const struct thermal_trip *trips = of_thermal_get_trip_points(tz);
0789 int ret;
0790 int i;
0791
0792 if (!trips)
0793 return -EINVAL;
0794
0795 for (i = 0; i < of_thermal_get_ntrips(tz); i++)
0796 if (trips[i].type == THERMAL_TRIP_CRITICAL)
0797 break;
0798
0799 if (i == of_thermal_get_ntrips(tz))
0800 return -EINVAL;
0801
0802 ret = armada_select_channel(priv, sensor_id);
0803 if (ret)
0804 return ret;
0805
0806 armada_set_overheat_thresholds(priv,
0807 trips[i].temperature,
0808 trips[i].hysteresis);
0809 priv->overheat_sensor = tz;
0810 priv->interrupt_source = sensor_id;
0811
0812 armada_enable_overheat_interrupt(priv);
0813
0814 return 0;
0815 }
0816
0817 static int armada_thermal_probe(struct platform_device *pdev)
0818 {
0819 struct thermal_zone_device *tz;
0820 struct armada_thermal_sensor *sensor;
0821 struct armada_drvdata *drvdata;
0822 const struct of_device_id *match;
0823 struct armada_thermal_priv *priv;
0824 int sensor_id, irq;
0825 int ret;
0826
0827 match = of_match_device(armada_thermal_id_table, &pdev->dev);
0828 if (!match)
0829 return -ENODEV;
0830
0831 priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL);
0832 if (!priv)
0833 return -ENOMEM;
0834
0835 drvdata = devm_kzalloc(&pdev->dev, sizeof(*drvdata), GFP_KERNEL);
0836 if (!drvdata)
0837 return -ENOMEM;
0838
0839 priv->dev = &pdev->dev;
0840 priv->data = (struct armada_thermal_data *)match->data;
0841
0842 mutex_init(&priv->update_lock);
0843
0844
0845
0846
0847
0848
0849
0850
0851
0852
0853
0854
0855
0856 if (IS_ERR(syscon_node_to_regmap(pdev->dev.parent->of_node))) {
0857
0858 armada_set_sane_name(pdev, priv);
0859
0860 ret = armada_thermal_probe_legacy(pdev, priv);
0861 if (ret)
0862 return ret;
0863
0864 priv->data->init(pdev, priv);
0865
0866
0867 armada_wait_sensor_validity(priv);
0868
0869 tz = thermal_zone_device_register(priv->zone_name, 0, 0, priv,
0870 &legacy_ops, NULL, 0, 0);
0871 if (IS_ERR(tz)) {
0872 dev_err(&pdev->dev,
0873 "Failed to register thermal zone device\n");
0874 return PTR_ERR(tz);
0875 }
0876
0877 ret = thermal_zone_device_enable(tz);
0878 if (ret) {
0879 thermal_zone_device_unregister(tz);
0880 return ret;
0881 }
0882
0883 drvdata->type = LEGACY;
0884 drvdata->data.tz = tz;
0885 platform_set_drvdata(pdev, drvdata);
0886
0887 return 0;
0888 }
0889
0890 ret = armada_thermal_probe_syscon(pdev, priv);
0891 if (ret)
0892 return ret;
0893
0894 priv->current_channel = -1;
0895 priv->data->init(pdev, priv);
0896 drvdata->type = SYSCON;
0897 drvdata->data.priv = priv;
0898 platform_set_drvdata(pdev, drvdata);
0899
0900 irq = platform_get_irq(pdev, 0);
0901 if (irq == -EPROBE_DEFER)
0902 return irq;
0903
0904
0905 if (irq > 0) {
0906 ret = devm_request_threaded_irq(&pdev->dev, irq,
0907 armada_overheat_isr,
0908 armada_overheat_isr_thread,
0909 0, NULL, priv);
0910 if (ret) {
0911 dev_err(&pdev->dev, "Cannot request threaded IRQ %d\n",
0912 irq);
0913 return ret;
0914 }
0915 }
0916
0917
0918
0919
0920
0921 for (sensor_id = 0; sensor_id <= priv->data->cpu_nr; sensor_id++) {
0922 sensor = devm_kzalloc(&pdev->dev,
0923 sizeof(struct armada_thermal_sensor),
0924 GFP_KERNEL);
0925 if (!sensor)
0926 return -ENOMEM;
0927
0928
0929 sensor->priv = priv;
0930 sensor->id = sensor_id;
0931 tz = devm_thermal_zone_of_sensor_register(&pdev->dev,
0932 sensor->id, sensor,
0933 &of_ops);
0934 if (IS_ERR(tz)) {
0935 dev_info(&pdev->dev, "Thermal sensor %d unavailable\n",
0936 sensor_id);
0937 devm_kfree(&pdev->dev, sensor);
0938 continue;
0939 }
0940
0941
0942
0943
0944
0945
0946 if (irq > 0 && !priv->overheat_sensor)
0947 armada_configure_overheat_int(priv, tz, sensor->id);
0948 }
0949
0950
0951 if (!priv->overheat_sensor)
0952 dev_warn(&pdev->dev, "Overheat interrupt not available\n");
0953
0954 return 0;
0955 }
0956
0957 static int armada_thermal_exit(struct platform_device *pdev)
0958 {
0959 struct armada_drvdata *drvdata = platform_get_drvdata(pdev);
0960
0961 if (drvdata->type == LEGACY)
0962 thermal_zone_device_unregister(drvdata->data.tz);
0963
0964 return 0;
0965 }
0966
0967 static struct platform_driver armada_thermal_driver = {
0968 .probe = armada_thermal_probe,
0969 .remove = armada_thermal_exit,
0970 .driver = {
0971 .name = "armada_thermal",
0972 .of_match_table = armada_thermal_id_table,
0973 },
0974 };
0975
0976 module_platform_driver(armada_thermal_driver);
0977
0978 MODULE_AUTHOR("Ezequiel Garcia <ezequiel.garcia@free-electrons.com>");
0979 MODULE_DESCRIPTION("Marvell EBU Armada SoCs thermal driver");
0980 MODULE_LICENSE("GPL v2");