diff options
Diffstat (limited to 'drivers/rtc/rtc-rx8025.c')
| -rw-r--r-- | drivers/rtc/rtc-rx8025.c | 277 | 
1 files changed, 105 insertions, 172 deletions
diff --git a/drivers/rtc/rtc-rx8025.c b/drivers/rtc/rtc-rx8025.c index e6298e02b400..24c3d69ce1b9 100644 --- a/drivers/rtc/rtc-rx8025.c +++ b/drivers/rtc/rtc-rx8025.c @@ -18,13 +18,11 @@   * modify it under the terms of the GNU General Public License   * version 2 as published by the Free Software Foundation.   */ -#include <linux/kernel.h> -#include <linux/module.h> -#include <linux/slab.h> -#include <linux/init.h>  #include <linux/bcd.h> +#include <linux/bitops.h>  #include <linux/i2c.h> -#include <linux/list.h> +#include <linux/kernel.h> +#include <linux/module.h>  #include <linux/rtc.h>  /* Register definitions */ @@ -48,17 +46,17 @@  #define RX8025_BIT_CTRL1_CT	(7 << 0)  /* 1 Hz periodic level irq */  #define RX8025_BIT_CTRL1_CT_1HZ	4 -#define RX8025_BIT_CTRL1_TEST	(1 << 3) -#define RX8025_BIT_CTRL1_1224	(1 << 5) -#define RX8025_BIT_CTRL1_DALE	(1 << 6) -#define RX8025_BIT_CTRL1_WALE	(1 << 7) - -#define RX8025_BIT_CTRL2_DAFG	(1 << 0) -#define RX8025_BIT_CTRL2_WAFG	(1 << 1) -#define RX8025_BIT_CTRL2_CTFG	(1 << 2) -#define RX8025_BIT_CTRL2_PON	(1 << 4) -#define RX8025_BIT_CTRL2_XST	(1 << 5) -#define RX8025_BIT_CTRL2_VDET	(1 << 6) +#define RX8025_BIT_CTRL1_TEST	BIT(3) +#define RX8025_BIT_CTRL1_1224	BIT(5) +#define RX8025_BIT_CTRL1_DALE	BIT(6) +#define RX8025_BIT_CTRL1_WALE	BIT(7) + +#define RX8025_BIT_CTRL2_DAFG	BIT(0) +#define RX8025_BIT_CTRL2_WAFG	BIT(1) +#define RX8025_BIT_CTRL2_CTFG	BIT(2) +#define RX8025_BIT_CTRL2_PON	BIT(4) +#define RX8025_BIT_CTRL2_XST	BIT(5) +#define RX8025_BIT_CTRL2_VDET	BIT(6)  /* Clock precision adjustment */  #define RX8025_ADJ_RESOLUTION	3050 /* in ppb */ @@ -74,84 +72,84 @@ MODULE_DEVICE_TABLE(i2c, rx8025_id);  struct rx8025_data {  	struct i2c_client *client;  	struct rtc_device *rtc; -	struct work_struct work;  	u8 ctrl1; -	unsigned exiting:1;  }; -static int rx8025_read_reg(struct i2c_client *client, int number, u8 *value) +static s32 rx8025_read_reg(const struct i2c_client *client, u8 number)  { -	int ret = i2c_smbus_read_byte_data(client, (number << 4) | 0x08); - -	if (ret < 0) { -		dev_err(&client->dev, "Unable to read register #%d\n", number); -		return ret; -	} - -	*value = ret; -	return 0; +	return i2c_smbus_read_byte_data(client, number << 4);  } -static int rx8025_read_regs(struct i2c_client *client, -			    int number, u8 length, u8 *values) +static int rx8025_read_regs(const struct i2c_client *client, +			    u8 number, u8 length, u8 *values)  { -	int ret = i2c_smbus_read_i2c_block_data(client, (number << 4) | 0x08, -						length, values); - -	if (ret != length) { -		dev_err(&client->dev, "Unable to read registers #%d..#%d\n", -			number, number + length - 1); +	int ret = i2c_smbus_read_i2c_block_data(client, number << 4, length, +						values); +	if (ret != length)  		return ret < 0 ? ret : -EIO; -	}  	return 0;  } -static int rx8025_write_reg(struct i2c_client *client, int number, u8 value) +static s32 rx8025_write_reg(const struct i2c_client *client, u8 number, +			    u8 value)  { -	int ret = i2c_smbus_write_byte_data(client, number << 4, value); - -	if (ret) -		dev_err(&client->dev, "Unable to write register #%d\n", -			number); +	return i2c_smbus_write_byte_data(client, number << 4, value); +} -	return ret; +static s32 rx8025_write_regs(const struct i2c_client *client, +			     u8 number, u8 length, const u8 *values) +{ +	return i2c_smbus_write_i2c_block_data(client, number << 4, +					      length, values);  } -static int rx8025_write_regs(struct i2c_client *client, -			     int number, u8 length, u8 *values) +static int rx8025_check_validity(struct device *dev)  { -	int ret = i2c_smbus_write_i2c_block_data(client, (number << 4) | 0x08, -						 length, values); +	struct rx8025_data *rx8025 = dev_get_drvdata(dev); +	int ctrl2; + +	ctrl2 = rx8025_read_reg(rx8025->client, RX8025_REG_CTRL2); +	if (ctrl2 < 0) +		return ctrl2; + +	if (ctrl2 & RX8025_BIT_CTRL2_VDET) +		dev_warn(dev, "power voltage drop detected\n"); + +	if (ctrl2 & RX8025_BIT_CTRL2_PON) { +		dev_warn(dev, "power-on reset detected, date is invalid\n"); +		return -EINVAL; +	} -	if (ret) -		dev_err(&client->dev, "Unable to write registers #%d..#%d\n", -			number, number + length - 1); +	if (!(ctrl2 & RX8025_BIT_CTRL2_XST)) { +		dev_warn(dev, "crystal stopped, date is invalid\n"); +		return -EINVAL; +	} -	return ret; +	return 0;  } -static irqreturn_t rx8025_irq(int irq, void *dev_id) +static int rx8025_reset_validity(struct i2c_client *client)  { -	struct i2c_client *client = dev_id; -	struct rx8025_data *rx8025 = i2c_get_clientdata(client); +	int ctrl2 = rx8025_read_reg(client, RX8025_REG_CTRL2); -	disable_irq_nosync(irq); -	schedule_work(&rx8025->work); -	return IRQ_HANDLED; +	if (ctrl2 < 0) +		return ctrl2; + +	ctrl2 &= ~(RX8025_BIT_CTRL2_PON | RX8025_BIT_CTRL2_VDET); + +	return rx8025_write_reg(client, RX8025_REG_CTRL2, +				ctrl2 | RX8025_BIT_CTRL2_XST);  } -static void rx8025_work(struct work_struct *work) +static irqreturn_t rx8025_handle_irq(int irq, void *dev_id)  { -	struct rx8025_data *rx8025 = container_of(work, struct rx8025_data, -						  work); -	struct i2c_client *client = rx8025->client; -	struct mutex *lock = &rx8025->rtc->ops_lock; -	u8 status; - -	mutex_lock(lock); +	struct i2c_client *client = dev_id; +	struct rx8025_data *rx8025 = i2c_get_clientdata(client); +	int status; -	if (rx8025_read_reg(client, RX8025_REG_CTRL2, &status)) +	status = rx8025_read_reg(client, RX8025_REG_CTRL2); +	if (status < 0)  		goto out;  	if (!(status & RX8025_BIT_CTRL2_XST)) @@ -161,9 +159,7 @@ static void rx8025_work(struct work_struct *work)  	if (status & RX8025_BIT_CTRL2_CTFG) {  		/* periodic */  		status &= ~RX8025_BIT_CTRL2_CTFG; -		local_irq_disable();  		rtc_update_irq(rx8025->rtc, 1, RTC_PF | RTC_IRQF); -		local_irq_enable();  	}  	if (status & RX8025_BIT_CTRL2_DAFG) { @@ -172,20 +168,11 @@ static void rx8025_work(struct work_struct *work)  		if (rx8025_write_reg(client, RX8025_REG_CTRL1,  				     rx8025->ctrl1 & ~RX8025_BIT_CTRL1_DALE))  			goto out; -		local_irq_disable();  		rtc_update_irq(rx8025->rtc, 1, RTC_AF | RTC_IRQF); -		local_irq_enable();  	} -	/* acknowledge IRQ */ -	rx8025_write_reg(client, RX8025_REG_CTRL2, -			 status | RX8025_BIT_CTRL2_XST); -  out: -	if (!rx8025->exiting) -		enable_irq(client->irq); - -	mutex_unlock(lock); +	return IRQ_HANDLED;  }  static int rx8025_get_time(struct device *dev, struct rtc_time *dt) @@ -194,6 +181,10 @@ static int rx8025_get_time(struct device *dev, struct rtc_time *dt)  	u8 date[7];  	int err; +	err = rx8025_check_validity(dev); +	if (err) +		return err; +  	err = rx8025_read_regs(rx8025->client, RX8025_REG_SEC, 7, date);  	if (err)  		return err; @@ -213,10 +204,7 @@ static int rx8025_get_time(struct device *dev, struct rtc_time *dt)  	dt->tm_mday = bcd2bin(date[RX8025_REG_MDAY] & 0x3f);  	dt->tm_mon = bcd2bin(date[RX8025_REG_MONTH] & 0x1f) - 1; -	dt->tm_year = bcd2bin(date[RX8025_REG_YEAR]); - -	if (dt->tm_year < 70) -		dt->tm_year += 100; +	dt->tm_year = bcd2bin(date[RX8025_REG_YEAR]) + 100;  	dev_dbg(dev, "%s: date %ds %dm %dh %dmd %dm %dy\n", __func__,  		dt->tm_sec, dt->tm_min, dt->tm_hour, @@ -229,12 +217,10 @@ static int rx8025_set_time(struct device *dev, struct rtc_time *dt)  {  	struct rx8025_data *rx8025 = dev_get_drvdata(dev);  	u8 date[7]; +	int ret; -	/* -	 * BUG: The HW assumes every year that is a multiple of 4 to be a leap -	 * year.  Next time this is wrong is 2100, which will not be a leap -	 * year. -	 */ +	if ((dt->tm_year < 100) || (dt->tm_year > 199)) +		return -EINVAL;  	/*  	 * Here the read-only bits are written as "0".  I'm not sure if that @@ -251,17 +237,21 @@ static int rx8025_set_time(struct device *dev, struct rtc_time *dt)  	date[RX8025_REG_WDAY] = bin2bcd(dt->tm_wday);  	date[RX8025_REG_MDAY] = bin2bcd(dt->tm_mday);  	date[RX8025_REG_MONTH] = bin2bcd(dt->tm_mon + 1); -	date[RX8025_REG_YEAR] = bin2bcd(dt->tm_year % 100); +	date[RX8025_REG_YEAR] = bin2bcd(dt->tm_year - 100);  	dev_dbg(dev,  		"%s: write 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x\n",  		__func__,  		date[0], date[1], date[2], date[3], date[4], date[5], date[6]); -	return rx8025_write_regs(rx8025->client, RX8025_REG_SEC, 7, date); +	ret = rx8025_write_regs(rx8025->client, RX8025_REG_SEC, 7, date); +	if (ret < 0) +		return ret; + +	return rx8025_reset_validity(rx8025->client);  } -static int rx8025_init_client(struct i2c_client *client, int *need_reset) +static int rx8025_init_client(struct i2c_client *client)  {  	struct rx8025_data *rx8025 = i2c_get_clientdata(client);  	u8 ctrl[2], ctrl2; @@ -275,38 +265,18 @@ static int rx8025_init_client(struct i2c_client *client, int *need_reset)  	/* Keep test bit zero ! */  	rx8025->ctrl1 = ctrl[0] & ~RX8025_BIT_CTRL1_TEST; -	if (ctrl[1] & RX8025_BIT_CTRL2_PON) { -		dev_warn(&client->dev, "power-on reset was detected, " -			 "you may have to readjust the clock\n"); -		*need_reset = 1; -	} - -	if (ctrl[1] & RX8025_BIT_CTRL2_VDET) { -		dev_warn(&client->dev, "a power voltage drop was detected, " -			 "you may have to readjust the clock\n"); -		*need_reset = 1; -	} - -	if (!(ctrl[1] & RX8025_BIT_CTRL2_XST)) { -		dev_warn(&client->dev, "Oscillation stop was detected," -			 "you may have to readjust the clock\n"); -		*need_reset = 1; -	} -  	if (ctrl[1] & (RX8025_BIT_CTRL2_DAFG | RX8025_BIT_CTRL2_WAFG)) {  		dev_warn(&client->dev, "Alarm was detected\n");  		need_clear = 1;  	} -	if (!(ctrl[1] & RX8025_BIT_CTRL2_CTFG)) +	if (ctrl[1] & RX8025_BIT_CTRL2_CTFG)  		need_clear = 1; -	if (*need_reset || need_clear) { -		ctrl2 = ctrl[0]; -		ctrl2 &= ~(RX8025_BIT_CTRL2_PON | RX8025_BIT_CTRL2_VDET | -			   RX8025_BIT_CTRL2_CTFG | RX8025_BIT_CTRL2_WAFG | +	if (need_clear) { +		ctrl2 = ctrl[1]; +		ctrl2 &= ~(RX8025_BIT_CTRL2_CTFG | RX8025_BIT_CTRL2_WAFG |  			   RX8025_BIT_CTRL2_DAFG); -		ctrl2 |= RX8025_BIT_CTRL2_XST;  		err = rx8025_write_reg(client, RX8025_REG_CTRL2, ctrl2);  	} @@ -319,8 +289,8 @@ static int rx8025_read_alarm(struct device *dev, struct rtc_wkalrm *t)  {  	struct rx8025_data *rx8025 = dev_get_drvdata(dev);  	struct i2c_client *client = rx8025->client; -	u8 ctrl2, ald[2]; -	int err; +	u8 ald[2]; +	int ctrl2, err;  	if (client->irq <= 0)  		return -EINVAL; @@ -329,9 +299,9 @@ static int rx8025_read_alarm(struct device *dev, struct rtc_wkalrm *t)  	if (err)  		return err; -	err = rx8025_read_reg(client, RX8025_REG_CTRL2, &ctrl2); -	if (err) -		return err; +	ctrl2 = rx8025_read_reg(client, RX8025_REG_CTRL2); +	if (ctrl2 < 0) +		return ctrl2;  	dev_dbg(dev, "%s: read alarm 0x%02x 0x%02x ctrl2 %02x\n",  		__func__, ald[0], ald[1], ctrl2); @@ -452,12 +422,11 @@ static struct rtc_class_ops rx8025_rtc_ops = {  static int rx8025_get_clock_adjust(struct device *dev, int *adj)  {  	struct i2c_client *client = to_i2c_client(dev); -	u8 digoff; -	int err; +	int digoff; -	err = rx8025_read_reg(client, RX8025_REG_DIGOFF, &digoff); -	if (err) -		return err; +	digoff = rx8025_read_reg(client, RX8025_REG_DIGOFF); +	if (digoff < 0) +		return digoff;  	*adj = digoff >= 64 ? digoff - 128 : digoff;  	if (*adj > 0) @@ -539,88 +508,53 @@ static int rx8025_probe(struct i2c_client *client,  {  	struct i2c_adapter *adapter = to_i2c_adapter(client->dev.parent);  	struct rx8025_data *rx8025; -	int err, need_reset = 0; +	int err = 0;  	if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA  				     | I2C_FUNC_SMBUS_I2C_BLOCK)) {  		dev_err(&adapter->dev,  			"doesn't support required functionality\n"); -		err = -EIO; -		goto errout; +		return -EIO;  	}  	rx8025 = devm_kzalloc(&client->dev, sizeof(*rx8025), GFP_KERNEL);  	if (!rx8025) { -		err = -ENOMEM; -		goto errout; +		return -ENOMEM;  	}  	rx8025->client = client;  	i2c_set_clientdata(client, rx8025); -	INIT_WORK(&rx8025->work, rx8025_work); -	err = rx8025_init_client(client, &need_reset); +	err = rx8025_init_client(client);  	if (err) -		goto errout; - -	if (need_reset) { -		struct rtc_time tm; -		dev_info(&client->dev, -			 "bad conditions detected, resetting date\n"); -		rtc_time_to_tm(0, &tm);	/* 1970/1/1 */ -		rx8025_set_time(&client->dev, &tm); -	} +		return err;  	rx8025->rtc = devm_rtc_device_register(&client->dev, client->name,  					  &rx8025_rtc_ops, THIS_MODULE);  	if (IS_ERR(rx8025->rtc)) { -		err = PTR_ERR(rx8025->rtc);  		dev_err(&client->dev, "unable to register the class device\n"); -		goto errout; +		return PTR_ERR(rx8025->rtc);  	}  	if (client->irq > 0) {  		dev_info(&client->dev, "IRQ %d supplied\n", client->irq); -		err = request_irq(client->irq, rx8025_irq, -				  0, "rx8025", client); +		err = devm_request_threaded_irq(&client->dev, client->irq, NULL, +						rx8025_handle_irq, 0, "rx8025", +						client);  		if (err) { -			dev_err(&client->dev, "unable to request IRQ\n"); -			goto errout; +			dev_err(&client->dev, "unable to request IRQ, alarms disabled\n"); +			client->irq = 0;  		}  	} -	rx8025->rtc->irq_freq = 1;  	rx8025->rtc->max_user_freq = 1;  	err = rx8025_sysfs_register(&client->dev); -	if (err) -		goto errout_irq; - -	return 0; - -errout_irq: -	if (client->irq > 0) -		free_irq(client->irq, client); - -errout: -	dev_err(&adapter->dev, "probing for rx8025 failed\n");  	return err;  }  static int rx8025_remove(struct i2c_client *client)  { -	struct rx8025_data *rx8025 = i2c_get_clientdata(client); -	struct mutex *lock = &rx8025->rtc->ops_lock; - -	if (client->irq > 0) { -		mutex_lock(lock); -		rx8025->exiting = 1; -		mutex_unlock(lock); - -		free_irq(client->irq, client); -		cancel_work_sync(&rx8025->work); -	} -  	rx8025_sysfs_unregister(&client->dev);  	return 0;  } @@ -628,7 +562,6 @@ static int rx8025_remove(struct i2c_client *client)  static struct i2c_driver rx8025_driver = {  	.driver = {  		.name = "rtc-rx8025", -		.owner = THIS_MODULE,  	},  	.probe		= rx8025_probe,  	.remove		= rx8025_remove,  |