LKML Archive on lore.kernel.org
help / color / mirror / Atom feed
* [PATCH v2 0/9] ARM: sun9i: Add USB host controller support for A80
@ 2015-01-25 12:22 Chen-Yu Tsai
2015-01-25 12:22 ` [PATCH v2 1/9] clk: sunxi: Add support for sun9i a80 usb clocks and resets Chen-Yu Tsai
` (8 more replies)
0 siblings, 9 replies; 14+ messages in thread
From: Chen-Yu Tsai @ 2015-01-25 12:22 UTC (permalink / raw)
To: Maxime Ripard, Mike Turquette, Emilio Lopez, Rob Herring,
Grant Likely, Kishon Vijay Abraham I
Cc: Chen-Yu Tsai, linux-arm-kernel, devicetree, linux-kernel, linux-sunxi
Hi everyone,
This is v2 of the sun9i A80 USB host support series.
This series adds USB host controller (EHCI/OHCI) support for the Allwinner
A80 SoC. The A80 has 3 pairs of host controllers and USB PHYs. The PHYs,
unlike in previous SoCs, do not have low level control registers anymore.
As such, this series forgoes the original phy-sun4i-usb driver, and adds
a new, simpler driver for the USB PHYs. It may be possible to merge the
two, but given that work is being done on the OTG front for the earlier
SoCs, it may be better to merge them after support is complete.
EHCI/OHCI0 corresponds to USB1 DP/DM pins; EHCI1 only has HSIC support;
EHCI2/OHCI/2 is USB2 DP/DM externally. External pins labeled USB0 are
for the USB 3.0 OTG controller.
Changes since v1:
- Rework usb clock/reset driver to only enable ahb gate when child
clock gates are enabled.
- Add AHB_INCR16_BURST flag and HSIC specific bits to phy driver.
- Renumber USB PHYs according to sunxi tradition, usbphy0 for OTG,
usbphy1 and later for xHCI.
- Add VBUS regulator for usb3 to sunxi common regulators.
- Use common regulators for usb vbus regulators.
- Adapt to label references in board dts file.
- Use gpio and pinctrl macros in dts.
Patch 1 adds a80 specific support for usb-related clocks and resets.
Patch 2 adds the device tree nodes for the usb clocks.
Patch 3 adds a new generic phy driver for a80 usb phys. This has some
code that is the same as the original phy-sun4i-usb driver, but is simpler.
Patch 4 adds the 3 USB PHY nodes to the a80 dtsi.
Patch 5 adds the USB host controller nodes to the a80 dtsi.
Patch 6 adds a VBUS regulator for usb3 to sunxi common regulators.
Patch 7 enables USB on the A80 Optimus board.
Patch 8 enables sun9i USB PHY in sunxi_defconfig.
Patch 9 enables sun9i USB PHY in multi_v7_defconfig.
Regards,
ChenYu
Chen-Yu Tsai (9):
clk: sunxi: Add support for sun9i a80 usb clocks and resets
ARM: dts: sun9i: Add usb clock nodes to a80 dtsi
phy: Add driver to support individual USB PHYs on sun9i
ARM: dts: sun9i: Add usb phy nodes to a80 dtsi
ARM: dts: sun9i: Add USB host controller nodes to a80 dtsi
ARM: dts: sunxi: Add usb3_vbus regulator to common regulators dtsi
ARM: dts: sun9i: Enable USB support on A80 Optimus board
ARM: sunxi_defconfig: Enable CONFIG_PHY_SUN9I_USB
ARM: multi_v7_defconfig: Enable CONFIG_PHY_SUN9I_USB
Documentation/devicetree/bindings/clock/sunxi.txt | 2 +
.../devicetree/bindings/phy/sun9i-usb-phy.txt | 34 +++
arch/arm/boot/dts/sun9i-a80-optimus.dts | 60 ++++++
arch/arm/boot/dts/sun9i-a80.dtsi | 129 +++++++++++
arch/arm/boot/dts/sunxi-common-regulators.dtsi | 10 +
arch/arm/configs/multi_v7_defconfig | 1 +
arch/arm/configs/sunxi_defconfig | 1 +
drivers/clk/sunxi/Makefile | 1 +
drivers/clk/sunxi/clk-usb.c | 193 +++++++++++++++++
drivers/phy/Kconfig | 12 ++
drivers/phy/Makefile | 1 +
drivers/phy/phy-sun9i-usb.c | 238 +++++++++++++++++++++
12 files changed, 682 insertions(+)
create mode 100644 Documentation/devicetree/bindings/phy/sun9i-usb-phy.txt
create mode 100644 drivers/clk/sunxi/clk-usb.c
create mode 100644 drivers/phy/phy-sun9i-usb.c
--
2.1.4
^ permalink raw reply [flat|nested] 14+ messages in thread
* [PATCH v2 1/9] clk: sunxi: Add support for sun9i a80 usb clocks and resets
2015-01-25 12:22 [PATCH v2 0/9] ARM: sun9i: Add USB host controller support for A80 Chen-Yu Tsai
@ 2015-01-25 12:22 ` Chen-Yu Tsai
2015-01-25 16:02 ` Maxime Ripard
2015-01-25 12:22 ` [PATCH v2 2/9] ARM: dts: sun9i: Add usb clock nodes to a80 dtsi Chen-Yu Tsai
` (7 subsequent siblings)
8 siblings, 1 reply; 14+ messages in thread
From: Chen-Yu Tsai @ 2015-01-25 12:22 UTC (permalink / raw)
To: Maxime Ripard, Mike Turquette, Emilio Lopez, Rob Herring,
Grant Likely, Kishon Vijay Abraham I
Cc: Chen-Yu Tsai, linux-arm-kernel, devicetree, linux-kernel, linux-sunxi
The USB controller/phy clocks and reset controls are in a separate
address block, unlike previous SoCs where they were in the clock
controller.
This patch copies the original gates clk functions used for usb
clocks into a separate file, and renames them to *_usb_*. Also
add a per-gate parent index, so we can set different parents for
each gate.
Signed-off-by: Chen-Yu Tsai <wens@csie.org>
---
Documentation/devicetree/bindings/clock/sunxi.txt | 2 +
drivers/clk/sunxi/Makefile | 1 +
drivers/clk/sunxi/clk-usb.c | 193 ++++++++++++++++++++++
3 files changed, 196 insertions(+)
create mode 100644 drivers/clk/sunxi/clk-usb.c
diff --git a/Documentation/devicetree/bindings/clock/sunxi.txt b/Documentation/devicetree/bindings/clock/sunxi.txt
index 60b44285250d..3f1dcd879af7 100644
--- a/Documentation/devicetree/bindings/clock/sunxi.txt
+++ b/Documentation/devicetree/bindings/clock/sunxi.txt
@@ -66,6 +66,8 @@ Required properties:
"allwinner,sun4i-a10-usb-clk" - for usb gates + resets on A10 / A20
"allwinner,sun5i-a13-usb-clk" - for usb gates + resets on A13
"allwinner,sun6i-a31-usb-clk" - for usb gates + resets on A31
+ "allwinner,sun9i-a80-usb-mod-clk" - for usb gates + resets on A80
+ "allwinner,sun9i-a80-usb-phy-clk" - for usb phy gates + resets on A80
Required properties for all clocks:
- reg : shall be the control register address for the clock.
diff --git a/drivers/clk/sunxi/Makefile b/drivers/clk/sunxi/Makefile
index 3a5292e3fcf8..058f273d6154 100644
--- a/drivers/clk/sunxi/Makefile
+++ b/drivers/clk/sunxi/Makefile
@@ -9,6 +9,7 @@ obj-y += clk-mod0.o
obj-y += clk-sun8i-mbus.o
obj-y += clk-sun9i-core.o
obj-y += clk-sun9i-mmc.o
+obj-y += clk-usb.o
obj-$(CONFIG_MFD_SUN6I_PRCM) += \
clk-sun6i-ar100.o clk-sun6i-apb0.o clk-sun6i-apb0-gates.o \
diff --git a/drivers/clk/sunxi/clk-usb.c b/drivers/clk/sunxi/clk-usb.c
new file mode 100644
index 000000000000..1a93400353de
--- /dev/null
+++ b/drivers/clk/sunxi/clk-usb.c
@@ -0,0 +1,193 @@
+/*
+ * Copyright 2013 Emilio López
+ *
+ * Emilio López <emilio@elopez.com.ar>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/clk-provider.h>
+#include <linux/clkdev.h>
+#include <linux/of.h>
+#include <linux/of_address.h>
+#include <linux/reset-controller.h>
+#include <linux/spinlock.h>
+
+
+/**
+ * sunxi_usb_reset... - reset bits in usb clk registers handling
+ */
+
+struct usb_reset_data {
+ void __iomem *reg;
+ spinlock_t *lock;
+ struct clk *clk;
+ struct reset_controller_dev rcdev;
+};
+
+static int sunxi_usb_reset_assert(struct reset_controller_dev *rcdev,
+ unsigned long id)
+{
+ struct usb_reset_data *data = container_of(rcdev,
+ struct usb_reset_data,
+ rcdev);
+ unsigned long flags;
+ u32 reg;
+
+ clk_prepare_enable(data->clk);
+ spin_lock_irqsave(data->lock, flags);
+
+ reg = readl(data->reg);
+ writel(reg & ~BIT(id), data->reg);
+
+ spin_unlock_irqrestore(data->lock, flags);
+ clk_disable_unprepare(data->clk);
+
+ return 0;
+}
+
+static int sunxi_usb_reset_deassert(struct reset_controller_dev *rcdev,
+ unsigned long id)
+{
+ struct usb_reset_data *data = container_of(rcdev,
+ struct usb_reset_data,
+ rcdev);
+ unsigned long flags;
+ u32 reg;
+
+ clk_prepare_enable(data->clk);
+ spin_lock_irqsave(data->lock, flags);
+
+ reg = readl(data->reg);
+ writel(reg | BIT(id), data->reg);
+
+ spin_unlock_irqrestore(data->lock, flags);
+ clk_disable_unprepare(data->clk);
+
+ return 0;
+}
+
+static struct reset_control_ops sunxi_usb_reset_ops = {
+ .assert = sunxi_usb_reset_assert,
+ .deassert = sunxi_usb_reset_deassert,
+};
+
+/**
+ * sunxi_usb_clk_setup() - Setup function for usb gate clocks
+ */
+
+#define SUNXI_USB_MAX_SIZE 32
+
+struct usb_clk_data {
+ u32 clk_mask;
+ u32 reset_mask;
+ bool reset_needs_clk;
+};
+
+static void __init sunxi_usb_clk_setup(struct device_node *node,
+ const struct usb_clk_data *data,
+ spinlock_t *lock)
+{
+ struct clk_onecell_data *clk_data;
+ struct usb_reset_data *reset_data;
+ const char *clk_parent;
+ const char *clk_name;
+ void __iomem *reg;
+ int qty;
+ int i = 0;
+ int j = 0;
+
+ reg = of_io_request_and_map(node, 0, of_node_full_name(node));
+
+ clk_parent = of_clk_get_parent_name(node, 0);
+ if (!clk_parent)
+ return;
+
+ /* Worst-case size approximation and memory allocation */
+ qty = find_last_bit((unsigned long *)&data->clk_mask,
+ SUNXI_USB_MAX_SIZE);
+ clk_data = kmalloc(sizeof(struct clk_onecell_data), GFP_KERNEL);
+ if (!clk_data)
+ return;
+ clk_data->clks = kzalloc((qty+1) * sizeof(struct clk *), GFP_KERNEL);
+ if (!clk_data->clks) {
+ kfree(clk_data);
+ return;
+ }
+
+ for_each_set_bit(i, (unsigned long *)&data->clk_mask,
+ SUNXI_USB_MAX_SIZE) {
+ of_property_read_string_index(node, "clock-output-names",
+ j, &clk_name);
+ clk_data->clks[i] = clk_register_gate(NULL, clk_name,
+ clk_parent, 0,
+ reg, i, 0, lock);
+ WARN_ON(IS_ERR(clk_data->clks[i]));
+ clk_register_clkdev(clk_data->clks[i], clk_name, NULL);
+
+ j++;
+ }
+
+ /* Adjust to the real max */
+ clk_data->clk_num = i;
+
+ of_clk_add_provider(node, of_clk_src_onecell_get, clk_data);
+
+ /* Register a reset controller for usb with reset bits */
+ if (data->reset_mask == 0)
+ return;
+
+ reset_data = kzalloc(sizeof(*reset_data), GFP_KERNEL);
+ if (!reset_data)
+ return;
+
+ if (data->reset_needs_clk)
+ reset_data->clk = of_clk_get(node, 0);
+ if (IS_ERR(reset_data->clk)) {
+ pr_err("Could not get clock for reset controls\n");
+ kfree(reset_data);
+ return;
+ }
+ reset_data->reg = reg;
+ reset_data->lock = lock;
+ reset_data->rcdev.nr_resets = __fls(data->reset_mask) + 1;
+ reset_data->rcdev.ops = &sunxi_usb_reset_ops;
+ reset_data->rcdev.of_node = node;
+ reset_controller_register(&reset_data->rcdev);
+}
+
+static const struct usb_clk_data sun9i_a80_usb_mod_data __initconst = {
+ .clk_mask = BIT(6) | BIT(5) | BIT(4) | BIT(3) | BIT(2) | BIT(1),
+ .reset_mask = BIT(19) | BIT(18) | BIT(17),
+ .reset_needs_clk = 1,
+};
+
+static DEFINE_SPINLOCK(a80_usb_mod_lock);
+
+static void __init sun9i_a80_usb_mod_setup(struct device_node *node)
+{
+ sunxi_usb_clk_setup(node, &sun9i_a80_usb_mod_data, &a80_usb_mod_lock);
+}
+CLK_OF_DECLARE(sun9i_a80_usb_mod, "allwinner,sun9i-a80-usb-mod-clk", sun9i_a80_usb_mod_setup);
+
+static const struct usb_clk_data sun9i_a80_usb_phy_data __initconst = {
+ .clk_mask = BIT(10) | BIT(5) | BIT(4) | BIT(3) | BIT(2) | BIT(1),
+ .reset_mask = BIT(21) | BIT(20) | BIT(19) | BIT(18) | BIT(17),
+ .reset_needs_clk = 1,
+};
+
+static DEFINE_SPINLOCK(a80_usb_phy_lock);
+
+static void __init sun9i_a80_usb_phy_setup(struct device_node *node)
+{
+ sunxi_usb_clk_setup(node, &sun9i_a80_usb_phy_data, &a80_usb_phy_lock);
+}
+CLK_OF_DECLARE(sun9i_a80_usb_phy, "allwinner,sun9i-a80-usb-phy-clk", sun9i_a80_usb_phy_setup);
--
2.1.4
^ permalink raw reply [flat|nested] 14+ messages in thread
* [PATCH v2 2/9] ARM: dts: sun9i: Add usb clock nodes to a80 dtsi
2015-01-25 12:22 [PATCH v2 0/9] ARM: sun9i: Add USB host controller support for A80 Chen-Yu Tsai
2015-01-25 12:22 ` [PATCH v2 1/9] clk: sunxi: Add support for sun9i a80 usb clocks and resets Chen-Yu Tsai
@ 2015-01-25 12:22 ` Chen-Yu Tsai
2015-01-25 12:22 ` [PATCH v2 3/9] phy: Add driver to support individual USB PHYs on sun9i Chen-Yu Tsai
` (6 subsequent siblings)
8 siblings, 0 replies; 14+ messages in thread
From: Chen-Yu Tsai @ 2015-01-25 12:22 UTC (permalink / raw)
To: Maxime Ripard, Mike Turquette, Emilio Lopez, Rob Herring,
Grant Likely, Kishon Vijay Abraham I
Cc: Chen-Yu Tsai, linux-arm-kernel, devicetree, linux-kernel, linux-sunxi
The USB controller and phy clocks and resets have a separate address
block and driver. Add the nodes to represent them.
Signed-off-by: Chen-Yu Tsai <wens@csie.org>
---
arch/arm/boot/dts/sun9i-a80.dtsi | 22 ++++++++++++++++++++++
1 file changed, 22 insertions(+)
diff --git a/arch/arm/boot/dts/sun9i-a80.dtsi b/arch/arm/boot/dts/sun9i-a80.dtsi
index 9e28ffc6dd90..679cf2878800 100644
--- a/arch/arm/boot/dts/sun9i-a80.dtsi
+++ b/arch/arm/boot/dts/sun9i-a80.dtsi
@@ -147,6 +147,28 @@
clock-output-names = "osc32k";
};
+ usb_mod_clk: clk@00a08000 {
+ #clock-cells = <1>;
+ #reset-cells = <1>;
+ compatible = "allwinner,sun9i-a80-usb-mod-clk";
+ reg = <0x00a08000 0x4>;
+ clocks = <&ahb1_gates 1>;
+ clock-output-names = "usb0_ahb", "usb_ohci0",
+ "usb1_ahb", "usb_ohci1",
+ "usb2_ahb", "usb_ohci2";
+ };
+
+ usb_phy_clk: clk@00a08004 {
+ #clock-cells = <1>;
+ #reset-cells = <1>;
+ compatible = "allwinner,sun9i-a80-usb-phy-clk";
+ reg = <0x00a08004 0x4>;
+ clocks = <&ahb1_gates 1>;
+ clock-output-names = "usb_phy0", "usb_hsic1_480M",
+ "usb_phy1", "usb_hsic2_480M",
+ "usb_phy2", "usb_hsic_12M";
+ };
+
pll4: clk@0600000c {
#clock-cells = <0>;
compatible = "allwinner,sun9i-a80-pll4-clk";
--
2.1.4
^ permalink raw reply [flat|nested] 14+ messages in thread
* [PATCH v2 3/9] phy: Add driver to support individual USB PHYs on sun9i
2015-01-25 12:22 [PATCH v2 0/9] ARM: sun9i: Add USB host controller support for A80 Chen-Yu Tsai
2015-01-25 12:22 ` [PATCH v2 1/9] clk: sunxi: Add support for sun9i a80 usb clocks and resets Chen-Yu Tsai
2015-01-25 12:22 ` [PATCH v2 2/9] ARM: dts: sun9i: Add usb clock nodes to a80 dtsi Chen-Yu Tsai
@ 2015-01-25 12:22 ` Chen-Yu Tsai
2015-01-25 12:22 ` [PATCH v2 4/9] ARM: dts: sun9i: Add usb phy nodes to a80 dtsi Chen-Yu Tsai
` (5 subsequent siblings)
8 siblings, 0 replies; 14+ messages in thread
From: Chen-Yu Tsai @ 2015-01-25 12:22 UTC (permalink / raw)
To: Maxime Ripard, Mike Turquette, Emilio Lopez, Rob Herring,
Grant Likely, Kishon Vijay Abraham I
Cc: Chen-Yu Tsai, linux-arm-kernel, devicetree, linux-kernel, linux-sunxi
Unlike previous Allwinner SoCs, there is no central PHY control block
on the A80. Also, OTG support is completely split off into a different
controller.
This adds a new driver to support the regular USB PHYs.
Signed-off-by: Chen-Yu Tsai <wens@csie.org>
---
.../devicetree/bindings/phy/sun9i-usb-phy.txt | 34 +++
drivers/phy/Kconfig | 12 ++
drivers/phy/Makefile | 1 +
drivers/phy/phy-sun9i-usb.c | 238 +++++++++++++++++++++
4 files changed, 285 insertions(+)
create mode 100644 Documentation/devicetree/bindings/phy/sun9i-usb-phy.txt
create mode 100644 drivers/phy/phy-sun9i-usb.c
diff --git a/Documentation/devicetree/bindings/phy/sun9i-usb-phy.txt b/Documentation/devicetree/bindings/phy/sun9i-usb-phy.txt
new file mode 100644
index 000000000000..af40dd2fe0eb
--- /dev/null
+++ b/Documentation/devicetree/bindings/phy/sun9i-usb-phy.txt
@@ -0,0 +1,34 @@
+Allwinner sun9i USB PHY
+-----------------------
+
+Required properties:
+- compatible : should be one of
+ * allwinner,sun9i-a80-usb-phy
+- reg : a list of offset + length pairs
+- #phy-cells : from the generic phy bindings, must be 0
+- phy_type : "hsic" for HSIC usage;
+ other values or absence of this property indicates normal USB
+- clocks : phandle + clock specifier for the phy clocks
+- clock-names : depending on the "phy_type" property,
+ * "phy" for normal USB
+ * "hsic_480M", "hsic_12M" for HSIC
+- resets : a list of phandle + reset specifier pairs
+- reset-names : depending on the "phy_type" property,
+ * "phy" for normal USB
+ * "hsic" for HSIC
+
+It is recommended to list all clocks and resets available.
+The driver will only use those matching the phy_type.
+
+Example:
+ usbphy1: phy@00a01800 {
+ compatible = "allwinner,sun9i-a80-usb-phy";
+ reg = <0x00a01800 0x4>;
+ clocks = <&usb_phy_clk 2>, <&usb_phy_clk 10>,
+ <&usb_phy_clk 3>;
+ clock-names = "hsic_480M", "hsic_12M", "phy";
+ resets = <&usb_phy_clk 18>, <&usb_phy_clk 19>;
+ reset-names = "hsic", "phy";
+ status = "disabled";
+ #phy-cells = <0>;
+ };
diff --git a/drivers/phy/Kconfig b/drivers/phy/Kconfig
index ccad8809ecb1..4c280b28a2ce 100644
--- a/drivers/phy/Kconfig
+++ b/drivers/phy/Kconfig
@@ -174,6 +174,18 @@ config PHY_SUN4I_USB
This driver controls the entire USB PHY block, both the USB OTG
parts, as well as the 2 regular USB 2 host PHYs.
+config PHY_SUN9I_USB
+ tristate "Allwinner sun9i SoC USB PHY driver"
+ depends on ARCH_SUNXI && HAS_IOMEM && OF
+ depends on RESET_CONTROLLER
+ select USB_PHY
+ select GENERIC_PHY
+ help
+ Enable this to support the transceiver that is part of Allwinner
+ sun9i SoCs.
+
+ This driver controls each individual USB 2 host PHY.
+
config PHY_SAMSUNG_USB2
tristate "Samsung USB 2.0 PHY driver"
depends on HAS_IOMEM
diff --git a/drivers/phy/Makefile b/drivers/phy/Makefile
index aa74f961e44e..11ead804d9a4 100644
--- a/drivers/phy/Makefile
+++ b/drivers/phy/Makefile
@@ -20,6 +20,7 @@ obj-$(CONFIG_TWL4030_USB) += phy-twl4030-usb.o
obj-$(CONFIG_PHY_EXYNOS5250_SATA) += phy-exynos5250-sata.o
obj-$(CONFIG_PHY_HIX5HD2_SATA) += phy-hix5hd2-sata.o
obj-$(CONFIG_PHY_SUN4I_USB) += phy-sun4i-usb.o
+obj-$(CONFIG_PHY_SUN9I_USB) += phy-sun9i-usb.o
obj-$(CONFIG_PHY_SAMSUNG_USB2) += phy-exynos-usb2.o
phy-exynos-usb2-y += phy-samsung-usb2.o
phy-exynos-usb2-$(CONFIG_PHY_EXYNOS4210_USB2) += phy-exynos4210-usb2.o
diff --git a/drivers/phy/phy-sun9i-usb.c b/drivers/phy/phy-sun9i-usb.c
new file mode 100644
index 000000000000..0fddd56df38c
--- /dev/null
+++ b/drivers/phy/phy-sun9i-usb.c
@@ -0,0 +1,238 @@
+/*
+ * Allwinner sun9i USB phy driver
+ *
+ * Copyright (C) 2014 Chen-Yu Tsai <wens@csie.org>
+ *
+ * Based on phy-sun4i-usb.c from
+ * Hans de Goede <hdegoede@redhat.com>
+ *
+ * and code from
+ * Allwinner Technology Co., Ltd. <www.allwinnertech.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/clk.h>
+#include <linux/err.h>
+#include <linux/io.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/mutex.h>
+#include <linux/of.h>
+#include <linux/of_address.h>
+#include <linux/phy/phy.h>
+#include <linux/usb/of.h>
+#include <linux/platform_device.h>
+#include <linux/reset.h>
+
+#define SUNXI_AHB_INCR16_BURST_EN BIT(11)
+#define SUNXI_AHB_INCR8_BURST_EN BIT(10)
+#define SUNXI_AHB_INCR4_BURST_EN BIT(9)
+#define SUNXI_AHB_INCRX_ALIGN_EN BIT(8)
+#define SUNXI_ULPI_BYPASS_EN BIT(0)
+
+/* usb1 HSIC specific bits */
+#define SUNXI_EHCI_HS_FORCE BIT(20)
+#define SUNXI_HSIC_CONNECT_DET BIT(17)
+#define SUNXI_HSIC_CONNECT_INT BIT(16)
+#define SUNXI_HSIC BIT(1)
+
+struct sun9i_usb_phy {
+ struct phy *phy;
+ void __iomem *pmu;
+ struct regulator *vbus;
+ struct reset_control *reset;
+ struct clk *clk;
+ struct clk *hsic_clk;
+ enum usb_phy_interface type;
+};
+
+static void sun9i_usb_phy_passby(struct sun9i_usb_phy *phy, int enable)
+{
+ u32 bits, reg_value;
+
+ bits = SUNXI_AHB_INCR16_BURST_EN | SUNXI_AHB_INCR8_BURST_EN |
+ SUNXI_AHB_INCR4_BURST_EN | SUNXI_AHB_INCRX_ALIGN_EN |
+ SUNXI_ULPI_BYPASS_EN;
+
+ if (phy->type == USBPHY_INTERFACE_MODE_HSIC)
+ bits |= SUNXI_HSIC | SUNXI_EHCI_HS_FORCE |
+ SUNXI_HSIC_CONNECT_DET | SUNXI_HSIC_CONNECT_INT;
+
+ reg_value = readl(phy->pmu);
+
+ if (enable)
+ reg_value |= bits;
+ else
+ reg_value &= ~bits;
+
+ writel(reg_value, phy->pmu);
+}
+
+static int sun9i_usb_phy_init(struct phy *_phy)
+{
+ struct sun9i_usb_phy *phy = phy_get_drvdata(_phy);
+ int ret;
+
+ ret = clk_prepare_enable(phy->clk);
+ if (ret)
+ goto err_clk;
+
+ ret = clk_prepare_enable(phy->hsic_clk);
+ if (ret)
+ goto err_hsic_clk;
+
+ ret = reset_control_deassert(phy->reset);
+ if (ret)
+ goto err_reset;
+
+ sun9i_usb_phy_passby(phy, 1);
+ return 0;
+
+err_reset:
+ clk_disable_unprepare(phy->hsic_clk);
+
+err_hsic_clk:
+ clk_disable_unprepare(phy->clk);
+
+err_clk:
+ return ret;
+}
+
+static int sun9i_usb_phy_exit(struct phy *_phy)
+{
+ struct sun9i_usb_phy *phy = phy_get_drvdata(_phy);
+
+ sun9i_usb_phy_passby(phy, 0);
+ reset_control_assert(phy->reset);
+ clk_disable_unprepare(phy->hsic_clk);
+ clk_disable_unprepare(phy->clk);
+
+ return 0;
+}
+
+static int sun9i_usb_phy_power_on(struct phy *_phy)
+{
+ struct sun9i_usb_phy *phy = phy_get_drvdata(_phy);
+ int ret = 0;
+
+ if (phy->vbus)
+ ret = regulator_enable(phy->vbus);
+
+ return ret;
+}
+
+static int sun9i_usb_phy_power_off(struct phy *_phy)
+{
+ struct sun9i_usb_phy *phy = phy_get_drvdata(_phy);
+
+ if (phy->vbus)
+ regulator_disable(phy->vbus);
+
+ return 0;
+}
+
+static struct phy_ops sun9i_usb_phy_ops = {
+ .init = sun9i_usb_phy_init,
+ .exit = sun9i_usb_phy_exit,
+ .power_on = sun9i_usb_phy_power_on,
+ .power_off = sun9i_usb_phy_power_off,
+ .owner = THIS_MODULE,
+};
+
+static int sun9i_usb_phy_probe(struct platform_device *pdev)
+{
+ struct sun9i_usb_phy *phy;
+ struct device *dev = &pdev->dev;
+ struct device_node *np = dev->of_node;
+ struct phy_provider *phy_provider;
+ struct resource *res;
+
+ phy = devm_kzalloc(dev, sizeof(*phy), GFP_KERNEL);
+ if (!phy)
+ return -ENOMEM;
+
+ phy->vbus = devm_regulator_get_optional(dev, "vbus");
+ if (IS_ERR(phy->vbus)) {
+ if (PTR_ERR(phy->vbus) == -EPROBE_DEFER)
+ return -EPROBE_DEFER;
+ phy->vbus = NULL;
+ }
+
+ phy->type = of_usb_get_phy_mode(np);
+ if (phy->type == USBPHY_INTERFACE_MODE_HSIC) {
+ phy->clk = devm_clk_get(dev, "hsic_480M");
+ if (IS_ERR(phy->clk)) {
+ dev_err(dev, "failed to get hsic_480M clock\n");
+ return PTR_ERR(phy->clk);
+ }
+
+ phy->hsic_clk = devm_clk_get(dev, "hsic_12M");
+ if (IS_ERR(phy->clk)) {
+ dev_err(dev, "failed to get hsic_12M clock\n");
+ return PTR_ERR(phy->clk);
+ }
+
+ phy->reset = devm_reset_control_get(dev, "hsic");
+ if (IS_ERR(phy->reset)) {
+ dev_err(dev, "failed to get reset control\n");
+ return PTR_ERR(phy->reset);
+ }
+ } else {
+ phy->clk = devm_clk_get(dev, "phy");
+ if (IS_ERR(phy->clk)) {
+ dev_err(dev, "failed to get phy clock\n");
+ return PTR_ERR(phy->clk);
+ }
+
+ phy->reset = devm_reset_control_get(dev, "phy");
+ if (IS_ERR(phy->reset)) {
+ dev_err(dev, "failed to get reset control\n");
+ return PTR_ERR(phy->reset);
+ }
+ }
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ phy->pmu = devm_ioremap_resource(dev, res);
+ if (IS_ERR(phy->pmu))
+ return PTR_ERR(phy->pmu);
+
+ phy->phy = devm_phy_create(dev, NULL, &sun9i_usb_phy_ops);
+ if (IS_ERR(phy->phy)) {
+ dev_err(dev, "failed to create PHY\n");
+ return PTR_ERR(phy->phy);
+ }
+
+ phy_set_drvdata(phy->phy, phy);
+ dev_set_drvdata(dev, phy);
+ phy_provider = devm_of_phy_provider_register(dev, of_phy_simple_xlate);
+
+ return PTR_ERR_OR_ZERO(phy_provider);
+}
+
+static const struct of_device_id sun9i_usb_phy_of_match[] = {
+ { .compatible = "allwinner,sun9i-a80-usb-phy" },
+ { },
+};
+MODULE_DEVICE_TABLE(of, sun9i_usb_phy_of_match);
+
+static struct platform_driver sun9i_usb_phy_driver = {
+ .probe = sun9i_usb_phy_probe,
+ .driver = {
+ .of_match_table = sun9i_usb_phy_of_match,
+ .name = "sun9i-usb-phy",
+ }
+};
+module_platform_driver(sun9i_usb_phy_driver);
+
+MODULE_DESCRIPTION("Allwinner sun9i USB phy driver");
+MODULE_AUTHOR("Chen-Yu Tsai <wens@csie.org>");
+MODULE_LICENSE("GPL v2");
--
2.1.4
^ permalink raw reply [flat|nested] 14+ messages in thread
* [PATCH v2 4/9] ARM: dts: sun9i: Add usb phy nodes to a80 dtsi
2015-01-25 12:22 [PATCH v2 0/9] ARM: sun9i: Add USB host controller support for A80 Chen-Yu Tsai
` (2 preceding siblings ...)
2015-01-25 12:22 ` [PATCH v2 3/9] phy: Add driver to support individual USB PHYs on sun9i Chen-Yu Tsai
@ 2015-01-25 12:22 ` Chen-Yu Tsai
2015-01-25 12:22 ` [PATCH v2 5/9] ARM: dts: sun9i: Add USB host controller " Chen-Yu Tsai
` (4 subsequent siblings)
8 siblings, 0 replies; 14+ messages in thread
From: Chen-Yu Tsai @ 2015-01-25 12:22 UTC (permalink / raw)
To: Maxime Ripard, Mike Turquette, Emilio Lopez, Rob Herring,
Grant Likely, Kishon Vijay Abraham I
Cc: Chen-Yu Tsai, linux-arm-kernel, devicetree, linux-kernel, linux-sunxi
On sun9i, there are 3 independent usb phys for EHCI/OHCI.
Add device nodes for them.
Signed-off-by: Chen-Yu Tsai <wens@csie.org>
---
arch/arm/boot/dts/sun9i-a80.dtsi | 37 +++++++++++++++++++++++++++++++++++++
1 file changed, 37 insertions(+)
diff --git a/arch/arm/boot/dts/sun9i-a80.dtsi b/arch/arm/boot/dts/sun9i-a80.dtsi
index 679cf2878800..d7ebd9390b01 100644
--- a/arch/arm/boot/dts/sun9i-a80.dtsi
+++ b/arch/arm/boot/dts/sun9i-a80.dtsi
@@ -355,6 +355,43 @@
*/
ranges = <0 0 0 0x20000000>;
+ usbphy1: phy@00a00800 {
+ compatible = "allwinner,sun9i-a80-usb-phy";
+ reg = <0x00a00800 0x4>;
+ clocks = <&usb_phy_clk 1>;
+ clock-names = "phy";
+ resets = <&usb_phy_clk 17>;
+ reset-names = "phy";
+ status = "disabled";
+ #phy-cells = <0>;
+ };
+
+ usbphy2: phy@00a01800 {
+ compatible = "allwinner,sun9i-a80-usb-phy";
+ reg = <0x00a01800 0x4>;
+ clocks = <&usb_phy_clk 2>, <&usb_phy_clk 10>,
+ <&usb_phy_clk 3>;
+ clock-names = "hsic_480M", "hsic_12M", "phy";
+ resets = <&usb_phy_clk 18>, <&usb_phy_clk 19>;
+ reset-names = "hsic", "phy";
+ status = "disabled";
+ #phy-cells = <0>;
+ /* usb1 is always used with HSIC */
+ phy_type = "hsic";
+ };
+
+ usbphy3: phy@00a02800 {
+ compatible = "allwinner,sun9i-a80-usb-phy";
+ reg = <0x00a02800 0x4>;
+ clocks = <&usb_phy_clk 4>, <&usb_phy_clk 10>,
+ <&usb_phy_clk 5>;
+ clock-names = "hsic_480M", "hsic_12M", "phy";
+ resets = <&usb_phy_clk 20>, <&usb_phy_clk 21>;
+ reset-names = "hsic", "phy";
+ status = "disabled";
+ #phy-cells = <0>;
+ };
+
mmc0: mmc@01c0f000 {
compatible = "allwinner,sun5i-a13-mmc";
reg = <0x01c0f000 0x1000>;
--
2.1.4
^ permalink raw reply [flat|nested] 14+ messages in thread
* [PATCH v2 5/9] ARM: dts: sun9i: Add USB host controller nodes to a80 dtsi
2015-01-25 12:22 [PATCH v2 0/9] ARM: sun9i: Add USB host controller support for A80 Chen-Yu Tsai
` (3 preceding siblings ...)
2015-01-25 12:22 ` [PATCH v2 4/9] ARM: dts: sun9i: Add usb phy nodes to a80 dtsi Chen-Yu Tsai
@ 2015-01-25 12:22 ` Chen-Yu Tsai
2015-01-25 12:22 ` [PATCH v2 6/9] ARM: dts: sunxi: Add usb3_vbus regulator to common regulators dtsi Chen-Yu Tsai
` (3 subsequent siblings)
8 siblings, 0 replies; 14+ messages in thread
From: Chen-Yu Tsai @ 2015-01-25 12:22 UTC (permalink / raw)
To: Maxime Ripard, Mike Turquette, Emilio Lopez, Rob Herring,
Grant Likely, Kishon Vijay Abraham I
Cc: Chen-Yu Tsai, linux-arm-kernel, devicetree, linux-kernel, linux-sunxi
The A80 has 3 EHCI/OHCI USB controllers.
Signed-off-by: Chen-Yu Tsai <wens@csie.org>
---
arch/arm/boot/dts/sun9i-a80.dtsi | 70 ++++++++++++++++++++++++++++++++++++++++
1 file changed, 70 insertions(+)
diff --git a/arch/arm/boot/dts/sun9i-a80.dtsi b/arch/arm/boot/dts/sun9i-a80.dtsi
index d7ebd9390b01..9483b15bfda7 100644
--- a/arch/arm/boot/dts/sun9i-a80.dtsi
+++ b/arch/arm/boot/dts/sun9i-a80.dtsi
@@ -355,6 +355,28 @@
*/
ranges = <0 0 0 0x20000000>;
+ ehci0: usb@00a00000 {
+ compatible = "allwinner,sun9i-a80-ehci", "generic-ehci";
+ reg = <0x00a00000 0x100>;
+ interrupts = <GIC_SPI 72 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&usb_mod_clk 1>;
+ resets = <&usb_mod_clk 17>;
+ phys = <&usbphy1>;
+ phy-names = "usb";
+ status = "disabled";
+ };
+
+ ohci0: usb@00a00400 {
+ compatible = "allwinner,sun9i-a80-ohci", "generic-ohci";
+ reg = <0x00a00400 0x100>;
+ interrupts = <GIC_SPI 73 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&usb_mod_clk 1>, <&usb_mod_clk 2>;
+ resets = <&usb_mod_clk 17>;
+ phys = <&usbphy1>;
+ phy-names = "usb";
+ status = "disabled";
+ };
+
usbphy1: phy@00a00800 {
compatible = "allwinner,sun9i-a80-usb-phy";
reg = <0x00a00800 0x4>;
@@ -366,6 +388,32 @@
#phy-cells = <0>;
};
+ ehci1: usb@00a01000 {
+ compatible = "allwinner,sun9i-a80-ehci", "generic-ehci";
+ reg = <0x00a01000 0x100>;
+ interrupts = <GIC_SPI 74 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&usb_mod_clk 3>;
+ resets = <&usb_mod_clk 18>;
+ phys = <&usbphy2>;
+ phy-names = "usb";
+ status = "disabled";
+ };
+
+ /*
+ * Even though ohci1 exists, it is never used as
+ * usb1 only has HSIC pins routed externally
+ */
+ ohci1: usb@00a01400 {
+ compatible = "allwinner,sun9i-a80-ohci", "generic-ohci";
+ reg = <0x00a01400 0x100>;
+ interrupts = <GIC_SPI 75 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&usb_mod_clk 3>, <&usb_mod_clk 4>;
+ resets = <&usb_mod_clk 18>;
+ phys = <&usbphy2>;
+ phy-names = "usb";
+ status = "disabled";
+ };
+
usbphy2: phy@00a01800 {
compatible = "allwinner,sun9i-a80-usb-phy";
reg = <0x00a01800 0x4>;
@@ -380,6 +428,28 @@
phy_type = "hsic";
};
+ ehci2: usb@00a02000 {
+ compatible = "allwinner,sun9i-a80-ehci", "generic-ehci";
+ reg = <0x00a02000 0x100>;
+ interrupts = <GIC_SPI 76 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&usb_mod_clk 5>;
+ resets = <&usb_mod_clk 19>;
+ phys = <&usbphy3>;
+ phy-names = "usb";
+ status = "disabled";
+ };
+
+ ohci2: usb@00a02400 {
+ compatible = "allwinner,sun9i-a80-ohci", "generic-ohci";
+ reg = <0x00a02400 0x100>;
+ interrupts = <GIC_SPI 77 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&usb_mod_clk 5>, <&usb_mod_clk 6>;
+ resets = <&usb_mod_clk 19>;
+ phys = <&usbphy3>;
+ phy-names = "usb";
+ status = "disabled";
+ };
+
usbphy3: phy@00a02800 {
compatible = "allwinner,sun9i-a80-usb-phy";
reg = <0x00a02800 0x4>;
--
2.1.4
^ permalink raw reply [flat|nested] 14+ messages in thread
* [PATCH v2 6/9] ARM: dts: sunxi: Add usb3_vbus regulator to common regulators dtsi
2015-01-25 12:22 [PATCH v2 0/9] ARM: sun9i: Add USB host controller support for A80 Chen-Yu Tsai
` (4 preceding siblings ...)
2015-01-25 12:22 ` [PATCH v2 5/9] ARM: dts: sun9i: Add USB host controller " Chen-Yu Tsai
@ 2015-01-25 12:22 ` Chen-Yu Tsai
2015-01-25 16:06 ` Maxime Ripard
2015-01-25 12:22 ` [PATCH v2 7/9] ARM: dts: sun9i: Enable USB support on A80 Optimus board Chen-Yu Tsai
` (2 subsequent siblings)
8 siblings, 1 reply; 14+ messages in thread
From: Chen-Yu Tsai @ 2015-01-25 12:22 UTC (permalink / raw)
To: Maxime Ripard, Mike Turquette, Emilio Lopez, Rob Herring,
Grant Likely, Kishon Vijay Abraham I
Cc: Chen-Yu Tsai, linux-arm-kernel, devicetree, linux-kernel, linux-sunxi
Some SoCs have a total of 4 possible USB controllers. One such example
is the A80, which has one USB3 dual role device and 3 EHCI/OHCI pairs.
Add a common VBUS regulator for the last host controller.
Signed-off-by: Chen-Yu Tsai <wens@csie.org>
---
arch/arm/boot/dts/sunxi-common-regulators.dtsi | 10 ++++++++++
1 file changed, 10 insertions(+)
diff --git a/arch/arm/boot/dts/sunxi-common-regulators.dtsi b/arch/arm/boot/dts/sunxi-common-regulators.dtsi
index e02baa66b33c..97fe8d73c4f7 100644
--- a/arch/arm/boot/dts/sunxi-common-regulators.dtsi
+++ b/arch/arm/boot/dts/sunxi-common-regulators.dtsi
@@ -130,6 +130,16 @@
status = "disabled";
};
+ reg_usb3_vbus: usb3-vbus {
+ compatible = "regulator-fixed";
+ pinctrl-names = "default";
+ regulator-name = "usb3-vbus";
+ regulator-min-microvolt = <5000000>;
+ regulator-max-microvolt = <5000000>;
+ enable-active-high;
+ status = "disabled";
+ };
+
reg_vcc3v0: vcc3v0 {
compatible = "regulator-fixed";
regulator-name = "vcc3v0";
--
2.1.4
^ permalink raw reply [flat|nested] 14+ messages in thread
* [PATCH v2 7/9] ARM: dts: sun9i: Enable USB support on A80 Optimus board
2015-01-25 12:22 [PATCH v2 0/9] ARM: sun9i: Add USB host controller support for A80 Chen-Yu Tsai
` (5 preceding siblings ...)
2015-01-25 12:22 ` [PATCH v2 6/9] ARM: dts: sunxi: Add usb3_vbus regulator to common regulators dtsi Chen-Yu Tsai
@ 2015-01-25 12:22 ` Chen-Yu Tsai
2015-01-25 12:22 ` [PATCH v2 8/9] ARM: sunxi_defconfig: Enable CONFIG_PHY_SUN9I_USB Chen-Yu Tsai
2015-01-25 12:22 ` [PATCH v2 9/9] ARM: multi_v7_defconfig: " Chen-Yu Tsai
8 siblings, 0 replies; 14+ messages in thread
From: Chen-Yu Tsai @ 2015-01-25 12:22 UTC (permalink / raw)
To: Maxime Ripard, Mike Turquette, Emilio Lopez, Rob Herring,
Grant Likely, Kishon Vijay Abraham I
Cc: Chen-Yu Tsai, linux-arm-kernel, devicetree, linux-kernel, linux-sunxi
Signed-off-by: Chen-Yu Tsai <wens@csie.org>
---
arch/arm/boot/dts/sun9i-a80-optimus.dts | 60 +++++++++++++++++++++++++++++++++
1 file changed, 60 insertions(+)
diff --git a/arch/arm/boot/dts/sun9i-a80-optimus.dts b/arch/arm/boot/dts/sun9i-a80-optimus.dts
index c4de9cb9a5f6..16d30bb3a872 100644
--- a/arch/arm/boot/dts/sun9i-a80-optimus.dts
+++ b/arch/arm/boot/dts/sun9i-a80-optimus.dts
@@ -83,6 +83,18 @@
};
};
+&ehci0 {
+ status = "okay";
+};
+
+&ehci1 {
+ status = "okay";
+};
+
+&ehci2 {
+ status = "okay";
+};
+
&i2c3 {
pinctrl-names = "default";
pinctrl-0 = <&i2c3_pins_a>;
@@ -94,6 +106,14 @@
allwinner,pull = <SUN4I_PINCTRL_PULL_UP>;
};
+&ohci0 {
+ status = "okay";
+};
+
+&ohci2 {
+ status = "okay";
+};
+
&pio {
led_pins_optimus: led-pins@0 {
allwinner,pins = "PH0", "PH1";
@@ -108,6 +128,20 @@
allwinner,drive = <SUN4I_PINCTRL_10_MA>;
allwinner,pull = <SUN4I_PINCTRL_PULL_UP>;
};
+
+ usb1_vbus_pin_optimus: usb1_vbus_pin@1 {
+ allwinner,pins = "PH4";
+ allwinner,function = "gpio_out";
+ allwinner,drive = <SUN4I_PINCTRL_10_MA>;
+ allwinner,pull = <SUN4I_PINCTRL_NO_PULL>;
+ };
+
+ usb3_vbus_pin_optimus: usb3_vbus_pin@1 {
+ allwinner,pins = "PH5";
+ allwinner,function = "gpio_out";
+ allwinner,drive = <SUN4I_PINCTRL_10_MA>;
+ allwinner,pull = <SUN4I_PINCTRL_NO_PULL>;
+ };
};
&mmc0 {
@@ -129,6 +163,18 @@
status = "okay";
};
+®_usb1_vbus {
+ pinctrl-0 = <&usb1_vbus_pin_optimus>;
+ gpio = <&pio 7 4 GPIO_ACTIVE_HIGH>; /* PH4 */
+ status = "okay";
+};
+
+®_usb3_vbus {
+ pinctrl-0 = <&usb3_vbus_pin_optimus>;
+ gpio = <&pio 7 5 GPIO_ACTIVE_HIGH>; /* PH5 */
+ status = "okay";
+};
+
&uart0 {
pinctrl-names = "default";
pinctrl-0 = <&uart0_pins_a>;
@@ -145,3 +191,17 @@
/* Enable internal pull-up */
allwinner,pull = <SUN4I_PINCTRL_PULL_UP>;
};
+
+&usbphy1 {
+ vbus-supply = <®_usb1_vbus>;
+ status = "okay";
+};
+
+&usbphy2 {
+ status = "okay";
+};
+
+&usbphy3 {
+ vbus-supply = <®_usb3_vbus>;
+ status = "okay";
+};
--
2.1.4
^ permalink raw reply [flat|nested] 14+ messages in thread
* [PATCH v2 8/9] ARM: sunxi_defconfig: Enable CONFIG_PHY_SUN9I_USB
2015-01-25 12:22 [PATCH v2 0/9] ARM: sun9i: Add USB host controller support for A80 Chen-Yu Tsai
` (6 preceding siblings ...)
2015-01-25 12:22 ` [PATCH v2 7/9] ARM: dts: sun9i: Enable USB support on A80 Optimus board Chen-Yu Tsai
@ 2015-01-25 12:22 ` Chen-Yu Tsai
2015-01-25 12:22 ` [PATCH v2 9/9] ARM: multi_v7_defconfig: " Chen-Yu Tsai
8 siblings, 0 replies; 14+ messages in thread
From: Chen-Yu Tsai @ 2015-01-25 12:22 UTC (permalink / raw)
To: Maxime Ripard, Mike Turquette, Emilio Lopez, Rob Herring,
Grant Likely, Kishon Vijay Abraham I
Cc: Chen-Yu Tsai, linux-arm-kernel, devicetree, linux-kernel, linux-sunxi
On sun9i we have a new PHY driver for USB.
Signed-off-by: Chen-Yu Tsai <wens@csie.org>
---
arch/arm/configs/sunxi_defconfig | 1 +
1 file changed, 1 insertion(+)
diff --git a/arch/arm/configs/sunxi_defconfig b/arch/arm/configs/sunxi_defconfig
index 38840a812924..6b271645eb43 100644
--- a/arch/arm/configs/sunxi_defconfig
+++ b/arch/arm/configs/sunxi_defconfig
@@ -106,6 +106,7 @@ CONFIG_RTC_DRV_SUN6I=y
CONFIG_RTC_DRV_SUNXI=y
# CONFIG_IOMMU_SUPPORT is not set
CONFIG_PHY_SUN4I_USB=y
+CONFIG_PHY_SUN9I_USB=y
CONFIG_EXT4_FS=y
CONFIG_VFAT_FS=y
CONFIG_TMPFS=y
--
2.1.4
^ permalink raw reply [flat|nested] 14+ messages in thread
* [PATCH v2 9/9] ARM: multi_v7_defconfig: Enable CONFIG_PHY_SUN9I_USB
2015-01-25 12:22 [PATCH v2 0/9] ARM: sun9i: Add USB host controller support for A80 Chen-Yu Tsai
` (7 preceding siblings ...)
2015-01-25 12:22 ` [PATCH v2 8/9] ARM: sunxi_defconfig: Enable CONFIG_PHY_SUN9I_USB Chen-Yu Tsai
@ 2015-01-25 12:22 ` Chen-Yu Tsai
8 siblings, 0 replies; 14+ messages in thread
From: Chen-Yu Tsai @ 2015-01-25 12:22 UTC (permalink / raw)
To: Maxime Ripard, Mike Turquette, Emilio Lopez, Rob Herring,
Grant Likely, Kishon Vijay Abraham I
Cc: Chen-Yu Tsai, linux-arm-kernel, devicetree, linux-kernel, linux-sunxi
On sun9i we have a new PHY driver for USB.
Signed-off-by: Chen-Yu Tsai <wens@csie.org>
---
arch/arm/configs/multi_v7_defconfig | 1 +
1 file changed, 1 insertion(+)
diff --git a/arch/arm/configs/multi_v7_defconfig b/arch/arm/configs/multi_v7_defconfig
index eec304487e6d..63fcc5522393 100644
--- a/arch/arm/configs/multi_v7_defconfig
+++ b/arch/arm/configs/multi_v7_defconfig
@@ -462,6 +462,7 @@ CONFIG_TI_PIPE3=y
CONFIG_PHY_MIPHY365X=y
CONFIG_PHY_STIH41X_USB=y
CONFIG_PHY_SUN4I_USB=y
+CONFIG_PHY_SUN9I_USB=y
CONFIG_EXT4_FS=y
CONFIG_AUTOFS4_FS=y
CONFIG_MSDOS_FS=y
--
2.1.4
^ permalink raw reply [flat|nested] 14+ messages in thread
* Re: [PATCH v2 1/9] clk: sunxi: Add support for sun9i a80 usb clocks and resets
2015-01-25 12:22 ` [PATCH v2 1/9] clk: sunxi: Add support for sun9i a80 usb clocks and resets Chen-Yu Tsai
@ 2015-01-25 16:02 ` Maxime Ripard
2015-01-26 9:25 ` Chen-Yu Tsai
0 siblings, 1 reply; 14+ messages in thread
From: Maxime Ripard @ 2015-01-25 16:02 UTC (permalink / raw)
To: Chen-Yu Tsai
Cc: Mike Turquette, Emilio Lopez, Rob Herring, Grant Likely,
Kishon Vijay Abraham I, linux-arm-kernel, devicetree,
linux-kernel, linux-sunxi
[-- Attachment #1: Type: text/plain, Size: 8642 bytes --]
Hi,
On Sun, Jan 25, 2015 at 08:22:02PM +0800, Chen-Yu Tsai wrote:
> The USB controller/phy clocks and reset controls are in a separate
> address block, unlike previous SoCs where they were in the clock
> controller.
>
> This patch copies the original gates clk functions used for usb
> clocks into a separate file, and renames them to *_usb_*. Also
> add a per-gate parent index, so we can set different parents for
> each gate.
>
> Signed-off-by: Chen-Yu Tsai <wens@csie.org>
> ---
> Documentation/devicetree/bindings/clock/sunxi.txt | 2 +
> drivers/clk/sunxi/Makefile | 1 +
> drivers/clk/sunxi/clk-usb.c | 193 ++++++++++++++++++++++
> 3 files changed, 196 insertions(+)
> create mode 100644 drivers/clk/sunxi/clk-usb.c
>
> diff --git a/Documentation/devicetree/bindings/clock/sunxi.txt b/Documentation/devicetree/bindings/clock/sunxi.txt
> index 60b44285250d..3f1dcd879af7 100644
> --- a/Documentation/devicetree/bindings/clock/sunxi.txt
> +++ b/Documentation/devicetree/bindings/clock/sunxi.txt
> @@ -66,6 +66,8 @@ Required properties:
> "allwinner,sun4i-a10-usb-clk" - for usb gates + resets on A10 / A20
> "allwinner,sun5i-a13-usb-clk" - for usb gates + resets on A13
> "allwinner,sun6i-a31-usb-clk" - for usb gates + resets on A31
> + "allwinner,sun9i-a80-usb-mod-clk" - for usb gates + resets on A80
> + "allwinner,sun9i-a80-usb-phy-clk" - for usb phy gates + resets on A80
>
> Required properties for all clocks:
> - reg : shall be the control register address for the clock.
> diff --git a/drivers/clk/sunxi/Makefile b/drivers/clk/sunxi/Makefile
> index 3a5292e3fcf8..058f273d6154 100644
> --- a/drivers/clk/sunxi/Makefile
> +++ b/drivers/clk/sunxi/Makefile
> @@ -9,6 +9,7 @@ obj-y += clk-mod0.o
> obj-y += clk-sun8i-mbus.o
> obj-y += clk-sun9i-core.o
> obj-y += clk-sun9i-mmc.o
> +obj-y += clk-usb.o
Is that supposed to handle the other USB clocks in the future as well?
>
> obj-$(CONFIG_MFD_SUN6I_PRCM) += \
> clk-sun6i-ar100.o clk-sun6i-apb0.o clk-sun6i-apb0-gates.o \
> diff --git a/drivers/clk/sunxi/clk-usb.c b/drivers/clk/sunxi/clk-usb.c
> new file mode 100644
> index 000000000000..1a93400353de
> --- /dev/null
> +++ b/drivers/clk/sunxi/clk-usb.c
> @@ -0,0 +1,193 @@
> +/*
> + * Copyright 2013 Emilio López
> + *
> + * Emilio López <emilio@elopez.com.ar>
Hmmmm, the copyright notice seems weird :)
> + *
> + * This program is free software; you can redistribute it and/or modify
> + * it under the terms of the GNU General Public License as published by
> + * the Free Software Foundation; either version 2 of the License, or
> + * (at your option) any later version.
> + *
> + * This program is distributed in the hope that it will be useful,
> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
> + * GNU General Public License for more details.
> + */
> +
> +#include <linux/clk-provider.h>
> +#include <linux/clkdev.h>
> +#include <linux/of.h>
> +#include <linux/of_address.h>
> +#include <linux/reset-controller.h>
> +#include <linux/spinlock.h>
> +
> +
> +/**
> + * sunxi_usb_reset... - reset bits in usb clk registers handling
> + */
> +
> +struct usb_reset_data {
> + void __iomem *reg;
> + spinlock_t *lock;
> + struct clk *clk;
> + struct reset_controller_dev rcdev;
> +};
> +
> +static int sunxi_usb_reset_assert(struct reset_controller_dev *rcdev,
> + unsigned long id)
> +{
> + struct usb_reset_data *data = container_of(rcdev,
> + struct usb_reset_data,
> + rcdev);
> + unsigned long flags;
> + u32 reg;
> +
> + clk_prepare_enable(data->clk);
> + spin_lock_irqsave(data->lock, flags);
> +
> + reg = readl(data->reg);
> + writel(reg & ~BIT(id), data->reg);
> +
> + spin_unlock_irqrestore(data->lock, flags);
> + clk_disable_unprepare(data->clk);
> +
> + return 0;
> +}
> +
> +static int sunxi_usb_reset_deassert(struct reset_controller_dev *rcdev,
> + unsigned long id)
> +{
> + struct usb_reset_data *data = container_of(rcdev,
> + struct usb_reset_data,
> + rcdev);
> + unsigned long flags;
> + u32 reg;
> +
> + clk_prepare_enable(data->clk);
> + spin_lock_irqsave(data->lock, flags);
> +
> + reg = readl(data->reg);
> + writel(reg | BIT(id), data->reg);
> +
> + spin_unlock_irqrestore(data->lock, flags);
> + clk_disable_unprepare(data->clk);
> +
> + return 0;
> +}
> +
> +static struct reset_control_ops sunxi_usb_reset_ops = {
> + .assert = sunxi_usb_reset_assert,
> + .deassert = sunxi_usb_reset_deassert,
> +};
> +
> +/**
> + * sunxi_usb_clk_setup() - Setup function for usb gate clocks
> + */
> +
> +#define SUNXI_USB_MAX_SIZE 32
> +
> +struct usb_clk_data {
> + u32 clk_mask;
> + u32 reset_mask;
> + bool reset_needs_clk;
> +};
> +
> +static void __init sunxi_usb_clk_setup(struct device_node *node,
> + const struct usb_clk_data *data,
> + spinlock_t *lock)
> +{
> + struct clk_onecell_data *clk_data;
> + struct usb_reset_data *reset_data;
> + const char *clk_parent;
> + const char *clk_name;
> + void __iomem *reg;
> + int qty;
> + int i = 0;
> + int j = 0;
> +
> + reg = of_io_request_and_map(node, 0, of_node_full_name(node));
You should check the return code here.
> + clk_parent = of_clk_get_parent_name(node, 0);
> + if (!clk_parent)
> + return;
> +
> + /* Worst-case size approximation and memory allocation */
> + qty = find_last_bit((unsigned long *)&data->clk_mask,
> + SUNXI_USB_MAX_SIZE);
Newline
> + clk_data = kmalloc(sizeof(struct clk_onecell_data), GFP_KERNEL);
> + if (!clk_data)
> + return;
Newline.
> + clk_data->clks = kzalloc((qty+1) * sizeof(struct clk *), GFP_KERNEL);
> + if (!clk_data->clks) {
> + kfree(clk_data);
> + return;
> + }
> +
> + for_each_set_bit(i, (unsigned long *)&data->clk_mask,
> + SUNXI_USB_MAX_SIZE) {
> + of_property_read_string_index(node, "clock-output-names",
> + j, &clk_name);
> + clk_data->clks[i] = clk_register_gate(NULL, clk_name,
> + clk_parent, 0,
> + reg, i, 0, lock);
> + WARN_ON(IS_ERR(clk_data->clks[i]));
> + clk_register_clkdev(clk_data->clks[i], clk_name, NULL);
Do we really need to use clkdev for these clocks?
> + j++;
> + }
> +
> + /* Adjust to the real max */
> + clk_data->clk_num = i;
> +
> + of_clk_add_provider(node, of_clk_src_onecell_get, clk_data);
> +
> + /* Register a reset controller for usb with reset bits */
> + if (data->reset_mask == 0)
> + return;
> +
> + reset_data = kzalloc(sizeof(*reset_data), GFP_KERNEL);
> + if (!reset_data)
> + return;
> +
> + if (data->reset_needs_clk)
> + reset_data->clk = of_clk_get(node, 0);
Newline
> + if (IS_ERR(reset_data->clk)) {
> + pr_err("Could not get clock for reset controls\n");
> + kfree(reset_data);
> + return;
> + }
Newline, and that block should probably be part of the if block above.
> + reset_data->reg = reg;
> + reset_data->lock = lock;
> + reset_data->rcdev.nr_resets = __fls(data->reset_mask) + 1;
> + reset_data->rcdev.ops = &sunxi_usb_reset_ops;
> + reset_data->rcdev.of_node = node;
> + reset_controller_register(&reset_data->rcdev);
> +}
> +
> +static const struct usb_clk_data sun9i_a80_usb_mod_data __initconst = {
> + .clk_mask = BIT(6) | BIT(5) | BIT(4) | BIT(3) | BIT(2) | BIT(1),
> + .reset_mask = BIT(19) | BIT(18) | BIT(17),
> + .reset_needs_clk = 1,
> +};
> +
> +static DEFINE_SPINLOCK(a80_usb_mod_lock);
> +
> +static void __init sun9i_a80_usb_mod_setup(struct device_node *node)
> +{
> + sunxi_usb_clk_setup(node, &sun9i_a80_usb_mod_data, &a80_usb_mod_lock);
> +}
> +CLK_OF_DECLARE(sun9i_a80_usb_mod, "allwinner,sun9i-a80-usb-mod-clk", sun9i_a80_usb_mod_setup);
> +
> +static const struct usb_clk_data sun9i_a80_usb_phy_data __initconst = {
> + .clk_mask = BIT(10) | BIT(5) | BIT(4) | BIT(3) | BIT(2) | BIT(1),
> + .reset_mask = BIT(21) | BIT(20) | BIT(19) | BIT(18) | BIT(17),
> + .reset_needs_clk = 1,
> +};
> +
> +static DEFINE_SPINLOCK(a80_usb_phy_lock);
> +
> +static void __init sun9i_a80_usb_phy_setup(struct device_node *node)
> +{
> + sunxi_usb_clk_setup(node, &sun9i_a80_usb_phy_data, &a80_usb_phy_lock);
> +}
> +CLK_OF_DECLARE(sun9i_a80_usb_phy, "allwinner,sun9i-a80-usb-phy-clk", sun9i_a80_usb_phy_setup);
Looks good otherwise, thanks!
Maxime
--
Maxime Ripard, Free Electrons
Embedded Linux, Kernel and Android engineering
http://free-electrons.com
[-- Attachment #2: Digital signature --]
[-- Type: application/pgp-signature, Size: 819 bytes --]
^ permalink raw reply [flat|nested] 14+ messages in thread
* Re: [PATCH v2 6/9] ARM: dts: sunxi: Add usb3_vbus regulator to common regulators dtsi
2015-01-25 12:22 ` [PATCH v2 6/9] ARM: dts: sunxi: Add usb3_vbus regulator to common regulators dtsi Chen-Yu Tsai
@ 2015-01-25 16:06 ` Maxime Ripard
0 siblings, 0 replies; 14+ messages in thread
From: Maxime Ripard @ 2015-01-25 16:06 UTC (permalink / raw)
To: Chen-Yu Tsai
Cc: Mike Turquette, Emilio Lopez, Rob Herring, Grant Likely,
Kishon Vijay Abraham I, linux-arm-kernel, devicetree,
linux-kernel, linux-sunxi
[-- Attachment #1: Type: text/plain, Size: 1360 bytes --]
On Sun, Jan 25, 2015 at 08:22:07PM +0800, Chen-Yu Tsai wrote:
> Some SoCs have a total of 4 possible USB controllers. One such example
> is the A80, which has one USB3 dual role device and 3 EHCI/OHCI pairs.
>
> Add a common VBUS regulator for the last host controller.
>
> Signed-off-by: Chen-Yu Tsai <wens@csie.org>
> ---
> arch/arm/boot/dts/sunxi-common-regulators.dtsi | 10 ++++++++++
> 1 file changed, 10 insertions(+)
>
> diff --git a/arch/arm/boot/dts/sunxi-common-regulators.dtsi b/arch/arm/boot/dts/sunxi-common-regulators.dtsi
> index e02baa66b33c..97fe8d73c4f7 100644
> --- a/arch/arm/boot/dts/sunxi-common-regulators.dtsi
> +++ b/arch/arm/boot/dts/sunxi-common-regulators.dtsi
> @@ -130,6 +130,16 @@
> status = "disabled";
> };
>
> + reg_usb3_vbus: usb3-vbus {
> + compatible = "regulator-fixed";
> + pinctrl-names = "default";
> + regulator-name = "usb3-vbus";
> + regulator-min-microvolt = <5000000>;
> + regulator-max-microvolt = <5000000>;
> + enable-active-high;
> + status = "disabled";
> + };
> +
If the A80 is the only user so far, maybe that would make more sense
to have it in the A80 dtsi? Especially since this regulator doesn't
really do anything else than reg_vcc5v0.
--
Maxime Ripard, Free Electrons
Embedded Linux, Kernel and Android engineering
http://free-electrons.com
[-- Attachment #2: Digital signature --]
[-- Type: application/pgp-signature, Size: 819 bytes --]
^ permalink raw reply [flat|nested] 14+ messages in thread
* Re: [PATCH v2 1/9] clk: sunxi: Add support for sun9i a80 usb clocks and resets
2015-01-25 16:02 ` Maxime Ripard
@ 2015-01-26 9:25 ` Chen-Yu Tsai
2015-01-26 13:37 ` Maxime Ripard
0 siblings, 1 reply; 14+ messages in thread
From: Chen-Yu Tsai @ 2015-01-26 9:25 UTC (permalink / raw)
To: Maxime Ripard
Cc: Rob Herring, linux-kernel, Mike Turquette, devicetree,
Emilio Lopez, Kishon Vijay Abraham I, Grant Likely,
linux-arm-kernel, linux-sunxi
Hi,
2015年1月25日 下午11:05 於 "Maxime Ripard" <maxime.ripard@free-electrons.com> 寫道:
>
> Hi,
>
> On Sun, Jan 25, 2015 at 08:22:02PM +0800, Chen-Yu Tsai wrote:
> > The USB controller/phy clocks and reset controls are in a separate
> > address block, unlike previous SoCs where they were in the clock
> > controller.
> >
> > This patch copies the original gates clk functions used for usb
> > clocks into a separate file, and renames them to *_usb_*. Also
> > add a per-gate parent index, so we can set different parents for
> > each gate.
> >
> > Signed-off-by: Chen-Yu Tsai <wens@csie.org>
> > ---
> > Documentation/devicetree/bindings/clock/sunxi.txt | 2 +
> > drivers/clk/sunxi/Makefile | 1 +
> > drivers/clk/sunxi/clk-usb.c | 193 ++++++++++++++++++++++
> > 3 files changed, 196 insertions(+)
> > create mode 100644 drivers/clk/sunxi/clk-usb.c
> >
> > diff --git a/Documentation/devicetree/bindings/clock/sunxi.txt b/Documentation/devicetree/bindings/clock/sunxi.txt
> > index 60b44285250d..3f1dcd879af7 100644
> > --- a/Documentation/devicetree/bindings/clock/sunxi.txt
> > +++ b/Documentation/devicetree/bindings/clock/sunxi.txt
> > @@ -66,6 +66,8 @@ Required properties:
> > "allwinner,sun4i-a10-usb-clk" - for usb gates + resets on A10 / A20
> > "allwinner,sun5i-a13-usb-clk" - for usb gates + resets on A13
> > "allwinner,sun6i-a31-usb-clk" - for usb gates + resets on A31
> > + "allwinner,sun9i-a80-usb-mod-clk" - for usb gates + resets on A80
> > + "allwinner,sun9i-a80-usb-phy-clk" - for usb phy gates + resets on A80
> >
> > Required properties for all clocks:
> > - reg : shall be the control register address for the clock.
> > diff --git a/drivers/clk/sunxi/Makefile b/drivers/clk/sunxi/Makefile
> > index 3a5292e3fcf8..058f273d6154 100644
> > --- a/drivers/clk/sunxi/Makefile
> > +++ b/drivers/clk/sunxi/Makefile
> > @@ -9,6 +9,7 @@ obj-y += clk-mod0.o
> > obj-y += clk-sun8i-mbus.o
> > obj-y += clk-sun9i-core.o
> > obj-y += clk-sun9i-mmc.o
> > +obj-y += clk-usb.o
>
> Is that supposed to handle the other USB clocks in the future as well?
I plan to do that. If you compare this and the original USB clk driver,
you'll notice it's pretty much the same.
> >
> > obj-$(CONFIG_MFD_SUN6I_PRCM) += \
> > clk-sun6i-ar100.o clk-sun6i-apb0.o clk-sun6i-apb0-gates.o \
> > diff --git a/drivers/clk/sunxi/clk-usb.c b/drivers/clk/sunxi/clk-usb.c
> > new file mode 100644
> > index 000000000000..1a93400353de
> > --- /dev/null
> > +++ b/drivers/clk/sunxi/clk-usb.c
> > @@ -0,0 +1,193 @@
> > +/*
> > + * Copyright 2013 Emilio López
> > + *
> > + * Emilio López <emilio@elopez.com.ar>
>
> Hmmmm, the copyright notice seems weird :)
The code was pulled from clk-sunxi.c, which only has Emilio's
copyright. I suppose I could dig up who actually wrote the code.
I think it was Hans.
> > + *
> > + * This program is free software; you can redistribute it and/or modify
> > + * it under the terms of the GNU General Public License as published by
> > + * the Free Software Foundation; either version 2 of the License, or
> > + * (at your option) any later version.
> > + *
> > + * This program is distributed in the hope that it will be useful,
> > + * but WITHOUT ANY WARRANTY; without even the implied warranty of
> > + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
> > + * GNU General Public License for more details.
> > + */
> > +
> > +#include <linux/clk-provider.h>
> > +#include <linux/clkdev.h>
> > +#include <linux/of.h>
> > +#include <linux/of_address.h>
> > +#include <linux/reset-controller.h>
> > +#include <linux/spinlock.h>
> > +
> > +
> > +/**
> > + * sunxi_usb_reset... - reset bits in usb clk registers handling
> > + */
> > +
> > +struct usb_reset_data {
> > + void __iomem *reg;
> > + spinlock_t *lock;
> > + struct clk *clk;
> > + struct reset_controller_dev rcdev;
> > +};
> > +
> > +static int sunxi_usb_reset_assert(struct reset_controller_dev *rcdev,
> > + unsigned long id)
> > +{
> > + struct usb_reset_data *data = container_of(rcdev,
> > + struct usb_reset_data,
> > + rcdev);
> > + unsigned long flags;
> > + u32 reg;
> > +
> > + clk_prepare_enable(data->clk);
> > + spin_lock_irqsave(data->lock, flags);
> > +
> > + reg = readl(data->reg);
> > + writel(reg & ~BIT(id), data->reg);
> > +
> > + spin_unlock_irqrestore(data->lock, flags);
> > + clk_disable_unprepare(data->clk);
> > +
> > + return 0;
> > +}
> > +
> > +static int sunxi_usb_reset_deassert(struct reset_controller_dev *rcdev,
> > + unsigned long id)
> > +{
> > + struct usb_reset_data *data = container_of(rcdev,
> > + struct usb_reset_data,
> > + rcdev);
> > + unsigned long flags;
> > + u32 reg;
> > +
> > + clk_prepare_enable(data->clk);
> > + spin_lock_irqsave(data->lock, flags);
> > +
> > + reg = readl(data->reg);
> > + writel(reg | BIT(id), data->reg);
> > +
> > + spin_unlock_irqrestore(data->lock, flags);
> > + clk_disable_unprepare(data->clk);
> > +
> > + return 0;
> > +}
> > +
> > +static struct reset_control_ops sunxi_usb_reset_ops = {
> > + .assert = sunxi_usb_reset_assert,
> > + .deassert = sunxi_usb_reset_deassert,
> > +};
> > +
> > +/**
> > + * sunxi_usb_clk_setup() - Setup function for usb gate clocks
> > + */
> > +
> > +#define SUNXI_USB_MAX_SIZE 32
> > +
> > +struct usb_clk_data {
> > + u32 clk_mask;
> > + u32 reset_mask;
> > + bool reset_needs_clk;
> > +};
> > +
> > +static void __init sunxi_usb_clk_setup(struct device_node *node,
> > + const struct usb_clk_data *data,
> > + spinlock_t *lock)
> > +{
> > + struct clk_onecell_data *clk_data;
> > + struct usb_reset_data *reset_data;
> > + const char *clk_parent;
> > + const char *clk_name;
> > + void __iomem *reg;
> > + int qty;
> > + int i = 0;
> > + int j = 0;
> > +
> > + reg = of_io_request_and_map(node, 0, of_node_full_name(node));
>
> You should check the return code here.
Right.
> > + clk_parent = of_clk_get_parent_name(node, 0);
> > + if (!clk_parent)
> > + return;
> > +
> > + /* Worst-case size approximation and memory allocation */
> > + qty = find_last_bit((unsigned long *)&data->clk_mask,
> > + SUNXI_USB_MAX_SIZE);
>
> Newline
OK.
> > + clk_data = kmalloc(sizeof(struct clk_onecell_data), GFP_KERNEL);
> > + if (!clk_data)
> > + return;
>
> Newline.
OK.
> > + clk_data->clks = kzalloc((qty+1) * sizeof(struct clk *), GFP_KERNEL);
> > + if (!clk_data->clks) {
> > + kfree(clk_data);
> > + return;
> > + }
> > +
> > + for_each_set_bit(i, (unsigned long *)&data->clk_mask,
> > + SUNXI_USB_MAX_SIZE) {
> > + of_property_read_string_index(node, "clock-output-names",
> > + j, &clk_name);
> > + clk_data->clks[i] = clk_register_gate(NULL, clk_name,
> > + clk_parent, 0,
> > + reg, i, 0, lock);
> > + WARN_ON(IS_ERR(clk_data->clks[i]));
> > + clk_register_clkdev(clk_data->clks[i], clk_name, NULL);
>
> Do we really need to use clkdev for these clocks?
Original code. I don't think we do.
> > + j++;
> > + }
> > +
> > + /* Adjust to the real max */
> > + clk_data->clk_num = i;
> > +
> > + of_clk_add_provider(node, of_clk_src_onecell_get, clk_data);
> > +
> > + /* Register a reset controller for usb with reset bits */
> > + if (data->reset_mask == 0)
> > + return;
> > +
> > + reset_data = kzalloc(sizeof(*reset_data), GFP_KERNEL);
> > + if (!reset_data)
> > + return;
> > +
> > + if (data->reset_needs_clk)
> > + reset_data->clk = of_clk_get(node, 0);
>
> Newline
OK.
> > + if (IS_ERR(reset_data->clk)) {
> > + pr_err("Could not get clock for reset controls\n");
> > + kfree(reset_data);
> > + return;
> > + }
>
> Newline, and that block should probably be part of the if block above.
NULL is not considered an error, but maybe being in the same block
makes it clear that they are related.
> > + reset_data->reg = reg;
> > + reset_data->lock = lock;
> > + reset_data->rcdev.nr_resets = __fls(data->reset_mask) + 1;
> > + reset_data->rcdev.ops = &sunxi_usb_reset_ops;
> > + reset_data->rcdev.of_node = node;
> > + reset_controller_register(&reset_data->rcdev);
> > +}
> > +
> > +static const struct usb_clk_data sun9i_a80_usb_mod_data __initconst = {
> > + .clk_mask = BIT(6) | BIT(5) | BIT(4) | BIT(3) | BIT(2) | BIT(1),
> > + .reset_mask = BIT(19) | BIT(18) | BIT(17),
> > + .reset_needs_clk = 1,
> > +};
> > +
> > +static DEFINE_SPINLOCK(a80_usb_mod_lock);
> > +
> > +static void __init sun9i_a80_usb_mod_setup(struct device_node *node)
> > +{
> > + sunxi_usb_clk_setup(node, &sun9i_a80_usb_mod_data, &a80_usb_mod_lock);
> > +}
> > +CLK_OF_DECLARE(sun9i_a80_usb_mod, "allwinner,sun9i-a80-usb-mod-clk", sun9i_a80_usb_mod_setup);
> > +
> > +static const struct usb_clk_data sun9i_a80_usb_phy_data __initconst = {
> > + .clk_mask = BIT(10) | BIT(5) | BIT(4) | BIT(3) | BIT(2) | BIT(1),
> > + .reset_mask = BIT(21) | BIT(20) | BIT(19) | BIT(18) | BIT(17),
> > + .reset_needs_clk = 1,
> > +};
> > +
> > +static DEFINE_SPINLOCK(a80_usb_phy_lock);
> > +
> > +static void __init sun9i_a80_usb_phy_setup(struct device_node *node)
> > +{
> > + sunxi_usb_clk_setup(node, &sun9i_a80_usb_phy_data, &a80_usb_phy_lock);
> > +}
> > +CLK_OF_DECLARE(sun9i_a80_usb_phy, "allwinner,sun9i-a80-usb-phy-clk", sun9i_a80_usb_phy_setup);
>
> Looks good otherwise, thanks!
Thanks.
ChenYu
^ permalink raw reply [flat|nested] 14+ messages in thread
* Re: [PATCH v2 1/9] clk: sunxi: Add support for sun9i a80 usb clocks and resets
2015-01-26 9:25 ` Chen-Yu Tsai
@ 2015-01-26 13:37 ` Maxime Ripard
0 siblings, 0 replies; 14+ messages in thread
From: Maxime Ripard @ 2015-01-26 13:37 UTC (permalink / raw)
To: Chen-Yu Tsai
Cc: Rob Herring, linux-kernel, Mike Turquette, devicetree,
Emilio Lopez, Kishon Vijay Abraham I, Grant Likely,
linux-arm-kernel, linux-sunxi
[-- Attachment #1: Type: text/plain, Size: 5340 bytes --]
On Mon, Jan 26, 2015 at 05:25:49PM +0800, Chen-Yu Tsai wrote:
> Hi,
>
> 2015年1月25日 下午11:05 於 "Maxime Ripard" <maxime.ripard@free-electrons.com> 寫道:
> >
> > Hi,
> >
> > On Sun, Jan 25, 2015 at 08:22:02PM +0800, Chen-Yu Tsai wrote:
> > > The USB controller/phy clocks and reset controls are in a separate
> > > address block, unlike previous SoCs where they were in the clock
> > > controller.
> > >
> > > This patch copies the original gates clk functions used for usb
> > > clocks into a separate file, and renames them to *_usb_*. Also
> > > add a per-gate parent index, so we can set different parents for
> > > each gate.
> > >
> > > Signed-off-by: Chen-Yu Tsai <wens@csie.org>
> > > ---
> > > Documentation/devicetree/bindings/clock/sunxi.txt | 2 +
> > > drivers/clk/sunxi/Makefile | 1 +
> > > drivers/clk/sunxi/clk-usb.c | 193 ++++++++++++++++++++++
> > > 3 files changed, 196 insertions(+)
> > > create mode 100644 drivers/clk/sunxi/clk-usb.c
> > >
> > > diff --git a/Documentation/devicetree/bindings/clock/sunxi.txt b/Documentation/devicetree/bindings/clock/sunxi.txt
> > > index 60b44285250d..3f1dcd879af7 100644
> > > --- a/Documentation/devicetree/bindings/clock/sunxi.txt
> > > +++ b/Documentation/devicetree/bindings/clock/sunxi.txt
> > > @@ -66,6 +66,8 @@ Required properties:
> > > "allwinner,sun4i-a10-usb-clk" - for usb gates + resets on A10 / A20
> > > "allwinner,sun5i-a13-usb-clk" - for usb gates + resets on A13
> > > "allwinner,sun6i-a31-usb-clk" - for usb gates + resets on A31
> > > + "allwinner,sun9i-a80-usb-mod-clk" - for usb gates + resets on A80
> > > + "allwinner,sun9i-a80-usb-phy-clk" - for usb phy gates + resets on A80
> > >
> > > Required properties for all clocks:
> > > - reg : shall be the control register address for the clock.
> > > diff --git a/drivers/clk/sunxi/Makefile b/drivers/clk/sunxi/Makefile
> > > index 3a5292e3fcf8..058f273d6154 100644
> > > --- a/drivers/clk/sunxi/Makefile
> > > +++ b/drivers/clk/sunxi/Makefile
> > > @@ -9,6 +9,7 @@ obj-y += clk-mod0.o
> > > obj-y += clk-sun8i-mbus.o
> > > obj-y += clk-sun9i-core.o
> > > obj-y += clk-sun9i-mmc.o
> > > +obj-y += clk-usb.o
> >
> > Is that supposed to handle the other USB clocks in the future as well?
>
> I plan to do that. If you compare this and the original USB clk driver,
> you'll notice it's pretty much the same.
Yeah, hence why I asked :)
I'd rather not have two distinct copies of the same code. Could you
move these old clocks first, and then add the A80 clocks?
At least your commit log somewhat induces that this is new code, while
it clearly isn't.
> > >
> > > obj-$(CONFIG_MFD_SUN6I_PRCM) += \
> > > clk-sun6i-ar100.o clk-sun6i-apb0.o clk-sun6i-apb0-gates.o \
> > > diff --git a/drivers/clk/sunxi/clk-usb.c b/drivers/clk/sunxi/clk-usb.c
> > > new file mode 100644
> > > index 000000000000..1a93400353de
> > > --- /dev/null
> > > +++ b/drivers/clk/sunxi/clk-usb.c
> > > @@ -0,0 +1,193 @@
> > > +/*
> > > + * Copyright 2013 Emilio López
> > > + *
> > > + * Emilio López <emilio@elopez.com.ar>
> >
> > Hmmmm, the copyright notice seems weird :)
>
> The code was pulled from clk-sunxi.c, which only has Emilio's
> copyright. I suppose I could dig up who actually wrote the code.
> I think it was Hans.
Ok. The copyright date should at least be updated.
> > > + clk_data->clks = kzalloc((qty+1) * sizeof(struct clk *), GFP_KERNEL);
> > > + if (!clk_data->clks) {
> > > + kfree(clk_data);
> > > + return;
> > > + }
> > > +
> > > + for_each_set_bit(i, (unsigned long *)&data->clk_mask,
> > > + SUNXI_USB_MAX_SIZE) {
> > > + of_property_read_string_index(node, "clock-output-names",
> > > + j, &clk_name);
> > > + clk_data->clks[i] = clk_register_gate(NULL, clk_name,
> > > + clk_parent, 0,
> > > + reg, i, 0, lock);
> > > + WARN_ON(IS_ERR(clk_data->clks[i]));
> > > + clk_register_clkdev(clk_data->clks[i], clk_name, NULL);
> >
> > Do we really need to use clkdev for these clocks?
>
> Original code. I don't think we do.
The only reason why we should have clkdev is for the protected
clocks. We should move away from that code, and I don't think any of
the USB clocks are in that case anyway.
> > > + if (IS_ERR(reset_data->clk)) {
> > > + pr_err("Could not get clock for reset controls\n");
> > > + kfree(reset_data);
> > > + return;
> > > + }
> >
> > Newline, and that block should probably be part of the if block above.
>
> NULL is not considered an error, but maybe being in the same block
> makes it clear that they are related.
Yeah, maybe it's just me, but it triggered a might-be-uninitialized
warning in my brain while reading it (while the kzalloc above
obviously takes care of it)
It would be more logical to have that inside the if statement.
Maxime
--
Maxime Ripard, Free Electrons
Embedded Linux, Kernel and Android engineering
http://free-electrons.com
[-- Attachment #2: Digital signature --]
[-- Type: application/pgp-signature, Size: 819 bytes --]
^ permalink raw reply [flat|nested] 14+ messages in thread
end of thread, other threads:[~2015-01-26 13:40 UTC | newest]
Thread overview: 14+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2015-01-25 12:22 [PATCH v2 0/9] ARM: sun9i: Add USB host controller support for A80 Chen-Yu Tsai
2015-01-25 12:22 ` [PATCH v2 1/9] clk: sunxi: Add support for sun9i a80 usb clocks and resets Chen-Yu Tsai
2015-01-25 16:02 ` Maxime Ripard
2015-01-26 9:25 ` Chen-Yu Tsai
2015-01-26 13:37 ` Maxime Ripard
2015-01-25 12:22 ` [PATCH v2 2/9] ARM: dts: sun9i: Add usb clock nodes to a80 dtsi Chen-Yu Tsai
2015-01-25 12:22 ` [PATCH v2 3/9] phy: Add driver to support individual USB PHYs on sun9i Chen-Yu Tsai
2015-01-25 12:22 ` [PATCH v2 4/9] ARM: dts: sun9i: Add usb phy nodes to a80 dtsi Chen-Yu Tsai
2015-01-25 12:22 ` [PATCH v2 5/9] ARM: dts: sun9i: Add USB host controller " Chen-Yu Tsai
2015-01-25 12:22 ` [PATCH v2 6/9] ARM: dts: sunxi: Add usb3_vbus regulator to common regulators dtsi Chen-Yu Tsai
2015-01-25 16:06 ` Maxime Ripard
2015-01-25 12:22 ` [PATCH v2 7/9] ARM: dts: sun9i: Enable USB support on A80 Optimus board Chen-Yu Tsai
2015-01-25 12:22 ` [PATCH v2 8/9] ARM: sunxi_defconfig: Enable CONFIG_PHY_SUN9I_USB Chen-Yu Tsai
2015-01-25 12:22 ` [PATCH v2 9/9] ARM: multi_v7_defconfig: " Chen-Yu Tsai
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).