summaryrefslogtreecommitdiff
path: root/drivers/rtc
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/rtc')
-rw-r--r--drivers/rtc/Kconfig3
-rw-r--r--drivers/rtc/rtc-sensorhub.c119
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;
}