1 // SPDX-License-Identifier: GPL-2.0
3 * System Control and Management Interface (SCMI) NXP BBM Protocol
8 #define pr_fmt(fmt) "SCMI Notifications BBM - " fmt
10 #include <linux/bits.h>
12 #include <linux/module.h>
14 #include <linux/platform_device.h>
15 #include <linux/scmi_protocol.h>
16 #include <linux/scmi_imx_protocol.h>
18 #include "../../protocols.h"
19 #include "../../notify.h"
21 #define SCMI_PROTOCOL_SUPPORTED_VERSION 0x10000
23 enum scmi_imx_bbm_protocol_cmd
{
24 IMX_BBM_GPR_SET
= 0x3,
25 IMX_BBM_GPR_GET
= 0x4,
26 IMX_BBM_RTC_ATTRIBUTES
= 0x5,
27 IMX_BBM_RTC_TIME_SET
= 0x6,
28 IMX_BBM_RTC_TIME_GET
= 0x7,
29 IMX_BBM_RTC_ALARM_SET
= 0x8,
30 IMX_BBM_BUTTON_GET
= 0x9,
31 IMX_BBM_RTC_NOTIFY
= 0xA,
32 IMX_BBM_BUTTON_NOTIFY
= 0xB,
35 #define GET_RTCS_NR(x) le32_get_bits((x), GENMASK(23, 16))
36 #define GET_GPRS_NR(x) le32_get_bits((x), GENMASK(15, 0))
38 #define SCMI_IMX_BBM_NOTIFY_RTC_UPDATED BIT(2)
39 #define SCMI_IMX_BBM_NOTIFY_RTC_ROLLOVER BIT(1)
40 #define SCMI_IMX_BBM_NOTIFY_RTC_ALARM BIT(0)
42 #define SCMI_IMX_BBM_RTC_ALARM_ENABLE_FLAG BIT(0)
44 #define SCMI_IMX_BBM_NOTIFY_RTC_FLAG \
45 (SCMI_IMX_BBM_NOTIFY_RTC_UPDATED | SCMI_IMX_BBM_NOTIFY_RTC_ROLLOVER | \
46 SCMI_IMX_BBM_NOTIFY_RTC_ALARM)
48 #define SCMI_IMX_BBM_EVENT_RTC_MASK GENMASK(31, 24)
50 struct scmi_imx_bbm_info
{
56 struct scmi_msg_imx_bbm_protocol_attributes
{
60 struct scmi_imx_bbm_set_time
{
67 struct scmi_imx_bbm_get_time
{
72 struct scmi_imx_bbm_alarm_time
{
79 struct scmi_msg_imx_bbm_rtc_notify
{
84 struct scmi_msg_imx_bbm_button_notify
{
88 struct scmi_imx_bbm_notify_payld
{
92 static int scmi_imx_bbm_attributes_get(const struct scmi_protocol_handle
*ph
,
93 struct scmi_imx_bbm_info
*pi
)
97 struct scmi_msg_imx_bbm_protocol_attributes
*attr
;
99 ret
= ph
->xops
->xfer_get_init(ph
, PROTOCOL_ATTRIBUTES
, 0, sizeof(*attr
), &t
);
105 ret
= ph
->xops
->do_xfer(ph
, t
);
107 pi
->nr_rtc
= GET_RTCS_NR(attr
->attributes
);
108 pi
->nr_gpr
= GET_GPRS_NR(attr
->attributes
);
111 ph
->xops
->xfer_put(ph
, t
);
116 static int scmi_imx_bbm_notify(const struct scmi_protocol_handle
*ph
,
117 u32 src_id
, int message_id
, bool enable
)
122 if (message_id
== IMX_BBM_RTC_NOTIFY
) {
123 struct scmi_msg_imx_bbm_rtc_notify
*rtc_notify
;
125 ret
= ph
->xops
->xfer_get_init(ph
, message_id
,
126 sizeof(*rtc_notify
), 0, &t
);
130 rtc_notify
= t
->tx
.buf
;
131 rtc_notify
->rtc_id
= cpu_to_le32(0);
133 cpu_to_le32(enable
? SCMI_IMX_BBM_NOTIFY_RTC_FLAG
: 0);
134 } else if (message_id
== IMX_BBM_BUTTON_NOTIFY
) {
135 struct scmi_msg_imx_bbm_button_notify
*button_notify
;
137 ret
= ph
->xops
->xfer_get_init(ph
, message_id
,
138 sizeof(*button_notify
), 0, &t
);
142 button_notify
= t
->tx
.buf
;
143 button_notify
->flags
= cpu_to_le32(enable
? 1 : 0);
148 ret
= ph
->xops
->do_xfer(ph
, t
);
150 ph
->xops
->xfer_put(ph
, t
);
154 static enum scmi_imx_bbm_protocol_cmd evt_2_cmd
[] = {
156 IMX_BBM_BUTTON_NOTIFY
159 static int scmi_imx_bbm_set_notify_enabled(const struct scmi_protocol_handle
*ph
,
160 u8 evt_id
, u32 src_id
, bool enable
)
164 if (evt_id
>= ARRAY_SIZE(evt_2_cmd
))
167 cmd_id
= evt_2_cmd
[evt_id
];
168 ret
= scmi_imx_bbm_notify(ph
, src_id
, cmd_id
, enable
);
170 pr_debug("FAIL_ENABLED - evt[%X] dom[%d] - ret:%d\n",
171 evt_id
, src_id
, ret
);
176 static void *scmi_imx_bbm_fill_custom_report(const struct scmi_protocol_handle
*ph
,
177 u8 evt_id
, ktime_t timestamp
,
178 const void *payld
, size_t payld_sz
,
179 void *report
, u32
*src_id
)
181 const struct scmi_imx_bbm_notify_payld
*p
= payld
;
182 struct scmi_imx_bbm_notif_report
*r
= report
;
184 if (sizeof(*p
) != payld_sz
)
187 if (evt_id
== SCMI_EVENT_IMX_BBM_RTC
) {
189 r
->is_button
= false;
190 r
->timestamp
= timestamp
;
191 r
->rtc_id
= le32_get_bits(p
->flags
, SCMI_IMX_BBM_EVENT_RTC_MASK
);
192 r
->rtc_evt
= le32_get_bits(p
->flags
, SCMI_IMX_BBM_NOTIFY_RTC_FLAG
);
193 dev_dbg(ph
->dev
, "RTC: %d evt: %x\n", r
->rtc_id
, r
->rtc_evt
);
194 *src_id
= r
->rtc_evt
;
195 } else if (evt_id
== SCMI_EVENT_IMX_BBM_BUTTON
) {
198 r
->timestamp
= timestamp
;
199 dev_dbg(ph
->dev
, "BBM Button\n");
209 static const struct scmi_event scmi_imx_bbm_events
[] = {
211 .id
= SCMI_EVENT_IMX_BBM_RTC
,
212 .max_payld_sz
= sizeof(struct scmi_imx_bbm_notify_payld
),
213 .max_report_sz
= sizeof(struct scmi_imx_bbm_notif_report
),
216 .id
= SCMI_EVENT_IMX_BBM_BUTTON
,
217 .max_payld_sz
= sizeof(struct scmi_imx_bbm_notify_payld
),
218 .max_report_sz
= sizeof(struct scmi_imx_bbm_notif_report
),
222 static const struct scmi_event_ops scmi_imx_bbm_event_ops
= {
223 .set_notify_enabled
= scmi_imx_bbm_set_notify_enabled
,
224 .fill_custom_report
= scmi_imx_bbm_fill_custom_report
,
227 static const struct scmi_protocol_events scmi_imx_bbm_protocol_events
= {
228 .queue_sz
= SCMI_PROTO_QUEUE_SZ
,
229 .ops
= &scmi_imx_bbm_event_ops
,
230 .evts
= scmi_imx_bbm_events
,
231 .num_events
= ARRAY_SIZE(scmi_imx_bbm_events
),
235 static int scmi_imx_bbm_rtc_time_set(const struct scmi_protocol_handle
*ph
,
238 struct scmi_imx_bbm_info
*pi
= ph
->get_priv(ph
);
239 struct scmi_imx_bbm_set_time
*cfg
;
243 if (rtc_id
>= pi
->nr_rtc
)
246 ret
= ph
->xops
->xfer_get_init(ph
, IMX_BBM_RTC_TIME_SET
, sizeof(*cfg
), 0, &t
);
251 cfg
->id
= cpu_to_le32(rtc_id
);
253 cfg
->value_low
= cpu_to_le32(lower_32_bits(sec
));
254 cfg
->value_high
= cpu_to_le32(upper_32_bits(sec
));
256 ret
= ph
->xops
->do_xfer(ph
, t
);
258 ph
->xops
->xfer_put(ph
, t
);
263 static int scmi_imx_bbm_rtc_time_get(const struct scmi_protocol_handle
*ph
,
264 u32 rtc_id
, u64
*value
)
266 struct scmi_imx_bbm_info
*pi
= ph
->get_priv(ph
);
267 struct scmi_imx_bbm_get_time
*cfg
;
271 if (rtc_id
>= pi
->nr_rtc
)
274 ret
= ph
->xops
->xfer_get_init(ph
, IMX_BBM_RTC_TIME_GET
, sizeof(*cfg
),
280 cfg
->id
= cpu_to_le32(rtc_id
);
283 ret
= ph
->xops
->do_xfer(ph
, t
);
285 *value
= get_unaligned_le64(t
->rx
.buf
);
287 ph
->xops
->xfer_put(ph
, t
);
292 static int scmi_imx_bbm_rtc_alarm_set(const struct scmi_protocol_handle
*ph
,
293 u32 rtc_id
, bool enable
, u64 sec
)
295 struct scmi_imx_bbm_info
*pi
= ph
->get_priv(ph
);
296 struct scmi_imx_bbm_alarm_time
*cfg
;
300 if (rtc_id
>= pi
->nr_rtc
)
303 ret
= ph
->xops
->xfer_get_init(ph
, IMX_BBM_RTC_ALARM_SET
, sizeof(*cfg
), 0, &t
);
308 cfg
->id
= cpu_to_le32(rtc_id
);
309 cfg
->flags
= enable
?
310 cpu_to_le32(SCMI_IMX_BBM_RTC_ALARM_ENABLE_FLAG
) : 0;
311 cfg
->value_low
= cpu_to_le32(lower_32_bits(sec
));
312 cfg
->value_high
= cpu_to_le32(upper_32_bits(sec
));
314 ret
= ph
->xops
->do_xfer(ph
, t
);
316 ph
->xops
->xfer_put(ph
, t
);
321 static int scmi_imx_bbm_button_get(const struct scmi_protocol_handle
*ph
, u32
*state
)
326 ret
= ph
->xops
->xfer_get_init(ph
, IMX_BBM_BUTTON_GET
, 0, sizeof(u32
), &t
);
330 ret
= ph
->xops
->do_xfer(ph
, t
);
332 *state
= get_unaligned_le32(t
->rx
.buf
);
334 ph
->xops
->xfer_put(ph
, t
);
339 static const struct scmi_imx_bbm_proto_ops scmi_imx_bbm_proto_ops
= {
340 .rtc_time_get
= scmi_imx_bbm_rtc_time_get
,
341 .rtc_time_set
= scmi_imx_bbm_rtc_time_set
,
342 .rtc_alarm_set
= scmi_imx_bbm_rtc_alarm_set
,
343 .button_get
= scmi_imx_bbm_button_get
,
346 static int scmi_imx_bbm_protocol_init(const struct scmi_protocol_handle
*ph
)
350 struct scmi_imx_bbm_info
*binfo
;
352 ret
= ph
->xops
->version_get(ph
, &version
);
356 dev_info(ph
->dev
, "NXP SM BBM Version %d.%d\n",
357 PROTOCOL_REV_MAJOR(version
), PROTOCOL_REV_MINOR(version
));
359 binfo
= devm_kzalloc(ph
->dev
, sizeof(*binfo
), GFP_KERNEL
);
363 ret
= scmi_imx_bbm_attributes_get(ph
, binfo
);
367 return ph
->set_priv(ph
, binfo
, version
);
370 static const struct scmi_protocol scmi_imx_bbm
= {
371 .id
= SCMI_PROTOCOL_IMX_BBM
,
372 .owner
= THIS_MODULE
,
373 .instance_init
= &scmi_imx_bbm_protocol_init
,
374 .ops
= &scmi_imx_bbm_proto_ops
,
375 .events
= &scmi_imx_bbm_protocol_events
,
376 .supported_version
= SCMI_PROTOCOL_SUPPORTED_VERSION
,
378 .sub_vendor_id
= "IMX",
380 module_scmi_protocol(scmi_imx_bbm
);
382 MODULE_DESCRIPTION("i.MX SCMI BBM driver");
383 MODULE_LICENSE("GPL");