现在的位置: 首页 > 综合 > 正文

regulator

2013年10月13日 ⁄ 综合 ⁄ 共 11240字 ⁄ 字号 评论关闭

        原文地址:http://lhsblog01.blog.163.com/blog/static/1020045192010221104120218/



        regulator是驱动中电源管理的基础设施。要先注册到内核中,然后使用这些电压输出的模块get其regulator,在驱动中的init里,在适当时间中进行电压电流的设置.



         Linux内核的动态电压和电流控制接口



         "LDO是low dropout
regulator,意为低压差线性稳压器",是相对于传统的线性稳压器来说的。传统的线性稳压器,如78xx系列的芯片都要求输入电压要比输出电压高出
2v~3V以上,否则就不能正常工作。但是在一些情况下,这样的条件显然是太苛刻了,如5v转3.3v,输入与输出的压差只有1.7v,显然是不满足条件
的。针对这种情况,才有了LDO类的电源转换芯片。生产LDO芯片的公司很多,常见的有ALPHA, Linear(LT), Micrel,
National semiconductor,TI等。



       

in:twl4030-poweroff.c


一种称为校准器(regulator)的动态电压和电流控制的方法,很有参考意义和实际使用价值。


       

1:校准器的基本概念
所谓校准器实际是在软件控制下把输入的电源调节精心输出。


2:Consumer的API
regulator = regulator_get(dev, “Vcc”);
其中,dev 是设备“Vcc”一个字符串代表,校准器(regulator)然后返回一个指针,也是regulator_put(regulator)使用的。
打开和关闭校准器(regulator)API如下。
int regulator_enable(regulator);
int regulator_disable(regulator);


3: 电压的API
消费者可以申请提供给它们的电压,如下所示。
int regulator_set_voltage(regulator, int min_uV, int max_uV);
在改变电压前要检查约束,如下所示。
regulator_set_voltage(regulator,100000,150000)
电压值下面的设置改变如下所示。
int regulator_get_voltage)struct regulator *regulator);


4:校准器的驱动和系统配置
在实际使用校准器之前,需要按照下面的结构写校准器的驱动程序,然后注册后通知给消费者使用。


//************************* linux regulator 模型******************************************//


static LIST_HEAD(regulator_list);     //整个regulator模型的所有regulator.
static LIST_HEAD(regulator_map_list); //整个regulator模型的map


struct regulator_consumer_supply :
用户支持的接口映射。  supply -> device

struct regulator_state:
用于表示 在整个系统的低功耗状态下的设备状态。

struct regulation_constraints :
操作约束。

struct regulator_init_da
ta  
校准器平台初始化数据。

struct regulator_dev
向内核注册后 得到regulator设备结构



注册:
struct regulator_dev *regulator_register(struct regulator_desc *regulator_desc,struct device *dev, void *driver_da
ta)

反注册:
要使用注册得到 regulator_dev:
void regulator_unregister(struct regulator_dev *rdev)


/* Regulator operating modes.**/
#define REGULATOR_MODE_FAST
0x1 //电压可以快速调

#define REGULATOR_MODE_NORMAL
0x2 //一般模式

#define REGULATOR_MODE_IDLE
0x4 //低load

#define REGULATOR_MODE_STANDBY
0x8 //sleep/ standby 状态下 低功耗



例子:
/* VSIM for OMAP VDD_MMC1A (i/o for DAT4..DAT7) */
static struct regulator_init_da
ta zoom2_vsim = { //这个da
ta被置于 对应的 platform_device 的da
ta字段中。


.constraints = {


.min_uV
= 1800000,


.max_uV
= 3000000,


.valid_modes_mask
= REGULATOR_MODE_NORMAL  /*这里设置*/


| REGULATOR_MODE_STANDBY,


.valid_ops_mask
= REGULATOR_CHANGE_VOLTAGE /*这里设置这个regulator上可进行的操作。调电压,模式可变,可以打开关闭*/


| REGULATOR_CHANGE_MODE


| REGULATOR_CHANGE_STATUS,


},


.num_consumer_supplies  = 1,


.consumer_supplies      = &zoom2_vsim_supply,

};
// regulator 的初始化数据要放到  device 's  platform_da
ta

