1. 程式人生 > >linux kernel 平臺匯流排例項分析

linux kernel 平臺匯流排例項分析

linux 平臺匯流排的實現有三大塊  , platform bus , platform device , platform drvice

平臺型別結構體:

 1                                                                                  
 2 /**                                                                             
 3  * struct bus_type - The bus type of the device                                 
4 * 5 * @name: The name of the bus. 6 * @bus_attrs: Default attributes of the bus. 7 * @dev_attrs: Default attributes of the devices on the bus.
8 * @drv_attrs: Default attributes of the device drivers on the bus. 9 * @match: Called, perhaps multiple times, whenever a new device or driver 10 * is added for this bus. It should return a nonzero value if the 11 * given device can be handled by the given driver.
12 * @uevent: Called when a device is added, removed, or a few other things 13 * that generate uevents to add the environment variables. 14 * @probe: Called when a new device or driver add to this bus, and callback 15 * the specific driver's probe to initial the matched device. 16 * @remove: Called when a device removed from this bus. 17 * @shutdown: Called at shut-down time to quiesce the device. 18 * @suspend: Called when a device on this bus wants to go to sleep mode. 19 * @resume: Called to bring a device on this bus out of sleep mode. 20 * @pm: Power management operations of this bus, callback the specific 21 * device driver's pm-ops. 22 * @p: The private data of the driver core, only the driver core can 23 * touch this. 24 * 25 * A bus is a channel between the processor and one or more devices. For the 26 * purposes of the device model, all devices are connected via a bus, even if 27 * it is an internal, virtual, "platform" bus. Buses can plug into each other. 28 * A USB controller is usually a PCI device, for example. The device model 29 * represents the actual connections between buses and the devices they control. 30 * A bus is represented by the bus_type structure. It contains the name, the 31 * default attributes, the bus' methods, PM operations, and the driver core's 32 * private data. 33 */
 1 struct bus_type {                                                               
 2     const char      *name;                                                      
 3     struct bus_attribute    *bus_attrs; // 匯流排屬性                             
 4     struct device_attribute *dev_attrs; // 裝置屬性                             
 5     struct driver_attribute *drv_attrs; // 驅動性                                                                                                             
 6     int (*match)(struct device *dev, struct device_driver *drv); //匹配平臺裝置與平臺驅動的函式
 7     int (*uevent)(struct device *dev, struct kobj_uevent_env *env);             
 8     int (*probe)(struct device *dev);                                           
 9     int (*remove)(struct device *dev);                                          
10     void (*shutdown)(struct device *dev);                                       
11                                                                                 
12     int (*suspend)(struct device *dev, pm_message_t state);                     
13     int (*resume)(struct device *dev);                                          
14                                                                                 
15     const struct dev_pm_ops *pm;                                                
16                                                                                 
17     struct subsys_private *p;                                                   
18 };                                                                              

參考: http://blog.chinaunix.net/uid-25622207-id-2778126.html

在kernel中 , 首先是有platform bus被kernel 註冊

有以下流程:

init/main.c

 1 static int __init kernel_init(void * unused)                                    
 2 {                                                                              
 3     ......
 4     do_basic_setup();
 5     ......
 6 }
 7 
 8 //再到
 9 static void __init do_basic_setup(void)                                         
10 {                                                                               
11     cpuset_init_smp();                                                          
12     usermodehelper_init();                                                      
13     init_tmpfs();                                                               
14     driver_init();                                                              
15     init_irq_proc();                                                            
16     do_ctors();                                                                 
17     do_initcalls();                                                             
18 }                                                       

再進 driver_init()

 1 void __init driver_init(void)                                                   
 2 {                                                                               
 3     /* These are the core pieces */                                             
 4     devtmpfs_init();                                                            
 5     devices_init();                                                             
 6     buses_init();                                                               
 7     classes_init();                                                             
 8     firmware_init();                                                            
 9     hypervisor_init();                                                          
10                                                                                 
11     /* These are also core pieces, but must come after the                      
12      * core core pieces.                                                        
13      */                                                                         
14     platform_bus_init();            //平臺匯流排初始化                                              
15     system_bus_init();                                                          
16     cpu_dev_init();                                                             
17     memory_dev_init();                                                          
18 }                                                 

