diff mbox

[RFC,v2,09/13] power: pwrseq: Add support for USB hubs with external power

Message ID 1462451666-17945-10-git-send-email-k.kozlowski@samsung.com (mailing list archive)
State Not Applicable
Headers show

Commit Message

Krzysztof Kozlowski May 5, 2016, 12:34 p.m. UTC
Some USB devices on embedded boards have external power supply which has
to be reset in certain conditions. Add pwrseq interface for this.

Signed-off-by: Krzysztof Kozlowski <k.kozlowski@samsung.com>
---
 drivers/power/pwrseq/pwrseq.c | 44 +++++++++++++++++++++++++++++++++++++++++++
 include/linux/pwrseq.h        |  8 ++++++++
 2 files changed, 52 insertions(+)

Comments

Javier Martinez Canillas May 5, 2016, 7:52 p.m. UTC | #1
Hello Krzysztof,

On 05/05/2016 08:34 AM, Krzysztof Kozlowski wrote:
> Some USB devices on embedded boards have external power supply which has
> to be reset in certain conditions. Add pwrseq interface for this.
> 
> Signed-off-by: Krzysztof Kozlowski <k.kozlowski@samsung.com>
> ---
>  drivers/power/pwrseq/pwrseq.c | 44 +++++++++++++++++++++++++++++++++++++++++++
>  include/linux/pwrseq.h        |  8 ++++++++
>  2 files changed, 52 insertions(+)
> 
> diff --git a/drivers/power/pwrseq/pwrseq.c b/drivers/power/pwrseq/pwrseq.c
> index 495a19d3c30b..306265f55a10 100644
> --- a/drivers/power/pwrseq/pwrseq.c
> +++ b/drivers/power/pwrseq/pwrseq.c
> @@ -52,6 +52,43 @@ int mmc_pwrseq_alloc(struct mmc_host *host)
>  }
>  EXPORT_SYMBOL_GPL(mmc_pwrseq_alloc);
>  
> +struct pwrseq *pwrseq_alloc(struct device *dev)
> +{

This function is USB specific so better to call it usb_pwrseq_alloc() instead.

Although, this function has a lot of duplicated code from mmc_pwrseq_alloc()
so I think is better to keep the name generic and factorize the common code.

I expect other devices are also needing some kind of power seq in the future
so having a single alloc function instead of each for device type makes sense.

> +	struct device_node *np;
> +	struct pwrseq *p, *ret = NULL;
> +
> +	np = of_parse_phandle(dev->of_node, "usb-pwrseq", 0);

I know this is just an RFC but you should really add DT bindings for this.

Best regards,
Krzysztof Kozlowski May 6, 2016, 6:26 a.m. UTC | #2
On 05/05/2016 09:52 PM, Javier Martinez Canillas wrote:
> Hello Krzysztof,
> 
> On 05/05/2016 08:34 AM, Krzysztof Kozlowski wrote:
>> Some USB devices on embedded boards have external power supply which has
>> to be reset in certain conditions. Add pwrseq interface for this.
>>
>> Signed-off-by: Krzysztof Kozlowski <k.kozlowski@samsung.com>
>> ---
>>  drivers/power/pwrseq/pwrseq.c | 44 +++++++++++++++++++++++++++++++++++++++++++
>>  include/linux/pwrseq.h        |  8 ++++++++
>>  2 files changed, 52 insertions(+)
>>
>> diff --git a/drivers/power/pwrseq/pwrseq.c b/drivers/power/pwrseq/pwrseq.c
>> index 495a19d3c30b..306265f55a10 100644
>> --- a/drivers/power/pwrseq/pwrseq.c
>> +++ b/drivers/power/pwrseq/pwrseq.c
>> @@ -52,6 +52,43 @@ int mmc_pwrseq_alloc(struct mmc_host *host)
>>  }
>>  EXPORT_SYMBOL_GPL(mmc_pwrseq_alloc);
>>  
>> +struct pwrseq *pwrseq_alloc(struct device *dev)
>> +{
> 
> This function is USB specific so better to call it usb_pwrseq_alloc() instead.

Indeed it is parsing USB specific bindings so such prefix is needed.

> Although, this function has a lot of duplicated code from mmc_pwrseq_alloc()
> so I think is better to keep the name generic and factorize the common code.
> 
> I expect other devices are also needing some kind of power seq in the future
> so having a single alloc function instead of each for device type makes sense.

Yes, this can be cleaned up and unified.

> 
>> +	struct device_node *np;
>> +	struct pwrseq *p, *ret = NULL;
>> +
>> +	np = of_parse_phandle(dev->of_node, "usb-pwrseq", 0);
> 
> I know this is just an RFC but you should really add DT bindings for this.

Yep, next step.

Best regards,
Krzysztof

--
To unsubscribe from this list: send the line "unsubscribe linux-samsung-soc" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
diff mbox

Patch

diff --git a/drivers/power/pwrseq/pwrseq.c b/drivers/power/pwrseq/pwrseq.c
index 495a19d3c30b..306265f55a10 100644
--- a/drivers/power/pwrseq/pwrseq.c
+++ b/drivers/power/pwrseq/pwrseq.c
@@ -52,6 +52,43 @@  int mmc_pwrseq_alloc(struct mmc_host *host)
 }
 EXPORT_SYMBOL_GPL(mmc_pwrseq_alloc);
 
