Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

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>

authored by

Charles Keepax and committed by
Mark Brown
a06ccd9c 0cdfcc0f

+412
+170
drivers/regulator/core.c
··· 53 53 static LIST_HEAD(regulator_list); 54 54 static LIST_HEAD(regulator_map_list); 55 55 static LIST_HEAD(regulator_ena_gpio_list); 56 + static LIST_HEAD(regulator_supply_alias_list); 56 57 static bool has_full_constraints; 57 58 static bool board_wants_dummy_regulator; 58 59 ··· 82 81 u32 enable_count; /* a number of enabled shared GPIO */ 83 82 u32 request_count; /* a number of requested shared GPIO */ 84 83 unsigned int ena_gpio_invert:1; 84 + }; 85 + 86 + /* 87 + * struct regulator_supply_alias 88 + * 89 + * Used to map lookups for a supply onto an alternative device. 90 + */ 91 + struct regulator_supply_alias { 92 + struct list_head list; 93 + struct device *src_dev; 94 + const char *src_supply; 95 + struct device *alias_dev; 96 + const char *alias_supply; 85 97 }; 86 98 87 99 static int _regulator_is_enabled(struct regulator_dev *rdev); ··· 1187 1173 return rdev->desc->ops->enable_time(rdev); 1188 1174 } 1189 1175 1176 + static struct regulator_supply_alias *regulator_find_supply_alias( 1177 + struct device *dev, const char *supply) 1178 + { 1179 + struct regulator_supply_alias *map; 1180 + 1181 + list_for_each_entry(map, &regulator_supply_alias_list, list) 1182 + if (map->src_dev == dev && strcmp(map->src_supply, supply) == 0) 1183 + return map; 1184 + 1185 + return NULL; 1186 + } 1187 + 1188 + static void regulator_supply_alias(struct device **dev, const char **supply) 1189 + { 1190 + struct regulator_supply_alias *map; 1191 + 1192 + map = regulator_find_supply_alias(*dev, *supply); 1193 + if (map) { 1194 + dev_dbg(*dev, "Mapping supply %s to %s,%s\n", 1195 + *supply, map->alias_supply, 1196 + dev_name(map->alias_dev)); 1197 + *dev = map->alias_dev; 1198 + *supply = map->alias_supply; 1199 + } 1200 + } 1201 + 1190 1202 static struct regulator_dev *regulator_dev_lookup(struct device *dev, 1191 1203 const char *supply, 1192 1204 int *ret) ··· 1221 1181 struct device_node *node; 1222 1182 struct regulator_map *map; 1223 1183 const char *devname = NULL; 1184 + 1185 + regulator_supply_alias(&dev, &supply); 1224 1186 1225 1187 /* first do a dt based lookup */ 1226 1188 if (dev && dev->of_node) { ··· 1473 1431 mutex_unlock(&regulator_list_mutex); 1474 1432 } 1475 1433 EXPORT_SYMBOL_GPL(regulator_put); 1434 + 1435 + /** 1436 + * regulator_register_supply_alias - Provide device alias for supply lookup 1437 + * 1438 + * @dev: device that will be given as the regulator "consumer" 1439 + * @id: Supply name or regulator ID 1440 + * @alias_dev: device that should be used to lookup the supply 1441 + * @alias_id: Supply name or regulator ID that should be used to lookup the 1442 + * supply 1443 + * 1444 + * All lookups for id on dev will instead be conducted for alias_id on 1445 + * alias_dev. 1446 + */ 1447 + int regulator_register_supply_alias(struct device *dev, const char *id, 1448 + struct device *alias_dev, 1449 + const char *alias_id) 1450 + { 1451 + struct regulator_supply_alias *map; 1452 + 1453 + map = regulator_find_supply_alias(dev, id); 1454 + if (map) 1455 + return -EEXIST; 1456 + 1457 + map = kzalloc(sizeof(struct regulator_supply_alias), GFP_KERNEL); 1458 + if (!map) 1459 + return -ENOMEM; 1460 + 1461 + map->src_dev = dev; 1462 + map->src_supply = id; 1463 + map->alias_dev = alias_dev; 1464 + map->alias_supply = alias_id; 1465 + 1466 + list_add(&map->list, &regulator_supply_alias_list); 1467 + 1468 + pr_info("Adding alias for supply %s,%s -> %s,%s\n", 1469 + id, dev_name(dev), alias_id, dev_name(alias_dev)); 1470 + 1471 + return 0; 1472 + } 1473 + EXPORT_SYMBOL_GPL(regulator_register_supply_alias); 1474 + 1475 + /** 1476 + * regulator_unregister_supply_alias - Remove device alias 1477 + * 1478 + * @dev: device that will be given as the regulator "consumer" 1479 + * @id: Supply name or regulator ID 1480 + * 1481 + * Remove a lookup alias if one exists for id on dev. 1482 + */ 1483 + void regulator_unregister_supply_alias(struct device *dev, const char *id) 1484 + { 1485 + struct regulator_supply_alias *map; 1486 + 1487 + map = regulator_find_supply_alias(dev, id); 1488 + if (map) { 1489 + list_del(&map->list); 1490 + kfree(map); 1491 + } 1492 + } 1493 + EXPORT_SYMBOL_GPL(regulator_unregister_supply_alias); 1494 + 1495 + /** 1496 + * regulator_bulk_register_supply_alias - register multiple aliases 1497 + * 1498 + * @dev: device that will be given as the regulator "consumer" 1499 + * @id: List of supply names or regulator IDs 1500 + * @alias_dev: device that should be used to lookup the supply 1501 + * @alias_id: List of supply names or regulator IDs that should be used to 1502 + * lookup the supply 1503 + * @num_id: Number of aliases to register 1504 + * 1505 + * @return 0 on success, an errno on failure. 1506 + * 1507 + * This helper function allows drivers to register several supply 1508 + * aliases in one operation. If any of the aliases cannot be 1509 + * registered any aliases that were registered will be removed 1510 + * before returning to the caller. 1511 + */ 1512 + int regulator_bulk_register_supply_alias(struct device *dev, const char **id, 1513 + struct device *alias_dev, 1514 + const char **alias_id, 1515 + int num_id) 1516 + { 1517 + int i; 1518 + int ret; 1519 + 1520 + for (i = 0; i < num_id; ++i) { 1521 + ret = regulator_register_supply_alias(dev, id[i], alias_dev, 1522 + alias_id[i]); 1523 + if (ret < 0) 1524 + goto err; 1525 + } 1526 + 1527 + return 0; 1528 + 1529 + err: 1530 + dev_err(dev, 1531 + "Failed to create supply alias %s,%s -> %s,%s\n", 1532 + id[i], dev_name(dev), alias_id[i], dev_name(alias_dev)); 1533 + 1534 + while (--i >= 0) 1535 + regulator_unregister_supply_alias(dev, id[i]); 1536 + 1537 + return ret; 1538 + } 1539 + EXPORT_SYMBOL_GPL(regulator_bulk_register_supply_alias); 1540 + 1541 + /** 1542 + * regulator_bulk_unregister_supply_alias - unregister multiple aliases 1543 + * 1544 + * @dev: device that will be given as the regulator "consumer" 1545 + * @id: List of supply names or regulator IDs 1546 + * @num_id: Number of aliases to unregister 1547 + * 1548 + * This helper function allows drivers to unregister several supply 1549 + * aliases in one operation. 1550 + */ 1551 + void regulator_bulk_unregister_supply_alias(struct device *dev, 1552 + const char **id, 1553 + int num_id) 1554 + { 1555 + int i; 1556 + 1557 + for (i = 0; i < num_id; ++i) 1558 + regulator_unregister_supply_alias(dev, id[i]); 1559 + } 1560 + EXPORT_SYMBOL_GPL(regulator_bulk_unregister_supply_alias); 1561 + 1476 1562 1477 1563 /* Manage enable GPIO list. Same GPIO pin can be shared among regulators */ 1478 1564 static int regulator_ena_gpio_request(struct regulator_dev *rdev,
+163
drivers/regulator/devres.c
··· 250 250 WARN_ON(rc); 251 251 } 252 252 EXPORT_SYMBOL_GPL(devm_regulator_unregister); 253 + 254 + struct regulator_supply_alias_match { 255 + struct device *dev; 256 + const char *id; 257 + }; 258 + 259 + static int devm_regulator_match_supply_alias(struct device *dev, void *res, 260 + void *data) 261 + { 262 + struct regulator_supply_alias_match *match = res; 263 + struct regulator_supply_alias_match *target = data; 264 + 265 + return match->dev == target->dev && strcmp(match->id, target->id) == 0; 266 + } 267 + 268 + static void devm_regulator_destroy_supply_alias(struct device *dev, void *res) 269 + { 270 + struct regulator_supply_alias_match *match = res; 271 + 272 + regulator_unregister_supply_alias(match->dev, match->id); 273 + } 274 + 275 + /** 276 + * devm_regulator_register_supply_alias - Resource managed 277 + * regulator_register_supply_alias() 278 + * 279 + * @dev: device that will be given as the regulator "consumer" 280 + * @id: Supply name or regulator ID 281 + * @alias_dev: device that should be used to lookup the supply 282 + * @alias_id: Supply name or regulator ID that should be used to lookup the 283 + * supply 284 + * 285 + * The supply alias will automatically be unregistered when the source 286 + * device is unbound. 287 + */ 288 + int devm_regulator_register_supply_alias(struct device *dev, const char *id, 289 + struct device *alias_dev, 290 + const char *alias_id) 291 + { 292 + struct regulator_supply_alias_match *match; 293 + int ret; 294 + 295 + match = devres_alloc(devm_regulator_destroy_supply_alias, 296 + sizeof(struct regulator_supply_alias_match), 297 + GFP_KERNEL); 298 + if (!match) 299 + return -ENOMEM; 300 + 301 + match->dev = dev; 302 + match->id = id; 303 + 304 + ret = regulator_register_supply_alias(dev, id, alias_dev, alias_id); 305 + if (ret < 0) { 306 + devres_free(match); 307 + return ret; 308 + } 309 + 310 + devres_add(dev, match); 311 + 312 + return 0; 313 + } 314 + EXPORT_SYMBOL_GPL(devm_regulator_register_supply_alias); 315 + 316 + /** 317 + * devm_regulator_unregister_supply_alias - Resource managed 318 + * regulator_unregister_supply_alias() 319 + * 320 + * @dev: device that will be given as the regulator "consumer" 321 + * @id: Supply name or regulator ID 322 + * 323 + * Unregister an alias registered with 324 + * devm_regulator_register_supply_alias(). Normally this function 325 + * will not need to be called and the resource management code 326 + * will ensure that the resource is freed. 327 + */ 328 + void devm_regulator_unregister_supply_alias(struct device *dev, const char *id) 329 + { 330 + struct regulator_supply_alias_match match; 331 + int rc; 332 + 333 + match.dev = dev; 334 + match.id = id; 335 + 336 + rc = devres_release(dev, devm_regulator_destroy_supply_alias, 337 + devm_regulator_match_supply_alias, &match); 338 + if (rc != 0) 339 + WARN_ON(rc); 340 + } 341 + EXPORT_SYMBOL_GPL(devm_regulator_unregister_supply_alias); 342 + 343 + /** 344 + * devm_regulator_bulk_register_supply_alias - Managed register 345 + * multiple aliases 346 + * 347 + * @dev: device that will be given as the regulator "consumer" 348 + * @id: List of supply names or regulator IDs 349 + * @alias_dev: device that should be used to lookup the supply 350 + * @alias_id: List of supply names or regulator IDs that should be used to 351 + * lookup the supply 352 + * @num_id: Number of aliases to register 353 + * 354 + * @return 0 on success, an errno on failure. 355 + * 356 + * This helper function allows drivers to register several supply 357 + * aliases in one operation, the aliases will be automatically 358 + * unregisters when the source device is unbound. If any of the 359 + * aliases cannot be registered any aliases that were registered 360 + * will be removed before returning to the caller. 361 + */ 362 + int devm_regulator_bulk_register_supply_alias(struct device *dev, 363 + const char **id, 364 + struct device *alias_dev, 365 + const char **alias_id, 366 + int num_id) 367 + { 368 + int i; 369 + int ret; 370 + 371 + for (i = 0; i < num_id; ++i) { 372 + ret = devm_regulator_register_supply_alias(dev, id[i], 373 + alias_dev, 374 + alias_id[i]); 375 + if (ret < 0) 376 + goto err; 377 + } 378 + 379 + return 0; 380 + 381 + err: 382 + dev_err(dev, 383 + "Failed to create supply alias %s,%s -> %s,%s\n", 384 + id[i], dev_name(dev), alias_id[i], dev_name(alias_dev)); 385 + 386 + while (--i >= 0) 387 + devm_regulator_unregister_supply_alias(dev, id[i]); 388 + 389 + return ret; 390 + } 391 + EXPORT_SYMBOL_GPL(devm_regulator_bulk_register_supply_alias); 392 + 393 + /** 394 + * devm_regulator_bulk_unregister_supply_alias - Managed unregister 395 + * multiple aliases 396 + * 397 + * @dev: device that will be given as the regulator "consumer" 398 + * @id: List of supply names or regulator IDs 399 + * @num_id: Number of aliases to unregister 400 + * 401 + * Unregister aliases registered with 402 + * devm_regulator_bulk_register_supply_alias(). Normally this function 403 + * will not need to be called and the resource management code 404 + * will ensure that the resource is freed. 405 + */ 406 + void devm_regulator_bulk_unregister_supply_alias(struct device *dev, 407 + const char **id, 408 + int num_id) 409 + { 410 + int i; 411 + 412 + for (i = 0; i < num_id; ++i) 413 + devm_regulator_unregister_supply_alias(dev, id[i]); 414 + } 415 + EXPORT_SYMBOL_GPL(devm_regulator_bulk_unregister_supply_alias);
+79
include/linux/regulator/consumer.h
··· 146 146 void regulator_put(struct regulator *regulator); 147 147 void devm_regulator_put(struct regulator *regulator); 148 148 149 + int regulator_register_supply_alias(struct device *dev, const char *id, 150 + struct device *alias_dev, 151 + const char *alias_id); 152 + void regulator_unregister_supply_alias(struct device *dev, const char *id); 153 + 154 + int regulator_bulk_register_supply_alias(struct device *dev, const char **id, 155 + struct device *alias_dev, 156 + const char **alias_id, int num_id); 157 + void regulator_bulk_unregister_supply_alias(struct device *dev, 158 + const char **id, int num_id); 159 + 160 + int devm_regulator_register_supply_alias(struct device *dev, const char *id, 161 + struct device *alias_dev, 162 + const char *alias_id); 163 + void devm_regulator_unregister_supply_alias(struct device *dev, 164 + const char *id); 165 + 166 + int devm_regulator_bulk_register_supply_alias(struct device *dev, 167 + const char **id, 168 + struct device *alias_dev, 169 + const char **alias_id, 170 + int num_id); 171 + void devm_regulator_bulk_unregister_supply_alias(struct device *dev, 172 + const char **id, 173 + int num_id); 174 + 149 175 /* regulator output control and status */ 150 176 int __must_check regulator_enable(struct regulator *regulator); 151 177 int regulator_disable(struct regulator *regulator); ··· 273 247 } 274 248 275 249 static inline void devm_regulator_put(struct regulator *regulator) 250 + { 251 + } 252 + 253 + static inline int regulator_register_supply_alias(struct device *dev, 254 + const char *id, 255 + struct device *alias_dev, 256 + const char *alias_id) 257 + { 258 + return 0; 259 + } 260 + 261 + static inline void regulator_unregister_supply_alias(struct device *dev, 262 + const char *id) 263 + { 264 + } 265 + 266 + static inline int regulator_bulk_register_supply_alias(struct device *dev, 267 + const char **id, 268 + struct device *alias_dev, 269 + const char **alias_id, 270 + int num_id) 271 + { 272 + return 0; 273 + } 274 + 275 + static inline void regulator_bulk_unregister_supply_alias(struct device *dev, 276 + const char **id, 277 + int num_id) 278 + { 279 + } 280 + 281 + static inline int devm_regulator_register_supply_alias(struct device *dev, 282 + const char *id, 283 + struct device *alias_dev, 284 + const char *alias_id) 285 + { 286 + return 0; 287 + } 288 + 289 + static inline void devm_regulator_unregister_supply_alias(struct device *dev, 290 + const char *id) 291 + { 292 + } 293 + 294 + static inline int devm_regulator_bulk_register_supply_alias( 295 + struct device *dev, const char **id, struct device *alias_dev, 296 + const char **alias_id, int num_id) 297 + { 298 + return 0; 299 + } 300 + 301 + static inline void devm_regulator_bulk_unregister_supply_alias( 302 + struct device *dev, const char **id, int num_id) 276 303 { 277 304 } 278 305