diff options
Diffstat (limited to 'drivers/clk')
-rw-r--r-- | drivers/clk/Makefile | 1 | ||||
-rw-r--r-- | drivers/clk/clk-devres.c | 55 | ||||
-rw-r--r-- | drivers/clk/clkdev.c | 45 | ||||
-rw-r--r-- | drivers/clk/mxs/Makefile | 2 | ||||
-rw-r--r-- | drivers/clk/mxs/clk-ssp.c | 62 |
5 files changed, 119 insertions, 46 deletions
diff --git a/drivers/clk/Makefile b/drivers/clk/Makefile index 5869ea3..72ce247 100644 --- a/drivers/clk/Makefile +++ b/drivers/clk/Makefile @@ -1,4 +1,5 @@ # common clock types +obj-$(CONFIG_HAVE_CLK) += clk-devres.o obj-$(CONFIG_CLKDEV_LOOKUP) += clkdev.o obj-$(CONFIG_COMMON_CLK) += clk.o clk-fixed-rate.o clk-gate.o \ clk-mux.o clk-divider.o clk-fixed-factor.o diff --git a/drivers/clk/clk-devres.c b/drivers/clk/clk-devres.c new file mode 100644 index 0000000..8f57154 --- /dev/null +++ b/drivers/clk/clk-devres.c @@ -0,0 +1,55 @@ +/* + * 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 <linux/clk.h> +#include <linux/device.h> +#include <linux/export.h> +#include <linux/gfp.h> + +static void devm_clk_release(struct device *dev, void *res) +{ + clk_put(*(struct clk **)res); +} + +struct clk *devm_clk_get(struct device *dev, const char *id) +{ + struct clk **ptr, *clk; + + ptr = devres_alloc(devm_clk_release, sizeof(*ptr), GFP_KERNEL); + if (!ptr) + return ERR_PTR(-ENOMEM); + + clk = clk_get(dev, id); + if (!IS_ERR(clk)) { + *ptr = clk; + devres_add(dev, ptr); + } else { + devres_free(ptr); + } + + return clk; +} +EXPORT_SYMBOL(devm_clk_get); + +static int devm_clk_match(struct device *dev, void *res, void *data) +{ + struct clk **c = res; + if (!c || !*c) { + WARN_ON(!c || !*c); + return 0; + } + return *c == data; +} + +void devm_clk_put(struct device *dev, struct clk *clk) +{ + int ret; + + ret = devres_release(dev, devm_clk_release, devm_clk_match, clk); + + WARN_ON(ret); +} +EXPORT_SYMBOL(devm_clk_put); diff --git a/drivers/clk/clkdev.c b/drivers/clk/clkdev.c index d423c9b..442a313 100644 --- a/drivers/clk/clkdev.c +++ b/drivers/clk/clkdev.c @@ -171,51 +171,6 @@ void clk_put(struct clk *clk) } EXPORT_SYMBOL(clk_put); -static void devm_clk_release(struct device *dev, void *res) -{ - clk_put(*(struct clk **)res); -} - -struct clk *devm_clk_get(struct device *dev, const char *id) -{ - struct clk **ptr, *clk; - - ptr = devres_alloc(devm_clk_release, sizeof(*ptr), GFP_KERNEL); - if (!ptr) - return ERR_PTR(-ENOMEM); - - clk = clk_get(dev, id); - if (!IS_ERR(clk)) { - *ptr = clk; - devres_add(dev, ptr); - } else { - devres_free(ptr); - } - - return clk; -} -EXPORT_SYMBOL(devm_clk_get); - -static int devm_clk_match(struct device *dev, void *res, void *data) -{ - struct clk **c = res; - if (!c || !*c) { - WARN_ON(!c || !*c); - return 0; - } - return *c == data; -} - -void devm_clk_put(struct device *dev, struct clk *clk) -{ - int ret; - - ret = devres_destroy(dev, devm_clk_release, devm_clk_match, clk); - - WARN_ON(ret); -} -EXPORT_SYMBOL(devm_clk_put); - void clkdev_add(struct clk_lookup *cl) { mutex_lock(&clocks_mutex); diff --git a/drivers/clk/mxs/Makefile b/drivers/clk/mxs/Makefile index 7bedeec..a6a2223 100644 --- a/drivers/clk/mxs/Makefile +++ b/drivers/clk/mxs/Makefile @@ -2,7 +2,7 @@ # Makefile for mxs specific clk # -obj-y += clk.o clk-pll.o clk-ref.o clk-div.o clk-frac.o +obj-y += clk.o clk-pll.o clk-ref.o clk-div.o clk-frac.o clk-ssp.o obj-$(CONFIG_SOC_IMX23) += clk-imx23.o obj-$(CONFIG_SOC_IMX28) += clk-imx28.o diff --git a/drivers/clk/mxs/clk-ssp.c b/drivers/clk/mxs/clk-ssp.c new file mode 100644 index 0000000..af7bdbf --- /dev/null +++ b/drivers/clk/mxs/clk-ssp.c @@ -0,0 +1,62 @@ +/* + * Copyright 2012 DENX Software Engineering, GmbH + * + * Pulled from code: + * Portions copyright (C) 2003 Russell King, PXA MMCI Driver + * Portions copyright (C) 2004-2005 Pierre Ossman, W83L51xD SD/MMC driver + * + * Copyright 2008 Embedded Alley Solutions, Inc. + * Copyright 2009-2011 Freescale Semiconductor, Inc. + * + * The code contained herein is licensed under the GNU General Public + * License. You may obtain a copy of the GNU General Public License + * Version 2 or later at the following locations: + * + * http://www.opensource.org/licenses/gpl-license.html + * http://www.gnu.org/copyleft/gpl.html + */ + +#include <linux/kernel.h> +#include <linux/init.h> +#include <linux/clk.h> +#include <linux/module.h> +#include <linux/device.h> +#include <linux/io.h> +#include <linux/spi/mxs-spi.h> + +void mxs_ssp_set_clk_rate(struct mxs_ssp *ssp, unsigned int rate) +{ + unsigned int ssp_clk, ssp_sck; + u32 clock_divide, clock_rate; + u32 val; + + ssp_clk = clk_get_rate(ssp->clk); + + for (clock_divide = 2; clock_divide <= 254; clock_divide += 2) { + clock_rate = DIV_ROUND_UP(ssp_clk, rate * clock_divide); + clock_rate = (clock_rate > 0) ? clock_rate - 1 : 0; + if (clock_rate <= 255) + break; + } + + if (clock_divide > 254) { + dev_err(ssp->dev, + "%s: cannot set clock to %d\n", __func__, rate); + return; + } + + ssp_sck = ssp_clk / clock_divide / (1 + clock_rate); + + val = readl(ssp->base + HW_SSP_TIMING(ssp)); + val &= ~(BM_SSP_TIMING_CLOCK_DIVIDE | BM_SSP_TIMING_CLOCK_RATE); + val |= BF_SSP(clock_divide, TIMING_CLOCK_DIVIDE); + val |= BF_SSP(clock_rate, TIMING_CLOCK_RATE); + writel(val, ssp->base + HW_SSP_TIMING(ssp)); + + ssp->clk_rate = ssp_sck; + + dev_dbg(ssp->dev, + "%s: clock_divide %d, clock_rate %d, ssp_clk %d, rate_actual %d, rate_requested %d\n", + __func__, clock_divide, clock_rate, ssp_clk, ssp_sck, rate); +} +EXPORT_SYMBOL_GPL(mxs_ssp_set_clk_rate); |