163 lines · 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 13struct 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 20static 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 36static 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 47static 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 59static 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 71static 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 78static 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 else86 pr_err("Unexpected bbm event: %s\n", __func__);87 88 return 0;89}90 91static 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 115static 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 147static const struct scmi_device_id scmi_id_table[] = {148 { SCMI_PROTOCOL_IMX_BBM, "imx-bbm-rtc" },149 { },150};151MODULE_DEVICE_TABLE(scmi, scmi_id_table);152 153static 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};158module_scmi_driver(scmi_imx_bbm_rtc_driver);159 160MODULE_AUTHOR("Peng Fan <peng.fan@nxp.com>");161MODULE_DESCRIPTION("IMX SM BBM RTC driver");162MODULE_LICENSE("GPL");163