From 8e6bf16d7dba5032e366110260ac6df067f55023 Mon Sep 17 00:00:00 2001 From: Liam Girdwood Date: Mon, 14 Feb 2011 23:09:32 -0600 Subject: [PATCH 27/60] ASoC: McPDM: Merge McPDM support commit b7629e4de85cf25c8f6fc6eee90b7d040ec46e2c upstream There is currently no need to separate McPDM support into two separate files, this just complicates implementation. This patch merges files into a single more simplified DAI driver. Change-Id: Ia1a166d084cbf1e8043ccff9afefcdf3d680b1d3 Signed-off-by: Liam Girdwood Signed-off-by: Margarita Olaya Cabrera Integrated-by: Jingdong Lu --- arch/arm/plat-omap/include/plat/mcpdm.h | 30 ++ sound/soc/omap/mcpdm.c | 470 -------------------------- sound/soc/omap/mcpdm.h | 153 --------- sound/soc/omap/omap-mcpdm.c | 552 +++++++++++++++++++++++++++---- sound/soc/omap/omap-mcpdm.h | 130 ++++++++ 5 files changed, 649 insertions(+), 686 deletions(-) create mode 100644 arch/arm/plat-omap/include/plat/mcpdm.h delete mode 100644 sound/soc/omap/mcpdm.c delete mode 100644 sound/soc/omap/mcpdm.h create mode 100644 sound/soc/omap/omap-mcpdm.h diff --git a/arch/arm/plat-omap/include/plat/mcpdm.h b/arch/arm/plat-omap/include/plat/mcpdm.h new file mode 100644 index 0000000..1ed2b8f --- /dev/null +++ b/arch/arm/plat-omap/include/plat/mcpdm.h @@ -0,0 +1,30 @@ +/* + * + * 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. + * + * 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., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA + * + */ + +#ifndef __OMAP_PLAT_MCPDM_H__ +#define __OMAP_PLAT_MCPDM_H__ + +#include + +struct omap_mcpdm_platform_data { + int (*device_enable) (struct platform_device *pdev); + int (*device_shutdown) (struct platform_device *pdev); + int (*device_idle) (struct platform_device *pdev); +}; + +#endif diff --git a/sound/soc/omap/mcpdm.c b/sound/soc/omap/mcpdm.c deleted file mode 100644 index 928f037..0000000 --- a/sound/soc/omap/mcpdm.c +++ /dev/null @@ -1,470 +0,0 @@ -/* - * mcpdm.c -- McPDM interface driver - * - * Author: Jorge Eduardo Candelaria - * Copyright (C) 2009 - Texas Instruments, Inc. - * - * 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. - * - * 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., 51 Franklin St, Fifth Floor, Boston, MA - * 02110-1301 USA - * - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "mcpdm.h" - -static struct omap_mcpdm *mcpdm; - -static inline void omap_mcpdm_write(u16 reg, u32 val) -{ - __raw_writel(val, mcpdm->io_base + reg); -} - -static inline int omap_mcpdm_read(u16 reg) -{ - return __raw_readl(mcpdm->io_base + reg); -} - -static void omap_mcpdm_reg_dump(void) -{ - dev_dbg(mcpdm->dev, "***********************\n"); - dev_dbg(mcpdm->dev, "IRQSTATUS_RAW: 0x%04x\n", - omap_mcpdm_read(MCPDM_IRQSTATUS_RAW)); - dev_dbg(mcpdm->dev, "IRQSTATUS: 0x%04x\n", - omap_mcpdm_read(MCPDM_IRQSTATUS)); - dev_dbg(mcpdm->dev, "IRQENABLE_SET: 0x%04x\n", - omap_mcpdm_read(MCPDM_IRQENABLE_SET)); - dev_dbg(mcpdm->dev, "IRQENABLE_CLR: 0x%04x\n", - omap_mcpdm_read(MCPDM_IRQENABLE_CLR)); - dev_dbg(mcpdm->dev, "IRQWAKE_EN: 0x%04x\n", - omap_mcpdm_read(MCPDM_IRQWAKE_EN)); - dev_dbg(mcpdm->dev, "DMAENABLE_SET: 0x%04x\n", - omap_mcpdm_read(MCPDM_DMAENABLE_SET)); - dev_dbg(mcpdm->dev, "DMAENABLE_CLR: 0x%04x\n", - omap_mcpdm_read(MCPDM_DMAENABLE_CLR)); - dev_dbg(mcpdm->dev, "DMAWAKEEN: 0x%04x\n", - omap_mcpdm_read(MCPDM_DMAWAKEEN)); - dev_dbg(mcpdm->dev, "CTRL: 0x%04x\n", - omap_mcpdm_read(MCPDM_CTRL)); - dev_dbg(mcpdm->dev, "DN_DATA: 0x%04x\n", - omap_mcpdm_read(MCPDM_DN_DATA)); - dev_dbg(mcpdm->dev, "UP_DATA: 0x%04x\n", - omap_mcpdm_read(MCPDM_UP_DATA)); - dev_dbg(mcpdm->dev, "FIFO_CTRL_DN: 0x%04x\n", - omap_mcpdm_read(MCPDM_FIFO_CTRL_DN)); - dev_dbg(mcpdm->dev, "FIFO_CTRL_UP: 0x%04x\n", - omap_mcpdm_read(MCPDM_FIFO_CTRL_UP)); - dev_dbg(mcpdm->dev, "DN_OFFSET: 0x%04x\n", - omap_mcpdm_read(MCPDM_DN_OFFSET)); - dev_dbg(mcpdm->dev, "***********************\n"); -} - -/* - * Takes the McPDM module in and out of reset state. - * Uplink and downlink can be reset individually. - */ -static void omap_mcpdm_reset_capture(int reset) -{ - int ctrl = omap_mcpdm_read(MCPDM_CTRL); - - if (reset) - ctrl |= SW_UP_RST; - else - ctrl &= ~SW_UP_RST; - - omap_mcpdm_write(MCPDM_CTRL, ctrl); -} - -static void omap_mcpdm_reset_playback(int reset) -{ - int ctrl = omap_mcpdm_read(MCPDM_CTRL); - - if (reset) - ctrl |= SW_DN_RST; - else - ctrl &= ~SW_DN_RST; - - omap_mcpdm_write(MCPDM_CTRL, ctrl); -} - -/* - * Enables the transfer through the PDM interface to/from the Phoenix - * codec by enabling the corresponding UP or DN channels. - */ -void omap_mcpdm_start(int stream) -{ - int ctrl = omap_mcpdm_read(MCPDM_CTRL); - - if (stream) - ctrl |= mcpdm->up_channels; - else - ctrl |= mcpdm->dn_channels; - - omap_mcpdm_write(MCPDM_CTRL, ctrl); -} - -/* - * Disables the transfer through the PDM interface to/from the Phoenix - * codec by disabling the corresponding UP or DN channels. - */ -void omap_mcpdm_stop(int stream) -{ - int ctrl = omap_mcpdm_read(MCPDM_CTRL); - - if (stream) - ctrl &= ~mcpdm->up_channels; - else - ctrl &= ~mcpdm->dn_channels; - - omap_mcpdm_write(MCPDM_CTRL, ctrl); -} - -/* - * Configures McPDM uplink for audio recording. - * This function should be called before omap_mcpdm_start. - */ -int omap_mcpdm_capture_open(struct omap_mcpdm_link *uplink) -{ - int irq_mask = 0; - int ctrl; - - if (!uplink) - return -EINVAL; - - mcpdm->uplink = uplink; - - /* Enable irq request generation */ - irq_mask |= uplink->irq_mask & MCPDM_UPLINK_IRQ_MASK; - omap_mcpdm_write(MCPDM_IRQENABLE_SET, irq_mask); - - /* Configure uplink threshold */ - if (uplink->threshold > UP_THRES_MAX) - uplink->threshold = UP_THRES_MAX; - - omap_mcpdm_write(MCPDM_FIFO_CTRL_UP, uplink->threshold); - - /* Configure DMA controller */ - omap_mcpdm_write(MCPDM_DMAENABLE_SET, DMA_UP_ENABLE); - - /* Set pdm out format */ - ctrl = omap_mcpdm_read(MCPDM_CTRL); - ctrl &= ~PDMOUTFORMAT; - ctrl |= uplink->format & PDMOUTFORMAT; - - /* Uplink channels */ - mcpdm->up_channels = uplink->channels & (PDM_UP_MASK | PDM_STATUS_MASK); - - omap_mcpdm_write(MCPDM_CTRL, ctrl); - - return 0; -} - -/* - * Configures McPDM downlink for audio playback. - * This function should be called before omap_mcpdm_start. - */ -int omap_mcpdm_playback_open(struct omap_mcpdm_link *downlink) -{ - int irq_mask = 0; - int ctrl; - - if (!downlink) - return -EINVAL; - - mcpdm->downlink = downlink; - - /* Enable irq request generation */ - irq_mask |= downlink->irq_mask & MCPDM_DOWNLINK_IRQ_MASK; - omap_mcpdm_write(MCPDM_IRQENABLE_SET, irq_mask); - - /* Configure uplink threshold */ - if (downlink->threshold > DN_THRES_MAX) - downlink->threshold = DN_THRES_MAX; - - omap_mcpdm_write(MCPDM_FIFO_CTRL_DN, downlink->threshold); - - /* Enable DMA request generation */ - omap_mcpdm_write(MCPDM_DMAENABLE_SET, DMA_DN_ENABLE); - - /* Set pdm out format */ - ctrl = omap_mcpdm_read(MCPDM_CTRL); - ctrl &= ~PDMOUTFORMAT; - ctrl |= downlink->format & PDMOUTFORMAT; - - /* Downlink channels */ - mcpdm->dn_channels = downlink->channels & (PDM_DN_MASK | PDM_CMD_MASK); - - omap_mcpdm_write(MCPDM_CTRL, ctrl); - - return 0; -} - -/* - * Cleans McPDM uplink configuration. - * This function should be called when the stream is closed. - */ -int omap_mcpdm_capture_close(struct omap_mcpdm_link *uplink) -{ - int irq_mask = 0; - - if (!uplink) - return -EINVAL; - - /* Disable irq request generation */ - irq_mask |= uplink->irq_mask & MCPDM_UPLINK_IRQ_MASK; - omap_mcpdm_write(MCPDM_IRQENABLE_CLR, irq_mask); - - /* Disable DMA request generation */ - omap_mcpdm_write(MCPDM_DMAENABLE_CLR, DMA_UP_ENABLE); - - /* Clear Downlink channels */ - mcpdm->up_channels = 0; - - mcpdm->uplink = NULL; - - return 0; -} - -/* - * Cleans McPDM downlink configuration. - * This function should be called when the stream is closed. - */ -int omap_mcpdm_playback_close(struct omap_mcpdm_link *downlink) -{ - int irq_mask = 0; - - if (!downlink) - return -EINVAL; - - /* Disable irq request generation */ - irq_mask |= downlink->irq_mask & MCPDM_DOWNLINK_IRQ_MASK; - omap_mcpdm_write(MCPDM_IRQENABLE_CLR, irq_mask); - - /* Disable DMA request generation */ - omap_mcpdm_write(MCPDM_DMAENABLE_CLR, DMA_DN_ENABLE); - - /* clear Downlink channels */ - mcpdm->dn_channels = 0; - - mcpdm->downlink = NULL; - - return 0; -} - -static irqreturn_t omap_mcpdm_irq_handler(int irq, void *dev_id) -{ - struct omap_mcpdm *mcpdm_irq = dev_id; - int irq_status; - - irq_status = omap_mcpdm_read(MCPDM_IRQSTATUS); - - /* Acknowledge irq event */ - omap_mcpdm_write(MCPDM_IRQSTATUS, irq_status); - - if (irq & MCPDM_DN_IRQ_FULL) { - dev_err(mcpdm_irq->dev, "DN FIFO error %x\n", irq_status); - omap_mcpdm_reset_playback(1); - omap_mcpdm_playback_open(mcpdm_irq->downlink); - omap_mcpdm_reset_playback(0); - } - - if (irq & MCPDM_DN_IRQ_EMPTY) { - dev_err(mcpdm_irq->dev, "DN FIFO error %x\n", irq_status); - omap_mcpdm_reset_playback(1); - omap_mcpdm_playback_open(mcpdm_irq->downlink); - omap_mcpdm_reset_playback(0); - } - - if (irq & MCPDM_DN_IRQ) { - dev_dbg(mcpdm_irq->dev, "DN write request\n"); - } - - if (irq & MCPDM_UP_IRQ_FULL) { - dev_err(mcpdm_irq->dev, "UP FIFO error %x\n", irq_status); - omap_mcpdm_reset_capture(1); - omap_mcpdm_capture_open(mcpdm_irq->uplink); - omap_mcpdm_reset_capture(0); - } - - if (irq & MCPDM_UP_IRQ_EMPTY) { - dev_err(mcpdm_irq->dev, "UP FIFO error %x\n", irq_status); - omap_mcpdm_reset_capture(1); - omap_mcpdm_capture_open(mcpdm_irq->uplink); - omap_mcpdm_reset_capture(0); - } - - if (irq & MCPDM_UP_IRQ) { - dev_dbg(mcpdm_irq->dev, "UP write request\n"); - } - - return IRQ_HANDLED; -} - -int omap_mcpdm_request(void) -{ - int ret; - - clk_enable(mcpdm->clk); - - spin_lock(&mcpdm->lock); - - if (!mcpdm->free) { - dev_err(mcpdm->dev, "McPDM interface is in use\n"); - spin_unlock(&mcpdm->lock); - ret = -EBUSY; - goto err; - } - mcpdm->free = 0; - - spin_unlock(&mcpdm->lock); - - /* Disable lines while request is ongoing */ - omap_mcpdm_write(MCPDM_CTRL, 0x00); - - ret = request_irq(mcpdm->irq, omap_mcpdm_irq_handler, - 0, "McPDM", (void *)mcpdm); - if (ret) { - dev_err(mcpdm->dev, "Request for McPDM IRQ failed\n"); - goto err; - } - - return 0; - -err: - clk_disable(mcpdm->clk); - return ret; -} - -void omap_mcpdm_free(void) -{ - spin_lock(&mcpdm->lock); - if (mcpdm->free) { - dev_err(mcpdm->dev, "McPDM interface is already free\n"); - spin_unlock(&mcpdm->lock); - return; - } - mcpdm->free = 1; - spin_unlock(&mcpdm->lock); - - clk_disable(mcpdm->clk); - - free_irq(mcpdm->irq, (void *)mcpdm); -} - -/* Enable/disable DC offset cancelation for the analog - * headset path (PDM channels 1 and 2). - */ -int omap_mcpdm_set_offset(int offset1, int offset2) -{ - int offset; - - if ((offset1 > DN_OFST_MAX) || (offset2 > DN_OFST_MAX)) - return -EINVAL; - - offset = (offset1 << DN_OFST_RX1) | (offset2 << DN_OFST_RX2); - - /* offset cancellation for channel 1 */ - if (offset1) - offset |= DN_OFST_RX1_EN; - else - offset &= ~DN_OFST_RX1_EN; - - /* offset cancellation for channel 2 */ - if (offset2) - offset |= DN_OFST_RX2_EN; - else - offset &= ~DN_OFST_RX2_EN; - - omap_mcpdm_write(MCPDM_DN_OFFSET, offset); - - return 0; -} - -int __devinit omap_mcpdm_probe(struct platform_device *pdev) -{ - struct resource *res; - int ret = 0; - - mcpdm = kzalloc(sizeof(struct omap_mcpdm), GFP_KERNEL); - if (!mcpdm) { - ret = -ENOMEM; - goto exit; - } - - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - if (res == NULL) { - dev_err(&pdev->dev, "no resource\n"); - goto err_resource; - } - - spin_lock_init(&mcpdm->lock); - mcpdm->free = 1; - mcpdm->io_base = ioremap(res->start, resource_size(res)); - if (!mcpdm->io_base) { - ret = -ENOMEM; - goto err_resource; - } - - mcpdm->irq = platform_get_irq(pdev, 0); - - mcpdm->clk = clk_get(&pdev->dev, "pdm_ck"); - if (IS_ERR(mcpdm->clk)) { - ret = PTR_ERR(mcpdm->clk); - dev_err(&pdev->dev, "unable to get pdm_ck: %d\n", ret); - goto err_clk; - } - - mcpdm->dev = &pdev->dev; - platform_set_drvdata(pdev, mcpdm); - - return 0; - -err_clk: - iounmap(mcpdm->io_base); -err_resource: - kfree(mcpdm); -exit: - return ret; -} - -int __devexit omap_mcpdm_remove(struct platform_device *pdev) -{ - struct omap_mcpdm *mcpdm_ptr = platform_get_drvdata(pdev); - - platform_set_drvdata(pdev, NULL); - - clk_put(mcpdm_ptr->clk); - - iounmap(mcpdm_ptr->io_base); - - mcpdm_ptr->clk = NULL; - mcpdm_ptr->free = 0; - mcpdm_ptr->dev = NULL; - - kfree(mcpdm_ptr); - - return 0; -} - diff --git a/sound/soc/omap/mcpdm.h b/sound/soc/omap/mcpdm.h deleted file mode 100644 index df3e16f..0000000 --- a/sound/soc/omap/mcpdm.h +++ /dev/null @@ -1,153 +0,0 @@ -/* - * mcpdm.h -- Defines for McPDM driver - * - * Author: Jorge Eduardo Candelaria - * - * 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. - * - * 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., 51 Franklin St, Fifth Floor, Boston, MA - * 02110-1301 USA - * - */ - -/* McPDM registers */ - -#define MCPDM_REVISION 0x00 -#define MCPDM_SYSCONFIG 0x10 -#define MCPDM_IRQSTATUS_RAW 0x24 -#define MCPDM_IRQSTATUS 0x28 -#define MCPDM_IRQENABLE_SET 0x2C -#define MCPDM_IRQENABLE_CLR 0x30 -#define MCPDM_IRQWAKE_EN 0x34 -#define MCPDM_DMAENABLE_SET 0x38 -#define MCPDM_DMAENABLE_CLR 0x3C -#define MCPDM_DMAWAKEEN 0x40 -#define MCPDM_CTRL 0x44 -#define MCPDM_DN_DATA 0x48 -#define MCPDM_UP_DATA 0x4C -#define MCPDM_FIFO_CTRL_DN 0x50 -#define MCPDM_FIFO_CTRL_UP 0x54 -#define MCPDM_DN_OFFSET 0x58 - -/* - * MCPDM_IRQ bit fields - * IRQSTATUS_RAW, IRQSTATUS, IRQENABLE_SET, IRQENABLE_CLR - */ - -#define MCPDM_DN_IRQ (1 << 0) -#define MCPDM_DN_IRQ_EMPTY (1 << 1) -#define MCPDM_DN_IRQ_ALMST_EMPTY (1 << 2) -#define MCPDM_DN_IRQ_FULL (1 << 3) - -#define MCPDM_UP_IRQ (1 << 8) -#define MCPDM_UP_IRQ_EMPTY (1 << 9) -#define MCPDM_UP_IRQ_ALMST_FULL (1 << 10) -#define MCPDM_UP_IRQ_FULL (1 << 11) - -#define MCPDM_DOWNLINK_IRQ_MASK 0x00F -#define MCPDM_UPLINK_IRQ_MASK 0xF00 - -/* - * MCPDM_DMAENABLE bit fields - */ - -#define DMA_DN_ENABLE 0x1 -#define DMA_UP_ENABLE 0x2 - -/* - * MCPDM_CTRL bit fields - */ - -#define PDM_UP1_EN 0x0001 -#define PDM_UP2_EN 0x0002 -#define PDM_UP3_EN 0x0004 -#define PDM_DN1_EN 0x0008 -#define PDM_DN2_EN 0x0010 -#define PDM_DN3_EN 0x0020 -#define PDM_DN4_EN 0x0040 -#define PDM_DN5_EN 0x0080 -#define PDMOUTFORMAT 0x0100 -#define CMD_INT 0x0200 -#define STATUS_INT 0x0400 -#define SW_UP_RST 0x0800 -#define SW_DN_RST 0x1000 -#define PDM_UP_MASK 0x007 -#define PDM_DN_MASK 0x0F8 -#define PDM_CMD_MASK 0x200 -#define PDM_STATUS_MASK 0x400 - - -#define PDMOUTFORMAT_LJUST (0 << 8) -#define PDMOUTFORMAT_RJUST (1 << 8) - -/* - * MCPDM_FIFO_CTRL bit fields - */ - -#define UP_THRES_MAX 0xF -#define DN_THRES_MAX 0xF - -/* - * MCPDM_DN_OFFSET bit fields - */ - -#define DN_OFST_RX1_EN 0x0001 -#define DN_OFST_RX2_EN 0x0100 - -#define DN_OFST_RX1 1 -#define DN_OFST_RX2 9 -#define DN_OFST_MAX 0x1F - -#define MCPDM_UPLINK 1 -#define MCPDM_DOWNLINK 2 - -struct omap_mcpdm_link { - int irq_mask; - int threshold; - int format; - int channels; -}; - -struct omap_mcpdm_platform_data { - unsigned long phys_base; - u16 irq; -}; - -struct omap_mcpdm { - struct device *dev; - unsigned long phys_base; - void __iomem *io_base; - u8 free; - int irq; - - spinlock_t lock; - struct omap_mcpdm_platform_data *pdata; - struct clk *clk; - struct omap_mcpdm_link *downlink; - struct omap_mcpdm_link *uplink; - struct completion irq_completion; - - int dn_channels; - int up_channels; -}; - -extern void omap_mcpdm_start(int stream); -extern void omap_mcpdm_stop(int stream); -extern int omap_mcpdm_capture_open(struct omap_mcpdm_link *uplink); -extern int omap_mcpdm_playback_open(struct omap_mcpdm_link *downlink); -extern int omap_mcpdm_capture_close(struct omap_mcpdm_link *uplink); -extern int omap_mcpdm_playback_close(struct omap_mcpdm_link *downlink); -extern int omap_mcpdm_request(void); -extern void omap_mcpdm_free(void); -extern int omap_mcpdm_set_offset(int offset1, int offset2); -int __devinit omap_mcpdm_probe(struct platform_device *pdev); -int __devexit omap_mcpdm_remove(struct platform_device *pdev); diff --git a/sound/soc/omap/omap-mcpdm.c b/sound/soc/omap/omap-mcpdm.c index bed09c2..7259a55 100644 --- a/sound/soc/omap/omap-mcpdm.c +++ b/sound/soc/omap/omap-mcpdm.c @@ -25,7 +25,15 @@ #include #include -#include +#include +#include +#include +#include +#include +#include +#include +#include + #include #include #include @@ -33,8 +41,9 @@ #include #include +#include #include -#include "mcpdm.h" +#include "omap-mcpdm.h" #include "omap-pcm.h" struct omap_mcpdm_data { @@ -42,6 +51,23 @@ struct omap_mcpdm_data { int active; }; +struct omap_mcpdm { + struct device *dev; + unsigned long phys_base; + void __iomem *io_base; + u8 free; + int irq; + + spinlock_t lock; + struct omap_mcpdm_platform_data *pdata; + struct omap_mcpdm_link *downlink; + struct omap_mcpdm_link *uplink; + struct completion irq_completion; + + int dn_channels; + int up_channels; +}; + static struct omap_mcpdm_link omap_mcpdm_links[] = { /* downlink */ { @@ -57,11 +83,6 @@ static struct omap_mcpdm_link omap_mcpdm_links[] = { }, }; -static struct omap_mcpdm_data mcpdm_data = { - .links = omap_mcpdm_links, - .active = 0, -}; - /* * Stream DMA parameters */ @@ -84,58 +105,402 @@ static struct omap_pcm_dma_data omap_mcpdm_dai_dma_params[] = { }, }; -static int omap_mcpdm_dai_startup(struct snd_pcm_substream *substream, - struct snd_soc_dai *dai) +static inline void omap_mcpdm_write(struct omap_mcpdm *mcpdm, + u16 reg, u32 val) { - int err = 0; + __raw_writel(val, mcpdm->io_base + reg); +} - if (!dai->active) - err = omap_mcpdm_request(); +static inline int omap_mcpdm_read(struct omap_mcpdm *mcpdm, u16 reg) +{ + return __raw_readl(mcpdm->io_base + reg); +} - return err; +#ifdef DEBUG +static void omap_mcpdm_reg_dump(struct omap_mcpdm *mcpdm) +{ + dev_dbg(mcpdm->dev, "***********************\n"); + dev_dbg(mcpdm->dev, "IRQSTATUS_RAW: 0x%04x\n", + omap_mcpdm_read(mcpdm, MCPDM_IRQSTATUS_RAW)); + dev_dbg(mcpdm->dev, "IRQSTATUS: 0x%04x\n", + omap_mcpdm_read(mcpdm, MCPDM_IRQSTATUS)); + dev_dbg(mcpdm->dev, "IRQENABLE_SET: 0x%04x\n", + omap_mcpdm_read(mcpdm, MCPDM_IRQENABLE_SET)); + dev_dbg(mcpdm->dev, "IRQENABLE_CLR: 0x%04x\n", + omap_mcpdm_read(mcpdm, MCPDM_IRQENABLE_CLR)); + dev_dbg(mcpdm->dev, "IRQWAKE_EN: 0x%04x\n", + omap_mcpdm_read(mcpdm, MCPDM_IRQWAKE_EN)); + dev_dbg(mcpdm->dev, "DMAENABLE_SET: 0x%04x\n", + omap_mcpdm_read(mcpdm, MCPDM_DMAENABLE_SET)); + dev_dbg(mcpdm->dev, "DMAENABLE_CLR: 0x%04x\n", + omap_mcpdm_read(mcpdm, MCPDM_DMAENABLE_CLR)); + dev_dbg(mcpdm->dev, "DMAWAKEEN: 0x%04x\n", + omap_mcpdm_read(mcpdm, MCPDM_DMAWAKEEN)); + dev_dbg(mcpdm->dev, "CTRL: 0x%04x\n", + omap_mcpdm_read(mcpdm, MCPDM_CTRL)); + dev_dbg(mcpdm->dev, "DN_DATA: 0x%04x\n", + omap_mcpdm_read(mcpdm, MCPDM_DN_DATA)); + dev_dbg(mcpdm->dev, "UP_DATA: 0x%04x\n", + omap_mcpdm_read(mcpdm, MCPDM_UP_DATA)); + dev_dbg(mcpdm->dev, "FIFO_CTRL_DN: 0x%04x\n", + omap_mcpdm_read(mcpdm, MCPDM_FIFO_CTRL_DN)); + dev_dbg(mcpdm->dev, "FIFO_CTRL_UP: 0x%04x\n", + omap_mcpdm_read(mcpdm, MCPDM_FIFO_CTRL_UP)); + dev_dbg(mcpdm->dev, "DN_OFFSET: 0x%04x\n", + omap_mcpdm_read(mcpdm, MCPDM_DN_OFFSET)); + dev_dbg(mcpdm->dev, "***********************\n"); } +#else +static void omap_mcpdm_reg_dump(struct omap_mcpdm *mcpdm) {} +#endif -static void omap_mcpdm_dai_shutdown(struct snd_pcm_substream *substream, - struct snd_soc_dai *dai) +/* + * Takes the McPDM module in and out of reset state. + * Uplink and downlink can be reset individually. + */ +static void omap_mcpdm_reset_capture(struct omap_mcpdm * mcpdm, + int reset) { - if (!dai->active) - omap_mcpdm_free(); + int ctrl = omap_mcpdm_read(mcpdm, MCPDM_CTRL); + + if (reset) + ctrl |= SW_UP_RST; + else + ctrl &= ~SW_UP_RST; + + omap_mcpdm_write(mcpdm, MCPDM_CTRL, ctrl); } -static int omap_mcpdm_dai_trigger(struct snd_pcm_substream *substream, int cmd, - struct snd_soc_dai *dai) +static void omap_mcpdm_reset_playback(struct omap_mcpdm * mcpdm, + int reset) { - struct omap_mcpdm_data *mcpdm_priv = snd_soc_dai_get_drvdata(dai); - int stream = substream->stream; - int err = 0; + int ctrl = omap_mcpdm_read(mcpdm, MCPDM_CTRL); - switch (cmd) { - case SNDRV_PCM_TRIGGER_START: - case SNDRV_PCM_TRIGGER_RESUME: - case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: - if (!mcpdm_priv->active++) - omap_mcpdm_start(stream); - break; + if (reset) + ctrl |= SW_DN_RST; + else + ctrl &= ~SW_DN_RST; - case SNDRV_PCM_TRIGGER_STOP: - case SNDRV_PCM_TRIGGER_SUSPEND: - case SNDRV_PCM_TRIGGER_PAUSE_PUSH: - if (!--mcpdm_priv->active) - omap_mcpdm_stop(stream); - break; - default: - err = -EINVAL; + omap_mcpdm_write(mcpdm, MCPDM_CTRL, ctrl); +} + +/* + * Enables the transfer through the PDM interface to/from the Phoenix + * codec by enabling the corresponding UP or DN channels. + */ +static void omap_mcpdm_start(struct omap_mcpdm *mcpdm, int stream) +{ + int ctrl = omap_mcpdm_read(mcpdm, MCPDM_CTRL); + + if (stream) + ctrl |= mcpdm->up_channels; + else + ctrl |= mcpdm->dn_channels; + + omap_mcpdm_write(mcpdm, MCPDM_CTRL, ctrl); +} + +/* + * Disables the transfer through the PDM interface to/from the Phoenix + * codec by disabling the corresponding UP or DN channels. + */ +static void omap_mcpdm_stop(struct omap_mcpdm *mcpdm, int stream) +{ + int ctrl = omap_mcpdm_read(mcpdm, MCPDM_CTRL); + + if (stream) + ctrl &= ~mcpdm->up_channels; + else + ctrl &= ~mcpdm->dn_channels; + + omap_mcpdm_write(mcpdm, MCPDM_CTRL, ctrl); +} + +/* + * Configures McPDM uplink for audio recording. + * This function should be called before omap_mcpdm_start. + */ +static int omap_mcpdm_capture_open(struct omap_mcpdm *mcpdm, + struct omap_mcpdm_link *uplink) +{ + int irq_mask = 0; + int ctrl; + + /* Enable irq request generation */ + irq_mask |= uplink->irq_mask & MCPDM_UPLINK_IRQ_MASK; + omap_mcpdm_write(mcpdm, MCPDM_IRQENABLE_SET, irq_mask); + + /* Configure uplink threshold */ + if (uplink->threshold > UP_THRES_MAX) + uplink->threshold = UP_THRES_MAX; + + omap_mcpdm_write(mcpdm, MCPDM_FIFO_CTRL_UP, uplink->threshold); + + /* Configure DMA controller */ + omap_mcpdm_write(mcpdm, MCPDM_DMAENABLE_SET, DMA_UP_ENABLE); + + /* Set pdm out format */ + ctrl = omap_mcpdm_read(mcpdm, MCPDM_CTRL); + ctrl &= ~PDMOUTFORMAT; + ctrl |= uplink->format & PDMOUTFORMAT; + + /* Uplink channels */ + mcpdm->up_channels = uplink->channels & (PDM_UP_MASK | PDM_STATUS_MASK); + + omap_mcpdm_write(mcpdm, MCPDM_CTRL, ctrl); + + return 0; +} + +/* + * Configures McPDM downlink for audio playback. + * This function should be called before omap_mcpdm_start. + */ +static int omap_mcpdm_playback_open(struct omap_mcpdm *mcpdm, + struct omap_mcpdm_link *downlink) +{ + int irq_mask = 0; + int ctrl; + + /* Enable irq request generation */ + irq_mask |= downlink->irq_mask & MCPDM_DOWNLINK_IRQ_MASK; + omap_mcpdm_write(mcpdm, MCPDM_IRQENABLE_SET, irq_mask); + + /* Configure uplink threshold */ + if (downlink->threshold > DN_THRES_MAX) + downlink->threshold = DN_THRES_MAX; + + omap_mcpdm_write(mcpdm, MCPDM_FIFO_CTRL_DN, downlink->threshold); + + /* Enable DMA request generation */ + omap_mcpdm_write(mcpdm, MCPDM_DMAENABLE_SET, DMA_DN_ENABLE); + + /* Set pdm out format */ + ctrl = omap_mcpdm_read(mcpdm, MCPDM_CTRL); + ctrl &= ~PDMOUTFORMAT; + ctrl |= downlink->format & PDMOUTFORMAT; + + /* Downlink channels */ + mcpdm->dn_channels = (PDM_DN_MASK | PDM_CMD_MASK); + + omap_mcpdm_write(mcpdm, MCPDM_CTRL, ctrl); + + return 0; +} + +/* + * Cleans McPDM uplink configuration. + * This function should be called when the stream is closed. + */ +static int omap_mcpdm_capture_close(struct omap_mcpdm *mcpdm, + struct omap_mcpdm_link *uplink) +{ + int irq_mask = 0; + + /* Disable irq request generation */ + irq_mask |= uplink->irq_mask & MCPDM_UPLINK_IRQ_MASK; + omap_mcpdm_write(mcpdm, MCPDM_IRQENABLE_CLR, irq_mask); + + /* Disable DMA request generation */ + omap_mcpdm_write(mcpdm, MCPDM_DMAENABLE_CLR, DMA_UP_ENABLE); + + /* Clear Downlink channels */ + mcpdm->up_channels = 0; + + return 0; +} + +/* + * Cleans McPDM downlink configuration. + * This function should be called when the stream is closed. + */ +static int omap_mcpdm_playback_close(struct omap_mcpdm *mcpdm, + struct omap_mcpdm_link *downlink) +{ + int irq_mask = 0; + + /* Disable irq request generation */ + irq_mask |= downlink->irq_mask & MCPDM_DOWNLINK_IRQ_MASK; + omap_mcpdm_write(mcpdm, MCPDM_IRQENABLE_CLR, irq_mask); + + /* Disable DMA request generation */ + omap_mcpdm_write(mcpdm, MCPDM_DMAENABLE_CLR, DMA_DN_ENABLE); + + /* clear Downlink channels */ + mcpdm->dn_channels = 0; + + return 0; +} + +static irqreturn_t omap_mcpdm_irq_handler(int irq, void *dev_id) +{ + struct omap_mcpdm *mcpdm = dev_id; + int irq_status; + + irq_status = omap_mcpdm_read(mcpdm, MCPDM_IRQSTATUS); + + /* Acknowledge irq event */ + omap_mcpdm_write(mcpdm, MCPDM_IRQSTATUS, irq_status); + + if (irq & MCPDM_DN_IRQ_FULL) { + dev_err(mcpdm->dev, "DN FIFO error %x\n", irq_status); + omap_mcpdm_reset_playback(mcpdm, 1); + omap_mcpdm_playback_open(mcpdm, mcpdm->downlink); + omap_mcpdm_reset_playback(mcpdm, 0); + } + + if (irq & MCPDM_DN_IRQ_EMPTY) { + dev_err(mcpdm->dev, "DN FIFO error %x\n", irq_status); + omap_mcpdm_reset_playback(mcpdm, 1); + omap_mcpdm_playback_open(mcpdm, mcpdm->downlink); + omap_mcpdm_reset_playback(mcpdm, 0); + } + + if (irq & MCPDM_DN_IRQ) { + dev_dbg(mcpdm->dev, "DN write request\n"); + } + + if (irq & MCPDM_UP_IRQ_FULL) { + dev_err(mcpdm->dev, "UP FIFO error %x\n", irq_status); + omap_mcpdm_reset_capture(mcpdm, 1); + omap_mcpdm_capture_open(mcpdm, mcpdm->uplink); + omap_mcpdm_reset_capture(mcpdm, 0); + } + + if (irq & MCPDM_UP_IRQ_EMPTY) { + dev_err(mcpdm->dev, "UP FIFO error %x\n", irq_status); + omap_mcpdm_reset_capture(mcpdm, 1); + omap_mcpdm_capture_open(mcpdm, mcpdm->uplink); + omap_mcpdm_reset_capture(mcpdm, 0); + } + + if (irq & MCPDM_UP_IRQ) { + dev_dbg(mcpdm->dev, "UP write request\n"); + } + + return IRQ_HANDLED; +} + +static int omap_mcpdm_request(struct omap_mcpdm *mcpdm) +{ + struct platform_device *pdev; + struct omap_mcpdm_platform_data *pdata; + int ret; + + pdev = container_of(mcpdm->dev, struct platform_device, dev); + pdata = pdev->dev.platform_data; + + if (pdata->device_enable) + pdata->device_enable(pdev); + + spin_lock(&mcpdm->lock); + + if (!mcpdm->free) { + dev_err(mcpdm->dev, "McPDM interface is in use\n"); + spin_unlock(&mcpdm->lock); + ret = -EBUSY; + goto err; + } + mcpdm->free = 0; + + spin_unlock(&mcpdm->lock); + + /* Disable lines while request is ongoing */ + omap_mcpdm_write(mcpdm, MCPDM_CTRL, 0x00); + + ret = request_irq(mcpdm->irq, omap_mcpdm_irq_handler, + 0, "McPDM", (void *)mcpdm); + if (ret) { + dev_err(mcpdm->dev, "Request for McPDM IRQ failed\n"); + goto err; + } + return 0; + +err: + if (pdata->device_idle) + pdata->device_idle(pdev); + return ret; +} + +static void omap_mcpdm_free(struct omap_mcpdm *mcpdm) +{ + struct platform_device *pdev; + struct omap_mcpdm_platform_data *pdata; + + pdev = to_platform_device(mcpdm->dev); + pdata = pdev->dev.platform_data; + + spin_lock(&mcpdm->lock); + if (mcpdm->free) { + dev_err(mcpdm->dev, "McPDM interface is already free\n"); + spin_unlock(&mcpdm->lock); + return; } + mcpdm->free = 1; + spin_unlock(&mcpdm->lock); + + if (pdata->device_idle) + pdata->device_idle(pdev); + + free_irq(mcpdm->irq, (void *)mcpdm); +} + +/* Enable/disable DC offset cancelation for the analog + * headset path (PDM channels 1 and 2). + */ +static int omap_mcpdm_set_offset(struct omap_mcpdm *mcpdm, + int offset1, int offset2) +{ + int offset; + + if ((offset1 > DN_OFST_MAX) || (offset2 > DN_OFST_MAX)) + return -EINVAL; + + offset = (offset1 << DN_OFST_RX1) | (offset2 << DN_OFST_RX2); + + /* offset cancellation for channel 1 */ + if (offset1) + offset |= DN_OFST_RX1_EN; + else + offset &= ~DN_OFST_RX1_EN; + + /* offset cancellation for channel 2 */ + if (offset2) + offset |= DN_OFST_RX2_EN; + else + offset &= ~DN_OFST_RX2_EN; + + omap_mcpdm_write(mcpdm, MCPDM_DN_OFFSET, offset); + + return 0; +} + +static int omap_mcpdm_dai_startup(struct snd_pcm_substream *substream, + struct snd_soc_dai *dai) +{ + struct omap_mcpdm *mcpdm = snd_soc_dai_get_drvdata(dai); + int err = 0; + + if (!dai->active) + err = omap_mcpdm_request(mcpdm); return err; } +static void omap_mcpdm_dai_shutdown(struct snd_pcm_substream *substream, + struct snd_soc_dai *dai) +{ + struct omap_mcpdm *mcpdm = snd_soc_dai_get_drvdata(dai); + + if (!dai->active) + omap_mcpdm_free(mcpdm); +} + static int omap_mcpdm_dai_hw_params(struct snd_pcm_substream *substream, struct snd_pcm_hw_params *params, struct snd_soc_dai *dai) { - struct omap_mcpdm_data *mcpdm_priv = snd_soc_dai_get_drvdata(dai); - struct omap_mcpdm_link *mcpdm_links = mcpdm_priv->links; + struct omap_mcpdm *mcpdm = snd_soc_dai_get_drvdata(dai); int stream = substream->stream; int channels, err, link_mask = 0; @@ -165,11 +530,11 @@ static int omap_mcpdm_dai_hw_params(struct snd_pcm_substream *substream, } if (stream == SNDRV_PCM_STREAM_PLAYBACK) { - mcpdm_links[stream].channels = link_mask << 3; - err = omap_mcpdm_playback_open(&mcpdm_links[stream]); + mcpdm->downlink->channels = link_mask << 3; + err = omap_mcpdm_playback_open(mcpdm, &omap_mcpdm_links[0]); } else { - mcpdm_links[stream].channels = link_mask << 0; - err = omap_mcpdm_capture_open(&mcpdm_links[stream]); + mcpdm->uplink->channels = link_mask << 0; + err = omap_mcpdm_capture_open(mcpdm, &omap_mcpdm_links[1]); } return err; @@ -178,38 +543,55 @@ static int omap_mcpdm_dai_hw_params(struct snd_pcm_substream *substream, static int omap_mcpdm_dai_hw_free(struct snd_pcm_substream *substream, struct snd_soc_dai *dai) { - struct omap_mcpdm_data *mcpdm_priv = snd_soc_dai_get_drvdata(dai); - struct omap_mcpdm_link *mcpdm_links = mcpdm_priv->links; - int stream = substream->stream; + struct omap_mcpdm *mcpdm = snd_soc_dai_get_drvdata(dai); int err; if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) - err = omap_mcpdm_playback_close(&mcpdm_links[stream]); + err = omap_mcpdm_playback_close(mcpdm, mcpdm->downlink); else - err = omap_mcpdm_capture_close(&mcpdm_links[stream]); + err = omap_mcpdm_capture_close(mcpdm, mcpdm->uplink); return err; } +static int omap_mcpdm_dai_trigger(struct snd_pcm_substream *substream, + int cmd, struct snd_soc_dai *dai) +{ + struct omap_mcpdm *mcpdm = snd_soc_dai_get_drvdata(dai); + int stream = substream->stream; + + dev_dbg(dai->dev, "cmd %d\n", cmd); + omap_mcpdm_reg_dump(mcpdm); + + switch (cmd) { + case SNDRV_PCM_TRIGGER_START: + omap_mcpdm_start(mcpdm, stream); + break; + case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: + break; + case SNDRV_PCM_TRIGGER_PAUSE_PUSH: + break; + case SNDRV_PCM_TRIGGER_STOP: + omap_mcpdm_stop(mcpdm, stream); + break; + default: + break; + } + return 0; +} + static struct snd_soc_dai_ops omap_mcpdm_dai_ops = { .startup = omap_mcpdm_dai_startup, .shutdown = omap_mcpdm_dai_shutdown, - .trigger = omap_mcpdm_dai_trigger, .hw_params = omap_mcpdm_dai_hw_params, .hw_free = omap_mcpdm_dai_hw_free, + .trigger = omap_mcpdm_dai_trigger, }; #define OMAP_MCPDM_RATES (SNDRV_PCM_RATE_88200 | SNDRV_PCM_RATE_96000) #define OMAP_MCPDM_FORMATS (SNDRV_PCM_FMTBIT_S32_LE) -static int omap_mcpdm_dai_probe(struct snd_soc_dai *dai) -{ - snd_soc_dai_set_drvdata(dai, &mcpdm_data); - return 0; -} - static struct snd_soc_dai_driver omap_mcpdm_dai = { - .probe = omap_mcpdm_dai_probe, .playback = { .channels_min = 1, .channels_max = 4, @@ -227,21 +609,65 @@ static struct snd_soc_dai_driver omap_mcpdm_dai = { static __devinit int asoc_mcpdm_probe(struct platform_device *pdev) { - int ret; + struct omap_mcpdm *mcpdm; + struct resource *res; + int ret = 0; + + mcpdm = kzalloc(sizeof(struct omap_mcpdm), GFP_KERNEL); + if (!mcpdm) { + ret = -ENOMEM; + goto exit; + } + platform_set_drvdata(pdev, mcpdm); + mcpdm->downlink = &omap_mcpdm_links[0]; + mcpdm->uplink = &omap_mcpdm_links[1]; + + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + if (res == NULL) { + dev_err(&pdev->dev, "no resource\n"); + goto err_resource; + } + + spin_lock_init(&mcpdm->lock); + mcpdm->free = 1; + + mcpdm->io_base = ioremap(res->start, resource_size(res)); + if (!mcpdm->io_base) { + ret = -ENOMEM; + goto err_resource; + } + + mcpdm->irq = platform_get_irq(pdev, 0); + if (mcpdm->irq < 0) { + ret = mcpdm->irq; + goto err_irq; + } + + mcpdm->dev = &pdev->dev; - ret = omap_mcpdm_probe(pdev); - if (ret < 0) - return ret; ret = snd_soc_register_dai(&pdev->dev, &omap_mcpdm_dai); - if (ret < 0) - omap_mcpdm_remove(pdev); + if (ret == 0) + return 0; + +err_irq: + iounmap(mcpdm->io_base); +err_resource: + kfree(mcpdm); +exit: return ret; } static int __devexit asoc_mcpdm_remove(struct platform_device *pdev) { + struct omap_mcpdm *mcpdm = platform_get_drvdata(pdev); + snd_soc_unregister_dai(&pdev->dev); - omap_mcpdm_remove(pdev); + + if (pdata->device_shutdown) + pdata->device_shutdown(pdev); + iounmap(mcpdm->io_base); + + kfree(mcpdm); return 0; } diff --git a/sound/soc/omap/omap-mcpdm.h b/sound/soc/omap/omap-mcpdm.h new file mode 100644 index 0000000..d926cfe --- /dev/null +++ b/sound/soc/omap/omap-mcpdm.h @@ -0,0 +1,130 @@ +/* + * omap-mcpdm.h + * + * Copyright (C) 2009 Texas Instruments + * + * Contact: Misael Lopez Cruz + * + * 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. + * + * 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., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA + * + */ + +#ifndef __OMAP_MCPDM_H__ +#define __OMAP_MCPDM_H__ + +#include + +#define MCPDM_REVISION 0x00 +#define MCPDM_SYSCONFIG 0x10 +#define MCPDM_IRQSTATUS_RAW 0x24 +#define MCPDM_IRQSTATUS 0x28 +#define MCPDM_IRQENABLE_SET 0x2C +#define MCPDM_IRQENABLE_CLR 0x30 +#define MCPDM_IRQWAKE_EN 0x34 +#define MCPDM_DMAENABLE_SET 0x38 +#define MCPDM_DMAENABLE_CLR 0x3C +#define MCPDM_DMAWAKEEN 0x40 +#define MCPDM_CTRL 0x44 +#define MCPDM_DN_DATA 0x48 +#define MCPDM_UP_DATA 0x4C +#define MCPDM_FIFO_CTRL_DN 0x50 +#define MCPDM_FIFO_CTRL_UP 0x54 +#define MCPDM_DN_OFFSET 0x58 + +/* + * MCPDM_IRQ bit fields + * IRQSTATUS_RAW, IRQSTATUS, IRQENABLE_SET, IRQENABLE_CLR + */ + +#define MCPDM_DN_IRQ (1 << 0) +#define MCPDM_DN_IRQ_EMPTY (1 << 1) +#define MCPDM_DN_IRQ_ALMST_EMPTY (1 << 2) +#define MCPDM_DN_IRQ_FULL (1 << 3) + +#define MCPDM_UP_IRQ (1 << 8) +#define MCPDM_UP_IRQ_EMPTY (1 << 9) +#define MCPDM_UP_IRQ_ALMST_FULL (1 << 10) +#define MCPDM_UP_IRQ_FULL (1 << 11) + +#define MCPDM_DOWNLINK_IRQ_MASK 0x00F +#define MCPDM_UPLINK_IRQ_MASK 0xF00 + +/* + * MCPDM_DMAENABLE bit fields + */ + +#define DMA_DN_ENABLE 0x1 +#define DMA_UP_ENABLE 0x2 + +/* + * MCPDM_CTRL bit fields + */ + +#define PDM_UP1_EN 0x0001 +#define PDM_UP2_EN 0x0002 +#define PDM_UP3_EN 0x0004 +#define PDM_DN1_EN 0x0008 +#define PDM_DN2_EN 0x0010 +#define PDM_DN3_EN 0x0020 +#define PDM_DN4_EN 0x0040 +#define PDM_DN5_EN 0x0080 +#define PDMOUTFORMAT 0x0100 +#define CMD_INT 0x0200 +#define STATUS_INT 0x0400 +#define SW_UP_RST 0x0800 +#define SW_DN_RST 0x1000 +#define PDM_UP_MASK 0x007 +#define PDM_DN_MASK 0x0F8 +#define PDM_CMD_MASK 0x200 +#define PDM_STATUS_MASK 0x400 + + +#define PDMOUTFORMAT_LJUST (0 << 8) +#define PDMOUTFORMAT_RJUST (1 << 8) + +/* + * MCPDM_FIFO_CTRL bit fields + */ + +#define UP_THRES_MAX 0xF +#define DN_THRES_MAX 0xF + +/* + * MCPDM_DN_OFFSET bit fields + */ + +#define DN_OFST_RX1_EN 0x0001 +#define DN_OFST_RX2_EN 0x0100 + +#define DN_OFST_RX1 1 +#define DN_OFST_RX2 9 +#define DN_OFST_MAX 0x1F + +#define MCPDM_UPLINK 1 +#define MCPDM_DOWNLINK 2 + +struct omap_mcpdm_link { + int irq_mask; + int threshold; + int format; + int channels; +}; + +struct omap_mcpdm; + +extern int omap_mcpdm_set_offset(struct omap_mcpdm *mcpdm, + int offset1, int offset2); + +#endif /* End of __OMAP_MCPDM_H__ */ -- 1.7.4.1