From 38a41fdf94c449c165213e4665c3f8a0d30f8aba Mon Sep 17 00:00:00 2001
From: Sascha Hauer <s.hauer@pengutronix.de>
Date: Sat, 5 Jul 2008 10:02:46 +0200
Subject: [PATCH] IMX: introduce clock API

This patch introduces the clock API for i.MX and converts all
in-Kernel drivers to use it.

Signed-off-by: Sascha Hauer <s.hauer@pengutronix.de>
---
 arch/arm/mach-imx/Makefile          |   2 +-
 arch/arm/mach-imx/clock.c           | 205 ++++++++++++++++++++++++++++
 arch/arm/mach-imx/cpufreq.c         |  20 ++-
 arch/arm/mach-imx/generic.c         |  76 -----------
 arch/arm/mach-imx/time.c            |  23 +++-
 drivers/mmc/host/imxmmc.c           |  19 ++-
 drivers/serial/imx.c                |  25 +++-
 drivers/spi/spi_imx.c               |  38 ++++--
 include/asm-arm/arch-imx/hardware.h |   8 --
 9 files changed, 307 insertions(+), 109 deletions(-)
 create mode 100644 arch/arm/mach-imx/clock.c

diff --git a/arch/arm/mach-imx/Makefile b/arch/arm/mach-imx/Makefile
index 88d5e61a2e13d..b047c7e795a97 100644
--- a/arch/arm/mach-imx/Makefile
+++ b/arch/arm/mach-imx/Makefile
@@ -4,7 +4,7 @@
 
 # Object file lists.
 
-obj-y			+= irq.o time.o dma.o generic.o
+obj-y			+= irq.o time.o dma.o generic.o clock.o
 
 obj-$(CONFIG_CPU_FREQ_IMX)	+= cpufreq.o
 
