]> Git Repo - J-linux.git/blob - drivers/rtc/rtc-imx-sm-bbm.c
Merge tag 'vfs-6.13-rc7.fixes' of git://git.kernel.org/pub/scm/linux/kernel/git/vfs/vfs
[J-linux.git] / drivers / rtc / rtc-imx-sm-bbm.c
1 // SPDX-License-Identifier: GPL-2.0+
2 /*
3  * Copyright 2024 NXP.
4  */
5
6 #include <linux/jiffies.h>
7 #include <linux/module.h>
8 #include <linux/platform_device.h>
9 #include <linux/rtc.h>
10 #include <linux/scmi_protocol.h>
11 #include <linux/scmi_imx_protocol.h>
12
13 struct scmi_imx_bbm {
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;
18 };
19
20 static int scmi_imx_bbm_read_time(struct device *dev, struct rtc_time *tm)
21 {
22         struct scmi_imx_bbm *bbnsm = dev_get_drvdata(dev);
23         struct scmi_protocol_handle *ph = bbnsm->ph;
24         u64 val;
25         int ret;
26
27         ret = bbnsm->ops->rtc_time_get(ph, 0, &val);
28         if (ret)
29                 return ret;
30
31         rtc_time64_to_tm(val, tm);
32
33         return 0;
34 }
35
36 static int scmi_imx_bbm_set_time(struct device *dev, struct rtc_time *tm)
37 {
38         struct scmi_imx_bbm *bbnsm = dev_get_drvdata(dev);
39         struct scmi_protocol_handle *ph = bbnsm->ph;
40         u64 val;
41
42         val = rtc_tm_to_time64(tm);
43
44         return bbnsm->ops->rtc_time_set(ph, 0, val);
45 }
46
47 static int scmi_imx_bbm_alarm_irq_enable(struct device *dev, unsigned int enable)
48 {
49         struct scmi_imx_bbm *bbnsm = dev_get_drvdata(dev);
50         struct scmi_protocol_handle *ph = bbnsm->ph;
51
52         /* scmi_imx_bbm_set_alarm enables the irq, just handle disable here */
53         if (!enable)
54                 return bbnsm->ops->rtc_alarm_set(ph, 0, false, 0);
55
56         return 0;
57 }
58
59 static int scmi_imx_bbm_set_alarm(struct device *dev, struct rtc_wkalrm *alrm)
60 {
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;
64         u64 val;
65
66         val = rtc_tm_to_time64(alrm_tm);
67
68         return bbnsm->ops->rtc_alarm_set(ph, 0, true, val);
69 }
70
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,
76 };
77
78 static int scmi_imx_bbm_rtc_notifier(struct notifier_block *nb, unsigned long event, void *data)
79 {
80         struct scmi_imx_bbm *bbnsm = container_of(nb, struct scmi_imx_bbm, nb);
81         struct scmi_imx_bbm_notif_report *r = data;
82
83         if (r->is_rtc)
84                 rtc_update_irq(bbnsm->rtc_dev, 1, RTC_AF | RTC_IRQF);
85         else
86                 pr_err("Unexpected bbm event: %s\n", __func__);
87
88         return 0;
89 }
90
91 static int scmi_imx_bbm_rtc_init(struct scmi_device *sdev)
92 {
93         const struct scmi_handle *handle = sdev->handle;
94         struct device *dev = &sdev->dev;
95         struct scmi_imx_bbm *bbnsm = dev_get_drvdata(dev);
96         int ret;
97
98         bbnsm->rtc_dev = devm_rtc_allocate_device(dev);
99         if (IS_ERR(bbnsm->rtc_dev))
100                 return PTR_ERR(bbnsm->rtc_dev);
101
102         bbnsm->rtc_dev->ops = &smci_imx_bbm_rtc_ops;
103         bbnsm->rtc_dev->range_max = U32_MAX;
104
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,
108                                                                NULL, &bbnsm->nb);
109         if (ret)
110                 return ret;
111
112         return devm_rtc_register_device(bbnsm->rtc_dev);
113 }
114
115 static int scmi_imx_bbm_rtc_probe(struct scmi_device *sdev)
116 {
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;
121         int ret;
122
123         if (!handle)
124                 return -ENODEV;
125
126         bbnsm = devm_kzalloc(dev, sizeof(*bbnsm), GFP_KERNEL);
127         if (!bbnsm)
128                 return -ENOMEM;
129
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);
133
134         bbnsm->ph = ph;
135
136         device_init_wakeup(dev, true);
137
138         dev_set_drvdata(dev, bbnsm);
139
140         ret = scmi_imx_bbm_rtc_init(sdev);
141         if (ret)
142                 device_init_wakeup(dev, false);
143
144         return ret;
145 }
146
147 static const struct scmi_device_id scmi_id_table[] = {
148         { SCMI_PROTOCOL_IMX_BBM, "imx-bbm-rtc" },
149         { },
150 };
151 MODULE_DEVICE_TABLE(scmi, scmi_id_table);
152
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,
157 };
158 module_scmi_driver(scmi_imx_bbm_rtc_driver);
159
160 MODULE_AUTHOR("Peng Fan <[email protected]>");
161 MODULE_DESCRIPTION("IMX SM BBM RTC driver");
162 MODULE_LICENSE("GPL");
This page took 0.034711 seconds and 4 git commands to generate.