Blame view

drivers/rtc/rtc-imx-sc.c 4.58 KB
e01b57819   Anson Huang   rtc: add i.MX sys...
1
2
3
4
  // SPDX-License-Identifier: GPL-2.0+
  /*
   * Copyright 2018 NXP.
   */
a3094fc1a   Anson Huang   rtc: imx-sc: add ...
5
  #include <dt-bindings/firmware/imx/rsrc.h>
13a929f38   Anson Huang   rtc: imx-sc: add ...
6
  #include <linux/arm-smccc.h>
e01b57819   Anson Huang   rtc: add i.MX sys...
7
8
9
10
11
12
13
  #include <linux/firmware/imx/sci.h>
  #include <linux/module.h>
  #include <linux/of.h>
  #include <linux/platform_device.h>
  #include <linux/rtc.h>
  
  #define IMX_SC_TIMER_FUNC_GET_RTC_SEC1970	9
a3094fc1a   Anson Huang   rtc: imx-sc: add ...
14
  #define IMX_SC_TIMER_FUNC_SET_RTC_ALARM		8
e01b57819   Anson Huang   rtc: add i.MX sys...
15
  #define IMX_SC_TIMER_FUNC_SET_RTC_TIME		6
13a929f38   Anson Huang   rtc: imx-sc: add ...
16
17
  #define IMX_SIP_SRTC			0xC2000002
  #define IMX_SIP_SRTC_SET_TIME		0x0
a3094fc1a   Anson Huang   rtc: imx-sc: add ...
18
19
  #define SC_IRQ_GROUP_RTC    2
  #define SC_IRQ_RTC          1
e01b57819   Anson Huang   rtc: add i.MX sys...
20
21
22
23
24
25
26
  static struct imx_sc_ipc *rtc_ipc_handle;
  static struct rtc_device *imx_sc_rtc;
  
  struct imx_sc_msg_timer_get_rtc_time {
  	struct imx_sc_rpc_msg hdr;
  	u32 time;
  } __packed;
a3094fc1a   Anson Huang   rtc: imx-sc: add ...
27
28
29
30
31
32
33
34
  struct imx_sc_msg_timer_rtc_set_alarm {
  	struct imx_sc_rpc_msg hdr;
  	u16 year;
  	u8 mon;
  	u8 day;
  	u8 hour;
  	u8 min;
  	u8 sec;
a29de8652   Leonard Crestez   rtc: imx-sc: Alig...
35
  } __packed __aligned(4);
a3094fc1a   Anson Huang   rtc: imx-sc: add ...
36

