This patchset adds a generic USB repeater framework to be used by
platforms that have eUSB2 support and want to have USB 2.0 compliance.
In such cases there is a device between the eUSB2 PHY and the actual
connector. That device is basically a repeater and the most important
thing it does is to level shift in both directions. Such a device needs
to be controlled in software usually by the PHY or by the HC.
So add a generic framework with basic ops to allow consumer drivers
to get a phandle to it and to control it.
Also add the SM8550 PMIC eUSB2 repeater which uses the generic
framework.
Abel Vesa (3):
usb: Add USB repeater generic framework
dt-bindings: usb: Add qcom,snps-eusb2-repeater schema
usb: repeater: Add Qualcomm PMIC eUSB2 driver
.../usb/qcom,snps-eusb2-repeater.yaml | 43 +++
drivers/usb/Kconfig | 2 +
drivers/usb/Makefile | 2 +
drivers/usb/repeater/Kconfig | 20 ++
drivers/usb/repeater/Makefile | 7 +
.../usb/repeater/repeater-qcom-pmic-eusb2.c | 251 ++++++++++++++++++
drivers/usb/repeater/repeater.c | 198 ++++++++++++++
include/linux/usb/repeater.h | 78 ++++++
8 files changed, 601 insertions(+)
create mode 100644 Documentation/devicetree/bindings/usb/qcom,snps-eusb2-repeater.yaml
create mode 100644 drivers/usb/repeater/Kconfig
create mode 100644 drivers/usb/repeater/Makefile
create mode 100644 drivers/usb/repeater/repeater-qcom-pmic-eusb2.c
create mode 100644 drivers/usb/repeater/repeater.c
create mode 100644 include/linux/usb/repeater.h
--
2.34.1
PM8550B contains a eUSB2 repeater used for making the eUSB2 from
SM8550 USB 2.0 compliant.
Add a platform specific repeater driver. It implements ops for init,
reset and power on/off. On init, there is a configuration table that
needs to be written to the repeater's registers.
Signed-off-by: Abel Vesa <[email protected]>
---
drivers/usb/repeater/Kconfig | 11 +
drivers/usb/repeater/Makefile | 1 +
.../usb/repeater/repeater-qcom-pmic-eusb2.c | 251 ++++++++++++++++++
3 files changed, 263 insertions(+)
create mode 100644 drivers/usb/repeater/repeater-qcom-pmic-eusb2.c
diff --git a/drivers/usb/repeater/Kconfig b/drivers/usb/repeater/Kconfig
index e12cd22c0adb..20baeb8f950c 100644
--- a/drivers/usb/repeater/Kconfig
+++ b/drivers/usb/repeater/Kconfig
@@ -7,3 +7,14 @@ config USB_REPEATER
driver to bind together and to provide the USB driver ways to perform
set of operations with repeater for USB2 functionality using PHY and
controller driver.
+
+config QCOM_PMIC_EUSB2_REPEATER
+ tristate "USB eUSB2 Repeater driver"
+ select USB_REPEATER
+ help
+ Enable this to support the USB eUSB2 repeater on Qualcomm PMIC chips.
+ This driver provides support to reset, initialize, power up and configure
+ the eUSB2 repeater for USB HS/FS/LS functionality where eUSB2 repeater
+ is used.
+
+ To compile the driver as a module, choose M here.
diff --git a/drivers/usb/repeater/Makefile b/drivers/usb/repeater/Makefile
index 2d1b5f348976..fed128407315 100644
--- a/drivers/usb/repeater/Makefile
+++ b/drivers/usb/repeater/Makefile
@@ -4,3 +4,4 @@
#
obj-$(CONFIG_USB_REPEATER) += repeater.o
+obj-$(CONFIG_QCOM_PMIC_EUSB2_REPEATER) += repeater-qcom-pmic-eusb2.o
diff --git a/drivers/usb/repeater/repeater-qcom-pmic-eusb2.c b/drivers/usb/repeater/repeater-qcom-pmic-eusb2.c
new file mode 100644
index 000000000000..1b6d46c28da4
--- /dev/null
+++ b/drivers/usb/repeater/repeater-qcom-pmic-eusb2.c
@@ -0,0 +1,251 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (c) 2022, Qualcomm Innovation Center, Inc. All rights reserved.
+ * Copyright (c) 2022, Linaro Limited
+ */
+
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/regulator/consumer.h>
+#include <linux/regmap.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
+
+#include <linux/usb/repeater.h>
+
+/* eUSB2 status registers */
+#define EUSB2_RPTR_STATUS 0x08
+#define RPTR_OK BIT(7)
+
+/* eUSB2 control registers */
+#define EUSB2_EN_CTL1 0x46
+#define EUSB2_RPTR_EN BIT(7)
+
+#define PHY_HOST_MODE BIT(0)
+#define EUSB2_FORCE_EN_5 0xE8
+#define F_CLK_19P2M_EN BIT(6)
+#define F_CLK_19P2M_EN_SHIFT 6
+
+#define EUSB2_FORCE_VAL_5 0xED
+#define V_CLK_19P2M_EN BIT(6)
+#define V_CLK_19P2M_EN_SHIFT 6
+
+#define EUSB2_TUNE_IUSB2 0x51
+#define EUSB2_TUNE_SQUELCH_U 0x54
+#define EUSB2_TUNE_USB2_PREEM 0x57
+
+#define QCOM_EUSB2_REPEATER_INIT_CFG(o, v) \
+ { \
+ .offset = o, \
+ .val = v, \
+ }
+
+#define to_qcom_eusb2_repeater(x) \
+ container_of((x), struct qcom_eusb2_repeater, repeater)
+
+struct qcom_eusb2_repeater_init_tbl {
+ unsigned int offset;
+ unsigned int val;
+};
+
+struct qcom_eusb2_repeater {
+ struct usb_repeater repeater;
+ struct regmap *regmap;
+ u16 base;
+ struct regulator_bulk_data *vregs;
+ const struct qcom_eusb2_repeater_cfg *cfg;
+};
+
+struct qcom_eusb2_repeater_cfg {
+ const struct qcom_eusb2_repeater_init_tbl *init_tbl;
+ int init_tbl_num;
+ /* regulators to be requested */
+ const char * const *vreg_list;
+ int num_vregs;
+};
+
+static const char * const pm8550b_vreg_l[] = {
+ "vdd18", "vdd3",
+};
+
+static const struct qcom_eusb2_repeater_init_tbl pm8550b_init_tbl[] = {
+ QCOM_EUSB2_REPEATER_INIT_CFG(EUSB2_TUNE_IUSB2, 0x8),
+ QCOM_EUSB2_REPEATER_INIT_CFG(EUSB2_TUNE_SQUELCH_U, 0x3),
+ QCOM_EUSB2_REPEATER_INIT_CFG(EUSB2_TUNE_USB2_PREEM, 0x5),
+};
+
+static const struct qcom_eusb2_repeater_cfg pm8550b_eusb2_cfg = {
+ .init_tbl = pm8550b_init_tbl,
+ .init_tbl_num = ARRAY_SIZE(pm8550b_init_tbl),
+ .vreg_list = pm8550b_vreg_l,
+ .num_vregs = ARRAY_SIZE(pm8550b_vreg_l),
+};
+
+static int qcom_eusb2_repeater_init_vregs(struct qcom_eusb2_repeater *rptr)
+{
+ int num = rptr->cfg->num_vregs;
+ struct device *dev = rptr->repeater.dev;
+ int i;
+
+ rptr->vregs = devm_kcalloc(dev, num, sizeof(*rptr->vregs), GFP_KERNEL);
+ if (!rptr->vregs)
+ return -ENOMEM;
+
+ for (i = 0; i < num; i++)
+ rptr->vregs[i].supply = rptr->cfg->vreg_list[i];
+
+ return devm_regulator_bulk_get(dev, num, rptr->vregs);
+}
+
+static int qcom_eusb2_repeater_cfg_init(struct qcom_eusb2_repeater *rptr)
+{
+ const struct qcom_eusb2_repeater_init_tbl *init_tbl = rptr->cfg->init_tbl;
+ int num = rptr->cfg->init_tbl_num;
+ int i;
+
+ for (i = 0; i < num; i++)
+ regmap_update_bits(rptr->regmap, rptr->base + init_tbl[i].offset,
+ init_tbl[i].val, init_tbl[i].val);
+ return 0;
+}
+
+static int qcom_eusb2_repeater_init(struct usb_repeater *r)
+{
+ struct qcom_eusb2_repeater *rptr = to_qcom_eusb2_repeater(r);
+ int ret = 0;
+ u32 val;
+
+ qcom_eusb2_repeater_cfg_init(rptr);
+
+ if (r->flags & PHY_HOST_MODE) {
+ /*
+ * CM.Lx is prohibited when repeater is already into Lx state as
+ * per eUSB 1.2 Spec. Below implement software workaround until
+ * PHY and controller is fixing seen observation.
+ */
+ regmap_update_bits(rptr->regmap, rptr->base + EUSB2_FORCE_EN_5,
+ F_CLK_19P2M_EN, F_CLK_19P2M_EN);
+ regmap_update_bits(rptr->regmap, rptr->base + EUSB2_FORCE_VAL_5,
+ V_CLK_19P2M_EN, V_CLK_19P2M_EN);
+ } else {
+ /*
+ * In device mode clear host mode related workaround as there
+ * is no repeater reset available, and enable/disable of
+ * repeater doesn't clear previous value due to shared
+ * regulators (say host <-> device mode switch).
+ */
+ regmap_update_bits(rptr->regmap, rptr->base + EUSB2_FORCE_EN_5,
+ F_CLK_19P2M_EN, 0);
+ regmap_update_bits(rptr->regmap, rptr->base + EUSB2_FORCE_VAL_5,
+ V_CLK_19P2M_EN, 0);
+ }
+
+ ret = regmap_read_poll_timeout(rptr->regmap, rptr->base + EUSB2_RPTR_STATUS, val,
+ val & RPTR_OK, 10, 5);
+ if (ret)
+ dev_err(r->dev, "initialization timed-out\n");
+
+ return ret;
+}
+
+static int qcom_eusb2_repeater_reset(struct usb_repeater *r, bool assert)
+{
+ struct qcom_eusb2_repeater *rptr = to_qcom_eusb2_repeater(r);
+
+ return regmap_update_bits(rptr->regmap, rptr->base + EUSB2_EN_CTL1,
+ EUSB2_RPTR_EN, assert ? EUSB2_RPTR_EN : 0x0);
+}
+
+static int qcom_eusb2_repeater_power_on(struct usb_repeater *r)
+{
+ struct qcom_eusb2_repeater *rptr = to_qcom_eusb2_repeater(r);
+
+ return regulator_bulk_enable(rptr->cfg->num_vregs, rptr->vregs);
+}
+
+static int qcom_eusb2_repeater_power_off(struct usb_repeater *r)
+{
+ struct qcom_eusb2_repeater *rptr = to_qcom_eusb2_repeater(r);
+
+ return regulator_bulk_disable(rptr->cfg->num_vregs, rptr->vregs);
+}
+
+static int qcom_eusb2_repeater_probe(struct platform_device *pdev)
+{
+ struct qcom_eusb2_repeater *rptr;
+ struct device *dev = &pdev->dev;
+ struct device_node *node;
+ u32 res;
+ int ret;
+
+ node = dev->of_node;
+
+ rptr = devm_kzalloc(dev, sizeof(*rptr), GFP_KERNEL);
+ if (!rptr)
+ return -ENOMEM;
+
+ rptr->repeater.dev = dev;
+ dev_set_drvdata(dev, rptr);
+
+ /* Get the specific init parameters of QMP phy */
+ rptr->cfg = of_device_get_match_data(dev);
+ if (!rptr->cfg)
+ return -EINVAL;
+
+ rptr->regmap = dev_get_regmap(dev->parent, NULL);
+ if (!rptr->regmap)
+ return -ENXIO;
+
+ ret = of_property_read_u32(node, "reg", &res);
+ if (ret < 0)
+ return ret;
+
+ rptr->base = res;
+
+ ret = qcom_eusb2_repeater_init_vregs(rptr);
+ if (ret < 0) {
+ dev_err(dev, "unable to get supplies\n");
+ return ret;
+ }
+
+ rptr->repeater.init = qcom_eusb2_repeater_init;
+ rptr->repeater.reset = qcom_eusb2_repeater_reset;
+ rptr->repeater.power_on = qcom_eusb2_repeater_power_on;
+ rptr->repeater.power_off = qcom_eusb2_repeater_power_off;
+
+ return usb_add_repeater_dev(&rptr->repeater);
+}
+
+static int qcom_eusb2_repeater_remove(struct platform_device *pdev)
+{
+ struct qcom_eusb2_repeater *rptr = platform_get_drvdata(pdev);
+
+ if (!rptr)
+ return 0;
+
+ usb_remove_repeater_dev(&rptr->repeater);
+ qcom_eusb2_repeater_power_off(&rptr->repeater);
+ return 0;
+}
+
+static const struct of_device_id qcom_eusb2_repeater_id_table[] = {
+ {
+ .compatible = "qcom,pm8550b-eusb2-repeater",
+ .data = &pm8550b_eusb2_cfg,
+ },
+ { },
+};
+MODULE_DEVICE_TABLE(of, qcom_eusb2_repeater_id_table);
+
+static struct platform_driver qcom_eusb2_repeater_driver = {
+ .probe = qcom_eusb2_repeater_probe,
+ .remove = qcom_eusb2_repeater_remove,
+ .driver = {
+ .name = "qcom-pmic-eusb2-repeater",
+ .of_match_table = of_match_ptr(qcom_eusb2_repeater_id_table),
+ },
+};
+
+module_platform_driver(qcom_eusb2_repeater_driver);
+MODULE_DESCRIPTION("Qualcomm PMIC eUSB2 repeater driver");
+MODULE_LICENSE("GPL");
--
2.34.1
Add dt-binding schema for the Qualcomm SNPS eUSB2 repeater.
Signed-off-by: Abel Vesa <[email protected]>
---
.../usb/qcom,snps-eusb2-repeater.yaml | 43 +++++++++++++++++++
1 file changed, 43 insertions(+)
create mode 100644 Documentation/devicetree/bindings/usb/qcom,snps-eusb2-repeater.yaml
diff --git a/Documentation/devicetree/bindings/usb/qcom,snps-eusb2-repeater.yaml b/Documentation/devicetree/bindings/usb/qcom,snps-eusb2-repeater.yaml
new file mode 100644
index 000000000000..f2b5ace675eb
--- /dev/null
+++ b/Documentation/devicetree/bindings/usb/qcom,snps-eusb2-repeater.yaml
@@ -0,0 +1,43 @@
+# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/usb/qcom,snps-eusb2-repeater.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Qualcomm Synopsis eUSB2 to USB 2.0 repeater
+
+maintainers:
+ - Abel Vesa <[email protected]>
+
+properties:
+ compatible:
+ const: qcom,pm8550b-eusb2-repeater
+
+ reg:
+ maxItems: 1
+
+ vdd18-supply: true
+
+ vdd3-supply: true
+
+required:
+ - compatible
+ - reg
+
+additionalProperties: false
+
+examples:
+ - |
+ #include <dt-bindings/spmi/spmi.h>
+ pm8550b: pmic@7 {
+ compatible = "qcom,pm8550", "qcom,spmi-pmic";
+ reg = <0x7 SPMI_USID>;
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ pm8550b_eusb2_repeater: usb-repeater@fd00 {
+ compatible = "qcom,pm8550b-eusb2-repeater";
+ reg = <0xfd00>;
+ };
+ };
+...
--
2.34.1
With more SoCs moving towards eUSB2, such platforms will have to use
a USB 2.0 compliance repeater. This repeater HW-wise usually deals with
level shifting, but depending on the implementation it can do much more.
So add a ganeric USB framework that would allow either a generic PHY or
some USB host controller to control and get a repeater from a devicetree
phandle. This framework will further be used by platform specific
drivers to register the repeater and implement platform specific ops.
Signed-off-by: Abel Vesa <[email protected]>
---
drivers/usb/Kconfig | 2 +
drivers/usb/Makefile | 2 +
drivers/usb/repeater/Kconfig | 9 ++
drivers/usb/repeater/Makefile | 6 +
drivers/usb/repeater/repeater.c | 198 ++++++++++++++++++++++++++++++++
include/linux/usb/repeater.h | 78 +++++++++++++
6 files changed, 295 insertions(+)
create mode 100644 drivers/usb/repeater/Kconfig
create mode 100644 drivers/usb/repeater/Makefile
create mode 100644 drivers/usb/repeater/repeater.c
create mode 100644 include/linux/usb/repeater.h
diff --git a/drivers/usb/Kconfig b/drivers/usb/Kconfig
index a871a988829d..c9ad102a0fa9 100644
--- a/drivers/usb/Kconfig
+++ b/drivers/usb/Kconfig
@@ -176,6 +176,8 @@ source "drivers/usb/gadget/Kconfig"
source "drivers/usb/typec/Kconfig"
+source "drivers/usb/repeater/Kconfig"
+
source "drivers/usb/roles/Kconfig"
endif # USB_SUPPORT
diff --git a/drivers/usb/Makefile b/drivers/usb/Makefile
index a81e6ef293af..c96c66304edd 100644
--- a/drivers/usb/Makefile
+++ b/drivers/usb/Makefile
@@ -67,4 +67,6 @@ obj-$(CONFIG_USBIP_CORE) += usbip/
obj-$(CONFIG_TYPEC) += typec/
+obj-$(CONFIG_USB_REPEATER) += repeater/
+
obj-$(CONFIG_USB_ROLE_SWITCH) += roles/
diff --git a/drivers/usb/repeater/Kconfig b/drivers/usb/repeater/Kconfig
new file mode 100644
index 000000000000..e12cd22c0adb
--- /dev/null
+++ b/drivers/usb/repeater/Kconfig
@@ -0,0 +1,9 @@
+# SPDX-License-Identifier: GPL-2.0
+
+config USB_REPEATER
+ tristate "USB Repeater Framework"
+ help
+ Enable this to allow the USB PHY drivers and the connected repeater
+ driver to bind together and to provide the USB driver ways to perform
+ set of operations with repeater for USB2 functionality using PHY and
+ controller driver.
diff --git a/drivers/usb/repeater/Makefile b/drivers/usb/repeater/Makefile
new file mode 100644
index 000000000000..2d1b5f348976
--- /dev/null
+++ b/drivers/usb/repeater/Makefile
@@ -0,0 +1,6 @@
+# SPDX-License-Identifier: GPL-2.0
+#
+# Makefile for USB repeater drivers
+#
+
+obj-$(CONFIG_USB_REPEATER) += repeater.o
diff --git a/drivers/usb/repeater/repeater.c b/drivers/usb/repeater/repeater.c
new file mode 100644
index 000000000000..e97a95422735
--- /dev/null
+++ b/drivers/usb/repeater/repeater.c
@@ -0,0 +1,198 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (c) 2022, Qualcomm Innovation Center, Inc. All rights reserved.
+ * Copyright (c) 2022, Linaro Limited
+ */
+
+#include <linux/device.h>
+#include <linux/list.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/overflow.h>
+
+#include <linux/usb/repeater.h>
+
+static LIST_HEAD(usb_repeater_list);
+static DEFINE_SPINLOCK(usb_repeater_lock);
+
+/**
+ * usb_put_repeater - release the USB repeater
+ * @rptr: the repeater returned by usb_get_repeater()
+ *
+ * Releases a refcount the caller received from usb_get_repeater().
+ *
+ * For use by USB PHY drivers.
+ */
+void usb_put_repeater(struct usb_repeater *rptr)
+{
+ if (rptr) {
+ put_device(rptr->dev);
+ if (rptr->dev->driver && rptr->dev->driver->owner) {
+ struct module *owner = rptr->dev->driver->owner;
+
+ module_put(owner);
+ }
+ }
+}
+EXPORT_SYMBOL_GPL(usb_put_repeater);
+
+static struct usb_repeater *of_usb_find_repeater(struct device_node *node)
+{
+ struct usb_repeater *rptr;
+
+ if (!of_device_is_available(node))
+ return ERR_PTR(-ENODEV);
+
+ list_for_each_entry(rptr, &usb_repeater_list, head) {
+ if (node != rptr->dev->of_node)
+ continue;
+
+ return rptr;
+ }
+
+ return ERR_PTR(-EPROBE_DEFER);
+}
+
+static void devm_usb_repeater_release(struct device *dev, void *res)
+{
+ struct usb_repeater *rptr = *(struct usb_repeater **)res;
+
+ usb_put_repeater(rptr);
+}
+
+/**
+ * devm_usb_get_repeater_by_node - find the USB repeater by device_node
+ * @dev: device that requests this USB repeater
+ * @node: the device_node for the USB repeater device.
+ * @nb: a notifier_block to register with the USB repeater.
+ *
+ * Returns the USB repeater driver associated with the given device_node,
+ * after getting a refcount to it, -ENODEV if there is no such repeater or
+ * -EPROBE_DEFER if the device is not yet loaded. While at that, it
+ * also associates the device with
+ * the repeater using devres. On driver detach, release function is invoked
+ * on the devres data, then, devres data is freed.
+ *
+ * For use by peripheral drivers for devices related to a repeater,
+ * such as a charger.
+ */
+struct usb_repeater *devm_usb_get_repeater_by_node(struct device *dev,
+ struct device_node *node,
+ struct notifier_block *nb)
+{
+ struct usb_repeater *rptr = ERR_PTR(-ENOMEM);
+ struct usb_repeater *rptr_devm;
+ unsigned long flags;
+
+ rptr_devm = devres_alloc(devm_usb_repeater_release,
+ sizeof(*rptr_devm), GFP_KERNEL);
+ if (!rptr_devm) {
+ dev_dbg(dev, "failed to allocate memory for devres\n");
+ goto err0;
+ }
+
+ spin_lock_irqsave(&usb_repeater_lock, flags);
+
+ rptr = of_usb_find_repeater(node);
+ if (IS_ERR(rptr)) {
+ devres_free(rptr_devm);
+ goto err0;
+ }
+
+ if (!try_module_get(rptr->dev->driver->owner)) {
+ rptr = ERR_PTR(-ENODEV);
+ devres_free(rptr_devm);
+ goto err0;
+ }
+ devres_add(dev, rptr_devm);
+
+ get_device(rptr->dev);
+err0:
+ spin_unlock_irqrestore(&usb_repeater_lock, flags);
+
+ return rptr;
+}
+EXPORT_SYMBOL_GPL(devm_usb_get_repeater_by_node);
+
+/**
+ * devm_usb_get_repeater_by_phandle - find the USB repeater by phandle
+ * @dev: device that requests this repeater
+ * @phandle: name of the property holding the repeater phandle value
+ * @index: the index of the repeater
+ *
+ * Returns the USB repeater driver associated with the given phandle value,
+ * after getting a refcount to it, -ENODEV if there is no such repeater or
+ * -EPROBE_DEFER if there is a phandle to the repeater, but the device is
+ * not yet loaded. While at that, it also associates the device with
+ * the repeater using devres. On driver detach, release function is invoked
+ * on the devres data, then, devres data is freed.
+ *
+ * For use by USB PHY drivers.
+ */
+struct usb_repeater *devm_usb_get_repeater_by_phandle(struct device *dev,
+ const char *phandle, u8 index)
+{
+ struct device_node *node;
+ struct usb_repeater *rptr;
+
+ if (!dev->of_node) {
+ dev_dbg(dev, "device does not have a device node entry\n");
+ return ERR_PTR(-EINVAL);
+ }
+
+ node = of_parse_phandle(dev->of_node, phandle, index);
+ if (!node) {
+ dev_dbg(dev, "failed to get %s phandle in %pOF node\n", phandle,
+ dev->of_node);
+ return ERR_PTR(-ENODEV);
+ }
+ rptr = devm_usb_get_repeater_by_node(dev, node, NULL);
+ of_node_put(node);
+ return rptr;
+}
+EXPORT_SYMBOL_GPL(devm_usb_get_repeater_by_phandle);
+
+/**
+ * usb_add_repeater_dev - declare the USB repeater
+ * @rptr: the USB repeater to be used; or NULL
+ *
+ * This call is exclusively for use by repeater drivers to
+ * register the device to allow the USB phy driver to control it
+ * via repeater specific ops.
+ */
+int usb_add_repeater_dev(struct usb_repeater *rptr)
+{
+ unsigned long flags;
+
+ if (!rptr->dev) {
+ dev_err(rptr->dev, "no device provided for repeater\n");
+ return -EINVAL;
+ }
+
+ spin_lock_irqsave(&usb_repeater_lock, flags);
+ list_add_tail(&rptr->head, &usb_repeater_list);
+ spin_unlock_irqrestore(&usb_repeater_lock, flags);
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(usb_add_repeater_dev);
+
+/**
+ * usb_remove_repeater - remove the USB repeater
+ * @rptr: the USB Repeater to be removed;
+ *
+ * This reverts the effects of usb_add_repeater_dev
+ */
+void usb_remove_repeater_dev(struct usb_repeater *rptr)
+{
+ unsigned long flags;
+
+ spin_lock_irqsave(&usb_repeater_lock, flags);
+ if (rptr)
+ list_del(&rptr->head);
+ spin_unlock_irqrestore(&usb_repeater_lock, flags);
+}
+EXPORT_SYMBOL_GPL(usb_remove_repeater_dev);
+
+MODULE_DESCRIPTION("USB Repeater Framework");
+MODULE_LICENSE("GPL");
diff --git a/include/linux/usb/repeater.h b/include/linux/usb/repeater.h
new file mode 100644
index 000000000000..e68e0936f1e5
--- /dev/null
+++ b/include/linux/usb/repeater.h
@@ -0,0 +1,78 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * USB Repeater defines
+ */
+
+#ifndef __LINUX_USB_REPEATER_H
+#define __LINUX_USB_REPEATER_H
+
+struct usb_repeater {
+ struct device *dev;
+ const char *label;
+ unsigned int flags;
+
+ struct list_head head;
+ int (*reset)(struct usb_repeater *rptr, bool assert);
+ int (*init)(struct usb_repeater *rptr);
+ int (*power_on)(struct usb_repeater *rptr);
+ int (*power_off)(struct usb_repeater *rptr);
+};
+
+#if IS_ENABLED(CONFIG_USB_REPEATER)
+extern struct usb_repeater *devm_usb_get_repeater_by_phandle(struct device *dev,
+ const char *phandle, u8 index);
+extern struct usb_repeater *devm_usb_get_repeater_by_node(struct device *dev,
+ struct device_node *node, struct notifier_block *nb);
+extern int usb_add_repeater_dev(struct usb_repeater *rptr);
+extern void usb_remove_repeater_dev(struct usb_repeater *rptr);
+#else
+static inline struct usb_repeater *devm_usb_get_repeater_by_phandle(struct device *dev,
+ const char *phandle, u8 index)
+{
+ return ERR_PTR(-ENXIO);
+}
+
+static inline struct usb_repeater *devm_usb_get_repeater_by_node(struct device *dev,
+ struct device_node *node, struct notifier_block *nb)
+{
+ return ERR_PTR(-ENXIO);
+}
+
+static inline int usb_add_repeater_dev(struct usb_repeater *rptr) { return 0; }
+static inline void usb_remove_repeater_dev(struct usb_repeater *rptr) { }
+
+#endif
+
+static inline int usb_repeater_reset(struct usb_repeater *rptr, bool assert)
+{
+ if (rptr && rptr->reset != NULL)
+ return rptr->reset(rptr, assert);
+ else
+ return 0;
+}
+
+static inline int usb_repeater_init(struct usb_repeater *rptr)
+{
+ if (rptr && rptr->init != NULL)
+ return rptr->init(rptr);
+ else
+ return 0;
+}
+
+static inline int usb_repeater_power_on(struct usb_repeater *rptr)
+{
+ if (rptr && rptr->power_on != NULL)
+ return rptr->power_on(rptr);
+ else
+ return 0;
+}
+
+static inline int usb_repeater_power_off(struct usb_repeater *rptr)
+{
+ if (rptr && rptr->power_off != NULL)
+ return rptr->power_off(rptr);
+ else
+ return 0;
+}
+
+#endif /* __LINUX_USB_REPEATER_H */
--
2.34.1
On Wed, 16 Nov 2022 14:30:18 +0200, Abel Vesa wrote:
> Add dt-binding schema for the Qualcomm SNPS eUSB2 repeater.
>
> Signed-off-by: Abel Vesa <[email protected]>
> ---
> .../usb/qcom,snps-eusb2-repeater.yaml | 43 +++++++++++++++++++
> 1 file changed, 43 insertions(+)
> create mode 100644 Documentation/devicetree/bindings/usb/qcom,snps-eusb2-repeater.yaml
>
My bot found errors running 'make DT_CHECKER_FLAGS=-m dt_binding_check'
on your patch (DT_CHECKER_FLAGS is new in v5.13):
yamllint warnings/errors:
dtschema/dtc warnings/errors:
/builds/robherring/dt-review-ci/linux/Documentation/devicetree/bindings/usb/qcom,snps-eusb2-repeater.example.dtb: pmic@7: compatible:0: 'qcom,pm8550' is not one of ['qcom,pm6150', 'qcom,pm6150l', 'qcom,pm6350', 'qcom,pm660', 'qcom,pm660l', 'qcom,pm7250b', 'qcom,pm7325', 'qcom,pm8004', 'qcom,pm8005', 'qcom,pm8009', 'qcom,pm8019', 'qcom,pm8028', 'qcom,pm8110', 'qcom,pm8150', 'qcom,pm8150b', 'qcom,pm8150c', 'qcom,pm8150l', 'qcom,pm8226', 'qcom,pm8350', 'qcom,pm8350b', 'qcom,pm8350c', 'qcom,pm8841', 'qcom,pm8909', 'qcom,pm8916', 'qcom,pm8941', 'qcom,pm8950', 'qcom,pm8953', 'qcom,pm8994', 'qcom,pm8998', 'qcom,pma8084', 'qcom,pmd9635', 'qcom,pmi8950', 'qcom,pmi8962', 'qcom,pmi8994', 'qcom,pmi8998', 'qcom,pmk8002', 'qcom,pmk8350', 'qcom,pmm8155au', 'qcom,pmp8074', 'qcom,pmr735a', 'qcom,pmr735b', 'qcom,pms405', 'qcom,pmx55', 'qcom,pmx65', 'qcom,smb2351']
From schema: /builds/robherring/dt-review-ci/linux/Documentation/devicetree/bindings/mfd/qcom,spmi-pmic.yaml
/builds/robherring/dt-review-ci/linux/Documentation/devicetree/bindings/usb/qcom,snps-eusb2-repeater.example.dtb: pmic@7: 'usb-repeater@fd00' does not match any of the regexes: '(.*)?(wled|leds)@[0-9a-f]+$', '^adc-tm@[0-9a-f]+$', '^adc@[0-9a-f]+$', '^audio-codec@[0-9a-f]+$', '^mpps@[0-9a-f]+$', '^rtc@[0-9a-f]+$', '^temp-alarm@[0-9a-f]+$', '^vibrator@[0-9a-f]+$', 'extcon@[0-9a-f]+$', 'gpio(s)?@[0-9a-f]+$', 'pinctrl-[0-9]+', 'pon@[0-9a-f]+$', 'pwm@[0-9a-f]+$'
From schema: /builds/robherring/dt-review-ci/linux/Documentation/devicetree/bindings/mfd/qcom,spmi-pmic.yaml
Documentation/devicetree/bindings/usb/qcom,snps-eusb2-repeater.example.dtb:0:0: /example-0/pmic@7: failed to match any schema with compatible: ['qcom,pm8550', 'qcom,spmi-pmic']
doc reference errors (make refcheckdocs):
See https://patchwork.ozlabs.org/patch/
This check can fail if there are any dependencies. The base for a patch
series is generally the most recent rc1.
If you already ran 'make dt_binding_check' and didn't see the above
error(s), then make sure 'yamllint' is installed and dt-schema is up to
date:
pip3 install dtschema --upgrade
Please check and re-submit.
Hi Abel,
W dniu 16.11.2022 o 13:30, Abel Vesa pisze:
> With more SoCs moving towards eUSB2,
Can you name a few?
such platforms will have to use
> a USB 2.0 compliance repeater. This repeater HW-wise usually deals with
> level shifting, but depending on the implementation it can do much more.
> So add a ganeric USB framework that would allow either a generic PHY or
> some USB host controller to control and get a repeater from a devicetree
> phandle. This framework will further be used by platform specific
> drivers to register the repeater and implement platform specific ops.
>
> Signed-off-by: Abel Vesa <[email protected]>
> ---
> drivers/usb/Kconfig | 2 +
> drivers/usb/Makefile | 2 +
> drivers/usb/repeater/Kconfig | 9 ++
> drivers/usb/repeater/Makefile | 6 +
> drivers/usb/repeater/repeater.c | 198 ++++++++++++++++++++++++++++++++
> include/linux/usb/repeater.h | 78 +++++++++++++
> 6 files changed, 295 insertions(+)
> create mode 100644 drivers/usb/repeater/Kconfig
> create mode 100644 drivers/usb/repeater/Makefile
> create mode 100644 drivers/usb/repeater/repeater.c
> create mode 100644 include/linux/usb/repeater.h
>
<snip>
> diff --git a/include/linux/usb/repeater.h b/include/linux/usb/repeater.h
> new file mode 100644
> index 000000000000..e68e0936f1e5
> --- /dev/null
> +++ b/include/linux/usb/repeater.h
> @@ -0,0 +1,78 @@
> +/* SPDX-License-Identifier: GPL-2.0 */
> +/*
> + * USB Repeater defines
> + */
> +
> +#ifndef __LINUX_USB_REPEATER_H
> +#define __LINUX_USB_REPEATER_H
> +
> +struct usb_repeater {
> + struct device *dev;
> + const char *label;
> + unsigned int flags;
> +
> + struct list_head head;
This member serves the purpose of a list _entry_, no?
The _head_ is static LIST_HEAD(usb_repeater_list);
Maybe call it "entry"?
> + int (*reset)(struct usb_repeater *rptr, bool assert);
> + int (*init)(struct usb_repeater *rptr);
> + int (*power_on)(struct usb_repeater *rptr);
> + int (*power_off)(struct usb_repeater *rptr);
Would you document these ops somehow? Potential driver writers need to
understand when they are called and what they are supposed to do.
In particular, how do these relate to what's in "Embedded USB2 (eUSB2)
Physical Layer Supplement to the USB Revision 2.0 Specification"?
Regards,
Andrzej
On 22-11-18 09:59:43, Andrzej Pietrasiewicz wrote:
> Hi Abel,
>
> W dniu 16.11.2022 o?13:30, Abel Vesa pisze:
> > With more SoCs moving towards eUSB2,
>
> Can you name a few?
Right now, for SoCs, I can only name the SM8550 from Qualcomm. But I
would think there will be more from now on, not just from Qualcomm.
But I found a couple of more repeaters already existent. Like TUSB2E11
or TUSB2E22 from TI or PTN3222 from NXP. I'm not sure if they are used
already alongside any specific SoC though (yet).
Anyway, I can rephrase that.
>
> such platforms will have to use
> > a USB 2.0 compliance repeater. This repeater HW-wise usually deals with
> > level shifting, but depending on the implementation it can do much more.
> > So add a ganeric USB framework that would allow either a generic PHY or
> > some USB host controller to control and get a repeater from a devicetree
> > phandle. This framework will further be used by platform specific
> > drivers to register the repeater and implement platform specific ops.
> >
> > Signed-off-by: Abel Vesa <[email protected]>
> > ---
> > drivers/usb/Kconfig | 2 +
> > drivers/usb/Makefile | 2 +
> > drivers/usb/repeater/Kconfig | 9 ++
> > drivers/usb/repeater/Makefile | 6 +
> > drivers/usb/repeater/repeater.c | 198 ++++++++++++++++++++++++++++++++
> > include/linux/usb/repeater.h | 78 +++++++++++++
> > 6 files changed, 295 insertions(+)
> > create mode 100644 drivers/usb/repeater/Kconfig
> > create mode 100644 drivers/usb/repeater/Makefile
> > create mode 100644 drivers/usb/repeater/repeater.c
> > create mode 100644 include/linux/usb/repeater.h
> >
>
> <snip>
>
> > diff --git a/include/linux/usb/repeater.h b/include/linux/usb/repeater.h
> > new file mode 100644
> > index 000000000000..e68e0936f1e5
> > --- /dev/null
> > +++ b/include/linux/usb/repeater.h
> > @@ -0,0 +1,78 @@
> > +/* SPDX-License-Identifier: GPL-2.0 */
> > +/*
> > + * USB Repeater defines
> > + */
> > +
> > +#ifndef __LINUX_USB_REPEATER_H
> > +#define __LINUX_USB_REPEATER_H
> > +
> > +struct usb_repeater {
> > + struct device *dev;
> > + const char *label;
> > + unsigned int flags;
> > +
> > + struct list_head head;
>
> This member serves the purpose of a list _entry_, no?
> The _head_ is static LIST_HEAD(usb_repeater_list);
> Maybe call it "entry"?
Sure thing. Will do.
>
> > + int (*reset)(struct usb_repeater *rptr, bool assert);
> > + int (*init)(struct usb_repeater *rptr);
> > + int (*power_on)(struct usb_repeater *rptr);
> > + int (*power_off)(struct usb_repeater *rptr);
>
> Would you document these ops somehow? Potential driver writers need to
> understand when they are called and what they are supposed to do.
> In particular, how do these relate to what's in "Embedded USB2 (eUSB2)
> Physical Layer Supplement to the USB Revision 2.0 Specification"?
Yes. Will document them appropriately.
>
> Regards,
>
> Andrzej
Thanks,
Abel