今天在调试一个外设时,需要用vgp1控制,需要设置3.3v,一直没有输出来。6580 8.1平台tp默认是用vgp1控制的,用下面的代码是可以输出2.8v的
下面是ft的tp驱动部分
int fts_power_init(void)
{int ret;/*set TP volt*/tpd->reg = regulator_get(tpd->tpd_dev, "vtouch");ret = regulator_set_voltage(tpd->reg, 2800000, 2800000);if (ret != 0) {FTS_ERROR("[POWER]Failed to set voltage of regulator,ret=%d!", ret);return ret;}ret = regulator_enable(tpd->reg);if (ret != 0) {FTS_ERROR("[POWER]Fail to enable regulator when init,ret=%d!", ret);return ret;}return 0;
}
kernel-3.18\arch\arm\boot\dts\mt6580.dts
touch: touch@0 {compatible = "mediatek,touch";vtouch-supply = <&mt_pmic_vgp1_ldo_reg>;};
为了保持代码的可移植性和方便查阅问题,没有采取在tp里面操作这个电压,而是在对应驱动里面去操作vgp1
按照tp的方法,加入如下代码:
kernel-3.18\arch\arm\boot\dts\mt6580.dts
breathled: breathled {compatible = "mediatek,breathled";mx9016-supply = <&mt_pmic_vgp1_ldo_reg>; };
在对应驱动操作电压部分代码
static int breathled_probe(struct platform_device *pdev)
{struct regulator *reg_mx9016;//zxw open vgp1 注意要引入头文件#include <linux/regulator/consumer.h>,不然编译会报错reg_mx9016 = regulator_get(&pdev->dev, "mx9016");ret = regulator_set_voltage(reg_mx9016, 3300000, 3300000);ret = regulator_enable(reg_mx9016);//zxw end
}
但是输出不了3.3v,为什么tp用vtouch加个-supply就可以输出,我同样用了mx9016加了个-supply就不能呢?
然后跟一下代码查个究竟。
在kernel-3.18搜索regulator_get,会找到mt6580v178\kernel-3.18\drivers\regulator\core.c
struct regulator *regulator_get(struct device *dev, const char *id)
{return _regulator_get(dev, id, false, true);
}
EXPORT_SYMBOL_GPL(regulator_get);
看到这个函数struct regulator *regulator_get(struct device *dev, const char *id)不要怕,它是
一个指针函数(不是函数指针啊,注意区别),只不过返回的是一个指针,一个地址,别的一般返回int类型。
搜索_regulator_get,找到如下函数:
static struct regulator *_regulator_get(struct device *dev, const char *id,bool exclusive, bool allow_dummy)
{struct regulator_dev *rdev;struct regulator *regulator = ERR_PTR(-EPROBE_DEFER);const char *devname = NULL;int ret;if (id == NULL) {pr_err("get() with no identifier\n");return ERR_PTR(-EINVAL);}if (dev)devname = dev_name(dev);if (have_full_constraints())ret = -ENODEV;elseret = -EPROBE_DEFER;mutex_lock(®ulator_list_mutex);rdev = regulator_dev_lookup(dev, id, &ret);if (rdev)goto found;regulator = ERR_PTR(ret);/** If we have return value from dev_lookup fail, we do not expect to* succeed, so, quit with appropriate error value*/if (ret && ret != -ENODEV)goto out;if (!devname)devname = "deviceless";/** 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(®ulator_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;}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;elserdev->use_count = 0;}out:mutex_unlock(®ulator_list_mutex);return regulator;
}
搜索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, ®ulator_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, ®ulator_list, list)if (strcmp(rdev_get_name(r), supply) == 0)return r;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)return map->regulator;}return NULL;
}
搜索of_get_regulator,找到如下函数:
static struct device_node *of_get_regulator(struct device *dev, const char *supply)
{
struct device_node regnode = NULL;
char prop_name[32]; / 32 is max size of property name */
dev_dbg(dev, "Looking up %s-supply from device tree\n", supply);snprintf(prop_name, 32, "%s-supply", supply);
regnode = of_parse_phandle(dev->of_node, prop_name, 0);if (!regnode) {dev_dbg(dev, "Looking up %s property in node %s failed",prop_name, dev->of_node->full_name);return NULL;
}
return regnode;
}
这时关键的地方来了,由snprintf(prop_name, 32, “%s-supply”, supply);
和regnode = of_parse_phandle(dev->of_node, prop_name, 0);可以知道%s是dev的节点,
所以将只需要将代码做如下改动:
1.kernel-3.18\arch\arm\boot\dts\mt6580.dts
mx9016-supply = <&mt_pmic_vgp1_ldo_reg>; 改为 breathled-supply = <&mt_pmic_vgp1_ldo_reg>;
2.对应的驱动
reg_mx9016 = regulator_get(&pdev->dev, “mx9016”); 改为 reg_mx9016 = regulator_get(&pdev->dev, “breathled”);
后面成功输出3.3v