Skip to content

Commit f7c2068

Browse files
miquelraynalEduardo Valentin
authored andcommitted
thermal: armada: add multi-channel sensors support
MVEBU thermal IP supports multiple channels. Each channel may have several sensors but for now each channel is wired to only one thermal sensor. The first channel always points to the so called internal sensor, within the thermal IP. There is usually one more channel (with one sensor each time) per CPU. The code has been written to support possible evolutions of the ap806 IP that would embed more CPUs and thus more channels to select. Each channel should be referenced in the device tree as an independent thermal zone. Add the possibility to read each of these sensors through sysfs by registering all the sensors (translated in "thermal_zone"). Also add a mutex on these accesses to avoid read conflicts (only one channel/sensor may be selected and read at a time). Signed-off-by: Miquel Raynal <miquel.raynal@bootlin.com> Signed-off-by: Eduardo Valentin <edubezval@gmail.com>
1 parent c9899c1 commit f7c2068

File tree

1 file changed

+114
-21
lines changed

1 file changed

+114
-21
lines changed

drivers/thermal/armada_thermal.c

Lines changed: 114 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -49,8 +49,13 @@
4949
#define CONTROL0_TSEN_RESET BIT(1)
5050
#define CONTROL0_TSEN_ENABLE BIT(2)
5151
#define CONTROL0_TSEN_AVG_BYPASS BIT(6)
52+
#define CONTROL0_TSEN_CHAN_SHIFT 13
53+
#define CONTROL0_TSEN_CHAN_MASK 0xF
5254
#define CONTROL0_TSEN_OSR_SHIFT 24
5355
#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
5459

5560
#define CONTROL1_TSEN_AVG_SHIFT 0
5661
#define CONTROL1_TSEN_AVG_MASK 0x7
@@ -67,7 +72,10 @@ struct armada_thermal_priv {
6772
struct device *dev;
6873
struct regmap *syscon;
6974
char zone_name[THERMAL_NAME_LENGTH];
75+
/* serialize temperature reads/updates */
76+
struct mutex update_lock;
7077
struct armada_thermal_data *data;
78+
int current_channel;
7179
};
7280

7381
struct armada_thermal_data {
@@ -94,6 +102,9 @@ struct armada_thermal_data {
94102
unsigned int syscon_control0_off;
95103
unsigned int syscon_control1_off;
96104
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;
97108
};
98109

99110
struct armada_drvdata {
@@ -111,9 +122,11 @@ struct armada_drvdata {
111122
* struct armada_thermal_sensor - hold the information of one thermal sensor
112123
* @thermal: pointer to the local private structure
113124
* @tzd: pointer to the thermal zone device
125+
* @id: identifier of the thermal sensor
114126
*/
115127
struct armada_thermal_sensor {
116128
struct armada_thermal_priv *priv;
129+
int id;
117130
};
118131

119132
static void armadaxp_init(struct platform_device *pdev,
@@ -181,14 +194,15 @@ static void armada375_init(struct platform_device *pdev,
181194
msleep(50);
182195
}
183196

184-
static void armada_wait_sensor_validity(struct armada_thermal_priv *priv)
197+
static int armada_wait_sensor_validity(struct armada_thermal_priv *priv)
185198
{
186199
u32 reg;
187200

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);
192206
}
193207

194208
static void armada380_init(struct platform_device *pdev,
@@ -264,6 +278,58 @@ static bool armada_is_valid(struct armada_thermal_priv *priv)
264278
return reg & priv->data->is_valid_bit;
265279
}
266280

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+
267333
static int armada_read_sensor(struct armada_thermal_priv *priv, int *temp)
268334
{
269335
u32 reg, div;
@@ -317,9 +383,22 @@ static int armada_get_temp(void *_sensor, int *temp)
317383
{
318384
struct armada_thermal_sensor *sensor = _sensor;
319385
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;
320394

321395
/* 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;
323402
}
324403

325404
static struct thermal_zone_of_device_ops of_ops = {
@@ -393,6 +472,7 @@ static const struct armada_thermal_data armada_ap806_data = {
393472
.syscon_control0_off = 0x84,
394473
.syscon_control1_off = 0x88,
395474
.syscon_status_off = 0x8C,
475+
.cpu_nr = 4,
396476
};
397477

398478
static const struct armada_thermal_data armada_cp110_data = {
@@ -526,10 +606,11 @@ static void armada_set_sane_name(struct platform_device *pdev,
526606
static int armada_thermal_probe(struct platform_device *pdev)
527607
{
528608
struct thermal_zone_device *tz;
529-
struct armada_thermal_sensor *sensors;
609+
struct armada_thermal_sensor *sensor;
530610
struct armada_drvdata *drvdata;
531611
const struct of_device_id *match;
532612
struct armada_thermal_priv *priv;
613+
int sensor_id;
533614
int ret;
534615

535616
match = of_match_device(armada_thermal_id_table, &pdev->dev);
@@ -547,6 +628,8 @@ static int armada_thermal_probe(struct platform_device *pdev)
547628
priv->dev = &pdev->dev;
548629
priv->data = (struct armada_thermal_data *)match->data;
549630

631+
mutex_init(&priv->update_lock);
632+
550633
/*
551634
* Legacy DT bindings only described "control1" register (also referred
552635
* as "control MSB" on old documentation). Then, bindings moved to cover
@@ -588,25 +671,35 @@ static int armada_thermal_probe(struct platform_device *pdev)
588671
if (ret)
589672
return ret;
590673

674+
priv->current_channel = -1;
591675
priv->data->init(pdev, priv);
592676
drvdata->type = SYSCON;
593677
drvdata->data.priv = priv;
594678
platform_set_drvdata(pdev, drvdata);
595679

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+
}
610703
}
611704

612705
return 0;

0 commit comments

Comments
 (0)