summaryrefslogtreecommitdiffstats
path: root/drivers
diff options
context:
space:
mode:
Diffstat (limited to 'drivers')
-rw-r--r--drivers/clk/Kconfig3
-rw-r--r--drivers/clk/Makefile2
-rw-r--r--drivers/clk/clk-divider.c98
-rw-r--r--drivers/clk/clk-fixed-factor.c63
-rw-r--r--drivers/clk/clk-fixed.c55
-rw-r--r--drivers/clk/clk-mux.c77
-rw-r--r--drivers/clk/clk.c224
-rw-r--r--drivers/clk/clkdev.c55
-rw-r--r--drivers/i2c/busses/i2c-imx.c23
-rw-r--r--drivers/mci/imx-esdhc.c16
-rw-r--r--drivers/mci/imx.c15
-rw-r--r--drivers/net/fec_imx.c34
-rw-r--r--drivers/net/fec_imx.h1
-rw-r--r--drivers/serial/serial_imx.c26
-rw-r--r--drivers/spi/imx_spi.c22
-rw-r--r--drivers/video/imx-ipu-fb.c10
-rw-r--r--drivers/video/imx.c10
17 files changed, 708 insertions, 26 deletions
diff --git a/drivers/clk/Kconfig b/drivers/clk/Kconfig
index 4168c8896e..66c1c465e8 100644
--- a/drivers/clk/Kconfig
+++ b/drivers/clk/Kconfig
@@ -2,3 +2,6 @@
config CLKDEV_LOOKUP
bool
select HAVE_CLK
+
+config COMMON_CLK
+ bool
diff --git a/drivers/clk/Makefile b/drivers/clk/Makefile
index 07613fa172..39a75a4e4a 100644
--- a/drivers/clk/Makefile
+++ b/drivers/clk/Makefile
@@ -1,2 +1,2 @@
-
+obj-$(CONFIG_COMMON_CLK) += clk.o clk-fixed.o clk-divider.o clk-fixed-factor.o clk-mux.o
obj-$(CONFIG_CLKDEV_LOOKUP) += clkdev.o
diff --git a/drivers/clk/clk-divider.c b/drivers/clk/clk-divider.c
new file mode 100644
index 0000000000..58a7ea564c
--- /dev/null
+++ b/drivers/clk/clk-divider.c
@@ -0,0 +1,98 @@
+/*
+ * clk-divider.c - generic barebox clock support. Based on Linux clk support
+ *
+ * Copyright (c) 2012 Sascha Hauer <s.hauer@pengutronix.de>, Pengutronix
+ *
+ * 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 <io.h>
+#include <malloc.h>
+#include <linux/clk.h>
+#include <linux/err.h>
+
+struct clk_divider {
+ struct clk clk;
+ u8 shift;
+ u8 width;
+ void __iomem *reg;
+ const char *parent;
+};
+
+static int clk_divider_set_rate(struct clk *clk, unsigned long rate,
+ unsigned long parent_rate)
+{
+ struct clk_divider *div = container_of(clk, struct clk_divider, clk);
+ unsigned int val, divval;
+
+ if (rate > parent_rate)
+ rate = parent_rate;
+ if (!rate)
+ rate = 1;
+
+ divval = DIV_ROUND_UP(parent_rate, rate);
+
+ if (divval > (1 << div->width))
+ divval = 1 << (div->width);
+
+ divval--;
+
+ val = readl(div->reg);
+ val &= ~(((1 << div->width) - 1) << div->shift);
+ val |= divval << div->shift;
+ writel(val, div->reg);
+
+ return 0;
+}
+
+static unsigned long clk_divider_recalc_rate(struct clk *clk,
+ unsigned long parent_rate)
+{
+ struct clk_divider *div = container_of(clk, struct clk_divider, clk);
+ unsigned int val;
+
+ val = readl(div->reg) >> div->shift;
+ val &= (1 << div->width) - 1;
+
+ val++;
+
+ return parent_rate / val;
+}
+
+struct clk_ops clk_divider_ops = {
+ .set_rate = clk_divider_set_rate,
+ .recalc_rate = clk_divider_recalc_rate,
+};
+
+struct clk *clk_divider(const char *name, const char *parent,
+ void __iomem *reg, u8 shift, u8 width)
+{
+ struct clk_divider *div = xzalloc(sizeof(*div));
+ int ret;
+
+ div->shift = shift;
+ div->reg = reg;
+ div->width = width;
+ div->parent = parent;
+ div->clk.ops = &clk_divider_ops;
+ div->clk.name = name;
+ div->clk.parent_names = &div->parent;
+ div->clk.num_parents = 1;
+
+ ret = clk_register(&div->clk);
+ if (ret) {
+ free(div);
+ return ERR_PTR(ret);
+ }
+
+ return &div->clk;
+}
diff --git a/drivers/clk/clk-fixed-factor.c b/drivers/clk/clk-fixed-factor.c
new file mode 100644
index 0000000000..52e7c16c49
--- /dev/null
+++ b/drivers/clk/clk-fixed-factor.c
@@ -0,0 +1,63 @@
+/*
+ * clk-fixed-factor.c - generic barebox clock support. Based on Linux clk support
+ *
+ * Copyright (c) 2012 Sascha Hauer <s.hauer@pengutronix.de>, Pengutronix
+ *
+ * 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 <io.h>
+#include <malloc.h>
+#include <linux/clk.h>
+#include <linux/err.h>
+
+struct clk_fixed_factor {
+ struct clk clk;
+ int mult;
+ int div;
+ const char *parent;
+};
+
+static unsigned long clk_fixed_factor_recalc_rate(struct clk *clk,
+ unsigned long parent_rate)
+{
+ struct clk_fixed_factor *f = container_of(clk, struct clk_fixed_factor, clk);
+
+ return (parent_rate / f->div) * f->mult;
+}
+
+struct clk_ops clk_fixed_factor_ops = {
+ .recalc_rate = clk_fixed_factor_recalc_rate,
+};
+
+struct clk *clk_fixed_factor(const char *name,
+ const char *parent, unsigned int mult, unsigned int div)
+{
+ struct clk_fixed_factor *f = xzalloc(sizeof(*f));
+ int ret;
+
+ f->mult = mult;
+ f->div = div;
+ f->parent = parent;
+ f->clk.ops = &clk_fixed_factor_ops;
+ f->clk.name = name;
+ f->clk.parent_names = &f->parent;
+ f->clk.num_parents = 1;
+
+ ret = clk_register(&f->clk);
+ if (ret) {
+ free(f);
+ return ERR_PTR(ret);
+ }
+
+ return &f->clk;
+}
diff --git a/drivers/clk/clk-fixed.c b/drivers/clk/clk-fixed.c
new file mode 100644
index 0000000000..fa89cb2840
--- /dev/null
+++ b/drivers/clk/clk-fixed.c
@@ -0,0 +1,55 @@
+/*
+ * clk-fixed.c - generic barebox clock support. Based on Linux clk support
+ *
+ * Copyright (c) 2012 Sascha Hauer <s.hauer@pengutronix.de>, Pengutronix
+ *
+ * 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 <malloc.h>
+#include <linux/clk.h>
+#include <linux/err.h>
+
+struct clk_fixed {
+ struct clk clk;
+ unsigned long rate;
+};
+
+static unsigned long clk_fixed_recalc_rate(struct clk *clk,
+ unsigned long parent_rate)
+{
+ struct clk_fixed *fix = container_of(clk, struct clk_fixed, clk);
+
+ return fix->rate;
+}
+
+struct clk_ops clk_fixed_ops = {
+ .recalc_rate = clk_fixed_recalc_rate,
+};
+
+struct clk *clk_fixed(const char *name, int rate)
+{
+ struct clk_fixed *fix = xzalloc(sizeof *fix);
+ int ret;
+
+ fix->rate = rate;
+ fix->clk.ops = &clk_fixed_ops;
+ fix->clk.name = name;
+
+ ret = clk_register(&fix->clk);
+ if (ret) {
+ free(fix);
+ return ERR_PTR(ret);
+ }
+
+ return &fix->clk;
+}
diff --git a/drivers/clk/clk-mux.c b/drivers/clk/clk-mux.c
new file mode 100644
index 0000000000..cb5f1a1a7b
--- /dev/null
+++ b/drivers/clk/clk-mux.c
@@ -0,0 +1,77 @@
+/*
+ * clk-mux.c - generic barebox clock support. Based on Linux clk support
+ *
+ * Copyright (c) 2012 Sascha Hauer <s.hauer@pengutronix.de>, Pengutronix
+ *
+ * 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 <io.h>
+#include <malloc.h>
+#include <linux/clk.h>
+#include <linux/err.h>
+
+struct clk_mux {
+ struct clk clk;
+ void __iomem *reg;
+ int shift;
+ int width;
+};
+
+static int clk_mux_get_parent(struct clk *clk)
+{
+ struct clk_mux *m = container_of(clk, struct clk_mux, clk);
+ int idx = readl(m->reg) >> m->shift & ((1 << m->width) - 1);
+
+ return idx;
+}
+
+static int clk_mux_set_parent(struct clk *clk, u8 idx)
+{
+ struct clk_mux *m = container_of(clk, struct clk_mux, clk);
+ u32 val;
+
+ val = readl(m->reg);
+ val &= ~(((1 << m->width) - 1) << m->shift);
+ val |= idx << m->shift;
+ writel(val, m->reg);
+
+ return 0;
+}
+
+struct clk_ops clk_mux_ops = {
+ .get_parent = clk_mux_get_parent,
+ .set_parent = clk_mux_set_parent,
+};
+
+struct clk *clk_mux(const char *name, void __iomem *reg,
+ u8 shift, u8 width, const char **parents, u8 num_parents)
+{
+ struct clk_mux *m = xzalloc(sizeof(*m));
+ int ret;
+
+ m->reg = reg;
+ m->shift = shift;
+ m->width = width;
+ m->clk.ops = &clk_mux_ops;
+ m->clk.name = name;
+ m->clk.parent_names = parents;
+ m->clk.num_parents = num_parents;
+
+ ret = clk_register(&m->clk);
+ if (ret) {
+ free(m);
+ return ERR_PTR(ret);
+ }
+
+ return &m->clk;
+}
diff --git a/drivers/clk/clk.c b/drivers/clk/clk.c
new file mode 100644
index 0000000000..bf61e5db94
--- /dev/null
+++ b/drivers/clk/clk.c
@@ -0,0 +1,224 @@
+/*
+ * clk.c - generic barebox clock support. Based on Linux clk support
+ *
+ * Copyright (c) 2012 Sascha Hauer <s.hauer@pengutronix.de>, Pengutronix
+ *
+ * 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 <linux/clk.h>
+#include <linux/err.h>
+
+static LIST_HEAD(clks);
+
+static int clk_parent_enable(struct clk *clk)
+{
+ struct clk *parent = clk_get_parent(clk);
+
+ if (!IS_ERR_OR_NULL(parent))
+ return clk_enable(parent);
+
+ return 0;
+}
+
+static void clk_parent_disable(struct clk *clk)
+{
+ struct clk *parent = clk_get_parent(clk);
+
+ if (!IS_ERR_OR_NULL(parent))
+ clk_disable(parent);
+}
+
+int clk_enable(struct clk *clk)
+{
+ int ret;
+
+ if (!clk->enable_count) {
+ ret = clk_parent_enable(clk);
+ if (ret)
+ return ret;
+
+ if (clk->ops->enable) {
+ ret = clk->ops->enable(clk);
+ if (ret) {
+ clk_parent_disable(clk);
+ return ret;
+ }
+ }
+ }
+
+ clk->enable_count++;
+
+ return 0;
+}
+
+void clk_disable(struct clk *clk)
+{
+ if (!clk->enable_count)
+ return;
+
+ clk->enable_count--;
+
+ if (!clk->enable_count) {
+ if (clk->ops->disable)
+ clk->ops->disable(clk);
+
+ clk_parent_disable(clk);
+ }
+}
+
+unsigned long clk_get_rate(struct clk *clk)
+{
+ struct clk *parent;
+ unsigned long parent_rate = 0;
+
+ parent = clk_get_parent(clk);
+ if (!IS_ERR_OR_NULL(parent))
+ parent_rate = clk_get_rate(parent);
+
+ if (clk->ops->recalc_rate)
+ return clk->ops->recalc_rate(clk, parent_rate);
+
+ return parent_rate;
+}
+
+long clk_round_rate(struct clk *clk, unsigned long rate)
+{
+ return clk_get_rate(clk);
+}
+
+int clk_set_rate(struct clk *clk, unsigned long rate)
+{
+ struct clk *parent;
+ unsigned long parent_rate = 0;
+
+ parent = clk_get_parent(clk);
+ if (parent)
+ parent_rate = clk_get_rate(parent);
+
+ if (clk->ops->set_rate)
+ return clk->ops->set_rate(clk, rate, parent_rate);
+
+ return -ENOSYS;
+}
+
+struct clk *clk_lookup(const char *name)
+{
+ struct clk *c;
+
+ if (!name)
+ return ERR_PTR(-ENODEV);
+
+ list_for_each_entry(c, &clks, list) {
+ if (!strcmp(c->name, name))
+ return c;
+ }
+
+ return ERR_PTR(-ENODEV);
+}
+
+int clk_set_parent(struct clk *clk, struct clk *parent)
+{
+ int i;
+
+ if (!clk->num_parents)
+ return -EINVAL;
+ if (!clk->ops->set_parent)
+ return -EINVAL;
+
+ for (i = 0; i < clk->num_parents; i++) {
+ if (IS_ERR_OR_NULL(clk->parents[i]))
+ clk->parents[i] = clk_lookup(clk->parent_names[i]);
+
+ if (!IS_ERR_OR_NULL(clk->parents[i]))
+ if (clk->parents[i] == parent)
+ break;
+ }
+
+ if (i == clk->num_parents)
+ return -EINVAL;
+
+ return clk->ops->set_parent(clk, i);
+}
+
+struct clk *clk_get_parent(struct clk *clk)
+{
+ int idx;
+
+ if (!clk->num_parents)
+ return ERR_PTR(-ENODEV);
+
+ if (clk->num_parents != 1) {
+ if (!clk->ops->get_parent)
+ return ERR_PTR(-EINVAL);
+
+ idx = clk->ops->get_parent(clk);
+
+ if (idx >= clk->num_parents)
+ return ERR_PTR(-ENODEV);
+ } else {
+ idx = 0;
+ }
+
+ if (IS_ERR_OR_NULL(clk->parents[idx]))
+ clk->parents[idx] = clk_lookup(clk->parent_names[idx]);
+
+ return clk->parents[idx];
+}
+
+int clk_register(struct clk *clk)
+{
+ clk->parents = xzalloc(sizeof(struct clk *) * clk->num_parents);
+
+ list_add_tail(&clk->list, &clks);
+
+ return 0;
+}
+
+static void dump_one(struct clk *clk, int verbose, int indent)
+{
+ struct clk *c;
+
+ printf("%*s%s (rate %ld, %sabled)\n", indent * 4, "", clk->name, clk_get_rate(clk),
+ clk->enable_count ? "en" : "dis");
+ if (verbose) {
+
+ if (clk->num_parents > 1) {
+ int i;
+ printf("%*s`---- possible parents: ", indent * 4, "");
+ for (i = 0; i < clk->num_parents; i++)
+ printf("%s ", clk->parent_names[i]);
+ printf("\n");
+ }
+ }
+
+ list_for_each_entry(c, &clks, list) {
+ struct clk *parent = clk_get_parent(c);
+
+ if (parent == clk) {
+ dump_one(c, verbose, indent + 1);
+ }
+ }
+}
+
+void clk_dump(int verbose)
+{
+ struct clk *c;
+
+ list_for_each_entry(c, &clks, list) {
+ struct clk *parent = clk_get_parent(c);
+
+ if (IS_ERR_OR_NULL(parent))
+ dump_one(c, verbose, 0);
+ }
+}
diff --git a/drivers/clk/clkdev.c b/drivers/clk/clkdev.c
index 717fea5689..1ae822ffa6 100644
--- a/drivers/clk/clkdev.c
+++ b/drivers/clk/clkdev.c
@@ -62,6 +62,34 @@ static struct clk *clk_find(const char *dev_id, const char *con_id)
return clk;
}
+static struct clk *clk_find_physbase(struct device_d *dev, const char *con_id)
+{
+ struct clk_lookup *p;
+ unsigned long start;
+ struct clk *clk = ERR_PTR(-ENOSYS);
+
+ if (!dev || !dev->resource)
+ return ERR_PTR(-ENOSYS);
+
+ start = dev->resource[0].start;
+
+ list_for_each_entry(p, &clocks, node) {
+ if (p->physbase == ~0)
+ continue;
+ if (p->physbase != start)
+ continue;
+ if (p->con_id) {
+ if (!con_id || strcmp(p->con_id, con_id))
+ continue;
+ return p->clk;
+ }
+ clk = p->clk;
+ }
+
+ return clk;
+
+}
+
struct clk *clk_get_sys(const char *dev_id, const char *con_id)
{
struct clk *clk;
@@ -77,6 +105,11 @@ EXPORT_SYMBOL(clk_get_sys);
struct clk *clk_get(struct device_d *dev, const char *con_id)
{
const char *dev_id = dev ? dev_name(dev) : NULL;
+ struct clk *clk;
+
+ clk = clk_find_physbase(dev, con_id);
+ if (!IS_ERR(clk))
+ return clk;
return clk_get_sys(dev_id, con_id);
}
@@ -90,6 +123,9 @@ EXPORT_SYMBOL(clk_put);
void clkdev_add(struct clk_lookup *cl)
{
+ if (cl->dev_id)
+ cl->physbase = ~0;
+
list_add_tail(&cl->node, &clocks);
}
EXPORT_SYMBOL(clkdev_add);
@@ -97,6 +133,8 @@ EXPORT_SYMBOL(clkdev_add);
void __init clkdev_add_table(struct clk_lookup *cl, size_t num)
{
while (num--) {
+ if (cl->dev_id)
+ cl->physbase = ~0;
list_add_tail(&cl->node, &clocks);
cl++;
}
@@ -120,6 +158,7 @@ struct clk_lookup *clkdev_alloc(struct clk *clk, const char *con_id,
if (!cla)
return NULL;
+ cla->cl.physbase = ~0;
cla->cl.clk = clk;
if (con_id) {
strlcpy(cla->con_id, con_id, sizeof(cla->con_id));
@@ -166,3 +205,19 @@ void clkdev_drop(struct clk_lookup *cl)
kfree(cl);
}
EXPORT_SYMBOL(clkdev_drop);
+
+int clkdev_add_physbase(struct clk *clk, unsigned long base, const char *id)
+{
+ struct clk_lookup *cl;
+
+ cl = xzalloc(sizeof(*cl));
+
+ cl->clk = clk;
+ cl->con_id = id;
+ cl->physbase = base;
+
+ clkdev_add(cl);
+
+ return 0;
+}
+EXPORT_SYMBOL(clkdev_add_physbase);
diff --git a/drivers/i2c/busses/i2c-imx.c b/drivers/i2c/busses/i2c-imx.c
index eed104fb52..24bbc6b7cc 100644
--- a/drivers/i2c/busses/i2c-imx.c
+++ b/drivers/i2c/busses/i2c-imx.c
@@ -37,7 +37,7 @@
#include <malloc.h>
#include <types.h>
#include <xfuncs.h>
-
+#include <linux/clk.h>
#include <linux/err.h>
#include <io.h>
@@ -101,6 +101,7 @@ static u16 i2c_clk_div[50][2] = {
struct fsl_i2c_struct {
void __iomem *base;
+ struct clk *clk;
struct i2c_adapter adapter;
unsigned int disable_delay;
int stopped;
@@ -109,6 +110,19 @@ struct fsl_i2c_struct {
};
#define to_fsl_i2c_struct(a) container_of(a, struct fsl_i2c_struct, adapter)
+#ifdef CONFIG_COMMON_CLK
+static inline unsigned long i2c_fsl_clk_get_rate(struct fsl_i2c_struct *i2c_fsl)
+{
+ return clk_get_rate(i2c_fsl->clk);
+}
+
+#else
+static inline unsigned long i2c_fsl_clk_get_rate(struct fsl_i2c_struct *i2c_fsl)
+{
+ return fsl_get_i2cclk();
+}
+#endif
+
#ifdef CONFIG_I2C_DEBUG
static void i2c_fsl_dump_reg(struct i2c_adapter *adapter)
{
@@ -344,7 +358,7 @@ static void i2c_fsl_set_clk(struct fsl_i2c_struct *i2c_fsl,
int i;
/* Divider value calculation */
- i2c_clk_rate = fsl_get_i2cclk();
+ i2c_clk_rate = i2c_fsl_clk_get_rate(i2c_fsl);
div = (i2c_clk_rate + rate - 1) / rate;
if (div < i2c_clk_div[0][0])
i = 0;
@@ -535,6 +549,11 @@ static int __init i2c_fsl_probe(struct device_d *pdev)
i2c_fsl = kzalloc(sizeof(struct fsl_i2c_struct), GFP_KERNEL);
+#ifdef CONFIG_COMMON_CLK
+ i2c_fsl->clk = clk_get(pdev, NULL);
+ if (IS_ERR(i2c_fsl->clk))
+ return PTR_ERR(i2c_fsl->clk);
+#endif
/* Setup i2c_fsl driver structure */
i2c_fsl->adapter.master_xfer = i2c_fsl_xfer;
i2c_fsl->adapter.nr = pdev->id;
diff --git a/drivers/mci/imx-esdhc.c b/drivers/mci/imx-esdhc.c
index 599a639251..dccffc6eec 100644
--- a/drivers/mci/imx-esdhc.c
+++ b/drivers/mci/imx-esdhc.c
@@ -28,8 +28,9 @@
#include <mci.h>
#include <clock.h>
#include <io.h>
+#include <linux/clk.h>
+#include <linux/err.h>
#include <asm/mmu.h>
-#include <mach/clock.h>
#include <mach/generic.h>
#include <mach/esdhc.h>
#include <gpio.h>
@@ -70,6 +71,7 @@ struct fsl_esdhc_host {
u32 no_snoop;
unsigned long cur_clock;
struct device_d *dev;
+ struct clk *clk;
};
#define to_fsl_esdhc(mci) container_of(mci, struct fsl_esdhc_host, mci)
@@ -354,7 +356,7 @@ static void set_sysctl(struct mci_host *mci, u32 clock)
int div, pre_div;
struct fsl_esdhc_host *host = to_fsl_esdhc(mci);
struct fsl_esdhc __iomem *regs = host->regs;
- int sdhc_clk = imx_get_mmcclk();
+ int sdhc_clk = clk_get_rate(host->clk);
u32 clk;
if (clock < mci->f_min)
@@ -516,11 +518,16 @@ static int fsl_esdhc_probe(struct device_d *dev)
struct mci_host *mci;
u32 caps;
int ret;
+ unsigned long rate;
struct esdhc_platform_data *pdata = dev->platform_data;
host = xzalloc(sizeof(*host));
mci = &host->mci;
+ host->clk = clk_get(dev, NULL);
+ if (IS_ERR(host->clk))
+ return PTR_ERR(host->clk);
+
host->dev = dev;
host->regs = dev_request_mem_region(dev, 0);
@@ -553,10 +560,11 @@ static int fsl_esdhc_probe(struct device_d *dev)
host->mci.init = esdhc_init;
host->mci.hw_dev = dev;
- host->mci.f_min = imx_get_mmcclk() >> 12;
+ rate = clk_get_rate(host->clk);
+ host->mci.f_min = rate >> 12;
if (host->mci.f_min < 200000)
host->mci.f_min = 200000;
- host->mci.f_max = imx_get_mmcclk();
+ host->mci.f_max = rate;
mci_register(&host->mci);
diff --git a/drivers/mci/imx.c b/drivers/mci/imx.c
index 8a6547d87b..072ca93794 100644
--- a/drivers/mci/imx.c
+++ b/drivers/mci/imx.c
@@ -25,6 +25,8 @@
#include <clock.h>
#include <init.h>
#include <driver.h>
+#include <linux/clk.h>
+#include <linux/err.h>
#include <mach/clock.h>
#include <io.h>
@@ -103,6 +105,7 @@ struct mxcmci_regs {
struct mxcmci_host {
struct mci_host mci;
struct mxcmci_regs *base;
+ struct clk *clk;
int irq;
int detect_irq;
int dma;
@@ -415,7 +418,7 @@ static void mxcmci_set_clk_rate(struct mxcmci_host *host, unsigned int clk_ios)
{
unsigned int divider;
int prescaler = 0;
- unsigned long clk_in = imx_get_mmcclk();
+ unsigned long clk_in = clk_get_rate(host->clk);
while (prescaler <= 0x800) {
for (divider = 1; divider <= 0xF; divider++) {
@@ -490,9 +493,14 @@ static int mxcmci_init(struct mci_host *mci, struct device_d *dev)
static int mxcmci_probe(struct device_d *dev)
{
struct mxcmci_host *host;
+ unsigned long rate;
host = xzalloc(sizeof(*host));
+ host->clk = clk_get(dev, NULL);
+ if (IS_ERR(host->clk))
+ return PTR_ERR(host->clk);
+
host->mci.send_cmd = mxcmci_request;
host->mci.set_ios = mxcmci_set_ios;
host->mci.init = mxcmci_init;
@@ -503,8 +511,9 @@ static int mxcmci_probe(struct device_d *dev)
host->mci.voltages = MMC_VDD_32_33 | MMC_VDD_33_34;
- host->mci.f_min = imx_get_mmcclk() >> 7;
- host->mci.f_max = imx_get_mmcclk() >> 1;
+ rate = clk_get_rate(host->clk);
+ host->mci.f_min = rate >> 7;
+ host->mci.f_max = rate >> 1;
mci_register(&host->mci);
diff --git a/drivers/net/fec_imx.c b/drivers/net/fec_imx.c
index 1aebee7056..b95c4f056e 100644
--- a/drivers/net/fec_imx.c
+++ b/drivers/net/fec_imx.c
@@ -24,6 +24,8 @@
#include <clock.h>
#include <xfuncs.h>
#include <linux/phy.h>
+#include <linux/clk.h>
+#include <linux/err.h>
#include <asm/mmu.h>
@@ -43,6 +45,19 @@ struct fec_frame {
uint8_t head[16]; /* MAC header(6 + 6 + 2) + 2(aligned) */
};
+#ifdef CONFIG_COMMON_CLK
+static inline unsigned long fec_clk_get_rate(struct fec_priv *fec)
+{
+ return clk_get_rate(fec->clk);
+}
+#else
+static inline unsigned long fec_clk_get_rate(struct fec_priv *fec)
+{
+ return imx_get_fecclk();
+}
+#endif
+
+
/*
* MII-interface related functions
*/
@@ -54,7 +69,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(((imx_get_fecclk() >> 20) / 5) << 1,
+ writel(((fec_clk_get_rate(fec) >> 20) / 5) << 1,
fec->regs + FEC_MII_SPEED);
/*
* reading from any PHY's register is done by properly
@@ -97,7 +112,7 @@ static int fec_miibus_write(struct mii_bus *bus, int phyAddr,
uint32_t phy; /* convenient holder for the PHY */
uint64_t start;
- writel(((imx_get_fecclk() >> 20) / 5) << 1,
+ writel(((fec_clk_get_rate(fec) >> 20) / 5) << 1,
fec->regs + FEC_MII_SPEED);
reg = regAddr << FEC_MII_DATA_RA_SHIFT;
@@ -290,7 +305,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(((imx_get_fecclk() >> 20) / 5) << 1,
+ writel(((fec_clk_get_rate(fec) >> 20) / 5) << 1,
fec->regs + FEC_MII_SPEED);
}
@@ -612,6 +627,7 @@ static int fec_probe(struct device_d *dev)
struct eth_device *edev;
struct fec_priv *fec;
void *base;
+ int ret;
#ifdef CONFIG_ARCH_IMX27
PCCR0 |= PCCR0_FEC_EN;
#endif
@@ -628,6 +644,14 @@ static int fec_probe(struct device_d *dev)
edev->set_ethaddr = fec_set_hwaddr;
edev->parent = dev;
+ if (IS_ENABLED(CONFIG_COMMON_CLK)) {
+ fec->clk = clk_get(dev, NULL);
+ if (IS_ERR(fec->clk)) {
+ ret = PTR_ERR(fec->clk);
+ goto err_free;
+ }
+ }
+
fec->regs = dev_request_mem_region(dev, 0);
/* Reset chip. */
@@ -682,6 +706,10 @@ static int fec_probe(struct device_d *dev)
eth_register(edev);
return 0;
+
+err_free:
+ free(fec);
+ return ret;
}
static void fec_remove(struct device_d *dev)
diff --git a/drivers/net/fec_imx.h b/drivers/net/fec_imx.h
index d10385a531..d147dca113 100644
--- a/drivers/net/fec_imx.h
+++ b/drivers/net/fec_imx.h
@@ -138,6 +138,7 @@ struct fec_priv {
u32 phy_flags;
struct mii_bus miibus;
void (*phy_init)(struct phy_device *dev);
+ struct clk *clk;
};
/**
diff --git a/drivers/serial/serial_imx.c b/drivers/serial/serial_imx.c
index 61ceb48c91..a7119405c2 100644
--- a/drivers/serial/serial_imx.c
+++ b/drivers/serial/serial_imx.c
@@ -16,12 +16,13 @@
#include <common.h>
#include <mach/imx-regs.h>
-#include <mach/clock.h>
#include <driver.h>
#include <init.h>
#include <malloc.h>
#include <notifier.h>
#include <io.h>
+#include <linux/err.h>
+#include <linux/clk.h>
#define URXD0 0x0 /* Receiver Register */
#define URTX0 0x40 /* Transmitter Register */
@@ -170,16 +171,17 @@ struct imx_serial_priv {
int baudrate;
struct notifier_block notify;
void __iomem *regs;
+ struct clk *clk;
};
-static int imx_serial_reffreq(void __iomem *regs)
+static int imx_serial_reffreq(struct imx_serial_priv *priv)
{
ulong rfdiv;
- rfdiv = (readl(regs + UFCR) >> 7) & 7;
+ rfdiv = (readl(priv->regs + UFCR) >> 7) & 7;
rfdiv = rfdiv < 6 ? 6 - rfdiv : 7;
- return imx_get_uartclk() / rfdiv;
+ return clk_get_rate(priv->clk) / rfdiv;
}
/*
@@ -209,7 +211,7 @@ static int imx_serial_init_port(struct console_device *cdev)
writel(0xa81, regs + UFCR);
#ifdef ONEMS
- writel(imx_serial_reffreq(regs) / 1000, regs + ONEMS);
+ writel(imx_serial_reffreq(priv) / 1000, regs + ONEMS);
#endif
/* Enable FIFOs */
@@ -291,7 +293,7 @@ static int imx_serial_setbaudrate(struct console_device *cdev, int baudrate)
/* Set the numerator value minus one of the BRM ratio */
writel((baudrate / 100) - 1, regs + UBIR);
/* Set the denominator value minus one of the BRM ratio */
- writel((imx_serial_reffreq(regs) / 1600) - 1, regs + UBMR);
+ writel((imx_serial_reffreq(priv) / 1600) - 1, regs + UBMR);
writel(ucr1, regs + UCR1);
@@ -316,11 +318,18 @@ static int imx_serial_probe(struct device_d *dev)
struct console_device *cdev;
struct imx_serial_priv *priv;
uint32_t val;
+ int ret;
priv = xzalloc(sizeof(*priv));
cdev = &priv->cdev;
dev->priv = priv;
+ priv->clk = clk_get(dev, NULL);
+ if (IS_ERR(priv->clk)) {
+ ret = PTR_ERR(priv->clk);
+ goto err_free;
+ }
+
priv->regs = dev_request_mem_region(dev, 0);
cdev->dev = dev;
cdev->f_caps = CONSOLE_STDIN | CONSOLE_STDOUT | CONSOLE_STDERR;
@@ -343,6 +352,11 @@ static int imx_serial_probe(struct device_d *dev)
clock_register_client(&priv->notify);
return 0;
+
+err_free:
+ free(priv);
+
+ return ret;
}
static void imx_serial_remove(struct device_d *dev)
diff --git a/drivers/spi/imx_spi.c b/drivers/spi/imx_spi.c
index 8551f73afa..71fac3de3b 100644
--- a/drivers/spi/imx_spi.c
+++ b/drivers/spi/imx_spi.c
@@ -21,10 +21,12 @@
#include <xfuncs.h>
#include <io.h>
#include <errno.h>
+#include <malloc.h>
#include <gpio.h>
#include <mach/spi.h>
#include <mach/generic.h>
-#include <mach/clock.h>
+#include <linux/clk.h>
+#include <linux/err.h>
#define CSPI_0_0_RXDATA 0x00
#define CSPI_0_0_TXDATA 0x04
@@ -128,6 +130,7 @@ struct imx_spi {
struct spi_master master;
int *cs_array;
void __iomem *regs;
+ struct clk *clk;
unsigned int (*xchg_single)(struct imx_spi *imx, u32 data);
void (*chipselect)(struct spi_device *spi, int active);
@@ -276,7 +279,7 @@ static void cspi_0_7_chipselect(struct spi_device *spi, int is_active)
return;
}
- reg |= spi_imx_clkdiv_2(imx_get_cspiclk(), spi->max_speed_hz) <<
+ reg |= spi_imx_clkdiv_2(clk_get_rate(imx->clk), spi->max_speed_hz) <<
CSPI_0_7_CTRL_DR_SHIFT;
reg |= (spi->bits_per_word - 1) << CSPI_0_7_CTRL_BL_SHIFT;
@@ -381,7 +384,7 @@ static void cspi_2_3_chipselect(struct spi_device *spi, int is_active)
ctrl |= CSPI_2_3_CTRL_MODE(cs);
/* set clock speed */
- ctrl |= cspi_2_3_clkdiv(imx_get_cspiclk(), spi->max_speed_hz);
+ ctrl |= cspi_2_3_clkdiv(clk_get_rate(imx->clk), spi->max_speed_hz);
/* set chip select to use */
ctrl |= CSPI_2_3_CTRL_CS(cs);
@@ -524,6 +527,7 @@ static int imx_spi_probe(struct device_d *dev)
struct imx_spi *imx;
struct spi_imx_master *pdata = dev->platform_data;
enum imx_spi_devtype version;
+ int ret;
imx = xzalloc(sizeof(*imx));
@@ -532,6 +536,7 @@ static int imx_spi_probe(struct device_d *dev)
master->setup = imx_spi_setup;
master->transfer = imx_spi_transfer;
+
if (pdata) {
master->num_chipselect = pdata->num_chipselect;
imx->cs_array = pdata->chipselect;
@@ -540,6 +545,12 @@ static int imx_spi_probe(struct device_d *dev)
imx_spi_dt_probe(imx);
}
+ imx->clk = clk_get(dev, NULL);
+ if (IS_ERR(imx->clk)) {
+ ret = PTR_ERR(imx->clk);
+ goto err_free;
+ }
+
#ifdef CONFIG_DRIVER_SPI_IMX_0_0
if (cpu_is_mx27())
version = SPI_IMX_VER_0_0;
@@ -562,6 +573,11 @@ static int imx_spi_probe(struct device_d *dev)
spi_register_master(master);
return 0;
+
+err_free:
+ free(imx);
+
+ return ret;
}
static __maybe_unused struct of_device_id imx_spi_dt_ids[] = {
diff --git a/drivers/video/imx-ipu-fb.c b/drivers/video/imx-ipu-fb.c
index 5e5244d367..3f8fd33416 100644
--- a/drivers/video/imx-ipu-fb.c
+++ b/drivers/video/imx-ipu-fb.c
@@ -27,10 +27,12 @@
#include <errno.h>
#include <asm-generic/div64.h>
#include <mach/imx-ipu-fb.h>
-#include <mach/clock.h>
+#include <linux/clk.h>
+#include <linux/err.h>
struct ipu_fb_info {
void __iomem *regs;
+ struct clk *clk;
void (*enable)(int enable);
@@ -480,7 +482,7 @@ static int sdc_init_panel(struct fb_info *info, enum pixel_fmt pixel_fmt)
* i.MX31 it (HSP_CLK) is <= 178MHz. Currently 128.267MHz
*/
pixel_clk = PICOS2KHZ(mode->pixclock) * 1000UL;
- div = imx_get_lcdclk() * 16 / pixel_clk;
+ div = clk_get_rate(fbi->clk) * 16 / pixel_clk;
if (div < 0x40) { /* Divider less than 4 */
dev_dbg(&info->dev,
@@ -986,6 +988,10 @@ static int imxfb_probe(struct device_d *dev)
fbi = xzalloc(sizeof(*fbi));
info = &fbi->info;
+ fbi->clk = clk_get(dev, NULL);
+ if (IS_ERR(fbi->clk))
+ return PTR_ERR(fbi->clk);
+
fbi->regs = dev_request_mem_region(dev, 0);
fbi->dev = dev;
fbi->enable = pdata->enable;
diff --git a/drivers/video/imx.c b/drivers/video/imx.c
index 29b1fc523d..9406b36e71 100644
--- a/drivers/video/imx.c
+++ b/drivers/video/imx.c
@@ -22,9 +22,10 @@
#include <malloc.h>
#include <errno.h>
#include <init.h>
+#include <linux/clk.h>
+#include <linux/err.h>
#include <mach/imx-regs.h>
#include <asm-generic/div64.h>
-#include <mach/clock.h>
#define LCDC_SSA 0x00
@@ -138,6 +139,7 @@ struct imxfb_rgb {
struct imxfb_info {
void __iomem *regs;
+ struct clk *clk;
u_int pcr;
u_int pwmr;
@@ -341,7 +343,7 @@ static int imxfb_activate_var(struct fb_info *info)
writel(readl(fbi->regs + LCDC_CPOS) & ~(CPOS_CC0 | CPOS_CC1),
fbi->regs + LCDC_CPOS);
- lcd_clk = imx_get_lcdclk();
+ lcd_clk = clk_get_rate(fbi->clk);
tmp = mode->pixclock * (unsigned long long)lcd_clk;
@@ -564,6 +566,10 @@ static int imxfb_probe(struct device_d *dev)
fbi = xzalloc(sizeof(*fbi));
info = &fbi->info;
+ fbi->clk = clk_get(dev, NULL);
+ if (IS_ERR(fbi->clk))
+ return PTR_ERR(fbi->clk);
+
fbi->mode = pdata->mode;
fbi->regs = dev_request_mem_region(dev, 0);
fbi->pcr = pdata->mode->pcr;