电源管理之pmu驱动分析

电源管理芯片可以为多设备供电,且这些设备电压电流有所不同。为这些设备提供的稳压器代码模型即为regulator。

说白了regulator就是稳压器,它提供电源供给.简单的可以gpio操作,高电平开电,低电平关电.一般的还包括电流值,

电压值等.

一般regulator有两种不同的电源,即:ldo和sd.

Ldo适合电压要求比较稳,但是功率不是很大的设备.

Sd适合功率要求比较大,但可以接受较小的纹波的设备.

除此之外pmu还可能集成,charger,battery, 音频功放等等.

首先我们分析pmu驱动的平台设备注册部分.

我以max77663这款pmu芯片为分析对象, cpu用的是nvidia的tegra3.

Pmu的板级初始化文件:kernelarcharmmach-tegraoard-kai-power.c

主要代码如下:

#define PMC_CTRL             0x0

#define PMC_CTRL_INTR_LOW         (1 << 17)

#define REBOOT_FLAG"rebooting"

#define DEVICE_PATH  "/dev/block/platform/sdhci-tegra.3/by-name/UDE"

static structregulator_consumer_supply max77663_sd0_supply[] = {

  REGULATOR_SUPPLY("vdd_cpu",NULL),

};

static structregulator_consumer_supply max77663_sd1_supply[] = {

  REGULATOR_SUPPLY("vdd_core",NULL),

};

static struct regulator_consumer_supplymax77663_sd2_supply[] = {

  REGULATOR_SUPPLY("vdd_gen1v8",NULL),

  REGULATOR_SUPPLY("avdd_hdmi_pll",NULL),

  REGULATOR_SUPPLY("avdd_usb_pll",NULL),

  REGULATOR_SUPPLY("avdd_osc",NULL),

  REGULATOR_SUPPLY("vddio_sys",NULL),

  REGULATOR_SUPPLY("vddio_sdmmc","sdhci-tegra.3"),

  REGULATOR_SUPPLY("pwrdet_sdmmc4",NULL),

  REGULATOR_SUPPLY("vddio_uart",NULL),

  REGULATOR_SUPPLY("pwrdet_uart",NULL),

  REGULATOR_SUPPLY("vddio_bb",NULL),

  REGULATOR_SUPPLY("pwrdet_bb",NULL),

  REGULATOR_SUPPLY("vddio_lcd_pmu",NULL),

  REGULATOR_SUPPLY("pwrdet_lcd",NULL),

  REGULATOR_SUPPLY("vddio_audio",NULL),

  REGULATOR_SUPPLY("pwrdet_audio",NULL),

  REGULATOR_SUPPLY("vddio_cam",NULL),

  REGULATOR_SUPPLY("pwrdet_cam",NULL),

  REGULATOR_SUPPLY("vddio_sdmmc","sdhci-tegra.2"),

  REGULATOR_SUPPLY("pwrdet_sdmmc3",NULL),

  REGULATOR_SUPPLY("vddio_vi",NULL),

  REGULATOR_SUPPLY("pwrdet_vi",NULL),

  REGULATOR_SUPPLY("vcore_nand",NULL),

  REGULATOR_SUPPLY("pwrdet_nand",NULL),

};

static structregulator_consumer_supply max77663_sd3_supply[] = {

  REGULATOR_SUPPLY("vdd_ddr3l_1v35",NULL),

};

static structregulator_consumer_supply max77663_ldo0_supply[] = {

  REGULATOR_SUPPLY("vdd_ddr_hs",NULL),

};

static structregulator_consumer_supply max77663_ldo1_supply[] = {

};

static structregulator_consumer_supply max77663_ldo2_supply[] = {

  REGULATOR_SUPPLY("vdd_ddr_rx",NULL),

};

static structregulator_consumer_supply max77663_ldo3_supply[] = {

  REGULATOR_SUPPLY("vmmc",NULL),

};

static structregulator_consumer_supply max77663_ldo4_supply[] = {

  REGULATOR_SUPPLY("vdd_rtc",NULL),

};

static structregulator_consumer_supply max77663_ldo5_supply[] = {

  REGULATOR_SUPPLY("vdd_sensor_2v8",NULL),

};

static structregulator_consumer_supply max77663_ldo6_supply[] = {

  REGULATOR_SUPPLY("vddio_sdmmc","sdhci-tegra.0"),

  REGULATOR_SUPPLY("pwrdet_sdmmc1",NULL),

};

static structregulator_consumer_supply max77663_ldo7_supply[] = {

  REGULATOR_SUPPLY("avdd_dsi_csi",NULL),

  REGULATOR_SUPPLY("pwrdet_mipi",NULL),

};

static struct regulator_consumer_supplymax77663_ldo8_supply[] = {

  REGULATOR_SUPPLY("avdd_plla_p_c_s",NULL),

  REGULATOR_SUPPLY("avdd_pllm",NULL),

  REGULATOR_SUPPLY("avdd_pllu_d",NULL),

  REGULATOR_SUPPLY("avdd_pllu_d2",NULL),

  REGULATOR_SUPPLY("avdd_pllx",NULL),

};

static structmax77663_regulator_fps_cfg max77663_fps_cfgs[] = {

  {

            .src= FPS_SRC_0,

            .en_src= FPS_EN_SRC_EN0,

            .time_period= FPS_TIME_PERIOD_DEF,

  },

  {

            .src= FPS_SRC_1,

            .en_src= FPS_EN_SRC_EN1,

            .time_period= FPS_TIME_PERIOD_DEF,

  },

  {

            .src= FPS_SRC_2,

            .en_src= FPS_EN_SRC_EN0,

            .time_period= FPS_TIME_PERIOD_DEF,

  },

};