再進平臺匯流排初始化

 1 struct device platform_bus = {                                                  
 2     .init_name  = "platform",                                                   
 3 };                                                                              
 4 EXPORT_SYMBOL_GPL(platform_bus);                                              
 5 //...
 6                                                                                 
 7 struct bus_type platform_bus_type = {                                           
 8     .name       = "platform",                                                   
 9     .dev_attrs  = platform_dev_attrs,                                           
10     .match      = platform_match,                                               
11     .uevent     = platform_uevent,                                              
12     .pm     = &platform_dev_pm_ops,                                             
13 };                                                                              
14 EXPORT_SYMBOL_GPL(platform_bus_type);                           
15 
16 //...
17 int __init platform_bus_init(void)                                              
18 {                                                                               
19     int error;                                                                  
20                                                                                 
21     early_platform_cleanup();                                                   
22                                                                                 
23     error = device_register(&platform_bus);  //將平臺匯流排作為一個設備註冊       
24     if (error)                                                                  
25         return error;                                                           
26     error =  bus_register(&platform_bus_type); 
27     if (error)                                                                  
28         device_unregister(&platform_bus);                                       
29     return error;                                                               
30 }                                                             

match 函式是等下匹配platform device 和 platform driver 的函式

 1 /**                                                                             
 2  * platform_match - bind platform device to platform driver.                    
 3  * @dev: device.                                                                
 4  * @drv: driver.                                                                
 5  *                                                                              
 6  * Platform device IDs are assumed to be encoded like this:                     
 7  * "<name><instance>", where <name> is a short description of the type of       
 8  * device, like "pci" or "floppy", and <instance> is the enumerated             
 9  * instance of the device, like '0' or '42'.  Driver IDs are simply             
10  * "<name>".  So, extract the <name> from the platform_device structure,        
11  * and compare it against the name of the driver. Return whether they match     
12  * or not.                                                                      
13  */                                                            
14 
15 static int platform_match(struct device *dev, struct device_driver *drv)        
16 {                                                                               
17     struct platform_device *pdev = to_platform_device(dev);                     
18     struct platform_driver *pdrv = to_platform_driver(drv);                     
19                                                                                 
20     /* Attempt an OF style match first */                                       
21     if (of_driver_match_device(dev, drv))                                       
22         return 1;                                                               
23                                                                                 
24     /* Then try to match against the id table */                                
25     if (pdrv->id_table)                                                         
26         return platform_match_id(pdrv->id_table, pdev) != NULL;                 
27                                                                                 
28     /* fall-back to driver name match */                                        
29     return (strcmp(pdev->name, drv->name) == 0);                                
30 }                                                       
 //通過id_table 來匹配
1 static const struct platform_device_id *platform_match_id( 2 const struct platform_device_id *id, 3 struct platform_device *pdev) 4 { 5 while (id->name[0]) { 6 if (strcmp(pdev->name, id->name) == 0) { 7 pdev->id_entry = id; 8 return id; 9 } 10 id++; 11 } 12 return NULL; 13 }
1 int device_register(struct device *dev)                                         
2 {                                                                               
3     device_initialize(dev);                                                     
4     return device_add(dev);                                                     
5 }                                                                               

此時platform bus 已經作為一個裝置掛到核心上

 

看完平臺匯流排, 下面看平臺裝置的註冊流程:

