1 // SPDX-License-Identifier: GPL-2.0+
6 #include <linux/jiffies.h>
7 #include <linux/module.h>
8 #include <linux/platform_device.h>
10 #include <linux/scmi_protocol.h>
11 #include <linux/scmi_imx_protocol.h>
14 const struct scmi_imx_bbm_proto_ops
*ops
;
15 struct rtc_device
*rtc_dev
;
16 struct scmi_protocol_handle
*ph
;
17 struct notifier_block nb
;
20 static int scmi_imx_bbm_read_time(struct device
*dev
, struct rtc_time
*tm
)
22 struct scmi_imx_bbm
*bbnsm
= dev_get_drvdata(dev
);
23 struct scmi_protocol_handle
*ph
= bbnsm
->ph
;
27 ret
= bbnsm
->ops
->rtc_time_get(ph
, 0, &val
);
31 rtc_time64_to_tm(val
, tm
);
36 static int scmi_imx_bbm_set_time(struct device
*dev
, struct rtc_time
*tm
)
38 struct scmi_imx_bbm
*bbnsm
= dev_get_drvdata(dev
);
39 struct scmi_protocol_handle
*ph
= bbnsm
->ph
;
42 val
= rtc_tm_to_time64(tm
);
44 return bbnsm
->ops
->rtc_time_set(ph
, 0, val
);
47 static int scmi_imx_bbm_alarm_irq_enable(struct device
*dev
, unsigned int enable
)
49 struct scmi_imx_bbm
*bbnsm
= dev_get_drvdata(dev
);
50 struct scmi_protocol_handle
*ph
= bbnsm
->ph
;
52 /* scmi_imx_bbm_set_alarm enables the irq, just handle disable here */
54 return bbnsm
->ops
->rtc_alarm_set(ph
, 0, false, 0);
59 static int scmi_imx_bbm_set_alarm(struct device
*dev
, struct rtc_wkalrm
*alrm
)
61 struct scmi_imx_bbm
*bbnsm
= dev_get_drvdata(dev
);
62 struct scmi_protocol_handle
*ph
= bbnsm
->ph
;
63 struct rtc_time
*alrm_tm
= &alrm
->time
;
66 val
= rtc_tm_to_time64(alrm_tm
);
68 return bbnsm
->ops
->rtc_alarm_set(ph
, 0, true, val
);
71 static const struct rtc_class_ops smci_imx_bbm_rtc_ops
= {
72 .read_time
= scmi_imx_bbm_read_time
,
73 .set_time
= scmi_imx_bbm_set_time
,
74 .set_alarm
= scmi_imx_bbm_set_alarm
,
75 .alarm_irq_enable
= scmi_imx_bbm_alarm_irq_enable
,
78 static int scmi_imx_bbm_rtc_notifier(struct notifier_block
*nb
, unsigned long event
, void *data
)
80 struct scmi_imx_bbm
*bbnsm
= container_of(nb
, struct scmi_imx_bbm
, nb
);
81 struct scmi_imx_bbm_notif_report
*r
= data
;
84 rtc_update_irq(bbnsm
->rtc_dev
, 1, RTC_AF
| RTC_IRQF
);
86 pr_err("Unexpected bbm event: %s\n", __func__
);
91 static int scmi_imx_bbm_rtc_init(struct scmi_device
*sdev
)
93 const struct scmi_handle
*handle
= sdev
->handle
;
94 struct device
*dev
= &sdev
->dev
;
95 struct scmi_imx_bbm
*bbnsm
= dev_get_drvdata(dev
);
98 bbnsm
->rtc_dev
= devm_rtc_allocate_device(dev
);
99 if (IS_ERR(bbnsm
->rtc_dev
))
100 return PTR_ERR(bbnsm
->rtc_dev
);
102 bbnsm
->rtc_dev
->ops
= &smci_imx_bbm_rtc_ops
;
103 bbnsm
->rtc_dev
->range_max
= U32_MAX
;
105 bbnsm
->nb
.notifier_call
= &scmi_imx_bbm_rtc_notifier
;
106 ret
= handle
->notify_ops
->devm_event_notifier_register(sdev
, SCMI_PROTOCOL_IMX_BBM
,
107 SCMI_EVENT_IMX_BBM_RTC
,
112 return devm_rtc_register_device(bbnsm
->rtc_dev
);
115 static int scmi_imx_bbm_rtc_probe(struct scmi_device
*sdev
)
117 const struct scmi_handle
*handle
= sdev
->handle
;
118 struct device
*dev
= &sdev
->dev
;
119 struct scmi_protocol_handle
*ph
;
120 struct scmi_imx_bbm
*bbnsm
;
126 bbnsm
= devm_kzalloc(dev
, sizeof(*bbnsm
), GFP_KERNEL
);
130 bbnsm
->ops
= handle
->devm_protocol_get(sdev
, SCMI_PROTOCOL_IMX_BBM
, &ph
);
131 if (IS_ERR(bbnsm
->ops
))
132 return PTR_ERR(bbnsm
->ops
);
136 device_init_wakeup(dev
, true);
138 dev_set_drvdata(dev
, bbnsm
);
140 ret
= scmi_imx_bbm_rtc_init(sdev
);
142 device_init_wakeup(dev
, false);
147 static const struct scmi_device_id scmi_id_table
[] = {
148 { SCMI_PROTOCOL_IMX_BBM
, "imx-bbm-rtc" },
151 MODULE_DEVICE_TABLE(scmi
, scmi_id_table
);
153 static struct scmi_driver scmi_imx_bbm_rtc_driver
= {
154 .name
= "scmi-imx-bbm-rtc",
155 .probe
= scmi_imx_bbm_rtc_probe
,
156 .id_table
= scmi_id_table
,
158 module_scmi_driver(scmi_imx_bbm_rtc_driver
);
160 MODULE_AUTHOR("Peng Fan <peng.fan@nxp.com>");
161 MODULE_DESCRIPTION("IMX SM BBM RTC driver");
162 MODULE_LICENSE("GPL");