From 609f9e92b570f390a457a81effe0af6b758dc582 Mon Sep 17 00:00:00 2001 From: Jonathan Corbet Date: Fri, 16 May 2008 13:46:14 -0600 Subject: spidev: BKL pushdown Add the BKL to spidev_open(), even though the existing locking looks adequate. Signed-off-by: Jonathan Corbet --- drivers/spi/spidev.c | 3 +++ 1 file changed, 3 insertions(+) (limited to 'drivers/spi') diff --git a/drivers/spi/spidev.c b/drivers/spi/spidev.c index b3518ca9f04e..ab2b769c83ca 100644 --- a/drivers/spi/spidev.c +++ b/drivers/spi/spidev.c @@ -29,6 +29,7 @@ #include #include #include +#include #include #include @@ -393,6 +394,7 @@ static int spidev_open(struct inode *inode, struct file *filp) struct spidev_data *spidev; int status = -ENXIO; + lock_kernel(); mutex_lock(&device_list_lock); list_for_each_entry(spidev, &device_list, device_entry) { @@ -418,6 +420,7 @@ static int spidev_open(struct inode *inode, struct file *filp) pr_debug("spidev: nothing for minor %d\n", iminor(inode)); mutex_unlock(&device_list_lock); + unlock_kernel(); return status; } -- cgit v1.2.3 From f7def13ed0775ee506c62a8612a124dce1776ac2 Mon Sep 17 00:00:00 2001 From: Paulius Zaleckas Date: Wed, 25 Jun 2008 13:25:13 +0100 Subject: [ARM] 5122/1: imx_dma_request_by_prio simpilfication imx_dma_request_by_prio can return channel number by itself. No need to supply variable address through parameters. Also converted all drivers using this function. Signed-off-by: Paulius Zaleckas Acked-by: Sascha Hauer Signed-off-by: Russell King --- arch/arm/mach-imx/dma.c | 13 ++++--------- drivers/mmc/host/imxmmc.c | 4 ++-- drivers/spi/spi_imx.c | 16 ++++++++-------- include/asm-arm/arch-imx/imx-dma.h | 2 +- 4 files changed, 15 insertions(+), 20 deletions(-) (limited to 'drivers/spi') diff --git a/arch/arm/mach-imx/dma.c b/arch/arm/mach-imx/dma.c index a59ff2987cb7..ee1c6f06ff64 100644 --- a/arch/arm/mach-imx/dma.c +++ b/arch/arm/mach-imx/dma.c @@ -410,7 +410,6 @@ void imx_dma_free(imx_dmach_t dma_ch) /** * imx_dma_request_by_prio - find and request some of free channels best suiting requested priority - * @dma_ch: i.MX DMA channel number * @name: the driver/caller own non-%NULL identification * @prio: one of the hardware distinguished priority level: * %DMA_PRIO_HIGH, %DMA_PRIO_MEDIUM, %DMA_PRIO_LOW @@ -420,11 +419,9 @@ void imx_dma_free(imx_dmach_t dma_ch) * in the higher and then even lower priority groups. * * Return value: If there is no free channel to allocate, -%ENODEV is returned. - * Zero value indicates successful channel allocation. + * On successful allocation channel is returned. */ -int -imx_dma_request_by_prio(imx_dmach_t * pdma_ch, const char *name, - imx_dma_prio prio) +imx_dmach_t imx_dma_request_by_prio(const char *name, imx_dma_prio prio) { int i; int best; @@ -444,15 +441,13 @@ imx_dma_request_by_prio(imx_dmach_t * pdma_ch, const char *name, for (i = best; i < IMX_DMA_CHANNELS; i++) { if (!imx_dma_request(i, name)) { - *pdma_ch = i; - return 0; + return i; } } for (i = best - 1; i >= 0; i--) { if (!imx_dma_request(i, name)) { - *pdma_ch = i; - return 0; + return i; } } diff --git a/drivers/mmc/host/imxmmc.c b/drivers/mmc/host/imxmmc.c index 95f33e87a99c..c4349c746cb3 100644 --- a/drivers/mmc/host/imxmmc.c +++ b/drivers/mmc/host/imxmmc.c @@ -1017,8 +1017,8 @@ static int imxmci_probe(struct platform_device *pdev) host->imask = IMXMCI_INT_MASK_DEFAULT; MMC_INT_MASK = host->imask; - - if(imx_dma_request_by_prio(&host->dma, DRIVER_NAME, DMA_PRIO_LOW)<0){ + host->dma = imx_dma_request_by_prio(DRIVER_NAME, DMA_PRIO_LOW); + if(host->dma < 0) { dev_err(mmc_dev(host->mmc), "imx_dma_request_by_prio failed\n"); ret = -EBUSY; goto out; diff --git a/drivers/spi/spi_imx.c b/drivers/spi/spi_imx.c index c730d05bfeb6..547e30298278 100644 --- a/drivers/spi/spi_imx.c +++ b/drivers/spi/spi_imx.c @@ -1526,24 +1526,24 @@ static int __init spi_imx_probe(struct platform_device *pdev) drv_data->rx_channel = -1; if (platform_info->enable_dma) { /* Get rx DMA channel */ - status = imx_dma_request_by_prio(&drv_data->rx_channel, - "spi_imx_rx", DMA_PRIO_HIGH); - if (status < 0) { + drv_data->rx_channel = imx_dma_request_by_prio("spi_imx_rx", + DMA_PRIO_HIGH); + if (drv_data->rx_channel < 0) { dev_err(dev, "probe - problem (%d) requesting rx channel\n", - status); + drv_data->rx_channel); goto err_no_rxdma; } else imx_dma_setup_handlers(drv_data->rx_channel, NULL, dma_err_handler, drv_data); /* Get tx DMA channel */ - status = imx_dma_request_by_prio(&drv_data->tx_channel, - "spi_imx_tx", DMA_PRIO_MEDIUM); - if (status < 0) { + drv_data->tx_channel = imx_dma_request_by_prio("spi_imx_tx", + DMA_PRIO_MEDIUM); + if (drv_data->tx_channel < 0) { dev_err(dev, "probe - problem (%d) requesting tx channel\n", - status); + drv_data->tx_channel); imx_dma_free(drv_data->rx_channel); goto err_no_txdma; } else diff --git a/include/asm-arm/arch-imx/imx-dma.h b/include/asm-arm/arch-imx/imx-dma.h index 5b1066da4e1f..44d89c35539a 100644 --- a/include/asm-arm/arch-imx/imx-dma.h +++ b/include/asm-arm/arch-imx/imx-dma.h @@ -88,7 +88,7 @@ int imx_dma_request(imx_dmach_t dma_ch, const char *name); void imx_dma_free(imx_dmach_t dma_ch); -int imx_dma_request_by_prio(imx_dmach_t *pdma_ch, const char *name, imx_dma_prio prio); +imx_dmach_t imx_dma_request_by_prio(const char *name, imx_dma_prio prio); #endif /* _ASM_ARCH_IMX_DMA_H */ -- cgit v1.2.3 From 38a41fdf94c449c165213e4665c3f8a0d30f8aba Mon Sep 17 00:00:00 2001 From: Sascha Hauer Date: Sat, 5 Jul 2008 10:02:46 +0200 Subject: 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 --- 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 (limited to 'drivers/spi') diff --git a/arch/arm/mach-imx/Makefile b/arch/arm/mach-imx/Makefile index 88d5e61a2e13..b047c7e795a9 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 000000000000..6a90fe5578df --- /dev/null +++ b/arch/arm/mach-imx/clock.c @@ -0,0 +1,205 @@ +/* + * Copyright (C) 2008 Sascha Hauer , 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 +#include +#include +#include +#include + +#include +#include + +/* + * 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 e548ba74a4d2..be0809b33e08 100644 --- a/arch/arm/mach-imx/cpufreq.c +++ b/arch/arm/mach-imx/cpufreq.c @@ -32,6 +32,8 @@ #include #include #include +#include +#include #include #include @@ -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 4cfc9d3af28a..98ddd8a6d05f 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 d86d124aea22..5a41e96e8586 100644 --- a/arch/arm/mach-imx/time.c +++ b/arch/arm/mach-imx/time.c @@ -17,6 +17,7 @@ #include #include #include +#include #include #include @@ -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 95f33e87a99c..ef2f6fc86541 100644 --- a/drivers/mmc/host/imxmmc.c +++ b/drivers/mmc/host/imxmmc.c @@ -42,6 +42,7 @@ #include #include #include +#include #include #include @@ -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 @@ out: 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 8d6cb745bd93..9e2162ebf1bb 100644 --- a/drivers/serial/imx.c +++ b/drivers/serial/imx.c @@ -40,6 +40,7 @@ #include #include #include +#include #include #include @@ -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 c730d05bfeb6..bd0729b6b6ed 100644 --- a/drivers/spi/spi_imx.c +++ b/drivers/spi/spi_imx.c @@ -29,6 +29,7 @@ #include #include #include +#include #include #include @@ -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 @@ msg_rejected: 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 @@ err_no_iores: 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 adffb6acf42a..6542ca5e8c33 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 -- cgit v1.2.3