Linux驱动程序中的platform总线详解

Linux驱动程序中的platform总线详解

在linux2.6设备模型中,关心总线,设备,驱动这三个实体,总线将设备和驱动绑定,在系统每注册一个设备的时候,会寻找与之匹配的驱动。相反,在系统每注册一个驱动的时候,寻找与之匹配的设备,匹配是由总线来完成的。

一个现实的Linux 设备和驱动通常都需要挂接在一种总线上,对于本身依附于PCI、USB、I2C、SPI 等的设备而言,这自然不是问题,但是在嵌入式系统里面,SoC 系统中集成的独立的外设控制器、挂接在SoC 内存空间的外设等确不依附于此类总线。基于这一背景,Linux 发明了一种虚拟的总线,称为platform 总线

SOC系统中集成的独立外设单元(I2C,LCD,SPI,RTC等)都被当作平台设备来处理,而它们本身是字符型设备。
  从Linux2.6内核起,引入一套新的驱动管理和注册机制:platform_device 和 platform_driver 。Linux 中大部分的设备驱动,都可以使用这套机制,设备用 platform_device 表示;驱动用platform_driver 进行注册。

platform_device 结构体 include/linux/platform_device.h   struct platform_device   {
  const char *name; //设备名   u32 id;
  struct device dev;
  u32 num_resources; //设备所使用的各类资源数量  
struct resource *resource; //使用的资源
  }
  platform_driver 结构体 include/linux/platform_device.h   struct platform_driver   {
  int (*probe)(struct platform_device *);   int (*remove)(struct platform_device *);   void (*shutdown)(struct platform_device *);
  int (*suspend)(struct platform_device *, pm_message_t state);
  int (*suspend_late)(struct platform_device *, pm_message_t state);   int (*resume_early)(struct platform_device *);   int (*resume)(struct platform_device *);   struct pm_ext_ops *pm;
  struct device_driver driver;   };
  系统为platform总线定义一个bus_type的实例platform_bus_type,通过其成员函数match(),确定device和driver如何匹配。
  匹配platform_device和platform_driver主要看二者的name字段是否相同。(name必须要相同才能匹配)
  用platform_device_register()函数注册单个的平台设备。

一般是在平台的BSP文件中定义platform_device,通过platform_add_devices()函数将平台设备注册到系统中
  platform_driver 的注册与注销:   platform_driver_register()   platform_driver_unregister()   以s3c2440 LCD驱动为例:  
在BSP文件中:
  struct platform_device s3c_device_lcd = {   .name = "s3c2410-lcd",   .id = -1,
  .num_resources = ARRAY_SIZE(s3c_lcd_resource),   .resource = s3c_lcd_resource,
  .dev = {
  .dma_mask = &s3c_device_lcd_dmamask,   .coherent_dma_mask = 0xffffffffUL   }
  };
  为了完成LCD设备的注册,将其放进/arch/arm/mach-s3c2440/mach-smdk2440.c中定义的smdk2440_devices数组中:
  static struct platform_device *smdk2440_devices[] __initdata = {   ........   ........
  &s3c_device_lcd,   };
 
由platform_add_devices(smdk2440_devices, ARRAY_SIZE(smdk2440_devices));注册
在相应的driver文件中:(/drivers/video/s3c2410fb.c)   static struct platform_driver s3c2410fb_driver = {   .probe = s3c2410fb_probe, //驱动探测
  .remove = __devexit_p(s3c2410fb_remove), //驱动移除   .suspend = s3c2410fb_suspend,   .resume = s3c2410fb_resume,   .driver = {
  .name = "s3c2410-lcd", //和platform_device中的name相同  
.owner = THIS_MODULE,
  },   };
  static int __devinit s3c2410_fb_init(void)
  {
  return platform_driver_register(&s3c2410fb_driver);   }
  static void __exit s3c2410fb_cleanup(void)   {
  platform_driver_unregister(&s3c2410fb_driver);   }

注册成功后会在下面两个目录下看到设备节点:   /sys/bus/platform/devices/   /sys/devices/platform/   平台设备资源和数据:  
resource结构体:
  struct resource   {
  resource_size_t start;   resource_size_t end;   const char *name;
  unsigned long flags;
  struct resource *parent, *sibling, *child;
  };
  我们通常关心start、end 和flags 这3 个字段,分别标明资源的开始值、结束值和类型,flags
  可以为
IORESOURCE_IO、IORESOURCE_MEM、IORESOURCE_IRQ、
IORESOURCE_DMA 等。   如LCD资源:
  static struct resource s3c_lcd_resource[] = {
  [0] = {
  .start = S3C24XX_PA_LCD, //LCD的IO资源起始地始(LCD控制器寄存器地址)   .end = S3C24XX_PA_LCD + S3C24XX_SZ_LCD - 1, //结束地址   .flags = IORESOURCE_MEM,   },
  [1] = {
  .start = IRQ_LCD, //LCD中断号
  .end = IRQ_LCD,
  .flags = IORESOURCE_IRQ,   }   };
 
在driver中用platform_get_resource()或platform_get_irq()等函数获取设备资源
  struct resource *platform_get_resource(struct platform_device *, unsigned int, unsigned int);   int platform_get_irq(struct platform_device *dev, unsigned int num);   获取到的内存或IO资源,需要ioremap后才能使用
  获取到的IRQ资源,需要request_irq
  设备除了可以在BSP 中定义资源以外,还可以附加一些数据信息,因为对设备的硬件描述除了中断、内存、DMA 通道以外,可能还会有一些配置信息,而这些配置信息也依赖于板,不适宜直接放置在设
  备驱动本身,因此,platform 也提供了platform_data 的支持。
  platform_data可以自定义,比如DM9000驱动,用platform_data描述它的一些属性:   static struct dm9000_plat_data s3c_dm9000_platdata = {   .flags = DM9000_PLATF_16BITONLY,   };
  static struct platform_device s3c_device_dm9000 = {
.name = "dm9000",   .id = 0,
  .num_resources = ARRAY_SIZE(s3c_dm9000_resource),   .resource = s3c_dm9000_resource,  
.dev = {
  .platform_data = &s3c_dm9000_platdata,   }
  };
  在相应的驱动中使用:
  struct dm9000_plat_data *pdata = pdev->dev.platform_data;   可获取platform_data
  找一个和平台相关的驱动程序,从BSP文件开始分析它的结构,一直分析到它的最底层的硬件操作,这样很快就能熟悉platform的工作原理。 


 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

刘仕豪

IT发展快就是因为有开源精神

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值