aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorCharles Keepax <ckeepax@opensource.wolfsonmicro.com>2013-10-15 15:14:20 -0400
committerMark Brown <broonie@linaro.org>2013-10-17 19:56:05 -0400
commita06ccd9c3785fa5550917ae036944f4e080b5749 (patch)
tree9314ebad2316f4f1e016f53e8f10eb0fbf911190
parent0cdfcc0f9352a4c076fbb51299e2b12a35619a51 (diff)
regulator: core: Add ability to create a lookup alias for supply
These patches add the ability to create an alternative device on which a lookup for a certain supply should be conducted. A common use-case for this would be devices that are logically represented as a collection of drivers within Linux but are are presented as a single device from device tree. It this case it is necessary for each sub device to locate their supply data on the main device. Signed-off-by: Charles Keepax <ckeepax@opensource.wolfsonmicro.com> Signed-off-by: Mark Brown <broonie@linaro.org>
-rw-r--r--drivers/regulator/core.c170
-rw-r--r--drivers/regulator/devres.c163
-rw-r--r--include/linux/regulator/consumer.h79
3 files changed, 412 insertions, 0 deletions
diff --git a/drivers/regulator/core.c b/drivers/regulator/core.c
index 906deb7354ed..16427de56ce8 100644
--- a/drivers/regulator/core.c
+++ b/drivers/regulator/core.c
@@ -53,6 +53,7 @@ static DEFINE_MUTEX(regulator_list_mutex);
53static LIST_HEAD(regulator_list); 53static LIST_HEAD(regulator_list);
54static LIST_HEAD(regulator_map_list); 54static LIST_HEAD(regulator_map_list);
55static LIST_HEAD(regulator_ena_gpio_list); 55static LIST_HEAD(regulator_ena_gpio_list);
56static LIST_HEAD(regulator_supply_alias_list);
56static bool has_full_constraints; 57static bool has_full_constraints;
57static bool board_wants_dummy_regulator; 58static bool board_wants_dummy_regulator;
58 59
@@ -83,6 +84,19 @@ struct regulator_enable_gpio {
83 unsigned int ena_gpio_invert:1; 84 unsigned int ena_gpio_invert:1;
84}; 85};
85 86
87/*
88 * struct regulator_supply_alias
89 *
90 * Used to map lookups for a supply onto an alternative device.
91 */
92struct regulator_supply_alias {
93 struct list_head list;
94 struct device *src_dev;
95 const char *src_supply;
96 struct device *alias_dev;
97 const char *alias_supply;
98};
99
86static int _regulator_is_enabled(struct regulator_dev *rdev); 100static int _regulator_is_enabled(struct regulator_dev *rdev);
87static int _regulator_disable(struct regulator_dev *rdev); 101static int _regulator_disable(struct regulator_dev *rdev);
88static int _regulator_get_voltage(struct regulator_dev *rdev); 102static int _regulator_get_voltage(struct regulator_dev *rdev);
@@ -1173,6 +1187,32 @@ static int _regulator_get_enable_time(struct regulator_dev *rdev)
1173 return rdev->desc->ops->enable_time(rdev); 1187 return rdev->desc->ops->enable_time(rdev);
1174} 1188}
1175 1189
1190static struct regulator_supply_alias *regulator_find_supply_alias(
1191 struct device *dev, const char *supply)
1192{
1193 struct regulator_supply_alias *map;
1194
1195 list_for_each_entry(map, &regulator_supply_alias_list, list)
1196 if (map->src_dev == dev && strcmp(map->src_supply, supply) == 0)
1197 return map;
1198
1199 return NULL;
1200}
1201
1202static void regulator_supply_alias(struct device **dev, const char **supply)
1203{
1204 struct regulator_supply_alias *map;
1205
1206 map = regulator_find_supply_alias(*dev, *supply);
1207 if (map) {
1208 dev_dbg(*dev, "Mapping supply %s to %s,%s\n",
1209 *supply, map->alias_supply,
1210 dev_name(map->alias_dev));
1211 *dev = map->alias_dev;
1212 *supply = map->alias_supply;
1213 }
1214}
1215
1176static struct regulator_dev *regulator_dev_lookup(struct device *dev, 1216static struct regulator_dev *regulator_dev_lookup(struct device *dev,
1177 const char *supply, 1217 const char *supply,
1178 int *ret) 1218 int *ret)
@@ -1182,6 +1222,8 @@ static struct regulator_dev *regulator_dev_lookup(struct device *dev,
1182 struct regulator_map *map; 1222 struct regulator_map *map;
1183 const char *devname = NULL; 1223 const char *devname = NULL;
1184 1224
1225 regulator_supply_alias(&dev, &supply);
1226
1185 /* first do a dt based lookup */ 1227 /* first do a dt based lookup */
1186 if (dev && dev->of_node) { 1228 if (dev && dev->of_node) {
1187 node = of_get_regulator(dev, supply); 1229 node = of_get_regulator(dev, supply);
@@ -1432,6 +1474,134 @@ void regulator_put(struct regulator *regulator)
1432} 1474}
1433EXPORT_SYMBOL_GPL(regulator_put); 1475EXPORT_SYMBOL_GPL(regulator_put);
1434 1476
1477/**
1478 * regulator_register_supply_alias - Provide device alias for supply lookup
1479 *
1480 * @dev: device that will be given as the regulator "consumer"
1481 * @id: Supply name or regulator ID
1482 * @alias_dev: device that should be used to lookup the supply
1483 * @alias_id: Supply name or regulator ID that should be used to lookup the
1484 * supply
1485 *
1486 * All lookups for id on dev will instead be conducted for alias_id on
1487 * alias_dev.
1488 */
1489int regulator_register_supply_alias(struct device *dev, const char *id,
1490 struct device *alias_dev,
1491 const char *alias_id)
1492{
1493 struct regulator_supply_alias *map;
1494
1495 map = regulator_find_supply_alias(dev, id);
1496 if (map)
1497 return -EEXIST;
1498
1499 map = kzalloc(sizeof(struct regulator_supply_alias), GFP_KERNEL);
1500 if (!map)
1501 return -ENOMEM;
1502
1503 map->src_dev = dev;
1504 map->src_supply = id;
1505 map->alias_dev = alias_dev;
1506 map->alias_supply = alias_id;
1507
1508 list_add(&map->list, &regulator_supply_alias_list);
1509
1510 pr_info("Adding alias for supply %s,%s -> %s,%s\n",
1511 id, dev_name(dev), alias_id, dev_name(alias_dev));
1512
1513 return 0;
1514}
1515EXPORT_SYMBOL_GPL(regulator_register_supply_alias);
1516
1517/**
1518 * regulator_unregister_supply_alias - Remove device alias
1519 *
1520 * @dev: device that will be given as the regulator "consumer"
1521 * @id: Supply name or regulator ID
1522 *
1523 * Remove a lookup alias if one exists for id on dev.
1524 */
1525void regulator_unregister_supply_alias(struct device *dev, const char *id)
1526{
1527 struct regulator_supply_alias *map;
1528
1529 map = regulator_find_supply_alias(dev, id);
1530 if (map) {
1531 list_del(&map->list);
1532 kfree(map);
1533 }
1534}
1535EXPORT_SYMBOL_GPL(regulator_unregister_supply_alias);
1536
1537/**
1538 * regulator_bulk_register_supply_alias - register multiple aliases
1539 *
1540 * @dev: device that will be given as the regulator "consumer"
1541 * @id: List of supply names or regulator IDs
1542 * @alias_dev: device that should be used to lookup the supply
1543 * @alias_id: List of supply names or regulator IDs that should be used to
1544 * lookup the supply
1545 * @num_id: Number of aliases to register
1546 *
1547 * @return 0 on success, an errno on failure.
1548 *
1549 * This helper function allows drivers to register several supply
1550 * aliases in one operation. If any of the aliases cannot be
1551 * registered any aliases that were registered will be removed
1552 * before returning to the caller.
1553 */
1554int regulator_bulk_register_supply_alias(struct device *dev, const char **id,
1555 struct device *alias_dev,
1556 const char **alias_id,
1557 int num_id)
1558{
1559 int i;
1560 int ret;
1561
1562 for (i = 0; i < num_id; ++i) {
1563 ret = regulator_register_supply_alias(dev, id[i], alias_dev,
1564 alias_id[i]);
1565 if (ret < 0)
1566 goto err;
1567 }
1568
1569 return 0;
1570
1571err:
1572 dev_err(dev,
1573 "Failed to create supply alias %s,%s -> %s,%s\n",
1574 id[i], dev_name(dev), alias_id[i], dev_name(alias_dev));
1575
1576 while (--i >= 0)
1577 regulator_unregister_supply_alias(dev, id[i]);
1578
1579 return ret;
1580}
1581EXPORT_SYMBOL_GPL(regulator_bulk_register_supply_alias);
1582
1583/**
1584 * regulator_bu