diff options
| author | Eric Tashakkor <w36098@motorola.com> | 2014-05-28 15:06:02 -0500 |
|---|---|---|
| committer | ERIC TASHAKKOR <w36098@motorola.com> | 2014-05-29 19:50:47 +0000 |
| commit | 987ba520f90fcdbb32a1f84ef8b168507d700e30 (patch) | |
| tree | 2394ffd2a210caa57e93f06e72350de623e319a5 /drivers/rtc/rtc-sensorhub.c | |
| parent | 9c1764fef85c8f34489dfe73183b258bbfced4e1 (diff) | |
| download | olio-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/rtc-sensorhub.c')
| -rw-r--r-- | drivers/rtc/rtc-sensorhub.c | 221 |
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); |