カーネル - レギュレータ

、レギュレータサブシステム共通のデータ構造

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;                             
    bool continuous_voltage_range;      
    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;

    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 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 enable_time;

    unsigned int off_on_delay;

    unsigned int (*of_map_mode)(unsigned int mode);                                                                                                                                                
};

struct regulator_config {
    struct device *dev;
    const struct regulator_init_data *init_data;
    void *driver_data;
    struct device_node *of_node;
    struct regmap *regmap;

    bool ena_gpio_initialized;
    int ena_gpio;
    unsigned int ena_gpio_invert:1;
    unsigned int ena_gpio_flags;
};
  • 二つの構造パラメータに必要な登録regulator_register
struct regulator_dev {
    const struct regulator_desc *desc;
    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 */

    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 */
    const char *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;
    unsigned int ena_gpio_state:1;

    /* time when this regulator was disabled last time */
    unsigned long last_off_jiffy;
};
  • 登録regulator_registerのregulator_desc、最終的に生成された構造regulator_config

登録されたうちの2つ、レギュレータ

struct regulator_dev *
regulator_register(const struct regulator_desc *regulator_desc,
           const struct regulator_config *cfg)
{
    ......
    
    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);
    }

    ......
    
    /* 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)) {
        ret = regulator_ena_gpio_request(rdev, config);
        if (ret != 0) {
            rdev_err(rdev, "Failed to request enable GPIO%d: %d\n",
                 config->ena_gpio, ret);
            goto wash;
        }
    }

    /* set regulator constraints */
    if (init_data)
        constraints = &init_data->constraints;

    ret = set_machine_constraints(rdev, constraints);
    if (ret < 0)
        goto scrub;

    if (init_data && init_data->supply_regulator)
        rdev->supply_name = init_data->supply_regulator;
    else if (regulator_desc->supply_name)
        rdev->supply_name = regulator_desc->supply_name;

    /* add consumers devices */
    if (init_data) {
        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) {
                dev_err(dev, "Failed to set supply %s\n",
                    init_data->consumer_supplies[i].supply);
                goto unset_supplies;
            }
        }
    }

    list_add(&rdev->list, &regulator_list);

    rdev_init_debugfs(rdev);

    ......
}
  • 分布とregulator_dev機器を作成し、regulator_listを一覧表示する登録
  • set_consumer_device_supply登録consumer_suppliesを呼び出し
  • コールrdev_init_debugfsはdebugfsのインターフェイスを作成します

レギュレータへの第三に、アクセス

struct regulator *regulator_get(struct device *dev, const char *id)
{
    return _regulator_get(dev, id, false, true);
}
EXPORT_SYMBOL_GPL(regulator_get);

/* Internal regulator request function */
static struct regulator *_regulator_get(struct device *dev, const char *id,
                    bool exclusive, bool allow_dummy)
{
    ......

    rdev = regulator_dev_lookup(dev, id, &ret);
    if (rdev)
        goto found;

   ......

    /*
     * Assume that a regulator is physically present and enabled
     * even if it isn't hooked up and just provide a dummy.
     */
    if (have_full_constraints() && allow_dummy) {
        pr_warn("%s supply %s not found, using dummy regulator\n",
            devname, id);

        rdev = dummy_regulator_rdev;
        goto found;
    /* Don't log an error when called from regulator_get_optional() */
    } else if (!have_full_constraints() || exclusive) {
        dev_warn(dev, "dummy supplies not allowed\n");
    }

    mutex_unlock(&regulator_list_mutex);
    return regulator;

found:
    if (rdev->exclusive) {
        regulator = ERR_PTR(-EPERM);
        goto out;
    }

    if (exclusive && rdev->open_count) {
        regulator = ERR_PTR(-EBUSY);
        goto out;
    }

    ret = regulator_resolve_supply(rdev);
    if (ret < 0) {
        regulator = ERR_PTR(ret);
        goto out;
    }

    if (!try_module_get(rdev->owner))
        goto out;

    regulator = create_regulator(rdev, dev, id);
    if (regulator == NULL) {
        regulator = ERR_PTR(-ENOMEM);
        module_put(rdev->owner);
        goto out;
    }

    rdev->open_count++;
    if (exclusive) {
        rdev->exclusive = 1;

        ret = _regulator_is_enabled(rdev);
        if (ret > 0)
            rdev->use_count = 1;
        else
            rdev->use_count = 0;
    }

out:
    mutex_unlock(&regulator_list_mutex);

    return regulator;
}
  • レギュレータを取得するために、間接的に_regulator_get呼び出しregulator_get
  • _regulator_get見つかりませんリターンがdummy_regulator_rdev場合create_regulatorと呼ばれるレギュレータを作成することが分かった場合、RDEVを見つけることregulator_dev_lookup呼び出します
static struct regulator_dev *regulator_dev_lookup(struct device *dev,
                          const char *supply,
                          int *ret)
{
    struct regulator_dev *r;
    struct device_node *node;
    struct regulator_map *map;
    const char *devname = NULL;

    regulator_supply_alias(&dev, &supply);

    /* first do a dt based lookup */
    if (dev && dev->of_node) {
        node = of_get_regulator(dev, supply);
        if (node) {
            list_for_each_entry(r, &regulator_list, list)
                if (r->dev.parent &&
                    node == r->dev.of_node)
                    return r;
            *ret = -EPROBE_DEFER;
            return NULL;
        } else {
            /*
             * If we couldn't even get the node then it's
             * not just that the device didn't register
             * yet, there's no node and we'll never
             * succeed.
             */
            *ret = -ENODEV;
        }
    }

    /* if not found, try doing it non-dt way */
    if (dev)
        devname = dev_name(dev);

    list_for_each_entry(r, &regulator_list, list)
        if (strcmp(rdev_get_name(r), supply) == 0)
            return r;

    list_for_each_entry(map, &regulator_map_list, list) {
        /* If the mapping has a device set up it must match */
        if (map->dev_name &&
            (!devname || strcmp(map->dev_name, devname)))
            continue;

        if (strcmp(map->supply, supply) == 0)
            return map->regulator;
    }


    return NULL;
}
  • まず、デバイスツリーを経由してrdevを見つけるために
  • 見つからない場合は、初期化を登録regulator_rdevとき、regulator_map_listを通じてrdev.regulator_map_listを探します
static struct regulator *create_regulator(struct regulator_dev *rdev,
                      struct device *dev,
                      const char *supply_name)
{
    struct regulator *regulator;
    char buf[REG_STR_SIZE];
    int err, size;

    regulator = kzalloc(sizeof(*regulator), GFP_KERNEL);
    if (regulator == NULL)
        return NULL;

    mutex_lock(&rdev->mutex);
    regulator->rdev = rdev;
    list_add(&regulator->list, &rdev->consumer_list);

    ......

    regulator->debugfs = debugfs_create_dir(regulator->supply_name,
                        rdev->debugfs);
    if (!regulator->debugfs) {
        rdev_warn(rdev, "Failed to create debugfs directory\n");
    } else {
        debugfs_create_u32("uA_load", 0444, regulator->debugfs,
                   &regulator->uA_load);
        debugfs_create_u32("min_uV", 0444, regulator->debugfs,
                   &regulator->min_uV);
        debugfs_create_u32("max_uV", 0444, regulator->debugfs,
                   &regulator->max_uV);
    }

    ......
}
  • レギュレータを作成し、RDEVのconsumer_listに登録
  • レギュレータ対応debugfsのデバッグインタフェースを作成します

おすすめ

転載: www.cnblogs.com/qzhang1535/p/10995943.html