#include <linux/davinci_emac.h>
#include <linux/platform_device.h>
#include <linux/spi/spi.h>
-
- #include <mach/asp.h>
+ #include <linux/platform_data/davinci_asp.h>
-
-#include <mach/keyscan.h>
+#include <linux/platform_data/keyscan-davinci.h>
#include <mach/hardware.h>
+ #include <mach/edma.h>
#include <media/davinci/vpfe_capture.h>
#include <media/davinci/vpif_types.h>
#include <mach/time.h>
#include <mach/serial.h>
#include <mach/common.h>
- #include <mach/asp.h>
-#include <mach/spi.h>
+#include <linux/platform_data/spi-davinci.h>
#include <mach/gpio-davinci.h>
#include "davinci.h"
#include <mach/time.h>
#include <mach/serial.h>
#include <mach/common.h>
- #include <mach/asp.h>
-#include <mach/keyscan.h>
-#include <mach/spi.h>
+#include <linux/platform_data/keyscan-davinci.h>
+#include <linux/platform_data/spi-davinci.h>
#include <mach/gpio-davinci.h>
#include "davinci.h"
#include <mach/serial.h>
#include <mach/edma.h>
- #include <mach/asp.h>
-#include <mach/i2c.h>
-#include <mach/mmc.h>
-#include <mach/usb.h>
#include <mach/pm.h>
-#include <mach/spi.h>
+#include <linux/platform_data/i2c-davinci.h>
+#include <linux/platform_data/mmc-davinci.h>
+#include <linux/platform_data/usb-davinci.h>
+#include <linux/platform_data/spi-davinci.h>
extern void __iomem *da8xx_syscfg0_base;
extern void __iomem *da8xx_syscfg1_base;
#include <linux/delay.h>
#include <linux/dma-mapping.h>
#include <linux/leds.h>
-#include <linux/memblock.h>
+ #include <linux/platform_data/asoc-mx27vis.h>
#include <media/soc_camera.h>
#include <sound/tlv320aic32x4.h>
#include <asm/mach-types.h>
.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;
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,
};
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;
#include <linux/clk.h>
#include <linux/err.h>
#include <linux/io.h>
+ #include <linux/of.h>
#include <linux/platform_device.h>
#include <linux/slab.h>
+#include <linux/platform_data/asoc-ti-mcbsp.h>
-#include <mach/irqs.h>
#include <plat/dma.h>
-#include <plat/cpu.h>
-#include <plat/mcbsp.h>
#include <plat/omap_device.h>
#include <linux/pm_runtime.h>
* @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
--- /dev/null
- 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);
+/*
+ * 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 <linux/spinlock.h>
+#include <linux/clk.h>
+
+#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);
+};
+
+/**
+ * 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
--- /dev/null
-#include <mach/dma.h>
+ /*
+ * 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 <linux/delay.h>
+ #include <linux/io.h>
+ #include <linux/init.h>
+ #include <linux/module.h>
+ #include <linux/platform_device.h>
+ #include <linux/slab.h>
+
+ #include <sound/core.h>
+ #include <sound/ac97_codec.h>
+ #include <sound/soc.h>
+
++#include <linux/platform_data/dma-ep93xx.h>
+ #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 <mika.westerberg@iki.fi>");
+ MODULE_LICENSE("GPL");
+ MODULE_ALIAS("platform:ep93xx-ac97");
--- /dev/null
-#include <mach/dma.h>
+ /*
+ * 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 <chasedouglas@gmail>
+ * Copyright (C) 2006 Lennert Buytenhek <buytenh@wantstofly.org>
+ *
+ * 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/module.h>
+ #include <linux/init.h>
+ #include <linux/slab.h>
+ #include <linux/clk.h>
+ #include <linux/io.h>
+
+ #include <sound/core.h>
+ #include <sound/pcm.h>
+ #include <sound/pcm_params.h>
+ #include <sound/initval.h>
+ #include <sound/soc.h>
+
+ #include <mach/hardware.h>
+ #include <mach/ep93xx-regs.h>
++#include <linux/platform_data/dma-ep93xx.h>
+
+ #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");
--- /dev/null
-#include <mach/dma.h>
+ /*
+ * linux/sound/arm/ep93xx-pcm.c - EP93xx ALSA PCM interface
+ *
+ * Copyright (C) 2006 Lennert Buytenhek <buytenh@wantstofly.org>
+ * 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 <linux/module.h>
+ #include <linux/init.h>
+ #include <linux/device.h>
+ #include <linux/slab.h>
+ #include <linux/dmaengine.h>
+ #include <linux/dma-mapping.h>
+
+ #include <sound/core.h>
+ #include <sound/pcm.h>
+ #include <sound/pcm_params.h>
+ #include <sound/soc.h>
+ #include <sound/dmaengine_pcm.h>
+
++#include <linux/platform_data/dma-ep93xx.h>
+ #include <mach/hardware.h>
+ #include <mach/ep93xx-regs.h>
+
+ #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");
#include <linux/delay.h>
#include <linux/io.h>
#include <linux/slab.h>
+ #include <linux/pm_runtime.h>
-#include <plat/mcbsp.h>
+#include <linux/platform_data/asoc-ti-mcbsp.h>
+
+#include <plat/cpu.h>
#include "mcbsp.h"
#include <sound/initval.h>
#include <sound/soc.h>
-#include <plat/mcbsp.h>
+#include <plat/cpu.h>
- #include <plat/dma.h>
+#include <linux/platform_data/asoc-ti-mcbsp.h>
#include "mcbsp.h"
#include "omap-mcbsp.h"
#include "omap-pcm.h"
#include <sound/core.h>
#include <sound/pcm.h>
#include <sound/pcm_params.h>
+ #include <sound/dmaengine_pcm.h>
#include <sound/soc.h>
- #include <plat/dma.h>
+#include <plat/cpu.h>
#include "omap-pcm.h"
static const struct snd_pcm_hardware omap_pcm_hardware = {