This implements reset_control_bulk_get() to get multiple reset controllers at once. This somewhat overlaps with reset_control_array_get(). The difference is that reset_control_array_get() returns a single reset controller which internally handles the array of reset controllers whereas reset_control_bulk_get() allows the consumer to control each reset controller individually. Signed-off-by: Sascha Hauer <s.hauer@xxxxxxxxxxxxxx> --- drivers/reset/core.c | 24 ++++++++++++++++++++++++ include/linux/reset.h | 44 ++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 68 insertions(+) diff --git a/drivers/reset/core.c b/drivers/reset/core.c index 679deee3c1..2431a9374a 100644 --- a/drivers/reset/core.c +++ b/drivers/reset/core.c @@ -484,6 +484,30 @@ struct reset_control *reset_control_array_get(struct device *dev) return rstc; } +int __reset_control_bulk_get(struct device *dev, int num_rstcs, + struct reset_control_bulk_data *rstcs, + bool optional) +{ + int ret, i; + + for (i = 0; i < num_rstcs; i++) { + rstcs[i].rstc = __reset_control_get(dev, rstcs[i].id, optional); + if (IS_ERR(rstcs[i].rstc)) { + ret = PTR_ERR(rstcs[i].rstc); + goto err; + } + } + + return 0; + +err: + while (i--) + reset_control_put(rstcs[i].rstc); + + return ret; +} +EXPORT_SYMBOL_GPL(__reset_control_bulk_get); + int device_reset_all(struct device *dev) { struct reset_control *rstc; diff --git a/include/linux/reset.h b/include/linux/reset.h index 183d7d55a0..9469825faf 100644 --- a/include/linux/reset.h +++ b/include/linux/reset.h @@ -6,6 +6,21 @@ struct device; struct reset_control; +/** + * struct reset_control_bulk_data - Data used for bulk reset control operations. + * + * @id: reset control consumer ID + * @rstc: struct reset_control * to store the associated reset control + * + * The reset APIs provide a series of reset_control_bulk_*() API calls as + * a convenience to consumers which require multiple reset controls. + * This structure is used to manage data for these calls. + */ +struct reset_control_bulk_data { + const char *id; + struct reset_control *rstc; +}; + #ifdef CONFIG_RESET_CONTROLLER int reset_control_status(struct reset_control *rstc); @@ -28,6 +43,10 @@ int reset_control_get_count(struct device *dev); struct reset_control *reset_control_array_get(struct device *dev); +int __reset_control_bulk_get(struct device *dev, int num_rstcs, + struct reset_control_bulk_data *rstcs, + bool optional); + #else static inline int reset_control_status(struct reset_control *rstc) @@ -91,6 +110,14 @@ static inline struct reset_control *reset_control_array_get(struct device *dev) return NULL; } +static inline int +__reset_control_bulk_get(struct device *dev, int num_rstcs, + struct reset_control_bulk_data *rstcs, + bool optional) +{ + return optional ? 0 : -EOPNOTSUPP; +} + #endif /* CONFIG_RESET_CONTROLLER */ static inline struct reset_control *reset_control_get_optional(struct device *dev, @@ -105,4 +132,21 @@ static inline struct reset_control *reset_control_get(struct device *dev, return __reset_control_get(dev, id, false); } +/** + * reset_control_bulk_get - Lookup and obtain references to + * multiple reset controllers. + * @dev: device to be reset by the controller + * @num_rstcs: number of entries in rstcs array + * @rstcs: array of struct reset_control_bulk_data with reset line names set + * + * Fills the rstcs array with pointers to reset controls and + * returns 0, or an IS_ERR() condition containing errno. + */ +static inline int __must_check +reset_control_bulk_get(struct device *dev, int num_rstcs, + struct reset_control_bulk_data *rstcs) +{ + return __reset_control_bulk_get(dev, num_rstcs, rstcs, false); +} + #endif -- 2.39.5