Commit 8e6714ac authored by Mark Brown's avatar Mark Brown

Merge branch 'topic/samsung' of...

Merge branch 'topic/samsung' of git://git.kernel.org/pub/scm/linux/kernel/git/broonie/sound into asoc-dma
parents 67c2fe2f 328089a4
...@@ -723,6 +723,7 @@ config ARCH_S3C64XX ...@@ -723,6 +723,7 @@ config ARCH_S3C64XX
bool "Samsung S3C64XX" bool "Samsung S3C64XX"
select ARCH_HAS_CPUFREQ select ARCH_HAS_CPUFREQ
select ARCH_REQUIRE_GPIOLIB select ARCH_REQUIRE_GPIOLIB
select ARM_AMBA
select ARM_VIC select ARM_VIC
select CLKDEV_LOOKUP select CLKDEV_LOOKUP
select CLKSRC_SAMSUNG_PWM select CLKSRC_SAMSUNG_PWM
......
...@@ -17,9 +17,10 @@ config CPU_S3C6410 ...@@ -17,9 +17,10 @@ config CPU_S3C6410
help help
Enable S3C6410 CPU support Enable S3C6410 CPU support
config S3C64XX_DMA config S3C64XX_PL080
bool "S3C64XX DMA" bool "S3C64XX DMA using generic PL08x driver"
select S3C_DMA select AMBA_PL08X
select SAMSUNG_DMADEV
config S3C64XX_SETUP_SDHCI config S3C64XX_SETUP_SDHCI
bool bool
......
...@@ -26,7 +26,7 @@ obj-$(CONFIG_CPU_IDLE) += cpuidle.o ...@@ -26,7 +26,7 @@ obj-$(CONFIG_CPU_IDLE) += cpuidle.o
# DMA support # DMA support
obj-$(CONFIG_S3C64XX_DMA) += dma.o obj-$(CONFIG_S3C64XX_PL080) += pl080.o
# Device support # Device support
......
...@@ -58,4 +58,9 @@ int __init s3c64xx_pm_late_initcall(void); ...@@ -58,4 +58,9 @@ int __init s3c64xx_pm_late_initcall(void);
static inline int s3c64xx_pm_late_initcall(void) { return 0; } static inline int s3c64xx_pm_late_initcall(void) { return 0; }
#endif #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 */ #endif /* __ARCH_ARM_MACH_S3C64XX_COMMON_H */
This diff is collapsed.
...@@ -11,51 +11,48 @@ ...@@ -11,51 +11,48 @@
#ifndef __ASM_ARCH_DMA_H #ifndef __ASM_ARCH_DMA_H
#define __ASM_ARCH_DMA_H __FILE__ #define __ASM_ARCH_DMA_H __FILE__
#define S3C_DMA_CHANNELS (16) #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")
/* 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 { enum dma_ch {
/* DMA0/SDMA0 */ DMACH_MAX = 32
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 */ struct s3c2410_dma_client {
DMACH_PCM1_TX = 16, char *name;
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) static inline bool samsung_dma_has_circular(void)
...@@ -65,67 +62,10 @@ static inline bool samsung_dma_has_circular(void) ...@@ -65,67 +62,10 @@ static inline bool samsung_dma_has_circular(void)
static inline bool samsung_dma_is_dmadev(void) static inline bool samsung_dma_is_dmadev(void)
{ {
return false; return true;
} }
#define S3C2410_DMAF_CIRCULAR (1 << 0)
#include <plat/dma.h>
#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 <plat/dma-core.h> #include <linux/amba/pl08x.h>
#include <plat/dma-ops.h>
#endif /* __ASM_ARCH_IRQ_H */ #endif /* __ASM_ARCH_IRQ_H */
/*
* Samsung's S3C64XX generic DMA support using amba-pl08x driver.
*
* Copyright (c) 2013 Tomasz Figa <tomasz.figa@gmail.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*/
#include <linux/kernel.h>
#include <linux/amba/bus.h>
#include <linux/amba/pl080.h>
#include <linux/amba/pl08x.h>
#include <linux/of.h>
#include <mach/irqs.h>
#include <mach/map.h>
#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);
...@@ -1468,6 +1468,8 @@ void __init s3c64xx_spi0_set_platdata(int (*cfg_gpio)(void), int src_clk_nr, ...@@ -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; pd.cfg_gpio = (cfg_gpio) ? cfg_gpio : s3c64xx_spi0_cfg_gpio;
#if defined(CONFIG_PL330_DMA) #if defined(CONFIG_PL330_DMA)
pd.filter = pl330_filter; pd.filter = pl330_filter;
#elif defined(CONFIG_S3C64XX_PL080)
pd.filter = pl08x_filter_id;
#elif defined(CONFIG_S3C24XX_DMAC) #elif defined(CONFIG_S3C24XX_DMAC)
pd.filter = s3c24xx_dma_filter; pd.filter = s3c24xx_dma_filter;
#endif #endif
...@@ -1509,8 +1511,10 @@ void __init s3c64xx_spi1_set_platdata(int (*cfg_gpio)(void), int src_clk_nr, ...@@ -1509,8 +1511,10 @@ void __init s3c64xx_spi1_set_platdata(int (*cfg_gpio)(void), int src_clk_nr,
pd.num_cs = num_cs; pd.num_cs = num_cs;
pd.src_clk_nr = src_clk_nr; pd.src_clk_nr = src_clk_nr;
pd.cfg_gpio = (cfg_gpio) ? cfg_gpio : s3c64xx_spi1_cfg_gpio; pd.cfg_gpio = (cfg_gpio) ? cfg_gpio : s3c64xx_spi1_cfg_gpio;
#ifdef CONFIG_PL330_DMA #if defined(CONFIG_PL330_DMA)
pd.filter = pl330_filter; pd.filter = pl330_filter;
#elif defined(CONFIG_S3C64XX_PL080)
pd.filter = pl08x_filter_id;
#endif #endif
s3c_set_platdata(&pd, sizeof(pd), &s3c64xx_device_spi1); 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, ...@@ -1550,8 +1554,10 @@ void __init s3c64xx_spi2_set_platdata(int (*cfg_gpio)(void), int src_clk_nr,
pd.num_cs = num_cs; pd.num_cs = num_cs;
pd.src_clk_nr = src_clk_nr; pd.src_clk_nr = src_clk_nr;
pd.cfg_gpio = (cfg_gpio) ? cfg_gpio : s3c64xx_spi2_cfg_gpio; pd.cfg_gpio = (cfg_gpio) ? cfg_gpio : s3c64xx_spi2_cfg_gpio;
#ifdef CONFIG_PL330_DMA #if defined(CONFIG_PL330_DMA)
pd.filter = pl330_filter; pd.filter = pl330_filter;
#elif defined(CONFIG_S3C64XX_PL080)
pd.filter = pl08x_filter_id;
#endif #endif
s3c_set_platdata(&pd, sizeof(pd), &s3c64xx_device_spi2); s3c_set_platdata(&pd, sizeof(pd), &s3c64xx_device_spi2);
......
...@@ -18,6 +18,12 @@ ...@@ -18,6 +18,12 @@
#include <mach/dma.h> #include <mach/dma.h>
#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, static unsigned samsung_dmadev_request(enum dma_ch dma_ch,
struct samsung_dma_req *param, struct samsung_dma_req *param,
struct device *dev, char *ch_name) struct device *dev, char *ch_name)
...@@ -30,7 +36,7 @@ static unsigned samsung_dmadev_request(enum dma_ch dma_ch, ...@@ -30,7 +36,7 @@ static unsigned samsung_dmadev_request(enum dma_ch dma_ch,
if (dev->of_node) if (dev->of_node)
return (unsigned)dma_request_slave_channel(dev, ch_name); return (unsigned)dma_request_slave_channel(dev, ch_name);
else else
return (unsigned)dma_request_channel(mask, pl330_filter, return (unsigned)dma_request_channel(mask, dma_filter,
(void *)dma_ch); (void *)dma_ch);
} }
......
...@@ -331,8 +331,8 @@ static struct samsung_clock_alias s3c64xx_clock_aliases[] = { ...@@ -331,8 +331,8 @@ static struct samsung_clock_alias s3c64xx_clock_aliases[] = {
ALIAS(HCLK_HSMMC1, "s3c-sdhci.1", "mmc_busclk.0"), ALIAS(HCLK_HSMMC1, "s3c-sdhci.1", "mmc_busclk.0"),
ALIAS(HCLK_HSMMC0, "s3c-sdhci.0", "hsmmc"), ALIAS(HCLK_HSMMC0, "s3c-sdhci.0", "hsmmc"),
ALIAS(HCLK_HSMMC0, "s3c-sdhci.0", "mmc_busclk.0"), 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_CAMIF, "s3c-camif", "camif"),
ALIAS(HCLK_LCD, "s3c-fb", "lcd"), ALIAS(HCLK_LCD, "s3c-fb", "lcd"),
ALIAS(PCLK_SPI1, "s3c6410-spi.1", "spi"), ALIAS(PCLK_SPI1, "s3c6410-spi.1", "spi"),
......
...@@ -395,7 +395,7 @@ config SPI_S3C24XX_FIQ ...@@ -395,7 +395,7 @@ config SPI_S3C24XX_FIQ
config SPI_S3C64XX config SPI_S3C64XX
tristate "Samsung S3C64XX series type SPI" tristate "Samsung S3C64XX series type SPI"
depends on PLAT_SAMSUNG depends on PLAT_SAMSUNG
select S3C64XX_DMA if ARCH_S3C64XX select S3C64XX_PL080 if ARCH_S3C64XX
help help
SPI driver for Samsung S3C64XX and newer SoCs. SPI driver for Samsung S3C64XX and newer SoCs.
......
config SND_SOC_SAMSUNG config SND_SOC_SAMSUNG
tristate "ASoC support for Samsung" tristate "ASoC support for Samsung"
depends on PLAT_SAMSUNG depends on PLAT_SAMSUNG
select S3C64XX_DMA if ARCH_S3C64XX select S3C2410_DMA if ARCH_S3C24XX
select S3C24XX_DMA if ARCH_S3C24XX select S3C64XX_PL080 if ARCH_S3C64XX
select SND_S3C_DMA if !ARCH_S3C24XX
select SND_S3C_DMA_LEGACY if ARCH_S3C24XX
select SND_SOC_GENERIC_DMAENGINE_PCM if !ARCH_S3C24XX
help help
Say Y or M if you want to add support for codecs attached to Say Y or M if you want to add support for codecs attached to
the Samsung SoCs' Audio interfaces. You will also need to the Samsung SoCs' Audio interfaces. You will also need to
select the audio interfaces to support below. select the audio interfaces to support below.
config SND_S3C_DMA
tristate
config SND_S3C_DMA_LEGACY
tristate
config SND_S3C24XX_I2S config SND_S3C24XX_I2S
tristate tristate
select S3C2410_DMA select S3C2410_DMA
......
# S3c24XX Platform Support # S3c24XX Platform Support
snd-soc-s3c24xx-objs := dma.o snd-soc-s3c-dma-objs := dmaengine.o
snd-soc-s3c-dma-legacy-objs := dma.o
snd-soc-idma-objs := idma.o snd-soc-idma-objs := idma.o
snd-soc-s3c24xx-i2s-objs := s3c24xx-i2s.o snd-soc-s3c24xx-i2s-objs := s3c24xx-i2s.o
snd-soc-s3c2412-i2s-objs := s3c2412-i2s.o snd-soc-s3c2412-i2s-objs := s3c2412-i2s.o
...@@ -9,7 +10,8 @@ snd-soc-samsung-spdif-objs := spdif.o ...@@ -9,7 +10,8 @@ snd-soc-samsung-spdif-objs := spdif.o
snd-soc-pcm-objs := pcm.o snd-soc-pcm-objs := pcm.o
snd-soc-i2s-objs := i2s.o snd-soc-i2s-objs := i2s.o
obj-$(CONFIG_SND_SOC_SAMSUNG) += snd-soc-s3c24xx.o obj-$(CONFIG_SND_S3C_DMA) += snd-soc-s3c-dma.o
obj-$(CONFIG_SND_S3C_DMA_LEGACY) += snd-soc-s3c-dma-legacy.o
obj-$(CONFIG_SND_S3C24XX_I2S) += snd-soc-s3c24xx-i2s.o obj-$(CONFIG_SND_S3C24XX_I2S) += snd-soc-s3c24xx-i2s.o
obj-$(CONFIG_SND_SAMSUNG_AC97) += snd-soc-ac97.o obj-$(CONFIG_SND_SAMSUNG_AC97) += snd-soc-ac97.o
obj-$(CONFIG_SND_S3C2412_SOC_I2S) += snd-soc-s3c2412-i2s.o obj-$(CONFIG_SND_S3C2412_SOC_I2S) += snd-soc-s3c2412-i2s.o
......
...@@ -221,24 +221,6 @@ static struct snd_ac97_bus_ops s3c_ac97_ops = { ...@@ -221,24 +221,6 @@ static struct snd_ac97_bus_ops s3c_ac97_ops = {
.reset = s3c_ac97_cold_reset, .reset = s3c_ac97_cold_reset,
}; };
static int s3c_ac97_hw_params(struct snd_pcm_substream *substream,
struct snd_pcm_hw_params *params,
struct snd_soc_dai *dai)
{
struct snd_soc_pcm_runtime *rtd = substream->private_data;
struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
struct s3c_dma_params *dma_data;
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
dma_data = &s3c_ac97_pcm_out;
else
dma_data = &s3c_ac97_pcm_in;
snd_soc_dai_set_dma_data(cpu_dai, substream, dma_data);
return 0;
}
static int s3c_ac97_trigger(struct snd_pcm_substream *substream, int cmd, static int s3c_ac97_trigger(struct snd_pcm_substream *substream, int cmd,
struct snd_soc_dai *dai) struct snd_soc_dai *dai)
{ {
...@@ -279,21 +261,6 @@ static int s3c_ac97_trigger(struct snd_pcm_substream *substream, int cmd, ...@@ -279,21 +261,6 @@ static int s3c_ac97_trigger(struct snd_pcm_substream *substream, int cmd,
return 0; return 0;
} }
static int s3c_ac97_hw_mic_params(struct snd_pcm_substream *substream,
struct snd_pcm_hw_params *params,
struct snd_soc_dai *dai)
{
struct snd_soc_pcm_runtime *rtd = substream->private_data;
struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
return -ENODEV;
else
snd_soc_dai_set_dma_data(cpu_dai, substream, &s3c_ac97_mic_in);
return 0;
}
static int s3c_ac97_mic_trigger(struct snd_pcm_substream *substream, static int s3c_ac97_mic_trigger(struct snd_pcm_substream *substream,
int cmd, struct snd_soc_dai *dai) int cmd, struct snd_soc_dai *dai)
{ {
...@@ -329,15 +296,27 @@ static int s3c_ac97_mic_trigger(struct snd_pcm_substream *substream, ...@@ -329,15 +296,27 @@ static int s3c_ac97_mic_trigger(struct snd_pcm_substream *substream,
} }
static const struct snd_soc_dai_ops s3c_ac97_dai_ops = { static const struct snd_soc_dai_ops s3c_ac97_dai_ops = {
.hw_params = s3c_ac97_hw_params,
.trigger = s3c_ac97_trigger, .trigger = s3c_ac97_trigger,
}; };
static const struct snd_soc_dai_ops s3c_ac97_mic_dai_ops = { static const struct snd_soc_dai_ops s3c_ac97_mic_dai_ops = {
.hw_params = s3c_ac97_hw_mic_params,
.trigger = s3c_ac97_mic_trigger, .trigger = s3c_ac97_mic_trigger,
}; };
static int s3c_ac97_dai_probe(struct snd_soc_dai *dai)
{
samsung_asoc_init_dma_data(dai, &s3c_ac97_pcm_out, &s3c_ac97_pcm_in);
return 0;
}
static int s3c_ac97_mic_dai_probe(struct snd_soc_dai *dai)
{
samsung_asoc_init_dma_data(dai, NULL, &s3c_ac97_mic_in);
return 0;
}
static struct snd_soc_dai_driver s3c_ac97_dai[] = { static struct snd_soc_dai_driver s3c_ac97_dai[] = {
[S3C_AC97_DAI_PCM] = { [S3C_AC97_DAI_PCM] = {
.name = "samsung-ac97", .name = "samsung-ac97",
...@@ -354,6 +333,7 @@ static struct snd_soc_dai_driver s3c_ac97_dai[] = { ...@@ -354,6 +333,7 @@ static struct snd_soc_dai_driver s3c_ac97_dai[] = {
.channels_max = 2, .channels_max = 2,
.rates = SNDRV_PCM_RATE_8000_48000, .rates = SNDRV_PCM_RATE_8000_48000,
.formats = SNDRV_PCM_FMTBIT_S16_LE,}, .formats = SNDRV_PCM_FMTBIT_S16_LE,},
.probe = s3c_ac97_dai_probe,
.ops = &s3c_ac97_dai_ops, .ops = &s3c_ac97_dai_ops,
}, },
[S3C_AC97_DAI_MIC] = { [S3C_AC97_DAI_MIC] = {
...@@ -365,6 +345,7 @@ static struct snd_soc_dai_driver s3c_ac97_dai[] = { ...@@ -365,6 +345,7 @@ static struct snd_soc_dai_driver s3c_ac97_dai[] = {
.channels_max = 1, .channels_max = 1,
.rates = SNDRV_PCM_RATE_8000_48000, .rates = SNDRV_PCM_RATE_8000_48000,
.formats = SNDRV_PCM_FMTBIT_S16_LE,}, .formats = SNDRV_PCM_FMTBIT_S16_LE,},
.probe = s3c_ac97_mic_dai_probe,
.ops = &s3c_ac97_mic_dai_ops, .ops = &s3c_ac97_mic_dai_ops,
}, },
}; };
......
...@@ -35,12 +35,6 @@ static const struct snd_pcm_hardware dma_hardware = { ...@@ -35,12 +35,6 @@ static const struct snd_pcm_hardware dma_hardware = {
SNDRV_PCM_INFO_BLOCK_TRANSFER | SNDRV_PCM_INFO_BLOCK_TRANSFER |
SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_MMAP |
SNDRV_PCM_INFO_MMAP_VALID, SNDRV_PCM_INFO_MMAP_VALID,
.formats = SNDRV_PCM_FMTBIT_S16_LE |
SNDRV_PCM_FMTBIT_U16_LE |
SNDRV_PCM_FMTBIT_U8 |
SNDRV_PCM_FMTBIT_S8,
.channels_min = 2,
.channels_max = 2,
.buffer_bytes_max = 128*1024, .buffer_bytes_max = 128*1024,
.period_bytes_min = PAGE_SIZE, .period_bytes_min = PAGE_SIZE,
.period_bytes_max = PAGE_SIZE*2, .period_bytes_max = PAGE_SIZE*2,
...@@ -441,6 +435,14 @@ static struct snd_soc_platform_driver samsung_asoc_platform = { ...@@ -441,6 +435,14 @@ static struct snd_soc_platform_driver samsung_asoc_platform = {
.pcm_free = dma_free_dma_buffers, .pcm_free = dma_free_dma_buffers,
}; };
void samsung_asoc_init_dma_data(struct snd_soc_dai *dai,
struct s3c_dma_params *playback,
struct s3c_dma_params *capture)
{
snd_soc_dai_init_dma_data(dai, playback, capture);
}
EXPORT_SYMBOL_GPL(samsung_asoc_init_dma_data);
int samsung_asoc_dma_platform_register(struct device *dev) int samsung_asoc_dma_platform_register(struct device *dev)
{ {
return snd_soc_register_platform(dev, &samsung_asoc_platform); return snd_soc_register_platform(dev, &samsung_asoc_platform);
......
...@@ -12,6 +12,8 @@ ...@@ -12,6 +12,8 @@
#ifndef _S3C_AUDIO_H #ifndef _S3C_AUDIO_H
#define _S3C_AUDIO_H #define _S3C_AUDIO_H
#include <sound/dmaengine_pcm.h>
struct s3c_dma_params { struct s3c_dma_params {
struct s3c2410_dma_client *client; /* stream identifier */ struct s3c2410_dma_client *client; /* stream identifier */
int channel; /* Channel ID */ int channel; /* Channel ID */
...@@ -20,8 +22,12 @@ struct s3c_dma_params { ...@@ -20,8 +22,12 @@ struct s3c_dma_params {
unsigned ch; unsigned ch;
struct samsung_dma_ops *ops; struct samsung_dma_ops *ops;
char *ch_name; char *ch_name;
struct snd_dmaengine_dai_dma_data dma_data;
}; };
void samsung_asoc_init_dma_data(struct snd_soc_dai *dai,
struct s3c_dma_params *playback,
struct s3c_dma_params *capture);
int samsung_asoc_dma_platform_register(struct device *dev); int samsung_asoc_dma_platform_register(struct device *dev);
void samsung_asoc_dma_platform_unregister(struct device *dev); void samsung_asoc_dma_platform_unregister(struct device *dev);
......
/*
* dmaengine.c - Samsung dmaengine wrapper
*
* Author: Mark Brown <broonie@linaro.org>
* Copyright 2013 Linaro
*
* 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.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
*/
#include <linux/module.h>
#include <linux/amba/pl08x.h>
#include <sound/core.h>
#include <sound/pcm.h>
#include <sound/pcm_params.h>
#include <sound/dmaengine_pcm.h>
#include <sound/soc.h>
#include <sound/soc-dai.h>
#include "dma.h"
#ifdef CONFIG_ARCH_S3C64XX
#define filter_fn pl08x_filter_id
#else
#define filter_fn NULL
#endif
static const struct snd_dmaengine_pcm_config samsung_dmaengine_pcm_config = {
.prepare_slave_config = snd_dmaengine_pcm_prepare_slave_config,
.compat_filter_fn = filter_fn,
};
void samsung_asoc_init_dma_data(struct snd_soc_dai *dai,
struct s3c_dma_params *playback,
struct s3c_dma_params *capture)
{
struct snd_dmaengine_dai_dma_data *playback_data = NULL;
struct snd_dmaengine_dai_dma_data *capture_data = NULL;
if (playback) {
playback_data = &playback->dma_data;
playback_data->filter_data = (void *)playback->channel;
playback_data->chan_name = playback->ch_name;
playback_data->addr = playback->dma_addr;
playback_data->addr_width = playback->dma_size;
}
if (capture) {
capture_data = &capture->dma_data;
capture_data->filter_data = (void *)capture->channel;
capture_data->chan_name = capture->ch_name;
capture_data->addr = capture->dma_addr;
capture_data->addr_width = capture->dma_size;
}
snd_soc_dai_init_dma_data(dai, playback_data, capture_data);
}
EXPORT_SYMBOL_GPL(samsung_asoc_init_dma_data);
int samsung_asoc_dma_platform_register(struct device *dev)
{
return snd_dmaengine_pcm_register(dev, &samsung_dmaengine_pcm_config,
SND_DMAENGINE_PCM_FLAG_CUSTOM_CHANNEL_NAME |
SND_DMAENGINE_PCM_FLAG_NO_RESIDUE |
SND_DMAENGINE_PCM_FLAG_COMPAT);
}
EXPORT_SYMBOL_GPL(samsung_asoc_dma_platform_register);
void samsung_asoc_dma_platform_unregister(struct device *dev)
{
return snd_dmaengine_pcm_unregister(dev);
}
EXPORT_SYMBOL_GPL(samsung_asoc_dma_platform_unregister);
MODULE_AUTHOR("Mark Brown <broonie@linaro.org>");
MODULE_DESCRIPTION("Samsung dmaengine ASoC driver");
MODULE_LICENSE("GPL");
...@@ -702,6 +702,8 @@ static int i2s_hw_params(struct snd_pcm_substream *substream, ...@@ -702,6 +702,8 @@ static int i2s_hw_params(struct snd_pcm_substream *substream,
} }
writel(mod, i2s->addr + I2SMOD); writel(mod, i2s->addr + I2SMOD);
samsung_asoc_init_dma_data(dai, &i2s->dma_playback, &i2s->dma_capture);
i2s->frmclk = params_rate(params); i2s->frmclk = params_rate(params);
return 0; return 0;
...@@ -946,8 +948,11 @@ static int samsung_i2s_dai_probe(struct snd_soc_dai *dai) ...@@ -946,8 +948,11 @@ static int samsung_i2s_dai_probe(struct snd_soc_dai *dai)
struct i2s_dai *i2s = to_info(dai); struct i2s_dai *i2s = to_info(dai);
struct i2s_dai *other = i2s->pri_dai ? : i2s->sec_dai; struct i2s_dai *other = i2s->pri_dai ? : i2s->sec_dai;
if (other && other->clk) /* If this is probe on secondary */ if (other && other->clk) { /* If this is probe on secondary */
samsung_asoc_init_dma_data(dai, &other->sec_dai->dma_playback,
NULL);
goto probe_exit; goto probe_exit;
}
i2s->addr = ioremap(i2s->base, 0x100); i2s->addr = ioremap(i2s->base, 0x100);
if (i2s->addr == NULL) { if (i2s->addr == NULL) {
...@@ -963,7 +968,7 @@ static int samsung_i2s_dai_probe(struct snd_soc_dai *dai) ...@@ -963,7 +968,7 @@ static int samsung_i2s_dai_probe(struct snd_soc_dai *dai)
} }
clk_prepare_enable(i2s->clk); clk_prepare_enable(i2s->clk);
snd_soc_dai_init_dma_data(dai, &i2s->dma_playback, &i2s->dma_capture); samsung_asoc_init_dma_data(dai, &i2s->dma_playback, &i2s->dma_capture);
if (other) { if (other) {
other->addr = i2s->addr; other->addr = i2s->addr;
......
...@@ -35,14 +35,6 @@ static const struct snd_pcm_hardware idma_hardware = { ...@@ -35,14 +35,6 @@ static const struct snd_pcm_hardware idma_hardware = {
SNDRV_PCM_INFO_MMAP_VALID | SNDRV_PCM_INFO_MMAP_VALID |
SNDRV_PCM_INFO_PAUSE | SNDRV_PCM_INFO_PAUSE |
SNDRV_PCM_INFO_RESUME, SNDRV_PCM_INFO_RESUME,
.formats = SNDRV_PCM_FMTBIT_S16_LE |
SNDRV_PCM_FMTBIT_U16_LE |
SNDRV_PCM_FMTBIT_S24_LE |
SNDRV_PCM_FMTBIT_U24_LE |
SNDRV_PCM_FMTBIT_U8 |
SNDRV_PCM_FMTBIT_S8,
.channels_min = 2,
.channels_max = 2,
.buffer_bytes_max = MAX_IDMA_BUFFER, .buffer_bytes_max = MAX_IDMA_BUFFER,
.period_bytes_min = 128, .period_bytes_min = 128,
.period_bytes_max = MAX_IDMA_PERIOD, .period_bytes_max = MAX_IDMA_PERIOD,
......
...@@ -275,7 +275,6 @@ static int s3c_pcm_hw_params(struct snd_pcm_substream *substream, ...@@ -275,7 +275,6 @@ static int s3c_pcm_hw_params(struct snd_pcm_substream *substream,
{ {
struct snd_soc_pcm_runtime *rtd = substream->private_data; struct snd_soc_pcm_runtime *rtd = substream->private_data;
struct s3c_pcm_info *pcm = snd_soc_dai_get_drvdata(rtd->cpu_dai); struct s3c_pcm_info *pcm = snd_soc_dai_get_drvdata(rtd->cpu_dai);
struct s3c_dma_params *dma_data;
void __iomem *regs = pcm->regs; void __iomem *regs = pcm->regs;
struct clk *clk; struct clk *clk;
int sclk_div, sync_div; int sclk_div, sync_div;
...@@ -284,13 +283,6 @@ static int s3c_pcm_hw_params(struct snd_pcm_substream *substream, ...@@ -284,13 +283,6 @@ static int s3c_pcm_hw_params(struct snd_pcm_substream *substream,
dev_dbg(pcm->dev, "Entered %s\n", __func__); dev_dbg(pcm->dev, "Entered %s\n", __func__);
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
dma_data = pcm->dma_playback;
else
dma_data = pcm->dma_capture;
snd_soc_dai_set_dma_data(rtd->cpu_dai, substream, dma_data);
/* Strictly check for sample size */ /* Strictly check for sample size */
switch (params_format(params)) { switch (params_format(params)) {
case SNDRV_PCM_FORMAT_S16_LE: case SNDRV_PCM_FORMAT_S16_LE:
...@@ -461,10 +453,20 @@ static const struct snd_soc_dai_ops s3c_pcm_dai_ops = { ...@@ -461,10 +453,20 @@ static const struct snd_soc_dai_ops s3c_pcm_dai_ops = {
.set_fmt = s3c_pcm_set_fmt, .set_fmt = s3c_pcm_set_fmt,
}; };
static int s3c_pcm_dai_probe(struct snd_soc_dai *dai)
{
struct s3c_pcm_info *pcm = snd_soc_dai_get_drvdata(dai);
snd_soc_dai_init_dma_data(dai, pcm->dma_playback, pcm->dma_capture);
return 0;
}
#define S3C_PCM_RATES SNDRV_PCM_RATE_8000_96000 #define S3C_PCM_RATES SNDRV_PCM_RATE_8000_96000
#define S3C_PCM_DAI_DECLARE \ #define S3C_PCM_DAI_DECLARE \
.symmetric_rates = 1, \ .symmetric_rates = 1, \
.probe = s3c_pcm_dai_probe, \
.ops = &s3c_pcm_dai_ops, \ .ops = &s3c_pcm_dai_ops, \
.playback = { \ .playback = { \
.channels_min = 2, \ .channels_min = 2, \
......
/* arch/arm/mach-s3c2410/include/mach/regs-ac97.h /*
*
* Copyright (c) 2006 Simtec Electronics <linux@simtec.co.uk> * Copyright (c) 2006 Simtec Electronics <linux@simtec.co.uk>
* http://www.simtec.co.uk/products/SWLINUX/ * http://www.simtec.co.uk/products/SWLINUX/
* *
...@@ -10,8 +9,8 @@ ...@@ -10,8 +9,8 @@
* S3C2440 AC97 Controller * S3C2440 AC97 Controller
*/ */
#ifndef __ASM_ARCH_REGS_AC97_H #ifndef __SAMSUNG_REGS_AC97_H__
#define __ASM_ARCH_REGS_AC97_H __FILE__ #define __SAMSUNG_REGS_AC97_H__
#define S3C_AC97_GLBCTRL (0x00) #define S3C_AC97_GLBCTRL (0x00)
...@@ -64,4 +63,4 @@ ...@@ -64,4 +63,4 @@
#define S3C_AC97_PCM_DATA (0x18) #define S3C_AC97_PCM_DATA (0x18)
#define S3C_AC97_MIC_DATA (0x1C) #define S3C_AC97_MIC_DATA (0x1C)
#endif /* __ASM_ARCH_REGS_AC97_H */ #endif /* __SAMSUNG_REGS_AC97_H__ */
/* arch/arm/plat-samsung/include/plat/regs-iis.h /*
*
* Copyright (c) 2003 Simtec Electronics <linux@simtec.co.uk> * Copyright (c) 2003 Simtec Electronics <linux@simtec.co.uk>
* http://www.simtec.co.uk/products/SWLINUX/ * http://www.simtec.co.uk/products/SWLINUX/
* *
...@@ -10,8 +9,8 @@ ...@@ -10,8 +9,8 @@
* S3C2410 IIS register definition * S3C2410 IIS register definition
*/ */
#ifndef __ASM_ARCH_REGS_IIS_H #ifndef __SAMSUNG_REGS_IIS_H__
#define __ASM_ARCH_REGS_IIS_H #define __SAMSUNG_REGS_IIS_H__
#define S3C2410_IISCON (0x00) #define S3C2410_IISCON (0x00)
...@@ -67,4 +66,4 @@ ...@@ -67,4 +66,4 @@
#define S3C2410_IISFIFO (0x10) #define S3C2410_IISFIFO (0x10)
#endif /* __ASM_ARCH_REGS_IIS_H */ #endif /* __SAMSUNG_REGS_IIS_H__ */
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment