in arm_scmi/sensors.c [421:561]
static int scmi_sensor_description_get(const struct scmi_protocol_handle *ph,
struct sensors_info *si)
{
int ret, cnt;
u32 desc_index = 0;
u16 num_returned, num_remaining;
struct scmi_xfer *t;
struct scmi_msg_resp_sensor_description *buf;
ret = ph->xops->xfer_get_init(ph, SENSOR_DESCRIPTION_GET,
sizeof(__le32), 0, &t);
if (ret)
return ret;
buf = t->rx.buf;
do {
struct scmi_sensor_descriptor *sdesc;
/* Set the number of sensors to be skipped/already read */
put_unaligned_le32(desc_index, t->tx.buf);
ret = ph->xops->do_xfer(ph, t);
if (ret)
break;
num_returned = le16_to_cpu(buf->num_returned);
num_remaining = le16_to_cpu(buf->num_remaining);
if (desc_index + num_returned > si->num_sensors) {
dev_err(ph->dev, "No. of sensors can't exceed %d",
si->num_sensors);
break;
}
sdesc = &buf->desc[0];
for (cnt = 0; cnt < num_returned; cnt++) {
u32 attrh, attrl;
struct scmi_sensor_info *s;
size_t dsize = SCMI_MSG_RESP_SENS_DESCR_BASE_SZ;
s = &si->sensors[desc_index + cnt];
s->id = le32_to_cpu(sdesc->id);
attrl = le32_to_cpu(sdesc->attributes_low);
/* common bitfields parsing */
s->async = SUPPORTS_ASYNC_READ(attrl);
s->num_trip_points = NUM_TRIP_POINTS(attrl);
/**
* only SCMIv3.0 specific bitfield below.
* Such bitfields are assumed to be zeroed on non
* relevant fw versions...assuming fw not buggy !
*/
s->update = SUPPORTS_UPDATE_NOTIFY(attrl);
s->timestamped = SUPPORTS_TIMESTAMP(attrl);
if (s->timestamped)
s->tstamp_scale =
S32_EXT(SENSOR_TSTAMP_EXP(attrl));
s->extended_scalar_attrs =
SUPPORTS_EXTEND_ATTRS(attrl);
attrh = le32_to_cpu(sdesc->attributes_high);
/* common bitfields parsing */
s->scale = S32_EXT(SENSOR_SCALE(attrh));
s->type = SENSOR_TYPE(attrh);
/* Use pre-allocated pool wherever possible */
s->intervals.desc = s->intervals.prealloc_pool;
if (si->version == SCMIv2_SENSOR_PROTOCOL) {
s->intervals.segmented = false;
s->intervals.count = 1;
/*
* Convert SCMIv2.0 update interval format to
* SCMIv3.0 to be used as the common exposed
* descriptor, accessible via common macros.
*/
s->intervals.desc[0] =
(SENSOR_UPDATE_BASE(attrh) << 5) |
SENSOR_UPDATE_SCALE(attrh);
} else {
/*
* From SCMIv3.0 update intervals are retrieved
* via a dedicated (optional) command.
* Since the command is optional, on error carry
* on without any update interval.
*/
if (scmi_sensor_update_intervals(ph, s))
dev_dbg(ph->dev,
"Update Intervals not available for sensor ID:%d\n",
s->id);
}
/**
* only > SCMIv2.0 specific bitfield below.
* Such bitfields are assumed to be zeroed on non
* relevant fw versions...assuming fw not buggy !
*/
s->num_axis = min_t(unsigned int,
SUPPORTS_AXIS(attrh) ?
SENSOR_AXIS_NUMBER(attrh) : 0,
SCMI_MAX_NUM_SENSOR_AXIS);
strlcpy(s->name, sdesc->name, SCMI_MAX_STR_SIZE);
if (s->extended_scalar_attrs) {
s->sensor_power = le32_to_cpu(sdesc->power);
dsize += sizeof(sdesc->power);
/* Only for sensors reporting scalar values */
if (s->num_axis == 0) {
unsigned int sres =
le32_to_cpu(sdesc->resolution);
s->resolution = SENSOR_RES(sres);
s->exponent =
S32_EXT(SENSOR_RES_EXP(sres));
dsize += sizeof(sdesc->resolution);
scmi_parse_range_attrs(&s->scalar_attrs,
&sdesc->scalar_attrs);
dsize += sizeof(sdesc->scalar_attrs);
}
}
if (s->num_axis > 0) {
ret = scmi_sensor_axis_description(ph, s);
if (ret)
goto out;
}
sdesc = (typeof(sdesc))((u8 *)sdesc + dsize);
}
desc_index += num_returned;
ph->xops->reset_rx_to_maxsz(ph, t);
/*
* check for both returned and remaining to avoid infinite
* loop due to buggy firmware
*/
} while (num_returned && num_remaining);
out:
ph->xops->xfer_put(ph, t);
return ret;
}