diff options
Diffstat (limited to 'drivers/rtc/rtc-wm831x.c')
| -rw-r--r-- | drivers/rtc/rtc-wm831x.c | 99 | 
1 files changed, 31 insertions, 68 deletions
diff --git a/drivers/rtc/rtc-wm831x.c b/drivers/rtc/rtc-wm831x.c index 82931dc65c0..75aea4c4d33 100644 --- a/drivers/rtc/rtc-wm831x.c +++ b/drivers/rtc/rtc-wm831x.c @@ -24,7 +24,7 @@  #include <linux/mfd/wm831x/core.h>  #include <linux/delay.h>  #include <linux/platform_device.h> - +#include <linux/random.h>  /*   * R16416 (0x4020) - RTC Write Counter @@ -96,6 +96,26 @@ struct wm831x_rtc {  	unsigned int alarm_enabled:1;  }; +static void wm831x_rtc_add_randomness(struct wm831x *wm831x) +{ +	int ret; +	u16 reg; + +	/* +	 * The write counter contains a pseudo-random number which is +	 * regenerated every time we set the RTC so it should be a +	 * useful per-system source of entropy. +	 */ +	ret = wm831x_reg_read(wm831x, WM831X_RTC_WRITE_COUNTER); +	if (ret >= 0) { +		reg = ret; +		add_device_randomness(®, sizeof(reg)); +	} else { +		dev_warn(wm831x->dev, "Failed to read RTC write counter: %d\n", +			 ret); +	} +} +  /*   * Read current time and date in RTC   */ @@ -315,21 +335,6 @@ static int wm831x_rtc_alarm_irq_enable(struct device *dev,  		return wm831x_rtc_stop_alarm(wm831x_rtc);  } -static int wm831x_rtc_update_irq_enable(struct device *dev, -					unsigned int enabled) -{ -	struct wm831x_rtc *wm831x_rtc = dev_get_drvdata(dev); -	int val; - -	if (enabled) -		val = 1 << WM831X_RTC_PINT_FREQ_SHIFT; -	else -		val = 0; - -	return wm831x_set_bits(wm831x_rtc->wm831x, WM831X_RTC_CONTROL, -			       WM831X_RTC_PINT_FREQ_MASK, val); -} -  static irqreturn_t wm831x_alm_irq(int irq, void *data)  {  	struct wm831x_rtc *wm831x_rtc = data; @@ -339,22 +344,12 @@ static irqreturn_t wm831x_alm_irq(int irq, void *data)  	return IRQ_HANDLED;  } -static irqreturn_t wm831x_per_irq(int irq, void *data) -{ -	struct wm831x_rtc *wm831x_rtc = data; - -	rtc_update_irq(wm831x_rtc->rtc, 1, RTC_IRQF | RTC_UF); - -	return IRQ_HANDLED; -} -  static const struct rtc_class_ops wm831x_rtc_ops = {  	.read_time = wm831x_rtc_readtime,  	.set_mmss = wm831x_rtc_set_mmss,  	.read_alarm = wm831x_rtc_readalarm,  	.set_alarm = wm831x_rtc_setalarm,  	.alarm_irq_enable = wm831x_rtc_alarm_irq_enable, -	.update_irq_enable = wm831x_rtc_update_irq_enable,  };  #ifdef CONFIG_PM @@ -421,11 +416,10 @@ static int wm831x_rtc_probe(struct platform_device *pdev)  {  	struct wm831x *wm831x = dev_get_drvdata(pdev->dev.parent);  	struct wm831x_rtc *wm831x_rtc; -	int per_irq = platform_get_irq_byname(pdev, "PER"); -	int alm_irq = platform_get_irq_byname(pdev, "ALM"); +	int alm_irq = wm831x_irq(wm831x, platform_get_irq_byname(pdev, "ALM"));  	int ret = 0; -	wm831x_rtc = kzalloc(sizeof(*wm831x_rtc), GFP_KERNEL); +	wm831x_rtc = devm_kzalloc(&pdev->dev, sizeof(*wm831x_rtc), GFP_KERNEL);  	if (wm831x_rtc == NULL)  		return -ENOMEM; @@ -442,50 +436,30 @@ static int wm831x_rtc_probe(struct platform_device *pdev)  	device_init_wakeup(&pdev->dev, 1); -	wm831x_rtc->rtc = rtc_device_register("wm831x", &pdev->dev, +	wm831x_rtc->rtc = devm_rtc_device_register(&pdev->dev, "wm831x",  					      &wm831x_rtc_ops, THIS_MODULE);  	if (IS_ERR(wm831x_rtc->rtc)) {  		ret = PTR_ERR(wm831x_rtc->rtc);  		goto err;  	} -	ret = request_threaded_irq(per_irq, NULL, wm831x_per_irq, -				   IRQF_TRIGGER_RISING, "RTC period", -				   wm831x_rtc); -	if (ret != 0) { -		dev_err(&pdev->dev, "Failed to request periodic IRQ %d: %d\n", -			per_irq, ret); -	} - -	ret = request_threaded_irq(alm_irq, NULL, wm831x_alm_irq, -				   IRQF_TRIGGER_RISING, "RTC alarm", -				   wm831x_rtc); +	ret = devm_request_threaded_irq(&pdev->dev, alm_irq, NULL, +				wm831x_alm_irq, +				IRQF_TRIGGER_RISING, "RTC alarm", +				wm831x_rtc);  	if (ret != 0) {  		dev_err(&pdev->dev, "Failed to request alarm IRQ %d: %d\n",  			alm_irq, ret);  	} +	wm831x_rtc_add_randomness(wm831x); +  	return 0;  err: -	kfree(wm831x_rtc);  	return ret;  } -static int __devexit wm831x_rtc_remove(struct platform_device *pdev) -{ -	struct wm831x_rtc *wm831x_rtc = platform_get_drvdata(pdev); -	int per_irq = platform_get_irq_byname(pdev, "PER"); -	int alm_irq = platform_get_irq_byname(pdev, "ALM"); - -	free_irq(alm_irq, wm831x_rtc); -	free_irq(per_irq, wm831x_rtc); -	rtc_device_unregister(wm831x_rtc->rtc); -	kfree(wm831x_rtc); - -	return 0; -} -  static const struct dev_pm_ops wm831x_rtc_pm_ops = {  	.suspend = wm831x_rtc_suspend,  	.resume = wm831x_rtc_resume, @@ -499,24 +473,13 @@ static const struct dev_pm_ops wm831x_rtc_pm_ops = {  static struct platform_driver wm831x_rtc_driver = {  	.probe = wm831x_rtc_probe, -	.remove = __devexit_p(wm831x_rtc_remove),  	.driver = {  		.name = "wm831x-rtc",  		.pm = &wm831x_rtc_pm_ops,  	},  }; -static int __init wm831x_rtc_init(void) -{ -	return platform_driver_register(&wm831x_rtc_driver); -} -module_init(wm831x_rtc_init); - -static void __exit wm831x_rtc_exit(void) -{ -	platform_driver_unregister(&wm831x_rtc_driver); -} -module_exit(wm831x_rtc_exit); +module_platform_driver(wm831x_rtc_driver);  MODULE_AUTHOR("Mark Brown <broonie@opensource.wolfsonmicro.com>");  MODULE_DESCRIPTION("RTC driver for the WM831x series PMICs");  | 
