diff options
Diffstat (limited to 'drivers/rtc/rtc-twl.c')
| -rw-r--r-- | drivers/rtc/rtc-twl.c | 269 | 
1 files changed, 140 insertions, 129 deletions
diff --git a/drivers/rtc/rtc-twl.c b/drivers/rtc/rtc-twl.c index ed1b8682812..1915464e4cd 100644 --- a/drivers/rtc/rtc-twl.c +++ b/drivers/rtc/rtc-twl.c @@ -27,6 +27,7 @@  #include <linux/bcd.h>  #include <linux/platform_device.h>  #include <linux/interrupt.h> +#include <linux/of.h>  #include <linux/i2c/twl.h> @@ -112,6 +113,7 @@ static const u8 twl6030_rtc_reg_map[] = {  #define BIT_RTC_CTRL_REG_TEST_MODE_M             0x10  #define BIT_RTC_CTRL_REG_SET_32_COUNTER_M        0x20  #define BIT_RTC_CTRL_REG_GET_TIME_M              0x40 +#define BIT_RTC_CTRL_REG_RTC_V_OPT               0x80  /* RTC_STATUS_REG bitfields */  #define BIT_RTC_STATUS_REG_RUN_M                 0x02 @@ -176,6 +178,10 @@ static int set_rtc_irq_bit(unsigned char bit)  	unsigned char val;  	int ret; +	/* if the bit is set, return from here */ +	if (rtc_irq_bits & bit) +		return 0; +  	val = rtc_irq_bits | bit;  	val &= ~BIT_RTC_INTERRUPTS_REG_EVERY_M;  	ret = twl_rtc_write_u8(val, REG_RTC_INTERRUPTS_REG); @@ -193,6 +199,10 @@ static int mask_rtc_irq_bit(unsigned char bit)  	unsigned char val;  	int ret; +	/* if the bit is clear, return from here */ +	if (!(rtc_irq_bits & bit)) +		return 0; +  	val = rtc_irq_bits & ~bit;  	ret = twl_rtc_write_u8(val, REG_RTC_INTERRUPTS_REG);  	if (ret == 0) @@ -203,24 +213,24 @@ static int mask_rtc_irq_bit(unsigned char bit)  static int twl_rtc_alarm_irq_enable(struct device *dev, unsigned enabled)  { +	struct platform_device *pdev = to_platform_device(dev); +	int irq = platform_get_irq(pdev, 0); +	static bool twl_rtc_wake_enabled;  	int ret; -	if (enabled) +	if (enabled) {  		ret = set_rtc_irq_bit(BIT_RTC_INTERRUPTS_REG_IT_ALARM_M); -	else +		if (device_can_wakeup(dev) && !twl_rtc_wake_enabled) { +			enable_irq_wake(irq); +			twl_rtc_wake_enabled = true; +		} +	} else {  		ret = mask_rtc_irq_bit(BIT_RTC_INTERRUPTS_REG_IT_ALARM_M); - -	return ret; -} - -static int twl_rtc_update_irq_enable(struct device *dev, unsigned enabled) -{ -	int ret; - -	if (enabled) -		ret = set_rtc_irq_bit(BIT_RTC_INTERRUPTS_REG_IT_TIMER_M); -	else -		ret = mask_rtc_irq_bit(BIT_RTC_INTERRUPTS_REG_IT_TIMER_M); +		if (twl_rtc_wake_enabled) { +			disable_irq_wake(irq); +			twl_rtc_wake_enabled = false; +		} +	}  	return ret;  } @@ -236,28 +246,60 @@ static int twl_rtc_update_irq_enable(struct device *dev, unsigned enabled)   */  static int twl_rtc_read_time(struct device *dev, struct rtc_time *tm)  { -	unsigned char rtc_data[ALL_TIME_REGS + 1]; +	unsigned char rtc_data[ALL_TIME_REGS];  	int ret;  	u8 save_control; +	u8 rtc_control;  	ret = twl_rtc_read_u8(&save_control, REG_RTC_CTRL_REG); -	if (ret < 0) +	if (ret < 0) { +		dev_err(dev, "%s: reading CTRL_REG, error %d\n", __func__, ret);  		return ret; +	} +	/* for twl6030/32 make sure BIT_RTC_CTRL_REG_GET_TIME_M is clear */ +	if (twl_class_is_6030()) { +		if (save_control & BIT_RTC_CTRL_REG_GET_TIME_M) { +			save_control &= ~BIT_RTC_CTRL_REG_GET_TIME_M; +			ret = twl_rtc_write_u8(save_control, REG_RTC_CTRL_REG); +			if (ret < 0) { +				dev_err(dev, "%s clr GET_TIME, error %d\n", +					__func__, ret); +				return ret; +			} +		} +	} -	save_control |= BIT_RTC_CTRL_REG_GET_TIME_M; +	/* Copy RTC counting registers to static registers or latches */ +	rtc_control = save_control | BIT_RTC_CTRL_REG_GET_TIME_M; -	ret = twl_rtc_write_u8(save_control, REG_RTC_CTRL_REG); -	if (ret < 0) +	/* for twl6030/32 enable read access to static shadowed registers */ +	if (twl_class_is_6030()) +		rtc_control |= BIT_RTC_CTRL_REG_RTC_V_OPT; + +	ret = twl_rtc_write_u8(rtc_control, REG_RTC_CTRL_REG); +	if (ret < 0) { +		dev_err(dev, "%s: writing CTRL_REG, error %d\n", __func__, ret);  		return ret; +	}  	ret = twl_i2c_read(TWL_MODULE_RTC, rtc_data,  			(rtc_reg_map[REG_SECONDS_REG]), ALL_TIME_REGS);  	if (ret < 0) { -		dev_err(dev, "rtc_read_time error %d\n", ret); +		dev_err(dev, "%s: reading data, error %d\n", __func__, ret);  		return ret;  	} +	/* for twl6030 restore original state of rtc control register */ +	if (twl_class_is_6030()) { +		ret = twl_rtc_write_u8(save_control, REG_RTC_CTRL_REG); +		if (ret < 0) { +			dev_err(dev, "%s: restore CTRL_REG, error %d\n", +				__func__, ret); +			return ret; +		} +	} +  	tm->tm_sec = bcd2bin(rtc_data[0]);  	tm->tm_min = bcd2bin(rtc_data[1]);  	tm->tm_hour = bcd2bin(rtc_data[2]); @@ -271,15 +313,15 @@ static int twl_rtc_read_time(struct device *dev, struct rtc_time *tm)  static int twl_rtc_set_time(struct device *dev, struct rtc_time *tm)  {  	unsigned char save_control; -	unsigned char rtc_data[ALL_TIME_REGS + 1]; +	unsigned char rtc_data[ALL_TIME_REGS];  	int ret; -	rtc_data[1] = bin2bcd(tm->tm_sec); -	rtc_data[2] = bin2bcd(tm->tm_min); -	rtc_data[3] = bin2bcd(tm->tm_hour); -	rtc_data[4] = bin2bcd(tm->tm_mday); -	rtc_data[5] = bin2bcd(tm->tm_mon + 1); -	rtc_data[6] = bin2bcd(tm->tm_year - 100); +	rtc_data[0] = bin2bcd(tm->tm_sec); +	rtc_data[1] = bin2bcd(tm->tm_min); +	rtc_data[2] = bin2bcd(tm->tm_hour); +	rtc_data[3] = bin2bcd(tm->tm_mday); +	rtc_data[4] = bin2bcd(tm->tm_mon + 1); +	rtc_data[5] = bin2bcd(tm->tm_year - 100);  	/* Stop RTC while updating the TC registers */  	ret = twl_rtc_read_u8(&save_control, REG_RTC_CTRL_REG); @@ -287,7 +329,7 @@ static int twl_rtc_set_time(struct device *dev, struct rtc_time *tm)  		goto out;  	save_control &= ~BIT_RTC_CTRL_REG_STOP_RTC_M; -	twl_rtc_write_u8(save_control, REG_RTC_CTRL_REG); +	ret = twl_rtc_write_u8(save_control, REG_RTC_CTRL_REG);  	if (ret < 0)  		goto out; @@ -312,7 +354,7 @@ out:   */  static int twl_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alm)  { -	unsigned char rtc_data[ALL_TIME_REGS + 1]; +	unsigned char rtc_data[ALL_TIME_REGS];  	int ret;  	ret = twl_i2c_read(TWL_MODULE_RTC, rtc_data, @@ -339,19 +381,19 @@ static int twl_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alm)  static int twl_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alm)  { -	unsigned char alarm_data[ALL_TIME_REGS + 1]; +	unsigned char alarm_data[ALL_TIME_REGS];  	int ret;  	ret = twl_rtc_alarm_irq_enable(dev, 0);  	if (ret)  		goto out; -	alarm_data[1] = bin2bcd(alm->time.tm_sec); -	alarm_data[2] = bin2bcd(alm->time.tm_min); -	alarm_data[3] = bin2bcd(alm->time.tm_hour); -	alarm_data[4] = bin2bcd(alm->time.tm_mday); -	alarm_data[5] = bin2bcd(alm->time.tm_mon + 1); -	alarm_data[6] = bin2bcd(alm->time.tm_year - 100); +	alarm_data[0] = bin2bcd(alm->time.tm_sec); +	alarm_data[1] = bin2bcd(alm->time.tm_min); +	alarm_data[2] = bin2bcd(alm->time.tm_hour); +	alarm_data[3] = bin2bcd(alm->time.tm_mday); +	alarm_data[4] = bin2bcd(alm->time.tm_mon + 1); +	alarm_data[5] = bin2bcd(alm->time.tm_year - 100);  	/* update all the alarm registers in one shot */  	ret = twl_i2c_write(TWL_MODULE_RTC, alarm_data, @@ -369,19 +411,11 @@ out:  static irqreturn_t twl_rtc_interrupt(int irq, void *rtc)  { -	unsigned long events = 0; +	unsigned long events;  	int ret = IRQ_NONE;  	int res;  	u8 rd_reg; -#ifdef CONFIG_LOCKDEP -	/* WORKAROUND for lockdep forcing IRQF_DISABLED on us, which -	 * we don't want and can't tolerate.  Although it might be -	 * friendlier not to borrow this thread context... -	 */ -	local_irq_enable(); -#endif -  	res = twl_rtc_read_u8(&rd_reg, REG_RTC_STATUS_REG);  	if (res)  		goto out; @@ -392,11 +426,11 @@ static irqreturn_t twl_rtc_interrupt(int irq, void *rtc)  	 * by reading RTS_INTERRUPTS_REGISTER[IT_TIMER,IT_ALARM]  	 */  	if (rd_reg & BIT_RTC_STATUS_REG_ALARM_M) -		events |= RTC_IRQF | RTC_AF; +		events = RTC_IRQF | RTC_AF;  	else -		events |= RTC_IRQF | RTC_UF; +		events = RTC_IRQF | RTC_PF; -	res = twl_rtc_write_u8(rd_reg | BIT_RTC_STATUS_REG_ALARM_M, +	res = twl_rtc_write_u8(BIT_RTC_STATUS_REG_ALARM_M,  				   REG_RTC_STATUS_REG);  	if (res)  		goto out; @@ -433,36 +467,29 @@ static struct rtc_class_ops twl_rtc_ops = {  	.read_alarm	= twl_rtc_read_alarm,  	.set_alarm	= twl_rtc_set_alarm,  	.alarm_irq_enable = twl_rtc_alarm_irq_enable, -	.update_irq_enable = twl_rtc_update_irq_enable,  };  /*----------------------------------------------------------------------*/ -static int __devinit twl_rtc_probe(struct platform_device *pdev) +static int twl_rtc_probe(struct platform_device *pdev)  {  	struct rtc_device *rtc; -	int ret = 0; +	int ret = -EINVAL;  	int irq = platform_get_irq(pdev, 0);  	u8 rd_reg;  	if (irq <= 0) -		return -EINVAL; - -	rtc = rtc_device_register(pdev->name, -				  &pdev->dev, &twl_rtc_ops, THIS_MODULE); -	if (IS_ERR(rtc)) { -		ret = PTR_ERR(rtc); -		dev_err(&pdev->dev, "can't register RTC device, err %ld\n", -			PTR_ERR(rtc)); -		goto out0; - -	} +		return ret; -	platform_set_drvdata(pdev, rtc); +	/* Initialize the register map */ +	if (twl_class_is_4030()) +		rtc_reg_map = (u8 *)twl4030_rtc_reg_map; +	else +		rtc_reg_map = (u8 *)twl6030_rtc_reg_map;  	ret = twl_rtc_read_u8(&rd_reg, REG_RTC_STATUS_REG);  	if (ret < 0) -		goto out1; +		return ret;  	if (rd_reg & BIT_RTC_STATUS_REG_POWER_UP_M)  		dev_warn(&pdev->dev, "Power up reset detected.\n"); @@ -473,15 +500,7 @@ static int __devinit twl_rtc_probe(struct platform_device *pdev)  	/* Clear RTC Power up reset and pending alarm interrupts */  	ret = twl_rtc_write_u8(rd_reg, REG_RTC_STATUS_REG);  	if (ret < 0) -		goto out1; - -	ret = request_irq(irq, twl_rtc_interrupt, -				IRQF_TRIGGER_RISING, -				dev_name(&rtc->dev), rtc); -	if (ret < 0) { -		dev_err(&pdev->dev, "IRQ is not free.\n"); -		goto out1; -	} +		return ret;  	if (twl_class_is_6030()) {  		twl6030_interrupt_unmask(TWL6030_RTC_INT_MASK, @@ -490,44 +509,51 @@ static int __devinit twl_rtc_probe(struct platform_device *pdev)  			REG_INT_MSK_STS_A);  	} -	/* Check RTC module status, Enable if it is off */ -	ret = twl_rtc_read_u8(&rd_reg, REG_RTC_CTRL_REG); +	dev_info(&pdev->dev, "Enabling TWL-RTC\n"); +	ret = twl_rtc_write_u8(BIT_RTC_CTRL_REG_STOP_RTC_M, REG_RTC_CTRL_REG);  	if (ret < 0) -		goto out2; - -	if (!(rd_reg & BIT_RTC_CTRL_REG_STOP_RTC_M)) { -		dev_info(&pdev->dev, "Enabling TWL-RTC.\n"); -		rd_reg = BIT_RTC_CTRL_REG_STOP_RTC_M; -		ret = twl_rtc_write_u8(rd_reg, REG_RTC_CTRL_REG); -		if (ret < 0) -			goto out2; -	} +		return ret; + +	/* ensure interrupts are disabled, bootloaders can be strange */ +	ret = twl_rtc_write_u8(0, REG_RTC_INTERRUPTS_REG); +	if (ret < 0) +		dev_warn(&pdev->dev, "unable to disable interrupt\n");  	/* init cached IRQ enable bits */  	ret = twl_rtc_read_u8(&rtc_irq_bits, REG_RTC_INTERRUPTS_REG);  	if (ret < 0) -		goto out2; +		return ret; -	return ret; +	device_init_wakeup(&pdev->dev, 1); -out2: -	free_irq(irq, rtc); -out1: -	rtc_device_unregister(rtc); -out0: -	return ret; +	rtc = devm_rtc_device_register(&pdev->dev, pdev->name, +					&twl_rtc_ops, THIS_MODULE); +	if (IS_ERR(rtc)) { +		dev_err(&pdev->dev, "can't register RTC device, err %ld\n", +			PTR_ERR(rtc)); +		return PTR_ERR(rtc); +	} + +	ret = devm_request_threaded_irq(&pdev->dev, irq, NULL, +					twl_rtc_interrupt, +					IRQF_TRIGGER_RISING | IRQF_ONESHOT, +					dev_name(&rtc->dev), rtc); +	if (ret < 0) { +		dev_err(&pdev->dev, "IRQ is not free.\n"); +		return ret; +	} + +	platform_set_drvdata(pdev, rtc); +	return 0;  }  /*   * Disable all TWL RTC module interrupts.   * Sets status flag to free.   */ -static int __devexit twl_rtc_remove(struct platform_device *pdev) +static int twl_rtc_remove(struct platform_device *pdev)  {  	/* leave rtc running, but disable irqs */ -	struct rtc_device *rtc = platform_get_drvdata(pdev); -	int irq = platform_get_irq(pdev, 0); -  	mask_rtc_irq_bit(BIT_RTC_INTERRUPTS_REG_IT_ALARM_M);  	mask_rtc_irq_bit(BIT_RTC_INTERRUPTS_REG_IT_TIMER_M);  	if (twl_class_is_6030()) { @@ -537,11 +563,6 @@ static int __devexit twl_rtc_remove(struct platform_device *pdev)  			REG_INT_MSK_STS_A);  	} - -	free_irq(irq, rtc); - -	rtc_device_unregister(rtc); -	platform_set_drvdata(pdev, NULL);  	return 0;  } @@ -552,11 +573,10 @@ static void twl_rtc_shutdown(struct platform_device *pdev)  	mask_rtc_irq_bit(BIT_RTC_INTERRUPTS_REG_IT_TIMER_M);  } -#ifdef CONFIG_PM - +#ifdef CONFIG_PM_SLEEP  static unsigned char irqstat; -static int twl_rtc_suspend(struct platform_device *pdev, pm_message_t state) +static int twl_rtc_suspend(struct device *dev)  {  	irqstat = rtc_irq_bits; @@ -564,47 +584,38 @@ static int twl_rtc_suspend(struct platform_device *pdev, pm_message_t state)  	return 0;  } -static int twl_rtc_resume(struct platform_device *pdev) +static int twl_rtc_resume(struct device *dev)  {  	set_rtc_irq_bit(irqstat);  	return 0;  } +#endif -#else -#define twl_rtc_suspend NULL -#define twl_rtc_resume  NULL +static SIMPLE_DEV_PM_OPS(twl_rtc_pm_ops, twl_rtc_suspend, twl_rtc_resume); + +#ifdef CONFIG_OF +static const struct of_device_id twl_rtc_of_match[] = { +	{.compatible = "ti,twl4030-rtc", }, +	{ }, +}; +MODULE_DEVICE_TABLE(of, twl_rtc_of_match);  #endif  MODULE_ALIAS("platform:twl_rtc");  static struct platform_driver twl4030rtc_driver = {  	.probe		= twl_rtc_probe, -	.remove		= __devexit_p(twl_rtc_remove), +	.remove		= twl_rtc_remove,  	.shutdown	= twl_rtc_shutdown, -	.suspend	= twl_rtc_suspend, -	.resume		= twl_rtc_resume,  	.driver		= { -		.owner	= THIS_MODULE, -		.name	= "twl_rtc", +		.owner		= THIS_MODULE, +		.name		= "twl_rtc", +		.pm		= &twl_rtc_pm_ops, +		.of_match_table = of_match_ptr(twl_rtc_of_match),  	},  }; -static int __init twl_rtc_init(void) -{ -	if (twl_class_is_4030()) -		rtc_reg_map = (u8 *) twl4030_rtc_reg_map; -	else -		rtc_reg_map = (u8 *) twl6030_rtc_reg_map; - -	return platform_driver_register(&twl4030rtc_driver); -} -module_init(twl_rtc_init); - -static void __exit twl_rtc_exit(void) -{ -	platform_driver_unregister(&twl4030rtc_driver); -} -module_exit(twl_rtc_exit); +module_platform_driver(twl4030rtc_driver);  MODULE_AUTHOR("Texas Instruments, MontaVista Software");  MODULE_LICENSE("GPL");  | 
