2.6内核以后的多数驱动都是基于平台总线驱动模型(platform),对于平台总线来说,无非是两块组成
platform_driver和platform_device,在a5d2的bsp中,因为引入了device tree,因此,代码里已经看不到
platform_device了,下面以mac驱动为实例来分析device tree
1. 下面两段代码实现了macb平台驱动的注册
driver/net/ethernet/cadence/macb.c
include/linux.h
2. macb平台设备的创建是由设备树实现
3. 当注册驱动的时候,回调用platform_match这个函数进行driver和device的匹配,
static int platform_match(struct device *dev, struct device_driver *drv)
static inline int of_driver_match_device(struct device *dev, const struct device_driver *drv)
const struct of_device_id *of_match_device(const struct of_device_id *matches, const struct device *dev)
const struct of_device_id *of_match_node(const struct of_device_id *matches, const struct device_node *node)
static const struct of_device_id *__of_match_node(const struct of_device_id *matches, const struct device_node *node)
static int __of_device_is_compatible(const struct device_node *device,const char *compat, const char *type, const char *name)
通过上面的调用流程,最终会匹配设备树的compatible与platform_driver的of_match_table(下图)
从上图可以看到,最终回匹配到sama5d2-gen,匹配成功后,便会调用macb_probe函数
在macb_probe函数中进行mdiobus的注册,mdiobus的实现在mdio_bus.c
接下来就是从设备树中读取管脚配置,并配置管脚复用
int pinctrl_bind_pins(struct device *dev)
struct pinctrl *devm_pinctrl_get(struct device *dev)
struct pinctrl *pinctrl_get(struct device *dev)
static struct pinctrl *create_pinctrl(struct device *dev)
int pinctrl_dt_to_map(struct pinctrl *p)
static int dt_to_map_one_config(struct pinctrl *p, const char *statename, struct device_node *np_config)
static int dt_remember_or_free_map(struct pinctrl *p, const char *statename, struct pinctrl_dev *pctldev,
struct pinctrl_map *map, unsigned num_maps)
最终在这个函数的for循环里,可以打印出解析好的管脚配置
map[i].data.mux.group 为管脚的名字,如PB14
map[i].data.mux.function 为管脚的功能,为GPIO,A,B,C,D,E,F对应sama5d2-pinfunc.h中0,1,2,3,4,5,6
map[i].dev_name 为设备节点名称,如 f8008000.ethernet
map[i].name 为 pinctrl-names 的值
map[i].ctrl_dev_name 管脚复用节点父节点的名称,如fc038000.pinctrl
上面的函数调用完成了设备树管脚配置的解析,解析完成后,调用
static int atmel_pmx_set_mux(struct pinctrl_dev *pctldev, unsigned function, unsigned group)
来实现真正的管脚配置寄存器的写入