1e01b5781SAnson Huang // SPDX-License-Identifier: GPL-2.0+ 2e01b5781SAnson Huang /* 3e01b5781SAnson Huang * Copyright 2018 NXP. 4e01b5781SAnson Huang */ 5e01b5781SAnson Huang 6*13a929f3SAnson Huang #include <linux/arm-smccc.h> 7e01b5781SAnson Huang #include <linux/firmware/imx/sci.h> 8e01b5781SAnson Huang #include <linux/module.h> 9e01b5781SAnson Huang #include <linux/of.h> 10e01b5781SAnson Huang #include <linux/platform_device.h> 11e01b5781SAnson Huang #include <linux/rtc.h> 12e01b5781SAnson Huang 13e01b5781SAnson Huang #define IMX_SC_TIMER_FUNC_GET_RTC_SEC1970 9 14e01b5781SAnson Huang #define IMX_SC_TIMER_FUNC_SET_RTC_TIME 6 15e01b5781SAnson Huang 16*13a929f3SAnson Huang #define IMX_SIP_SRTC 0xC2000002 17*13a929f3SAnson Huang #define IMX_SIP_SRTC_SET_TIME 0x0 18*13a929f3SAnson Huang 19e01b5781SAnson Huang static struct imx_sc_ipc *rtc_ipc_handle; 20e01b5781SAnson Huang static struct rtc_device *imx_sc_rtc; 21e01b5781SAnson Huang 22e01b5781SAnson Huang struct imx_sc_msg_timer_get_rtc_time { 23e01b5781SAnson Huang struct imx_sc_rpc_msg hdr; 24e01b5781SAnson Huang u32 time; 25e01b5781SAnson Huang } __packed; 26e01b5781SAnson Huang 27e01b5781SAnson Huang static int imx_sc_rtc_read_time(struct device *dev, struct rtc_time *tm) 28e01b5781SAnson Huang { 29e01b5781SAnson Huang struct imx_sc_msg_timer_get_rtc_time msg; 30e01b5781SAnson Huang struct imx_sc_rpc_msg *hdr = &msg.hdr; 31e01b5781SAnson Huang int ret; 32e01b5781SAnson Huang 33e01b5781SAnson Huang hdr->ver = IMX_SC_RPC_VERSION; 34e01b5781SAnson Huang hdr->svc = IMX_SC_RPC_SVC_TIMER; 35e01b5781SAnson Huang hdr->func = IMX_SC_TIMER_FUNC_GET_RTC_SEC1970; 36e01b5781SAnson Huang hdr->size = 1; 37e01b5781SAnson Huang 38e01b5781SAnson Huang ret = imx_scu_call_rpc(rtc_ipc_handle, &msg, true); 39e01b5781SAnson Huang if (ret) { 40e01b5781SAnson Huang dev_err(dev, "read rtc time failed, ret %d\n", ret); 41e01b5781SAnson Huang return ret; 42e01b5781SAnson Huang } 43e01b5781SAnson Huang 44e01b5781SAnson Huang rtc_time_to_tm(msg.time, tm); 45e01b5781SAnson Huang 46e01b5781SAnson Huang return 0; 47e01b5781SAnson Huang } 48e01b5781SAnson Huang 49*13a929f3SAnson Huang static int imx_sc_rtc_set_time(struct device *dev, struct rtc_time *tm) 50*13a929f3SAnson Huang { 51*13a929f3SAnson Huang struct arm_smccc_res res; 52*13a929f3SAnson Huang 53*13a929f3SAnson Huang /* pack 2 time parameters into 1 register, 16 bits for each */ 54*13a929f3SAnson Huang arm_smccc_smc(IMX_SIP_SRTC, IMX_SIP_SRTC_SET_TIME, 55*13a929f3SAnson Huang ((tm->tm_year + 1900) << 16) | (tm->tm_mon + 1), 56*13a929f3SAnson Huang (tm->tm_mday << 16) | tm->tm_hour, 57*13a929f3SAnson Huang (tm->tm_min << 16) | tm->tm_sec, 58*13a929f3SAnson Huang 0, 0, 0, &res); 59*13a929f3SAnson Huang 60*13a929f3SAnson Huang return res.a0; 61*13a929f3SAnson Huang } 62*13a929f3SAnson Huang 63e01b5781SAnson Huang static const struct rtc_class_ops imx_sc_rtc_ops = { 64e01b5781SAnson Huang .read_time = imx_sc_rtc_read_time, 65*13a929f3SAnson Huang .set_time = imx_sc_rtc_set_time, 66e01b5781SAnson Huang }; 67e01b5781SAnson Huang 68e01b5781SAnson Huang static int imx_sc_rtc_probe(struct platform_device *pdev) 69e01b5781SAnson Huang { 70e01b5781SAnson Huang int ret; 71e01b5781SAnson Huang 72e01b5781SAnson Huang ret = imx_scu_get_handle(&rtc_ipc_handle); 73e01b5781SAnson Huang if (ret) 74e01b5781SAnson Huang return ret; 75e01b5781SAnson Huang 76e01b5781SAnson Huang imx_sc_rtc = devm_rtc_allocate_device(&pdev->dev); 77e01b5781SAnson Huang if (IS_ERR(imx_sc_rtc)) 78e01b5781SAnson Huang return PTR_ERR(imx_sc_rtc); 79e01b5781SAnson Huang 80e01b5781SAnson Huang imx_sc_rtc->ops = &imx_sc_rtc_ops; 81e01b5781SAnson Huang imx_sc_rtc->range_min = 0; 82e01b5781SAnson Huang imx_sc_rtc->range_max = U32_MAX; 83e01b5781SAnson Huang 84e01b5781SAnson Huang ret = rtc_register_device(imx_sc_rtc); 85e01b5781SAnson Huang if (ret) { 86e01b5781SAnson Huang dev_err(&pdev->dev, "failed to register rtc: %d\n", ret); 87e01b5781SAnson Huang return ret; 88e01b5781SAnson Huang } 89e01b5781SAnson Huang 90e01b5781SAnson Huang return 0; 91e01b5781SAnson Huang } 92e01b5781SAnson Huang 93e01b5781SAnson Huang static const struct of_device_id imx_sc_dt_ids[] = { 94e01b5781SAnson Huang { .compatible = "fsl,imx8qxp-sc-rtc", }, 95e01b5781SAnson Huang {} 96e01b5781SAnson Huang }; 97e01b5781SAnson Huang MODULE_DEVICE_TABLE(of, imx_sc_dt_ids); 98e01b5781SAnson Huang 99e01b5781SAnson Huang static struct platform_driver imx_sc_rtc_driver = { 100e01b5781SAnson Huang .driver = { 101e01b5781SAnson Huang .name = "imx-sc-rtc", 102e01b5781SAnson Huang .of_match_table = imx_sc_dt_ids, 103e01b5781SAnson Huang }, 104e01b5781SAnson Huang .probe = imx_sc_rtc_probe, 105e01b5781SAnson Huang }; 106e01b5781SAnson Huang module_platform_driver(imx_sc_rtc_driver); 107e01b5781SAnson Huang 108e01b5781SAnson Huang MODULE_AUTHOR("Anson Huang <Anson.Huang@nxp.com>"); 109e01b5781SAnson Huang MODULE_DESCRIPTION("NXP i.MX System Controller RTC Driver"); 110e01b5781SAnson Huang MODULE_LICENSE("GPL"); 111