diff options
Diffstat (limited to 'drivers/rtc/rtc-isl1208.c')
| -rw-r--r-- | drivers/rtc/rtc-isl1208.c | 36 | 
1 files changed, 24 insertions, 12 deletions
| diff --git a/drivers/rtc/rtc-isl1208.c b/drivers/rtc/rtc-isl1208.c index e50c23ee1646..7b82e4a14b7a 100644 --- a/drivers/rtc/rtc-isl1208.c +++ b/drivers/rtc/rtc-isl1208.c @@ -7,6 +7,7 @@  #include <linux/bcd.h>  #include <linux/clk.h> +#include <linux/delay.h>  #include <linux/i2c.h>  #include <linux/module.h>  #include <linux/of.h> @@ -628,6 +629,18 @@ isl1208_rtc_interrupt(int irq, void *data)  	struct isl1208_state *isl1208 = i2c_get_clientdata(client);  	int handled = 0, sr, err; +	if (!isl1208->config->has_tamper) { +		/* +		 * The INT# output is pulled low 250ms after the alarm is +		 * triggered. After the INT# output is pulled low, it is low for +		 * at least 250ms, even if the correct action is taken to clear +		 * it. It is impossible to clear ALM if it is still active. The +		 * host must wait for the RTC to progress past the alarm time +		 * plus the 250ms delay before clearing ALM. +		 */ +		msleep(250); +	} +  	/*  	 * I2C reads get NAK'ed if we read straight away after an interrupt?  	 * Using a mdelay/msleep didn't seem to help either, so we work around @@ -650,6 +663,13 @@ isl1208_rtc_interrupt(int irq, void *data)  		rtc_update_irq(isl1208->rtc, 1, RTC_IRQF | RTC_AF); +		/* Disable the alarm */ +		err = isl1208_rtc_toggle_alarm(client, 0); +		if (err) +			return err; + +		fsleep(275); +  		/* Clear the alarm */  		sr &= ~ISL1208_REG_SR_ALM;  		sr = i2c_smbus_write_byte_data(client, ISL1208_REG_SR, sr); @@ -658,11 +678,6 @@ isl1208_rtc_interrupt(int irq, void *data)  				__func__);  		else  			handled = 1; - -		/* Disable the alarm */ -		err = isl1208_rtc_toggle_alarm(client, 0); -		if (err) -			return err;  	}  	if (isl1208->config->has_tamper && (sr & ISL1208_REG_SR_EVT)) { @@ -775,14 +790,13 @@ static int isl1208_nvmem_read(void *priv, unsigned int off, void *buf,  {  	struct isl1208_state *isl1208 = priv;  	struct i2c_client *client = to_i2c_client(isl1208->rtc->dev.parent); -	int ret;  	/* nvmem sanitizes offset/count for us, but count==0 is possible */  	if (!count)  		return count; -	ret = isl1208_i2c_read_regs(client, ISL1208_REG_USR1 + off, buf, + +	return isl1208_i2c_read_regs(client, ISL1208_REG_USR1 + off, buf,  				    count); -	return ret == 0 ? count : ret;  }  static int isl1208_nvmem_write(void *priv, unsigned int off, void *buf, @@ -790,15 +804,13 @@ static int isl1208_nvmem_write(void *priv, unsigned int off, void *buf,  {  	struct isl1208_state *isl1208 = priv;  	struct i2c_client *client = to_i2c_client(isl1208->rtc->dev.parent); -	int ret;  	/* nvmem sanitizes off/count for us, but count==0 is possible */  	if (!count)  		return count; -	ret = isl1208_i2c_set_regs(client, ISL1208_REG_USR1 + off, buf, -				   count); -	return ret == 0 ? count : ret; +	return isl1208_i2c_set_regs(client, ISL1208_REG_USR1 + off, buf, +				   count);  }  static const struct nvmem_config isl1208_nvmem_config = { |