Skip to contentSkip to conversation

power: add generic power sequence framework

PATCH New Peter Chen 10 participants 29 messages Jun 17, 2016 – Jun 24, 2016

Subsystems (5)
lore
Share & tools
lore

Peter Chen

author
#0 lore raw

cover power: add generic power sequence framework

Hi all,

We have an well-known problem that the device needs to do some power sequence before it can be recognized by related host, the typical example like hard-wired mmc devices and usb devices. This power sequence is hard to be described at device tree and handled by related host driver, so we have created a common power sequence framework to handle this requirement. The generic code is supplied some common helpers from host driver, and individual power sequence driver handles kinds of power sequence for devices.

Since the MMC has already done the similar things, and this power sequence handling can be generic, we use mmc power sequence code as base to create this framework.

This patch set is based on Krzysztof Kozlowski's RFC patch set (v4.7-rc1) [1], and making some changes which can let it be generic. After that, we create a generic power sequence driver for USB devices which handles below things, it includes all input signals for devices I can consider.

- Clock and its frequencies
- GPIO for reset and the duration time
- GPIO for enable
- Regulator for power

This patch set is tested on i.mx6 sabresx evk using a dts change, I use two hot-plug devices to simulate this use case. The udoo board changes were tested using my last power sequence patch set. [2]

@Maciej S. Szmigiero, Oscar, would you please test them on imx6qdl udoo boards?
@Krzysztof Kozlowski, I have not written changes for your case since I find the other sequences have already at drivers/usb/misc/usb3503.c, this driver should be the place for your power sequence, I am not sure if enable regualator at usb core is suitable for you or not. @others, it is better you can help test this patch set for MMC devices and your USB devices with dts changes.

Thank you for your time!

[1] http://www.spinics.net/lists/linux-usb/msg142351.html
[2] http://lists.infradead.org/pipermail/linux-arm-kernel/2016-March/413580.html

Krzysztof Kozlowski (5):
power/mmc: Move pwrseq drivers to power/pwrseq
MAINTAINERS: Retain Ulf Hansson as the same maintainer of pwrseq
power: pwrseq: Enable COMPILE_TEST for drivers
power: pwrseq: Remove mmc prefix from mmc_pwrseq
power: pwrseq: Generalize mmc_pwrseq operations by removing mmc prefix

Peter Chen (7):
power: pwrseq: change common helpers as generic
power: pwrseq: rename file name for generic driver
doc: binding: pwrseq-usb-generic: add binding doc for generic usb
power sequence driver
power: pwrseq: pwrseq_usb_generic: add generic power sequence support
for USB deivces
usb: core: add power sequence handling for USB devices
usb: chipidea: host: let the hcd know's parent device node
ARM: dts: imx6qdl-udoo.dtsi: fix onboard USB HUB property

 .../{mmc => power/pwrseq}/mmc-pwrseq-simple.txt    |   0
 .../pwrseq/pwrseq-emmc.txt}                        |   0
 .../bindings/power/pwrseq/pwrseq-usb-generic.txt   |  31 ++++
 .../devicetree/bindings/usb/usb-device.txt         |   2 +
 MAINTAINERS                                        |   9 +
 arch/arm/boot/dts/imx6qdl-udoo.dtsi                |  30 +--
 drivers/mmc/Kconfig                                |   2 -
 drivers/mmc/core/Kconfig                           |  24 ---
 drivers/mmc/core/Makefile                          |   3 -
 drivers/mmc/core/core.c                            |   8 +-
 drivers/mmc/core/host.c                            |  10 +-
 drivers/mmc/core/pwrseq.h                          |  52 ------
 drivers/power/Kconfig                              |   1 +
 drivers/power/Makefile                             |   1 +
 drivers/power/pwrseq/Kconfig                       |  43 +++++
 drivers/power/pwrseq/Makefile                      |   4 +
 drivers/{mmc/core/pwrseq.c => power/pwrseq/core.c} |  71 ++++----
 drivers/{mmc/core => power/pwrseq}/pwrseq_emmc.c   |  17 +-
 .../pwrseq/pwrseq_mmc_simple.c}                    |  33 ++--
 drivers/power/pwrseq/pwrseq_usb_generic.c          | 202 +++++++++++++++++++++
 drivers/usb/chipidea/host.c                        |  18 +-
 drivers/usb/core/hub.c                             |  73 +++++++-
 drivers/usb/core/hub.h                             |   1 +
 include/linux/mmc/host.h                           |   4 +-
 include/linux/pwrseq.h                             |  61 +++++++
 25 files changed, 527 insertions(+), 173 deletions(-)
 rename Documentation/devicetree/bindings/{mmc => power/pwrseq}/mmc-pwrseq-simple.txt (100%)
 rename Documentation/devicetree/bindings/{mmc/mmc-pwrseq-emmc.txt => power/pwrseq/pwrseq-emmc.txt} (100%)
 create mode 100644 Documentation/devicetree/bindings/power/pwrseq/pwrseq-usb-generic.txt
 delete mode 100644 drivers/mmc/core/Kconfig
 delete mode 100644 drivers/mmc/core/pwrseq.h
 create mode 100644 drivers/power/pwrseq/Kconfig
 create mode 100644 drivers/power/pwrseq/Makefile
 rename drivers/{mmc/core/pwrseq.c => power/pwrseq/core.c} (51%)
 rename drivers/{mmc/core => power/pwrseq}/pwrseq_emmc.c (88%)
 rename drivers/{mmc/core/pwrseq_simple.c => power/pwrseq/pwrseq_mmc_simple.c} (81%)
 create mode 100644 drivers/power/pwrseq/pwrseq_usb_generic.c
 create mode 100644 include/linux/pwrseq.h
Signature · 1 line
1.9.1
author
#1 lore raw

PATCH 1/12 power/mmc: Move pwrseq drivers to power/pwrseq

From: Krzysztof Kozlowski <[email protected]>

The MMC power sequence drivers are useful also outside of MMC world: for USB devices needed a hard-reset before probing. Before extending and re-using pwrseq drivers, move them to a new place.

The commit does not introduce significant changes in the pwrseq drivers code so still all the functions are prefixed with "mmc_pwrseq". However the MMC-specific pwrseq functions has to be now exported and everything is hidden not by CONFIG_OF but by new CONFIG_POWER_SEQ option.

---
 .../pwrseq/pwrseq-emmc.txt}                            |  0
 .../pwrseq/pwrseq-simple.txt}                          |  0
 drivers/mmc/Kconfig                                    |  2 --
 drivers/mmc/core/Makefile                              |  3 ---
 drivers/mmc/core/core.c                                |  2 +-
 drivers/mmc/core/host.c                                |  2 +-
 drivers/power/Kconfig                                  |  1 +
 drivers/power/Makefile                                 |  1 +
 drivers/{mmc/core => power/pwrseq}/Kconfig             | 18 +++++++++++++-----
 drivers/power/pwrseq/Makefile                          |  3 +++
 drivers/{mmc/core => power/pwrseq}/pwrseq.c            |  8 ++++++--
 drivers/{mmc/core => power/pwrseq}/pwrseq_emmc.c       |  3 +--
 drivers/{mmc/core => power/pwrseq}/pwrseq_simple.c     |  3 +--
 {drivers/mmc/core => include/linux}/pwrseq.h           |  6 +++---
 14 files changed, 31 insertions(+), 21 deletions(-)
 rename Documentation/devicetree/bindings/{mmc/mmc-pwrseq-emmc.txt => power/pwrseq/pwrseq-emmc.txt} (100%)
 rename Documentation/devicetree/bindings/{mmc/mmc-pwrseq-simple.txt => power/pwrseq/pwrseq-simple.txt} (100%)
 rename drivers/{mmc/core => power/pwrseq}/Kconfig (66%)
 create mode 100644 drivers/power/pwrseq/Makefile
 rename drivers/{mmc/core => power/pwrseq}/pwrseq.c (90%)
 rename drivers/{mmc/core => power/pwrseq}/pwrseq_emmc.c (99%)
 rename drivers/{mmc/core => power/pwrseq}/pwrseq_simple.c (99%)
 rename {drivers/mmc/core => include/linux}/pwrseq.h (94%)
Documentation/devicetree/bindings/power/pwrseq/pwrseq-emmc.txt renamed from Documentation/devicetree/bindings/mmc/mmc-pwrseq-emmc.txt +0 -0
similarity index 100%
rename from Documentation/devicetree/bindings/mmc/mmc-pwrseq-emmc.txt
rename to Documentation/devicetree/bindings/power/pwrseq/pwrseq-emmc.txt
Documentation/devicetree/bindings/power/pwrseq/pwrseq-simple.txt renamed from Documentation/devicetree/bindings/mmc/mmc-pwrseq-simple.txt +0 -0
similarity index 100%
rename from Documentation/devicetree/bindings/mmc/mmc-pwrseq-simple.txt
rename to Documentation/devicetree/bindings/power/pwrseq/pwrseq-simple.txt
drivers/mmc/Kconfig +0 -2
index f2eeb38..7ade379 100644
@@ -21,8 +21,6 @@ config MMC_DEBUG
 
 if MMC
 
-source "drivers/mmc/core/Kconfig"
-
 source "drivers/mmc/card/Kconfig"
 
 source "drivers/mmc/host/Kconfig"
drivers/mmc/core/Makefile +0 -3
index f007151..a901d3c 100644
@@ -8,7 +8,4 @@ mmc_core-y			:= core.o bus.o host.o \
 				   sdio.o sdio_ops.o sdio_bus.o \
 				   sdio_cis.o sdio_io.o sdio_irq.o \
 				   quirks.o slot-gpio.o
-mmc_core-$(CONFIG_OF)		+= pwrseq.o
-obj-$(CONFIG_PWRSEQ_SIMPLE)	+= pwrseq_simple.o
-obj-$(CONFIG_PWRSEQ_EMMC)	+= pwrseq_emmc.o
 mmc_core-$(CONFIG_DEBUG_FS)	+= debugfs.o
drivers/mmc/core/core.c +1 -1
index 8b4dfd4..edefc3f 100644
@@ -25,6 +25,7 @@
 #include <linux/pm_runtime.h>
 #include <linux/pm_wakeup.h>
 #include <linux/suspend.h>
+#include <linux/pwrseq.h>
 #include <linux/fault-inject.h>
 #include <linux/random.h>
 #include <linux/slab.h>
@@ -43,7 +44,6 @@
 #include "bus.h"
 #include "host.h"
 #include "sdio_bus.h"
-#include "pwrseq.h"
 
 #include "mmc_ops.h"
 #include "sd_ops.h"
drivers/mmc/core/host.c +1 -1
index 1be42fa..1db7d58 100644
@@ -21,6 +21,7 @@
 #include <linux/export.h>
 #include <linux/leds.h>
 #include <linux/slab.h>
+#include <linux/pwrseq.h>
 
 #include <linux/mmc/host.h>
 #include <linux/mmc/card.h>
@@ -29,7 +30,6 @@
 #include "core.h"
 #include "host.h"
 #include "slot-gpio.h"
-#include "pwrseq.h"
 
 #define cls_dev_to_mmc_host(d)	container_of(d, struct mmc_host, class_dev)
 
drivers/power/Kconfig +1 -0
index 421770d..2702aca 100644
@@ -511,5 +511,6 @@ config AXP20X_POWER
 
 endif # POWER_SUPPLY
 
+source "drivers/power/pwrseq/Kconfig"
 source "drivers/power/reset/Kconfig"
 source "drivers/power/avs/Kconfig"
drivers/power/Makefile +1 -0
index e46b75d..02f9d5d 100644
@@ -71,6 +71,7 @@ obj-$(CONFIG_POWER_AVS)		+= avs/
 obj-$(CONFIG_CHARGER_SMB347)	+= smb347-charger.o
 obj-$(CONFIG_CHARGER_TPS65090)	+= tps65090-charger.o
 obj-$(CONFIG_CHARGER_TPS65217)	+= tps65217_charger.o
+obj-$(CONFIG_POWER_SEQ)		+= pwrseq/
 obj-$(CONFIG_POWER_RESET)	+= reset/
 obj-$(CONFIG_AXP288_FUEL_GAUGE) += axp288_fuel_gauge.o
 obj-$(CONFIG_AXP288_CHARGER)	+= axp288_charger.o
drivers/power/pwrseq/Kconfig renamed from drivers/mmc/core/Kconfig +13 -5
similarity index 66%
rename from drivers/mmc/core/Kconfig
rename to drivers/power/pwrseq/Kconfig
index 250f223..7ecd66a 100644
@@ -1,7 +1,13 @@
-#
-# MMC core configuration
-#
-config PWRSEQ_EMMC
+menuconfig POWER_SEQ
+	default y if OF
+	bool "Hardware reset support for specific devices"
+	help
+	  Provides drivers that implements specific power sequences for chips,
+	  using the generic power sequence management interface.
+
+if POWER_SEQ
+
+config POWER_SEQ_EMMC
 	tristate "HW reset support for eMMC"
 	default y
 	depends on OF
@@ -12,7 +18,7 @@ config PWRSEQ_EMMC
 	  This driver can also be built as a module. If so, the module
 	  will be called pwrseq_emmc.
 
-config PWRSEQ_SIMPLE
+config POWER_SEQ_SIMPLE
 	tristate "Simple HW reset support for MMC"
 	default y
 	depends on OF
@@ -22,3 +28,5 @@ config PWRSEQ_SIMPLE
 
 	  This driver can also be built as a module. If so, the module
 	  will be called pwrseq_simple.
