185 lines · c
1// SPDX-License-Identifier: GPL-2.0+2/*3 * Copyright 2018 NXP.4 */5 6#include <dt-bindings/firmware/imx/rsrc.h>7#include <linux/arm-smccc.h>8#include <linux/firmware/imx/sci.h>9#include <linux/module.h>10#include <linux/of.h>11#include <linux/platform_device.h>12#include <linux/rtc.h>13 14#define IMX_SC_TIMER_FUNC_GET_RTC_SEC1970 915#define IMX_SC_TIMER_FUNC_SET_RTC_ALARM 816#define IMX_SC_TIMER_FUNC_SET_RTC_TIME 617 18#define IMX_SIP_SRTC 0xC200000219#define IMX_SIP_SRTC_SET_TIME 0x020 21#define SC_IRQ_GROUP_RTC 222#define SC_IRQ_RTC 123 24static struct imx_sc_ipc *rtc_ipc_handle;25static struct rtc_device *imx_sc_rtc;26 27struct imx_sc_msg_timer_get_rtc_time {28 struct imx_sc_rpc_msg hdr;29 u32 time;30} __packed;31 32struct imx_sc_msg_timer_rtc_set_alarm {33 struct imx_sc_rpc_msg hdr;34 u16 year;35 u8 mon;36 u8 day;37 u8 hour;38 u8 min;39 u8 sec;40} __packed __aligned(4);41 42static int imx_sc_rtc_read_time(struct device *dev, struct rtc_time *tm)43{44 struct imx_sc_msg_timer_get_rtc_time msg;45 struct imx_sc_rpc_msg *hdr = &msg.hdr;46 int ret;47 48 hdr->ver = IMX_SC_RPC_VERSION;49 hdr->svc = IMX_SC_RPC_SVC_TIMER;50 hdr->func = IMX_SC_TIMER_FUNC_GET_RTC_SEC1970;51 hdr->size = 1;52 53 ret = imx_scu_call_rpc(rtc_ipc_handle, &msg, true);54 if (ret) {55 dev_err(dev, "read rtc time failed, ret %d\n", ret);56 return ret;57 }58 59 rtc_time64_to_tm(msg.time, tm);60 61 return 0;62}63 64static int imx_sc_rtc_set_time(struct device *dev, struct rtc_time *tm)65{66 struct arm_smccc_res res;67 68 /* pack 2 time parameters into 1 register, 16 bits for each */69 arm_smccc_smc(IMX_SIP_SRTC, IMX_SIP_SRTC_SET_TIME,70 ((tm->tm_year + 1900) << 16) | (tm->tm_mon + 1),71 (tm->tm_mday << 16) | tm->tm_hour,72 (tm->tm_min << 16) | tm->tm_sec,73 0, 0, 0, &res);74 75 return res.a0;76}77 78static int imx_sc_rtc_alarm_irq_enable(struct device *dev, unsigned int enable)79{80 return imx_scu_irq_group_enable(SC_IRQ_GROUP_RTC, SC_IRQ_RTC, enable);81}82 83static int imx_sc_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alrm)84{85 struct imx_sc_msg_timer_rtc_set_alarm msg;86 struct imx_sc_rpc_msg *hdr = &msg.hdr;87 int ret;88 struct rtc_time *alrm_tm = &alrm->time;89 90 hdr->ver = IMX_SC_RPC_VERSION;91 hdr->svc = IMX_SC_RPC_SVC_TIMER;92 hdr->func = IMX_SC_TIMER_FUNC_SET_RTC_ALARM;93 hdr->size = 3;94 95 msg.year = alrm_tm->tm_year + 1900;96 msg.mon = alrm_tm->tm_mon + 1;97 msg.day = alrm_tm->tm_mday;98 msg.hour = alrm_tm->tm_hour;99 msg.min = alrm_tm->tm_min;100 msg.sec = alrm_tm->tm_sec;101 102 ret = imx_scu_call_rpc(rtc_ipc_handle, &msg, true);103 if (ret) {104 dev_err(dev, "set rtc alarm failed, ret %d\n", ret);105 return ret;106 }107 108 ret = imx_sc_rtc_alarm_irq_enable(dev, alrm->enabled);109 if (ret) {110 dev_err(dev, "enable rtc alarm failed, ret %d\n", ret);111 return ret;112 }113 114 return 0;115}116 117static const struct rtc_class_ops imx_sc_rtc_ops = {118 .read_time = imx_sc_rtc_read_time,119 .set_time = imx_sc_rtc_set_time,120 .set_alarm = imx_sc_rtc_set_alarm,121 .alarm_irq_enable = imx_sc_rtc_alarm_irq_enable,122};123 124static int imx_sc_rtc_alarm_notify(struct notifier_block *nb,125 unsigned long event, void *group)126{127 /* ignore non-rtc irq */128 if (!((event & SC_IRQ_RTC) && (*(u8 *)group == SC_IRQ_GROUP_RTC)))129 return 0;130 131 rtc_update_irq(imx_sc_rtc, 1, RTC_IRQF | RTC_AF);132 133 return 0;134}135 136static struct notifier_block imx_sc_rtc_alarm_sc_notifier = {137 .notifier_call = imx_sc_rtc_alarm_notify,138};139 140static int imx_sc_rtc_probe(struct platform_device *pdev)141{142 int ret;143 144 ret = imx_scu_get_handle(&rtc_ipc_handle);145 if (ret)146 return ret;147 148 device_init_wakeup(&pdev->dev, true);149 150 imx_sc_rtc = devm_rtc_allocate_device(&pdev->dev);151 if (IS_ERR(imx_sc_rtc))152 return PTR_ERR(imx_sc_rtc);153 154 imx_sc_rtc->ops = &imx_sc_rtc_ops;155 imx_sc_rtc->range_min = 0;156 imx_sc_rtc->range_max = U32_MAX;157 158 ret = devm_rtc_register_device(imx_sc_rtc);159 if (ret)160 return ret;161 162 imx_scu_irq_register_notifier(&imx_sc_rtc_alarm_sc_notifier);163 164 return 0;165}166 167static const struct of_device_id imx_sc_dt_ids[] = {168 { .compatible = "fsl,imx8qxp-sc-rtc", },169 {}170};171MODULE_DEVICE_TABLE(of, imx_sc_dt_ids);172 173static struct platform_driver imx_sc_rtc_driver = {174 .driver = {175 .name = "imx-sc-rtc",176 .of_match_table = imx_sc_dt_ids,177 },178 .probe = imx_sc_rtc_probe,179};180module_platform_driver(imx_sc_rtc_driver);181 182MODULE_AUTHOR("Anson Huang <Anson.Huang@nxp.com>");183MODULE_DESCRIPTION("NXP i.MX System Controller RTC Driver");184MODULE_LICENSE("GPL");185