struct regulator_init_da
ta *init_da
ta = dev->platform_da
ta;



"重点"
//*************************** twl4030 regulator 的实现  ****************************//
struct twlreg_info : 关联到驱动与设备的数据。驱动的私有数据,driver_da
ta.

struct twlreg_info {

/* start of regulator's PM_RECEIVER control register bank */


u8
base;




/* twl4030 resource ID, for resource control state machine */


u8
id;




/* FIXED_LDO voltage */


u8
deciV;




/* voltage in mV = table[VSEL]; table_len must be a power-of-two */


u8
table_len;


const u16
*table;




/* used by regulator core */


struct regulator_desc
desc;

};
//一个驱动(platform_driver)对应所有的regulator, 每个regulator在内核中表示为一个platform_device. 所以调用了许多次的probe
//在probe中,从全局数组中取出自定义的数据结构: twlreg_info, 然后从platform_device中取出初始化数据(device's platform_da
ta),然后就可以向内核注册一个 regulator(会返回一个regulator_dev:类)。


"struct regulator_dev *regulator_register(struct regulator_desc *regulator_desc,struct device *dev, void *driver_da
ta)"



1:每个regulator 的  "twlreg_info" 被 存于 regulator_dev 的 device 's driver_da
ta, twlreg_info中的 table 存支持的电压值。

2:两种操作结构"regulator_ops":twl4030fixed_ops(电压固定),  twl4030ldo_ops(电压可调)
3:传入每个 ops中的操作函数 的参数是:  regulator_dev.
4: 在  twl4030-core.c中,在添加 twl4030的 i2c_client时,添加了所有的 regulator 的 platform_device.


5: 在驱动初始化注册中,内核会自动去匹配 bus上的所有符合的 platform_device(代表regulator,init_da
ta放于device's platform_da
ta), 所以一个驱动就可以匹配到 bus上所有对应的 regulator.

6: 每匹配一个 regulator的 platform_device时,就会从中,platform_device的 device 中的 platform_da
ta 中得到 regulator的初始化数据: regulator_init_da
ta

7: 取出初始化数据后, 设置一下. "设置,即是当设备支持一定的功能后,由驱动来控制时,要匹配驱动能做到的功能。that is 两者 与(&) 一下"
  然后,从regulator模块的全局数组"twl4030_regs[]" 中取出 twlreg_info 

if (twl4030_regs[i].desc.id != pdev->id)


continue;


info = twl4030_regs + i;




就可以向内核注册这个 regulator了:


"rdev = regulator_register(&info->desc, &pdev->dev, info);"


"注册后返回一个 regulator_dev": 然后把这个rdev输入到 platform_device 's device 's driver_da
ta... 主要用于 remove中???


regulator_dev:是一个类,其父是 本regulator的platform_device 's device.



8: // regulator_ops 存入了 regulator_desc, 然后注册时,desc 关联到了 regulator_dev-> desc = desc.
生成regualator_dev, 设置数据,注册sysfs,然后: constraints, attribute, supply ,comsumer device.
struct regulator_dev *regulator_register(struct regulator_desc *regulator_desc,
struct device *dev, void *driver_da
ta)





9:另:
大部分的regulator的platform_device生成如下:

每个regulator设备注册到内核的时机是在 twl4030-core.c 中。


把regulator的初始化数据,放到新生成的platform_device 's device 's platform_da
ta...


然后注册 platform_device 到内核中。



usb部分的regulator生成如下:(这里明显是由于OMAP不一定是有USB??,然后在其board-zoom2.c中,"没有设置每个初始化数据"(包括:supply,constraints(min,max,mask)))


对于usb模块的 regulator, 先生成对应的platform_device,
返回了platform_device->device,
然后利用这个device去形成多个: regulator_consumer_supply.dev = device.