e01b57819   Anson Huang   rtc: add i.MX sys...
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
  static int imx_sc_rtc_read_time(struct device *dev, struct rtc_time *tm)
  {
  	struct imx_sc_msg_timer_get_rtc_time msg;
  	struct imx_sc_rpc_msg *hdr = &msg.hdr;
  	int ret;
  
  	hdr->ver = IMX_SC_RPC_VERSION;
  	hdr->svc = IMX_SC_RPC_SVC_TIMER;
  	hdr->func = IMX_SC_TIMER_FUNC_GET_RTC_SEC1970;
  	hdr->size = 1;
  
  	ret = imx_scu_call_rpc(rtc_ipc_handle, &msg, true);
  	if (ret) {
  		dev_err(dev, "read rtc time failed, ret %d
  ", ret);
  		return ret;
  	}
30adde6b1   Alexandre Belloni   rtc: imx-sc: use ...
54
  	rtc_time64_to_tm(msg.time, tm);
e01b57819   Anson Huang   rtc: add i.MX sys...
55
56
57
  
  	return 0;
  }
13a929f38   Anson Huang   rtc: imx-sc: add ...
58
59
60
61
62
63
64
65
66
67
68
69
70
  static int imx_sc_rtc_set_time(struct device *dev, struct rtc_time *tm)
  {
  	struct arm_smccc_res res;
  
  	/* pack 2 time parameters into 1 register, 16 bits for each */
  	arm_smccc_smc(IMX_SIP_SRTC, IMX_SIP_SRTC_SET_TIME,
  		      ((tm->tm_year + 1900) << 16) | (tm->tm_mon + 1),
  		      (tm->tm_mday << 16) | tm->tm_hour,
  		      (tm->tm_min << 16) | tm->tm_sec,
  		      0, 0, 0, &res);
  
  	return res.a0;
  }
a3094fc1a   Anson Huang   rtc: imx-sc: add ...
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
  static int imx_sc_rtc_alarm_irq_enable(struct device *dev, unsigned int enable)
  {
  	return imx_scu_irq_group_enable(SC_IRQ_GROUP_RTC, SC_IRQ_RTC, enable);
  }
  
  static int imx_sc_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alrm)
  {
  	/*
  	 * SCU firmware does NOT provide read alarm API, but .read_alarm
  	 * callback is required by RTC framework to support alarm function,
  	 * so just return here.
  	 */
  	return 0;
  }
  
  static int imx_sc_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alrm)
  {
  	struct imx_sc_msg_timer_rtc_set_alarm msg;
  	struct imx_sc_rpc_msg *hdr = &msg.hdr;
  	int ret;
  	struct rtc_time *alrm_tm = &alrm->time;
  
  	hdr->ver = IMX_SC_RPC_VERSION;
  	hdr->svc = IMX_SC_RPC_SVC_TIMER;
  	hdr->func = IMX_SC_TIMER_FUNC_SET_RTC_ALARM;
  	hdr->size = 3;
  
  	msg.year = alrm_tm->tm_year + 1900;
  	msg.mon = alrm_tm->tm_mon + 1;
  	msg.day = alrm_tm->tm_mday;
  	msg.hour = alrm_tm->tm_hour;
  	msg.min = alrm_tm->tm_min;
  	msg.sec = alrm_tm->tm_sec;
  
  	ret = imx_scu_call_rpc(rtc_ipc_handle, &msg, true);
  	if (ret) {
  		dev_err(dev, "set rtc alarm failed, ret %d
  ", ret);
  		return ret;
  	}
  
  	ret = imx_sc_rtc_alarm_irq_enable(dev, alrm->enabled);
  	if (ret) {
  		dev_err(dev, "enable rtc alarm failed, ret %d
  ", ret);
  		return ret;
  	}
  
  	return 0;
  }
e01b57819   Anson Huang   rtc: add i.MX sys...
121
122
  static const struct rtc_class_ops imx_sc_rtc_ops = {
  	.read_time = imx_sc_rtc_read_time,
13a929f38   Anson Huang   rtc: imx-sc: add ...
123
  	.set_time = imx_sc_rtc_set_time,
a3094fc1a   Anson Huang   rtc: imx-sc: add ...
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
  	.read_alarm = imx_sc_rtc_read_alarm,
  	.set_alarm = imx_sc_rtc_set_alarm,
  	.alarm_irq_enable = imx_sc_rtc_alarm_irq_enable,
  };
  
  static int imx_sc_rtc_alarm_notify(struct notifier_block *nb,
  					unsigned long event, void *group)
  {
  	/* ignore non-rtc irq */
  	if (!((event & SC_IRQ_RTC) && (*(u8 *)group == SC_IRQ_GROUP_RTC)))
  		return 0;
  
  	rtc_update_irq(imx_sc_rtc, 1, RTC_IRQF | RTC_AF);
  
  	return 0;
  }
  
  static struct notifier_block imx_sc_rtc_alarm_sc_notifier = {
  	.notifier_call = imx_sc_rtc_alarm_notify,
e01b57819   Anson Huang   rtc: add i.MX sys...
143
144
145
146
147
148
149
150
151
  };
  
  static int imx_sc_rtc_probe(struct platform_device *pdev)
  {
  	int ret;
  
  	ret = imx_scu_get_handle(&rtc_ipc_handle);
  	if (ret)
  		return ret;
a3094fc1a   Anson Huang   rtc: imx-sc: add ...
152
  	device_init_wakeup(&pdev->dev, true);
e01b57819   Anson Huang   rtc: add i.MX sys...
153
154
155
156
157
158
159
160
161
  	imx_sc_rtc = devm_rtc_allocate_device(&pdev->dev);
  	if (IS_ERR(imx_sc_rtc))
  		return PTR_ERR(imx_sc_rtc);
  
  	imx_sc_rtc->ops = &imx_sc_rtc_ops;
  	imx_sc_rtc->range_min = 0;
  	imx_sc_rtc->range_max = U32_MAX;
  
  	ret = rtc_register_device(imx_sc_rtc);
44c638ce4   Alexandre Belloni   rtc: remove super...
162
  	if (ret)
e01b57819   Anson Huang   rtc: add i.MX sys...
163
  		return ret;
e01b57819   Anson Huang   rtc: add i.MX sys...
164

a3094fc1a   Anson Huang   rtc: imx-sc: add ...
165
  	imx_scu_irq_register_notifier(&imx_sc_rtc_alarm_sc_notifier);
e01b57819   Anson Huang   rtc: add i.MX sys...
166
167
168
169
170
  	return 0;
  }
  
  static const struct of_device_id imx_sc_dt_ids[] = {
  	{ .compatible = "fsl,imx8qxp-sc-rtc", },
a87442ad5   Anson Huang   rtc: imx-sc: Add ...
171
  	{ .compatible = "fsl,imx8qm-sc-rtc", },
e01b57819   Anson Huang   rtc: add i.MX sys...
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
  	{}
  };
  MODULE_DEVICE_TABLE(of, imx_sc_dt_ids);
  
  static struct platform_driver imx_sc_rtc_driver = {
  	.driver = {
  		.name	= "imx-sc-rtc",
  		.of_match_table = imx_sc_dt_ids,
  	},
  	.probe		= imx_sc_rtc_probe,
  };
  module_platform_driver(imx_sc_rtc_driver);
  
  MODULE_AUTHOR("Anson Huang <Anson.Huang@nxp.com>");
  MODULE_DESCRIPTION("NXP i.MX System Controller RTC Driver");
  MODULE_LICENSE("GPL");