static int scmi_sensor_axis_description()

in arm_scmi/sensors.c [329:419]


static int scmi_sensor_axis_description(const struct scmi_protocol_handle *ph,
					struct scmi_sensor_info *s)
{
	int ret, cnt;
	u32 desc_index = 0;
	u16 num_returned, num_remaining;
	struct scmi_xfer *te;
	struct scmi_msg_resp_sensor_axis_description *buf;
	struct scmi_msg_sensor_axis_description_get *msg;

	s->axis = devm_kcalloc(ph->dev, s->num_axis,
			       sizeof(*s->axis), GFP_KERNEL);
	if (!s->axis)
		return -ENOMEM;

	ret = ph->xops->xfer_get_init(ph, SENSOR_AXIS_DESCRIPTION_GET,
				      sizeof(*msg), 0, &te);
	if (ret)
		return ret;

	buf = te->rx.buf;
	do {
		u32 flags;
		struct scmi_axis_descriptor *adesc;

		msg = te->tx.buf;
		/* Set the number of sensors to be skipped/already read */
		msg->id = cpu_to_le32(s->id);
		msg->axis_desc_index = cpu_to_le32(desc_index);

		ret = ph->xops->do_xfer(ph, te);
		if (ret)
			break;

		flags = le32_to_cpu(buf->num_axis_flags);
		num_returned = NUM_AXIS_RETURNED(flags);
		num_remaining = NUM_AXIS_REMAINING(flags);

		if (desc_index + num_returned > s->num_axis) {
			dev_err(ph->dev, "No. of axis can't exceed %d\n",
				s->num_axis);
			break;
		}

		adesc = &buf->desc[0];
		for (cnt = 0; cnt < num_returned; cnt++) {
			u32 attrh, attrl;
			struct scmi_sensor_axis_info *a;
			size_t dsize = SCMI_MSG_RESP_AXIS_DESCR_BASE_SZ;

			attrl = le32_to_cpu(adesc->attributes_low);

			a = &s->axis[desc_index + cnt];

			a->id = le32_to_cpu(adesc->id);
			a->extended_attrs = SUPPORTS_EXTEND_ATTRS(attrl);

			attrh = le32_to_cpu(adesc->attributes_high);
			a->scale = S32_EXT(SENSOR_SCALE(attrh));
			a->type = SENSOR_TYPE(attrh);
			strlcpy(a->name, adesc->name, SCMI_MAX_STR_SIZE);

			if (a->extended_attrs) {
				unsigned int ares =
					le32_to_cpu(adesc->resolution);

				a->resolution = SENSOR_RES(ares);
				a->exponent =
					S32_EXT(SENSOR_RES_EXP(ares));
				dsize += sizeof(adesc->resolution);

				scmi_parse_range_attrs(&a->attrs,
						       &adesc->attrs);
				dsize += sizeof(adesc->attrs);
			}

			adesc = (typeof(adesc))((u8 *)adesc + dsize);
		}

		desc_index += num_returned;

		ph->xops->reset_rx_to_maxsz(ph, te);
		/*
		 * check for both returned and remaining to avoid infinite
		 * loop due to buggy firmware
		 */
	} while (num_returned && num_remaining);

	ph->xops->xfer_put(ph, te);
	return ret;
}