Chinaunix首页 | 论坛 | 博客
  • 博客访问: 405331
  • 博文数量: 53
  • 博客积分: 1910
  • 博客等级: 中尉
  • 技术积分: 1130
  • 用 户 组: 普通用户
  • 注册时间: 2010-05-10 14:56
文章分类

全部博文(53)

文章存档

2013年(1)

2012年(17)

2011年(33)

2010年(2)

分类: LINUX

2011-12-19 08:24:35

这个regulator 比较复杂点,主要调节是通过I2C,先看下sys目录:
sys/devices/platform/omap/omap_i2c.1/i2c-1
  1-0048
  1-0049
    twl4030_gpio
    twl4030_pwrbutton
    twl4030-audio
  1-004a
    twl4030_keypad
  1-004b  --->regulator
    twl_rtc
    twl_reg.2   VIO
    twl_reg.6   VMMC1
    twl_reg.3   VDAC
    twl_reg.10  VAUX2_4030(only 4030)
    twl_reg.5   VPLL2
    twl_reg.8   VSIM
    twl_reg.12  VAUX3
1.platform device register
  omap3_evm_i2c_init
        => omap_register_i2c_bus(1, 2600, omap3evm_i2c_boardinfo,
              注册i2c 总线, omap3evm_i2c_boardinfo 为挂在总线上的多个slave的info
              => i2c_register_board_info (带client dev的)
              => omap_i2c_add_bus(bus_id) devname = "omap_i2c"
                   => omap_device_build (这是1个hwmod 设备),实际最后也是注册platform device
                      (sys 目录如上/sys/devices/platform/omap/omap_i2c.1/)
                       之所以要omap_device_build ,而不是直接platform_device_register,
                       是要满足omap复杂的PCRM的L4,L3层的东西
                          => platform device 被注册,如果总线已经注册驱动,驱动就去probe
2. platform driver register
   platform_driver_register(&omap_i2c_driver);
   static struct platform_driver omap_i2c_driver = {
 .probe  = omap_i2c_probe,
 .remove  = omap_i2c_remove,
 .driver  = {
  .name = "omap_i2c",
  .owner = THIS_MODULE,
 },
   };
   开始probe
   omap_i2c_probe (I2C_omap.c)
             dev_set_name(&adap->dev, "i2c-%d", adap->nr);
      adap->dev.bus = &i2c_bus_type;
      adap->dev.type = &i2c_adapter_type;
   => res = device_register(&adap->dev); (注册adaptor device)
       (sys 目录如上/sys/devices/platform/omap/omap_i2c.1/i2c-1)
  
   =>i2c_add_numbered_adapter(adap);
              => i2c_register_adapter(adap);
                  =>i2c_scan_static_board_info(adap);
                      scan  __i2c_board_list
                      =>i2c_new_device(adapter,&devinfo->board_info)
                             (I2C bus client device register )
                             client->dev.platform_data = info->platform_data; (就是omap3evm_twldata)
                             client->addr = info.add 就是0x48
                             strlcpy(client->name, info->type, sizeof(client->name));
                                           client->name  如下omap3evm_i2c_boardinfo
                                                   = twl4030 (i2c bus match 时会比对)
                             ......
                             client->dev.bus = &i2c_bus_type;
                      client->dev.type = &i2c_client_type;
                             dev_set_name(&client->dev, "%d-%04x", adap-nr, client->addr)
                          => device_register(&client->dev); 
                         (sys 目录如上/sys/devices/platform/omap/omap_i2c.1/i2c-1/1-0048)
                         
       对于twl4030设备的i2c board info如下
        static struct i2c_board_info __initdata omap3evm_i2c_boardinfo[] = {
 {
  I2C_BOARD_INFO("twl4030", 0x48),
  /*#define I2C_BOARD_INFO(dev_type, dev_addr)
               .type = twl4030, .addr = 0x48 第1个client  地址
  */
  .flags = I2C_CLIENT_WAKE,
  .irq = INT_34XX_SYS_NIRQ,
  .platform_data = &omap3evm_twldata,
         },
        };
  
   
    上面device_register "1-0048"这个device ,进入
    /sys/devices/platform/omap/omap_i2c.1/i2c-1/1-0048
    其中包含的driver 进入该driver目录,其实他是个link
    指向:/sys/bus/i2c/drivers/twl
    dirver 名称叫twl,这个就是client driver!!!
    在(twl-core.c)
    static struct i2c_driver twl_driver = {
 .driver.name = DRIVER_NAME,  =>"twl"
 .id_table = twl_ids,
 .probe  = twl_probe,
 .remove  = twl_remove,
    };
   
    twl_init
      => i2c_add_driver(&twl_driver);
           => i2c_register_driver(THIS_MODULE, driver);
                 (I2C bus driver register )
                 driver->driver.bus = &i2c_bus_type;
                 /* When registration returns, the driver core
           * will have called probe() for all matching-but-unbound devices. */ 
           res = driver_register(&driver->driver);
                  I2C总线上引起probe  ,(关于总线的设备attach过程,可以跟下(bus_add_driver)了解
                   大概过程就是 driver_attach=> __driver_attach(bustype)
                                                   =>driver_match_device(bus->match)
                                                      => driver_probe_device(bus->probe)
                  struct bus_type i2c_bus_type = {
   .name  = "i2c",
   .match  = i2c_device_match,
   .probe  = i2c_device_probe,
   .remove  = i2c_device_remove,
   .shutdown = i2c_device_shutdown,
   .pm  = &i2c_device_pm_ops,
    };
   
    下面继续跟bus->probe(i2c_device_probe),
    really_probe(dev,driver) => driver->probe
    driver 就是twl_driver ,driver->probe 就是twl_probe
   
   
    twl_probe
       struct twl4030_platform_data *pdata = client->dev.platform_data;
       就是omap3evm_twldata
       TWL_NUM_SLAVES 有4个第一个0x48已经生成
           twl_client twl_modules[0] = 等于0x48 client
      
       => i2c_new_dummy( ,0x48++)
          这样就生成了剩余的3个client,
          (sys 目录如上/sys/devices/platform/omap/omap_i2c.1/i2c-1/1-0049,1-004a,1-004b)
       => add_children(omap3evm_twldata,TWL4030_VAUX2)
            => 目前只关心 regulator
               主要regulator 如下:
               add_regulator(TWL4030_REG_VPLL1, pdata->vpll1);
               child = add_regulator(TWL4030_REG_VIO, pdata->vio);
               child = add_regulator(TWL4030_REG_VDD1, pdata->vdd1);
        child = add_regulator(TWL4030_REG_VDD2, pdata->vdd2);
          child = add_regulator(TWL4030_REG_VMMC1, pdata->vmmc1);
        child = add_regulator(TWL4030_REG_VDAC, pdata->vdac);
        child = add_regulator((features & TWL4030_VAUX2)
    ? TWL4030_REG_VAUX2_4030: TWL4030_REG_VAUX2,pdata->vaux2);
        child = add_regulator(TWL4030_REG_VINTANA1, pdata->vintana1);
               child = add_regulator(TWL4030_REG_VINTANA2, pdata->vintana2);
        child = add_regulator(TWL4030_REG_VINTDIG, pdata->vintdig);
        child = add_regulator(TWL4030_REG_VPLL2, pdata->vpll2);
        child = add_regulator(TWL4030_REG_VMMC2, pdata->vmmc2);
        child = add_regulator(TWL4030_REG_VSIM, pdata->vsim);
        child = add_regulator(TWL4030_REG_VAUX1, pdata->vaux1);
               child = add_regulator(TWL4030_REG_VAUX3, pdata->vaux3);
        child = add_regulator(TWL4030_REG_VAUX4, pdata->vaux4);
        child = add_regulator(TWL4030_REG_VUSB1V5, pdata->vusb1v5);
        child = add_regulator(TWL4030_REG_VUSB1V8, pdata->vusb1v8);
        child = add_regulator(TWL4030_REG_VUSB3V1, pdata->vusb3v1);
            =>add_regulator_linked(int num, struct regulator_init_data *pdata,
        struct regulator_consumer_supply *consumers, unsigned num_consumers)
           => 根据static struct twl_mapping twl4030_map[TWL4030_MODULE_LAST + 1] 
              查到subchipid 是3,就是0x4b ,查看下目录
               /sys/devices/platform/omap/omap_i2c.1/i2c-1/1——004b
               的确regulator 都在这里
           =>  add_numbered_child(sub_chip_id=3, "twl_reg", num=TWL4030_REG_VMMC1,
                   pdata, sizeof(*pdata), false, 0, 0);
              
           =>  下面看下vmmc1的 add  add_regulator_linked过程
           => platform_device_alloc(name=twl_reg, num=TWL4030_REG_VMMC1(6));
              platform_device_add_data, tel_reg.6的platformdata=pdata->vmmc1
              就是下面的omap3evm_vmmc1
static struct regulator_consumer_supply omap3evm_vmmc1_supply = {
 .supply   = "vmmc",
};
static struct regulator_consumer_supply omap3evm_vsim_supply = {
 .supply   = "vmmc_aux",
};
/* VMMC1 for MMC1 pins CMD, CLK, DAT0..DAT3 (20 mA, plus card == max 220 mA) */
static struct regulator_init_data omap3evm_vmmc1 = {
 .constraints = {
  .min_uV   = 1850000,
  .max_uV   = 3150000,
  .valid_modes_mask = REGULATOR_MODE_NORMAL
     | REGULATOR_MODE_STANDBY,
  .valid_ops_mask  = REGULATOR_CHANGE_VOLTAGE
     | REGULATOR_CHANGE_MODE
     | REGULATOR_CHANGE_STATUS,
 },
 .num_consumer_supplies = 1,
 .consumer_supplies = &omap3evm_vmmc1_supply,
};         
                         => 最后platform_device_add(pdev)
                         注册regulator vmmc1的platform device
                         于是/sys/devices/platform/omap/omap_i2c.1/i2c-1/1_004b/twl_reg.6生成
                        
其他以次类推,根据omap3evm_twldata实际传入regulator 相关 有下面几组:
static struct twl4030_platform_data omap3evm_twldata = {
 .vdac  = &omap3_evm_vdac,
 .vpll2  = &omap3_evm_vpll2,
 .vaux2          = &omap3evm_vaux2,
 .vio  = &omap3_evm_vio,
 .vaux3  = &omap3evm_vaux3,
};                 
另外两组,直接赋值:
         omap3evm_twldata.vmmc1 = &omap3evm_vmmc1;
  omap3evm_twldata.vsim = &omap3evm_vsim;
共7组 
         查看目录/sys/devices/platform/omap/omap_i2c.1/i2c-1/1-004b
    twl_reg.2   VIO
    twl_reg.6   VMMC1
    twl_reg.3   VDAC
    twl_reg.10  VAUX2_4030(only 4030)
    twl_reg.5   VPLL2
    twl_reg.8   VSIM
    twl_reg.12  VAUX3
    实际也是如此
   
   
经过上面过程所有twl regulator platform device 已经注册完成
接下来就是twl_reg driver 了
twl-regulator.c 中 定义twl regulator driver 结构如下:
static struct platform_driver twlreg_driver = {
 .probe  = twlreg_probe,
 .remove  = __devexit_p(twlreg_remove),
 /* NOTE: short name, to work around driver model truncation of
  * "twl_regulator.12" (and friends) to "twl_regulator.1".
  */
 .driver.name = "twl_reg",
 .driver.owner = THIS_MODULE,
};
platform_driver_register(&twlreg_driver); 执行后,引发platform bus probe
经过attach,match后执行到
twlreg_probe
         => 根据pdev.id(就是上面twl_reg.x)到 struct twlreg_info
             twl_regs查找匹配twl_info
            然后根据dev 的platform_data活动regulator init data
            比如 vmmc1 twl_info为:
       /*
 .base = 0x27, (+0x5b PM_RECEIVER start addr ) 0x82
               VMMC1_DEV_GRP RW 8 0x00 0x27 0x82 P187
 .id = 5,
 .table_len = ARRAY_SIZE(VMMC1_VSEL_table),  1850, 2850, 3000, 3150,
 .table = VMMC1_VSEL_table,
 .delay = 100,
 .remap = 0x8,
 .desc = {  regulator_desc ,主要是regulator ops函数组设置
  .name = "VMMC1",
  .id = TWL4030_REG_VMMC1,
  .n_voltages = ARRAY_SIZE(VMMC1_VSEL_table),
  .ops = &twl4030ldo_ops,
  .type = REGULATOR_VOLTAGE,
  .owner = THIS_MODULE,
  },
 }*/
 接下来对传入的 regulator init data中constraint进行调整
 然后regulator_register(&info->desc, &pdev->dev, initdata, info);
 向regulator core注册regulator,这样以后可以通过regulator core中
 接口对twl_reg  进行操作,实际操作是twl4030ldo_ops 中对应function
 
 最后
 twlreg_write(info, TWL_MODULE_PM_RECEIVER, VREG_REMAP,info->remap);
 return twl_i2c_write_u8(slavesugp=TWL_MODULE_PM_RECEIVER=0x15
           , value=info.remap=0x8, info->base + offset=0x27+2);
           TWL_MODULE_PM_RECEIVER 可以到twl_map中查pm receiver base addr!
 表示对client 0x4b addr ,VMMC1_REMAP (RW 8 0x08 0x29 0x84)register
 写入0x8 (如 P199 描述)
 When VMMC1 device is either in SLEEP or OFF mode allows to
 set the resource in Active or OFF/SLEEP (VRRTC
        domain)
       
接下来主要是regulator 的操作函数,和omap pmic 的PM相关register
对于omap pmic PM 部分
1. PM_RECEIVER  对某个power resource 操作
   对应每个regulator 主要有DEV_GRP,TYPE,REMAP,DEDICATE
   比如VMMC1 (P187)
    VMMC1_DEV_GRP RW 8 0x00 0x27 0x82
    VMMC1_TYPE RW 8 0x00 0x28 0x83
    VMMC1_REMAP RW 8 0x08 0x29 0x84
    VMMC1_DEDICATED RW 8 0x02 0x2A 0x85
   
2. PM_MASTER
     对整个PMIC的操作,比如sequancer,reset等等
       
        static struct regulator_ops twl4030ldo_ops = {
 .list_voltage = twl4030ldo_list_voltage,
 .set_voltage = twl4030ldo_set_voltage,
 .get_voltage = twl4030ldo_get_voltage,
 .enable  = twlreg_enable,
 .disable = twlreg_disable,
 .is_enabled = twlreg_is_enabled,
 .set_mode = twlreg_set_mode,
 .get_status = twlreg_get_status,
};
1.  twlreg_enable
        主要操作就是设置DEV_GRP register
        P1_GRP_4030(bit(5)) 001: Associated with P1 device group
        表示关联到MPU group,这样就enable了
       
2.  twl4030ldo_set_voltage(struct regulator_dev *rdev, int min_uV, int max_uV)
        操作  DEDICATE register
        对于VMMC1   
        static const u16 VMMC1_VSEL_table[] = {
 1850, 2850, 3000, 3150,
        };
        在电压表中查找,4个电压中满足>=min_uV 并且<=max_uV
        并设置VMMC1_DEDICATED,中VSEL(0-3) 进行选择
       
        omap_hsmmc_switch_opcond=>
           在omap_hsmmc_1_set_power=>
                =>mmc_regulator_set_ocr=>
                      regulator_set_voltage(supply, min_uV, max_uV);
                      设置卡电压
                     
              
3.   twlreg_set_mode                  
      就是发power bus message
      首先生成sigular message,根据 REGULATOR_MODE_NORMAL,or STANDBY
      消息格式为 P252:
        DEV_GR[2:0]  Power Providers   (PP)
                     Reset and Control (PC)
                     Power Reference   (PR)
        MT - sigular
        RES_ID[7:0]  P246
        RES_STATE[3:0]  P243 都有解释
       
      然后读该regulator(power source) 是否关联P1,2,3
      最后写PMB MSB, LSB ,完成mode转换
     
* I2c 操作到pmic reg 定位:
    1. PM MASTER register:
   int twl_i2c_write_u8(u8 mod_no, u8 value, u8 reg)
  
   mod_no -- 定义在 twl.h
    比如:
      #define TWL4030_MODULE_PM_MASTER 0x14
     根据twl4030_map[mod_no],可以获得sid(slave id)
     再根据sid 从 twl_modules 获得哪个twl_client(他包含slave addr)
 
    reg -- 定义为offset,通过mod_no查base reg addr ,然后加上reg
      twl_map[mod_no].base + reg;
      比如PM Receiver base =>
           #define TWL4030_BASEADD_PM_MASTER 0x0036
      而  Power bus msg reg offset =>
           #define TWL4030_PM_MASTER_PB_WORD_MSB 0x15    
      0x36+0x15 =0x4B  就是PB_WORD_MSB reg addr    
     
    2. PM RECEIVER register:
    int twlreg_write(struct twlreg_info *info, unsigned slave_subgp,
         unsigned offset, u8 value) 
     下面这个和上面类似
     但多了twlreg_info ,用来确定某twl regulator(power source)的base addr
     twlreg_info 定义在
      static struct twlreg_info twl_regs[] (twl_regulator.c)
      全局数组中
    
     offset就是
     #define VREG_GRP  0
     /* TWL4030 register offsets */
     #define VREG_TYPE  1
     #define VREG_REMAP  2
     #define VREG_DEDICATED 3 /* LDO control */
     
       
     
     
* sysfs attrib:
   add_regulator_attributes (regulator core.c) ,比如
  /sys/devices/platform/omap/omap_i2c.1/i2c-1/1-004b/twl_reg.15/regulator/regulator.7
  的   microvolts 查看当前电压
阅读(5003) | 评论(0) | 转发(1) |
给主人留下些什么吧!~~