Commit cb42f06c authored by Linus Torvalds's avatar Linus Torvalds

Merge tag 'sound-5.3-rc4' of git://git.kernel.org/pub/scm/linux/kernel/git/tiwai/sound

Pull sound fixes from Takashi Iwai:
 "Lots of small fixes at this time since we've received the ASoC fix
  batch now.

   - Some coverage in ASoC core mostly for minor issues like NULL checks
     for DPCM and proper error handling in DAI instantiation

   - A collection of small device-specific changes in various ASoC codec
     and platform drivers

   - OF-tree refcount fixes in a few ASoC drivers

   - Fixes of memory leaks in the error paths of various ASoC / ALSA
     drivers

   - A workaround for a long-standing issue on AMD HD-audio device

   - Updates of MAINTAINERS, mail addresses, file permission fixups"

* tag 'sound-5.3-rc4' of git://git.kernel.org/pub/scm/linux/kernel/git/tiwai/sound: (38 commits)
  ALSA: firewire: fix a memory leak bug
  sound: fix a memory leak bug
  ALSA: hda - Workaround for crackled sound on AMD controller (1022:1457)
  ALSA: hiface: fix multiple memory leak bugs
  ALSA: hda - Don't override global PCM hw info flag
  ALSA: usb-audio: fix a memory leak bug
  ASoC: max98373: Remove executable bits
  ASoC: amd: acp3x: use dma address for acp3x dma driver
  ASoC: amd: acp3x: use dma_ops of parent device for acp3x dma driver
  ASoC: max98373: add 88200 and 96000 sampling rate support
  ASoC: sun4i-i2s: Incorrect SR and WSS computation
  MAINTAINERS: Update Intel ASoC drivers maintainers
  ASoC: ti: davinci-mcasp: Correct slot_width posed constraint
  ASoC: rockchip: Fix mono capture
  ASoC: Intel: Fix some acpi vs apci typo in somme comments
  ASoC: ti: davinci-mcasp: Fix clk PDIR handling for i2s master mode
  ASoC: Fail card instantiation if DAI format setup fails
  ASoC: SOF: Intel: hda: remove misleading error trace from IRQ thread
  ASoC: qcom: apq8016_sbc: Fix oops with multiple DAI links
  ASoC: dapm: fix a memory leak bug
  ...