還是得把一開始的platform device 結構體放到這裡來:

 1                                                                                 
 2 struct platform_device {                                                        
 3     const char  * name;             //平臺裝置名字                              
 4     int     id;                                                                 
 5     struct device   dev;            //裝置結構體                                          
 6     u32     num_resources;          //資源個數                                  
 7     struct resource * resource;     //資源                                      
 8                                                                                 
 9     const struct platform_device_id *id_entry;                                  
10                                                                                 
11     /* MFD cell pointer */                                                      
12     struct mfd_cell *mfd_cell;                                                  
13                                                                                 
14     /* arch specific additions */                                               
15     struct pdev_archdata    archdata;                                           
16 };                                                                              
17                                                                                 
18 #define platform_get_device_id(pdev)    ((pdev)->id_entry)                      
19 //通過device 找到對應的platform_device 結構體                                   
20 #define to_platform_device(x) container_of((x), struct platform_device, dev)   
 

 其實這裡邊還有個裝置結構體 , 他是依附在平臺裝置裡面

 1 /**                                                                             
 2  * struct device - The basic device structure                                   
 3  * @parent: The device's "parent" device, the device to which it is attached.   
 4  *      In most cases, a parent device is some sort of bus or host              
 5  *      controller. If parent is NULL, the device, is a top-level device,       
 6  *      which is not usually what you want.                                     
 7  * @p:      Holds the private data of the driver core portions of the device.   
 8  *      See the comment of the struct device_private for detail.                
 9  * @kobj:   A top-level, abstract class from which other classes are derived.   
10  * @init_name:  Initial name of the device.                                     
11  * @type:   The type of device.                                                 
12  *      This identifies the device type and carries type-specific               
13  *      information.                                                            
14  * @mutex:  Mutex to synchronize calls to its driver.                           
15  * @bus:    Type of bus device is on.                                           
16  * @driver: Which driver has allocated this                                     
17  * @platform_data: Platform data specific to the device.                        
18  *      Example: For devices on custom boards, as typical of embedded           
19  *      and SOC based hardware, Linux often uses platform_data to point         
20  *      to board-specific structures describing devices and how they            
21  *      are wired.  That can include what ports are available, chip             
22  *      variants, which GPIO pins act in what additional roles, and so   
23  *      on.  This shrinks the "Board Support Packages" (BSPs) and               
24  *      minimizes board-specific #ifdefs in drivers.                            
25  * @power:  For device power management.                                        
26  *      See Documentation/power/devices.txt for details.                        
27  * @pwr_domain: Provide callbacks that are executed during system suspend,      
28  *      hibernation, system resume and during runtime PM transitions            
29  *      along with subsystem-level and driver-level callbacks.                  
30  * @numa_node:  NUMA node this device is close to.                              
31  * @dma_mask:   Dma mask (if dma'ble device).                                   
32  * @coherent_dma_mask: Like dma_mask, but for alloc_coherent mapping as not all 
33  *      hardware supports 64-bit addresses for consistent allocations           
34  *      such descriptors.                                                       
35  * @dma_parms:  A low level driver may set these to teach IOMMU code about      
36  *      segment limitations.                                                    
37  * @dma_pools:  Dma pools (if dma'ble device).                                  
38  * @dma_mem:    Internal for coherent mem override.                             
39  * @archdata:   For arch-specific additions.                                    
40  * @of_node:    Associated device tree node.                                    
41  * @devt:   For creating the sysfs "dev".                                       
42  * @devres_lock: Spinlock to protect the resource of the device.      
43  * @devres_head: The resources list of the device.                              
44  * @knode_class: The node used to add the device to the class list.             
45  * @class:  The class of the device.                                            
46  * @groups: Optional attribute groups.                                          
47  * @release:    Callback to free the device after all references have           
48  *      gone away. This should be set by the allocator of the                   
49  *      device (i.e. the bus driver that discovered the device).                
50  *                                                                              
51  * At the lowest level, every device in a Linux system is represented by an     
52  * instance of struct device. The device structure contains the information     
53  * that the device model core needs to model the system. Most subsystems,       
54  * however, track additional information about the devices they host. As a      
55  * result, it is rare for devices to be represented by bare device structures;  
56  * instead, that structure, like kobject structures, is usually embedded within 
57  * a higher-level representation of the device.                                 
58  */                                                       

 1 struct device {                                                                 
 2     struct device       *parent;     // 裝置的父類                              
 3                                                                                 
 4     struct device_private   *p;       //裝置的私有資料                                          
 5                                                                                 
 6     struct kobject kobj;                                                        
 7     const char      *init_name; /* initial name of the device */                
 8     const struct device_type *type;                                             
 9                                                                                 
10     struct mutex        mutex;  /* mutex to synchronize calls to                
11                      * its driver.                                              
12                      */                                                         
13     //表示該裝置是屬於哪一條匯流排                                                
14     struct bus_type *bus;       /* type of bus device is on */                  
15     struct device_driver *driver;   /* which driver has allocated this          
16         device */ // 哪個驅動呼叫了這個裝置                                     
17     void        *platform_data; /* Platform specific data, device               
18                        core doesn't touch it ***********/                                 
19     struct dev_pm_info  power;                                                  
20     struct dev_power_domain *pwr_domain;                                       
21                                                                                 
22 #ifdef CONFIG_NUMA                                                              
23     int     numa_node;  /* NUMA node this device is close to */                 
24 #endif                                                                          
25     u64     *dma_mask;  /* dma mask (if dma'able device) */                     
26     u64     coherent_dma_mask;/* Like dma_mask, but for                         
27                          alloc_coherent mappings as                             
28                          not all hardware supports                              
29                          64 bit addresses for consistent                        
30                          allocations such descriptors. */                       
31                                                                                 
32     struct device_dma_parameters *dma_parms;                                    
33                                                                                 
34     struct list_head    dma_pools;  /* dma pools (if dma'ble) */                
35                                                                                 
36     struct dma_coherent_mem *dma_mem; /* internal for coherent mem              
37                          override */                                            
38     /* arch specific additions */                                               
39     struct dev_archdata archdata;                                               
40                                                                                 
41     struct device_node  *of_node; /* associated device tree node */    
42                                                                                 
43     dev_t           devt;   /* dev_t, creates the sysfs "dev" */ //主次裝置號的>結合體
44                                                                                 
45     spinlock_t      devres_lock;                                                
46     struct list_head    devres_head;                                            
47                                                                                 
48     struct klist_node   knode_class;                                            
49     struct class        *class;                                                 
50     const struct attribute_group **groups;  /* optional groups */               
51                                                                                 
52     void    (*release)(struct device *dev);                                     
53 };                                          

 
1 //平臺設備註冊函式                                                              
2 extern int platform_device_register(struct platform_device *);                  
3 extern void platform_device_unregister(struct platform_device *);               
4 //平臺裝置解註冊函式                                                            