+struct pwrseq *pwrseq_alloc(struct device *dev)
+{
+	struct device_node *np;
+	struct pwrseq *p, *ret = NULL;
+
+	np = of_parse_phandle(dev->of_node, "usb-pwrseq", 0);
+	if (!np)
+		return NULL;
+
+	mutex_lock(&pwrseq_list_mutex);
+	list_for_each_entry(p, &pwrseq_list, pwrseq_node) {
+		if (p->dev->of_node == np) {
+			if (!try_module_get(p->owner))
+				dev_err(dev,
+					"increasing module refcount failed\n");
+			else
+				ret = p;
+
+			break;
+		}
+	}
+
+	of_node_put(np);
+	mutex_unlock(&pwrseq_list_mutex);
+
+	/* FIXME: this path can be simplified... */
+	if (!ret) {
+		dev_info(dev, "usb-pwrseq defer\n");
+		return ERR_PTR(-EPROBE_DEFER);
+	}
+
+	dev_info(dev, "allocated usb-pwrseq\n");
+
+	return ret;
+}
+EXPORT_SYMBOL_GPL(pwrseq_alloc);
+
 void pwrseq_pre_power_on(struct pwrseq *pwrseq)
 {
 	if (pwrseq && pwrseq->ops->pre_power_on)
@@ -84,6 +121,13 @@  void mmc_pwrseq_free(struct mmc_host *host)
 }
 EXPORT_SYMBOL_GPL(mmc_pwrseq_free);
 
+void pwrseq_free(const struct pwrseq *pwrseq)
+{
+	if (pwrseq)
+		module_put(pwrseq->owner);
+}
+EXPORT_SYMBOL_GPL(pwrseq_free);
+
 int pwrseq_register(struct pwrseq *pwrseq)
 {
 	if (!pwrseq || !pwrseq->ops || !pwrseq->dev)
diff --git a/include/linux/pwrseq.h b/include/linux/pwrseq.h
index fcc8fd855d4c..c3c91f50e4cb 100644
--- a/include/linux/pwrseq.h
+++ b/include/linux/pwrseq.h
@@ -31,9 +31,13 @@  void pwrseq_unregister(struct pwrseq *pwrseq);
 void pwrseq_pre_power_on(struct pwrseq *pwrseq);
 void pwrseq_post_power_on(struct pwrseq *pwrseq);
 void pwrseq_power_off(struct pwrseq *pwrseq);
+
 int mmc_pwrseq_alloc(struct mmc_host *host);
 void mmc_pwrseq_free(struct mmc_host *host);
 
+struct pwrseq *pwrseq_alloc(struct device *dev);
+void pwrseq_free(const struct pwrseq *pwrseq);
+
 #else /* CONFIG_POWER_SEQ */
 
 static inline int pwrseq_register(struct pwrseq *pwrseq)
@@ -44,9 +48,13 @@  static inline void pwrseq_unregister(struct pwrseq *pwrseq) {}
 static inline void pwrseq_pre_power_on(struct pwrseq *pwrseq) {}
 static inline void pwrseq_post_power_on(struct pwrseq *pwrseq) {}
 static inline void pwrseq_power_off(struct pwrseq *pwrseq) {}
+
 static inline int mmc_pwrseq_alloc(struct mmc_host *host) { return 0; }
 static inline void mmc_pwrseq_free(struct mmc_host *host) {}
 
+static inline struct pwrseq *pwrseq_alloc(struct device *dev) { return NULL; }
+static inline void pwrseq_free(const struct pwrseq *pwrseq) {}
+
 #endif /* CONFIG_POWER_SEQ */
 
 #endif /* _LINUX_PWRSEQ_H */