regulator_dev代表一个regulator设备
/*
* struct regulator_dev
*
* Voltage / Current regulator class device. One for each
* regulator.
*
* This should *not* be used directly by anything except the regulator
* core and notification injection (which should take the mutex and do
* no other direct access).
*/struct regulator_dev {
conststruct regulator_desc *desc;//描述符,包括regulator的名称、ID、regulator_ops等int exclusive;
u32 use_count; // 使用计数
u32 open_count;
u32 bypass_count;
/* lists we belong to */struct list_head list; /* list of all regulators *//* lists we own */struct list_head consumer_list; /* consumers we supply */// 此regulator负责供电的设备列表struct blocking_notifier_head notifier;
struct mutex mutex; /* consumer lock */struct module *owner;
struct device dev;
struct regulation_constraints *constraints;
struct regulator *supply; /* for tree */constchar *supply_name;
struct regmap *regmap;
struct delayed_work disable_work;
int deferred_disables;
void *reg_data; /* regulator_dev data */struct dentry *debugfs;
struct regulator_enable_gpio *ena_pin;
unsignedint ena_gpio_state:1;
/* time when this regulator was disabled last time */unsignedlong last_off_jiffy;
};
regulator_init_data在初始化时使用,用来建立父子regulator、受电模块之间的树状结构,以及一些regulator的基本参数。
/**
* struct regulator_init_data - regulator platform initialisation data.
*
* Initialisation constraints, our supply and consumers supplies.
*
* @supply_regulator: Parent regulator. Specified using the regulator name
* as it appears in the name field in sysfs, which can
* be explicitly set using the constraints field 'name'.
*
* @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_data: Data passed to regulator_init.
*/
struct regulator_init_data {
constchar *supply_regulator; /* or NULL for system supply */
struct regulation_constraints constraints;
int num_consumer_supplies;
struct regulator_consumer_supply *consumer_supplies;
/* optional regulator machine specific init */int (*regulator_init)(void *driver_data);
void *driver_data; /* core does not touch this */
};
regulator_desc 结构体
/**
* struct regulator_desc - Static regulator descriptor
*
* Each regulator registered with the core is described with a
* structure of this type and a struct regulator_config. This
* structure contains the non-varying parts of the regulator
* description.
*
* @name: Identifying name for the regulator.
* @supply_name: Identifying the regulator supply
* @of_match: Name used to identify regulator in DT.
* @regulators_node: Name of node containing regulator definitions in DT.
* @of_parse_cb: Optional callback called only if of_match is present.
* Will be called foreach regulator parsed from DT, during
* init_data parsing.
* The regulator_config passed as argument to the callback will
* be a copy of config passed to regulator_register, valid only
* for this particular call. Callback may freely change the
* config but it cannot store it for later usage.
* Callback should return0 on success or negative ERRNO
* indicating failure.
* @id: Numerical identifier for the regulator.
* @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.
*
* @continuous_voltage_range: Indicates if the regulator can set any
* voltage within constrains range.
* @n_voltages: Number of selectors available for ops.list_voltage().
*
* @min_uV: Voltage given by the lowest selector (if linear mapping)
* @uV_step: Voltage increase with each selector (if linear mapping)
* @linear_min_sel: Minimal selector for starting linear mapping
* @fixed_uV: Fixed voltage of rails.
* @ramp_delay: Time to settle down after voltage change (unit: uV/us)
* @min_dropout_uV: The minimum dropout voltage this regulator can handle
* @linear_ranges: A constant table of possible voltage ranges.
* @n_linear_ranges: Number of entries in the @linear_ranges table.
* @volt_table: Voltage mapping table (if table based mapping)
*
* @vsel_reg: Register for selector when using regulator_regmap_X_voltage_
* @vsel_mask: Mask for register bitfield used for selector
* @csel_reg: Register for TPS65218 LS3 current regulator
* @csel_mask: Mask for TPS65218 LS3 current regulator
* @apply_reg: Register for initiate voltage change on the output when
* using regulator_set_voltage_sel_regmap
* @apply_bit: Register bitfield used for initiate voltage change on the
* output when using regulator_set_voltage_sel_regmap
* @enable_reg: Register for control when using regmap enable/disable ops
* @enable_mask: Mask for control when using regmap enable/disable ops
* @enable_val: Enabling value for control when using regmap enable/disable ops
* @disable_val: Disabling value for control when using regmap enable/disable ops
* @enable_is_inverted: A flag to indicate set enable_mask bits to disable
* when using regulator_enable_regmap and friends APIs.
* @bypass_reg: Register for control when using regmap set_bypass
* @bypass_mask: Mask for control when using regmap set_bypass
* @bypass_val_on: Enabling value for control when using regmap set_bypass
* @bypass_val_off: Disabling value for control when using regmap set_bypass
* @active_discharge_off: Enabling value for control when using regmap
* set_active_discharge
* @active_discharge_on: Disabling value for control when using regmap
* set_active_discharge
* @active_discharge_mask: Mask for control when using regmap
* set_active_discharge
* @active_discharge_reg: Register for control when using regmap
* set_active_discharge
*
* @enable_time: Time taken for initial enable of regulator (in uS).
* @off_on_delay: guard time (in uS), before re-enabling a regulator
*
* @of_map_mode: Maps a hardware mode defined in a DeviceTree to a standard mode
*/
struct regulator_desc {
const char *name;
const char *supply_name;
const char *of_match;
const char *regulators_node;
int (*of_parse_cb)(struct device_node *,
const struct regulator_desc *,
struct regulator_config *);
int id;
unsigned int continuous_voltage_range:1;
unsigned n_voltages;
const struct regulator_ops *ops;
int irq;
enum regulator_type type;
struct module *owner;
unsigned int min_uV;
unsigned int uV_step;
unsigned int linear_min_sel;
int fixed_uV;
unsigned int ramp_delay;
int min_dropout_uV;
const struct regulator_linear_range *linear_ranges;
int n_linear_ranges;
const unsigned int*volt_table;
unsigned int vsel_reg;
unsigned int vsel_mask;
unsigned int csel_reg;
unsigned int csel_mask;
unsigned int apply_reg;
unsigned int apply_bit;
unsigned int enable_reg;
unsigned int enable_mask;
unsigned int enable_val;
unsigned int disable_val;
bool enable_is_inverted;
unsigned int bypass_reg;
unsigned int bypass_mask;
unsigned int bypass_val_on;
unsigned int bypass_val_off;
unsigned int active_discharge_on;
unsigned int active_discharge_off;
unsigned int active_discharge_mask;
unsigned int active_discharge_reg;
unsigned int enable_time;
unsigned int off_on_delay;
unsigned int (*of_map_mode)(unsigned int mode);
};
其它结构体 struct regulator设备驱动直接操作的结构体 struct regulation_constraints regulator限制范围,用于初始化 struct regulator_consumer_supply regulator的consumer信息 struct regulator_map 为consumers与regulator对应表 struct regulator_config regulator的动态运行信息 struct regulator_opsregulator的操作函数集合
注册regulator
通过regulator_register函数登记生成一个regulator_dev/**
* regulator_register - register regulator
* @regulator_desc: regulator to register
* @cfg: runtime configuration for regulator
*
* Called by regulator drivers to register a regulator.
* Returns a valid pointer to struct regulator_dev on success
* or an ERR_PTR() on error.
*/
struct regulator_dev *
regulator_register(const struct regulator_desc *regulator_desc,
const struct regulator_config *cfg)
{
const struct regulation_constraints *constraints =NULL;
const struct regulator_init_data *init_data;
struct regulator_config *config =NULL;
static atomic_t regulator_no = ATOMIC_INIT(-1);
struct regulator_dev *rdev;
struct device *dev;
int ret, i;
if (regulator_desc ==NULL|| cfg ==NULL)
return ERR_PTR(-EINVAL);
dev = cfg->dev;
WARN_ON(!dev);
if (regulator_desc->name ==NULL|| regulator_desc->ops ==NULL)
return ERR_PTR(-EINVAL);
if (regulator_desc->type!= REGULATOR_VOLTAGE &&
regulator_desc->type!= REGULATOR_CURRENT)
return ERR_PTR(-EINVAL);
/* Only one of each should be implemented */
WARN_ON(regulator_desc->ops->get_voltage &&
regulator_desc->ops->get_voltage_sel);
WARN_ON(regulator_desc->ops->set_voltage &&
regulator_desc->ops->set_voltage_sel);
/* If we're using selectors we must implement list_voltage. */if (regulator_desc->ops->get_voltage_sel &&!regulator_desc->ops->list_voltage) {
return ERR_PTR(-EINVAL);
}
if (regulator_desc->ops->set_voltage_sel &&!regulator_desc->ops->list_voltage) {
return ERR_PTR(-EINVAL);
}
rdev = kzalloc(sizeof(struct regulator_dev), GFP_KERNEL);
if (rdev ==NULL)
return ERR_PTR(-ENOMEM);
/*
* Duplicate the config so the driver could override it after
* parsing init data.
*/
config = kmemdup(cfg, sizeof(*cfg), GFP_KERNEL);
if (config ==NULL) {
kfree(rdev);
return ERR_PTR(-ENOMEM);
}
init_data = regulator_of_get_init_data(dev, regulator_desc, config,
&rdev->dev.of_node);
if (!init_data) {
init_data = config->init_data;
rdev->dev.of_node = of_node_get(config->of_node);
}
mutex_init(&rdev->mutex);
rdev->reg_data = config->driver_data;
rdev->owner = regulator_desc->owner;
rdev->desc = regulator_desc;
if (config->regmap)
rdev->regmap = config->regmap;
elseif (dev_get_regmap(dev, NULL))
rdev->regmap = dev_get_regmap(dev, NULL);
elseif (dev->parent)
rdev->regmap = dev_get_regmap(dev->parent, NULL);
INIT_LIST_HEAD(&rdev->consumer_list);
INIT_LIST_HEAD(&rdev->list);
BLOCKING_INIT_NOTIFIER_HEAD(&rdev->notifier);
INIT_DELAYED_WORK(&rdev->disable_work, regulator_disable_work);
/* preform any regulator specific init */if (init_data && init_data->regulator_init) {
ret = init_data->regulator_init(rdev->reg_data);
if (ret <0)
goto clean;
}
if ((config->ena_gpio || config->ena_gpio_initialized) &&
gpio_is_valid(config->ena_gpio)) {
mutex_lock(®ulator_list_mutex);
ret = regulator_ena_gpio_request(rdev, config);
mutex_unlock(®ulator_list_mutex);
if (ret !=0) {
rdev_err(rdev, "Failed to request enable GPIO%d: %d
",
config->ena_gpio, ret);
goto clean;
}
}
/* register with sysfs */
rdev->dev.class =®ulator_class;
rdev->dev.parent= dev;
dev_set_name(&rdev->dev, "regulator.%lu",
(unsigned long) atomic_inc_return(®ulator_no));
/* set regulator constraints */if (init_data)
constraints =&init_data->constraints;
if (init_data && init_data->supply_regulator)
rdev->supply_name = init_data->supply_regulator;
elseif (regulator_desc->supply_name)
rdev->supply_name = regulator_desc->supply_name;
/*
* Attempt to resolve the regulator supply, if specified,
* but don't return an error if we fail because we will try
* to resolve it again later as more regulators are added.
*/if (regulator_resolve_supply(rdev))
rdev_dbg(rdev, "unable to resolve supply
");
ret = set_machine_constraints(rdev, constraints);
if (ret <0)
goto wash;
/* add consumers devices */if (init_data) {
mutex_lock(®ulator_list_mutex);
for (i =0; i < init_data->num_consumer_supplies; i++) {
ret = set_consumer_device_supply(rdev,
init_data->consumer_supplies[i].dev_name,
init_data->consumer_supplies[i].supply);
if (ret < 0) {
mutex_unlock(®ulator_list_mutex);
dev_err(dev, "Failed to set supply %s
",
init_data->consumer_supplies[i].supply);
goto unset_supplies;
}
}
mutex_unlock(®ulator_list_mutex);
}
ret = device_register(&rdev->dev);
if (ret != 0) {
put_device(&rdev->dev);
goto unset_supplies;
}
dev_set_drvdata(&rdev->dev, rdev);
rdev_init_debugfs(rdev);
/* try to resolve regulators supply since a new one was registered */
class_for_each_device(®ulator_class, NULL, NULL,
regulator_register_resolve_supply);
kfree(config);
return rdev;
unset_supplies:
mutex_lock(®ulator_list_mutex);
unset_regulator_supplies(rdev);
mutex_unlock(®ulator_list_mutex);
wash:
kfree(rdev->constraints);
mutex_lock(®ulator_list_mutex);
regulator_ena_gpio_free(rdev);
mutex_unlock(®ulator_list_mutex);
clean:
kfree(rdev);
kfree(config);
return ERR_PTR(ret);
}
set_consumer_device_supply函数用于登记regulator_dev与comsumer_dev(regulator负责供电的设备)之间的对应关系。对于每一个regulator_dev—comsumer_dev的配对,都会有一个regulator_map结构,这些结构会被加入到全局链表regulator_map_list中。
在设备驱动使用regulator对其驱动的设备供电时,需要首先保证设备与对应regulator之间的匹配关系已经被登记到regulator框架中。
设备驱动通过regulator_get函数得到regulator结构,此函数通过regulator_map_list找到对应regulator_dev,再生成regulator结构给用户使用。
通过regulator_enable/regulator_disable打开、关闭regulator,这两个函数最终都是调用struct regulator_ops里的对应成员。
除此之外,还有regualtor_set_voltage / regulator_get_voltage等等。