硬件平台
- RiotBoard imx6sol cortex A9
- linux 3.10
- RTC 芯片 MC13XXX i2c接口
驱动加载流程
<1> dts
mc13xxx是挂载在I2C下面的一个RTC芯片,和SOC自带RTC外设的方式多了一层I2C和 mc13xxx驱动代码的实例,后面关于RTC核心的内容都是一致的。
a)首先mc13xxx的驱动是在i2c下面实现的。
compatible 如下
static const struct of_device_id mc13xxx_dt_ids[] = {
{
.compatible = "fsl,mc13892",
.data = &mc13xxx_variant_mc13892,
}, {
.compatible = "fsl,mc34708",
.data = &mc13xxx_variant_mc34708,
}, {
/* sentinel */
}
};
b)dts 信息如下
&i2c2 {
pinctrl-names = "default";
pinctrl-0 = <&pinctrl_i2c2_1>;
status = "okay";
pmic: mc13892@08 {
compatible = "fsl,mc13892", "fsl,mc13xxx";
reg = <0x08>;
};
codec: sgtl5000@0a {
compatible = "fsl,sgtl5000";
reg = <0x0a>;
};
};
c)底层实现
mc13xxx_i2c.c 主要实现设备和驱动的匹配,使得mc13xxx设备获得操作本身的资源,即i2c driver。
借助I2C驱动,在mc13xxx core.c里面实现RTC基本操作,主要是一些读写寄存器的操作,和中断的访问等。
int mc13xxx_reg_read(struct mc13xxx *mc13xxx, unsigned int offset, u32 *val)
int mc13xxx_reg_write(struct mc13xxx *mc13xxx, unsigned int offset, u32 val)
这些个操作会被rtc-mc13xxx所用到实例化一个rtc设备,并在这个里面实现RTC相关的操作。(真是层层套娃呀。)
由于rtc-mc3xxx是一个虚拟出来的rtc设备他的实质是mc13xxx_i2c和mc13xxx的勾搭。(20211121增加,主要原因是,这个RTC设备没有在dts中体现,dts里面展现的是一个挂载在i2c下面的设备,没有办法通过platform_device和platfor_driver 自动匹配,这里直接手动进行匹配)
所以在设备和驱动匹配方面不能够像mc13xxx_i2c里卖弄一样通过dts文件去关联,这里使用了如下函数:
static const struct platform_device_id mc13xxx_rtc_idtable[] = {
{
.name = "mc13783-rtc",
}, {
.name = "mc13892-rtc",
}, {
.name = "mc34708-rtc",
},
{
/* sentinel */ }
};
MODULE_DEVICE_TABLE(platform, mc13xxx_rtc_idtable);
static struct platform_driver mc13xxx_rtc_driver = {
.id_table = mc13xxx_rtc_idtable,
.remove = __exit_p(mc13xxx_rtc_remove),
.driver = {
.name = DRIVER_NAME,
.owner = THIS_MODULE,
},
};
module_platform_driver_probe(mc13xxx_rtc_driver, &mc13xxx_rtc_probe);
把RTC的设备和相关的driver匹配起来。
实现了rtc设备和驱动下面的操作:
static const struct rtc_class_ops mc13xxx_rtc_ops = {
.read_time = mc13xxx_rtc_read_time,
.set_mmss = mc13xxx_rtc_set_mmss,
.read_alarm = mc13xxx_rtc_read_alarm,
.set_alarm = mc13xxx_rtc_set_alarm,
.alarm_irq_enable = mc13xxx_rtc_alarm_irq_enable,
};
上面的 mc13xxx_rtc_read_time 些都是调用 mc13xxx core.c 里面的函数实现的,读写不同寄存器的地址。这个时候RTC底层的设备驱动已经完成了,下面要添加设备文件了。
d)添加设备文件
在上面的底层操作里面,static int __init mc13xxx_rtc_probe(struct platform_device *pdev)是匹配设备和驱动的,匹配完成后会被执行。这个里面主要是设备设备的用的空间,设备的一些资源什么的。
static int __init mc13xxx_rtc_probe(struct platform_device *pdev)
{
int ret;
struct mc13xxx_rtc *priv;
struct mc13xxx *mc13xxx;
int rtcrst_pending;
priv = devm_kzalloc(&pdev->dev, sizeof(*priv)