diff --git a/Documentation/devicetree/bindings/sound/es8328.txt b/Documentation/devicetree/bindings/sound/es8328.txt index 30ea8a318ae9..33fbf058c997 100644 --- a/Documentation/devicetree/bindings/sound/es8328.txt +++ b/Documentation/devicetree/bindings/sound/es8328.txt @@ -4,7 +4,7 @@ This device supports both I2C and SPI. Required properties: - - compatible : "everest,es8328" + - compatible : Should be "everest,es8328" or "everest,es8388" - DVDD-supply : Regulator providing digital core supply voltage 1.8 - 3.6V - AVDD-supply : Regulator providing analog supply voltage 3.3V - PVDD-supply : Regulator providing digital IO supply voltage 1.8 - 3.6V diff --git a/include/sound/soc.h b/include/sound/soc.h index c6cabf3daebe..cdfb55f7aede 100644 --- a/include/sound/soc.h +++ b/include/sound/soc.h @@ -1645,37 +1645,21 @@ static inline struct snd_soc_platform *snd_soc_kcontrol_platform( int snd_soc_util_init(void); void snd_soc_util_exit(void); -#define snd_soc_of_parse_card_name(card, propname) \ - snd_soc_of_parse_card_name_from_node(card, NULL, propname) -int snd_soc_of_parse_card_name_from_node(struct snd_soc_card *card, - struct device_node *np, - const char *propname); -#define snd_soc_of_parse_audio_simple_widgets(card, propname)\ - snd_soc_of_parse_audio_simple_widgets_from_node(card, NULL, propname) -int snd_soc_of_parse_audio_simple_widgets_from_node(struct snd_soc_card *card, - struct device_node *np, - const char *propname); - +int snd_soc_of_parse_card_name(struct snd_soc_card *card, + const char *propname); +int snd_soc_of_parse_audio_simple_widgets(struct snd_soc_card *card, + const char *propname); int snd_soc_of_parse_tdm_slot(struct device_node *np, unsigned int *tx_mask, unsigned int *rx_mask, unsigned int *slots, unsigned int *slot_width); -#define snd_soc_of_parse_audio_prefix(card, codec_conf, of_node, propname) \ - snd_soc_of_parse_audio_prefix_from_node(card, NULL, codec_conf, \ - of_node, propname) -void snd_soc_of_parse_audio_prefix_from_node(struct snd_soc_card *card, - struct device_node *np, +void snd_soc_of_parse_audio_prefix(struct snd_soc_card *card, struct snd_soc_codec_conf *codec_conf, struct device_node *of_node, const char *propname); - -#define snd_soc_of_parse_audio_routing(card, propname) \ - snd_soc_of_parse_audio_routing_from_node(card, NULL, propname) -int snd_soc_of_parse_audio_routing_from_node(struct snd_soc_card *card, - struct device_node *np, - const char *propname); - +int snd_soc_of_parse_audio_routing(struct snd_soc_card *card, + const char *propname); unsigned int snd_soc_of_parse_daifmt(struct device_node *np, const char *prefix, struct device_node **bitclkmaster, diff --git a/sound/soc/codecs/Kconfig b/sound/soc/codecs/Kconfig index 928baa69de91..e00ba806ef86 100644 --- a/sound/soc/codecs/Kconfig +++ b/sound/soc/codecs/Kconfig @@ -525,14 +525,16 @@ config SND_SOC_HDMI_CODEC select HDMI config SND_SOC_ES8328 - tristate "Everest Semi ES8328 CODEC" + tristate config SND_SOC_ES8328_I2C - tristate + tristate "Everest Semi ES8328 CODEC (I2C)" + depends on I2C select SND_SOC_ES8328 config SND_SOC_ES8328_SPI - tristate + tristate "Everest Semi ES8328 CODEC (SPI)" + depends on SPI_MASTER select SND_SOC_ES8328 config SND_SOC_GTM601 diff --git a/sound/soc/codecs/es8328-i2c.c b/sound/soc/codecs/es8328-i2c.c index 2d05b5d3a6ce..318ab28c5351 100644 --- a/sound/soc/codecs/es8328-i2c.c +++ b/sound/soc/codecs/es8328-i2c.c @@ -20,12 +20,14 @@ static const struct i2c_device_id es8328_id[] = { { "es8328", 0 }, + { "es8388", 0 }, { } }; MODULE_DEVICE_TABLE(i2c, es8328_id); static const struct of_device_id es8328_of_match[] = { { .compatible = "everest,es8328", }, + { .compatible = "everest,es8388", }, { } }; MODULE_DEVICE_TABLE(of, es8328_of_match); diff --git a/sound/soc/codecs/es8328.c b/sound/soc/codecs/es8328.c index 37722194b107..3f84fbd071e2 100644 --- a/sound/soc/codecs/es8328.c +++ b/sound/soc/codecs/es8328.c @@ -589,9 +589,21 @@ static int es8328_set_dai_fmt(struct snd_soc_dai *codec_dai, u8 dac_mode = 0; u8 adc_mode = 0; - /* set master/slave audio interface */ - if ((fmt & SND_SOC_DAIFMT_MASTER_MASK) != SND_SOC_DAIFMT_CBM_CFM) + switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { + case SND_SOC_DAIFMT_CBM_CFM: + /* Master serial port mode, with BCLK generated automatically */ + snd_soc_update_bits(codec, ES8328_MASTERMODE, + ES8328_MASTERMODE_MSC, + ES8328_MASTERMODE_MSC); + break; + case SND_SOC_DAIFMT_CBS_CFS: + /* Slave serial port mode */ + snd_soc_update_bits(codec, ES8328_MASTERMODE, + ES8328_MASTERMODE_MSC, 0); + break; + default: return -EINVAL; + } /* interface format */ switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) { @@ -620,10 +632,6 @@ static int es8328_set_dai_fmt(struct snd_soc_dai *codec_dai, snd_soc_update_bits(codec, ES8328_ADCCONTROL4, ES8328_ADCCONTROL4_ADCFORMAT_MASK, adc_mode); - /* Master serial port mode, with BCLK generated automatically */ - snd_soc_update_bits(codec, ES8328_MASTERMODE, - ES8328_MASTERMODE_MSC, ES8328_MASTERMODE_MSC); - return 0; } diff --git a/sound/soc/dwc/designware_i2s.c b/sound/soc/dwc/designware_i2s.c index bdf8398cbc81..9c46e4112026 100644 --- a/sound/soc/dwc/designware_i2s.c +++ b/sound/soc/dwc/designware_i2s.c @@ -121,9 +121,14 @@ static irqreturn_t i2s_irq_handler(int irq, void *dev_id) irq_valid = true; } - /* Data available. Record mode not supported in PIO mode */ - if (isr[i] & ISR_RXDA) + /* + * Data available. Retrieve samples from FIFO + * NOTE: Only two channels supported + */ + if ((isr[i] & ISR_RXDA) && (i == 0) && dev->use_pio) { + dw_pcm_pop_rx(dev); irq_valid = true; + } /* Error Handling: TX */ if (isr[i] & ISR_TXFO) { diff --git a/sound/soc/dwc/designware_pcm.c b/sound/soc/dwc/designware_pcm.c index 4a83a22fa3cb..459ec861e6b6 100644 --- a/sound/soc/dwc/designware_pcm.c +++ b/sound/soc/dwc/designware_pcm.c @@ -41,10 +41,33 @@ static unsigned int dw_pcm_tx_##sample_bits(struct dw_i2s_dev *dev, \ return tx_ptr; \ } +#define dw_pcm_rx_fn(sample_bits) \ +static unsigned int dw_pcm_rx_##sample_bits(struct dw_i2s_dev *dev, \ + struct snd_pcm_runtime *runtime, unsigned int rx_ptr, \ + bool *period_elapsed) \ +{ \ + u##sample_bits (*p)[2] = (void *)runtime->dma_area; \ + unsigned int period_pos = rx_ptr % runtime->period_size; \ + int i; \ +\ + for (i = 0; i < dev->fifo_th; i++) { \ + p[rx_ptr][0] = ioread32(dev->i2s_base + LRBR_LTHR(0)); \ + p[rx_ptr][1] = ioread32(dev->i2s_base + RRBR_RTHR(0)); \ + period_pos++; \ + if (++rx_ptr >= runtime->buffer_size) \ + rx_ptr = 0; \ + } \ + *period_elapsed = period_pos >= runtime->period_size; \ + return rx_ptr; \ +} + dw_pcm_tx_fn(16); dw_pcm_tx_fn(32); +dw_pcm_rx_fn(16); +dw_pcm_rx_fn(32); #undef dw_pcm_tx_fn +#undef dw_pcm_rx_fn static const struct snd_pcm_hardware dw_pcm_hardware = { .info = SNDRV_PCM_INFO_INTERLEAVED | @@ -57,6 +80,7 @@ static const struct snd_pcm_hardware dw_pcm_hardware = { .rate_min = 32000, .rate_max = 48000, .formats = SNDRV_PCM_FMTBIT_S16_LE | + SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S32_LE, .channels_min = 2, .channels_max = 2, @@ -68,27 +92,51 @@ static const struct snd_pcm_hardware dw_pcm_hardware = { .fifo_size = 16, }; -void dw_pcm_push_tx(struct dw_i2s_dev *dev) +static void dw_pcm_transfer(struct dw_i2s_dev *dev, bool push) { - struct snd_pcm_substream *tx_substream; - bool tx_active, period_elapsed; + struct snd_pcm_substream *substream; + bool active, period_elapsed; rcu_read_lock(); - tx_substream = rcu_dereference(dev->tx_substream); - tx_active = tx_substream && snd_pcm_running(tx_substream); - if (tx_active) { - unsigned int tx_ptr = READ_ONCE(dev->tx_ptr); - unsigned int new_tx_ptr = dev->tx_fn(dev, tx_substream->runtime, - tx_ptr, &period_elapsed); - cmpxchg(&dev->tx_ptr, tx_ptr, new_tx_ptr); + if (push) + substream = rcu_dereference(dev->tx_substream); + else + substream = rcu_dereference(dev->rx_substream); + active = substream && snd_pcm_running(substream); + if (active) { + unsigned int ptr; + unsigned int new_ptr; + + if (push) { + ptr = READ_ONCE(dev->tx_ptr); + new_ptr = dev->tx_fn(dev, substream->runtime, ptr, + &period_elapsed); + cmpxchg(&dev->tx_ptr, ptr, new_ptr); + } else { + ptr = READ_ONCE(dev->rx_ptr); + new_ptr = dev->rx_fn(dev, substream->runtime, ptr, + &period_elapsed); + cmpxchg(&dev->rx_ptr, ptr, new_ptr); + } if (period_elapsed) - snd_pcm_period_elapsed(tx_substream); + snd_pcm_period_elapsed(substream); } rcu_read_unlock(); } + +void dw_pcm_push_tx(struct dw_i2s_dev *dev) +{ + dw_pcm_transfer(dev, true); +} EXPORT_SYMBOL_GPL(dw_pcm_push_tx); +void dw_pcm_pop_rx(struct dw_i2s_dev *dev) +{ + dw_pcm_transfer(dev, false); +} +EXPORT_SYMBOL_GPL(dw_pcm_pop_rx); + static int dw_pcm_open(struct snd_pcm_substream *substream) { struct snd_pcm_runtime *runtime = substream->runtime; @@ -126,20 +174,18 @@ static int dw_pcm_hw_params(struct snd_pcm_substream *substream, switch (params_format(hw_params)) { case SNDRV_PCM_FORMAT_S16_LE: dev->tx_fn = dw_pcm_tx_16; + dev->rx_fn = dw_pcm_rx_16; break; + case SNDRV_PCM_FORMAT_S24_LE: case SNDRV_PCM_FORMAT_S32_LE: dev->tx_fn = dw_pcm_tx_32; + dev->rx_fn = dw_pcm_rx_32; break; default: dev_err(dev->dev, "invalid format\n"); return -EINVAL; } - if (substream->stream != SNDRV_PCM_STREAM_PLAYBACK) { - dev_err(dev->dev, "only playback is available\n"); - return -EINVAL; - } - ret = snd_pcm_lib_malloc_pages(substream, params_buffer_bytes(hw_params)); if (ret < 0) @@ -163,13 +209,21 @@ static int dw_pcm_trigger(struct snd_pcm_substream *substream, int cmd) case SNDRV_PCM_TRIGGER_START: case SNDRV_PCM_TRIGGER_RESUME: case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: - WRITE_ONCE(dev->tx_ptr, 0); - rcu_assign_pointer(dev->tx_substream, substream); + if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { + WRITE_ONCE(dev->tx_ptr, 0); + rcu_assign_pointer(dev->tx_substream, substream); + } else { + WRITE_ONCE(dev->rx_ptr, 0); + rcu_assign_pointer(dev->rx_substream, substream); + } break; case SNDRV_PCM_TRIGGER_STOP: case SNDRV_PCM_TRIGGER_SUSPEND: case SNDRV_PCM_TRIGGER_PAUSE_PUSH: - rcu_assign_pointer(dev->tx_substream, NULL); + if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) + rcu_assign_pointer(dev->tx_substream, NULL); + else + rcu_assign_pointer(dev->rx_substream, NULL); break; default: ret = -EINVAL; @@ -183,7 +237,12 @@ static snd_pcm_uframes_t dw_pcm_pointer(struct snd_pcm_substream *substream) { struct snd_pcm_runtime *runtime = substream->runtime; struct dw_i2s_dev *dev = runtime->private_data; - snd_pcm_uframes_t pos = READ_ONCE(dev->tx_ptr); + snd_pcm_uframes_t pos; + + if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) + pos = READ_ONCE(dev->tx_ptr); + else + pos = READ_ONCE(dev->rx_ptr); return pos < runtime->buffer_size ? pos : 0; } diff --git a/sound/soc/dwc/local.h b/sound/soc/dwc/local.h index 68afd7577343..91dc70a826f8 100644 --- a/sound/soc/dwc/local.h +++ b/sound/soc/dwc/local.h @@ -105,20 +105,27 @@ struct dw_i2s_dev { struct i2s_clk_config_data config; int (*i2s_clk_cfg)(struct i2s_clk_config_data *config); - /* data related to PIO transfers (TX) */ + /* data related to PIO transfers */ bool use_pio; struct snd_pcm_substream __rcu *tx_substream; + struct snd_pcm_substream __rcu *rx_substream; unsigned int (*tx_fn)(struct dw_i2s_dev *dev, struct snd_pcm_runtime *runtime, unsigned int tx_ptr, bool *period_elapsed); + unsigned int (*rx_fn)(struct dw_i2s_dev *dev, + struct snd_pcm_runtime *runtime, unsigned int rx_ptr, + bool *period_elapsed); unsigned int tx_ptr; + unsigned int rx_ptr; }; #if IS_ENABLED(CONFIG_SND_DESIGNWARE_PCM) void dw_pcm_push_tx(struct dw_i2s_dev *dev); +void dw_pcm_pop_rx(struct dw_i2s_dev *dev); int dw_pcm_register(struct platform_device *pdev); #else void dw_pcm_push_tx(struct dw_i2s_dev *dev) { } +void dw_pcm_pop_rx(struct dw_i2s_dev *dev) { } int dw_pcm_register(struct platform_device *pdev) { return -EINVAL; diff --git a/sound/soc/fsl/efika-audio-fabric.c b/sound/soc/fsl/efika-audio-fabric.c index f200d1cfc4bd..667f4215dfc0 100644 --- a/sound/soc/fsl/efika-audio-fabric.c +++ b/sound/soc/fsl/efika-audio-fabric.c @@ -26,7 +26,6 @@ #include #include "mpc5200_dma.h" -#include "mpc5200_psc_ac97.h" #define DRV_NAME "efika-audio-fabric" diff --git a/sound/soc/fsl/fsl_sai.c b/sound/soc/fsl/fsl_sai.c index 9fadf7e31c5f..18e5ce81527d 100644 --- a/sound/soc/fsl/fsl_sai.c +++ b/sound/soc/fsl/fsl_sai.c @@ -668,7 +668,7 @@ static struct snd_soc_dai_driver fsl_sai_dai = { .playback = { .stream_name = "CPU-Playback", .channels_min = 1, - .channels_max = 2, + .channels_max = 32, .rate_min = 8000, .rate_max = 192000, .rates = SNDRV_PCM_RATE_KNOT, @@ -677,7 +677,7 @@ static struct snd_soc_dai_driver fsl_sai_dai = { .capture = { .stream_name = "CPU-Capture", .channels_min = 1, - .channels_max = 2, + .channels_max = 32, .rate_min = 8000, .rate_max = 192000, .rates = SNDRV_PCM_RATE_KNOT, diff --git a/sound/soc/fsl/mpc5200_psc_ac97.c b/sound/soc/fsl/mpc5200_psc_ac97.c index 243700cc29e6..07ee355ee385 100644 --- a/sound/soc/fsl/mpc5200_psc_ac97.c +++ b/sound/soc/fsl/mpc5200_psc_ac97.c @@ -25,7 +25,6 @@ #include #include "mpc5200_dma.h" -#include "mpc5200_psc_ac97.h" #define DRV_NAME "mpc5200-psc-ac97" diff --git a/sound/soc/fsl/mpc5200_psc_ac97.h b/sound/soc/fsl/mpc5200_psc_ac97.h deleted file mode 100644 index e881e784b270..000000000000 --- a/sound/soc/fsl/mpc5200_psc_ac97.h +++ /dev/null @@ -1,13 +0,0 @@ -/* - * Freescale MPC5200 PSC in AC97 mode - * ALSA SoC Digital Audio Interface (DAI) driver - * - */ - -#ifndef __SOUND_SOC_FSL_MPC52xx_PSC_AC97_H__ -#define __SOUND_SOC_FSL_MPC52xx_PSC_AC97_H__ - -#define MPC5200_AC97_NORMAL 0 -#define MPC5200_AC97_SPDIF 1 - -#endif /* __SOUND_SOC_FSL_MPC52xx_PSC_AC97_H__ */ diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c index 175c8227de2c..a110d3987d4a 100644 --- a/sound/soc/soc-core.c +++ b/sound/soc/soc-core.c @@ -3675,10 +3675,10 @@ void snd_soc_unregister_codec(struct device *dev) EXPORT_SYMBOL_GPL(snd_soc_unregister_codec); /* Retrieve a card's name from device tree */ -int snd_soc_of_parse_card_name_from_node(struct snd_soc_card *card, - struct device_node *np, - const char *propname) +int snd_soc_of_parse_card_name(struct snd_soc_card *card, + const char *propname) { + struct device_node *np; int ret; if (!card->dev) { @@ -3686,8 +3686,7 @@ int snd_soc_of_parse_card_name_from_node(struct snd_soc_card *card, return -EINVAL; } - if (!np) - np = card->dev->of_node; + np = card->dev->of_node; ret = of_property_read_string_index(np, propname, 0, &card->name); /* @@ -3704,7 +3703,7 @@ int snd_soc_of_parse_card_name_from_node(struct snd_soc_card *card, return 0; } -EXPORT_SYMBOL_GPL(snd_soc_of_parse_card_name_from_node); +EXPORT_SYMBOL_GPL(snd_soc_of_parse_card_name); static const struct snd_soc_dapm_widget simple_widgets[] = { SND_SOC_DAPM_MIC("Microphone", NULL), @@ -3713,17 +3712,14 @@ static const struct snd_soc_dapm_widget simple_widgets[] = { SND_SOC_DAPM_SPK("Speaker", NULL), }; -int snd_soc_of_parse_audio_simple_widgets_from_node(struct snd_soc_card *card, - struct device_node *np, +int snd_soc_of_parse_audio_simple_widgets(struct snd_soc_card *card, const char *propname) { + struct device_node *np = card->dev->of_node; struct snd_soc_dapm_widget *widgets; const char *template, *wname; int i, j, num_widgets, ret; - if (!np) - np = card->dev->of_node; - num_widgets = of_property_count_strings(np, propname); if (num_widgets < 0) { dev_err(card->dev, @@ -3794,7 +3790,7 @@ int snd_soc_of_parse_audio_simple_widgets_from_node(struct snd_soc_card *card, return 0; } -EXPORT_SYMBOL_GPL(snd_soc_of_parse_audio_simple_widgets_from_node); +EXPORT_SYMBOL_GPL(snd_soc_of_parse_audio_simple_widgets); static int snd_soc_of_get_slot_mask(struct device_node *np, const char *prop_name, @@ -3850,18 +3846,15 @@ int snd_soc_of_parse_tdm_slot(struct device_node *np, } EXPORT_SYMBOL_GPL(snd_soc_of_parse_tdm_slot); -void snd_soc_of_parse_audio_prefix_from_node(struct snd_soc_card *card, - struct device_node *np, +void snd_soc_of_parse_audio_prefix(struct snd_soc_card *card, struct snd_soc_codec_conf *codec_conf, struct device_node *of_node, const char *propname) { + struct device_node *np = card->dev->of_node; const char *str; int ret; - if (!np) - np = card->dev->of_node; - ret = of_property_read_string(np, propname, &str); if (ret < 0) { /* no prefix is not error */ @@ -3871,19 +3864,16 @@ void snd_soc_of_parse_audio_prefix_from_node(struct snd_soc_card *card, codec_conf->of_node = of_node; codec_conf->name_prefix = str; } -EXPORT_SYMBOL_GPL(snd_soc_of_parse_audio_prefix_from_node); +EXPORT_SYMBOL_GPL(snd_soc_of_parse_audio_prefix); -int snd_soc_of_parse_audio_routing_from_node(struct snd_soc_card *card, - struct device_node *np, +int snd_soc_of_parse_audio_routing(struct snd_soc_card *card, const char *propname) { + struct device_node *np = card->dev->of_node; int num_routes; struct snd_soc_dapm_route *routes; int i, ret; - if (!np) - np = card->dev->of_node; - num_routes = of_property_count_strings(np, propname); if (num_routes < 0 || num_routes & 1) { dev_err(card->dev, @@ -3930,7 +3920,7 @@ int snd_soc_of_parse_audio_routing_from_node(struct snd_soc_card *card, return 0; } -EXPORT_SYMBOL_GPL(snd_soc_of_parse_audio_routing_from_node); +EXPORT_SYMBOL_GPL(snd_soc_of_parse_audio_routing); unsigned int snd_soc_of_parse_daifmt(struct device_node *np, const char *prefix,