x1205 fix osc on startup
PATCH 1/1 x1205 fix osc on startup
Content-Disposition: inline; filename=i2c-x1205-fix-osc.patch
When the battery fails, the x1205 will refuse to run the oscillator unless something is written to its date/time register.
On platforms where this driver is actually used (NSLU2), along with a class based RTC core, the time is updated via /dev/rtc using the hwclock utility.
hwclock will wait for a seconds increment before writing the new date/time and that's why this patch is required for it to work.
Requires i2c-x1205-cleanup.patch
Signed-off-by Alessandro Zummo <a.zummo at towertech.it>
--- drivers/i2c/chips/x1205.c | 116 ++++++++++++++++++++++++++++++---------------- 1 file changed, 76 insertions(+), 40 deletions(-)
drivers/i2c/chips/x1205.c +76 -40
@@ -22,9 +22,9 @@#include <linux/string.h> #include <linux/bcd.h> #include <linux/rtc.h> +#include <linux/delay.h> - -#define DRV_VERSION "1.0.0" +#define DRV_VERSION "1.0.1"/* Addresses to scan: none. This chip is located at * 0x6f and uses a two bytes register addressing.
@@ -141,35 +141,19 @@ static int x1205_validate_tm(struct rtc_* Epoch is initialized as 2000. Time is set to UTC. */ static int x1205_get_datetime (struct i2c_client *client,struct rtc_time *tm, -u8 reg_base) +unsigned char reg_base) {unsigned char dt_addr[2 ] = {0 , reg_base }; -static unsigned char sr_addr[2 ] = {0 ,X1205_REG_SR }; -unsigned char buf[8 ], sr; +unsigned char buf[8 ];struct i2c_msg msgs[] = { - { client->addr,0 ,2 , sr_addr },/* setup read ptr */ - { client->addr,I2C_M_RD ,1 , &sr },/* read status */ { client->addr,0 ,2 , dt_addr },/* setup read ptr */ { client->addr,I2C_M_RD ,8 , buf },/* read date */ }; -/* read status register */ -if ((i2c_transfer (client->adapter, &msgs[0 ],2 )) !=2 ) { -dev_err (&client->dev,"%s: read error\n" , __FUNCTION__); -return -EIO ; - } - -/* check for battery failure */ -if (sr &X1205_SR_RTCF ) { -dev_warn (&client->dev, -"Clock had a power failure, you must set the date.\n" ); -return -EINVAL ; - } -/* read date registers */ -if ((i2c_transfer (client->adapter, &msgs[2 ],2 )) !=2 ) { +if ((i2c_transfer (client->adapter, &msgs[0 ],2 )) !=2 ) {dev_err (&client->dev,"%s: read error\n" , __FUNCTION__);return -EIO ; }
@@ -199,11 +183,28 @@ static int x1205_get_datetime(struct i2creturn 0 ; } +static int x1205_get_status (struct i2c_client *client,unsigned char *sr) +{ +static unsigned char sr_addr[2 ] = {0 ,X1205_REG_SR }; + +struct i2c_msg msgs[] = { + { client->addr,0 ,2 , sr_addr },/* setup read ptr */ + { client->addr,I2C_M_RD ,1 , sr },/* read status */ + }; + +/* read status register */ +if ((i2c_transfer (client->adapter, &msgs[0 ],2 )) !=2 ) { +dev_err (&client->dev,"%s: read error\n" , __FUNCTION__); +return -EIO ; + } + +return 0 ; +} +static int x1205_set_datetime (struct i2c_client *client,struct rtc_time *tm,int datetoo,u8 reg_base) { -int i, err, xfer; - +int i, xfer;unsigned char buf[8 ];static const unsigned char wel[3 ] = {0 ,X1205_REG_SR ,
@@ -214,15 +215,10 @@ static int x1205_set_datetime(struct i2cstatic const unsigned char diswe[3 ] = {0 ,X1205_REG_SR ,0 }; -/* check if all values in the tm struct are correct */ -if ((err =x1205_validate_tm (tm)) <0 ) -return err; - -dev_dbg (&client->dev,"%s: secs=%d, mins=%d, hours=%d, " -"mday=%d, mon=%d, year=%d, wday=%d\n" , +dev_dbg (&client->dev, +"%s: secs=%d, mins=%d, hours=%d\n" , __FUNCTION__, - tm->tm_sec, tm->tm_min, tm->tm_hour, - tm->tm_mday, tm->tm_mon, tm->tm_year, tm->tm_wday); + tm->tm_sec, tm->tm_min, tm->tm_hour); buf[CCR_SEC ] =BIN2BCD (tm->tm_sec); buf[CCR_MIN ] =BIN2BCD (tm->tm_min);
@@ -232,6 +228,11 @@ static int x1205_set_datetime(struct i2c/* should we also set the date? */ if (datetoo) { +dev_dbg (&client->dev, +"%s: mday=%d, mon=%d, year=%d, wday=%d\n" , + __FUNCTION__, + tm->tm_mday, tm->tm_mon, tm->tm_year, tm->tm_wday); + buf[CCR_MDAY ] =BIN2BCD (tm->tm_mday);/* month, 0 - 11 */
@@ -280,6 +281,22 @@ static int x1205_set_datetime(struct i2creturn 0 ; } +static int x1205_fix_osc (struct i2c_client *client) +{ +int err; +struct rtc_time tm; + + tm.tm_hour =0 ; + tm.tm_min =0 ; + tm.tm_sec =0 ; + +if ((err =x1205_set_datetime (client, &tm,0 ,X1205_CCR_BASE )) <0 ) +dev_err (&client->dev, +"unable to restart the clock\n" ); + +return err; +} +static int x1205_get_dtrim (struct i2c_client *client,int *trim) {unsigned char dtr;
@@ -352,14 +369,17 @@ static int x1205_hctosys(struct i2c_cliestruct rtc_time tm;struct timespec tv; +unsigned char sr; +if ((err =x1205_get_status (client, &sr)) <0 ) +return err; - err =x1205_get_datetime (client, &tm,X1205_CCR_BASE ); -if (err) { -dev_err (&client->dev, -"Unable to set the system clock\n" ); +/* Don't set if we had a power failure */ +if (sr &X1205_SR_RTCF ) +return -EINVAL ; + +if ((err =x1205_get_datetime (client, &tm,X1205_CCR_BASE )) <0 )return err; - }/* IMPORTANT: the RTC only stores whole seconds. It is arbitrary * whether it stores the most close value or the value with partial
@@ -506,9 +526,9 @@ static int x1205_attach(struct i2c_adaptstatic int x1205_probe (struct i2c_adapter *adapter,int address,int kind) { -struct i2c_client *client; -int err =0 ; +unsigned char sr; +struct i2c_client *client;dev_dbg (&adapter->dev,"%s\n" , __FUNCTION__);
@@ -543,9 +563,25 @@ static int x1205_probe(struct i2c_adaptedev_info (&client->dev,"chip found, driver version " DRV_VERSION "\n" ); +/* Check for power failures and eventualy enable the osc */ +if ((err =x1205_get_status (client, &sr)) =0 ) { +if (sr &X1205_SR_RTCF ) { +dev_err (&client->dev, +"power failure detected, " +"please set the clock\n" ); +udelay (50 ); +x1205_fix_osc (client); + } + } +else +dev_err (&client->dev,"couldn't read status\n" ); +/* If requested, set the system time */ -if (hctosys) -x1205_hctosys (client); +if (hctosys) { +if ((err =x1205_hctosys (client)) <0 ) +dev_err (&client->dev, +"unable to set the system clock\n" ); + }return 0 ;