嵌入式学习笔记——platform设备

来源:互联网 发布:淘宝卖家上传图片失败 编辑:程序博客网 时间:2024/06/06 15:43

        platform机制将本身的资源注册进内核,由内核统一管理,在驱动程序中使用这些资源时通过platform_device提供的标准接口进行申请并使用。

        开发环境:ubuntu 12.04

        开发板:龙芯1B开发板

        交叉编译工具:gcc-4.3-ls232-softfloat

        内核版本:3.0.0

        platform的设备可以有两种形式,一种是将设备编译在内核中,在内核初始化的时候,将资源注册到内核里;一种是以加载的方式,将设备资源注册在内核中。

        如果是编译在内核中的,就要修改内核中,对应cpu型号的platform.c,以我现在用的龙芯1b开发板为例,打开linux3.0.0/arch/mips/loongson/ls1x/ls1x-board/platform.c,里面的代码大致上分为两大部分,一部分用于定义各个设备结构和资源,以龙芯1b里的pwm设备为例

//分别定义pwm寄存器的首地址,此处地址是物理地址#define LS1B_PWM0_BASE  0x1fe5c000#define LS1B_PWM1_BASE  0x1fe5c010#define LS1B_PWM2_BASE  0x1fe5c020#define LS1B_PWM3_BASE  0x1fe5c030//设备的变量static struct platform_device ls1b_pwm_device = {      //定义一个ls1b的pwm的设备    .name   = "ls1b-pwm",                              //设备名称    .id = -1,                                               .num_resources  = ARRAY_SIZE(ls1b_pwm0_resource),  //资源数量    .resource   = ls1b_pwm0_resource,                  //资源名称};//设备资源static struct resource ls1b_pwm0_resource[] = {        //定义一个ls1b的pwm的资源    [0]={                                              //因为龙芯1b系列内置四路pwm输出,所以要将每路的资源分别定义        .start  = LS1B_PWM0_BASE,                      //这是pwm0第一个寄存器的物理地址,在这里用的是物理地址而不是                                                       //虚拟地址是因为platform机制是CPU直接寻址设备的寄存器空间                                                              .end    = (LS1B_PWM0_BASE + 0x0f),             //这是pwm0最后一个寄存器的物理地址        .flags  = IORESOURCE_MEM,                      //标识资源的类型,在这是可直接寻址空间    },                                             [1]={                                              .start  = LS1B_PWM1_BASE,                      .end    = (LS1B_PWM1_BASE + 0x0f),             .flags  = IORESOURCE_MEM,                  },                                             [2]={                                              .start  = LS1B_PWM2_BASE,                      .end    = (LS1B_PWM2_BASE + 0x0f),             .flags  = IORESOURCE_MEM,                  },                                             [3]={                                              .start  = LS1B_PWM3_BASE,                      .end    = (LS1B_PWM3_BASE + 0x0f),             .flags  = IORESOURCE_MEM,                  },                                         };

      第二部分是将定义好的设备添加到platform设备数组里,然后注册到内核中,由内核统一管理。

static struct platform_device *ls1b_platform_devices[] __initdata = { //将定义好的设备结构添加到该数组中    &ls1b_pwm0_device,                                                                                                                           &ls1x_fb0_device,                                                     &ls1b_nand_device,                                                    &ls1b_ohci_device,                                                    &ls1b_ehci_device,                                                    &ls1b_gmac0_mac,                                                      &ls1b_gmac0_phy,//以下省略其他的设备                                                   };int __init ls1b_platform_init(void)  {                                        //在此可以添加一些简单的初始化    return platform_add_devices(ls1b_platform_devices, ARRAY_SIZE(ls1b_platform_devices));  //将platform设备列表添加到内核中}                                                                                                                                                                                   arch_initcall(ls1b_platform_init);       //在include/linux/init.h中,是这样定义的“#define arch_initcall(fn)       module_init(fn)”,所以应该是用来声明模块初始化入口