+
+endif
drivers/power/pwrseq/Makefile new file +3 -0
new file mode 100644
index 0000000..9e40e4b
@@ -0,0 +1,3 @@
+obj-$(CONFIG_POWER_SEQ)		+= pwrseq.o
+obj-$(CONFIG_POWER_SEQ_SIMPLE)	+= pwrseq_simple.o
+obj-$(CONFIG_POWER_SEQ_EMMC)	+= pwrseq_emmc.o
drivers/power/pwrseq/pwrseq.c renamed from drivers/mmc/core/pwrseq.c +6 -2
similarity index 90%
rename from drivers/mmc/core/pwrseq.c
rename to drivers/power/pwrseq/pwrseq.c
index 9386c47..66310d7 100644
@@ -11,11 +11,10 @@
 #include <linux/err.h>
 #include <linux/module.h>
 #include <linux/of.h>
+#include <linux/pwrseq.h>
 
 #include <linux/mmc/host.h>
 
-#include "pwrseq.h"
-
 static DEFINE_MUTEX(pwrseq_list_mutex);
 static LIST_HEAD(pwrseq_list);
 
@@ -51,6 +50,7 @@ int mmc_pwrseq_alloc(struct mmc_host *host)
 
 	return 0;
 }
+EXPORT_SYMBOL_GPL(mmc_pwrseq_alloc);
 
 void mmc_pwrseq_pre_power_on(struct mmc_host *host)
 {
@@ -59,6 +59,7 @@ void mmc_pwrseq_pre_power_on(struct mmc_host *host)
 	if (pwrseq && pwrseq->ops->pre_power_on)
 		pwrseq->ops->pre_power_on(host);
 }
+EXPORT_SYMBOL_GPL(mmc_pwrseq_pre_power_on);
 
 void mmc_pwrseq_post_power_on(struct mmc_host *host)
 {
@@ -67,6 +68,7 @@ void mmc_pwrseq_post_power_on(struct mmc_host *host)
 	if (pwrseq && pwrseq->ops->post_power_on)
 		pwrseq->ops->post_power_on(host);
 }
+EXPORT_SYMBOL_GPL(mmc_pwrseq_post_power_on);
 
 void mmc_pwrseq_power_off(struct mmc_host *host)
 {
@@ -75,6 +77,7 @@ void mmc_pwrseq_power_off(struct mmc_host *host)
 	if (pwrseq && pwrseq->ops->power_off)
 		pwrseq->ops->power_off(host);
 }
+EXPORT_SYMBOL_GPL(mmc_pwrseq_power_off);
 
 void mmc_pwrseq_free(struct mmc_host *host)
 {
@@ -85,6 +88,7 @@ void mmc_pwrseq_free(struct mmc_host *host)
 		host->pwrseq = NULL;
 	}
 }
