diff options
Diffstat (limited to 'drivers')
-rw-r--r-- | drivers/clk/Kconfig | 3 | ||||
-rw-r--r-- | drivers/clk/Makefile | 2 | ||||
-rw-r--r-- | drivers/clk/clk-divider.c | 98 | ||||
-rw-r--r-- | drivers/clk/clk-fixed-factor.c | 63 | ||||
-rw-r--r-- | drivers/clk/clk-fixed.c | 55 | ||||
-rw-r--r-- | drivers/clk/clk-mux.c | 77 | ||||
-rw-r--r-- | drivers/clk/clk.c | 224 | ||||
-rw-r--r-- | drivers/clk/clkdev.c | 55 | ||||
-rw-r--r-- | drivers/i2c/busses/i2c-imx.c | 23 | ||||
-rw-r--r-- | drivers/mci/imx-esdhc.c | 16 | ||||
-rw-r--r-- | drivers/mci/imx.c | 15 | ||||
-rw-r--r-- | drivers/net/fec_imx.c | 34 | ||||
-rw-r--r-- | drivers/net/fec_imx.h | 1 | ||||
-rw-r--r-- | drivers/serial/serial_imx.c | 26 | ||||
-rw-r--r-- | drivers/spi/imx_spi.c | 22 | ||||
-rw-r--r-- | drivers/video/imx-ipu-fb.c | 10 | ||||
-rw-r--r-- | drivers/video/imx.c | 10 |
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; |