這兩個函式對外發布

i2c 裝置就用到了這個 函式進行 platform device 的 register

在arch/arm/mach-mx6/board-mx6q_sabresd.c 中

1 MACHINE_START(MX6Q_SABRESD, "Freescale i.MX 6Quad/DualLite/Solo Sabre-SD Board")    /* Maintainer: Freescale Semiconductor, Inc. */                             
2     .boot_params = MX6_PHYS_OFFSET + 0x100,                                     
3     .fixup = fixup_mxc_board,                                                   
4     .map_io = mx6_map_io,                                                       
5     .init_irq = mx6_init_irq,                                                   
6     .init_machine = mx6_sabresd_board_init,  // 板級的初始化                    
7     .timer = &mx6_sabresd_timer,            // 時鐘的初始化                     
8     .reserve = mx6q_sabresd_reserve,                                            
9 MACHINE_END                                                                     

時鐘的話跟過去得到 i2c 的   CLK  的速度是400KB/s

在mx6_sabresd_board_init 中

平臺裝置內裝置的平臺數據進行賦值

1 static struct i2c_gpio_platform_data i2c_bus_gpio_data = {                      
2     .sda_pin = SABRESD_I2C4_SDA_GPIO,                                           
3     .scl_pin = SABRESD_I2C4_SCL_GPIO,                                           
4     .udelay  = 10,      //10Khz                                                 
5     .timeout = 500,                                                             
6     //.sda_is_open_drain = 1,       //在當前板子上不能加                        
7     //.scl_is_open_drain = 1,       //在當前板子上不能加                        
8 };                                                                 

