/* * uni_reader_irq_handler * In case of error audio stream is stopped; stop action is protected via PCM * stream lock to avoid race condition with trigger callback. */ static irqreturn_t uni_reader_irq_handler(int irq, void *dev_id) { irqreturn_t ret = IRQ_NONE; struct uniperif *reader = dev_id; unsigned int status; if (reader->state == UNIPERIF_STATE_STOPPED) { /* Unexpected IRQ: do nothing */ dev_warn(reader->dev, "unexpected IRQ "); return IRQ_HANDLED; } /* Get interrupt status & clear them immediately */ status = GET_UNIPERIF_ITS(reader); SET_UNIPERIF_ITS_BCLR(reader, status); /* Check for fifo overflow error */ if (unlikely(status & UNIPERIF_ITS_FIFO_ERROR_MASK(reader))) { dev_err(reader->dev, "FIFO error detected"); snd_pcm_stream_lock(reader->substream); snd_pcm_stop(reader->substream, SNDRV_PCM_STATE_XRUN); snd_pcm_stream_unlock(reader->substream); return IRQ_HANDLED; } return ret; }
/* * uni_player_irq_handler * In case of error audio stream is stopped; stop action is protected via PCM * stream lock to avoid race condition with trigger callback. */ static irqreturn_t uni_player_irq_handler(int irq, void *dev_id) { irqreturn_t ret = IRQ_NONE; struct uniperif *player = dev_id; unsigned int status; unsigned int tmp; if (player->state == UNIPERIF_STATE_STOPPED) { /* Unexpected IRQ: do nothing */ return IRQ_NONE; } /* Get interrupt status & clear them immediately */ status = GET_UNIPERIF_ITS(player); SET_UNIPERIF_ITS_BCLR(player, status); /* Check for fifo error (underrun) */ if (unlikely(status & UNIPERIF_ITS_FIFO_ERROR_MASK(player))) { dev_err(player->dev, "FIFO underflow error detected\n"); /* Interrupt is just for information when underflow recovery */ if (player->underflow_enabled) { /* Update state to underflow */ player->state = UNIPERIF_STATE_UNDERFLOW; } else { /* Disable interrupt so doesn't continually fire */ SET_UNIPERIF_ITM_BCLR_FIFO_ERROR(player); /* Stop the player */ snd_pcm_stream_lock(player->substream); snd_pcm_stop(player->substream, SNDRV_PCM_STATE_XRUN); snd_pcm_stream_unlock(player->substream); } ret = IRQ_HANDLED; } /* Check for dma error (overrun) */ if (unlikely(status & UNIPERIF_ITS_DMA_ERROR_MASK(player))) { dev_err(player->dev, "DMA error detected\n"); /* Disable interrupt so doesn't continually fire */ SET_UNIPERIF_ITM_BCLR_DMA_ERROR(player); /* Stop the player */ snd_pcm_stream_lock(player->substream); snd_pcm_stop(player->substream, SNDRV_PCM_STATE_XRUN); snd_pcm_stream_unlock(player->substream); ret = IRQ_HANDLED; } /* Check for underflow recovery done */ if (unlikely(status & UNIPERIF_ITM_UNDERFLOW_REC_DONE_MASK(player))) { if (!player->underflow_enabled) { dev_err(player->dev, "unexpected Underflow recovering\n"); return -EPERM; } /* Read the underflow recovery duration */ tmp = GET_UNIPERIF_STATUS_1_UNDERFLOW_DURATION(player); dev_dbg(player->dev, "Underflow recovered (%d LR clocks max)\n", tmp); /* Clear the underflow recovery duration */ SET_UNIPERIF_BIT_CONTROL_CLR_UNDERFLOW_DURATION(player); /* Update state to started */ player->state = UNIPERIF_STATE_STARTED; ret = IRQ_HANDLED; } /* Check if underflow recovery failed */ if (unlikely(status & UNIPERIF_ITM_UNDERFLOW_REC_FAILED_MASK(player))) { dev_err(player->dev, "Underflow recovery failed\n"); /* Stop the player */ snd_pcm_stream_lock(player->substream); snd_pcm_stop(player->substream, SNDRV_PCM_STATE_XRUN); snd_pcm_stream_unlock(player->substream); ret = IRQ_HANDLED; } return ret; }