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

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

电压值等.

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

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

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

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

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

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

Pmu的板级初始化文件:kernel\arch\arm\mach-tegra\board-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\n",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驱动:      kernel\drivers\regulator\max77663-regulator.c

kernel\include\linux\regulator\max77663-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\n", 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\n", rdesc->name);

ret =max77663_regulator_preinit(reg);

if (ret) {

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

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\n",

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\n",

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\n",

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\n",

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\n");

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\n");

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\n",

pdata->fps_src);

return ret;

}

ret = max77663_regulator_set_fps(reg);

if (ret < 0) {

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

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\n",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\n", 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\n",

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\n",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\n");

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\n",

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\n",

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\n",

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驱动:      kernel\drivers\regulator\max77663-regulator.c

kernel\include\linux\regulator\max77663-regulator.h

rtc驱动:         kernel\drivers\rtc\rtc-max77663.c

max77663  core驱动:      kernel\drivers\mfd\max77663-core.c

kernel\linux\mfd\max77663-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)

….

具体请参考: kernel\drivers\regulator\core.c

Over!

电源管理之pmu驱动分析的更多相关文章

  1. exynos 4412 电源管理芯片PMIC 的配置及使用方法

    /** ****************************************************************************** * @author    Maox ...

  2. [专业名词·硬件] 2、DC\DC、LDO电源稳压基本常识(包含基本原理、高效率模块设计、常见问题、基于nRF51822电源管理模块分析等)·长文

    综述先看这里 第一节的1.1简单介绍了DC/DC是什么: 第二节是关于DC/DC的常见的疑问答疑,非常实用: 第三节是针对nRF51822这款芯片电源管理部分的DC/DC.LDO.1.8的详细分析,对 ...

  3. Android电源管理-休眠简要分析

    一.开篇 1.Linux 描述的电源状态 - On(on)                                                 S0 -  Working - Standb ...

  4. ALSA声卡驱动中的DAPM详解之二:widget-具备路径和电源管理信息的kcontrol

    上一篇文章中,我们介绍了音频驱动中对基本控制单元的封装:kcontrol.利用kcontrol,我们可以完成对音频系统中的mixer,mux,音量控制,音效控制,以及各种开关量的控制,通过对各种kco ...

  5. linux驱动程序之电源管理之标准linux休眠与唤醒机制分析(一)

    1. Based on linux2.6.32,  only for mem(SDR) 2. 有兴趣请先参考阅读: 电源管理方案APM和ACPI比较.doc Linux系统的休眠与唤醒简介.doc 3 ...

  6. linux驱动编写(电源管理驱动)

    对于嵌入式设备来说,合适的电源管理,不仅可以延长电池的寿命,而且可以省电,延长设备运行时间,在提高用户体验方面有很大的好处.所以,各个soc厂家在这方面花了很多的功夫.下面,我们可以看看linux是如 ...

  7. Laravel驱动管理类Manager的分析和使用

    Laravel驱动管理类Manager的分析和使用 第一部分 概念说明 第二部分 Illuminate\Support\Manager源码 第三部分 Manager类的使用 第一部分:概念解释 结合实 ...

  8. Linux电源管理(11)_Runtime PM之功能描述

    转自:http://www.wowotech.net/pm_subsystem/rpm_overview.html 1. 前言 终于可以写Runtime PM(后面简称RPM)了,说实话,蜗蜗有点小激 ...

  9. linux电源管理系列(一)

    本系列将逐步介绍linux电源管理相关的知识,涉及到常见电源管理机制.linux电源管理机制.linux驱动中有关电源管理的相关接口.内核文档中关于Linux电源管理架构文档的分析.以下将以此来介绍相 ...

随机推荐

  1. ASP.NET前端语法应用

    字符拼接 <%# "abc" + Eval("列名").ToString() %> <%# Eval("列名"," ...

  2. linux - 创建用户

    apt-get update apt-get upgrade root@iZ28t2p7lz9Z:~# adduser cuiAdding user `cui' ...Adding new group ...

  3. ellang 中进程异步通信中的信箱与保序

    erlang 进程通讯中 执行到 receive 语句时 如果信箱没有消息可以匹配时会暂停等待消息. go() -> register(echo, spawn(test_pid,loop,[]) ...

  4. Socket 死连接详解

    Socket 死连接详解 当使用 Socket 进行通信时,由于各种不同的因素,都有可能导致死连接停留在服务器端,假如服务端需要处理的连接较多,就有可能造成服务器资源严重浪费,对此,本文将阐述其原理以 ...

  5. sar监控系统状态

    sar 命令很强大,它可以监控系统所有资源状态,比如平均负载.网卡流量.磁盘状态.内存使用等等. 它不同于其他系统状态监控工具的地方在于,它可以打印历史信息,可以显示当天从零点开始到当前时刻的系统状态 ...

  6. jquery 之事件 多库共存(noConflict)

    /*jquery 之 简单事件jquery 与其它库共存,提供了 .noConflict() 方法,用法如下<script src="jquery 库"><scr ...

  7. PHP 插入排序法

    <?php function insertSort($arr) { //区分 哪部分是已经排序好的 //哪部分是没有排序的 //找到其中一个需要排序的元素 //这个元素 就是从第二个元素开始,到 ...

  8. mongodb 非 admin 库 认证登陆失败 原因(百度好多都 是渣)db.addUser() 请走开。

    首先先晒一下log 日志错误信息 2016-07-13T22:19:43.667+0800 I ACCESS [conn4] authenticate db: finddemo { aut henti ...

  9. 一个小程序[Socrates]中学到的Perl点滴

    1. 抓取网页源文件,只要三行代码 use LWP::Simple; $url='http://music.baidu.com/top/dayhot'; $page=get($url) or die ...

  10. std::copy的使用

    看到有人在用std::copy这个东西,很简洁和爽啊,,所以找些帖子学习学习 http://blog.sina.com.cn/s/blog_8655aeca0100t6qe.html https:// ...