diff options
Diffstat (limited to 'drivers/rtc')
| -rw-r--r-- | drivers/rtc/Kconfig | 3 | ||||
| -rw-r--r-- | drivers/rtc/rtc-sensorhub.c | 119 |
2 files changed, 108 insertions, 14 deletions
diff --git a/drivers/rtc/Kconfig b/drivers/rtc/Kconfig index 47128ffc013..6d1b57e3a64 100644 --- a/drivers/rtc/Kconfig +++ b/drivers/rtc/Kconfig @@ -490,8 +490,9 @@ config RTC_DRV_RV3029C2 config RTC_DRV_SENSORHUB bool "SensorHub based RTC" + depends on MFD_M4SENSORHUB help - If you say yes here you get support for the SensorHub based + If you say yes here you get support for M4 SensorHub based RTC. endif # I2C diff --git a/drivers/rtc/rtc-sensorhub.c b/drivers/rtc/rtc-sensorhub.c index 7560170f309..46b68ce7e70 100644 --- a/drivers/rtc/rtc-sensorhub.c +++ b/drivers/rtc/rtc-sensorhub.c @@ -15,10 +15,17 @@ #include <linux/m4sensorhub.h> #include <linux/m4sensorhub/m4sensorhub_registers.h> +static bool g_m4ready; + static int rtc_sensorhub_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alrm) { pr_err("%s:\n", __func__); + + if (!g_m4ready) { + pr_err("%s: ignore func call\n", __func__); + return -EIO; + } /* TODO : implement a real handler*/ return 0; } @@ -27,17 +34,20 @@ static int rtc_sensorhub_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alrm) { pr_err("%s:\n", __func__); + + if (!g_m4ready) { + pr_err("%s: ignore func call\n", __func__); + return -EIO; + } /* TODO : implement a real handler*/ return 0; } -static int rtc_sensorhub_rtc_read_time(struct device *dev, - struct rtc_time *tm) +static int rtc_sensorhub_get_rtc_from_m4(struct rtc_time *p_tm) { + struct m4sensorhub_data *p_m4_drvdata; u32 seconds; - - struct m4sensorhub_data *p_m4_drvdata = - m4sensorhub_client_get_drvdata(); + p_m4_drvdata = m4sensorhub_client_get_drvdata(); if (m4sensorhub_reg_getsize(p_m4_drvdata, M4SH_REG_GENERAL_UTC) != m4sensorhub_reg_read( @@ -47,21 +57,44 @@ static int rtc_sensorhub_rtc_read_time(struct device *dev, return -EIO; } - rtc_time_to_tm(seconds, tm); + rtc_time_to_tm(seconds, p_tm); return 0; } +static int rtc_sensorhub_rtc_read_time(struct device *dev, + struct rtc_time *p_tm) +{ + int err; + + if (!g_m4ready) { + pr_err("%s: func called, RTC hardware not ready\n", __func__); + /* M4 driver is not yet ready, just give the time since boot + and treat boot as start of epoch */ + rtc_time_to_tm(get_seconds(), p_tm); + return 0; + } + + err = rtc_sensorhub_get_rtc_from_m4(p_tm); + + return err; +} + static int rtc_sensorhub_rtc_set_time(struct device *dev, - struct rtc_time *tm) + struct rtc_time *p_tm) { u32 seconds; unsigned long sec; - struct m4sensorhub_data *p_m4_drvdata = - m4sensorhub_client_get_drvdata(); + struct m4sensorhub_data *p_m4_drvdata; + + if (!g_m4ready) { + pr_err("%s: ignore func call\n", __func__); + return 0; + } + p_m4_drvdata = m4sensorhub_client_get_drvdata(); /* M4 expects the UTC time in seconds from Jan 1, 1970, basically epoch_time in seconds */ - rtc_tm_to_time(tm, &sec); + rtc_tm_to_time(p_tm, &sec); /* M4 accepts time as u32*/ seconds = (u32) sec; @@ -81,6 +114,11 @@ static int rtc_sensorhub_rtc_set_mmss(struct device *dev, unsigned long secs) { /* TODO : implement a real handler*/ dev_info(dev, "%s, secs = %lu\n", __func__, secs); + + if (!g_m4ready) { + pr_err("%s: ignore func call\n", __func__); + return -EIO; + } return 0; } @@ -107,7 +145,10 @@ static int rtc_sensorhub_rtc_alarm_irq_enable(struct device *dev, unsigned int enable) { /* TODO : implement a real handler*/ - pr_err("%s:\n", __func__); + if (!g_m4ready) { + pr_err("%s: ignore func call\n", __func__); + return 0; + } return 0; } @@ -125,7 +166,10 @@ static ssize_t rtc_sensorhub_irq_show(struct device *dev, struct device_attribute *attr, char *buf) { /* TODO : implement a real handler*/ - pr_err("%s:\n", __func__); + if (!g_m4ready) { + pr_err("%s: ignore func call\n", __func__); + return -EIO; + } return sprintf(buf, "%d\n", 42); } static ssize_t rtc_sensorhub_irq_store(struct device *dev, @@ -134,12 +178,48 @@ static ssize_t rtc_sensorhub_irq_store(struct device *dev, { /* TODO : implement a real handler*/ pr_err("%s:\n", __func__); + if (!g_m4ready) { + pr_err("%s: ignore func call\n", __func__); + return -EIO; + } return count; } static DEVICE_ATTR(irq, S_IRUGO | S_IWUSR, rtc_sensorhub_irq_show, rtc_sensorhub_irq_store); +static int rtc_sensorhub_init(struct m4sensorhub_data *m4sensorhub) +{ + struct rtc_time rtc; + int err; + struct timespec tv; + + g_m4ready = true; + + /* read RTC time from M4 and set the system time */ + err = rtc_sensorhub_get_rtc_from_m4(&rtc); + if (err) { + pr_err("%s: get_rtc failed\n", __func__); + return 0; + } + + rtc_tm_to_time(&rtc, &tv.tv_sec); + + err = do_settimeofday(&tv); + if (err) { + pr_err("%s: settimeofday failed\n", __func__); + return 0; + } + + pr_info("setting system clock to " + "%d-%02d-%02d %02d:%02d:%02d UTC (%u)\n", + rtc.tm_year + 1900, rtc.tm_mon + 1, rtc.tm_mday, + rtc.tm_hour, rtc.tm_min, rtc.tm_sec, + (unsigned int) tv.tv_sec); + + return 0; +} + static int rtc_sensorhub_probe(struct platform_device *plat_dev) { int err; @@ -161,12 +241,22 @@ static int rtc_sensorhub_probe(struct platform_device *plat_dev) err = device_create_file(&plat_dev->dev, &dev_attr_irq); if (err) - goto err_disable_wakeup; + goto err_unregister_rtc; + + err = m4sensorhub_register_initcall(rtc_sensorhub_init); + if (err) { + pr_err("%s: can't register init with m4\n", __func__); + goto err_remove_file; + } platform_set_drvdata(plat_dev, rtc); return 0; +err_remove_file: + device_remove_file(&plat_dev->dev, &dev_attr_irq); +err_unregister_rtc: + devm_rtc_device_unregister(&plat_dev->dev, rtc); err_disable_wakeup: device_init_wakeup(&plat_dev->dev, false); return err; @@ -174,8 +264,11 @@ err_disable_wakeup: static int rtc_sensorhub_remove(struct platform_device *plat_dev) { + struct rtc_device *rtc = platform_get_drvdata(plat_dev); device_remove_file(&plat_dev->dev, &dev_attr_irq); device_init_wakeup(&plat_dev->dev, false); + devm_rtc_device_unregister(&plat_dev->dev, rtc); + m4sensorhub_unregister_initcall(rtc_sensorhub_init); return 0; } |