forked from mirrors/linux
		
	clk: generalize devm_clk_get() a bit
Allow to add an exit hook to devm managed clocks. Also use clk_get_optional() in devm_clk_get_optional instead of open coding it. The generalisation will be used in the next commit to add some more devm_clk helpers. Reviewed-by: Jonathan Cameron <Jonathan.Cameron@huawei.com> Reviewed-by: Alexandru Ardelean <aardelean@deviqon.com> Signed-off-by: Uwe Kleine-König <u.kleine-koenig@pengutronix.de> Link: https://lore.kernel.org/r/20220520075737.758761-3-u.kleine-koenig@pengutronix.de Signed-off-by: Stephen Boyd <sboyd@kernel.org>
This commit is contained in:
		
							parent
							
								
									af89cd4560
								
							
						
					
					
						commit
						abae8e57e4
					
				
					 1 changed files with 54 additions and 22 deletions
				
			
		|  | @ -4,39 +4,71 @@ | ||||||
| #include <linux/export.h> | #include <linux/export.h> | ||||||
| #include <linux/gfp.h> | #include <linux/gfp.h> | ||||||
| 
 | 
 | ||||||
|  | struct devm_clk_state { | ||||||
|  | 	struct clk *clk; | ||||||
|  | 	void (*exit)(struct clk *clk); | ||||||
|  | }; | ||||||
|  | 
 | ||||||
| static void devm_clk_release(struct device *dev, void *res) | static void devm_clk_release(struct device *dev, void *res) | ||||||
| { | { | ||||||
| 	clk_put(*(struct clk **)res); | 	struct devm_clk_state *state = *(struct devm_clk_state **)res; | ||||||
|  | 
 | ||||||
|  | 	if (state->exit) | ||||||
|  | 		state->exit(state->clk); | ||||||
|  | 
 | ||||||
|  | 	clk_put(state->clk); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | static struct clk *__devm_clk_get(struct device *dev, const char *id, | ||||||
|  | 				  struct clk *(*get)(struct device *dev, const char *id), | ||||||
|  | 				  int (*init)(struct clk *clk), | ||||||
|  | 				  void (*exit)(struct clk *clk)) | ||||||
|  | { | ||||||
|  | 	struct devm_clk_state *state; | ||||||
|  | 	struct clk *clk; | ||||||
|  | 	int ret; | ||||||
|  | 
 | ||||||
|  | 	state = devres_alloc(devm_clk_release, sizeof(*state), GFP_KERNEL); | ||||||
|  | 	if (!state) | ||||||
|  | 		return ERR_PTR(-ENOMEM); | ||||||
|  | 
 | ||||||
|  | 	clk = get(dev, id); | ||||||
|  | 	if (IS_ERR(clk)) { | ||||||
|  | 		ret = PTR_ERR(clk); | ||||||
|  | 		goto err_clk_get; | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	if (init) { | ||||||
|  | 		ret = init(clk); | ||||||
|  | 		if (ret) | ||||||
|  | 			goto err_clk_init; | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	state->clk = clk; | ||||||
|  | 	state->exit = exit; | ||||||
|  | 
 | ||||||
|  | 	devres_add(dev, state); | ||||||
|  | 
 | ||||||
|  | 	return clk; | ||||||
|  | 
 | ||||||
|  | err_clk_init: | ||||||
|  | 
 | ||||||
|  | 	clk_put(clk); | ||||||
|  | err_clk_get: | ||||||
|  | 
 | ||||||
|  | 	devres_free(state); | ||||||
|  | 	return ERR_PTR(ret); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| struct clk *devm_clk_get(struct device *dev, const char *id) | struct clk *devm_clk_get(struct device *dev, const char *id) | ||||||
| { | { | ||||||
| 	struct clk **ptr, *clk; | 	return __devm_clk_get(dev, id, clk_get, NULL, NULL); | ||||||
| 
 |  | ||||||
| 	ptr = devres_alloc(devm_clk_release, sizeof(*ptr), GFP_KERNEL); |  | ||||||
| 	if (!ptr) |  | ||||||
| 		return ERR_PTR(-ENOMEM); |  | ||||||
| 
 |  | ||||||
| 	clk = clk_get(dev, id); |  | ||||||
| 	if (!IS_ERR(clk)) { |  | ||||||
| 		*ptr = clk; |  | ||||||
| 		devres_add(dev, ptr); |  | ||||||
| 	} else { |  | ||||||
| 		devres_free(ptr); |  | ||||||
| 	} |  | ||||||
| 
 |  | ||||||
| 	return clk; |  | ||||||
| } | } | ||||||
| EXPORT_SYMBOL(devm_clk_get); | EXPORT_SYMBOL(devm_clk_get); | ||||||
| 
 | 
 | ||||||
| struct clk *devm_clk_get_optional(struct device *dev, const char *id) | struct clk *devm_clk_get_optional(struct device *dev, const char *id) | ||||||
| { | { | ||||||
| 	struct clk *clk = devm_clk_get(dev, id); | 	return __devm_clk_get(dev, id, clk_get_optional, NULL, NULL); | ||||||
| 
 |  | ||||||
| 	if (clk == ERR_PTR(-ENOENT)) |  | ||||||
| 		return NULL; |  | ||||||
| 
 |  | ||||||
| 	return clk; |  | ||||||
| } | } | ||||||
| EXPORT_SYMBOL(devm_clk_get_optional); | EXPORT_SYMBOL(devm_clk_get_optional); | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
		Loading…
	
		Reference in a new issue
	
	 Uwe Kleine-König
						Uwe Kleine-König