在rtc ds1307的驱动中增加rtc ht1382芯片驱动

硬件修改版本后将原来用的rtc ds1307芯片换成了ht1382,导致系统无法启动。接下来准备在ds1307驱动中增加ht1382的驱动。

1 DS1307与HT1382的寄存器差异

DS1307 register:
****1-1 ds1307 register viewHT1382 register:
1-2 HT1382 register view note: 红色框的内容是两种芯片差异的部分

2 增加HT1382驱动

在设备类型中增加我们的rtc芯片:

/*
 * 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.
 */
enum ds_type {
	ds_1307,
	ds_1337,
	ds_1338,
	ds_1339,
	ds_1340,
	ds_1388,
	ds_3231,
	m41t00,
	mcp794xx,
	rx_8025,
	ht_1382, /*add rtc ht1382 type*/
	last_ds_type /* always last */
	/* rs5c372 too?  different address... */
};

根据HT1382寄存器手册增加宏定义:

/****************add ht1382 register define****************/
#define HT1382_REG_MDAY	0x03	/* 01-31 */
#define HT1382_REG_MONTH	0x04	/* 01-12 */
#define HT1382_REG_WDAY	0x05	/* 01-07 */
#define HT1382_REG_WP		0x07
#	define HT1382_BIT_WP		0x80
/********************add end**********************/

增加芯片描述:

static struct chip_desc chips[last_ds_type] = {
	[ds_1307] = {
		.nvram_offset	= 8,
		.nvram_size	= 56,
	},
	
	/*add ht1382 chip desc, same as ds1307*/
	[ht_1382] = {
		.nvram_offset	= 8,
		.nvram_size	= 56,
	},
	
	[ds_1337] = {
		.alarm		= 1,
	},
	[ds_1338] = {
		.nvram_offset	= 8,
		.nvram_size	= 56,
	},
	[ds_1339] = {
		.alarm		= 1,
		.trickle_charger_reg = 0x10,
		.do_trickle_setup = &do_trickle_setup_ds1339,
	},
	[ds_1340] = {
		.trickle_charger_reg = 0x08,
	},
	[ds_1388] = {
		.trickle_charger_reg = 0x0a,
	},
	[ds_3231] = {
		.alarm		= 1,
	},
	[mcp794xx] = {
		.alarm		= 1,
		/* this is battery backed SRAM */
		.nvram_offset	= 0x20,
		.nvram_size	= 0x40,
	},
};

增加ht1382 device id:

static const struct i2c_device_id ds1307_id[] = {
	{ "ds1307", ds_1307 },
	{ "ds1337", ds_1337 },
	{ "ds1338", ds_1338 },
	{ "ds1339", ds_1339 },
	{ "ds1388", ds_1388 },
	{ "ds1340", ds_1340 },
	{ "ds3231", ds_3231 },
	{ "m41t00", m41t00 },
	{ "mcp7940x", mcp794xx },
	{ "mcp7941x", mcp794xx },
	{ "pt7c4338", ds_1307 },
	{ "rx8025", rx_8025 },
	/*dts compatible should be set "dallas,ht1382"*/
	{ "ht1382", ht_1382 },
	{ }
};

以上是需要在数据结构中添加的一些东西。

然后在添加驱动时需要注意,HT1382比DS1307多了一个Write Protect寄存器,我们可以在设备probe时直接设置关掉,或者仅在用户调用写时间函数时关闭写保护,此处笔者选择的前者:

