linux/drivers/rtc/rtc-imx-sc.c
<<
>>
Prefs
   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       9
  15#define IMX_SC_TIMER_FUNC_SET_RTC_ALARM         8
  16#define IMX_SC_TIMER_FUNC_SET_RTC_TIME          6
  17
  18#define IMX_SIP_SRTC                    0xC2000002
  19#define IMX_SIP_SRTC_SET_TIME           0x0
  20
  21#define SC_IRQ_GROUP_RTC    2
  22#define SC_IRQ_RTC          1
  23
  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