linux学习(5)---平台总线

主要内容---平台总线
1, 平台总线的作用
2, 平台总线的编程
3, 平台总线中的自定义数据
4, 内核中的平台设备

-----------------------------------
linux字符设备驱动编程

    1,实现入口函数 xxx_init()和卸载函数 xxx_exit()
    2,申请主设备号  register_chrdev_region (与内核相关)
    3,注册字符设备驱动 cdev_alloc  cdev_init  cdev_add (与内核相关)
    4,利用udev/mdev机制创建设备文件(节点) class_create, device_create (与内核相关)
    5,硬件部分初始化
        io资源映射 ioremap,内核提供gpio库函数 (与硬件相关)
        注册中断(与硬件相关)
        初始化等待队列 (与内核相关)
    6,构建 file_operation结构 (与内核相关)
    7,实现操作硬件方法  xxx_open,xxx_read,xxxx_write...(与硬件相关)

    
    
    如果要实现一个驱动代码兼容多个设备
        分离: 将通用/相似的代码和差异化代码分离
        合并: 在实际运行时候,需要将差异化代码拿出来,进行操作
        
    很多的相似的硬件:
        都有相似的操作方法
        有不同的操作地址
        
    
平台总线的作用: 用于soc的升级/ 驱动相似的设备


    soc:
        s3c2440                   s3c6410              s5pv210
          arm9                      arm11               A8
        
        gpio                        gpio                gpio
        uart                         uart                uart
        i2c                         i2c                   i2c


    gpio控制器:
        1, 配置gpio的功能
        2, 给数据寄存器赋值
        
    uart:
        1,设置波特率115200,8n1
        2,设置no fifo, no AFC
        3, 发送数据---写发送数据寄存器
            读取数据---读取接收数据寄存器
            
    不同soc中:
        操作逻辑/操作方法相似
        操作的硬件地址不一样
        
    如果要编写一个gpio驱动,能够用在不同的soc中,该怎么办
        在代码编程的时候:
            操作方法的代码(通用)---------分离---------硬件的资源(差异化代码)
                                    为了更好的代码维护
            
        在运行的时候:
            操作方法的代码(通用)---------合并---------硬件的资源(差异化代码)
                    
            
            
            


    如果需要合并就需要总线:
         bus
         device
         driver

    
2, 平台总线的编程
    平台总线:struct bus_type总线对象
        struct bus_type platform_bus_type = {
            .name        = "platform",
            .dev_attrs    = platform_dev_attrs,
            .match        = platform_match, //匹配方法
            .uevent        = platform_uevent,
            .pm        = &platform_dev_pm_ops,
        };
    pdev:
        struct platform_device {// 描述一个设备的信息
            const char    * name; // 名字,用于匹配
            int        id; // 表示不同寄存器组的编号, 一般可以填-1
            struct device    dev;//   父类
            u32        num_resources;//  资源的个数
            struct resource    * resource;// 资源的详细信息--描述中断和内存资源
        };
        
        struct resource {
            resource_size_t start;
            resource_size_t end;
            const char *name;
            unsigned long flags;
            struct resource *parent, *sibling, *child;
        };
        
        注册:
            int platform_device_register(struct platform_device *);
            void platform_device_unregister(struct platform_device *);


    pdrv:
        struct platform_driver {
            int (*probe)(struct platform_device *);//表示匹配之后的函数
            int (*remove)(struct platform_device *);
            struct device_driver driver;//   父类中有name成员也可以用于匹配,但是一定要赋值
            const struct platform_device_id *id_table;// 可以匹配列表,优先匹配
        };
        注册和注销:
            extern int platform_driver_register(struct platform_driver *);
            extern void platform_driver_unregister(struct platform_driver *);

        
        probe中要做事情:
            //为用户提供接口
            0, 实例化全局的设备对象-- kzalloc
            1,  申请主设备号---register_chrdev
            2, 自动创建设备节点---class_create, device_create
            3, 初始化硬件--ioremap
            4,实现 file_operation

            
            
            5,拿到pdev中的资源对硬件进行初始化


gpio操作方法:
        1, 直接操作gpio口对应的寄存器地址(看原理图---数据手册---地址--ioremap)
            *gpc0_conf &= ~(0xff<<12);
            *gpc0_conf |= (0x11<<12);
    
        2, gpio库函数的接口---只需要知道gpio口的号码即可
            gpio_request(unsigned gpio,const char * label)
            // 将某个gpio配置成输出功能,并且直接输出高低电平
            gpio_direction_output(unsigned gpio,int value)
            
            // 将某个gpio配置成输入功能
            gpio_direction_input(unsigned gpio)
            
            // 将某个gpio配置成特定功能
            s3c_gpio_cfgpin(unsigned int pin,unsigned int config)
            
            //将某个gpio口内部上拉或者下拉
            s3c_gpio_setpull(unsigned int pin,s3c_gpio_pull_t pull)
            
            //获取到gpio的值
            gpio_get_value
            //设置gpio的值
            gpio_set_value
            //通过gpio口获取到中断号码
            gpio_to_irq    
            gpio_free(unsigned gpio)


        3,内核提供接口:readl/writel---__raw_readl/__raw_writel
            主要用于操作地址
            
            __raw_readl(a)
            __raw_writel(d,ad)
        
        

3, 平台总线中的自定义数据
    pdev:
        resource: 地址 和中断号 (资源)
        定义其他类型的资源/数据
        struct led_platdata led_pdata = {
            .name = "gpc0_3/4",
            .shift = 3,
        };

        struct platform_device led_pdev = {
            .name = "s5pv210_led",
            .id = -1,
            .num_resources = ARRAY_SIZE(led_resource),
            .resource = led_resource,
            .dev = {
                .platform_data = &led_pdata,  // <------------

            },
        };

    pdrv: 获取到自定义数据
        led_dev->pdata = pdev->dev.platform_data;

4, 内核中的平台设备
    static struct platform_device *smdkv210_devices[] __initdata = {
        &s3c_device_adc,
        &s3c_device_cfcon,
        &s3c_device_fb,
        &s3c_device_hsmmc0,
        &s3c_device_hsmmc1,
        &s3c_device_hsmmc2,
        &s3c_device_hsmmc3,
        &s3c_device_i2c0,
        &s3c_device_i2c1,
        &s3c_device_i2c2,
        &s3c_device_rtc,
        &s3c_device_ts,
        &s3c_device_wdt,
        &s5pv210_device_ac97,
        &s5pv210_device_iis0,
        &s5pv210_device_spdif,
        &samsung_asoc_dma,
        &samsung_device_keypad,
        &smdkv210_dm9000,
        &smdkv210_lcd_lte480wv,
        &s3c_device_timer[3],
        &smdkv210_backlight_device,
    };
    arch/arm/mach-s5pv210/mach-smdkv210.c
        |
        smdkv210_machine_init(void)//在内核启动的时候会自动执行
            |
            platform_add_devices(smdkv210_devices, ARRAY_SIZE(smdkv210_devices));    
                |
                    for (i = 0; i < num; i++) {
                        ret = platform_device_register(devs[i]);//开机的时候批量的注册pdev    
        
        
        
    
    
    
    
    什么时候用平台总线
        1, 只要有设备的地址和中断都可以用平台总线
        2, 如果写的驱动需要在多个平台中升级使用
        3, 平台总线只是一个功能代码:将操作方法和操作资源进行了分离

猜你喜欢

转载自blog.csdn.net/linken_yue/article/details/82320630