针对s2121b_16t方案电池驱动进行详细的分析和解读过程如下:
该函数主要是做两方面的工作,一方面是初始化平台的相关信息(平台操作集和平台资源等),另一方面是讲设备添加到设备链表中去;对于这一部分的内容,我们可以抽空去复习下之前整理的平台设备的相关内容,也不对设备添加具体进行讲了,可以自己找到这个函数自己看看。
首先我们和一般程序一样找到它的电池驱动所在的位置,在当前项目中驱动文件为: kernel/drivers/power/jz4775-battery-lut.c
当我们打开该文件时我们会发现它和一般的驱动文件一样,都有它的入口函数和退出函数,没有什么特别之处;下面我们先来了解下它的设备注册的过程,以帮助我们后面来了解它的驱动过程。代码位于arch/mips/xburst/soc-4775/board/s2121b_16t/misc.c文件中
/* ADC*/#ifdef CONFIG_BATTERY_JZ4775_LUTjz_device_register(& jz_adc_device, &s2121b_16t_battery_pdata);/* ac charger */platform_device_register (& s2121b_16t_ac_charger_device) ;/* li-ion charger */platform_device_register (& s2121b_16t_li_ion_charger_device) ;#endif
先来看看
jz_adc_device结构体做了那些初始化。
/* ADC controller*/static struct resource jz_adc_resources[] = {
{
.start = SADC_IOBASE, // 0x10070000 平台资源的起始地址.end = SADC_IOBASE + 0x34,.flags = IORESOURCE_MEM,
},{
.start = IRQ_SADC, // 26 中断资源.end = IRQ_SADC,.flags = IORESOURCE_IRQ,
},{.start = IRQ_SADC_BASE, //278 中断资源地址.end = IRQ_SADC_BASE,.flags = IORESOURCE_IRQ,},
};
struct platform_device jz_adc_device = { // 平台设备初始化
.name = "jz4775-adc",.id = -1,.num_resources = ARRAY_SIZE(jz_adc_resources),.resource = jz_adc_resources ,
再来看看平台注册函数的具体的注册过程。};
int jz_device_register (struct platform_device *pdev,void *pdata){
pdev->dev.platform_data = pdata;
return platform_device_register (pdev); // 调用注册函数
}
从这里我们基本看不出来它做了什么事情,仅能看出它把
s2121b_16t_battery_pdata赋给了pdev->dev.platform_data,我们继续看platform_device_register(pdev)做了些什么工作。
int platform_device_register (struct platform_device *pdev){
device_initialize (&pdev->dev); // 设备初始化
return platform_device_add (pdev); // 将设备添加到设备链表中去
}
从两个函数接口的字面的意思们就可以知道,一个是初始化设备,而另外一个函数接口是将该设备加入到相应的平台下;如果觉得仅仅看看字面意思不够严谨的话,我们可以具体看看它们主要的作用。先看device_initalize(&pdev->dev)函数接口:
void device_initialize (struct device *dev) /*初始化device结构*/{
dev->kobj.kset = devices_kset; /*所属为devices_kset,所以他的父kobj为/sys/devices/*/kobject_init (&dev->kobj, &device_ktype); // 初始化设备层次关系INIT_LIST_HEAD (&dev->dma_pools); // 初始化链表mutex_init (&dev->mutex); // 初始化锁机制lockdep_set_novalidate_class (&dev->mutex);spin_lock_init (&dev->devres_lock); // 初始化锁机制INIT_LIST_HEAD (&dev->devres_head); // 初始化链表device_pm_init (dev); /*初始化dev的power属性*/set_dev_node (dev, -1); /*CONFIG_NUMA结构下才有意义*/
}
对于设备模型中有所了解的话,我们就可以简单的发现该函数主要是将设备添加到设备层次关系和链表中以便于访问与管理;下面我们再来看看另外已一个设备添加接口函数。
int platform_device_add (struct platform_device *pdev){int i, ret = 0;if (!pdev)return -EINVAL;if (!pdev->dev.parent)pdev->dev.parent = &platform_bus;pdev->dev.bus = &platform_bus_type; // 设置平台总线if (pdev->id != -1)dev_set_name(&pdev->dev, "%s.%d", pdev->name, pdev->id);elsedev_set_name(&pdev->dev, "%s", pdev->name);for (i = 0; i < pdev->num_resources; i++) {struct resource *p, *r = &pdev->resource[i];if (r->name == NULL)r->name = dev_name(&pdev->dev);p = r->parent;if (!p) { // 根据资源类型获取资源if (resource_type(r) == IORESOURCE_MEM) //0x00000200p = &iomem_resource;else if (resource_type(r) == IORESOURCE_IO) //0x00000100p = &ioport_resource;}if (p && insert_resource(p, r)) {printk(KERN_ERR "%s: failed to claim resource %d\n", dev_name(&pdev->dev), i);ret = -EBUSY;goto failed;}}pr_debug("Registering platform device '%s'. Parent at %s\n", dev_name(&pdev->dev), dev_name(pdev->dev.parent));ret = device_add(&pdev->dev); // 添加设备到设备链表中if (ret == 0)return ret;failed: // 错误处理while (--i >= 0) {struct resource *r = &pdev->resource[i];unsigned long type = resource_type(r);
if (type == IORESOURCE_MEM || type == IORESOURCE_IO) // 0x00000200 0x00000100release_resource(r);}return ret;}
关于平台总线的类型的初始化:
struct bus_type platform_bus_type = {.name = "platform",.dev_attrs = platform_dev_attrs ,.match = platform_match , // 平台设备和驱动的匹配函数.uevent = platform_uevent , //产生事件时调用(热插拔).pm = &platform_dev_pm_ops ,};
我们一直在间接这些函数接口的功能,乎略了一个重要的东西,那就是s2121b_16t_battery_pdata这儿结构的内容,下面我们来看看它的具体赋值:
static struct jz_battery_platform_data s2121b_16t_battery_pdata = {.info = { // 在串口打印时会打印出来这些信息.battery_max_cpt = 330,.ac_chg_current = 400,.usb_chg_current = 400,.sleep_current = 20,},};
初一看我们不知道这个结构体的成员是什么意思,只能通过字面意思来理解,那我们先把它放下,不管它的具体含义了,我们来简单看看另外两个注册函数的注册。
/* ac charger */platform_device_register (&s2121b_16t_ac_charger_device ) ;
/* ac charger */static char * s2121b_16t_ac_supplied_to[] = {"li_ion_charge",};
static struct gpio_charger_platform_data s2121b_16t_ac_charger_pdata = { // 数据初始化.name = "ac",.type = POWER_SUPPLY_TYPE_MAINS, // 2.gpio = GPIO_USB_DETE, //GPIO_PB(29) (1*32 + 29).gpio_active_low = GPIO_USB_DETE_ACTIVE_LOW, // 1.supplied_to = s2121b_16t_ac_supplied_to ,.num_supplicants = ARRAY_SIZE(s2121b_16t_ac_supplied_to), // 1};
static struct platform_device s2121b_16t_ac_charger_device = {.name = "gpio-charger", // 平台设备名.dev = {.platform_data = & s2121b_16t_ac_charger_pdata ,},};
这个注册函数和前面的注册过程一样,这里我们只看看它的一些私有的基本信息,以便于我们更好的理解驱动之间的关系。我再来简单看看最后一个注册函数。
/* li-ion charger */platform_device_register ( &s2121b_16t_li_ion_charger_device ) ;
/* li-ion charger */static struct li_ion_charger_platform_data s2121b_16t_li_ion_charger_pdata = { // 数据初始化.gpio = GPIO_PA(17), // 输入接口.gpio_active_low = 1, // 工作状态};static struct platform_device s2121b_16t_li_ion_charger_device = {.name = "li-ion-charger", // 平台设备名.dev = {.platform_data = & s2121b_16t_li_ion_charger_pdata ,},};
这个函数值注册锂电池的注册函数,注册过程和之前的一样,在这里了我就不多讲了,讲了这么多主要是讲的是函数的注册过程,通过讲解函数的注册过程让我们进一步了解内核的管理机制。