diff options
Diffstat (limited to 'drivers/media/v4l2-core/v4l2-clk.c')
| -rw-r--r-- | drivers/media/v4l2-core/v4l2-clk.c | 81 | 
1 files changed, 58 insertions, 23 deletions
diff --git a/drivers/media/v4l2-core/v4l2-clk.c b/drivers/media/v4l2-core/v4l2-clk.c index e18cc0469cf8..34e416a554f6 100644 --- a/drivers/media/v4l2-core/v4l2-clk.c +++ b/drivers/media/v4l2-core/v4l2-clk.c @@ -9,6 +9,7 @@   */  #include <linux/atomic.h> +#include <linux/clk.h>  #include <linux/device.h>  #include <linux/errno.h>  #include <linux/list.h> @@ -23,17 +24,13 @@  static DEFINE_MUTEX(clk_lock);  static LIST_HEAD(clk_list); -static struct v4l2_clk *v4l2_clk_find(const char *dev_id, const char *id) +static struct v4l2_clk *v4l2_clk_find(const char *dev_id)  {  	struct v4l2_clk *clk; -	list_for_each_entry(clk, &clk_list, list) { -		if (strcmp(dev_id, clk->dev_id)) -			continue; - -		if (!id || !clk->id || !strcmp(clk->id, id)) +	list_for_each_entry(clk, &clk_list, list) +		if (!strcmp(dev_id, clk->dev_id))  			return clk; -	}  	return ERR_PTR(-ENODEV);  } @@ -41,9 +38,24 @@ static struct v4l2_clk *v4l2_clk_find(const char *dev_id, const char *id)  struct v4l2_clk *v4l2_clk_get(struct device *dev, const char *id)  {  	struct v4l2_clk *clk; +	struct clk *ccf_clk = clk_get(dev, id); + +	if (PTR_ERR(ccf_clk) == -EPROBE_DEFER) +		return ERR_PTR(-EPROBE_DEFER); + +	if (!IS_ERR_OR_NULL(ccf_clk)) { +		clk = kzalloc(sizeof(*clk), GFP_KERNEL); +		if (!clk) { +			clk_put(ccf_clk); +			return ERR_PTR(-ENOMEM); +		} +		clk->clk = ccf_clk; + +		return clk; +	}  	mutex_lock(&clk_lock); -	clk = v4l2_clk_find(dev_name(dev), id); +	clk = v4l2_clk_find(dev_name(dev));  	if (!IS_ERR(clk))  		atomic_inc(&clk->use_count); @@ -60,6 +72,12 @@ void v4l2_clk_put(struct v4l2_clk *clk)  	if (IS_ERR(clk))  		return; +	if (clk->clk) { +		clk_put(clk->clk); +		kfree(clk); +		return; +	} +  	mutex_lock(&clk_lock);  	list_for_each_entry(tmp, &clk_list, list) @@ -97,8 +115,12 @@ static void v4l2_clk_unlock_driver(struct v4l2_clk *clk)  int v4l2_clk_enable(struct v4l2_clk *clk)  { -	int ret = v4l2_clk_lock_driver(clk); +	int ret; + +	if (clk->clk) +		return clk_prepare_enable(clk->clk); +	ret = v4l2_clk_lock_driver(clk);  	if (ret < 0)  		return ret; @@ -124,11 +146,14 @@ void v4l2_clk_disable(struct v4l2_clk *clk)  {  	int enable; +	if (clk->clk) +		return clk_disable_unprepare(clk->clk); +  	mutex_lock(&clk->lock);  	enable = --clk->enable; -	if (WARN(enable < 0, "Unbalanced %s() on %s:%s!\n", __func__, -		 clk->dev_id, clk->id)) +	if (WARN(enable < 0, "Unbalanced %s() on %s!\n", __func__, +		 clk->dev_id))  		clk->enable++;  	else if (!enable && clk->ops->disable)  		clk->ops->disable(clk); @@ -141,8 +166,12 @@ EXPORT_SYMBOL(v4l2_clk_disable);  unsigned long v4l2_clk_get_rate(struct v4l2_clk *clk)  { -	int ret = v4l2_clk_lock_driver(clk); +	int ret; + +	if (clk->clk) +		return clk_get_rate(clk->clk); +	ret = v4l2_clk_lock_driver(clk);  	if (ret < 0)  		return ret; @@ -161,7 +190,16 @@ EXPORT_SYMBOL(v4l2_clk_get_rate);  int v4l2_clk_set_rate(struct v4l2_clk *clk, unsigned long rate)  { -	int ret = v4l2_clk_lock_driver(clk); +	int ret; + +	if (clk->clk) { +		long r = clk_round_rate(clk->clk, rate); +		if (r < 0) +			return r; +		return clk_set_rate(clk->clk, r); +	} + +	ret = v4l2_clk_lock_driver(clk);  	if (ret < 0)  		return ret; @@ -181,7 +219,7 @@ EXPORT_SYMBOL(v4l2_clk_set_rate);  struct v4l2_clk *v4l2_clk_register(const struct v4l2_clk_ops *ops,  				   const char *dev_id, -				   const char *id, void *priv) +				   void *priv)  {  	struct v4l2_clk *clk;  	int ret; @@ -193,9 +231,8 @@ struct v4l2_clk *v4l2_clk_register(const struct v4l2_clk_ops *ops,  	if (!clk)  		return ERR_PTR(-ENOMEM); -	clk->id = kstrdup(id, GFP_KERNEL);  	clk->dev_id = kstrdup(dev_id, GFP_KERNEL); -	if ((id && !clk->id) || !clk->dev_id) { +	if (!clk->dev_id) {  		ret = -ENOMEM;  		goto ealloc;  	} @@ -205,7 +242,7 @@ struct v4l2_clk *v4l2_clk_register(const struct v4l2_clk_ops *ops,  	mutex_init(&clk->lock);  	mutex_lock(&clk_lock); -	if (!IS_ERR(v4l2_clk_find(dev_id, id))) { +	if (!IS_ERR(v4l2_clk_find(dev_id))) {  		mutex_unlock(&clk_lock);  		ret = -EEXIST;  		goto eexist; @@ -217,7 +254,6 @@ struct v4l2_clk *v4l2_clk_register(const struct v4l2_clk_ops *ops,  eexist:  ealloc: -	kfree(clk->id);  	kfree(clk->dev_id);  	kfree(clk);  	return ERR_PTR(ret); @@ -227,15 +263,14 @@ EXPORT_SYMBOL(v4l2_clk_register);  void v4l2_clk_unregister(struct v4l2_clk *clk)  {  	if (WARN(atomic_read(&clk->use_count), -		 "%s(): Refusing to unregister ref-counted %s:%s clock!\n", -		 __func__, clk->dev_id, clk->id)) +		 "%s(): Refusing to unregister ref-counted %s clock!\n", +		 __func__, clk->dev_id))  		return;  	mutex_lock(&clk_lock);  	list_del(&clk->list);  	mutex_unlock(&clk_lock); -	kfree(clk->id);  	kfree(clk->dev_id);  	kfree(clk);  } @@ -253,7 +288,7 @@ static unsigned long fixed_get_rate(struct v4l2_clk *clk)  }  struct v4l2_clk *__v4l2_clk_register_fixed(const char *dev_id, -		const char *id, unsigned long rate, struct module *owner) +				unsigned long rate, struct module *owner)  {  	struct v4l2_clk *clk;  	struct v4l2_clk_fixed *priv = kzalloc(sizeof(*priv), GFP_KERNEL); @@ -265,7 +300,7 @@ struct v4l2_clk *__v4l2_clk_register_fixed(const char *dev_id,  	priv->ops.get_rate = fixed_get_rate;  	priv->ops.owner = owner; -	clk = v4l2_clk_register(&priv->ops, dev_id, id, priv); +	clk = v4l2_clk_register(&priv->ops, dev_id, priv);  	if (IS_ERR(clk))  		kfree(priv);  |