平臺裝置結構體的賦值

1 static struct platform_device i2c_bus_gpio_device = {                           
2     .name  = "i2c-gpio",  //這個名字是必須這樣,主要是為了和i2c-gpio驅動對應    
3     //由於板子已經用掉了0,1,2號,這裡使用3                                      
4     .id  = 3, /* bus have 0,1,2, so start at 3 */                               
5     .dev = {                                                                    
6         .platform_data = &i2c_bus_gpio_data,                                    
7     }                                                                           
8 };                                                                              

板級的初始化:

 1 static void __init mx6_sabresd_board_init(void)                                 
 2 {                                                                               
 3 
 4     //。。。。。。
 5 
 6     /**                                                                         
 7       * register gpio i2c bus                   write by zengjf                 
 8       * 註冊i2c-gpio裝置,相當於註冊一個I2C控制器                               
 9       */                                                                        
10     platform_device_register(&i2c_bus_gpio_device);                             
11                                                                                 
12     i2c_register_board_info(0, mxc_i2c0_board_info,                             
13             ARRAY_SIZE(mxc_i2c0_board_info));                                   
14     i2c_register_board_info(1, mxc_i2c1_board_info,                             
15             ARRAY_SIZE(mxc_i2c1_board_info));                                   
16     i2c_register_board_info(2, mxc_i2c2_board_info,                             
17             ARRAY_SIZE(mxc_i2c2_board_info));                                   
18      /**                                                                        
19       * register gpio i2c device                write by zengjf                 
20       * 在I2C控制器3上註冊I2C裝置,這裡的控制器3就是前面註冊的I2C控制器,       
21       * 主要是因為前面註冊的I2C控制器的id是3                                    
22       */                                                                        
23      i2c_register_board_info(3, gpio_i2c_devices, ARRAY_SIZE(gpio_i2c_devices));
24 
25     //。。。。。。
26 
27 }

在mx6這塊板子身上 , i2c 0 , 1 , 2 是比較正常的i2c 匯流排, 但是i2c 3 是用的兩個GPIO口模擬的 i2c 的SCL和 SDA線 

下面 , 跟進

1    platform_device_register(&i2c_bus_gpio_device);       

/drivers/base/platform.c

 1 /**                                                                             
 2  * platform_device_register - add a platform-level device                       
 3  * @pdev: platform device we're adding                                          
 4  */                                                                             
 5 int platform_device_register(struct platform_device *pdev)                      
 6 {                                                                               
 7     device_initialize(&pdev->dev);         //初始化裝置                                       
 8     return platform_device_add(pdev);      //平臺裝置新增                                     
 9 }                                                                               
10 EXPORT_SYMBOL_GPL(platform_device_register);                                   

 跟進 platform_device_add(pdev)

 1 /**                                                                             
 2  * platform_device_add - add a platform device to device hierarchy              
 3  * @pdev: platform device we're adding                                          
 4  *                                                                              
 5  * This is part 2 of platform_device_register(), though may be called           
 6  * separately _iff_ pdev was allocated by platform_device_alloc().              
 7  */                                                                             
 8 int platform_device_add(struct platform_device *pdev)                           
 9 {                                                                               
10     int i, ret = 0;                                                             
11                                                                                 
12     if (!pdev)                                                                  
13         return -EINVAL;                                                         
14                                                                                 
15     if (!pdev->dev.parent)                                                      
16         pdev->dev.parent = &platform_bus;    //屬於平臺匯流排,                    
17                                                                                 
18     pdev->dev.bus = &platform_bus_type;         // 在platform_bus_init()的時候已經註冊了平臺匯流排型別                         
19                                                                                 
20     if (pdev->id != -1)                                                        
21         dev_set_name(&pdev->dev, "%s.%d", pdev->name,  pdev->id);   //pdev->dev 只有一個platform_data , pdev->name == i2c-gpio , pdev->id == 3      
22     else                                                                        
23         dev_set_name(&pdev->dev, "%s", pdev->