diff options
Diffstat (limited to 'drivers/rtc/rtc-ds1307.c')
| -rw-r--r-- | drivers/rtc/rtc-ds1307.c | 182 | 
1 files changed, 94 insertions, 88 deletions
| diff --git a/drivers/rtc/rtc-ds1307.c b/drivers/rtc/rtc-ds1307.c index 62b0763b7b9a..cd188ab72f79 100644 --- a/drivers/rtc/rtc-ds1307.c +++ b/drivers/rtc/rtc-ds1307.c @@ -20,7 +20,8 @@ -/* We can't determine type by probing, but if we expect pre-Linux code +/* + * We can't determine type by probing, but if we expect pre-Linux code   * to have set the chip up as a clock (turning on the oscillator and   * setting the date and time), Linux can ignore the non-clock features.   * That's a natural job for a factory or repair bench. @@ -36,7 +37,8 @@ enum ds_type {  	m41t00,  	mcp7941x,  	rx_8025, -	// rs5c372 too?  different address... +	last_ds_type /* always last */ +	/* rs5c372 too?  different address... */  }; @@ -58,7 +60,8 @@ enum ds_type {  #	define DS1337_BIT_CENTURY	0x80	/* in REG_MONTH */  #define DS1307_REG_YEAR		0x06	/* 00-99 */ -/* Other registers (control, status, alarms, trickle charge, NVRAM, etc) +/* + * Other registers (control, status, alarms, trickle charge, NVRAM, etc)   * start at 7, and they differ a LOT. Only control and status matter for   * basic RTC date and time functionality; be careful using them.   */ @@ -102,6 +105,8 @@ enum ds_type {  struct ds1307 {  	u8			offset; /* register's offset */  	u8			regs[11]; +	u16			nvram_offset; +	struct bin_attribute	*nvram;  	enum ds_type		type;  	unsigned long		flags;  #define HAS_NVRAM	0		/* bit 0 == sysfs file active */ @@ -116,34 +121,35 @@ struct ds1307 {  };  struct chip_desc { -	unsigned		nvram56:1;  	unsigned		alarm:1; +	u16			nvram_offset; +	u16			nvram_size;  }; -static const struct chip_desc chips[] = { -[ds_1307] = { -	.nvram56	= 1, -}, -[ds_1337] = { -	.alarm		= 1, -}, -[ds_1338] = { -	.nvram56	= 1, -}, -[ds_1339] = { -	.alarm		= 1, -}, -[ds_1340] = { -}, -[ds_3231] = { -	.alarm		= 1, -}, -[m41t00] = { -}, -[mcp7941x] = { -}, -[rx_8025] = { -}, }; +static const struct chip_desc chips[last_ds_type] = { +	[ds_1307] = { +		.nvram_offset	= 8, +		.nvram_size	= 56, +	}, +	[ds_1337] = { +		.alarm		= 1, +	}, +	[ds_1338] = { +		.nvram_offset	= 8, +		.nvram_size	= 56, +	}, +	[ds_1339] = { +		.alarm		= 1, +	}, +	[ds_3231] = { +		.alarm		= 1, +	}, +	[mcp7941x] = { +		/* this is battery backed SRAM */ +		.nvram_offset	= 0x20, +		.nvram_size	= 0x40, +	}, +};  static const struct i2c_device_id ds1307_id[] = {  	{ "ds1307", ds_1307 }, @@ -372,6 +378,11 @@ static int ds1307_set_time(struct device *dev, struct rtc_time *t)  				| DS1340_BIT_CENTURY;  		break;  	case mcp7941x: +		/* +		 * these bits were cleared when preparing the date/time +		 * values and need to be set again before writing the +		 * buffer out to the device. +		 */  		buf[DS1307_REG_SECS] |= MCP7941X_BIT_ST;  		buf[DS1307_REG_WDAY] |= MCP7941X_BIT_VBATEN;  		break; @@ -417,7 +428,8 @@ static int ds1337_read_alarm(struct device *dev, struct rtc_wkalrm *t)  			ds1307->regs[6], ds1307->regs[7],  			ds1307->regs[8]); -	/* report alarm time (ALARM1); assume 24 hour and day-of-month modes, +	/* +	 * report alarm time (ALARM1); assume 24 hour and day-of-month modes,  	 * and that all four fields are checked matches  	 */  	t->time.tm_sec = bcd2bin(ds1307->regs[0] & 0x7f); @@ -445,7 +457,7 @@ static int ds1337_read_alarm(struct device *dev, struct rtc_wkalrm *t)  static int ds1337_set_alarm(struct device *dev, struct rtc_wkalrm *t)  { -	struct i2c_client       *client = to_i2c_client(dev); +	struct i2c_client	*client = to_i2c_client(dev);  	struct ds1307		*ds1307 = i2c_get_clientdata(client);  	unsigned char		*buf = ds1307->regs;  	u8			control, status; @@ -541,8 +553,6 @@ static const struct rtc_class_ops ds13xx_rtc_ops = {  /*----------------------------------------------------------------------*/ -#define NVRAM_SIZE	56 -  static ssize_t  ds1307_nvram_read(struct file *filp, struct kobject *kobj,  		struct bin_attribute *attr, @@ -555,14 +565,15 @@ ds1307_nvram_read(struct file *filp, struct kobject *kobj,  	client = kobj_to_i2c_client(kobj);  	ds1307 = i2c_get_clientdata(client); -	if (unlikely(off >= NVRAM_SIZE)) +	if (unlikely(off >= ds1307->nvram->size))  		return 0; -	if ((off + count) > NVRAM_SIZE) -		count = NVRAM_SIZE - off; +	if ((off + count) > ds1307->nvram->size) +		count = ds1307->nvram->size - off;  	if (unlikely(!count))  		return count; -	result = ds1307->read_block_data(client, 8 + off, count, buf); +	result = ds1307->read_block_data(client, ds1307->nvram_offset + off, +								count, buf);  	if (result < 0)  		dev_err(&client->dev, "%s error %d\n", "nvram read", result);  	return result; @@ -580,14 +591,15 @@ ds1307_nvram_write(struct file *filp, struct kobject *kobj,  	client = kobj_to_i2c_client(kobj);  	ds1307 = i2c_get_clientdata(client); -	if (unlikely(off >= NVRAM_SIZE)) +	if (unlikely(off >= ds1307->nvram->size))  		return -EFBIG; -	if ((off + count) > NVRAM_SIZE) -		count = NVRAM_SIZE - off; +	if ((off + count) > ds1307->nvram->size) +		count = ds1307->nvram->size - off;  	if (unlikely(!count))  		return count; -	result = ds1307->write_block_data(client, 8 + off, count, buf); +	result = ds1307->write_block_data(client, ds1307->nvram_offset + off, +								count, buf);  	if (result < 0) {  		dev_err(&client->dev, "%s error %d\n", "nvram write", result);  		return result; @@ -595,21 +607,8 @@ ds1307_nvram_write(struct file *filp, struct kobject *kobj,  	return count;  } -static struct bin_attribute nvram = { -	.attr = { -		.name	= "nvram", -		.mode	= S_IRUGO | S_IWUSR, -	}, - -	.read	= ds1307_nvram_read, -	.write	= ds1307_nvram_write, -	.size	= NVRAM_SIZE, -}; -  /*----------------------------------------------------------------------*/ -static struct i2c_driver ds1307_driver; -  static int __devinit ds1307_probe(struct i2c_client *client,  				  const struct i2c_device_id *id)  { @@ -630,7 +629,8 @@ static int __devinit ds1307_probe(struct i2c_client *client,  	    && !i2c_check_functionality(adapter, I2C_FUNC_SMBUS_I2C_BLOCK))  		return -EIO; -	if (!(ds1307 = kzalloc(sizeof(struct ds1307), GFP_KERNEL))) +	ds1307 = kzalloc(sizeof(struct ds1307), GFP_KERNEL); +	if (!ds1307)  		return -ENOMEM;  	i2c_set_clientdata(client, ds1307); @@ -652,11 +652,6 @@ static int __devinit ds1307_probe(struct i2c_client *client,  	case ds_1337:  	case ds_1339:  	case ds_3231: -		/* has IRQ? */ -		if (ds1307->client->irq > 0 && chip->alarm) { -			INIT_WORK(&ds1307->work, ds1307_work); -			want_irq = true; -		}  		/* get registers that the "rtc" read below won't read... */  		tmp = ds1307->read_block_data(ds1307->client,  				DS1337_REG_CONTROL, 2, buf); @@ -670,14 +665,19 @@ static int __devinit ds1307_probe(struct i2c_client *client,  		if (ds1307->regs[0] & DS1337_BIT_nEOSC)  			ds1307->regs[0] &= ~DS1337_BIT_nEOSC; -		/* Using IRQ?  Disable the square wave and both alarms. +		/* +		 * Using IRQ?  Disable the square wave and both alarms.  		 * For some variants, be sure alarms can trigger when we're  		 * running on Vbackup (BBSQI/BBSQW)  		 */ -		if (want_irq) { +		if (ds1307->client->irq > 0 && chip->alarm) { +			INIT_WORK(&ds1307->work, ds1307_work); +  			ds1307->regs[0] |= DS1337_BIT_INTCN  					| bbsqi_bitpos[ds1307->type];  			ds1307->regs[0] &= ~(DS1337_BIT_A2IE | DS1337_BIT_A1IE); + +			want_irq = true;  		}  		i2c_smbus_write_byte_data(client, DS1337_REG_CONTROL, @@ -772,7 +772,8 @@ read_rtc:  		goto exit_free;  	} -	/* minimal sanity checking; some chips (like DS1340) don't +	/* +	 * minimal sanity checking; some chips (like DS1340) don't  	 * specify the extra bits as must-be-zero, but there are  	 * still a few values that are clearly out-of-range.  	 */ @@ -836,11 +837,7 @@ read_rtc:  		}  		break; -	case rx_8025: -	case ds_1337: -	case ds_1339: -	case ds_1388: -	case ds_3231: +	default:  		break;  	} @@ -848,7 +845,8 @@ read_rtc:  	switch (ds1307->type) {  	case ds_1340:  	case m41t00: -		/* NOTE: ignores century bits; fix before deploying +		/* +		 * NOTE: ignores century bits; fix before deploying  		 * systems that will run through year 2100.  		 */  		break; @@ -858,7 +856,8 @@ read_rtc:  		if (!(tmp & DS1307_BIT_12HR))  			break; -		/* Be sure we're in 24 hour mode.  Multi-master systems +		/* +		 * Be sure we're in 24 hour mode.  Multi-master systems  		 * take note...  		 */  		tmp = bcd2bin(tmp & 0x1f); @@ -894,16 +893,31 @@ read_rtc:  		dev_dbg(&client->dev, "got IRQ %d\n", client->irq);  	} -	if (chip->nvram56) { -		err = sysfs_create_bin_file(&client->dev.kobj, &nvram); -		if (err == 0) { -			set_bit(HAS_NVRAM, &ds1307->flags); -			dev_info(&client->dev, "56 bytes nvram\n"); +	if (chip->nvram_size) { +		ds1307->nvram = kzalloc(sizeof(struct bin_attribute), +							GFP_KERNEL); +		if (!ds1307->nvram) { +			err = -ENOMEM; +			goto exit_nvram; +		} +		ds1307->nvram->attr.name = "nvram"; +		ds1307->nvram->attr.mode = S_IRUGO | S_IWUSR; +		ds1307->nvram->read = ds1307_nvram_read, +		ds1307->nvram->write = ds1307_nvram_write, +		ds1307->nvram->size = chip->nvram_size; +		ds1307->nvram_offset = chip->nvram_offset; +		err = sysfs_create_bin_file(&client->dev.kobj, ds1307->nvram); +		if (err) { +			kfree(ds1307->nvram); +			goto exit_nvram;  		} +		set_bit(HAS_NVRAM, &ds1307->flags); +		dev_info(&client->dev, "%zu bytes nvram\n", ds1307->nvram->size);  	}  	return 0; +exit_nvram:  exit_irq:  	rtc_device_unregister(ds1307->rtc);  exit_free: @@ -913,15 +927,17 @@ exit_free:  static int __devexit ds1307_remove(struct i2c_client *client)  { -	struct ds1307		*ds1307 = i2c_get_clientdata(client); +	struct ds1307 *ds1307 = i2c_get_clientdata(client);  	if (test_and_clear_bit(HAS_ALARM, &ds1307->flags)) {  		free_irq(client->irq, client);  		cancel_work_sync(&ds1307->work);  	} -	if (test_and_clear_bit(HAS_NVRAM, &ds1307->flags)) -		sysfs_remove_bin_file(&client->dev.kobj, &nvram); +	if (test_and_clear_bit(HAS_NVRAM, &ds1307->flags)) { +		sysfs_remove_bin_file(&client->dev.kobj, ds1307->nvram); +		kfree(ds1307->nvram); +	}  	rtc_device_unregister(ds1307->rtc);  	kfree(ds1307); @@ -938,17 +954,7 @@ static struct i2c_driver ds1307_driver = {  	.id_table	= ds1307_id,  }; -static int __init ds1307_init(void) -{ -	return i2c_add_driver(&ds1307_driver); -} -module_init(ds1307_init); - -static void __exit ds1307_exit(void) -{ -	i2c_del_driver(&ds1307_driver); -} -module_exit(ds1307_exit); +module_i2c_driver(ds1307_driver);  MODULE_DESCRIPTION("RTC driver for DS1307 and similar chips");  MODULE_LICENSE("GPL"); | 