+EXPORT_SYMBOL_GPL(mmc_pwrseq_free);
 
 int mmc_pwrseq_register(struct mmc_pwrseq *pwrseq)
 {
drivers/power/pwrseq/pwrseq_emmc.c renamed from drivers/mmc/core/pwrseq_emmc.c +1 -2
similarity index 99%
rename from drivers/mmc/core/pwrseq_emmc.c
rename to drivers/power/pwrseq/pwrseq_emmc.c
index adc9c0c..a0583ed 100644
@@ -17,11 +17,10 @@
 #include <linux/err.h>
 #include <linux/gpio/consumer.h>
 #include <linux/reboot.h>
+#include <linux/pwrseq.h>
 
 #include <linux/mmc/host.h>
 
-#include "pwrseq.h"
-
 struct mmc_pwrseq_emmc {
 	struct mmc_pwrseq pwrseq;
 	struct notifier_block reset_nb;
drivers/power/pwrseq/pwrseq_simple.c renamed from drivers/mmc/core/pwrseq_simple.c +1 -2
similarity index 99%
rename from drivers/mmc/core/pwrseq_simple.c
rename to drivers/power/pwrseq/pwrseq_simple.c
index 450d907..786f1db 100644
@@ -16,11 +16,10 @@
 #include <linux/device.h>
 #include <linux/err.h>
 #include <linux/gpio/consumer.h>
+#include <linux/pwrseq.h>
 
 #include <linux/mmc/host.h>
 
-#include "pwrseq.h"
-
 struct mmc_pwrseq_simple {
 	struct mmc_pwrseq pwrseq;
 	bool clk_enabled;
include/linux/pwrseq.h renamed from drivers/mmc/core/pwrseq.h +3 -3
similarity index 94%
rename from drivers/mmc/core/pwrseq.h
rename to include/linux/pwrseq.h
index d69e751..e230670 100644
@@ -23,7 +23,7 @@ struct mmc_pwrseq {
 	struct module *owner;
 };
 
-#ifdef CONFIG_OF
+#ifdef CONFIG_POWER_SEQ
 
 int mmc_pwrseq_register(struct mmc_pwrseq *pwrseq);
 void mmc_pwrseq_unregister(struct mmc_pwrseq *pwrseq);
@@ -34,7 +34,7 @@ void mmc_pwrseq_post_power_on(struct mmc_host *host);
 void mmc_pwrseq_power_off(struct mmc_host *host);
 void mmc_pwrseq_free(struct mmc_host *host);
 
-#else
+#else /* CONFIG_POWER_SEQ */
 
 static inline int mmc_pwrseq_register(struct mmc_pwrseq *pwrseq)
 {
@@ -47,6 +47,6 @@ static inline void mmc_pwrseq_post_power_on(struct mmc_host *host) {}
 static inline void mmc_pwrseq_power_off(struct mmc_host *host) {}
 static inline void mmc_pwrseq_free(struct mmc_host *host) {}
 
-#endif
+#endif /* CONFIG_POWER_SEQ */
 
 #endif
Signature · 1 line
1.9.1
author
#2 lore raw

PATCH 2/12 MAINTAINERS: Retain Ulf Hansson as the same maintainer of pwrseq

In reply to Peter Chen

From: Krzysztof Kozlowski <[email protected]>

Before moving pwrseq drivers from drivers/mmc/core/ to drivers/power/, they were maintained by Ulf Hansson.

---
 MAINTAINERS | 9 +++++++++
 1 file changed, 9 insertions(+)
MAINTAINERS +9 -0
index ed42cb6..0bc1821 100644
@@ -9072,6 +9072,15 @@ F:	include/linux/power_supply.h
 F:	drivers/power/
 X:	drivers/power/avs/
 
+POWER SEQ CORE and DRIVERS
+M:	Ulf Hansson <[email protected]>
+L:	linux-mmc at vger.kernel.org
+T:	git git://git.linaro.org/people/ulf.hansson/mmc.git
+S:	Maintained
+F:	drivers/power/pwrseq/
+F:	include/linux/pwrseq.h
+F:	Documentation/devicetree/bindings/power/pwrseq/
+
 POWER STATE COORDINATION INTERFACE (PSCI)
 M:	Mark Rutland <[email protected]>
 M:	Lorenzo Pieralisi <[email protected]>
Signature · 1 line
1.9.1
author
#3 lore raw

PATCH 3/12 power: pwrseq: Enable COMPILE_TEST for drivers

In reply to Peter Chen

From: Krzysztof Kozlowski <[email protected]>

Allow build testing for power sequence drivers.

---
 drivers/power/pwrseq/Kconfig | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)
drivers/power/pwrseq/Kconfig +2 -2
index 7ecd66a..c7e9271 100644
@@ -10,7 +10,7 @@ if POWER_SEQ
 config POWER_SEQ_EMMC
 	tristate "HW reset support for eMMC"
 	default y
-	depends on OF
+	depends on OF || COMPILE_TEST
 	help
 	  This selects Hardware reset support aka pwrseq-emmc for eMMC
 	  devices. By default this option is set to y.
@@ -21,7 +21,7 @@ config POWER_SEQ_EMMC
 config POWER_SEQ_SIMPLE
 	tristate "Simple HW reset support for MMC"
 	default y
-	depends on OF
+	depends on OF || COMPILE_TEST
 	help
 	  This selects simple hardware reset support aka pwrseq-simple for MMC
 	  devices. By default this option is set to y.
Signature · 1 line
1.9.1
author
#4 lore raw

PATCH 4/12 power: pwrseq: Remove mmc prefix from mmc_pwrseq

In reply to Peter Chen

From: Krzysztof Kozlowski <[email protected]>

The "mmc" prefix is no longer needed after moving the pwrseq core code from mmc/ to power/.

---
 drivers/power/pwrseq/pwrseq.c        | 18 +++++++++---------
 drivers/power/pwrseq/pwrseq_emmc.c   |  8 ++++----
 drivers/power/pwrseq/pwrseq_simple.c |  8 ++++----
 include/linux/mmc/host.h             |  4 ++--
 include/linux/pwrseq.h               | 20 ++++++++++----------
 5 files changed, 29 insertions(+), 29 deletions(-)
drivers/power/pwrseq/pwrseq.c +9 -9
index 66310d7..9c66582 100644
@@ -21,7 +21,7 @@ static LIST_HEAD(pwrseq_list);
 int mmc_pwrseq_alloc(struct mmc_host *host)
 {
 	struct device_node *np;
-	struct mmc_pwrseq *p;
+	struct pwrseq *p;
 
 	np = of_parse_phandle(host->parent->of_node, "mmc-pwrseq", 0);
 	if (!np)
@@ -54,7 +54,7 @@ EXPORT_SYMBOL_GPL(mmc_pwrseq_alloc);
 
 void mmc_pwrseq_pre_power_on(struct mmc_host *host)
 {
-	struct mmc_pwrseq *pwrseq = host->pwrseq;
+	struct pwrseq *pwrseq = host->pwrseq;
 
 	if (pwrseq && pwrseq->ops->pre_power_on)
 		pwrseq->ops->pre_power_on(host);
@@ -63,7 +63,7 @@ EXPORT_SYMBOL_GPL(mmc_pwrseq_pre_power_on);
 
 void mmc_pwrseq_post_power_on(struct mmc_host *host)
 {
-	struct mmc_pwrseq *pwrseq = host->pwrseq;
+	struct pwrseq *pwrseq = host->pwrseq;
 
 	if (pwrseq && pwrseq->ops->post_power_on)
 		pwrseq->ops->post_power_on(host);
@@ -72,7 +72,7 @@ EXPORT_SYMBOL_GPL(mmc_pwrseq_post_power_on);
 
 void mmc_pwrseq_power_off(struct mmc_host *host)
 {
-	struct mmc_pwrseq *pwrseq = host->pwrseq;
+	struct pwrseq *pwrseq = host->pwrseq;
 
 	if (pwrseq && pwrseq->ops->power_off)
 		pwrseq->ops->power_off(host);
@@ -81,7 +81,7 @@ EXPORT_SYMBOL_GPL(mmc_pwrseq_power_off);
 
 void mmc_pwrseq_free(struct mmc_host *host)
 {
-	struct mmc_pwrseq *pwrseq = host->pwrseq;
+	struct pwrseq *pwrseq = host->pwrseq;
 
 	if (pwrseq) {
 		module_put(pwrseq->owner);
@@ -90,7 +90,7 @@ void mmc_pwrseq_free(struct mmc_host *host)
 }
 EXPORT_SYMBOL_GPL(mmc_pwrseq_free);
 
-int mmc_pwrseq_register(struct mmc_pwrseq *pwrseq)
+int pwrseq_register(struct pwrseq *pwrseq)
 {
 	if (!pwrseq || !pwrseq->ops || !pwrseq->dev)
 		return -EINVAL;
@@ -101,9 +101,9 @@ int mmc_pwrseq_register(struct mmc_pwrseq *pwrseq)
 
 	return 0;
 }
-EXPORT_SYMBOL_GPL(mmc_pwrseq_register);
+EXPORT_SYMBOL_GPL(pwrseq_register);
 
-void mmc_pwrseq_unregister(struct mmc_pwrseq *pwrseq)
+void pwrseq_unregister(struct pwrseq *pwrseq)
 {
 	if (pwrseq) {
 		mutex_lock(&pwrseq_list_mutex);
@@ -111,4 +111,4 @@ void mmc_pwrseq_unregister(struct mmc_pwrseq *pwrseq)
 		mutex_unlock(&pwrseq_list_mutex);
 	}
 }
-EXPORT_SYMBOL_GPL(mmc_pwrseq_unregister);
+EXPORT_SYMBOL_GPL(pwrseq_unregister);
drivers/power/pwrseq/pwrseq_emmc.c +4 -4
index a0583ed..a68ac9a 100644
@@ -22,7 +22,7 @@
 #include <linux/mmc/host.h>
 
 struct mmc_pwrseq_emmc {
-	struct mmc_pwrseq pwrseq;
+	struct pwrseq pwrseq;
 	struct notifier_block reset_nb;
 	struct gpio_desc *reset_gpio;
 };
@@ -54,7 +54,7 @@ static int mmc_pwrseq_emmc_reset_nb(struct notifier_block *this,
 	return NOTIFY_DONE;
 }
 
-static const struct mmc_pwrseq_ops mmc_pwrseq_emmc_ops = {
+static const struct pwrseq_ops mmc_pwrseq_emmc_ops = {
 	.post_power_on = mmc_pwrseq_emmc_reset,
 };
 
@@ -85,7 +85,7 @@ static int mmc_pwrseq_emmc_probe(struct platform_device *pdev)
 	pwrseq->pwrseq.owner = THIS_MODULE;
 	platform_set_drvdata(pdev, pwrseq);
 
-	return mmc_pwrseq_register(&pwrseq->pwrseq);
+	return pwrseq_register(&pwrseq->pwrseq);
 }
 
 static int mmc_pwrseq_emmc_remove(struct platform_device *pdev)
@@ -93,7 +93,7 @@ static int mmc_pwrseq_emmc_remove(struct platform_device *pdev)
 	struct mmc_pwrseq_emmc *pwrseq = platform_get_drvdata(pdev);
 
 	unregister_restart_handler(&pwrseq->reset_nb);
-	mmc_pwrseq_unregister(&pwrseq->pwrseq);
+	pwrseq_unregister(&pwrseq->pwrseq);
 
 	return 0;
 }
drivers/power/pwrseq/pwrseq_simple.c +4 -4
index 786f1db..d5fbd65 100644
@@ -21,7 +21,7 @@
 #include <linux/mmc/host.h>
 
 struct mmc_pwrseq_simple {
-	struct mmc_pwrseq pwrseq;
+	struct pwrseq pwrseq;
 	bool clk_enabled;
 	struct clk *ext_clk;
 	struct gpio_descs *reset_gpios;
@@ -77,7 +77,7 @@ static void mmc_pwrseq_simple_power_off(struct mmc_host *host)
 	}
 }
 
-static const struct mmc_pwrseq_ops mmc_pwrseq_simple_ops = {
+static const struct pwrseq_ops mmc_pwrseq_simple_ops = {
 	.pre_power_on = mmc_pwrseq_simple_pre_power_on,
 	.post_power_on = mmc_pwrseq_simple_post_power_on,
 	.power_off = mmc_pwrseq_simple_power_off,
@@ -115,14 +115,14 @@ static int mmc_pwrseq_simple_probe(struct platform_device *pdev)
 	pwrseq->pwrseq.owner = THIS_MODULE;
 	platform_set_drvdata(pdev, pwrseq);
 
-	return mmc_pwrseq_register(&pwrseq->pwrseq);
+	return pwrseq_register(&pwrseq->pwrseq);
 }
 
 static int mmc_pwrseq_simple_remove(struct platform_device *pdev)
 {
 	struct mmc_pwrseq_simple *pwrseq = platform_get_drvdata(pdev);
 
-	mmc_pwrseq_unregister(&pwrseq->pwrseq);
+	pwrseq_unregister(&pwrseq->pwrseq);
 
 	return 0;
 }
include/linux/mmc/host.h +2 -2
index 45cde8c..f3e29f4 100644
@@ -203,7 +203,7 @@ struct mmc_context_info {
 };
 
 struct regulator;
-struct mmc_pwrseq;
+struct pwrseq;
 
 struct mmc_supply {
 	struct regulator *vmmc;		/* Card power supply */
@@ -215,7 +215,7 @@ struct mmc_host {
 	struct device		class_dev;
 	int			index;
 	const struct mmc_host_ops *ops;
-	struct mmc_pwrseq	*pwrseq;
+	struct pwrseq		*pwrseq;
 	unsigned int		f_min;
 	unsigned int		f_max;
 	unsigned int		f_init;
include/linux/pwrseq.h +10 -10
index e230670..6d2d2a4 100644
@@ -5,19 +5,19 @@
  *
  * License terms: GNU General Public License (GPL) version 2
  */
-#ifndef _MMC_CORE_PWRSEQ_H
-#define _MMC_CORE_PWRSEQ_H
+#ifndef _LINUX_PWRSEQ_H
+#define _LINUX_PWRSEQ_H
 
 #include <linux/mmc/host.h>
 
-struct mmc_pwrseq_ops {
+struct pwrseq_ops {
 	void (*pre_power_on)(struct mmc_host *host);
 	void (*post_power_on)(struct mmc_host *host);
 	void (*power_off)(struct mmc_host *host);
 };
 
-struct mmc_pwrseq {
-	const struct mmc_pwrseq_ops *ops;
+struct pwrseq {
+	const struct pwrseq_ops *ops;
 	struct device *dev;
 	struct list_head pwrseq_node;
 	struct module *owner;
@@ -25,8 +25,8 @@ struct mmc_pwrseq {
 
 #ifdef CONFIG_POWER_SEQ
 
-int mmc_pwrseq_register(struct mmc_pwrseq *pwrseq);
-void mmc_pwrseq_unregister(struct mmc_pwrseq *pwrseq);
+int pwrseq_register(struct pwrseq *pwrseq);
+void pwrseq_unregister(struct pwrseq *pwrseq);
 
 int mmc_pwrseq_alloc(struct mmc_host *host);
 void mmc_pwrseq_pre_power_on(struct mmc_host *host);
@@ -36,11 +36,11 @@ void mmc_pwrseq_free(struct mmc_host *host);
 
 #else /* CONFIG_POWER_SEQ */
 
-static inline int mmc_pwrseq_register(struct mmc_pwrseq *pwrseq)
+static inline int pwrseq_register(struct pwrseq *pwrseq)
 {
 	return -ENOSYS;
 }
-static inline void mmc_pwrseq_unregister(struct mmc_pwrseq *pwrseq) {}
+static inline void pwrseq_unregister(struct pwrseq *pwrseq) {}
 static inline int mmc_pwrseq_alloc(struct mmc_host *host) { return 0; }
 static inline void mmc_pwrseq_pre_power_on(struct mmc_host *host) {}
 static inline void mmc_pwrseq_post_power_on(struct mmc_host *host) {}
@@ -49,4 +49,4 @@ static inline void mmc_pwrseq_free(struct mmc_host *host) {}
 
 #endif /* CONFIG_POWER_SEQ */
 
-#endif
+#endif /* _LINUX_PWRSEQ_H */
Signature · 1 line
1.9.1
author
#5 lore raw

PATCH 5/12 power: pwrseq: Generalize mmc_pwrseq operations by removing mmc prefix

In reply to Peter Chen

From: Krzysztof Kozlowski <[email protected]>

The power sequence hooks (mmc_pwrseq_pre_power_on(), mmc_pwrseq_post_power_on() and mmc_pwrseq_power_off()) can be made more generic to allow re-use in other subsystems. They do not need to take pointer to struct mmc_host but instead the struct pwrseq should be sufficient.

Remove the "mmc" prefix and use the pointer to struct pwrseq as argument.

---
 drivers/mmc/core/core.c              |  6 +++---
 drivers/power/pwrseq/pwrseq.c        | 24 +++++++++---------------
 drivers/power/pwrseq/pwrseq_emmc.c   |  6 ++----
 drivers/power/pwrseq/pwrseq_simple.c | 14 ++++++--------
 include/linux/pwrseq.h               | 18 +++++++++---------
 5 files changed, 29 insertions(+), 39 deletions(-)
drivers/mmc/core/core.c +3 -3
index edefc3f..09a4722 100644
@@ -1719,7 +1719,7 @@ void mmc_power_up(struct mmc_host *host, u32 ocr)
 	if (host->ios.power_mode == MMC_POWER_ON)
 		return;
 
-	mmc_pwrseq_pre_power_on(host);
+	pwrseq_pre_power_on(host->pwrseq);
 
 	host->ios.vdd = fls(ocr) - 1;
 	host->ios.power_mode = MMC_POWER_UP;
@@ -1740,7 +1740,7 @@ void mmc_power_up(struct mmc_host *host, u32 ocr)
 	 */
 	mmc_delay(10);
 
-	mmc_pwrseq_post_power_on(host);
+	pwrseq_post_power_on(host->pwrseq);
 
 	host->ios.clock = host->f_init;
 
@@ -1759,7 +1759,7 @@ void mmc_power_off(struct mmc_host *host)
 	if (host->ios.power_mode == MMC_POWER_OFF)
 		return;
 
-	mmc_pwrseq_power_off(host);
+	pwrseq_power_off(host->pwrseq);
 
 	host->ios.clock = 0;
 	host->ios.vdd = 0;
drivers/power/pwrseq/pwrseq.c +9 -15
index 9c66582..495a19d 100644
@@ -52,32 +52,26 @@ int mmc_pwrseq_alloc(struct mmc_host *host)
 }
 EXPORT_SYMBOL_GPL(mmc_pwrseq_alloc);
 
-void mmc_pwrseq_pre_power_on(struct mmc_host *host)
+void pwrseq_pre_power_on(struct pwrseq *pwrseq)
 {
-	struct pwrseq *pwrseq = host->pwrseq;
-
 	if (pwrseq && pwrseq->ops->pre_power_on)
-		pwrseq->ops->pre_power_on(host);
+		pwrseq->ops->pre_power_on(pwrseq);
 }
-EXPORT_SYMBOL_GPL(mmc_pwrseq_pre_power_on);
+EXPORT_SYMBOL_GPL(pwrseq_pre_power_on);
 
-void mmc_pwrseq_post_power_on(struct mmc_host *host)
+void pwrseq_post_power_on(struct pwrseq *pwrseq)
 {
-	struct pwrseq *pwrseq = host->pwrseq;
-
 	if (pwrseq && pwrseq->ops->post_power_on)
-		pwrseq->ops->post_power_on(host);
+		pwrseq->ops->post_power_on(pwrseq);
 }
-EXPORT_SYMBOL_GPL(mmc_pwrseq_post_power_on);
+EXPORT_SYMBOL_GPL(pwrseq_post_power_on);
 
-void mmc_pwrseq_power_off(struct mmc_host *host)
+void pwrseq_power_off(struct pwrseq *pwrseq)
 {
-	struct pwrseq *pwrseq = host->pwrseq;
-
 	if (pwrseq && pwrseq->ops->power_off)
-		pwrseq->ops->power_off(host);
+		pwrseq->ops->power_off(pwrseq);
 }
-EXPORT_SYMBOL_GPL(mmc_pwrseq_power_off);
+EXPORT_SYMBOL_GPL(pwrseq_power_off);
 
 void mmc_pwrseq_free(struct mmc_host *host)
 {
drivers/power/pwrseq/pwrseq_emmc.c +2 -4
index a68ac9a..dbb7e75 100644
@@ -19,8 +19,6 @@
 #include <linux/reboot.h>
 #include <linux/pwrseq.h>
 
-#include <linux/mmc/host.h>
-
 struct mmc_pwrseq_emmc {
 	struct pwrseq pwrseq;
 	struct notifier_block reset_nb;
@@ -37,9 +35,9 @@ static void __mmc_pwrseq_emmc_reset(struct mmc_pwrseq_emmc *pwrseq)
 	udelay(200);
 }
 
-static void mmc_pwrseq_emmc_reset(struct mmc_host *host)
+static void mmc_pwrseq_emmc_reset(struct pwrseq *_pwrseq)
 {
-	struct mmc_pwrseq_emmc *pwrseq =  to_pwrseq_emmc(host->pwrseq);
+	struct mmc_pwrseq_emmc *pwrseq = to_pwrseq_emmc(_pwrseq);
 
 	__mmc_pwrseq_emmc_reset(pwrseq);
 }
drivers/power/pwrseq/pwrseq_simple.c +6 -8
index d5fbd65..93807a6 100644
@@ -18,8 +18,6 @@
 #include <linux/gpio/consumer.h>
 #include <linux/pwrseq.h>
 
-#include <linux/mmc/host.h>
-
 struct mmc_pwrseq_simple {
 	struct pwrseq pwrseq;
 	bool clk_enabled;
@@ -46,9 +44,9 @@ static void mmc_pwrseq_simple_set_gpios_value(struct mmc_pwrseq_simple *pwrseq,
 	}
 }
 
-static void mmc_pwrseq_simple_pre_power_on(struct mmc_host *host)
+static void mmc_pwrseq_simple_pre_power_on(struct pwrseq *_pwrseq)
 {
-	struct mmc_pwrseq_simple *pwrseq = to_pwrseq_simple(host->pwrseq);
+	struct mmc_pwrseq_simple *pwrseq = to_pwrseq_simple(_pwrseq);
 
 	if (!IS_ERR(pwrseq->ext_clk) && !pwrseq->clk_enabled) {
 		clk_prepare_enable(pwrseq->ext_clk);
@@ -58,16 +56,16 @@ static void mmc_pwrseq_simple_pre_power_on(struct mmc_host *host)
 	mmc_pwrseq_simple_set_gpios_value(pwrseq, 1);
 }
 
-static void mmc_pwrseq_simple_post_power_on(struct mmc_host *host)
+static void mmc_pwrseq_simple_post_power_on(struct pwrseq *_pwrseq)
 {
-	struct mmc_pwrseq_simple *pwrseq = to_pwrseq_simple(host->pwrseq);
+	struct mmc_pwrseq_simple *pwrseq = to_pwrseq_simple(_pwrseq);
 
 	mmc_pwrseq_simple_set_gpios_value(pwrseq, 0);
 }
 
-static void mmc_pwrseq_simple_power_off(struct mmc_host *host)
+static void mmc_pwrseq_simple_power_off(struct pwrseq *_pwrseq)
 {
-	struct mmc_pwrseq_simple *pwrseq = to_pwrseq_simple(host->pwrseq);
+	struct mmc_pwrseq_simple *pwrseq = to_pwrseq_simple(_pwrseq);
 
 	mmc_pwrseq_simple_set_gpios_value(pwrseq, 1);
 
include/linux/pwrseq.h +9 -9
index 6d2d2a4..fcc8fd8 100644
@@ -11,9 +11,9 @@
 #include <linux/mmc/host.h>
 
 struct pwrseq_ops {
-	void (*pre_power_on)(struct mmc_host *host);
-	void (*post_power_on)(struct mmc_host *host);
-	void (*power_off)(struct mmc_host *host);
+	void (*pre_power_on)(struct pwrseq *pwrseq);
+	void (*post_power_on)(struct pwrseq *pwrseq);
+	void (*power_off)(struct pwrseq *pwrseq);
 };
 
 struct pwrseq {
@@ -28,10 +28,10 @@ struct pwrseq {
 int pwrseq_register(struct pwrseq *pwrseq);
 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_pre_power_on(struct mmc_host *host);
-void mmc_pwrseq_post_power_on(struct mmc_host *host);
-void mmc_pwrseq_power_off(struct mmc_host *host);
 void mmc_pwrseq_free(struct mmc_host *host);
 
 #else /* CONFIG_POWER_SEQ */
@@ -41,10 +41,10 @@ static inline int pwrseq_register(struct pwrseq *pwrseq)
 	return -ENOSYS;
 }
 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_pre_power_on(struct mmc_host *host) {}
-static inline void mmc_pwrseq_post_power_on(struct mmc_host *host) {}
-static inline void mmc_pwrseq_power_off(struct mmc_host *host) {}
 static inline void mmc_pwrseq_free(struct mmc_host *host) {}
 
 #endif /* CONFIG_POWER_SEQ */
Signature · 1 line
1.9.1
author
#6 lore raw

PATCH 6/12 power: pwrseq: change common helpers as generic

In reply to Peter Chen

These helpers are only used by mmc now, change them as generic and do corresponding changes at mmc code.

Meanwhile, change return value of helper pwrseq_pre_power_on since it may occur error during enable clock/regulator, etc.

---
 drivers/mmc/core/host.c              |  8 +++++--
 drivers/power/pwrseq/pwrseq.c        | 45 ++++++++++++++++++------------------
 drivers/power/pwrseq/pwrseq_simple.c | 10 +++++---
 include/linux/pwrseq.h               | 31 ++++++++++++++-----------
 4 files changed, 52 insertions(+), 42 deletions(-)
drivers/mmc/core/host.c +6 -2
index 1db7d58..c8ffd9b 100644
@@ -322,7 +322,11 @@ int mmc_of_parse(struct mmc_host *host)
 		host->dsr_req = 0;
 	}
 
-	return mmc_pwrseq_alloc(host);
+	host->pwrseq = pwrseq_alloc(host->parent->of_node, "mmc-pwrseq");
+	if (IS_ERR(host->pwrseq))
+		return PTR_ERR(host->pwrseq);
+	else
+		return 0;
 }
 
 EXPORT_SYMBOL(mmc_of_parse);
@@ -462,7 +466,7 @@ EXPORT_SYMBOL(mmc_remove_host);
  */
 void mmc_free_host(struct mmc_host *host)
 {
-	mmc_pwrseq_free(host);
+	pwrseq_free(host->pwrseq);
 	put_device(&host->class_dev);
 }
 
drivers/power/pwrseq/pwrseq.c +22 -23

94 lines not on this page · raw message

drivers/power/pwrseq/pwrseq_simple.c +7 -3
index 93807a6..349443f 100644
@@ -44,16 +44,20 @@ static void mmc_pwrseq_simple_set_gpios_value(struct mmc_pwrseq_simple *pwrseq,
 	}
 }
 
-static void mmc_pwrseq_simple_pre_power_on(struct pwrseq *_pwrseq)
+static int mmc_pwrseq_simple_pre_power_on(struct pwrseq *_pwrseq)
 {
 	struct mmc_pwrseq_simple *pwrseq = to_pwrseq_simple(_pwrseq);
+	int ret = 0;
 
 	if (!IS_ERR(pwrseq->ext_clk) && !pwrseq->clk_enabled) {
-		clk_prepare_enable(pwrseq->ext_clk);
-		pwrseq->clk_enabled = true;
+		ret = clk_prepare_enable(pwrseq->ext_clk);
+		if (!ret)
+			pwrseq->clk_enabled = true;
 	}
 
 	mmc_pwrseq_simple_set_gpios_value(pwrseq, 1);
+
+	return 0;
 }
 
 static void mmc_pwrseq_simple_post_power_on(struct pwrseq *_pwrseq)
include/linux/pwrseq.h +17 -14
index fcc8fd8..f726e7e 100644
@@ -8,14 +8,6 @@
 #ifndef _LINUX_PWRSEQ_H
 #define _LINUX_PWRSEQ_H
 
-#include <linux/mmc/host.h>
-
-struct pwrseq_ops {
-	void (*pre_power_on)(struct pwrseq *pwrseq);
-	void (*post_power_on)(struct pwrseq *pwrseq);
-	void (*power_off)(struct pwrseq *pwrseq);
-};
-
 struct pwrseq {
 	const struct pwrseq_ops *ops;
 	struct device *dev;
@@ -23,16 +15,23 @@ struct pwrseq {
 	struct module *owner;
 };
 
+struct pwrseq_ops {
+	int (*pre_power_on)(struct pwrseq *pwrseq);
+	void (*post_power_on)(struct pwrseq *pwrseq);
+	void (*power_off)(struct pwrseq *pwrseq);
+};
+
 #ifdef CONFIG_POWER_SEQ
 
 int pwrseq_register(struct pwrseq *pwrseq);
 void pwrseq_unregister(struct pwrseq *pwrseq);
 
-void pwrseq_pre_power_on(struct pwrseq *pwrseq);
+int 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(const struct device_node *node,
+	const char *phandle_name);
+void pwrseq_free(struct pwrseq *pwrseq);
 
 #else /* CONFIG_POWER_SEQ */
 
@@ -41,11 +40,15 @@ static inline int pwrseq_register(struct pwrseq *pwrseq)
 	return -ENOSYS;
 }
 static inline void pwrseq_unregister(struct pwrseq *pwrseq) {}
-static inline void pwrseq_pre_power_on(struct pwrseq *pwrseq) {}
+static inline int 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(const struct device_node *node,
+	const char *phandle_name)
+{
+	return NULL;
+}
+static inline void pwrseq_free(struct mmc_host *host) {}
 
 #endif /* CONFIG_POWER_SEQ */
 
Signature · 1 line
1.9.1
author
#7 lore raw

PATCH 7/12 power: pwrseq: rename file name for generic driver

In reply to Peter Chen

The individual driver file name is better to contain module name.

---
 .../power/pwrseq/{pwrseq-simple.txt => mmc-pwrseq-simple.txt}         | 0
 drivers/power/pwrseq/Makefile                                         | 4 ++--
 drivers/power/pwrseq/{pwrseq.c => core.c}                             | 0
 drivers/power/pwrseq/{pwrseq_simple.c => pwrseq_mmc_simple.c}         | 0
 4 files changed, 2 insertions(+), 2 deletions(-)
 rename Documentation/devicetree/bindings/power/pwrseq/{pwrseq-simple.txt => mmc-pwrseq-simple.txt} (100%)
 rename drivers/power/pwrseq/{pwrseq.c => core.c} (100%)
 rename drivers/power/pwrseq/{pwrseq_simple.c => pwrseq_mmc_simple.c} (100%)
Documentation/devicetree/bindings/power/pwrseq/mmc-pwrseq-simple.txt renamed from Documentation/devicetree/bindings/power/pwrseq/pwrseq-simple.txt +0 -0
similarity index 100%
rename from Documentation/devicetree/bindings/power/pwrseq/pwrseq-simple.txt
rename to Documentation/devicetree/bindings/power/pwrseq/mmc-pwrseq-simple.txt
drivers/power/pwrseq/Makefile +2 -2
index 9e40e4b..d475e01 100644
@@ -1,3 +1,3 @@
-obj-$(CONFIG_POWER_SEQ)		+= pwrseq.o
-obj-$(CONFIG_POWER_SEQ_SIMPLE)	+= pwrseq_simple.o
+obj-$(CONFIG_POWER_SEQ)		+= core.o
+obj-$(CONFIG_POWER_SEQ_SIMPLE)	+= pwrseq_mmc_simple.o
 obj-$(CONFIG_POWER_SEQ_EMMC)	+= pwrseq_emmc.o
drivers/power/pwrseq/core.c renamed from drivers/power/pwrseq/pwrseq.c +0 -0
similarity index 100%
rename from drivers/power/pwrseq/pwrseq.c
rename to drivers/power/pwrseq/core.c
drivers/power/pwrseq/pwrseq_mmc_simple.c renamed from drivers/power/pwrseq/pwrseq_simple.c +0 -0
similarity index 100%
rename from drivers/power/pwrseq/pwrseq_simple.c
rename to drivers/power/pwrseq/pwrseq_mmc_simple.c
Signature · 1 line
1.9.1
#8 lore raw

PATCH 7/12 power: pwrseq: rename file name for generic driver

Quoted 22 lines · Peter Chen

The individual driver file name is better to contain module name.

---
 .../power/pwrseq/{pwrseq-simple.txt => mmc-pwrseq-simple.txt}         | 0
 drivers/power/pwrseq/Makefile                                         | 4 ++--
 drivers/power/pwrseq/{pwrseq.c => core.c}                             | 0
 drivers/power/pwrseq/{pwrseq_simple.c => pwrseq_mmc_simple.c}         | 0
 4 files changed, 2 insertions(+), 2 deletions(-)
 rename Documentation/devicetree/bindings/power/pwrseq/{pwrseq-simple.txt => mmc-pwrseq-simple.txt} (100%)
 rename drivers/power/pwrseq/{pwrseq.c => core.c} (100%)
 rename drivers/power/pwrseq/{pwrseq_simple.c => pwrseq_mmc_simple.c} (100%)
Documentation/devicetree/bindings/power/pwrseq/mmc-pwrseq-simple.txt renamed from Documentation/devicetree/bindings/power/pwrseq/pwrseq-simple.txt +0 -0
similarity index 100%
rename from Documentation/devicetree/bindings/power/pwrseq/pwrseq-simple.txt
rename to Documentation/devicetree/bindings/power/pwrseq/mmc-pwrseq-simple.txt
drivers/power/pwrseq/Makefile +0 -0
index 9e40e4b..d475e01 100644

drivers/power/pwrseq/Makefile line 2

Quoted 4 lines
drivers/power/pwrseq/Makefile +2 -2
@@ -1,3 +1,3 @@
-obj-$(CONFIG_POWER_SEQ)		+= pwrseq.o
-obj-$(CONFIG_POWER_SEQ_SIMPLE)	+= pwrseq_simple.o
+obj-$(CONFIG_POWER_SEQ)		+= core.o
+obj-$(CONFIG_POWER_SEQ_SIMPLE)	+= pwrseq_mmc_simple.o

Although the driver was developed for MMC but it is quite generic (or rather - mmc independent). The name of the driver is just "pwrseq_simple" so I think MMC prefix is not needed.

Best regards,
Krzysztof

#9 lore raw

PATCH 7/12 power: pwrseq: rename file name for generic driver

Quoted 23 lines · Krzysztof Kozlowski
Quoted 22 lines · Peter Chen

The individual driver file name is better to contain module name.

---
 .../power/pwrseq/{pwrseq-simple.txt => mmc-pwrseq-simple.txt}         | 0
 drivers/power/pwrseq/Makefile                                         | 4 ++--
 drivers/power/pwrseq/{pwrseq.c => core.c}                             | 0
 drivers/power/pwrseq/{pwrseq_simple.c => pwrseq_mmc_simple.c}         | 0
 4 files changed, 2 insertions(+), 2 deletions(-)
 rename Documentation/devicetree/bindings/power/pwrseq/{pwrseq-simple.txt => mmc-pwrseq-simple.txt} (100%)
 rename drivers/power/pwrseq/{pwrseq.c => core.c} (100%)
 rename drivers/power/pwrseq/{pwrseq_simple.c => pwrseq_mmc_simple.c} (100%)
Documentation/devicetree/bindings/power/pwrseq/mmc-pwrseq-simple.txt renamed from Documentation/devicetree/bindings/power/pwrseq/pwrseq-simple.txt +0 -0
similarity index 100%
rename from Documentation/devicetree/bindings/power/pwrseq/pwrseq-simple.txt
rename to Documentation/devicetree/bindings/power/pwrseq/mmc-pwrseq-simple.txt
drivers/power/pwrseq/Makefile +0 -0
index 9e40e4b..d475e01 100644
@@ -1,3 +1,3 @@
Quoted 9 lines

drivers/power/pwrseq/Makefile line 2

Quoted 4 lines
drivers/power/pwrseq/Makefile +2 -2
-obj-$(CONFIG_POWER_SEQ)		+= pwrseq.o
-obj-$(CONFIG_POWER_SEQ_SIMPLE)	+= pwrseq_simple.o
+obj-$(CONFIG_POWER_SEQ)		+= core.o
+obj-$(CONFIG_POWER_SEQ_SIMPLE)	+= pwrseq_mmc_simple.o

Although the driver was developed for MMC but it is quite generic (or rather - mmc independent). The name of the driver is just "pwrseq_simple" so I think MMC prefix is not needed.

It is may be common for MMC, but not USB, or others. Eg, its reset-gpios is just like enable-gpios. Some reset chip process needs to toggle gpio.

Signature · 2 lines
Best Regards,
Peter Chen
author
#10 lore raw

PATCH 8/12 doc: binding: pwrseq-usb-generic: add binding doc for generic usb power sequence driver

In reply to Peter Chen

Add binding doc for generic usb power sequence driver, and update generic usb device binding-doc accordingly.

---
 .../bindings/power/pwrseq/pwrseq-usb-generic.txt   | 31 ++++++++++++++++++++++
 .../devicetree/bindings/usb/usb-device.txt         |  2 ++
 2 files changed, 33 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/power/pwrseq/pwrseq-usb-generic.txt
Documentation/devicetree/bindings/power/pwrseq/pwrseq-usb-generic.txt new file +31 -0
new file mode 100644
index 0000000..8ad98382
@@ -0,0 +1,31 @@
+The power sequence for generic USB Devices
+
+Some hard-wired USB devices need to do power sequence to let the
+device work normally, the typical power sequence like: enable USB
+PHY clock, toggle reset pin, etc. But current Linux USB driver
+lacks of such code to do it, it may cause some hard-wired USB devices
+works abnormal or can't be recognized by controller at all. The
+power sequence will be done before this device can be found at USB
+bus.
+
+Required properties:
+- compatible : contains "usb-pwrseq-generic".
+
+Optional properties:
+- clocks: the input clock for USB device.
+- clock-frequency: the frequency for device's clock.
+- reset-gpios: Should specify the GPIO for reset.
+- reset-duration-us: the duration in microsecond for assert reset signal.
+- enable-gpios: Should specify the GPIO for enable.
+- power-supply: The regulator of the power
+
+Example:
+
+usb2415_pwrseq: usb2415_pwrseq {
+	compatible = "usb-pwrseq-generic";
+	clocks = <&clks IMX6QDL_CLK_CKO>;
+	reset-gpios = <&gpio7 12 GPIO_ACTIVE_LOW>;
+	reset-duration-us = <3000>;
+	enable-gpios = <&gpio7 11 GPIO_ACTIVE_LOW>;
+	power-supply = <&reg_usb_power>;
+};
Documentation/devicetree/bindings/usb/usb-device.txt +2 -0
index 1c35e7b..4c8a25e 100644
@@ -12,6 +12,7 @@ Required properties:
   for usbVID,PID.
 - reg: the port number which this device is connecting to, the range
   is 1-31.
+- usb-pwrseq: phandle for power sequence.
 
 Example:
 
@@ -24,5 +25,6 @@ Example:
 	hub: genesys at 1 {
 		compatible = "usb5e3,608";
 		reg = <1>;
+		usb-pwrseq = <&usb_genesys_pwrseq>;
 	};
 }
Signature · 1 line
1.9.1
#11 lore raw

PATCH 8/12 doc: binding: pwrseq-usb-generic: add binding doc for generic usb power sequence driver

Quoted 18 lines · Peter Chen

Add binding doc for generic usb power sequence driver, and update generic usb device binding-doc accordingly.

---
 .../bindings/power/pwrseq/pwrseq-usb-generic.txt   | 31 ++++++++++++++++++++++
 .../devicetree/bindings/usb/usb-device.txt         |  2 ++
 2 files changed, 33 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/power/pwrseq/pwrseq-usb-generic.txt
Documentation/devicetree/bindings/power/pwrseq/pwrseq-usb-generic.txt new file +2 -0
new file mode 100644
index 0000000..8ad98382
@@ -0,0 +1,31 @@
+The power sequence for generic USB Devices
+

Documentation/devicetree/bindings/power/pwrseq/pwrseq-usb-generic.txt line 12

Quoted 10 lines
Documentation/devicetree/bindings/power/pwrseq/pwrseq-usb-generic.txt new file +10 -0
+Some hard-wired USB devices need to do power sequence to let the
+device work normally, the typical power sequence like: enable USB
+PHY clock, toggle reset pin, etc. But current Linux USB driver
+lacks of such code to do it, it may cause some hard-wired USB devices
+works abnormal or can't be recognized by controller at all. The
+power sequence will be done before this device can be found at USB
+bus.
+
+Required properties:
+- compatible : contains "usb-pwrseq-generic".

In case I have not been clear, no.

I am not going to accept anything along the lines of the current mmc pwrseq. I am basically okay with Krzysztof's proposal as it is *only* an added property and not a duplication of information. I'd suggest you figure out how to make the kernel work with that rather than trying to work-around whatever kernel limitations there are.

Rob

#12 lore raw

PATCH 8/12 doc: binding: pwrseq-usb-generic: add binding doc for generic usb power sequence driver

Quoted 32 lines · Rob Herring
Quoted 18 lines · Peter Chen

Add binding doc for generic usb power sequence driver, and update generic usb device binding-doc accordingly.

---
 .../bindings/power/pwrseq/pwrseq-usb-generic.txt   | 31 ++++++++++++++++++++++
 .../devicetree/bindings/usb/usb-device.txt         |  2 ++
 2 files changed, 33 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/power/pwrseq/pwrseq-usb-generic.txt
Documentation/devicetree/bindings/power/pwrseq/pwrseq-usb-generic.txt new file +2 -0
new file mode 100644
index 0000000..8ad98382
@@ -0,0 +1,31 @@
+The power sequence for generic USB Devices
+

Documentation/devicetree/bindings/power/pwrseq/pwrseq-usb-generic.txt line 12

Quoted 10 lines
Documentation/devicetree/bindings/power/pwrseq/pwrseq-usb-generic.txt new file +10 -0
+Some hard-wired USB devices need to do power sequence to let the
+device work normally, the typical power sequence like: enable USB
+PHY clock, toggle reset pin, etc. But current Linux USB driver
+lacks of such code to do it, it may cause some hard-wired USB devices
+works abnormal or can't be recognized by controller at all. The
+power sequence will be done before this device can be found at USB
+bus.
+
+Required properties:
+- compatible : contains "usb-pwrseq-generic".

In case I have not been clear, no.

Quoted 6 lines

I am not going to accept anything along the lines of the current mmc pwrseq. I am basically okay with Krzysztof's proposal as it is *only* an added property and not a duplication of information. I'd suggest you figure out how to make the kernel work with that rather than trying to work-around whatever kernel limitations there are.

I see.

Would you agree with below:

&usbotg1 {
	vbus-supply = <&reg_usb_otg1_vbus>;
	pinctrl-names = "default";
	pinctrl-0 = <&pinctrl_usb_otg1_id>;
	status = "okay";

	#address-cells = <1>;
	#size-cells = <0>;
	hub: genesys at 1 {
		compatible = "usb5e3,608";
		reg = <1>;

		power-sequence;
		reset-gpios = <&gpio4 5 GPIO_ACTIVE_LOW>; /* hub reset pin */
		reset-duration-us = <10>;
		clocks = <&clks IMX6SX_CLK_CKO>;

		#address-cells = <1>;
		#size-cells = <0>;
		ethernet: asix at 1 {
			compatible = "usbb95,1708";
			reg = <1>;

			power-sequence;
			reset-gpios = <&gpio4 6 GPIO_ACTIVE_LOW>; /* ethernet_rst */
			reset-duration-us = <15>;
			clocks = <&clks IMX6SX_CLK_IPG>;
		};
	};
};

If the node has property "power-sequence", the pwrseq core will create related platform device, and the driver under pwrseq driver will handle power sequence stuffs. The property below "power-sequence" will be handled at pwrseq driver.

Signature · 2 lines
Best Regards,
Peter Chen
#13 lore raw

PATCH 8/12 doc: binding: pwrseq-usb-generic: add binding doc for generic usb power sequence driver

Hi,

Quoted 75 lines · Peter Chen
Quoted 32 lines · Rob Herring
Quoted 18 lines · Peter Chen

Add binding doc for generic usb power sequence driver, and update generic usb device binding-doc accordingly.

---
 .../bindings/power/pwrseq/pwrseq-usb-generic.txt   | 31 ++++++++++++++++++++++
 .../devicetree/bindings/usb/usb-device.txt         |  2 ++
 2 files changed, 33 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/power/pwrseq/pwrseq-usb-generic.txt
Documentation/devicetree/bindings/power/pwrseq/pwrseq-usb-generic.txt new file +2 -0
new file mode 100644
index 0000000..8ad98382
@@ -0,0 +1,31 @@
+The power sequence for generic USB Devices
+

Documentation/devicetree/bindings/power/pwrseq/pwrseq-usb-generic.txt line 12

Quoted 10 lines
Documentation/devicetree/bindings/power/pwrseq/pwrseq-usb-generic.txt new file +10 -0
+Some hard-wired USB devices need to do power sequence to let the
+device work normally, the typical power sequence like: enable USB
+PHY clock, toggle reset pin, etc. But current Linux USB driver
+lacks of such code to do it, it may cause some hard-wired USB devices
+works abnormal or can't be recognized by controller at all. The
+power sequence will be done before this device can be found at USB
+bus.
+
+Required properties:
+- compatible : contains "usb-pwrseq-generic".

In case I have not been clear, no.

Quoted 6 lines

I am not going to accept anything along the lines of the current mmc pwrseq. I am basically okay with Krzysztof's proposal as it is *only* an added property and not a duplication of information. I'd suggest you figure out how to make the kernel work with that rather than trying to work-around whatever kernel limitations there are.

I see.

Would you agree with below:

&usbotg1 {
        vbus-supply = <&reg_usb_otg1_vbus>;
        pinctrl-names = "default";
        pinctrl-0 = <&pinctrl_usb_otg1_id>;
        status = "okay";

        #address-cells = <1>;
        #size-cells = <0>;
        hub: genesys at 1 {
                compatible = "usb5e3,608";
                reg = <1>;

                power-sequence;
                reset-gpios = <&gpio4 5 GPIO_ACTIVE_LOW>; /* hub reset pin */
                reset-duration-us = <10>;
                clocks = <&clks IMX6SX_CLK_CKO>;

                #address-cells = <1>;
                #size-cells = <0>;
                ethernet: asix at 1 {
                        compatible = "usbb95,1708";
                        reg = <1>;

                        power-sequence;
                        reset-gpios = <&gpio4 6 GPIO_ACTIVE_LOW>; /* ethernet_rst */
                        reset-duration-us = <15>;
                        clocks = <&clks IMX6SX_CLK_IPG>;
                };
        };
};
Quoted 4 lines

If the node has property "power-sequence", the pwrseq core will create related platform device, and the driver under pwrseq driver will handle power sequence stuffs. The property below "power-sequence" will be handled at pwrseq driver.

Isn't this binding what Krzysztof proposed? His series also provides example code for enabling USB device power sequencing. Does it not work for you?

Having 2 series by 2 separate people doing the same thing but slightly different is very confusing.

Regards
ChenYu

#14 lore raw

PATCH 8/12 doc: binding: pwrseq-usb-generic: add binding doc for generic usb power sequence driver

Quoted 78 lines · Chen-Yu Tsai

Hi,

Quoted 75 lines · Peter Chen
Quoted 32 lines · Rob Herring
Quoted 18 lines · Peter Chen

Add binding doc for generic usb power sequence driver, and update generic usb device binding-doc accordingly.

---
 .../bindings/power/pwrseq/pwrseq-usb-generic.txt   | 31 ++++++++++++++++++++++
 .../devicetree/bindings/usb/usb-device.txt         |  2 ++
 2 files changed, 33 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/power/pwrseq/pwrseq-usb-generic.txt
Documentation/devicetree/bindings/power/pwrseq/pwrseq-usb-generic.txt new file +2 -0
new file mode 100644
index 0000000..8ad98382
@@ -0,0 +1,31 @@
+The power sequence for generic USB Devices
+

Documentation/devicetree/bindings/power/pwrseq/pwrseq-usb-generic.txt line 12

Quoted 10 lines
Documentation/devicetree/bindings/power/pwrseq/pwrseq-usb-generic.txt new file +10 -0
+Some hard-wired USB devices need to do power sequence to let the
+device work normally, the typical power sequence like: enable USB
+PHY clock, toggle reset pin, etc. But current Linux USB driver
+lacks of such code to do it, it may cause some hard-wired USB devices
+works abnormal or can't be recognized by controller at all. The
+power sequence will be done before this device can be found at USB
+bus.
+
+Required properties:
+- compatible : contains "usb-pwrseq-generic".

In case I have not been clear, no.

Quoted 6 lines

I am not going to accept anything along the lines of the current mmc pwrseq. I am basically okay with Krzysztof's proposal as it is *only* an added property and not a duplication of information. I'd suggest you figure out how to make the kernel work with that rather than trying to work-around whatever kernel limitations there are.

I see.

Would you agree with below:

&usbotg1 {
        vbus-supply = <&reg_usb_otg1_vbus>;
        pinctrl-names = "default";
        pinctrl-0 = <&pinctrl_usb_otg1_id>;
        status = "okay";

        #address-cells = <1>;
        #size-cells = <0>;
        hub: genesys at 1 {
                compatible = "usb5e3,608";
                reg = <1>;

                power-sequence;
                reset-gpios = <&gpio4 5 GPIO_ACTIVE_LOW>; /* hub reset pin */
                reset-duration-us = <10>;
                clocks = <&clks IMX6SX_CLK_CKO>;

                #address-cells = <1>;
                #size-cells = <0>;
                ethernet: asix at 1 {
                        compatible = "usbb95,1708";
                        reg = <1>;

                        power-sequence;
                        reset-gpios = <&gpio4 6 GPIO_ACTIVE_LOW>; /* ethernet_rst */
                        reset-duration-us = <15>;
                        clocks = <&clks IMX6SX_CLK_IPG>;
                };
        };
};
Quoted 8 lines
Quoted 4 lines

If the node has property "power-sequence", the pwrseq core will create related platform device, and the driver under pwrseq driver will handle power sequence stuffs. The property below "power-sequence" will be handled at pwrseq driver.

Isn't this binding what Krzysztof proposed? His series also provides example code for enabling USB device power sequencing. Does it not work for you?

In this series, I just change RFC to formal patch, and finished his example code. USB power sequence should be described on USB bus, not platform bus.

Signature · 2 lines
Best Regards,
Peter Chen
maintainer
#15 lore raw

PATCH 8/12 doc: binding: pwrseq-usb-generic: add binding doc for generic usb power sequence driver

In reply to Peter Chen
Quoted 40 lines · Peter Chen
Quoted 32 lines · Rob Herring
Quoted 18 lines · Peter Chen

Add binding doc for generic usb power sequence driver, and update generic usb device binding-doc accordingly.

---
 .../bindings/power/pwrseq/pwrseq-usb-generic.txt   | 31 ++++++++++++++++++++++
 .../devicetree/bindings/usb/usb-device.txt         |  2 ++
 2 files changed, 33 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/power/pwrseq/pwrseq-usb-generic.txt
Documentation/devicetree/bindings/power/pwrseq/pwrseq-usb-generic.txt new file +2 -0
new file mode 100644
index 0000000..8ad98382
@@ -0,0 +1,31 @@
+The power sequence for generic USB Devices
+

Documentation/devicetree/bindings/power/pwrseq/pwrseq-usb-generic.txt line 12

Quoted 10 lines
Documentation/devicetree/bindings/power/pwrseq/pwrseq-usb-generic.txt new file +10 -0
+Some hard-wired USB devices need to do power sequence to let the
+device work normally, the typical power sequence like: enable USB
+PHY clock, toggle reset pin, etc. But current Linux USB driver
+lacks of such code to do it, it may cause some hard-wired USB devices
+works abnormal or can't be recognized by controller at all. The
+power sequence will be done before this device can be found at USB
+bus.
+
+Required properties:
+- compatible : contains "usb-pwrseq-generic".

In case I have not been clear, no.

Quoted 6 lines

I am not going to accept anything along the lines of the current mmc pwrseq. I am basically okay with Krzysztof's proposal as it is *only* an added property and not a duplication of information. I'd suggest you figure out how to make the kernel work with that rather than trying to work-around whatever kernel limitations there are.

Quoted 3 lines

I see.

Would you agree with below:

In general, yes. There are some points being discussed in the other thread.

Quoted 7 lines
&usbotg1 {
	vbus-supply = <&reg_usb_otg1_vbus>;
	pinctrl-names = "default";
	pinctrl-0 = <&pinctrl_usb_otg1_id>;
	status = "okay";

	#address-cells = <1>;
Quoted 8 lines
	#size-cells = <0>;
	hub: genesys at 1 {
		compatible = "usb5e3,608";
		reg = <1>;

		power-sequence;
		reset-gpios = <&gpio4 5 GPIO_ACTIVE_LOW>; /* hub reset pin */
		reset-duration-us = <10>;

I wonder if this really needs to be specified. A sufficiently long default should be good enough for 90 something % of devices.

Quoted 16 lines
		clocks = <&clks IMX6SX_CLK_CKO>;

		#address-cells = <1>;
		#size-cells = <0>;
		ethernet: asix at 1 {
			compatible = "usbb95,1708";
			reg = <1>;

			power-sequence;
			reset-gpios = <&gpio4 6 GPIO_ACTIVE_LOW>; /* ethernet_rst */
			reset-duration-us = <15>;
			clocks = <&clks IMX6SX_CLK_IPG>;
		};
	};
};
Quoted 3 lines

If the node has property "power-sequence", the pwrseq core will create related platform device, and the driver under pwrseq driver will handle power sequence stuffs.

This I have issue with. If you are creating a platform device here, you are trying to work-around limitations in the linux driver model. Either we need some sort of pre-probe hook to the drivers to call or each parent node driver is responsible for checking and calling pwr-seq functions for child nodes. e.g. The host controller calls pwr-seq for the hub, the hub driver calls the power seq for the asix chip. Soon as we have a case too complex for the generic pwr-seq, we're going to need the pre-probe hook as I don't want to see a continual expansion of generic pwr-seq binding for ever more complex cases.

Quoted 2 lines

The property below "power-sequence" will be
handled at pwrseq driver.

You cannot rely on order other than for logical readability. There are no guarantees of either the dtb or kernel ordering of properties.

Rob

#16 lore raw

PATCH 8/12 doc: binding: pwrseq-usb-generic: add binding doc for generic usb power sequence driver

Quoted 6 lines · Rob Herring
Quoted 3 lines · Peter Chen

If the node has property "power-sequence", the pwrseq core will create related platform device, and the driver under pwrseq driver will handle power sequence stuffs.

Quoted 9 lines

This I have issue with. If you are creating a platform device here, you are trying to work-around limitations in the linux driver model. Either we need some sort of pre-probe hook to the drivers to call or each parent node driver is responsible for checking and calling pwr-seq functions for child nodes. e.g. The host controller calls pwr-seq for the hub, the hub driver calls the power seq for the asix chip. Soon as we have a case too complex for the generic pwr-seq, we're going to need the pre-probe hook as I don't want to see a continual expansion of generic pwr-seq binding for ever more complex cases.

I think it's fairly clear that we need one or both of these mechanisms
for enumerable buses in embedded contexts - it's something that keeps
croping up.
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 473 bytes
Desc: not available
URL: <http://lists.infradead.org/pipermail/linux-arm-kernel/attachments/20160620/fb903add/attachment.sig>

#17 lore raw

PATCH 8/12 doc: binding: pwrseq-usb-generic: add binding doc for generic usb power sequence driver

In reply to Rob Herring
Quoted 60 lines · Rob Herring
Quoted 40 lines · Peter Chen
Quoted 32 lines · Rob Herring
Quoted 18 lines · Peter Chen

Add binding doc for generic usb power sequence driver, and update generic usb device binding-doc accordingly.

---
 .../bindings/power/pwrseq/pwrseq-usb-generic.txt   | 31 ++++++++++++++++++++++
 .../devicetree/bindings/usb/usb-device.txt         |  2 ++
 2 files changed, 33 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/power/pwrseq/pwrseq-usb-generic.txt
Documentation/devicetree/bindings/power/pwrseq/pwrseq-usb-generic.txt new file +2 -0
new file mode 100644
index 0000000..8ad98382
@@ -0,0 +1,31 @@
+The power sequence for generic USB Devices
+

Documentation/devicetree/bindings/power/pwrseq/pwrseq-usb-generic.txt line 12

Quoted 10 lines
Documentation/devicetree/bindings/power/pwrseq/pwrseq-usb-generic.txt new file +10 -0
+Some hard-wired USB devices need to do power sequence to let the
+device work normally, the typical power sequence like: enable USB
+PHY clock, toggle reset pin, etc. But current Linux USB driver
+lacks of such code to do it, it may cause some hard-wired USB devices
+works abnormal or can't be recognized by controller at all. The
+power sequence will be done before this device can be found at USB
+bus.
+
+Required properties:
+- compatible : contains "usb-pwrseq-generic".

In case I have not been clear, no.

Quoted 6 lines

I am not going to accept anything along the lines of the current mmc pwrseq. I am basically okay with Krzysztof's proposal as it is *only* an added property and not a duplication of information. I'd suggest you figure out how to make the kernel work with that rather than trying to work-around whatever kernel limitations there are.

Quoted 3 lines

I see.

Would you agree with below:

In general, yes. There are some points being discussed in the other thread.

Quoted 12 lines
&usbotg1 {
	vbus-supply = <&reg_usb_otg1_vbus>;
	pinctrl-names = "default";
	pinctrl-0 = <&pinctrl_usb_otg1_id>;
	status = "okay";

	#address-cells = <1>;
	#size-cells = <0>;
	hub: genesys at 1 {
		compatible = "usb5e3,608";
		reg = <1>;
Quoted 7 lines
Quoted 3 lines
		power-sequence;
		reset-gpios = <&gpio4 5 GPIO_ACTIVE_LOW>; /* hub reset pin */
		reset-duration-us = <10>;

I wonder if this really needs to be specified. A sufficiently long default should be good enough for 90 something % of devices.

This property is optional, there is a default value in pwrseq driver.

Quoted 16 lines
Quoted 16 lines
		clocks = <&clks IMX6SX_CLK_CKO>;

		#address-cells = <1>;
		#size-cells = <0>;
		ethernet: asix at 1 {
			compatible = "usbb95,1708";
			reg = <1>;

			power-sequence;
			reset-gpios = <&gpio4 6 GPIO_ACTIVE_LOW>; /* ethernet_rst */
			reset-duration-us = <15>;
			clocks = <&clks IMX6SX_CLK_IPG>;
		};
	};
};
Quoted 6 lines
Quoted 3 lines

If the node has property "power-sequence", the pwrseq core will create related platform device, and the driver under pwrseq driver will handle power sequence stuffs.

This I have issue with. If you are creating a platform device here, you are trying to work-around limitations in the linux driver model.

My current solution like below, but it seems you didn't agree with that. I just double confirm here, if you don't, I give up the solution for using generic power sequence framework.

In drivers/usb/core/hub.c

	for_each_child_of_node(parent->of_node, node) {
		hdev_pwrseq = pwrseq_alloc(node, "usb_pwrseq_generic");
		if (!IS_ERR_OR_NULL(hdev_pwrseq)) {
			pwrseq_node = kzalloc(sizeof(pwrseq_node), GFP_KERNEL);
			if (!pwrseq_node) {
				ret = -ENOMEM;
				goto err1;
			}
			/* power on sequence */
			ret = pwrseq_pre_power_on(hdev_pwrseq);
			if (ret)
				goto err2;

			pwrseq_node->pwrseq_on = hdev_pwrseq;
			list_add(&pwrseq_node->list, &hub->pwrseq_list);
		} else if (IS_ERR(hdev_pwrseq)) {
			return PTR_ERR(hdev_pwrseq);
		}
	}

In drivers/power/pwrseq/core.c

struct pwrseq *pwrseq_alloc(struct device_node *np, const char *dev_name)

{
	struct pwrseq *p, *pwrseq = NULL;
	bool created;

	/* If there is no device is associated with this node, create it */
	if (!of_find_device_by_node(np)) {
		if (of_platform_device_create(np, dev_name, NULL))
			created = true;
		else
			return ERR_PTR(-ENODEV);
	}

	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(p->dev,
					"increasing module refcount failed\n");
			else
				pwrseq = p;
			break;
		}
	}

And there is a platform driver at drivers/power/pwrseq/pwrseq_usb_generic.c to handle these pwrseq properties, see my patch 9/12.

Quoted 9 lines

Either
we need some sort of pre-probe hook to the drivers to call or each parent node driver is responsible for checking and calling pwr-seq functions for child nodes. e.g. The host controller calls pwr-seq for the hub, the hub driver calls the power seq for the asix chip. Soon as we have a case too complex for the generic pwr-seq, we're going to need the pre-probe hook as I don't want to see a continual expansion of generic pwr-seq binding for ever more complex cases.

How the driver know what it needs to handle (eg, gpio, clock) if there is no device for it? The most important we need to consider is which device owns there power sequence properties, then the corresponding driver can handle it.

Signature · 2 lines
Best Regards,
Peter Chen
maintainer
#18 lore raw

PATCH 8/12 doc: binding: pwrseq-usb-generic: add binding doc for generic usb power sequence driver

Quoted 6 lines · Peter Chen
Quoted 5 lines · Rob Herring
Quoted 4 lines · Peter Chen
Quoted 3 lines · Rob Herring
Quoted 2 lines · Peter Chen

Add binding doc for generic usb power sequence driver, and update generic usb device binding-doc accordingly.

[...]

Quoted 29 lines
Quoted 16 lines
Quoted 16 lines
		clocks = <&clks IMX6SX_CLK_CKO>;

		#address-cells = <1>;
		#size-cells = <0>;
		ethernet: asix at 1 {
			compatible = "usbb95,1708";
			reg = <1>;

			power-sequence;
			reset-gpios = <&gpio4 6 GPIO_ACTIVE_LOW>; /* ethernet_rst */
			reset-duration-us = <15>;
			clocks = <&clks IMX6SX_CLK_IPG>;
		};
	};
};
Quoted 6 lines
Quoted 3 lines

If the node has property "power-sequence", the pwrseq core will create related platform device, and the driver under pwrseq driver will handle power sequence stuffs.

This I have issue with. If you are creating a platform device here, you are trying to work-around limitations in the linux driver model.

My current solution like below, but it seems you didn't agree with that. I just double confirm here, if you don't, I give up the solution for using generic power sequence framework.

In drivers/usb/core/hub.c

Quoted 10 lines
	for_each_child_of_node(parent->of_node, node) {
		hdev_pwrseq = pwrseq_alloc(node, "usb_pwrseq_generic");
		if (!IS_ERR_OR_NULL(hdev_pwrseq)) {
			pwrseq_node = kzalloc(sizeof(pwrseq_node), GFP_KERNEL);
			if (!pwrseq_node) {
				ret = -ENOMEM;
				goto err1;
			}
			/* power on sequence */
			ret = pwrseq_pre_power_on(hdev_pwrseq);

Why does this function need to do anything more than:

- Check if the child has a "power-sequence" property
- Get the "reset-gpios" GPIO
- Assert reset for specified/default time
- Deassert reset

Then continue on as normal. That seems straight-forward to me.

There is no reason you need a platform device in the mix. Perhaps trying to move the MMC pwr-seq code is pointless as it adds needless complexity.

[...]

Quoted 10 lines
Quoted 9 lines

Either
we need some sort of pre-probe hook to the drivers to call or each parent node driver is responsible for checking and calling pwr-seq functions for child nodes. e.g. The host controller calls pwr-seq for the hub, the hub driver calls the power seq for the asix chip. Soon as we have a case too complex for the generic pwr-seq, we're going to need the pre-probe hook as I don't want to see a continual expansion of generic pwr-seq binding for ever more complex cases.

Quoted 4 lines

How the driver know what it needs to handle (eg, gpio, clock) if there is no device for it? The most important we need to consider is which device owns there power sequence properties, then the corresponding driver can handle it.

What can be handled by is defined by presence of power-sequence property. There can be 1 driver for the device. That is the USB hub driver in this example. You should not have 2 "devices".

Rob

#19 lore raw

PATCH 8/12 doc: binding: pwrseq-usb-generic: add binding doc for generic usb power sequence driver

Quoted 50 lines · Rob Herring
Quoted 6 lines · Peter Chen
Quoted 5 lines · Rob Herring
Quoted 4 lines · Peter Chen
Quoted 3 lines · Rob Herring
Quoted 2 lines · Peter Chen

Add binding doc for generic usb power sequence driver, and update generic usb device binding-doc accordingly.

[...]

Quoted 29 lines
Quoted 16 lines
Quoted 16 lines
		clocks = <&clks IMX6SX_CLK_CKO>;

		#address-cells = <1>;
		#size-cells = <0>;
		ethernet: asix at 1 {
			compatible = "usbb95,1708";
			reg = <1>;

			power-sequence;
			reset-gpios = <&gpio4 6 GPIO_ACTIVE_LOW>; /* ethernet_rst */
			reset-duration-us = <15>;
			clocks = <&clks IMX6SX_CLK_IPG>;
		};
	};
};
Quoted 6 lines
Quoted 3 lines

If the node has property "power-sequence", the pwrseq core will create related platform device, and the driver under pwrseq driver will handle power sequence stuffs.

This I have issue with. If you are creating a platform device here, you are trying to work-around limitations in the linux driver model.

My current solution like below, but it seems you didn't agree with that. I just double confirm here, if you don't, I give up the solution for using generic power sequence framework.

In drivers/usb/core/hub.c

Quoted 10 lines
	for_each_child_of_node(parent->of_node, node) {
		hdev_pwrseq = pwrseq_alloc(node, "usb_pwrseq_generic");
		if (!IS_ERR_OR_NULL(hdev_pwrseq)) {
			pwrseq_node = kzalloc(sizeof(pwrseq_node), GFP_KERNEL);
			if (!pwrseq_node) {
				ret = -ENOMEM;
				goto err1;
			}
			/* power on sequence */
			ret = pwrseq_pre_power_on(hdev_pwrseq);
Quoted 7 lines

Why does this function need to do anything more than:

- Check if the child has a "power-sequence" property
- Get the "reset-gpios" GPIO
- Assert reset for specified/default time
- Deassert reset

Besides gpios, it may exist clock and regulator operation, and the operation may be failed. I thought these operations can be easy done belongs to a device, but now, let me try this straight-forward way, thanks.

Peter

Quoted 28 lines

Then continue on as normal. That seems straight-forward to me.

There is no reason you need a platform device in the mix. Perhaps trying to move the MMC pwr-seq code is pointless as it adds needless complexity.

[...]

Quoted 10 lines
Quoted 9 lines

Either
we need some sort of pre-probe hook to the drivers to call or each parent node driver is responsible for checking and calling pwr-seq functions for child nodes. e.g. The host controller calls pwr-seq for the hub, the hub driver calls the power seq for the asix chip. Soon as we have a case too complex for the generic pwr-seq, we're going to need the pre-probe hook as I don't want to see a continual expansion of generic pwr-seq binding for ever more complex cases.

Quoted 4 lines

How the driver know what it needs to handle (eg, gpio, clock) if there is no device for it? The most important we need to consider is which device owns there power sequence properties, then the corresponding driver can handle it.

What can be handled by is defined by presence of power-sequence property. There can be 1 driver for the device. That is the USB hub driver in this example. You should not have 2 "devices".

Rob

Signature · 2 lines
Best Regards,
Peter Chen
#20 lore raw

PATCH 8/12 doc: binding: pwrseq-usb-generic: add binding doc for generic usb power sequence driver

In reply to Rob Herring
Quoted 26 lines · Rob Herring
Quoted 6 lines · Peter Chen
Quoted 5 lines · Rob Herring
Quoted 4 lines · Peter Chen
Quoted 3 lines · Rob Herring
Quoted 2 lines · Peter Chen

Add binding doc for generic usb power sequence driver, and update generic usb device binding-doc accordingly.

[...]

Quoted 16 lines
Quoted 16 lines
Quoted 16 lines
          clocks = <&clks IMX6SX_CLK_CKO>;

          #address-cells = <1>;
          #size-cells = <0>;
          ethernet: asix at 1 {
                  compatible = "usbb95,1708";
                  reg = <1>;

                  power-sequence;
                  reset-gpios = <&gpio4 6 GPIO_ACTIVE_LOW>; /* ethernet_rst */
                  reset-duration-us = <15>;
                  clocks = <&clks IMX6SX_CLK_IPG>;
          };

};
};

Quoted 6 lines
Quoted 6 lines
Quoted 6 lines
Quoted 3 lines

If the node has property "power-sequence", the pwrseq core will create related platform device, and the driver under pwrseq driver will handle power sequence stuffs.

This I have issue with. If you are creating a platform device here, you are trying to work-around limitations in the linux driver model.

I somewhat understand your point.

Although, having the option to use a driver (which requires a device) has turned out to be quite convenient from many aspects - at least in the mmc case.

Certainly one can do without it, but in the end using a driver avoids open coding.

Quoted 25 lines
Quoted 7 lines

My current solution like below, but it seems you didn't agree with that. I just double confirm here, if you don't, I give up the solution for using generic power sequence framework.

In drivers/usb/core/hub.c

Quoted 10 lines
      for_each_child_of_node(parent->of_node, node) {
              hdev_pwrseq = pwrseq_alloc(node, "usb_pwrseq_generic");
              if (!IS_ERR_OR_NULL(hdev_pwrseq)) {
                      pwrseq_node = kzalloc(sizeof(pwrseq_node), GFP_KERNEL);
                      if (!pwrseq_node) {
                              ret = -ENOMEM;
                              goto err1;
                      }
                      /* power on sequence */
                      ret = pwrseq_pre_power_on(hdev_pwrseq);

Why does this function need to do anything more than:

- Check if the child has a "power-sequence" property
- Get the "reset-gpios" GPIO
- Assert reset for specified/default time
- Deassert reset

Quoted 5 lines

Then continue on as normal. That seems straight-forward to me.

There is no reason you need a platform device in the mix. Perhaps trying to move the MMC pwr-seq code is pointless as it adds needless complexity.

Complexity?

The problem we are tying to solve, is to make the various platform/SoC specific power sequences to be able to live in generic drivers.

One could decide to encode the sequences inside the driver code itself, but it will soon turn into a mess and more importantly, lots of open coding as to support different platforms/SoCs. To most kernel hackers I don't think this is an option to consider.

The MMC pwr-seq code/drivers tries to address these issues - in a somewhat generic way.
Initially we have decided to start with only a few flavours of supported sequences and so far these have been sufficient.

Finally, I am indeed concerned that it so hard to agree on a solution to deal with generic power sequences. There have been many attempts throughout the last ~4-5 years, but peoples strong opinions about different approaches mad them all fail. Isn't it time to finally just pick a solution and stick with it, even if it doesn't meet all peoples expectations?

[...]

Kind regards
Uffe

maintainer
#21 lore raw

PATCH 8/12 doc: binding: pwrseq-usb-generic: add binding doc for generic usb power sequence driver

Quoted 34 lines · Ulf Hansson
Quoted 26 lines · Rob Herring
Quoted 6 lines · Peter Chen
Quoted 5 lines · Rob Herring
Quoted 4 lines · Peter Chen
Quoted 3 lines · Rob Herring
Quoted 2 lines · Peter Chen

Add binding doc for generic usb power sequence driver, and update generic usb device binding-doc accordingly.

[...]

Quoted 16 lines
Quoted 16 lines
Quoted 16 lines
          clocks = <&clks IMX6SX_CLK_CKO>;

          #address-cells = <1>;
          #size-cells = <0>;
          ethernet: asix at 1 {
                  compatible = "usbb95,1708";
                  reg = <1>;

                  power-sequence;
                  reset-gpios = <&gpio4 6 GPIO_ACTIVE_LOW>; /* ethernet_rst */
                  reset-duration-us = <15>;
                  clocks = <&clks IMX6SX_CLK_IPG>;
          };

};
};

Quoted 6 lines
Quoted 6 lines
Quoted 6 lines
Quoted 3 lines

If the node has property "power-sequence", the pwrseq core will create related platform device, and the driver under pwrseq driver will handle power sequence stuffs.

This I have issue with. If you are creating a platform device here, you are trying to work-around limitations in the linux driver model.

Quoted 8 lines

I somewhat understand your point.

Although, having the option to use a driver (which requires a device) has turned out to be quite convenient from many aspects - at least in the mmc case.

Certainly one can do without it, but in the end using a driver avoids open coding.

Why would it be open coded? Just create library functions to parse the node and implement the generic pwr-seq steps.

Quoted 32 lines
Quoted 24 lines
Quoted 6 lines

My current solution like below, but it seems you didn't agree with that. I just double confirm here, if you don't, I give up the solution for using generic power sequence framework.

In drivers/usb/core/hub.c

Quoted 10 lines
      for_each_child_of_node(parent->of_node, node) {
              hdev_pwrseq = pwrseq_alloc(node, "usb_pwrseq_generic");
              if (!IS_ERR_OR_NULL(hdev_pwrseq)) {
                      pwrseq_node = kzalloc(sizeof(pwrseq_node), GFP_KERNEL);
                      if (!pwrseq_node) {
                              ret = -ENOMEM;
                              goto err1;
                      }
                      /* power on sequence */
                      ret = pwrseq_pre_power_on(hdev_pwrseq);

Why does this function need to do anything more than:

- Check if the child has a "power-sequence" property
- Get the "reset-gpios" GPIO
- Assert reset for specified/default time
- Deassert reset

Quoted 5 lines

Then continue on as normal. That seems straight-forward to me.

There is no reason you need a platform device in the mix. Perhaps trying to move the MMC pwr-seq code is pointless as it adds needless complexity.

Complexity?

Quoted 7 lines

The problem we are tying to solve, is to make the various platform/SoC specific power sequences to be able to live in generic drivers.

One could decide to encode the sequences inside the driver code itself, but it will soon turn into a mess and more importantly, lots of open coding as to support different platforms/SoCs. To most kernel hackers I don't think this is an option to consider.

I'm not proposing open coding, but having generic library functions. I'm not saying the mmc pwr-seq has to change from being a driver either. Leave it as is. I'm only talking about Krzysztof's new proposal.

Quoted 4 lines

The MMC pwr-seq code/drivers tries to address these issues - in a somewhat generic way.
Initially we have decided to start with only a few flavours of supported sequences and so far these have been sufficient.

Only a few because we've pushed back against defining state machines in DT.

Quoted 6 lines

Finally, I am indeed concerned that it so hard to agree on a solution to deal with generic power sequences. There have been many attempts throughout the last ~4-5 years, but peoples strong opinions about different approaches mad them all fail. Isn't it time to finally just pick a solution and stick with it, even if it doesn't meet all peoples expectations?

No. I'm pretty that is not how kernel development works. Features get merged when all are happy (or not paying attention).

Quoted 1 line

From what I recall, all attempts have worked around the problem that

the driver model has no way to either force probe or provide a pre-probe hook on probeable buses. This then leads to the work-around defining the DT binding.

Rob

author
#22 lore raw

PATCH 9/12 power: pwrseq: pwrseq_usb_generic: add generic power sequence support for USB deivces

In reply to Peter Chen

Add driver for generic power sequence support for USB deivces which handles below things:

- Clock and its frequencies
- GPIO for reset and the duration time
- GPIO for enable
- Regulator for power

---
 drivers/power/pwrseq/Kconfig              |  11 ++
 drivers/power/pwrseq/Makefile             |   1 +
 drivers/power/pwrseq/pwrseq_usb_generic.c | 202 ++++++++++++++++++++++++++++++
 3 files changed, 214 insertions(+)
 create mode 100644 drivers/power/pwrseq/pwrseq_usb_generic.c
drivers/power/pwrseq/Kconfig +11 -0
index c7e9271..9749c6d 100644
@@ -29,4 +29,15 @@ config POWER_SEQ_SIMPLE
 	  This driver can also be built as a module. If so, the module
 	  will be called pwrseq_simple.
 
+config POWER_SEQ_USB_GENERIC
+	tristate "Generic power sequence support for USB devices"
+	default y
+	depends on OF || COMPILE_TEST
+	help
+	  This selects generic power sequence support for USB devices.
+	  By default this option is set to y.
+
+	  This driver can also be built as a module. If so, the module
+	  will be called pwrseq_usb_generic.
+
 endif
drivers/power/pwrseq/Makefile +1 -0
index d475e01..230bb45 100644
@@ -1,3 +1,4 @@
 obj-$(CONFIG_POWER_SEQ)		+= core.o
 obj-$(CONFIG_POWER_SEQ_SIMPLE)	+= pwrseq_mmc_simple.o
 obj-$(CONFIG_POWER_SEQ_EMMC)	+= pwrseq_emmc.o
+obj-$(CONFIG_POWER_SEQ_USB_GENERIC)	+= pwrseq_usb_generic.o
drivers/power/pwrseq/pwrseq_usb_generic.c new file +202 -0

202 lines not on this page · raw message

Signature · 1 line
1.9.1
author
#23 lore raw

PATCH 10/12 usb: core: add power sequence handling for USB devices

In reply to Peter Chen

Some hard-wired USB devices need to do power sequence to let the device work normally, the typical power sequence like: enable USB PHY clock, toggle reset pin, etc. But current Linux USB driver lacks of such code to do it, it may cause some hard-wired USB devices works abnormal or can't be recognized by controller at all.

In this patch, it will do power on sequence at hub's probe for all devices under this hub (includes root hub) if this device is described at dts and there is a phandle "usb-pwrseq" for it.

At hub_disconnect, it will do power off sequence which is at powered on list.

---
 drivers/usb/core/hub.c | 73 +++++++++++++++++++++++++++++++++++++++++++++++---
 drivers/usb/core/hub.h |  1 +
 include/linux/pwrseq.h |  6 +++++
 3 files changed, 77 insertions(+), 3 deletions(-)
drivers/usb/core/hub.c +70 -3
index bee1351..cc0f942 100644
@@ -26,6 +26,7 @@
 #include <linux/mutex.h>
 #include <linux/random.h>
 #include <linux/pm_qos.h>
+#include <linux/pwrseq.h>
 
 #include <asm/uaccess.h>
 #include <asm/byteorder.h>
@@ -1684,6 +1685,66 @@ static void hub_release(struct kref *kref)
 
 static unsigned highspeed_hubs;
 
+static void hub_of_pwrseq_off(struct usb_interface *intf)
+{
+	struct usb_hub *hub = usb_get_intfdata(intf);
+	struct pwrseq *hdev_pwrseq;
+	struct pwrseq_node_powered_on *pwrseq_node, *tmp_node;
+
+	list_for_each_entry_safe(pwrseq_node, tmp_node,
+			&hub->pwrseq_list, list) {
+		hdev_pwrseq = pwrseq_node->pwrseq_on;
+		pwrseq_power_off(hdev_pwrseq);
+		list_del(&pwrseq_node->list);
+		pwrseq_free(hdev_pwrseq);
+		kfree(pwrseq_node);
+	}
+}
+
+static int hub_of_pwrseq_on(struct usb_interface *intf)
+{
+	struct device *parent;
+	struct device_node *node;
+	struct pwrseq *hdev_pwrseq;
+	struct usb_device *hdev = interface_to_usbdev(intf);
+	struct usb_hub *hub = usb_get_intfdata(intf);
+	struct pwrseq_node_powered_on *pwrseq_node;
+	int ret = 0;
+
+	if (hdev->parent)
+		parent = &hdev->dev;
+	else
+		parent = bus_to_hcd(hdev->bus)->self.controller;
+
+	for_each_child_of_node(parent->of_node, node) {
+		hdev_pwrseq = pwrseq_alloc(node, "usb-pwrseq");
+		if (!IS_ERR_OR_NULL(hdev_pwrseq)) {
+			pwrseq_node = kzalloc(sizeof(pwrseq_node), GFP_KERNEL);
+			if (!pwrseq_node) {
+				ret = -ENOMEM;
+				goto err1;
+			}
+			/* power on sequence */
+			ret = pwrseq_pre_power_on(hdev_pwrseq);
+			if (ret)
+				goto err2;
+
+			pwrseq_node->pwrseq_on = hdev_pwrseq;
+			list_add(&pwrseq_node->list, &hub->pwrseq_list);
+		} else if (IS_ERR(hdev_pwrseq)) {
+			return PTR_ERR(hdev_pwrseq);
+		}
+	}
+
+	return ret;
+
+err2:
+	kfree(pwrseq_node);
+err1:
+	pwrseq_free(hdev_pwrseq);
+	return ret;
+}
+
 static void hub_disconnect(struct usb_interface *intf)
 {
 	struct usb_hub *hub = usb_get_intfdata(intf);
@@ -1700,6 +1761,7 @@ static void hub_disconnect(struct usb_interface *intf)
 	hub->error = 0;
 	hub_quiesce(hub, HUB_DISCONNECT);
 
+	hub_of_pwrseq_off(intf);
 	mutex_lock(&usb_port_peer_mutex);
 
 	/* Avoid races with recursively_mark_NOTATTACHED() */
@@ -1733,6 +1795,7 @@ static int hub_probe(struct usb_interface *intf, const struct usb_device_id *id)
 	struct usb_endpoint_descriptor *endpoint;
 	struct usb_device *hdev;
 	struct usb_hub *hub;
+	int ret = -ENODEV;
 
 	desc = intf->cur_altsetting;
 	hdev = interface_to_usbdev(intf);
@@ -1839,6 +1902,7 @@ descriptor_error:
 	INIT_DELAYED_WORK(&hub->leds, led_work);
 	INIT_DELAYED_WORK(&hub->init_work, NULL);
 	INIT_WORK(&hub->events, hub_event);
+	INIT_LIST_HEAD(&hub->pwrseq_list);
 	usb_get_intf(intf);
 	usb_get_dev(hdev);
 
@@ -1852,11 +1916,14 @@ descriptor_error:
 	if (id->driver_info & HUB_QUIRK_CHECK_PORT_AUTOSUSPEND)
 		hub->quirk_check_port_auto_suspend = 1;
 
-	if (hub_configure(hub, endpoint) >= 0)
-		return 0;
+	if (hub_configure(hub, endpoint) >= 0) {
+		ret = hub_of_pwrseq_on(intf);
+		if (!ret)
+			return 0;
+	}
 
 	hub_disconnect(intf);
-	return -ENODEV;
+	return ret;
 }
 
 static int
drivers/usb/core/hub.h +1 -0
index 34c1a7e..f52169c 100644
@@ -78,6 +78,7 @@ struct usb_hub {
 	struct delayed_work	init_work;
 	struct work_struct      events;
 	struct usb_port		**ports;
+	struct list_head	pwrseq_list; /* powered on pwrseq node list */
 };
 
 /**
include/linux/pwrseq.h +6 -0
index f726e7e..36dde42 100644
@@ -15,6 +15,12 @@ struct pwrseq {
 	struct module *owner;
 };
 
+/* This structure is used for recording powered on pwrseq node */
+struct pwrseq_node_powered_on {
+	struct pwrseq *pwrseq_on;
+	struct list_head list;
+};
+
 struct pwrseq_ops {
 	int (*pre_power_on)(struct pwrseq *pwrseq);
 	void (*post_power_on)(struct pwrseq *pwrseq);
Signature · 1 line
1.9.1
#24 lore raw

PATCH 10/12 usb: core: add power sequence handling for USB devices

Quoted 33 lines · Peter Chen

Some hard-wired USB devices need to do power sequence to let the device work normally, the typical power sequence like: enable USB PHY clock, toggle reset pin, etc. But current Linux USB driver lacks of such code to do it, it may cause some hard-wired USB devices works abnormal or can't be recognized by controller at all.

In this patch, it will do power on sequence at hub's probe for all devices under this hub (includes root hub) if this device is described at dts and there is a phandle "usb-pwrseq" for it.

At hub_disconnect, it will do power off sequence which is at powered on list.

---
 drivers/usb/core/hub.c | 73 +++++++++++++++++++++++++++++++++++++++++++++++---
 drivers/usb/core/hub.h |  1 +
 include/linux/pwrseq.h |  6 +++++
 3 files changed, 77 insertions(+), 3 deletions(-)
drivers/usb/core/hub.c +1 -0
index bee1351..cc0f942 100644
@@ -26,6 +26,7 @@
 #include <linux/mutex.h>
 #include <linux/random.h>
 #include <linux/pm_qos.h>
+#include <linux/pwrseq.h>
 
 #include <asm/uaccess.h>
 #include <asm/byteorder.h>

drivers/usb/core/hub.c static void hub_release(struct kref *kref) · line 1690

Quoted 6 lines
drivers/usb/core/hub.c +3 -0
@@ -1684,6 +1685,66 @@ static void hub_release(struct kref *kref)
 
 static unsigned highspeed_hubs;
 
+static void hub_of_pwrseq_off(struct usb_interface *intf)
+{
+	struct usb_hub *hub = usb_get_intfdata(intf);

It would be easier to pass hub as the argument instead of intf.

Otherwise this looks okay to me.

Alan Stern

author
#25 lore raw

PATCH 11/12 usb: chipidea: host: let the hcd know's parent device node

In reply to Peter Chen

From: Peter Chen <[email protected]>

Since the hcd (chipidea core device) has no device node, so if we want to describe the child node under the hcd, we had to put it under its parent's node (glue layer device), and in the code, we need to let the hcd knows glue layer's code, then the USB core can handle this node.

---
 drivers/usb/chipidea/host.c | 18 ++++++++++++++----
 1 file changed, 14 insertions(+), 4 deletions(-)
drivers/usb/chipidea/host.c +14 -4
index 053bac9..55120ef 100644
@@ -109,15 +109,25 @@ static int host_start(struct ci_hdrc *ci)
 	struct ehci_hcd *ehci;
 	struct ehci_ci_priv *priv;
 	int ret;
+	struct device *dev = ci->dev;
 
-	if (usb_disabled())
+	if (usb_disabled() || !dev)
 		return -ENODEV;
 
-	hcd = usb_create_hcd(&ci_ehci_hc_driver, ci->dev, dev_name(ci->dev));
+	/*
+	 * USB Core will try to get child node under roothub,
+	 * but chipidea core has no of_node, and the child node
+	 * for controller is located at glue layer's node which
+	 * is chipidea core's parent.
+	 */
+	if (dev->parent && dev->parent->of_node)
+		dev->of_node = dev->parent->of_node;
+
+	hcd = usb_create_hcd(&ci_ehci_hc_driver, dev, dev_name(dev));
 	if (!hcd)
 		return -ENOMEM;
 
-	dev_set_drvdata(ci->dev, ci);
+	dev_set_drvdata(dev, ci);
 	hcd->rsrc_start = ci->hw_bank.phys;
 	hcd->rsrc_len = ci->hw_bank.size;
 	hcd->regs = ci->hw_bank.abs;
@@ -143,7 +153,7 @@ static int host_start(struct ci_hdrc *ci)
 		if (ci->platdata->flags & CI_HDRC_TURN_VBUS_EARLY_ON) {
 			ret = regulator_enable(ci->platdata->reg_vbus);
 			if (ret) {
-				dev_err(ci->dev,
+				dev_err(dev,
 				"Failed to enable vbus regulator, ret=%d\n",
 									ret);
 				goto put_hcd;
Signature · 1 line
1.9.1
author
#26 lore raw

PATCH 12/12 ARM: dts: imx6qdl-udoo.dtsi: fix onboard USB HUB property

In reply to Peter Chen

From: Peter Chen <[email protected]>

The current dts describes USB HUB's property at USB controller's entry, it is improper. The USB HUB should be the child node under USB controller, with "usb-pwrseq" phandle to handle power sequence stuffs.

---
 arch/arm/boot/dts/imx6qdl-udoo.dtsi | 30 +++++++++++++++++-------------
 1 file changed, 17 insertions(+), 13 deletions(-)
arch/arm/boot/dts/imx6qdl-udoo.dtsi +17 -13
index 3bee2f9..f921174 100644
@@ -9,6 +9,8 @@
  *
  */
 
+#include <dt-bindings/gpio/gpio.h>
+
 / {
 	aliases {
 		backlight = &backlight;
@@ -58,17 +60,6 @@
 		#address-cells = <1>;
 		#size-cells = <0>;
 
-		reg_usb_h1_vbus: regulator at 0 {
-			compatible = "regulator-fixed";
-			reg = <0>;
-			regulator-name = "usb_h1_vbus";
-			regulator-min-microvolt = <5000000>;
-			regulator-max-microvolt = <5000000>;
-			enable-active-high;
-			startup-delay-us = <2>; /* USB2415 requires a POR of 1 us minimum */
-			gpio = <&gpio7 12 0>;
-		};
-
 		reg_panel: regulator at 1 {
 			compatible = "regulator-fixed";
 			reg = <1>;
@@ -89,6 +80,13 @@
 		mux-int-port = <1>;
 		mux-ext-port = <6>;
 	};
+
+	usb2415_pwrseq: usb2415_pwrseq {
+		compatible = "usb-pwrseq-generic";
+		clocks = <&clks IMX6QDL_CLK_CKO>;
+		reset-gpios = <&gpio7 12 GPIO_ACTIVE_LOW>;
+		reset-duration-us = <3000>;
+	};
 };
 
 &fec {
@@ -259,9 +257,15 @@
 &usbh1 {
 	pinctrl-names = "default";
 	pinctrl-0 = <&pinctrl_usbh>;
-	vbus-supply = <&reg_usb_h1_vbus>;
-	clocks = <&clks IMX6QDL_CLK_CKO>;
 	status = "okay";
+
+	#address-cells = <1>;
+	#size-cells = <0>;
+	hub: usb2415 at 1 {
+		compatible = "usb424,2514";
+		reg = <1>;
+		usb-pwrseq = <&usb2415_pwrseq>;
+	};
 };
 
 &usdhc3 {
Signature · 1 line
1.9.1
#27 lore raw

cover power: add generic power sequence framework

In reply to Peter Chen

Hi Peter,

Quoted 25 lines · Peter Chen

Hi all,

We have an well-known problem that the device needs to do some power sequence before it can be recognized by related host, the typical example like hard-wired mmc devices and usb devices. This power sequence is hard to be described at device tree and handled by related host driver, so we have created a common power sequence framework to handle this requirement. The generic code is supplied some common helpers from host driver, and individual power sequence driver handles kinds of power sequence for devices.

Since the MMC has already done the similar things, and this power sequence handling can be generic, we use mmc power sequence code as base to create this framework.

This patch set is based on Krzysztof Kozlowski's RFC patch set (v4.7-rc1) [1], and making some changes which can let it be generic. After that, we create a generic power sequence driver for USB devices which handles below things, it includes all input signals for devices I can consider.

- Clock and its frequencies
- GPIO for reset and the duration time
- GPIO for enable
- Regulator for power

Quoted 6 lines

This patch set is tested on i.mx6 sabresx evk using a dts change, I use two hot-plug devices to simulate this use case. The udoo board changes were tested using my last power sequence patch set. [2]

@Maciej S. Szmigiero, Oscar, would you please test them on imx6qdl udoo boards?

Thanks for the patch set, just tested them on my UDOO Quad board and can confirm that USB and on-board hub work fine.

Maciej

#28 lore raw

cover power: add generic power sequence framework

Quoted 35 lines · Maciej S. Szmigiero

Hi Peter,

Quoted 25 lines · Peter Chen

Hi all,

We have an well-known problem that the device needs to do some power sequence before it can be recognized by related host, the typical example like hard-wired mmc devices and usb devices. This power sequence is hard to be described at device tree and handled by related host driver, so we have created a common power sequence framework to handle this requirement. The generic code is supplied some common helpers from host driver, and individual power sequence driver handles kinds of power sequence for devices.

Since the MMC has already done the similar things, and this power sequence handling can be generic, we use mmc power sequence code as base to create this framework.

This patch set is based on Krzysztof Kozlowski's RFC patch set (v4.7-rc1) [1], and making some changes which can let it be generic. After that, we create a generic power sequence driver for USB devices which handles below things, it includes all input signals for devices I can consider.

- Clock and its frequencies
- GPIO for reset and the duration time
- GPIO for enable
- Regulator for power

Quoted 6 lines

This patch set is tested on i.mx6 sabresx evk using a dts change, I use two hot-plug devices to simulate this use case. The udoo board changes were tested using my last power sequence patch set. [2]

@Maciej S. Szmigiero, Oscar, would you please test them on imx6qdl udoo boards?

Quoted 7 lines

Thanks for the patch set, just tested them on my UDOO Quad board and can confirm that USB and on-board hub work fine.

Maciej

Many thanks, Maciej.

Signature · 2 lines
Best Regards,
Peter Chen