電源管理芯片可以為多設(shè)備供電,且這些設(shè)備電壓電流有所同。為這些設(shè)備提供的穩(wěn)壓器代碼模型即為regulator。
下面通過下面三個(gè)過程分析regulartor供電機(jī)制: 1.分析regulator結(jié)構(gòu)體 2.regulator 注冊過程 3.設(shè)備使用regulator過程
一.分析regulator結(jié)構(gòu)體 Regulator模塊用于控制系統(tǒng)中某些設(shè)備的電壓/電流供應(yīng)。在嵌入式系統(tǒng)(尤其是手機(jī))中,控制耗電量很重要,直接影響到電池的續(xù)航時(shí)間。所以,如果系統(tǒng)中某一個(gè)模塊暫時(shí)不需要使用,就可以通過regulator關(guān)閉其電源供應(yīng);或者降低提供給該模塊的電壓、電流大小。 Regulator的文檔在KERNEL/Documentation/Power/Regulator中。
Regulator與模塊之間是樹狀關(guān)系。父regulator可以給設(shè)備供電,也可以給子regulator供電: 父Regulator --> 子Regulator --> [supply] --> 設(shè)備[Consumer] 具體細(xì)節(jié)可參考內(nèi)核文檔machine.txt。
regulator_dev regulator_dev代表一個(gè)regulator設(shè)備。 struct regulator_dev { struct regulator_desc *desc; // 描述符,包括regulator的名稱、ID、regulator_ops等 int use_count; // 使用計(jì)數(shù)
struct list_head list; // regulator通過此結(jié)構(gòu)掛到regulator_list鏈表中 struct list_head slist; // 如果有父regulator,通過此域掛到父regulator的鏈表
struct list_head consumer_list; // 此regulator負(fù)責(zé)供電的設(shè)備列表 struct list_head supply_list; //此regulator負(fù)責(zé)供電的子regulator struct blocking_notifier_head notifier; // notifier,具體的值在consumer.h中,比如REGULATOR_EVENT_FAIL struct mutex mutex; struct module *owner; struct device dev; // device結(jié)構(gòu),屬于class regulator_class struct regulation_constraints *constraints; // 限制,比如最大電壓/電流、最小電壓/電流 struct regulator_dev *supply; // 父regulator的指針,即由此regulator 供電 void *reg_data; };
regulator_init_data
regulator_init_data在初始化時(shí)使用,用來建立父子regulator、受電模塊之間的樹狀結(jié)構(gòu),以及一些regulator的基本參數(shù)。 struct regulator_init_data { struct device *supply_regulator_dev; // 父regulator的指針 struct regulation_constraints constraints; int num_consumer_supplies; struct regulator_consumer_supply *consumer_supplies; // 負(fù)責(zé)供電的設(shè)備數(shù)組
int (*regulator_init)(void *driver_data); // 初始化函數(shù),在regulator_register被調(diào)用 void *driver_data; };
其它結(jié)構(gòu)體自己可以看看~如
struct regulator
struct regulation_constraints struct regulator_init_data,用于初始化 struct regulator_consumer_supply ----->consumer信息
struct regulator_desc
struct regulator_map ........................................ ............................................ 先說明下兩具在regulator的core中有兩個(gè)關(guān)鍵的全局變量鏈表: regulator_list 每注冊一個(gè)regulator都會(huì)掛到這里 regulator_map_list 每一個(gè)regulator都會(huì)為多個(gè)consumer供電,此表為掛consumer
regulator注冊過程是通過platform平臺(tái)注冊,當(dāng)然一個(gè)電源管理芯片可以供幾十個(gè)設(shè)備供電,所以不可能每個(gè)regulator一個(gè)驅(qū)動(dòng)文件,它們是通過,在電源管理芯片驅(qū)動(dòng)中一塊注冊到regulato的core中。 對于電源管理芯片驅(qū)動(dòng)的注冊則通過I2C注冊的。接下來以中星微方案過下, 首先,在平臺(tái)設(shè)備文件中,有關(guān)struct regulator_init_data XX定義~ 如: …......................... static struct regulator_init_data va7882_ldo13_data = { .constraints = { .name = "LDO13-HDMI1V2", //Default: 1.5V , Powered By DCDC5, C-class .min_uV = 1200000, .max_uV = 1800000, .apply_uV = 1, // TEMP_ON .valid_ops_mask = REGULATOR_CHANGE_VOLTAGE | REGULATOR_CHANGE_STATUS | REGULATOR_CHANGE_MODE, .initial_mode = REGULATOR_MODE_NORMAL, .valid_modes_mask = REGULATOR_MODE_NORMAL | REGULATOR_MODE_STANDBY, }, .supply_regulator = supply_regulator_name_arrary[ID_VA7882_LDO13], .num_consumer_supplies = 2, .consumer_supplies = (struct regulator_consumer_supply []) { { .supply = regulator_name_arrary[ID_VA7882_LDO13][0] }, { .supply = regulator_name_arrary[ID_VA7882_LDO13][1] }, { .supply = regulator_name_arrary[ID_VA7882_LDO13][2] }, }, }; …........................................ 其實(shí)這些結(jié)構(gòu)體又會(huì)被同一文件中的自定義文件初始化函數(shù) v8_va7882_init調(diào)用,其實(shí)就是 va7882_register_regulator---->為每個(gè)regulator分配對應(yīng)的struct platform_device---->再platform_device_add 那platform_driver在哪? static struct platform_driver va7882_regulator_driver = { .driver = { .name = "va7882-regulator", .owner = THIS_MODULE, }, .probe = va7882_regulator_probe, .remove = __exit_p(va7882_regulator_remove), .suspend = va7882_regulator_suspend, //可見休眠喚醒是使用同一個(gè),
.resume = va7882_regulator_resume, .shutdown = va7882_regulator_shutdown, };
這個(gè)platform_driver是每個(gè)regulator共用的的,因?yàn)?span style="font-family:Times New Roman,serif; word-wrap:normal; word-break:normal">name都是" 在這個(gè)platform_driver中probe中就干了一件事regulator_register,從而獲得regulator_dev。
接下來分析下regulator_register注冊 Regulator的注冊由regulator_register完成。 一般來說,為了添加regulator_dev,需要實(shí)現(xiàn)一個(gè)設(shè)備驅(qū)動(dòng)程序,以及在板子的設(shè)備列表中增加一個(gè)該驅(qū)動(dòng)對應(yīng)的設(shè)備(比如platform_device)。在這個(gè)設(shè)備的struct device->platform_data域,需要設(shè)置regulator_init結(jié)構(gòu),填寫該regulator的相關(guān)信息。另外,還需要定義一個(gè)regulator_desc結(jié)構(gòu)。這樣,在這個(gè)物理設(shè)備的驅(qū)動(dòng)程序中,就可以通過regulator_register函數(shù)登記生成一個(gè)regulator_dev。 struct regulator_dev *regulator_register(struct regulator_desc *regulator_desc, struct device *dev, void *driver_data) struct regulator_init_data *init_data = dev->platform_data;// 得到init_data // 完整性檢查 … // 分配regulator_dev結(jié)構(gòu) struct regulator_dev *rdev = kzalloc (sizeof(struct regulator_dev), GFP_KERNEL); // 初始化regulator_dev結(jié)構(gòu) … // 執(zhí)行regulator_init,該函數(shù)中實(shí)現(xiàn)regulator代表的硬件設(shè)備的初始化 if (init_data->regulator_init) ret = init_data->regulator_init(rdev->reg_data); rdev->dev.class = ®ulator_class; // 指定class為regulator_class rdev->dev.parent = dev; device_register(&rdev->dev); // 注冊設(shè)備 // 設(shè)置constraints,其中可能會(huì)包括供電狀態(tài)的初始化(設(shè)置初始電壓,enable/disable等等) set_machine_constraints(rdev, &init_data->constraints); add_regulator_attributes (rdev); // 如果此regulator有父regulator,設(shè)置父regulator if (init_data->supply_regulator_dev) { ret = set_supply(rdev, dev_get_drvdata(init_data->supply_regulator_dev)); if (ret < 0) goto scrub; } // 設(shè)置此regulator與其負(fù)責(zé)供電的設(shè)備之間的聯(lián)系 for (i = 0; i < init_data->num_consumer_supplies; i++) ret = set_consumer_device_supply(rdev, init_data->consumer_supplies[i].dev, init_data->consumer_supplies[i].supply); // 將regulator加入一個(gè)鏈表,該鏈表包含所有regulator list_add(&rdev->list, ®ulator_list); ….............................
那個(gè)regulator 根據(jù)在regulator_list中用init_data->supply_regulator來匹配 匹配成功用set_supply()來設(shè)置注冊的regulator是由那個(gè)regulator供電,rdev->supply = supply_rdev; list_add(&rdev->slist, &supply_rdev->supply_list); 多個(gè)consumer用set_consumer_device_supply(),先檢查 list_for_each_entry(node, ®ulator_map_list, list) 后添加 list_add(&node->list, ®ulator_map_list);當(dāng)然node已經(jīng)在 node->regulator = rdev; node->supply = supply; 形成 對于每一個(gè)regulator_dev—comsumer_dev的配對 最后在把regulator通過list_add(&rdev->list, ®ulator_list);加到 regulator_list鏈表中。
三.設(shè)備使用regulator過程
在設(shè)備驅(qū)動(dòng)使用regulator對其驅(qū)動(dòng)的設(shè)備供電時(shí),首先要確保設(shè)備與對應(yīng)regulator之間的匹配關(guān)系已經(jīng)被登記到regulator框架中。 之后,設(shè)備驅(qū)動(dòng)通過regulator_get函數(shù)得到regulator結(jié)構(gòu),此函數(shù)通過前文所述regulator_map_list找到對應(yīng)regulator_dev,再生成regulator結(jié)構(gòu)給用戶使用。 通過regulator_enable / regulator_disable打開、關(guān)閉regulator,這兩個(gè)函數(shù)最終都是調(diào)用struct regulator_ops里的對應(yīng)成員。 除此之外,還有regualtor_set_voltage / regulator_get_voltage等等。 Regulator能夠支持的所有功能列表都在struct regulator_ops中定義,具體可參考代碼中的注釋。 struct regulator_ops {
int (*set_voltage) (struct regulator_dev *, int min_uV, int max_uV); int (*get_voltage) (struct regulator_dev *);
int (*set_current_limit) (struct regulator_dev *, int min_uA, int max_uA); int (*get_current_limit) (struct regulator_dev *);
int (*enable) (struct regulator_dev *); int (*disable) (struct regulator_dev *); int (*is_enabled) (struct regulator_dev *);
int (*set_mode) (struct regulator_dev *, unsigned int mode); unsigned int (*get_mode) (struct regulator_dev *);
unsigned int (*get_optimum_mode) (struct regulator_dev *, int input_uV, int output_uV, int load_uA);
int (*set_suspend_voltage) (struct regulator_dev *, int uV);
int (*set_suspend_enable) (struct regulator_dev *); int (*set_suspend_disable) (struct regulator_dev *);
int (*set_suspend_mode) (struct regulator_dev *, unsigned int mode); };
接下來我就以中星型的HDMI驅(qū)動(dòng)使用regulator過一遍。 vc088x_hdmi.c文件: HDMI驅(qū)動(dòng)也是通過platform平臺(tái)注冊上去,所以在platform_driver的probe中有這個(gè)句 ret = v8hdmi_pwr_get(&pdev->dev); regulator_get(dev,id); _regulator_get(dev, id, 0); { …........ …........... if (dev) devname = dev_name(dev); list_for_each_entry(map, ®ulator_map_list, list) {
if (map->dev_name &&(!devname || strcmp(map->dev_name, devname))) continue; if (strcmp(map->supply, id) == 0) {//查找配對 rdev = map->regulator; goto found; } } …..................... ….......................... //這個(gè)用于在sys目錄下建立對應(yīng)的regulator文件,用于用戶空間操作 regulator = create_regulator(rdev, dev, id); //regulator -->struct regulator …............................. return regulator; }
返回的regulator會(huì)賦給全局變量,如 hdmi_core_consumer = regulator,//這只是例子,不同方案處理不一樣。 在恰當(dāng)?shù)臅r(shí)候使能它,如 ret = v8hdmi_pwr_enable(); regulator_enable(hdmi_io_consumer); struct regulator_dev *rdev = regulator->rdev; ret = _regulator_enable(rdev); …................. if (rdev->use_count == 0) {
if (rdev->supply) { mutex_lock(&rdev->supply->mutex); ret = _regulator_enable(rdev->supply);//使能父regulator mutex_unlock(&rdev->supply->mutex); If (ret < 0) { rdev_err(rdev, "failed to enable: %d\n", ret); return ret; } } } …............................... ret = rdev->desc->ops->enable(rdev);//調(diào)用真正使能操作. …....................... 使能函數(shù)到此結(jié)束.
總的來看,使用也是通過regulator_get()-->regulator_enable()就可以了 想關(guān)時(shí),regulator_disable()--->regulator_put(),反操作~
其實(shí)我疑惑是真正操作電源管理芯片那些操作,存放在struct regulator_ops 結(jié)構(gòu)體內(nèi) 而這個(gè)結(jié)構(gòu)體包含在于struct regulator_desc內(nèi),這個(gè)結(jié)構(gòu)體,在執(zhí)行注冊regulator時(shí),使用到,被賦到regulator_dev-->desc中~ 對于struct regulator_ops中的操作方法,就涉及到電源芯片驅(qū)動(dòng),下面是va7882的操作方法 static struct regulator_ops va7882_dcdc_ops = { .set_voltage = va7882_dcdc_set_voltage, .get_voltage = va7882_dcdc_get_voltage, .list_voltage = va7882_dcdc_list_voltage, .enable = va7882_dcdc_enable, .disable = va7882_dcdc_disable, .is_enabled = va7882_dcdc_is_enabled, .get_mode = va7882_dcdc_get_mode, .set_mode = va7882_dcdc_set_mode, .get_optimum_mode = va7882_dcdc_get_optimum_mode, .set_suspend_voltage = va7882_dcdc_set_suspend_voltage, .set_suspend_enable = va7882_dcdc_set_suspend_enable, .set_suspend_disable = va7882_dcdc_set_suspend_disable, .set_suspend_mode = va7882_dcdc_set_suspend_mode, .enable_time = va7882_enable_time, };
接后面再討論電源管理芯片驅(qū)動(dòng),還有像v8_va7882_init函數(shù)來初始化及注冊各種regulator,那誰去調(diào)用這個(gè)初始函數(shù)呢?怎么的調(diào)用流程呢?這些都在電源管理芯片驅(qū)動(dòng)會(huì)講到! |
|