1 // SPDX-License-Identifier: GPL-2.0
3 * System Control and Management Interface (SCMI) Sensor Protocol
5 * Copyright (C) 2018 ARM Ltd.
10 enum scmi_sensor_protocol_cmd
{
11 SENSOR_DESCRIPTION_GET
= 0x3,
12 SENSOR_TRIP_POINT_NOTIFY
= 0x4,
13 SENSOR_TRIP_POINT_CONFIG
= 0x5,
14 SENSOR_READING_GET
= 0x6,
17 struct scmi_msg_resp_sensor_attributes
{
26 struct scmi_msg_resp_sensor_description
{
31 __le32 attributes_low
;
32 #define SUPPORTS_ASYNC_READ(x) ((x) & BIT(31))
33 #define NUM_TRIP_POINTS(x) ((x) & 0xff)
34 __le32 attributes_high
;
35 #define SENSOR_TYPE(x) ((x) & 0xff)
36 #define SENSOR_SCALE(x) (((x) >> 11) & 0x1f)
37 #define SENSOR_SCALE_SIGN BIT(4)
38 #define SENSOR_SCALE_EXTEND GENMASK(7, 5)
39 #define SENSOR_UPDATE_SCALE(x) (((x) >> 22) & 0x1f)
40 #define SENSOR_UPDATE_BASE(x) (((x) >> 27) & 0x1f)
41 u8 name
[SCMI_MAX_STR_SIZE
];
45 struct scmi_msg_sensor_trip_point_notify
{
48 #define SENSOR_TP_NOTIFY_ALL BIT(0)
51 struct scmi_msg_set_sensor_trip_point
{
54 #define SENSOR_TP_EVENT_MASK (0x3)
55 #define SENSOR_TP_DISABLED 0x0
56 #define SENSOR_TP_POSITIVE 0x1
57 #define SENSOR_TP_NEGATIVE 0x2
58 #define SENSOR_TP_BOTH 0x3
59 #define SENSOR_TP_ID(x) (((x) & 0xff) << 4)
64 struct scmi_msg_sensor_reading_get
{
67 #define SENSOR_READ_ASYNC BIT(0)
75 struct scmi_sensor_info
*sensors
;
78 static int scmi_sensor_attributes_get(const struct scmi_handle
*handle
,
79 struct sensors_info
*si
)
83 struct scmi_msg_resp_sensor_attributes
*attr
;
85 ret
= scmi_xfer_get_init(handle
, PROTOCOL_ATTRIBUTES
,
86 SCMI_PROTOCOL_SENSOR
, 0, sizeof(*attr
), &t
);
92 ret
= scmi_do_xfer(handle
, t
);
94 si
->num_sensors
= le16_to_cpu(attr
->num_sensors
);
95 si
->max_requests
= attr
->max_requests
;
96 si
->reg_addr
= le32_to_cpu(attr
->reg_addr_low
) |
97 (u64
)le32_to_cpu(attr
->reg_addr_high
) << 32;
98 si
->reg_size
= le32_to_cpu(attr
->reg_size
);
101 scmi_xfer_put(handle
, t
);
105 static int scmi_sensor_description_get(const struct scmi_handle
*handle
,
106 struct sensors_info
*si
)
110 u16 num_returned
, num_remaining
;
112 struct scmi_msg_resp_sensor_description
*buf
;
114 ret
= scmi_xfer_get_init(handle
, SENSOR_DESCRIPTION_GET
,
115 SCMI_PROTOCOL_SENSOR
, sizeof(__le32
), 0, &t
);
122 /* Set the number of sensors to be skipped/already read */
123 put_unaligned_le32(desc_index
, t
->tx
.buf
);
125 ret
= scmi_do_xfer(handle
, t
);
129 num_returned
= le16_to_cpu(buf
->num_returned
);
130 num_remaining
= le16_to_cpu(buf
->num_remaining
);
132 if (desc_index
+ num_returned
> si
->num_sensors
) {
133 dev_err(handle
->dev
, "No. of sensors can't exceed %d",
138 for (cnt
= 0; cnt
< num_returned
; cnt
++) {
140 struct scmi_sensor_info
*s
;
142 attrl
= le32_to_cpu(buf
->desc
[cnt
].attributes_low
);
143 attrh
= le32_to_cpu(buf
->desc
[cnt
].attributes_high
);
144 s
= &si
->sensors
[desc_index
+ cnt
];
145 s
->id
= le32_to_cpu(buf
->desc
[cnt
].id
);
146 s
->type
= SENSOR_TYPE(attrh
);
147 s
->scale
= SENSOR_SCALE(attrh
);
148 /* Sign extend to a full s8 */
149 if (s
->scale
& SENSOR_SCALE_SIGN
)
150 s
->scale
|= SENSOR_SCALE_EXTEND
;
151 s
->async
= SUPPORTS_ASYNC_READ(attrl
);
152 s
->num_trip_points
= NUM_TRIP_POINTS(attrl
);
153 strlcpy(s
->name
, buf
->desc
[cnt
].name
, SCMI_MAX_STR_SIZE
);
156 desc_index
+= num_returned
;
158 * check for both returned and remaining to avoid infinite
159 * loop due to buggy firmware
161 } while (num_returned
&& num_remaining
);
163 scmi_xfer_put(handle
, t
);
167 static int scmi_sensor_trip_point_notify(const struct scmi_handle
*handle
,
168 u32 sensor_id
, bool enable
)
171 u32 evt_cntl
= enable
? SENSOR_TP_NOTIFY_ALL
: 0;
173 struct scmi_msg_sensor_trip_point_notify
*cfg
;
175 ret
= scmi_xfer_get_init(handle
, SENSOR_TRIP_POINT_NOTIFY
,
176 SCMI_PROTOCOL_SENSOR
, sizeof(*cfg
), 0, &t
);
181 cfg
->id
= cpu_to_le32(sensor_id
);
182 cfg
->event_control
= cpu_to_le32(evt_cntl
);
184 ret
= scmi_do_xfer(handle
, t
);
186 scmi_xfer_put(handle
, t
);
191 scmi_sensor_trip_point_config(const struct scmi_handle
*handle
, u32 sensor_id
,
192 u8 trip_id
, u64 trip_value
)
195 u32 evt_cntl
= SENSOR_TP_BOTH
;
197 struct scmi_msg_set_sensor_trip_point
*trip
;
199 ret
= scmi_xfer_get_init(handle
, SENSOR_TRIP_POINT_CONFIG
,
200 SCMI_PROTOCOL_SENSOR
, sizeof(*trip
), 0, &t
);
205 trip
->id
= cpu_to_le32(sensor_id
);
206 trip
->event_control
= cpu_to_le32(evt_cntl
| SENSOR_TP_ID(trip_id
));
207 trip
->value_low
= cpu_to_le32(trip_value
& 0xffffffff);
208 trip
->value_high
= cpu_to_le32(trip_value
>> 32);
210 ret
= scmi_do_xfer(handle
, t
);
212 scmi_xfer_put(handle
, t
);
216 static int scmi_sensor_reading_get(const struct scmi_handle
*handle
,
217 u32 sensor_id
, u64
*value
)
221 struct scmi_msg_sensor_reading_get
*sensor
;
222 struct sensors_info
*si
= handle
->sensor_priv
;
223 struct scmi_sensor_info
*s
= si
->sensors
+ sensor_id
;
225 ret
= scmi_xfer_get_init(handle
, SENSOR_READING_GET
,
226 SCMI_PROTOCOL_SENSOR
, sizeof(*sensor
),
232 sensor
->id
= cpu_to_le32(sensor_id
);
235 sensor
->flags
= cpu_to_le32(SENSOR_READ_ASYNC
);
236 ret
= scmi_do_xfer_with_response(handle
, t
);
238 *value
= get_unaligned_le64((void *)
239 ((__le32
*)t
->rx
.buf
+ 1));
241 sensor
->flags
= cpu_to_le32(0);
242 ret
= scmi_do_xfer(handle
, t
);
244 *value
= get_unaligned_le64(t
->rx
.buf
);
247 scmi_xfer_put(handle
, t
);
251 static const struct scmi_sensor_info
*
252 scmi_sensor_info_get(const struct scmi_handle
*handle
, u32 sensor_id
)
254 struct sensors_info
*si
= handle
->sensor_priv
;
256 return si
->sensors
+ sensor_id
;
259 static int scmi_sensor_count_get(const struct scmi_handle
*handle
)
261 struct sensors_info
*si
= handle
->sensor_priv
;
263 return si
->num_sensors
;
266 static struct scmi_sensor_ops sensor_ops
= {
267 .count_get
= scmi_sensor_count_get
,
268 .info_get
= scmi_sensor_info_get
,
269 .trip_point_notify
= scmi_sensor_trip_point_notify
,
270 .trip_point_config
= scmi_sensor_trip_point_config
,
271 .reading_get
= scmi_sensor_reading_get
,
274 static int scmi_sensors_protocol_init(struct scmi_handle
*handle
)
277 struct sensors_info
*sinfo
;
279 scmi_version_get(handle
, SCMI_PROTOCOL_SENSOR
, &version
);
281 dev_dbg(handle
->dev
, "Sensor Version %d.%d\n",
282 PROTOCOL_REV_MAJOR(version
), PROTOCOL_REV_MINOR(version
));
284 sinfo
= devm_kzalloc(handle
->dev
, sizeof(*sinfo
), GFP_KERNEL
);
288 scmi_sensor_attributes_get(handle
, sinfo
);
290 sinfo
->sensors
= devm_kcalloc(handle
->dev
, sinfo
->num_sensors
,
291 sizeof(*sinfo
->sensors
), GFP_KERNEL
);
295 scmi_sensor_description_get(handle
, sinfo
);
297 handle
->sensor_ops
= &sensor_ops
;
298 handle
->sensor_priv
= sinfo
;
303 static int __init
scmi_sensors_init(void)
305 return scmi_protocol_register(SCMI_PROTOCOL_SENSOR
,
306 &scmi_sensors_protocol_init
);
308 subsys_initcall(scmi_sensors_init
);