然后用这些 regulator_consumer_supply, 来做comsumer并生成 platform_device.注册



//************************** 使用regulator ***************************//
regulator已经向内核模型注册了,但如何使用呢,怎样调节电压??
//注册后,内核中就已经有对应的regulator对应的 supply consumer. 然后在驱动中任何地方调用接口即可:
//regulator_get, regulator_enable, regulator_disable, regulator_set_voltage, regulator_get_voltage......


1:在twl4030-usb模块中,会用到 usb对应的 reuglator,,   fixed_ops

twl->usb3v1 = regulator_get(twl->dev, "usb3v1");


regulator_enable(twl->usb3v1);


regulator_disable(twl->usb1v5);

2:
regulator = regulator_get(dev, “Vcc”);
其中,dev 是设备“Vcc”一个字符串代表,校准器(regulator)然后返回一个指针,也是regulator_put(regulator)使用的。
打开和关闭校准器(regulator)API如下。
int regulator_enable(regulator);
int regulator_disable(regulator);


 电压的API
消费者可以申请提供给它们的电压,如下所示。
int regulator_set_voltage(regulator, int min_uV, int max_uV);
在改变电压前要检查约束,如下所示。
regulator_set_voltage(regulator,100000,150000)


//************************************************//

/**
 * struct regulator_desc - Regulator descriptor
 *
 * Each regulator registered with the core is described with a structure of
 * this type.
 *
 * @name: Identifying name for the regulator.
 * @id: Numerical identifier for the regulator.
 * @n_voltages: Number of selectors available for ops.list_voltage().
 * @ops: Regulator operations table.
 * @irq: Interrupt number for the regulator.
 * @type: Indicates if the regulator is a voltage or current regulator.
 * @owner: Module providing the regulator, used for refcounting.
 */
struct regulator_desc {

const char *name;


int id;


unsigned n_voltages;


struct regulator_ops *ops;


int irq;


enum regulator_type type;


struct module *owner;

};
enum regulator_status {

REGULATOR_STATUS_OFF,


REGULATOR_STATUS_ON,


REGULATOR_STATUS_ERROR,


/* fast/normal/idle/standby are flavors of "on" */


REGULATOR_STATUS_FAST,


REGULATOR_STATUS_NORMAL,


REGULATOR_STATUS_IDLE,


REGULATOR_STATUS_STANDBY,

};
/*
 * struct regulator_dev
 *
 * Voltage / Current regulator class device. On
e for each regulator.

 */
struct regulator_dev {

struct regulator_desc *desc;


int use_count;




/* lists we belong to */


struct list_head list; /* list of all regulators */


struct list_head slist; /* list of supplied regulators */




/* lists we own */


struct list_head consumer_list; /* consumers we supply */


struct list_head supply_list; /* regulators we supply */




struct blocking_notifier_head notifier;


struct mutex mutex; /* consumer lock */


struct module *owner;


struct device dev;


struct regulation_constraints *constraints;


struct regulator_dev *supply;
/* for tree */




void *reg_da
ta;
/* regulator_dev da
ta */

};
/*
 * struct regulator
 *
 * On
e for each consumer device.

 */
struct regulator {

struct device *dev;


struct list_head list;


int uA_load;


int min_uV;


int max_uV;


int enabled; /* count of client enables */


char *supply_name;


struct device_attribute dev_attr;


struct regulator_dev *rdev;

};


/*
 * struct regulator_map
 *
 * Used to provide symbolic supply names to devices.
 */
struct regulator_map {

struct list_head list;


struct device *dev;


const char *supply;


struct regulator_dev *regulator;

};
/**
 * struct regulator_state - regulator state during low power syatem states
 *
 * This describes a regulators state during a system wide low power state.
 *
 * @uV: Operating voltage during suspend.
 * @mode: Operating mode during suspend.
 * @enabled: Enabled during suspend.
 */
struct regulator_state {

int uV;
/* suspend voltage */


unsigned int mode; /* suspend regulator operating mode */


int enabled; /* is regulator enabled in this suspend state */

};


