devm_regulator_get

设备树中配置资源结点,然后通过供应商接口调用devm_regulator_get来获取资源

/**
 * devm_regulator_get - Resource managed regulator_get()
 * @dev: device for regulator "consumer"
 * @id: Supply name or regulator ID.
 *
 * Managed regulator_get(). Regulators returned from this function are
 * automatically regulator_put() on driver detach. See regulator_get() for more
 * information.
 */
获取通过regulator_get()管理的资源
该函数返回的regulators在driver detach的时候自动regulator_put()
struct regulator *devm_regulator_get(struct device *dev, const char *id)
{
	return _devm_regulator_get(dev, id, NORMAL_GET);
}

static struct regulator *_devm_regulator_get(struct device *dev, const char *id,  int get_type)
{
	struct regulator **ptr, *regulator;

	ptr = devres_alloc(devm_regulator_release, sizeof(*ptr), GFP_KERNEL);
	if (!ptr)
		return ERR_PTR(-ENOMEM);

	regulator = _regulator_get(dev, id, get_type);
	if (!IS_ERR(regulator)) {
		*ptr = regulator;
		devres_add(dev, ptr);
	} else {
		devres_free(ptr);
	}

	return regulator;
}
struct regulator *_regulator_get(struct device *dev, const char *id,
				 enum regulator_get_type get_type)
{
	struct regulator_dev *rdev;
	struct regulator *regulator;
	const char *devname = dev ? dev_name(dev) : "deviceless";
	int ret;

	if (get_type >= MAX_GET_TYPE) {
		dev_err(dev, "invalid type %d in %s\n", get_type, __func__);
		return ERR_PTR(-EINVAL);
	}

	if (id == NULL) {
		pr_err("get() with no identifier\n");
		return ERR_PTR(-EINVAL);
	}

	rdev = regulator_dev_lookup(dev, id);
	if (IS_ERR(rdev)) {
		ret = PTR_ERR(rdev);

		/*
		 * If regulator_dev_lookup() fails with error other
		 * than -ENODEV our job here is done, we simply return it.
		 */
		if (ret != -ENODEV)
			return ERR_PTR(ret);

		if (!have_full_constraints()) {
			dev_warn(dev, "incomplete constraints, dummy supplies not allowed\n");
			return ERR_PTR(-ENODEV);
		}

		switch (get_type) {
		case NORMAL_GET:
			/*
			 * Assume that a regulator is physically present and
			 * enabled, even if it isn't hooked up, and just
			 * provide a dummy.
			 */
			dev_warn(dev,
				 "%s supply %s not found, using dummy regulator\n",
				 devname, id);
			rdev = dummy_regulator_rdev;
			get_device(&rdev->dev);
			break;

		case EXCLUSIVE_GET:
			dev_warn(dev,
				 "dummy supplies not allowed for exclusive requests\n");
			/* fall through */

		default:
			return ERR_PTR(-ENODEV);
		}
	}

	if (rdev->exclusive) {
		regulator = ERR_PTR(-EPERM);
		put_device(&rdev->dev);
		return regulator;
	}

	if (get_type == EXCLUSIVE_GET && rdev->open_count) {
		regulator = ERR_PTR(-EBUSY);
		put_device(&rdev->dev);
		return regulator;
	}

	ret = regulator_resolve_supply(rdev);
	if (ret < 0) {
		regulator = ERR_PTR(ret);
		put_device(&rdev->dev);
		return regulator;
	}

	if (!try_module_get(rdev->owner)) {
		regulator = ERR_PTR(-EPROBE_DEFER);
		put_device(&rdev->dev);
		return regulator;
	}

	//通过找到的rdev来创建regulator
	regulator = create_regulator(rdev, dev, id);
	if (regulator == NULL) {
		regulator = ERR_PTR(-ENOMEM);
		module_put(rdev->owner);
		put_device(&rdev->dev);
		return regulator;
	}

	//设备的引用计数++
	rdev->open_count++;
	if (get_type == EXCLUSIVE_GET) {
		rdev->exclusive = 1;

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

	//将传入的dev挂载到rdev->dev链表上
	device_link_add(dev, &rdev->dev, DL_FLAG_STATELESS);

	return regulator;
}
/**
 * regulator_dev_lookup - lookup a regulator device.
 * @dev: device for regulator "consumer".
 * @supply: Supply name or regulator ID.
 *
 * If successful, returns a struct regulator_dev that corresponds to the name
 * @supply and with the embedded struct device refcount incremented by one.
 * The refcount must be dropped by calling put_device().
 * On failure one of the following ERR-PTR-encoded values is returned:
 * -ENODEV if lookup fails permanently, -EPROBE_DEFER if lookup could succeed
 * in the future.
 */
static struct regulator_dev *regulator_dev_lookup(struct device *dev,
						  const char *supply)
{
	struct regulator_dev *r = NULL;
	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) {
			r = of_find_regulator_by_node(node);
			if (r)
				return r;

			/*
			 * We have a node, but there is no device.
			 * assume it has not registered yet.
			 */
			return ERR_PTR(-EPROBE_DEFER);
		}
	}

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

	mutex_lock(®ulator_list_mutex);
	list_for_each_entry(map, ®ulator_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 &&
		    get_device(&map->regulator->dev)) {
			r = map->regulator;
			break;
		}
	}
	mutex_unlock(®ulator_list_mutex);

	if (r)
		return r;

	r = regulator_lookup_by_name(supply);
	if (r)
		return r;

	return ERR_PTR(-ENODEV);
}

你可能感兴趣的:(kernel)