硬件修改版本后将原来用的rtc ds1307芯片换成了ht1382,导致系统无法启动。接下来准备在ds1307驱动中增加ht1382的驱动。
1 DS1307与HT1382的寄存器差异
DS1307 register:
****HT1382 register:
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;
}
修改这两个函数关于月,日,星期的寄存器内容写入即可。