/**
 * struct regulation_constraints - regulator operating constraints.
 *
 * This struct describes regulator and board/machine specific constraints.
 *
 * @name: Descriptive name for the constraints, used for display purposes.
 *
 * @min_uV: Smallest voltage consumers may set.
 * @max_uV: Largest voltage consumers may set.
 *
 * @min_uA: Smallest consumers consumers may set.
 * @max_uA: Largest current consumers may set.
 *
 * @valid_modes_mask: Mask of modes which may be configured by consumers.
 * @valid_ops_mask: Operations which may be performed by consumers.
 *
 * @always_on: Set if the regulator should never be disabled.
 * @boot_on: Set if the regulator is enabled when the system is initially
 *           started.
 * @apply_uV: Apply the voltage constraint when initialising.
 *
 * @input_uV: Input voltage for regulator when supplied by another regulator.
 *
 * @state_disk: State for regulator when system is suspended in disk mode.
 * @state_mem: State for regulator when system is suspended in mem mode.
 * @state_standby: State for regulator when system is suspended in standby
 *                 mode.
 * @initial_state: Suspend state to set by default.
 */
struct regulation_constraints {



char *name;




/* voltage output range (inclusive) - for voltage control */


int min_uV;


int max_uV;




/* current output range (inclusive) - for current control */


int min_uA;


int max_uA;




/* valid regulator operating modes for this machine */


unsigned int valid_modes_mask;




/* valid operations for regulator on this machine */


unsigned int valid_ops_mask;




/* regulator input voltage - on
ly if supply is another regulator */


int input_uV;




/* regulator suspend states for global PMIC STANDBY/HIBERNATE */


struct regulator_state state_disk;


struct regulator_state state_mem;


struct regulator_state state_standby;


suspend_state_t initial_state; /* suspend state to set at init */




/* constriant flags */


unsigned always_on:1;
/* regulator never off when system is on */


unsigned boot_on:1;
/* bootloader/firmware enabled regulator */


unsigned apply_uV:1;
/* apply uV constraint iff min == max */

};


/**
 * struct regulator_consumer_supply - supply -> device mapping
 *
 * This maps a supply name to a device.
 *
 * @dev: Device structure for the consumer.
 * @supply: Name for the supply.
 */
struct regulator_consumer_supply {

struct device *dev;
/* consumer */


const char *supply;
/* consumer supply - e.g. "vcc" */

};
/**
 * struct regulator_desc - Regulator descriptor
 *
 * Each regulator registered with the core is described with a structure of
 * this type.
 *
 * @name: Identifying name for the regulator.
 * @id: Numerical identifier for the regulator.
 * @n_voltages: Number of selectors available for ops.list_voltage().
 * @ops: Regulator operations table.
 * @irq: Interrupt number for the regulator.
 * @type: Indicates if the regulator is a voltage or current regulator.
 * @owner: Module providing the regulator, used for refcounting.
 */
struct regulator_desc {

const char *name;


int id;


unsigned n_voltages;


struct regulator_ops *ops;


int irq;


enum regulator_type type;


struct module *owner;

};


/**
 * struct regulator_init_da
ta - regulator platform initialisation da
ta.

 *
 * Initialisation constraints, our supply and consumers supplies.
 *
 * @supply_regulator_dev: Parent regulator (if any).
 *
 * @constraints: Constraints.  These must be specified for the regulator to
 *               be usable.
 * @num_consumer_supplies: Number of consumer device supplies.
 * @consumer_supplies: Consumer device supply configuration.
 *
 * @regulator_init: Callback invoked when the regulator has been registered.
 * @driver_da
ta: Da
ta passed to regulator_init.

 */
struct regulator_init_da
ta {


struct device *supply_regulator_dev; /* or NULL for LINE */




struct regulation_constraints constraints;




int num_consumer_supplies;


struct regulator_consumer_supply *consumer_supplies;




/* optional regulator machine specific init */


int (*regulator_init)(void *dri

抱歉!评论已关闭.