123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152 |
- // SPDX-License-Identifier: GPL-2.0
- /*
- * System Control and Management Interface (SCMI) Sensor Protocol
- *
- * Copyright (C) 2018-2022 ARM Ltd.
- */
- #define pr_fmt(fmt) "SCMI Notifications SENSOR - " fmt
- #include <linux/bitfield.h>
- #include <linux/module.h>
- #include <linux/scmi_protocol.h>
- #include "protocols.h"
- #include "notify.h"
- #define SCMI_MAX_NUM_SENSOR_AXIS 63
- #define SCMIv2_SENSOR_PROTOCOL 0x10000
- enum scmi_sensor_protocol_cmd {
- SENSOR_DESCRIPTION_GET = 0x3,
- SENSOR_TRIP_POINT_NOTIFY = 0x4,
- SENSOR_TRIP_POINT_CONFIG = 0x5,
- SENSOR_READING_GET = 0x6,
- SENSOR_AXIS_DESCRIPTION_GET = 0x7,
- SENSOR_LIST_UPDATE_INTERVALS = 0x8,
- SENSOR_CONFIG_GET = 0x9,
- SENSOR_CONFIG_SET = 0xA,
- SENSOR_CONTINUOUS_UPDATE_NOTIFY = 0xB,
- SENSOR_NAME_GET = 0xC,
- SENSOR_AXIS_NAME_GET = 0xD,
- };
- struct scmi_msg_resp_sensor_attributes {
- __le16 num_sensors;
- u8 max_requests;
- u8 reserved;
- __le32 reg_addr_low;
- __le32 reg_addr_high;
- __le32 reg_size;
- };
- /* v3 attributes_low macros */
- #define SUPPORTS_UPDATE_NOTIFY(x) FIELD_GET(BIT(30), (x))
- #define SENSOR_TSTAMP_EXP(x) FIELD_GET(GENMASK(14, 10), (x))
- #define SUPPORTS_TIMESTAMP(x) FIELD_GET(BIT(9), (x))
- #define SUPPORTS_EXTEND_ATTRS(x) FIELD_GET(BIT(8), (x))
- /* v2 attributes_high macros */
- #define SENSOR_UPDATE_BASE(x) FIELD_GET(GENMASK(31, 27), (x))
- #define SENSOR_UPDATE_SCALE(x) FIELD_GET(GENMASK(26, 22), (x))
- /* v3 attributes_high macros */
- #define SENSOR_AXIS_NUMBER(x) FIELD_GET(GENMASK(21, 16), (x))
- #define SUPPORTS_AXIS(x) FIELD_GET(BIT(8), (x))
- /* v3 resolution macros */
- #define SENSOR_RES(x) FIELD_GET(GENMASK(26, 0), (x))
- #define SENSOR_RES_EXP(x) FIELD_GET(GENMASK(31, 27), (x))
- struct scmi_msg_resp_attrs {
- __le32 min_range_low;
- __le32 min_range_high;
- __le32 max_range_low;
- __le32 max_range_high;
- };
- struct scmi_msg_sensor_description {
- __le32 desc_index;
- };
- struct scmi_msg_resp_sensor_description {
- __le16 num_returned;
- __le16 num_remaining;
- struct scmi_sensor_descriptor {
- __le32 id;
- __le32 attributes_low;
- /* Common attributes_low macros */
- #define SUPPORTS_ASYNC_READ(x) FIELD_GET(BIT(31), (x))
- #define SUPPORTS_EXTENDED_NAMES(x) FIELD_GET(BIT(29), (x))
- #define NUM_TRIP_POINTS(x) FIELD_GET(GENMASK(7, 0), (x))
- __le32 attributes_high;
- /* Common attributes_high macros */
- #define SENSOR_SCALE(x) FIELD_GET(GENMASK(15, 11), (x))
- #define SENSOR_SCALE_SIGN BIT(4)
- #define SENSOR_SCALE_EXTEND GENMASK(31, 5)
- #define SENSOR_TYPE(x) FIELD_GET(GENMASK(7, 0), (x))
- u8 name[SCMI_SHORT_NAME_MAX_SIZE];
- /* only for version > 2.0 */
- __le32 power;
- __le32 resolution;
- struct scmi_msg_resp_attrs scalar_attrs;
- } desc[];
- };
- /* Base scmi_sensor_descriptor size excluding extended attrs after name */
- #define SCMI_MSG_RESP_SENS_DESCR_BASE_SZ 28
- /* Sign extend to a full s32 */
- #define S32_EXT(v) \
- ({ \
- int __v = (v); \
- \
- if (__v & SENSOR_SCALE_SIGN) \
- __v |= SENSOR_SCALE_EXTEND; \
- __v; \
- })
- struct scmi_msg_sensor_axis_description_get {
- __le32 id;
- __le32 axis_desc_index;
- };
- struct scmi_msg_resp_sensor_axis_description {
- __le32 num_axis_flags;
- #define NUM_AXIS_RETURNED(x) FIELD_GET(GENMASK(5, 0), (x))
- #define NUM_AXIS_REMAINING(x) FIELD_GET(GENMASK(31, 26), (x))
- struct scmi_axis_descriptor {
- __le32 id;
- __le32 attributes_low;
- #define SUPPORTS_EXTENDED_AXIS_NAMES(x) FIELD_GET(BIT(9), (x))
- __le32 attributes_high;
- u8 name[SCMI_SHORT_NAME_MAX_SIZE];
- __le32 resolution;
- struct scmi_msg_resp_attrs attrs;
- } desc[];
- };
- struct scmi_msg_resp_sensor_axis_names_description {
- __le32 num_axis_flags;
- struct scmi_sensor_axis_name_descriptor {
- __le32 axis_id;
- u8 name[SCMI_MAX_STR_SIZE];
- } desc[];
- };
- /* Base scmi_axis_descriptor size excluding extended attrs after name */
- #define SCMI_MSG_RESP_AXIS_DESCR_BASE_SZ 28
- struct scmi_msg_sensor_list_update_intervals {
- __le32 id;
- __le32 index;
- };
- struct scmi_msg_resp_sensor_list_update_intervals {
- __le32 num_intervals_flags;
- #define NUM_INTERVALS_RETURNED(x) FIELD_GET(GENMASK(11, 0), (x))
- #define SEGMENTED_INTVL_FORMAT(x) FIELD_GET(BIT(12), (x))
- #define NUM_INTERVALS_REMAINING(x) FIELD_GET(GENMASK(31, 16), (x))
- __le32 intervals[];
- };
- struct scmi_msg_sensor_request_notify {
- __le32 id;
- __le32 event_control;
- #define SENSOR_NOTIFY_ALL BIT(0)
- };
- struct scmi_msg_set_sensor_trip_point {
- __le32 id;
- __le32 event_control;
- #define SENSOR_TP_EVENT_MASK (0x3)
- #define SENSOR_TP_DISABLED 0x0
- #define SENSOR_TP_POSITIVE 0x1
- #define SENSOR_TP_NEGATIVE 0x2
- #define SENSOR_TP_BOTH 0x3
- #define SENSOR_TP_ID(x) (((x) & 0xff) << 4)
- __le32 value_low;
- __le32 value_high;
- };
- struct scmi_msg_sensor_config_set {
- __le32 id;
- __le32 sensor_config;
- };
- struct scmi_msg_sensor_reading_get {
- __le32 id;
- __le32 flags;
- #define SENSOR_READ_ASYNC BIT(0)
- };
- struct scmi_resp_sensor_reading_complete {
- __le32 id;
- __le32 readings_low;
- __le32 readings_high;
- };
- struct scmi_sensor_reading_resp {
- __le32 sensor_value_low;
- __le32 sensor_value_high;
- __le32 timestamp_low;
- __le32 timestamp_high;
- };
- struct scmi_resp_sensor_reading_complete_v3 {
- __le32 id;
- struct scmi_sensor_reading_resp readings[];
- };
- struct scmi_sensor_trip_notify_payld {
- __le32 agent_id;
- __le32 sensor_id;
- __le32 trip_point_desc;
- };
- struct scmi_sensor_update_notify_payld {
- __le32 agent_id;
- __le32 sensor_id;
- struct scmi_sensor_reading_resp readings[];
- };
- struct sensors_info {
- u32 version;
- int num_sensors;
- int max_requests;
- u64 reg_addr;
- u32 reg_size;
- struct scmi_sensor_info *sensors;
- };
- static int scmi_sensor_attributes_get(const struct scmi_protocol_handle *ph,
- struct sensors_info *si)
- {
- int ret;
- struct scmi_xfer *t;
- struct scmi_msg_resp_sensor_attributes *attr;
- ret = ph->xops->xfer_get_init(ph, PROTOCOL_ATTRIBUTES,
- 0, sizeof(*attr), &t);
- if (ret)
- return ret;
- attr = t->rx.buf;
- ret = ph->xops->do_xfer(ph, t);
- if (!ret) {
- si->num_sensors = le16_to_cpu(attr->num_sensors);
- si->max_requests = attr->max_requests;
- si->reg_addr = le32_to_cpu(attr->reg_addr_low) |
- (u64)le32_to_cpu(attr->reg_addr_high) << 32;
- si->reg_size = le32_to_cpu(attr->reg_size);
- }
- ph->xops->xfer_put(ph, t);
- return ret;
- }
- static inline void scmi_parse_range_attrs(struct scmi_range_attrs *out,
- const struct scmi_msg_resp_attrs *in)
- {
- out->min_range = get_unaligned_le64((void *)&in->min_range_low);
- out->max_range = get_unaligned_le64((void *)&in->max_range_low);
- }
- struct scmi_sens_ipriv {
- void *priv;
- struct device *dev;
- };
- static void iter_intervals_prepare_message(void *message,
- unsigned int desc_index,
- const void *p)
- {
- struct scmi_msg_sensor_list_update_intervals *msg = message;
- const struct scmi_sensor_info *s;
- s = ((const struct scmi_sens_ipriv *)p)->priv;
- /* Set the number of sensors to be skipped/already read */
- msg->id = cpu_to_le32(s->id);
- msg->index = cpu_to_le32(desc_index);
- }
- static int iter_intervals_update_state(struct scmi_iterator_state *st,
- const void *response, void *p)
- {
- u32 flags;
- struct scmi_sensor_info *s = ((struct scmi_sens_ipriv *)p)->priv;
- struct device *dev = ((struct scmi_sens_ipriv *)p)->dev;
- const struct scmi_msg_resp_sensor_list_update_intervals *r = response;
- flags = le32_to_cpu(r->num_intervals_flags);
- st->num_returned = NUM_INTERVALS_RETURNED(flags);
- st->num_remaining = NUM_INTERVALS_REMAINING(flags);
- /*
- * Max intervals is not declared previously anywhere so we
- * assume it's returned+remaining on first call.
- */
- if (!st->max_resources) {
- s->intervals.segmented = SEGMENTED_INTVL_FORMAT(flags);
- s->intervals.count = st->num_returned + st->num_remaining;
- /* segmented intervals are reported in one triplet */
- if (s->intervals.segmented &&
- (st->num_remaining || st->num_returned != 3)) {
- dev_err(dev,
- "Sensor ID:%d advertises an invalid segmented interval (%d)\n",
- s->id, s->intervals.count);
- s->intervals.segmented = false;
- s->intervals.count = 0;
- return -EINVAL;
- }
- /* Direct allocation when exceeding pre-allocated */
- if (s->intervals.count >= SCMI_MAX_PREALLOC_POOL) {
- s->intervals.desc =
- devm_kcalloc(dev,
- s->intervals.count,
- sizeof(*s->intervals.desc),
- GFP_KERNEL);
- if (!s->intervals.desc) {
- s->intervals.segmented = false;
- s->intervals.count = 0;
- return -ENOMEM;
- }
- }
- st->max_resources = s->intervals.count;
- }
- return 0;
- }
- static int
- iter_intervals_process_response(const struct scmi_protocol_handle *ph,
- const void *response,
- struct scmi_iterator_state *st, void *p)
- {
- const struct scmi_msg_resp_sensor_list_update_intervals *r = response;
- struct scmi_sensor_info *s = ((struct scmi_sens_ipriv *)p)->priv;
- s->intervals.desc[st->desc_index + st->loop_idx] =
- le32_to_cpu(r->intervals[st->loop_idx]);
- return 0;
- }
- static int scmi_sensor_update_intervals(const struct scmi_protocol_handle *ph,
- struct scmi_sensor_info *s)
- {
- void *iter;
- struct scmi_iterator_ops ops = {
- .prepare_message = iter_intervals_prepare_message,
- .update_state = iter_intervals_update_state,
- .process_response = iter_intervals_process_response,
- };
- struct scmi_sens_ipriv upriv = {
- .priv = s,
- .dev = ph->dev,
- };
- iter = ph->hops->iter_response_init(ph, &ops, s->intervals.count,
- SENSOR_LIST_UPDATE_INTERVALS,
- sizeof(struct scmi_msg_sensor_list_update_intervals),
- &upriv);
- if (IS_ERR(iter))
- return PTR_ERR(iter);
- return ph->hops->iter_response_run(iter);
- }
- struct scmi_apriv {
- bool any_axes_support_extended_names;
- struct scmi_sensor_info *s;
- };
- static void iter_axes_desc_prepare_message(void *message,
- const unsigned int desc_index,
- const void *priv)
- {
- struct scmi_msg_sensor_axis_description_get *msg = message;
- const struct scmi_apriv *apriv = priv;
- /* Set the number of sensors to be skipped/already read */
- msg->id = cpu_to_le32(apriv->s->id);
- msg->axis_desc_index = cpu_to_le32(desc_index);
- }
- static int
- iter_axes_desc_update_state(struct scmi_iterator_state *st,
- const void *response, void *priv)
- {
- u32 flags;
- const struct scmi_msg_resp_sensor_axis_description *r = response;
- flags = le32_to_cpu(r->num_axis_flags);
- st->num_returned = NUM_AXIS_RETURNED(flags);
- st->num_remaining = NUM_AXIS_REMAINING(flags);
- st->priv = (void *)&r->desc[0];
- return 0;
- }
- static int
- iter_axes_desc_process_response(const struct scmi_protocol_handle *ph,
- const void *response,
- struct scmi_iterator_state *st, void *priv)
- {
- u32 attrh, attrl;
- struct scmi_sensor_axis_info *a;
- size_t dsize = SCMI_MSG_RESP_AXIS_DESCR_BASE_SZ;
- struct scmi_apriv *apriv = priv;
- const struct scmi_axis_descriptor *adesc = st->priv;
- attrl = le32_to_cpu(adesc->attributes_low);
- if (SUPPORTS_EXTENDED_AXIS_NAMES(attrl))
- apriv->any_axes_support_extended_names = true;
- a = &apriv->s->axis[st->desc_index + st->loop_idx];
- 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);
- strscpy(a->name, adesc->name, SCMI_SHORT_NAME_MAX_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);
- }
- st->priv = ((u8 *)adesc + dsize);
- return 0;
- }
- static int
- iter_axes_extended_name_update_state(struct scmi_iterator_state *st,
- const void *response, void *priv)
- {
- u32 flags;
- const struct scmi_msg_resp_sensor_axis_names_description *r = response;
- flags = le32_to_cpu(r->num_axis_flags);
- st->num_returned = NUM_AXIS_RETURNED(flags);
- st->num_remaining = NUM_AXIS_REMAINING(flags);
- st->priv = (void *)&r->desc[0];
- return 0;
- }
- static int
- iter_axes_extended_name_process_response(const struct scmi_protocol_handle *ph,
- const void *response,
- struct scmi_iterator_state *st,
- void *priv)
- {
- struct scmi_sensor_axis_info *a;
- const struct scmi_apriv *apriv = priv;
- struct scmi_sensor_axis_name_descriptor *adesc = st->priv;
- u32 axis_id = le32_to_cpu(adesc->axis_id);
- if (axis_id >= st->max_resources)
- return -EPROTO;
- /*
- * Pick the corresponding descriptor based on the axis_id embedded
- * in the reply since the list of axes supporting extended names
- * can be a subset of all the axes.
- */
- a = &apriv->s->axis[axis_id];
- strscpy(a->name, adesc->name, SCMI_MAX_STR_SIZE);
- st->priv = ++adesc;
- return 0;
- }
- static int
- scmi_sensor_axis_extended_names_get(const struct scmi_protocol_handle *ph,
- struct scmi_sensor_info *s)
- {
- int ret;
- void *iter;
- struct scmi_iterator_ops ops = {
- .prepare_message = iter_axes_desc_prepare_message,
- .update_state = iter_axes_extended_name_update_state,
- .process_response = iter_axes_extended_name_process_response,
- };
- struct scmi_apriv apriv = {
- .any_axes_support_extended_names = false,
- .s = s,
- };
- iter = ph->hops->iter_response_init(ph, &ops, s->num_axis,
- SENSOR_AXIS_NAME_GET,
- sizeof(struct scmi_msg_sensor_axis_description_get),
- &apriv);
- if (IS_ERR(iter))
- return PTR_ERR(iter);
- /*
- * Do not cause whole protocol initialization failure when failing to
- * get extended names for axes.
- */
- ret = ph->hops->iter_response_run(iter);
- if (ret)
- dev_warn(ph->dev,
- "Failed to get axes extended names for %s (ret:%d).\n",
- s->name, ret);
- return 0;
- }
- static int scmi_sensor_axis_description(const struct scmi_protocol_handle *ph,
- struct scmi_sensor_info *s,
- u32 version)
- {
- int ret;
- void *iter;
- struct scmi_iterator_ops ops = {
- .prepare_message = iter_axes_desc_prepare_message,
- .update_state = iter_axes_desc_update_state,
- .process_response = iter_axes_desc_process_response,
- };
- struct scmi_apriv apriv = {
- .any_axes_support_extended_names = false,
- .s = s,
- };
- s->axis = devm_kcalloc(ph->dev, s->num_axis,
- sizeof(*s->axis), GFP_KERNEL);
- if (!s->axis)
- return -ENOMEM;
- iter = ph->hops->iter_response_init(ph, &ops, s->num_axis,
- SENSOR_AXIS_DESCRIPTION_GET,
- sizeof(struct scmi_msg_sensor_axis_description_get),
- &apriv);
- if (IS_ERR(iter))
- return PTR_ERR(iter);
- ret = ph->hops->iter_response_run(iter);
- if (ret)
- return ret;
- if (PROTOCOL_REV_MAJOR(version) >= 0x3 &&
- apriv.any_axes_support_extended_names)
- ret = scmi_sensor_axis_extended_names_get(ph, s);
- return ret;
- }
- static void iter_sens_descr_prepare_message(void *message,
- unsigned int desc_index,
- const void *priv)
- {
- struct scmi_msg_sensor_description *msg = message;
- msg->desc_index = cpu_to_le32(desc_index);
- }
- static int iter_sens_descr_update_state(struct scmi_iterator_state *st,
- const void *response, void *priv)
- {
- const struct scmi_msg_resp_sensor_description *r = response;
- st->num_returned = le16_to_cpu(r->num_returned);
- st->num_remaining = le16_to_cpu(r->num_remaining);
- st->priv = (void *)&r->desc[0];
- return 0;
- }
- static int
- iter_sens_descr_process_response(const struct scmi_protocol_handle *ph,
- const void *response,
- struct scmi_iterator_state *st, void *priv)
- {
- int ret = 0;
- u32 attrh, attrl;
- size_t dsize = SCMI_MSG_RESP_SENS_DESCR_BASE_SZ;
- struct scmi_sensor_info *s;
- struct sensors_info *si = priv;
- const struct scmi_sensor_descriptor *sdesc = st->priv;
- s = &si->sensors[st->desc_index + st->loop_idx];
- 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);
- strscpy(s->name, sdesc->name, SCMI_SHORT_NAME_MAX_SIZE);
- /*
- * If supported overwrite short name with the extended
- * one; on error just carry on and use already provided
- * short name.
- */
- if (PROTOCOL_REV_MAJOR(si->version) >= 0x3 &&
- SUPPORTS_EXTENDED_NAMES(attrl))
- ph->hops->extended_name_get(ph, SENSOR_NAME_GET, s->id,
- s->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, si->version);
- st->priv = ((u8 *)sdesc + dsize);
- return ret;
- }
- static int scmi_sensor_description_get(const struct scmi_protocol_handle *ph,
- struct sensors_info *si)
- {
- void *iter;
- struct scmi_iterator_ops ops = {
- .prepare_message = iter_sens_descr_prepare_message,
- .update_state = iter_sens_descr_update_state,
- .process_response = iter_sens_descr_process_response,
- };
- iter = ph->hops->iter_response_init(ph, &ops, si->num_sensors,
- SENSOR_DESCRIPTION_GET,
- sizeof(__le32), si);
- if (IS_ERR(iter))
- return PTR_ERR(iter);
- return ph->hops->iter_response_run(iter);
- }
- static inline int
- scmi_sensor_request_notify(const struct scmi_protocol_handle *ph, u32 sensor_id,
- u8 message_id, bool enable)
- {
- int ret;
- u32 evt_cntl = enable ? SENSOR_NOTIFY_ALL : 0;
- struct scmi_xfer *t;
- struct scmi_msg_sensor_request_notify *cfg;
- ret = ph->xops->xfer_get_init(ph, message_id, sizeof(*cfg), 0, &t);
- if (ret)
- return ret;
- cfg = t->tx.buf;
- cfg->id = cpu_to_le32(sensor_id);
- cfg->event_control = cpu_to_le32(evt_cntl);
- ret = ph->xops->do_xfer(ph, t);
- ph->xops->xfer_put(ph, t);
- return ret;
- }
- static int scmi_sensor_trip_point_notify(const struct scmi_protocol_handle *ph,
- u32 sensor_id, bool enable)
- {
- return scmi_sensor_request_notify(ph, sensor_id,
- SENSOR_TRIP_POINT_NOTIFY,
- enable);
- }
- static int
- scmi_sensor_continuous_update_notify(const struct scmi_protocol_handle *ph,
- u32 sensor_id, bool enable)
- {
- return scmi_sensor_request_notify(ph, sensor_id,
- SENSOR_CONTINUOUS_UPDATE_NOTIFY,
- enable);
- }
- static int
- scmi_sensor_trip_point_config(const struct scmi_protocol_handle *ph,
- u32 sensor_id, u8 trip_id, u64 trip_value)
- {
- int ret;
- u32 evt_cntl = SENSOR_TP_BOTH;
- struct scmi_xfer *t;
- struct scmi_msg_set_sensor_trip_point *trip;
- ret = ph->xops->xfer_get_init(ph, SENSOR_TRIP_POINT_CONFIG,
- sizeof(*trip), 0, &t);
- if (ret)
- return ret;
- trip = t->tx.buf;
- trip->id = cpu_to_le32(sensor_id);
- trip->event_control = cpu_to_le32(evt_cntl | SENSOR_TP_ID(trip_id));
- trip->value_low = cpu_to_le32(trip_value & 0xffffffff);
- trip->value_high = cpu_to_le32(trip_value >> 32);
- ret = ph->xops->do_xfer(ph, t);
- ph->xops->xfer_put(ph, t);
- return ret;
- }
- static int scmi_sensor_config_get(const struct scmi_protocol_handle *ph,
- u32 sensor_id, u32 *sensor_config)
- {
- int ret;
- struct scmi_xfer *t;
- struct sensors_info *si = ph->get_priv(ph);
- if (sensor_id >= si->num_sensors)
- return -EINVAL;
- ret = ph->xops->xfer_get_init(ph, SENSOR_CONFIG_GET,
- sizeof(__le32), sizeof(__le32), &t);
- if (ret)
- return ret;
- put_unaligned_le32(sensor_id, t->tx.buf);
- ret = ph->xops->do_xfer(ph, t);
- if (!ret) {
- struct scmi_sensor_info *s = si->sensors + sensor_id;
- *sensor_config = get_unaligned_le64(t->rx.buf);
- s->sensor_config = *sensor_config;
- }
- ph->xops->xfer_put(ph, t);
- return ret;
- }
- static int scmi_sensor_config_set(const struct scmi_protocol_handle *ph,
- u32 sensor_id, u32 sensor_config)
- {
- int ret;
- struct scmi_xfer *t;
- struct scmi_msg_sensor_config_set *msg;
- struct sensors_info *si = ph->get_priv(ph);
- if (sensor_id >= si->num_sensors)
- return -EINVAL;
- ret = ph->xops->xfer_get_init(ph, SENSOR_CONFIG_SET,
- sizeof(*msg), 0, &t);
- if (ret)
- return ret;
- msg = t->tx.buf;
- msg->id = cpu_to_le32(sensor_id);
- msg->sensor_config = cpu_to_le32(sensor_config);
- ret = ph->xops->do_xfer(ph, t);
- if (!ret) {
- struct scmi_sensor_info *s = si->sensors + sensor_id;
- s->sensor_config = sensor_config;
- }
- ph->xops->xfer_put(ph, t);
- return ret;
- }
- /**
- * scmi_sensor_reading_get - Read scalar sensor value
- * @ph: Protocol handle
- * @sensor_id: Sensor ID
- * @value: The 64bit value sensor reading
- *
- * This function returns a single 64 bit reading value representing the sensor
- * value; if the platform SCMI Protocol implementation and the sensor support
- * multiple axis and timestamped-reads, this just returns the first axis while
- * dropping the timestamp value.
- * Use instead the @scmi_sensor_reading_get_timestamped to retrieve the array of
- * timestamped multi-axis values.
- *
- * Return: 0 on Success
- */
- static int scmi_sensor_reading_get(const struct scmi_protocol_handle *ph,
- u32 sensor_id, u64 *value)
- {
- int ret;
- struct scmi_xfer *t;
- struct scmi_msg_sensor_reading_get *sensor;
- struct scmi_sensor_info *s;
- struct sensors_info *si = ph->get_priv(ph);
- if (sensor_id >= si->num_sensors)
- return -EINVAL;
- ret = ph->xops->xfer_get_init(ph, SENSOR_READING_GET,
- sizeof(*sensor), 0, &t);
- if (ret)
- return ret;
- sensor = t->tx.buf;
- sensor->id = cpu_to_le32(sensor_id);
- s = si->sensors + sensor_id;
- if (s->async) {
- sensor->flags = cpu_to_le32(SENSOR_READ_ASYNC);
- ret = ph->xops->do_xfer_with_response(ph, t);
- if (!ret) {
- struct scmi_resp_sensor_reading_complete *resp;
- resp = t->rx.buf;
- if (le32_to_cpu(resp->id) == sensor_id)
- *value =
- get_unaligned_le64(&resp->readings_low);
- else
- ret = -EPROTO;
- }
- } else {
- sensor->flags = cpu_to_le32(0);
- ret = ph->xops->do_xfer(ph, t);
- if (!ret)
- *value = get_unaligned_le64(t->rx.buf);
- }
- ph->xops->xfer_put(ph, t);
- return ret;
- }
- static inline void
- scmi_parse_sensor_readings(struct scmi_sensor_reading *out,
- const struct scmi_sensor_reading_resp *in)
- {
- out->value = get_unaligned_le64((void *)&in->sensor_value_low);
- out->timestamp = get_unaligned_le64((void *)&in->timestamp_low);
- }
- /**
- * scmi_sensor_reading_get_timestamped - Read multiple-axis timestamped values
- * @ph: Protocol handle
- * @sensor_id: Sensor ID
- * @count: The length of the provided @readings array
- * @readings: An array of elements each representing a timestamped per-axis
- * reading of type @struct scmi_sensor_reading.
- * Returned readings are ordered as the @axis descriptors array
- * included in @struct scmi_sensor_info and the max number of
- * returned elements is min(@count, @num_axis); ideally the provided
- * array should be of length @count equal to @num_axis.
- *
- * Return: 0 on Success
- */
- static int
- scmi_sensor_reading_get_timestamped(const struct scmi_protocol_handle *ph,
- u32 sensor_id, u8 count,
- struct scmi_sensor_reading *readings)
- {
- int ret;
- struct scmi_xfer *t;
- struct scmi_msg_sensor_reading_get *sensor;
- struct scmi_sensor_info *s;
- struct sensors_info *si = ph->get_priv(ph);
- if (sensor_id >= si->num_sensors)
- return -EINVAL;
- s = si->sensors + sensor_id;
- if (!count || !readings ||
- (!s->num_axis && count > 1) || (s->num_axis && count > s->num_axis))
- return -EINVAL;
- ret = ph->xops->xfer_get_init(ph, SENSOR_READING_GET,
- sizeof(*sensor), 0, &t);
- if (ret)
- return ret;
- sensor = t->tx.buf;
- sensor->id = cpu_to_le32(sensor_id);
- if (s->async) {
- sensor->flags = cpu_to_le32(SENSOR_READ_ASYNC);
- ret = ph->xops->do_xfer_with_response(ph, t);
- if (!ret) {
- int i;
- struct scmi_resp_sensor_reading_complete_v3 *resp;
- resp = t->rx.buf;
- /* Retrieve only the number of requested axis anyway */
- if (le32_to_cpu(resp->id) == sensor_id)
- for (i = 0; i < count; i++)
- scmi_parse_sensor_readings(&readings[i],
- &resp->readings[i]);
- else
- ret = -EPROTO;
- }
- } else {
- sensor->flags = cpu_to_le32(0);
- ret = ph->xops->do_xfer(ph, t);
- if (!ret) {
- int i;
- struct scmi_sensor_reading_resp *resp_readings;
- resp_readings = t->rx.buf;
- for (i = 0; i < count; i++)
- scmi_parse_sensor_readings(&readings[i],
- &resp_readings[i]);
- }
- }
- ph->xops->xfer_put(ph, t);
- return ret;
- }
- static const struct scmi_sensor_info *
- scmi_sensor_info_get(const struct scmi_protocol_handle *ph, u32 sensor_id)
- {
- struct sensors_info *si = ph->get_priv(ph);
- if (sensor_id >= si->num_sensors)
- return NULL;
- return si->sensors + sensor_id;
- }
- static int scmi_sensor_count_get(const struct scmi_protocol_handle *ph)
- {
- struct sensors_info *si = ph->get_priv(ph);
- return si->num_sensors;
- }
- static const struct scmi_sensor_proto_ops sensor_proto_ops = {
- .count_get = scmi_sensor_count_get,
- .info_get = scmi_sensor_info_get,
- .trip_point_config = scmi_sensor_trip_point_config,
- .reading_get = scmi_sensor_reading_get,
- .reading_get_timestamped = scmi_sensor_reading_get_timestamped,
- .config_get = scmi_sensor_config_get,
- .config_set = scmi_sensor_config_set,
- };
- static int scmi_sensor_set_notify_enabled(const struct scmi_protocol_handle *ph,
- u8 evt_id, u32 src_id, bool enable)
- {
- int ret;
- switch (evt_id) {
- case SCMI_EVENT_SENSOR_TRIP_POINT_EVENT:
- ret = scmi_sensor_trip_point_notify(ph, src_id, enable);
- break;
- case SCMI_EVENT_SENSOR_UPDATE:
- ret = scmi_sensor_continuous_update_notify(ph, src_id, enable);
- break;
- default:
- ret = -EINVAL;
- break;
- }
- if (ret)
- pr_debug("FAIL_ENABLED - evt[%X] dom[%d] - ret:%d\n",
- evt_id, src_id, ret);
- return ret;
- }
- static void *
- scmi_sensor_fill_custom_report(const struct scmi_protocol_handle *ph,
- u8 evt_id, ktime_t timestamp,
- const void *payld, size_t payld_sz,
- void *report, u32 *src_id)
- {
- void *rep = NULL;
- switch (evt_id) {
- case SCMI_EVENT_SENSOR_TRIP_POINT_EVENT:
- {
- const struct scmi_sensor_trip_notify_payld *p = payld;
- struct scmi_sensor_trip_point_report *r = report;
- if (sizeof(*p) != payld_sz)
- break;
- r->timestamp = timestamp;
- r->agent_id = le32_to_cpu(p->agent_id);
- r->sensor_id = le32_to_cpu(p->sensor_id);
- r->trip_point_desc = le32_to_cpu(p->trip_point_desc);
- *src_id = r->sensor_id;
- rep = r;
- break;
- }
- case SCMI_EVENT_SENSOR_UPDATE:
- {
- int i;
- struct scmi_sensor_info *s;
- const struct scmi_sensor_update_notify_payld *p = payld;
- struct scmi_sensor_update_report *r = report;
- struct sensors_info *sinfo = ph->get_priv(ph);
- /* payld_sz is variable for this event */
- r->sensor_id = le32_to_cpu(p->sensor_id);
- if (r->sensor_id >= sinfo->num_sensors)
- break;
- r->timestamp = timestamp;
- r->agent_id = le32_to_cpu(p->agent_id);
- s = &sinfo->sensors[r->sensor_id];
- /*
- * The generated report r (@struct scmi_sensor_update_report)
- * was pre-allocated to contain up to SCMI_MAX_NUM_SENSOR_AXIS
- * readings: here it is filled with the effective @num_axis
- * readings defined for this sensor or 1 for scalar sensors.
- */
- r->readings_count = s->num_axis ?: 1;
- for (i = 0; i < r->readings_count; i++)
- scmi_parse_sensor_readings(&r->readings[i],
- &p->readings[i]);
- *src_id = r->sensor_id;
- rep = r;
- break;
- }
- default:
- break;
- }
- return rep;
- }
- static int scmi_sensor_get_num_sources(const struct scmi_protocol_handle *ph)
- {
- struct sensors_info *si = ph->get_priv(ph);
- return si->num_sensors;
- }
- static const struct scmi_event sensor_events[] = {
- {
- .id = SCMI_EVENT_SENSOR_TRIP_POINT_EVENT,
- .max_payld_sz = sizeof(struct scmi_sensor_trip_notify_payld),
- .max_report_sz = sizeof(struct scmi_sensor_trip_point_report),
- },
- {
- .id = SCMI_EVENT_SENSOR_UPDATE,
- .max_payld_sz =
- sizeof(struct scmi_sensor_update_notify_payld) +
- SCMI_MAX_NUM_SENSOR_AXIS *
- sizeof(struct scmi_sensor_reading_resp),
- .max_report_sz = sizeof(struct scmi_sensor_update_report) +
- SCMI_MAX_NUM_SENSOR_AXIS *
- sizeof(struct scmi_sensor_reading),
- },
- };
- static const struct scmi_event_ops sensor_event_ops = {
- .get_num_sources = scmi_sensor_get_num_sources,
- .set_notify_enabled = scmi_sensor_set_notify_enabled,
- .fill_custom_report = scmi_sensor_fill_custom_report,
- };
- static const struct scmi_protocol_events sensor_protocol_events = {
- .queue_sz = SCMI_PROTO_QUEUE_SZ,
- .ops = &sensor_event_ops,
- .evts = sensor_events,
- .num_events = ARRAY_SIZE(sensor_events),
- };
- static int scmi_sensors_protocol_init(const struct scmi_protocol_handle *ph)
- {
- u32 version;
- int ret;
- struct sensors_info *sinfo;
- ret = ph->xops->version_get(ph, &version);
- if (ret)
- return ret;
- dev_dbg(ph->dev, "Sensor Version %d.%d\n",
- PROTOCOL_REV_MAJOR(version), PROTOCOL_REV_MINOR(version));
- sinfo = devm_kzalloc(ph->dev, sizeof(*sinfo), GFP_KERNEL);
- if (!sinfo)
- return -ENOMEM;
- sinfo->version = version;
- ret = scmi_sensor_attributes_get(ph, sinfo);
- if (ret)
- return ret;
- sinfo->sensors = devm_kcalloc(ph->dev, sinfo->num_sensors,
- sizeof(*sinfo->sensors), GFP_KERNEL);
- if (!sinfo->sensors)
- return -ENOMEM;
- ret = scmi_sensor_description_get(ph, sinfo);
- if (ret)
- return ret;
- return ph->set_priv(ph, sinfo);
- }
- static const struct scmi_protocol scmi_sensors = {
- .id = SCMI_PROTOCOL_SENSOR,
- .owner = THIS_MODULE,
- .instance_init = &scmi_sensors_protocol_init,
- .ops = &sensor_proto_ops,
- .events = &sensor_protocol_events,
- };
- DEFINE_SCMI_PROTOCOL_REGISTER_UNREGISTER(sensors, scmi_sensors)
|