From 1b49f10c69b45a8b169c69eaa127e7f91a32f7c7 Mon Sep 17 00:00:00 2001 From: Tomasz Figa Date: Wed, 16 Oct 2013 21:10:52 +0200 Subject: [PATCH 01/23] spi: s3c64xx: Do not require legacy DMA API in case of S3C64XX With support for amba-pl08x driver, on S3C64xx the generic DMA engine API can be used instead of the private s3c-dma interface. Signed-off-by: Tomasz Figa Signed-off-by: Mark Brown --- drivers/spi/Kconfig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/spi/Kconfig b/drivers/spi/Kconfig index eb1f1ef5fa2e..760d7b6b8591 100644 --- a/drivers/spi/Kconfig +++ b/drivers/spi/Kconfig @@ -395,7 +395,7 @@ config SPI_S3C24XX_FIQ config SPI_S3C64XX tristate "Samsung S3C64XX series type SPI" depends on PLAT_SAMSUNG - select S3C64XX_DMA if ARCH_S3C64XX + select S3C64XX_DMA if ARCH_S3C64XX && !S3C64XX_PL080 help SPI driver for Samsung S3C64XX and newer SoCs. From 1db0287ab186637488e51ae43109692624f2d5a3 Mon Sep 17 00:00:00 2001 From: Tomasz Figa Date: Wed, 16 Oct 2013 21:10:54 +0200 Subject: [PATCH 02/23] ARM: s3c64xx: Add support for DMA using generic amba-pl08x driver This patch adds all required platform-specific data and initialization code to support the generic amba-pl08x driver on S3C64xx SoCs. Also some compatibility definitions are added to make the transition from legacy API to DMA engine easier. The biggest hack here is passing const char * pointers through DMA resource, casted to unsigned long, but this is how Samsung DMA wrappers (used to support both s3c-dma and DMA engine in drivers) are designed. Signed-off-by: Tomasz Figa Signed-off-by: Mark Brown --- arch/arm/Kconfig | 1 + arch/arm/mach-s3c64xx/Kconfig | 8 +- arch/arm/mach-s3c64xx/Makefile | 1 + arch/arm/mach-s3c64xx/common.h | 5 + arch/arm/mach-s3c64xx/include/mach/dma.h | 63 ++++++ arch/arm/mach-s3c64xx/pl080.c | 244 +++++++++++++++++++++++ arch/arm/plat-samsung/devs.c | 10 +- arch/arm/plat-samsung/dma-ops.c | 8 +- 8 files changed, 336 insertions(+), 4 deletions(-) create mode 100644 arch/arm/mach-s3c64xx/pl080.c diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig index c1f1a7eee953..ba0e23234ecf 100644 --- a/arch/arm/Kconfig +++ b/arch/arm/Kconfig @@ -723,6 +723,7 @@ config ARCH_S3C64XX bool "Samsung S3C64XX" select ARCH_HAS_CPUFREQ select ARCH_REQUIRE_GPIOLIB + select ARM_AMBA select ARM_VIC select CLKDEV_LOOKUP select CLKSRC_SAMSUNG_PWM diff --git a/arch/arm/mach-s3c64xx/Kconfig b/arch/arm/mach-s3c64xx/Kconfig index 2cb8dc55b50e..d8e0288bf2bf 100644 --- a/arch/arm/mach-s3c64xx/Kconfig +++ b/arch/arm/mach-s3c64xx/Kconfig @@ -17,9 +17,15 @@ config CPU_S3C6410 help Enable S3C6410 CPU support +config S3C64XX_PL080 + bool "S3C64XX DMA using generic PL08x driver" + select AMBA_PL08X + select SAMSUNG_DMADEV + config S3C64XX_DMA - bool "S3C64XX DMA" + bool "S3C64XX DMA using legacy S3C DMA API" select S3C_DMA + depends on !S3C64XX_PL080 config S3C64XX_SETUP_SDHCI bool diff --git a/arch/arm/mach-s3c64xx/Makefile b/arch/arm/mach-s3c64xx/Makefile index 6faedcffce04..e8e9a468cbc9 100644 --- a/arch/arm/mach-s3c64xx/Makefile +++ b/arch/arm/mach-s3c64xx/Makefile @@ -27,6 +27,7 @@ obj-$(CONFIG_CPU_IDLE) += cpuidle.o # DMA support obj-$(CONFIG_S3C64XX_DMA) += dma.o +obj-$(CONFIG_S3C64XX_PL080) += pl080.o # Device support diff --git a/arch/arm/mach-s3c64xx/common.h b/arch/arm/mach-s3c64xx/common.h index bd3bd562011e..7043e7a3a67e 100644 --- a/arch/arm/mach-s3c64xx/common.h +++ b/arch/arm/mach-s3c64xx/common.h @@ -58,4 +58,9 @@ int __init s3c64xx_pm_late_initcall(void); static inline int s3c64xx_pm_late_initcall(void) { return 0; } #endif +#ifdef CONFIG_S3C64XX_PL080 +extern struct pl08x_platform_data s3c64xx_dma0_plat_data; +extern struct pl08x_platform_data s3c64xx_dma1_plat_data; +#endif + #endif /* __ARCH_ARM_MACH_S3C64XX_COMMON_H */ diff --git a/arch/arm/mach-s3c64xx/include/mach/dma.h b/arch/arm/mach-s3c64xx/include/mach/dma.h index fe1a98cf0e4c..26a6bc300589 100644 --- a/arch/arm/mach-s3c64xx/include/mach/dma.h +++ b/arch/arm/mach-s3c64xx/include/mach/dma.h @@ -11,6 +11,8 @@ #ifndef __ASM_ARCH_DMA_H #define __ASM_ARCH_DMA_H __FILE__ +#ifdef CONFIG_S3C64XX_DMA + #define S3C_DMA_CHANNELS (16) /* see mach-s3c2410/dma.h for notes on dma channel numbers */ @@ -128,4 +130,65 @@ struct s3c2410_dma_chan { #include +#else + +#define S3C64XX_DMA_CHAN(name) ((unsigned long)(name)) + +/* DMA0/SDMA0 */ +#define DMACH_UART0 S3C64XX_DMA_CHAN("uart0_tx") +#define DMACH_UART0_SRC2 S3C64XX_DMA_CHAN("uart0_rx") +#define DMACH_UART1 S3C64XX_DMA_CHAN("uart1_tx") +#define DMACH_UART1_SRC2 S3C64XX_DMA_CHAN("uart1_rx") +#define DMACH_UART2 S3C64XX_DMA_CHAN("uart2_tx") +#define DMACH_UART2_SRC2 S3C64XX_DMA_CHAN("uart2_rx") +#define DMACH_UART3 S3C64XX_DMA_CHAN("uart3_tx") +#define DMACH_UART3_SRC2 S3C64XX_DMA_CHAN("uart3_rx") +#define DMACH_PCM0_TX S3C64XX_DMA_CHAN("pcm0_tx") +#define DMACH_PCM0_RX S3C64XX_DMA_CHAN("pcm0_rx") +#define DMACH_I2S0_OUT S3C64XX_DMA_CHAN("i2s0_tx") +#define DMACH_I2S0_IN S3C64XX_DMA_CHAN("i2s0_rx") +#define DMACH_SPI0_TX S3C64XX_DMA_CHAN("spi0_tx") +#define DMACH_SPI0_RX S3C64XX_DMA_CHAN("spi0_rx") +#define DMACH_HSI_I2SV40_TX S3C64XX_DMA_CHAN("i2s2_tx") +#define DMACH_HSI_I2SV40_RX S3C64XX_DMA_CHAN("i2s2_rx") + +/* DMA1/SDMA1 */ +#define DMACH_PCM1_TX S3C64XX_DMA_CHAN("pcm1_tx") +#define DMACH_PCM1_RX S3C64XX_DMA_CHAN("pcm1_rx") +#define DMACH_I2S1_OUT S3C64XX_DMA_CHAN("i2s1_tx") +#define DMACH_I2S1_IN S3C64XX_DMA_CHAN("i2s1_rx") +#define DMACH_SPI1_TX S3C64XX_DMA_CHAN("spi1_tx") +#define DMACH_SPI1_RX S3C64XX_DMA_CHAN("spi1_rx") +#define DMACH_AC97_PCMOUT S3C64XX_DMA_CHAN("ac97_out") +#define DMACH_AC97_PCMIN S3C64XX_DMA_CHAN("ac97_in") +#define DMACH_AC97_MICIN S3C64XX_DMA_CHAN("ac97_mic") +#define DMACH_PWM S3C64XX_DMA_CHAN("pwm") +#define DMACH_IRDA S3C64XX_DMA_CHAN("irda") +#define DMACH_EXTERNAL S3C64XX_DMA_CHAN("external") +#define DMACH_SECURITY_RX S3C64XX_DMA_CHAN("sec_rx") +#define DMACH_SECURITY_TX S3C64XX_DMA_CHAN("sec_tx") + +enum dma_ch { + DMACH_MAX = 32 +}; + +struct s3c2410_dma_client { + char *name; +}; + +static inline bool samsung_dma_has_circular(void) +{ + return true; +} + +static inline bool samsung_dma_is_dmadev(void) +{ + return true; +} + +#include +#include + +#endif + #endif /* __ASM_ARCH_IRQ_H */ diff --git a/arch/arm/mach-s3c64xx/pl080.c b/arch/arm/mach-s3c64xx/pl080.c new file mode 100644 index 000000000000..901a984bddc2 --- /dev/null +++ b/arch/arm/mach-s3c64xx/pl080.c @@ -0,0 +1,244 @@ +/* + * Samsung's S3C64XX generic DMA support using amba-pl08x driver. + * + * Copyright (c) 2013 Tomasz Figa + * + * 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 +#include +#include +#include +#include + +#include +#include + +#include "regs-sys.h" + +static int pl08x_get_xfer_signal(const struct pl08x_channel_data *cd) +{ + return cd->min_signal; +} + +static void pl08x_put_xfer_signal(const struct pl08x_channel_data *cd, int ch) +{ +} + +/* + * DMA0 + */ + +static struct pl08x_channel_data s3c64xx_dma0_info[] = { + { + .bus_id = "uart0_tx", + .min_signal = 0, + .max_signal = 0, + .periph_buses = PL08X_AHB2, + }, { + .bus_id = "uart0_rx", + .min_signal = 1, + .max_signal = 1, + .periph_buses = PL08X_AHB2, + }, { + .bus_id = "uart1_tx", + .min_signal = 2, + .max_signal = 2, + .periph_buses = PL08X_AHB2, + }, { + .bus_id = "uart1_rx", + .min_signal = 3, + .max_signal = 3, + .periph_buses = PL08X_AHB2, + }, { + .bus_id = "uart2_tx", + .min_signal = 4, + .max_signal = 4, + .periph_buses = PL08X_AHB2, + }, { + .bus_id = "uart2_rx", + .min_signal = 5, + .max_signal = 5, + .periph_buses = PL08X_AHB2, + }, { + .bus_id = "uart3_tx", + .min_signal = 6, + .max_signal = 6, + .periph_buses = PL08X_AHB2, + }, { + .bus_id = "uart3_rx", + .min_signal = 7, + .max_signal = 7, + .periph_buses = PL08X_AHB2, + }, { + .bus_id = "pcm0_tx", + .min_signal = 8, + .max_signal = 8, + .periph_buses = PL08X_AHB2, + }, { + .bus_id = "pcm0_rx", + .min_signal = 9, + .max_signal = 9, + .periph_buses = PL08X_AHB2, + }, { + .bus_id = "i2s0_tx", + .min_signal = 10, + .max_signal = 10, + .periph_buses = PL08X_AHB2, + }, { + .bus_id = "i2s0_rx", + .min_signal = 11, + .max_signal = 11, + .periph_buses = PL08X_AHB2, + }, { + .bus_id = "spi0_tx", + .min_signal = 12, + .max_signal = 12, + .periph_buses = PL08X_AHB2, + }, { + .bus_id = "spi0_rx", + .min_signal = 13, + .max_signal = 13, + .periph_buses = PL08X_AHB2, + }, { + .bus_id = "i2s2_tx", + .min_signal = 14, + .max_signal = 14, + .periph_buses = PL08X_AHB2, + }, { + .bus_id = "i2s2_rx", + .min_signal = 15, + .max_signal = 15, + .periph_buses = PL08X_AHB2, + } +}; + +struct pl08x_platform_data s3c64xx_dma0_plat_data = { + .memcpy_channel = { + .bus_id = "memcpy", + .cctl_memcpy = + (PL080_BSIZE_4 << PL080_CONTROL_SB_SIZE_SHIFT | + PL080_BSIZE_4 << PL080_CONTROL_DB_SIZE_SHIFT | + PL080_WIDTH_32BIT << PL080_CONTROL_SWIDTH_SHIFT | + PL080_WIDTH_32BIT << PL080_CONTROL_DWIDTH_SHIFT | + PL080_CONTROL_PROT_BUFF | PL080_CONTROL_PROT_CACHE | + PL080_CONTROL_PROT_SYS), + }, + .lli_buses = PL08X_AHB1, + .mem_buses = PL08X_AHB1, + .get_xfer_signal = pl08x_get_xfer_signal, + .put_xfer_signal = pl08x_put_xfer_signal, + .slave_channels = s3c64xx_dma0_info, + .num_slave_channels = ARRAY_SIZE(s3c64xx_dma0_info), +}; + +static AMBA_AHB_DEVICE(s3c64xx_dma0, "dma-pl080s.0", 0, + 0x75000000, {IRQ_DMA0}, &s3c64xx_dma0_plat_data); + +/* + * DMA1 + */ + +static struct pl08x_channel_data s3c64xx_dma1_info[] = { + { + .bus_id = "pcm1_tx", + .min_signal = 0, + .max_signal = 0, + .periph_buses = PL08X_AHB2, + }, { + .bus_id = "pcm1_rx", + .min_signal = 1, + .max_signal = 1, + .periph_buses = PL08X_AHB2, + }, { + .bus_id = "i2s1_tx", + .min_signal = 2, + .max_signal = 2, + .periph_buses = PL08X_AHB2, + }, { + .bus_id = "i2s1_rx", + .min_signal = 3, + .max_signal = 3, + .periph_buses = PL08X_AHB2, + }, { + .bus_id = "spi1_tx", + .min_signal = 4, + .max_signal = 4, + .periph_buses = PL08X_AHB2, + }, { + .bus_id = "spi1_rx", + .min_signal = 5, + .max_signal = 5, + .periph_buses = PL08X_AHB2, + }, { + .bus_id = "ac97_out", + .min_signal = 6, + .max_signal = 6, + .periph_buses = PL08X_AHB2, + }, { + .bus_id = "ac97_in", + .min_signal = 7, + .max_signal = 7, + .periph_buses = PL08X_AHB2, + }, { + .bus_id = "ac97_mic", + .min_signal = 8, + .max_signal = 8, + .periph_buses = PL08X_AHB2, + }, { + .bus_id = "pwm", + .min_signal = 9, + .max_signal = 9, + .periph_buses = PL08X_AHB2, + }, { + .bus_id = "irda", + .min_signal = 10, + .max_signal = 10, + .periph_buses = PL08X_AHB2, + }, { + .bus_id = "external", + .min_signal = 11, + .max_signal = 11, + .periph_buses = PL08X_AHB2, + }, +}; + +struct pl08x_platform_data s3c64xx_dma1_plat_data = { + .memcpy_channel = { + .bus_id = "memcpy", + .cctl_memcpy = + (PL080_BSIZE_4 << PL080_CONTROL_SB_SIZE_SHIFT | + PL080_BSIZE_4 << PL080_CONTROL_DB_SIZE_SHIFT | + PL080_WIDTH_32BIT << PL080_CONTROL_SWIDTH_SHIFT | + PL080_WIDTH_32BIT << PL080_CONTROL_DWIDTH_SHIFT | + PL080_CONTROL_PROT_BUFF | PL080_CONTROL_PROT_CACHE | + PL080_CONTROL_PROT_SYS), + }, + .lli_buses = PL08X_AHB1, + .mem_buses = PL08X_AHB1, + .get_xfer_signal = pl08x_get_xfer_signal, + .put_xfer_signal = pl08x_put_xfer_signal, + .slave_channels = s3c64xx_dma1_info, + .num_slave_channels = ARRAY_SIZE(s3c64xx_dma1_info), +}; + +static AMBA_AHB_DEVICE(s3c64xx_dma1, "dma-pl080s.1", 0, + 0x75100000, {IRQ_DMA1}, &s3c64xx_dma1_plat_data); + +static int __init s3c64xx_pl080_init(void) +{ + /* Set all DMA configuration to be DMA, not SDMA */ + writel(0xffffff, S3C64XX_SDMA_SEL); + + if (of_have_populated_dt()) + return 0; + + amba_device_register(&s3c64xx_dma0_device, &iomem_resource); + amba_device_register(&s3c64xx_dma1_device, &iomem_resource); + + return 0; +} +arch_initcall(s3c64xx_pl080_init); diff --git a/arch/arm/plat-samsung/devs.c b/arch/arm/plat-samsung/devs.c index 99a3590f0349..ac07e871f6a7 100644 --- a/arch/arm/plat-samsung/devs.c +++ b/arch/arm/plat-samsung/devs.c @@ -1468,6 +1468,8 @@ void __init s3c64xx_spi0_set_platdata(int (*cfg_gpio)(void), int src_clk_nr, pd.cfg_gpio = (cfg_gpio) ? cfg_gpio : s3c64xx_spi0_cfg_gpio; #if defined(CONFIG_PL330_DMA) pd.filter = pl330_filter; +#elif defined(CONFIG_S3C64XX_PL080) + pd.filter = pl08x_filter_id; #elif defined(CONFIG_S3C24XX_DMAC) pd.filter = s3c24xx_dma_filter; #endif @@ -1509,8 +1511,10 @@ void __init s3c64xx_spi1_set_platdata(int (*cfg_gpio)(void), int src_clk_nr, pd.num_cs = num_cs; pd.src_clk_nr = src_clk_nr; pd.cfg_gpio = (cfg_gpio) ? cfg_gpio : s3c64xx_spi1_cfg_gpio; -#ifdef CONFIG_PL330_DMA +#if defined(CONFIG_PL330_DMA) pd.filter = pl330_filter; +#elif defined(CONFIG_S3C64XX_PL080) + pd.filter = pl08x_filter_id; #endif s3c_set_platdata(&pd, sizeof(pd), &s3c64xx_device_spi1); @@ -1550,8 +1554,10 @@ void __init s3c64xx_spi2_set_platdata(int (*cfg_gpio)(void), int src_clk_nr, pd.num_cs = num_cs; pd.src_clk_nr = src_clk_nr; pd.cfg_gpio = (cfg_gpio) ? cfg_gpio : s3c64xx_spi2_cfg_gpio; -#ifdef CONFIG_PL330_DMA +#if defined(CONFIG_PL330_DMA) pd.filter = pl330_filter; +#elif defined(CONFIG_S3C64XX_PL080) + pd.filter = pl08x_filter_id; #endif s3c_set_platdata(&pd, sizeof(pd), &s3c64xx_device_spi2); diff --git a/arch/arm/plat-samsung/dma-ops.c b/arch/arm/plat-samsung/dma-ops.c index ec0d731b0e7b..886326ee6f6c 100644 --- a/arch/arm/plat-samsung/dma-ops.c +++ b/arch/arm/plat-samsung/dma-ops.c @@ -18,6 +18,12 @@ #include +#if defined(CONFIG_PL330_DMA) +#define dma_filter pl330_filter +#elif defined(CONFIG_S3C64XX_PL080) +#define dma_filter pl08x_filter_id +#endif + static unsigned samsung_dmadev_request(enum dma_ch dma_ch, struct samsung_dma_req *param, struct device *dev, char *ch_name) @@ -30,7 +36,7 @@ static unsigned samsung_dmadev_request(enum dma_ch dma_ch, if (dev->of_node) return (unsigned)dma_request_slave_channel(dev, ch_name); else - return (unsigned)dma_request_channel(mask, pl330_filter, + return (unsigned)dma_request_channel(mask, dma_filter, (void *)dma_ch); } From d37f7617bd677c46c49daa3c023920cb91fe14db Mon Sep 17 00:00:00 2001 From: Tomasz Figa Date: Wed, 16 Oct 2013 21:10:55 +0200 Subject: [PATCH 03/23] clk: samsung: s3c64xx: Add aliases for DMA clocks This patch adds clkdev aliases for clocks used by PL08x DMA driver. Signed-off-by: Tomasz Figa Signed-off-by: Mark Brown --- drivers/clk/samsung/clk-s3c64xx.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/clk/samsung/clk-s3c64xx.c b/drivers/clk/samsung/clk-s3c64xx.c index 7d2c84265947..06cf10592f52 100644 --- a/drivers/clk/samsung/clk-s3c64xx.c +++ b/drivers/clk/samsung/clk-s3c64xx.c @@ -332,7 +332,9 @@ static struct samsung_clock_alias s3c64xx_clock_aliases[] = { ALIAS(HCLK_HSMMC0, "s3c-sdhci.0", "hsmmc"), ALIAS(HCLK_HSMMC0, "s3c-sdhci.0", "mmc_busclk.0"), ALIAS(HCLK_DMA1, NULL, "dma1"), + ALIAS(HCLK_DMA1, "dma-pl080s.1", "apb_pclk"), ALIAS(HCLK_DMA0, NULL, "dma0"), + ALIAS(HCLK_DMA0, "dma-pl080s.0", "apb_pclk"), ALIAS(HCLK_CAMIF, "s3c-camif", "camif"), ALIAS(HCLK_LCD, "s3c-fb", "lcd"), ALIAS(PCLK_SPI1, "s3c6410-spi.1", "spi"), From 15469ed37f8a9c004ac537495f9f7c51790a80c0 Mon Sep 17 00:00:00 2001 From: Tomasz Figa Date: Wed, 16 Oct 2013 21:10:56 +0200 Subject: [PATCH 04/23] ARM: s3c64xx: Remove legacy DMA driver Since support for generic PL08x DMA engine driver has been added, there is no need to keep the old legacy driver, so this patch removes it. Signed-off-by: Tomasz Figa Signed-off-by: Mark Brown --- arch/arm/mach-s3c64xx/Kconfig | 5 - arch/arm/mach-s3c64xx/Makefile | 1 - arch/arm/mach-s3c64xx/dma.c | 762 ----------------------- arch/arm/mach-s3c64xx/include/mach/dma.h | 123 ---- 4 files changed, 891 deletions(-) delete mode 100644 arch/arm/mach-s3c64xx/dma.c diff --git a/arch/arm/mach-s3c64xx/Kconfig b/arch/arm/mach-s3c64xx/Kconfig index d8e0288bf2bf..7094bccbae91 100644 --- a/arch/arm/mach-s3c64xx/Kconfig +++ b/arch/arm/mach-s3c64xx/Kconfig @@ -22,11 +22,6 @@ config S3C64XX_PL080 select AMBA_PL08X select SAMSUNG_DMADEV -config S3C64XX_DMA - bool "S3C64XX DMA using legacy S3C DMA API" - select S3C_DMA - depends on !S3C64XX_PL080 - config S3C64XX_SETUP_SDHCI bool select S3C64XX_SETUP_SDHCI_GPIO diff --git a/arch/arm/mach-s3c64xx/Makefile b/arch/arm/mach-s3c64xx/Makefile index e8e9a468cbc9..58069a702a43 100644 --- a/arch/arm/mach-s3c64xx/Makefile +++ b/arch/arm/mach-s3c64xx/Makefile @@ -26,7 +26,6 @@ obj-$(CONFIG_CPU_IDLE) += cpuidle.o # DMA support -obj-$(CONFIG_S3C64XX_DMA) += dma.o obj-$(CONFIG_S3C64XX_PL080) += pl080.o # Device support diff --git a/arch/arm/mach-s3c64xx/dma.c b/arch/arm/mach-s3c64xx/dma.c deleted file mode 100644 index 7e22c2113816..000000000000 --- a/arch/arm/mach-s3c64xx/dma.c +++ /dev/null @@ -1,762 +0,0 @@ -/* linux/arch/arm/plat-s3c64xx/dma.c - * - * Copyright 2009 Openmoko, Inc. - * Copyright 2009 Simtec Electronics - * Ben Dooks - * http://armlinux.simtec.co.uk/ - * - * S3C64XX DMA core - * - * 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. -*/ - -/* - * NOTE: Code in this file is not used when booting with Device Tree support. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include - -#include "regs-sys.h" - -/* dma channel state information */ - -struct s3c64xx_dmac { - struct device dev; - struct clk *clk; - void __iomem *regs; - struct s3c2410_dma_chan *channels; - enum dma_ch chanbase; -}; - -/* pool to provide LLI buffers */ -static struct dma_pool *dma_pool; - -/* Debug configuration and code */ - -static unsigned char debug_show_buffs = 0; - -static void dbg_showchan(struct s3c2410_dma_chan *chan) -{ - pr_debug("DMA%d: %08x->%08x L %08x C %08x,%08x S %08x\n", - chan->number, - readl(chan->regs + PL080_CH_SRC_ADDR), - readl(chan->regs + PL080_CH_DST_ADDR), - readl(chan->regs + PL080_CH_LLI), - readl(chan->regs + PL080_CH_CONTROL), - readl(chan->regs + PL080S_CH_CONTROL2), - readl(chan->regs + PL080S_CH_CONFIG)); -} - -static void show_lli(struct pl080s_lli *lli) -{ - pr_debug("LLI[%p] %08x->%08x, NL %08x C %08x,%08x\n", - lli, lli->src_addr, lli->dst_addr, lli->next_lli, - lli->control0, lli->control1); -} - -static void dbg_showbuffs(struct s3c2410_dma_chan *chan) -{ - struct s3c64xx_dma_buff *ptr; - struct s3c64xx_dma_buff *end; - - pr_debug("DMA%d: buffs next %p, curr %p, end %p\n", - chan->number, chan->next, chan->curr, chan->end); - - ptr = chan->next; - end = chan->end; - - if (debug_show_buffs) { - for (; ptr != NULL; ptr = ptr->next) { - pr_debug("DMA%d: %08x ", - chan->number, ptr->lli_dma); - show_lli(ptr->lli); - } - } -} - -/* End of Debug */ - -static struct s3c2410_dma_chan *s3c64xx_dma_map_channel(unsigned int channel) -{ - struct s3c2410_dma_chan *chan; - unsigned int start, offs; - - start = 0; - - if (channel >= DMACH_PCM1_TX) - start = 8; - - for (offs = 0; offs < 8; offs++) { - chan = &s3c2410_chans[start + offs]; - if (!chan->in_use) - goto found; - } - - return NULL; - -found: - s3c_dma_chan_map[channel] = chan; - return chan; -} - -int s3c2410_dma_config(enum dma_ch channel, int xferunit) -{ - struct s3c2410_dma_chan *chan = s3c_dma_lookup_channel(channel); - - if (chan == NULL) - return -EINVAL; - - switch (xferunit) { - case 1: - chan->hw_width = 0; - break; - case 2: - chan->hw_width = 1; - break; - case 4: - chan->hw_width = 2; - break; - default: - printk(KERN_ERR "%s: illegal width %d\n", __func__, xferunit); - return -EINVAL; - } - - return 0; -} -EXPORT_SYMBOL(s3c2410_dma_config); - -static void s3c64xx_dma_fill_lli(struct s3c2410_dma_chan *chan, - struct pl080s_lli *lli, - dma_addr_t data, int size) -{ - dma_addr_t src, dst; - u32 control0, control1; - - switch (chan->source) { - case DMA_FROM_DEVICE: - src = chan->dev_addr; - dst = data; - control0 = PL080_CONTROL_SRC_AHB2; - control0 |= PL080_CONTROL_DST_INCR; - break; - - case DMA_TO_DEVICE: - src = data; - dst = chan->dev_addr; - control0 = PL080_CONTROL_DST_AHB2; - control0 |= PL080_CONTROL_SRC_INCR; - break; - default: - BUG(); - } - - /* note, we do not currently setup any of the burst controls */ - - control1 = size >> chan->hw_width; /* size in no of xfers */ - control0 |= PL080_CONTROL_PROT_SYS; /* always in priv. mode */ - control0 |= PL080_CONTROL_TC_IRQ_EN; /* always fire IRQ */ - control0 |= (u32)chan->hw_width << PL080_CONTROL_DWIDTH_SHIFT; - control0 |= (u32)chan->hw_width << PL080_CONTROL_SWIDTH_SHIFT; - - lli->src_addr = src; - lli->dst_addr = dst; - lli->next_lli = 0; - lli->control0 = control0; - lli->control1 = control1; -} - -static void s3c64xx_lli_to_regs(struct s3c2410_dma_chan *chan, - struct pl080s_lli *lli) -{ - void __iomem *regs = chan->regs; - - pr_debug("%s: LLI %p => regs\n", __func__, lli); - show_lli(lli); - - writel(lli->src_addr, regs + PL080_CH_SRC_ADDR); - writel(lli->dst_addr, regs + PL080_CH_DST_ADDR); - writel(lli->next_lli, regs + PL080_CH_LLI); - writel(lli->control0, regs + PL080_CH_CONTROL); - writel(lli->control1, regs + PL080S_CH_CONTROL2); -} - -static int s3c64xx_dma_start(struct s3c2410_dma_chan *chan) -{ - struct s3c64xx_dmac *dmac = chan->dmac; - u32 config; - u32 bit = chan->bit; - - dbg_showchan(chan); - - pr_debug("%s: clearing interrupts\n", __func__); - - /* clear interrupts */ - writel(bit, dmac->regs + PL080_TC_CLEAR); - writel(bit, dmac->regs + PL080_ERR_CLEAR); - - pr_debug("%s: starting channel\n", __func__); - - config = readl(chan->regs + PL080S_CH_CONFIG); - config |= PL080_CONFIG_ENABLE; - config &= ~PL080_CONFIG_HALT; - - pr_debug("%s: writing config %08x\n", __func__, config); - writel(config, chan->regs + PL080S_CH_CONFIG); - - return 0; -} - -static int s3c64xx_dma_stop(struct s3c2410_dma_chan *chan) -{ - u32 config; - int timeout; - - pr_debug("%s: stopping channel\n", __func__); - - dbg_showchan(chan); - - config = readl(chan->regs + PL080S_CH_CONFIG); - config |= PL080_CONFIG_HALT; - writel(config, chan->regs + PL080S_CH_CONFIG); - - timeout = 1000; - do { - config = readl(chan->regs + PL080S_CH_CONFIG); - pr_debug("%s: %d - config %08x\n", __func__, timeout, config); - if (config & PL080_CONFIG_ACTIVE) - udelay(10); - else - break; - } while (--timeout > 0); - - if (config & PL080_CONFIG_ACTIVE) { - printk(KERN_ERR "%s: channel still active\n", __func__); - return -EFAULT; - } - - config = readl(chan->regs + PL080S_CH_CONFIG); - config &= ~PL080_CONFIG_ENABLE; - writel(config, chan->regs + PL080S_CH_CONFIG); - - return 0; -} - -static inline void s3c64xx_dma_bufffdone(struct s3c2410_dma_chan *chan, - struct s3c64xx_dma_buff *buf, - enum s3c2410_dma_buffresult result) -{ - if (chan->callback_fn != NULL) - (chan->callback_fn)(chan, buf->pw, 0, result); -} - -static void s3c64xx_dma_freebuff(struct s3c64xx_dma_buff *buff) -{ - dma_pool_free(dma_pool, buff->lli, buff->lli_dma); - kfree(buff); -} - -static int s3c64xx_dma_flush(struct s3c2410_dma_chan *chan) -{ - struct s3c64xx_dma_buff *buff, *next; - u32 config; - - dbg_showchan(chan); - - pr_debug("%s: flushing channel\n", __func__); - - config = readl(chan->regs + PL080S_CH_CONFIG); - config &= ~PL080_CONFIG_ENABLE; - writel(config, chan->regs + PL080S_CH_CONFIG); - - /* dump all the buffers associated with this channel */ - - for (buff = chan->curr; buff != NULL; buff = next) { - next = buff->next; - pr_debug("%s: buff %p (next %p)\n", __func__, buff, buff->next); - - s3c64xx_dma_bufffdone(chan, buff, S3C2410_RES_ABORT); - s3c64xx_dma_freebuff(buff); - } - - chan->curr = chan->next = chan->end = NULL; - - return 0; -} - -int s3c2410_dma_ctrl(enum dma_ch channel, enum s3c2410_chan_op op) -{ - struct s3c2410_dma_chan *chan = s3c_dma_lookup_channel(channel); - - WARN_ON(!chan); - if (!chan) - return -EINVAL; - - switch (op) { - case S3C2410_DMAOP_START: - return s3c64xx_dma_start(chan); - - case S3C2410_DMAOP_STOP: - return s3c64xx_dma_stop(chan); - - case S3C2410_DMAOP_FLUSH: - return s3c64xx_dma_flush(chan); - - /* believe PAUSE/RESUME are no-ops */ - case S3C2410_DMAOP_PAUSE: - case S3C2410_DMAOP_RESUME: - case S3C2410_DMAOP_STARTED: - case S3C2410_DMAOP_TIMEOUT: - return 0; - } - - return -ENOENT; -} -EXPORT_SYMBOL(s3c2410_dma_ctrl); - -/* s3c2410_dma_enque - * - */ - -int s3c2410_dma_enqueue(enum dma_ch channel, void *id, - dma_addr_t data, int size) -{ - struct s3c2410_dma_chan *chan = s3c_dma_lookup_channel(channel); - struct s3c64xx_dma_buff *next; - struct s3c64xx_dma_buff *buff; - struct pl080s_lli *lli; - unsigned long flags; - int ret; - - WARN_ON(!chan); - if (!chan) - return -EINVAL; - - buff = kzalloc(sizeof(struct s3c64xx_dma_buff), GFP_ATOMIC); - if (!buff) { - printk(KERN_ERR "%s: no memory for buffer\n", __func__); - return -ENOMEM; - } - - lli = dma_pool_alloc(dma_pool, GFP_ATOMIC, &buff->lli_dma); - if (!lli) { - printk(KERN_ERR "%s: no memory for lli\n", __func__); - ret = -ENOMEM; - goto err_buff; - } - - pr_debug("%s: buff %p, dp %08x lli (%p, %08x) %d\n", - __func__, buff, data, lli, (u32)buff->lli_dma, size); - - buff->lli = lli; - buff->pw = id; - - s3c64xx_dma_fill_lli(chan, lli, data, size); - - local_irq_save(flags); - - if ((next = chan->next) != NULL) { - struct s3c64xx_dma_buff *end = chan->end; - struct pl080s_lli *endlli = end->lli; - - pr_debug("enquing onto channel\n"); - - end->next = buff; - endlli->next_lli = buff->lli_dma; - - if (chan->flags & S3C2410_DMAF_CIRCULAR) { - struct s3c64xx_dma_buff *curr = chan->curr; - lli->next_lli = curr->lli_dma; - } - - if (next == chan->curr) { - writel(buff->lli_dma, chan->regs + PL080_CH_LLI); - chan->next = buff; - } - - show_lli(endlli); - chan->end = buff; - } else { - pr_debug("enquing onto empty channel\n"); - - chan->curr = buff; - chan->next = buff; - chan->end = buff; - - s3c64xx_lli_to_regs(chan, lli); - } - - local_irq_restore(flags); - - show_lli(lli); - - dbg_showchan(chan); - dbg_showbuffs(chan); - return 0; - -err_buff: - kfree(buff); - return ret; -} - -EXPORT_SYMBOL(s3c2410_dma_enqueue); - - -int s3c2410_dma_devconfig(enum dma_ch channel, - enum dma_data_direction source, - unsigned long devaddr) -{ - struct s3c2410_dma_chan *chan = s3c_dma_lookup_channel(channel); - u32 peripheral; - u32 config = 0; - - pr_debug("%s: channel %d, source %d, dev %08lx, chan %p\n", - __func__, channel, source, devaddr, chan); - - WARN_ON(!chan); - if (!chan) - return -EINVAL; - - peripheral = (chan->peripheral & 0xf); - chan->source = source; - chan->dev_addr = devaddr; - - pr_debug("%s: peripheral %d\n", __func__, peripheral); - - switch (source) { - case DMA_FROM_DEVICE: - config = 2 << PL080_CONFIG_FLOW_CONTROL_SHIFT; - config |= peripheral << PL080_CONFIG_SRC_SEL_SHIFT; - break; - case DMA_TO_DEVICE: - config = 1 << PL080_CONFIG_FLOW_CONTROL_SHIFT; - config |= peripheral << PL080_CONFIG_DST_SEL_SHIFT; - break; - default: - printk(KERN_ERR "%s: bad source\n", __func__); - return -EINVAL; - } - - /* allow TC and ERR interrupts */ - config |= PL080_CONFIG_TC_IRQ_MASK; - config |= PL080_CONFIG_ERR_IRQ_MASK; - - pr_debug("%s: config %08x\n", __func__, config); - - writel(config, chan->regs + PL080S_CH_CONFIG); - - return 0; -} -EXPORT_SYMBOL(s3c2410_dma_devconfig); - - -int s3c2410_dma_getposition(enum dma_ch channel, - dma_addr_t *src, dma_addr_t *dst) -{ - struct s3c2410_dma_chan *chan = s3c_dma_lookup_channel(channel); - - WARN_ON(!chan); - if (!chan) - return -EINVAL; - - if (src != NULL) - *src = readl(chan->regs + PL080_CH_SRC_ADDR); - - if (dst != NULL) - *dst = readl(chan->regs + PL080_CH_DST_ADDR); - - return 0; -} -EXPORT_SYMBOL(s3c2410_dma_getposition); - -/* s3c2410_request_dma - * - * get control of an dma channel -*/ - -int s3c2410_dma_request(enum dma_ch channel, - struct s3c2410_dma_client *client, - void *dev) -{ - struct s3c2410_dma_chan *chan; - unsigned long flags; - - pr_debug("dma%d: s3c2410_request_dma: client=%s, dev=%p\n", - channel, client->name, dev); - - local_irq_save(flags); - - chan = s3c64xx_dma_map_channel(channel); - if (chan == NULL) { - local_irq_restore(flags); - return -EBUSY; - } - - dbg_showchan(chan); - - chan->client = client; - chan->in_use = 1; - chan->peripheral = channel; - chan->flags = 0; - - local_irq_restore(flags); - - /* need to setup */ - - pr_debug("%s: channel initialised, %p\n", __func__, chan); - - return chan->number | DMACH_LOW_LEVEL; -} - -EXPORT_SYMBOL(s3c2410_dma_request); - -/* s3c2410_dma_free - * - * release the given channel back to the system, will stop and flush - * any outstanding transfers, and ensure the channel is ready for the - * next claimant. - * - * Note, although a warning is currently printed if the freeing client - * info is not the same as the registrant's client info, the free is still - * allowed to go through. -*/ - -int s3c2410_dma_free(enum dma_ch channel, struct s3c2410_dma_client *client) -{ - struct s3c2410_dma_chan *chan = s3c_dma_lookup_channel(channel); - unsigned long flags; - - if (chan == NULL) - return -EINVAL; - - local_irq_save(flags); - - if (chan->client != client) { - printk(KERN_WARNING "dma%d: possible free from different client (channel %p, passed %p)\n", - channel, chan->client, client); - } - - /* sort out stopping and freeing the channel */ - - - chan->client = NULL; - chan->in_use = 0; - - if (!(channel & DMACH_LOW_LEVEL)) - s3c_dma_chan_map[channel] = NULL; - - local_irq_restore(flags); - - return 0; -} - -EXPORT_SYMBOL(s3c2410_dma_free); - -static irqreturn_t s3c64xx_dma_irq(int irq, void *pw) -{ - struct s3c64xx_dmac *dmac = pw; - struct s3c2410_dma_chan *chan; - enum s3c2410_dma_buffresult res; - u32 tcstat, errstat; - u32 bit; - int offs; - - tcstat = readl(dmac->regs + PL080_TC_STATUS); - errstat = readl(dmac->regs + PL080_ERR_STATUS); - - for (offs = 0, bit = 1; offs < 8; offs++, bit <<= 1) { - struct s3c64xx_dma_buff *buff; - - if (!(errstat & bit) && !(tcstat & bit)) - continue; - - chan = dmac->channels + offs; - res = S3C2410_RES_ERR; - - if (tcstat & bit) { - writel(bit, dmac->regs + PL080_TC_CLEAR); - res = S3C2410_RES_OK; - } - - if (errstat & bit) - writel(bit, dmac->regs + PL080_ERR_CLEAR); - - /* 'next' points to the buffer that is next to the - * currently active buffer. - * For CIRCULAR queues, 'next' will be same as 'curr' - * when 'end' is the active buffer. - */ - buff = chan->curr; - while (buff && buff != chan->next - && buff->next != chan->next) - buff = buff->next; - - if (!buff) - BUG(); - - if (buff == chan->next) - buff = chan->end; - - s3c64xx_dma_bufffdone(chan, buff, res); - - /* Free the node and update curr, if non-circular queue */ - if (!(chan->flags & S3C2410_DMAF_CIRCULAR)) { - chan->curr = buff->next; - s3c64xx_dma_freebuff(buff); - } - - /* Update 'next' */ - buff = chan->next; - if (chan->next == chan->end) { - chan->next = chan->curr; - if (!(chan->flags & S3C2410_DMAF_CIRCULAR)) - chan->end = NULL; - } else { - chan->next = buff->next; - } - } - - return IRQ_HANDLED; -} - -static struct bus_type dma_subsys = { - .name = "s3c64xx-dma", - .dev_name = "s3c64xx-dma", -}; - -static int s3c64xx_dma_init1(int chno, enum dma_ch chbase, - int irq, unsigned int base) -{ - struct s3c2410_dma_chan *chptr = &s3c2410_chans[chno]; - struct s3c64xx_dmac *dmac; - char clkname[16]; - void __iomem *regs; - void __iomem *regptr; - int err, ch; - - dmac = kzalloc(sizeof(struct s3c64xx_dmac), GFP_KERNEL); - if (!dmac) { - printk(KERN_ERR "%s: failed to alloc mem\n", __func__); - return -ENOMEM; - } - - dmac->dev.id = chno / 8; - dmac->dev.bus = &dma_subsys; - - err = device_register(&dmac->dev); - if (err) { - printk(KERN_ERR "%s: failed to register device\n", __func__); - goto err_alloc; - } - - regs = ioremap(base, 0x200); - if (!regs) { - printk(KERN_ERR "%s: failed to ioremap()\n", __func__); - err = -ENXIO; - goto err_dev; - } - - snprintf(clkname, sizeof(clkname), "dma%d", dmac->dev.id); - - dmac->clk = clk_get(NULL, clkname); - if (IS_ERR(dmac->clk)) { - printk(KERN_ERR "%s: failed to get clock %s\n", __func__, clkname); - err = PTR_ERR(dmac->clk); - goto err_map; - } - - clk_prepare_enable(dmac->clk); - - dmac->regs = regs; - dmac->chanbase = chbase; - dmac->channels = chptr; - - err = request_irq(irq, s3c64xx_dma_irq, 0, "DMA", dmac); - if (err < 0) { - printk(KERN_ERR "%s: failed to get irq\n", __func__); - goto err_clk; - } - - regptr = regs + PL080_Cx_BASE(0); - - for (ch = 0; ch < 8; ch++, chptr++) { - pr_debug("%s: registering DMA %d (%p)\n", - __func__, chno + ch, regptr); - - chptr->bit = 1 << ch; - chptr->number = chno + ch; - chptr->dmac = dmac; - chptr->regs = regptr; - regptr += PL080_Cx_STRIDE; - } - - /* for the moment, permanently enable the controller */ - writel(PL080_CONFIG_ENABLE, regs + PL080_CONFIG); - - printk(KERN_INFO "PL080: IRQ %d, at %p, channels %d..%d\n", - irq, regs, chno, chno+8); - - return 0; - -err_clk: - clk_disable_unprepare(dmac->clk); - clk_put(dmac->clk); -err_map: - iounmap(regs); -err_dev: - device_unregister(&dmac->dev); -err_alloc: - kfree(dmac); - return err; -} - -static int __init s3c64xx_dma_init(void) -{ - int ret; - - /* This driver is not supported when booting with device tree. */ - if (of_have_populated_dt()) - return -ENODEV; - - printk(KERN_INFO "%s: Registering DMA channels\n", __func__); - - dma_pool = dma_pool_create("DMA-LLI", NULL, sizeof(struct pl080s_lli), 16, 0); - if (!dma_pool) { - printk(KERN_ERR "%s: failed to create pool\n", __func__); - return -ENOMEM; - } - - ret = subsys_system_register(&dma_subsys, NULL); - if (ret) { - printk(KERN_ERR "%s: failed to create subsys\n", __func__); - return -ENOMEM; - } - - /* Set all DMA configuration to be DMA, not SDMA */ - writel(0xffffff, S3C64XX_SDMA_SEL); - - /* Register standard DMA controllers */ - s3c64xx_dma_init1(0, DMACH_UART0, IRQ_DMA0, 0x75000000); - s3c64xx_dma_init1(8, DMACH_PCM1_TX, IRQ_DMA1, 0x75100000); - - return 0; -} - -arch_initcall(s3c64xx_dma_init); diff --git a/arch/arm/mach-s3c64xx/include/mach/dma.h b/arch/arm/mach-s3c64xx/include/mach/dma.h index 26a6bc300589..059b1fc85037 100644 --- a/arch/arm/mach-s3c64xx/include/mach/dma.h +++ b/arch/arm/mach-s3c64xx/include/mach/dma.h @@ -11,127 +11,6 @@ #ifndef __ASM_ARCH_DMA_H #define __ASM_ARCH_DMA_H __FILE__ -#ifdef CONFIG_S3C64XX_DMA - -#define S3C_DMA_CHANNELS (16) - -/* see mach-s3c2410/dma.h for notes on dma channel numbers */ - -/* Note, for the S3C64XX architecture we keep the DMACH_ - * defines in the order they are allocated to [S]DMA0/[S]DMA1 - * so that is easy to do DHACH_ -> DMA controller conversion - */ -enum dma_ch { - /* DMA0/SDMA0 */ - DMACH_UART0 = 0, - DMACH_UART0_SRC2, - DMACH_UART1, - DMACH_UART1_SRC2, - DMACH_UART2, - DMACH_UART2_SRC2, - DMACH_UART3, - DMACH_UART3_SRC2, - DMACH_PCM0_TX, - DMACH_PCM0_RX, - DMACH_I2S0_OUT, - DMACH_I2S0_IN, - DMACH_SPI0_TX, - DMACH_SPI0_RX, - DMACH_HSI_I2SV40_TX, - DMACH_HSI_I2SV40_RX, - - /* DMA1/SDMA1 */ - DMACH_PCM1_TX = 16, - DMACH_PCM1_RX, - DMACH_I2S1_OUT, - DMACH_I2S1_IN, - DMACH_SPI1_TX, - DMACH_SPI1_RX, - DMACH_AC97_PCMOUT, - DMACH_AC97_PCMIN, - DMACH_AC97_MICIN, - DMACH_PWM, - DMACH_IRDA, - DMACH_EXTERNAL, - DMACH_RES1, - DMACH_RES2, - DMACH_SECURITY_RX, /* SDMA1 only */ - DMACH_SECURITY_TX, /* SDMA1 only */ - DMACH_MAX /* the end */ -}; - -static inline bool samsung_dma_has_circular(void) -{ - return true; -} - -static inline bool samsung_dma_is_dmadev(void) -{ - return false; -} -#define S3C2410_DMAF_CIRCULAR (1 << 0) - -#include - -#define DMACH_LOW_LEVEL (1<<28) /* use this to specifiy hardware ch no */ - -struct s3c64xx_dma_buff; - -/** s3c64xx_dma_buff - S3C64XX DMA buffer descriptor - * @next: Pointer to next buffer in queue or ring. - * @pw: Client provided identifier - * @lli: Pointer to hardware descriptor this buffer is associated with. - * @lli_dma: Hardare address of the descriptor. - */ -struct s3c64xx_dma_buff { - struct s3c64xx_dma_buff *next; - - void *pw; - struct pl080s_lli *lli; - dma_addr_t lli_dma; -}; - -struct s3c64xx_dmac; - -struct s3c2410_dma_chan { - unsigned char number; /* number of this dma channel */ - unsigned char in_use; /* channel allocated */ - unsigned char bit; /* bit for enable/disable/etc */ - unsigned char hw_width; - unsigned char peripheral; - - unsigned int flags; - enum dma_data_direction source; - - - dma_addr_t dev_addr; - - struct s3c2410_dma_client *client; - struct s3c64xx_dmac *dmac; /* pointer to controller */ - - void __iomem *regs; - - /* cdriver callbacks */ - s3c2410_dma_cbfn_t callback_fn; /* buffer done callback */ - s3c2410_dma_opfn_t op_fn; /* channel op callback */ - - /* buffer list and information */ - struct s3c64xx_dma_buff *curr; /* current dma buffer */ - struct s3c64xx_dma_buff *next; /* next buffer to load */ - struct s3c64xx_dma_buff *end; /* end of queue */ - - /* note, when channel is running in circular mode, curr is the - * first buffer enqueued, end is the last and curr is where the - * last buffer-done event is set-at. The buffers are not freed - * and the last buffer hardware descriptor points back to the - * first. - */ -}; - -#include - -#else - #define S3C64XX_DMA_CHAN(name) ((unsigned long)(name)) /* DMA0/SDMA0 */ @@ -189,6 +68,4 @@ static inline bool samsung_dma_is_dmadev(void) #include #include -#endif - #endif /* __ASM_ARCH_IRQ_H */ From a7a996d19219424c8ca8f16474138b4ee170727f Mon Sep 17 00:00:00 2001 From: Tomasz Figa Date: Wed, 16 Oct 2013 21:10:57 +0200 Subject: [PATCH 05/23] clk: samsung: s3c64xx: Remove clock aliases of old DMA driver Since the old DMA driver got removed, these aliases are no longer necessary. Signed-off-by: Tomasz Figa Signed-off-by: Mark Brown --- drivers/clk/samsung/clk-s3c64xx.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/drivers/clk/samsung/clk-s3c64xx.c b/drivers/clk/samsung/clk-s3c64xx.c index 06cf10592f52..8e27aee6887e 100644 --- a/drivers/clk/samsung/clk-s3c64xx.c +++ b/drivers/clk/samsung/clk-s3c64xx.c @@ -331,9 +331,7 @@ static struct samsung_clock_alias s3c64xx_clock_aliases[] = { ALIAS(HCLK_HSMMC1, "s3c-sdhci.1", "mmc_busclk.0"), ALIAS(HCLK_HSMMC0, "s3c-sdhci.0", "hsmmc"), ALIAS(HCLK_HSMMC0, "s3c-sdhci.0", "mmc_busclk.0"), - ALIAS(HCLK_DMA1, NULL, "dma1"), ALIAS(HCLK_DMA1, "dma-pl080s.1", "apb_pclk"), - ALIAS(HCLK_DMA0, NULL, "dma0"), ALIAS(HCLK_DMA0, "dma-pl080s.0", "apb_pclk"), ALIAS(HCLK_CAMIF, "s3c-camif", "camif"), ALIAS(HCLK_LCD, "s3c-fb", "lcd"), From 3faecea70b0d6d050e0ae911032ec340341dc389 Mon Sep 17 00:00:00 2001 From: Tomasz Figa Date: Wed, 16 Oct 2013 21:10:58 +0200 Subject: [PATCH 06/23] spi: s3c64xx: Always select S3C64XX_PL080 when ARCH_S3C64XX is enabled The legacy S3C64xx DMA driver has been removed, DMA support on S3C64xx is provided only by the generic PL08x driver. This patch modifies the Kconfig entry of spi-s3c64xx driver, which relies on availability of DMA, to always select the S3C64XX_PL080 symbol. Signed-off-by: Tomasz Figa Signed-off-by: Mark Brown --- drivers/spi/Kconfig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/spi/Kconfig b/drivers/spi/Kconfig index 760d7b6b8591..e2dd2fbec5ee 100644 --- a/drivers/spi/Kconfig +++ b/drivers/spi/Kconfig @@ -395,7 +395,7 @@ config SPI_S3C24XX_FIQ config SPI_S3C64XX tristate "Samsung S3C64XX series type SPI" depends on PLAT_SAMSUNG - select S3C64XX_DMA if ARCH_S3C64XX && !S3C64XX_PL080 + select S3C64XX_PL080 if ARCH_S3C64XX help SPI driver for Samsung S3C64XX and newer SoCs. From 4cc16085c80d3363315ad183ad72654993766a0f Mon Sep 17 00:00:00 2001 From: Jingoo Han Date: Wed, 4 Dec 2013 14:15:23 +0900 Subject: [PATCH 07/23] spi: xcomm: Use devm_spi_register_master() Use devm_spi_register_master() to make cleanup paths simpler, and remove unnecessary remove(). Signed-off-by: Jingoo Han Acked-by: Lars-Peter Clausen Signed-off-by: Mark Brown --- drivers/spi/spi-xcomm.c | 12 +----------- 1 file changed, 1 insertion(+), 11 deletions(-) diff --git a/drivers/spi/spi-xcomm.c b/drivers/spi/spi-xcomm.c index 4258c712ad3c..24c40b13dab1 100644 --- a/drivers/spi/spi-xcomm.c +++ b/drivers/spi/spi-xcomm.c @@ -231,22 +231,13 @@ static int spi_xcomm_probe(struct i2c_client *i2c, master->dev.of_node = i2c->dev.of_node; i2c_set_clientdata(i2c, master); - ret = spi_register_master(master); + ret = devm_spi_register_master(&i2c->dev, master); if (ret < 0) spi_master_put(master); return ret; } -static int spi_xcomm_remove(struct i2c_client *i2c) -{ - struct spi_master *master = i2c_get_clientdata(i2c); - - spi_unregister_master(master); - - return 0; -} - static const struct i2c_device_id spi_xcomm_ids[] = { { "spi-xcomm" }, { }, @@ -259,7 +250,6 @@ static struct i2c_driver spi_xcomm_driver = { }, .id_table = spi_xcomm_ids, .probe = spi_xcomm_probe, - .remove = spi_xcomm_remove, }; module_i2c_driver(spi_xcomm_driver); From 48c3fc93803a27bb9d2c79d718cf142974f080c8 Mon Sep 17 00:00:00 2001 From: Michal Nazarewicz Date: Sun, 8 Dec 2013 16:35:09 +0100 Subject: [PATCH 08/23] spi: tegra114: use u32 for 32-bit register values MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Previously used “unsigned long” may lead to confusion should the code be compiled for 64-bit machine. This commit also removes some unused fields of the tegra_spi_data structure as well as removes duplicated #defines. Signed-off-by: Michal Nazarewicz Tested-by: Stephen Warren Acked-by: Stephen Warren Signed-off-by: Mark Brown --- drivers/spi/spi-tegra114.c | 98 +++++++++++++------------------------- 1 file changed, 34 insertions(+), 64 deletions(-) diff --git a/drivers/spi/spi-tegra114.c b/drivers/spi/spi-tegra114.c index aaecfb3ebf58..47b93cc4bd19 100644 --- a/drivers/spi/spi-tegra114.c +++ b/drivers/spi/spi-tegra114.c @@ -54,11 +54,8 @@ #define SPI_CS_SS_VAL (1 << 20) #define SPI_CS_SW_HW (1 << 21) /* SPI_CS_POL_INACTIVE bits are default high */ -#define SPI_CS_POL_INACTIVE 22 -#define SPI_CS_POL_INACTIVE_0 (1 << 22) -#define SPI_CS_POL_INACTIVE_1 (1 << 23) -#define SPI_CS_POL_INACTIVE_2 (1 << 24) -#define SPI_CS_POL_INACTIVE_3 (1 << 25) + /* n from 0 to 3 */ +#define SPI_CS_POL_INACTIVE(n) (1 << (22 + (n))) #define SPI_CS_POL_INACTIVE_MASK (0xF << 22) #define SPI_CS_SEL_0 (0 << 26) @@ -165,9 +162,6 @@ #define MAX_HOLD_CYCLES 16 #define SPI_DEFAULT_SPEED 25000000 -#define MAX_CHIP_SELECT 4 -#define SPI_FIFO_DEPTH 64 - struct tegra_spi_data { struct device *dev; struct spi_master *master; @@ -184,7 +178,6 @@ struct tegra_spi_data { struct spi_device *cur_spi; struct spi_device *cs_control; unsigned cur_pos; - unsigned cur_len; unsigned words_per_32bit; unsigned bytes_per_word; unsigned curr_dma_words; @@ -204,12 +197,10 @@ struct tegra_spi_data { u32 rx_status; u32 status_reg; bool is_packed; - unsigned long packed_size; u32 command1_reg; u32 dma_control_reg; u32 def_command1_reg; - u32 spi_cs_timing; struct completion xfer_completion; struct spi_transfer *curr_xfer; @@ -227,14 +218,14 @@ struct tegra_spi_data { static int tegra_spi_runtime_suspend(struct device *dev); static int tegra_spi_runtime_resume(struct device *dev); -static inline unsigned long tegra_spi_readl(struct tegra_spi_data *tspi, +static inline u32 tegra_spi_readl(struct tegra_spi_data *tspi, unsigned long reg) { return readl(tspi->base + reg); } static inline void tegra_spi_writel(struct tegra_spi_data *tspi, - unsigned long val, unsigned long reg) + u32 val, unsigned long reg) { writel(val, tspi->base + reg); @@ -245,7 +236,7 @@ static inline void tegra_spi_writel(struct tegra_spi_data *tspi, static void tegra_spi_clear_status(struct tegra_spi_data *tspi) { - unsigned long val; + u32 val; /* Write 1 to clear status register */ val = tegra_spi_readl(tspi, SPI_TRANS_STATUS); @@ -296,10 +287,9 @@ static unsigned tegra_spi_fill_tx_fifo_from_client_txbuf( { unsigned nbytes; unsigned tx_empty_count; - unsigned long fifo_status; + u32 fifo_status; unsigned max_n_32bit; unsigned i, count; - unsigned long x; unsigned int written_words; unsigned fifo_words_left; u8 *tx_buf = (u8 *)t->tx_buf + tspi->cur_tx_pos; @@ -313,9 +303,9 @@ static unsigned tegra_spi_fill_tx_fifo_from_client_txbuf( nbytes = written_words * tspi->bytes_per_word; max_n_32bit = DIV_ROUND_UP(nbytes, 4); for (count = 0; count < max_n_32bit; count++) { - x = 0; + u32 x = 0; for (i = 0; (i < 4) && nbytes; i++, nbytes--) - x |= (*tx_buf++) << (i*8); + x |= (u32)(*tx_buf++) << (i * 8); tegra_spi_writel(tspi, x, SPI_TX_FIFO); } } else { @@ -323,10 +313,10 @@ static unsigned tegra_spi_fill_tx_fifo_from_client_txbuf( written_words = max_n_32bit; nbytes = written_words * tspi->bytes_per_word; for (count = 0; count < max_n_32bit; count++) { - x = 0; + u32 x = 0; for (i = 0; nbytes && (i < tspi->bytes_per_word); i++, nbytes--) - x |= ((*tx_buf++) << i*8); + x |= (u32)(*tx_buf++) << (i * 8); tegra_spi_writel(tspi, x, SPI_TX_FIFO); } } @@ -338,9 +328,8 @@ static unsigned int tegra_spi_read_rx_fifo_to_client_rxbuf( struct tegra_spi_data *tspi, struct spi_transfer *t) { unsigned rx_full_count; - unsigned long fifo_status; + u32 fifo_status; unsigned i, count; - unsigned long x; unsigned int read_words = 0; unsigned len; u8 *rx_buf = (u8 *)t->rx_buf + tspi->cur_rx_pos; @@ -350,20 +339,16 @@ static unsigned int tegra_spi_read_rx_fifo_to_client_rxbuf( if (tspi->is_packed) { len = tspi->curr_dma_words * tspi->bytes_per_word; for (count = 0; count < rx_full_count; count++) { - x = tegra_spi_readl(tspi, SPI_RX_FIFO); + u32 x = tegra_spi_readl(tspi, SPI_RX_FIFO); for (i = 0; len && (i < 4); i++, len--) *rx_buf++ = (x >> i*8) & 0xFF; } tspi->cur_rx_pos += tspi->curr_dma_words * tspi->bytes_per_word; read_words += tspi->curr_dma_words; } else { - unsigned int rx_mask; - unsigned int bits_per_word = t->bits_per_word; - - rx_mask = (1 << bits_per_word) - 1; + u32 rx_mask = ((u32)1 << t->bits_per_word) - 1; for (count = 0; count < rx_full_count; count++) { - x = tegra_spi_readl(tspi, SPI_RX_FIFO); - x &= rx_mask; + u32 x = tegra_spi_readl(tspi, SPI_RX_FIFO) & rx_mask; for (i = 0; (i < tspi->bytes_per_word); i++) *rx_buf++ = (x >> (i*8)) & 0xFF; } @@ -376,27 +361,24 @@ static unsigned int tegra_spi_read_rx_fifo_to_client_rxbuf( static void tegra_spi_copy_client_txbuf_to_spi_txbuf( struct tegra_spi_data *tspi, struct spi_transfer *t) { - unsigned len; - /* Make the dma buffer to read by cpu */ dma_sync_single_for_cpu(tspi->dev, tspi->tx_dma_phys, tspi->dma_buf_size, DMA_TO_DEVICE); if (tspi->is_packed) { - len = tspi->curr_dma_words * tspi->bytes_per_word; + unsigned len = tspi->curr_dma_words * tspi->bytes_per_word; memcpy(tspi->tx_dma_buf, t->tx_buf + tspi->cur_pos, len); } else { unsigned int i; unsigned int count; u8 *tx_buf = (u8 *)t->tx_buf + tspi->cur_tx_pos; unsigned consume = tspi->curr_dma_words * tspi->bytes_per_word; - unsigned int x; for (count = 0; count < tspi->curr_dma_words; count++) { - x = 0; + u32 x = 0; for (i = 0; consume && (i < tspi->bytes_per_word); i++, consume--) - x |= ((*tx_buf++) << i * 8); + x |= (u32)(*tx_buf++) << (i * 8); tspi->tx_dma_buf[count] = x; } } @@ -410,27 +392,21 @@ static void tegra_spi_copy_client_txbuf_to_spi_txbuf( static void tegra_spi_copy_spi_rxbuf_to_client_rxbuf( struct tegra_spi_data *tspi, struct spi_transfer *t) { - unsigned len; - /* Make the dma buffer to read by cpu */ dma_sync_single_for_cpu(tspi->dev, tspi->rx_dma_phys, tspi->dma_buf_size, DMA_FROM_DEVICE); if (tspi->is_packed) { - len = tspi->curr_dma_words * tspi->bytes_per_word; + unsigned len = tspi->curr_dma_words * tspi->bytes_per_word; memcpy(t->rx_buf + tspi->cur_rx_pos, tspi->rx_dma_buf, len); } else { unsigned int i; unsigned int count; unsigned char *rx_buf = t->rx_buf + tspi->cur_rx_pos; - unsigned int x; - unsigned int rx_mask; - unsigned int bits_per_word = t->bits_per_word; + u32 rx_mask = ((u32)1 << t->bits_per_word) - 1; - rx_mask = (1 << bits_per_word) - 1; for (count = 0; count < tspi->curr_dma_words; count++) { - x = tspi->rx_dma_buf[count]; - x &= rx_mask; + u32 x = tspi->rx_dma_buf[count] & rx_mask; for (i = 0; (i < tspi->bytes_per_word); i++) *rx_buf++ = (x >> (i*8)) & 0xFF; } @@ -490,16 +466,16 @@ static int tegra_spi_start_rx_dma(struct tegra_spi_data *tspi, int len) static int tegra_spi_start_dma_based_transfer( struct tegra_spi_data *tspi, struct spi_transfer *t) { - unsigned long val; + u32 val; unsigned int len; int ret = 0; - unsigned long status; + u32 status; /* Make sure that Rx and Tx fifo are empty */ status = tegra_spi_readl(tspi, SPI_FIFO_STATUS); if ((status & SPI_FIFO_EMPTY) != SPI_FIFO_EMPTY) { - dev_err(tspi->dev, - "Rx/Tx fifo are not empty status 0x%08lx\n", status); + dev_err(tspi->dev, "Rx/Tx fifo are not empty status 0x%08x\n", + (unsigned)status); return -EIO; } @@ -564,7 +540,7 @@ static int tegra_spi_start_dma_based_transfer( static int tegra_spi_start_cpu_based_transfer( struct tegra_spi_data *tspi, struct spi_transfer *t) { - unsigned long val; + u32 val; unsigned cur_words; if (tspi->cur_direction & DATA_DIR_TX) @@ -677,13 +653,13 @@ static void tegra_spi_deinit_dma_param(struct tegra_spi_data *tspi, dma_release_channel(dma_chan); } -static unsigned long tegra_spi_setup_transfer_one(struct spi_device *spi, +static u32 tegra_spi_setup_transfer_one(struct spi_device *spi, struct spi_transfer *t, bool is_first_of_msg) { struct tegra_spi_data *tspi = spi_master_get_devdata(spi->master); u32 speed = t->speed_hz; u8 bits_per_word = t->bits_per_word; - unsigned long command1; + u32 command1; int req_mode; if (speed != tspi->cur_speed) { @@ -738,7 +714,7 @@ static unsigned long tegra_spi_setup_transfer_one(struct spi_device *spi, } static int tegra_spi_start_transfer_one(struct spi_device *spi, - struct spi_transfer *t, unsigned long command1) + struct spi_transfer *t, u32 command1) { struct tegra_spi_data *tspi = spi_master_get_devdata(spi->master); unsigned total_fifo_words; @@ -763,8 +739,8 @@ static int tegra_spi_start_transfer_one(struct spi_device *spi, tegra_spi_writel(tspi, command1, SPI_COMMAND1); tspi->command1_reg = command1; - dev_dbg(tspi->dev, "The def 0x%x and written 0x%lx\n", - tspi->def_command1_reg, command1); + dev_dbg(tspi->dev, "The def 0x%x and written 0x%x\n", + tspi->def_command1_reg, (unsigned)command1); if (total_fifo_words > SPI_FIFO_DEPTH) ret = tegra_spi_start_dma_based_transfer(tspi, t); @@ -776,15 +752,9 @@ static int tegra_spi_start_transfer_one(struct spi_device *spi, static int tegra_spi_setup(struct spi_device *spi) { struct tegra_spi_data *tspi = spi_master_get_devdata(spi->master); - unsigned long val; + u32 val; unsigned long flags; int ret; - unsigned int cs_pol_bit[MAX_CHIP_SELECT] = { - SPI_CS_POL_INACTIVE_0, - SPI_CS_POL_INACTIVE_1, - SPI_CS_POL_INACTIVE_2, - SPI_CS_POL_INACTIVE_3, - }; dev_dbg(&spi->dev, "setup %d bpw, %scpol, %scpha, %dHz\n", spi->bits_per_word, @@ -806,9 +776,9 @@ static int tegra_spi_setup(struct spi_device *spi) spin_lock_irqsave(&tspi->lock, flags); val = tspi->def_command1_reg; if (spi->mode & SPI_CS_HIGH) - val &= ~cs_pol_bit[spi->chip_select]; + val &= ~SPI_CS_POL_INACTIVE(spi->chip_select); else - val |= cs_pol_bit[spi->chip_select]; + val |= SPI_CS_POL_INACTIVE(spi->chip_select); tspi->def_command1_reg = val; tegra_spi_writel(tspi, tspi->def_command1_reg, SPI_COMMAND1); spin_unlock_irqrestore(&tspi->lock, flags); @@ -842,7 +812,7 @@ static int tegra_spi_transfer_one_message(struct spi_master *master, msg->actual_length = 0; list_for_each_entry(xfer, &msg->transfers, transfer_list) { - unsigned long cmd1; + u32 cmd1; reinit_completion(&tspi->xfer_completion); From 5fd38677a48deab4ea480f078a838758a030d3a2 Mon Sep 17 00:00:00 2001 From: Michal Nazarewicz Date: Sun, 8 Dec 2013 16:35:10 +0100 Subject: [PATCH 09/23] spi: tegra20-slink: use u32 for 32-bit register values MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Previously used “unsigned long” may lead to confusion should the code be compiled for 64-bit machine. Signed-off-by: Michal Nazarewicz Signed-off-by: Mark Brown --- drivers/spi/spi-tegra20-slink.c | 97 ++++++++++++++------------------- 1 file changed, 40 insertions(+), 57 deletions(-) diff --git a/drivers/spi/spi-tegra20-slink.c b/drivers/spi/spi-tegra20-slink.c index e66715ba37ed..3ce1de8872f0 100644 --- a/drivers/spi/spi-tegra20-slink.c +++ b/drivers/spi/spi-tegra20-slink.c @@ -196,7 +196,7 @@ struct tegra_slink_data { u32 rx_status; u32 status_reg; bool is_packed; - unsigned long packed_size; + u32 packed_size; u32 command_reg; u32 command2_reg; @@ -220,14 +220,14 @@ struct tegra_slink_data { static int tegra_slink_runtime_suspend(struct device *dev); static int tegra_slink_runtime_resume(struct device *dev); -static inline unsigned long tegra_slink_readl(struct tegra_slink_data *tspi, +static inline u32 tegra_slink_readl(struct tegra_slink_data *tspi, unsigned long reg) { return readl(tspi->base + reg); } static inline void tegra_slink_writel(struct tegra_slink_data *tspi, - unsigned long val, unsigned long reg) + u32 val, unsigned long reg) { writel(val, tspi->base + reg); @@ -238,38 +238,30 @@ static inline void tegra_slink_writel(struct tegra_slink_data *tspi, static void tegra_slink_clear_status(struct tegra_slink_data *tspi) { - unsigned long val; - unsigned long val_write = 0; + u32 val_write; - val = tegra_slink_readl(tspi, SLINK_STATUS); + tegra_slink_readl(tspi, SLINK_STATUS); /* Write 1 to clear status register */ val_write = SLINK_RDY | SLINK_FIFO_ERROR; tegra_slink_writel(tspi, val_write, SLINK_STATUS); } -static unsigned long tegra_slink_get_packed_size(struct tegra_slink_data *tspi, +static u32 tegra_slink_get_packed_size(struct tegra_slink_data *tspi, struct spi_transfer *t) { - unsigned long val; - switch (tspi->bytes_per_word) { case 0: - val = SLINK_PACK_SIZE_4; - break; + return SLINK_PACK_SIZE_4; case 1: - val = SLINK_PACK_SIZE_8; - break; + return SLINK_PACK_SIZE_8; case 2: - val = SLINK_PACK_SIZE_16; - break; + return SLINK_PACK_SIZE_16; case 4: - val = SLINK_PACK_SIZE_32; - break; + return SLINK_PACK_SIZE_32; default: - val = 0; + return 0; } - return val; } static unsigned tegra_slink_calculate_curr_xfer_param( @@ -312,10 +304,9 @@ static unsigned tegra_slink_fill_tx_fifo_from_client_txbuf( { unsigned nbytes; unsigned tx_empty_count; - unsigned long fifo_status; + u32 fifo_status; unsigned max_n_32bit; unsigned i, count; - unsigned long x; unsigned int written_words; unsigned fifo_words_left; u8 *tx_buf = (u8 *)t->tx_buf + tspi->cur_tx_pos; @@ -329,9 +320,9 @@ static unsigned tegra_slink_fill_tx_fifo_from_client_txbuf( nbytes = written_words * tspi->bytes_per_word; max_n_32bit = DIV_ROUND_UP(nbytes, 4); for (count = 0; count < max_n_32bit; count++) { - x = 0; + u32 x = 0; for (i = 0; (i < 4) && nbytes; i++, nbytes--) - x |= (*tx_buf++) << (i*8); + x |= (u32)(*tx_buf++) << (i * 8); tegra_slink_writel(tspi, x, SLINK_TX_FIFO); } } else { @@ -339,10 +330,10 @@ static unsigned tegra_slink_fill_tx_fifo_from_client_txbuf( written_words = max_n_32bit; nbytes = written_words * tspi->bytes_per_word; for (count = 0; count < max_n_32bit; count++) { - x = 0; + u32 x = 0; for (i = 0; nbytes && (i < tspi->bytes_per_word); i++, nbytes--) - x |= ((*tx_buf++) << i*8); + x |= (u32)(*tx_buf++) << (i * 8); tegra_slink_writel(tspi, x, SLINK_TX_FIFO); } } @@ -354,9 +345,8 @@ static unsigned int tegra_slink_read_rx_fifo_to_client_rxbuf( struct tegra_slink_data *tspi, struct spi_transfer *t) { unsigned rx_full_count; - unsigned long fifo_status; + u32 fifo_status; unsigned i, count; - unsigned long x; unsigned int read_words = 0; unsigned len; u8 *rx_buf = (u8 *)t->rx_buf + tspi->cur_rx_pos; @@ -366,7 +356,7 @@ static unsigned int tegra_slink_read_rx_fifo_to_client_rxbuf( if (tspi->is_packed) { len = tspi->curr_dma_words * tspi->bytes_per_word; for (count = 0; count < rx_full_count; count++) { - x = tegra_slink_readl(tspi, SLINK_RX_FIFO); + u32 x = tegra_slink_readl(tspi, SLINK_RX_FIFO); for (i = 0; len && (i < 4); i++, len--) *rx_buf++ = (x >> i*8) & 0xFF; } @@ -374,7 +364,7 @@ static unsigned int tegra_slink_read_rx_fifo_to_client_rxbuf( read_words += tspi->curr_dma_words; } else { for (count = 0; count < rx_full_count; count++) { - x = tegra_slink_readl(tspi, SLINK_RX_FIFO); + u32 x = tegra_slink_readl(tspi, SLINK_RX_FIFO); for (i = 0; (i < tspi->bytes_per_word); i++) *rx_buf++ = (x >> (i*8)) & 0xFF; } @@ -387,27 +377,24 @@ static unsigned int tegra_slink_read_rx_fifo_to_client_rxbuf( static void tegra_slink_copy_client_txbuf_to_spi_txbuf( struct tegra_slink_data *tspi, struct spi_transfer *t) { - unsigned len; - /* Make the dma buffer to read by cpu */ dma_sync_single_for_cpu(tspi->dev, tspi->tx_dma_phys, tspi->dma_buf_size, DMA_TO_DEVICE); if (tspi->is_packed) { - len = tspi->curr_dma_words * tspi->bytes_per_word; + unsigned len = tspi->curr_dma_words * tspi->bytes_per_word; memcpy(tspi->tx_dma_buf, t->tx_buf + tspi->cur_pos, len); } else { unsigned int i; unsigned int count; u8 *tx_buf = (u8 *)t->tx_buf + tspi->cur_tx_pos; unsigned consume = tspi->curr_dma_words * tspi->bytes_per_word; - unsigned int x; for (count = 0; count < tspi->curr_dma_words; count++) { - x = 0; + u32 x = 0; for (i = 0; consume && (i < tspi->bytes_per_word); i++, consume--) - x |= ((*tx_buf++) << i * 8); + x |= (u32)(*tx_buf++) << (i * 8); tspi->tx_dma_buf[count] = x; } } @@ -434,14 +421,10 @@ static void tegra_slink_copy_spi_rxbuf_to_client_rxbuf( unsigned int i; unsigned int count; unsigned char *rx_buf = t->rx_buf + tspi->cur_rx_pos; - unsigned int x; - unsigned int rx_mask, bits_per_word; + u32 rx_mask = ((u32)1 << t->bits_per_word) - 1; - bits_per_word = t->bits_per_word; - rx_mask = (1 << bits_per_word) - 1; for (count = 0; count < tspi->curr_dma_words; count++) { - x = tspi->rx_dma_buf[count]; - x &= rx_mask; + u32 x = tspi->rx_dma_buf[count] & rx_mask; for (i = 0; (i < tspi->bytes_per_word); i++) *rx_buf++ = (x >> (i*8)) & 0xFF; } @@ -501,17 +484,16 @@ static int tegra_slink_start_rx_dma(struct tegra_slink_data *tspi, int len) static int tegra_slink_start_dma_based_transfer( struct tegra_slink_data *tspi, struct spi_transfer *t) { - unsigned long val; - unsigned long test_val; + u32 val; unsigned int len; int ret = 0; - unsigned long status; + u32 status; /* Make sure that Rx and Tx fifo are empty */ status = tegra_slink_readl(tspi, SLINK_STATUS); if ((status & SLINK_FIFO_EMPTY) != SLINK_FIFO_EMPTY) { - dev_err(tspi->dev, - "Rx/Tx fifo are not empty status 0x%08lx\n", status); + dev_err(tspi->dev, "Rx/Tx fifo are not empty status 0x%08x\n", + (unsigned)status); return -EIO; } @@ -551,9 +533,9 @@ static int tegra_slink_start_dma_based_transfer( } /* Wait for tx fifo to be fill before starting slink */ - test_val = tegra_slink_readl(tspi, SLINK_STATUS); - while (!(test_val & SLINK_TX_FULL)) - test_val = tegra_slink_readl(tspi, SLINK_STATUS); + status = tegra_slink_readl(tspi, SLINK_STATUS); + while (!(status & SLINK_TX_FULL)) + status = tegra_slink_readl(tspi, SLINK_STATUS); } if (tspi->cur_direction & DATA_DIR_RX) { @@ -587,7 +569,7 @@ static int tegra_slink_start_dma_based_transfer( static int tegra_slink_start_cpu_based_transfer( struct tegra_slink_data *tspi, struct spi_transfer *t) { - unsigned long val; + u32 val; unsigned cur_words; val = tspi->packed_size; @@ -714,8 +696,8 @@ static int tegra_slink_start_transfer_one(struct spi_device *spi, u8 bits_per_word; unsigned total_fifo_words; int ret; - unsigned long command; - unsigned long command2; + u32 command; + u32 command2; bits_per_word = t->bits_per_word; speed = t->speed_hz; @@ -762,17 +744,18 @@ static int tegra_slink_start_transfer_one(struct spi_device *spi, static int tegra_slink_setup(struct spi_device *spi) { - struct tegra_slink_data *tspi = spi_master_get_devdata(spi->master); - unsigned long val; - unsigned long flags; - int ret; - unsigned int cs_pol_bit[MAX_CHIP_SELECT] = { + static const u32 cs_pol_bit[MAX_CHIP_SELECT] = { SLINK_CS_POLARITY, SLINK_CS_POLARITY1, SLINK_CS_POLARITY2, SLINK_CS_POLARITY3, }; + struct tegra_slink_data *tspi = spi_master_get_devdata(spi->master); + u32 val; + unsigned long flags; + int ret; + dev_dbg(&spi->dev, "setup %d bpw, %scpol, %scpha, %dHz\n", spi->bits_per_word, spi->mode & SPI_CPOL ? "" : "~", From a553a31d9f32700ef0d3a1490e222ec15e600140 Mon Sep 17 00:00:00 2001 From: Michal Nazarewicz Date: Sun, 8 Dec 2013 16:35:11 +0100 Subject: [PATCH 10/23] spi: tegra20-sflash: use u32 for 32-bit register values MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Previously used “unsigned long” may lead to confusion should the code be compiled for 64-bit machine. Signed-off-by: Michal Nazarewicz Signed-off-by: Mark Brown --- drivers/spi/spi-tegra20-sflash.c | 22 ++++++++++------------ 1 file changed, 10 insertions(+), 12 deletions(-) diff --git a/drivers/spi/spi-tegra20-sflash.c b/drivers/spi/spi-tegra20-sflash.c index 4dc8e8129459..af78c17388d2 100644 --- a/drivers/spi/spi-tegra20-sflash.c +++ b/drivers/spi/spi-tegra20-sflash.c @@ -148,14 +148,14 @@ struct tegra_sflash_data { static int tegra_sflash_runtime_suspend(struct device *dev); static int tegra_sflash_runtime_resume(struct device *dev); -static inline unsigned long tegra_sflash_readl(struct tegra_sflash_data *tsd, +static inline u32 tegra_sflash_readl(struct tegra_sflash_data *tsd, unsigned long reg) { return readl(tsd->base + reg); } static inline void tegra_sflash_writel(struct tegra_sflash_data *tsd, - unsigned long val, unsigned long reg) + u32 val, unsigned long reg) { writel(val, tsd->base + reg); } @@ -185,7 +185,7 @@ static unsigned tegra_sflash_fill_tx_fifo_from_client_txbuf( struct tegra_sflash_data *tsd, struct spi_transfer *t) { unsigned nbytes; - unsigned long status; + u32 status; unsigned max_n_32bit = tsd->curr_xfer_words; u8 *tx_buf = (u8 *)t->tx_buf + tsd->cur_tx_pos; @@ -196,11 +196,11 @@ static unsigned tegra_sflash_fill_tx_fifo_from_client_txbuf( status = tegra_sflash_readl(tsd, SPI_STATUS); while (!(status & SPI_TXF_FULL)) { int i; - unsigned int x = 0; + u32 x = 0; for (i = 0; nbytes && (i < tsd->bytes_per_word); i++, nbytes--) - x |= ((*tx_buf++) << i*8); + x |= (u32)(*tx_buf++) << (i * 8); tegra_sflash_writel(tsd, x, SPI_TX_FIFO); if (!nbytes) break; @@ -214,16 +214,14 @@ static unsigned tegra_sflash_fill_tx_fifo_from_client_txbuf( static int tegra_sflash_read_rx_fifo_to_client_rxbuf( struct tegra_sflash_data *tsd, struct spi_transfer *t) { - unsigned long status; + u32 status; unsigned int read_words = 0; u8 *rx_buf = (u8 *)t->rx_buf + tsd->cur_rx_pos; status = tegra_sflash_readl(tsd, SPI_STATUS); while (!(status & SPI_RXF_EMPTY)) { int i; - unsigned long x; - - x = tegra_sflash_readl(tsd, SPI_RX_FIFO); + u32 x = tegra_sflash_readl(tsd, SPI_RX_FIFO); for (i = 0; (i < tsd->bytes_per_word); i++) *rx_buf++ = (x >> (i*8)) & 0xFF; read_words++; @@ -236,7 +234,7 @@ static int tegra_sflash_read_rx_fifo_to_client_rxbuf( static int tegra_sflash_start_cpu_based_transfer( struct tegra_sflash_data *tsd, struct spi_transfer *t) { - unsigned long val = 0; + u32 val = 0; unsigned cur_words; if (tsd->cur_direction & DATA_DIR_TX) @@ -266,7 +264,7 @@ static int tegra_sflash_start_transfer_one(struct spi_device *spi, { struct tegra_sflash_data *tsd = spi_master_get_devdata(spi->master); u32 speed; - unsigned long command; + u32 command; speed = t->speed_hz; if (speed != tsd->cur_speed) { @@ -313,7 +311,7 @@ static int tegra_sflash_start_transfer_one(struct spi_device *spi, tegra_sflash_writel(tsd, command, SPI_COMMAND); tsd->command_reg = command; - return tegra_sflash_start_cpu_based_transfer(tsd, t); + return tegra_sflash_start_cpu_based_transfer(tsd, t); } static int tegra_sflash_setup(struct spi_device *spi) From c9f722e879953f74d3e09023ba339c98d68f1998 Mon Sep 17 00:00:00 2001 From: Jingoo Han Date: Mon, 9 Dec 2013 19:19:13 +0900 Subject: [PATCH 11/23] spi: s3c24xx: Use devm_*() functions Use devm_*() functions to make cleanup paths simpler. Signed-off-by: Jingoo Han Signed-off-by: Mark Brown --- drivers/spi/spi-s3c24xx.c | 67 ++++++++------------------------------- 1 file changed, 14 insertions(+), 53 deletions(-) diff --git a/drivers/spi/spi-s3c24xx.c b/drivers/spi/spi-s3c24xx.c index 0dc32a11bd3c..ebf80bbc93b3 100644 --- a/drivers/spi/spi-s3c24xx.c +++ b/drivers/spi/spi-s3c24xx.c @@ -78,7 +78,6 @@ struct s3c24xx_spi { unsigned char *rx; struct clk *clk; - struct resource *ioarea; struct spi_master *master; struct spi_device *curdev; struct device *dev; @@ -517,8 +516,7 @@ static int s3c24xx_spi_probe(struct platform_device *pdev) master = spi_alloc_master(&pdev->dev, sizeof(struct s3c24xx_spi)); if (master == NULL) { dev_err(&pdev->dev, "No memory for spi_master\n"); - err = -ENOMEM; - goto err_nomem; + return -ENOMEM; } hw = spi_master_get_devdata(master); @@ -567,43 +565,34 @@ static int s3c24xx_spi_probe(struct platform_device *pdev) if (res == NULL) { dev_err(&pdev->dev, "Cannot get IORESOURCE_MEM\n"); err = -ENOENT; - goto err_no_iores; + goto err_no_pdata; } - hw->ioarea = request_mem_region(res->start, resource_size(res), - pdev->name); - - if (hw->ioarea == NULL) { - dev_err(&pdev->dev, "Cannot reserve region\n"); - err = -ENXIO; - goto err_no_iores; - } - - hw->regs = ioremap(res->start, resource_size(res)); - if (hw->regs == NULL) { - dev_err(&pdev->dev, "Cannot map IO\n"); - err = -ENXIO; - goto err_no_iomap; + hw->regs = devm_ioremap_resource(&pdev->dev, res); + if (IS_ERR(hw->regs)) { + err = PTR_ERR(hw->regs); + goto err_no_pdata; } hw->irq = platform_get_irq(pdev, 0); if (hw->irq < 0) { dev_err(&pdev->dev, "No IRQ specified\n"); err = -ENOENT; - goto err_no_irq; + goto err_no_pdata; } - err = request_irq(hw->irq, s3c24xx_spi_irq, 0, pdev->name, hw); + err = devm_request_irq(&pdev->dev, hw->irq, s3c24xx_spi_irq, 0, + pdev->name, hw); if (err) { dev_err(&pdev->dev, "Cannot claim IRQ\n"); - goto err_no_irq; + goto err_no_pdata; } - hw->clk = clk_get(&pdev->dev, "spi"); + hw->clk = devm_clk_get(&pdev->dev, "spi"); if (IS_ERR(hw->clk)) { dev_err(&pdev->dev, "No clock for device\n"); err = PTR_ERR(hw->clk); - goto err_no_clk; + goto err_no_pdata; } /* setup any gpio we can */ @@ -615,7 +604,8 @@ static int s3c24xx_spi_probe(struct platform_device *pdev) goto err_register; } - err = gpio_request(pdata->pin_cs, dev_name(&pdev->dev)); + err = devm_gpio_request(&pdev->dev, pdata->pin_cs, + dev_name(&pdev->dev)); if (err) { dev_err(&pdev->dev, "Failed to get gpio for cs\n"); goto err_register; @@ -639,27 +629,10 @@ static int s3c24xx_spi_probe(struct platform_device *pdev) return 0; err_register: - if (hw->set_cs == s3c24xx_spi_gpiocs) - gpio_free(pdata->pin_cs); - clk_disable(hw->clk); - clk_put(hw->clk); - err_no_clk: - free_irq(hw->irq, hw); - - err_no_irq: - iounmap(hw->regs); - - err_no_iomap: - release_resource(hw->ioarea); - kfree(hw->ioarea); - - err_no_iores: err_no_pdata: spi_master_put(hw->master); - - err_nomem: return err; } @@ -668,19 +641,7 @@ static int s3c24xx_spi_remove(struct platform_device *dev) struct s3c24xx_spi *hw = platform_get_drvdata(dev); spi_bitbang_stop(&hw->bitbang); - clk_disable(hw->clk); - clk_put(hw->clk); - - free_irq(hw->irq, hw); - iounmap(hw->regs); - - if (hw->set_cs == s3c24xx_spi_gpiocs) - gpio_free(hw->pdata->pin_cs); - - release_resource(hw->ioarea); - kfree(hw->ioarea); - spi_master_put(hw->master); return 0; } From 18e34d568efa5f1f8b75a76400dbd06c7811c73b Mon Sep 17 00:00:00 2001 From: Jingoo Han Date: Mon, 9 Dec 2013 19:23:12 +0900 Subject: [PATCH 12/23] spi: txx9: Use devm_clk_get() Use devm_clk_get() to make cleanup paths simpler. Signed-off-by: Jingoo Han Signed-off-by: Mark Brown --- drivers/spi/spi-txx9.c | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/drivers/spi/spi-txx9.c b/drivers/spi/spi-txx9.c index 637cce2b8bdd..b206de1616d5 100644 --- a/drivers/spi/spi-txx9.c +++ b/drivers/spi/spi-txx9.c @@ -348,7 +348,7 @@ static int txx9spi_probe(struct platform_device *dev) INIT_LIST_HEAD(&c->queue); init_waitqueue_head(&c->waitq); - c->clk = clk_get(&dev->dev, "spi-baseclk"); + c->clk = devm_clk_get(&dev->dev, "spi-baseclk"); if (IS_ERR(c->clk)) { ret = PTR_ERR(c->clk); c->clk = NULL; @@ -415,10 +415,8 @@ exit_busy: exit: if (c->workqueue) destroy_workqueue(c->workqueue); - if (c->clk) { + if (c->clk) clk_disable(c->clk); - clk_put(c->clk); - } spi_master_put(master); return ret; } @@ -430,7 +428,6 @@ static int txx9spi_remove(struct platform_device *dev) destroy_workqueue(c->workqueue); clk_disable(c->clk); - clk_put(c->clk); return 0; } From 6b3938aed04587dab42f9df83122a40c596f495a Mon Sep 17 00:00:00 2001 From: Sourav Poddar Date: Fri, 6 Dec 2013 19:54:43 +0530 Subject: [PATCH 13/23] spi/qspi: parse register by name. Modify the qspi driver to parse reg information by name. If "reg names" is not found, then revert back to normal get resource. Signed-off-by: Sourav Poddar Signed-off-by: Mark Brown --- drivers/spi/spi-ti-qspi.c | 53 +++++++++++++++++++++++++++++++++++++-- 1 file changed, 51 insertions(+), 2 deletions(-) diff --git a/drivers/spi/spi-ti-qspi.c b/drivers/spi/spi-ti-qspi.c index 0b71270fbf67..1211b663c814 100644 --- a/drivers/spi/spi-ti-qspi.c +++ b/drivers/spi/spi-ti-qspi.c @@ -46,6 +46,8 @@ struct ti_qspi { struct spi_master *master; void __iomem *base; + void __iomem *ctrl_base; + void __iomem *mmap_base; struct clk *fclk; struct device *dev; @@ -54,6 +56,8 @@ struct ti_qspi { u32 spi_max_frequency; u32 cmd; u32 dc; + + bool ctrl_mod; }; #define QSPI_PID (0x0) @@ -437,7 +441,7 @@ static int ti_qspi_probe(struct platform_device *pdev) { struct ti_qspi *qspi; struct spi_master *master; - struct resource *r; + struct resource *r, *res_ctrl, *res_mmap; struct device_node *np = pdev->dev.of_node; u32 max_freq; int ret = 0, num_cs, irq; @@ -465,7 +469,35 @@ static int ti_qspi_probe(struct platform_device *pdev) qspi->master = master; qspi->dev = &pdev->dev; - r = platform_get_resource(pdev, IORESOURCE_MEM, 0); + r = platform_get_resource_byname(pdev, IORESOURCE_MEM, "qspi_base"); + if (r == NULL) { + r = platform_get_resource(pdev, IORESOURCE_MEM, 0); + if (r == NULL) { + dev_err(&pdev->dev, "missing platform data\n"); + return -ENODEV; + } + } + + res_mmap = platform_get_resource_byname(pdev, + IORESOURCE_MEM, "qspi_mmap"); + if (res_mmap == NULL) { + res_mmap = platform_get_resource(pdev, IORESOURCE_MEM, 1); + if (res_mmap == NULL) { + dev_err(&pdev->dev, + "memory mapped resource not required\n"); + return -ENODEV; + } + } + + res_ctrl = platform_get_resource_byname(pdev, + IORESOURCE_MEM, "qspi_ctrlmod"); + if (res_ctrl == NULL) { + res_ctrl = platform_get_resource(pdev, IORESOURCE_MEM, 2); + if (res_ctrl == NULL) { + dev_dbg(&pdev->dev, + "control module resources not required\n"); + } + } irq = platform_get_irq(pdev, 0); if (irq < 0) { @@ -481,6 +513,23 @@ static int ti_qspi_probe(struct platform_device *pdev) goto free_master; } + if (res_ctrl) { + qspi->ctrl_mod = true; + qspi->ctrl_base = devm_ioremap_resource(&pdev->dev, res_ctrl); + if (IS_ERR(qspi->ctrl_base)) { + ret = PTR_ERR(qspi->ctrl_base); + goto free_master; + } + } + + if (res_mmap) { + qspi->mmap_base = devm_ioremap_resource(&pdev->dev, res_mmap); + if (IS_ERR(qspi->mmap_base)) { + ret = PTR_ERR(qspi->mmap_base); + goto free_master; + } + } + ret = devm_request_irq(&pdev->dev, irq, ti_qspi_isr, 0, dev_name(&pdev->dev), qspi); if (ret < 0) { From 52690a6a868719d1d2f9e12b039c05d966600d41 Mon Sep 17 00:00:00 2001 From: Sourav Poddar Date: Fri, 6 Dec 2013 19:54:49 +0530 Subject: [PATCH 14/23] spi/qspi: update binding information These update binding information for ti qspi controller. Signed-off-by: Sourav Poddar Signed-off-by: Mark Brown --- Documentation/devicetree/bindings/spi/ti_qspi.txt | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/Documentation/devicetree/bindings/spi/ti_qspi.txt b/Documentation/devicetree/bindings/spi/ti_qspi.txt index 1f9641ade0b5..601a360531a5 100644 --- a/Documentation/devicetree/bindings/spi/ti_qspi.txt +++ b/Documentation/devicetree/bindings/spi/ti_qspi.txt @@ -3,6 +3,11 @@ TI QSPI controller. Required properties: - compatible : should be "ti,dra7xxx-qspi" or "ti,am4372-qspi". - reg: Should contain QSPI registers location and length. +- reg-names: Should contain the resource reg names. + - qspi_base: Qspi configuration register Address space + - qspi_mmap: Memory mapped Address space + - (optional) qspi_ctrlmod: Control module Address space +- interrupts: should contain the qspi interrupt number. - #address-cells, #size-cells : Must be present if the device has sub-nodes - ti,hwmods: Name of the hwmod associated to the QSPI @@ -14,7 +19,8 @@ Example: qspi: qspi@4b300000 { compatible = "ti,dra7xxx-qspi"; - reg = <0x4b300000 0x100>; + reg = <0x47900000 0x100>, <0x30000000 0x3ffffff>; + reg-names = "qspi_base", "qspi_mmap"; #address-cells = <1>; #size-cells = <0>; spi-max-frequency = <25000000>; From 8f51c8108267443865d8ec08403b66da9905ba14 Mon Sep 17 00:00:00 2001 From: Wei Yongjun Date: Fri, 20 Dec 2013 10:22:20 +0800 Subject: [PATCH 15/23] spi: spi-s3c24xx: remove redundant return value check of platform_get_resource() Remove unneeded error handling on the result of a call to platform_get_resource() when the value is passed to devm_ioremap_resource(). Signed-off-by: Wei Yongjun Reviewed-by: Jingoo Han Signed-off-by: Mark Brown --- drivers/spi/spi-s3c24xx.c | 7 ------- 1 file changed, 7 deletions(-) diff --git a/drivers/spi/spi-s3c24xx.c b/drivers/spi/spi-s3c24xx.c index ebf80bbc93b3..2ccb28d57ba9 100644 --- a/drivers/spi/spi-s3c24xx.c +++ b/drivers/spi/spi-s3c24xx.c @@ -560,14 +560,7 @@ static int s3c24xx_spi_probe(struct platform_device *pdev) dev_dbg(hw->dev, "bitbang at %p\n", &hw->bitbang); /* find and map our resources */ - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - if (res == NULL) { - dev_err(&pdev->dev, "Cannot get IORESOURCE_MEM\n"); - err = -ENOENT; - goto err_no_pdata; - } - hw->regs = devm_ioremap_resource(&pdev->dev, res); if (IS_ERR(hw->regs)) { err = PTR_ERR(hw->regs); From bdf0290ac70f5a09e85507bf6c84dc6a399dff82 Mon Sep 17 00:00:00 2001 From: Wei Yongjun Date: Fri, 20 Dec 2013 10:15:45 +0800 Subject: [PATCH 16/23] spi: txx9: drop clk_put for devm_clk_get in txx9spi_probe() devm_clk_get() is used so there is no reason to explicitly call clk_put() in txx9spi_probe() functions. Fixes: 18e34d568efa ('spi: txx9: Use devm_clk_get()') Signed-off-by: Wei Yongjun Reviewed-by: Jingoo Han Signed-off-by: Mark Brown --- drivers/spi/spi-txx9.c | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/spi/spi-txx9.c b/drivers/spi/spi-txx9.c index b206de1616d5..c72a8f840b4b 100644 --- a/drivers/spi/spi-txx9.c +++ b/drivers/spi/spi-txx9.c @@ -356,7 +356,6 @@ static int txx9spi_probe(struct platform_device *dev) } ret = clk_enable(c->clk); if (ret) { - clk_put(c->clk); c->clk = NULL; goto exit; } From 0abd3e37e6b2c3ea77f7d8597b3f22ad42d8defc Mon Sep 17 00:00:00 2001 From: Axel Lin Date: Thu, 2 Jan 2014 20:19:02 +0800 Subject: [PATCH 17/23] spi: s3c64xx: Remove duplicate code to clear S3C64XX_SPI_SLAVE_SEL register Signed-off-by: Axel Lin Signed-off-by: Mark Brown --- drivers/spi/spi-s3c64xx.c | 3 --- 1 file changed, 3 deletions(-) diff --git a/drivers/spi/spi-s3c64xx.c b/drivers/spi/spi-s3c64xx.c index 4c4b0a1219a7..b4ea9306cf35 100644 --- a/drivers/spi/spi-s3c64xx.c +++ b/drivers/spi/spi-s3c64xx.c @@ -927,9 +927,6 @@ static int s3c64xx_spi_transfer_one(struct spi_master *master, /* Start the signals */ writel(0, sdd->regs + S3C64XX_SPI_SLAVE_SEL); - /* Start the signals */ - writel(0, sdd->regs + S3C64XX_SPI_SLAVE_SEL); - spin_unlock_irqrestore(&sdd->lock, flags); status = wait_for_xfer(sdd, xfer, use_dma); From 85a9012446d4b59a57c5942ca059144fdf8cd439 Mon Sep 17 00:00:00 2001 From: Sachin Kamat Date: Tue, 31 Dec 2013 14:00:39 +0530 Subject: [PATCH 18/23] spi: s3c24xx: Remove reference to plat/fiq.h fiq.h contains only a function declaration and is not used by anyone else. Move the declaration to the driver header file and remove the unnecessary platform dependency from the driver. Signed-off-by: Sachin Kamat Signed-off-by: Mark Brown --- arch/arm/plat-samsung/include/plat/fiq.h | 13 ------------- drivers/spi/spi-s3c24xx.c | 2 -- include/linux/spi/s3c24xx.h | 2 ++ 3 files changed, 2 insertions(+), 15 deletions(-) delete mode 100644 arch/arm/plat-samsung/include/plat/fiq.h diff --git a/arch/arm/plat-samsung/include/plat/fiq.h b/arch/arm/plat-samsung/include/plat/fiq.h deleted file mode 100644 index 535d06a35628..000000000000 --- a/arch/arm/plat-samsung/include/plat/fiq.h +++ /dev/null @@ -1,13 +0,0 @@ -/* linux/arch/arm/plat-samsung/include/plat/fiq.h - * - * Copyright (c) 2009 Simtec Electronics - * Ben Dooks - * - * Header file for S3C24XX CPU FIQ support - * - * 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. -*/ - -extern int s3c24xx_set_fiq(unsigned int irq, bool on); diff --git a/drivers/spi/spi-s3c24xx.c b/drivers/spi/spi-s3c24xx.c index 2ccb28d57ba9..746424aa5353 100644 --- a/drivers/spi/spi-s3c24xx.c +++ b/drivers/spi/spi-s3c24xx.c @@ -29,7 +29,6 @@ #include -#include #include #include "spi-s3c24xx-fiq.h" @@ -84,7 +83,6 @@ struct s3c24xx_spi { struct s3c2410_spi_info *pdata; }; - #define SPCON_DEFAULT (S3C2410_SPCON_MSTR | S3C2410_SPCON_SMOD_INT) #define SPPIN_DEFAULT (S3C2410_SPPIN_KEEP) diff --git a/include/linux/spi/s3c24xx.h b/include/linux/spi/s3c24xx.h index c23b923e493b..ca271c06c591 100644 --- a/include/linux/spi/s3c24xx.h +++ b/include/linux/spi/s3c24xx.h @@ -23,4 +23,6 @@ struct s3c2410_spi_info { void (*set_cs)(struct s3c2410_spi_info *spi, int cs, int pol); }; +extern int s3c24xx_set_fiq(unsigned int irq, bool on); + #endif /* __LINUX_SPI_S3C24XX_H */ From 3ab546205411a245ef0f60ec708467a072855c6f Mon Sep 17 00:00:00 2001 From: Axel Lin Date: Sun, 12 Jan 2014 14:40:22 +0800 Subject: [PATCH 19/23] spi: ti-qspi: Simplify qspi_write_msg and qspi_read_msg implementation Make the unit of wlen to be byte, and simplify the code to avoid duplicate code for different wlen cases. Signed-off-by: Axel Lin Acked-by: Sourav Poddar Signed-off-by: Mark Brown --- drivers/spi/spi-ti-qspi.c | 61 +++++++++++++-------------------------- 1 file changed, 20 insertions(+), 41 deletions(-) diff --git a/drivers/spi/spi-ti-qspi.c b/drivers/spi/spi-ti-qspi.c index 1211b663c814..a850b403b51b 100644 --- a/drivers/spi/spi-ti-qspi.c +++ b/drivers/spi/spi-ti-qspi.c @@ -208,53 +208,36 @@ static int qspi_write_msg(struct ti_qspi *qspi, struct spi_transfer *t) txbuf = t->tx_buf; cmd = qspi->cmd | QSPI_WR_SNGL; count = t->len; - wlen = t->bits_per_word; + wlen = t->bits_per_word >> 3; /* in bytes */ while (count) { switch (wlen) { - case 8: + case 1: dev_dbg(qspi->dev, "tx cmd %08x dc %08x data %02x\n", cmd, qspi->dc, *txbuf); writeb(*txbuf, qspi->base + QSPI_SPI_DATA_REG); - ti_qspi_write(qspi, cmd, QSPI_SPI_CMD_REG); - ret = wait_for_completion_timeout(&qspi->transfer_complete, - QSPI_COMPLETION_TIMEOUT); - if (ret == 0) { - dev_err(qspi->dev, "write timed out\n"); - return -ETIMEDOUT; - } - txbuf += 1; - count -= 1; break; - case 16: + case 2: dev_dbg(qspi->dev, "tx cmd %08x dc %08x data %04x\n", cmd, qspi->dc, *txbuf); writew(*((u16 *)txbuf), qspi->base + QSPI_SPI_DATA_REG); - ti_qspi_write(qspi, cmd, QSPI_SPI_CMD_REG); - ret = wait_for_completion_timeout(&qspi->transfer_complete, - QSPI_COMPLETION_TIMEOUT); - if (ret == 0) { - dev_err(qspi->dev, "write timed out\n"); - return -ETIMEDOUT; - } - txbuf += 2; - count -= 2; break; - case 32: + case 4: dev_dbg(qspi->dev, "tx cmd %08x dc %08x data %08x\n", cmd, qspi->dc, *txbuf); writel(*((u32 *)txbuf), qspi->base + QSPI_SPI_DATA_REG); - ti_qspi_write(qspi, cmd, QSPI_SPI_CMD_REG); - ret = wait_for_completion_timeout(&qspi->transfer_complete, - QSPI_COMPLETION_TIMEOUT); - if (ret == 0) { - dev_err(qspi->dev, "write timed out\n"); - return -ETIMEDOUT; - } - txbuf += 4; - count -= 4; break; } + + ti_qspi_write(qspi, cmd, QSPI_SPI_CMD_REG); + ret = wait_for_completion_timeout(&qspi->transfer_complete, + QSPI_COMPLETION_TIMEOUT); + if (ret == 0) { + dev_err(qspi->dev, "write timed out\n"); + return -ETIMEDOUT; + } + txbuf += wlen; + count -= wlen; } return 0; @@ -280,7 +263,7 @@ static int qspi_read_msg(struct ti_qspi *qspi, struct spi_transfer *t) break; } count = t->len; - wlen = t->bits_per_word; + wlen = t->bits_per_word >> 3; /* in bytes */ while (count) { dev_dbg(qspi->dev, "rx cmd %08x dc %08x\n", cmd, qspi->dc); @@ -292,22 +275,18 @@ static int qspi_read_msg(struct ti_qspi *qspi, struct spi_transfer *t) return -ETIMEDOUT; } switch (wlen) { - case 8: + case 1: *rxbuf = readb(qspi->base + QSPI_SPI_DATA_REG); - rxbuf += 1; - count -= 1; break; - case 16: + case 2: *((u16 *)rxbuf) = readw(qspi->base + QSPI_SPI_DATA_REG); - rxbuf += 2; - count -= 2; break; - case 32: + case 4: *((u32 *)rxbuf) = readl(qspi->base + QSPI_SPI_DATA_REG); - rxbuf += 4; - count -= 4; break; } + rxbuf += wlen; + count -= wlen; } return 0; From 5a33d30ff1b8fdfb5bd8f4fa46dd473bf768aeff Mon Sep 17 00:00:00 2001 From: Axel Lin Date: Sun, 12 Jan 2014 15:02:32 +0800 Subject: [PATCH 20/23] spi: ti-qspi: Fixup driver name The driver name in current code looks like a compatible string which is not the naming convention for platform drivers. Fix it and also add modalias since this driver can be built as a module. Signed-off-by: Axel Lin Acked-by: Sourav Poddar Signed-off-by: Mark Brown --- drivers/spi/spi-ti-qspi.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/spi/spi-ti-qspi.c b/drivers/spi/spi-ti-qspi.c index a850b403b51b..251e43f72dbb 100644 --- a/drivers/spi/spi-ti-qspi.c +++ b/drivers/spi/spi-ti-qspi.c @@ -560,7 +560,7 @@ static struct platform_driver ti_qspi_driver = { .probe = ti_qspi_probe, .remove = ti_qspi_remove, .driver = { - .name = "ti,dra7xxx-qspi", + .name = "ti-qspi", .owner = THIS_MODULE, .pm = &ti_qspi_pm_ops, .of_match_table = ti_qspi_match, @@ -572,3 +572,4 @@ module_platform_driver(ti_qspi_driver); MODULE_AUTHOR("Sourav Poddar "); MODULE_LICENSE("GPL v2"); MODULE_DESCRIPTION("TI QSPI controller driver"); +MODULE_ALIAS("platform:ti-qspi"); From 909e709c77df739ccba610dc48a301fd9ee8249c Mon Sep 17 00:00:00 2001 From: Axel Lin Date: Mon, 13 Jan 2014 10:00:44 +0800 Subject: [PATCH 21/23] spi: sh: Use spi_sh_clear_bit() instead of open-coded We have a spi_sh_clear_bit() function, there's no reason not to use it. Signed-off-by: Axel Lin Signed-off-by: Mark Brown --- drivers/spi/spi-sh.c | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-) diff --git a/drivers/spi/spi-sh.c b/drivers/spi/spi-sh.c index c120a70094f2..9fea8ccdce45 100644 --- a/drivers/spi/spi-sh.c +++ b/drivers/spi/spi-sh.c @@ -171,7 +171,6 @@ static int spi_sh_send(struct spi_sh_data *ss, struct spi_message *mesg, int remain = t->len; int cur_len; unsigned char *data; - unsigned long tmp; long ret; if (t->len) @@ -213,9 +212,7 @@ static int spi_sh_send(struct spi_sh_data *ss, struct spi_message *mesg, } if (list_is_last(&t->transfer_list, &mesg->transfers)) { - tmp = spi_sh_read(ss, SPI_SH_CR1); - tmp = tmp & ~(SPI_SH_SSD | SPI_SH_SSDB); - spi_sh_write(ss, tmp, SPI_SH_CR1); + spi_sh_clear_bit(ss, SPI_SH_SSD | SPI_SH_SSDB, SPI_SH_CR1); spi_sh_set_bit(ss, SPI_SH_SSA, SPI_SH_CR1); ss->cr1 &= ~SPI_SH_TBE; @@ -239,7 +236,6 @@ static int spi_sh_receive(struct spi_sh_data *ss, struct spi_message *mesg, int remain = t->len; int cur_len; unsigned char *data; - unsigned long tmp; long ret; if (t->len > SPI_SH_MAX_BYTE) @@ -247,9 +243,7 @@ static int spi_sh_receive(struct spi_sh_data *ss, struct spi_message *mesg, else spi_sh_write(ss, t->len, SPI_SH_CR3); - tmp = spi_sh_read(ss, SPI_SH_CR1); - tmp = tmp & ~(SPI_SH_SSD | SPI_SH_SSDB); - spi_sh_write(ss, tmp, SPI_SH_CR1); + spi_sh_clear_bit(ss, SPI_SH_SSD | SPI_SH_SSDB, SPI_SH_CR1); spi_sh_set_bit(ss, SPI_SH_SSA, SPI_SH_CR1); spi_sh_wait_write_buffer_empty(ss); From 3e83c1949790d542435866651f451ddecc30ad41 Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Sun, 12 Jan 2014 14:07:50 +0100 Subject: [PATCH 22/23] spi/s3c64xx: Correct indentation Signed-off-by: Geert Uytterhoeven Signed-off-by: Mark Brown --- drivers/spi/spi-s3c64xx.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/spi/spi-s3c64xx.c b/drivers/spi/spi-s3c64xx.c index b4ea9306cf35..ae907dde1371 100644 --- a/drivers/spi/spi-s3c64xx.c +++ b/drivers/spi/spi-s3c64xx.c @@ -890,7 +890,7 @@ static int s3c64xx_spi_transfer_one(struct spi_master *master, unsigned long flags; int use_dma; - reinit_completion(&sdd->xfer_completion); + reinit_completion(&sdd->xfer_completion); /* Only BPW and Speed may change across transfers */ bpw = xfer->bits_per_word; From 382cebb02a68764a51a412b8affccd325059d0a5 Mon Sep 17 00:00:00 2001 From: Mika Westerberg Date: Thu, 16 Jan 2014 14:50:55 +0200 Subject: [PATCH 23/23] spi/pxa2xx: fix compilation warning when !CONFIG_PM_SLEEP MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit CONFIG_PM will be set if either or both CONFIG_PM_SLEEP and CONFIG_PM_RUNTIME is set. Compiling the driver with !CONFIG_PM_SLEEP causes following compilation warning: drivers/spi/spi-pxa2xx.c:1270:12: warning: ‘pxa2xx_spi_suspend’ defined but not used [-Wunused-function] Fix this by using CONFIG_PM_SLEEP instead. Signed-off-by: Mika Westerberg Signed-off-by: Mark Brown --- drivers/spi/spi-pxa2xx.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/spi/spi-pxa2xx.c b/drivers/spi/spi-pxa2xx.c index cb0e1f1137ad..7d98a64e6a09 100644 --- a/drivers/spi/spi-pxa2xx.c +++ b/drivers/spi/spi-pxa2xx.c @@ -1264,7 +1264,7 @@ static void pxa2xx_spi_shutdown(struct platform_device *pdev) dev_err(&pdev->dev, "shutdown failed with %d\n", status); } -#ifdef CONFIG_PM +#ifdef CONFIG_PM_SLEEP static int pxa2xx_spi_suspend(struct device *dev) { struct driver_data *drv_data = dev_get_drvdata(dev);