diff options
| author | Amit Jain <ajain@motorola.com> | 2014-03-18 13:17:30 -0500 |
|---|---|---|
| committer | Amit Jain <ajain@motorola.com> | 2014-03-19 17:53:11 +0000 |
| commit | 6d74f0b71a4d80398fe74735812cd71de79b433c (patch) | |
| tree | fa55c09379ffb6130cf4526350467a4421255c07 /drivers/rtc/rtc-sensorhub.c | |
| parent | acf177dd1abd73e873e244fcb575569d3338ef5e (diff) | |
| download | olio-linux-3.10-6d74f0b71a4d80398fe74735812cd71de79b433c.tar.xz olio-linux-3.10-6d74f0b71a4d80398fe74735812cd71de79b433c.zip | |
IKXCLOCK-376: RTC driver and sensorhub based alarm
Diffstat (limited to 'drivers/rtc/rtc-sensorhub.c')
| -rw-r--r-- | drivers/rtc/rtc-sensorhub.c | 256 |
1 files changed, 152 insertions, 104 deletions
diff --git a/drivers/rtc/rtc-sensorhub.c b/drivers/rtc/rtc-sensorhub.c index 8c4a4e9b1fc..92e19700c3b 100644 --- a/drivers/rtc/rtc-sensorhub.c +++ b/drivers/rtc/rtc-sensorhub.c @@ -9,48 +9,133 @@ */ #include <linux/module.h> +#include <linux/device.h> #include <linux/err.h> #include <linux/rtc.h> #include <linux/slab.h> #include <linux/platform_device.h> #include <linux/m4sensorhub.h> #include <linux/m4sensorhub/m4sensorhub_registers.h> +#include <linux/m4sensorhub/m4sensorhub_irqs.h> + +#define SECONDS_IN_DAY (24*60*60) +#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; }; -static int rtc_sensorhub_rtc_read_alarm(struct device *dev, - struct rtc_wkalrm *alrm) +static int rtc_sensorhub_rtc_alarm_irq_enable(struct device *p_dev, + unsigned int enable) { - struct platform_device *pdev = to_platform_device(dev); + int err = 0; + struct platform_device *p_platdev = to_platform_device(p_dev); struct rtc_sensorhub_private_data *p_priv_data = - platform_get_drvdata(pdev); + platform_get_drvdata(p_platdev); - pr_err("%s:\n", __func__); + dev_dbg(p_dev, "enable is %u\n", enable); if (!(p_priv_data->p_m4sensorhub_data)) { - pr_err("%s: ignore func call\n", __func__); + dev_err(p_dev, "RTC hardware not ready yet\n"); return -EIO; } - /* TODO : implement a real handler*/ + + if (enable == 1) + err = m4sensorhub_irq_enable(p_priv_data->p_m4sensorhub_data, + M4SH_IRQ_AP_ALARM_EXPIRED); + 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"); + + return err; +} + +static int rtc_sensorhub_rtc_read_alarm(struct device *p_dev, + struct rtc_wkalrm *p_alrm) +{ + struct platform_device *p_platdev = to_platform_device(p_dev); + struct rtc_sensorhub_private_data *p_priv_data = + 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) + ); + + 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); + return 0; } -static int rtc_sensorhub_rtc_set_alarm(struct device *dev, - struct rtc_wkalrm *alrm) +static int rtc_sensorhub_rtc_set_alarm(struct device *p_dev, + struct rtc_wkalrm *p_alrm) { - struct platform_device *pdev = to_platform_device(dev); + struct platform_device *p_platdev = to_platform_device(p_dev); struct rtc_sensorhub_private_data *p_priv_data = - platform_get_drvdata(pdev); - pr_err("%s:\n", __func__); + platform_get_drvdata(p_platdev); + struct m4sensorhub_data *p_m4_drvdata = + p_priv_data->p_m4sensorhub_data; + struct rtc_time rtc = p_alrm->time; - if (!(p_priv_data->p_m4sensorhub_data)) { - pr_err("%s: ignore func call\n", __func__); + struct timeval tv_current; + unsigned long requested_time, time_diff; + int ret; + + 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); + + if (!p_m4_drvdata) { + dev_err(p_dev, "M4 not ready, ignore func call\n"); return -EIO; } - /* TODO : implement a real handler*/ + + rtc_tm_to_time(&rtc, &requested_time); + do_gettimeofday(&tv_current); + + /* make sure alarm requested is for future*/ + if (requested_time < tv_current.tv_sec) { + dev_err(p_dev, "alarm in past, rejecting\n"); + return -EINVAL; + } + + 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"); + return -EINVAL; + } + + 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; + } + + ret = rtc_sensorhub_rtc_alarm_irq_enable(p_dev, p_alrm->enabled); + if (ret < 0) { + dev_err(p_dev, "failed enabling irq for alarm\n"); + return ret; + } + + /* Store the info abt this alarm in our local datastructure */ + memcpy( + &(p_priv_data->next_alarm_set), p_alrm, + sizeof(struct rtc_wkalrm) + ); return 0; } @@ -63,7 +148,7 @@ static int rtc_sensorhub_get_rtc_from_m4(struct rtc_time *p_tm, M4SH_REG_GENERAL_UTC) != m4sensorhub_reg_read( p_m4_drvdata, M4SH_REG_GENERAL_UTC, (char *)&seconds)) { - pr_err("%s: Failed get M4 clock!\n", __func__); + pr_err("%s: Failed get M4 clock!\n", DRIVER_NAME); return -EIO; } @@ -71,16 +156,16 @@ static int rtc_sensorhub_get_rtc_from_m4(struct rtc_time *p_tm, return 0; } -static int rtc_sensorhub_rtc_read_time(struct device *dev, +static int rtc_sensorhub_rtc_read_time(struct device *p_dev, struct rtc_time *p_tm) { int err; - struct platform_device *pdev = to_platform_device(dev); + struct platform_device *p_platdev = to_platform_device(p_dev); struct rtc_sensorhub_private_data *p_priv_data = - platform_get_drvdata(pdev); + platform_get_drvdata(p_platdev); if (!(p_priv_data->p_m4sensorhub_data)) { - pr_err("%s: func called, RTC hardware not ready\n", __func__); + 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); @@ -93,19 +178,18 @@ static int rtc_sensorhub_rtc_read_time(struct device *dev, return err; } -static int rtc_sensorhub_rtc_set_time(struct device *dev, +static int rtc_sensorhub_rtc_set_time(struct device *p_dev, struct rtc_time *p_tm) { - u32 seconds; unsigned long sec; - struct platform_device *pdev = to_platform_device(dev); + struct platform_device *p_platdev = to_platform_device(p_dev); struct rtc_sensorhub_private_data *p_priv_data = - platform_get_drvdata(pdev); + platform_get_drvdata(p_platdev); struct m4sensorhub_data *p_m4_drvdata = p_priv_data->p_m4sensorhub_data; if (!(p_m4_drvdata)) { - pr_err("%s: ignore func call\n", __func__); + dev_err(p_dev, "set time, but M4 not ready, ignore func call\n"); return 0; } @@ -114,79 +198,36 @@ static int rtc_sensorhub_rtc_set_time(struct device *dev, rtc_tm_to_time(p_tm, &sec); /* M4 accepts time as u32*/ - seconds = (u32) sec; - if (m4sensorhub_reg_getsize(p_m4_drvdata, M4SH_REG_GENERAL_UTC) != m4sensorhub_reg_write( p_m4_drvdata, M4SH_REG_GENERAL_UTC, - (char *)&seconds, m4sh_no_mask)) { - pr_err("%s: Failed set M4 clock!\n", __func__); + (char *)&sec, m4sh_no_mask)) { + dev_err(p_dev, "set time, but failed to set M4 clock!\n"); return -EIO; } return 0; } -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); - return 0; -} - -static int rtc_sensorhub_rtc_proc(struct device *dev, struct seq_file *seq) -{ - /* TODO : implement a real handler*/ - struct platform_device *plat_dev = to_platform_device(dev); - char buffer[50]; - int length; - pr_err("%s:\n", __func__); - - seq_puts(seq, "sensorhub\t\t: yes\n"); - - length = sprintf(buffer, "id\t\t: %d\n", plat_dev->id); - if (length < 49) { - buffer[length] = 0; - seq_puts(seq, buffer); - } - - return 0; -} - -static int rtc_sensorhub_rtc_alarm_irq_enable(struct device *dev, - unsigned int enable) -{ - /* TODO : implement a real handler*/ - return 0; -} static const struct rtc_class_ops rtc_sensorhub_rtc_ops = { - .proc = rtc_sensorhub_rtc_proc, .read_time = rtc_sensorhub_rtc_read_time, .set_time = rtc_sensorhub_rtc_set_time, .read_alarm = rtc_sensorhub_rtc_read_alarm, .set_alarm = rtc_sensorhub_rtc_set_alarm, - .set_mmss = rtc_sensorhub_rtc_set_mmss, .alarm_irq_enable = rtc_sensorhub_rtc_alarm_irq_enable, }; -static ssize_t rtc_sensorhub_irq_show(struct device *dev, - struct device_attribute *attr, char *buf) +static void rtc_handle_sensorhub_irq(enum m4sensorhub_irqs int_event, + void *p_data) { - return sprintf(buf, "%d\n", 42); -} -static ssize_t rtc_sensorhub_irq_store(struct device *dev, - struct device_attribute *attr, - const char *buf, size_t count) -{ - /* TODO : implement a real handler*/ - pr_err("%s:\n", __func__); - return count; -} + struct rtc_sensorhub_private_data *p_priv_data = + (struct rtc_sensorhub_private_data *)(p_data); -static DEVICE_ATTR(irq, S_IRUGO | S_IWUSR, rtc_sensorhub_irq_show, - rtc_sensorhub_irq_store); + pr_info("%s: RTC alarm fired\n", DRIVER_NAME); + rtc_update_irq(p_priv_data->p_rtc, 1, RTC_AF | RTC_IRQF); +} static int rtc_sensorhub_init(struct init_calldata *p_arg) { @@ -202,17 +243,15 @@ static int rtc_sensorhub_init(struct init_calldata *p_arg) err = rtc_sensorhub_get_rtc_from_m4(&rtc, p_priv_data->p_m4sensorhub_data); if (err) { - pr_err("%s: get_rtc failed\n", __func__); + pr_err("%s: get_rtc failed\n", DRIVER_NAME); 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; - } + if (err) + pr_err("%s: settimeofday failed\n", DRIVER_NAME); pr_info("setting system clock to " "%d-%02d-%02d %02d:%02d:%02d UTC (%u)\n", @@ -220,10 +259,19 @@ static int rtc_sensorhub_init(struct init_calldata *p_arg) rtc.tm_hour, rtc.tm_min, rtc.tm_sec, (unsigned int) tv.tv_sec); - return 0; + /* 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); + + if (err < 0) + pr_err("%s: irq register failed\n", DRIVER_NAME); + + return err; } -static int rtc_sensorhub_probe(struct platform_device *plat_dev) +static int rtc_sensorhub_probe(struct platform_device *p_platdev) { int err; struct rtc_device *p_rtc; @@ -235,18 +283,19 @@ static int rtc_sensorhub_probe(struct platform_device *plat_dev) return -ENOMEM; p_priv_data->p_m4sensorhub_data = NULL; + p_priv_data->next_alarm_set.enabled = false; /* Set the private data before registering this driver with RTC core since hctosys will call rtc interface right away, we need to make sure our private data is set by this time */ - platform_set_drvdata(plat_dev, p_priv_data); + platform_set_drvdata(p_platdev, p_priv_data); - err = device_init_wakeup(&plat_dev->dev, true); + err = device_init_wakeup(&p_platdev->dev, true); if (err) { - pr_err("%s: failed to init as wakeup\n", __func__); + dev_err(&(p_platdev->dev), "failed to init as wakeup\n"); goto err_free_priv_data; } - p_rtc = devm_rtc_device_register(&plat_dev->dev, "rtc_sensorhub", + p_rtc = devm_rtc_device_register(&p_platdev->dev, "rtc_sensorhub", &rtc_sensorhub_rtc_ops, THIS_MODULE); if (IS_ERR(p_rtc)) { @@ -256,39 +305,38 @@ static int rtc_sensorhub_probe(struct platform_device *plat_dev) p_priv_data->p_rtc = p_rtc; - err = device_create_file(&plat_dev->dev, &dev_attr_irq); - if (err) - goto err_unregister_rtc; - err = m4sensorhub_register_initcall(rtc_sensorhub_init, p_priv_data); if (err) { - pr_err("%s: can't register init with m4\n", __func__); - goto err_remove_file; + dev_err(&(p_platdev->dev), "can't register init with m4\n"); + goto err_unregister_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, p_rtc); + devm_rtc_device_unregister(&p_platdev->dev, p_rtc); kfree(p_rtc); err_disable_wakeup: - device_init_wakeup(&plat_dev->dev, false); + device_init_wakeup(&p_platdev->dev, false); err_free_priv_data: kfree(p_priv_data); return err; } -static int rtc_sensorhub_remove(struct platform_device *plat_dev) +static int rtc_sensorhub_remove(struct platform_device *p_platdev) { struct rtc_sensorhub_private_data *p_priv_data = - platform_get_drvdata(plat_dev); + platform_get_drvdata(p_platdev); struct rtc_device *p_rtc = p_priv_data->p_rtc; - device_remove_file(&plat_dev->dev, &dev_attr_irq); - device_init_wakeup(&plat_dev->dev, false); - devm_rtc_device_unregister(&plat_dev->dev, p_rtc); + device_init_wakeup(&p_platdev->dev, false); + devm_rtc_device_unregister(&p_platdev->dev, p_rtc); m4sensorhub_unregister_initcall(rtc_sensorhub_init); + m4sensorhub_irq_disable( + p_priv_data->p_m4sensorhub_data, + M4SH_IRQ_AP_ALARM_EXPIRED); + m4sensorhub_irq_unregister( + p_priv_data->p_m4sensorhub_data, + M4SH_IRQ_AP_ALARM_EXPIRED); kfree(p_priv_data->p_rtc); kfree(p_priv_data); return 0; @@ -303,7 +351,7 @@ static struct platform_driver rtc_sensorhub_driver = { .probe = rtc_sensorhub_probe, .remove = rtc_sensorhub_remove, .driver = { - .name = "rtc-sensorhub", + .name = DRIVER_NAME, .owner = THIS_MODULE, .of_match_table = of_rtc_sensorhub_match, }, |