summaryrefslogtreecommitdiff
path: root/drivers/rtc/rtc-da9052.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/rtc/rtc-da9052.c')
-rw-r--r--drivers/rtc/rtc-da9052.c694
1 files changed, 694 insertions, 0 deletions
diff --git a/drivers/rtc/rtc-da9052.c b/drivers/rtc/rtc-da9052.c
new file mode 100644
index 000000000000..8f4d26fbc23b
--- /dev/null
+++ b/drivers/rtc/rtc-da9052.c
@@ -0,0 +1,694 @@
+/*
+ * Copyright(c) 2009 Dialog Semiconductor Ltd.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * rtc-da9052.c: RTC driver for DA9052
+ */
+
+#include <linux/platform_device.h>
+#include <linux/rtc.h>
+#include <linux/mfd/da9052/da9052.h>
+#include <linux/mfd/da9052/reg.h>
+#include <linux/mfd/da9052/rtc.h>
+
+#define DRIVER_NAME "da9052-rtc"
+#define ENABLE 1
+#define DISABLE 0
+
+struct da9052_rtc {
+ struct rtc_device *rtc;
+ struct da9052 *da9052;
+ struct da9052_eh_nb eh_data;
+ unsigned char is_min_alarm;
+ unsigned char enable_tick_alarm;
+ unsigned char enable_clk_buffer;
+ unsigned char set_osc_trim_freq;
+};
+
+static int da9052_rtc_enable_alarm(struct da9052 *da9052, unsigned char flag);
+
+void da9052_rtc_notifier(struct da9052_eh_nb *eh_data, unsigned int event)
+{
+ struct da9052_rtc *rtc =
+ container_of(eh_data, struct da9052_rtc, eh_data);
+ struct da9052_ssc_msg msg;
+ unsigned int ret;
+
+ /* Check the alarm type - TIMER or TICK */
+ msg.addr = DA9052_ALARMMI_REG;
+
+ da9052_lock(rtc->da9052);
+ ret = rtc->da9052->read(rtc->da9052, &msg);
+ if (ret != 0) {
+ da9052_unlock(rtc->da9052);
+ return;
+ }
+
+ da9052_unlock(rtc->da9052);
+
+
+ if (msg.data & DA9052_ALARMMI_ALARMTYPE) {
+ da9052_rtc_enable_alarm(rtc->da9052, 0);
+ printk(KERN_INFO "RTC: TIMER ALARM\n");
+ } else {
+ kobject_uevent(&rtc->rtc->dev.kobj, KOBJ_CHANGE);
+ printk(KERN_INFO "RTC: TICK ALARM\n");
+ }
+}
+
+static int da9052_rtc_validate_parameters(struct rtc_time *rtc_tm)
+{
+
+ if (rtc_tm->tm_sec > DA9052_RTC_SECONDS_LIMIT)
+ return DA9052_RTC_INVALID_SECONDS;
+
+ if (rtc_tm->tm_min > DA9052_RTC_MINUTES_LIMIT)
+ return DA9052_RTC_INVALID_MINUTES;
+
+ if (rtc_tm->tm_hour > DA9052_RTC_HOURS_LIMIT)
+ return DA9052_RTC_INVALID_HOURS;
+
+ if (rtc_tm->tm_mday == 0)
+ return DA9052_RTC_INVALID_DAYS;
+
+ if ((rtc_tm->tm_mon > DA9052_RTC_MONTHS_LIMIT) ||
+ (rtc_tm->tm_mon == 0))
+ return DA9052_RTC_INVALID_MONTHS;
+
+ if (rtc_tm->tm_year > DA9052_RTC_YEARS_LIMIT)
+ return DA9052_RTC_INVALID_YEARS;
+
+ if ((rtc_tm->tm_mon == FEBRUARY)) {
+ if (((rtc_tm->tm_year % 4 == 0) &&
+ (rtc_tm->tm_year % 100 != 0)) ||
+ (rtc_tm->tm_year % 400 == 0)) {
+ if (rtc_tm->tm_mday > 29)
+ return DA9052_RTC_INVALID_DAYS;
+ } else if (rtc_tm->tm_mday > 28) {
+ return DA9052_RTC_INVALID_DAYS;
+ }
+ }
+
+ if (((rtc_tm->tm_mon == APRIL) || (rtc_tm->tm_mon == JUNE) ||
+ (rtc_tm->tm_mon == SEPTEMBER) || (rtc_tm->tm_mon == NOVEMBER))
+ && (rtc_tm->tm_mday == 31)) {
+ return DA9052_RTC_INVALID_DAYS;
+ }
+
+
+ return 0;
+}
+
+static int da9052_rtc_settime(struct da9052 *da9052, struct rtc_time *rtc_tm)
+{
+
+ struct da9052_ssc_msg msg_arr[6];
+ int validate_param = 0;
+ unsigned char loop_index = 0;
+ int ret = 0;
+
+
+ /* System compatability */
+ rtc_tm->tm_year -= 100;
+ rtc_tm->tm_mon += 1;
+
+ validate_param = da9052_rtc_validate_parameters(rtc_tm);
+ if (validate_param)
+ return validate_param;
+
+ msg_arr[loop_index].addr = DA9052_COUNTS_REG;
+ msg_arr[loop_index++].data = DA9052_COUNTS_MONITOR | rtc_tm->tm_sec;
+
+ msg_arr[loop_index].addr = DA9052_COUNTMI_REG;
+ msg_arr[loop_index].data = 0;
+ msg_arr[loop_index++].data = rtc_tm->tm_min;
+
+ msg_arr[loop_index].addr = DA9052_COUNTH_REG;
+ msg_arr[loop_index].data = 0;
+ msg_arr[loop_index++].data = rtc_tm->tm_hour;
+
+ msg_arr[loop_index].addr = DA9052_COUNTD_REG;
+ msg_arr[loop_index].data = 0;
+ msg_arr[loop_index++].data = rtc_tm->tm_mday;
+
+ msg_arr[loop_index].addr = DA9052_COUNTMO_REG;
+ msg_arr[loop_index].data = 0;
+ msg_arr[loop_index++].data = rtc_tm->tm_mon;
+
+ msg_arr[loop_index].addr = DA9052_COUNTY_REG;
+ msg_arr[loop_index].data = 0;
+ msg_arr[loop_index++].data = rtc_tm->tm_year;
+
+ da9052_lock(da9052);
+ ret = da9052->write_many(da9052, msg_arr, loop_index);
+ if (ret != 0) {
+ da9052_unlock(da9052);
+ return ret;
+ }
+
+ da9052_unlock(da9052);
+ return 0;
+}
+
+static int da9052_rtc_gettime(struct da9052 *da9052, struct rtc_time *rtc_tm)
+{
+
+ struct da9052_ssc_msg msg[6];
+ unsigned char loop_index = 0;
+ int validate_param = 0;
+ int ret = 0;
+
+ msg[loop_index].data = 0;
+ msg[loop_index++].addr = DA9052_COUNTS_REG;
+
+ msg[loop_index].data = 0;
+ msg[loop_index++].addr = DA9052_COUNTMI_REG;
+
+ msg[loop_index].data = 0;
+ msg[loop_index++].addr = DA9052_COUNTH_REG;
+
+ msg[loop_index].data = 0;
+ msg[loop_index++].addr = DA9052_COUNTD_REG;
+
+ msg[loop_index].data = 0;
+ msg[loop_index++].addr = DA9052_COUNTMO_REG;
+
+ msg[loop_index].data = 0;
+ msg[loop_index++].addr = DA9052_COUNTY_REG;
+
+ da9052_lock(da9052);
+ ret = da9052->read_many(da9052, msg, loop_index);
+ if (ret != 0) {
+ da9052_unlock(da9052);
+ return ret;
+ }
+ da9052_unlock(da9052);
+
+ rtc_tm->tm_year = msg[--loop_index].data & DA9052_COUNTY_COUNTYEAR;
+ rtc_tm->tm_mon = msg[--loop_index].data & DA9052_COUNTMO_COUNTMONTH;
+ rtc_tm->tm_mday = msg[--loop_index].data & DA9052_COUNTD_COUNTDAY;
+ rtc_tm->tm_hour = msg[--loop_index].data & DA9052_COUNTH_COUNTHOUR;
+ rtc_tm->tm_min = msg[--loop_index].data & DA9052_COUNTMI_COUNTMIN;
+ rtc_tm->tm_sec = msg[--loop_index].data & DA9052_COUNTS_COUNTSEC;
+
+ validate_param = da9052_rtc_validate_parameters(rtc_tm);
+ if (validate_param)
+ return validate_param;
+
+ /* System compatability */
+ rtc_tm->tm_year += 100;
+ rtc_tm->tm_mon -= 1;
+ return 0;
+}
+
+static int da9052_alarm_gettime(struct da9052 *da9052, struct rtc_time *rtc_tm)
+{
+ struct da9052_ssc_msg msg[5];
+ unsigned char loop_index = 0;
+ int validate_param = 0;
+ int ret = 0;
+
+ msg[loop_index].data = 0;
+ msg[loop_index++].addr = DA9052_ALARMMI_REG;
+
+ msg[loop_index].data = 0;
+ msg[loop_index++].addr = DA9052_ALARMH_REG;
+
+ msg[loop_index].data = 0;
+ msg[loop_index++].addr = DA9052_ALARMD_REG;
+
+ msg[loop_index].data = 0;
+ msg[loop_index++].addr = DA9052_ALARMMO_REG;
+
+ msg[loop_index].data = 0;
+ msg[loop_index++].addr = DA9052_ALARMY_REG;
+
+ da9052_lock(da9052);
+ ret = da9052->read_many(da9052, msg, loop_index);
+ if (ret != 0) {
+ da9052_unlock(da9052);
+ return ret;
+ }
+ da9052_unlock(da9052);
+
+ rtc_tm->tm_year = msg[--loop_index].data & DA9052_ALARMY_ALARMYEAR;
+ rtc_tm->tm_mon = msg[--loop_index].data & DA9052_ALARMMO_ALARMMONTH;
+ rtc_tm->tm_mday = msg[--loop_index].data & DA9052_ALARMD_ALARMDAY;
+ rtc_tm->tm_hour = msg[--loop_index].data & DA9052_ALARMH_ALARMHOUR;
+ rtc_tm->tm_min = msg[--loop_index].data & DA9052_ALARMMI_ALARMMIN;
+
+ validate_param = da9052_rtc_validate_parameters(rtc_tm);
+ if (validate_param)
+ return validate_param;
+
+ /* System compatability */
+ rtc_tm->tm_year += 100;
+ rtc_tm->tm_mon -= 1;
+
+ return 0;
+}
+
+static int da9052_alarm_settime(struct da9052 *da9052, struct rtc_time *rtc_tm)
+{
+
+ struct da9052_ssc_msg msg_arr[5];
+ struct da9052_ssc_msg msg;
+ int validate_param = 0;
+ unsigned char loop_index = 0;
+ int ret = 0;
+
+ rtc_tm->tm_sec = 0;
+
+ /* System compatability */
+ rtc_tm->tm_year -= 100;
+ rtc_tm->tm_mon += 1;
+
+ validate_param = da9052_rtc_validate_parameters(rtc_tm);
+ if (validate_param)
+ return validate_param;
+
+ msg.addr = DA9052_ALARMMI_REG;
+ msg.data = 0;
+
+ da9052_lock(da9052);
+ ret = da9052->read(da9052, &msg);
+ if (ret != 0) {
+ da9052_unlock(da9052);
+ return ret;
+ }
+
+ msg.data = msg.data & ~(DA9052_ALARMMI_ALARMMIN);
+ msg.data |= rtc_tm->tm_min;
+
+ msg_arr[loop_index].addr = DA9052_ALARMMI_REG;
+ msg_arr[loop_index].data = 0;
+ msg_arr[loop_index++].data = msg.data;
+
+ msg_arr[loop_index].addr = DA9052_ALARMH_REG;
+ msg_arr[loop_index].data = 0;
+ msg_arr[loop_index++].data = rtc_tm->tm_hour;
+
+ msg_arr[loop_index].addr = DA9052_ALARMD_REG;
+ msg_arr[loop_index].data = 0;
+ msg_arr[loop_index++].data = rtc_tm->tm_mday;
+
+ msg_arr[loop_index].addr = DA9052_ALARMMO_REG;
+ msg_arr[loop_index].data = 0;
+ msg_arr[loop_index++].data = rtc_tm->tm_mon;
+
+ msg.addr = DA9052_ALARMY_REG;
+ msg.data = 0;
+ ret = da9052->read(da9052, &msg);
+ if (ret != 0) {
+ da9052_unlock(da9052);
+ return ret;
+ }
+
+ msg.data = msg.data & ~(DA9052_ALARMY_ALARMYEAR);
+
+
+ msg.data |= rtc_tm->tm_year;
+ msg_arr[loop_index].addr = DA9052_ALARMY_REG;
+ msg_arr[loop_index].data = 0;
+ msg_arr[loop_index++].data = msg.data;
+
+ ret = da9052->write_many(da9052, msg_arr, loop_index);
+ if (ret) {
+ da9052_unlock(da9052);
+ return ret;
+ }
+
+ da9052_unlock(da9052);
+ return 0;
+}
+
+static int da9052_rtc_get_alarm_status(struct da9052 *da9052)
+{
+ struct da9052_ssc_msg msg;
+ int ret = 0;
+
+ msg.addr = DA9052_ALARMY_REG;
+ msg.data = 0;
+ da9052_lock(da9052);
+ ret = da9052->read(da9052, &msg);
+ if (ret != 0) {
+ da9052_unlock(da9052);
+ return ret;
+ }
+
+ da9052_unlock(da9052);
+ msg.data &= DA9052_ALARMY_ALARMON;
+
+ return (msg.data > 0) ? 1 : 0;
+}
+
+
+static int da9052_rtc_enable_alarm(struct da9052 *da9052, unsigned char flag)
+{
+ struct da9052_ssc_msg msg;
+ int ret = 0;
+
+ msg.addr = DA9052_ALARMY_REG;
+ da9052_lock(da9052);
+ ret = da9052->read(da9052, &msg);
+ if (ret != 0) {
+ da9052_unlock(da9052);
+ return ret;
+ }
+
+ if (flag)
+ msg.data = msg.data | DA9052_ALARMY_ALARMON;
+ else
+ msg.data = msg.data & ~(DA9052_ALARMY_ALARMON);
+
+ ret = da9052->write(da9052, &msg);
+ if (ret != 0) {
+ da9052_unlock(da9052);
+ return ret;
+ }
+ da9052_unlock(da9052);
+
+ return 0;
+}
+
+
+static ssize_t da9052_rtc_mask_irq(struct da9052 *da9052)
+ {
+ unsigned char data = 0;
+ ssize_t ret = 0;
+ struct da9052_ssc_msg ssc_msg;
+
+ ssc_msg.addr = DA9052_IRQMASKA_REG;
+ ssc_msg.data = 0;
+
+ da9052_lock(da9052);
+ ret = da9052->read(da9052, &ssc_msg);
+ if (ret != 0) {
+ da9052_unlock(da9052);
+ return ret;
+ }
+
+ data = ret;
+ ssc_msg.data = data |= DA9052_IRQMASKA_MALRAM;
+
+ ret = da9052->write(da9052, &ssc_msg);
+ if (ret != 0) {
+ da9052_unlock(da9052);
+ return ret;
+ }
+
+ da9052_unlock(da9052);
+ return 0;
+}
+
+
+static ssize_t da9052_rtc_unmask_irq(struct da9052 *da9052)
+{
+ unsigned char data = 0;
+ ssize_t ret = 0;
+ struct da9052_ssc_msg ssc_msg;
+
+ ssc_msg.addr = DA9052_IRQMASKA_REG;
+ ssc_msg.data = 0;
+
+ da9052_lock(da9052);
+ ret = da9052->read(da9052, &ssc_msg);
+ if (ret != 0) {
+ da9052_unlock(da9052);
+ return ret;
+ }
+
+ data = ret;
+ ssc_msg.data = data &= ~DA9052_IRQMASKA_MALRAM;
+
+ ret = da9052->write(da9052, &ssc_msg);
+ if (ret != 0) {
+ da9052_unlock(da9052);
+ return ret;
+ }
+
+ da9052_unlock(da9052);
+ return 0;
+
+}
+
+static int da9052_rtc_class_ops_gettime
+ (struct device *dev, struct rtc_time *rtc_tm)
+{
+ int ret;
+ struct da9052 *da9052 = dev_get_drvdata(dev->parent);
+ ret = da9052_rtc_gettime(da9052, rtc_tm);
+ if (ret)
+ return ret;
+ return 0;
+}
+
+
+static int da9052_rtc_class_ops_settime(struct device *dev, struct rtc_time *tm)
+{
+ int ret;
+ struct da9052 *da9052 = dev_get_drvdata(dev->parent);
+ ret = da9052_rtc_settime(da9052, tm);
+
+ return ret;
+}
+
+static int da9052_rtc_readalarm(struct device *dev, struct rtc_wkalrm *alrm)
+{
+ int ret;
+ struct rtc_time *tm = &alrm->time;
+ struct da9052 *da9052 = dev_get_drvdata(dev->parent);
+ ret = da9052_alarm_gettime(da9052, tm);
+
+ if (ret)
+ return ret;
+
+ alrm->enabled = da9052_rtc_get_alarm_status(da9052);
+
+ return 0;
+
+}
+
+static int da9052_rtc_setalarm(struct device *dev, struct rtc_wkalrm *alrm)
+{
+ int ret = 0;
+ struct rtc_time *tm = &alrm->time;
+ struct da9052 *da9052 = dev_get_drvdata(dev->parent);
+
+ ret = da9052_alarm_settime(da9052, tm);
+
+ if (ret)
+ return ret;
+
+ ret = da9052_rtc_enable_alarm(da9052, 1);
+
+ return ret;
+}
+
+static int da9052_rtc_update_irq_enable(struct device *dev,
+ unsigned int enabled)
+{
+ struct da9052_rtc *priv = dev_get_drvdata(dev);
+ int ret = -ENODATA;
+
+ da9052_lock(priv->da9052);
+
+ ret = (enabled ? da9052_rtc_unmask_irq : da9052_rtc_mask_irq)
+ (priv->da9052);
+
+ da9052_unlock(priv->da9052);
+
+ return ret;
+}
+
+static int da9052_rtc_alarm_irq_enable(struct device *dev,
+ unsigned int enabled)
+{
+ struct da9052_rtc *priv = dev_get_drvdata(dev);
+
+ if (enabled)
+ return da9052_rtc_enable_alarm(priv->da9052, enabled);
+ else
+ return da9052_rtc_enable_alarm(priv->da9052, enabled);
+}
+
+static const struct rtc_class_ops da9052_rtc_ops = {
+ .read_time = da9052_rtc_class_ops_gettime,
+ .set_time = da9052_rtc_class_ops_settime,
+ .read_alarm = da9052_rtc_readalarm,
+ .set_alarm = da9052_rtc_setalarm,
+#if 0
+ .update_irq_enable = da9052_rtc_update_irq_enable,
+ .alarm_irq_enable = da9052_rtc_alarm_irq_enable,
+#endif
+};
+
+
+static int __devinit da9052_rtc_probe(struct platform_device *pdev)
+{
+ int ret;
+ struct da9052_rtc *priv;
+ struct da9052_ssc_msg ssc_msg;
+ priv = kzalloc(sizeof(*priv), GFP_KERNEL);
+ if (!priv)
+ return -ENOMEM;
+
+ priv->da9052 = dev_get_drvdata(pdev->dev.parent);
+ platform_set_drvdata(pdev, priv);
+
+ /* KPIT added to support sysfs wakealarm attribute */
+ pdev->dev.power.can_wakeup = 1;
+ /* KPIT added to support sysfs wakealarm attribute */
+
+ /* Set the EH structure */
+ priv->eh_data.eve_type = ALARM_EVE;
+ priv->eh_data.call_back = &da9052_rtc_notifier;
+ ret = priv->da9052->register_event_notifier(priv->da9052,
+ &priv->eh_data);
+ if (ret)
+ goto err_register_alarm;
+
+ priv->is_min_alarm = 1;
+ priv->enable_tick_alarm = 1;
+ priv->enable_clk_buffer = 1;
+ priv->set_osc_trim_freq = 5;
+ /* Enable/Disable TICK Alarm */
+ /* Read ALARM YEAR register */
+ ssc_msg.addr = DA9052_ALARMY_REG;
+ ssc_msg.data = 0;
+
+ da9052_lock(priv->da9052);
+ ret = priv->da9052->read(priv->da9052, &ssc_msg);
+ if (ret != 0) {
+ da9052_unlock(priv->da9052);
+ goto err_ssc_comm;
+ }
+
+ if (priv->enable_tick_alarm)
+ ssc_msg.data = (ssc_msg.data | DA9052_ALARMY_TICKON);
+ else
+ ssc_msg.data =
+ ((ssc_msg.data & ~(DA9052_ALARMY_TICKON)));
+
+ ret = priv->da9052->write(priv->da9052, &ssc_msg);
+ if (ret != 0) {
+ da9052_unlock(priv->da9052);
+ goto err_ssc_comm;
+ }
+
+ /* Set TICK Alarm to 1 minute or 1 sec */
+ /* Read ALARM MINUTES register */
+ ssc_msg.addr = DA9052_ALARMMI_REG;
+ ssc_msg.data = 0;
+
+ ret = priv->da9052->read(priv->da9052, &ssc_msg);
+ if (ret != 0) {
+ da9052_unlock(priv->da9052);
+ goto err_ssc_comm;
+ }
+
+ if (priv->is_min_alarm)
+ /* Set 1 minute tick type */
+ ssc_msg.data = (ssc_msg.data | DA9052_ALARMMI_TICKTYPE);
+ else
+ /* Set 1 sec tick type */
+ ssc_msg.data = (ssc_msg.data & ~(DA9052_ALARMMI_TICKTYPE));
+
+ ret = priv->da9052->write(priv->da9052, &ssc_msg);
+ if (ret != 0) {
+ da9052_unlock(priv->da9052);
+ goto err_ssc_comm;
+ }
+
+ /* Enable/Disable Clock buffer in Power Down Mode */
+ ssc_msg.addr = DA9052_PDDIS_REG;
+ ssc_msg.data = 0;
+
+ ret = priv->da9052->read(priv->da9052, &ssc_msg);
+ if (ret != 0) {
+ da9052_unlock(priv->da9052);
+ goto err_ssc_comm;
+ }
+
+ if (priv->enable_clk_buffer)
+ ssc_msg.data = (ssc_msg.data | DA9052_PDDIS_OUT32KPD);
+ else
+ ssc_msg.data = (ssc_msg.data & ~(DA9052_PDDIS_OUT32KPD));
+
+ ret = priv->da9052->write(priv->da9052, &ssc_msg);
+ if (ret != 0) {
+ da9052_unlock(priv->da9052);
+ goto err_ssc_comm;
+ }
+
+ /* Set clock trim frequency value */
+ ssc_msg.addr = DA9052_OSCTRIM_REG;
+ ssc_msg.data = priv->set_osc_trim_freq;
+
+ ret = priv->da9052->write(priv->da9052, &ssc_msg);
+ if (ret != 0) {
+ da9052_unlock(priv->da9052);
+ goto err_ssc_comm;
+ }
+ da9052_unlock(priv->da9052);
+
+ priv->rtc = rtc_device_register(pdev->name,
+ &pdev->dev, &da9052_rtc_ops, THIS_MODULE);
+ if (IS_ERR(priv->rtc)) {
+ ret = PTR_ERR(priv->rtc);
+ goto err_ssc_comm;
+ }
+ return 0;
+
+err_ssc_comm:
+ priv->da9052->unregister_event_notifier
+ (priv->da9052, &priv->eh_data);
+err_register_alarm:
+ platform_set_drvdata(pdev, NULL);
+ kfree(priv);
+
+ return ret;
+}
+
+static int __devexit da9052_rtc_remove(struct platform_device *pdev)
+{
+ struct da9052_rtc *priv = platform_get_drvdata(pdev);
+ rtc_device_unregister(priv->rtc);
+ da9052_lock(priv->da9052);
+ priv->da9052->unregister_event_notifier(priv->da9052, &priv->eh_data);
+ da9052_unlock(priv->da9052);
+ platform_set_drvdata(pdev, NULL);
+ kfree(priv);
+ return 0;
+}
+
+static struct platform_driver da9052_rtc_driver = {
+ .probe = da9052_rtc_probe,
+ .remove = __devexit_p(da9052_rtc_remove),
+ .driver = {
+ .name = DRIVER_NAME,
+ .owner = THIS_MODULE,
+ },
+};
+
+
+static int __init da9052_rtc_init(void)
+{
+ return platform_driver_register(&da9052_rtc_driver);
+}
+module_init(da9052_rtc_init);
+
+static void __exit da9052_rtc_exit(void)
+{
+ platform_driver_unregister(&da9052_rtc_driver);
+}
+module_exit(da9052_rtc_exit);
+
+MODULE_AUTHOR("Dialog Semiconductor Ltd <dchen@diasemi.com>");
+MODULE_DESCRIPTION("RTC driver for Dialog DA9052 PMIC");
+MODULE_LICENSE("GPL v2");
+MODULE_ALIAS("platform:" DRIVER_NAME);