diff --git a/arch/arm/mach-imx/clock.c b/arch/arm/mach-imx/clock.c
new file mode 100644
index 0000000000000..6a90fe5578df9
--- /dev/null
+++ b/arch/arm/mach-imx/clock.c
@@ -0,0 +1,205 @@
+/*
+ *  Copyright (C) 2008 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.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#include <linux/kernel.h>
+#include <linux/device.h>
+#include <linux/list.h>
+#include <linux/math64.h>
+#include <linux/err.h>
+
+#include <asm/io.h>
+#include <asm/arch/imx-regs.h>
+
+/*
+ * Very simple approach: We can't disable clocks, so we do
+ * not need refcounting
+ */
+
+struct clk {
+	struct list_head node;
+	const char *name;
+	unsigned long (*get_rate)(void);
+};
+
+/*
+ *  get the system pll clock in Hz
+ *
+ *                  mfi + mfn / (mfd +1)
+ *  f = 2 * f_ref * --------------------
+ *                        pd + 1
+ */
+static unsigned long imx_decode_pll(unsigned int pll, u32 f_ref)
+{
+	unsigned long long ll;
+	unsigned long quot;
+
+	u32 mfi = (pll >> 10) & 0xf;
+	u32 mfn = pll & 0x3ff;
+	u32 mfd = (pll >> 16) & 0x3ff;
+	u32 pd =  (pll >> 26) & 0xf;
+
+	mfi = mfi <= 5 ? 5 : mfi;
+
+	ll = 2 * (unsigned long long)f_ref *
+		((mfi << 16) + (mfn << 16) / (mfd + 1));
+	quot = (pd + 1) * (1 << 16);
+	ll += quot / 2;
+	do_div(ll, quot);
+	return (unsigned long)ll;
+}
+
+static unsigned long imx_get_system_clk(void)
+{
+	u32 f_ref = (CSCR & CSCR_SYSTEM_SEL) ? 16000000 : (CLK32 * 512);
+
+	return imx_decode_pll(SPCTL0, f_ref);
+}
+
+static unsigned long imx_get_mcu_clk(void)
+{
+	return imx_decode_pll(MPCTL0, CLK32 * 512);
+}
+
+/*
+ *  get peripheral clock 1 ( UART[12], Timer[12], PWM )
+ */
+static unsigned long imx_get_perclk1(void)
+{
+	return imx_get_system_clk() / (((PCDR) & 0xf)+1);
+}
+
+/*
+ *  get peripheral clock 2 ( LCD, SD, SPI[12] )
+ */
+static unsigned long imx_get_perclk2(void)
+{
+	return imx_get_system_clk() / (((PCDR>>4) & 0xf)+1);
+}
+
+/*
+ *  get peripheral clock 3 ( SSI )
+ */
+static unsigned long imx_get_perclk3(void)
+{
+	return imx_get_system_clk() / (((PCDR>>16) & 0x7f)+1);
+}
+
+/*
+ *  get hclk ( SDRAM, CSI, Memory Stick, I2C, DMA )
+ */
+static unsigned long imx_get_hclk(void)
+{
+	return imx_get_system_clk() / (((CSCR>>10) & 0xf)+1);
+}
+
+static struct clk clk_system_clk = {
+	.name = "system_clk",
+	.get_rate = imx_get_system_clk,
+};
+
+static struct clk clk_hclk = {
+	.name = "hclk",
+	.get_rate = imx_get_hclk,
+};
+
+static struct clk clk_mcu_clk = {
+	.name = "mcu_clk",
+	.get_rate = imx_get_mcu_clk,
+};
+
+static struct clk clk_perclk1 = {
+	.name = "perclk1",
+	.get_rate = imx_get_perclk1,
+};
+
+static struct clk clk_uart_clk = {
+	.name = "uart_clk",
+	.get_rate = imx_get_perclk1,
+};
+
+static struct clk clk_perclk2 = {
+	.name = "perclk2",
+	.get_rate = imx_get_perclk2,
+};
+
+static struct clk clk_perclk3 = {
+	.name = "perclk3",
+	.get_rate = imx_get_perclk3,
+};
+
+static struct clk *clks[] = {
+	&clk_perclk1,
+	&clk_perclk2,
+	&clk_perclk3,
+	&clk_system_clk,
+	&clk_hclk,
+	&clk_mcu_clk,
+	&clk_uart_clk,
+};
+
+static LIST_HEAD(clocks);
+static DEFINE_MUTEX(clocks_mutex);
+
+struct clk *clk_get(struct device *dev, const char *id)
+{
+	struct clk *p, *clk = ERR_PTR(-ENOENT);
+
+	mutex_lock(&clocks_mutex);
+	list_for_each_entry(p, &clocks, node) {
+		if (!strcmp(p->name, id)) {
+			clk = p;
+			goto found;
+		}
+	}
+
+found:
+	mutex_unlock(&clocks_mutex);
+
+	return clk;
+}
+
+void clk_put(struct clk *clk)
+{
+}
+
+int clk_enable(struct clk *clk)
+{
+	return 0;
+}
+
+void clk_disable(struct clk *clk)
+{
+}
+
+unsigned long clk_get_rate(struct clk *clk)
+{
+	return clk->get_rate();
+}
+
+int imx_clocks_init(void)
+{
+	int i;
+
+	mutex_lock(&clocks_mutex);
+	for (i = 0; i < ARRAY_SIZE(clks); i++)
+		list_add(&clks[i]->node, &clocks);
+	mutex_unlock(&clocks_mutex);
+
+	return 0;
+}
+
diff --git a/arch/arm/mach-imx/cpufreq.c b/arch/arm/mach-imx/cpufreq.c
index e548ba74a4d2a..be0809b33e089 100644
--- a/arch/arm/mach-imx/cpufreq.c
+++ b/arch/arm/mach-imx/cpufreq.c
@@ -32,6 +32,8 @@
 #include <linux/types.h>
 #include <linux/init.h>
 #include <linux/cpufreq.h>
+#include <linux/clk.h>
+#include <linux/err.h>
 #include <asm/system.h>
 
 #include <asm/hardware.h>
@@ -52,6 +54,8 @@
 static u32 mpctl0_at_boot;
 static u32 bclk_div_at_boot;
 