parents 6c02b630 1be3c1fa
...@@ -8042,6 +8042,7 @@ S: Maintained ...@@ -8042,6 +8042,7 @@ S: Maintained
F: drivers/video/fbdev/i810/ F: drivers/video/fbdev/i810/
INTEL ASoC DRIVERS INTEL ASoC DRIVERS
M: Cezary Rojewski <cezary.rojewski@intel.com>
M: Pierre-Louis Bossart <pierre-louis.bossart@linux.intel.com> M: Pierre-Louis Bossart <pierre-louis.bossart@linux.intel.com>
M: Liam Girdwood <liam.r.girdwood@linux.intel.com> M: Liam Girdwood <liam.r.girdwood@linux.intel.com>
M: Jie Yang <yang.jie@linux.intel.com> M: Jie Yang <yang.jie@linux.intel.com>
...@@ -16084,7 +16085,7 @@ S: Maintained ...@@ -16084,7 +16085,7 @@ S: Maintained
F: drivers/net/ethernet/ti/netcp* F: drivers/net/ethernet/ti/netcp*
TI PCM3060 ASoC CODEC DRIVER TI PCM3060 ASoC CODEC DRIVER
M: Kirill Marinushkin <kmarinushkin@birdec.tech> M: Kirill Marinushkin <kmarinushkin@birdec.com>
L: alsa-devel@alsa-project.org (moderated for non-subscribers) L: alsa-devel@alsa-project.org (moderated for non-subscribers)
S: Maintained S: Maintained
F: Documentation/devicetree/bindings/sound/pcm3060.txt F: Documentation/devicetree/bindings/sound/pcm3060.txt
......
...@@ -141,6 +141,10 @@ inline void asoc_simple_debug_dai(struct asoc_simple_priv *priv, ...@@ -141,6 +141,10 @@ inline void asoc_simple_debug_dai(struct asoc_simple_priv *priv,
{ {
struct device *dev = simple_priv_to_dev(priv); struct device *dev = simple_priv_to_dev(priv);
/* dai might be NULL */
if (!dai)
return;
if (dai->name) if (dai->name)
dev_dbg(dev, "%s dai name = %s\n", dev_dbg(dev, "%s dai name = %s\n",
name, dai->name); name, dai->name);
......
...@@ -13,6 +13,8 @@ ...@@ -13,6 +13,8 @@
#ifndef __INCLUDE_UAPI_SOF_FW_H__ #ifndef __INCLUDE_UAPI_SOF_FW_H__
#define __INCLUDE_UAPI_SOF_FW_H__ #define __INCLUDE_UAPI_SOF_FW_H__
#include <linux/types.h>
#define SND_SOF_FW_SIG_SIZE 4 #define SND_SOF_FW_SIG_SIZE 4
#define SND_SOF_FW_ABI 1 #define SND_SOF_FW_ABI 1
#define SND_SOF_FW_SIG "Reef" #define SND_SOF_FW_SIG "Reef"
...@@ -46,8 +48,8 @@ enum snd_sof_fw_blk_type { ...@@ -46,8 +48,8 @@ enum snd_sof_fw_blk_type {
struct snd_sof_blk_hdr { struct snd_sof_blk_hdr {
enum snd_sof_fw_blk_type type; enum snd_sof_fw_blk_type type;
uint32_t size; /* bytes minus this header */ __u32 size; /* bytes minus this header */
uint32_t offset; /* offset from base */ __u32 offset; /* offset from base */
} __packed; } __packed;
/* /*
...@@ -61,8 +63,8 @@ enum snd_sof_fw_mod_type { ...@@ -61,8 +63,8 @@ enum snd_sof_fw_mod_type {
struct snd_sof_mod_hdr { struct snd_sof_mod_hdr {
enum snd_sof_fw_mod_type type; enum snd_sof_fw_mod_type type;
uint32_t size; /* bytes minus this header */ __u32 size; /* bytes minus this header */
uint32_t num_blocks; /* number of blocks */ __u32 num_blocks; /* number of blocks */
} __packed; } __packed;
/* /*
...@@ -70,9 +72,9 @@ struct snd_sof_mod_hdr { ...@@ -70,9 +72,9 @@ struct snd_sof_mod_hdr {
*/ */
struct snd_sof_fw_header { struct snd_sof_fw_header {
unsigned char sig[SND_SOF_FW_SIG_SIZE]; /* "Reef" */ unsigned char sig[SND_SOF_FW_SIG_SIZE]; /* "Reef" */
uint32_t file_size; /* size of file minus this header */ __u32 file_size; /* size of file minus this header */
uint32_t num_modules; /* number of modules */ __u32 num_modules; /* number of modules */
uint32_t abi; /* version of header format */ __u32 abi; /* version of header format */
} __packed; } __packed;
#endif #endif
...@@ -9,6 +9,8 @@ ...@@ -9,6 +9,8 @@
#ifndef __INCLUDE_UAPI_SOUND_SOF_USER_HEADER_H__ #ifndef __INCLUDE_UAPI_SOUND_SOF_USER_HEADER_H__
#define __INCLUDE_UAPI_SOUND_SOF_USER_HEADER_H__ #define __INCLUDE_UAPI_SOUND_SOF_USER_HEADER_H__
#include <linux/types.h>
/* /*
* Header for all non IPC ABI data. * Header for all non IPC ABI data.
* *
...@@ -16,12 +18,12 @@ ...@@ -16,12 +18,12 @@
* Used by any bespoke component data structures or binary blobs. * Used by any bespoke component data structures or binary blobs.
*/ */
struct sof_abi_hdr { struct sof_abi_hdr {
uint32_t magic; /**< 'S', 'O', 'F', '\0' */ __u32 magic; /**< 'S', 'O', 'F', '\0' */
uint32_t type; /**< component specific type */ __u32 type; /**< component specific type */
uint32_t size; /**< size in bytes of data excl. this struct */ __u32 size; /**< size in bytes of data excl. this struct */
uint32_t abi; /**< SOF ABI version */ __u32 abi; /**< SOF ABI version */
uint32_t reserved[4]; /**< reserved for future use */ __u32 reserved[4]; /**< reserved for future use */
uint32_t data[0]; /**< Component data - opaque to core */ __u32 data[0]; /**< Component data - opaque to core */
} __packed; } __packed;
#endif #endif
...@@ -37,7 +37,7 @@ int iso_packets_buffer_init(struct iso_packets_buffer *b, struct fw_unit *unit, ...@@ -37,7 +37,7 @@ int iso_packets_buffer_init(struct iso_packets_buffer *b, struct fw_unit *unit,
packets_per_page = PAGE_SIZE / packet_size; packets_per_page = PAGE_SIZE / packet_size;
if (WARN_ON(!packets_per_page)) { if (WARN_ON(!packets_per_page)) {
err = -EINVAL; err = -EINVAL;
goto error; goto err_packets;
} }
pages = DIV_ROUND_UP(count, packets_per_page); pages = DIV_ROUND_UP(count, packets_per_page);
......
...@@ -598,11 +598,9 @@ static int azx_pcm_open(struct snd_pcm_substream *substream) ...@@ -598,11 +598,9 @@ static int azx_pcm_open(struct snd_pcm_substream *substream)
} }
runtime->private_data = azx_dev; runtime->private_data = azx_dev;
if (chip->gts_present)
azx_pcm_hw.info = azx_pcm_hw.info |
SNDRV_PCM_INFO_HAS_LINK_SYNCHRONIZED_ATIME;
runtime->hw = azx_pcm_hw; runtime->hw = azx_pcm_hw;
if (chip->gts_present)
runtime->hw.info |= SNDRV_PCM_INFO_HAS_LINK_SYNCHRONIZED_ATIME;
runtime->hw.channels_min = hinfo->channels_min; runtime->hw.channels_min = hinfo->channels_min;
runtime->hw.channels_max = hinfo->channels_max; runtime->hw.channels_max = hinfo->channels_max;
runtime->hw.formats = hinfo->formats; runtime->hw.formats = hinfo->formats;
...@@ -615,6 +613,13 @@ static int azx_pcm_open(struct snd_pcm_substream *substream) ...@@ -615,6 +613,13 @@ static int azx_pcm_open(struct snd_pcm_substream *substream)
20, 20,
178000000); 178000000);
/* by some reason, the playback stream stalls on PulseAudio with
* tsched=1 when a capture stream triggers. Until we figure out the
* real cause, disable tsched mode by telling the PCM info flag.
*/
if (chip->driver_caps & AZX_DCAPS_AMD_WORKAROUND)
runtime->hw.info |= SNDRV_PCM_INFO_BATCH;
if (chip->align_buffer_size) if (chip->align_buffer_size)
/* constrain buffer sizes to be multiple of 128 /* constrain buffer sizes to be multiple of 128
bytes. This is more efficient in terms of memory bytes. This is more efficient in terms of memory
......
...@@ -31,7 +31,7 @@ ...@@ -31,7 +31,7 @@
/* 14 unused */ /* 14 unused */
#define AZX_DCAPS_CTX_WORKAROUND (1 << 15) /* X-Fi workaround */ #define AZX_DCAPS_CTX_WORKAROUND (1 << 15) /* X-Fi workaround */
#define AZX_DCAPS_POSFIX_LPIB (1 << 16) /* Use LPIB as default */ #define AZX_DCAPS_POSFIX_LPIB (1 << 16) /* Use LPIB as default */
/* 17 unused */ #define AZX_DCAPS_AMD_WORKAROUND (1 << 17) /* AMD-specific workaround */
#define AZX_DCAPS_NO_64BIT (1 << 18) /* No 64bit address */ #define AZX_DCAPS_NO_64BIT (1 << 18) /* No 64bit address */
#define AZX_DCAPS_SYNC_WRITE (1 << 19) /* sync each cmd write */ #define AZX_DCAPS_SYNC_WRITE (1 << 19) /* sync each cmd write */
#define AZX_DCAPS_OLD_SSYNC (1 << 20) /* Old SSYNC reg for ICH */ #define AZX_DCAPS_OLD_SSYNC (1 << 20) /* Old SSYNC reg for ICH */
......
...@@ -64,6 +64,7 @@ enum { ...@@ -64,6 +64,7 @@ enum {
POS_FIX_VIACOMBO, POS_FIX_VIACOMBO,
POS_FIX_COMBO, POS_FIX_COMBO,
POS_FIX_SKL, POS_FIX_SKL,
POS_FIX_FIFO,
}; };
/* Defines for ATI HD Audio support in SB450 south bridge */ /* Defines for ATI HD Audio support in SB450 south bridge */
...@@ -135,7 +136,7 @@ module_param_array(model, charp, NULL, 0444); ...@@ -135,7 +136,7 @@ module_param_array(model, charp, NULL, 0444);
MODULE_PARM_DESC(model, "Use the given board model."); MODULE_PARM_DESC(model, "Use the given board model.");
module_param_array(position_fix, int, NULL, 0444); module_param_array(position_fix, int, NULL, 0444);
MODULE_PARM_DESC(position_fix, "DMA pointer read method." MODULE_PARM_DESC(position_fix, "DMA pointer read method."
"(-1 = system default, 0 = auto, 1 = LPIB, 2 = POSBUF, 3 = VIACOMBO, 4 = COMBO, 5 = SKL+)."); "(-1 = system default, 0 = auto, 1 = LPIB, 2 = POSBUF, 3 = VIACOMBO, 4 = COMBO, 5 = SKL+, 6 = FIFO).");
module_param_array(bdl_pos_adj, int, NULL, 0644); module_param_array(bdl_pos_adj, int, NULL, 0644);
MODULE_PARM_DESC(bdl_pos_adj, "BDL position adjustment offset."); MODULE_PARM_DESC(bdl_pos_adj, "BDL position adjustment offset.");
module_param_array(probe_mask, int, NULL, 0444); module_param_array(probe_mask, int, NULL, 0444);
...@@ -332,6 +333,11 @@ enum { ...@@ -332,6 +333,11 @@ enum {
#define AZX_DCAPS_PRESET_ATI_HDMI_NS \ #define AZX_DCAPS_PRESET_ATI_HDMI_NS \
(AZX_DCAPS_PRESET_ATI_HDMI | AZX_DCAPS_SNOOP_OFF) (AZX_DCAPS_PRESET_ATI_HDMI | AZX_DCAPS_SNOOP_OFF)
/* quirks for AMD SB */
#define AZX_DCAPS_PRESET_AMD_SB \
(AZX_DCAPS_NO_TCSEL | AZX_DCAPS_SYNC_WRITE | AZX_DCAPS_AMD_WORKAROUND |\
AZX_DCAPS_SNOOP_TYPE(ATI) | AZX_DCAPS_PM_RUNTIME)
/* quirks for Nvidia */ /* quirks for Nvidia */
#define AZX_DCAPS_PRESET_NVIDIA \ #define AZX_DCAPS_PRESET_NVIDIA \
(AZX_DCAPS_NO_MSI | AZX_DCAPS_CORBRP_SELF_CLEAR |\ (AZX_DCAPS_NO_MSI | AZX_DCAPS_CORBRP_SELF_CLEAR |\
...@@ -841,6 +847,49 @@ static unsigned int azx_via_get_position(struct azx *chip, ...@@ -841,6 +847,49 @@ static unsigned int azx_via_get_position(struct azx *chip,
return bound_pos + mod_dma_pos; return bound_pos + mod_dma_pos;
} }
#define AMD_FIFO_SIZE 32
/* get the current DMA position with FIFO size correction */
static unsigned int azx_get_pos_fifo(struct azx *chip, struct azx_dev *azx_dev)
{
struct snd_pcm_substream *substream = azx_dev->core.substream;
struct snd_pcm_runtime *runtime = substream->runtime;
unsigned int pos, delay;
pos = snd_hdac_stream_get_pos_lpib(azx_stream(azx_dev));
if (!runtime)
return pos;
runtime->delay = AMD_FIFO_SIZE;
delay = frames_to_bytes(runtime, AMD_FIFO_SIZE);
if (azx_dev->insufficient) {
if (pos < delay) {
delay = pos;
runtime->delay = bytes_to_frames(runtime, pos);
} else {
azx_dev->insufficient = 0;
}
}
/* correct the DMA position for capture stream */
if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) {
if (pos < delay)
pos += azx_dev->core.bufsize;
pos -= delay;
}
return pos;
}
static int azx_get_delay_from_fifo(struct azx *chip, struct azx_dev *azx_dev,
unsigned int pos)
{
struct snd_pcm_substream *substream = azx_dev->core.substream;
/* just read back the calculated value in the above */
return substream->runtime->delay;
}
static unsigned int azx_skl_get_dpib_pos(struct azx *chip, static unsigned int azx_skl_get_dpib_pos(struct azx *chip,
struct azx_dev *azx_dev) struct azx_dev *azx_dev)
{ {
...@@ -1417,6 +1466,7 @@ static int check_position_fix(struct azx *chip, int fix) ...@@ -1417,6 +1466,7 @@ static int check_position_fix(struct azx *chip, int fix)
case POS_FIX_VIACOMBO: case POS_FIX_VIACOMBO:
case POS_FIX_COMBO: case POS_FIX_COMBO:
case POS_FIX_SKL: case POS_FIX_SKL:
case POS_FIX_FIFO:
return fix; return fix;
} }
...@@ -1433,6 +1483,10 @@ static int check_position_fix(struct azx *chip, int fix) ...@@ -1433,6 +1483,10 @@ static int check_position_fix(struct azx *chip, int fix)
dev_dbg(chip->card->dev, "Using VIACOMBO position fix\n"); dev_dbg(chip->card->dev, "Using VIACOMBO position fix\n");
return POS_FIX_VIACOMBO; return POS_FIX_VIACOMBO;
} }
if (chip->driver_caps & AZX_DCAPS_AMD_WORKAROUND) {
dev_dbg(chip->card->dev, "Using FIFO position fix\n");
return POS_FIX_FIFO;
}
if (chip->driver_caps & AZX_DCAPS_POSFIX_LPIB) { if (chip->driver_caps & AZX_DCAPS_POSFIX_LPIB) {
dev_dbg(chip->card->dev, "Using LPIB position fix\n"); dev_dbg(chip->card->dev, "Using LPIB position fix\n");
return POS_FIX_LPIB; return POS_FIX_LPIB;
...@@ -1453,6 +1507,7 @@ static void assign_position_fix(struct azx *chip, int fix) ...@@ -1453,6 +1507,7 @@ static void assign_position_fix(struct azx *chip, int fix)
[POS_FIX_VIACOMBO] = azx_via_get_position, [POS_FIX_VIACOMBO] = azx_via_get_position,
[POS_FIX_COMBO] = azx_get_pos_lpib, [POS_FIX_COMBO] = azx_get_pos_lpib,
[POS_FIX_SKL] = azx_get_pos_skl, [POS_FIX_SKL] = azx_get_pos_skl,
[POS_FIX_FIFO] = azx_get_pos_fifo,
}; };
chip->get_position[0] = chip->get_position[1] = callbacks[fix]; chip->get_position[0] = chip->get_position[1] = callbacks[fix];
...@@ -1467,6 +1522,9 @@ static void assign_position_fix(struct azx *chip, int fix) ...@@ -1467,6 +1522,9 @@ static void assign_position_fix(struct azx *chip, int fix)
azx_get_delay_from_lpib; azx_get_delay_from_lpib;
} }
if (fix == POS_FIX_FIFO)
chip->get_delay[0] = chip->get_delay[1] =
azx_get_delay_from_fifo;
} }
/* /*
...@@ -2447,6 +2505,9 @@ static const struct pci_device_id azx_ids[] = { ...@@ -2447,6 +2505,9 @@ static const struct pci_device_id azx_ids[] = {
/* AMD Hudson */ /* AMD Hudson */
{ PCI_DEVICE(0x1022, 0x780d), { PCI_DEVICE(0x1022, 0x780d),
.driver_data = AZX_DRIVER_GENERIC | AZX_DCAPS_PRESET_ATI_SB }, .driver_data = AZX_DRIVER_GENERIC | AZX_DCAPS_PRESET_ATI_SB },
/* AMD, X370 & co */
{ PCI_DEVICE(0x1022, 0x1457),
.driver_data = AZX_DRIVER_GENERIC | AZX_DCAPS_PRESET_AMD_SB },
/* AMD Stoney */ /* AMD Stoney */
{ PCI_DEVICE(0x1022, 0x157a), { PCI_DEVICE(0x1022, 0x157a),
.driver_data = AZX_DRIVER_GENERIC | AZX_DCAPS_PRESET_ATI_SB | .driver_data = AZX_DRIVER_GENERIC | AZX_DCAPS_PRESET_ATI_SB |
......
...@@ -31,8 +31,8 @@ struct i2s_stream_instance { ...@@ -31,8 +31,8 @@ struct i2s_stream_instance {
u16 num_pages; u16 num_pages;
u16 channels; u16 channels;
u32 xfer_resolution; u32 xfer_resolution;
struct page *pg;
u64 bytescount; u64 bytescount;
dma_addr_t dma_addr;
void __iomem *acp3x_base; void __iomem *acp3x_base;
}; };
...@@ -211,9 +211,8 @@ static irqreturn_t i2s_irq_handler(int irq, void *dev_id) ...@@ -211,9 +211,8 @@ static irqreturn_t i2s_irq_handler(int irq, void *dev_id)
static void config_acp3x_dma(struct i2s_stream_instance *rtd, int direction) static void config_acp3x_dma(struct i2s_stream_instance *rtd, int direction)
{ {
u16 page_idx; u16 page_idx;
u64 addr;
u32 low, high, val, acp_fifo_addr; u32 low, high, val, acp_fifo_addr;
struct page *pg = rtd->pg; dma_addr_t addr = rtd->dma_addr;
/* 8 scratch registers used to map one 64 bit address */ /* 8 scratch registers used to map one 64 bit address */
if (direction == SNDRV_PCM_STREAM_PLAYBACK) if (direction == SNDRV_PCM_STREAM_PLAYBACK)
...@@ -229,7 +228,6 @@ static void config_acp3x_dma(struct i2s_stream_instance *rtd, int direction) ...@@ -229,7 +228,6 @@ static void config_acp3x_dma(struct i2s_stream_instance *rtd, int direction)
for (page_idx = 0; page_idx < rtd->num_pages; page_idx++) { for (page_idx = 0; page_idx < rtd->num_pages; page_idx++) {
/* Load the low address of page int ACP SRAM through SRBM */ /* Load the low address of page int ACP SRAM through SRBM */
addr = page_to_phys(pg);
low = lower_32_bits(addr); low = lower_32_bits(addr);
high = upper_32_bits(addr); high = upper_32_bits(addr);
...@@ -239,7 +237,7 @@ static void config_acp3x_dma(struct i2s_stream_instance *rtd, int direction) ...@@ -239,7 +237,7 @@ static void config_acp3x_dma(struct i2s_stream_instance *rtd, int direction)
+ 4); + 4);
/* Move to next physically contiguos page */ /* Move to next physically contiguos page */
val += 8; val += 8;
pg++; addr += PAGE_SIZE;
} }
if (direction == SNDRV_PCM_STREAM_PLAYBACK) { if (direction == SNDRV_PCM_STREAM_PLAYBACK) {
...@@ -341,7 +339,6 @@ static int acp3x_dma_hw_params(struct snd_pcm_substream *substream, ...@@ -341,7 +339,6 @@ static int acp3x_dma_hw_params(struct snd_pcm_substream *substream,
{ {
int status; int status;
u64 size; u64 size;
struct page *pg;
struct snd_pcm_runtime *runtime = substream->runtime; struct snd_pcm_runtime *runtime = substream->runtime;
struct i2s_stream_instance *rtd = runtime->private_data; struct i2s_stream_instance *rtd = runtime->private_data;
...@@ -354,9 +351,8 @@ static int acp3x_dma_hw_params(struct snd_pcm_substream *substream, ...@@ -354,9 +351,8 @@ static int acp3x_dma_hw_params(struct snd_pcm_substream *substream,
return status; return status;
memset(substream->runtime->dma_area, 0, params_buffer_bytes(params)); memset(substream->runtime->dma_area, 0, params_buffer_bytes(params));
pg = virt_to_page(substream->dma_buffer.area); if (substream->dma_buffer.area) {
if (pg) { rtd->dma_addr = substream->dma_buffer.addr;
rtd->pg = pg;
rtd->num_pages = (PAGE_ALIGN(size) >> PAGE_SHIFT); rtd->num_pages = (PAGE_ALIGN(size) >> PAGE_SHIFT);
config_acp3x_dma(rtd, substream->stream); config_acp3x_dma(rtd, substream->stream);
status = 0; status = 0;
...@@ -385,9 +381,11 @@ static snd_pcm_uframes_t acp3x_dma_pointer(struct snd_pcm_substream *substream) ...@@ -385,9 +381,11 @@ static snd_pcm_uframes_t acp3x_dma_pointer(struct snd_pcm_substream *substream)
static int acp3x_dma_new(struct snd_soc_pcm_runtime *rtd) static int acp3x_dma_new(struct snd_soc_pcm_runtime *rtd)
{ {
struct snd_soc_component *component = snd_soc_rtdcom_lookup(rtd,
DRV_NAME);
struct device *parent = component->dev->parent;
snd_pcm_lib_preallocate_pages_for_all(rtd->pcm, SNDRV_DMA_TYPE_DEV, snd_pcm_lib_preallocate_pages_for_all(rtd->pcm, SNDRV_DMA_TYPE_DEV,
rtd->pcm->card->dev, parent, MIN_BUFFER, MAX_BUFFER);
MIN_BUFFER, MAX_BUFFER);
return 0; return 0;
} }
......
...@@ -47,6 +47,7 @@ struct cs42xx8_priv { ...@@ -47,6 +47,7 @@ struct cs42xx8_priv {
unsigned long sysclk; unsigned long sysclk;
u32 tx_channels; u32 tx_channels;
struct gpio_desc *gpiod_reset; struct gpio_desc *gpiod_reset;
u32 rate[2];
}; };
/* -127.5dB to 0dB with step of 0.5dB */ /* -127.5dB to 0dB with step of 0.5dB */
...@@ -176,21 +177,27 @@ static const struct snd_soc_dapm_route cs42xx8_adc3_dapm_routes[] = { ...@@ -176,21 +177,27 @@ static const struct snd_soc_dapm_route cs42xx8_adc3_dapm_routes[] = {
}; };
struct cs42xx8_ratios { struct cs42xx8_ratios {
unsigned int ratio; unsigned int mfreq;
unsigned char speed; unsigned int min_mclk;
unsigned char mclk; unsigned int max_mclk;
unsigned int ratio[3];
}; };
/*
* According to reference mannual, define the cs42xx8_ratio struct
* MFreq2 | MFreq1 | MFreq0 | Description | SSM | DSM | QSM |
* 0 | 0 | 0 |1.029MHz to 12.8MHz | 256 | 128 | 64 |
* 0 | 0 | 1 |1.536MHz to 19.2MHz | 384 | 192 | 96 |
* 0 | 1 | 0 |2.048MHz to 25.6MHz | 512 | 256 | 128 |
* 0 | 1 | 1 |3.072MHz to 38.4MHz | 768 | 384 | 192 |
* 1 | x | x |4.096MHz to 51.2MHz |1024 | 512 | 256 |
*/
static const struct cs42xx8_ratios cs42xx8_ratios[] = { static const struct cs42xx8_ratios cs42xx8_ratios[] = {
{ 64, CS42XX8_FM_QUAD, CS42XX8_FUNCMOD_MFREQ_256(4) }, { 0, 1029000, 12800000, {256, 128, 64} },
{ 96, CS42XX8_FM_QUAD, CS42XX8_FUNCMOD_MFREQ_384(4) }, { 2, 1536000, 19200000, {384, 192, 96} },
{ 128, CS42XX8_FM_QUAD, CS42XX8_FUNCMOD_MFREQ_512(4) }, { 4, 2048000, 25600000, {512, 256, 128} },
{ 192, CS42XX8_FM_QUAD, CS42XX8_FUNCMOD_MFREQ_768(4) }, { 6, 3072000, 38400000, {768, 384, 192} },
{ 256, CS42XX8_FM_SINGLE, CS42XX8_FUNCMOD_MFREQ_256(1) }, { 8, 4096000, 51200000, {1024, 512, 256} },
{ 384, CS42XX8_FM_SINGLE, CS42XX8_FUNCMOD_MFREQ_384(1) },
{ 512, CS42XX8_FM_SINGLE, CS42XX8_FUNCMOD_MFREQ_512(1) },
{ 768, CS42XX8_FM_SINGLE, CS42XX8_FUNCMOD_MFREQ_768(1) },
{ 1024, CS42XX8_FM_SINGLE, CS42XX8_FUNCMOD_MFREQ_1024(1) }
}; };
static int cs42xx8_set_dai_sysclk(struct snd_soc_dai *codec_dai, static int cs42xx8_set_dai_sysclk(struct snd_soc_dai *codec_dai,
...@@ -257,14 +264,68 @@ static int cs42xx8_hw_params(struct snd_pcm_substream *substream, ...@@ -257,14 +264,68 @@ static int cs42xx8_hw_params(struct snd_pcm_substream *substream,
struct snd_soc_component *component = dai->component; struct snd_soc_component *component = dai->component;
struct cs42xx8_priv *cs42xx8 = snd_soc_component_get_drvdata(component); struct cs42xx8_priv *cs42xx8 = snd_soc_component_get_drvdata(component);
bool tx = substream->stream == SNDRV_PCM_STREAM_PLAYBACK; bool tx = substream->stream == SNDRV_PCM_STREAM_PLAYBACK;
u32 ratio = cs42xx8->sysclk / params_rate(params); u32 ratio[2];
u32 i, fm, val, mask; u32 rate[2];
u32 fm[2];
u32 i, val, mask;
bool condition1, condition2;
if (tx) if (tx)
cs42xx8->tx_channels = params_channels(params); cs42xx8->tx_channels = params_channels(params);
rate[tx] = params_rate(params);
rate[!tx] = cs42xx8->rate[!tx];
ratio[tx] = rate[tx] > 0 ? cs42xx8->sysclk / rate[tx] : 0;
ratio[!tx] = rate[!tx] > 0 ? cs42xx8->sysclk / rate[!tx] : 0;
/* Get functional mode for tx and rx according to rate */
for (i = 0; i < 2; i++) {
if (cs42xx8->slave_mode) {
fm[i] = CS42XX8_FM_AUTO;
} else {
if (rate[i] < 50000) {
fm[i] = CS42XX8_FM_SINGLE;
} else if (rate[i] > 50000 && rate[i] < 100000) {
fm[i] = CS42XX8_FM_DOUBLE;
} else if (rate[i] > 100000 && rate[i] < 200000) {
fm[i] = CS42XX8_FM_QUAD;
} else {
dev_err(component->dev,
"unsupported sample rate\n");
return -EINVAL;
}
}
}
for (i = 0; i < ARRAY_SIZE(cs42xx8_ratios); i++) { for (i = 0; i < ARRAY_SIZE(cs42xx8_ratios); i++) {
if (cs42xx8_ratios[i].ratio == ratio) /* Is the ratio[tx] valid ? */
condition1 = ((fm[tx] == CS42XX8_FM_AUTO) ?
(cs42xx8_ratios[i].ratio[0] == ratio[tx] ||
cs42xx8_ratios[i].ratio[1] == ratio[tx] ||
cs42xx8_ratios[i].ratio[2] == ratio[tx]) :
(cs42xx8_ratios[i].ratio[fm[tx]] == ratio[tx])) &&
cs42xx8->sysclk >= cs42xx8_ratios[i].min_mclk &&
cs42xx8->sysclk <= cs42xx8_ratios[i].max_mclk;
if (!ratio[tx])
condition1 = true;
/* Is the ratio[!tx] valid ? */
condition2 = ((fm[!tx] == CS42XX8_FM_AUTO) ?
(cs42xx8_ratios[i].ratio[0] == ratio[!tx] ||
cs42xx8_ratios[i].ratio[1] == ratio[!tx] ||
cs42xx8_ratios[i].ratio[2] == ratio[!tx]) :
(cs42xx8_ratios[i].ratio[fm[!tx]] == ratio[!tx]));
if (!ratio[!tx])
condition2 = true;
/*
* Both ratio[tx] and ratio[!tx] is valid, then we get
* a proper MFreq.
*/
if (condition1 && condition2)
break; break;
} }
...@@ -273,15 +334,31 @@ static int cs42xx8_hw_params(struct snd_pcm_substream *substream, ...@@ -273,15 +334,31 @@ static int cs42xx8_hw_params(struct snd_pcm_substream *substream,
return -EINVAL; return -EINVAL;
} }
mask = CS42XX8_FUNCMOD_MFREQ_MASK; cs42xx8->rate[tx] = params_rate(params);
val = cs42xx8_ratios[i].mclk;
fm = cs42xx8->slave_mode ? CS42XX8_FM_AUTO : cs42xx8_ratios[i].speed; mask = CS42XX8_FUNCMOD_MFREQ_MASK;
val = cs42xx8_ratios[i].mfreq;
regmap_update_bits(cs42xx8->regmap, CS42XX8_FUNCMOD, regmap_update_bits(cs42xx8->regmap, CS42XX8_FUNCMOD,
CS42XX8_FUNCMOD_xC_FM_MASK(tx) | mask, CS42XX8_FUNCMOD_xC_FM_MASK(tx) | mask,
CS42XX8_FUNCMOD_xC_FM(tx, fm) | val); CS42XX8_FUNCMOD_xC_FM(tx, fm[tx]) | val);
return 0;
}
static int cs42xx8_hw_free(struct snd_pcm_substream *substream,
struct snd_soc_dai *dai)
{
struct snd_soc_component *component = dai->component;
struct cs42xx8_priv *cs42xx8 = snd_soc_component_get_drvdata(component);
bool tx = substream->stream == SNDRV_PCM_STREAM_PLAYBACK;
/* Clear stored rate */
cs42xx8->rate[tx] = 0;
regmap_update_bits(cs42xx8->regmap, CS42XX8_FUNCMOD,
CS42XX8_FUNCMOD_xC_FM_MASK(tx),
CS42XX8_FUNCMOD_xC_FM(tx, CS42XX8_FM_AUTO));
return 0; return 0;
} }
...@@ -302,6 +379,7 @@ static const struct snd_soc_dai_ops cs42xx8_dai_ops = { ...@@ -302,6 +379,7 @@ static const struct snd_soc_dai_ops cs42xx8_dai_ops = {
.set_fmt = cs42xx8_set_dai_fmt, .set_fmt = cs42xx8_set_dai_fmt,
.set_sysclk = cs42xx8_set_dai_sysclk, .set_sysclk = cs42xx8_set_dai_sysclk,
.hw_params = cs42xx8_hw_params, .hw_params = cs42xx8_hw_params,
.hw_free = cs42xx8_hw_free,
.digital_mute = cs42xx8_digital_mute, .digital_mute = cs42xx8_digital_mute,
}; };
......
...@@ -20,20 +20,10 @@ ...@@ -20,20 +20,10 @@
#include <sound/soc-dapm.h> #include <sound/soc-dapm.h>
struct max98357a_priv { struct max98357a_priv {
struct delayed_work enable_sdmode_work;
struct gpio_desc *sdmode; struct gpio_desc *sdmode;
unsigned int sdmode_delay; unsigned int sdmode_delay;
}; };
static void max98357a_enable_sdmode_work(struct work_struct *work)
{
struct max98357a_priv *max98357a =
container_of(work, struct max98357a_priv,
enable_sdmode_work.work);
gpiod_set_value(max98357a->sdmode, 1);
}
static int max98357a_daiops_trigger(struct snd_pcm_substream *substream, static int max98357a_daiops_trigger(struct snd_pcm_substream *substream,
int cmd, struct snd_soc_dai *dai) int cmd, struct snd_soc_dai *dai)
{ {
...@@ -46,14 +36,12 @@ static int max98357a_daiops_trigger(struct snd_pcm_substream *substream, ...@@ -46,14 +36,12 @@ static int max98357a_daiops_trigger(struct snd_pcm_substream *substream,
case SNDRV_PCM_TRIGGER_START: case SNDRV_PCM_TRIGGER_START:
case SNDRV_PCM_TRIGGER_RESUME: case SNDRV_PCM_TRIGGER_RESUME:
case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
queue_delayed_work(system_power_efficient_wq, mdelay(max98357a->sdmode_delay);
&max98357a->enable_sdmode_work, gpiod_set_value(max98357a->sdmode, 1);
msecs_to_jiffies(max98357a->sdmode_delay));
break; break;
case SNDRV_PCM_TRIGGER_STOP: case SNDRV_PCM_TRIGGER_STOP:
case SNDRV_PCM_TRIGGER_SUSPEND: case SNDRV_PCM_TRIGGER_SUSPEND:
case SNDRV_PCM_TRIGGER_PAUSE_PUSH: case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
cancel_delayed_work_sync(&max98357a->enable_sdmode_work);
gpiod_set_value(max98357a->sdmode, 0); gpiod_set_value(max98357a->sdmode, 0);
break; break;
} }
...@@ -112,30 +100,25 @@ static int max98357a_platform_probe(struct platform_device *pdev) ...@@ -112,30 +100,25 @@ static int max98357a_platform_probe(struct platform_device *pdev)
int ret; int ret;
max98357a = devm_kzalloc(&pdev->dev, sizeof(*max98357a), GFP_KERNEL); max98357a = devm_kzalloc(&pdev->dev, sizeof(*max98357a), GFP_KERNEL);
if (!max98357a) if (!max98357a)
return -ENOMEM; return -ENOMEM;
max98357a->sdmode = devm_gpiod_get_optional(&pdev->dev, max98357a->sdmode = devm_gpiod_get_optional(&pdev->dev,
"sdmode", GPIOD_OUT_LOW); "sdmode", GPIOD_OUT_LOW);
if (IS_ERR(max98357a->sdmode)) if (IS_ERR(max98357a->sdmode))
return PTR_ERR(max98357a->sdmode); return PTR_ERR(max98357a->sdmode);
ret = device_property_read_u32(&pdev->dev, "sdmode-delay", ret = device_property_read_u32(&pdev->dev, "sdmode-delay",
&max98357a->sdmode_delay); &max98357a->sdmode_delay);
if (ret) { if (ret) {
max98357a->sdmode_delay = 0; max98357a->sdmode_delay = 0;
dev_dbg(&pdev->dev, dev_dbg(&pdev->dev,
"no optional property 'sdmode-delay' found, default: no delay\n"); "no optional property 'sdmode-delay' found, "
"default: no delay\n");
} }
dev_set_drvdata(&pdev->dev, max98357a); dev_set_drvdata(&pdev->dev, max98357a);
INIT_DELAYED_WORK(&max98357a->enable_sdmode_work,
max98357a_enable_sdmode_work);
return devm_snd_soc_register_component(&pdev->dev, return devm_snd_soc_register_component(&pdev->dev,
&max98357a_component_driver, &max98357a_component_driver,
&max98357a_dai_driver, 1); &max98357a_dai_driver, 1);
......
...@@ -267,6 +267,12 @@ static int max98373_dai_hw_params(struct snd_pcm_substream *substream, ...@@ -267,6 +267,12 @@ static int max98373_dai_hw_params(struct snd_pcm_substream *substream,
case 48000: case 48000:
sampling_rate = MAX98373_PCM_SR_SET1_SR_48000; sampling_rate = MAX98373_PCM_SR_SET1_SR_48000;
break; break;
case 88200:
sampling_rate = MAX98373_PCM_SR_SET1_SR_88200;
break;
case 96000:
sampling_rate = MAX98373_PCM_SR_SET1_SR_96000;
break;
default: default:
dev_err(component->dev, "rate %d not supported\n", dev_err(component->dev, "rate %d not supported\n",
params_rate(params)); params_rate(params));
......
...@@ -130,6 +130,8 @@ ...@@ -130,6 +130,8 @@
#define MAX98373_PCM_SR_SET1_SR_32000 (0x6 << 0) #define MAX98373_PCM_SR_SET1_SR_32000 (0x6 << 0)
#define MAX98373_PCM_SR_SET1_SR_44100 (0x7 << 0) #define MAX98373_PCM_SR_SET1_SR_44100 (0x7 << 0)
#define MAX98373_PCM_SR_SET1_SR_48000 (0x8 << 0) #define MAX98373_PCM_SR_SET1_SR_48000 (0x8 << 0)
#define MAX98373_PCM_SR_SET1_SR_88200 (0x9 << 0)
#define MAX98373_PCM_SR_SET1_SR_96000 (0xA << 0)
/* MAX98373_R2028_PCM_SR_SETUP_2 */ /* MAX98373_R2028_PCM_SR_SETUP_2 */
#define MAX98373_PCM_SR_SET2_SR_MASK (0xF << 4) #define MAX98373_PCM_SR_SET2_SR_MASK (0xF << 4)
......
...@@ -2,7 +2,7 @@ ...@@ -2,7 +2,7 @@
// //
// PCM3060 I2C driver // PCM3060 I2C driver
// //
// Copyright (C) 2018 Kirill Marinushkin <kmarinushkin@birdec.tech> // Copyright (C) 2018 Kirill Marinushkin <kmarinushkin@birdec.com>
#include <linux/i2c.h> #include <linux/i2c.h>
#include <linux/module.h> #include <linux/module.h>
...@@ -56,5 +56,5 @@ static struct i2c_driver pcm3060_i2c_driver = { ...@@ -56,5 +56,5 @@ static struct i2c_driver pcm3060_i2c_driver = {
module_i2c_driver(pcm3060_i2c_driver); module_i2c_driver(pcm3060_i2c_driver);
MODULE_DESCRIPTION("PCM3060 I2C driver"); MODULE_DESCRIPTION("PCM3060 I2C driver");
MODULE_AUTHOR("Kirill Marinushkin <kmarinushkin@birdec.tech>"); MODULE_AUTHOR("Kirill Marinushkin <kmarinushkin@birdec.com>");
MODULE_LICENSE("GPL v2"); MODULE_LICENSE("GPL v2");
...@@ -2,7 +2,7 @@ ...@@ -2,7 +2,7 @@
// //
// PCM3060 SPI driver // PCM3060 SPI driver
// //
// Copyright (C) 2018 Kirill Marinushkin <kmarinushkin@birdec.tech> // Copyright (C) 2018 Kirill Marinushkin <kmarinushkin@birdec.com>
#include <linux/module.h> #include <linux/module.h>
#include <linux/spi/spi.h> #include <linux/spi/spi.h>
...@@ -55,5 +55,5 @@ static struct spi_driver pcm3060_spi_driver = { ...@@ -55,5 +55,5 @@ static struct spi_driver pcm3060_spi_driver = {
module_spi_driver(pcm3060_spi_driver); module_spi_driver(pcm3060_spi_driver);
MODULE_DESCRIPTION("PCM3060 SPI driver"); MODULE_DESCRIPTION("PCM3060 SPI driver");
MODULE_AUTHOR("Kirill Marinushkin <kmarinushkin@birdec.tech>"); MODULE_AUTHOR("Kirill Marinushkin <kmarinushkin@birdec.com>");
MODULE_LICENSE("GPL v2"); MODULE_LICENSE("GPL v2");
...@@ -2,7 +2,7 @@ ...@@ -2,7 +2,7 @@
// //
// PCM3060 codec driver // PCM3060 codec driver
// //
// Copyright (C) 2018 Kirill Marinushkin <kmarinushkin@birdec.tech> // Copyright (C) 2018 Kirill Marinushkin <kmarinushkin@birdec.com>
#include <linux/module.h> #include <linux/module.h>
#include <sound/pcm_params.h> #include <sound/pcm_params.h>
...@@ -342,5 +342,5 @@ int pcm3060_probe(struct device *dev) ...@@ -342,5 +342,5 @@ int pcm3060_probe(struct device *dev)
EXPORT_SYMBOL(pcm3060_probe); EXPORT_SYMBOL(pcm3060_probe);
MODULE_DESCRIPTION("PCM3060 codec driver"); MODULE_DESCRIPTION("PCM3060 codec driver");
MODULE_AUTHOR("Kirill Marinushkin <kmarinushkin@birdec.tech>"); MODULE_AUTHOR("Kirill Marinushkin <kmarinushkin@birdec.com>");
MODULE_LICENSE("GPL v2"); MODULE_LICENSE("GPL v2");
...@@ -2,7 +2,7 @@ ...@@ -2,7 +2,7 @@
/* /*
* PCM3060 codec driver * PCM3060 codec driver
* *
* Copyright (C) 2018 Kirill Marinushkin <kmarinushkin@birdec.tech> * Copyright (C) 2018 Kirill Marinushkin <kmarinushkin@birdec.com>
*/ */
#ifndef _SND_SOC_PCM3060_H #ifndef _SND_SOC_PCM3060_H
......
...@@ -39,7 +39,7 @@ static const struct reg_sequence init_list[] = { ...@@ -39,7 +39,7 @@ static const struct reg_sequence init_list[] = {
{ RT1011_POWER_9, 0xa840 }, { RT1011_POWER_9, 0xa840 },
{ RT1011_ADC_SET_5, 0x0a20 }, { RT1011_ADC_SET_5, 0x0a20 },
{ RT1011_DAC_SET_2, 0xa232 }, { RT1011_DAC_SET_2, 0xa032 },
{ RT1011_ADC_SET_1, 0x2925 }, { RT1011_ADC_SET_1, 0x2925 },
{ RT1011_SPK_PRO_DC_DET_1, 0xb00c }, { RT1011_SPK_PRO_DC_DET_1, 0xb00c },
...@@ -1917,7 +1917,7 @@ static int rt1011_set_bias_level(struct snd_soc_component *component, ...@@ -1917,7 +1917,7 @@ static int rt1011_set_bias_level(struct snd_soc_component *component,
snd_soc_component_write(component, snd_soc_component_write(component,
RT1011_SYSTEM_RESET_2, 0x0000); RT1011_SYSTEM_RESET_2, 0x0000);
snd_soc_component_write(component, snd_soc_component_write(component,
RT1011_SYSTEM_RESET_3, 0x0000); RT1011_SYSTEM_RESET_3, 0x0001);
snd_soc_component_write(component, snd_soc_component_write(component,
RT1011_SYSTEM_RESET_1, 0x003f); RT1011_SYSTEM_RESET_1, 0x003f);
snd_soc_component_write(component, snd_soc_component_write(component,
......
File mode changed from 100755 to 100644
File mode changed from 100755 to 100644
...@@ -63,6 +63,7 @@ static int graph_get_dai_id(struct device_node *ep) ...@@ -63,6 +63,7 @@ static int graph_get_dai_id(struct device_node *ep)
struct device_node *endpoint; struct device_node *endpoint;
struct of_endpoint info; struct of_endpoint info;
int i, id; int i, id;
const u32 *reg;
int ret; int ret;
/* use driver specified DAI ID if exist */ /* use driver specified DAI ID if exist */
...@@ -83,8 +84,9 @@ static int graph_get_dai_id(struct device_node *ep) ...@@ -83,8 +84,9 @@ static int graph_get_dai_id(struct device_node *ep)
return info.id; return info.id;
node = of_get_parent(ep); node = of_get_parent(ep);
reg = of_get_property(node, "reg", NULL);
of_node_put(node); of_node_put(node);
if (of_get_property(node, "reg", NULL)) if (reg)
return info.port; return info.port;
} }
node = of_graph_get_port_parent(ep); node = of_graph_get_port_parent(ep);
...@@ -208,10 +210,6 @@ static int graph_dai_link_of_dpcm(struct asoc_simple_priv *priv, ...@@ -208,10 +210,6 @@ static int graph_dai_link_of_dpcm(struct asoc_simple_priv *priv,
dev_dbg(dev, "link_of DPCM (%pOF)\n", ep); dev_dbg(dev, "link_of DPCM (%pOF)\n", ep);
of_node_put(ports);
of_node_put(port);
of_node_put(node);
if (li->cpu) { if (li->cpu) {
int is_single_links = 0; int is_single_links = 0;
...@@ -229,17 +227,17 @@ static int graph_dai_link_of_dpcm(struct asoc_simple_priv *priv, ...@@ -229,17 +227,17 @@ static int graph_dai_link_of_dpcm(struct asoc_simple_priv *priv,
ret = asoc_simple_parse_cpu(ep, dai_link, &is_single_links); ret = asoc_simple_parse_cpu(ep, dai_link, &is_single_links);
if (ret) if (ret)
return ret; goto out_put_node;
ret = asoc_simple_parse_clk_cpu(dev, ep, dai_link, dai); ret = asoc_simple_parse_clk_cpu(dev, ep, dai_link, dai);
if (ret < 0) if (ret < 0)
return ret; goto out_put_node;
ret = asoc_simple_set_dailink_name(dev, dai_link, ret = asoc_simple_set_dailink_name(dev, dai_link,
"fe.%s", "fe.%s",
cpus->dai_name); cpus->dai_name);
if (ret < 0) if (ret < 0)
return ret; goto out_put_node;
/* card->num_links includes Codec */ /* card->num_links includes Codec */
asoc_simple_canonicalize_cpu(dai_link, is_single_links); asoc_simple_canonicalize_cpu(dai_link, is_single_links);
...@@ -263,17 +261,17 @@ static int graph_dai_link_of_dpcm(struct asoc_simple_priv *priv, ...@@ -263,17 +261,17 @@ static int graph_dai_link_of_dpcm(struct asoc_simple_priv *priv,
ret = asoc_simple_parse_codec(ep, dai_link); ret = asoc_simple_parse_codec(ep, dai_link);
if (ret < 0) if (ret < 0)
return ret; goto out_put_node;
ret = asoc_simple_parse_clk_codec(dev, ep, dai_link, dai); ret = asoc_simple_parse_clk_codec(dev, ep, dai_link, dai);
if (ret < 0) if (ret < 0)
return ret; goto out_put_node;
ret = asoc_simple_set_dailink_name(dev, dai_link, ret = asoc_simple_set_dailink_name(dev, dai_link,
"be.%s", "be.%s",
codecs->dai_name); codecs->dai_name);
if (ret < 0) if (ret < 0)
return ret; goto out_put_node;
/* check "prefix" from top node */ /* check "prefix" from top node */
snd_soc_of_parse_node_prefix(top, cconf, codecs->of_node, snd_soc_of_parse_node_prefix(top, cconf, codecs->of_node,
...@@ -293,19 +291,23 @@ static int graph_dai_link_of_dpcm(struct asoc_simple_priv *priv, ...@@ -293,19 +291,23 @@ static int graph_dai_link_of_dpcm(struct asoc_simple_priv *priv,
ret = asoc_simple_parse_tdm(ep, dai); ret = asoc_simple_parse_tdm(ep, dai);
if (ret) if (ret)
return ret; goto out_put_node;
ret = asoc_simple_parse_daifmt(dev, cpu_ep, codec_ep, ret = asoc_simple_parse_daifmt(dev, cpu_ep, codec_ep,
NULL, &dai_link->dai_fmt); NULL, &dai_link->dai_fmt);
if (ret < 0) if (ret < 0)
return ret; goto out_put_node;
dai_link->dpcm_playback = 1; dai_link->dpcm_playback = 1;
dai_link->dpcm_capture = 1; dai_link->dpcm_capture = 1;
dai_link->ops = &graph_ops; dai_link->ops = &graph_ops;
dai_link->init = asoc_simple_dai_init; dai_link->init = asoc_simple_dai_init;
return 0; out_put_node:
of_node_put(ports);
of_node_put(port);
of_node_put(node);
return ret;
} }
static int graph_dai_link_of(struct asoc_simple_priv *priv, static int graph_dai_link_of(struct asoc_simple_priv *priv,
......
...@@ -349,6 +349,13 @@ void asoc_simple_canonicalize_platform(struct snd_soc_dai_link *dai_link) ...@@ -349,6 +349,13 @@ void asoc_simple_canonicalize_platform(struct snd_soc_dai_link *dai_link)
/* Assumes platform == cpu */ /* Assumes platform == cpu */
if (!dai_link->platforms->of_node) if (!dai_link->platforms->of_node)
dai_link->platforms->of_node = dai_link->cpus->of_node; dai_link->platforms->of_node = dai_link->cpus->of_node;
/*
* DPCM BE can be no platform.
* Alloced memory will be waste, but not leak.
*/
if (!dai_link->platforms->of_node)
dai_link->num_platforms = 0;
} }
EXPORT_SYMBOL_GPL(asoc_simple_canonicalize_platform); EXPORT_SYMBOL_GPL(asoc_simple_canonicalize_platform);
......
...@@ -124,8 +124,6 @@ static int simple_dai_link_of_dpcm(struct asoc_simple_priv *priv, ...@@ -124,8 +124,6 @@ static int simple_dai_link_of_dpcm(struct asoc_simple_priv *priv,
li->link++; li->link++;
of_node_put(node);
/* For single DAI link & old style of DT node */ /* For single DAI link & old style of DT node */
if (is_top) if (is_top)
prefix = PREFIX; prefix = PREFIX;
...@@ -147,17 +145,17 @@ static int simple_dai_link_of_dpcm(struct asoc_simple_priv *priv, ...@@ -147,17 +145,17 @@ static int simple_dai_link_of_dpcm(struct asoc_simple_priv *priv,
ret = asoc_simple_parse_cpu(np, dai_link, &is_single_links); ret = asoc_simple_parse_cpu(np, dai_link, &is_single_links);
if (ret) if (ret)
return ret; goto out_put_node;
ret = asoc_simple_parse_clk_cpu(dev, np, dai_link, dai); ret = asoc_simple_parse_clk_cpu(dev, np, dai_link, dai);
if (ret < 0) if (ret < 0)
return ret; goto out_put_node;
ret = asoc_simple_set_dailink_name(dev, dai_link, ret = asoc_simple_set_dailink_name(dev, dai_link,
"fe.%s", "fe.%s",
cpus->dai_name); cpus->dai_name);
if (ret < 0) if (ret < 0)
return ret; goto out_put_node;
asoc_simple_canonicalize_cpu(dai_link, is_single_links); asoc_simple_canonicalize_cpu(dai_link, is_single_links);
} else { } else {
...@@ -180,17 +178,17 @@ static int simple_dai_link_of_dpcm(struct asoc_simple_priv *priv, ...@@ -180,17 +178,17 @@ static int simple_dai_link_of_dpcm(struct asoc_simple_priv *priv,
ret = asoc_simple_parse_codec(np, dai_link); ret = asoc_simple_parse_codec(np, dai_link);
if (ret < 0) if (ret < 0)
return ret; goto out_put_node;
ret = asoc_simple_parse_clk_codec(dev, np, dai_link, dai); ret = asoc_simple_parse_clk_codec(dev, np, dai_link, dai);
if (ret < 0) if (ret < 0)
return ret; goto out_put_node;
ret = asoc_simple_set_dailink_name(dev, dai_link, ret = asoc_simple_set_dailink_name(dev, dai_link,
"be.%s", "be.%s",
codecs->dai_name); codecs->dai_name);
if (ret < 0) if (ret < 0)
return ret; goto out_put_node;
/* check "prefix" from top node */ /* check "prefix" from top node */
snd_soc_of_parse_node_prefix(top, cconf, codecs->of_node, snd_soc_of_parse_node_prefix(top, cconf, codecs->of_node,
...@@ -208,19 +206,21 @@ static int simple_dai_link_of_dpcm(struct asoc_simple_priv *priv, ...@@ -208,19 +206,21 @@ static int simple_dai_link_of_dpcm(struct asoc_simple_priv *priv,
ret = asoc_simple_parse_tdm(np, dai); ret = asoc_simple_parse_tdm(np, dai);
if (ret) if (ret)
return ret; goto out_put_node;
ret = asoc_simple_parse_daifmt(dev, node, codec, ret = asoc_simple_parse_daifmt(dev, node, codec,
prefix, &dai_link->dai_fmt); prefix, &dai_link->dai_fmt);
if (ret < 0) if (ret < 0)
return ret; goto out_put_node;
dai_link->dpcm_playback = 1; dai_link->dpcm_playback = 1;
dai_link->dpcm_capture = 1; dai_link->dpcm_capture = 1;
dai_link->ops = &simple_ops; dai_link->ops = &simple_ops;
dai_link->init = asoc_simple_dai_init; dai_link->init = asoc_simple_dai_init;
return 0; out_put_node:
of_node_put(node);
return ret;
} }
static int simple_dai_link_of(struct asoc_simple_priv *priv, static int simple_dai_link_of(struct asoc_simple_priv *priv,
...@@ -364,8 +364,6 @@ static int simple_for_each_link(struct asoc_simple_priv *priv, ...@@ -364,8 +364,6 @@ static int simple_for_each_link(struct asoc_simple_priv *priv,
goto error; goto error;
} }
of_node_put(codec);
/* get convert-xxx property */ /* get convert-xxx property */
memset(&adata, 0, sizeof(adata)); memset(&adata, 0, sizeof(adata));
for_each_child_of_node(node, np) for_each_child_of_node(node, np)
...@@ -387,11 +385,13 @@ static int simple_for_each_link(struct asoc_simple_priv *priv, ...@@ -387,11 +385,13 @@ static int simple_for_each_link(struct asoc_simple_priv *priv,
ret = func_noml(priv, np, codec, li, is_top); ret = func_noml(priv, np, codec, li, is_top);
if (ret < 0) { if (ret < 0) {
of_node_put(codec);
of_node_put(np); of_node_put(np);
goto error; goto error;
} }
} }
of_node_put(codec);
node = of_get_next_child(top, node); node = of_get_next_child(top, node);
} while (!is_top && node); } while (!is_top && node);
......
...@@ -437,6 +437,14 @@ static const struct acpi_gpio_mapping byt_cht_es8316_gpios[] = { ...@@ -437,6 +437,14 @@ static const struct acpi_gpio_mapping byt_cht_es8316_gpios[] = {
/* Please keep this list alphabetically sorted */ /* Please keep this list alphabetically sorted */
static const struct dmi_system_id byt_cht_es8316_quirk_table[] = { static const struct dmi_system_id byt_cht_es8316_quirk_table[] = {
{ /* Irbis NB41 */
.matches = {
DMI_MATCH(DMI_SYS_VENDOR, "IRBIS"),
DMI_MATCH(DMI_PRODUCT_NAME, "NB41"),
},
.driver_data = (void *)(BYT_CHT_ES8316_INTMIC_IN2_MAP
| BYT_CHT_ES8316_JD_INVERTED),
},
{ /* Teclast X98 Plus II */ { /* Teclast X98 Plus II */
.matches = { .matches = {
DMI_MATCH(DMI_SYS_VENDOR, "TECLAST"), DMI_MATCH(DMI_SYS_VENDOR, "TECLAST"),
......
// SPDX-License-Identifier: GPL-2.0 // SPDX-License-Identifier: GPL-2.0
/* /*
* soc-apci-intel-bxt-match.c - tables and support for BXT ACPI enumeration. * soc-acpi-intel-bxt-match.c - tables and support for BXT ACPI enumeration.
* *
* Copyright (c) 2018, Intel Corporation. * Copyright (c) 2018, Intel Corporation.
* *
......
// SPDX-License-Identifier: GPL-2.0-only // SPDX-License-Identifier: GPL-2.0-only
/* /*
* soc-apci-intel-byt-match.c - tables and support for BYT ACPI enumeration. * soc-acpi-intel-byt-match.c - tables and support for BYT ACPI enumeration.
* *
* Copyright (c) 2017, Intel Corporation. * Copyright (c) 2017, Intel Corporation.
*/ */
......
// SPDX-License-Identifier: GPL-2.0-only // SPDX-License-Identifier: GPL-2.0-only
/* /*
* soc-apci-intel-cht-match.c - tables and support for CHT ACPI enumeration. * soc-acpi-intel-cht-match.c - tables and support for CHT ACPI enumeration.
* *
* Copyright (c) 2017, Intel Corporation. * Copyright (c) 2017, Intel Corporation.
*/ */
......
// SPDX-License-Identifier: GPL-2.0 // SPDX-License-Identifier: GPL-2.0
/* /*
* soc-apci-intel-cnl-match.c - tables and support for CNL ACPI enumeration. * soc-acpi-intel-cnl-match.c - tables and support for CNL ACPI enumeration.
* *
* Copyright (c) 2018, Intel Corporation. * Copyright (c) 2018, Intel Corporation.
* *
......
// SPDX-License-Identifier: GPL-2.0 // SPDX-License-Identifier: GPL-2.0
/* /*
* soc-apci-intel-glk-match.c - tables and support for GLK ACPI enumeration. * soc-acpi-intel-glk-match.c - tables and support for GLK ACPI enumeration.
* *
* Copyright (c) 2018, Intel Corporation. * Copyright (c) 2018, Intel Corporation.
* *
......
...@@ -2,7 +2,7 @@ ...@@ -2,7 +2,7 @@
// Copyright (c) 2018, Intel Corporation. // Copyright (c) 2018, Intel Corporation.
/* /*
* soc-apci-intel-hda-match.c - tables and support for HDA+ACPI enumeration. * soc-acpi-intel-hda-match.c - tables and support for HDA+ACPI enumeration.
* *
*/ */
......
// SPDX-License-Identifier: GPL-2.0-only // SPDX-License-Identifier: GPL-2.0-only
/* /*
* soc-apci-intel-hsw-bdw-match.c - tables and support for ACPI enumeration. * soc-acpi-intel-hsw-bdw-match.c - tables and support for ACPI enumeration.
* *
* Copyright (c) 2017, Intel Corporation. * Copyright (c) 2017, Intel Corporation.
*/ */
......
// SPDX-License-Identifier: GPL-2.0 // SPDX-License-Identifier: GPL-2.0
/* /*
* soc-apci-intel-icl-match.c - tables and support for ICL ACPI enumeration. * soc-acpi-intel-icl-match.c - tables and support for ICL ACPI enumeration.
* *
* Copyright (c) 2018, Intel Corporation. * Copyright (c) 2018, Intel Corporation.
* *
......
// SPDX-License-Identifier: GPL-2.0 // SPDX-License-Identifier: GPL-2.0
/* /*
* soc-apci-intel-kbl-match.c - tables and support for KBL ACPI enumeration. * soc-acpi-intel-kbl-match.c - tables and support for KBL ACPI enumeration.
* *
* Copyright (c) 2018, Intel Corporation. * Copyright (c) 2018, Intel Corporation.
* *
......
// SPDX-License-Identifier: GPL-2.0 // SPDX-License-Identifier: GPL-2.0
/* /*
* soc-apci-intel-skl-match.c - tables and support for SKL ACPI enumeration. * soc-acpi-intel-skl-match.c - tables and support for SKL ACPI enumeration.
* *
* Copyright (c) 2018, Intel Corporation. * Copyright (c) 2018, Intel Corporation.
* *
......
...@@ -150,17 +150,17 @@ static struct apq8016_sbc_data *apq8016_sbc_parse_of(struct snd_soc_card *card) ...@@ -150,17 +150,17 @@ static struct apq8016_sbc_data *apq8016_sbc_parse_of(struct snd_soc_card *card)
link = data->dai_link; link = data->dai_link;
dlc = devm_kzalloc(dev, 2 * sizeof(*dlc), GFP_KERNEL); for_each_child_of_node(node, np) {
if (!dlc) dlc = devm_kzalloc(dev, 2 * sizeof(*dlc), GFP_KERNEL);
return ERR_PTR(-ENOMEM); if (!dlc)
return ERR_PTR(-ENOMEM);
link->cpus = &dlc[0]; link->cpus = &dlc[0];
link->platforms = &dlc[1]; link->platforms = &dlc[1];
link->num_cpus = 1; link->num_cpus = 1;
link->num_platforms = 1; link->num_platforms = 1;
for_each_child_of_node(node, np) {
cpu = of_get_child_by_name(np, "cpu"); cpu = of_get_child_by_name(np, "cpu");
codec = of_get_child_by_name(np, "codec"); codec = of_get_child_by_name(np, "codec");
......
...@@ -326,7 +326,6 @@ static int rockchip_i2s_hw_params(struct snd_pcm_substream *substream, ...@@ -326,7 +326,6 @@ static int rockchip_i2s_hw_params(struct snd_pcm_substream *substream,
val |= I2S_CHN_4; val |= I2S_CHN_4;
break; break;
case 2: case 2:
case 1:
val |= I2S_CHN_2; val |= I2S_CHN_2;
break; break;
default: default:
...@@ -459,7 +458,7 @@ static struct snd_soc_dai_driver rockchip_i2s_dai = { ...@@ -459,7 +458,7 @@ static struct snd_soc_dai_driver rockchip_i2s_dai = {
}, },
.capture = { .capture = {
.stream_name = "Capture", .stream_name = "Capture",
.channels_min = 1, .channels_min = 2,
.channels_max = 2, .channels_max = 2,
.rates = SNDRV_PCM_RATE_8000_192000, .rates = SNDRV_PCM_RATE_8000_192000,
.formats = (SNDRV_PCM_FMTBIT_S8 | .formats = (SNDRV_PCM_FMTBIT_S8 |
...@@ -659,7 +658,7 @@ static int rockchip_i2s_probe(struct platform_device *pdev) ...@@ -659,7 +658,7 @@ static int rockchip_i2s_probe(struct platform_device *pdev)
} }
if (!of_property_read_u32(node, "rockchip,capture-channels", &val)) { if (!of_property_read_u32(node, "rockchip,capture-channels", &val)) {
if (val >= 1 && val <= 8) if (val >= 2 && val <= 8)
soc_dai->capture.channels_max = val; soc_dai->capture.channels_max = val;
} }
......
...@@ -61,6 +61,37 @@ static const struct snd_kcontrol_new rk_mc_controls[] = { ...@@ -61,6 +61,37 @@ static const struct snd_kcontrol_new rk_mc_controls[] = {
SOC_DAPM_PIN_SWITCH("Speaker"), SOC_DAPM_PIN_SWITCH("Speaker"),
}; };
static int rk_jack_event(struct notifier_block *nb, unsigned long event,
void *data)
{
struct snd_soc_jack *jack = (struct snd_soc_jack *)data;
struct snd_soc_dapm_context *dapm = &jack->card->dapm;
if (event & SND_JACK_MICROPHONE)
snd_soc_dapm_force_enable_pin(dapm, "MICBIAS");
else
snd_soc_dapm_disable_pin(dapm, "MICBIAS");
snd_soc_dapm_sync(dapm);
return 0;
}
static struct notifier_block rk_jack_nb = {
.notifier_call = rk_jack_event,
};
static int rk_init(struct snd_soc_pcm_runtime *runtime)
{
/*
* The jack has already been created in the rk_98090_headset_init()
* function.
*/
snd_soc_jack_notifier_register(&headset_jack, &rk_jack_nb);
return 0;
}
static int rk_aif1_hw_params(struct snd_pcm_substream *substream, static int rk_aif1_hw_params(struct snd_pcm_substream *substream,
struct snd_pcm_hw_params *params) struct snd_pcm_hw_params *params)
{ {
...@@ -119,6 +150,7 @@ SND_SOC_DAILINK_DEFS(hifi, ...@@ -119,6 +150,7 @@ SND_SOC_DAILINK_DEFS(hifi,
static struct snd_soc_dai_link rk_dailink = { static struct snd_soc_dai_link rk_dailink = {
.name = "max98090", .name = "max98090",
.stream_name = "Audio", .stream_name = "Audio",
.init = rk_init,
.ops = &rk_aif1_ops, .ops = &rk_aif1_ops,
/* set max98090 as slave */ /* set max98090 as slave */
.dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF | .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF |
......
...@@ -284,9 +284,8 @@ static int odroid_audio_probe(struct platform_device *pdev) ...@@ -284,9 +284,8 @@ static int odroid_audio_probe(struct platform_device *pdev)
} }
of_node_put(cpu); of_node_put(cpu);
of_node_put(codec);
if (ret < 0) if (ret < 0)
return ret; goto err_put_node;
ret = snd_soc_of_get_dai_link_codecs(dev, codec, codec_link); ret = snd_soc_of_get_dai_link_codecs(dev, codec, codec_link);
if (ret < 0) if (ret < 0)
...@@ -309,7 +308,6 @@ static int odroid_audio_probe(struct platform_device *pdev) ...@@ -309,7 +308,6 @@ static int odroid_audio_probe(struct platform_device *pdev)
ret = PTR_ERR(priv->clk_i2s_bus); ret = PTR_ERR(priv->clk_i2s_bus);
goto err_put_sclk; goto err_put_sclk;
} }
of_node_put(cpu_dai);
ret = devm_snd_soc_register_card(dev, card); ret = devm_snd_soc_register_card(dev, card);
if (ret < 0) { if (ret < 0) {
...@@ -317,6 +315,8 @@ static int odroid_audio_probe(struct platform_device *pdev) ...@@ -317,6 +315,8 @@ static int odroid_audio_probe(struct platform_device *pdev)
goto err_put_clk_i2s; goto err_put_clk_i2s;
} }
of_node_put(cpu_dai);
of_node_put(codec);
return 0; return 0;
err_put_clk_i2s: err_put_clk_i2s:
...@@ -326,6 +326,8 @@ static int odroid_audio_probe(struct platform_device *pdev) ...@@ -326,6 +326,8 @@ static int odroid_audio_probe(struct platform_device *pdev)
err_put_cpu_dai: err_put_cpu_dai:
of_node_put(cpu_dai); of_node_put(cpu_dai);
snd_soc_of_put_dai_link_codecs(codec_link); snd_soc_of_put_dai_link_codecs(codec_link);
err_put_node:
of_node_put(codec);
return ret; return ret;
} }
......
...@@ -1515,8 +1515,11 @@ static int soc_probe_link_dais(struct snd_soc_card *card, ...@@ -1515,8 +1515,11 @@ static int soc_probe_link_dais(struct snd_soc_card *card,
} }
} }
if (dai_link->dai_fmt) if (dai_link->dai_fmt) {
snd_soc_runtime_set_dai_fmt(rtd, dai_link->dai_fmt); ret = snd_soc_runtime_set_dai_fmt(rtd, dai_link->dai_fmt);
if (ret)
return ret;
}
ret = soc_post_component_init(rtd, dai_link->name); ret = soc_post_component_init(rtd, dai_link->name);
if (ret) if (ret)
......
...@@ -1157,8 +1157,8 @@ static __always_inline int is_connected_ep(struct snd_soc_dapm_widget *widget, ...@@ -1157,8 +1157,8 @@ static __always_inline int is_connected_ep(struct snd_soc_dapm_widget *widget,
list_add_tail(&widget->work_list, list); list_add_tail(&widget->work_list, list);
if (custom_stop_condition && custom_stop_condition(widget, dir)) { if (custom_stop_condition && custom_stop_condition(widget, dir)) {
widget->endpoints[dir] = 1; list = NULL;
return widget->endpoints[dir]; custom_stop_condition = NULL;
} }
if ((widget->is_ep & SND_SOC_DAPM_DIR_TO_EP(dir)) && widget->connected) { if ((widget->is_ep & SND_SOC_DAPM_DIR_TO_EP(dir)) && widget->connected) {
...@@ -1195,8 +1195,8 @@ static __always_inline int is_connected_ep(struct snd_soc_dapm_widget *widget, ...@@ -1195,8 +1195,8 @@ static __always_inline int is_connected_ep(struct snd_soc_dapm_widget *widget,
* *
* Optionally, can be supplied with a function acting as a stopping condition. * Optionally, can be supplied with a function acting as a stopping condition.
* This function takes the dapm widget currently being examined and the walk * This function takes the dapm widget currently being examined and the walk
* direction as an arguments, it should return true if the walk should be * direction as an arguments, it should return true if widgets from that point
* stopped and false otherwise. * in the graph onwards should not be added to the widget list.
*/ */
static int is_connected_output_ep(struct snd_soc_dapm_widget *widget, static int is_connected_output_ep(struct snd_soc_dapm_widget *widget,
struct list_head *list, struct list_head *list,
...@@ -3706,6 +3706,8 @@ snd_soc_dapm_new_control_unlocked(struct snd_soc_dapm_context *dapm, ...@@ -3706,6 +3706,8 @@ snd_soc_dapm_new_control_unlocked(struct snd_soc_dapm_context *dapm,
dev_err(dapm->dev, "ASoC: Failed to request %s: %d\n", dev_err(dapm->dev, "ASoC: Failed to request %s: %d\n",
w->name, ret); w->name, ret);
kfree_const(w->sname);
kfree(w);
return ERR_PTR(ret); return ERR_PTR(ret);
} }
......
...@@ -101,8 +101,8 @@ static irqreturn_t cnl_ipc_irq_thread(int irq, void *context) ...@@ -101,8 +101,8 @@ static irqreturn_t cnl_ipc_irq_thread(int irq, void *context)
/* /*
* This interrupt is not shared so no need to return IRQ_NONE. * This interrupt is not shared so no need to return IRQ_NONE.
*/ */
dev_err_ratelimited(sdev->dev, dev_dbg_ratelimited(sdev->dev,
"error: nothing to do in IRQ thread\n"); "nothing to do in IPC IRQ thread\n");
} }
/* re-enable IPC interrupt */ /* re-enable IPC interrupt */
......
...@@ -224,8 +224,8 @@ irqreturn_t hda_dsp_ipc_irq_thread(int irq, void *context) ...@@ -224,8 +224,8 @@ irqreturn_t hda_dsp_ipc_irq_thread(int irq, void *context)
/* /*
* This interrupt is not shared so no need to return IRQ_NONE. * This interrupt is not shared so no need to return IRQ_NONE.
*/ */
dev_err_ratelimited(sdev->dev, dev_dbg_ratelimited(sdev->dev,
"error: nothing to do in IRQ thread\n"); "nothing to do in IPC IRQ thread\n");
} }
/* re-enable IPC interrupt */ /* re-enable IPC interrupt */
......
...@@ -1002,8 +1002,8 @@ static const struct sun4i_i2s_quirks sun50i_a64_codec_i2s_quirks = { ...@@ -1002,8 +1002,8 @@ static const struct sun4i_i2s_quirks sun50i_a64_codec_i2s_quirks = {
.field_rxchanmap = REG_FIELD(SUN4I_I2S_RX_CHAN_MAP_REG, 0, 31), .field_rxchanmap = REG_FIELD(SUN4I_I2S_RX_CHAN_MAP_REG, 0, 31),
.field_txchansel = REG_FIELD(SUN4I_I2S_TX_CHAN_SEL_REG, 0, 2), .field_txchansel = REG_FIELD(SUN4I_I2S_TX_CHAN_SEL_REG, 0, 2),
.field_rxchansel = REG_FIELD(SUN4I_I2S_RX_CHAN_SEL_REG, 0, 2), .field_rxchansel = REG_FIELD(SUN4I_I2S_RX_CHAN_SEL_REG, 0, 2),
.get_sr = sun8i_i2s_get_sr_wss, .get_sr = sun4i_i2s_get_sr,
.get_wss = sun8i_i2s_get_sr_wss, .get_wss = sun4i_i2s_get_wss,
}; };
static int sun4i_i2s_init_regmap_fields(struct device *dev, static int sun4i_i2s_init_regmap_fields(struct device *dev,
......
...@@ -195,7 +195,7 @@ static inline void mcasp_set_axr_pdir(struct davinci_mcasp *mcasp, bool enable) ...@@ -195,7 +195,7 @@ static inline void mcasp_set_axr_pdir(struct davinci_mcasp *mcasp, bool enable)
{ {
u32 bit; u32 bit;
for_each_set_bit(bit, &mcasp->pdir, PIN_BIT_AFSR) { for_each_set_bit(bit, &mcasp->pdir, PIN_BIT_AMUTE) {
if (enable) if (enable)
mcasp_set_bits(mcasp, DAVINCI_MCASP_PDIR_REG, BIT(bit)); mcasp_set_bits(mcasp, DAVINCI_MCASP_PDIR_REG, BIT(bit));
else else
...@@ -223,6 +223,7 @@ static void mcasp_start_rx(struct davinci_mcasp *mcasp) ...@@ -223,6 +223,7 @@ static void mcasp_start_rx(struct davinci_mcasp *mcasp)
if (mcasp_is_synchronous(mcasp)) { if (mcasp_is_synchronous(mcasp)) {
mcasp_set_ctl_reg(mcasp, DAVINCI_MCASP_GBLCTLX_REG, TXHCLKRST); mcasp_set_ctl_reg(mcasp, DAVINCI_MCASP_GBLCTLX_REG, TXHCLKRST);
mcasp_set_ctl_reg(mcasp, DAVINCI_MCASP_GBLCTLX_REG, TXCLKRST); mcasp_set_ctl_reg(mcasp, DAVINCI_MCASP_GBLCTLX_REG, TXCLKRST);
mcasp_set_clk_pdir(mcasp, true);
} }
/* Activate serializer(s) */ /* Activate serializer(s) */
...@@ -1256,6 +1257,28 @@ static int davinci_mcasp_trigger(struct snd_pcm_substream *substream, ...@@ -1256,6 +1257,28 @@ static int davinci_mcasp_trigger(struct snd_pcm_substream *substream,
return ret; return ret;
} }
static int davinci_mcasp_hw_rule_slot_width(struct snd_pcm_hw_params *params,
struct snd_pcm_hw_rule *rule)
{
struct davinci_mcasp_ruledata *rd = rule->private;
struct snd_mask *fmt = hw_param_mask(params, SNDRV_PCM_HW_PARAM_FORMAT);
struct snd_mask nfmt;
int i, slot_width;
snd_mask_none(&nfmt);
slot_width = rd->mcasp->slot_width;
for (i = 0; i <= SNDRV_PCM_FORMAT_LAST; i++) {
if (snd_mask_test(fmt, i)) {
if (snd_pcm_format_width(i) <= slot_width) {
snd_mask_set(&nfmt, i);
}
}
}
return snd_mask_refine(fmt, &nfmt);
}
static const unsigned int davinci_mcasp_dai_rates[] = { static const unsigned int davinci_mcasp_dai_rates[] = {
8000, 11025, 16000, 22050, 32000, 44100, 48000, 64000, 8000, 11025, 16000, 22050, 32000, 44100, 48000, 64000,
88200, 96000, 176400, 192000, 88200, 96000, 176400, 192000,
...@@ -1377,7 +1400,7 @@ static int davinci_mcasp_startup(struct snd_pcm_substream *substream, ...@@ -1377,7 +1400,7 @@ static int davinci_mcasp_startup(struct snd_pcm_substream *substream,
struct davinci_mcasp_ruledata *ruledata = struct davinci_mcasp_ruledata *ruledata =
&mcasp->ruledata[substream->stream]; &mcasp->ruledata[substream->stream];
u32 max_channels = 0; u32 max_channels = 0;
int i, dir; int i, dir, ret;
int tdm_slots = mcasp->tdm_slots; int tdm_slots = mcasp->tdm_slots;
/* Do not allow more then one stream per direction */ /* Do not allow more then one stream per direction */
...@@ -1406,6 +1429,7 @@ static int davinci_mcasp_startup(struct snd_pcm_substream *substream, ...@@ -1406,6 +1429,7 @@ static int davinci_mcasp_startup(struct snd_pcm_substream *substream,
max_channels++; max_channels++;
} }
ruledata->serializers = max_channels; ruledata->serializers = max_channels;
ruledata->mcasp = mcasp;
max_channels *= tdm_slots; max_channels *= tdm_slots;
/* /*
* If the already active stream has less channels than the calculated * If the already active stream has less channels than the calculated
...@@ -1431,20 +1455,22 @@ static int davinci_mcasp_startup(struct snd_pcm_substream *substream, ...@@ -1431,20 +1455,22 @@ static int davinci_mcasp_startup(struct snd_pcm_substream *substream,
0, SNDRV_PCM_HW_PARAM_CHANNELS, 0, SNDRV_PCM_HW_PARAM_CHANNELS,
&mcasp->chconstr[substream->stream]); &mcasp->chconstr[substream->stream]);
if (mcasp->slot_width) if (mcasp->slot_width) {
snd_pcm_hw_constraint_minmax(substream->runtime, /* Only allow formats require <= slot_width bits on the bus */
SNDRV_PCM_HW_PARAM_SAMPLE_BITS, ret = snd_pcm_hw_rule_add(substream->runtime, 0,
8, mcasp->slot_width); SNDRV_PCM_HW_PARAM_FORMAT,
davinci_mcasp_hw_rule_slot_width,
ruledata,
SNDRV_PCM_HW_PARAM_FORMAT, -1);
if (ret)
return ret;
}
/* /*
* If we rely on implicit BCLK divider setting we should * If we rely on implicit BCLK divider setting we should
* set constraints based on what we can provide. * set constraints based on what we can provide.
*/ */
if (mcasp->bclk_master && mcasp->bclk_div == 0 && mcasp->sysclk_freq) { if (mcasp->bclk_master && mcasp->bclk_div == 0 && mcasp->sysclk_freq) {
int ret;
ruledata->mcasp = mcasp;
ret = snd_pcm_hw_rule_add(substream->runtime, 0, ret = snd_pcm_hw_rule_add(substream->runtime, 0,
SNDRV_PCM_HW_PARAM_RATE, SNDRV_PCM_HW_PARAM_RATE,
davinci_mcasp_hw_rule_rate, davinci_mcasp_hw_rule_rate,
......
...@@ -275,7 +275,8 @@ static int sound_insert_unit(struct sound_unit **list, const struct file_operati ...@@ -275,7 +275,8 @@ static int sound_insert_unit(struct sound_unit **list, const struct file_operati
goto retry; goto retry;
} }
spin_unlock(&sound_loader_lock); spin_unlock(&sound_loader_lock);
return -EBUSY; r = -EBUSY;
goto fail;
} }
} }
......
...@@ -600,14 +600,13 @@ int hiface_pcm_init(struct hiface_chip *chip, u8 extra_freq) ...@@ -600,14 +600,13 @@ int hiface_pcm_init(struct hiface_chip *chip, u8 extra_freq)
ret = hiface_pcm_init_urb(&rt->out_urbs[i], chip, OUT_EP, ret = hiface_pcm_init_urb(&rt->out_urbs[i], chip, OUT_EP,
hiface_pcm_out_urb_handler); hiface_pcm_out_urb_handler);
if (ret < 0) if (ret < 0)
return ret; goto error;
} }
ret = snd_pcm_new(chip->card, "USB-SPDIF Audio", 0, 1, 0, &pcm); ret = snd_pcm_new(chip->card, "USB-SPDIF Audio", 0, 1, 0, &pcm);
if (ret < 0) { if (ret < 0) {
kfree(rt);
dev_err(&chip->dev->dev, "Cannot create pcm instance\n"); dev_err(&chip->dev->dev, "Cannot create pcm instance\n");
return ret; goto error;
} }
pcm->private_data = rt; pcm->private_data = rt;
...@@ -620,4 +619,10 @@ int hiface_pcm_init(struct hiface_chip *chip, u8 extra_freq) ...@@ -620,4 +619,10 @@ int hiface_pcm_init(struct hiface_chip *chip, u8 extra_freq)
chip->pcm = rt; chip->pcm = rt;
return 0; return 0;
error:
for (i = 0; i < PCM_N_URBS; i++)
kfree(rt->out_urbs[i].buffer);
kfree(rt);
return ret;
} }
...@@ -1043,6 +1043,7 @@ snd_usb_get_audioformat_uac3(struct snd_usb_audio *chip, ...@@ -1043,6 +1043,7 @@ snd_usb_get_audioformat_uac3(struct snd_usb_audio *chip,
pd = kzalloc(sizeof(*pd), GFP_KERNEL); pd = kzalloc(sizeof(*pd), GFP_KERNEL);
if (!pd) { if (!pd) {
kfree(fp->chmap);
kfree(fp->rate_table); kfree(fp->rate_table);
kfree(fp); kfree(fp);
return NULL; return NULL;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment