[PATCH v3 1/5] Add clk wizard and mxic host controller driver
JaimeLiao
jaimeliao.tw at gmail.com
Thu Nov 9 03:24:56 PST 2023
Signed-off-by: JaimeLiao <jaimeliao at mxic.com.tw>
---
arch/arm/boot/dts/xilinx/zynq-7000.dtsi | 4 +-
.../dts/xilinx/zynq-mxic-picozed.spi-nand.dts | 141 ++++++
.../zynq-mxic-picozed.spi-nand_manual.dts | 141 ++++++
.../dts/xilinx/zynq-mxic-picozed.spi-nor.dts | 142 ++++++
drivers/clk/Kconfig | 1 +
drivers/clk/zynq/Kconfig | 6 +
drivers/clk/zynq/Makefile | 1 +
drivers/clk/zynq/clk-wizard.c | 409 ++++++++++++++++++
drivers/spi/spi-mxic.c | 84 ++--
9 files changed, 885 insertions(+), 44 deletions(-)
create mode 100644 arch/arm/boot/dts/xilinx/zynq-mxic-picozed.spi-nand.dts
create mode 100644 arch/arm/boot/dts/xilinx/zynq-mxic-picozed.spi-nand_manual.dts
create mode 100644 arch/arm/boot/dts/xilinx/zynq-mxic-picozed.spi-nor.dts
create mode 100644 drivers/clk/zynq/Kconfig
create mode 100644 drivers/clk/zynq/clk-wizard.c
diff --git a/arch/arm/boot/dts/xilinx/zynq-7000.dtsi b/arch/arm/boot/dts/xilinx/zynq-7000.dtsi
index a7db3f3009f2..45c207b62396 100644
--- a/arch/arm/boot/dts/xilinx/zynq-7000.dtsi
+++ b/arch/arm/boot/dts/xilinx/zynq-7000.dtsi
@@ -289,7 +289,7 @@
sdhci0: mmc at e0100000 {
compatible = "arasan,sdhci-8.9a";
- status = "disabled";
+ status = "okay";
clock-names = "clk_xin", "clk_ahb";
clocks = <&clkc 21>, <&clkc 32>;
interrupt-parent = <&intc>;
@@ -316,7 +316,7 @@
clkc: clkc at 100 {
#clock-cells = <1>;
compatible = "xlnx,ps7-clkc";
- fclk-enable = <0>;
+ fclk-enable = <0xf>;
clock-output-names = "armpll", "ddrpll", "iopll", "cpu_6or4x",
"cpu_3or2x", "cpu_2x", "cpu_1x", "ddr2x", "ddr3x",
"dci", "lqspi", "smc", "pcap", "gem0", "gem1",
diff --git a/arch/arm/boot/dts/xilinx/zynq-mxic-picozed.spi-nand.dts b/arch/arm/boot/dts/xilinx/zynq-mxic-picozed.spi-nand.dts
new file mode 100644
index 000000000000..a34223b70199
--- /dev/null
+++ b/arch/arm/boot/dts/xilinx/zynq-mxic-picozed.spi-nand.dts
@@ -0,0 +1,141 @@
+/dts-v1/;
+/include/ "zynq-7000.dtsi"
+
+/ {
+ model = "Zynq MXIC PicoZed Development Board";
+ compatible = "mxicy,zynq-mxic-picozed", "xlnx,zynq-7000";
+
+ aliases {
+ ethernet0 = &gem0;
+ serial0 = &uart1;
+ };
+
+ memory at 0 {
+ device_type = "memory";
+ reg = <0x0 0x30000000>;
+ };
+
+ chosen {
+ bootargs = "";
+ stdout-path = "serial0:115200n8";
+ };
+
+ clkwzd_in: clkwzd_in {
+ compatible = "fixed-clock";
+ #clock-cells = <0>;
+ clock-frequency = <133300000>;
+ };
+};
+
+&amba {
+ sdhci at e0100000 {
+ compatible = "arasan,sdhci-8.9a";
+ status = "okay";
+ clock-names = "clk_xin", "clk_ahb";
+ clocks = <0x1 0x15 0x1 0x20>;
+ interrupt-parent = <0x3>;
+ interrupts = <0x0 0x18 0x4>;
+ reg = <0xe0100000 0x1000>;
+ xlnx,has-cd = <0x1>;
+ xlnx,has-power = <0x0>;
+ xlnx,has-wp = <0x0>;
+ };
+
+ sdhci at e0101000 {
+ compatible = "arasan,sdhci-8.9a";
+ status = "okay";
+ clock-names = "clk_xin", "clk_ahb";
+ clocks = <0x1 0x16 0x1 0x21>;
+ interrupt-parent = <0x3>;
+ interrupts = <0x0 0x2f 0x4>;
+ reg = <0xe0101000 0x1000>;
+ xlnx,has-cd = <0x1>;
+ xlnx,has-power = <0x0>;
+ xlnx,has-wp = <0x0>;
+ };
+
+ clkwizard: clkwizard at 43c20000 {
+ compatible = "xlnx,clk-wizard-5.1";
+ reg = <0x43c20000 0x10000>;
+ clocks = <&clkc 0xf>, <&clkc 0xf>;
+ clock-names = "aclk", "clk_in1";
+ #clock-cells = <1>;
+ xlnx,clk-wizard-num-outputs = <2>;
+ phandle = <0x12>;
+ };
+
+/* v11 */
+/*
+ clkwizard: clkwizard at 43c20000 {
+ #clock-cells = <1>;
+ reg = <0x43c20000 0x1000>;
+ compatible = "xlnx,clocking-wizard";
+ xlnx,speed-grade = <1>;
+ xlnx,nr-outputs = <6>;
+ clock-names = "clk_in1", "s_axi_aclk";
+ clocks = <&clkc 18>, <&clkc 18>;
+ };
+*/
+
+ spi at 43c30000 {
+ compatible = "mxicy,mx25f0a-spi";
+ reg = <0x43c30000 0x10000>, <0xa0000000 0x4000000>;
+ reg-names = "regs", "dirmap";
+ clocks = <&clkwizard 0x0>, <&clkwizard 0x1>, <&clkc 0xf>;
+ clock-names = "send_clk", "send_dly_clk", "ps_clk";
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ flash at 0 {
+ compatible = "spi-nand";
+ reg = <0>;
+ #nand-use-soft-ecc-engine;
+ #nand-ecc-algo = "bch";
+ #nand-ecc-strength = <8>;
+ #nand-ecc-step-size = <512>;
+ spi-max-frequency = <25000000>;
+ spi-tx-bus-width = <4>;
+ spi-rx-bus-width = <4>;
+ #address-cells = <0x1>;
+ #size-cells = <0x1>;
+ };
+ };
+
+/*
+ nand: mxic-nfc at 43c30000 {
+ compatible = "mxic,multi-itfc-v009-nand-controller";
+ reg = <0x43c30000 0x10000>;
+ clocks = <&clkwizard 0>, <&clkwizard 1>, <&clkc 15>;
+ clock-names = "send", "send_dly", "ps";
+ interrupt-parent = <&intc>;
+ interrupts = <GIC_SPI 29 IRQ_TYPE_EDGE_RISING>;
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ nand at 0 {
+ reg = <0>;
+ label = "main-storage";
+
+ nand-use-soft-ecc-engine;
+ nand-ecc-algo = "bch";
+ nand-ecc-algo = "hamming";
+ nand-ecc-strength = <8>;
+ nand-ecc-step-size = <512>;
+ };
+
+ };
+*/
+};
+
+&clkc {
+ ps-clk-frequency = <33333333>;
+};
+
+&gem0 {
+ status = "okay";
+ phy-mode = "rgmii-id";
+};
+
+&uart1 {
+ status = "okay";
+};
diff --git a/arch/arm/boot/dts/xilinx/zynq-mxic-picozed.spi-nand_manual.dts b/arch/arm/boot/dts/xilinx/zynq-mxic-picozed.spi-nand_manual.dts
new file mode 100644
index 000000000000..7b68c03deb65
--- /dev/null
+++ b/arch/arm/boot/dts/xilinx/zynq-mxic-picozed.spi-nand_manual.dts
@@ -0,0 +1,141 @@
+/dts-v1/;
+/include/ "zynq-7000.dtsi"
+
+/ {
+ model = "Zynq MXIC PicoZed Development Board";
+ compatible = "mxicy,zynq-mxic-picozed", "xlnx,zynq-7000";
+
+ aliases {
+ ethernet0 = &gem0;
+ serial0 = &uart1;
+ };
+
+ memory at 0 {
+ device_type = "memory";
+ reg = <0x0 0x30000000>;
+ };
+
+ chosen {
+ bootargs = "";
+ stdout-path = "serial0:115200n8";
+ };
+
+ clkwzd_in: clkwzd_in {
+ compatible = "fixed-clock";
+ #clock-cells = <0>;
+ clock-frequency = <133300000>;
+ };
+};
+
+&amba {
+ sdhci at e0100000 {
+ compatible = "arasan,sdhci-8.9a";
+ status = "okay";
+ clock-names = "clk_xin", "clk_ahb";
+ clocks = <0x1 0x15 0x1 0x20>;
+ interrupt-parent = <0x3>;
+ interrupts = <0x0 0x18 0x4>;
+ reg = <0xe0100000 0x1000>;
+ xlnx,has-cd = <0x1>;
+ xlnx,has-power = <0x0>;
+ xlnx,has-wp = <0x0>;
+ };
+
+ sdhci at e0101000 {
+ compatible = "arasan,sdhci-8.9a";
+ status = "okay";
+ clock-names = "clk_xin", "clk_ahb";
+ clocks = <0x1 0x16 0x1 0x21>;
+ interrupt-parent = <0x3>;
+ interrupts = <0x0 0x2f 0x4>;
+ reg = <0xe0101000 0x1000>;
+ xlnx,has-cd = <0x1>;
+ xlnx,has-power = <0x0>;
+ xlnx,has-wp = <0x0>;
+ };
+
+ clkwizard: clkwizard at 43c20000 {
+ compatible = "xlnx,clk-wizard-5.1";
+ reg = <0x43c20000 0x10000>;
+ clocks = <&clkc 0xf>, <&clkc 0xf>;
+ clock-names = "aclk", "clk_in1";
+ #clock-cells = <1>;
+ xlnx,clk-wizard-num-outputs = <2>;
+ phandle = <0x12>;
+ };
+
+/* v11 */
+/*
+ clkwizard: clkwizard at 43c20000 {
+ #clock-cells = <1>;
+ reg = <0x43c20000 0x1000>;
+ compatible = "xlnx,clocking-wizard";
+ xlnx,speed-grade = <1>;
+ xlnx,nr-outputs = <6>;
+ clock-names = "clk_in1", "s_axi_aclk";
+ clocks = <&clkc 18>, <&clkc 18>;
+ };
+*/
+
+ spi at 43c30000 {
+ compatible = "mxicy,mx25f0a-spi";
+ reg = <0x43c30000 0x10000>;
+ reg-names = "regs";
+ clocks = <&clkwizard 0x0>, <&clkwizard 0x1>, <&clkc 0xf>;
+ clock-names = "send_clk", "send_dly_clk", "ps_clk";
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ flash at 0 {
+ compatible = "spi-nand";
+ reg = <0>;
+ #nand-use-soft-ecc-engine;
+ #nand-ecc-algo = "bch";
+ #nand-ecc-strength = <8>;
+ #nand-ecc-step-size = <512>;
+ spi-max-frequency = <25000000>;
+ spi-tx-bus-width = <1>;
+ spi-rx-bus-width = <1>;
+ #address-cells = <0x1>;
+ #size-cells = <0x1>;
+ };
+ };
+
+/*
+ nand: mxic-nfc at 43c30000 {
+ compatible = "mxic,multi-itfc-v009-nand-controller";
+ reg = <0x43c30000 0x10000>;
+ clocks = <&clkwizard 0>, <&clkwizard 1>, <&clkc 15>;
+ clock-names = "send", "send_dly", "ps";
+ interrupt-parent = <&intc>;
+ interrupts = <GIC_SPI 29 IRQ_TYPE_EDGE_RISING>;
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ nand at 0 {
+ reg = <0>;
+ label = "main-storage";
+
+ nand-use-soft-ecc-engine;
+ nand-ecc-algo = "bch";
+ nand-ecc-algo = "hamming";
+ nand-ecc-strength = <8>;
+ nand-ecc-step-size = <512>;
+ };
+
+ };
+*/
+};
+
+&clkc {
+ ps-clk-frequency = <33333333>;
+};
+
+&gem0 {
+ status = "okay";
+ phy-mode = "rgmii-id";
+};
+
+&uart1 {
+ status = "okay";
+};
diff --git a/arch/arm/boot/dts/xilinx/zynq-mxic-picozed.spi-nor.dts b/arch/arm/boot/dts/xilinx/zynq-mxic-picozed.spi-nor.dts
new file mode 100644
index 000000000000..ee700c43218f
--- /dev/null
+++ b/arch/arm/boot/dts/xilinx/zynq-mxic-picozed.spi-nor.dts
@@ -0,0 +1,142 @@
+/dts-v1/;
+/include/ "zynq-7000.dtsi"
+
+/ {
+ model = "Zynq MXIC PicoZed Development Board";
+ compatible = "mxicy,zynq-mxic-picozed", "xlnx,zynq-7000";
+
+ aliases {
+ ethernet0 = &gem0;
+ serial0 = &uart1;
+ };
+
+ memory at 0 {
+ device_type = "memory";
+ reg = <0x0 0x30000000>;
+ };
+
+ chosen {
+ bootargs = "";
+ stdout-path = "serial0:115200n8";
+ };
+
+ clkwzd_in: clkwzd_in {
+ compatible = "fixed-clock";
+ #clock-cells = <0>;
+ clock-frequency = <133300000>;
+ };
+};
+
+&amba {
+ sdhci at e0100000 {
+ compatible = "arasan,sdhci-8.9a";
+ status = "okay";
+ clock-names = "clk_xin", "clk_ahb";
+ clocks = <0x1 0x15 0x1 0x20>;
+ interrupt-parent = <0x3>;
+ interrupts = <0x0 0x18 0x4>;
+ reg = <0xe0100000 0x1000>;
+ xlnx,has-cd = <0x1>;
+ xlnx,has-power = <0x0>;
+ xlnx,has-wp = <0x0>;
+ };
+
+ sdhci at e0101000 {
+ compatible = "arasan,sdhci-8.9a";
+ status = "okay";
+ clock-names = "clk_xin", "clk_ahb";
+ clocks = <0x1 0x16 0x1 0x21>;
+ interrupt-parent = <0x3>;
+ interrupts = <0x0 0x2f 0x4>;
+ reg = <0xe0101000 0x1000>;
+ xlnx,has-cd = <0x1>;
+ xlnx,has-power = <0x0>;
+ xlnx,has-wp = <0x0>;
+ };
+
+ clkwizard: clkwizard at 43c20000 {
+ compatible = "xlnx,clk-wizard-5.1";
+ reg = <0x43c20000 0x10000>;
+ clocks = <&clkc 0xf>, <&clkc 0xf>;
+ clock-names = "aclk", "clk_in1";
+ #clock-cells = <1>;
+ xlnx,clk-wizard-num-outputs = <2>;
+ phandle = <0x12>;
+ };
+
+/* v11 */
+/*
+ clkwizard: clkwizard at 43c20000 {
+ #clock-cells = <1>;
+ reg = <0x43c20000 0x1000>;
+ compatible = "xlnx,clocking-wizard";
+ xlnx,speed-grade = <1>;
+ xlnx,nr-outputs = <6>;
+ clock-names = "clk_in1", "s_axi_aclk";
+ clocks = <&clkc 18>, <&clkc 18>;
+ };
+*/
+
+ spi at 43c30000 {
+ compatible = "mxicy,mx25f0a-spi";
+ reg = <0x43c30000 0x10000>, <0xa0000000 0x4000000>;
+ reg-names = "regs", "dirmap";
+ clocks = <&clkwizard 0x0>, <&clkwizard 0x1>, <&clkc 0xf>;
+ clock-names = "send_clk", "send_dly_clk", "ps_clk";
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ flash at 0 {
+ #compatible = "spi-nand";
+ compatible = "jedec,spi-nor";
+ reg = <0>;
+ #nand-use-soft-ecc-engine;
+ #nand-ecc-algo = "bch";
+ #nand-ecc-strength = <8>;
+ #nand-ecc-step-size = <512>;
+ spi-max-frequency = <25000000>;
+ spi-tx-bus-width = <8>;
+ spi-rx-bus-width = <8>;
+ #address-cells = <0x1>;
+ #size-cells = <0x1>;
+ };
+ };
+
+/*
+ nand: mxic-nfc at 43c30000 {
+ compatible = "mxic,multi-itfc-v009-nand-controller";
+ reg = <0x43c30000 0x10000>;
+ clocks = <&clkwizard 0>, <&clkwizard 1>, <&clkc 15>;
+ clock-names = "send", "send_dly", "ps";
+ interrupt-parent = <&intc>;
+ interrupts = <GIC_SPI 29 IRQ_TYPE_EDGE_RISING>;
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ nand at 0 {
+ reg = <0>;
+ label = "main-storage";
+
+ nand-use-soft-ecc-engine;
+ nand-ecc-algo = "bch";
+ nand-ecc-algo = "hamming";
+ nand-ecc-strength = <8>;
+ nand-ecc-step-size = <512>;
+ };
+
+ };
+*/
+};
+
+&clkc {
+ ps-clk-frequency = <33333333>;
+};
+
+&gem0 {
+ status = "okay";
+ phy-mode = "rgmii-id";
+};
+
+&uart1 {
+ status = "okay";
+};
diff --git a/drivers/clk/Kconfig b/drivers/clk/Kconfig
index c30d0d396f7a..f16464abacf5 100644
--- a/drivers/clk/Kconfig
+++ b/drivers/clk/Kconfig
@@ -510,6 +510,7 @@ source "drivers/clk/visconti/Kconfig"
source "drivers/clk/x86/Kconfig"
source "drivers/clk/xilinx/Kconfig"
source "drivers/clk/zynqmp/Kconfig"
+source "drivers/clk/zynq/Kconfig"
# Kunit test cases
config CLK_KUNIT_TEST
diff --git a/drivers/clk/zynq/Kconfig b/drivers/clk/zynq/Kconfig
new file mode 100644
index 000000000000..240ff17daa8f
--- /dev/null
+++ b/drivers/clk/zynq/Kconfig
@@ -0,0 +1,6 @@
+config CLK_ZYNQ_CLK_WIZARD
+ tristate "Xilinx clocking wizard driver"
+ depends on ARCH_ZYNQ || COMPILE_TEST
+ help
+ Enable the driver for Xilinx clocking wizard IP.
+
diff --git a/drivers/clk/zynq/Makefile b/drivers/clk/zynq/Makefile
index a5bb696de943..b1a1628048fb 100644
--- a/drivers/clk/zynq/Makefile
+++ b/drivers/clk/zynq/Makefile
@@ -2,3 +2,4 @@
# Zynq clock specific Makefile
obj-y += clkc.o pll.o
+obj-$(CONFIG_CLK_ZYNQ_CLK_WIZARD) += clk-wizard.o
diff --git a/drivers/clk/zynq/clk-wizard.c b/drivers/clk/zynq/clk-wizard.c
new file mode 100644
index 000000000000..3b217f8a8ffa
--- /dev/null
+++ b/drivers/clk/zynq/clk-wizard.c
@@ -0,0 +1,409 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Zynq Clocking Wizard driver
+ *
+ * Copyright (C) 2018 Macronix
+ */
+
+#include <linux/clk.h>
+#include <linux/clk-provider.h>
+#include <linux/io.h>
+#include <linux/iopoll.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/of_address.h>
+#include <linux/platform_device.h>
+#include <linux/slab.h>
+#include <linux/string.h>
+
+#define SRR 0x0
+
+#define SR 0x4
+#define SR_LOCKED BIT(0)
+
+#define CCR(x) (0x200 + ((x) * 4))
+
+#define FBOUT_CFG CCR(0)
+#define FBOUT_DIV(x) (x)
+#define FBOUT_GET_DIV(x) ((x) & GENMASK(7, 0))
+#define FBOUT_MUL(x) ((x) << 8)
+#define FBOUT_GET_MUL(x) (((x) & GENMASK(15, 8)) >> 8)
+#define FBOUT_FRAC(x) ((x) << 16)
+#define FBOUT_GET_FRAC(x) (((x) & GENMASK(25, 16)) >> 16)
+#define FBOUT_FRAC_EN BIT(26)
+
+#define FBOUT_PHASE CCR(1)
+
+#define OUT_CFG(x) CCR(2 + ((x) * 3))
+#define OUT_DIV(x) (x)
+#define OUT_GET_DIV(x) ((x) & GENMASK(7, 0))
+#define OUT_FRAC(x) ((x) << 8)
+#define OUT_GET_FRAC(x) (((x) & GENMASK(17, 8)) >> 8)
+#define OUT_FRAC_EN BIT(18)
+
+#define OUT_PHASE(x) CCR(3 + ((x) * 3))
+#define OUT_DUTY(x) CCR(4 + ((x) * 3))
+
+#define CTRL CCR(23)
+#define CTRL_SEN BIT(2)
+#define CTRL_SADDR BIT(1)
+#define CTRL_LOAD BIT(0)
+
+struct clkwzd;
+
+struct clkwzd_fbout {
+ struct clk_hw base;
+ struct clkwzd *wzd;
+};
+
+static inline struct clkwzd_fbout *to_clkwzd_fbout(struct clk_hw *hw)
+{
+ return container_of(hw, struct clkwzd_fbout, base);
+}
+
+struct clkwzd_out {
+ struct clk_hw base;
+ struct clkwzd *wzd;
+ unsigned int id;
+};
+
+static inline struct clkwzd_out *to_clkwzd_out(struct clk_hw *hw)
+{
+ return container_of(hw, struct clkwzd_out, base);
+}
+
+#define CLKWZD_MAX_OUTPUT 7
+
+struct clkwzd {
+ struct mutex lock;
+ struct clk *aclk;
+ struct clk *clk_in1;
+ void __iomem *regs;
+ struct clkwzd_out out[CLKWZD_MAX_OUTPUT];
+ struct clkwzd_fbout fbout;
+ struct clk_hw_onecell_data *onecell;
+};
+
+
+static int clkwzd_is_locked(struct clkwzd *wzd)
+{
+ bool prepared;
+
+ mutex_lock(&wzd->lock);
+ prepared = readl(wzd->regs + SR) & SR_LOCKED;
+ mutex_unlock(&wzd->lock);
+
+ return prepared;
+}
+
+static int clkwzd_apply_conf(struct clkwzd *wzd)
+{
+ int ret;
+ u32 val;
+
+ mutex_lock(&wzd->lock);
+ ret = readl_poll_timeout(wzd->regs + SR, val, val & SR_LOCKED, 1, 100);
+ if (!ret) {
+ writel(CTRL_SEN | CTRL_SADDR | CTRL_LOAD, wzd->regs + CTRL);
+ writel(CTRL_SADDR, wzd->regs + CTRL);
+ ret = readl_poll_timeout(wzd->regs + SR, val, val & SR_LOCKED,
+ 1, 100);
+ }
+ mutex_unlock(&wzd->lock);
+
+ return 0;
+}
+
+static int clkwzd_fbout_is_prepared(struct clk_hw *hw)
+{
+ struct clkwzd_fbout *fbout = to_clkwzd_fbout(hw);
+
+ return clkwzd_is_locked(fbout->wzd);
+}
+
+static int clkwzd_fbout_prepare(struct clk_hw *hw)
+{
+ struct clkwzd_fbout *fbout = to_clkwzd_fbout(hw);
+
+ return clkwzd_apply_conf(fbout->wzd);
+}
+
+static unsigned long clkwzd_fbout_recalc_rate(struct clk_hw *hw,
+ unsigned long parent_rate)
+{
+ struct clkwzd_fbout *fbout = to_clkwzd_fbout(hw);
+ unsigned long rate;
+ u32 cfg;
+
+ cfg = readl(fbout->wzd->regs + FBOUT_CFG);
+ if (cfg & FBOUT_FRAC_EN)
+ rate = DIV_ROUND_DOWN_ULL((u64)parent_rate *
+ ((FBOUT_GET_MUL(cfg) * 1000) +
+ FBOUT_GET_FRAC(cfg)),
+ 1000);
+ else
+ rate = parent_rate * FBOUT_GET_MUL(cfg);
+
+ rate /= FBOUT_GET_DIV(cfg);
+
+ return rate;
+}
+
+static int clkwzd_fbout_set_phase(struct clk_hw *hw, int degrees)
+{
+ struct clkwzd_fbout *fbout = to_clkwzd_fbout(hw);
+
+ writel(degrees * 1000, fbout->wzd->regs + FBOUT_PHASE);
+
+ return 0;
+}
+
+static int clkwzd_fbout_get_phase(struct clk_hw *hw)
+{
+ struct clkwzd_fbout *fbout = to_clkwzd_fbout(hw);
+
+ return readl(fbout->wzd->regs + FBOUT_PHASE) / 1000;
+}
+
+const struct clk_ops fbout_ops = {
+ .is_prepared = clkwzd_fbout_is_prepared,
+ .prepare = clkwzd_fbout_prepare,
+ .recalc_rate = clkwzd_fbout_recalc_rate,
+ .set_phase = clkwzd_fbout_set_phase,
+ .get_phase = clkwzd_fbout_get_phase,
+};
+
+static int clkwzd_out_is_prepared(struct clk_hw *hw)
+{
+ struct clkwzd_out *out = to_clkwzd_out(hw);
+
+ return clkwzd_is_locked(out->wzd);
+}
+
+static int clkwzd_out_prepare(struct clk_hw *hw)
+{
+ struct clkwzd_out *out = to_clkwzd_out(hw);
+
+ return clkwzd_apply_conf(out->wzd);
+}
+
+static unsigned long clkwzd_out_recalc_rate(struct clk_hw *hw,
+ unsigned long parent_rate)
+{
+ struct clkwzd_out *out = to_clkwzd_out(hw);
+ unsigned long rate;
+ u32 cfg;
+
+ cfg = readl(out->wzd->regs + OUT_CFG(out->id));
+ if (cfg & OUT_FRAC_EN)
+ rate = DIV_ROUND_DOWN_ULL((u64)parent_rate * 1000,
+ ((OUT_GET_DIV(cfg) * 1000) +
+ OUT_GET_FRAC(cfg)));
+ else
+ rate = parent_rate / OUT_GET_DIV(cfg);
+
+ return rate;
+}
+
+static int clkwzd_out_set_rate(struct clk_hw *hw,
+ unsigned long rate,
+ unsigned long parent_rate)
+{
+ struct clkwzd_out *out = to_clkwzd_out(hw);
+ u64 div;
+ u32 cfg;
+
+ div = DIV_ROUND_DOWN_ULL((u64)parent_rate * 1000, rate);
+ if (div < 1000 || div > 255999)
+ return -EINVAL;
+
+ cfg = OUT_DIV((u32)div / 1000);
+
+ if ((u32)div % 1000)
+ cfg |= OUT_FRAC_EN | OUT_FRAC((u32)div % 1000);
+
+ writel(cfg, out->wzd->regs + OUT_CFG(out->id));
+
+ /* Set duty cycle to 50%. */
+ writel(50000, out->wzd->regs + OUT_DUTY(out->id));
+
+ return 0;
+}
+
+static long clkwzd_out_round_rate(struct clk_hw *hw,
+ unsigned long rate,
+ unsigned long *parent_rate)
+{
+ u64 div;
+
+ div = DIV_ROUND_CLOSEST_ULL((u64)(*parent_rate) * 1000, rate);
+ if (div < 1000)
+ return *parent_rate;
+
+ if (div > 255999)
+ div = 255999;
+
+ return DIV_ROUND_DOWN_ULL((u64)(*parent_rate) * 1000, (u32)div);
+}
+
+static int clkwzd_out_set_phase(struct clk_hw *hw, int degrees)
+{
+ struct clkwzd_out *out = to_clkwzd_out(hw);
+
+ writel(degrees * 1000, out->wzd->regs + OUT_PHASE(out->id));
+
+ return 0;
+}
+
+static int clkwzd_out_get_phase(struct clk_hw *hw)
+{
+ struct clkwzd_out *out = to_clkwzd_out(hw);
+
+ return readl(out->wzd->regs + OUT_PHASE(out->id)) / 1000;
+}
+
+static const struct clk_ops out_ops = {
+ .is_prepared = clkwzd_out_is_prepared,
+ .prepare = clkwzd_out_prepare,
+ .recalc_rate = clkwzd_out_recalc_rate,
+ .round_rate = clkwzd_out_round_rate,
+ .set_rate = clkwzd_out_set_rate,
+ .set_phase = clkwzd_out_set_phase,
+ .get_phase = clkwzd_out_get_phase,
+};
+
+static int zynq_clkwzd_probe(struct platform_device *pdev)
+{
+ struct clk_init_data fboutinit = { };
+ const char *clk_in_name;
+ struct resource *res;
+ struct clkwzd *wzd;
+ u32 i, noutputs = 0;
+ int ret;
+
+ wzd = devm_kzalloc(&pdev->dev, sizeof(*wzd), GFP_KERNEL);
+ if (!wzd)
+ return -ENOMEM;
+
+ wzd->aclk = devm_clk_get(&pdev->dev, "aclk");
+ if (IS_ERR(wzd->aclk))
+ return PTR_ERR(wzd->aclk);
+
+ wzd->clk_in1 = devm_clk_get(&pdev->dev, "clk_in1");
+ if (IS_ERR(wzd->clk_in1))
+ return PTR_ERR(wzd->clk_in1);
+
+ of_property_read_u32(pdev->dev.of_node, "xlnx,clk-wizard-num-outputs",
+ &noutputs);
+ if (!noutputs || noutputs >= CLKWZD_MAX_OUTPUT)
+ return -EINVAL;
+
+ wzd->onecell = devm_kzalloc(&pdev->dev,
+ sizeof(*wzd->onecell) +
+ (sizeof(*wzd->onecell->hws) * noutputs),
+ GFP_KERNEL);
+ if (!wzd->onecell)
+ return -ENOMEM;
+
+ clk_in_name = __clk_get_name(wzd->clk_in1);
+ if (!clk_in_name)
+ return -EINVAL;
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ wzd->regs = devm_ioremap_resource(&pdev->dev, res);
+ if (IS_ERR(wzd->regs))
+ return PTR_ERR(wzd->regs);
+
+ mutex_init(&wzd->lock);
+
+ wzd->fbout.wzd = wzd;
+ fboutinit.ops = &fbout_ops;
+ fboutinit.flags = CLK_SET_RATE_GATE;
+ fboutinit.num_parents = 1;
+ fboutinit.parent_names = &clk_in_name;
+ fboutinit.flags = CLK_SET_RATE_GATE;
+
+ fboutinit.name = devm_kasprintf(&pdev->dev, GFP_KERNEL, "%s-fbout",
+ dev_name(&pdev->dev));
+ if (!fboutinit.name)
+ return -ENOMEM;
+
+ ret = clk_prepare_enable(wzd->aclk);
+ if (ret)
+ return ret;
+
+ wzd->fbout.base.init = &fboutinit;
+ ret = devm_clk_hw_register(&pdev->dev, &wzd->fbout.base);
+ if (ret)
+ goto err_disable_aclk;
+
+ for (i = 0; i < noutputs; i++) {
+ struct clk_init_data outinit = { };
+
+ wzd->out[i].id = i;
+ wzd->out[i].wzd = wzd;
+ outinit.ops = &out_ops;
+ outinit.num_parents = 1;
+ outinit.parent_names = &fboutinit.name;
+ outinit.flags = CLK_SET_RATE_GATE;
+ wzd->out[i].base.init = &outinit;
+ outinit.name = devm_kasprintf(&pdev->dev, GFP_KERNEL,
+ "%s-out%d",
+ dev_name(&pdev->dev), i);
+ if (!outinit.name) {
+ ret = -ENOMEM;
+ goto err_disable_aclk;
+ }
+
+ ret = devm_clk_hw_register(&pdev->dev, &wzd->out[i].base);
+ if (ret)
+ goto err_disable_aclk;
+
+ wzd->onecell->hws[i] = &wzd->out[i].base;
+ }
+
+ wzd->onecell->num = noutputs;
+ ret = devm_of_clk_add_hw_provider(&pdev->dev,
+ of_clk_hw_onecell_get,
+ wzd->onecell);
+ if (ret)
+ goto err_disable_aclk;
+
+ platform_set_drvdata(pdev, wzd);
+
+ return 0;
+
+err_disable_aclk:
+ clk_disable_unprepare(wzd->aclk);
+
+ return ret;
+}
+
+static int zynq_clkwzd_remove(struct platform_device *pdev)
+{
+ struct clkwzd *wzd = platform_get_drvdata(pdev);
+
+ clk_disable_unprepare(wzd->aclk);
+
+ return 0;
+}
+
+static const struct of_device_id zynq_clkwzd_of_ids[] = {
+ { .compatible = "xlnx,clk-wizard-5.1" },
+ { /* sentinel */ },
+};
+MODULE_DEVICE_TABLE(of, zynq_clkwzd_of_ids);
+
+static struct platform_driver zynq_clkwzd_driver = {
+ .probe = zynq_clkwzd_probe,
+ .remove = zynq_clkwzd_remove,
+ .driver = {
+ .name = "zynq-clk-wizard",
+ .of_match_table = zynq_clkwzd_of_ids,
+ },
+};
+module_platform_driver(zynq_clkwzd_driver);
+
+MODULE_AUTHOR("Boris Brezillon <boris.brezillon at bootlin.com>");
+MODULE_DESCRIPTION("Xilinx Clocking Wizard driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/spi/spi-mxic.c b/drivers/spi/spi-mxic.c
index 60c9f3048ac9..28c324d7200a 100644
--- a/drivers/spi/spi-mxic.c
+++ b/drivers/spi/spi-mxic.c
@@ -323,7 +323,7 @@ static u32 mxic_spi_mem_prep_op_cfg(const struct spi_mem_op *op,
(op->addr.dtr ? OP_ADDR_DDR : 0);
if (op->dummy.nbytes)
- cfg |= OP_DUMMY_CYC(op->dummy.nbytes);
+ cfg |= OP_DUMMY_CYC((op->dummy.nbytes) * (op->data.buswidth));
/* Direct mapping data.nbytes field is not populated */
if (data_len) {
@@ -390,7 +390,7 @@ static int mxic_spi_data_xfer(struct mxic_spi *mxic, const void *txbuf,
static ssize_t mxic_spi_mem_dirmap_read(struct spi_mem_dirmap_desc *desc,
u64 offs, size_t len, void *buf)
{
- struct mxic_spi *mxic = spi_controller_get_devdata(desc->mem->spi->controller);
+ struct mxic_spi *mxic = spi_master_get_devdata(desc->mem->spi->master);
int ret;
u32 sts;
@@ -434,7 +434,7 @@ static ssize_t mxic_spi_mem_dirmap_write(struct spi_mem_dirmap_desc *desc,
u64 offs, size_t len,
const void *buf)
{
- struct mxic_spi *mxic = spi_controller_get_devdata(desc->mem->spi->controller);
+ struct mxic_spi *mxic = spi_master_get_devdata(desc->mem->spi->master);
u32 sts;
int ret;
@@ -481,9 +481,9 @@ static bool mxic_spi_mem_supports_op(struct spi_mem *mem,
op->dummy.buswidth > 8 || op->cmd.buswidth > 8)
return false;
- if (op->data.nbytes && op->dummy.nbytes &&
- op->data.buswidth != op->dummy.buswidth)
- return false;
+ //if (op->data.nbytes && op->dummy.nbytes &&
+ // op->data.buswidth != op->dummy.buswidth)
+ // return false;
if (op->addr.nbytes > 7)
return false;
@@ -493,7 +493,7 @@ static bool mxic_spi_mem_supports_op(struct spi_mem *mem,
static int mxic_spi_mem_dirmap_create(struct spi_mem_dirmap_desc *desc)
{
- struct mxic_spi *mxic = spi_controller_get_devdata(desc->mem->spi->controller);
+ struct mxic_spi *mxic = spi_master_get_devdata(desc->mem->spi->master);
if (!mxic->linear.map)
return -EINVAL;
@@ -510,7 +510,7 @@ static int mxic_spi_mem_dirmap_create(struct spi_mem_dirmap_desc *desc)
static int mxic_spi_mem_exec_op(struct spi_mem *mem,
const struct spi_mem_op *op)
{
- struct mxic_spi *mxic = spi_controller_get_devdata(mem->spi->controller);
+ struct mxic_spi *mxic = spi_master_get_devdata(mem->spi->master);
int i, ret;
u8 addr[8], cmd[2];
@@ -543,7 +543,7 @@ static int mxic_spi_mem_exec_op(struct spi_mem *mem,
if (ret)
goto out;
- ret = mxic_spi_data_xfer(mxic, NULL, NULL, op->dummy.nbytes);
+ ret = mxic_spi_data_xfer(mxic, NULL, NULL, (op->dummy.nbytes) * (op->data.buswidth));
if (ret)
goto out;
@@ -565,9 +565,9 @@ static int mxic_spi_mem_exec_op(struct spi_mem *mem,
static const struct spi_controller_mem_ops mxic_spi_mem_ops = {
.supports_op = mxic_spi_mem_supports_op,
.exec_op = mxic_spi_mem_exec_op,
- .dirmap_create = mxic_spi_mem_dirmap_create,
- .dirmap_read = mxic_spi_mem_dirmap_read,
- .dirmap_write = mxic_spi_mem_dirmap_write,
+ //.dirmap_create = mxic_spi_mem_dirmap_create,
+ //.dirmap_read = mxic_spi_mem_dirmap_read,
+ //.dirmap_write = mxic_spi_mem_dirmap_write,
};
static const struct spi_controller_mem_caps mxic_spi_mem_caps = {
@@ -577,7 +577,7 @@ static const struct spi_controller_mem_caps mxic_spi_mem_caps = {
static void mxic_spi_set_cs(struct spi_device *spi, bool lvl)
{
- struct mxic_spi *mxic = spi_controller_get_devdata(spi->controller);
+ struct mxic_spi *mxic = spi_master_get_devdata(spi->master);
if (!lvl) {
writel(readl(mxic->regs + HC_CFG) | HC_CFG_MAN_CS_EN,
@@ -592,11 +592,11 @@ static void mxic_spi_set_cs(struct spi_device *spi, bool lvl)
}
}
-static int mxic_spi_transfer_one(struct spi_controller *host,
+static int mxic_spi_transfer_one(struct spi_master *master,
struct spi_device *spi,
struct spi_transfer *t)
{
- struct mxic_spi *mxic = spi_controller_get_devdata(host);
+ struct mxic_spi *mxic = spi_master_get_devdata(master);
unsigned int busw = OP_BUSW_1;
int ret;
@@ -632,7 +632,7 @@ static int mxic_spi_transfer_one(struct spi_controller *host,
if (ret)
return ret;
- spi_finalize_current_transfer(host);
+ spi_finalize_current_transfer(master);
return 0;
}
@@ -713,8 +713,8 @@ static int mxic_spi_mem_ecc_probe(struct platform_device *pdev,
static int __maybe_unused mxic_spi_runtime_suspend(struct device *dev)
{
- struct spi_controller *host = dev_get_drvdata(dev);
- struct mxic_spi *mxic = spi_controller_get_devdata(host);
+ struct spi_master *master = dev_get_drvdata(dev);
+ struct mxic_spi *mxic = spi_master_get_devdata(master);
mxic_spi_clk_disable(mxic);
clk_disable_unprepare(mxic->ps_clk);
@@ -724,8 +724,8 @@ static int __maybe_unused mxic_spi_runtime_suspend(struct device *dev)
static int __maybe_unused mxic_spi_runtime_resume(struct device *dev)
{
- struct spi_controller *host = dev_get_drvdata(dev);
- struct mxic_spi *mxic = spi_controller_get_devdata(host);
+ struct spi_master *master = dev_get_drvdata(dev);
+ struct mxic_spi *mxic = spi_master_get_devdata(master);
int ret;
ret = clk_prepare_enable(mxic->ps_clk);
@@ -744,21 +744,21 @@ static const struct dev_pm_ops mxic_spi_dev_pm_ops = {
static int mxic_spi_probe(struct platform_device *pdev)
{
- struct spi_controller *host;
+ struct spi_master *master;
struct resource *res;
struct mxic_spi *mxic;
int ret;
- host = devm_spi_alloc_host(&pdev->dev, sizeof(struct mxic_spi));
- if (!host)
+ master = devm_spi_alloc_master(&pdev->dev, sizeof(struct mxic_spi));
+ if (!master)
return -ENOMEM;
- platform_set_drvdata(pdev, host);
+ platform_set_drvdata(pdev, master);
- mxic = spi_controller_get_devdata(host);
+ mxic = spi_master_get_devdata(master);
mxic->dev = &pdev->dev;
- host->dev.of_node = pdev->dev.of_node;
+ master->dev.of_node = pdev->dev.of_node;
mxic->ps_clk = devm_clk_get(&pdev->dev, "ps_clk");
if (IS_ERR(mxic->ps_clk))
@@ -786,19 +786,19 @@ static int mxic_spi_probe(struct platform_device *pdev)
}
pm_runtime_enable(&pdev->dev);
- host->auto_runtime_pm = true;
+ master->auto_runtime_pm = true;
- host->num_chipselect = 1;
- host->mem_ops = &mxic_spi_mem_ops;
- host->mem_caps = &mxic_spi_mem_caps;
+ master->num_chipselect = 1;
+ master->mem_ops = &mxic_spi_mem_ops;
+ master->mem_caps = &mxic_spi_mem_caps;
- host->set_cs = mxic_spi_set_cs;
- host->transfer_one = mxic_spi_transfer_one;
- host->bits_per_word_mask = SPI_BPW_MASK(8);
- host->mode_bits = SPI_CPOL | SPI_CPHA |
- SPI_RX_DUAL | SPI_TX_DUAL |
- SPI_RX_QUAD | SPI_TX_QUAD |
- SPI_RX_OCTAL | SPI_TX_OCTAL;
+ master->set_cs = mxic_spi_set_cs;
+ master->transfer_one = mxic_spi_transfer_one;
+ master->bits_per_word_mask = SPI_BPW_MASK(8);
+ master->mode_bits = SPI_CPOL | SPI_CPHA |
+ SPI_RX_DUAL | SPI_TX_DUAL |
+ SPI_RX_QUAD | SPI_TX_QUAD |
+ SPI_RX_OCTAL | SPI_TX_OCTAL;
mxic_spi_hw_init(mxic);
@@ -808,9 +808,9 @@ static int mxic_spi_probe(struct platform_device *pdev)
return ret;
}
- ret = spi_register_controller(host);
+ ret = spi_register_master(master);
if (ret) {
- dev_err(&pdev->dev, "spi_register_controller failed\n");
+ dev_err(&pdev->dev, "spi_register_master failed\n");
pm_runtime_disable(&pdev->dev);
mxic_spi_mem_ecc_remove(mxic);
}
@@ -820,12 +820,12 @@ static int mxic_spi_probe(struct platform_device *pdev)
static void mxic_spi_remove(struct platform_device *pdev)
{
- struct spi_controller *host = platform_get_drvdata(pdev);
- struct mxic_spi *mxic = spi_controller_get_devdata(host);
+ struct spi_master *master = platform_get_drvdata(pdev);
+ struct mxic_spi *mxic = spi_master_get_devdata(master);
pm_runtime_disable(&pdev->dev);
mxic_spi_mem_ecc_remove(mxic);
- spi_unregister_controller(host);
+ spi_unregister_master(master);
}
static const struct of_device_id mxic_spi_of_ids[] = {
--
2.17.1
More information about the linux-mtd
mailing list