summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Documentation/devicetree/bindings/sound/mchp-i2s-mcc.txt10
-rw-r--r--sound/soc/atmel/Kconfig3
-rw-r--r--sound/soc/atmel/mchp-i2s-mcc.c161
-rw-r--r--sound/soc/codecs/nau8825.c9
-rw-r--r--sound/soc/codecs/wm8524.c2
-rw-r--r--sound/soc/intel/atom/sst/sst_acpi.c2
-rw-r--r--sound/soc/intel/atom/sst/sst_loader.c2
-rw-r--r--sound/soc/soc-dai.c2
-rw-r--r--sound/soc/sof/intel/hda.c2
9 files changed, 161 insertions, 32 deletions
diff --git a/Documentation/devicetree/bindings/sound/mchp-i2s-mcc.txt b/Documentation/devicetree/bindings/sound/mchp-i2s-mcc.txt
index 91ec83a6faed..af8fe3e657df 100644
--- a/Documentation/devicetree/bindings/sound/mchp-i2s-mcc.txt
+++ b/Documentation/devicetree/bindings/sound/mchp-i2s-mcc.txt
@@ -1,7 +1,8 @@
* Microchip I2S Multi-Channel Controller
Required properties:
-- compatible: Should be "microchip,sam9x60-i2smcc".
+- compatible: Should be "microchip,sam9x60-i2smcc" or
+ "microchip,sama7g5-i2smcc".
- reg: Should be the physical base address of the controller and the
length of memory mapped region.
- interrupts: Should contain the interrupt for the controller.
@@ -18,7 +19,12 @@ Required properties:
Optional properties:
- pinctrl-0: Should specify pin control groups used for this controller.
- princtrl-names: Should contain only one value - "default".
-
+- microchip,tdm-data-pair: 8 bit value that represents the DIN/DOUT pair pins
+ which are used to receive/send TDM data. It is optional
+ and it is only needed if the controller uses the TDM
+ mode. Not available for "microchip,sam9x60-i2smcc"
+ compatible. If it's not present, the default value is 0,
+ so the DIN/DOUT 0 pins are used.
(1) : Only the peripheral clock is required. The generated clock is optional
and should be set mostly when Master Mode is required.
diff --git a/sound/soc/atmel/Kconfig b/sound/soc/atmel/Kconfig
index 9fe9471f4514..ec04e3386bc0 100644
--- a/sound/soc/atmel/Kconfig
+++ b/sound/soc/atmel/Kconfig
@@ -127,10 +127,13 @@ config SND_MCHP_SOC_I2S_MCC
Say Y or M if you want to add support for I2S Multi-Channel ASoC
driver on the following Microchip platforms:
- sam9x60
+ - sama7g5
The I2SMCC complies with the Inter-IC Sound (I2S) bus specification
and supports a Time Division Multiplexed (TDM) interface with
external multi-channel audio codecs.
+ Starting with sama7g5, I2S and Left-Justified multi-channel is
+ supported by using multiple data pins, output and input, without TDM.
config SND_MCHP_SOC_SPDIFTX
tristate "Microchip ASoC driver for boards using S/PDIF TX"
diff --git a/sound/soc/atmel/mchp-i2s-mcc.c b/sound/soc/atmel/mchp-i2s-mcc.c
index 6d5ae18f8b38..673bc16cb46a 100644
--- a/sound/soc/atmel/mchp-i2s-mcc.c
+++ b/sound/soc/atmel/mchp-i2s-mcc.c
@@ -16,6 +16,7 @@
#include <linux/clk.h>
#include <linux/mfd/syscon.h>
#include <linux/lcm.h>
+#include <linux/of_device.h>
#include <sound/core.h>
#include <sound/pcm.h>
@@ -99,6 +100,8 @@
#define MCHP_I2SMCC_MRA_DATALENGTH_8_BITS_COMPACT (7 << 1)
#define MCHP_I2SMCC_MRA_WIRECFG_MASK GENMASK(5, 4)
+#define MCHP_I2SMCC_MRA_WIRECFG_TDM(pin) (((pin) << 4) & \
+ MCHP_I2SMCC_MRA_WIRECFG_MASK)
#define MCHP_I2SMCC_MRA_WIRECFG_I2S_1_TDM_0 (0 << 4)
#define MCHP_I2SMCC_MRA_WIRECFG_I2S_2_TDM_1 (1 << 4)
#define MCHP_I2SMCC_MRA_WIRECFG_I2S_4_TDM_2 (2 << 4)
@@ -173,7 +176,7 @@
*/
#define MCHP_I2SMCC_MRB_CRAMODE_REGULAR (1 << 0)
-#define MCHP_I2SMCC_MRB_FIFOEN BIT(1)
+#define MCHP_I2SMCC_MRB_FIFOEN BIT(4)
#define MCHP_I2SMCC_MRB_DMACHUNK_MASK GENMASK(9, 8)
#define MCHP_I2SMCC_MRB_DMACHUNK(no_words) \
@@ -225,6 +228,11 @@ static const struct regmap_config mchp_i2s_mcc_regmap_config = {
.max_register = MCHP_I2SMCC_VERSION,
};
+struct mchp_i2s_mcc_soc_data {
+ unsigned int data_pin_pair_num;
+ bool has_fifo;
+};
+
struct mchp_i2s_mcc_dev {
struct wait_queue_head wq_txrdy;
struct wait_queue_head wq_rxrdy;
@@ -232,6 +240,7 @@ struct mchp_i2s_mcc_dev {
struct regmap *regmap;
struct clk *pclk;
struct clk *gclk;
+ const struct mchp_i2s_mcc_soc_data *soc;
struct snd_dmaengine_dai_dma_data playback;
struct snd_dmaengine_dai_dma_data capture;
unsigned int fmt;
@@ -239,6 +248,7 @@ struct mchp_i2s_mcc_dev {
unsigned int frame_length;
int tdm_slots;
int channels;
+ u8 tdm_data_pair;
unsigned int gclk_use:1;
unsigned int gclk_running:1;
unsigned int tx_rdy:1;
@@ -248,7 +258,7 @@ struct mchp_i2s_mcc_dev {
static irqreturn_t mchp_i2s_mcc_interrupt(int irq, void *dev_id)
{
struct mchp_i2s_mcc_dev *dev = dev_id;
- u32 sra, imra, srb, imrb, pendinga, pendingb, idra = 0;
+ u32 sra, imra, srb, imrb, pendinga, pendingb, idra = 0, idrb = 0;
irqreturn_t ret = IRQ_NONE;
regmap_read(dev->regmap, MCHP_I2SMCC_IMRA, &imra);
@@ -266,24 +276,36 @@ static irqreturn_t mchp_i2s_mcc_interrupt(int irq, void *dev_id)
* Tx/Rx ready interrupts are enabled when stopping only, to assure
* availability and to disable clocks if necessary
*/
- idra |= pendinga & (MCHP_I2SMCC_INT_TXRDY_MASK(dev->channels) |
- MCHP_I2SMCC_INT_RXRDY_MASK(dev->channels));
- if (idra)
+ if (dev->soc->has_fifo) {
+ idrb |= pendingb & (MCHP_I2SMCC_INT_TXFFRDY |
+ MCHP_I2SMCC_INT_RXFFRDY);
+ } else {
+ idra |= pendinga & (MCHP_I2SMCC_INT_TXRDY_MASK(dev->channels) |
+ MCHP_I2SMCC_INT_RXRDY_MASK(dev->channels));
+ }
+ if (idra || idrb)
ret = IRQ_HANDLED;
- if ((imra & MCHP_I2SMCC_INT_TXRDY_MASK(dev->channels)) &&
- (imra & MCHP_I2SMCC_INT_TXRDY_MASK(dev->channels)) ==
- (idra & MCHP_I2SMCC_INT_TXRDY_MASK(dev->channels))) {
+ if ((!dev->soc->has_fifo &&
+ (imra & MCHP_I2SMCC_INT_TXRDY_MASK(dev->channels)) &&
+ (imra & MCHP_I2SMCC_INT_TXRDY_MASK(dev->channels)) ==
+ (idra & MCHP_I2SMCC_INT_TXRDY_MASK(dev->channels))) ||
+ (dev->soc->has_fifo && imrb & MCHP_I2SMCC_INT_TXFFRDY)) {
dev->tx_rdy = 1;
wake_up_interruptible(&dev->wq_txrdy);
}
- if ((imra & MCHP_I2SMCC_INT_RXRDY_MASK(dev->channels)) &&
- (imra & MCHP_I2SMCC_INT_RXRDY_MASK(dev->channels)) ==
- (idra & MCHP_I2SMCC_INT_RXRDY_MASK(dev->channels))) {
+ if ((!dev->soc->has_fifo &&
+ (imra & MCHP_I2SMCC_INT_RXRDY_MASK(dev->channels)) &&
+ (imra & MCHP_I2SMCC_INT_RXRDY_MASK(dev->channels)) ==
+ (idra & MCHP_I2SMCC_INT_RXRDY_MASK(dev->channels))) ||
+ (dev->soc->has_fifo && imrb & MCHP_I2SMCC_INT_RXFFRDY)) {
dev->rx_rdy = 1;
wake_up_interruptible(&dev->wq_rxrdy);
}
- regmap_write(dev->regmap, MCHP_I2SMCC_IDRA, idra);
+ if (dev->soc->has_fifo)
+ regmap_write(dev->regmap, MCHP_I2SMCC_IDRB, idrb);
+ else
+ regmap_write(dev->regmap, MCHP_I2SMCC_IDRA, idra);
return ret;
}
@@ -549,6 +571,17 @@ static int mchp_i2s_mcc_hw_params(struct snd_pcm_substream *substream,
}
if (dev->fmt & (SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_LEFT_J)) {
+ /* for I2S and LEFT_J one pin is needed for every 2 channels */
+ if (channels > dev->soc->data_pin_pair_num * 2) {
+ dev_err(dev->dev,
+ "unsupported number of audio channels: %d\n",
+ channels);
+ return -EINVAL;
+ }
+
+ /* enable for interleaved format */
+ mrb |= MCHP_I2SMCC_MRB_CRAMODE_REGULAR;
+
switch (channels) {
case 1:
if (is_playback)
@@ -558,6 +591,12 @@ static int mchp_i2s_mcc_hw_params(struct snd_pcm_substream *substream,
break;
case 2:
break;
+ case 4:
+ mra |= MCHP_I2SMCC_MRA_WIRECFG_I2S_2_TDM_1;
+ break;
+ case 8:
+ mra |= MCHP_I2SMCC_MRA_WIRECFG_I2S_4_TDM_2;
+ break;
default:
dev_err(dev->dev, "unsupported number of audio channels\n");
return -EINVAL;
@@ -566,6 +605,8 @@ static int mchp_i2s_mcc_hw_params(struct snd_pcm_substream *substream,
if (!frame_length)
frame_length = 2 * params_physical_width(params);
} else if (dev->fmt & SND_SOC_DAIFMT_DSP_A) {
+ mra |= MCHP_I2SMCC_MRA_WIRECFG_TDM(dev->tdm_data_pair);
+
if (dev->tdm_slots) {
if (channels % 2 && channels * 2 <= dev->tdm_slots) {
/*
@@ -636,6 +677,10 @@ static int mchp_i2s_mcc_hw_params(struct snd_pcm_substream *substream,
}
}
+ /* enable FIFO if available */
+ if (dev->soc->has_fifo)
+ mrb |= MCHP_I2SMCC_MRB_FIFOEN;
+
/*
* If we are already running, the wanted setup must be
* the same with the one that's currently ongoing
@@ -698,8 +743,13 @@ static int mchp_i2s_mcc_hw_free(struct snd_pcm_substream *substream,
if (err == 0) {
dev_warn_once(dev->dev,
"Timeout waiting for Tx ready\n");
- regmap_write(dev->regmap, MCHP_I2SMCC_IDRA,
- MCHP_I2SMCC_INT_TXRDY_MASK(dev->channels));
+ if (dev->soc->has_fifo)
+ regmap_write(dev->regmap, MCHP_I2SMCC_IDRB,
+ MCHP_I2SMCC_INT_TXFFRDY);
+ else
+ regmap_write(dev->regmap, MCHP_I2SMCC_IDRA,
+ MCHP_I2SMCC_INT_TXRDY_MASK(dev->channels));
+
dev->tx_rdy = 1;
}
} else {
@@ -709,8 +759,12 @@ static int mchp_i2s_mcc_hw_free(struct snd_pcm_substream *substream,
if (err == 0) {
dev_warn_once(dev->dev,
"Timeout waiting for Rx ready\n");
- regmap_write(dev->regmap, MCHP_I2SMCC_IDRA,
- MCHP_I2SMCC_INT_RXRDY_MASK(dev->channels));
+ if (dev->soc->has_fifo)
+ regmap_write(dev->regmap, MCHP_I2SMCC_IDRB,
+ MCHP_I2SMCC_INT_RXFFRDY);
+ else
+ regmap_write(dev->regmap, MCHP_I2SMCC_IDRA,
+ MCHP_I2SMCC_INT_RXRDY_MASK(dev->channels));
dev->rx_rdy = 1;
}
}
@@ -737,7 +791,7 @@ static int mchp_i2s_mcc_trigger(struct snd_pcm_substream *substream, int cmd,
struct mchp_i2s_mcc_dev *dev = snd_soc_dai_get_drvdata(dai);
bool is_playback = (substream->stream == SNDRV_PCM_STREAM_PLAYBACK);
u32 cr = 0;
- u32 iera = 0;
+ u32 iera = 0, ierb = 0;
u32 sr;
int err;
@@ -761,7 +815,10 @@ static int mchp_i2s_mcc_trigger(struct snd_pcm_substream *substream, int cmd,
* Enable Tx Ready interrupts on all channels
* to assure all data is sent
*/
- iera = MCHP_I2SMCC_INT_TXRDY_MASK(dev->channels);
+ if (dev->soc->has_fifo)
+ ierb = MCHP_I2SMCC_INT_TXFFRDY;
+ else
+ iera = MCHP_I2SMCC_INT_TXRDY_MASK(dev->channels);
} else if (!is_playback && (sr & MCHP_I2SMCC_SR_RXEN)) {
cr = MCHP_I2SMCC_CR_RXDIS;
dev->rx_rdy = 0;
@@ -769,7 +826,10 @@ static int mchp_i2s_mcc_trigger(struct snd_pcm_substream *substream, int cmd,
* Enable Rx Ready interrupts on all channels
* to assure all data is received
*/
- iera = MCHP_I2SMCC_INT_RXRDY_MASK(dev->channels);
+ if (dev->soc->has_fifo)
+ ierb = MCHP_I2SMCC_INT_RXFFRDY;
+ else
+ iera = MCHP_I2SMCC_INT_RXRDY_MASK(dev->channels);
}
break;
default:
@@ -787,7 +847,10 @@ static int mchp_i2s_mcc_trigger(struct snd_pcm_substream *substream, int cmd,
}
}
- regmap_write(dev->regmap, MCHP_I2SMCC_IERA, iera);
+ if (dev->soc->has_fifo)
+ regmap_write(dev->regmap, MCHP_I2SMCC_IERB, ierb);
+ else
+ regmap_write(dev->regmap, MCHP_I2SMCC_IERA, iera);
regmap_write(dev->regmap, MCHP_I2SMCC_CR, cr);
return 0;
@@ -869,15 +932,68 @@ static const struct snd_soc_component_driver mchp_i2s_mcc_component = {
};
#ifdef CONFIG_OF
+static struct mchp_i2s_mcc_soc_data mchp_i2s_mcc_sam9x60 = {
+ .data_pin_pair_num = 1,
+};
+
+static struct mchp_i2s_mcc_soc_data mchp_i2s_mcc_sama7g5 = {
+ .data_pin_pair_num = 4,
+ .has_fifo = true,
+};
+
static const struct of_device_id mchp_i2s_mcc_dt_ids[] = {
{
.compatible = "microchip,sam9x60-i2smcc",
+ .data = &mchp_i2s_mcc_sam9x60,
+ },
+ {
+ .compatible = "microchip,sama7g5-i2smcc",
+ .data = &mchp_i2s_mcc_sama7g5,
},
{ /* sentinel */ }
};
MODULE_DEVICE_TABLE(of, mchp_i2s_mcc_dt_ids);
#endif
+static int mchp_i2s_mcc_soc_data_parse(struct platform_device *pdev,
+ struct mchp_i2s_mcc_dev *dev)
+{
+ int err;
+
+ if (!dev->soc) {
+ dev_err(&pdev->dev, "failed to get soc data\n");
+ return -ENODEV;
+ }
+
+ if (dev->soc->data_pin_pair_num == 1)
+ return 0;
+
+ err = of_property_read_u8(pdev->dev.of_node, "microchip,tdm-data-pair",
+ &dev->tdm_data_pair);
+ if (err < 0 && err != -EINVAL) {
+ dev_err(&pdev->dev,
+ "bad property data for 'microchip,tdm-data-pair': %d",
+ err);
+ return err;
+ }
+ if (err == -EINVAL) {
+ dev_info(&pdev->dev,
+ "'microchip,tdm-data-pair' not found; assuming DIN/DOUT 0 for TDM\n");
+ dev->tdm_data_pair = 0;
+ } else {
+ if (dev->tdm_data_pair > dev->soc->data_pin_pair_num - 1) {
+ dev_err(&pdev->dev,
+ "invalid value for 'microchip,tdm-data-pair': %d\n",
+ dev->tdm_data_pair);
+ return -EINVAL;
+ }
+ dev_dbg(&pdev->dev, "TMD format on DIN/DOUT %d pins\n",
+ dev->tdm_data_pair);
+ }
+
+ return 0;
+}
+
static int mchp_i2s_mcc_probe(struct platform_device *pdev)
{
struct mchp_i2s_mcc_dev *dev;
@@ -929,6 +1045,11 @@ static int mchp_i2s_mcc_probe(struct platform_device *pdev)
dev->gclk = NULL;
}
+ dev->soc = of_device_get_match_data(&pdev->dev);
+ err = mchp_i2s_mcc_soc_data_parse(pdev, dev);
+ if (err < 0)
+ return err;
+
dev->dev = &pdev->dev;
dev->regmap = regmap;
platform_set_drvdata(pdev, dev);
diff --git a/sound/soc/codecs/nau8825.c b/sound/soc/codecs/nau8825.c
index f0cba7b5758b..e19db30c457b 100644
--- a/sound/soc/codecs/nau8825.c
+++ b/sound/soc/codecs/nau8825.c
@@ -295,7 +295,7 @@ static inline void nau8825_sema_reset(struct nau8825 *nau8825)
}
/**
- * Ramp up the headphone volume change gradually to target level.
+ * nau8825_hpvol_ramp - Ramp up the headphone volume change gradually to target level.
*
* @nau8825: component to register the codec private data with
* @vol_from: the volume to start up
@@ -347,8 +347,9 @@ static void nau8825_hpvol_ramp(struct nau8825 *nau8825,
}
/**
- * Computes log10 of a value; the result is round off to 3 decimal. This func-
- * tion takes reference to dvb-math. The source code locates as the following.
+ * nau8825_intlog10_dec3 - Computes log10 of a value
+ * the result is round off to 3 decimal. This function takes reference to
+ * dvb-math. The source code locates as the following.
* Linux/drivers/media/dvb-core/dvb_math.c
* @value: input for log10
*
@@ -408,7 +409,7 @@ static u32 nau8825_intlog10_dec3(u32 value)
}
/**
- * computes cross talk suppression sidetone gain.
+ * nau8825_xtalk_sidetone - computes cross talk suppression sidetone gain.
*
* @sig_org: orignal signal level
* @sig_cros: cross talk signal level
diff --git a/sound/soc/codecs/wm8524.c b/sound/soc/codecs/wm8524.c
index 4e9ab542f648..81f858f6bd67 100644
--- a/sound/soc/codecs/wm8524.c
+++ b/sound/soc/codecs/wm8524.c
@@ -227,7 +227,7 @@ static int wm8524_codec_probe(struct platform_device *pdev)
wm8524->mute = devm_gpiod_get(&pdev->dev, "wlf,mute", GPIOD_OUT_LOW);
if (IS_ERR(wm8524->mute)) {
ret = PTR_ERR(wm8524->mute);
- dev_err(&pdev->dev, "Failed to get mute line: %d\n", ret);
+ dev_err_probe(&pdev->dev, ret, "Failed to get mute line\n");
return ret;
}
diff --git a/sound/soc/intel/atom/sst/sst_acpi.c b/sound/soc/intel/atom/sst/sst_acpi.c
index 2c1b8a2e3506..3be64430c256 100644
--- a/sound/soc/intel/atom/sst/sst_acpi.c
+++ b/sound/soc/intel/atom/sst/sst_acpi.c
@@ -328,7 +328,7 @@ static int sst_acpi_probe(struct platform_device *pdev)
}
/**
-* intel_sst_remove - remove function
+* sst_acpi_remove - remove function
*
* @pdev: platform device structure
*
diff --git a/sound/soc/intel/atom/sst/sst_loader.c b/sound/soc/intel/atom/sst/sst_loader.c
index 1c9b0c9ec483..eea889001c24 100644
--- a/sound/soc/intel/atom/sst/sst_loader.c
+++ b/sound/soc/intel/atom/sst/sst_loader.c
@@ -76,7 +76,7 @@ int intel_sst_reset_dsp_mrfld(struct intel_sst_drv *sst_drv_ctx)
}
/**
- * sst_start_merrifield - Start the SST DSP processor
+ * sst_start_mrfld - Start the SST DSP processor
* @sst_drv_ctx: intel_sst_drv context pointer
*
* This starts the DSP in MERRIFIELD platfroms
diff --git a/sound/soc/soc-dai.c b/sound/soc/soc-dai.c
index cd3bb9a7983f..080fbe053fc5 100644
--- a/sound/soc/soc-dai.c
+++ b/sound/soc/soc-dai.c
@@ -154,7 +154,7 @@ int snd_soc_dai_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
EXPORT_SYMBOL_GPL(snd_soc_dai_set_fmt);
/**
- * snd_soc_xlate_tdm_slot - generate tx/rx slot mask.
+ * snd_soc_xlate_tdm_slot_mask - generate tx/rx slot mask.
* @slots: Number of slots in use.
* @tx_mask: bitmask representing active TX slots.
* @rx_mask: bitmask representing active RX slots.
diff --git a/sound/soc/sof/intel/hda.c b/sound/soc/sof/intel/hda.c
index 0c096db07322..5317dfa4a4bf 100644
--- a/sound/soc/sof/intel/hda.c
+++ b/sound/soc/sof/intel/hda.c
@@ -616,8 +616,6 @@ static int hda_init_caps(struct snd_sof_dev *sdev)
u32 link_mask;
int ret = 0;
- device_disable_async_suspend(bus->dev);
-
/* check if dsp is there */
if (bus->ppcap)
dev_dbg(sdev->dev, "PP capability, will probe DSP later.\n");