summaryrefslogtreecommitdiff
path: root/drivers/rtc
diff options
context:
space:
mode:
authorEric Tashakkor <w36098@motorola.com>2014-05-28 15:06:02 -0500
committerERIC TASHAKKOR <w36098@motorola.com>2014-05-29 19:50:47 +0000
commit987ba520f90fcdbb32a1f84ef8b168507d700e30 (patch)
tree2394ffd2a210caa57e93f06e72350de623e319a5 /drivers/rtc
parent9c1764fef85c8f34489dfe73183b258bbfced4e1 (diff)
downloadolio-linux-3.10-987ba520f90fcdbb32a1f84ef8b168507d700e30.tar.xz
olio-linux-3.10-987ba520f90fcdbb32a1f84ef8b168507d700e30.zip
IKXCLOCK-1703 Add M4 Pre-Flash Callback for RTC
Added a pre-flash callback system for drivers with timing restrictions like RTC Updated the RTC driver to save and use set time requests until M4 is ready Fixed a bug where uninitialized memory was preventing the time being set Minor clean up of driver files to meet checkpatch style requirements Change-Id: I9e03f373226e678e8e884c836f68fcb265f39a57 Signed-off-by: Eric Tashakkor <w36098@motorola.com>
Diffstat (limited to 'drivers/rtc')
-rw-r--r--drivers/rtc/rtc-sensorhub.c221
1 files changed, 155 insertions, 66 deletions
diff --git a/drivers/rtc/rtc-sensorhub.c b/drivers/rtc/rtc-sensorhub.c
index 4939ff8874f..c57d7ea95a5 100644
--- a/drivers/rtc/rtc-sensorhub.c
+++ b/drivers/rtc/rtc-sensorhub.c
@@ -22,9 +22,14 @@
#define DRIVER_NAME "rtc-sensorhub"
struct rtc_sensorhub_private_data {
- struct rtc_device *p_rtc;
- struct m4sensorhub_data *p_m4sensorhub_data;
- struct rtc_wkalrm next_alarm_set;
+ struct rtc_device *p_rtc;
+ struct m4sensorhub_data *p_m4sensorhub_data;
+ struct rtc_wkalrm next_alarm_set;
+
+ unsigned long m4_seconds_cached;
+ unsigned long m4_boot_cached;
+ unsigned long sys_seconds_cached;
+ unsigned long sys_boot_cached;
};
static int rtc_sensorhub_rtc_alarm_irq_enable(struct device *p_dev,
@@ -38,19 +43,22 @@ static int rtc_sensorhub_rtc_alarm_irq_enable(struct device *p_dev,
dev_dbg(p_dev, "enable is %u\n", enable);
if (!(p_priv_data->p_m4sensorhub_data)) {
- dev_err(p_dev, "RTC hardware not ready yet\n");
+ dev_err(p_dev, "Cannot %s alarm--RTC hardware not ready yet\n",
+ (enable ? "set" : "clear"));
return -EIO;
}
- if (enable == 1)
+ if (enable == 1) {
err = m4sensorhub_irq_enable(p_priv_data->p_m4sensorhub_data,
M4SH_IRQ_AP_ALARM_EXPIRED);
- else
+ if (err < 0)
+ dev_err(p_dev, "Enabling IRQ failed (%d)\n", err);
+ } else {
err = m4sensorhub_irq_disable(p_priv_data->p_m4sensorhub_data,
M4SH_IRQ_AP_ALARM_EXPIRED);
-
- if (err < 0)
- dev_err(p_dev, "couldn't enable irq\n");
+ if (err < 0)
+ dev_err(p_dev, "Disabling IRQ failed (%d)\n", err);
+ }
return err;
}
@@ -63,13 +71,10 @@ static int rtc_sensorhub_rtc_read_alarm(struct device *p_dev,
platform_get_drvdata(p_platdev);
struct rtc_time rtc = p_alrm->time;
- memcpy(
- p_alrm, &(p_priv_data->next_alarm_set),
- sizeof(struct rtc_wkalrm)
- );
+ memcpy(p_alrm, &(p_priv_data->next_alarm_set),
+ sizeof(struct rtc_wkalrm));
- dev_info(p_dev, "alarm read for "
- "%d-%02d-%02d %02d:%02d:%02d UTC\n",
+ dev_info(p_dev, "alarm read for %d-%02d-%02d %02d:%02d:%02d UTC\n",
rtc.tm_year + 1900, rtc.tm_mon + 1, rtc.tm_mday,
rtc.tm_hour, rtc.tm_min, rtc.tm_sec);
@@ -90,8 +95,7 @@ static int rtc_sensorhub_rtc_set_alarm(struct device *p_dev,
unsigned long requested_time, time_diff;
int ret;
- dev_info(p_dev, "alarm requested for "
- "%d-%02d-%02d %02d:%02d:%02d UTC\n",
+ dev_info(p_dev, "alarm requested for %d-%02d-%02d %02d:%02d:%02d UTC\n",
rtc.tm_year + 1900, rtc.tm_mon + 1, rtc.tm_mday,
rtc.tm_hour, rtc.tm_min, rtc.tm_sec);
@@ -111,18 +115,16 @@ static int rtc_sensorhub_rtc_set_alarm(struct device *p_dev,
time_diff = requested_time - tv_current.tv_sec;
if (time_diff >= SECONDS_IN_DAY || time_diff <= 0) {
- dev_err(p_dev, "requested alarm out of range, rejecting alarm\n");
+ dev_err(p_dev,
+ "requested alarm out of range, rejecting alarm\n");
return -EINVAL;
}
- if (m4sensorhub_reg_getsize(
- p_m4_drvdata,
- M4SH_REG_GENERAL_APALARM
- ) != m4sensorhub_reg_write(
- p_m4_drvdata, M4SH_REG_GENERAL_APALARM,
+ if (m4sensorhub_reg_getsize(p_m4_drvdata, M4SH_REG_GENERAL_APALARM) !=
+ m4sensorhub_reg_write(p_m4_drvdata, M4SH_REG_GENERAL_APALARM,
(char *)&time_diff, m4sh_no_mask)) {
- dev_err(p_dev, "Failed to set M4 alarm!\n");
- return -EIO;
+ dev_err(p_dev, "Failed to set M4 alarm!\n");
+ return -EIO;
}
ret = rtc_sensorhub_rtc_alarm_irq_enable(p_dev, p_alrm->enabled);
@@ -132,23 +134,20 @@ static int rtc_sensorhub_rtc_set_alarm(struct device *p_dev,
}
/* Store the info abt this alarm in our local datastructure */
- memcpy(
- &(p_priv_data->next_alarm_set), p_alrm,
- sizeof(struct rtc_wkalrm)
- );
+ memcpy(&(p_priv_data->next_alarm_set), p_alrm,
+ sizeof(struct rtc_wkalrm));
return 0;
}
static int rtc_sensorhub_get_rtc_from_m4(struct rtc_time *p_tm,
struct m4sensorhub_data *p_m4_drvdata)
{
- u32 seconds;
+ u32 seconds = 0;
- if (m4sensorhub_reg_getsize(p_m4_drvdata,
- M4SH_REG_GENERAL_UTC) != m4sensorhub_reg_read(
- p_m4_drvdata, M4SH_REG_GENERAL_UTC,
+ if (m4sensorhub_reg_getsize(p_m4_drvdata, M4SH_REG_GENERAL_UTC) !=
+ m4sensorhub_reg_read(p_m4_drvdata, M4SH_REG_GENERAL_UTC,
(char *)&seconds)) {
- pr_err("%s: Failed get M4 clock!\n", DRIVER_NAME);
+ pr_err("%s: Failed to get M4 clock!\n", DRIVER_NAME);
return -EIO;
}
@@ -159,16 +158,26 @@ static int rtc_sensorhub_get_rtc_from_m4(struct rtc_time *p_tm,
static int rtc_sensorhub_rtc_read_time(struct device *p_dev,
struct rtc_time *p_tm)
{
- int err;
+ int err = 0;
struct platform_device *p_platdev = to_platform_device(p_dev);
struct rtc_sensorhub_private_data *p_priv_data =
platform_get_drvdata(p_platdev);
if (!(p_priv_data->p_m4sensorhub_data)) {
- dev_err(p_dev, "read time, but RTC hardware not ready\n");
- /* 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);
+ if ((p_priv_data->sys_seconds_cached != 0) &&
+ (p_priv_data->sys_boot_cached != 0)) {
+ dev_err(p_dev,
+ "Using saved set RTC time (hardware not ready)\n");
+ /* Use saved settime request (will go to M4) */
+ rtc_time_to_tm(p_priv_data->sys_seconds_cached +
+ get_seconds() - p_priv_data->sys_boot_cached, p_tm);
+ } else {
+ dev_err(p_dev,
+ "Using cached M4 RTC time (hardware not ready)\n");
+ /* Use cached time from M4 */
+ rtc_time_to_tm(p_priv_data->m4_seconds_cached +
+ get_seconds() - p_priv_data->m4_boot_cached, p_tm);
+ }
return 0;
}
@@ -181,36 +190,37 @@ static int rtc_sensorhub_rtc_read_time(struct device *p_dev,
static int rtc_sensorhub_rtc_set_time(struct device *p_dev,
struct rtc_time *p_tm)
{
- unsigned long sec;
+ unsigned long sec = 0;
struct platform_device *p_platdev = to_platform_device(p_dev);
struct rtc_sensorhub_private_data *p_priv_data =
platform_get_drvdata(p_platdev);
struct m4sensorhub_data *p_m4_drvdata =
p_priv_data->p_m4sensorhub_data;
- if (!(p_m4_drvdata)) {
- dev_err(p_dev, "set time, but M4 not ready, ignore func call\n");
- return 0;
- }
-
/* M4 expects the UTC time in seconds from Jan 1, 1970,
basically epoch_time in seconds */
rtc_tm_to_time(p_tm, &sec);
+ if (!(p_m4_drvdata)) {
+ dev_err(p_dev,
+ "Saving set time request (hardware not ready)\n");
+ p_priv_data->sys_seconds_cached = sec;
+ p_priv_data->sys_boot_cached = get_seconds();
+ return 0;
+ }
+
/* M4 accepts time as u32*/
- if (m4sensorhub_reg_getsize(p_m4_drvdata,
- M4SH_REG_GENERAL_UTC) != m4sensorhub_reg_write(
- p_m4_drvdata, M4SH_REG_GENERAL_UTC,
+ if (m4sensorhub_reg_getsize(p_m4_drvdata, M4SH_REG_GENERAL_UTC) !=
+ m4sensorhub_reg_write(p_m4_drvdata, M4SH_REG_GENERAL_UTC,
(char *)&sec, m4sh_no_mask)) {
- dev_err(p_dev, "set time, but failed to set M4 clock!\n");
+ dev_err(p_dev,
+ "set time, but failed to set M4 clock!\n");
return -EIO;
}
return 0;
}
-
-
static const struct rtc_class_ops rtc_sensorhub_rtc_ops = {
.read_time = rtc_sensorhub_rtc_read_time,
.set_time = rtc_sensorhub_rtc_set_time,
@@ -219,8 +229,55 @@ static const struct rtc_class_ops rtc_sensorhub_rtc_ops = {
.alarm_irq_enable = rtc_sensorhub_rtc_alarm_irq_enable,
};
+static int rtc_sensorhub_preflash(struct init_calldata *p_arg)
+{
+ int err = 0;
+ uint32_t seconds = 0;
+ int size = 0;
+ struct rtc_sensorhub_private_data *rtcpd = NULL;
+ struct m4sensorhub_data *m4 = NULL;
+
+ if (p_arg == NULL) {
+ pr_err("%s: No callback data received.\n", __func__);
+ err = -ENODATA;
+ goto rtc_sensorhub_preflash_fail;
+ } else if (p_arg->p_data == NULL) {
+ pr_err("%s: No private data received.\n", __func__);
+ err = -ENODATA;
+ goto rtc_sensorhub_preflash_fail;
+ } else if (p_arg->p_m4sensorhub_data == NULL) {
+ pr_err("%s: M4 data is NULL.\n", __func__);
+ err = -ENODATA;
+ goto rtc_sensorhub_preflash_fail;
+ }
+
+ /*
+ * NOTE: We don't want to save the M4 data struct;
+ * M4 will be reflashed after this callback returns
+ * (thus the struct will become invalid but we have
+ * no way to communicate that to the rest of the driver).
+ */
+ rtcpd = p_arg->p_data;
+ m4 = p_arg->p_m4sensorhub_data;
+ size = m4sensorhub_reg_getsize(m4, M4SH_REG_GENERAL_UTC);
+ err = m4sensorhub_reg_read(m4, M4SH_REG_GENERAL_UTC, (char *)&seconds);
+ if (err < 0) {
+ pr_err("%s: Failed to read RTC seconds from M4.\n", __func__);
+ goto rtc_sensorhub_preflash_fail;
+ } else if (err != size) {
+ pr_err("%s: Read %d bytes instead of %d.\n",
+ __func__, err, size);
+ }
+
+ rtcpd->m4_seconds_cached = seconds;
+ rtcpd->m4_boot_cached = get_seconds();
+
+rtc_sensorhub_preflash_fail:
+ return err;
+}
+
static void rtc_handle_sensorhub_irq(enum m4sensorhub_irqs int_event,
- void *p_data)
+ void *p_data)
{
struct rtc_sensorhub_private_data *p_priv_data =
(struct rtc_sensorhub_private_data *)(p_data);
@@ -236,34 +293,56 @@ static int rtc_sensorhub_init(struct init_calldata *p_arg)
struct timespec tv;
struct rtc_sensorhub_private_data *p_priv_data =
(struct rtc_sensorhub_private_data *)(p_arg->p_data);
+ uint32_t seconds = 0;
p_priv_data->p_m4sensorhub_data = p_arg->p_m4sensorhub_data;
- /* read RTC time from M4 and set the system time */
- err = rtc_sensorhub_get_rtc_from_m4(&rtc,
- p_priv_data->p_m4sensorhub_data);
- if (err) {
- pr_err("%s: get_rtc failed\n", DRIVER_NAME);
- return 0;
+ if ((p_priv_data->sys_seconds_cached != 0) &&
+ (p_priv_data->sys_boot_cached != 0)) {
+ pr_err("%s: Setting M4 to a saved time request\n", __func__);
+ seconds = p_priv_data->sys_seconds_cached +
+ get_seconds() - p_priv_data->sys_boot_cached;
+ if (m4sensorhub_reg_getsize(p_priv_data->p_m4sensorhub_data,
+ M4SH_REG_GENERAL_UTC) != m4sensorhub_reg_write(
+ p_priv_data->p_m4sensorhub_data, M4SH_REG_GENERAL_UTC,
+ (char *)&seconds, m4sh_no_mask)) {
+ pr_err("%s: Failed to set M4 RTC\n",
+ __func__);
+ return 0;
+ }
+ /*
+ * We don't write directly to tv_sec here because we want
+ * to print below the system clock we are setting,
+ * which means we need to populate rtc anyway.
+ */
+ rtc_time_to_tm(seconds, &rtc);
+ } else {
+ /* read RTC time from M4 and set the system time */
+ err = rtc_sensorhub_get_rtc_from_m4(&rtc,
+ p_priv_data->p_m4sensorhub_data);
+ if (err) {
+ pr_err("%s: get_rtc failed\n", DRIVER_NAME);
+ return 0;
+ }
}
+ tv.tv_nsec = 0; /* Initialize variable or do_settimeofday will fail */
rtc_tm_to_time(&rtc, &tv.tv_sec);
err = do_settimeofday(&tv);
if (err)
- pr_err("%s: settimeofday failed\n", DRIVER_NAME);
+ pr_err("%s: settimeofday failed (err=%d)\n", DRIVER_NAME, err);
- pr_info("setting system clock to "
- "%d-%02d-%02d %02d:%02d:%02d UTC (%u)\n",
+ pr_info("%s %d-%02d-%02d %02d:%02d:%02d UTC (%u)\n",
+ "setting system clock to",
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);
/* register an irq handler*/
err = m4sensorhub_irq_register(p_priv_data->p_m4sensorhub_data,
- M4SH_IRQ_AP_ALARM_EXPIRED,
- rtc_handle_sensorhub_irq,
- p_priv_data, 1);
+ M4SH_IRQ_AP_ALARM_EXPIRED, rtc_handle_sensorhub_irq,
+ p_priv_data, 1);
if (err < 0)
pr_err("%s: irq register failed\n", DRIVER_NAME);
@@ -296,7 +375,7 @@ static int rtc_sensorhub_probe(struct platform_device *p_platdev)
}
p_rtc = devm_rtc_device_register(&p_platdev->dev, "rtc_sensorhub",
- &rtc_sensorhub_rtc_ops, THIS_MODULE);
+ &rtc_sensorhub_rtc_ops, THIS_MODULE);
if (IS_ERR(p_rtc)) {
err = PTR_ERR(p_rtc);
@@ -305,14 +384,24 @@ static int rtc_sensorhub_probe(struct platform_device *p_platdev)
p_priv_data->p_rtc = p_rtc;
+ err = m4sensorhub_register_preflash_callback(rtc_sensorhub_preflash,
+ p_priv_data);
+ if (err < 0) {
+ dev_err(&(p_platdev->dev),
+ "Failed to register M4 preflash callback\n");
+ goto err_unregister_rtc;
+ }
+
err = m4sensorhub_register_initcall(rtc_sensorhub_init, p_priv_data);
if (err) {
dev_err(&(p_platdev->dev), "can't register init with m4\n");
- goto err_unregister_rtc;
+ goto err_unregister_preflash_callback;
}
return 0;
+err_unregister_preflash_callback:
+ m4sensorhub_unregister_preflash_callback(rtc_sensorhub_preflash);
err_unregister_rtc:
devm_rtc_device_unregister(&p_platdev->dev, p_rtc);
kfree(p_rtc);