Alsa-devel
Threads by month
- ----- 2024 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2023 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2022 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2021 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2020 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2019 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2018 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2017 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2016 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2015 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2014 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2013 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2012 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2011 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2010 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2009 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2008 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2007 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
November 2018
- 114 participants
- 285 discussions
[alsa-devel] Applied "ASoC: omap-mcbsp: Move out the FIFO check from set_threshold and get_delay" to the asoc tree
by Mark Brown 13 Nov '18
by Mark Brown 13 Nov '18
13 Nov '18
The patch
ASoC: omap-mcbsp: Move out the FIFO check from set_threshold and get_delay
has been applied to the asoc tree at
https://git.kernel.org/pub/scm/linux/kernel/git/broonie/sound.git
All being well this means that it will be integrated into the linux-next
tree (usually sometime in the next 24 hours) and sent to Linus during
the next merge window (or sooner if it is a bug fix), however if
problems are discovered then the patch may be dropped or reverted.
You may get further e-mails resulting from automated or manual testing
and review of the tree, please engage with people reporting problems and
send followup patches addressing any issues that are reported if needed.
If any updates are required or you are submitting further changes they
should be sent as incremental updates against current git, existing
patches will not be replaced.
Please add any relevant lists and maintainers to the CCs when replying
to this mail.
Thanks,
Mark
>From be51c576e8495fd2cffbababad6de7e0a0a562ba Mon Sep 17 00:00:00 2001
From: Peter Ujfalusi <peter.ujfalusi(a)ti.com>
Date: Thu, 8 Nov 2018 09:29:57 +0200
Subject: [PATCH] ASoC: omap-mcbsp: Move out the FIFO check from set_threshold
and get_delay
Check if the McBSP have FIFO in the omap_mcbsp_set_threshold() and
omap_mcbsp_dai_delay() delay function to skip calling the lower layer if
it is not needed.
Signed-off-by: Peter Ujfalusi <peter.ujfalusi(a)ti.com>
Acked-by: Jarkko Nikula <jarkko.nikula(a)bitmer.com>
Tested-by: Jarkko Nikula <jarkko.nikula(a)bitmer.com>
Signed-off-by: Mark Brown <broonie(a)kernel.org>
---
sound/soc/omap/mcbsp.c | 12 ------------
sound/soc/omap/omap-mcbsp.c | 8 ++++++++
2 files changed, 8 insertions(+), 12 deletions(-)
diff --git a/sound/soc/omap/mcbsp.c b/sound/soc/omap/mcbsp.c
index 7ff22561f00f..b19168f5c110 100644
--- a/sound/soc/omap/mcbsp.c
+++ b/sound/soc/omap/mcbsp.c
@@ -450,9 +450,6 @@ int omap_st_is_enabled(struct omap_mcbsp *mcbsp)
*/
void omap_mcbsp_set_tx_threshold(struct omap_mcbsp *mcbsp, u16 threshold)
{
- if (mcbsp->pdata->buffer_size == 0)
- return;
-
if (threshold && threshold <= mcbsp->max_tx_thres)
MCBSP_WRITE(mcbsp, THRSH2, threshold - 1);
}
@@ -464,9 +461,6 @@ void omap_mcbsp_set_tx_threshold(struct omap_mcbsp *mcbsp, u16 threshold)
*/
void omap_mcbsp_set_rx_threshold(struct omap_mcbsp *mcbsp, u16 threshold)
{
- if (mcbsp->pdata->buffer_size == 0)
- return;
-
if (threshold && threshold <= mcbsp->max_rx_thres)
MCBSP_WRITE(mcbsp, THRSH1, threshold - 1);
}
@@ -478,9 +472,6 @@ u16 omap_mcbsp_get_tx_delay(struct omap_mcbsp *mcbsp)
{
u16 buffstat;
- if (mcbsp->pdata->buffer_size == 0)
- return 0;
-
/* Returns the number of free locations in the buffer */
buffstat = MCBSP_READ(mcbsp, XBUFFSTAT);
@@ -496,9 +487,6 @@ u16 omap_mcbsp_get_rx_delay(struct omap_mcbsp *mcbsp)
{
u16 buffstat, threshold;
- if (mcbsp->pdata->buffer_size == 0)
- return 0;
-
/* Returns the number of used locations in the buffer */
buffstat = MCBSP_READ(mcbsp, RBUFFSTAT);
/* RX threshold */
diff --git a/sound/soc/omap/omap-mcbsp.c b/sound/soc/omap/omap-mcbsp.c
index a18b7ecc3a2e..69a6b8ad6d42 100644
--- a/sound/soc/omap/omap-mcbsp.c
+++ b/sound/soc/omap/omap-mcbsp.c
@@ -71,6 +71,10 @@ static void omap_mcbsp_set_threshold(struct snd_pcm_substream *substream,
struct omap_mcbsp *mcbsp = snd_soc_dai_get_drvdata(cpu_dai);
int words;
+ /* No need to proceed further if McBSP does not have FIFO */
+ if (mcbsp->pdata->buffer_size == 0)
+ return;
+
/*
* Configure McBSP threshold based on either:
* packet_size, when the sDMA is in packet mode, or based on the
@@ -233,6 +237,10 @@ static snd_pcm_sframes_t omap_mcbsp_dai_delay(
u16 fifo_use;
snd_pcm_sframes_t delay;
+ /* No need to proceed further if McBSP does not have FIFO */
+ if (mcbsp->pdata->buffer_size == 0)
+ return 0;
+
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
fifo_use = omap_mcbsp_get_tx_delay(mcbsp);
else
--
2.19.1
1
0
[alsa-devel] Applied "ASoC: omap-mcbsp: Re-arrange files for core McBSP and Sidetone function split" to the asoc tree
by Mark Brown 13 Nov '18
by Mark Brown 13 Nov '18
13 Nov '18
The patch
ASoC: omap-mcbsp: Re-arrange files for core McBSP and Sidetone function split
has been applied to the asoc tree at
https://git.kernel.org/pub/scm/linux/kernel/git/broonie/sound.git
All being well this means that it will be integrated into the linux-next
tree (usually sometime in the next 24 hours) and sent to Linus during
the next merge window (or sooner if it is a bug fix), however if
problems are discovered then the patch may be dropped or reverted.
You may get further e-mails resulting from automated or manual testing
and review of the tree, please engage with people reporting problems and
send followup patches addressing any issues that are reported if needed.
If any updates are required or you are submitting further changes they
should be sent as incremental updates against current git, existing
patches will not be replaced.
Please add any relevant lists and maintainers to the CCs when replying
to this mail.
Thanks,
Mark
>From 9c34d023dc35a4b3d005d94db512742dfcdc8f82 Mon Sep 17 00:00:00 2001
From: Peter Ujfalusi <peter.ujfalusi(a)ti.com>
Date: Thu, 8 Nov 2018 09:29:58 +0200
Subject: [PATCH] ASoC: omap-mcbsp: Re-arrange files for core McBSP and
Sidetone function split
The mcbsp.c was copied a while back from arch/arm/plat-omap/mcbsp.c and it
contained a mix of McBSP and McBSP sidetone functions.
Create new file structure with the following split:
omap-mcbsp.c - McBSP related functions
omap-mcbsp-st.c - McBSP sidetone functionality
omap-mcbsp-priv.h - Private header for internal use
omap-mcbsp.h - Header for user drivers
I have tried to do the code move with minimal code change, cleanup patches
can be based on the new structure.
Signed-off-by: Peter Ujfalusi <peter.ujfalusi(a)ti.com>
Acked-by: Jarkko Nikula <jarkko.nikula(a)bitmer.com>
Tested-by: Jarkko Nikula <jarkko.nikula(a)bitmer.com>
Signed-off-by: Mark Brown <broonie(a)kernel.org>
---
sound/soc/omap/Makefile | 2 +-
sound/soc/omap/mcbsp.c | 1094 -----------------
sound/soc/omap/{mcbsp.h => omap-mcbsp-priv.h} | 126 +-
sound/soc/omap/omap-mcbsp-st.c | 516 ++++++++
sound/soc/omap/omap-mcbsp.c | 838 ++++++++++---
sound/soc/omap/omap-mcbsp.h | 8 +-
6 files changed, 1269 insertions(+), 1315 deletions(-)
delete mode 100644 sound/soc/omap/mcbsp.c
rename sound/soc/omap/{mcbsp.h => omap-mcbsp-priv.h} (70%)
create mode 100644 sound/soc/omap/omap-mcbsp-st.c
diff --git a/sound/soc/omap/Makefile b/sound/soc/omap/Makefile
index af50cdd6eea9..d005338dd13c 100644
--- a/sound/soc/omap/Makefile
+++ b/sound/soc/omap/Makefile
@@ -2,7 +2,7 @@
# OMAP Platform Support
snd-soc-sdma-objs := sdma-pcm.o
snd-soc-omap-dmic-objs := omap-dmic.o
-snd-soc-omap-mcbsp-objs := omap-mcbsp.o mcbsp.o
+snd-soc-omap-mcbsp-objs := omap-mcbsp.o omap-mcbsp-st.o
snd-soc-omap-mcpdm-objs := omap-mcpdm.o
snd-soc-omap-hdmi-audio-objs := omap-hdmi-audio.o
diff --git a/sound/soc/omap/mcbsp.c b/sound/soc/omap/mcbsp.c
deleted file mode 100644
index b19168f5c110..000000000000
--- a/sound/soc/omap/mcbsp.c
+++ /dev/null
@@ -1,1094 +0,0 @@
-/*
- * sound/soc/omap/mcbsp.c
- *
- * Copyright (C) 2004 Nokia Corporation
- * Author: Samuel Ortiz <samuel.ortiz(a)nokia.com>
- *
- * Contact: Jarkko Nikula <jarkko.nikula(a)bitmer.com>
- * Peter Ujfalusi <peter.ujfalusi(a)ti.com>
- *
- * 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.
- *
- * Multichannel mode not supported.
- */
-
-#include <linux/module.h>
-#include <linux/init.h>
-#include <linux/device.h>
-#include <linux/platform_device.h>
-#include <linux/interrupt.h>
-#include <linux/err.h>
-#include <linux/clk.h>
-#include <linux/delay.h>
-#include <linux/io.h>
-#include <linux/slab.h>
-#include <linux/pm_runtime.h>
-
-#include <linux/platform_data/asoc-ti-mcbsp.h>
-
-#include "mcbsp.h"
-
-static void omap_mcbsp_write(struct omap_mcbsp *mcbsp, u16 reg, u32 val)
-{
- void __iomem *addr = mcbsp->io_base + reg * mcbsp->pdata->reg_step;
-
- if (mcbsp->pdata->reg_size == 2) {
- ((u16 *)mcbsp->reg_cache)[reg] = (u16)val;
- writew_relaxed((u16)val, addr);
- } else {
- ((u32 *)mcbsp->reg_cache)[reg] = val;
- writel_relaxed(val, addr);
- }
-}
-
-static int omap_mcbsp_read(struct omap_mcbsp *mcbsp, u16 reg, bool from_cache)
-{
- void __iomem *addr = mcbsp->io_base + reg * mcbsp->pdata->reg_step;
-
- if (mcbsp->pdata->reg_size == 2) {
- return !from_cache ? readw_relaxed(addr) :
- ((u16 *)mcbsp->reg_cache)[reg];
- } else {
- return !from_cache ? readl_relaxed(addr) :
- ((u32 *)mcbsp->reg_cache)[reg];
- }
-}
-
-static void omap_mcbsp_st_write(struct omap_mcbsp *mcbsp, u16 reg, u32 val)
-{
- writel_relaxed(val, mcbsp->st_data->io_base_st + reg);
-}
-
-static int omap_mcbsp_st_read(struct omap_mcbsp *mcbsp, u16 reg)
-{
- return readl_relaxed(mcbsp->st_data->io_base_st + reg);
-}
-
-#define MCBSP_READ(mcbsp, reg) \
- omap_mcbsp_read(mcbsp, OMAP_MCBSP_REG_##reg, 0)
-#define MCBSP_WRITE(mcbsp, reg, val) \
- omap_mcbsp_write(mcbsp, OMAP_MCBSP_REG_##reg, val)
-#define MCBSP_READ_CACHE(mcbsp, reg) \
- omap_mcbsp_read(mcbsp, OMAP_MCBSP_REG_##reg, 1)
-
-#define MCBSP_ST_READ(mcbsp, reg) \
- omap_mcbsp_st_read(mcbsp, OMAP_ST_REG_##reg)
-#define MCBSP_ST_WRITE(mcbsp, reg, val) \
- omap_mcbsp_st_write(mcbsp, OMAP_ST_REG_##reg, val)
-
-static void omap_mcbsp_dump_reg(struct omap_mcbsp *mcbsp)
-{
- dev_dbg(mcbsp->dev, "**** McBSP%d regs ****\n", mcbsp->id);
- dev_dbg(mcbsp->dev, "DRR2: 0x%04x\n",
- MCBSP_READ(mcbsp, DRR2));
- dev_dbg(mcbsp->dev, "DRR1: 0x%04x\n",
- MCBSP_READ(mcbsp, DRR1));
- dev_dbg(mcbsp->dev, "DXR2: 0x%04x\n",
- MCBSP_READ(mcbsp, DXR2));
- dev_dbg(mcbsp->dev, "DXR1: 0x%04x\n",
- MCBSP_READ(mcbsp, DXR1));
- dev_dbg(mcbsp->dev, "SPCR2: 0x%04x\n",
- MCBSP_READ(mcbsp, SPCR2));
- dev_dbg(mcbsp->dev, "SPCR1: 0x%04x\n",
- MCBSP_READ(mcbsp, SPCR1));
- dev_dbg(mcbsp->dev, "RCR2: 0x%04x\n",
- MCBSP_READ(mcbsp, RCR2));
- dev_dbg(mcbsp->dev, "RCR1: 0x%04x\n",
- MCBSP_READ(mcbsp, RCR1));
- dev_dbg(mcbsp->dev, "XCR2: 0x%04x\n",
- MCBSP_READ(mcbsp, XCR2));
- dev_dbg(mcbsp->dev, "XCR1: 0x%04x\n",
- MCBSP_READ(mcbsp, XCR1));
- dev_dbg(mcbsp->dev, "SRGR2: 0x%04x\n",
- MCBSP_READ(mcbsp, SRGR2));
- dev_dbg(mcbsp->dev, "SRGR1: 0x%04x\n",
- MCBSP_READ(mcbsp, SRGR1));
- dev_dbg(mcbsp->dev, "PCR0: 0x%04x\n",
- MCBSP_READ(mcbsp, PCR0));
- dev_dbg(mcbsp->dev, "***********************\n");
-}
-
-static irqreturn_t omap_mcbsp_irq_handler(int irq, void *data)
-{
- struct omap_mcbsp *mcbsp = data;
- u16 irqst;
-
- irqst = MCBSP_READ(mcbsp, IRQST);
- dev_dbg(mcbsp->dev, "IRQ callback : 0x%x\n", irqst);
-
- if (irqst & RSYNCERREN)
- dev_err(mcbsp->dev, "RX Frame Sync Error!\n");
- if (irqst & RFSREN)
- dev_dbg(mcbsp->dev, "RX Frame Sync\n");
- if (irqst & REOFEN)
- dev_dbg(mcbsp->dev, "RX End Of Frame\n");
- if (irqst & RRDYEN)
- dev_dbg(mcbsp->dev, "RX Buffer Threshold Reached\n");
- if (irqst & RUNDFLEN)
- dev_err(mcbsp->dev, "RX Buffer Underflow!\n");
- if (irqst & ROVFLEN)
- dev_err(mcbsp->dev, "RX Buffer Overflow!\n");
-
- if (irqst & XSYNCERREN)
- dev_err(mcbsp->dev, "TX Frame Sync Error!\n");
- if (irqst & XFSXEN)
- dev_dbg(mcbsp->dev, "TX Frame Sync\n");
- if (irqst & XEOFEN)
- dev_dbg(mcbsp->dev, "TX End Of Frame\n");
- if (irqst & XRDYEN)
- dev_dbg(mcbsp->dev, "TX Buffer threshold Reached\n");
- if (irqst & XUNDFLEN)
- dev_err(mcbsp->dev, "TX Buffer Underflow!\n");
- if (irqst & XOVFLEN)
- dev_err(mcbsp->dev, "TX Buffer Overflow!\n");
- if (irqst & XEMPTYEOFEN)
- dev_dbg(mcbsp->dev, "TX Buffer empty at end of frame\n");
-
- MCBSP_WRITE(mcbsp, IRQST, irqst);
-
- return IRQ_HANDLED;
-}
-
-static irqreturn_t omap_mcbsp_tx_irq_handler(int irq, void *data)
-{
- struct omap_mcbsp *mcbsp = data;
- u16 irqst_spcr2;
-
- irqst_spcr2 = MCBSP_READ(mcbsp, SPCR2);
- dev_dbg(mcbsp->dev, "TX IRQ callback : 0x%x\n", irqst_spcr2);
-
- if (irqst_spcr2 & XSYNC_ERR) {
- dev_err(mcbsp->dev, "TX Frame Sync Error! : 0x%x\n",
- irqst_spcr2);
- /* Writing zero to XSYNC_ERR clears the IRQ */
- MCBSP_WRITE(mcbsp, SPCR2, MCBSP_READ_CACHE(mcbsp, SPCR2));
- }
-
- return IRQ_HANDLED;
-}
-
-static irqreturn_t omap_mcbsp_rx_irq_handler(int irq, void *data)
-{
- struct omap_mcbsp *mcbsp = data;
- u16 irqst_spcr1;
-
- irqst_spcr1 = MCBSP_READ(mcbsp, SPCR1);
- dev_dbg(mcbsp->dev, "RX IRQ callback : 0x%x\n", irqst_spcr1);
-
- if (irqst_spcr1 & RSYNC_ERR) {
- dev_err(mcbsp->dev, "RX Frame Sync Error! : 0x%x\n",
- irqst_spcr1);
- /* Writing zero to RSYNC_ERR clears the IRQ */
- MCBSP_WRITE(mcbsp, SPCR1, MCBSP_READ_CACHE(mcbsp, SPCR1));
- }
-
- return IRQ_HANDLED;
-}
-
-/*
- * omap_mcbsp_config simply write a config to the
- * appropriate McBSP.
- * You either call this function or set the McBSP registers
- * by yourself before calling omap_mcbsp_start().
- */
-void omap_mcbsp_config(struct omap_mcbsp *mcbsp,
- const struct omap_mcbsp_reg_cfg *config)
-{
- dev_dbg(mcbsp->dev, "Configuring McBSP%d phys_base: 0x%08lx\n",
- mcbsp->id, mcbsp->phys_base);
-
- /* We write the given config */
- MCBSP_WRITE(mcbsp, SPCR2, config->spcr2);
- MCBSP_WRITE(mcbsp, SPCR1, config->spcr1);
- MCBSP_WRITE(mcbsp, RCR2, config->rcr2);
- MCBSP_WRITE(mcbsp, RCR1, config->rcr1);
- MCBSP_WRITE(mcbsp, XCR2, config->xcr2);
- MCBSP_WRITE(mcbsp, XCR1, config->xcr1);
- MCBSP_WRITE(mcbsp, SRGR2, config->srgr2);
- MCBSP_WRITE(mcbsp, SRGR1, config->srgr1);
- MCBSP_WRITE(mcbsp, MCR2, config->mcr2);
- MCBSP_WRITE(mcbsp, MCR1, config->mcr1);
- MCBSP_WRITE(mcbsp, PCR0, config->pcr0);
- if (mcbsp->pdata->has_ccr) {
- MCBSP_WRITE(mcbsp, XCCR, config->xccr);
- MCBSP_WRITE(mcbsp, RCCR, config->rccr);
- }
- /* Enable wakeup behavior */
- if (mcbsp->pdata->has_wakeup)
- MCBSP_WRITE(mcbsp, WAKEUPEN, XRDYEN | RRDYEN);
-
- /* Enable TX/RX sync error interrupts by default */
- if (mcbsp->irq)
- MCBSP_WRITE(mcbsp, IRQEN, RSYNCERREN | XSYNCERREN |
- RUNDFLEN | ROVFLEN | XUNDFLEN | XOVFLEN);
-}
-
-/**
- * omap_mcbsp_dma_reg_params - returns the address of mcbsp data register
- * @mcbsp: omap_mcbsp struct for the McBSP instance
- * @stream: Stream direction (playback/capture)
- *
- * Returns the address of mcbsp data transmit register or data receive register
- * to be used by DMA for transferring/receiving data
- */
-static int omap_mcbsp_dma_reg_params(struct omap_mcbsp *mcbsp,
- unsigned int stream)
-{
- int data_reg;
-
- if (stream == SNDRV_PCM_STREAM_PLAYBACK) {
- if (mcbsp->pdata->reg_size == 2)
- data_reg = OMAP_MCBSP_REG_DXR1;
- else
- data_reg = OMAP_MCBSP_REG_DXR;
- } else {
- if (mcbsp->pdata->reg_size == 2)
- data_reg = OMAP_MCBSP_REG_DRR1;
- else
- data_reg = OMAP_MCBSP_REG_DRR;
- }
-
- return mcbsp->phys_dma_base + data_reg * mcbsp->pdata->reg_step;
-}
-
-static void omap_st_on(struct omap_mcbsp *mcbsp)
-{
- unsigned int w;
-
- if (mcbsp->pdata->force_ick_on)
- mcbsp->pdata->force_ick_on(mcbsp->st_data->mcbsp_iclk, true);
-
- /* Disable Sidetone clock auto-gating for normal operation */
- w = MCBSP_ST_READ(mcbsp, SYSCONFIG);
- MCBSP_ST_WRITE(mcbsp, SYSCONFIG, w & ~(ST_AUTOIDLE));
-
- /* Enable McBSP Sidetone */
- w = MCBSP_READ(mcbsp, SSELCR);
- MCBSP_WRITE(mcbsp, SSELCR, w | SIDETONEEN);
-
- /* Enable Sidetone from Sidetone Core */
- w = MCBSP_ST_READ(mcbsp, SSELCR);
- MCBSP_ST_WRITE(mcbsp, SSELCR, w | ST_SIDETONEEN);
-}
-
-static void omap_st_off(struct omap_mcbsp *mcbsp)
-{
- unsigned int w;
-
- w = MCBSP_ST_READ(mcbsp, SSELCR);
- MCBSP_ST_WRITE(mcbsp, SSELCR, w & ~(ST_SIDETONEEN));
-
- w = MCBSP_READ(mcbsp, SSELCR);
- MCBSP_WRITE(mcbsp, SSELCR, w & ~(SIDETONEEN));
-
- /* Enable Sidetone clock auto-gating to reduce power consumption */
- w = MCBSP_ST_READ(mcbsp, SYSCONFIG);
- MCBSP_ST_WRITE(mcbsp, SYSCONFIG, w | ST_AUTOIDLE);
-
- if (mcbsp->pdata->force_ick_on)
- mcbsp->pdata->force_ick_on(mcbsp->st_data->mcbsp_iclk, false);
-}
-
-static void omap_st_fir_write(struct omap_mcbsp *mcbsp, s16 *fir)
-{
- u16 val, i;
-
- val = MCBSP_ST_READ(mcbsp, SSELCR);
-
- if (val & ST_COEFFWREN)
- MCBSP_ST_WRITE(mcbsp, SSELCR, val & ~(ST_COEFFWREN));
-
- MCBSP_ST_WRITE(mcbsp, SSELCR, val | ST_COEFFWREN);
-
- for (i = 0; i < 128; i++)
- MCBSP_ST_WRITE(mcbsp, SFIRCR, fir[i]);
-
- i = 0;
-
- val = MCBSP_ST_READ(mcbsp, SSELCR);
- while (!(val & ST_COEFFWRDONE) && (++i < 1000))
- val = MCBSP_ST_READ(mcbsp, SSELCR);
-
- MCBSP_ST_WRITE(mcbsp, SSELCR, val & ~(ST_COEFFWREN));
-
- if (i == 1000)
- dev_err(mcbsp->dev, "McBSP FIR load error!\n");
-}
-
-static void omap_st_chgain(struct omap_mcbsp *mcbsp)
-{
- u16 w;
- struct omap_mcbsp_st_data *st_data = mcbsp->st_data;
-
- w = MCBSP_ST_READ(mcbsp, SSELCR);
-
- MCBSP_ST_WRITE(mcbsp, SGAINCR, ST_CH0GAIN(st_data->ch0gain) | \
- ST_CH1GAIN(st_data->ch1gain));
-}
-
-int omap_st_set_chgain(struct omap_mcbsp *mcbsp, int channel, s16 chgain)
-{
- struct omap_mcbsp_st_data *st_data = mcbsp->st_data;
- int ret = 0;
-
- if (!st_data)
- return -ENOENT;
-
- spin_lock_irq(&mcbsp->lock);
- if (channel == 0)
- st_data->ch0gain = chgain;
- else if (channel == 1)
- st_data->ch1gain = chgain;
- else
- ret = -EINVAL;
-
- if (st_data->enabled)
- omap_st_chgain(mcbsp);
- spin_unlock_irq(&mcbsp->lock);
-
- return ret;
-}
-
-int omap_st_get_chgain(struct omap_mcbsp *mcbsp, int channel, s16 *chgain)
-{
- struct omap_mcbsp_st_data *st_data = mcbsp->st_data;
- int ret = 0;
-
- if (!st_data)
- return -ENOENT;
-
- spin_lock_irq(&mcbsp->lock);
- if (channel == 0)
- *chgain = st_data->ch0gain;
- else if (channel == 1)
- *chgain = st_data->ch1gain;
- else
- ret = -EINVAL;
- spin_unlock_irq(&mcbsp->lock);
-
- return ret;
-}
-
-static int omap_st_start(struct omap_mcbsp *mcbsp)
-{
- struct omap_mcbsp_st_data *st_data = mcbsp->st_data;
-
- if (st_data->enabled && !st_data->running) {
- omap_st_fir_write(mcbsp, st_data->taps);
- omap_st_chgain(mcbsp);
-
- if (!mcbsp->free) {
- omap_st_on(mcbsp);
- st_data->running = 1;
- }
- }
-
- return 0;
-}
-
-int omap_st_enable(struct omap_mcbsp *mcbsp)
-{
- struct omap_mcbsp_st_data *st_data = mcbsp->st_data;
-
- if (!st_data)
- return -ENODEV;
-
- spin_lock_irq(&mcbsp->lock);
- st_data->enabled = 1;
- omap_st_start(mcbsp);
- spin_unlock_irq(&mcbsp->lock);
-
- return 0;
-}
-
-static int omap_st_stop(struct omap_mcbsp *mcbsp)
-{
- struct omap_mcbsp_st_data *st_data = mcbsp->st_data;
-
- if (st_data->running) {
- if (!mcbsp->free) {
- omap_st_off(mcbsp);
- st_data->running = 0;
- }
- }
-
- return 0;
-}
-
-int omap_st_disable(struct omap_mcbsp *mcbsp)
-{
- struct omap_mcbsp_st_data *st_data = mcbsp->st_data;
- int ret = 0;
-
- if (!st_data)
- return -ENODEV;
-
- spin_lock_irq(&mcbsp->lock);
- omap_st_stop(mcbsp);
- st_data->enabled = 0;
- spin_unlock_irq(&mcbsp->lock);
-
- return ret;
-}
-
-int omap_st_is_enabled(struct omap_mcbsp *mcbsp)
-{
- struct omap_mcbsp_st_data *st_data = mcbsp->st_data;
-
- if (!st_data)
- return -ENODEV;
-
- return st_data->enabled;
-}
-
-/*
- * omap_mcbsp_set_rx_threshold configures the transmit threshold in words.
- * The threshold parameter is 1 based, and it is converted (threshold - 1)
- * for the THRSH2 register.
- */
-void omap_mcbsp_set_tx_threshold(struct omap_mcbsp *mcbsp, u16 threshold)
-{
- if (threshold && threshold <= mcbsp->max_tx_thres)
- MCBSP_WRITE(mcbsp, THRSH2, threshold - 1);
-}
-
-/*
- * omap_mcbsp_set_rx_threshold configures the receive threshold in words.
- * The threshold parameter is 1 based, and it is converted (threshold - 1)
- * for the THRSH1 register.
- */
-void omap_mcbsp_set_rx_threshold(struct omap_mcbsp *mcbsp, u16 threshold)
-{
- if (threshold && threshold <= mcbsp->max_rx_thres)
- MCBSP_WRITE(mcbsp, THRSH1, threshold - 1);
-}
-
-/*
- * omap_mcbsp_get_tx_delay returns the number of used slots in the McBSP FIFO
- */
-u16 omap_mcbsp_get_tx_delay(struct omap_mcbsp *mcbsp)
-{
- u16 buffstat;
-
- /* Returns the number of free locations in the buffer */
- buffstat = MCBSP_READ(mcbsp, XBUFFSTAT);
-
- /* Number of slots are different in McBSP ports */
- return mcbsp->pdata->buffer_size - buffstat;
-}
-
-/*
- * omap_mcbsp_get_rx_delay returns the number of free slots in the McBSP FIFO
- * to reach the threshold value (when the DMA will be triggered to read it)
- */
-u16 omap_mcbsp_get_rx_delay(struct omap_mcbsp *mcbsp)
-{
- u16 buffstat, threshold;
-
- /* Returns the number of used locations in the buffer */
- buffstat = MCBSP_READ(mcbsp, RBUFFSTAT);
- /* RX threshold */
- threshold = MCBSP_READ(mcbsp, THRSH1);
-
- /* Return the number of location till we reach the threshold limit */
- if (threshold <= buffstat)
- return 0;
- else
- return threshold - buffstat;
-}
-
-int omap_mcbsp_request(struct omap_mcbsp *mcbsp)
-{
- void *reg_cache;
- int err;
-
- reg_cache = kzalloc(mcbsp->reg_cache_size, GFP_KERNEL);
- if (!reg_cache) {
- return -ENOMEM;
- }
-
- spin_lock(&mcbsp->lock);
- if (!mcbsp->free) {
- dev_err(mcbsp->dev, "McBSP%d is currently in use\n",
- mcbsp->id);
- err = -EBUSY;
- goto err_kfree;
- }
-
- mcbsp->free = false;
- mcbsp->reg_cache = reg_cache;
- spin_unlock(&mcbsp->lock);
-
- if (mcbsp->pdata && mcbsp->pdata->ops && mcbsp->pdata->ops->request)
- mcbsp->pdata->ops->request(mcbsp->id - 1);
-
- /*
- * Make sure that transmitter, receiver and sample-rate generator are
- * not running before activating IRQs.
- */
- MCBSP_WRITE(mcbsp, SPCR1, 0);
- MCBSP_WRITE(mcbsp, SPCR2, 0);
-
- if (mcbsp->irq) {
- err = request_irq(mcbsp->irq, omap_mcbsp_irq_handler, 0,
- "McBSP", (void *)mcbsp);
- if (err != 0) {
- dev_err(mcbsp->dev, "Unable to request IRQ\n");
- goto err_clk_disable;
- }
- } else {
- err = request_irq(mcbsp->tx_irq, omap_mcbsp_tx_irq_handler, 0,
- "McBSP TX", (void *)mcbsp);
- if (err != 0) {
- dev_err(mcbsp->dev, "Unable to request TX IRQ\n");
- goto err_clk_disable;
- }
-
- err = request_irq(mcbsp->rx_irq, omap_mcbsp_rx_irq_handler, 0,
- "McBSP RX", (void *)mcbsp);
- if (err != 0) {
- dev_err(mcbsp->dev, "Unable to request RX IRQ\n");
- goto err_free_irq;
- }
- }
-
- return 0;
-err_free_irq:
- free_irq(mcbsp->tx_irq, (void *)mcbsp);
-err_clk_disable:
- if (mcbsp->pdata && mcbsp->pdata->ops && mcbsp->pdata->ops->free)
- mcbsp->pdata->ops->free(mcbsp->id - 1);
-
- /* Disable wakeup behavior */
- if (mcbsp->pdata->has_wakeup)
- MCBSP_WRITE(mcbsp, WAKEUPEN, 0);
-
- spin_lock(&mcbsp->lock);
- mcbsp->free = true;
- mcbsp->reg_cache = NULL;
-err_kfree:
- spin_unlock(&mcbsp->lock);
- kfree(reg_cache);
-
- return err;
-}
-
-void omap_mcbsp_free(struct omap_mcbsp *mcbsp)
-{
- void *reg_cache;
-
- if (mcbsp->pdata && mcbsp->pdata->ops && mcbsp->pdata->ops->free)
- mcbsp->pdata->ops->free(mcbsp->id - 1);
-
- /* Disable wakeup behavior */
- if (mcbsp->pdata->has_wakeup)
- MCBSP_WRITE(mcbsp, WAKEUPEN, 0);
-
- /* Disable interrupt requests */
- if (mcbsp->irq)
- MCBSP_WRITE(mcbsp, IRQEN, 0);
-
- if (mcbsp->irq) {
- free_irq(mcbsp->irq, (void *)mcbsp);
- } else {
- free_irq(mcbsp->rx_irq, (void *)mcbsp);
- free_irq(mcbsp->tx_irq, (void *)mcbsp);
- }
-
- reg_cache = mcbsp->reg_cache;
-
- /*
- * Select CLKS source from internal source unconditionally before
- * marking the McBSP port as free.
- * If the external clock source via MCBSP_CLKS pin has been selected the
- * system will refuse to enter idle if the CLKS pin source is not reset
- * back to internal source.
- */
- if (!mcbsp_omap1())
- omap2_mcbsp_set_clks_src(mcbsp, MCBSP_CLKS_PRCM_SRC);
-
- spin_lock(&mcbsp->lock);
- if (mcbsp->free)
- dev_err(mcbsp->dev, "McBSP%d was not reserved\n", mcbsp->id);
- else
- mcbsp->free = true;
- mcbsp->reg_cache = NULL;
- spin_unlock(&mcbsp->lock);
-
- kfree(reg_cache);
-}
-
-/*
- * Here we start the McBSP, by enabling transmitter, receiver or both.
- * If no transmitter or receiver is active prior calling, then sample-rate
- * generator and frame sync are started.
- */
-void omap_mcbsp_start(struct omap_mcbsp *mcbsp, int stream)
-{
- int tx = (stream == SNDRV_PCM_STREAM_PLAYBACK);
- int rx = !tx;
- int enable_srg = 0;
- u16 w;
-
- if (mcbsp->st_data)
- omap_st_start(mcbsp);
-
- /* Only enable SRG, if McBSP is master */
- w = MCBSP_READ_CACHE(mcbsp, PCR0);
- if (w & (FSXM | FSRM | CLKXM | CLKRM))
- enable_srg = !((MCBSP_READ_CACHE(mcbsp, SPCR2) |
- MCBSP_READ_CACHE(mcbsp, SPCR1)) & 1);
-
- if (enable_srg) {
- /* Start the sample generator */
- w = MCBSP_READ_CACHE(mcbsp, SPCR2);
- MCBSP_WRITE(mcbsp, SPCR2, w | (1 << 6));
- }
-
- /* Enable transmitter and receiver */
- tx &= 1;
- w = MCBSP_READ_CACHE(mcbsp, SPCR2);
- MCBSP_WRITE(mcbsp, SPCR2, w | tx);
-
- rx &= 1;
- w = MCBSP_READ_CACHE(mcbsp, SPCR1);
- MCBSP_WRITE(mcbsp, SPCR1, w | rx);
-
- /*
- * Worst case: CLKSRG*2 = 8000khz: (1/8000) * 2 * 2 usec
- * REVISIT: 100us may give enough time for two CLKSRG, however
- * due to some unknown PM related, clock gating etc. reason it
- * is now at 500us.
- */
- udelay(500);
-
- if (enable_srg) {
- /* Start frame sync */
- w = MCBSP_READ_CACHE(mcbsp, SPCR2);
- MCBSP_WRITE(mcbsp, SPCR2, w | (1 << 7));
- }
-
- if (mcbsp->pdata->has_ccr) {
- /* Release the transmitter and receiver */
- w = MCBSP_READ_CACHE(mcbsp, XCCR);
- w &= ~(tx ? XDISABLE : 0);
- MCBSP_WRITE(mcbsp, XCCR, w);
- w = MCBSP_READ_CACHE(mcbsp, RCCR);
- w &= ~(rx ? RDISABLE : 0);
- MCBSP_WRITE(mcbsp, RCCR, w);
- }
-
- /* Dump McBSP Regs */
- omap_mcbsp_dump_reg(mcbsp);
-}
-
-void omap_mcbsp_stop(struct omap_mcbsp *mcbsp, int stream)
-{
- int tx = (stream == SNDRV_PCM_STREAM_PLAYBACK);
- int rx = !tx;
- int idle;
- u16 w;
-
- /* Reset transmitter */
- tx &= 1;
- if (mcbsp->pdata->has_ccr) {
- w = MCBSP_READ_CACHE(mcbsp, XCCR);
- w |= (tx ? XDISABLE : 0);
- MCBSP_WRITE(mcbsp, XCCR, w);
- }
- w = MCBSP_READ_CACHE(mcbsp, SPCR2);
- MCBSP_WRITE(mcbsp, SPCR2, w & ~tx);
-
- /* Reset receiver */
- rx &= 1;
- if (mcbsp->pdata->has_ccr) {
- w = MCBSP_READ_CACHE(mcbsp, RCCR);
- w |= (rx ? RDISABLE : 0);
- MCBSP_WRITE(mcbsp, RCCR, w);
- }
- w = MCBSP_READ_CACHE(mcbsp, SPCR1);
- MCBSP_WRITE(mcbsp, SPCR1, w & ~rx);
-
- idle = !((MCBSP_READ_CACHE(mcbsp, SPCR2) |
- MCBSP_READ_CACHE(mcbsp, SPCR1)) & 1);
-
- if (idle) {
- /* Reset the sample rate generator */
- w = MCBSP_READ_CACHE(mcbsp, SPCR2);
- MCBSP_WRITE(mcbsp, SPCR2, w & ~(1 << 6));
- }
-
- if (mcbsp->st_data)
- omap_st_stop(mcbsp);
-}
-
-int omap2_mcbsp_set_clks_src(struct omap_mcbsp *mcbsp, u8 fck_src_id)
-{
- struct clk *fck_src;
- const char *src;
- int r;
-
- if (fck_src_id == MCBSP_CLKS_PAD_SRC)
- src = "pad_fck";
- else if (fck_src_id == MCBSP_CLKS_PRCM_SRC)
- src = "prcm_fck";
- else
- return -EINVAL;
-
- fck_src = clk_get(mcbsp->dev, src);
- if (IS_ERR(fck_src)) {
- dev_err(mcbsp->dev, "CLKS: could not clk_get() %s\n", src);
- return -EINVAL;
- }
-
- pm_runtime_put_sync(mcbsp->dev);
-
- r = clk_set_parent(mcbsp->fclk, fck_src);
- if (r) {
- dev_err(mcbsp->dev, "CLKS: could not clk_set_parent() to %s\n",
- src);
- clk_put(fck_src);
- return r;
- }
-
- pm_runtime_get_sync(mcbsp->dev);
-
- clk_put(fck_src);
-
- return 0;
-
-}
-
-#define max_thres(m) (mcbsp->pdata->buffer_size)
-#define valid_threshold(m, val) ((val) <= max_thres(m))
-#define THRESHOLD_PROP_BUILDER(prop) \
-static ssize_t prop##_show(struct device *dev, \
- struct device_attribute *attr, char *buf) \
-{ \
- struct omap_mcbsp *mcbsp = dev_get_drvdata(dev); \
- \
- return sprintf(buf, "%u\n", mcbsp->prop); \
-} \
- \
-static ssize_t prop##_store(struct device *dev, \
- struct device_attribute *attr, \
- const char *buf, size_t size) \
-{ \
- struct omap_mcbsp *mcbsp = dev_get_drvdata(dev); \
- unsigned long val; \
- int status; \
- \
- status = kstrtoul(buf, 0, &val); \
- if (status) \
- return status; \
- \
- if (!valid_threshold(mcbsp, val)) \
- return -EDOM; \
- \
- mcbsp->prop = val; \
- return size; \
-} \
- \
-static DEVICE_ATTR(prop, 0644, prop##_show, prop##_store);
-
-THRESHOLD_PROP_BUILDER(max_tx_thres);
-THRESHOLD_PROP_BUILDER(max_rx_thres);
-
-static const char *dma_op_modes[] = {
- "element", "threshold",
-};
-
-static ssize_t dma_op_mode_show(struct device *dev,
- struct device_attribute *attr, char *buf)
-{
- struct omap_mcbsp *mcbsp = dev_get_drvdata(dev);
- int dma_op_mode, i = 0;
- ssize_t len = 0;
- const char * const *s;
-
- dma_op_mode = mcbsp->dma_op_mode;
-
- for (s = &dma_op_modes[i]; i < ARRAY_SIZE(dma_op_modes); s++, i++) {
- if (dma_op_mode == i)
- len += sprintf(buf + len, "[%s] ", *s);
- else
- len += sprintf(buf + len, "%s ", *s);
- }
- len += sprintf(buf + len, "\n");
-
- return len;
-}
-
-static ssize_t dma_op_mode_store(struct device *dev,
- struct device_attribute *attr,
- const char *buf, size_t size)
-{
- struct omap_mcbsp *mcbsp = dev_get_drvdata(dev);
- int i;
-
- i = sysfs_match_string(dma_op_modes, buf);
- if (i < 0)
- return i;
-
- spin_lock_irq(&mcbsp->lock);
- if (!mcbsp->free) {
- size = -EBUSY;
- goto unlock;
- }
- mcbsp->dma_op_mode = i;
-
-unlock:
- spin_unlock_irq(&mcbsp->lock);
-
- return size;
-}
-
-static DEVICE_ATTR_RW(dma_op_mode);
-
-static const struct attribute *additional_attrs[] = {
- &dev_attr_max_tx_thres.attr,
- &dev_attr_max_rx_thres.attr,
- &dev_attr_dma_op_mode.attr,
- NULL,
-};
-
-static const struct attribute_group additional_attr_group = {
- .attrs = (struct attribute **)additional_attrs,
-};
-
-static ssize_t st_taps_show(struct device *dev,
- struct device_attribute *attr, char *buf)
-{
- struct omap_mcbsp *mcbsp = dev_get_drvdata(dev);
- struct omap_mcbsp_st_data *st_data = mcbsp->st_data;
- ssize_t status = 0;
- int i;
-
- spin_lock_irq(&mcbsp->lock);
- for (i = 0; i < st_data->nr_taps; i++)
- status += sprintf(&buf[status], (i ? ", %d" : "%d"),
- st_data->taps[i]);
- if (i)
- status += sprintf(&buf[status], "\n");
- spin_unlock_irq(&mcbsp->lock);
-
- return status;
-}
-
-static ssize_t st_taps_store(struct device *dev,
- struct device_attribute *attr,
- const char *buf, size_t size)
-{
- struct omap_mcbsp *mcbsp = dev_get_drvdata(dev);
- struct omap_mcbsp_st_data *st_data = mcbsp->st_data;
- int val, tmp, status, i = 0;
-
- spin_lock_irq(&mcbsp->lock);
- memset(st_data->taps, 0, sizeof(st_data->taps));
- st_data->nr_taps = 0;
-
- do {
- status = sscanf(buf, "%d%n", &val, &tmp);
- if (status < 0 || status == 0) {
- size = -EINVAL;
- goto out;
- }
- if (val < -32768 || val > 32767) {
- size = -EINVAL;
- goto out;
- }
- st_data->taps[i++] = val;
- buf += tmp;
- if (*buf != ',')
- break;
- buf++;
- } while (1);
-
- st_data->nr_taps = i;
-
-out:
- spin_unlock_irq(&mcbsp->lock);
-
- return size;
-}
-
-static DEVICE_ATTR_RW(st_taps);
-
-static const struct attribute *sidetone_attrs[] = {
- &dev_attr_st_taps.attr,
- NULL,
-};
-
-static const struct attribute_group sidetone_attr_group = {
- .attrs = (struct attribute **)sidetone_attrs,
-};
-
-static int omap_st_add(struct omap_mcbsp *mcbsp, struct resource *res)
-{
- struct omap_mcbsp_st_data *st_data;
- int err;
-
- st_data = devm_kzalloc(mcbsp->dev, sizeof(*mcbsp->st_data), GFP_KERNEL);
- if (!st_data)
- return -ENOMEM;
-
- st_data->mcbsp_iclk = clk_get(mcbsp->dev, "ick");
- if (IS_ERR(st_data->mcbsp_iclk)) {
- dev_warn(mcbsp->dev,
- "Failed to get ick, sidetone might be broken\n");
- st_data->mcbsp_iclk = NULL;
- }
-
- st_data->io_base_st = devm_ioremap(mcbsp->dev, res->start,
- resource_size(res));
- if (!st_data->io_base_st)
- return -ENOMEM;
-
- err = sysfs_create_group(&mcbsp->dev->kobj, &sidetone_attr_group);
- if (err)
- return err;
-
- mcbsp->st_data = st_data;
- return 0;
-}
-
-/*
- * McBSP1 and McBSP3 are directly mapped on 1610 and 1510.
- * 730 has only 2 McBSP, and both of them are MPU peripherals.
- */
-int omap_mcbsp_init(struct platform_device *pdev)
-{
- struct omap_mcbsp *mcbsp = platform_get_drvdata(pdev);
- struct resource *res;
- int ret = 0;
-
- spin_lock_init(&mcbsp->lock);
- mcbsp->free = true;
-
- res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "mpu");
- if (!res)
- res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-
- mcbsp->io_base = devm_ioremap_resource(&pdev->dev, res);
- if (IS_ERR(mcbsp->io_base))
- return PTR_ERR(mcbsp->io_base);
-
- mcbsp->phys_base = res->start;
- mcbsp->reg_cache_size = resource_size(res);
-
- res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "dma");
- if (!res)
- mcbsp->phys_dma_base = mcbsp->phys_base;
- else
- mcbsp->phys_dma_base = res->start;
-
- /*
- * OMAP1, 2 uses two interrupt lines: TX, RX
- * OMAP2430, OMAP3 SoC have combined IRQ line as well.
- * OMAP4 and newer SoC only have the combined IRQ line.
- * Use the combined IRQ if available since it gives better debugging
- * possibilities.
- */
- mcbsp->irq = platform_get_irq_byname(pdev, "common");
- if (mcbsp->irq == -ENXIO) {
- mcbsp->tx_irq = platform_get_irq_byname(pdev, "tx");
-
- if (mcbsp->tx_irq == -ENXIO) {
- mcbsp->irq = platform_get_irq(pdev, 0);
- mcbsp->tx_irq = 0;
- } else {
- mcbsp->rx_irq = platform_get_irq_byname(pdev, "rx");
- mcbsp->irq = 0;
- }
- }
-
- if (!pdev->dev.of_node) {
- res = platform_get_resource_byname(pdev, IORESOURCE_DMA, "tx");
- if (!res) {
- dev_err(&pdev->dev, "invalid tx DMA channel\n");
- return -ENODEV;
- }
- mcbsp->dma_req[0] = res->start;
- mcbsp->dma_data[0].filter_data = &mcbsp->dma_req[0];
-
- res = platform_get_resource_byname(pdev, IORESOURCE_DMA, "rx");
- if (!res) {
- dev_err(&pdev->dev, "invalid rx DMA channel\n");
- return -ENODEV;
- }
- mcbsp->dma_req[1] = res->start;
- mcbsp->dma_data[1].filter_data = &mcbsp->dma_req[1];
- } else {
- mcbsp->dma_data[0].filter_data = "tx";
- mcbsp->dma_data[1].filter_data = "rx";
- }
-
- mcbsp->dma_data[0].addr = omap_mcbsp_dma_reg_params(mcbsp,
- SNDRV_PCM_STREAM_PLAYBACK);
- mcbsp->dma_data[1].addr = omap_mcbsp_dma_reg_params(mcbsp,
- SNDRV_PCM_STREAM_CAPTURE);
-
- mcbsp->fclk = clk_get(&pdev->dev, "fck");
- if (IS_ERR(mcbsp->fclk)) {
- ret = PTR_ERR(mcbsp->fclk);
- dev_err(mcbsp->dev, "unable to get fck: %d\n", ret);
- return ret;
- }
-
- mcbsp->dma_op_mode = MCBSP_DMA_MODE_ELEMENT;
- if (mcbsp->pdata->buffer_size) {
- /*
- * Initially configure the maximum thresholds to a safe value.
- * The McBSP FIFO usage with these values should not go under
- * 16 locations.
- * If the whole FIFO without safety buffer is used, than there
- * is a possibility that the DMA will be not able to push the
- * new data on time, causing channel shifts in runtime.
- */
- mcbsp->max_tx_thres = max_thres(mcbsp) - 0x10;
- mcbsp->max_rx_thres = max_thres(mcbsp) - 0x10;
-
- ret = sysfs_create_group(&mcbsp->dev->kobj,
- &additional_attr_group);
- if (ret) {
- dev_err(mcbsp->dev,
- "Unable to create additional controls\n");
- goto err_thres;
- }
- } else {
- mcbsp->max_tx_thres = -EINVAL;
- mcbsp->max_rx_thres = -EINVAL;
- }
-
- res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "sidetone");
- if (res) {
- ret = omap_st_add(mcbsp, res);
- if (ret) {
- dev_err(mcbsp->dev,
- "Unable to create sidetone controls\n");
- goto err_st;
- }
- }
-
- return 0;
-
-err_st:
- if (mcbsp->pdata->buffer_size)
- sysfs_remove_group(&mcbsp->dev->kobj, &additional_attr_group);
-err_thres:
- clk_put(mcbsp->fclk);
- return ret;
-}
-
-void omap_mcbsp_cleanup(struct omap_mcbsp *mcbsp)
-{
- if (mcbsp->pdata->buffer_size)
- sysfs_remove_group(&mcbsp->dev->kobj, &additional_attr_group);
-
- if (mcbsp->st_data) {
- sysfs_remove_group(&mcbsp->dev->kobj, &sidetone_attr_group);
- clk_put(mcbsp->st_data->mcbsp_iclk);
- }
-}
diff --git a/sound/soc/omap/mcbsp.h b/sound/soc/omap/omap-mcbsp-priv.h
similarity index 70%
rename from sound/soc/omap/mcbsp.h
rename to sound/soc/omap/omap-mcbsp-priv.h
index 92472c6ef358..7865cda4bf0a 100644
--- a/sound/soc/omap/mcbsp.h
+++ b/sound/soc/omap/omap-mcbsp-priv.h
@@ -1,28 +1,15 @@
+/* SPDX-License-Identifier: GPL-2.0 */
/*
- * sound/soc/omap/mcbsp.h
- *
* OMAP Multi-Channel Buffered Serial Port
*
* Contact: Jarkko Nikula <jarkko.nikula(a)bitmer.com>
* Peter Ujfalusi <peter.ujfalusi(a)ti.com>
- *
- * 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 __ASOC_MCBSP_H
-#define __ASOC_MCBSP_H
+
+#ifndef __OMAP_MCBSP_PRIV_H__
+#define __OMAP_MCBSP_PRIV_H__
+
+#include <linux/platform_data/asoc-ti-mcbsp.h>
#ifdef CONFIG_ARCH_OMAP1
#define mcbsp_omap1() 1
@@ -30,8 +17,6 @@
#define mcbsp_omap1() 0
#endif
-#include <sound/dmaengine_pcm.h>
-
/* McBSP register numbers. Register address offset = num * reg_step */
enum {
/* Common registers */
@@ -85,15 +70,6 @@ enum {
OMAP_MCBSP_REG_SSELCR,
};
-/* OMAP3 sidetone control registers */
-#define OMAP_ST_REG_REV 0x00
-#define OMAP_ST_REG_SYSCONFIG 0x10
-#define OMAP_ST_REG_IRQSTATUS 0x18
-#define OMAP_ST_REG_IRQENABLE 0x1C
-#define OMAP_ST_REG_SGAINCR 0x24
-#define OMAP_ST_REG_SFIRCR 0x28
-#define OMAP_ST_REG_SSELCR 0x2C
-
/************************** McBSP SPCR1 bit definitions ***********************/
#define RRST BIT(0)
#define RRDY BIT(1)
@@ -202,24 +178,6 @@ enum {
#define SIDLEMODE(value) (((value) & 0x3) << 3)
#define CLOCKACTIVITY(value) (((value) & 0x3) << 8)
-/********************** McBSP SSELCR bit definitions ***********************/
-#define SIDETONEEN BIT(10)
-
-/********************** McBSP Sidetone SYSCONFIG bit definitions ***********/
-#define ST_AUTOIDLE BIT(0)
-
-/********************** McBSP Sidetone SGAINCR bit definitions *************/
-#define ST_CH0GAIN(value) ((value) & 0xffff) /* Bits 0:15 */
-#define ST_CH1GAIN(value) (((value) & 0xffff) << 16) /* Bits 16:31 */
-
-/********************** McBSP Sidetone SFIRCR bit definitions **************/
-#define ST_FIRCOEFF(value) ((value) & 0xffff) /* Bits 0:15 */
-
-/********************** McBSP Sidetone SSELCR bit definitions **************/
-#define ST_SIDETONEEN BIT(0)
-#define ST_COEFFWREN BIT(1)
-#define ST_COEFFWRDONE BIT(2)
-
/********************** McBSP DMA operating modes **************************/
#define MCBSP_DMA_MODE_ELEMENT 0
#define MCBSP_DMA_MODE_THRESHOLD 1
@@ -278,16 +236,7 @@ struct omap_mcbsp_reg_cfg {
u16 rccr;
};
-struct omap_mcbsp_st_data {
- void __iomem *io_base_st;
- struct clk *mcbsp_iclk;
- bool running;
- bool enabled;
- s16 taps[128]; /* Sidetone filter coefficients */
- int nr_taps; /* Number of filter coefficients in use */
- s16 ch0gain;
- s16 ch1gain;
-};
+struct omap_mcbsp_st_data;
struct omap_mcbsp {
struct device *dev;
@@ -330,29 +279,46 @@ struct omap_mcbsp {
struct pm_qos_request pm_qos_req;
};
-void omap_mcbsp_config(struct omap_mcbsp *mcbsp,
- const struct omap_mcbsp_reg_cfg *config);
-void omap_mcbsp_set_tx_threshold(struct omap_mcbsp *mcbsp, u16 threshold);
-void omap_mcbsp_set_rx_threshold(struct omap_mcbsp *mcbsp, u16 threshold);
-u16 omap_mcbsp_get_tx_delay(struct omap_mcbsp *mcbsp);
-u16 omap_mcbsp_get_rx_delay(struct omap_mcbsp *mcbsp);
-int omap_mcbsp_get_dma_op_mode(struct omap_mcbsp *mcbsp);
-int omap_mcbsp_request(struct omap_mcbsp *mcbsp);
-void omap_mcbsp_free(struct omap_mcbsp *mcbsp);
-void omap_mcbsp_start(struct omap_mcbsp *mcbsp, int stream);
-void omap_mcbsp_stop(struct omap_mcbsp *mcbsp, int stream);
-
-/* McBSP functional clock source changing function */
-int omap2_mcbsp_set_clks_src(struct omap_mcbsp *mcbsp, u8 fck_src_id);
+static inline void omap_mcbsp_write(struct omap_mcbsp *mcbsp, u16 reg, u32 val)
+{
+ void __iomem *addr = mcbsp->io_base + reg * mcbsp->pdata->reg_step;
+
+ if (mcbsp->pdata->reg_size == 2) {
+ ((u16 *)mcbsp->reg_cache)[reg] = (u16)val;
+ writew_relaxed((u16)val, addr);
+ } else {
+ ((u32 *)mcbsp->reg_cache)[reg] = val;
+ writel_relaxed(val, addr);
+ }
+}
+
+static inline int omap_mcbsp_read(struct omap_mcbsp *mcbsp, u16 reg,
+ bool from_cache)
+{
+ void __iomem *addr = mcbsp->io_base + reg * mcbsp->pdata->reg_step;
+
+ if (mcbsp->pdata->reg_size == 2) {
+ return !from_cache ? readw_relaxed(addr) :
+ ((u16 *)mcbsp->reg_cache)[reg];
+ } else {
+ return !from_cache ? readl_relaxed(addr) :
+ ((u32 *)mcbsp->reg_cache)[reg];
+ }
+}
+
+#define MCBSP_READ(mcbsp, reg) \
+ omap_mcbsp_read(mcbsp, OMAP_MCBSP_REG_##reg, 0)
+#define MCBSP_WRITE(mcbsp, reg, val) \
+ omap_mcbsp_write(mcbsp, OMAP_MCBSP_REG_##reg, val)
+#define MCBSP_READ_CACHE(mcbsp, reg) \
+ omap_mcbsp_read(mcbsp, OMAP_MCBSP_REG_##reg, 1)
+
/* Sidetone specific API */
-int omap_st_set_chgain(struct omap_mcbsp *mcbsp, int channel, s16 chgain);
-int omap_st_get_chgain(struct omap_mcbsp *mcbsp, int channel, s16 *chgain);
-int omap_st_enable(struct omap_mcbsp *mcbsp);
-int omap_st_disable(struct omap_mcbsp *mcbsp);
-int omap_st_is_enabled(struct omap_mcbsp *mcbsp);
+int omap_mcbsp_st_init(struct platform_device *pdev);
+void omap_mcbsp_st_cleanup(struct platform_device *pdev);
-int omap_mcbsp_init(struct platform_device *pdev);
-void omap_mcbsp_cleanup(struct omap_mcbsp *mcbsp);
+int omap_mcbsp_st_start(struct omap_mcbsp *mcbsp);
+int omap_mcbsp_st_stop(struct omap_mcbsp *mcbsp);
-#endif /* __ASOC_MCBSP_H */
+#endif /* __OMAP_MCBSP_PRIV_H__ */
diff --git a/sound/soc/omap/omap-mcbsp-st.c b/sound/soc/omap/omap-mcbsp-st.c
new file mode 100644
index 000000000000..1a3fe854e856
--- /dev/null
+++ b/sound/soc/omap/omap-mcbsp-st.c
@@ -0,0 +1,516 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * McBSP Sidetone support
+ *
+ * Copyright (C) 2004 Nokia Corporation
+ * Author: Samuel Ortiz <samuel.ortiz(a)nokia.com>
+ *
+ * Contact: Jarkko Nikula <jarkko.nikula(a)bitmer.com>
+ * Peter Ujfalusi <peter.ujfalusi(a)ti.com>
+ */
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/device.h>
+#include <linux/platform_device.h>
+#include <linux/interrupt.h>
+#include <linux/err.h>
+#include <linux/clk.h>
+#include <linux/delay.h>
+#include <linux/io.h>
+#include <linux/slab.h>
+#include <linux/pm_runtime.h>
+
+#include "omap-mcbsp.h"
+#include "omap-mcbsp-priv.h"
+
+/* OMAP3 sidetone control registers */
+#define OMAP_ST_REG_REV 0x00
+#define OMAP_ST_REG_SYSCONFIG 0x10
+#define OMAP_ST_REG_IRQSTATUS 0x18
+#define OMAP_ST_REG_IRQENABLE 0x1C
+#define OMAP_ST_REG_SGAINCR 0x24
+#define OMAP_ST_REG_SFIRCR 0x28
+#define OMAP_ST_REG_SSELCR 0x2C
+
+/********************** McBSP SSELCR bit definitions ***********************/
+#define SIDETONEEN BIT(10)
+
+/********************** McBSP Sidetone SYSCONFIG bit definitions ***********/
+#define ST_AUTOIDLE BIT(0)
+
+/********************** McBSP Sidetone SGAINCR bit definitions *************/
+#define ST_CH0GAIN(value) ((value) & 0xffff) /* Bits 0:15 */
+#define ST_CH1GAIN(value) (((value) & 0xffff) << 16) /* Bits 16:31 */
+
+/********************** McBSP Sidetone SFIRCR bit definitions **************/
+#define ST_FIRCOEFF(value) ((value) & 0xffff) /* Bits 0:15 */
+
+/********************** McBSP Sidetone SSELCR bit definitions **************/
+#define ST_SIDETONEEN BIT(0)
+#define ST_COEFFWREN BIT(1)
+#define ST_COEFFWRDONE BIT(2)
+
+struct omap_mcbsp_st_data {
+ void __iomem *io_base_st;
+ struct clk *mcbsp_iclk;
+ bool running;
+ bool enabled;
+ s16 taps[128]; /* Sidetone filter coefficients */
+ int nr_taps; /* Number of filter coefficients in use */
+ s16 ch0gain;
+ s16 ch1gain;
+};
+
+static void omap_mcbsp_st_write(struct omap_mcbsp *mcbsp, u16 reg, u32 val)
+{
+ writel_relaxed(val, mcbsp->st_data->io_base_st + reg);
+}
+
+static int omap_mcbsp_st_read(struct omap_mcbsp *mcbsp, u16 reg)
+{
+ return readl_relaxed(mcbsp->st_data->io_base_st + reg);
+}
+
+#define MCBSP_ST_READ(mcbsp, reg) omap_mcbsp_st_read(mcbsp, OMAP_ST_REG_##reg)
+#define MCBSP_ST_WRITE(mcbsp, reg, val) \
+ omap_mcbsp_st_write(mcbsp, OMAP_ST_REG_##reg, val)
+
+static void omap_mcbsp_st_on(struct omap_mcbsp *mcbsp)
+{
+ unsigned int w;
+
+ if (mcbsp->pdata->force_ick_on)
+ mcbsp->pdata->force_ick_on(mcbsp->st_data->mcbsp_iclk, true);
+
+ /* Disable Sidetone clock auto-gating for normal operation */
+ w = MCBSP_ST_READ(mcbsp, SYSCONFIG);
+ MCBSP_ST_WRITE(mcbsp, SYSCONFIG, w & ~(ST_AUTOIDLE));
+
+ /* Enable McBSP Sidetone */
+ w = MCBSP_READ(mcbsp, SSELCR);
+ MCBSP_WRITE(mcbsp, SSELCR, w | SIDETONEEN);
+
+ /* Enable Sidetone from Sidetone Core */
+ w = MCBSP_ST_READ(mcbsp, SSELCR);
+ MCBSP_ST_WRITE(mcbsp, SSELCR, w | ST_SIDETONEEN);
+}
+
+static void omap_mcbsp_st_off(struct omap_mcbsp *mcbsp)
+{
+ unsigned int w;
+
+ w = MCBSP_ST_READ(mcbsp, SSELCR);
+ MCBSP_ST_WRITE(mcbsp, SSELCR, w & ~(ST_SIDETONEEN));
+
+ w = MCBSP_READ(mcbsp, SSELCR);
+ MCBSP_WRITE(mcbsp, SSELCR, w & ~(SIDETONEEN));
+
+ /* Enable Sidetone clock auto-gating to reduce power consumption */
+ w = MCBSP_ST_READ(mcbsp, SYSCONFIG);
+ MCBSP_ST_WRITE(mcbsp, SYSCONFIG, w | ST_AUTOIDLE);
+
+ if (mcbsp->pdata->force_ick_on)
+ mcbsp->pdata->force_ick_on(mcbsp->st_data->mcbsp_iclk, false);
+}
+
+static void omap_mcbsp_st_fir_write(struct omap_mcbsp *mcbsp, s16 *fir)
+{
+ u16 val, i;
+
+ val = MCBSP_ST_READ(mcbsp, SSELCR);
+
+ if (val & ST_COEFFWREN)
+ MCBSP_ST_WRITE(mcbsp, SSELCR, val & ~(ST_COEFFWREN));
+
+ MCBSP_ST_WRITE(mcbsp, SSELCR, val | ST_COEFFWREN);
+
+ for (i = 0; i < 128; i++)
+ MCBSP_ST_WRITE(mcbsp, SFIRCR, fir[i]);
+
+ i = 0;
+
+ val = MCBSP_ST_READ(mcbsp, SSELCR);
+ while (!(val & ST_COEFFWRDONE) && (++i < 1000))
+ val = MCBSP_ST_READ(mcbsp, SSELCR);
+
+ MCBSP_ST_WRITE(mcbsp, SSELCR, val & ~(ST_COEFFWREN));
+
+ if (i == 1000)
+ dev_err(mcbsp->dev, "McBSP FIR load error!\n");
+}
+
+static void omap_mcbsp_st_chgain(struct omap_mcbsp *mcbsp)
+{
+ u16 w;
+ struct omap_mcbsp_st_data *st_data = mcbsp->st_data;
+
+ w = MCBSP_ST_READ(mcbsp, SSELCR);
+
+ MCBSP_ST_WRITE(mcbsp, SGAINCR, ST_CH0GAIN(st_data->ch0gain) |
+ ST_CH1GAIN(st_data->ch1gain));
+}
+
+static int omap_mcbsp_st_set_chgain(struct omap_mcbsp *mcbsp, int channel,
+ s16 chgain)
+{
+ struct omap_mcbsp_st_data *st_data = mcbsp->st_data;
+ int ret = 0;
+
+ if (!st_data)
+ return -ENOENT;
+
+ spin_lock_irq(&mcbsp->lock);
+ if (channel == 0)
+ st_data->ch0gain = chgain;
+ else if (channel == 1)
+ st_data->ch1gain = chgain;
+ else
+ ret = -EINVAL;
+
+ if (st_data->enabled)
+ omap_mcbsp_st_chgain(mcbsp);
+ spin_unlock_irq(&mcbsp->lock);
+
+ return ret;
+}
+
+static int omap_mcbsp_st_get_chgain(struct omap_mcbsp *mcbsp, int channel,
+ s16 *chgain)
+{
+ struct omap_mcbsp_st_data *st_data = mcbsp->st_data;
+ int ret = 0;
+
+ if (!st_data)
+ return -ENOENT;
+
+ spin_lock_irq(&mcbsp->lock);
+ if (channel == 0)
+ *chgain = st_data->ch0gain;
+ else if (channel == 1)
+ *chgain = st_data->ch1gain;
+ else
+ ret = -EINVAL;
+ spin_unlock_irq(&mcbsp->lock);
+
+ return ret;
+}
+
+static int omap_mcbsp_st_enable(struct omap_mcbsp *mcbsp)
+{
+ struct omap_mcbsp_st_data *st_data = mcbsp->st_data;
+
+ if (!st_data)
+ return -ENODEV;
+
+ spin_lock_irq(&mcbsp->lock);
+ st_data->enabled = 1;
+ omap_mcbsp_st_start(mcbsp);
+ spin_unlock_irq(&mcbsp->lock);
+
+ return 0;
+}
+
+static int omap_mcbsp_st_disable(struct omap_mcbsp *mcbsp)
+{
+ struct omap_mcbsp_st_data *st_data = mcbsp->st_data;
+ int ret = 0;
+
+ if (!st_data)
+ return -ENODEV;
+
+ spin_lock_irq(&mcbsp->lock);
+ omap_mcbsp_st_stop(mcbsp);
+ st_data->enabled = 0;
+ spin_unlock_irq(&mcbsp->lock);
+
+ return ret;
+}
+
+static int omap_mcbsp_st_is_enabled(struct omap_mcbsp *mcbsp)
+{
+ struct omap_mcbsp_st_data *st_data = mcbsp->st_data;
+
+ if (!st_data)
+ return -ENODEV;
+
+ return st_data->enabled;
+}
+
+static ssize_t st_taps_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct omap_mcbsp *mcbsp = dev_get_drvdata(dev);
+ struct omap_mcbsp_st_data *st_data = mcbsp->st_data;
+ ssize_t status = 0;
+ int i;
+
+ spin_lock_irq(&mcbsp->lock);
+ for (i = 0; i < st_data->nr_taps; i++)
+ status += sprintf(&buf[status], (i ? ", %d" : "%d"),
+ st_data->taps[i]);
+ if (i)
+ status += sprintf(&buf[status], "\n");
+ spin_unlock_irq(&mcbsp->lock);
+
+ return status;
+}
+
+static ssize_t st_taps_store(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t size)
+{
+ struct omap_mcbsp *mcbsp = dev_get_drvdata(dev);
+ struct omap_mcbsp_st_data *st_data = mcbsp->st_data;
+ int val, tmp, status, i = 0;
+
+ spin_lock_irq(&mcbsp->lock);
+ memset(st_data->taps, 0, sizeof(st_data->taps));
+ st_data->nr_taps = 0;
+
+ do {
+ status = sscanf(buf, "%d%n", &val, &tmp);
+ if (status < 0 || status == 0) {
+ size = -EINVAL;
+ goto out;
+ }
+ if (val < -32768 || val > 32767) {
+ size = -EINVAL;
+ goto out;
+ }
+ st_data->taps[i++] = val;
+ buf += tmp;
+ if (*buf != ',')
+ break;
+ buf++;
+ } while (1);
+
+ st_data->nr_taps = i;
+
+out:
+ spin_unlock_irq(&mcbsp->lock);
+
+ return size;
+}
+
+static DEVICE_ATTR_RW(st_taps);
+
+static const struct attribute *sidetone_attrs[] = {
+ &dev_attr_st_taps.attr,
+ NULL,
+};
+
+static const struct attribute_group sidetone_attr_group = {
+ .attrs = (struct attribute **)sidetone_attrs,
+};
+
+int omap_mcbsp_st_start(struct omap_mcbsp *mcbsp)
+{
+ struct omap_mcbsp_st_data *st_data = mcbsp->st_data;
+
+ if (st_data->enabled && !st_data->running) {
+ omap_mcbsp_st_fir_write(mcbsp, st_data->taps);
+ omap_mcbsp_st_chgain(mcbsp);
+
+ if (!mcbsp->free) {
+ omap_mcbsp_st_on(mcbsp);
+ st_data->running = 1;
+ }
+ }
+
+ return 0;
+}
+
+int omap_mcbsp_st_stop(struct omap_mcbsp *mcbsp)
+{
+ struct omap_mcbsp_st_data *st_data = mcbsp->st_data;
+
+ if (st_data->running) {
+ if (!mcbsp->free) {
+ omap_mcbsp_st_off(mcbsp);
+ st_data->running = 0;
+ }
+ }
+
+ return 0;
+}
+
+int omap_mcbsp_st_init(struct platform_device *pdev)
+{
+ struct omap_mcbsp *mcbsp = platform_get_drvdata(pdev);
+ struct omap_mcbsp_st_data *st_data;
+ struct resource *res;
+ int ret;
+
+ res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "sidetone");
+ if (!res)
+ return 0;
+
+ st_data = devm_kzalloc(mcbsp->dev, sizeof(*mcbsp->st_data), GFP_KERNEL);
+ if (!st_data)
+ return -ENOMEM;
+
+ st_data->mcbsp_iclk = clk_get(mcbsp->dev, "ick");
+ if (IS_ERR(st_data->mcbsp_iclk)) {
+ dev_warn(mcbsp->dev,
+ "Failed to get ick, sidetone might be broken\n");
+ st_data->mcbsp_iclk = NULL;
+ }
+
+ st_data->io_base_st = devm_ioremap(mcbsp->dev, res->start,
+ resource_size(res));
+ if (!st_data->io_base_st)
+ return -ENOMEM;
+
+ ret = sysfs_create_group(&mcbsp->dev->kobj, &sidetone_attr_group);
+ if (ret)
+ return ret;
+
+ mcbsp->st_data = st_data;
+
+ return 0;
+}
+
+void omap_mcbsp_st_cleanup(struct platform_device *pdev)
+{
+ struct omap_mcbsp *mcbsp = platform_get_drvdata(pdev);
+
+ if (mcbsp->st_data) {
+ sysfs_remove_group(&mcbsp->dev->kobj, &sidetone_attr_group);
+ clk_put(mcbsp->st_data->mcbsp_iclk);
+ }
+}
+
+static int omap_mcbsp_st_info_volsw(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_info *uinfo)
+{
+ struct soc_mixer_control *mc =
+ (struct soc_mixer_control *)kcontrol->private_value;
+ int max = mc->max;
+ int min = mc->min;
+
+ uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
+ uinfo->count = 1;
+ uinfo->value.integer.min = min;
+ uinfo->value.integer.max = max;
+ return 0;
+}
+
+#define OMAP_MCBSP_ST_CHANNEL_VOLUME(channel) \
+static int \
+omap_mcbsp_set_st_ch##channel##_volume(struct snd_kcontrol *kc, \
+ struct snd_ctl_elem_value *uc) \
+{ \
+ struct snd_soc_dai *cpu_dai = snd_kcontrol_chip(kc); \
+ struct omap_mcbsp *mcbsp = snd_soc_dai_get_drvdata(cpu_dai); \
+ struct soc_mixer_control *mc = \
+ (struct soc_mixer_control *)kc->private_value; \
+ int max = mc->max; \
+ int min = mc->min; \
+ int val = uc->value.integer.value[0]; \
+ \
+ if (val < min || val > max) \
+ return -EINVAL; \
+ \
+ /* OMAP McBSP implementation uses index values 0..4 */ \
+ return omap_mcbsp_st_set_chgain(mcbsp, channel, val); \
+} \
+ \
+static int \
+omap_mcbsp_get_st_ch##channel##_volume(struct snd_kcontrol *kc, \
+ struct snd_ctl_elem_value *uc) \
+{ \
+ struct snd_soc_dai *cpu_dai = snd_kcontrol_chip(kc); \
+ struct omap_mcbsp *mcbsp = snd_soc_dai_get_drvdata(cpu_dai); \
+ s16 chgain; \
+ \
+ if (omap_mcbsp_st_get_chgain(mcbsp, channel, &chgain)) \
+ return -EAGAIN; \
+ \
+ uc->value.integer.value[0] = chgain; \
+ return 0; \
+}
+
+OMAP_MCBSP_ST_CHANNEL_VOLUME(0)
+OMAP_MCBSP_ST_CHANNEL_VOLUME(1)
+
+static int omap_mcbsp_st_put_mode(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_dai *cpu_dai = snd_kcontrol_chip(kcontrol);
+ struct omap_mcbsp *mcbsp = snd_soc_dai_get_drvdata(cpu_dai);
+ u8 value = ucontrol->value.integer.value[0];
+
+ if (value == omap_mcbsp_st_is_enabled(mcbsp))
+ return 0;
+
+ if (value)
+ omap_mcbsp_st_enable(mcbsp);
+ else
+ omap_mcbsp_st_disable(mcbsp);
+
+ return 1;
+}
+
+static int omap_mcbsp_st_get_mode(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_dai *cpu_dai = snd_kcontrol_chip(kcontrol);
+ struct omap_mcbsp *mcbsp = snd_soc_dai_get_drvdata(cpu_dai);
+
+ ucontrol->value.integer.value[0] = omap_mcbsp_st_is_enabled(mcbsp);
+ return 0;
+}
+
+#define OMAP_MCBSP_SOC_SINGLE_S16_EXT(xname, xmin, xmax, \
+ xhandler_get, xhandler_put) \
+{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, \
+ .info = omap_mcbsp_st_info_volsw, \
+ .get = xhandler_get, .put = xhandler_put, \
+ .private_value = (unsigned long)&(struct soc_mixer_control) \
+ {.min = xmin, .max = xmax} }
+
+#define OMAP_MCBSP_ST_CONTROLS(port) \
+static const struct snd_kcontrol_new omap_mcbsp##port##_st_controls[] = { \
+SOC_SINGLE_EXT("McBSP" #port " Sidetone Switch", 1, 0, 1, 0, \
+ omap_mcbsp_st_get_mode, omap_mcbsp_st_put_mode), \
+OMAP_MCBSP_SOC_SINGLE_S16_EXT("McBSP" #port " Sidetone Channel 0 Volume", \
+ -32768, 32767, \
+ omap_mcbsp_get_st_ch0_volume, \
+ omap_mcbsp_set_st_ch0_volume), \
+OMAP_MCBSP_SOC_SINGLE_S16_EXT("McBSP" #port " Sidetone Channel 1 Volume", \
+ -32768, 32767, \
+ omap_mcbsp_get_st_ch1_volume, \
+ omap_mcbsp_set_st_ch1_volume), \
+}
+
+OMAP_MCBSP_ST_CONTROLS(2);
+OMAP_MCBSP_ST_CONTROLS(3);
+
+int omap_mcbsp_st_add_controls(struct snd_soc_pcm_runtime *rtd, int port_id)
+{
+ struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
+ struct omap_mcbsp *mcbsp = snd_soc_dai_get_drvdata(cpu_dai);
+
+ if (!mcbsp->st_data) {
+ dev_warn(mcbsp->dev, "No sidetone data for port\n");
+ return 0;
+ }
+
+ switch (port_id) {
+ case 2: /* McBSP 2 */
+ return snd_soc_add_dai_controls(cpu_dai,
+ omap_mcbsp2_st_controls,
+ ARRAY_SIZE(omap_mcbsp2_st_controls));
+ case 3: /* McBSP 3 */
+ return snd_soc_add_dai_controls(cpu_dai,
+ omap_mcbsp3_st_controls,
+ ARRAY_SIZE(omap_mcbsp3_st_controls));
+ default:
+ dev_err(mcbsp->dev, "Port %d not supported\n", port_id);
+ break;
+ }
+
+ return -EINVAL;
+}
+EXPORT_SYMBOL_GPL(omap_mcbsp_st_add_controls);
diff --git a/sound/soc/omap/omap-mcbsp.c b/sound/soc/omap/omap-mcbsp.c
index 69a6b8ad6d42..e48fad11a0cc 100644
--- a/sound/soc/omap/omap-mcbsp.c
+++ b/sound/soc/omap/omap-mcbsp.c
@@ -35,21 +35,12 @@
#include <sound/soc.h>
#include <sound/dmaengine_pcm.h>
-#include <linux/platform_data/asoc-ti-mcbsp.h>
-#include "mcbsp.h"
+#include "omap-mcbsp-priv.h"
#include "omap-mcbsp.h"
#include "sdma-pcm.h"
#define OMAP_MCBSP_RATES (SNDRV_PCM_RATE_8000_96000)
-#define OMAP_MCBSP_SOC_SINGLE_S16_EXT(xname, xmin, xmax, \
- xhandler_get, xhandler_put) \
-{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, \
- .info = omap_mcbsp_st_info_volsw, \
- .get = xhandler_get, .put = xhandler_put, \
- .private_value = (unsigned long) &(struct soc_mixer_control) \
- {.min = xmin, .max = xmax} }
-
enum {
OMAP_MCBSP_WORD_8 = 0,
OMAP_MCBSP_WORD_12,
@@ -59,6 +50,702 @@ enum {
OMAP_MCBSP_WORD_32,
};
+static void omap_mcbsp_dump_reg(struct omap_mcbsp *mcbsp)
+{
+ dev_dbg(mcbsp->dev, "**** McBSP%d regs ****\n", mcbsp->id);
+ dev_dbg(mcbsp->dev, "DRR2: 0x%04x\n", MCBSP_READ(mcbsp, DRR2));
+ dev_dbg(mcbsp->dev, "DRR1: 0x%04x\n", MCBSP_READ(mcbsp, DRR1));
+ dev_dbg(mcbsp->dev, "DXR2: 0x%04x\n", MCBSP_READ(mcbsp, DXR2));
+ dev_dbg(mcbsp->dev, "DXR1: 0x%04x\n", MCBSP_READ(mcbsp, DXR1));
+ dev_dbg(mcbsp->dev, "SPCR2: 0x%04x\n", MCBSP_READ(mcbsp, SPCR2));
+ dev_dbg(mcbsp->dev, "SPCR1: 0x%04x\n", MCBSP_READ(mcbsp, SPCR1));
+ dev_dbg(mcbsp->dev, "RCR2: 0x%04x\n", MCBSP_READ(mcbsp, RCR2));
+ dev_dbg(mcbsp->dev, "RCR1: 0x%04x\n", MCBSP_READ(mcbsp, RCR1));
+ dev_dbg(mcbsp->dev, "XCR2: 0x%04x\n", MCBSP_READ(mcbsp, XCR2));
+ dev_dbg(mcbsp->dev, "XCR1: 0x%04x\n", MCBSP_READ(mcbsp, XCR1));
+ dev_dbg(mcbsp->dev, "SRGR2: 0x%04x\n", MCBSP_READ(mcbsp, SRGR2));
+ dev_dbg(mcbsp->dev, "SRGR1: 0x%04x\n", MCBSP_READ(mcbsp, SRGR1));
+ dev_dbg(mcbsp->dev, "PCR0: 0x%04x\n", MCBSP_READ(mcbsp, PCR0));
+ dev_dbg(mcbsp->dev, "***********************\n");
+}
+
+static int omap2_mcbsp_set_clks_src(struct omap_mcbsp *mcbsp, u8 fck_src_id)
+{
+ struct clk *fck_src;
+ const char *src;
+ int r;
+
+ if (fck_src_id == MCBSP_CLKS_PAD_SRC)
+ src = "pad_fck";
+ else if (fck_src_id == MCBSP_CLKS_PRCM_SRC)
+ src = "prcm_fck";
+ else
+ return -EINVAL;
+
+ fck_src = clk_get(mcbsp->dev, src);
+ if (IS_ERR(fck_src)) {
+ dev_err(mcbsp->dev, "CLKS: could not clk_get() %s\n", src);
+ return -EINVAL;
+ }
+
+ pm_runtime_put_sync(mcbsp->dev);
+
+ r = clk_set_parent(mcbsp->fclk, fck_src);
+ if (r) {
+ dev_err(mcbsp->dev, "CLKS: could not clk_set_parent() to %s\n",
+ src);
+ clk_put(fck_src);
+ return r;
+ }
+
+ pm_runtime_get_sync(mcbsp->dev);
+
+ clk_put(fck_src);
+
+ return 0;
+}
+
+static irqreturn_t omap_mcbsp_irq_handler(int irq, void *data)
+{
+ struct omap_mcbsp *mcbsp = data;
+ u16 irqst;
+
+ irqst = MCBSP_READ(mcbsp, IRQST);
+ dev_dbg(mcbsp->dev, "IRQ callback : 0x%x\n", irqst);
+
+ if (irqst & RSYNCERREN)
+ dev_err(mcbsp->dev, "RX Frame Sync Error!\n");
+ if (irqst & RFSREN)
+ dev_dbg(mcbsp->dev, "RX Frame Sync\n");
+ if (irqst & REOFEN)
+ dev_dbg(mcbsp->dev, "RX End Of Frame\n");
+ if (irqst & RRDYEN)
+ dev_dbg(mcbsp->dev, "RX Buffer Threshold Reached\n");
+ if (irqst & RUNDFLEN)
+ dev_err(mcbsp->dev, "RX Buffer Underflow!\n");
+ if (irqst & ROVFLEN)
+ dev_err(mcbsp->dev, "RX Buffer Overflow!\n");
+
+ if (irqst & XSYNCERREN)
+ dev_err(mcbsp->dev, "TX Frame Sync Error!\n");
+ if (irqst & XFSXEN)
+ dev_dbg(mcbsp->dev, "TX Frame Sync\n");
+ if (irqst & XEOFEN)
+ dev_dbg(mcbsp->dev, "TX End Of Frame\n");
+ if (irqst & XRDYEN)
+ dev_dbg(mcbsp->dev, "TX Buffer threshold Reached\n");
+ if (irqst & XUNDFLEN)
+ dev_err(mcbsp->dev, "TX Buffer Underflow!\n");
+ if (irqst & XOVFLEN)
+ dev_err(mcbsp->dev, "TX Buffer Overflow!\n");
+ if (irqst & XEMPTYEOFEN)
+ dev_dbg(mcbsp->dev, "TX Buffer empty at end of frame\n");
+
+ MCBSP_WRITE(mcbsp, IRQST, irqst);
+
+ return IRQ_HANDLED;
+}
+
+static irqreturn_t omap_mcbsp_tx_irq_handler(int irq, void *data)
+{
+ struct omap_mcbsp *mcbsp = data;
+ u16 irqst_spcr2;
+
+ irqst_spcr2 = MCBSP_READ(mcbsp, SPCR2);
+ dev_dbg(mcbsp->dev, "TX IRQ callback : 0x%x\n", irqst_spcr2);
+
+ if (irqst_spcr2 & XSYNC_ERR) {
+ dev_err(mcbsp->dev, "TX Frame Sync Error! : 0x%x\n",
+ irqst_spcr2);
+ /* Writing zero to XSYNC_ERR clears the IRQ */
+ MCBSP_WRITE(mcbsp, SPCR2, MCBSP_READ_CACHE(mcbsp, SPCR2));
+ }
+
+ return IRQ_HANDLED;
+}
+
+static irqreturn_t omap_mcbsp_rx_irq_handler(int irq, void *data)
+{
+ struct omap_mcbsp *mcbsp = data;
+ u16 irqst_spcr1;
+
+ irqst_spcr1 = MCBSP_READ(mcbsp, SPCR1);
+ dev_dbg(mcbsp->dev, "RX IRQ callback : 0x%x\n", irqst_spcr1);
+
+ if (irqst_spcr1 & RSYNC_ERR) {
+ dev_err(mcbsp->dev, "RX Frame Sync Error! : 0x%x\n",
+ irqst_spcr1);
+ /* Writing zero to RSYNC_ERR clears the IRQ */
+ MCBSP_WRITE(mcbsp, SPCR1, MCBSP_READ_CACHE(mcbsp, SPCR1));
+ }
+
+ return IRQ_HANDLED;
+}
+
+/*
+ * omap_mcbsp_config simply write a config to the
+ * appropriate McBSP.
+ * You either call this function or set the McBSP registers
+ * by yourself before calling omap_mcbsp_start().
+ */
+static void omap_mcbsp_config(struct omap_mcbsp *mcbsp,
+ const struct omap_mcbsp_reg_cfg *config)
+{
+ dev_dbg(mcbsp->dev, "Configuring McBSP%d phys_base: 0x%08lx\n",
+ mcbsp->id, mcbsp->phys_base);
+
+ /* We write the given config */
+ MCBSP_WRITE(mcbsp, SPCR2, config->spcr2);
+ MCBSP_WRITE(mcbsp, SPCR1, config->spcr1);
+ MCBSP_WRITE(mcbsp, RCR2, config->rcr2);
+ MCBSP_WRITE(mcbsp, RCR1, config->rcr1);
+ MCBSP_WRITE(mcbsp, XCR2, config->xcr2);
+ MCBSP_WRITE(mcbsp, XCR1, config->xcr1);
+ MCBSP_WRITE(mcbsp, SRGR2, config->srgr2);
+ MCBSP_WRITE(mcbsp, SRGR1, config->srgr1);
+ MCBSP_WRITE(mcbsp, MCR2, config->mcr2);
+ MCBSP_WRITE(mcbsp, MCR1, config->mcr1);
+ MCBSP_WRITE(mcbsp, PCR0, config->pcr0);
+ if (mcbsp->pdata->has_ccr) {
+ MCBSP_WRITE(mcbsp, XCCR, config->xccr);
+ MCBSP_WRITE(mcbsp, RCCR, config->rccr);
+ }
+ /* Enable wakeup behavior */
+ if (mcbsp->pdata->has_wakeup)
+ MCBSP_WRITE(mcbsp, WAKEUPEN, XRDYEN | RRDYEN);
+
+ /* Enable TX/RX sync error interrupts by default */
+ if (mcbsp->irq)
+ MCBSP_WRITE(mcbsp, IRQEN, RSYNCERREN | XSYNCERREN |
+ RUNDFLEN | ROVFLEN | XUNDFLEN | XOVFLEN);
+}
+
+/**
+ * omap_mcbsp_dma_reg_params - returns the address of mcbsp data register
+ * @mcbsp: omap_mcbsp struct for the McBSP instance
+ * @stream: Stream direction (playback/capture)
+ *
+ * Returns the address of mcbsp data transmit register or data receive register
+ * to be used by DMA for transferring/receiving data
+ */
+static int omap_mcbsp_dma_reg_params(struct omap_mcbsp *mcbsp,
+ unsigned int stream)
+{
+ int data_reg;
+
+ if (stream == SNDRV_PCM_STREAM_PLAYBACK) {
+ if (mcbsp->pdata->reg_size == 2)
+ data_reg = OMAP_MCBSP_REG_DXR1;
+ else
+ data_reg = OMAP_MCBSP_REG_DXR;
+ } else {
+ if (mcbsp->pdata->reg_size == 2)
+ data_reg = OMAP_MCBSP_REG_DRR1;
+ else
+ data_reg = OMAP_MCBSP_REG_DRR;
+ }
+
+ return mcbsp->phys_dma_base + data_reg * mcbsp->pdata->reg_step;
+}
+
+/*
+ * omap_mcbsp_set_rx_threshold configures the transmit threshold in words.
+ * The threshold parameter is 1 based, and it is converted (threshold - 1)
+ * for the THRSH2 register.
+ */
+static void omap_mcbsp_set_tx_threshold(struct omap_mcbsp *mcbsp, u16 threshold)
+{
+ if (threshold && threshold <= mcbsp->max_tx_thres)
+ MCBSP_WRITE(mcbsp, THRSH2, threshold - 1);
+}
+
+/*
+ * omap_mcbsp_set_rx_threshold configures the receive threshold in words.
+ * The threshold parameter is 1 based, and it is converted (threshold - 1)
+ * for the THRSH1 register.
+ */
+static void omap_mcbsp_set_rx_threshold(struct omap_mcbsp *mcbsp, u16 threshold)
+{
+ if (threshold && threshold <= mcbsp->max_rx_thres)
+ MCBSP_WRITE(mcbsp, THRSH1, threshold - 1);
+}
+
+/*
+ * omap_mcbsp_get_tx_delay returns the number of used slots in the McBSP FIFO
+ */
+static u16 omap_mcbsp_get_tx_delay(struct omap_mcbsp *mcbsp)
+{
+ u16 buffstat;
+
+ /* Returns the number of free locations in the buffer */
+ buffstat = MCBSP_READ(mcbsp, XBUFFSTAT);
+
+ /* Number of slots are different in McBSP ports */
+ return mcbsp->pdata->buffer_size - buffstat;
+}
+
+/*
+ * omap_mcbsp_get_rx_delay returns the number of free slots in the McBSP FIFO
+ * to reach the threshold value (when the DMA will be triggered to read it)
+ */
+static u16 omap_mcbsp_get_rx_delay(struct omap_mcbsp *mcbsp)
+{
+ u16 buffstat, threshold;
+
+ /* Returns the number of used locations in the buffer */
+ buffstat = MCBSP_READ(mcbsp, RBUFFSTAT);
+ /* RX threshold */
+ threshold = MCBSP_READ(mcbsp, THRSH1);
+
+ /* Return the number of location till we reach the threshold limit */
+ if (threshold <= buffstat)
+ return 0;
+ else
+ return threshold - buffstat;
+}
+
+static int omap_mcbsp_request(struct omap_mcbsp *mcbsp)
+{
+ void *reg_cache;
+ int err;
+
+ reg_cache = kzalloc(mcbsp->reg_cache_size, GFP_KERNEL);
+ if (!reg_cache)
+ return -ENOMEM;
+
+ spin_lock(&mcbsp->lock);
+ if (!mcbsp->free) {
+ dev_err(mcbsp->dev, "McBSP%d is currently in use\n", mcbsp->id);
+ err = -EBUSY;
+ goto err_kfree;
+ }
+
+ mcbsp->free = false;
+ mcbsp->reg_cache = reg_cache;
+ spin_unlock(&mcbsp->lock);
+
+ if (mcbsp->pdata && mcbsp->pdata->ops && mcbsp->pdata->ops->request)
+ mcbsp->pdata->ops->request(mcbsp->id - 1);
+
+ /*
+ * Make sure that transmitter, receiver and sample-rate generator are
+ * not running before activating IRQs.
+ */
+ MCBSP_WRITE(mcbsp, SPCR1, 0);
+ MCBSP_WRITE(mcbsp, SPCR2, 0);
+
+ if (mcbsp->irq) {
+ err = request_irq(mcbsp->irq, omap_mcbsp_irq_handler, 0,
+ "McBSP", (void *)mcbsp);
+ if (err != 0) {
+ dev_err(mcbsp->dev, "Unable to request IRQ\n");
+ goto err_clk_disable;
+ }
+ } else {
+ err = request_irq(mcbsp->tx_irq, omap_mcbsp_tx_irq_handler, 0,
+ "McBSP TX", (void *)mcbsp);
+ if (err != 0) {
+ dev_err(mcbsp->dev, "Unable to request TX IRQ\n");
+ goto err_clk_disable;
+ }
+
+ err = request_irq(mcbsp->rx_irq, omap_mcbsp_rx_irq_handler, 0,
+ "McBSP RX", (void *)mcbsp);
+ if (err != 0) {
+ dev_err(mcbsp->dev, "Unable to request RX IRQ\n");
+ goto err_free_irq;
+ }
+ }
+
+ return 0;
+err_free_irq:
+ free_irq(mcbsp->tx_irq, (void *)mcbsp);
+err_clk_disable:
+ if (mcbsp->pdata && mcbsp->pdata->ops && mcbsp->pdata->ops->free)
+ mcbsp->pdata->ops->free(mcbsp->id - 1);
+
+ /* Disable wakeup behavior */
+ if (mcbsp->pdata->has_wakeup)
+ MCBSP_WRITE(mcbsp, WAKEUPEN, 0);
+
+ spin_lock(&mcbsp->lock);
+ mcbsp->free = true;
+ mcbsp->reg_cache = NULL;
+err_kfree:
+ spin_unlock(&mcbsp->lock);
+ kfree(reg_cache);
+
+ return err;
+}
+
+static void omap_mcbsp_free(struct omap_mcbsp *mcbsp)
+{
+ void *reg_cache;
+
+ if (mcbsp->pdata && mcbsp->pdata->ops && mcbsp->pdata->ops->free)
+ mcbsp->pdata->ops->free(mcbsp->id - 1);
+
+ /* Disable wakeup behavior */
+ if (mcbsp->pdata->has_wakeup)
+ MCBSP_WRITE(mcbsp, WAKEUPEN, 0);
+
+ /* Disable interrupt requests */
+ if (mcbsp->irq)
+ MCBSP_WRITE(mcbsp, IRQEN, 0);
+
+ if (mcbsp->irq) {
+ free_irq(mcbsp->irq, (void *)mcbsp);
+ } else {
+ free_irq(mcbsp->rx_irq, (void *)mcbsp);
+ free_irq(mcbsp->tx_irq, (void *)mcbsp);
+ }
+
+ reg_cache = mcbsp->reg_cache;
+
+ /*
+ * Select CLKS source from internal source unconditionally before
+ * marking the McBSP port as free.
+ * If the external clock source via MCBSP_CLKS pin has been selected the
+ * system will refuse to enter idle if the CLKS pin source is not reset
+ * back to internal source.
+ */
+ if (!mcbsp_omap1())
+ omap2_mcbsp_set_clks_src(mcbsp, MCBSP_CLKS_PRCM_SRC);
+
+ spin_lock(&mcbsp->lock);
+ if (mcbsp->free)
+ dev_err(mcbsp->dev, "McBSP%d was not reserved\n", mcbsp->id);
+ else
+ mcbsp->free = true;
+ mcbsp->reg_cache = NULL;
+ spin_unlock(&mcbsp->lock);
+
+ kfree(reg_cache);
+}
+
+/*
+ * Here we start the McBSP, by enabling transmitter, receiver or both.
+ * If no transmitter or receiver is active prior calling, then sample-rate
+ * generator and frame sync are started.
+ */
+static void omap_mcbsp_start(struct omap_mcbsp *mcbsp, int stream)
+{
+ int tx = (stream == SNDRV_PCM_STREAM_PLAYBACK);
+ int rx = !tx;
+ int enable_srg = 0;
+ u16 w;
+
+ if (mcbsp->st_data)
+ omap_mcbsp_st_start(mcbsp);
+
+ /* Only enable SRG, if McBSP is master */
+ w = MCBSP_READ_CACHE(mcbsp, PCR0);
+ if (w & (FSXM | FSRM | CLKXM | CLKRM))
+ enable_srg = !((MCBSP_READ_CACHE(mcbsp, SPCR2) |
+ MCBSP_READ_CACHE(mcbsp, SPCR1)) & 1);
+
+ if (enable_srg) {
+ /* Start the sample generator */
+ w = MCBSP_READ_CACHE(mcbsp, SPCR2);
+ MCBSP_WRITE(mcbsp, SPCR2, w | (1 << 6));
+ }
+
+ /* Enable transmitter and receiver */
+ tx &= 1;
+ w = MCBSP_READ_CACHE(mcbsp, SPCR2);
+ MCBSP_WRITE(mcbsp, SPCR2, w | tx);
+
+ rx &= 1;
+ w = MCBSP_READ_CACHE(mcbsp, SPCR1);
+ MCBSP_WRITE(mcbsp, SPCR1, w | rx);
+
+ /*
+ * Worst case: CLKSRG*2 = 8000khz: (1/8000) * 2 * 2 usec
+ * REVISIT: 100us may give enough time for two CLKSRG, however
+ * due to some unknown PM related, clock gating etc. reason it
+ * is now at 500us.
+ */
+ udelay(500);
+
+ if (enable_srg) {
+ /* Start frame sync */
+ w = MCBSP_READ_CACHE(mcbsp, SPCR2);
+ MCBSP_WRITE(mcbsp, SPCR2, w | (1 << 7));
+ }
+
+ if (mcbsp->pdata->has_ccr) {
+ /* Release the transmitter and receiver */
+ w = MCBSP_READ_CACHE(mcbsp, XCCR);
+ w &= ~(tx ? XDISABLE : 0);
+ MCBSP_WRITE(mcbsp, XCCR, w);
+ w = MCBSP_READ_CACHE(mcbsp, RCCR);
+ w &= ~(rx ? RDISABLE : 0);
+ MCBSP_WRITE(mcbsp, RCCR, w);
+ }
+
+ /* Dump McBSP Regs */
+ omap_mcbsp_dump_reg(mcbsp);
+}
+
+static void omap_mcbsp_stop(struct omap_mcbsp *mcbsp, int stream)
+{
+ int tx = (stream == SNDRV_PCM_STREAM_PLAYBACK);
+ int rx = !tx;
+ int idle;
+ u16 w;
+
+ /* Reset transmitter */
+ tx &= 1;
+ if (mcbsp->pdata->has_ccr) {
+ w = MCBSP_READ_CACHE(mcbsp, XCCR);
+ w |= (tx ? XDISABLE : 0);
+ MCBSP_WRITE(mcbsp, XCCR, w);
+ }
+ w = MCBSP_READ_CACHE(mcbsp, SPCR2);
+ MCBSP_WRITE(mcbsp, SPCR2, w & ~tx);
+
+ /* Reset receiver */
+ rx &= 1;
+ if (mcbsp->pdata->has_ccr) {
+ w = MCBSP_READ_CACHE(mcbsp, RCCR);
+ w |= (rx ? RDISABLE : 0);
+ MCBSP_WRITE(mcbsp, RCCR, w);
+ }
+ w = MCBSP_READ_CACHE(mcbsp, SPCR1);
+ MCBSP_WRITE(mcbsp, SPCR1, w & ~rx);
+
+ idle = !((MCBSP_READ_CACHE(mcbsp, SPCR2) |
+ MCBSP_READ_CACHE(mcbsp, SPCR1)) & 1);
+
+ if (idle) {
+ /* Reset the sample rate generator */
+ w = MCBSP_READ_CACHE(mcbsp, SPCR2);
+ MCBSP_WRITE(mcbsp, SPCR2, w & ~(1 << 6));
+ }
+
+ if (mcbsp->st_data)
+ omap_mcbsp_st_stop(mcbsp);
+}
+
+#define max_thres(m) (mcbsp->pdata->buffer_size)
+#define valid_threshold(m, val) ((val) <= max_thres(m))
+#define THRESHOLD_PROP_BUILDER(prop) \
+static ssize_t prop##_show(struct device *dev, \
+ struct device_attribute *attr, char *buf) \
+{ \
+ struct omap_mcbsp *mcbsp = dev_get_drvdata(dev); \
+ \
+ return sprintf(buf, "%u\n", mcbsp->prop); \
+} \
+ \
+static ssize_t prop##_store(struct device *dev, \
+ struct device_attribute *attr, \
+ const char *buf, size_t size) \
+{ \
+ struct omap_mcbsp *mcbsp = dev_get_drvdata(dev); \
+ unsigned long val; \
+ int status; \
+ \
+ status = kstrtoul(buf, 0, &val); \
+ if (status) \
+ return status; \
+ \
+ if (!valid_threshold(mcbsp, val)) \
+ return -EDOM; \
+ \
+ mcbsp->prop = val; \
+ return size; \
+} \
+ \
+static DEVICE_ATTR(prop, 0644, prop##_show, prop##_store)
+
+THRESHOLD_PROP_BUILDER(max_tx_thres);
+THRESHOLD_PROP_BUILDER(max_rx_thres);
+
+static const char * const dma_op_modes[] = {
+ "element", "threshold",
+};
+
+static ssize_t dma_op_mode_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct omap_mcbsp *mcbsp = dev_get_drvdata(dev);
+ int dma_op_mode, i = 0;
+ ssize_t len = 0;
+ const char * const *s;
+
+ dma_op_mode = mcbsp->dma_op_mode;
+
+ for (s = &dma_op_modes[i]; i < ARRAY_SIZE(dma_op_modes); s++, i++) {
+ if (dma_op_mode == i)
+ len += sprintf(buf + len, "[%s] ", *s);
+ else
+ len += sprintf(buf + len, "%s ", *s);
+ }
+ len += sprintf(buf + len, "\n");
+
+ return len;
+}
+
+static ssize_t dma_op_mode_store(struct device *dev,
+ struct device_attribute *attr, const char *buf,
+ size_t size)
+{
+ struct omap_mcbsp *mcbsp = dev_get_drvdata(dev);
+ int i;
+
+ i = sysfs_match_string(dma_op_modes, buf);
+ if (i < 0)
+ return i;
+
+ spin_lock_irq(&mcbsp->lock);
+ if (!mcbsp->free) {
+ size = -EBUSY;
+ goto unlock;
+ }
+ mcbsp->dma_op_mode = i;
+
+unlock:
+ spin_unlock_irq(&mcbsp->lock);
+
+ return size;
+}
+
+static DEVICE_ATTR_RW(dma_op_mode);
+
+static const struct attribute *additional_attrs[] = {
+ &dev_attr_max_tx_thres.attr,
+ &dev_attr_max_rx_thres.attr,
+ &dev_attr_dma_op_mode.attr,
+ NULL,
+};
+
+static const struct attribute_group additional_attr_group = {
+ .attrs = (struct attribute **)additional_attrs,
+};
+
+/*
+ * McBSP1 and McBSP3 are directly mapped on 1610 and 1510.
+ * 730 has only 2 McBSP, and both of them are MPU peripherals.
+ */
+static int omap_mcbsp_init(struct platform_device *pdev)
+{
+ struct omap_mcbsp *mcbsp = platform_get_drvdata(pdev);
+ struct resource *res;
+ int ret = 0;
+
+ spin_lock_init(&mcbsp->lock);
+ mcbsp->free = true;
+
+ res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "mpu");
+ if (!res)
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+
+ mcbsp->io_base = devm_ioremap_resource(&pdev->dev, res);
+ if (IS_ERR(mcbsp->io_base))
+ return PTR_ERR(mcbsp->io_base);
+
+ mcbsp->phys_base = res->start;
+ mcbsp->reg_cache_size = resource_size(res);
+
+ res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "dma");
+ if (!res)
+ mcbsp->phys_dma_base = mcbsp->phys_base;
+ else
+ mcbsp->phys_dma_base = res->start;
+
+ /*
+ * OMAP1, 2 uses two interrupt lines: TX, RX
+ * OMAP2430, OMAP3 SoC have combined IRQ line as well.
+ * OMAP4 and newer SoC only have the combined IRQ line.
+ * Use the combined IRQ if available since it gives better debugging
+ * possibilities.
+ */
+ mcbsp->irq = platform_get_irq_byname(pdev, "common");
+ if (mcbsp->irq == -ENXIO) {
+ mcbsp->tx_irq = platform_get_irq_byname(pdev, "tx");
+
+ if (mcbsp->tx_irq == -ENXIO) {
+ mcbsp->irq = platform_get_irq(pdev, 0);
+ mcbsp->tx_irq = 0;
+ } else {
+ mcbsp->rx_irq = platform_get_irq_byname(pdev, "rx");
+ mcbsp->irq = 0;
+ }
+ }
+
+ if (!pdev->dev.of_node) {
+ res = platform_get_resource_byname(pdev, IORESOURCE_DMA, "tx");
+ if (!res) {
+ dev_err(&pdev->dev, "invalid tx DMA channel\n");
+ return -ENODEV;
+ }
+ mcbsp->dma_req[0] = res->start;
+ mcbsp->dma_data[0].filter_data = &mcbsp->dma_req[0];
+
+ res = platform_get_resource_byname(pdev, IORESOURCE_DMA, "rx");
+ if (!res) {
+ dev_err(&pdev->dev, "invalid rx DMA channel\n");
+ return -ENODEV;
+ }
+ mcbsp->dma_req[1] = res->start;
+ mcbsp->dma_data[1].filter_data = &mcbsp->dma_req[1];
+ } else {
+ mcbsp->dma_data[0].filter_data = "tx";
+ mcbsp->dma_data[1].filter_data = "rx";
+ }
+
+ mcbsp->dma_data[0].addr = omap_mcbsp_dma_reg_params(mcbsp,
+ SNDRV_PCM_STREAM_PLAYBACK);
+ mcbsp->dma_data[1].addr = omap_mcbsp_dma_reg_params(mcbsp,
+ SNDRV_PCM_STREAM_CAPTURE);
+
+ mcbsp->fclk = clk_get(&pdev->dev, "fck");
+ if (IS_ERR(mcbsp->fclk)) {
+ ret = PTR_ERR(mcbsp->fclk);
+ dev_err(mcbsp->dev, "unable to get fck: %d\n", ret);
+ return ret;
+ }
+
+ mcbsp->dma_op_mode = MCBSP_DMA_MODE_ELEMENT;
+ if (mcbsp->pdata->buffer_size) {
+ /*
+ * Initially configure the maximum thresholds to a safe value.
+ * The McBSP FIFO usage with these values should not go under
+ * 16 locations.
+ * If the whole FIFO without safety buffer is used, than there
+ * is a possibility that the DMA will be not able to push the
+ * new data on time, causing channel shifts in runtime.
+ */
+ mcbsp->max_tx_thres = max_thres(mcbsp) - 0x10;
+ mcbsp->max_rx_thres = max_thres(mcbsp) - 0x10;
+
+ ret = sysfs_create_group(&mcbsp->dev->kobj,
+ &additional_attr_group);
+ if (ret) {
+ dev_err(mcbsp->dev,
+ "Unable to create additional controls\n");
+ goto err_thres;
+ }
+ } else {
+ mcbsp->max_tx_thres = -EINVAL;
+ mcbsp->max_rx_thres = -EINVAL;
+ }
+
+ ret = omap_mcbsp_st_init(pdev);
+ if (ret)
+ goto err_st;
+
+ return 0;
+
+err_st:
+ if (mcbsp->pdata->buffer_size)
+ sysfs_remove_group(&mcbsp->dev->kobj, &additional_attr_group);
+err_thres:
+ clk_put(mcbsp->fclk);
+ return ret;
+}
+
/*
* Stream DMA parameters. DMA request line and port address are set runtime
* since they are different between OMAP1 and later OMAPs
@@ -656,132 +1343,6 @@ static const struct snd_soc_component_driver omap_mcbsp_component = {
.name = "omap-mcbsp",
};
-static int omap_mcbsp_st_info_volsw(struct snd_kcontrol *kcontrol,
- struct snd_ctl_elem_info *uinfo)
-{
- struct soc_mixer_control *mc =
- (struct soc_mixer_control *)kcontrol->private_value;
- int max = mc->max;
- int min = mc->min;
-
- uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
- uinfo->count = 1;
- uinfo->value.integer.min = min;
- uinfo->value.integer.max = max;
- return 0;
-}
-
-#define OMAP_MCBSP_ST_CHANNEL_VOLUME(channel) \
-static int \
-omap_mcbsp_set_st_ch##channel##_volume(struct snd_kcontrol *kc, \
- struct snd_ctl_elem_value *uc) \
-{ \
- struct snd_soc_dai *cpu_dai = snd_kcontrol_chip(kc); \
- struct omap_mcbsp *mcbsp = snd_soc_dai_get_drvdata(cpu_dai); \
- struct soc_mixer_control *mc = \
- (struct soc_mixer_control *)kc->private_value; \
- int max = mc->max; \
- int min = mc->min; \
- int val = uc->value.integer.value[0]; \
- \
- if (val < min || val > max) \
- return -EINVAL; \
- \
- /* OMAP McBSP implementation uses index values 0..4 */ \
- return omap_st_set_chgain(mcbsp, channel, val); \
-} \
- \
-static int \
-omap_mcbsp_get_st_ch##channel##_volume(struct snd_kcontrol *kc, \
- struct snd_ctl_elem_value *uc) \
-{ \
- struct snd_soc_dai *cpu_dai = snd_kcontrol_chip(kc); \
- struct omap_mcbsp *mcbsp = snd_soc_dai_get_drvdata(cpu_dai); \
- s16 chgain; \
- \
- if (omap_st_get_chgain(mcbsp, channel, &chgain)) \
- return -EAGAIN; \
- \
- uc->value.integer.value[0] = chgain; \
- return 0; \
-}
-
-OMAP_MCBSP_ST_CHANNEL_VOLUME(0)
-OMAP_MCBSP_ST_CHANNEL_VOLUME(1)
-
-static int omap_mcbsp_st_put_mode(struct snd_kcontrol *kcontrol,
- struct snd_ctl_elem_value *ucontrol)
-{
- struct snd_soc_dai *cpu_dai = snd_kcontrol_chip(kcontrol);
- struct omap_mcbsp *mcbsp = snd_soc_dai_get_drvdata(cpu_dai);
- u8 value = ucontrol->value.integer.value[0];
-
- if (value == omap_st_is_enabled(mcbsp))
- return 0;
-
- if (value)
- omap_st_enable(mcbsp);
- else
- omap_st_disable(mcbsp);
-
- return 1;
-}
-
-static int omap_mcbsp_st_get_mode(struct snd_kcontrol *kcontrol,
- struct snd_ctl_elem_value *ucontrol)
-{
- struct snd_soc_dai *cpu_dai = snd_kcontrol_chip(kcontrol);
- struct omap_mcbsp *mcbsp = snd_soc_dai_get_drvdata(cpu_dai);
-
- ucontrol->value.integer.value[0] = omap_st_is_enabled(mcbsp);
- return 0;
-}
-
-#define OMAP_MCBSP_ST_CONTROLS(port) \
-static const struct snd_kcontrol_new omap_mcbsp##port##_st_controls[] = { \
-SOC_SINGLE_EXT("McBSP" #port " Sidetone Switch", 1, 0, 1, 0, \
- omap_mcbsp_st_get_mode, omap_mcbsp_st_put_mode), \
-OMAP_MCBSP_SOC_SINGLE_S16_EXT("McBSP" #port " Sidetone Channel 0 Volume", \
- -32768, 32767, \
- omap_mcbsp_get_st_ch0_volume, \
- omap_mcbsp_set_st_ch0_volume), \
-OMAP_MCBSP_SOC_SINGLE_S16_EXT("McBSP" #port " Sidetone Channel 1 Volume", \
- -32768, 32767, \
- omap_mcbsp_get_st_ch1_volume, \
- omap_mcbsp_set_st_ch1_volume), \
-}
-
-OMAP_MCBSP_ST_CONTROLS(2);
-OMAP_MCBSP_ST_CONTROLS(3);
-
-int omap_mcbsp_st_add_controls(struct snd_soc_pcm_runtime *rtd, int port_id)
-{
- struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
- struct omap_mcbsp *mcbsp = snd_soc_dai_get_drvdata(cpu_dai);
-
- if (!mcbsp->st_data) {
- dev_warn(mcbsp->dev, "No sidetone data for port\n");
- return 0;
- }
-
- switch (port_id) {
- case 2: /* McBSP 2 */
- return snd_soc_add_dai_controls(cpu_dai,
- omap_mcbsp2_st_controls,
- ARRAY_SIZE(omap_mcbsp2_st_controls));
- case 3: /* McBSP 3 */
- return snd_soc_add_dai_controls(cpu_dai,
- omap_mcbsp3_st_controls,
- ARRAY_SIZE(omap_mcbsp3_st_controls));
- default:
- dev_err(mcbsp->dev, "Port %d not supported\n", port_id);
- break;
- }
-
- return -EINVAL;
-}
-EXPORT_SYMBOL_GPL(omap_mcbsp_st_add_controls);
-
static struct omap_mcbsp_platform_data omap2420_pdata = {
.reg_step = 4,
.reg_size = 2,
@@ -893,7 +1454,10 @@ static int asoc_mcbsp_remove(struct platform_device *pdev)
if (pm_qos_request_active(&mcbsp->pm_qos_req))
pm_qos_remove_request(&mcbsp->pm_qos_req);
- omap_mcbsp_cleanup(mcbsp);
+ if (mcbsp->pdata->buffer_size)
+ sysfs_remove_group(&mcbsp->dev->kobj, &additional_attr_group);
+
+ omap_mcbsp_st_cleanup(pdev);
clk_put(mcbsp->fclk);
diff --git a/sound/soc/omap/omap-mcbsp.h b/sound/soc/omap/omap-mcbsp.h
index 2e3369c27be3..7911d24898c9 100644
--- a/sound/soc/omap/omap-mcbsp.h
+++ b/sound/soc/omap/omap-mcbsp.h
@@ -22,8 +22,10 @@
*
*/
-#ifndef __OMAP_I2S_H__
-#define __OMAP_I2S_H__
+#ifndef __OMAP_MCBSP_H__
+#define __OMAP_MCBSP_H__
+
+#include <sound/dmaengine_pcm.h>
/* Source clocks for McBSP sample rate generator */
enum omap_mcbsp_clksrg_clk {
@@ -41,4 +43,4 @@ enum omap_mcbsp_div {
int omap_mcbsp_st_add_controls(struct snd_soc_pcm_runtime *rtd, int port_id);
-#endif
+#endif /* __OMAP_MCBSP_H__ */
--
2.19.1
1
0
[alsa-devel] Applied "ASoC: omap-mcbsp: Remove redundant check for mcbsp->pdata" to the asoc tree
by Mark Brown 13 Nov '18
by Mark Brown 13 Nov '18
13 Nov '18
The patch
ASoC: omap-mcbsp: Remove redundant check for mcbsp->pdata
has been applied to the asoc tree at
https://git.kernel.org/pub/scm/linux/kernel/git/broonie/sound.git
All being well this means that it will be integrated into the linux-next
tree (usually sometime in the next 24 hours) and sent to Linus during
the next merge window (or sooner if it is a bug fix), however if
problems are discovered then the patch may be dropped or reverted.
You may get further e-mails resulting from automated or manual testing
and review of the tree, please engage with people reporting problems and
send followup patches addressing any issues that are reported if needed.
If any updates are required or you are submitting further changes they
should be sent as incremental updates against current git, existing
patches will not be replaced.
Please add any relevant lists and maintainers to the CCs when replying
to this mail.
Thanks,
Mark
>From 465d85b3976a15c9e0e205ff50be64efa11b7af3 Mon Sep 17 00:00:00 2001
From: Peter Ujfalusi <peter.ujfalusi(a)ti.com>
Date: Thu, 8 Nov 2018 09:29:59 +0200
Subject: [PATCH] ASoC: omap-mcbsp: Remove redundant check for mcbsp->pdata
The driver will not probe if the pdata is not provided or created.
Signed-off-by: Peter Ujfalusi <peter.ujfalusi(a)ti.com>
Acked-by: Jarkko Nikula <jarkko.nikula(a)bitmer.com>
Tested-by: Jarkko Nikula <jarkko.nikula(a)bitmer.com>
Signed-off-by: Mark Brown <broonie(a)kernel.org>
---
sound/soc/omap/omap-mcbsp.c | 6 +++---
1 file changed, 3 insertions(+), 3 deletions(-)
diff --git a/sound/soc/omap/omap-mcbsp.c b/sound/soc/omap/omap-mcbsp.c
index e48fad11a0cc..8cab1151d3bb 100644
--- a/sound/soc/omap/omap-mcbsp.c
+++ b/sound/soc/omap/omap-mcbsp.c
@@ -324,7 +324,7 @@ static int omap_mcbsp_request(struct omap_mcbsp *mcbsp)
mcbsp->reg_cache = reg_cache;
spin_unlock(&mcbsp->lock);
- if (mcbsp->pdata && mcbsp->pdata->ops && mcbsp->pdata->ops->request)
+ if(mcbsp->pdata->ops && mcbsp->pdata->ops->request)
mcbsp->pdata->ops->request(mcbsp->id - 1);
/*
@@ -361,7 +361,7 @@ static int omap_mcbsp_request(struct omap_mcbsp *mcbsp)
err_free_irq:
free_irq(mcbsp->tx_irq, (void *)mcbsp);
err_clk_disable:
- if (mcbsp->pdata && mcbsp->pdata->ops && mcbsp->pdata->ops->free)
+ if(mcbsp->pdata->ops && mcbsp->pdata->ops->free)
mcbsp->pdata->ops->free(mcbsp->id - 1);
/* Disable wakeup behavior */
@@ -382,7 +382,7 @@ static void omap_mcbsp_free(struct omap_mcbsp *mcbsp)
{
void *reg_cache;
- if (mcbsp->pdata && mcbsp->pdata->ops && mcbsp->pdata->ops->free)
+ if(mcbsp->pdata->ops && mcbsp->pdata->ops->free)
mcbsp->pdata->ops->free(mcbsp->id - 1);
/* Disable wakeup behavior */
--
2.19.1
1
0
[alsa-devel] Applied "ASoC: omap-mcbsp: No need to initialize max_xx_thres when it is not used" to the asoc tree
by Mark Brown 13 Nov '18
by Mark Brown 13 Nov '18
13 Nov '18
The patch
ASoC: omap-mcbsp: No need to initialize max_xx_thres when it is not used
has been applied to the asoc tree at
https://git.kernel.org/pub/scm/linux/kernel/git/broonie/sound.git
All being well this means that it will be integrated into the linux-next
tree (usually sometime in the next 24 hours) and sent to Linus during
the next merge window (or sooner if it is a bug fix), however if
problems are discovered then the patch may be dropped or reverted.
You may get further e-mails resulting from automated or manual testing
and review of the tree, please engage with people reporting problems and
send followup patches addressing any issues that are reported if needed.
If any updates are required or you are submitting further changes they
should be sent as incremental updates against current git, existing
patches will not be replaced.
Please add any relevant lists and maintainers to the CCs when replying
to this mail.
Thanks,
Mark
>From f15c19af929d380d0acb2a8d8277d688351bd5de Mon Sep 17 00:00:00 2001
From: Peter Ujfalusi <peter.ujfalusi(a)ti.com>
Date: Thu, 8 Nov 2018 09:30:00 +0200
Subject: [PATCH] ASoC: omap-mcbsp: No need to initialize max_xx_thres when it
is not used
Initializing to -EINVAL is not correct as the variables are unsigned and
if buffer_size is 0 then they are not used anyway.
Signed-off-by: Peter Ujfalusi <peter.ujfalusi(a)ti.com>
Acked-by: Jarkko Nikula <jarkko.nikula(a)bitmer.com>
Tested-by: Jarkko Nikula <jarkko.nikula(a)bitmer.com>
Signed-off-by: Mark Brown <broonie(a)kernel.org>
---
sound/soc/omap/omap-mcbsp.c | 3 ---
1 file changed, 3 deletions(-)
diff --git a/sound/soc/omap/omap-mcbsp.c b/sound/soc/omap/omap-mcbsp.c
index 8cab1151d3bb..e0ef4774c710 100644
--- a/sound/soc/omap/omap-mcbsp.c
+++ b/sound/soc/omap/omap-mcbsp.c
@@ -727,9 +727,6 @@ static int omap_mcbsp_init(struct platform_device *pdev)
"Unable to create additional controls\n");
goto err_thres;
}
- } else {
- mcbsp->max_tx_thres = -EINVAL;
- mcbsp->max_rx_thres = -EINVAL;
}
ret = omap_mcbsp_st_init(pdev);
--
2.19.1
1
0
[alsa-devel] [PATCH] ASoC: rockchip: add missing slave_config setting for I2S
by Katsuhiro Suzuki 13 Nov '18
by Katsuhiro Suzuki 13 Nov '18
13 Nov '18
This patch adds missing prepare_sleve_config that is needed for
setup the DMA slave channel for I2S.
Signed-off-by: Katsuhiro Suzuki <katsuhiro(a)katsuster.net>
---
sound/soc/rockchip/rockchip_pcm.c | 1 +
1 file changed, 1 insertion(+)
diff --git a/sound/soc/rockchip/rockchip_pcm.c b/sound/soc/rockchip/rockchip_pcm.c
index 9e7b5fa4cf59..4ac78d7a4b2d 100644
--- a/sound/soc/rockchip/rockchip_pcm.c
+++ b/sound/soc/rockchip/rockchip_pcm.c
@@ -33,6 +33,7 @@ static const struct snd_pcm_hardware snd_rockchip_hardware = {
static const struct snd_dmaengine_pcm_config rk_dmaengine_pcm_config = {
.pcm_hardware = &snd_rockchip_hardware,
+ .prepare_slave_config = snd_dmaengine_pcm_prepare_slave_config,
.prealloc_buffer_size = 32 * 1024,
};
--
2.19.1
2
1
[alsa-devel] [PATCH 1/2] ASoC: wm_adsp: Fix dma-unsafe read of scratch registers
by Richard Fitzgerald 13 Nov '18
by Richard Fitzgerald 13 Nov '18
13 Nov '18
Stack memory isn't DMA-safe so it isn't safe to use either
regmap_raw_read or regmap_bulk_read to read into stack memory.
The two functions to read the scratch registers were using
stack memory and regmap_raw_read. It's not worth allocating
memory just for this trivial read, and it isn't time-critical.
A simple regmap_read for each register is sufficient.
Signed-off-by: Richard Fitzgerald <rf(a)opensource.cirrus.com>
---
sound/soc/codecs/wm_adsp.c | 37 ++++++++++++++++++++-----------------
1 file changed, 20 insertions(+), 17 deletions(-)
diff --git a/sound/soc/codecs/wm_adsp.c b/sound/soc/codecs/wm_adsp.c
index a53dc174bbf0..66501b8dc46f 100644
--- a/sound/soc/codecs/wm_adsp.c
+++ b/sound/soc/codecs/wm_adsp.c
@@ -765,38 +765,41 @@ static unsigned int wm_adsp_region_to_reg(struct wm_adsp_region const *mem,
static void wm_adsp2_show_fw_status(struct wm_adsp *dsp)
{
- u16 scratch[4];
+ unsigned int scratch[4];
+ unsigned int addr = dsp->base + ADSP2_SCRATCH0;
+ unsigned int i;
int ret;
- ret = regmap_raw_read(dsp->regmap, dsp->base + ADSP2_SCRATCH0,
- scratch, sizeof(scratch));
- if (ret) {
- adsp_err(dsp, "Failed to read SCRATCH regs: %d\n", ret);
- return;
+ for (i = 0; i < ARRAY_SIZE(scratch); ++i) {
+ ret = regmap_read(dsp->regmap, addr + i, &scratch[i]);
+ if (ret) {
+ adsp_err(dsp, "Failed to read SCRATCH%u: %d\n", i, ret);
+ return;
+ }
}
adsp_dbg(dsp, "FW SCRATCH 0:0x%x 1:0x%x 2:0x%x 3:0x%x\n",
- be16_to_cpu(scratch[0]),
- be16_to_cpu(scratch[1]),
- be16_to_cpu(scratch[2]),
- be16_to_cpu(scratch[3]));
+ scratch[0], scratch[1], scratch[2], scratch[3]);
}
static void wm_adsp2v2_show_fw_status(struct wm_adsp *dsp)
{
- u32 scratch[2];
+ unsigned int scratch[2];
int ret;
- ret = regmap_raw_read(dsp->regmap, dsp->base + ADSP2V2_SCRATCH0_1,
- scratch, sizeof(scratch));
-
+ ret = regmap_read(dsp->regmap, dsp->base + ADSP2V2_SCRATCH0_1,
+ &scratch[0]);
if (ret) {
- adsp_err(dsp, "Failed to read SCRATCH regs: %d\n", ret);
+ adsp_err(dsp, "Failed to read SCRATCH0_1: %d\n", ret);
return;
}
- scratch[0] = be32_to_cpu(scratch[0]);
- scratch[1] = be32_to_cpu(scratch[1]);
+ ret = regmap_read(dsp->regmap, dsp->base + ADSP2V2_SCRATCH2_3,
+ &scratch[1]);
+ if (ret) {
+ adsp_err(dsp, "Failed to read SCRATCH2_3: %d\n", ret);
+ return;
+ }
adsp_dbg(dsp, "FW SCRATCH 0:0x%x 1:0x%x 2:0x%x 3:0x%x\n",
scratch[0] & 0xFFFF,
--
2.11.0
2
3
Re: [alsa-devel] Realtek ALC294 Intel Sunrise Point-LP HD Audio driver - sound does not work
by Takashi Iwai 13 Nov '18
by Takashi Iwai 13 Nov '18
13 Nov '18
On Tue, 13 Nov 2018 19:11:18 +0100,
Tomasz PrzybyX2 wrote:
>
> Hello Takashi,
>
> > Does the headphone work?
>
> No.
For making the headphone working, you don't need any jack detection,
in general. You can disable the auto-mute mode. And, at best, avoid
PulseAudio for the basic testing in this level.
If both headphone and speaker don't work even with the statically
enabled routing, I have no idea what's wrong. You really need to ping
ASUS for a better help. It's vendor-specific things, after all.
thanks,
Takashi
>
> Internal speakers are muted
> Headphones and external speakers connected via JACK output combo are
> muted . Even with `options snd_hda_intel index=0
> model=dell-headset-multi` custom flag
>
> QUOTE from arch wiki
> https://wiki.archlinux.org/index.php/Advanced_Linux_Sound_Architecture#Corr…
> ---
> Correctly detect microphone plugged in a 4-pin 3.5mm (TRRS) jack
> On some modern laptops you may have a combined 3.5mm headset jack,
> instead of two separated ones, which may not be correctly detected by
> default. To make ALSA correctly detect plug-in status on your 3.5mm
> jack, you could put the following line into your
> /etc/modprobe.d/alsa-base.conf :
>
> # options snd_hda_intel index=0 model=[YOUR_MODEL_SETTING]
> For complete list of options put in [YOUR_MODEL_SETTING], see
> HD-Audio-Models.txt. Tested with Gigabyte Aero15 2017 (P65 Model),
> with ALC255 and set model to dell-headset-multi.
>
> ----
>
> See main bug report
>
> https://bugs.launchpad.net/ubuntu/+source/alsa-driver/+bug/1784485
>
> Others forum issue reports:
>
> https://forum.manjaro.org/t/alc294-analog-audio-card-detected-but-no-sound-…
>
> https://forum.ubuntuusers.de/topic/asus-zenbook-lautsprecher-ohne-funktion/
>
>
> One more report from me:
> ```
>
> [manjaro@manjaro ~]$ pactl list sinks
> Sink #0
> State: SUSPENDED
> Name: alsa_output.pci-0000_00_1f.3.analog-stereo
> Description: Built-in Audio Analog Stereo
> Driver: module-alsa-card.c
> Sample Specification: s16le 2ch 44100Hz
> Channel Map: front-left,front-right
> Owner Module: 6
> Mute: no
> Volume: front-left: 30129 / 46% / -20.25 dB, front-right:
> 30129 / 46% / -20.25 dB
> balance 0.00
> Base Volume: 65536 / 100% / 0.00 dB
> Monitor Source: alsa_output.pci-0000_00_1f.3.analog-stereo.monitor
> Latency: 0 usec, configured 0 usec
> Flags: HARDWARE HW_MUTE_CTRL HW_VOLUME_CTRL DECIBEL_VOLUME LATENCY
> Properties:
> alsa.resolution_bits = "16"
> device.api = "alsa"
> device.class = "sound"
> alsa.class = "generic"
> alsa.subclass = "generic-mix"
> alsa.name = "ALC294 Analog"
> alsa.id = "ALC294 Analog"
> alsa.subdevice = "0"
> alsa.subdevice_name = "subdevice #0"
> alsa.device = "0"
> alsa.card = "0"
> alsa.card_name = "HDA Intel PCH"
> alsa.long_card_name = "HDA Intel PCH at 0xef528000 irq 130"
> alsa.driver_name = "snd_hda_intel"
> device.bus_path = "pci-0000:00:1f.3"
> sysfs.path = "/devices/pci0000:00/0000:00:1f.3/sound/card0"
> device.bus = "pci"
> device.vendor.id = "8086"
> device.vendor.name = "Intel Corporation"
> device.product.id = "9d71"
> device.product.name = "Sunrise Point-LP HD Audio"
> device.form_factor = "internal"
> device.string = "front:0"
> device.buffering.buffer_size = "352800"
> device.buffering.fragment_size = "176400"
> device.access_mode = "mmap+timer"
> device.profile.name = "analog-stereo"
> device.profile.description = "Analog Stereo"
> device.description = "Built-in Audio Analog Stereo"
> alsa.mixer_name = "Realtek ALC294"
> alsa.components = "HDA:10ec0294,10431a00,00100004
> HDA:8086280b,80860101,00100000"
> module-udev-detect.discovered = "1"
> device.icon_name = "audio-card-pci"
> Ports:
> analog-output-speaker: Speakers (priority: 10000, not
> available)
> analog-output-headphones: Headphones (priority: 9000,
> available)
> Active Port: analog-output-headphones
> Formats:
> pcm
> [manjaro@manjaro ~]$
>
> ```
>
>
> This is common issue.
>
> Tomasz
>
> W dniu 13.11.2018 o 18:37, Takashi Iwai pisze:
> > On Sat, 10 Nov 2018 14:42:01 +0100,
> > Tomasz PrzybyX2 wrote:
> >>
> >> Hello Devs
> >>
> >> Lots of users with Intel Sunrise Point-LP HD Audio driver (ALC294)
> >> (snd_hda_intel) have major issue. Not sound at all. Only crackling
> >> from external speakers OR silence from internal notebook speakers.
> >> Tried fix with extra boot flags does not work at all.
> >
> > Does the headphone work? If yes, it's possibly either a wrong pin
> > config or some extra stuff needed to drive the speaker amp.
> > In the latter case, only vendors know the details.
> >
> >
> > Takashi
> >
> >>
> >> Also affected Asus VivoBook R542UF
> >>
> >> ```
> >> Machine:
> >> Type: Laptop System: ASUSTeK product: VivoBook 15_ASUS Laptop X542UF
> >> v: 1.0 serial: <filter>
> >> Mobo: ASUSTeK model: X542UF v: 1.0 serial: <filter>
> >> UEFI: American Megatrends v: X542UF.303 date: 03/15/2018
> >> Audio:
> >> Device-1: Intel Sunrise Point-LP HD Audio driver: snd_hda_intel
> >> v: kernel bus ID: 00:1f.3
> >> Sound Server: ALSA Kernel: 4.19
> >> ```
> >> ```
> >> aplay -l
> >> **** List of PLAYBACK Hardware Devices ****
> >> card 0: PCH [HDA Intel PCH], device 0: ALC294 Analog [ALC294 Analog]
> >> Subdevices: 1/1
> >> Subdevice #0: subdevice #0
> >> card 0: PCH [HDA Intel PCH], device 3: HDMI 0 [HDMI 0]
> >> Subdevices: 1/1
> >> Subdevice #0: subdevice #0
> >> card 0: PCH [HDA Intel PCH], device 7: HDMI 1 [HDMI 1]
> >> Subdevices: 1/1
> >> Subdevice #0: subdevice #0
> >> card 0: PCH [HDA Intel PCH], device 8: HDMI 2 [HDMI 2]
> >> Subdevices: 1/1
> >> Subdevice #0: subdevice #0
> >> card 0: PCH [HDA Intel PCH], device 9: HDMI 3 [HDMI 3]
> >> Subdevices: 1/1
> >> Subdevice #0: subdevice #0
> >> card 0: PCH [HDA Intel PCH], device 10: HDMI 4 [HDMI 4]
> >> Subdevices: 1/1
> >> Subdevice #0: subdevice #0
> >> ```
> >> Dmesg parts
> >> ```
> >> [ 12.342528] snd_hda_codec_realtek hdaudioC0D0: autoconfig for ALC294:
> >> line_outs=1 (0x14/0x0/0x0/0x0/0x0) type:speaker
> >> [ 12.342531] snd_hda_codec_realtek hdaudioC0D0: speaker_outs=0
> >> (0x0/0x0/0x0/0x0/0x0)
> >> [ 12.342533] snd_hda_codec_realtek hdaudioC0D0: hp_outs=1
> >> (0x21/0x0/0x0/0x0/0x0)
> >> [ 12.342535] snd_hda_codec_realtek hdaudioC0D0: mono: mono_out=0x0
> >> [ 12.342536] snd_hda_codec_realtek hdaudioC0D0: inputs:
> >> [ 12.342538] snd_hda_codec_realtek hdaudioC0D0: Mic=0x1b
> >> ```
> >> ```
> >> [ 12.634171] input: HDA Intel PCH Headphone as
> >> /devices/pci0000:00/0000:00:1f.3/sound/card0/input18
> >> [ 12.634389] input: HDA Intel PCH HDMI/DP,pcm=3 as
> >> /devices/pci0000:00/0000:00:1f.3/sound/card0/input19
> >> [ 12.634563] input: HDA Intel PCH HDMI/DP,pcm=7 as
> >> /devices/pci0000:00/0000:00:1f.3/sound/card0/input20
> >> [ 12.634737] input: HDA Intel PCH HDMI/DP,pcm=8 as
> >> /devices/pci0000:00/0000:00:1f.3/sound/card0/input21
> >> [ 12.634905] input: HDA Intel PCH HDMI/DP,pcm=9 as
> >> /devices/pci0000:00/0000:00:1f.3/sound/card0/input22
> >> [ 12.635045] input: HDA Intel PCH HDMI/DP,pcm=10 as
> >> /devices/pci0000:00/0000:00:1f.3/sound/card0/input23
> >> ```
> >>
> >> Regards
> >>
> >> Tomasz
> >>
> >> _______________________________________________
> >> Alsa-devel mailing list
> >> Alsa-devel(a)alsa-project.org
> >> http://mailman.alsa-project.org/mailman/listinfo/alsa-devel
>
>
1
0
[alsa-devel] [sound:for-linus 5/5] sound/pci//hda/patch_ca0132.c:8416:3: error: implicit declaration of function 'pci_iounmap'; did you mean 'pcim_iounmap'?
by kbuild test robot 13 Nov '18
by kbuild test robot 13 Nov '18
13 Nov '18
tree: https://git.kernel.org/pub/scm/linux/kernel/git/tiwai/sound.git for-linus
head: d99501b8575dc1248bacf1b58d2241cb4b265d49
commit: d99501b8575dc1248bacf1b58d2241cb4b265d49 [5/5] ALSA: hda/ca0132 - Call pci_iounmap() instead of iounmap()
config: sh-allyesconfig (attached as .config)
compiler: sh4-linux-gnu-gcc (Debian 7.2.0-11) 7.2.0
reproduce:
wget https://raw.githubusercontent.com/intel/lkp-tests/master/sbin/make.cross -O ~/bin/make.cross
chmod +x ~/bin/make.cross
git checkout d99501b8575dc1248bacf1b58d2241cb4b265d49
# save the attached .config to linux build tree
GCC_VERSION=7.2.0 make.cross ARCH=sh
All errors (new ones prefixed by >>):
sound/pci//hda/patch_ca0132.c: In function 'ca0132_free':
>> sound/pci//hda/patch_ca0132.c:8416:3: error: implicit declaration of function 'pci_iounmap'; did you mean 'pcim_iounmap'? [-Werror=implicit-function-declaration]
pci_iounmap(codec->bus->pci, spec->mem_base);
^~~~~~~~~~~
pcim_iounmap
sound/pci//hda/patch_ca0132.c: In function 'patch_ca0132':
sound/pci//hda/patch_ca0132.c:8799:20: error: implicit declaration of function 'pci_iomap'; did you mean 'pcim_iomap'? [-Werror=implicit-function-declaration]
spec->mem_base = pci_iomap(codec->bus->pci, 2, 0xC20);
^~~~~~~~~
pcim_iomap
sound/pci//hda/patch_ca0132.c:8799:18: warning: assignment makes pointer from integer without a cast [-Wint-conversion]
spec->mem_base = pci_iomap(codec->bus->pci, 2, 0xC20);
^
cc1: some warnings being treated as errors
vim +8416 sound/pci//hda/patch_ca0132.c
8386
8387 static void ca0132_free(struct hda_codec *codec)
8388 {
8389 struct ca0132_spec *spec = codec->spec;
8390
8391 cancel_delayed_work_sync(&spec->unsol_hp_work);
8392 snd_hda_power_up(codec);
8393 switch (spec->quirk) {
8394 case QUIRK_SBZ:
8395 sbz_exit_chip(codec);
8396 break;
8397 case QUIRK_ZXR:
8398 zxr_exit_chip(codec);
8399 break;
8400 case QUIRK_R3D:
8401 r3d_exit_chip(codec);
8402 break;
8403 case QUIRK_AE5:
8404 ae5_exit_chip(codec);
8405 break;
8406 case QUIRK_R3DI:
8407 r3di_gpio_shutdown(codec);
8408 break;
8409 }
8410
8411 snd_hda_sequence_write(codec, spec->base_exit_verbs);
8412 ca0132_exit_chip(codec);
8413
8414 snd_hda_power_down(codec);
8415 if (spec->mem_base)
> 8416 pci_iounmap(codec->bus->pci, spec->mem_base);
8417 kfree(spec->spec_init_verbs);
8418 kfree(codec->spec);
8419 }
8420
---
0-DAY kernel test infrastructure Open Source Technology Center
https://lists.01.org/pipermail/kbuild-all Intel Corporation
1
0
13 Nov '18
Adopt the SPDX license identifier headers to ease license compliance
management.
Cc: Florian Kauer <florian.kauer(a)koalo.de>
Signed-off-by: Stefan Wahren <stefan.wahren(a)i2se.com>
---
sound/soc/bcm/bcm2835-i2s.c | 10 +---------
1 file changed, 1 insertion(+), 9 deletions(-)
diff --git a/sound/soc/bcm/bcm2835-i2s.c b/sound/soc/bcm/bcm2835-i2s.c
index d5f73a8..0e4a0e9 100644
--- a/sound/soc/bcm/bcm2835-i2s.c
+++ b/sound/soc/bcm/bcm2835-i2s.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0
/*
* ALSA SoC I2S Audio Layer for Broadcom BCM2835 SoC
*
@@ -20,15 +21,6 @@
* Freescale SSI ALSA SoC Digital Audio Interface (DAI) driver
* Author: Timur Tabi <timur(a)freescale.com>
* Copyright 2007-2010 Freescale Semiconductor, 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.
*/
#include <linux/bitops.h>
--
2.7.4
2
1
I have small program that captures audio from a microphone. As my
microphone is very sensitive, I prefer to mute the microphone boost before
capturing. I open alsamixer and set volume of the microphone boost to zero,
save settings and exit. Then I execute my program. I see that it resets
volume of the microphone boost in snd_pcm_hw_params. What should I do
resolve this problem? Where can I find default value and change it?
2
1