summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorSascha Hauer <s.hauer@pengutronix.de>2017-01-11 19:05:11 +0100
committerSascha Hauer <s.hauer@pengutronix.de>2017-01-12 07:13:47 +0100
commitdcedcec3751d3307e42b2a6583186b2a39f2076d (patch)
tree3defe034003c9025c1caf6ce71ac5568e2abf832
parent08c62ae2fa9378732588ef7b9a9120b377d26d1e (diff)
parent1b2cc689fc2db0db56c617e789906a684b22097a (diff)
downloadbarebox-dcedcec3751d3307e42b2a6583186b2a39f2076d.tar.gz
barebox-dcedcec3751d3307e42b2a6583186b2a39f2076d.tar.xz
Merge branch 'for-next/vybrid'
-rw-r--r--arch/arm/dts/vf610-twr.dts4
-rw-r--r--arch/arm/mach-imx/Kconfig2
-rw-r--r--arch/arm/mach-imx/Makefile23
-rw-r--r--arch/arm/mach-imx/ocotp.c51
-rw-r--r--drivers/clk/Makefile3
-rw-r--r--drivers/clk/clk-conf.c148
-rw-r--r--drivers/clk/clk.c2
-rw-r--r--drivers/clk/imx/Makefile22
-rw-r--r--drivers/clk/imx/clk-gate-exclusive.c (renamed from arch/arm/mach-imx/clk-gate-exclusive.c)0
-rw-r--r--drivers/clk/imx/clk-gate2.c (renamed from arch/arm/mach-imx/clk-gate2.c)12
-rw-r--r--drivers/clk/imx/clk-imx1.c (renamed from arch/arm/mach-imx/clk-imx1.c)0
-rw-r--r--drivers/clk/imx/clk-imx21.c (renamed from arch/arm/mach-imx/clk-imx21.c)0
-rw-r--r--drivers/clk/imx/clk-imx25.c (renamed from arch/arm/mach-imx/clk-imx25.c)0
-rw-r--r--drivers/clk/imx/clk-imx27.c (renamed from arch/arm/mach-imx/clk-imx27.c)0
-rw-r--r--drivers/clk/imx/clk-imx31.c (renamed from arch/arm/mach-imx/clk-imx31.c)0
-rw-r--r--drivers/clk/imx/clk-imx35.c (renamed from arch/arm/mach-imx/clk-imx35.c)0
-rw-r--r--drivers/clk/imx/clk-imx5.c (renamed from arch/arm/mach-imx/clk-imx5.c)0
-rw-r--r--drivers/clk/imx/clk-imx6.c (renamed from arch/arm/mach-imx/clk-imx6.c)0
-rw-r--r--drivers/clk/imx/clk-imx6sx.c (renamed from arch/arm/mach-imx/clk-imx6sx.c)0
-rw-r--r--drivers/clk/imx/clk-imx6ul.c (renamed from arch/arm/mach-imx/clk-imx6ul.c)0
-rw-r--r--drivers/clk/imx/clk-pfd.c (renamed from arch/arm/mach-imx/clk-pfd.c)0
-rw-r--r--drivers/clk/imx/clk-pllv1.c (renamed from arch/arm/mach-imx/clk-pllv1.c)0
-rw-r--r--drivers/clk/imx/clk-pllv2.c (renamed from arch/arm/mach-imx/clk-pllv2.c)0
-rw-r--r--drivers/clk/imx/clk-pllv3.c (renamed from arch/arm/mach-imx/clk-pllv3.c)9
-rw-r--r--drivers/clk/imx/clk-vf610.c446
-rw-r--r--drivers/clk/imx/clk.c21
-rw-r--r--drivers/clk/imx/clk.h (renamed from arch/arm/mach-imx/clk.h)23
-rw-r--r--drivers/gpio/Kconfig3
-rw-r--r--drivers/gpio/Makefile1
-rw-r--r--drivers/gpio/gpio-vf610.c166
-rw-r--r--drivers/i2c/busses/i2c-imx.c222
-rw-r--r--drivers/mci/imx-esdhc.c129
-rw-r--r--drivers/net/fec_imx.c74
-rw-r--r--drivers/net/fec_imx.h10
-rw-r--r--drivers/serial/Kconfig5
-rw-r--r--drivers/serial/Makefile1
-rw-r--r--drivers/serial/serial_lpuart.c217
-rw-r--r--include/linux/clk/clk-conf.h17
38 files changed, 1485 insertions, 126 deletions
diff --git a/arch/arm/dts/vf610-twr.dts b/arch/arm/dts/vf610-twr.dts
index 54b4435a54..5947fdbdaa 100644
--- a/arch/arm/dts/vf610-twr.dts
+++ b/arch/arm/dts/vf610-twr.dts
@@ -12,3 +12,7 @@
&usbdev0 {
status = "disabled";
};
+
+&enet_ext {
+ clock-output-names = "enet_ext";
+};
diff --git a/arch/arm/mach-imx/Kconfig b/arch/arm/mach-imx/Kconfig
index ed5f9d9655..9dbe31c4b6 100644
--- a/arch/arm/mach-imx/Kconfig
+++ b/arch/arm/mach-imx/Kconfig
@@ -668,7 +668,7 @@ config IMX_IIM_FUSE_BLOW
config IMX_OCOTP
tristate "i.MX6 On Chip OTP controller"
- depends on ARCH_IMX6
+ depends on ARCH_IMX6 || ARCH_VF610
depends on OFDEVICE
help
This adds support for the i.MX6 On-Chip OTP controller. Currently the
diff --git a/arch/arm/mach-imx/Makefile b/arch/arm/mach-imx/Makefile
index ee839f7443..d0fe7abc00 100644
--- a/arch/arm/mach-imx/Makefile
+++ b/arch/arm/mach-imx/Makefile
@@ -1,26 +1,23 @@
obj-y += clocksource.o
-obj-$(CONFIG_ARCH_IMX1) += imx1.o clk-imx1.o
-obj-$(CONFIG_ARCH_IMX25) += imx25.o clk-imx25.o
-obj-$(CONFIG_ARCH_IMX21) += imx21.o clk-imx21.o
-obj-$(CONFIG_ARCH_IMX27) += imx27.o clk-imx27.o
-obj-$(CONFIG_ARCH_IMX31) += imx31.o clk-imx31.o
-obj-$(CONFIG_ARCH_IMX35) += imx35.o clk-imx35.o
-obj-$(CONFIG_ARCH_IMX50) += imx50.o imx5.o clk-imx5.o
+obj-$(CONFIG_ARCH_IMX1) += imx1.o
+obj-$(CONFIG_ARCH_IMX25) += imx25.o
+obj-$(CONFIG_ARCH_IMX21) += imx21.o
+obj-$(CONFIG_ARCH_IMX27) += imx27.o
+obj-$(CONFIG_ARCH_IMX31) += imx31.o
+obj-$(CONFIG_ARCH_IMX35) += imx35.o
+obj-$(CONFIG_ARCH_IMX50) += imx50.o imx5.o
pbl-$(CONFIG_ARCH_IMX50) += imx50.o imx5.o
-obj-$(CONFIG_ARCH_IMX51) += imx51.o imx5.o clk-imx5.o
+obj-$(CONFIG_ARCH_IMX51) += imx51.o imx5.o
pbl-$(CONFIG_ARCH_IMX51) += imx51.o imx5.o
-obj-$(CONFIG_ARCH_IMX53) += imx53.o imx5.o clk-imx5.o esdctl-v4.o
+obj-$(CONFIG_ARCH_IMX53) += imx53.o imx5.o esdctl-v4.o
pbl-$(CONFIG_ARCH_IMX53) += imx53.o imx5.o esdctl-v4.o
-obj-$(CONFIG_ARCH_IMX6) += imx6.o usb-imx6.o clk-imx6.o
+obj-$(CONFIG_ARCH_IMX6) += imx6.o usb-imx6.o
lwl-$(CONFIG_ARCH_IMX6) += imx6-mmdc.o
-obj-$(CONFIG_ARCH_IMX6SX) += clk-imx6sx.o
-obj-$(CONFIG_ARCH_IMX6UL) += clk-imx6ul.o
obj-$(CONFIG_ARCH_IMX_XLOAD) += xload.o
obj-$(CONFIG_IMX_IIM) += iim.o
obj-$(CONFIG_IMX_OCOTP) += ocotp.o
obj-$(CONFIG_NAND_IMX) += nand.o
lwl-$(CONFIG_ARCH_IMX_EXTERNAL_BOOT_NAND) += external-nand-boot.o
-obj-$(CONFIG_COMMON_CLK) += clk-pllv1.o clk-pllv2.o clk-pllv3.o clk-pfd.o clk-gate2.o clk-gate-exclusive.o
obj-y += devices.o imx.o
obj-pbl-y += esdctl.o boot.o
obj-$(CONFIG_BAREBOX_UPDATE) += imx-bbu-internal.o
diff --git a/arch/arm/mach-imx/ocotp.c b/arch/arm/mach-imx/ocotp.c
index e1d0c256a5..68ff0ce28b 100644
--- a/arch/arm/mach-imx/ocotp.c
+++ b/arch/arm/mach-imx/ocotp.c
@@ -67,7 +67,6 @@
#define BF(value, field) (((value) << field) & field##_MASK)
/* Other definitions */
-#define FUSE_REGS_COUNT (16 * 8)
#define IMX6_OTP_DATA_ERROR_VAL 0xBADABADA
#define DEF_RELAX 20
#define MAC_OFFSET (0x22 * 4)
@@ -75,6 +74,7 @@
struct imx_ocotp_data {
int num_regs;
+ u32 (*addr_to_offset)(u32 addr);
};
struct ocotp_priv {
@@ -86,6 +86,7 @@ struct ocotp_priv {
int sense_enable;
char ethaddr[6];
struct regmap_config map_config;
+ const struct imx_ocotp_data *data;
};
static struct ocotp_priv *imx_ocotp;
@@ -196,7 +197,8 @@ static int imx_ocotp_reg_read(void *ctx, unsigned int reg, unsigned int *val)
if (ret)
return ret;
} else {
- *(u32 *)val = readl(priv->base + 0x400 + index * 0x10);
+ *(u32 *)val = readl(priv->base +
+ priv->data->addr_to_offset(index));
}
return 0;
@@ -276,7 +278,8 @@ static int imx_ocotp_reg_write(void *ctx, unsigned int reg, unsigned int val)
if (ret < 0)
return ret;
} else {
- writel(val, priv->base + 0x400 + index * 0x10);
+ writel(val, priv->base +
+ priv->data->addr_to_offset(index));
}
if (priv->permanent_write_enable)
@@ -438,7 +441,7 @@ static int imx_ocotp_probe(struct device_d *dev)
void __iomem *base;
struct ocotp_priv *priv;
int ret = 0;
- struct imx_ocotp_data *data;
+ const struct imx_ocotp_data *data;
ret = dev_get_drvdata(dev, (const void **)&data);
if (ret)
@@ -453,6 +456,7 @@ static int imx_ocotp_probe(struct device_d *dev)
priv = xzalloc(sizeof(*priv));
+ priv->data = data;
priv->base = base;
priv->clk = clk_get(dev, NULL);
if (IS_ERR(priv->clk))
@@ -491,12 +495,48 @@ static int imx_ocotp_probe(struct device_d *dev)
return 0;
}
+static u32 imx6sl_addr_to_offset(u32 addr)
+{
+ return 0x400 + addr * 0x10;
+}
+
+static u32 imx6q_addr_to_offset(u32 addr)
+{
+ u32 addendum = 0;
+
+ if (addr > 0x2F) {
+ /*
+ * If we are reading past Bank 5, take into account a
+ * 0x100 bytes wide gap between Bank 5 and Bank 6
+ */
+ addendum += 0x100;
+ }
+
+
+ return imx6sl_addr_to_offset(addr) + addendum;
+}
+
+static u32 vf610_addr_to_offset(u32 addr)
+{
+ if (addr == 0x04)
+ return 0x450;
+ else
+ return imx6q_addr_to_offset(addr);
+}
+
static struct imx_ocotp_data imx6q_ocotp_data = {
.num_regs = 512,
+ .addr_to_offset = imx6q_addr_to_offset,
};
static struct imx_ocotp_data imx6sl_ocotp_data = {
.num_regs = 256,
+ .addr_to_offset = imx6sl_addr_to_offset,
+};
+
+static struct imx_ocotp_data vf610_ocotp_data = {
+ .num_regs = 512,
+ .addr_to_offset = vf610_addr_to_offset,
};
static __maybe_unused struct of_device_id imx_ocotp_dt_ids[] = {
@@ -513,6 +553,9 @@ static __maybe_unused struct of_device_id imx_ocotp_dt_ids[] = {
.compatible = "fsl,imx6ul-ocotp",
.data = &imx6q_ocotp_data,
}, {
+ .compatible = "fsl,vf610-ocotp",
+ .data = &vf610_ocotp_data,
+ }, {
/* sentinel */
}
};
diff --git a/drivers/clk/Makefile b/drivers/clk/Makefile
index 47ed7b1b6e..a4e4ed0241 100644
--- a/drivers/clk/Makefile
+++ b/drivers/clk/Makefile
@@ -1,6 +1,6 @@
obj-$(CONFIG_COMMON_CLK) += clk.o clk-fixed.o clk-divider.o clk-fixed-factor.o \
clk-mux.o clk-gate.o clk-composite.o \
- clk-fractional-divider.o
+ clk-fractional-divider.o clk-conf.o
obj-$(CONFIG_CLKDEV_LOOKUP) += clkdev.o
obj-$(CONFIG_ARCH_MVEBU) += mvebu/
@@ -9,3 +9,4 @@ obj-$(CONFIG_ARCH_ROCKCHIP) += rockchip/
obj-$(CONFIG_ARCH_TEGRA) += tegra/
obj-$(CONFIG_CLK_SOCFPGA) += socfpga.o
obj-$(CONFIG_MACH_MIPS_ATH79) += clk-ar933x.o
+obj-$(CONFIG_ARCH_IMX) += imx/
diff --git a/drivers/clk/clk-conf.c b/drivers/clk/clk-conf.c
new file mode 100644
index 0000000000..93271b4f99
--- /dev/null
+++ b/drivers/clk/clk-conf.c
@@ -0,0 +1,148 @@
+/*
+ * Copyright (C) 2014 Samsung Electronics Co., Ltd.
+ * Sylwester Nawrocki <s.nawrocki@samsung.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <common.h>
+#include <io.h>
+#include <malloc.h>
+#include <linux/clk.h>
+#include <linux/err.h>
+#include <linux/clk/clk-conf.h>
+
+#if defined(CONFIG_OFTREE) && defined(CONFIG_COMMON_CLK_OF_PROVIDER)
+
+static int __set_clk_parents(struct device_node *node, bool clk_supplier)
+{
+ struct of_phandle_args clkspec;
+ int index, rc, num_parents;
+ struct clk *clk, *pclk;
+
+ num_parents = of_count_phandle_with_args(node, "assigned-clock-parents",
+ "#clock-cells");
+ if (num_parents == -EINVAL)
+ pr_err("clk: invalid value of clock-parents property at %s\n",
+ node->full_name);
+
+ for (index = 0; index < num_parents; index++) {
+ rc = of_parse_phandle_with_args(node, "assigned-clock-parents",
+ "#clock-cells", index, &clkspec);
+ if (rc < 0) {
+ /* skip empty (null) phandles */
+ if (rc == -ENOENT)
+ continue;
+ else
+ return rc;
+ }
+ if (clkspec.np == node && !clk_supplier)
+ return 0;
+ pclk = of_clk_get_from_provider(&clkspec);
+ if (IS_ERR(pclk)) {
+ pr_warn("clk: couldn't get parent clock %d for %s\n",
+ index, node->full_name);
+ return PTR_ERR(pclk);
+ }
+
+ rc = of_parse_phandle_with_args(node, "assigned-clocks",
+ "#clock-cells", index, &clkspec);
+ if (rc < 0)
+ goto err;
+ if (clkspec.np == node && !clk_supplier) {
+ rc = 0;
+ goto err;
+ }
+ clk = of_clk_get_from_provider(&clkspec);
+ if (IS_ERR(clk)) {
+ pr_warn("clk: couldn't get parent clock %d for %s\n",
+ index, node->full_name);
+ rc = PTR_ERR(clk);
+ goto err;
+ }
+
+ rc = clk_set_parent(clk, pclk);
+ if (rc < 0)
+ pr_err("clk: failed to reparent %s to %s: %d\n",
+ __clk_get_name(clk), __clk_get_name(pclk), rc);
+ clk_put(clk);
+ clk_put(pclk);
+ }
+ return 0;
+err:
+ clk_put(pclk);
+ return rc;
+}
+
+static int __set_clk_rates(struct device_node *node, bool clk_supplier)
+{
+ struct of_phandle_args clkspec;
+ struct property *prop;
+ const __be32 *cur;
+ int rc, index = 0;
+ struct clk *clk;
+ u32 rate;
+
+ of_property_for_each_u32(node, "assigned-clock-rates", prop, cur, rate) {
+ if (rate) {
+ rc = of_parse_phandle_with_args(node, "assigned-clocks",
+ "#clock-cells", index, &clkspec);
+ if (rc < 0) {
+ /* skip empty (null) phandles */
+ if (rc == -ENOENT)
+ continue;
+ else
+ return rc;
+ }
+ if (clkspec.np == node && !clk_supplier)
+ return 0;
+
+ clk = of_clk_get_from_provider(&clkspec);
+ if (IS_ERR(clk)) {
+ pr_warn("clk: couldn't get clock %d for %s\n",
+ index, node->full_name);
+ return PTR_ERR(clk);
+ }
+
+ rc = clk_set_rate(clk, rate);
+ if (rc < 0)
+ pr_err("clk: couldn't set %s clk rate to %d (%d), current rate: %ld\n",
+ __clk_get_name(clk), rate, rc,
+ clk_get_rate(clk));
+ clk_put(clk);
+ }
+ index++;
+ }
+ return 0;
+}
+
+/**
+ * of_clk_set_defaults() - parse and set assigned clocks configuration
+ * @node: device node to apply clock settings for
+ * @clk_supplier: true if clocks supplied by @node should also be considered
+ *
+ * This function parses 'assigned-{clocks/clock-parents/clock-rates}' properties
+ * and sets any specified clock parents and rates. The @clk_supplier argument
+ * should be set to true if @node may be also a clock supplier of any clock
+ * listed in its 'assigned-clocks' or 'assigned-clock-parents' properties.
+ * If @clk_supplier is false the function exits returning 0 as soon as it
+ * determines the @node is also a supplier of any of the clocks.
+ */
+int of_clk_set_defaults(struct device_node *node, bool clk_supplier)
+{
+ int rc;
+
+ if (!node)
+ return 0;
+
+ rc = __set_clk_parents(node, clk_supplier);
+ if (rc < 0)
+ return rc;
+
+ return __set_clk_rates(node, clk_supplier);
+}
+EXPORT_SYMBOL_GPL(of_clk_set_defaults);
+
+#endif
diff --git a/drivers/clk/clk.c b/drivers/clk/clk.c
index 19377b893c..1566beabda 100644
--- a/drivers/clk/clk.c
+++ b/drivers/clk/clk.c
@@ -21,6 +21,7 @@
#include <complete.h>
#include <linux/clk.h>
#include <linux/err.h>
+#include <linux/clk/clk-conf.h>
static LIST_HEAD(clks);
@@ -527,6 +528,7 @@ int of_clk_init(struct device_node *root, const struct of_device_id *matches)
if (force || parent_ready(clk_provider->np)) {
clk_provider->clk_init_cb(clk_provider->np);
+ of_clk_set_defaults(clk_provider->np, true);
list_del(&clk_provider->node);
free(clk_provider);
diff --git a/drivers/clk/imx/Makefile b/drivers/clk/imx/Makefile
new file mode 100644
index 0000000000..65d7859ed3
--- /dev/null
+++ b/drivers/clk/imx/Makefile
@@ -0,0 +1,22 @@
+obj-$(CONFIG_COMMON_CLK) += \
+ clk-pllv1.o \
+ clk-pllv2.o \
+ clk-pllv3.o \
+ clk-pfd.o \
+ clk-gate2.o \
+ clk-gate-exclusive.o \
+ clk.o
+
+obj-$(CONFIG_ARCH_IMX1) += clk-imx1.o
+obj-$(CONFIG_ARCH_IMX25) += clk-imx25.o
+obj-$(CONFIG_ARCH_IMX21) += clk-imx21.o
+obj-$(CONFIG_ARCH_IMX27) += clk-imx27.o
+obj-$(CONFIG_ARCH_IMX31) += clk-imx31.o
+obj-$(CONFIG_ARCH_IMX35) += clk-imx35.o
+obj-$(CONFIG_ARCH_IMX50) += clk-imx5.o
+obj-$(CONFIG_ARCH_IMX51) += clk-imx5.o
+obj-$(CONFIG_ARCH_IMX53) += clk-imx5.o
+obj-$(CONFIG_ARCH_IMX6) += clk-imx6.o
+obj-$(CONFIG_ARCH_IMX6SX) += clk-imx6sx.o
+obj-$(CONFIG_ARCH_IMX6UL) += clk-imx6ul.o
+obj-$(CONFIG_ARCH_VF610) += clk-vf610.o
diff --git a/arch/arm/mach-imx/clk-gate-exclusive.c b/drivers/clk/imx/clk-gate-exclusive.c
index db88db0237..db88db0237 100644
--- a/arch/arm/mach-imx/clk-gate-exclusive.c
+++ b/drivers/clk/imx/clk-gate-exclusive.c
diff --git a/arch/arm/mach-imx/clk-gate2.c b/drivers/clk/imx/clk-gate2.c
index faed6313fb..f952f3e3f6 100644
--- a/arch/arm/mach-imx/clk-gate2.c
+++ b/drivers/clk/imx/clk-gate2.c
@@ -26,6 +26,7 @@ struct clk_gate2 {
struct clk clk;
void __iomem *reg;
int shift;
+ u8 cgr_val;
const char *parent;
#define CLK_GATE_INVERTED (1 << 0)
unsigned flags;
@@ -43,7 +44,7 @@ static int clk_gate2_enable(struct clk *clk)
if (g->flags & CLK_GATE_INVERTED)
val &= ~(3 << g->shift);
else
- val |= 3 << g->shift;
+ val |= g->cgr_val << g->shift;
writel(val, g->reg);
@@ -87,12 +88,13 @@ static struct clk_ops clk_gate2_ops = {
};
struct clk *clk_gate2_alloc(const char *name, const char *parent,
- void __iomem *reg, u8 shift)
+ void __iomem *reg, u8 shift, u8 cgr_val)
{
struct clk_gate2 *g = xzalloc(sizeof(*g));
g->parent = parent;
g->reg = reg;
+ g->cgr_val = cgr_val;
g->shift = shift;
g->clk.ops = &clk_gate2_ops;
g->clk.name = name;
@@ -111,12 +113,12 @@ void clk_gate2_free(struct clk *clk)
}
struct clk *clk_gate2(const char *name, const char *parent, void __iomem *reg,
- u8 shift)
+ u8 shift, u8 cgr_val)
{
struct clk *g;
int ret;
- g = clk_gate2_alloc(name , parent, reg, shift);
+ g = clk_gate2_alloc(name , parent, reg, shift, cgr_val);
ret = clk_register(g);
if (ret) {
@@ -133,7 +135,7 @@ struct clk *clk_gate2_inverted(const char *name, const char *parent,
struct clk *clk;
struct clk_gate2 *g;
- clk = clk_gate2(name, parent, reg, shift);
+ clk = clk_gate2(name, parent, reg, shift, 0x3);
if (IS_ERR(clk))
return clk;
diff --git a/arch/arm/mach-imx/clk-imx1.c b/drivers/clk/imx/clk-imx1.c
index 5f600a9da3..5f600a9da3 100644
--- a/arch/arm/mach-imx/clk-imx1.c
+++ b/drivers/clk/imx/clk-imx1.c
diff --git a/arch/arm/mach-imx/clk-imx21.c b/drivers/clk/imx/clk-imx21.c
index 546461b8ee..546461b8ee 100644
--- a/arch/arm/mach-imx/clk-imx21.c
+++ b/drivers/clk/imx/clk-imx21.c
diff --git a/arch/arm/mach-imx/clk-imx25.c b/drivers/clk/imx/clk-imx25.c
index 864d06e195..864d06e195 100644
--- a/arch/arm/mach-imx/clk-imx25.c
+++ b/drivers/clk/imx/clk-imx25.c
diff --git a/arch/arm/mach-imx/clk-imx27.c b/drivers/clk/imx/clk-imx27.c
index 4b63244211..4b63244211 100644
--- a/arch/arm/mach-imx/clk-imx27.c
+++ b/drivers/clk/imx/clk-imx27.c
diff --git a/arch/arm/mach-imx/clk-imx31.c b/drivers/clk/imx/clk-imx31.c
index 8d135c9a1f..8d135c9a1f 100644
--- a/arch/arm/mach-imx/clk-imx31.c
+++ b/drivers/clk/imx/clk-imx31.c
diff --git a/arch/arm/mach-imx/clk-imx35.c b/drivers/clk/imx/clk-imx35.c
index af6c4058d7..af6c4058d7 100644
--- a/arch/arm/mach-imx/clk-imx35.c
+++ b/drivers/clk/imx/clk-imx35.c
diff --git a/arch/arm/mach-imx/clk-imx5.c b/drivers/clk/imx/clk-imx5.c
index c4c47a6d87..c4c47a6d87 100644
--- a/arch/arm/mach-imx/clk-imx5.c
+++ b/drivers/clk/imx/clk-imx5.c
diff --git a/arch/arm/mach-imx/clk-imx6.c b/drivers/clk/imx/clk-imx6.c
index 8ac43bebb0..8ac43bebb0 100644
--- a/arch/arm/mach-imx/clk-imx6.c
+++ b/drivers/clk/imx/clk-imx6.c
diff --git a/arch/arm/mach-imx/clk-imx6sx.c b/drivers/clk/imx/clk-imx6sx.c
index d758957d4d..d758957d4d 100644
--- a/arch/arm/mach-imx/clk-imx6sx.c
+++ b/drivers/clk/imx/clk-imx6sx.c
diff --git a/arch/arm/mach-imx/clk-imx6ul.c b/drivers/clk/imx/clk-imx6ul.c
index 72b5fa2b75..72b5fa2b75 100644
--- a/arch/arm/mach-imx/clk-imx6ul.c
+++ b/drivers/clk/imx/clk-imx6ul.c
diff --git a/arch/arm/mach-imx/clk-pfd.c b/drivers/clk/imx/clk-pfd.c
index 8f6d5ad7a8..8f6d5ad7a8 100644
--- a/arch/arm/mach-imx/clk-pfd.c
+++ b/drivers/clk/imx/clk-pfd.c
diff --git a/arch/arm/mach-imx/clk-pllv1.c b/drivers/clk/imx/clk-pllv1.c
index f992134f7e..f992134f7e 100644
--- a/arch/arm/mach-imx/clk-pllv1.c
+++ b/drivers/clk/imx/clk-pllv1.c
diff --git a/arch/arm/mach-imx/clk-pllv2.c b/drivers/clk/imx/clk-pllv2.c
index 5ba07fa5e6..5ba07fa5e6 100644
--- a/arch/arm/mach-imx/clk-pllv2.c
+++ b/drivers/clk/imx/clk-pllv2.c
diff --git a/arch/arm/mach-imx/clk-pllv3.c b/drivers/clk/imx/clk-pllv3.c
index e38dcdfdaa..29c0f1c700 100644
--- a/arch/arm/mach-imx/clk-pllv3.c
+++ b/drivers/clk/imx/clk-pllv3.c
@@ -36,6 +36,7 @@ struct clk_pllv3 {
void __iomem *base;
bool powerup_set;
u32 div_mask;
+ u32 div_shift;
const char *parent;
};
@@ -92,7 +93,7 @@ static unsigned long clk_pllv3_recalc_rate(struct clk *clk,
unsigned long parent_rate)
{
struct clk_pllv3 *pll = to_clk_pllv3(clk);
- u32 div = readl(pll->base) & pll->div_mask;
+ u32 div = (readl(pll->base) >> pll->div_shift) & pll->div_mask;
return (div == 1) ? parent_rate * 22 : parent_rate * 20;
}
@@ -120,8 +121,8 @@ static int clk_pllv3_set_rate(struct clk *clk, unsigned long rate,
return -EINVAL;
val = readl(pll->base);
- val &= ~pll->div_mask;
- val |= div;
+ val &= ~(pll->div_mask << pll->div_shift);
+ val |= div << pll->div_shift;
writel(val, pll->base);
return 0;
@@ -292,6 +293,8 @@ struct clk *imx_clk_pllv3(enum imx_pllv3_type type, const char *name,
case IMX_PLLV3_SYS:
ops = &clk_pllv3_sys_ops;
break;
+ case IMX_PLLV3_USB_VF610:
+ pll->div_shift = 1;
case IMX_PLLV3_USB:
ops = &clk_pllv3_ops;
pll->powerup_set = true;
diff --git a/drivers/clk/imx/clk-vf610.c b/drivers/clk/imx/clk-vf610.c
new file mode 100644
index 0000000000..9b9ac6cb0a
--- /dev/null
+++ b/drivers/clk/imx/clk-vf610.c
@@ -0,0 +1,446 @@
+/*
+ * Copyright 2012-2013 Freescale Semiconductor, Inc.
+ *
+ * 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.
+ *
+ */
+
+#include <common.h>
+#include <init.h>
+#include <driver.h>
+#include <io.h>
+#include <of.h>
+#include <of_address.h>
+#include <linux/clkdev.h>
+#include <linux/clk.h>
+#include <dt-bindings/clock/vf610-clock.h>
+
+#include "clk.h"
+
+#define CCM_CCR (ccm_base + 0x00)
+#define CCM_CSR (ccm_base + 0x04)
+#define CCM_CCSR (ccm_base + 0x08)
+#define CCSR_PLL1_PFDn_EN(n) BIT((n) + 7)
+#define CCSR_PLL2_PFDn_EN(n) BIT((n) + 11)
+#define CCSR_PLL3_PFDn_EN(n) BIT((n) + 27)
+#define CCM_CACRR (ccm_base + 0x0c)
+#define CCM_CSCMR1 (ccm_base + 0x10)
+#define CCM_CSCDR1 (ccm_base + 0x14)
+#define CCM_CSCDR2 (ccm_base + 0x18)
+#define CCM_CSCDR3 (ccm_base + 0x1c)
+#define CCM_CSCMR2 (ccm_base + 0x20)
+#define CCM_CSCDR4 (ccm_base + 0x24)
+#define CCM_CLPCR (ccm_base + 0x2c)
+#define CCM_CISR (ccm_base + 0x30)
+#define CCM_CIMR (ccm_base + 0x34)
+#define CCM_CGPR (ccm_base + 0x3c)
+#define CCM_CCGR0 (ccm_base + 0x40)
+#define CCM_CCGR1 (ccm_base + 0x44)
+#define CCM_CCGR2 (ccm_base + 0x48)
+#define CCM_CCGR3 (ccm_base + 0x4c)
+#define CCM_CCGR4 (ccm_base + 0x50)
+#define CCM_CCGR5 (ccm_base + 0x54)
+#define CCM_CCGR6 (ccm_base + 0x58)
+#define CCM_CCGR7 (ccm_base + 0x5c)
+#define CCM_CCGR8 (ccm_base + 0x60)
+#define CCM_CCGR9 (ccm_base + 0x64)
+#define CCM_CCGR10 (ccm_base + 0x68)
+#define CCM_CCGR11 (ccm_base + 0x6c)
+#define CCM_CCGRx(x) (CCM_CCGR0 + (x) * 4)
+#define CCM_CMEOR0 (ccm_base + 0x70)
+#define CCM_CMEOR1 (ccm_base + 0x74)
+#define CCM_CMEOR2 (ccm_base + 0x78)
+#define CCM_CMEOR3 (ccm_base + 0x7c)
+#define CCM_CMEOR4 (ccm_base + 0x80)
+#define CCM_CMEOR5 (ccm_base + 0x84)
+#define CCM_CPPDSR (ccm_base + 0x88)
+#define CCM_CCOWR (ccm_base + 0x8c)
+#define CCM_CCPGR0 (ccm_base + 0x90)
+#define CCM_CCPGR1 (ccm_base + 0x94)
+#define CCM_CCPGR2 (ccm_base + 0x98)
+#define CCM_CCPGR3 (ccm_base + 0x9c)
+
+#define CCM_CCGRx_CGn(n) ((n) * 2)
+
+#define PFD_PLL1_BASE (anatop_base + 0x2b0)
+#define PFD_PLL2_BASE (anatop_base + 0x100)
+#define PFD_PLL3_BASE (anatop_base + 0xf0)
+#define PLL1_CTRL (anatop_base + 0x270)
+#define PLL2_CTRL (anatop_base + 0x30)
+#define PLL3_CTRL (anatop_base + 0x10)
+#define PLL4_CTRL (anatop_base + 0x70)
+#define PLL5_CTRL (anatop_base + 0xe0)
+#define PLL6_CTRL (anatop_base + 0xa0)
+#define PLL7_CTRL (anatop_base + 0x20)
+#define ANA_MISC1 (anatop_base + 0x160)
+
+static void __iomem *anatop_base;
+static void __iomem *ccm_base;
+
+/* sources for multiplexer clocks, this is used multiple times */
+static const char *fast_sels[] = { "firc", "fxosc", };
+static const char *slow_sels[] = { "sirc_32k", "sxosc", };
+static const char *pll1_sels[] = { "pll1_sys", "pll1_pfd1", "pll1_pfd2", "pll1_pfd3", "pll1_pfd4", };
+static const char *pll2_sels[] = { "pll2_bus", "pll2_pfd1", "pll2_pfd2", "pll2_pfd3", "pll2_pfd4", };
+static const char *pll_bypass_src_sels[] = { "fast_clk_sel", "lvds1_in", };
+static const char *pll1_bypass_sels[] = { "pll1", "pll1_bypass_src", };
+static const char *pll2_bypass_sels[] = { "pll2", "pll2_bypass_src", };
+static const char *pll3_bypass_sels[] = { "pll3", "pll3_bypass_src", };
+static const char *pll4_bypass_sels[] = { "pll4", "pll4_bypass_src", };
+static const char *pll5_bypass_sels[] = { "pll5", "pll5_bypass_src", };
+static const char *pll6_bypass_sels[] = { "pll6", "pll6_bypass_src", };
+static const char *pll7_bypass_sels[] = { "pll7", "pll7_bypass_src", };
+static const char *sys_sels[] = { "fast_clk_sel", "slow_clk_sel", "pll2_pfd_sel", "pll2_bus", "pll1_pfd_sel", "pll3_usb_otg", };
+static const char *ddr_sels[] = { "pll2_pfd2", "sys_sel", };
+static const char *rmii_sels[] = { "enet_ext", "audio_ext", "enet_50m", "enet_25m", };
+static const char *enet_ts_sels[] = { "enet_ext", "fxosc", "audio_ext", "usb", "enet_ts", "enet_25m", "enet_50m", };
+static const char *esai_sels[] = { "audio_ext", "mlb", "spdif_rx", "pll4_audio_div", };
+static const char *sai_sels[] = { "audio_ext", "mlb", "spdif_rx", "pll4_audio_div", };
+static const char *nfc_sels[] = { "platform_bus", "pll1_pfd1", "pll3_pfd1", "pll3_pfd3", };
+static const char *qspi_sels[] = { "pll3_usb_otg", "pll3_pfd4", "pll2_pfd4", "pll1_pfd4", };
+static const char *esdhc_sels[] = { "pll3_usb_otg", "pll3_pfd3", "pll1_pfd3", "platform_bus", };
+static const char *dcu_sels[] = { "pll1_pfd2", "pll3_usb_otg", };
+static const char *gpu_sels[] = { "pll2_pfd2", "pll3_pfd2", };
+static const char *vadc_sels[] = { "pll6_video_div", "pll3_usb_otg_div", "pll3_usb_otg", };
+/* FTM counter clock source, not module clock */
+static const char *ftm_ext_sels[] = {"sirc_128k", "sxosc", "fxosc_half", "audio_ext", };
+static const char *ftm_fix_sels[] = { "sxosc", "ipg_bus", };
+
+
+static struct clk_div_table pll4_audio_div_table[] = {
+ { .val = 0, .div = 1 },
+ { .val = 1, .div = 2 },
+ { .val = 2, .div = 6 },
+ { .val = 3, .div = 8 },
+ { .val = 4, .div = 10 },
+ { .val = 5, .div = 12 },
+ { .val = 6, .div = 14 },
+ { .val = 7, .div = 16 },
+ { }
+};
+
+static struct clk *clk[VF610_CLK_END];
+static struct clk_onecell_data clk_data;
+
+static unsigned int const clks_init_on[] __initconst = {
+ VF610_CLK_SYS_BUS,
+ VF610_CLK_DDR_SEL,
+ VF610_CLK_DAP,
+ VF610_CLK_DDRMC,
+ VF610_CLK_WKPU,
+};
+
+static void __init vf610_clocks_init(struct device_node *ccm_node)
+{
+ u32 ccsr;
+ struct device_node *np;
+ int i;
+
+ clk[VF610_CLK_DUMMY] = clk_fixed("dummy", 0);
+ clk[VF610_CLK_SIRC_128K] = clk_fixed("sirc_128k", 128000);
+ clk[VF610_CLK_SIRC_32K] = clk_fixed("sirc_32k", 32000);
+ clk[VF610_CLK_FIRC] = clk_fixed("firc", 24000000);
+
+ clk[VF610_CLK_SXOSC] = of_clk_get_by_name(ccm_node, "sxosc");
+ clk[VF610_CLK_FXOSC] = of_clk_get_by_name(ccm_node, "fxosc");
+ clk[VF610_CLK_AUDIO_EXT] = of_clk_get_by_name(ccm_node, "audio_ext");
+ clk[VF610_CLK_ENET_EXT] = of_clk_get_by_name(ccm_node, "enet_ext");
+
+ /* Clock source from external clock via LVDs PAD */
+ clk[VF610_CLK_ANACLK1] = of_clk_get_by_name(ccm_node, "anaclk1");
+
+ clk[VF610_CLK_FXOSC_HALF] = imx_clk_fixed_factor("fxosc_half", "fxosc", 1, 2);
+
+ np = of_find_compatible_node(NULL, NULL, "fsl,vf610-anatop");
+ anatop_base = of_iomap(np, 0);
+ BUG_ON(!anatop_base);
+
+ np = ccm_node;
+ ccm_base = of_iomap(np, 0);
+ BUG_ON(!ccm_base);
+
+ ccsr = readl(CCM_CCSR);
+ ccsr |= CCSR_PLL3_PFDn_EN(1) |
+ CCSR_PLL3_PFDn_EN(2) |
+ CCSR_PLL3_PFDn_EN(3) |
+ CCSR_PLL3_PFDn_EN(4) |
+ CCSR_PLL2_PFDn_EN(1) |
+ CCSR_PLL2_PFDn_EN(2) |
+ CCSR_PLL2_PFDn_EN(3) |
+ CCSR_PLL2_PFDn_EN(4) |
+ CCSR_PLL1_PFDn_EN(1) |
+ CCSR_PLL1_PFDn_EN(2) |
+ CCSR_PLL1_PFDn_EN(3) |
+ CCSR_PLL1_PFDn_EN(4);
+ writel(ccsr, CCM_CCSR);
+
+ clk[VF610_CLK_SLOW_CLK_SEL] = imx_clk_mux("slow_clk_sel", CCM_CCSR, 4, 1, slow_sels, ARRAY_SIZE(slow_sels));
+ clk[VF610_CLK_FASK_CLK_SEL] = imx_clk_mux("fast_clk_sel", CCM_CCSR, 5, 1, fast_sels, ARRAY_SIZE(fast_sels));
+
+ clk[VF610_CLK_PLL1_BYPASS_SRC] = imx_clk_mux("pll1_bypass_src", PLL1_CTRL, 14, 1, pll_bypass_src_sels, ARRAY_SIZE(pll_bypass_src_sels));
+ clk[VF610_CLK_PLL2_BYPASS_SRC] = imx_clk_mux("pll2_bypass_src", PLL2_CTRL, 14, 1, pll_bypass_src_sels, ARRAY_SIZE(pll_bypass_src_sels));
+ clk[VF610_CLK_PLL3_BYPASS_SRC] = imx_clk_mux("pll3_bypass_src", PLL3_CTRL, 14, 1, pll_bypass_src_sels, ARRAY_SIZE(pll_bypass_src_sels));
+ clk[VF610_CLK_PLL4_BYPASS_SRC] = imx_clk_mux("pll4_bypass_src", PLL4_CTRL, 14, 1, pll_bypass_src_sels, ARRAY_SIZE(pll_bypass_src_sels));
+ clk[VF610_CLK_PLL5_BYPASS_SRC] = imx_clk_mux("pll5_bypass_src", PLL5_CTRL, 14, 1, pll_bypass_src_sels, ARRAY_SIZE(pll_bypass_src_sels));
+ clk[VF610_CLK_PLL6_BYPASS_SRC] = imx_clk_mux("pll6_bypass_src", PLL6_CTRL, 14, 1, pll_bypass_src_sels, ARRAY_SIZE(pll_bypass_src_sels));
+ clk[VF610_CLK_PLL7_BYPASS_SRC] = imx_clk_mux("pll7_bypass_src", PLL7_CTRL, 14, 1, pll_bypass_src_sels, ARRAY_SIZE(pll_bypass_src_sels));
+
+ clk[VF610_CLK_PLL1] = imx_clk_pllv3(IMX_PLLV3_GENERIC, "pll1", "pll1_bypass_src", PLL1_CTRL, 0x1);
+ clk[VF610_CLK_PLL2] = imx_clk_pllv3(IMX_PLLV3_GENERIC, "pll2", "pll2_bypass_src", PLL2_CTRL, 0x1);
+ clk[VF610_CLK_PLL3] = imx_clk_pllv3(IMX_PLLV3_USB_VF610, "pll3", "pll3_bypass_src", PLL3_CTRL, 0x2);
+ clk[VF610_CLK_PLL4] = imx_clk_pllv3(IMX_PLLV3_AV, "pll4", "pll4_bypass_src", PLL4_CTRL, 0x7f);
+ clk[VF610_CLK_PLL5] = imx_clk_pllv3(IMX_PLLV3_ENET, "pll5", "pll5_bypass_src", PLL5_CTRL, 0x3);
+ clk[VF610_CLK_PLL6] = imx_clk_pllv3(IMX_PLLV3_AV, "pll6", "pll6_bypass_src", PLL6_CTRL, 0x7f);
+ clk[VF610_CLK_PLL7] = imx_clk_pllv3(IMX_PLLV3_USB_VF610, "pll7", "pll7_bypass_src", PLL7_CTRL, 0x2);
+
+ clk[VF610_PLL1_BYPASS] = imx_clk_mux_flags("pll1_bypass", PLL1_CTRL, 16, 1, pll1_bypass_sels, ARRAY_SIZE(pll1_bypass_sels), CLK_SET_RATE_PARENT);
+ clk[VF610_PLL2_BYPASS] = imx_clk_mux_flags("pll2_bypass", PLL2_CTRL, 16, 1, pll2_bypass_sels, ARRAY_SIZE(pll2_bypass_sels), CLK_SET_RATE_PARENT);
+ clk[VF610_PLL3_BYPASS] = imx_clk_mux_flags("pll3_bypass", PLL3_CTRL, 16, 1, pll3_bypass_sels, ARRAY_SIZE(pll3_bypass_sels), CLK_SET_RATE_PARENT);
+ clk[VF610_PLL4_BYPASS] = imx_clk_mux_flags("pll4_bypass", PLL4_CTRL, 16, 1, pll4_bypass_sels, ARRAY_SIZE(pll4_bypass_sels), CLK_SET_RATE_PARENT);
+ clk[VF610_PLL5_BYPASS] = imx_clk_mux_flags("pll5_bypass", PLL5_CTRL, 16, 1, pll5_bypass_sels, ARRAY_SIZE(pll5_bypass_sels), CLK_SET_RATE_PARENT);
+ clk[VF610_PLL6_BYPASS] = imx_clk_mux_flags("pll6_bypass", PLL6_CTRL, 16, 1, pll6_bypass_sels, ARRAY_SIZE(pll6_bypass_sels), CLK_SET_RATE_PARENT);
+ clk[VF610_PLL7_BYPASS] = imx_clk_mux_flags("pll7_bypass", PLL7_CTRL, 16, 1, pll7_bypass_sels, ARRAY_SIZE(pll7_bypass_sels), CLK_SET_RATE_PARENT);
+
+ /* Do not bypass PLLs initially */
+ clk_set_parent(clk[VF610_PLL1_BYPASS], clk[VF610_CLK_PLL1]);
+ clk_set_parent(clk[VF610_PLL2_BYPASS], clk[VF610_CLK_PLL2]);
+ clk_set_parent(clk[VF610_PLL3_BYPASS], clk[VF610_CLK_PLL3]);
+ clk_set_parent(clk[VF610_PLL4_BYPASS], clk[VF610_CLK_PLL4]);
+ clk_set_parent(clk[VF610_PLL5_BYPASS], clk[VF610_CLK_PLL5]);
+ clk_set_parent(clk[VF610_PLL6_BYPASS], clk[VF610_CLK_PLL6]);
+ clk_set_parent(clk[VF610_PLL7_BYPASS], clk[VF610_CLK_PLL7]);
+
+ clk[VF610_CLK_PLL1_SYS] = imx_clk_gate("pll1_sys", "pll1_bypass", PLL1_CTRL, 13);
+ clk[VF610_CLK_PLL2_BUS] = imx_clk_gate("pll2_bus", "pll2_bypass", PLL2_CTRL, 13);
+ clk[VF610_CLK_PLL3_USB_OTG] = imx_clk_gate("pll3_usb_otg", "pll3_bypass", PLL3_CTRL, 13);
+ clk[VF610_CLK_PLL4_AUDIO] = imx_clk_gate("pll4_audio", "pll4_bypass", PLL4_CTRL, 13);
+ clk[VF610_CLK_PLL5_ENET] = imx_clk_gate("pll5_enet", "pll5_bypass", PLL5_CTRL, 13);
+ clk[VF610_CLK_PLL6_VIDEO] = imx_clk_gate("pll6_video", "pll6_bypass", PLL6_CTRL, 13);
+ clk[VF610_CLK_PLL7_USB_HOST] = imx_clk_gate("pll7_usb_host", "pll7_bypass", PLL7_CTRL, 13);
+
+ clk[VF610_CLK_LVDS1_IN] = imx_clk_gate_exclusive("lvds1_in", "anaclk1", ANA_MISC1, 12, BIT(10));
+
+ clk[VF610_CLK_PLL1_PFD1] = imx_clk_pfd("pll1_pfd1", "pll1_sys", PFD_PLL1_BASE, 0);
+ clk[VF610_CLK_PLL1_PFD2] = imx_clk_pfd("pll1_pfd2", "pll1_sys", PFD_PLL1_BASE, 1);
+ clk[VF610_CLK_PLL1_PFD3] = imx_clk_pfd("pll1_pfd3", "pll1_sys", PFD_PLL1_BASE, 2);
+ clk[VF610_CLK_PLL1_PFD4] = imx_clk_pfd("pll1_pfd4", "pll1_sys", PFD_PLL1_BASE, 3);
+
+ clk[VF610_CLK_PLL2_PFD1] = imx_clk_pfd("pll2_pfd1", "pll2_bus", PFD_PLL2_BASE, 0);
+ clk[VF610_CLK_PLL2_PFD2] = imx_clk_pfd("pll2_pfd2", "pll2_bus", PFD_PLL2_BASE, 1);
+ clk[VF610_CLK_PLL2_PFD3] = imx_clk_pfd("pll2_pfd3", "pll2_bus", PFD_PLL2_BASE, 2);
+ clk[VF610_CLK_PLL2_PFD4] = imx_clk_pfd("pll2_pfd4", "pll2_bus", PFD_PLL2_BASE, 3);
+
+ clk[VF610_CLK_PLL3_PFD1] = imx_clk_pfd("pll3_pfd1", "pll3_usb_otg", PFD_PLL3_BASE, 0);
+ clk[VF610_CLK_PLL3_PFD2] = imx_clk_pfd("pll3_pfd2", "pll3_usb_otg", PFD_PLL3_BASE, 1);
+ clk[VF610_CLK_PLL3_PFD3] = imx_clk_pfd("pll3_pfd3", "pll3_usb_otg", PFD_PLL3_BASE, 2);
+ clk[VF610_CLK_PLL3_PFD4] = imx_clk_pfd("pll3_pfd4", "pll3_usb_otg", PFD_PLL3_BASE, 3);
+
+ clk[VF610_CLK_PLL1_PFD_SEL] = imx_clk_mux("pll1_pfd_sel", CCM_CCSR, 16, 3, pll1_sels, 5);
+ clk[VF610_CLK_PLL2_PFD_SEL] = imx_clk_mux("pll2_pfd_sel", CCM_CCSR, 19, 3, pll2_sels, 5);
+ clk[VF610_CLK_SYS_SEL] = imx_clk_mux("sys_sel", CCM_CCSR, 0, 3, sys_sels, ARRAY_SIZE(sys_sels));
+ clk[VF610_CLK_DDR_SEL] = imx_clk_mux("ddr_sel", CCM_CCSR, 6, 1, ddr_sels, ARRAY_SIZE(ddr_sels));
+ clk[VF610_CLK_SYS_BUS] = imx_clk_divider("sys_bus", "sys_sel", CCM_CACRR, 0, 3);
+ clk[VF610_CLK_PLATFORM_BUS] = imx_clk_divider("platform_bus", "sys_bus", CCM_CACRR, 3, 3);
+ clk[VF610_CLK_IPG_BUS] = imx_clk_divider("ipg_bus", "platform_bus", CCM_CACRR, 11, 2);
+
+ clk[VF610_CLK_PLL3_MAIN_DIV] = imx_clk_divider("pll3_usb_otg_div", "pll3_usb_otg", CCM_CACRR, 20, 1);
+ clk[VF610_CLK_PLL4_MAIN_DIV] = clk_divider_table("pll4_audio_div", "pll4_audio", CCM_CACRR, 6, 3, pll4_audio_div_table, 0);
+ clk[VF610_CLK_PLL6_MAIN_DIV] = imx_clk_divider("pll6_video_div", "pll6_video", CCM_CACRR, 21, 1);
+
+ clk[VF610_CLK_DDRMC] = imx_clk_gate2_cgr("ddrmc", "ddr_sel", CCM_CCGR6, CCM_CCGRx_CGn(14), 0x2);
+ clk[VF610_CLK_WKPU] = imx_clk_gate2_cgr("wkpu", "ipg_bus", CCM_CCGR4, CCM_CCGRx_CGn(10), 0x2);
+
+ clk[VF610_CLK_USBPHY0] = imx_clk_gate("usbphy0", "pll3_usb_otg", PLL3_CTRL, 6);
+ clk[VF610_CLK_USBPHY1] = imx_clk_gate("usbphy1", "pll7_usb_host", PLL7_CTRL, 6);
+
+ clk[VF610_CLK_USBC0] = imx_clk_gate2("usbc0", "ipg_bus", CCM_CCGR1, CCM_CCGRx_CGn(4));
+ clk[VF610_CLK_USBC1] = imx_clk_gate2("usbc1", "ipg_bus", CCM_CCGR7, CCM_CCGRx_CGn(4));
+
+ clk[VF610_CLK_QSPI0_SEL] = imx_clk_mux("qspi0_sel", CCM_CSCMR1, 22, 2, qspi_sels, 4);
+ clk[VF610_CLK_QSPI0_EN] = imx_clk_gate("qspi0_en", "qspi0_sel", CCM_CSCDR3, 4);
+ clk[VF610_CLK_QSPI0_X4_DIV] = imx_clk_divider("qspi0_x4", "qspi0_en", CCM_CSCDR3, 0, 2);
+ clk[VF610_CLK_QSPI0_X2_DIV] = imx_clk_divider("qspi0_x2", "qspi0_x4", CCM_CSCDR3, 2, 1);
+ clk[VF610_CLK_QSPI0_X1_DIV] = imx_clk_divider("qspi0_x1", "qspi0_x2", CCM_CSCDR3, 3, 1);
+ clk[VF610_CLK_QSPI0] = imx_clk_gate2("qspi0", "qspi0_x1", CCM_CCGR2, CCM_CCGRx_CGn(4));
+
+ clk[VF610_CLK_QSPI1_SEL] = imx_clk_mux("qspi1_sel", CCM_CSCMR1, 24, 2, qspi_sels, 4);
+ clk[VF610_CLK_QSPI1_EN] = imx_clk_gate("qspi1_en", "qspi1_sel", CCM_CSCDR3, 12);
+ clk[VF610_CLK_QSPI1_X4_DIV] = imx_clk_divider("qspi1_x4", "qspi1_en", CCM_CSCDR3, 8, 2);
+ clk[VF610_CLK_QSPI1_X2_DIV] = imx_clk_divider("qspi1_x2", "qspi1_x4", CCM_CSCDR3, 10, 1);
+ clk[VF610_CLK_QSPI1_X1_DIV] = imx_clk_divider("qspi1_x1", "qspi1_x2", CCM_CSCDR3, 11, 1);
+ clk[VF610_CLK_QSPI1] = imx_clk_gate2("qspi1", "qspi1_x1", CCM_CCGR8, CCM_CCGRx_CGn(4));
+
+ clk[VF610_CLK_ENET_50M] = imx_clk_fixed_factor("enet_50m", "pll5_enet", 1, 10);
+ clk[VF610_CLK_ENET_25M] = imx_clk_fixed_factor("enet_25m", "pll5_enet", 1, 20);
+ clk[VF610_CLK_ENET_SEL] = imx_clk_mux("enet_sel", CCM_CSCMR2, 4, 2, rmii_sels, 4);
+ clk[VF610_CLK_ENET_TS_SEL] = imx_clk_mux("enet_ts_sel", CCM_CSCMR2, 0, 3, enet_ts_sels, 7);
+ clk[VF610_CLK_ENET] = imx_clk_gate("enet", "enet_sel", CCM_CSCDR1, 24);
+ clk[VF610_CLK_ENET_TS] = imx_clk_gate("enet_ts", "enet_ts_sel", CCM_CSCDR1, 23);
+ clk[VF610_CLK_ENET0] = imx_clk_gate2("enet0", "ipg_bus", CCM_CCGR9, CCM_CCGRx_CGn(0));
+ clk[VF610_CLK_ENET1] = imx_clk_gate2("enet1", "ipg_bus", CCM_CCGR9, CCM_CCGRx_CGn(1));
+
+ clk[VF610_CLK_PIT] = imx_clk_gate2("pit", "ipg_bus", CCM_CCGR1, CCM_CCGRx_CGn(7));
+
+ clk[VF610_CLK_UART0] = imx_clk_gate2_cgr("uart0", "ipg_bus", CCM_CCGR0, CCM_CCGRx_CGn(7), 0x2);
+ clk[VF610_CLK_UART1] = imx_clk_gate2_cgr("uart1", "ipg_bus", CCM_CCGR0, CCM_CCGRx_CGn(8), 0x2);
+ clk[VF610_CLK_UART2] = imx_clk_gate2_cgr("uart2", "ipg_bus", CCM_CCGR0, CCM_CCGRx_CGn(9), 0x2);
+ clk[VF610_CLK_UART3] = imx_clk_gate2_cgr("uart3", "ipg_bus", CCM_CCGR0, CCM_CCGRx_CGn(10), 0x2);
+ clk[VF610_CLK_UART4] = imx_clk_gate2_cgr("uart4", "ipg_bus", CCM_CCGR6, CCM_CCGRx_CGn(9), 0x2);
+ clk[VF610_CLK_UART5] = imx_clk_gate2_cgr("uart5", "ipg_bus", CCM_CCGR6, CCM_CCGRx_CGn(10), 0x2);
+
+ clk[VF610_CLK_I2C0] = imx_clk_gate2("i2c0", "ipg_bus", CCM_CCGR4, CCM_CCGRx_CGn(6));
+ clk[VF610_CLK_I2C1] = imx_clk_gate2("i2c1", "ipg_bus", CCM_CCGR4, CCM_CCGRx_CGn(7));
+ clk[VF610_CLK_I2C2] = imx_clk_gate2("i2c2", "ipg_bus", CCM_CCGR10, CCM_CCGRx_CGn(6));
+ clk[VF610_CLK_I2C3] = imx_clk_gate2("i2c3", "ipg_bus", CCM_CCGR10, CCM_CCGRx_CGn(7));
+
+ clk[VF610_CLK_DSPI0] = imx_clk_gate2("dspi0", "ipg_bus", CCM_CCGR0, CCM_CCGRx_CGn(12));
+ clk[VF610_CLK_DSPI1] = imx_clk_gate2("dspi1", "ipg_bus", CCM_CCGR0, CCM_CCGRx_CGn(13));
+ clk[VF610_CLK_DSPI2] = imx_clk_gate2("dspi2", "ipg_bus", CCM_CCGR6, CCM_CCGRx_CGn(12));
+ clk[VF610_CLK_DSPI3] = imx_clk_gate2("dspi3", "ipg_bus", CCM_CCGR6, CCM_CCGRx_CGn(13));
+
+ clk[VF610_CLK_WDT] = imx_clk_gate2("wdt", "ipg_bus", CCM_CCGR1, CCM_CCGRx_CGn(14));
+
+ clk[VF610_CLK_ESDHC0_SEL] = imx_clk_mux("esdhc0_sel", CCM_CSCMR1, 16, 2, esdhc_sels, 4);
+ clk[VF610_CLK_ESDHC0_EN] = imx_clk_gate("esdhc0_en", "esdhc0_sel", CCM_CSCDR2, 28);
+ clk[VF610_CLK_ESDHC0_DIV] = imx_clk_divider("esdhc0_div", "esdhc0_en", CCM_CSCDR2, 16, 4);
+ clk[VF610_CLK_ESDHC0] = imx_clk_gate2("eshc0", "esdhc0_div", CCM_CCGR7, CCM_CCGRx_CGn(1));
+
+ clk[VF610_CLK_ESDHC1_SEL] = imx_clk_mux("esdhc1_sel", CCM_CSCMR1, 18, 2, esdhc_sels, 4);
+ clk[VF610_CLK_ESDHC1_EN] = imx_clk_gate("esdhc1_en", "esdhc1_sel", CCM_CSCDR2, 29);
+ clk[VF610_CLK_ESDHC1_DIV] = imx_clk_divider("esdhc1_div", "esdhc1_en", CCM_CSCDR2, 20, 4);
+ clk[VF610_CLK_ESDHC1] = imx_clk_gate2("eshc1", "esdhc1_div", CCM_CCGR7, CCM_CCGRx_CGn(2));
+
+ /*
+ * ftm_ext_clk and ftm_fix_clk are FTM timer counter's
+ * selectable clock sources, both use a common enable bit
+ * in CCM_CSCDR1, selecting "dummy" clock as parent of
+ * "ftm0_ext_fix" make it serve only for enable/disable.
+ */
+ clk[VF610_CLK_FTM0_EXT_SEL] = imx_clk_mux("ftm0_ext_sel", CCM_CSCMR2, 6, 2, ftm_ext_sels, 4);
+ clk[VF610_CLK_FTM0_FIX_SEL] = imx_clk_mux("ftm0_fix_sel", CCM_CSCMR2, 14, 1, ftm_fix_sels, 2);
+ clk[VF610_CLK_FTM0_EXT_FIX_EN] = imx_clk_gate("ftm0_ext_fix_en", "dummy", CCM_CSCDR1, 25);
+ clk[VF610_CLK_FTM1_EXT_SEL] = imx_clk_mux("ftm1_ext_sel", CCM_CSCMR2, 8, 2, ftm_ext_sels, 4);
+ clk[VF610_CLK_FTM1_FIX_SEL] = imx_clk_mux("ftm1_fix_sel", CCM_CSCMR2, 15, 1, ftm_fix_sels, 2);
+ clk[VF610_CLK_FTM1_EXT_FIX_EN] = imx_clk_gate("ftm1_ext_fix_en", "dummy", CCM_CSCDR1, 26);
+ clk[VF610_CLK_FTM2_EXT_SEL] = imx_clk_mux("ftm2_ext_sel", CCM_CSCMR2, 10, 2, ftm_ext_sels, 4);
+ clk[VF610_CLK_FTM2_FIX_SEL] = imx_clk_mux("ftm2_fix_sel", CCM_CSCMR2, 16, 1, ftm_fix_sels, 2);
+ clk[VF610_CLK_FTM2_EXT_FIX_EN] = imx_clk_gate("ftm2_ext_fix_en", "dummy", CCM_CSCDR1, 27);
+ clk[VF610_CLK_FTM3_EXT_SEL] = imx_clk_mux("ftm3_ext_sel", CCM_CSCMR2, 12, 2, ftm_ext_sels, 4);
+ clk[VF610_CLK_FTM3_FIX_SEL] = imx_clk_mux("ftm3_fix_sel", CCM_CSCMR2, 17, 1, ftm_fix_sels, 2);
+ clk[VF610_CLK_FTM3_EXT_FIX_EN] = imx_clk_gate("ftm3_ext_fix_en", "dummy", CCM_CSCDR1, 28);
+
+ /* ftm(n)_clk are FTM module operation clock */
+ clk[VF610_CLK_FTM0] = imx_clk_gate2("ftm0", "ipg_bus", CCM_CCGR1, CCM_CCGRx_CGn(8));
+ clk[VF610_CLK_FTM1] = imx_clk_gate2("ftm1", "ipg_bus", CCM_CCGR1, CCM_CCGRx_CGn(9));
+ clk[VF610_CLK_FTM2] = imx_clk_gate2("ftm2", "ipg_bus", CCM_CCGR7, CCM_CCGRx_CGn(8));
+ clk[VF610_CLK_FTM3] = imx_clk_gate2("ftm3", "ipg_bus", CCM_CCGR7, CCM_CCGRx_CGn(9));
+
+ clk[VF610_CLK_DCU0_SEL] = imx_clk_mux("dcu0_sel", CCM_CSCMR1, 28, 1, dcu_sels, 2);
+ clk[VF610_CLK_DCU0_EN] = imx_clk_gate("dcu0_en", "dcu0_sel", CCM_CSCDR3, 19);
+ clk[VF610_CLK_DCU0_DIV] = imx_clk_divider("dcu0_div", "dcu0_en", CCM_CSCDR3, 16, 3);
+ clk[VF610_CLK_DCU0] = imx_clk_gate2("dcu0", "ipg_bus", CCM_CCGR3, CCM_CCGRx_CGn(8));
+ clk[VF610_CLK_DCU1_SEL] = imx_clk_mux("dcu1_sel", CCM_CSCMR1, 29, 1, dcu_sels, 2);
+ clk[VF610_CLK_DCU1_EN] = imx_clk_gate("dcu1_en", "dcu1_sel", CCM_CSCDR3, 23);
+ clk[VF610_CLK_DCU1_DIV] = imx_clk_divider("dcu1_div", "dcu1_en", CCM_CSCDR3, 20, 3);
+ clk[VF610_CLK_DCU1] = imx_clk_gate2("dcu1", "ipg_bus", CCM_CCGR9, CCM_CCGRx_CGn(8));
+
+ clk[VF610_CLK_TCON0] = imx_clk_gate2("tcon0", "platform_bus", CCM_CCGR1, CCM_CCGRx_CGn(13));
+ clk[VF610_CLK_TCON1] = imx_clk_gate2("tcon1", "platform_bus", CCM_CCGR7, CCM_CCGRx_CGn(13));
+
+ clk[VF610_CLK_ESAI_SEL] = imx_clk_mux("esai_sel", CCM_CSCMR1, 20, 2, esai_sels, 4);
+ clk[VF610_CLK_ESAI_EN] = imx_clk_gate("esai_en", "esai_sel", CCM_CSCDR2, 30);
+ clk[VF610_CLK_ESAI_DIV] = imx_clk_divider("esai_div", "esai_en", CCM_CSCDR2, 24, 4);
+ clk[VF610_CLK_ESAI] = imx_clk_gate2("esai", "esai_div", CCM_CCGR4, CCM_CCGRx_CGn(2));
+
+ clk[VF610_CLK_SAI0_SEL] = imx_clk_mux("sai0_sel", CCM_CSCMR1, 0, 2, sai_sels, 4);
+ clk[VF610_CLK_SAI0_EN] = imx_clk_gate("sai0_en", "sai0_sel", CCM_CSCDR1, 16);
+ clk[VF610_CLK_SAI0_DIV] = imx_clk_divider("sai0_div", "sai0_en", CCM_CSCDR1, 0, 4);
+ clk[VF610_CLK_SAI0] = imx_clk_gate2("sai0", "ipg_bus", CCM_CCGR0, CCM_CCGRx_CGn(15));
+
+ clk[VF610_CLK_SAI1_SEL] = imx_clk_mux("sai1_sel", CCM_CSCMR1, 2, 2, sai_sels, 4);
+ clk[VF610_CLK_SAI1_EN] = imx_clk_gate("sai1_en", "sai1_sel", CCM_CSCDR1, 17);
+ clk[VF610_CLK_SAI1_DIV] = imx_clk_divider("sai1_div", "sai1_en", CCM_CSCDR1, 4, 4);
+ clk[VF610_CLK_SAI1] = imx_clk_gate2("sai1", "ipg_bus", CCM_CCGR1, CCM_CCGRx_CGn(0));
+
+ clk[VF610_CLK_SAI2_SEL] = imx_clk_mux("sai2_sel", CCM_CSCMR1, 4, 2, sai_sels, 4);
+ clk[VF610_CLK_SAI2_EN] = imx_clk_gate("sai2_en", "sai2_sel", CCM_CSCDR1, 18);
+ clk[VF610_CLK_SAI2_DIV] = imx_clk_divider("sai2_div", "sai2_en", CCM_CSCDR1, 8, 4);
+ clk[VF610_CLK_SAI2] = imx_clk_gate2("sai2", "ipg_bus", CCM_CCGR1, CCM_CCGRx_CGn(1));
+
+ clk[VF610_CLK_SAI3_SEL] = imx_clk_mux("sai3_sel", CCM_CSCMR1, 6, 2, sai_sels, 4);
+ clk[VF610_CLK_SAI3_EN] = imx_clk_gate("sai3_en", "sai3_sel", CCM_CSCDR1, 19);
+ clk[VF610_CLK_SAI3_DIV] = imx_clk_divider("sai3_div", "sai3_en", CCM_CSCDR1, 12, 4);
+ clk[VF610_CLK_SAI3] = imx_clk_gate2("sai3", "ipg_bus", CCM_CCGR1, CCM_CCGRx_CGn(2));
+
+ clk[VF610_CLK_NFC_SEL] = imx_clk_mux("nfc_sel", CCM_CSCMR1, 12, 2, nfc_sels, 4);
+ clk[VF610_CLK_NFC_EN] = imx_clk_gate("nfc_en", "nfc_sel", CCM_CSCDR2, 9);
+ clk[VF610_CLK_NFC_PRE_DIV] = imx_clk_divider("nfc_pre_div", "nfc_en", CCM_CSCDR3, 13, 3);
+ clk[VF610_CLK_NFC_FRAC_DIV] = imx_clk_divider("nfc_frac_div", "nfc_pre_div", CCM_CSCDR2, 4, 4);
+ clk[VF610_CLK_NFC] = imx_clk_gate2("nfc", "nfc_frac_div", CCM_CCGR10, CCM_CCGRx_CGn(0));
+
+ clk[VF610_CLK_GPU_SEL] = imx_clk_mux("gpu_sel", CCM_CSCMR1, 14, 1, gpu_sels, 2);
+ clk[VF610_CLK_GPU_EN] = imx_clk_gate("gpu_en", "gpu_sel", CCM_CSCDR2, 10);
+ clk[VF610_CLK_GPU2D] = imx_clk_gate2("gpu", "gpu_en", CCM_CCGR8, CCM_CCGRx_CGn(15));
+
+ clk[VF610_CLK_VADC_SEL] = imx_clk_mux("vadc_sel", CCM_CSCMR1, 8, 2, vadc_sels, 3);
+ clk[VF610_CLK_VADC_EN] = imx_clk_gate("vadc_en", "vadc_sel", CCM_CSCDR1, 22);
+ clk[VF610_CLK_VADC_DIV] = imx_clk_divider("vadc_div", "vadc_en", CCM_CSCDR1, 20, 2);
+ clk[VF610_CLK_VADC_DIV_HALF] = imx_clk_fixed_factor("vadc_div_half", "vadc_div", 1, 2);
+ clk[VF610_CLK_VADC] = imx_clk_gate2("vadc", "vadc_div", CCM_CCGR8, CCM_CCGRx_CGn(7));
+
+ clk[VF610_CLK_ADC0] = imx_clk_gate2("adc0", "ipg_bus", CCM_CCGR1, CCM_CCGRx_CGn(11));
+ clk[VF610_CLK_ADC1] = imx_clk_gate2("adc1", "ipg_bus", CCM_CCGR7, CCM_CCGRx_CGn(11));
+ clk[VF610_CLK_DAC0] = imx_clk_gate2("dac0", "ipg_bus", CCM_CCGR8, CCM_CCGRx_CGn(12));
+ clk[VF610_CLK_DAC1] = imx_clk_gate2("dac1", "ipg_bus", CCM_CCGR8, CCM_CCGRx_CGn(13));
+
+ clk[VF610_CLK_ASRC] = imx_clk_gate2("asrc", "ipg_bus", CCM_CCGR4, CCM_CCGRx_CGn(1));
+
+ clk[VF610_CLK_FLEXCAN0_EN] = imx_clk_gate("flexcan0_en", "ipg_bus", CCM_CSCDR2, 11);
+ clk[VF610_CLK_FLEXCAN0] = imx_clk_gate2("flexcan0", "flexcan0_en", CCM_CCGR0, CCM_CCGRx_CGn(0));
+ clk[VF610_CLK_FLEXCAN1_EN] = imx_clk_gate("flexcan1_en", "ipg_bus", CCM_CSCDR2, 12);
+ clk[VF610_CLK_FLEXCAN1] = imx_clk_gate2("flexcan1", "flexcan1_en", CCM_CCGR9, CCM_CCGRx_CGn(4));
+
+ clk[VF610_CLK_DMAMUX0] = imx_clk_gate2("dmamux0", "platform_bus", CCM_CCGR0, CCM_CCGRx_CGn(4));
+ clk[VF610_CLK_DMAMUX1] = imx_clk_gate2("dmamux1", "platform_bus", CCM_CCGR0, CCM_CCGRx_CGn(5));
+ clk[VF610_CLK_DMAMUX2] = imx_clk_gate2("dmamux2", "platform_bus", CCM_CCGR6, CCM_CCGRx_CGn(1));
+ clk[VF610_CLK_DMAMUX3] = imx_clk_gate2("dmamux3", "platform_bus", CCM_CCGR6, CCM_CCGRx_CGn(2));
+
+ clk[VF610_CLK_SNVS] = imx_clk_gate2("snvs-rtc", "ipg_bus", CCM_CCGR6, CCM_CCGRx_CGn(7));
+ clk[VF610_CLK_DAP] = imx_clk_gate("dap", "platform_bus", CCM_CCSR, 24);
+ clk[VF610_CLK_OCOTP] = imx_clk_gate("ocotp", "ipg_bus", CCM_CCGR6, CCM_CCGRx_CGn(5));
+
+ imx_check_clocks(clk, ARRAY_SIZE(clk));
+
+ clk_set_parent(clk[VF610_CLK_QSPI0_SEL], clk[VF610_CLK_PLL1_PFD4]);
+ clk_set_rate(clk[VF610_CLK_QSPI0_X4_DIV], clk_get_rate(clk[VF610_CLK_QSPI0_SEL]) / 2);
+ clk_set_rate(clk[VF610_CLK_QSPI0_X2_DIV], clk_get_rate(clk[VF610_CLK_QSPI0_X4_DIV]) / 2);
+ clk_set_rate(clk[VF610_CLK_QSPI0_X1_DIV], clk_get_rate(clk[VF610_CLK_QSPI0_X2_DIV]) / 2);
+
+ clk_set_parent(clk[VF610_CLK_QSPI1_SEL], clk[VF610_CLK_PLL1_PFD4]);
+ clk_set_rate(clk[VF610_CLK_QSPI1_X4_DIV], clk_get_rate(clk[VF610_CLK_QSPI1_SEL]) / 2);
+ clk_set_rate(clk[VF610_CLK_QSPI1_X2_DIV], clk_get_rate(clk[VF610_CLK_QSPI1_X4_DIV]) / 2);
+ clk_set_rate(clk[VF610_CLK_QSPI1_X1_DIV], clk_get_rate(clk[VF610_CLK_QSPI1_X2_DIV]) / 2);
+
+ clk_set_parent(clk[VF610_CLK_ESDHC1_SEL], clk[VF610_CLK_PLL1_PFD3]);
+ clk_set_rate(clk[VF610_CLK_ESDHC1_DIV], clk_get_rate(clk[VF610_CLK_PLL1_PFD3]) / 9);
+
+ clk_set_parent(clk[VF610_CLK_ESDHC0_SEL], clk[VF610_CLK_PLL1_PFD3]);
+ clk_set_rate(clk[VF610_CLK_ESDHC0_DIV], clk_get_rate(clk[VF610_CLK_PLL1_PFD3]) / 9);
+
+ clk_set_parent(clk[VF610_CLK_SAI0_SEL], clk[VF610_CLK_AUDIO_EXT]);
+ clk_set_parent(clk[VF610_CLK_SAI1_SEL], clk[VF610_CLK_AUDIO_EXT]);
+ clk_set_parent(clk[VF610_CLK_SAI2_SEL], clk[VF610_CLK_AUDIO_EXT]);
+ clk_set_parent(clk[VF610_CLK_SAI3_SEL], clk[VF610_CLK_AUDIO_EXT]);
+
+ for (i = 0; i < ARRAY_SIZE(clks_init_on); i++)
+ clk_enable(clk[clks_init_on[i]]);
+
+ /* Add the clocks to provider list */
+ clk_data.clks = clk;
+ clk_data.clk_num = ARRAY_SIZE(clk);
+ of_clk_add_provider(np, of_clk_src_onecell_get, &clk_data);
+}
+CLK_OF_DECLARE(vf610, "fsl,vf610-ccm", vf610_clocks_init);
diff --git a/drivers/clk/imx/clk.c b/drivers/clk/imx/clk.c
new file mode 100644
index 0000000000..7488dfcdc8
--- /dev/null
+++ b/drivers/clk/imx/clk.c
@@ -0,0 +1,21 @@
+#include <common.h>
+#include <init.h>
+#include <driver.h>
+#include <linux/clk.h>
+#include <io.h>
+#include <of.h>
+#include <linux/clkdev.h>
+#include <linux/err.h>
+
+#include "clk.h"
+
+void __init imx_check_clocks(struct clk *clks[], unsigned int count)
+{
+ unsigned i;
+
+ for (i = 0; i < count; i++)
+ if (IS_ERR(clks[i]))
+ pr_err("i.MX clk %u: register failed with %ld\n",
+ i, PTR_ERR(clks[i]));
+}
+
diff --git a/arch/arm/mach-imx/clk.h b/drivers/clk/imx/clk.h
index c5913e1879..970f65c7d1 100644
--- a/arch/arm/mach-imx/clk.h
+++ b/drivers/clk/imx/clk.h
@@ -2,7 +2,7 @@
#define __IMX_CLK_H
struct clk *clk_gate2(const char *name, const char *parent, void __iomem *reg,
- u8 shift);
+ u8 shift, u8 cgr_val);
static inline struct clk *imx_clk_divider(const char *name, const char *parent,
void __iomem *reg, u8 shift, u8 width)
@@ -30,6 +30,14 @@ static inline struct clk *imx_clk_fixed_factor(const char *name,
return clk_fixed_factor(name, parent, mult, div, CLK_SET_RATE_PARENT);
}
+static inline struct clk *imx_clk_mux_flags(const char *name, void __iomem *reg,
+ u8 shift, u8 width,
+ const char **parents, u8 num_parents,
+ unsigned long flags)
+{
+ return clk_mux(name, reg, shift, width, parents, num_parents, flags);
+}
+
static inline struct clk *imx_clk_mux(const char *name, void __iomem *reg,
u8 shift, u8 width, const char **parents, u8 num_parents)
{
@@ -51,9 +59,16 @@ static inline struct clk *imx_clk_gate(const char *name, const char *parent,
static inline struct clk *imx_clk_gate2(const char *name, const char *parent,
void __iomem *reg, u8 shift)
{
- return clk_gate2(name, parent, reg, shift);
+ return clk_gate2(name, parent, reg, shift, 0x3);
}
+static inline struct clk *imx_clk_gate2_cgr(const char *name, const char *parent,
+ void __iomem *reg, u8 shift, u8 cgr_val)
+{
+ return clk_gate2(name, parent, reg, shift, cgr_val);
+}
+
+
struct clk *imx_clk_pllv1(const char *name, const char *parent,
void __iomem *base);
@@ -64,6 +79,7 @@ enum imx_pllv3_type {
IMX_PLLV3_GENERIC,
IMX_PLLV3_SYS,
IMX_PLLV3_USB,
+ IMX_PLLV3_USB_VF610,
IMX_PLLV3_AV,
IMX_PLLV3_ENET,
IMX_PLLV3_MLB,
@@ -101,4 +117,7 @@ static inline struct clk *imx_clk_busy_mux(const char *name, void __iomem *reg,
struct clk *imx_clk_gate_exclusive(const char *name, const char *parent,
void __iomem *reg, u8 shift, u32 exclusive_mask);
+void imx_check_clocks(struct clk *clks[], unsigned int count);
+
+
#endif /* __IMX_CLK_H */
diff --git a/drivers/gpio/Kconfig b/drivers/gpio/Kconfig
index 078deee4e5..434c5688b4 100644
--- a/drivers/gpio/Kconfig
+++ b/drivers/gpio/Kconfig
@@ -49,6 +49,9 @@ config GPIO_GENERIC_PLATFORM
config GPIO_IMX
def_bool ARCH_IMX
+config GPIO_VF610
+ def_bool ARCH_VF610
+
config GPIO_MXS
def_bool ARCH_MXS
diff --git a/drivers/gpio/Makefile b/drivers/gpio/Makefile
index 2d5142d41c..f37dd08f1a 100644
--- a/drivers/gpio/Makefile
+++ b/drivers/gpio/Makefile
@@ -19,3 +19,4 @@ obj-$(CONFIG_GPIO_STMPE) += gpio-stmpe.o
obj-$(CONFIG_GPIO_TEGRA) += gpio-tegra.o
obj-$(CONFIG_GPIO_DESIGNWARE) += gpio-dw.o
obj-$(CONFIG_GPIO_SX150X) += gpio-sx150x.o
+obj-$(CONFIG_GPIO_VF610) += gpio-vf610.o
diff --git a/drivers/gpio/gpio-vf610.c b/drivers/gpio/gpio-vf610.c
new file mode 100644
index 0000000000..7c8d1e4c98
--- /dev/null
+++ b/drivers/gpio/gpio-vf610.c
@@ -0,0 +1,166 @@
+/*
+ * vf610 GPIO support through PORT and GPIO module
+ *
+ * Copyright (c) 2014 Toradex AG.
+ *
+ * Author: Stefan Agner <stefan@agner.ch>.
+ *
+ * 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 <common.h>
+#include <errno.h>
+#include <io.h>
+#include <of.h>
+#include <gpio.h>
+#include <init.h>
+#include <pinctrl.h>
+
+#define VF610_GPIO_PER_PORT 32
+#define PINCTRL_BASE 2
+#define COUNT 3
+
+struct vf610_gpio_port {
+ struct gpio_chip chip;
+ void __iomem *gpio_base;
+ unsigned int pinctrl_base;
+};
+
+#define GPIO_PDOR 0x00
+#define GPIO_PSOR 0x04
+#define GPIO_PCOR 0x08
+#define GPIO_PTOR 0x0c
+#define GPIO_PDIR 0x10
+
+static const struct of_device_id vf610_gpio_dt_ids[] = {
+ { .compatible = "fsl,vf610-gpio" },
+ { /* sentinel */ }
+};
+
+
+static int vf610_gpio_get_value(struct gpio_chip *chip, unsigned int gpio)
+{
+ struct vf610_gpio_port *port =
+ container_of(chip, struct vf610_gpio_port, chip);
+
+ return !!(readl(port->gpio_base + GPIO_PDIR) & BIT(gpio));
+}
+
+static void vf610_gpio_set_value(struct gpio_chip *chip,
+ unsigned int gpio, int val)
+{
+ struct vf610_gpio_port *port =
+ container_of(chip, struct vf610_gpio_port, chip);
+ unsigned long mask = BIT(gpio);
+
+ writel(mask, port->gpio_base + ((val) ? GPIO_PSOR : GPIO_PCOR));
+}
+
+static int vf610_gpio_direction_input(struct gpio_chip *chip, unsigned gpio)
+{
+ struct vf610_gpio_port *port =
+ container_of(chip, struct vf610_gpio_port, chip);
+
+ return pinctrl_gpio_direction_input(port->pinctrl_base + gpio);
+}
+
+static int vf610_gpio_direction_output(struct gpio_chip *chip, unsigned gpio,
+ int value)
+{
+ struct vf610_gpio_port *port =
+ container_of(chip, struct vf610_gpio_port, chip);
+
+ vf610_gpio_set_value(chip, gpio, value);
+
+ return pinctrl_gpio_direction_output(port->pinctrl_base + gpio);
+}
+
+static int vf610_gpio_get_direction(struct gpio_chip *chip, unsigned gpio)
+{
+ struct vf610_gpio_port *port =
+ container_of(chip, struct vf610_gpio_port, chip);
+
+ return pinctrl_gpio_get_direction(port->pinctrl_base + gpio);
+}
+
+static struct gpio_ops vf610_gpio_ops = {
+ .direction_input = vf610_gpio_direction_input,
+ .direction_output = vf610_gpio_direction_output,
+ .get = vf610_gpio_get_value,
+ .set = vf610_gpio_set_value,
+ .get_direction = vf610_gpio_get_direction,
+};
+
+static int vf610_gpio_probe(struct device_d *dev)
+{
+ int ret, size;
+ struct resource *iores;
+ struct vf610_gpio_port *port;
+ const __be32 *gpio_ranges;
+
+ port = xzalloc(sizeof(*port));
+ if (!port)
+ return -ENOMEM;
+
+ gpio_ranges = of_get_property(dev->device_node, "gpio-ranges", &size);
+ if (!gpio_ranges) {
+ dev_err(dev, "Couldn't read 'gpio-ranges' propery of %s\n",
+ dev->device_node->full_name);
+ ret = -EINVAL;
+ goto free_port;
+ }
+
+ port->pinctrl_base = be32_to_cpu(gpio_ranges[PINCTRL_BASE]);
+ port->chip.ngpio = be32_to_cpu(gpio_ranges[COUNT]);
+
+ iores = dev_request_mem_resource(dev, 1);
+ if (IS_ERR(iores)) {
+ ret = PTR_ERR(iores);
+ dev_dbg(dev, "Failed to request memory resource\n");
+ goto free_port;
+ }
+
+ port->gpio_base = IOMEM(iores->start);
+
+ port->chip.ops = &vf610_gpio_ops;
+ if (dev->id < 0) {
+ port->chip.base = of_alias_get_id(dev->device_node, "gpio");
+ if (port->chip.base < 0) {
+ ret = port->chip.base;
+ dev_dbg(dev, "Failed to get GPIO alias\n");
+ goto free_port;
+ }
+ } else {
+ port->chip.base = dev->id;
+ }
+
+
+ port->chip.base *= VF610_GPIO_PER_PORT;
+ port->chip.dev = dev;
+ gpiochip_add(&port->chip);
+
+ return 0;
+
+free_port:
+ free(port);
+ return ret;
+}
+
+static struct driver_d vf610_gpio_driver = {
+ .name = "gpio-vf610",
+ .probe = vf610_gpio_probe,
+ .of_compatible = DRV_OF_COMPAT(vf610_gpio_dt_ids),
+};
+
+static int __init gpio_vf610_init(void)
+{
+ return platform_driver_register(&vf610_gpio_driver);
+}
+core_initcall(gpio_vf610_init);
diff --git a/drivers/i2c/busses/i2c-imx.c b/drivers/i2c/busses/i2c-imx.c
index e407896394..74f046d00c 100644
--- a/drivers/i2c/busses/i2c-imx.c
+++ b/drivers/i2c/busses/i2c-imx.c
@@ -43,6 +43,7 @@
#include <linux/err.h>
#include <pinctrl.h>
#include <of_gpio.h>
+#include <of_device.h>
#include <io.h>
#include <i2c/i2c.h>
@@ -54,14 +55,25 @@
/* Default value */
#define FSL_I2C_BIT_RATE 100000 /* 100kHz */
-/* FSL I2C registers */
+/* IMX I2C registers:
+ * the I2C register offset is different between SoCs,
+ * to provid support for all these chips, split the
+ * register offset into a fixed base address and a
+ * variable shift value, then the full register offset
+ * will be calculated by
+ * reg_off = ( reg_base_addr << reg_shift)
+ */
#define FSL_I2C_IADR 0x00 /* i2c slave address */
-#define FSL_I2C_IFDR 0x04 /* i2c frequency divider */
-#define FSL_I2C_I2CR 0x08 /* i2c control */
-#define FSL_I2C_I2SR 0x0C /* i2c status */
-#define FSL_I2C_I2DR 0x10 /* i2c transfer data */
+#define FSL_I2C_IFDR 0x01 /* i2c frequency divider */
+#define FSL_I2C_I2CR 0x02 /* i2c control */
+#define FSL_I2C_I2SR 0x03 /* i2c status */
+#define FSL_I2C_I2DR 0x04 /* i2c transfer data */
#define FSL_I2C_DFSRR 0x14 /* i2c digital filter sampling rate */
+#define IMX_I2C_REGSHIFT 2
+#define VF610_I2C_REGSHIFT 0
+
+
/* Bits of FSL I2C registers */
#define I2SR_RXAK 0x01
#define I2SR_IIF 0x02
@@ -77,6 +89,22 @@
#define I2CR_IIEN 0x40
#define I2CR_IEN 0x80
+/* register bits different operating codes definition:
+ * 1) I2SR: Interrupt flags clear operation differ between SoCs:
+ * - write zero to clear(w0c) INT flag on i.MX,
+ * - but write one to clear(w1c) INT flag on Vybrid.
+ * 2) I2CR: I2C module enable operation also differ between SoCs:
+ * - set I2CR_IEN bit enable the module on i.MX,
+ * - but clear I2CR_IEN bit enable the module on Vybrid.
+ */
+#define I2SR_CLR_OPCODE_W0C 0x0
+#define I2SR_CLR_OPCODE_W1C (I2SR_IAL | I2SR_IIF)
+#define I2CR_IEN_OPCODE_0 0x0
+#define I2CR_IEN_OPCODE_1 I2CR_IEN
+
+#define I2C_PM_TIMEOUT 10 /* ms */
+
+
/*
* sorted list of clock divider, register value pairs
* taken from table 26-5, p.26-9, Freescale i.MX
@@ -85,8 +113,12 @@
*
* Duplicated divider values removed from list
*/
-#ifndef CONFIG_PPC
-static u16 i2c_clk_div[50][2] = {
+struct fsl_i2c_clk_pair {
+ u16 div;
+ u16 val;
+};
+
+static struct fsl_i2c_clk_pair imx_i2c_clk_div[] = {
{ 22, 0x20 }, { 24, 0x21 }, { 26, 0x22 }, { 28, 0x23 },
{ 30, 0x00 }, { 32, 0x24 }, { 36, 0x25 }, { 40, 0x26 },
{ 42, 0x03 }, { 44, 0x27 }, { 48, 0x28 }, { 52, 0x05 },
@@ -101,7 +133,33 @@ static u16 i2c_clk_div[50][2] = {
{ 1920, 0x1B }, { 2048, 0x3F }, { 2304, 0x1C }, { 2560, 0x1D },
{ 3072, 0x1E }, { 3840, 0x1F }
};
-#endif
+
+/* Vybrid VF610 clock divider, register value pairs */
+static struct fsl_i2c_clk_pair vf610_i2c_clk_div[] = {
+ { 20, 0x00 }, { 22, 0x01 }, { 24, 0x02 }, { 26, 0x03 },
+ { 28, 0x04 }, { 30, 0x05 }, { 32, 0x09 }, { 34, 0x06 },
+ { 36, 0x0A }, { 40, 0x07 }, { 44, 0x0C }, { 48, 0x0D },
+ { 52, 0x43 }, { 56, 0x0E }, { 60, 0x45 }, { 64, 0x12 },
+ { 68, 0x0F }, { 72, 0x13 }, { 80, 0x14 }, { 88, 0x15 },
+ { 96, 0x19 }, { 104, 0x16 }, { 112, 0x1A }, { 128, 0x17 },
+ { 136, 0x4F }, { 144, 0x1C }, { 160, 0x1D }, { 176, 0x55 },
+ { 192, 0x1E }, { 208, 0x56 }, { 224, 0x22 }, { 228, 0x24 },
+ { 240, 0x1F }, { 256, 0x23 }, { 288, 0x5C }, { 320, 0x25 },
+ { 384, 0x26 }, { 448, 0x2A }, { 480, 0x27 }, { 512, 0x2B },
+ { 576, 0x2C }, { 640, 0x2D }, { 768, 0x31 }, { 896, 0x32 },
+ { 960, 0x2F }, { 1024, 0x33 }, { 1152, 0x34 }, { 1280, 0x35 },
+ { 1536, 0x36 }, { 1792, 0x3A }, { 1920, 0x37 }, { 2048, 0x3B },
+ { 2304, 0x3C }, { 2560, 0x3D }, { 3072, 0x3E }, { 3584, 0x7A },
+ { 3840, 0x3F }, { 4096, 0x7B }, { 5120, 0x7D }, { 6144, 0x7E },
+};
+
+struct fsl_i2c_hwdata {
+ unsigned regshift;
+ struct fsl_i2c_clk_pair *clk_div;
+ unsigned ndivs;
+ unsigned i2sr_clr_opcode;
+ unsigned i2cr_ien_opcode;
+};
struct fsl_i2c_struct {
void __iomem *base;
@@ -112,17 +170,33 @@ struct fsl_i2c_struct {
unsigned int ifdr; /* FSL_I2C_IFDR */
unsigned int dfsrr; /* FSL_I2C_DFSRR */
struct i2c_bus_recovery_info rinfo;
+ const struct fsl_i2c_hwdata *hwdata;
};
#define to_fsl_i2c_struct(a) container_of(a, struct fsl_i2c_struct, adapter)
+static inline void fsl_i2c_write_reg(unsigned int val,
+ struct fsl_i2c_struct *i2c_fsl,
+ unsigned int reg)
+{
+ reg <<= i2c_fsl->hwdata->regshift;
+ writeb(val, i2c_fsl->base + reg);
+}
+
+static inline unsigned char fsl_i2c_read_reg(struct fsl_i2c_struct *i2c_fsl,
+ unsigned int reg)
+{
+ reg <<= i2c_fsl->hwdata->regshift;
+ return readb(i2c_fsl->base + reg);
+}
+
#ifdef CONFIG_I2C_DEBUG
static void i2c_fsl_dump_reg(struct i2c_adapter *adapter)
{
struct fsl_i2c_struct *i2c_fsl = to_fsl_i2c_struct(adapter);
u32 reg_cr, reg_sr;
- reg_cr = readb(i2c_fsl->base + FSL_I2C_I2CR);
- reg_sr = readb(i2c_fsl->base + FSL_I2C_I2SR);
+ reg_cr = fsl_i2c_read_reg(i2c_fsl, FSL_I2C_I2CR);
+ reg_sr = fsl_i2c_read_reg(i2c_fsl, FSL_I2C_I2SR);
dev_dbg(adapter->dev, "CONTROL:\t"
"IEN =%d, IIEN=%d, MSTA=%d, MTX =%d, TXAK=%d, RSTA=%d\n",
@@ -144,16 +218,16 @@ static inline void i2c_fsl_dump_reg(struct i2c_adapter *adapter)
}
#endif
+
static int i2c_fsl_bus_busy(struct i2c_adapter *adapter, int for_busy)
{
struct fsl_i2c_struct *i2c_fsl = to_fsl_i2c_struct(adapter);
- void __iomem *base = i2c_fsl->base;
uint64_t start;
unsigned int temp;
start = get_time_ns();
while (1) {
- temp = readb(base + FSL_I2C_I2SR);
+ temp = fsl_i2c_read_reg(i2c_fsl, FSL_I2C_I2SR);
if (for_busy && (temp & I2SR_IBB))
break;
if (!for_busy && !(temp & I2SR_IBB))
@@ -172,12 +246,11 @@ static int i2c_fsl_bus_busy(struct i2c_adapter *adapter, int for_busy)
static int i2c_fsl_trx_complete(struct i2c_adapter *adapter)
{
struct fsl_i2c_struct *i2c_fsl = to_fsl_i2c_struct(adapter);
- void __iomem *base = i2c_fsl->base;
uint64_t start;
start = get_time_ns();
while (1) {
- unsigned int reg = readb(base + FSL_I2C_I2SR);
+ unsigned int reg = fsl_i2c_read_reg(i2c_fsl, FSL_I2C_I2SR);
if (reg & I2SR_IIF)
break;
@@ -186,7 +259,9 @@ static int i2c_fsl_trx_complete(struct i2c_adapter *adapter)
return -EIO;
}
}
- writeb(0, base + FSL_I2C_I2SR);
+
+ fsl_i2c_write_reg(i2c_fsl->hwdata->i2sr_clr_opcode,
+ i2c_fsl, FSL_I2C_I2SR);
return 0;
}
@@ -194,12 +269,11 @@ static int i2c_fsl_trx_complete(struct i2c_adapter *adapter)
static int i2c_fsl_acked(struct i2c_adapter *adapter)
{
struct fsl_i2c_struct *i2c_fsl = to_fsl_i2c_struct(adapter);
- void __iomem *base = i2c_fsl->base;
uint64_t start;
start = get_time_ns();
while (1) {
- unsigned int reg = readb(base + FSL_I2C_I2SR);
+ unsigned int reg = fsl_i2c_read_reg(i2c_fsl, FSL_I2C_I2SR);
if (!(reg & I2SR_RXAK))
break;
@@ -215,25 +289,28 @@ static int i2c_fsl_acked(struct i2c_adapter *adapter)
static int i2c_fsl_start(struct i2c_adapter *adapter)
{
struct fsl_i2c_struct *i2c_fsl = to_fsl_i2c_struct(adapter);
- void __iomem *base = i2c_fsl->base;
unsigned int temp = 0;
int result;
- writeb(i2c_fsl->ifdr, base + FSL_I2C_IFDR);
+ fsl_i2c_write_reg(i2c_fsl->ifdr, i2c_fsl, FSL_I2C_IFDR);
+#ifdef CONFIG_PPC
if (i2c_fsl->dfsrr != -1)
- writeb(i2c_fsl->dfsrr, base + FSL_I2C_DFSRR);
+ fsl_i2c_write_reg(i2c_fsl->dfsrr, i2c_fsl, FSL_I2C_DFSRR);
+#endif
/* Enable I2C controller */
- writeb(0, base + FSL_I2C_I2SR);
- writeb(I2CR_IEN, base + FSL_I2C_I2CR);
+ fsl_i2c_write_reg(i2c_fsl->hwdata->i2sr_clr_opcode,
+ i2c_fsl, FSL_I2C_I2SR);
+ fsl_i2c_write_reg(i2c_fsl->hwdata->i2cr_ien_opcode,
+ i2c_fsl, FSL_I2C_I2CR);
/* Wait controller to be stable */
udelay(100);
/* Start I2C transaction */
- temp = readb(base + FSL_I2C_I2CR);
+ temp = fsl_i2c_read_reg(i2c_fsl, FSL_I2C_I2CR);
temp |= I2CR_MSTA;
- writeb(temp, base + FSL_I2C_I2CR);
+ fsl_i2c_write_reg(temp, i2c_fsl, FSL_I2C_I2CR);
result = i2c_fsl_bus_busy(adapter, 1);
if (result) {
@@ -246,7 +323,7 @@ static int i2c_fsl_start(struct i2c_adapter *adapter)
i2c_fsl->stopped = 0;
temp |= I2CR_MTX | I2CR_TXAK;
- writeb(temp, base + FSL_I2C_I2CR);
+ fsl_i2c_write_reg(temp, i2c_fsl, FSL_I2C_I2CR);
return result;
}
@@ -254,14 +331,13 @@ static int i2c_fsl_start(struct i2c_adapter *adapter)
static void i2c_fsl_stop(struct i2c_adapter *adapter)
{
struct fsl_i2c_struct *i2c_fsl = to_fsl_i2c_struct(adapter);
- void __iomem *base = i2c_fsl->base;
unsigned int temp = 0;
if (!i2c_fsl->stopped) {
/* Stop I2C transaction */
- temp = readb(base + FSL_I2C_I2CR);
+ temp = fsl_i2c_read_reg(i2c_fsl, FSL_I2C_I2CR);
temp &= ~(I2CR_MSTA | I2CR_MTX);
- writeb(temp, base + FSL_I2C_I2CR);
+ fsl_i2c_write_reg(temp, i2c_fsl, FSL_I2C_I2CR);
/* wait for the stop condition to be send, otherwise the i2c
* controller is disabled before the STOP is sent completely */
i2c_fsl->stopped = i2c_fsl_bus_busy(adapter, 0) ? 0 : 1;
@@ -273,14 +349,14 @@ static void i2c_fsl_stop(struct i2c_adapter *adapter)
}
/* Disable I2C controller, and force our state to stopped */
- writeb(0, base + FSL_I2C_I2CR);
+ temp = i2c_fsl->hwdata->i2cr_ien_opcode ^ I2CR_IEN,
+ fsl_i2c_write_reg(temp, i2c_fsl, FSL_I2C_I2CR);
}
#ifdef CONFIG_PPC
static void i2c_fsl_set_clk(struct fsl_i2c_struct *i2c_fsl,
unsigned int rate)
{
- void __iomem *base;
unsigned int i2c_clk;
unsigned short divider;
/*
@@ -295,7 +371,6 @@ static void i2c_fsl_set_clk(struct fsl_i2c_struct *i2c_fsl,
unsigned long c_div, est_div;
fdr = 0x31; /* Default if no FDR found */
- base = i2c_fsl->base;
i2c_clk = fsl_get_i2c_freq();
divider = min((unsigned short)(i2c_clk / rate), (unsigned short) -1);
@@ -349,6 +424,7 @@ static void i2c_fsl_set_clk(struct fsl_i2c_struct *i2c_fsl,
static void i2c_fsl_set_clk(struct fsl_i2c_struct *i2c_fsl,
unsigned int rate)
{
+ struct fsl_i2c_clk_pair *i2c_clk_div = i2c_fsl->hwdata->clk_div;
unsigned int i2c_clk_rate;
unsigned int div;
int i;
@@ -356,16 +432,16 @@ static void i2c_fsl_set_clk(struct fsl_i2c_struct *i2c_fsl,
/* Divider value calculation */
i2c_clk_rate = clk_get_rate(i2c_fsl->clk);
div = (i2c_clk_rate + rate - 1) / rate;
- if (div < i2c_clk_div[0][0])
+ if (div < i2c_clk_div[0].div)
i = 0;
- else if (div > i2c_clk_div[ARRAY_SIZE(i2c_clk_div) - 1][0])
- i = ARRAY_SIZE(i2c_clk_div) - 1;
+ else if (div > i2c_clk_div[i2c_fsl->hwdata->ndivs - 1].div)
+ i = i2c_clk_div[i2c_fsl->hwdata->ndivs - 1].div - 1;
else
- for (i = 0; i2c_clk_div[i][0] < div; i++)
+ for (i = 0; i2c_clk_div[i].div < div; i++)
;
/* Store divider value */
- i2c_fsl->ifdr = i2c_clk_div[i][1];
+ i2c_fsl->ifdr = i2c_clk_div[i].val;
/*
* There dummy delay is calculated.
@@ -374,20 +450,19 @@ static void i2c_fsl_set_clk(struct fsl_i2c_struct *i2c_fsl,
* to fix chip hardware bug.
*/
i2c_fsl->disable_delay =
- (500000U * i2c_clk_div[i][0] + (i2c_clk_rate / 2) - 1) /
+ (500000U * i2c_clk_div[i].div + (i2c_clk_rate / 2) - 1) /
(i2c_clk_rate / 2);
dev_dbg(&i2c_fsl->adapter.dev, "<%s> I2C_CLK=%d, REQ DIV=%d\n",
__func__, i2c_clk_rate, div);
dev_dbg(&i2c_fsl->adapter.dev, "<%s> IFDR[IC]=0x%x, REAL DIV=%d\n",
- __func__, i2c_clk_div[i][1], i2c_clk_div[i][0]);
+ __func__, i2c_clk_div[i].val, i2c_clk_div[i].div);
}
#endif
static int i2c_fsl_write(struct i2c_adapter *adapter, struct i2c_msg *msgs)
{
struct fsl_i2c_struct *i2c_fsl = to_fsl_i2c_struct(adapter);
- void __iomem *base = i2c_fsl->base;
int i, result;
if ( !(msgs->flags & I2C_M_DATA_ONLY) ) {
@@ -396,7 +471,7 @@ static int i2c_fsl_write(struct i2c_adapter *adapter, struct i2c_msg *msgs)
__func__, msgs->addr << 1);
/* write slave address */
- writeb(msgs->addr << 1, base + FSL_I2C_I2DR);
+ fsl_i2c_write_reg(msgs->addr << 1, i2c_fsl, FSL_I2C_I2DR);
result = i2c_fsl_trx_complete(adapter);
if (result)
@@ -411,7 +486,7 @@ static int i2c_fsl_write(struct i2c_adapter *adapter, struct i2c_msg *msgs)
dev_dbg(&adapter->dev,
"<%s> write byte: B%d=0x%02X\n",
__func__, i, msgs->buf[i]);
- writeb(msgs->buf[i], base + FSL_I2C_I2DR);
+ fsl_i2c_write_reg(msgs->buf[i], i2c_fsl, FSL_I2C_I2DR);
result = i2c_fsl_trx_complete(adapter);
if (result)
@@ -426,12 +501,12 @@ static int i2c_fsl_write(struct i2c_adapter *adapter, struct i2c_msg *msgs)
static int i2c_fsl_read(struct i2c_adapter *adapter, struct i2c_msg *msgs)
{
struct fsl_i2c_struct *i2c_fsl = to_fsl_i2c_struct(adapter);
- void __iomem *base = i2c_fsl->base;
int i, result;
unsigned int temp;
/* clear IIF */
- writeb(0x0, base + FSL_I2C_I2SR);
+ fsl_i2c_write_reg(i2c_fsl->hwdata->i2sr_clr_opcode,
+ i2c_fsl, FSL_I2C_I2SR);
if ( !(msgs->flags & I2C_M_DATA_ONLY) ) {
dev_dbg(&adapter->dev,
@@ -439,7 +514,7 @@ static int i2c_fsl_read(struct i2c_adapter *adapter, struct i2c_msg *msgs)
__func__, (msgs->addr << 1) | 0x01);
/* write slave address */
- writeb((msgs->addr << 1) | 0x01, base + FSL_I2C_I2DR);
+ fsl_i2c_write_reg((msgs->addr << 1) | 0x01, i2c_fsl, FSL_I2C_I2DR);
result = i2c_fsl_trx_complete(adapter);
if (result)
@@ -450,13 +525,13 @@ static int i2c_fsl_read(struct i2c_adapter *adapter, struct i2c_msg *msgs)
}
/* setup bus to read data */
- temp = readb(base + FSL_I2C_I2CR);
+ temp = fsl_i2c_read_reg(i2c_fsl, FSL_I2C_I2CR);
temp &= ~I2CR_MTX;
if (msgs->len - 1)
temp &= ~I2CR_TXAK;
- writeb(temp, base + FSL_I2C_I2CR);
+ fsl_i2c_write_reg(temp, i2c_fsl, FSL_I2C_I2CR);
- readb(base + FSL_I2C_I2DR); /* dummy read */
+ fsl_i2c_read_reg(i2c_fsl, FSL_I2C_I2DR); /* dummy read */
/* read data */
for (i = 0; i < msgs->len; i++) {
@@ -469,9 +544,9 @@ static int i2c_fsl_read(struct i2c_adapter *adapter, struct i2c_msg *msgs)
* It must generate STOP before read I2DR to prevent
* controller from generating another clock cycle
*/
- temp = readb(base + FSL_I2C_I2CR);
+ temp = fsl_i2c_read_reg(i2c_fsl, FSL_I2C_I2CR);
temp &= ~(I2CR_MSTA | I2CR_MTX);
- writeb(temp, base + FSL_I2C_I2CR);
+ fsl_i2c_write_reg(temp, i2c_fsl, FSL_I2C_I2CR);
/*
* adding this delay helps on low bitrates
@@ -481,11 +556,11 @@ static int i2c_fsl_read(struct i2c_adapter *adapter, struct i2c_msg *msgs)
i2c_fsl_bus_busy(adapter, 0);
i2c_fsl->stopped = 1;
} else if (i == (msgs->len - 2)) {
- temp = readb(base + FSL_I2C_I2CR);
+ temp = fsl_i2c_read_reg(i2c_fsl, FSL_I2C_I2CR);
temp |= I2CR_TXAK;
- writeb(temp, base + FSL_I2C_I2CR);
+ fsl_i2c_write_reg(temp, i2c_fsl, FSL_I2C_I2CR);
}
- msgs->buf[i] = readb(base + FSL_I2C_I2DR);
+ msgs->buf[i] = fsl_i2c_read_reg(i2c_fsl, FSL_I2C_I2DR);
dev_dbg(&adapter->dev, "<%s> read byte: B%d=0x%02X\n",
__func__, i, msgs->buf[i]);
@@ -497,7 +572,6 @@ static int i2c_fsl_xfer(struct i2c_adapter *adapter,
struct i2c_msg *msgs, int num)
{
struct fsl_i2c_struct *i2c_fsl = to_fsl_i2c_struct(adapter);
- void __iomem *base = i2c_fsl->base;
unsigned int i, temp;
int result;
@@ -514,9 +588,9 @@ static int i2c_fsl_xfer(struct i2c_adapter *adapter,
/* read/write data */
for (i = 0; i < num; i++) {
if (i && !(msgs[i].flags & I2C_M_DATA_ONLY)) {
- temp = readb(base + FSL_I2C_I2CR);
+ temp = fsl_i2c_read_reg(i2c_fsl, FSL_I2C_I2CR);
temp |= I2CR_RSTA;
- writeb(temp, base + FSL_I2C_I2CR);
+ fsl_i2c_write_reg(temp, i2c_fsl, FSL_I2C_I2CR);
result = i2c_fsl_bus_busy(adapter, 1);
if (result)
@@ -600,6 +674,13 @@ static int __init i2c_fsl_probe(struct device_d *pdev)
goto fail;
}
#endif
+
+ i2c_fsl->hwdata = of_device_get_match_data(pdev);
+ if (!i2c_fsl->hwdata) {
+ ret = -EINVAL;
+ goto fail;
+ }
+
/* Setup i2c_fsl driver structure */
i2c_fsl->adapter.master_xfer = i2c_fsl_xfer;
i2c_fsl->adapter.nr = pdev->id;
@@ -623,8 +704,9 @@ static int __init i2c_fsl_probe(struct device_d *pdev)
i2c_fsl_set_clk(i2c_fsl, FSL_I2C_BIT_RATE);
/* Set up chip registers to defaults */
- writeb(0, i2c_fsl->base + FSL_I2C_I2CR);
- writeb(0, i2c_fsl->base + FSL_I2C_I2SR);
+ fsl_i2c_write_reg(i2c_fsl->hwdata->i2cr_ien_opcode ^ I2CR_IEN,
+ i2c_fsl, FSL_I2C_I2CR);
+ fsl_i2c_write_reg(i2c_fsl->hwdata->i2sr_clr_opcode, i2c_fsl, FSL_I2C_I2SR);
/* Add I2C adapter */
ret = i2c_add_numbered_adapter(&i2c_fsl->adapter);
@@ -640,17 +722,33 @@ fail:
return ret;
}
+static const struct fsl_i2c_hwdata imx21_i2c_hwdata = {
+ .regshift = IMX_I2C_REGSHIFT,
+ .clk_div = imx_i2c_clk_div,
+ .ndivs = ARRAY_SIZE(imx_i2c_clk_div),
+ .i2sr_clr_opcode = I2SR_CLR_OPCODE_W0C,
+ .i2cr_ien_opcode = I2CR_IEN_OPCODE_1,
+};
+
+static const struct fsl_i2c_hwdata vf610_i2c_hwdata = {
+ .regshift = VF610_I2C_REGSHIFT,
+ .clk_div = vf610_i2c_clk_div,
+ .ndivs = ARRAY_SIZE(vf610_i2c_clk_div),
+ .i2sr_clr_opcode = I2SR_CLR_OPCODE_W1C,
+ .i2cr_ien_opcode = I2CR_IEN_OPCODE_0,
+};
+
static __maybe_unused struct of_device_id imx_i2c_dt_ids[] = {
- {
- .compatible = "fsl,imx21-i2c",
- }, {
- /* sentinel */
- }
+ { .compatible = "fsl,imx21-i2c", .data = &imx21_i2c_hwdata, },
+ { .compatible = "fsl,vf610-i2c", .data = &vf610_i2c_hwdata, },
+ { /* sentinel */ }
};
static struct driver_d i2c_fsl_driver = {
.probe = i2c_fsl_probe,
.name = DRIVER_NAME,
+#ifndef CONFIG_PPC
.of_compatible = DRV_OF_COMPAT(imx_i2c_dt_ids),
+#endif
};
coredevice_platform_driver(i2c_fsl_driver);
diff --git a/drivers/mci/imx-esdhc.c b/drivers/mci/imx-esdhc.c
index 41f0562e3c..951ac4501b 100644
--- a/drivers/mci/imx-esdhc.c
+++ b/drivers/mci/imx-esdhc.c
@@ -35,28 +35,81 @@
#include <mach/generic.h>
#include <mach/esdhc.h>
#include <gpio.h>
+#include <of_device.h>
#include "sdhci.h"
#include "imx-esdhc.h"
+/*
+ * The CMDTYPE of the CMD register (offset 0xE) should be set to
+ * "11" when the STOP CMD12 is issued on imx53 to abort one
+ * open ended multi-blk IO. Otherwise the TC INT wouldn't
+ * be generated.
+ * In exact block transfer, the controller doesn't complete the
+ * operations automatically as required at the end of the
+ * transfer and remains on hold if the abort command is not sent.
+ * As a result, the TC flag is not asserted and SW received timeout
+ * exeception. Bit1 of Vendor Spec registor is used to fix it.
+ */
+#define ESDHC_FLAG_MULTIBLK_NO_INT BIT(1)
+/*
+ * The flag enables the workaround for ESDHC errata ENGcm07207 which
+ * affects i.MX25 and i.MX35.
+ */
+#define ESDHC_FLAG_ENGCM07207 BIT(2)
+/*
+ * The flag tells that the ESDHC controller is an USDHC block that is
+ * integrated on the i.MX6 series.
+ */
+#define ESDHC_FLAG_USDHC BIT(3)
+/* The IP supports manual tuning process */
+#define ESDHC_FLAG_MAN_TUNING BIT(4)
+/* The IP supports standard tuning process */
+#define ESDHC_FLAG_STD_TUNING BIT(5)
+/* The IP has SDHCI_CAPABILITIES_1 register */
+#define ESDHC_FLAG_HAVE_CAP1 BIT(6)
+/*
+ * The IP has errata ERR004536
+ * uSDHC: ADMA Length Mismatch Error occurs if the AHB read access is slow,
+ * when reading data from the card
+ */
+#define ESDHC_FLAG_ERR004536 BIT(7)
+/* The IP supports HS200 mode */
+#define ESDHC_FLAG_HS200 BIT(8)
+/* The IP supports HS400 mode */
+#define ESDHC_FLAG_HS400 BIT(9)
+
+
#define IMX_SDHCI_WML 0x44
#define IMX_SDHCI_MIXCTRL 0x48
#define IMX_SDHCI_DLL_CTRL 0x60
#define IMX_SDHCI_MIX_CTRL_FBCLK_SEL (BIT(25))
+struct esdhc_soc_data {
+ u32 flags;
+};
+
struct fsl_esdhc_host {
struct mci_host mci;
void __iomem *regs;
struct device_d *dev;
struct clk *clk;
+ const struct esdhc_soc_data *socdata;
};
#define to_fsl_esdhc(mci) container_of(mci, struct fsl_esdhc_host, mci)
#define SDHCI_CMD_ABORTCMD (0xC0 << 16)
+static inline int esdhc_is_usdhc(struct fsl_esdhc_host *data)
+{
+ return !!(data->socdata->flags & ESDHC_FLAG_USDHC);
+}
+
+
/* Return the XFERTYP flags for a given command and data packet */
-static u32 esdhc_xfertyp(struct mci_cmd *cmd, struct mci_data *data)
+static u32 esdhc_xfertyp(struct fsl_esdhc_host *host,
+ struct mci_cmd *cmd, struct mci_data *data)
{
u32 xfertyp = 0;
@@ -85,8 +138,8 @@ static u32 esdhc_xfertyp(struct mci_cmd *cmd, struct mci_data *data)
xfertyp |= COMMAND_RSPTYP_48_BUSY;
else if (cmd->resp_type & MMC_RSP_PRESENT)
xfertyp |= COMMAND_RSPTYP_48;
- if ((cpu_is_mx50() || cpu_is_mx51() || cpu_is_mx53()) &&
- cmd->cmdidx == MMC_CMD_STOP_TRANSMISSION)
+ if ((host->socdata->flags & ESDHC_FLAG_MULTIBLK_NO_INT) &&
+ (cmd->cmdidx == MMC_CMD_STOP_TRANSMISSION))
xfertyp |= SDHCI_CMD_ABORTCMD;
return COMMAND_CMD(cmd->cmdidx) | xfertyp;
@@ -273,12 +326,12 @@ esdhc_send_cmd(struct mci_host *mci, struct mci_cmd *cmd, struct mci_data *data)
}
/* Figure out the transfer arguments */
- xfertyp = esdhc_xfertyp(cmd, data);
+ xfertyp = esdhc_xfertyp(host, cmd, data);
/* Send the command */
esdhc_write32(regs + SDHCI_ARGUMENT, cmd->cmdarg);
- if (cpu_is_mx6()) {
+ if (esdhc_is_usdhc(host)) {
/* write lower-half of xfertyp to mixctrl */
mixctrl = xfertyp & 0xFFFF;
/* Keep the bits 22-25 of the register as is */
@@ -525,7 +578,7 @@ static int esdhc_reset(struct fsl_esdhc_host *host)
SYSCTL_RSTA);
/* extra register reset for i.MX6 Solo/DualLite */
- if (cpu_is_mx6()) {
+ if (esdhc_is_usdhc(host)) {
/* reset bit FBCLK_SEL */
val = esdhc_read32(regs + IMX_SDHCI_MIXCTRL);
val &= ~IMX_SDHCI_MIX_CTRL_FBCLK_SEL;
@@ -570,7 +623,11 @@ static int fsl_esdhc_probe(struct device_d *dev)
host = xzalloc(sizeof(*host));
mci = &host->mci;
- host->clk = clk_get(dev, NULL);
+ host->socdata = of_device_get_match_data(dev);
+ if (!host->socdata)
+ return -EINVAL;
+
+ host->clk = clk_get(dev, "per");
if (IS_ERR(host->clk))
return PTR_ERR(host->clk);
@@ -634,24 +691,48 @@ static int fsl_esdhc_probe(struct device_d *dev)
return mci_register(&host->mci);
}
+static struct esdhc_soc_data esdhc_imx25_data = {
+ .flags = ESDHC_FLAG_ENGCM07207,
+};
+
+static struct esdhc_soc_data esdhc_imx50_data = {
+ .flags = ESDHC_FLAG_MULTIBLK_NO_INT,
+ /* .flags = 0, */
+};
+
+static struct esdhc_soc_data esdhc_imx51_data = {
+ .flags = ESDHC_FLAG_MULTIBLK_NO_INT,
+ /* .flags = 0, */
+};
+
+static struct esdhc_soc_data esdhc_imx53_data = {
+ .flags = ESDHC_FLAG_MULTIBLK_NO_INT,
+};
+
+static struct esdhc_soc_data usdhc_imx6q_data = {
+ .flags = ESDHC_FLAG_USDHC | ESDHC_FLAG_MAN_TUNING,
+};
+
+static struct esdhc_soc_data usdhc_imx6sl_data = {
+ .flags = ESDHC_FLAG_USDHC | ESDHC_FLAG_STD_TUNING
+ | ESDHC_FLAG_HAVE_CAP1 | ESDHC_FLAG_ERR004536
+ | ESDHC_FLAG_HS200,
+};
+
+static struct esdhc_soc_data usdhc_imx6sx_data = {
+ .flags = ESDHC_FLAG_USDHC | ESDHC_FLAG_STD_TUNING
+ | ESDHC_FLAG_HAVE_CAP1 | ESDHC_FLAG_HS200,
+};
+
static __maybe_unused struct of_device_id fsl_esdhc_compatible[] = {
- {
- .compatible = "fsl,imx25-esdhc",
- }, {
- .compatible = "fsl,imx50-esdhc",
- }, {
- .compatible = "fsl,imx51-esdhc",
- }, {
- .compatible = "fsl,imx53-esdhc",
- }, {
- .compatible = "fsl,imx6q-usdhc",
- }, {
- .compatible = "fsl,imx6sl-usdhc",
- }, {
- .compatible = "fsl,imx6sx-usdhc",
- }, {
- /* sentinel */
- }
+ { .compatible = "fsl,imx25-esdhc", .data = &esdhc_imx25_data },
+ { .compatible = "fsl,imx50-esdhc", .data = &esdhc_imx50_data },
+ { .compatible = "fsl,imx51-esdhc", .data = &esdhc_imx51_data },
+ { .compatible = "fsl,imx53-esdhc", .data = &esdhc_imx53_data },
+ { .compatible = "fsl,imx6q-usdhc", .data = &usdhc_imx6q_data },
+ { .compatible = "fsl,imx6sl-usdhc", .data = &usdhc_imx6sl_data },
+ { .compatible = "fsl,imx6sx-usdhc", .data = &usdhc_imx6sx_data },
+ { /* sentinel */ }
};
static struct driver_d fsl_esdhc_driver = {
diff --git a/drivers/net/fec_imx.c b/drivers/net/fec_imx.c
index 8bc7c2993a..e2b25fe375 100644
--- a/drivers/net/fec_imx.c
+++ b/drivers/net/fec_imx.c
@@ -51,7 +51,7 @@ static int fec_miibus_read(struct mii_bus *bus, int phyAddr, int regAddr)
uint32_t phy; /* convenient holder for the PHY */
uint64_t start;
- writel(((clk_get_rate(fec->clk) >> 20) / 5) << 1,
+ writel(((clk_get_rate(fec->clk[FEC_CLK_IPG]) >> 20) / 5) << 1,
fec->regs + FEC_MII_SPEED);
/*
* reading from any PHY's register is done by properly
@@ -94,7 +94,7 @@ static int fec_miibus_write(struct mii_bus *bus, int phyAddr,
uint32_t phy; /* convenient holder for the PHY */
uint64_t start;
- writel(((clk_get_rate(fec->clk) >> 20) / 5) << 1,
+ writel(((clk_get_rate(fec->clk[FEC_CLK_IPG]) >> 20) / 5) << 1,
fec->regs + FEC_MII_SPEED);
reg = regAddr << FEC_MII_DATA_RA_SHIFT;
@@ -287,7 +287,7 @@ static int fec_init(struct eth_device *dev)
* Set MII_SPEED = (1/(mii_speed * 2)) * System Clock
* and do not drop the Preamble.
*/
- writel(((clk_get_rate(fec->clk) >> 20) / 5) << 1,
+ writel(((clk_get_rate(fec->clk[FEC_CLK_IPG]) >> 20) / 5) << 1,
fec->regs + FEC_MII_SPEED);
if (fec->interface == PHY_INTERFACE_MODE_RMII) {
@@ -651,6 +651,59 @@ static int fec_probe_dt(struct device_d *dev, struct fec_priv *fec)
return -ENODEV;
}
#endif
+
+static int fec_clk_enable(struct fec_priv *fec)
+{
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(fec->clk); i++) {
+ const int err = clk_enable(fec->clk[i]);
+ if (err < 0)
+ return err;
+ }
+
+ return 0;
+}
+
+static void fec_clk_disable(struct fec_priv *fec)
+{
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(fec->clk); i++) {
+ if (!IS_ERR_OR_NULL(fec->clk[i]))
+ clk_disable(fec->clk[i]);
+ }
+}
+
+static void fec_clk_put(struct fec_priv *fec)
+{
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(fec->clk); i++) {
+ if (!IS_ERR_OR_NULL(fec->clk[i]))
+ clk_put(fec->clk[i]);
+ }
+}
+
+static int fec_clk_get(struct fec_priv *fec)
+{
+ int i, err = 0;
+ static const char *clk_names[ARRAY_SIZE(fec->clk)] = {
+ "ipg", "ahb", "ptp"
+ };
+
+ for (i = 0; i < ARRAY_SIZE(fec->clk); i++) {
+ fec->clk[i] = clk_get(fec->edev.parent, clk_names[i]);
+ if (IS_ERR(fec->clk[i])) {
+ err = PTR_ERR(fec->clk[i]);
+ fec_clk_put(fec);
+ break;
+ }
+ }
+
+ return err;
+}
+
static int fec_probe(struct device_d *dev)
{
struct resource *iores;
@@ -681,13 +734,11 @@ static int fec_probe(struct device_d *dev)
edev->set_ethaddr = fec_set_hwaddr;
edev->parent = dev;
- fec->clk = clk_get(dev, NULL);
- if (IS_ERR(fec->clk)) {
- ret = PTR_ERR(fec->clk);
+ ret = fec_clk_get(fec);
+ if (ret < 0)
goto err_free;
- }
- ret = clk_enable(fec->clk);
+ ret = fec_clk_enable(fec);
if (ret < 0)
goto put_clk;
@@ -787,9 +838,9 @@ free_gpio:
release_res:
release_region(iores);
disable_clk:
- clk_disable(fec->clk);
+ fec_clk_disable(fec);
put_clk:
- clk_put(fec->clk);
+ fec_clk_put(fec);
err_free:
free(fec);
return ret;
@@ -819,6 +870,9 @@ static __maybe_unused struct of_device_id imx_fec_dt_ids[] = {
.compatible = "fsl,imx6sx-fec",
.data = (void *)FEC_TYPE_IMX6,
}, {
+ .compatible = "fsl,mvf600-fec",
+ .data = (void *)FEC_TYPE_IMX6,
+ }, {
/* sentinel */
}
};
diff --git a/drivers/net/fec_imx.h b/drivers/net/fec_imx.h
index 1947e60f69..85d51bad60 100644
--- a/drivers/net/fec_imx.h
+++ b/drivers/net/fec_imx.h
@@ -129,6 +129,14 @@ enum fec_type {
FEC_TYPE_IMX6,
};
+enum fec_clock {
+ FEC_CLK_IPG,
+ FEC_CLK_AHB,
+ FEC_CLK_PTP,
+
+ FEC_CLK_NUM
+};
+
/**
* @brief i.MX27-FEC private structure
*/
@@ -144,7 +152,7 @@ struct fec_priv {
u32 phy_flags;
struct mii_bus miibus;
void (*phy_init)(struct phy_device *dev);
- struct clk *clk;
+ struct clk *clk[FEC_CLK_NUM];
enum fec_type type;
};
diff --git a/drivers/serial/Kconfig b/drivers/serial/Kconfig
index b112d7ee04..4eab437ea5 100644
--- a/drivers/serial/Kconfig
+++ b/drivers/serial/Kconfig
@@ -137,4 +137,9 @@ config DRIVER_SERIAL_DIGIC
bool "Canon DIGIC serial driver"
depends on ARCH_DIGIC
+config DRIVER_SERIAL_LPUART
+ depends on ARCH_VF610
+ default y
+ bool "LPUART serial driver"
+
endmenu
diff --git a/drivers/serial/Makefile b/drivers/serial/Makefile
index 189e777777..7d1bae195f 100644
--- a/drivers/serial/Makefile
+++ b/drivers/serial/Makefile
@@ -20,3 +20,4 @@ obj-$(CONFIG_DRIVER_SERIAL_AUART) += serial_auart.o
obj-$(CONFIG_DRIVER_SERIAL_CADENCE) += serial_cadence.o
obj-$(CONFIG_DRIVER_SERIAL_EFI_STDIO) += efi-stdio.o
obj-$(CONFIG_DRIVER_SERIAL_DIGIC) += serial_digic.o
+obj-$(CONFIG_DRIVER_SERIAL_LPUART) += serial_lpuart.o
diff --git a/drivers/serial/serial_lpuart.c b/drivers/serial/serial_lpuart.c
new file mode 100644
index 0000000000..52fb6d39c0
--- /dev/null
+++ b/drivers/serial/serial_lpuart.c
@@ -0,0 +1,217 @@
+/*
+ * Copyright (c) 2016 Zodiac Inflight Innovation
+ * Author: Andrey Smirnov <andrew.smirnov@gmail.com>
+ *
+ * Based on analogous driver from U-Boot
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2
+ * as published by the Free Software Foundation.
+ *
+ * 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 <common.h>
+#include <driver.h>
+#include <init.h>
+#include <malloc.h>
+#include <notifier.h>
+#include <io.h>
+#include <of.h>
+#include <linux/err.h>
+#include <linux/clk.h>
+#include <serial/lpuart.h>
+
+struct lpuart {
+ struct console_device cdev;
+ int baudrate;
+ int dte_mode;
+ struct notifier_block notify;
+ struct resource *io;
+ void __iomem *base;
+ struct clk *clk;
+};
+
+static struct lpuart *cdev_to_lpuart(struct console_device *cdev)
+{
+ return container_of(cdev, struct lpuart, cdev);
+}
+
+static struct lpuart *nb_to_lpuart(struct notifier_block *nb)
+{
+ return container_of(nb, struct lpuart, notify);
+}
+
+static void lpuart_enable(struct lpuart *lpuart, bool on)
+{
+ u8 ctrl;
+
+ ctrl = readb(lpuart->base + UARTCR2);
+ if (on)
+ ctrl |= UARTCR2_TE | UARTCR2_RE;
+ else
+ ctrl &= ~(UARTCR2_TE | UARTCR2_RE);
+ writeb(ctrl, lpuart->base + UARTCR2);
+}
+
+static int lpuart_serial_setbaudrate(struct console_device *cdev,
+ int baudrate)
+{
+ struct lpuart *lpuart = cdev_to_lpuart(cdev);
+
+ lpuart_enable(lpuart, false);
+
+ lpuart_setbrg(lpuart->base,
+ clk_get_rate(lpuart->clk),
+ baudrate);
+
+ lpuart_enable(lpuart, true);
+
+ lpuart->baudrate = baudrate;
+
+ return 0;
+}
+
+static int lpuart_serial_getc(struct console_device *cdev)
+{
+ bool ready;
+ struct lpuart *lpuart = cdev_to_lpuart(cdev);
+
+ do {
+ const u8 sr1 = readb(lpuart->base + UARTSR1);
+ ready = !!(sr1 & (UARTSR1_OR | UARTSR1_RDRF));
+ } while (!ready);
+
+ return readb(lpuart->base + UARTDR);
+}
+
+static void lpuart_serial_putc(struct console_device *cdev, char c)
+{
+ lpuart_putc(cdev_to_lpuart(cdev)->base, c);
+}
+
+/* Test whether a character is in the RX buffer */
+static int lpuart_serial_tstc(struct console_device *cdev)
+{
+ return !!readb(cdev_to_lpuart(cdev)->base + UARTRCFIFO);
+}
+
+static void lpuart_serial_flush(struct console_device *cdev)
+{
+ bool tx_empty;
+ struct lpuart *lpuart = cdev_to_lpuart(cdev);
+
+ do {
+ const u8 sr1 = readb(lpuart->base + UARTSR1);
+ tx_empty = !!(sr1 & UARTSR1_TDRE);
+ } while (!tx_empty);
+}
+
+static int lpuart_clocksource_clock_change(struct notifier_block *nb,
+ unsigned long event, void *data)
+{
+ struct lpuart *lpuart = nb_to_lpuart(nb);
+
+ return lpuart_serial_setbaudrate(&lpuart->cdev, lpuart->baudrate);
+}
+
+static int lpuart_serial_probe(struct device_d *dev)
+{
+ int ret;
+ struct console_device *cdev;
+ struct lpuart *lpuart;
+ const char *devname;
+
+ lpuart = xzalloc(sizeof(*lpuart));
+ cdev = &lpuart->cdev;
+ dev->priv = lpuart;
+
+ lpuart->io = dev_request_mem_resource(dev, 0);
+ if (IS_ERR(lpuart->io)) {
+ ret = PTR_ERR(lpuart->io);
+ goto err_free;
+ }
+ lpuart->base = IOMEM(lpuart->io->start);
+
+ lpuart->clk = clk_get(dev, NULL);
+ if (IS_ERR(lpuart->clk)) {
+ ret = PTR_ERR(lpuart->clk);
+ dev_err(dev, "Failed to get UART clock %d\n", ret);
+ goto io_release;
+ }
+
+ ret = clk_enable(lpuart->clk);
+ if (ret) {
+ dev_err(dev, "Failed to enable UART clock %d\n", ret);
+ goto io_release;
+ }
+
+ cdev->dev = dev;
+ cdev->tstc = lpuart_serial_tstc;
+ cdev->putc = lpuart_serial_putc;
+ cdev->getc = lpuart_serial_getc;
+ cdev->flush = lpuart_serial_flush;
+ cdev->setbrg = lpuart_serial_setbaudrate;
+
+ if (dev->device_node) {
+ devname = of_alias_get(dev->device_node);
+ if (devname) {
+ cdev->devname = xstrdup(devname);
+ cdev->devid = DEVICE_ID_SINGLE;
+ }
+ }
+
+ cdev->linux_console_name = "ttyLP";
+
+ lpuart_setup_with_fifo(lpuart->base,
+ clk_get_rate(lpuart->clk),
+ 15);
+
+ ret = console_register(cdev);
+ if (!ret) {
+ lpuart->notify.notifier_call = lpuart_clocksource_clock_change;
+ clock_register_client(&lpuart->notify);
+
+ return 0;
+ }
+
+ clk_put(lpuart->clk);
+io_release:
+ release_region(lpuart->io);
+err_free:
+ free(lpuart);
+
+ return ret;
+}
+
+static void lpuart_serial_remove(struct device_d *dev)
+{
+ struct lpuart *lpuart = dev->priv;
+
+ lpuart_serial_flush(&lpuart->cdev);
+ console_unregister(&lpuart->cdev);
+ release_region(lpuart->io);
+ clk_put(lpuart->clk);
+
+ free(lpuart);
+}
+
+static struct of_device_id lpuart_serial_dt_ids[] = {
+ { .compatible = "fsl,vf610-lpuart" },
+ {}
+};
+
+static struct driver_d lpuart_serial_driver = {
+ .name = "lpuart-serial",
+ .probe = lpuart_serial_probe,
+ .remove = lpuart_serial_remove,
+ .of_compatible = DRV_OF_COMPAT(lpuart_serial_dt_ids),
+};
+console_platform_driver(lpuart_serial_driver);
diff --git a/include/linux/clk/clk-conf.h b/include/linux/clk/clk-conf.h
new file mode 100644
index 0000000000..8f4382e6c6
--- /dev/null
+++ b/include/linux/clk/clk-conf.h
@@ -0,0 +1,17 @@
+/*
+ * Copyright (C) 2014 Samsung Electronics Co., Ltd.
+ * Sylwester Nawrocki <s.nawrocki@samsung.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#if defined(CONFIG_OFTREE) && defined(CONFIG_COMMON_CLK_OF_PROVIDER)
+
+#include <linux/types.h>
+
+struct device_node;
+int of_clk_set_defaults(struct device_node *node, bool clk_supplier);
+
+#endif