前言
前面《Linux驱动分析之RTC框架》分析了RTC的基本框架,接下来拿个RTC驱动实例来分析一下。
RTC驱动分析
Linux版本:5.11
RTC设备: DS1302
(1) 加载和卸载函数
//DTS匹配staticconststructof_device_idds1302_dt_ids[] = { { .compatible="maxim,ds1302", }, { /* sentinel */ } }; MODULE_DEVICE_TABLE(of, ds1302_dt_ids); staticstructspi_driverds1302_driver= { .driver.name="rtc-ds1302", .driver.of_match_table=of_match_ptr(ds1302_dt_ids), .probe=ds1302_probe, .remove=ds1302_remove, }; //封住了module_init()和module_exit()module_spi_driver(ds1302_driver);
ds1302是一个SPI接口的RTC芯片。所以它的module_init是按照SPI接口框架实现的。
(2) probe()函数
staticintds1302_probe(structspi_device*spi) { structrtc_device*rtc; u8addr; u8buf[4]; u8*bp; intstatus; //检查SPI参数设置if (spi->bits_per_word&& (spi->bits_per_word!=8)) { dev_err(&spi->dev, "bad word length\n"); return-EINVAL; } elseif (spi->max_speed_hz>2000000) { dev_err(&spi->dev, "speed is too high\n"); return-EINVAL; } elseif (spi->mode&SPI_CPHA) { dev_err(&spi->dev, "bad mode\n"); return-EINVAL; } //省略ds1302的初始化spi_set_drvdata(spi, spi); //注册RTC设备rtc=devm_rtc_device_register(&spi->dev, "ds1302", &ds1302_rtc_ops, THIS_MODULE); //.....return0; }
probe()主要就是ds1302的初始化,我们省略掉这部分,它其实就是通过spi接口去设置ds1302的寄存器。
初始化完成之后就是调用 devm_rtc_device_register 进行rtc设备的注册,这个我们在前面的RTC框架中讲过。注册的函数中有一个 ds1302_rtc_ops 参数,它包含了操作RTC的接口函数。
(3)RTC操作函数
staticconststructrtc_class_opsds1302_rtc_ops= { .read_time=ds1302_rtc_get_time, //获取时间 .set_time=ds1302_rtc_set_time, //设置时间};
- ds1302_rtc_set_time
staticintds1302_rtc_set_time(structdevice*dev, structrtc_time*time) { structspi_device*spi=dev_get_drvdata(dev); u8buf[1+RTC_CLCK_LEN]; u8*bp; intstatus; /* 使能写 */bp=buf; *bp++=RTC_ADDR_CTRL<<1|RTC_CMD_WRITE; *bp++=RTC_CMD_WRITE_ENABLE; status=spi_write_then_read(spi, buf, 2, NULL, 0); if (status) returnstatus; /*设置寄存器地址和写入的数据 */bp=buf; *bp++=RTC_CLCK_BURST<<1|RTC_CMD_WRITE; *bp++=bin2bcd(time->tm_sec); *bp++=bin2bcd(time->tm_min); *bp++=bin2bcd(time->tm_hour); *bp++=bin2bcd(time->tm_mday); *bp++=bin2bcd(time->tm_mon+1); *bp++=time->tm_wday+1; *bp++=bin2bcd(time->tm_year%100); *bp++=RTC_CMD_WRITE_DISABLE; //使用SPI写入时间数据returnspi_write_then_read(spi, buf, sizeof(buf), NULL, 0); }
- ds1302_rtc_get_time
staticintds1302_rtc_get_time(structdevice*dev, structrtc_time*time) { structspi_device*spi=dev_get_drvdata(dev); u8addr=RTC_CLCK_BURST<<1|RTC_CMD_READ; u8buf[RTC_CLCK_LEN-1]; intstatus; //从寄存器中读取时间值status=spi_write_then_read(spi, &addr, sizeof(addr), buf, sizeof(buf)); if (status<0) returnstatus; //转成结构体保存time->tm_sec=bcd2bin(buf[RTC_ADDR_SEC]); time->tm_min=bcd2bin(buf[RTC_ADDR_MIN]); time->tm_hour=bcd2bin(buf[RTC_ADDR_HOUR]); time->tm_wday=buf[RTC_ADDR_DAY] -1; time->tm_mday=bcd2bin(buf[RTC_ADDR_DATE]); time->tm_mon=bcd2bin(buf[RTC_ADDR_MON]) -1; time->tm_year=bcd2bin(buf[RTC_ADDR_YEAR]) +100; return0; }
读写函数都比较简单,就是操作寄存器即可。
总结
RTC的驱动其实很简单,就是总线(I2C, SPI等)加上RTC驱动框架,其他的就是芯片寄存器的操作了,这部分只需要根据芯片手册来实现即可。