+static struct clk *system_clk, *mcu_clk;
+
 static void imx_set_async_mode(void)
 {
 	adjust_cr(CR_920T_CLOCK_MODE, CR_920T_ASYNC_MODE);
@@ -160,10 +164,10 @@ static unsigned int imx_get_speed(unsigned int cpu)
 	cr = get_cr();
 
 	if((cr & CR_920T_CLOCK_MODE) == CR_920T_FASTBUS_MODE) {
-		freq = imx_get_system_clk();
+		freq = clk_get_rate(system_clk);
 		freq = (freq + bclk_div/2) / bclk_div;
 	} else {
-		freq = imx_get_mcu_clk();
+		freq = clk_get_rate(mcu_clk);
 		if (cscr & CSCR_MPU_PRESC)
 			freq /= 2;
 	}
@@ -201,7 +205,7 @@ static int imx_set_target(struct cpufreq_policy *policy,
 	pr_debug(KERN_DEBUG "imx: requested frequency %ld Hz, mpctl0 at boot 0x%08x\n",
 			freq, mpctl0_at_boot);
 
-	sysclk = imx_get_system_clk();
+	sysclk = clk_get_rate(system_clk);
 
 	if (freq > sysclk / bclk_div_at_boot + 1000000) {
 		freq = imx_compute_mpctl(&mpctl0, mpctl0_at_boot, CLK32 * 512, freq, relation);
@@ -290,6 +294,16 @@ static int __init imx_cpufreq_init(void)
 	bclk_div_at_boot = __mfld2val(CSCR_BCLK_DIV, CSCR) + 1;
 	mpctl0_at_boot = 0;
 
+	system_clk = clk_get(NULL, "system_clk");
+	if (IS_ERR(system_clk))
+		return PTR_ERR(system_clk);
+
+	mcu_clk = clk_get(NULL, "mcu_clk");
+	if (IS_ERR(mcu_clk)) {
+		clk_put(system_clk);
+		return PTR_ERR(mcu_clk);
+	}
+
 	if((CSCR & CSCR_MPEN) &&
 	   ((get_cr() & CR_920T_CLOCK_MODE) != CR_920T_FASTBUS_MODE))
 		mpctl0_at_boot = MPCTL0;
diff --git a/arch/arm/mach-imx/generic.c b/arch/arm/mach-imx/generic.c
index 4cfc9d3af28a1..98ddd8a6d05fb 100644
--- a/arch/arm/mach-imx/generic.c
+++ b/arch/arm/mach-imx/generic.c
@@ -214,82 +214,6 @@ int imx_irq_to_gpio(unsigned irq)
 
 EXPORT_SYMBOL(imx_irq_to_gpio);
 
-/*
- *  get the system pll clock in Hz
- *
- *                  mfi + mfn / (mfd +1)
- *  f = 2 * f_ref * --------------------
- *                        pd + 1
- */
-static unsigned int imx_decode_pll(unsigned int pll, u32 f_ref)
-{
-	unsigned long long ll;
-	unsigned long quot;
-
-	u32 mfi = (pll >> 10) & 0xf;
-	u32 mfn = pll & 0x3ff;
-	u32 mfd = (pll >> 16) & 0x3ff;
-	u32 pd =  (pll >> 26) & 0xf;
-
-	mfi = mfi <= 5 ? 5 : mfi;
-
-	ll = 2 * (unsigned long long)f_ref * ( (mfi<<16) + (mfn<<16) / (mfd+1) );
-	quot = (pd+1) * (1<<16);
-	ll += quot / 2;
-	do_div(ll, quot);
-	return (unsigned int) ll;
-}
-
-unsigned int imx_get_system_clk(void)
-{
-	u32 f_ref = (CSCR & CSCR_SYSTEM_SEL) ? 16000000 : (CLK32 * 512);
-
-	return imx_decode_pll(SPCTL0, f_ref);
-}
-EXPORT_SYMBOL(imx_get_system_clk);
-
-unsigned int imx_get_mcu_clk(void)
-{
-	return imx_decode_pll(MPCTL0, CLK32 * 512);
-}
-EXPORT_SYMBOL(imx_get_mcu_clk);
-
-/*
- *  get peripheral clock 1 ( UART[12], Timer[12], PWM )
- */
-unsigned int imx_get_perclk1(void)
-{
-	return imx_get_system_clk() / (((PCDR) & 0xf)+1);
-}
-EXPORT_SYMBOL(imx_get_perclk1);
-
-/*
- *  get peripheral clock 2 ( LCD, SD, SPI[12] )
- */
-unsigned int imx_get_perclk2(void)
-{
-	return imx_get_system_clk() / (((PCDR>>4) & 0xf)+1);
-}
-EXPORT_SYMBOL(imx_get_perclk2);
-
-/*
- *  get peripheral clock 3 ( SSI )
- */
-unsigned int imx_get_perclk3(void)
-{
-	return imx_get_system_clk() / (((PCDR>>16) & 0x7f)+1);
-}
-EXPORT_SYMBOL(imx_get_perclk3);
-
-/*
- *  get hclk ( SDRAM, CSI, Memory Stick, I2C, DMA )
- */
-unsigned int imx_get_hclk(void)
-{
-	return imx_get_system_clk() / (((CSCR>>10) & 0xf)+1);
-}
-EXPORT_SYMBOL(imx_get_hclk);
-
 static struct resource imx_mmc_resources[] = {
 	[0] = {
 		.start	= 0x00214000,
diff --git a/arch/arm/mach-imx/time.c b/arch/arm/mach-imx/time.c
index d86d124aea229..5a41e96e85860 100644
--- a/arch/arm/mach-imx/time.c
+++ b/arch/arm/mach-imx/time.c
@@ -17,6 +17,7 @@
 #include <linux/time.h>
 #include <linux/clocksource.h>
 #include <linux/clockchips.h>
+#include <linux/clk.h>
 
 #include <asm/hardware.h>
 #include <asm/io.h>
@@ -86,10 +87,10 @@ static struct clocksource clocksource_imx = {
 	.flags		= CLOCK_SOURCE_IS_CONTINUOUS,
 };
 
-static int __init imx_clocksource_init(void)
+static int __init imx_clocksource_init(unsigned long rate)
 {
 	clocksource_imx.mult =
-		clocksource_hz2mult(imx_get_perclk1(), clocksource_imx.shift);
+		clocksource_hz2mult(rate, clocksource_imx.shift);
 	clocksource_register(&clocksource_imx);
 
 	return 0;
@@ -174,9 +175,9 @@ static struct clock_event_device clockevent_imx = {
 	.rating		= 200,
 };
 
-static int __init imx_clockevent_init(void)
+static int __init imx_clockevent_init(unsigned long rate)
 {
-	clockevent_imx.mult = div_sc(imx_get_perclk1(), NSEC_PER_SEC,
+	clockevent_imx.mult = div_sc(rate, NSEC_PER_SEC,
 					clockevent_imx.shift);
 	clockevent_imx.max_delta_ns =
 		clockevent_delta2ns(0xfffffffe, &clockevent_imx);
@@ -190,13 +191,23 @@ static int __init imx_clockevent_init(void)
 	return 0;
 }
 
+extern int imx_clocks_init(void);
 
 static void __init imx_timer_init(void)
 {
+	struct clk *clk;
+	unsigned long rate;
+
+	imx_clocks_init();
+
+	clk = clk_get(NULL, "perclk1");
+	clk_enable(clk);
+	rate = clk_get_rate(clk);
+
 	imx_timer_hardware_init();
-	imx_clocksource_init();
+	imx_clocksource_init(rate);
 
-	imx_clockevent_init();
+	imx_clockevent_init(rate);
 
 	/*
 	 * Make irqs happen for the system timer
diff --git a/drivers/mmc/host/imxmmc.c b/drivers/mmc/host/imxmmc.c
index 95f33e87a99ce..ef2f6fc865411 100644
--- a/drivers/mmc/host/imxmmc.c
+++ b/drivers/mmc/host/imxmmc.c
@@ -42,6 +42,7 @@
 #include <linux/mmc/host.h>
 #include <linux/mmc/card.h>
 #include <linux/delay.h>
+#include <linux/clk.h>
 
 #include <asm/dma.h>
 #include <asm/io.h>
@@ -92,6 +93,8 @@ struct imxmci_host {
 	unsigned char		actual_bus_width;
 
 	int			prev_cmd_code;
+
+	struct clk		*clk;
 };
 
 #define IMXMCI_PEND_IRQ_b	0
@@ -841,7 +844,7 @@ static void imxmci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
 		/* The prescaler is 5 for PERCLK2 equal to 96MHz
 		 * then 96MHz / 5 = 19.2 MHz
 		 */
-		clk=imx_get_perclk2();
+		clk = clk_get_rate(host->clk);
 		prescaler=(clk+(CLK_RATE*7)/8)/CLK_RATE;
 		switch(prescaler) {
 		case 0:
@@ -994,6 +997,13 @@ static int imxmci_probe(struct platform_device *pdev)
 	host->res = r;
 	host->irq = irq;
 
+	host->clk = clk_get(&pdev->dev, "perclk2");
+	if (IS_ERR(host->clk)) {
+		ret = PTR_ERR(host->clk);
+		goto out;
+	}
+	clk_enable(host->clk);
+
 	imx_gpio_mode(PB8_PF_SD_DAT0);
 	imx_gpio_mode(PB9_PF_SD_DAT1);
 	imx_gpio_mode(PB10_PF_SD_DAT2);
@@ -1053,6 +1063,10 @@ static int imxmci_probe(struct platform_device *pdev)
 			imx_dma_free(host->dma);
 			host->dma_allocated=0;
 		}
+		if (host->clk) {
+			clk_disable(host->clk);
+			clk_put(host->clk);
+		}
 	}
 	if (mmc)
 		mmc_free_host(mmc);
@@ -1082,6 +1096,9 @@ static int imxmci_remove(struct platform_device *pdev)
 
 		tasklet_kill(&host->tasklet);
 
+		clk_disable(host->clk);
+		clk_put(host->clk);
+
 		release_resource(host->res);
 
 		mmc_free_host(mmc);
diff --git a/drivers/serial/imx.c b/drivers/serial/imx.c
index 8d6cb745bd93c..9e2162ebf1bb8 100644
--- a/drivers/serial/imx.c
+++ b/drivers/serial/imx.c
@@ -40,6 +40,7 @@
 #include <linux/tty_flip.h>
 #include <linux/serial_core.h>
 #include <linux/serial.h>
+#include <linux/clk.h>
 
 #include <asm/io.h>
 #include <asm/irq.h>
@@ -184,6 +185,7 @@ struct imx_port {
 	unsigned int		old_status;
 	int			txirq,rxirq,rtsirq;
 	int			have_rtscts:1;
+	struct clk		*clk;
 };
 
 /*
@@ -479,7 +481,8 @@ static int imx_setup_ufcr(struct imx_port *sport, unsigned int mode)
 	 * RFDIV is set such way to satisfy requested uartclk value
 	 */
 	val = TXTL << 10 | RXTL;
-	ufcr_rfdiv = (imx_get_perclk1() + sport->port.uartclk / 2) / sport->port.uartclk;
+	ufcr_rfdiv = (clk_get_rate(sport->clk) + sport->port.uartclk / 2)
+			/ sport->port.uartclk;
 
 	if(!ufcr_rfdiv)
 		ufcr_rfdiv = 1;
@@ -916,7 +919,7 @@ imx_console_get_options(struct imx_port *sport, int *baud,
 		else
 			ucfr_rfdiv = 6 - ucfr_rfdiv;
 
-		uartclk = imx_get_perclk1();
+		uartclk = clk_get_rate(sport->clk);
 		uartclk /= ucfr_rfdiv;
 
 		{	/*
@@ -1054,7 +1057,15 @@ static int serial_imx_probe(struct platform_device *pdev)
 	init_timer(&sport->timer);
 	sport->timer.function = imx_timeout;
 	sport->timer.data     = (unsigned long)sport;
-	sport->port.uartclk = imx_get_perclk1();
+
+	sport->clk = clk_get(&pdev->dev, "uart_clk");
+	if (IS_ERR(sport->clk)) {
+		ret = PTR_ERR(sport->clk);
+		goto unmap;
+	}
+	clk_enable(sport->clk);
+
+	sport->port.uartclk = clk_get_rate(sport->clk);
 
 	imx_ports[pdev->id] = sport;
 
@@ -1069,6 +1080,8 @@ static int serial_imx_probe(struct platform_device *pdev)
 	platform_set_drvdata(pdev, &sport->port);
 
 	return 0;
+unmap:
+	iounmap(sport->port.membase);
 free:
 	kfree(sport);
 
@@ -1084,8 +1097,12 @@ static int serial_imx_remove(struct platform_device *pdev)
 
 	platform_set_drvdata(pdev, NULL);
 
-	if (sport)
+	if (sport) {
 		uart_remove_one_port(&imx_reg, &sport->port);
+		clk_put(sport->clk);
+	}
+
+	clk_disable(sport->clk);
 
 	if (pdata->exit)
 		pdata->exit(pdev);
diff --git a/drivers/spi/spi_imx.c b/drivers/spi/spi_imx.c
index c730d05bfeb68..bd0729b6b6ed3 100644
--- a/drivers/spi/spi_imx.c
+++ b/drivers/spi/spi_imx.c
@@ -29,6 +29,7 @@
 #include <linux/spi/spi.h>
 #include <linux/workqueue.h>
 #include <linux/delay.h>
+#include <linux/clk.h>
 
 #include <asm/io.h>
 #include <asm/irq.h>
@@ -250,6 +251,8 @@ struct driver_data {
 	int tx_dma_needs_unmap;
 	size_t tx_map_len;
 	u32 dummy_dma_buf ____cacheline_aligned;
+
+	struct clk *clk;
 };
 
 /* Runtime state */
@@ -855,15 +858,15 @@ static irqreturn_t spi_int(int irq, void *dev_id)
 	return drv_data->transfer_handler(drv_data);
 }
 
-static inline u32 spi_speed_hz(u32 data_rate)
+static inline u32 spi_speed_hz(struct driver_data *drv_data, u32 data_rate)
 {
-	return imx_get_perclk2() / (4 << ((data_rate) >> 13));
+	return clk_get_rate(drv_data->clk) / (4 << ((data_rate) >> 13));
 }
 
-static u32 spi_data_rate(u32 speed_hz)
+static u32 spi_data_rate(struct driver_data *drv_data, u32 speed_hz)
 {
 	u32 div;
-	u32 quantized_hz = imx_get_perclk2() >> 2;
+	u32 quantized_hz = clk_get_rate(drv_data->clk) >> 2;
 
 	for (div = SPI_PERCLK2_DIV_MIN;
 		div <= SPI_PERCLK2_DIV_MAX;
@@ -947,7 +950,7 @@ static void pump_transfers(unsigned long data)
 	tmp = transfer->speed_hz;
 	if (tmp == 0)
 		tmp = chip->max_speed_hz;
-	tmp = spi_data_rate(tmp);
+	tmp = spi_data_rate(drv_data, tmp);
 	u32_EDIT(control, SPI_CONTROL_DATARATE, tmp);
 
 	writel(control, regs + SPI_CONTROL);
@@ -1109,7 +1112,7 @@ static int transfer(struct spi_device *spi, struct spi_message *msg)
 	msg->actual_length = 0;
 
 	/* Per transfer setup check */
-	min_speed_hz = spi_speed_hz(SPI_CONTROL_DATARATE_MIN);
+	min_speed_hz = spi_speed_hz(drv_data, SPI_CONTROL_DATARATE_MIN);
 	max_speed_hz = spi->max_speed_hz;
 	list_for_each_entry(trans, &msg->transfers, transfer_list) {
 		tmp = trans->bits_per_word;
@@ -1176,6 +1179,7 @@ static int transfer(struct spi_device *spi, struct spi_message *msg)
    applied and notified to the calling driver. */
 static int setup(struct spi_device *spi)
 {
+	struct driver_data *drv_data = spi_master_get_devdata(spi->master);
 	struct spi_imx_chip *chip_info;
 	struct chip_data *chip;
 	int first_setup = 0;
@@ -1304,14 +1308,14 @@ static int setup(struct spi_device *spi)
 	chip->n_bytes = (tmp <= 8) ? 1 : 2;
 
 	/* SPI datarate */
-	tmp = spi_data_rate(spi->max_speed_hz);
+	tmp = spi_data_rate(drv_data, spi->max_speed_hz);
 	if (tmp == SPI_CONTROL_DATARATE_BAD) {
 		status = -EINVAL;
 		dev_err(&spi->dev,
 			"setup - "
 			"HW min speed (%d Hz) exceeds required "
 			"max speed (%d Hz)\n",
-			spi_speed_hz(SPI_CONTROL_DATARATE_MIN),
+			spi_speed_hz(drv_data, SPI_CONTROL_DATARATE_MIN),
 			spi->max_speed_hz);
 		if (first_setup)
 			goto err_first_setup;
@@ -1321,7 +1325,7 @@ static int setup(struct spi_device *spi)
 	} else {
 		u32_EDIT(chip->control, SPI_CONTROL_DATARATE, tmp);
 		/* Actual rounded max_speed_hz */
-		tmp = spi_speed_hz(tmp);
+		tmp = spi_speed_hz(drv_data, tmp);
 		spi->max_speed_hz = tmp;
 		chip->max_speed_hz = tmp;
 	}
@@ -1352,7 +1356,7 @@ static int setup(struct spi_device *spi)
 		chip->period & SPI_PERIOD_WAIT,
 		spi->mode,
 		spi->bits_per_word,
-		spi_speed_hz(SPI_CONTROL_DATARATE_MIN),
+		spi_speed_hz(drv_data, SPI_CONTROL_DATARATE_MIN),
 		spi->max_speed_hz);
 	return status;
 
@@ -1465,6 +1469,14 @@ static int __init spi_imx_probe(struct platform_device *pdev)
 		goto err_no_pdata;
 	}
 
+	drv_data->clk = clk_get(&pdev->dev, "perclk2");
+	if (IS_ERR(drv_data->clk)) {
+		dev_err(&pdev->dev, "probe - cannot get get\n");
+		status = PTR_ERR(drv_data->clk);
+		goto err_no_clk;
+	}
+	clk_enable(drv_data->clk);
+
 	/* Allocate master with space for drv_data */
 	master = spi_alloc_master(dev, sizeof(struct driver_data));
 	if (!master) {
@@ -1623,6 +1635,9 @@ static int __init spi_imx_probe(struct platform_device *pdev)
 	spi_master_put(master);
 
 err_no_pdata:
+	clk_disable(drv_data->clk);
+	clk_put(drv_data->clk);
+err_no_clk:
 err_no_mem:
 	return status;
 }
@@ -1662,6 +1677,9 @@ static int __exit spi_imx_remove(struct platform_device *pdev)
 	if (irq >= 0)
 		free_irq(irq, drv_data);
 
+	clk_disable(drv_data->clk);
+	clk_put(drv_data->clk);
+
 	/* Release map resources */
 	iounmap(drv_data->regs);
 	release_resource(drv_data->ioarea);
diff --git a/include/asm-arm/arch-imx/hardware.h b/include/asm-arm/arch-imx/hardware.h
index adffb6acf42a2..6542ca5e8c33f 100644
--- a/include/asm-arm/arch-imx/hardware.h
+++ b/include/asm-arm/arch-imx/hardware.h
@@ -73,14 +73,6 @@
  */
 extern void imx_gpio_mode( int gpio_mode );
 
-/* get frequencies in Hz */
-extern unsigned int imx_get_system_clk(void);
-extern unsigned int imx_get_mcu_clk(void);
-extern unsigned int imx_get_perclk1(void); /* UART[12], Timer[12], PWM */
-extern unsigned int imx_get_perclk2(void); /* LCD, SD, SPI[12]         */
-extern unsigned int imx_get_perclk3(void); /* SSI                      */
-extern unsigned int imx_get_hclk(void);    /* SDRAM, CSI, Memory Stick,*/
-                                           /* I2C, DMA                 */
 #endif
 
 #define MAXIRQNUM                       62
-- 
GitLab