From: Linus Torvalds Date: Mon, 8 Oct 2012 22:07:14 +0000 (+0900) Subject: Merge tag 'sound-3.7' of git://git.kernel.org/pub/scm/linux/kernel/git/tiwai/sound X-Git-Url: https://git.stricted.de/?a=commitdiff_plain;h=f5a246eab9a268f51ba8189ea5b098a1bfff200e;p=GitHub%2FLineageOS%2Fandroid_kernel_motorola_exynos9610.git Merge tag 'sound-3.7' of git://git./linux/kernel/git/tiwai/sound Pull sound updates from Takashi Iwai: "This contains pretty many small commits covering fairly large range of files in sound/ directory. Partly because of additional API support and partly because of constantly developed ASoC and ARM stuff. Some highlights: - Introduced the helper function and documentation for exposing the channel map via control API, as discussed in Plumbers; most of PCI drivers are covered, will follow more drivers later - Most of drivers have been replaced with the new PM callbacks (if the bus is supported) - HD-audio controller got the support of runtime PM and the support of D3 clock-stop. Also changing the power_save option in sysfs kicks off immediately to enable / disable the power-save mode. - Another significant code change in HD-audio is the rewrite of firmware loading code. Other than that, most of changes in HD-audio are continued cleanups and standardization for the generic auto parser and bug fixes (HBR, device-specific fixups), in addition to the support of channel-map API. - Addition of ASoC bindings for the compressed API, used by the mid-x86 drivers. - Lots of cleanups and API refreshes for ASoC codec drivers and DaVinci. - Conversion of OMAP to dmaengine. - New machine driver for Wolfson Microelectronics Bells. - New CODEC driver for Wolfson Microelectronics WM0010. - Enhancements to the ux500 and wm2000 drivers - A new driver for DA9055 and the support for regulator bypass mode." Fix up various arm soc header file reorg conflicts. * tag 'sound-3.7' of git://git.kernel.org/pub/scm/linux/kernel/git/tiwai/sound: (339 commits) ALSA: hda - Add new codec ALC283 ALC290 support ALSA: hda - avoid unneccesary indices on "Headphone Jack" controls ALSA: hda - fix indices on boost volume on Conexant ALSA: aloop - add locking to timer access ALSA: hda - Fix hang caused by race during suspend. sound: Remove unnecessary semicolon ALSA: hda/realtek - Fix detection of ALC271X codec ALSA: hda - Add inverted internal mic quirk for Lenovo IdeaPad U310 ALSA: hda - make Realtek/Sigmatel/Conexant use the generic unsol event ALSA: hda - make a generic unsol event handler ASoC: codecs: Add DA9055 codec driver ASoC: eukrea-tlv320: Convert it to platform driver ALSA: ASoC: add DT bindings for CS4271 ASoC: wm_hubs: Ensure volume updates are handled during class W startup ASoC: wm5110: Adding missing volume update bits ASoC: wm5110: Add OUT3R support ASoC: wm5110: Add AEC loopback support ASoC: wm5110: Rename EPOUT to HPOUT3 ASoC: arizona: Add more clock rates ASoC: arizona: Add more DSP options for mixer input muxes ... --- f5a246eab9a268f51ba8189ea5b098a1bfff200e diff --cc arch/arm/mach-davinci/davinci.h index a37fc44e29bc,8661b2013527..12d544befcfa --- a/arch/arm/mach-davinci/davinci.h +++ b/arch/arm/mach-davinci/davinci.h @@@ -22,10 -22,11 +22,10 @@@ #include #include #include - - #include + #include - -#include +#include #include + #include #include #include diff --cc arch/arm/mach-davinci/dm355.c index adbde33eca01,e47a3f0e8ac4..a255434908db --- a/arch/arm/mach-davinci/dm355.c +++ b/arch/arm/mach-davinci/dm355.c @@@ -26,8 -26,7 +26,7 @@@ #include #include #include - #include -#include +#include #include #include "davinci.h" diff --cc arch/arm/mach-davinci/dm365.c index 719e22f2a37e,f473745d6e3c..b680c832e0ba --- a/arch/arm/mach-davinci/dm365.c +++ b/arch/arm/mach-davinci/dm365.c @@@ -29,9 -29,8 +29,8 @@@ #include #include #include - #include -#include -#include +#include +#include #include #include "davinci.h" diff --cc arch/arm/mach-davinci/include/mach/da8xx.h index 33e78ae2a254,c74a6abef187..c9ee723c56f3 --- a/arch/arm/mach-davinci/include/mach/da8xx.h +++ b/arch/arm/mach-davinci/include/mach/da8xx.h @@@ -19,12 -20,11 +20,11 @@@ #include #include - #include -#include -#include -#include #include -#include +#include +#include +#include +#include extern void __iomem *da8xx_syscfg0_base; extern void __iomem *da8xx_syscfg1_base; diff --cc arch/arm/mach-imx/mach-imx27_visstrim_m10.c index 821d6aac411c,562722959666..141756f00ae5 --- a/arch/arm/mach-imx/mach-imx27_visstrim_m10.c +++ b/arch/arm/mach-imx/mach-imx27_visstrim_m10.c @@@ -32,6 -32,8 +32,7 @@@ #include #include #include -#include + #include #include #include #include @@@ -403,47 -436,14 +434,55 @@@ static const struct imx_ssi_platform_da .flags = IMX_SSI_DMA | IMX_SSI_SYN, }; +/* coda */ + +static void __init visstrim_coda_init(void) +{ + struct platform_device *pdev; + int dma; + + pdev = imx27_add_coda(); + dma = dma_declare_coherent_memory(&pdev->dev, + mx2_camera_base + MX2_CAMERA_BUF_SIZE, + mx2_camera_base + MX2_CAMERA_BUF_SIZE, + MX2_CAMERA_BUF_SIZE, + DMA_MEMORY_MAP | DMA_MEMORY_EXCLUSIVE); + if (!(dma & DMA_MEMORY_MAP)) + return; +} + +/* DMA deinterlace */ +static struct platform_device visstrim_deinterlace = { + .name = "m2m-deinterlace", + .id = 0, +}; + +static void __init visstrim_deinterlace_init(void) +{ + int ret = -ENOMEM; + struct platform_device *pdev = &visstrim_deinterlace; + int dma; + + ret = platform_device_register(pdev); + + dma = dma_declare_coherent_memory(&pdev->dev, + mx2_camera_base + 2 * MX2_CAMERA_BUF_SIZE, + mx2_camera_base + 2 * MX2_CAMERA_BUF_SIZE, + MX2_CAMERA_BUF_SIZE, + DMA_MEMORY_MAP | DMA_MEMORY_EXCLUSIVE); + if (!(dma & DMA_MEMORY_MAP)) + return; +} + + + /* Audio */ + static const struct snd_mx27vis_platform_data snd_mx27vis_pdata __initconst = { + .amp_gain0_gpio = AMP_GAIN_0, + .amp_gain1_gpio = AMP_GAIN_1, + .amp_mutel_gpio = AMP_MUTE_SDL, + .amp_muter_gpio = AMP_MUTE_SDR, + }; + static void __init visstrim_m10_revision(void) { int exp_version = 0; diff --cc arch/arm/mach-omap2/board-zoom-peripherals.c index 6bcc107b9fc3,a7d3b0480744..67f8540c8e07 --- a/arch/arm/mach-omap2/board-zoom-peripherals.c +++ b/arch/arm/mach-omap2/board-zoom-peripherals.c @@@ -245,13 -245,10 +246,7 @@@ static int zoom_twl_gpio_setup(struct d return ret; } - /* EXTMUTE callback function */ - static void zoom2_set_hs_extmute(int mute) - { - gpio_set_value(ZOOM2_HEADSET_EXTMUTE_GPIO, mute); - } - static struct twl4030_gpio_platform_data zoom_gpio_data = { - .gpio_base = OMAP_MAX_GPIO_LINES, - .irq_base = TWL4030_GPIO_IRQ_BASE, - .irq_end = TWL4030_GPIO_IRQ_END, .setup = zoom_twl_gpio_setup, }; @@@ -277,9 -274,9 +272,9 @@@ static int __init omap_i2c_init(void codec_data->ramp_delay_value = 3; /* 161 ms */ codec_data->hs_extmute = 1; - codec_data->set_hs_extmute = zoom2_set_hs_extmute; + codec_data->hs_extmute_gpio = ZOOM2_HEADSET_EXTMUTE_GPIO; } - omap_pmic_init(1, 2400, "twl5030", INT_34XX_SYS_NIRQ, &zoom_twldata); + omap_pmic_init(1, 2400, "twl5030", 7 + OMAP_INTC_START, &zoom_twldata); omap_register_i2c_bus(2, 400, NULL, 0); omap_register_i2c_bus(3, 400, NULL, 0); return 0; diff --cc arch/arm/mach-omap2/mcbsp.c index 7d47407d6d46,d57a3578bf03..37f8f948047b --- a/arch/arm/mach-omap2/mcbsp.c +++ b/arch/arm/mach-omap2/mcbsp.c @@@ -15,11 -15,14 +15,12 @@@ #include #include #include + #include #include #include +#include -#include #include -#include -#include #include #include diff --cc drivers/dma/ep93xx_dma.c index 64256f644252,493735b9b2c9..bcfde400904f --- a/drivers/dma/ep93xx_dma.c +++ b/drivers/dma/ep93xx_dma.c @@@ -1118,8 -1118,9 +1118,9 @@@ fail * @chan: channel * @dma_addr: DMA mapped address of the buffer * @buf_len: length of the buffer (in bytes) - * @period_len: lenght of a single period + * @period_len: length of a single period * @dir: direction of the operation + * @flags: tx descriptor status flags * @context: operation context (ignored) * * Prepares a descriptor for cyclic DMA operation. This means that once the diff --cc include/linux/platform_data/asoc-ti-mcbsp.h index 18814127809a,000000000000..c78d90b28b19 mode 100644,000000..100644 --- a/include/linux/platform_data/asoc-ti-mcbsp.h +++ b/include/linux/platform_data/asoc-ti-mcbsp.h @@@ -1,62 -1,0 +1,60 @@@ +/* + * arch/arm/plat-omap/include/mach/mcbsp.h + * + * Defines for Multi-Channel Buffered Serial Port + * + * Copyright (C) 2002 RidgeRun, Inc. + * Author: Steve Johnson + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + */ +#ifndef __ASM_ARCH_OMAP_MCBSP_H +#define __ASM_ARCH_OMAP_MCBSP_H + +#include +#include + +#define MCBSP_CONFIG_TYPE2 0x2 +#define MCBSP_CONFIG_TYPE3 0x3 +#define MCBSP_CONFIG_TYPE4 0x4 + +/* Platform specific configuration */ +struct omap_mcbsp_ops { + void (*request)(unsigned int); + void (*free)(unsigned int); +}; + +struct omap_mcbsp_platform_data { + struct omap_mcbsp_ops *ops; + u16 buffer_size; + u8 reg_size; + u8 reg_step; + + /* McBSP platform and instance specific features */ + bool has_wakeup; /* Wakeup capability */ + bool has_ccr; /* Transceiver has configuration control registers */ + int (*enable_st_clock)(unsigned int, bool); - int (*set_clk_src)(struct device *dev, struct clk *clk, const char *src); - int (*mux_signal)(struct device *dev, const char *signal, const char *src); +}; + +/** + * omap_mcbsp_dev_attr - OMAP McBSP device attributes for omap_hwmod + * @sidetone: name of the sidetone device + */ +struct omap_mcbsp_dev_attr { + const char *sidetone; +}; + +#endif diff --cc sound/soc/cirrus/ep93xx-ac97.c index 000000000000,bdffab33e160..c3521653cfd3 mode 000000,100644..100644 --- a/sound/soc/cirrus/ep93xx-ac97.c +++ b/sound/soc/cirrus/ep93xx-ac97.c @@@ -1,0 -1,435 +1,435 @@@ + /* + * ASoC driver for Cirrus Logic EP93xx AC97 controller. + * + * Copyright (c) 2010 Mika Westerberg + * + * Based on s3c-ac97 ASoC driver by Jaswinder Singh. + * + * 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 + #include + -#include ++#include + #include "ep93xx-pcm.h" + + /* + * Per channel (1-4) registers. + */ + #define AC97CH(n) (((n) - 1) * 0x20) + + #define AC97DR(n) (AC97CH(n) + 0x0000) + + #define AC97RXCR(n) (AC97CH(n) + 0x0004) + #define AC97RXCR_REN BIT(0) + #define AC97RXCR_RX3 BIT(3) + #define AC97RXCR_RX4 BIT(4) + #define AC97RXCR_CM BIT(15) + + #define AC97TXCR(n) (AC97CH(n) + 0x0008) + #define AC97TXCR_TEN BIT(0) + #define AC97TXCR_TX3 BIT(3) + #define AC97TXCR_TX4 BIT(4) + #define AC97TXCR_CM BIT(15) + + #define AC97SR(n) (AC97CH(n) + 0x000c) + #define AC97SR_TXFE BIT(1) + #define AC97SR_TXUE BIT(6) + + #define AC97RISR(n) (AC97CH(n) + 0x0010) + #define AC97ISR(n) (AC97CH(n) + 0x0014) + #define AC97IE(n) (AC97CH(n) + 0x0018) + + /* + * Global AC97 controller registers. + */ + #define AC97S1DATA 0x0080 + #define AC97S2DATA 0x0084 + #define AC97S12DATA 0x0088 + + #define AC97RGIS 0x008c + #define AC97GIS 0x0090 + #define AC97IM 0x0094 + /* + * Common bits for RGIS, GIS and IM registers. + */ + #define AC97_SLOT2RXVALID BIT(1) + #define AC97_CODECREADY BIT(5) + #define AC97_SLOT2TXCOMPLETE BIT(6) + + #define AC97EOI 0x0098 + #define AC97EOI_WINT BIT(0) + #define AC97EOI_CODECREADY BIT(1) + + #define AC97GCR 0x009c + #define AC97GCR_AC97IFE BIT(0) + + #define AC97RESET 0x00a0 + #define AC97RESET_TIMEDRESET BIT(0) + + #define AC97SYNC 0x00a4 + #define AC97SYNC_TIMEDSYNC BIT(0) + + #define AC97_TIMEOUT msecs_to_jiffies(5) + + /** + * struct ep93xx_ac97_info - EP93xx AC97 controller info structure + * @lock: mutex serializing access to the bus (slot 1 & 2 ops) + * @dev: pointer to the platform device dev structure + * @regs: mapped AC97 controller registers + * @done: bus ops wait here for an interrupt + */ + struct ep93xx_ac97_info { + struct mutex lock; + struct device *dev; + void __iomem *regs; + struct completion done; + }; + + /* currently ALSA only supports a single AC97 device */ + static struct ep93xx_ac97_info *ep93xx_ac97_info; + + static struct ep93xx_pcm_dma_params ep93xx_ac97_pcm_out = { + .name = "ac97-pcm-out", + .dma_port = EP93XX_DMA_AAC1, + }; + + static struct ep93xx_pcm_dma_params ep93xx_ac97_pcm_in = { + .name = "ac97-pcm-in", + .dma_port = EP93XX_DMA_AAC1, + }; + + static inline unsigned ep93xx_ac97_read_reg(struct ep93xx_ac97_info *info, + unsigned reg) + { + return __raw_readl(info->regs + reg); + } + + static inline void ep93xx_ac97_write_reg(struct ep93xx_ac97_info *info, + unsigned reg, unsigned val) + { + __raw_writel(val, info->regs + reg); + } + + static unsigned short ep93xx_ac97_read(struct snd_ac97 *ac97, + unsigned short reg) + { + struct ep93xx_ac97_info *info = ep93xx_ac97_info; + unsigned short val; + + mutex_lock(&info->lock); + + ep93xx_ac97_write_reg(info, AC97S1DATA, reg); + ep93xx_ac97_write_reg(info, AC97IM, AC97_SLOT2RXVALID); + if (!wait_for_completion_timeout(&info->done, AC97_TIMEOUT)) { + dev_warn(info->dev, "timeout reading register %x\n", reg); + mutex_unlock(&info->lock); + return -ETIMEDOUT; + } + val = (unsigned short)ep93xx_ac97_read_reg(info, AC97S2DATA); + + mutex_unlock(&info->lock); + return val; + } + + static void ep93xx_ac97_write(struct snd_ac97 *ac97, + unsigned short reg, + unsigned short val) + { + struct ep93xx_ac97_info *info = ep93xx_ac97_info; + + mutex_lock(&info->lock); + + /* + * Writes to the codec need to be done so that slot 2 is filled in + * before slot 1. + */ + ep93xx_ac97_write_reg(info, AC97S2DATA, val); + ep93xx_ac97_write_reg(info, AC97S1DATA, reg); + + ep93xx_ac97_write_reg(info, AC97IM, AC97_SLOT2TXCOMPLETE); + if (!wait_for_completion_timeout(&info->done, AC97_TIMEOUT)) + dev_warn(info->dev, "timeout writing register %x\n", reg); + + mutex_unlock(&info->lock); + } + + static void ep93xx_ac97_warm_reset(struct snd_ac97 *ac97) + { + struct ep93xx_ac97_info *info = ep93xx_ac97_info; + + mutex_lock(&info->lock); + + /* + * We are assuming that before this functions gets called, the codec + * BIT_CLK is stopped by forcing the codec into powerdown mode. We can + * control the SYNC signal directly via AC97SYNC register. Using + * TIMEDSYNC the controller will keep the SYNC high > 1us. + */ + ep93xx_ac97_write_reg(info, AC97SYNC, AC97SYNC_TIMEDSYNC); + ep93xx_ac97_write_reg(info, AC97IM, AC97_CODECREADY); + if (!wait_for_completion_timeout(&info->done, AC97_TIMEOUT)) + dev_warn(info->dev, "codec warm reset timeout\n"); + + mutex_unlock(&info->lock); + } + + static void ep93xx_ac97_cold_reset(struct snd_ac97 *ac97) + { + struct ep93xx_ac97_info *info = ep93xx_ac97_info; + + mutex_lock(&info->lock); + + /* + * For doing cold reset, we disable the AC97 controller interface, clear + * WINT and CODECREADY bits, and finally enable the interface again. + */ + ep93xx_ac97_write_reg(info, AC97GCR, 0); + ep93xx_ac97_write_reg(info, AC97EOI, AC97EOI_CODECREADY | AC97EOI_WINT); + ep93xx_ac97_write_reg(info, AC97GCR, AC97GCR_AC97IFE); + + /* + * Now, assert the reset and wait for the codec to become ready. + */ + ep93xx_ac97_write_reg(info, AC97RESET, AC97RESET_TIMEDRESET); + ep93xx_ac97_write_reg(info, AC97IM, AC97_CODECREADY); + if (!wait_for_completion_timeout(&info->done, AC97_TIMEOUT)) + dev_warn(info->dev, "codec cold reset timeout\n"); + + /* + * Give the codec some time to come fully out from the reset. This way + * we ensure that the subsequent reads/writes will work. + */ + usleep_range(15000, 20000); + + mutex_unlock(&info->lock); + } + + static irqreturn_t ep93xx_ac97_interrupt(int irq, void *dev_id) + { + struct ep93xx_ac97_info *info = dev_id; + unsigned status, mask; + + /* + * Just mask out the interrupt and wake up the waiting thread. + * Interrupts are cleared via reading/writing to slot 1 & 2 registers by + * the waiting thread. + */ + status = ep93xx_ac97_read_reg(info, AC97GIS); + mask = ep93xx_ac97_read_reg(info, AC97IM); + mask &= ~status; + ep93xx_ac97_write_reg(info, AC97IM, mask); + + complete(&info->done); + return IRQ_HANDLED; + } + + struct snd_ac97_bus_ops soc_ac97_ops = { + .read = ep93xx_ac97_read, + .write = ep93xx_ac97_write, + .reset = ep93xx_ac97_cold_reset, + .warm_reset = ep93xx_ac97_warm_reset, + }; + EXPORT_SYMBOL_GPL(soc_ac97_ops); + + static int ep93xx_ac97_trigger(struct snd_pcm_substream *substream, + int cmd, struct snd_soc_dai *dai) + { + struct ep93xx_ac97_info *info = snd_soc_dai_get_drvdata(dai); + unsigned v = 0; + + switch (cmd) { + case SNDRV_PCM_TRIGGER_START: + case SNDRV_PCM_TRIGGER_RESUME: + case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: + if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { + /* + * Enable compact mode, TX slots 3 & 4, and the TX FIFO + * itself. + */ + v |= AC97TXCR_CM; + v |= AC97TXCR_TX3 | AC97TXCR_TX4; + v |= AC97TXCR_TEN; + ep93xx_ac97_write_reg(info, AC97TXCR(1), v); + } else { + /* + * Enable compact mode, RX slots 3 & 4, and the RX FIFO + * itself. + */ + v |= AC97RXCR_CM; + v |= AC97RXCR_RX3 | AC97RXCR_RX4; + v |= AC97RXCR_REN; + ep93xx_ac97_write_reg(info, AC97RXCR(1), v); + } + break; + + case SNDRV_PCM_TRIGGER_STOP: + case SNDRV_PCM_TRIGGER_SUSPEND: + case SNDRV_PCM_TRIGGER_PAUSE_PUSH: + if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { + /* + * As per Cirrus EP93xx errata described below: + * + * http://www.cirrus.com/en/pubs/errata/ER667E2B.pdf + * + * we will wait for the TX FIFO to be empty before + * clearing the TEN bit. + */ + unsigned long timeout = jiffies + AC97_TIMEOUT; + + do { + v = ep93xx_ac97_read_reg(info, AC97SR(1)); + if (time_after(jiffies, timeout)) { + dev_warn(info->dev, "TX timeout\n"); + break; + } + } while (!(v & (AC97SR_TXFE | AC97SR_TXUE))); + + /* disable the TX FIFO */ + ep93xx_ac97_write_reg(info, AC97TXCR(1), 0); + } else { + /* disable the RX FIFO */ + ep93xx_ac97_write_reg(info, AC97RXCR(1), 0); + } + break; + + default: + dev_warn(info->dev, "unknown command %d\n", cmd); + return -EINVAL; + } + + return 0; + } + + static int ep93xx_ac97_startup(struct snd_pcm_substream *substream, + struct snd_soc_dai *dai) + { + struct ep93xx_pcm_dma_params *dma_data; + + if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) + dma_data = &ep93xx_ac97_pcm_out; + else + dma_data = &ep93xx_ac97_pcm_in; + + snd_soc_dai_set_dma_data(dai, substream, dma_data); + return 0; + } + + static const struct snd_soc_dai_ops ep93xx_ac97_dai_ops = { + .startup = ep93xx_ac97_startup, + .trigger = ep93xx_ac97_trigger, + }; + + static struct snd_soc_dai_driver ep93xx_ac97_dai = { + .name = "ep93xx-ac97", + .id = 0, + .ac97_control = 1, + .playback = { + .stream_name = "AC97 Playback", + .channels_min = 2, + .channels_max = 2, + .rates = SNDRV_PCM_RATE_8000_48000, + .formats = SNDRV_PCM_FMTBIT_S16_LE, + }, + .capture = { + .stream_name = "AC97 Capture", + .channels_min = 2, + .channels_max = 2, + .rates = SNDRV_PCM_RATE_8000_48000, + .formats = SNDRV_PCM_FMTBIT_S16_LE, + }, + .ops = &ep93xx_ac97_dai_ops, + }; + + static int __devinit ep93xx_ac97_probe(struct platform_device *pdev) + { + struct ep93xx_ac97_info *info; + struct resource *res; + unsigned int irq; + int ret; + + info = devm_kzalloc(&pdev->dev, sizeof(*info), GFP_KERNEL); + if (!info) + return -ENOMEM; + + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + if (!res) + return -ENODEV; + + info->regs = devm_request_and_ioremap(&pdev->dev, res); + if (!info->regs) + return -ENXIO; + + irq = platform_get_irq(pdev, 0); + if (!irq) + return -ENODEV; + + ret = devm_request_irq(&pdev->dev, irq, ep93xx_ac97_interrupt, + IRQF_TRIGGER_HIGH, pdev->name, info); + if (ret) + goto fail; + + dev_set_drvdata(&pdev->dev, info); + + mutex_init(&info->lock); + init_completion(&info->done); + info->dev = &pdev->dev; + + ep93xx_ac97_info = info; + platform_set_drvdata(pdev, info); + + ret = snd_soc_register_dai(&pdev->dev, &ep93xx_ac97_dai); + if (ret) + goto fail; + + return 0; + + fail: + platform_set_drvdata(pdev, NULL); + ep93xx_ac97_info = NULL; + dev_set_drvdata(&pdev->dev, NULL); + return ret; + } + + static int __devexit ep93xx_ac97_remove(struct platform_device *pdev) + { + struct ep93xx_ac97_info *info = platform_get_drvdata(pdev); + + snd_soc_unregister_dai(&pdev->dev); + + /* disable the AC97 controller */ + ep93xx_ac97_write_reg(info, AC97GCR, 0); + + platform_set_drvdata(pdev, NULL); + ep93xx_ac97_info = NULL; + dev_set_drvdata(&pdev->dev, NULL); + + return 0; + } + + static struct platform_driver ep93xx_ac97_driver = { + .probe = ep93xx_ac97_probe, + .remove = __devexit_p(ep93xx_ac97_remove), + .driver = { + .name = "ep93xx-ac97", + .owner = THIS_MODULE, + }, + }; + + module_platform_driver(ep93xx_ac97_driver); + + MODULE_DESCRIPTION("EP93xx AC97 ASoC Driver"); + MODULE_AUTHOR("Mika Westerberg "); + MODULE_LICENSE("GPL"); + MODULE_ALIAS("platform:ep93xx-ac97"); diff --cc sound/soc/cirrus/ep93xx-i2s.c index 000000000000,8df8f6dc474f..ac4a7515e7be mode 000000,100644..100644 --- a/sound/soc/cirrus/ep93xx-i2s.c +++ b/sound/soc/cirrus/ep93xx-i2s.c @@@ -1,0 -1,451 +1,451 @@@ + /* + * linux/sound/soc/ep93xx-i2s.c + * EP93xx I2S driver + * + * Copyright (C) 2010 Ryan Mallon + * + * Based on the original driver by: + * Copyright (C) 2007 Chase Douglas + * Copyright (C) 2006 Lennert Buytenhek + * + * 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 + #include + #include + + #include + #include -#include ++#include + + #include "ep93xx-pcm.h" + + #define EP93XX_I2S_TXCLKCFG 0x00 + #define EP93XX_I2S_RXCLKCFG 0x04 + #define EP93XX_I2S_GLCTRL 0x0C + + #define EP93XX_I2S_TXLINCTRLDATA 0x28 + #define EP93XX_I2S_TXCTRL 0x2C + #define EP93XX_I2S_TXWRDLEN 0x30 + #define EP93XX_I2S_TX0EN 0x34 + + #define EP93XX_I2S_RXLINCTRLDATA 0x58 + #define EP93XX_I2S_RXCTRL 0x5C + #define EP93XX_I2S_RXWRDLEN 0x60 + #define EP93XX_I2S_RX0EN 0x64 + + #define EP93XX_I2S_WRDLEN_16 (0 << 0) + #define EP93XX_I2S_WRDLEN_24 (1 << 0) + #define EP93XX_I2S_WRDLEN_32 (2 << 0) + + #define EP93XX_I2S_LINCTRLDATA_R_JUST (1 << 2) /* Right justify */ + + #define EP93XX_I2S_CLKCFG_LRS (1 << 0) /* lrclk polarity */ + #define EP93XX_I2S_CLKCFG_CKP (1 << 1) /* Bit clock polarity */ + #define EP93XX_I2S_CLKCFG_REL (1 << 2) /* First bit transition */ + #define EP93XX_I2S_CLKCFG_MASTER (1 << 3) /* Master mode */ + #define EP93XX_I2S_CLKCFG_NBCG (1 << 4) /* Not bit clock gating */ + + struct ep93xx_i2s_info { + struct clk *mclk; + struct clk *sclk; + struct clk *lrclk; + struct ep93xx_pcm_dma_params *dma_params; + void __iomem *regs; + }; + + struct ep93xx_pcm_dma_params ep93xx_i2s_dma_params[] = { + [SNDRV_PCM_STREAM_PLAYBACK] = { + .name = "i2s-pcm-out", + .dma_port = EP93XX_DMA_I2S1, + }, + [SNDRV_PCM_STREAM_CAPTURE] = { + .name = "i2s-pcm-in", + .dma_port = EP93XX_DMA_I2S1, + }, + }; + + static inline void ep93xx_i2s_write_reg(struct ep93xx_i2s_info *info, + unsigned reg, unsigned val) + { + __raw_writel(val, info->regs + reg); + } + + static inline unsigned ep93xx_i2s_read_reg(struct ep93xx_i2s_info *info, + unsigned reg) + { + return __raw_readl(info->regs + reg); + } + + static void ep93xx_i2s_enable(struct ep93xx_i2s_info *info, int stream) + { + unsigned base_reg; + int i; + + if ((ep93xx_i2s_read_reg(info, EP93XX_I2S_TX0EN) & 0x1) == 0 && + (ep93xx_i2s_read_reg(info, EP93XX_I2S_RX0EN) & 0x1) == 0) { + /* Enable clocks */ + clk_enable(info->mclk); + clk_enable(info->sclk); + clk_enable(info->lrclk); + + /* Enable i2s */ + ep93xx_i2s_write_reg(info, EP93XX_I2S_GLCTRL, 1); + } + + /* Enable fifos */ + if (stream == SNDRV_PCM_STREAM_PLAYBACK) + base_reg = EP93XX_I2S_TX0EN; + else + base_reg = EP93XX_I2S_RX0EN; + for (i = 0; i < 3; i++) + ep93xx_i2s_write_reg(info, base_reg + (i * 4), 1); + } + + static void ep93xx_i2s_disable(struct ep93xx_i2s_info *info, int stream) + { + unsigned base_reg; + int i; + + /* Disable fifos */ + if (stream == SNDRV_PCM_STREAM_PLAYBACK) + base_reg = EP93XX_I2S_TX0EN; + else + base_reg = EP93XX_I2S_RX0EN; + for (i = 0; i < 3; i++) + ep93xx_i2s_write_reg(info, base_reg + (i * 4), 0); + + if ((ep93xx_i2s_read_reg(info, EP93XX_I2S_TX0EN) & 0x1) == 0 && + (ep93xx_i2s_read_reg(info, EP93XX_I2S_RX0EN) & 0x1) == 0) { + /* Disable i2s */ + ep93xx_i2s_write_reg(info, EP93XX_I2S_GLCTRL, 0); + + /* Disable clocks */ + clk_disable(info->lrclk); + clk_disable(info->sclk); + clk_disable(info->mclk); + } + } + + static int ep93xx_i2s_startup(struct snd_pcm_substream *substream, + struct snd_soc_dai *dai) + { + struct snd_soc_pcm_runtime *rtd = substream->private_data; + struct ep93xx_i2s_info *info = snd_soc_dai_get_drvdata(dai); + struct snd_soc_dai *cpu_dai = rtd->cpu_dai; + + snd_soc_dai_set_dma_data(cpu_dai, substream, + &info->dma_params[substream->stream]); + return 0; + } + + static void ep93xx_i2s_shutdown(struct snd_pcm_substream *substream, + struct snd_soc_dai *dai) + { + struct ep93xx_i2s_info *info = snd_soc_dai_get_drvdata(dai); + + ep93xx_i2s_disable(info, substream->stream); + } + + static int ep93xx_i2s_set_dai_fmt(struct snd_soc_dai *cpu_dai, + unsigned int fmt) + { + struct ep93xx_i2s_info *info = snd_soc_dai_get_drvdata(cpu_dai); + unsigned int clk_cfg, lin_ctrl; + + clk_cfg = ep93xx_i2s_read_reg(info, EP93XX_I2S_RXCLKCFG); + lin_ctrl = ep93xx_i2s_read_reg(info, EP93XX_I2S_RXLINCTRLDATA); + + switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) { + case SND_SOC_DAIFMT_I2S: + clk_cfg |= EP93XX_I2S_CLKCFG_REL; + lin_ctrl &= ~EP93XX_I2S_LINCTRLDATA_R_JUST; + break; + + case SND_SOC_DAIFMT_LEFT_J: + clk_cfg &= ~EP93XX_I2S_CLKCFG_REL; + lin_ctrl &= ~EP93XX_I2S_LINCTRLDATA_R_JUST; + break; + + case SND_SOC_DAIFMT_RIGHT_J: + clk_cfg &= ~EP93XX_I2S_CLKCFG_REL; + lin_ctrl |= EP93XX_I2S_LINCTRLDATA_R_JUST; + break; + + default: + return -EINVAL; + } + + switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { + case SND_SOC_DAIFMT_CBS_CFS: + /* CPU is master */ + clk_cfg |= EP93XX_I2S_CLKCFG_MASTER; + break; + + case SND_SOC_DAIFMT_CBM_CFM: + /* Codec is master */ + clk_cfg &= ~EP93XX_I2S_CLKCFG_MASTER; + break; + + default: + return -EINVAL; + } + + switch (fmt & SND_SOC_DAIFMT_INV_MASK) { + case SND_SOC_DAIFMT_NB_NF: + /* Negative bit clock, lrclk low on left word */ + clk_cfg &= ~(EP93XX_I2S_CLKCFG_CKP | EP93XX_I2S_CLKCFG_REL); + break; + + case SND_SOC_DAIFMT_NB_IF: + /* Negative bit clock, lrclk low on right word */ + clk_cfg &= ~EP93XX_I2S_CLKCFG_CKP; + clk_cfg |= EP93XX_I2S_CLKCFG_REL; + break; + + case SND_SOC_DAIFMT_IB_NF: + /* Positive bit clock, lrclk low on left word */ + clk_cfg |= EP93XX_I2S_CLKCFG_CKP; + clk_cfg &= ~EP93XX_I2S_CLKCFG_REL; + break; + + case SND_SOC_DAIFMT_IB_IF: + /* Positive bit clock, lrclk low on right word */ + clk_cfg |= EP93XX_I2S_CLKCFG_CKP | EP93XX_I2S_CLKCFG_REL; + break; + } + + /* Write new register values */ + ep93xx_i2s_write_reg(info, EP93XX_I2S_RXCLKCFG, clk_cfg); + ep93xx_i2s_write_reg(info, EP93XX_I2S_TXCLKCFG, clk_cfg); + ep93xx_i2s_write_reg(info, EP93XX_I2S_RXLINCTRLDATA, lin_ctrl); + ep93xx_i2s_write_reg(info, EP93XX_I2S_TXLINCTRLDATA, lin_ctrl); + return 0; + } + + static int ep93xx_i2s_hw_params(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params, + struct snd_soc_dai *dai) + { + struct ep93xx_i2s_info *info = snd_soc_dai_get_drvdata(dai); + unsigned word_len, div, sdiv, lrdiv; + int err; + + switch (params_format(params)) { + case SNDRV_PCM_FORMAT_S16_LE: + word_len = EP93XX_I2S_WRDLEN_16; + break; + + case SNDRV_PCM_FORMAT_S24_LE: + word_len = EP93XX_I2S_WRDLEN_24; + break; + + case SNDRV_PCM_FORMAT_S32_LE: + word_len = EP93XX_I2S_WRDLEN_32; + break; + + default: + return -EINVAL; + } + + if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) + ep93xx_i2s_write_reg(info, EP93XX_I2S_TXWRDLEN, word_len); + else + ep93xx_i2s_write_reg(info, EP93XX_I2S_RXWRDLEN, word_len); + + /* + * EP93xx I2S module can be setup so SCLK / LRCLK value can be + * 32, 64, 128. MCLK / SCLK value can be 2 and 4. + * We set LRCLK equal to `rate' and minimum SCLK / LRCLK + * value is 64, because our sample size is 32 bit * 2 channels. + * I2S standard permits us to transmit more bits than + * the codec uses. + */ + div = clk_get_rate(info->mclk) / params_rate(params); + sdiv = 4; + if (div > (256 + 512) / 2) { + lrdiv = 128; + } else { + lrdiv = 64; + if (div < (128 + 256) / 2) + sdiv = 2; + } + + err = clk_set_rate(info->sclk, clk_get_rate(info->mclk) / sdiv); + if (err) + return err; + + err = clk_set_rate(info->lrclk, clk_get_rate(info->sclk) / lrdiv); + if (err) + return err; + + ep93xx_i2s_enable(info, substream->stream); + return 0; + } + + static int ep93xx_i2s_set_sysclk(struct snd_soc_dai *cpu_dai, int clk_id, + unsigned int freq, int dir) + { + struct ep93xx_i2s_info *info = snd_soc_dai_get_drvdata(cpu_dai); + + if (dir == SND_SOC_CLOCK_IN || clk_id != 0) + return -EINVAL; + + return clk_set_rate(info->mclk, freq); + } + + #ifdef CONFIG_PM + static int ep93xx_i2s_suspend(struct snd_soc_dai *dai) + { + struct ep93xx_i2s_info *info = snd_soc_dai_get_drvdata(dai); + + if (!dai->active) + return 0; + + ep93xx_i2s_disable(info, SNDRV_PCM_STREAM_PLAYBACK); + ep93xx_i2s_disable(info, SNDRV_PCM_STREAM_CAPTURE); + + return 0; + } + + static int ep93xx_i2s_resume(struct snd_soc_dai *dai) + { + struct ep93xx_i2s_info *info = snd_soc_dai_get_drvdata(dai); + + if (!dai->active) + return 0; + + ep93xx_i2s_enable(info, SNDRV_PCM_STREAM_PLAYBACK); + ep93xx_i2s_enable(info, SNDRV_PCM_STREAM_CAPTURE); + + return 0; + } + #else + #define ep93xx_i2s_suspend NULL + #define ep93xx_i2s_resume NULL + #endif + + static const struct snd_soc_dai_ops ep93xx_i2s_dai_ops = { + .startup = ep93xx_i2s_startup, + .shutdown = ep93xx_i2s_shutdown, + .hw_params = ep93xx_i2s_hw_params, + .set_sysclk = ep93xx_i2s_set_sysclk, + .set_fmt = ep93xx_i2s_set_dai_fmt, + }; + + #define EP93XX_I2S_FORMATS (SNDRV_PCM_FMTBIT_S32_LE) + + static struct snd_soc_dai_driver ep93xx_i2s_dai = { + .symmetric_rates= 1, + .suspend = ep93xx_i2s_suspend, + .resume = ep93xx_i2s_resume, + .playback = { + .channels_min = 2, + .channels_max = 2, + .rates = SNDRV_PCM_RATE_8000_192000, + .formats = EP93XX_I2S_FORMATS, + }, + .capture = { + .channels_min = 2, + .channels_max = 2, + .rates = SNDRV_PCM_RATE_8000_192000, + .formats = EP93XX_I2S_FORMATS, + }, + .ops = &ep93xx_i2s_dai_ops, + }; + + static int ep93xx_i2s_probe(struct platform_device *pdev) + { + struct ep93xx_i2s_info *info; + struct resource *res; + int err; + + info = devm_kzalloc(&pdev->dev, sizeof(*info), GFP_KERNEL); + if (!info) + return -ENOMEM; + + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + if (!res) + return -ENODEV; + + info->regs = devm_request_and_ioremap(&pdev->dev, res); + if (!info->regs) + return -ENXIO; + + info->mclk = clk_get(&pdev->dev, "mclk"); + if (IS_ERR(info->mclk)) { + err = PTR_ERR(info->mclk); + goto fail; + } + + info->sclk = clk_get(&pdev->dev, "sclk"); + if (IS_ERR(info->sclk)) { + err = PTR_ERR(info->sclk); + goto fail_put_mclk; + } + + info->lrclk = clk_get(&pdev->dev, "lrclk"); + if (IS_ERR(info->lrclk)) { + err = PTR_ERR(info->lrclk); + goto fail_put_sclk; + } + + dev_set_drvdata(&pdev->dev, info); + info->dma_params = ep93xx_i2s_dma_params; + + err = snd_soc_register_dai(&pdev->dev, &ep93xx_i2s_dai); + if (err) + goto fail_put_lrclk; + + return 0; + + fail_put_lrclk: + dev_set_drvdata(&pdev->dev, NULL); + clk_put(info->lrclk); + fail_put_sclk: + clk_put(info->sclk); + fail_put_mclk: + clk_put(info->mclk); + fail: + return err; + } + + static int __devexit ep93xx_i2s_remove(struct platform_device *pdev) + { + struct ep93xx_i2s_info *info = dev_get_drvdata(&pdev->dev); + + snd_soc_unregister_dai(&pdev->dev); + dev_set_drvdata(&pdev->dev, NULL); + clk_put(info->lrclk); + clk_put(info->sclk); + clk_put(info->mclk); + return 0; + } + + static struct platform_driver ep93xx_i2s_driver = { + .probe = ep93xx_i2s_probe, + .remove = __devexit_p(ep93xx_i2s_remove), + .driver = { + .name = "ep93xx-i2s", + .owner = THIS_MODULE, + }, + }; + + module_platform_driver(ep93xx_i2s_driver); + + MODULE_ALIAS("platform:ep93xx-i2s"); + MODULE_AUTHOR("Ryan Mallon"); + MODULE_DESCRIPTION("EP93XX I2S driver"); + MODULE_LICENSE("GPL"); diff --cc sound/soc/cirrus/ep93xx-pcm.c index 000000000000,4eea98b42bc8..665d9c94cc17 mode 000000,100644..100644 --- a/sound/soc/cirrus/ep93xx-pcm.c +++ b/sound/soc/cirrus/ep93xx-pcm.c @@@ -1,0 -1,242 +1,242 @@@ + /* + * linux/sound/arm/ep93xx-pcm.c - EP93xx ALSA PCM interface + * + * Copyright (C) 2006 Lennert Buytenhek + * Copyright (C) 2006 Applied Data Systems + * + * Rewritten for the SoC audio subsystem (Based on PXA2xx code): + * Copyright (c) 2008 Ryan Mallon + * + * 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 + #include + #include + #include + -#include ++#include + #include + #include + + #include "ep93xx-pcm.h" + + static const struct snd_pcm_hardware ep93xx_pcm_hardware = { + .info = (SNDRV_PCM_INFO_MMAP | + SNDRV_PCM_INFO_MMAP_VALID | + SNDRV_PCM_INFO_INTERLEAVED | + SNDRV_PCM_INFO_BLOCK_TRANSFER), + + .rates = SNDRV_PCM_RATE_8000_192000, + .rate_min = SNDRV_PCM_RATE_8000, + .rate_max = SNDRV_PCM_RATE_192000, + + .formats = (SNDRV_PCM_FMTBIT_S16_LE | + SNDRV_PCM_FMTBIT_S24_LE | + SNDRV_PCM_FMTBIT_S32_LE), + + .buffer_bytes_max = 131072, + .period_bytes_min = 32, + .period_bytes_max = 32768, + .periods_min = 1, + .periods_max = 32, + .fifo_size = 32, + }; + + static bool ep93xx_pcm_dma_filter(struct dma_chan *chan, void *filter_param) + { + struct ep93xx_dma_data *data = filter_param; + + if (data->direction == ep93xx_dma_chan_direction(chan)) { + chan->private = data; + return true; + } + + return false; + } + + static int ep93xx_pcm_open(struct snd_pcm_substream *substream) + { + struct snd_soc_pcm_runtime *rtd = substream->private_data; + struct snd_soc_dai *cpu_dai = rtd->cpu_dai; + struct ep93xx_pcm_dma_params *dma_params; + struct ep93xx_dma_data *dma_data; + int ret; + + snd_soc_set_runtime_hwparams(substream, &ep93xx_pcm_hardware); + + dma_data = kmalloc(sizeof(*dma_data), GFP_KERNEL); + if (!dma_data) + return -ENOMEM; + + dma_params = snd_soc_dai_get_dma_data(cpu_dai, substream); + dma_data->port = dma_params->dma_port; + dma_data->name = dma_params->name; + dma_data->direction = snd_pcm_substream_to_dma_direction(substream); + + ret = snd_dmaengine_pcm_open(substream, ep93xx_pcm_dma_filter, dma_data); + if (ret) { + kfree(dma_data); + return ret; + } + + snd_dmaengine_pcm_set_data(substream, dma_data); + + return 0; + } + + static int ep93xx_pcm_close(struct snd_pcm_substream *substream) + { + struct dma_data *dma_data = snd_dmaengine_pcm_get_data(substream); + + snd_dmaengine_pcm_close(substream); + kfree(dma_data); + return 0; + } + + static int ep93xx_pcm_hw_params(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params) + { + snd_pcm_set_runtime_buffer(substream, &substream->dma_buffer); + + return 0; + } + + static int ep93xx_pcm_hw_free(struct snd_pcm_substream *substream) + { + snd_pcm_set_runtime_buffer(substream, NULL); + return 0; + } + + static int ep93xx_pcm_mmap(struct snd_pcm_substream *substream, + struct vm_area_struct *vma) + { + struct snd_pcm_runtime *runtime = substream->runtime; + + return dma_mmap_writecombine(substream->pcm->card->dev, vma, + runtime->dma_area, + runtime->dma_addr, + runtime->dma_bytes); + } + + static struct snd_pcm_ops ep93xx_pcm_ops = { + .open = ep93xx_pcm_open, + .close = ep93xx_pcm_close, + .ioctl = snd_pcm_lib_ioctl, + .hw_params = ep93xx_pcm_hw_params, + .hw_free = ep93xx_pcm_hw_free, + .trigger = snd_dmaengine_pcm_trigger, + .pointer = snd_dmaengine_pcm_pointer_no_residue, + .mmap = ep93xx_pcm_mmap, + }; + + static int ep93xx_pcm_preallocate_dma_buffer(struct snd_pcm *pcm, int stream) + { + struct snd_pcm_substream *substream = pcm->streams[stream].substream; + struct snd_dma_buffer *buf = &substream->dma_buffer; + size_t size = ep93xx_pcm_hardware.buffer_bytes_max; + + buf->dev.type = SNDRV_DMA_TYPE_DEV; + buf->dev.dev = pcm->card->dev; + buf->private_data = NULL; + buf->area = dma_alloc_writecombine(pcm->card->dev, size, + &buf->addr, GFP_KERNEL); + buf->bytes = size; + + return (buf->area == NULL) ? -ENOMEM : 0; + } + + static void ep93xx_pcm_free_dma_buffers(struct snd_pcm *pcm) + { + struct snd_pcm_substream *substream; + struct snd_dma_buffer *buf; + int stream; + + for (stream = 0; stream < 2; stream++) { + substream = pcm->streams[stream].substream; + if (!substream) + continue; + + buf = &substream->dma_buffer; + if (!buf->area) + continue; + + dma_free_writecombine(pcm->card->dev, buf->bytes, buf->area, + buf->addr); + buf->area = NULL; + } + } + + static u64 ep93xx_pcm_dmamask = DMA_BIT_MASK(32); + + static int ep93xx_pcm_new(struct snd_soc_pcm_runtime *rtd) + { + struct snd_card *card = rtd->card->snd_card; + struct snd_pcm *pcm = rtd->pcm; + int ret = 0; + + if (!card->dev->dma_mask) + card->dev->dma_mask = &ep93xx_pcm_dmamask; + if (!card->dev->coherent_dma_mask) + card->dev->coherent_dma_mask = DMA_BIT_MASK(32); + + if (pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream) { + ret = ep93xx_pcm_preallocate_dma_buffer(pcm, + SNDRV_PCM_STREAM_PLAYBACK); + if (ret) + return ret; + } + + if (pcm->streams[SNDRV_PCM_STREAM_CAPTURE].substream) { + ret = ep93xx_pcm_preallocate_dma_buffer(pcm, + SNDRV_PCM_STREAM_CAPTURE); + if (ret) + return ret; + } + + return 0; + } + + static struct snd_soc_platform_driver ep93xx_soc_platform = { + .ops = &ep93xx_pcm_ops, + .pcm_new = &ep93xx_pcm_new, + .pcm_free = &ep93xx_pcm_free_dma_buffers, + }; + + static int __devinit ep93xx_soc_platform_probe(struct platform_device *pdev) + { + return snd_soc_register_platform(&pdev->dev, &ep93xx_soc_platform); + } + + static int __devexit ep93xx_soc_platform_remove(struct platform_device *pdev) + { + snd_soc_unregister_platform(&pdev->dev); + return 0; + } + + static struct platform_driver ep93xx_pcm_driver = { + .driver = { + .name = "ep93xx-pcm-audio", + .owner = THIS_MODULE, + }, + + .probe = ep93xx_soc_platform_probe, + .remove = __devexit_p(ep93xx_soc_platform_remove), + }; + + module_platform_driver(ep93xx_pcm_driver); + + MODULE_AUTHOR("Ryan Mallon"); + MODULE_DESCRIPTION("EP93xx ALSA PCM interface"); + MODULE_LICENSE("GPL"); + MODULE_ALIAS("platform:ep93xx-pcm-audio"); diff --cc sound/soc/omap/mcbsp.c index a681a9a8b846,bc06175e6367..afb8d4f1bedf --- a/sound/soc/omap/mcbsp.c +++ b/sound/soc/omap/mcbsp.c @@@ -24,10 -24,9 +24,11 @@@ #include #include #include + #include -#include +#include + +#include #include "mcbsp.h" diff --cc sound/soc/omap/omap-mcbsp.c index 1b18627763ce,fef2f5933bb2..a6ee15747859 --- a/sound/soc/omap/omap-mcbsp.c +++ b/sound/soc/omap/omap-mcbsp.c @@@ -32,9 -34,7 +34,8 @@@ #include #include -#include +#include - #include +#include #include "mcbsp.h" #include "omap-mcbsp.h" #include "omap-pcm.h" diff --cc sound/soc/omap/omap-pcm.c index b30994179885,a2636f6b8362..340874ebf9ae --- a/sound/soc/omap/omap-pcm.c +++ b/sound/soc/omap/omap-pcm.c @@@ -28,10 -29,9 +29,10 @@@ #include #include #include + #include #include +#include - #include #include "omap-pcm.h" static const struct snd_pcm_hardware omap_pcm_hardware = {