   到此为止,设备的申请已经完成了。下面在看一下driver/char/ls1b-pwm.c,这是pwm的驱动程序。以下是部分代码:



static struct platform_driver ls1f_pwm_driver = {             //定义一个platform_driver结构的变量                                  .probe = ls1f_pwm_probe,                                  //定义.probe所指向的函数ls1b_pwm_probe                                  .driver = {                                                                                         .name = "ls1b-pwm",                               //定义该设备的名称,这名称将会与之前内核初始化所申请的platform设备一一对比,当对比到有一样的时候,将自动调用probe函数                                  },                                                                                      };                                                                                                                                                                                      static int ls1f_pwm_open(struct inode *inode, struct file *file)      //file_operations结构中的open函数,用于应用程序调用该驱动时,打开驱动。                      {                                                                                                                                                                                           long val = readl(SB2F_GPIO_MUX_CTRL1);                                                      val &= 0xfffffffc;                                                                          writel(val, SB2F_GPIO_MUX_CTRL1);                                                                                                                                                       val = readl(REG_GPIO_CFG0);                                                                                                                                                             //配置GPIO复用为使用PWM工作的模式                                                           val &= 0xfffffff0;                                                                          writel(val, REG_GPIO_CFG0);                                                                                                                                                             return 0;                                                                               }                                                                                                                                                                                       static int ls1f_pwm_close(struct inode *inode, struct file *file)     //用于关闭驱动调用                      {                                                                                               writeb(0x0, pwm_base + REG_PWM_CTRL);                                                       return 0;                                                                               }                                                                                                                                                                                       static ssize_t ls1f_pwm_read(struct file *file, char __user *buf, size_t count, loff_t *ptr)   //对设备进行读操作{                                                                                               unsigned int pwm_val;                                                                       pwm_val = readl(pwm_base);                                                                                                                                                              if (copy_to_user(buf, &pwm_val, sizeof(unsigned int)))                                          return -EFAULT;                                                                         return 4;                                                                               }                                                                                           static ssize_t ls1f_pwm_write(struct file *file, const char __user *buf, size_t count, loff_t *ptr)//用于对设备进行写操作    {                                                                                                    unsigned int hrc_val, lrc_val;                                                                   unsigned int data[2] = {0x0};                                                                                                                                                                     if (copy_from_user(data, buf, sizeof(data)))                                                     {                                                                                                    printk("Write error!\n");                                                                        return -EIO;                                                                                 }                                                                                                                                                                                                 hrc_val = data[1] - 1;                                                                           lrc_val = data[0] + data[1] -1;                                                                                                                                                                   //设置占空比                                                                                     writel(hrc_val, pwm_base + REG_PWM_HRC);                                                         writel(lrc_val, pwm_base + REG_PWM_LRC);                                                         return 0;                                                                                    }                                                                                                                                                                                                 static long ls1f_pwm_ioctl(struct file *file, unsigned int cmd, unsigned long arg)         //对设备的I/O通道进行管理{                                                                                     printk("into %s\n", __FUNCTION__);                                                printk("cmd: %d\n", cmd);                                                         printk("arg: %ld\n", arg);                                                                                                                                          if (arg > 3)                                                                          return -1;                                                                                                                                                      switch (cmd) {                                                                    case CMD_PWM_GET:                                                                     ls1f_pwm_getResourse(pwm_dev, arg);                                               break;                                                                        case CMD_PWM_START:                                                               case CMD_PWM_STOP:                                                                    return pwm_start_stop(cmd, arg);                                              default:                                                                              break;                                                                        }                                                                                 return 0;                                                                     }                                                                                                                                                                                                                                                     static const struct file_operations ls1f_pwm_ops = {  //file_operations结构是一个虚拟文件系统,通过该结构对设备进行操作,就是说用于驱动程序与设备的交互                  .owner = THIS_MODULE,                         //将结构指向该模块                                    .open = ls1f_pwm_open,                        //将结构中open函数与我们编写的open函数关联,以后应用程序调用open的时候,就会调用到我们写的open函数                                    .release = ls1f_pwm_close,                    //同上                                    .read = ls1f_pwm_read,                                                            .write = ls1f_pwm_write,                                                          .unlocked_ioctl = ls1f_pwm_ioctl,                                         };                                                                                                                                                                  static struct miscdevice ls1f_pwm_miscdev = {         //定义一个杂项字符设备结构类型的变量                                    MISC_DYNAMIC_MINOR,                           //动态获取次设备号                                    "ls1f-pwm",                                   //设备名称                                    &ls1f_pwm_ops,                                //关联file_opertiaons结构                            };                                                                                static int ls1f_pwm_getResourse(struct platform_device *pdev, unsigned int index)   //该函数是用来获取在内核中申请到的设备资源{                                                                                     res = platform_get_resource(pdev, IORESOURCE_MEM, index);                                                                                                           if (res == NULL)                                                                  {                                                                                   printk("Fail to get ls1f_pwm_resource!\n");                                       return -ENOENT;                                                                 }                                                                                 printk("Resource start=0x%x, end = 0x%x\n", res->start, res->end);                if (res1 != NULL)                                                                 {                                                                                     release_mem_region(res->start, 0x0f);                                         }                                                                                 res1 = request_mem_region(res->start, 0x0f, "ls1f-pwm");                          if (res1 == NULL)                                                                 {                                                                                   printk("Fail to request ls1f_pwm region!\n");                                     return -ENOENT;                                                                 }                                                                                 pwm_base = ioremap(res->start, res->end - res->start + 1);                        if (pwm_base == NULL)                                                             {                                                                                   printk("Fail to ioremap ls1f_pwm resource!\n");                                   return -EINVAL;                                                                 }                                                                                 return 0;                                                                     }                                                                                                                                                                   static int __devinit ls1f_pwm_probe(struct platform_device *pdev)      //当初始化设备时,我们申请设备名称已经在内核管理的platform设备中存在,就会自动调用该函数           {                                                                                     pwm_dev = pdev;                                                                   return ls1f_pwm_getResourse(pdev, 1);                              //获取内核中已申请的设备资源          }                                                                                 static int __init ls1f_pwm_init(void) {                                    //模块初始化函数    if (misc_register(&ls1f_pwm_miscdev))                                  //注册杂项字符设备,会自动创建设备节点,即设备文件    {                                                                            printk(KERN_WARNING "pwm: Couldn't register device 10, %d.\n", 255);       return -EBUSY;                                                           }                                                                          return platform_driver_register(&ls1f_pwm_driver);                     //注册platform设备,如果这时发现设备已存在,就会自动调用probe函数}                                                                                                                                                     static void __exit ls1f_pwm_exit(void)                                     //模块卸载函数{                                                                              misc_deregister(&ls1f_pwm_miscdev);                                    //从杂项字符设备中注销该设备    release_mem_region(res->start, 0x20);                                  //用于释放不需要的I/O内存区    platform_driver_unregister(&ls1f_pwm_driver);                          //从platform中注销驱动}                                                                                                                                                     module_init(ls1f_pwm_init);                                                module_exit(ls1f_pwm_exit);                                                MODULE_AUTHOR("<xuhongmeng xuhongmeng-gz@loongson.cn>");                   MODULE_DESCRIPTION("loongson 1B PWM driver");                              MODULE_LICENSE("GPL");                                                     

 

0 0
原创粉丝点击