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)
76 struct scmi_sensor_info
*sensors
;
79 static int scmi_sensor_attributes_get(const struct scmi_handle
*handle
,
80 struct sensors_info
*si
)
84 struct scmi_msg_resp_sensor_attributes
*attr
;
86 ret
= scmi_xfer_get_init(handle
, PROTOCOL_ATTRIBUTES
,
87 SCMI_PROTOCOL_SENSOR
, 0, sizeof(*attr
), &t
);
93 ret
= scmi_do_xfer(handle
, t
);
95 si
->num_sensors
= le16_to_cpu(attr
->num_sensors
);
96 si
->max_requests
= attr
->max_requests
;
97 si
->reg_addr
= le32_to_cpu(attr
->reg_addr_low
) |
98 (u64
)le32_to_cpu(attr
->reg_addr_high
) << 32;
99 si
->reg_size
= le32_to_cpu(attr
->reg_size
);
102 scmi_xfer_put(handle
, t
);
106 static int scmi_sensor_description_get(const struct scmi_handle
*handle
,
107 struct sensors_info
*si
)
111 u16 num_returned
, num_remaining
;
113 struct scmi_msg_resp_sensor_description
*buf
;
115 ret
= scmi_xfer_get_init(handle
, SENSOR_DESCRIPTION_GET
,
116 SCMI_PROTOCOL_SENSOR
, sizeof(__le32
), 0, &t
);
123 /* Set the number of sensors to be skipped/already read */
124 put_unaligned_le32(desc_index
, t
->tx
.buf
);
126 ret
= scmi_do_xfer(handle
, t
);
130 num_returned
= le16_to_cpu(buf
->num_returned
);
131 num_remaining
= le16_to_cpu(buf
->num_remaining
);
133 if (desc_index
+ num_returned
> si
->num_sensors
) {
134 dev_err(handle
->dev
, "No. of sensors can't exceed %d",
139 for (cnt
= 0; cnt
< num_returned
; cnt
++) {
141 struct scmi_sensor_info
*s
;
143 attrl
= le32_to_cpu(buf
->desc
[cnt
].attributes_low
);
144 attrh
= le32_to_cpu(buf
->desc
[cnt
].attributes_high
);
145 s
= &si
->sensors
[desc_index
+ cnt
];
146 s
->id
= le32_to_cpu(buf
->desc
[cnt
].id
);
147 s
->type
= SENSOR_TYPE(attrh
);
148 s
->scale
= SENSOR_SCALE(attrh
);
149 /* Sign extend to a full s8 */
150 if (s
->scale
& SENSOR_SCALE_SIGN
)
151 s
->scale
|= SENSOR_SCALE_EXTEND
;
152 s
->async
= SUPPORTS_ASYNC_READ(attrl
);
153 s
->num_trip_points
= NUM_TRIP_POINTS(attrl
);
154 strlcpy(s
->name
, buf
->desc
[cnt
].name
, SCMI_MAX_STR_SIZE
);
157 desc_index
+= num_returned
;
159 * check for both returned and remaining to avoid infinite
160 * loop due to buggy firmware
162 } while (num_returned
&& num_remaining
);
164 scmi_xfer_put(handle
, t
);
168 static int scmi_sensor_trip_point_notify(const struct scmi_handle
*handle
,
169 u32 sensor_id
, bool enable
)
172 u32 evt_cntl
= enable
? SENSOR_TP_NOTIFY_ALL
: 0;
174 struct scmi_msg_sensor_trip_point_notify
*cfg
;
176 ret
= scmi_xfer_get_init(handle
, SENSOR_TRIP_POINT_NOTIFY
,
177 SCMI_PROTOCOL_SENSOR
, sizeof(*cfg
), 0, &t
);
182 cfg
->id
= cpu_to_le32(sensor_id
);
183 cfg
->event_control
= cpu_to_le32(evt_cntl
);
185 ret
= scmi_do_xfer(handle
, t
);
187 scmi_xfer_put(handle
, t
);
192 scmi_sensor_trip_point_config(const struct scmi_handle
*handle
, u32 sensor_id
,
193 u8 trip_id
, u64 trip_value
)
196 u32 evt_cntl
= SENSOR_TP_BOTH
;
198 struct scmi_msg_set_sensor_trip_point
*trip
;
200 ret
= scmi_xfer_get_init(handle
, SENSOR_TRIP_POINT_CONFIG
,
201 SCMI_PROTOCOL_SENSOR
, sizeof(*trip
), 0, &t
);
206 trip
->id
= cpu_to_le32(sensor_id
);
207 trip
->event_control
= cpu_to_le32(evt_cntl
| SENSOR_TP_ID(trip_id
));
208 trip
->value_low
= cpu_to_le32(trip_value
& 0xffffffff);
209 trip
->value_high
= cpu_to_le32(trip_value
>> 32);
211 ret
= scmi_do_xfer(handle
, t
);
213 scmi_xfer_put(handle
, t
);
217 static int scmi_sensor_reading_get(const struct scmi_handle
*handle
,
218 u32 sensor_id
, u64
*value
)
222 struct scmi_msg_sensor_reading_get
*sensor
;
223 struct sensors_info
*si
= handle
->sensor_priv
;
224 struct scmi_sensor_info
*s
= si
->sensors
+ sensor_id
;
226 ret
= scmi_xfer_get_init(handle
, SENSOR_READING_GET
,
227 SCMI_PROTOCOL_SENSOR
, sizeof(*sensor
),
233 sensor
->id
= cpu_to_le32(sensor_id
);
236 sensor
->flags
= cpu_to_le32(SENSOR_READ_ASYNC
);
237 ret
= scmi_do_xfer_with_response(handle
, t
);
239 *value
= get_unaligned_le64((void *)
240 ((__le32
*)t
->rx
.buf
+ 1));
242 sensor
->flags
= cpu_to_le32(0);
243 ret
= scmi_do_xfer(handle
, t
);
245 *value
= get_unaligned_le64(t
->rx
.buf
);
248 scmi_xfer_put(handle
, t
);
252 static const struct scmi_sensor_info
*
253 scmi_sensor_info_get(const struct scmi_handle
*handle
, u32 sensor_id
)
255 struct sensors_info
*si
= handle
->sensor_priv
;
257 return si
->sensors
+ sensor_id
;
260 static int scmi_sensor_count_get(const struct scmi_handle
*handle
)
262 struct sensors_info
*si
= handle
->sensor_priv
;
264 return si
->num_sensors
;
267 static struct scmi_sensor_ops sensor_ops
= {
268 .count_get
= scmi_sensor_count_get
,
269 .info_get
= scmi_sensor_info_get
,
270 .trip_point_notify
= scmi_sensor_trip_point_notify
,
271 .trip_point_config
= scmi_sensor_trip_point_config
,
272 .reading_get
= scmi_sensor_reading_get
,
275 static int scmi_sensors_protocol_init(struct scmi_handle
*handle
)
278 struct sensors_info
*sinfo
;
280 scmi_version_get(handle
, SCMI_PROTOCOL_SENSOR
, &version
);
282 dev_dbg(handle
->dev
, "Sensor Version %d.%d\n",
283 PROTOCOL_REV_MAJOR(version
), PROTOCOL_REV_MINOR(version
));
285 sinfo
= devm_kzalloc(handle
->dev
, sizeof(*sinfo
), GFP_KERNEL
);
289 scmi_sensor_attributes_get(handle
, sinfo
);
291 sinfo
->sensors
= devm_kcalloc(handle
->dev
, sinfo
->num_sensors
,
292 sizeof(*sinfo
->sensors
), GFP_KERNEL
);
296 scmi_sensor_description_get(handle
, sinfo
);
298 sinfo
->version
= version
;
299 handle
->sensor_ops
= &sensor_ops
;
300 handle
->sensor_priv
= sinfo
;
305 static int __init
scmi_sensors_init(void)
307 return scmi_protocol_register(SCMI_PROTOCOL_SENSOR
,
308 &scmi_sensors_protocol_init
);
310 subsys_initcall(scmi_sensors_init
);