#define MAX77663_PDATA_INIT(_id,_min_uV, _max_uV, _supply_reg,                  

                         _always_on, _boot_on, _apply_uV,                 

                         _init_apply, _init_enable, _init_uV,         

                         _fps_src, _fps_pu_period, _fps_pd_period,_flags)

  staticstruct max77663_regulator_platform_data max77663_regulator_pdata_##_id =

  {                                                                        

            .init_data= {                                                  

                     .constraints= {                                    

                              .min_uV= _min_uV,                           

                              .max_uV= _max_uV,                         

                              .valid_modes_mask= (REGULATOR_MODE_NORMAL | 

                                                      REGULATOR_MODE_STANDBY),

                              .valid_ops_mask= (REGULATOR_CHANGE_MODE |   

                                                    REGULATOR_CHANGE_STATUS | 

                                                    REGULATOR_CHANGE_VOLTAGE),

                              .always_on= _always_on,               

                              .boot_on= _boot_on,                        

                              .apply_uV= _apply_uV,                     

                     },                                                    

                     .num_consumer_supplies=                      

                              ARRAY_SIZE(max77663_##_id##_supply),     

                     .consumer_supplies= max77663_##_id##_supply,       

                     .supply_regulator= _supply_reg,            

            },                                                              

            .init_apply= _init_apply,                            

            .init_enable= _init_enable,                                

            .init_uV= _init_uV,                                      

            .fps_src= _fps_src,                                     

            .fps_pu_period= _fps_pu_period,                    

            .fps_pd_period= _fps_pd_period,                    

            .fps_cfgs= max77663_fps_cfgs,                                

            .flags= _flags,                                     

  }

MAX77663_PDATA_INIT(sd0,  600000, 3387500, NULL, 1, 0, 0,0, 0, -1,FPS_SRC_NONE, -1, -1, EN2_CTRL_SD0);

MAX77663_PDATA_INIT(sd1,  800000, 1587500, NULL, 1, 0, 0,1, 1, -1,FPS_SRC_1, FPS_POWER_PERIOD_1, FPS_POWER_PERIOD_6, 0);

MAX77663_PDATA_INIT(sd2,  1800000, 1800000, NULL, 1, 0, 0,1, 1, -1,FPS_SRC_0, -1, -1, 0);

MAX77663_PDATA_INIT(sd3,  600000, 3387500, NULL, 1, 0, 0,1, 1, -1,FPS_SRC_0, -1, -1, 0);

MAX77663_PDATA_INIT(ldo0, 800000,2350000, max77663_rails(sd3), 1, 0, 0,1, 1, -1, FPS_SRC_1, -1, -1, 0);

MAX77663_PDATA_INIT(ldo1, 800000,2350000, max77663_rails(sd3), 0, 0, 0,0, 0, -1, FPS_SRC_NONE, -1, -1, 0);

MAX77663_PDATA_INIT(ldo2, 800000,3950000, NULL, 1, 0, 0,1, 1, -1, FPS_SRC_1, -1, -1, 0);

MAX77663_PDATA_INIT(ldo3, 800000,3950000, NULL, 1, 0, 0,1, 1, -1, FPS_SRC_1, -1, -1, 0);

MAX77663_PDATA_INIT(ldo4, 800000,1587500, NULL, 0, 0, 0,1, 1, 1000000, FPS_SRC_0, -1, -1, LDO4_EN_TRACKING);

MAX77663_PDATA_INIT(ldo5, 800000,2800000, NULL, 0, 0, 0,1, 1, -1, FPS_SRC_NONE, -1, -1, 0);

MAX77663_PDATA_INIT(ldo6, 800000,3950000, NULL, 0, 0, 0,0, 0, -1, FPS_SRC_NONE, -1, -1, 0);

MAX77663_PDATA_INIT(ldo7, 800000,3950000, max77663_rails(sd3), 0, 0, 0,0, 0, -1, FPS_SRC_NONE, -1, -1, 0);

MAX77663_PDATA_INIT(ldo8, 800000,3950000, max77663_rails(sd3), 0, 0, 0,1, 1, -1, FPS_SRC_1, -1, -1, 0);

#define MAX77663_REG(_id, _data)                                              

  {                                                                        

            .name= "max77663-regulator",                                

            .id= MAX77663_REGULATOR_ID_##_id,                          

            .platform_data= &max77663_regulator_pdata_##_data,  

            .pdata_size= sizeof(max77663_regulator_pdata_##_data),        

  }

#define MAX77663_RTC()                                                        

  {                                                                        

            .name= "max77663-rtc",                                            

            .id= 0,                                                    

  }

static struct mfd_cellmax77663_subdevs[] = {

  MAX77663_REG(SD0,sd0),

  MAX77663_REG(SD1,sd1),

  MAX77663_REG(SD2,sd2),

  MAX77663_REG(SD3,sd3),

  MAX77663_REG(LDO0,ldo0),

  MAX77663_REG(LDO1,ldo1),

  MAX77663_REG(LDO2,ldo2),

  MAX77663_REG(LDO3,ldo3),

  MAX77663_REG(LDO4,ldo4),

  MAX77663_REG(LDO5,ldo5),

  MAX77663_REG(LDO6,ldo6),

  MAX77663_REG(LDO7,ldo7),

  MAX77663_REG(LDO8,ldo8),

  MAX77663_RTC(),

};

static structmax77663_gpio_config max77663_gpio_cfgs[] = {

  {

            .gpio= MAX77663_GPIO0,

            .dir= GPIO_DIR_OUT,

            .dout= GPIO_DOUT_LOW,

            .out_drv= GPIO_OUT_DRV_PUSH_PULL,

            .alternate= GPIO_ALT_DISABLE,

  },

  {

            .gpio= MAX77663_GPIO1,

            .dir= GPIO_DIR_IN,

            .dout= GPIO_DOUT_LOW,

            .out_drv= GPIO_OUT_DRV_PUSH_PULL,

            .alternate= GPIO_ALT_DISABLE,

  },

  {

            .gpio= MAX77663_GPIO2,

            .dir= GPIO_DIR_OUT,

            .dout= GPIO_DOUT_HIGH,

            .out_drv= GPIO_OUT_DRV_OPEN_DRAIN,

            .alternate= GPIO_ALT_DISABLE,

  },

  {

            .gpio= MAX77663_GPIO3,

            .dir= GPIO_DIR_OUT,

            .dout= GPIO_DOUT_LOW,

            .out_drv= GPIO_OUT_DRV_OPEN_DRAIN,

            .alternate= GPIO_ALT_ENABLE,

  },

  {

            .gpio= MAX77663_GPIO4,

            .dir= GPIO_DIR_OUT,

            .dout= GPIO_DOUT_HIGH,

            .out_drv= GPIO_OUT_DRV_PUSH_PULL,

            .alternate= GPIO_ALT_ENABLE,

  },

  {

            .gpio= MAX77663_GPIO5,

            .dir= GPIO_DIR_OUT,

            .dout= GPIO_DOUT_LOW,

            .out_drv= GPIO_OUT_DRV_PUSH_PULL,

            .alternate= GPIO_ALT_DISABLE,

  },

  {

            .gpio= MAX77663_GPIO6,

            .dir= GPIO_DIR_IN,

            .alternate= GPIO_ALT_DISABLE,

  },

  {

            .gpio= MAX77663_GPIO7,

            .dir= GPIO_DIR_OUT,

            .dout= GPIO_DOUT_LOW,

            .out_drv= GPIO_OUT_DRV_OPEN_DRAIN,

            .alternate= GPIO_ALT_DISABLE,

  },

};

static structmax77663_platform_data max7763_pdata = {

  .irq_base = MAX77663_IRQ_BASE,

  .gpio_base       = MAX77663_GPIO_BASE,

  .flags=SLP_MONITORS_ENABLE|SLP_LPM_ENABLE,

  .num_gpio_cfgs       = ARRAY_SIZE(max77663_gpio_cfgs),

  .gpio_cfgs         = max77663_gpio_cfgs,

  .num_subdevs = ARRAY_SIZE(max77663_subdevs),

  .sub_devices    = max77663_subdevs,

  .rtc_i2c_addr   = 0x68,

  .use_power_off        = true,

};

static struct i2c_board_info__initdata max77663_regulators[] = {

  {

            /*The I2C address was determined by OTP factory setting */

            I2C_BOARD_INFO("max77663",0x3c),

            .irq            = INT_EXTERNAL_PMU,

            .platform_data         = &max7763_pdata,

  },

};

static int __initkai_max77663_regulator_init(void)

{

  void__iomem *pmc = IO_ADDRESS(TEGRA_PMC_BASE);

  u32pmc_ctrl;

  /*configure the power management controller to trigger PMU

   * interrupts when low */

  pmc_ctrl= readl(pmc + PMC_CTRL);

  writel(pmc_ctrl| PMC_CTRL_INTR_LOW, pmc + PMC_CTRL);

  i2c_register_board_info(4,max77663_regulators,

                              ARRAY_SIZE(max77663_regulators));

  return0;

}

static structregulator_consumer_supply fixed_reg_en_1v8_cam_supply[] = {      

  REGULATOR_SUPPLY("vdd_1v8_cam1",NULL),

};

static structregulator_consumer_supply fixed_reg_en_cam1_ldo_supply[] = {     

  REGULATOR_SUPPLY("vdd_cam1",NULL),

};

static structregulator_consumer_supply fixed_reg_en_3v3_sys_a01_supply[] = {

  REGULATOR_SUPPLY("vdd_3v3",NULL),

  REGULATOR_SUPPLY("vdd_3v3_devices",NULL),

  REGULATOR_SUPPLY("debug_cons",NULL),

  REGULATOR_SUPPLY("pwrdet_pex_ctl",NULL),

  REGULATOR_SUPPLY("vddio_gmi",NULL),

};

static structregulator_consumer_supply fixed_reg_en_avdd_hdmi_usb_a01_supply[] = {

  REGULATOR_SUPPLY("avdd_hdmi",NULL),

  REGULATOR_SUPPLY("avdd_usb",NULL),

};

static structregulator_consumer_supply fixed_reg_en_vddio_vid_supply[] = {

  REGULATOR_SUPPLY("vdd_hdmi_con",NULL),

};

static structregulator_consumer_supply fixed_reg_en_vdd_sdmmc1_supply[] = {

  REGULATOR_SUPPLY("vddio_sd_slot","sdhci-tegra.0"),

};

static structregulator_consumer_supply fixed_reg_en_3v3_fuse_supply[] = {

  REGULATOR_SUPPLY("vdd_fuse",NULL),

};

/* Macro for defining fixedregulator sub device data */

#define FIXED_SUPPLY(_name)"fixed_reg_"#_name

#define FIXED_REG(_id, _var,_name, _in_supply, _always_on, _boot_on,    

  _gpio_nr,_active_high, _boot_state, _millivolts) 

  staticstruct regulator_init_data ri_data_##_var =                 

  {                                                                        

            .supply_regulator= _in_supply,                                  

            .num_consumer_supplies=                               

                     ARRAY_SIZE(fixed_reg_##_name##_supply),                  

            .consumer_supplies= fixed_reg_##_name##_supply,  

            .constraints= {                                             

                     .valid_modes_mask= (REGULATOR_MODE_NORMAL |        

                                        REGULATOR_MODE_STANDBY),    

                     .valid_ops_mask= (REGULATOR_CHANGE_MODE |     

                                        REGULATOR_CHANGE_STATUS|   

                                        REGULATOR_CHANGE_VOLTAGE),

                     .always_on= _always_on,                        

                     .boot_on= _boot_on,                                 

            },                                                              

  };                                                                       

  staticstruct fixed_voltage_config fixed_reg_##_var##_pdata =  

  {                                                                        

            .supply_name= FIXED_SUPPLY(_name),                           

            .microvolts= _millivolts * 1000,                        

            .gpio= _gpio_nr,                                          

            .enable_high= _active_high,                             

            .enabled_at_boot= _boot_state,                              

            .init_data= &ri_data_##_var,                                    

  };                                                                       

  staticstruct platform_device fixed_reg_##_var##_dev = {   

            .name= "reg-fixed-voltage",                             

            .id= _id,                                                

            .dev= {                                                   

                     .platform_data= &fixed_reg_##_var##_pdata,    

            },                                                              

  }

/* A01 specific */

FIXED_REG(1, en_3v3_sys_a01,        en_3v3_sys_a01,              NULL,

  1,      0,      MAX77663_GPIO_BASE+ MAX77663_GPIO3,        true,         1,      3300);

FIXED_REG(2,en_avdd_hdmi_usb_a01, en_avdd_hdmi_usb_a01, FIXED_SUPPLY(en_3v3_sys_a01),

  0,      0,      MAX77663_GPIO_BASE+ MAX77663_GPIO2,        true,         0,      3300);

FIXED_REG(4, en_vddio_vid_a01,     en_vddio_vid,           NULL,

  0,      0,      TEGRA_GPIO_PB2,                             true,         0,      5000);

FIXED_REG(9,  en_vdd_sdmmc1_a01, en_vdd_sdmmc1,                FIXED_SUPPLY(en_3v3_sys_a01),

  0,      0,      TEGRA_GPIO_PC6,                             true,         0,      3300);

FIXED_REG(10, en_3v3_fuse_a01,   en_3v3_fuse,            FIXED_SUPPLY(en_3v3_sys_a01),

  0,      0,      TEGRA_GPIO_PC1,                             true,         0,      3300);

FIXED_REG(11, en_1v8_cam_a01,   en_1v8_cam,            NULL,

  0,      0,      TEGRA_GPIO_PS0,                              true,         0,      1800);

FIXED_REG(12, en_cam1_ldo_a01,  en_cam1_ldo,           FIXED_SUPPLY(en_3v3_sys_a01),  

  0,      0,      TEGRA_GPIO_PR6,                             true,         0,      2800);

/*

 * Creating the fixed regulator device tables

 */

#define ADD_FIXED_REG(_name)     (&fixed_reg_##_name##_dev)

/* A01 specific */

#define E1565_A01_FIXED_REG

  ADD_FIXED_REG(en_3v3_sys_a01),               

  ADD_FIXED_REG(en_avdd_hdmi_usb_a01), 

  ADD_FIXED_REG(en_vddio_vid_a01),   

  ADD_FIXED_REG(en_vdd_sdmmc1_a01),     

  ADD_FIXED_REG(en_3v3_fuse_a01),    

  ADD_FIXED_REG(en_1v8_cam_a01),

  ADD_FIXED_REG(en_cam1_ldo_a01)

/* Gpio switch regulator platformdata for Kai A01 */

static struct platform_device*fixed_reg_devs_a01[] = {

  E1565_A01_FIXED_REG

};

static int __initkai_fixed_regulator_init(void)

{

  inti;

  structboard_info board_info;

  structplatform_device **fixed_reg_devs;

  intnfixreg_devs;

  tegra_get_board_info(&board_info);

  fixed_reg_devs= fixed_reg_devs_a01;

  nfixreg_devs= ARRAY_SIZE(fixed_reg_devs_a01);

  for(i = 0; i < nfixreg_devs; ++i) {

            intgpio_nr;

            structfixed_voltage_config *fixed_reg_pdata =

                     fixed_reg_devs[i]->dev.platform_data;

            gpio_nr= fixed_reg_pdata->gpio;

  }

  printk("kai_fixed_regulator_initnfixreg_devs=%d ",nfixreg_devs);

  returnplatform_add_devices(fixed_reg_devs, nfixreg_devs);

}

subsys_initcall_sync(kai_fixed_regulator_init);

int __initkai_regulator_init(void)

{

  void__iomem *pmc = IO_ADDRESS(TEGRA_PMC_BASE);

  u32pmc_ctrl;

  intret;

  /*configure the power management controller to trigger PMU

   * interrupts when low */

  pmc_ctrl= readl(pmc + PMC_CTRL);

  writel(pmc_ctrl| PMC_CTRL_INTR_LOW, pmc + PMC_CTRL);

  ret= kai_max77663_regulator_init();

  if(ret < 0)

            returnret;

  return0;

}

分析:

首先看__init函数int __initkai_regulator_init(void)

àkai_max77663_regulator_init(); //max77663设备初始化函数

ài2c_register_board_info(4,max77663_regulators,ARRAY_SIZE(max77663_regulators)); //注册i2c硬件信息

->static structi2c_board_info __initdata max77663_regulators[] = {

  {

            /* The I2C address was determined byOTP factory setting */

            I2C_BOARD_INFO("max77663",0x3c),   //i2c地址

            .irq            =INT_EXTERNAL_PMU,           //pmu中断

            .platform_data         = &max7763_pdata, //要传的平台数据,

  },

};

接下来看平台数据:

static structmax77663_platform_data max7763_pdata = {

  .irq_base =MAX77663_IRQ_BASE,

  .gpio_base       =MAX77663_GPIO_BASE,

  .flags=SLP_MONITORS_ENABLE|SLP_LPM_ENABLE,

  .num_gpio_cfgs       =ARRAY_SIZE(max77663_gpio_cfgs),

  .gpio_cfgs         =max77663_gpio_cfgs,

  .num_subdevs =ARRAY_SIZE(max77663_subdevs),

  .sub_devices    =max77663_subdevs,

  .rtc_i2c_addr   =0x68, //rtc i2c地址

  .use_power_off        =true,

};

  max77663_gpio_cfgs函数主要是一些gpio引脚的初始化.

  接下来最重要的函数是: max77663_subdevs

static structmfd_cell max77663_subdevs[] = {

  MAX77663_REG(SD0, sd0),

  MAX77663_REG(SD1, sd1),

……….

};

MAX77663_REG它是一个宏,我们展开看一下.

#defineMAX77663_REG(_id, _data)                                               

  {                                                                        

            .name ="max77663-regulator",                                

            .id = MAX77663_REGULATOR_ID_##_id,                          

            .platform_data =&max77663_regulator_pdata_##_data,  

            .pdata_size =sizeof(max77663_regulator_pdata_##_data),        

  }

很明显他是要给一些参数赋值.

不过,到这里好像我们的跟踪断了...

不用着急我们再看下面一个宏.

MAX77663_PDATA_INIT(sd0,  600000, 3387500, NULL, 1, 0, 0,0, 0, -1,FPS_SRC_NONE, -1, -1, EN2_CTRL_SD0);

MAX77663_PDATA_INIT(sd1,  800000, 1587500, NULL, 1, 0, 0,1, 1, -1,FPS_SRC_1, FPS_POWER_PERIOD_1, FPS_POWER_PERIOD_6, 0);

……

先猜想一下,这个应该是赋值的地方. 接下来我们看MAX77663_PDATA_INIT是一个什么东东.

#defineMAX77663_PDATA_INIT(_id, _min_uV, _max_uV, _supply_reg,                   

                         _always_on, _boot_on, _apply_uV,                 

                         _init_apply, _init_enable, _init_uV,         

                         _fps_src, _fps_pu_period, _fps_pd_period,_flags)

  static struct max77663_regulator_platform_datamax77663_regulator_pdata_##_id =

  {                                                                        

            .init_data = {                                                  

                     .constraints = {                                    

                              .min_uV = _min_uV,                           

                              .max_uV = _max_uV,                         

                              .valid_modes_mask= (REGULATOR_MODE_NORMAL | 

                                                      REGULATOR_MODE_STANDBY),

                              .valid_ops_mask =(REGULATOR_CHANGE_MODE |   

                                                    REGULATOR_CHANGE_STATUS | 

                                                    REGULATOR_CHANGE_VOLTAGE),

                              .always_on =_always_on,               

                              .boot_on =_boot_on,                        

                              .apply_uV =_apply_uV,                     

                     },                                                    

                     .num_consumer_supplies =                      

                              ARRAY_SIZE(max77663_##_id##_supply),     

                     .consumer_supplies =max77663_##_id##_supply,       

                     .supply_regulator =_supply_reg,            

            },                                                              

            .init_apply = _init_apply,                            

            .init_enable = _init_enable,                                

            .init_uV = _init_uV,                                      

            .fps_src = _fps_src,                                     

            .fps_pu_period = _fps_pu_period,                    

            .fps_pd_period = _fps_pd_period,                    

            .fps_cfgs = max77663_fps_cfgs,                                

            .flags = _flags,                                     

  }

哇~~~ 这又是一个宏.

不用头晕.

我们对比一个这两个东东: 1.                                        .platform_data =  &max77663_regulator_pdata_##_data,        

2.               staticstruct max77663_regulator_platform_data   max77663_regulator_pdata_##_id =

明白了,程序执行MAX77663_REG(SD0, sd0),这一句的时候

会执行这个&max77663_regulator_pdata_##_data,  (注意,data=sd0)

然后会执行max77663_regulator_pdata_##_id   (_id传过来的是值是sd0)

就等于执行了这个宏:

#defineMAX77663_PDATA_INIT(_id, _min_uV, _max_uV, _supply_reg,                   

                         _always_on, _boot_on, _apply_uV,                 

                         _init_apply, _init_enable, _init_uV,         

                         _fps_src, _fps_pu_period, _fps_pd_period,_flags)

         static structmax77663_regulator_platform_data max77663_regulator_pdata_##_id =

这个宏是怎么赋值参数的, 参数在哪里传进来呢?

答案就是这个宏: MAX77663_PDATA_INIT

别忘记了这个函数max77663_regulator_pdata_##_id ,传进来的_id=sd0

那么等于这组参数会被调用:

MAX77663_PDATA_INIT(sd0, 600000, 3387500, NULL, 1, 0, 0,0, 0, -1, FPS_SRC_NONE, -1, -1,EN2_CTRL_SD0);

好了,在这里参数值传进来了,可以赋值了.

赋值:

#defineMAX77663_PDATA_INIT(_id, _min_uV, _max_uV, _supply_reg,                   

                         _always_on, _boot_on, _apply_uV,                 

                         _init_apply, _init_enable, _init_uV,         

                         _fps_src, _fps_pu_period, _fps_pd_period,_flags)

  static struct max77663_regulator_platform_datamax77663_regulator_pdata_##_id =

  {                                                                        

            .init_data = {                                                  

                     .constraints = {                                    

                              .min_uV = _min_uV,                           

                              .max_uV = _max_uV,                         

                              .valid_modes_mask= (REGULATOR_MODE_NORMAL | 

                                                      REGULATOR_MODE_STANDBY),

                              .valid_ops_mask =(REGULATOR_CHANGE_MODE |   

                                                    REGULATOR_CHANGE_STATUS | 

                                                    REGULATOR_CHANGE_VOLTAGE),

                              .always_on =_always_on,               

                              .boot_on =_boot_on,                        

                              .apply_uV =_apply_uV,                     

                     },                                                    

                     .num_consumer_supplies =                      

                              ARRAY_SIZE(max77663_##_id##_supply),     

                     .consumer_supplies =max77663_##_id##_supply,       

                     .supply_regulator =_supply_reg,            

            },                                                              

            .init_apply = _init_apply,                            

            .init_enable = _init_enable,                                

            .init_uV = _init_uV,                                      

            .fps_src = _fps_src,                                     

            .fps_pu_period = _fps_pu_period,                    

            .fps_pd_period = _fps_pd_period,                    

            .fps_cfgs = max77663_fps_cfgs,                                

            .flags = _flags,                                     

  }

接下来我们需要关心消费者的问题,就是我们注册了regulator,谁去使用它呢?

注意这个函数: .consumer_supplies = max77663_##_id##_supply,        

又是一个宏, ##_id## ,我们知道了,刚刚我们传进来的_id是sd0,那么该函数就是:max77663_sd0_supply.

查找一下函数试试~~~

~~~找到了.

static struct regulator_consumer_supply max77663_sd0_supply[] ={

         REGULATOR_SUPPLY("vdd_cpu",NULL),

};

static struct regulator_consumer_supply max77663_sd1_supply[] ={

         REGULATOR_SUPPLY("vdd_core",NULL),

};

….

Ok! 终于对上了.

REGULATOR_SUPPLY("vdd_cpu", NULL),

"vdd_cpu"是代表一路regulator

后面的NULL代表消费者, 

注意一个regulator可以包括很多消费者的.

为NULL那我们get的时候就不用关心消费者,只关心是哪一路regulator就好

其它路的regulator流程完全一样.

还有一点要特别指出的是:

#defineMAX77663_REG(_id, _data)                                               

  {                                                                        

            .name ="max77663-regulator",                                

            .id = MAX77663_REGULATOR_ID_##_id,                          

            .platform_data =&max77663_regulator_pdata_##_data,  

            .pdata_size =sizeof(max77663_regulator_pdata_##_data),        

  }

这个宏它会多次被调用, 就是说他有多路regulator的平台设备name都一样, .name ="max77663-regulator".

那么我们可以大胆的设想一下,是不是平台驱动会probe很多次?

Yes,答案是肯定的,这个等我们分析平台驱动的时候就会知道.

到这里为止平台设备注册成功了.下一步需要关心驱动了.

Regulator驱动:      kerneldrivers egulatormax77663-regulator.c

                                     kernelincludelinux egulatormax77663-regulator.h

首先看init函数:

static int __init max77663_regulator_init(void)

{

         returnplatform_driver_register(&max77663_regulator_driver);

}

注册了一个max77663_regulator_driver的平台驱动.

static struct platform_driver max77663_regulator_driver = {

         .probe =max77663_regulator_probe,

         .remove =__devexit_p(max77663_regulator_remove),

         .driver = {

                   .name ="max77663-regulator",

                   .owner =THIS_MODULE,

         },

};

重点关心probe函数: .probe = max77663_regulator_probe,

static int max77663_regulator_probe(struct platform_device*pdev)

{

         structregulator_desc *rdesc;

         structmax77663_regulator *reg;

         int ret = 0;

         if ((pdev->id< 0) || (pdev->id >= MAX77663_REGULATOR_ID_NR)) {

                   dev_err(&pdev->dev,"Invalid device id %d ", pdev->id);

                   return-ENODEV;

         }

         rdesc =&max77663_rdesc[pdev->id];

         reg =&max77663_regs[pdev->id];

         reg->dev =&pdev->dev;

         reg->pdata =dev_get_platdata(&pdev->dev);

         dev_dbg(&pdev->dev,"probe: name=%s ", rdesc->name);

         ret =max77663_regulator_preinit(reg);

         if (ret) {

                   dev_err(&pdev->dev,"probe: Failed to preinit regulator %s ",

                            rdesc->name);

                   returnret;

         }

         reg->rdev =regulator_register(rdesc, &pdev->dev,

                                            &reg->pdata->init_data, reg);

         if(IS_ERR(reg->rdev)) {

                   dev_err(&pdev->dev,"probe: Failed to register regulator %s ",

                            rdesc->name);

                   returnPTR_ERR(reg->rdev);

         }

         return 0;

}

这几条用于得到平台设备传过来的平台数据:

         rdesc =&max77663_rdesc[pdev->id];

         reg =&max77663_regs[pdev->id];

         reg->dev =&pdev->dev;

         reg->pdata =dev_get_platdata(&pdev->dev);

注意这里只传过来一路regulator的信息, 所以我们之前的猜想完全是对的,

就是这个probe函数会多次被调用,每一路regulator设备会调用一次.

那么是不是意味着这不是一个驱动而是一组驱动呢?

嗯,或许你可以这样理解.

这里我们分析一路就好了,其它的也就完全一样了.

其中这两句比较重要:

         rdesc =&max77663_rdesc[pdev->id];

         reg =&max77663_regs[pdev->id];

先看rdesc =&max77663_rdesc[pdev->id];

static struct regulator_descmax77663_rdesc[MAX77663_REGULATOR_ID_NR] = {

         REGULATOR_DESC(SD0,sd0),

         REGULATOR_DESC(DVSSD0,dvssd0),

……

};

我们展开宏: REGULATOR_DESC

#define REGULATOR_DESC(_id, _name)                            

         [MAX77663_REGULATOR_ID_##_id]= {         

                   .name =max77663_rails(_name),          

                   .id =MAX77663_REGULATOR_ID_##_id,       

                   .ops =&max77663_ldo_ops,           

                   .type =REGULATOR_VOLTAGE,               

                   .owner =THIS_MODULE,                          

         }

明白了,他是注册了一个opration操作函数.

static struct regulator_ops max77663_ldo_ops = {

         .set_voltage =max77663_regulator_set_voltage,

         .get_voltage =max77663_regulator_get_voltage,

         .enable =max77663_regulator_enable,

         .disable =max77663_regulator_disable,

         .is_enabled =max77663_regulator_is_enabled,

         .set_mode =max77663_regulator_set_mode,

         .get_mode =max77663_regulator_get_mode,

};

看见了没有?这是有设置regulator的电压,和得到电压,以及enabled等函数.

很明显,这些函数是留给消费者使用的.

好了,消费者怎么使用的问题有了头绪了,可是还有一个问题,硬件信息呢?

接下来我们看: reg =&max77663_regs[pdev->id];

static struct max77663_regulatormax77663_regs[MAX77663_REGULATOR_ID_NR] = {

         REGULATOR_SD(SD0,    SDX, SD0, 600000, 3387500, 12500),

         REGULATOR_SD(DVSSD0,SDX, NONE, 600000, 3387500, 12500),

……

}

这好像是设置一些电压,电流值的,怎么这么熟悉呢?

对了,我们在平台设备注册的时候见过类似的.

MAX77663_PDATA_INIT(sd0, 600000, 3387500, NULL, 1, 0, 0,0, 0, -1, FPS_SRC_NONE, -1, -1,EN2_CTRL_SD0);

……

继续展开宏:REGULATOR_SD

#define REGULATOR_LDO(_id, _type, _min_uV, _max_uV, _step_uV)  

         [MAX77663_REGULATOR_ID_##_id]= {                  

                   .id =MAX77663_REGULATOR_ID_##_id,                

                   .type =REGULATOR_TYPE_LDO_##_type,              

                   .volt_mask= LDO_VOLT_MASK,                        

                   .regs ={                                        

                            [VOLT_REG]= {                                    

                                     .addr= MAX77663_REG_##_id##_CFG,

                            },                                           

                            [CFG_REG]= {                             

                                     .addr= MAX77663_REG_##_id##_CFG2,

                            },                                           

                            [FPS_REG]= {                              

                                     .addr= MAX77663_REG_FPS_##_id,      

                            },                                           

                   },                                                    

                   .min_uV= _min_uV,                                    

                   .max_uV= _max_uV,                                  

                   .step_uV= _step_uV,                                 

                   .regulator_mode= REGULATOR_MODE_NORMAL,      

                   .power_mode= POWER_MODE_NORMAL,            

                   .power_mode_mask= LDO_POWER_MODE_MASK,              

                   .power_mode_shift= LDO_POWER_MODE_SHIFT,       

         }

好了,这就是要设置的硬件信息了, 电压值, 寄存器地址都有了.

寄存器.regs = {                                             

                            [VOLT_REG]= {                                    

                                     .addr= MAX77663_REG_##_id##_CFG,

                            },                                           

                            [CFG_REG]= {                             

                                     .addr= MAX77663_REG_##_id##_CFG2,

                            },                                           

                            [FPS_REG]= {                              

                                     .addr= MAX77663_REG_FPS_##_id,      

                            },                        

我们猜想一下这三个词的意思:

 VOLT_REG  电压寄存器

CFG_REG   config寄存器

FPS_REG   频率寄存器

…..先到这吧.

大家一定也想到了:

         rdesc =&max77663_rdesc[pdev->id];

         reg =&max77663_regs[pdev->id];

这两个值好像有着某种对应关系, 一个可以提供操作函数,一个可以提供硬件的操作信息.那他们俩合在一起的话驱动不就完整了吗?

接下来看这个函数:

ret = max77663_regulator_preinit(reg);

顾名思义,对这些传过来的数据进行初始化.

staticint max77663_regulator_preinit(struct max77663_regulator *reg)

{

         struct max77663_regulator_platform_data*pdata = _to_pdata(reg);

         struct device *parent =_to_parent(reg);

         int i;

         u8 val, mask;

         int ret;

         /* Update registers */

         for (i = 0; i <= FPS_REG; i++) {

                   ret = max77663_read(parent,reg->regs[i].addr,

                                         &reg->regs[i].val, 1, 0);

                   if (ret < 0) {

                            dev_err(reg->dev,

                                     "preinit:Failed to get register 0x%x ",

                                     reg->regs[i].addr);

                            return ret;

                   }

         }

         /* Update FPS source */

         if (reg->regs[FPS_REG].addr ==MAX77663_REG_FPS_NONE)

                   reg->fps_src =FPS_SRC_NONE;

         else

                   reg->fps_src =(reg->regs[FPS_REG].val & FPS_SRC_MASK)

                                     >>FPS_SRC_SHIFT;

         dev_dbg(reg->dev, "preinit:initial fps_src=%s ",

                   fps_src_name(reg->fps_src));

         /* Update power mode */

         max77663_regulator_get_power_mode(reg);

         /* Check Chip Identification */

         ret = max77663_read(parent,MAX77663_REG_CID5, &val, 1, 0);

         if (ret < 0) {

                   dev_err(reg->dev,"preinit: Failed to get register 0x%x ",

                            MAX77663_REG_CID5);

                   return ret;

         }

         /* If metal revision is less thanrev.3,

          * set safe_down_uV for stable down scaling. */

         if ((reg->type == REGULATOR_TYPE_SD)&&

                            ((val &CID_DIDM_MASK) >> CID_DIDM_SHIFT) <= 2)

                   reg->safe_down_uV =SD_SAFE_DOWN_UV;

         else

                   reg->safe_down_uV = 0;

         /* Set FPS */

         ret =max77663_regulator_set_fps_cfgs(reg, pdata->fps_cfgs,

                                                     pdata->num_fps_cfgs);

         if (ret < 0) {

                   dev_err(reg->dev,"preinit: Failed to set FPSCFG ");

                   return ret;

         }

         /* N-Channel LDOs don't supportLow-Power mode. */

         if ((reg->type ==REGULATOR_TYPE_LDO_N) &&

                            (pdata->flags& GLPM_ENABLE))

                   pdata->flags &=~GLPM_ENABLE;

         /* To prevent power rail turn-off whenchange FPS source,

          * it must set power mode to NORMAL beforechange FPS source to NONE

          * from SRC_0, SRC_1 and SRC_2. */

         if ((reg->fps_src != FPS_SRC_NONE)&& (pdata->fps_src == FPS_SRC_NONE)

                            &&(reg->power_mode != POWER_MODE_NORMAL)) {

                   val = (pdata->flags &GLPM_ENABLE) ?

                         POWER_MODE_GLPM : POWER_MODE_NORMAL;

                   ret =max77663_regulator_set_power_mode(reg, val);

                   if (ret < 0) {

                            dev_err(reg->dev,"preinit: Failed to "

                                     "setpower mode to POWER_MODE_NORMAL ");

                            return ret;

                   }

         }

         ret =max77663_regulator_set_fps_src(reg, pdata->fps_src);

         if (ret < 0) {

                   dev_err(reg->dev,"preinit: Failed to set FPSSRC to %d ",

                            pdata->fps_src);

                   return ret;

         }

         ret = max77663_regulator_set_fps(reg);

         if (ret < 0) {

                   dev_err(reg->dev,"preinit: Failed to set FPS ");

                   return ret;

         }

         /* Set initial state */

         if (!pdata->init_apply)

                   goto skip_init_apply;

         if (pdata->init_uV >= 0) {

                   ret =max77663_regulator_do_set_voltage(reg, pdata->init_uV,

                                                                 pdata->init_uV);

                   if (ret < 0) {

                            dev_err(reg->dev,"preinit: Failed to set voltage to "

                                     "%d ",pdata->init_uV);

                            return ret;

                   }

         }

         if (pdata->init_enable)

                   val = (pdata->flags &GLPM_ENABLE) ?

                         POWER_MODE_GLPM : POWER_MODE_NORMAL;

         else

                   val = POWER_MODE_DISABLE;

         ret =max77663_regulator_set_power_mode(reg, val);

         if (ret < 0) {

                   dev_err(reg->dev,

                            "preinit:Failed to set power mode to %d ", val);

                   return ret;

         }

skip_init_apply:

         if (reg->type == REGULATOR_TYPE_SD){

                   val = 0;

                   mask = 0;

                   if (pdata->flags &SD_SLEW_RATE_MASK) {

                            mask |= SD_SR_MASK;

                            if (pdata->flags& SD_SLEW_RATE_SLOWEST)

                                     val |=(SD_SR_13_75 << SD_SR_SHIFT);

                            else if(pdata->flags & SD_SLEW_RATE_SLOW)

                                     val |=(SD_SR_27_5 << SD_SR_SHIFT);

                            else if(pdata->flags & SD_SLEW_RATE_FAST)

                                     val |=(SD_SR_55 << SD_SR_SHIFT);

                            else

                                     val |=(SD_SR_100 << SD_SR_SHIFT);

                   }

                   mask |= SD_FPWM_MASK;

                   if (pdata->flags &SD_FORCED_PWM_MODE)

                            val |= SD_FPWM_MASK;

                   mask |= SD_FSRADE_MASK;

                   if (pdata->flags &SD_FSRADE_DISABLE)

                            val |=SD_FSRADE_MASK;

                   ret =max77663_regulator_cache_write(reg,

                                     reg->regs[CFG_REG].addr,mask, val,

                                     &reg->regs[CFG_REG].val);

                   if (ret < 0) {

                            dev_err(reg->dev,"preinit: "

                                     "Failedto set register 0x%x ",

                                     reg->regs[CFG_REG].addr);

                            return ret;

                   }

                   if ((reg->id ==MAX77663_REGULATOR_ID_SD0)

                                     &&(pdata->flags & EN2_CTRL_SD0)) {

                            val =POWER_MODE_DISABLE;

                            ret =max77663_regulator_set_power_mode(reg, val);

                            if (ret < 0) {

                                     dev_err(reg->dev,"preinit: "

                                               "Failedto set power mode to %d for "

                                               "EN2_CTRL_SD0 ",val);

                                     return ret;

                            }

                            ret =max77663_regulator_set_fps_src(reg, FPS_SRC_NONE);

                            if (ret < 0) {

                                     dev_err(reg->dev,"preinit: "

                                               "Failedto set FPSSRC to FPS_SRC_NONE "

                                               "forEN2_CTRL_SD0 ");

                                     return ret;

                            }

                   }

         }

         if ((reg->id ==MAX77663_REGULATOR_ID_LDO4)

                            &&(pdata->flags & LDO4_EN_TRACKING)) {

                   val = TRACK4_MASK;

                   ret = max77663_write(parent,MAX77663_REG_LDO_CFG3, &val, 1, 0);

                   if (ret < 0) {

                            dev_err(reg->dev,"preinit: "

                                     "Failedto set register 0x%x ",

                                     MAX77663_REG_LDO_CFG3);

                            return ret;

                   }

         }

         return 0;

}

哇,好像有点长.

         structmax77663_regulator_platform_data *pdata = _to_pdata(reg);

         struct device*parent = _to_parent(reg);

第一句是得到平台设备数据,在平台设备注册的时候也有一个max77663_regulator_platform_data哦,可别忘记了.

第二句是得到一个父regulator,你的regulator可以给子的regulator供电嘛. 好像也没看见怎么使用,不用管了.

/* Update registers */

         for (i = 0; i<= FPS_REG; i++) {

                   ret =max77663_read(parent, reg->regs[i].addr,

                                         &reg->regs[i].val, 1, 0);

                   if (ret< 0) {

                            dev_err(reg->dev,

                                     "preinit:Failed to get register 0x%x ",

                                     reg->regs[i].addr);

                            returnret;

                   }

         }

         /* Update FPSsource */

         if(reg->regs[FPS_REG].addr == MAX77663_REG_FPS_NONE)

                   reg->fps_src= FPS_SRC_NONE;

         else

                   reg->fps_src= (reg->regs[FPS_REG].val & FPS_SRC_MASK)

                                     >>FPS_SRC_SHIFT;

         dev_dbg(reg->dev,"preinit: initial fps_src=%s ",

                   fps_src_name(reg->fps_src));

         /* Update powermode */

         max77663_regulator_get_power_mode(reg);

这一部分好像都是更新什么寄存器, 都是读的我们不管它.

Pmu珍对某个cpu出厂都会预设一组参数进去的,保证cpu最低限度的正常上电时序.

….

ret = max77663_regulator_set_fps_cfgs(reg,pdata->fps_cfgs,pdata->num_fps_cfgs);

进函数:

static int  max77663_regulator_set_fps_cfgs(structmax77663_regulator *reg,

                                     structmax77663_regulator_fps_cfg *fps_cfgs,

                                     intnum_fps_cfgs)

{

         ……

                   ret =max77663_regulator_set_fps_cfg(reg, &fps_cfgs[i]);

…..

}

很明显,设置 config寄存器.

接着往下看:

….

ret = max77663_regulator_set_power_mode(reg, val);

….

ret = max77663_regulator_set_fps_src(reg, pdata->fps_src);

….

ret = max77663_regulator_set_fps(reg);

….

ret = max77663_regulator_do_set_voltage(reg,pdata->init_uV,pdata->init_uV);

….

不想看了,写的很长,但无非全是些初始化操作, 什么config寄存器呀,频率寄存器呀,电压寄存器呀.

初始化函数到此为止吧.

我们接着probe函数往下看:

         reg->rdev =regulator_register(rdesc, &pdev->dev,&reg->pdata->init_data,reg);

这就是注册regulator了.

和我们之前说的一样.

         rdesc =&max77663_rdesc[pdev->id];

         reg =&max77663_regs[pdev->id];

这两个结构合作了, 一个有硬件,寄存器配制信息,一个有opration操作函数,驱动完整了.

接下个完成各自的opration操作函数就ok了.

static struct regulator_ops max77663_ldo_ops = {

         .set_voltage =max77663_regulator_set_voltage,

         .get_voltage =max77663_regulator_get_voltage,

         .enable =max77663_regulator_enable,

         .disable =max77663_regulator_disable,

         .is_enabled =max77663_regulator_is_enabled,

         .set_mode =max77663_regulator_set_mode,

         .get_mode =max77663_regulator_get_mode,

};

到此为止,流程全通了,实现这些函数应该没难度,和平常写函数的思路大同小异.

其实max77663驱动除了,regulator驱动部分还有.

Regulator驱动:      kerneldrivers egulatormax77663-regulator.c

                                     kernelincludelinux egulatormax77663-regulator.h

rtc驱动:         kerneldrivers tc tc-max77663.c

max77663  core驱动:      kerneldriversmfdmax77663-core.c

                                kernellinuxmfdmax77663-core.h

细心的人一定发现了,我们在平台设备注册的时候有两个i2c地址,

其中一个是regulator的i2c地址,另一个则是rtc的i2c地址.

max77663  Core驱动其实是包括了一些regulator的具体硬件最终的操作, 我们的opration的最终操作函数会调用到里面.

这些部分和平常的驱动几乎一样,所以也没有必要分析了.

Regulator讲完了,pmu的流程其实都已经清楚了.

最后还要就是regulator怎么使用? 我们注册了regulator,也初始化了它,还注册了opration函数.但并没有消费者真正去使用它.

记得我们刚学linux驱动的时候, 有一个file_opration函数,

这里的操作函数是让上层c语言应用程序调用的.

可是我们这里的opration函数不是这样的,他是给其它模块使用的. 即:其它驱动程序使用.

比如:触摸屏它使用了一路regulator,他在机器suspend的时候要求关电(或者说低电),在机器开屏的时候才要求上电使用.

那么:

使用过程是这样的:

1.我们先注册一个全局的regulator

static struct regulator *nabi2_dsi_reg = NULL;

2.然后get regulator

nabi2_dsi_reg = regulator_get(NULL, "avdd_dsi_csi");

这个我们应该有印象,在平台设备注册的时候我们有注册它.

如:

static struct regulator_consumer_supply max77663_ldo7_supply[] ={

         REGULATOR_SUPPLY("avdd_dsi_csi",NULL),

         REGULATOR_SUPPLY("pwrdet_mipi",NULL),

};

Ok,之前我们注册了它,现在我们得到它

3.给它上电就使能它

regulator_enable(nabi2_dsi_reg);

4.我们不再需要的时候就禁止它,以及放回它的使用权.

         regulator_disable(nabi2_dsi_reg);

         regulator_put(nabi2_dsi_reg);

还有一些操作函数如:

int regulator_get_voltage(struct regulator *regulator)

int regulator_set_current_limit(struct regulator *regulator,intmin_uA, int max_uA)

….

具体请参考: kerneldrivers egulatorcore.c

Over!

原文地址:https://www.cnblogs.com/biglucky/p/4059386.html