static int ds1307_probe(struct i2c_client *client,
			const struct i2c_device_id *id)
{
	struct ds1307		*ds1307;
	int			err = -ENODEV;
	int			tmp;
	struct chip_desc	*chip = &chips[id->driver_data];
	struct i2c_adapter	*adapter = to_i2c_adapter(client->dev.parent);

	....................

	if (i2c_check_functionality(adapter, I2C_FUNC_SMBUS_I2C_BLOCK)) {
		ds1307->read_block_data = ds1307_native_smbus_read_block_data;
		ds1307->write_block_data = ds1307_native_smbus_write_block_data;
	} else {
		ds1307->read_block_data = ds1307_read_block_data;
		ds1307->write_block_data = ds1307_write_block_data;
	}

	switch (ds1307->type) {
	/*add ht1382 driver for close write protect*/
	case ht_1382:
		/* check write protect reg */
		tmp = ds1307->read_block_data(ds1307->client,
				HT1382_REG_WP, 2, &(ds1307->regs[HT1382_REG_WP]));
		if(tmp != 2){
			dev_dbg(&client->dev, "read error %d\n", tmp);
			err = -EIO;
			goto exit;
		}

		if (ds1307->regs[HT1382_REG_WP] & HT1382_BIT_WP){
			ds1307->regs[HT1382_REG_WP] &= ~HT1382_BIT_WP;
			i2c_smbus_write_byte_data(client, HT1382_REG_WP,
							ds1307->regs[HT1382_REG_WP]);
		}
		break;
	case ds_1337:
	case ds_1339:
	case ds_3231:
		/* get registers that the "rtc" read below won't read... */
		tmp = ds1307->read_block_data(ds1307->client,
				DS1337_REG_CONTROL, 2, buf);

在probe函数中还有一处是需要检查Clock HALT 的,我们需要给ht1382也加上:

	/*
	 * 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.
	 */
	tmp = ds1307->regs[DS1307_REG_SECS];
	switch (ds1307->type) {
	case ds_1307:
	case ht_1382:
	case m41t00:
		/* clock halted?  turn it on, so clock can tick. */
		if (tmp & DS1307_BIT_CH) {
			i2c_smbus_write_byte_data(client, DS1307_REG_SECS, 0);
			dev_warn(&client->dev, "SET TIME!\n");
			goto read_rtc;
		}
		break;

由于HT1382的月份,日期和星期的寄存器和DS1307不太相同,所以我们还需要修改ds13xx_rtc_ops中的read_time和set_time

static const struct rtc_class_ops ds13xx_rtc_ops = {
	.read_time	= ds1307_get_time, //need modify
	.set_time	= ds1307_set_time, //need modify
	.read_alarm	= ds1337_read_alarm,
	.set_alarm	= ds1337_set_alarm,
	.alarm_irq_enable = ds1307_alarm_irq_enable,
};

修改ds1307_get_time函数:

static int ds1307_get_time(struct device *dev, struct rtc_time *t)
{
	struct ds1307	*ds1307 = dev_get_drvdata(dev);
	int		tmp;

	/* read the RTC date and time registers all at once */
	tmp = ds1307->read_block_data(ds1307->client,
		ds1307->offset, 7, ds1307->regs);
	if (tmp != 7) {
		dev_err(dev, "%s error %d\n", "read", tmp);
		return -EIO;
	}

	dev_dbg(dev, "%s: %7ph\n", "read", ds1307->regs);

	t->tm_sec = bcd2bin(ds1307->regs[DS1307_REG_SECS] & 0x7f);
	t->tm_min = bcd2bin(ds1307->regs[DS1307_REG_MIN] & 0x7f);
	tmp = ds1307->regs[DS1307_REG_HOUR] & 0x3f;
	t->tm_hour = bcd2bin(tmp);
	/*add ht1382*/
	switch (ds1307->type) {
	case ht_1382:
		t->tm_wday = bcd2bin(ds1307->regs[HT1382_REG_WDAY] & 0x07) - 1;
		t->tm_mday = bcd2bin(ds1307->regs[HT1382_REG_MDAY] & 0x3f);
		tmp = ds1307->regs[HT1382_REG_MONTH] & 0x1f;
		t->tm_mon = bcd2bin(tmp) - 1;
		break;
	default:
		t->tm_wday = bcd2bin(ds1307->regs[DS1307_REG_WDAY] & 0x07) - 1;
		t->tm_mday = bcd2bin(ds1307->regs[DS1307_REG_MDAY] & 0x3f);
		tmp = ds1307->regs[DS1307_REG_MONTH] & 0x1f;
		t->tm_mon = bcd2bin(tmp) - 1;
		break;
	}
	/*add end*/
	/* assume 20YY not 19YY, and ignore DS1337_BIT_CENTURY */
	t->tm_year = bcd2bin(ds1307->regs[DS1307_REG_YEAR]) + 100;

	dev_dbg(dev, "%s secs=%d, mins=%d, "
		"hours=%d, mday=%d, mon=%d, year=%d, wday=%d\n",
		"read", t->tm_sec, t->tm_min,
		t->tm_hour, t->tm_mday,
		t->tm_mon, t->tm_year, t->tm_wday);

	/* initial clock setting can be undefined */
	return rtc_valid_tm(t);
}

修改ds1307_set_time函数:

static int ds1307_set_time(struct device *dev, struct rtc_time *t)
{
	struct ds1307	*ds1307 = dev_get_drvdata(dev);
	int		result;
	int		tmp;
	u8		*buf = ds1307->regs;

	dev_dbg(dev, "%s secs=%d, mins=%d, "
		"hours=%d, mday=%d, mon=%d, year=%d, wday=%d\n",
		"write", t->tm_sec, t->tm_min,
		t->tm_hour, t->tm_mday,
		t->tm_mon, t->tm_year, t->tm_wday);

	buf[DS1307_REG_SECS] = bin2bcd(t->tm_sec);
	buf[DS1307_REG_MIN] = bin2bcd(t->tm_min);
	buf[DS1307_REG_HOUR] = bin2bcd(t->tm_hour);
	buf[DS1307_REG_WDAY] = bin2bcd(t->tm_wday + 1);
	buf[DS1307_REG_MDAY] = bin2bcd(t->tm_mday);
	buf[DS1307_REG_MONTH] = bin2bcd(t->tm_mon + 1);

	/* assume 20YY not 19YY */
	tmp = t->tm_year - 100;
	buf[DS1307_REG_YEAR] = bin2bcd(tmp);

	switch (ds1307->type) {
	case ds_1337:
	case ds_1339:
	case ds_3231:
		buf[DS1307_REG_MONTH] |= DS1337_BIT_CENTURY;
		break;
	case ds_1340:
		buf[DS1307_REG_HOUR] |= DS1340_BIT_CENTURY_EN
				| DS1340_BIT_CENTURY;
		break;
	case mcp794xx:
		/*
		 * 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] |= MCP794XX_BIT_ST;
		buf[DS1307_REG_WDAY] |= MCP794XX_BIT_VBATEN;
		break;
	/*add ht1382*/
	case ht_1382:
		buf[HT1382_REG_WDAY] = bin2bcd(t->tm_wday + 1);
		buf[HT1382_REG_MDAY] = bin2bcd(t->tm_mday);
		buf[HT1382_REG_MONTH] = bin2bcd(t->tm_mon + 1);
		break;
	/*add end*/
	default:
		break;
	}

	dev_dbg(dev, "%s: %7ph\n", "write", buf);

	result = ds1307->write_block_data(ds1307->client,
		ds1307->offset, 7, buf);
	if (result < 0) {
		dev_err(dev, "%s error %d\n", "write", result);
		return result;
	}
	return 0;
}

修改这两个函数关于月,日,星期的寄存器内容写入即可。

  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值