一.注册硬件模块
1.硬件模块
struct omap_hwmod {
const char *name;
struct omap_hwmod_class *class;
struct omap_device *od;
struct omap_hwmod_mux_info *mux;
struct omap_hwmod_irq_info *mpu_irqs;
struct omap_hwmod_dma_info *sdma_reqs;
struct omap_hwmod_rst_info *rst_lines;
union {
struct omap_hwmod_omap2_prcm omap2;
struct omap_hwmod_omap4_prcm omap4;
} prcm;
const char *main_clk;
struct clk *_clk;
struct omap_hwmod_opt_clk *opt_clks;
char *clkdm_name;
struct clockdomain *clkdm;
char *vdd_name;
struct omap_hwmod_ocp_if **masters; /* connect to *_IA */
struct omap_hwmod_ocp_if **slaves; /* connect to *_TA */
void *dev_attr;
u32 _sysc_cache;
void __iomem *_mpu_rt_va;
spinlock_t _lock;
struct list_head node;
u16 flags;
u8 _mpu_port_index;
u8 response_lat;
u8 rst_lines_cnt;
u8 opt_clks_cnt;
u8 masters_cnt;
u8 slaves_cnt;
u8 hwmods_cnt;
u8 _int_flags;
u8 _state;
u8 _postsetup_state;
};
static struct omap_hwmod am33xx_gpio0_hwmod = {
.name = "gpio1",
.class = &am33xx_gpio_hwmod_class,
.clkdm_name = "l4_wkup_clkdm",
.mpu_irqs = am33xx_gpio0_irqs,
.main_clk = "gpio0_ick",
.flags = HWMOD_CONTROL_OPT_CLKS_IN_RESET | HWMOD_INIT_NO_RESET,
.prcm = {
.omap4 = {
.clkctrl_offs = AM33XX_CM_WKUP_GPIO0_CLKCTRL_OFFSET,
.modulemode = MODULEMODE_SWCTRL,
},
},
.opt_clks = gpio0_opt_clks,
.opt_clks_cnt = ARRAY_SIZE(gpio0_opt_clks),
.dev_attr = &gpio_dev_attr,
.slaves = am33xx_gpio0_slaves,
.slaves_cnt = ARRAY_SIZE(am33xx_gpio0_slaves),
};
static __initdata struct omap_hwmod *am33xx_hwmods[] = {
........
/* gpio class */
&am33xx_gpio0_hwmod,
&am33xx_gpio1_hwmod,
&am33xx_gpio2_hwmod,
&am33xx_gpio3_hwmod,
.........
NULL,
};
........
2.注册模块
添加硬件模块到双向链表omap_hwmod_list,入口函数为
\arch\arm\mach-omap2\omap_hwmod_33xx_data.c
int __init am33xx_hwmod_init(void)
该函数的调用过程为start_kernel()->setup_arch()->init_early()->am33xx_init_early()->am33xx_hwmod_init()
二.创建/sys/devices/platform/omap目录
struct device omap_device_parent = {
.init_name = "omap",
.parent = &platform_bus,///sys/devices/platform目录
};
static int __init omap_device_init(void)
{
bus_register_notifier(&platform_bus_type, &platform_nb);
// 创建/sys/devices/platform/omap目录
return device_register(&omap_device_parent);
}
//#define core_initcall(fn) __define_initcall("1",fn,1)
core_initcall(omap_device_init);
三.创建platform_device(/sys/devices/platform/omap/omap_gpioX目录)
//创建/sys/devices/platform/omap/omap_gpio0,omap_gpio1,omap_gpio2,omap_gpio3目录
static int __init omap2_gpio_init(void)
{
......
}
//#define postcore_initcall(fn) __define_initcall("2",fn,2)
postcore_initcall(omap2_gpio_init);
四.创建platform_driver(创建/sys/bus/platform/drivers/omap_gpio目录)
1.创建/sys/bus/platform/drivers/omap_gpio目录
//\drivers\gpio\Gpio-omap.c
static struct platform_driver omap_gpio_driver = {
.probe = omap_gpio_probe,
.driver = {
.name = "omap_gpio",
},
};
static int __init omap_gpio_drv_reg(void)
{
return platform_driver_register(&omap_gpio_driver);
}
//#define postcore_initcall(fn) __define_initcall("2",fn,2)
postcore_initcall(omap_gpio_drv_reg);
2.调用omap_gpio_probe
omap_gpio_probe()->omap_gpio_chip_init()->gpiochip_add();添加芯片控制器gpio_chip;
五.添加字符设备
static int gpio_open(struct inode *inode,struct file *filp)
static int gpio_release(struct inode *inode,struct file *filp)
static long gpio_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
struct file_operations gpio_fops = {
.owner = THIS_MODULE,
.open = gpio_open, // int (*open) (struct inode *, struct file *);
.unlocked_ioctl = gpio_ioctl,//long (*unlocked_ioctl) (struct file *, unsigned int, unsigned long);
.release = gpio_release,// int (*release) (struct inode *, struct file *);
};
static int __init am335x_gpio_init(void)
{
int result;
dev_t dev = 0;
//alloc_chrdev_region:分配设备号,并添加到chrdevs数组./proc/devices 里的设备号, 设备名从chrdevs[255]里取
result = alloc_chrdev_region(&dev, gpio_minor, 1,"am335x_gpio");
gpio_major = MAJOR(dev);
if (result < 0) {
printk(KERN_WARNING "Can't get major %d\n", gpio_major);
return result;
}
printk("AM335X GPIO Driver Registered.\n");
// 初始化cdev
cdev_init(&gpio_cdev, &gpio_fops);
gpio_cdev.owner = THIS_MODULE;
gpio_cdev.ops = &gpio_fops;
// 添加cdev到cdev_map结构(probe),
result = cdev_add (&gpio_cdev, dev, 1);
// 创建一个class,生成/sys/class/am335x_gpio目录
gpio_class = class_create(THIS_MODULE, "am335x_gpio");
if (IS_ERR(gpio_class)) {
printk(KERN_WARNING "Class_create faild\n");
cdev_del(&gpio_cdev);
unregister_chrdev_region(dev, 0);
return result;
}
// 创建一个device,生成/sys/class/am335x_gpio/am335x_gpio文件.udev程序搜索该目录生成/dev/am335x_gpio设备文件
class_dev = device_create(gpio_class,NULL,dev,0,"am335x_gpio");
head = (struct am335x_gpio_node *)kmalloc(sizeof(struct am335x_gpio_node), GFP_KERNEL);
if(head == NULL)
{
return -1;
}
else
{
head->pin = 0;
head->next = NULL;
}
return 0;
}
//#define device_initcall(fn) __define_initcall("6",fn,6)
//#define __initcall(fn) device_initcall(fn)
//#define module_init(x) __initcall(x);
module_init(am335x_gpio_init);