内核:4.20
芯片:HYM8563 RTC
下面的代码分析主要都在注释中,会按照驱动中函数的执行顺序分析。
一、加载和卸载函数
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 | static const struct i2c_device_id hym8563_id[] = { { "hym8563", 0 }, {}, }; MODULE_DEVICE_TABLE(i2c, hym8563_id); static const struct of_device_id hym8563_dt_idtable[] = { { .compatible = "haoyu,hym8563" }, {}, }; MODULE_DEVICE_TABLE(of, hym8563_dt_idtable); static struct i2c_driver hym8563_driver = { .driver = { .name = "rtc-hym8563", .pm = &hym8563_pm_ops, .of_match_table = hym8563_dt_idtable, //dt匹配表 }, .probe = hym8563_probe, .id_table = hym8563_id,// id表 }; // 封住了module_init()和module_exit() // 里面会调用i2c_register_driver(hym8563_driver) // 和i2c_del_driver(hym8563_driver) module_i2c_driver(hym8563_driver); |
二、probe()函数
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 | static int hym8563_probe(struct i2c_client *client, const struct i2c_device_id *id) { struct hym8563 *hym8563; int ret; //申请内存空间 hym8563 = devm_kzalloc(&client->dev, sizeof(*hym8563), GFP_KERNEL); if (!hym8563) return -ENOMEM; //保存数据 hym8563->client = client; i2c_set_clientdata(client, hym8563); //HYM8563初始化 ret = hym8563_init_device(client); //申请中断 if (client->irq > 0) { ret = devm_request_threaded_irq(&client->dev, client->irq, NULL, hym8563_irq, IRQF_TRIGGER_LOW | IRQF_ONESHOT, client->name, hym8563); } //检查一下模块是否正常运行 ret = i2c_smbus_read_byte_data(client, HYM8563_SEC); if (ret < 0) return ret; //VL位用来标识模块是否正常工作 hym8563->valid = !(ret & HYM8563_SEC_VL); dev_dbg(&client->dev, "rtc information is %s\n", hym8563->valid ? "valid" : "invalid"); //注册RTC设备 hym8563->rtc = devm_rtc_device_register(&client->dev, client->name, &hym8563_rtc_ops, THIS_MODULE); /* the hym8563 alarm only supports a minute accuracy */ hym8563->rtc->uie_unsupported = 1; #ifdef CONFIG_COMMON_CLK //HYM8563可以作为时钟源 hym8563_clkout_register_clk(hym8563); #endif return 0; } |
上面删掉了一些判断和Log信息。
三、HYM8563初始化
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 | //查看datasheet对8563进行初始化,对寄存器进行设置 static int hym8563_init_device(struct i2c_client *client) { int ret; /* Clear stop flag if present */ //向寄存器中写入值 ret = i2c_smbus_write_byte_data(client, HYM8563_CTL1, 0); if (ret < 0) return ret; //读取寄存器的值 ret = i2c_smbus_read_byte_data(client, HYM8563_CTL2); if (ret < 0) return ret; /* Disable alarm and timer interrupts */ ret &= ~HYM8563_CTL2_AIE; ret &= ~HYM8563_CTL2_TIE; /* Clear any pending alarm and timer flags */ if (ret & HYM8563_CTL2_AF) ret &= ~HYM8563_CTL2_AF; if (ret & HYM8563_CTL2_TF) ret &= ~HYM8563_CTL2_TF; ret &= ~HYM8563_CTL2_TI_TP; //将修改后的值写入寄存器 return i2c_smbus_write_byte_data(client, HYM8563_CTL2, ret); } |
四、HYM8563操作函数
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 | static int hym8563_rtc_read_time(struct device *dev, struct rtc_time *tm) { struct i2c_client *client = to_i2c_client(dev); struct hym8563 *hym8563 = i2c_get_clientdata(client); u8 buf[7]; int ret; if (!hym8563->valid) { dev_warn(&client->dev, "no valid clock/calendar values available\n"); return -EPERM; } //读取寄存器值, 连续读取7个寄存器 ret = i2c_smbus_read_i2c_block_data(client, HYM8563_SEC, 7, buf); //bcd数转成2进制 tm->tm_sec = bcd2bin(buf[0] & HYM8563_SEC_MASK); tm->tm_min = bcd2bin(buf[1] & HYM8563_MIN_MASK); tm->tm_hour = bcd2bin(buf[2] & HYM8563_HOUR_MASK); tm->tm_mday = bcd2bin(buf[3] & HYM8563_DAY_MASK); tm->tm_wday = bcd2bin(buf[4] & HYM8563_WEEKDAY_MASK); /* 0 = Sun */ tm->tm_mon = bcd2bin(buf[5] & HYM8563_MONTH_MASK) - 1; /* 0 = Jan */ tm->tm_year = bcd2bin(buf[6]) + 100; return 0; } static const struct rtc_class_ops hym8563_rtc_ops = { .read_time = hym8563_rtc_read_time, .set_time = hym8563_rtc_set_time, .alarm_irq_enable = hym8563_rtc_alarm_irq_enable, .read_alarm = hym8563_rtc_read_alarm, .set_alarm = hym8563_rtc_set_alarm, }; |
其他的读写函数都是去通过I2C去读取寄存器的值。

上面的调用关系图显示了设备与控制器之间的关系。