diff options
| -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;  }  |