49
49
#define CONTROL0_TSEN_RESET BIT(1)
50
50
#define CONTROL0_TSEN_ENABLE BIT(2)
51
51
#define CONTROL0_TSEN_AVG_BYPASS BIT(6)
52
+ #define CONTROL0_TSEN_CHAN_SHIFT 13
53
+ #define CONTROL0_TSEN_CHAN_MASK 0xF
52
54
#define CONTROL0_TSEN_OSR_SHIFT 24
53
55
#define CONTROL0_TSEN_OSR_MAX 0x3
56
+ #define CONTROL0_TSEN_MODE_SHIFT 30
57
+ #define CONTROL0_TSEN_MODE_EXTERNAL 0x2
58
+ #define CONTROL0_TSEN_MODE_MASK 0x3
54
59
55
60
#define CONTROL1_TSEN_AVG_SHIFT 0
56
61
#define CONTROL1_TSEN_AVG_MASK 0x7
@@ -67,7 +72,10 @@ struct armada_thermal_priv {
67
72
struct device * dev ;
68
73
struct regmap * syscon ;
69
74
char zone_name [THERMAL_NAME_LENGTH ];
75
+ /* serialize temperature reads/updates */
76
+ struct mutex update_lock ;
70
77
struct armada_thermal_data * data ;
78
+ int current_channel ;
71
79
};
72
80
73
81
struct armada_thermal_data {
@@ -94,6 +102,9 @@ struct armada_thermal_data {
94
102
unsigned int syscon_control0_off ;
95
103
unsigned int syscon_control1_off ;
96
104
unsigned int syscon_status_off ;
105
+
106
+ /* One sensor is in the thermal IC, the others are in the CPUs if any */
107
+ unsigned int cpu_nr ;
97
108
};
98
109
99
110
struct armada_drvdata {
@@ -111,9 +122,11 @@ struct armada_drvdata {
111
122
* struct armada_thermal_sensor - hold the information of one thermal sensor
112
123
* @thermal: pointer to the local private structure
113
124
* @tzd: pointer to the thermal zone device
125
+ * @id: identifier of the thermal sensor
114
126
*/
115
127
struct armada_thermal_sensor {
116
128
struct armada_thermal_priv * priv ;
129
+ int id ;
117
130
};
118
131
119
132
static void armadaxp_init (struct platform_device * pdev ,
@@ -181,14 +194,15 @@ static void armada375_init(struct platform_device *pdev,
181
194
msleep (50 );
182
195
}
183
196
184
- static void armada_wait_sensor_validity (struct armada_thermal_priv * priv )
197
+ static int armada_wait_sensor_validity (struct armada_thermal_priv * priv )
185
198
{
186
199
u32 reg ;
187
200
188
- regmap_read_poll_timeout (priv -> syscon , priv -> data -> syscon_status_off ,
189
- reg , reg & priv -> data -> is_valid_bit ,
190
- STATUS_POLL_PERIOD_US ,
191
- STATUS_POLL_TIMEOUT_US );
201
+ return regmap_read_poll_timeout (priv -> syscon ,
202
+ priv -> data -> syscon_status_off , reg ,
203
+ reg & priv -> data -> is_valid_bit ,
204
+ STATUS_POLL_PERIOD_US ,
205
+ STATUS_POLL_TIMEOUT_US );
192
206
}
193
207
194
208
static void armada380_init (struct platform_device * pdev ,
@@ -264,6 +278,58 @@ static bool armada_is_valid(struct armada_thermal_priv *priv)
264
278
return reg & priv -> data -> is_valid_bit ;
265
279
}
266
280
281
+ /* There is currently no board with more than one sensor per channel */
282
+ static int armada_select_channel (struct armada_thermal_priv * priv , int channel )
283
+ {
284
+ struct armada_thermal_data * data = priv -> data ;
285
+ u32 ctrl0 ;
286
+
287
+ if (channel < 0 || channel > priv -> data -> cpu_nr )
288
+ return - EINVAL ;
289
+
290
+ if (priv -> current_channel == channel )
291
+ return 0 ;
292
+
293
+ /* Stop the measurements */
294
+ regmap_read (priv -> syscon , data -> syscon_control0_off , & ctrl0 );
295
+ ctrl0 &= ~CONTROL0_TSEN_START ;
296
+ regmap_write (priv -> syscon , data -> syscon_control0_off , ctrl0 );
297
+
298
+ /* Reset the mode, internal sensor will be automatically selected */
299
+ ctrl0 &= ~(CONTROL0_TSEN_MODE_MASK << CONTROL0_TSEN_MODE_SHIFT );
300
+
301
+ /* Other channels are external and should be selected accordingly */
302
+ if (channel ) {
303
+ /* Change the mode to external */
304
+ ctrl0 |= CONTROL0_TSEN_MODE_EXTERNAL <<
305
+ CONTROL0_TSEN_MODE_SHIFT ;
306
+ /* Select the sensor */
307
+ ctrl0 &= ~(CONTROL0_TSEN_CHAN_MASK << CONTROL0_TSEN_CHAN_SHIFT );
308
+ ctrl0 |= (channel - 1 ) << CONTROL0_TSEN_CHAN_SHIFT ;
309
+ }
310
+
311
+ /* Actually set the mode/channel */
312
+ regmap_write (priv -> syscon , data -> syscon_control0_off , ctrl0 );
313
+ priv -> current_channel = channel ;
314
+
315
+ /* Re-start the measurements */
316
+ ctrl0 |= CONTROL0_TSEN_START ;
317
+ regmap_write (priv -> syscon , data -> syscon_control0_off , ctrl0 );
318
+
319
+ /*
320
+ * The IP has a latency of ~15ms, so after updating the selected source,
321
+ * we must absolutely wait for the sensor validity bit to ensure we read
322
+ * actual data.
323
+ */
324
+ if (armada_wait_sensor_validity (priv )) {
325
+ dev_err (priv -> dev ,
326
+ "Temperature sensor reading not valid\n" );
327
+ return - EIO ;
328
+ }
329
+
330
+ return 0 ;
331
+ }
332
+
267
333
static int armada_read_sensor (struct armada_thermal_priv * priv , int * temp )
268
334
{
269
335
u32 reg , div ;
@@ -317,9 +383,22 @@ static int armada_get_temp(void *_sensor, int *temp)
317
383
{
318
384
struct armada_thermal_sensor * sensor = _sensor ;
319
385
struct armada_thermal_priv * priv = sensor -> priv ;
386
+ int ret ;
387
+
388
+ mutex_lock (& priv -> update_lock );
389
+
390
+ /* Select the desired channel */
391
+ ret = armada_select_channel (priv , sensor -> id );
392
+ if (ret )
393
+ goto unlock_mutex ;
320
394
321
395
/* Do the actual reading */
322
- return armada_read_sensor (priv , temp );
396
+ ret = armada_read_sensor (priv , temp );
397
+
398
+ unlock_mutex :
399
+ mutex_unlock (& priv -> update_lock );
400
+
401
+ return ret ;
323
402
}
324
403
325
404
static struct thermal_zone_of_device_ops of_ops = {
@@ -393,6 +472,7 @@ static const struct armada_thermal_data armada_ap806_data = {
393
472
.syscon_control0_off = 0x84 ,
394
473
.syscon_control1_off = 0x88 ,
395
474
.syscon_status_off = 0x8C ,
475
+ .cpu_nr = 4 ,
396
476
};
397
477
398
478
static const struct armada_thermal_data armada_cp110_data = {
@@ -526,10 +606,11 @@ static void armada_set_sane_name(struct platform_device *pdev,
526
606
static int armada_thermal_probe (struct platform_device * pdev )
527
607
{
528
608
struct thermal_zone_device * tz ;
529
- struct armada_thermal_sensor * sensors ;
609
+ struct armada_thermal_sensor * sensor ;
530
610
struct armada_drvdata * drvdata ;
531
611
const struct of_device_id * match ;
532
612
struct armada_thermal_priv * priv ;
613
+ int sensor_id ;
533
614
int ret ;
534
615
535
616
match = of_match_device (armada_thermal_id_table , & pdev -> dev );
@@ -547,6 +628,8 @@ static int armada_thermal_probe(struct platform_device *pdev)
547
628
priv -> dev = & pdev -> dev ;
548
629
priv -> data = (struct armada_thermal_data * )match -> data ;
549
630
631
+ mutex_init (& priv -> update_lock );
632
+
550
633
/*
551
634
* Legacy DT bindings only described "control1" register (also referred
552
635
* as "control MSB" on old documentation). Then, bindings moved to cover
@@ -588,25 +671,35 @@ static int armada_thermal_probe(struct platform_device *pdev)
588
671
if (ret )
589
672
return ret ;
590
673
674
+ priv -> current_channel = -1 ;
591
675
priv -> data -> init (pdev , priv );
592
676
drvdata -> type = SYSCON ;
593
677
drvdata -> data .priv = priv ;
594
678
platform_set_drvdata (pdev , drvdata );
595
679
596
- sensors = devm_kzalloc (& pdev -> dev , sizeof (struct armada_thermal_sensor ),
597
- GFP_KERNEL );
598
- if (!sensors )
599
- return - ENOMEM ;
600
-
601
- sensors -> priv = priv ;
602
-
603
- tz = devm_thermal_zone_of_sensor_register (& pdev -> dev , 0 , sensors ,
604
- & of_ops );
605
- if (IS_ERR (tz )) {
606
- dev_err (& pdev -> dev ,
607
- "Failed to register thermal sensor (err: %ld)\n" ,
608
- PTR_ERR (tz ));
609
- return PTR_ERR (tz );
680
+ /*
681
+ * There is one channel for the IC and one per CPU (if any), each
682
+ * channel has one sensor.
683
+ */
684
+ for (sensor_id = 0 ; sensor_id <= priv -> data -> cpu_nr ; sensor_id ++ ) {
685
+ sensor = devm_kzalloc (& pdev -> dev ,
686
+ sizeof (struct armada_thermal_sensor ),
687
+ GFP_KERNEL );
688
+ if (!sensor )
689
+ return - ENOMEM ;
690
+
691
+ /* Register the sensor */
692
+ sensor -> priv = priv ;
693
+ sensor -> id = sensor_id ;
694
+ tz = devm_thermal_zone_of_sensor_register (& pdev -> dev ,
695
+ sensor -> id , sensor ,
696
+ & of_ops );
697
+ if (IS_ERR (tz )) {
698
+ dev_info (& pdev -> dev , "Thermal sensor %d unavailable\n" ,
699
+ sensor_id );
700
+ devm_kfree (& pdev -> dev , sensor );
701
+ continue ;
702
+ }
610
703
}
611
704
612
705
return 0 ;
0 commit comments