/* * 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; }
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_REG_IRQSTATUS); /* Acknowledge irq event */ omap_mcpdm_write(mcpdm, MCPDM_REG_IRQSTATUS, irq_status); if (irq_status & MCPDM_DN_IRQ_FULL) dev_dbg(mcpdm->dev, "DN (playback) FIFO Full\n"); if (irq_status & MCPDM_DN_IRQ_EMPTY) dev_dbg(mcpdm->dev, "DN (playback) FIFO Empty\n"); if (irq_status & MCPDM_DN_IRQ) dev_dbg(mcpdm->dev, "DN (playback) write request\n"); if (irq_status & MCPDM_UP_IRQ_FULL) dev_dbg(mcpdm->dev, "UP (capture) FIFO Full\n"); if (irq_status & MCPDM_UP_IRQ_EMPTY) dev_dbg(mcpdm->dev, "UP (capture) FIFO Empty\n"); if (irq_status & MCPDM_UP_IRQ) dev_dbg(mcpdm->dev, "UP (capture) write request\n"); return IRQ_HANDLED; }
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); switch (irq_status) { case DN_IRQ_FULL: case DN_IRQ_EMTPY: dev_err(mcpdm_irq->dev, "DN FIFO error %x\n", irq_status); omap_mcpdm_reset(MCPDM_DOWNLINK, 1); omap_mcpdm_set_downlink(mcpdm_irq->downlink); omap_mcpdm_reset(MCPDM_DOWNLINK, 0); break; case DN_IRQ: dev_dbg(mcpdm_irq->dev, "DN write request\n"); break; case UP_IRQ_FULL: case UP_IRQ_EMPTY: dev_err(mcpdm_irq->dev, "UP FIFO error %x\n", irq_status); omap_mcpdm_reset(MCPDM_UPLINK, 1); omap_mcpdm_set_uplink(mcpdm_irq->uplink); omap_mcpdm_reset(MCPDM_UPLINK, 0); break; case UP_IRQ: dev_dbg(mcpdm_irq->dev, "UP write request\n"); break; } return IRQ_HANDLED; }
/* * Configures McPDM uplink, and downlink for audio. * This function should be called before omap_mcpdm_start. */ static void omap_mcpdm_open_streams(struct omap_mcpdm *mcpdm) { u32 ctrl = omap_mcpdm_read(mcpdm, MCPDM_REG_CTRL); omap_mcpdm_write(mcpdm, MCPDM_REG_CTRL, ctrl | MCPDM_WD_EN); omap_mcpdm_write(mcpdm, MCPDM_REG_IRQENABLE_SET, MCPDM_DN_IRQ_EMPTY | MCPDM_DN_IRQ_FULL | MCPDM_UP_IRQ_EMPTY | MCPDM_UP_IRQ_FULL); /* Enable DN RX1/2 offset cancellation feature, if configured */ if (mcpdm->dn_rx_offset) { u32 dn_offset = mcpdm->dn_rx_offset; omap_mcpdm_write(mcpdm, MCPDM_REG_DN_OFFSET, dn_offset); dn_offset |= (MCPDM_DN_OFST_RX1_EN | MCPDM_DN_OFST_RX2_EN); omap_mcpdm_write(mcpdm, MCPDM_REG_DN_OFFSET, dn_offset); } omap_mcpdm_write(mcpdm, MCPDM_REG_FIFO_CTRL_DN, mcpdm->config[SNDRV_PCM_STREAM_PLAYBACK].threshold); omap_mcpdm_write(mcpdm, MCPDM_REG_FIFO_CTRL_UP, mcpdm->config[SNDRV_PCM_STREAM_CAPTURE].threshold); omap_mcpdm_write(mcpdm, MCPDM_REG_DMAENABLE_SET, MCPDM_DMA_DN_ENABLE | MCPDM_DMA_UP_ENABLE); }
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); }
/* * 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); }
/* * 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); }
/* * 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) { u32 ctrl = omap_mcpdm_read(mcpdm, MCPDM_REG_CTRL); u32 link_mask = mcpdm->config[0].link_mask | mcpdm->config[1].link_mask; ctrl |= (MCPDM_SW_DN_RST | MCPDM_SW_UP_RST); omap_mcpdm_write(mcpdm, MCPDM_REG_CTRL, ctrl); ctrl |= link_mask; omap_mcpdm_write(mcpdm, MCPDM_REG_CTRL, ctrl); ctrl &= ~(MCPDM_SW_DN_RST | MCPDM_SW_UP_RST); omap_mcpdm_write(mcpdm, MCPDM_REG_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) { u32 ctrl = omap_mcpdm_read(mcpdm, MCPDM_REG_CTRL); u32 link_mask = MCPDM_PDM_DN_MASK | MCPDM_PDM_UP_MASK; ctrl |= (MCPDM_SW_DN_RST | MCPDM_SW_UP_RST); omap_mcpdm_write(mcpdm, MCPDM_REG_CTRL, ctrl); ctrl &= ~(link_mask); omap_mcpdm_write(mcpdm, MCPDM_REG_CTRL, ctrl); ctrl &= ~(MCPDM_SW_DN_RST | MCPDM_SW_UP_RST); omap_mcpdm_write(mcpdm, MCPDM_REG_CTRL, ctrl); }
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; }
void omap_mcpdm_reset(int links, int reset) { int ctrl = omap_mcpdm_read(MCPDM_CTRL); if (links & MCPDM_UPLINK) { if (reset) ctrl |= SW_UP_RST; else ctrl &= ~SW_UP_RST; } if (links & MCPDM_DOWNLINK) { if (reset) ctrl |= SW_DN_RST; else ctrl &= ~SW_DN_RST; } omap_mcpdm_write(MCPDM_CTRL, ctrl); }
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); mutex_lock(&mcpdm->mutex); if (!dai->active) { u32 ctrl = omap_mcpdm_read(mcpdm, MCPDM_REG_CTRL); omap_mcpdm_write(mcpdm, MCPDM_REG_CTRL, ctrl | MCPDM_WD_EN); omap_mcpdm_open_streams(mcpdm); } mutex_unlock(&mcpdm->mutex); snd_soc_dai_set_dma_data(dai, substream, &mcpdm->dma_data[substream->stream]); return 0; }
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"); }
/* * Is the physical McPDM interface active. */ static inline int omap_mcpdm_active(struct omap_mcpdm *mcpdm) { return omap_mcpdm_read(mcpdm, MCPDM_REG_CTRL) & (MCPDM_PDM_DN_MASK | MCPDM_PDM_UP_MASK); }