1、RTC模块的设备驱动模型
3、RTC模块涉及的文件和数据结构
(1)、相关的文件:
934x.c :该文件为系统的硬件平台文件,定义了RTC模块用到的硬件资源,包括内存地址空间,GPIO,中断资源,并将RTC设备注册进内核的设备链表中。
rtc-ds1307.c:该文件为RTC模块的设备驱动文件,实现了对RTC硬件的操作接口,并将该设备驱动注册进内核的设备驱动链表中。
/driver/rtc/class.c:该文件实现RTC设备驱动模型的核心,包括创建rtc类,注册rtc设备
/driver/rtc/rtc-dev.c:该文件初始化一个file_operation,并实现结构体内的函数
/driver/rtc/interface.h:该文件实现file_operation中ioctl中对应命令的函数实现。
/driver/rtc/rtc-sysfs.c:该文件主要实现和sysfs相关的操作,在sysfs目录下创建设备属性组。
/driver/rtc/rtc-proc.c:该文件提供RTC的proc文件系统接口。
i2c-gpio.c :该文件为GPIO模拟I2C适配器的设备驱动文件,实现了对I2C适配器的操作接口,并将该I2C适配器的驱动注册进内核,
i2c-core.c :该文件是i2c的核心,提供i2c模块相关的公共接口,包括i2c设备注册 i2c适配器注册,以及和文件系统相关的操作。
i2c-algo-bit.c :该文件时I2C协议的实现,通过该文件提供的接口,完成对I2C设备的访问。
gpio.c: 该文件实现了对GPIO的操作接口,包括对GPIO的配置,读写操作。
gpiolib.c: 该文件实现了和GPIO相关的接口。
(2)、RTC模块涉及的数据结构:
//RTC设备
struct rtc_device
{
struct device dev;
struct module *owner;
int id;
char name[RTC_DEVICE_NAME_SIZE];
const struct rtc_class_ops *ops;
struct mutex ops_lock;
struct cdev char_dev;
unsigned long flags;
unsigned long irq_data;
spinlock_t irq_lock;
wait_queue_head_t irq_queue;
struct fasync_struct *async_queue;
struct rtc_task *irq_task;
spinlock_t irq_task_lock;
int irq_freq;
int max_user_freq;
#ifdef CONFIG_RTC_INTF_DEV_UIE_EMUL
struct work_struct uie_task;
struct timer_list uie_timer;
/* Those fields are protected by rtc->irq_lock */
unsigned int oldsecs;
unsigned int uie_irq_active:1;
unsigned int stop_uie_polling:1;
unsigned int uie_task_active:1;
unsigned int uie_timer_active:1;
#endif
};
//RTC设备的操作接口
struct rtc_class_ops {
int (*open)(structdevice *);
void (*release)(structdevice *);
int (*ioctl)(struct device *, unsigned int, unsigned long);
int (*read_time)(struct device *, struct rtc_time *);
int(*set_time)(struct device *, struct rtc_time *);
int (*read_alarm)(struct device *, struct rtc_wkalrm *);
int(*set_alarm)(struct device *, struct rtc_wkalrm *);
int (*proc)(structdevice *, struct seq_file *);
int (*set_mmss)(structdevice *, unsigned long secs);
int(*irq_set_state)(struct device *, int enabled);
int(*irq_set_freq)(struct device *, int freq);
int(*read_callback)(struct device *, int data);
int(*alarm_irq_enable)(struct device *, unsigned int enabled);
int(*update_irq_enable)(struct device *, unsigned int enabled);
};
//代表了时间与日期,从RTC设备读回的时间和日期就保存在这个结构体中
struct rtc_time
{ int tm_sec;
int tm_min;
int tm_hour;
int tm_mday;
int tm_mon;
int tm_year;
int tm_wday;
int tm_yday;
int tm_isdst;
};
(3)、I2C模块涉及的数据结构
//记录i2c设备的信息
struct i2c_board_info {
char type[I2C_NAME_SIZE];//I2C_client芯片的型号
unsigned short flags;//I2C_client的标志位
unsigned short addr;//I2C_client的地址
void *platform_data;//I2C_client的平台数据
struct dev_archdata *archdata;// I2C_client的物理数据
int irq;//中断
};
//记录i2c总线适配器的平台信息
struct i2c_gpio_platform_data {
unsigned int sda_pin;
unsigned int scl_pin;
int udelay;
int timeout;
unsigned int sda_is_open_drain:1;
unsigned int scl_is_open_drain:1;
unsigned int scl_is_output_only:1;
};
//i2c设备驱动
struct i2c_driver {
int id;
unsigned int class;
int(*attach_adapter)(struct i2c_adapter *);
int (*detach_adapter)(structi2c_adapter *);
/* Standard drivermodel interfaces */
int (*probe)(struct i2c_client *, const struct i2c_device_id *);
int(*remove)(struct i2c_client *);
/* driver modelinterfaces that don't relate to enumeration */
void (*shutdown)(structi2c_client *);
int (*suspend)(structi2c_client *, pm_message_t mesg);
int (*resume)(structi2c_client *);
int (*command)(structi2c_client *client, unsigned int cmd, void *arg);
struct device_driver driver;
const struct i2c_device_id *id_table;
/* Device detectioncallback for automatic device creation */
int (*detect)(structi2c_client *, int kind, struct i2c_board_info *);
const structi2c_client_address_data *address_data;
struct list_headclients;
};
//I2C总线的协议算法实现
struct i2c_algorithm {
int(*master_xfer)(struct i2c_adapter *adap, struct i2c_msg *msgs, int num);
int (*smbus_xfer)(struct i2c_adapter *adap, u16 addr, unsigned short flags, char read_write,
u8 command, int size, union i2c_smbus_data*data);
u32 (*functionality)(struct i2c_adapter *);
};
//i2c总线适配器
struct i2c_adapter {
struct module *owner;
unsigned intid;
unsigned int class; /* classes to allow probing for */
const struct i2c_algorithm *algo; /* the algorithm to access thebus */
void *algo_data;
/* data fields that arevalid for all devices */
u8 level; /* nesting level for lockdep */
struct mutex bus_lock;
int timeout; /* in jiffies */
int retries;
struct device dev; /* the adapter device */
int nr;
char name[48];
struct completiondev_released;
};
//GPIO控制器
struct gpio_chip {
const char *label;
struct device *dev;
struct module *owner;
int (*request)(struct gpio_chip*chip,unsigned offset);
void (*free)(struct gpio_chip *chip,unsignedoffset);
int (*direction_input)(struct gpio_chip*chip,unsigned offset);
int (*get)(struct gpio_chip *chip,unsigned offset);
int (*direction_output)(structgpio_chip *chip,unsigned offset, int value);
void (*set)(struct gpio_chip *chip,unsigned offset,int value);
int (*to_irq)(struct gpio_chip*chip,unsigned offset);
void (*dbg_show)(struct seq_file *s,structgpio_chip *chip);
int base;
u16 ngpio;
char **names;
unsigned can_sleep:1;
unsigned exported:1;
};
4、RTC模块驱动重要代码和流程分析
(1)代码分析:参见SVN源码,注释处有声明
rtc-dev.c-->interface.c-->rtc-ds1307
rtc-dev.c: 该文件最终生成/dev/rtc,为应用层提供操作RTC的标准接口
interface.c:接口文件,对驱动接口进行封装,给上层提供统一的接口,屏蔽芯片的差异性。
rtc-ds1307.c:直接和硬件交互的驱动接口的文件
class.c:提供子RTC子系统一些公共函数,将RTC驱动注册集成到linux内核中,是一个粘合剂。
hctosys.c:系统起来后,读RTC硬件中的时间,更新系统时间。
2.函数的实现
(2)流程分析:
设备端: 定义并初始化RTC设备结构体,并将其注册进内核设备链表中,(设备的类型和地址)
定义并初始化I2C总线适配器的结构体,并以平台设备注册进内核的设备链表中,
设备驱动端:实现对RTC设备的操作接口,定义并初始化RTC设备驱动结构体,注册进内核设备驱动链表,匹配设备和驱动,成功后调用设备初始化函数对设备进行初始化。
5、开发过程中遇到的问题
(1)对GPIO配置的问题
GPIO的IO基地址设置错误,GPIO的function寄存器未设置。
(2)对I2C适配器参数设置的问题,(使用硬件资源的配置,硬件参数配置、延迟和超时的配置,满足I2C协议和硬件特性的要求)