From 62ba568f7aef4beb0eda945a2b2a91b7a2b8f215 Mon Sep 17 00:00:00 2001 From: Ricardo Biehl Pasquali Date: Sat, 25 Aug 2018 16:53:23 -0300 Subject: [PATCH 001/299] ALSA: pcm: Return 0 when size < start_threshold in capture In __snd_pcm_lib_xfer(), when capture, if state is PREPARED and size is less than start_threshold nothing can be done. As there is no error, 0 is returned. Signed-off-by: Ricardo Biehl Pasquali Signed-off-by: Takashi Iwai --- sound/core/pcm_lib.c | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/sound/core/pcm_lib.c b/sound/core/pcm_lib.c index 4e6110d778bd..7f71c2449af5 100644 --- a/sound/core/pcm_lib.c +++ b/sound/core/pcm_lib.c @@ -2173,11 +2173,16 @@ snd_pcm_sframes_t __snd_pcm_lib_xfer(struct snd_pcm_substream *substream, goto _end_unlock; if (!is_playback && - runtime->status->state == SNDRV_PCM_STATE_PREPARED && - size >= runtime->start_threshold) { - err = snd_pcm_start(substream); - if (err < 0) + runtime->status->state == SNDRV_PCM_STATE_PREPARED) { + if (size >= runtime->start_threshold) { + err = snd_pcm_start(substream); + if (err < 0) + goto _end_unlock; + } else { + /* nothing to do */ + err = 0; goto _end_unlock; + } } runtime->twake = runtime->control->avail_min ? : 1; From 1bb6d9e2f682a401417f925d602de992c559b057 Mon Sep 17 00:00:00 2001 From: Colin Ian King Date: Sun, 26 Aug 2018 23:09:52 +0100 Subject: [PATCH 002/299] ALSA: hdspm: fix spelling mistake "Initializeing" -> "Initializing" Trivial fix to spelling mistake in dev_dbg message and also remove extraneous white space and repeated question marks. Signed-off-by: Colin Ian King Signed-off-by: Takashi Iwai --- sound/pci/rme9652/hdspm.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sound/pci/rme9652/hdspm.c b/sound/pci/rme9652/hdspm.c index 11b5b5e0e058..679ad0415e3b 100644 --- a/sound/pci/rme9652/hdspm.c +++ b/sound/pci/rme9652/hdspm.c @@ -6534,7 +6534,7 @@ static int snd_hdspm_create_alsa_devices(struct snd_card *card, dev_dbg(card->dev, "Update mixer controls...\n"); hdspm_update_simple_mixer_controls(hdspm); - dev_dbg(card->dev, "Initializeing complete ???\n"); + dev_dbg(card->dev, "Initializing complete?\n"); err = snd_card_register(card); if (err < 0) { From 6f128fa41f310e1f39ebcea9621d2905549ecf52 Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Mon, 27 Aug 2018 12:21:45 +0300 Subject: [PATCH 003/299] ALSA: pcm: signedness bug in snd_pcm_plug_alloc() The "frames" variable is unsigned so the error handling doesn't work properly. Signed-off-by: Dan Carpenter Signed-off-by: Takashi Iwai --- sound/core/oss/pcm_plugin.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/sound/core/oss/pcm_plugin.c b/sound/core/oss/pcm_plugin.c index 0391cb1a4f19..141c5f3a9575 100644 --- a/sound/core/oss/pcm_plugin.c +++ b/sound/core/oss/pcm_plugin.c @@ -111,7 +111,7 @@ int snd_pcm_plug_alloc(struct snd_pcm_substream *plug, snd_pcm_uframes_t frames) while (plugin->next) { if (plugin->dst_frames) frames = plugin->dst_frames(plugin, frames); - if (snd_BUG_ON(frames <= 0)) + if (snd_BUG_ON((snd_pcm_sframes_t)frames <= 0)) return -ENXIO; plugin = plugin->next; err = snd_pcm_plugin_alloc(plugin, frames); @@ -123,7 +123,7 @@ int snd_pcm_plug_alloc(struct snd_pcm_substream *plug, snd_pcm_uframes_t frames) while (plugin->prev) { if (plugin->src_frames) frames = plugin->src_frames(plugin, frames); - if (snd_BUG_ON(frames <= 0)) + if (snd_BUG_ON((snd_pcm_sframes_t)frames <= 0)) return -ENXIO; plugin = plugin->prev; err = snd_pcm_plugin_alloc(plugin, frames); From c4f1957e14444e444b35418e85069b7ab65465a5 Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Tue, 28 Aug 2018 11:46:34 +0300 Subject: [PATCH 004/299] ALSA: seq: add error check in snd_seq_system_client_init() Static checkers complain that snd_seq_create_kernel_client() can return -EBUSY here so we need to have some error handling. Signed-off-by: Dan Carpenter Signed-off-by: Takashi Iwai --- sound/core/seq/seq_system.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/sound/core/seq/seq_system.c b/sound/core/seq/seq_system.c index 8ce1d0b40dce..3b89b0adad6a 100644 --- a/sound/core/seq/seq_system.c +++ b/sound/core/seq/seq_system.c @@ -134,6 +134,10 @@ int __init snd_seq_system_client_init(void) /* register client */ sysclient = snd_seq_create_kernel_client(NULL, 0, "System"); + if (sysclient < 0) { + kfree(port); + return sysclient; + } /* register timer */ strcpy(port->name, "Timer"); From b8e131542b47b81236ecf6768c923128e1f5db6e Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Tue, 28 Aug 2018 12:49:43 +0200 Subject: [PATCH 005/299] ALSA: seq: Do error checks at creating system ports snd_seq_system_client_init() doesn't check the errors returned from its port creations. Let's do it properly and handle the error paths. Signed-off-by: Takashi Iwai --- sound/core/seq/seq_system.c | 18 +++++++++++++++--- 1 file changed, 15 insertions(+), 3 deletions(-) diff --git a/sound/core/seq/seq_system.c b/sound/core/seq/seq_system.c index 3b89b0adad6a..0dc5d5a45ecc 100644 --- a/sound/core/seq/seq_system.c +++ b/sound/core/seq/seq_system.c @@ -123,6 +123,7 @@ int __init snd_seq_system_client_init(void) { struct snd_seq_port_callback pcallbacks; struct snd_seq_port_info *port; + int err; port = kzalloc(sizeof(*port), GFP_KERNEL); if (!port) @@ -148,7 +149,10 @@ int __init snd_seq_system_client_init(void) port->flags = SNDRV_SEQ_PORT_FLG_GIVEN_PORT; port->addr.client = sysclient; port->addr.port = SNDRV_SEQ_PORT_SYSTEM_TIMER; - snd_seq_kernel_client_ctl(sysclient, SNDRV_SEQ_IOCTL_CREATE_PORT, port); + err = snd_seq_kernel_client_ctl(sysclient, SNDRV_SEQ_IOCTL_CREATE_PORT, + port); + if (err < 0) + goto error_port; /* register announcement port */ strcpy(port->name, "Announce"); @@ -158,16 +162,24 @@ int __init snd_seq_system_client_init(void) port->flags = SNDRV_SEQ_PORT_FLG_GIVEN_PORT; port->addr.client = sysclient; port->addr.port = SNDRV_SEQ_PORT_SYSTEM_ANNOUNCE; - snd_seq_kernel_client_ctl(sysclient, SNDRV_SEQ_IOCTL_CREATE_PORT, port); + err = snd_seq_kernel_client_ctl(sysclient, SNDRV_SEQ_IOCTL_CREATE_PORT, + port); + if (err < 0) + goto error_port; announce_port = port->addr.port; kfree(port); return 0; + + error_port: + snd_seq_system_client_done(); + kfree(port); + return err; } /* unregister our internal client */ -void __exit snd_seq_system_client_done(void) +void snd_seq_system_client_done(void) { int oldsysclient = sysclient; From 03486830c577d3fe49c1f2c316414552a549ff00 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Wed, 8 Aug 2018 16:56:46 +0200 Subject: [PATCH 006/299] ALSA: memalloc: Don't align the size to power-of-two The size passed to dma_alloc_coherent() doesn't have to be aligned with power-of-two, rather it should be the raw size. As a minor optimization, remove the size adjustment in the current code. Signed-off-by: Takashi Iwai --- sound/core/memalloc.c | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) diff --git a/sound/core/memalloc.c b/sound/core/memalloc.c index 753d5fc4b284..d85df01bf055 100644 --- a/sound/core/memalloc.c +++ b/sound/core/memalloc.c @@ -84,29 +84,24 @@ EXPORT_SYMBOL(snd_free_pages); /* allocate the coherent DMA pages */ static void *snd_malloc_dev_pages(struct device *dev, size_t size, dma_addr_t *dma) { - int pg; gfp_t gfp_flags; if (WARN_ON(!dma)) return NULL; - pg = get_order(size); gfp_flags = GFP_KERNEL | __GFP_COMP /* compound page lets parts be mapped */ | __GFP_NORETRY /* don't trigger OOM-killer */ | __GFP_NOWARN; /* no stack trace print - this call is non-critical */ - return dma_alloc_coherent(dev, PAGE_SIZE << pg, dma, gfp_flags); + return dma_alloc_coherent(dev, size, dma, gfp_flags); } /* free the coherent DMA pages */ static void snd_free_dev_pages(struct device *dev, size_t size, void *ptr, dma_addr_t dma) { - int pg; - if (ptr == NULL) return; - pg = get_order(size); - dma_free_coherent(dev, PAGE_SIZE << pg, ptr, dma); + dma_free_coherent(dev, size, ptr, dma); } #ifdef CONFIG_GENERIC_ALLOCATOR From 28f3f4f685d7d7226ba4ed4f78e04c75dd3a5b27 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Fri, 10 Aug 2018 14:43:37 +0200 Subject: [PATCH 007/299] ALSA: memalloc: Simplify snd_malloc_dev_pages() calls snd_malloc_dev_pages() and snd_free_dev_pages() are local functions and the parameters passed there are all contained in snd_dma_buffer object. As a code-simplification, pass snd_dma_buffer object and assign the address there like other allocators do (except for snd_malloc_pages() which is called from outside, hence we can't change easily). Only code refactoring, no functional changes. Signed-off-by: Takashi Iwai --- sound/core/memalloc.c | 18 +++++++----------- 1 file changed, 7 insertions(+), 11 deletions(-) diff --git a/sound/core/memalloc.c b/sound/core/memalloc.c index d85df01bf055..cc051bfe2f6f 100644 --- a/sound/core/memalloc.c +++ b/sound/core/memalloc.c @@ -82,26 +82,22 @@ EXPORT_SYMBOL(snd_free_pages); #ifdef CONFIG_HAS_DMA /* allocate the coherent DMA pages */ -static void *snd_malloc_dev_pages(struct device *dev, size_t size, dma_addr_t *dma) +static void snd_malloc_dev_pages(struct snd_dma_buffer *dmab, size_t size) { gfp_t gfp_flags; - if (WARN_ON(!dma)) - return NULL; gfp_flags = GFP_KERNEL | __GFP_COMP /* compound page lets parts be mapped */ | __GFP_NORETRY /* don't trigger OOM-killer */ | __GFP_NOWARN; /* no stack trace print - this call is non-critical */ - return dma_alloc_coherent(dev, size, dma, gfp_flags); + dmab->area = dma_alloc_coherent(dmab->dev.dev, size, &dmab->addr, + gfp_flags); } /* free the coherent DMA pages */ -static void snd_free_dev_pages(struct device *dev, size_t size, void *ptr, - dma_addr_t dma) +static void snd_free_dev_pages(struct snd_dma_buffer *dmab) { - if (ptr == NULL) - return; - dma_free_coherent(dev, size, ptr, dma); + dma_free_coherent(dmab->dev.dev, dmab->bytes, dmab->area, dmab->addr); } #ifdef CONFIG_GENERIC_ALLOCATOR @@ -195,7 +191,7 @@ int snd_dma_alloc_pages(int type, struct device *device, size_t size, dmab->dev.type = SNDRV_DMA_TYPE_DEV; #endif /* CONFIG_GENERIC_ALLOCATOR */ case SNDRV_DMA_TYPE_DEV: - dmab->area = snd_malloc_dev_pages(device, size, &dmab->addr); + snd_malloc_dev_pages(dmab, size); break; #endif #ifdef CONFIG_SND_DMA_SGBUF @@ -270,7 +266,7 @@ void snd_dma_free_pages(struct snd_dma_buffer *dmab) break; #endif /* CONFIG_GENERIC_ALLOCATOR */ case SNDRV_DMA_TYPE_DEV: - snd_free_dev_pages(dmab->dev.dev, dmab->bytes, dmab->area, dmab->addr); + snd_free_dev_pages(dmab); break; #endif #ifdef CONFIG_SND_DMA_SGBUF From 42e748a0b3251cca0de2c269ca106884907eb289 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Wed, 8 Aug 2018 17:01:00 +0200 Subject: [PATCH 008/299] ALSA: memalloc: Add non-cached buffer type In some cases (mainly for x86), we need the DMA coherent buffer with non-cached pages. Although this has been done in each driver side like HD-audio and intel8x0, it can be done cleaner in the core memory allocator. This patch adds the new types, SNDRV_DMA_TYPE_DEV_UC and SNDRV_DMA_TYPE_DEV_UC_SG, for allocating such non-cached buffer pages. On non-x86 architectures, they work as same as the standard SNDRV_DMA_TYPE_DEV and *_SG. One additional change by this move is that we can assure to pass the non-cached pgprot to the vmapped buffer, too. It eventually fixes the case like non-snoop mode without mmap access on HD-audio. Signed-off-by: Takashi Iwai --- include/sound/memalloc.h | 3 +++ sound/core/memalloc.c | 17 +++++++++++++++++ sound/core/sgbuf.c | 15 +++++++++++++-- 3 files changed, 33 insertions(+), 2 deletions(-) diff --git a/include/sound/memalloc.h b/include/sound/memalloc.h index 67561b997915..af3fa577fa06 100644 --- a/include/sound/memalloc.h +++ b/include/sound/memalloc.h @@ -47,10 +47,13 @@ struct snd_dma_device { #define SNDRV_DMA_TYPE_UNKNOWN 0 /* not defined */ #define SNDRV_DMA_TYPE_CONTINUOUS 1 /* continuous no-DMA memory */ #define SNDRV_DMA_TYPE_DEV 2 /* generic device continuous */ +#define SNDRV_DMA_TYPE_DEV_UC 5 /* continuous non-cahced */ #ifdef CONFIG_SND_DMA_SGBUF #define SNDRV_DMA_TYPE_DEV_SG 3 /* generic device SG-buffer */ +#define SNDRV_DMA_TYPE_DEV_UC_SG 6 /* SG non-cached */ #else #define SNDRV_DMA_TYPE_DEV_SG SNDRV_DMA_TYPE_DEV /* no SG-buf support */ +#define SNDRV_DMA_TYPE_DEV_UC_SG SNDRV_DMA_TYPE_DEV_UC #endif #ifdef CONFIG_GENERIC_ALLOCATOR #define SNDRV_DMA_TYPE_DEV_IRAM 4 /* generic device iram-buffer */ diff --git a/sound/core/memalloc.c b/sound/core/memalloc.c index cc051bfe2f6f..aa266907ec9b 100644 --- a/sound/core/memalloc.c +++ b/sound/core/memalloc.c @@ -25,6 +25,9 @@ #include #include #include +#ifdef CONFIG_X86 +#include +#endif #include /* @@ -92,11 +95,21 @@ static void snd_malloc_dev_pages(struct snd_dma_buffer *dmab, size_t size) | __GFP_NOWARN; /* no stack trace print - this call is non-critical */ dmab->area = dma_alloc_coherent(dmab->dev.dev, size, &dmab->addr, gfp_flags); +#ifdef CONFIG_X86 + if (dmab->area && dmab->dev.type == SNDRV_DMA_TYPE_DEV_UC) + set_memory_wc((unsigned long)dmab->area, + PAGE_ALIGN(size) >> PAGE_SHIFT); +#endif } /* free the coherent DMA pages */ static void snd_free_dev_pages(struct snd_dma_buffer *dmab) { +#ifdef CONFIG_X86 + if (dmab->dev.type == SNDRV_DMA_TYPE_DEV_UC) + set_memory_wb((unsigned long)dmab->area, + PAGE_ALIGN(dmab->bytes) >> PAGE_SHIFT); +#endif dma_free_coherent(dmab->dev.dev, dmab->bytes, dmab->area, dmab->addr); } @@ -191,11 +204,13 @@ int snd_dma_alloc_pages(int type, struct device *device, size_t size, dmab->dev.type = SNDRV_DMA_TYPE_DEV; #endif /* CONFIG_GENERIC_ALLOCATOR */ case SNDRV_DMA_TYPE_DEV: + case SNDRV_DMA_TYPE_DEV_UC: snd_malloc_dev_pages(dmab, size); break; #endif #ifdef CONFIG_SND_DMA_SGBUF case SNDRV_DMA_TYPE_DEV_SG: + case SNDRV_DMA_TYPE_DEV_UC_SG: snd_malloc_sgbuf_pages(device, size, dmab, NULL); break; #endif @@ -266,11 +281,13 @@ void snd_dma_free_pages(struct snd_dma_buffer *dmab) break; #endif /* CONFIG_GENERIC_ALLOCATOR */ case SNDRV_DMA_TYPE_DEV: + case SNDRV_DMA_TYPE_DEV_UC: snd_free_dev_pages(dmab); break; #endif #ifdef CONFIG_SND_DMA_SGBUF case SNDRV_DMA_TYPE_DEV_SG: + case SNDRV_DMA_TYPE_DEV_UC_SG: snd_free_sgbuf_pages(dmab); break; #endif diff --git a/sound/core/sgbuf.c b/sound/core/sgbuf.c index 84fffabdd129..c1cfaa01a5cb 100644 --- a/sound/core/sgbuf.c +++ b/sound/core/sgbuf.c @@ -23,6 +23,7 @@ #include #include #include +#include #include @@ -43,6 +44,8 @@ int snd_free_sgbuf_pages(struct snd_dma_buffer *dmab) dmab->area = NULL; tmpb.dev.type = SNDRV_DMA_TYPE_DEV; + if (dmab->dev.type == SNDRV_DMA_TYPE_DEV_UC_SG) + tmpb.dev.type = SNDRV_DMA_TYPE_DEV_UC; tmpb.dev.dev = sgbuf->dev; for (i = 0; i < sgbuf->pages; i++) { if (!(sgbuf->table[i].addr & ~PAGE_MASK)) @@ -72,12 +75,20 @@ void *snd_malloc_sgbuf_pages(struct device *device, struct snd_dma_buffer tmpb; struct snd_sg_page *table; struct page **pgtable; + int type = SNDRV_DMA_TYPE_DEV; + pgprot_t prot = PAGE_KERNEL; dmab->area = NULL; dmab->addr = 0; dmab->private_data = sgbuf = kzalloc(sizeof(*sgbuf), GFP_KERNEL); if (! sgbuf) return NULL; + if (dmab->dev.type == SNDRV_DMA_TYPE_DEV_UC_SG) { + type = SNDRV_DMA_TYPE_DEV_UC; +#ifdef pgprot_noncached + prot = pgprot_noncached(PAGE_KERNEL); +#endif + } sgbuf->dev = device; pages = snd_sgbuf_aligned_pages(size); sgbuf->tblsize = sgbuf_align_table(pages); @@ -98,7 +109,7 @@ void *snd_malloc_sgbuf_pages(struct device *device, if (chunk > maxpages) chunk = maxpages; chunk <<= PAGE_SHIFT; - if (snd_dma_alloc_pages_fallback(SNDRV_DMA_TYPE_DEV, device, + if (snd_dma_alloc_pages_fallback(type, device, chunk, &tmpb) < 0) { if (!sgbuf->pages) goto _failed; @@ -125,7 +136,7 @@ void *snd_malloc_sgbuf_pages(struct device *device, } sgbuf->size = size; - dmab->area = vmap(sgbuf->page_table, sgbuf->pages, VM_MAP, PAGE_KERNEL); + dmab->area = vmap(sgbuf->page_table, sgbuf->pages, VM_MAP, prot); if (! dmab->area) goto _failed; if (res_size) From 78c9be61c3a5cd9e2439fd27a5ffad73a81958c7 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Sat, 11 Aug 2018 23:33:34 +0200 Subject: [PATCH 009/299] ALSA: hda: Check the non-cached stream buffers more explicitly Introduce a new flag, uc_buffer, to indicate that the controller requires the non-cached pages for stream buffers, either as a chip-specific requirement or specified via snoop=0 option. This improves the code-readability. Also, this patch fixes the incorrect behavior for C-Media chip where the stream buffers were never handled as non-cached due to the check of driver_type even if you pass snoop=0 option. Signed-off-by: Takashi Iwai --- sound/pci/hda/hda_controller.h | 1 + sound/pci/hda/hda_intel.c | 11 ++++++++--- 2 files changed, 9 insertions(+), 3 deletions(-) diff --git a/sound/pci/hda/hda_controller.h b/sound/pci/hda/hda_controller.h index a68e75b00ea3..53c3cd28bc99 100644 --- a/sound/pci/hda/hda_controller.h +++ b/sound/pci/hda/hda_controller.h @@ -160,6 +160,7 @@ struct azx { unsigned int msi:1; unsigned int probing:1; /* codec probing phase */ unsigned int snoop:1; + unsigned int uc_buffer:1; /* non-cached pages for stream buffers */ unsigned int align_buffer_size:1; unsigned int region_requested:1; unsigned int disabled:1; /* disabled by vga_switcheroo */ diff --git a/sound/pci/hda/hda_intel.c b/sound/pci/hda/hda_intel.c index 1b2ce304152a..e5482fd21568 100644 --- a/sound/pci/hda/hda_intel.c +++ b/sound/pci/hda/hda_intel.c @@ -410,7 +410,7 @@ static void __mark_pages_wc(struct azx *chip, struct snd_dma_buffer *dmab, bool #ifdef CONFIG_SND_DMA_SGBUF if (dmab->dev.type == SNDRV_DMA_TYPE_DEV_SG) { struct snd_sg_buf *sgbuf = dmab->private_data; - if (chip->driver_type == AZX_DRIVER_CMEDIA) + if (!chip->uc_buffer) return; /* deal with only CORB/RIRB buffers */ if (on) set_pages_array_wc(sgbuf->page_table, sgbuf->pages); @@ -1637,6 +1637,7 @@ static void azx_check_snoop_available(struct azx *chip) dev_info(chip->card->dev, "Force to %s mode by module option\n", snoop ? "snoop" : "non-snoop"); chip->snoop = snoop; + chip->uc_buffer = !snoop; return; } @@ -1657,8 +1658,12 @@ static void azx_check_snoop_available(struct azx *chip) snoop = false; chip->snoop = snoop; - if (!snoop) + if (!snoop) { dev_info(chip->card->dev, "Force to non-snoop mode\n"); + /* C-Media requires non-cached pages only for CORB/RIRB */ + if (chip->driver_type != AZX_DRIVER_CMEDIA) + chip->uc_buffer = true; + } } static void azx_probe_work(struct work_struct *work) @@ -2097,7 +2102,7 @@ static void pcm_mmap_prepare(struct snd_pcm_substream *substream, #ifdef CONFIG_X86 struct azx_pcm *apcm = snd_pcm_substream_chip(substream); struct azx *chip = apcm->chip; - if (!azx_snoop(chip) && chip->driver_type != AZX_DRIVER_CMEDIA) + if (chip->uc_buffer) area->vm_page_prot = pgprot_writecombine(area->vm_page_prot); #endif } From fc478143693d8750dca5e35d03d497bdd0202b3f Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Wed, 8 Aug 2018 22:23:30 +0200 Subject: [PATCH 010/299] ALSA: hda: Use new non-cached allocation for non-snoop mode Now the ALSA memory allocator helper supports the new non-cached pages, let's use the new type, SNDRV_DMA_TYPE_DEV_UC_SG, for HD-audio driver. This allows us to reduce lots of codes. As another positive side-effect by this patch, the long-standing issue with non-snoop mode playing in the non-mmap mode is fixed. The core memalloc helper does the proper pgprot setup for non-cached pages for vmap(), which was missing in the past. Reported-and-tested-by: Hans Hu Signed-off-by: Takashi Iwai --- sound/pci/hda/hda_controller.c | 5 ++- sound/pci/hda/hda_controller.h | 1 - sound/pci/hda/hda_intel.c | 81 ++-------------------------------- 3 files changed, 8 insertions(+), 79 deletions(-) diff --git a/sound/pci/hda/hda_controller.c b/sound/pci/hda/hda_controller.c index a12e594d4e3b..8bc46676c278 100644 --- a/sound/pci/hda/hda_controller.c +++ b/sound/pci/hda/hda_controller.c @@ -732,6 +732,7 @@ int snd_hda_attach_pcm_stream(struct hda_bus *_bus, struct hda_codec *codec, int pcm_dev = cpcm->device; unsigned int size; int s, err; + int type = SNDRV_DMA_TYPE_DEV_SG; list_for_each_entry(apcm, &chip->pcm_list, list) { if (apcm->pcm->device == pcm_dev) { @@ -770,7 +771,9 @@ int snd_hda_attach_pcm_stream(struct hda_bus *_bus, struct hda_codec *codec, size = CONFIG_SND_HDA_PREALLOC_SIZE * 1024; if (size > MAX_PREALLOC_SIZE) size = MAX_PREALLOC_SIZE; - snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV_SG, + if (chip->uc_buffer) + type = SNDRV_DMA_TYPE_DEV_UC_SG; + snd_pcm_lib_preallocate_pages_for_all(pcm, type, chip->card->dev, size, MAX_PREALLOC_SIZE); return 0; diff --git a/sound/pci/hda/hda_controller.h b/sound/pci/hda/hda_controller.h index 53c3cd28bc99..c4b3de6c42b8 100644 --- a/sound/pci/hda/hda_controller.h +++ b/sound/pci/hda/hda_controller.h @@ -76,7 +76,6 @@ struct azx_dev { * when link position is not greater than FIFO size */ unsigned int insufficient:1; - unsigned int wc_marked:1; }; #define azx_stream(dev) (&(dev)->core) diff --git a/sound/pci/hda/hda_intel.c b/sound/pci/hda/hda_intel.c index e5482fd21568..03ddd1abb44d 100644 --- a/sound/pci/hda/hda_intel.c +++ b/sound/pci/hda/hda_intel.c @@ -397,61 +397,6 @@ static char *driver_short_names[] = { [AZX_DRIVER_GENERIC] = "HD-Audio Generic", }; -#ifdef CONFIG_X86 -static void __mark_pages_wc(struct azx *chip, struct snd_dma_buffer *dmab, bool on) -{ - int pages; - - if (azx_snoop(chip)) - return; - if (!dmab || !dmab->area || !dmab->bytes) - return; - -#ifdef CONFIG_SND_DMA_SGBUF - if (dmab->dev.type == SNDRV_DMA_TYPE_DEV_SG) { - struct snd_sg_buf *sgbuf = dmab->private_data; - if (!chip->uc_buffer) - return; /* deal with only CORB/RIRB buffers */ - if (on) - set_pages_array_wc(sgbuf->page_table, sgbuf->pages); - else - set_pages_array_wb(sgbuf->page_table, sgbuf->pages); - return; - } -#endif - - pages = (dmab->bytes + PAGE_SIZE - 1) >> PAGE_SHIFT; - if (on) - set_memory_wc((unsigned long)dmab->area, pages); - else - set_memory_wb((unsigned long)dmab->area, pages); -} - -static inline void mark_pages_wc(struct azx *chip, struct snd_dma_buffer *buf, - bool on) -{ - __mark_pages_wc(chip, buf, on); -} -static inline void mark_runtime_wc(struct azx *chip, struct azx_dev *azx_dev, - struct snd_pcm_substream *substream, bool on) -{ - if (azx_dev->wc_marked != on) { - __mark_pages_wc(chip, snd_pcm_get_dma_buf(substream), on); - azx_dev->wc_marked = on; - } -} -#else -/* NOP for other archs */ -static inline void mark_pages_wc(struct azx *chip, struct snd_dma_buffer *buf, - bool on) -{ -} -static inline void mark_runtime_wc(struct azx *chip, struct azx_dev *azx_dev, - struct snd_pcm_substream *substream, bool on) -{ -} -#endif - static int azx_acquire_irq(struct azx *chip, int do_disconnect); /* @@ -2054,22 +1999,14 @@ static int dma_alloc_pages(struct hdac_bus *bus, struct snd_dma_buffer *buf) { struct azx *chip = bus_to_azx(bus); - int err; - err = snd_dma_alloc_pages(type, - bus->dev, - size, buf); - if (err < 0) - return err; - mark_pages_wc(chip, buf, true); - return 0; + if (!azx_snoop(chip) && type == SNDRV_DMA_TYPE_DEV) + type = SNDRV_DMA_TYPE_DEV_UC; + return snd_dma_alloc_pages(type, bus->dev, size, buf); } static void dma_free_pages(struct hdac_bus *bus, struct snd_dma_buffer *buf) { - struct azx *chip = bus_to_azx(bus); - - mark_pages_wc(chip, buf, false); snd_dma_free_pages(buf); } @@ -2077,22 +2014,12 @@ static int substream_alloc_pages(struct azx *chip, struct snd_pcm_substream *substream, size_t size) { - struct azx_dev *azx_dev = get_azx_dev(substream); - int ret; - - mark_runtime_wc(chip, azx_dev, substream, false); - ret = snd_pcm_lib_malloc_pages(substream, size); - if (ret < 0) - return ret; - mark_runtime_wc(chip, azx_dev, substream, true); - return 0; + return snd_pcm_lib_malloc_pages(substream, size); } static int substream_free_pages(struct azx *chip, struct snd_pcm_substream *substream) { - struct azx_dev *azx_dev = get_azx_dev(substream); - mark_runtime_wc(chip, azx_dev, substream, false); return snd_pcm_lib_free_pages(substream); } From 193c7e14762a58003af7914183f9b963c0267788 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Wed, 8 Aug 2018 17:12:58 +0200 Subject: [PATCH 011/299] ALSA: hda: Remove substream allocation/free ops Since we dropped the memory page fiddling in the own allocators in hda_intel.c, the substream allocation and free ops in both hda_intel.c and hda_tegra.c became nothing but the simple calls of the standard snd_pcm_lib helpers. As both are identical, there is no longer need for indirect calls via ops; it's a good opportunity for removing ops and simplifying the codes. Signed-off-by: Takashi Iwai --- sound/pci/hda/hda_controller.c | 8 ++++---- sound/pci/hda/hda_controller.h | 5 ----- sound/pci/hda/hda_intel.c | 15 --------------- sound/pci/hda/hda_tegra.c | 18 +----------------- 4 files changed, 5 insertions(+), 41 deletions(-) diff --git a/sound/pci/hda/hda_controller.c b/sound/pci/hda/hda_controller.c index 8bc46676c278..53bdf76fcbba 100644 --- a/sound/pci/hda/hda_controller.c +++ b/sound/pci/hda/hda_controller.c @@ -130,8 +130,9 @@ static int azx_pcm_hw_params(struct snd_pcm_substream *substream, azx_dev->core.bufsize = 0; azx_dev->core.period_bytes = 0; azx_dev->core.format_val = 0; - ret = chip->ops->substream_alloc_pages(chip, substream, - params_buffer_bytes(hw_params)); + ret = snd_pcm_lib_malloc_pages(substream, + params_buffer_bytes(hw_params)); + unlock: dsp_unlock(azx_dev); return ret; @@ -141,7 +142,6 @@ static int azx_pcm_hw_free(struct snd_pcm_substream *substream) { struct azx_pcm *apcm = snd_pcm_substream_chip(substream); struct azx_dev *azx_dev = get_azx_dev(substream); - struct azx *chip = apcm->chip; struct hda_pcm_stream *hinfo = to_hda_pcm_stream(substream); int err; @@ -152,7 +152,7 @@ static int azx_pcm_hw_free(struct snd_pcm_substream *substream) snd_hda_codec_cleanup(apcm->codec, hinfo, substream); - err = chip->ops->substream_free_pages(chip, substream); + err = snd_pcm_lib_free_pages(substream); azx_stream(azx_dev)->prepared = 0; dsp_unlock(azx_dev); return err; diff --git a/sound/pci/hda/hda_controller.h b/sound/pci/hda/hda_controller.h index c4b3de6c42b8..3c9a2f81cfbf 100644 --- a/sound/pci/hda/hda_controller.h +++ b/sound/pci/hda/hda_controller.h @@ -87,11 +87,6 @@ struct azx; struct hda_controller_ops { /* Disable msi if supported, PCI only */ int (*disable_msi_reset_irq)(struct azx *); - int (*substream_alloc_pages)(struct azx *chip, - struct snd_pcm_substream *substream, - size_t size); - int (*substream_free_pages)(struct azx *chip, - struct snd_pcm_substream *substream); void (*pcm_mmap_prepare)(struct snd_pcm_substream *substream, struct vm_area_struct *area); /* Check if current position is acceptable */ diff --git a/sound/pci/hda/hda_intel.c b/sound/pci/hda/hda_intel.c index 03ddd1abb44d..0a3ce9c60f50 100644 --- a/sound/pci/hda/hda_intel.c +++ b/sound/pci/hda/hda_intel.c @@ -2010,19 +2010,6 @@ static void dma_free_pages(struct hdac_bus *bus, struct snd_dma_buffer *buf) snd_dma_free_pages(buf); } -static int substream_alloc_pages(struct azx *chip, - struct snd_pcm_substream *substream, - size_t size) -{ - return snd_pcm_lib_malloc_pages(substream, size); -} - -static int substream_free_pages(struct azx *chip, - struct snd_pcm_substream *substream) -{ - return snd_pcm_lib_free_pages(substream); -} - static void pcm_mmap_prepare(struct snd_pcm_substream *substream, struct vm_area_struct *area) { @@ -2047,8 +2034,6 @@ static const struct hdac_io_ops pci_hda_io_ops = { static const struct hda_controller_ops pci_hda_ops = { .disable_msi_reset_irq = disable_msi_reset_irq, - .substream_alloc_pages = substream_alloc_pages, - .substream_free_pages = substream_free_pages, .pcm_mmap_prepare = pcm_mmap_prepare, .position_check = azx_position_check, .link_power = azx_intel_link_power, diff --git a/sound/pci/hda/hda_tegra.c b/sound/pci/hda/hda_tegra.c index 0621920f7617..8fd20e4dca17 100644 --- a/sound/pci/hda/hda_tegra.c +++ b/sound/pci/hda/hda_tegra.c @@ -99,19 +99,6 @@ static void dma_free_pages(struct hdac_bus *bus, struct snd_dma_buffer *buf) snd_dma_free_pages(buf); } -static int substream_alloc_pages(struct azx *chip, - struct snd_pcm_substream *substream, - size_t size) -{ - return snd_pcm_lib_malloc_pages(substream, size); -} - -static int substream_free_pages(struct azx *chip, - struct snd_pcm_substream *substream) -{ - return snd_pcm_lib_free_pages(substream); -} - /* * Register access ops. Tegra HDA register access is DWORD only. */ @@ -180,10 +167,7 @@ static const struct hdac_io_ops hda_tegra_io_ops = { .dma_free_pages = dma_free_pages, }; -static const struct hda_controller_ops hda_tegra_ops = { - .substream_alloc_pages = substream_alloc_pages, - .substream_free_pages = substream_free_pages, -}; +static const struct hda_controller_ops hda_tegra_ops; /* nothing special */ static void hda_tegra_init(struct hda_tegra *hda) { From 4985ddbf1edb06f0dc4ae22e9886bde267925e6c Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Wed, 8 Aug 2018 22:31:52 +0200 Subject: [PATCH 012/299] ALSA: intel8x0: Use the new non-cached allocation for 440MX workaround intel8x0 driver requires the non-cached pages for 440MX workaround, and this can be implemented more easily with the new memalloc type, SNDRV_DMA_TYPE_DEV_UC. This allows us to reduce lots of code. Signed-off-by: Takashi Iwai --- sound/pci/intel8x0.c | 89 ++++++-------------------------------------- 1 file changed, 12 insertions(+), 77 deletions(-) diff --git a/sound/pci/intel8x0.c b/sound/pci/intel8x0.c index 5ee468d1aefe..9517f9b8f1d4 100644 --- a/sound/pci/intel8x0.c +++ b/sound/pci/intel8x0.c @@ -38,11 +38,6 @@ #include #include #include -/* for 440MX workaround */ -#include -#ifdef CONFIG_X86 -#include -#endif MODULE_AUTHOR("Jaroslav Kysela "); MODULE_DESCRIPTION("Intel 82801AA,82901AB,i810,i820,i830,i840,i845,MX440; SiS 7012; Ali 5455"); @@ -374,7 +369,6 @@ struct ichdev { unsigned int ali_slot; /* ALI DMA slot */ struct ac97_pcm *pcm; int pcm_open_flag; - unsigned int page_attr_changed: 1; unsigned int suspended: 1; }; @@ -724,25 +718,6 @@ static void snd_intel8x0_setup_periods(struct intel8x0 *chip, struct ichdev *ich iputbyte(chip, port + ichdev->roff_sr, ICH_FIFOE | ICH_BCIS | ICH_LVBCI); } -#ifdef __i386__ -/* - * Intel 82443MX running a 100MHz processor system bus has a hardware bug, - * which aborts PCI busmaster for audio transfer. A workaround is to set - * the pages as non-cached. For details, see the errata in - * http://download.intel.com/design/chipsets/specupdt/24505108.pdf - */ -static void fill_nocache(void *buf, int size, int nocache) -{ - size = (size + PAGE_SIZE - 1) >> PAGE_SHIFT; - if (nocache) - set_pages_uc(virt_to_page(buf), size); - else - set_pages_wb(virt_to_page(buf), size); -} -#else -#define fill_nocache(buf, size, nocache) do { ; } while (0) -#endif - /* * Interrupt handler */ @@ -938,23 +913,12 @@ static int snd_intel8x0_hw_params(struct snd_pcm_substream *substream, { struct intel8x0 *chip = snd_pcm_substream_chip(substream); struct ichdev *ichdev = get_ichdev(substream); - struct snd_pcm_runtime *runtime = substream->runtime; int dbl = params_rate(hw_params) > 48000; int err; - if (chip->fix_nocache && ichdev->page_attr_changed) { - fill_nocache(runtime->dma_area, runtime->dma_bytes, 0); /* clear */ - ichdev->page_attr_changed = 0; - } err = snd_pcm_lib_malloc_pages(substream, params_buffer_bytes(hw_params)); if (err < 0) return err; - if (chip->fix_nocache) { - if (runtime->dma_area && ! ichdev->page_attr_changed) { - fill_nocache(runtime->dma_area, runtime->dma_bytes, 1); - ichdev->page_attr_changed = 1; - } - } if (ichdev->pcm_open_flag) { snd_ac97_pcm_close(ichdev->pcm); ichdev->pcm_open_flag = 0; @@ -974,17 +938,12 @@ static int snd_intel8x0_hw_params(struct snd_pcm_substream *substream, static int snd_intel8x0_hw_free(struct snd_pcm_substream *substream) { - struct intel8x0 *chip = snd_pcm_substream_chip(substream); struct ichdev *ichdev = get_ichdev(substream); if (ichdev->pcm_open_flag) { snd_ac97_pcm_close(ichdev->pcm); ichdev->pcm_open_flag = 0; } - if (chip->fix_nocache && ichdev->page_attr_changed) { - fill_nocache(substream->runtime->dma_area, substream->runtime->dma_bytes, 0); - ichdev->page_attr_changed = 0; - } return snd_pcm_lib_free_pages(substream); } @@ -1510,6 +1469,9 @@ struct ich_pcm_table { int ac97_idx; }; +#define intel8x0_dma_type(chip) \ + ((chip)->fix_nocache ? SNDRV_DMA_TYPE_DEV_UC : SNDRV_DMA_TYPE_DEV) + static int snd_intel8x0_pcm1(struct intel8x0 *chip, int device, struct ich_pcm_table *rec) { @@ -1540,7 +1502,7 @@ static int snd_intel8x0_pcm1(struct intel8x0 *chip, int device, strcpy(pcm->name, chip->card->shortname); chip->pcm[device] = pcm; - snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV, + snd_pcm_lib_preallocate_pages_for_all(pcm, intel8x0_dma_type(chip), snd_dma_pci_data(chip->pci), rec->prealloc_size, rec->prealloc_max_size); @@ -2629,11 +2591,8 @@ static int snd_intel8x0_free(struct intel8x0 *chip) __hw_end: if (chip->irq >= 0) free_irq(chip->irq, chip); - if (chip->bdbars.area) { - if (chip->fix_nocache) - fill_nocache(chip->bdbars.area, chip->bdbars.bytes, 0); + if (chip->bdbars.area) snd_dma_free_pages(&chip->bdbars); - } if (chip->addr) pci_iounmap(chip->pci, chip->addr); if (chip->bmaddr) @@ -2657,17 +2616,6 @@ static int intel8x0_suspend(struct device *dev) snd_power_change_state(card, SNDRV_CTL_POWER_D3hot); for (i = 0; i < chip->pcm_devs; i++) snd_pcm_suspend_all(chip->pcm[i]); - /* clear nocache */ - if (chip->fix_nocache) { - for (i = 0; i < chip->bdbars_count; i++) { - struct ichdev *ichdev = &chip->ichd[i]; - if (ichdev->substream && ichdev->page_attr_changed) { - struct snd_pcm_runtime *runtime = ichdev->substream->runtime; - if (runtime->dma_area) - fill_nocache(runtime->dma_area, runtime->dma_bytes, 0); - } - } - } for (i = 0; i < chip->ncodecs; i++) snd_ac97_suspend(chip->ac97[i]); if (chip->device_type == DEVICE_INTEL_ICH4) @@ -2708,25 +2656,9 @@ static int intel8x0_resume(struct device *dev) ICH_PCM_SPDIF_1011); } - /* refill nocache */ - if (chip->fix_nocache) - fill_nocache(chip->bdbars.area, chip->bdbars.bytes, 1); - for (i = 0; i < chip->ncodecs; i++) snd_ac97_resume(chip->ac97[i]); - /* refill nocache */ - if (chip->fix_nocache) { - for (i = 0; i < chip->bdbars_count; i++) { - struct ichdev *ichdev = &chip->ichd[i]; - if (ichdev->substream && ichdev->page_attr_changed) { - struct snd_pcm_runtime *runtime = ichdev->substream->runtime; - if (runtime->dma_area) - fill_nocache(runtime->dma_area, runtime->dma_bytes, 1); - } - } - } - /* resume status */ for (i = 0; i < chip->bdbars_count; i++) { struct ichdev *ichdev = &chip->ichd[i]; @@ -3057,6 +2989,12 @@ static int snd_intel8x0_create(struct snd_card *card, chip->inside_vm = snd_intel8x0_inside_vm(pci); + /* + * Intel 82443MX running a 100MHz processor system bus has a hardware + * bug, which aborts PCI busmaster for audio transfer. A workaround + * is to set the pages as non-cached. For details, see the errata in + * http://download.intel.com/design/chipsets/specupdt/24505108.pdf + */ if (pci->vendor == PCI_VENDOR_ID_INTEL && pci->device == PCI_DEVICE_ID_INTEL_440MX) chip->fix_nocache = 1; /* enable workaround */ @@ -3128,7 +3066,7 @@ static int snd_intel8x0_create(struct snd_card *card, /* allocate buffer descriptor lists */ /* the start of each lists must be aligned to 8 bytes */ - if (snd_dma_alloc_pages(SNDRV_DMA_TYPE_DEV, snd_dma_pci_data(pci), + if (snd_dma_alloc_pages(intel8x0_dma_type(chip), snd_dma_pci_data(pci), chip->bdbars_count * sizeof(u32) * ICH_MAX_FRAGS * 2, &chip->bdbars) < 0) { snd_intel8x0_free(chip); @@ -3137,9 +3075,6 @@ static int snd_intel8x0_create(struct snd_card *card, } /* tables must be aligned to 8 bytes here, but the kernel pages are much bigger, so we don't care (on i386) */ - /* workaround for 440MX */ - if (chip->fix_nocache) - fill_nocache(chip->bdbars.area, chip->bdbars.bytes, 1); int_sta_masks = 0; for (i = 0; i < chip->bdbars_count; i++) { ichdev = &chip->ichd[i]; From 87246f7fd572f9c3db752708730d68cc9eb08d72 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Wed, 8 Aug 2018 22:38:36 +0200 Subject: [PATCH 013/299] ALSA: intel_hdmi: Use the new non-cached allocation The HDMI LPE audio driver requires the non-cached page allocations for its buffers. With the recent support of SNDRV_DMA_TYPE_DEV_UC type, we can reduce lots of codes in the driver side and let the memalloc core doing it properly. Signed-off-by: Takashi Iwai --- sound/x86/intel_hdmi_audio.c | 29 +++-------------------------- 1 file changed, 3 insertions(+), 26 deletions(-) diff --git a/sound/x86/intel_hdmi_audio.c b/sound/x86/intel_hdmi_audio.c index fa7dca5a68c8..83d76c345940 100644 --- a/sound/x86/intel_hdmi_audio.c +++ b/sound/x86/intel_hdmi_audio.c @@ -30,7 +30,6 @@ #include #include #include -#include #include #include #include @@ -1141,8 +1140,7 @@ static int had_pcm_hw_params(struct snd_pcm_substream *substream, struct snd_pcm_hw_params *hw_params) { struct snd_intelhad *intelhaddata; - unsigned long addr; - int pages, buf_size, retval; + int buf_size, retval; intelhaddata = snd_pcm_substream_chip(substream); buf_size = params_buffer_bytes(hw_params); @@ -1151,17 +1149,6 @@ static int had_pcm_hw_params(struct snd_pcm_substream *substream, return retval; dev_dbg(intelhaddata->dev, "%s:allocated memory = %d\n", __func__, buf_size); - /* mark the pages as uncached region */ - addr = (unsigned long) substream->runtime->dma_area; - pages = (substream->runtime->dma_bytes + PAGE_SIZE - 1) / PAGE_SIZE; - retval = set_memory_uc(addr, pages); - if (retval) { - dev_err(intelhaddata->dev, "set_memory_uc failed.Error:%d\n", - retval); - return retval; - } - memset(substream->runtime->dma_area, 0, buf_size); - return retval; } @@ -1171,21 +1158,11 @@ static int had_pcm_hw_params(struct snd_pcm_substream *substream, static int had_pcm_hw_free(struct snd_pcm_substream *substream) { struct snd_intelhad *intelhaddata; - unsigned long addr; - u32 pages; intelhaddata = snd_pcm_substream_chip(substream); had_do_reset(intelhaddata); - /* mark back the pages as cached/writeback region before the free */ - if (substream->runtime->dma_area != NULL) { - addr = (unsigned long) substream->runtime->dma_area; - pages = (substream->runtime->dma_bytes + PAGE_SIZE - 1) / - PAGE_SIZE; - set_memory_wb(addr, pages); - return snd_pcm_lib_free_pages(substream); - } - return 0; + return snd_pcm_lib_free_pages(substream); } /* @@ -1860,7 +1837,7 @@ static int hdmi_lpe_audio_probe(struct platform_device *pdev) * try to allocate 600k buffer as default which is large enough */ snd_pcm_lib_preallocate_pages_for_all(pcm, - SNDRV_DMA_TYPE_DEV, NULL, + SNDRV_DMA_TYPE_DEV_UC, NULL, HAD_DEFAULT_BUFFER, HAD_MAX_BUFFER); /* create controls */ From 5d585e1e756838d91144c3173323b96f5aa12874 Mon Sep 17 00:00:00 2001 From: Rob Herring Date: Tue, 28 Aug 2018 10:44:28 -0500 Subject: [PATCH 014/299] ASoC: Convert to using %pOFn instead of device_node.name In preparation to remove the node name pointer from struct device_node, convert printf users to use the %pOFn format specifier. Signed-off-by: Rob Herring Signed-off-by: Mark Brown --- sound/soc/fsl/fsl_esai.c | 2 +- sound/soc/fsl/fsl_utils.c | 4 ++-- sound/soc/meson/axg-card.c | 2 +- sound/soc/stm/stm32_sai.c | 2 +- sound/soc/stm/stm32_sai_sub.c | 7 +++---- 5 files changed, 8 insertions(+), 9 deletions(-) diff --git a/sound/soc/fsl/fsl_esai.c b/sound/soc/fsl/fsl_esai.c index c1d1d06783e5..57b484768a58 100644 --- a/sound/soc/fsl/fsl_esai.c +++ b/sound/soc/fsl/fsl_esai.c @@ -807,7 +807,7 @@ static int fsl_esai_probe(struct platform_device *pdev) return -ENOMEM; esai_priv->pdev = pdev; - strncpy(esai_priv->name, np->name, sizeof(esai_priv->name) - 1); + snprintf(esai_priv->name, sizeof(esai_priv->name), "%pOFn", np); /* Get the addresses and IRQ */ res = platform_get_resource(pdev, IORESOURCE_MEM, 0); diff --git a/sound/soc/fsl/fsl_utils.c b/sound/soc/fsl/fsl_utils.c index 7f0fa4b52223..9981668ab590 100644 --- a/sound/soc/fsl/fsl_utils.c +++ b/sound/soc/fsl/fsl_utils.c @@ -57,8 +57,8 @@ int fsl_asoc_get_dma_channel(struct device_node *ssi_np, of_node_put(dma_channel_np); return ret; } - snprintf((char *)dai->platform_name, DAI_NAME_SIZE, "%llx.%s", - (unsigned long long) res.start, dma_channel_np->name); + snprintf((char *)dai->platform_name, DAI_NAME_SIZE, "%llx.%pOFn", + (unsigned long long) res.start, dma_channel_np); iprop = of_get_property(dma_channel_np, "cell-index", NULL); if (!iprop) { diff --git a/sound/soc/meson/axg-card.c b/sound/soc/meson/axg-card.c index 2914ba0d965b..b76a5f4f1785 100644 --- a/sound/soc/meson/axg-card.c +++ b/sound/soc/meson/axg-card.c @@ -478,7 +478,7 @@ static int axg_card_set_be_link(struct snd_soc_card *card, ret = axg_card_set_link_name(card, link, "be"); if (ret) - dev_err(card->dev, "error setting %s link name\n", np->name); + dev_err(card->dev, "error setting %pOFn link name\n", np); return ret; } diff --git a/sound/soc/stm/stm32_sai.c b/sound/soc/stm/stm32_sai.c index f22654253c43..d597eba61992 100644 --- a/sound/soc/stm/stm32_sai.c +++ b/sound/soc/stm/stm32_sai.c @@ -104,7 +104,7 @@ static int stm32_sai_set_sync(struct stm32_sai_data *sai_client, if (!pdev) { dev_err(&sai_client->pdev->dev, - "Device not found for node %s\n", np_provider->name); + "Device not found for node %pOFn\n", np_provider); return -ENODEV; } diff --git a/sound/soc/stm/stm32_sai_sub.c b/sound/soc/stm/stm32_sai_sub.c index 06fba9650ac4..56a227e0bd71 100644 --- a/sound/soc/stm/stm32_sai_sub.c +++ b/sound/soc/stm/stm32_sai_sub.c @@ -1124,16 +1124,15 @@ static int stm32_sai_sub_parse_of(struct platform_device *pdev, sai->sync = SAI_SYNC_NONE; if (args.np) { if (args.np == np) { - dev_err(&pdev->dev, "%s sync own reference\n", - np->name); + dev_err(&pdev->dev, "%pOFn sync own reference\n", np); of_node_put(args.np); return -EINVAL; } sai->np_sync_provider = of_get_parent(args.np); if (!sai->np_sync_provider) { - dev_err(&pdev->dev, "%s parent node not found\n", - np->name); + dev_err(&pdev->dev, "%pOFn parent node not found\n", + np); of_node_put(args.np); return -ENODEV; } From d78b1e43e2182640b33d1c39245965d9231f0130 Mon Sep 17 00:00:00 2001 From: Charles Keepax Date: Tue, 28 Aug 2018 14:35:02 +0100 Subject: [PATCH 015/299] ASoC: dapm: Remove clock framework ifdefs The clock code now has stub functions defined in its header files so the ifdefs around clocking code should no longer be necessary. Signed-off-by: Charles Keepax Signed-off-by: Mark Brown --- sound/soc/soc-dapm.c | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/sound/soc/soc-dapm.c b/sound/soc/soc-dapm.c index 461d951917c0..78ab6965af55 100644 --- a/sound/soc/soc-dapm.c +++ b/sound/soc/soc-dapm.c @@ -1320,14 +1320,13 @@ int dapm_clock_event(struct snd_soc_dapm_widget *w, soc_dapm_async_complete(w->dapm); -#ifdef CONFIG_HAVE_CLK if (SND_SOC_DAPM_EVENT_ON(event)) { return clk_prepare_enable(w->clk); } else { clk_disable_unprepare(w->clk); return 0; } -#endif + return 0; } EXPORT_SYMBOL_GPL(dapm_clock_event); @@ -3498,7 +3497,6 @@ snd_soc_dapm_new_control_unlocked(struct snd_soc_dapm_context *dapm, } break; case snd_soc_dapm_clock_supply: -#ifdef CONFIG_CLKDEV_LOOKUP w->clk = devm_clk_get(dapm->dev, w->name); if (IS_ERR(w->clk)) { ret = PTR_ERR(w->clk); @@ -3508,9 +3506,6 @@ snd_soc_dapm_new_control_unlocked(struct snd_soc_dapm_context *dapm, w->name, ret); return NULL; } -#else - return NULL; -#endif break; default: break; From a5cd7e9cf587f51a84b86c828b4e1c7b392f448e Mon Sep 17 00:00:00 2001 From: Charles Keepax Date: Tue, 28 Aug 2018 14:35:03 +0100 Subject: [PATCH 016/299] ASoC: dapm: Don't fail creating new DAPM control on NULL pinctrl devm_pinctrl_get will only return NULL in the case that pinctrl is not built into the kernel and all the pinctrl functions used by the DAPM core are appropriately stubbed for that case. There is no need to error out of snd_soc_dapm_new_control_unlocked if pinctrl isn't built into the kernel, so change the IS_ERR_OR_NULL to just an IS_ERR. Signed-off-by: Charles Keepax Signed-off-by: Mark Brown --- sound/soc/soc-dapm.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sound/soc/soc-dapm.c b/sound/soc/soc-dapm.c index 78ab6965af55..d7be3981f026 100644 --- a/sound/soc/soc-dapm.c +++ b/sound/soc/soc-dapm.c @@ -3487,7 +3487,7 @@ snd_soc_dapm_new_control_unlocked(struct snd_soc_dapm_context *dapm, break; case snd_soc_dapm_pinctrl: w->pinctrl = devm_pinctrl_get(dapm->dev); - if (IS_ERR_OR_NULL(w->pinctrl)) { + if (IS_ERR(w->pinctrl)) { ret = PTR_ERR(w->pinctrl); if (ret == -EPROBE_DEFER) return ERR_PTR(ret); From e33ffbd9cd39da09831ce62c11025d830bf78d9e Mon Sep 17 00:00:00 2001 From: Charles Keepax Date: Mon, 27 Aug 2018 14:26:47 +0100 Subject: [PATCH 017/299] ASoC: dpcm: Properly initialise hw->rate_max If the CPU DAI does not initialise rate_max, say if using using KNOT or CONTINUOUS, then the rate_max field will be initialised to 0. A value of zero in the rate_max field of the hardware runtime will cause the sound card to support no sample rates at all. Obviously this is not desired, just a different mechanism is being used to apply the constraints. As such update the setting of rate_max in dpcm_init_runtime_hw to be consistent with the non-DPCM cases and set rate_max to UINT_MAX if nothing is defined on the CPU DAI. Signed-off-by: Charles Keepax Signed-off-by: Mark Brown --- sound/soc/soc-pcm.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sound/soc/soc-pcm.c b/sound/soc/soc-pcm.c index e8b98bfd4cf1..eb6f4f1b65a9 100644 --- a/sound/soc/soc-pcm.c +++ b/sound/soc/soc-pcm.c @@ -1680,7 +1680,7 @@ static void dpcm_init_runtime_hw(struct snd_pcm_runtime *runtime, struct snd_soc_pcm_stream *stream) { runtime->hw.rate_min = stream->rate_min; - runtime->hw.rate_max = stream->rate_max; + runtime->hw.rate_max = min_not_zero(stream->rate_max, UINT_MAX); runtime->hw.channels_min = stream->channels_min; runtime->hw.channels_max = stream->channels_max; if (runtime->hw.formats) From ac16df938e5107a1e08cf0f52818fa6a5f7bba94 Mon Sep 17 00:00:00 2001 From: Jerome Brunet Date: Tue, 28 Aug 2018 14:17:21 +0200 Subject: [PATCH 018/299] ASoC: meson: imply clock and reset controllers Add audio clock controller and ARB reset controller module implication for the device using them Signed-off-by: Jerome Brunet Signed-off-by: Mark Brown --- sound/soc/meson/Kconfig | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/sound/soc/meson/Kconfig b/sound/soc/meson/Kconfig index 8af8bc358a90..2ccbadc387de 100644 --- a/sound/soc/meson/Kconfig +++ b/sound/soc/meson/Kconfig @@ -4,6 +4,8 @@ menu "ASoC support for Amlogic platforms" config SND_MESON_AXG_FIFO tristate select REGMAP_MMIO + imply COMMON_CLK_AXG_AUDIO + imply RESET_MESON_AUDIO_ARB config SND_MESON_AXG_FRDDR tristate "Amlogic AXG Playback FIFO support" @@ -22,6 +24,7 @@ config SND_MESON_AXG_TODDR config SND_MESON_AXG_TDM_FORMATTER tristate select REGMAP_MMIO + imply COMMON_CLK_AXG_AUDIO config SND_MESON_AXG_TDM_INTERFACE tristate @@ -58,6 +61,7 @@ config SND_MESON_AXG_SPDIFOUT tristate "Amlogic AXG SPDIF Output Support" select SND_PCM_IEC958 imply SND_SOC_SPDIF + imply COMMON_CLK_AXG_AUDIO help Select Y or M to add support for SPDIF output serializer embedded in the Amlogic AXG SoC family From dadfab7272b13ca441efdb9aa9117bc669680b05 Mon Sep 17 00:00:00 2001 From: Jerome Brunet Date: Mon, 27 Aug 2018 16:15:29 +0200 Subject: [PATCH 019/299] ASoC: meson: axg-fifo: report interrupt request failure Return value of request_irq() was irgnored. Fix this and report the failure if any Fixes: 6dc4fa179fb8 ("ASoC: meson: add axg fifo base driver") Signed-off-by: Jerome Brunet Signed-off-by: Mark Brown --- sound/soc/meson/axg-fifo.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/sound/soc/meson/axg-fifo.c b/sound/soc/meson/axg-fifo.c index 30262550e37b..0e4f65e654c4 100644 --- a/sound/soc/meson/axg-fifo.c +++ b/sound/soc/meson/axg-fifo.c @@ -203,6 +203,8 @@ static int axg_fifo_pcm_open(struct snd_pcm_substream *ss) ret = request_irq(fifo->irq, axg_fifo_pcm_irq_block, 0, dev_name(dev), ss); + if (ret) + return ret; /* Enable pclk to access registers and clock the fifo ip */ ret = clk_prepare_enable(fifo->pclk); From 302df2694b97e6a56f7956c1105630809b141ea0 Mon Sep 17 00:00:00 2001 From: Jerome Brunet Date: Mon, 27 Aug 2018 16:21:07 +0200 Subject: [PATCH 020/299] ASoC: meson: axg-tdm: restrict formats depending on slot width Restrict the formats possible on the TDM interface depending on the width of the TDM slot and let dpcm merging do the rest. Fixes: d60e4f1e4be5 ("ASoC: meson: add tdm interface driver") Signed-off-by: Jerome Brunet Signed-off-by: Mark Brown --- sound/soc/meson/axg-tdm-interface.c | 52 +++++++++++++++++------------ 1 file changed, 30 insertions(+), 22 deletions(-) diff --git a/sound/soc/meson/axg-tdm-interface.c b/sound/soc/meson/axg-tdm-interface.c index 7b8baf46d968..585ce030b79b 100644 --- a/sound/soc/meson/axg-tdm-interface.c +++ b/sound/soc/meson/axg-tdm-interface.c @@ -42,6 +42,7 @@ int axg_tdm_set_tdm_slots(struct snd_soc_dai *dai, u32 *tx_mask, struct axg_tdm_stream *rx = (struct axg_tdm_stream *) dai->capture_dma_data; unsigned int tx_slots, rx_slots; + unsigned int fmt = 0; tx_slots = axg_tdm_slots_total(tx_mask); rx_slots = axg_tdm_slots_total(rx_mask); @@ -52,36 +53,43 @@ int axg_tdm_set_tdm_slots(struct snd_soc_dai *dai, u32 *tx_mask, return -EINVAL; } - /* - * Amend the dai driver channel number and let dpcm channel merge do - * its job - */ + iface->slots = slots; + + switch (slot_width) { + case 0: + slot_width = 32; + /* Fall-through */ + case 32: + fmt |= SNDRV_PCM_FMTBIT_S32_LE; + /* Fall-through */ + case 24: + fmt |= SNDRV_PCM_FMTBIT_S24_LE; + fmt |= SNDRV_PCM_FMTBIT_S20_LE; + /* Fall-through */ + case 16: + fmt |= SNDRV_PCM_FMTBIT_S16_LE; + /* Fall-through */ + case 8: + fmt |= SNDRV_PCM_FMTBIT_S8; + break; + default: + dev_err(dai->dev, "unsupported slot width: %d\n", slot_width); + return -EINVAL; + } + + iface->slot_width = slot_width; + + /* Amend the dai driver and let dpcm merge do its job */ if (tx) { tx->mask = tx_mask; dai->driver->playback.channels_max = tx_slots; + dai->driver->playback.formats = fmt; } if (rx) { rx->mask = rx_mask; dai->driver->capture.channels_max = rx_slots; - } - - iface->slots = slots; - - switch (slot_width) { - case 0: - /* defaults width to 32 if not provided */ - iface->slot_width = 32; - break; - case 8: - case 16: - case 24: - case 32: - iface->slot_width = slot_width; - break; - default: - dev_err(dai->dev, "unsupported slot width: %d\n", slot_width); - return -EINVAL; + dai->driver->capture.formats = fmt; } return 0; From 513792c2554bdece11d82568ea25501a555abd34 Mon Sep 17 00:00:00 2001 From: Shuming Fan Date: Fri, 24 Aug 2018 10:51:51 +0800 Subject: [PATCH 021/299] ASoC: rt5682: Update calibration function New calibration sequence allows rt5682 do calibration without MCLK. Signed-off-by: Shuming Fan Signed-off-by: Mark Brown --- sound/soc/codecs/rt5682.c | 22 +++++----------------- 1 file changed, 5 insertions(+), 17 deletions(-) diff --git a/sound/soc/codecs/rt5682.c b/sound/soc/codecs/rt5682.c index 640d400ca013..0ea2759e5885 100644 --- a/sound/soc/codecs/rt5682.c +++ b/sound/soc/codecs/rt5682.c @@ -2454,27 +2454,15 @@ static void rt5682_calibrate(struct rt5682_priv *rt5682) regmap_write(rt5682->regmap, RT5682_PWR_ANLG_1, 0xa2bf); usleep_range(15000, 20000); regmap_write(rt5682->regmap, RT5682_PWR_ANLG_1, 0xf2bf); - regmap_write(rt5682->regmap, RT5682_MICBIAS_2, 0x0380); - regmap_write(rt5682->regmap, RT5682_PWR_DIG_1, 0x8001); - regmap_write(rt5682->regmap, RT5682_TEST_MODE_CTRL_1, 0x0000); - regmap_write(rt5682->regmap, RT5682_STO1_DAC_MIXER, 0x2080); - regmap_write(rt5682->regmap, RT5682_STO1_ADC_MIXER, 0x4040); - regmap_write(rt5682->regmap, RT5682_DEPOP_1, 0x0069); + regmap_write(rt5682->regmap, RT5682_MICBIAS_2, 0x0300); + regmap_write(rt5682->regmap, RT5682_GLB_CLK, 0x8000); + regmap_write(rt5682->regmap, RT5682_PWR_DIG_1, 0x0100); regmap_write(rt5682->regmap, RT5682_CHOP_DAC, 0x3000); - regmap_write(rt5682->regmap, RT5682_HP_CTRL_2, 0x6000); - regmap_write(rt5682->regmap, RT5682_HP_CHARGE_PUMP_1, 0x0f26); - regmap_write(rt5682->regmap, RT5682_CALIB_ADC_CTRL, 0x7f05); - regmap_write(rt5682->regmap, RT5682_STO1_ADC_MIXER, 0x686c); - regmap_write(rt5682->regmap, RT5682_CAL_REC, 0x0d0d); - regmap_write(rt5682->regmap, RT5682_HP_CALIB_CTRL_9, 0x000f); - regmap_write(rt5682->regmap, RT5682_PWR_DIG_1, 0x8d01); regmap_write(rt5682->regmap, RT5682_HP_CALIB_CTRL_2, 0x0321); regmap_write(rt5682->regmap, RT5682_HP_LOGIC_CTRL_2, 0x0004); regmap_write(rt5682->regmap, RT5682_HP_CALIB_CTRL_1, 0x7c00); regmap_write(rt5682->regmap, RT5682_HP_CALIB_CTRL_3, 0x06a1); - regmap_write(rt5682->regmap, RT5682_A_DAC1_MUX, 0x0311); - regmap_write(rt5682->regmap, RT5682_RESET_HPF_CTRL, 0x0000); - regmap_write(rt5682->regmap, RT5682_ADC_STO1_HP_CTRL_1, 0x3320); + regmap_write(rt5682->regmap, RT5682_HP_CALIB_CTRL_1, 0x7c00); regmap_write(rt5682->regmap, RT5682_HP_CALIB_CTRL_1, 0xfc00); @@ -2490,7 +2478,7 @@ static void rt5682_calibrate(struct rt5682_priv *rt5682) pr_err("HP Calibration Failure\n"); /* restore settings */ - regmap_write(rt5682->regmap, RT5682_STO1_ADC_MIXER, 0xc0c4); + regmap_write(rt5682->regmap, RT5682_GLB_CLK, 0x0000); regmap_write(rt5682->regmap, RT5682_PWR_DIG_1, 0x0000); mutex_unlock(&rt5682->calibrate_mutex); From b4af16d617add4f6380d6651473b8efba13ca8ca Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Wed, 22 Aug 2018 15:24:57 -0500 Subject: [PATCH 022/299] ALSA: hda: move hda_codec.h to include/sound As suggested by Takashi, move this header file to make it easier to include from e.g. the Intel Skylake driver in follow-up patches Signed-off-by: Pierre-Louis Bossart Signed-off-by: Mark Brown --- {sound/pci/hda => include/sound}/hda_codec.h | 0 sound/pci/hda/hda_auto_parser.c | 2 +- sound/pci/hda/hda_beep.h | 2 +- sound/pci/hda/hda_bind.c | 2 +- sound/pci/hda/hda_codec.c | 2 +- sound/pci/hda/hda_controller.h | 2 +- sound/pci/hda/hda_eld.c | 2 +- sound/pci/hda/hda_generic.c | 2 +- sound/pci/hda/hda_hwdep.c | 2 +- sound/pci/hda/hda_intel.c | 2 +- sound/pci/hda/hda_jack.c | 2 +- sound/pci/hda/hda_proc.c | 2 +- sound/pci/hda/hda_sysfs.c | 2 +- sound/pci/hda/hda_tegra.c | 2 +- sound/pci/hda/patch_analog.c | 2 +- sound/pci/hda/patch_ca0110.c | 2 +- sound/pci/hda/patch_ca0132.c | 2 +- sound/pci/hda/patch_cirrus.c | 2 +- sound/pci/hda/patch_cmedia.c | 2 +- sound/pci/hda/patch_conexant.c | 2 +- sound/pci/hda/patch_hdmi.c | 2 +- sound/pci/hda/patch_realtek.c | 2 +- sound/pci/hda/patch_si3054.c | 2 +- sound/pci/hda/patch_sigmatel.c | 2 +- sound/pci/hda/patch_via.c | 2 +- 25 files changed, 24 insertions(+), 24 deletions(-) rename {sound/pci/hda => include/sound}/hda_codec.h (100%) diff --git a/sound/pci/hda/hda_codec.h b/include/sound/hda_codec.h similarity index 100% rename from sound/pci/hda/hda_codec.h rename to include/sound/hda_codec.h diff --git a/sound/pci/hda/hda_auto_parser.c b/sound/pci/hda/hda_auto_parser.c index b9a6b66aeb0e..df0d636145f8 100644 --- a/sound/pci/hda/hda_auto_parser.c +++ b/sound/pci/hda/hda_auto_parser.c @@ -13,7 +13,7 @@ #include #include #include -#include "hda_codec.h" +#include #include "hda_local.h" #include "hda_auto_parser.h" diff --git a/sound/pci/hda/hda_beep.h b/sound/pci/hda/hda_beep.h index d1a6a9c1329a..f1457c6b3969 100644 --- a/sound/pci/hda/hda_beep.h +++ b/sound/pci/hda/hda_beep.h @@ -9,7 +9,7 @@ #ifndef __SOUND_HDA_BEEP_H #define __SOUND_HDA_BEEP_H -#include "hda_codec.h" +#include #define HDA_BEEP_MODE_OFF 0 #define HDA_BEEP_MODE_ON 1 diff --git a/sound/pci/hda/hda_bind.c b/sound/pci/hda/hda_bind.c index d361bb77ca00..2222b47d4ec4 100644 --- a/sound/pci/hda/hda_bind.c +++ b/sound/pci/hda/hda_bind.c @@ -11,7 +11,7 @@ #include #include #include -#include "hda_codec.h" +#include #include "hda_local.h" /* diff --git a/sound/pci/hda/hda_codec.c b/sound/pci/hda/hda_codec.c index 0a5085537034..ccbb0d12b8cc 100644 --- a/sound/pci/hda/hda_codec.c +++ b/sound/pci/hda/hda_codec.c @@ -27,7 +27,7 @@ #include #include #include -#include "hda_codec.h" +#include #include #include #include diff --git a/sound/pci/hda/hda_controller.h b/sound/pci/hda/hda_controller.h index a68e75b00ea3..55760e5231e6 100644 --- a/sound/pci/hda/hda_controller.h +++ b/sound/pci/hda/hda_controller.h @@ -20,7 +20,7 @@ #include #include #include -#include "hda_codec.h" +#include #include #define AZX_MAX_CODECS HDA_MAX_CODECS diff --git a/sound/pci/hda/hda_eld.c b/sound/pci/hda/hda_eld.c index ba7fe9b6655c..806b12ed44a2 100644 --- a/sound/pci/hda/hda_eld.c +++ b/sound/pci/hda/hda_eld.c @@ -27,7 +27,7 @@ #include #include #include -#include "hda_codec.h" +#include #include "hda_local.h" enum eld_versions { diff --git a/sound/pci/hda/hda_generic.c b/sound/pci/hda/hda_generic.c index 579984ecdec3..276150f29cda 100644 --- a/sound/pci/hda/hda_generic.c +++ b/sound/pci/hda/hda_generic.c @@ -32,7 +32,7 @@ #include #include #include -#include "hda_codec.h" +#include #include "hda_local.h" #include "hda_auto_parser.h" #include "hda_jack.h" diff --git a/sound/pci/hda/hda_hwdep.c b/sound/pci/hda/hda_hwdep.c index cc009a4a3d1d..268bba6ec985 100644 --- a/sound/pci/hda/hda_hwdep.c +++ b/sound/pci/hda/hda_hwdep.c @@ -23,7 +23,7 @@ #include #include #include -#include "hda_codec.h" +#include #include "hda_local.h" #include #include diff --git a/sound/pci/hda/hda_intel.c b/sound/pci/hda/hda_intel.c index 1b2ce304152a..c8fde95e2393 100644 --- a/sound/pci/hda/hda_intel.c +++ b/sound/pci/hda/hda_intel.c @@ -63,7 +63,7 @@ #include #include #include -#include "hda_codec.h" +#include #include "hda_controller.h" #include "hda_intel.h" diff --git a/sound/pci/hda/hda_jack.c b/sound/pci/hda/hda_jack.c index a33234e04d4f..c499727920e6 100644 --- a/sound/pci/hda/hda_jack.c +++ b/sound/pci/hda/hda_jack.c @@ -15,7 +15,7 @@ #include #include #include -#include "hda_codec.h" +#include #include "hda_local.h" #include "hda_auto_parser.h" #include "hda_jack.h" diff --git a/sound/pci/hda/hda_proc.c b/sound/pci/hda/hda_proc.c index c6b778b2580c..a65740419650 100644 --- a/sound/pci/hda/hda_proc.c +++ b/sound/pci/hda/hda_proc.c @@ -25,7 +25,7 @@ #include #include #include -#include "hda_codec.h" +#include #include "hda_local.h" static int dump_coef = -1; diff --git a/sound/pci/hda/hda_sysfs.c b/sound/pci/hda/hda_sysfs.c index 6ec79c58d48d..c154b19a0c45 100644 --- a/sound/pci/hda/hda_sysfs.c +++ b/sound/pci/hda/hda_sysfs.c @@ -14,7 +14,7 @@ #include #include #include -#include "hda_codec.h" +#include #include "hda_local.h" #include #include diff --git a/sound/pci/hda/hda_tegra.c b/sound/pci/hda/hda_tegra.c index 0621920f7617..4bc5232eac1c 100644 --- a/sound/pci/hda/hda_tegra.c +++ b/sound/pci/hda/hda_tegra.c @@ -35,7 +35,7 @@ #include #include -#include "hda_codec.h" +#include #include "hda_controller.h" /* Defines for Nvidia Tegra HDA support */ diff --git a/sound/pci/hda/patch_analog.c b/sound/pci/hda/patch_analog.c index fd476fb40e1b..ebfd0be885b3 100644 --- a/sound/pci/hda/patch_analog.c +++ b/sound/pci/hda/patch_analog.c @@ -24,7 +24,7 @@ #include #include -#include "hda_codec.h" +#include #include "hda_local.h" #include "hda_auto_parser.h" #include "hda_beep.h" diff --git a/sound/pci/hda/patch_ca0110.c b/sound/pci/hda/patch_ca0110.c index c2d9ee9cfdc0..21d0f0610913 100644 --- a/sound/pci/hda/patch_ca0110.c +++ b/sound/pci/hda/patch_ca0110.c @@ -22,7 +22,7 @@ #include #include #include -#include "hda_codec.h" +#include #include "hda_local.h" #include "hda_auto_parser.h" #include "hda_jack.h" diff --git a/sound/pci/hda/patch_ca0132.c b/sound/pci/hda/patch_ca0132.c index 0166a3d7cd55..a585d0ec6d77 100644 --- a/sound/pci/hda/patch_ca0132.c +++ b/sound/pci/hda/patch_ca0132.c @@ -32,7 +32,7 @@ #include #include #include -#include "hda_codec.h" +#include #include "hda_local.h" #include "hda_auto_parser.h" #include "hda_jack.h" diff --git a/sound/pci/hda/patch_cirrus.c b/sound/pci/hda/patch_cirrus.c index a7f91be45194..64fa5a82bb9f 100644 --- a/sound/pci/hda/patch_cirrus.c +++ b/sound/pci/hda/patch_cirrus.c @@ -23,7 +23,7 @@ #include #include #include -#include "hda_codec.h" +#include #include "hda_local.h" #include "hda_auto_parser.h" #include "hda_jack.h" diff --git a/sound/pci/hda/patch_cmedia.c b/sound/pci/hda/patch_cmedia.c index 1b2195dd2b26..52642ba3e2c0 100644 --- a/sound/pci/hda/patch_cmedia.c +++ b/sound/pci/hda/patch_cmedia.c @@ -25,7 +25,7 @@ #include #include #include -#include "hda_codec.h" +#include #include "hda_local.h" #include "hda_auto_parser.h" #include "hda_jack.h" diff --git a/sound/pci/hda/patch_conexant.c b/sound/pci/hda/patch_conexant.c index cfd4e4f97f8f..5592557fe50e 100644 --- a/sound/pci/hda/patch_conexant.c +++ b/sound/pci/hda/patch_conexant.c @@ -27,7 +27,7 @@ #include #include -#include "hda_codec.h" +#include #include "hda_local.h" #include "hda_auto_parser.h" #include "hda_beep.h" diff --git a/sound/pci/hda/patch_hdmi.c b/sound/pci/hda/patch_hdmi.c index cb587dce67a9..67099cbb6be2 100644 --- a/sound/pci/hda/patch_hdmi.c +++ b/sound/pci/hda/patch_hdmi.c @@ -41,7 +41,7 @@ #include #include #include -#include "hda_codec.h" +#include #include "hda_local.h" #include "hda_jack.h" diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c index 1d117f00d04d..6f3c8e888c2a 100644 --- a/sound/pci/hda/patch_realtek.c +++ b/sound/pci/hda/patch_realtek.c @@ -32,7 +32,7 @@ #include #include #include -#include "hda_codec.h" +#include #include "hda_local.h" #include "hda_auto_parser.h" #include "hda_jack.h" diff --git a/sound/pci/hda/patch_si3054.c b/sound/pci/hda/patch_si3054.c index f63acb1b965c..c49d25bcd7f2 100644 --- a/sound/pci/hda/patch_si3054.c +++ b/sound/pci/hda/patch_si3054.c @@ -27,7 +27,7 @@ #include #include #include -#include "hda_codec.h" +#include #include "hda_local.h" /* si3054 verbs */ diff --git a/sound/pci/hda/patch_sigmatel.c b/sound/pci/hda/patch_sigmatel.c index 046705b4691a..d16a25a395c9 100644 --- a/sound/pci/hda/patch_sigmatel.c +++ b/sound/pci/hda/patch_sigmatel.c @@ -32,7 +32,7 @@ #include #include #include -#include "hda_codec.h" +#include #include "hda_local.h" #include "hda_auto_parser.h" #include "hda_beep.h" diff --git a/sound/pci/hda/patch_via.c b/sound/pci/hda/patch_via.c index 6b9617aee0e6..9f6f13e25145 100644 --- a/sound/pci/hda/patch_via.c +++ b/sound/pci/hda/patch_via.c @@ -52,7 +52,7 @@ #include #include #include -#include "hda_codec.h" +#include #include "hda_local.h" #include "hda_auto_parser.h" #include "hda_jack.h" From 8dce1d026da4588382ed8c03e791c7c9b37b22e8 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Wed, 22 Aug 2018 15:24:58 -0500 Subject: [PATCH 023/299] ASoC: Intel: common: add table for HDA-based platforms Expose a table containing machine driver information for HDAudio-based platforms handled by ASoC on Intel hardware. We only set constant values that are valid across multiple platforms. The firmware name used by the DSP will be set dynamically for each platform. The table is made of a single entry for now, if we need more complicated set-up where HDAudio is mixed with ACPI-enumerated devices (I2C, SoundWire) then we'd expect the differentiation to be handled through information provided by the BIOS (as done for KBL Chromebooks). Signed-off-by: Pierre-Louis Bossart Signed-off-by: Mark Brown --- include/sound/soc-acpi-intel-match.h | 6 +++ sound/soc/intel/common/Makefile | 3 +- .../intel/common/soc-acpi-intel-hda-match.c | 40 +++++++++++++++++++ 3 files changed, 48 insertions(+), 1 deletion(-) create mode 100644 sound/soc/intel/common/soc-acpi-intel-hda-match.c diff --git a/include/sound/soc-acpi-intel-match.h b/include/sound/soc-acpi-intel-match.h index bb1d24b703fb..f48f59e5b7b0 100644 --- a/include/sound/soc-acpi-intel-match.h +++ b/include/sound/soc-acpi-intel-match.h @@ -25,4 +25,10 @@ extern struct snd_soc_acpi_mach snd_soc_acpi_intel_bxt_machines[]; extern struct snd_soc_acpi_mach snd_soc_acpi_intel_glk_machines[]; extern struct snd_soc_acpi_mach snd_soc_acpi_intel_cnl_machines[]; +/* + * generic table used for HDA codec-based platforms, possibly with + * additional ACPI-enumerated codecs + */ +extern struct snd_soc_acpi_mach snd_soc_acpi_intel_hda_machines[]; + #endif diff --git a/sound/soc/intel/common/Makefile b/sound/soc/intel/common/Makefile index 915a34cdc8ac..c1f50a079d34 100644 --- a/sound/soc/intel/common/Makefile +++ b/sound/soc/intel/common/Makefile @@ -7,7 +7,8 @@ snd-soc-acpi-intel-match-objs := soc-acpi-intel-byt-match.o soc-acpi-intel-cht-m soc-acpi-intel-hsw-bdw-match.o \ soc-acpi-intel-skl-match.o soc-acpi-intel-kbl-match.o \ soc-acpi-intel-bxt-match.o soc-acpi-intel-glk-match.o \ - soc-acpi-intel-cnl-match.o + soc-acpi-intel-cnl-match.o \ + soc-acpi-intel-hda-match.o obj-$(CONFIG_SND_SOC_INTEL_SST) += snd-soc-sst-dsp.o snd-soc-sst-ipc.o obj-$(CONFIG_SND_SOC_INTEL_SST_ACPI) += snd-soc-sst-acpi.o diff --git a/sound/soc/intel/common/soc-acpi-intel-hda-match.c b/sound/soc/intel/common/soc-acpi-intel-hda-match.c new file mode 100644 index 000000000000..533c1064f84b --- /dev/null +++ b/sound/soc/intel/common/soc-acpi-intel-hda-match.c @@ -0,0 +1,40 @@ +// SPDX-License-Identifier: GPL-2.0 +// Copyright (c) 2018, Intel Corporation. + +/* + * soc-apci-intel-hda-match.c - tables and support for HDA+ACPI enumeration. + * + */ + +#include +#include +#include "../skylake/skl.h" + +static struct skl_machine_pdata hda_pdata = { + .use_tplg_pcm = true, +}; + +struct snd_soc_acpi_mach snd_soc_acpi_intel_hda_machines[] = { + { + /* .id is not used in this file */ + .drv_name = "skl_hda_dsp_generic", + + /* .fw_filename is dynamically set in skylake driver */ + + /* .sof_fw_filename is dynamically set in sof/intel driver */ + + .sof_tplg_filename = "intel/sof-hda-generic.tplg", + + /* + * .machine_quirk and .quirk_data are not used here but + * can be used if we need a more complicated machine driver + * combining HDA+other device (e.g. DMIC). + */ + .pdata = &hda_pdata, + }, + {}, +}; +EXPORT_SYMBOL_GPL(snd_soc_acpi_intel_hda_machines); + +MODULE_LICENSE("GPL v2"); +MODULE_DESCRIPTION("Intel Common ACPI Match module"); From 7c33b5f16915a7bc3d3b81a9a041bdc562f71dfb Mon Sep 17 00:00:00 2001 From: Rakesh Ughreja Date: Wed, 22 Aug 2018 15:24:59 -0500 Subject: [PATCH 024/299] ASoC: Intel: Boards: Machine driver for SKL+ w/ HDAudio codecs Add machine driver for Intel platforms (SKL/KBL/BXT/APL) with HDA and iDisp codecs. This patch adds support for only iDisp (HDMI/DP) codec. In the following patches support for HDA codecs will be added. This should work for other Intel platforms as well e.g. GLK,CNL however this series is not tested on all the platforms. Signed-off-by: Rakesh Ughreja Signed-off-by: Pierre-Louis Bossart Signed-off-by: Mark Brown --- sound/soc/intel/boards/Kconfig | 8 ++ sound/soc/intel/boards/Makefile | 2 + sound/soc/intel/boards/skl_hda_dsp_common.c | 103 +++++++++++++ sound/soc/intel/boards/skl_hda_dsp_common.h | 38 +++++ sound/soc/intel/boards/skl_hda_dsp_generic.c | 144 +++++++++++++++++++ sound/soc/intel/skylake/skl.h | 2 + 6 files changed, 297 insertions(+) create mode 100644 sound/soc/intel/boards/skl_hda_dsp_common.c create mode 100644 sound/soc/intel/boards/skl_hda_dsp_common.h create mode 100644 sound/soc/intel/boards/skl_hda_dsp_generic.c diff --git a/sound/soc/intel/boards/Kconfig b/sound/soc/intel/boards/Kconfig index cccda87f4b34..0f0d57859555 100644 --- a/sound/soc/intel/boards/Kconfig +++ b/sound/soc/intel/boards/Kconfig @@ -279,6 +279,14 @@ config SND_SOC_INTEL_KBL_DA7219_MAX98357A_MACH This adds support for ASoC Onboard Codec I2S machine driver. This will create an alsa sound card for DA7219 + MAX98357A I2S audio codec. Say Y if you have such a device. + +config SND_SOC_INTEL_SKL_HDA_DSP_GENERIC_MACH + tristate "SKL/KBL/BXT/APL with HDA Codecs" + select SND_SOC_HDAC_HDMI + help + This adds support for ASoC machine driver for Intel platforms + SKL/KBL/BXT/APL with iDisp, HDA audio codecs. + Say Y or m if you have such a device. This is a recommended option. If unsure select "N". config SND_SOC_INTEL_GLK_RT5682_MAX98357A_MACH diff --git a/sound/soc/intel/boards/Makefile b/sound/soc/intel/boards/Makefile index 87ef8b4058e5..6e88373cbe35 100644 --- a/sound/soc/intel/boards/Makefile +++ b/sound/soc/intel/boards/Makefile @@ -20,6 +20,7 @@ snd-soc-kbl_da7219_max98357a-objs := kbl_da7219_max98357a.o snd-soc-kbl_rt5663_max98927-objs := kbl_rt5663_max98927.o snd-soc-kbl_rt5663_rt5514_max98927-objs := kbl_rt5663_rt5514_max98927.o snd-soc-skl_rt286-objs := skl_rt286.o +snd-soc-skl_hda_dsp-objs := skl_hda_dsp_generic.o skl_hda_dsp_common.o snd-skl_nau88l25_max98357a-objs := skl_nau88l25_max98357a.o snd-soc-skl_nau88l25_ssm4567-objs := skl_nau88l25_ssm4567.o @@ -46,3 +47,4 @@ obj-$(CONFIG_SND_SOC_INTEL_KBL_RT5663_RT5514_MAX98927_MACH) += snd-soc-kbl_rt566 obj-$(CONFIG_SND_SOC_INTEL_SKL_RT286_MACH) += snd-soc-skl_rt286.o obj-$(CONFIG_SND_SOC_INTEL_SKL_NAU88L25_MAX98357A_MACH) += snd-skl_nau88l25_max98357a.o obj-$(CONFIG_SND_SOC_INTEL_SKL_NAU88L25_SSM4567_MACH) += snd-soc-skl_nau88l25_ssm4567.o +obj-$(CONFIG_SND_SOC_INTEL_SKL_HDA_DSP_GENERIC_MACH) += snd-soc-skl_hda_dsp.o diff --git a/sound/soc/intel/boards/skl_hda_dsp_common.c b/sound/soc/intel/boards/skl_hda_dsp_common.c new file mode 100644 index 000000000000..f9917e0f2ba8 --- /dev/null +++ b/sound/soc/intel/boards/skl_hda_dsp_common.c @@ -0,0 +1,103 @@ +// SPDX-License-Identifier: GPL-2.0 +// Copyright(c) 2015-18 Intel Corporation. + +/* + * Common functions used in different Intel machine drivers + */ +#include +#include +#include +#include +#include +#include +#include +#include "../../codecs/hdac_hdmi.h" +#include "../skylake/skl.h" +#include "skl_hda_dsp_common.h" + +#define NAME_SIZE 32 + +int skl_hda_hdmi_add_pcm(struct snd_soc_card *card, int device) +{ + struct skl_hda_private *ctx = snd_soc_card_get_drvdata(card); + struct skl_hda_hdmi_pcm *pcm; + char dai_name[NAME_SIZE]; + + pcm = devm_kzalloc(card->dev, sizeof(*pcm), GFP_KERNEL); + if (!pcm) + return -ENOMEM; + + snprintf(dai_name, sizeof(dai_name), "intel-hdmi-hifi%d", + ctx->dai_index); + pcm->codec_dai = snd_soc_card_get_codec_dai(card, dai_name); + if (!pcm->codec_dai) + return -EINVAL; + + pcm->device = device; + list_add_tail(&pcm->head, &ctx->hdmi_pcm_list); + + return 0; +} + +/* skl_hda_digital audio interface glue - connects codec <--> CPU */ +struct snd_soc_dai_link skl_hda_be_dai_links[HDA_DSP_MAX_BE_DAI_LINKS] = { + /* Back End DAI links */ + { + .name = "iDisp1", + .id = 1, + .cpu_dai_name = "iDisp1 Pin", + .codec_name = "ehdaudio0D2", + .codec_dai_name = "intel-hdmi-hifi1", + .dpcm_playback = 1, + .no_pcm = 1, + }, + { + .name = "iDisp2", + .id = 2, + .cpu_dai_name = "iDisp2 Pin", + .codec_name = "ehdaudio0D2", + .codec_dai_name = "intel-hdmi-hifi2", + .dpcm_playback = 1, + .no_pcm = 1, + }, + { + .name = "iDisp3", + .id = 3, + .cpu_dai_name = "iDisp3 Pin", + .codec_name = "ehdaudio0D2", + .codec_dai_name = "intel-hdmi-hifi3", + .dpcm_playback = 1, + .no_pcm = 1, + }, +}; + +int skl_hda_hdmi_jack_init(struct snd_soc_card *card) +{ + struct skl_hda_private *ctx = snd_soc_card_get_drvdata(card); + struct snd_soc_component *component = NULL; + struct skl_hda_hdmi_pcm *pcm; + char jack_name[NAME_SIZE]; + int err; + + list_for_each_entry(pcm, &ctx->hdmi_pcm_list, head) { + component = pcm->codec_dai->component; + snprintf(jack_name, sizeof(jack_name), + "HDMI/DP, pcm=%d Jack", pcm->device); + err = snd_soc_card_jack_new(card, jack_name, + SND_JACK_AVOUT, &pcm->hdmi_jack, + NULL, 0); + + if (err) + return err; + + err = hdac_hdmi_jack_init(pcm->codec_dai, pcm->device, + &pcm->hdmi_jack); + if (err < 0) + return err; + } + + if (!component) + return -EINVAL; + + return hdac_hdmi_jack_port_init(component, &card->dapm); +} diff --git a/sound/soc/intel/boards/skl_hda_dsp_common.h b/sound/soc/intel/boards/skl_hda_dsp_common.h new file mode 100644 index 000000000000..b6c79696bfba --- /dev/null +++ b/sound/soc/intel/boards/skl_hda_dsp_common.h @@ -0,0 +1,38 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright(c) 2015-18 Intel Corporation. + */ + +/* + * This file defines data structures used in Machine Driver for Intel + * platforms with HDA Codecs. + */ + +#ifndef __SOUND_SOC_HDA_DSP_COMMON_H +#define __SOUND_SOC_HDA_DSP_COMMON_H +#include +#include +#include +#include + +#define HDA_DSP_MAX_BE_DAI_LINKS 3 + +struct skl_hda_hdmi_pcm { + struct list_head head; + struct snd_soc_dai *codec_dai; + struct snd_soc_jack hdmi_jack; + int device; +}; + +struct skl_hda_private { + struct list_head hdmi_pcm_list; + int pcm_count; + int dai_index; + const char *platform_name; +}; + +extern struct snd_soc_dai_link skl_hda_be_dai_links[HDA_DSP_MAX_BE_DAI_LINKS]; +int skl_hda_hdmi_jack_init(struct snd_soc_card *card); +int skl_hda_hdmi_add_pcm(struct snd_soc_card *card, int device); + +#endif /* __SOUND_SOC_HDA_DSP_COMMON_H */ diff --git a/sound/soc/intel/boards/skl_hda_dsp_generic.c b/sound/soc/intel/boards/skl_hda_dsp_generic.c new file mode 100644 index 000000000000..920bc2ce22aa --- /dev/null +++ b/sound/soc/intel/boards/skl_hda_dsp_generic.c @@ -0,0 +1,144 @@ +// SPDX-License-Identifier: GPL-2.0 +// Copyright(c) 2015-18 Intel Corporation. + +/* + * Machine Driver for SKL+ platforms with DSP and iDisp, HDA Codecs + */ + +#include +#include +#include +#include +#include +#include +#include +#include "../../codecs/hdac_hdmi.h" +#include "../skylake/skl.h" +#include "skl_hda_dsp_common.h" + +static const struct snd_soc_dapm_route skl_hda_map[] = { + { "hifi3", NULL, "iDisp3 Tx"}, + { "iDisp3 Tx", NULL, "iDisp3_out"}, + { "hifi2", NULL, "iDisp2 Tx"}, + { "iDisp2 Tx", NULL, "iDisp2_out"}, + { "hifi1", NULL, "iDisp1 Tx"}, + { "iDisp1 Tx", NULL, "iDisp1_out"}, +}; + +static int skl_hda_card_late_probe(struct snd_soc_card *card) +{ + return skl_hda_hdmi_jack_init(card); +} + +static int +skl_hda_add_dai_link(struct snd_soc_card *card, struct snd_soc_dai_link *link) +{ + struct skl_hda_private *ctx = snd_soc_card_get_drvdata(card); + int ret = 0; + + dev_dbg(card->dev, "%s: dai link name - %s\n", __func__, link->name); + link->platform_name = ctx->platform_name; + link->nonatomic = 1; + + if (strstr(link->name, "HDMI")) { + ret = skl_hda_hdmi_add_pcm(card, ctx->pcm_count); + + if (ret < 0) + return ret; + + ctx->dai_index++; + } + + ctx->pcm_count++; + return ret; +} + +static struct snd_soc_card hda_soc_card = { + .name = "skl_hda_card", + .owner = THIS_MODULE, + .dai_link = skl_hda_be_dai_links, + .dapm_routes = skl_hda_map, + .add_dai_link = skl_hda_add_dai_link, + .fully_routed = true, + .late_probe = skl_hda_card_late_probe, +}; + +#define IDISP_DAI_COUNT 3 +/* there are two routes per iDisp output */ +#define IDISP_ROUTE_COUNT (IDISP_DAI_COUNT * 2) +#define IDISP_CODEC_MASK 0x4 + +static int skl_hda_fill_card_info(struct skl_machine_pdata *pdata) +{ + struct snd_soc_card *card = &hda_soc_card; + u32 codec_count, codec_mask; + int i, num_links, num_route; + + codec_mask = pdata->codec_mask; + codec_count = hweight_long(codec_mask); + + if (codec_count == 1 && pdata->codec_mask & IDISP_CODEC_MASK) { + num_links = IDISP_DAI_COUNT; + num_route = IDISP_ROUTE_COUNT; + } else { + return -EINVAL; + } + + card->num_links = num_links; + card->num_dapm_routes = num_route; + + for (i = 0; i < num_links; i++) + skl_hda_be_dai_links[i].platform_name = pdata->platform; + + return 0; +} + +static int skl_hda_audio_probe(struct platform_device *pdev) +{ + struct skl_machine_pdata *pdata; + struct skl_hda_private *ctx; + int ret; + + dev_dbg(&pdev->dev, "%s: entry\n", __func__); + + ctx = devm_kzalloc(&pdev->dev, sizeof(*ctx), GFP_ATOMIC); + if (!ctx) + return -ENOMEM; + + INIT_LIST_HEAD(&ctx->hdmi_pcm_list); + + pdata = dev_get_drvdata(&pdev->dev); + if (!pdata) + return -EINVAL; + + ret = skl_hda_fill_card_info(pdata); + if (ret < 0) { + dev_err(&pdev->dev, "Unsupported HDAudio/iDisp configuration found\n"); + return ret; + } + + ctx->pcm_count = hda_soc_card.num_links; + ctx->dai_index = 1; /* hdmi codec dai name starts from index 1 */ + ctx->platform_name = pdata->platform; + + hda_soc_card.dev = &pdev->dev; + snd_soc_card_set_drvdata(&hda_soc_card, ctx); + + return devm_snd_soc_register_card(&pdev->dev, &hda_soc_card); +} + +static struct platform_driver skl_hda_audio = { + .probe = skl_hda_audio_probe, + .driver = { + .name = "skl_hda_dsp_generic", + .pm = &snd_soc_pm_ops, + }, +}; + +module_platform_driver(skl_hda_audio) + +/* Module information */ +MODULE_DESCRIPTION("SKL/KBL/BXT/APL HDA Generic Machine driver"); +MODULE_AUTHOR("Rakesh Ughreja "); +MODULE_LICENSE("GPL v2"); +MODULE_ALIAS("platform:skl_hda_dsp_generic"); diff --git a/sound/soc/intel/skylake/skl.h b/sound/soc/intel/skylake/skl.h index 78aa8bdcb619..4105a9371b64 100644 --- a/sound/soc/intel/skylake/skl.h +++ b/sound/soc/intel/skylake/skl.h @@ -117,6 +117,8 @@ struct skl_dma_params { struct skl_machine_pdata { u32 dmic_num; bool use_tplg_pcm; /* use dais and dai links from topology */ + const char *platform; + u32 codec_mask; }; struct skl_dsp_ops { From 9cdae4352cba3f66d39a4ef78bb726940ae1e513 Mon Sep 17 00:00:00 2001 From: Rakesh Ughreja Date: Wed, 22 Aug 2018 15:25:00 -0500 Subject: [PATCH 025/299] ASoC: Intel: Skylake: use HDAudio if ACPI enumeration fails When no I2S based codec entries are found in the BIOS, check if there are any HDA codecs detected on the bus. Based on the number of codecs found take appropriate action in machine driver. If there are two HDA codecs i.e. iDisp + HDA found on the bus, register DAIs and DAI links for both. If only one codec i.e. iDisp is found then load only iDisp machine driver. Signed-off-by: Rakesh Ughreja Signed-off-by: Pierre-Louis Bossart Signed-off-by: Mark Brown --- sound/soc/intel/skylake/skl.c | 38 ++++++++++++++++++++++++++++++----- 1 file changed, 33 insertions(+), 5 deletions(-) diff --git a/sound/soc/intel/skylake/skl.c b/sound/soc/intel/skylake/skl.c index cf09721ca13e..3b836125d1de 100644 --- a/sound/soc/intel/skylake/skl.c +++ b/sound/soc/intel/skylake/skl.c @@ -472,6 +472,25 @@ static struct skl_ssp_clk skl_ssp_clks[] = { {.name = "ssp5_sclkfs"}, }; +static struct snd_soc_acpi_mach *skl_find_hda_machine(struct skl *skl, + struct snd_soc_acpi_mach *machines) +{ + struct hdac_bus *bus = skl_to_bus(skl); + struct snd_soc_acpi_mach *mach; + + /* check if we have any codecs detected on bus */ + if (bus->codec_mask == 0) + return NULL; + + /* point to common table */ + mach = snd_soc_acpi_intel_hda_machines; + + /* all entries in the machine table use the same firmware */ + mach->fw_filename = machines->fw_filename; + + return mach; +} + static int skl_find_machine(struct skl *skl, void *driver_data) { struct hdac_bus *bus = skl_to_bus(skl); @@ -479,9 +498,13 @@ static int skl_find_machine(struct skl *skl, void *driver_data) struct skl_machine_pdata *pdata; mach = snd_soc_acpi_find_machine(mach); - if (mach == NULL) { - dev_err(bus->dev, "No matching machine driver found\n"); - return -ENODEV; + if (!mach) { + dev_dbg(bus->dev, "No matching I2S machine driver found\n"); + mach = skl_find_hda_machine(skl, driver_data); + if (!mach) { + dev_err(bus->dev, "No matching machine driver found\n"); + return -ENODEV; + } } skl->mach = mach; @@ -498,8 +521,9 @@ static int skl_find_machine(struct skl *skl, void *driver_data) static int skl_machine_device_register(struct skl *skl) { - struct hdac_bus *bus = skl_to_bus(skl); struct snd_soc_acpi_mach *mach = skl->mach; + struct hdac_bus *bus = skl_to_bus(skl); + struct skl_machine_pdata *pdata; struct platform_device *pdev; int ret; @@ -516,8 +540,12 @@ static int skl_machine_device_register(struct skl *skl) return -EIO; } - if (mach->pdata) + if (mach->pdata) { + pdata = (struct skl_machine_pdata *)mach->pdata; + pdata->platform = dev_name(bus->dev); + pdata->codec_mask = bus->codec_mask; dev_set_drvdata(&pdev->dev, mach->pdata); + } skl->i2s_dev = pdev; From 3d17871349d5cec0a37ce9407ba72fdbf8572cfd Mon Sep 17 00:00:00 2001 From: Rakesh Ughreja Date: Wed, 22 Aug 2018 15:25:01 -0500 Subject: [PATCH 026/299] ASoC: Intel: Skylake: add HDA BE DAIs Add support for HDA BE DAIs in SKL platform driver. Signed-off-by: Rakesh Ughreja Signed-off-by: Pierre-Louis Bossart Signed-off-by: Mark Brown --- sound/soc/intel/skylake/skl-pcm.c | 70 +++++++++++++++++++++++++------ 1 file changed, 58 insertions(+), 12 deletions(-) diff --git a/sound/soc/intel/skylake/skl-pcm.c b/sound/soc/intel/skylake/skl-pcm.c index 823e39103edd..00b7a91b18c9 100644 --- a/sound/soc/intel/skylake/skl-pcm.c +++ b/sound/soc/intel/skylake/skl-pcm.c @@ -32,6 +32,7 @@ #define HDA_MONO 1 #define HDA_STEREO 2 #define HDA_QUAD 4 +#define HDA_MAX 8 static const struct snd_pcm_hardware azx_pcm_hw = { .info = (SNDRV_PCM_INFO_MMAP | @@ -569,7 +570,10 @@ static int skl_link_hw_params(struct snd_pcm_substream *substream, stream_tag = hdac_stream(link_dev)->stream_tag; /* set the stream tag in the codec dai dma params */ - snd_soc_dai_set_tdm_slot(codec_dai, stream_tag, 0, 0, 0); + if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) + snd_soc_dai_set_tdm_slot(codec_dai, stream_tag, 0, 0, 0); + else + snd_soc_dai_set_tdm_slot(codec_dai, 0, stream_tag, 0, 0); p_params.s_fmt = snd_pcm_format_width(params_format(params)); p_params.ch = params_channels(params); @@ -995,21 +999,63 @@ static struct snd_soc_dai_driver skl_platform_dai[] = { }, }, { - .name = "HD-Codec Pin", + .name = "Analog CPU DAI", .ops = &skl_link_dai_ops, .playback = { - .stream_name = "HD-Codec Tx", - .channels_min = HDA_STEREO, - .channels_max = HDA_STEREO, - .rates = SNDRV_PCM_RATE_48000, - .formats = SNDRV_PCM_FMTBIT_S16_LE, + .stream_name = "Analog CPU Playback", + .channels_min = HDA_MONO, + .channels_max = HDA_MAX, + .rates = SNDRV_PCM_RATE_8000_192000, + .formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S24_LE | + SNDRV_PCM_FMTBIT_S32_LE, }, .capture = { - .stream_name = "HD-Codec Rx", - .channels_min = HDA_STEREO, - .channels_max = HDA_STEREO, - .rates = SNDRV_PCM_RATE_48000, - .formats = SNDRV_PCM_FMTBIT_S16_LE, + .stream_name = "Analog CPU Capture", + .channels_min = HDA_MONO, + .channels_max = HDA_MAX, + .rates = SNDRV_PCM_RATE_8000_192000, + .formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S24_LE | + SNDRV_PCM_FMTBIT_S32_LE, + }, +}, +{ + .name = "Alt Analog CPU DAI", + .ops = &skl_link_dai_ops, + .playback = { + .stream_name = "Alt Analog CPU Playback", + .channels_min = HDA_MONO, + .channels_max = HDA_MAX, + .rates = SNDRV_PCM_RATE_8000_192000, + .formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S24_LE | + SNDRV_PCM_FMTBIT_S32_LE, + }, + .capture = { + .stream_name = "Alt Analog CPU Capture", + .channels_min = HDA_MONO, + .channels_max = HDA_MAX, + .rates = SNDRV_PCM_RATE_8000_192000, + .formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S24_LE | + SNDRV_PCM_FMTBIT_S32_LE, + }, +}, +{ + .name = "Digital CPU DAI", + .ops = &skl_link_dai_ops, + .playback = { + .stream_name = "Digital CPU Playback", + .channels_min = HDA_MONO, + .channels_max = HDA_MAX, + .rates = SNDRV_PCM_RATE_8000_192000, + .formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S24_LE | + SNDRV_PCM_FMTBIT_S32_LE, + }, + .capture = { + .stream_name = "Digital CPU Capture", + .channels_min = HDA_MONO, + .channels_max = HDA_MAX, + .rates = SNDRV_PCM_RATE_8000_192000, + .formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S24_LE | + SNDRV_PCM_FMTBIT_S32_LE, }, }, }; From 00deadb5d86a3c1e691aaa073a8852a198595099 Mon Sep 17 00:00:00 2001 From: Rakesh Ughreja Date: Wed, 22 Aug 2018 15:25:02 -0500 Subject: [PATCH 027/299] ASoC: Intel: Skylake: use hda_bus instead of hdac_bus Use hda_bus instead of hdac_bus in the SKL ASoC platform driver to enable reuse of legacy HDA codec drivers. Signed-off-by: Rakesh Ughreja Signed-off-by: Pierre-Louis Bossart Signed-off-by: Mark Brown --- sound/soc/intel/skylake/skl.c | 11 +++++++++-- sound/soc/intel/skylake/skl.h | 10 +++++++--- 2 files changed, 16 insertions(+), 5 deletions(-) diff --git a/sound/soc/intel/skylake/skl.c b/sound/soc/intel/skylake/skl.c index 3b836125d1de..5f281d443a53 100644 --- a/sound/soc/intel/skylake/skl.c +++ b/sound/soc/intel/skylake/skl.c @@ -33,6 +33,7 @@ #include #include #include +#include #include "skl.h" #include "skl-sst-dsp.h" #include "skl-sst-ipc.h" @@ -673,7 +674,7 @@ static int probe_codec(struct hdac_bus *bus, int addr) mutex_unlock(&bus->cmd_mutex); if (res == -1) return -EIO; - dev_dbg(bus->dev, "codec #%d probed OK\n", addr); + dev_dbg(bus->dev, "codec #%d probed OK: %x\n", addr, res); hdev = devm_kzalloc(&skl->pci->dev, sizeof(*hdev), GFP_KERNEL); if (!hdev) @@ -816,7 +817,7 @@ static int skl_create(struct pci_dev *pci, { struct skl *skl; struct hdac_bus *bus; - + struct hda_bus *hbus; int err; *rskl = NULL; @@ -831,6 +832,7 @@ static int skl_create(struct pci_dev *pci, return -ENOMEM; } + hbus = skl_to_hbus(skl); bus = skl_to_bus(skl); snd_hdac_ext_bus_init(bus, &pci->dev, &bus_core_ops, io_ops, NULL); bus->use_posbuf = 1; @@ -838,6 +840,11 @@ static int skl_create(struct pci_dev *pci, INIT_WORK(&skl->probe_work, skl_probe_work); bus->bdl_pos_adj = 0; + mutex_init(&hbus->prepare_mutex); + hbus->pci = pci; + hbus->mixer_assigned = -1; + hbus->modelname = "sklbus"; + *rskl = skl; return 0; diff --git a/sound/soc/intel/skylake/skl.h b/sound/soc/intel/skylake/skl.h index 4105a9371b64..8d48cd7c56c8 100644 --- a/sound/soc/intel/skylake/skl.h +++ b/sound/soc/intel/skylake/skl.h @@ -23,6 +23,7 @@ #include #include +#include #include #include "skl-nhlt.h" #include "skl-ssp-clk.h" @@ -71,7 +72,7 @@ struct skl_fw_config { }; struct skl { - struct hdac_bus hbus; + struct hda_bus hbus; struct pci_dev *pci; unsigned int init_done:1; /* delayed init status */ @@ -105,8 +106,11 @@ struct skl { struct snd_soc_acpi_mach *mach; }; -#define skl_to_bus(s) (&(s)->hbus) -#define bus_to_skl(bus) container_of(bus, struct skl, hbus) +#define skl_to_bus(s) (&(s)->hbus.core) +#define bus_to_skl(bus) container_of(bus, struct skl, hbus.core) + +#define skl_to_hbus(s) (&(s)->hbus) +#define hbus_to_skl(hbus) container_of((hbus), struct skl, (hbus)) /* to pass dai dma data */ struct skl_dma_params { From 6bae5ea9498926440ffc883f3dbceb0adc65e492 Mon Sep 17 00:00:00 2001 From: Rakesh Ughreja Date: Wed, 22 Aug 2018 15:25:03 -0500 Subject: [PATCH 028/299] ASoC: hdac_hda: add asoc extension for legacy HDA codec drivers This patch adds a kernel module which is used by the legacy HDA codec drivers as library. This implements hdac_ext_bus_ops to enable the reuse of legacy HDA codec drivers with ASoC platform drivers. Signed-off-by: Rakesh Ughreja Signed-off-by: Pierre-Louis Bossart Signed-off-by: Mark Brown --- sound/pci/hda/hda_bind.c | 12 + sound/soc/codecs/Kconfig | 5 + sound/soc/codecs/Makefile | 2 + sound/soc/codecs/hdac_hda.c | 484 +++++++++++++++++++ sound/soc/codecs/hdac_hda.h | 24 + sound/soc/intel/boards/Kconfig | 1 + sound/soc/intel/boards/skl_hda_dsp_common.c | 24 + sound/soc/intel/boards/skl_hda_dsp_common.h | 2 +- sound/soc/intel/boards/skl_hda_dsp_generic.c | 38 ++ sound/soc/intel/skylake/skl.c | 47 +- 10 files changed, 634 insertions(+), 5 deletions(-) create mode 100644 sound/soc/codecs/hdac_hda.c create mode 100644 sound/soc/codecs/hdac_hda.h diff --git a/sound/pci/hda/hda_bind.c b/sound/pci/hda/hda_bind.c index 2222b47d4ec4..9174f1b3a987 100644 --- a/sound/pci/hda/hda_bind.c +++ b/sound/pci/hda/hda_bind.c @@ -81,6 +81,12 @@ static int hda_codec_driver_probe(struct device *dev) hda_codec_patch_t patch; int err; + if (codec->bus->core.ext_ops) { + if (WARN_ON(!codec->bus->core.ext_ops->hdev_attach)) + return -EINVAL; + return codec->bus->core.ext_ops->hdev_attach(&codec->core); + } + if (WARN_ON(!codec->preset)) return -EINVAL; @@ -134,6 +140,12 @@ static int hda_codec_driver_remove(struct device *dev) { struct hda_codec *codec = dev_to_hda_codec(dev); + if (codec->bus->core.ext_ops) { + if (WARN_ON(!codec->bus->core.ext_ops->hdev_detach)) + return -EINVAL; + return codec->bus->core.ext_ops->hdev_detach(&codec->core); + } + if (codec->patch_ops.free) codec->patch_ops.free(codec); snd_hda_codec_cleanup_for_unbind(codec); diff --git a/sound/soc/codecs/Kconfig b/sound/soc/codecs/Kconfig index efb095dbcd71..bf0b949eb7e8 100644 --- a/sound/soc/codecs/Kconfig +++ b/sound/soc/codecs/Kconfig @@ -82,6 +82,7 @@ config SND_SOC_ALL_CODECS select SND_SOC_ES7241 select SND_SOC_GTM601 select SND_SOC_HDAC_HDMI + select SND_SOC_HDAC_HDA select SND_SOC_ICS43432 select SND_SOC_INNO_RK3036 select SND_SOC_ISABELLE if I2C @@ -615,6 +616,10 @@ config SND_SOC_HDAC_HDMI select SND_PCM_ELD select HDMI +config SND_SOC_HDAC_HDA + tristate + select SND_HDA + config SND_SOC_ICS43432 tristate diff --git a/sound/soc/codecs/Makefile b/sound/soc/codecs/Makefile index 7ae7c85e8219..3046b33ca9d3 100644 --- a/sound/soc/codecs/Makefile +++ b/sound/soc/codecs/Makefile @@ -78,6 +78,7 @@ snd-soc-es8328-i2c-objs := es8328-i2c.o snd-soc-es8328-spi-objs := es8328-spi.o snd-soc-gtm601-objs := gtm601.o snd-soc-hdac-hdmi-objs := hdac_hdmi.o +snd-soc-hdac-hda-objs := hdac_hda.o snd-soc-ics43432-objs := ics43432.o snd-soc-inno-rk3036-objs := inno_rk3036.o snd-soc-isabelle-objs := isabelle.o @@ -338,6 +339,7 @@ obj-$(CONFIG_SND_SOC_ES8328_I2C)+= snd-soc-es8328-i2c.o obj-$(CONFIG_SND_SOC_ES8328_SPI)+= snd-soc-es8328-spi.o obj-$(CONFIG_SND_SOC_GTM601) += snd-soc-gtm601.o obj-$(CONFIG_SND_SOC_HDAC_HDMI) += snd-soc-hdac-hdmi.o +obj-$(CONFIG_SND_SOC_HDAC_HDA) += snd-soc-hdac-hda.o obj-$(CONFIG_SND_SOC_ICS43432) += snd-soc-ics43432.o obj-$(CONFIG_SND_SOC_INNO_RK3036) += snd-soc-inno-rk3036.o obj-$(CONFIG_SND_SOC_ISABELLE) += snd-soc-isabelle.o diff --git a/sound/soc/codecs/hdac_hda.c b/sound/soc/codecs/hdac_hda.c new file mode 100644 index 000000000000..8c25a1332fa7 --- /dev/null +++ b/sound/soc/codecs/hdac_hda.c @@ -0,0 +1,484 @@ +// SPDX-License-Identifier: GPL-2.0 +// Copyright(c) 2015-18 Intel Corporation. + +/* + * hdac_hda.c - ASoC extensions to reuse the legacy HDA codec drivers + * with ASoC platform drivers. These APIs are called by the legacy HDA + * codec drivers using hdac_ext_bus_ops ops. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "hdac_hda.h" + +#define HDAC_ANALOG_DAI_ID 0 +#define HDAC_DIGITAL_DAI_ID 1 +#define HDAC_ALT_ANALOG_DAI_ID 2 + +#define STUB_FORMATS (SNDRV_PCM_FMTBIT_S8 | \ + SNDRV_PCM_FMTBIT_U8 | \ + SNDRV_PCM_FMTBIT_S16_LE | \ + SNDRV_PCM_FMTBIT_U16_LE | \ + SNDRV_PCM_FMTBIT_S24_LE | \ + SNDRV_PCM_FMTBIT_U24_LE | \ + SNDRV_PCM_FMTBIT_S32_LE | \ + SNDRV_PCM_FMTBIT_U32_LE | \ + SNDRV_PCM_FMTBIT_IEC958_SUBFRAME_LE) + +static int hdac_hda_dai_open(struct snd_pcm_substream *substream, + struct snd_soc_dai *dai); +static void hdac_hda_dai_close(struct snd_pcm_substream *substream, + struct snd_soc_dai *dai); +static int hdac_hda_dai_prepare(struct snd_pcm_substream *substream, + struct snd_soc_dai *dai); +static int hdac_hda_dai_hw_free(struct snd_pcm_substream *substream, + struct snd_soc_dai *dai); +static int hdac_hda_dai_set_tdm_slot(struct snd_soc_dai *dai, + unsigned int tx_mask, unsigned int rx_mask, + int slots, int slot_width); +static struct hda_pcm *snd_soc_find_pcm_from_dai(struct hdac_hda_priv *hda_pvt, + struct snd_soc_dai *dai); + +static struct snd_soc_dai_ops hdac_hda_dai_ops = { + .startup = hdac_hda_dai_open, + .shutdown = hdac_hda_dai_close, + .prepare = hdac_hda_dai_prepare, + .hw_free = hdac_hda_dai_hw_free, + .set_tdm_slot = hdac_hda_dai_set_tdm_slot, +}; + +static struct snd_soc_dai_driver hdac_hda_dais[] = { +{ + .id = HDAC_ANALOG_DAI_ID, + .name = "Analog Codec DAI", + .ops = &hdac_hda_dai_ops, + .playback = { + .stream_name = "Analog Codec Playback", + .channels_min = 1, + .channels_max = 16, + .rates = SNDRV_PCM_RATE_8000_192000, + .formats = STUB_FORMATS, + .sig_bits = 24, + }, + .capture = { + .stream_name = "Analog Codec Capture", + .channels_min = 1, + .channels_max = 16, + .rates = SNDRV_PCM_RATE_8000_192000, + .formats = STUB_FORMATS, + .sig_bits = 24, + }, +}, +{ + .id = HDAC_DIGITAL_DAI_ID, + .name = "Digital Codec DAI", + .ops = &hdac_hda_dai_ops, + .playback = { + .stream_name = "Digital Codec Playback", + .channels_min = 1, + .channels_max = 16, + .rates = SNDRV_PCM_RATE_8000_192000, + .formats = STUB_FORMATS, + .sig_bits = 24, + }, + .capture = { + .stream_name = "Digital Codec Capture", + .channels_min = 1, + .channels_max = 16, + .rates = SNDRV_PCM_RATE_8000_192000, + .formats = STUB_FORMATS, + .sig_bits = 24, + }, +}, +{ + .id = HDAC_ALT_ANALOG_DAI_ID, + .name = "Alt Analog Codec DAI", + .ops = &hdac_hda_dai_ops, + .playback = { + .stream_name = "Alt Analog Codec Playback", + .channels_min = 1, + .channels_max = 16, + .rates = SNDRV_PCM_RATE_8000_192000, + .formats = STUB_FORMATS, + .sig_bits = 24, + }, + .capture = { + .stream_name = "Alt Analog Codec Capture", + .channels_min = 1, + .channels_max = 16, + .rates = SNDRV_PCM_RATE_8000_192000, + .formats = STUB_FORMATS, + .sig_bits = 24, + }, +} + +}; + +static int hdac_hda_dai_set_tdm_slot(struct snd_soc_dai *dai, + unsigned int tx_mask, unsigned int rx_mask, + int slots, int slot_width) +{ + struct snd_soc_component *component = dai->component; + struct hdac_hda_priv *hda_pvt; + struct hdac_hda_pcm *pcm; + + hda_pvt = snd_soc_component_get_drvdata(component); + pcm = &hda_pvt->pcm[dai->id]; + if (tx_mask) + pcm[dai->id].stream_tag[SNDRV_PCM_STREAM_PLAYBACK] = tx_mask; + else + pcm[dai->id].stream_tag[SNDRV_PCM_STREAM_CAPTURE] = rx_mask; + + return 0; +} + +static int hdac_hda_dai_hw_free(struct snd_pcm_substream *substream, + struct snd_soc_dai *dai) +{ + struct snd_soc_component *component = dai->component; + struct hdac_hda_priv *hda_pvt; + struct hda_pcm_stream *hda_stream; + struct hda_pcm *pcm; + + hda_pvt = snd_soc_component_get_drvdata(component); + pcm = snd_soc_find_pcm_from_dai(hda_pvt, dai); + if (!pcm) + return -EINVAL; + + hda_stream = &pcm->stream[substream->stream]; + snd_hda_codec_cleanup(&hda_pvt->codec, hda_stream, substream); + + return 0; +} + +static int hdac_hda_dai_prepare(struct snd_pcm_substream *substream, + struct snd_soc_dai *dai) +{ + struct snd_soc_component *component = dai->component; + struct hdac_hda_priv *hda_pvt; + struct snd_pcm_runtime *runtime = substream->runtime; + struct hdac_device *hdev; + struct hda_pcm_stream *hda_stream; + unsigned int format_val; + struct hda_pcm *pcm; + unsigned int stream; + int ret = 0; + + hda_pvt = snd_soc_component_get_drvdata(component); + hdev = &hda_pvt->codec.core; + pcm = snd_soc_find_pcm_from_dai(hda_pvt, dai); + if (!pcm) + return -EINVAL; + + hda_stream = &pcm->stream[substream->stream]; + + format_val = snd_hdac_calc_stream_format(runtime->rate, + runtime->channels, + runtime->format, + hda_stream->maxbps, + 0); + if (!format_val) { + dev_err(&hdev->dev, + "invalid format_val, rate=%d, ch=%d, format=%d\n", + runtime->rate, runtime->channels, runtime->format); + return -EINVAL; + } + + stream = hda_pvt->pcm[dai->id].stream_tag[substream->stream]; + + ret = snd_hda_codec_prepare(&hda_pvt->codec, hda_stream, + stream, format_val, substream); + if (ret < 0) + dev_err(&hdev->dev, "codec prepare failed %d\n", ret); + + return ret; +} + +static int hdac_hda_dai_open(struct snd_pcm_substream *substream, + struct snd_soc_dai *dai) +{ + struct snd_soc_component *component = dai->component; + struct hdac_hda_priv *hda_pvt; + struct hda_pcm_stream *hda_stream; + struct hda_pcm *pcm; + int ret; + + hda_pvt = snd_soc_component_get_drvdata(component); + pcm = snd_soc_find_pcm_from_dai(hda_pvt, dai); + if (!pcm) + return -EINVAL; + + snd_hda_codec_pcm_get(pcm); + + hda_stream = &pcm->stream[substream->stream]; + + ret = hda_stream->ops.open(hda_stream, &hda_pvt->codec, substream); + if (ret < 0) + snd_hda_codec_pcm_put(pcm); + + return ret; +} + +static void hdac_hda_dai_close(struct snd_pcm_substream *substream, + struct snd_soc_dai *dai) +{ + struct snd_soc_component *component = dai->component; + struct hdac_hda_priv *hda_pvt; + struct hda_pcm_stream *hda_stream; + struct hda_pcm *pcm; + + hda_pvt = snd_soc_component_get_drvdata(component); + pcm = snd_soc_find_pcm_from_dai(hda_pvt, dai); + if (!pcm) + return; + + hda_stream = &pcm->stream[substream->stream]; + + hda_stream->ops.close(hda_stream, &hda_pvt->codec, substream); + + snd_hda_codec_pcm_put(pcm); +} + +static struct hda_pcm *snd_soc_find_pcm_from_dai(struct hdac_hda_priv *hda_pvt, + struct snd_soc_dai *dai) +{ + struct hda_codec *hcodec = &hda_pvt->codec; + struct hda_pcm *cpcm; + const char *pcm_name; + + switch (dai->id) { + case HDAC_ANALOG_DAI_ID: + pcm_name = "Analog"; + break; + case HDAC_DIGITAL_DAI_ID: + pcm_name = "Digital"; + break; + case HDAC_ALT_ANALOG_DAI_ID: + pcm_name = "Alt Analog"; + break; + default: + dev_err(&hcodec->core.dev, "invalid dai id %d\n", dai->id); + return NULL; + } + + list_for_each_entry(cpcm, &hcodec->pcm_list_head, list) { + if (strpbrk(cpcm->name, pcm_name)) + return cpcm; + } + + dev_err(&hcodec->core.dev, "didn't find PCM for DAI %s\n", dai->name); + return NULL; +} + +static int hdac_hda_codec_probe(struct snd_soc_component *component) +{ + struct hdac_hda_priv *hda_pvt = + snd_soc_component_get_drvdata(component); + struct snd_soc_dapm_context *dapm = + snd_soc_component_get_dapm(component); + struct hdac_device *hdev = &hda_pvt->codec.core; + struct hda_codec *hcodec = &hda_pvt->codec; + struct hdac_ext_link *hlink; + hda_codec_patch_t patch; + int ret; + + hlink = snd_hdac_ext_bus_get_link(hdev->bus, dev_name(&hdev->dev)); + if (!hlink) { + dev_err(&hdev->dev, "hdac link not found\n"); + return -EIO; + } + + snd_hdac_ext_bus_link_get(hdev->bus, hlink); + + ret = snd_hda_codec_device_new(hcodec->bus, component->card->snd_card, + hdev->addr, hcodec); + if (ret < 0) { + dev_err(&hdev->dev, "failed to create hda codec %d\n", ret); + goto error_no_pm; + } + + /* + * snd_hda_codec_device_new decrements the usage count so call get pm + * else the device will be powered off + */ + pm_runtime_get_noresume(&hdev->dev); + + hcodec->bus->card = dapm->card->snd_card; + + ret = snd_hda_codec_set_name(hcodec, hcodec->preset->name); + if (ret < 0) { + dev_err(&hdev->dev, "name failed %s\n", hcodec->preset->name); + goto error; + } + + ret = snd_hdac_regmap_init(&hcodec->core); + if (ret < 0) { + dev_err(&hdev->dev, "regmap init failed\n"); + goto error; + } + + patch = (hda_codec_patch_t)hcodec->preset->driver_data; + if (patch) { + ret = patch(hcodec); + if (ret < 0) { + dev_err(&hdev->dev, "patch failed %d\n", ret); + goto error; + } + } else { + dev_dbg(&hdev->dev, "no patch file found\n"); + } + + ret = snd_hda_codec_parse_pcms(hcodec); + if (ret < 0) { + dev_err(&hdev->dev, "unable to map pcms to dai %d\n", ret); + goto error; + } + + ret = snd_hda_codec_build_controls(hcodec); + if (ret < 0) { + dev_err(&hdev->dev, "unable to create controls %d\n", ret); + goto error; + } + + hcodec->core.lazy_cache = true; + + /* + * hdac_device core already sets the state to active and calls + * get_noresume. So enable runtime and set the device to suspend. + * pm_runtime_enable is also called during codec registeration + */ + pm_runtime_put(&hdev->dev); + pm_runtime_suspend(&hdev->dev); + + return 0; + +error: + pm_runtime_put(&hdev->dev); +error_no_pm: + snd_hdac_ext_bus_link_put(hdev->bus, hlink); + return ret; +} + +static void hdac_hda_codec_remove(struct snd_soc_component *component) +{ + struct hdac_hda_priv *hda_pvt = + snd_soc_component_get_drvdata(component); + struct hdac_device *hdev = &hda_pvt->codec.core; + struct hdac_ext_link *hlink = NULL; + + hlink = snd_hdac_ext_bus_get_link(hdev->bus, dev_name(&hdev->dev)); + if (!hlink) { + dev_err(&hdev->dev, "hdac link not found\n"); + return; + } + + snd_hdac_ext_bus_link_put(hdev->bus, hlink); + pm_runtime_disable(&hdev->dev); +} + +static const struct snd_soc_dapm_route hdac_hda_dapm_routes[] = { + {"AIF1TX", NULL, "Codec Input Pin1"}, + {"AIF2TX", NULL, "Codec Input Pin2"}, + {"AIF3TX", NULL, "Codec Input Pin3"}, + + {"Codec Output Pin1", NULL, "AIF1RX"}, + {"Codec Output Pin2", NULL, "AIF2RX"}, + {"Codec Output Pin3", NULL, "AIF3RX"}, +}; + +static const struct snd_soc_dapm_widget hdac_hda_dapm_widgets[] = { + /* Audio Interface */ + SND_SOC_DAPM_AIF_IN("AIF1RX", "Analog Codec Playback", 0, + SND_SOC_NOPM, 0, 0), + SND_SOC_DAPM_AIF_IN("AIF2RX", "Digital Codec Playback", 0, + SND_SOC_NOPM, 0, 0), + SND_SOC_DAPM_AIF_IN("AIF3RX", "Alt Analog Codec Playback", 0, + SND_SOC_NOPM, 0, 0), + SND_SOC_DAPM_AIF_OUT("AIF1TX", "Analog Codec Capture", 0, + SND_SOC_NOPM, 0, 0), + SND_SOC_DAPM_AIF_OUT("AIF2TX", "Digital Codec Capture", 0, + SND_SOC_NOPM, 0, 0), + SND_SOC_DAPM_AIF_OUT("AIF3TX", "Alt Analog Codec Capture", 0, + SND_SOC_NOPM, 0, 0), + + /* Input Pins */ + SND_SOC_DAPM_INPUT("Codec Input Pin1"), + SND_SOC_DAPM_INPUT("Codec Input Pin2"), + SND_SOC_DAPM_INPUT("Codec Input Pin3"), + + /* Output Pins */ + SND_SOC_DAPM_OUTPUT("Codec Output Pin1"), + SND_SOC_DAPM_OUTPUT("Codec Output Pin2"), + SND_SOC_DAPM_OUTPUT("Codec Output Pin3"), +}; + +static const struct snd_soc_component_driver hdac_hda_codec = { + .probe = hdac_hda_codec_probe, + .remove = hdac_hda_codec_remove, + .idle_bias_on = false, + .dapm_widgets = hdac_hda_dapm_widgets, + .num_dapm_widgets = ARRAY_SIZE(hdac_hda_dapm_widgets), + .dapm_routes = hdac_hda_dapm_routes, + .num_dapm_routes = ARRAY_SIZE(hdac_hda_dapm_routes), +}; + +static int hdac_hda_dev_probe(struct hdac_device *hdev) +{ + struct hdac_ext_link *hlink; + struct hdac_hda_priv *hda_pvt; + int ret; + + /* hold the ref while we probe */ + hlink = snd_hdac_ext_bus_get_link(hdev->bus, dev_name(&hdev->dev)); + if (!hlink) { + dev_err(&hdev->dev, "hdac link not found\n"); + return -EIO; + } + snd_hdac_ext_bus_link_get(hdev->bus, hlink); + + hda_pvt = hdac_to_hda_priv(hdev); + if (!hda_pvt) + return -ENOMEM; + + /* ASoC specific initialization */ + ret = snd_soc_register_component(&hdev->dev, + &hdac_hda_codec, hdac_hda_dais, + ARRAY_SIZE(hdac_hda_dais)); + if (ret < 0) { + dev_err(&hdev->dev, "failed to register HDA codec %d\n", ret); + return ret; + } + + dev_set_drvdata(&hdev->dev, hda_pvt); + snd_hdac_ext_bus_link_put(hdev->bus, hlink); + + return ret; +} + +static int hdac_hda_dev_remove(struct hdac_device *hdev) +{ + snd_soc_unregister_component(&hdev->dev); + return 0; +} + +static struct hdac_ext_bus_ops hdac_ops = { + .hdev_attach = hdac_hda_dev_probe, + .hdev_detach = hdac_hda_dev_remove, +}; + +struct hdac_ext_bus_ops *snd_soc_hdac_hda_get_ops(void) +{ + return &hdac_ops; +} +EXPORT_SYMBOL_GPL(snd_soc_hdac_hda_get_ops); + +MODULE_LICENSE("GPL v2"); +MODULE_DESCRIPTION("ASoC Extensions for legacy HDA Drivers"); +MODULE_AUTHOR("Rakesh Ughreja"); diff --git a/sound/soc/codecs/hdac_hda.h b/sound/soc/codecs/hdac_hda.h new file mode 100644 index 000000000000..e444ef593360 --- /dev/null +++ b/sound/soc/codecs/hdac_hda.h @@ -0,0 +1,24 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright(c) 2015-18 Intel Corporation. + */ + +#ifndef __HDAC_HDA_H__ +#define __HDAC_HDA_H__ + +struct hdac_hda_pcm { + int stream_tag[2]; +}; + +struct hdac_hda_priv { + struct hda_codec codec; + struct hdac_hda_pcm pcm[2]; +}; + +#define hdac_to_hda_priv(_hdac) \ + container_of(_hdac, struct hdac_hda_priv, codec.core) +#define hdac_to_hda_codec(_hdac) container_of(_hdac, struct hda_codec, core) + +struct hdac_ext_bus_ops *snd_soc_hdac_hda_get_ops(void); + +#endif /* __HDAC_HDA_H__ */ diff --git a/sound/soc/intel/boards/Kconfig b/sound/soc/intel/boards/Kconfig index 0f0d57859555..88e4b4284738 100644 --- a/sound/soc/intel/boards/Kconfig +++ b/sound/soc/intel/boards/Kconfig @@ -283,6 +283,7 @@ config SND_SOC_INTEL_KBL_DA7219_MAX98357A_MACH config SND_SOC_INTEL_SKL_HDA_DSP_GENERIC_MACH tristate "SKL/KBL/BXT/APL with HDA Codecs" select SND_SOC_HDAC_HDMI + select SND_SOC_HDAC_HDA help This adds support for ASoC machine driver for Intel platforms SKL/KBL/BXT/APL with iDisp, HDA audio codecs. diff --git a/sound/soc/intel/boards/skl_hda_dsp_common.c b/sound/soc/intel/boards/skl_hda_dsp_common.c index f9917e0f2ba8..3fdbf239da74 100644 --- a/sound/soc/intel/boards/skl_hda_dsp_common.c +++ b/sound/soc/intel/boards/skl_hda_dsp_common.c @@ -69,6 +69,30 @@ struct snd_soc_dai_link skl_hda_be_dai_links[HDA_DSP_MAX_BE_DAI_LINKS] = { .dpcm_playback = 1, .no_pcm = 1, }, + { + .name = "Analog Playback and Capture", + .id = 4, + .cpu_dai_name = "Analog CPU DAI", + .codec_name = "ehdaudio0D0", + .codec_dai_name = "Analog Codec DAI", + .platform_name = "0000:00:1f.3", + .dpcm_playback = 1, + .dpcm_capture = 1, + .init = NULL, + .no_pcm = 1, + }, + { + .name = "Digital Playback and Capture", + .id = 5, + .cpu_dai_name = "Digital CPU DAI", + .codec_name = "ehdaudio0D0", + .codec_dai_name = "Digital Codec DAI", + .platform_name = "0000:00:1f.3", + .dpcm_playback = 1, + .dpcm_capture = 1, + .init = NULL, + .no_pcm = 1, + }, }; int skl_hda_hdmi_jack_init(struct snd_soc_card *card) diff --git a/sound/soc/intel/boards/skl_hda_dsp_common.h b/sound/soc/intel/boards/skl_hda_dsp_common.h index b6c79696bfba..87c50aff56cd 100644 --- a/sound/soc/intel/boards/skl_hda_dsp_common.h +++ b/sound/soc/intel/boards/skl_hda_dsp_common.h @@ -15,7 +15,7 @@ #include #include -#define HDA_DSP_MAX_BE_DAI_LINKS 3 +#define HDA_DSP_MAX_BE_DAI_LINKS 5 struct skl_hda_hdmi_pcm { struct list_head head; diff --git a/sound/soc/intel/boards/skl_hda_dsp_generic.c b/sound/soc/intel/boards/skl_hda_dsp_generic.c index 920bc2ce22aa..b213e9b47505 100644 --- a/sound/soc/intel/boards/skl_hda_dsp_generic.c +++ b/sound/soc/intel/boards/skl_hda_dsp_generic.c @@ -16,6 +16,15 @@ #include "../skylake/skl.h" #include "skl_hda_dsp_common.h" +static const struct snd_soc_dapm_widget skl_hda_widgets[] = { + SND_SOC_DAPM_HP("Analog Out", NULL), + SND_SOC_DAPM_MIC("Analog In", NULL), + SND_SOC_DAPM_HP("Alt Analog Out", NULL), + SND_SOC_DAPM_MIC("Alt Analog In", NULL), + SND_SOC_DAPM_SPK("Digital Out", NULL), + SND_SOC_DAPM_MIC("Digital In", NULL), +}; + static const struct snd_soc_dapm_route skl_hda_map[] = { { "hifi3", NULL, "iDisp3 Tx"}, { "iDisp3 Tx", NULL, "iDisp3_out"}, @@ -23,6 +32,29 @@ static const struct snd_soc_dapm_route skl_hda_map[] = { { "iDisp2 Tx", NULL, "iDisp2_out"}, { "hifi1", NULL, "iDisp1 Tx"}, { "iDisp1 Tx", NULL, "iDisp1_out"}, + + { "Analog Out", NULL, "Codec Output Pin1" }, + { "Digital Out", NULL, "Codec Output Pin2" }, + { "Alt Analog Out", NULL, "Codec Output Pin3" }, + + { "Codec Input Pin1", NULL, "Analog In" }, + { "Codec Input Pin2", NULL, "Digital In" }, + { "Codec Input Pin3", NULL, "Alt Analog In" }, + + /* CODEC BE connections */ + { "Analog Codec Playback", NULL, "Analog CPU Playback" }, + { "Analog CPU Playback", NULL, "codec0_out" }, + { "Digital Codec Playback", NULL, "Digital CPU Playback" }, + { "Digital CPU Playback", NULL, "codec1_out" }, + { "Alt Analog Codec Playback", NULL, "Alt Analog CPU Playback" }, + { "Alt Analog CPU Playback", NULL, "codec2_out" }, + + { "codec0_in", NULL, "Analog CPU Capture" }, + { "Analog CPU Capture", NULL, "Analog Codec Capture" }, + { "codec1_in", NULL, "Digital CPU Capture" }, + { "Digital CPU Capture", NULL, "Digital Codec Capture" }, + { "codec2_in", NULL, "Alt Analog CPU Capture" }, + { "Alt Analog CPU Capture", NULL, "Alt Analog Codec Capture" }, }; static int skl_hda_card_late_probe(struct snd_soc_card *card) @@ -57,6 +89,7 @@ static struct snd_soc_card hda_soc_card = { .name = "skl_hda_card", .owner = THIS_MODULE, .dai_link = skl_hda_be_dai_links, + .dapm_widgets = skl_hda_widgets, .dapm_routes = skl_hda_map, .add_dai_link = skl_hda_add_dai_link, .fully_routed = true, @@ -80,6 +113,11 @@ static int skl_hda_fill_card_info(struct skl_machine_pdata *pdata) if (codec_count == 1 && pdata->codec_mask & IDISP_CODEC_MASK) { num_links = IDISP_DAI_COUNT; num_route = IDISP_ROUTE_COUNT; + } else if (codec_count == 2 && codec_mask & IDISP_CODEC_MASK) { + num_links = ARRAY_SIZE(skl_hda_be_dai_links); + num_route = ARRAY_SIZE(skl_hda_map), + card->dapm_widgets = skl_hda_widgets; + card->num_dapm_widgets = ARRAY_SIZE(skl_hda_widgets); } else { return -EINVAL; } diff --git a/sound/soc/intel/skylake/skl.c b/sound/soc/intel/skylake/skl.c index 5f281d443a53..e7fd14daeb4f 100644 --- a/sound/soc/intel/skylake/skl.c +++ b/sound/soc/intel/skylake/skl.c @@ -37,6 +37,7 @@ #include "skl.h" #include "skl-sst-dsp.h" #include "skl-sst-ipc.h" +#include "../../../soc/codecs/hdac_hda.h" /* * initialize the PCI registers @@ -657,6 +658,24 @@ static void skl_clock_device_unregister(struct skl *skl) platform_device_unregister(skl->clk_dev); } +#define IDISP_INTEL_VENDOR_ID 0x80860000 + +/* + * load the legacy codec driver + */ +static void load_codec_module(struct hda_codec *codec) +{ +#ifdef MODULE + char modalias[MODULE_NAME_LEN]; + const char *mod = NULL; + + snd_hdac_codec_modalias(&codec->core, modalias, sizeof(modalias)); + mod = modalias; + dev_dbg(&codec->core.dev, "loading %s codec module\n", mod); + request_module(mod); +#endif +} + /* * Probe the given codec address */ @@ -666,7 +685,9 @@ static int probe_codec(struct hdac_bus *bus, int addr) (AC_VERB_PARAMETERS << 8) | AC_PAR_VENDOR_ID; unsigned int res = -1; struct skl *skl = bus_to_skl(bus); + struct hdac_hda_priv *hda_codec; struct hdac_device *hdev; + int err; mutex_lock(&bus->cmd_mutex); snd_hdac_bus_send_cmd(bus, cmd); @@ -676,11 +697,24 @@ static int probe_codec(struct hdac_bus *bus, int addr) return -EIO; dev_dbg(bus->dev, "codec #%d probed OK: %x\n", addr, res); - hdev = devm_kzalloc(&skl->pci->dev, sizeof(*hdev), GFP_KERNEL); - if (!hdev) + hda_codec = devm_kzalloc(&skl->pci->dev, sizeof(*hda_codec), + GFP_KERNEL); + if (!hda_codec) return -ENOMEM; - return snd_hdac_ext_bus_device_init(bus, addr, hdev); + hda_codec->codec.bus = skl_to_hbus(skl); + hdev = &hda_codec->codec.core; + + err = snd_hdac_ext_bus_device_init(bus, addr, hdev); + if (err < 0) + return err; + + /* use legacy bus only for HDA codecs, idisp uses ext bus */ + if ((res & 0xFFFF0000) != IDISP_INTEL_VENDOR_ID) { + hdev->type = HDA_DEV_LEGACY; + load_codec_module(&hda_codec->codec); + } + return 0; } /* Codec initialization */ @@ -815,6 +849,7 @@ static int skl_create(struct pci_dev *pci, const struct hdac_io_ops *io_ops, struct skl **rskl) { + struct hdac_ext_bus_ops *ext_ops = NULL; struct skl *skl; struct hdac_bus *bus; struct hda_bus *hbus; @@ -834,7 +869,11 @@ static int skl_create(struct pci_dev *pci, hbus = skl_to_hbus(skl); bus = skl_to_bus(skl); - snd_hdac_ext_bus_init(bus, &pci->dev, &bus_core_ops, io_ops, NULL); + +#if IS_ENABLED(CONFIG_SND_SOC_HDAC_HDA) + ext_ops = snd_soc_hdac_hda_get_ops(); +#endif + snd_hdac_ext_bus_init(bus, &pci->dev, &bus_core_ops, io_ops, ext_ops); bus->use_posbuf = 1; skl->pci = pci; INIT_WORK(&skl->probe_work, skl_probe_work); From b0f2d651299f0743818bdadcbe6a67d7869e0da1 Mon Sep 17 00:00:00 2001 From: Danny Smith Date: Tue, 21 Aug 2018 13:07:49 +0200 Subject: [PATCH 029/299] ASoC: adau17x1: Implemented safeload support Safeload support has been implemented which is used when updating for instance filter parameters using alsa controls. Without safeload support audio can become distorted during update. Signed-off-by: Danny Smith Signed-off-by: Robert Rosengren Acked-by: Lars-Peter Clausen Signed-off-by: Mark Brown --- sound/soc/codecs/adau17x1.c | 77 ++++++++++++++++++++++++++++++++++++- 1 file changed, 75 insertions(+), 2 deletions(-) diff --git a/sound/soc/codecs/adau17x1.c b/sound/soc/codecs/adau17x1.c index 57169b8ff14e..c0bc429249fa 100644 --- a/sound/soc/codecs/adau17x1.c +++ b/sound/soc/codecs/adau17x1.c @@ -21,11 +21,18 @@ #include #include #include +#include #include "sigmadsp.h" #include "adau17x1.h" #include "adau-utils.h" +#define ADAU17X1_SAFELOAD_TARGET_ADDRESS 0x0006 +#define ADAU17X1_SAFELOAD_TRIGGER 0x0007 +#define ADAU17X1_SAFELOAD_DATA 0x0001 +#define ADAU17X1_SAFELOAD_DATA_SIZE 20 +#define ADAU17X1_WORD_SIZE 4 + static const char * const adau17x1_capture_mixer_boost_text[] = { "Normal operation", "Boost Level 1", "Boost Level 2", "Boost Level 3", }; @@ -326,6 +333,17 @@ bool adau17x1_has_dsp(struct adau *adau) } EXPORT_SYMBOL_GPL(adau17x1_has_dsp); +static bool adau17x1_has_safeload(struct adau *adau) +{ + switch (adau->type) { + case ADAU1761: + case ADAU1781: + return true; + default: + return false; + } +} + static int adau17x1_set_dai_pll(struct snd_soc_dai *dai, int pll_id, int source, unsigned int freq_in, unsigned int freq_out) { @@ -957,6 +975,56 @@ int adau17x1_resume(struct snd_soc_component *component) } EXPORT_SYMBOL_GPL(adau17x1_resume); +static int adau17x1_safeload(struct sigmadsp *sigmadsp, unsigned int addr, + const uint8_t bytes[], size_t len) +{ + uint8_t buf[ADAU17X1_WORD_SIZE]; + uint8_t data[ADAU17X1_SAFELOAD_DATA_SIZE]; + unsigned int addr_offset; + unsigned int nbr_words; + int ret; + + /* write data to safeload addresses. Check if len is not a multiple of + * 4 bytes, if so we need to zero pad. + */ + nbr_words = len / ADAU17X1_WORD_SIZE; + if ((len - nbr_words * ADAU17X1_WORD_SIZE) == 0) { + ret = regmap_raw_write(sigmadsp->control_data, + ADAU17X1_SAFELOAD_DATA, bytes, len); + } else { + nbr_words++; + memset(data, 0, ADAU17X1_SAFELOAD_DATA_SIZE); + memcpy(data, bytes, len); + ret = regmap_raw_write(sigmadsp->control_data, + ADAU17X1_SAFELOAD_DATA, data, + nbr_words * ADAU17X1_WORD_SIZE); + } + + if (ret < 0) + return ret; + + /* Write target address, target address is offset by 1 */ + addr_offset = addr - 1; + put_unaligned_be32(addr_offset, buf); + ret = regmap_raw_write(sigmadsp->control_data, + ADAU17X1_SAFELOAD_TARGET_ADDRESS, buf, ADAU17X1_WORD_SIZE); + if (ret < 0) + return ret; + + /* write nbr of words to trigger address */ + put_unaligned_be32(nbr_words, buf); + ret = regmap_raw_write(sigmadsp->control_data, + ADAU17X1_SAFELOAD_TRIGGER, buf, ADAU17X1_WORD_SIZE); + if (ret < 0) + return ret; + + return 0; +} + +static const struct sigmadsp_ops adau17x1_sigmadsp_ops = { + .safeload = adau17x1_safeload, +}; + int adau17x1_probe(struct device *dev, struct regmap *regmap, enum adau17x1_type type, void (*switch_mode)(struct device *dev), const char *firmware_name) @@ -1002,8 +1070,13 @@ int adau17x1_probe(struct device *dev, struct regmap *regmap, dev_set_drvdata(dev, adau); if (firmware_name) { - adau->sigmadsp = devm_sigmadsp_init_regmap(dev, regmap, NULL, - firmware_name); + if (adau17x1_has_safeload(adau)) { + adau->sigmadsp = devm_sigmadsp_init_regmap(dev, regmap, + &adau17x1_sigmadsp_ops, firmware_name); + } else { + adau->sigmadsp = devm_sigmadsp_init_regmap(dev, regmap, + NULL, firmware_name); + } if (IS_ERR(adau->sigmadsp)) { dev_warn(dev, "Could not find firmware file: %ld\n", PTR_ERR(adau->sigmadsp)); From 818838e6bfa4ddc6c76703237028dcffb80d6496 Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Tue, 21 Aug 2018 13:43:35 +0200 Subject: [PATCH 030/299] ASoC: rt5670: Add quirk for Thinkpad 8 tablet The Thinkpad 8 needs a quirk for jack-detect and the internal mic to work correctly. Signed-off-by: Hans de Goede Signed-off-by: Mark Brown --- sound/soc/codecs/rt5670.c | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/sound/soc/codecs/rt5670.c b/sound/soc/codecs/rt5670.c index 732ef928b25d..455fe7cff700 100644 --- a/sound/soc/codecs/rt5670.c +++ b/sound/soc/codecs/rt5670.c @@ -2875,6 +2875,18 @@ static const struct dmi_system_id dmi_platform_intel_quirks[] = { RT5670_DEV_GPIO | RT5670_JD_MODE1), }, + { + .callback = rt5670_quirk_cb, + .ident = "Lenovo Thinkpad Tablet 8", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"), + DMI_MATCH(DMI_PRODUCT_VERSION, "ThinkPad 8"), + }, + .driver_data = (unsigned long *)(RT5670_DMIC_EN | + RT5670_DMIC2_INR | + RT5670_DEV_GPIO | + RT5670_JD_MODE1), + }, { .callback = rt5670_quirk_cb, .ident = "Lenovo Thinkpad Tablet 10", From 2ca426a24dd75e775ece1466ae45e019f0035b8d Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Tue, 21 Aug 2018 13:43:36 +0200 Subject: [PATCH 031/299] ASoC: Intel: common: Add quirk for Thinkpad 8 tablet The Thinkpad 8 tablet uses 10EC5640 as ACPI HID, but it has a rt5670 codec add a quirk for this. Signed-off-by: Hans de Goede Signed-off-by: Mark Brown --- sound/soc/intel/common/soc-acpi-intel-byt-match.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/sound/soc/intel/common/soc-acpi-intel-byt-match.c b/sound/soc/intel/common/soc-acpi-intel-byt-match.c index 4daa8a4f0c0c..097dc06377ba 100644 --- a/sound/soc/intel/common/soc-acpi-intel-byt-match.c +++ b/sound/soc/intel/common/soc-acpi-intel-byt-match.c @@ -30,6 +30,13 @@ static int byt_thinkpad10_quirk_cb(const struct dmi_system_id *id) static const struct dmi_system_id byt_table[] = { + { + .callback = byt_thinkpad10_quirk_cb, + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"), + DMI_MATCH(DMI_PRODUCT_VERSION, "ThinkPad 8"), + }, + }, { .callback = byt_thinkpad10_quirk_cb, .matches = { From f8fc397e13107f925186ee742e9e8dfbfe9a3d03 Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Tue, 21 Aug 2018 13:43:37 +0200 Subject: [PATCH 032/299] ASoC: Intel: cht-bsw-rt5672: Add key-mappings for the headset buttons Having the headset buttons send BTN_0, BTN_1 and BTN_2 events is not really useful. Add mappings to PLAYPAUSE VOLUME_UP and VOLUME_DOWN like we do in other Intel machine drivers. Signed-off-by: Hans de Goede Signed-off-by: Mark Brown --- sound/soc/intel/boards/cht_bsw_rt5672.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/sound/soc/intel/boards/cht_bsw_rt5672.c b/sound/soc/intel/boards/cht_bsw_rt5672.c index e5aa13058dd7..e054318185ea 100644 --- a/sound/soc/intel/boards/cht_bsw_rt5672.c +++ b/sound/soc/intel/boards/cht_bsw_rt5672.c @@ -16,6 +16,7 @@ * General Public License for more details. */ +#include #include #include #include @@ -212,6 +213,10 @@ static int cht_codec_init(struct snd_soc_pcm_runtime *runtime) if (ret) return ret; + snd_jack_set_key(ctx->headset.jack, SND_JACK_BTN_0, KEY_PLAYPAUSE); + snd_jack_set_key(ctx->headset.jack, SND_JACK_BTN_1, KEY_VOLUMEUP); + snd_jack_set_key(ctx->headset.jack, SND_JACK_BTN_2, KEY_VOLUMEDOWN); + rt5670_set_jack_detect(component, &ctx->headset); if (ctx->mclk) { /* From 6fbf9d8e2793b81dd5f8738999163582ce61dba7 Mon Sep 17 00:00:00 2001 From: Fabrizio Castro Date: Tue, 21 Aug 2018 17:42:28 +0100 Subject: [PATCH 033/299] ASoC: rsnd: Add r8a774a1 support Document RZ/G2M (R8A774A1) SoC bindings. Signed-off-by: Fabrizio Castro Reviewed-by: Biju Das Acked-by: Kuninori Morimoto Reviewed-by: Simon Horman Signed-off-by: Mark Brown --- Documentation/devicetree/bindings/sound/renesas,rsnd.txt | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/Documentation/devicetree/bindings/sound/renesas,rsnd.txt b/Documentation/devicetree/bindings/sound/renesas,rsnd.txt index 9e764270c36b..8083f0d8f263 100644 --- a/Documentation/devicetree/bindings/sound/renesas,rsnd.txt +++ b/Documentation/devicetree/bindings/sound/renesas,rsnd.txt @@ -340,10 +340,11 @@ Required properties: - compatible : "renesas,rcar_sound-", fallbacks "renesas,rcar_sound-gen1" if generation1, and "renesas,rcar_sound-gen2" if generation2 (or RZ/G1) - "renesas,rcar_sound-gen3" if generation3 + "renesas,rcar_sound-gen3" if generation3 (or RZ/G2) Examples with soctypes are: - "renesas,rcar_sound-r8a7743" (RZ/G1M) - "renesas,rcar_sound-r8a7745" (RZ/G1E) + - "renesas,rcar_sound-r8a774a1" (RZ/G2M) - "renesas,rcar_sound-r8a7778" (R-Car M1A) - "renesas,rcar_sound-r8a7779" (R-Car H1) - "renesas,rcar_sound-r8a7790" (R-Car H2) From 6ee47d4a8dacfa484d526c0475730568d979de24 Mon Sep 17 00:00:00 2001 From: Kirill Marinushkin Date: Tue, 21 Aug 2018 18:52:46 +0200 Subject: [PATCH 034/299] ASoC: pcm3060: Add codec driver This commit adds support for TI PCM3060 CODEC. The technical documentation is available at [1]. [1] http://ti.com/product/pcm3060 Signed-off-by: Kirill Marinushkin Cc: Mark Brown Cc: Liam Girdwood Cc: Jaroslav Kysela Cc: Takashi Iwai Cc: M R Swami Reddy Cc: Vishwas A Deshpande Cc: Kevin Cernekee Cc: Peter Ujfalusi Cc: alsa-devel@alsa-project.org Cc: linux-kernel@vger.kernel.org Signed-off-by: Mark Brown --- .../devicetree/bindings/sound/pcm3060.txt | 17 + MAINTAINERS | 7 + sound/soc/codecs/Kconfig | 17 + sound/soc/codecs/Makefile | 6 + sound/soc/codecs/pcm3060-i2c.c | 61 ++++ sound/soc/codecs/pcm3060-spi.c | 60 ++++ sound/soc/codecs/pcm3060.c | 290 ++++++++++++++++++ sound/soc/codecs/pcm3060.h | 88 ++++++ 8 files changed, 546 insertions(+) create mode 100644 Documentation/devicetree/bindings/sound/pcm3060.txt create mode 100644 sound/soc/codecs/pcm3060-i2c.c create mode 100644 sound/soc/codecs/pcm3060-spi.c create mode 100644 sound/soc/codecs/pcm3060.c create mode 100644 sound/soc/codecs/pcm3060.h diff --git a/Documentation/devicetree/bindings/sound/pcm3060.txt b/Documentation/devicetree/bindings/sound/pcm3060.txt new file mode 100644 index 000000000000..90fcb8523099 --- /dev/null +++ b/Documentation/devicetree/bindings/sound/pcm3060.txt @@ -0,0 +1,17 @@ +PCM3060 audio CODEC + +This driver supports both I2C and SPI. + +Required properties: + +- compatible: "ti,pcm3060" + +- reg : the I2C address of the device for I2C, the chip select + number for SPI. + +Examples: + + pcm3060: pcm3060@46 { + compatible = "ti,pcm3060"; + reg = <0x46>; + }; diff --git a/MAINTAINERS b/MAINTAINERS index a5b256b25905..161b26e05732 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -14597,6 +14597,13 @@ L: netdev@vger.kernel.org S: Maintained F: drivers/net/ethernet/ti/netcp* +TI PCM3060 ASoC CODEC DRIVER +M: Kirill Marinushkin +L: alsa-devel@alsa-project.org (moderated for non-subscribers) +S: Maintained +F: Documentation/devicetree/bindings/sound/pcm3060.txt +F: sound/soc/codecs/pcm3060* + TI TAS571X FAMILY ASoC CODEC DRIVER M: Kevin Cernekee L: alsa-devel@alsa-project.org (moderated for non-subscribers) diff --git a/sound/soc/codecs/Kconfig b/sound/soc/codecs/Kconfig index bf0b949eb7e8..adaf26e1989c 100644 --- a/sound/soc/codecs/Kconfig +++ b/sound/soc/codecs/Kconfig @@ -120,6 +120,8 @@ config SND_SOC_ALL_CODECS select SND_SOC_PCM186X_I2C if I2C select SND_SOC_PCM186X_SPI if SPI_MASTER select SND_SOC_PCM3008 + select SND_SOC_PCM3060_I2C if I2C + select SND_SOC_PCM3060_SPI if SPI_MASTER select SND_SOC_PCM3168A_I2C if I2C select SND_SOC_PCM3168A_SPI if SPI_MASTER select SND_SOC_PCM5102A @@ -737,6 +739,21 @@ config SND_SOC_PCM186X_SPI config SND_SOC_PCM3008 tristate +config SND_SOC_PCM3060 + tristate + +config SND_SOC_PCM3060_I2C + tristate "Texas Instruments PCM3060 CODEC - I2C" + depends on I2C + select SND_SOC_PCM3060 + select REGMAP_I2C + +config SND_SOC_PCM3060_SPI + tristate "Texas Instruments PCM3060 CODEC - SPI" + depends on SPI_MASTER + select SND_SOC_PCM3060 + select REGMAP_SPI + config SND_SOC_PCM3168A tristate diff --git a/sound/soc/codecs/Makefile b/sound/soc/codecs/Makefile index 3046b33ca9d3..3d694c26192c 100644 --- a/sound/soc/codecs/Makefile +++ b/sound/soc/codecs/Makefile @@ -120,6 +120,9 @@ snd-soc-pcm186x-objs := pcm186x.o snd-soc-pcm186x-i2c-objs := pcm186x-i2c.o snd-soc-pcm186x-spi-objs := pcm186x-spi.o snd-soc-pcm3008-objs := pcm3008.o +snd-soc-pcm3060-objs := pcm3060.o +snd-soc-pcm3060-i2c-objs := pcm3060-i2c.o +snd-soc-pcm3060-spi-objs := pcm3060-spi.o snd-soc-pcm3168a-objs := pcm3168a.o snd-soc-pcm3168a-i2c-objs := pcm3168a-i2c.o snd-soc-pcm3168a-spi-objs := pcm3168a-spi.o @@ -381,6 +384,9 @@ obj-$(CONFIG_SND_SOC_PCM186X) += snd-soc-pcm186x.o obj-$(CONFIG_SND_SOC_PCM186X_I2C) += snd-soc-pcm186x-i2c.o obj-$(CONFIG_SND_SOC_PCM186X_SPI) += snd-soc-pcm186x-spi.o obj-$(CONFIG_SND_SOC_PCM3008) += snd-soc-pcm3008.o +obj-$(CONFIG_SND_SOC_PCM3060) += snd-soc-pcm3060.o +obj-$(CONFIG_SND_SOC_PCM3060_I2C) += snd-soc-pcm3060-i2c.o +obj-$(CONFIG_SND_SOC_PCM3060_SPI) += snd-soc-pcm3060-spi.o obj-$(CONFIG_SND_SOC_PCM3168A) += snd-soc-pcm3168a.o obj-$(CONFIG_SND_SOC_PCM3168A_I2C) += snd-soc-pcm3168a-i2c.o obj-$(CONFIG_SND_SOC_PCM3168A_SPI) += snd-soc-pcm3168a-spi.o diff --git a/sound/soc/codecs/pcm3060-i2c.c b/sound/soc/codecs/pcm3060-i2c.c new file mode 100644 index 000000000000..03d2b4323626 --- /dev/null +++ b/sound/soc/codecs/pcm3060-i2c.c @@ -0,0 +1,61 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * PCM3060 I2C driver + * + * Copyright (C) 2018 Kirill Marinushkin + */ + +#include +#include +#include + +#include "pcm3060.h" + +static int pcm3060_i2c_probe(struct i2c_client *i2c, + const struct i2c_device_id *id) +{ + struct pcm3060_priv *priv; + + priv = devm_kzalloc(&i2c->dev, sizeof(*priv), GFP_KERNEL); + if (!priv) + return -ENOMEM; + + i2c_set_clientdata(i2c, priv); + + priv->regmap = devm_regmap_init_i2c(i2c, &pcm3060_regmap); + if (IS_ERR(priv->regmap)) + return PTR_ERR(priv->regmap); + + return pcm3060_probe(&i2c->dev); +} + +static const struct i2c_device_id pcm3060_i2c_id[] = { + { .name = "pcm3060" }, + { }, +}; +MODULE_DEVICE_TABLE(i2c, pcm3060_i2c_id); + +#ifdef CONFIG_OF +static const struct of_device_id pcm3060_of_match[] = { + { .compatible = "ti,pcm3060" }, + { }, +}; +MODULE_DEVICE_TABLE(of, pcm3060_of_match); +#endif /* CONFIG_OF */ + +static struct i2c_driver pcm3060_i2c_driver = { + .driver = { + .name = "pcm3060", +#ifdef CONFIG_OF + .of_match_table = pcm3060_of_match, +#endif /* CONFIG_OF */ + }, + .id_table = pcm3060_i2c_id, + .probe = pcm3060_i2c_probe, +}; + +module_i2c_driver(pcm3060_i2c_driver); + +MODULE_DESCRIPTION("PCM3060 I2C driver"); +MODULE_AUTHOR("Kirill Marinushkin "); +MODULE_LICENSE("GPL v2"); diff --git a/sound/soc/codecs/pcm3060-spi.c b/sound/soc/codecs/pcm3060-spi.c new file mode 100644 index 000000000000..8961e095ae73 --- /dev/null +++ b/sound/soc/codecs/pcm3060-spi.c @@ -0,0 +1,60 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * PCM3060 SPI driver + * + * Copyright (C) 2018 Kirill Marinushkin + */ + +#include +#include +#include + +#include "pcm3060.h" + +static int pcm3060_spi_probe(struct spi_device *spi) +{ + struct pcm3060_priv *priv; + + priv = devm_kzalloc(&spi->dev, sizeof(*priv), GFP_KERNEL); + if (!priv) + return -ENOMEM; + + spi_set_drvdata(spi, priv); + + priv->regmap = devm_regmap_init_spi(spi, &pcm3060_regmap); + if (IS_ERR(priv->regmap)) + return PTR_ERR(priv->regmap); + + return pcm3060_probe(&spi->dev); +} + +static const struct spi_device_id pcm3060_spi_id[] = { + { .name = "pcm3060" }, + { }, +}; +MODULE_DEVICE_TABLE(spi, pcm3060_spi_id); + +#ifdef CONFIG_OF +static const struct of_device_id pcm3060_of_match[] = { + { .compatible = "ti,pcm3060" }, + { }, +}; +MODULE_DEVICE_TABLE(of, pcm3060_of_match); +#endif /* CONFIG_OF */ + +static struct spi_driver pcm3060_spi_driver = { + .driver = { + .name = "pcm3060", +#ifdef CONFIG_OF + .of_match_table = pcm3060_of_match, +#endif /* CONFIG_OF */ + }, + .id_table = pcm3060_spi_id, + .probe = pcm3060_spi_probe, +}; + +module_spi_driver(pcm3060_spi_driver); + +MODULE_DESCRIPTION("PCM3060 SPI driver"); +MODULE_AUTHOR("Kirill Marinushkin "); +MODULE_LICENSE("GPL v2"); diff --git a/sound/soc/codecs/pcm3060.c b/sound/soc/codecs/pcm3060.c new file mode 100644 index 000000000000..ef7c627c9ac5 --- /dev/null +++ b/sound/soc/codecs/pcm3060.c @@ -0,0 +1,290 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * PCM3060 codec driver + * + * Copyright (C) 2018 Kirill Marinushkin + */ + +#include +#include +#include +#include + +#include "pcm3060.h" + +/* dai */ + +static int pcm3060_set_sysclk(struct snd_soc_dai *dai, int clk_id, + unsigned int freq, int dir) +{ + struct snd_soc_component *comp = dai->component; + struct pcm3060_priv *priv = snd_soc_component_get_drvdata(comp); + + if (dir != SND_SOC_CLOCK_IN) { + dev_err(comp->dev, "unsupported sysclock dir: %d\n", dir); + return -EINVAL; + } + + priv->dai[dai->id].sclk_freq = freq; + + return 0; +} + +static int pcm3060_set_fmt(struct snd_soc_dai *dai, unsigned int fmt) +{ + struct snd_soc_component *comp = dai->component; + struct pcm3060_priv *priv = snd_soc_component_get_drvdata(comp); + unsigned int reg; + unsigned int val; + + if ((fmt & SND_SOC_DAIFMT_INV_MASK) != SND_SOC_DAIFMT_NB_NF) { + dev_err(comp->dev, "unsupported DAI polarity: 0x%x\n", fmt); + return -EINVAL; + } + + switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { + case SND_SOC_DAIFMT_CBM_CFM: + priv->dai[dai->id].is_master = true; + break; + case SND_SOC_DAIFMT_CBS_CFS: + priv->dai[dai->id].is_master = false; + break; + default: + dev_err(comp->dev, "unsupported DAI master mode: 0x%x\n", fmt); + return -EINVAL; + } + + switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) { + case SND_SOC_DAIFMT_I2S: + val = PCM3060_REG_FMT_I2S; + break; + case SND_SOC_DAIFMT_RIGHT_J: + val = PCM3060_REG_FMT_RJ; + break; + case SND_SOC_DAIFMT_LEFT_J: + val = PCM3060_REG_FMT_LJ; + break; + default: + dev_err(comp->dev, "unsupported DAI format: 0x%x\n", fmt); + return -EINVAL; + } + + reg = (dai->id == PCM3060_DAI_ID_DAC ? PCM3060_REG67 : PCM3060_REG72); + + regmap_update_bits(priv->regmap, reg, PCM3060_REG_MASK_FMT, val); + + return 0; +} + +static int pcm3060_hw_params(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params, + struct snd_soc_dai *dai) +{ + struct snd_soc_component *comp = dai->component; + struct pcm3060_priv *priv = snd_soc_component_get_drvdata(comp); + unsigned int rate; + unsigned int ratio; + unsigned int reg; + unsigned int val; + + if (!priv->dai[dai->id].is_master) { + val = PCM3060_REG_MS_S; + goto val_ready; + } + + rate = params_rate(params); + if (!rate) { + dev_err(comp->dev, "rate is not configured\n"); + return -EINVAL; + } + + ratio = priv->dai[dai->id].sclk_freq / rate; + + switch (ratio) { + case 768: + val = PCM3060_REG_MS_M768; + break; + case 512: + val = PCM3060_REG_MS_M512; + break; + case 384: + val = PCM3060_REG_MS_M384; + break; + case 256: + val = PCM3060_REG_MS_M256; + break; + case 192: + val = PCM3060_REG_MS_M192; + break; + case 128: + val = PCM3060_REG_MS_M128; + break; + default: + dev_err(comp->dev, "unsupported ratio: %d\n", ratio); + return -EINVAL; + } + +val_ready: + reg = (dai->id == PCM3060_DAI_ID_DAC ? PCM3060_REG67 : PCM3060_REG72); + + regmap_update_bits(priv->regmap, reg, PCM3060_REG_MASK_MS, val); + + return 0; +} + +static const struct snd_soc_dai_ops pcm3060_dai_ops = { + .set_sysclk = pcm3060_set_sysclk, + .set_fmt = pcm3060_set_fmt, + .hw_params = pcm3060_hw_params, +}; + +#define PCM3060_DAI_RATES_ADC (SNDRV_PCM_RATE_16000 | SNDRV_PCM_RATE_32000 | \ + SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000 | \ + SNDRV_PCM_RATE_88200 | SNDRV_PCM_RATE_96000) + +#define PCM3060_DAI_RATES_DAC (PCM3060_DAI_RATES_ADC | \ + SNDRV_PCM_RATE_176400 | SNDRV_PCM_RATE_192000) + +static struct snd_soc_dai_driver pcm3060_dai[] = { + { + .name = "pcm3060-dac", + .id = PCM3060_DAI_ID_DAC, + .playback = { + .stream_name = "Playback", + .channels_min = 2, + .channels_max = 2, + .rates = PCM3060_DAI_RATES_DAC, + .formats = SNDRV_PCM_FMTBIT_S24_LE, + }, + .ops = &pcm3060_dai_ops, + }, + { + .name = "pcm3060-adc", + .id = PCM3060_DAI_ID_ADC, + .capture = { + .stream_name = "Capture", + .channels_min = 2, + .channels_max = 2, + .rates = PCM3060_DAI_RATES_ADC, + .formats = SNDRV_PCM_FMTBIT_S24_LE, + }, + .ops = &pcm3060_dai_ops, + }, +}; + +/* dapm */ + +static DECLARE_TLV_DB_SCALE(pcm3060_dapm_tlv, -10050, 50, 1); + +static const struct snd_kcontrol_new pcm3060_dapm_controls[] = { + SOC_DOUBLE_R_RANGE_TLV("Master Playback Volume", + PCM3060_REG65, PCM3060_REG66, 0, + PCM3060_REG_AT2_MIN, PCM3060_REG_AT2_MAX, + 0, pcm3060_dapm_tlv), + SOC_DOUBLE("Master Playback Switch", PCM3060_REG68, + PCM3060_REG_SHIFT_MUT21, PCM3060_REG_SHIFT_MUT22, 1, 1), + + SOC_DOUBLE_R_RANGE_TLV("Master Capture Volume", + PCM3060_REG70, PCM3060_REG71, 0, + PCM3060_REG_AT1_MIN, PCM3060_REG_AT1_MAX, + 0, pcm3060_dapm_tlv), + SOC_DOUBLE("Master Capture Switch", PCM3060_REG73, + PCM3060_REG_SHIFT_MUT11, PCM3060_REG_SHIFT_MUT12, 1, 1), +}; + +static const struct snd_soc_dapm_widget pcm3060_dapm_widgets[] = { + SND_SOC_DAPM_OUTPUT("OUTL+"), + SND_SOC_DAPM_OUTPUT("OUTR+"), + SND_SOC_DAPM_OUTPUT("OUTL-"), + SND_SOC_DAPM_OUTPUT("OUTR-"), + + SND_SOC_DAPM_INPUT("INL"), + SND_SOC_DAPM_INPUT("INR"), +}; + +static const struct snd_soc_dapm_route pcm3060_dapm_map[] = { + { "OUTL+", NULL, "Playback" }, + { "OUTR+", NULL, "Playback" }, + { "OUTL-", NULL, "Playback" }, + { "OUTR-", NULL, "Playback" }, + + { "Capture", NULL, "INL" }, + { "Capture", NULL, "INR" }, +}; + +/* soc component */ + +static const struct snd_soc_component_driver pcm3060_soc_comp_driver = { + .controls = pcm3060_dapm_controls, + .num_controls = ARRAY_SIZE(pcm3060_dapm_controls), + .dapm_widgets = pcm3060_dapm_widgets, + .num_dapm_widgets = ARRAY_SIZE(pcm3060_dapm_widgets), + .dapm_routes = pcm3060_dapm_map, + .num_dapm_routes = ARRAY_SIZE(pcm3060_dapm_map), +}; + +/* regmap */ + +static bool pcm3060_reg_writeable(struct device *dev, unsigned int reg) +{ + return (reg >= PCM3060_REG64); +} + +static bool pcm3060_reg_readable(struct device *dev, unsigned int reg) +{ + return (reg >= PCM3060_REG64); +} + +static bool pcm3060_reg_volatile(struct device *dev, unsigned int reg) +{ + /* PCM3060_REG64 is volatile */ + return (reg == PCM3060_REG64); +} + +static const struct reg_default pcm3060_reg_defaults[] = { + { PCM3060_REG64, 0xF0 }, + { PCM3060_REG65, 0xFF }, + { PCM3060_REG66, 0xFF }, + { PCM3060_REG67, 0x00 }, + { PCM3060_REG68, 0x00 }, + { PCM3060_REG69, 0x00 }, + { PCM3060_REG70, 0xD7 }, + { PCM3060_REG71, 0xD7 }, + { PCM3060_REG72, 0x00 }, + { PCM3060_REG73, 0x00 }, +}; + +const struct regmap_config pcm3060_regmap = { + .reg_bits = 8, + .val_bits = 8, + .writeable_reg = pcm3060_reg_writeable, + .readable_reg = pcm3060_reg_readable, + .volatile_reg = pcm3060_reg_volatile, + .max_register = PCM3060_REG73, + .reg_defaults = pcm3060_reg_defaults, + .num_reg_defaults = ARRAY_SIZE(pcm3060_reg_defaults), + .cache_type = REGCACHE_RBTREE, +}; +EXPORT_SYMBOL(pcm3060_regmap); + +/* device */ + +int pcm3060_probe(struct device *dev) +{ + int rc; + + rc = devm_snd_soc_register_component(dev, &pcm3060_soc_comp_driver, + pcm3060_dai, + ARRAY_SIZE(pcm3060_dai)); + if (rc) { + dev_err(dev, "failed to register component, rc=%d\n", rc); + return rc; + } + + return 0; +} +EXPORT_SYMBOL(pcm3060_probe); + +MODULE_DESCRIPTION("PCM3060 codec driver"); +MODULE_AUTHOR("Kirill Marinushkin "); +MODULE_LICENSE("GPL v2"); diff --git a/sound/soc/codecs/pcm3060.h b/sound/soc/codecs/pcm3060.h new file mode 100644 index 000000000000..fd89a68aa8a7 --- /dev/null +++ b/sound/soc/codecs/pcm3060.h @@ -0,0 +1,88 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * PCM3060 codec driver + * + * Copyright (C) 2018 Kirill Marinushkin + */ + +#ifndef _SND_SOC_PCM3060_H +#define _SND_SOC_PCM3060_H + +#include +#include + +extern const struct regmap_config pcm3060_regmap; + +#define PCM3060_DAI_ID_DAC 0 +#define PCM3060_DAI_ID_ADC 1 +#define PCM3060_DAI_IDS_NUM 2 + +struct pcm3060_priv_dai { + bool is_master; + unsigned int sclk_freq; +}; + +struct pcm3060_priv { + struct regmap *regmap; + struct pcm3060_priv_dai dai[PCM3060_DAI_IDS_NUM]; +}; + +int pcm3060_probe(struct device *dev); +int pcm3060_remove(struct device *dev); + +/* registers */ + +#define PCM3060_REG64 0x40 +#define PCM3060_REG_MRST 0x80 +#define PCM3060_REG_SRST 0x40 +#define PCM3060_REG_ADPSV 0x20 +#define PCM3060_REG_DAPSV 0x10 +#define PCM3060_REG_SE 0x01 + +#define PCM3060_REG65 0x41 +#define PCM3060_REG66 0x42 +#define PCM3060_REG_AT2_MIN 0x36 +#define PCM3060_REG_AT2_MAX 0xFF + +#define PCM3060_REG67 0x43 +#define PCM3060_REG72 0x48 +#define PCM3060_REG_CSEL 0x80 +#define PCM3060_REG_MASK_MS 0x70 +#define PCM3060_REG_MS_S 0x00 +#define PCM3060_REG_MS_M768 (0x01 << 4) +#define PCM3060_REG_MS_M512 (0x02 << 4) +#define PCM3060_REG_MS_M384 (0x03 << 4) +#define PCM3060_REG_MS_M256 (0x04 << 4) +#define PCM3060_REG_MS_M192 (0x05 << 4) +#define PCM3060_REG_MS_M128 (0x06 << 4) +#define PCM3060_REG_MASK_FMT 0x03 +#define PCM3060_REG_FMT_I2S 0x00 +#define PCM3060_REG_FMT_LJ 0x01 +#define PCM3060_REG_FMT_RJ 0x02 + +#define PCM3060_REG68 0x44 +#define PCM3060_REG_OVER 0x40 +#define PCM3060_REG_DREV2 0x04 +#define PCM3060_REG_SHIFT_MUT21 0x00 +#define PCM3060_REG_SHIFT_MUT22 0x01 + +#define PCM3060_REG69 0x45 +#define PCM3060_REG_FLT 0x80 +#define PCM3060_REG_MASK_DMF 0x60 +#define PCM3060_REG_DMC 0x10 +#define PCM3060_REG_ZREV 0x02 +#define PCM3060_REG_AZRO 0x01 + +#define PCM3060_REG70 0x46 +#define PCM3060_REG71 0x47 +#define PCM3060_REG_AT1_MIN 0x0E +#define PCM3060_REG_AT1_MAX 0xFF + +#define PCM3060_REG73 0x49 +#define PCM3060_REG_ZCDD 0x10 +#define PCM3060_REG_BYP 0x08 +#define PCM3060_REG_DREV1 0x04 +#define PCM3060_REG_SHIFT_MUT11 0x00 +#define PCM3060_REG_SHIFT_MUT12 0x01 + +#endif /* _SND_SOC_PCM3060_H */ From c736cbd3a668c3befd3ce08e0fbccac302fbecac Mon Sep 17 00:00:00 2001 From: Akshu Agrawal Date: Tue, 21 Aug 2018 12:25:05 +0530 Subject: [PATCH 035/299] ASoC: AMD: Set constraints for DMIC and MAX98357a codec We support dual channel, 48Khz. This constraint was set only for da7219. It is being extended to DMIC and MAX98357a. Signed-off-by: Akshu Agrawal Reviewed-by: Daniel Kurtz Signed-off-by: Mark Brown --- sound/soc/amd/acp-da7219-max98357a.c | 33 ++++++++++++++++++++++++++++ 1 file changed, 33 insertions(+) diff --git a/sound/soc/amd/acp-da7219-max98357a.c b/sound/soc/amd/acp-da7219-max98357a.c index 8e3275a96a82..95c5701e2a30 100644 --- a/sound/soc/amd/acp-da7219-max98357a.c +++ b/sound/soc/amd/acp-da7219-max98357a.c @@ -162,10 +162,21 @@ static void cz_da7219_shutdown(struct snd_pcm_substream *substream) static int cz_max_startup(struct snd_pcm_substream *substream) { + struct snd_pcm_runtime *runtime = substream->runtime; struct snd_soc_pcm_runtime *rtd = substream->private_data; struct snd_soc_card *card = rtd->card; struct acp_platform_info *machine = snd_soc_card_get_drvdata(card); + /* + * On this platform for PCM device we support stereo + */ + + runtime->hw.channels_max = DUAL_CHANNEL; + snd_pcm_hw_constraint_list(runtime, 0, SNDRV_PCM_HW_PARAM_CHANNELS, + &constraints_channels); + snd_pcm_hw_constraint_list(runtime, 0, SNDRV_PCM_HW_PARAM_RATE, + &constraints_rates); + machine->i2s_instance = I2S_BT_INSTANCE; return da7219_clk_enable(substream); } @@ -177,20 +188,42 @@ static void cz_max_shutdown(struct snd_pcm_substream *substream) static int cz_dmic0_startup(struct snd_pcm_substream *substream) { + struct snd_pcm_runtime *runtime = substream->runtime; struct snd_soc_pcm_runtime *rtd = substream->private_data; struct snd_soc_card *card = rtd->card; struct acp_platform_info *machine = snd_soc_card_get_drvdata(card); + /* + * On this platform for PCM device we support stereo + */ + + runtime->hw.channels_max = DUAL_CHANNEL; + snd_pcm_hw_constraint_list(runtime, 0, SNDRV_PCM_HW_PARAM_CHANNELS, + &constraints_channels); + snd_pcm_hw_constraint_list(runtime, 0, SNDRV_PCM_HW_PARAM_RATE, + &constraints_rates); + machine->i2s_instance = I2S_BT_INSTANCE; return da7219_clk_enable(substream); } static int cz_dmic1_startup(struct snd_pcm_substream *substream) { + struct snd_pcm_runtime *runtime = substream->runtime; struct snd_soc_pcm_runtime *rtd = substream->private_data; struct snd_soc_card *card = rtd->card; struct acp_platform_info *machine = snd_soc_card_get_drvdata(card); + /* + * On this platform for PCM device we support stereo + */ + + runtime->hw.channels_max = DUAL_CHANNEL; + snd_pcm_hw_constraint_list(runtime, 0, SNDRV_PCM_HW_PARAM_CHANNELS, + &constraints_channels); + snd_pcm_hw_constraint_list(runtime, 0, SNDRV_PCM_HW_PARAM_RATE, + &constraints_rates); + machine->i2s_instance = I2S_SP_INSTANCE; machine->capture_channel = CAP_CHANNEL0; return da7219_clk_enable(substream); From a1b1e9880f0c2754a5ac416a546d9f295f72eabc Mon Sep 17 00:00:00 2001 From: Akshu Agrawal Date: Tue, 21 Aug 2018 12:29:43 +0530 Subject: [PATCH 036/299] ASoC: AMD: Change MCLK to 48Mhz 25Mhz MCLK which was earlier used was of spread type. Thus, we were not getting accurate rate. The 48Mhz system clk is of non-spread type and we are changing to it to get accurate rate. Signed-off-by: Akshu Agrawal Reviewed-by: Daniel Kurtz Signed-off-by: Mark Brown --- sound/soc/amd/acp-da7219-max98357a.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sound/soc/amd/acp-da7219-max98357a.c b/sound/soc/amd/acp-da7219-max98357a.c index 95c5701e2a30..3879cccbd2c0 100644 --- a/sound/soc/amd/acp-da7219-max98357a.c +++ b/sound/soc/amd/acp-da7219-max98357a.c @@ -42,7 +42,7 @@ #include "../codecs/da7219.h" #include "../codecs/da7219-aad.h" -#define CZ_PLAT_CLK 25000000 +#define CZ_PLAT_CLK 48000000 #define DUAL_CHANNEL 2 static struct snd_soc_jack cz_jack; From 1b3b7981524af2b6dcdf78cfa6dca89522c13ade Mon Sep 17 00:00:00 2001 From: Peter Rosin Date: Mon, 20 Aug 2018 12:14:09 +0200 Subject: [PATCH 037/299] ASoC: atmel: tse850: switch to SPDX license identifier Convert to // comments in the leading comment, drop the boilerplate license text and use the correct MODULE_LICENSE. Signed-off-by: Peter Rosin Signed-off-by: Mark Brown --- sound/soc/atmel/tse850-pcm5142.c | 78 +++++++++++++++----------------- 1 file changed, 36 insertions(+), 42 deletions(-) diff --git a/sound/soc/atmel/tse850-pcm5142.c b/sound/soc/atmel/tse850-pcm5142.c index 3a1393283156..214adcad5419 100644 --- a/sound/soc/atmel/tse850-pcm5142.c +++ b/sound/soc/atmel/tse850-pcm5142.c @@ -1,44 +1,38 @@ -/* - * TSE-850 audio - ASoC driver for the Axentia TSE-850 with a PCM5142 codec - * - * Copyright (C) 2016 Axentia Technologies AB - * - * Author: Peter Rosin - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - */ - -/* - * loop1 relays - * IN1 +---o +------------+ o---+ OUT1 - * \ / - * + + - * | / | - * +--o +--. | - * | add | | - * | V | - * | .---. | - * DAC +----------->|Sum|---+ - * | '---' | - * | | - * + + - * - * IN2 +---o--+------------+--o---+ OUT2 - * loop2 relays - * - * The 'loop1' gpio pin controlls two relays, which are either in loop - * position, meaning that input and output are directly connected, or - * they are in mixer position, meaning that the signal is passed through - * the 'Sum' mixer. Similarly for 'loop2'. - * - * In the above, the 'loop1' relays are inactive, thus feeding IN1 to the - * mixer (if 'add' is active) and feeding the mixer output to OUT1. The - * 'loop2' relays are active, short-cutting the TSE-850 from channel 2. - * IN1, IN2, OUT1 and OUT2 are TSE-850 connectors and DAC is the PCB name - * of the (filtered) output from the PCM5142 codec. - */ +// SPDX-License-Identifier: GPL-2.0 +// +// TSE-850 audio - ASoC driver for the Axentia TSE-850 with a PCM5142 codec +// +// Copyright (C) 2016 Axentia Technologies AB +// +// Author: Peter Rosin +// +// loop1 relays +// IN1 +---o +------------+ o---+ OUT1 +// \ / +// + + +// | / | +// +--o +--. | +// | add | | +// | V | +// | .---. | +// DAC +----------->|Sum|---+ +// | '---' | +// | | +// + + +// +// IN2 +---o--+------------+--o---+ OUT2 +// loop2 relays +// +// The 'loop1' gpio pin controlls two relays, which are either in loop +// position, meaning that input and output are directly connected, or +// they are in mixer position, meaning that the signal is passed through +// the 'Sum' mixer. Similarly for 'loop2'. +// +// In the above, the 'loop1' relays are inactive, thus feeding IN1 to the +// mixer (if 'add' is active) and feeding the mixer output to OUT1. The +// 'loop2' relays are active, short-cutting the TSE-850 from channel 2. +// IN1, IN2, OUT1 and OUT2 are TSE-850 connectors and DAC is the PCB name +// of the (filtered) output from the PCM5142 codec. #include #include @@ -452,4 +446,4 @@ module_platform_driver(tse850_driver); /* Module information */ MODULE_AUTHOR("Peter Rosin "); MODULE_DESCRIPTION("ALSA SoC driver for TSE-850 with PCM5142 codec"); -MODULE_LICENSE("GPL"); +MODULE_LICENSE("GPL v2"); From aec785f6a0dcd68c3d2ad4a7d5b48d5fc94d75e8 Mon Sep 17 00:00:00 2001 From: Kirill Marinushkin Date: Tue, 28 Aug 2018 23:42:30 +0200 Subject: [PATCH 038/299] ASoC: pcm3060: Improve stylistics of file comments Modified the complete file comments in C++ style, to make them look more intentional Signed-off-by: Kirill Marinushkin Signed-off-by: Mark Brown --- sound/soc/codecs/pcm3060-i2c.c | 9 ++++----- sound/soc/codecs/pcm3060-spi.c | 9 ++++----- sound/soc/codecs/pcm3060.c | 9 ++++----- 3 files changed, 12 insertions(+), 15 deletions(-) diff --git a/sound/soc/codecs/pcm3060-i2c.c b/sound/soc/codecs/pcm3060-i2c.c index 03d2b4323626..cdc8314882bc 100644 --- a/sound/soc/codecs/pcm3060-i2c.c +++ b/sound/soc/codecs/pcm3060-i2c.c @@ -1,9 +1,8 @@ // SPDX-License-Identifier: GPL-2.0 -/* - * PCM3060 I2C driver - * - * Copyright (C) 2018 Kirill Marinushkin - */ +// +// PCM3060 I2C driver +// +// Copyright (C) 2018 Kirill Marinushkin #include #include diff --git a/sound/soc/codecs/pcm3060-spi.c b/sound/soc/codecs/pcm3060-spi.c index 8961e095ae73..f6f19fa80932 100644 --- a/sound/soc/codecs/pcm3060-spi.c +++ b/sound/soc/codecs/pcm3060-spi.c @@ -1,9 +1,8 @@ // SPDX-License-Identifier: GPL-2.0 -/* - * PCM3060 SPI driver - * - * Copyright (C) 2018 Kirill Marinushkin - */ +// +// PCM3060 SPI driver +// +// Copyright (C) 2018 Kirill Marinushkin #include #include diff --git a/sound/soc/codecs/pcm3060.c b/sound/soc/codecs/pcm3060.c index ef7c627c9ac5..5b9718fa766d 100644 --- a/sound/soc/codecs/pcm3060.c +++ b/sound/soc/codecs/pcm3060.c @@ -1,9 +1,8 @@ // SPDX-License-Identifier: GPL-2.0 -/* - * PCM3060 codec driver - * - * Copyright (C) 2018 Kirill Marinushkin - */ +// +// PCM3060 codec driver +// +// Copyright (C) 2018 Kirill Marinushkin #include #include From 080aaf10892eec4b359126473e582f62ebb09496 Mon Sep 17 00:00:00 2001 From: Kirill Marinushkin Date: Tue, 28 Aug 2018 23:42:31 +0200 Subject: [PATCH 039/299] ASoC: pcm3060: Improve legibility of if-statements Modified some if-statements to make them more clear Signed-off-by: Kirill Marinushkin Signed-off-by: Mark Brown --- sound/soc/codecs/pcm3060.c | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/sound/soc/codecs/pcm3060.c b/sound/soc/codecs/pcm3060.c index 5b9718fa766d..494d9d662be8 100644 --- a/sound/soc/codecs/pcm3060.c +++ b/sound/soc/codecs/pcm3060.c @@ -68,7 +68,10 @@ static int pcm3060_set_fmt(struct snd_soc_dai *dai, unsigned int fmt) return -EINVAL; } - reg = (dai->id == PCM3060_DAI_ID_DAC ? PCM3060_REG67 : PCM3060_REG72); + if (dai->id == PCM3060_DAI_ID_DAC) + reg = PCM3060_REG67; + else + reg = PCM3060_REG72; regmap_update_bits(priv->regmap, reg, PCM3060_REG_MASK_FMT, val); @@ -124,7 +127,10 @@ static int pcm3060_hw_params(struct snd_pcm_substream *substream, } val_ready: - reg = (dai->id == PCM3060_DAI_ID_DAC ? PCM3060_REG67 : PCM3060_REG72); + if (dai->id == PCM3060_DAI_ID_DAC) + reg = PCM3060_REG67; + else + reg = PCM3060_REG72; regmap_update_bits(priv->regmap, reg, PCM3060_REG_MASK_MS, val); From dba508b5ab1d138bd7543a3f503492f1a173aa32 Mon Sep 17 00:00:00 2001 From: Robert Rosengren Date: Mon, 13 Aug 2018 09:33:58 +0200 Subject: [PATCH 040/299] ASoC: adau17x1: Unused exported functions changed to internal adau17x1_setup_firmware and adau17x1_has_dsp is only used internally, so making them static instead of exported. Signed-off-by: Robert Rosengren Acked-by: Lars-Peter Clausen Signed-off-by: Mark Brown --- sound/soc/codecs/adau17x1.c | 9 +++++---- sound/soc/codecs/adau17x1.h | 4 ---- 2 files changed, 5 insertions(+), 8 deletions(-) diff --git a/sound/soc/codecs/adau17x1.c b/sound/soc/codecs/adau17x1.c index c0bc429249fa..3959e6ad113d 100644 --- a/sound/soc/codecs/adau17x1.c +++ b/sound/soc/codecs/adau17x1.c @@ -67,6 +67,9 @@ static const struct snd_kcontrol_new adau17x1_controls[] = { SOC_ENUM("Mic Bias Mode", adau17x1_mic_bias_mode_enum), }; +static int adau17x1_setup_firmware(struct snd_soc_component *component, + unsigned int rate); + static int adau17x1_pll_event(struct snd_soc_dapm_widget *w, struct snd_kcontrol *kcontrol, int event) { @@ -320,7 +323,7 @@ static const struct snd_soc_dapm_route adau17x1_no_dsp_dapm_routes[] = { { "Capture", NULL, "Right Decimator" }, }; -bool adau17x1_has_dsp(struct adau *adau) +static bool adau17x1_has_dsp(struct adau *adau) { switch (adau->type) { case ADAU1761: @@ -331,7 +334,6 @@ bool adau17x1_has_dsp(struct adau *adau) return false; } } -EXPORT_SYMBOL_GPL(adau17x1_has_dsp); static bool adau17x1_has_safeload(struct adau *adau) { @@ -854,7 +856,7 @@ bool adau17x1_volatile_register(struct device *dev, unsigned int reg) } EXPORT_SYMBOL_GPL(adau17x1_volatile_register); -int adau17x1_setup_firmware(struct snd_soc_component *component, +static int adau17x1_setup_firmware(struct snd_soc_component *component, unsigned int rate) { int ret; @@ -898,7 +900,6 @@ err: return ret; } -EXPORT_SYMBOL_GPL(adau17x1_setup_firmware); int adau17x1_add_widgets(struct snd_soc_component *component) { diff --git a/sound/soc/codecs/adau17x1.h b/sound/soc/codecs/adau17x1.h index e6fe87beec07..98a3b6f5bc96 100644 --- a/sound/soc/codecs/adau17x1.h +++ b/sound/soc/codecs/adau17x1.h @@ -68,10 +68,6 @@ int adau17x1_resume(struct snd_soc_component *component); extern const struct snd_soc_dai_ops adau17x1_dai_ops; -int adau17x1_setup_firmware(struct snd_soc_component *component, - unsigned int rate); -bool adau17x1_has_dsp(struct adau *adau); - #define ADAU17X1_CLOCK_CONTROL 0x4000 #define ADAU17X1_PLL_CONTROL 0x4002 #define ADAU17X1_REC_POWER_MGMT 0x4009 From 26bcf1c368d9460987d597fb0476d60e51a1bf82 Mon Sep 17 00:00:00 2001 From: Jerome Brunet Date: Wed, 29 Aug 2018 17:00:48 +0200 Subject: [PATCH 041/299] ASoC: dmic: add Kconfig prompt for the generic dmic codec. Add Kconfig prompt for the generic digital mic to make it configurable through menuconfig Signed-off-by: Jerome Brunet Signed-off-by: Mark Brown --- sound/soc/codecs/Kconfig | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/sound/soc/codecs/Kconfig b/sound/soc/codecs/Kconfig index adaf26e1989c..9989d35e0fc6 100644 --- a/sound/soc/codecs/Kconfig +++ b/sound/soc/codecs/Kconfig @@ -578,7 +578,11 @@ config SND_SOC_DA9055 tristate config SND_SOC_DMIC - tristate + tristate "Generic Digital Microphone CODEC" + depends on GPIOLIB + help + Enable support for the Generic Digital Microphone CODEC. + Select this if your sound card has DMICs. config SND_SOC_HDMI_CODEC tristate From cb06a037f8362e250a6e61872ffa01ab086ec9e2 Mon Sep 17 00:00:00 2001 From: Jerome Brunet Date: Wed, 29 Aug 2018 17:00:49 +0200 Subject: [PATCH 042/299] ASoC: dmic: add DT module alias Before this patch the only alias provided by the dmic module is: alias: platform:dmic-codec Device instantiated from DT will not probe automatically with this After this patch, here is the new alias list: alias: platform:dmic-codec alias: of:N*T*Cdmic-codecC* alias: of:N*T*Cdmic-codec Now the dmic codec probes automatically when instantiated from DT. Signed-off-by: Jerome Brunet Signed-off-by: Mark Brown --- sound/soc/codecs/dmic.c | 1 + 1 file changed, 1 insertion(+) diff --git a/sound/soc/codecs/dmic.c b/sound/soc/codecs/dmic.c index 8c4926df9286..71322e0410ee 100644 --- a/sound/soc/codecs/dmic.c +++ b/sound/soc/codecs/dmic.c @@ -148,6 +148,7 @@ static const struct of_device_id dmic_dev_match[] = { {.compatible = "dmic-codec"}, {} }; +MODULE_DEVICE_TABLE(of, dmic_dev_match); static struct platform_driver dmic_driver = { .driver = { From 5cc3f8f89f2a42992315c4917e0c67ccb0269dec Mon Sep 17 00:00:00 2001 From: Jerome Brunet Date: Wed, 29 Aug 2018 17:00:50 +0200 Subject: [PATCH 043/299] ASoC: meson: add axg pdm input DT binding documentation Add the DT binding documentation for axg's PDM input Signed-off-by: Jerome Brunet Signed-off-by: Mark Brown --- .../bindings/sound/amlogic,axg-pdm.txt | 24 +++++++++++++++++++ 1 file changed, 24 insertions(+) create mode 100644 Documentation/devicetree/bindings/sound/amlogic,axg-pdm.txt diff --git a/Documentation/devicetree/bindings/sound/amlogic,axg-pdm.txt b/Documentation/devicetree/bindings/sound/amlogic,axg-pdm.txt new file mode 100644 index 000000000000..5672d0bc5b16 --- /dev/null +++ b/Documentation/devicetree/bindings/sound/amlogic,axg-pdm.txt @@ -0,0 +1,24 @@ +* Amlogic Audio PDM input + +Required properties: +- compatible: 'amlogic,axg-pdm' +- reg: physical base address of the controller and length of memory + mapped region. +- clocks: list of clock phandle, one for each entry clock-names. +- clock-names: should contain the following: + * "pclk" : peripheral clock. + * "dclk" : pdm digital clock + * "sysclk" : dsp system clock +- #sound-dai-cells: must be 0. + +Example of PDM on the A113 SoC: + +pdm: audio-controller@ff632000 { + compatible = "amlogic,axg-pdm"; + reg = <0x0 0xff632000 0x0 0x34>; + #sound-dai-cells = <0>; + clocks = <&clkc_audio AUD_CLKID_PDM>, + <&clkc_audio AUD_CLKID_PDM_DCLK>, + <&clkc_audio AUD_CLKID_PDM_SYSCLK>; + clock-names = "pclk", "dclk", "sysclk"; +}; From 2cfc123eea7477f26f59506fb45f25cb09ee1591 Mon Sep 17 00:00:00 2001 From: Jerome Brunet Date: Wed, 29 Aug 2018 17:00:51 +0200 Subject: [PATCH 044/299] ASoC: meson: add axg pdm input Add pdm input driver for the device found on the amlogic AXG SoC family Signed-off-by: Jerome Brunet Signed-off-by: Mark Brown --- sound/soc/meson/Kconfig | 9 + sound/soc/meson/Makefile | 2 + sound/soc/meson/axg-pdm.c | 654 ++++++++++++++++++++++++++++++++++++++ 3 files changed, 665 insertions(+) create mode 100644 sound/soc/meson/axg-pdm.c diff --git a/sound/soc/meson/Kconfig b/sound/soc/meson/Kconfig index 2ccbadc387de..8b8426ed2363 100644 --- a/sound/soc/meson/Kconfig +++ b/sound/soc/meson/Kconfig @@ -54,6 +54,7 @@ config SND_MESON_AXG_SOUND_CARD imply SND_MESON_AXG_TDMIN imply SND_MESON_AXG_TDMOUT imply SND_MESON_AXG_SPDIFOUT + imply SND_MESON_AXG_PDM help Select Y or M to add support for the AXG SoC sound card @@ -66,4 +67,12 @@ config SND_MESON_AXG_SPDIFOUT Select Y or M to add support for SPDIF output serializer embedded in the Amlogic AXG SoC family +config SND_MESON_AXG_PDM + tristate "Amlogic AXG PDM Input Support" + imply SND_SOC_DMIC + imply COMMON_CLK_AXG_AUDIO + help + Select Y or M to add support for PDM input embedded + in the Amlogic AXG SoC family + endmenu diff --git a/sound/soc/meson/Makefile b/sound/soc/meson/Makefile index c5e003b093db..4cd25104029d 100644 --- a/sound/soc/meson/Makefile +++ b/sound/soc/meson/Makefile @@ -9,6 +9,7 @@ snd-soc-meson-axg-tdmin-objs := axg-tdmin.o snd-soc-meson-axg-tdmout-objs := axg-tdmout.o snd-soc-meson-axg-sound-card-objs := axg-card.o snd-soc-meson-axg-spdifout-objs := axg-spdifout.o +snd-soc-meson-axg-pdm-objs := axg-pdm.o obj-$(CONFIG_SND_MESON_AXG_FIFO) += snd-soc-meson-axg-fifo.o obj-$(CONFIG_SND_MESON_AXG_FRDDR) += snd-soc-meson-axg-frddr.o @@ -19,3 +20,4 @@ obj-$(CONFIG_SND_MESON_AXG_TDMIN) += snd-soc-meson-axg-tdmin.o obj-$(CONFIG_SND_MESON_AXG_TDMOUT) += snd-soc-meson-axg-tdmout.o obj-$(CONFIG_SND_MESON_AXG_SOUND_CARD) += snd-soc-meson-axg-sound-card.o obj-$(CONFIG_SND_MESON_AXG_SPDIFOUT) += snd-soc-meson-axg-spdifout.o +obj-$(CONFIG_SND_MESON_AXG_PDM) += snd-soc-meson-axg-pdm.o diff --git a/sound/soc/meson/axg-pdm.c b/sound/soc/meson/axg-pdm.c new file mode 100644 index 000000000000..9d5684493ffc --- /dev/null +++ b/sound/soc/meson/axg-pdm.c @@ -0,0 +1,654 @@ +// SPDX-License-Identifier: (GPL-2.0 OR MIT) +// +// Copyright (c) 2018 BayLibre, SAS. +// Author: Jerome Brunet + +#include +#include +#include +#include +#include +#include +#include +#include + +#define PDM_CTRL 0x00 +#define PDM_CTRL_EN BIT(31) +#define PDM_CTRL_OUT_MODE BIT(29) +#define PDM_CTRL_BYPASS_MODE BIT(28) +#define PDM_CTRL_RST_FIFO BIT(16) +#define PDM_CTRL_CHAN_RSTN_MASK GENMASK(15, 8) +#define PDM_CTRL_CHAN_RSTN(x) ((x) << 8) +#define PDM_CTRL_CHAN_EN_MASK GENMASK(7, 0) +#define PDM_CTRL_CHAN_EN(x) ((x) << 0) +#define PDM_HCIC_CTRL1 0x04 +#define PDM_FILTER_EN BIT(31) +#define PDM_HCIC_CTRL1_GAIN_SFT_MASK GENMASK(29, 24) +#define PDM_HCIC_CTRL1_GAIN_SFT(x) ((x) << 24) +#define PDM_HCIC_CTRL1_GAIN_MULT_MASK GENMASK(23, 16) +#define PDM_HCIC_CTRL1_GAIN_MULT(x) ((x) << 16) +#define PDM_HCIC_CTRL1_DSR_MASK GENMASK(8, 4) +#define PDM_HCIC_CTRL1_DSR(x) ((x) << 4) +#define PDM_HCIC_CTRL1_STAGE_NUM_MASK GENMASK(3, 0) +#define PDM_HCIC_CTRL1_STAGE_NUM(x) ((x) << 0) +#define PDM_HCIC_CTRL2 0x08 +#define PDM_F1_CTRL 0x0c +#define PDM_LPF_ROUND_MODE_MASK GENMASK(17, 16) +#define PDM_LPF_ROUND_MODE(x) ((x) << 16) +#define PDM_LPF_DSR_MASK GENMASK(15, 12) +#define PDM_LPF_DSR(x) ((x) << 12) +#define PDM_LPF_STAGE_NUM_MASK GENMASK(8, 0) +#define PDM_LPF_STAGE_NUM(x) ((x) << 0) +#define PDM_LPF_MAX_STAGE 336 +#define PDM_LPF_NUM 3 +#define PDM_F2_CTRL 0x10 +#define PDM_F3_CTRL 0x14 +#define PDM_HPF_CTRL 0x18 +#define PDM_HPF_SFT_STEPS_MASK GENMASK(20, 16) +#define PDM_HPF_SFT_STEPS(x) ((x) << 16) +#define PDM_HPF_OUT_FACTOR_MASK GENMASK(15, 0) +#define PDM_HPF_OUT_FACTOR(x) ((x) << 0) +#define PDM_CHAN_CTRL 0x1c +#define PDM_CHAN_CTRL_POINTER_WIDTH 8 +#define PDM_CHAN_CTRL_POINTER_MAX ((1 << PDM_CHAN_CTRL_POINTER_WIDTH) - 1) +#define PDM_CHAN_CTRL_NUM 4 +#define PDM_CHAN_CTRL1 0x20 +#define PDM_COEFF_ADDR 0x24 +#define PDM_COEFF_DATA 0x28 +#define PDM_CLKG_CTRL 0x2c +#define PDM_STS 0x30 + +struct axg_pdm_lpf { + unsigned int ds; + unsigned int round_mode; + const unsigned int *tap; + unsigned int tap_num; +}; + +struct axg_pdm_hcic { + unsigned int shift; + unsigned int mult; + unsigned int steps; + unsigned int ds; +}; + +struct axg_pdm_hpf { + unsigned int out_factor; + unsigned int steps; +}; + +struct axg_pdm_filters { + struct axg_pdm_hcic hcic; + struct axg_pdm_hpf hpf; + struct axg_pdm_lpf lpf[PDM_LPF_NUM]; +}; + +struct axg_pdm_cfg { + const struct axg_pdm_filters *filters; + unsigned int sys_rate; +}; + +struct axg_pdm { + const struct axg_pdm_cfg *cfg; + struct regmap *map; + struct clk *dclk; + struct clk *sysclk; + struct clk *pclk; +}; + +static void axg_pdm_enable(struct regmap *map) +{ + /* Reset AFIFO */ + regmap_update_bits(map, PDM_CTRL, PDM_CTRL_RST_FIFO, PDM_CTRL_RST_FIFO); + regmap_update_bits(map, PDM_CTRL, PDM_CTRL_RST_FIFO, 0); + + /* Enable PDM */ + regmap_update_bits(map, PDM_CTRL, PDM_CTRL_EN, PDM_CTRL_EN); +} + +static void axg_pdm_disable(struct regmap *map) +{ + regmap_update_bits(map, PDM_CTRL, PDM_CTRL_EN, 0); +} + +static void axg_pdm_filters_enable(struct regmap *map, bool enable) +{ + unsigned int val = enable ? PDM_FILTER_EN : 0; + + regmap_update_bits(map, PDM_HCIC_CTRL1, PDM_FILTER_EN, val); + regmap_update_bits(map, PDM_F1_CTRL, PDM_FILTER_EN, val); + regmap_update_bits(map, PDM_F2_CTRL, PDM_FILTER_EN, val); + regmap_update_bits(map, PDM_F3_CTRL, PDM_FILTER_EN, val); + regmap_update_bits(map, PDM_HPF_CTRL, PDM_FILTER_EN, val); +} + +static int axg_pdm_trigger(struct snd_pcm_substream *substream, int cmd, + struct snd_soc_dai *dai) +{ + struct axg_pdm *priv = snd_soc_dai_get_drvdata(dai); + + switch (cmd) { + case SNDRV_PCM_TRIGGER_START: + case SNDRV_PCM_TRIGGER_RESUME: + case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: + axg_pdm_enable(priv->map); + return 0; + + case SNDRV_PCM_TRIGGER_STOP: + case SNDRV_PCM_TRIGGER_SUSPEND: + case SNDRV_PCM_TRIGGER_PAUSE_PUSH: + axg_pdm_disable(priv->map); + return 0; + + default: + return -EINVAL; + } +} + +static unsigned int axg_pdm_get_os(struct axg_pdm *priv) +{ + const struct axg_pdm_filters *filters = priv->cfg->filters; + unsigned int os = filters->hcic.ds; + int i; + + /* + * The global oversampling factor is defined by the down sampling + * factor applied by each filter (HCIC and LPFs) + */ + + for (i = 0; i < PDM_LPF_NUM; i++) + os *= filters->lpf[i].ds; + + return os; +} + +static int axg_pdm_set_sysclk(struct axg_pdm *priv, unsigned int os, + unsigned int rate) +{ + unsigned int sys_rate = os * 2 * rate * PDM_CHAN_CTRL_POINTER_MAX; + + /* + * Set the default system clock rate unless it is too fast for + * for the requested sample rate. In this case, the sample pointer + * counter could overflow so set a lower system clock rate + */ + if (sys_rate < priv->cfg->sys_rate) + return clk_set_rate(priv->sysclk, sys_rate); + + return clk_set_rate(priv->sysclk, priv->cfg->sys_rate); +} + +static int axg_pdm_set_sample_pointer(struct axg_pdm *priv) +{ + unsigned int spmax, sp, val; + int i; + + /* Max sample counter value per half period of dclk */ + spmax = DIV_ROUND_UP_ULL((u64)clk_get_rate(priv->sysclk), + clk_get_rate(priv->dclk) * 2); + + /* Check if sysclk is not too fast - should not happen */ + if (WARN_ON(spmax > PDM_CHAN_CTRL_POINTER_MAX)) + return -EINVAL; + + /* Capture the data when we are at 75% of the half period */ + sp = spmax * 3 / 4; + + for (i = 0, val = 0; i < PDM_CHAN_CTRL_NUM; i++) + val |= sp << (PDM_CHAN_CTRL_POINTER_WIDTH * i); + + regmap_write(priv->map, PDM_CHAN_CTRL, val); + regmap_write(priv->map, PDM_CHAN_CTRL1, val); + + return 0; +} + +static void axg_pdm_set_channel_mask(struct axg_pdm *priv, + unsigned int channels) +{ + unsigned int mask = GENMASK(channels - 1, 0); + + /* Put all channel in reset */ + regmap_update_bits(priv->map, PDM_CTRL, + PDM_CTRL_CHAN_RSTN_MASK, 0); + + /* Take the necessary channels out of reset and enable them */ + regmap_update_bits(priv->map, PDM_CTRL, + PDM_CTRL_CHAN_RSTN_MASK | + PDM_CTRL_CHAN_EN_MASK, + PDM_CTRL_CHAN_RSTN(mask) | + PDM_CTRL_CHAN_EN(mask)); +} + +static int axg_pdm_hw_params(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params, + struct snd_soc_dai *dai) +{ + struct axg_pdm *priv = snd_soc_dai_get_drvdata(dai); + unsigned int os = axg_pdm_get_os(priv); + unsigned int rate = params_rate(params); + unsigned int val; + int ret; + + switch (params_width(params)) { + case 24: + val = PDM_CTRL_OUT_MODE; + break; + case 32: + val = 0; + break; + default: + dev_err(dai->dev, "unsupported sample width\n"); + return -EINVAL; + } + + regmap_update_bits(priv->map, PDM_CTRL, PDM_CTRL_OUT_MODE, val); + + ret = axg_pdm_set_sysclk(priv, os, rate); + if (ret) { + dev_err(dai->dev, "failed to set system clock\n"); + return ret; + } + + ret = clk_set_rate(priv->dclk, rate * os); + if (ret) { + dev_err(dai->dev, "failed to set dclk\n"); + return ret; + } + + ret = axg_pdm_set_sample_pointer(priv); + if (ret) { + dev_err(dai->dev, "invalid clock setting\n"); + return ret; + } + + axg_pdm_set_channel_mask(priv, params_channels(params)); + + return 0; +} + +static int axg_pdm_startup(struct snd_pcm_substream *substream, + struct snd_soc_dai *dai) +{ + struct axg_pdm *priv = snd_soc_dai_get_drvdata(dai); + int ret; + + ret = clk_prepare_enable(priv->dclk); + if (ret) { + dev_err(dai->dev, "enabling dclk failed\n"); + return ret; + } + + /* Enable the filters */ + axg_pdm_filters_enable(priv->map, true); + + return ret; +} + +static void axg_pdm_shutdown(struct snd_pcm_substream *substream, + struct snd_soc_dai *dai) +{ + struct axg_pdm *priv = snd_soc_dai_get_drvdata(dai); + + axg_pdm_filters_enable(priv->map, false); + clk_disable_unprepare(priv->dclk); +} + +static const struct snd_soc_dai_ops axg_pdm_dai_ops = { + .trigger = axg_pdm_trigger, + .hw_params = axg_pdm_hw_params, + .startup = axg_pdm_startup, + .shutdown = axg_pdm_shutdown, +}; + +static void axg_pdm_set_hcic_ctrl(struct axg_pdm *priv) +{ + const struct axg_pdm_hcic *hcic = &priv->cfg->filters->hcic; + unsigned int val; + + val = PDM_HCIC_CTRL1_STAGE_NUM(hcic->steps); + val |= PDM_HCIC_CTRL1_DSR(hcic->ds); + val |= PDM_HCIC_CTRL1_GAIN_MULT(hcic->mult); + val |= PDM_HCIC_CTRL1_GAIN_SFT(hcic->shift); + + regmap_update_bits(priv->map, PDM_HCIC_CTRL1, + PDM_HCIC_CTRL1_STAGE_NUM_MASK | + PDM_HCIC_CTRL1_DSR_MASK | + PDM_HCIC_CTRL1_GAIN_MULT_MASK | + PDM_HCIC_CTRL1_GAIN_SFT_MASK, + val); +} + +static void axg_pdm_set_lpf_ctrl(struct axg_pdm *priv, unsigned int index) +{ + const struct axg_pdm_lpf *lpf = &priv->cfg->filters->lpf[index]; + unsigned int offset = index * regmap_get_reg_stride(priv->map) + + PDM_F1_CTRL; + unsigned int val; + + val = PDM_LPF_STAGE_NUM(lpf->tap_num); + val |= PDM_LPF_DSR(lpf->ds); + val |= PDM_LPF_ROUND_MODE(lpf->round_mode); + + regmap_update_bits(priv->map, offset, + PDM_LPF_STAGE_NUM_MASK | + PDM_LPF_DSR_MASK | + PDM_LPF_ROUND_MODE_MASK, + val); +} + +static void axg_pdm_set_hpf_ctrl(struct axg_pdm *priv) +{ + const struct axg_pdm_hpf *hpf = &priv->cfg->filters->hpf; + unsigned int val; + + val = PDM_HPF_OUT_FACTOR(hpf->out_factor); + val |= PDM_HPF_SFT_STEPS(hpf->steps); + + regmap_update_bits(priv->map, PDM_HPF_CTRL, + PDM_HPF_OUT_FACTOR_MASK | + PDM_HPF_SFT_STEPS_MASK, + val); +} + +static int axg_pdm_set_lpf_filters(struct axg_pdm *priv) +{ + const struct axg_pdm_lpf *lpf = priv->cfg->filters->lpf; + unsigned int count = 0; + int i, j; + + for (i = 0; i < PDM_LPF_NUM; i++) + count += lpf[i].tap_num; + + /* Make sure the coeffs fit in the memory */ + if (count >= PDM_LPF_MAX_STAGE) + return -EINVAL; + + /* Set the initial APB bus register address */ + regmap_write(priv->map, PDM_COEFF_ADDR, 0); + + /* Set the tap filter values of all 3 filters */ + for (i = 0; i < PDM_LPF_NUM; i++) { + axg_pdm_set_lpf_ctrl(priv, i); + + for (j = 0; j < lpf[i].tap_num; j++) + regmap_write(priv->map, PDM_COEFF_DATA, lpf[i].tap[j]); + } + + return 0; +} + +static int axg_pdm_dai_probe(struct snd_soc_dai *dai) +{ + struct axg_pdm *priv = snd_soc_dai_get_drvdata(dai); + int ret; + + ret = clk_prepare_enable(priv->pclk); + if (ret) { + dev_err(dai->dev, "enabling pclk failed\n"); + return ret; + } + + /* + * sysclk must be set and enabled as well to access the pdm registers + * Accessing the register w/o it will give a bus error. + */ + ret = clk_set_rate(priv->sysclk, priv->cfg->sys_rate); + if (ret) { + dev_err(dai->dev, "setting sysclk failed\n"); + goto err_pclk; + } + + ret = clk_prepare_enable(priv->sysclk); + if (ret) { + dev_err(dai->dev, "enabling sysclk failed\n"); + goto err_pclk; + } + + /* Make sure the device is initially disabled */ + axg_pdm_disable(priv->map); + + /* Make sure filter bypass is disabled */ + regmap_update_bits(priv->map, PDM_CTRL, PDM_CTRL_BYPASS_MODE, 0); + + /* Load filter settings */ + axg_pdm_set_hcic_ctrl(priv); + axg_pdm_set_hpf_ctrl(priv); + + ret = axg_pdm_set_lpf_filters(priv); + if (ret) { + dev_err(dai->dev, "invalid filter configuration\n"); + goto err_sysclk; + } + + return 0; + +err_sysclk: + clk_disable_unprepare(priv->sysclk); +err_pclk: + clk_disable_unprepare(priv->pclk); + return ret; +} + +static int axg_pdm_dai_remove(struct snd_soc_dai *dai) +{ + struct axg_pdm *priv = snd_soc_dai_get_drvdata(dai); + + clk_disable_unprepare(priv->sysclk); + clk_disable_unprepare(priv->pclk); + + return 0; +} + +static struct snd_soc_dai_driver axg_pdm_dai_drv = { + .name = "PDM", + .capture = { + .stream_name = "Capture", + .channels_min = 1, + .channels_max = 8, + .rates = SNDRV_PCM_RATE_CONTINUOUS, + .rate_min = 5512, + .rate_max = 48000, + .formats = (SNDRV_PCM_FMTBIT_S24_LE | + SNDRV_PCM_FMTBIT_S32_LE), + }, + .ops = &axg_pdm_dai_ops, + .probe = axg_pdm_dai_probe, + .remove = axg_pdm_dai_remove, +}; + +static const struct snd_soc_component_driver axg_pdm_component_drv = {}; + +static const struct regmap_config axg_pdm_regmap_cfg = { + .reg_bits = 32, + .val_bits = 32, + .reg_stride = 4, + .max_register = PDM_STS, +}; + +static const unsigned int lpf1_default_tap[] = { + 0x000014, 0xffffb2, 0xfffed9, 0xfffdce, 0xfffd45, + 0xfffe32, 0x000147, 0x000645, 0x000b86, 0x000e21, + 0x000ae3, 0x000000, 0xffeece, 0xffdca8, 0xffd212, + 0xffd7d1, 0xfff2a7, 0x001f4c, 0x0050c2, 0x0072aa, + 0x006ff1, 0x003c32, 0xffdc4e, 0xff6a18, 0xff0fef, + 0xfefbaf, 0xff4c40, 0x000000, 0x00ebc8, 0x01c077, + 0x02209e, 0x01c1a4, 0x008e60, 0xfebe52, 0xfcd690, + 0xfb8fa5, 0xfba498, 0xfd9812, 0x0181ce, 0x06f5f3, + 0x0d112f, 0x12a958, 0x169686, 0x18000e, 0x169686, + 0x12a958, 0x0d112f, 0x06f5f3, 0x0181ce, 0xfd9812, + 0xfba498, 0xfb8fa5, 0xfcd690, 0xfebe52, 0x008e60, + 0x01c1a4, 0x02209e, 0x01c077, 0x00ebc8, 0x000000, + 0xff4c40, 0xfefbaf, 0xff0fef, 0xff6a18, 0xffdc4e, + 0x003c32, 0x006ff1, 0x0072aa, 0x0050c2, 0x001f4c, + 0xfff2a7, 0xffd7d1, 0xffd212, 0xffdca8, 0xffeece, + 0x000000, 0x000ae3, 0x000e21, 0x000b86, 0x000645, + 0x000147, 0xfffe32, 0xfffd45, 0xfffdce, 0xfffed9, + 0xffffb2, 0x000014, +}; + +static const unsigned int lpf2_default_tap[] = { + 0x00050a, 0xfff004, 0x0002c1, 0x003c12, 0xffa818, + 0xffc87d, 0x010aef, 0xff5223, 0xfebd93, 0x028f41, + 0xff5c0e, 0xfc63f8, 0x055f81, 0x000000, 0xf478a0, + 0x11c5e3, 0x2ea74d, 0x11c5e3, 0xf478a0, 0x000000, + 0x055f81, 0xfc63f8, 0xff5c0e, 0x028f41, 0xfebd93, + 0xff5223, 0x010aef, 0xffc87d, 0xffa818, 0x003c12, + 0x0002c1, 0xfff004, 0x00050a, +}; + +static const unsigned int lpf3_default_tap[] = { + 0x000000, 0x000081, 0x000000, 0xfffedb, 0x000000, + 0x00022d, 0x000000, 0xfffc46, 0x000000, 0x0005f7, + 0x000000, 0xfff6eb, 0x000000, 0x000d4e, 0x000000, + 0xffed1e, 0x000000, 0x001a1c, 0x000000, 0xffdcb0, + 0x000000, 0x002ede, 0x000000, 0xffc2d1, 0x000000, + 0x004ebe, 0x000000, 0xff9beb, 0x000000, 0x007dd7, + 0x000000, 0xff633a, 0x000000, 0x00c1d2, 0x000000, + 0xff11d5, 0x000000, 0x012368, 0x000000, 0xfe9c45, + 0x000000, 0x01b252, 0x000000, 0xfdebf6, 0x000000, + 0x0290b8, 0x000000, 0xfcca0d, 0x000000, 0x041d7c, + 0x000000, 0xfa8152, 0x000000, 0x07e9c6, 0x000000, + 0xf28fb5, 0x000000, 0x28b216, 0x3fffde, 0x28b216, + 0x000000, 0xf28fb5, 0x000000, 0x07e9c6, 0x000000, + 0xfa8152, 0x000000, 0x041d7c, 0x000000, 0xfcca0d, + 0x000000, 0x0290b8, 0x000000, 0xfdebf6, 0x000000, + 0x01b252, 0x000000, 0xfe9c45, 0x000000, 0x012368, + 0x000000, 0xff11d5, 0x000000, 0x00c1d2, 0x000000, + 0xff633a, 0x000000, 0x007dd7, 0x000000, 0xff9beb, + 0x000000, 0x004ebe, 0x000000, 0xffc2d1, 0x000000, + 0x002ede, 0x000000, 0xffdcb0, 0x000000, 0x001a1c, + 0x000000, 0xffed1e, 0x000000, 0x000d4e, 0x000000, + 0xfff6eb, 0x000000, 0x0005f7, 0x000000, 0xfffc46, + 0x000000, 0x00022d, 0x000000, 0xfffedb, 0x000000, + 0x000081, 0x000000, +}; + +/* + * These values are sane defaults for the axg platform: + * - OS = 64 + * - Latency = 38700 (?) + * + * TODO: There is a lot of different HCIC, LPFs and HPF configurations possible. + * the configuration may depend on the dmic used by the platform, the + * expected tradeoff between latency and quality, etc ... If/When other + * settings are required, we should add a fw interface to this driver to + * load new filter settings. + */ +static const struct axg_pdm_filters axg_default_filters = { + .hcic = { + .shift = 0x15, + .mult = 0x80, + .steps = 7, + .ds = 8, + }, + .hpf = { + .out_factor = 0x8000, + .steps = 13, + }, + .lpf = { + [0] = { + .ds = 2, + .round_mode = 1, + .tap = lpf1_default_tap, + .tap_num = ARRAY_SIZE(lpf1_default_tap), + }, + [1] = { + .ds = 2, + .round_mode = 0, + .tap = lpf2_default_tap, + .tap_num = ARRAY_SIZE(lpf2_default_tap), + }, + [2] = { + .ds = 2, + .round_mode = 1, + .tap = lpf3_default_tap, + .tap_num = ARRAY_SIZE(lpf3_default_tap) + }, + }, +}; + +static const struct axg_pdm_cfg axg_pdm_config = { + .filters = &axg_default_filters, + .sys_rate = 250000000, +}; + +static const struct of_device_id axg_pdm_of_match[] = { + { + .compatible = "amlogic,axg-pdm", + .data = &axg_pdm_config, + }, {} +}; +MODULE_DEVICE_TABLE(of, axg_pdm_of_match); + +static int axg_pdm_probe(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + struct axg_pdm *priv; + struct resource *res; + void __iomem *regs; + int ret; + + priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL); + if (!priv) + return -ENOMEM; + platform_set_drvdata(pdev, priv); + + priv->cfg = of_device_get_match_data(dev); + if (!priv->cfg) { + dev_err(dev, "failed to match device\n"); + return -ENODEV; + } + + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + regs = devm_ioremap_resource(dev, res); + if (IS_ERR(regs)) + return PTR_ERR(regs); + + priv->map = devm_regmap_init_mmio(dev, regs, &axg_pdm_regmap_cfg); + if (IS_ERR(priv->map)) { + dev_err(dev, "failed to init regmap: %ld\n", + PTR_ERR(priv->map)); + return PTR_ERR(priv->map); + } + + priv->pclk = devm_clk_get(dev, "pclk"); + if (IS_ERR(priv->pclk)) { + ret = PTR_ERR(priv->pclk); + if (ret != -EPROBE_DEFER) + dev_err(dev, "failed to get pclk: %d\n", ret); + return ret; + } + + priv->dclk = devm_clk_get(dev, "dclk"); + if (IS_ERR(priv->dclk)) { + ret = PTR_ERR(priv->dclk); + if (ret != -EPROBE_DEFER) + dev_err(dev, "failed to get dclk: %d\n", ret); + return ret; + } + + priv->sysclk = devm_clk_get(dev, "sysclk"); + if (IS_ERR(priv->sysclk)) { + ret = PTR_ERR(priv->sysclk); + if (ret != -EPROBE_DEFER) + dev_err(dev, "failed to get dclk: %d\n", ret); + return ret; + } + + return devm_snd_soc_register_component(dev, &axg_pdm_component_drv, + &axg_pdm_dai_drv, 1); +} + +static struct platform_driver axg_pdm_pdrv = { + .probe = axg_pdm_probe, + .driver = { + .name = "axg-pdm", + .of_match_table = axg_pdm_of_match, + }, +}; +module_platform_driver(axg_pdm_pdrv); + +MODULE_DESCRIPTION("Amlogic AXG PDM Input driver"); +MODULE_AUTHOR("Jerome Brunet "); +MODULE_LICENSE("GPL v2"); From 3a182c848946584a241b4ae220359888bb2f5936 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Thu, 30 Aug 2018 07:58:50 +0200 Subject: [PATCH 045/299] ALSA: hda - Clean up jackpoll_ms option handling Currently the jackpoll_ms option value is passed indirectly by referring to an array in chip->jackpoll_ms although each card needs to see only the assigned value. Also, the sanity check is done at each time in get_jackpoll_interval() although basically jackpoll_ms option is a read-only, hence we need to evaluate only once at probe time. This patch is the code simplification about the above points: the jack polling interval is directly set to chip->jackpoll_interval so that it can be simply copied to each codec. No functional change but only code reduction. Signed-off-by: Takashi Iwai --- sound/pci/hda/hda_controller.c | 23 +---------------------- sound/pci/hda/hda_controller.h | 2 +- sound/pci/hda/hda_intel.c | 3 ++- 3 files changed, 4 insertions(+), 24 deletions(-) diff --git a/sound/pci/hda/hda_controller.c b/sound/pci/hda/hda_controller.c index 53bdf76fcbba..fe2506672a72 100644 --- a/sound/pci/hda/hda_controller.c +++ b/sound/pci/hda/hda_controller.c @@ -1223,27 +1223,6 @@ void snd_hda_bus_reset(struct hda_bus *bus) bus->in_reset = 0; } -static int get_jackpoll_interval(struct azx *chip) -{ - int i; - unsigned int j; - - if (!chip->jackpoll_ms) - return 0; - - i = chip->jackpoll_ms[chip->dev_index]; - if (i == 0) - return 0; - if (i < 50 || i > 60000) - j = 0; - else - j = msecs_to_jiffies(i); - if (j == 0) - dev_warn(chip->card->dev, - "jackpoll_ms value out of range: %d\n", i); - return j; -} - /* HD-audio bus initialization */ int azx_bus_init(struct azx *chip, const char *model, const struct hdac_io_ops *io_ops) @@ -1326,7 +1305,7 @@ int azx_probe_codecs(struct azx *chip, unsigned int max_slots) err = snd_hda_codec_new(&chip->bus, chip->card, c, &codec); if (err < 0) continue; - codec->jackpoll_interval = get_jackpoll_interval(chip); + codec->jackpoll_interval = chip->jackpoll_interval; codec->beep_mode = chip->beep_mode; codecs++; } diff --git a/sound/pci/hda/hda_controller.h b/sound/pci/hda/hda_controller.h index 3c9a2f81cfbf..33b99839753d 100644 --- a/sound/pci/hda/hda_controller.h +++ b/sound/pci/hda/hda_controller.h @@ -121,7 +121,7 @@ struct azx { int capture_streams; int capture_index_offset; int num_streams; - const int *jackpoll_ms; /* per-card jack poll interval */ + int jackpoll_interval; /* jack poll interval in jiffies */ /* Register interaction. */ const struct hda_controller_ops *ops; diff --git a/sound/pci/hda/hda_intel.c b/sound/pci/hda/hda_intel.c index 0a3ce9c60f50..12647de19381 100644 --- a/sound/pci/hda/hda_intel.c +++ b/sound/pci/hda/hda_intel.c @@ -1676,7 +1676,8 @@ static int azx_create(struct snd_card *card, struct pci_dev *pci, chip->driver_type = driver_caps & 0xff; check_msi(chip); chip->dev_index = dev; - chip->jackpoll_ms = jackpoll_ms; + if (jackpoll_ms[dev] >= 50 && jackpoll_ms[dev] <= 60000) + chip->jackpoll_interval = msecs_to_jiffies(jackpoll_ms[dev]); INIT_LIST_HEAD(&chip->pcm_list); INIT_WORK(&hda->irq_pending_work, azx_irq_pending_work); INIT_LIST_HEAD(&hda->list); From be57bfffb7b5ba72e1293643053f8861fcaa5163 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Wed, 22 Aug 2018 15:24:57 -0500 Subject: [PATCH 046/299] ALSA: hda: move hda_codec.h to include/sound As suggested by Takashi, move this header file to make it easier to include from e.g. the Intel Skylake driver in follow-up patches Signed-off-by: Pierre-Louis Bossart Signed-off-by: Mark Brown --- {sound/pci/hda => include/sound}/hda_codec.h | 0 sound/pci/hda/hda_auto_parser.c | 2 +- sound/pci/hda/hda_beep.h | 2 +- sound/pci/hda/hda_bind.c | 2 +- sound/pci/hda/hda_codec.c | 2 +- sound/pci/hda/hda_controller.h | 2 +- sound/pci/hda/hda_eld.c | 2 +- sound/pci/hda/hda_generic.c | 2 +- sound/pci/hda/hda_hwdep.c | 2 +- sound/pci/hda/hda_intel.c | 2 +- sound/pci/hda/hda_jack.c | 2 +- sound/pci/hda/hda_proc.c | 2 +- sound/pci/hda/hda_sysfs.c | 2 +- sound/pci/hda/hda_tegra.c | 2 +- sound/pci/hda/patch_analog.c | 2 +- sound/pci/hda/patch_ca0110.c | 2 +- sound/pci/hda/patch_ca0132.c | 2 +- sound/pci/hda/patch_cirrus.c | 2 +- sound/pci/hda/patch_cmedia.c | 2 +- sound/pci/hda/patch_conexant.c | 2 +- sound/pci/hda/patch_hdmi.c | 2 +- sound/pci/hda/patch_realtek.c | 2 +- sound/pci/hda/patch_si3054.c | 2 +- sound/pci/hda/patch_sigmatel.c | 2 +- sound/pci/hda/patch_via.c | 2 +- 25 files changed, 24 insertions(+), 24 deletions(-) rename {sound/pci/hda => include/sound}/hda_codec.h (100%) diff --git a/sound/pci/hda/hda_codec.h b/include/sound/hda_codec.h similarity index 100% rename from sound/pci/hda/hda_codec.h rename to include/sound/hda_codec.h diff --git a/sound/pci/hda/hda_auto_parser.c b/sound/pci/hda/hda_auto_parser.c index b9a6b66aeb0e..df0d636145f8 100644 --- a/sound/pci/hda/hda_auto_parser.c +++ b/sound/pci/hda/hda_auto_parser.c @@ -13,7 +13,7 @@ #include #include #include -#include "hda_codec.h" +#include #include "hda_local.h" #include "hda_auto_parser.h" diff --git a/sound/pci/hda/hda_beep.h b/sound/pci/hda/hda_beep.h index d1a6a9c1329a..f1457c6b3969 100644 --- a/sound/pci/hda/hda_beep.h +++ b/sound/pci/hda/hda_beep.h @@ -9,7 +9,7 @@ #ifndef __SOUND_HDA_BEEP_H #define __SOUND_HDA_BEEP_H -#include "hda_codec.h" +#include #define HDA_BEEP_MODE_OFF 0 #define HDA_BEEP_MODE_ON 1 diff --git a/sound/pci/hda/hda_bind.c b/sound/pci/hda/hda_bind.c index d361bb77ca00..2222b47d4ec4 100644 --- a/sound/pci/hda/hda_bind.c +++ b/sound/pci/hda/hda_bind.c @@ -11,7 +11,7 @@ #include #include #include -#include "hda_codec.h" +#include #include "hda_local.h" /* diff --git a/sound/pci/hda/hda_codec.c b/sound/pci/hda/hda_codec.c index 0a5085537034..ccbb0d12b8cc 100644 --- a/sound/pci/hda/hda_codec.c +++ b/sound/pci/hda/hda_codec.c @@ -27,7 +27,7 @@ #include #include #include -#include "hda_codec.h" +#include #include #include #include diff --git a/sound/pci/hda/hda_controller.h b/sound/pci/hda/hda_controller.h index a68e75b00ea3..55760e5231e6 100644 --- a/sound/pci/hda/hda_controller.h +++ b/sound/pci/hda/hda_controller.h @@ -20,7 +20,7 @@ #include #include #include -#include "hda_codec.h" +#include #include #define AZX_MAX_CODECS HDA_MAX_CODECS diff --git a/sound/pci/hda/hda_eld.c b/sound/pci/hda/hda_eld.c index ba7fe9b6655c..806b12ed44a2 100644 --- a/sound/pci/hda/hda_eld.c +++ b/sound/pci/hda/hda_eld.c @@ -27,7 +27,7 @@ #include #include #include -#include "hda_codec.h" +#include #include "hda_local.h" enum eld_versions { diff --git a/sound/pci/hda/hda_generic.c b/sound/pci/hda/hda_generic.c index 579984ecdec3..276150f29cda 100644 --- a/sound/pci/hda/hda_generic.c +++ b/sound/pci/hda/hda_generic.c @@ -32,7 +32,7 @@ #include #include #include -#include "hda_codec.h" +#include #include "hda_local.h" #include "hda_auto_parser.h" #include "hda_jack.h" diff --git a/sound/pci/hda/hda_hwdep.c b/sound/pci/hda/hda_hwdep.c index cc009a4a3d1d..268bba6ec985 100644 --- a/sound/pci/hda/hda_hwdep.c +++ b/sound/pci/hda/hda_hwdep.c @@ -23,7 +23,7 @@ #include #include #include -#include "hda_codec.h" +#include #include "hda_local.h" #include #include diff --git a/sound/pci/hda/hda_intel.c b/sound/pci/hda/hda_intel.c index 1b2ce304152a..c8fde95e2393 100644 --- a/sound/pci/hda/hda_intel.c +++ b/sound/pci/hda/hda_intel.c @@ -63,7 +63,7 @@ #include #include #include -#include "hda_codec.h" +#include #include "hda_controller.h" #include "hda_intel.h" diff --git a/sound/pci/hda/hda_jack.c b/sound/pci/hda/hda_jack.c index a33234e04d4f..c499727920e6 100644 --- a/sound/pci/hda/hda_jack.c +++ b/sound/pci/hda/hda_jack.c @@ -15,7 +15,7 @@ #include #include #include -#include "hda_codec.h" +#include #include "hda_local.h" #include "hda_auto_parser.h" #include "hda_jack.h" diff --git a/sound/pci/hda/hda_proc.c b/sound/pci/hda/hda_proc.c index c6b778b2580c..a65740419650 100644 --- a/sound/pci/hda/hda_proc.c +++ b/sound/pci/hda/hda_proc.c @@ -25,7 +25,7 @@ #include #include #include -#include "hda_codec.h" +#include #include "hda_local.h" static int dump_coef = -1; diff --git a/sound/pci/hda/hda_sysfs.c b/sound/pci/hda/hda_sysfs.c index 6ec79c58d48d..c154b19a0c45 100644 --- a/sound/pci/hda/hda_sysfs.c +++ b/sound/pci/hda/hda_sysfs.c @@ -14,7 +14,7 @@ #include #include #include -#include "hda_codec.h" +#include #include "hda_local.h" #include #include diff --git a/sound/pci/hda/hda_tegra.c b/sound/pci/hda/hda_tegra.c index 0621920f7617..4bc5232eac1c 100644 --- a/sound/pci/hda/hda_tegra.c +++ b/sound/pci/hda/hda_tegra.c @@ -35,7 +35,7 @@ #include #include -#include "hda_codec.h" +#include #include "hda_controller.h" /* Defines for Nvidia Tegra HDA support */ diff --git a/sound/pci/hda/patch_analog.c b/sound/pci/hda/patch_analog.c index fd476fb40e1b..ebfd0be885b3 100644 --- a/sound/pci/hda/patch_analog.c +++ b/sound/pci/hda/patch_analog.c @@ -24,7 +24,7 @@ #include #include -#include "hda_codec.h" +#include #include "hda_local.h" #include "hda_auto_parser.h" #include "hda_beep.h" diff --git a/sound/pci/hda/patch_ca0110.c b/sound/pci/hda/patch_ca0110.c index c2d9ee9cfdc0..21d0f0610913 100644 --- a/sound/pci/hda/patch_ca0110.c +++ b/sound/pci/hda/patch_ca0110.c @@ -22,7 +22,7 @@ #include #include #include -#include "hda_codec.h" +#include #include "hda_local.h" #include "hda_auto_parser.h" #include "hda_jack.h" diff --git a/sound/pci/hda/patch_ca0132.c b/sound/pci/hda/patch_ca0132.c index 0166a3d7cd55..a585d0ec6d77 100644 --- a/sound/pci/hda/patch_ca0132.c +++ b/sound/pci/hda/patch_ca0132.c @@ -32,7 +32,7 @@ #include #include #include -#include "hda_codec.h" +#include #include "hda_local.h" #include "hda_auto_parser.h" #include "hda_jack.h" diff --git a/sound/pci/hda/patch_cirrus.c b/sound/pci/hda/patch_cirrus.c index a7f91be45194..64fa5a82bb9f 100644 --- a/sound/pci/hda/patch_cirrus.c +++ b/sound/pci/hda/patch_cirrus.c @@ -23,7 +23,7 @@ #include #include #include -#include "hda_codec.h" +#include #include "hda_local.h" #include "hda_auto_parser.h" #include "hda_jack.h" diff --git a/sound/pci/hda/patch_cmedia.c b/sound/pci/hda/patch_cmedia.c index 1b2195dd2b26..52642ba3e2c0 100644 --- a/sound/pci/hda/patch_cmedia.c +++ b/sound/pci/hda/patch_cmedia.c @@ -25,7 +25,7 @@ #include #include #include -#include "hda_codec.h" +#include #include "hda_local.h" #include "hda_auto_parser.h" #include "hda_jack.h" diff --git a/sound/pci/hda/patch_conexant.c b/sound/pci/hda/patch_conexant.c index cfd4e4f97f8f..5592557fe50e 100644 --- a/sound/pci/hda/patch_conexant.c +++ b/sound/pci/hda/patch_conexant.c @@ -27,7 +27,7 @@ #include #include -#include "hda_codec.h" +#include #include "hda_local.h" #include "hda_auto_parser.h" #include "hda_beep.h" diff --git a/sound/pci/hda/patch_hdmi.c b/sound/pci/hda/patch_hdmi.c index cb587dce67a9..67099cbb6be2 100644 --- a/sound/pci/hda/patch_hdmi.c +++ b/sound/pci/hda/patch_hdmi.c @@ -41,7 +41,7 @@ #include #include #include -#include "hda_codec.h" +#include #include "hda_local.h" #include "hda_jack.h" diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c index 1d117f00d04d..6f3c8e888c2a 100644 --- a/sound/pci/hda/patch_realtek.c +++ b/sound/pci/hda/patch_realtek.c @@ -32,7 +32,7 @@ #include #include #include -#include "hda_codec.h" +#include #include "hda_local.h" #include "hda_auto_parser.h" #include "hda_jack.h" diff --git a/sound/pci/hda/patch_si3054.c b/sound/pci/hda/patch_si3054.c index f63acb1b965c..c49d25bcd7f2 100644 --- a/sound/pci/hda/patch_si3054.c +++ b/sound/pci/hda/patch_si3054.c @@ -27,7 +27,7 @@ #include #include #include -#include "hda_codec.h" +#include #include "hda_local.h" /* si3054 verbs */ diff --git a/sound/pci/hda/patch_sigmatel.c b/sound/pci/hda/patch_sigmatel.c index 046705b4691a..d16a25a395c9 100644 --- a/sound/pci/hda/patch_sigmatel.c +++ b/sound/pci/hda/patch_sigmatel.c @@ -32,7 +32,7 @@ #include #include #include -#include "hda_codec.h" +#include #include "hda_local.h" #include "hda_auto_parser.h" #include "hda_beep.h" diff --git a/sound/pci/hda/patch_via.c b/sound/pci/hda/patch_via.c index 6b9617aee0e6..9f6f13e25145 100644 --- a/sound/pci/hda/patch_via.c +++ b/sound/pci/hda/patch_via.c @@ -52,7 +52,7 @@ #include #include #include -#include "hda_codec.h" +#include #include "hda_local.h" #include "hda_auto_parser.h" #include "hda_jack.h" From 5fcb457ac2fdc62c5ff6d3962c958b1301bc5ea1 Mon Sep 17 00:00:00 2001 From: Peter Ujfalusi Date: Fri, 31 Aug 2018 11:24:56 +0300 Subject: [PATCH 047/299] ASoC: davinci-mcasp: Add support for FIFO usage caused delay reporting McASP have write and read FIFO, each 64 words deep. From the WFIFOS/RFIFOS registers we can read the amount of data currently in the FIFO which can be directly reported as delay. Signed-off-by: Peter Ujfalusi Signed-off-by: Mark Brown --- sound/soc/davinci/davinci-mcasp.c | 37 +++++++++++++++++++++++++++++++ 1 file changed, 37 insertions(+) diff --git a/sound/soc/davinci/davinci-mcasp.c b/sound/soc/davinci/davinci-mcasp.c index f70db8412c7c..267aee776b2d 100644 --- a/sound/soc/davinci/davinci-mcasp.c +++ b/sound/soc/davinci/davinci-mcasp.c @@ -1041,6 +1041,42 @@ static int davinci_mcasp_calc_clk_div(struct davinci_mcasp *mcasp, return error_ppm; } +static inline u32 davinci_mcasp_tx_delay(struct davinci_mcasp *mcasp) +{ + if (!mcasp->txnumevt) + return 0; + + return mcasp_get_reg(mcasp, mcasp->fifo_base + MCASP_WFIFOSTS_OFFSET); +} + +static inline u32 davinci_mcasp_rx_delay(struct davinci_mcasp *mcasp) +{ + if (!mcasp->rxnumevt) + return 0; + + return mcasp_get_reg(mcasp, mcasp->fifo_base + MCASP_RFIFOSTS_OFFSET); +} + +static snd_pcm_sframes_t davinci_mcasp_delay( + struct snd_pcm_substream *substream, + struct snd_soc_dai *cpu_dai) +{ + struct davinci_mcasp *mcasp = snd_soc_dai_get_drvdata(cpu_dai); + u32 fifo_use; + + if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) + fifo_use = davinci_mcasp_tx_delay(mcasp); + else + fifo_use = davinci_mcasp_rx_delay(mcasp); + + /* + * Divide the used locations with the channel count to get the + * FIFO usage in samples (don't care about partial samples in the + * buffer). + */ + return fifo_use / substream->runtime->channels; +} + static int davinci_mcasp_hw_params(struct snd_pcm_substream *substream, struct snd_pcm_hw_params *params, struct snd_soc_dai *cpu_dai) @@ -1365,6 +1401,7 @@ static const struct snd_soc_dai_ops davinci_mcasp_dai_ops = { .startup = davinci_mcasp_startup, .shutdown = davinci_mcasp_shutdown, .trigger = davinci_mcasp_trigger, + .delay = davinci_mcasp_delay, .hw_params = davinci_mcasp_hw_params, .set_fmt = davinci_mcasp_set_dai_fmt, .set_clkdiv = davinci_mcasp_set_clkdiv, From ec94c177bf3700ce44c53c375a3fb4c347f2b08f Mon Sep 17 00:00:00 2001 From: Andreas Dannenberg Date: Fri, 31 Aug 2018 09:47:13 -0500 Subject: [PATCH 048/299] ASoC: codecs: tas5720: add TAS5722 specific volume control The TAS5722 supports modifying volume in 0.25dB steps (as opposed to 0.5dB steps on the TAS5720). Introduce a custom mixer control that allows taking advantage of this finer output volume granularity. Also add custom getters/setters for access as the TAS5722 digital volume controls are split over two registers. Signed-off-by: Andreas Dannenberg Signed-off-by: Andrew F. Davis Signed-off-by: Mark Brown --- sound/soc/codecs/tas5720.c | 88 ++++++++++++++++++++++++++++++++++---- 1 file changed, 80 insertions(+), 8 deletions(-) diff --git a/sound/soc/codecs/tas5720.c b/sound/soc/codecs/tas5720.c index ae3d032ac35a..3c469112477a 100644 --- a/sound/soc/codecs/tas5720.c +++ b/sound/soc/codecs/tas5720.c @@ -485,15 +485,56 @@ static const DECLARE_TLV_DB_RANGE(dac_analog_tlv, ); /* - * DAC digital volumes. From -103.5 to 24 dB in 0.5 dB steps. Note that - * setting the gain below -100 dB (register value <0x7) is effectively a MUTE - * as per device datasheet. + * DAC digital volumes. From -103.5 to 24 dB in 0.5 dB or 0.25 dB steps + * depending on the device. Note that setting the gain below -100 dB + * (register value <0x7) is effectively a MUTE as per device datasheet. + * + * Note that for the TAS5722 the digital volume controls are actually split + * over two registers, so we need custom getters/setters for access. */ -static DECLARE_TLV_DB_SCALE(dac_tlv, -10350, 50, 0); +static DECLARE_TLV_DB_SCALE(tas5720_dac_tlv, -10350, 50, 0); +static DECLARE_TLV_DB_SCALE(tas5722_dac_tlv, -10350, 25, 0); + +static int tas5722_volume_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol); + unsigned int val; + + snd_soc_component_read(component, TAS5720_VOLUME_CTRL_REG, &val); + ucontrol->value.integer.value[0] = val << 1; + + snd_soc_component_read(component, TAS5722_DIGITAL_CTRL2_REG, &val); + ucontrol->value.integer.value[0] |= val & TAS5722_VOL_CONTROL_LSB; + + return 0; +} + +static int tas5722_volume_set(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol); + unsigned int sel = ucontrol->value.integer.value[0]; + + snd_soc_component_write(component, TAS5720_VOLUME_CTRL_REG, sel >> 1); + snd_soc_component_update_bits(component, TAS5722_DIGITAL_CTRL2_REG, + TAS5722_VOL_CONTROL_LSB, sel); + + return 0; +} static const struct snd_kcontrol_new tas5720_snd_controls[] = { SOC_SINGLE_TLV("Speaker Driver Playback Volume", - TAS5720_VOLUME_CTRL_REG, 0, 0xff, 0, dac_tlv), + TAS5720_VOLUME_CTRL_REG, 0, 0xff, 0, tas5720_dac_tlv), + SOC_SINGLE_TLV("Speaker Driver Analog Gain", TAS5720_ANALOG_CTRL_REG, + TAS5720_ANALOG_GAIN_SHIFT, 3, 0, dac_analog_tlv), +}; + +static const struct snd_kcontrol_new tas5722_snd_controls[] = { + SOC_SINGLE_EXT_TLV("Speaker Driver Playback Volume", + 0, 0, 511, 0, + tas5722_volume_get, tas5722_volume_set, + tas5722_dac_tlv), SOC_SINGLE_TLV("Speaker Driver Analog Gain", TAS5720_ANALOG_CTRL_REG, TAS5720_ANALOG_GAIN_SHIFT, 3, 0, dac_analog_tlv), }; @@ -527,6 +568,23 @@ static const struct snd_soc_component_driver soc_component_dev_tas5720 = { .non_legacy_dai_naming = 1, }; +static const struct snd_soc_component_driver soc_component_dev_tas5722 = { + .probe = tas5720_codec_probe, + .remove = tas5720_codec_remove, + .suspend = tas5720_suspend, + .resume = tas5720_resume, + .controls = tas5722_snd_controls, + .num_controls = ARRAY_SIZE(tas5722_snd_controls), + .dapm_widgets = tas5720_dapm_widgets, + .num_dapm_widgets = ARRAY_SIZE(tas5720_dapm_widgets), + .dapm_routes = tas5720_audio_map, + .num_dapm_routes = ARRAY_SIZE(tas5720_audio_map), + .idle_bias_on = 1, + .use_pmdown_time = 1, + .endianness = 1, + .non_legacy_dai_naming = 1, +}; + /* PCM rates supported by the TAS5720 driver */ #define TAS5720_RATES (SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000 |\ SNDRV_PCM_RATE_88200 | SNDRV_PCM_RATE_96000) @@ -613,9 +671,23 @@ static int tas5720_probe(struct i2c_client *client, dev_set_drvdata(dev, data); - ret = devm_snd_soc_register_component(&client->dev, - &soc_component_dev_tas5720, - tas5720_dai, ARRAY_SIZE(tas5720_dai)); + switch (id->driver_data) { + case TAS5720: + ret = devm_snd_soc_register_component(&client->dev, + &soc_component_dev_tas5720, + tas5720_dai, + ARRAY_SIZE(tas5720_dai)); + break; + case TAS5722: + ret = devm_snd_soc_register_component(&client->dev, + &soc_component_dev_tas5722, + tas5720_dai, + ARRAY_SIZE(tas5720_dai)); + break; + default: + dev_err(dev, "unexpected private driver data\n"); + return -EINVAL; + } if (ret < 0) { dev_err(dev, "failed to register component: %d\n", ret); return ret; From db658f40cae33a9fddbd9ca5c35c6bbfbd593a82 Mon Sep 17 00:00:00 2001 From: Andreas Dannenberg Date: Fri, 31 Aug 2018 09:47:14 -0500 Subject: [PATCH 049/299] ASoC: codecs: tas5720: add TAS5722 TDM slot width setting support Unlike the TAS5720, the TAS5722 can be configured to utilize 16-bit wide slots in TDM mode. This can help easing audio clocking/frequency requirements. Signed-off-by: Andreas Dannenberg Signed-off-by: Andrew F. Davis Signed-off-by: Mark Brown --- sound/soc/codecs/tas5720.c | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/sound/soc/codecs/tas5720.c b/sound/soc/codecs/tas5720.c index 3c469112477a..6bd0e5d5347f 100644 --- a/sound/soc/codecs/tas5720.c +++ b/sound/soc/codecs/tas5720.c @@ -152,6 +152,7 @@ static int tas5720_set_dai_tdm_slot(struct snd_soc_dai *dai, int slots, int slot_width) { struct snd_soc_component *component = dai->component; + struct tas5720_data *tas5720 = snd_soc_component_get_drvdata(component); unsigned int first_slot; int ret; @@ -185,6 +186,20 @@ static int tas5720_set_dai_tdm_slot(struct snd_soc_dai *dai, if (ret < 0) goto error_snd_soc_component_update_bits; + /* Configure TDM slot width. This is only applicable to TAS5722. */ + switch (tas5720->devtype) { + case TAS5722: + ret = snd_soc_component_update_bits(component, TAS5722_DIGITAL_CTRL2_REG, + TAS5722_TDM_SLOT_16B, + slot_width == 16 ? + TAS5722_TDM_SLOT_16B : 0); + if (ret < 0) + goto error_snd_soc_component_update_bits; + break; + default: + break; + } + return 0; error_snd_soc_component_update_bits: From 6f18bcdaa24bae39c746b57b95af19ff3c41b17f Mon Sep 17 00:00:00 2001 From: Matt Flax Date: Thu, 30 Aug 2018 09:38:00 +1000 Subject: [PATCH 050/299] ASoC: cs4265: SOC_SINGLE register value error fix The cs4265 driver declares the "MMTLR Data Switch" register setting with a 0 register value rather then the 0x12 register (CS4265_SPDIF_CTL2). This incorrect value causes alsamixer to fault with the output : cannot load mixer controls: Input/output error This patch corrects the register value. alsamixer now runs. Signed-off-by: Matt Flax Signed-off-by: Mark Brown --- sound/soc/codecs/cs4265.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/sound/soc/codecs/cs4265.c b/sound/soc/codecs/cs4265.c index 275677de669f..15b4ae04870f 100644 --- a/sound/soc/codecs/cs4265.c +++ b/sound/soc/codecs/cs4265.c @@ -157,8 +157,7 @@ static const struct snd_kcontrol_new cs4265_snd_controls[] = { SOC_SINGLE("Validity Bit Control Switch", CS4265_SPDIF_CTL2, 3, 1, 0), SOC_ENUM("SPDIF Mono/Stereo", spdif_mono_stereo_enum), - SOC_SINGLE("MMTLR Data Switch", 0, - 1, 1, 0), + SOC_SINGLE("MMTLR Data Switch", CS4265_SPDIF_CTL2, 0, 1, 0), SOC_ENUM("Mono Channel Select", spdif_mono_select_enum), SND_SOC_BYTES("C Data Buffer", CS4265_C_DATA_BUFF, 24), }; From be47e75eb1419ffc1d9c26230963fd5fa3055097 Mon Sep 17 00:00:00 2001 From: Matt Flax Date: Thu, 30 Aug 2018 09:38:01 +1000 Subject: [PATCH 051/299] ASoC: cs4265: Add native 32bit I2S transport The cs4265 uses 32 bit transport on the I2S bus. This patch enables native 32 bit mode for machine drivers which use this sound card driver. Signed-off-by: Matt Flax Reviewed-by: Charles Keepax Signed-off-by: Mark Brown --- sound/soc/codecs/cs4265.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/sound/soc/codecs/cs4265.c b/sound/soc/codecs/cs4265.c index 15b4ae04870f..17d7e6f0dcdb 100644 --- a/sound/soc/codecs/cs4265.c +++ b/sound/soc/codecs/cs4265.c @@ -495,7 +495,8 @@ static int cs4265_set_bias_level(struct snd_soc_component *component, SNDRV_PCM_RATE_176400 | SNDRV_PCM_RATE_192000) #define CS4265_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_U16_LE | \ - SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_U24_LE) + SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_U24_LE | \ + SNDRV_PCM_FMTBIT_S32_LE | SNDRV_PCM_FMTBIT_U32_LE) static const struct snd_soc_dai_ops cs4265_ops = { .hw_params = cs4265_pcm_hw_params, From f853d6b3ba345297974d877d8ed0f4a91eaca739 Mon Sep 17 00:00:00 2001 From: Matt Flax Date: Thu, 30 Aug 2018 09:38:02 +1000 Subject: [PATCH 052/299] ASoC: cs4265: Add a S/PDIF enable switch This patch adds a S/PDIF enable switch as a SOC_SINGLE. Signed-off-by: Matt Flax Reviewed-by: Charles Keepax Signed-off-by: Mark Brown --- sound/soc/codecs/cs4265.c | 1 + 1 file changed, 1 insertion(+) diff --git a/sound/soc/codecs/cs4265.c b/sound/soc/codecs/cs4265.c index 17d7e6f0dcdb..d9eebf6af7a8 100644 --- a/sound/soc/codecs/cs4265.c +++ b/sound/soc/codecs/cs4265.c @@ -154,6 +154,7 @@ static const struct snd_kcontrol_new cs4265_snd_controls[] = { SOC_SINGLE("E to F Buffer Disable Switch", CS4265_SPDIF_CTL1, 6, 1, 0), SOC_ENUM("C Data Access", cam_mode_enum), + SOC_SINGLE("SPDIF Switch", CS4265_SPDIF_CTL2, 5, 1, 1), SOC_SINGLE("Validity Bit Control Switch", CS4265_SPDIF_CTL2, 3, 1, 0), SOC_ENUM("SPDIF Mono/Stereo", spdif_mono_stereo_enum), From e664de680b10c13d65f982bcb9cfe56096e1de55 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Fri, 31 Aug 2018 03:08:09 +0000 Subject: [PATCH 053/299] ASoC: simple_card_utils: support snd_soc_dai_link_component style for codec Current ASoC is supporting snd_soc_dai_link_component for binding, it is more useful than current legacy style. Currently only codec is supporting it as multicodec (= codecs). CPU will support multi style in the future. We want to have it on Platform too in the future. If all Codec/CPU/Platform are replaced into snd_soc_dai_link_component style, we can remove legacy complex style. This patch supports snd_soc_dai_link_component style for simple_card_utils for codec. [current] struct snd_soc_dai_link { ... *cpu_name; *cpu_of_node; *cpu_dai_name; *codec_name; *codec_of_node; *codec_dai_name; *codecs; num_codecs; *platform_name; *platform_of_node; ... } [in the future] struct snd_soc_dai_link { ... *cpus num_cpus; *codecs; num_codecs; *platform; ... } Signed-off-by: Kuninori Morimoto Signed-off-by: Mark Brown --- include/sound/simple_card_utils.h | 27 +++++++++++------ sound/soc/generic/simple-card-utils.c | 42 +++++++++++++++++++++++++-- 2 files changed, 58 insertions(+), 11 deletions(-) diff --git a/include/sound/simple_card_utils.h b/include/sound/simple_card_utils.h index 8bc5e2d8b13c..3b5bd6e76f88 100644 --- a/include/sound/simple_card_utils.h +++ b/include/sound/simple_card_utils.h @@ -51,29 +51,35 @@ int asoc_simple_card_parse_card_name(struct snd_soc_card *card, #define asoc_simple_card_parse_clk_cpu(dev, node, dai_link, simple_dai) \ asoc_simple_card_parse_clk(dev, node, dai_link->cpu_of_node, simple_dai, \ - dai_link->cpu_dai_name) + dai_link->cpu_dai_name, NULL) #define asoc_simple_card_parse_clk_codec(dev, node, dai_link, simple_dai) \ asoc_simple_card_parse_clk(dev, node, dai_link->codec_of_node, simple_dai,\ - dai_link->codec_dai_name) + dai_link->codec_dai_name, dai_link->codecs) int asoc_simple_card_parse_clk(struct device *dev, struct device_node *node, struct device_node *dai_of_node, struct asoc_simple_dai *simple_dai, - const char *name); + const char *dai_name, + struct snd_soc_dai_link_component *dlc); int asoc_simple_card_clk_enable(struct asoc_simple_dai *dai); void asoc_simple_card_clk_disable(struct asoc_simple_dai *dai); #define asoc_simple_card_parse_cpu(node, dai_link, \ list_name, cells_name, is_single_link) \ - asoc_simple_card_parse_dai(node, &dai_link->cpu_of_node, \ + asoc_simple_card_parse_dai(node, NULL, \ + &dai_link->cpu_of_node, \ &dai_link->cpu_dai_name, list_name, cells_name, is_single_link) #define asoc_simple_card_parse_codec(node, dai_link, list_name, cells_name) \ - asoc_simple_card_parse_dai(node, &dai_link->codec_of_node, \ - &dai_link->codec_dai_name, list_name, cells_name, NULL) + asoc_simple_card_parse_dai(node, dai_link->codecs, \ + &dai_link->codec_of_node, \ + &dai_link->codec_dai_name, \ + list_name, cells_name, NULL) #define asoc_simple_card_parse_platform(node, dai_link, list_name, cells_name) \ - asoc_simple_card_parse_dai(node, &dai_link->platform_of_node, \ + asoc_simple_card_parse_dai(node, NULL, \ + &dai_link->platform_of_node, \ NULL, list_name, cells_name, NULL) int asoc_simple_card_parse_dai(struct device_node *node, + struct snd_soc_dai_link_component *dlc, struct device_node **endpoint_np, const char **dai_name, const char *list_name, @@ -81,12 +87,15 @@ int asoc_simple_card_parse_dai(struct device_node *node, int *is_single_links); #define asoc_simple_card_parse_graph_cpu(ep, dai_link) \ - asoc_simple_card_parse_graph_dai(ep, &dai_link->cpu_of_node, \ + asoc_simple_card_parse_graph_dai(ep, NULL, \ + &dai_link->cpu_of_node, \ &dai_link->cpu_dai_name) #define asoc_simple_card_parse_graph_codec(ep, dai_link) \ - asoc_simple_card_parse_graph_dai(ep, &dai_link->codec_of_node, \ + asoc_simple_card_parse_graph_dai(ep, dai_link->codecs, \ + &dai_link->codec_of_node, \ &dai_link->codec_dai_name) int asoc_simple_card_parse_graph_dai(struct device_node *ep, + struct snd_soc_dai_link_component *dlc, struct device_node **endpoint_np, const char **dai_name); diff --git a/sound/soc/generic/simple-card-utils.c b/sound/soc/generic/simple-card-utils.c index d3f3f0fec74c..73c0a904f32e 100644 --- a/sound/soc/generic/simple-card-utils.c +++ b/sound/soc/generic/simple-card-utils.c @@ -173,11 +173,23 @@ int asoc_simple_card_parse_clk(struct device *dev, struct device_node *node, struct device_node *dai_of_node, struct asoc_simple_dai *simple_dai, - const char *name) + const char *dai_name, + struct snd_soc_dai_link_component *dlc) { struct clk *clk; u32 val; + /* + * Use snd_soc_dai_link_component instead of legacy style. + * It is only for codec, but cpu will be supported in the future. + * see + * soc-core.c :: snd_soc_init_multicodec() + */ + if (dlc) { + dai_of_node = dlc->of_node; + dai_name = dlc->dai_name; + } + /* * Parse dai->sysclk come from "clocks = <&xxx>" * (if system has common clock) @@ -200,7 +212,7 @@ int asoc_simple_card_parse_clk(struct device *dev, if (of_property_read_bool(node, "system-clock-direction-out")) simple_dai->clk_direction = SND_SOC_CLOCK_OUT; - dev_dbg(dev, "%s : sysclk = %d, direction %d\n", name, + dev_dbg(dev, "%s : sysclk = %d, direction %d\n", dai_name, simple_dai->sysclk, simple_dai->clk_direction); return 0; @@ -208,6 +220,7 @@ int asoc_simple_card_parse_clk(struct device *dev, EXPORT_SYMBOL_GPL(asoc_simple_card_parse_clk); int asoc_simple_card_parse_dai(struct device_node *node, + struct snd_soc_dai_link_component *dlc, struct device_node **dai_of_node, const char **dai_name, const char *list_name, @@ -220,6 +233,17 @@ int asoc_simple_card_parse_dai(struct device_node *node, if (!node) return 0; + /* + * Use snd_soc_dai_link_component instead of legacy style. + * It is only for codec, but cpu will be supported in the future. + * see + * soc-core.c :: snd_soc_init_multicodec() + */ + if (dlc) { + dai_name = &dlc->dai_name; + dai_of_node = &dlc->of_node; + } + /* * Get node via "sound-dai = <&phandle port>" * it will be used as xxx_of_node on soc_bind_dai_link() @@ -278,6 +302,7 @@ static int asoc_simple_card_get_dai_id(struct device_node *ep) } int asoc_simple_card_parse_graph_dai(struct device_node *ep, + struct snd_soc_dai_link_component *dlc, struct device_node **dai_of_node, const char **dai_name) { @@ -285,6 +310,17 @@ int asoc_simple_card_parse_graph_dai(struct device_node *ep, struct of_phandle_args args; int ret; + /* + * Use snd_soc_dai_link_component instead of legacy style. + * It is only for codec, but cpu will be supported in the future. + * see + * soc-core.c :: snd_soc_init_multicodec() + */ + if (dlc) { + dai_name = &dlc->dai_name; + dai_of_node = &dlc->of_node; + } + if (!ep) return 0; if (!dai_name) @@ -374,6 +410,8 @@ int asoc_simple_card_clean_reference(struct snd_soc_card *card) num_links++, dai_link++) { of_node_put(dai_link->cpu_of_node); of_node_put(dai_link->codec_of_node); + if (dai_link->codecs) + of_node_put(dai_link->codecs->of_node); } return 0; } From 710af9196ce614ee02185c2ec55e617a71843183 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Fri, 31 Aug 2018 03:08:24 +0000 Subject: [PATCH 054/299] ASoC: simple-card: support snd_soc_dai_link_component style for codec Current ASoC is supporting snd_soc_dai_link_component for binding, it is more useful than current legacy style. Currently only codec is supporting it as multicodec (= codecs). CPU will support multi style in the future. We want to have it on Platform too in the future. If all Codec/CPU/Platform are replaced into snd_soc_dai_link_component style, we can remove legacy complex style. This patch supports snd_soc_dai_link_component style for simple-card for codec. [current] struct snd_soc_dai_link { ... *cpu_name; *cpu_of_node; *cpu_dai_name; *codec_name; *codec_of_node; *codec_dai_name; *codecs; num_codecs; *platform_name; *platform_of_node; ... } [in the future] struct snd_soc_dai_link { ... *cpus num_cpus; *codecs; num_codecs; *platform; ... } Signed-off-by: Kuninori Morimoto Signed-off-by: Mark Brown --- sound/soc/generic/simple-card.c | 23 +++++++++++++++++++---- 1 file changed, 19 insertions(+), 4 deletions(-) diff --git a/sound/soc/generic/simple-card.c b/sound/soc/generic/simple-card.c index 64bf3560c1d1..67a56f32f983 100644 --- a/sound/soc/generic/simple-card.c +++ b/sound/soc/generic/simple-card.c @@ -20,6 +20,7 @@ struct simple_card_data { struct simple_dai_props { struct asoc_simple_dai cpu_dai; struct asoc_simple_dai codec_dai; + struct snd_soc_dai_link_component codecs; /* single codec */ unsigned int mclk_fs; } *dai_props; unsigned int mclk_fs; @@ -234,7 +235,7 @@ static int asoc_simple_card_dai_link_of(struct device_node *node, ret = asoc_simple_card_set_dailink_name(dev, dai_link, "%s-%s", dai_link->cpu_dai_name, - dai_link->codec_dai_name); + dai_link->codecs->dai_name); if (ret < 0) goto dai_link_of_err; @@ -363,7 +364,7 @@ static int asoc_simple_card_probe(struct platform_device *pdev) struct device *dev = &pdev->dev; struct device_node *np = dev->of_node; struct snd_soc_card *card; - int num, ret; + int num, ret, i; /* Get the number of DAI links */ if (np && of_get_child_by_name(np, PREFIX "dai-link")) @@ -381,6 +382,17 @@ static int asoc_simple_card_probe(struct platform_device *pdev) if (!dai_props || !dai_link) return -ENOMEM; + /* + * Use snd_soc_dai_link_component instead of legacy style + * It is codec only. but cpu/platform will be supported in the future. + * see + * soc-core.c :: snd_soc_init_multicodec() + */ + for (i = 0; i < num; i++) { + dai_link[i].codecs = &dai_props[i].codecs; + dai_link[i].num_codecs = 1; + } + priv->dai_props = dai_props; priv->dai_link = dai_link; @@ -403,6 +415,7 @@ static int asoc_simple_card_probe(struct platform_device *pdev) } else { struct asoc_simple_card_info *cinfo; + struct snd_soc_dai_link_component *codecs; cinfo = dev->platform_data; if (!cinfo) { @@ -419,13 +432,15 @@ static int asoc_simple_card_probe(struct platform_device *pdev) return -EINVAL; } + codecs = dai_link->codecs; + codecs->name = cinfo->codec; + codecs->dai_name = cinfo->codec_dai.name; + card->name = (cinfo->card) ? cinfo->card : cinfo->name; dai_link->name = cinfo->name; dai_link->stream_name = cinfo->name; dai_link->platform_name = cinfo->platform; - dai_link->codec_name = cinfo->codec; dai_link->cpu_dai_name = cinfo->cpu_dai.name; - dai_link->codec_dai_name = cinfo->codec_dai.name; dai_link->dai_fmt = cinfo->daifmt; dai_link->init = asoc_simple_card_dai_init; memcpy(&priv->dai_props->cpu_dai, &cinfo->cpu_dai, From 5ece10ab99205d11419e3d2e6c7ac0e382d952b5 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Fri, 31 Aug 2018 03:08:38 +0000 Subject: [PATCH 055/299] ASoC: simple-scu-card: use simple_dai_props simple-card and simple-scu-card are very similar driver, but using different feature. Thus we are keeping synchronization on these 2 drivers style, because it is easy to confirm / check. Current big difference between these 2 drivers are "dai_props" on simple_card_data (= priv). It will be difficult to keep synchronize if we will add new feature on simple-scu-card. Thus, this patch synchronize it. [simple] struct simple_card_data { ... struct simple_dai_props { ... } *dai_props; ... }; [simple scu] struct simple_card_data { ... struct asoc_simple_dai *dai_props; ... }; Signed-off-by: Kuninori Morimoto Signed-off-by: Mark Brown --- sound/soc/generic/simple-scu-card.c | 26 ++++++++++++++------------ 1 file changed, 14 insertions(+), 12 deletions(-) diff --git a/sound/soc/generic/simple-scu-card.c b/sound/soc/generic/simple-scu-card.c index 16a83bc51e0e..09be02e7416f 100644 --- a/sound/soc/generic/simple-scu-card.c +++ b/sound/soc/generic/simple-scu-card.c @@ -22,7 +22,9 @@ struct simple_card_data { struct snd_soc_card snd_card; struct snd_soc_codec_conf codec_conf; - struct asoc_simple_dai *dai_props; + struct simple_dai_props { + struct asoc_simple_dai dai; + } *dai_props; struct snd_soc_dai_link *dai_link; struct asoc_simple_card_data adata; }; @@ -40,20 +42,20 @@ static int asoc_simple_card_startup(struct snd_pcm_substream *substream) { struct snd_soc_pcm_runtime *rtd = substream->private_data; struct simple_card_data *priv = snd_soc_card_get_drvdata(rtd->card); - struct asoc_simple_dai *dai_props = + struct simple_dai_props *dai_props = simple_priv_to_props(priv, rtd->num); - return asoc_simple_card_clk_enable(dai_props); + return asoc_simple_card_clk_enable(&dai_props->dai); } static void asoc_simple_card_shutdown(struct snd_pcm_substream *substream) { struct snd_soc_pcm_runtime *rtd = substream->private_data; struct simple_card_data *priv = snd_soc_card_get_drvdata(rtd->card); - struct asoc_simple_dai *dai_props = + struct simple_dai_props *dai_props = simple_priv_to_props(priv, rtd->num); - asoc_simple_card_clk_disable(dai_props); + asoc_simple_card_clk_disable(&dai_props->dai); } static const struct snd_soc_ops asoc_simple_card_ops = { @@ -66,7 +68,7 @@ static int asoc_simple_card_dai_init(struct snd_soc_pcm_runtime *rtd) struct simple_card_data *priv = snd_soc_card_get_drvdata(rtd->card); struct snd_soc_dai *dai; struct snd_soc_dai_link *dai_link; - struct asoc_simple_dai *dai_props; + struct simple_dai_props *dai_props; int num = rtd->num; dai_link = simple_priv_to_link(priv, num); @@ -75,7 +77,7 @@ static int asoc_simple_card_dai_init(struct snd_soc_pcm_runtime *rtd) rtd->cpu_dai : rtd->codec_dai; - return asoc_simple_card_init_dai(dai, dai_props); + return asoc_simple_card_init_dai(dai, &dai_props->dai); } static int asoc_simple_card_be_hw_params_fixup(struct snd_soc_pcm_runtime *rtd, @@ -95,7 +97,7 @@ static int asoc_simple_card_dai_link_of(struct device_node *np, { struct device *dev = simple_priv_to_dev(priv); struct snd_soc_dai_link *dai_link = simple_priv_to_link(priv, idx); - struct asoc_simple_dai *dai_props = simple_priv_to_props(priv, idx); + struct simple_dai_props *dai_props = simple_priv_to_props(priv, idx); struct snd_soc_card *card = simple_priv_to_card(priv); int ret; @@ -116,7 +118,7 @@ static int asoc_simple_card_dai_link_of(struct device_node *np, if (ret) return ret; - ret = asoc_simple_card_parse_clk_cpu(dev, np, dai_link, dai_props); + ret = asoc_simple_card_parse_clk_cpu(dev, np, dai_link, &dai_props->dai); if (ret < 0) return ret; @@ -141,7 +143,7 @@ static int asoc_simple_card_dai_link_of(struct device_node *np, if (ret < 0) return ret; - ret = asoc_simple_card_parse_clk_codec(dev, np, dai_link, dai_props); + ret = asoc_simple_card_parse_clk_codec(dev, np, dai_link, &dai_props->dai); if (ret < 0) return ret; @@ -157,7 +159,7 @@ static int asoc_simple_card_dai_link_of(struct device_node *np, PREFIX "prefix"); } - ret = asoc_simple_card_of_parse_tdm(np, dai_props); + ret = asoc_simple_card_of_parse_tdm(np, &dai_props->dai); if (ret) return ret; @@ -230,7 +232,7 @@ static int asoc_simple_card_probe(struct platform_device *pdev) { struct simple_card_data *priv; struct snd_soc_dai_link *dai_link; - struct asoc_simple_dai *dai_props; + struct simple_dai_props *dai_props; struct snd_soc_card *card; struct device *dev = &pdev->dev; struct device_node *np = dev->of_node; From 2289cc1c78574653d30b80696327646ba340babf Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Fri, 31 Aug 2018 03:08:51 +0000 Subject: [PATCH 056/299] ASoC: simple-scu-card: support snd_soc_dai_link_component style for codec Current ASoC is supporting snd_soc_dai_link_component for binding, it is more useful than current legacy style. Currently only codec is supporting it as multicodec (= codecs). CPU will support multi style in the future. We want to have it on Platform too in the future. If all Codec/CPU/Platform are replaced into snd_soc_dai_link_component style, we can remove legacy complex style. This patch supports snd_soc_dai_link_component style for simple-scu-card for codec. [current] struct snd_soc_dai_link { ... *cpu_name; *cpu_of_node; *cpu_dai_name; *codec_name; *codec_of_node; *codec_dai_name; *codecs; num_codecs; *platform_name; *platform_of_node; ... } [in the future] struct snd_soc_dai_link { ... *cpus num_cpus; *codecs; num_codecs; *platform; ... } Signed-off-by: Kuninori Morimoto Signed-off-by: Mark Brown --- sound/soc/generic/simple-scu-card.c | 26 ++++++++++++++++++++------ 1 file changed, 20 insertions(+), 6 deletions(-) diff --git a/sound/soc/generic/simple-scu-card.c b/sound/soc/generic/simple-scu-card.c index 09be02e7416f..91efc8653746 100644 --- a/sound/soc/generic/simple-scu-card.c +++ b/sound/soc/generic/simple-scu-card.c @@ -24,6 +24,7 @@ struct simple_card_data { struct snd_soc_codec_conf codec_conf; struct simple_dai_props { struct asoc_simple_dai dai; + struct snd_soc_dai_link_component codecs; } *dai_props; struct snd_soc_dai_link *dai_link; struct asoc_simple_card_data adata; @@ -103,11 +104,13 @@ static int asoc_simple_card_dai_link_of(struct device_node *np, if (is_fe) { int is_single_links = 0; + struct snd_soc_dai_link_component *codecs; /* BE is dummy */ - dai_link->codec_of_node = NULL; - dai_link->codec_dai_name = "snd-soc-dummy-dai"; - dai_link->codec_name = "snd-soc-dummy"; + codecs = dai_link->codecs; + codecs->of_node = NULL; + codecs->dai_name = "snd-soc-dummy-dai"; + codecs->name = "snd-soc-dummy"; /* FE settings */ dai_link->dynamic = 1; @@ -149,13 +152,13 @@ static int asoc_simple_card_dai_link_of(struct device_node *np, ret = asoc_simple_card_set_dailink_name(dev, dai_link, "be.%s", - dai_link->codec_dai_name); + dai_link->codecs->dai_name); if (ret < 0) return ret; snd_soc_of_parse_audio_prefix(card, &priv->codec_conf, - dai_link->codec_of_node, + dai_link->codecs->of_node, PREFIX "prefix"); } @@ -236,7 +239,7 @@ static int asoc_simple_card_probe(struct platform_device *pdev) struct snd_soc_card *card; struct device *dev = &pdev->dev; struct device_node *np = dev->of_node; - int num, ret; + int num, ret, i; /* Allocate the private data */ priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL); @@ -250,6 +253,17 @@ static int asoc_simple_card_probe(struct platform_device *pdev) if (!dai_props || !dai_link) return -ENOMEM; + /* + * Use snd_soc_dai_link_component instead of legacy style + * It is codec only. but cpu/platform will be supported in the future. + * see + * soc-core.c :: snd_soc_init_multicodec() + */ + for (i = 0; i < num; i++) { + dai_link[i].codecs = &dai_props[i].codecs; + dai_link[i].num_codecs = 1; + } + priv->dai_props = dai_props; priv->dai_link = dai_link; From 8e6746db2e66c30e59a49ac15eb0c54d51acfb4b Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Fri, 31 Aug 2018 03:09:05 +0000 Subject: [PATCH 057/299] ASoC: audio-graph-card: support snd_soc_dai_link_component style for codec Current ASoC is supporting snd_soc_dai_link_component for binding, it is more useful than current legacy style. Currently only codec is supporting it as multicodec (= codecs). CPU will support multi style in the future. We want to have it on Platform too in the future. If all Codec/CPU/Platform are replaced into snd_soc_dai_link_component style, we can remove legacy complex style. This patch supports snd_soc_dai_link_component style for audio-graph-card for codec. [current] struct snd_soc_dai_link { ... *cpu_name; *cpu_of_node; *cpu_dai_name; *codec_name; *codec_of_node; *codec_dai_name; *codecs; num_codecs; *platform_name; *platform_of_node; ... } [in the future] struct snd_soc_dai_link { ... *cpus num_cpus; *codecs; num_codecs; *platform; ... } Signed-off-by: Kuninori Morimoto Signed-off-by: Mark Brown --- sound/soc/generic/audio-graph-card.c | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/sound/soc/generic/audio-graph-card.c b/sound/soc/generic/audio-graph-card.c index 2094d2c8919f..5b2ecf8c2652 100644 --- a/sound/soc/generic/audio-graph-card.c +++ b/sound/soc/generic/audio-graph-card.c @@ -25,6 +25,7 @@ struct graph_card_data { struct graph_dai_props { struct asoc_simple_dai cpu_dai; struct asoc_simple_dai codec_dai; + struct snd_soc_dai_link_component codecs; /* single codec */ unsigned int mclk_fs; } *dai_props; unsigned int mclk_fs; @@ -213,7 +214,7 @@ static int asoc_graph_card_dai_link_of(struct device_node *cpu_port, ret = asoc_simple_card_set_dailink_name(dev, dai_link, "%s-%s", dai_link->cpu_dai_name, - dai_link->codec_dai_name); + dai_link->codecs->dai_name); if (ret < 0) goto dai_link_of_err; @@ -299,7 +300,7 @@ static int asoc_graph_card_probe(struct platform_device *pdev) struct graph_dai_props *dai_props; struct device *dev = &pdev->dev; struct snd_soc_card *card; - int num, ret; + int num, ret, i; /* Allocate the private data and the DAI link array */ priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL); @@ -315,6 +316,17 @@ static int asoc_graph_card_probe(struct platform_device *pdev) if (!dai_props || !dai_link) return -ENOMEM; + /* + * Use snd_soc_dai_link_component instead of legacy style + * It is codec only. but cpu/platform will be supported in the future. + * see + * soc-core.c :: snd_soc_init_multicodec() + */ + for (i = 0; i < num; i++) { + dai_link[i].codecs = &dai_props[i].codecs; + dai_link[i].num_codecs = 1; + } + priv->pa_gpio = devm_gpiod_get_optional(dev, "pa", GPIOD_OUT_LOW); if (IS_ERR(priv->pa_gpio)) { ret = PTR_ERR(priv->pa_gpio); From 1340739d4de4d9d99f1134180f95b42cc4eda438 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Fri, 31 Aug 2018 03:09:20 +0000 Subject: [PATCH 058/299] ASoC: audio-graph-scu-card: use simple_dai_props audi-graph-card and audio-graph-scu-card are very similar driver, but using different feature. Thus we are keeping synchronization on these 2 drivers style, because it is easy to confirm / check. Current big difference between these 2 drivers are "dai_props" on graph_card_data (= priv). It will be difficult to keep synchronize if we will add new feature on audio-graph-scu-card. Thus, this patch synchronize it. [audio-graph] struct graph_card_data { ... struct graph_dai_props { ... } *dai_props; ... }; [audio-graph-scu] struct graph_card_data { ... struct asoc_simple_dai *dai_props; ... }; Signed-off-by: Kuninori Morimoto Signed-off-by: Mark Brown --- sound/soc/generic/audio-graph-scu-card.c | 26 +++++++++++++----------- 1 file changed, 14 insertions(+), 12 deletions(-) diff --git a/sound/soc/generic/audio-graph-scu-card.c b/sound/soc/generic/audio-graph-scu-card.c index 92882e392d6c..043938fece42 100644 --- a/sound/soc/generic/audio-graph-scu-card.c +++ b/sound/soc/generic/audio-graph-scu-card.c @@ -25,7 +25,9 @@ struct graph_card_data { struct snd_soc_card snd_card; struct snd_soc_codec_conf codec_conf; - struct asoc_simple_dai *dai_props; + struct graph_dai_props { + struct asoc_simple_dai dai; + } *dai_props; struct snd_soc_dai_link *dai_link; struct asoc_simple_card_data adata; }; @@ -39,18 +41,18 @@ static int asoc_graph_card_startup(struct snd_pcm_substream *substream) { struct snd_soc_pcm_runtime *rtd = substream->private_data; struct graph_card_data *priv = snd_soc_card_get_drvdata(rtd->card); - struct asoc_simple_dai *dai_props = graph_priv_to_props(priv, rtd->num); + struct graph_dai_props *dai_props = graph_priv_to_props(priv, rtd->num); - return asoc_simple_card_clk_enable(dai_props); + return asoc_simple_card_clk_enable(&dai_props->dai); } static void asoc_graph_card_shutdown(struct snd_pcm_substream *substream) { struct snd_soc_pcm_runtime *rtd = substream->private_data; struct graph_card_data *priv = snd_soc_card_get_drvdata(rtd->card); - struct asoc_simple_dai *dai_props = graph_priv_to_props(priv, rtd->num); + struct graph_dai_props *dai_props = graph_priv_to_props(priv, rtd->num); - asoc_simple_card_clk_disable(dai_props); + asoc_simple_card_clk_disable(&dai_props->dai); } static const struct snd_soc_ops asoc_graph_card_ops = { @@ -63,7 +65,7 @@ static int asoc_graph_card_dai_init(struct snd_soc_pcm_runtime *rtd) struct graph_card_data *priv = snd_soc_card_get_drvdata(rtd->card); struct snd_soc_dai *dai; struct snd_soc_dai_link *dai_link; - struct asoc_simple_dai *dai_props; + struct graph_dai_props *dai_props; int num = rtd->num; dai_link = graph_priv_to_link(priv, num); @@ -72,7 +74,7 @@ static int asoc_graph_card_dai_init(struct snd_soc_pcm_runtime *rtd) rtd->cpu_dai : rtd->codec_dai; - return asoc_simple_card_init_dai(dai, dai_props); + return asoc_simple_card_init_dai(dai, &dai_props->dai); } static int asoc_graph_card_be_hw_params_fixup(struct snd_soc_pcm_runtime *rtd, @@ -92,7 +94,7 @@ static int asoc_graph_card_dai_link_of(struct device_node *ep, { struct device *dev = graph_priv_to_dev(priv); struct snd_soc_dai_link *dai_link = graph_priv_to_link(priv, idx); - struct asoc_simple_dai *dai_props = graph_priv_to_props(priv, idx); + struct graph_dai_props *dai_props = graph_priv_to_props(priv, idx); struct snd_soc_card *card = graph_priv_to_card(priv); int ret; @@ -110,7 +112,7 @@ static int asoc_graph_card_dai_link_of(struct device_node *ep, if (ret) return ret; - ret = asoc_simple_card_parse_clk_cpu(dev, ep, dai_link, dai_props); + ret = asoc_simple_card_parse_clk_cpu(dev, ep, dai_link, &dai_props->dai); if (ret < 0) return ret; @@ -137,7 +139,7 @@ static int asoc_graph_card_dai_link_of(struct device_node *ep, if (ret < 0) return ret; - ret = asoc_simple_card_parse_clk_codec(dev, ep, dai_link, dai_props); + ret = asoc_simple_card_parse_clk_codec(dev, ep, dai_link, &dai_props->dai); if (ret < 0) return ret; @@ -153,7 +155,7 @@ static int asoc_graph_card_dai_link_of(struct device_node *ep, "prefix"); } - ret = asoc_simple_card_of_parse_tdm(ep, dai_props); + ret = asoc_simple_card_of_parse_tdm(ep, &dai_props->dai); if (ret) return ret; @@ -331,7 +333,7 @@ static int asoc_graph_card_probe(struct platform_device *pdev) { struct graph_card_data *priv; struct snd_soc_dai_link *dai_link; - struct asoc_simple_dai *dai_props; + struct graph_dai_props *dai_props; struct device *dev = &pdev->dev; struct snd_soc_card *card; int num, ret; From 04f7267aa8d17773917580951c740496e8059cba Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Fri, 31 Aug 2018 03:09:33 +0000 Subject: [PATCH 059/299] ASoC: audio-graph-scu-card: support snd_soc_dai_link_component style for codec Current ASoC is supporting snd_soc_dai_link_component for binding, it is more useful than current legacy style. Currently only codec is supporting it as multicodec (= codecs). CPU will support multi style in the future. We want to have it on Platform too in the future. If all Codec/CPU/Platform are replaced into snd_soc_dai_link_component style, we can remove legacy complex style. This patch supports snd_soc_dai_link_component style for audio-graph-scu-card for codec. [current] struct snd_soc_dai_link { ... *cpu_name; *cpu_of_node; *cpu_dai_name; *codec_name; *codec_of_node; *codec_dai_name; *codecs; num_codecs; *platform_name; *platform_of_node; ... } [in the future] struct snd_soc_dai_link { ... *cpus num_cpus; *codecs; num_codecs; *platform; ... } Signed-off-by: Kuninori Morimoto Signed-off-by: Mark Brown --- sound/soc/generic/audio-graph-scu-card.c | 27 ++++++++++++++++++------ 1 file changed, 21 insertions(+), 6 deletions(-) diff --git a/sound/soc/generic/audio-graph-scu-card.c b/sound/soc/generic/audio-graph-scu-card.c index 043938fece42..eeb3c1975fe3 100644 --- a/sound/soc/generic/audio-graph-scu-card.c +++ b/sound/soc/generic/audio-graph-scu-card.c @@ -27,6 +27,7 @@ struct graph_card_data { struct snd_soc_codec_conf codec_conf; struct graph_dai_props { struct asoc_simple_dai dai; + struct snd_soc_dai_link_component codecs; } *dai_props; struct snd_soc_dai_link *dai_link; struct asoc_simple_card_data adata; @@ -99,10 +100,13 @@ static int asoc_graph_card_dai_link_of(struct device_node *ep, int ret; if (is_fe) { + struct snd_soc_dai_link_component *codecs; + /* BE is dummy */ - dai_link->codec_of_node = NULL; - dai_link->codec_dai_name = "snd-soc-dummy-dai"; - dai_link->codec_name = "snd-soc-dummy"; + codecs = dai_link->codecs; + codecs->of_node = NULL; + codecs->dai_name = "snd-soc-dummy-dai"; + codecs->name = "snd-soc-dummy"; /* FE settings */ dai_link->dynamic = 1; @@ -145,13 +149,13 @@ static int asoc_graph_card_dai_link_of(struct device_node *ep, ret = asoc_simple_card_set_dailink_name(dev, dai_link, "be.%s", - dai_link->codec_dai_name); + dai_link->codecs->dai_name); if (ret < 0) return ret; snd_soc_of_parse_audio_prefix(card, &priv->codec_conf, - dai_link->codec_of_node, + dai_link->codecs->of_node, "prefix"); } @@ -336,7 +340,7 @@ static int asoc_graph_card_probe(struct platform_device *pdev) struct graph_dai_props *dai_props; struct device *dev = &pdev->dev; struct snd_soc_card *card; - int num, ret; + int num, ret, i; /* Allocate the private data and the DAI link array */ priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL); @@ -352,6 +356,17 @@ static int asoc_graph_card_probe(struct platform_device *pdev) if (!dai_props || !dai_link) return -ENOMEM; + /* + * Use snd_soc_dai_link_component instead of legacy style + * It is codec only. but cpu/platform will be supported in the future. + * see + * soc-core.c :: snd_soc_init_multicodec() + */ + for (i = 0; i < num; i++) { + dai_link[i].codecs = &dai_props[i].codecs; + dai_link[i].num_codecs = 1; + } + priv->dai_props = dai_props; priv->dai_link = dai_link; From 2967e5ea19ec041104fd43da4cb07e8e76a39e55 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Fri, 31 Aug 2018 03:09:47 +0000 Subject: [PATCH 060/299] ASoC: simple-card-util: remove dai_link compatible code for codec Now no simple/audio cards are using legacy dai_link style for codec. Let's remove compatible code. Signed-off-by: Kuninori Morimoto Signed-off-by: Mark Brown --- sound/soc/generic/simple-card-utils.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/sound/soc/generic/simple-card-utils.c b/sound/soc/generic/simple-card-utils.c index 73c0a904f32e..e7057be957e1 100644 --- a/sound/soc/generic/simple-card-utils.c +++ b/sound/soc/generic/simple-card-utils.c @@ -409,9 +409,7 @@ int asoc_simple_card_clean_reference(struct snd_soc_card *card) num_links < card->num_links; num_links++, dai_link++) { of_node_put(dai_link->cpu_of_node); - of_node_put(dai_link->codec_of_node); - if (dai_link->codecs) - of_node_put(dai_link->codecs->of_node); + of_node_put(dai_link->codecs->of_node); } return 0; } From daecf46ee0e5f0fb2349e20af53c4653e2afc440 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Fri, 31 Aug 2018 03:10:08 +0000 Subject: [PATCH 061/299] ASoC: soc-core: use snd_soc_dai_link_component for platform Current struct snd_soc_dai_link is supporting multicodec, and it is supporting legacy style of codec_name codec_of_node code_dai_name This is handled as single entry of multicodec. We don't have multicpu support yet, but in the future we will. In such case, we can use snd_soc_dai_link_component for both cpu/codec. Then the code will be more simple and readble. As next step, we want to use it for platform, too. This patch adds snd_soc_dai_link_component style for platform. We might have multiplatform support in the future, but we don't know yet. To avoid un-known issue / complex code, this patch supports just single-platform as 1st step. If we could use snd_soc_dai_link_component for all CPU/Codec/Platform, we will switch to new style, and remove legacy code. This is prepare for it. Signed-off-by: Kuninori Morimoto Signed-off-by: Mark Brown --- include/sound/soc.h | 2 ++ sound/soc/soc-core.c | 48 +++++++++++++++++++++++++++++++++++++------- 2 files changed, 43 insertions(+), 7 deletions(-) diff --git a/include/sound/soc.h b/include/sound/soc.h index 41cec42fb456..96c19aabf21b 100644 --- a/include/sound/soc.h +++ b/include/sound/soc.h @@ -915,6 +915,8 @@ struct snd_soc_dai_link { */ const char *platform_name; struct device_node *platform_of_node; + struct snd_soc_dai_link_component *platform; + int id; /* optional ID for machine driver link identification */ const struct snd_soc_pcm_stream *params; diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c index 473eefe8658e..2a73630d0680 100644 --- a/sound/soc/soc-core.c +++ b/sound/soc/soc-core.c @@ -892,8 +892,8 @@ static int soc_bind_dai_link(struct snd_soc_card *card, rtd->codec_dai = codec_dais[0]; /* if there's no platform we match on the empty platform */ - platform_name = dai_link->platform_name; - if (!platform_name && !dai_link->platform_of_node) + platform_name = dai_link->platform->name; + if (!platform_name && !dai_link->platform->of_node) platform_name = "snd-soc-dummy"; /* find one from the set of registered platforms */ @@ -902,8 +902,8 @@ static int soc_bind_dai_link(struct snd_soc_card *card, if (!platform_of_node && component->dev->parent->of_node) platform_of_node = component->dev->parent->of_node; - if (dai_link->platform_of_node) { - if (platform_of_node != dai_link->platform_of_node) + if (dai_link->platform->of_node) { + if (platform_of_node != dai_link->platform->of_node) continue; } else { if (strcmp(component->name, platform_name)) @@ -1015,6 +1015,31 @@ static void soc_remove_dai_links(struct snd_soc_card *card) } } +static int snd_soc_init_platform(struct snd_soc_card *card, + struct snd_soc_dai_link *dai_link) +{ + /* + * FIXME + * + * this function should be removed in the future + */ + /* convert Legacy platform link */ + if (dai_link->platform) + return 0; + + dai_link->platform = devm_kzalloc(card->dev, + sizeof(struct snd_soc_dai_link_component), + GFP_KERNEL); + if (!dai_link->platform) + return -ENOMEM; + + dai_link->platform->name = dai_link->platform_name; + dai_link->platform->of_node = dai_link->platform_of_node; + dai_link->platform->dai_name = NULL; + + return 0; +} + static int snd_soc_init_multicodec(struct snd_soc_card *card, struct snd_soc_dai_link *dai_link) { @@ -1047,6 +1072,12 @@ static int soc_init_dai_link(struct snd_soc_card *card, { int i, ret; + ret = snd_soc_init_platform(card, link); + if (ret) { + dev_err(card->dev, "ASoC: failed to init multiplatform\n"); + return ret; + } + ret = snd_soc_init_multicodec(card, link); if (ret) { dev_err(card->dev, "ASoC: failed to init multicodec\n"); @@ -1076,13 +1107,12 @@ static int soc_init_dai_link(struct snd_soc_card *card, * Platform may be specified by either name or OF node, but * can be left unspecified, and a dummy platform will be used. */ - if (link->platform_name && link->platform_of_node) { + if (link->platform->name && link->platform->of_node) { dev_err(card->dev, "ASoC: Both platform name/of_node are set for %s\n", link->name); return -EINVAL; } - /* * CPU device may be specified by either name or OF node, but * can be left unspecified, and will be matched based on DAI @@ -1917,7 +1947,11 @@ static void soc_check_tplg_fes(struct snd_soc_card *card) card->dai_link[i].name); /* override platform component */ - dai_link->platform_name = component->name; + if (snd_soc_init_platform(card, dai_link) < 0) { + dev_err(card->dev, "init platform error"); + continue; + } + dai_link->platform->name = component->name; /* convert non BE into BE */ dai_link->no_pcm = 1; From 868cdb4690699b04ca4d09b1e0178dfc680dbd8e Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Fri, 31 Aug 2018 03:10:20 +0000 Subject: [PATCH 062/299] ASoC: simple-card-util: support snd_soc_dai_link_component style for platform Current ASoC is supporting snd_soc_dai_link_component for binding, it is more useful than current legacy style. Currently only codec is supporting it as multicodec (= codecs). CPU will support multi style in the future. We want to have it on Platform too in the future. If all Codec/CPU/Platform are replaced into snd_soc_dai_link_component style, we can remove legacy complex style. This patch supports snd_soc_dai_link_component style for simple-card-util for platform. [current] struct snd_soc_dai_link { ... *cpu_name; *cpu_of_node; *cpu_dai_name; *codec_name; *codec_of_node; *codec_dai_name; *codecs; num_codecs; *platform_name; *platform_of_node; ... } [in the future] struct snd_soc_dai_link { ... *cpus num_cpus; *codecs; num_codecs; *platform; ... } Signed-off-by: Kuninori Morimoto Signed-off-by: Mark Brown --- include/sound/simple_card_utils.h | 2 +- sound/soc/generic/simple-card-utils.c | 11 ++++++++--- 2 files changed, 9 insertions(+), 4 deletions(-) diff --git a/include/sound/simple_card_utils.h b/include/sound/simple_card_utils.h index 3b5bd6e76f88..fb0318f9b10f 100644 --- a/include/sound/simple_card_utils.h +++ b/include/sound/simple_card_utils.h @@ -75,7 +75,7 @@ void asoc_simple_card_clk_disable(struct asoc_simple_dai *dai); &dai_link->codec_dai_name, \ list_name, cells_name, NULL) #define asoc_simple_card_parse_platform(node, dai_link, list_name, cells_name) \ - asoc_simple_card_parse_dai(node, NULL, \ + asoc_simple_card_parse_dai(node, dai_link->platform, \ &dai_link->platform_of_node, \ NULL, list_name, cells_name, NULL) int asoc_simple_card_parse_dai(struct device_node *node, diff --git a/sound/soc/generic/simple-card-utils.c b/sound/soc/generic/simple-card-utils.c index e7057be957e1..644cd62ba027 100644 --- a/sound/soc/generic/simple-card-utils.c +++ b/sound/soc/generic/simple-card-utils.c @@ -376,10 +376,15 @@ EXPORT_SYMBOL_GPL(asoc_simple_card_init_dai); int asoc_simple_card_canonicalize_dailink(struct snd_soc_dai_link *dai_link) { /* Assumes platform == cpu */ - if (!dai_link->platform_of_node) - dai_link->platform_of_node = dai_link->cpu_of_node; - + if (dai_link->platform) { + if (!dai_link->platform->of_node) + dai_link->platform->of_node = dai_link->cpu_of_node; + } else { + if (!dai_link->platform_of_node) + dai_link->platform_of_node = dai_link->cpu_of_node; + } return 0; + } EXPORT_SYMBOL_GPL(asoc_simple_card_canonicalize_dailink); From e58f41e41185c6906bd11c73c4e76aa5fc3ea685 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Fri, 31 Aug 2018 03:10:33 +0000 Subject: [PATCH 063/299] ASoC: simple-card: support snd_soc_dai_link_component style for platform Current ASoC is supporting snd_soc_dai_link_component for binding, it is more useful than current legacy style. Currently only codec is supporting it as multicodec (= codecs). CPU will support multi style in the future. We want to have it on Platform too in the future. If all Codec/CPU/Platform are replaced into snd_soc_dai_link_component style, we can remove legacy complex style. This patch supports snd_soc_dai_link_component style for simple-card for platform. [current] struct snd_soc_dai_link { ... *cpu_name; *cpu_of_node; *cpu_dai_name; *codec_name; *codec_of_node; *codec_dai_name; *codecs; num_codecs; *platform_name; *platform_of_node; ... } [in the future] struct snd_soc_dai_link { ... *cpus num_cpus; *codecs; num_codecs; *platform; ... } Signed-off-by: Kuninori Morimoto Signed-off-by: Mark Brown --- sound/soc/generic/simple-card.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/sound/soc/generic/simple-card.c b/sound/soc/generic/simple-card.c index 67a56f32f983..5a3f59aa4ba5 100644 --- a/sound/soc/generic/simple-card.c +++ b/sound/soc/generic/simple-card.c @@ -21,6 +21,7 @@ struct simple_card_data { struct asoc_simple_dai cpu_dai; struct asoc_simple_dai codec_dai; struct snd_soc_dai_link_component codecs; /* single codec */ + struct snd_soc_dai_link_component platform; unsigned int mclk_fs; } *dai_props; unsigned int mclk_fs; @@ -391,6 +392,7 @@ static int asoc_simple_card_probe(struct platform_device *pdev) for (i = 0; i < num; i++) { dai_link[i].codecs = &dai_props[i].codecs; dai_link[i].num_codecs = 1; + dai_link[i].platform = &dai_props[i].platform; } priv->dai_props = dai_props; @@ -416,6 +418,7 @@ static int asoc_simple_card_probe(struct platform_device *pdev) } else { struct asoc_simple_card_info *cinfo; struct snd_soc_dai_link_component *codecs; + struct snd_soc_dai_link_component *platform; cinfo = dev->platform_data; if (!cinfo) { @@ -436,10 +439,12 @@ static int asoc_simple_card_probe(struct platform_device *pdev) codecs->name = cinfo->codec; codecs->dai_name = cinfo->codec_dai.name; + platform = dai_link->platform; + platform->name = cinfo->platform; + card->name = (cinfo->card) ? cinfo->card : cinfo->name; dai_link->name = cinfo->name; dai_link->stream_name = cinfo->name; - dai_link->platform_name = cinfo->platform; dai_link->cpu_dai_name = cinfo->cpu_dai.name; dai_link->dai_fmt = cinfo->daifmt; dai_link->init = asoc_simple_card_dai_init; From 24f3bead9b72cbd91956be28ab6a74d51bdd4c6b Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Fri, 31 Aug 2018 03:10:46 +0000 Subject: [PATCH 064/299] ASoC: simple-scu-card: support snd_soc_dai_link_component style for platform Current ASoC is supporting snd_soc_dai_link_component for binding, it is more useful than current legacy style. Currently only codec is supporting it as multicodec (= codecs). CPU will support multi style in the future. We want to have it on Platform too in the future. If all Codec/CPU/Platform are replaced into snd_soc_dai_link_component style, we can remove legacy complex style. This patch supports snd_soc_dai_link_component style for simple-scu-card for platform. [current] struct snd_soc_dai_link { ... *cpu_name; *cpu_of_node; *cpu_dai_name; *codec_name; *codec_of_node; *codec_dai_name; *codecs; num_codecs; *platform_name; *platform_of_node; ... } [in the future] struct snd_soc_dai_link { ... *cpus num_cpus; *codecs; num_codecs; *platform; ... } Signed-off-by: Kuninori Morimoto Signed-off-by: Mark Brown --- sound/soc/generic/simple-scu-card.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/sound/soc/generic/simple-scu-card.c b/sound/soc/generic/simple-scu-card.c index 91efc8653746..85b46f0eae0f 100644 --- a/sound/soc/generic/simple-scu-card.c +++ b/sound/soc/generic/simple-scu-card.c @@ -25,6 +25,7 @@ struct simple_card_data { struct simple_dai_props { struct asoc_simple_dai dai; struct snd_soc_dai_link_component codecs; + struct snd_soc_dai_link_component platform; } *dai_props; struct snd_soc_dai_link *dai_link; struct asoc_simple_card_data adata; @@ -262,6 +263,7 @@ static int asoc_simple_card_probe(struct platform_device *pdev) for (i = 0; i < num; i++) { dai_link[i].codecs = &dai_props[i].codecs; dai_link[i].num_codecs = 1; + dai_link[i].platform = &dai_props[i].platform; } priv->dai_props = dai_props; From 46c73187f2986e40b427485bb8f4401aa9143ed0 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Fri, 31 Aug 2018 03:10:58 +0000 Subject: [PATCH 065/299] ASoC: audio-graph-card: support snd_soc_dai_link_component style for platform Current ASoC is supporting snd_soc_dai_link_component for binding, it is more useful than current legacy style. Currently only codec is supporting it as multicodec (= codecs). CPU will support multi style in the future. We want to have it on Platform too in the future. If all Codec/CPU/Platform are replaced into snd_soc_dai_link_component style, we can remove legacy complex style. This patch supports snd_soc_dai_link_component style for audio-graph-card for platform. [current] struct snd_soc_dai_link { ... *cpu_name; *cpu_of_node; *cpu_dai_name; *codec_name; *codec_of_node; *codec_dai_name; *codecs; num_codecs; *platform_name; *platform_of_node; ... } [in the future] struct snd_soc_dai_link { ... *cpus num_cpus; *codecs; num_codecs; *platform; ... } Signed-off-by: Kuninori Morimoto Signed-off-by: Mark Brown --- sound/soc/generic/audio-graph-card.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/sound/soc/generic/audio-graph-card.c b/sound/soc/generic/audio-graph-card.c index 5b2ecf8c2652..fb6635f8d5d7 100644 --- a/sound/soc/generic/audio-graph-card.c +++ b/sound/soc/generic/audio-graph-card.c @@ -26,6 +26,7 @@ struct graph_card_data { struct asoc_simple_dai cpu_dai; struct asoc_simple_dai codec_dai; struct snd_soc_dai_link_component codecs; /* single codec */ + struct snd_soc_dai_link_component platform; unsigned int mclk_fs; } *dai_props; unsigned int mclk_fs; @@ -325,6 +326,7 @@ static int asoc_graph_card_probe(struct platform_device *pdev) for (i = 0; i < num; i++) { dai_link[i].codecs = &dai_props[i].codecs; dai_link[i].num_codecs = 1; + dai_link[i].platform = &dai_props[i].platform; } priv->pa_gpio = devm_gpiod_get_optional(dev, "pa", GPIOD_OUT_LOW); From 77b9b84132f0b9ca0802a25277eb7be49713661f Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Fri, 31 Aug 2018 03:11:12 +0000 Subject: [PATCH 066/299] ASoC: audio-graph-scu-card: support snd_soc_dai_link_component style for platform Current ASoC is supporting snd_soc_dai_link_component for binding, it is more useful than current legacy style. Currently only codec is supporting it as multicodec (= codecs). CPU will support multi style in the future. We want to have it on Platform too in the future. If all Codec/CPU/Platform are replaced into snd_soc_dai_link_component style, we can remove legacy complex style. This patch supports snd_soc_dai_link_component style for audio-graph-scu-card for platform. [current] struct snd_soc_dai_link { ... *cpu_name; *cpu_of_node; *cpu_dai_name; *codec_name; *codec_of_node; *codec_dai_name; *codecs; num_codecs; *platform_name; *platform_of_node; ... } [in the future] struct snd_soc_dai_link { ... *cpus num_cpus; *codecs; num_codecs; *platform; ... } Signed-off-by: Kuninori Morimoto Signed-off-by: Mark Brown --- sound/soc/generic/audio-graph-scu-card.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/sound/soc/generic/audio-graph-scu-card.c b/sound/soc/generic/audio-graph-scu-card.c index eeb3c1975fe3..b83bb31021a9 100644 --- a/sound/soc/generic/audio-graph-scu-card.c +++ b/sound/soc/generic/audio-graph-scu-card.c @@ -28,6 +28,7 @@ struct graph_card_data { struct graph_dai_props { struct asoc_simple_dai dai; struct snd_soc_dai_link_component codecs; + struct snd_soc_dai_link_component platform; } *dai_props; struct snd_soc_dai_link *dai_link; struct asoc_simple_card_data adata; @@ -365,6 +366,7 @@ static int asoc_graph_card_probe(struct platform_device *pdev) for (i = 0; i < num; i++) { dai_link[i].codecs = &dai_props[i].codecs; dai_link[i].num_codecs = 1; + dai_link[i].platform = &dai_props[i].platform; } priv->dai_props = dai_props; From c2f0898b86486a459fa8c91d194f3b699498c0c1 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Fri, 31 Aug 2018 03:11:25 +0000 Subject: [PATCH 067/299] ASoC: simple-card-util: remove dai_link compatible code for platform Now no simple/audio cards are using legacy dai_link style for platform. Let's remove compatible code. Signed-off-by: Kuninori Morimoto Signed-off-by: Mark Brown --- sound/soc/generic/simple-card-utils.c | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/sound/soc/generic/simple-card-utils.c b/sound/soc/generic/simple-card-utils.c index 644cd62ba027..b400dbf1f834 100644 --- a/sound/soc/generic/simple-card-utils.c +++ b/sound/soc/generic/simple-card-utils.c @@ -376,13 +376,9 @@ EXPORT_SYMBOL_GPL(asoc_simple_card_init_dai); int asoc_simple_card_canonicalize_dailink(struct snd_soc_dai_link *dai_link) { /* Assumes platform == cpu */ - if (dai_link->platform) { - if (!dai_link->platform->of_node) - dai_link->platform->of_node = dai_link->cpu_of_node; - } else { - if (!dai_link->platform_of_node) - dai_link->platform_of_node = dai_link->cpu_of_node; - } + if (!dai_link->platform->of_node) + dai_link->platform->of_node = dai_link->cpu_of_node; + return 0; } From 919869214b8e0b24926a278e121879f60df485bb Mon Sep 17 00:00:00 2001 From: "Andrew F. Davis" Date: Fri, 31 Aug 2018 10:14:06 -0500 Subject: [PATCH 068/299] ASoC: tas6424: Print full register name in error message The current short version of the register name may be ambiguous when another fault register detection is added. Use the full name. While here fix comment about clearing faults, the CLEAR_FAULT register actually only clears sticky bits, which are only warnings, fault bits can only cleared by resolving the fault. Signed-off-by: Andrew F. Davis Signed-off-by: Mark Brown --- sound/soc/codecs/tas6424.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/sound/soc/codecs/tas6424.c b/sound/soc/codecs/tas6424.c index 14999b999fd3..3315ce8a15e6 100644 --- a/sound/soc/codecs/tas6424.c +++ b/sound/soc/codecs/tas6424.c @@ -408,7 +408,7 @@ static void tas6424_fault_check_work(struct work_struct *work) ret = regmap_read(tas6424->regmap, TAS6424_GLOB_FAULT1, ®); if (ret < 0) { - dev_err(dev, "failed to read FAULT1 register: %d\n", ret); + dev_err(dev, "failed to read GLOB_FAULT1 register: %d\n", ret); goto out; } @@ -451,7 +451,7 @@ static void tas6424_fault_check_work(struct work_struct *work) check_global_fault2_reg: ret = regmap_read(tas6424->regmap, TAS6424_GLOB_FAULT2, ®); if (ret < 0) { - dev_err(dev, "failed to read FAULT2 register: %d\n", ret); + dev_err(dev, "failed to read GLOB_FAULT2 register: %d\n", ret); goto out; } @@ -524,7 +524,7 @@ check_warn_reg: /* Store current warn value so we can detect any changes next time */ tas6424->last_warn = reg; - /* Clear any faults by toggling the CLEAR_FAULT control bit */ + /* Clear any warnings by toggling the CLEAR_FAULT control bit */ ret = regmap_write_bits(tas6424->regmap, TAS6424_MISC_CTRL3, TAS6424_CLEAR_FAULT, TAS6424_CLEAR_FAULT); if (ret < 0) From 5fb6589acc3860304436aa436e7ea33712de6fc2 Mon Sep 17 00:00:00 2001 From: "Andrew F. Davis" Date: Fri, 31 Aug 2018 10:14:07 -0500 Subject: [PATCH 069/299] ASoC: tas6424: Add channel fault reporting The TAS6426 has a register that reports channel faults such as overcurrent and continuous DC output. Add reporting of this here. Signed-off-by: Andrew F. Davis Signed-off-by: Mark Brown --- sound/soc/codecs/tas6424.c | 52 +++++++++++++++++++++++++++++++++----- sound/soc/codecs/tas6424.h | 10 ++++++++ 2 files changed, 56 insertions(+), 6 deletions(-) diff --git a/sound/soc/codecs/tas6424.c b/sound/soc/codecs/tas6424.c index aac559fffc1a..36aebdb8f55c 100644 --- a/sound/soc/codecs/tas6424.c +++ b/sound/soc/codecs/tas6424.c @@ -41,6 +41,7 @@ struct tas6424_data { struct regmap *regmap; struct regulator_bulk_data supplies[TAS6424_NUM_SUPPLIES]; struct delayed_work fault_check_work; + unsigned int last_cfault; unsigned int last_fault1; unsigned int last_fault2; unsigned int last_warn; @@ -406,6 +407,51 @@ static void tas6424_fault_check_work(struct work_struct *work) unsigned int reg; int ret; + ret = regmap_read(tas6424->regmap, TAS6424_CHANNEL_FAULT, ®); + if (ret < 0) { + dev_err(dev, "failed to read CHANNEL_FAULT register: %d\n", ret); + goto out; + } + + if (!reg) { + tas6424->last_cfault = reg; + goto check_global_fault1_reg; + } + + /* + * Only flag errors once for a given occurrence. This is needed as + * the TAS6424 will take time clearing the fault condition internally + * during which we don't want to bombard the system with the same + * error message over and over. + */ + if ((reg & TAS6424_FAULT_OC_CH1) && !(tas6424->last_cfault & TAS6424_FAULT_OC_CH1)) + dev_crit(dev, "experienced a channel 1 overcurrent fault\n"); + + if ((reg & TAS6424_FAULT_OC_CH2) && !(tas6424->last_cfault & TAS6424_FAULT_OC_CH2)) + dev_crit(dev, "experienced a channel 2 overcurrent fault\n"); + + if ((reg & TAS6424_FAULT_OC_CH3) && !(tas6424->last_cfault & TAS6424_FAULT_OC_CH3)) + dev_crit(dev, "experienced a channel 3 overcurrent fault\n"); + + if ((reg & TAS6424_FAULT_OC_CH4) && !(tas6424->last_cfault & TAS6424_FAULT_OC_CH4)) + dev_crit(dev, "experienced a channel 4 overcurrent fault\n"); + + if ((reg & TAS6424_FAULT_DC_CH1) && !(tas6424->last_cfault & TAS6424_FAULT_DC_CH1)) + dev_crit(dev, "experienced a channel 1 DC fault\n"); + + if ((reg & TAS6424_FAULT_DC_CH2) && !(tas6424->last_cfault & TAS6424_FAULT_DC_CH2)) + dev_crit(dev, "experienced a channel 2 DC fault\n"); + + if ((reg & TAS6424_FAULT_DC_CH3) && !(tas6424->last_cfault & TAS6424_FAULT_DC_CH3)) + dev_crit(dev, "experienced a channel 3 DC fault\n"); + + if ((reg & TAS6424_FAULT_DC_CH4) && !(tas6424->last_cfault & TAS6424_FAULT_DC_CH4)) + dev_crit(dev, "experienced a channel 4 DC fault\n"); + + /* Store current fault1 value so we can detect any changes next time */ + tas6424->last_cfault = reg; + +check_global_fault1_reg: ret = regmap_read(tas6424->regmap, TAS6424_GLOB_FAULT1, ®); if (ret < 0) { dev_err(dev, "failed to read GLOB_FAULT1 register: %d\n", ret); @@ -429,12 +475,6 @@ static void tas6424_fault_check_work(struct work_struct *work) goto check_global_fault2_reg; } - /* - * Only flag errors once for a given occurrence. This is needed as - * the TAS6424 will take time clearing the fault condition internally - * during which we don't want to bombard the system with the same - * error message over and over. - */ if ((reg & TAS6424_FAULT_PVDD_OV) && !(tas6424->last_fault1 & TAS6424_FAULT_PVDD_OV)) dev_crit(dev, "experienced a PVDD overvoltage fault\n"); diff --git a/sound/soc/codecs/tas6424.h b/sound/soc/codecs/tas6424.h index b5958c45ed0e..c67a7835ca66 100644 --- a/sound/soc/codecs/tas6424.h +++ b/sound/soc/codecs/tas6424.h @@ -115,6 +115,16 @@ #define TAS6424_LDGBYPASS_SHIFT 0 #define TAS6424_LDGBYPASS_MASK BIT(TAS6424_LDGBYPASS_SHIFT) +/* TAS6424_GLOB_FAULT1_REG */ +#define TAS6424_FAULT_OC_CH1 BIT(7) +#define TAS6424_FAULT_OC_CH2 BIT(6) +#define TAS6424_FAULT_OC_CH3 BIT(5) +#define TAS6424_FAULT_OC_CH4 BIT(4) +#define TAS6424_FAULT_DC_CH1 BIT(3) +#define TAS6424_FAULT_DC_CH2 BIT(2) +#define TAS6424_FAULT_DC_CH3 BIT(1) +#define TAS6424_FAULT_DC_CH4 BIT(0) + /* TAS6424_GLOB_FAULT1_REG */ #define TAS6424_FAULT_CLOCK BIT(4) #define TAS6424_FAULT_PVDD_OV BIT(3) From 63a886f38dd96868e33488eccee8ed427144d397 Mon Sep 17 00:00:00 2001 From: Randy Dunlap Date: Sun, 2 Sep 2018 19:38:10 -0700 Subject: [PATCH 070/299] ASoC: fix soc-core.c kernel-doc warning Fix kernel-doc warning: ../sound/soc/soc-core.c:2918: warning: Excess function parameter 'legacy_dai_naming' description in 'snd_soc_register_dais' Signed-off-by: Randy Dunlap Signed-off-by: Mark Brown --- sound/soc/soc-core.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c index 2a73630d0680..e9c2304afaf1 100644 --- a/sound/soc/soc-core.c +++ b/sound/soc/soc-core.c @@ -2944,8 +2944,6 @@ static struct snd_soc_dai *soc_add_dai(struct snd_soc_component *component, * @component: The component the DAIs are registered for * @dai_drv: DAI driver to use for the DAIs * @count: Number of DAIs - * @legacy_dai_naming: Use the legacy naming scheme and let the DAI inherit the - * parent's name. */ static int snd_soc_register_dais(struct snd_soc_component *component, struct snd_soc_dai_driver *dai_drv, size_t count) From 80863ee222d37b1797cea74d2257ad6d68444d30 Mon Sep 17 00:00:00 2001 From: "Andrew F. Davis" Date: Fri, 31 Aug 2018 13:24:31 -0500 Subject: [PATCH 071/299] ASoC: tlv320aic31xx: Add short circuit detection support These devices support detecting and reporting short circuits across the output stages. Add support for reporting these issue. Do this by registering an interrupt if available and enabling this error to trigger that interrupt in the device. Signed-off-by: Andrew F. Davis Signed-off-by: Mark Brown --- sound/soc/codecs/tlv320aic31xx.c | 55 ++++++++++++++++++++++++++++++++ sound/soc/codecs/tlv320aic31xx.h | 16 ++++++++++ 2 files changed, 71 insertions(+) diff --git a/sound/soc/codecs/tlv320aic31xx.c b/sound/soc/codecs/tlv320aic31xx.c index bf92d36b8f8a..2abe51d9f879 100644 --- a/sound/soc/codecs/tlv320aic31xx.c +++ b/sound/soc/codecs/tlv320aic31xx.c @@ -167,6 +167,7 @@ struct aic31xx_priv { u8 p_div; int rate_div_line; bool master_dapm_route_applied; + int irq; }; struct aic31xx_rate_divs { @@ -1391,6 +1392,40 @@ static const struct acpi_device_id aic31xx_acpi_match[] = { MODULE_DEVICE_TABLE(acpi, aic31xx_acpi_match); #endif +static irqreturn_t aic31xx_irq(int irq, void *data) +{ + struct aic31xx_priv *aic31xx = data; + struct device *dev = aic31xx->dev; + unsigned int value; + bool handled = false; + int ret; + + ret = regmap_read(aic31xx->regmap, AIC31XX_INTRDACFLAG, &value); + if (ret) { + dev_err(dev, "Failed to read interrupt mask: %d\n", ret); + goto exit; + } + + if (value) + handled = true; + else + goto exit; + + if (value & AIC31XX_HPLSCDETECT) + dev_err(dev, "Short circuit on Left output is detected\n"); + if (value & AIC31XX_HPRSCDETECT) + dev_err(dev, "Short circuit on Right output is detected\n"); + if (value & ~(AIC31XX_HPLSCDETECT | + AIC31XX_HPRSCDETECT)) + dev_err(dev, "Unknown DAC interrupt flags: 0x%08x\n", value); + +exit: + if (handled) + return IRQ_HANDLED; + else + return IRQ_NONE; +} + static int aic31xx_i2c_probe(struct i2c_client *i2c, const struct i2c_device_id *id) { @@ -1413,6 +1448,7 @@ static int aic31xx_i2c_probe(struct i2c_client *i2c, return ret; } aic31xx->dev = &i2c->dev; + aic31xx->irq = i2c->irq; aic31xx->codec_type = id->driver_data; @@ -1456,6 +1492,25 @@ static int aic31xx_i2c_probe(struct i2c_client *i2c, return ret; } + if (aic31xx->irq > 0) { + regmap_update_bits(aic31xx->regmap, AIC31XX_GPIO1, + AIC31XX_GPIO1_FUNC_MASK, + AIC31XX_GPIO1_INT1 << + AIC31XX_GPIO1_FUNC_SHIFT); + + regmap_write(aic31xx->regmap, AIC31XX_INT1CTRL, + AIC31XX_SC); + + ret = devm_request_threaded_irq(aic31xx->dev, aic31xx->irq, + NULL, aic31xx_irq, + IRQF_ONESHOT, "aic31xx-irq", + aic31xx); + if (ret) { + dev_err(aic31xx->dev, "Unable to request IRQ\n"); + return ret; + } + } + if (aic31xx->codec_type & DAC31XX_BIT) return devm_snd_soc_register_component(&i2c->dev, &soc_codec_driver_aic31xx, diff --git a/sound/soc/codecs/tlv320aic31xx.h b/sound/soc/codecs/tlv320aic31xx.h index 0b587585b38b..52e171988906 100644 --- a/sound/soc/codecs/tlv320aic31xx.h +++ b/sound/soc/codecs/tlv320aic31xx.h @@ -191,6 +191,22 @@ struct aic31xx_pdata { #define AIC31XX_SC BIT(3) #define AIC31XX_ENGINE BIT(2) +/* AIC31XX_GPIO1 */ +#define AIC31XX_GPIO1_FUNC_MASK GENMASK(5, 2) +#define AIC31XX_GPIO1_FUNC_SHIFT 2 +#define AIC31XX_GPIO1_DISABLED 0x00 +#define AIC31XX_GPIO1_INPUT 0x01 +#define AIC31XX_GPIO1_GPI 0x02 +#define AIC31XX_GPIO1_GPO 0x03 +#define AIC31XX_GPIO1_CLKOUT 0x04 +#define AIC31XX_GPIO1_INT1 0x05 +#define AIC31XX_GPIO1_INT2 0x06 +#define AIC31XX_GPIO1_ADC_WCLK 0x07 +#define AIC31XX_GPIO1_SBCLK 0x08 +#define AIC31XX_GPIO1_SWCLK 0x09 +#define AIC31XX_GPIO1_ADC_MOD_CLK 0x10 +#define AIC31XX_GPIO1_SDOUT 0x11 + /* AIC31XX_DACSETUP */ #define AIC31XX_SOFTSTEP_MASK GENMASK(1, 0) From b5c088689847372794500f83b65673aaa8ca4d8d Mon Sep 17 00:00:00 2001 From: Jiada Wang Date: Mon, 3 Sep 2018 07:05:11 +0000 Subject: [PATCH 072/299] ASoC: rsnd: add warning message to rsnd_kctrl_accept_runtime() Add warning message to rsnd_kctrl_accept_runtime(), when kctrl update is rejected due to corresponding dai-link is idle. So that user can notice the reason of kctrl update failure. Signed-off-by: Jiada Wang Signed-off-by: Timo Wischer [kuninori: adjust to upstream] Signed-off-by: Kuninori Morimoto Tested-by: Hiroyuki Yokoyama Signed-off-by: Mark Brown --- sound/soc/sh/rcar/core.c | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/sound/soc/sh/rcar/core.c b/sound/soc/sh/rcar/core.c index f8425d8b44d2..ab7e317bbed8 100644 --- a/sound/soc/sh/rcar/core.c +++ b/sound/soc/sh/rcar/core.c @@ -1263,8 +1263,15 @@ int rsnd_kctrl_accept_anytime(struct rsnd_dai_stream *io) int rsnd_kctrl_accept_runtime(struct rsnd_dai_stream *io) { struct snd_pcm_runtime *runtime = rsnd_io_to_runtime(io); + struct rsnd_priv *priv = rsnd_io_to_priv(io); + struct device *dev = rsnd_priv_to_dev(priv); - return !!runtime; + if (!runtime) { + dev_warn(dev, "Can't update kctrl when idle\n"); + return 0; + } + + return 1; } struct rsnd_kctrl_cfg *rsnd_kctrl_init_m(struct rsnd_kctrl_cfg_m *cfg) From fb2815f44a9eb341ed8990263855a266960a5135 Mon Sep 17 00:00:00 2001 From: Dragos Tarcatu Date: Mon, 3 Sep 2018 07:05:42 +0000 Subject: [PATCH 073/299] ASoC: rsnd: add support for 16/24 bit slot widths The slot width (system word length) was fixed at 32 bits. This patch allows also setting it to 16 or 24 bits. Signed-off-by: Dragos Tarcatu Signed-off-by: Jiada Wang Signed-off-by: Timo Wischer [Kuninori: tidyup for upstream] Signed-off-by: Kuninori Morimoto Tested-by: Hiroyuki Yokoyama Signed-off-by: Mark Brown --- sound/soc/sh/rcar/core.c | 32 ++++++++++++++++++------ sound/soc/sh/rcar/rsnd.h | 8 +++++- sound/soc/sh/rcar/ssi.c | 54 +++++++++++++++++++++++++++++----------- 3 files changed, 72 insertions(+), 22 deletions(-) diff --git a/sound/soc/sh/rcar/core.c b/sound/soc/sh/rcar/core.c index ab7e317bbed8..ce0a3a61c441 100644 --- a/sound/soc/sh/rcar/core.c +++ b/sound/soc/sh/rcar/core.c @@ -540,6 +540,14 @@ int rsnd_rdai_ssi_lane_ctrl(struct rsnd_dai *rdai, return rdai->ssi_lane; } +int rsnd_rdai_width_ctrl(struct rsnd_dai *rdai, int width) +{ + if (width > 0) + rdai->chan_width = width; + + return rdai->chan_width; +} + struct rsnd_dai *rsnd_rdai_get(struct rsnd_priv *priv, int id) { if ((id < 0) || (id >= rsnd_rdai_nr(priv))) @@ -720,6 +728,16 @@ static int rsnd_soc_set_dai_tdm_slot(struct snd_soc_dai *dai, struct rsnd_dai *rdai = rsnd_dai_to_rdai(dai); struct device *dev = rsnd_priv_to_dev(priv); + switch (slot_width) { + case 16: + case 24: + case 32: + break; + default: + dev_err(dev, "unsupported slot width value: %d\n", slot_width); + return -EINVAL; + } + switch (slots) { case 2: case 6: @@ -727,6 +745,7 @@ static int rsnd_soc_set_dai_tdm_slot(struct snd_soc_dai *dai, /* TDM Extend Mode */ rsnd_rdai_channels_set(rdai, slots); rsnd_rdai_ssi_lane_set(rdai, 1); + rsnd_rdai_width_set(rdai, slot_width); break; default: dev_err(dev, "unsupported TDM slots (%d)\n", slots); @@ -755,7 +774,7 @@ static unsigned int rsnd_soc_hw_rate_list[] = { 192000, }; -static int rsnd_soc_hw_rule(struct rsnd_priv *priv, +static int rsnd_soc_hw_rule(struct rsnd_dai *rdai, unsigned int *list, int list_num, struct snd_interval *baseline, struct snd_interval *iv) { @@ -772,14 +791,14 @@ static int rsnd_soc_hw_rule(struct rsnd_priv *priv, if (!snd_interval_test(iv, list[i])) continue; - rate = rsnd_ssi_clk_query(priv, + rate = rsnd_ssi_clk_query(rdai, baseline->min, list[i], NULL); if (rate > 0) { p.min = min(p.min, list[i]); p.max = max(p.max, list[i]); } - rate = rsnd_ssi_clk_query(priv, + rate = rsnd_ssi_clk_query(rdai, baseline->max, list[i], NULL); if (rate > 0) { p.min = min(p.min, list[i]); @@ -799,7 +818,6 @@ static int __rsnd_soc_hw_rule_rate(struct snd_pcm_hw_params *params, struct snd_interval ic; struct snd_soc_dai *dai = rule->private; struct rsnd_dai *rdai = rsnd_dai_to_rdai(dai); - struct rsnd_priv *priv = rsnd_rdai_to_priv(rdai); struct rsnd_dai_stream *io = is_play ? &rdai->playback : &rdai->capture; /* @@ -811,7 +829,7 @@ static int __rsnd_soc_hw_rule_rate(struct snd_pcm_hw_params *params, ic.min = ic.max = rsnd_runtime_channel_for_ssi_with_params(io, params); - return rsnd_soc_hw_rule(priv, rsnd_soc_hw_rate_list, + return rsnd_soc_hw_rule(rdai, rsnd_soc_hw_rate_list, ARRAY_SIZE(rsnd_soc_hw_rate_list), &ic, ir); } @@ -837,7 +855,6 @@ static int __rsnd_soc_hw_rule_channels(struct snd_pcm_hw_params *params, struct snd_interval ic; struct snd_soc_dai *dai = rule->private; struct rsnd_dai *rdai = rsnd_dai_to_rdai(dai); - struct rsnd_priv *priv = rsnd_rdai_to_priv(rdai); struct rsnd_dai_stream *io = is_play ? &rdai->playback : &rdai->capture; /* @@ -849,7 +866,7 @@ static int __rsnd_soc_hw_rule_channels(struct snd_pcm_hw_params *params, ic.min = ic.max = rsnd_runtime_channel_for_ssi_with_params(io, params); - return rsnd_soc_hw_rule(priv, rsnd_soc_hw_channels_list, + return rsnd_soc_hw_rule(rdai, rsnd_soc_hw_channels_list, ARRAY_SIZE(rsnd_soc_hw_channels_list), ir, &ic); } @@ -1072,6 +1089,7 @@ static void __rsnd_dai_probe(struct rsnd_priv *priv, rdai->capture.rdai = rdai; rsnd_rdai_channels_set(rdai, 2); /* default 2ch */ rsnd_rdai_ssi_lane_set(rdai, 1); /* default 1lane */ + rsnd_rdai_width_set(rdai, 32); /* default 32bit width */ for (io_i = 0;; io_i++) { playback = of_parse_phandle(dai_np, "playback", io_i); diff --git a/sound/soc/sh/rcar/rsnd.h b/sound/soc/sh/rcar/rsnd.h index 96d93330b1e1..698b08155b06 100644 --- a/sound/soc/sh/rcar/rsnd.h +++ b/sound/soc/sh/rcar/rsnd.h @@ -460,6 +460,7 @@ struct rsnd_dai { int max_channels; /* 2ch - 16ch */ int ssi_lane; /* 1lane - 4lane */ + int chan_width; /* 16/24/32 bit width */ unsigned int clk_master:1; unsigned int bit_clk_inv:1; @@ -493,6 +494,11 @@ int rsnd_rdai_channels_ctrl(struct rsnd_dai *rdai, int rsnd_rdai_ssi_lane_ctrl(struct rsnd_dai *rdai, int ssi_lane); +#define rsnd_rdai_width_set(rdai, width) \ + rsnd_rdai_width_ctrl(rdai, width) +#define rsnd_rdai_width_get(rdai) \ + rsnd_rdai_width_ctrl(rdai, 0) +int rsnd_rdai_width_ctrl(struct rsnd_dai *rdai, int width); void rsnd_dai_period_elapsed(struct rsnd_dai_stream *io); int rsnd_dai_connect(struct rsnd_mod *mod, struct rsnd_dai_stream *io, @@ -702,7 +708,7 @@ int __rsnd_ssi_is_pin_sharing(struct rsnd_mod *mod); void rsnd_parse_connect_ssi(struct rsnd_dai *rdai, struct device_node *playback, struct device_node *capture); -unsigned int rsnd_ssi_clk_query(struct rsnd_priv *priv, +unsigned int rsnd_ssi_clk_query(struct rsnd_dai *rdai, int param1, int param2, int *idx); /* diff --git a/sound/soc/sh/rcar/ssi.c b/sound/soc/sh/rcar/ssi.c index 8304e4ec9242..f707f53748bd 100644 --- a/sound/soc/sh/rcar/ssi.c +++ b/sound/soc/sh/rcar/ssi.c @@ -42,7 +42,13 @@ #define DWL_24 (5 << 19) /* Data Word Length */ #define DWL_32 (6 << 19) /* Data Word Length */ +/* + * System word length + */ +#define SWL_16 (1 << 16) /* R/W System Word Length */ +#define SWL_24 (2 << 16) /* R/W System Word Length */ #define SWL_32 (3 << 16) /* R/W System Word Length */ + #define SCKD (1 << 15) /* Serial Bit Clock Direction */ #define SWSD (1 << 14) /* Serial WS Direction */ #define SCKP (1 << 13) /* Serial Bit Clock Polarity */ @@ -220,14 +226,32 @@ u32 rsnd_ssi_multi_slaves_runtime(struct rsnd_dai_stream *io) return 0; } -unsigned int rsnd_ssi_clk_query(struct rsnd_priv *priv, +static u32 rsnd_rdai_width_to_swl(struct rsnd_dai *rdai) +{ + struct rsnd_priv *priv = rsnd_rdai_to_priv(rdai); + struct device *dev = rsnd_priv_to_dev(priv); + int width = rsnd_rdai_width_get(rdai); + + switch (width) { + case 32: return SWL_32; + case 24: return SWL_24; + case 16: return SWL_16; + } + + dev_err(dev, "unsupported slot width value: %d\n", width); + return 0; +} + +unsigned int rsnd_ssi_clk_query(struct rsnd_dai *rdai, int param1, int param2, int *idx) { + struct rsnd_priv *priv = rsnd_rdai_to_priv(rdai); int ssi_clk_mul_table[] = { 1, 2, 4, 8, 16, 6, 12, }; int j, ret; unsigned int main_rate; + int width = rsnd_rdai_width_get(rdai); for (j = 0; j < ARRAY_SIZE(ssi_clk_mul_table); j++) { @@ -240,12 +264,7 @@ unsigned int rsnd_ssi_clk_query(struct rsnd_priv *priv, if (j == 0) continue; - /* - * this driver is assuming that - * system word is 32bit x chan - * see rsnd_ssi_init() - */ - main_rate = 32 * param1 * param2 * ssi_clk_mul_table[j]; + main_rate = width * param1 * param2 * ssi_clk_mul_table[j]; ret = rsnd_adg_clk_query(priv, main_rate); if (ret < 0) @@ -292,7 +311,7 @@ static int rsnd_ssi_master_clk_start(struct rsnd_mod *mod, return 0; } - main_rate = rsnd_ssi_clk_query(priv, rate, chan, &idx); + main_rate = rsnd_ssi_clk_query(rdai, rate, chan, &idx); if (!main_rate) { dev_err(dev, "unsupported clock rate\n"); return -EIO; @@ -312,7 +331,8 @@ static int rsnd_ssi_master_clk_start(struct rsnd_mod *mod, * SSICR : FORCE, SCKD, SWSD * SSIWSR : CONT */ - ssi->cr_clk = FORCE | SWL_32 | SCKD | SWSD | CKDV(idx); + ssi->cr_clk = FORCE | rsnd_rdai_width_to_swl(rdai) | + SCKD | SWSD | CKDV(idx); ssi->wsr = CONT; ssi->rate = rate; @@ -357,11 +377,7 @@ static void rsnd_ssi_config_init(struct rsnd_mod *mod, is_tdm = rsnd_runtime_is_ssi_tdm(io); - /* - * always use 32bit system word. - * see also rsnd_ssi_master_clk_enable() - */ - cr_own |= FORCE | SWL_32; + cr_own |= FORCE | rsnd_rdai_width_to_swl(rdai); if (rdai->bit_clk_inv) cr_own |= SCKP; @@ -494,7 +510,17 @@ static int rsnd_ssi_hw_params(struct rsnd_mod *mod, struct snd_pcm_hw_params *params) { struct rsnd_ssi *ssi = rsnd_mod_to_ssi(mod); + struct rsnd_dai *rdai = rsnd_io_to_rdai(io); int chan = params_channels(params); + unsigned int fmt_width = snd_pcm_format_width(params_format(params)); + + if (fmt_width > rdai->chan_width) { + struct rsnd_priv *priv = rsnd_io_to_priv(io); + struct device *dev = rsnd_priv_to_dev(priv); + + dev_err(dev, "invalid combination of slot-width and format-data-width\n"); + return -EINVAL; + } /* * snd_pcm_ops::hw_params will be called *before* From 3791b3ee4bb13c381868da89e9e6deb11de660ad Mon Sep 17 00:00:00 2001 From: Dragos Tarcatu Date: Mon, 3 Sep 2018 07:06:01 +0000 Subject: [PATCH 074/299] ASoC: rsnd: add support for the DSP_A/DSP_B formats Signed-off-by: Dragos Tarcatu Signed-off-by: Jiada Wang Signed-off-by: Timo Wischer [Kuninori: tidyup for upstream] Signed-off-by: Kuninori Morimoto Tested-by: Hiroyuki Yokoyama Signed-off-by: Mark Brown --- sound/soc/sh/rcar/core.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/sound/soc/sh/rcar/core.c b/sound/soc/sh/rcar/core.c index ce0a3a61c441..8a417768b7ef 100644 --- a/sound/soc/sh/rcar/core.c +++ b/sound/soc/sh/rcar/core.c @@ -689,6 +689,7 @@ static int rsnd_soc_dai_set_fmt(struct snd_soc_dai *dai, unsigned int fmt) rdai->frm_clk_inv = 0; break; case SND_SOC_DAIFMT_LEFT_J: + case SND_SOC_DAIFMT_DSP_B: rdai->sys_delay = 1; rdai->data_alignment = 0; rdai->frm_clk_inv = 1; @@ -698,6 +699,11 @@ static int rsnd_soc_dai_set_fmt(struct snd_soc_dai *dai, unsigned int fmt) rdai->data_alignment = 1; rdai->frm_clk_inv = 1; break; + case SND_SOC_DAIFMT_DSP_A: + rdai->sys_delay = 0; + rdai->data_alignment = 0; + rdai->frm_clk_inv = 1; + break; } /* set clock inversion */ From ba5d553b7bd71e63d639863e2cb09e0c9543b8b7 Mon Sep 17 00:00:00 2001 From: Dragos Tarcatu Date: Mon, 3 Sep 2018 07:06:29 +0000 Subject: [PATCH 075/299] ASoC: rsnd: add support for 8 bit S8 format This patch adds support for SNDRV_PCM_FMTBIT_S8 format. Signed-off-by: Dragos Tarcatu Signed-off-by: Jiada Wang Signed-off-by: Timo Wischer [Kuninori: tidyup for upstream] Signed-off-by: Kuninori Morimoto Tested-by: Hiroyuki Yokoyama Signed-off-by: Mark Brown --- sound/soc/sh/rcar/core.c | 10 +++++++--- sound/soc/sh/rcar/ssi.c | 3 +++ 2 files changed, 10 insertions(+), 3 deletions(-) diff --git a/sound/soc/sh/rcar/core.c b/sound/soc/sh/rcar/core.c index 8a417768b7ef..cd0ff1eef463 100644 --- a/sound/soc/sh/rcar/core.c +++ b/sound/soc/sh/rcar/core.c @@ -102,7 +102,9 @@ #include "rsnd.h" #define RSND_RATES SNDRV_PCM_RATE_8000_192000 -#define RSND_FMTS (SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S16_LE) +#define RSND_FMTS (SNDRV_PCM_FMTBIT_S8 |\ + SNDRV_PCM_FMTBIT_S16_LE |\ + SNDRV_PCM_FMTBIT_S24_LE) static const struct of_device_id rsnd_of_match[] = { { .compatible = "renesas,rcar_sound-gen1", .data = (void *)RSND_GEN1 }, @@ -280,6 +282,8 @@ u32 rsnd_get_adinr_bit(struct rsnd_mod *mod, struct rsnd_dai_stream *io) struct device *dev = rsnd_priv_to_dev(priv); switch (snd_pcm_format_width(runtime->format)) { + case 8: + return 16 << 16; case 16: return 8 << 16; case 24: @@ -331,7 +335,7 @@ u32 rsnd_get_dalign(struct rsnd_mod *mod, struct rsnd_dai_stream *io) target = cmd ? cmd : ssiu; } - /* Non target mod or 24bit data needs normal DALIGN */ + /* Non target mod or non 16bit needs normal DALIGN */ if ((snd_pcm_format_width(runtime->format) != 16) || (mod != target)) return 0x76543210; @@ -367,7 +371,7 @@ u32 rsnd_get_busif_shift(struct rsnd_dai_stream *io, struct rsnd_mod *mod) * HW 24bit data is located as 0x******00 * */ - if (snd_pcm_format_width(runtime->format) == 16) + if (snd_pcm_format_width(runtime->format) != 24) return 0; for (i = 0; i < ARRAY_SIZE(playback_mods); i++) { diff --git a/sound/soc/sh/rcar/ssi.c b/sound/soc/sh/rcar/ssi.c index f707f53748bd..765ecc06c7c9 100644 --- a/sound/soc/sh/rcar/ssi.c +++ b/sound/soc/sh/rcar/ssi.c @@ -400,6 +400,9 @@ static void rsnd_ssi_config_init(struct rsnd_mod *mod, cr_own &= ~DWL_MASK; switch (snd_pcm_format_width(runtime->format)) { + case 8: + cr_own |= DWL_8; + break; case 16: cr_own |= DWL_16; break; From b735662fa473c0e3618a4d645ce797d31e0c9192 Mon Sep 17 00:00:00 2001 From: Jiada Wang Date: Mon, 3 Sep 2018 07:06:50 +0000 Subject: [PATCH 076/299] ASoC: rsnd: remove is_play parameter from hw_rule function Currently rsnd_dai_stream *io is set to either &rdai->playback or &rdai->capture based on whether it is a playback or capture stream, in __rsnd_soc_hw_rule_* functions, but this is not necessary, rsnd_dai_stream *io handler can be get from rule->private. This patch removes 'is_play' parameter from hw_rule function. Signed-off-by: Jiada Wang Signed-off-by: Timo Wischer [Kuninori: tidyup for upstream] Signed-off-by: Kuninori Morimoto Tested-by: Hiroyuki Yokoyama Signed-off-by: Mark Brown --- sound/soc/sh/rcar/core.c | 54 +++++++++------------------------------- 1 file changed, 12 insertions(+), 42 deletions(-) diff --git a/sound/soc/sh/rcar/core.c b/sound/soc/sh/rcar/core.c index cd0ff1eef463..c66b3dade947 100644 --- a/sound/soc/sh/rcar/core.c +++ b/sound/soc/sh/rcar/core.c @@ -819,16 +819,14 @@ static int rsnd_soc_hw_rule(struct rsnd_dai *rdai, return snd_interval_refine(iv, &p); } -static int __rsnd_soc_hw_rule_rate(struct snd_pcm_hw_params *params, - struct snd_pcm_hw_rule *rule, - int is_play) +static int rsnd_soc_hw_rule_rate(struct snd_pcm_hw_params *params, + struct snd_pcm_hw_rule *rule) { struct snd_interval *ic_ = hw_param_interval(params, SNDRV_PCM_HW_PARAM_CHANNELS); struct snd_interval *ir = hw_param_interval(params, SNDRV_PCM_HW_PARAM_RATE); struct snd_interval ic; - struct snd_soc_dai *dai = rule->private; - struct rsnd_dai *rdai = rsnd_dai_to_rdai(dai); - struct rsnd_dai_stream *io = is_play ? &rdai->playback : &rdai->capture; + struct rsnd_dai_stream *io = rule->private; + struct rsnd_dai *rdai = rsnd_io_to_rdai(io); /* * possible sampling rate limitation is same as @@ -844,28 +842,14 @@ static int __rsnd_soc_hw_rule_rate(struct snd_pcm_hw_params *params, &ic, ir); } -static int rsnd_soc_hw_rule_rate_playback(struct snd_pcm_hw_params *params, - struct snd_pcm_hw_rule *rule) -{ - return __rsnd_soc_hw_rule_rate(params, rule, 1); -} - -static int rsnd_soc_hw_rule_rate_capture(struct snd_pcm_hw_params *params, - struct snd_pcm_hw_rule *rule) -{ - return __rsnd_soc_hw_rule_rate(params, rule, 0); -} - -static int __rsnd_soc_hw_rule_channels(struct snd_pcm_hw_params *params, - struct snd_pcm_hw_rule *rule, - int is_play) +static int rsnd_soc_hw_rule_channels(struct snd_pcm_hw_params *params, + struct snd_pcm_hw_rule *rule) { struct snd_interval *ic_ = hw_param_interval(params, SNDRV_PCM_HW_PARAM_CHANNELS); struct snd_interval *ir = hw_param_interval(params, SNDRV_PCM_HW_PARAM_RATE); struct snd_interval ic; - struct snd_soc_dai *dai = rule->private; - struct rsnd_dai *rdai = rsnd_dai_to_rdai(dai); - struct rsnd_dai_stream *io = is_play ? &rdai->playback : &rdai->capture; + struct rsnd_dai_stream *io = rule->private; + struct rsnd_dai *rdai = rsnd_io_to_rdai(io); /* * possible sampling rate limitation is same as @@ -881,18 +865,6 @@ static int __rsnd_soc_hw_rule_channels(struct snd_pcm_hw_params *params, ir, &ic); } -static int rsnd_soc_hw_rule_channels_playback(struct snd_pcm_hw_params *params, - struct snd_pcm_hw_rule *rule) -{ - return __rsnd_soc_hw_rule_channels(params, rule, 1); -} - -static int rsnd_soc_hw_rule_channels_capture(struct snd_pcm_hw_params *params, - struct snd_pcm_hw_rule *rule) -{ - return __rsnd_soc_hw_rule_channels(params, rule, 0); -} - static const struct snd_pcm_hardware rsnd_pcm_hardware = { .info = SNDRV_PCM_INFO_INTERLEAVED | SNDRV_PCM_INFO_MMAP | @@ -949,14 +921,12 @@ static int rsnd_soc_dai_startup(struct snd_pcm_substream *substream, int is_play = substream->stream == SNDRV_PCM_STREAM_PLAYBACK; snd_pcm_hw_rule_add(runtime, 0, SNDRV_PCM_HW_PARAM_RATE, - is_play ? rsnd_soc_hw_rule_rate_playback : - rsnd_soc_hw_rule_rate_capture, - dai, + rsnd_soc_hw_rule_rate, + is_play ? &rdai->playback : &rdai->capture, SNDRV_PCM_HW_PARAM_CHANNELS, -1); snd_pcm_hw_rule_add(runtime, 0, SNDRV_PCM_HW_PARAM_CHANNELS, - is_play ? rsnd_soc_hw_rule_channels_playback : - rsnd_soc_hw_rule_channels_capture, - dai, + rsnd_soc_hw_rule_channels, + is_play ? &rdai->playback : &rdai->capture, SNDRV_PCM_HW_PARAM_RATE, -1); } From 0e289012b47a2de1f029a6b61c75998e2f159dd9 Mon Sep 17 00:00:00 2001 From: Jiada Wang Date: Mon, 3 Sep 2018 07:07:07 +0000 Subject: [PATCH 077/299] ASoC: rsnd: ssi: Fix issue in dma data address assignment Same SSI device may be used in different dai links, by only having one dma struct in rsnd_ssi, after the first instance's dma config be initilized, the following instances can no longer configure dma, this causes issue, when their dma data address are different from the first instance. Signed-off-by: Jiada Wang Signed-off-by: Timo Wischer [Kuninori: tidyup for upstream] Signed-off-by: Kuninori Morimoto Tested-by: Hiroyuki Yokoyama Signed-off-by: Mark Brown --- sound/soc/sh/rcar/rsnd.h | 1 + sound/soc/sh/rcar/ssi.c | 4 +--- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/sound/soc/sh/rcar/rsnd.h b/sound/soc/sh/rcar/rsnd.h index 698b08155b06..20e6a2ebebed 100644 --- a/sound/soc/sh/rcar/rsnd.h +++ b/sound/soc/sh/rcar/rsnd.h @@ -431,6 +431,7 @@ struct rsnd_dai_stream { char name[RSND_DAI_NAME_SIZE]; struct snd_pcm_substream *substream; struct rsnd_mod *mod[RSND_MOD_MAX]; + struct rsnd_mod *dma; struct rsnd_dai *rdai; struct device *dmac_dev; /* for IPMMU */ u32 parent_ssi_status; diff --git a/sound/soc/sh/rcar/ssi.c b/sound/soc/sh/rcar/ssi.c index 765ecc06c7c9..89cc433e2fc9 100644 --- a/sound/soc/sh/rcar/ssi.c +++ b/sound/soc/sh/rcar/ssi.c @@ -78,7 +78,6 @@ struct rsnd_ssi { struct rsnd_mod mod; - struct rsnd_mod *dma; u32 flags; u32 cr_own; @@ -899,7 +898,6 @@ static int rsnd_ssi_dma_probe(struct rsnd_mod *mod, struct rsnd_dai_stream *io, struct rsnd_priv *priv) { - struct rsnd_ssi *ssi = rsnd_mod_to_ssi(mod); int ret; /* @@ -914,7 +912,7 @@ static int rsnd_ssi_dma_probe(struct rsnd_mod *mod, return ret; /* SSI probe might be called many times in MUX multi path */ - ret = rsnd_dma_attach(io, mod, &ssi->dma); + ret = rsnd_dma_attach(io, mod, &io->dma); return ret; } From 599da084e041b877ef89211dcbb4c7bd8380049d Mon Sep 17 00:00:00 2001 From: Jiada Wang Date: Mon, 3 Sep 2018 07:07:26 +0000 Subject: [PATCH 078/299] ASoC: rsnd: ssi: Check runtime channel number rather than hw_params The number of channel handled by SSI maybe differs from the one set in hw_params, currently SSI checks hw_params's channel number, and constrains to use same channel number, when it is being used by multiple clients. This patch corrects to check runtime channel number rather than channel number set in hw_params. Signed-off-by: Jiada Wang Signed-off-by: Timo Wischer [kuninori: adjust to upstreaming] Signed-off-by: Kuninori Morimoto Tested-by: Hiroyuki Yokoyama Signed-off-by: Mark Brown --- sound/soc/sh/rcar/ssi.c | 27 +++++++-------------------- 1 file changed, 7 insertions(+), 20 deletions(-) diff --git a/sound/soc/sh/rcar/ssi.c b/sound/soc/sh/rcar/ssi.c index 89cc433e2fc9..3f6dd9f07bc6 100644 --- a/sound/soc/sh/rcar/ssi.c +++ b/sound/soc/sh/rcar/ssi.c @@ -307,6 +307,11 @@ static int rsnd_ssi_master_clk_start(struct rsnd_mod *mod, return -EINVAL; } + if (ssi->chan != chan) { + dev_err(dev, "SSI parent/child should use same chan\n"); + return -EINVAL; + } + return 0; } @@ -334,6 +339,7 @@ static int rsnd_ssi_master_clk_start(struct rsnd_mod *mod, SCKD | SWSD | CKDV(idx); ssi->wsr = CONT; ssi->rate = rate; + ssi->chan = chan; dev_dbg(dev, "%s[%d] outputs %u Hz\n", rsnd_mod_name(mod), @@ -359,6 +365,7 @@ static void rsnd_ssi_master_clk_stop(struct rsnd_mod *mod, ssi->cr_clk = 0; ssi->rate = 0; + ssi->chan = 0; rsnd_adg_ssi_clk_stop(mod); } @@ -511,9 +518,7 @@ static int rsnd_ssi_hw_params(struct rsnd_mod *mod, struct snd_pcm_substream *substream, struct snd_pcm_hw_params *params) { - struct rsnd_ssi *ssi = rsnd_mod_to_ssi(mod); struct rsnd_dai *rdai = rsnd_io_to_rdai(io); - int chan = params_channels(params); unsigned int fmt_width = snd_pcm_format_width(params_format(params)); if (fmt_width > rdai->chan_width) { @@ -524,24 +529,6 @@ static int rsnd_ssi_hw_params(struct rsnd_mod *mod, return -EINVAL; } - /* - * snd_pcm_ops::hw_params will be called *before* - * snd_soc_dai_ops::trigger. Thus, ssi->usrcnt is 0 - * in 1st call. - */ - if (ssi->usrcnt) { - /* - * Already working. - * It will happen if SSI has parent/child connection. - * it is error if child <-> parent SSI uses - * different channels. - */ - if (ssi->chan != chan) - return -EIO; - } - - ssi->chan = chan; - return 0; } From 5e45a6fab3b90ca300e13191fc68baaa8e37d1d4 Mon Sep 17 00:00:00 2001 From: Jiada Wang Date: Mon, 3 Sep 2018 07:07:43 +0000 Subject: [PATCH 079/299] ASoc: rsnd: dma: Calculate dma address with consider of BUSIF DMA address calculated by rsnd_dma_addr() only considers BUSIF0 so far. But BUSIF1 ~ BUSIF7 also maybe used, in the future. This patch updates DMA address calculations, to also consider BUSIF number used by SSI. One note is that we can't support SSI9-4/5/6/7 so far, because its address is out of calculation rule. Signed-off-by: Jiada Wang Signed-off-by: Timo Wischer [kuninori: adjust to upstreaming] Signed-off-by: Kuninori Morimoto Tested-by: Hiroyuki Yokoyama Signed-off-by: Mark Brown --- sound/soc/sh/rcar/dma.c | 43 +++++++++++++++++++++++++--------------- sound/soc/sh/rcar/rsnd.h | 1 + sound/soc/sh/rcar/ssi.c | 5 +++++ 3 files changed, 33 insertions(+), 16 deletions(-) diff --git a/sound/soc/sh/rcar/dma.c b/sound/soc/sh/rcar/dma.c index fe63ef8600d0..73f743ea3d08 100644 --- a/sound/soc/sh/rcar/dma.c +++ b/sound/soc/sh/rcar/dma.c @@ -487,11 +487,11 @@ static struct rsnd_mod_ops rsnd_dmapp_ops = { #define RDMA_SSI_I_N(addr, i) (addr ##_reg - 0x00300000 + (0x40 * i) + 0x8) #define RDMA_SSI_O_N(addr, i) (addr ##_reg - 0x00300000 + (0x40 * i) + 0xc) -#define RDMA_SSIU_I_N(addr, i) (addr ##_reg - 0x00441000 + (0x1000 * i)) -#define RDMA_SSIU_O_N(addr, i) (addr ##_reg - 0x00441000 + (0x1000 * i)) +#define RDMA_SSIU_I_N(addr, i, j) (addr ##_reg - 0x00441000 + (0x1000 * (i)) + (((j) / 4) * 0xA000) + (((j) % 4) * 0x400)) +#define RDMA_SSIU_O_N(addr, i, j) RDMA_SSIU_I_N(addr, i, j) -#define RDMA_SSIU_I_P(addr, i) (addr ##_reg - 0x00141000 + (0x1000 * i)) -#define RDMA_SSIU_O_P(addr, i) (addr ##_reg - 0x00141000 + (0x1000 * i)) +#define RDMA_SSIU_I_P(addr, i, j) (addr ##_reg - 0x00141000 + (0x1000 * (i)) + (((j) / 4) * 0xA000) + (((j) % 4) * 0x400)) +#define RDMA_SSIU_O_P(addr, i, j) RDMA_SSIU_I_P(addr, i, j) #define RDMA_SRC_I_N(addr, i) (addr ##_reg - 0x00500000 + (0x400 * i)) #define RDMA_SRC_O_N(addr, i) (addr ##_reg - 0x004fc000 + (0x400 * i)) @@ -517,6 +517,7 @@ rsnd_gen2_dma_addr(struct rsnd_dai_stream *io, !!rsnd_io_to_mod_mix(io) || !!rsnd_io_to_mod_ctu(io); int id = rsnd_mod_id(mod); + int busif = rsnd_ssi_get_busif(io); struct dma_addr { dma_addr_t out_addr; dma_addr_t in_addr; @@ -533,25 +534,35 @@ rsnd_gen2_dma_addr(struct rsnd_dai_stream *io, }, /* SSI */ /* Capture */ - {{{ RDMA_SSI_O_N(ssi, id), 0 }, - { RDMA_SSIU_O_P(ssi, id), 0 }, - { RDMA_SSIU_O_P(ssi, id), 0 } }, + {{{ RDMA_SSI_O_N(ssi, id), 0 }, + { RDMA_SSIU_O_P(ssi, id, busif), 0 }, + { RDMA_SSIU_O_P(ssi, id, busif), 0 } }, /* Playback */ - {{ 0, RDMA_SSI_I_N(ssi, id) }, - { 0, RDMA_SSIU_I_P(ssi, id) }, - { 0, RDMA_SSIU_I_P(ssi, id) } } + {{ 0, RDMA_SSI_I_N(ssi, id) }, + { 0, RDMA_SSIU_I_P(ssi, id, busif) }, + { 0, RDMA_SSIU_I_P(ssi, id, busif) } } }, /* SSIU */ /* Capture */ - {{{ RDMA_SSIU_O_N(ssi, id), 0 }, - { RDMA_SSIU_O_P(ssi, id), 0 }, - { RDMA_SSIU_O_P(ssi, id), 0 } }, + {{{ RDMA_SSIU_O_N(ssi, id, busif), 0 }, + { RDMA_SSIU_O_P(ssi, id, busif), 0 }, + { RDMA_SSIU_O_P(ssi, id, busif), 0 } }, /* Playback */ - {{ 0, RDMA_SSIU_I_N(ssi, id) }, - { 0, RDMA_SSIU_I_P(ssi, id) }, - { 0, RDMA_SSIU_I_P(ssi, id) } } }, + {{ 0, RDMA_SSIU_I_N(ssi, id, busif) }, + { 0, RDMA_SSIU_I_P(ssi, id, busif) }, + { 0, RDMA_SSIU_I_P(ssi, id, busif) } } }, }; + /* + * FIXME + * + * We can't support SSI9-4/5/6/7, because its address is + * out of calculation rule + */ + if ((id == 9) && (busif >= 4)) + dev_err(dev, "This driver doesn't support SSI%d-%d, so far", + id, busif); + /* it shouldn't happen */ if (use_cmd && !use_src) dev_err(dev, "DVC is selected without SRC\n"); diff --git a/sound/soc/sh/rcar/rsnd.h b/sound/soc/sh/rcar/rsnd.h index 20e6a2ebebed..cb27a679dc65 100644 --- a/sound/soc/sh/rcar/rsnd.h +++ b/sound/soc/sh/rcar/rsnd.h @@ -692,6 +692,7 @@ void rsnd_ssi_remove(struct rsnd_priv *priv); struct rsnd_mod *rsnd_ssi_mod_get(struct rsnd_priv *priv, int id); int rsnd_ssi_is_dma_mode(struct rsnd_mod *mod); int rsnd_ssi_use_busif(struct rsnd_dai_stream *io); +int rsnd_ssi_get_busif(struct rsnd_dai_stream *io); u32 rsnd_ssi_multi_slaves_runtime(struct rsnd_dai_stream *io); #define RSND_SSI_HDMI_PORT0 0xf0 diff --git a/sound/soc/sh/rcar/ssi.c b/sound/soc/sh/rcar/ssi.c index 3f6dd9f07bc6..85da4fc82011 100644 --- a/sound/soc/sh/rcar/ssi.c +++ b/sound/soc/sh/rcar/ssi.c @@ -150,6 +150,11 @@ int rsnd_ssi_use_busif(struct rsnd_dai_stream *io) return use_busif; } +int rsnd_ssi_get_busif(struct rsnd_dai_stream *io) +{ + return 0; /* BUSIF0 only for now */ +} + static void rsnd_ssi_status_clear(struct rsnd_mod *mod) { rsnd_mod_write(mod, SSISR, 0); From 92c7d384ff7282738c70720f8670c9b65c90c7df Mon Sep 17 00:00:00 2001 From: Jiada Wang Date: Mon, 3 Sep 2018 07:08:00 +0000 Subject: [PATCH 080/299] ASoc: rsnd: dma: Calculate PDMACHCRE with consider of BUSIF PDMACHCR setting for SSI only considers BUSIF0 so far. But BUSIF1 ~ BUSIF7 also maybe used, in the future. This patch updates table gen2_id_table_ssiu, to also consider BUSIF number used by SSI. Signed-off-by: Jiada Wang Signed-off-by: Timo Wischer [kuninori: adjust to upstreaming] Signed-off-by: Kuninori Morimoto Tested-by: Hiroyuki Yokoyama Signed-off-by: Mark Brown --- sound/soc/sh/rcar/dma.c | 37 ++++++++++++++++++++++++++----------- 1 file changed, 26 insertions(+), 11 deletions(-) diff --git a/sound/soc/sh/rcar/dma.c b/sound/soc/sh/rcar/dma.c index 73f743ea3d08..d3b1a4ae876a 100644 --- a/sound/soc/sh/rcar/dma.c +++ b/sound/soc/sh/rcar/dma.c @@ -298,16 +298,26 @@ static struct rsnd_mod_ops rsnd_dmaen_ops = { * Audio DMAC peri peri */ static const u8 gen2_id_table_ssiu[] = { - 0x00, /* SSI00 */ - 0x04, /* SSI10 */ - 0x08, /* SSI20 */ - 0x0c, /* SSI3 */ - 0x0d, /* SSI4 */ - 0x0e, /* SSI5 */ - 0x0f, /* SSI6 */ - 0x10, /* SSI7 */ - 0x11, /* SSI8 */ - 0x12, /* SSI90 */ + /* SSI00 ~ SSI07 */ + 0x00, 0x01, 0x02, 0x03, 0x39, 0x3a, 0x3b, 0x3c, + /* SSI10 ~ SSI17 */ + 0x04, 0x05, 0x06, 0x07, 0x3d, 0x3e, 0x3f, 0x40, + /* SSI20 ~ SSI27 */ + 0x08, 0x09, 0x0a, 0x0b, 0x41, 0x42, 0x43, 0x44, + /* SSI30 ~ SSI37 */ + 0x0c, 0x45, 0x46, 0x47, 0x48, 0x49, 0x4a, 0x4b, + /* SSI40 ~ SSI47 */ + 0x0d, 0x4c, 0x4d, 0x4e, 0x4f, 0x50, 0x51, 0x52, + /* SSI5 */ + 0x0e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + /* SSI6 */ + 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + /* SSI7 */ + 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + /* SSI8 */ + 0x11, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + /* SSI90 ~ SSI97 */ + 0x12, 0x13, 0x14, 0x15, 0x53, 0x54, 0x55, 0x56, }; static const u8 gen2_id_table_scu[] = { 0x2d, /* SCU_SRCI0 */ @@ -333,18 +343,23 @@ static u32 rsnd_dmapp_get_id(struct rsnd_dai_stream *io, struct rsnd_mod *src = rsnd_io_to_mod_src(io); struct rsnd_mod *dvc = rsnd_io_to_mod_dvc(io); const u8 *entry = NULL; - int id = rsnd_mod_id(mod); + int id = 255; int size = 0; if (mod == ssi) { + int busif = rsnd_ssi_get_busif(io); + entry = gen2_id_table_ssiu; size = ARRAY_SIZE(gen2_id_table_ssiu); + id = (rsnd_mod_id(mod) * 8) + busif; } else if (mod == src) { entry = gen2_id_table_scu; size = ARRAY_SIZE(gen2_id_table_scu); + id = rsnd_mod_id(mod); } else if (mod == dvc) { entry = gen2_id_table_cmd; size = ARRAY_SIZE(gen2_id_table_cmd); + id = rsnd_mod_id(mod); } if ((!entry) || (size <= id)) { From 8c9d750333408420a1e4816b1820f10be2a84af6 Mon Sep 17 00:00:00 2001 From: Jiada Wang Date: Mon, 3 Sep 2018 07:08:20 +0000 Subject: [PATCH 081/299] ASoC: rsnd: ssiu: Support BUSIF other than BUSIF0 Currently only BUSIF0 is supported by SSIU, all register setting is done only for BUSIF. Since BUSIF1 ~ BUSIF7 has been supported, so also support these BUSIF from SSIU. One note is that we can't support SSI9-4/5/6/7 so far, because its address is out of calculation rule. Signed-off-by: Jiada Wang Signed-off-by: Timo Wischer [Kuninori: tidyup for upstream] Signed-off-by: Kuninori Morimoto Tested-by: Hiroyuki Yokoyama Signed-off-by: Mark Brown --- sound/soc/sh/rcar/gen.c | 27 ++++++++++++++-- sound/soc/sh/rcar/rsnd.h | 27 ++++++++++++++-- sound/soc/sh/rcar/ssiu.c | 70 +++++++++++++++++++++++++++++++++------- 3 files changed, 107 insertions(+), 17 deletions(-) diff --git a/sound/soc/sh/rcar/gen.c b/sound/soc/sh/rcar/gen.c index 0230301fe078..3032869a7f26 100644 --- a/sound/soc/sh/rcar/gen.c +++ b/sound/soc/sh/rcar/gen.c @@ -219,9 +219,30 @@ static int rsnd_gen2_probe(struct rsnd_priv *priv) RSND_GEN_S_REG(HDMI1_SEL, 0x9e4), /* FIXME: it needs SSI_MODE2/3 in the future */ - RSND_GEN_M_REG(SSI_BUSIF_MODE, 0x0, 0x80), - RSND_GEN_M_REG(SSI_BUSIF_ADINR, 0x4, 0x80), - RSND_GEN_M_REG(SSI_BUSIF_DALIGN,0x8, 0x80), + RSND_GEN_M_REG(SSI_BUSIF0_MODE, 0x0, 0x80), + RSND_GEN_M_REG(SSI_BUSIF0_ADINR, 0x4, 0x80), + RSND_GEN_M_REG(SSI_BUSIF0_DALIGN, 0x8, 0x80), + RSND_GEN_M_REG(SSI_BUSIF1_MODE, 0x20, 0x80), + RSND_GEN_M_REG(SSI_BUSIF1_ADINR, 0x24, 0x80), + RSND_GEN_M_REG(SSI_BUSIF1_DALIGN, 0x28, 0x80), + RSND_GEN_M_REG(SSI_BUSIF2_MODE, 0x40, 0x80), + RSND_GEN_M_REG(SSI_BUSIF2_ADINR, 0x44, 0x80), + RSND_GEN_M_REG(SSI_BUSIF2_DALIGN, 0x48, 0x80), + RSND_GEN_M_REG(SSI_BUSIF3_MODE, 0x60, 0x80), + RSND_GEN_M_REG(SSI_BUSIF3_ADINR, 0x64, 0x80), + RSND_GEN_M_REG(SSI_BUSIF3_DALIGN, 0x68, 0x80), + RSND_GEN_M_REG(SSI_BUSIF4_MODE, 0x500, 0x80), + RSND_GEN_M_REG(SSI_BUSIF4_ADINR, 0x504, 0x80), + RSND_GEN_M_REG(SSI_BUSIF4_DALIGN, 0x508, 0x80), + RSND_GEN_M_REG(SSI_BUSIF5_MODE, 0x520, 0x80), + RSND_GEN_M_REG(SSI_BUSIF5_ADINR, 0x524, 0x80), + RSND_GEN_M_REG(SSI_BUSIF5_DALIGN, 0x528, 0x80), + RSND_GEN_M_REG(SSI_BUSIF6_MODE, 0x540, 0x80), + RSND_GEN_M_REG(SSI_BUSIF6_ADINR, 0x544, 0x80), + RSND_GEN_M_REG(SSI_BUSIF6_DALIGN, 0x548, 0x80), + RSND_GEN_M_REG(SSI_BUSIF7_MODE, 0x560, 0x80), + RSND_GEN_M_REG(SSI_BUSIF7_ADINR, 0x564, 0x80), + RSND_GEN_M_REG(SSI_BUSIF7_DALIGN, 0x568, 0x80), RSND_GEN_M_REG(SSI_MODE, 0xc, 0x80), RSND_GEN_M_REG(SSI_CTRL, 0x10, 0x80), RSND_GEN_M_REG(SSI_INT_ENABLE, 0x18, 0x80), diff --git a/sound/soc/sh/rcar/rsnd.h b/sound/soc/sh/rcar/rsnd.h index cb27a679dc65..7ff58b0e8002 100644 --- a/sound/soc/sh/rcar/rsnd.h +++ b/sound/soc/sh/rcar/rsnd.h @@ -156,9 +156,30 @@ enum rsnd_reg { RSND_REG_SSI_MODE2, RSND_REG_SSI_CONTROL, RSND_REG_SSI_CTRL, - RSND_REG_SSI_BUSIF_MODE, - RSND_REG_SSI_BUSIF_ADINR, - RSND_REG_SSI_BUSIF_DALIGN, + RSND_REG_SSI_BUSIF0_MODE, + RSND_REG_SSI_BUSIF0_ADINR, + RSND_REG_SSI_BUSIF0_DALIGN, + RSND_REG_SSI_BUSIF1_MODE, + RSND_REG_SSI_BUSIF1_ADINR, + RSND_REG_SSI_BUSIF1_DALIGN, + RSND_REG_SSI_BUSIF2_MODE, + RSND_REG_SSI_BUSIF2_ADINR, + RSND_REG_SSI_BUSIF2_DALIGN, + RSND_REG_SSI_BUSIF3_MODE, + RSND_REG_SSI_BUSIF3_ADINR, + RSND_REG_SSI_BUSIF3_DALIGN, + RSND_REG_SSI_BUSIF4_MODE, + RSND_REG_SSI_BUSIF4_ADINR, + RSND_REG_SSI_BUSIF4_DALIGN, + RSND_REG_SSI_BUSIF5_MODE, + RSND_REG_SSI_BUSIF5_ADINR, + RSND_REG_SSI_BUSIF5_DALIGN, + RSND_REG_SSI_BUSIF6_MODE, + RSND_REG_SSI_BUSIF6_ADINR, + RSND_REG_SSI_BUSIF6_DALIGN, + RSND_REG_SSI_BUSIF7_MODE, + RSND_REG_SSI_BUSIF7_ADINR, + RSND_REG_SSI_BUSIF7_DALIGN, RSND_REG_SSI_INT_ENABLE, RSND_REG_SSI_SYS_STATUS0, RSND_REG_SSI_SYS_STATUS1, diff --git a/sound/soc/sh/rcar/ssiu.c b/sound/soc/sh/rcar/ssiu.c index 016fbf5ac242..a9605a0163f2 100644 --- a/sound/soc/sh/rcar/ssiu.c +++ b/sound/soc/sh/rcar/ssiu.c @@ -140,15 +140,59 @@ static int rsnd_ssiu_init_gen2(struct rsnd_mod *mod, rsnd_mod_write(mod, SSI_MODE, mode); if (rsnd_ssi_use_busif(io)) { - rsnd_mod_write(mod, SSI_BUSIF_ADINR, - rsnd_get_adinr_bit(mod, io) | - (rsnd_io_is_play(io) ? - rsnd_runtime_channel_after_ctu(io) : - rsnd_runtime_channel_original(io))); - rsnd_mod_write(mod, SSI_BUSIF_MODE, - rsnd_get_busif_shift(io, mod) | 1); - rsnd_mod_write(mod, SSI_BUSIF_DALIGN, - rsnd_get_dalign(mod, io)); + int id = rsnd_mod_id(mod); + int busif = rsnd_ssi_get_busif(io); + + /* + * FIXME + * + * We can't support SSI9-4/5/6/7, because its address is + * out of calculation rule + */ + if ((id == 9) && (busif >= 4)) { + struct device *dev = rsnd_priv_to_dev(priv); + + dev_err(dev, "This driver doesn't support SSI%d-%d, so far", + id, busif); + } + +#define RSND_WRITE_BUSIF(i) \ + rsnd_mod_write(mod, SSI_BUSIF##i##_ADINR, \ + rsnd_get_adinr_bit(mod, io) | \ + (rsnd_io_is_play(io) ? \ + rsnd_runtime_channel_after_ctu(io) : \ + rsnd_runtime_channel_original(io))); \ + rsnd_mod_write(mod, SSI_BUSIF##i##_MODE, \ + rsnd_get_busif_shift(io, mod) | 1); \ + rsnd_mod_write(mod, SSI_BUSIF##i##_DALIGN, \ + rsnd_get_dalign(mod, io)) + + switch (busif) { + case 0: + RSND_WRITE_BUSIF(0); + break; + case 1: + RSND_WRITE_BUSIF(1); + break; + case 2: + RSND_WRITE_BUSIF(2); + break; + case 3: + RSND_WRITE_BUSIF(3); + break; + case 4: + RSND_WRITE_BUSIF(4); + break; + case 5: + RSND_WRITE_BUSIF(5); + break; + case 6: + RSND_WRITE_BUSIF(6); + break; + case 7: + RSND_WRITE_BUSIF(7); + break; + } } if (hdmi) { @@ -194,10 +238,12 @@ static int rsnd_ssiu_start_gen2(struct rsnd_mod *mod, struct rsnd_dai_stream *io, struct rsnd_priv *priv) { + int busif = rsnd_ssi_get_busif(io); + if (!rsnd_ssi_use_busif(io)) return 0; - rsnd_mod_write(mod, SSI_CTRL, 0x1); + rsnd_mod_bset(mod, SSI_CTRL, 1 << (busif * 4), 1 << (busif * 4)); if (rsnd_ssi_multi_slaves_runtime(io)) rsnd_mod_write(mod, SSI_CONTROL, 0x1); @@ -209,10 +255,12 @@ static int rsnd_ssiu_stop_gen2(struct rsnd_mod *mod, struct rsnd_dai_stream *io, struct rsnd_priv *priv) { + int busif = rsnd_ssi_get_busif(io); + if (!rsnd_ssi_use_busif(io)) return 0; - rsnd_mod_write(mod, SSI_CTRL, 0); + rsnd_mod_bset(mod, SSI_CTRL, 1 << (busif * 4), 0); if (rsnd_ssi_multi_slaves_runtime(io)) rsnd_mod_write(mod, SSI_CONTROL, 0); From 2e66d523cd055ac3fa920f7e630c4bfa80d24c24 Mon Sep 17 00:00:00 2001 From: Jiada Wang Date: Mon, 3 Sep 2018 07:08:37 +0000 Subject: [PATCH 082/299] ASoC: rsnd: ssiu: Support to init different BUSIF instance Currently ssiu's .init is only called once during audio stream. But SSIU with different BUSIF, shall be initialized each time, even they are used in the same audio stream. This patch introduces ssiu_status for BUSIF0 to BUSIF7 in rsnd_ssiu, to make sure same .init for different BUSIF can always be executed. To avoid the first stopped stream to stop the whole SSIU, which may still has other BUSIF instance running, use usrcnt to count the usage of SSIU, only the last user of SSIU can stop the whole SSIU. Signed-off-by: Jiada Wang Signed-off-by: Timo Wischer [Kuninori: tidyup for upstream] Signed-off-by: Kuninori Morimoto Tested-by: Hiroyuki Yokoyama Signed-off-by: Mark Brown --- sound/soc/sh/rcar/ssiu.c | 22 +++++++++++++++++++++- 1 file changed, 21 insertions(+), 1 deletion(-) diff --git a/sound/soc/sh/rcar/ssiu.c b/sound/soc/sh/rcar/ssiu.c index a9605a0163f2..39b67643b5dc 100644 --- a/sound/soc/sh/rcar/ssiu.c +++ b/sound/soc/sh/rcar/ssiu.c @@ -10,9 +10,12 @@ struct rsnd_ssiu { struct rsnd_mod mod; + u32 busif_status[8]; /* for BUSIF0 - BUSIF7 */ + unsigned int usrcnt; }; #define rsnd_ssiu_nr(priv) ((priv)->ssiu_nr) +#define rsnd_mod_to_ssiu(_mod) container_of((_mod), struct rsnd_ssiu, mod) #define for_each_rsnd_ssiu(pos, priv, i) \ for (i = 0; \ (i < rsnd_ssiu_nr(priv)) && \ @@ -120,6 +123,7 @@ static int rsnd_ssiu_init_gen2(struct rsnd_mod *mod, struct rsnd_dai_stream *io, struct rsnd_priv *priv) { + struct rsnd_ssiu *ssiu = rsnd_mod_to_ssiu(mod); int hdmi = rsnd_ssi_hdmi_port(io); int ret; u32 mode = 0; @@ -128,6 +132,8 @@ static int rsnd_ssiu_init_gen2(struct rsnd_mod *mod, if (ret < 0) return ret; + ssiu->usrcnt++; + if (rsnd_runtime_is_ssi_tdm(io)) { /* * TDM Extend Mode @@ -255,6 +261,7 @@ static int rsnd_ssiu_stop_gen2(struct rsnd_mod *mod, struct rsnd_dai_stream *io, struct rsnd_priv *priv) { + struct rsnd_ssiu *ssiu = rsnd_mod_to_ssiu(mod); int busif = rsnd_ssi_get_busif(io); if (!rsnd_ssi_use_busif(io)) @@ -262,6 +269,9 @@ static int rsnd_ssiu_stop_gen2(struct rsnd_mod *mod, rsnd_mod_bset(mod, SSI_CTRL, 1 << (busif * 4), 0); + if (--ssiu->usrcnt) + return 0; + if (rsnd_ssi_multi_slaves_runtime(io)) rsnd_mod_write(mod, SSI_CONTROL, 0); @@ -294,6 +304,16 @@ int rsnd_ssiu_attach(struct rsnd_dai_stream *io, return rsnd_dai_connect(mod, io, mod->type); } +static u32 *rsnd_ssiu_get_status(struct rsnd_dai_stream *io, + struct rsnd_mod *mod, + enum rsnd_mod_type type) +{ + struct rsnd_ssiu *ssiu = rsnd_mod_to_ssiu(mod); + int busif = rsnd_ssi_get_busif(io); + + return &ssiu->busif_status[busif]; +} + int rsnd_ssiu_probe(struct rsnd_priv *priv) { struct device *dev = rsnd_priv_to_dev(priv); @@ -317,7 +337,7 @@ int rsnd_ssiu_probe(struct rsnd_priv *priv) for_each_rsnd_ssiu(ssiu, priv, i) { ret = rsnd_mod_init(priv, rsnd_mod_get(ssiu), - ops, NULL, rsnd_mod_get_status, + ops, NULL, rsnd_ssiu_get_status, RSND_MOD_SSIU, i); if (ret) return ret; From 6ab6a2474e0dce02f71e92adb9778a168a8931f4 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Mon, 3 Sep 2018 07:09:17 +0000 Subject: [PATCH 083/299] ASoC: rsnd: merge .nolock_start and .prepare Main purpose of .nolock_start is we need to call some function without spinlock. OTOH we have .prepare which main purpose is called under atomic context. Then, it is called without spinlock. In summary, our main callback init/quit, and start/stop are called under "atomic context and with spinlock". And some function need to be called under "non-atomic context or without spinlock". Let's merge .nolock_start and prepare to be more clear code. Then, let's rename nolock_stop to cleanup Signed-off-by: Kuninori Morimoto Tested-by: Hiroyuki Yokoyama Signed-off-by: Mark Brown --- sound/soc/sh/rcar/core.c | 13 ++----------- sound/soc/sh/rcar/dma.c | 20 ++++++++++---------- sound/soc/sh/rcar/rsnd.h | 26 ++++++++++---------------- 3 files changed, 22 insertions(+), 37 deletions(-) diff --git a/sound/soc/sh/rcar/core.c b/sound/soc/sh/rcar/core.c index 299fb457573d..e46415c807a0 100644 --- a/sound/soc/sh/rcar/core.c +++ b/sound/soc/sh/rcar/core.c @@ -881,12 +881,10 @@ static int rsnd_soc_dai_startup(struct snd_pcm_substream *substream, struct snd_soc_dai *dai) { struct rsnd_dai *rdai = rsnd_dai_to_rdai(dai); - struct rsnd_priv *priv = rsnd_rdai_to_priv(rdai); struct rsnd_dai_stream *io = rsnd_rdai_to_io(rdai, substream); struct snd_pcm_hw_constraint_list *constraint = &rdai->constraint; struct snd_pcm_runtime *runtime = substream->runtime; unsigned int max_channels = rsnd_rdai_channels_get(rdai); - int ret; int i; rsnd_dai_stream_init(io, substream); @@ -930,14 +928,7 @@ static int rsnd_soc_dai_startup(struct snd_pcm_substream *substream, SNDRV_PCM_HW_PARAM_RATE, -1); } - /* - * call rsnd_dai_call without spinlock - */ - ret = rsnd_dai_call(nolock_start, io, priv); - if (ret < 0) - rsnd_dai_call(nolock_stop, io, priv); - - return ret; + return 0; } static void rsnd_soc_dai_shutdown(struct snd_pcm_substream *substream, @@ -950,7 +941,7 @@ static void rsnd_soc_dai_shutdown(struct snd_pcm_substream *substream, /* * call rsnd_dai_call without spinlock */ - rsnd_dai_call(nolock_stop, io, priv); + rsnd_dai_call(cleanup, io, priv); rsnd_dai_stream_quit(io); } diff --git a/sound/soc/sh/rcar/dma.c b/sound/soc/sh/rcar/dma.c index d3b1a4ae876a..f99c1ab3b0bd 100644 --- a/sound/soc/sh/rcar/dma.c +++ b/sound/soc/sh/rcar/dma.c @@ -106,9 +106,9 @@ static int rsnd_dmaen_stop(struct rsnd_mod *mod, return 0; } -static int rsnd_dmaen_nolock_stop(struct rsnd_mod *mod, - struct rsnd_dai_stream *io, - struct rsnd_priv *priv) +static int rsnd_dmaen_cleanup(struct rsnd_mod *mod, + struct rsnd_dai_stream *io, + struct rsnd_priv *priv) { struct rsnd_dma *dma = rsnd_mod_to_dma(mod); struct rsnd_dmaen *dmaen = rsnd_dma_to_dmaen(dma); @@ -116,7 +116,7 @@ static int rsnd_dmaen_nolock_stop(struct rsnd_mod *mod, /* * DMAEngine release uses mutex lock. * Thus, it shouldn't be called under spinlock. - * Let's call it under nolock_start + * Let's call it under prepare */ if (dmaen->chan) dma_release_channel(dmaen->chan); @@ -126,9 +126,9 @@ static int rsnd_dmaen_nolock_stop(struct rsnd_mod *mod, return 0; } -static int rsnd_dmaen_nolock_start(struct rsnd_mod *mod, - struct rsnd_dai_stream *io, - struct rsnd_priv *priv) +static int rsnd_dmaen_prepare(struct rsnd_mod *mod, + struct rsnd_dai_stream *io, + struct rsnd_priv *priv) { struct rsnd_dma *dma = rsnd_mod_to_dma(mod); struct rsnd_dmaen *dmaen = rsnd_dma_to_dmaen(dma); @@ -142,7 +142,7 @@ static int rsnd_dmaen_nolock_start(struct rsnd_mod *mod, /* * DMAEngine request uses mutex lock. * Thus, it shouldn't be called under spinlock. - * Let's call it under nolock_start + * Let's call it under prepare */ dmaen->chan = rsnd_dmaen_request_channel(io, dma->mod_from, @@ -287,8 +287,8 @@ static int rsnd_dmaen_pointer(struct rsnd_mod *mod, static struct rsnd_mod_ops rsnd_dmaen_ops = { .name = "audmac", - .nolock_start = rsnd_dmaen_nolock_start, - .nolock_stop = rsnd_dmaen_nolock_stop, + .prepare = rsnd_dmaen_prepare, + .cleanup = rsnd_dmaen_cleanup, .start = rsnd_dmaen_start, .stop = rsnd_dmaen_stop, .pointer= rsnd_dmaen_pointer, diff --git a/sound/soc/sh/rcar/rsnd.h b/sound/soc/sh/rcar/rsnd.h index 7a04b19e405c..e857311ee5c1 100644 --- a/sound/soc/sh/rcar/rsnd.h +++ b/sound/soc/sh/rcar/rsnd.h @@ -295,15 +295,12 @@ struct rsnd_mod_ops { int (*fallback)(struct rsnd_mod *mod, struct rsnd_dai_stream *io, struct rsnd_priv *priv); - int (*nolock_start)(struct rsnd_mod *mod, - struct rsnd_dai_stream *io, - struct rsnd_priv *priv); - int (*nolock_stop)(struct rsnd_mod *mod, - struct rsnd_dai_stream *io, - struct rsnd_priv *priv); int (*prepare)(struct rsnd_mod *mod, struct rsnd_dai_stream *io, struct rsnd_priv *priv); + int (*cleanup)(struct rsnd_mod *mod, + struct rsnd_dai_stream *io, + struct rsnd_priv *priv); }; struct rsnd_dai_stream; @@ -323,7 +320,7 @@ struct rsnd_mod { * * 0xH0000CBA * - * A 0: nolock_start 1: nolock_stop + * A 0: prepare 1: cleanup * B 0: init 1: quit * C 0: start 1: stop * @@ -335,8 +332,8 @@ struct rsnd_mod { * H 0: pointer * H 0: prepare */ -#define __rsnd_mod_shift_nolock_start 0 -#define __rsnd_mod_shift_nolock_stop 0 +#define __rsnd_mod_shift_prepare 0 +#define __rsnd_mod_shift_cleanup 0 #define __rsnd_mod_shift_init 4 #define __rsnd_mod_shift_quit 4 #define __rsnd_mod_shift_start 8 @@ -348,12 +345,11 @@ struct rsnd_mod { #define __rsnd_mod_shift_fallback 28 /* always called */ #define __rsnd_mod_shift_hw_params 28 /* always called */ #define __rsnd_mod_shift_pointer 28 /* always called */ -#define __rsnd_mod_shift_prepare 28 /* always called */ #define __rsnd_mod_add_probe 0 #define __rsnd_mod_add_remove 0 -#define __rsnd_mod_add_nolock_start 1 -#define __rsnd_mod_add_nolock_stop -1 +#define __rsnd_mod_add_prepare 1 +#define __rsnd_mod_add_cleanup -1 #define __rsnd_mod_add_init 1 #define __rsnd_mod_add_quit -1 #define __rsnd_mod_add_start 1 @@ -363,10 +359,11 @@ struct rsnd_mod { #define __rsnd_mod_add_fallback 0 #define __rsnd_mod_add_hw_params 0 #define __rsnd_mod_add_pointer 0 -#define __rsnd_mod_add_prepare 0 #define __rsnd_mod_call_probe 0 #define __rsnd_mod_call_remove 0 +#define __rsnd_mod_call_prepare 0 +#define __rsnd_mod_call_cleanup 1 #define __rsnd_mod_call_init 0 #define __rsnd_mod_call_quit 1 #define __rsnd_mod_call_start 0 @@ -376,9 +373,6 @@ struct rsnd_mod { #define __rsnd_mod_call_fallback 0 #define __rsnd_mod_call_hw_params 0 #define __rsnd_mod_call_pointer 0 -#define __rsnd_mod_call_nolock_start 0 -#define __rsnd_mod_call_nolock_stop 1 -#define __rsnd_mod_call_prepare 0 #define rsnd_mod_to_priv(mod) ((mod)->priv) #define rsnd_mod_name(mod) ((mod)->ops->name) From a45f8853a5f95e3760dfbd7ba09d3d597d247040 Mon Sep 17 00:00:00 2001 From: Codrin Ciubotariu Date: Fri, 31 Aug 2018 20:14:35 +0300 Subject: [PATCH 084/299] ASoC: Add driver for PROTO Audio CODEC (with a WM8731) Add support for the MikroElektronika PROTO audio codec board. URL to the audio chip: http://www.mikroe.com/add-on-boards/audio-voice/audio-codec-proto/ Signed-off-by: Florian Meier Signed-off-by: Codrin Ciubotariu Signed-off-by: Mark Brown --- sound/soc/atmel/Kconfig | 11 +++ sound/soc/atmel/Makefile | 2 + sound/soc/atmel/mikroe-proto.c | 165 +++++++++++++++++++++++++++++++++ 3 files changed, 178 insertions(+) create mode 100644 sound/soc/atmel/mikroe-proto.c diff --git a/sound/soc/atmel/Kconfig b/sound/soc/atmel/Kconfig index 64b784e96f84..81a0712d4f14 100644 --- a/sound/soc/atmel/Kconfig +++ b/sound/soc/atmel/Kconfig @@ -97,4 +97,15 @@ config SND_ATMEL_SOC_I2S help Say Y or M if you want to add support for Atmel ASoc driver for boards using I2S. + +config SND_SOC_MIKROE_PROTO + tristate "Support for Mikroe-PROTO board" + depends on OF + select SND_SOC_WM8731 + help + Say Y or M if you want to add support for MikroElektronika PROTO Audio + Board. This board contains the WM8731 codec, which can be configured + using I2C over SDA (MPU Data Input) and SCL (MPU Clock Input) pins. + Both playback and capture are supported. + endif diff --git a/sound/soc/atmel/Makefile b/sound/soc/atmel/Makefile index cd87cb4bcff5..9f41bfa0fea3 100644 --- a/sound/soc/atmel/Makefile +++ b/sound/soc/atmel/Makefile @@ -17,6 +17,7 @@ snd-soc-sam9x5-wm8731-objs := sam9x5_wm8731.o snd-atmel-soc-classd-objs := atmel-classd.o snd-atmel-soc-pdmic-objs := atmel-pdmic.o snd-atmel-soc-tse850-pcm5142-objs := tse850-pcm5142.o +snd-soc-mikroe-proto-objs := mikroe-proto.o obj-$(CONFIG_SND_AT91_SOC_SAM9G20_WM8731) += snd-soc-sam9g20-wm8731.o obj-$(CONFIG_SND_ATMEL_SOC_WM8904) += snd-atmel-soc-wm8904.o @@ -24,3 +25,4 @@ obj-$(CONFIG_SND_AT91_SOC_SAM9X5_WM8731) += snd-soc-sam9x5-wm8731.o obj-$(CONFIG_SND_ATMEL_SOC_CLASSD) += snd-atmel-soc-classd.o obj-$(CONFIG_SND_ATMEL_SOC_PDMIC) += snd-atmel-soc-pdmic.o obj-$(CONFIG_SND_ATMEL_SOC_TSE850_PCM5142) += snd-atmel-soc-tse850-pcm5142.o +obj-$(CONFIG_SND_SOC_MIKROE_PROTO) += snd-soc-mikroe-proto.o diff --git a/sound/soc/atmel/mikroe-proto.c b/sound/soc/atmel/mikroe-proto.c new file mode 100644 index 000000000000..d47aaa5bf75a --- /dev/null +++ b/sound/soc/atmel/mikroe-proto.c @@ -0,0 +1,165 @@ +/* + * ASoC driver for PROTO AudioCODEC (with a WM8731) + * + * Author: Florian Meier, + * Copyright 2013 + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#include +#include + +#include +#include +#include +#include + +#include "../codecs/wm8731.h" + +#define XTAL_RATE 12288000 /* This is fixed on this board */ + +static int snd_proto_init(struct snd_soc_pcm_runtime *rtd) +{ + struct snd_soc_card *card = rtd->card; + struct snd_soc_dai *codec_dai = rtd->codec_dai; + + /* Set proto sysclk */ + int ret = snd_soc_dai_set_sysclk(codec_dai, WM8731_SYSCLK_XTAL, + XTAL_RATE, SND_SOC_CLOCK_IN); + if (ret < 0) { + dev_err(card->dev, "Failed to set WM8731 SYSCLK: %d\n", + ret); + return ret; + } + + return 0; +} + +static const struct snd_soc_dapm_widget snd_proto_widget[] = { + SND_SOC_DAPM_MIC("Microphone Jack", NULL), + SND_SOC_DAPM_HP("Headphone Jack", NULL), +}; + +static const struct snd_soc_dapm_route snd_proto_route[] = { + /* speaker connected to LHPOUT/RHPOUT */ + {"Headphone Jack", NULL, "LHPOUT"}, + {"Headphone Jack", NULL, "RHPOUT"}, + + /* mic is connected to Mic Jack, with WM8731 Mic Bias */ + {"MICIN", NULL, "Mic Bias"}, + {"Mic Bias", NULL, "Microphone Jack"}, +}; + +/* audio machine driver */ +static struct snd_soc_card snd_proto = { + .name = "snd_mikroe_proto", + .owner = THIS_MODULE, + .dapm_widgets = snd_proto_widget, + .num_dapm_widgets = ARRAY_SIZE(snd_proto_widget), + .dapm_routes = snd_proto_route, + .num_dapm_routes = ARRAY_SIZE(snd_proto_route), +}; + +static int snd_proto_probe(struct platform_device *pdev) +{ + struct snd_soc_dai_link *dai; + struct device_node *np = pdev->dev.of_node; + struct device_node *codec_np, *cpu_np; + struct device_node *bitclkmaster = NULL; + struct device_node *framemaster = NULL; + unsigned int dai_fmt; + int ret = 0; + + if (!np) { + dev_err(&pdev->dev, "No device node supplied\n"); + return -EINVAL; + } + + snd_proto.dev = &pdev->dev; + ret = snd_soc_of_parse_card_name(&snd_proto, "model"); + if (ret) + return ret; + + dai = devm_kzalloc(&pdev->dev, sizeof(*dai), GFP_KERNEL); + if (!dai) + return -ENOMEM; + + snd_proto.dai_link = dai; + snd_proto.num_links = 1; + + dai->name = "WM8731"; + dai->stream_name = "WM8731 HiFi"; + dai->codec_dai_name = "wm8731-hifi"; + dai->init = &snd_proto_init; + + codec_np = of_parse_phandle(np, "audio-codec", 0); + if (!codec_np) { + dev_err(&pdev->dev, "audio-codec node missing\n"); + return -EINVAL; + } + dai->codec_of_node = codec_np; + + cpu_np = of_parse_phandle(np, "i2s-controller", 0); + if (!cpu_np) { + dev_err(&pdev->dev, "i2s-controller missing\n"); + return -EINVAL; + } + dai->cpu_of_node = cpu_np; + dai->platform_of_node = cpu_np; + + dai_fmt = snd_soc_of_parse_daifmt(np, NULL, + &bitclkmaster, &framemaster); + if (bitclkmaster != framemaster) { + dev_err(&pdev->dev, "Must be the same bitclock and frame master\n"); + return -EINVAL; + } + if (bitclkmaster) { + dai_fmt &= ~SND_SOC_DAIFMT_MASTER_MASK; + if (codec_np == bitclkmaster) + dai_fmt |= SND_SOC_DAIFMT_CBM_CFM; + else + dai_fmt |= SND_SOC_DAIFMT_CBS_CFS; + } + of_node_put(bitclkmaster); + of_node_put(framemaster); + dai->dai_fmt = dai_fmt; + + of_node_put(codec_np); + of_node_put(cpu_np); + + ret = snd_soc_register_card(&snd_proto); + if (ret && ret != -EPROBE_DEFER) + dev_err(&pdev->dev, + "snd_soc_register_card() failed: %d\n", ret); + + return ret; +} + +static int snd_proto_remove(struct platform_device *pdev) +{ + return snd_soc_unregister_card(&snd_proto); +} + +static const struct of_device_id snd_proto_of_match[] = { + { .compatible = "mikroe,mikroe-proto", }, + {}, +}; +MODULE_DEVICE_TABLE(of, snd_proto_of_match); + +static struct platform_driver snd_proto_driver = { + .driver = { + .name = "snd-mikroe-proto", + .of_match_table = snd_proto_of_match, + }, + .probe = snd_proto_probe, + .remove = snd_proto_remove, +}; + +module_platform_driver(snd_proto_driver); + +MODULE_AUTHOR("Florian Meier"); +MODULE_DESCRIPTION("ASoC Driver for PROTO board (WM8731)"); +MODULE_LICENSE("GPL"); From 85e16fdd2f25ef6b08b4275acd5f60fdccfe0973 Mon Sep 17 00:00:00 2001 From: Codrin Ciubotariu Date: Fri, 31 Aug 2018 20:14:36 +0300 Subject: [PATCH 085/299] ASoC: mikroe-proto: dt-bindings: add DT bindings for PROTO board DT binding documentation for this new ASoC driver. Signed-off-by: Codrin Ciubotariu Signed-off-by: Mark Brown --- .../bindings/sound/mikroe,mikroe-proto.txt | 23 +++++++++++++++++++ .../devicetree/bindings/vendor-prefixes.txt | 1 + 2 files changed, 24 insertions(+) create mode 100644 Documentation/devicetree/bindings/sound/mikroe,mikroe-proto.txt diff --git a/Documentation/devicetree/bindings/sound/mikroe,mikroe-proto.txt b/Documentation/devicetree/bindings/sound/mikroe,mikroe-proto.txt new file mode 100644 index 000000000000..912f8fae11c5 --- /dev/null +++ b/Documentation/devicetree/bindings/sound/mikroe,mikroe-proto.txt @@ -0,0 +1,23 @@ +Mikroe-PROTO audio board + +Required properties: + - compatible: "mikroe,mikroe-proto" + - dai-format: Must be "i2s". + - i2s-controller: The phandle of the I2S controller. + - audio-codec: The phandle of the WM8731 audio codec. +Optional properties: + - model: The user-visible name of this sound complex. + - bitclock-master: Indicates dai-link bit clock master; for details see simple-card.txt (1). + - frame-master: Indicates dai-link frame master; for details see simple-card.txt (1). + +(1) : There must be the same master for both bit and frame clocks. + +Example: + sound { + compatible = "mikroe,mikroe-proto"; + model = "wm8731 @ sama5d2_xplained"; + i2s-controller = <&i2s0>; + audio-codec = <&wm8731>; + dai-format = "i2s"; + }; +}; diff --git a/Documentation/devicetree/bindings/vendor-prefixes.txt b/Documentation/devicetree/bindings/vendor-prefixes.txt index 2c3fc512e746..f26bf667e530 100644 --- a/Documentation/devicetree/bindings/vendor-prefixes.txt +++ b/Documentation/devicetree/bindings/vendor-prefixes.txt @@ -235,6 +235,7 @@ micrel Micrel Inc. microchip Microchip Technology Inc. microcrystal Micro Crystal AG micron Micron Technology Inc. +mikroe MikroElektronika d.o.o. minix MINIX Technology Ltd. miramems MiraMEMS Sensing Technology Co., Ltd. mitsubishi Mitsubishi Electric Corporation From e03546ddd3db5352a74dec247dbdaa29889e93f7 Mon Sep 17 00:00:00 2001 From: Jon Hunter Date: Fri, 17 Aug 2018 16:35:43 +0100 Subject: [PATCH 086/299] ASoC: core: Don't schedule DAPM work if already in target state When dapm_power_widgets() is called, the dapm_pre_sequence_async() and dapm_post_sequence_async() functions are scheduled for all DAPM contexts (apart from the card DAPM context) regardless of whether the DAPM context is already in the desired state. The overhead of this is not insignificant and the more DAPM contexts there are the more overhead there is. For example, on the Tegra124 Jetson TK1, when profiling the time taken to execute the dapm_power_widgets() the following times were observed. Times for function dapm_power_widgets() are (us): Min 23, Ave 190, Max 434, Count 39 Here 'Count' is the number of times that dapm_power_widgets() has been called. Please note that the above time were measured using ktime_get() to log the time on entry and exit from dapm_power_widgets(). So it should be noted that these times may not be purely the time take to execute this function if it is preempted. However, after applying this patch and measuring the time taken to execute dapm_power_widgets() again a significant improvement is seen as shown below. Times for function dapm_power_widgets() are (us): Min 4, Ave 16, Max 82, Count 39 Therefore, optimise the dapm_power_widgets() function by only scheduling the dapm_pre/post_sequence_async() work if the DAPM context is not in the desired state. Signed-off-by: Jon Hunter Reviewed-by: Charles Keepax Signed-off-by: Mark Brown --- sound/soc/soc-dapm.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/sound/soc/soc-dapm.c b/sound/soc/soc-dapm.c index d7be3981f026..9feccd2e7c11 100644 --- a/sound/soc/soc-dapm.c +++ b/sound/soc/soc-dapm.c @@ -1952,7 +1952,7 @@ static int dapm_power_widgets(struct snd_soc_card *card, int event) dapm_pre_sequence_async(&card->dapm, 0); /* Run other bias changes in parallel */ list_for_each_entry(d, &card->dapm_list, list) { - if (d != &card->dapm) + if (d != &card->dapm && d->bias_level != d->target_bias_level) async_schedule_domain(dapm_pre_sequence_async, d, &async_domain); } @@ -1976,7 +1976,7 @@ static int dapm_power_widgets(struct snd_soc_card *card, int event) /* Run all the bias changes in parallel */ list_for_each_entry(d, &card->dapm_list, list) { - if (d != &card->dapm) + if (d != &card->dapm && d->bias_level != d->target_bias_level) async_schedule_domain(dapm_post_sequence_async, d, &async_domain); } From b917d58dcfaada52bbf2c734411c87532c0af67d Mon Sep 17 00:00:00 2001 From: Rob Herring Date: Tue, 28 Aug 2018 10:44:31 -0500 Subject: [PATCH 087/299] ALSA: aoa: Convert to using %pOFn instead of device_node.name In preparation to remove the node name pointer from struct device_node, convert printf users to use the %pOFn format specifier. Signed-off-by: Rob Herring Signed-off-by: Takashi Iwai --- sound/aoa/soundbus/i2sbus/core.c | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/sound/aoa/soundbus/i2sbus/core.c b/sound/aoa/soundbus/i2sbus/core.c index 000b58522106..bd7c5029fc59 100644 --- a/sound/aoa/soundbus/i2sbus/core.c +++ b/sound/aoa/soundbus/i2sbus/core.c @@ -157,18 +157,19 @@ static int i2sbus_add_dev(struct macio_dev *macio, struct device_node *child = NULL, *sound = NULL; struct resource *r; int i, layout = 0, rlen, ok = force; - static const char *rnames[] = { "i2sbus: %s (control)", - "i2sbus: %s (tx)", - "i2sbus: %s (rx)" }; + char node_name[6]; + static const char *rnames[] = { "i2sbus: %pOFn (control)", + "i2sbus: %pOFn (tx)", + "i2sbus: %pOFn (rx)" }; static irq_handler_t ints[] = { i2sbus_bus_intr, i2sbus_tx_intr, i2sbus_rx_intr }; - if (strlen(np->name) != 5) + if (snprintf(node_name, sizeof(node_name), "%pOFn", np) != 5) return 0; - if (strncmp(np->name, "i2s-", 4)) + if (strncmp(node_name, "i2s-", 4)) return 0; dev = kzalloc(sizeof(struct i2sbus_dev), GFP_KERNEL); @@ -228,13 +229,13 @@ static int i2sbus_add_dev(struct macio_dev *macio, dev->sound.pcmid = -1; dev->macio = macio; dev->control = control; - dev->bus_number = np->name[4] - 'a'; + dev->bus_number = node_name[4] - 'a'; INIT_LIST_HEAD(&dev->sound.codec_list); for (i = aoa_resource_i2smmio; i <= aoa_resource_rxdbdma; i++) { dev->interrupts[i] = -1; snprintf(dev->rnames[i], sizeof(dev->rnames[i]), - rnames[i], np->name); + rnames[i], np); } for (i = aoa_resource_i2smmio; i <= aoa_resource_rxdbdma; i++) { int irq = irq_of_parse_and_map(np, i); From 38ce57ad164816b432b80feb67d46d53137ff82a Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Sun, 2 Sep 2018 10:22:13 +0200 Subject: [PATCH 088/299] ALSA: rme32: Use SNDRV_PCM_INFO_SYNC_APPLPTR info flag The recently introduced PCM info flag assures the call of ack ops at each applptr change, and this is mandatory for the indirect PCM helpers. Also, with the proper ack callback, we need no longer prefill at trigger start. The relevant code can be killed. Reviewed-by: Takashi Sakamoto Signed-off-by: Takashi Iwai --- sound/pci/rme32.c | 22 ++++++++-------------- 1 file changed, 8 insertions(+), 14 deletions(-) diff --git a/sound/pci/rme32.c b/sound/pci/rme32.c index f0906ba416d4..3ac8c71d567c 100644 --- a/sound/pci/rme32.c +++ b/sound/pci/rme32.c @@ -319,7 +319,8 @@ static const struct snd_pcm_hardware snd_rme32_spdif_info = { SNDRV_PCM_INFO_MMAP_VALID | SNDRV_PCM_INFO_INTERLEAVED | SNDRV_PCM_INFO_PAUSE | - SNDRV_PCM_INFO_SYNC_START), + SNDRV_PCM_INFO_SYNC_START | + SNDRV_PCM_INFO_SYNC_APPLPTR), .formats = (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S32_LE), .rates = (SNDRV_PCM_RATE_32000 | @@ -346,7 +347,8 @@ static const struct snd_pcm_hardware snd_rme32_adat_info = SNDRV_PCM_INFO_MMAP_VALID | SNDRV_PCM_INFO_INTERLEAVED | SNDRV_PCM_INFO_PAUSE | - SNDRV_PCM_INFO_SYNC_START), + SNDRV_PCM_INFO_SYNC_START | + SNDRV_PCM_INFO_SYNC_APPLPTR), .formats= SNDRV_PCM_FMTBIT_S16_LE, .rates = (SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000), @@ -370,7 +372,8 @@ static const struct snd_pcm_hardware snd_rme32_spdif_fd_info = { SNDRV_PCM_INFO_MMAP_VALID | SNDRV_PCM_INFO_INTERLEAVED | SNDRV_PCM_INFO_PAUSE | - SNDRV_PCM_INFO_SYNC_START), + SNDRV_PCM_INFO_SYNC_START | + SNDRV_PCM_INFO_SYNC_APPLPTR), .formats = (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S32_LE), .rates = (SNDRV_PCM_RATE_32000 | @@ -397,7 +400,8 @@ static const struct snd_pcm_hardware snd_rme32_adat_fd_info = SNDRV_PCM_INFO_MMAP_VALID | SNDRV_PCM_INFO_INTERLEAVED | SNDRV_PCM_INFO_PAUSE | - SNDRV_PCM_INFO_SYNC_START), + SNDRV_PCM_INFO_SYNC_START | + SNDRV_PCM_INFO_SYNC_APPLPTR), .formats= SNDRV_PCM_FMTBIT_S16_LE, .rates = (SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000), @@ -1104,16 +1108,6 @@ snd_rme32_pcm_trigger(struct snd_pcm_substream *substream, int cmd) snd_pcm_trigger_done(s, substream); } - /* prefill playback buffer */ - if (cmd == SNDRV_PCM_TRIGGER_START && rme32->fullduplex_mode) { - snd_pcm_group_for_each_entry(s, substream) { - if (s == rme32->playback_substream) { - s->ops->ack(s); - break; - } - } - } - switch (cmd) { case SNDRV_PCM_TRIGGER_START: if (rme32->running && ! RME32_ISWORKING(rme32)) From dc0d1c4519095a6c6bbd9ec4a808674aba502741 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Sun, 2 Sep 2018 10:22:37 +0200 Subject: [PATCH 089/299] ALSA: mips: Use SNDRV_PCM_INFO_SYNC_APPLPTR info flag The recently introduced PCM info flag assures the call of ack ops at each applptr change, and this is mandatory for the indirect PCM helpers. Also, with the proper ack callback, we need no longer prefill at trigger start. The relevant code can be killed. Reviewed-by: Takashi Sakamoto Signed-off-by: Takashi Iwai --- sound/mips/hal2.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/sound/mips/hal2.c b/sound/mips/hal2.c index c8904e732aaa..2bd1cb7489ff 100644 --- a/sound/mips/hal2.c +++ b/sound/mips/hal2.c @@ -500,7 +500,8 @@ static const struct snd_pcm_hardware hal2_pcm_hw = { .info = (SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_MMAP_VALID | SNDRV_PCM_INFO_INTERLEAVED | - SNDRV_PCM_INFO_BLOCK_TRANSFER), + SNDRV_PCM_INFO_BLOCK_TRANSFER | + SNDRV_PCM_INFO_SYNC_APPLPTR), .formats = SNDRV_PCM_FMTBIT_S16_BE, .rates = SNDRV_PCM_RATE_8000_48000, .rate_min = 8000, @@ -577,7 +578,6 @@ static int hal2_playback_trigger(struct snd_pcm_substream *substream, int cmd) case SNDRV_PCM_TRIGGER_START: hal2->dac.pcm_indirect.hw_io = hal2->dac.buffer_dma; hal2->dac.pcm_indirect.hw_data = 0; - substream->ops->ack(substream); hal2_start_dac(hal2); break; case SNDRV_PCM_TRIGGER_STOP: From 10a23f614dc96ff46087edfc1ffd7e19ff23d8fe Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Sun, 2 Sep 2018 10:23:07 +0200 Subject: [PATCH 090/299] ALSA: emu10k1: Use SNDRV_PCM_INFO_SYNC_APPLPTR info flag The recently introduced PCM info flag assures the call of ack ops at each applptr change, and this is mandatory for the indirect PCM helpers. Reviewed-by: Takashi Sakamoto Signed-off-by: Takashi Iwai --- sound/pci/emu10k1/emupcm.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/sound/pci/emu10k1/emupcm.c b/sound/pci/emu10k1/emupcm.c index 9f2b6097f486..30b3472d0b75 100644 --- a/sound/pci/emu10k1/emupcm.c +++ b/sound/pci/emu10k1/emupcm.c @@ -1753,7 +1753,8 @@ static const struct snd_pcm_hardware snd_emu10k1_fx8010_playback = { .info = (SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_INTERLEAVED | SNDRV_PCM_INFO_RESUME | - /* SNDRV_PCM_INFO_MMAP_VALID | */ SNDRV_PCM_INFO_PAUSE), + /* SNDRV_PCM_INFO_MMAP_VALID | */ SNDRV_PCM_INFO_PAUSE | + SNDRV_PCM_INFO_SYNC_APPLPTR), .formats = SNDRV_PCM_FMTBIT_U8 | SNDRV_PCM_FMTBIT_S16_LE, .rates = SNDRV_PCM_RATE_48000, .rate_min = 48000, From b81e7732ce86eb4b2a7804e1210007f8fcbdb7dd Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Sun, 2 Sep 2018 10:23:22 +0200 Subject: [PATCH 091/299] ALSA: cs46xx: Use SNDRV_PCM_INFO_SYNC_APPLPTR info flag The recently introduced PCM info flag assures the call of ack ops at each applptr change, and this is mandatory for the indirect PCM helpers. Reviewed-by: Takashi Sakamoto Signed-off-by: Takashi Iwai --- sound/pci/cs46xx/cs46xx_lib.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/sound/pci/cs46xx/cs46xx_lib.c b/sound/pci/cs46xx/cs46xx_lib.c index 146e1a3498c7..750eec437a79 100644 --- a/sound/pci/cs46xx/cs46xx_lib.c +++ b/sound/pci/cs46xx/cs46xx_lib.c @@ -1443,7 +1443,8 @@ static const struct snd_pcm_hardware snd_cs46xx_playback = .info = (SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_INTERLEAVED | SNDRV_PCM_INFO_BLOCK_TRANSFER /*|*/ - /*SNDRV_PCM_INFO_RESUME*/), + /*SNDRV_PCM_INFO_RESUME*/ | + SNDRV_PCM_INFO_SYNC_APPLPTR), .formats = (SNDRV_PCM_FMTBIT_S8 | SNDRV_PCM_FMTBIT_U8 | SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S16_BE | SNDRV_PCM_FMTBIT_U16_LE | SNDRV_PCM_FMTBIT_U16_BE), @@ -1465,7 +1466,8 @@ static const struct snd_pcm_hardware snd_cs46xx_capture = .info = (SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_INTERLEAVED | SNDRV_PCM_INFO_BLOCK_TRANSFER /*|*/ - /*SNDRV_PCM_INFO_RESUME*/), + /*SNDRV_PCM_INFO_RESUME*/ | + SNDRV_PCM_INFO_SYNC_APPLPTR), .formats = SNDRV_PCM_FMTBIT_S16_LE, .rates = SNDRV_PCM_RATE_CONTINUOUS | SNDRV_PCM_RATE_8000_48000, .rate_min = 5500, From d873d5ea89e39e3224ec873a00414b6861507cac Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Sun, 2 Sep 2018 10:26:08 +0200 Subject: [PATCH 092/299] ALSA: mips: Cleanup indirect PCM helper usages We shouldn't set up the indirect PCM parameters at trigger but they should be set at prepare. Also, remove a useless debug message, too. Reviewed-by: Takashi Sakamoto Signed-off-by: Takashi Iwai --- sound/mips/hal2.c | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/sound/mips/hal2.c b/sound/mips/hal2.c index 2bd1cb7489ff..a4ed54aeaf1d 100644 --- a/sound/mips/hal2.c +++ b/sound/mips/hal2.c @@ -564,6 +564,8 @@ static int hal2_playback_prepare(struct snd_pcm_substream *substream) dac->sample_rate = hal2_compute_rate(dac, runtime->rate); memset(&dac->pcm_indirect, 0, sizeof(dac->pcm_indirect)); dac->pcm_indirect.hw_buffer_size = H2_BUF_SIZE; + dac->pcm_indirect.hw_queue_size = H2_BUF_SIZE / 2; + dac->pcm_indirect.hw_io = dac->buffer_dma; dac->pcm_indirect.sw_buffer_size = snd_pcm_lib_buffer_bytes(substream); dac->substream = substream; hal2_setup_dac(hal2); @@ -576,8 +578,6 @@ static int hal2_playback_trigger(struct snd_pcm_substream *substream, int cmd) switch (cmd) { case SNDRV_PCM_TRIGGER_START: - hal2->dac.pcm_indirect.hw_io = hal2->dac.buffer_dma; - hal2->dac.pcm_indirect.hw_data = 0; hal2_start_dac(hal2); break; case SNDRV_PCM_TRIGGER_STOP: @@ -615,7 +615,6 @@ static int hal2_playback_ack(struct snd_pcm_substream *substream) struct snd_hal2 *hal2 = snd_pcm_substream_chip(substream); struct hal2_codec *dac = &hal2->dac; - dac->pcm_indirect.hw_queue_size = H2_BUF_SIZE / 2; return snd_pcm_indirect_playback_transfer(substream, &dac->pcm_indirect, hal2_playback_transfer); @@ -655,6 +654,7 @@ static int hal2_capture_prepare(struct snd_pcm_substream *substream) memset(&adc->pcm_indirect, 0, sizeof(adc->pcm_indirect)); adc->pcm_indirect.hw_buffer_size = H2_BUF_SIZE; adc->pcm_indirect.hw_queue_size = H2_BUF_SIZE / 2; + adc->pcm_indirect.hw_io = adc->buffer_dma; adc->pcm_indirect.sw_buffer_size = snd_pcm_lib_buffer_bytes(substream); adc->substream = substream; hal2_setup_adc(hal2); @@ -667,9 +667,6 @@ static int hal2_capture_trigger(struct snd_pcm_substream *substream, int cmd) switch (cmd) { case SNDRV_PCM_TRIGGER_START: - hal2->adc.pcm_indirect.hw_io = hal2->adc.buffer_dma; - hal2->adc.pcm_indirect.hw_data = 0; - printk(KERN_DEBUG "buffer_dma %x\n", hal2->adc.buffer_dma); hal2_start_adc(hal2); break; case SNDRV_PCM_TRIGGER_STOP: From 18d545bb2599d6e5b0747351eaeebb0160d261f9 Mon Sep 17 00:00:00 2001 From: "Andrew F. Davis" Date: Tue, 4 Sep 2018 10:36:17 -0500 Subject: [PATCH 093/299] ASoC: tlv320aic31xx: Add overflow detection support Similar to short circuit detection, when the ADC/DAC is saturated and overflows poor audio quality can result and should be reported to the user. This device support Automatic Dynamic Range Compression (DRC) to reduce this but it is not enabled currently in this driver. Signed-off-by: Andrew F. Davis Signed-off-by: Mark Brown --- sound/soc/codecs/tlv320aic31xx.c | 34 ++++++++++++++++++++++++++++++-- sound/soc/codecs/tlv320aic31xx.h | 7 +++++++ 2 files changed, 39 insertions(+), 2 deletions(-) diff --git a/sound/soc/codecs/tlv320aic31xx.c b/sound/soc/codecs/tlv320aic31xx.c index 2abe51d9f879..608ad49ad978 100644 --- a/sound/soc/codecs/tlv320aic31xx.c +++ b/sound/soc/codecs/tlv320aic31xx.c @@ -1409,7 +1409,7 @@ static irqreturn_t aic31xx_irq(int irq, void *data) if (value) handled = true; else - goto exit; + goto read_overflow; if (value & AIC31XX_HPLSCDETECT) dev_err(dev, "Short circuit on Left output is detected\n"); @@ -1419,6 +1419,35 @@ static irqreturn_t aic31xx_irq(int irq, void *data) AIC31XX_HPRSCDETECT)) dev_err(dev, "Unknown DAC interrupt flags: 0x%08x\n", value); +read_overflow: + ret = regmap_read(aic31xx->regmap, AIC31XX_OFFLAG, &value); + if (ret) { + dev_err(dev, "Failed to read overflow flag: %d\n", ret); + goto exit; + } + + if (value) + handled = true; + else + goto exit; + + if (value & AIC31XX_DAC_OF_LEFT) + dev_warn(dev, "Left-channel DAC overflow has occurred\n"); + if (value & AIC31XX_DAC_OF_RIGHT) + dev_warn(dev, "Right-channel DAC overflow has occurred\n"); + if (value & AIC31XX_DAC_OF_SHIFTER) + dev_warn(dev, "DAC barrel shifter overflow has occurred\n"); + if (value & AIC31XX_ADC_OF) + dev_warn(dev, "ADC overflow has occurred\n"); + if (value & AIC31XX_ADC_OF_SHIFTER) + dev_warn(dev, "ADC barrel shifter overflow has occurred\n"); + if (value & ~(AIC31XX_DAC_OF_LEFT | + AIC31XX_DAC_OF_RIGHT | + AIC31XX_DAC_OF_SHIFTER | + AIC31XX_ADC_OF | + AIC31XX_ADC_OF_SHIFTER)) + dev_warn(dev, "Unknown overflow interrupt flags: 0x%08x\n", value); + exit: if (handled) return IRQ_HANDLED; @@ -1499,7 +1528,8 @@ static int aic31xx_i2c_probe(struct i2c_client *i2c, AIC31XX_GPIO1_FUNC_SHIFT); regmap_write(aic31xx->regmap, AIC31XX_INT1CTRL, - AIC31XX_SC); + AIC31XX_SC | + AIC31XX_ENGINE); ret = devm_request_threaded_irq(aic31xx->dev, aic31xx->irq, NULL, aic31xx_irq, diff --git a/sound/soc/codecs/tlv320aic31xx.h b/sound/soc/codecs/tlv320aic31xx.h index 52e171988906..2636f2c6bc79 100644 --- a/sound/soc/codecs/tlv320aic31xx.h +++ b/sound/soc/codecs/tlv320aic31xx.h @@ -173,6 +173,13 @@ struct aic31xx_pdata { #define AIC31XX_HPRDRVPWRSTATUS_MASK BIT(1) #define AIC31XX_SPRDRVPWRSTATUS_MASK BIT(0) +/* AIC31XX_OFFLAG */ +#define AIC31XX_DAC_OF_LEFT BIT(7) +#define AIC31XX_DAC_OF_RIGHT BIT(6) +#define AIC31XX_DAC_OF_SHIFTER BIT(5) +#define AIC31XX_ADC_OF BIT(3) +#define AIC31XX_ADC_OF_SHIFTER BIT(1) + /* AIC31XX_INTRDACFLAG */ #define AIC31XX_HPLSCDETECT BIT(7) #define AIC31XX_HPRSCDETECT BIT(6) From 3db769f17714ae65f2faf44ff2bae9d52f4bd46b Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Mon, 3 Sep 2018 02:12:40 +0000 Subject: [PATCH 094/299] ASoC: add for_each_link_codecs() macro ALSA SoC snd_soc_dai_link has snd_soc_dai_link_component array for codecs. To be more readable code, this patch adds new for_each_link_codecs() macro, and replace existing code to it. Signed-off-by: Kuninori Morimoto Signed-off-by: Mark Brown --- include/sound/soc.h | 4 ++++ sound/soc/meson/axg-card.c | 5 +++-- sound/soc/soc-core.c | 17 ++++++++--------- 3 files changed, 15 insertions(+), 11 deletions(-) diff --git a/include/sound/soc.h b/include/sound/soc.h index 96c19aabf21b..ce42c578fe82 100644 --- a/include/sound/soc.h +++ b/include/sound/soc.h @@ -978,6 +978,10 @@ struct snd_soc_dai_link { struct list_head list; /* DAI link list of the soc card */ struct snd_soc_dobj dobj; /* For topology */ }; +#define for_each_link_codecs(link, i, codec) \ + for ((i) = 0; \ + ((i) < link->num_codecs) && ((codec) = &link->codecs[i]); \ + (i)++) struct snd_soc_codec_conf { /* diff --git a/sound/soc/meson/axg-card.c b/sound/soc/meson/axg-card.c index b76a5f4f1785..3e68f1aa68ff 100644 --- a/sound/soc/meson/axg-card.c +++ b/sound/soc/meson/axg-card.c @@ -97,14 +97,15 @@ static void axg_card_clean_references(struct axg_card *priv) { struct snd_soc_card *card = &priv->card; struct snd_soc_dai_link *link; + struct snd_soc_dai_link_component *codec; int i, j; if (card->dai_link) { for (i = 0; i < card->num_links; i++) { link = &card->dai_link[i]; of_node_put(link->cpu_of_node); - for (j = 0; j < link->num_codecs; j++) - of_node_put(link->codecs[j].of_node); + for_each_link_codecs(link, j, codec) + of_node_put(codec->of_node); } } diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c index e9c2304afaf1..eeab492e954f 100644 --- a/sound/soc/soc-core.c +++ b/sound/soc/soc-core.c @@ -1071,6 +1071,7 @@ static int soc_init_dai_link(struct snd_soc_card *card, struct snd_soc_dai_link *link) { int i, ret; + struct snd_soc_dai_link_component *codec; ret = snd_soc_init_platform(card, link); if (ret) { @@ -1084,19 +1085,19 @@ static int soc_init_dai_link(struct snd_soc_card *card, return ret; } - for (i = 0; i < link->num_codecs; i++) { + for_each_link_codecs(link, i, codec) { /* * Codec must be specified by 1 of name or OF node, * not both or neither. */ - if (!!link->codecs[i].name == - !!link->codecs[i].of_node) { + if (!!codec->name == + !!codec->of_node) { dev_err(card->dev, "ASoC: Neither/both codec name/of_node are set for %s\n", link->name); return -EINVAL; } /* Codec DAI name must be specified */ - if (!link->codecs[i].dai_name) { + if (!codec->dai_name) { dev_err(card->dev, "ASoC: codec_dai_name not set for %s\n", link->name); return -EINVAL; @@ -3796,10 +3797,10 @@ EXPORT_SYMBOL_GPL(snd_soc_of_get_dai_name); */ void snd_soc_of_put_dai_link_codecs(struct snd_soc_dai_link *dai_link) { - struct snd_soc_dai_link_component *component = dai_link->codecs; + struct snd_soc_dai_link_component *component; int index; - for (index = 0; index < dai_link->num_codecs; index++, component++) { + for_each_link_codecs(dai_link, index, component) { if (!component->of_node) break; of_node_put(component->of_node); @@ -3851,9 +3852,7 @@ int snd_soc_of_get_dai_link_codecs(struct device *dev, dai_link->num_codecs = num_codecs; /* Parse the list */ - for (index = 0, component = dai_link->codecs; - index < dai_link->num_codecs; - index++, component++) { + for_each_link_codecs(dai_link, index, component) { ret = of_parse_phandle_with_args(of_node, name, "#sound-dai-cells", index, &args); From 0b7990e38971da403ce223d8bdc758a817eb72f8 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Mon, 3 Sep 2018 02:12:56 +0000 Subject: [PATCH 095/299] ASoC: add for_each_rtd_codec_dai() macro ALSA SoC snd_soc_pcm_runtime has snd_soc_dai array for codec_dai. To be more readable code, this patch adds new for_each_rtd_codec_dai() macro, and replace existing code to it. Signed-off-by: Kuninori Morimoto Signed-off-by: Mark Brown --- include/sound/soc.h | 7 + sound/soc/intel/boards/kbl_rt5663_max98927.c | 5 +- .../intel/boards/kbl_rt5663_rt5514_max98927.c | 5 +- .../mediatek/mt8173/mt8173-rt5650-rt5514.c | 5 +- .../mediatek/mt8173/mt8173-rt5650-rt5676.c | 5 +- sound/soc/mediatek/mt8173/mt8173-rt5650.c | 5 +- sound/soc/meson/axg-card.c | 6 +- sound/soc/soc-core.c | 38 ++--- sound/soc/soc-dapm.c | 14 +- sound/soc/soc-pcm.c | 154 ++++++++---------- 10 files changed, 118 insertions(+), 126 deletions(-) diff --git a/include/sound/soc.h b/include/sound/soc.h index ce42c578fe82..6b68b31e3140 100644 --- a/include/sound/soc.h +++ b/include/sound/soc.h @@ -1158,6 +1158,13 @@ struct snd_soc_pcm_runtime { unsigned int dev_registered:1; unsigned int pop_wait:1; }; +#define for_each_rtd_codec_dai(rtd, i, dai)\ + for ((i) = 0; \ + ((i) < rtd->num_codecs) && ((dai) = rtd->codec_dais[i]); \ + (i)++) +#define for_each_rtd_codec_dai_reverse(rtd, i, dai) \ + for (; ((i--) >= 0) && ((dai) = rtd->codec_dais[i]);) + /* mixer control */ struct soc_mixer_control { diff --git a/sound/soc/intel/boards/kbl_rt5663_max98927.c b/sound/soc/intel/boards/kbl_rt5663_max98927.c index 21a6490746a6..99e1320c485f 100644 --- a/sound/soc/intel/boards/kbl_rt5663_max98927.c +++ b/sound/soc/intel/boards/kbl_rt5663_max98927.c @@ -488,11 +488,10 @@ static int kabylake_ssp0_hw_params(struct snd_pcm_substream *substream, struct snd_pcm_hw_params *params) { struct snd_soc_pcm_runtime *rtd = substream->private_data; + struct snd_soc_dai *codec_dai; int ret = 0, j; - for (j = 0; j < rtd->num_codecs; j++) { - struct snd_soc_dai *codec_dai = rtd->codec_dais[j]; - + for_each_rtd_codec_dai(rtd, j, codec_dai) { if (!strcmp(codec_dai->component->name, MAXIM_DEV0_NAME)) { /* * Use channel 4 and 5 for the first amp diff --git a/sound/soc/intel/boards/kbl_rt5663_rt5514_max98927.c b/sound/soc/intel/boards/kbl_rt5663_rt5514_max98927.c index a892b37eab7c..a737c915d46a 100644 --- a/sound/soc/intel/boards/kbl_rt5663_rt5514_max98927.c +++ b/sound/soc/intel/boards/kbl_rt5663_rt5514_max98927.c @@ -353,11 +353,10 @@ static int kabylake_ssp0_hw_params(struct snd_pcm_substream *substream, struct snd_pcm_hw_params *params) { struct snd_soc_pcm_runtime *rtd = substream->private_data; + struct snd_soc_dai *codec_dai; int ret = 0, j; - for (j = 0; j < rtd->num_codecs; j++) { - struct snd_soc_dai *codec_dai = rtd->codec_dais[j]; - + for_each_rtd_codec_dai(rtd, j, codec_dai) { if (!strcmp(codec_dai->component->name, RT5514_DEV_NAME)) { ret = snd_soc_dai_set_tdm_slot(codec_dai, 0xF, 0, 8, 16); if (ret < 0) { diff --git a/sound/soc/mediatek/mt8173/mt8173-rt5650-rt5514.c b/sound/soc/mediatek/mt8173/mt8173-rt5650-rt5514.c index 582174d98c6c..5b4e90180827 100644 --- a/sound/soc/mediatek/mt8173/mt8173-rt5650-rt5514.c +++ b/sound/soc/mediatek/mt8173/mt8173-rt5650-rt5514.c @@ -44,11 +44,10 @@ static int mt8173_rt5650_rt5514_hw_params(struct snd_pcm_substream *substream, struct snd_pcm_hw_params *params) { struct snd_soc_pcm_runtime *rtd = substream->private_data; + struct snd_soc_dai *codec_dai; int i, ret; - for (i = 0; i < rtd->num_codecs; i++) { - struct snd_soc_dai *codec_dai = rtd->codec_dais[i]; - + for_each_rtd_codec_dai(rtd, i, codec_dai) { /* pll from mclk 12.288M */ ret = snd_soc_dai_set_pll(codec_dai, 0, 0, MCLK_FOR_CODECS, params_rate(params) * 512); diff --git a/sound/soc/mediatek/mt8173/mt8173-rt5650-rt5676.c b/sound/soc/mediatek/mt8173/mt8173-rt5650-rt5676.c index b3670c8a5b8d..82675ed057de 100644 --- a/sound/soc/mediatek/mt8173/mt8173-rt5650-rt5676.c +++ b/sound/soc/mediatek/mt8173/mt8173-rt5650-rt5676.c @@ -48,11 +48,10 @@ static int mt8173_rt5650_rt5676_hw_params(struct snd_pcm_substream *substream, struct snd_pcm_hw_params *params) { struct snd_soc_pcm_runtime *rtd = substream->private_data; + struct snd_soc_dai *codec_dai; int i, ret; - for (i = 0; i < rtd->num_codecs; i++) { - struct snd_soc_dai *codec_dai = rtd->codec_dais[i]; - + for_each_rtd_codec_dai(rtd, i, codec_dai) { /* pll from mclk 12.288M */ ret = snd_soc_dai_set_pll(codec_dai, 0, 0, MCLK_FOR_CODECS, params_rate(params) * 512); diff --git a/sound/soc/mediatek/mt8173/mt8173-rt5650.c b/sound/soc/mediatek/mt8173/mt8173-rt5650.c index 7a89b4aad182..ef05fbc40c32 100644 --- a/sound/soc/mediatek/mt8173/mt8173-rt5650.c +++ b/sound/soc/mediatek/mt8173/mt8173-rt5650.c @@ -59,6 +59,7 @@ static int mt8173_rt5650_hw_params(struct snd_pcm_substream *substream, { struct snd_soc_pcm_runtime *rtd = substream->private_data; unsigned int mclk_clock; + struct snd_soc_dai *codec_dai; int i, ret; switch (mt8173_rt5650_priv.pll_from) { @@ -76,9 +77,7 @@ static int mt8173_rt5650_hw_params(struct snd_pcm_substream *substream, break; } - for (i = 0; i < rtd->num_codecs; i++) { - struct snd_soc_dai *codec_dai = rtd->codec_dais[i]; - + for_each_rtd_codec_dai(rtd, i, codec_dai) { /* pll from mclk */ ret = snd_soc_dai_set_pll(codec_dai, 0, 0, mclk_clock, params_rate(params) * 512); diff --git a/sound/soc/meson/axg-card.c b/sound/soc/meson/axg-card.c index 3e68f1aa68ff..197e10a96e28 100644 --- a/sound/soc/meson/axg-card.c +++ b/sound/soc/meson/axg-card.c @@ -168,8 +168,7 @@ static int axg_card_tdm_be_hw_params(struct snd_pcm_substream *substream, if (be->mclk_fs) { mclk = params_rate(params) * be->mclk_fs; - for (i = 0; i < rtd->num_codecs; i++) { - codec_dai = rtd->codec_dais[i]; + for_each_rtd_codec_dai(rtd, i, codec_dai) { ret = snd_soc_dai_set_sysclk(codec_dai, 0, mclk, SND_SOC_CLOCK_IN); if (ret && ret != -ENOTSUPP) @@ -197,8 +196,7 @@ static int axg_card_tdm_dai_init(struct snd_soc_pcm_runtime *rtd) struct snd_soc_dai *codec_dai; int ret, i; - for (i = 0; i < rtd->num_codecs; i++) { - codec_dai = rtd->codec_dais[i]; + for_each_rtd_codec_dai(rtd, i, codec_dai) { ret = snd_soc_dai_set_tdm_slot(codec_dai, be->codec_masks[i].tx, be->codec_masks[i].rx, diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c index eeab492e954f..390da15c4a8b 100644 --- a/sound/soc/soc-core.c +++ b/sound/soc/soc-core.c @@ -452,12 +452,12 @@ int snd_soc_suspend(struct device *dev) /* mute any active DACs */ list_for_each_entry(rtd, &card->rtd_list, list) { + struct snd_soc_dai *dai; if (rtd->dai_link->ignore_suspend) continue; - for (i = 0; i < rtd->num_codecs; i++) { - struct snd_soc_dai *dai = rtd->codec_dais[i]; + for_each_rtd_codec_dai(rtd, i, dai) { struct snd_soc_dai_driver *drv = dai->driver; if (drv->ops->digital_mute && dai->playback_active) @@ -625,12 +625,12 @@ static void soc_resume_deferred(struct work_struct *work) /* unmute any active DACs */ list_for_each_entry(rtd, &card->rtd_list, list) { + struct snd_soc_dai *dai; if (rtd->dai_link->ignore_suspend) continue; - for (i = 0; i < rtd->num_codecs; i++) { - struct snd_soc_dai *dai = rtd->codec_dais[i]; + for_each_rtd_codec_dai(rtd, i, dai) { struct snd_soc_dai_driver *drv = dai->driver; if (drv->ops->digital_mute && dai->playback_active) @@ -674,15 +674,14 @@ int snd_soc_resume(struct device *dev) /* activate pins from sleep state */ list_for_each_entry(rtd, &card->rtd_list, list) { - struct snd_soc_dai **codec_dais = rtd->codec_dais; + struct snd_soc_dai *codec_dai; struct snd_soc_dai *cpu_dai = rtd->cpu_dai; int j; if (cpu_dai->active) pinctrl_pm_select_default_state(cpu_dai->dev); - for (j = 0; j < rtd->num_codecs; j++) { - struct snd_soc_dai *codec_dai = codec_dais[j]; + for_each_rtd_codec_dai(rtd, j, codec_dai) { if (codec_dai->active) pinctrl_pm_select_default_state(codec_dai->dev); } @@ -877,6 +876,7 @@ static int soc_bind_dai_link(struct snd_soc_card *card, rtd->num_codecs = dai_link->num_codecs; /* Find CODEC from registered CODECs */ + /* we can use for_each_rtd_codec_dai() after this */ codec_dais = rtd->codec_dais; for (i = 0; i < rtd->num_codecs; i++) { codec_dais[i] = snd_soc_find_dai(&codecs[i]); @@ -959,6 +959,7 @@ static void soc_remove_link_dais(struct snd_soc_card *card, struct snd_soc_pcm_runtime *rtd, int order) { int i; + struct snd_soc_dai *codec_dai; /* unregister the rtd device */ if (rtd->dev_registered) { @@ -967,8 +968,8 @@ static void soc_remove_link_dais(struct snd_soc_card *card, } /* remove the CODEC DAI */ - for (i = 0; i < rtd->num_codecs; i++) - soc_remove_dai(rtd->codec_dais[i], order); + for_each_rtd_codec_dai(rtd, i, codec_dai) + soc_remove_dai(codec_dai, order); soc_remove_dai(rtd->cpu_dai, order); } @@ -1511,6 +1512,7 @@ static int soc_probe_link_dais(struct snd_soc_card *card, struct snd_soc_dai *cpu_dai = rtd->cpu_dai; struct snd_soc_rtdcom_list *rtdcom; struct snd_soc_component *component; + struct snd_soc_dai *codec_dai; int i, ret, num; dev_dbg(card->dev, "ASoC: probe %s dai link %d late %d\n", @@ -1524,8 +1526,8 @@ static int soc_probe_link_dais(struct snd_soc_card *card, return ret; /* probe the CODEC DAI */ - for (i = 0; i < rtd->num_codecs; i++) { - ret = soc_probe_dai(rtd->codec_dais[i], order); + for_each_rtd_codec_dai(rtd, i, codec_dai) { + ret = soc_probe_dai(codec_dai, order); if (ret) return ret; } @@ -1712,14 +1714,12 @@ static void soc_remove_aux_devices(struct snd_soc_card *card) int snd_soc_runtime_set_dai_fmt(struct snd_soc_pcm_runtime *rtd, unsigned int dai_fmt) { - struct snd_soc_dai **codec_dais = rtd->codec_dais; struct snd_soc_dai *cpu_dai = rtd->cpu_dai; + struct snd_soc_dai *codec_dai; unsigned int i; int ret; - for (i = 0; i < rtd->num_codecs; i++) { - struct snd_soc_dai *codec_dai = codec_dais[i]; - + for_each_rtd_codec_dai(rtd, i, codec_dai) { ret = snd_soc_dai_set_fmt(codec_dai, dai_fmt); if (ret != 0 && ret != -ENOTSUPP) { dev_warn(codec_dai->dev, @@ -2266,11 +2266,11 @@ int snd_soc_poweroff(struct device *dev) /* deactivate pins to sleep state */ list_for_each_entry(rtd, &card->rtd_list, list) { struct snd_soc_dai *cpu_dai = rtd->cpu_dai; + struct snd_soc_dai *codec_dai; int i; pinctrl_pm_select_sleep_state(cpu_dai->dev); - for (i = 0; i < rtd->num_codecs; i++) { - struct snd_soc_dai *codec_dai = rtd->codec_dais[i]; + for_each_rtd_codec_dai(rtd, i, codec_dai) { pinctrl_pm_select_sleep_state(codec_dai->dev); } } @@ -2776,10 +2776,10 @@ int snd_soc_register_card(struct snd_soc_card *card) /* deactivate pins to sleep state */ list_for_each_entry(rtd, &card->rtd_list, list) { struct snd_soc_dai *cpu_dai = rtd->cpu_dai; + struct snd_soc_dai *codec_dai; int j; - for (j = 0; j < rtd->num_codecs; j++) { - struct snd_soc_dai *codec_dai = rtd->codec_dais[j]; + for_each_rtd_codec_dai(rtd, j, codec_dai) { if (!codec_dai->active) pinctrl_pm_select_sleep_state(codec_dai->dev); } diff --git a/sound/soc/soc-dapm.c b/sound/soc/soc-dapm.c index 9feccd2e7c11..0a738cb439be 100644 --- a/sound/soc/soc-dapm.c +++ b/sound/soc/soc-dapm.c @@ -2370,12 +2370,13 @@ static ssize_t dapm_widget_show(struct device *dev, struct device_attribute *attr, char *buf) { struct snd_soc_pcm_runtime *rtd = dev_get_drvdata(dev); + struct snd_soc_dai *codec_dai; int i, count = 0; mutex_lock(&rtd->card->dapm_mutex); - for (i = 0; i < rtd->num_codecs; i++) { - struct snd_soc_component *cmpnt = rtd->codec_dais[i]->component; + for_each_rtd_codec_dai(rtd, i, codec_dai) { + struct snd_soc_component *cmpnt = codec_dai->component; count += dapm_widget_show_component(cmpnt, buf + count); } @@ -4110,11 +4111,11 @@ static void dapm_connect_dai_link_widgets(struct snd_soc_card *card, struct snd_soc_pcm_runtime *rtd) { struct snd_soc_dai *cpu_dai = rtd->cpu_dai; + struct snd_soc_dai *codec_dai; struct snd_soc_dapm_widget *sink, *source; int i; - for (i = 0; i < rtd->num_codecs; i++) { - struct snd_soc_dai *codec_dai = rtd->codec_dais[i]; + for_each_rtd_codec_dai(rtd, i, codec_dai) { /* connect BE DAI playback if widgets are valid */ if (codec_dai->playback_widget && cpu_dai->playback_widget) { @@ -4202,11 +4203,12 @@ void snd_soc_dapm_connect_dai_link_widgets(struct snd_soc_card *card) static void soc_dapm_stream_event(struct snd_soc_pcm_runtime *rtd, int stream, int event) { + struct snd_soc_dai *codec_dai; int i; soc_dapm_dai_stream_event(rtd->cpu_dai, stream, event); - for (i = 0; i < rtd->num_codecs; i++) - soc_dapm_dai_stream_event(rtd->codec_dais[i], stream, event); + for_each_rtd_codec_dai(rtd, i, codec_dai) + soc_dapm_dai_stream_event(codec_dai, stream, event); dapm_power_widgets(rtd->card, event); } diff --git a/sound/soc/soc-pcm.c b/sound/soc/soc-pcm.c index eb6f4f1b65a9..79f5dd541d29 100644 --- a/sound/soc/soc-pcm.c +++ b/sound/soc/soc-pcm.c @@ -59,25 +59,26 @@ static bool snd_soc_dai_stream_valid(struct snd_soc_dai *dai, int stream) void snd_soc_runtime_activate(struct snd_soc_pcm_runtime *rtd, int stream) { struct snd_soc_dai *cpu_dai = rtd->cpu_dai; + struct snd_soc_dai *codec_dai; int i; lockdep_assert_held(&rtd->pcm_mutex); if (stream == SNDRV_PCM_STREAM_PLAYBACK) { cpu_dai->playback_active++; - for (i = 0; i < rtd->num_codecs; i++) - rtd->codec_dais[i]->playback_active++; + for_each_rtd_codec_dai(rtd, i, codec_dai) + codec_dai->playback_active++; } else { cpu_dai->capture_active++; - for (i = 0; i < rtd->num_codecs; i++) - rtd->codec_dais[i]->capture_active++; + for_each_rtd_codec_dai(rtd, i, codec_dai) + codec_dai->capture_active++; } cpu_dai->active++; cpu_dai->component->active++; - for (i = 0; i < rtd->num_codecs; i++) { - rtd->codec_dais[i]->active++; - rtd->codec_dais[i]->component->active++; + for_each_rtd_codec_dai(rtd, i, codec_dai) { + codec_dai->active++; + codec_dai->component->active++; } } @@ -94,25 +95,26 @@ void snd_soc_runtime_activate(struct snd_soc_pcm_runtime *rtd, int stream) void snd_soc_runtime_deactivate(struct snd_soc_pcm_runtime *rtd, int stream) { struct snd_soc_dai *cpu_dai = rtd->cpu_dai; + struct snd_soc_dai *codec_dai; int i; lockdep_assert_held(&rtd->pcm_mutex); if (stream == SNDRV_PCM_STREAM_PLAYBACK) { cpu_dai->playback_active--; - for (i = 0; i < rtd->num_codecs; i++) - rtd->codec_dais[i]->playback_active--; + for_each_rtd_codec_dai(rtd, i, codec_dai) + codec_dai->playback_active--; } else { cpu_dai->capture_active--; - for (i = 0; i < rtd->num_codecs; i++) - rtd->codec_dais[i]->capture_active--; + for_each_rtd_codec_dai(rtd, i, codec_dai) + codec_dai->capture_active--; } cpu_dai->active--; cpu_dai->component->active--; - for (i = 0; i < rtd->num_codecs; i++) { - rtd->codec_dais[i]->component->active--; - rtd->codec_dais[i]->active--; + for_each_rtd_codec_dai(rtd, i, codec_dai) { + codec_dai->component->active--; + codec_dai->active--; } } @@ -253,6 +255,7 @@ static int soc_pcm_params_symmetry(struct snd_pcm_substream *substream, { struct snd_soc_pcm_runtime *rtd = substream->private_data; struct snd_soc_dai *cpu_dai = rtd->cpu_dai; + struct snd_soc_dai *codec_dai; unsigned int rate, channels, sample_bits, symmetry, i; rate = params_rate(params); @@ -263,8 +266,8 @@ static int soc_pcm_params_symmetry(struct snd_pcm_substream *substream, symmetry = cpu_dai->driver->symmetric_rates || rtd->dai_link->symmetric_rates; - for (i = 0; i < rtd->num_codecs; i++) - symmetry |= rtd->codec_dais[i]->driver->symmetric_rates; + for_each_rtd_codec_dai(rtd, i, codec_dai) + symmetry |= codec_dai->driver->symmetric_rates; if (symmetry && cpu_dai->rate && cpu_dai->rate != rate) { dev_err(rtd->dev, "ASoC: unmatched rate symmetry: %d - %d\n", @@ -275,8 +278,8 @@ static int soc_pcm_params_symmetry(struct snd_pcm_substream *substream, symmetry = cpu_dai->driver->symmetric_channels || rtd->dai_link->symmetric_channels; - for (i = 0; i < rtd->num_codecs; i++) - symmetry |= rtd->codec_dais[i]->driver->symmetric_channels; + for_each_rtd_codec_dai(rtd, i, codec_dai) + symmetry |= codec_dai->driver->symmetric_channels; if (symmetry && cpu_dai->channels && cpu_dai->channels != channels) { dev_err(rtd->dev, "ASoC: unmatched channel symmetry: %d - %d\n", @@ -287,8 +290,8 @@ static int soc_pcm_params_symmetry(struct snd_pcm_substream *substream, symmetry = cpu_dai->driver->symmetric_samplebits || rtd->dai_link->symmetric_samplebits; - for (i = 0; i < rtd->num_codecs; i++) - symmetry |= rtd->codec_dais[i]->driver->symmetric_samplebits; + for_each_rtd_codec_dai(rtd, i, codec_dai) + symmetry |= codec_dai->driver->symmetric_samplebits; if (symmetry && cpu_dai->sample_bits && cpu_dai->sample_bits != sample_bits) { dev_err(rtd->dev, "ASoC: unmatched sample bits symmetry: %d - %d\n", @@ -304,17 +307,18 @@ static bool soc_pcm_has_symmetry(struct snd_pcm_substream *substream) struct snd_soc_pcm_runtime *rtd = substream->private_data; struct snd_soc_dai_driver *cpu_driver = rtd->cpu_dai->driver; struct snd_soc_dai_link *link = rtd->dai_link; + struct snd_soc_dai *codec_dai; unsigned int symmetry, i; symmetry = cpu_driver->symmetric_rates || link->symmetric_rates || cpu_driver->symmetric_channels || link->symmetric_channels || cpu_driver->symmetric_samplebits || link->symmetric_samplebits; - for (i = 0; i < rtd->num_codecs; i++) + for_each_rtd_codec_dai(rtd, i, codec_dai) symmetry = symmetry || - rtd->codec_dais[i]->driver->symmetric_rates || - rtd->codec_dais[i]->driver->symmetric_channels || - rtd->codec_dais[i]->driver->symmetric_samplebits; + codec_dai->driver->symmetric_rates || + codec_dai->driver->symmetric_channels || + codec_dai->driver->symmetric_samplebits; return symmetry; } @@ -342,8 +346,7 @@ static void soc_pcm_apply_msb(struct snd_pcm_substream *substream) unsigned int bits = 0, cpu_bits; if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { - for (i = 0; i < rtd->num_codecs; i++) { - codec_dai = rtd->codec_dais[i]; + for_each_rtd_codec_dai(rtd, i, codec_dai) { if (codec_dai->driver->playback.sig_bits == 0) { bits = 0; break; @@ -352,8 +355,7 @@ static void soc_pcm_apply_msb(struct snd_pcm_substream *substream) } cpu_bits = cpu_dai->driver->playback.sig_bits; } else { - for (i = 0; i < rtd->num_codecs; i++) { - codec_dai = rtd->codec_dais[i]; + for_each_rtd_codec_dai(rtd, i, codec_dai) { if (codec_dai->driver->capture.sig_bits == 0) { bits = 0; break; @@ -372,6 +374,7 @@ static void soc_pcm_init_runtime_hw(struct snd_pcm_substream *substream) struct snd_pcm_runtime *runtime = substream->runtime; struct snd_pcm_hardware *hw = &runtime->hw; struct snd_soc_pcm_runtime *rtd = substream->private_data; + struct snd_soc_dai *codec_dai; struct snd_soc_dai_driver *cpu_dai_drv = rtd->cpu_dai->driver; struct snd_soc_dai_driver *codec_dai_drv; struct snd_soc_pcm_stream *codec_stream; @@ -388,7 +391,7 @@ static void soc_pcm_init_runtime_hw(struct snd_pcm_substream *substream) cpu_stream = &cpu_dai_drv->capture; /* first calculate min/max only for CODECs in the DAI link */ - for (i = 0; i < rtd->num_codecs; i++) { + for_each_rtd_codec_dai(rtd, i, codec_dai) { /* * Skip CODECs which don't support the current stream type. @@ -399,11 +402,11 @@ static void soc_pcm_init_runtime_hw(struct snd_pcm_substream *substream) * bailed out on a higher level, since there would be no * CODEC to support the transfer direction in that case. */ - if (!snd_soc_dai_stream_valid(rtd->codec_dais[i], + if (!snd_soc_dai_stream_valid(codec_dai, substream->stream)) continue; - codec_dai_drv = rtd->codec_dais[i]->driver; + codec_dai_drv = codec_dai->driver; if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) codec_stream = &codec_dai_drv->playback; else @@ -482,8 +485,8 @@ static int soc_pcm_open(struct snd_pcm_substream *substream) int i, ret = 0; pinctrl_pm_select_default_state(cpu_dai->dev); - for (i = 0; i < rtd->num_codecs; i++) - pinctrl_pm_select_default_state(rtd->codec_dais[i]->dev); + for_each_rtd_codec_dai(rtd, i, codec_dai) + pinctrl_pm_select_default_state(codec_dai->dev); for_each_rtdcom(rtd, rtdcom) { component = rtdcom->component; @@ -520,8 +523,7 @@ static int soc_pcm_open(struct snd_pcm_substream *substream) } component = NULL; - for (i = 0; i < rtd->num_codecs; i++) { - codec_dai = rtd->codec_dais[i]; + for_each_rtd_codec_dai(rtd, i, codec_dai) { if (codec_dai->driver->ops->startup) { ret = codec_dai->driver->ops->startup(substream, codec_dai); @@ -588,10 +590,9 @@ static int soc_pcm_open(struct snd_pcm_substream *substream) goto config_err; } - for (i = 0; i < rtd->num_codecs; i++) { - if (rtd->codec_dais[i]->active) { - ret = soc_pcm_apply_symmetry(substream, - rtd->codec_dais[i]); + for_each_rtd_codec_dai(rtd, i, codec_dai) { + if (codec_dai->active) { + ret = soc_pcm_apply_symmetry(substream, codec_dai); if (ret != 0) goto config_err; } @@ -620,8 +621,7 @@ machine_err: i = rtd->num_codecs; codec_dai_err: - while (--i >= 0) { - codec_dai = rtd->codec_dais[i]; + for_each_rtd_codec_dai_reverse(rtd, i, codec_dai) { if (codec_dai->driver->ops->shutdown) codec_dai->driver->ops->shutdown(substream, codec_dai); } @@ -641,9 +641,9 @@ out: pm_runtime_put_autosuspend(component->dev); } - for (i = 0; i < rtd->num_codecs; i++) { - if (!rtd->codec_dais[i]->active) - pinctrl_pm_select_sleep_state(rtd->codec_dais[i]->dev); + for_each_rtd_codec_dai(rtd, i, codec_dai) { + if (!codec_dai->active) + pinctrl_pm_select_sleep_state(codec_dai->dev); } if (!cpu_dai->active) pinctrl_pm_select_sleep_state(cpu_dai->dev); @@ -701,8 +701,7 @@ static int soc_pcm_close(struct snd_pcm_substream *substream) if (!cpu_dai->active) cpu_dai->rate = 0; - for (i = 0; i < rtd->num_codecs; i++) { - codec_dai = rtd->codec_dais[i]; + for_each_rtd_codec_dai(rtd, i, codec_dai) { if (!codec_dai->active) codec_dai->rate = 0; } @@ -712,8 +711,7 @@ static int soc_pcm_close(struct snd_pcm_substream *substream) if (cpu_dai->driver->ops->shutdown) cpu_dai->driver->ops->shutdown(substream, cpu_dai); - for (i = 0; i < rtd->num_codecs; i++) { - codec_dai = rtd->codec_dais[i]; + for_each_rtd_codec_dai(rtd, i, codec_dai) { if (codec_dai->driver->ops->shutdown) codec_dai->driver->ops->shutdown(substream, codec_dai); } @@ -751,9 +749,9 @@ static int soc_pcm_close(struct snd_pcm_substream *substream) pm_runtime_put_autosuspend(component->dev); } - for (i = 0; i < rtd->num_codecs; i++) { - if (!rtd->codec_dais[i]->active) - pinctrl_pm_select_sleep_state(rtd->codec_dais[i]->dev); + for_each_rtd_codec_dai(rtd, i, codec_dai) { + if (!codec_dai->active) + pinctrl_pm_select_sleep_state(codec_dai->dev); } if (!cpu_dai->active) pinctrl_pm_select_sleep_state(cpu_dai->dev); @@ -801,8 +799,7 @@ static int soc_pcm_prepare(struct snd_pcm_substream *substream) } } - for (i = 0; i < rtd->num_codecs; i++) { - codec_dai = rtd->codec_dais[i]; + for_each_rtd_codec_dai(rtd, i, codec_dai) { if (codec_dai->driver->ops->prepare) { ret = codec_dai->driver->ops->prepare(substream, codec_dai); @@ -834,8 +831,8 @@ static int soc_pcm_prepare(struct snd_pcm_substream *substream) snd_soc_dapm_stream_event(rtd, substream->stream, SND_SOC_DAPM_STREAM_START); - for (i = 0; i < rtd->num_codecs; i++) - snd_soc_dai_digital_mute(rtd->codec_dais[i], 0, + for_each_rtd_codec_dai(rtd, i, codec_dai) + snd_soc_dai_digital_mute(codec_dai, 0, substream->stream); snd_soc_dai_digital_mute(cpu_dai, 0, substream->stream); @@ -920,6 +917,7 @@ static int soc_pcm_hw_params(struct snd_pcm_substream *substream, struct snd_soc_component *component; struct snd_soc_rtdcom_list *rtdcom; struct snd_soc_dai *cpu_dai = rtd->cpu_dai; + struct snd_soc_dai *codec_dai; int i, ret = 0; mutex_lock_nested(&rtd->pcm_mutex, rtd->pcm_subclass); @@ -932,8 +930,7 @@ static int soc_pcm_hw_params(struct snd_pcm_substream *substream, } } - for (i = 0; i < rtd->num_codecs; i++) { - struct snd_soc_dai *codec_dai = rtd->codec_dais[i]; + for_each_rtd_codec_dai(rtd, i, codec_dai) { struct snd_pcm_hw_params codec_params; /* @@ -1018,8 +1015,7 @@ interface_err: i = rtd->num_codecs; codec_err: - while (--i >= 0) { - struct snd_soc_dai *codec_dai = rtd->codec_dais[i]; + for_each_rtd_codec_dai_reverse(rtd, i, codec_dai) { if (codec_dai->driver->ops->hw_free) codec_dai->driver->ops->hw_free(substream, codec_dai); codec_dai->rate = 0; @@ -1052,8 +1048,7 @@ static int soc_pcm_hw_free(struct snd_pcm_substream *substream) cpu_dai->sample_bits = 0; } - for (i = 0; i < rtd->num_codecs; i++) { - codec_dai = rtd->codec_dais[i]; + for_each_rtd_codec_dai(rtd, i, codec_dai) { if (codec_dai->active == 1) { codec_dai->rate = 0; codec_dai->channels = 0; @@ -1062,10 +1057,10 @@ static int soc_pcm_hw_free(struct snd_pcm_substream *substream) } /* apply codec digital mute */ - for (i = 0; i < rtd->num_codecs; i++) { - if ((playback && rtd->codec_dais[i]->playback_active == 1) || - (!playback && rtd->codec_dais[i]->capture_active == 1)) - snd_soc_dai_digital_mute(rtd->codec_dais[i], 1, + for_each_rtd_codec_dai(rtd, i, codec_dai) { + if ((playback && codec_dai->playback_active == 1) || + (!playback && codec_dai->capture_active == 1)) + snd_soc_dai_digital_mute(codec_dai, 1, substream->stream); } @@ -1077,8 +1072,7 @@ static int soc_pcm_hw_free(struct snd_pcm_substream *substream) soc_pcm_components_hw_free(substream, NULL); /* now free hw params for the DAIs */ - for (i = 0; i < rtd->num_codecs; i++) { - codec_dai = rtd->codec_dais[i]; + for_each_rtd_codec_dai(rtd, i, codec_dai) { if (codec_dai->driver->ops->hw_free) codec_dai->driver->ops->hw_free(substream, codec_dai); } @@ -1099,8 +1093,7 @@ static int soc_pcm_trigger(struct snd_pcm_substream *substream, int cmd) struct snd_soc_dai *codec_dai; int i, ret; - for (i = 0; i < rtd->num_codecs; i++) { - codec_dai = rtd->codec_dais[i]; + for_each_rtd_codec_dai(rtd, i, codec_dai) { if (codec_dai->driver->ops->trigger) { ret = codec_dai->driver->ops->trigger(substream, cmd, codec_dai); @@ -1144,8 +1137,7 @@ static int soc_pcm_bespoke_trigger(struct snd_pcm_substream *substream, struct snd_soc_dai *codec_dai; int i, ret; - for (i = 0; i < rtd->num_codecs; i++) { - codec_dai = rtd->codec_dais[i]; + for_each_rtd_codec_dai(rtd, i, codec_dai) { if (codec_dai->driver->ops->bespoke_trigger) { ret = codec_dai->driver->ops->bespoke_trigger(substream, cmd, codec_dai); @@ -1199,8 +1191,7 @@ static snd_pcm_uframes_t soc_pcm_pointer(struct snd_pcm_substream *substream) if (cpu_dai->driver->ops->delay) delay += cpu_dai->driver->ops->delay(substream, cpu_dai); - for (i = 0; i < rtd->num_codecs; i++) { - codec_dai = rtd->codec_dais[i]; + for_each_rtd_codec_dai(rtd, i, codec_dai) { if (codec_dai->driver->ops->delay) codec_delay = max(codec_delay, codec_dai->driver->ops->delay(substream, @@ -1388,6 +1379,7 @@ static bool dpcm_end_walk_at_be(struct snd_soc_dapm_widget *widget, { struct snd_soc_card *card = widget->dapm->card; struct snd_soc_pcm_runtime *rtd; + struct snd_soc_dai *dai; int i; if (dir == SND_SOC_DAPM_DIR_OUT) { @@ -1398,8 +1390,7 @@ static bool dpcm_end_walk_at_be(struct snd_soc_dapm_widget *widget, if (rtd->cpu_dai->playback_widget == widget) return true; - for (i = 0; i < rtd->num_codecs; ++i) { - struct snd_soc_dai *dai = rtd->codec_dais[i]; + for_each_rtd_codec_dai(rtd, i, dai) { if (dai->playback_widget == widget) return true; } @@ -1412,8 +1403,7 @@ static bool dpcm_end_walk_at_be(struct snd_soc_dapm_widget *widget, if (rtd->cpu_dai->capture_widget == widget) return true; - for (i = 0; i < rtd->num_codecs; ++i) { - struct snd_soc_dai *dai = rtd->codec_dais[i]; + for_each_rtd_codec_dai(rtd, i, dai) { if (dai->capture_widget == widget) return true; } @@ -1907,6 +1897,7 @@ static int dpcm_apply_symmetry(struct snd_pcm_substream *fe_substream, struct snd_pcm_substream *be_substream = snd_soc_dpcm_get_substream(be, stream); struct snd_soc_pcm_runtime *rtd = be_substream->private_data; + struct snd_soc_dai *codec_dai; int i; if (rtd->dai_link->be_hw_params_fixup) @@ -1923,10 +1914,10 @@ static int dpcm_apply_symmetry(struct snd_pcm_substream *fe_substream, return err; } - for (i = 0; i < rtd->num_codecs; i++) { - if (rtd->codec_dais[i]->active) { + for_each_rtd_codec_dai(rtd, i, codec_dai) { + if (codec_dai->active) { err = soc_pcm_apply_symmetry(fe_substream, - rtd->codec_dais[i]); + codec_dai); if (err < 0) return err; } @@ -3041,8 +3032,7 @@ int soc_new_pcm(struct snd_soc_pcm_runtime *rtd, int num) playback = rtd->dai_link->dpcm_playback; capture = rtd->dai_link->dpcm_capture; } else { - for (i = 0; i < rtd->num_codecs; i++) { - codec_dai = rtd->codec_dais[i]; + for_each_rtd_codec_dai(rtd, i, codec_dai) { if (codec_dai->driver->playback.channels_min) playback = 1; if (codec_dai->driver->capture.channels_min) From 3bbf5d34fd4a0c41246290b70338095ae291851b Mon Sep 17 00:00:00 2001 From: Charles Keepax Date: Wed, 5 Sep 2018 15:20:58 +0100 Subject: [PATCH 096/299] ASoC: dapm: Move error handling to snd_soc_dapm_new_control_unlocked Currently DAPM has a lot of similar code to handle errors from snd_soc_dapm_new_control_unlocked, and much of this code does not really accurately reflect what the function returns. Firstly, most places will check for a return value of -EPROBE_DEFER and silence any error messages in that case. The one notable exception here being dapm_kcontrol_data_alloc which does currently print any error messages in the case of snd_soc_dapm_new_control_unlocked returning NULL or an error. Additionally the error prints being silenced in these case are redundant as snd_soc_dapm_new_control_unlocked can only return -EPROBE_DEFER or NULL when failing. Secondly, most places will treat a return value of NULL as an -ENOMEM. This is not correct either since any error except EPROBE_DEFER will cause a return value of NULL from snd_soc_dapm_new_control_unlocked. Centralise this handling and the error messages within snd_soc_dapm_new_control_unlocked and update the callers to simply check IS_ERR and return. Note that this update is slightly simpler in the case of dapm_kcontrol_data_alloc where that is fairly close to the handling that was already in place. Signed-off-by: Charles Keepax Signed-off-by: Mark Brown --- sound/soc/soc-dapm.c | 118 +++++++-------------------------------- sound/soc/soc-topology.c | 11 ---- 2 files changed, 19 insertions(+), 110 deletions(-) diff --git a/sound/soc/soc-dapm.c b/sound/soc/soc-dapm.c index 0a738cb439be..d13a25ce1275 100644 --- a/sound/soc/soc-dapm.c +++ b/sound/soc/soc-dapm.c @@ -364,10 +364,6 @@ static int dapm_kcontrol_data_alloc(struct snd_soc_dapm_widget *widget, ret = PTR_ERR(data->widget); goto err_data; } - if (!data->widget) { - ret = -ENOMEM; - goto err_data; - } } break; case snd_soc_dapm_demux: @@ -402,10 +398,6 @@ static int dapm_kcontrol_data_alloc(struct snd_soc_dapm_widget *widget, ret = PTR_ERR(data->widget); goto err_data; } - if (!data->widget) { - ret = -ENOMEM; - goto err_data; - } snd_soc_dapm_add_path(widget->dapm, data->widget, widget, NULL, NULL); @@ -3433,23 +3425,8 @@ snd_soc_dapm_new_control(struct snd_soc_dapm_context *dapm, mutex_lock_nested(&dapm->card->dapm_mutex, SND_SOC_DAPM_CLASS_RUNTIME); w = snd_soc_dapm_new_control_unlocked(dapm, widget); - /* Do not nag about probe deferrals */ - if (IS_ERR(w)) { - int ret = PTR_ERR(w); - - if (ret != -EPROBE_DEFER) - dev_err(dapm->dev, - "ASoC: Failed to create DAPM control %s (%d)\n", - widget->name, ret); - goto out_unlock; - } - if (!w) - dev_err(dapm->dev, - "ASoC: Failed to create DAPM control %s\n", - widget->name); - -out_unlock: mutex_unlock(&dapm->card->dapm_mutex); + return w; } EXPORT_SYMBOL_GPL(snd_soc_dapm_new_control); @@ -3464,24 +3441,20 @@ snd_soc_dapm_new_control_unlocked(struct snd_soc_dapm_context *dapm, int ret; if ((w = dapm_cnew_widget(widget)) == NULL) - return NULL; + return ERR_PTR(-ENOMEM); switch (w->id) { case snd_soc_dapm_regulator_supply: w->regulator = devm_regulator_get(dapm->dev, w->name); if (IS_ERR(w->regulator)) { ret = PTR_ERR(w->regulator); - if (ret == -EPROBE_DEFER) - return ERR_PTR(ret); - dev_err(dapm->dev, "ASoC: Failed to request %s: %d\n", - w->name, ret); - return NULL; + goto request_failed; } if (w->on_val & SND_SOC_DAPM_REGULATOR_BYPASS) { ret = regulator_allow_bypass(w->regulator, true); if (ret != 0) - dev_warn(w->dapm->dev, + dev_warn(dapm->dev, "ASoC: Failed to bypass %s: %d\n", w->name, ret); } @@ -3490,22 +3463,14 @@ snd_soc_dapm_new_control_unlocked(struct snd_soc_dapm_context *dapm, w->pinctrl = devm_pinctrl_get(dapm->dev); if (IS_ERR(w->pinctrl)) { ret = PTR_ERR(w->pinctrl); - if (ret == -EPROBE_DEFER) - return ERR_PTR(ret); - dev_err(dapm->dev, "ASoC: Failed to request %s: %d\n", - w->name, ret); - return NULL; + goto request_failed; } break; case snd_soc_dapm_clock_supply: w->clk = devm_clk_get(dapm->dev, w->name); if (IS_ERR(w->clk)) { ret = PTR_ERR(w->clk); - if (ret == -EPROBE_DEFER) - return ERR_PTR(ret); - dev_err(dapm->dev, "ASoC: Failed to request %s: %d\n", - w->name, ret); - return NULL; + goto request_failed; } break; default: @@ -3519,7 +3484,7 @@ snd_soc_dapm_new_control_unlocked(struct snd_soc_dapm_context *dapm, w->name = kstrdup_const(widget->name, GFP_KERNEL); if (w->name == NULL) { kfree(w); - return NULL; + return ERR_PTR(-ENOMEM); } switch (w->id) { @@ -3596,6 +3561,13 @@ snd_soc_dapm_new_control_unlocked(struct snd_soc_dapm_context *dapm, /* machine layer sets up unconnected pins and insertions */ w->connected = 1; return w; + +request_failed: + if (ret != -EPROBE_DEFER) + dev_err(dapm->dev, "ASoC: Failed to request %s: %d\n", + w->name, ret); + + return ERR_PTR(ret); } /** @@ -3621,19 +3593,6 @@ int snd_soc_dapm_new_controls(struct snd_soc_dapm_context *dapm, w = snd_soc_dapm_new_control_unlocked(dapm, widget); if (IS_ERR(w)) { ret = PTR_ERR(w); - /* Do not nag about probe deferrals */ - if (ret == -EPROBE_DEFER) - break; - dev_err(dapm->dev, - "ASoC: Failed to create DAPM control %s (%d)\n", - widget->name, ret); - break; - } - if (!w) { - dev_err(dapm->dev, - "ASoC: Failed to create DAPM control %s\n", - widget->name); - ret = -ENOMEM; break; } widget++; @@ -3944,21 +3903,8 @@ int snd_soc_dapm_new_pcm(struct snd_soc_card *card, dev_dbg(card->dev, "ASoC: adding %s widget\n", link_name); w = snd_soc_dapm_new_control_unlocked(&card->dapm, &template); - if (IS_ERR(w)) { - ret = PTR_ERR(w); - /* Do not nag about probe deferrals */ - if (ret != -EPROBE_DEFER) - dev_err(card->dev, - "ASoC: Failed to create %s widget (%d)\n", - link_name, ret); + if (IS_ERR(w)) goto outfree_kcontrol_news; - } - if (!w) { - dev_err(card->dev, "ASoC: Failed to create %s widget\n", - link_name); - ret = -ENOMEM; - goto outfree_kcontrol_news; - } w->params = params; w->num_params = num_params; @@ -3999,21 +3945,8 @@ int snd_soc_dapm_new_dai_widgets(struct snd_soc_dapm_context *dapm, template.name); w = snd_soc_dapm_new_control_unlocked(dapm, &template); - if (IS_ERR(w)) { - int ret = PTR_ERR(w); - - /* Do not nag about probe deferrals */ - if (ret != -EPROBE_DEFER) - dev_err(dapm->dev, - "ASoC: Failed to create %s widget (%d)\n", - dai->driver->playback.stream_name, ret); - return ret; - } - if (!w) { - dev_err(dapm->dev, "ASoC: Failed to create %s widget\n", - dai->driver->playback.stream_name); - return -ENOMEM; - } + if (IS_ERR(w)) + return PTR_ERR(w); w->priv = dai; dai->playback_widget = w; @@ -4028,21 +3961,8 @@ int snd_soc_dapm_new_dai_widgets(struct snd_soc_dapm_context *dapm, template.name); w = snd_soc_dapm_new_control_unlocked(dapm, &template); - if (IS_ERR(w)) { - int ret = PTR_ERR(w); - - /* Do not nag about probe deferrals */ - if (ret != -EPROBE_DEFER) - dev_err(dapm->dev, - "ASoC: Failed to create %s widget (%d)\n", - dai->driver->playback.stream_name, ret); - return ret; - } - if (!w) { - dev_err(dapm->dev, "ASoC: Failed to create %s widget\n", - dai->driver->capture.stream_name); - return -ENOMEM; - } + if (IS_ERR(w)) + return PTR_ERR(w); w->priv = dai; dai->capture_widget = w; diff --git a/sound/soc/soc-topology.c b/sound/soc/soc-topology.c index 66e77e020745..17f81b9a5754 100644 --- a/sound/soc/soc-topology.c +++ b/sound/soc/soc-topology.c @@ -1565,17 +1565,6 @@ widget: widget = snd_soc_dapm_new_control_unlocked(dapm, &template); if (IS_ERR(widget)) { ret = PTR_ERR(widget); - /* Do not nag about probe deferrals */ - if (ret != -EPROBE_DEFER) - dev_err(tplg->dev, - "ASoC: failed to create widget %s controls (%d)\n", - w->name, ret); - goto hdr_err; - } - if (widget == NULL) { - dev_err(tplg->dev, "ASoC: failed to create widget %s controls\n", - w->name); - ret = -ENOMEM; goto hdr_err; } From 94e630a35d3383b42f12a873a5404bdf61e38e42 Mon Sep 17 00:00:00 2001 From: Charles Keepax Date: Wed, 5 Sep 2018 15:20:59 +0100 Subject: [PATCH 097/299] ASoC: dapm: Cosmetic tidy up of snd_soc_dapm_new_control Move the function snd_soc_dapm_new_control to be next to snd_soc_dapm_new_controls and add some kernel doc for it. Signed-off-by: Charles Keepax Signed-off-by: Mark Brown --- sound/soc/soc-dapm.c | 37 +++++++++++++++++++++++-------------- 1 file changed, 23 insertions(+), 14 deletions(-) diff --git a/sound/soc/soc-dapm.c b/sound/soc/soc-dapm.c index d13a25ce1275..c111e69b9a09 100644 --- a/sound/soc/soc-dapm.c +++ b/sound/soc/soc-dapm.c @@ -3417,20 +3417,6 @@ int snd_soc_dapm_put_pin_switch(struct snd_kcontrol *kcontrol, } EXPORT_SYMBOL_GPL(snd_soc_dapm_put_pin_switch); -struct snd_soc_dapm_widget * -snd_soc_dapm_new_control(struct snd_soc_dapm_context *dapm, - const struct snd_soc_dapm_widget *widget) -{ - struct snd_soc_dapm_widget *w; - - mutex_lock_nested(&dapm->card->dapm_mutex, SND_SOC_DAPM_CLASS_RUNTIME); - w = snd_soc_dapm_new_control_unlocked(dapm, widget); - mutex_unlock(&dapm->card->dapm_mutex); - - return w; -} -EXPORT_SYMBOL_GPL(snd_soc_dapm_new_control); - struct snd_soc_dapm_widget * snd_soc_dapm_new_control_unlocked(struct snd_soc_dapm_context *dapm, const struct snd_soc_dapm_widget *widget) @@ -3570,6 +3556,29 @@ request_failed: return ERR_PTR(ret); } +/** + * snd_soc_dapm_new_control - create new dapm control + * @dapm: DAPM context + * @widget: widget template + * + * Creates new DAPM control based upon a template. + * + * Returns a widget pointer on success or an error pointer on failure + */ +struct snd_soc_dapm_widget * +snd_soc_dapm_new_control(struct snd_soc_dapm_context *dapm, + const struct snd_soc_dapm_widget *widget) +{ + struct snd_soc_dapm_widget *w; + + mutex_lock_nested(&dapm->card->dapm_mutex, SND_SOC_DAPM_CLASS_RUNTIME); + w = snd_soc_dapm_new_control_unlocked(dapm, widget); + mutex_unlock(&dapm->card->dapm_mutex); + + return w; +} +EXPORT_SYMBOL_GPL(snd_soc_dapm_new_control); + /** * snd_soc_dapm_new_controls - create new dapm controls * @dapm: DAPM context From 778ff5bb8689eb4fd05a72a409e32a3a34e23faf Mon Sep 17 00:00:00 2001 From: Charles Keepax Date: Wed, 5 Sep 2018 15:21:00 +0100 Subject: [PATCH 098/299] ASoC: dapm: Move connection of CODEC to CODEC DAIs Currently, snd_soc_dapm_connect_dai_link_widgets connects up the routes representing normal DAIs, however CODEC to CODEC links are hooked up through separate infrastructure in soc_link_dai_widgets. Improve the consistency of the code by using snd_soc_dapm_connect_dai_link for both types of DAIs. Signed-off-by: Charles Keepax Signed-off-by: Mark Brown --- include/sound/soc-dapm.h | 6 --- sound/soc/soc-core.c | 47 ----------------- sound/soc/soc-dapm.c | 107 +++++++++++++++++++++++++-------------- 3 files changed, 68 insertions(+), 92 deletions(-) diff --git a/include/sound/soc-dapm.h b/include/sound/soc-dapm.h index fdaaafdc7a00..cb177fa21ce7 100644 --- a/include/sound/soc-dapm.h +++ b/include/sound/soc-dapm.h @@ -406,12 +406,6 @@ int snd_soc_dapm_new_dai_widgets(struct snd_soc_dapm_context *dapm, struct snd_soc_dai *dai); int snd_soc_dapm_link_dai_widgets(struct snd_soc_card *card); void snd_soc_dapm_connect_dai_link_widgets(struct snd_soc_card *card); -int snd_soc_dapm_new_pcm(struct snd_soc_card *card, - struct snd_soc_pcm_runtime *rtd, - const struct snd_soc_pcm_stream *params, - unsigned int num_params, - struct snd_soc_dapm_widget *source, - struct snd_soc_dapm_widget *sink); /* dapm path setup */ int snd_soc_dapm_new_widgets(struct snd_soc_card *card); diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c index 390da15c4a8b..4e9367aacc0c 100644 --- a/sound/soc/soc-core.c +++ b/sound/soc/soc-core.c @@ -1463,48 +1463,6 @@ static int soc_link_dai_pcm_new(struct snd_soc_dai **dais, int num_dais, return 0; } -static int soc_link_dai_widgets(struct snd_soc_card *card, - struct snd_soc_dai_link *dai_link, - struct snd_soc_pcm_runtime *rtd) -{ - struct snd_soc_dai *cpu_dai = rtd->cpu_dai; - struct snd_soc_dai *codec_dai = rtd->codec_dai; - struct snd_soc_dapm_widget *sink, *source; - int ret; - - if (rtd->num_codecs > 1) - dev_warn(card->dev, "ASoC: Multiple codecs not supported yet\n"); - - /* link the DAI widgets */ - sink = codec_dai->playback_widget; - source = cpu_dai->capture_widget; - if (sink && source) { - ret = snd_soc_dapm_new_pcm(card, rtd, dai_link->params, - dai_link->num_params, - source, sink); - if (ret != 0) { - dev_err(card->dev, "ASoC: Can't link %s to %s: %d\n", - sink->name, source->name, ret); - return ret; - } - } - - sink = cpu_dai->playback_widget; - source = codec_dai->capture_widget; - if (sink && source) { - ret = snd_soc_dapm_new_pcm(card, rtd, dai_link->params, - dai_link->num_params, - source, sink); - if (ret != 0) { - dev_err(card->dev, "ASoC: Can't link %s to %s: %d\n", - sink->name, source->name, ret); - return ret; - } - } - - return 0; -} - static int soc_probe_link_dais(struct snd_soc_card *card, struct snd_soc_pcm_runtime *rtd, int order) { @@ -1606,11 +1564,6 @@ static int soc_probe_link_dais(struct snd_soc_card *card, } else { INIT_DELAYED_WORK(&rtd->delayed_work, codec2codec_close_delayed_work); - - /* link the DAI widgets */ - ret = soc_link_dai_widgets(card, dai_link, rtd); - if (ret) - return ret; } } diff --git a/sound/soc/soc-dapm.c b/sound/soc/soc-dapm.c index c111e69b9a09..bbfcb7fc05cc 100644 --- a/sound/soc/soc-dapm.c +++ b/sound/soc/soc-dapm.c @@ -3860,12 +3860,10 @@ outfree_w_param: return NULL; } -int snd_soc_dapm_new_pcm(struct snd_soc_card *card, - struct snd_soc_pcm_runtime *rtd, - const struct snd_soc_pcm_stream *params, - unsigned int num_params, - struct snd_soc_dapm_widget *source, - struct snd_soc_dapm_widget *sink) +static struct snd_soc_dapm_widget * +snd_soc_dapm_new_dai(struct snd_soc_card *card, struct snd_soc_pcm_runtime *rtd, + struct snd_soc_dapm_widget *source, + struct snd_soc_dapm_widget *sink) { struct snd_soc_dapm_widget template; struct snd_soc_dapm_widget *w; @@ -3877,7 +3875,7 @@ int snd_soc_dapm_new_pcm(struct snd_soc_card *card, link_name = devm_kasprintf(card->dev, GFP_KERNEL, "%s-%s", source->name, sink->name); if (!link_name) - return -ENOMEM; + return ERR_PTR(-ENOMEM); memset(&template, 0, sizeof(template)); template.reg = SND_SOC_NOPM; @@ -3889,9 +3887,10 @@ int snd_soc_dapm_new_pcm(struct snd_soc_card *card, template.kcontrol_news = NULL; /* allocate memory for control, only in case of multiple configs */ - if (num_params > 1) { - w_param_text = devm_kcalloc(card->dev, num_params, - sizeof(char *), GFP_KERNEL); + if (rtd->dai_link->num_params > 1) { + w_param_text = devm_kcalloc(card->dev, + rtd->dai_link->num_params, + sizeof(char *), GFP_KERNEL); if (!w_param_text) { ret = -ENOMEM; goto param_fail; @@ -3900,7 +3899,9 @@ int snd_soc_dapm_new_pcm(struct snd_soc_card *card, template.num_kcontrols = 1; template.kcontrol_news = snd_soc_dapm_alloc_kcontrol(card, - link_name, params, num_params, + link_name, + rtd->dai_link->params, + rtd->dai_link->num_params, w_param_text, &private_value); if (!template.kcontrol_news) { ret = -ENOMEM; @@ -3915,23 +3916,19 @@ int snd_soc_dapm_new_pcm(struct snd_soc_card *card, if (IS_ERR(w)) goto outfree_kcontrol_news; - w->params = params; - w->num_params = num_params; + w->params = rtd->dai_link->params; + w->num_params = rtd->dai_link->num_params; w->priv = rtd; - ret = snd_soc_dapm_add_path(&card->dapm, source, w, NULL, NULL); - if (ret) - goto outfree_w; - return snd_soc_dapm_add_path(&card->dapm, w, sink, NULL, NULL); + return w; -outfree_w: - devm_kfree(card->dev, w); outfree_kcontrol_news: devm_kfree(card->dev, (void *)template.kcontrol_news); - snd_soc_dapm_free_kcontrol(card, &private_value, num_params, w_param_text); + snd_soc_dapm_free_kcontrol(card, &private_value, + rtd->dai_link->num_params, w_param_text); param_fail: devm_kfree(card->dev, link_name); - return ret; + return ERR_PTR(ret); } int snd_soc_dapm_new_dai_widgets(struct snd_soc_dapm_context *dapm, @@ -4041,33 +4038,65 @@ static void dapm_connect_dai_link_widgets(struct snd_soc_card *card, { struct snd_soc_dai *cpu_dai = rtd->cpu_dai; struct snd_soc_dai *codec_dai; - struct snd_soc_dapm_widget *sink, *source; + struct snd_soc_dapm_widget *playback = NULL, *capture = NULL; + struct snd_soc_dapm_widget *codec, *playback_cpu, *capture_cpu; int i; + if (rtd->dai_link->params) { + if (rtd->num_codecs > 1) + dev_warn(card->dev, "ASoC: Multiple codecs not supported yet\n"); + + playback_cpu = cpu_dai->capture_widget; + capture_cpu = cpu_dai->playback_widget; + } else { + playback = cpu_dai->playback_widget; + capture = cpu_dai->capture_widget; + playback_cpu = playback; + capture_cpu = capture; + } + for_each_rtd_codec_dai(rtd, i, codec_dai) { /* connect BE DAI playback if widgets are valid */ - if (codec_dai->playback_widget && cpu_dai->playback_widget) { - source = cpu_dai->playback_widget; - sink = codec_dai->playback_widget; - dev_dbg(rtd->dev, "connected DAI link %s:%s -> %s:%s\n", - cpu_dai->component->name, source->name, - codec_dai->component->name, sink->name); + codec = codec_dai->playback_widget; - snd_soc_dapm_add_path(&card->dapm, source, sink, - NULL, NULL); + if (playback_cpu && codec) { + if (!playback) { + playback = snd_soc_dapm_new_dai(card, rtd, + playback_cpu, + codec); + + snd_soc_dapm_add_path(&card->dapm, playback_cpu, + playback, NULL, NULL); + } + + dev_dbg(rtd->dev, "connected DAI link %s:%s -> %s:%s\n", + cpu_dai->component->name, playback_cpu->name, + codec_dai->component->name, codec->name); + + snd_soc_dapm_add_path(&card->dapm, playback, codec, + NULL, NULL); } /* connect BE DAI capture if widgets are valid */ - if (codec_dai->capture_widget && cpu_dai->capture_widget) { - source = codec_dai->capture_widget; - sink = cpu_dai->capture_widget; - dev_dbg(rtd->dev, "connected DAI link %s:%s -> %s:%s\n", - codec_dai->component->name, source->name, - cpu_dai->component->name, sink->name); + codec = codec_dai->capture_widget; - snd_soc_dapm_add_path(&card->dapm, source, sink, - NULL, NULL); + if (codec && capture_cpu) { + if (!capture) { + capture = snd_soc_dapm_new_dai(card, rtd, + codec, + capture_cpu); + + snd_soc_dapm_add_path(&card->dapm, capture, + capture_cpu, NULL, NULL); + } + + dev_dbg(rtd->dev, "connected DAI link %s:%s -> %s:%s\n", + codec_dai->component->name, codec->name, + cpu_dai->component->name, capture_cpu->name); + + snd_soc_dapm_add_path(&card->dapm, codec, capture, + NULL, NULL); } } } @@ -4122,7 +4151,7 @@ void snd_soc_dapm_connect_dai_link_widgets(struct snd_soc_card *card) * dynamic FE links have no fixed DAI mapping. * CODEC<->CODEC links have no direct connection. */ - if (rtd->dai_link->dynamic || rtd->dai_link->params) + if (rtd->dai_link->dynamic) continue; dapm_connect_dai_link_widgets(card, rtd); From 4a75aae17b2a802a7267206414050408392c374c Mon Sep 17 00:00:00 2001 From: Charles Keepax Date: Wed, 5 Sep 2018 15:21:01 +0100 Subject: [PATCH 099/299] ASoC: dapm: Add support for multi-CODEC CODEC to CODEC links Currently multi-CODEC is not supported on CODEC to CODEC links. There are common applications where this would be useful, such as connecting two mono amplifiers to an audio CODEC. Adding support simply requires an update of snd_soc_dai_link_event to loop over the attached CODEC DAIs. Signed-off-by: Charles Keepax Signed-off-by: Mark Brown --- sound/soc/soc-dapm.c | 123 ++++++++++++++++++++++++------------------- 1 file changed, 70 insertions(+), 53 deletions(-) diff --git a/sound/soc/soc-dapm.c b/sound/soc/soc-dapm.c index bbfcb7fc05cc..40f27c95da61 100644 --- a/sound/soc/soc-dapm.c +++ b/sound/soc/soc-dapm.c @@ -3614,7 +3614,7 @@ EXPORT_SYMBOL_GPL(snd_soc_dapm_new_controls); static int snd_soc_dai_link_event(struct snd_soc_dapm_widget *w, struct snd_kcontrol *kcontrol, int event) { - struct snd_soc_dapm_path *source_p, *sink_p; + struct snd_soc_dapm_path *path; struct snd_soc_dai *source, *sink; struct snd_soc_pcm_runtime *rtd = w->priv; const struct snd_soc_pcm_stream *config = w->params + w->params_select; @@ -3629,17 +3629,6 @@ static int snd_soc_dai_link_event(struct snd_soc_dapm_widget *w, list_empty(&w->edges[SND_SOC_DAPM_DIR_IN]))) return -EINVAL; - /* We only support a single source and sink, pick the first */ - source_p = list_first_entry(&w->edges[SND_SOC_DAPM_DIR_OUT], - struct snd_soc_dapm_path, - list_node[SND_SOC_DAPM_DIR_OUT]); - sink_p = list_first_entry(&w->edges[SND_SOC_DAPM_DIR_IN], - struct snd_soc_dapm_path, - list_node[SND_SOC_DAPM_DIR_IN]); - - source = source_p->source->priv; - sink = sink_p->sink->priv; - /* Be a little careful as we don't want to overflow the mask array */ if (config->formats) { fmt = ffs(config->formats) - 1; @@ -3681,59 +3670,90 @@ static int snd_soc_dai_link_event(struct snd_soc_dapm_widget *w, switch (event) { case SND_SOC_DAPM_PRE_PMU: substream.stream = SNDRV_PCM_STREAM_CAPTURE; - if (source->driver->ops->startup) { - ret = source->driver->ops->startup(&substream, source); - if (ret < 0) { - dev_err(source->dev, - "ASoC: startup() failed: %d\n", ret); - goto out; + snd_soc_dapm_widget_for_each_source_path(w, path) { + source = path->source->priv; + + if (source->driver->ops->startup) { + ret = source->driver->ops->startup(&substream, + source); + if (ret < 0) { + dev_err(source->dev, + "ASoC: startup() failed: %d\n", + ret); + goto out; + } + source->active++; } - source->active++; + ret = soc_dai_hw_params(&substream, params, source); + if (ret < 0) + goto out; } - ret = soc_dai_hw_params(&substream, params, source); - if (ret < 0) - goto out; substream.stream = SNDRV_PCM_STREAM_PLAYBACK; - if (sink->driver->ops->startup) { - ret = sink->driver->ops->startup(&substream, sink); - if (ret < 0) { - dev_err(sink->dev, - "ASoC: startup() failed: %d\n", ret); - goto out; + snd_soc_dapm_widget_for_each_sink_path(w, path) { + sink = path->sink->priv; + + if (sink->driver->ops->startup) { + ret = sink->driver->ops->startup(&substream, + sink); + if (ret < 0) { + dev_err(sink->dev, + "ASoC: startup() failed: %d\n", + ret); + goto out; + } + sink->active++; } - sink->active++; + ret = soc_dai_hw_params(&substream, params, sink); + if (ret < 0) + goto out; } - ret = soc_dai_hw_params(&substream, params, sink); - if (ret < 0) - goto out; break; case SND_SOC_DAPM_POST_PMU: - ret = snd_soc_dai_digital_mute(sink, 0, - SNDRV_PCM_STREAM_PLAYBACK); - if (ret != 0 && ret != -ENOTSUPP) - dev_warn(sink->dev, "ASoC: Failed to unmute: %d\n", ret); - ret = 0; + snd_soc_dapm_widget_for_each_sink_path(w, path) { + sink = path->sink->priv; + + ret = snd_soc_dai_digital_mute(sink, 0, + SNDRV_PCM_STREAM_PLAYBACK); + if (ret != 0 && ret != -ENOTSUPP) + dev_warn(sink->dev, + "ASoC: Failed to unmute: %d\n", ret); + ret = 0; + } break; case SND_SOC_DAPM_PRE_PMD: - ret = snd_soc_dai_digital_mute(sink, 1, - SNDRV_PCM_STREAM_PLAYBACK); - if (ret != 0 && ret != -ENOTSUPP) - dev_warn(sink->dev, "ASoC: Failed to mute: %d\n", ret); - ret = 0; + snd_soc_dapm_widget_for_each_sink_path(w, path) { + sink = path->sink->priv; - source->active--; - if (source->driver->ops->shutdown) { - substream.stream = SNDRV_PCM_STREAM_CAPTURE; - source->driver->ops->shutdown(&substream, source); + ret = snd_soc_dai_digital_mute(sink, 1, + SNDRV_PCM_STREAM_PLAYBACK); + if (ret != 0 && ret != -ENOTSUPP) + dev_warn(sink->dev, + "ASoC: Failed to mute: %d\n", ret); + ret = 0; } - sink->active--; - if (sink->driver->ops->shutdown) { - substream.stream = SNDRV_PCM_STREAM_PLAYBACK; - sink->driver->ops->shutdown(&substream, sink); + snd_soc_dapm_widget_for_each_source_path(w, path) { + source = path->source->priv; + + source->active--; + if (source->driver->ops->shutdown) { + substream.stream = SNDRV_PCM_STREAM_CAPTURE; + source->driver->ops->shutdown(&substream, + source); + } + } + + snd_soc_dapm_widget_for_each_sink_path(w, path) { + sink = path->sink->priv; + + sink->active--; + if (sink->driver->ops->shutdown) { + substream.stream = SNDRV_PCM_STREAM_PLAYBACK; + sink->driver->ops->shutdown(&substream, sink); + } } break; @@ -4043,9 +4063,6 @@ static void dapm_connect_dai_link_widgets(struct snd_soc_card *card, int i; if (rtd->dai_link->params) { - if (rtd->num_codecs > 1) - dev_warn(card->dev, "ASoC: Multiple codecs not supported yet\n"); - playback_cpu = cpu_dai->capture_widget; capture_cpu = cpu_dai->playback_widget; } else { From 243bcfafcd9a23a20867fd488dc3a35264918d87 Mon Sep 17 00:00:00 2001 From: Charles Keepax Date: Wed, 5 Sep 2018 15:21:02 +0100 Subject: [PATCH 100/299] ASoC: dapm: Move CODEC to CODEC params from the widget to the runtime Larger CODECs may contain many several hundred widgets and which set of parameters is selected only needs to be recorded on a per DAI basis. As such move the selected CODEC to CODEC link params to be stored in the runtime rather than the DAPM widget, to save some memory. Signed-off-by: Charles Keepax Signed-off-by: Mark Brown --- include/sound/soc-dapm.h | 3 --- include/sound/soc.h | 2 ++ sound/soc/soc-dapm.c | 19 +++++++++++-------- 3 files changed, 13 insertions(+), 11 deletions(-) diff --git a/include/sound/soc-dapm.h b/include/sound/soc-dapm.h index cb177fa21ce7..bd8163f151cb 100644 --- a/include/sound/soc-dapm.h +++ b/include/sound/soc-dapm.h @@ -584,9 +584,6 @@ struct snd_soc_dapm_widget { void *priv; /* widget specific data */ struct regulator *regulator; /* attached regulator */ struct pinctrl *pinctrl; /* attached pinctrl */ - const struct snd_soc_pcm_stream *params; /* params for dai links */ - unsigned int num_params; /* number of params for dai links */ - unsigned int params_select; /* currently selected param for dai link */ /* dapm control */ int reg; /* negative reg = no direct dapm */ diff --git a/include/sound/soc.h b/include/sound/soc.h index 6b68b31e3140..821bf99992b8 100644 --- a/include/sound/soc.h +++ b/include/sound/soc.h @@ -1130,6 +1130,8 @@ struct snd_soc_pcm_runtime { enum snd_soc_pcm_subclass pcm_subclass; struct snd_pcm_ops ops; + unsigned int params_select; /* currently selected param for dai link */ + /* Dynamic PCM BE runtime data */ struct snd_soc_dpcm_runtime dpcm[2]; int fe_compr; diff --git a/sound/soc/soc-dapm.c b/sound/soc/soc-dapm.c index 40f27c95da61..9f4edcd19e02 100644 --- a/sound/soc/soc-dapm.c +++ b/sound/soc/soc-dapm.c @@ -1018,9 +1018,10 @@ static int dapm_new_dai_link(struct snd_soc_dapm_widget *w) struct snd_kcontrol *kcontrol; struct snd_soc_dapm_context *dapm = w->dapm; struct snd_card *card = dapm->card->snd_card; + struct snd_soc_pcm_runtime *rtd = w->priv; /* create control for links with > 1 config */ - if (w->num_params <= 1) + if (rtd->dai_link->num_params <= 1) return 0; /* add kcontrol */ @@ -3617,13 +3618,15 @@ static int snd_soc_dai_link_event(struct snd_soc_dapm_widget *w, struct snd_soc_dapm_path *path; struct snd_soc_dai *source, *sink; struct snd_soc_pcm_runtime *rtd = w->priv; - const struct snd_soc_pcm_stream *config = w->params + w->params_select; + const struct snd_soc_pcm_stream *config; struct snd_pcm_substream substream; struct snd_pcm_hw_params *params = NULL; struct snd_pcm_runtime *runtime = NULL; unsigned int fmt; int ret; + config = rtd->dai_link->params + rtd->params_select; + if (WARN_ON(!config) || WARN_ON(list_empty(&w->edges[SND_SOC_DAPM_DIR_OUT]) || list_empty(&w->edges[SND_SOC_DAPM_DIR_IN]))) @@ -3772,8 +3775,9 @@ static int snd_soc_dapm_dai_link_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { struct snd_soc_dapm_widget *w = snd_kcontrol_chip(kcontrol); + struct snd_soc_pcm_runtime *rtd = w->priv; - ucontrol->value.enumerated.item[0] = w->params_select; + ucontrol->value.enumerated.item[0] = rtd->params_select; return 0; } @@ -3782,18 +3786,19 @@ static int snd_soc_dapm_dai_link_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { struct snd_soc_dapm_widget *w = snd_kcontrol_chip(kcontrol); + struct snd_soc_pcm_runtime *rtd = w->priv; /* Can't change the config when widget is already powered */ if (w->power) return -EBUSY; - if (ucontrol->value.enumerated.item[0] == w->params_select) + if (ucontrol->value.enumerated.item[0] == rtd->params_select) return 0; - if (ucontrol->value.enumerated.item[0] >= w->num_params) + if (ucontrol->value.enumerated.item[0] >= rtd->dai_link->num_params) return -EINVAL; - w->params_select = ucontrol->value.enumerated.item[0]; + rtd->params_select = ucontrol->value.enumerated.item[0]; return 0; } @@ -3936,8 +3941,6 @@ snd_soc_dapm_new_dai(struct snd_soc_card *card, struct snd_soc_pcm_runtime *rtd, if (IS_ERR(w)) goto outfree_kcontrol_news; - w->params = rtd->dai_link->params; - w->num_params = rtd->dai_link->num_params; w->priv = rtd; return w; From c24fb71fa4f764f02c17cbf88a969f109794e602 Mon Sep 17 00:00:00 2001 From: Colin Ian King Date: Thu, 6 Sep 2018 10:39:01 +0100 Subject: [PATCH 101/299] ASoC: hdac_hdmi: remove redundant check for !port condition The !port check is redundant as it being performed in the following check. Remove it. Signed-off-by: Colin Ian King Signed-off-by: Mark Brown --- sound/soc/codecs/hdac_hdmi.c | 3 --- 1 file changed, 3 deletions(-) diff --git a/sound/soc/codecs/hdac_hdmi.c b/sound/soc/codecs/hdac_hdmi.c index 7b8533abf637..dc6a0dfea050 100644 --- a/sound/soc/codecs/hdac_hdmi.c +++ b/sound/soc/codecs/hdac_hdmi.c @@ -1961,9 +1961,6 @@ static int hdac_hdmi_get_spk_alloc(struct hdac_device *hdev, int pcm_idx) port = list_first_entry(&pcm->port_list, struct hdac_hdmi_port, head); - if (!port) - return 0; - if (!port || !port->eld.eld_valid) return 0; From 501683d0cd54714de78501efe945bbe4356b922b Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Thu, 6 Sep 2018 03:21:16 +0000 Subject: [PATCH 102/299] ASoC: rsnd: gen: use tab instead of white-space commit 8c9d75033340 ("ASoC: rsnd: ssiu: Support BUSIF other than BUSIF0") added new SSIU registers. But it is using white-space for it. This patch fixup it to use tab. Signed-off-by: Kuninori Morimoto Signed-off-by: Mark Brown --- sound/soc/sh/rcar/gen.c | 48 ++++++++++++++++++++--------------------- 1 file changed, 24 insertions(+), 24 deletions(-) diff --git a/sound/soc/sh/rcar/gen.c b/sound/soc/sh/rcar/gen.c index 3032869a7f26..1f7881cc16b2 100644 --- a/sound/soc/sh/rcar/gen.c +++ b/sound/soc/sh/rcar/gen.c @@ -222,30 +222,30 @@ static int rsnd_gen2_probe(struct rsnd_priv *priv) RSND_GEN_M_REG(SSI_BUSIF0_MODE, 0x0, 0x80), RSND_GEN_M_REG(SSI_BUSIF0_ADINR, 0x4, 0x80), RSND_GEN_M_REG(SSI_BUSIF0_DALIGN, 0x8, 0x80), - RSND_GEN_M_REG(SSI_BUSIF1_MODE, 0x20, 0x80), - RSND_GEN_M_REG(SSI_BUSIF1_ADINR, 0x24, 0x80), - RSND_GEN_M_REG(SSI_BUSIF1_DALIGN, 0x28, 0x80), - RSND_GEN_M_REG(SSI_BUSIF2_MODE, 0x40, 0x80), - RSND_GEN_M_REG(SSI_BUSIF2_ADINR, 0x44, 0x80), - RSND_GEN_M_REG(SSI_BUSIF2_DALIGN, 0x48, 0x80), - RSND_GEN_M_REG(SSI_BUSIF3_MODE, 0x60, 0x80), - RSND_GEN_M_REG(SSI_BUSIF3_ADINR, 0x64, 0x80), - RSND_GEN_M_REG(SSI_BUSIF3_DALIGN, 0x68, 0x80), - RSND_GEN_M_REG(SSI_BUSIF4_MODE, 0x500, 0x80), - RSND_GEN_M_REG(SSI_BUSIF4_ADINR, 0x504, 0x80), - RSND_GEN_M_REG(SSI_BUSIF4_DALIGN, 0x508, 0x80), - RSND_GEN_M_REG(SSI_BUSIF5_MODE, 0x520, 0x80), - RSND_GEN_M_REG(SSI_BUSIF5_ADINR, 0x524, 0x80), - RSND_GEN_M_REG(SSI_BUSIF5_DALIGN, 0x528, 0x80), - RSND_GEN_M_REG(SSI_BUSIF6_MODE, 0x540, 0x80), - RSND_GEN_M_REG(SSI_BUSIF6_ADINR, 0x544, 0x80), - RSND_GEN_M_REG(SSI_BUSIF6_DALIGN, 0x548, 0x80), - RSND_GEN_M_REG(SSI_BUSIF7_MODE, 0x560, 0x80), - RSND_GEN_M_REG(SSI_BUSIF7_ADINR, 0x564, 0x80), - RSND_GEN_M_REG(SSI_BUSIF7_DALIGN, 0x568, 0x80), - RSND_GEN_M_REG(SSI_MODE, 0xc, 0x80), - RSND_GEN_M_REG(SSI_CTRL, 0x10, 0x80), - RSND_GEN_M_REG(SSI_INT_ENABLE, 0x18, 0x80), + RSND_GEN_M_REG(SSI_BUSIF1_MODE, 0x20, 0x80), + RSND_GEN_M_REG(SSI_BUSIF1_ADINR, 0x24, 0x80), + RSND_GEN_M_REG(SSI_BUSIF1_DALIGN, 0x28, 0x80), + RSND_GEN_M_REG(SSI_BUSIF2_MODE, 0x40, 0x80), + RSND_GEN_M_REG(SSI_BUSIF2_ADINR, 0x44, 0x80), + RSND_GEN_M_REG(SSI_BUSIF2_DALIGN, 0x48, 0x80), + RSND_GEN_M_REG(SSI_BUSIF3_MODE, 0x60, 0x80), + RSND_GEN_M_REG(SSI_BUSIF3_ADINR, 0x64, 0x80), + RSND_GEN_M_REG(SSI_BUSIF3_DALIGN, 0x68, 0x80), + RSND_GEN_M_REG(SSI_BUSIF4_MODE, 0x500, 0x80), + RSND_GEN_M_REG(SSI_BUSIF4_ADINR, 0x504, 0x80), + RSND_GEN_M_REG(SSI_BUSIF4_DALIGN, 0x508, 0x80), + RSND_GEN_M_REG(SSI_BUSIF5_MODE, 0x520, 0x80), + RSND_GEN_M_REG(SSI_BUSIF5_ADINR, 0x524, 0x80), + RSND_GEN_M_REG(SSI_BUSIF5_DALIGN, 0x528, 0x80), + RSND_GEN_M_REG(SSI_BUSIF6_MODE, 0x540, 0x80), + RSND_GEN_M_REG(SSI_BUSIF6_ADINR, 0x544, 0x80), + RSND_GEN_M_REG(SSI_BUSIF6_DALIGN, 0x548, 0x80), + RSND_GEN_M_REG(SSI_BUSIF7_MODE, 0x560, 0x80), + RSND_GEN_M_REG(SSI_BUSIF7_ADINR, 0x564, 0x80), + RSND_GEN_M_REG(SSI_BUSIF7_DALIGN, 0x568, 0x80), + RSND_GEN_M_REG(SSI_MODE, 0xc, 0x80), + RSND_GEN_M_REG(SSI_CTRL, 0x10, 0x80), + RSND_GEN_M_REG(SSI_INT_ENABLE, 0x18, 0x80), }; static const struct rsnd_regmap_field_conf conf_scu[] = { From dabdbe3ae0cb9a67872fa4ac80ffdef61391f645 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Thu, 6 Sep 2018 03:22:01 +0000 Subject: [PATCH 103/299] ASoC: rsnd: don't use %p for dev_dbg() rsnd driver sometimes want to know which address is used when debugging. But it will indicate "(____ptrval____)" if it used "%p" on dev_dbg(). Let's use "%pa" or "%px" for it. Signed-off-by: Kuninori Morimoto Tested-by: Hiroyuki Yokoyama Signed-off-by: Mark Brown --- sound/soc/sh/rcar/adg.c | 4 ++-- sound/soc/sh/rcar/dma.c | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/sound/soc/sh/rcar/adg.c b/sound/soc/sh/rcar/adg.c index 3a3064dda57f..b100c44ec3a3 100644 --- a/sound/soc/sh/rcar/adg.c +++ b/sound/soc/sh/rcar/adg.c @@ -577,7 +577,7 @@ static void rsnd_adg_clk_dbg_info(struct rsnd_priv *priv, struct rsnd_adg *adg) int i; for_each_rsnd_clk(clk, adg, i) - dev_dbg(dev, "%s : %p : %ld\n", + dev_dbg(dev, "%s : %pa : %ld\n", clk_name[i], clk, clk_get_rate(clk)); dev_dbg(dev, "BRGCKR = 0x%08x, BRRA/BRRB = 0x%x/0x%x\n", @@ -590,7 +590,7 @@ static void rsnd_adg_clk_dbg_info(struct rsnd_priv *priv, struct rsnd_adg *adg) * by BRGCKR::BRGCKR_31 */ for_each_rsnd_clkout(clk, adg, i) - dev_dbg(dev, "clkout %d : %p : %ld\n", i, + dev_dbg(dev, "clkout %d : %pa : %ld\n", i, clk, clk_get_rate(clk)); } #else diff --git a/sound/soc/sh/rcar/dma.c b/sound/soc/sh/rcar/dma.c index f99c1ab3b0bd..c19342d18998 100644 --- a/sound/soc/sh/rcar/dma.c +++ b/sound/soc/sh/rcar/dma.c @@ -393,7 +393,7 @@ static void rsnd_dmapp_write(struct rsnd_dma *dma, u32 data, u32 reg) struct rsnd_dma_ctrl *dmac = rsnd_priv_to_dmac(priv); struct device *dev = rsnd_priv_to_dev(priv); - dev_dbg(dev, "w %p : %08x\n", rsnd_dmapp_addr(dmac, dma, reg), data); + dev_dbg(dev, "w 0x%px : %08x\n", rsnd_dmapp_addr(dmac, dma, reg), data); iowrite32(data, rsnd_dmapp_addr(dmac, dma, reg)); } From 9ab708aef61f5620113269a9d1bdb1543d1207d0 Mon Sep 17 00:00:00 2001 From: Colin Ian King Date: Thu, 6 Sep 2018 11:41:52 +0100 Subject: [PATCH 104/299] ASoC: sgtl5000: avoid division by zero if lo_vag is zero In the case where lo_vag <= SGTL5000_LINE_OUT_GND_BASE, lo_vag is set to zero and later vol_quot is computed by dividing by lo_vag causing a division by zero error. Fix this by avoiding a zero division and set vol_quot to zero in this specific case so that the lowest setting for i is correctly set. Signed-off-by: Colin Ian King Signed-off-by: Mark Brown --- sound/soc/codecs/sgtl5000.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sound/soc/codecs/sgtl5000.c b/sound/soc/codecs/sgtl5000.c index 60764f6201b1..add18d6d77da 100644 --- a/sound/soc/codecs/sgtl5000.c +++ b/sound/soc/codecs/sgtl5000.c @@ -1218,7 +1218,7 @@ static int sgtl5000_set_power_regs(struct snd_soc_component *component) * Searching for a suitable index solving this formula: * idx = 40 * log10(vag_val / lo_cagcntrl) + 15 */ - vol_quot = (vag * 100) / lo_vag; + vol_quot = lo_vag ? (vag * 100) / lo_vag : 0; lo_vol = 0; for (i = 0; i < ARRAY_SIZE(vol_quot_table); i++) { if (vol_quot >= vol_quot_table[i]) From e058a4033240d30192124d6bf32b78e9a1f8975c Mon Sep 17 00:00:00 2001 From: Hiroyuki Yokoyama Date: Thu, 6 Sep 2018 22:28:33 +0900 Subject: [PATCH 105/299] ASoC: rsnd: Add device tree binding for r8a77990 This patch adds the device tree binding of the r8a77990 SoC. Signed-off-by: Hiroyuki Yokoyama Signed-off-by: Yoshihiro Kaneko Signed-off-by: Mark Brown --- Documentation/devicetree/bindings/sound/renesas,rsnd.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/Documentation/devicetree/bindings/sound/renesas,rsnd.txt b/Documentation/devicetree/bindings/sound/renesas,rsnd.txt index 8083f0d8f263..f4688c508be6 100644 --- a/Documentation/devicetree/bindings/sound/renesas,rsnd.txt +++ b/Documentation/devicetree/bindings/sound/renesas,rsnd.txt @@ -354,6 +354,7 @@ Required properties: - "renesas,rcar_sound-r8a7795" (R-Car H3) - "renesas,rcar_sound-r8a7796" (R-Car M3-W) - "renesas,rcar_sound-r8a77965" (R-Car M3-N) + - "renesas,rcar_sound-r8a77990" (R-Car E3) - reg : Should contain the register physical address. required register is SRU/ADG/SSI if generation1 From fc269c0396448cabe1afd648c0b335669aa347b7 Mon Sep 17 00:00:00 2001 From: Charles Keepax Date: Thu, 6 Sep 2018 17:41:55 +0100 Subject: [PATCH 106/299] ASoC: dapm: Avoid uninitialised variable warning Commit 4a75aae17b2a ("ASoC: dapm: Add support for multi-CODEC CODEC to CODEC links") adds loops that iterate over multiple CODECs in snd_soc_dai_link_event. This also introduced a compiler warning for a potentially uninitialised variable in the case no CODECs are present. This should never be the case as the DAI link must by definition contain at least 1 CODEC however probably best to avoid the compiler warning by initialising ret to zero. Signed-off-by: Charles Keepax Signed-off-by: Mark Brown --- sound/soc/soc-dapm.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sound/soc/soc-dapm.c b/sound/soc/soc-dapm.c index 9f4edcd19e02..e496bc642c99 100644 --- a/sound/soc/soc-dapm.c +++ b/sound/soc/soc-dapm.c @@ -3623,7 +3623,7 @@ static int snd_soc_dai_link_event(struct snd_soc_dapm_widget *w, struct snd_pcm_hw_params *params = NULL; struct snd_pcm_runtime *runtime = NULL; unsigned int fmt; - int ret; + int ret = 0; config = rtd->dai_link->params + rtd->params_select; From 3b857472f34faa7d11001afa5e158833812c98d7 Mon Sep 17 00:00:00 2001 From: Yong Zhi Date: Tue, 7 Aug 2018 12:19:16 -0500 Subject: [PATCH 107/299] ASoC: Intel: hdac_hdmi: Limit sampling rates at dai creation Playback of 44.1Khz contents with HDMI plugged returns "Invalid pipe config" because HDMI paths in the FW topology are configured to operate at 48Khz. This patch filters out sampling rates not supported at hdac_hdmi_create_dais() to let user space SRC to do the converting. Signed-off-by: Yong Zhi Reviewed-by: Pierre-Louis Bossart Reviewed-by: Takashi Iwai Signed-off-by: Mark Brown --- sound/soc/codecs/hdac_hdmi.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/sound/soc/codecs/hdac_hdmi.c b/sound/soc/codecs/hdac_hdmi.c index dc6a0dfea050..41d90dc6ebf7 100644 --- a/sound/soc/codecs/hdac_hdmi.c +++ b/sound/soc/codecs/hdac_hdmi.c @@ -1410,6 +1410,12 @@ static int hdac_hdmi_create_dais(struct hdac_device *hdev, if (ret) return ret; + /* Filter out 44.1, 88.2 and 176.4Khz */ + rates &= ~(SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_88200 | + SNDRV_PCM_RATE_176400); + if (!rates) + return -EINVAL; + sprintf(dai_name, "intel-hdmi-hifi%d", i+1); hdmi_dais[i].name = devm_kstrdup(&hdev->dev, dai_name, GFP_KERNEL); From 3004136b90bedc9e254ff659adb7a60299e9495e Mon Sep 17 00:00:00 2001 From: Grant Grundler Date: Thu, 6 Sep 2018 17:27:28 -0700 Subject: [PATCH 108/299] ASoC: max98373: usleep_range() needs include/delay.h Commit ca917f9fe1a0fab added use of usleep_range() but not the corresponding "include ". The result is with Chrome OS won't build because warnings are forced to be errors: mnt/host/source/src/third_party/kernel/v4.4/sound/soc/codecs/max98373.c:734:2: error: implicit declaration of function 'usleep_range' [-Werror,-Wimplicit-function-declaration] usleep_range(10000, 11000); ^ Including delay.h "fixes" this. Signed-off-by: Grant Grundler Reviewed-by: Benson Leung Signed-off-by: Mark Brown --- sound/soc/codecs/max98373.c | 1 + 1 file changed, 1 insertion(+) diff --git a/sound/soc/codecs/max98373.c b/sound/soc/codecs/max98373.c index 1093f766d0d2..d6868c9a9ce6 100644 --- a/sound/soc/codecs/max98373.c +++ b/sound/soc/codecs/max98373.c @@ -2,6 +2,7 @@ // Copyright (c) 2017, Maxim Integrated #include +#include #include #include #include From 64b6acf60b665fffd419c23886a1cbeeb253cfb4 Mon Sep 17 00:00:00 2001 From: Ricardo Biehl Pasquali Date: Fri, 7 Sep 2018 16:58:54 -0300 Subject: [PATCH 109/299] ALSA: pcm: Update hardware pointer before start capture This ensures the transfer loop won't waste a run to read the few frames (if any) between start and hw_ptr update. It will wait for the next interrupt with wait_for_avail(). Signed-off-by: Ricardo Biehl Pasquali Signed-off-by: Takashi Iwai --- sound/core/pcm_lib.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/sound/core/pcm_lib.c b/sound/core/pcm_lib.c index 7f71c2449af5..40013b26f671 100644 --- a/sound/core/pcm_lib.c +++ b/sound/core/pcm_lib.c @@ -2172,6 +2172,10 @@ snd_pcm_sframes_t __snd_pcm_lib_xfer(struct snd_pcm_substream *substream, if (err < 0) goto _end_unlock; + runtime->twake = runtime->control->avail_min ? : 1; + if (runtime->status->state == SNDRV_PCM_STATE_RUNNING) + snd_pcm_update_hw_ptr(substream); + if (!is_playback && runtime->status->state == SNDRV_PCM_STATE_PREPARED) { if (size >= runtime->start_threshold) { @@ -2185,10 +2189,8 @@ snd_pcm_sframes_t __snd_pcm_lib_xfer(struct snd_pcm_substream *substream, } } - runtime->twake = runtime->control->avail_min ? : 1; - if (runtime->status->state == SNDRV_PCM_STATE_RUNNING) - snd_pcm_update_hw_ptr(substream); avail = snd_pcm_avail(substream); + while (size > 0) { snd_pcm_uframes_t frames, appl_ptr, appl_ofs; snd_pcm_uframes_t cont; From 2e558a8127de7b2ed3302f9adcf332ba3feeadb2 Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Fri, 7 Sep 2018 22:40:33 +0300 Subject: [PATCH 110/299] ASoC: dapm: Fix a couple uninitialized ret variables Smatch complains that these variables could be uninitialized. The first one in snd_soc_dai_link_event() is probably a false positive, because probably we know the lists are not empty. I would normally ignore the warning, but GCC complains here as well so I just silenced the warning. The "ret" in snd_soc_dapm_new_dai() does need to be initialized or it leads to a bogus dereference in the caller. Fixes: 3bbf5d34fd4a ("ASoC: dapm: Move error handling to snd_soc_dapm_new_control_unlocked") Signed-off-by: Dan Carpenter Signed-off-by: Mark Brown --- sound/soc/soc-dapm.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/sound/soc/soc-dapm.c b/sound/soc/soc-dapm.c index e496bc642c99..0dcdcc23dcfd 100644 --- a/sound/soc/soc-dapm.c +++ b/sound/soc/soc-dapm.c @@ -3938,8 +3938,10 @@ snd_soc_dapm_new_dai(struct snd_soc_card *card, struct snd_soc_pcm_runtime *rtd, dev_dbg(card->dev, "ASoC: adding %s widget\n", link_name); w = snd_soc_dapm_new_control_unlocked(&card->dapm, &template); - if (IS_ERR(w)) + if (IS_ERR(w)) { + ret = PTR_ERR(w); goto outfree_kcontrol_news; + } w->priv = rtd; From 0712e0288b7602efbde95d95bca4c651ccad01b8 Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Mon, 10 Sep 2018 11:40:48 +0300 Subject: [PATCH 111/299] ASoC: qdsp6: q6asm-dai: clean up a return Smatch complains that if both "psubstream" and "csubstream" are NULL then "ret" is uninitialized. That probably can't happen, but it's cleaner to just return zero anyway so let's do that. Signed-off-by: Dan Carpenter Acked-by: Srinivas Kandagatla Signed-off-by: Mark Brown --- sound/soc/qcom/qdsp6/q6asm-dai.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sound/soc/qcom/qdsp6/q6asm-dai.c b/sound/soc/qcom/qdsp6/q6asm-dai.c index 9db9a2944ef2..c75fab38905d 100644 --- a/sound/soc/qcom/qdsp6/q6asm-dai.c +++ b/sound/soc/qcom/qdsp6/q6asm-dai.c @@ -493,7 +493,7 @@ static int q6asm_dai_pcm_new(struct snd_soc_pcm_runtime *rtd) } } - return ret; + return 0; } static void q6asm_dai_pcm_free(struct snd_pcm *pcm) From e14614dc5153ad41f7d1e5b125e4cd155ca79aa2 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Fri, 7 Sep 2018 01:00:15 +0000 Subject: [PATCH 112/299] ASoC: atmel_ssc_dai: use devm_snd_soc_register_component() Now we have devm_snd_soc_register_component(). Let's use it instead of snd_soc_register_component(). Signed-off-by: Kuninori Morimoto Signed-off-by: Mark Brown --- sound/soc/atmel/atmel_ssc_dai.c | 13 +++---------- 1 file changed, 3 insertions(+), 10 deletions(-) diff --git a/sound/soc/atmel/atmel_ssc_dai.c b/sound/soc/atmel/atmel_ssc_dai.c index d3b69682d9c2..6291ec7f9dd6 100644 --- a/sound/soc/atmel/atmel_ssc_dai.c +++ b/sound/soc/atmel/atmel_ssc_dai.c @@ -1005,11 +1005,11 @@ static int asoc_ssc_init(struct device *dev) struct ssc_device *ssc = dev_get_drvdata(dev); int ret; - ret = snd_soc_register_component(dev, &atmel_ssc_component, + ret = devm_snd_soc_register_component(dev, &atmel_ssc_component, &atmel_ssc_dai, 1); if (ret) { dev_err(dev, "Could not register DAI: %d\n", ret); - goto err; + return ret; } if (ssc->pdata->use_dma) @@ -1019,15 +1019,10 @@ static int asoc_ssc_init(struct device *dev) if (ret) { dev_err(dev, "Could not register PCM: %d\n", ret); - goto err_unregister_dai; + return ret; } return 0; - -err_unregister_dai: - snd_soc_unregister_component(dev); -err: - return ret; } static void asoc_ssc_exit(struct device *dev) @@ -1038,8 +1033,6 @@ static void asoc_ssc_exit(struct device *dev) atmel_pcm_dma_platform_unregister(dev); else atmel_pcm_pdc_platform_unregister(dev); - - snd_soc_unregister_component(dev); } /** From 570f75b93551a6d70ecbd0a7b6d962b4ca4722f0 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Fri, 7 Sep 2018 01:00:49 +0000 Subject: [PATCH 113/299] ASoC: bcm: use devm_snd_soc_register_component() Now we have devm_snd_soc_register_component(). Let's use it instead of snd_soc_register_component(). Signed-off-by: Kuninori Morimoto Signed-off-by: Mark Brown --- sound/soc/bcm/cygnus-ssp.c | 13 ++++--------- 1 file changed, 4 insertions(+), 9 deletions(-) diff --git a/sound/soc/bcm/cygnus-ssp.c b/sound/soc/bcm/cygnus-ssp.c index b733f1446353..b7c358b48d8d 100644 --- a/sound/soc/bcm/cygnus-ssp.c +++ b/sound/soc/bcm/cygnus-ssp.c @@ -1334,7 +1334,7 @@ static int cygnus_ssp_probe(struct platform_device *pdev) cygaud->active_ports = 0; dev_dbg(dev, "Registering %d DAIs\n", active_port_count); - err = snd_soc_register_component(dev, &cygnus_ssp_component, + err = devm_snd_soc_register_component(dev, &cygnus_ssp_component, cygnus_ssp_dai, active_port_count); if (err) { dev_err(dev, "snd_soc_register_dai failed\n"); @@ -1345,32 +1345,27 @@ static int cygnus_ssp_probe(struct platform_device *pdev) if (cygaud->irq_num <= 0) { dev_err(dev, "platform_get_irq failed\n"); err = cygaud->irq_num; - goto err_irq; + return err; } err = audio_clk_init(pdev, cygaud); if (err) { dev_err(dev, "audio clock initialization failed\n"); - goto err_irq; + return err; } err = cygnus_soc_platform_register(dev, cygaud); if (err) { dev_err(dev, "platform reg error %d\n", err); - goto err_irq; + return err; } return 0; - -err_irq: - snd_soc_unregister_component(dev); - return err; } static int cygnus_ssp_remove(struct platform_device *pdev) { cygnus_soc_platform_unregister(&pdev->dev); - snd_soc_unregister_component(&pdev->dev); return 0; } From 10ccaa39d7628470a3de4aae9d2346a55cbee46e Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Fri, 7 Sep 2018 01:01:19 +0000 Subject: [PATCH 114/299] ASoC: hdac_hda: use devm_snd_soc_register_component() Now we have devm_snd_soc_register_component(). Let's use it instead of snd_soc_register_component(). Signed-off-by: Kuninori Morimoto Signed-off-by: Mark Brown --- sound/soc/codecs/hdac_hda.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/sound/soc/codecs/hdac_hda.c b/sound/soc/codecs/hdac_hda.c index 8c25a1332fa7..2aaa83028e55 100644 --- a/sound/soc/codecs/hdac_hda.c +++ b/sound/soc/codecs/hdac_hda.c @@ -448,7 +448,7 @@ static int hdac_hda_dev_probe(struct hdac_device *hdev) return -ENOMEM; /* ASoC specific initialization */ - ret = snd_soc_register_component(&hdev->dev, + ret = devm_snd_soc_register_component(&hdev->dev, &hdac_hda_codec, hdac_hda_dais, ARRAY_SIZE(hdac_hda_dais)); if (ret < 0) { @@ -464,7 +464,6 @@ static int hdac_hda_dev_probe(struct hdac_device *hdev) static int hdac_hda_dev_remove(struct hdac_device *hdev) { - snd_soc_unregister_component(&hdev->dev); return 0; } From 4fe1984ebc086ee39dd57983a7fee84c96c954a7 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Fri, 7 Sep 2018 01:01:34 +0000 Subject: [PATCH 115/299] ASoC: rt5668: use devm_snd_soc_register_component() Now we have devm_snd_soc_register_component(). Let's use it instead of snd_soc_register_component(). Signed-off-by: Kuninori Morimoto Signed-off-by: Mark Brown --- sound/soc/codecs/rt5668.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/sound/soc/codecs/rt5668.c b/sound/soc/codecs/rt5668.c index 3c19d03f2446..4412cd2910cd 100644 --- a/sound/soc/codecs/rt5668.c +++ b/sound/soc/codecs/rt5668.c @@ -2587,14 +2587,12 @@ static int rt5668_i2c_probe(struct i2c_client *i2c, } - return snd_soc_register_component(&i2c->dev, &soc_component_dev_rt5668, + return devm_snd_soc_register_component(&i2c->dev, &soc_component_dev_rt5668, rt5668_dai, ARRAY_SIZE(rt5668_dai)); } static int rt5668_i2c_remove(struct i2c_client *i2c) { - snd_soc_unregister_component(&i2c->dev); - return 0; } From 007ac42db9ff4c36e91d192353421c6209058e06 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Fri, 7 Sep 2018 01:01:50 +0000 Subject: [PATCH 116/299] ASoC: tscs454: use devm_snd_soc_register_component() Now we have devm_snd_soc_register_component(). Let's use it instead of snd_soc_register_component(). Signed-off-by: Kuninori Morimoto Signed-off-by: Mark Brown --- sound/soc/codecs/tscs454.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sound/soc/codecs/tscs454.c b/sound/soc/codecs/tscs454.c index ff85a0bf6170..93d84e5ae2d5 100644 --- a/sound/soc/codecs/tscs454.c +++ b/sound/soc/codecs/tscs454.c @@ -3459,7 +3459,7 @@ static int tscs454_i2c_probe(struct i2c_client *i2c, /* Sync pg sel reg with cache */ regmap_write(tscs454->regmap, R_PAGESEL, 0x00); - ret = snd_soc_register_component(&i2c->dev, &soc_component_dev_tscs454, + ret = devm_snd_soc_register_component(&i2c->dev, &soc_component_dev_tscs454, tscs454_dais, ARRAY_SIZE(tscs454_dais)); if (ret) { dev_err(&i2c->dev, "Failed to register component (%d)\n", ret); From bfacaa8c8956dd6076641043b7be848267a708eb Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Fri, 7 Sep 2018 01:02:38 +0000 Subject: [PATCH 117/299] ASoC: nuc900: use devm_snd_soc_register_component() Now we have devm_snd_soc_register_component(). Let's use it instead of snd_soc_register_component(). Signed-off-by: Kuninori Morimoto Signed-off-by: Mark Brown --- sound/soc/nuc900/nuc900-ac97.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/sound/soc/nuc900/nuc900-ac97.c b/sound/soc/nuc900/nuc900-ac97.c index 81b09d740ed9..6384bb6dacfd 100644 --- a/sound/soc/nuc900/nuc900-ac97.c +++ b/sound/soc/nuc900/nuc900-ac97.c @@ -356,7 +356,7 @@ static int nuc900_ac97_drvprobe(struct platform_device *pdev) if (ret) goto out; - ret = snd_soc_register_component(&pdev->dev, &nuc900_ac97_component, + ret = devm_snd_soc_register_component(&pdev->dev, &nuc900_ac97_component, &nuc900_ac97_dai, 1); if (ret) goto out; @@ -373,8 +373,6 @@ out: static int nuc900_ac97_drvremove(struct platform_device *pdev) { - snd_soc_unregister_component(&pdev->dev); - nuc900_ac97_data = NULL; snd_soc_set_ac97_ops(NULL); From 642a722d3116fbd22e59ac027f81b5ecd285f17c Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Fri, 7 Sep 2018 01:02:54 +0000 Subject: [PATCH 118/299] ASoC: omap: use devm_snd_soc_register_component() Now we have devm_snd_soc_register_component(). Let's use it instead of snd_soc_register_component(). Signed-off-by: Kuninori Morimoto Signed-off-by: Mark Brown --- sound/soc/omap/omap-hdmi-audio.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/sound/soc/omap/omap-hdmi-audio.c b/sound/soc/omap/omap-hdmi-audio.c index 8a99a8837dc9..673a9eb153b2 100644 --- a/sound/soc/omap/omap-hdmi-audio.c +++ b/sound/soc/omap/omap-hdmi-audio.c @@ -348,7 +348,7 @@ static int omap_hdmi_audio_probe(struct platform_device *pdev) default: return -EINVAL; } - ret = snd_soc_register_component(ad->dssdev, &omap_hdmi_component, + ret = devm_snd_soc_register_component(ad->dssdev, &omap_hdmi_component, dai_drv, 1); if (ret) return ret; @@ -383,7 +383,6 @@ static int omap_hdmi_audio_probe(struct platform_device *pdev) ret = snd_soc_register_card(card); if (ret) { dev_err(dev, "snd_soc_register_card failed (%d)\n", ret); - snd_soc_unregister_component(ad->dssdev); return ret; } @@ -400,7 +399,6 @@ static int omap_hdmi_audio_remove(struct platform_device *pdev) struct hdmi_audio_data *ad = platform_get_drvdata(pdev); snd_soc_unregister_card(ad->card); - snd_soc_unregister_component(ad->dssdev); return 0; } From afa88ee37b1383490df003ea005d1d9bc8afa8a8 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Fri, 7 Sep 2018 01:03:25 +0000 Subject: [PATCH 119/299] ASoC: sh: use devm_snd_soc_register_component() Now we have devm_snd_soc_register_component(). Let's use it instead of snd_soc_register_component(). Signed-off-by: Kuninori Morimoto Signed-off-by: Mark Brown --- sound/soc/sh/hac.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/sound/soc/sh/hac.c b/sound/soc/sh/hac.c index c2b496398e6b..17622ceb98c0 100644 --- a/sound/soc/sh/hac.c +++ b/sound/soc/sh/hac.c @@ -319,13 +319,12 @@ static int hac_soc_platform_probe(struct platform_device *pdev) if (ret != 0) return ret; - return snd_soc_register_component(&pdev->dev, &sh4_hac_component, + return devm_snd_soc_register_component(&pdev->dev, &sh4_hac_component, sh4_hac_dai, ARRAY_SIZE(sh4_hac_dai)); } static int hac_soc_platform_remove(struct platform_device *pdev) { - snd_soc_unregister_component(&pdev->dev); snd_soc_set_ac97_ops(NULL); return 0; } From fb77436a444e9836e6b1b0a457bc9c09cdce22f6 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Fri, 7 Sep 2018 01:03:53 +0000 Subject: [PATCH 120/299] ASoC: txx9: use devm_snd_soc_register_component() Now we have devm_snd_soc_register_component(). Let's use it instead of snd_soc_register_component(). Signed-off-by: Kuninori Morimoto Signed-off-by: Mark Brown --- sound/soc/txx9/txx9aclc-ac97.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/sound/soc/txx9/txx9aclc-ac97.c b/sound/soc/txx9/txx9aclc-ac97.c index e2ad00e3cae1..1cfca698ae4b 100644 --- a/sound/soc/txx9/txx9aclc-ac97.c +++ b/sound/soc/txx9/txx9aclc-ac97.c @@ -208,13 +208,12 @@ static int txx9aclc_ac97_dev_probe(struct platform_device *pdev) if (err < 0) return err; - return snd_soc_register_component(&pdev->dev, &txx9aclc_ac97_component, + return devm_snd_soc_register_component(&pdev->dev, &txx9aclc_ac97_component, &txx9aclc_ac97_dai, 1); } static int txx9aclc_ac97_dev_remove(struct platform_device *pdev) { - snd_soc_unregister_component(&pdev->dev); snd_soc_set_ac97_ops(NULL); return 0; } From 18fbe800e6066050ab6ae7751708da04975cdc22 Mon Sep 17 00:00:00 2001 From: zhong jiang Date: Sat, 8 Sep 2018 16:36:19 +0800 Subject: [PATCH 121/299] ASoC: q6core: Use kmemdup to replace kzalloc + memcpy kmemdup has implemented the function that kzalloc() + memcpy() will do. and we prefer to use the kmemdup rather than the open coded implementation. Signed-off-by: zhong jiang Signed-off-by: Mark Brown --- sound/soc/qcom/qdsp6/q6core.c | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/sound/soc/qcom/qdsp6/q6core.c b/sound/soc/qcom/qdsp6/q6core.c index 06f03a5fe9bd..ca1be7305524 100644 --- a/sound/soc/qcom/qdsp6/q6core.c +++ b/sound/soc/qcom/qdsp6/q6core.c @@ -105,12 +105,10 @@ static int q6core_callback(struct apr_device *adev, struct apr_resp_pkt *data) bytes = sizeof(*fwk) + fwk->num_services * sizeof(fwk->svc_api_info[0]); - core->fwk_version = kzalloc(bytes, GFP_ATOMIC); + core->fwk_version = kmemdup(data->payload, bytes, GFP_ATOMIC); if (!core->fwk_version) return -ENOMEM; - memcpy(core->fwk_version, data->payload, bytes); - core->fwk_version_supported = true; core->resp_received = true; @@ -124,12 +122,10 @@ static int q6core_callback(struct apr_device *adev, struct apr_resp_pkt *data) len = sizeof(*v) + v->num_services * sizeof(v->svc_api_info[0]); - core->svc_version = kzalloc(len, GFP_ATOMIC); + core->svc_version = kmemdup(data->payload, len, GFP_ATOMIC); if (!core->svc_version) return -ENOMEM; - memcpy(core->svc_version, data->payload, len); - core->get_version_supported = true; core->resp_received = true; From ca92cc4636fdedf0d7ee88a5e50cd2b85c246a3b Mon Sep 17 00:00:00 2001 From: zhong jiang Date: Sat, 8 Sep 2018 16:36:20 +0800 Subject: [PATCH 122/299] ASoC: skl-topology: Use kmemdup to replace kzalloc + memcpy kmemdup has implemented the function that kzalloc() + memcpy() will do. and we prefer to kmemdup rather than the open coded implementation. Signed-off-by: zhong jiang Signed-off-by: Mark Brown --- sound/soc/intel/skylake/skl-topology.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/sound/soc/intel/skylake/skl-topology.c b/sound/soc/intel/skylake/skl-topology.c index 2620d77729c5..52a9915da0f5 100644 --- a/sound/soc/intel/skylake/skl-topology.c +++ b/sound/soc/intel/skylake/skl-topology.c @@ -898,11 +898,10 @@ static int skl_tplg_set_module_bind_params(struct snd_soc_dapm_widget *w, bc = (struct skl_algo_data *)sb->dobj.private; if (bc->set_params == SKL_PARAM_BIND) { - params = kzalloc(bc->max, GFP_KERNEL); + params = kmemdup(bc->params, bc->max, GFP_KERNEL); if (!params) return -ENOMEM; - memcpy(params, bc->params, bc->max); skl_fill_sink_instance_id(ctx, params, bc->max, mconfig); From e36a1d0d249aa09f94d551cadf043a7f9f7fae00 Mon Sep 17 00:00:00 2001 From: Charles Keepax Date: Mon, 10 Sep 2018 15:28:39 +0100 Subject: [PATCH 123/299] ASoC: dapm: Add missing return value check for snd_soc_dapm_new_dai snd_soc_dapm_new_dai may return an error pointer and currently this isn't checked for in dapm_connect_dai_link_widgets. Add code to check the return value and not add routes in that case. Fixes: 778ff5bb8689 ("ASoC: dapm: Move connection of CODEC to CODEC DAIs") Reported-by: Dan Carpenter Signed-off-by: Charles Keepax Signed-off-by: Mark Brown --- sound/soc/soc-dapm.c | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/sound/soc/soc-dapm.c b/sound/soc/soc-dapm.c index 0dcdcc23dcfd..43983c69f6aa 100644 --- a/sound/soc/soc-dapm.c +++ b/sound/soc/soc-dapm.c @@ -4087,6 +4087,13 @@ static void dapm_connect_dai_link_widgets(struct snd_soc_card *card, playback = snd_soc_dapm_new_dai(card, rtd, playback_cpu, codec); + if (IS_ERR(playback)) { + dev_err(rtd->dev, + "ASoC: Failed to create DAI %s: %ld\n", + codec_dai->name, + PTR_ERR(playback)); + continue; + } snd_soc_dapm_add_path(&card->dapm, playback_cpu, playback, NULL, NULL); @@ -4099,7 +4106,9 @@ static void dapm_connect_dai_link_widgets(struct snd_soc_card *card, snd_soc_dapm_add_path(&card->dapm, playback, codec, NULL, NULL); } + } + for_each_rtd_codec_dai(rtd, i, codec_dai) { /* connect BE DAI capture if widgets are valid */ codec = codec_dai->capture_widget; @@ -4108,6 +4117,13 @@ static void dapm_connect_dai_link_widgets(struct snd_soc_card *card, capture = snd_soc_dapm_new_dai(card, rtd, codec, capture_cpu); + if (IS_ERR(capture)) { + dev_err(rtd->dev, + "ASoC: Failed to create DAI %s: %ld\n", + codec_dai->name, + PTR_ERR(capture)); + continue; + } snd_soc_dapm_add_path(&card->dapm, capture, capture_cpu, NULL, NULL); From 8dcb0c90c691de5b79608d04ec7941ef9b3fee9c Mon Sep 17 00:00:00 2001 From: Akshu Agrawal Date: Mon, 10 Sep 2018 22:50:27 +0530 Subject: [PATCH 124/299] ASoC: AMD: Fix simultaneous playback and capture on different channel If capture and playback are started on different channel (I2S/BT) there is a possibilty that channel information passed from machine driver is overwritten before the configuration is done in dma driver. Example: 113.597588: cz_max_startup: ---playback sets BT channel 113.597694: cz_dmic1_startup: ---capture sets I2S channel 113.597979: acp_dma_hw_params: ---configures capture for I2S channel 113.598114: acp_dma_hw_params: ---configures playback for I2S channel This is fixed by having 2 separate instance for playback and capture. Signed-off-by: Akshu Agrawal Signed-off-by: Mark Brown --- sound/soc/amd/acp-da7219-max98357a.c | 40 +++++++++++++++++++++++----- sound/soc/amd/acp-pcm-dma.c | 8 ++++-- sound/soc/amd/acp.h | 3 ++- 3 files changed, 41 insertions(+), 10 deletions(-) diff --git a/sound/soc/amd/acp-da7219-max98357a.c b/sound/soc/amd/acp-da7219-max98357a.c index 3879cccbd2c0..717a017f0db6 100644 --- a/sound/soc/amd/acp-da7219-max98357a.c +++ b/sound/soc/amd/acp-da7219-max98357a.c @@ -133,7 +133,7 @@ static const struct snd_pcm_hw_constraint_list constraints_channels = { .mask = 0, }; -static int cz_da7219_startup(struct snd_pcm_substream *substream) +static int cz_da7219_play_startup(struct snd_pcm_substream *substream) { struct snd_pcm_runtime *runtime = substream->runtime; struct snd_soc_pcm_runtime *rtd = substream->private_data; @@ -150,7 +150,28 @@ static int cz_da7219_startup(struct snd_pcm_substream *substream) snd_pcm_hw_constraint_list(runtime, 0, SNDRV_PCM_HW_PARAM_RATE, &constraints_rates); - machine->i2s_instance = I2S_SP_INSTANCE; + machine->play_i2s_instance = I2S_SP_INSTANCE; + return da7219_clk_enable(substream); +} + +static int cz_da7219_cap_startup(struct snd_pcm_substream *substream) +{ + struct snd_pcm_runtime *runtime = substream->runtime; + struct snd_soc_pcm_runtime *rtd = substream->private_data; + struct snd_soc_card *card = rtd->card; + struct acp_platform_info *machine = snd_soc_card_get_drvdata(card); + + /* + * On this platform for PCM device we support stereo + */ + + runtime->hw.channels_max = DUAL_CHANNEL; + snd_pcm_hw_constraint_list(runtime, 0, SNDRV_PCM_HW_PARAM_CHANNELS, + &constraints_channels); + snd_pcm_hw_constraint_list(runtime, 0, SNDRV_PCM_HW_PARAM_RATE, + &constraints_rates); + + machine->cap_i2s_instance = I2S_SP_INSTANCE; machine->capture_channel = CAP_CHANNEL1; return da7219_clk_enable(substream); } @@ -177,7 +198,7 @@ static int cz_max_startup(struct snd_pcm_substream *substream) snd_pcm_hw_constraint_list(runtime, 0, SNDRV_PCM_HW_PARAM_RATE, &constraints_rates); - machine->i2s_instance = I2S_BT_INSTANCE; + machine->play_i2s_instance = I2S_BT_INSTANCE; return da7219_clk_enable(substream); } @@ -203,7 +224,7 @@ static int cz_dmic0_startup(struct snd_pcm_substream *substream) snd_pcm_hw_constraint_list(runtime, 0, SNDRV_PCM_HW_PARAM_RATE, &constraints_rates); - machine->i2s_instance = I2S_BT_INSTANCE; + machine->cap_i2s_instance = I2S_BT_INSTANCE; return da7219_clk_enable(substream); } @@ -224,7 +245,7 @@ static int cz_dmic1_startup(struct snd_pcm_substream *substream) snd_pcm_hw_constraint_list(runtime, 0, SNDRV_PCM_HW_PARAM_RATE, &constraints_rates); - machine->i2s_instance = I2S_SP_INSTANCE; + machine->cap_i2s_instance = I2S_SP_INSTANCE; machine->capture_channel = CAP_CHANNEL0; return da7219_clk_enable(substream); } @@ -234,8 +255,13 @@ static void cz_dmic_shutdown(struct snd_pcm_substream *substream) da7219_clk_disable(); } +static const struct snd_soc_ops cz_da7219_play_ops = { + .startup = cz_da7219_play_startup, + .shutdown = cz_da7219_shutdown, +}; + static const struct snd_soc_ops cz_da7219_cap_ops = { - .startup = cz_da7219_startup, + .startup = cz_da7219_cap_startup, .shutdown = cz_da7219_shutdown, }; @@ -266,7 +292,7 @@ static struct snd_soc_dai_link cz_dai_7219_98357[] = { | SND_SOC_DAIFMT_CBM_CFM, .init = cz_da7219_init, .dpcm_playback = 1, - .ops = &cz_da7219_cap_ops, + .ops = &cz_da7219_play_ops, }, { .name = "amd-da7219-cap", diff --git a/sound/soc/amd/acp-pcm-dma.c b/sound/soc/amd/acp-pcm-dma.c index e359938e3d7e..8f3bc6e37f26 100644 --- a/sound/soc/amd/acp-pcm-dma.c +++ b/sound/soc/amd/acp-pcm-dma.c @@ -846,8 +846,12 @@ static int acp_dma_hw_params(struct snd_pcm_substream *substream, return -EINVAL; if (pinfo) { - rtd->i2s_instance = pinfo->i2s_instance; - rtd->capture_channel = pinfo->capture_channel; + if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { + rtd->i2s_instance = pinfo->play_i2s_instance; + } else { + rtd->i2s_instance = pinfo->cap_i2s_instance; + rtd->capture_channel = pinfo->capture_channel; + } } if (adata->asic_type == CHIP_STONEY) { val = acp_reg_read(adata->acp_mmio, diff --git a/sound/soc/amd/acp.h b/sound/soc/amd/acp.h index be3963e8f4fa..dbbb1a85638d 100644 --- a/sound/soc/amd/acp.h +++ b/sound/soc/amd/acp.h @@ -158,7 +158,8 @@ struct audio_drv_data { * and dma driver */ struct acp_platform_info { - u16 i2s_instance; + u16 play_i2s_instance; + u16 cap_i2s_instance; u16 capture_channel; }; From 1c8bc7b3de5e76cb89aacdc7be1475a028af505f Mon Sep 17 00:00:00 2001 From: Robert Jarzmik Date: Sat, 25 Aug 2018 10:46:18 +0200 Subject: [PATCH 125/299] ASoC: pxa: switch to new ac97 bus support Switch to the new ac97 bus support in sound/ac97 instead of the legacy snd_ac97 one. Signed-off-by: Robert Jarzmik Signed-off-by: Mark Brown --- sound/arm/Kconfig | 1 - sound/soc/pxa/Kconfig | 5 ++-- sound/soc/pxa/pxa2xx-ac97.c | 48 +++++++++++++++++++------------------ 3 files changed, 27 insertions(+), 27 deletions(-) diff --git a/sound/arm/Kconfig b/sound/arm/Kconfig index 5fbd47a9177e..28867732a318 100644 --- a/sound/arm/Kconfig +++ b/sound/arm/Kconfig @@ -31,7 +31,6 @@ endif # SND_ARM config SND_PXA2XX_LIB tristate - select SND_AC97_CODEC if SND_PXA2XX_LIB_AC97 select SND_DMAENGINE_PCM config SND_PXA2XX_LIB_AC97 diff --git a/sound/soc/pxa/Kconfig b/sound/soc/pxa/Kconfig index 776e148b0aa2..29f577e6dfc0 100644 --- a/sound/soc/pxa/Kconfig +++ b/sound/soc/pxa/Kconfig @@ -19,14 +19,13 @@ config SND_MMP_SOC config SND_PXA2XX_AC97 tristate - select SND_AC97_CODEC config SND_PXA2XX_SOC_AC97 tristate - select AC97_BUS + select AC97_BUS_NEW select SND_PXA2XX_LIB select SND_PXA2XX_LIB_AC97 - select SND_SOC_AC97_BUS + select SND_SOC_AC97_BUS_NEW config SND_PXA2XX_SOC_I2S select SND_PXA2XX_LIB diff --git a/sound/soc/pxa/pxa2xx-ac97.c b/sound/soc/pxa/pxa2xx-ac97.c index 9f779657bc86..f8a3aa6c6d4e 100644 --- a/sound/soc/pxa/pxa2xx-ac97.c +++ b/sound/soc/pxa/pxa2xx-ac97.c @@ -17,6 +17,7 @@ #include #include +#include #include #include #include @@ -27,43 +28,35 @@ #include #include -static void pxa2xx_ac97_warm_reset(struct snd_ac97 *ac97) +static void pxa2xx_ac97_warm_reset(struct ac97_controller *adrv) { pxa2xx_ac97_try_warm_reset(); pxa2xx_ac97_finish_reset(); } -static void pxa2xx_ac97_cold_reset(struct snd_ac97 *ac97) +static void pxa2xx_ac97_cold_reset(struct ac97_controller *adrv) { pxa2xx_ac97_try_cold_reset(); pxa2xx_ac97_finish_reset(); } -static unsigned short pxa2xx_ac97_legacy_read(struct snd_ac97 *ac97, - unsigned short reg) +static int pxa2xx_ac97_read_actrl(struct ac97_controller *adrv, int slot, + unsigned short reg) { - int ret; - - ret = pxa2xx_ac97_read(ac97->num, reg); - if (ret < 0) - return 0; - else - return (unsigned short)(ret & 0xffff); + return pxa2xx_ac97_read(slot, reg); } -static void pxa2xx_ac97_legacy_write(struct snd_ac97 *ac97, - unsigned short reg, unsigned short val) +static int pxa2xx_ac97_write_actrl(struct ac97_controller *adrv, int slot, + unsigned short reg, unsigned short val) { - int ret; - - ret = pxa2xx_ac97_write(ac97->num, reg, val); + return pxa2xx_ac97_write(slot, reg, val); } -static struct snd_ac97_bus_ops pxa2xx_ac97_ops = { - .read = pxa2xx_ac97_legacy_read, - .write = pxa2xx_ac97_legacy_write, +static struct ac97_controller_ops pxa2xx_ac97_ops = { + .read = pxa2xx_ac97_read_actrl, + .write = pxa2xx_ac97_write_actrl, .warm_reset = pxa2xx_ac97_warm_reset, .reset = pxa2xx_ac97_cold_reset, }; @@ -233,6 +226,9 @@ MODULE_DEVICE_TABLE(of, pxa2xx_ac97_dt_ids); static int pxa2xx_ac97_dev_probe(struct platform_device *pdev) { int ret; + struct ac97_controller *ctrl; + pxa2xx_audio_ops_t *pdata = pdev->dev.platform_data; + void **codecs_pdata; if (pdev->id != -1) { dev_err(&pdev->dev, "PXA2xx has only one AC97 port.\n"); @@ -245,10 +241,14 @@ static int pxa2xx_ac97_dev_probe(struct platform_device *pdev) return ret; } - ret = snd_soc_set_ac97_ops(&pxa2xx_ac97_ops); - if (ret != 0) - return ret; + codecs_pdata = pdata ? pdata->codec_pdata : NULL; + ctrl = snd_ac97_controller_register(&pxa2xx_ac97_ops, &pdev->dev, + AC97_SLOTS_AVAILABLE_ALL, + codecs_pdata); + if (IS_ERR(ctrl)) + return PTR_ERR(ctrl); + platform_set_drvdata(pdev, ctrl); /* Punt most of the init to the SoC probe; we may need the machine * driver to do interesting things with the clocking to get us up * and running. @@ -259,8 +259,10 @@ static int pxa2xx_ac97_dev_probe(struct platform_device *pdev) static int pxa2xx_ac97_dev_remove(struct platform_device *pdev) { + struct ac97_controller *ctrl = platform_get_drvdata(pdev); + snd_soc_unregister_component(&pdev->dev); - snd_soc_set_ac97_ops(NULL); + snd_ac97_controller_unregister(ctrl); pxa2xx_ac97_hw_remove(pdev); return 0; } From ae7d1247d8673ebfd686b17e759d4be391165368 Mon Sep 17 00:00:00 2001 From: Rohit kumar Date: Tue, 11 Sep 2018 14:59:21 +0530 Subject: [PATCH 126/299] ASoC: Fix UBSAN warning at snd_soc_get/put_volsw_sx() In functions snd_soc_get_volsw_sx() or snd_soc_put_volsw_sx(), if the result of (min + max) is negative, then fls() returns signed integer with value as 32. This leads to signed integer overflow as complete operation is considered as signed integer. UBSAN: Undefined behaviour in sound/soc/soc-ops.c:382:50 signed integer overflow: -2147483648 - 1 cannot be represented in type 'int' Call trace: [] __dump_stack lib/dump_stack.c:15 [inline] [] dump_stack+0xec/0x158 lib/dump_stack.c:51 [] ubsan_epilogue+0x18/0x50 lib/ubsan.c:164 [] handle_overflow+0xf8/0x130 lib/ubsan.c:195 [] __ubsan_handle_sub_overflow+0x34/0x44 lib/ubsan.c:211 [] snd_soc_get_volsw_sx+0x1a8/0x1f8 sound/soc/soc-ops.c:382 Typecast the operation to unsigned int to fix the issue. Signed-off-by: Rohit kumar Signed-off-by: Mark Brown --- sound/soc/soc-ops.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/sound/soc/soc-ops.c b/sound/soc/soc-ops.c index 592efb370c44..f4dc3d445aae 100644 --- a/sound/soc/soc-ops.c +++ b/sound/soc/soc-ops.c @@ -373,7 +373,7 @@ int snd_soc_get_volsw_sx(struct snd_kcontrol *kcontrol, unsigned int rshift = mc->rshift; int max = mc->max; int min = mc->min; - unsigned int mask = (1 << (fls(min + max) - 1)) - 1; + unsigned int mask = (1U << (fls(min + max) - 1)) - 1; unsigned int val; int ret; @@ -418,7 +418,7 @@ int snd_soc_put_volsw_sx(struct snd_kcontrol *kcontrol, unsigned int rshift = mc->rshift; int max = mc->max; int min = mc->min; - unsigned int mask = (1 << (fls(min + max) - 1)) - 1; + unsigned int mask = (1U << (fls(min + max) - 1)) - 1; int err = 0; unsigned int val, val_mask, val2 = 0; From 5b03006d5c58ddd31caf542eef4d0269bcf265b3 Mon Sep 17 00:00:00 2001 From: Anders Roxell Date: Tue, 11 Sep 2018 16:18:36 +0200 Subject: [PATCH 127/299] ALSA: hda: fix unused variable warning MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit When CONFIG_X86=n function azx_snoop doesn't use the variable chip it only returns true. sound/pci/hda/hda_intel.c: In function ‘dma_alloc_pages’: sound/pci/hda/hda_intel.c:2002:14: warning: unused variable ‘chip’ [-Wunused-variable] struct azx *chip = bus_to_azx(bus); ^~~~ Create a inline function of azx_snoop. Fixes: a41d122449be ("ALSA: hda - Embed bus into controller object") Signed-off-by: Anders Roxell Signed-off-by: Takashi Iwai --- sound/pci/hda/hda_controller.h | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/sound/pci/hda/hda_controller.h b/sound/pci/hda/hda_controller.h index 0053b704ddc4..c95097bb5a0c 100644 --- a/sound/pci/hda/hda_controller.h +++ b/sound/pci/hda/hda_controller.h @@ -170,11 +170,10 @@ struct azx { #define azx_bus(chip) (&(chip)->bus.core) #define bus_to_azx(_bus) container_of(_bus, struct azx, bus.core) -#ifdef CONFIG_X86 -#define azx_snoop(chip) ((chip)->snoop) -#else -#define azx_snoop(chip) true -#endif +static inline bool azx_snoop(struct azx *chip) +{ + return !IS_ENABLED(CONFIG_X86) || chip->snoop; +} /* * macros for easy use From a6ebf4c9770e918e601aa9bf4bc3cf4001dd3d4d Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Tue, 11 Sep 2018 07:02:04 +0000 Subject: [PATCH 128/299] ASoC: rt5668: remove empty rt5668_i2c_remove() rt5668_i2c_remove() is empty, and no longer needed. Let's remove it. Signed-off-by: Kuninori Morimoto Signed-off-by: Mark Brown --- sound/soc/codecs/rt5668.c | 6 ------ 1 file changed, 6 deletions(-) diff --git a/sound/soc/codecs/rt5668.c b/sound/soc/codecs/rt5668.c index 4412cd2910cd..85ba04d6e7ae 100644 --- a/sound/soc/codecs/rt5668.c +++ b/sound/soc/codecs/rt5668.c @@ -2591,11 +2591,6 @@ static int rt5668_i2c_probe(struct i2c_client *i2c, rt5668_dai, ARRAY_SIZE(rt5668_dai)); } -static int rt5668_i2c_remove(struct i2c_client *i2c) -{ - return 0; -} - static void rt5668_i2c_shutdown(struct i2c_client *client) { struct rt5668_priv *rt5668 = i2c_get_clientdata(client); @@ -2626,7 +2621,6 @@ static struct i2c_driver rt5668_i2c_driver = { .acpi_match_table = ACPI_PTR(rt5668_acpi_match), }, .probe = rt5668_i2c_probe, - .remove = rt5668_i2c_remove, .shutdown = rt5668_i2c_shutdown, .id_table = rt5668_i2c_id, }; From 2eda3cb108b699a6ff78a87e25143c153bc88e41 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Tue, 11 Sep 2018 06:54:26 +0000 Subject: [PATCH 129/299] ASoC: soc-core: avoid nested code on soc_remove_dai() Nested code is not readable. This patch avoid it on soc_remove_dai(). Signed-off-by: Kuninori Morimoto Signed-off-by: Mark Brown --- sound/soc/soc-core.c | 21 +++++++++++---------- 1 file changed, 11 insertions(+), 10 deletions(-) diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c index 4e9367aacc0c..dde9b70b58b5 100644 --- a/sound/soc/soc-core.c +++ b/sound/soc/soc-core.c @@ -942,17 +942,18 @@ static void soc_remove_dai(struct snd_soc_dai *dai, int order) { int err; - if (dai && dai->probed && - dai->driver->remove_order == order) { - if (dai->driver->remove) { - err = dai->driver->remove(dai); - if (err < 0) - dev_err(dai->dev, - "ASoC: failed to remove %s: %d\n", - dai->name, err); - } - dai->probed = 0; + if (!dai || !dai->probed || + dai->driver->remove_order != order) + return; + + if (dai->driver->remove) { + err = dai->driver->remove(dai); + if (err < 0) + dev_err(dai->dev, + "ASoC: failed to remove %s: %d\n", + dai->name, err); } + dai->probed = 0; } static void soc_remove_link_dais(struct snd_soc_card *card, From 4f1b327e65a9516a46ea491ce72a5161be176af8 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Tue, 11 Sep 2018 06:59:01 +0000 Subject: [PATCH 130/299] ASoC: soc-core: remove unused num_dai_links ALSA SoC is counting card->dai_link_list user, but no-one is using it. Let's remove it. Signed-off-by: Kuninori Morimoto Signed-off-by: Mark Brown --- include/sound/soc.h | 1 - sound/soc/soc-core.c | 4 ---- 2 files changed, 5 deletions(-) diff --git a/include/sound/soc.h b/include/sound/soc.h index 821bf99992b8..e17a7ae9a155 100644 --- a/include/sound/soc.h +++ b/include/sound/soc.h @@ -1060,7 +1060,6 @@ struct snd_soc_card { struct snd_soc_dai_link *dai_link; /* predefined links only */ int num_links; /* predefined links only */ struct list_head dai_link_list; /* all links */ - int num_dai_links; struct list_head rtd_list; int num_rtd; diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c index dde9b70b58b5..7e18937c2214 100644 --- a/sound/soc/soc-core.c +++ b/sound/soc/soc-core.c @@ -1013,7 +1013,6 @@ static void soc_remove_dai_links(struct snd_soc_card *card) link->name); list_del(&link->list); - card->num_dai_links--; } } @@ -1182,7 +1181,6 @@ int snd_soc_add_dai_link(struct snd_soc_card *card, card->add_dai_link(card, dai_link); list_add_tail(&dai_link->list, &card->dai_link_list); - card->num_dai_links++; return 0; } @@ -1220,7 +1218,6 @@ void snd_soc_remove_dai_link(struct snd_soc_card *card, list_for_each_entry_safe(link, _link, &card->dai_link_list, list) { if (link == dai_link) { list_del(&link->list); - card->num_dai_links--; return; } } @@ -2712,7 +2709,6 @@ int snd_soc_register_card(struct snd_soc_card *card) snd_soc_initialize_card_lists(card); INIT_LIST_HEAD(&card->dai_link_list); - card->num_dai_links = 0; INIT_LIST_HEAD(&card->rtd_list); card->num_rtd = 0; From 24d6638302b48328a58c13439276d4531af4ca7d Mon Sep 17 00:00:00 2001 From: Katsuhiro Suzuki Date: Tue, 11 Sep 2018 01:39:32 +0900 Subject: [PATCH 131/299] ASoC: rockchip: add missing INTERLEAVED PCM attribute This patch adds SNDRV_PCM_INFO_INTERLEAVED into PCM hardware info. Signed-off-by: Katsuhiro Suzuki Signed-off-by: Mark Brown --- sound/soc/rockchip/rockchip_pcm.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/sound/soc/rockchip/rockchip_pcm.c b/sound/soc/rockchip/rockchip_pcm.c index f77538319221..9e7b5fa4cf59 100644 --- a/sound/soc/rockchip/rockchip_pcm.c +++ b/sound/soc/rockchip/rockchip_pcm.c @@ -21,7 +21,8 @@ static const struct snd_pcm_hardware snd_rockchip_hardware = { .info = SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_MMAP_VALID | SNDRV_PCM_INFO_PAUSE | - SNDRV_PCM_INFO_RESUME, + SNDRV_PCM_INFO_RESUME | + SNDRV_PCM_INFO_INTERLEAVED, .period_bytes_min = 32, .period_bytes_max = 8192, .periods_min = 1, From e1e38ea14ea3294546e6350d05a1376197a73589 Mon Sep 17 00:00:00 2001 From: zhong jiang Date: Wed, 12 Sep 2018 11:41:49 +0800 Subject: [PATCH 132/299] ASoC: remove unneeded static set .owner field in platform_driver platform_driver_register will set the .owner field. So it is safe to remove the redundant assignment. The issue is detected with the help of Coccinelle. Signed-off-by: zhong jiang Signed-off-by: Mark Brown --- sound/soc/mediatek/mt2701/mt2701-wm8960.c | 1 - sound/soc/mediatek/mt6797/mt6797-mt6351.c | 1 - sound/soc/rockchip/rk3288_hdmi_analog.c | 1 - 3 files changed, 3 deletions(-) diff --git a/sound/soc/mediatek/mt2701/mt2701-wm8960.c b/sound/soc/mediatek/mt2701/mt2701-wm8960.c index 89f34efd9747..e5d49e6e2f99 100644 --- a/sound/soc/mediatek/mt2701/mt2701-wm8960.c +++ b/sound/soc/mediatek/mt2701/mt2701-wm8960.c @@ -150,7 +150,6 @@ static const struct of_device_id mt2701_wm8960_machine_dt_match[] = { static struct platform_driver mt2701_wm8960_machine = { .driver = { .name = "mt2701-wm8960", - .owner = THIS_MODULE, #ifdef CONFIG_OF .of_match_table = mt2701_wm8960_machine_dt_match, #endif diff --git a/sound/soc/mediatek/mt6797/mt6797-mt6351.c b/sound/soc/mediatek/mt6797/mt6797-mt6351.c index b1558c57b9ca..6e578e830e42 100644 --- a/sound/soc/mediatek/mt6797/mt6797-mt6351.c +++ b/sound/soc/mediatek/mt6797/mt6797-mt6351.c @@ -205,7 +205,6 @@ static const struct of_device_id mt6797_mt6351_dt_match[] = { static struct platform_driver mt6797_mt6351_driver = { .driver = { .name = "mt6797-mt6351", - .owner = THIS_MODULE, #ifdef CONFIG_OF .of_match_table = mt6797_mt6351_dt_match, #endif diff --git a/sound/soc/rockchip/rk3288_hdmi_analog.c b/sound/soc/rockchip/rk3288_hdmi_analog.c index 929b3fe289b0..a472d5eb2950 100644 --- a/sound/soc/rockchip/rk3288_hdmi_analog.c +++ b/sound/soc/rockchip/rk3288_hdmi_analog.c @@ -286,7 +286,6 @@ static struct platform_driver rockchip_sound_driver = { .probe = snd_rk_mc_probe, .driver = { .name = DRV_NAME, - .owner = THIS_MODULE, .pm = &snd_soc_pm_ops, .of_match_table = rockchip_sound_of_match, }, From e894efef9ac7c10b7727798dcc711cccf07569f9 Mon Sep 17 00:00:00 2001 From: Srinivas Kandagatla Date: Wed, 12 Sep 2018 10:15:00 +0100 Subject: [PATCH 133/299] ASoC: core: add support to card rebind Current behaviour of ASoC core w.r.t to component removal is that it unregisters dependent sound card totally. There is no support to rebind the card if the component comes back. Typical use case is DSP restart or kernel modules itself. With this patch, core now maintains list of cards that are unbind due to any of its depended components are removed and card not unregistered yet. This list is cleared when the card is rebind successfully or when the card is unregistered from machine driver. This list of unbind cards are tried to bind once again after every new component is successfully added, giving a fair chance for card bind to be successful. Signed-off-by: Srinivas Kandagatla Signed-off-by: Mark Brown --- include/sound/soc.h | 2 + sound/soc/soc-core.c | 87 ++++++++++++++++++++++++++++++-------------- 2 files changed, 61 insertions(+), 28 deletions(-) diff --git a/include/sound/soc.h b/include/sound/soc.h index e17a7ae9a155..1e093b399bc0 100644 --- a/include/sound/soc.h +++ b/include/sound/soc.h @@ -1097,6 +1097,7 @@ struct snd_soc_card { /* lists of probed devices belonging to this card */ struct list_head component_dev_list; + struct list_head list; struct list_head widgets; struct list_head paths; @@ -1373,6 +1374,7 @@ static inline void snd_soc_initialize_card_lists(struct snd_soc_card *card) INIT_LIST_HEAD(&card->dapm_list); INIT_LIST_HEAD(&card->aux_comp_list); INIT_LIST_HEAD(&card->component_dev_list); + INIT_LIST_HEAD(&card->list); } static inline bool snd_soc_volsw_is_stereo(struct soc_mixer_control *mc) diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c index 7e18937c2214..807f112fad80 100644 --- a/sound/soc/soc-core.c +++ b/sound/soc/soc-core.c @@ -52,6 +52,7 @@ EXPORT_SYMBOL_GPL(snd_soc_debugfs_root); static DEFINE_MUTEX(client_mutex); static LIST_HEAD(component_list); +static LIST_HEAD(unbind_card_list); /* * This is a timeout to do a DAPM powerdown after a stream is closed(). @@ -2679,6 +2680,33 @@ int snd_soc_dai_digital_mute(struct snd_soc_dai *dai, int mute, } EXPORT_SYMBOL_GPL(snd_soc_dai_digital_mute); +static int snd_soc_bind_card(struct snd_soc_card *card) +{ + struct snd_soc_pcm_runtime *rtd; + int ret; + + ret = snd_soc_instantiate_card(card); + if (ret != 0) + return ret; + + /* deactivate pins to sleep state */ + list_for_each_entry(rtd, &card->rtd_list, list) { + struct snd_soc_dai *cpu_dai = rtd->cpu_dai; + struct snd_soc_dai *codec_dai; + int j; + + for_each_rtd_codec_dai(rtd, j, codec_dai) { + if (!codec_dai->active) + pinctrl_pm_select_sleep_state(codec_dai->dev); + } + + if (!cpu_dai->active) + pinctrl_pm_select_sleep_state(cpu_dai->dev); + } + + return ret; +} + /** * snd_soc_register_card - Register a card with the ASoC core * @@ -2688,7 +2716,6 @@ EXPORT_SYMBOL_GPL(snd_soc_dai_digital_mute); int snd_soc_register_card(struct snd_soc_card *card) { int i, ret; - struct snd_soc_pcm_runtime *rtd; if (!card->name || !card->dev) return -EINVAL; @@ -2719,29 +2746,24 @@ int snd_soc_register_card(struct snd_soc_card *card) mutex_init(&card->mutex); mutex_init(&card->dapm_mutex); - ret = snd_soc_instantiate_card(card); - if (ret != 0) - return ret; - - /* deactivate pins to sleep state */ - list_for_each_entry(rtd, &card->rtd_list, list) { - struct snd_soc_dai *cpu_dai = rtd->cpu_dai; - struct snd_soc_dai *codec_dai; - int j; - - for_each_rtd_codec_dai(rtd, j, codec_dai) { - if (!codec_dai->active) - pinctrl_pm_select_sleep_state(codec_dai->dev); - } - - if (!cpu_dai->active) - pinctrl_pm_select_sleep_state(cpu_dai->dev); - } - - return ret; + return snd_soc_bind_card(card); } EXPORT_SYMBOL_GPL(snd_soc_register_card); +static void snd_soc_unbind_card(struct snd_soc_card *card, bool unregister) +{ + if (card->instantiated) { + card->instantiated = false; + snd_soc_dapm_shutdown(card); + soc_cleanup_card_resources(card); + if (!unregister) + list_add(&card->list, &unbind_card_list); + } else { + if (unregister) + list_del(&card->list); + } +} + /** * snd_soc_unregister_card - Unregister a card with the ASoC core * @@ -2750,12 +2772,8 @@ EXPORT_SYMBOL_GPL(snd_soc_register_card); */ int snd_soc_unregister_card(struct snd_soc_card *card) { - if (card->instantiated) { - card->instantiated = false; - snd_soc_dapm_shutdown(card); - soc_cleanup_card_resources(card); - dev_dbg(card->dev, "ASoC: Unregistered card '%s'\n", card->name); - } + snd_soc_unbind_card(card, true); + dev_dbg(card->dev, "ASoC: Unregistered card '%s'\n", card->name); return 0; } @@ -3099,7 +3117,7 @@ static void snd_soc_component_del_unlocked(struct snd_soc_component *component) struct snd_soc_card *card = component->card; if (card) - snd_soc_unregister_card(card); + snd_soc_unbind_card(card, false); list_del(&component->list); } @@ -3139,6 +3157,18 @@ static void convert_endianness_formats(struct snd_soc_pcm_stream *stream) stream->formats |= endianness_format_map[i]; } +static void snd_soc_try_rebind_card(void) +{ + struct snd_soc_card *card, *c; + + if (!list_empty(&unbind_card_list)) { + list_for_each_entry_safe(card, c, &unbind_card_list, list) { + if (!snd_soc_bind_card(card)) + list_del(&card->list); + } + } +} + int snd_soc_add_component(struct device *dev, struct snd_soc_component *component, const struct snd_soc_component_driver *component_driver, @@ -3166,6 +3196,7 @@ int snd_soc_add_component(struct device *dev, } snd_soc_component_add(component); + snd_soc_try_rebind_card(); return 0; From a7c439d6128de2cbc087ae7524b47f613ff8bc6c Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Tue, 11 Sep 2018 15:50:27 +0900 Subject: [PATCH 134/299] ASoC: soc-core: remove dai->driver NULL check It is strange if it has "dai" but doesn't have "dai->driver". And more over "dai->driver->xxx" is used everywhere without "dai->driver" pointer NULL checking. It got Oops already if "dai->driver" was NULL. Let's remove un-needed "dai->driver" NULL check. Signed-off-by: Kuninori Morimoto Signed-off-by: Mark Brown --- sound/soc/soc-core.c | 5 ----- 1 file changed, 5 deletions(-) diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c index 807f112fad80..325dc1964850 100644 --- a/sound/soc/soc-core.c +++ b/sound/soc/soc-core.c @@ -2519,8 +2519,6 @@ EXPORT_SYMBOL_GPL(snd_soc_dai_set_bclk_ratio); */ int snd_soc_dai_set_fmt(struct snd_soc_dai *dai, unsigned int fmt) { - if (dai->driver == NULL) - return -EINVAL; if (dai->driver->ops->set_fmt == NULL) return -ENOTSUPP; return dai->driver->ops->set_fmt(dai, fmt); @@ -2667,9 +2665,6 @@ EXPORT_SYMBOL_GPL(snd_soc_dai_set_tristate); int snd_soc_dai_digital_mute(struct snd_soc_dai *dai, int mute, int direction) { - if (!dai->driver) - return -ENOTSUPP; - if (dai->driver->ops->mute_stream) return dai->driver->ops->mute_stream(dai, mute, direction); else if (direction == SNDRV_PCM_STREAM_PLAYBACK && From d9b84a15892c02334ac8a5c28865ae54168d9b22 Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Wed, 12 Sep 2018 12:31:32 +0100 Subject: [PATCH 135/299] ALSA: hda: Fix implicit definition of pci_iomap() on SH Include asm/io.h directly so we've got a definition of pci_iomap(), the current set of includes do this implicitly on most architectures but not on SH. Reported-by: kbuild test robot Signed-off-by: Mark Brown --- sound/pci/hda/patch_ca0132.c | 1 + 1 file changed, 1 insertion(+) diff --git a/sound/pci/hda/patch_ca0132.c b/sound/pci/hda/patch_ca0132.c index a585d0ec6d77..6ea04f889809 100644 --- a/sound/pci/hda/patch_ca0132.c +++ b/sound/pci/hda/patch_ca0132.c @@ -31,6 +31,7 @@ #include #include #include +#include #include #include #include "hda_local.h" From 7064f376d4a10686f51c879401a569bb4babf9c6 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Tue, 28 Aug 2018 16:39:10 +0200 Subject: [PATCH 136/299] ALSA: intel8x0m: Register irq handler after register initializations The interrupt handler has to be acquired after the other resource initialization when allocated with IRQF_SHARED. Otherwise it's triggered before the resource gets ready, and may lead to unpleasant behavior. Signed-off-by: Takashi Iwai --- sound/pci/intel8x0m.c | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/sound/pci/intel8x0m.c b/sound/pci/intel8x0m.c index 943a726b1c1b..c84629190cba 100644 --- a/sound/pci/intel8x0m.c +++ b/sound/pci/intel8x0m.c @@ -1171,16 +1171,6 @@ static int snd_intel8x0m_create(struct snd_card *card, } port_inited: - if (request_irq(pci->irq, snd_intel8x0m_interrupt, IRQF_SHARED, - KBUILD_MODNAME, chip)) { - dev_err(card->dev, "unable to grab IRQ %d\n", pci->irq); - snd_intel8x0m_free(chip); - return -EBUSY; - } - chip->irq = pci->irq; - pci_set_master(pci); - synchronize_irq(chip->irq); - /* initialize offsets */ chip->bdbars_count = 2; tbl = intel_regs; @@ -1224,11 +1214,21 @@ static int snd_intel8x0m_create(struct snd_card *card, chip->int_sta_reg = ICH_REG_GLOB_STA; chip->int_sta_mask = int_sta_masks; + pci_set_master(pci); + if ((err = snd_intel8x0m_chip_init(chip, 1)) < 0) { snd_intel8x0m_free(chip); return err; } + if (request_irq(pci->irq, snd_intel8x0m_interrupt, IRQF_SHARED, + KBUILD_MODNAME, chip)) { + dev_err(card->dev, "unable to grab IRQ %d\n", pci->irq); + snd_intel8x0m_free(chip); + return -EBUSY; + } + chip->irq = pci->irq; + if ((err = snd_device_new(card, SNDRV_DEV_LOWLEVEL, chip, &ops)) < 0) { snd_intel8x0m_free(chip); return err; From 05e2ec3b00edb277b325489e0d1de3570ad16359 Mon Sep 17 00:00:00 2001 From: "Gustavo A. R. Silva" Date: Thu, 13 Sep 2018 13:43:47 -0500 Subject: [PATCH 137/299] ALSA: atiixp: fix fall-through annotations Replace "fallthru" with a proper "fall through" annotation. This fix is part of the ongoing efforts to enabling -Wimplicit-fallthrough Signed-off-by: Gustavo A. R. Silva Signed-off-by: Takashi Iwai --- sound/pci/atiixp.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/sound/pci/atiixp.c b/sound/pci/atiixp.c index a1e4944dcfe8..1a41f8c80243 100644 --- a/sound/pci/atiixp.c +++ b/sound/pci/atiixp.c @@ -903,15 +903,15 @@ static int snd_atiixp_playback_prepare(struct snd_pcm_substream *substream) case 8: data |= ATI_REG_OUT_DMA_SLOT_BIT(10) | ATI_REG_OUT_DMA_SLOT_BIT(11); - /* fallthru */ + /* fall through */ case 6: data |= ATI_REG_OUT_DMA_SLOT_BIT(7) | ATI_REG_OUT_DMA_SLOT_BIT(8); - /* fallthru */ + /* fall through */ case 4: data |= ATI_REG_OUT_DMA_SLOT_BIT(6) | ATI_REG_OUT_DMA_SLOT_BIT(9); - /* fallthru */ + /* fall through */ default: data |= ATI_REG_OUT_DMA_SLOT_BIT(3) | ATI_REG_OUT_DMA_SLOT_BIT(4); From 597d18325acdb48eb516ca9ef33d5148e79ca3bb Mon Sep 17 00:00:00 2001 From: "Gustavo A. R. Silva" Date: Thu, 13 Sep 2018 14:08:15 -0500 Subject: [PATCH 138/299] ASoC: es8328: Fix fall-through annotations Replace "fallthru" with a proper "fall through" annotation. This fix is part of the ongoing efforts to enabling -Wimplicit-fallthrough Signed-off-by: Gustavo A. R. Silva Signed-off-by: Mark Brown --- sound/soc/codecs/es8328.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/sound/soc/codecs/es8328.c b/sound/soc/codecs/es8328.c index e9fc2fd97d2f..3aedd609626c 100644 --- a/sound/soc/codecs/es8328.c +++ b/sound/soc/codecs/es8328.c @@ -566,14 +566,14 @@ static int es8328_set_sysclk(struct snd_soc_dai *codec_dai, break; case 22579200: mclkdiv2 = 1; - /* fallthru */ + /* fall through */ case 11289600: es8328->sysclk_constraints = &constraints_11289; es8328->mclk_ratios = ratios_11289; break; case 24576000: mclkdiv2 = 1; - /* fallthru */ + /* fall through */ case 12288000: es8328->sysclk_constraints = &constraints_12288; es8328->mclk_ratios = ratios_12288; From 982e386379f01aa6254e3313cff1edcb04c66685 Mon Sep 17 00:00:00 2001 From: "Gustavo A. R. Silva" Date: Thu, 13 Sep 2018 14:11:07 -0500 Subject: [PATCH 139/299] ASoC: hisilicon: fix fall-through annotations Replace "fallthru" with a proper "fall through" annotation. This fix is part of the ongoing efforts to enabling -Wimplicit-fallthrough Signed-off-by: Gustavo A. R. Silva Signed-off-by: Mark Brown --- sound/soc/hisilicon/hi6210-i2s.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/sound/soc/hisilicon/hi6210-i2s.c b/sound/soc/hisilicon/hi6210-i2s.c index 53344a3b7a60..a69e5b11b3da 100644 --- a/sound/soc/hisilicon/hi6210-i2s.c +++ b/sound/soc/hisilicon/hi6210-i2s.c @@ -269,13 +269,13 @@ static int hi6210_i2s_hw_params(struct snd_pcm_substream *substream, switch (params_format(params)) { case SNDRV_PCM_FORMAT_U16_LE: signed_data = HII2S_I2S_CFG__S2_CODEC_DATA_FORMAT; - /* fallthru */ + /* fall through */ case SNDRV_PCM_FORMAT_S16_LE: bits = HII2S_BITS_16; break; case SNDRV_PCM_FORMAT_U24_LE: signed_data = HII2S_I2S_CFG__S2_CODEC_DATA_FORMAT; - /* fallthru */ + /* fall through */ case SNDRV_PCM_FORMAT_S24_LE: bits = HII2S_BITS_24; break; From 24b7a0aa1abec41b62c9a29a75e511d29f95033b Mon Sep 17 00:00:00 2001 From: YueHaibing Date: Fri, 14 Sep 2018 01:36:04 +0000 Subject: [PATCH 140/299] ASoC: qdsp6: q6asm-dai: remove duplicated include from q6asm-dai.c Remove duplicated include. Signed-off-by: YueHaibing Acked-by: Srinivas Kandagatla Signed-off-by: Mark Brown --- sound/soc/qcom/qdsp6/q6asm-dai.c | 1 - 1 file changed, 1 deletion(-) diff --git a/sound/soc/qcom/qdsp6/q6asm-dai.c b/sound/soc/qcom/qdsp6/q6asm-dai.c index c75fab38905d..c3806d7037fc 100644 --- a/sound/soc/qcom/qdsp6/q6asm-dai.c +++ b/sound/soc/qcom/qdsp6/q6asm-dai.c @@ -8,7 +8,6 @@ #include #include #include -#include #include #include #include From 4a9ed39477bd1635cf23b49e10f9e364329bbe46 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Tue, 11 Sep 2018 06:51:14 +0000 Subject: [PATCH 141/299] ASoC: soc-core: manage platform name under snd_soc_init_platform() Now "platform" is controlled by snd_soc_dai_link_component, thus its "name" can be initialized in snd_soc_init_platform(), instead of soc_bind_dai_link() local. This patch do it. Signed-off-by: Kuninori Morimoto Signed-off-by: Mark Brown --- sound/soc/soc-core.c | 33 +++++++++++++++++---------------- 1 file changed, 17 insertions(+), 16 deletions(-) diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c index 325dc1964850..d856b08f5f99 100644 --- a/sound/soc/soc-core.c +++ b/sound/soc/soc-core.c @@ -845,7 +845,6 @@ static int soc_bind_dai_link(struct snd_soc_card *card, struct snd_soc_component *component; struct snd_soc_dai **codec_dais; struct device_node *platform_of_node; - const char *platform_name; int i; if (dai_link->ignore) @@ -892,11 +891,6 @@ static int soc_bind_dai_link(struct snd_soc_card *card, /* Single codec links expect codec and codec_dai in runtime data */ rtd->codec_dai = codec_dais[0]; - /* if there's no platform we match on the empty platform */ - platform_name = dai_link->platform->name; - if (!platform_name && !dai_link->platform->of_node) - platform_name = "snd-soc-dummy"; - /* find one from the set of registered platforms */ list_for_each_entry(component, &component_list, list) { platform_of_node = component->dev->of_node; @@ -907,7 +901,7 @@ static int soc_bind_dai_link(struct snd_soc_card *card, if (platform_of_node != dai_link->platform->of_node) continue; } else { - if (strcmp(component->name, platform_name)) + if (strcmp(component->name, dai_link->platform->name)) continue; } @@ -1020,24 +1014,31 @@ static void soc_remove_dai_links(struct snd_soc_card *card) static int snd_soc_init_platform(struct snd_soc_card *card, struct snd_soc_dai_link *dai_link) { + struct snd_soc_dai_link_component *platform = dai_link->platform; + /* * FIXME * * this function should be removed in the future */ /* convert Legacy platform link */ - if (dai_link->platform) - return 0; - - dai_link->platform = devm_kzalloc(card->dev, + if (!platform) { + platform = devm_kzalloc(card->dev, sizeof(struct snd_soc_dai_link_component), GFP_KERNEL); - if (!dai_link->platform) - return -ENOMEM; + if (!platform) + return -ENOMEM; - dai_link->platform->name = dai_link->platform_name; - dai_link->platform->of_node = dai_link->platform_of_node; - dai_link->platform->dai_name = NULL; + dai_link->platform = platform; + platform->name = dai_link->platform_name; + platform->of_node = dai_link->platform_of_node; + platform->dai_name = NULL; + } + + /* if there's no platform we match on the empty platform */ + if (!platform->name && + !platform->of_node) + platform->name = "snd-soc-dummy"; return 0; } From be6ac0a9ced99403c435b2b2fe9ac4bd55749823 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Tue, 11 Sep 2018 06:51:45 +0000 Subject: [PATCH 142/299] ASoC: soc-core: add snd_soc_is_matching_component() To find (CPU/)Codec/Platform, we need to find component first (= on CPU/Codec/Platform), and find DAI from it (= CPU/Codec). These are similar operation but difficult to be simple, and has many duplicate code to finding component. This patch adds new snd_soc_is_matching_component(), and reduce duplicate codes. Signed-off-by: Kuninori Morimoto Signed-off-by: Mark Brown --- sound/soc/soc-core.c | 42 ++++++++++++++++++++++-------------------- 1 file changed, 22 insertions(+), 20 deletions(-) diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c index d856b08f5f99..da2b2a758b6d 100644 --- a/sound/soc/soc-core.c +++ b/sound/soc/soc-core.c @@ -737,6 +737,24 @@ static struct snd_soc_component *soc_find_component( return NULL; } +static int snd_soc_is_matching_component( + const struct snd_soc_dai_link_component *dlc, + struct snd_soc_component *component) +{ + struct device_node *component_of_node; + + component_of_node = component->dev->of_node; + if (!component_of_node && component->dev->parent) + component_of_node = component->dev->parent->of_node; + + if (dlc->of_node && component_of_node != dlc->of_node) + return 0; + if (dlc->name && strcmp(component->name, dlc->name)) + return 0; + + return 1; +} + /** * snd_soc_find_dai - Find a registered DAI * @@ -753,19 +771,12 @@ struct snd_soc_dai *snd_soc_find_dai( { struct snd_soc_component *component; struct snd_soc_dai *dai; - struct device_node *component_of_node; lockdep_assert_held(&client_mutex); /* Find CPU DAI from registered DAIs*/ list_for_each_entry(component, &component_list, list) { - component_of_node = component->dev->of_node; - if (!component_of_node && component->dev->parent) - component_of_node = component->dev->parent->of_node; - - if (dlc->of_node && component_of_node != dlc->of_node) - continue; - if (dlc->name && strcmp(component->name, dlc->name)) + if (!snd_soc_is_matching_component(dlc, component)) continue; list_for_each_entry(dai, &component->dai_list, list) { if (dlc->dai_name && strcmp(dai->name, dlc->dai_name) @@ -844,7 +855,6 @@ static int soc_bind_dai_link(struct snd_soc_card *card, struct snd_soc_dai_link_component cpu_dai_component; struct snd_soc_component *component; struct snd_soc_dai **codec_dais; - struct device_node *platform_of_node; int i; if (dai_link->ignore) @@ -893,17 +903,9 @@ static int soc_bind_dai_link(struct snd_soc_card *card, /* find one from the set of registered platforms */ list_for_each_entry(component, &component_list, list) { - platform_of_node = component->dev->of_node; - if (!platform_of_node && component->dev->parent->of_node) - platform_of_node = component->dev->parent->of_node; - - if (dai_link->platform->of_node) { - if (platform_of_node != dai_link->platform->of_node) - continue; - } else { - if (strcmp(component->name, dai_link->platform->name)) - continue; - } + if (!snd_soc_is_matching_component(dai_link->platform, + component)) + continue; snd_soc_rtdcom_add(rtd, component); } From fbb673f7c6555d5434ad005f86b0d4368b1203d9 Mon Sep 17 00:00:00 2001 From: Oder Chiou Date: Mon, 17 Sep 2018 19:03:09 +0800 Subject: [PATCH 143/299] ASoC: rt5514-spi: Get the period_bytes in the copy work to make sure the value correctly The value of period_bytes will get the zero before the hw_params() is not run completely. Move the function snd_pcm_lib_period_bytes() to copy work, and make sure that is not zero. Signed-off-by: Oder Chiou Signed-off-by: Mark Brown --- sound/soc/codecs/rt5514-spi.c | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/sound/soc/codecs/rt5514-spi.c b/sound/soc/codecs/rt5514-spi.c index 18686ffb0cd5..13809821e1f8 100644 --- a/sound/soc/codecs/rt5514-spi.c +++ b/sound/soc/codecs/rt5514-spi.c @@ -91,6 +91,14 @@ static void rt5514_spi_copy_work(struct work_struct *work) runtime = rt5514_dsp->substream->runtime; period_bytes = snd_pcm_lib_period_bytes(rt5514_dsp->substream); + if (!period_bytes) { + schedule_delayed_work(&rt5514_dsp->copy_work, 5); + goto done; + } + + if (rt5514_dsp->buf_size % period_bytes) + rt5514_dsp->buf_size = (rt5514_dsp->buf_size / period_bytes) * + period_bytes; if (rt5514_dsp->get_size >= rt5514_dsp->buf_size) { rt5514_spi_burst_read(RT5514_BUFFER_VOICE_WP, (u8 *)&buf, @@ -149,13 +157,11 @@ done: static void rt5514_schedule_copy(struct rt5514_dsp *rt5514_dsp) { - size_t period_bytes; u8 buf[8]; if (!rt5514_dsp->substream) return; - period_bytes = snd_pcm_lib_period_bytes(rt5514_dsp->substream); rt5514_dsp->get_size = 0; /** @@ -183,10 +189,6 @@ static void rt5514_schedule_copy(struct rt5514_dsp *rt5514_dsp) rt5514_dsp->buf_size = rt5514_dsp->buf_limit - rt5514_dsp->buf_base; - if (rt5514_dsp->buf_size % period_bytes) - rt5514_dsp->buf_size = (rt5514_dsp->buf_size / period_bytes) * - period_bytes; - if (rt5514_dsp->buf_base && rt5514_dsp->buf_limit && rt5514_dsp->buf_rp && rt5514_dsp->buf_size) schedule_delayed_work(&rt5514_dsp->copy_work, 0); From 29ca7d32d7f10737e8d165fcf40fe31d44b06bee Mon Sep 17 00:00:00 2001 From: zhong jiang Date: Tue, 18 Sep 2018 16:16:24 +0800 Subject: [PATCH 144/299] ASoC: remove redundant include module.h already contained moduleparam.h, so it is safe to remove the redundant include. The issue is detected with the help of Coccinelle. Signed-off-by: zhong jiang Acked-by: Charles Keepax Signed-off-by: Mark Brown --- sound/soc/codecs/rt5651.c | 1 - sound/soc/codecs/wm8904.c | 1 - sound/soc/codecs/wm8974.c | 1 - sound/soc/soc-dapm.c | 1 - 4 files changed, 4 deletions(-) diff --git a/sound/soc/codecs/rt5651.c b/sound/soc/codecs/rt5651.c index 985852fd9723..b613103d801b 100644 --- a/sound/soc/codecs/rt5651.c +++ b/sound/soc/codecs/rt5651.c @@ -10,7 +10,6 @@ */ #include -#include #include #include #include diff --git a/sound/soc/codecs/wm8904.c b/sound/soc/codecs/wm8904.c index 1965635ec07c..2a3e5fbd04e4 100644 --- a/sound/soc/codecs/wm8904.c +++ b/sound/soc/codecs/wm8904.c @@ -13,7 +13,6 @@ #include #include -#include #include #include #include diff --git a/sound/soc/codecs/wm8974.c b/sound/soc/codecs/wm8974.c index 43edaf8cd276..593a11960888 100644 --- a/sound/soc/codecs/wm8974.c +++ b/sound/soc/codecs/wm8974.c @@ -11,7 +11,6 @@ */ #include -#include #include #include #include diff --git a/sound/soc/soc-dapm.c b/sound/soc/soc-dapm.c index 43983c69f6aa..ee6b9758ec15 100644 --- a/sound/soc/soc-dapm.c +++ b/sound/soc/soc-dapm.c @@ -18,7 +18,6 @@ // device reopen. #include -#include #include #include #include From bf0fa00fd8410b377a3403adb58e32fc703e86e8 Mon Sep 17 00:00:00 2001 From: Shuming Fan Date: Tue, 18 Sep 2018 19:51:08 +0800 Subject: [PATCH 145/299] ASoC: rt5682: Improve HP performance We change the settings while HP power-up for better performance. Signed-off-by: Shuming Fan Signed-off-by: Mark Brown --- sound/soc/codecs/rt5682.c | 32 +++++++++++++++++++++++++++++--- sound/soc/codecs/rt5682.h | 14 ++++++++++++++ 2 files changed, 43 insertions(+), 3 deletions(-) diff --git a/sound/soc/codecs/rt5682.c b/sound/soc/codecs/rt5682.c index 731c6a849f69..83202e9e5abd 100644 --- a/sound/soc/codecs/rt5682.c +++ b/sound/soc/codecs/rt5682.c @@ -1437,6 +1437,28 @@ static const struct snd_kcontrol_new hpor_switch = SOC_DAPM_SINGLE_AUTODISABLE("Switch", RT5682_HP_CTRL_1, RT5682_R_MUTE_SFT, 1, 1); +static int rt5682_charge_pump_event(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kcontrol, int event) +{ + struct snd_soc_component *component = + snd_soc_dapm_to_component(w->dapm); + + switch (event) { + case SND_SOC_DAPM_PRE_PMU: + snd_soc_component_update_bits(component, + RT5682_HP_CHARGE_PUMP_1, RT5682_PM_HP_MASK, RT5682_PM_HP_HV); + break; + case SND_SOC_DAPM_POST_PMD: + snd_soc_component_update_bits(component, + RT5682_HP_CHARGE_PUMP_1, RT5682_PM_HP_MASK, RT5682_PM_HP_LV); + break; + default: + return 0; + } + + return 0; +} + static int rt5682_hp_event(struct snd_soc_dapm_widget *w, struct snd_kcontrol *kcontrol, int event) { @@ -1449,8 +1471,6 @@ static int rt5682_hp_event(struct snd_soc_dapm_widget *w, RT5682_HP_LOGIC_CTRL_2, 0x0012); snd_soc_component_write(component, RT5682_HP_CTRL_2, 0x6000); - snd_soc_component_update_bits(component, RT5682_STO_NG2_CTRL_1, - RT5682_NG2_EN_MASK, RT5682_NG2_EN); snd_soc_component_update_bits(component, RT5682_DEPOP_1, 0x60, 0x60); break; @@ -1723,7 +1743,8 @@ static const struct snd_soc_dapm_widget rt5682_dapm_widgets[] = { SND_SOC_DAPM_SUPPLY("HP Amp R", RT5682_PWR_ANLG_1, RT5682_PWR_HA_R_BIT, 0, NULL, 0), SND_SOC_DAPM_SUPPLY_S("Charge Pump", 1, RT5682_DEPOP_1, - RT5682_PUMP_EN_SFT, 0, NULL, 0), + RT5682_PUMP_EN_SFT, 0, rt5682_charge_pump_event, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), SND_SOC_DAPM_SUPPLY_S("Capless", 2, RT5682_DEPOP_1, RT5682_CAPLESS_EN_SFT, 0, NULL, 0), @@ -1884,6 +1905,7 @@ static const struct snd_soc_dapm_route rt5682_dapm_routes[] = { {"HP Amp", NULL, "Charge Pump"}, {"HP Amp", NULL, "CLKDET SYS"}, {"HP Amp", NULL, "CBJ Power"}, + {"HP Amp", NULL, "Vref1"}, {"HP Amp", NULL, "Vref2"}, {"HPOL Playback", "Switch", "HP Amp"}, {"HPOR Playback", "Switch", "HP Amp"}, @@ -2607,6 +2629,10 @@ static int rt5682_i2c_probe(struct i2c_client *i2c, RT5682_GP4_PIN_MASK | RT5682_GP5_PIN_MASK, RT5682_GP4_PIN_ADCDAT1 | RT5682_GP5_PIN_DACDAT1); regmap_write(rt5682->regmap, RT5682_TEST_MODE_CTRL_1, 0x0000); + regmap_update_bits(rt5682->regmap, RT5682_BIAS_CUR_CTRL_8, + RT5682_HPA_CP_BIAS_CTRL_MASK, RT5682_HPA_CP_BIAS_3UA); + regmap_update_bits(rt5682->regmap, RT5682_CHARGE_PUMP_1, + RT5682_CP_CLK_HP_MASK, RT5682_CP_CLK_HP_300KHZ); INIT_DELAYED_WORK(&rt5682->jack_detect_work, rt5682_jack_detect_handler); diff --git a/sound/soc/codecs/rt5682.h b/sound/soc/codecs/rt5682.h index 8068140ebe3f..d82a8301fd74 100644 --- a/sound/soc/codecs/rt5682.h +++ b/sound/soc/codecs/rt5682.h @@ -1214,6 +1214,20 @@ #define RT5682_JDH_NO_PLUG (0x1 << 4) #define RT5682_JDH_PLUG (0x0 << 4) +/* Bias current control 8 (0x0111) */ +#define RT5682_HPA_CP_BIAS_CTRL_MASK (0x3 << 2) +#define RT5682_HPA_CP_BIAS_2UA (0x0 << 2) +#define RT5682_HPA_CP_BIAS_3UA (0x1 << 2) +#define RT5682_HPA_CP_BIAS_4UA (0x2 << 2) +#define RT5682_HPA_CP_BIAS_6UA (0x3 << 2) + +/* Charge Pump Internal Register1 (0x0125) */ +#define RT5682_CP_CLK_HP_MASK (0x3 << 4) +#define RT5682_CP_CLK_HP_100KHZ (0x0 << 4) +#define RT5682_CP_CLK_HP_200KHZ (0x1 << 4) +#define RT5682_CP_CLK_HP_300KHZ (0x2 << 4) +#define RT5682_CP_CLK_HP_600KHZ (0x3 << 4) + /* Chopper and Clock control for DAC (0x013a)*/ #define RT5682_CKXEN_DAC1_MASK (0x1 << 13) #define RT5682_CKXEN_DAC1_SFT 13 From 3f24f37adbc9a1059420a9c8f857e3490a4bce5e Mon Sep 17 00:00:00 2001 From: Shuming Fan Date: Tue, 18 Sep 2018 19:51:24 +0800 Subject: [PATCH 146/299] ASoC: rt5682: Remove HP volume control This patch removed Headphone Playback Volume control. Due to codec settings, we don't want the user to change HP analog gain. The user could use DAC1 Playback Volume control to change playback volume. Signed-off-by: Shuming Fan Signed-off-by: Mark Brown --- sound/soc/codecs/rt5682.c | 5 ----- 1 file changed, 5 deletions(-) diff --git a/sound/soc/codecs/rt5682.c b/sound/soc/codecs/rt5682.c index afe7d5b19313..fad0bed82d79 100644 --- a/sound/soc/codecs/rt5682.c +++ b/sound/soc/codecs/rt5682.c @@ -749,7 +749,6 @@ static bool rt5682_readable_register(struct device *dev, unsigned int reg) } } -static const DECLARE_TLV_DB_SCALE(hp_vol_tlv, -2250, 150, 0); static const DECLARE_TLV_DB_SCALE(dac_vol_tlv, -6525, 75, 0); static const DECLARE_TLV_DB_SCALE(adc_vol_tlv, -1725, 75, 0); static const DECLARE_TLV_DB_SCALE(adc_bst_tlv, 0, 1200, 0); @@ -1108,10 +1107,6 @@ static void rt5682_jack_detect_handler(struct work_struct *work) } static const struct snd_kcontrol_new rt5682_snd_controls[] = { - /* Headphone Output Volume */ - SOC_DOUBLE_R_TLV("Headphone Playback Volume", RT5682_HPL_GAIN, - RT5682_HPR_GAIN, RT5682_G_HP_SFT, 15, 1, hp_vol_tlv), - /* DAC Digital Volume */ SOC_DOUBLE_TLV("DAC1 Playback Volume", RT5682_DAC1_DIG_VOL, RT5682_L_VOL_SFT + 1, RT5682_R_VOL_SFT + 1, 86, 0, dac_vol_tlv), From afd603e4ded0fad9e3102d514020af8494da1604 Mon Sep 17 00:00:00 2001 From: Shuming Fan Date: Tue, 18 Sep 2018 19:50:38 +0800 Subject: [PATCH 147/299] ASoC: rt5682: Update calibration function The ADC/DAC path should open while calibration process. Signed-off-by: Shuming Fan Signed-off-by: Mark Brown --- sound/soc/codecs/rt5682.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/sound/soc/codecs/rt5682.c b/sound/soc/codecs/rt5682.c index 7213b1cfb18a..2725eb72fb1b 100644 --- a/sound/soc/codecs/rt5682.c +++ b/sound/soc/codecs/rt5682.c @@ -2468,17 +2468,22 @@ static void rt5682_calibrate(struct rt5682_priv *rt5682) mutex_lock(&rt5682->calibrate_mutex); rt5682_reset(rt5682->regmap); - regmap_write(rt5682->regmap, RT5682_PWR_ANLG_1, 0xa2bf); + regmap_write(rt5682->regmap, RT5682_PWR_ANLG_1, 0xa2af); usleep_range(15000, 20000); - regmap_write(rt5682->regmap, RT5682_PWR_ANLG_1, 0xf2bf); + regmap_write(rt5682->regmap, RT5682_PWR_ANLG_1, 0xf2af); regmap_write(rt5682->regmap, RT5682_MICBIAS_2, 0x0300); regmap_write(rt5682->regmap, RT5682_GLB_CLK, 0x8000); regmap_write(rt5682->regmap, RT5682_PWR_DIG_1, 0x0100); + regmap_write(rt5682->regmap, RT5682_HP_IMP_SENS_CTRL_19, 0x3800); regmap_write(rt5682->regmap, RT5682_CHOP_DAC, 0x3000); + regmap_write(rt5682->regmap, RT5682_CALIB_ADC_CTRL, 0x7005); + regmap_write(rt5682->regmap, RT5682_STO1_ADC_MIXER, 0x686c); + regmap_write(rt5682->regmap, RT5682_CAL_REC, 0x0d0d); regmap_write(rt5682->regmap, RT5682_HP_CALIB_CTRL_2, 0x0321); regmap_write(rt5682->regmap, RT5682_HP_LOGIC_CTRL_2, 0x0004); regmap_write(rt5682->regmap, RT5682_HP_CALIB_CTRL_1, 0x7c00); regmap_write(rt5682->regmap, RT5682_HP_CALIB_CTRL_3, 0x06a1); + regmap_write(rt5682->regmap, RT5682_A_DAC1_MUX, 0x0311); regmap_write(rt5682->regmap, RT5682_HP_CALIB_CTRL_1, 0x7c00); regmap_write(rt5682->regmap, RT5682_HP_CALIB_CTRL_1, 0xfc00); @@ -2495,8 +2500,12 @@ static void rt5682_calibrate(struct rt5682_priv *rt5682) pr_err("HP Calibration Failure\n"); /* restore settings */ + regmap_write(rt5682->regmap, RT5682_PWR_ANLG_1, 0x02af); + regmap_write(rt5682->regmap, RT5682_MICBIAS_2, 0x0080); regmap_write(rt5682->regmap, RT5682_GLB_CLK, 0x0000); regmap_write(rt5682->regmap, RT5682_PWR_DIG_1, 0x0000); + regmap_write(rt5682->regmap, RT5682_CHOP_DAC, 0x2000); + regmap_write(rt5682->regmap, RT5682_CALIB_ADC_CTRL, 0x2005); mutex_unlock(&rt5682->calibrate_mutex); From 28b20dde5e1c943ab899549a655ac4935cffccbb Mon Sep 17 00:00:00 2001 From: Shuming Fan Date: Tue, 18 Sep 2018 19:51:38 +0800 Subject: [PATCH 148/299] ASoC: rt5682: Fix the boost volume at the begining of playback This patch fixed the boost volume at the begining of playback while DAC volume set to lower level. Signed-off-by: Shuming Fan Signed-off-by: Mark Brown --- sound/soc/codecs/rt5682.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/sound/soc/codecs/rt5682.c b/sound/soc/codecs/rt5682.c index 2725eb72fb1b..18099668e960 100644 --- a/sound/soc/codecs/rt5682.c +++ b/sound/soc/codecs/rt5682.c @@ -68,6 +68,7 @@ struct rt5682_priv { static const struct reg_sequence patch_list[] = { {0x01c1, 0x1000}, + {RT5682_DAC_ADC_DIG_VOL1, 0xa020}, }; static const struct reg_default rt5682_reg[] = { @@ -1468,6 +1469,8 @@ static int rt5682_hp_event(struct snd_soc_dapm_widget *w, RT5682_HP_CTRL_2, 0x6000); snd_soc_component_update_bits(component, RT5682_DEPOP_1, 0x60, 0x60); + snd_soc_component_update_bits(component, + RT5682_DAC_ADC_DIG_VOL1, 0x00c0, 0x0080); break; case SND_SOC_DAPM_POST_PMD: @@ -1475,6 +1478,8 @@ static int rt5682_hp_event(struct snd_soc_dapm_widget *w, RT5682_DEPOP_1, 0x60, 0x0); snd_soc_component_write(component, RT5682_HP_CTRL_2, 0x0000); + snd_soc_component_update_bits(component, + RT5682_DAC_ADC_DIG_VOL1, 0x00c0, 0x0000); break; default: From c50535ed6a10fcae1b64ae83c0f6b1eeb5535afc Mon Sep 17 00:00:00 2001 From: Akshu Agrawal Date: Tue, 18 Sep 2018 12:53:13 +0530 Subject: [PATCH 149/299] ASoC: AMD: Fix capture unstable in beginning for some runs alsa_conformance_test -C hw:0,4 -p 1024 --debug would sometime show: TIME_DIFF(s) HW_LEVEL READ RATE 0.000095970 1024 1024 10670001.041992 0.042609555 1024 2048 24032.168372 0.021330364 1024 3072 48006.681930 0.021339559 1024 4096 47985.996337 The issue is that in dma pointer function we can have stale value of the register for current descriptor of channel. The register retains the number of the last descriptor that was transferred. Fix ensures that we report position, 0, till the one period worth of data is transferred. After one period of data, in handler of period completion interrupt we update the config and correct value of descriptor starts reflecting. Signed-off-by: Akshu Agrawal Signed-off-by: Mark Brown --- sound/soc/amd/acp-pcm-dma.c | 22 ++++++++++++++-------- 1 file changed, 14 insertions(+), 8 deletions(-) diff --git a/sound/soc/amd/acp-pcm-dma.c b/sound/soc/amd/acp-pcm-dma.c index 77b265bd0505..3135e9eafd18 100644 --- a/sound/soc/amd/acp-pcm-dma.c +++ b/sound/soc/amd/acp-pcm-dma.c @@ -1036,16 +1036,22 @@ static snd_pcm_uframes_t acp_dma_pointer(struct snd_pcm_substream *substream) if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) { period_bytes = frames_to_bytes(runtime, runtime->period_size); - dscr = acp_reg_read(rtd->acp_mmio, rtd->dma_curr_dscr); - if (dscr == rtd->dma_dscr_idx_1) - pos = period_bytes; - else - pos = 0; bytescount = acp_get_byte_count(rtd); - if (bytescount > rtd->bytescount) + if (bytescount >= rtd->bytescount) bytescount -= rtd->bytescount; - delay = do_div(bytescount, period_bytes); - runtime->delay = bytes_to_frames(runtime, delay); + if (bytescount < period_bytes) { + pos = 0; + } else { + dscr = acp_reg_read(rtd->acp_mmio, rtd->dma_curr_dscr); + if (dscr == rtd->dma_dscr_idx_1) + pos = period_bytes; + else + pos = 0; + } + if (bytescount > 0) { + delay = do_div(bytescount, period_bytes); + runtime->delay = bytes_to_frames(runtime, delay); + } } else { buffersize = frames_to_bytes(runtime, runtime->buffer_size); bytescount = acp_get_byte_count(rtd); From 37efe23dcca3c59cee662f1c28835020bef31cc0 Mon Sep 17 00:00:00 2001 From: Shuming Fan Date: Tue, 18 Sep 2018 19:51:53 +0800 Subject: [PATCH 150/299] ASoC: rt5682: Minor code modification Minor code changes are: - improve the readability in patch list - add i2c remove function - regmap_register_patch changes to regmap_multi_reg_write Signed-off-by: Shuming Fan Signed-off-by: Mark Brown --- sound/soc/codecs/rt5682.c | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/sound/soc/codecs/rt5682.c b/sound/soc/codecs/rt5682.c index 18099668e960..340f90497d07 100644 --- a/sound/soc/codecs/rt5682.c +++ b/sound/soc/codecs/rt5682.c @@ -67,7 +67,7 @@ struct rt5682_priv { }; static const struct reg_sequence patch_list[] = { - {0x01c1, 0x1000}, + {RT5682_HP_IMP_SENS_CTRL_19, 0x1000}, {RT5682_DAC_ADC_DIG_VOL1, 0xa020}, }; @@ -2584,7 +2584,7 @@ static int rt5682_i2c_probe(struct i2c_client *i2c, rt5682_calibrate(rt5682); - ret = regmap_register_patch(rt5682->regmap, patch_list, + ret = regmap_multi_reg_write(rt5682->regmap, patch_list, ARRAY_SIZE(patch_list)); if (ret != 0) dev_warn(&i2c->dev, "Failed to apply regmap patch: %d\n", ret); @@ -2659,11 +2659,17 @@ static int rt5682_i2c_probe(struct i2c_client *i2c, } - return devm_snd_soc_register_component(&i2c->dev, - &soc_component_dev_rt5682, + return snd_soc_register_component(&i2c->dev, &soc_component_dev_rt5682, rt5682_dai, ARRAY_SIZE(rt5682_dai)); } +static int rt5682_i2c_remove(struct i2c_client *i2c) +{ + snd_soc_unregister_component(&i2c->dev); + + return 0; +} + static void rt5682_i2c_shutdown(struct i2c_client *client) { struct rt5682_priv *rt5682 = i2c_get_clientdata(client); @@ -2694,6 +2700,7 @@ static struct i2c_driver rt5682_i2c_driver = { .acpi_match_table = ACPI_PTR(rt5682_acpi_match), }, .probe = rt5682_i2c_probe, + .remove = rt5682_i2c_remove, .shutdown = rt5682_i2c_shutdown, .id_table = rt5682_i2c_id, }; From 65ba4dd5200a537eae0f6b29e120f3971eac5a4d Mon Sep 17 00:00:00 2001 From: Linus Walleij Date: Tue, 18 Sep 2018 12:11:57 -0700 Subject: [PATCH 151/299] ASoC: rt5677-spi: Drop unused GPIO include This SPI driver does not use the legacy GPIO header so just delete it. Signed-off-by: Linus Walleij Signed-off-by: Mark Brown --- sound/soc/codecs/rt5677-spi.c | 1 - 1 file changed, 1 deletion(-) diff --git a/sound/soc/codecs/rt5677-spi.c b/sound/soc/codecs/rt5677-spi.c index bd51f3655ee3..84501c2020c7 100644 --- a/sound/soc/codecs/rt5677-spi.c +++ b/sound/soc/codecs/rt5677-spi.c @@ -18,7 +18,6 @@ #include #include #include -#include #include #include #include From 3a6818c771671c34b090244c92ab5aea6176d6da Mon Sep 17 00:00:00 2001 From: Rohit kumar Date: Wed, 19 Sep 2018 11:41:21 +0530 Subject: [PATCH 152/299] ASoC: q6afe: dt-bindings: Update input range for qcom,sd-lines Input to qcom,sd-lines should be between 0 and 3 instead of 1 to 4 as 0 corresponds to BIT(0) which is MI2S_SD0 line. Bit 1 to 3 corresponds to SD1 to SD3 lines respectively. Updated documentation for the same. Signed-off-by: Rohit kumar Signed-off-by: Mark Brown --- .../devicetree/bindings/sound/qcom,q6afe.txt | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/Documentation/devicetree/bindings/sound/qcom,q6afe.txt b/Documentation/devicetree/bindings/sound/qcom,q6afe.txt index a8179409c194..d74888b9f1bb 100644 --- a/Documentation/devicetree/bindings/sound/qcom,q6afe.txt +++ b/Documentation/devicetree/bindings/sound/qcom,q6afe.txt @@ -49,7 +49,7 @@ configuration of each dai. Must contain the following properties. Usage: required for mi2s interface Value type: Definition: Must be list of serial data lines used by this dai. - should be one or more of the 1-4 sd lines. + should be one or more of the 0-3 sd lines. - qcom,tdm-sync-mode: Usage: required for tdm interface @@ -137,42 +137,42 @@ q6afe@4 { prim-mi2s-rx@16 { reg = <16>; - qcom,sd-lines = <1 3>; + qcom,sd-lines = <0 2>; }; prim-mi2s-tx@17 { reg = <17>; - qcom,sd-lines = <2>; + qcom,sd-lines = <1>; }; sec-mi2s-rx@18 { reg = <18>; - qcom,sd-lines = <1 4>; + qcom,sd-lines = <0 3>; }; sec-mi2s-tx@19 { reg = <19>; - qcom,sd-lines = <2>; + qcom,sd-lines = <1>; }; tert-mi2s-rx@20 { reg = <20>; - qcom,sd-lines = <2 4>; + qcom,sd-lines = <1 3>; }; tert-mi2s-tx@21 { reg = <21>; - qcom,sd-lines = <1>; + qcom,sd-lines = <0>; }; quat-mi2s-rx@22 { reg = <22>; - qcom,sd-lines = <1>; + qcom,sd-lines = <0>; }; quat-mi2s-tx@23 { reg = <23>; - qcom,sd-lines = <2>; + qcom,sd-lines = <1>; }; }; }; From e53134fefd20c863a873ba77cf2a78fa00c18eec Mon Sep 17 00:00:00 2001 From: Nick Simonov Date: Thu, 20 Sep 2018 00:47:10 +0300 Subject: [PATCH 153/299] ALSA: xen-front: Refine indentations and constify snd_pcm_ops snd_pcm_ops are not supposed to change. So mark the non-const structs as const. Also, refine indentation to ncrease readability. Signed-off-by: Nick Simonov Reviewed-by: Oleksandr Andrushchenko Signed-off-by: Takashi Iwai --- sound/xen/xen_snd_front_alsa.c | 46 +++++++++++++++++----------------- 1 file changed, 23 insertions(+), 23 deletions(-) diff --git a/sound/xen/xen_snd_front_alsa.c b/sound/xen/xen_snd_front_alsa.c index 129180e17db1..2cbd9679aca1 100644 --- a/sound/xen/xen_snd_front_alsa.c +++ b/sound/xen/xen_snd_front_alsa.c @@ -637,31 +637,31 @@ static int alsa_pb_fill_silence(struct snd_pcm_substream *substream, * to know when the buffer can be transferred to the backend. */ -static struct snd_pcm_ops snd_drv_alsa_playback_ops = { - .open = alsa_open, - .close = alsa_close, - .ioctl = snd_pcm_lib_ioctl, - .hw_params = alsa_hw_params, - .hw_free = alsa_hw_free, - .prepare = alsa_prepare, - .trigger = alsa_trigger, - .pointer = alsa_pointer, - .copy_user = alsa_pb_copy_user, - .copy_kernel = alsa_pb_copy_kernel, - .fill_silence = alsa_pb_fill_silence, +static const struct snd_pcm_ops snd_drv_alsa_playback_ops = { + .open = alsa_open, + .close = alsa_close, + .ioctl = snd_pcm_lib_ioctl, + .hw_params = alsa_hw_params, + .hw_free = alsa_hw_free, + .prepare = alsa_prepare, + .trigger = alsa_trigger, + .pointer = alsa_pointer, + .copy_user = alsa_pb_copy_user, + .copy_kernel = alsa_pb_copy_kernel, + .fill_silence = alsa_pb_fill_silence, }; -static struct snd_pcm_ops snd_drv_alsa_capture_ops = { - .open = alsa_open, - .close = alsa_close, - .ioctl = snd_pcm_lib_ioctl, - .hw_params = alsa_hw_params, - .hw_free = alsa_hw_free, - .prepare = alsa_prepare, - .trigger = alsa_trigger, - .pointer = alsa_pointer, - .copy_user = alsa_cap_copy_user, - .copy_kernel = alsa_cap_copy_kernel, +static const struct snd_pcm_ops snd_drv_alsa_capture_ops = { + .open = alsa_open, + .close = alsa_close, + .ioctl = snd_pcm_lib_ioctl, + .hw_params = alsa_hw_params, + .hw_free = alsa_hw_free, + .prepare = alsa_prepare, + .trigger = alsa_trigger, + .pointer = alsa_pointer, + .copy_user = alsa_cap_copy_user, + .copy_kernel = alsa_cap_copy_kernel, }; static int new_pcm_instance(struct xen_snd_front_card_info *card_info, From bf85a91c2f96cf022ada65921d2805fa87f15b8f Mon Sep 17 00:00:00 2001 From: Connor McAdams Date: Tue, 18 Sep 2018 14:33:29 -0400 Subject: [PATCH 154/299] ALSA: hda/ca0132 - Define new verbs and control params This patch defines some new verbs found from reverse engineering of the onboard 8051 CPU, and a control param found there as well. This clears up usage of these verbs in other parts of the driver, and removes their usage where they're now known to be unnecessary. Signed-off-by: Connor McAdams Signed-off-by: Takashi Iwai --- sound/pci/hda/patch_ca0132.c | 23 ++++++++++++----------- 1 file changed, 12 insertions(+), 11 deletions(-) diff --git a/sound/pci/hda/patch_ca0132.c b/sound/pci/hda/patch_ca0132.c index a585d0ec6d77..b5bddb05c064 100644 --- a/sound/pci/hda/patch_ca0132.c +++ b/sound/pci/hda/patch_ca0132.c @@ -685,6 +685,9 @@ enum hda_cmd_vendor_io { VENDOR_CHIPIO_DATA_LOW = 0x300, VENDOR_CHIPIO_DATA_HIGH = 0x400, + VENDOR_CHIPIO_8051_WRITE_DIRECT = 0x500, + VENDOR_CHIPIO_8051_READ_DIRECT = 0xD00, + VENDOR_CHIPIO_GET_PARAMETER = 0xF00, VENDOR_CHIPIO_STATUS = 0xF01, VENDOR_CHIPIO_HIC_POST_READ = 0x702, @@ -692,6 +695,9 @@ enum hda_cmd_vendor_io { VENDOR_CHIPIO_8051_DATA_WRITE = 0x707, VENDOR_CHIPIO_8051_DATA_READ = 0xF07, + VENDOR_CHIPIO_8051_PMEM_READ = 0xF08, + VENDOR_CHIPIO_8051_IRAM_WRITE = 0x709, + VENDOR_CHIPIO_8051_IRAM_READ = 0xF09, VENDOR_CHIPIO_CT_EXTENSIONS_ENABLE = 0x70A, VENDOR_CHIPIO_CT_EXTENSIONS_GET = 0xF0A, @@ -798,6 +804,12 @@ enum control_param_id { * impedance is selected*/ CONTROL_PARAM_PORTD_160OHM_GAIN = 10, + /* + * This control param name was found in the 8051 memory, and makes + * sense given the fact the AE-5 uses it and has the ASI flag set. + */ + CONTROL_PARAM_ASI = 23, + /* Stream Control */ /* Select stream with the given ID */ @@ -7140,11 +7152,6 @@ static void sbz_pre_dsp_setup(struct hda_codec *codec) writel(0x00820680, spec->mem_base + 0x01C); writel(0x00820680, spec->mem_base + 0x01C); - snd_hda_codec_write(codec, 0x15, 0, 0xd00, 0xfc); - snd_hda_codec_write(codec, 0x15, 0, 0xd00, 0xfd); - snd_hda_codec_write(codec, 0x15, 0, 0xd00, 0xfe); - snd_hda_codec_write(codec, 0x15, 0, 0xd00, 0xff); - chipio_write(codec, 0x18b0a4, 0x000000c2); snd_hda_codec_write(codec, 0x11, 0, @@ -7153,12 +7160,6 @@ static void sbz_pre_dsp_setup(struct hda_codec *codec) static void r3d_pre_dsp_setup(struct hda_codec *codec) { - - snd_hda_codec_write(codec, 0x15, 0, 0xd00, 0xfc); - snd_hda_codec_write(codec, 0x15, 0, 0xd00, 0xfd); - snd_hda_codec_write(codec, 0x15, 0, 0xd00, 0xfe); - snd_hda_codec_write(codec, 0x15, 0, 0xd00, 0xff); - chipio_write(codec, 0x18b0a4, 0x000000c2); snd_hda_codec_write(codec, WIDGET_CHIP_CTRL, 0, From f62764638ae8b8c05b544b287c5a8466d9dd72b7 Mon Sep 17 00:00:00 2001 From: Connor McAdams Date: Tue, 18 Sep 2018 14:33:30 -0400 Subject: [PATCH 155/299] ALSA: hda/ca0132 - Add quirk for Sound BlasterX AE-5 This patch adds the PCI subsys ID quirk for the Sound BlasterX AE-5. Signed-off-by: Connor McAdams Signed-off-by: Takashi Iwai --- sound/pci/hda/patch_ca0132.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/sound/pci/hda/patch_ca0132.c b/sound/pci/hda/patch_ca0132.c index b5bddb05c064..c9a15b982335 100644 --- a/sound/pci/hda/patch_ca0132.c +++ b/sound/pci/hda/patch_ca0132.c @@ -1009,6 +1009,7 @@ enum { QUIRK_SBZ, QUIRK_R3DI, QUIRK_R3D, + QUIRK_AE5, }; static const struct hda_pintbl alienware_pincfgs[] = { @@ -1081,6 +1082,7 @@ static const struct snd_pci_quirk ca0132_quirks[] = { SND_PCI_QUIRK(0x1458, 0xA026, "Gigabyte G1.Sniper Z97", QUIRK_R3DI), SND_PCI_QUIRK(0x1458, 0xA036, "Gigabyte GA-Z170X-Gaming 7", QUIRK_R3DI), SND_PCI_QUIRK(0x1102, 0x0013, "Recon3D", QUIRK_R3D), + SND_PCI_QUIRK(0x1102, 0x0051, "Sound Blaster AE-5", QUIRK_AE5), {} }; From d06feaf02fe659ed579dfb10580683ecb6264ca0 Mon Sep 17 00:00:00 2001 From: Connor McAdams Date: Tue, 18 Sep 2018 14:33:31 -0400 Subject: [PATCH 156/299] ALSA: hda/ca0132 - Add pincfg for AE-5 This patch adds the pincfg for the Sound BlasterX AE-5, and cleans up the function it's assigned in. Signed-off-by: Connor McAdams Signed-off-by: Takashi Iwai --- sound/pci/hda/patch_ca0132.c | 73 +++++++++++++++++++++++++++++------- 1 file changed, 60 insertions(+), 13 deletions(-) diff --git a/sound/pci/hda/patch_ca0132.c b/sound/pci/hda/patch_ca0132.c index c9a15b982335..fe1829b4e2d3 100644 --- a/sound/pci/hda/patch_ca0132.c +++ b/sound/pci/hda/patch_ca0132.c @@ -1056,6 +1056,21 @@ static const struct hda_pintbl r3d_pincfgs[] = { {} }; +/* Sound Blaster AE-5 pin configs taken from Windows Driver */ +static const struct hda_pintbl ae5_pincfgs[] = { + { 0x0b, 0x01017010 }, /* Port G -- Lineout FRONT L/R */ + { 0x0c, 0x014510f0 }, /* SPDIF Out 1 */ + { 0x0d, 0x014510f0 }, /* Digital Out */ + { 0x0e, 0x01c510f0 }, /* SPDIF In */ + { 0x0f, 0x01017114 }, /* Port A -- Rear L/R. */ + { 0x10, 0x01017012 }, /* Port D -- Center/LFE or FP Hp */ + { 0x11, 0x01a170ff }, /* Port B -- LineMicIn2 / Rear Headphone */ + { 0x12, 0x01a170f0 }, /* Port C -- LineIn1 */ + { 0x13, 0x908700f0 }, /* What U Hear In*/ + { 0x18, 0x50d000f0 }, /* N/A */ + {} +}; + /* Recon3D integrated pin configs taken from Windows Driver */ static const struct hda_pintbl r3di_pincfgs[] = { { 0x0b, 0x01014110 }, /* Port G -- Lineout FRONT L/R */ @@ -7435,9 +7450,29 @@ static void ca0132_config(struct hda_codec *codec) switch (spec->quirk) { case QUIRK_ALIENWARE: - codec_dbg(codec, "ca0132_config: QUIRK_ALIENWARE applied.\n"); + codec_dbg(codec, "%s: QUIRK_ALIENWARE applied.\n", __func__); snd_hda_apply_pincfgs(codec, alienware_pincfgs); + break; + case QUIRK_SBZ: + codec_dbg(codec, "%s: QUIRK_SBZ applied.\n", __func__); + snd_hda_apply_pincfgs(codec, sbz_pincfgs); + break; + case QUIRK_R3D: + codec_dbg(codec, "%s: QUIRK_R3D applied.\n", __func__); + snd_hda_apply_pincfgs(codec, r3d_pincfgs); + break; + case QUIRK_R3DI: + codec_dbg(codec, "%s: QUIRK_R3DI applied.\n", __func__); + snd_hda_apply_pincfgs(codec, r3di_pincfgs); + break; + case QUIRK_AE5: + codec_dbg(codec, "%s: QUIRK_AE5 applied.\n", __func__); + snd_hda_apply_pincfgs(codec, r3di_pincfgs); + break; + } + switch (spec->quirk) { + case QUIRK_ALIENWARE: spec->num_outputs = 2; spec->out_pins[0] = 0x0b; /* speaker out */ spec->out_pins[1] = 0x0f; @@ -7457,15 +7492,6 @@ static void ca0132_config(struct hda_codec *codec) break; case QUIRK_SBZ: case QUIRK_R3D: - if (spec->quirk == QUIRK_SBZ) { - codec_dbg(codec, "%s: QUIRK_SBZ applied.\n", __func__); - snd_hda_apply_pincfgs(codec, sbz_pincfgs); - } - if (spec->quirk == QUIRK_R3D) { - codec_dbg(codec, "%s: QUIRK_R3D applied.\n", __func__); - snd_hda_apply_pincfgs(codec, r3d_pincfgs); - } - spec->num_outputs = 2; spec->out_pins[0] = 0x0B; /* Line out */ spec->out_pins[1] = 0x0F; /* Rear headphone out */ @@ -7490,10 +7516,31 @@ static void ca0132_config(struct hda_codec *codec) spec->multiout.dig_out_nid = spec->dig_out; spec->dig_in = 0x09; break; - case QUIRK_R3DI: - codec_dbg(codec, "%s: QUIRK_R3DI applied.\n", __func__); - snd_hda_apply_pincfgs(codec, r3di_pincfgs); + case QUIRK_AE5: + spec->num_outputs = 2; + spec->out_pins[0] = 0x0B; /* Line out */ + spec->out_pins[1] = 0x11; /* Rear headphone out */ + spec->out_pins[2] = 0x10; /* Front Headphone / Center/LFE*/ + spec->out_pins[3] = 0x0F; /* Rear surround */ + spec->shared_out_nid = 0x2; + spec->unsol_tag_hp = spec->out_pins[1]; + spec->unsol_tag_front_hp = spec->out_pins[2]; + spec->adcs[0] = 0x7; /* Rear Mic / Line-in */ + spec->adcs[1] = 0x8; /* Front Mic, but only if no DSP */ + spec->adcs[2] = 0xa; /* what u hear */ + + spec->num_inputs = 2; + spec->input_pins[0] = 0x12; /* Rear Mic / Line-in */ + spec->input_pins[1] = 0x13; /* What U Hear */ + spec->shared_mic_nid = 0x7; + spec->unsol_tag_amic1 = spec->input_pins[0]; + + /* SPDIF I/O */ + spec->dig_out = 0x05; + spec->multiout.dig_out_nid = spec->dig_out; + break; + case QUIRK_R3DI: spec->num_outputs = 2; spec->out_pins[0] = 0x0B; /* Line out */ spec->out_pins[1] = 0x0F; /* Rear headphone out */ From 88268ce8a64e707bd67d7025f5947f46cabbb98d Mon Sep 17 00:00:00 2001 From: Connor McAdams Date: Tue, 18 Sep 2018 14:33:32 -0400 Subject: [PATCH 157/299] ALSA: hda/ca0132 - Set AE-5 bools and select mixer This patch sets the bool values for the AE-5, as well as selects the mixer it will use. Signed-off-by: Connor McAdams Signed-off-by: Takashi Iwai --- sound/pci/hda/patch_ca0132.c | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/sound/pci/hda/patch_ca0132.c b/sound/pci/hda/patch_ca0132.c index fe1829b4e2d3..9caa2678866b 100644 --- a/sound/pci/hda/patch_ca0132.c +++ b/sound/pci/hda/patch_ca0132.c @@ -7597,7 +7597,11 @@ static int ca0132_prepare_verbs(struct hda_codec *codec) struct ca0132_spec *spec = codec->spec; spec->chip_init_verbs = ca0132_init_verbs0; - if (spec->quirk == QUIRK_SBZ || spec->quirk == QUIRK_R3D) + /* + * Since desktop cards use pci_mmio, this can be used to determine + * whether or not to use these verbs instead of a separate bool. + */ + if (spec->use_pci_mmio) spec->desktop_init_verbs = ca0132_init_verbs1; spec->spec_init_verbs = kcalloc(NUM_SPEC_VERBS, sizeof(struct hda_verb), @@ -7671,6 +7675,10 @@ static int patch_ca0132(struct hda_codec *codec) spec->mixers[0] = r3di_mixer; snd_hda_codec_set_name(codec, "Recon3Di"); break; + case QUIRK_AE5: + spec->mixers[0] = desktop_mixer; + snd_hda_codec_set_name(codec, "Sound BlasterX AE-5"); + break; default: spec->mixers[0] = ca0132_mixer; break; @@ -7680,6 +7688,7 @@ static int patch_ca0132(struct hda_codec *codec) switch (spec->quirk) { case QUIRK_SBZ: case QUIRK_R3D: + case QUIRK_AE5: spec->use_alt_controls = true; spec->use_alt_functions = true; spec->use_pci_mmio = true; From ce7154480cf9e3141476ffc138ff02bb4243ec8a Mon Sep 17 00:00:00 2001 From: Connor McAdams Date: Tue, 18 Sep 2018 14:33:33 -0400 Subject: [PATCH 158/299] ALSA: hda/ca0132 - Change ca0132_mmio_init for AE-5 This patch adds the unique writes for the AE-5 on startup to ca0132_mmio_init. The other cards share some addresses written to, but use different values. Signed-off-by: Connor McAdams Signed-off-by: Takashi Iwai --- sound/pci/hda/patch_ca0132.c | 61 ++++++++++++++++++++++++++++++++---- 1 file changed, 55 insertions(+), 6 deletions(-) diff --git a/sound/pci/hda/patch_ca0132.c b/sound/pci/hda/patch_ca0132.c index 9caa2678866b..7dfa6bf4cd4a 100644 --- a/sound/pci/hda/patch_ca0132.c +++ b/sound/pci/hda/patch_ca0132.c @@ -7223,23 +7223,72 @@ static void ca0132_mmio_init(struct hda_codec *codec) { struct ca0132_spec *spec = codec->spec; - writel(0x00000000, spec->mem_base + 0x400); - writel(0x00000000, spec->mem_base + 0x408); - writel(0x00000000, spec->mem_base + 0x40C); + if (spec->quirk == QUIRK_AE5) + writel(0x00000001, spec->mem_base + 0x400); + else + writel(0x00000000, spec->mem_base + 0x400); + + if (spec->quirk == QUIRK_AE5) + writel(0x00000001, spec->mem_base + 0x408); + else + writel(0x00000000, spec->mem_base + 0x408); + + if (spec->quirk == QUIRK_AE5) + writel(0x00000001, spec->mem_base + 0x40c); + else + writel(0x00000000, spec->mem_base + 0x40C); + writel(0x00880680, spec->mem_base + 0x01C); - writel(0x00000083, spec->mem_base + 0xC0C); + + if (spec->quirk == QUIRK_AE5) + writel(0x00000080, spec->mem_base + 0xC0C); + else + writel(0x00000083, spec->mem_base + 0xC0C); + writel(0x00000030, spec->mem_base + 0xC00); writel(0x00000000, spec->mem_base + 0xC04); + + if (spec->quirk == QUIRK_AE5) + writel(0x00000000, spec->mem_base + 0xC0C); + else + writel(0x00000003, spec->mem_base + 0xC0C); + writel(0x00000003, spec->mem_base + 0xC0C); writel(0x00000003, spec->mem_base + 0xC0C); writel(0x00000003, spec->mem_base + 0xC0C); - writel(0x00000003, spec->mem_base + 0xC0C); - writel(0x000000C1, spec->mem_base + 0xC08); + + if (spec->quirk == QUIRK_AE5) + writel(0x00000001, spec->mem_base + 0xC08); + else + writel(0x000000C1, spec->mem_base + 0xC08); + writel(0x000000F1, spec->mem_base + 0xC08); writel(0x00000001, spec->mem_base + 0xC08); writel(0x000000C7, spec->mem_base + 0xC08); writel(0x000000C1, spec->mem_base + 0xC08); writel(0x00000080, spec->mem_base + 0xC04); + + if (spec->quirk == QUIRK_AE5) { + writel(0x00000000, spec->mem_base + 0x42c); + writel(0x00000000, spec->mem_base + 0x46c); + writel(0x00000000, spec->mem_base + 0x4ac); + writel(0x00000000, spec->mem_base + 0x4ec); + writel(0x00000000, spec->mem_base + 0x43c); + writel(0x00000000, spec->mem_base + 0x47c); + writel(0x00000000, spec->mem_base + 0x4bc); + writel(0x00000000, spec->mem_base + 0x4fc); + writel(0x00000600, spec->mem_base + 0x100); + writel(0x00000014, spec->mem_base + 0x410); + writel(0x0000060f, spec->mem_base + 0x100); + writel(0x0000070f, spec->mem_base + 0x100); + writel(0x00000aff, spec->mem_base + 0x830); + writel(0x00000000, spec->mem_base + 0x86c); + writel(0x0000006b, spec->mem_base + 0x800); + writel(0x00000001, spec->mem_base + 0x86c); + writel(0x0000006b, spec->mem_base + 0x800); + writel(0x00000057, spec->mem_base + 0x804); + writel(0x00800000, spec->mem_base + 0x20c); + } } /* From b9b413450cd60681eef257e78061dd0671e5b151 Mon Sep 17 00:00:00 2001 From: Connor McAdams Date: Tue, 18 Sep 2018 14:33:34 -0400 Subject: [PATCH 159/299] ALSA: hda/ca0132 - Add AE-5 pre-init and ca0113 functions This patch adds AE-5 pre-init functions that happen before the main ca0132_alt_init, and gives functions related to the ca0113 a ca0113 prefix instead of ca0132. It also adds functions to write to the 8051's SFRs, and to write the special ca0113 commands for the AE-5. Signed-off-by: Connor McAdams Signed-off-by: Takashi Iwai --- sound/pci/hda/patch_ca0132.c | 157 ++++++++++++++++++++++++++++++----- 1 file changed, 134 insertions(+), 23 deletions(-) diff --git a/sound/pci/hda/patch_ca0132.c b/sound/pci/hda/patch_ca0132.c index 7dfa6bf4cd4a..89d8ace9afd4 100644 --- a/sound/pci/hda/patch_ca0132.c +++ b/sound/pci/hda/patch_ca0132.c @@ -1482,6 +1482,20 @@ static void chipio_set_conn_rate(struct hda_codec *codec, rate); } +/* + * Writes to the 8051's internal address space directly instead of indirectly, + * giving access to the special function registers located at addresses + * 0x80-0xFF. + */ +static void chipio_8051_write_direct(struct hda_codec *codec, + unsigned int addr, unsigned int data) +{ + unsigned int verb; + + verb = VENDOR_CHIPIO_8051_WRITE_DIRECT | data; + snd_hda_codec_write(codec, WIDGET_CHIP_CTRL, 0, verb, addr); +} + /* * Enable clocks. */ @@ -3117,7 +3131,9 @@ static bool dspload_wait_loaded(struct hda_codec *codec) } /* - * Setup GPIO for the other variants of Core3D. + * ca0113 related functions. The ca0113 acts as the HDA bus for the pci-e + * based cards, and has a second mmio region, region2, that's used for special + * commands. */ /* @@ -3125,8 +3141,11 @@ static bool dspload_wait_loaded(struct hda_codec *codec) * the mmio address 0x320 is used to set GPIO pins. The format for the data * The first eight bits are just the number of the pin. So far, I've only seen * this number go to 7. + * AE-5 note: The AE-5 seems to use pins 2 and 3 to somehow set the color value + * of the on-card LED. It seems to use pin 2 for data, then toggles 3 to on and + * then off to send that bit. */ -static void ca0132_mmio_gpio_set(struct hda_codec *codec, unsigned int gpio_pin, +static void ca0113_mmio_gpio_set(struct hda_codec *codec, unsigned int gpio_pin, bool enable) { struct ca0132_spec *spec = codec->spec; @@ -3138,6 +3157,54 @@ static void ca0132_mmio_gpio_set(struct hda_codec *codec, unsigned int gpio_pin, writew(gpio_data, spec->mem_base + 0x320); } +/* + * Special pci region2 commands that are only used by the AE-5. They follow + * a set format, and require reads at certain points to seemingly 'clear' + * the response data. My first tests didn't do these reads, and would cause + * the card to get locked up until the memory was read. These commands + * seem to work with three distinct values that I've taken to calling group, + * target-id, and value. + */ +static void ca0113_mmio_command_set(struct hda_codec *codec, unsigned int group, + unsigned int target, unsigned int value) +{ + struct ca0132_spec *spec = codec->spec; + unsigned int write_val; + + writel(0x0000007e, spec->mem_base + 0x210); + readl(spec->mem_base + 0x210); + writel(0x0000005a, spec->mem_base + 0x210); + readl(spec->mem_base + 0x210); + readl(spec->mem_base + 0x210); + + writel(0x00800005, spec->mem_base + 0x20c); + writel(group, spec->mem_base + 0x804); + + writel(0x00800005, spec->mem_base + 0x20c); + write_val = (target & 0xff); + write_val |= (value << 8); + + + writel(write_val, spec->mem_base + 0x204); + /* + * Need delay here or else it goes too fast and works inconsistently. + */ + msleep(20); + + readl(spec->mem_base + 0x860); + readl(spec->mem_base + 0x854); + readl(spec->mem_base + 0x840); + + writel(0x00800004, spec->mem_base + 0x20c); + writel(0x00000000, spec->mem_base + 0x210); + readl(spec->mem_base + 0x210); + readl(spec->mem_base + 0x210); +} + +/* + * Setup GPIO for the other variants of Core3D. + */ + /* * Sets up the GPIO pins so that they are discoverable. If this isn't done, * the card shows as having no GPIO pins. @@ -4013,9 +4080,9 @@ static int ca0132_alt_select_out(struct hda_codec *codec) /*speaker out config*/ switch (spec->quirk) { case QUIRK_SBZ: - ca0132_mmio_gpio_set(codec, 7, false); - ca0132_mmio_gpio_set(codec, 4, true); - ca0132_mmio_gpio_set(codec, 1, true); + ca0113_mmio_gpio_set(codec, 7, false); + ca0113_mmio_gpio_set(codec, 4, true); + ca0113_mmio_gpio_set(codec, 1, true); chipio_set_control_param(codec, 0x0D, 0x18); break; case QUIRK_R3DI: @@ -4024,7 +4091,7 @@ static int ca0132_alt_select_out(struct hda_codec *codec) break; case QUIRK_R3D: chipio_set_control_param(codec, 0x0D, 0x24); - ca0132_mmio_gpio_set(codec, 1, true); + ca0113_mmio_gpio_set(codec, 1, true); break; } @@ -4053,9 +4120,9 @@ static int ca0132_alt_select_out(struct hda_codec *codec) /* Headphone out config*/ switch (spec->quirk) { case QUIRK_SBZ: - ca0132_mmio_gpio_set(codec, 7, true); - ca0132_mmio_gpio_set(codec, 4, true); - ca0132_mmio_gpio_set(codec, 1, false); + ca0113_mmio_gpio_set(codec, 7, true); + ca0113_mmio_gpio_set(codec, 4, true); + ca0113_mmio_gpio_set(codec, 1, false); chipio_set_control_param(codec, 0x0D, 0x12); break; case QUIRK_R3DI: @@ -4064,7 +4131,7 @@ static int ca0132_alt_select_out(struct hda_codec *codec) break; case QUIRK_R3D: chipio_set_control_param(codec, 0x0D, 0x21); - ca0132_mmio_gpio_set(codec, 0x1, false); + ca0113_mmio_gpio_set(codec, 0x1, false); break; } @@ -4099,9 +4166,9 @@ static int ca0132_alt_select_out(struct hda_codec *codec) /* Surround out config*/ switch (spec->quirk) { case QUIRK_SBZ: - ca0132_mmio_gpio_set(codec, 7, false); - ca0132_mmio_gpio_set(codec, 4, true); - ca0132_mmio_gpio_set(codec, 1, true); + ca0113_mmio_gpio_set(codec, 7, false); + ca0113_mmio_gpio_set(codec, 4, true); + ca0113_mmio_gpio_set(codec, 1, true); chipio_set_control_param(codec, 0x0D, 0x18); break; case QUIRK_R3DI: @@ -4109,7 +4176,7 @@ static int ca0132_alt_select_out(struct hda_codec *codec) r3di_gpio_out_set(codec, R3DI_LINE_OUT); break; case QUIRK_R3D: - ca0132_mmio_gpio_set(codec, 1, true); + ca0113_mmio_gpio_set(codec, 1, true); chipio_set_control_param(codec, 0x0D, 0x24); break; } @@ -4370,7 +4437,7 @@ static int ca0132_alt_select_in(struct hda_codec *codec) switch (spec->quirk) { case QUIRK_SBZ: case QUIRK_R3D: - ca0132_mmio_gpio_set(codec, 0, false); + ca0113_mmio_gpio_set(codec, 0, false); tmp = FLOAT_THREE; break; case QUIRK_R3DI: @@ -4403,7 +4470,7 @@ static int ca0132_alt_select_in(struct hda_codec *codec) switch (spec->quirk) { case QUIRK_SBZ: case QUIRK_R3D: - ca0132_mmio_gpio_set(codec, 0, false); + ca0113_mmio_gpio_set(codec, 0, false); break; case QUIRK_R3DI: r3di_gpio_mic_set(codec, R3DI_REAR_MIC); @@ -4430,8 +4497,8 @@ static int ca0132_alt_select_in(struct hda_codec *codec) switch (spec->quirk) { case QUIRK_SBZ: case QUIRK_R3D: - ca0132_mmio_gpio_set(codec, 0, true); - ca0132_mmio_gpio_set(codec, 5, false); + ca0113_mmio_gpio_set(codec, 0, true); + ca0113_mmio_gpio_set(codec, 5, false); tmp = FLOAT_THREE; break; case QUIRK_R3DI: @@ -6977,11 +7044,11 @@ static void sbz_region2_exit(struct hda_codec *codec) for (i = 0; i < 8; i++) writeb(0xb3, spec->mem_base + 0x304); - ca0132_mmio_gpio_set(codec, 0, false); - ca0132_mmio_gpio_set(codec, 1, false); - ca0132_mmio_gpio_set(codec, 4, true); - ca0132_mmio_gpio_set(codec, 5, false); - ca0132_mmio_gpio_set(codec, 7, false); + ca0113_mmio_gpio_set(codec, 0, false); + ca0113_mmio_gpio_set(codec, 1, false); + ca0113_mmio_gpio_set(codec, 4, true); + ca0113_mmio_gpio_set(codec, 5, false); + ca0113_mmio_gpio_set(codec, 7, false); } static void sbz_set_pin_ctl_default(struct hda_codec *codec) @@ -7291,6 +7358,47 @@ static void ca0132_mmio_init(struct hda_codec *codec) } } +/* + * This function writes to some SFR's, does some region2 writes, and then + * eventually resets the codec with the 0x7ff verb. Not quite sure why it does + * what it does. + */ +static void ae5_register_set(struct hda_codec *codec) +{ + struct ca0132_spec *spec = codec->spec; + + chipio_8051_write_direct(codec, 0x93, 0x10); + snd_hda_codec_write(codec, WIDGET_CHIP_CTRL, 0, + VENDOR_CHIPIO_8051_ADDRESS_LOW, 0x44); + snd_hda_codec_write(codec, WIDGET_CHIP_CTRL, 0, + VENDOR_CHIPIO_PLL_PMU_WRITE, 0xc2); + + writeb(0x0f, spec->mem_base + 0x304); + writeb(0x0f, spec->mem_base + 0x304); + writeb(0x0f, spec->mem_base + 0x304); + writeb(0x0f, spec->mem_base + 0x304); + writeb(0x0e, spec->mem_base + 0x100); + writeb(0x1f, spec->mem_base + 0x304); + writeb(0x0c, spec->mem_base + 0x100); + writeb(0x3f, spec->mem_base + 0x304); + writeb(0x08, spec->mem_base + 0x100); + writeb(0x7f, spec->mem_base + 0x304); + writeb(0x00, spec->mem_base + 0x100); + writeb(0xff, spec->mem_base + 0x304); + + ca0113_mmio_command_set(codec, 0x30, 0x2d, 0x3f); + + chipio_8051_write_direct(codec, 0x90, 0x00); + chipio_8051_write_direct(codec, 0x90, 0x10); + + ca0113_mmio_command_set(codec, 0x48, 0x07, 0x83); + + chipio_write(codec, 0x18b0a4, 0x000000c2); + + snd_hda_codec_write(codec, 0x01, 0, 0x7ff, 0x00); + snd_hda_codec_write(codec, 0x01, 0, 0x7ff, 0x00); +} + /* * Extra init functions for alternative ca0132 codecs. Done * here so they don't clutter up the main ca0132_init function @@ -7365,6 +7473,9 @@ static int ca0132_init(struct hda_codec *codec) snd_hda_power_up_pm(codec); + if (spec->quirk == QUIRK_AE5) + ae5_register_set(codec); + ca0132_init_unsol(codec); ca0132_init_params(codec); ca0132_init_flags(codec); From 03c9b6b1e02e6f798d5f554e8ecdc8a37242fa17 Mon Sep 17 00:00:00 2001 From: Connor McAdams Date: Tue, 18 Sep 2018 14:33:35 -0400 Subject: [PATCH 160/299] ALSA: hda/ca0132 - Add AE-5 regular init setup This patch adds AE-5 specific stuff to the ca0132_alt_init function. Signed-off-by: Connor McAdams Signed-off-by: Takashi Iwai --- sound/pci/hda/patch_ca0132.c | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/sound/pci/hda/patch_ca0132.c b/sound/pci/hda/patch_ca0132.c index 89d8ace9afd4..bd90771827ca 100644 --- a/sound/pci/hda/patch_ca0132.c +++ b/sound/pci/hda/patch_ca0132.c @@ -3215,6 +3215,7 @@ static void ca0132_gpio_init(struct hda_codec *codec) switch (spec->quirk) { case QUIRK_SBZ: + case QUIRK_AE5: snd_hda_codec_write(codec, 0x01, 0, 0x793, 0x00); snd_hda_codec_write(codec, 0x01, 0, 0x794, 0x53); snd_hda_codec_write(codec, 0x01, 0, 0x790, 0x23); @@ -7432,6 +7433,17 @@ static void ca0132_alt_init(struct hda_codec *codec) snd_hda_sequence_write(codec, spec->chip_init_verbs); snd_hda_sequence_write(codec, spec->desktop_init_verbs); break; + case QUIRK_AE5: + ca0132_gpio_init(codec); + snd_hda_codec_write(codec, WIDGET_CHIP_CTRL, 0, + VENDOR_CHIPIO_8051_ADDRESS_LOW, 0x49); + snd_hda_codec_write(codec, WIDGET_CHIP_CTRL, 0, + VENDOR_CHIPIO_PLL_PMU_WRITE, 0x88); + chipio_write(codec, 0x18b030, 0x00000020); + snd_hda_sequence_write(codec, spec->chip_init_verbs); + snd_hda_sequence_write(codec, spec->desktop_init_verbs); + ca0113_mmio_command_set(codec, 0x30, 0x32, 0x3f); + break; } } From 7a928186b377a7ef3392e902378dc2d63bf332f7 Mon Sep 17 00:00:00 2001 From: Connor McAdams Date: Tue, 18 Sep 2018 14:33:36 -0400 Subject: [PATCH 161/299] ALSA: hda/ca0132 - Change firmware name and usage The Recon3D, AE-5, Z and ZxR all share the same firmware file. Rename this from the specific "ctefx-sbz.bin" to "ctefx-desktop.bin" and set the AE-5 and Recon3D to use it as well. Signed-off-by: Connor McAdams Signed-off-by: Takashi Iwai --- sound/pci/hda/patch_ca0132.c | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/sound/pci/hda/patch_ca0132.c b/sound/pci/hda/patch_ca0132.c index bd90771827ca..4453a53acbf3 100644 --- a/sound/pci/hda/patch_ca0132.c +++ b/sound/pci/hda/patch_ca0132.c @@ -81,12 +81,12 @@ #define SCP_GET 1 #define EFX_FILE "ctefx.bin" -#define SBZ_EFX_FILE "ctefx-sbz.bin" +#define DESKTOP_EFX_FILE "ctefx-desktop.bin" #define R3DI_EFX_FILE "ctefx-r3di.bin" #ifdef CONFIG_SND_HDA_CODEC_CA0132_DSP MODULE_FIRMWARE(EFX_FILE); -MODULE_FIRMWARE(SBZ_EFX_FILE); +MODULE_FIRMWARE(DESKTOP_EFX_FILE); MODULE_FIRMWARE(R3DI_EFX_FILE); #endif @@ -6770,12 +6770,14 @@ static bool ca0132_download_dsp_images(struct hda_codec *codec) */ switch (spec->quirk) { case QUIRK_SBZ: - if (request_firmware(&fw_entry, SBZ_EFX_FILE, + case QUIRK_R3D: + case QUIRK_AE5: + if (request_firmware(&fw_entry, DESKTOP_EFX_FILE, codec->card->dev) != 0) { - codec_dbg(codec, "SBZ alt firmware not detected. "); + codec_dbg(codec, "Desktop firmware not found. "); spec->alt_firmware_present = false; } else { - codec_dbg(codec, "Sound Blaster Z firmware selected."); + codec_dbg(codec, "Desktop firmware selected."); spec->alt_firmware_present = true; } break; From 6ef0e91ec433f337877c9112bf0d27a9e1d0fe95 Mon Sep 17 00:00:00 2001 From: Connor McAdams Date: Tue, 18 Sep 2018 14:33:37 -0400 Subject: [PATCH 162/299] ALSA: hda/ca0132 - Merge post-dsp functions + cleanup This patch cleans up some of the formatting of the post-dsp load setup functions, and also merges some of the sub functions into individual ones. Signed-off-by: Connor McAdams Signed-off-by: Takashi Iwai --- sound/pci/hda/patch_ca0132.c | 171 +++++++++++++++-------------------- 1 file changed, 75 insertions(+), 96 deletions(-) diff --git a/sound/pci/hda/patch_ca0132.c b/sound/pci/hda/patch_ca0132.c index 4453a53acbf3..b89616c57c18 100644 --- a/sound/pci/hda/patch_ca0132.c +++ b/sound/pci/hda/patch_ca0132.c @@ -6335,69 +6335,48 @@ static void ca0132_refresh_widget_caps(struct hda_codec *codec) } /* - * Recon3D r3d_setup_defaults sub functions. + * Creates a dummy stream to bind the output to. This seems to have to be done + * after changing the main outputs source and destination streams. */ - -static void r3d_dsp_scp_startup(struct hda_codec *codec) +static void ca0132_alt_create_dummy_stream(struct hda_codec *codec) { - unsigned int tmp; + struct ca0132_spec *spec = codec->spec; + unsigned int stream_format; - tmp = 0x00000000; - dspio_set_uint_param_no_source(codec, 0x80, 0x0A, tmp); + stream_format = snd_hdac_calc_stream_format(48000, 2, + SNDRV_PCM_FORMAT_S32_LE, 32, 0); - tmp = 0x00000001; - dspio_set_uint_param_no_source(codec, 0x80, 0x0B, tmp); + snd_hda_codec_setup_stream(codec, spec->dacs[0], spec->dsp_stream_id, + 0, stream_format); - tmp = 0x00000004; - dspio_set_uint_param_no_source(codec, 0x80, 0x0C, tmp); - - tmp = 0x00000005; - dspio_set_uint_param_no_source(codec, 0x80, 0x0C, tmp); - - tmp = 0x00000000; - dspio_set_uint_param_no_source(codec, 0x80, 0x0C, tmp); - -} - -static void r3d_dsp_initial_mic_setup(struct hda_codec *codec) -{ - unsigned int tmp; - - /* Mic 1 Setup */ - chipio_set_conn_rate(codec, MEM_CONNID_MICIN1, SR_96_000); - chipio_set_conn_rate(codec, MEM_CONNID_MICOUT1, SR_96_000); - /* This ConnPointID is unique to Recon3Di. Haven't seen it elsewhere */ - chipio_set_conn_rate(codec, 0x0F, SR_96_000); - tmp = FLOAT_ONE; - dspio_set_uint_param(codec, 0x80, 0x00, tmp); - - /* Mic 2 Setup, even though it isn't connected on SBZ */ - chipio_set_conn_rate(codec, MEM_CONNID_MICIN2, SR_96_000); - chipio_set_conn_rate(codec, MEM_CONNID_MICOUT2, SR_96_000); - chipio_set_conn_rate(codec, 0x0F, SR_96_000); - tmp = FLOAT_ZERO; - dspio_set_uint_param(codec, 0x80, 0x01, tmp); + snd_hda_codec_cleanup_stream(codec, spec->dacs[0]); } /* - * Initialize Sound Blaster Z analog microphones. + * Initialize mic for non-chromebook ca0132 implementations. */ -static void sbz_init_analog_mics(struct hda_codec *codec) +static void ca0132_alt_init_analog_mics(struct hda_codec *codec) { + struct ca0132_spec *spec = codec->spec; unsigned int tmp; /* Mic 1 Setup */ chipio_set_conn_rate(codec, MEM_CONNID_MICIN1, SR_96_000); chipio_set_conn_rate(codec, MEM_CONNID_MICOUT1, SR_96_000); - tmp = FLOAT_THREE; + if (spec->quirk == QUIRK_R3DI) { + chipio_set_conn_rate(codec, 0x0F, SR_96_000); + tmp = FLOAT_ONE; + } else + tmp = FLOAT_THREE; dspio_set_uint_param(codec, 0x80, 0x00, tmp); - /* Mic 2 Setup, even though it isn't connected on SBZ */ + /* Mic 2 setup (not present on desktop cards) */ chipio_set_conn_rate(codec, MEM_CONNID_MICIN2, SR_96_000); chipio_set_conn_rate(codec, MEM_CONNID_MICOUT2, SR_96_000); + if (spec->quirk == QUIRK_R3DI) + chipio_set_conn_rate(codec, 0x0F, SR_96_000); tmp = FLOAT_ZERO; dspio_set_uint_param(codec, 0x80, 0x01, tmp); - } /* @@ -6430,7 +6409,6 @@ static void sbz_connect_streams(struct hda_codec *codec) codec_dbg(codec, "Connect Streams exited, mutex released.\n"); mutex_unlock(&spec->chipio_mutex); - } /* @@ -6477,35 +6455,49 @@ static void sbz_chipio_startup_data(struct hda_codec *codec) } /* - * Sound Blaster Z uses these after DSP is loaded. Weird SCP commands - * without a 0x20 source like normal. + * Custom DSP SCP commands where the src value is 0x00 instead of 0x20. This is + * done after the DSP is loaded. */ -static void sbz_dsp_scp_startup(struct hda_codec *codec) +static void ca0132_alt_dsp_scp_startup(struct hda_codec *codec) { + struct ca0132_spec *spec = codec->spec; unsigned int tmp; - tmp = 0x00000003; - dspio_set_uint_param_no_source(codec, 0x80, 0x0C, tmp); - - tmp = 0x00000000; - dspio_set_uint_param_no_source(codec, 0x80, 0x0A, tmp); - - tmp = 0x00000001; - dspio_set_uint_param_no_source(codec, 0x80, 0x0B, tmp); - - tmp = 0x00000004; - dspio_set_uint_param_no_source(codec, 0x80, 0x0C, tmp); - - tmp = 0x00000005; - dspio_set_uint_param_no_source(codec, 0x80, 0x0C, tmp); - - tmp = 0x00000000; - dspio_set_uint_param_no_source(codec, 0x80, 0x0C, tmp); - + switch (spec->quirk) { + case QUIRK_SBZ: + case QUIRK_AE5: + tmp = 0x00000003; + dspio_set_uint_param_no_source(codec, 0x80, 0x0C, tmp); + tmp = 0x00000000; + dspio_set_uint_param_no_source(codec, 0x80, 0x0A, tmp); + tmp = 0x00000001; + dspio_set_uint_param_no_source(codec, 0x80, 0x0B, tmp); + tmp = 0x00000004; + dspio_set_uint_param_no_source(codec, 0x80, 0x0C, tmp); + tmp = 0x00000005; + dspio_set_uint_param_no_source(codec, 0x80, 0x0C, tmp); + tmp = 0x00000000; + dspio_set_uint_param_no_source(codec, 0x80, 0x0C, tmp); + break; + case QUIRK_R3D: + case QUIRK_R3DI: + tmp = 0x00000000; + dspio_set_uint_param_no_source(codec, 0x80, 0x0A, tmp); + tmp = 0x00000001; + dspio_set_uint_param_no_source(codec, 0x80, 0x0B, tmp); + tmp = 0x00000004; + dspio_set_uint_param_no_source(codec, 0x80, 0x0C, tmp); + tmp = 0x00000005; + dspio_set_uint_param_no_source(codec, 0x80, 0x0C, tmp); + tmp = 0x00000000; + dspio_set_uint_param_no_source(codec, 0x80, 0x0C, tmp); + break; + } } -static void sbz_dsp_initial_mic_setup(struct hda_codec *codec) +static void ca0132_alt_dsp_initial_mic_setup(struct hda_codec *codec) { + struct ca0132_spec *spec = codec->spec; unsigned int tmp; chipio_set_stream_control(codec, 0x03, 0); @@ -6520,8 +6512,16 @@ static void sbz_dsp_initial_mic_setup(struct hda_codec *codec) chipio_set_stream_control(codec, 0x03, 1); chipio_set_stream_control(codec, 0x04, 1); - chipio_write(codec, 0x18b098, 0x0000000c); - chipio_write(codec, 0x18b09C, 0x0000000c); + switch (spec->quirk) { + case QUIRK_SBZ: + chipio_write(codec, 0x18b098, 0x0000000c); + chipio_write(codec, 0x18b09C, 0x0000000c); + break; + case QUIRK_AE5: + chipio_write(codec, 0x18b098, 0x0000000c); + chipio_write(codec, 0x18b09c, 0x0000004c); + break; + } } /* @@ -6582,9 +6582,8 @@ static void r3d_setup_defaults(struct hda_codec *codec) if (spec->dsp_state != DSP_DOWNLOADED) return; - r3d_dsp_scp_startup(codec); - - r3d_dsp_initial_mic_setup(codec); + ca0132_alt_dsp_scp_startup(codec); + ca0132_alt_init_analog_mics(codec); /*remove DSP headroom*/ tmp = FLOAT_ZERO; @@ -6620,19 +6619,16 @@ static void r3d_setup_defaults(struct hda_codec *codec) static void sbz_setup_defaults(struct hda_codec *codec) { struct ca0132_spec *spec = codec->spec; - unsigned int tmp, stream_format; + unsigned int tmp; int num_fx; int idx, i; if (spec->dsp_state != DSP_DOWNLOADED) return; - sbz_dsp_scp_startup(codec); - - sbz_init_analog_mics(codec); - + ca0132_alt_dsp_scp_startup(codec); + ca0132_alt_init_analog_mics(codec); sbz_connect_streams(codec); - sbz_chipio_startup_data(codec); chipio_set_stream_control(codec, 0x03, 1); @@ -6658,8 +6654,7 @@ static void sbz_setup_defaults(struct hda_codec *codec) /* Set speaker source? */ dspio_set_uint_param(codec, 0x32, 0x00, tmp); - sbz_dsp_initial_mic_setup(codec); - + ca0132_alt_dsp_initial_mic_setup(codec); /* out, in effects + voicefx */ num_fx = OUT_EFFECTS_COUNT + IN_EFFECTS_COUNT + 1; @@ -6672,23 +6667,7 @@ static void sbz_setup_defaults(struct hda_codec *codec) } } - /* - * Have to make a stream to bind the sound output to, otherwise - * you'll get dead audio. Before I did this, it would bind to an - * audio input, and would never work - */ - stream_format = snd_hdac_calc_stream_format(48000, 2, - SNDRV_PCM_FORMAT_S32_LE, 32, 0); - - snd_hda_codec_setup_stream(codec, spec->dacs[0], spec->dsp_stream_id, - 0, stream_format); - - snd_hda_codec_cleanup_stream(codec, spec->dacs[0]); - - snd_hda_codec_setup_stream(codec, spec->dacs[0], spec->dsp_stream_id, - 0, stream_format); - - snd_hda_codec_cleanup_stream(codec, spec->dacs[0]); + ca0132_alt_create_dummy_stream(codec); } /* @@ -6774,7 +6753,7 @@ static bool ca0132_download_dsp_images(struct hda_codec *codec) case QUIRK_AE5: if (request_firmware(&fw_entry, DESKTOP_EFX_FILE, codec->card->dev) != 0) { - codec_dbg(codec, "Desktop firmware not found. "); + codec_dbg(codec, "Desktop firmware not found."); spec->alt_firmware_present = false; } else { codec_dbg(codec, "Desktop firmware selected."); From 415cd8447c60e942ea44a33d7bad85ec5da4dfa8 Mon Sep 17 00:00:00 2001 From: Connor McAdams Date: Tue, 18 Sep 2018 14:33:38 -0400 Subject: [PATCH 163/299] ALSA: hda/ca0132 - Add DSP setup functions for AE-5 This patch adds DSP setup functions for the AE-5. Signed-off-by: Connor McAdams Signed-off-by: Takashi Iwai --- sound/pci/hda/patch_ca0132.c | 215 +++++++++++++++++++++++++++++++++++ 1 file changed, 215 insertions(+) diff --git a/sound/pci/hda/patch_ca0132.c b/sound/pci/hda/patch_ca0132.c index b89616c57c18..1e52d3b0af64 100644 --- a/sound/pci/hda/patch_ca0132.c +++ b/sound/pci/hda/patch_ca0132.c @@ -6524,6 +6524,151 @@ static void ca0132_alt_dsp_initial_mic_setup(struct hda_codec *codec) } } +static void ae5_post_dsp_register_set(struct hda_codec *codec) +{ + struct ca0132_spec *spec = codec->spec; + + chipio_8051_write_direct(codec, 0x93, 0x10); + snd_hda_codec_write(codec, WIDGET_CHIP_CTRL, 0, + VENDOR_CHIPIO_8051_ADDRESS_LOW, 0x44); + snd_hda_codec_write(codec, WIDGET_CHIP_CTRL, 0, + VENDOR_CHIPIO_PLL_PMU_WRITE, 0xc2); + + writeb(0xff, spec->mem_base + 0x304); + writeb(0xff, spec->mem_base + 0x304); + writeb(0xff, spec->mem_base + 0x304); + writeb(0xff, spec->mem_base + 0x304); + writeb(0x00, spec->mem_base + 0x100); + writeb(0xff, spec->mem_base + 0x304); + writeb(0x00, spec->mem_base + 0x100); + writeb(0xff, spec->mem_base + 0x304); + writeb(0x00, spec->mem_base + 0x100); + writeb(0xff, spec->mem_base + 0x304); + writeb(0x00, spec->mem_base + 0x100); + writeb(0xff, spec->mem_base + 0x304); + + ca0113_mmio_command_set(codec, 0x30, 0x2b, 0x3f); + ca0113_mmio_command_set(codec, 0x30, 0x2d, 0x3f); + ca0113_mmio_command_set(codec, 0x48, 0x07, 0x83); +} + +static void ae5_post_dsp_param_setup(struct hda_codec *codec) +{ + /* + * Param3 in the 8051's memory is represented by the ascii string 'mch' + * which seems to be 'multichannel'. This is also mentioned in the + * AE-5's registry values in Windows. + */ + chipio_set_control_param(codec, 3, 0); + /* + * I believe ASI is 'audio serial interface' and that it's used to + * change colors on the external LED strip connected to the AE-5. + */ + chipio_set_control_flag(codec, CONTROL_FLAG_ASI_96KHZ, 1); + + snd_hda_codec_write(codec, WIDGET_CHIP_CTRL, 0, 0x724, 0x83); + chipio_set_control_param(codec, CONTROL_PARAM_ASI, 0); + + snd_hda_codec_write(codec, WIDGET_CHIP_CTRL, 0, + VENDOR_CHIPIO_8051_ADDRESS_LOW, 0x92); + snd_hda_codec_write(codec, WIDGET_CHIP_CTRL, 0, + VENDOR_CHIPIO_8051_ADDRESS_HIGH, 0xfa); + snd_hda_codec_write(codec, WIDGET_CHIP_CTRL, 0, + VENDOR_CHIPIO_8051_DATA_WRITE, 0x22); +} + +static void ae5_post_dsp_pll_setup(struct hda_codec *codec) +{ + snd_hda_codec_write(codec, WIDGET_CHIP_CTRL, 0, + VENDOR_CHIPIO_8051_ADDRESS_LOW, 0x41); + snd_hda_codec_write(codec, WIDGET_CHIP_CTRL, 0, + VENDOR_CHIPIO_PLL_PMU_WRITE, 0xc8); + + snd_hda_codec_write(codec, WIDGET_CHIP_CTRL, 0, + VENDOR_CHIPIO_8051_ADDRESS_LOW, 0x45); + snd_hda_codec_write(codec, WIDGET_CHIP_CTRL, 0, + VENDOR_CHIPIO_PLL_PMU_WRITE, 0xcc); + + snd_hda_codec_write(codec, WIDGET_CHIP_CTRL, 0, + VENDOR_CHIPIO_8051_ADDRESS_LOW, 0x40); + snd_hda_codec_write(codec, WIDGET_CHIP_CTRL, 0, + VENDOR_CHIPIO_PLL_PMU_WRITE, 0xcb); + + snd_hda_codec_write(codec, WIDGET_CHIP_CTRL, 0, + VENDOR_CHIPIO_8051_ADDRESS_LOW, 0x43); + snd_hda_codec_write(codec, WIDGET_CHIP_CTRL, 0, + VENDOR_CHIPIO_PLL_PMU_WRITE, 0xc7); + + snd_hda_codec_write(codec, WIDGET_CHIP_CTRL, 0, + VENDOR_CHIPIO_8051_ADDRESS_LOW, 0x51); + snd_hda_codec_write(codec, WIDGET_CHIP_CTRL, 0, + VENDOR_CHIPIO_PLL_PMU_WRITE, 0x8d); +} + +static void ae5_post_dsp_stream_setup(struct hda_codec *codec) +{ + struct ca0132_spec *spec = codec->spec; + + mutex_lock(&spec->chipio_mutex); + + snd_hda_codec_write(codec, WIDGET_CHIP_CTRL, 0, 0x725, 0x81); + + chipio_set_conn_rate_no_mutex(codec, 0x70, SR_96_000); + + chipio_set_stream_channels(codec, 0x0C, 6); + chipio_set_stream_control(codec, 0x0C, 1); + + chipio_set_stream_source_dest(codec, 0x5, 0x43, 0x0); + + chipio_set_stream_source_dest(codec, 0x18, 0x9, 0xd0); + chipio_set_conn_rate_no_mutex(codec, 0xd0, SR_96_000); + chipio_set_stream_channels(codec, 0x18, 6); + chipio_set_stream_control(codec, 0x18, 1); + + chipio_set_control_param_no_mutex(codec, CONTROL_PARAM_ASI, 4); + + snd_hda_codec_write(codec, WIDGET_CHIP_CTRL, 0, + VENDOR_CHIPIO_8051_ADDRESS_LOW, 0x43); + snd_hda_codec_write(codec, WIDGET_CHIP_CTRL, 0, + VENDOR_CHIPIO_PLL_PMU_WRITE, 0xc7); + + ca0113_mmio_command_set(codec, 0x48, 0x01, 0x80); + + mutex_unlock(&spec->chipio_mutex); +} + +static void ae5_post_dsp_startup_data(struct hda_codec *codec) +{ + struct ca0132_spec *spec = codec->spec; + + mutex_lock(&spec->chipio_mutex); + + chipio_write_no_mutex(codec, 0x189000, 0x0001f101); + chipio_write_no_mutex(codec, 0x189004, 0x0001f101); + chipio_write_no_mutex(codec, 0x189024, 0x00014004); + chipio_write_no_mutex(codec, 0x189028, 0x0002000f); + + ca0113_mmio_command_set(codec, 0x48, 0x0a, 0x05); + chipio_set_control_param_no_mutex(codec, CONTROL_PARAM_ASI, 7); + ca0113_mmio_command_set(codec, 0x48, 0x0b, 0x12); + ca0113_mmio_command_set(codec, 0x48, 0x04, 0x00); + ca0113_mmio_command_set(codec, 0x48, 0x06, 0x48); + ca0113_mmio_command_set(codec, 0x48, 0x0a, 0x05); + ca0113_mmio_command_set(codec, 0x48, 0x07, 0x83); + ca0113_mmio_command_set(codec, 0x48, 0x0f, 0x00); + ca0113_mmio_command_set(codec, 0x48, 0x10, 0x00); + ca0113_mmio_gpio_set(codec, 0, true); + ca0113_mmio_gpio_set(codec, 1, true); + ca0113_mmio_command_set(codec, 0x48, 0x07, 0x80); + + chipio_write_no_mutex(codec, 0x18b03c, 0x00000012); + + ca0113_mmio_command_set(codec, 0x48, 0x0f, 0x00); + ca0113_mmio_command_set(codec, 0x48, 0x10, 0x00); + + mutex_unlock(&spec->chipio_mutex); +} + /* * Setup default parameters for DSP */ @@ -6670,6 +6815,73 @@ static void sbz_setup_defaults(struct hda_codec *codec) ca0132_alt_create_dummy_stream(codec); } +/* + * Setup default parameters for the Sound BlasterX AE-5 DSP. + */ +static void ae5_setup_defaults(struct hda_codec *codec) +{ + struct ca0132_spec *spec = codec->spec; + unsigned int tmp; + int num_fx; + int idx, i; + + if (spec->dsp_state != DSP_DOWNLOADED) + return; + + ca0132_alt_dsp_scp_startup(codec); + ca0132_alt_init_analog_mics(codec); + chipio_set_stream_control(codec, 0x03, 1); + chipio_set_stream_control(codec, 0x04, 1); + + /* New, unknown SCP req's */ + tmp = FLOAT_ZERO; + dspio_set_uint_param(codec, 0x96, 0x29, tmp); + dspio_set_uint_param(codec, 0x96, 0x2a, tmp); + dspio_set_uint_param(codec, 0x80, 0x0d, tmp); + dspio_set_uint_param(codec, 0x80, 0x0e, tmp); + + ca0113_mmio_command_set(codec, 0x30, 0x2e, 0x3f); + ca0113_mmio_gpio_set(codec, 0, false); + ca0113_mmio_command_set(codec, 0x30, 0x28, 0x00); + + /* Internal loopback off */ + tmp = FLOAT_ONE; + dspio_set_uint_param(codec, 0x37, 0x08, tmp); + dspio_set_uint_param(codec, 0x37, 0x10, tmp); + + /*remove DSP headroom*/ + tmp = FLOAT_ZERO; + dspio_set_uint_param(codec, 0x96, 0x3C, tmp); + + /* set WUH source */ + tmp = FLOAT_TWO; + dspio_set_uint_param(codec, 0x31, 0x00, tmp); + chipio_set_conn_rate(codec, MEM_CONNID_WUH, SR_48_000); + + /* Set speaker source? */ + dspio_set_uint_param(codec, 0x32, 0x00, tmp); + + ca0132_alt_dsp_initial_mic_setup(codec); + ae5_post_dsp_register_set(codec); + ae5_post_dsp_param_setup(codec); + ae5_post_dsp_pll_setup(codec); + ae5_post_dsp_stream_setup(codec); + ae5_post_dsp_startup_data(codec); + + /* out, in effects + voicefx */ + num_fx = OUT_EFFECTS_COUNT + IN_EFFECTS_COUNT + 1; + for (idx = 0; idx < num_fx; idx++) { + for (i = 0; i <= ca0132_effects[idx].params; i++) { + dspio_set_uint_param(codec, + ca0132_effects[idx].mid, + ca0132_effects[idx].reqs[i], + ca0132_effects[idx].def_vals[i]); + } + } + + ca0132_alt_create_dummy_stream(codec); +} + /* * Initialization of flags in chip */ @@ -7490,6 +7702,9 @@ static int ca0132_init(struct hda_codec *codec) case QUIRK_SBZ: sbz_setup_defaults(codec); break; + case QUIRK_AE5: + ae5_setup_defaults(codec); + break; default: ca0132_setup_defaults(codec); ca0132_init_analog_mic2(codec); From 746fc9deb4349e6af24573b2446c7de6a9c6928a Mon Sep 17 00:00:00 2001 From: Connor McAdams Date: Tue, 18 Sep 2018 14:33:39 -0400 Subject: [PATCH 164/299] ALSA: hda/ca0132 - Clean up ca0132_alt_out_select This patch cleans up ca0132_alt_out_select by moving the card specific output commands into a separate function. As more cards are added, the function ca0132_alt_out_select is going to get more bloated with these, so moving into a separate function tries to keep that from happening. Signed-off-by: Connor McAdams Signed-off-by: Takashi Iwai --- sound/pci/hda/patch_ca0132.c | 120 ++++++++++++++++++++--------------- 1 file changed, 69 insertions(+), 51 deletions(-) diff --git a/sound/pci/hda/patch_ca0132.c b/sound/pci/hda/patch_ca0132.c index 1e52d3b0af64..1fe99233d29f 100644 --- a/sound/pci/hda/patch_ca0132.c +++ b/sound/pci/hda/patch_ca0132.c @@ -4025,6 +4025,72 @@ exit: return err < 0 ? err : 0; } +/* + * These are the commands needed to setup output on each of the different card + * types. + */ +static void ca0132_alt_select_out_quirk_handler(struct hda_codec *codec) +{ + struct ca0132_spec *spec = codec->spec; + + switch (spec->cur_out_type) { + case SPEAKER_OUT: + switch (spec->quirk) { + case QUIRK_SBZ: + ca0113_mmio_gpio_set(codec, 7, false); + ca0113_mmio_gpio_set(codec, 4, true); + ca0113_mmio_gpio_set(codec, 1, true); + chipio_set_control_param(codec, 0x0D, 0x18); + break; + case QUIRK_R3DI: + chipio_set_control_param(codec, 0x0D, 0x24); + r3di_gpio_out_set(codec, R3DI_LINE_OUT); + break; + case QUIRK_R3D: + chipio_set_control_param(codec, 0x0D, 0x24); + ca0113_mmio_gpio_set(codec, 1, true); + break; + } + break; + case HEADPHONE_OUT: + switch (spec->quirk) { + case QUIRK_SBZ: + ca0113_mmio_gpio_set(codec, 7, true); + ca0113_mmio_gpio_set(codec, 4, true); + ca0113_mmio_gpio_set(codec, 1, false); + chipio_set_control_param(codec, 0x0D, 0x12); + break; + case QUIRK_R3DI: + chipio_set_control_param(codec, 0x0D, 0x21); + r3di_gpio_out_set(codec, R3DI_HEADPHONE_OUT); + break; + case QUIRK_R3D: + chipio_set_control_param(codec, 0x0D, 0x21); + ca0113_mmio_gpio_set(codec, 0x1, false); + break; + } + break; + case SURROUND_OUT: + switch (spec->quirk) { + case QUIRK_SBZ: + ca0113_mmio_gpio_set(codec, 7, false); + ca0113_mmio_gpio_set(codec, 4, true); + ca0113_mmio_gpio_set(codec, 1, true); + chipio_set_control_param(codec, 0x0D, 0x18); + break; + case QUIRK_R3DI: + chipio_set_control_param(codec, 0x0D, 0x24); + r3di_gpio_out_set(codec, R3DI_LINE_OUT); + break; + case QUIRK_R3D: + ca0113_mmio_gpio_set(codec, 1, true); + chipio_set_control_param(codec, 0x0D, 0x24); + break; + } + break; + } +} + /* * This function behaves similarly to the ca0132_select_out funciton above, * except with a few differences. It adds the ability to select the current @@ -4075,26 +4141,11 @@ static int ca0132_alt_select_out(struct hda_codec *codec) if (err < 0) goto exit; + ca0132_alt_select_out_quirk_handler(codec); + switch (spec->cur_out_type) { case SPEAKER_OUT: codec_dbg(codec, "%s speaker\n", __func__); - /*speaker out config*/ - switch (spec->quirk) { - case QUIRK_SBZ: - ca0113_mmio_gpio_set(codec, 7, false); - ca0113_mmio_gpio_set(codec, 4, true); - ca0113_mmio_gpio_set(codec, 1, true); - chipio_set_control_param(codec, 0x0D, 0x18); - break; - case QUIRK_R3DI: - chipio_set_control_param(codec, 0x0D, 0x24); - r3di_gpio_out_set(codec, R3DI_LINE_OUT); - break; - case QUIRK_R3D: - chipio_set_control_param(codec, 0x0D, 0x24); - ca0113_mmio_gpio_set(codec, 1, true); - break; - } /* disable headphone node */ pin_ctl = snd_hda_codec_read(codec, spec->out_pins[1], 0, @@ -4118,23 +4169,6 @@ static int ca0132_alt_select_out(struct hda_codec *codec) break; case HEADPHONE_OUT: codec_dbg(codec, "%s hp\n", __func__); - /* Headphone out config*/ - switch (spec->quirk) { - case QUIRK_SBZ: - ca0113_mmio_gpio_set(codec, 7, true); - ca0113_mmio_gpio_set(codec, 4, true); - ca0113_mmio_gpio_set(codec, 1, false); - chipio_set_control_param(codec, 0x0D, 0x12); - break; - case QUIRK_R3DI: - chipio_set_control_param(codec, 0x0D, 0x21); - r3di_gpio_out_set(codec, R3DI_HEADPHONE_OUT); - break; - case QUIRK_R3D: - chipio_set_control_param(codec, 0x0D, 0x21); - ca0113_mmio_gpio_set(codec, 0x1, false); - break; - } snd_hda_codec_write(codec, spec->out_pins[0], 0, AC_VERB_SET_EAPD_BTLENABLE, 0x00); @@ -4164,23 +4198,7 @@ static int ca0132_alt_select_out(struct hda_codec *codec) break; case SURROUND_OUT: codec_dbg(codec, "%s surround\n", __func__); - /* Surround out config*/ - switch (spec->quirk) { - case QUIRK_SBZ: - ca0113_mmio_gpio_set(codec, 7, false); - ca0113_mmio_gpio_set(codec, 4, true); - ca0113_mmio_gpio_set(codec, 1, true); - chipio_set_control_param(codec, 0x0D, 0x18); - break; - case QUIRK_R3DI: - chipio_set_control_param(codec, 0x0D, 0x24); - r3di_gpio_out_set(codec, R3DI_LINE_OUT); - break; - case QUIRK_R3D: - ca0113_mmio_gpio_set(codec, 1, true); - chipio_set_control_param(codec, 0x0D, 0x24); - break; - } + /* enable line out node */ pin_ctl = snd_hda_codec_read(codec, spec->out_pins[0], 0, AC_VERB_GET_PIN_WIDGET_CONTROL, 0); From 2283c85b4aa6b65e23be898f6a629d260e0cc07a Mon Sep 17 00:00:00 2001 From: Connor McAdams Date: Tue, 18 Sep 2018 14:33:40 -0400 Subject: [PATCH 165/299] ALSA: hda/ca0132 - Add output set commands for AE-5 This patch adds output selection commands for the AE-5. Signed-off-by: Connor McAdams Signed-off-by: Takashi Iwai --- sound/pci/hda/patch_ca0132.c | 80 +++++++++++++++++++++++++++++++----- 1 file changed, 70 insertions(+), 10 deletions(-) diff --git a/sound/pci/hda/patch_ca0132.c b/sound/pci/hda/patch_ca0132.c index 1fe99233d29f..2b7442f4a72d 100644 --- a/sound/pci/hda/patch_ca0132.c +++ b/sound/pci/hda/patch_ca0132.c @@ -666,6 +666,29 @@ static const struct ct_dsp_volume_ctl ca0132_alt_vol_ctls[] = { } }; +/* Values for ca0113_mmio_command_set for selecting output. */ +#define AE5_CA0113_OUT_SET_COMMANDS 6 +struct ae5_ca0113_output_set { + unsigned int group[AE5_CA0113_OUT_SET_COMMANDS]; + unsigned int target[AE5_CA0113_OUT_SET_COMMANDS]; + unsigned int vals[AE5_CA0113_OUT_SET_COMMANDS]; +}; + +static const struct ae5_ca0113_output_set ae5_ca0113_output_presets[] = { + { .group = { 0x30, 0x30, 0x48, 0x48, 0x48, 0x30 }, + .target = { 0x2e, 0x30, 0x0d, 0x17, 0x19, 0x32 }, + .vals = { 0x00, 0x00, 0x40, 0x00, 0x00, 0x3f } + }, + { .group = { 0x30, 0x30, 0x48, 0x48, 0x48, 0x30 }, + .target = { 0x2e, 0x30, 0x0d, 0x17, 0x19, 0x32 }, + .vals = { 0x3f, 0x3f, 0x00, 0x00, 0x00, 0x00 } + }, + { .group = { 0x30, 0x30, 0x48, 0x48, 0x48, 0x30 }, + .target = { 0x2e, 0x30, 0x0d, 0x17, 0x19, 0x32 }, + .vals = { 0x00, 0x00, 0x40, 0x00, 0x00, 0x3f } + } +}; + enum hda_cmd_vendor_io { /* for DspIO node */ VENDOR_DSPIO_SCP_WRITE_DATA_LOW = 0x000, @@ -4025,6 +4048,18 @@ exit: return err < 0 ? err : 0; } +static void ae5_mmio_select_out(struct hda_codec *codec) +{ + struct ca0132_spec *spec = codec->spec; + unsigned int i; + + for (i = 0; i < AE5_CA0113_OUT_SET_COMMANDS; i++) + ca0113_mmio_command_set(codec, + ae5_ca0113_output_presets[spec->cur_out_type].group[i], + ae5_ca0113_output_presets[spec->cur_out_type].target[i], + ae5_ca0113_output_presets[spec->cur_out_type].vals[i]); +} + /* * These are the commands needed to setup output on each of the different card * types. @@ -4032,6 +4067,7 @@ exit: static void ca0132_alt_select_out_quirk_handler(struct hda_codec *codec) { struct ca0132_spec *spec = codec->spec; + unsigned int tmp; switch (spec->cur_out_type) { case SPEAKER_OUT: @@ -4040,16 +4076,24 @@ static void ca0132_alt_select_out_quirk_handler(struct hda_codec *codec) ca0113_mmio_gpio_set(codec, 7, false); ca0113_mmio_gpio_set(codec, 4, true); ca0113_mmio_gpio_set(codec, 1, true); - chipio_set_control_param(codec, 0x0D, 0x18); + chipio_set_control_param(codec, 0x0d, 0x18); break; case QUIRK_R3DI: - chipio_set_control_param(codec, 0x0D, 0x24); + chipio_set_control_param(codec, 0x0d, 0x24); r3di_gpio_out_set(codec, R3DI_LINE_OUT); break; case QUIRK_R3D: - chipio_set_control_param(codec, 0x0D, 0x24); + chipio_set_control_param(codec, 0x0d, 0x24); ca0113_mmio_gpio_set(codec, 1, true); break; + case QUIRK_AE5: + ae5_mmio_select_out(codec); + tmp = FLOAT_ZERO; + dspio_set_uint_param(codec, 0x96, 0x29, tmp); + dspio_set_uint_param(codec, 0x96, 0x2a, tmp); + chipio_set_control_param(codec, 0x0d, 0xa4); + chipio_write(codec, 0x18b03c, 0x00000012); + break; } break; case HEADPHONE_OUT: @@ -4058,16 +4102,24 @@ static void ca0132_alt_select_out_quirk_handler(struct hda_codec *codec) ca0113_mmio_gpio_set(codec, 7, true); ca0113_mmio_gpio_set(codec, 4, true); ca0113_mmio_gpio_set(codec, 1, false); - chipio_set_control_param(codec, 0x0D, 0x12); + chipio_set_control_param(codec, 0x0d, 0x12); break; case QUIRK_R3DI: - chipio_set_control_param(codec, 0x0D, 0x21); + chipio_set_control_param(codec, 0x0d, 0x21); r3di_gpio_out_set(codec, R3DI_HEADPHONE_OUT); break; case QUIRK_R3D: - chipio_set_control_param(codec, 0x0D, 0x21); + chipio_set_control_param(codec, 0x0d, 0x21); ca0113_mmio_gpio_set(codec, 0x1, false); break; + case QUIRK_AE5: + ae5_mmio_select_out(codec); + tmp = FLOAT_ONE; + dspio_set_uint_param(codec, 0x96, 0x29, tmp); + dspio_set_uint_param(codec, 0x96, 0x2a, tmp); + chipio_set_control_param(codec, 0x0d, 0xa1); + chipio_write(codec, 0x18b03c, 0x00000012); + break; } break; case SURROUND_OUT: @@ -4076,15 +4128,23 @@ static void ca0132_alt_select_out_quirk_handler(struct hda_codec *codec) ca0113_mmio_gpio_set(codec, 7, false); ca0113_mmio_gpio_set(codec, 4, true); ca0113_mmio_gpio_set(codec, 1, true); - chipio_set_control_param(codec, 0x0D, 0x18); + chipio_set_control_param(codec, 0x0d, 0x18); break; case QUIRK_R3DI: - chipio_set_control_param(codec, 0x0D, 0x24); + chipio_set_control_param(codec, 0x0d, 0x24); r3di_gpio_out_set(codec, R3DI_LINE_OUT); break; case QUIRK_R3D: ca0113_mmio_gpio_set(codec, 1, true); - chipio_set_control_param(codec, 0x0D, 0x24); + chipio_set_control_param(codec, 0x0d, 0x24); + break; + case QUIRK_AE5: + ae5_mmio_select_out(codec); + tmp = FLOAT_ZERO; + dspio_set_uint_param(codec, 0x96, 0x29, tmp); + dspio_set_uint_param(codec, 0x96, 0x2a, tmp); + chipio_set_control_param(codec, 0x0d, 0xa4); + chipio_write(codec, 0x18b03c, 0x00000012); break; } break; @@ -4230,7 +4290,7 @@ static int ca0132_alt_select_out(struct hda_codec *codec) break; } - /* run through the output dsp commands for line-out */ + /* run through the output dsp commands for the selected output. */ for (i = 0; i < alt_out_presets[spec->cur_out_type].commands; i++) { err = dspio_set_uint_param(codec, alt_out_presets[spec->cur_out_type].mids[i], From f231daaf51daa78c8bf2d0dd94ebeba7836f8efe Mon Sep 17 00:00:00 2001 From: Connor McAdams Date: Tue, 18 Sep 2018 14:33:41 -0400 Subject: [PATCH 166/299] ALSA: hda/ca0132 - Add input selection commands for AE-5 This patch adds the input selection commands for the Sound BlasterX AE-5. Signed-off-by: Connor McAdams Signed-off-by: Takashi Iwai --- sound/pci/hda/patch_ca0132.c | 35 +++++++++++++++++++++++++++++------ 1 file changed, 29 insertions(+), 6 deletions(-) diff --git a/sound/pci/hda/patch_ca0132.c b/sound/pci/hda/patch_ca0132.c index 2b7442f4a72d..cfbcc3f16542 100644 --- a/sound/pci/hda/patch_ca0132.c +++ b/sound/pci/hda/patch_ca0132.c @@ -4523,6 +4523,10 @@ static int ca0132_alt_select_in(struct hda_codec *codec) r3di_gpio_mic_set(codec, R3DI_REAR_MIC); tmp = FLOAT_ONE; break; + case QUIRK_AE5: + ca0113_mmio_command_set(codec, 0x48, 0x28, 0x00); + tmp = FLOAT_THREE; + break; default: tmp = FLOAT_ONE; break; @@ -4537,10 +4541,15 @@ static int ca0132_alt_select_in(struct hda_codec *codec) chipio_set_stream_control(codec, 0x03, 1); chipio_set_stream_control(codec, 0x04, 1); - - if (spec->quirk == QUIRK_SBZ) { + switch (spec->quirk) { + case QUIRK_SBZ: chipio_write(codec, 0x18B098, 0x0000000C); chipio_write(codec, 0x18B09C, 0x0000000C); + break; + case QUIRK_AE5: + chipio_write(codec, 0x18B098, 0x0000000C); + chipio_write(codec, 0x18B09C, 0x0000004C); + break; } ca0132_alt_mic_boost_set(codec, spec->mic_boost_enum_val); break; @@ -4554,6 +4563,9 @@ static int ca0132_alt_select_in(struct hda_codec *codec) case QUIRK_R3DI: r3di_gpio_mic_set(codec, R3DI_REAR_MIC); break; + case QUIRK_AE5: + ca0113_mmio_command_set(codec, 0x48, 0x28, 0x00); + break; } chipio_set_conn_rate(codec, MEM_CONNID_MICIN1, SR_96_000); @@ -4564,11 +4576,13 @@ static int ca0132_alt_select_in(struct hda_codec *codec) tmp = FLOAT_ZERO; dspio_set_uint_param(codec, 0x80, 0x00, tmp); - if (spec->quirk == QUIRK_SBZ) { + switch (spec->quirk) { + case QUIRK_SBZ: + case QUIRK_AE5: chipio_write(codec, 0x18B098, 0x00000000); chipio_write(codec, 0x18B09C, 0x00000000); + break; } - chipio_set_stream_control(codec, 0x03, 1); chipio_set_stream_control(codec, 0x04, 1); break; @@ -4584,6 +4598,10 @@ static int ca0132_alt_select_in(struct hda_codec *codec) r3di_gpio_mic_set(codec, R3DI_FRONT_MIC); tmp = FLOAT_ONE; break; + case QUIRK_AE5: + ca0113_mmio_command_set(codec, 0x48, 0x28, 0x3f); + tmp = FLOAT_THREE; + break; default: tmp = FLOAT_ONE; break; @@ -4599,9 +4617,15 @@ static int ca0132_alt_select_in(struct hda_codec *codec) chipio_set_stream_control(codec, 0x03, 1); chipio_set_stream_control(codec, 0x04, 1); - if (spec->quirk == QUIRK_SBZ) { + switch (spec->quirk) { + case QUIRK_SBZ: chipio_write(codec, 0x18B098, 0x0000000C); chipio_write(codec, 0x18B09C, 0x000000CC); + break; + case QUIRK_AE5: + chipio_write(codec, 0x18B098, 0x0000000C); + chipio_write(codec, 0x18B09C, 0x0000004C); + break; } ca0132_alt_mic_boost_set(codec, spec->mic_boost_enum_val); break; @@ -4610,7 +4634,6 @@ static int ca0132_alt_select_in(struct hda_codec *codec) snd_hda_power_down_pm(codec); return 0; - } /* From 212de2e7414a8a719d7a1206ba940380d6fb6bc0 Mon Sep 17 00:00:00 2001 From: Connor McAdams Date: Tue, 18 Sep 2018 14:33:42 -0400 Subject: [PATCH 167/299] ALSA: hda/ca0132 - Add AE-5 specific controls This patch adds controls for the AE-5's headphone gain setting, and the DAC's interpolation filter setting. Signed-off-by: Connor McAdams Signed-off-by: Takashi Iwai --- sound/pci/hda/patch_ca0132.c | 239 ++++++++++++++++++++++++++++++++++- 1 file changed, 238 insertions(+), 1 deletion(-) diff --git a/sound/pci/hda/patch_ca0132.c b/sound/pci/hda/patch_ca0132.c index cfbcc3f16542..dbd17d8f9513 100644 --- a/sound/pci/hda/patch_ca0132.c +++ b/sound/pci/hda/patch_ca0132.c @@ -152,7 +152,9 @@ enum { XBASS_XOVER, EQ_PRESET_ENUM, SMART_VOLUME_ENUM, - MIC_BOOST_ENUM + MIC_BOOST_ENUM, + AE5_HEADPHONE_GAIN_ENUM, + AE5_SOUND_FILTER_ENUM #define EFFECTS_COUNT (EFFECT_END_NID - EFFECT_START_NID) }; @@ -689,6 +691,42 @@ static const struct ae5_ca0113_output_set ae5_ca0113_output_presets[] = { } }; +/* ae5 ca0113 command sequences to set headphone gain levels. */ +#define AE5_HEADPHONE_GAIN_PRESET_MAX_COMMANDS 4 +struct ae5_headphone_gain_set { + char *name; + unsigned int vals[AE5_HEADPHONE_GAIN_PRESET_MAX_COMMANDS]; +}; + +static const struct ae5_headphone_gain_set ae5_headphone_gain_presets[] = { + { .name = "Low (16-31", + .vals = { 0xff, 0x2c, 0xf5, 0x32 } + }, + { .name = "Medium (32-149", + .vals = { 0x38, 0xa8, 0x3e, 0x4c } + }, + { .name = "High (150-600", + .vals = { 0xff, 0xff, 0xff, 0x7f } + } +}; + +struct ae5_filter_set { + char *name; + unsigned int val; +}; + +static const struct ae5_filter_set ae5_filter_presets[] = { + { .name = "Slow Roll Off", + .val = 0xa0 + }, + { .name = "Minimum Phase", + .val = 0xc0 + }, + { .name = "Fast Roll Off", + .val = 0x80 + } +}; + enum hda_cmd_vendor_io { /* for DspIO node */ VENDOR_DSPIO_SCP_WRITE_DATA_LOW = 0x000, @@ -990,6 +1028,9 @@ struct ca0132_spec { long eq_preset_val; unsigned int tlv[4]; struct hda_vmaster_mute_hook vmaster_mute; + /* AE-5 Control values */ + unsigned char ae5_headphone_gain_val; + unsigned char ae5_filter_val; struct hda_codec *codec; @@ -3224,6 +3265,41 @@ static void ca0113_mmio_command_set(struct hda_codec *codec, unsigned int group, readl(spec->mem_base + 0x210); } +/* + * This second type of command is used for setting the sound filter type. + */ +static void ca0113_mmio_command_set_type2(struct hda_codec *codec, + unsigned int group, unsigned int target, unsigned int value) +{ + struct ca0132_spec *spec = codec->spec; + unsigned int write_val; + + writel(0x0000007e, spec->mem_base + 0x210); + readl(spec->mem_base + 0x210); + writel(0x0000005a, spec->mem_base + 0x210); + readl(spec->mem_base + 0x210); + readl(spec->mem_base + 0x210); + + writel(0x00800003, spec->mem_base + 0x20c); + writel(group, spec->mem_base + 0x804); + + writel(0x00800005, spec->mem_base + 0x20c); + write_val = (target & 0xff); + write_val |= (value << 8); + + + writel(write_val, spec->mem_base + 0x204); + msleep(20); + readl(spec->mem_base + 0x860); + readl(spec->mem_base + 0x854); + readl(spec->mem_base + 0x840); + + writel(0x00800004, spec->mem_base + 0x20c); + writel(0x00000000, spec->mem_base + 0x210); + readl(spec->mem_base + 0x210); + readl(spec->mem_base + 0x210); +} + /* * Setup GPIO for the other variants of Core3D. */ @@ -4048,6 +4124,8 @@ exit: return err < 0 ? err : 0; } +static int ae5_headphone_gain_set(struct hda_codec *codec, long val); + static void ae5_mmio_select_out(struct hda_codec *codec) { struct ca0132_spec *spec = codec->spec; @@ -4088,6 +4166,7 @@ static void ca0132_alt_select_out_quirk_handler(struct hda_codec *codec) break; case QUIRK_AE5: ae5_mmio_select_out(codec); + ae5_headphone_gain_set(codec, 2); tmp = FLOAT_ZERO; dspio_set_uint_param(codec, 0x96, 0x29, tmp); dspio_set_uint_param(codec, 0x96, 0x2a, tmp); @@ -4114,6 +4193,8 @@ static void ca0132_alt_select_out_quirk_handler(struct hda_codec *codec) break; case QUIRK_AE5: ae5_mmio_select_out(codec); + ae5_headphone_gain_set(codec, + spec->ae5_headphone_gain_val); tmp = FLOAT_ONE; dspio_set_uint_param(codec, 0x96, 0x29, tmp); dspio_set_uint_param(codec, 0x96, 0x2a, tmp); @@ -4140,6 +4221,7 @@ static void ca0132_alt_select_out_quirk_handler(struct hda_codec *codec) break; case QUIRK_AE5: ae5_mmio_select_out(codec); + ae5_headphone_gain_set(codec, 2); tmp = FLOAT_ZERO; dspio_set_uint_param(codec, 0x96, 0x29, tmp); dspio_set_uint_param(codec, 0x96, 0x2a, tmp); @@ -4876,6 +4958,16 @@ static int ca0132_alt_mic_boost_set(struct hda_codec *codec, long val) return ret; } +static int ae5_headphone_gain_set(struct hda_codec *codec, long val) +{ + unsigned int i; + + for (i = 0; i < 4; i++) + ca0113_mmio_command_set(codec, 0x48, 0x11 + i, + ae5_headphone_gain_presets[val].vals[i]); + return 0; +} + static int ca0132_vnode_switch_set(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { @@ -5140,6 +5232,112 @@ static int ca0132_alt_mic_boost_put(struct snd_kcontrol *kcontrol, return 1; } +/* + * Sound BlasterX AE-5 Headphone Gain Controls. + */ +#define AE5_HEADPHONE_GAIN_MAX 3 +static int ae5_headphone_gain_info(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_info *uinfo) +{ + char *sfx = " Ohms)"; + char namestr[SNDRV_CTL_ELEM_ID_NAME_MAXLEN]; + + uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; + uinfo->count = 1; + uinfo->value.enumerated.items = AE5_HEADPHONE_GAIN_MAX; + if (uinfo->value.enumerated.item >= AE5_HEADPHONE_GAIN_MAX) + uinfo->value.enumerated.item = AE5_HEADPHONE_GAIN_MAX - 1; + sprintf(namestr, "%s %s", + ae5_headphone_gain_presets[uinfo->value.enumerated.item].name, + sfx); + strcpy(uinfo->value.enumerated.name, namestr); + return 0; +} + +static int ae5_headphone_gain_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct hda_codec *codec = snd_kcontrol_chip(kcontrol); + struct ca0132_spec *spec = codec->spec; + + ucontrol->value.enumerated.item[0] = spec->ae5_headphone_gain_val; + return 0; +} + +static int ae5_headphone_gain_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct hda_codec *codec = snd_kcontrol_chip(kcontrol); + struct ca0132_spec *spec = codec->spec; + int sel = ucontrol->value.enumerated.item[0]; + unsigned int items = AE5_HEADPHONE_GAIN_MAX; + + if (sel >= items) + return 0; + + codec_dbg(codec, "ae5_headphone_gain: boost=%d\n", + sel); + + spec->ae5_headphone_gain_val = sel; + + if (spec->out_enum_val == HEADPHONE_OUT) + ae5_headphone_gain_set(codec, spec->ae5_headphone_gain_val); + + return 1; +} + +/* + * Sound BlasterX AE-5 sound filter enumerated control. + */ +#define AE5_SOUND_FILTER_MAX 3 + +static int ae5_sound_filter_info(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_info *uinfo) +{ + char namestr[SNDRV_CTL_ELEM_ID_NAME_MAXLEN]; + + uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; + uinfo->count = 1; + uinfo->value.enumerated.items = AE5_SOUND_FILTER_MAX; + if (uinfo->value.enumerated.item >= AE5_SOUND_FILTER_MAX) + uinfo->value.enumerated.item = AE5_SOUND_FILTER_MAX - 1; + sprintf(namestr, "%s", + ae5_filter_presets[uinfo->value.enumerated.item].name); + strcpy(uinfo->value.enumerated.name, namestr); + return 0; +} + +static int ae5_sound_filter_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct hda_codec *codec = snd_kcontrol_chip(kcontrol); + struct ca0132_spec *spec = codec->spec; + + ucontrol->value.enumerated.item[0] = spec->ae5_filter_val; + return 0; +} + +static int ae5_sound_filter_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct hda_codec *codec = snd_kcontrol_chip(kcontrol); + struct ca0132_spec *spec = codec->spec; + int sel = ucontrol->value.enumerated.item[0]; + unsigned int items = AE5_SOUND_FILTER_MAX; + + if (sel >= items) + return 0; + + codec_dbg(codec, "ae5_sound_filter: %s\n", + ae5_filter_presets[sel].name); + + spec->ae5_filter_val = sel; + + ca0113_mmio_command_set_type2(codec, 0x48, 0x07, + ae5_filter_presets[sel].val); + + return 1; +} /* * Input Select Control for alternative ca0132 codecs. This exists because @@ -5902,6 +6100,40 @@ static int ca0132_alt_add_mic_boost_enum(struct hda_codec *codec) } +/* + * Add headphone gain enumerated control for the AE-5. This switches between + * three modes, low, medium, and high. When non-headphone outputs are selected, + * it is automatically set to high. This is the same behavior as Windows. + */ +static int ae5_add_headphone_gain_enum(struct hda_codec *codec) +{ + struct snd_kcontrol_new knew = + HDA_CODEC_MUTE_MONO("AE-5: Headphone Gain", + AE5_HEADPHONE_GAIN_ENUM, 1, 0, HDA_INPUT); + knew.info = ae5_headphone_gain_info; + knew.get = ae5_headphone_gain_get; + knew.put = ae5_headphone_gain_put; + return snd_hda_ctl_add(codec, AE5_HEADPHONE_GAIN_ENUM, + snd_ctl_new1(&knew, codec)); +} + +/* + * Add sound filter enumerated control for the AE-5. This adds three different + * settings: Slow Roll Off, Minimum Phase, and Fast Roll Off. From what I've + * read into it, it changes the DAC's interpolation filter. + */ +static int ae5_add_sound_filter_enum(struct hda_codec *codec) +{ + struct snd_kcontrol_new knew = + HDA_CODEC_MUTE_MONO("AE-5: Sound Filter", + AE5_SOUND_FILTER_ENUM, 1, 0, HDA_INPUT); + knew.info = ae5_sound_filter_info; + knew.get = ae5_sound_filter_get; + knew.put = ae5_sound_filter_put; + return snd_hda_ctl_add(codec, AE5_SOUND_FILTER_ENUM, + snd_ctl_new1(&knew, codec)); +} + /* * Need to create slave controls for the alternate codecs that have surround * capabilities. @@ -6122,6 +6354,11 @@ static int ca0132_build_controls(struct hda_codec *codec) ca0132_alt_add_input_enum(codec); ca0132_alt_add_mic_boost_enum(codec); } + + if (spec->quirk == QUIRK_AE5) { + ae5_add_headphone_gain_enum(codec); + ae5_add_sound_filter_enum(codec); + } #ifdef ENABLE_TUNING_CONTROLS add_tuning_ctls(codec); #endif From edb1b3abdb20597d92a68c34afba9b01848b2acf Mon Sep 17 00:00:00 2001 From: Connor McAdams Date: Tue, 18 Sep 2018 14:33:43 -0400 Subject: [PATCH 168/299] ALSA: hda/ca0132 - Add AE-5 exit function This patch adds exit commands for the AE-5. Signed-off-by: Connor McAdams Signed-off-by: Takashi Iwai --- sound/pci/hda/patch_ca0132.c | 28 ++++++++++++++++++++++++++++ 1 file changed, 28 insertions(+) diff --git a/sound/pci/hda/patch_ca0132.c b/sound/pci/hda/patch_ca0132.c index dbd17d8f9513..225aa05dafae 100644 --- a/sound/pci/hda/patch_ca0132.c +++ b/sound/pci/hda/patch_ca0132.c @@ -7665,6 +7665,31 @@ static void r3d_exit_chip(struct hda_codec *codec) snd_hda_codec_write(codec, 0x01, 0, 0x794, 0x5b); } +static void ae5_exit_chip(struct hda_codec *codec) +{ + chipio_set_stream_control(codec, 0x03, 0); + chipio_set_stream_control(codec, 0x04, 0); + + ca0113_mmio_command_set(codec, 0x30, 0x32, 0x3f); + ca0113_mmio_command_set(codec, 0x48, 0x07, 0x83); + ca0113_mmio_command_set(codec, 0x48, 0x07, 0x83); + ca0113_mmio_command_set(codec, 0x30, 0x30, 0x00); + ca0113_mmio_command_set(codec, 0x30, 0x2b, 0x00); + ca0113_mmio_command_set(codec, 0x30, 0x2d, 0x00); + ca0113_mmio_gpio_set(codec, 0, false); + ca0113_mmio_gpio_set(codec, 1, false); + + snd_hda_codec_write(codec, 0x01, 0, 0x793, 0x00); + snd_hda_codec_write(codec, 0x01, 0, 0x794, 0x53); + + chipio_set_control_param(codec, CONTROL_PARAM_ASI, 0); + + chipio_set_stream_control(codec, 0x18, 0); + chipio_set_stream_control(codec, 0x0c, 0); + + snd_hda_codec_write(codec, 0x01, 0, 0x724, 0x83); +} + static void ca0132_exit_chip(struct hda_codec *codec) { /* put any chip cleanup stuffs here. */ @@ -8109,6 +8134,9 @@ static void ca0132_free(struct hda_codec *codec) case QUIRK_R3D: r3d_exit_chip(codec); break; + case QUIRK_AE5: + ae5_exit_chip(codec); + break; case QUIRK_R3DI: r3di_gpio_shutdown(codec); break; From 7afecb3073e357ebfe4087e4ab8bb493c32bb652 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Tue, 18 Sep 2018 01:28:04 +0000 Subject: [PATCH 169/299] ASoC: convert for_each_rtd_codec_dai() for missing part commit 0b7990e38971 ("ASoC: add for_each_rtd_codec_dai() macro") added for_each_rtd_codec_dai(), but it didn't convert few loop which is not using "rtd". This patch fixup it. Signed-off-by: Kuninori Morimoto Signed-off-by: Mark Brown --- sound/soc/soc-pcm.c | 31 +++++++++++++++---------------- 1 file changed, 15 insertions(+), 16 deletions(-) diff --git a/sound/soc/soc-pcm.c b/sound/soc/soc-pcm.c index 79f5dd541d29..e387fff352c8 100644 --- a/sound/soc/soc-pcm.c +++ b/sound/soc/soc-pcm.c @@ -1301,6 +1301,7 @@ static struct snd_soc_pcm_runtime *dpcm_get_be(struct snd_soc_card *card, struct snd_soc_dapm_widget *widget, int stream) { struct snd_soc_pcm_runtime *be; + struct snd_soc_dai *dai; int i; dev_dbg(card->dev, "ASoC: find BE for widget %s\n", widget->name); @@ -1318,8 +1319,7 @@ static struct snd_soc_pcm_runtime *dpcm_get_be(struct snd_soc_card *card, if (be->cpu_dai->playback_widget == widget) return be; - for (i = 0; i < be->num_codecs; i++) { - struct snd_soc_dai *dai = be->codec_dais[i]; + for_each_rtd_codec_dai(be, i, dai) { if (dai->playback_widget == widget) return be; } @@ -1338,8 +1338,7 @@ static struct snd_soc_pcm_runtime *dpcm_get_be(struct snd_soc_card *card, if (be->cpu_dai->capture_widget == widget) return be; - for (i = 0; i < be->num_codecs; i++) { - struct snd_soc_dai *dai = be->codec_dais[i]; + for_each_rtd_codec_dai(be, i, dai) { if (dai->capture_widget == widget) return be; } @@ -1435,6 +1434,7 @@ static int dpcm_prune_paths(struct snd_soc_pcm_runtime *fe, int stream, struct snd_soc_dpcm *dpcm; struct snd_soc_dapm_widget_list *list = *list_; struct snd_soc_dapm_widget *widget; + struct snd_soc_dai *dai; int prune = 0; /* Destroy any old FE <--> BE connections */ @@ -1449,8 +1449,7 @@ static int dpcm_prune_paths(struct snd_soc_pcm_runtime *fe, int stream, continue; /* is there a valid CODEC DAI widget for this BE */ - for (i = 0; i < dpcm->be->num_codecs; i++) { - struct snd_soc_dai *dai = dpcm->be->codec_dais[i]; + for_each_rtd_codec_dai(dpcm->be, i, dai) { widget = dai_get_widget(dai, stream); /* prune the BE if it's no longer in our active list */ @@ -1685,6 +1684,7 @@ static void dpcm_runtime_merge_format(struct snd_pcm_substream *substream, { struct snd_soc_pcm_runtime *fe = substream->private_data; struct snd_soc_dpcm *dpcm; + struct snd_soc_dai *dai; int stream = substream->stream; if (!fe->dai_link->dpcm_merged_format) @@ -1701,16 +1701,15 @@ static void dpcm_runtime_merge_format(struct snd_pcm_substream *substream, struct snd_soc_pcm_stream *codec_stream; int i; - for (i = 0; i < be->num_codecs; i++) { + for_each_rtd_codec_dai(be, i, dai) { /* * Skip CODECs which don't support the current stream * type. See soc_pcm_init_runtime_hw() for more details */ - if (!snd_soc_dai_stream_valid(be->codec_dais[i], - stream)) + if (!snd_soc_dai_stream_valid(dai, stream)) continue; - codec_dai_drv = be->codec_dais[i]->driver; + codec_dai_drv = dai->driver; if (stream == SNDRV_PCM_STREAM_PLAYBACK) codec_stream = &codec_dai_drv->playback; else @@ -1795,6 +1794,7 @@ static void dpcm_runtime_merge_rate(struct snd_pcm_substream *substream, struct snd_soc_dai_driver *codec_dai_drv; struct snd_soc_pcm_stream *codec_stream; struct snd_soc_pcm_stream *cpu_stream; + struct snd_soc_dai *dai; int i; if (stream == SNDRV_PCM_STREAM_PLAYBACK) @@ -1806,16 +1806,15 @@ static void dpcm_runtime_merge_rate(struct snd_pcm_substream *substream, *rate_max = min_not_zero(*rate_max, cpu_stream->rate_max); *rates = snd_pcm_rate_mask_intersect(*rates, cpu_stream->rates); - for (i = 0; i < be->num_codecs; i++) { + for_each_rtd_codec_dai(be, i, dai) { /* * Skip CODECs which don't support the current stream * type. See soc_pcm_init_runtime_hw() for more details */ - if (!snd_soc_dai_stream_valid(be->codec_dais[i], - stream)) + if (!snd_soc_dai_stream_valid(dai, stream)) continue; - codec_dai_drv = be->codec_dais[i]->driver; + codec_dai_drv = dai->driver; if (stream == SNDRV_PCM_STREAM_PLAYBACK) codec_stream = &codec_dai_drv->playback; else @@ -2784,6 +2783,7 @@ int soc_dpcm_be_digital_mute(struct snd_soc_pcm_runtime *fe, int mute) struct snd_soc_dpcm *dpcm; struct list_head *clients = &fe->dpcm[SNDRV_PCM_STREAM_PLAYBACK].be_clients; + struct snd_soc_dai *dai; list_for_each_entry(dpcm, clients, list_be) { @@ -2793,8 +2793,7 @@ int soc_dpcm_be_digital_mute(struct snd_soc_pcm_runtime *fe, int mute) if (be->dai_link->ignore_suspend) continue; - for (i = 0; i < be->num_codecs; i++) { - struct snd_soc_dai *dai = be->codec_dais[i]; + for_each_rtd_codec_dai(be, i, dai) { struct snd_soc_dai_driver *drv = dai->driver; dev_dbg(be->dev, "ASoC: BE digital mute %s\n", From 6d11b12879144da5f5aa08071a8a7f95f3b5a4e8 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Tue, 18 Sep 2018 01:28:30 +0000 Subject: [PATCH 170/299] ASoC: rename for_each_rtd_codec_dai_reverse to rollback commit 0b7990e38971 ("ASoC: add for_each_rtd_codec_dai() macro") added for_each_rtd_codec_dai_reverse(). but _rollback() is better naming than _reverse(). This patch rename it. Signed-off-by: Kuninori Morimoto Signed-off-by: Mark Brown --- include/sound/soc.h | 2 +- sound/soc/soc-pcm.c | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/include/sound/soc.h b/include/sound/soc.h index 1e093b399bc0..ec1ae9f4feeb 100644 --- a/include/sound/soc.h +++ b/include/sound/soc.h @@ -1164,7 +1164,7 @@ struct snd_soc_pcm_runtime { for ((i) = 0; \ ((i) < rtd->num_codecs) && ((dai) = rtd->codec_dais[i]); \ (i)++) -#define for_each_rtd_codec_dai_reverse(rtd, i, dai) \ +#define for_each_rtd_codec_dai_rollback(rtd, i, dai) \ for (; ((i--) >= 0) && ((dai) = rtd->codec_dais[i]);) diff --git a/sound/soc/soc-pcm.c b/sound/soc/soc-pcm.c index e387fff352c8..1eff1dbb0d00 100644 --- a/sound/soc/soc-pcm.c +++ b/sound/soc/soc-pcm.c @@ -621,7 +621,7 @@ machine_err: i = rtd->num_codecs; codec_dai_err: - for_each_rtd_codec_dai_reverse(rtd, i, codec_dai) { + for_each_rtd_codec_dai_rollback(rtd, i, codec_dai) { if (codec_dai->driver->ops->shutdown) codec_dai->driver->ops->shutdown(substream, codec_dai); } @@ -1015,7 +1015,7 @@ interface_err: i = rtd->num_codecs; codec_err: - for_each_rtd_codec_dai_reverse(rtd, i, codec_dai) { + for_each_rtd_codec_dai_rollback(rtd, i, codec_dai) { if (codec_dai->driver->ops->hw_free) codec_dai->driver->ops->hw_free(substream, codec_dai); codec_dai->rate = 0; From 7fe072b4df5d0cc832eb758c1eed243c145a2dfc Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Tue, 18 Sep 2018 01:28:49 +0000 Subject: [PATCH 171/299] ASoC: add for_each_card_prelinks() macro To be more readable code, this patch adds new for_each_card_prelinks() macro, and replace existing code to it. Signed-off-by: Kuninori Morimoto Signed-off-by: Mark Brown --- include/sound/soc.h | 4 ++++ sound/soc/fsl/pcm030-audio-fabric.c | 5 +++-- sound/soc/generic/simple-card-utils.c | 6 ++---- sound/soc/intel/boards/skl_hda_dsp_generic.c | 5 +++-- sound/soc/mediatek/mt2701/mt2701-cs42448.c | 13 +++++++------ sound/soc/mediatek/mt2701/mt2701-wm8960.c | 13 +++++++------ sound/soc/mediatek/mt6797/mt6797-mt6351.c | 13 +++++++------ sound/soc/mediatek/mt8173/mt8173-max98090.c | 13 +++++++------ sound/soc/mediatek/mt8173/mt8173-rt5650-rt5514.c | 7 ++++--- sound/soc/mediatek/mt8173/mt8173-rt5650-rt5676.c | 7 ++++--- sound/soc/mediatek/mt8173/mt8173-rt5650.c | 7 ++++--- sound/soc/meson/axg-card.c | 3 +-- sound/soc/qcom/apq8096.c | 7 +++---- sound/soc/qcom/sdm845.c | 7 +++---- sound/soc/samsung/tm2_wm5110.c | 13 +++++++------ sound/soc/soc-core.c | 16 +++++++--------- 16 files changed, 73 insertions(+), 66 deletions(-) diff --git a/include/sound/soc.h b/include/sound/soc.h index ec1ae9f4feeb..f94b989e7a1a 100644 --- a/include/sound/soc.h +++ b/include/sound/soc.h @@ -1120,6 +1120,10 @@ struct snd_soc_card { void *drvdata; }; +#define for_each_card_prelinks(card, i, link) \ + for ((i) = 0; \ + ((i) < (card)->num_links) && ((link) = &(card)->dai_link[i]); \ + (i)++) /* SoC machine DAI configuration, glues a codec and cpu DAI together */ struct snd_soc_pcm_runtime { diff --git a/sound/soc/fsl/pcm030-audio-fabric.c b/sound/soc/fsl/pcm030-audio-fabric.c index ec731223cab3..e339f36cea95 100644 --- a/sound/soc/fsl/pcm030-audio-fabric.c +++ b/sound/soc/fsl/pcm030-audio-fabric.c @@ -57,6 +57,7 @@ static int pcm030_fabric_probe(struct platform_device *op) struct device_node *platform_np; struct snd_soc_card *card = &pcm030_card; struct pcm030_audio_data *pdata; + struct snd_soc_dai_link *dai_link; int ret; int i; @@ -78,8 +79,8 @@ static int pcm030_fabric_probe(struct platform_device *op) return -ENODEV; } - for (i = 0; i < card->num_links; i++) - card->dai_link[i].platform_of_node = platform_np; + for_each_card_prelinks(card, i, dai_link) + dai_link->platform_of_node = platform_np; ret = request_module("snd-soc-wm9712"); if (ret) diff --git a/sound/soc/generic/simple-card-utils.c b/sound/soc/generic/simple-card-utils.c index b400dbf1f834..f34cc6cddfa2 100644 --- a/sound/soc/generic/simple-card-utils.c +++ b/sound/soc/generic/simple-card-utils.c @@ -404,11 +404,9 @@ EXPORT_SYMBOL_GPL(asoc_simple_card_canonicalize_cpu); int asoc_simple_card_clean_reference(struct snd_soc_card *card) { struct snd_soc_dai_link *dai_link; - int num_links; + int i; - for (num_links = 0, dai_link = card->dai_link; - num_links < card->num_links; - num_links++, dai_link++) { + for_each_card_prelinks(card, i, dai_link) { of_node_put(dai_link->cpu_of_node); of_node_put(dai_link->codecs->of_node); } diff --git a/sound/soc/intel/boards/skl_hda_dsp_generic.c b/sound/soc/intel/boards/skl_hda_dsp_generic.c index b213e9b47505..b415dd4c85f5 100644 --- a/sound/soc/intel/boards/skl_hda_dsp_generic.c +++ b/sound/soc/intel/boards/skl_hda_dsp_generic.c @@ -104,6 +104,7 @@ static struct snd_soc_card hda_soc_card = { static int skl_hda_fill_card_info(struct skl_machine_pdata *pdata) { struct snd_soc_card *card = &hda_soc_card; + struct snd_soc_dai_link *dai_link; u32 codec_count, codec_mask; int i, num_links, num_route; @@ -125,8 +126,8 @@ static int skl_hda_fill_card_info(struct skl_machine_pdata *pdata) card->num_links = num_links; card->num_dapm_routes = num_route; - for (i = 0; i < num_links; i++) - skl_hda_be_dai_links[i].platform_name = pdata->platform; + for_each_card_prelinks(card, i, dai_link) + dai_link->platform_name = pdata->platform; return 0; } diff --git a/sound/soc/mediatek/mt2701/mt2701-cs42448.c b/sound/soc/mediatek/mt2701/mt2701-cs42448.c index 666282b865a8..875f84691535 100644 --- a/sound/soc/mediatek/mt2701/mt2701-cs42448.c +++ b/sound/soc/mediatek/mt2701/mt2701-cs42448.c @@ -299,6 +299,7 @@ static int mt2701_cs42448_machine_probe(struct platform_device *pdev) devm_kzalloc(&pdev->dev, sizeof(struct mt2701_cs42448_private), GFP_KERNEL); struct device *dev = &pdev->dev; + struct snd_soc_dai_link *dai_link; if (!priv) return -ENOMEM; @@ -309,10 +310,10 @@ static int mt2701_cs42448_machine_probe(struct platform_device *pdev) dev_err(&pdev->dev, "Property 'platform' missing or invalid\n"); return -EINVAL; } - for (i = 0; i < card->num_links; i++) { - if (mt2701_cs42448_dai_links[i].platform_name) + for_each_card_prelinks(card, i, dai_link) { + if (dai_links->platform_name) continue; - mt2701_cs42448_dai_links[i].platform_of_node = platform_node; + dai_links->platform_of_node = platform_node; } card->dev = dev; @@ -324,10 +325,10 @@ static int mt2701_cs42448_machine_probe(struct platform_device *pdev) "Property 'audio-codec' missing or invalid\n"); return -EINVAL; } - for (i = 0; i < card->num_links; i++) { - if (mt2701_cs42448_dai_links[i].codec_name) + for_each_card_prelinks(card, i, dai_link) { + if (dai_links->codec_name) continue; - mt2701_cs42448_dai_links[i].codec_of_node = codec_node; + dai_links->codec_of_node = codec_node; } codec_node_bt_mrg = of_parse_phandle(pdev->dev.of_node, diff --git a/sound/soc/mediatek/mt2701/mt2701-wm8960.c b/sound/soc/mediatek/mt2701/mt2701-wm8960.c index e5d49e6e2f99..c67f62935e53 100644 --- a/sound/soc/mediatek/mt2701/mt2701-wm8960.c +++ b/sound/soc/mediatek/mt2701/mt2701-wm8960.c @@ -97,6 +97,7 @@ static int mt2701_wm8960_machine_probe(struct platform_device *pdev) { struct snd_soc_card *card = &mt2701_wm8960_card; struct device_node *platform_node, *codec_node; + struct snd_soc_dai_link *dai_link; int ret, i; platform_node = of_parse_phandle(pdev->dev.of_node, @@ -105,10 +106,10 @@ static int mt2701_wm8960_machine_probe(struct platform_device *pdev) dev_err(&pdev->dev, "Property 'platform' missing or invalid\n"); return -EINVAL; } - for (i = 0; i < card->num_links; i++) { - if (mt2701_wm8960_dai_links[i].platform_name) + for_each_card_prelinks(card, i, dai_link) { + if (dai_links->platform_name) continue; - mt2701_wm8960_dai_links[i].platform_of_node = platform_node; + dai_links->platform_of_node = platform_node; } card->dev = &pdev->dev; @@ -120,10 +121,10 @@ static int mt2701_wm8960_machine_probe(struct platform_device *pdev) "Property 'audio-codec' missing or invalid\n"); return -EINVAL; } - for (i = 0; i < card->num_links; i++) { - if (mt2701_wm8960_dai_links[i].codec_name) + for_each_card_prelinks(card, i, dai_link) { + if (dai_links->codec_name) continue; - mt2701_wm8960_dai_links[i].codec_of_node = codec_node; + dai_links->codec_of_node = codec_node; } ret = snd_soc_of_parse_audio_routing(card, "audio-routing"); diff --git a/sound/soc/mediatek/mt6797/mt6797-mt6351.c b/sound/soc/mediatek/mt6797/mt6797-mt6351.c index 6e578e830e42..ff2e0ca4384e 100644 --- a/sound/soc/mediatek/mt6797/mt6797-mt6351.c +++ b/sound/soc/mediatek/mt6797/mt6797-mt6351.c @@ -158,6 +158,7 @@ static int mt6797_mt6351_dev_probe(struct platform_device *pdev) { struct snd_soc_card *card = &mt6797_mt6351_card; struct device_node *platform_node, *codec_node; + struct snd_soc_dai_link *dai_link; int ret, i; card->dev = &pdev->dev; @@ -168,10 +169,10 @@ static int mt6797_mt6351_dev_probe(struct platform_device *pdev) dev_err(&pdev->dev, "Property 'platform' missing or invalid\n"); return -EINVAL; } - for (i = 0; i < card->num_links; i++) { - if (mt6797_mt6351_dai_links[i].platform_name) + for_each_card_prelinks(card, i, dai_link) { + if (dai_link->platform_name) continue; - mt6797_mt6351_dai_links[i].platform_of_node = platform_node; + dai_links->platform_of_node = platform_node; } codec_node = of_parse_phandle(pdev->dev.of_node, @@ -181,10 +182,10 @@ static int mt6797_mt6351_dev_probe(struct platform_device *pdev) "Property 'audio-codec' missing or invalid\n"); return -EINVAL; } - for (i = 0; i < card->num_links; i++) { - if (mt6797_mt6351_dai_links[i].codec_name) + for_each_card_prelinks(card, i, dai_link) { + if (dai_links->codec_name) continue; - mt6797_mt6351_dai_links[i].codec_of_node = codec_node; + dai_links->codec_of_node = codec_node; } ret = devm_snd_soc_register_card(&pdev->dev, card); diff --git a/sound/soc/mediatek/mt8173/mt8173-max98090.c b/sound/soc/mediatek/mt8173/mt8173-max98090.c index 902d111016d6..4d6596d5cb07 100644 --- a/sound/soc/mediatek/mt8173/mt8173-max98090.c +++ b/sound/soc/mediatek/mt8173/mt8173-max98090.c @@ -137,6 +137,7 @@ static int mt8173_max98090_dev_probe(struct platform_device *pdev) { struct snd_soc_card *card = &mt8173_max98090_card; struct device_node *codec_node, *platform_node; + struct snd_soc_dai_link *dai_link; int ret, i; platform_node = of_parse_phandle(pdev->dev.of_node, @@ -145,10 +146,10 @@ static int mt8173_max98090_dev_probe(struct platform_device *pdev) dev_err(&pdev->dev, "Property 'platform' missing or invalid\n"); return -EINVAL; } - for (i = 0; i < card->num_links; i++) { - if (mt8173_max98090_dais[i].platform_name) + for_each_card_prelinks(card, i, dai_link) { + if (dai_link->platform_name) continue; - mt8173_max98090_dais[i].platform_of_node = platform_node; + dai_link->platform_of_node = platform_node; } codec_node = of_parse_phandle(pdev->dev.of_node, @@ -158,10 +159,10 @@ static int mt8173_max98090_dev_probe(struct platform_device *pdev) "Property 'audio-codec' missing or invalid\n"); return -EINVAL; } - for (i = 0; i < card->num_links; i++) { - if (mt8173_max98090_dais[i].codec_name) + for_each_card_prelinks(card, i, dai_link) { + if (dai_link->codec_name) continue; - mt8173_max98090_dais[i].codec_of_node = codec_node; + dai_link->codec_of_node = codec_node; } card->dev = &pdev->dev; diff --git a/sound/soc/mediatek/mt8173/mt8173-rt5650-rt5514.c b/sound/soc/mediatek/mt8173/mt8173-rt5650-rt5514.c index 5b4e90180827..da5b58ce791b 100644 --- a/sound/soc/mediatek/mt8173/mt8173-rt5650-rt5514.c +++ b/sound/soc/mediatek/mt8173/mt8173-rt5650-rt5514.c @@ -178,6 +178,7 @@ static int mt8173_rt5650_rt5514_dev_probe(struct platform_device *pdev) { struct snd_soc_card *card = &mt8173_rt5650_rt5514_card; struct device_node *platform_node; + struct snd_soc_dai_link *dai_link; int i, ret; platform_node = of_parse_phandle(pdev->dev.of_node, @@ -187,10 +188,10 @@ static int mt8173_rt5650_rt5514_dev_probe(struct platform_device *pdev) return -EINVAL; } - for (i = 0; i < card->num_links; i++) { - if (mt8173_rt5650_rt5514_dais[i].platform_name) + for_each_card_prelinks(card, i, dai_link) { + if (dai_link->platform_name) continue; - mt8173_rt5650_rt5514_dais[i].platform_of_node = platform_node; + dai_link->platform_of_node = platform_node; } mt8173_rt5650_rt5514_codecs[0].of_node = diff --git a/sound/soc/mediatek/mt8173/mt8173-rt5650-rt5676.c b/sound/soc/mediatek/mt8173/mt8173-rt5650-rt5676.c index 82675ed057de..d83cd039b413 100644 --- a/sound/soc/mediatek/mt8173/mt8173-rt5650-rt5676.c +++ b/sound/soc/mediatek/mt8173/mt8173-rt5650-rt5676.c @@ -224,6 +224,7 @@ static int mt8173_rt5650_rt5676_dev_probe(struct platform_device *pdev) { struct snd_soc_card *card = &mt8173_rt5650_rt5676_card; struct device_node *platform_node; + struct snd_soc_dai_link *dai_link; int i, ret; platform_node = of_parse_phandle(pdev->dev.of_node, @@ -233,10 +234,10 @@ static int mt8173_rt5650_rt5676_dev_probe(struct platform_device *pdev) return -EINVAL; } - for (i = 0; i < card->num_links; i++) { - if (mt8173_rt5650_rt5676_dais[i].platform_name) + for_each_card_prelinks(card, i, dai_link) { + if (dai_link->platform_name) continue; - mt8173_rt5650_rt5676_dais[i].platform_of_node = platform_node; + dai_link->platform_of_node = platform_node; } mt8173_rt5650_rt5676_codecs[0].of_node = diff --git a/sound/soc/mediatek/mt8173/mt8173-rt5650.c b/sound/soc/mediatek/mt8173/mt8173-rt5650.c index ef05fbc40c32..7edf250c8fb1 100644 --- a/sound/soc/mediatek/mt8173/mt8173-rt5650.c +++ b/sound/soc/mediatek/mt8173/mt8173-rt5650.c @@ -239,6 +239,7 @@ static int mt8173_rt5650_dev_probe(struct platform_device *pdev) struct device_node *platform_node; struct device_node *np; const char *codec_capture_dai; + struct snd_soc_dai_link *dai_link; int i, ret; platform_node = of_parse_phandle(pdev->dev.of_node, @@ -248,10 +249,10 @@ static int mt8173_rt5650_dev_probe(struct platform_device *pdev) return -EINVAL; } - for (i = 0; i < card->num_links; i++) { - if (mt8173_rt5650_dais[i].platform_name) + for_each_card_prelinks(card, i, dai_link) { + if (dai_link->platform_name) continue; - mt8173_rt5650_dais[i].platform_of_node = platform_node; + dai_link->platform_of_node = platform_node; } mt8173_rt5650_codecs[0].of_node = diff --git a/sound/soc/meson/axg-card.c b/sound/soc/meson/axg-card.c index 197e10a96e28..aa54d2c612c9 100644 --- a/sound/soc/meson/axg-card.c +++ b/sound/soc/meson/axg-card.c @@ -101,8 +101,7 @@ static void axg_card_clean_references(struct axg_card *priv) int i, j; if (card->dai_link) { - for (i = 0; i < card->num_links; i++) { - link = &card->dai_link[i]; + for_each_card_prelinks(card, i, link) { of_node_put(link->cpu_of_node); for_each_link_codecs(link, j, codec) of_node_put(codec->of_node); diff --git a/sound/soc/qcom/apq8096.c b/sound/soc/qcom/apq8096.c index 1543e85629f8..fb45f396ab4a 100644 --- a/sound/soc/qcom/apq8096.c +++ b/sound/soc/qcom/apq8096.c @@ -25,13 +25,12 @@ static int apq8096_be_hw_params_fixup(struct snd_soc_pcm_runtime *rtd, static void apq8096_add_be_ops(struct snd_soc_card *card) { - struct snd_soc_dai_link *link = card->dai_link; - int i, num_links = card->num_links; + struct snd_soc_dai_link *link; + int i; - for (i = 0; i < num_links; i++) { + for_each_card_prelinks(card, i, link) { if (link->no_pcm == 1) link->be_hw_params_fixup = apq8096_be_hw_params_fixup; - link++; } } diff --git a/sound/soc/qcom/sdm845.c b/sound/soc/qcom/sdm845.c index 2a781d87ee65..9effbecc571f 100644 --- a/sound/soc/qcom/sdm845.c +++ b/sound/soc/qcom/sdm845.c @@ -195,15 +195,14 @@ static int sdm845_be_hw_params_fixup(struct snd_soc_pcm_runtime *rtd, static void sdm845_add_be_ops(struct snd_soc_card *card) { - struct snd_soc_dai_link *link = card->dai_link; - int i, num_links = card->num_links; + struct snd_soc_dai_link *link; + int i; - for (i = 0; i < num_links; i++) { + for_each_card_prelinks(card, i, link) { if (link->no_pcm == 1) { link->ops = &sdm845_be_ops; link->be_hw_params_fixup = sdm845_be_hw_params_fixup; } - link++; } } diff --git a/sound/soc/samsung/tm2_wm5110.c b/sound/soc/samsung/tm2_wm5110.c index 43332c32d7e9..dc93941e01c3 100644 --- a/sound/soc/samsung/tm2_wm5110.c +++ b/sound/soc/samsung/tm2_wm5110.c @@ -491,6 +491,7 @@ static int tm2_probe(struct platform_device *pdev) struct snd_soc_card *card = &tm2_card; struct tm2_machine_priv *priv; struct of_phandle_args args; + struct snd_soc_dai_link *dai_link; int num_codecs, ret, i; priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL); @@ -558,18 +559,18 @@ static int tm2_probe(struct platform_device *pdev) } /* Initialize WM5110 - I2S and HDMI - I2S1 DAI links */ - for (i = 0; i < card->num_links; i++) { + for_each_card_prelinks(card, i, dai_link) { unsigned int dai_index = 0; /* WM5110 */ - card->dai_link[i].cpu_name = NULL; - card->dai_link[i].platform_name = NULL; + dai_link->cpu_name = NULL; + dai_link->platform_name = NULL; if (num_codecs > 1 && i == card->num_links - 1) dai_index = 1; /* HDMI */ - card->dai_link[i].codec_of_node = codec_dai_node[dai_index]; - card->dai_link[i].cpu_of_node = cpu_dai_node[dai_index]; - card->dai_link[i].platform_of_node = cpu_dai_node[dai_index]; + dai_link->codec_of_node = codec_dai_node[dai_index]; + dai_link->cpu_of_node = cpu_dai_node[dai_index]; + dai_link->platform_of_node = cpu_dai_node[dai_index]; } if (num_codecs > 1) { diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c index da2b2a758b6d..532d8c59ed1e 100644 --- a/sound/soc/soc-core.c +++ b/sound/soc/soc-core.c @@ -1889,9 +1889,7 @@ static void soc_check_tplg_fes(struct snd_soc_card *card) continue; /* machine matches, so override the rtd data */ - for (i = 0; i < card->num_links; i++) { - - dai_link = &card->dai_link[i]; + for_each_card_prelinks(card, i, dai_link) { /* ignore this FE */ if (dai_link->dynamic) { @@ -1955,8 +1953,8 @@ static int snd_soc_instantiate_card(struct snd_soc_card *card) soc_check_tplg_fes(card); /* bind DAIs */ - for (i = 0; i < card->num_links; i++) { - ret = soc_bind_dai_link(card, &card->dai_link[i]); + for_each_card_prelinks(card, i, dai_link) { + ret = soc_bind_dai_link(card, dai_link); if (ret != 0) goto base_error; } @@ -1969,8 +1967,8 @@ static int snd_soc_instantiate_card(struct snd_soc_card *card) } /* add predefined DAI links to the list */ - for (i = 0; i < card->num_links; i++) - snd_soc_add_dai_link(card, card->dai_link+i); + for_each_card_prelinks(card, i, dai_link) + snd_soc_add_dai_link(card, dai_link); /* card bind complete so register a sound card */ ret = snd_card_new(card->dev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1, @@ -2714,12 +2712,12 @@ static int snd_soc_bind_card(struct snd_soc_card *card) int snd_soc_register_card(struct snd_soc_card *card) { int i, ret; + struct snd_soc_dai_link *link; if (!card->name || !card->dev) return -EINVAL; - for (i = 0; i < card->num_links; i++) { - struct snd_soc_dai_link *link = &card->dai_link[i]; + for_each_card_prelinks(card, i, link) { ret = soc_init_dai_link(card, link); if (ret) { From 98061fdbfccc02aa0fd6637c67a0524aab385b8d Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Tue, 18 Sep 2018 01:29:16 +0000 Subject: [PATCH 172/299] ASoC: add for_each_card_links() macro To be more readable code, this patch adds new for_each_card_links() macro, and replace existing code to it. Signed-off-by: Kuninori Morimoto Signed-off-by: Mark Brown --- include/sound/soc.h | 6 ++++++ sound/soc/soc-core.c | 8 ++++---- 2 files changed, 10 insertions(+), 4 deletions(-) diff --git a/include/sound/soc.h b/include/sound/soc.h index f94b989e7a1a..1fffbaa819d9 100644 --- a/include/sound/soc.h +++ b/include/sound/soc.h @@ -1125,6 +1125,12 @@ struct snd_soc_card { ((i) < (card)->num_links) && ((link) = &(card)->dai_link[i]); \ (i)++) +#define for_each_card_links(card, link) \ + list_for_each_entry(dai_link, &(card)->dai_link_list, list) +#define for_each_card_links_safe(card, link, _link) \ + list_for_each_entry_safe(link, _link, &(card)->dai_link_list, list) + + /* SoC machine DAI configuration, glues a codec and cpu DAI together */ struct snd_soc_pcm_runtime { struct device *dev; diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c index 532d8c59ed1e..495173635642 100644 --- a/sound/soc/soc-core.c +++ b/sound/soc/soc-core.c @@ -816,7 +816,7 @@ struct snd_soc_dai_link *snd_soc_find_dai_link(struct snd_soc_card *card, lockdep_assert_held(&client_mutex); - list_for_each_entry_safe(link, _link, &card->dai_link_list, list) { + for_each_card_links_safe(card, link, _link) { if (link->id != id) continue; @@ -1004,7 +1004,7 @@ static void soc_remove_dai_links(struct snd_soc_card *card) soc_remove_link_components(card, rtd, order); } - list_for_each_entry_safe(link, _link, &card->dai_link_list, list) { + for_each_card_links_safe(card, link, _link) { if (link->dobj.type == SND_SOC_DOBJ_DAI_LINK) dev_warn(card->dev, "Topology forgot to remove link %s?\n", link->name); @@ -1219,7 +1219,7 @@ void snd_soc_remove_dai_link(struct snd_soc_card *card, if (dai_link->dobj.type && card->remove_dai_link) card->remove_dai_link(card, dai_link); - list_for_each_entry_safe(link, _link, &card->dai_link_list, list) { + for_each_card_links_safe(card, link, _link) { if (link == dai_link) { list_del(&link->list); return; @@ -2033,7 +2033,7 @@ static int snd_soc_instantiate_card(struct snd_soc_card *card) /* Find new DAI links added during probing components and bind them. * Components with topology may bring new DAIs and DAI links. */ - list_for_each_entry(dai_link, &card->dai_link_list, list) { + for_each_card_links(card, dai_link) { if (soc_is_dai_link_bound(card, dai_link)) continue; From bcb1fd1fcd6507ba5a1f8610550135dc367aedb7 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Tue, 18 Sep 2018 01:29:35 +0000 Subject: [PATCH 173/299] ASoC: add for_each_card_rtds() macro To be more readable code, this patch adds new for_each_card_rtds() macro, and replace existing code to it. Signed-off-by: Kuninori Morimoto Signed-off-by: Mark Brown --- include/sound/soc.h | 4 ++ sound/soc/codecs/hdac_hdmi.c | 2 +- sound/soc/intel/atom/sst-mfld-platform-pcm.c | 4 +- sound/soc/soc-core.c | 48 ++++++++++---------- sound/soc/soc-dapm.c | 2 +- sound/soc/soc-pcm.c | 12 ++--- 6 files changed, 38 insertions(+), 34 deletions(-) diff --git a/include/sound/soc.h b/include/sound/soc.h index 1fffbaa819d9..164418dbf40e 100644 --- a/include/sound/soc.h +++ b/include/sound/soc.h @@ -1130,6 +1130,10 @@ struct snd_soc_card { #define for_each_card_links_safe(card, link, _link) \ list_for_each_entry_safe(link, _link, &(card)->dai_link_list, list) +#define for_each_card_rtds(card, rtd) \ + list_for_each_entry(rtd, &(card)->rtd_list, list) +#define for_each_card_rtds_safe(card, rtd, _rtd) \ + list_for_each_entry_safe(rtd, _rtd, &(card)->rtd_list, list) /* SoC machine DAI configuration, glues a codec and cpu DAI together */ struct snd_soc_pcm_runtime { diff --git a/sound/soc/codecs/hdac_hdmi.c b/sound/soc/codecs/hdac_hdmi.c index 41d90dc6ebf7..4e9854889a95 100644 --- a/sound/soc/codecs/hdac_hdmi.c +++ b/sound/soc/codecs/hdac_hdmi.c @@ -1604,7 +1604,7 @@ static struct snd_pcm *hdac_hdmi_get_pcm_from_id(struct snd_soc_card *card, { struct snd_soc_pcm_runtime *rtd; - list_for_each_entry(rtd, &card->rtd_list, list) { + for_each_card_rtds(card, rtd) { if (rtd->pcm && (rtd->pcm->device == device)) return rtd->pcm; } diff --git a/sound/soc/intel/atom/sst-mfld-platform-pcm.c b/sound/soc/intel/atom/sst-mfld-platform-pcm.c index 6c36da560877..afc559866095 100644 --- a/sound/soc/intel/atom/sst-mfld-platform-pcm.c +++ b/sound/soc/intel/atom/sst-mfld-platform-pcm.c @@ -765,7 +765,7 @@ static int sst_soc_prepare(struct device *dev) snd_soc_poweroff(drv->soc_card->dev); /* set the SSPs to idle */ - list_for_each_entry(rtd, &drv->soc_card->rtd_list, list) { + for_each_card_rtds(drv->soc_card, rtd) { struct snd_soc_dai *dai = rtd->cpu_dai; if (dai->active) { @@ -786,7 +786,7 @@ static void sst_soc_complete(struct device *dev) return; /* restart SSPs */ - list_for_each_entry(rtd, &drv->soc_card->rtd_list, list) { + for_each_card_rtds(drv->soc_card, rtd) { struct snd_soc_dai *dai = rtd->cpu_dai; if (dai->active) { diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c index 495173635642..7efcf3475d6f 100644 --- a/sound/soc/soc-core.c +++ b/sound/soc/soc-core.c @@ -342,7 +342,7 @@ struct snd_pcm_substream *snd_soc_get_dai_substream(struct snd_soc_card *card, { struct snd_soc_pcm_runtime *rtd; - list_for_each_entry(rtd, &card->rtd_list, list) { + for_each_card_rtds(card, rtd) { if (rtd->dai_link->no_pcm && !strcmp(rtd->dai_link->name, dai_link)) return rtd->pcm->streams[stream].substream; @@ -399,7 +399,7 @@ static void soc_remove_pcm_runtimes(struct snd_soc_card *card) { struct snd_soc_pcm_runtime *rtd, *_rtd; - list_for_each_entry_safe(rtd, _rtd, &card->rtd_list, list) { + for_each_card_rtds_safe(card, rtd, _rtd) { list_del(&rtd->list); soc_free_pcm_runtime(rtd); } @@ -412,7 +412,7 @@ struct snd_soc_pcm_runtime *snd_soc_get_pcm_runtime(struct snd_soc_card *card, { struct snd_soc_pcm_runtime *rtd; - list_for_each_entry(rtd, &card->rtd_list, list) { + for_each_card_rtds(card, rtd) { if (!strcmp(rtd->dai_link->name, dai_link)) return rtd; } @@ -452,7 +452,7 @@ int snd_soc_suspend(struct device *dev) snd_power_change_state(card->snd_card, SNDRV_CTL_POWER_D3hot); /* mute any active DACs */ - list_for_each_entry(rtd, &card->rtd_list, list) { + for_each_card_rtds(card, rtd) { struct snd_soc_dai *dai; if (rtd->dai_link->ignore_suspend) @@ -467,7 +467,7 @@ int snd_soc_suspend(struct device *dev) } /* suspend all pcms */ - list_for_each_entry(rtd, &card->rtd_list, list) { + for_each_card_rtds(card, rtd) { if (rtd->dai_link->ignore_suspend) continue; @@ -477,7 +477,7 @@ int snd_soc_suspend(struct device *dev) if (card->suspend_pre) card->suspend_pre(card); - list_for_each_entry(rtd, &card->rtd_list, list) { + for_each_card_rtds(card, rtd) { struct snd_soc_dai *cpu_dai = rtd->cpu_dai; if (rtd->dai_link->ignore_suspend) @@ -488,10 +488,10 @@ int snd_soc_suspend(struct device *dev) } /* close any waiting streams */ - list_for_each_entry(rtd, &card->rtd_list, list) + for_each_card_rtds(card, rtd) flush_delayed_work(&rtd->delayed_work); - list_for_each_entry(rtd, &card->rtd_list, list) { + for_each_card_rtds(card, rtd) { if (rtd->dai_link->ignore_suspend) continue; @@ -548,7 +548,7 @@ int snd_soc_suspend(struct device *dev) } } - list_for_each_entry(rtd, &card->rtd_list, list) { + for_each_card_rtds(card, rtd) { struct snd_soc_dai *cpu_dai = rtd->cpu_dai; if (rtd->dai_link->ignore_suspend) @@ -592,7 +592,7 @@ static void soc_resume_deferred(struct work_struct *work) card->resume_pre(card); /* resume control bus DAIs */ - list_for_each_entry(rtd, &card->rtd_list, list) { + for_each_card_rtds(card, rtd) { struct snd_soc_dai *cpu_dai = rtd->cpu_dai; if (rtd->dai_link->ignore_suspend) @@ -610,7 +610,7 @@ static void soc_resume_deferred(struct work_struct *work) } } - list_for_each_entry(rtd, &card->rtd_list, list) { + for_each_card_rtds(card, rtd) { if (rtd->dai_link->ignore_suspend) continue; @@ -625,7 +625,7 @@ static void soc_resume_deferred(struct work_struct *work) } /* unmute any active DACs */ - list_for_each_entry(rtd, &card->rtd_list, list) { + for_each_card_rtds(card, rtd) { struct snd_soc_dai *dai; if (rtd->dai_link->ignore_suspend) @@ -639,7 +639,7 @@ static void soc_resume_deferred(struct work_struct *work) } } - list_for_each_entry(rtd, &card->rtd_list, list) { + for_each_card_rtds(card, rtd) { struct snd_soc_dai *cpu_dai = rtd->cpu_dai; if (rtd->dai_link->ignore_suspend) @@ -674,7 +674,7 @@ int snd_soc_resume(struct device *dev) return 0; /* activate pins from sleep state */ - list_for_each_entry(rtd, &card->rtd_list, list) { + for_each_card_rtds(card, rtd) { struct snd_soc_dai *codec_dai; struct snd_soc_dai *cpu_dai = rtd->cpu_dai; int j; @@ -694,7 +694,7 @@ int snd_soc_resume(struct device *dev) * have that problem and may take a substantial amount of time to resume * due to I/O costs and anti-pop so handle them out of line. */ - list_for_each_entry(rtd, &card->rtd_list, list) { + for_each_card_rtds(card, rtd) { struct snd_soc_dai *cpu_dai = rtd->cpu_dai; bus_control |= cpu_dai->driver->bus_control; } @@ -839,7 +839,7 @@ static bool soc_is_dai_link_bound(struct snd_soc_card *card, { struct snd_soc_pcm_runtime *rtd; - list_for_each_entry(rtd, &card->rtd_list, list) { + for_each_card_rtds(card, rtd) { if (rtd->dai_link == dai_link) return true; } @@ -994,13 +994,13 @@ static void soc_remove_dai_links(struct snd_soc_card *card) for (order = SND_SOC_COMP_ORDER_FIRST; order <= SND_SOC_COMP_ORDER_LAST; order++) { - list_for_each_entry(rtd, &card->rtd_list, list) + for_each_card_rtds(card, rtd) soc_remove_link_dais(card, rtd, order); } for (order = SND_SOC_COMP_ORDER_FIRST; order <= SND_SOC_COMP_ORDER_LAST; order++) { - list_for_each_entry(rtd, &card->rtd_list, list) + for_each_card_rtds(card, rtd) soc_remove_link_components(card, rtd, order); } @@ -2014,7 +2014,7 @@ static int snd_soc_instantiate_card(struct snd_soc_card *card) /* probe all components used by DAI links on this card */ for (order = SND_SOC_COMP_ORDER_FIRST; order <= SND_SOC_COMP_ORDER_LAST; order++) { - list_for_each_entry(rtd, &card->rtd_list, list) { + for_each_card_rtds(card, rtd) { ret = soc_probe_link_components(card, rtd, order); if (ret < 0) { dev_err(card->dev, @@ -2048,7 +2048,7 @@ static int snd_soc_instantiate_card(struct snd_soc_card *card) /* probe all DAI links on this card */ for (order = SND_SOC_COMP_ORDER_FIRST; order <= SND_SOC_COMP_ORDER_LAST; order++) { - list_for_each_entry(rtd, &card->rtd_list, list) { + for_each_card_rtds(card, rtd) { ret = soc_probe_link_dais(card, rtd, order); if (ret < 0) { dev_err(card->dev, @@ -2169,7 +2169,7 @@ static int soc_cleanup_card_resources(struct snd_soc_card *card) struct snd_soc_pcm_runtime *rtd; /* make sure any delayed work runs */ - list_for_each_entry(rtd, &card->rtd_list, list) + for_each_card_rtds(card, rtd) flush_delayed_work(&rtd->delayed_work); /* free the ALSA card at first; this syncs with pending operations */ @@ -2211,13 +2211,13 @@ int snd_soc_poweroff(struct device *dev) /* Flush out pmdown_time work - we actually do want to run it * now, we're shutting down so no imminent restart. */ - list_for_each_entry(rtd, &card->rtd_list, list) + for_each_card_rtds(card, rtd) flush_delayed_work(&rtd->delayed_work); snd_soc_dapm_shutdown(card); /* deactivate pins to sleep state */ - list_for_each_entry(rtd, &card->rtd_list, list) { + for_each_card_rtds(card, rtd) { struct snd_soc_dai *cpu_dai = rtd->cpu_dai; struct snd_soc_dai *codec_dai; int i; @@ -2686,7 +2686,7 @@ static int snd_soc_bind_card(struct snd_soc_card *card) return ret; /* deactivate pins to sleep state */ - list_for_each_entry(rtd, &card->rtd_list, list) { + for_each_card_rtds(card, rtd) { struct snd_soc_dai *cpu_dai = rtd->cpu_dai; struct snd_soc_dai *codec_dai; int j; diff --git a/sound/soc/soc-dapm.c b/sound/soc/soc-dapm.c index ee6b9758ec15..8c5b065c8880 100644 --- a/sound/soc/soc-dapm.c +++ b/sound/soc/soc-dapm.c @@ -4183,7 +4183,7 @@ void snd_soc_dapm_connect_dai_link_widgets(struct snd_soc_card *card) struct snd_soc_pcm_runtime *rtd; /* for each BE DAI link... */ - list_for_each_entry(rtd, &card->rtd_list, list) { + for_each_card_rtds(card, rtd) { /* * dynamic FE links have no fixed DAI mapping. * CODEC<->CODEC links have no direct connection. diff --git a/sound/soc/soc-pcm.c b/sound/soc/soc-pcm.c index 1eff1dbb0d00..09d0f668c78e 100644 --- a/sound/soc/soc-pcm.c +++ b/sound/soc/soc-pcm.c @@ -1307,7 +1307,7 @@ static struct snd_soc_pcm_runtime *dpcm_get_be(struct snd_soc_card *card, dev_dbg(card->dev, "ASoC: find BE for widget %s\n", widget->name); if (stream == SNDRV_PCM_STREAM_PLAYBACK) { - list_for_each_entry(be, &card->rtd_list, list) { + for_each_card_rtds(card, be) { if (!be->dai_link->no_pcm) continue; @@ -1326,7 +1326,7 @@ static struct snd_soc_pcm_runtime *dpcm_get_be(struct snd_soc_card *card, } } else { - list_for_each_entry(be, &card->rtd_list, list) { + for_each_card_rtds(card, be) { if (!be->dai_link->no_pcm) continue; @@ -1382,7 +1382,7 @@ static bool dpcm_end_walk_at_be(struct snd_soc_dapm_widget *widget, int i; if (dir == SND_SOC_DAPM_DIR_OUT) { - list_for_each_entry(rtd, &card->rtd_list, list) { + for_each_card_rtds(card, rtd) { if (!rtd->dai_link->no_pcm) continue; @@ -1395,7 +1395,7 @@ static bool dpcm_end_walk_at_be(struct snd_soc_dapm_widget *widget, } } } else { /* SND_SOC_DAPM_DIR_IN */ - list_for_each_entry(rtd, &card->rtd_list, list) { + for_each_card_rtds(card, rtd) { if (!rtd->dai_link->no_pcm) continue; @@ -2761,14 +2761,14 @@ int soc_dpcm_runtime_update(struct snd_soc_card *card) mutex_lock_nested(&card->mutex, SND_SOC_CARD_CLASS_RUNTIME); /* shutdown all old paths first */ - list_for_each_entry(fe, &card->rtd_list, list) { + for_each_card_rtds(card, fe) { ret = soc_dpcm_fe_runtime_update(fe, 0); if (ret) goto out; } /* bring new paths up */ - list_for_each_entry(fe, &card->rtd_list, list) { + for_each_card_rtds(card, fe) { ret = soc_dpcm_fe_runtime_update(fe, 1); if (ret) goto out; From f70f18f7d459b7958a4d3944396e2bc4a9f7ed72 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Tue, 18 Sep 2018 01:29:55 +0000 Subject: [PATCH 174/299] ASoC: add for_each_card_components() macro To be more readable code, this patch adds new for_each_card_components() macro, and replace existing code to it. Signed-off-by: Kuninori Morimoto Signed-off-by: Mark Brown --- include/sound/soc.h | 3 +++ sound/soc/intel/boards/broadwell.c | 4 ++-- sound/soc/intel/boards/bytcr_rt5640.c | 4 ++-- sound/soc/intel/boards/bytcr_rt5651.c | 4 ++-- sound/soc/intel/boards/cht_bsw_rt5672.c | 4 ++-- sound/soc/soc-core.c | 5 +++-- 6 files changed, 14 insertions(+), 10 deletions(-) diff --git a/include/sound/soc.h b/include/sound/soc.h index 164418dbf40e..34efab6baff6 100644 --- a/include/sound/soc.h +++ b/include/sound/soc.h @@ -1135,6 +1135,9 @@ struct snd_soc_card { #define for_each_card_rtds_safe(card, rtd, _rtd) \ list_for_each_entry_safe(rtd, _rtd, &(card)->rtd_list, list) +#define for_each_card_components(card, component) \ + list_for_each_entry(component, &(card)->component_dev_list, card_list) + /* SoC machine DAI configuration, glues a codec and cpu DAI together */ struct snd_soc_pcm_runtime { struct device *dev; diff --git a/sound/soc/intel/boards/broadwell.c b/sound/soc/intel/boards/broadwell.c index 7b0ee67b4fc8..68e6543e6cb0 100644 --- a/sound/soc/intel/boards/broadwell.c +++ b/sound/soc/intel/boards/broadwell.c @@ -223,7 +223,7 @@ static struct snd_soc_dai_link broadwell_rt286_dais[] = { static int broadwell_suspend(struct snd_soc_card *card){ struct snd_soc_component *component; - list_for_each_entry(component, &card->component_dev_list, card_list) { + for_each_card_components(card, component) { if (!strcmp(component->name, "i2c-INT343A:00")) { dev_dbg(component->dev, "disabling jack detect before going to suspend.\n"); @@ -237,7 +237,7 @@ static int broadwell_suspend(struct snd_soc_card *card){ static int broadwell_resume(struct snd_soc_card *card){ struct snd_soc_component *component; - list_for_each_entry(component, &card->component_dev_list, card_list) { + for_each_card_components(card, component) { if (!strcmp(component->name, "i2c-INT343A:00")) { dev_dbg(component->dev, "enabling jack detect for resume.\n"); diff --git a/sound/soc/intel/boards/bytcr_rt5640.c b/sound/soc/intel/boards/bytcr_rt5640.c index b6dc524830b2..8587bd3d1cc1 100644 --- a/sound/soc/intel/boards/bytcr_rt5640.c +++ b/sound/soc/intel/boards/bytcr_rt5640.c @@ -1048,7 +1048,7 @@ static int byt_rt5640_suspend(struct snd_soc_card *card) if (!BYT_RT5640_JDSRC(byt_rt5640_quirk)) return 0; - list_for_each_entry(component, &card->component_dev_list, card_list) { + for_each_card_components(card, component) { if (!strcmp(component->name, byt_rt5640_codec_name)) { dev_dbg(component->dev, "disabling jack detect before suspend\n"); snd_soc_component_set_jack(component, NULL, NULL); @@ -1067,7 +1067,7 @@ static int byt_rt5640_resume(struct snd_soc_card *card) if (!BYT_RT5640_JDSRC(byt_rt5640_quirk)) return 0; - list_for_each_entry(component, &card->component_dev_list, card_list) { + for_each_card_components(card, component) { if (!strcmp(component->name, byt_rt5640_codec_name)) { dev_dbg(component->dev, "re-enabling jack detect after resume\n"); snd_soc_component_set_jack(component, &priv->jack, NULL); diff --git a/sound/soc/intel/boards/bytcr_rt5651.c b/sound/soc/intel/boards/bytcr_rt5651.c index f8a68bdb3885..8dffeecda55b 100644 --- a/sound/soc/intel/boards/bytcr_rt5651.c +++ b/sound/soc/intel/boards/bytcr_rt5651.c @@ -742,7 +742,7 @@ static int byt_rt5651_suspend(struct snd_soc_card *card) if (!BYT_RT5651_JDSRC(byt_rt5651_quirk)) return 0; - list_for_each_entry(component, &card->component_dev_list, card_list) { + for_each_card_components(card, component) { if (!strcmp(component->name, byt_rt5651_codec_name)) { dev_dbg(component->dev, "disabling jack detect before suspend\n"); snd_soc_component_set_jack(component, NULL, NULL); @@ -761,7 +761,7 @@ static int byt_rt5651_resume(struct snd_soc_card *card) if (!BYT_RT5651_JDSRC(byt_rt5651_quirk)) return 0; - list_for_each_entry(component, &card->component_dev_list, card_list) { + for_each_card_components(card, component) { if (!strcmp(component->name, byt_rt5651_codec_name)) { dev_dbg(component->dev, "re-enabling jack detect after resume\n"); snd_soc_component_set_jack(component, &priv->jack, NULL); diff --git a/sound/soc/intel/boards/cht_bsw_rt5672.c b/sound/soc/intel/boards/cht_bsw_rt5672.c index e054318185ea..51f0d45d6f8f 100644 --- a/sound/soc/intel/boards/cht_bsw_rt5672.c +++ b/sound/soc/intel/boards/cht_bsw_rt5672.c @@ -347,7 +347,7 @@ static int cht_suspend_pre(struct snd_soc_card *card) struct snd_soc_component *component; struct cht_mc_private *ctx = snd_soc_card_get_drvdata(card); - list_for_each_entry(component, &card->component_dev_list, card_list) { + for_each_card_components(card, component) { if (!strncmp(component->name, ctx->codec_name, sizeof(ctx->codec_name))) { @@ -364,7 +364,7 @@ static int cht_resume_post(struct snd_soc_card *card) struct snd_soc_component *component; struct cht_mc_private *ctx = snd_soc_card_get_drvdata(card); - list_for_each_entry(component, &card->component_dev_list, card_list) { + for_each_card_components(card, component) { if (!strncmp(component->name, ctx->codec_name, sizeof(ctx->codec_name))) { diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c index 7efcf3475d6f..673a694ede3e 100644 --- a/sound/soc/soc-core.c +++ b/sound/soc/soc-core.c @@ -510,7 +510,7 @@ int snd_soc_suspend(struct device *dev) snd_soc_dapm_sync(&card->dapm); /* suspend all COMPONENTs */ - list_for_each_entry(component, &card->component_dev_list, card_list) { + for_each_card_components(card, component) { struct snd_soc_dapm_context *dapm = snd_soc_component_get_dapm(component); /* If there are paths active then the COMPONENT will be held with @@ -602,7 +602,7 @@ static void soc_resume_deferred(struct work_struct *work) cpu_dai->driver->resume(cpu_dai); } - list_for_each_entry(component, &card->component_dev_list, card_list) { + for_each_card_components(card, component) { if (component->suspended) { if (component->driver->resume) component->driver->resume(component); @@ -1354,6 +1354,7 @@ static int soc_probe_component(struct snd_soc_card *card, component->driver->num_dapm_routes); list_add(&dapm->list, &card->dapm_list); + /* see for_each_card_components */ list_add(&component->card_list, &card->component_dev_list); return 0; From 1a1035a9854fd893d487a84edccc1d5804e1d716 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Tue, 18 Sep 2018 01:30:41 +0000 Subject: [PATCH 175/299] ASoC: add for_each_comp_order() macro To be more readable code, this patch adds new for_each_comp_order() macro, and replace existing code to it. Signed-off-by: Kuninori Morimoto Signed-off-by: Mark Brown --- include/sound/soc.h | 5 +++++ sound/soc/soc-core.c | 18 ++++++------------ 2 files changed, 11 insertions(+), 12 deletions(-) diff --git a/include/sound/soc.h b/include/sound/soc.h index 34efab6baff6..93aa894a57ef 100644 --- a/include/sound/soc.h +++ b/include/sound/soc.h @@ -372,6 +372,11 @@ #define SND_SOC_COMP_ORDER_LATE 1 #define SND_SOC_COMP_ORDER_LAST 2 +#define for_each_comp_order(order) \ + for (order = SND_SOC_COMP_ORDER_FIRST; \ + order <= SND_SOC_COMP_ORDER_LAST; \ + order++) + /* * Bias levels * diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c index 673a694ede3e..d8625ac2b201 100644 --- a/sound/soc/soc-core.c +++ b/sound/soc/soc-core.c @@ -992,14 +992,12 @@ static void soc_remove_dai_links(struct snd_soc_card *card) struct snd_soc_pcm_runtime *rtd; struct snd_soc_dai_link *link, *_link; - for (order = SND_SOC_COMP_ORDER_FIRST; order <= SND_SOC_COMP_ORDER_LAST; - order++) { + for_each_comp_order(order) { for_each_card_rtds(card, rtd) soc_remove_link_dais(card, rtd, order); } - for (order = SND_SOC_COMP_ORDER_FIRST; order <= SND_SOC_COMP_ORDER_LAST; - order++) { + for_each_comp_order(order) { for_each_card_rtds(card, rtd) soc_remove_link_components(card, rtd, order); } @@ -1617,8 +1615,7 @@ static int soc_probe_aux_devices(struct snd_soc_card *card) int order; int ret; - for (order = SND_SOC_COMP_ORDER_FIRST; order <= SND_SOC_COMP_ORDER_LAST; - order++) { + for_each_comp_order(order) { list_for_each_entry(comp, &card->aux_comp_list, card_aux_list) { if (comp->driver->probe_order == order) { ret = soc_probe_component(card, comp); @@ -1640,8 +1637,7 @@ static void soc_remove_aux_devices(struct snd_soc_card *card) struct snd_soc_component *comp, *_comp; int order; - for (order = SND_SOC_COMP_ORDER_FIRST; order <= SND_SOC_COMP_ORDER_LAST; - order++) { + for_each_comp_order(order) { list_for_each_entry_safe(comp, _comp, &card->aux_comp_list, card_aux_list) { @@ -2013,8 +2009,7 @@ static int snd_soc_instantiate_card(struct snd_soc_card *card) } /* probe all components used by DAI links on this card */ - for (order = SND_SOC_COMP_ORDER_FIRST; order <= SND_SOC_COMP_ORDER_LAST; - order++) { + for_each_comp_order(order) { for_each_card_rtds(card, rtd) { ret = soc_probe_link_components(card, rtd, order); if (ret < 0) { @@ -2047,8 +2042,7 @@ static int snd_soc_instantiate_card(struct snd_soc_card *card) } /* probe all DAI links on this card */ - for (order = SND_SOC_COMP_ORDER_FIRST; order <= SND_SOC_COMP_ORDER_LAST; - order++) { + for_each_comp_order(order) { for_each_card_rtds(card, rtd) { ret = soc_probe_link_dais(card, rtd, order); if (ret < 0) { From d2e24d64652bf9d272e5496ae8a562bc64facff3 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Tue, 18 Sep 2018 01:30:54 +0000 Subject: [PATCH 176/299] ASoC: add for_each_dpcm_fe() macro To be more readable code, this patch adds new for_each_dpcm_fe() macro, and replace existing code to it. Signed-off-by: Kuninori Morimoto Signed-off-by: Mark Brown --- include/sound/soc-dpcm.h | 3 +++ sound/soc/soc-pcm.c | 6 +++--- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/include/sound/soc-dpcm.h b/include/sound/soc-dpcm.h index 9bb92f187af8..f130de6cfe8e 100644 --- a/include/sound/soc-dpcm.h +++ b/include/sound/soc-dpcm.h @@ -103,6 +103,9 @@ struct snd_soc_dpcm_runtime { int trigger_pending; /* trigger cmd + 1 if pending, 0 if not */ }; +#define for_each_dpcm_fe(be, stream, dpcm) \ + list_for_each_entry(dpcm, &(be)->dpcm[stream].fe_clients, list_fe) + /* can this BE stop and free */ int snd_soc_dpcm_can_be_free_stop(struct snd_soc_pcm_runtime *fe, struct snd_soc_pcm_runtime *be, int stream); diff --git a/sound/soc/soc-pcm.c b/sound/soc/soc-pcm.c index 09d0f668c78e..e7916630e6fa 100644 --- a/sound/soc/soc-pcm.c +++ b/sound/soc/soc-pcm.c @@ -1252,7 +1252,7 @@ static void dpcm_be_reparent(struct snd_soc_pcm_runtime *fe, be_substream = snd_soc_dpcm_get_substream(be, stream); - list_for_each_entry(dpcm, &be->dpcm[stream].fe_clients, list_fe) { + for_each_dpcm_fe(be, stream, dpcm) { if (dpcm->fe == fe) continue; @@ -3219,7 +3219,7 @@ int snd_soc_dpcm_can_be_free_stop(struct snd_soc_pcm_runtime *fe, struct snd_soc_dpcm *dpcm; int state; - list_for_each_entry(dpcm, &be->dpcm[stream].fe_clients, list_fe) { + for_each_dpcm_fe(be, stream, dpcm) { if (dpcm->fe == fe) continue; @@ -3246,7 +3246,7 @@ int snd_soc_dpcm_can_be_params(struct snd_soc_pcm_runtime *fe, struct snd_soc_dpcm *dpcm; int state; - list_for_each_entry(dpcm, &be->dpcm[stream].fe_clients, list_fe) { + for_each_dpcm_fe(be, stream, dpcm) { if (dpcm->fe == fe) continue; From 8d6258a4dd267838e2f10643c3d91b79fe75ef6e Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Tue, 18 Sep 2018 01:31:09 +0000 Subject: [PATCH 177/299] ASoC: add for_each_dpcm_be() macro To be more readable code, this patch adds new for_each_dpcm_be() macro, and replace existing code to it. Signed-off-by: Kuninori Morimoto Signed-off-by: Mark Brown --- include/sound/soc-dpcm.h | 7 ++++++ sound/soc/fsl/fsl_asrc_dma.c | 2 +- sound/soc/sh/rcar/ctu.c | 2 +- sound/soc/sh/rcar/src.c | 2 +- sound/soc/soc-compress.c | 4 +-- sound/soc/soc-pcm.c | 48 +++++++++++++++++------------------- 6 files changed, 35 insertions(+), 30 deletions(-) diff --git a/include/sound/soc-dpcm.h b/include/sound/soc-dpcm.h index f130de6cfe8e..4be3a2b7c106 100644 --- a/include/sound/soc-dpcm.h +++ b/include/sound/soc-dpcm.h @@ -106,6 +106,13 @@ struct snd_soc_dpcm_runtime { #define for_each_dpcm_fe(be, stream, dpcm) \ list_for_each_entry(dpcm, &(be)->dpcm[stream].fe_clients, list_fe) +#define for_each_dpcm_be(fe, stream, dpcm) \ + list_for_each_entry(dpcm, &(fe)->dpcm[stream].be_clients, list_be) +#define for_each_dpcm_be_safe(fe, stream, dpcm, _dpcm) \ + list_for_each_entry_safe(dpcm, _dpcm, &(fe)->dpcm[stream].be_clients, list_be) +#define for_each_dpcm_be_rollback(fe, stream, dpcm) \ + list_for_each_entry_continue_reverse(dpcm, &(fe)->dpcm[stream].be_clients, list_be) + /* can this BE stop and free */ int snd_soc_dpcm_can_be_free_stop(struct snd_soc_pcm_runtime *fe, struct snd_soc_pcm_runtime *be, int stream); diff --git a/sound/soc/fsl/fsl_asrc_dma.c b/sound/soc/fsl/fsl_asrc_dma.c index 1033ac6631b0..01052a0808b0 100644 --- a/sound/soc/fsl/fsl_asrc_dma.c +++ b/sound/soc/fsl/fsl_asrc_dma.c @@ -151,7 +151,7 @@ static int fsl_asrc_dma_hw_params(struct snd_pcm_substream *substream, int ret; /* Fetch the Back-End dma_data from DPCM */ - list_for_each_entry(dpcm, &rtd->dpcm[stream].be_clients, list_be) { + for_each_dpcm_be(rtd, stream, dpcm) { struct snd_soc_pcm_runtime *be = dpcm->be; struct snd_pcm_substream *substream_be; struct snd_soc_dai *dai = be->cpu_dai; diff --git a/sound/soc/sh/rcar/ctu.c b/sound/soc/sh/rcar/ctu.c index 6a55aa753003..ad702377a6c3 100644 --- a/sound/soc/sh/rcar/ctu.c +++ b/sound/soc/sh/rcar/ctu.c @@ -258,7 +258,7 @@ static int rsnd_ctu_hw_params(struct rsnd_mod *mod, struct snd_pcm_hw_params *be_params; int stream = substream->stream; - list_for_each_entry(dpcm, &fe->dpcm[stream].be_clients, list_be) { + for_each_dpcm_be(fe, stream, dpcm) { be_params = &dpcm->hw_params; if (params_channels(fe_params) != params_channels(be_params)) ctu->channels = params_channels(be_params); diff --git a/sound/soc/sh/rcar/src.c b/sound/soc/sh/rcar/src.c index beccfbac7581..cd38a43b976f 100644 --- a/sound/soc/sh/rcar/src.c +++ b/sound/soc/sh/rcar/src.c @@ -158,7 +158,7 @@ static int rsnd_src_hw_params(struct rsnd_mod *mod, struct snd_soc_dpcm *dpcm; struct snd_pcm_hw_params *be_params; - list_for_each_entry(dpcm, &fe->dpcm[stream].be_clients, list_be) { + for_each_dpcm_be(fe, stream, dpcm) { be_params = &dpcm->hw_params; if (params_rate(fe_params) != params_rate(be_params)) diff --git a/sound/soc/soc-compress.c b/sound/soc/soc-compress.c index 409d082e80d1..699397a09167 100644 --- a/sound/soc/soc-compress.c +++ b/sound/soc/soc-compress.c @@ -157,7 +157,7 @@ static int soc_compr_open_fe(struct snd_compr_stream *cstream) ret = dpcm_be_dai_startup(fe, stream); if (ret < 0) { /* clean up all links */ - list_for_each_entry(dpcm, &fe->dpcm[stream].be_clients, list_be) + for_each_dpcm_be(fe, stream, dpcm) dpcm->state = SND_SOC_DPCM_LINK_STATE_FREE; dpcm_be_disconnect(fe, stream); @@ -321,7 +321,7 @@ static int soc_compr_free_fe(struct snd_compr_stream *cstream) ret = dpcm_be_dai_shutdown(fe, stream); /* mark FE's links ready to prune */ - list_for_each_entry(dpcm, &fe->dpcm[stream].be_clients, list_be) + for_each_dpcm_be(fe, stream, dpcm) dpcm->state = SND_SOC_DPCM_LINK_STATE_FREE; dpcm_dapm_stream_event(fe, stream, SND_SOC_DAPM_STREAM_STOP); diff --git a/sound/soc/soc-pcm.c b/sound/soc/soc-pcm.c index e7916630e6fa..03f36e534050 100644 --- a/sound/soc/soc-pcm.c +++ b/sound/soc/soc-pcm.c @@ -174,7 +174,7 @@ int dpcm_dapm_stream_event(struct snd_soc_pcm_runtime *fe, int dir, { struct snd_soc_dpcm *dpcm; - list_for_each_entry(dpcm, &fe->dpcm[dir].be_clients, list_be) { + for_each_dpcm_be(fe, dir, dpcm) { struct snd_soc_pcm_runtime *be = dpcm->be; @@ -1211,7 +1211,7 @@ static int dpcm_be_connect(struct snd_soc_pcm_runtime *fe, struct snd_soc_dpcm *dpcm; /* only add new dpcms */ - list_for_each_entry(dpcm, &fe->dpcm[stream].be_clients, list_be) { + for_each_dpcm_be(fe, stream, dpcm) { if (dpcm->be == be && dpcm->fe == fe) return 0; } @@ -1272,7 +1272,7 @@ void dpcm_be_disconnect(struct snd_soc_pcm_runtime *fe, int stream) { struct snd_soc_dpcm *dpcm, *d; - list_for_each_entry_safe(dpcm, d, &fe->dpcm[stream].be_clients, list_be) { + for_each_dpcm_be_safe(fe, stream, dpcm, d) { dev_dbg(fe->dev, "ASoC: BE %s disconnect check for %s\n", stream ? "capture" : "playback", dpcm->be->dai_link->name); @@ -1438,7 +1438,7 @@ static int dpcm_prune_paths(struct snd_soc_pcm_runtime *fe, int stream, int prune = 0; /* Destroy any old FE <--> BE connections */ - list_for_each_entry(dpcm, &fe->dpcm[stream].be_clients, list_be) { + for_each_dpcm_be(fe, stream, dpcm) { unsigned int i; /* is there a valid CPU DAI widget for this BE */ @@ -1544,7 +1544,7 @@ void dpcm_clear_pending_state(struct snd_soc_pcm_runtime *fe, int stream) { struct snd_soc_dpcm *dpcm; - list_for_each_entry(dpcm, &fe->dpcm[stream].be_clients, list_be) + for_each_dpcm_be(fe, stream, dpcm) dpcm->be->dpcm[stream].runtime_update = SND_SOC_DPCM_UPDATE_NO; } @@ -1555,7 +1555,7 @@ static void dpcm_be_dai_startup_unwind(struct snd_soc_pcm_runtime *fe, struct snd_soc_dpcm *dpcm; /* disable any enabled and non active backends */ - list_for_each_entry(dpcm, &fe->dpcm[stream].be_clients, list_be) { + for_each_dpcm_be(fe, stream, dpcm) { struct snd_soc_pcm_runtime *be = dpcm->be; struct snd_pcm_substream *be_substream = @@ -1584,7 +1584,7 @@ int dpcm_be_dai_startup(struct snd_soc_pcm_runtime *fe, int stream) int err, count = 0; /* only startup BE DAIs that are either sinks or sources to this FE DAI */ - list_for_each_entry(dpcm, &fe->dpcm[stream].be_clients, list_be) { + for_each_dpcm_be(fe, stream, dpcm) { struct snd_soc_pcm_runtime *be = dpcm->be; struct snd_pcm_substream *be_substream = @@ -1638,7 +1638,7 @@ int dpcm_be_dai_startup(struct snd_soc_pcm_runtime *fe, int stream) unwind: /* disable any enabled and non active backends */ - list_for_each_entry_continue_reverse(dpcm, &fe->dpcm[stream].be_clients, list_be) { + for_each_dpcm_be_rollback(fe, stream, dpcm) { struct snd_soc_pcm_runtime *be = dpcm->be; struct snd_pcm_substream *be_substream = snd_soc_dpcm_get_substream(be, stream); @@ -1695,7 +1695,7 @@ static void dpcm_runtime_merge_format(struct snd_pcm_substream *substream, * if FE want to use it (= dpcm_merged_format) */ - list_for_each_entry(dpcm, &fe->dpcm[stream].be_clients, list_be) { + for_each_dpcm_be(fe, stream, dpcm) { struct snd_soc_pcm_runtime *be = dpcm->be; struct snd_soc_dai_driver *codec_dai_drv; struct snd_soc_pcm_stream *codec_stream; @@ -1736,7 +1736,7 @@ static void dpcm_runtime_merge_chan(struct snd_pcm_substream *substream, * if FE want to use it (= dpcm_merged_chan) */ - list_for_each_entry(dpcm, &fe->dpcm[stream].be_clients, list_be) { + for_each_dpcm_be(fe, stream, dpcm) { struct snd_soc_pcm_runtime *be = dpcm->be; struct snd_soc_dai_driver *cpu_dai_drv = be->cpu_dai->driver; struct snd_soc_dai_driver *codec_dai_drv; @@ -1788,7 +1788,7 @@ static void dpcm_runtime_merge_rate(struct snd_pcm_substream *substream, * if FE want to use it (= dpcm_merged_chan) */ - list_for_each_entry(dpcm, &fe->dpcm[stream].be_clients, list_be) { + for_each_dpcm_be(fe, stream, dpcm) { struct snd_soc_pcm_runtime *be = dpcm->be; struct snd_soc_dai_driver *cpu_dai_drv = be->cpu_dai->driver; struct snd_soc_dai_driver *codec_dai_drv; @@ -1891,7 +1891,7 @@ static int dpcm_apply_symmetry(struct snd_pcm_substream *fe_substream, } /* apply symmetry for BE */ - list_for_each_entry(dpcm, &fe->dpcm[stream].be_clients, list_be) { + for_each_dpcm_be(fe, stream, dpcm) { struct snd_soc_pcm_runtime *be = dpcm->be; struct snd_pcm_substream *be_substream = snd_soc_dpcm_get_substream(be, stream); @@ -1976,7 +1976,7 @@ int dpcm_be_dai_shutdown(struct snd_soc_pcm_runtime *fe, int stream) struct snd_soc_dpcm *dpcm; /* only shutdown BEs that are either sinks or sources to this FE DAI */ - list_for_each_entry(dpcm, &fe->dpcm[stream].be_clients, list_be) { + for_each_dpcm_be(fe, stream, dpcm) { struct snd_soc_pcm_runtime *be = dpcm->be; struct snd_pcm_substream *be_substream = @@ -2040,7 +2040,7 @@ int dpcm_be_dai_hw_free(struct snd_soc_pcm_runtime *fe, int stream) /* only hw_params backends that are either sinks or sources * to this frontend DAI */ - list_for_each_entry(dpcm, &fe->dpcm[stream].be_clients, list_be) { + for_each_dpcm_be(fe, stream, dpcm) { struct snd_soc_pcm_runtime *be = dpcm->be; struct snd_pcm_substream *be_substream = @@ -2109,7 +2109,7 @@ int dpcm_be_dai_hw_params(struct snd_soc_pcm_runtime *fe, int stream) struct snd_soc_dpcm *dpcm; int ret; - list_for_each_entry(dpcm, &fe->dpcm[stream].be_clients, list_be) { + for_each_dpcm_be(fe, stream, dpcm) { struct snd_soc_pcm_runtime *be = dpcm->be; struct snd_pcm_substream *be_substream = @@ -2160,7 +2160,7 @@ int dpcm_be_dai_hw_params(struct snd_soc_pcm_runtime *fe, int stream) unwind: /* disable any enabled and non active backends */ - list_for_each_entry_continue_reverse(dpcm, &fe->dpcm[stream].be_clients, list_be) { + for_each_dpcm_be_rollback(fe, stream, dpcm) { struct snd_soc_pcm_runtime *be = dpcm->be; struct snd_pcm_substream *be_substream = snd_soc_dpcm_get_substream(be, stream); @@ -2240,7 +2240,7 @@ int dpcm_be_dai_trigger(struct snd_soc_pcm_runtime *fe, int stream, struct snd_soc_dpcm *dpcm; int ret = 0; - list_for_each_entry(dpcm, &fe->dpcm[stream].be_clients, list_be) { + for_each_dpcm_be(fe, stream, dpcm) { struct snd_soc_pcm_runtime *be = dpcm->be; struct snd_pcm_substream *be_substream = @@ -2426,7 +2426,7 @@ int dpcm_be_dai_prepare(struct snd_soc_pcm_runtime *fe, int stream) struct snd_soc_dpcm *dpcm; int ret = 0; - list_for_each_entry(dpcm, &fe->dpcm[stream].be_clients, list_be) { + for_each_dpcm_be(fe, stream, dpcm) { struct snd_soc_pcm_runtime *be = dpcm->be; struct snd_pcm_substream *be_substream = @@ -2636,7 +2636,7 @@ close: dpcm_be_dai_shutdown(fe, stream); disconnect: /* disconnect any non started BEs */ - list_for_each_entry(dpcm, &fe->dpcm[stream].be_clients, list_be) { + for_each_dpcm_be(fe, stream, dpcm) { struct snd_soc_pcm_runtime *be = dpcm->be; if (be->dpcm[stream].state != SND_SOC_DPCM_STATE_START) dpcm->state = SND_SOC_DPCM_LINK_STATE_FREE; @@ -2781,11 +2781,9 @@ out: int soc_dpcm_be_digital_mute(struct snd_soc_pcm_runtime *fe, int mute) { struct snd_soc_dpcm *dpcm; - struct list_head *clients = - &fe->dpcm[SNDRV_PCM_STREAM_PLAYBACK].be_clients; struct snd_soc_dai *dai; - list_for_each_entry(dpcm, clients, list_be) { + for_each_dpcm_be(fe, SNDRV_PCM_STREAM_PLAYBACK, dpcm) { struct snd_soc_pcm_runtime *be = dpcm->be; int i; @@ -2834,7 +2832,7 @@ static int dpcm_fe_dai_open(struct snd_pcm_substream *fe_substream) ret = dpcm_fe_dai_startup(fe_substream); if (ret < 0) { /* clean up all links */ - list_for_each_entry(dpcm, &fe->dpcm[stream].be_clients, list_be) + for_each_dpcm_be(fe, stream, dpcm) dpcm->state = SND_SOC_DPCM_LINK_STATE_FREE; dpcm_be_disconnect(fe, stream); @@ -2857,7 +2855,7 @@ static int dpcm_fe_dai_close(struct snd_pcm_substream *fe_substream) ret = dpcm_fe_dai_shutdown(fe_substream); /* mark FE's links ready to prune */ - list_for_each_entry(dpcm, &fe->dpcm[stream].be_clients, list_be) + for_each_dpcm_be(fe, stream, dpcm) dpcm->state = SND_SOC_DPCM_LINK_STATE_FREE; dpcm_be_disconnect(fe, stream); @@ -3326,7 +3324,7 @@ static ssize_t dpcm_show_state(struct snd_soc_pcm_runtime *fe, goto out; } - list_for_each_entry(dpcm, &fe->dpcm[stream].be_clients, list_be) { + for_each_dpcm_be(fe, stream, dpcm) { struct snd_soc_pcm_runtime *be = dpcm->be; params = &dpcm->hw_params; From fc795bf7224efda8c35e505966c2757856064247 Mon Sep 17 00:00:00 2001 From: Oder Chiou Date: Wed, 19 Sep 2018 09:56:47 +0800 Subject: [PATCH 178/299] ASoC: rt5663: Remove the boost volume in the beginning of playback The patch removes the boost volume in the beginning of playback while the DAC volume set to lower. Signed-off-by: Oder Chiou Signed-off-by: Mark Brown --- sound/soc/codecs/rt5663.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/sound/soc/codecs/rt5663.c b/sound/soc/codecs/rt5663.c index 9bd24ad42240..2444fad7c2df 100644 --- a/sound/soc/codecs/rt5663.c +++ b/sound/soc/codecs/rt5663.c @@ -72,6 +72,7 @@ struct rt5663_priv { static const struct reg_sequence rt5663_patch_list[] = { { 0x002a, 0x8020 }, { 0x0086, 0x0028 }, + { 0x0100, 0xa020 }, { 0x0117, 0x0f28 }, { 0x02fb, 0x8089 }, }; @@ -580,7 +581,7 @@ static const struct reg_default rt5663_reg[] = { { 0x00fd, 0x0001 }, { 0x00fe, 0x10ec }, { 0x00ff, 0x6406 }, - { 0x0100, 0xa0a0 }, + { 0x0100, 0xa020 }, { 0x0108, 0x4444 }, { 0x0109, 0x4444 }, { 0x010a, 0xaaaa }, @@ -2337,6 +2338,8 @@ static int rt5663_hp_event(struct snd_soc_dapm_widget *w, 0x8000); snd_soc_component_update_bits(component, RT5663_DEPOP_1, 0x3000, 0x3000); + snd_soc_component_update_bits(component, + RT5663_DIG_VOL_ZCD, 0x00c0, 0x0080); } break; @@ -2351,6 +2354,8 @@ static int rt5663_hp_event(struct snd_soc_dapm_widget *w, RT5663_OVCD_HP_MASK, RT5663_OVCD_HP_EN); snd_soc_component_update_bits(component, RT5663_DACREF_LDO, 0x3e0e, 0); + snd_soc_component_update_bits(component, + RT5663_DIG_VOL_ZCD, 0x00c0, 0); } break; From 0310820c2738e92003d9dd8cabee77ff958a16dc Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Fri, 21 Sep 2018 07:46:28 +0000 Subject: [PATCH 179/299] ASoC: tidyup for_each_card_prelinks() dai_link commit 7fe072b4df5d0 ("ASoC: add for_each_card_prelinks() macro") added new for_each_card_prelinks() macro, but it had typo. This patch fixup it Signed-off-by: Kuninori Morimoto Signed-off-by: Mark Brown --- sound/soc/mediatek/mt2701/mt2701-cs42448.c | 8 ++++---- sound/soc/mediatek/mt2701/mt2701-wm8960.c | 8 ++++---- sound/soc/mediatek/mt6797/mt6797-mt6351.c | 6 +++--- 3 files changed, 11 insertions(+), 11 deletions(-) diff --git a/sound/soc/mediatek/mt2701/mt2701-cs42448.c b/sound/soc/mediatek/mt2701/mt2701-cs42448.c index 875f84691535..97f9f38ce6b3 100644 --- a/sound/soc/mediatek/mt2701/mt2701-cs42448.c +++ b/sound/soc/mediatek/mt2701/mt2701-cs42448.c @@ -311,9 +311,9 @@ static int mt2701_cs42448_machine_probe(struct platform_device *pdev) return -EINVAL; } for_each_card_prelinks(card, i, dai_link) { - if (dai_links->platform_name) + if (dai_link->platform_name) continue; - dai_links->platform_of_node = platform_node; + dai_link->platform_of_node = platform_node; } card->dev = dev; @@ -326,9 +326,9 @@ static int mt2701_cs42448_machine_probe(struct platform_device *pdev) return -EINVAL; } for_each_card_prelinks(card, i, dai_link) { - if (dai_links->codec_name) + if (dai_link->codec_name) continue; - dai_links->codec_of_node = codec_node; + dai_link->codec_of_node = codec_node; } codec_node_bt_mrg = of_parse_phandle(pdev->dev.of_node, diff --git a/sound/soc/mediatek/mt2701/mt2701-wm8960.c b/sound/soc/mediatek/mt2701/mt2701-wm8960.c index c67f62935e53..6bc1d3d58e64 100644 --- a/sound/soc/mediatek/mt2701/mt2701-wm8960.c +++ b/sound/soc/mediatek/mt2701/mt2701-wm8960.c @@ -107,9 +107,9 @@ static int mt2701_wm8960_machine_probe(struct platform_device *pdev) return -EINVAL; } for_each_card_prelinks(card, i, dai_link) { - if (dai_links->platform_name) + if (dai_link->platform_name) continue; - dai_links->platform_of_node = platform_node; + dai_link->platform_of_node = platform_node; } card->dev = &pdev->dev; @@ -122,9 +122,9 @@ static int mt2701_wm8960_machine_probe(struct platform_device *pdev) return -EINVAL; } for_each_card_prelinks(card, i, dai_link) { - if (dai_links->codec_name) + if (dai_link->codec_name) continue; - dai_links->codec_of_node = codec_node; + dai_link->codec_of_node = codec_node; } ret = snd_soc_of_parse_audio_routing(card, "audio-routing"); diff --git a/sound/soc/mediatek/mt6797/mt6797-mt6351.c b/sound/soc/mediatek/mt6797/mt6797-mt6351.c index ff2e0ca4384e..cc41eb531653 100644 --- a/sound/soc/mediatek/mt6797/mt6797-mt6351.c +++ b/sound/soc/mediatek/mt6797/mt6797-mt6351.c @@ -172,7 +172,7 @@ static int mt6797_mt6351_dev_probe(struct platform_device *pdev) for_each_card_prelinks(card, i, dai_link) { if (dai_link->platform_name) continue; - dai_links->platform_of_node = platform_node; + dai_link->platform_of_node = platform_node; } codec_node = of_parse_phandle(pdev->dev.of_node, @@ -183,9 +183,9 @@ static int mt6797_mt6351_dev_probe(struct platform_device *pdev) return -EINVAL; } for_each_card_prelinks(card, i, dai_link) { - if (dai_links->codec_name) + if (dai_link->codec_name) continue; - dai_links->codec_of_node = codec_node; + dai_link->codec_of_node = codec_node; } ret = devm_snd_soc_register_card(&pdev->dev, card); From c78d42c7fbd6f2a27a665bcd1ab60c9df617f7c9 Mon Sep 17 00:00:00 2001 From: zhong jiang Date: Fri, 21 Sep 2018 18:24:58 +0800 Subject: [PATCH 180/299] ASoC: qcom: qdsp6: remove duplicated include from q6adm.c We include wait.h twice in q6adm.c. it is unnecessary. hence remove it. Further, order the include files as alphabet. Signed-off-by: zhong jiang Signed-off-by: Mark Brown --- sound/soc/qcom/qdsp6/q6adm.c | 17 ++++++++--------- 1 file changed, 8 insertions(+), 9 deletions(-) diff --git a/sound/soc/qcom/qdsp6/q6adm.c b/sound/soc/qcom/qdsp6/q6adm.c index 932c3ebfd252..da242515e146 100644 --- a/sound/soc/qcom/qdsp6/q6adm.c +++ b/sound/soc/qcom/qdsp6/q6adm.c @@ -2,25 +2,24 @@ // Copyright (c) 2011-2017, The Linux Foundation. All rights reserved. // Copyright (c) 2018, Linaro Limited -#include -#include -#include #include -#include -#include #include +#include +#include +#include #include #include -#include -#include -#include #include +#include +#include +#include +#include #include #include "q6adm.h" #include "q6afe.h" #include "q6core.h" -#include "q6dsp-errno.h" #include "q6dsp-common.h" +#include "q6dsp-errno.h" #define ADM_CMD_DEVICE_OPEN_V5 0x00010326 #define ADM_CMDRSP_DEVICE_OPEN_V5 0x00010329 From 624d1a7cd8991e33dad96ab4629a52c412540e65 Mon Sep 17 00:00:00 2001 From: Dmytro Prokopchuk Date: Fri, 21 Sep 2018 04:59:59 +0000 Subject: [PATCH 181/299] ASoC: rsnd: fixup SSI clock during suspend/resume modes Prepare <-> Cleanup functions pair has balanced calls. But in case of suspend mode no call to rsnd_soc_dai_shutdown() function, so cleanup isn't called. OTOH during resume mode function rsnd_soc_dai_prepare() is called, but calling rsnd_ssi_prepare() is skipped (rsnd_status_update() returns zero, bacause was not cleanup before). We need to call rsnd_ssi_prepare(), because it enables SSI clocks by calling rsnd_ssi_master_clk_start(). This patch allows to call prepare/cleanup functions always. Signed-off-by: Dmytro Prokopchuk Tested-by: Hiroyuki Yokoyama [kuninori: adjusted to upstream] Signed-off-by: Kuninori Morimoto Signed-off-by: Mark Brown --- sound/soc/sh/rcar/dma.c | 7 +++---- sound/soc/sh/rcar/rsnd.h | 14 +++++++------- 2 files changed, 10 insertions(+), 11 deletions(-) diff --git a/sound/soc/sh/rcar/dma.c b/sound/soc/sh/rcar/dma.c index 0bbc4b0ea2c6..6d1947515dc8 100644 --- a/sound/soc/sh/rcar/dma.c +++ b/sound/soc/sh/rcar/dma.c @@ -134,10 +134,9 @@ static int rsnd_dmaen_prepare(struct rsnd_mod *mod, struct rsnd_dmaen *dmaen = rsnd_dma_to_dmaen(dma); struct device *dev = rsnd_priv_to_dev(priv); - if (dmaen->chan) { - dev_err(dev, "it already has dma channel\n"); - return -EIO; - } + /* maybe suspended */ + if (dmaen->chan) + return 0; /* * DMAEngine request uses mutex lock. diff --git a/sound/soc/sh/rcar/rsnd.h b/sound/soc/sh/rcar/rsnd.h index e857311ee5c1..4464d1d0a042 100644 --- a/sound/soc/sh/rcar/rsnd.h +++ b/sound/soc/sh/rcar/rsnd.h @@ -318,9 +318,8 @@ struct rsnd_mod { /* * status * - * 0xH0000CBA + * 0xH0000CB0 * - * A 0: prepare 1: cleanup * B 0: init 1: quit * C 0: start 1: stop * @@ -331,9 +330,8 @@ struct rsnd_mod { * H 0: hw_params * H 0: pointer * H 0: prepare + * H 0: cleanup */ -#define __rsnd_mod_shift_prepare 0 -#define __rsnd_mod_shift_cleanup 0 #define __rsnd_mod_shift_init 4 #define __rsnd_mod_shift_quit 4 #define __rsnd_mod_shift_start 8 @@ -345,11 +343,13 @@ struct rsnd_mod { #define __rsnd_mod_shift_fallback 28 /* always called */ #define __rsnd_mod_shift_hw_params 28 /* always called */ #define __rsnd_mod_shift_pointer 28 /* always called */ +#define __rsnd_mod_shift_prepare 28 /* always called */ +#define __rsnd_mod_shift_cleanup 28 /* always called */ #define __rsnd_mod_add_probe 0 #define __rsnd_mod_add_remove 0 -#define __rsnd_mod_add_prepare 1 -#define __rsnd_mod_add_cleanup -1 +#define __rsnd_mod_add_prepare 0 +#define __rsnd_mod_add_cleanup 0 #define __rsnd_mod_add_init 1 #define __rsnd_mod_add_quit -1 #define __rsnd_mod_add_start 1 @@ -363,7 +363,7 @@ struct rsnd_mod { #define __rsnd_mod_call_probe 0 #define __rsnd_mod_call_remove 0 #define __rsnd_mod_call_prepare 0 -#define __rsnd_mod_call_cleanup 1 +#define __rsnd_mod_call_cleanup 0 #define __rsnd_mod_call_init 0 #define __rsnd_mod_call_quit 1 #define __rsnd_mod_call_start 0 From 368dee9459472b44f760a35cd07a6f3b90b3e549 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Fri, 21 Sep 2018 05:23:01 +0000 Subject: [PATCH 182/299] ASoC: add for_each_component() macro To be more readable code, this patch adds new for_each_component() macro, and replace existing code to it. Signed-off-by: Kuninori Morimoto Signed-off-by: Mark Brown --- sound/soc/soc-core.c | 24 ++++++++++++++---------- 1 file changed, 14 insertions(+), 10 deletions(-) diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c index d8625ac2b201..b9b33c8cac2e 100644 --- a/sound/soc/soc-core.c +++ b/sound/soc/soc-core.c @@ -54,6 +54,9 @@ static DEFINE_MUTEX(client_mutex); static LIST_HEAD(component_list); static LIST_HEAD(unbind_card_list); +#define for_each_component(component) \ + list_for_each_entry(component, &component_list, list) + /* * This is a timeout to do a DAPM powerdown after a stream is closed(). * It can be used to eliminate pops between different playback streams, e.g. @@ -176,7 +179,7 @@ static int dai_list_show(struct seq_file *m, void *v) mutex_lock(&client_mutex); - list_for_each_entry(component, &component_list, list) + for_each_component(component) list_for_each_entry(dai, &component->dai_list, list) seq_printf(m, "%s\n", dai->name); @@ -192,7 +195,7 @@ static int component_list_show(struct seq_file *m, void *v) mutex_lock(&client_mutex); - list_for_each_entry(component, &component_list, list) + for_each_component(component) seq_printf(m, "%s\n", component->name); mutex_unlock(&client_mutex); @@ -725,7 +728,7 @@ static struct snd_soc_component *soc_find_component( lockdep_assert_held(&client_mutex); - list_for_each_entry(component, &component_list, list) { + for_each_component(component) { if (of_node) { if (component->dev->of_node == of_node) return component; @@ -775,7 +778,7 @@ struct snd_soc_dai *snd_soc_find_dai( lockdep_assert_held(&client_mutex); /* Find CPU DAI from registered DAIs*/ - list_for_each_entry(component, &component_list, list) { + for_each_component(component) { if (!snd_soc_is_matching_component(dlc, component)) continue; list_for_each_entry(dai, &component->dai_list, list) { @@ -902,7 +905,7 @@ static int soc_bind_dai_link(struct snd_soc_card *card, rtd->codec_dai = codec_dais[0]; /* find one from the set of registered platforms */ - list_for_each_entry(component, &component_list, list) { + for_each_component(component) { if (!snd_soc_is_matching_component(dai_link->platform, component)) continue; @@ -1874,7 +1877,7 @@ static void soc_check_tplg_fes(struct snd_soc_card *card) struct snd_soc_dai_link *dai_link; int i; - list_for_each_entry(component, &component_list, list) { + for_each_component(component) { /* does this component override FEs ? */ if (!component->driver->ignore_machine) @@ -3091,6 +3094,7 @@ static void snd_soc_component_add(struct snd_soc_component *component) snd_soc_component_setup_regmap(component); } + /* see for_each_component */ list_add(&component->list, &component_list); INIT_LIST_HEAD(&component->dobj_list); @@ -3226,7 +3230,7 @@ static int __snd_soc_unregister_component(struct device *dev) int found = 0; mutex_lock(&client_mutex); - list_for_each_entry(component, &component_list, list) { + for_each_component(component) { if (dev != component->dev) continue; @@ -3258,7 +3262,7 @@ struct snd_soc_component *snd_soc_lookup_component(struct device *dev, ret = NULL; mutex_lock(&client_mutex); - list_for_each_entry(component, &component_list, list) { + for_each_component(component) { if (dev != component->dev) continue; @@ -3658,7 +3662,7 @@ int snd_soc_get_dai_id(struct device_node *ep) */ ret = -ENOTSUPP; mutex_lock(&client_mutex); - list_for_each_entry(pos, &component_list, list) { + for_each_component(pos) { struct device_node *component_of_node = pos->dev->of_node; if (!component_of_node && pos->dev->parent) @@ -3688,7 +3692,7 @@ int snd_soc_get_dai_name(struct of_phandle_args *args, int ret = -EPROBE_DEFER; mutex_lock(&client_mutex); - list_for_each_entry(pos, &component_list, list) { + for_each_component(pos) { component_of_node = pos->dev->of_node; if (!component_of_node && pos->dev->parent) component_of_node = pos->dev->parent->of_node; From 15a0c64572463eddf59e80aa643d3a87809a7d9b Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Fri, 21 Sep 2018 05:23:17 +0000 Subject: [PATCH 183/299] ASoC: add for_each_component_dais() macro To be more readable code, this patch adds new for_each_component_dais() macro, and replace existing code to it. Signed-off-by: Kuninori Morimoto Signed-off-by: Mark Brown --- include/sound/soc.h | 5 +++++ sound/soc/soc-core.c | 11 ++++++----- 2 files changed, 11 insertions(+), 5 deletions(-) diff --git a/include/sound/soc.h b/include/sound/soc.h index 93aa894a57ef..f1dab1f4b194 100644 --- a/include/sound/soc.h +++ b/include/sound/soc.h @@ -864,6 +864,11 @@ struct snd_soc_component { #endif }; +#define for_each_component_dais(component, dai)\ + list_for_each_entry(dai, &(component)->dai_list, list) +#define for_each_component_dais_safe(component, dai, _dai)\ + list_for_each_entry_safe(dai, _dai, &(component)->dai_list, list) + struct snd_soc_rtdcom_list { struct snd_soc_component *component; struct list_head list; /* rtd::component_list */ diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c index b9b33c8cac2e..62e8e36062df 100644 --- a/sound/soc/soc-core.c +++ b/sound/soc/soc-core.c @@ -180,7 +180,7 @@ static int dai_list_show(struct seq_file *m, void *v) mutex_lock(&client_mutex); for_each_component(component) - list_for_each_entry(dai, &component->dai_list, list) + for_each_component_dais(component, dai) seq_printf(m, "%s\n", dai->name); mutex_unlock(&client_mutex); @@ -781,7 +781,7 @@ struct snd_soc_dai *snd_soc_find_dai( for_each_component(component) { if (!snd_soc_is_matching_component(dlc, component)) continue; - list_for_each_entry(dai, &component->dai_list, list) { + for_each_component_dais(component, dai) { if (dlc->dai_name && strcmp(dai->name, dlc->dai_name) && (!dai->driver->name || strcmp(dai->driver->name, dlc->dai_name))) @@ -1312,7 +1312,7 @@ static int soc_probe_component(struct snd_soc_card *card, } } - list_for_each_entry(dai, &component->dai_list, list) { + for_each_component_dais(component, dai) { ret = snd_soc_dapm_new_dai_widgets(dapm, dai); if (ret != 0) { dev_err(component->dev, @@ -2842,7 +2842,7 @@ static void snd_soc_unregister_dais(struct snd_soc_component *component) { struct snd_soc_dai *dai, *_dai; - list_for_each_entry_safe(dai, _dai, &component->dai_list, list) { + for_each_component_dais_safe(component, dai, _dai) { dev_dbg(component->dev, "ASoC: Unregistered DAI '%s'\n", dai->name); list_del(&dai->list); @@ -2894,6 +2894,7 @@ static struct snd_soc_dai *soc_add_dai(struct snd_soc_component *component, if (!dai->driver->ops) dai->driver->ops = &null_dai_ops; + /* see for_each_component_dais */ list_add_tail(&dai->list, &component->dai_list); component->num_dai++; @@ -3728,7 +3729,7 @@ int snd_soc_get_dai_name(struct of_phandle_args *args, ret = 0; /* find target DAI */ - list_for_each_entry(dai, &pos->dai_list, list) { + for_each_component_dais(pos, dai) { if (id == 0) break; id--; From b0ef5011b981ece1fde8063243a56d3038b87adb Mon Sep 17 00:00:00 2001 From: Matt Flax Date: Tue, 25 Sep 2018 16:40:18 +1000 Subject: [PATCH 184/299] ASoC: cs4265: Add a MIC pre. route The cs4265 driver is missing a microphone preamp enable. This patch enables/disables the microphone preamp when mic selection is made using the kcontrol. Signed-off-by: Matt Flax Reviewed-by: Charles Keepax Signed-off-by: Mark Brown --- sound/soc/codecs/cs4265.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/sound/soc/codecs/cs4265.c b/sound/soc/codecs/cs4265.c index d9eebf6af7a8..ab27d2b94d02 100644 --- a/sound/soc/codecs/cs4265.c +++ b/sound/soc/codecs/cs4265.c @@ -221,10 +221,11 @@ static const struct snd_soc_dapm_route cs4265_audio_map[] = { {"LINEOUTR", NULL, "DAC"}, {"SPDIFOUT", NULL, "SPDIF"}, + {"Pre-amp MIC", NULL, "MICL"}, + {"Pre-amp MIC", NULL, "MICR"}, + {"ADC Mux", "MIC", "Pre-amp MIC"}, {"ADC Mux", "LINEIN", "LINEINL"}, {"ADC Mux", "LINEIN", "LINEINR"}, - {"ADC Mux", "MIC", "MICL"}, - {"ADC Mux", "MIC", "MICR"}, {"ADC", NULL, "ADC Mux"}, {"DOUT", NULL, "ADC"}, {"DAI1 Capture", NULL, "DOUT"}, From 02a9fad843d5f86b5afe5e156f09ea87fe24d9c9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andreas=20F=C3=A4rber?= Date: Tue, 25 Sep 2018 16:23:48 +0200 Subject: [PATCH 185/299] ASoC: dt-bindings: add max98088 audio codec MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This patch adds the bindings for maxim max98088/9 audio codec. Signed-off-by: Andreas Färber [m.felsch@pengutronix.de: adapt commit message] [m.felsch@pengutronix.de: adapt formatting] Signed-off-by: Marco Felsch Signed-off-by: Mark Brown --- .../devicetree/bindings/sound/maxim,max98088.txt | 15 +++++++++++++++ 1 file changed, 15 insertions(+) create mode 100644 Documentation/devicetree/bindings/sound/maxim,max98088.txt diff --git a/Documentation/devicetree/bindings/sound/maxim,max98088.txt b/Documentation/devicetree/bindings/sound/maxim,max98088.txt new file mode 100644 index 000000000000..a79ad5c7af88 --- /dev/null +++ b/Documentation/devicetree/bindings/sound/maxim,max98088.txt @@ -0,0 +1,15 @@ +MAX98088 audio CODEC + +This device supports I2C only. + +Required properties: + +- compatible: "maxim,max98088" or "maxim,max98089". +- reg: The I2C address of the device. + +Example: + +max98089: codec@10 { + compatible = "maxim,max98089"; + reg = <0x10>; +}; From 85aa0fe73edd856365d074a5aa38c614c8b2ca45 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andreas=20F=C3=A4rber?= Date: Tue, 25 Sep 2018 16:23:49 +0200 Subject: [PATCH 186/299] ASoC: max98088: add OF support MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit MAX98088 is an older version of the MAX98089 device. Signed-off-by: Andreas Färber [m.felsch@pengutronix.de: add CONFIG_OF compile switch] [m.felsch@pengutronix.de: adapt commit message] Signed-off-by: Marco Felsch Signed-off-by: Mark Brown --- sound/soc/codecs/max98088.c | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/sound/soc/codecs/max98088.c b/sound/soc/codecs/max98088.c index fb515aaa54fc..9450d5d9c492 100644 --- a/sound/soc/codecs/max98088.c +++ b/sound/soc/codecs/max98088.c @@ -1742,9 +1742,19 @@ static const struct i2c_device_id max98088_i2c_id[] = { }; MODULE_DEVICE_TABLE(i2c, max98088_i2c_id); +#if defined(CONFIG_OF) +static const struct of_device_id max98088_of_match[] = { + { .compatible = "maxim,max98088" }, + { .compatible = "maxim,max98089" }, + { } +}; +MODULE_DEVICE_TABLE(of, max98088_of_match); +#endif + static struct i2c_driver max98088_i2c_driver = { .driver = { .name = "max98088", + .of_match_table = of_match_ptr(max98088_of_match), }, .probe = max98088_i2c_probe, .id_table = max98088_i2c_id, From 42cfb412e24ffbb46d6de9590293bc44f921a0fb Mon Sep 17 00:00:00 2001 From: Matthias Kaehlcke Date: Tue, 25 Sep 2018 11:09:14 -0700 Subject: [PATCH 187/299] ASoC: soc-utils: Rename dummy_dma_ops to snd_dummy_dma_ops The symbols 'dummy_dma_ops' is declared with different data types by sound/soc/soc-utils.c and arch/arm64/include/asm/dma-mapping.h. This leads to conflicts when soc-utils.c (indirectly) includes dma-mapping.h: sound/soc/soc-utils.c:282:33: error: conflicting types for 'dummy_dma_ops' static const struct snd_pcm_ops dummy_dma_ops = { ^ ... arch/arm64/include/asm/dma-mapping.h:27:33: note: previous declaration of 'dummy_dma_ops' was here extern const struct dma_map_ops dummy_dma_ops; ^ Rename the symbol in soc-utils.c to 'snd_dummy_dma_ops' to avoid the conflict. Signed-off-by: Matthias Kaehlcke Signed-off-by: Mark Brown --- sound/soc/soc-utils.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/sound/soc/soc-utils.c b/sound/soc/soc-utils.c index e0c93496c0cd..e3b9dd634c6d 100644 --- a/sound/soc/soc-utils.c +++ b/sound/soc/soc-utils.c @@ -273,13 +273,13 @@ static int dummy_dma_open(struct snd_pcm_substream *substream) return 0; } -static const struct snd_pcm_ops dummy_dma_ops = { +static const struct snd_pcm_ops snd_dummy_dma_ops = { .open = dummy_dma_open, .ioctl = snd_pcm_lib_ioctl, }; static const struct snd_soc_component_driver dummy_platform = { - .ops = &dummy_dma_ops, + .ops = &snd_dummy_dma_ops, }; static const struct snd_soc_component_driver dummy_codec = { From bec5ecdf41d404691980c9c82ba867113cc8dee5 Mon Sep 17 00:00:00 2001 From: Arnd Bergmann Date: Wed, 26 Sep 2018 14:46:35 +0200 Subject: [PATCH 188/299] ASoC: pxa: avoid AC97_BUS build warning Selecting AC97_BUS_NEW from SND_PXA2XX_SOC_AC97 leads to a Kconfig warning if any other driver selects AC97_BUS: WARNING: unmet direct dependencies detected for AC97_BUS_COMPAT Depends on [n]: SOUND [=y] && !UML && SND [=y] && AC97_BUS_NEW [=y] && !AC97_BUS [=y] Selected by [y]: - SND_SOC_WM9713 [=y] && SOUND [=y] && !UML && SND [=y] && SND_SOC [=y] && AC97_BUS_NEW [=y] I don't know if that combination is supposed to work. Assuming it is not, this adds a dependency on all users for PXA to avoids the combination. Fixes: 1c8bc7b3de5e ("ASoC: pxa: switch to new ac97 bus support") Signed-off-by: Arnd Bergmann Signed-off-by: Mark Brown --- sound/soc/pxa/Kconfig | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/sound/soc/pxa/Kconfig b/sound/soc/pxa/Kconfig index 29f577e6dfc0..943b44de1464 100644 --- a/sound/soc/pxa/Kconfig +++ b/sound/soc/pxa/Kconfig @@ -79,6 +79,7 @@ config SND_PXA2XX_SOC_TOSA tristate "SoC AC97 Audio support for Tosa" depends on SND_PXA2XX_SOC && MACH_TOSA depends on MFD_TC6393XB + depends on !AC97_BUS select SND_PXA2XX_SOC_AC97 select SND_SOC_WM9712 help @@ -88,6 +89,7 @@ config SND_PXA2XX_SOC_TOSA config SND_PXA2XX_SOC_E740 tristate "SoC AC97 Audio support for e740" depends on SND_PXA2XX_SOC && MACH_E740 + depends on !AC97_BUS select SND_SOC_WM9705 select SND_PXA2XX_SOC_AC97 help @@ -97,6 +99,7 @@ config SND_PXA2XX_SOC_E740 config SND_PXA2XX_SOC_E750 tristate "SoC AC97 Audio support for e750" depends on SND_PXA2XX_SOC && MACH_E750 + depends on !AC97_BUS select SND_SOC_WM9705 select SND_PXA2XX_SOC_AC97 help @@ -106,6 +109,7 @@ config SND_PXA2XX_SOC_E750 config SND_PXA2XX_SOC_E800 tristate "SoC AC97 Audio support for e800" depends on SND_PXA2XX_SOC && MACH_E800 + depends on !AC97_BUS select SND_SOC_WM9712 select SND_PXA2XX_SOC_AC97 help @@ -116,6 +120,7 @@ config SND_PXA2XX_SOC_EM_X270 tristate "SoC Audio support for CompuLab EM-x270, eXeda and CM-X300" depends on SND_PXA2XX_SOC && (MACH_EM_X270 || MACH_EXEDA || \ MACH_CM_X300) + depends on !AC97_BUS select SND_PXA2XX_SOC_AC97 select SND_SOC_WM9712 help @@ -126,6 +131,7 @@ config SND_PXA2XX_SOC_PALM27X bool "SoC Audio support for Palm T|X, T5, E2 and LifeDrive" depends on SND_PXA2XX_SOC && (MACH_PALMLD || MACH_PALMTX || \ MACH_PALMT5 || MACH_PALMTE2) + depends on !AC97_BUS select SND_PXA2XX_SOC_AC97 select SND_SOC_WM9712 help @@ -155,6 +161,7 @@ config SND_SOC_TTC_DKB config SND_SOC_ZYLONITE tristate "SoC Audio support for Marvell Zylonite" depends on SND_PXA2XX_SOC && MACH_ZYLONITE + depends on !AC97_BUS select SND_PXA2XX_SOC_AC97 select SND_PXA_SOC_SSP select SND_SOC_WM9713 @@ -194,6 +201,7 @@ config SND_PXA2XX_SOC_MAGICIAN config SND_PXA2XX_SOC_MIOA701 tristate "SoC Audio support for MIO A701" depends on SND_PXA2XX_SOC && MACH_MIOA701 + depends on !AC97_BUS select SND_PXA2XX_SOC_AC97 select SND_SOC_WM9713 help From 53c156ab9d8aae2083d3c895365a3e39b864a5a7 Mon Sep 17 00:00:00 2001 From: Arnd Bergmann Date: Wed, 26 Sep 2018 14:59:40 +0200 Subject: [PATCH 189/299] ASoC: atmel: add SND_SOC_I2C_AND_SPI dependency Selecting SND_SOC_WM8731 is only allowed when all its dependencies are already there: WARNING: unmet direct dependencies detected for SND_SOC_WM8731 Depends on [m]: SOUND [=y] && !UML && SND [=y] && SND_SOC [=y] && SND_SOC_I2C_AND_SPI [=m] Selected by [y]: - SND_SOC_MIKROE_PROTO [=y] && SOUND [=y] && !UML && SND [=y] && SND_SOC [=y] && SND_ATMEL_SOC [=y] && OF [=y] Selected by [m]: - SND_AT91_SOC_SAM9X5_WM8731 [=m] && SOUND [=y] && !UML && SND [=y] && SND_SOC [=y] && SND_ATMEL_SOC [=y] && (ARCH_AT91 [=y] || COMPILE_TEST [=y]) && ATMEL_SSC [=y] && SND_SOC_I2C_AND_SPI [=m] - SND_SOC_ALL_CODECS [=m] && SOUND [=y] && !UML && SND [=y] && SND_SOC [=y] && COMPILE_TEST [=y] && SND_SOC_I2C_AND_SPI [=m] Fixes: a45f8853a5f9 ("ASoC: Add driver for PROTO Audio CODEC (with a WM8731)") Signed-off-by: Arnd Bergmann Reviewed-by: Codrin Ciubotariu Signed-off-by: Mark Brown --- sound/soc/atmel/Kconfig | 1 + 1 file changed, 1 insertion(+) diff --git a/sound/soc/atmel/Kconfig b/sound/soc/atmel/Kconfig index 81a0712d4f14..64f86f0b87e5 100644 --- a/sound/soc/atmel/Kconfig +++ b/sound/soc/atmel/Kconfig @@ -101,6 +101,7 @@ config SND_ATMEL_SOC_I2S config SND_SOC_MIKROE_PROTO tristate "Support for Mikroe-PROTO board" depends on OF + depends on SND_SOC_I2C_AND_SPI select SND_SOC_WM8731 help Say Y or M if you want to add support for MikroElektronika PROTO Audio From 18380dcc52cc8965e5144ce33fdfad7e168679a5 Mon Sep 17 00:00:00 2001 From: Arnd Bergmann Date: Wed, 26 Sep 2018 21:37:40 +0200 Subject: [PATCH 190/299] ASoC: wm9712: fix unused variable warning The 'ret' variable is now only used in an #ifdef, and causes a warning if it is declared outside of that block: sound/soc/codecs/wm9712.c: In function 'wm9712_soc_probe': sound/soc/codecs/wm9712.c:641:6: error: unused variable 'ret' [-Werror=unused-variable] Fixes: 2ed1a8e0ce8d ("ASoC: wm9712: add ac97 new bus support") Signed-off-by: Arnd Bergmann Acked-by: Charles Keepax Signed-off-by: Mark Brown --- sound/soc/codecs/wm9712.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/sound/soc/codecs/wm9712.c b/sound/soc/codecs/wm9712.c index ade34c26ad2f..e873baa9e778 100644 --- a/sound/soc/codecs/wm9712.c +++ b/sound/soc/codecs/wm9712.c @@ -638,13 +638,14 @@ static int wm9712_soc_probe(struct snd_soc_component *component) { struct wm9712_priv *wm9712 = snd_soc_component_get_drvdata(component); struct regmap *regmap; - int ret; if (wm9712->mfd_pdata) { wm9712->ac97 = wm9712->mfd_pdata->ac97; regmap = wm9712->mfd_pdata->regmap; } else { #ifdef CONFIG_SND_SOC_AC97_BUS + int ret; + wm9712->ac97 = snd_soc_new_ac97_component(component, WM9712_VENDOR_ID, WM9712_VENDOR_ID_MASK); if (IS_ERR(wm9712->ac97)) { From 765f50d464457c6a397506b3f3dc58dacc227c6d Mon Sep 17 00:00:00 2001 From: Biju Das Date: Thu, 27 Sep 2018 14:51:25 +0100 Subject: [PATCH 191/299] ASoC: rsnd: Add r8a7744 support Document RZ/G1N (R8A7744) SoC bindings. Signed-off-by: Biju Das Reviewed-by: Chris Paterson Signed-off-by: Mark Brown --- Documentation/devicetree/bindings/sound/renesas,rsnd.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/Documentation/devicetree/bindings/sound/renesas,rsnd.txt b/Documentation/devicetree/bindings/sound/renesas,rsnd.txt index f4688c508be6..d92b705e7917 100644 --- a/Documentation/devicetree/bindings/sound/renesas,rsnd.txt +++ b/Documentation/devicetree/bindings/sound/renesas,rsnd.txt @@ -343,6 +343,7 @@ Required properties: "renesas,rcar_sound-gen3" if generation3 (or RZ/G2) Examples with soctypes are: - "renesas,rcar_sound-r8a7743" (RZ/G1M) + - "renesas,rcar_sound-r8a7744" (RZ/G1N) - "renesas,rcar_sound-r8a7745" (RZ/G1E) - "renesas,rcar_sound-r8a774a1" (RZ/G2M) - "renesas,rcar_sound-r8a7778" (R-Car M1A) From 06da26e5ce157bf2af09ef4a9f5dc30af4599fa0 Mon Sep 17 00:00:00 2001 From: YueHaibing Date: Wed, 26 Sep 2018 15:33:03 +0800 Subject: [PATCH 192/299] ASoC: qcom: qdsp6: remove duplicated include Remove duplicated includes linux/of_platform.h and linux/wait.h Signed-off-by: YueHaibing Signed-off-by: Mark Brown --- sound/soc/qcom/qdsp6/q6asm.c | 1 - sound/soc/qcom/qdsp6/q6core.c | 1 - 2 files changed, 2 deletions(-) diff --git a/sound/soc/qcom/qdsp6/q6asm.c b/sound/soc/qcom/qdsp6/q6asm.c index 2b2c7233bb5f..e1cfa846a1dc 100644 --- a/sound/soc/qcom/qdsp6/q6asm.c +++ b/sound/soc/qcom/qdsp6/q6asm.c @@ -11,7 +11,6 @@ #include #include #include -#include #include #include #include diff --git a/sound/soc/qcom/qdsp6/q6core.c b/sound/soc/qcom/qdsp6/q6core.c index ca1be7305524..cdfc8ab6cfc0 100644 --- a/sound/soc/qcom/qdsp6/q6core.c +++ b/sound/soc/qcom/qdsp6/q6core.c @@ -10,7 +10,6 @@ #include #include #include -#include #include #include "q6core.h" #include "q6dsp-errno.h" From c32bf867cb6721d6ea04044d33f19c8bd81280c1 Mon Sep 17 00:00:00 2001 From: Keyon Jie Date: Fri, 28 Sep 2018 17:38:59 +0800 Subject: [PATCH 193/299] ALSA: hda: Fix mismatch for register mask and value in ext controller. E.g. for snd_hdac_ext_bus_link_power_up(), we should set mask to be AZX_MLCTL_SPA(it was 0), and AZX_MLCTL_SPA as value to power up it, here correct it and several similar mismatches. Signed-off-by: Keyon Jie Signed-off-by: Takashi Iwai --- sound/hda/ext/hdac_ext_controller.c | 22 ++++++++++++++-------- 1 file changed, 14 insertions(+), 8 deletions(-) diff --git a/sound/hda/ext/hdac_ext_controller.c b/sound/hda/ext/hdac_ext_controller.c index 5bc4a1d587d4..60cb00fd0c69 100644 --- a/sound/hda/ext/hdac_ext_controller.c +++ b/sound/hda/ext/hdac_ext_controller.c @@ -48,9 +48,11 @@ void snd_hdac_ext_bus_ppcap_enable(struct hdac_bus *bus, bool enable) } if (enable) - snd_hdac_updatel(bus->ppcap, AZX_REG_PP_PPCTL, 0, AZX_PPCTL_GPROCEN); + snd_hdac_updatel(bus->ppcap, AZX_REG_PP_PPCTL, + AZX_PPCTL_GPROCEN, AZX_PPCTL_GPROCEN); else - snd_hdac_updatel(bus->ppcap, AZX_REG_PP_PPCTL, AZX_PPCTL_GPROCEN, 0); + snd_hdac_updatel(bus->ppcap, AZX_REG_PP_PPCTL, + AZX_PPCTL_GPROCEN, 0); } EXPORT_SYMBOL_GPL(snd_hdac_ext_bus_ppcap_enable); @@ -68,9 +70,11 @@ void snd_hdac_ext_bus_ppcap_int_enable(struct hdac_bus *bus, bool enable) } if (enable) - snd_hdac_updatel(bus->ppcap, AZX_REG_PP_PPCTL, 0, AZX_PPCTL_PIE); + snd_hdac_updatel(bus->ppcap, AZX_REG_PP_PPCTL, + AZX_PPCTL_PIE, AZX_PPCTL_PIE); else - snd_hdac_updatel(bus->ppcap, AZX_REG_PP_PPCTL, AZX_PPCTL_PIE, 0); + snd_hdac_updatel(bus->ppcap, AZX_REG_PP_PPCTL, + AZX_PPCTL_PIE, 0); } EXPORT_SYMBOL_GPL(snd_hdac_ext_bus_ppcap_int_enable); @@ -194,7 +198,8 @@ static int check_hdac_link_power_active(struct hdac_ext_link *link, bool enable) */ int snd_hdac_ext_bus_link_power_up(struct hdac_ext_link *link) { - snd_hdac_updatel(link->ml_addr, AZX_REG_ML_LCTL, 0, AZX_MLCTL_SPA); + snd_hdac_updatel(link->ml_addr, AZX_REG_ML_LCTL, + AZX_MLCTL_SPA, AZX_MLCTL_SPA); return check_hdac_link_power_active(link, true); } @@ -222,8 +227,8 @@ int snd_hdac_ext_bus_link_power_up_all(struct hdac_bus *bus) int ret; list_for_each_entry(hlink, &bus->hlink_list, list) { - snd_hdac_updatel(hlink->ml_addr, - AZX_REG_ML_LCTL, 0, AZX_MLCTL_SPA); + snd_hdac_updatel(hlink->ml_addr, AZX_REG_ML_LCTL, + AZX_MLCTL_SPA, AZX_MLCTL_SPA); ret = check_hdac_link_power_active(hlink, true); if (ret < 0) return ret; @@ -243,7 +248,8 @@ int snd_hdac_ext_bus_link_power_down_all(struct hdac_bus *bus) int ret; list_for_each_entry(hlink, &bus->hlink_list, list) { - snd_hdac_updatel(hlink->ml_addr, AZX_REG_ML_LCTL, AZX_MLCTL_SPA, 0); + snd_hdac_updatel(hlink->ml_addr, AZX_REG_ML_LCTL, + AZX_MLCTL_SPA, 0); ret = check_hdac_link_power_active(hlink, false); if (ret < 0) return ret; From a98401518def198e704b26d5d94f661f7561c140 Mon Sep 17 00:00:00 2001 From: Takashi Sakamoto Date: Sat, 29 Sep 2018 23:20:51 +0900 Subject: [PATCH 194/299] ALSA: timer: fix wrong comment to refer to 'SNDRV_TIMER_PSFLG_*' ALSA timer core has a comment referring to 'SNDRV_MIXER_PSFLG_*' in a definition of 'struct snd_timer_params' of UAPI header. I can see this in initial state of ALSA timer core, at least in 'alsa-driver-0.4.0.tar.gz'. This commit fixes the comment. Signed-off-by: Takashi Sakamoto Signed-off-by: Takashi Iwai --- include/uapi/sound/asound.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/uapi/sound/asound.h b/include/uapi/sound/asound.h index ed0a120d4f08..404d4b9ffe76 100644 --- a/include/uapi/sound/asound.h +++ b/include/uapi/sound/asound.h @@ -752,7 +752,7 @@ struct snd_timer_info { #define SNDRV_TIMER_PSFLG_EARLY_EVENT (1<<2) /* write early event to the poll queue */ struct snd_timer_params { - unsigned int flags; /* flags - SNDRV_MIXER_PSFLG_* */ + unsigned int flags; /* flags - SNDRV_TIMER_PSFLG_* */ unsigned int ticks; /* requested resolution in ticks */ unsigned int queue_size; /* total size of queue (32-1024) */ unsigned int reserved0; /* reserved, was: failure locations */ From 4b432ad4ca8cd63ab1c0b45d9af2d1fe7796944d Mon Sep 17 00:00:00 2001 From: Connor McAdams Date: Sat, 29 Sep 2018 23:03:16 -0400 Subject: [PATCH 195/299] ALSA: hda/ca0132 - Fix AE-5 control type This patch corrects the control type of the additional AE-5 controls added in a previous patch from HDA_INPUT to HDA_OUTPUT. Signed-off-by: Connor McAdams Reviewed-by: Takashi Sakamoto Signed-off-by: Takashi Iwai --- sound/pci/hda/patch_ca0132.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/sound/pci/hda/patch_ca0132.c b/sound/pci/hda/patch_ca0132.c index 225aa05dafae..aebc592d9ead 100644 --- a/sound/pci/hda/patch_ca0132.c +++ b/sound/pci/hda/patch_ca0132.c @@ -6109,7 +6109,7 @@ static int ae5_add_headphone_gain_enum(struct hda_codec *codec) { struct snd_kcontrol_new knew = HDA_CODEC_MUTE_MONO("AE-5: Headphone Gain", - AE5_HEADPHONE_GAIN_ENUM, 1, 0, HDA_INPUT); + AE5_HEADPHONE_GAIN_ENUM, 1, 0, HDA_OUTPUT); knew.info = ae5_headphone_gain_info; knew.get = ae5_headphone_gain_get; knew.put = ae5_headphone_gain_put; @@ -6126,7 +6126,7 @@ static int ae5_add_sound_filter_enum(struct hda_codec *codec) { struct snd_kcontrol_new knew = HDA_CODEC_MUTE_MONO("AE-5: Sound Filter", - AE5_SOUND_FILTER_ENUM, 1, 0, HDA_INPUT); + AE5_SOUND_FILTER_ENUM, 1, 0, HDA_OUTPUT); knew.info = ae5_sound_filter_info; knew.get = ae5_sound_filter_get; knew.put = ae5_sound_filter_put; From 8e6bc6b3aab019896a08498e32fec3b577a9044a Mon Sep 17 00:00:00 2001 From: Connor McAdams Date: Sat, 29 Sep 2018 23:03:17 -0400 Subject: [PATCH 196/299] ALSA: hda/ca0132 - Fix surround sound with output effects This patch fixes an issue where if surround sound was the selected output and output effects were enabled, the sound wasn't sent to all channels correctly. Signed-off-by: Connor McAdams Reviewed-by: Takashi Sakamoto Signed-off-by: Takashi Iwai --- sound/pci/hda/patch_ca0132.c | 19 ++++++++++++++----- 1 file changed, 14 insertions(+), 5 deletions(-) diff --git a/sound/pci/hda/patch_ca0132.c b/sound/pci/hda/patch_ca0132.c index aebc592d9ead..5a3fb56404db 100644 --- a/sound/pci/hda/patch_ca0132.c +++ b/sound/pci/hda/patch_ca0132.c @@ -4125,6 +4125,7 @@ exit: } static int ae5_headphone_gain_set(struct hda_codec *codec, long val); +static int ca0132_effects_set(struct hda_codec *codec, hda_nid_t nid, long val); static void ae5_mmio_select_out(struct hda_codec *codec) { @@ -4365,12 +4366,19 @@ static int ca0132_alt_select_out(struct hda_codec *codec) snd_hda_set_pin_ctl(codec, spec->out_pins[3], pin_ctl | PIN_OUT); - if (spec->effects_switch[PLAY_ENHANCEMENT - EFFECT_START_NID]) - dspio_set_uint_param(codec, 0x80, 0x04, FLOAT_ONE); - else - dspio_set_uint_param(codec, 0x80, 0x04, FLOAT_EIGHT); + dspio_set_uint_param(codec, 0x80, 0x04, FLOAT_EIGHT); break; } + /* + * Surround always sets it's scp command to req 0x04 to FLOAT_EIGHT. + * With this set though, X_BASS cannot be enabled. So, if we have OutFX + * enabled, we need to make sure X_BASS is off, otherwise everything + * sounds all muffled. Running ca0132_effects_set with X_BASS as the + * effect should sort this out. + */ + if (spec->effects_switch[PLAY_ENHANCEMENT - EFFECT_START_NID]) + ca0132_effects_set(codec, X_BASS, + spec->effects_switch[X_BASS - EFFECT_START_NID]); /* run through the output dsp commands for the selected output. */ for (i = 0; i < alt_out_presets[spec->cur_out_type].commands; i++) { @@ -4409,7 +4417,6 @@ static void ca0132_unsol_hp_delayed(struct work_struct *work) static void ca0132_set_dmic(struct hda_codec *codec, int enable); static int ca0132_mic_boost_set(struct hda_codec *codec, long val); -static int ca0132_effects_set(struct hda_codec *codec, hda_nid_t nid, long val); static void resume_mic1(struct hda_codec *codec, unsigned int oldval); static int stop_mic1(struct hda_codec *codec); static int ca0132_cvoice_switch_set(struct hda_codec *codec); @@ -4787,6 +4794,8 @@ static int ca0132_effects_set(struct hda_codec *codec, hda_nid_t nid, long val) /* if PE if off, turn off out effects. */ if (!spec->effects_switch[PLAY_ENHANCEMENT - EFFECT_START_NID]) val = 0; + if (spec->cur_out_type == SURROUND_OUT && nid == X_BASS) + val = 0; } /* for in effect, qualify with CrystalVoice */ From b29733db3b761684c90cb5ea195d9e47462059b2 Mon Sep 17 00:00:00 2001 From: Connor McAdams Date: Sat, 29 Sep 2018 23:03:18 -0400 Subject: [PATCH 197/299] ALSA: hda/ca0132 - Add ZxR quirks + new quirk check function This patch adds quirk ID's for the ZxR and it's daughter board, the DBPro. It also adds a function for determining the quirk for each board through HDA subsytem ID's instead of PCI subsystem ID's. Signed-off-by: Connor McAdams Reviewed-by: Takashi Sakamoto Signed-off-by: Takashi Iwai --- sound/pci/hda/patch_ca0132.c | 28 ++++++++++++++++++++++++++++ 1 file changed, 28 insertions(+) diff --git a/sound/pci/hda/patch_ca0132.c b/sound/pci/hda/patch_ca0132.c index 5a3fb56404db..08dd85db2953 100644 --- a/sound/pci/hda/patch_ca0132.c +++ b/sound/pci/hda/patch_ca0132.c @@ -1071,6 +1071,8 @@ enum { QUIRK_ALIENWARE, QUIRK_ALIENWARE_M17XR4, QUIRK_SBZ, + QUIRK_ZXR, + QUIRK_ZXR_DBPRO, QUIRK_R3DI, QUIRK_R3D, QUIRK_AE5, @@ -8376,6 +8378,29 @@ static int ca0132_prepare_verbs(struct hda_codec *codec) return 0; } +/* + * The Sound Blaster ZxR shares the same PCI subsystem ID as some regular + * Sound Blaster Z cards. However, they have different HDA codec subsystem + * ID's. So, we check for the ZxR's subsystem ID, as well as the DBPro + * daughter boards ID. + */ +static void sbz_detect_quirk(struct hda_codec *codec) +{ + struct ca0132_spec *spec = codec->spec; + + switch (codec->core.subsystem_id) { + case 0x11020033: + spec->quirk = QUIRK_ZXR; + break; + case 0x1102003f: + spec->quirk = QUIRK_ZXR_DBPRO; + break; + default: + spec->quirk = QUIRK_SBZ; + break; + } +} + static int patch_ca0132(struct hda_codec *codec) { struct ca0132_spec *spec; @@ -8401,6 +8426,9 @@ static int patch_ca0132(struct hda_codec *codec) else spec->quirk = QUIRK_NONE; + if (spec->quirk == QUIRK_SBZ) + sbz_detect_quirk(codec); + spec->dsp_state = DSP_DOWNLOAD_INIT; spec->num_mixers = 1; From 6dcd7244a2e27ccf4abbbdfe1ef437ba48af9c1f Mon Sep 17 00:00:00 2001 From: Connor McAdams Date: Sat, 29 Sep 2018 23:03:19 -0400 Subject: [PATCH 198/299] ALSA: hda/ca0132 - Add ZxR pincfg This patch adds a pincfg for the ZxR, and defines which pins are used for both. Signed-off-by: Connor McAdams Reviewed-by: Takashi Sakamoto Signed-off-by: Takashi Iwai --- sound/pci/hda/patch_ca0132.c | 50 ++++++++++++++++++++++++++++++++++++ 1 file changed, 50 insertions(+) diff --git a/sound/pci/hda/patch_ca0132.c b/sound/pci/hda/patch_ca0132.c index 08dd85db2953..4d23eb93792e 100644 --- a/sound/pci/hda/patch_ca0132.c +++ b/sound/pci/hda/patch_ca0132.c @@ -1107,6 +1107,21 @@ static const struct hda_pintbl sbz_pincfgs[] = { {} }; +/* Sound Blaster ZxR pin configs taken from Windows Driver */ +static const struct hda_pintbl zxr_pincfgs[] = { + { 0x0b, 0x01047110 }, /* Port G -- Lineout FRONT L/R */ + { 0x0c, 0x414510f0 }, /* SPDIF Out 1 - Disabled*/ + { 0x0d, 0x014510f0 }, /* Digital Out */ + { 0x0e, 0x41c520f0 }, /* SPDIF In - Disabled*/ + { 0x0f, 0x0122711f }, /* Port A -- BackPanel HP */ + { 0x10, 0x01017111 }, /* Port D -- Center/LFE */ + { 0x11, 0x01017114 }, /* Port B -- LineMicIn2 / Rear L/R */ + { 0x12, 0x01a271f0 }, /* Port C -- LineIn1 */ + { 0x13, 0x908700f0 }, /* What U Hear In*/ + { 0x18, 0x50d000f0 }, /* N/A */ + {} +}; + /* Recon3D pin configs taken from Windows Driver */ static const struct hda_pintbl r3d_pincfgs[] = { { 0x0b, 0x01014110 }, /* Port G -- Lineout FRONT L/R */ @@ -8202,6 +8217,10 @@ static void ca0132_config(struct hda_codec *codec) codec_dbg(codec, "%s: QUIRK_SBZ applied.\n", __func__); snd_hda_apply_pincfgs(codec, sbz_pincfgs); break; + case QUIRK_ZXR: + codec_dbg(codec, "%s: QUIRK_ZXR applied.\n", __func__); + snd_hda_apply_pincfgs(codec, zxr_pincfgs); + break; case QUIRK_R3D: codec_dbg(codec, "%s: QUIRK_R3D applied.\n", __func__); snd_hda_apply_pincfgs(codec, r3d_pincfgs); @@ -8259,6 +8278,37 @@ static void ca0132_config(struct hda_codec *codec) /* SPDIF I/O */ spec->dig_out = 0x05; spec->multiout.dig_out_nid = spec->dig_out; + spec->dig_in = 0x09; + break; + case QUIRK_ZXR: + spec->num_outputs = 2; + spec->out_pins[0] = 0x0B; /* Line out */ + spec->out_pins[1] = 0x0F; /* Rear headphone out */ + spec->out_pins[2] = 0x10; /* Center/LFE */ + spec->out_pins[3] = 0x11; /* Rear surround */ + spec->shared_out_nid = 0x2; + spec->unsol_tag_hp = spec->out_pins[1]; + spec->unsol_tag_front_hp = spec->out_pins[2]; + + spec->adcs[0] = 0x7; /* Rear Mic / Line-in */ + spec->adcs[1] = 0x8; /* Not connected, no front mic */ + spec->adcs[2] = 0xa; /* what u hear */ + + spec->num_inputs = 2; + spec->input_pins[0] = 0x12; /* Rear Mic / Line-in */ + spec->input_pins[1] = 0x13; /* What U Hear */ + spec->shared_mic_nid = 0x7; + spec->unsol_tag_amic1 = spec->input_pins[0]; + break; + case QUIRK_ZXR_DBPRO: + spec->adcs[0] = 0x8; /* ZxR DBPro Aux In */ + + spec->num_inputs = 1; + spec->input_pins[0] = 0x11; /* RCA Line-in */ + + spec->dig_out = 0x05; + spec->multiout.dig_out_nid = spec->dig_out; + spec->dig_in = 0x09; break; case QUIRK_AE5: From 7675a2a9398af3d910df8f8aa96382b3bb6b696f Mon Sep 17 00:00:00 2001 From: Connor McAdams Date: Sat, 29 Sep 2018 23:03:20 -0400 Subject: [PATCH 199/299] ALSA: hda/ca0132 - Add DBpro hda_codec_ops This patch adds separate hda_codec_ops for the DBPro daughter board, as it behaves more like a generic HDA codec than the other ca0132 cards, despite having a ca0132 on board. Signed-off-by: Connor McAdams Reviewed-by: Takashi Sakamoto Signed-off-by: Takashi Iwai --- sound/pci/hda/patch_ca0132.c | 100 +++++++++++++++++++++++++++++++++++ 1 file changed, 100 insertions(+) diff --git a/sound/pci/hda/patch_ca0132.c b/sound/pci/hda/patch_ca0132.c index 4d23eb93792e..a543b2368fbb 100644 --- a/sound/pci/hda/patch_ca0132.c +++ b/sound/pci/hda/patch_ca0132.c @@ -6416,6 +6416,27 @@ static int ca0132_build_controls(struct hda_codec *codec) return 0; } +static int dbpro_build_controls(struct hda_codec *codec) +{ + struct ca0132_spec *spec = codec->spec; + int err = 0; + + if (spec->dig_out) { + err = snd_hda_create_spdif_out_ctls(codec, spec->dig_out, + spec->dig_out); + if (err < 0) + return err; + } + + if (spec->dig_in) { + err = snd_hda_create_spdif_in_ctls(codec, spec->dig_in); + if (err < 0) + return err; + } + + return 0; +} + /* * PCM */ @@ -6519,6 +6540,40 @@ static int ca0132_build_pcms(struct hda_codec *codec) return 0; } +static int dbpro_build_pcms(struct hda_codec *codec) +{ + struct ca0132_spec *spec = codec->spec; + struct hda_pcm *info; + + info = snd_hda_codec_pcm_new(codec, "CA0132 Alt Analog"); + if (!info) + return -ENOMEM; + info->stream[SNDRV_PCM_STREAM_CAPTURE] = ca0132_pcm_analog_capture; + info->stream[SNDRV_PCM_STREAM_CAPTURE].substreams = 1; + info->stream[SNDRV_PCM_STREAM_CAPTURE].nid = spec->adcs[0]; + + + if (!spec->dig_out && !spec->dig_in) + return 0; + + info = snd_hda_codec_pcm_new(codec, "CA0132 Digital"); + if (!info) + return -ENOMEM; + info->pcm_type = HDA_PCM_TYPE_SPDIF; + if (spec->dig_out) { + info->stream[SNDRV_PCM_STREAM_PLAYBACK] = + ca0132_pcm_digital_playback; + info->stream[SNDRV_PCM_STREAM_PLAYBACK].nid = spec->dig_out; + } + if (spec->dig_in) { + info->stream[SNDRV_PCM_STREAM_CAPTURE] = + ca0132_pcm_digital_capture; + info->stream[SNDRV_PCM_STREAM_CAPTURE].nid = spec->dig_in; + } + + return 0; +} + static void init_output(struct hda_codec *codec, hda_nid_t pin, hda_nid_t dac) { if (pin) { @@ -7649,6 +7704,16 @@ static void sbz_gpio_shutdown_commands(struct hda_codec *codec, int dir, AC_VERB_SET_GPIO_DATA, data); } +static void zxr_dbpro_power_state_shutdown(struct hda_codec *codec) +{ + hda_nid_t pins[7] = {0x05, 0x0c, 0x09, 0x0e, 0x08, 0x11, 0x01}; + unsigned int i; + + for (i = 0; i < 7; i++) + snd_hda_codec_write(codec, pins[i], 0, + AC_VERB_SET_POWER_STATE, 0x03); +} + static void sbz_exit_chip(struct hda_codec *codec) { chipio_set_stream_control(codec, 0x03, 0); @@ -8147,6 +8212,21 @@ static int ca0132_init(struct hda_codec *codec) return 0; } +static int dbpro_init(struct hda_codec *codec) +{ + struct ca0132_spec *spec = codec->spec; + struct auto_pin_cfg *cfg = &spec->autocfg; + unsigned int i; + + init_output(codec, cfg->dig_out_pins[0], spec->dig_out); + init_input(codec, cfg->dig_in_pin, spec->dig_in); + + for (i = 0; i < spec->num_inputs; i++) + init_input(codec, spec->input_pins[i], spec->adcs[i]); + + return 0; +} + static void ca0132_free(struct hda_codec *codec) { struct ca0132_spec *spec = codec->spec; @@ -8178,6 +8258,16 @@ static void ca0132_free(struct hda_codec *codec) kfree(codec->spec); } +static void dbpro_free(struct hda_codec *codec) +{ + struct ca0132_spec *spec = codec->spec; + + zxr_dbpro_power_state_shutdown(codec); + + kfree(spec->spec_init_verbs); + kfree(codec->spec); +} + static void ca0132_reboot_notify(struct hda_codec *codec) { codec->patch_ops.free(codec); @@ -8192,6 +8282,13 @@ static const struct hda_codec_ops ca0132_patch_ops = { .reboot_notify = ca0132_reboot_notify, }; +static const struct hda_codec_ops dbpro_patch_ops = { + .build_controls = dbpro_build_controls, + .build_pcms = dbpro_build_pcms, + .init = dbpro_init, + .free = dbpro_free, +}; + static void ca0132_config(struct hda_codec *codec) { struct ca0132_spec *spec = codec->spec; @@ -8488,6 +8585,9 @@ static int patch_ca0132(struct hda_codec *codec) spec->mixers[0] = desktop_mixer; snd_hda_codec_set_name(codec, "Sound Blaster Z"); break; + case QUIRK_ZXR_DBPRO: + codec->patch_ops = dbpro_patch_ops; + break; case QUIRK_R3D: spec->mixers[0] = desktop_mixer; snd_hda_codec_set_name(codec, "Recon3D"); From 2e492b8ee5da8ac1c9b31f728c9d9624e4345548 Mon Sep 17 00:00:00 2001 From: Connor McAdams Date: Sat, 29 Sep 2018 23:03:21 -0400 Subject: [PATCH 200/299] ALSA: hda/ca0132 - Add ZxR init commands This patch adds init commands for the main Sound Blaster ZxR card. Signed-off-by: Connor McAdams Reviewed-by: Takashi Sakamoto Signed-off-by: Takashi Iwai --- sound/pci/hda/patch_ca0132.c | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/sound/pci/hda/patch_ca0132.c b/sound/pci/hda/patch_ca0132.c index a543b2368fbb..6e48c3dc022a 100644 --- a/sound/pci/hda/patch_ca0132.c +++ b/sound/pci/hda/patch_ca0132.c @@ -7953,7 +7953,10 @@ static void ca0132_mmio_init(struct hda_codec *codec) else writel(0x00000000, spec->mem_base + 0x40C); - writel(0x00880680, spec->mem_base + 0x01C); + if (spec->quirk == QUIRK_ZXR) + writel(0x00880640, spec->mem_base + 0x01C); + else + writel(0x00880680, spec->mem_base + 0x01C); if (spec->quirk == QUIRK_AE5) writel(0x00000080, spec->mem_base + 0xC0C); @@ -8091,6 +8094,10 @@ static void ca0132_alt_init(struct hda_codec *codec) snd_hda_sequence_write(codec, spec->desktop_init_verbs); ca0113_mmio_command_set(codec, 0x30, 0x32, 0x3f); break; + case QUIRK_ZXR: + snd_hda_sequence_write(codec, spec->chip_init_verbs); + snd_hda_sequence_write(codec, spec->desktop_init_verbs); + break; } } @@ -8585,6 +8592,10 @@ static int patch_ca0132(struct hda_codec *codec) spec->mixers[0] = desktop_mixer; snd_hda_codec_set_name(codec, "Sound Blaster Z"); break; + case QUIRK_ZXR: + spec->mixers[0] = desktop_mixer; + snd_hda_codec_set_name(codec, "Sound Blaster ZxR"); + break; case QUIRK_ZXR_DBPRO: codec->patch_ops = dbpro_patch_ops; break; @@ -8610,6 +8621,7 @@ static int patch_ca0132(struct hda_codec *codec) case QUIRK_SBZ: case QUIRK_R3D: case QUIRK_AE5: + case QUIRK_ZXR: spec->use_alt_controls = true; spec->use_alt_functions = true; spec->use_pci_mmio = true; From c25c73e06a70765578c86569086965b61973283f Mon Sep 17 00:00:00 2001 From: Connor McAdams Date: Sat, 29 Sep 2018 23:03:22 -0400 Subject: [PATCH 201/299] ALSA: hda/ca0132 - Add ZxR DSP post-download commands This patch adds commands for setting up the ZxR after the DSP is downloaded. The ZxR already shares most of the post-download commands from the regular Sound Blaster Z. Signed-off-by: Connor McAdams Reviewed-by: Takashi Sakamoto Signed-off-by: Takashi Iwai --- sound/pci/hda/patch_ca0132.c | 37 +++++++++++++++++++++++------------- 1 file changed, 24 insertions(+), 13 deletions(-) diff --git a/sound/pci/hda/patch_ca0132.c b/sound/pci/hda/patch_ca0132.c index 6e48c3dc022a..729766a57189 100644 --- a/sound/pci/hda/patch_ca0132.c +++ b/sound/pci/hda/patch_ca0132.c @@ -6854,19 +6854,29 @@ static void sbz_chipio_startup_data(struct hda_codec *codec) chipio_set_stream_channels(codec, 0x0C, 6); chipio_set_stream_control(codec, 0x0C, 1); /* No clue what these control */ - chipio_write_no_mutex(codec, 0x190030, 0x0001e0c0); - chipio_write_no_mutex(codec, 0x190034, 0x0001e1c1); - chipio_write_no_mutex(codec, 0x190038, 0x0001e4c2); - chipio_write_no_mutex(codec, 0x19003c, 0x0001e5c3); - chipio_write_no_mutex(codec, 0x190040, 0x0001e2c4); - chipio_write_no_mutex(codec, 0x190044, 0x0001e3c5); - chipio_write_no_mutex(codec, 0x190048, 0x0001e8c6); - chipio_write_no_mutex(codec, 0x19004c, 0x0001e9c7); - chipio_write_no_mutex(codec, 0x190050, 0x0001ecc8); - chipio_write_no_mutex(codec, 0x190054, 0x0001edc9); - chipio_write_no_mutex(codec, 0x190058, 0x0001eaca); - chipio_write_no_mutex(codec, 0x19005c, 0x0001ebcb); - + if (spec->quirk == QUIRK_SBZ) { + chipio_write_no_mutex(codec, 0x190030, 0x0001e0c0); + chipio_write_no_mutex(codec, 0x190034, 0x0001e1c1); + chipio_write_no_mutex(codec, 0x190038, 0x0001e4c2); + chipio_write_no_mutex(codec, 0x19003c, 0x0001e5c3); + chipio_write_no_mutex(codec, 0x190040, 0x0001e2c4); + chipio_write_no_mutex(codec, 0x190044, 0x0001e3c5); + chipio_write_no_mutex(codec, 0x190048, 0x0001e8c6); + chipio_write_no_mutex(codec, 0x19004c, 0x0001e9c7); + chipio_write_no_mutex(codec, 0x190050, 0x0001ecc8); + chipio_write_no_mutex(codec, 0x190054, 0x0001edc9); + chipio_write_no_mutex(codec, 0x190058, 0x0001eaca); + chipio_write_no_mutex(codec, 0x19005c, 0x0001ebcb); + } else if (spec->quirk == QUIRK_ZXR) { + chipio_write_no_mutex(codec, 0x190038, 0x000140c2); + chipio_write_no_mutex(codec, 0x19003c, 0x000141c3); + chipio_write_no_mutex(codec, 0x190040, 0x000150c4); + chipio_write_no_mutex(codec, 0x190044, 0x000151c5); + chipio_write_no_mutex(codec, 0x190050, 0x000142c8); + chipio_write_no_mutex(codec, 0x190054, 0x000143c9); + chipio_write_no_mutex(codec, 0x190058, 0x000152ca); + chipio_write_no_mutex(codec, 0x19005c, 0x000153cb); + } chipio_write_no_mutex(codec, 0x19042c, 0x00000001); codec_dbg(codec, "Startup Data exited, mutex released.\n"); @@ -8161,6 +8171,7 @@ static int ca0132_init(struct hda_codec *codec) r3d_setup_defaults(codec); break; case QUIRK_SBZ: + case QUIRK_ZXR: sbz_setup_defaults(codec); break; case QUIRK_AE5: From 55845949428007841af18011128735fc8cccf0e6 Mon Sep 17 00:00:00 2001 From: Connor McAdams Date: Sat, 29 Sep 2018 23:03:23 -0400 Subject: [PATCH 202/299] ALSA: hda/ca0132 - Add ZxR input/output select commands This patch adds commands for selecting input and output on the Sound Blaster ZxR. The ZxR has no front panel header, and has line-in on the separate daughter board, so it only does rear-mic. Signed-off-by: Connor McAdams Reviewed-by: Takashi Sakamoto Signed-off-by: Takashi Iwai --- sound/pci/hda/patch_ca0132.c | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/sound/pci/hda/patch_ca0132.c b/sound/pci/hda/patch_ca0132.c index 729766a57189..bc8745f48fff 100644 --- a/sound/pci/hda/patch_ca0132.c +++ b/sound/pci/hda/patch_ca0132.c @@ -4174,6 +4174,12 @@ static void ca0132_alt_select_out_quirk_handler(struct hda_codec *codec) ca0113_mmio_gpio_set(codec, 1, true); chipio_set_control_param(codec, 0x0d, 0x18); break; + case QUIRK_ZXR: + ca0113_mmio_gpio_set(codec, 2, true); + ca0113_mmio_gpio_set(codec, 3, true); + ca0113_mmio_gpio_set(codec, 5, false); + chipio_set_control_param(codec, 0x0d, 0x24); + break; case QUIRK_R3DI: chipio_set_control_param(codec, 0x0d, 0x24); r3di_gpio_out_set(codec, R3DI_LINE_OUT); @@ -4201,6 +4207,12 @@ static void ca0132_alt_select_out_quirk_handler(struct hda_codec *codec) ca0113_mmio_gpio_set(codec, 1, false); chipio_set_control_param(codec, 0x0d, 0x12); break; + case QUIRK_ZXR: + ca0113_mmio_gpio_set(codec, 2, false); + ca0113_mmio_gpio_set(codec, 3, false); + ca0113_mmio_gpio_set(codec, 5, true); + chipio_set_control_param(codec, 0x0d, 0x21); + break; case QUIRK_R3DI: chipio_set_control_param(codec, 0x0d, 0x21); r3di_gpio_out_set(codec, R3DI_HEADPHONE_OUT); @@ -4229,6 +4241,12 @@ static void ca0132_alt_select_out_quirk_handler(struct hda_codec *codec) ca0113_mmio_gpio_set(codec, 1, true); chipio_set_control_param(codec, 0x0d, 0x18); break; + case QUIRK_ZXR: + ca0113_mmio_gpio_set(codec, 2, true); + ca0113_mmio_gpio_set(codec, 3, true); + ca0113_mmio_gpio_set(codec, 5, false); + chipio_set_control_param(codec, 0x0d, 0x24); + break; case QUIRK_R3DI: chipio_set_control_param(codec, 0x0d, 0x24); r3di_gpio_out_set(codec, R3DI_LINE_OUT); @@ -4625,6 +4643,9 @@ static int ca0132_alt_select_in(struct hda_codec *codec) ca0113_mmio_gpio_set(codec, 0, false); tmp = FLOAT_THREE; break; + case QUIRK_ZXR: + tmp = FLOAT_THREE; + break; case QUIRK_R3DI: r3di_gpio_mic_set(codec, R3DI_REAR_MIC); tmp = FLOAT_ONE; @@ -4652,6 +4673,10 @@ static int ca0132_alt_select_in(struct hda_codec *codec) chipio_write(codec, 0x18B098, 0x0000000C); chipio_write(codec, 0x18B09C, 0x0000000C); break; + case QUIRK_ZXR: + chipio_write(codec, 0x18B098, 0x0000000C); + chipio_write(codec, 0x18B09C, 0x000000CC); + break; case QUIRK_AE5: chipio_write(codec, 0x18B098, 0x0000000C); chipio_write(codec, 0x18B09C, 0x0000004C); From 76dea4dbf06bd49557a1dcc4c54f3ada88d8c8a0 Mon Sep 17 00:00:00 2001 From: Connor McAdams Date: Sat, 29 Sep 2018 23:03:24 -0400 Subject: [PATCH 203/299] ALSA: hda/ca0132 - Remove input select enum for ZxR This patch removes the input select control for the ZxR, as it only has one input option, rear microphone. Signed-off-by: Connor McAdams Reviewed-by: Takashi Sakamoto Signed-off-by: Takashi Iwai --- sound/pci/hda/patch_ca0132.c | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/sound/pci/hda/patch_ca0132.c b/sound/pci/hda/patch_ca0132.c index bc8745f48fff..f0781e4b0da9 100644 --- a/sound/pci/hda/patch_ca0132.c +++ b/sound/pci/hda/patch_ca0132.c @@ -6402,8 +6402,13 @@ static int ca0132_build_controls(struct hda_codec *codec) */ if (spec->use_alt_functions) { ca0132_alt_add_output_enum(codec); - ca0132_alt_add_input_enum(codec); ca0132_alt_add_mic_boost_enum(codec); + /* + * ZxR only has microphone input, there is no front panel + * header on the card, and aux-in is handled by the DBPro board. + */ + if (spec->quirk != QUIRK_ZXR) + ca0132_alt_add_input_enum(codec); } if (spec->quirk == QUIRK_AE5) { @@ -7665,6 +7670,14 @@ static void ca0132_init_chip(struct hda_codec *codec) spec->effects_switch[PLAY_ENHANCEMENT - EFFECT_START_NID] = 1; spec->effects_switch[CRYSTAL_VOICE - EFFECT_START_NID] = 0; + /* + * The ZxR doesn't have a front panel header, and it's line-in is on + * the daughter board. So, there is no input enum control, and we need + * to make sure that spec->in_enum_val is set properly. + */ + if (spec->quirk == QUIRK_ZXR) + spec->in_enum_val = REAR_MIC; + #ifdef ENABLE_TUNING_CONTROLS ca0132_init_tuning_defaults(codec); #endif From d51434d43a2cbef2a656b780c7ab936105a30aaf Mon Sep 17 00:00:00 2001 From: Connor McAdams Date: Sat, 29 Sep 2018 23:03:25 -0400 Subject: [PATCH 204/299] ALSA: hda/ca0132 - Add ZxR 600 ohm gain control This patch adds a control for 600 ohm gain on the Sound Blaster ZxR. Signed-off-by: Connor McAdams Reviewed-by: Takashi Sakamoto Signed-off-by: Takashi Iwai --- sound/pci/hda/patch_ca0132.c | 44 ++++++++++++++++++++++++++++++++++-- 1 file changed, 42 insertions(+), 2 deletions(-) diff --git a/sound/pci/hda/patch_ca0132.c b/sound/pci/hda/patch_ca0132.c index f0781e4b0da9..90e6a96b3630 100644 --- a/sound/pci/hda/patch_ca0132.c +++ b/sound/pci/hda/patch_ca0132.c @@ -154,7 +154,8 @@ enum { SMART_VOLUME_ENUM, MIC_BOOST_ENUM, AE5_HEADPHONE_GAIN_ENUM, - AE5_SOUND_FILTER_ENUM + AE5_SOUND_FILTER_ENUM, + ZXR_HEADPHONE_GAIN #define EFFECTS_COUNT (EFFECT_END_NID - EFFECT_START_NID) }; @@ -1031,7 +1032,8 @@ struct ca0132_spec { /* AE-5 Control values */ unsigned char ae5_headphone_gain_val; unsigned char ae5_filter_val; - + /* ZxR Control Values */ + unsigned char zxr_gain_set; struct hda_codec *codec; struct delayed_work unsol_hp_work; @@ -4142,6 +4144,7 @@ exit: } static int ae5_headphone_gain_set(struct hda_codec *codec, long val); +static int zxr_headphone_gain_set(struct hda_codec *codec, long val); static int ca0132_effects_set(struct hda_codec *codec, hda_nid_t nid, long val); static void ae5_mmio_select_out(struct hda_codec *codec) @@ -4178,6 +4181,7 @@ static void ca0132_alt_select_out_quirk_handler(struct hda_codec *codec) ca0113_mmio_gpio_set(codec, 2, true); ca0113_mmio_gpio_set(codec, 3, true); ca0113_mmio_gpio_set(codec, 5, false); + zxr_headphone_gain_set(codec, 0); chipio_set_control_param(codec, 0x0d, 0x24); break; case QUIRK_R3DI: @@ -4211,6 +4215,7 @@ static void ca0132_alt_select_out_quirk_handler(struct hda_codec *codec) ca0113_mmio_gpio_set(codec, 2, false); ca0113_mmio_gpio_set(codec, 3, false); ca0113_mmio_gpio_set(codec, 5, true); + zxr_headphone_gain_set(codec, spec->zxr_gain_set); chipio_set_control_param(codec, 0x0d, 0x21); break; case QUIRK_R3DI: @@ -4245,6 +4250,7 @@ static void ca0132_alt_select_out_quirk_handler(struct hda_codec *codec) ca0113_mmio_gpio_set(codec, 2, true); ca0113_mmio_gpio_set(codec, 3, true); ca0113_mmio_gpio_set(codec, 5, false); + zxr_headphone_gain_set(codec, 0); chipio_set_control_param(codec, 0x0d, 0x24); break; case QUIRK_R3DI: @@ -5019,6 +5025,17 @@ static int ae5_headphone_gain_set(struct hda_codec *codec, long val) return 0; } +/* + * gpio pin 1 is a relay that switches on/off, apparently setting the headphone + * amplifier to handle a 600 ohm load. + */ +static int zxr_headphone_gain_set(struct hda_codec *codec, long val) +{ + ca0113_mmio_gpio_set(codec, 1, val); + + return 0; +} + static int ca0132_vnode_switch_set(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { @@ -5777,6 +5794,16 @@ static int ca0132_switch_put(struct snd_kcontrol *kcontrol, goto exit; } + if (nid == ZXR_HEADPHONE_GAIN) { + spec->zxr_gain_set = *valp; + if (spec->cur_out_type == HEADPHONE_OUT) + changed = zxr_headphone_gain_set(codec, *valp); + else + changed = 0; + + goto exit; + } + exit: snd_hda_power_down(codec); return changed; @@ -6185,6 +6212,16 @@ static int ae5_add_sound_filter_enum(struct hda_codec *codec) snd_ctl_new1(&knew, codec)); } +static int zxr_add_headphone_gain_switch(struct hda_codec *codec) +{ + struct snd_kcontrol_new knew = + CA0132_CODEC_MUTE_MONO("ZxR: 600 Ohm Gain", + ZXR_HEADPHONE_GAIN, 1, HDA_OUTPUT); + + return snd_hda_ctl_add(codec, ZXR_HEADPHONE_GAIN, + snd_ctl_new1(&knew, codec)); +} + /* * Need to create slave controls for the alternate codecs that have surround * capabilities. @@ -6415,6 +6452,9 @@ static int ca0132_build_controls(struct hda_codec *codec) ae5_add_headphone_gain_enum(codec); ae5_add_sound_filter_enum(codec); } + + if (spec->quirk == QUIRK_ZXR) + zxr_add_headphone_gain_switch(codec); #ifdef ENABLE_TUNING_CONTROLS add_tuning_ctls(codec); #endif From 96395e86e3f4c7f520bb7c53c7eee41b1992ebc2 Mon Sep 17 00:00:00 2001 From: Connor McAdams Date: Sat, 29 Sep 2018 23:03:26 -0400 Subject: [PATCH 205/299] ALSA: hda/ca0132 - Add ZxR exit commands This patch adds exit operations for the Sound Blaster ZxR. Signed-off-by: Connor McAdams Reviewed-by: Takashi Sakamoto Signed-off-by: Takashi Iwai --- sound/pci/hda/patch_ca0132.c | 33 +++++++++++++++++++++++++++++++++ 1 file changed, 33 insertions(+) diff --git a/sound/pci/hda/patch_ca0132.c b/sound/pci/hda/patch_ca0132.c index 90e6a96b3630..b0985045ebed 100644 --- a/sound/pci/hda/patch_ca0132.c +++ b/sound/pci/hda/patch_ca0132.c @@ -7869,6 +7869,36 @@ static void ae5_exit_chip(struct hda_codec *codec) snd_hda_codec_write(codec, 0x01, 0, 0x724, 0x83); } +static void zxr_exit_chip(struct hda_codec *codec) +{ + chipio_set_stream_control(codec, 0x03, 0); + chipio_set_stream_control(codec, 0x04, 0); + chipio_set_stream_control(codec, 0x14, 0); + chipio_set_stream_control(codec, 0x0C, 0); + + chipio_set_conn_rate(codec, 0x41, SR_192_000); + chipio_set_conn_rate(codec, 0x91, SR_192_000); + + chipio_write(codec, 0x18a020, 0x00000083); + + snd_hda_codec_write(codec, 0x01, 0, 0x793, 0x00); + snd_hda_codec_write(codec, 0x01, 0, 0x794, 0x53); + + ca0132_clear_unsolicited(codec); + sbz_set_pin_ctl_default(codec); + snd_hda_codec_write(codec, 0x0B, 0, AC_VERB_SET_EAPD_BTLENABLE, 0x00); + + ca0113_mmio_gpio_set(codec, 5, false); + ca0113_mmio_gpio_set(codec, 2, false); + ca0113_mmio_gpio_set(codec, 3, false); + ca0113_mmio_gpio_set(codec, 0, false); + ca0113_mmio_gpio_set(codec, 4, true); + ca0113_mmio_gpio_set(codec, 0, true); + ca0113_mmio_gpio_set(codec, 5, true); + ca0113_mmio_gpio_set(codec, 2, false); + ca0113_mmio_gpio_set(codec, 3, false); +} + static void ca0132_exit_chip(struct hda_codec *codec) { /* put any chip cleanup stuffs here. */ @@ -8333,6 +8363,9 @@ static void ca0132_free(struct hda_codec *codec) case QUIRK_SBZ: sbz_exit_chip(codec); break; + case QUIRK_ZXR: + zxr_exit_chip(codec); + break; case QUIRK_R3D: r3d_exit_chip(codec); break; From 5950229582bc4e5e332247dd9ec11e6fe85659e1 Mon Sep 17 00:00:00 2001 From: Takashi Sakamoto Date: Mon, 1 Oct 2018 04:11:49 +0900 Subject: [PATCH 206/299] ALSA: firewire-lib: add PCM rules to obsolete PCM constraints based on LCM of SYT_INTERVAL In blocking mode of IEC 61883-1/6, when one isochronous packet includes data for events, the data is for the same number of events as SYT_INTERVAL decided according to sampling transmission frequency (SFC). IEC 61883-1/6 engine of ALSA firewire stack applies constraints of period and buffer size of PCM intermediate buffer of PCM substream. At present, this constraint is designed to round the size up/down to 32 frames. This value comes from the least common multiple (LCM) of SYT_INTERVAL. Although this looks to work well, in lower sampling rate, applications are not allowed to set size of period quite near period time constraint (at present 5 msec per period). This commit adds PCM rules for period/buffer size and rate to obsoletes the constraints based on LCM. Signed-off-by: Takashi Sakamoto Signed-off-by: Takashi Iwai --- sound/firewire/amdtp-stream.c | 78 +++++++++++++++++++++++++++++++---- 1 file changed, 71 insertions(+), 7 deletions(-) diff --git a/sound/firewire/amdtp-stream.c b/sound/firewire/amdtp-stream.c index cb9acfe60f6a..fcd965f1d69e 100644 --- a/sound/firewire/amdtp-stream.c +++ b/sound/firewire/amdtp-stream.c @@ -140,6 +140,59 @@ const unsigned int amdtp_rate_table[CIP_SFC_COUNT] = { }; EXPORT_SYMBOL(amdtp_rate_table); +static int apply_constraint_to_size(struct snd_pcm_hw_params *params, + struct snd_pcm_hw_rule *rule) +{ + struct snd_interval *s = hw_param_interval(params, rule->var); + const struct snd_interval *r = + hw_param_interval_c(params, SNDRV_PCM_HW_PARAM_RATE); + struct snd_interval t = { + .min = s->min, .max = s->max, .integer = 1, + }; + int i; + + for (i = 0; i < CIP_SFC_COUNT; ++i) { + unsigned int rate = amdtp_rate_table[i]; + unsigned int step = amdtp_syt_intervals[i]; + + if (!snd_interval_test(r, rate)) + continue; + + t.min = roundup(t.min, step); + t.max = rounddown(t.max, step); + } + + if (snd_interval_checkempty(&t)) + return -EINVAL; + + return snd_interval_refine(s, &t); +} + +static int apply_constraint_to_rate(struct snd_pcm_hw_params *params, + struct snd_pcm_hw_rule *rule) +{ + struct snd_interval *r = + hw_param_interval(params, SNDRV_PCM_HW_PARAM_RATE); + const struct snd_interval *s = hw_param_interval_c(params, rule->deps[0]); + struct snd_interval t = { + .min = UINT_MAX, .max = 0, .integer = 1, + }; + int i; + + for (i = 0; i < CIP_SFC_COUNT; ++i) { + unsigned int step = amdtp_syt_intervals[i]; + unsigned int rate = amdtp_rate_table[i]; + + if (s->min % step || s->max % step) + continue; + + t.min = min(t.min, rate); + t.max = max(t.max, rate); + } + + return snd_interval_refine(r, &t); +} + /** * amdtp_stream_add_pcm_hw_constraints - add hw constraints for PCM substream * @s: the AMDTP stream, which must be initialized. @@ -194,16 +247,27 @@ int amdtp_stream_add_pcm_hw_constraints(struct amdtp_stream *s, * number equals to SYT_INTERVAL. So the number is 8, 16 or 32, * depending on its sampling rate. For accurate period interrupt, it's * preferrable to align period/buffer sizes to current SYT_INTERVAL. - * - * TODO: These constraints can be improved with proper rules. - * Currently apply LCM of SYT_INTERVALs. */ - err = snd_pcm_hw_constraint_step(runtime, 0, - SNDRV_PCM_HW_PARAM_PERIOD_SIZE, 32); + err = snd_pcm_hw_rule_add(runtime, 0, SNDRV_PCM_HW_PARAM_PERIOD_SIZE, + apply_constraint_to_size, NULL, + SNDRV_PCM_HW_PARAM_RATE, -1); + if (err < 0) + goto end; + err = snd_pcm_hw_rule_add(runtime, 0, SNDRV_PCM_HW_PARAM_RATE, + apply_constraint_to_rate, NULL, + SNDRV_PCM_HW_PARAM_PERIOD_SIZE, -1); + if (err < 0) + goto end; + err = snd_pcm_hw_rule_add(runtime, 0, SNDRV_PCM_HW_PARAM_BUFFER_SIZE, + apply_constraint_to_size, NULL, + SNDRV_PCM_HW_PARAM_RATE, -1); + if (err < 0) + goto end; + err = snd_pcm_hw_rule_add(runtime, 0, SNDRV_PCM_HW_PARAM_RATE, + apply_constraint_to_rate, NULL, + SNDRV_PCM_HW_PARAM_BUFFER_SIZE, -1); if (err < 0) goto end; - err = snd_pcm_hw_constraint_step(runtime, 0, - SNDRV_PCM_HW_PARAM_BUFFER_SIZE, 32); end: return err; } From fe1a10bab242ef0184fdaea6d63905e5f49b6041 Mon Sep 17 00:00:00 2001 From: "Gustavo A. R. Silva" Date: Tue, 2 Oct 2018 11:56:36 +0200 Subject: [PATCH 207/299] ALSA: sb8: Fix fall-through annotations Replace "fallthru" with a proper "fall through" annotation. This fix is part of the ongoing efforts to enabling -Wimplicit-fallthrough Signed-off-by: Gustavo A. R. Silva Signed-off-by: Takashi Iwai --- sound/isa/sb/sb8_main.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/sound/isa/sb/sb8_main.c b/sound/isa/sb/sb8_main.c index 481797744b3c..8288fae90085 100644 --- a/sound/isa/sb/sb8_main.c +++ b/sound/isa/sb/sb8_main.c @@ -130,13 +130,13 @@ static int snd_sb8_playback_prepare(struct snd_pcm_substream *substream) chip->playback_format = SB_DSP_HI_OUTPUT_AUTO; break; } - /* fallthru */ + /* fall through */ case SB_HW_201: if (rate > 23000) { chip->playback_format = SB_DSP_HI_OUTPUT_AUTO; break; } - /* fallthru */ + /* fall through */ case SB_HW_20: chip->playback_format = SB_DSP_LO_OUTPUT_AUTO; break; @@ -287,7 +287,7 @@ static int snd_sb8_capture_prepare(struct snd_pcm_substream *substream) chip->capture_format = SB_DSP_HI_INPUT_AUTO; break; } - /* fallthru */ + /* fall through */ case SB_HW_20: chip->capture_format = SB_DSP_LO_INPUT_AUTO; break; @@ -387,7 +387,7 @@ irqreturn_t snd_sb8dsp_interrupt(struct snd_sb *chip) case SB_MODE_PLAYBACK_16: /* ok.. playback is active */ if (chip->hardware != SB_HW_JAZZ16) break; - /* fallthru */ + /* fall through */ case SB_MODE_PLAYBACK_8: substream = chip->playback_substream; if (chip->playback_format == SB_DSP_OUTPUT) @@ -397,7 +397,7 @@ irqreturn_t snd_sb8dsp_interrupt(struct snd_sb *chip) case SB_MODE_CAPTURE_16: if (chip->hardware != SB_HW_JAZZ16) break; - /* fallthru */ + /* fall through */ case SB_MODE_CAPTURE_8: substream = chip->capture_substream; if (chip->capture_format == SB_DSP_INPUT) From 2e75b676c3284930489a968d33b75e5d2b2c36c6 Mon Sep 17 00:00:00 2001 From: "Gustavo A. R. Silva" Date: Wed, 3 Oct 2018 12:38:36 +0200 Subject: [PATCH 208/299] ALSA: intel8x0: Fix fall-through annotations Replace "fallthru" with a proper "fall through" annotation. This fix is part of the ongoing efforts to enabling -Wimplicit-fallthrough Signed-off-by: Gustavo A. R. Silva Signed-off-by: Takashi Iwai --- sound/pci/intel8x0.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/sound/pci/intel8x0.c b/sound/pci/intel8x0.c index 9517f9b8f1d4..ffddcdfe0c66 100644 --- a/sound/pci/intel8x0.c +++ b/sound/pci/intel8x0.c @@ -825,7 +825,7 @@ static int snd_intel8x0_pcm_trigger(struct snd_pcm_substream *substream, int cmd switch (cmd) { case SNDRV_PCM_TRIGGER_RESUME: ichdev->suspended = 0; - /* fallthru */ + /* fall through */ case SNDRV_PCM_TRIGGER_START: case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: val = ICH_IOCE | ICH_STARTBM; @@ -833,7 +833,7 @@ static int snd_intel8x0_pcm_trigger(struct snd_pcm_substream *substream, int cmd break; case SNDRV_PCM_TRIGGER_SUSPEND: ichdev->suspended = 1; - /* fallthru */ + /* fall through */ case SNDRV_PCM_TRIGGER_STOP: val = 0; break; @@ -867,7 +867,7 @@ static int snd_intel8x0_ali_trigger(struct snd_pcm_substream *substream, int cmd switch (cmd) { case SNDRV_PCM_TRIGGER_RESUME: ichdev->suspended = 0; - /* fallthru */ + /* fall through */ case SNDRV_PCM_TRIGGER_START: case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { @@ -884,7 +884,7 @@ static int snd_intel8x0_ali_trigger(struct snd_pcm_substream *substream, int cmd break; case SNDRV_PCM_TRIGGER_SUSPEND: ichdev->suspended = 1; - /* fallthru */ + /* fall through */ case SNDRV_PCM_TRIGGER_STOP: case SNDRV_PCM_TRIGGER_PAUSE_PUSH: /* pause */ From 366a20d7a75cff7f89dede6fdfd41bd491aaf8ac Mon Sep 17 00:00:00 2001 From: Takashi Sakamoto Date: Wed, 3 Oct 2018 08:21:50 +0900 Subject: [PATCH 209/299] ALSA: firewire: use managed-resource of fw unit device for private data At present, private data of each driver in ALSA firewire stack is allocated/freed by kernel slab allocator for corresponding unit on IEEE 1394 bus. In this case, resource-managed slab allocator is available to release memory object automatically just before releasing device structure for the unit. This idea can prevent runtime from memory leak due to programming mistakes. This commit uses the allocator for the private data. These drivers already use reference counter to maintain lifetime of device structure for the unit by a pair of fw_unit_get()/fw_unit_put(). The private data is safely released in a callback of 'struct snd_card.private_free(). Signed-off-by: Takashi Sakamoto Signed-off-by: Takashi Iwai --- sound/firewire/bebob/bebob.c | 13 ++++++------- sound/firewire/dice/dice.c | 8 +++----- sound/firewire/digi00x/digi00x.c | 9 ++++----- sound/firewire/fireface/ff.c | 10 +++------- sound/firewire/fireworks/fireworks.c | 6 ++---- sound/firewire/motu/motu.c | 10 ++++------ sound/firewire/oxfw/oxfw.c | 11 ++++------- sound/firewire/tascam/tascam.c | 10 +++------- 8 files changed, 29 insertions(+), 48 deletions(-) diff --git a/sound/firewire/bebob/bebob.c b/sound/firewire/bebob/bebob.c index 93676354f87f..fb05f2c1b60b 100644 --- a/sound/firewire/bebob/bebob.c +++ b/sound/firewire/bebob/bebob.c @@ -129,12 +129,11 @@ end: static void bebob_free(struct snd_bebob *bebob) { snd_bebob_stream_destroy_duplex(bebob); - fw_unit_put(bebob->unit); kfree(bebob->maudio_special_quirk); mutex_destroy(&bebob->mutex); - kfree(bebob); + fw_unit_put(bebob->unit); } /* @@ -295,15 +294,15 @@ bebob_probe(struct fw_unit *unit, const struct ieee1394_device_id *entry) } /* Allocate this independent of sound card instance. */ - bebob = kzalloc(sizeof(struct snd_bebob), GFP_KERNEL); - if (bebob == NULL) + bebob = devm_kzalloc(&unit->device, sizeof(struct snd_bebob), + GFP_KERNEL); + if (!bebob) return -ENOMEM; - bebob->unit = fw_unit_get(unit); - bebob->entry = entry; - bebob->spec = spec; dev_set_drvdata(&unit->device, bebob); + bebob->entry = entry; + bebob->spec = spec; mutex_init(&bebob->mutex); spin_lock_init(&bebob->lock); init_waitqueue_head(&bebob->hwdep_wait); diff --git a/sound/firewire/dice/dice.c b/sound/firewire/dice/dice.c index 774eb2205668..9bf77adb3127 100644 --- a/sound/firewire/dice/dice.c +++ b/sound/firewire/dice/dice.c @@ -126,10 +126,9 @@ static void dice_free(struct snd_dice *dice) { snd_dice_stream_destroy_duplex(dice); snd_dice_transaction_destroy(dice); - fw_unit_put(dice->unit); mutex_destroy(&dice->mutex); - kfree(dice); + fw_unit_put(dice->unit); } /* @@ -223,10 +222,9 @@ static int dice_probe(struct fw_unit *unit, } /* Allocate this independent of sound card instance. */ - dice = kzalloc(sizeof(struct snd_dice), GFP_KERNEL); - if (dice == NULL) + dice = devm_kzalloc(&unit->device, sizeof(struct snd_dice), GFP_KERNEL); + if (!dice) return -ENOMEM; - dice->unit = fw_unit_get(unit); dev_set_drvdata(&unit->device, dice); diff --git a/sound/firewire/digi00x/digi00x.c b/sound/firewire/digi00x/digi00x.c index ef689997d6a5..654420f1c9bd 100644 --- a/sound/firewire/digi00x/digi00x.c +++ b/sound/firewire/digi00x/digi00x.c @@ -46,10 +46,8 @@ static void dg00x_free(struct snd_dg00x *dg00x) snd_dg00x_stream_destroy_duplex(dg00x); snd_dg00x_transaction_unregister(dg00x); - fw_unit_put(dg00x->unit); - mutex_destroy(&dg00x->mutex); - kfree(dg00x); + fw_unit_put(dg00x->unit); } static void dg00x_card_free(struct snd_card *card) @@ -120,8 +118,9 @@ static int snd_dg00x_probe(struct fw_unit *unit, struct snd_dg00x *dg00x; /* Allocate this independent of sound card instance. */ - dg00x = kzalloc(sizeof(struct snd_dg00x), GFP_KERNEL); - if (dg00x == NULL) + dg00x = devm_kzalloc(&unit->device, sizeof(struct snd_dg00x), + GFP_KERNEL); + if (!dg00x) return -ENOMEM; dg00x->unit = fw_unit_get(unit); diff --git a/sound/firewire/fireface/ff.c b/sound/firewire/fireface/ff.c index 4974bc7980e9..98731bd8816f 100644 --- a/sound/firewire/fireface/ff.c +++ b/sound/firewire/fireface/ff.c @@ -32,10 +32,8 @@ static void ff_free(struct snd_ff *ff) snd_ff_stream_destroy_duplex(ff); snd_ff_transaction_unregister(ff); - fw_unit_put(ff->unit); - mutex_destroy(&ff->mutex); - kfree(ff); + fw_unit_put(ff->unit); } static void ff_card_free(struct snd_card *card) @@ -102,11 +100,9 @@ static int snd_ff_probe(struct fw_unit *unit, { struct snd_ff *ff; - ff = kzalloc(sizeof(struct snd_ff), GFP_KERNEL); - if (ff == NULL) + ff = devm_kzalloc(&unit->device, sizeof(struct snd_ff), GFP_KERNEL); + if (!ff) return -ENOMEM; - - /* initialize myself */ ff->unit = fw_unit_get(unit); dev_set_drvdata(&unit->device, ff); diff --git a/sound/firewire/fireworks/fireworks.c b/sound/firewire/fireworks/fireworks.c index f2d073365cf6..2ff7b9cff9b0 100644 --- a/sound/firewire/fireworks/fireworks.c +++ b/sound/firewire/fireworks/fireworks.c @@ -188,12 +188,11 @@ static void efw_free(struct snd_efw *efw) { snd_efw_stream_destroy_duplex(efw); snd_efw_transaction_remove_instance(efw); - fw_unit_put(efw->unit); kfree(efw->resp_buf); mutex_destroy(&efw->mutex); - kfree(efw); + fw_unit_put(efw->unit); } /* @@ -312,10 +311,9 @@ efw_probe(struct fw_unit *unit, const struct ieee1394_device_id *entry) { struct snd_efw *efw; - efw = kzalloc(sizeof(struct snd_efw), GFP_KERNEL); + efw = devm_kzalloc(&unit->device, sizeof(struct snd_efw), GFP_KERNEL); if (efw == NULL) return -ENOMEM; - efw->unit = fw_unit_get(unit); dev_set_drvdata(&unit->device, efw); diff --git a/sound/firewire/motu/motu.c b/sound/firewire/motu/motu.c index 300d31b6f191..fd5726424c7a 100644 --- a/sound/firewire/motu/motu.c +++ b/sound/firewire/motu/motu.c @@ -57,10 +57,9 @@ static void motu_free(struct snd_motu *motu) snd_motu_transaction_unregister(motu); snd_motu_stream_destroy_duplex(motu); - fw_unit_put(motu->unit); mutex_destroy(&motu->mutex); - kfree(motu); + fw_unit_put(motu->unit); } /* @@ -143,14 +142,13 @@ static int motu_probe(struct fw_unit *unit, struct snd_motu *motu; /* Allocate this independently of sound card instance. */ - motu = kzalloc(sizeof(struct snd_motu), GFP_KERNEL); - if (motu == NULL) + motu = devm_kzalloc(&unit->device, sizeof(struct snd_motu), GFP_KERNEL); + if (!motu) return -ENOMEM; - - motu->spec = (const struct snd_motu_spec *)entry->driver_data; motu->unit = fw_unit_get(unit); dev_set_drvdata(&unit->device, motu); + motu->spec = (const struct snd_motu_spec *)entry->driver_data; mutex_init(&motu->mutex); spin_lock_init(&motu->lock); init_waitqueue_head(&motu->hwdep_wait); diff --git a/sound/firewire/oxfw/oxfw.c b/sound/firewire/oxfw/oxfw.c index 2ea8be6c8584..b892a8642204 100644 --- a/sound/firewire/oxfw/oxfw.c +++ b/sound/firewire/oxfw/oxfw.c @@ -121,8 +121,6 @@ static void oxfw_free(struct snd_oxfw *oxfw) if (oxfw->has_output) snd_oxfw_stream_destroy_simplex(oxfw, &oxfw->tx_stream); - fw_unit_put(oxfw->unit); - for (i = 0; i < SND_OXFW_STREAM_FORMAT_ENTRIES; i++) { kfree(oxfw->tx_stream_formats[i]); kfree(oxfw->rx_stream_formats[i]); @@ -130,7 +128,7 @@ static void oxfw_free(struct snd_oxfw *oxfw) kfree(oxfw->spec); mutex_destroy(&oxfw->mutex); - kfree(oxfw); + fw_unit_put(oxfw->unit); } /* @@ -293,14 +291,13 @@ static int oxfw_probe(struct fw_unit *unit, return -ENODEV; /* Allocate this independent of sound card instance. */ - oxfw = kzalloc(sizeof(struct snd_oxfw), GFP_KERNEL); - if (oxfw == NULL) + oxfw = devm_kzalloc(&unit->device, sizeof(struct snd_oxfw), GFP_KERNEL); + if (!oxfw) return -ENOMEM; - - oxfw->entry = entry; oxfw->unit = fw_unit_get(unit); dev_set_drvdata(&unit->device, oxfw); + oxfw->entry = entry; mutex_init(&oxfw->mutex); spin_lock_init(&oxfw->lock); init_waitqueue_head(&oxfw->hwdep_wait); diff --git a/sound/firewire/tascam/tascam.c b/sound/firewire/tascam/tascam.c index d3fdc463a884..53f20153ba71 100644 --- a/sound/firewire/tascam/tascam.c +++ b/sound/firewire/tascam/tascam.c @@ -90,10 +90,8 @@ static void tscm_free(struct snd_tscm *tscm) snd_tscm_transaction_unregister(tscm); snd_tscm_stream_destroy_duplex(tscm); - fw_unit_put(tscm->unit); - mutex_destroy(&tscm->mutex); - kfree(tscm); + fw_unit_put(tscm->unit); } static void tscm_card_free(struct snd_card *card) @@ -164,11 +162,9 @@ static int snd_tscm_probe(struct fw_unit *unit, struct snd_tscm *tscm; /* Allocate this independent of sound card instance. */ - tscm = kzalloc(sizeof(struct snd_tscm), GFP_KERNEL); - if (tscm == NULL) + tscm = devm_kzalloc(&unit->device, sizeof(struct snd_tscm), GFP_KERNEL); + if (!tscm) return -ENOMEM; - - /* initialize myself */ tscm->unit = fw_unit_get(unit); dev_set_drvdata(&unit->device, tscm); From a3aaf7d2bd388caea2bd0fba266b815ac708c49d Mon Sep 17 00:00:00 2001 From: Takashi Sakamoto Date: Wed, 3 Oct 2018 08:21:51 +0900 Subject: [PATCH 210/299] ALSA: bebob: use managed-resource to maintain data specific to M-Audio FW-1814/ProjectMix I/O ALSA bebob driver allocates memory object for data specific to M-Audio FW-1884/ProjectMix I/O. The object is to maintain format of isochronous packet payload for packet streaming by components for ALSA rawMIDI/PCM interfaces. The object can be released as managed-resource of 'struct snd_card.card_dev'. This commit uses managed-resource of the sound card device for this purpose. Signed-off-by: Takashi Sakamoto Signed-off-by: Takashi Iwai --- sound/firewire/bebob/bebob.c | 4 ---- sound/firewire/bebob/bebob_maudio.c | 5 +++-- 2 files changed, 3 insertions(+), 6 deletions(-) diff --git a/sound/firewire/bebob/bebob.c b/sound/firewire/bebob/bebob.c index fb05f2c1b60b..72b04214a3b5 100644 --- a/sound/firewire/bebob/bebob.c +++ b/sound/firewire/bebob/bebob.c @@ -130,8 +130,6 @@ static void bebob_free(struct snd_bebob *bebob) { snd_bebob_stream_destroy_duplex(bebob); - kfree(bebob->maudio_special_quirk); - mutex_destroy(&bebob->mutex); fw_unit_put(bebob->unit); } @@ -262,8 +260,6 @@ do_registration(struct work_struct *work) error: mutex_unlock(&devices_mutex); snd_bebob_stream_destroy_duplex(bebob); - kfree(bebob->maudio_special_quirk); - bebob->maudio_special_quirk = NULL; snd_card_free(bebob->card); dev_info(&bebob->unit->device, "Sound card registration failed: %d\n", err); diff --git a/sound/firewire/bebob/bebob_maudio.c b/sound/firewire/bebob/bebob_maudio.c index c266997ad299..51152ca4af57 100644 --- a/sound/firewire/bebob/bebob_maudio.c +++ b/sound/firewire/bebob/bebob_maudio.c @@ -261,8 +261,9 @@ snd_bebob_maudio_special_discover(struct snd_bebob *bebob, bool is1814) struct special_params *params; int err; - params = kzalloc(sizeof(struct special_params), GFP_KERNEL); - if (params == NULL) + params = devm_kzalloc(&bebob->card->card_dev, + sizeof(struct special_params), GFP_KERNEL); + if (!params) return -ENOMEM; mutex_lock(&bebob->mutex); From 784fffbcfe117b508ff628cf296541ab70463140 Mon Sep 17 00:00:00 2001 From: Takashi Sakamoto Date: Wed, 3 Oct 2018 08:21:52 +0900 Subject: [PATCH 211/299] ALSA: fireworks: use managed-resource to maintain response buffer ALSA fireworks driver allocates memory object to handle response from target unit. The object is used to initiate transaction unique to Fireworks board module. This can be released as managed-resource of 'struct snd_card.card_dev'. This commit uses managed-resource of the sound card device for this purpose. Signed-off-by: Takashi Sakamoto Signed-off-by: Takashi Iwai --- sound/firewire/fireworks/fireworks.c | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/sound/firewire/fireworks/fireworks.c b/sound/firewire/fireworks/fireworks.c index 2ff7b9cff9b0..f680e2f27806 100644 --- a/sound/firewire/fireworks/fireworks.c +++ b/sound/firewire/fireworks/fireworks.c @@ -189,8 +189,6 @@ static void efw_free(struct snd_efw *efw) snd_efw_stream_destroy_duplex(efw); snd_efw_transaction_remove_instance(efw); - kfree(efw->resp_buf); - mutex_destroy(&efw->mutex); fw_unit_put(efw->unit); } @@ -247,8 +245,9 @@ do_registration(struct work_struct *work) /* prepare response buffer */ snd_efw_resp_buf_size = clamp(snd_efw_resp_buf_size, SND_EFW_RESPONSE_MAXIMUM_BYTES, 4096U); - efw->resp_buf = kzalloc(snd_efw_resp_buf_size, GFP_KERNEL); - if (efw->resp_buf == NULL) { + efw->resp_buf = devm_kzalloc(&efw->card->card_dev, + snd_efw_resp_buf_size, GFP_KERNEL); + if (!efw->resp_buf) { err = -ENOMEM; goto error; } @@ -300,8 +299,6 @@ error: snd_efw_transaction_remove_instance(efw); snd_efw_stream_destroy_duplex(efw); snd_card_free(efw->card); - kfree(efw->resp_buf); - efw->resp_buf = NULL; dev_info(&efw->unit->device, "Sound card registration failed: %d\n", err); } From 72bc8c4378f82307ff09f0959011fef2c818146d Mon Sep 17 00:00:00 2001 From: Takashi Sakamoto Date: Wed, 3 Oct 2018 08:21:53 +0900 Subject: [PATCH 212/299] ALSA: oxfw: use managed-resource to maintain model-specific data ALSA oxfw driver allocates memory objects for data specific to some models. These objects are used to maintain functionalities specific to the models for ALSA rawMIDI/control interfaces. They can be released as managed-resource of 'struct snd_card.card_dev'. This commit uses managed-resource of the sound card device for this purpose. Signed-off-by: Takashi Sakamoto Signed-off-by: Takashi Iwai --- sound/firewire/oxfw/oxfw-scs1x.c | 5 +++-- sound/firewire/oxfw/oxfw-spkr.c | 5 +++-- sound/firewire/oxfw/oxfw.c | 3 --- 3 files changed, 6 insertions(+), 7 deletions(-) diff --git a/sound/firewire/oxfw/oxfw-scs1x.c b/sound/firewire/oxfw/oxfw-scs1x.c index f33497cdc706..9d9545880a28 100644 --- a/sound/firewire/oxfw/oxfw-scs1x.c +++ b/sound/firewire/oxfw/oxfw-scs1x.c @@ -372,8 +372,9 @@ int snd_oxfw_scs1x_add(struct snd_oxfw *oxfw) struct fw_scs1x *scs; int err; - scs = kzalloc(sizeof(struct fw_scs1x), GFP_KERNEL); - if (scs == NULL) + scs = devm_kzalloc(&oxfw->card->card_dev, sizeof(struct fw_scs1x), + GFP_KERNEL); + if (!scs) return -ENOMEM; scs->fw_dev = fw_parent_device(oxfw->unit); oxfw->spec = scs; diff --git a/sound/firewire/oxfw/oxfw-spkr.c b/sound/firewire/oxfw/oxfw-spkr.c index cb905af0660d..66d4b1f73f0f 100644 --- a/sound/firewire/oxfw/oxfw-spkr.c +++ b/sound/firewire/oxfw/oxfw-spkr.c @@ -270,8 +270,9 @@ int snd_oxfw_add_spkr(struct snd_oxfw *oxfw, bool is_lacie) unsigned int i, first_ch; int err; - spkr = kzalloc(sizeof(struct fw_spkr), GFP_KERNEL); - if (spkr == NULL) + spkr = devm_kzalloc(&oxfw->card->card_dev, sizeof(struct fw_spkr), + GFP_KERNEL); + if (!spkr) return -ENOMEM; oxfw->spec = spkr; diff --git a/sound/firewire/oxfw/oxfw.c b/sound/firewire/oxfw/oxfw.c index b892a8642204..06d791acfdc5 100644 --- a/sound/firewire/oxfw/oxfw.c +++ b/sound/firewire/oxfw/oxfw.c @@ -126,7 +126,6 @@ static void oxfw_free(struct snd_oxfw *oxfw) kfree(oxfw->rx_stream_formats[i]); } - kfree(oxfw->spec); mutex_destroy(&oxfw->mutex); fw_unit_put(oxfw->unit); } @@ -276,8 +275,6 @@ error: oxfw->rx_stream_formats[i] = NULL; } snd_card_free(oxfw->card); - kfree(oxfw->spec); - oxfw->spec = NULL; dev_info(&oxfw->unit->device, "Sound card registration failed: %d\n", err); } From cd3b7116b57527f659b96ff6988d2de3d448c5b3 Mon Sep 17 00:00:00 2001 From: Takashi Sakamoto Date: Wed, 3 Oct 2018 08:21:54 +0900 Subject: [PATCH 213/299] ALSA: oxfw: use managed-resource to maintain cache of stream formats ALSA oxfw driver allocates memory objects for cache of stream formats. The objects are used to maintain packet streaming by components for ALSA rawMIDI/PCM interface. They can be released as managed-resource of 'struct snd_card.card_dev'. This commit uses managed-resource of the sound card device for this purpose. Signed-off-by: Takashi Sakamoto Signed-off-by: Takashi Iwai --- sound/firewire/oxfw/oxfw-stream.c | 13 ++++++++----- sound/firewire/oxfw/oxfw.c | 14 -------------- 2 files changed, 8 insertions(+), 19 deletions(-) diff --git a/sound/firewire/oxfw/oxfw-stream.c b/sound/firewire/oxfw/oxfw-stream.c index d9361f352133..f230a9e44c3c 100644 --- a/sound/firewire/oxfw/oxfw-stream.c +++ b/sound/firewire/oxfw/oxfw-stream.c @@ -517,8 +517,9 @@ assume_stream_formats(struct snd_oxfw *oxfw, enum avc_general_plug_dir dir, if (err < 0) goto end; - formats[eid] = kmemdup(buf, *len, GFP_KERNEL); - if (formats[eid] == NULL) { + formats[eid] = devm_kmemdup(&oxfw->card->card_dev, buf, *len, + GFP_KERNEL); + if (!formats[eid]) { err = -ENOMEM; goto end; } @@ -535,7 +536,8 @@ assume_stream_formats(struct snd_oxfw *oxfw, enum avc_general_plug_dir dir, continue; eid++; - formats[eid] = kmemdup(buf, *len, GFP_KERNEL); + formats[eid] = devm_kmemdup(&oxfw->card->card_dev, buf, *len, + GFP_KERNEL); if (formats[eid] == NULL) { err = -ENOMEM; goto end; @@ -597,8 +599,9 @@ static int fill_stream_formats(struct snd_oxfw *oxfw, if (err < 0) break; - formats[eid] = kmemdup(buf, len, GFP_KERNEL); - if (formats[eid] == NULL) { + formats[eid] = devm_kmemdup(&oxfw->card->card_dev, buf, len, + GFP_KERNEL); + if (!formats[eid]) { err = -ENOMEM; break; } diff --git a/sound/firewire/oxfw/oxfw.c b/sound/firewire/oxfw/oxfw.c index 06d791acfdc5..6ac551786b93 100644 --- a/sound/firewire/oxfw/oxfw.c +++ b/sound/firewire/oxfw/oxfw.c @@ -115,17 +115,10 @@ end: static void oxfw_free(struct snd_oxfw *oxfw) { - unsigned int i; - snd_oxfw_stream_destroy_simplex(oxfw, &oxfw->rx_stream); if (oxfw->has_output) snd_oxfw_stream_destroy_simplex(oxfw, &oxfw->tx_stream); - for (i = 0; i < SND_OXFW_STREAM_FORMAT_ENTRIES; i++) { - kfree(oxfw->tx_stream_formats[i]); - kfree(oxfw->rx_stream_formats[i]); - } - mutex_destroy(&oxfw->mutex); fw_unit_put(oxfw->unit); } @@ -205,7 +198,6 @@ static int detect_quirks(struct snd_oxfw *oxfw) static void do_registration(struct work_struct *work) { struct snd_oxfw *oxfw = container_of(work, struct snd_oxfw, dwork.work); - int i; int err; if (oxfw->registered) @@ -268,12 +260,6 @@ error: snd_oxfw_stream_destroy_simplex(oxfw, &oxfw->rx_stream); if (oxfw->has_output) snd_oxfw_stream_destroy_simplex(oxfw, &oxfw->tx_stream); - for (i = 0; i < SND_OXFW_STREAM_FORMAT_ENTRIES; ++i) { - kfree(oxfw->tx_stream_formats[i]); - oxfw->tx_stream_formats[i] = NULL; - kfree(oxfw->rx_stream_formats[i]); - oxfw->rx_stream_formats[i] = NULL; - } snd_card_free(oxfw->card); dev_info(&oxfw->unit->device, "Sound card registration failed: %d\n", err); From 9c80c5a8831471e0a3e139aad1b0d4c0fdc50b2f Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Wed, 3 Oct 2018 19:31:44 +0200 Subject: [PATCH 214/299] ASoC: intel: skylake: Add missing break in skl_tplg_get_token() skl_tplg_get_token() misses a break in the big switch() block for SKL_TKN_U8_CORE_ID entry. Spotted nicely by -Wimplicit-fallthrough compiler option. Fixes: 6277e83292a2 ("ASoC: Intel: Skylake: Parse vendor tokens to build module data") Cc: Signed-off-by: Takashi Iwai Signed-off-by: Mark Brown --- sound/soc/intel/skylake/skl-topology.c | 1 + 1 file changed, 1 insertion(+) diff --git a/sound/soc/intel/skylake/skl-topology.c b/sound/soc/intel/skylake/skl-topology.c index 52a9915da0f5..cf8848b779dc 100644 --- a/sound/soc/intel/skylake/skl-topology.c +++ b/sound/soc/intel/skylake/skl-topology.c @@ -2460,6 +2460,7 @@ static int skl_tplg_get_token(struct device *dev, case SKL_TKN_U8_CORE_ID: mconfig->core_id = tkn_elem->value; + break; case SKL_TKN_U8_MOD_TYPE: mconfig->m_type = tkn_elem->value; From 8e9f7265eda9f3a662ca1ca47a69042a7840735b Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Mon, 1 Oct 2018 19:44:30 +0300 Subject: [PATCH 215/299] ASoC: qdsp6: q6asm-dai: checking NULL vs IS_ERR() The q6asm_audio_client_alloc() doesn't return NULL, it returns error pointers. Fixes: 2a9e92d371db ("ASoC: qdsp6: q6asm: Add q6asm dai driver") Signed-off-by: Dan Carpenter Signed-off-by: Mark Brown --- sound/soc/qcom/qdsp6/q6asm-dai.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/sound/soc/qcom/qdsp6/q6asm-dai.c b/sound/soc/qcom/qdsp6/q6asm-dai.c index c3806d7037fc..a16c71c03058 100644 --- a/sound/soc/qcom/qdsp6/q6asm-dai.c +++ b/sound/soc/qcom/qdsp6/q6asm-dai.c @@ -318,10 +318,11 @@ static int q6asm_dai_open(struct snd_pcm_substream *substream) prtd->audio_client = q6asm_audio_client_alloc(dev, (q6asm_cb)event_handler, prtd, stream_id, LEGACY_PCM_MODE); - if (!prtd->audio_client) { + if (IS_ERR(prtd->audio_client)) { pr_info("%s: Could not allocate memory\n", __func__); + ret = PTR_ERR(prtd->audio_client); kfree(prtd); - return -ENOMEM; + return ret; } if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) From cfe9ee5f2b7808ceec21df83a45e38afcc647153 Mon Sep 17 00:00:00 2001 From: Daniel Mack Date: Wed, 3 Oct 2018 21:36:27 +0200 Subject: [PATCH 216/299] ASoC: pxa-ssp: enable and disable extclk if given If a "extclk" clock is given, enable and disable it when appropriate. Signed-off-by: Daniel Mack Signed-off-by: Mark Brown --- sound/soc/pxa/pxa-ssp.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/sound/soc/pxa/pxa-ssp.c b/sound/soc/pxa/pxa-ssp.c index 69033e1a84e6..adcf8ba9d287 100644 --- a/sound/soc/pxa/pxa-ssp.c +++ b/sound/soc/pxa/pxa-ssp.c @@ -103,6 +103,9 @@ static int pxa_ssp_startup(struct snd_pcm_substream *substream, pxa_ssp_disable(ssp); } + if (priv->extclk) + clk_prepare_enable(priv->extclk); + dma = kzalloc(sizeof(struct snd_dmaengine_dai_dma_data), GFP_KERNEL); if (!dma) return -ENOMEM; @@ -125,6 +128,9 @@ static void pxa_ssp_shutdown(struct snd_pcm_substream *substream, clk_disable_unprepare(ssp->clk); } + if (priv->extclk) + clk_disable_unprepare(priv->extclk); + kfree(snd_soc_dai_get_dma_data(cpu_dai, substream)); snd_soc_dai_set_dma_data(cpu_dai, substream, NULL); } From 466dee75b3364d05b43ddfe41ef2e8887b6a3ea7 Mon Sep 17 00:00:00 2001 From: Daniel Mack Date: Wed, 3 Oct 2018 21:32:34 +0200 Subject: [PATCH 217/299] ASoC: add fault detect recovery property to DT bindings The driver already has support for setting the FDRB bit in the CONFA register through platform data, but there was no property to set it in the device-tree bindings. Signed-off-by: Daniel Mack Signed-off-by: Mark Brown --- Documentation/devicetree/bindings/sound/st,sta32x.txt | 3 +++ sound/soc/codecs/sta32x.c | 2 ++ 2 files changed, 5 insertions(+) diff --git a/Documentation/devicetree/bindings/sound/st,sta32x.txt b/Documentation/devicetree/bindings/sound/st,sta32x.txt index 255de3ae5b2f..ff4a685a4303 100644 --- a/Documentation/devicetree/bindings/sound/st,sta32x.txt +++ b/Documentation/devicetree/bindings/sound/st,sta32x.txt @@ -39,6 +39,9 @@ Optional properties: - st,thermal-warning-recover: If present, thermal warning recovery is enabled. + - st,fault-detect-recovery: + If present, fault detect recovery is enabled. + - st,thermal-warning-adjustment: If present, thermal warning adjustment is enabled. diff --git a/sound/soc/codecs/sta32x.c b/sound/soc/codecs/sta32x.c index d5035f2f2b2b..22de1593443c 100644 --- a/sound/soc/codecs/sta32x.c +++ b/sound/soc/codecs/sta32x.c @@ -1038,6 +1038,8 @@ static int sta32x_probe_dt(struct device *dev, struct sta32x_priv *sta32x) of_property_read_u8(np, "st,ch3-output-mapping", &pdata->ch3_output_mapping); + if (of_get_property(np, "st,fault-detect-recovery", NULL)) + pdata->fault_detect_recovery = 1; if (of_get_property(np, "st,thermal-warning-recovery", NULL)) pdata->thermal_warning_recovery = 1; if (of_get_property(np, "st,thermal-warning-adjustment", NULL)) From 757b1aa00259a44f94bd120b9637720b9aaf36eb Mon Sep 17 00:00:00 2001 From: Tzung-Bi Shih Date: Thu, 4 Oct 2018 18:43:01 +0800 Subject: [PATCH 218/299] ASoC: ts3a227e: fix a typo in documentation There is no "MACBIAS". It should be "MICBIAS". Signed-off-by: Tzung-Bi Shih Signed-off-by: Mark Brown --- Documentation/devicetree/bindings/sound/ts3a227e.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Documentation/devicetree/bindings/sound/ts3a227e.txt b/Documentation/devicetree/bindings/sound/ts3a227e.txt index 3ed8359144d3..21ab45bc7e8f 100644 --- a/Documentation/devicetree/bindings/sound/ts3a227e.txt +++ b/Documentation/devicetree/bindings/sound/ts3a227e.txt @@ -14,7 +14,7 @@ Required properties: Optional properies: - ti,micbias: Intended MICBIAS voltage (datasheet section 9.6.7). - Select 0/1/2/3/4/5/6/7 to specify MACBIAS voltage + Select 0/1/2/3/4/5/6/7 to specify MICBIAS voltage 2.1V/2.2V/2.3V/2.4V/2.5V/2.6V/2.7V/2.8V Default value is "1" (2.2V). From 6aea5702e27ebc85747d6e4943a0c378e1752be0 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Thu, 13 Sep 2018 08:20:43 +0200 Subject: [PATCH 219/299] ALSA: rawmidi: A lightweight function to discard pending bytes For discarding the pending bytes on rawmidi, we process with a loop of snd_rawmidi_transmit() which is just a waste of CPU power. Implement a lightweight API function to discard the pending bytes and the proceed the ring buffer instantly, and use it instead of open codes. Signed-off-by: Takashi Iwai --- include/sound/rawmidi.h | 1 + sound/core/rawmidi.c | 22 ++++++++++++++++++++++ sound/core/seq/seq_virmidi.c | 4 +--- sound/usb/midi.c | 3 +-- 4 files changed, 25 insertions(+), 5 deletions(-) diff --git a/include/sound/rawmidi.h b/include/sound/rawmidi.h index 6665cb29e1a2..3b5a061132b6 100644 --- a/include/sound/rawmidi.h +++ b/include/sound/rawmidi.h @@ -171,6 +171,7 @@ int __snd_rawmidi_transmit_peek(struct snd_rawmidi_substream *substream, unsigned char *buffer, int count); int __snd_rawmidi_transmit_ack(struct snd_rawmidi_substream *substream, int count); +int snd_rawmidi_proceed(struct snd_rawmidi_substream *substream); /* main midi functions */ diff --git a/sound/core/rawmidi.c b/sound/core/rawmidi.c index 08d5662039e3..ee601d7f0926 100644 --- a/sound/core/rawmidi.c +++ b/sound/core/rawmidi.c @@ -1236,6 +1236,28 @@ int snd_rawmidi_transmit(struct snd_rawmidi_substream *substream, } EXPORT_SYMBOL(snd_rawmidi_transmit); +/** + * snd_rawmidi_proceed - Discard the all pending bytes and proceed + * @substream: rawmidi substream + * + * Return: the number of discarded bytes + */ +int snd_rawmidi_proceed(struct snd_rawmidi_substream *substream) +{ + struct snd_rawmidi_runtime *runtime = substream->runtime; + unsigned long flags; + int count = 0; + + spin_lock_irqsave(&runtime->lock, flags); + if (runtime->avail < runtime->buffer_size) { + count = runtime->buffer_size - runtime->avail; + __snd_rawmidi_transmit_ack(substream, count); + } + spin_unlock_irqrestore(&runtime->lock, flags); + return count; +} +EXPORT_SYMBOL(snd_rawmidi_proceed); + static long snd_rawmidi_kernel_write1(struct snd_rawmidi_substream *substream, const unsigned char __user *userbuf, const unsigned char *kernelbuf, diff --git a/sound/core/seq/seq_virmidi.c b/sound/core/seq/seq_virmidi.c index cb988efd1ed0..e5a40795914a 100644 --- a/sound/core/seq/seq_virmidi.c +++ b/sound/core/seq/seq_virmidi.c @@ -149,9 +149,7 @@ static void snd_vmidi_output_work(struct work_struct *work) /* discard the outputs in dispatch mode unless subscribed */ if (vmidi->seq_mode == SNDRV_VIRMIDI_SEQ_DISPATCH && !(vmidi->rdev->flags & SNDRV_VIRMIDI_SUBSCRIBE)) { - char buf[32]; - while (snd_rawmidi_transmit(substream, buf, sizeof(buf)) > 0) - ; /* ignored */ + snd_rawmidi_proceed(substream); return; } diff --git a/sound/usb/midi.c b/sound/usb/midi.c index dcfc546d81b9..b737f0ec77d0 100644 --- a/sound/usb/midi.c +++ b/sound/usb/midi.c @@ -1175,8 +1175,7 @@ static void snd_usbmidi_output_trigger(struct snd_rawmidi_substream *substream, if (port->ep->umidi->disconnected) { /* gobble up remaining bytes to prevent wait in * snd_rawmidi_drain_output */ - while (!snd_rawmidi_transmit_empty(substream)) - snd_rawmidi_transmit_ack(substream, 1); + snd_rawmidi_proceed(substream); return; } tasklet_schedule(&port->ep->tasklet); From d153135e93a50cdb6f1b52e238909e9965b56056 Mon Sep 17 00:00:00 2001 From: Michael Pobega Date: Thu, 4 Oct 2018 14:58:21 -0400 Subject: [PATCH 220/299] ALSA: hda/sigmatel - Disable automute for Elo VuPoint The Elo VuPoint 15MX has two headphone jacks of which neither work by default. Disabling automute allows ALSA to work normally with the speakers & left headphone jack. Future pin configuration changes may be required in the future to get the right headphone jack working in tandem. Signed-off-by: Michael Pobega Signed-off-by: Takashi Iwai --- sound/pci/hda/patch_sigmatel.c | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/sound/pci/hda/patch_sigmatel.c b/sound/pci/hda/patch_sigmatel.c index d16a25a395c9..1b6ecfb01759 100644 --- a/sound/pci/hda/patch_sigmatel.c +++ b/sound/pci/hda/patch_sigmatel.c @@ -77,6 +77,7 @@ enum { STAC_DELL_M6_BOTH, STAC_DELL_EQ, STAC_ALIENWARE_M17X, + STAC_ELO_VUPOINT_15MX, STAC_92HD89XX_HP_FRONT_JACK, STAC_92HD89XX_HP_Z1_G2_RIGHT_MIC_JACK, STAC_92HD73XX_ASUS_MOBO, @@ -1879,6 +1880,18 @@ static void stac92hd73xx_fixup_no_jd(struct hda_codec *codec, codec->no_jack_detect = 1; } + +static void stac92hd73xx_disable_automute(struct hda_codec *codec, + const struct hda_fixup *fix, int action) +{ + struct sigmatel_spec *spec = codec->spec; + + if (action != HDA_FIXUP_ACT_PRE_PROBE) + return; + + spec->gen.suppress_auto_mute = 1; +} + static const struct hda_fixup stac92hd73xx_fixups[] = { [STAC_92HD73XX_REF] = { .type = HDA_FIXUP_FUNC, @@ -1904,6 +1917,10 @@ static const struct hda_fixup stac92hd73xx_fixups[] = { .type = HDA_FIXUP_FUNC, .v.func = stac92hd73xx_fixup_alienware_m17x, }, + [STAC_ELO_VUPOINT_15MX] = { + .type = HDA_FIXUP_FUNC, + .v.func = stac92hd73xx_disable_automute, + }, [STAC_92HD73XX_INTEL] = { .type = HDA_FIXUP_PINS, .v.pins = intel_dg45id_pin_configs, @@ -1942,6 +1959,7 @@ static const struct hda_model_fixup stac92hd73xx_models[] = { { .id = STAC_DELL_M6_BOTH, .name = "dell-m6" }, { .id = STAC_DELL_EQ, .name = "dell-eq" }, { .id = STAC_ALIENWARE_M17X, .name = "alienware" }, + { .id = STAC_ELO_VUPOINT_15MX, .name = "elo-vupoint-15mx" }, { .id = STAC_92HD73XX_ASUS_MOBO, .name = "asus-mobo" }, {} }; @@ -1991,6 +2009,8 @@ static const struct snd_pci_quirk stac92hd73xx_fixup_tbl[] = { "Alienware M17x", STAC_ALIENWARE_M17X), SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x0490, "Alienware M17x R3", STAC_DELL_EQ), + SND_PCI_QUIRK(0x1059, 0x1011, + "ELO VuPoint 15MX", STAC_ELO_VUPOINT_15MX), SND_PCI_QUIRK(PCI_VENDOR_ID_HP, 0x1927, "HP Z1 G2", STAC_92HD89XX_HP_Z1_G2_RIGHT_MIC_JACK), SND_PCI_QUIRK(PCI_VENDOR_ID_HP, 0x2b17, From c369c8db15d51fa175d2ba85928f79d16af6b562 Mon Sep 17 00:00:00 2001 From: Nicolas Huaman Date: Thu, 4 Oct 2018 16:42:05 +0200 Subject: [PATCH 221/299] ALSA: usb-audio: update quirk for B&W PX to remove microphone A quirk in snd-usb-audio was added to automate setting sample rate to 4800k and remove the previously exposed nonfunctional microphone for the Bowers & Wilkins PX: commit 240a8af929c7c57dcde28682725b29cf8474e8e5 https://lore.kernel.org/patchwork/patch/919689/ However the headphones where updated shortly after that to remove the unintentional microphone functionality. I guess because of this the headphones now crash when connecting them via USB while the quirk is active. Dmesg: snd-usb-audio: probe of 2-3:1.0 failed with error -22 usb 2-3: 2:1: cannot get min/max values for control 2 (id 2) This patch removes the microfone and allows the headphones to connect and work out of the box. It is based on the current mainline kernel and successfully applied an tested on my machine (4.18.10.arch1-1). Fixes: 240a8af929c7 ("ALSA: usb-audio: Add a quirck for B&W PX headphones") Signed-off-by: Nicolas Huaman Signed-off-by: Takashi Iwai --- sound/usb/quirks-table.h | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) diff --git a/sound/usb/quirks-table.h b/sound/usb/quirks-table.h index 08aa78007020..849953e5775c 100644 --- a/sound/usb/quirks-table.h +++ b/sound/usb/quirks-table.h @@ -3346,19 +3346,14 @@ AU0828_DEVICE(0x2040, 0x7270, "Hauppauge", "HVR-950Q"), .ifnum = 0, .type = QUIRK_AUDIO_STANDARD_MIXER, }, - /* Capture */ - { - .ifnum = 1, - .type = QUIRK_IGNORE_INTERFACE, - }, /* Playback */ { - .ifnum = 2, + .ifnum = 1, .type = QUIRK_AUDIO_FIXED_ENDPOINT, .data = &(const struct audioformat) { .formats = SNDRV_PCM_FMTBIT_S16_LE, .channels = 2, - .iface = 2, + .iface = 1, .altsetting = 1, .altset_idx = 1, .attributes = UAC_EP_CS_ATTR_FILL_MAX | From d39f1d68fe1de1f9dbe167a73f0f605226905e27 Mon Sep 17 00:00:00 2001 From: Jussi Laako Date: Fri, 5 Oct 2018 11:00:04 +0300 Subject: [PATCH 222/299] ALSA: usb-audio: Add custom mixer status quirks for RME CC devices Adds several vendor specific mixer quirks for RME's Class Compliant USB devices. These provide extra status information from the device otherwise not available. These include AES/SPDIF rate and status information, current system sampling rate and measured frequency. This information is especially useful in cases where device's clock is slaved to external clock source. Signed-off-by: Jussi Laako Signed-off-by: Takashi Iwai --- sound/usb/mixer_quirks.c | 381 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 381 insertions(+) diff --git a/sound/usb/mixer_quirks.c b/sound/usb/mixer_quirks.c index cbfb48bdea51..85ae0ff2382a 100644 --- a/sound/usb/mixer_quirks.c +++ b/sound/usb/mixer_quirks.c @@ -29,6 +29,7 @@ #include #include +#include #include #include #include @@ -1817,6 +1818,380 @@ static int dell_dock_mixer_init(struct usb_mixer_interface *mixer) return 0; } +/* RME Class Compliant device quirks */ + +#define SND_RME_GET_STATUS1 23 +#define SND_RME_GET_CURRENT_FREQ 17 +#define SND_RME_CLK_SYSTEM_SHIFT 16 +#define SND_RME_CLK_SYSTEM_MASK 0x1f +#define SND_RME_CLK_AES_SHIFT 8 +#define SND_RME_CLK_SPDIF_SHIFT 12 +#define SND_RME_CLK_AES_SPDIF_MASK 0xf +#define SND_RME_CLK_SYNC_SHIFT 6 +#define SND_RME_CLK_SYNC_MASK 0x3 +#define SND_RME_CLK_FREQMUL_SHIFT 18 +#define SND_RME_CLK_FREQMUL_MASK 0x7 +#define SND_RME_CLK_SYSTEM(x) \ + ((x >> SND_RME_CLK_SYSTEM_SHIFT) & SND_RME_CLK_SYSTEM_MASK) +#define SND_RME_CLK_AES(x) \ + ((x >> SND_RME_CLK_AES_SHIFT) & SND_RME_CLK_AES_SPDIF_MASK) +#define SND_RME_CLK_SPDIF(x) \ + ((x >> SND_RME_CLK_SPDIF_SHIFT) & SND_RME_CLK_AES_SPDIF_MASK) +#define SND_RME_CLK_SYNC(x) \ + ((x >> SND_RME_CLK_SYNC_SHIFT) & SND_RME_CLK_SYNC_MASK) +#define SND_RME_CLK_FREQMUL(x) \ + ((x >> SND_RME_CLK_FREQMUL_SHIFT) & SND_RME_CLK_FREQMUL_MASK) +#define SND_RME_CLK_AES_LOCK 0x1 +#define SND_RME_CLK_AES_SYNC 0x4 +#define SND_RME_CLK_SPDIF_LOCK 0x2 +#define SND_RME_CLK_SPDIF_SYNC 0x8 +#define SND_RME_SPDIF_IF_SHIFT 4 +#define SND_RME_SPDIF_FORMAT_SHIFT 5 +#define SND_RME_BINARY_MASK 0x1 +#define SND_RME_SPDIF_IF(x) \ + ((x >> SND_RME_SPDIF_IF_SHIFT) & SND_RME_BINARY_MASK) +#define SND_RME_SPDIF_FORMAT(x) \ + ((x >> SND_RME_SPDIF_FORMAT_SHIFT) & SND_RME_BINARY_MASK) + +static const u32 snd_rme_rate_table[] = { + 32000, 44100, 48000, 50000, + 64000, 88200, 96000, 100000, + 128000, 176400, 192000, 200000, + 256000, 352800, 384000, 400000, + 512000, 705600, 768000, 800000 +}; +/* maximum number of items for AES and S/PDIF rates for above table */ +#define SND_RME_RATE_IDX_AES_SPDIF_NUM 12 + +enum snd_rme_domain { + SND_RME_DOMAIN_SYSTEM, + SND_RME_DOMAIN_AES, + SND_RME_DOMAIN_SPDIF +}; + +enum snd_rme_clock_status { + SND_RME_CLOCK_NOLOCK, + SND_RME_CLOCK_LOCK, + SND_RME_CLOCK_SYNC +}; + +static int snd_rme_read_value(struct snd_usb_audio *chip, + unsigned int item, + u32 *value) +{ + struct usb_device *dev = chip->dev; + int err; + + err = snd_usb_ctl_msg(dev, usb_rcvctrlpipe(dev, 0), + item, + USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE, + 0, 0, + value, sizeof(*value)); + if (err < 0) + dev_err(&dev->dev, + "unable to issue vendor read request %d (ret = %d)", + item, err); + return err; +} + +static int snd_rme_get_status1(struct snd_kcontrol *kcontrol, + u32 *status1) +{ + struct usb_mixer_elem_list *list = snd_kcontrol_chip(kcontrol); + struct snd_usb_audio *chip = list->mixer->chip; + int err; + + err = snd_usb_lock_shutdown(chip); + if (err < 0) + return err; + err = snd_rme_read_value(chip, SND_RME_GET_STATUS1, status1); + snd_usb_unlock_shutdown(chip); + return err; +} + +static int snd_rme_rate_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + u32 status1; + u32 rate = 0; + int idx; + int err; + + err = snd_rme_get_status1(kcontrol, &status1); + if (err < 0) + return err; + switch (kcontrol->private_value) { + case SND_RME_DOMAIN_SYSTEM: + idx = SND_RME_CLK_SYSTEM(status1); + if (idx < ARRAY_SIZE(snd_rme_rate_table)) + rate = snd_rme_rate_table[idx]; + break; + case SND_RME_DOMAIN_AES: + idx = SND_RME_CLK_AES(status1); + if (idx < SND_RME_RATE_IDX_AES_SPDIF_NUM) + rate = snd_rme_rate_table[idx]; + break; + case SND_RME_DOMAIN_SPDIF: + idx = SND_RME_CLK_SPDIF(status1); + if (idx < SND_RME_RATE_IDX_AES_SPDIF_NUM) + rate = snd_rme_rate_table[idx]; + break; + default: + return -EINVAL; + } + ucontrol->value.integer.value[0] = rate; + return 0; +} + +static int snd_rme_sync_state_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + u32 status1; + int idx = SND_RME_CLOCK_NOLOCK; + int err; + + err = snd_rme_get_status1(kcontrol, &status1); + if (err < 0) + return err; + switch (kcontrol->private_value) { + case SND_RME_DOMAIN_AES: /* AES */ + if (status1 & SND_RME_CLK_AES_SYNC) + idx = SND_RME_CLOCK_SYNC; + else if (status1 & SND_RME_CLK_AES_LOCK) + idx = SND_RME_CLOCK_LOCK; + break; + case SND_RME_DOMAIN_SPDIF: /* SPDIF */ + if (status1 & SND_RME_CLK_SPDIF_SYNC) + idx = SND_RME_CLOCK_SYNC; + else if (status1 & SND_RME_CLK_SPDIF_LOCK) + idx = SND_RME_CLOCK_LOCK; + break; + default: + return -EINVAL; + } + ucontrol->value.enumerated.item[0] = idx; + return 0; +} + +static int snd_rme_spdif_if_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + u32 status1; + int err; + + err = snd_rme_get_status1(kcontrol, &status1); + if (err < 0) + return err; + ucontrol->value.enumerated.item[0] = SND_RME_SPDIF_IF(status1); + return 0; +} + +static int snd_rme_spdif_format_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + u32 status1; + int err; + + err = snd_rme_get_status1(kcontrol, &status1); + if (err < 0) + return err; + ucontrol->value.enumerated.item[0] = SND_RME_SPDIF_FORMAT(status1); + return 0; +} + +static int snd_rme_sync_source_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + u32 status1; + int err; + + err = snd_rme_get_status1(kcontrol, &status1); + if (err < 0) + return err; + ucontrol->value.enumerated.item[0] = SND_RME_CLK_SYNC(status1); + return 0; +} + +static int snd_rme_current_freq_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct usb_mixer_elem_list *list = snd_kcontrol_chip(kcontrol); + struct snd_usb_audio *chip = list->mixer->chip; + u32 status1; + const u64 num = 104857600000000ULL; + u32 den; + unsigned int freq; + int err; + + err = snd_usb_lock_shutdown(chip); + if (err < 0) + return err; + err = snd_rme_read_value(chip, SND_RME_GET_STATUS1, &status1); + if (err < 0) + goto end; + err = snd_rme_read_value(chip, SND_RME_GET_CURRENT_FREQ, &den); + if (err < 0) + goto end; + freq = (den == 0) ? 0 : div64_u64(num, den); + freq <<= SND_RME_CLK_FREQMUL(status1); + ucontrol->value.integer.value[0] = freq; + +end: + snd_usb_unlock_shutdown(chip); + return err; +} + +static int snd_rme_rate_info(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_info *uinfo) +{ + uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; + uinfo->count = 1; + switch (kcontrol->private_value) { + case SND_RME_DOMAIN_SYSTEM: + uinfo->value.integer.min = 32000; + uinfo->value.integer.max = 800000; + break; + case SND_RME_DOMAIN_AES: + case SND_RME_DOMAIN_SPDIF: + default: + uinfo->value.integer.min = 0; + uinfo->value.integer.max = 200000; + } + uinfo->value.integer.step = 0; + return 0; +} + +static int snd_rme_sync_state_info(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_info *uinfo) +{ + static const char *const sync_states[] = { + "No Lock", "Lock", "Sync" + }; + + return snd_ctl_enum_info(uinfo, 1, + ARRAY_SIZE(sync_states), sync_states); +} + +static int snd_rme_spdif_if_info(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_info *uinfo) +{ + static const char *const spdif_if[] = { + "Coaxial", "Optical" + }; + + return snd_ctl_enum_info(uinfo, 1, + ARRAY_SIZE(spdif_if), spdif_if); +} + +static int snd_rme_spdif_format_info(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_info *uinfo) +{ + static const char *const optical_type[] = { + "Consumer", "Professional" + }; + + return snd_ctl_enum_info(uinfo, 1, + ARRAY_SIZE(optical_type), optical_type); +} + +static int snd_rme_sync_source_info(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_info *uinfo) +{ + static const char *const sync_sources[] = { + "Internal", "AES", "SPDIF", "Internal" + }; + + return snd_ctl_enum_info(uinfo, 1, + ARRAY_SIZE(sync_sources), sync_sources); +} + +static struct snd_kcontrol_new snd_rme_controls[] = { + { + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + .name = "AES Rate", + .access = SNDRV_CTL_ELEM_ACCESS_READ | SNDRV_CTL_ELEM_ACCESS_VOLATILE, + .info = snd_rme_rate_info, + .get = snd_rme_rate_get, + .private_value = SND_RME_DOMAIN_AES + }, + { + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + .name = "AES Sync", + .access = SNDRV_CTL_ELEM_ACCESS_READ | SNDRV_CTL_ELEM_ACCESS_VOLATILE, + .info = snd_rme_sync_state_info, + .get = snd_rme_sync_state_get, + .private_value = SND_RME_DOMAIN_AES + }, + { + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + .name = "SPDIF Rate", + .access = SNDRV_CTL_ELEM_ACCESS_READ | SNDRV_CTL_ELEM_ACCESS_VOLATILE, + .info = snd_rme_rate_info, + .get = snd_rme_rate_get, + .private_value = SND_RME_DOMAIN_SPDIF + }, + { + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + .name = "SPDIF Sync", + .access = SNDRV_CTL_ELEM_ACCESS_READ | SNDRV_CTL_ELEM_ACCESS_VOLATILE, + .info = snd_rme_sync_state_info, + .get = snd_rme_sync_state_get, + .private_value = SND_RME_DOMAIN_SPDIF + }, + { + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + .name = "SPDIF Interface", + .access = SNDRV_CTL_ELEM_ACCESS_READ | SNDRV_CTL_ELEM_ACCESS_VOLATILE, + .info = snd_rme_spdif_if_info, + .get = snd_rme_spdif_if_get, + }, + { + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + .name = "SPDIF Format", + .access = SNDRV_CTL_ELEM_ACCESS_READ | SNDRV_CTL_ELEM_ACCESS_VOLATILE, + .info = snd_rme_spdif_format_info, + .get = snd_rme_spdif_format_get, + }, + { + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + .name = "Sync Source", + .access = SNDRV_CTL_ELEM_ACCESS_READ | SNDRV_CTL_ELEM_ACCESS_VOLATILE, + .info = snd_rme_sync_source_info, + .get = snd_rme_sync_source_get + }, + { + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + .name = "System Rate", + .access = SNDRV_CTL_ELEM_ACCESS_READ | SNDRV_CTL_ELEM_ACCESS_VOLATILE, + .info = snd_rme_rate_info, + .get = snd_rme_rate_get, + .private_value = SND_RME_DOMAIN_SYSTEM + }, + { + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + .name = "Current Frequency", + .access = SNDRV_CTL_ELEM_ACCESS_READ | SNDRV_CTL_ELEM_ACCESS_VOLATILE, + .info = snd_rme_rate_info, + .get = snd_rme_current_freq_get + } +}; + +static int snd_rme_controls_create(struct usb_mixer_interface *mixer) +{ + int err, i; + + for (i = 0; i < ARRAY_SIZE(snd_rme_controls); ++i) { + err = add_single_ctl_with_resume(mixer, 0, + NULL, + &snd_rme_controls[i], + NULL); + if (err < 0) + return err; + } + + return 0; +} + int snd_usb_mixer_apply_create_quirk(struct usb_mixer_interface *mixer) { int err = 0; @@ -1904,6 +2279,12 @@ int snd_usb_mixer_apply_create_quirk(struct usb_mixer_interface *mixer) case USB_ID(0x0bda, 0x4014): /* Dell WD15 dock */ err = dell_dock_mixer_init(mixer); break; + + case USB_ID(0x2a39, 0x3fd2): /* RME ADI-2 Pro */ + case USB_ID(0x2a39, 0x3fd3): /* RME ADI-2 DAC */ + case USB_ID(0x2a39, 0x3fd4): /* RME */ + err = snd_rme_controls_create(mixer); + break; } return err; From 7e29317928bd79a03a9c35816afa709988b5d31b Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Thu, 4 Oct 2018 20:30:02 +0200 Subject: [PATCH 223/299] ASoC: adau1761: Use the standard fall-through annotation As a preparatory patch for the upcoming -Wimplicit-fallthrough compiler checks, replace with the standard "fall through" annotation at the right place. It has to be put right before the next label. Signed-off-by: Takashi Iwai Signed-off-by: Mark Brown --- sound/soc/codecs/adau1761.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/sound/soc/codecs/adau1761.c b/sound/soc/codecs/adau1761.c index be136e981653..bef3e9e74c26 100644 --- a/sound/soc/codecs/adau1761.c +++ b/sound/soc/codecs/adau1761.c @@ -518,7 +518,8 @@ static int adau1761_setup_digmic_jackdetect(struct snd_soc_component *component) ARRAY_SIZE(adau1761_jack_detect_controls)); if (ret) return ret; - case ADAU1761_DIGMIC_JACKDET_PIN_MODE_NONE: /* fallthrough */ + /* fall through */ + case ADAU1761_DIGMIC_JACKDET_PIN_MODE_NONE: ret = snd_soc_dapm_add_routes(dapm, adau1761_no_dmic_routes, ARRAY_SIZE(adau1761_no_dmic_routes)); if (ret) From 641f7f2195735b4fe93b541ea3a792fe4fee2415 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Thu, 4 Oct 2018 20:30:03 +0200 Subject: [PATCH 224/299] ASoC: pcm186x: Use the standard fall-through annotation As a preparatory patch for the upcoming -Wimplicit-fallthrough compiler checks, replace with the standard "fall through" annotation. Unfortunately gcc doesn't understand the mixed comment lines. Signed-off-by: Takashi Iwai Signed-off-by: Mark Brown --- sound/soc/codecs/pcm186x.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/sound/soc/codecs/pcm186x.c b/sound/soc/codecs/pcm186x.c index 690c26e7389e..809b7e9f03ca 100644 --- a/sound/soc/codecs/pcm186x.c +++ b/sound/soc/codecs/pcm186x.c @@ -401,7 +401,8 @@ static int pcm186x_set_fmt(struct snd_soc_dai *dai, unsigned int format) break; case SND_SOC_DAIFMT_DSP_A: priv->tdm_offset += 1; - /* Fall through... DSP_A uses the same basic config as DSP_B + /* fall through */ + /* DSP_A uses the same basic config as DSP_B * except we need to shift the TDM output by one BCK cycle */ case SND_SOC_DAIFMT_DSP_B: From 0beeb4baf56bd9deb920712a4034541fb33bbbe0 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Thu, 4 Oct 2018 20:30:04 +0200 Subject: [PATCH 225/299] ASoC: rt274: Add fall-through annotations As a preparatory patch for the upcoming -Wimplicit-fallthrough compiler checks, add the "fall through" annotations in rt274 driver. Signed-off-by: Takashi Iwai Signed-off-by: Mark Brown --- sound/soc/codecs/rt274.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/sound/soc/codecs/rt274.c b/sound/soc/codecs/rt274.c index d88e67341083..0ef966d56bac 100644 --- a/sound/soc/codecs/rt274.c +++ b/sound/soc/codecs/rt274.c @@ -755,6 +755,7 @@ static int rt274_set_dai_pll(struct snd_soc_dai *dai, int pll_id, int source, break; default: dev_warn(component->dev, "invalid pll source, use BCLK\n"); + /* fall through */ case RT274_PLL2_S_BCLK: snd_soc_component_update_bits(component, RT274_PLL2_CTRL, RT274_PLL2_SRC_MASK, RT274_PLL2_SRC_BCLK); @@ -782,6 +783,7 @@ static int rt274_set_dai_pll(struct snd_soc_dai *dai, int pll_id, int source, break; default: dev_warn(component->dev, "invalid freq_in, assume 4.8M\n"); + /* fall through */ case 100: snd_soc_component_write(component, 0x7a, 0xaab6); snd_soc_component_write(component, 0x7b, 0x0301); From e4bfd61571f5db5c69a7a49de401543cc7d6c87c Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Thu, 4 Oct 2018 20:30:05 +0200 Subject: [PATCH 226/299] ASoC: intel: skylake: Add fall-through annotation As a preparatory patch for the upcoming -Wimplicit-fallthrough compiler checks, add the "fall through" annotation in Intel SST skylake driver. Signed-off-by: Takashi Iwai Signed-off-by: Mark Brown --- sound/soc/intel/skylake/skl-pcm.c | 1 + 1 file changed, 1 insertion(+) diff --git a/sound/soc/intel/skylake/skl-pcm.c b/sound/soc/intel/skylake/skl-pcm.c index 00b7a91b18c9..557f80c0bfe5 100644 --- a/sound/soc/intel/skylake/skl-pcm.c +++ b/sound/soc/intel/skylake/skl-pcm.c @@ -495,6 +495,7 @@ static int skl_pcm_trigger(struct snd_pcm_substream *substream, int cmd, stream->lpib); snd_hdac_ext_stream_set_lpib(stream, stream->lpib); } + /* fall through */ case SNDRV_PCM_TRIGGER_START: case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: From 9c6c4d961e634413add345ee030e108e6d19cea2 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Thu, 4 Oct 2018 20:30:06 +0200 Subject: [PATCH 227/299] ASoC: topology: Use the standard fall-through annotations As a preparatory patch for the upcoming -Wimplicit-fallthrough compiler checks, replace with the standard "fall through" annotation. gcc can't understand the mixed texts, unfortunately. Signed-off-by: Takashi Iwai Signed-off-by: Mark Brown --- sound/soc/soc-topology.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/sound/soc/soc-topology.c b/sound/soc/soc-topology.c index 17f81b9a5754..045ef136903d 100644 --- a/sound/soc/soc-topology.c +++ b/sound/soc/soc-topology.c @@ -993,7 +993,7 @@ static int soc_tplg_denum_create(struct soc_tplg *tplg, unsigned int count, kfree(se); continue; } - /* fall through and create texts */ + /* fall through */ case SND_SOC_TPLG_CTL_ENUM: case SND_SOC_TPLG_DAPM_CTL_ENUM_DOUBLE: case SND_SOC_TPLG_DAPM_CTL_ENUM_VIRT: @@ -1310,7 +1310,7 @@ static struct snd_kcontrol_new *soc_tplg_dapm_widget_denum_create( ec->hdr.name); goto err_se; } - /* fall through to create texts */ + /* fall through */ case SND_SOC_TPLG_CTL_ENUM: case SND_SOC_TPLG_DAPM_CTL_ENUM_DOUBLE: case SND_SOC_TPLG_DAPM_CTL_ENUM_VIRT: From d5a5dcd3f815c82e719fd6563f027673160f88e1 Mon Sep 17 00:00:00 2001 From: Alexandru Ardelean Date: Tue, 2 Oct 2018 15:06:30 +0300 Subject: [PATCH 228/299] ASoC: dt-bindings: add dt bindings for adau1977 audio codec Add device-tree bindings documentation file for ADAU1977 audio codec. This describes device-tree fields that are already supported by the driver. The driver supports both I2C AND and SPI, and this doc covers both aspects of the DT configuration. Signed-off-by: Alexandru Ardelean Signed-off-by: Mark Brown --- .../bindings/sound/adi,adau1977.txt | 54 +++++++++++++++++++ 1 file changed, 54 insertions(+) create mode 100644 Documentation/devicetree/bindings/sound/adi,adau1977.txt diff --git a/Documentation/devicetree/bindings/sound/adi,adau1977.txt b/Documentation/devicetree/bindings/sound/adi,adau1977.txt new file mode 100644 index 000000000000..e79aeef73f28 --- /dev/null +++ b/Documentation/devicetree/bindings/sound/adi,adau1977.txt @@ -0,0 +1,54 @@ +Analog Devices ADAU1977/ADAU1978/ADAU1979 + +Datasheets: +http://www.analog.com/media/en/technical-documentation/data-sheets/ADAU1977.pdf +http://www.analog.com/media/en/technical-documentation/data-sheets/ADAU1978.pdf +http://www.analog.com/media/en/technical-documentation/data-sheets/ADAU1979.pdf + +This driver supports both the I2C and SPI bus. + +Required properties: + - compatible: Should contain one of the following: + "adi,adau1977" + "adi,adau1978" + "adi,adau1979" + + - AVDD-supply: analog power supply for the device, please consult + Documentation/devicetree/bindings/regulator/regulator.txt + +Optional properties: + - reset-gpio: the reset pin for the chip, for more details consult + Documentation/devicetree/bindings/gpio/gpio.txt + + - DVDD-supply: supply voltage for the digital core, please consult + Documentation/devicetree/bindings/regulator/regulator.txt + +For required properties on SPI, please consult +Documentation/devicetree/bindings/spi/spi-bus.txt + +Required properties on I2C: + + - reg: The i2c address. Value depends on the state of ADDR0 + and ADDR1, as wired in hardware. + +Examples: + + adau1977_spi: adau1977@0 { + compatible = "adi,adau1977"; + spi-max-frequency = <600000>; + + AVDD-supply = <®ulator>; + DVDD-supply = <®ulator_digital>; + + reset_gpio = <&gpio 10 GPIO_ACTIVE_LOW>; + }; + + adau1977_i2c: adau1977@11 { + compatible = "adi,adau1977"; + reg = <0x11>; + + AVDD-supply = <®ulator>; + DVDD-supply = <®ulator_digital>; + + reset_gpio = <&gpio 10 GPIO_ACTIVE_LOW>; + }; From 11ba6111160290ccd35562f4e05cec08942a6c4c Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Sun, 7 Oct 2018 09:44:17 +0200 Subject: [PATCH 229/299] ALSA: hda - Add quirk for ASUS G751 laptop MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ASUS G751 requires the extra COEF initialization to make it microphone working properly. Reported-and-tested-by: Håvard Cc: Signed-off-by: Takashi Iwai --- sound/pci/hda/patch_realtek.c | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c index 69283633ae91..389e8e996589 100644 --- a/sound/pci/hda/patch_realtek.c +++ b/sound/pci/hda/patch_realtek.c @@ -7738,6 +7738,7 @@ enum { ALC662_FIXUP_ASUS_Nx50, ALC668_FIXUP_ASUS_Nx51_HEADSET_MODE, ALC668_FIXUP_ASUS_Nx51, + ALC668_FIXUP_ASUS_G751, ALC891_FIXUP_HEADSET_MODE, ALC891_FIXUP_DELL_MIC_NO_PRESENCE, ALC662_FIXUP_ACER_VERITON, @@ -8007,6 +8008,14 @@ static const struct hda_fixup alc662_fixups[] = { .chained = true, .chain_id = ALC668_FIXUP_ASUS_Nx51_HEADSET_MODE, }, + [ALC668_FIXUP_ASUS_G751] = { + .type = HDA_FIXUP_VERBS, + .v.verbs = (const struct hda_verb[]) { + { 0x20, AC_VERB_SET_COEF_INDEX, 0xc3 }, + { 0x20, AC_VERB_SET_PROC_COEF, 0x4000 }, + {} + }, + }, [ALC891_FIXUP_HEADSET_MODE] = { .type = HDA_FIXUP_FUNC, .v.func = alc_fixup_headset_mode, @@ -8080,6 +8089,7 @@ static const struct snd_pci_quirk alc662_fixup_tbl[] = { SND_PCI_QUIRK(0x1043, 0x11cd, "Asus N550", ALC662_FIXUP_ASUS_Nx50), SND_PCI_QUIRK(0x1043, 0x13df, "Asus N550JX", ALC662_FIXUP_BASS_1A), SND_PCI_QUIRK(0x1043, 0x129d, "Asus N750", ALC662_FIXUP_ASUS_Nx50), + SND_PCI_QUIRK(0x1043, 0x12ff, "ASUS G751", ALC668_FIXUP_ASUS_G751), SND_PCI_QUIRK(0x1043, 0x1477, "ASUS N56VZ", ALC662_FIXUP_BASS_MODE4_CHMAP), SND_PCI_QUIRK(0x1043, 0x15a7, "ASUS UX51VZH", ALC662_FIXUP_BASS_16), SND_PCI_QUIRK(0x1043, 0x177d, "ASUS N551", ALC668_FIXUP_ASUS_Nx51), From 40c516757ba00bc17cae03fbb941c6fc131f698d Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Sun, 7 Oct 2018 09:47:39 +0200 Subject: [PATCH 230/299] ALSA: hda - Add ASUS G751 quirk model entry MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add a corresponding model list entry for ASUS G751 so that user can test the quirk for another compatible machines more easily. Reported-and-tested-by: Håvard Signed-off-by: Takashi Iwai --- Documentation/sound/hd-audio/models.rst | 2 ++ sound/pci/hda/patch_realtek.c | 1 + 2 files changed, 3 insertions(+) diff --git a/Documentation/sound/hd-audio/models.rst b/Documentation/sound/hd-audio/models.rst index e06238131f77..368a07a165f5 100644 --- a/Documentation/sound/hd-audio/models.rst +++ b/Documentation/sound/hd-audio/models.rst @@ -309,6 +309,8 @@ asus-nx50 ASUS Nx50 fixups asus-nx51 ASUS Nx51 fixups +asus-g751 + ASUS G751 fixups alc891-headset Headset mode support on ALC891 alc891-headset-multi diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c index 389e8e996589..3be7d7649525 100644 --- a/sound/pci/hda/patch_realtek.c +++ b/sound/pci/hda/patch_realtek.c @@ -8194,6 +8194,7 @@ static const struct hda_model_fixup alc662_fixup_models[] = { {.id = ALC668_FIXUP_DELL_XPS13, .name = "dell-xps13"}, {.id = ALC662_FIXUP_ASUS_Nx50, .name = "asus-nx50"}, {.id = ALC668_FIXUP_ASUS_Nx51, .name = "asus-nx51"}, + {.id = ALC668_FIXUP_ASUS_G751, .name = "asus-g751"}, {.id = ALC891_FIXUP_HEADSET_MODE, .name = "alc891-headset"}, {.id = ALC891_FIXUP_DELL_MIC_NO_PRESENCE, .name = "alc891-headset-multi"}, {.id = ALC662_FIXUP_ACER_VERITON, .name = "acer-veriton"}, From cc65fb650c682e3b43d50202a0f01da7dc11e647 Mon Sep 17 00:00:00 2001 From: Daniel Mack Date: Wed, 3 Oct 2018 21:34:35 +0200 Subject: [PATCH 231/299] ASoC: Add device tree documentation file for wm8782 stereo DAC Add a device tree documentation file for the wm8782 stereo DAC to describe the regulator handles. Signed-off-by: Daniel Mack Acked-by: Charles Keepax Signed-off-by: Mark Brown --- .../devicetree/bindings/sound/wm8782.txt | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) create mode 100644 Documentation/devicetree/bindings/sound/wm8782.txt diff --git a/Documentation/devicetree/bindings/sound/wm8782.txt b/Documentation/devicetree/bindings/sound/wm8782.txt new file mode 100644 index 000000000000..256cdec6ec4d --- /dev/null +++ b/Documentation/devicetree/bindings/sound/wm8782.txt @@ -0,0 +1,17 @@ +WM8782 stereo ADC + +This device does not have any control interface or reset pins. + +Required properties: + + - compatible : "wlf,wm8782" + - Vdda-supply : phandle to a regulator for the analog power supply (2.7V - 5.5V) + - Vdd-supply : phandle to a regulator for the digital power supply (2.7V - 3.6V) + +Example: + +wm8782: stereo-adc { + compatible = "wlf,wm8782"; + Vdda-supply = <&vdda_supply>; + Vdd-supply = <&vdd_supply>; +}; From 7454a21c13f7ce9bf1a4f9b639039b78462cec09 Mon Sep 17 00:00:00 2001 From: Daniel Mack Date: Wed, 3 Oct 2018 21:34:36 +0200 Subject: [PATCH 232/299] ASoC: wm8782: add support for regulators Lookup regulators for Vdd and Vdda during probe, and enable them when the component is linked. Signed-off-by: Daniel Mack Signed-off-by: Mark Brown --- sound/soc/codecs/wm8782.c | 63 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 63 insertions(+) diff --git a/sound/soc/codecs/wm8782.c b/sound/soc/codecs/wm8782.c index 317db9a149a7..cf2cdbece122 100644 --- a/sound/soc/codecs/wm8782.c +++ b/sound/soc/codecs/wm8782.c @@ -20,6 +20,7 @@ #include #include #include +#include #include #include #include @@ -50,7 +51,51 @@ static struct snd_soc_dai_driver wm8782_dai = { }, }; +/* regulator power supply names */ +static const char *supply_names[] = { + "Vdda", /* analog supply, 2.7V - 3.6V */ + "Vdd", /* digital supply, 2.7V - 5.5V */ +}; + +struct wm8782_priv { + struct regulator_bulk_data supplies[ARRAY_SIZE(supply_names)]; +}; + +static int wm8782_soc_probe(struct snd_soc_component *component) +{ + struct wm8782_priv *priv = snd_soc_component_get_drvdata(component); + return regulator_bulk_enable(ARRAY_SIZE(priv->supplies), priv->supplies); +} + +static void wm8782_soc_remove(struct snd_soc_component *component) +{ + struct wm8782_priv *priv = snd_soc_component_get_drvdata(component); + regulator_bulk_disable(ARRAY_SIZE(priv->supplies), priv->supplies); +} + +#ifdef CONFIG_PM +static int wm8782_soc_suspend(struct snd_soc_component *component) +{ + struct wm8782_priv *priv = snd_soc_component_get_drvdata(component); + regulator_bulk_disable(ARRAY_SIZE(priv->supplies), priv->supplies); + return 0; +} + +static int wm8782_soc_resume(struct snd_soc_component *component) +{ + struct wm8782_priv *priv = snd_soc_component_get_drvdata(component); + return regulator_bulk_enable(ARRAY_SIZE(priv->supplies), priv->supplies); +} +#else +#define wm8782_soc_suspend NULL +#define wm8782_soc_resume NULL +#endif /* CONFIG_PM */ + static const struct snd_soc_component_driver soc_component_dev_wm8782 = { + .probe = wm8782_soc_probe, + .remove = wm8782_soc_remove, + .suspend = wm8782_soc_suspend, + .resume = wm8782_soc_resume, .dapm_widgets = wm8782_dapm_widgets, .num_dapm_widgets = ARRAY_SIZE(wm8782_dapm_widgets), .dapm_routes = wm8782_dapm_routes, @@ -63,6 +108,24 @@ static const struct snd_soc_component_driver soc_component_dev_wm8782 = { static int wm8782_probe(struct platform_device *pdev) { + struct device *dev = &pdev->dev; + struct wm8782_priv *priv; + int ret, i; + + priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL); + if (!priv) + return -ENOMEM; + + dev_set_drvdata(dev, priv); + + for (i = 0; i < ARRAY_SIZE(supply_names); i++) + priv->supplies[i].supply = supply_names[i]; + + ret = devm_regulator_bulk_get(dev, ARRAY_SIZE(priv->supplies), + priv->supplies); + if (ret < 0) + return ret; + return devm_snd_soc_register_component(&pdev->dev, &soc_component_dev_wm8782, &wm8782_dai, 1); } From d6ed11edab5dd10ddf5548c02a9a1132ec728640 Mon Sep 17 00:00:00 2001 From: Marco Felsch Date: Fri, 5 Oct 2018 09:58:10 +0200 Subject: [PATCH 233/299] ASoC: dt-bindings: max98088: add external clock binding Allow setting the clock provider for the external clock called "mclk". Signed-off-by: Marco Felsch Signed-off-by: Mark Brown --- .../devicetree/bindings/sound/maxim,max98088.txt | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/Documentation/devicetree/bindings/sound/maxim,max98088.txt b/Documentation/devicetree/bindings/sound/maxim,max98088.txt index a79ad5c7af88..da764d913319 100644 --- a/Documentation/devicetree/bindings/sound/maxim,max98088.txt +++ b/Documentation/devicetree/bindings/sound/maxim,max98088.txt @@ -7,9 +7,17 @@ Required properties: - compatible: "maxim,max98088" or "maxim,max98089". - reg: The I2C address of the device. +Optional properties: + +- clocks: the clock provider of MCLK, see ../clock/clock-bindings.txt section + "consumer" for more information. +- clock-names: must be set to "mclk" + Example: max98089: codec@10 { compatible = "maxim,max98089"; reg = <0x10>; + clocks = <&clks IMX6QDL_CLK_CKO2>; + clock-names = "mclk"; }; From 62a7fc32a6289dce88787da03f893deab08158c3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andreas=20F=C3=A4rber?= Date: Fri, 5 Oct 2018 09:58:11 +0200 Subject: [PATCH 234/299] ASoC: max98088: Add master clock handling MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit If master clock is provided through device tree, then update the master clock frequency during set_sysclk. Cc: Tushar Behera Signed-off-by: Andreas Färber Acked-by: Tushar Behera Reviewed-by: Javier Martinez Canillas [m.felsch@pengutronix.de: move mclk request to i2c_probe] [m.felsch@pengutronix.de: make use of snd_soc_component_get_bias_level()] Signed-off-by: Marco Felsch Signed-off-by: Mark Brown --- sound/soc/codecs/max98088.c | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/sound/soc/codecs/max98088.c b/sound/soc/codecs/max98088.c index 9450d5d9c492..ca172a4b6849 100644 --- a/sound/soc/codecs/max98088.c +++ b/sound/soc/codecs/max98088.c @@ -16,6 +16,7 @@ #include #include #include +#include #include #include #include @@ -42,6 +43,7 @@ struct max98088_priv { struct regmap *regmap; enum max98088_type devtype; struct max98088_pdata *pdata; + struct clk *mclk; unsigned int sysclk; struct max98088_cdata dai[2]; int eq_textcnt; @@ -1103,6 +1105,11 @@ static int max98088_dai_set_sysclk(struct snd_soc_dai *dai, if (freq == max98088->sysclk) return 0; + if (!IS_ERR(max98088->mclk)) { + freq = clk_round_rate(max98088->mclk, freq); + clk_set_rate(max98088->mclk, freq); + } + /* Setup clocks for slave mode, and using the PLL * PSCLK = 0x01 (when master clk is 10MHz to 20MHz) * 0x02 (when master clk is 20MHz to 30MHz).. @@ -1310,6 +1317,20 @@ static int max98088_set_bias_level(struct snd_soc_component *component, break; case SND_SOC_BIAS_PREPARE: + /* + * SND_SOC_BIAS_PREPARE is called while preparing for a + * transition to ON or away from ON. If current bias_level + * is SND_SOC_BIAS_ON, then it is preparing for a transition + * away from ON. Disable the clock in that case, otherwise + * enable it. + */ + if (!IS_ERR(max98088->mclk)) { + if (snd_soc_component_get_bias_level(component) == + SND_SOC_BIAS_ON) + clk_disable_unprepare(max98088->mclk); + else + clk_prepare_enable(max98088->mclk); + } break; case SND_SOC_BIAS_STANDBY: @@ -1725,6 +1746,11 @@ static int max98088_i2c_probe(struct i2c_client *i2c, if (IS_ERR(max98088->regmap)) return PTR_ERR(max98088->regmap); + max98088->mclk = devm_clk_get(&i2c->dev, "mclk"); + if (IS_ERR(max98088->mclk)) + if (PTR_ERR(max98088->mclk) == -EPROBE_DEFER) + return PTR_ERR(max98088->mclk); + max98088->devtype = id->driver_data; i2c_set_clientdata(i2c, max98088); From 24ae67c5825004bcbce90e7c89fed63f25d96260 Mon Sep 17 00:00:00 2001 From: Marco Felsch Date: Fri, 5 Oct 2018 09:58:12 +0200 Subject: [PATCH 235/299] ASoC: max98988: make it selectable Currently the driver will build only if SND_SOC_ALL_CODECS is set. Adding a Kconfig menu description to build the driver standalone. Signed-off-by: Marco Felsch Signed-off-by: Mark Brown --- sound/soc/codecs/Kconfig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sound/soc/codecs/Kconfig b/sound/soc/codecs/Kconfig index 9989d35e0fc6..3c6bd6019b92 100644 --- a/sound/soc/codecs/Kconfig +++ b/sound/soc/codecs/Kconfig @@ -640,7 +640,7 @@ config SND_SOC_LM49453 tristate config SND_SOC_MAX98088 - tristate + tristate "Maxim MAX98088/9 Low-Power, Stereo Audio Codec" config SND_SOC_MAX98090 tristate From a88bcc8d96817ec0329b9cb402749e3d0d59698f Mon Sep 17 00:00:00 2001 From: Connor McAdams Date: Mon, 8 Oct 2018 15:39:57 -0400 Subject: [PATCH 236/299] ALSA: hda/ca0132 - Fix microphone inconsistency issues This patch fixes microphone inconsistency issues by adding a delay to each setup_defaults function. Without this, the microphone only works intermittently. Signed-off-by: Connor McAdams Reviewed-by: Takashi Sakamoto Signed-off-by: Takashi Iwai --- sound/pci/hda/patch_ca0132.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/sound/pci/hda/patch_ca0132.c b/sound/pci/hda/patch_ca0132.c index b0985045ebed..12a3581190af 100644 --- a/sound/pci/hda/patch_ca0132.c +++ b/sound/pci/hda/patch_ca0132.c @@ -7223,6 +7223,8 @@ static void r3d_setup_defaults(struct hda_codec *codec) int num_fx; int idx, i; + msleep(100); + if (spec->dsp_state != DSP_DOWNLOADED) return; @@ -7267,6 +7269,8 @@ static void sbz_setup_defaults(struct hda_codec *codec) int num_fx; int idx, i; + msleep(100); + if (spec->dsp_state != DSP_DOWNLOADED) return; @@ -7324,6 +7328,8 @@ static void ae5_setup_defaults(struct hda_codec *codec) int num_fx; int idx, i; + msleep(100); + if (spec->dsp_state != DSP_DOWNLOADED) return; From ebabde1e1841780d2faf5b1e8a07111753063796 Mon Sep 17 00:00:00 2001 From: Connor McAdams Date: Mon, 8 Oct 2018 15:39:58 -0400 Subject: [PATCH 237/299] ALSA: hda/ca0132 - Clean up patch_ca0132() This patch cleans up the patch_ca0132() function with suggestions from Takashi Sakamoto. Signed-off-by: Connor McAdams Reviewed-by: Takashi Sakamoto Signed-off-by: Takashi Iwai --- sound/pci/hda/patch_ca0132.c | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/sound/pci/hda/patch_ca0132.c b/sound/pci/hda/patch_ca0132.c index 12a3581190af..07d50d6b9ec5 100644 --- a/sound/pci/hda/patch_ca0132.c +++ b/sound/pci/hda/patch_ca0132.c @@ -8697,10 +8697,6 @@ static int patch_ca0132(struct hda_codec *codec) codec->spec = spec; spec->codec = codec; - codec->patch_ops = ca0132_patch_ops; - codec->pcm_format_first = 1; - codec->no_sticky_stream = 1; - /* Detect codec quirk */ quirk = snd_pci_quirk_lookup(codec->bus->pci, ca0132_quirks); if (quirk) @@ -8711,6 +8707,15 @@ static int patch_ca0132(struct hda_codec *codec) if (spec->quirk == QUIRK_SBZ) sbz_detect_quirk(codec); + if (spec->quirk == QUIRK_ZXR_DBPRO) + codec->patch_ops = dbpro_patch_ops; + else + codec->patch_ops = ca0132_patch_ops; + + codec->pcm_format_first = 1; + codec->no_sticky_stream = 1; + + spec->dsp_state = DSP_DOWNLOAD_INIT; spec->num_mixers = 1; @@ -8725,7 +8730,6 @@ static int patch_ca0132(struct hda_codec *codec) snd_hda_codec_set_name(codec, "Sound Blaster ZxR"); break; case QUIRK_ZXR_DBPRO: - codec->patch_ops = dbpro_patch_ops; break; case QUIRK_R3D: spec->mixers[0] = desktop_mixer; From 1502b432781ea5ab5a769f6d217503166ad775cc Mon Sep 17 00:00:00 2001 From: Connor McAdams Date: Mon, 8 Oct 2018 15:39:59 -0400 Subject: [PATCH 238/299] ALSA: hda/ca0132 - Add error checking in ca0132_build_controls() This patch adds error checking to functions creating controls inside of ca0132_build_controls(). Signed-off-by: Connor McAdams Reviewed-by: Takashi Sakamoto Signed-off-by: Takashi Iwai --- sound/pci/hda/patch_ca0132.c | 47 +++++++++++++++++++++++++++--------- 1 file changed, 35 insertions(+), 12 deletions(-) diff --git a/sound/pci/hda/patch_ca0132.c b/sound/pci/hda/patch_ca0132.c index 07d50d6b9ec5..693b0630efb2 100644 --- a/sound/pci/hda/patch_ca0132.c +++ b/sound/pci/hda/patch_ca0132.c @@ -6365,7 +6365,8 @@ static int ca0132_build_controls(struct hda_codec *codec) NULL, ca0132_alt_slave_pfxs, "Playback Switch", true, &spec->vmaster_mute.sw_kctl); - + if (err < 0) + return err; } /* Add in and out effects controls. @@ -6392,8 +6393,14 @@ static int ca0132_build_controls(struct hda_codec *codec) * prefix, and change PlayEnhancement and CrystalVoice to match. */ if (spec->use_alt_controls) { - ca0132_alt_add_svm_enum(codec); - add_ca0132_alt_eq_presets(codec); + err = ca0132_alt_add_svm_enum(codec); + if (err < 0) + return err; + + err = add_ca0132_alt_eq_presets(codec); + if (err < 0) + return err; + err = add_fx_switch(codec, PLAY_ENHANCEMENT, "Enable OutFX", 0); if (err < 0) @@ -6430,7 +6437,9 @@ static int ca0132_build_controls(struct hda_codec *codec) if (err < 0) return err; } - add_voicefx(codec); + err = add_voicefx(codec); + if (err < 0) + return err; /* * If the codec uses alt_functions, you need the enumerated controls @@ -6438,23 +6447,37 @@ static int ca0132_build_controls(struct hda_codec *codec) * setting control. */ if (spec->use_alt_functions) { - ca0132_alt_add_output_enum(codec); - ca0132_alt_add_mic_boost_enum(codec); + err = ca0132_alt_add_output_enum(codec); + if (err < 0) + return err; + err = ca0132_alt_add_mic_boost_enum(codec); + if (err < 0) + return err; /* * ZxR only has microphone input, there is no front panel * header on the card, and aux-in is handled by the DBPro board. */ - if (spec->quirk != QUIRK_ZXR) - ca0132_alt_add_input_enum(codec); + if (spec->quirk != QUIRK_ZXR) { + err = ca0132_alt_add_input_enum(codec); + if (err < 0) + return err; + } } if (spec->quirk == QUIRK_AE5) { - ae5_add_headphone_gain_enum(codec); - ae5_add_sound_filter_enum(codec); + err = ae5_add_headphone_gain_enum(codec); + if (err < 0) + return err; + err = ae5_add_sound_filter_enum(codec); + if (err < 0) + return err; } - if (spec->quirk == QUIRK_ZXR) - zxr_add_headphone_gain_switch(codec); + if (spec->quirk == QUIRK_ZXR) { + err = zxr_add_headphone_gain_switch(codec); + if (err < 0) + return err; + } #ifdef ENABLE_TUNING_CONTROLS add_tuning_ctls(codec); #endif From 7a2dc84fc480aec4f8f96e152327423014edf668 Mon Sep 17 00:00:00 2001 From: Connor McAdams Date: Mon, 8 Oct 2018 15:40:00 -0400 Subject: [PATCH 239/299] ALSA: hda/ca0132 - Fix input effect controls for desktop cards This patch removes the echo cancellation control for desktop cards, and makes use of the special 0x47 SCP command for noise reduction. Signed-off-by: Connor McAdams Reviewed-by: Takashi Sakamoto Signed-off-by: Takashi Iwai --- sound/pci/hda/patch_ca0132.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/sound/pci/hda/patch_ca0132.c b/sound/pci/hda/patch_ca0132.c index 693b0630efb2..1a13ceae261e 100644 --- a/sound/pci/hda/patch_ca0132.c +++ b/sound/pci/hda/patch_ca0132.c @@ -4857,7 +4857,7 @@ static int ca0132_effects_set(struct hda_codec *codec, hda_nid_t nid, long val) val = 0; /* If Voice Focus on SBZ, set to two channel. */ - if ((nid == VOICE_FOCUS) && (spec->quirk == QUIRK_SBZ) + if ((nid == VOICE_FOCUS) && (spec->use_pci_mmio) && (spec->cur_mic_type != REAR_LINE_IN)) { if (spec->effects_switch[CRYSTAL_VOICE - EFFECT_START_NID]) { @@ -4876,7 +4876,7 @@ static int ca0132_effects_set(struct hda_codec *codec, hda_nid_t nid, long val) * For SBZ noise reduction, there's an extra command * to module ID 0x47. No clue why. */ - if ((nid == NOISE_REDUCTION) && (spec->quirk == QUIRK_SBZ) + if ((nid == NOISE_REDUCTION) && (spec->use_pci_mmio) && (spec->cur_mic_type != REAR_LINE_IN)) { if (spec->effects_switch[CRYSTAL_VOICE - EFFECT_START_NID]) { @@ -6374,8 +6374,8 @@ static int ca0132_build_controls(struct hda_codec *codec) */ num_fx = OUT_EFFECTS_COUNT + IN_EFFECTS_COUNT; for (i = 0; i < num_fx; i++) { - /* SBZ and R3D break if Echo Cancellation is used. */ - if (spec->quirk == QUIRK_SBZ || spec->quirk == QUIRK_R3D) { + /* Desktop cards break if Echo Cancellation is used. */ + if (spec->use_pci_mmio) { if (i == (ECHO_CANCELLATION - IN_EFFECT_START_NID + OUT_EFFECTS_COUNT)) continue; From 5b7c5e1f4c36b99d0f694f38b9ad910f520cb7ef Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Tue, 9 Oct 2018 14:20:17 +0200 Subject: [PATCH 240/299] ALSA: hda - Fix headphone pin config for ASUS G751 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit BIOS on ASUS G751 doesn't seem to map the headphone pin (NID 0x16) correctly. Add a quirk to address it, as well as chaining to the previous fix for the microphone. Reported-by: Håvard Cc: Signed-off-by: Takashi Iwai --- sound/pci/hda/patch_realtek.c | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c index 3be7d7649525..6262d7b07099 100644 --- a/sound/pci/hda/patch_realtek.c +++ b/sound/pci/hda/patch_realtek.c @@ -7738,6 +7738,7 @@ enum { ALC662_FIXUP_ASUS_Nx50, ALC668_FIXUP_ASUS_Nx51_HEADSET_MODE, ALC668_FIXUP_ASUS_Nx51, + ALC668_FIXUP_MIC_COEF, ALC668_FIXUP_ASUS_G751, ALC891_FIXUP_HEADSET_MODE, ALC891_FIXUP_DELL_MIC_NO_PRESENCE, @@ -8008,7 +8009,7 @@ static const struct hda_fixup alc662_fixups[] = { .chained = true, .chain_id = ALC668_FIXUP_ASUS_Nx51_HEADSET_MODE, }, - [ALC668_FIXUP_ASUS_G751] = { + [ALC668_FIXUP_MIC_COEF] = { .type = HDA_FIXUP_VERBS, .v.verbs = (const struct hda_verb[]) { { 0x20, AC_VERB_SET_COEF_INDEX, 0xc3 }, @@ -8016,6 +8017,15 @@ static const struct hda_fixup alc662_fixups[] = { {} }, }, + [ALC668_FIXUP_ASUS_G751] = { + .type = HDA_FIXUP_PINS, + .v.pins = (const struct hda_pintbl[]) { + { 0x16, 0x0421101f }, /* HP */ + {} + }, + .chained = true, + .chain_id = ALC668_FIXUP_MIC_COEF + }, [ALC891_FIXUP_HEADSET_MODE] = { .type = HDA_FIXUP_FUNC, .v.func = alc_fixup_headset_mode, From d06fb562bff5d14defdacbd92449bacbaedd5cdf Mon Sep 17 00:00:00 2001 From: Hui Wang Date: Wed, 10 Oct 2018 11:57:25 +0800 Subject: [PATCH 241/299] ALSA: hda/realtek - Fix the problem of the front MIC on the Lenovo M715 The front MIC on the Lenovo M715 can't record sound, after applying the ALC294_FIXUP_LENOVO_MIC_LOCATION, the problem is fixed. So add the pin configuration of this machine to the pin quirk table. Cc: Signed-off-by: Hui Wang Signed-off-by: Takashi Iwai --- sound/pci/hda/patch_realtek.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c index 6262d7b07099..fa61674a5605 100644 --- a/sound/pci/hda/patch_realtek.c +++ b/sound/pci/hda/patch_realtek.c @@ -6841,6 +6841,12 @@ static const struct snd_hda_pin_quirk alc269_pin_fixup_tbl[] = { {0x1a, 0x02a11040}, {0x1b, 0x01014020}, {0x21, 0x0221101f}), + SND_HDA_PIN_QUIRK(0x10ec0235, 0x17aa, "Lenovo", ALC294_FIXUP_LENOVO_MIC_LOCATION, + {0x14, 0x90170110}, + {0x19, 0x02a11030}, + {0x1a, 0x02a11040}, + {0x1b, 0x01011020}, + {0x21, 0x0221101f}), SND_HDA_PIN_QUIRK(0x10ec0235, 0x17aa, "Lenovo", ALC294_FIXUP_LENOVO_MIC_LOCATION, {0x14, 0x90170110}, {0x19, 0x02a11020}, From 61ccc6f6b27c03bb32ca38a3c580d49ce1612d43 Mon Sep 17 00:00:00 2001 From: Takashi Sakamoto Date: Wed, 10 Oct 2018 15:34:59 +0900 Subject: [PATCH 242/299] ALSA: firewire: block .remove callback of bus driver till all of ALSA character devices are released At present, in .remove callback of bus driver just decrease reference count of device for ALSA card instance. This delegates release of the device to a process in which the last of ALSA character device is released. On the other hand, the other drivers such as for devices on PCIe are programmed to block .remove callback of bus driver till all of ALSA character devices are released. For consistency of behaviour for whole drivers, this probably confuses users. This commit takes drivers in ALSA firewire stack to imitate the above behaviour. Signed-off-by: Takashi Sakamoto Signed-off-by: Takashi Iwai --- sound/firewire/bebob/bebob.c | 4 ++-- sound/firewire/digi00x/digi00x.c | 4 ++-- sound/firewire/fireface/ff.c | 4 ++-- sound/firewire/fireworks/fireworks.c | 4 ++-- sound/firewire/isight.c | 3 ++- sound/firewire/motu/motu.c | 4 ++-- sound/firewire/oxfw/oxfw.c | 4 ++-- sound/firewire/tascam/tascam.c | 4 ++-- 8 files changed, 16 insertions(+), 15 deletions(-) diff --git a/sound/firewire/bebob/bebob.c b/sound/firewire/bebob/bebob.c index 72b04214a3b5..3a5579cb3aa8 100644 --- a/sound/firewire/bebob/bebob.c +++ b/sound/firewire/bebob/bebob.c @@ -374,8 +374,8 @@ static void bebob_remove(struct fw_unit *unit) cancel_delayed_work_sync(&bebob->dwork); if (bebob->registered) { - /* No need to wait for releasing card object in this context. */ - snd_card_free_when_closed(bebob->card); + // Block till all of ALSA character devices are released. + snd_card_free(bebob->card); } else { /* Don't forget this case. */ bebob_free(bebob); diff --git a/sound/firewire/digi00x/digi00x.c b/sound/firewire/digi00x/digi00x.c index 654420f1c9bd..554d7ff737a2 100644 --- a/sound/firewire/digi00x/digi00x.c +++ b/sound/firewire/digi00x/digi00x.c @@ -172,8 +172,8 @@ static void snd_dg00x_remove(struct fw_unit *unit) cancel_delayed_work_sync(&dg00x->dwork); if (dg00x->registered) { - /* No need to wait for releasing card object in this context. */ - snd_card_free_when_closed(dg00x->card); + // Block till all of ALSA character devices are released. + snd_card_free(dg00x->card); } else { /* Don't forget this case. */ dg00x_free(dg00x); diff --git a/sound/firewire/fireface/ff.c b/sound/firewire/fireface/ff.c index 98731bd8816f..73425dfe63bf 100644 --- a/sound/firewire/fireface/ff.c +++ b/sound/firewire/fireface/ff.c @@ -145,8 +145,8 @@ static void snd_ff_remove(struct fw_unit *unit) cancel_work_sync(&ff->dwork.work); if (ff->registered) { - /* No need to wait for releasing card object in this context. */ - snd_card_free_when_closed(ff->card); + // Block till all of ALSA character devices are released. + snd_card_free(ff->card); } else { /* Don't forget this case. */ ff_free(ff); diff --git a/sound/firewire/fireworks/fireworks.c b/sound/firewire/fireworks/fireworks.c index f680e2f27806..5a17ead86e61 100644 --- a/sound/firewire/fireworks/fireworks.c +++ b/sound/firewire/fireworks/fireworks.c @@ -358,8 +358,8 @@ static void efw_remove(struct fw_unit *unit) cancel_delayed_work_sync(&efw->dwork); if (efw->registered) { - /* No need to wait for releasing card object in this context. */ - snd_card_free_when_closed(efw->card); + // Block till all of ALSA character devices are released. + snd_card_free(efw->card); } else { /* Don't forget this case. */ efw_free(efw); diff --git a/sound/firewire/isight.c b/sound/firewire/isight.c index 30957477e005..1f591c8805ea 100644 --- a/sound/firewire/isight.c +++ b/sound/firewire/isight.c @@ -703,7 +703,8 @@ static void isight_remove(struct fw_unit *unit) isight_stop_streaming(isight); mutex_unlock(&isight->mutex); - snd_card_free_when_closed(isight->card); + // Block till all of ALSA character devices are released. + snd_card_free(isight->card); } static const struct ieee1394_device_id isight_id_table[] = { diff --git a/sound/firewire/motu/motu.c b/sound/firewire/motu/motu.c index fd5726424c7a..12680c85b37f 100644 --- a/sound/firewire/motu/motu.c +++ b/sound/firewire/motu/motu.c @@ -172,8 +172,8 @@ static void motu_remove(struct fw_unit *unit) cancel_delayed_work_sync(&motu->dwork); if (motu->registered) { - /* No need to wait for releasing card object in this context. */ - snd_card_free_when_closed(motu->card); + // Block till all of ALSA character devices are released. + snd_card_free(motu->card); } else { /* Don't forget this case. */ motu_free(motu); diff --git a/sound/firewire/oxfw/oxfw.c b/sound/firewire/oxfw/oxfw.c index 6ac551786b93..36f905b371e6 100644 --- a/sound/firewire/oxfw/oxfw.c +++ b/sound/firewire/oxfw/oxfw.c @@ -327,8 +327,8 @@ static void oxfw_remove(struct fw_unit *unit) cancel_delayed_work_sync(&oxfw->dwork); if (oxfw->registered) { - /* No need to wait for releasing card object in this context. */ - snd_card_free_when_closed(oxfw->card); + // Block till all of ALSA character devices are released. + snd_card_free(oxfw->card); } else { /* Don't forget this case. */ oxfw_free(oxfw); diff --git a/sound/firewire/tascam/tascam.c b/sound/firewire/tascam/tascam.c index 53f20153ba71..6f7aaa8c84aa 100644 --- a/sound/firewire/tascam/tascam.c +++ b/sound/firewire/tascam/tascam.c @@ -212,8 +212,8 @@ static void snd_tscm_remove(struct fw_unit *unit) cancel_delayed_work_sync(&tscm->dwork); if (tscm->registered) { - /* No need to wait for releasing card object in this context. */ - snd_card_free_when_closed(tscm->card); + // Block till all of ALSA character devices are released. + snd_card_free(tscm->card); } else { /* Don't forget this case. */ tscm_free(tscm); From 5b14ec25a79bf60fc9a663fe579a500b6ac9d8ab Mon Sep 17 00:00:00 2001 From: Takashi Sakamoto Date: Wed, 10 Oct 2018 15:35:00 +0900 Subject: [PATCH 243/299] ALSA: firewire: release reference count of firewire unit in .remove callback of bus driver In a previous commit, drivers in ALSA firewire stack blocks .remove callback of bus driver. This enables to release members of private data in the callback after releasing device of sound card. This commit simplifies codes to release the members. Signed-off-by: Takashi Sakamoto Signed-off-by: Takashi Iwai --- sound/firewire/bebob/bebob.c | 9 +++------ sound/firewire/dice/dice.c | 9 +++------ sound/firewire/digi00x/digi00x.c | 9 +++------ sound/firewire/fireface/ff.c | 9 +++------ sound/firewire/fireworks/fireworks.c | 9 +++------ sound/firewire/isight.c | 5 +++-- sound/firewire/motu/motu.c | 9 +++------ sound/firewire/oxfw/oxfw.c | 9 +++------ sound/firewire/tascam/tascam.c | 9 +++------ 9 files changed, 27 insertions(+), 50 deletions(-) diff --git a/sound/firewire/bebob/bebob.c b/sound/firewire/bebob/bebob.c index 3a5579cb3aa8..34ed8afbb30c 100644 --- a/sound/firewire/bebob/bebob.c +++ b/sound/firewire/bebob/bebob.c @@ -129,9 +129,6 @@ end: static void bebob_free(struct snd_bebob *bebob) { snd_bebob_stream_destroy_duplex(bebob); - - mutex_destroy(&bebob->mutex); - fw_unit_put(bebob->unit); } /* @@ -376,10 +373,10 @@ static void bebob_remove(struct fw_unit *unit) if (bebob->registered) { // Block till all of ALSA character devices are released. snd_card_free(bebob->card); - } else { - /* Don't forget this case. */ - bebob_free(bebob); } + + mutex_destroy(&bebob->mutex); + fw_unit_put(bebob->unit); } static const struct snd_bebob_rate_spec normal_rate_spec = { diff --git a/sound/firewire/dice/dice.c b/sound/firewire/dice/dice.c index 9bf77adb3127..c6b63e3f36a8 100644 --- a/sound/firewire/dice/dice.c +++ b/sound/firewire/dice/dice.c @@ -126,9 +126,6 @@ static void dice_free(struct snd_dice *dice) { snd_dice_stream_destroy_duplex(dice); snd_dice_transaction_destroy(dice); - - mutex_destroy(&dice->mutex); - fw_unit_put(dice->unit); } /* @@ -261,10 +258,10 @@ static void dice_remove(struct fw_unit *unit) if (dice->registered) { /* No need to wait for releasing card object in this context. */ snd_card_free_when_closed(dice->card); - } else { - /* Don't forget this case. */ - dice_free(dice); } + + mutex_destroy(&dice->mutex); + fw_unit_put(dice->unit); } static void dice_bus_reset(struct fw_unit *unit) diff --git a/sound/firewire/digi00x/digi00x.c b/sound/firewire/digi00x/digi00x.c index 554d7ff737a2..7a24348968b9 100644 --- a/sound/firewire/digi00x/digi00x.c +++ b/sound/firewire/digi00x/digi00x.c @@ -45,9 +45,6 @@ static void dg00x_free(struct snd_dg00x *dg00x) { snd_dg00x_stream_destroy_duplex(dg00x); snd_dg00x_transaction_unregister(dg00x); - - mutex_destroy(&dg00x->mutex); - fw_unit_put(dg00x->unit); } static void dg00x_card_free(struct snd_card *card) @@ -174,10 +171,10 @@ static void snd_dg00x_remove(struct fw_unit *unit) if (dg00x->registered) { // Block till all of ALSA character devices are released. snd_card_free(dg00x->card); - } else { - /* Don't forget this case. */ - dg00x_free(dg00x); } + + mutex_destroy(&dg00x->mutex); + fw_unit_put(dg00x->unit); } static const struct ieee1394_device_id snd_dg00x_id_table[] = { diff --git a/sound/firewire/fireface/ff.c b/sound/firewire/fireface/ff.c index 73425dfe63bf..37866beeb160 100644 --- a/sound/firewire/fireface/ff.c +++ b/sound/firewire/fireface/ff.c @@ -31,9 +31,6 @@ static void ff_free(struct snd_ff *ff) { snd_ff_stream_destroy_duplex(ff); snd_ff_transaction_unregister(ff); - - mutex_destroy(&ff->mutex); - fw_unit_put(ff->unit); } static void ff_card_free(struct snd_card *card) @@ -147,10 +144,10 @@ static void snd_ff_remove(struct fw_unit *unit) if (ff->registered) { // Block till all of ALSA character devices are released. snd_card_free(ff->card); - } else { - /* Don't forget this case. */ - ff_free(ff); } + + mutex_destroy(&ff->mutex); + fw_unit_put(ff->unit); } static const struct snd_ff_spec spec_ff400 = { diff --git a/sound/firewire/fireworks/fireworks.c b/sound/firewire/fireworks/fireworks.c index 5a17ead86e61..5854d2a87a18 100644 --- a/sound/firewire/fireworks/fireworks.c +++ b/sound/firewire/fireworks/fireworks.c @@ -188,9 +188,6 @@ static void efw_free(struct snd_efw *efw) { snd_efw_stream_destroy_duplex(efw); snd_efw_transaction_remove_instance(efw); - - mutex_destroy(&efw->mutex); - fw_unit_put(efw->unit); } /* @@ -360,10 +357,10 @@ static void efw_remove(struct fw_unit *unit) if (efw->registered) { // Block till all of ALSA character devices are released. snd_card_free(efw->card); - } else { - /* Don't forget this case. */ - efw_free(efw); } + + mutex_destroy(&efw->mutex); + fw_unit_put(efw->unit); } static const struct ieee1394_device_id efw_id_table[] = { diff --git a/sound/firewire/isight.c b/sound/firewire/isight.c index 1f591c8805ea..de4decfb74d5 100644 --- a/sound/firewire/isight.c +++ b/sound/firewire/isight.c @@ -602,8 +602,6 @@ static void isight_card_free(struct snd_card *card) struct isight *isight = card->private_data; fw_iso_resources_destroy(&isight->resources); - fw_unit_put(isight->unit); - mutex_destroy(&isight->mutex); } static u64 get_unit_base(struct fw_unit *unit) @@ -705,6 +703,9 @@ static void isight_remove(struct fw_unit *unit) // Block till all of ALSA character devices are released. snd_card_free(isight->card); + + mutex_destroy(&isight->mutex); + fw_unit_put(isight->unit); } static const struct ieee1394_device_id isight_id_table[] = { diff --git a/sound/firewire/motu/motu.c b/sound/firewire/motu/motu.c index 12680c85b37f..281028ee3273 100644 --- a/sound/firewire/motu/motu.c +++ b/sound/firewire/motu/motu.c @@ -57,9 +57,6 @@ static void motu_free(struct snd_motu *motu) snd_motu_transaction_unregister(motu); snd_motu_stream_destroy_duplex(motu); - - mutex_destroy(&motu->mutex); - fw_unit_put(motu->unit); } /* @@ -174,10 +171,10 @@ static void motu_remove(struct fw_unit *unit) if (motu->registered) { // Block till all of ALSA character devices are released. snd_card_free(motu->card); - } else { - /* Don't forget this case. */ - motu_free(motu); } + + mutex_destroy(&motu->mutex); + fw_unit_put(motu->unit); } static void motu_bus_update(struct fw_unit *unit) diff --git a/sound/firewire/oxfw/oxfw.c b/sound/firewire/oxfw/oxfw.c index 36f905b371e6..14fe02a9ed5d 100644 --- a/sound/firewire/oxfw/oxfw.c +++ b/sound/firewire/oxfw/oxfw.c @@ -118,9 +118,6 @@ static void oxfw_free(struct snd_oxfw *oxfw) snd_oxfw_stream_destroy_simplex(oxfw, &oxfw->rx_stream); if (oxfw->has_output) snd_oxfw_stream_destroy_simplex(oxfw, &oxfw->tx_stream); - - mutex_destroy(&oxfw->mutex); - fw_unit_put(oxfw->unit); } /* @@ -329,10 +326,10 @@ static void oxfw_remove(struct fw_unit *unit) if (oxfw->registered) { // Block till all of ALSA character devices are released. snd_card_free(oxfw->card); - } else { - /* Don't forget this case. */ - oxfw_free(oxfw); } + + mutex_destroy(&oxfw->mutex); + fw_unit_put(oxfw->unit); } static const struct compat_info griffin_firewave = { diff --git a/sound/firewire/tascam/tascam.c b/sound/firewire/tascam/tascam.c index 6f7aaa8c84aa..f4f959128341 100644 --- a/sound/firewire/tascam/tascam.c +++ b/sound/firewire/tascam/tascam.c @@ -89,9 +89,6 @@ static void tscm_free(struct snd_tscm *tscm) { snd_tscm_transaction_unregister(tscm); snd_tscm_stream_destroy_duplex(tscm); - - mutex_destroy(&tscm->mutex); - fw_unit_put(tscm->unit); } static void tscm_card_free(struct snd_card *card) @@ -214,10 +211,10 @@ static void snd_tscm_remove(struct fw_unit *unit) if (tscm->registered) { // Block till all of ALSA character devices are released. snd_card_free(tscm->card); - } else { - /* Don't forget this case. */ - tscm_free(tscm); } + + mutex_destroy(&tscm->mutex); + fw_unit_put(tscm->unit); } static const struct ieee1394_device_id snd_tscm_id_table[] = { From 873608dc6b5da7a2571419bfa10e0d088d39cee0 Mon Sep 17 00:00:00 2001 From: Takashi Sakamoto Date: Wed, 10 Oct 2018 15:35:01 +0900 Subject: [PATCH 244/299] ALSA: bebob/fireworks: simplify handling of local device entry table In drivers of ALSA firewire stack, bebob and fireworks drivers have local device entry table. At present, critical section to operate the table is from the beginning/end of 'do_registration' call. This can be more narrow and simplify codes. This commit applies small refactoring for the above purpose. Signed-off-by: Takashi Sakamoto Signed-off-by: Takashi Iwai --- sound/firewire/bebob/bebob.c | 17 ++++++----------- sound/firewire/fireworks/fireworks.c | 21 +++++++-------------- 2 files changed, 13 insertions(+), 25 deletions(-) diff --git a/sound/firewire/bebob/bebob.c b/sound/firewire/bebob/bebob.c index 34ed8afbb30c..3bc68499974a 100644 --- a/sound/firewire/bebob/bebob.c +++ b/sound/firewire/bebob/bebob.c @@ -128,6 +128,10 @@ end: static void bebob_free(struct snd_bebob *bebob) { + mutex_lock(&devices_mutex); + clear_bit(bebob->card_index, devices_used); + mutex_unlock(&devices_mutex); + snd_bebob_stream_destroy_duplex(bebob); } @@ -140,12 +144,6 @@ static void bebob_free(struct snd_bebob *bebob) static void bebob_card_free(struct snd_card *card) { - struct snd_bebob *bebob = card->private_data; - - mutex_lock(&devices_mutex); - clear_bit(bebob->card_index, devices_used); - mutex_unlock(&devices_mutex); - bebob_free(card->private_data); } @@ -186,7 +184,6 @@ do_registration(struct work_struct *work) return; mutex_lock(&devices_mutex); - for (card_index = 0; card_index < SNDRV_CARDS; card_index++) { if (!test_bit(card_index, devices_used) && enable[card_index]) break; @@ -202,6 +199,8 @@ do_registration(struct work_struct *work) mutex_unlock(&devices_mutex); return; } + set_bit(card_index, devices_used); + mutex_unlock(&devices_mutex); err = name_device(bebob); if (err < 0) @@ -242,9 +241,6 @@ do_registration(struct work_struct *work) if (err < 0) goto error; - set_bit(card_index, devices_used); - mutex_unlock(&devices_mutex); - /* * After registered, bebob instance can be released corresponding to * releasing the sound card instance. @@ -255,7 +251,6 @@ do_registration(struct work_struct *work) return; error: - mutex_unlock(&devices_mutex); snd_bebob_stream_destroy_duplex(bebob); snd_card_free(bebob->card); dev_info(&bebob->unit->device, diff --git a/sound/firewire/fireworks/fireworks.c b/sound/firewire/fireworks/fireworks.c index 5854d2a87a18..da0c31033821 100644 --- a/sound/firewire/fireworks/fireworks.c +++ b/sound/firewire/fireworks/fireworks.c @@ -186,6 +186,10 @@ end: static void efw_free(struct snd_efw *efw) { + mutex_lock(&devices_mutex); + clear_bit(efw->card_index, devices_used); + mutex_unlock(&devices_mutex); + snd_efw_stream_destroy_duplex(efw); snd_efw_transaction_remove_instance(efw); } @@ -199,14 +203,6 @@ static void efw_free(struct snd_efw *efw) static void efw_card_free(struct snd_card *card) { - struct snd_efw *efw = card->private_data; - - if (efw->card_index >= 0) { - mutex_lock(&devices_mutex); - clear_bit(efw->card_index, devices_used); - mutex_unlock(&devices_mutex); - } - efw_free(card->private_data); } @@ -220,9 +216,8 @@ do_registration(struct work_struct *work) if (efw->registered) return; - mutex_lock(&devices_mutex); - /* check registered cards */ + mutex_lock(&devices_mutex); for (card_index = 0; card_index < SNDRV_CARDS; ++card_index) { if (!test_bit(card_index, devices_used) && enable[card_index]) break; @@ -238,6 +233,8 @@ do_registration(struct work_struct *work) mutex_unlock(&devices_mutex); return; } + set_bit(card_index, devices_used); + mutex_unlock(&devices_mutex); /* prepare response buffer */ snd_efw_resp_buf_size = clamp(snd_efw_resp_buf_size, @@ -279,9 +276,6 @@ do_registration(struct work_struct *work) if (err < 0) goto error; - set_bit(card_index, devices_used); - mutex_unlock(&devices_mutex); - /* * After registered, efw instance can be released corresponding to * releasing the sound card instance. @@ -292,7 +286,6 @@ do_registration(struct work_struct *work) return; error: - mutex_unlock(&devices_mutex); snd_efw_transaction_remove_instance(efw); snd_efw_stream_destroy_duplex(efw); snd_card_free(efw->card); From 3babca4555b20fc80aff4776662fb237257d9afd Mon Sep 17 00:00:00 2001 From: Takashi Sakamoto Date: Wed, 10 Oct 2018 15:35:02 +0900 Subject: [PATCH 245/299] ALSA: firewire: simplify cleanup process when failing to register sound card In former commits, .private_free callback releases resources just for data transmission. This release function can be called without the resources are actually allocated in error paths. This commit applies a small refactoring to clean up codes in error paths. Signed-off-by: Takashi Sakamoto Signed-off-by: Takashi Iwai --- sound/firewire/bebob/bebob.c | 27 +++++++-------------------- sound/firewire/dice/dice.c | 28 ++++++---------------------- sound/firewire/digi00x/digi00x.c | 17 ++++++----------- sound/firewire/fireface/ff.c | 17 ++++++----------- sound/firewire/fireworks/fireworks.c | 28 +++++++--------------------- sound/firewire/motu/motu.c | 28 ++++++---------------------- sound/firewire/oxfw/oxfw.c | 26 +++++--------------------- sound/firewire/tascam/tascam.c | 21 ++++++--------------- 8 files changed, 49 insertions(+), 143 deletions(-) diff --git a/sound/firewire/bebob/bebob.c b/sound/firewire/bebob/bebob.c index 3bc68499974a..672d13488454 100644 --- a/sound/firewire/bebob/bebob.c +++ b/sound/firewire/bebob/bebob.c @@ -126,8 +126,11 @@ end: return err; } -static void bebob_free(struct snd_bebob *bebob) +static void +bebob_card_free(struct snd_card *card) { + struct snd_bebob *bebob = card->private_data; + mutex_lock(&devices_mutex); clear_bit(bebob->card_index, devices_used); mutex_unlock(&devices_mutex); @@ -135,18 +138,6 @@ static void bebob_free(struct snd_bebob *bebob) snd_bebob_stream_destroy_duplex(bebob); } -/* - * This module releases the FireWire unit data after all ALSA character devices - * are released by applications. This is for releasing stream data or finishing - * transactions safely. Thus at returning from .remove(), this module still keep - * references for the unit. - */ -static void -bebob_card_free(struct snd_card *card) -{ - bebob_free(card->private_data); -} - static const struct snd_bebob_spec * get_saffire_spec(struct fw_unit *unit) { @@ -202,6 +193,9 @@ do_registration(struct work_struct *work) set_bit(card_index, devices_used); mutex_unlock(&devices_mutex); + bebob->card->private_free = bebob_card_free; + bebob->card->private_data = bebob; + err = name_device(bebob); if (err < 0) goto error; @@ -241,17 +235,10 @@ do_registration(struct work_struct *work) if (err < 0) goto error; - /* - * After registered, bebob instance can be released corresponding to - * releasing the sound card instance. - */ - bebob->card->private_free = bebob_card_free; - bebob->card->private_data = bebob; bebob->registered = true; return; error: - snd_bebob_stream_destroy_duplex(bebob); snd_card_free(bebob->card); dev_info(&bebob->unit->device, "Sound card registration failed: %d\n", err); diff --git a/sound/firewire/dice/dice.c b/sound/firewire/dice/dice.c index c6b63e3f36a8..0f6dbcffe711 100644 --- a/sound/firewire/dice/dice.c +++ b/sound/firewire/dice/dice.c @@ -122,21 +122,12 @@ static void dice_card_strings(struct snd_dice *dice) strcpy(card->mixername, "DICE"); } -static void dice_free(struct snd_dice *dice) -{ - snd_dice_stream_destroy_duplex(dice); - snd_dice_transaction_destroy(dice); -} - -/* - * This module releases the FireWire unit data after all ALSA character devices - * are released by applications. This is for releasing stream data or finishing - * transactions safely. Thus at returning from .remove(), this module still keep - * references for the unit. - */ static void dice_card_free(struct snd_card *card) { - dice_free(card->private_data); + struct snd_dice *dice = card->private_data; + + snd_dice_stream_destroy_duplex(dice); + snd_dice_transaction_destroy(dice); } static void do_registration(struct work_struct *work) @@ -151,6 +142,8 @@ static void do_registration(struct work_struct *work) &dice->card); if (err < 0) return; + dice->card->private_free = dice_card_free; + dice->card->private_data = dice; err = snd_dice_transaction_init(dice); if (err < 0) @@ -188,19 +181,10 @@ static void do_registration(struct work_struct *work) if (err < 0) goto error; - /* - * After registered, dice instance can be released corresponding to - * releasing the sound card instance. - */ - dice->card->private_free = dice_card_free; - dice->card->private_data = dice; dice->registered = true; return; error: - snd_dice_stream_destroy_duplex(dice); - snd_dice_transaction_destroy(dice); - snd_dice_stream_destroy_duplex(dice); snd_card_free(dice->card); dev_info(&dice->unit->device, "Sound card registration failed: %d\n", err); diff --git a/sound/firewire/digi00x/digi00x.c b/sound/firewire/digi00x/digi00x.c index 7a24348968b9..6c6ea149ef6b 100644 --- a/sound/firewire/digi00x/digi00x.c +++ b/sound/firewire/digi00x/digi00x.c @@ -41,15 +41,12 @@ static int name_card(struct snd_dg00x *dg00x) return 0; } -static void dg00x_free(struct snd_dg00x *dg00x) -{ - snd_dg00x_stream_destroy_duplex(dg00x); - snd_dg00x_transaction_unregister(dg00x); -} - static void dg00x_card_free(struct snd_card *card) { - dg00x_free(card->private_data); + struct snd_dg00x *dg00x = card->private_data; + + snd_dg00x_stream_destroy_duplex(dg00x); + snd_dg00x_transaction_unregister(dg00x); } static void do_registration(struct work_struct *work) @@ -65,6 +62,8 @@ static void do_registration(struct work_struct *work) &dg00x->card); if (err < 0) return; + dg00x->card->private_free = dg00x_card_free; + dg00x->card->private_data = dg00x; err = name_card(dg00x); if (err < 0) @@ -96,14 +95,10 @@ static void do_registration(struct work_struct *work) if (err < 0) goto error; - dg00x->card->private_free = dg00x_card_free; - dg00x->card->private_data = dg00x; dg00x->registered = true; return; error: - snd_dg00x_transaction_unregister(dg00x); - snd_dg00x_stream_destroy_duplex(dg00x); snd_card_free(dg00x->card); dev_info(&dg00x->unit->device, "Sound card registration failed: %d\n", err); diff --git a/sound/firewire/fireface/ff.c b/sound/firewire/fireface/ff.c index 37866beeb160..3f61cfeace69 100644 --- a/sound/firewire/fireface/ff.c +++ b/sound/firewire/fireface/ff.c @@ -27,15 +27,12 @@ static void name_card(struct snd_ff *ff) dev_name(&ff->unit->device), 100 << fw_dev->max_speed); } -static void ff_free(struct snd_ff *ff) -{ - snd_ff_stream_destroy_duplex(ff); - snd_ff_transaction_unregister(ff); -} - static void ff_card_free(struct snd_card *card) { - ff_free(card->private_data); + struct snd_ff *ff = card->private_data; + + snd_ff_stream_destroy_duplex(ff); + snd_ff_transaction_unregister(ff); } static void do_registration(struct work_struct *work) @@ -50,6 +47,8 @@ static void do_registration(struct work_struct *work) &ff->card); if (err < 0) return; + ff->card->private_free = ff_card_free; + ff->card->private_data = ff; err = snd_ff_transaction_register(ff); if (err < 0) @@ -79,14 +78,10 @@ static void do_registration(struct work_struct *work) if (err < 0) goto error; - ff->card->private_free = ff_card_free; - ff->card->private_data = ff; ff->registered = true; return; error: - snd_ff_transaction_unregister(ff); - snd_ff_stream_destroy_duplex(ff); snd_card_free(ff->card); dev_info(&ff->unit->device, "Sound card registration failed: %d\n", err); diff --git a/sound/firewire/fireworks/fireworks.c b/sound/firewire/fireworks/fireworks.c index da0c31033821..faf0e001c4c5 100644 --- a/sound/firewire/fireworks/fireworks.c +++ b/sound/firewire/fireworks/fireworks.c @@ -184,8 +184,11 @@ end: return err; } -static void efw_free(struct snd_efw *efw) +static void +efw_card_free(struct snd_card *card) { + struct snd_efw *efw = card->private_data; + mutex_lock(&devices_mutex); clear_bit(efw->card_index, devices_used); mutex_unlock(&devices_mutex); @@ -194,18 +197,6 @@ static void efw_free(struct snd_efw *efw) snd_efw_transaction_remove_instance(efw); } -/* - * This module releases the FireWire unit data after all ALSA character devices - * are released by applications. This is for releasing stream data or finishing - * transactions safely. Thus at returning from .remove(), this module still keep - * references for the unit. - */ -static void -efw_card_free(struct snd_card *card) -{ - efw_free(card->private_data); -} - static void do_registration(struct work_struct *work) { @@ -236,6 +227,9 @@ do_registration(struct work_struct *work) set_bit(card_index, devices_used); mutex_unlock(&devices_mutex); + efw->card->private_free = efw_card_free; + efw->card->private_data = efw; + /* prepare response buffer */ snd_efw_resp_buf_size = clamp(snd_efw_resp_buf_size, SND_EFW_RESPONSE_MAXIMUM_BYTES, 4096U); @@ -276,18 +270,10 @@ do_registration(struct work_struct *work) if (err < 0) goto error; - /* - * After registered, efw instance can be released corresponding to - * releasing the sound card instance. - */ - efw->card->private_free = efw_card_free; - efw->card->private_data = efw; efw->registered = true; return; error: - snd_efw_transaction_remove_instance(efw); - snd_efw_stream_destroy_duplex(efw); snd_card_free(efw->card); dev_info(&efw->unit->device, "Sound card registration failed: %d\n", err); diff --git a/sound/firewire/motu/motu.c b/sound/firewire/motu/motu.c index 281028ee3273..220e61926ea4 100644 --- a/sound/firewire/motu/motu.c +++ b/sound/firewire/motu/motu.c @@ -52,22 +52,12 @@ static void name_card(struct snd_motu *motu) dev_name(&motu->unit->device), 100 << fw_dev->max_speed); } -static void motu_free(struct snd_motu *motu) -{ - snd_motu_transaction_unregister(motu); - - snd_motu_stream_destroy_duplex(motu); -} - -/* - * This module releases the FireWire unit data after all ALSA character devices - * are released by applications. This is for releasing stream data or finishing - * transactions safely. Thus at returning from .remove(), this module still keep - * references for the unit. - */ static void motu_card_free(struct snd_card *card) { - motu_free(card->private_data); + struct snd_motu *motu = card->private_data; + + snd_motu_transaction_unregister(motu); + snd_motu_stream_destroy_duplex(motu); } static void do_registration(struct work_struct *work) @@ -82,6 +72,8 @@ static void do_registration(struct work_struct *work) &motu->card); if (err < 0) return; + motu->card->private_free = motu_card_free; + motu->card->private_data = motu; name_card(motu); @@ -116,18 +108,10 @@ static void do_registration(struct work_struct *work) if (err < 0) goto error; - /* - * After registered, motu instance can be released corresponding to - * releasing the sound card instance. - */ - motu->card->private_free = motu_card_free; - motu->card->private_data = motu; motu->registered = true; return; error: - snd_motu_transaction_unregister(motu); - snd_motu_stream_destroy_duplex(motu); snd_card_free(motu->card); dev_info(&motu->unit->device, "Sound card registration failed: %d\n", err); diff --git a/sound/firewire/oxfw/oxfw.c b/sound/firewire/oxfw/oxfw.c index 14fe02a9ed5d..afb78d90384b 100644 --- a/sound/firewire/oxfw/oxfw.c +++ b/sound/firewire/oxfw/oxfw.c @@ -113,24 +113,15 @@ end: return err; } -static void oxfw_free(struct snd_oxfw *oxfw) +static void oxfw_card_free(struct snd_card *card) { + struct snd_oxfw *oxfw = card->private_data; + snd_oxfw_stream_destroy_simplex(oxfw, &oxfw->rx_stream); if (oxfw->has_output) snd_oxfw_stream_destroy_simplex(oxfw, &oxfw->tx_stream); } -/* - * This module releases the FireWire unit data after all ALSA character devices - * are released by applications. This is for releasing stream data or finishing - * transactions safely. Thus at returning from .remove(), this module still keep - * references for the unit. - */ -static void oxfw_card_free(struct snd_card *card) -{ - oxfw_free(card->private_data); -} - static int detect_quirks(struct snd_oxfw *oxfw) { struct fw_device *fw_dev = fw_parent_device(oxfw->unit); @@ -204,6 +195,8 @@ static void do_registration(struct work_struct *work) &oxfw->card); if (err < 0) return; + oxfw->card->private_free = oxfw_card_free; + oxfw->card->private_data = oxfw; err = name_card(oxfw); if (err < 0) @@ -244,19 +237,10 @@ static void do_registration(struct work_struct *work) if (err < 0) goto error; - /* - * After registered, oxfw instance can be released corresponding to - * releasing the sound card instance. - */ - oxfw->card->private_free = oxfw_card_free; - oxfw->card->private_data = oxfw; oxfw->registered = true; return; error: - snd_oxfw_stream_destroy_simplex(oxfw, &oxfw->rx_stream); - if (oxfw->has_output) - snd_oxfw_stream_destroy_simplex(oxfw, &oxfw->tx_stream); snd_card_free(oxfw->card); dev_info(&oxfw->unit->device, "Sound card registration failed: %d\n", err); diff --git a/sound/firewire/tascam/tascam.c b/sound/firewire/tascam/tascam.c index f4f959128341..ef57fa4db323 100644 --- a/sound/firewire/tascam/tascam.c +++ b/sound/firewire/tascam/tascam.c @@ -85,15 +85,12 @@ static int identify_model(struct snd_tscm *tscm) return 0; } -static void tscm_free(struct snd_tscm *tscm) -{ - snd_tscm_transaction_unregister(tscm); - snd_tscm_stream_destroy_duplex(tscm); -} - static void tscm_card_free(struct snd_card *card) { - tscm_free(card->private_data); + struct snd_tscm *tscm = card->private_data; + + snd_tscm_transaction_unregister(tscm); + snd_tscm_stream_destroy_duplex(tscm); } static void do_registration(struct work_struct *work) @@ -105,6 +102,8 @@ static void do_registration(struct work_struct *work) &tscm->card); if (err < 0) return; + tscm->card->private_free = tscm_card_free; + tscm->card->private_data = tscm; err = identify_model(tscm); if (err < 0) @@ -136,18 +135,10 @@ static void do_registration(struct work_struct *work) if (err < 0) goto error; - /* - * After registered, tscm instance can be released corresponding to - * releasing the sound card instance. - */ - tscm->card->private_free = tscm_card_free; - tscm->card->private_data = tscm; tscm->registered = true; return; error: - snd_tscm_transaction_unregister(tscm); - snd_tscm_stream_destroy_duplex(tscm); snd_card_free(tscm->card); dev_info(&tscm->unit->device, "Sound card registration failed: %d\n", err); From 9641faa2db7e856f50a6d1169e1b9f01e7fcb2b0 Mon Sep 17 00:00:00 2001 From: Arnd Bergmann Date: Wed, 10 Oct 2018 10:37:13 +0200 Subject: [PATCH 246/299] ASoC: max98988: add I2C dependency max98988 only builds with I2C support enabled, otherwise we get a build error: sound/soc/codecs/max98088.c:1789:1: error: data definition has no type or storage class [-Werror] module_i2c_driver(max98088_i2c_driver); ^~~~~~~~~~~~~~~~~ sound/soc/codecs/max98088.c:1789:1: error: type defaults to 'int' in declaration of 'module_i2c_driver' [-Werror=implicit-int] sound/soc/codecs/max98088.c:1789:1: error: parameter names (without types) in function declaration [-Werror] sound/soc/codecs/max98088.c:1780:26: error: 'max98088_i2c_driver' defined but not used [-Werror=unused-variable] Fixes: 24ae67c58250 ("ASoC: max98988: make it selectable") Signed-off-by: Arnd Bergmann Reviewed-by: Marco Felsch Signed-off-by: Mark Brown --- sound/soc/codecs/Kconfig | 1 + 1 file changed, 1 insertion(+) diff --git a/sound/soc/codecs/Kconfig b/sound/soc/codecs/Kconfig index 3c6bd6019b92..774d38310875 100644 --- a/sound/soc/codecs/Kconfig +++ b/sound/soc/codecs/Kconfig @@ -641,6 +641,7 @@ config SND_SOC_LM49453 config SND_SOC_MAX98088 tristate "Maxim MAX98088/9 Low-Power, Stereo Audio Codec" + depends on I2C config SND_SOC_MAX98090 tristate From 82ab7e9a4d3fcec27f745be04063e17da1881dda Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Wed, 10 Oct 2018 02:20:42 +0000 Subject: [PATCH 247/299] ASoC: rsnd: use 32bit TDM width as default commit fb2815f44a9e ("ASoC: rsnd: add support for 16/24 bit slot widths") added TDM width check, and return error if it was not 16/24/32 bit. But it is too strict. This patch uses 32bit same as default. Signed-off-by: Kuninori Morimoto Signed-off-by: Mark Brown --- sound/soc/sh/rcar/core.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/sound/soc/sh/rcar/core.c b/sound/soc/sh/rcar/core.c index 40d7dc4f7839..f930f51b686f 100644 --- a/sound/soc/sh/rcar/core.c +++ b/sound/soc/sh/rcar/core.c @@ -744,8 +744,8 @@ static int rsnd_soc_set_dai_tdm_slot(struct snd_soc_dai *dai, case 32: break; default: - dev_err(dev, "unsupported slot width value: %d\n", slot_width); - return -EINVAL; + /* use default */ + slot_width = 32; } switch (slots) { From 8036dbc490d16dc3d998246e14c9507ec8272ae2 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Wed, 10 Oct 2018 02:22:29 +0000 Subject: [PATCH 248/299] ASoC: audio-graph-card: enable mclk-fs on codec node Current audio-graph-card is supporting mclk-fs on CPU node side only. But having Codec node also is good idea. It will be just ignored if not defined. "rcpu_ep" is same as "cpu_ep", This patch tidyup it, too. Signed-off-by: Kuninori Morimoto Signed-off-by: Mark Brown --- sound/soc/generic/audio-graph-card.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/sound/soc/generic/audio-graph-card.c b/sound/soc/generic/audio-graph-card.c index fb6635f8d5d7..25c819e402e1 100644 --- a/sound/soc/generic/audio-graph-card.c +++ b/sound/soc/generic/audio-graph-card.c @@ -182,7 +182,8 @@ static int asoc_graph_card_dai_link_of(struct device_node *cpu_port, if (ret < 0) goto dai_link_of_err; - of_property_read_u32(rcpu_ep, "mclk-fs", &dai_props->mclk_fs); + of_property_read_u32(cpu_ep, "mclk-fs", &dai_props->mclk_fs); + of_property_read_u32(codec_ep, "mclk-fs", &dai_props->mclk_fs); ret = asoc_simple_card_parse_graph_cpu(cpu_ep, dai_link); if (ret < 0) From 4cbbc91609846c09a8350080cd7e6f7764fb2ec1 Mon Sep 17 00:00:00 2001 From: Ryan Lee Date: Wed, 10 Oct 2018 23:26:06 +0000 Subject: [PATCH 249/299] ASoC: max98373: Sort Digital Volume in reverse order Signed-off-by: Ryan Lee Signed-off-by: Mark Brown --- sound/soc/codecs/max98373.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/sound/soc/codecs/max98373.c b/sound/soc/codecs/max98373.c index d6868c9a9ce6..9b7ccd351cae 100644 --- a/sound/soc/codecs/max98373.c +++ b/sound/soc/codecs/max98373.c @@ -455,7 +455,7 @@ SND_SOC_DAPM_SIGGEN("IMON"), SND_SOC_DAPM_SIGGEN("FBMON"), }; -static DECLARE_TLV_DB_SCALE(max98373_digital_tlv, 0, -50, 0); +static DECLARE_TLV_DB_SCALE(max98373_digital_tlv, -6350, 50, 1); static const DECLARE_TLV_DB_RANGE(max98373_spk_tlv, 0, 8, TLV_DB_SCALE_ITEM(0, 50, 0), 9, 10, TLV_DB_SCALE_ITEM(500, 100, 0), @@ -605,7 +605,7 @@ SOC_SINGLE("Dither Switch", MAX98373_R203F_AMP_DSP_CFG, SOC_SINGLE("DC Blocker Switch", MAX98373_R203F_AMP_DSP_CFG, MAX98373_AMP_DSP_CFG_DCBLK_SHIFT, 1, 0), SOC_SINGLE_TLV("Digital Volume", MAX98373_R203D_AMP_DIG_VOL_CTRL, - 0, 0x7F, 0, max98373_digital_tlv), + 0, 0x7F, 1, max98373_digital_tlv), SOC_SINGLE_TLV("Speaker Volume", MAX98373_R203E_AMP_PATH_GAIN, MAX98373_SPK_DIGI_GAIN_SHIFT, 10, 0, max98373_spk_tlv), SOC_SINGLE_TLV("FS Max Volume", MAX98373_R203E_AMP_PATH_GAIN, From 6c3beeca424a0c8d6c79184a880a8954bd498d57 Mon Sep 17 00:00:00 2001 From: Ryan Lee Date: Wed, 10 Oct 2018 23:26:10 +0000 Subject: [PATCH 250/299] ASoC: max98373: Sort BDE Limiter Thresh Volume in reverse order Signed-off-by: Ryan Lee Signed-off-by: Mark Brown --- sound/soc/codecs/max98373.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/sound/soc/codecs/max98373.c b/sound/soc/codecs/max98373.c index 9b7ccd351cae..38871677cbae 100644 --- a/sound/soc/codecs/max98373.c +++ b/sound/soc/codecs/max98373.c @@ -479,7 +479,7 @@ static const DECLARE_TLV_DB_RANGE(max98373_dht_rotation_point_tlv, 14, 15, TLV_DB_SCALE_ITEM(-2500, -500, 0), ); static const DECLARE_TLV_DB_RANGE(max98373_limiter_thresh_tlv, - 0, 15, TLV_DB_SCALE_ITEM(0, -100, 0), + 0, 15, TLV_DB_SCALE_ITEM(-1500, 100, 0), ); static const DECLARE_TLV_DB_RANGE(max98373_bde_gain_tlv, @@ -670,13 +670,13 @@ SOC_SINGLE_TLV("BDE LVL3 Clip Reduction Volume", MAX98373_R20B0_BDE_L3_CFG_3, SOC_SINGLE_TLV("BDE LVL4 Clip Reduction Volume", MAX98373_R20B3_BDE_L4_CFG_3, 0, 0x3C, 0, max98373_bde_gain_tlv), SOC_SINGLE_TLV("BDE LVL1 Limiter Thresh Volume", MAX98373_R20A8_BDE_L1_CFG_1, - 0, 0xF, 0, max98373_limiter_thresh_tlv), + 0, 0xF, 1, max98373_limiter_thresh_tlv), SOC_SINGLE_TLV("BDE LVL2 Limiter Thresh Volume", MAX98373_R20AB_BDE_L2_CFG_1, - 0, 0xF, 0, max98373_limiter_thresh_tlv), + 0, 0xF, 1, max98373_limiter_thresh_tlv), SOC_SINGLE_TLV("BDE LVL3 Limiter Thresh Volume", MAX98373_R20AE_BDE_L3_CFG_1, - 0, 0xF, 0, max98373_limiter_thresh_tlv), + 0, 0xF, 1, max98373_limiter_thresh_tlv), SOC_SINGLE_TLV("BDE LVL4 Limiter Thresh Volume", MAX98373_R20B1_BDE_L4_CFG_1, - 0, 0xF, 0, max98373_limiter_thresh_tlv), + 0, 0xF, 1, max98373_limiter_thresh_tlv), /* Limiter */ SOC_SINGLE("Limiter Switch", MAX98373_R20E2_LIMITER_EN, MAX98373_LIMITER_EN_SHIFT, 1, 0), From d34c8f37c75b739efc26383145a43497143ada88 Mon Sep 17 00:00:00 2001 From: Ryan Lee Date: Wed, 10 Oct 2018 23:26:13 +0000 Subject: [PATCH 251/299] ASoC: max98373: Sort max98373_bde_gain_tlv in reverse order Signed-off-by: Ryan Lee Signed-off-by: Mark Brown --- sound/soc/codecs/max98373.c | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/sound/soc/codecs/max98373.c b/sound/soc/codecs/max98373.c index 38871677cbae..37f8bcdd8e35 100644 --- a/sound/soc/codecs/max98373.c +++ b/sound/soc/codecs/max98373.c @@ -483,7 +483,7 @@ static const DECLARE_TLV_DB_RANGE(max98373_limiter_thresh_tlv, ); static const DECLARE_TLV_DB_RANGE(max98373_bde_gain_tlv, - 0, 60, TLV_DB_SCALE_ITEM(0, -25, 0), + 0, 60, TLV_DB_SCALE_ITEM(-1500, 25, 0), ); static bool max98373_readable_register(struct device *dev, unsigned int reg) @@ -654,21 +654,21 @@ SOC_SINGLE("BDE Hold Time", MAX98373_R2090_BDE_LVL_HOLD, 0, 0xFF, 0), SOC_SINGLE("BDE Attack Rate", MAX98373_R2091_BDE_GAIN_ATK_REL_RATE, 4, 0xF, 0), SOC_SINGLE("BDE Release Rate", MAX98373_R2091_BDE_GAIN_ATK_REL_RATE, 0, 0xF, 0), SOC_SINGLE_TLV("BDE LVL1 Clip Thresh Volume", MAX98373_R20A9_BDE_L1_CFG_2, - 0, 0x3C, 0, max98373_bde_gain_tlv), + 0, 0x3C, 1, max98373_bde_gain_tlv), SOC_SINGLE_TLV("BDE LVL2 Clip Thresh Volume", MAX98373_R20AC_BDE_L2_CFG_2, - 0, 0x3C, 0, max98373_bde_gain_tlv), + 0, 0x3C, 1, max98373_bde_gain_tlv), SOC_SINGLE_TLV("BDE LVL3 Clip Thresh Volume", MAX98373_R20AF_BDE_L3_CFG_2, - 0, 0x3C, 0, max98373_bde_gain_tlv), + 0, 0x3C, 1, max98373_bde_gain_tlv), SOC_SINGLE_TLV("BDE LVL4 Clip Thresh Volume", MAX98373_R20B2_BDE_L4_CFG_2, - 0, 0x3C, 0, max98373_bde_gain_tlv), + 0, 0x3C, 1, max98373_bde_gain_tlv), SOC_SINGLE_TLV("BDE LVL1 Clip Reduction Volume", MAX98373_R20AA_BDE_L1_CFG_3, - 0, 0x3C, 0, max98373_bde_gain_tlv), + 0, 0x3C, 1, max98373_bde_gain_tlv), SOC_SINGLE_TLV("BDE LVL2 Clip Reduction Volume", MAX98373_R20AD_BDE_L2_CFG_3, - 0, 0x3C, 0, max98373_bde_gain_tlv), + 0, 0x3C, 1, max98373_bde_gain_tlv), SOC_SINGLE_TLV("BDE LVL3 Clip Reduction Volume", MAX98373_R20B0_BDE_L3_CFG_3, - 0, 0x3C, 0, max98373_bde_gain_tlv), + 0, 0x3C, 1, max98373_bde_gain_tlv), SOC_SINGLE_TLV("BDE LVL4 Clip Reduction Volume", MAX98373_R20B3_BDE_L4_CFG_3, - 0, 0x3C, 0, max98373_bde_gain_tlv), + 0, 0x3C, 1, max98373_bde_gain_tlv), SOC_SINGLE_TLV("BDE LVL1 Limiter Thresh Volume", MAX98373_R20A8_BDE_L1_CFG_1, 0, 0xF, 1, max98373_limiter_thresh_tlv), SOC_SINGLE_TLV("BDE LVL2 Limiter Thresh Volume", MAX98373_R20AB_BDE_L2_CFG_1, From a23f5dc8448694a0ffe2127a04aa5787b9cf9e5f Mon Sep 17 00:00:00 2001 From: Ryan Lee Date: Wed, 10 Oct 2018 23:26:17 +0000 Subject: [PATCH 252/299] ASoC: max98373: Sort DHT Rot Pnt Volume in reverse order Signed-off-by: Ryan Lee Signed-off-by: Mark Brown --- sound/soc/codecs/max98373.c | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/sound/soc/codecs/max98373.c b/sound/soc/codecs/max98373.c index 37f8bcdd8e35..a09d01318f79 100644 --- a/sound/soc/codecs/max98373.c +++ b/sound/soc/codecs/max98373.c @@ -471,12 +471,12 @@ static const DECLARE_TLV_DB_RANGE(max98373_dht_spkgain_min_tlv, 0, 9, TLV_DB_SCALE_ITEM(800, 100, 0), ); static const DECLARE_TLV_DB_RANGE(max98373_dht_rotation_point_tlv, - 0, 1, TLV_DB_SCALE_ITEM(-50, -50, 0), - 2, 7, TLV_DB_SCALE_ITEM(-200, -100, 0), - 8, 9, TLV_DB_SCALE_ITEM(-1000, -200, 0), - 10, 11, TLV_DB_SCALE_ITEM(-1500, -300, 0), - 12, 13, TLV_DB_SCALE_ITEM(-2000, -200, 0), - 14, 15, TLV_DB_SCALE_ITEM(-2500, -500, 0), + 0, 1, TLV_DB_SCALE_ITEM(-3000, 500, 0), + 2, 4, TLV_DB_SCALE_ITEM(-2200, 200, 0), + 5, 6, TLV_DB_SCALE_ITEM(-1500, 300, 0), + 7, 9, TLV_DB_SCALE_ITEM(-1000, 200, 0), + 10, 13, TLV_DB_SCALE_ITEM(-500, 100, 0), + 14, 15, TLV_DB_SCALE_ITEM(-100, 50, 0), ); static const DECLARE_TLV_DB_RANGE(max98373_limiter_thresh_tlv, 0, 15, TLV_DB_SCALE_ITEM(-1500, 100, 0), @@ -617,7 +617,7 @@ SOC_SINGLE("DHT Switch", MAX98373_R20D4_DHT_EN, SOC_SINGLE_TLV("DHT Min Volume", MAX98373_R20D1_DHT_CFG, MAX98373_DHT_SPK_GAIN_MIN_SHIFT, 9, 0, max98373_dht_spkgain_min_tlv), SOC_SINGLE_TLV("DHT Rot Pnt Volume", MAX98373_R20D1_DHT_CFG, - MAX98373_DHT_ROT_PNT_SHIFT, 15, 0, max98373_dht_rotation_point_tlv), + MAX98373_DHT_ROT_PNT_SHIFT, 15, 1, max98373_dht_rotation_point_tlv), SOC_SINGLE_TLV("DHT Attack Step Volume", MAX98373_R20D2_DHT_ATTACK_CFG, MAX98373_DHT_ATTACK_STEP_SHIFT, 4, 0, max98373_dht_step_size_tlv), SOC_SINGLE_TLV("DHT Release Step Volume", MAX98373_R20D3_DHT_RELEASE_CFG, From e7bb6ad5685f05685dd8a6a5eda7bfcd14d5f95b Mon Sep 17 00:00:00 2001 From: Jeremy Cline Date: Thu, 11 Oct 2018 15:49:17 -0400 Subject: [PATCH 253/299] ALSA: hda - Add mic quirk for the Lenovo G50-30 (17aa:3905) The Lenovo G50-30, like other G50 models, has a Conexant codec that requires a quirk for its inverted stereo dmic. Bugzilla: https://bugzilla.redhat.com/show_bug.cgi?id=1249364 Reported-by: Alexander Ploumistos Tested-by: Alexander Ploumistos Cc: stable@vger.kernel.org Signed-off-by: Jeremy Cline Signed-off-by: Takashi Iwai --- sound/pci/hda/patch_conexant.c | 1 + 1 file changed, 1 insertion(+) diff --git a/sound/pci/hda/patch_conexant.c b/sound/pci/hda/patch_conexant.c index 5592557fe50e..950e02e71766 100644 --- a/sound/pci/hda/patch_conexant.c +++ b/sound/pci/hda/patch_conexant.c @@ -943,6 +943,7 @@ static const struct snd_pci_quirk cxt5066_fixups[] = { SND_PCI_QUIRK(0x17aa, 0x21da, "Lenovo X220", CXT_PINCFG_LENOVO_TP410), SND_PCI_QUIRK(0x17aa, 0x21db, "Lenovo X220-tablet", CXT_PINCFG_LENOVO_TP410), SND_PCI_QUIRK(0x17aa, 0x38af, "Lenovo IdeaPad Z560", CXT_FIXUP_MUTE_LED_EAPD), + SND_PCI_QUIRK(0x17aa, 0x3905, "Lenovo G50-30", CXT_FIXUP_STEREO_DMIC), SND_PCI_QUIRK(0x17aa, 0x390b, "Lenovo G50-80", CXT_FIXUP_STEREO_DMIC), SND_PCI_QUIRK(0x17aa, 0x3975, "Lenovo U300s", CXT_FIXUP_STEREO_DMIC), SND_PCI_QUIRK(0x17aa, 0x3977, "Lenovo IdeaPad U310", CXT_FIXUP_STEREO_DMIC), From 51e68fb0929c29e47e9074ca3e99ffd6021a1c5a Mon Sep 17 00:00:00 2001 From: Takashi Sakamoto Date: Fri, 12 Oct 2018 14:25:22 +0900 Subject: [PATCH 254/299] ALSA: isight: fix leak of reference to firewire unit in error path of .probe callback In some error paths, reference count of firewire unit is not decreased. This commit fixes the bug. Fixes: 5b14ec25a79b('ALSA: firewire: release reference count of firewire unit in .remove callback of bus driver') Signed-off-by: Takashi Sakamoto Signed-off-by: Takashi Iwai --- sound/firewire/isight.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/sound/firewire/isight.c b/sound/firewire/isight.c index de4decfb74d5..9ebe510ea26b 100644 --- a/sound/firewire/isight.c +++ b/sound/firewire/isight.c @@ -638,7 +638,7 @@ static int isight_probe(struct fw_unit *unit, if (!isight->audio_base) { dev_err(&unit->device, "audio unit base not found\n"); err = -ENXIO; - goto err_unit; + goto error; } fw_iso_resources_init(&isight->resources, unit); @@ -667,12 +667,12 @@ static int isight_probe(struct fw_unit *unit, dev_set_drvdata(&unit->device, isight); return 0; - -err_unit: - fw_unit_put(isight->unit); - mutex_destroy(&isight->mutex); error: snd_card_free(card); + + mutex_destroy(&isight->mutex); + fw_unit_put(isight->unit); + return err; } From e953c7ecdf07f23310cd631913ee829c38de3aa2 Mon Sep 17 00:00:00 2001 From: Takashi Sakamoto Date: Fri, 12 Oct 2018 16:08:59 +0900 Subject: [PATCH 255/299] ALSA: firewire-motu: add missing entries to Kconfig MOTU Traveler and Audio Express are supported as well. Signed-off-by: Takashi Sakamoto Signed-off-by: Takashi Iwai --- sound/firewire/Kconfig | 2 ++ 1 file changed, 2 insertions(+) diff --git a/sound/firewire/Kconfig b/sound/firewire/Kconfig index 529d9f405fa9..8a146b039276 100644 --- a/sound/firewire/Kconfig +++ b/sound/firewire/Kconfig @@ -147,7 +147,9 @@ config SND_FIREWIRE_MOTU help Say Y here to enable support for FireWire devices which MOTU produced: * 828mk2 + * Traveler * 828mk3 + * Audio Express To compile this driver as a module, choose M here: the module will be called snd-firewire-motu. From 3c4cfa7bf6075be035cff3cac0986395f6fca32b Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Thu, 4 Oct 2018 19:54:51 +0200 Subject: [PATCH 256/299] ALSA: memalloc: Add fall-through annotation As a preparatory patch for the upcoming -Wimplicit-fallthrough compiler checks, add the "fall through" annotation in snd_dma_alloc_pages(). Note that this seems necessary to be put exactly before the next label, so it's outside the ifdef block. Signed-off-by: Takashi Iwai --- sound/core/memalloc.c | 1 + 1 file changed, 1 insertion(+) diff --git a/sound/core/memalloc.c b/sound/core/memalloc.c index aa266907ec9b..59a4adc286ed 100644 --- a/sound/core/memalloc.c +++ b/sound/core/memalloc.c @@ -203,6 +203,7 @@ int snd_dma_alloc_pages(int type, struct device *device, size_t size, */ dmab->dev.type = SNDRV_DMA_TYPE_DEV; #endif /* CONFIG_GENERIC_ALLOCATOR */ + /* fall through */ case SNDRV_DMA_TYPE_DEV: case SNDRV_DMA_TYPE_DEV_UC: snd_malloc_dev_pages(dmab, size); From 590b516e25636c696550b44b11fcfed42167adfd Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Thu, 4 Oct 2018 19:58:23 +0200 Subject: [PATCH 257/299] ALSA: caiaq: Add fall-through annotation As a preparatory patch for the upcoming -Wimplicit-fallthrough compiler checks, add the "fall through" annotation in caiaq driver. Note that this seems necessary to be put exactly before the next label, so it's outside the ifdef block. Signed-off-by: Takashi Iwai --- sound/usb/caiaq/device.c | 1 + 1 file changed, 1 insertion(+) diff --git a/sound/usb/caiaq/device.c b/sound/usb/caiaq/device.c index d55ca48de3ea..f4a72e39ffa9 100644 --- a/sound/usb/caiaq/device.c +++ b/sound/usb/caiaq/device.c @@ -200,6 +200,7 @@ static void usb_ep1_command_reply_dispatch (struct urb* urb) break; } #ifdef CONFIG_SND_USB_CAIAQ_INPUT + /* fall through */ case EP1_CMD_READ_ERP: case EP1_CMD_READ_ANALOG: snd_usb_caiaq_input_dispatch(cdev, buf, urb->actual_length); From e8c92251a8351f9550a9e20a47364d0a20f28d95 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Thu, 4 Oct 2018 19:59:41 +0200 Subject: [PATCH 258/299] ALSA: seq: oss: Use the standard fall-through annotation As a preparatory patch for the upcoming -Wimplicit-fallthrough compiler checks, replace with the standard "fall through" annotation. Unfortunately gcc doesn't understand a chattier text. Signed-off-by: Takashi Iwai --- sound/core/seq/oss/seq_oss_timer.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sound/core/seq/oss/seq_oss_timer.c b/sound/core/seq/oss/seq_oss_timer.c index ba127c22539a..0778d28421da 100644 --- a/sound/core/seq/oss/seq_oss_timer.c +++ b/sound/core/seq/oss/seq_oss_timer.c @@ -92,7 +92,7 @@ snd_seq_oss_process_timer_event(struct seq_oss_timer *rec, union evrec *ev) case TMR_WAIT_REL: parm += rec->cur_tick; rec->realtime = 0; - /* fall through and continue to next */ + /* fall through */ case TMR_WAIT_ABS: if (parm == 0) { rec->realtime = 1; From 74ce5a46bb7b0298dc0be11bae944fca5d1f18a7 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Thu, 4 Oct 2018 20:02:06 +0200 Subject: [PATCH 259/299] ALSA: opti92xx-ad1848: Use the standard fall-through annotation As a preparatory patch for the upcoming -Wimplicit-fallthrough compiler checks, replace with the standard "fall through" annotation at the right places. They have to be put right before the next labels. Signed-off-by: Takashi Iwai --- sound/isa/opti9xx/opti92x-ad1848.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/sound/isa/opti9xx/opti92x-ad1848.c b/sound/isa/opti9xx/opti92x-ad1848.c index ac0ab6eb40f0..47e0b2820ace 100644 --- a/sound/isa/opti9xx/opti92x-ad1848.c +++ b/sound/isa/opti9xx/opti92x-ad1848.c @@ -389,7 +389,8 @@ static int snd_opti9xx_configure(struct snd_opti9xx *chip, case OPTi9XX_HW_82C931: /* disable 3D sound (set GPIO1 as output, low) */ snd_opti9xx_write_mask(chip, OPTi9XX_MC_REG(20), 0x04, 0x0c); - case OPTi9XX_HW_82C933: /* FALL THROUGH */ + /* fall through */ + case OPTi9XX_HW_82C933: /* * The BTC 1817DW has QS1000 wavetable which is connected * to the serial digital input of the OPTI931. @@ -400,7 +401,8 @@ static int snd_opti9xx_configure(struct snd_opti9xx *chip, * or digital input signal. */ snd_opti9xx_write_mask(chip, OPTi9XX_MC_REG(26), 0x01, 0x01); - case OPTi9XX_HW_82C930: /* FALL THROUGH */ + /* fall through */ + case OPTi9XX_HW_82C930: snd_opti9xx_write_mask(chip, OPTi9XX_MC_REG(6), 0x02, 0x03); snd_opti9xx_write_mask(chip, OPTi9XX_MC_REG(3), 0x00, 0xff); snd_opti9xx_write_mask(chip, OPTi9XX_MC_REG(4), 0x10 | From 68da4fa51af4ea9d10099e48351b3cdaae7b1d23 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Thu, 4 Oct 2018 20:04:38 +0200 Subject: [PATCH 260/299] ALSA: au88xx: Add fall-through annotations As a preparatory patch for the upcoming -Wimplicit-fallthrough compiler checks, add the "fall through" annotation in au88xx driver. Although the usages in both both functions vortex_adbdma_setbuffers() and vortex_wtdma_setbuffers() look a bit suspicious, we keep the behavior as before, just to be safer. If it were broken, we should have already received bug reports. Signed-off-by: Takashi Iwai --- sound/pci/au88x0/au88x0_core.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/sound/pci/au88x0/au88x0_core.c b/sound/pci/au88x0/au88x0_core.c index 2e5b460a847c..96ece1a71cf1 100644 --- a/sound/pci/au88x0/au88x0_core.c +++ b/sound/pci/au88x0/au88x0_core.c @@ -1115,6 +1115,7 @@ vortex_adbdma_setbuffers(vortex_t * vortex, int adbdma, hwwrite(vortex->mmio, VORTEX_ADBDMA_BUFBASE + (adbdma << 4) + 0xc, snd_pcm_sgbuf_get_addr(dma->substream, psize * 3)); + /* fall through */ /* 3 pages */ case 3: dma->cfg0 |= 0x12000000; @@ -1122,12 +1123,14 @@ vortex_adbdma_setbuffers(vortex_t * vortex, int adbdma, hwwrite(vortex->mmio, VORTEX_ADBDMA_BUFBASE + (adbdma << 4) + 0x8, snd_pcm_sgbuf_get_addr(dma->substream, psize * 2)); + /* fall through */ /* 2 pages */ case 2: dma->cfg0 |= 0x88000000 | 0x44000000 | 0x10000000 | (psize - 1); hwwrite(vortex->mmio, VORTEX_ADBDMA_BUFBASE + (adbdma << 4) + 0x4, snd_pcm_sgbuf_get_addr(dma->substream, psize)); + /* fall through */ /* 1 page */ case 1: dma->cfg0 |= 0x80000000 | 0x40000000 | ((psize - 1) << 0xc); @@ -1390,17 +1393,20 @@ vortex_wtdma_setbuffers(vortex_t * vortex, int wtdma, dma->cfg1 |= 0x88000000 | 0x44000000 | 0x30000000 | (psize-1); hwwrite(vortex->mmio, VORTEX_WTDMA_BUFBASE + (wtdma << 4) + 0xc, snd_pcm_sgbuf_get_addr(dma->substream, psize * 3)); + /* fall through */ /* 3 pages */ case 3: dma->cfg0 |= 0x12000000; dma->cfg1 |= 0x80000000 | 0x40000000 | ((psize-1) << 0xc); hwwrite(vortex->mmio, VORTEX_WTDMA_BUFBASE + (wtdma << 4) + 0x8, snd_pcm_sgbuf_get_addr(dma->substream, psize * 2)); + /* fall through */ /* 2 pages */ case 2: dma->cfg0 |= 0x88000000 | 0x44000000 | 0x10000000 | (psize-1); hwwrite(vortex->mmio, VORTEX_WTDMA_BUFBASE + (wtdma << 4) + 0x4, snd_pcm_sgbuf_get_addr(dma->substream, psize)); + /* fall through */ /* 1 page */ case 1: dma->cfg0 |= 0x80000000 | 0x40000000 | ((psize-1) << 0xc); From 747df19747bc9752cd40b9cce761e17a033aa5c2 Mon Sep 17 00:00:00 2001 From: Daniel Mack Date: Thu, 11 Oct 2018 20:32:05 +0200 Subject: [PATCH 261/299] ASoC: sta32x: set ->component pointer in private struct The ESD watchdog code in sta32x_watchdog() dereferences the pointer which is never assigned. This is a regression from a1be4cead9b950 ("ASoC: sta32x: Convert to direct regmap API usage.") which went unnoticed since nobody seems to use that ESD workaround. Fixes: a1be4cead9b950 ("ASoC: sta32x: Convert to direct regmap API usage.") Signed-off-by: Daniel Mack Signed-off-by: Mark Brown Cc: stable@vger.kernel.org --- sound/soc/codecs/sta32x.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/sound/soc/codecs/sta32x.c b/sound/soc/codecs/sta32x.c index d5035f2f2b2b..ce508b4cc85c 100644 --- a/sound/soc/codecs/sta32x.c +++ b/sound/soc/codecs/sta32x.c @@ -879,6 +879,9 @@ static int sta32x_probe(struct snd_soc_component *component) struct sta32x_priv *sta32x = snd_soc_component_get_drvdata(component); struct sta32x_platform_data *pdata = sta32x->pdata; int i, ret = 0, thermal = 0; + + sta32x->component = component; + ret = regulator_bulk_enable(ARRAY_SIZE(sta32x->supplies), sta32x->supplies); if (ret != 0) { From 3809688980205622f75ed5d5890759430da4e7e4 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Fri, 12 Oct 2018 06:31:00 +0000 Subject: [PATCH 262/299] ASoC: pcm3168a: add HW constraint for non RIGHT_J RIGHT_J only can handle 16bit data bits. Current driver just errored if user requests non RIGHT_J + 16bit combination. But it is not useful for user. This patch adds HW constraint for it, and avoid error on such situation. Signed-off-by: Kuninori Morimoto Signed-off-by: Mark Brown --- sound/soc/codecs/pcm3168a.c | 36 ++++++++++++++++++++++++++++++++++++ 1 file changed, 36 insertions(+) diff --git a/sound/soc/codecs/pcm3168a.c b/sound/soc/codecs/pcm3168a.c index 3356c91f55b0..233a8df5d7a5 100644 --- a/sound/soc/codecs/pcm3168a.c +++ b/sound/soc/codecs/pcm3168a.c @@ -476,7 +476,43 @@ static int pcm3168a_hw_params(struct snd_pcm_substream *substream, return 0; } +static int pcm3168a_startup(struct snd_pcm_substream *substream, + struct snd_soc_dai *dai) +{ + struct snd_soc_component *component = dai->component; + struct pcm3168a_priv *pcm3168a = snd_soc_component_get_drvdata(component); + bool tx = substream->stream == SNDRV_PCM_STREAM_PLAYBACK; + unsigned int fmt; + unsigned int sample_min; + + if (tx) + fmt = pcm3168a->dac_fmt; + else + fmt = pcm3168a->adc_fmt; + + /* + * Available Data Bits + * + * RIGHT_J : 24 / 16 + * LEFT_J : 24 + * I2S : 24 + */ + switch (fmt) { + case PCM3168A_FMT_RIGHT_J: + sample_min = 16; + break; + default: + sample_min = 24; + } + + snd_pcm_hw_constraint_minmax(substream->runtime, + SNDRV_PCM_HW_PARAM_SAMPLE_BITS, + sample_min, 32); + + return 0; +} static const struct snd_soc_dai_ops pcm3168a_dac_dai_ops = { + .startup = pcm3168a_startup, .set_fmt = pcm3168a_set_dai_fmt_dac, .set_sysclk = pcm3168a_set_dai_sysclk, .hw_params = pcm3168a_hw_params, From 594680ea4a394f19d38a39a7d7c673fbad02a3d6 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Fri, 12 Oct 2018 06:31:18 +0000 Subject: [PATCH 263/299] ASoC: pcm3168a: add hw constraint for channel LEFT_J / I2S only can use TDM. This patch adds channel constraint for it. Signed-off-by: Kuninori Morimoto Signed-off-by: Mark Brown --- sound/soc/codecs/pcm3168a.c | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/sound/soc/codecs/pcm3168a.c b/sound/soc/codecs/pcm3168a.c index 233a8df5d7a5..f0e2b886323e 100644 --- a/sound/soc/codecs/pcm3168a.c +++ b/sound/soc/codecs/pcm3168a.c @@ -484,6 +484,7 @@ static int pcm3168a_startup(struct snd_pcm_substream *substream, bool tx = substream->stream == SNDRV_PCM_STREAM_PLAYBACK; unsigned int fmt; unsigned int sample_min; + unsigned int channel_max; if (tx) fmt = pcm3168a->dac_fmt; @@ -496,19 +497,38 @@ static int pcm3168a_startup(struct snd_pcm_substream *substream, * RIGHT_J : 24 / 16 * LEFT_J : 24 * I2S : 24 + * + * TDM available + * + * I2S + * LEFT_J */ switch (fmt) { case PCM3168A_FMT_RIGHT_J: sample_min = 16; + channel_max = 2; + break; + case PCM3168A_FMT_LEFT_J: + sample_min = 24; + channel_max = 8; + break; + case PCM3168A_FMT_I2S: + sample_min = 24; + channel_max = 8; break; default: sample_min = 24; + channel_max = 2; } snd_pcm_hw_constraint_minmax(substream->runtime, SNDRV_PCM_HW_PARAM_SAMPLE_BITS, sample_min, 32); + snd_pcm_hw_constraint_minmax(substream->runtime, + SNDRV_PCM_HW_PARAM_CHANNELS, + 2, channel_max); + return 0; } static const struct snd_soc_dai_ops pcm3168a_dac_dai_ops = { From 471a7ba89158c6d52dae69636c94c4aa1a6b7b22 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Fri, 12 Oct 2018 06:31:49 +0000 Subject: [PATCH 264/299] ASoC: pcm3168a: add I2S/Left_J TDM support pcm3168a is supporting TDM on I2S/Left_J, but there is no settings for it. This patch add it. Signed-off-by: Kuninori Morimoto Signed-off-by: Mark Brown --- sound/soc/codecs/pcm3168a.c | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/sound/soc/codecs/pcm3168a.c b/sound/soc/codecs/pcm3168a.c index f0e2b886323e..63aa02592bc0 100644 --- a/sound/soc/codecs/pcm3168a.c +++ b/sound/soc/codecs/pcm3168a.c @@ -33,6 +33,8 @@ #define PCM3168A_FMT_RIGHT_J_16 0x3 #define PCM3168A_FMT_DSP_A 0x4 #define PCM3168A_FMT_DSP_B 0x5 +#define PCM3168A_FMT_I2S_TDM 0x6 +#define PCM3168A_FMT_LEFT_J_TDM 0x7 #define PCM3168A_FMT_DSP_MASK 0x4 #define PCM3168A_NUM_SUPPLIES 6 @@ -401,9 +403,11 @@ static int pcm3168a_hw_params(struct snd_pcm_substream *substream, bool tx, master_mode; u32 val, mask, shift, reg; unsigned int rate, fmt, ratio, max_ratio; + unsigned int chan; int i, min_frame_size; rate = params_rate(params); + chan = params_channels(params); ratio = pcm3168a->sysclk / rate; @@ -456,6 +460,21 @@ static int pcm3168a_hw_params(struct snd_pcm_substream *substream, return -EINVAL; } + /* for TDM */ + if (chan > 2) { + switch (fmt) { + case PCM3168A_FMT_I2S: + fmt = PCM3168A_FMT_I2S_TDM; + break; + case PCM3168A_FMT_LEFT_J: + fmt = PCM3168A_FMT_LEFT_J_TDM; + break; + default: + dev_err(component->dev, "TDM is supported under I2S/Left_J only\n"); + return -EINVAL; + } + } + if (master_mode) val = ((i + 1) << shift); else From 23fdf223bbe4bd42bbb3f0f5b9d5e64a58956ef7 Mon Sep 17 00:00:00 2001 From: Christoph Hellwig Date: Sat, 13 Oct 2018 17:17:03 +0200 Subject: [PATCH 265/299] ALSA: asihpi: don't pass GFP_DMA32 to dma_alloc_coherent The DMA API does its own zone decisions based on the coherent_dma_mask. [ Note: as the driver doesn't set the DMA coherent mask, we can assume the default 32bit DMA, hence it should be safe to drop the flag here -- tiwai ] Signed-off-by: Christoph Hellwig Signed-off-by: Takashi Iwai --- sound/pci/asihpi/hpios.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sound/pci/asihpi/hpios.c b/sound/pci/asihpi/hpios.c index 5ef4fe964366..7c91330af719 100644 --- a/sound/pci/asihpi/hpios.c +++ b/sound/pci/asihpi/hpios.c @@ -49,7 +49,7 @@ u16 hpios_locked_mem_alloc(struct consistent_dma_area *p_mem_area, u32 size, /*?? any benefit in using managed dmam_alloc_coherent? */ p_mem_area->vaddr = dma_alloc_coherent(&pdev->dev, size, &p_mem_area->dma_handle, - GFP_DMA32 | GFP_KERNEL); + GFP_KERNEL); if (p_mem_area->vaddr) { HPI_DEBUG_LOG(DEBUG, "allocated %d bytes, dma 0x%x vma %p\n", From 2657c6a9037df1c98eb5dae10dd554ac8c37d38f Mon Sep 17 00:00:00 2001 From: Akshu Agrawal Date: Mon, 15 Oct 2018 12:24:44 +0530 Subject: [PATCH 266/299] ASoC: AMD: Add SND_JACK_LINEOUT jack type Some 3 pole connectors report impedance greater than threshold of 1000Ohm. Thus, da7219 reports them as LINEOUT. Adding the SND_JACK_LINEOUT type so that we don't fail to detect any 3 pole jack type. Also, changing SND_JACK_HEADPHONE | SND_JACK_MICROPHONE -> SND_JACK_HEADSET Signed-off-by: Akshu Agrawal Signed-off-by: Mark Brown --- sound/soc/amd/acp-da7219-max98357a.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sound/soc/amd/acp-da7219-max98357a.c b/sound/soc/amd/acp-da7219-max98357a.c index 717a017f0db6..3f813ea5210a 100644 --- a/sound/soc/amd/acp-da7219-max98357a.c +++ b/sound/soc/amd/acp-da7219-max98357a.c @@ -75,7 +75,7 @@ static int cz_da7219_init(struct snd_soc_pcm_runtime *rtd) da7219_dai_clk = clk_get(component->dev, "da7219-dai-clks"); ret = snd_soc_card_jack_new(card, "Headset Jack", - SND_JACK_HEADPHONE | SND_JACK_MICROPHONE | + SND_JACK_HEADSET | SND_JACK_LINEOUT | SND_JACK_BTN_0 | SND_JACK_BTN_1 | SND_JACK_BTN_2 | SND_JACK_BTN_3, &cz_jack, NULL, 0); From bca0ac1d96739c07ee1a158e4b1202260ad7480e Mon Sep 17 00:00:00 2001 From: Mac Chiang Date: Tue, 9 Oct 2018 15:35:47 +0800 Subject: [PATCH 267/299] ASoC: Intel: Boards: Add KBL Dialog Maxim I2S machine driver This patch adds Kabylake I2S machine driver with: DA7219 audio codec(SSP1) and MAXIM98927(SSP0) speaker amplifier. Signed-off-by: Mac Chiang Signed-off-by: Mark Brown --- sound/soc/intel/boards/Kconfig | 13 + sound/soc/intel/boards/Makefile | 2 + sound/soc/intel/boards/kbl_da7219_max98927.c | 983 +++++++++++++++++++ 3 files changed, 998 insertions(+) create mode 100644 sound/soc/intel/boards/kbl_da7219_max98927.c diff --git a/sound/soc/intel/boards/Kconfig b/sound/soc/intel/boards/Kconfig index 88e4b4284738..73ca1350aa31 100644 --- a/sound/soc/intel/boards/Kconfig +++ b/sound/soc/intel/boards/Kconfig @@ -280,6 +280,19 @@ config SND_SOC_INTEL_KBL_DA7219_MAX98357A_MACH create an alsa sound card for DA7219 + MAX98357A I2S audio codec. Say Y if you have such a device. +config SND_SOC_INTEL_KBL_DA7219_MAX98927_MACH + tristate "KBL with DA7219 and MAX98927 in I2S Mode" + depends on MFD_INTEL_LPSS && I2C && ACPI + select SND_SOC_DA7219 + select SND_SOC_MAX98927 + select SND_SOC_DMIC + select SND_SOC_HDAC_HDMI + help + This adds support for ASoC Onboard Codec I2S machine driver. This will + create an alsa sound card for DA7219 + MAX98927 I2S audio codec. + Say Y if you have such a device. + If unsure select "N". + config SND_SOC_INTEL_SKL_HDA_DSP_GENERIC_MACH tristate "SKL/KBL/BXT/APL with HDA Codecs" select SND_SOC_HDAC_HDMI diff --git a/sound/soc/intel/boards/Makefile b/sound/soc/intel/boards/Makefile index 6e88373cbe35..5381e27df9cc 100644 --- a/sound/soc/intel/boards/Makefile +++ b/sound/soc/intel/boards/Makefile @@ -17,6 +17,7 @@ snd-soc-sst-byt-cht-da7213-objs := bytcht_da7213.o snd-soc-sst-byt-cht-es8316-objs := bytcht_es8316.o snd-soc-sst-byt-cht-nocodec-objs := bytcht_nocodec.o snd-soc-kbl_da7219_max98357a-objs := kbl_da7219_max98357a.o +snd-soc-kbl_da7219_max98927-objs := kbl_da7219_max98927.o snd-soc-kbl_rt5663_max98927-objs := kbl_rt5663_max98927.o snd-soc-kbl_rt5663_rt5514_max98927-objs := kbl_rt5663_rt5514_max98927.o snd-soc-skl_rt286-objs := skl_rt286.o @@ -42,6 +43,7 @@ obj-$(CONFIG_SND_SOC_INTEL_BYT_CHT_DA7213_MACH) += snd-soc-sst-byt-cht-da7213.o obj-$(CONFIG_SND_SOC_INTEL_BYT_CHT_ES8316_MACH) += snd-soc-sst-byt-cht-es8316.o obj-$(CONFIG_SND_SOC_INTEL_BYT_CHT_NOCODEC_MACH) += snd-soc-sst-byt-cht-nocodec.o obj-$(CONFIG_SND_SOC_INTEL_KBL_DA7219_MAX98357A_MACH) += snd-soc-kbl_da7219_max98357a.o +obj-$(CONFIG_SND_SOC_INTEL_KBL_DA7219_MAX98927_MACH) += snd-soc-kbl_da7219_max98927.o obj-$(CONFIG_SND_SOC_INTEL_KBL_RT5663_MAX98927_MACH) += snd-soc-kbl_rt5663_max98927.o obj-$(CONFIG_SND_SOC_INTEL_KBL_RT5663_RT5514_MAX98927_MACH) += snd-soc-kbl_rt5663_rt5514_max98927.o obj-$(CONFIG_SND_SOC_INTEL_SKL_RT286_MACH) += snd-soc-skl_rt286.o diff --git a/sound/soc/intel/boards/kbl_da7219_max98927.c b/sound/soc/intel/boards/kbl_da7219_max98927.c new file mode 100644 index 000000000000..3ab96ee7bd3c --- /dev/null +++ b/sound/soc/intel/boards/kbl_da7219_max98927.c @@ -0,0 +1,983 @@ +// SPDX-License-Identifier: GPL-2.0 +// Copyright(c) 2018 Intel Corporation. + +/* + * Intel Kabylake I2S Machine Driver with MAX98927 & DA7219 Codecs + * + * Modified from: + * Intel Kabylake I2S Machine driver supporting MAX98927 and + * RT5663 codecs + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include "../../codecs/da7219.h" +#include "../../codecs/hdac_hdmi.h" +#include "../skylake/skl.h" +#include "../../codecs/da7219-aad.h" + +#define KBL_DIALOG_CODEC_DAI "da7219-hifi" +#define MAX98927_CODEC_DAI "max98927-aif1" +#define MAXIM_DEV0_NAME "i2c-MX98927:00" +#define MAXIM_DEV1_NAME "i2c-MX98927:01" +#define DUAL_CHANNEL 2 +#define QUAD_CHANNEL 4 +#define NAME_SIZE 32 + +static struct snd_soc_card *kabylake_audio_card; +static struct snd_soc_jack kabylake_hdmi[3]; + +struct kbl_hdmi_pcm { + struct list_head head; + struct snd_soc_dai *codec_dai; + int device; +}; + +struct kbl_codec_private { + struct snd_soc_jack kabylake_headset; + struct list_head hdmi_pcm_list; +}; + +enum { + KBL_DPCM_AUDIO_PB = 0, + KBL_DPCM_AUDIO_CP, + KBL_DPCM_AUDIO_ECHO_REF_CP, + KBL_DPCM_AUDIO_REF_CP, + KBL_DPCM_AUDIO_DMIC_CP, + KBL_DPCM_AUDIO_HDMI1_PB, + KBL_DPCM_AUDIO_HDMI2_PB, + KBL_DPCM_AUDIO_HDMI3_PB, + KBL_DPCM_AUDIO_HS_PB, +}; + +static int platform_clock_control(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *k, int event) +{ + struct snd_soc_dapm_context *dapm = w->dapm; + struct snd_soc_card *card = dapm->card; + struct snd_soc_dai *codec_dai; + int ret = 0; + + codec_dai = snd_soc_card_get_codec_dai(card, KBL_DIALOG_CODEC_DAI); + if (!codec_dai) { + dev_err(card->dev, "Codec dai not found; Unable to set/unset codec pll\n"); + return -EIO; + } + + /* Configure sysclk for codec */ + ret = snd_soc_dai_set_sysclk(codec_dai, DA7219_CLKSRC_MCLK, 24576000, + SND_SOC_CLOCK_IN); + if (ret) { + dev_err(card->dev, "can't set codec sysclk configuration\n"); + return ret; + } + + if (SND_SOC_DAPM_EVENT_OFF(event)) { + ret = snd_soc_dai_set_pll(codec_dai, 0, + DA7219_SYSCLK_MCLK, 0, 0); + if (ret) + dev_err(card->dev, "failed to stop PLL: %d\n", ret); + } else if (SND_SOC_DAPM_EVENT_ON(event)) { + ret = snd_soc_dai_set_pll(codec_dai, 0, DA7219_SYSCLK_PLL_SRM, + 0, DA7219_PLL_FREQ_OUT_98304); + if (ret) + dev_err(card->dev, "failed to start PLL: %d\n", ret); + } + + return ret; +} + +static const struct snd_kcontrol_new kabylake_controls[] = { + SOC_DAPM_PIN_SWITCH("Headphone Jack"), + SOC_DAPM_PIN_SWITCH("Headset Mic"), + SOC_DAPM_PIN_SWITCH("Left Spk"), + SOC_DAPM_PIN_SWITCH("Right Spk"), +}; + +static const struct snd_soc_dapm_widget kabylake_widgets[] = { + SND_SOC_DAPM_HP("Headphone Jack", NULL), + SND_SOC_DAPM_MIC("Headset Mic", NULL), + SND_SOC_DAPM_SPK("Left Spk", NULL), + SND_SOC_DAPM_SPK("Right Spk", NULL), + SND_SOC_DAPM_MIC("SoC DMIC", NULL), + SND_SOC_DAPM_SPK("DP", NULL), + SND_SOC_DAPM_SPK("HDMI", NULL), + SND_SOC_DAPM_SUPPLY("Platform Clock", SND_SOC_NOPM, 0, 0, + platform_clock_control, SND_SOC_DAPM_PRE_PMU | + SND_SOC_DAPM_POST_PMD), +}; + +static const struct snd_soc_dapm_route kabylake_map[] = { + /* speaker */ + { "Left Spk", NULL, "Left BE_OUT" }, + { "Right Spk", NULL, "Right BE_OUT" }, + + /* other jacks */ + { "DMic", NULL, "SoC DMIC" }, + + { "HDMI", NULL, "hif5 Output" }, + { "DP", NULL, "hif6 Output" }, + + /* CODEC BE connections */ + { "Left HiFi Playback", NULL, "ssp0 Tx" }, + { "Right HiFi Playback", NULL, "ssp0 Tx" }, + { "ssp0 Tx", NULL, "spk_out" }, + + /* IV feedback path */ + { "codec0_fb_in", NULL, "ssp0 Rx"}, + { "ssp0 Rx", NULL, "Left HiFi Capture" }, + { "ssp0 Rx", NULL, "Right HiFi Capture" }, + + /* AEC capture path */ + { "echo_ref_out", NULL, "ssp0 Rx" }, + + /* DMIC */ + { "dmic01_hifi", NULL, "DMIC01 Rx" }, + { "DMIC01 Rx", NULL, "DMIC AIF" }, + + { "hifi1", NULL, "iDisp1 Tx" }, + { "iDisp1 Tx", NULL, "iDisp1_out" }, + { "hifi2", NULL, "iDisp2 Tx" }, + { "iDisp2 Tx", NULL, "iDisp2_out" }, + { "hifi3", NULL, "iDisp3 Tx"}, + { "iDisp3 Tx", NULL, "iDisp3_out"}, +}; + +static const struct snd_soc_dapm_route kabylake_ssp1_map[] = { + { "Headphone Jack", NULL, "HPL" }, + { "Headphone Jack", NULL, "HPR" }, + + /* other jacks */ + { "MIC", NULL, "Headset Mic" }, + + /* CODEC BE connections */ + { "Playback", NULL, "ssp1 Tx" }, + { "ssp1 Tx", NULL, "codec1_out" }, + + { "hs_in", NULL, "ssp1 Rx" }, + { "ssp1 Rx", NULL, "Capture" }, + + { "Headphone Jack", NULL, "Platform Clock" }, + { "Headset Mic", NULL, "Platform Clock" }, +}; + +static int kabylake_ssp0_hw_params(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params) +{ + struct snd_soc_pcm_runtime *runtime = substream->private_data; + int ret = 0, j; + + for (j = 0; j < runtime->num_codecs; j++) { + struct snd_soc_dai *codec_dai = runtime->codec_dais[j]; + + if (!strcmp(codec_dai->component->name, MAXIM_DEV0_NAME)) { + ret = snd_soc_dai_set_tdm_slot(codec_dai, 0x30, 3, 8, 16); + if (ret < 0) { + dev_err(runtime->dev, "DEV0 TDM slot err:%d\n", ret); + return ret; + } + } + if (!strcmp(codec_dai->component->name, MAXIM_DEV1_NAME)) { + ret = snd_soc_dai_set_tdm_slot(codec_dai, 0xC0, 3, 8, 16); + if (ret < 0) { + dev_err(runtime->dev, "DEV1 TDM slot err:%d\n", ret); + return ret; + } + } + } + + return 0; +} + +static struct snd_soc_ops kabylake_ssp0_ops = { + .hw_params = kabylake_ssp0_hw_params, +}; + +static int kabylake_ssp_fixup(struct snd_soc_pcm_runtime *rtd, + struct snd_pcm_hw_params *params) +{ + struct snd_interval *rate = hw_param_interval(params, + SNDRV_PCM_HW_PARAM_RATE); + struct snd_interval *channels = hw_param_interval(params, + SNDRV_PCM_HW_PARAM_CHANNELS); + struct snd_mask *fmt = hw_param_mask(params, SNDRV_PCM_HW_PARAM_FORMAT); + struct snd_soc_dpcm *dpcm = container_of( + params, struct snd_soc_dpcm, hw_params); + struct snd_soc_dai_link *fe_dai_link = dpcm->fe->dai_link; + struct snd_soc_dai_link *be_dai_link = dpcm->be->dai_link; + + /* + * The ADSP will convert the FE rate to 48k, stereo, 24 bit + */ + if (!strcmp(fe_dai_link->name, "Kbl Audio Port") || + !strcmp(fe_dai_link->name, "Kbl Audio Headset Playback") || + !strcmp(fe_dai_link->name, "Kbl Audio Capture Port")) { + rate->min = rate->max = 48000; + channels->min = channels->max = 2; + snd_mask_none(fmt); + snd_mask_set(fmt, SNDRV_PCM_FORMAT_S24_LE); + } + + /* + * The speaker on the SSP0 supports S16_LE and not S24_LE. + * thus changing the mask here + */ + if (!strcmp(be_dai_link->name, "SSP0-Codec")) + snd_mask_set(fmt, SNDRV_PCM_FORMAT_S16_LE); + + return 0; +} + +static int kabylake_da7219_codec_init(struct snd_soc_pcm_runtime *rtd) +{ + struct kbl_codec_private *ctx = snd_soc_card_get_drvdata(rtd->card); + struct snd_soc_component *component = rtd->codec_dai->component; + struct snd_soc_jack *jack; + struct snd_soc_card *card = rtd->card; + int ret; + + + ret = snd_soc_dapm_add_routes(&card->dapm, + kabylake_ssp1_map, + ARRAY_SIZE(kabylake_ssp1_map)); + + /* + * Headset buttons map to the google Reference headset. + * These can be configured by userspace. + */ + ret = snd_soc_card_jack_new(kabylake_audio_card, "Headset Jack", + SND_JACK_HEADSET | SND_JACK_BTN_0 | SND_JACK_BTN_1 | + SND_JACK_BTN_2 | SND_JACK_BTN_3 | SND_JACK_LINEOUT, + &ctx->kabylake_headset, NULL, 0); + if (ret) { + dev_err(rtd->dev, "Headset Jack creation failed: %d\n", ret); + return ret; + } + + jack = &ctx->kabylake_headset; + snd_jack_set_key(jack->jack, SND_JACK_BTN_0, KEY_PLAYPAUSE); + snd_jack_set_key(jack->jack, SND_JACK_BTN_1, KEY_VOICECOMMAND); + snd_jack_set_key(jack->jack, SND_JACK_BTN_2, KEY_VOLUMEUP); + snd_jack_set_key(jack->jack, SND_JACK_BTN_3, KEY_VOLUMEDOWN); + + da7219_aad_jack_det(component, &ctx->kabylake_headset); + + ret = snd_soc_dapm_ignore_suspend(&rtd->card->dapm, "SoC DMIC"); + if (ret) + dev_err(rtd->dev, "SoC DMIC - Ignore suspend failed %d\n", ret); + + return ret; +} + +static int kabylake_hdmi_init(struct snd_soc_pcm_runtime *rtd, int device) +{ + struct kbl_codec_private *ctx = snd_soc_card_get_drvdata(rtd->card); + struct snd_soc_dai *dai = rtd->codec_dai; + struct kbl_hdmi_pcm *pcm; + + pcm = devm_kzalloc(rtd->card->dev, sizeof(*pcm), GFP_KERNEL); + if (!pcm) + return -ENOMEM; + + pcm->device = device; + pcm->codec_dai = dai; + + list_add_tail(&pcm->head, &ctx->hdmi_pcm_list); + + return 0; +} + +static int kabylake_hdmi1_init(struct snd_soc_pcm_runtime *rtd) +{ + return kabylake_hdmi_init(rtd, KBL_DPCM_AUDIO_HDMI1_PB); +} + +static int kabylake_hdmi2_init(struct snd_soc_pcm_runtime *rtd) +{ + return kabylake_hdmi_init(rtd, KBL_DPCM_AUDIO_HDMI2_PB); +} + +static int kabylake_hdmi3_init(struct snd_soc_pcm_runtime *rtd) +{ + return kabylake_hdmi_init(rtd, KBL_DPCM_AUDIO_HDMI3_PB); +} + +static int kabylake_da7219_fe_init(struct snd_soc_pcm_runtime *rtd) +{ + struct snd_soc_dapm_context *dapm; + struct snd_soc_component *component = rtd->cpu_dai->component; + + dapm = snd_soc_component_get_dapm(component); + snd_soc_dapm_ignore_suspend(dapm, "Reference Capture"); + + return 0; +} + +static const unsigned int rates[] = { + 48000, +}; + +static const struct snd_pcm_hw_constraint_list constraints_rates = { + .count = ARRAY_SIZE(rates), + .list = rates, + .mask = 0, +}; + +static const unsigned int channels[] = { + DUAL_CHANNEL, +}; + +static const struct snd_pcm_hw_constraint_list constraints_channels = { + .count = ARRAY_SIZE(channels), + .list = channels, + .mask = 0, +}; + +static unsigned int channels_quad[] = { + QUAD_CHANNEL, +}; + +static struct snd_pcm_hw_constraint_list constraints_channels_quad = { + .count = ARRAY_SIZE(channels_quad), + .list = channels_quad, + .mask = 0, +}; + +static int kbl_fe_startup(struct snd_pcm_substream *substream) +{ + struct snd_pcm_runtime *runtime = substream->runtime; + + /* + * On this platform for PCM device we support, + * 48Khz + * stereo + * 16 bit audio + */ + + runtime->hw.channels_max = DUAL_CHANNEL; + snd_pcm_hw_constraint_list(runtime, 0, SNDRV_PCM_HW_PARAM_CHANNELS, + &constraints_channels); + + runtime->hw.formats = SNDRV_PCM_FMTBIT_S16_LE; + snd_pcm_hw_constraint_msbits(runtime, 0, 16, 16); + + snd_pcm_hw_constraint_list(runtime, 0, + SNDRV_PCM_HW_PARAM_RATE, &constraints_rates); + + return 0; +} + +static const struct snd_soc_ops kabylake_da7219_fe_ops = { + .startup = kbl_fe_startup, +}; + +static int kabylake_dmic_fixup(struct snd_soc_pcm_runtime *rtd, + struct snd_pcm_hw_params *params) +{ + struct snd_interval *channels = hw_param_interval(params, + SNDRV_PCM_HW_PARAM_CHANNELS); + + /* + * set BE channel constraint as user FE channels + */ + + if (params_channels(params) == 2) + channels->min = channels->max = 2; + else + channels->min = channels->max = 4; + + return 0; +} + +static int kabylake_dmic_startup(struct snd_pcm_substream *substream) +{ + struct snd_pcm_runtime *runtime = substream->runtime; + + runtime->hw.channels_min = runtime->hw.channels_max = QUAD_CHANNEL; + snd_pcm_hw_constraint_list(runtime, 0, SNDRV_PCM_HW_PARAM_CHANNELS, + &constraints_channels_quad); + + return snd_pcm_hw_constraint_list(substream->runtime, 0, + SNDRV_PCM_HW_PARAM_RATE, &constraints_rates); +} + +static struct snd_soc_ops kabylake_dmic_ops = { + .startup = kabylake_dmic_startup, +}; + +static const unsigned int rates_16000[] = { + 16000, +}; + +static const struct snd_pcm_hw_constraint_list constraints_16000 = { + .count = ARRAY_SIZE(rates_16000), + .list = rates_16000, +}; + +static const unsigned int ch_mono[] = { + 1, +}; +static const struct snd_pcm_hw_constraint_list constraints_refcap = { + .count = ARRAY_SIZE(ch_mono), + .list = ch_mono, +}; + +static int kabylake_refcap_startup(struct snd_pcm_substream *substream) +{ + substream->runtime->hw.channels_max = 1; + snd_pcm_hw_constraint_list(substream->runtime, 0, + SNDRV_PCM_HW_PARAM_CHANNELS, + &constraints_refcap); + + return snd_pcm_hw_constraint_list(substream->runtime, 0, + SNDRV_PCM_HW_PARAM_RATE, + &constraints_16000); +} + + +static struct snd_soc_ops skylaye_refcap_ops = { + .startup = kabylake_refcap_startup, +}; + +static struct snd_soc_codec_conf max98927_codec_conf[] = { + + { + .dev_name = MAXIM_DEV0_NAME, + .name_prefix = "Right", + }, + + { + .dev_name = MAXIM_DEV1_NAME, + .name_prefix = "Left", + }, +}; + +static struct snd_soc_dai_link_component ssp0_codec_components[] = { + { /* Left */ + .name = MAXIM_DEV0_NAME, + .dai_name = MAX98927_CODEC_DAI, + }, + + { /* For Right */ + .name = MAXIM_DEV1_NAME, + .dai_name = MAX98927_CODEC_DAI, + }, + +}; + +/* kabylake digital audio interface glue - connects codec <--> CPU */ +static struct snd_soc_dai_link kabylake_dais[] = { + /* Front End DAI links */ + [KBL_DPCM_AUDIO_PB] = { + .name = "Kbl Audio Port", + .stream_name = "Audio", + .cpu_dai_name = "System Pin", + .platform_name = "0000:00:1f.3", + .dynamic = 1, + .codec_name = "snd-soc-dummy", + .codec_dai_name = "snd-soc-dummy-dai", + .nonatomic = 1, + .init = kabylake_da7219_fe_init, + .trigger = { + SND_SOC_DPCM_TRIGGER_POST, SND_SOC_DPCM_TRIGGER_POST}, + .dpcm_playback = 1, + .ops = &kabylake_da7219_fe_ops, + }, + [KBL_DPCM_AUDIO_CP] = { + .name = "Kbl Audio Capture Port", + .stream_name = "Audio Record", + .cpu_dai_name = "System Pin", + .platform_name = "0000:00:1f.3", + .dynamic = 1, + .codec_name = "snd-soc-dummy", + .codec_dai_name = "snd-soc-dummy-dai", + .nonatomic = 1, + .trigger = { + SND_SOC_DPCM_TRIGGER_POST, SND_SOC_DPCM_TRIGGER_POST}, + .dpcm_capture = 1, + .ops = &kabylake_da7219_fe_ops, + }, + [KBL_DPCM_AUDIO_ECHO_REF_CP] = { + .name = "Kbl Audio Echo Reference cap", + .stream_name = "Echoreference Capture", + .cpu_dai_name = "Echoref Pin", + .codec_name = "snd-soc-dummy", + .codec_dai_name = "snd-soc-dummy-dai", + .platform_name = "0000:00:1f.3", + .init = NULL, + .capture_only = 1, + .nonatomic = 1, + }, + [KBL_DPCM_AUDIO_REF_CP] = { + .name = "Kbl Audio Reference cap", + .stream_name = "Wake on Voice", + .cpu_dai_name = "Reference Pin", + .codec_name = "snd-soc-dummy", + .codec_dai_name = "snd-soc-dummy-dai", + .platform_name = "0000:00:1f.3", + .init = NULL, + .dpcm_capture = 1, + .nonatomic = 1, + .dynamic = 1, + .ops = &skylaye_refcap_ops, + }, + [KBL_DPCM_AUDIO_DMIC_CP] = { + .name = "Kbl Audio DMIC cap", + .stream_name = "dmiccap", + .cpu_dai_name = "DMIC Pin", + .codec_name = "snd-soc-dummy", + .codec_dai_name = "snd-soc-dummy-dai", + .platform_name = "0000:00:1f.3", + .init = NULL, + .dpcm_capture = 1, + .nonatomic = 1, + .dynamic = 1, + .ops = &kabylake_dmic_ops, + }, + [KBL_DPCM_AUDIO_HDMI1_PB] = { + .name = "Kbl HDMI Port1", + .stream_name = "Hdmi1", + .cpu_dai_name = "HDMI1 Pin", + .codec_name = "snd-soc-dummy", + .codec_dai_name = "snd-soc-dummy-dai", + .platform_name = "0000:00:1f.3", + .dpcm_playback = 1, + .init = NULL, + .trigger = { + SND_SOC_DPCM_TRIGGER_POST, SND_SOC_DPCM_TRIGGER_POST}, + .nonatomic = 1, + .dynamic = 1, + }, + [KBL_DPCM_AUDIO_HDMI2_PB] = { + .name = "Kbl HDMI Port2", + .stream_name = "Hdmi2", + .cpu_dai_name = "HDMI2 Pin", + .codec_name = "snd-soc-dummy", + .codec_dai_name = "snd-soc-dummy-dai", + .platform_name = "0000:00:1f.3", + .dpcm_playback = 1, + .init = NULL, + .trigger = { + SND_SOC_DPCM_TRIGGER_POST, SND_SOC_DPCM_TRIGGER_POST}, + .nonatomic = 1, + .dynamic = 1, + }, + [KBL_DPCM_AUDIO_HDMI3_PB] = { + .name = "Kbl HDMI Port3", + .stream_name = "Hdmi3", + .cpu_dai_name = "HDMI3 Pin", + .codec_name = "snd-soc-dummy", + .codec_dai_name = "snd-soc-dummy-dai", + .platform_name = "0000:00:1f.3", + .trigger = { + SND_SOC_DPCM_TRIGGER_POST, SND_SOC_DPCM_TRIGGER_POST}, + .dpcm_playback = 1, + .init = NULL, + .nonatomic = 1, + .dynamic = 1, + }, + [KBL_DPCM_AUDIO_HS_PB] = { + .name = "Kbl Audio Headset Playback", + .stream_name = "Headset Audio", + .cpu_dai_name = "System Pin2", + .codec_name = "snd-soc-dummy", + .codec_dai_name = "snd-soc-dummy-dai", + .platform_name = "0000:00:1f.3", + .dpcm_playback = 1, + .nonatomic = 1, + .dynamic = 1, + .init = kabylake_da7219_fe_init, + .trigger = { + SND_SOC_DPCM_TRIGGER_POST, SND_SOC_DPCM_TRIGGER_POST}, + .ops = &kabylake_da7219_fe_ops, + + }, + + /* Back End DAI links */ + { + /* SSP0 - Codec */ + .name = "SSP0-Codec", + .id = 0, + .cpu_dai_name = "SSP0 Pin", + .platform_name = "0000:00:1f.3", + .no_pcm = 1, + .codecs = ssp0_codec_components, + .num_codecs = ARRAY_SIZE(ssp0_codec_components), + .dai_fmt = SND_SOC_DAIFMT_DSP_B | + SND_SOC_DAIFMT_NB_NF | + SND_SOC_DAIFMT_CBS_CFS, + .dpcm_playback = 1, + .dpcm_capture = 1, + .ignore_pmdown_time = 1, + .be_hw_params_fixup = kabylake_ssp_fixup, + .ops = &kabylake_ssp0_ops, + }, + { + /* SSP1 - Codec */ + .name = "SSP1-Codec", + .id = 1, + .cpu_dai_name = "SSP1 Pin", + .platform_name = "0000:00:1f.3", + .no_pcm = 1, + .codec_name = "i2c-DLGS7219:00", + .codec_dai_name = KBL_DIALOG_CODEC_DAI, + .init = kabylake_da7219_codec_init, + .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF | + SND_SOC_DAIFMT_CBS_CFS, + .ignore_pmdown_time = 1, + .be_hw_params_fixup = kabylake_ssp_fixup, + .dpcm_playback = 1, + .dpcm_capture = 1, + }, + { + .name = "dmic01", + .id = 2, + .cpu_dai_name = "DMIC01 Pin", + .codec_name = "dmic-codec", + .codec_dai_name = "dmic-hifi", + .platform_name = "0000:00:1f.3", + .be_hw_params_fixup = kabylake_dmic_fixup, + .ignore_suspend = 1, + .dpcm_capture = 1, + .no_pcm = 1, + }, + { + .name = "iDisp1", + .id = 3, + .cpu_dai_name = "iDisp1 Pin", + .codec_name = "ehdaudio0D2", + .codec_dai_name = "intel-hdmi-hifi1", + .platform_name = "0000:00:1f.3", + .dpcm_playback = 1, + .init = kabylake_hdmi1_init, + .no_pcm = 1, + }, + { + .name = "iDisp2", + .id = 4, + .cpu_dai_name = "iDisp2 Pin", + .codec_name = "ehdaudio0D2", + .codec_dai_name = "intel-hdmi-hifi2", + .platform_name = "0000:00:1f.3", + .init = kabylake_hdmi2_init, + .dpcm_playback = 1, + .no_pcm = 1, + }, + { + .name = "iDisp3", + .id = 5, + .cpu_dai_name = "iDisp3 Pin", + .codec_name = "ehdaudio0D2", + .codec_dai_name = "intel-hdmi-hifi3", + .platform_name = "0000:00:1f.3", + .init = kabylake_hdmi3_init, + .dpcm_playback = 1, + .no_pcm = 1, + }, +}; + +/* kabylake digital audio interface glue - connects codec <--> CPU */ +static struct snd_soc_dai_link kabylake_max98927_dais[] = { + /* Front End DAI links */ + [KBL_DPCM_AUDIO_PB] = { + .name = "Kbl Audio Port", + .stream_name = "Audio", + .cpu_dai_name = "System Pin", + .platform_name = "0000:00:1f.3", + .dynamic = 1, + .codec_name = "snd-soc-dummy", + .codec_dai_name = "snd-soc-dummy-dai", + .nonatomic = 1, + .init = kabylake_da7219_fe_init, + .trigger = { + SND_SOC_DPCM_TRIGGER_POST, SND_SOC_DPCM_TRIGGER_POST}, + .dpcm_playback = 1, + .ops = &kabylake_da7219_fe_ops, + }, + [KBL_DPCM_AUDIO_CP] = { + .name = "Kbl Audio Capture Port", + .stream_name = "Audio Record", + .cpu_dai_name = "System Pin", + .platform_name = "0000:00:1f.3", + .dynamic = 1, + .codec_name = "snd-soc-dummy", + .codec_dai_name = "snd-soc-dummy-dai", + .nonatomic = 1, + .trigger = { + SND_SOC_DPCM_TRIGGER_POST, SND_SOC_DPCM_TRIGGER_POST}, + .dpcm_capture = 1, + .ops = &kabylake_da7219_fe_ops, + }, + [KBL_DPCM_AUDIO_ECHO_REF_CP] = { + .name = "Kbl Audio Echo Reference cap", + .stream_name = "Echoreference Capture", + .cpu_dai_name = "Echoref Pin", + .codec_name = "snd-soc-dummy", + .codec_dai_name = "snd-soc-dummy-dai", + .platform_name = "0000:00:1f.3", + .init = NULL, + .capture_only = 1, + .nonatomic = 1, + }, + [KBL_DPCM_AUDIO_REF_CP] = { + .name = "Kbl Audio Reference cap", + .stream_name = "Wake on Voice", + .cpu_dai_name = "Reference Pin", + .codec_name = "snd-soc-dummy", + .codec_dai_name = "snd-soc-dummy-dai", + .platform_name = "0000:00:1f.3", + .init = NULL, + .dpcm_capture = 1, + .nonatomic = 1, + .dynamic = 1, + .ops = &skylaye_refcap_ops, + }, + [KBL_DPCM_AUDIO_DMIC_CP] = { + .name = "Kbl Audio DMIC cap", + .stream_name = "dmiccap", + .cpu_dai_name = "DMIC Pin", + .codec_name = "snd-soc-dummy", + .codec_dai_name = "snd-soc-dummy-dai", + .platform_name = "0000:00:1f.3", + .init = NULL, + .dpcm_capture = 1, + .nonatomic = 1, + .dynamic = 1, + .ops = &kabylake_dmic_ops, + }, + [KBL_DPCM_AUDIO_HDMI1_PB] = { + .name = "Kbl HDMI Port1", + .stream_name = "Hdmi1", + .cpu_dai_name = "HDMI1 Pin", + .codec_name = "snd-soc-dummy", + .codec_dai_name = "snd-soc-dummy-dai", + .platform_name = "0000:00:1f.3", + .dpcm_playback = 1, + .init = NULL, + .trigger = { + SND_SOC_DPCM_TRIGGER_POST, SND_SOC_DPCM_TRIGGER_POST}, + .nonatomic = 1, + .dynamic = 1, + }, + [KBL_DPCM_AUDIO_HDMI2_PB] = { + .name = "Kbl HDMI Port2", + .stream_name = "Hdmi2", + .cpu_dai_name = "HDMI2 Pin", + .codec_name = "snd-soc-dummy", + .codec_dai_name = "snd-soc-dummy-dai", + .platform_name = "0000:00:1f.3", + .dpcm_playback = 1, + .init = NULL, + .trigger = { + SND_SOC_DPCM_TRIGGER_POST, SND_SOC_DPCM_TRIGGER_POST}, + .nonatomic = 1, + .dynamic = 1, + }, + [KBL_DPCM_AUDIO_HDMI3_PB] = { + .name = "Kbl HDMI Port3", + .stream_name = "Hdmi3", + .cpu_dai_name = "HDMI3 Pin", + .codec_name = "snd-soc-dummy", + .codec_dai_name = "snd-soc-dummy-dai", + .platform_name = "0000:00:1f.3", + .trigger = { + SND_SOC_DPCM_TRIGGER_POST, SND_SOC_DPCM_TRIGGER_POST}, + .dpcm_playback = 1, + .init = NULL, + .nonatomic = 1, + .dynamic = 1, + }, + + /* Back End DAI links */ + { + /* SSP0 - Codec */ + .name = "SSP0-Codec", + .id = 0, + .cpu_dai_name = "SSP0 Pin", + .platform_name = "0000:00:1f.3", + .no_pcm = 1, + .codecs = ssp0_codec_components, + .num_codecs = ARRAY_SIZE(ssp0_codec_components), + .dai_fmt = SND_SOC_DAIFMT_DSP_B | + SND_SOC_DAIFMT_NB_NF | + SND_SOC_DAIFMT_CBS_CFS, + .dpcm_playback = 1, + .dpcm_capture = 1, + .ignore_pmdown_time = 1, + .be_hw_params_fixup = kabylake_ssp_fixup, + .ops = &kabylake_ssp0_ops, + }, + { + .name = "dmic01", + .id = 1, + .cpu_dai_name = "DMIC01 Pin", + .codec_name = "dmic-codec", + .codec_dai_name = "dmic-hifi", + .platform_name = "0000:00:1f.3", + .be_hw_params_fixup = kabylake_dmic_fixup, + .ignore_suspend = 1, + .dpcm_capture = 1, + .no_pcm = 1, + }, + { + .name = "iDisp1", + .id = 2, + .cpu_dai_name = "iDisp1 Pin", + .codec_name = "ehdaudio0D2", + .codec_dai_name = "intel-hdmi-hifi1", + .platform_name = "0000:00:1f.3", + .dpcm_playback = 1, + .init = kabylake_hdmi1_init, + .no_pcm = 1, + }, + { + .name = "iDisp2", + .id = 3, + .cpu_dai_name = "iDisp2 Pin", + .codec_name = "ehdaudio0D2", + .codec_dai_name = "intel-hdmi-hifi2", + .platform_name = "0000:00:1f.3", + .init = kabylake_hdmi2_init, + .dpcm_playback = 1, + .no_pcm = 1, + }, + { + .name = "iDisp3", + .id = 4, + .cpu_dai_name = "iDisp3 Pin", + .codec_name = "ehdaudio0D2", + .codec_dai_name = "intel-hdmi-hifi3", + .platform_name = "0000:00:1f.3", + .init = kabylake_hdmi3_init, + .dpcm_playback = 1, + .no_pcm = 1, + }, +}; + +static int kabylake_card_late_probe(struct snd_soc_card *card) +{ + struct kbl_codec_private *ctx = snd_soc_card_get_drvdata(card); + struct kbl_hdmi_pcm *pcm; + struct snd_soc_component *component = NULL; + int err, i = 0; + char jack_name[NAME_SIZE]; + + list_for_each_entry(pcm, &ctx->hdmi_pcm_list, head) { + component = pcm->codec_dai->component; + snprintf(jack_name, sizeof(jack_name), + "HDMI/DP, pcm=%d Jack", pcm->device); + err = snd_soc_card_jack_new(card, jack_name, + SND_JACK_AVOUT, &kabylake_hdmi[i], + NULL, 0); + + if (err) + return err; + + err = hdac_hdmi_jack_init(pcm->codec_dai, pcm->device, + &kabylake_hdmi[i]); + if (err < 0) + return err; + + i++; + } + + if (!component) + return -EINVAL; + + return hdac_hdmi_jack_port_init(component, &card->dapm); + + return 0; +} + +/* kabylake audio machine driver for SPT + DA7219 */ +static struct snd_soc_card kbl_audio_card_da7219_m98927 = { + .name = "kblda7219m98927", + .owner = THIS_MODULE, + .dai_link = kabylake_dais, + .num_links = ARRAY_SIZE(kabylake_dais), + .controls = kabylake_controls, + .num_controls = ARRAY_SIZE(kabylake_controls), + .dapm_widgets = kabylake_widgets, + .num_dapm_widgets = ARRAY_SIZE(kabylake_widgets), + .dapm_routes = kabylake_map, + .num_dapm_routes = ARRAY_SIZE(kabylake_map), + .codec_conf = max98927_codec_conf, + .num_configs = ARRAY_SIZE(max98927_codec_conf), + .fully_routed = true, + .late_probe = kabylake_card_late_probe, +}; + +/* kabylake audio machine driver for Maxim98927 */ +static struct snd_soc_card kbl_audio_card_max98927 = { + .name = "kblmax98927", + .owner = THIS_MODULE, + .dai_link = kabylake_max98927_dais, + .num_links = ARRAY_SIZE(kabylake_max98927_dais), + .controls = kabylake_controls, + .num_controls = ARRAY_SIZE(kabylake_controls), + .dapm_widgets = kabylake_widgets, + .num_dapm_widgets = ARRAY_SIZE(kabylake_widgets), + .dapm_routes = kabylake_map, + .num_dapm_routes = ARRAY_SIZE(kabylake_map), + .codec_conf = max98927_codec_conf, + .num_configs = ARRAY_SIZE(max98927_codec_conf), + .fully_routed = true, + .late_probe = kabylake_card_late_probe, +}; + +static int kabylake_audio_probe(struct platform_device *pdev) +{ + struct kbl_codec_private *ctx; + + ctx = devm_kzalloc(&pdev->dev, sizeof(*ctx), GFP_ATOMIC); + if (!ctx) + return -ENOMEM; + + INIT_LIST_HEAD(&ctx->hdmi_pcm_list); + + kabylake_audio_card = + (struct snd_soc_card *)pdev->id_entry->driver_data; + + kabylake_audio_card->dev = &pdev->dev; + snd_soc_card_set_drvdata(kabylake_audio_card, ctx); + + return devm_snd_soc_register_card(&pdev->dev, kabylake_audio_card); +} + +static const struct platform_device_id kbl_board_ids[] = { + { + .name = "kbl_da7219_max98927", + .driver_data = + (kernel_ulong_t)&kbl_audio_card_da7219_m98927, + }, + { + .name = "kbl_max98927", + .driver_data = + (kernel_ulong_t)&kbl_audio_card_max98927, + }, + { } +}; + +static struct platform_driver kabylake_audio = { + .probe = kabylake_audio_probe, + .driver = { + .name = "kbl_da7219_max98927", + .pm = &snd_soc_pm_ops, + }, + .id_table = kbl_board_ids, +}; + +module_platform_driver(kabylake_audio) + +/* Module information */ +MODULE_DESCRIPTION("Audio KabyLake Machine driver for MAX98927 & DA7219"); +MODULE_AUTHOR("Mac Chiang "); +MODULE_LICENSE("GPL v2"); +MODULE_ALIAS("platform:kbl_da7219_max98927"); +MODULE_ALIAS("platform:kbl_max98927"); From 6530adeaaf5018cd13437dc82adcd9349657a00e Mon Sep 17 00:00:00 2001 From: Mac Chiang Date: Tue, 9 Oct 2018 15:37:08 +0800 Subject: [PATCH 268/299] ASoC: Intel: common: Add Kabylake Dialog+Maxim machine driver entry This patch adds da7219_max98927 machine driver entry into machine table Signed-off-by: Mac Chiang Signed-off-by: Mark Brown --- sound/soc/intel/common/soc-acpi-intel-kbl-match.c | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/sound/soc/intel/common/soc-acpi-intel-kbl-match.c b/sound/soc/intel/common/soc-acpi-intel-kbl-match.c index 0ee173ca437d..a317b7790fce 100644 --- a/sound/soc/intel/common/soc-acpi-intel-kbl-match.c +++ b/sound/soc/intel/common/soc-acpi-intel-kbl-match.c @@ -32,6 +32,11 @@ static struct snd_soc_acpi_codecs kbl_7219_98357_codecs = { .codecs = {"MX98357A"} }; +static struct snd_soc_acpi_codecs kbl_7219_98927_codecs = { + .num_codecs = 1, + .codecs = {"MX98927"} +}; + struct snd_soc_acpi_mach snd_soc_acpi_intel_kbl_machines[] = { { .id = "INT343A", @@ -83,6 +88,14 @@ struct snd_soc_acpi_mach snd_soc_acpi_intel_kbl_machines[] = { .quirk_data = &kbl_7219_98357_codecs, .pdata = &skl_dmic_data, }, + { + .id = "DLGS7219", + .drv_name = "kbl_da7219_max98927", + .fw_filename = "intel/dsp_fw_kbl.bin", + .machine_quirk = snd_soc_acpi_codec_list, + .quirk_data = &kbl_7219_98927_codecs, + .pdata = &skl_dmic_data + }, {}, }; EXPORT_SYMBOL_GPL(snd_soc_acpi_intel_kbl_machines); From 5cb6b5fc013ee711d19bfc4e9deb8d6ae80741db Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Tue, 16 Oct 2018 12:18:21 +0200 Subject: [PATCH 269/299] ALSA: hda: Add 2 more models to the power_save blacklist Power-saving is causing plops on audio start/stop on Dell Precision T3600 laptops and Intel DZ77BH boards, add these to the power_save blacklist. BugLink: https://bugzilla.redhat.com/show_bug.cgi?id=1525104 Signed-off-by: Hans de Goede Cc: Signed-off-by: Takashi Iwai --- sound/pci/hda/hda_intel.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/sound/pci/hda/hda_intel.c b/sound/pci/hda/hda_intel.c index 20d10757a9bc..d8eb2b5f51ae 100644 --- a/sound/pci/hda/hda_intel.c +++ b/sound/pci/hda/hda_intel.c @@ -2175,8 +2175,12 @@ static struct snd_pci_quirk power_save_blacklist[] = { /* https://bugzilla.redhat.com/show_bug.cgi?id=1581607 */ SND_PCI_QUIRK(0x1558, 0x3501, "Clevo W35xSS_370SS", 0), /* https://bugzilla.redhat.com/show_bug.cgi?id=1525104 */ + SND_PCI_QUIRK(0x1028, 0x0497, "Dell Precision T3600", 0), + /* https://bugzilla.redhat.com/show_bug.cgi?id=1525104 */ /* Note the P55A-UD3 and Z87-D3HP share the subsys id for the HDA dev */ SND_PCI_QUIRK(0x1458, 0xa002, "Gigabyte P55A-UD3 / Z87-D3HP", 0), + /* https://bugzilla.redhat.com/show_bug.cgi?id=1525104 */ + SND_PCI_QUIRK(0x8086, 0x2040, "Intel DZ77BH-55K", 0), /* https://bugzilla.kernel.org/show_bug.cgi?id=199607 */ SND_PCI_QUIRK(0x8086, 0x2057, "Intel NUC5i7RYB", 0), /* https://bugzilla.redhat.com/show_bug.cgi?id=1520902 */ From 3b991038498bc5011b063d6a804503c577a79434 Mon Sep 17 00:00:00 2001 From: Christoph Hellwig Date: Sat, 13 Oct 2018 17:17:04 +0200 Subject: [PATCH 270/299] ASoC: intel: don't pass GFP_DMA32 to dma_alloc_coherent The DMA API does its own zone decisions based on the coherent_dma_mask. Signed-off-by: Christoph Hellwig Reviewed-by: Takashi Iwai Signed-off-by: Mark Brown --- sound/soc/intel/common/sst-firmware.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sound/soc/intel/common/sst-firmware.c b/sound/soc/intel/common/sst-firmware.c index 11041aedea31..1e067504b604 100644 --- a/sound/soc/intel/common/sst-firmware.c +++ b/sound/soc/intel/common/sst-firmware.c @@ -355,7 +355,7 @@ struct sst_fw *sst_fw_new(struct sst_dsp *dsp, /* allocate DMA buffer to store FW data */ sst_fw->dma_buf = dma_alloc_coherent(dsp->dma_dev, sst_fw->size, - &sst_fw->dmable_fw_paddr, GFP_DMA | GFP_KERNEL); + &sst_fw->dmable_fw_paddr, GFP_KERNEL); if (!sst_fw->dma_buf) { dev_err(dsp->dev, "error: DMA alloc failed\n"); kfree(sst_fw); From 66ecce3325383c8304063e7d5a30f4374ef5a33e Mon Sep 17 00:00:00 2001 From: Marcus Cooper Date: Wed, 17 Oct 2018 00:38:05 -0700 Subject: [PATCH 271/299] ASoC: sun4i-i2s: Add compatibility with A64 codec I2S The I2S block used for the audio codec in the A64 differs from other 3 I2S modules in A64 and isn't compatible with H3. But it is very similar to what is found in A10(sun4i). However, its TX FIFO is located at a different address. Signed-off-by: Marcus Cooper Signed-off-by: Vasily Khoruzhick Acked-by: Maxime Ripard Signed-off-by: Mark Brown --- .../devicetree/bindings/sound/sun4i-i2s.txt | 2 ++ sound/soc/sunxi/sun4i-i2s.c | 21 +++++++++++++++++++ 2 files changed, 23 insertions(+) diff --git a/Documentation/devicetree/bindings/sound/sun4i-i2s.txt b/Documentation/devicetree/bindings/sound/sun4i-i2s.txt index b9d50d6cdef3..61e71c1729e0 100644 --- a/Documentation/devicetree/bindings/sound/sun4i-i2s.txt +++ b/Documentation/devicetree/bindings/sound/sun4i-i2s.txt @@ -10,6 +10,7 @@ Required properties: - "allwinner,sun6i-a31-i2s" - "allwinner,sun8i-a83t-i2s" - "allwinner,sun8i-h3-i2s" + - "allwinner,sun50i-a64-codec-i2s" - reg: physical base address of the controller and length of memory mapped region. - interrupts: should contain the I2S interrupt. @@ -26,6 +27,7 @@ Required properties for the following compatibles: - "allwinner,sun6i-a31-i2s" - "allwinner,sun8i-a83t-i2s" - "allwinner,sun8i-h3-i2s" + - "allwinner,sun50i-a64-codec-i2s" - resets: phandle to the reset line for this codec Example: diff --git a/sound/soc/sunxi/sun4i-i2s.c b/sound/soc/sunxi/sun4i-i2s.c index a4aa931ebfae..c63d226e2436 100644 --- a/sound/soc/sunxi/sun4i-i2s.c +++ b/sound/soc/sunxi/sun4i-i2s.c @@ -961,6 +961,23 @@ static const struct sun4i_i2s_quirks sun8i_h3_i2s_quirks = { .field_rxchansel = REG_FIELD(SUN8I_I2S_RX_CHAN_SEL_REG, 0, 2), }; +static const struct sun4i_i2s_quirks sun50i_a64_codec_i2s_quirks = { + .has_reset = true, + .reg_offset_txdata = SUN8I_I2S_FIFO_TX_REG, + .sun4i_i2s_regmap = &sun4i_i2s_regmap_config, + .has_slave_select_bit = true, + .field_clkdiv_mclk_en = REG_FIELD(SUN4I_I2S_CLK_DIV_REG, 7, 7), + .field_fmt_wss = REG_FIELD(SUN4I_I2S_FMT0_REG, 2, 3), + .field_fmt_sr = REG_FIELD(SUN4I_I2S_FMT0_REG, 4, 5), + .field_fmt_bclk = REG_FIELD(SUN4I_I2S_FMT0_REG, 6, 6), + .field_fmt_lrclk = REG_FIELD(SUN4I_I2S_FMT0_REG, 7, 7), + .field_fmt_mode = REG_FIELD(SUN4I_I2S_FMT0_REG, 0, 1), + .field_txchanmap = REG_FIELD(SUN4I_I2S_TX_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_rxchansel = REG_FIELD(SUN4I_I2S_RX_CHAN_SEL_REG, 0, 2), +}; + static int sun4i_i2s_init_regmap_fields(struct device *dev, struct sun4i_i2s *i2s) { @@ -1169,6 +1186,10 @@ static const struct of_device_id sun4i_i2s_match[] = { .compatible = "allwinner,sun8i-h3-i2s", .data = &sun8i_h3_i2s_quirks, }, + { + .compatible = "allwinner,sun50i-a64-codec-i2s", + .data = &sun50i_a64_codec_i2s_quirks, + }, {} }; MODULE_DEVICE_TABLE(of, sun4i_i2s_match); From 13c3bf174becfb8b55adcfeb6f01724dc99347f0 Mon Sep 17 00:00:00 2001 From: Vasily Khoruzhick Date: Wed, 17 Oct 2018 00:38:06 -0700 Subject: [PATCH 272/299] ASoC: sun8i-codec: Don't hardcode BCLK / LRCK ratio BCLK / LRCK ratio should be sample size * channels, but it was hardcoded to 32 (0x1 is 32 as per A33 and A64 datasheets). Calculate it basing on sample size and number of channels. Signed-off-by: Vasily Khoruzhick Acked-by: Maxime Ripard Signed-off-by: Mark Brown --- sound/soc/sunxi/sun8i-codec.c | 22 +++++++++++++++++++--- 1 file changed, 19 insertions(+), 3 deletions(-) diff --git a/sound/soc/sunxi/sun8i-codec.c b/sound/soc/sunxi/sun8i-codec.c index fb37dd927e33..522a72fde78d 100644 --- a/sound/soc/sunxi/sun8i-codec.c +++ b/sound/soc/sunxi/sun8i-codec.c @@ -24,6 +24,7 @@ #include #include #include +#include #include #include @@ -52,7 +53,6 @@ #define SUN8I_AIF1CLK_CTRL_AIF1_LRCK_INV 13 #define SUN8I_AIF1CLK_CTRL_AIF1_BCLK_DIV 9 #define SUN8I_AIF1CLK_CTRL_AIF1_LRCK_DIV 6 -#define SUN8I_AIF1CLK_CTRL_AIF1_LRCK_DIV_16 (1 << 6) #define SUN8I_AIF1CLK_CTRL_AIF1_WORD_SIZ 4 #define SUN8I_AIF1CLK_CTRL_AIF1_WORD_SIZ_16 (1 << 4) #define SUN8I_AIF1CLK_CTRL_AIF1_DATA_FMT 2 @@ -300,12 +300,23 @@ static u8 sun8i_codec_get_bclk_div(struct sun8i_codec *scodec, return best_val; } +static int sun8i_codec_get_lrck_div(unsigned int channels, + unsigned int word_size) +{ + unsigned int div = word_size * channels; + + if (div < 16 || div > 256) + return -EINVAL; + + return ilog2(div) - 4; +} + static int sun8i_codec_hw_params(struct snd_pcm_substream *substream, struct snd_pcm_hw_params *params, struct snd_soc_dai *dai) { struct sun8i_codec *scodec = snd_soc_component_get_drvdata(dai->component); - int sample_rate; + int sample_rate, lrck_div; u8 bclk_div; /* @@ -321,9 +332,14 @@ static int sun8i_codec_hw_params(struct snd_pcm_substream *substream, SUN8I_AIF1CLK_CTRL_AIF1_BCLK_DIV_MASK, bclk_div << SUN8I_AIF1CLK_CTRL_AIF1_BCLK_DIV); + lrck_div = sun8i_codec_get_lrck_div(params_channels(params), + params_physical_width(params)); + if (lrck_div < 0) + return lrck_div; + regmap_update_bits(scodec->regmap, SUN8I_AIF1CLK_CTRL, SUN8I_AIF1CLK_CTRL_AIF1_LRCK_DIV_MASK, - SUN8I_AIF1CLK_CTRL_AIF1_LRCK_DIV_16); + lrck_div << SUN8I_AIF1CLK_CTRL_AIF1_LRCK_DIV); sample_rate = sun8i_codec_get_hw_rate(params); if (sample_rate < 0) From 55b407f6468c481edc4a26b21c9f567ae57f01a4 Mon Sep 17 00:00:00 2001 From: Vasily Khoruzhick Date: Wed, 17 Oct 2018 00:38:07 -0700 Subject: [PATCH 273/299] ASoC: sun8i-codec-analog: split regmap code into separate driver It will be reused by sun50i-codec-analog later. Signed-off-by: Vasily Khoruzhick Acked-by: Maxime Ripard Signed-off-by: Mark Brown --- sound/soc/sunxi/Kconfig | 7 +- sound/soc/sunxi/Makefile | 1 + sound/soc/sunxi/sun8i-adda-pr-regmap.c | 102 +++++++++++++++++++++++++ sound/soc/sunxi/sun8i-adda-pr-regmap.h | 7 ++ sound/soc/sunxi/sun8i-codec-analog.c | 79 +------------------ 5 files changed, 119 insertions(+), 77 deletions(-) create mode 100644 sound/soc/sunxi/sun8i-adda-pr-regmap.c create mode 100644 sound/soc/sunxi/sun8i-adda-pr-regmap.h diff --git a/sound/soc/sunxi/Kconfig b/sound/soc/sunxi/Kconfig index 22408bc2d6ec..83b770cdfdaa 100644 --- a/sound/soc/sunxi/Kconfig +++ b/sound/soc/sunxi/Kconfig @@ -23,7 +23,7 @@ config SND_SUN8I_CODEC config SND_SUN8I_CODEC_ANALOG tristate "Allwinner sun8i Codec Analog Controls Support" depends on MACH_SUN8I || (ARM64 && ARCH_SUNXI) || COMPILE_TEST - select REGMAP + select SND_SUN8I_ADDA_PR_REGMAP help Say Y or M if you want to add support for the analog controls for the codec embedded in newer Allwinner SoCs. @@ -45,4 +45,9 @@ config SND_SUN4I_SPDIF help Say Y or M to add support for the S/PDIF audio block in the Allwinner A10 and affiliated SoCs. + +config SND_SUN8I_ADDA_PR_REGMAP + tristate + select REGMAP + endmenu diff --git a/sound/soc/sunxi/Makefile b/sound/soc/sunxi/Makefile index 4a9ef67386ca..74b99d55cfca 100644 --- a/sound/soc/sunxi/Makefile +++ b/sound/soc/sunxi/Makefile @@ -4,3 +4,4 @@ obj-$(CONFIG_SND_SUN4I_I2S) += sun4i-i2s.o obj-$(CONFIG_SND_SUN4I_SPDIF) += sun4i-spdif.o obj-$(CONFIG_SND_SUN8I_CODEC_ANALOG) += sun8i-codec-analog.o obj-$(CONFIG_SND_SUN8I_CODEC) += sun8i-codec.o +obj-$(CONFIG_SND_SUN8I_ADDA_PR_REGMAP) += sun8i-adda-pr-regmap.o diff --git a/sound/soc/sunxi/sun8i-adda-pr-regmap.c b/sound/soc/sunxi/sun8i-adda-pr-regmap.c new file mode 100644 index 000000000000..e68ce9d2884d --- /dev/null +++ b/sound/soc/sunxi/sun8i-adda-pr-regmap.c @@ -0,0 +1,102 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * This driver provides regmap to access to analog part of audio codec + * found on Allwinner A23, A31s, A33, H3 and A64 Socs + * + * Copyright 2016 Chen-Yu Tsai + * Copyright (C) 2018 Vasily Khoruzhick + */ + +#include +#include +#include +#include + +#include "sun8i-adda-pr-regmap.h" + +/* Analog control register access bits */ +#define ADDA_PR 0x0 /* PRCM base + 0x1c0 */ +#define ADDA_PR_RESET BIT(28) +#define ADDA_PR_WRITE BIT(24) +#define ADDA_PR_ADDR_SHIFT 16 +#define ADDA_PR_ADDR_MASK GENMASK(4, 0) +#define ADDA_PR_DATA_IN_SHIFT 8 +#define ADDA_PR_DATA_IN_MASK GENMASK(7, 0) +#define ADDA_PR_DATA_OUT_SHIFT 0 +#define ADDA_PR_DATA_OUT_MASK GENMASK(7, 0) + +/* regmap access bits */ +static int adda_reg_read(void *context, unsigned int reg, unsigned int *val) +{ + void __iomem *base = (void __iomem *)context; + u32 tmp; + + /* De-assert reset */ + writel(readl(base) | ADDA_PR_RESET, base); + + /* Clear write bit */ + writel(readl(base) & ~ADDA_PR_WRITE, base); + + /* Set register address */ + tmp = readl(base); + tmp &= ~(ADDA_PR_ADDR_MASK << ADDA_PR_ADDR_SHIFT); + tmp |= (reg & ADDA_PR_ADDR_MASK) << ADDA_PR_ADDR_SHIFT; + writel(tmp, base); + + /* Read back value */ + *val = readl(base) & ADDA_PR_DATA_OUT_MASK; + + return 0; +} + +static int adda_reg_write(void *context, unsigned int reg, unsigned int val) +{ + void __iomem *base = (void __iomem *)context; + u32 tmp; + + /* De-assert reset */ + writel(readl(base) | ADDA_PR_RESET, base); + + /* Set register address */ + tmp = readl(base); + tmp &= ~(ADDA_PR_ADDR_MASK << ADDA_PR_ADDR_SHIFT); + tmp |= (reg & ADDA_PR_ADDR_MASK) << ADDA_PR_ADDR_SHIFT; + writel(tmp, base); + + /* Set data to write */ + tmp = readl(base); + tmp &= ~(ADDA_PR_DATA_IN_MASK << ADDA_PR_DATA_IN_SHIFT); + tmp |= (val & ADDA_PR_DATA_IN_MASK) << ADDA_PR_DATA_IN_SHIFT; + writel(tmp, base); + + /* Set write bit to signal a write */ + writel(readl(base) | ADDA_PR_WRITE, base); + + /* Clear write bit */ + writel(readl(base) & ~ADDA_PR_WRITE, base); + + return 0; +} + +static const struct regmap_config adda_pr_regmap_cfg = { + .name = "adda-pr", + .reg_bits = 5, + .reg_stride = 1, + .val_bits = 8, + .reg_read = adda_reg_read, + .reg_write = adda_reg_write, + .fast_io = true, + .max_register = 31, +}; + +struct regmap *sun8i_adda_pr_regmap_init(struct device *dev, + void __iomem *base) +{ + return devm_regmap_init(dev, NULL, base, &adda_pr_regmap_cfg); +} +EXPORT_SYMBOL_GPL(sun8i_adda_pr_regmap_init); + +MODULE_DESCRIPTION("Allwinner analog audio codec regmap driver"); +MODULE_AUTHOR("Vasily Khoruzhick "); +MODULE_LICENSE("GPL"); +MODULE_ALIAS("platform:sunxi-adda-pr"); diff --git a/sound/soc/sunxi/sun8i-adda-pr-regmap.h b/sound/soc/sunxi/sun8i-adda-pr-regmap.h new file mode 100644 index 000000000000..a5ae95dfebc1 --- /dev/null +++ b/sound/soc/sunxi/sun8i-adda-pr-regmap.h @@ -0,0 +1,7 @@ +/* SPDX-License-Identifier: GPL-2.0+ */ +/* + * Copyright (C) 2018 Vasily Khoruzhick + */ + +struct regmap *sun8i_adda_pr_regmap_init(struct device *dev, + void __iomem *base); diff --git a/sound/soc/sunxi/sun8i-codec-analog.c b/sound/soc/sunxi/sun8i-codec-analog.c index 485e79f292c4..916a46bbc1c8 100644 --- a/sound/soc/sunxi/sun8i-codec-analog.c +++ b/sound/soc/sunxi/sun8i-codec-analog.c @@ -27,6 +27,8 @@ #include #include +#include "sun8i-adda-pr-regmap.h" + /* Codec analog control register offsets and bit fields */ #define SUN8I_ADDA_HP_VOLC 0x00 #define SUN8I_ADDA_HP_VOLC_PA_CLK_GATE 7 @@ -120,81 +122,6 @@ #define SUN8I_ADDA_ADC_AP_EN_ADCLEN 6 #define SUN8I_ADDA_ADC_AP_EN_ADCG 0 -/* Analog control register access bits */ -#define ADDA_PR 0x0 /* PRCM base + 0x1c0 */ -#define ADDA_PR_RESET BIT(28) -#define ADDA_PR_WRITE BIT(24) -#define ADDA_PR_ADDR_SHIFT 16 -#define ADDA_PR_ADDR_MASK GENMASK(4, 0) -#define ADDA_PR_DATA_IN_SHIFT 8 -#define ADDA_PR_DATA_IN_MASK GENMASK(7, 0) -#define ADDA_PR_DATA_OUT_SHIFT 0 -#define ADDA_PR_DATA_OUT_MASK GENMASK(7, 0) - -/* regmap access bits */ -static int adda_reg_read(void *context, unsigned int reg, unsigned int *val) -{ - void __iomem *base = (void __iomem *)context; - u32 tmp; - - /* De-assert reset */ - writel(readl(base) | ADDA_PR_RESET, base); - - /* Clear write bit */ - writel(readl(base) & ~ADDA_PR_WRITE, base); - - /* Set register address */ - tmp = readl(base); - tmp &= ~(ADDA_PR_ADDR_MASK << ADDA_PR_ADDR_SHIFT); - tmp |= (reg & ADDA_PR_ADDR_MASK) << ADDA_PR_ADDR_SHIFT; - writel(tmp, base); - - /* Read back value */ - *val = readl(base) & ADDA_PR_DATA_OUT_MASK; - - return 0; -} - -static int adda_reg_write(void *context, unsigned int reg, unsigned int val) -{ - void __iomem *base = (void __iomem *)context; - u32 tmp; - - /* De-assert reset */ - writel(readl(base) | ADDA_PR_RESET, base); - - /* Set register address */ - tmp = readl(base); - tmp &= ~(ADDA_PR_ADDR_MASK << ADDA_PR_ADDR_SHIFT); - tmp |= (reg & ADDA_PR_ADDR_MASK) << ADDA_PR_ADDR_SHIFT; - writel(tmp, base); - - /* Set data to write */ - tmp = readl(base); - tmp &= ~(ADDA_PR_DATA_IN_MASK << ADDA_PR_DATA_IN_SHIFT); - tmp |= (val & ADDA_PR_DATA_IN_MASK) << ADDA_PR_DATA_IN_SHIFT; - writel(tmp, base); - - /* Set write bit to signal a write */ - writel(readl(base) | ADDA_PR_WRITE, base); - - /* Clear write bit */ - writel(readl(base) & ~ADDA_PR_WRITE, base); - - return 0; -} - -static const struct regmap_config adda_pr_regmap_cfg = { - .name = "adda-pr", - .reg_bits = 5, - .reg_stride = 1, - .val_bits = 8, - .reg_read = adda_reg_read, - .reg_write = adda_reg_write, - .fast_io = true, - .max_register = 24, -}; - /* mixer controls */ static const struct snd_kcontrol_new sun8i_codec_mixer_controls[] = { SOC_DAPM_DOUBLE_R("DAC Playback Switch", @@ -912,7 +839,7 @@ static int sun8i_codec_analog_probe(struct platform_device *pdev) return PTR_ERR(base); } - regmap = devm_regmap_init(&pdev->dev, NULL, base, &adda_pr_regmap_cfg); + regmap = sun8i_adda_pr_regmap_init(&pdev->dev, base); if (IS_ERR(regmap)) { dev_err(&pdev->dev, "Failed to create regmap\n"); return PTR_ERR(regmap); From af2c06c41970eb0110a03696fd7f8f07854719db Mon Sep 17 00:00:00 2001 From: Vasily Khoruzhick Date: Wed, 17 Oct 2018 00:38:08 -0700 Subject: [PATCH 274/299] ASoC: dt-binding: Add bindings for Allwinner A64 codec's analog path controls The internal codec on Allwinner A64 is split into 2 parts. The analog path controls are routed through an embedded custom register bus accessed through the PRCM block just as on A23/A33/H3. Add a binding for this hardware. Signed-off-by: Vasily Khoruzhick Acked-by: Maxime Ripard Signed-off-by: Mark Brown --- .../bindings/sound/sun50i-codec-analog.txt | 12 ++++++++++++ 1 file changed, 12 insertions(+) create mode 100644 Documentation/devicetree/bindings/sound/sun50i-codec-analog.txt diff --git a/Documentation/devicetree/bindings/sound/sun50i-codec-analog.txt b/Documentation/devicetree/bindings/sound/sun50i-codec-analog.txt new file mode 100644 index 000000000000..4f8ad0e04d20 --- /dev/null +++ b/Documentation/devicetree/bindings/sound/sun50i-codec-analog.txt @@ -0,0 +1,12 @@ +* Allwinner A64 Codec Analog Controls + +Required properties: +- compatible: must be one of the following compatibles: + - "allwinner,sun50i-a64-codec-analog" +- reg: must contain the registers location and length + +Example: + codec_analog: codec-analog@1f015c0 { + compatible = "allwinner,sun50i-a64-codec-analog"; + reg = <0x01f015c0 0x4>; + }; From 42371f327df0b8e9d479b929c5cd301846dd0f70 Mon Sep 17 00:00:00 2001 From: Vasily Khoruzhick Date: Wed, 17 Oct 2018 00:38:09 -0700 Subject: [PATCH 275/299] ASoC: sunxi: Add new driver for Allwinner A64 codec's analog path controls The internal codec on A64 is split into 2 parts. The analog path controls are routed through an embedded custom register bus accessed through the PRCM block. Add an ASoC component driver for it. This should be tied to the codec audio card as an auxiliary device. Signed-off-by: Vasily Khoruzhick Acked-by: Maxime Ripard Signed-off-by: Mark Brown --- sound/soc/sunxi/Kconfig | 8 + sound/soc/sunxi/Makefile | 1 + sound/soc/sunxi/sun50i-codec-analog.c | 444 ++++++++++++++++++++++++++ 3 files changed, 453 insertions(+) create mode 100644 sound/soc/sunxi/sun50i-codec-analog.c diff --git a/sound/soc/sunxi/Kconfig b/sound/soc/sunxi/Kconfig index 83b770cdfdaa..8a055ca1819a 100644 --- a/sound/soc/sunxi/Kconfig +++ b/sound/soc/sunxi/Kconfig @@ -28,6 +28,14 @@ config SND_SUN8I_CODEC_ANALOG Say Y or M if you want to add support for the analog controls for the codec embedded in newer Allwinner SoCs. +config SND_SUN50I_CODEC_ANALOG + tristate "Allwinner sun50i Codec Analog Controls Support" + depends on (ARM64 && ARCH_SUNXI) || COMPILE_TEST + select SND_SUNXI_ADDA_PR_REGMAP + help + Say Y or M if you want to add support for the analog controls for + the codec embedded in Allwinner A64 SoC. + config SND_SUN4I_I2S tristate "Allwinner A10 I2S Support" select SND_SOC_GENERIC_DMAENGINE_PCM diff --git a/sound/soc/sunxi/Makefile b/sound/soc/sunxi/Makefile index 74b99d55cfca..a86be340a076 100644 --- a/sound/soc/sunxi/Makefile +++ b/sound/soc/sunxi/Makefile @@ -3,5 +3,6 @@ obj-$(CONFIG_SND_SUN4I_CODEC) += sun4i-codec.o obj-$(CONFIG_SND_SUN4I_I2S) += sun4i-i2s.o obj-$(CONFIG_SND_SUN4I_SPDIF) += sun4i-spdif.o obj-$(CONFIG_SND_SUN8I_CODEC_ANALOG) += sun8i-codec-analog.o +obj-$(CONFIG_SND_SUN50I_CODEC_ANALOG) += sun50i-codec-analog.o obj-$(CONFIG_SND_SUN8I_CODEC) += sun8i-codec.o obj-$(CONFIG_SND_SUN8I_ADDA_PR_REGMAP) += sun8i-adda-pr-regmap.o diff --git a/sound/soc/sunxi/sun50i-codec-analog.c b/sound/soc/sunxi/sun50i-codec-analog.c new file mode 100644 index 000000000000..8f5f999df631 --- /dev/null +++ b/sound/soc/sunxi/sun50i-codec-analog.c @@ -0,0 +1,444 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * This driver supports the analog controls for the internal codec + * found in Allwinner's A64 SoC. + * + * Copyright (C) 2016 Chen-Yu Tsai + * Copyright (C) 2017 Marcus Cooper + * Copyright (C) 2018 Vasily Khoruzhick + * + * Based on sun8i-codec-analog.c + * + */ + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include "sun8i-adda-pr-regmap.h" + +/* Codec analog control register offsets and bit fields */ +#define SUN50I_ADDA_HP_CTRL 0x00 +#define SUN50I_ADDA_HP_CTRL_PA_CLK_GATE 7 +#define SUN50I_ADDA_HP_CTRL_HPPA_EN 6 +#define SUN50I_ADDA_HP_CTRL_HPVOL 0 + +#define SUN50I_ADDA_OL_MIX_CTRL 0x01 +#define SUN50I_ADDA_OL_MIX_CTRL_MIC1 6 +#define SUN50I_ADDA_OL_MIX_CTRL_MIC2 5 +#define SUN50I_ADDA_OL_MIX_CTRL_PHONE 4 +#define SUN50I_ADDA_OL_MIX_CTRL_PHONEN 3 +#define SUN50I_ADDA_OL_MIX_CTRL_LINEINL 2 +#define SUN50I_ADDA_OL_MIX_CTRL_DACL 1 +#define SUN50I_ADDA_OL_MIX_CTRL_DACR 0 + +#define SUN50I_ADDA_OR_MIX_CTRL 0x02 +#define SUN50I_ADDA_OR_MIX_CTRL_MIC1 6 +#define SUN50I_ADDA_OR_MIX_CTRL_MIC2 5 +#define SUN50I_ADDA_OR_MIX_CTRL_PHONE 4 +#define SUN50I_ADDA_OR_MIX_CTRL_PHONEP 3 +#define SUN50I_ADDA_OR_MIX_CTRL_LINEINR 2 +#define SUN50I_ADDA_OR_MIX_CTRL_DACR 1 +#define SUN50I_ADDA_OR_MIX_CTRL_DACL 0 + +#define SUN50I_ADDA_LINEOUT_CTRL0 0x05 +#define SUN50I_ADDA_LINEOUT_CTRL0_LEN 7 +#define SUN50I_ADDA_LINEOUT_CTRL0_REN 6 +#define SUN50I_ADDA_LINEOUT_CTRL0_LSRC_SEL 5 +#define SUN50I_ADDA_LINEOUT_CTRL0_RSRC_SEL 4 + +#define SUN50I_ADDA_LINEOUT_CTRL1 0x06 +#define SUN50I_ADDA_LINEOUT_CTRL1_VOL 0 + +#define SUN50I_ADDA_MIC1_CTRL 0x07 +#define SUN50I_ADDA_MIC1_CTRL_MIC1G 4 +#define SUN50I_ADDA_MIC1_CTRL_MIC1AMPEN 3 +#define SUN50I_ADDA_MIC1_CTRL_MIC1BOOST 0 + +#define SUN50I_ADDA_MIC2_CTRL 0x08 +#define SUN50I_ADDA_MIC2_CTRL_MIC2G 4 +#define SUN50I_ADDA_MIC2_CTRL_MIC2AMPEN 3 +#define SUN50I_ADDA_MIC2_CTRL_MIC2BOOST 0 + +#define SUN50I_ADDA_LINEIN_CTRL 0x09 +#define SUN50I_ADDA_LINEIN_CTRL_LINEING 0 + +#define SUN50I_ADDA_MIX_DAC_CTRL 0x0a +#define SUN50I_ADDA_MIX_DAC_CTRL_DACAREN 7 +#define SUN50I_ADDA_MIX_DAC_CTRL_DACALEN 6 +#define SUN50I_ADDA_MIX_DAC_CTRL_RMIXEN 5 +#define SUN50I_ADDA_MIX_DAC_CTRL_LMIXEN 4 +#define SUN50I_ADDA_MIX_DAC_CTRL_RHPPAMUTE 3 +#define SUN50I_ADDA_MIX_DAC_CTRL_LHPPAMUTE 2 +#define SUN50I_ADDA_MIX_DAC_CTRL_RHPIS 1 +#define SUN50I_ADDA_MIX_DAC_CTRL_LHPIS 0 + +#define SUN50I_ADDA_L_ADCMIX_SRC 0x0b +#define SUN50I_ADDA_L_ADCMIX_SRC_MIC1 6 +#define SUN50I_ADDA_L_ADCMIX_SRC_MIC2 5 +#define SUN50I_ADDA_L_ADCMIX_SRC_PHONE 4 +#define SUN50I_ADDA_L_ADCMIX_SRC_PHONEN 3 +#define SUN50I_ADDA_L_ADCMIX_SRC_LINEINL 2 +#define SUN50I_ADDA_L_ADCMIX_SRC_OMIXRL 1 +#define SUN50I_ADDA_L_ADCMIX_SRC_OMIXRR 0 + +#define SUN50I_ADDA_R_ADCMIX_SRC 0x0c +#define SUN50I_ADDA_R_ADCMIX_SRC_MIC1 6 +#define SUN50I_ADDA_R_ADCMIX_SRC_MIC2 5 +#define SUN50I_ADDA_R_ADCMIX_SRC_PHONE 4 +#define SUN50I_ADDA_R_ADCMIX_SRC_PHONEP 3 +#define SUN50I_ADDA_R_ADCMIX_SRC_LINEINR 2 +#define SUN50I_ADDA_R_ADCMIX_SRC_OMIXR 1 +#define SUN50I_ADDA_R_ADCMIX_SRC_OMIXL 0 + +#define SUN50I_ADDA_ADC_CTRL 0x0d +#define SUN50I_ADDA_ADC_CTRL_ADCREN 7 +#define SUN50I_ADDA_ADC_CTRL_ADCLEN 6 +#define SUN50I_ADDA_ADC_CTRL_ADCG 0 + +#define SUN50I_ADDA_HS_MBIAS_CTRL 0x0e +#define SUN50I_ADDA_HS_MBIAS_CTRL_MMICBIASEN 7 + +#define SUN50I_ADDA_JACK_MIC_CTRL 0x1d +#define SUN50I_ADDA_JACK_MIC_CTRL_HMICBIASEN 5 + +/* mixer controls */ +static const struct snd_kcontrol_new sun50i_a64_codec_mixer_controls[] = { + SOC_DAPM_DOUBLE_R("DAC Playback Switch", + SUN50I_ADDA_OL_MIX_CTRL, + SUN50I_ADDA_OR_MIX_CTRL, + SUN50I_ADDA_OL_MIX_CTRL_DACL, 1, 0), + SOC_DAPM_DOUBLE_R("DAC Reversed Playback Switch", + SUN50I_ADDA_OL_MIX_CTRL, + SUN50I_ADDA_OR_MIX_CTRL, + SUN50I_ADDA_OL_MIX_CTRL_DACR, 1, 0), + SOC_DAPM_DOUBLE_R("Line In Playback Switch", + SUN50I_ADDA_OL_MIX_CTRL, + SUN50I_ADDA_OR_MIX_CTRL, + SUN50I_ADDA_OL_MIX_CTRL_LINEINL, 1, 0), + SOC_DAPM_DOUBLE_R("Mic1 Playback Switch", + SUN50I_ADDA_OL_MIX_CTRL, + SUN50I_ADDA_OR_MIX_CTRL, + SUN50I_ADDA_OL_MIX_CTRL_MIC1, 1, 0), + SOC_DAPM_DOUBLE_R("Mic2 Playback Switch", + SUN50I_ADDA_OL_MIX_CTRL, + SUN50I_ADDA_OR_MIX_CTRL, + SUN50I_ADDA_OL_MIX_CTRL_MIC2, 1, 0), +}; + +/* ADC mixer controls */ +static const struct snd_kcontrol_new sun50i_codec_adc_mixer_controls[] = { + SOC_DAPM_DOUBLE_R("Mixer Capture Switch", + SUN50I_ADDA_L_ADCMIX_SRC, + SUN50I_ADDA_R_ADCMIX_SRC, + SUN50I_ADDA_L_ADCMIX_SRC_OMIXRL, 1, 0), + SOC_DAPM_DOUBLE_R("Mixer Reversed Capture Switch", + SUN50I_ADDA_L_ADCMIX_SRC, + SUN50I_ADDA_R_ADCMIX_SRC, + SUN50I_ADDA_L_ADCMIX_SRC_OMIXRR, 1, 0), + SOC_DAPM_DOUBLE_R("Line In Capture Switch", + SUN50I_ADDA_L_ADCMIX_SRC, + SUN50I_ADDA_R_ADCMIX_SRC, + SUN50I_ADDA_L_ADCMIX_SRC_LINEINL, 1, 0), + SOC_DAPM_DOUBLE_R("Mic1 Capture Switch", + SUN50I_ADDA_L_ADCMIX_SRC, + SUN50I_ADDA_R_ADCMIX_SRC, + SUN50I_ADDA_L_ADCMIX_SRC_MIC1, 1, 0), + SOC_DAPM_DOUBLE_R("Mic2 Capture Switch", + SUN50I_ADDA_L_ADCMIX_SRC, + SUN50I_ADDA_R_ADCMIX_SRC, + SUN50I_ADDA_L_ADCMIX_SRC_MIC2, 1, 0), +}; + +static const DECLARE_TLV_DB_SCALE(sun50i_codec_out_mixer_pregain_scale, + -450, 150, 0); +static const DECLARE_TLV_DB_RANGE(sun50i_codec_mic_gain_scale, + 0, 0, TLV_DB_SCALE_ITEM(0, 0, 0), + 1, 7, TLV_DB_SCALE_ITEM(2400, 300, 0), +); + +static const DECLARE_TLV_DB_SCALE(sun50i_codec_hp_vol_scale, -6300, 100, 1); + +static const DECLARE_TLV_DB_RANGE(sun50i_codec_lineout_vol_scale, + 0, 1, TLV_DB_SCALE_ITEM(TLV_DB_GAIN_MUTE, 0, 1), + 2, 31, TLV_DB_SCALE_ITEM(-4350, 150, 0), +); + + +/* volume / mute controls */ +static const struct snd_kcontrol_new sun50i_a64_codec_controls[] = { + SOC_SINGLE_TLV("Headphone Playback Volume", + SUN50I_ADDA_HP_CTRL, + SUN50I_ADDA_HP_CTRL_HPVOL, 0x3f, 0, + sun50i_codec_hp_vol_scale), + + SOC_DOUBLE("Headphone Playback Switch", + SUN50I_ADDA_MIX_DAC_CTRL, + SUN50I_ADDA_MIX_DAC_CTRL_LHPPAMUTE, + SUN50I_ADDA_MIX_DAC_CTRL_RHPPAMUTE, 1, 0), + + /* Mixer pre-gain */ + SOC_SINGLE_TLV("Mic1 Playback Volume", SUN50I_ADDA_MIC1_CTRL, + SUN50I_ADDA_MIC1_CTRL_MIC1G, + 0x7, 0, sun50i_codec_out_mixer_pregain_scale), + + /* Microphone Amp boost gain */ + SOC_SINGLE_TLV("Mic1 Boost Volume", SUN50I_ADDA_MIC1_CTRL, + SUN50I_ADDA_MIC1_CTRL_MIC1BOOST, 0x7, 0, + sun50i_codec_mic_gain_scale), + + /* Mixer pre-gain */ + SOC_SINGLE_TLV("Mic2 Playback Volume", + SUN50I_ADDA_MIC2_CTRL, SUN50I_ADDA_MIC2_CTRL_MIC2G, + 0x7, 0, sun50i_codec_out_mixer_pregain_scale), + + /* Microphone Amp boost gain */ + SOC_SINGLE_TLV("Mic2 Boost Volume", SUN50I_ADDA_MIC2_CTRL, + SUN50I_ADDA_MIC2_CTRL_MIC2BOOST, 0x7, 0, + sun50i_codec_mic_gain_scale), + + /* ADC */ + SOC_SINGLE_TLV("ADC Gain Capture Volume", SUN50I_ADDA_ADC_CTRL, + SUN50I_ADDA_ADC_CTRL_ADCG, 0x7, 0, + sun50i_codec_out_mixer_pregain_scale), + + /* Mixer pre-gain */ + SOC_SINGLE_TLV("Line In Playback Volume", SUN50I_ADDA_LINEIN_CTRL, + SUN50I_ADDA_LINEIN_CTRL_LINEING, + 0x7, 0, sun50i_codec_out_mixer_pregain_scale), + + SOC_SINGLE_TLV("Line Out Playback Volume", + SUN50I_ADDA_LINEOUT_CTRL1, + SUN50I_ADDA_LINEOUT_CTRL1_VOL, 0x1f, 0, + sun50i_codec_lineout_vol_scale), + + SOC_DOUBLE("Line Out Playback Switch", + SUN50I_ADDA_LINEOUT_CTRL0, + SUN50I_ADDA_LINEOUT_CTRL0_LEN, + SUN50I_ADDA_LINEOUT_CTRL0_REN, 1, 0), + +}; + +static const char * const sun50i_codec_hp_src_enum_text[] = { + "DAC", "Mixer", +}; + +static SOC_ENUM_DOUBLE_DECL(sun50i_codec_hp_src_enum, + SUN50I_ADDA_MIX_DAC_CTRL, + SUN50I_ADDA_MIX_DAC_CTRL_LHPIS, + SUN50I_ADDA_MIX_DAC_CTRL_RHPIS, + sun50i_codec_hp_src_enum_text); + +static const struct snd_kcontrol_new sun50i_codec_hp_src[] = { + SOC_DAPM_ENUM("Headphone Source Playback Route", + sun50i_codec_hp_src_enum), +}; + +static const char * const sun50i_codec_lineout_src_enum_text[] = { + "Stereo", "Mono Differential", +}; + +static SOC_ENUM_DOUBLE_DECL(sun50i_codec_lineout_src_enum, + SUN50I_ADDA_LINEOUT_CTRL0, + SUN50I_ADDA_LINEOUT_CTRL0_LSRC_SEL, + SUN50I_ADDA_LINEOUT_CTRL0_RSRC_SEL, + sun50i_codec_lineout_src_enum_text); + +static const struct snd_kcontrol_new sun50i_codec_lineout_src[] = { + SOC_DAPM_ENUM("Line Out Source Playback Route", + sun50i_codec_lineout_src_enum), +}; + +static const struct snd_soc_dapm_widget sun50i_a64_codec_widgets[] = { + /* DAC */ + SND_SOC_DAPM_DAC("Left DAC", NULL, SUN50I_ADDA_MIX_DAC_CTRL, + SUN50I_ADDA_MIX_DAC_CTRL_DACALEN, 0), + SND_SOC_DAPM_DAC("Right DAC", NULL, SUN50I_ADDA_MIX_DAC_CTRL, + SUN50I_ADDA_MIX_DAC_CTRL_DACAREN, 0), + /* ADC */ + SND_SOC_DAPM_ADC("Left ADC", NULL, SUN50I_ADDA_ADC_CTRL, + SUN50I_ADDA_ADC_CTRL_ADCLEN, 0), + SND_SOC_DAPM_ADC("Right ADC", NULL, SUN50I_ADDA_ADC_CTRL, + SUN50I_ADDA_ADC_CTRL_ADCREN, 0), + /* + * Due to this component and the codec belonging to separate DAPM + * contexts, we need to manually link the above widgets to their + * stream widgets at the card level. + */ + + SND_SOC_DAPM_MUX("Headphone Source Playback Route", + SND_SOC_NOPM, 0, 0, sun50i_codec_hp_src), + SND_SOC_DAPM_OUT_DRV("Headphone Amp", SUN50I_ADDA_HP_CTRL, + SUN50I_ADDA_HP_CTRL_HPPA_EN, 0, NULL, 0), + SND_SOC_DAPM_OUTPUT("HP"), + + SND_SOC_DAPM_MUX("Line Out Source Playback Route", + SND_SOC_NOPM, 0, 0, sun50i_codec_lineout_src), + SND_SOC_DAPM_OUTPUT("LINEOUT"), + + /* Microphone inputs */ + SND_SOC_DAPM_INPUT("MIC1"), + + /* Microphone Bias */ + SND_SOC_DAPM_SUPPLY("MBIAS", SUN50I_ADDA_HS_MBIAS_CTRL, + SUN50I_ADDA_HS_MBIAS_CTRL_MMICBIASEN, + 0, NULL, 0), + + /* Mic input path */ + SND_SOC_DAPM_PGA("Mic1 Amplifier", SUN50I_ADDA_MIC1_CTRL, + SUN50I_ADDA_MIC1_CTRL_MIC1AMPEN, 0, NULL, 0), + + /* Microphone input */ + SND_SOC_DAPM_INPUT("MIC2"), + + /* Microphone Bias */ + SND_SOC_DAPM_SUPPLY("HBIAS", SUN50I_ADDA_JACK_MIC_CTRL, + SUN50I_ADDA_JACK_MIC_CTRL_HMICBIASEN, + 0, NULL, 0), + + /* Mic input path */ + SND_SOC_DAPM_PGA("Mic2 Amplifier", SUN50I_ADDA_MIC2_CTRL, + SUN50I_ADDA_MIC2_CTRL_MIC2AMPEN, 0, NULL, 0), + + /* Line input */ + SND_SOC_DAPM_INPUT("LINEIN"), + + /* Mixers */ + SND_SOC_DAPM_MIXER("Left Mixer", SUN50I_ADDA_MIX_DAC_CTRL, + SUN50I_ADDA_MIX_DAC_CTRL_LMIXEN, 0, + sun50i_a64_codec_mixer_controls, + ARRAY_SIZE(sun50i_a64_codec_mixer_controls)), + SND_SOC_DAPM_MIXER("Right Mixer", SUN50I_ADDA_MIX_DAC_CTRL, + SUN50I_ADDA_MIX_DAC_CTRL_RMIXEN, 0, + sun50i_a64_codec_mixer_controls, + ARRAY_SIZE(sun50i_a64_codec_mixer_controls)), + SND_SOC_DAPM_MIXER("Left ADC Mixer", SUN50I_ADDA_ADC_CTRL, + SUN50I_ADDA_ADC_CTRL_ADCLEN, 0, + sun50i_codec_adc_mixer_controls, + ARRAY_SIZE(sun50i_codec_adc_mixer_controls)), + SND_SOC_DAPM_MIXER("Right ADC Mixer", SUN50I_ADDA_ADC_CTRL, + SUN50I_ADDA_ADC_CTRL_ADCREN, 0, + sun50i_codec_adc_mixer_controls, + ARRAY_SIZE(sun50i_codec_adc_mixer_controls)), +}; + +static const struct snd_soc_dapm_route sun50i_a64_codec_routes[] = { + /* Left Mixer Routes */ + { "Left Mixer", "DAC Playback Switch", "Left DAC" }, + { "Left Mixer", "DAC Reversed Playback Switch", "Right DAC" }, + { "Left Mixer", "Mic1 Playback Switch", "Mic1 Amplifier" }, + + /* Right Mixer Routes */ + { "Right Mixer", "DAC Playback Switch", "Right DAC" }, + { "Right Mixer", "DAC Reversed Playback Switch", "Left DAC" }, + { "Right Mixer", "Mic1 Playback Switch", "Mic1 Amplifier" }, + + /* Left ADC Mixer Routes */ + { "Left ADC Mixer", "Mixer Capture Switch", "Left Mixer" }, + { "Left ADC Mixer", "Mixer Reversed Capture Switch", "Right Mixer" }, + { "Left ADC Mixer", "Mic1 Capture Switch", "Mic1 Amplifier" }, + + /* Right ADC Mixer Routes */ + { "Right ADC Mixer", "Mixer Capture Switch", "Right Mixer" }, + { "Right ADC Mixer", "Mixer Reversed Capture Switch", "Left Mixer" }, + { "Right ADC Mixer", "Mic1 Capture Switch", "Mic1 Amplifier" }, + + /* ADC Routes */ + { "Left ADC", NULL, "Left ADC Mixer" }, + { "Right ADC", NULL, "Right ADC Mixer" }, + + /* Headphone Routes */ + { "Headphone Source Playback Route", "DAC", "Left DAC" }, + { "Headphone Source Playback Route", "DAC", "Right DAC" }, + { "Headphone Source Playback Route", "Mixer", "Left Mixer" }, + { "Headphone Source Playback Route", "Mixer", "Right Mixer" }, + { "Headphone Amp", NULL, "Headphone Source Playback Route" }, + { "HP", NULL, "Headphone Amp" }, + + /* Microphone Routes */ + { "Mic1 Amplifier", NULL, "MIC1"}, + + /* Microphone Routes */ + { "Mic2 Amplifier", NULL, "MIC2"}, + { "Left Mixer", "Mic2 Playback Switch", "Mic2 Amplifier" }, + { "Right Mixer", "Mic2 Playback Switch", "Mic2 Amplifier" }, + { "Left ADC Mixer", "Mic2 Capture Switch", "Mic2 Amplifier" }, + { "Right ADC Mixer", "Mic2 Capture Switch", "Mic2 Amplifier" }, + + /* Line-in Routes */ + { "Left Mixer", "Line In Playback Switch", "LINEIN" }, + { "Right Mixer", "Line In Playback Switch", "LINEIN" }, + { "Left ADC Mixer", "Line In Capture Switch", "LINEIN" }, + { "Right ADC Mixer", "Line In Capture Switch", "LINEIN" }, + + /* Line-out Routes */ + { "Line Out Source Playback Route", "Stereo", "Left Mixer" }, + { "Line Out Source Playback Route", "Stereo", "Right Mixer" }, + { "Line Out Source Playback Route", "Mono Differential", "Left Mixer" }, + { "Line Out Source Playback Route", "Mono Differential", + "Right Mixer" }, + { "LINEOUT", NULL, "Line Out Source Playback Route" }, +}; + +static const struct snd_soc_component_driver sun50i_codec_analog_cmpnt_drv = { + .controls = sun50i_a64_codec_controls, + .num_controls = ARRAY_SIZE(sun50i_a64_codec_controls), + .dapm_widgets = sun50i_a64_codec_widgets, + .num_dapm_widgets = ARRAY_SIZE(sun50i_a64_codec_widgets), + .dapm_routes = sun50i_a64_codec_routes, + .num_dapm_routes = ARRAY_SIZE(sun50i_a64_codec_routes), +}; + +static const struct of_device_id sun50i_codec_analog_of_match[] = { + { + .compatible = "allwinner,sun50i-a64-codec-analog", + }, + {} +}; +MODULE_DEVICE_TABLE(of, sun50i_codec_analog_of_match); + +static int sun50i_codec_analog_probe(struct platform_device *pdev) +{ + struct resource *res; + struct regmap *regmap; + void __iomem *base; + + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + base = devm_ioremap_resource(&pdev->dev, res); + if (IS_ERR(base)) { + dev_err(&pdev->dev, "Failed to map the registers\n"); + return PTR_ERR(base); + } + + regmap = sun8i_adda_pr_regmap_init(&pdev->dev, base); + if (IS_ERR(regmap)) { + dev_err(&pdev->dev, "Failed to create regmap\n"); + return PTR_ERR(regmap); + } + + return devm_snd_soc_register_component(&pdev->dev, + &sun50i_codec_analog_cmpnt_drv, + NULL, 0); +} + +static struct platform_driver sun50i_codec_analog_driver = { + .driver = { + .name = "sun50i-codec-analog", + .of_match_table = sun50i_codec_analog_of_match, + }, + .probe = sun50i_codec_analog_probe, +}; +module_platform_driver(sun50i_codec_analog_driver); + +MODULE_DESCRIPTION("Allwinner internal codec analog controls driver for A64"); +MODULE_AUTHOR("Vasily Khoruzhick "); +MODULE_LICENSE("GPL"); +MODULE_ALIAS("platform:sun50i-codec-analog"); From 7e95aac96b554193760aaeb64e263da58127bf27 Mon Sep 17 00:00:00 2001 From: Vasily Khoruzhick Date: Wed, 17 Oct 2018 00:38:10 -0700 Subject: [PATCH 276/299] ASoC: sunxi: allow the sun8i-codec driver to be built on ARM64 Allwinner A64 uses the same digital codec part as in A33, so we need to build this driver on ARM64 as well. Signed-off-by: Vasily Khoruzhick Acked-by: Maxime Ripard Signed-off-by: Mark Brown --- sound/soc/sunxi/Kconfig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sound/soc/sunxi/Kconfig b/sound/soc/sunxi/Kconfig index 8a055ca1819a..66aad0d3f9c7 100644 --- a/sound/soc/sunxi/Kconfig +++ b/sound/soc/sunxi/Kconfig @@ -12,7 +12,7 @@ config SND_SUN4I_CODEC config SND_SUN8I_CODEC tristate "Allwinner SUN8I audio codec" depends on OF - depends on MACH_SUN8I || COMPILE_TEST + depends on MACH_SUN8I || (ARM64 && ARCH_SUNXI) || COMPILE_TEST select REGMAP_MMIO help This option enables the digital part of the internal audio codec for From a85227da2dcc291b762c8482a505bc7d0d2d4b07 Mon Sep 17 00:00:00 2001 From: Marcel Ziswiler Date: Tue, 16 Oct 2018 12:47:29 +0200 Subject: [PATCH 277/299] ASoC: tegra_sgtl5000: fix device_node refcounting Similar to the following: commit 4321723648b0 ("ASoC: tegra_alc5632: fix device_node refcounting") commit 7c5dfd549617 ("ASoC: tegra: fix device_node refcounting") Signed-off-by: Marcel Ziswiler Acked-by: Jon Hunter Signed-off-by: Mark Brown --- sound/soc/tegra/tegra_sgtl5000.c | 17 +++++++++++++++-- 1 file changed, 15 insertions(+), 2 deletions(-) diff --git a/sound/soc/tegra/tegra_sgtl5000.c b/sound/soc/tegra/tegra_sgtl5000.c index 45a4aa9d2a47..901457da25ec 100644 --- a/sound/soc/tegra/tegra_sgtl5000.c +++ b/sound/soc/tegra/tegra_sgtl5000.c @@ -149,14 +149,14 @@ static int tegra_sgtl5000_driver_probe(struct platform_device *pdev) dev_err(&pdev->dev, "Property 'nvidia,i2s-controller' missing/invalid\n"); ret = -EINVAL; - goto err; + goto err_put_codec_of_node; } tegra_sgtl5000_dai.platform_of_node = tegra_sgtl5000_dai.cpu_of_node; ret = tegra_asoc_utils_init(&machine->util_data, &pdev->dev); if (ret) - goto err; + goto err_put_cpu_of_node; ret = snd_soc_register_card(card); if (ret) { @@ -169,6 +169,13 @@ static int tegra_sgtl5000_driver_probe(struct platform_device *pdev) err_fini_utils: tegra_asoc_utils_fini(&machine->util_data); +err_put_cpu_of_node: + of_node_put(tegra_sgtl5000_dai.cpu_of_node); + tegra_sgtl5000_dai.cpu_of_node = NULL; + tegra_sgtl5000_dai.platform_of_node = NULL; +err_put_codec_of_node: + of_node_put(tegra_sgtl5000_dai.codec_of_node); + tegra_sgtl5000_dai.codec_of_node = NULL; err: return ret; } @@ -183,6 +190,12 @@ static int tegra_sgtl5000_driver_remove(struct platform_device *pdev) tegra_asoc_utils_fini(&machine->util_data); + of_node_put(tegra_sgtl5000_dai.cpu_of_node); + tegra_sgtl5000_dai.cpu_of_node = NULL; + tegra_sgtl5000_dai.platform_of_node = NULL; + of_node_put(tegra_sgtl5000_dai.codec_of_node); + tegra_sgtl5000_dai.codec_of_node = NULL; + return ret; } From 1e3cb6c321be2e5295dcaa94c2bf42a43a47a067 Mon Sep 17 00:00:00 2001 From: David Lin Date: Fri, 28 Sep 2018 11:10:04 +0800 Subject: [PATCH 278/299] ASoC: nau8822: new codec driver Add driver for NAU88C22. Signed-off-by: David Lin Signed-off-by: Mark Brown --- .../devicetree/bindings/sound/nau8822.txt | 16 + sound/soc/codecs/Kconfig | 5 + sound/soc/codecs/Makefile | 2 + sound/soc/codecs/nau8822.c | 1136 +++++++++++++++++ sound/soc/codecs/nau8822.h | 204 +++ 5 files changed, 1363 insertions(+) create mode 100644 Documentation/devicetree/bindings/sound/nau8822.txt create mode 100644 sound/soc/codecs/nau8822.c create mode 100644 sound/soc/codecs/nau8822.h diff --git a/Documentation/devicetree/bindings/sound/nau8822.txt b/Documentation/devicetree/bindings/sound/nau8822.txt new file mode 100644 index 000000000000..a471d162d4e5 --- /dev/null +++ b/Documentation/devicetree/bindings/sound/nau8822.txt @@ -0,0 +1,16 @@ +NAU8822 audio CODEC + +This device supports I2C only. + +Required properties: + + - compatible : "nuvoton,nau8822" + + - reg : the I2C address of the device. + +Example: + +codec: nau8822@1a { + compatible = "nuvoton,nau8822"; + reg = <0x1a>; +}; diff --git a/sound/soc/codecs/Kconfig b/sound/soc/codecs/Kconfig index 774d38310875..9cc4f1848c9b 100644 --- a/sound/soc/codecs/Kconfig +++ b/sound/soc/codecs/Kconfig @@ -110,6 +110,7 @@ config SND_SOC_ALL_CODECS select SND_SOC_MT6351 if MTK_PMIC_WRAP select SND_SOC_NAU8540 if I2C select SND_SOC_NAU8810 if I2C + select SND_SOC_NAU8822 if I2C select SND_SOC_NAU8824 if I2C select SND_SOC_NAU8825 if I2C select SND_SOC_HDMI_CODEC @@ -1326,6 +1327,10 @@ config SND_SOC_NAU8810 tristate "Nuvoton Technology Corporation NAU88C10 CODEC" depends on I2C +config SND_SOC_NAU8822 + tristate "Nuvoton Technology Corporation NAU88C22 CODEC" + depends on I2C + config SND_SOC_NAU8824 tristate "Nuvoton Technology Corporation NAU88L24 CODEC" depends on I2C diff --git a/sound/soc/codecs/Makefile b/sound/soc/codecs/Makefile index 3d694c26192c..8ffab8c8dbfa 100644 --- a/sound/soc/codecs/Makefile +++ b/sound/soc/codecs/Makefile @@ -107,6 +107,7 @@ snd-soc-msm8916-digital-objs := msm8916-wcd-digital.o snd-soc-mt6351-objs := mt6351.o snd-soc-nau8540-objs := nau8540.o snd-soc-nau8810-objs := nau8810.o +snd-soc-nau8822-objs := nau8822.o snd-soc-nau8824-objs := nau8824.o snd-soc-nau8825-objs := nau8825.o snd-soc-hdmi-codec-objs := hdmi-codec.o @@ -371,6 +372,7 @@ obj-$(CONFIG_SND_SOC_MSM8916_WCD_DIGITAL) +=snd-soc-msm8916-digital.o obj-$(CONFIG_SND_SOC_MT6351) += snd-soc-mt6351.o obj-$(CONFIG_SND_SOC_NAU8540) += snd-soc-nau8540.o obj-$(CONFIG_SND_SOC_NAU8810) += snd-soc-nau8810.o +obj-$(CONFIG_SND_SOC_NAU8822) += snd-soc-nau8822.o obj-$(CONFIG_SND_SOC_NAU8824) += snd-soc-nau8824.o obj-$(CONFIG_SND_SOC_NAU8825) += snd-soc-nau8825.o obj-$(CONFIG_SND_SOC_HDMI_CODEC) += snd-soc-hdmi-codec.o diff --git a/sound/soc/codecs/nau8822.c b/sound/soc/codecs/nau8822.c new file mode 100644 index 000000000000..622ce947f134 --- /dev/null +++ b/sound/soc/codecs/nau8822.c @@ -0,0 +1,1136 @@ +/* + * nau8822.c -- NAU8822 ALSA Soc Audio Codec driver + * + * Copyright 2017 Nuvoton Technology Corp. + * + * Author: David Lin + * Co-author: John Hsu + * Co-author: Seven Li + * + * Based on WM8974.c + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "nau8822.h" + +#define NAU_PLL_FREQ_MAX 100000000 +#define NAU_PLL_FREQ_MIN 90000000 +#define NAU_PLL_REF_MAX 33000000 +#define NAU_PLL_REF_MIN 8000000 +#define NAU_PLL_OPTOP_MIN 6 + +static const int nau8822_mclk_scaler[] = { 10, 15, 20, 30, 40, 60, 80, 120 }; + +static const struct reg_default nau8822_reg_defaults[] = { + { NAU8822_REG_POWER_MANAGEMENT_1, 0x0000 }, + { NAU8822_REG_POWER_MANAGEMENT_2, 0x0000 }, + { NAU8822_REG_POWER_MANAGEMENT_3, 0x0000 }, + { NAU8822_REG_AUDIO_INTERFACE, 0x0050 }, + { NAU8822_REG_COMPANDING_CONTROL, 0x0000 }, + { NAU8822_REG_CLOCKING, 0x0140 }, + { NAU8822_REG_ADDITIONAL_CONTROL, 0x0000 }, + { NAU8822_REG_GPIO_CONTROL, 0x0000 }, + { NAU8822_REG_JACK_DETECT_CONTROL_1, 0x0000 }, + { NAU8822_REG_DAC_CONTROL, 0x0000 }, + { NAU8822_REG_LEFT_DAC_DIGITAL_VOLUME, 0x00ff }, + { NAU8822_REG_RIGHT_DAC_DIGITAL_VOLUME, 0x00ff }, + { NAU8822_REG_JACK_DETECT_CONTROL_2, 0x0000 }, + { NAU8822_REG_ADC_CONTROL, 0x0100 }, + { NAU8822_REG_LEFT_ADC_DIGITAL_VOLUME, 0x00ff }, + { NAU8822_REG_RIGHT_ADC_DIGITAL_VOLUME, 0x00ff }, + { NAU8822_REG_EQ1, 0x012c }, + { NAU8822_REG_EQ2, 0x002c }, + { NAU8822_REG_EQ3, 0x002c }, + { NAU8822_REG_EQ4, 0x002c }, + { NAU8822_REG_EQ5, 0x002c }, + { NAU8822_REG_DAC_LIMITER_1, 0x0032 }, + { NAU8822_REG_DAC_LIMITER_2, 0x0000 }, + { NAU8822_REG_NOTCH_FILTER_1, 0x0000 }, + { NAU8822_REG_NOTCH_FILTER_2, 0x0000 }, + { NAU8822_REG_NOTCH_FILTER_3, 0x0000 }, + { NAU8822_REG_NOTCH_FILTER_4, 0x0000 }, + { NAU8822_REG_ALC_CONTROL_1, 0x0038 }, + { NAU8822_REG_ALC_CONTROL_2, 0x000b }, + { NAU8822_REG_ALC_CONTROL_3, 0x0032 }, + { NAU8822_REG_NOISE_GATE, 0x0010 }, + { NAU8822_REG_PLL_N, 0x0008 }, + { NAU8822_REG_PLL_K1, 0x000c }, + { NAU8822_REG_PLL_K2, 0x0093 }, + { NAU8822_REG_PLL_K3, 0x00e9 }, + { NAU8822_REG_3D_CONTROL, 0x0000 }, + { NAU8822_REG_RIGHT_SPEAKER_CONTROL, 0x0000 }, + { NAU8822_REG_INPUT_CONTROL, 0x0033 }, + { NAU8822_REG_LEFT_INP_PGA_CONTROL, 0x0010 }, + { NAU8822_REG_RIGHT_INP_PGA_CONTROL, 0x0010 }, + { NAU8822_REG_LEFT_ADC_BOOST_CONTROL, 0x0100 }, + { NAU8822_REG_RIGHT_ADC_BOOST_CONTROL, 0x0100 }, + { NAU8822_REG_OUTPUT_CONTROL, 0x0002 }, + { NAU8822_REG_LEFT_MIXER_CONTROL, 0x0001 }, + { NAU8822_REG_RIGHT_MIXER_CONTROL, 0x0001 }, + { NAU8822_REG_LHP_VOLUME, 0x0039 }, + { NAU8822_REG_RHP_VOLUME, 0x0039 }, + { NAU8822_REG_LSPKOUT_VOLUME, 0x0039 }, + { NAU8822_REG_RSPKOUT_VOLUME, 0x0039 }, + { NAU8822_REG_AUX2_MIXER, 0x0001 }, + { NAU8822_REG_AUX1_MIXER, 0x0001 }, + { NAU8822_REG_POWER_MANAGEMENT_4, 0x0000 }, + { NAU8822_REG_LEFT_TIME_SLOT, 0x0000 }, + { NAU8822_REG_MISC, 0x0020 }, + { NAU8822_REG_RIGHT_TIME_SLOT, 0x0000 }, + { NAU8822_REG_DEVICE_REVISION, 0x007f }, + { NAU8822_REG_DEVICE_ID, 0x001a }, + { NAU8822_REG_DAC_DITHER, 0x0114 }, + { NAU8822_REG_ALC_ENHANCE_1, 0x0000 }, + { NAU8822_REG_ALC_ENHANCE_2, 0x0000 }, + { NAU8822_REG_192KHZ_SAMPLING, 0x0008 }, + { NAU8822_REG_MISC_CONTROL, 0x0000 }, + { NAU8822_REG_INPUT_TIEOFF, 0x0000 }, + { NAU8822_REG_POWER_REDUCTION, 0x0000 }, + { NAU8822_REG_AGC_PEAK2PEAK, 0x0000 }, + { NAU8822_REG_AGC_PEAK_DETECT, 0x0000 }, + { NAU8822_REG_AUTOMUTE_CONTROL, 0x0000 }, + { NAU8822_REG_OUTPUT_TIEOFF, 0x0000 }, +}; + +static bool nau8822_readable_reg(struct device *dev, unsigned int reg) +{ + switch (reg) { + case NAU8822_REG_RESET ... NAU8822_REG_JACK_DETECT_CONTROL_1: + case NAU8822_REG_DAC_CONTROL ... NAU8822_REG_LEFT_ADC_DIGITAL_VOLUME: + case NAU8822_REG_RIGHT_ADC_DIGITAL_VOLUME: + case NAU8822_REG_EQ1 ... NAU8822_REG_EQ5: + case NAU8822_REG_DAC_LIMITER_1 ... NAU8822_REG_DAC_LIMITER_2: + case NAU8822_REG_NOTCH_FILTER_1 ... NAU8822_REG_NOTCH_FILTER_4: + case NAU8822_REG_ALC_CONTROL_1 ...NAU8822_REG_PLL_K3: + case NAU8822_REG_3D_CONTROL: + case NAU8822_REG_RIGHT_SPEAKER_CONTROL: + case NAU8822_REG_INPUT_CONTROL ... NAU8822_REG_LEFT_ADC_BOOST_CONTROL: + case NAU8822_REG_RIGHT_ADC_BOOST_CONTROL ... NAU8822_REG_AUX1_MIXER: + case NAU8822_REG_POWER_MANAGEMENT_4 ... NAU8822_REG_DEVICE_ID: + case NAU8822_REG_DAC_DITHER: + case NAU8822_REG_ALC_ENHANCE_1 ... NAU8822_REG_MISC_CONTROL: + case NAU8822_REG_INPUT_TIEOFF ... NAU8822_REG_OUTPUT_TIEOFF: + return true; + default: + return false; + } +} + +static bool nau8822_writeable_reg(struct device *dev, unsigned int reg) +{ + switch (reg) { + case NAU8822_REG_RESET ... NAU8822_REG_JACK_DETECT_CONTROL_1: + case NAU8822_REG_DAC_CONTROL ... NAU8822_REG_LEFT_ADC_DIGITAL_VOLUME: + case NAU8822_REG_RIGHT_ADC_DIGITAL_VOLUME: + case NAU8822_REG_EQ1 ... NAU8822_REG_EQ5: + case NAU8822_REG_DAC_LIMITER_1 ... NAU8822_REG_DAC_LIMITER_2: + case NAU8822_REG_NOTCH_FILTER_1 ... NAU8822_REG_NOTCH_FILTER_4: + case NAU8822_REG_ALC_CONTROL_1 ...NAU8822_REG_PLL_K3: + case NAU8822_REG_3D_CONTROL: + case NAU8822_REG_RIGHT_SPEAKER_CONTROL: + case NAU8822_REG_INPUT_CONTROL ... NAU8822_REG_LEFT_ADC_BOOST_CONTROL: + case NAU8822_REG_RIGHT_ADC_BOOST_CONTROL ... NAU8822_REG_AUX1_MIXER: + case NAU8822_REG_POWER_MANAGEMENT_4 ... NAU8822_REG_DEVICE_ID: + case NAU8822_REG_DAC_DITHER: + case NAU8822_REG_ALC_ENHANCE_1 ... NAU8822_REG_MISC_CONTROL: + case NAU8822_REG_INPUT_TIEOFF ... NAU8822_REG_OUTPUT_TIEOFF: + return true; + default: + return false; + } +} + +static bool nau8822_volatile(struct device *dev, unsigned int reg) +{ + switch (reg) { + case NAU8822_REG_RESET: + case NAU8822_REG_DEVICE_REVISION: + case NAU8822_REG_DEVICE_ID: + case NAU8822_REG_AGC_PEAK2PEAK: + case NAU8822_REG_AGC_PEAK_DETECT: + case NAU8822_REG_AUTOMUTE_CONTROL: + return true; + default: + return false; + } +} + +/* The EQ parameters get function is to get the 5 band equalizer control. + * The regmap raw read can't work here because regmap doesn't provide + * value format for value width of 9 bits. Therefore, the driver reads data + * from cache and makes value format according to the endianness of + * bytes type control element. + */ +static int nau8822_eq_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_component *component = + snd_soc_kcontrol_component(kcontrol); + struct soc_bytes_ext *params = (void *)kcontrol->private_value; + int i, reg; + u16 reg_val, *val; + + val = (u16 *)ucontrol->value.bytes.data; + reg = NAU8822_REG_EQ1; + for (i = 0; i < params->max / sizeof(u16); i++) { + reg_val = snd_soc_component_read32(component, reg + i); + /* conversion of 16-bit integers between native CPU format + * and big endian format + */ + reg_val = cpu_to_be16(reg_val); + memcpy(val + i, ®_val, sizeof(reg_val)); + } + + return 0; +} + +/* The EQ parameters put function is to make configuration of 5 band equalizer + * control. These configuration includes central frequency, equalizer gain, + * cut-off frequency, bandwidth control, and equalizer path. + * The regmap raw write can't work here because regmap doesn't provide + * register and value format for register with address 7 bits and value 9 bits. + * Therefore, the driver makes value format according to the endianness of + * bytes type control element and writes data to codec. + */ +static int nau8822_eq_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_component *component = + snd_soc_kcontrol_component(kcontrol); + struct soc_bytes_ext *params = (void *)kcontrol->private_value; + void *data; + u16 *val, value; + int i, reg, ret; + + data = kmemdup(ucontrol->value.bytes.data, + params->max, GFP_KERNEL | GFP_DMA); + if (!data) + return -ENOMEM; + + val = (u16 *)data; + reg = NAU8822_REG_EQ1; + for (i = 0; i < params->max / sizeof(u16); i++) { + /* conversion of 16-bit integers between native CPU format + * and big endian format + */ + value = be16_to_cpu(*(val + i)); + ret = snd_soc_component_write(component, reg + i, value); + if (ret) { + dev_err(component->dev, + "EQ configuration fail, register: %x ret: %d\n", + reg + i, ret); + kfree(data); + return ret; + } + } + kfree(data); + + return 0; +} + +static const char * const nau8822_companding[] = { + "Off", "NC", "u-law", "A-law"}; + +static const struct soc_enum nau8822_companding_adc_enum = + SOC_ENUM_SINGLE(NAU8822_REG_COMPANDING_CONTROL, NAU8822_ADCCM_SFT, + ARRAY_SIZE(nau8822_companding), nau8822_companding); + +static const struct soc_enum nau8822_companding_dac_enum = + SOC_ENUM_SINGLE(NAU8822_REG_COMPANDING_CONTROL, NAU8822_DACCM_SFT, + ARRAY_SIZE(nau8822_companding), nau8822_companding); + +static const char * const nau8822_eqmode[] = {"Capture", "Playback"}; + +static const struct soc_enum nau8822_eqmode_enum = + SOC_ENUM_SINGLE(NAU8822_REG_EQ1, NAU8822_EQM_SFT, + ARRAY_SIZE(nau8822_eqmode), nau8822_eqmode); + +static const char * const nau8822_alc1[] = {"Off", "Right", "Left", "Both"}; +static const char * const nau8822_alc3[] = {"Normal", "Limiter"}; + +static const struct soc_enum nau8822_alc_enable_enum = + SOC_ENUM_SINGLE(NAU8822_REG_ALC_CONTROL_1, NAU8822_ALCEN_SFT, + ARRAY_SIZE(nau8822_alc1), nau8822_alc1); + +static const struct soc_enum nau8822_alc_mode_enum = + SOC_ENUM_SINGLE(NAU8822_REG_ALC_CONTROL_3, NAU8822_ALCM_SFT, + ARRAY_SIZE(nau8822_alc3), nau8822_alc3); + +static const DECLARE_TLV_DB_SCALE(digital_tlv, -12750, 50, 1); +static const DECLARE_TLV_DB_SCALE(inpga_tlv, -1200, 75, 0); +static const DECLARE_TLV_DB_SCALE(spk_tlv, -5700, 100, 0); +static const DECLARE_TLV_DB_SCALE(pga_boost_tlv, 0, 2000, 0); +static const DECLARE_TLV_DB_SCALE(boost_tlv, -1500, 300, 1); +static const DECLARE_TLV_DB_SCALE(limiter_tlv, 0, 100, 0); + +static const struct snd_kcontrol_new nau8822_snd_controls[] = { + SOC_ENUM("ADC Companding", nau8822_companding_adc_enum), + SOC_ENUM("DAC Companding", nau8822_companding_dac_enum), + + SOC_ENUM("EQ Function", nau8822_eqmode_enum), + SND_SOC_BYTES_EXT("EQ Parameters", 10, + nau8822_eq_get, nau8822_eq_put), + + SOC_DOUBLE("DAC Inversion Switch", + NAU8822_REG_DAC_CONTROL, 0, 1, 1, 0), + SOC_DOUBLE_R_TLV("PCM Volume", + NAU8822_REG_LEFT_DAC_DIGITAL_VOLUME, + NAU8822_REG_RIGHT_DAC_DIGITAL_VOLUME, 0, 255, 0, digital_tlv), + + SOC_SINGLE("High Pass Filter Switch", + NAU8822_REG_ADC_CONTROL, 8, 1, 0), + SOC_SINGLE("High Pass Cut Off", + NAU8822_REG_ADC_CONTROL, 4, 7, 0), + + SOC_DOUBLE("ADC Inversion Switch", + NAU8822_REG_ADC_CONTROL, 0, 1, 1, 0), + SOC_DOUBLE_R_TLV("ADC Volume", + NAU8822_REG_LEFT_ADC_DIGITAL_VOLUME, + NAU8822_REG_RIGHT_ADC_DIGITAL_VOLUME, 0, 255, 0, digital_tlv), + + SOC_SINGLE("DAC Limiter Switch", + NAU8822_REG_DAC_LIMITER_1, 8, 1, 0), + SOC_SINGLE("DAC Limiter Decay", + NAU8822_REG_DAC_LIMITER_1, 4, 15, 0), + SOC_SINGLE("DAC Limiter Attack", + NAU8822_REG_DAC_LIMITER_1, 0, 15, 0), + SOC_SINGLE("DAC Limiter Threshold", + NAU8822_REG_DAC_LIMITER_2, 4, 7, 0), + SOC_SINGLE_TLV("DAC Limiter Volume", + NAU8822_REG_DAC_LIMITER_2, 0, 12, 0, limiter_tlv), + + SOC_ENUM("ALC Mode", nau8822_alc_mode_enum), + SOC_ENUM("ALC Enable Switch", nau8822_alc_enable_enum), + SOC_SINGLE("ALC Min Gain", + NAU8822_REG_ALC_CONTROL_1, 0, 7, 0), + SOC_SINGLE("ALC Max Gain", + NAU8822_REG_ALC_CONTROL_1, 3, 7, 0), + SOC_SINGLE("ALC Hold", + NAU8822_REG_ALC_CONTROL_2, 4, 10, 0), + SOC_SINGLE("ALC Target", + NAU8822_REG_ALC_CONTROL_2, 0, 15, 0), + SOC_SINGLE("ALC Decay", + NAU8822_REG_ALC_CONTROL_3, 4, 10, 0), + SOC_SINGLE("ALC Attack", + NAU8822_REG_ALC_CONTROL_3, 0, 10, 0), + SOC_SINGLE("ALC Noise Gate Switch", + NAU8822_REG_NOISE_GATE, 3, 1, 0), + SOC_SINGLE("ALC Noise Gate Threshold", + NAU8822_REG_NOISE_GATE, 0, 7, 0), + + SOC_DOUBLE_R("PGA ZC Switch", + NAU8822_REG_LEFT_INP_PGA_CONTROL, + NAU8822_REG_RIGHT_INP_PGA_CONTROL, + 7, 1, 0), + SOC_DOUBLE_R_TLV("PGA Volume", + NAU8822_REG_LEFT_INP_PGA_CONTROL, + NAU8822_REG_RIGHT_INP_PGA_CONTROL, 0, 63, 0, inpga_tlv), + + SOC_DOUBLE_R("Headphone ZC Switch", + NAU8822_REG_LHP_VOLUME, + NAU8822_REG_RHP_VOLUME, 7, 1, 0), + SOC_DOUBLE_R("Headphone Playback Switch", + NAU8822_REG_LHP_VOLUME, + NAU8822_REG_RHP_VOLUME, 6, 1, 1), + SOC_DOUBLE_R_TLV("Headphone Volume", + NAU8822_REG_LHP_VOLUME, + NAU8822_REG_RHP_VOLUME, 0, 63, 0, spk_tlv), + + SOC_DOUBLE_R("Speaker ZC Switch", + NAU8822_REG_LSPKOUT_VOLUME, + NAU8822_REG_RSPKOUT_VOLUME, 7, 1, 0), + SOC_DOUBLE_R("Speaker Playback Switch", + NAU8822_REG_LSPKOUT_VOLUME, + NAU8822_REG_RSPKOUT_VOLUME, 6, 1, 1), + SOC_DOUBLE_R_TLV("Speaker Volume", + NAU8822_REG_LSPKOUT_VOLUME, + NAU8822_REG_RSPKOUT_VOLUME, 0, 63, 0, spk_tlv), + + SOC_DOUBLE_R("AUXOUT Playback Switch", + NAU8822_REG_AUX2_MIXER, + NAU8822_REG_AUX1_MIXER, 6, 1, 1), + + SOC_DOUBLE_R_TLV("PGA Boost Volume", + NAU8822_REG_LEFT_ADC_BOOST_CONTROL, + NAU8822_REG_RIGHT_ADC_BOOST_CONTROL, 8, 1, 0, pga_boost_tlv), + SOC_DOUBLE_R_TLV("L2/R2 Boost Volume", + NAU8822_REG_LEFT_ADC_BOOST_CONTROL, + NAU8822_REG_RIGHT_ADC_BOOST_CONTROL, 4, 7, 0, boost_tlv), + SOC_DOUBLE_R_TLV("Aux Boost Volume", + NAU8822_REG_LEFT_ADC_BOOST_CONTROL, + NAU8822_REG_RIGHT_ADC_BOOST_CONTROL, 0, 7, 0, boost_tlv), + + SOC_SINGLE("DAC 128x Oversampling Switch", + NAU8822_REG_DAC_CONTROL, 5, 1, 0), + SOC_SINGLE("ADC 128x Oversampling Switch", + NAU8822_REG_ADC_CONTROL, 5, 1, 0), +}; + +/* LMAIN and RMAIN Mixer */ +static const struct snd_kcontrol_new nau8822_left_out_mixer[] = { + SOC_DAPM_SINGLE("LINMIX Switch", + NAU8822_REG_LEFT_MIXER_CONTROL, 1, 1, 0), + SOC_DAPM_SINGLE("LAUX Switch", + NAU8822_REG_LEFT_MIXER_CONTROL, 5, 1, 0), + SOC_DAPM_SINGLE("LDAC Switch", + NAU8822_REG_LEFT_MIXER_CONTROL, 0, 1, 0), + SOC_DAPM_SINGLE("RDAC Switch", + NAU8822_REG_OUTPUT_CONTROL, 5, 1, 0), +}; + +static const struct snd_kcontrol_new nau8822_right_out_mixer[] = { + SOC_DAPM_SINGLE("RINMIX Switch", + NAU8822_REG_RIGHT_MIXER_CONTROL, 1, 1, 0), + SOC_DAPM_SINGLE("RAUX Switch", + NAU8822_REG_RIGHT_MIXER_CONTROL, 5, 1, 0), + SOC_DAPM_SINGLE("RDAC Switch", + NAU8822_REG_RIGHT_MIXER_CONTROL, 0, 1, 0), + SOC_DAPM_SINGLE("LDAC Switch", + NAU8822_REG_OUTPUT_CONTROL, 6, 1, 0), +}; + +/* AUX1 and AUX2 Mixer */ +static const struct snd_kcontrol_new nau8822_auxout1_mixer[] = { + SOC_DAPM_SINGLE("RDAC Switch", NAU8822_REG_AUX1_MIXER, 0, 1, 0), + SOC_DAPM_SINGLE("RMIX Switch", NAU8822_REG_AUX1_MIXER, 1, 1, 0), + SOC_DAPM_SINGLE("RINMIX Switch", NAU8822_REG_AUX1_MIXER, 2, 1, 0), + SOC_DAPM_SINGLE("LDAC Switch", NAU8822_REG_AUX1_MIXER, 3, 1, 0), + SOC_DAPM_SINGLE("LMIX Switch", NAU8822_REG_AUX1_MIXER, 4, 1, 0), +}; + +static const struct snd_kcontrol_new nau8822_auxout2_mixer[] = { + SOC_DAPM_SINGLE("LDAC Switch", NAU8822_REG_AUX2_MIXER, 0, 1, 0), + SOC_DAPM_SINGLE("LMIX Switch", NAU8822_REG_AUX2_MIXER, 1, 1, 0), + SOC_DAPM_SINGLE("LINMIX Switch", NAU8822_REG_AUX2_MIXER, 2, 1, 0), + SOC_DAPM_SINGLE("AUX1MIX Output Switch", + NAU8822_REG_AUX2_MIXER, 3, 1, 0), +}; + +/* Input PGA */ +static const struct snd_kcontrol_new nau8822_left_input_mixer[] = { + SOC_DAPM_SINGLE("L2 Switch", NAU8822_REG_INPUT_CONTROL, 2, 1, 0), + SOC_DAPM_SINGLE("MicN Switch", NAU8822_REG_INPUT_CONTROL, 1, 1, 0), + SOC_DAPM_SINGLE("MicP Switch", NAU8822_REG_INPUT_CONTROL, 0, 1, 0), +}; +static const struct snd_kcontrol_new nau8822_right_input_mixer[] = { + SOC_DAPM_SINGLE("R2 Switch", NAU8822_REG_INPUT_CONTROL, 6, 1, 0), + SOC_DAPM_SINGLE("MicN Switch", NAU8822_REG_INPUT_CONTROL, 5, 1, 0), + SOC_DAPM_SINGLE("MicP Switch", NAU8822_REG_INPUT_CONTROL, 4, 1, 0), +}; + +/* Loopback Switch */ +static const struct snd_kcontrol_new nau8822_loopback = + SOC_DAPM_SINGLE("Switch", NAU8822_REG_COMPANDING_CONTROL, + NAU8822_ADDAP_SFT, 1, 0); + +static int check_mclk_select_pll(struct snd_soc_dapm_widget *source, + struct snd_soc_dapm_widget *sink) +{ + struct snd_soc_component *component = + snd_soc_dapm_to_component(source->dapm); + unsigned int value; + + value = snd_soc_component_read32(component, NAU8822_REG_CLOCKING); + + return (value & NAU8822_CLKM_MASK); +} + +static const struct snd_soc_dapm_widget nau8822_dapm_widgets[] = { + SND_SOC_DAPM_DAC("Left DAC", "Left HiFi Playback", + NAU8822_REG_POWER_MANAGEMENT_3, 0, 0), + SND_SOC_DAPM_DAC("Right DAC", "Right HiFi Playback", + NAU8822_REG_POWER_MANAGEMENT_3, 1, 0), + SND_SOC_DAPM_ADC("Left ADC", "Left HiFi Capture", + NAU8822_REG_POWER_MANAGEMENT_2, 0, 0), + SND_SOC_DAPM_ADC("Right ADC", "Right HiFi Capture", + NAU8822_REG_POWER_MANAGEMENT_2, 1, 0), + + SOC_MIXER_ARRAY("Left Output Mixer", + NAU8822_REG_POWER_MANAGEMENT_3, 2, 0, nau8822_left_out_mixer), + SOC_MIXER_ARRAY("Right Output Mixer", + NAU8822_REG_POWER_MANAGEMENT_3, 3, 0, nau8822_right_out_mixer), + SOC_MIXER_ARRAY("AUX1 Output Mixer", + NAU8822_REG_POWER_MANAGEMENT_1, 7, 0, nau8822_auxout1_mixer), + SOC_MIXER_ARRAY("AUX2 Output Mixer", + NAU8822_REG_POWER_MANAGEMENT_1, 6, 0, nau8822_auxout2_mixer), + + SOC_MIXER_ARRAY("Left Input Mixer", + NAU8822_REG_POWER_MANAGEMENT_2, + 2, 0, nau8822_left_input_mixer), + SOC_MIXER_ARRAY("Right Input Mixer", + NAU8822_REG_POWER_MANAGEMENT_2, + 3, 0, nau8822_right_input_mixer), + + SND_SOC_DAPM_PGA("Left Boost Mixer", + NAU8822_REG_POWER_MANAGEMENT_2, 4, 0, NULL, 0), + SND_SOC_DAPM_PGA("Right Boost Mixer", + NAU8822_REG_POWER_MANAGEMENT_2, 5, 0, NULL, 0), + + SND_SOC_DAPM_PGA("Left Capture PGA", + NAU8822_REG_LEFT_INP_PGA_CONTROL, 6, 1, NULL, 0), + SND_SOC_DAPM_PGA("Right Capture PGA", + NAU8822_REG_RIGHT_INP_PGA_CONTROL, 6, 1, NULL, 0), + + SND_SOC_DAPM_PGA("Left Headphone Out", + NAU8822_REG_POWER_MANAGEMENT_2, 7, 0, NULL, 0), + SND_SOC_DAPM_PGA("Right Headphone Out", + NAU8822_REG_POWER_MANAGEMENT_2, 8, 0, NULL, 0), + + SND_SOC_DAPM_PGA("Left Speaker Out", + NAU8822_REG_POWER_MANAGEMENT_3, 6, 0, NULL, 0), + SND_SOC_DAPM_PGA("Right Speaker Out", + NAU8822_REG_POWER_MANAGEMENT_3, 5, 0, NULL, 0), + + SND_SOC_DAPM_PGA("AUX1 Out", + NAU8822_REG_POWER_MANAGEMENT_3, 8, 0, NULL, 0), + SND_SOC_DAPM_PGA("AUX2 Out", + NAU8822_REG_POWER_MANAGEMENT_3, 7, 0, NULL, 0), + + SND_SOC_DAPM_SUPPLY("Mic Bias", + NAU8822_REG_POWER_MANAGEMENT_1, 4, 0, NULL, 0), + SND_SOC_DAPM_SUPPLY("PLL", + NAU8822_REG_POWER_MANAGEMENT_1, 5, 0, NULL, 0), + + SND_SOC_DAPM_SWITCH("Digital Loopback", SND_SOC_NOPM, 0, 0, + &nau8822_loopback), + + SND_SOC_DAPM_INPUT("LMICN"), + SND_SOC_DAPM_INPUT("LMICP"), + SND_SOC_DAPM_INPUT("RMICN"), + SND_SOC_DAPM_INPUT("RMICP"), + SND_SOC_DAPM_INPUT("LAUX"), + SND_SOC_DAPM_INPUT("RAUX"), + SND_SOC_DAPM_INPUT("L2"), + SND_SOC_DAPM_INPUT("R2"), + SND_SOC_DAPM_OUTPUT("LHP"), + SND_SOC_DAPM_OUTPUT("RHP"), + SND_SOC_DAPM_OUTPUT("LSPK"), + SND_SOC_DAPM_OUTPUT("RSPK"), + SND_SOC_DAPM_OUTPUT("AUXOUT1"), + SND_SOC_DAPM_OUTPUT("AUXOUT2"), +}; + +static const struct snd_soc_dapm_route nau8822_dapm_routes[] = { + {"Right DAC", NULL, "PLL", check_mclk_select_pll}, + {"Left DAC", NULL, "PLL", check_mclk_select_pll}, + + /* LMAIN and RMAIN Mixer */ + {"Right Output Mixer", "LDAC Switch", "Left DAC"}, + {"Right Output Mixer", "RDAC Switch", "Right DAC"}, + {"Right Output Mixer", "RAUX Switch", "RAUX"}, + {"Right Output Mixer", "RINMIX Switch", "Right Boost Mixer"}, + + {"Left Output Mixer", "LDAC Switch", "Left DAC"}, + {"Left Output Mixer", "RDAC Switch", "Right DAC"}, + {"Left Output Mixer", "LAUX Switch", "LAUX"}, + {"Left Output Mixer", "LINMIX Switch", "Left Boost Mixer"}, + + /* AUX1 and AUX2 Mixer */ + {"AUX1 Output Mixer", "RDAC Switch", "Right DAC"}, + {"AUX1 Output Mixer", "RMIX Switch", "Right Output Mixer"}, + {"AUX1 Output Mixer", "RINMIX Switch", "Right Boost Mixer"}, + {"AUX1 Output Mixer", "LDAC Switch", "Left DAC"}, + {"AUX1 Output Mixer", "LMIX Switch", "Left Output Mixer"}, + + {"AUX2 Output Mixer", "LDAC Switch", "Left DAC"}, + {"AUX2 Output Mixer", "LMIX Switch", "Left Output Mixer"}, + {"AUX2 Output Mixer", "LINMIX Switch", "Left Boost Mixer"}, + {"AUX2 Output Mixer", "AUX1MIX Output Switch", "AUX1 Output Mixer"}, + + /* Outputs */ + {"Right Headphone Out", NULL, "Right Output Mixer"}, + {"RHP", NULL, "Right Headphone Out"}, + + {"Left Headphone Out", NULL, "Left Output Mixer"}, + {"LHP", NULL, "Left Headphone Out"}, + + {"Right Speaker Out", NULL, "Right Output Mixer"}, + {"RSPK", NULL, "Right Speaker Out"}, + + {"Left Speaker Out", NULL, "Left Output Mixer"}, + {"LSPK", NULL, "Left Speaker Out"}, + + {"AUX1 Out", NULL, "AUX1 Output Mixer"}, + {"AUX2 Out", NULL, "AUX2 Output Mixer"}, + {"AUXOUT1", NULL, "AUX1 Out"}, + {"AUXOUT2", NULL, "AUX2 Out"}, + + /* Boost Mixer */ + {"Right ADC", NULL, "PLL", check_mclk_select_pll}, + {"Left ADC", NULL, "PLL", check_mclk_select_pll}, + + {"Right ADC", NULL, "Right Boost Mixer"}, + + {"Right Boost Mixer", NULL, "RAUX"}, + {"Right Boost Mixer", NULL, "Right Capture PGA"}, + {"Right Boost Mixer", NULL, "R2"}, + + {"Left ADC", NULL, "Left Boost Mixer"}, + + {"Left Boost Mixer", NULL, "LAUX"}, + {"Left Boost Mixer", NULL, "Left Capture PGA"}, + {"Left Boost Mixer", NULL, "L2"}, + + /* Input PGA */ + {"Right Capture PGA", NULL, "Right Input Mixer"}, + {"Left Capture PGA", NULL, "Left Input Mixer"}, + + /* Enable Microphone Power */ + {"Right Capture PGA", NULL, "Mic Bias"}, + {"Left Capture PGA", NULL, "Mic Bias"}, + + {"Right Input Mixer", "R2 Switch", "R2"}, + {"Right Input Mixer", "MicN Switch", "RMICN"}, + {"Right Input Mixer", "MicP Switch", "RMICP"}, + + {"Left Input Mixer", "L2 Switch", "L2"}, + {"Left Input Mixer", "MicN Switch", "LMICN"}, + {"Left Input Mixer", "MicP Switch", "LMICP"}, + + /* Digital Loopback */ + {"Digital Loopback", "Switch", "Left ADC"}, + {"Digital Loopback", "Switch", "Right ADC"}, + {"Left DAC", NULL, "Digital Loopback"}, + {"Right DAC", NULL, "Digital Loopback"}, +}; + +static int nau8822_set_dai_sysclk(struct snd_soc_dai *dai, int clk_id, + unsigned int freq, int dir) +{ + struct snd_soc_component *component = dai->component; + struct nau8822 *nau8822 = snd_soc_component_get_drvdata(component); + + nau8822->div_id = clk_id; + nau8822->sysclk = freq; + dev_dbg(component->dev, "master sysclk %dHz, source %s\n", freq, + clk_id == NAU8822_CLK_PLL ? "PLL" : "MCLK"); + + return 0; +} + +static int nau8822_calc_pll(unsigned int pll_in, unsigned int fs, + struct nau8822_pll *pll_param) +{ + u64 f2, f2_max, pll_ratio; + int i, scal_sel; + + if (pll_in > NAU_PLL_REF_MAX || pll_in < NAU_PLL_REF_MIN) + return -EINVAL; + f2_max = 0; + scal_sel = ARRAY_SIZE(nau8822_mclk_scaler); + + for (i = 0; i < scal_sel; i++) { + f2 = 256 * fs * 4 * nau8822_mclk_scaler[i] / 10; + if (f2 > NAU_PLL_FREQ_MIN && f2 < NAU_PLL_FREQ_MAX && + f2_max < f2) { + f2_max = f2; + scal_sel = i; + } + } + + if (ARRAY_SIZE(nau8822_mclk_scaler) == scal_sel) + return -EINVAL; + pll_param->mclk_scaler = scal_sel; + f2 = f2_max; + + /* Calculate the PLL 4-bit integer input and the PLL 24-bit fractional + * input; round up the 24+4bit. + */ + pll_ratio = div_u64(f2 << 28, pll_in); + pll_param->pre_factor = 0; + if (((pll_ratio >> 28) & 0xF) < NAU_PLL_OPTOP_MIN) { + pll_ratio <<= 1; + pll_param->pre_factor = 1; + } + pll_param->pll_int = (pll_ratio >> 28) & 0xF; + pll_param->pll_frac = ((pll_ratio & 0xFFFFFFF) >> 4); + + return 0; +} + +static int nau8822_config_clkdiv(struct snd_soc_dai *dai, int div, int rate) +{ + struct snd_soc_component *component = dai->component; + struct nau8822 *nau8822 = snd_soc_component_get_drvdata(component); + struct nau8822_pll *pll = &nau8822->pll; + int i, sclk, imclk; + + switch (nau8822->div_id) { + case NAU8822_CLK_MCLK: + /* Configure the master clock prescaler div to make system + * clock to approximate the internal master clock (IMCLK); + * and large or equal to IMCLK. + */ + div = 0; + imclk = rate * 256; + for (i = 1; i < ARRAY_SIZE(nau8822_mclk_scaler); i++) { + sclk = (nau8822->sysclk * 10) / nau8822_mclk_scaler[i]; + if (sclk < imclk) + break; + div = i; + } + dev_dbg(component->dev, "master clock prescaler %x for fs %d\n", + div, rate); + + /* master clock from MCLK and disable PLL */ + snd_soc_component_update_bits(component, + NAU8822_REG_CLOCKING, NAU8822_MCLKSEL_MASK, + (div << NAU8822_MCLKSEL_SFT)); + snd_soc_component_update_bits(component, + NAU8822_REG_CLOCKING, NAU8822_CLKM_MASK, + NAU8822_CLKM_MCLK); + break; + + case NAU8822_CLK_PLL: + /* master clock from PLL and enable PLL */ + if (pll->mclk_scaler != div) { + dev_err(component->dev, + "master clock prescaler not meet PLL parameters\n"); + return -EINVAL; + } + snd_soc_component_update_bits(component, + NAU8822_REG_CLOCKING, NAU8822_MCLKSEL_MASK, + (div << NAU8822_MCLKSEL_SFT)); + snd_soc_component_update_bits(component, + NAU8822_REG_CLOCKING, NAU8822_CLKM_MASK, + NAU8822_CLKM_PLL); + break; + + default: + return -EINVAL; + } + + return 0; +} + +static int nau8822_set_pll(struct snd_soc_dai *dai, int pll_id, int source, + unsigned int freq_in, unsigned int freq_out) +{ + struct snd_soc_component *component = dai->component; + struct nau8822 *nau8822 = snd_soc_component_get_drvdata(component); + struct nau8822_pll *pll_param = &nau8822->pll; + int ret, fs; + + fs = freq_out / 256; + + ret = nau8822_calc_pll(freq_in, fs, pll_param); + if (ret < 0) { + dev_err(component->dev, "Unsupported input clock %d\n", + freq_in); + return ret; + } + + dev_info(component->dev, + "pll_int=%x pll_frac=%x mclk_scaler=%x pre_factor=%x\n", + pll_param->pll_int, pll_param->pll_frac, + pll_param->mclk_scaler, pll_param->pre_factor); + + snd_soc_component_update_bits(component, + NAU8822_REG_PLL_N, NAU8822_PLLMCLK_DIV2 | NAU8822_PLLN_MASK, + (pll_param->pre_factor ? NAU8822_PLLMCLK_DIV2 : 0) | + pll_param->pll_int); + snd_soc_component_write(component, + NAU8822_REG_PLL_K1, (pll_param->pll_frac >> NAU8822_PLLK1_SFT) & + NAU8822_PLLK1_MASK); + snd_soc_component_write(component, + NAU8822_REG_PLL_K2, (pll_param->pll_frac >> NAU8822_PLLK2_SFT) & + NAU8822_PLLK2_MASK); + snd_soc_component_write(component, + NAU8822_REG_PLL_K3, pll_param->pll_frac & NAU8822_PLLK3_MASK); + snd_soc_component_update_bits(component, + NAU8822_REG_CLOCKING, NAU8822_MCLKSEL_MASK, + pll_param->mclk_scaler << NAU8822_MCLKSEL_SFT); + snd_soc_component_update_bits(component, + NAU8822_REG_CLOCKING, NAU8822_CLKM_MASK, NAU8822_CLKM_PLL); + + return 0; +} + +static int nau8822_set_dai_fmt(struct snd_soc_dai *dai, unsigned int fmt) +{ + struct snd_soc_component *component = dai->component; + u16 ctrl1_val = 0, ctrl2_val = 0; + + dev_dbg(component->dev, "%s\n", __func__); + + switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { + case SND_SOC_DAIFMT_CBM_CFM: + ctrl2_val |= 1; + break; + case SND_SOC_DAIFMT_CBS_CFS: + ctrl2_val &= ~1; + break; + default: + return -EINVAL; + } + + switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) { + case SND_SOC_DAIFMT_I2S: + ctrl1_val |= 0x10; + break; + case SND_SOC_DAIFMT_RIGHT_J: + break; + case SND_SOC_DAIFMT_LEFT_J: + ctrl1_val |= 0x8; + break; + case SND_SOC_DAIFMT_DSP_A: + ctrl1_val |= 0x18; + break; + default: + return -EINVAL; + } + + switch (fmt & SND_SOC_DAIFMT_INV_MASK) { + case SND_SOC_DAIFMT_NB_NF: + break; + case SND_SOC_DAIFMT_IB_IF: + ctrl1_val |= 0x180; + break; + case SND_SOC_DAIFMT_IB_NF: + ctrl1_val |= 0x100; + break; + case SND_SOC_DAIFMT_NB_IF: + ctrl1_val |= 0x80; + break; + default: + return -EINVAL; + } + + snd_soc_component_update_bits(component, + NAU8822_REG_AUDIO_INTERFACE, + NAU8822_AIFMT_MASK | NAU8822_LRP_MASK | NAU8822_BCLKP_MASK, + ctrl1_val); + snd_soc_component_update_bits(component, + NAU8822_REG_CLOCKING, NAU8822_CLKIOEN_MASK, ctrl2_val); + + return 0; +} + +static int nau8822_hw_params(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params, + struct snd_soc_dai *dai) +{ + struct snd_soc_component *component = dai->component; + struct nau8822 *nau8822 = snd_soc_component_get_drvdata(component); + int val_len = 0, val_rate = 0; + + switch (params_format(params)) { + case SNDRV_PCM_FORMAT_S16_LE: + break; + case SNDRV_PCM_FORMAT_S20_3LE: + val_len |= NAU8822_WLEN_20; + break; + case SNDRV_PCM_FORMAT_S24_LE: + val_len |= NAU8822_WLEN_24; + break; + case SNDRV_PCM_FORMAT_S32_LE: + val_len |= NAU8822_WLEN_32; + break; + default: + return -EINVAL; + } + + switch (params_rate(params)) { + case 8000: + val_rate |= NAU8822_SMPLR_8K; + break; + case 11025: + val_rate |= NAU8822_SMPLR_12K; + break; + case 16000: + val_rate |= NAU8822_SMPLR_16K; + break; + case 22050: + val_rate |= NAU8822_SMPLR_24K; + break; + case 32000: + val_rate |= NAU8822_SMPLR_32K; + break; + case 44100: + case 48000: + break; + default: + return -EINVAL; + } + + snd_soc_component_update_bits(component, + NAU8822_REG_AUDIO_INTERFACE, NAU8822_WLEN_MASK, val_len); + snd_soc_component_update_bits(component, + NAU8822_REG_ADDITIONAL_CONTROL, NAU8822_SMPLR_MASK, val_rate); + + /* If the master clock is from MCLK, provide the runtime FS for driver + * to get the master clock prescaler configuration. + */ + if (nau8822->div_id == NAU8822_CLK_MCLK) + nau8822_config_clkdiv(dai, 0, params_rate(params)); + + return 0; +} + +static int nau8822_mute(struct snd_soc_dai *dai, int mute) +{ + struct snd_soc_component *component = dai->component; + + dev_dbg(component->dev, "%s: %d\n", __func__, mute); + + if (mute) + snd_soc_component_update_bits(component, + NAU8822_REG_DAC_CONTROL, 0x40, 0x40); + else + snd_soc_component_update_bits(component, + NAU8822_REG_DAC_CONTROL, 0x40, 0); + + return 0; +} + +static int nau8822_set_bias_level(struct snd_soc_component *component, + enum snd_soc_bias_level level) +{ + switch (level) { + case SND_SOC_BIAS_ON: + case SND_SOC_BIAS_PREPARE: + snd_soc_component_update_bits(component, + NAU8822_REG_POWER_MANAGEMENT_1, + NAU8822_REFIMP_MASK, NAU8822_REFIMP_80K); + break; + + case SND_SOC_BIAS_STANDBY: + snd_soc_component_update_bits(component, + NAU8822_REG_POWER_MANAGEMENT_1, + NAU8822_IOBUF_EN | NAU8822_ABIAS_EN, + NAU8822_IOBUF_EN | NAU8822_ABIAS_EN); + + if (snd_soc_component_get_bias_level(component) == + SND_SOC_BIAS_OFF) { + snd_soc_component_update_bits(component, + NAU8822_REG_POWER_MANAGEMENT_1, + NAU8822_REFIMP_MASK, NAU8822_REFIMP_3K); + mdelay(100); + } + snd_soc_component_update_bits(component, + NAU8822_REG_POWER_MANAGEMENT_1, + NAU8822_REFIMP_MASK, NAU8822_REFIMP_300K); + break; + + case SND_SOC_BIAS_OFF: + snd_soc_component_write(component, + NAU8822_REG_POWER_MANAGEMENT_1, 0); + snd_soc_component_write(component, + NAU8822_REG_POWER_MANAGEMENT_2, 0); + snd_soc_component_write(component, + NAU8822_REG_POWER_MANAGEMENT_3, 0); + break; + } + + dev_dbg(component->dev, "%s: %d\n", __func__, level); + + return 0; +} + +#define NAU8822_RATES (SNDRV_PCM_RATE_8000_48000) + +#define NAU8822_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE | \ + SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S32_LE) + +static const struct snd_soc_dai_ops nau8822_dai_ops = { + .hw_params = nau8822_hw_params, + .digital_mute = nau8822_mute, + .set_fmt = nau8822_set_dai_fmt, + .set_sysclk = nau8822_set_dai_sysclk, + .set_pll = nau8822_set_pll, +}; + +static struct snd_soc_dai_driver nau8822_dai = { + .name = "nau8822-hifi", + .playback = { + .stream_name = "Playback", + .channels_min = 1, + .channels_max = 2, + .rates = NAU8822_RATES, + .formats = NAU8822_FORMATS, + }, + .capture = { + .stream_name = "Capture", + .channels_min = 1, + .channels_max = 2, + .rates = NAU8822_RATES, + .formats = NAU8822_FORMATS, + }, + .ops = &nau8822_dai_ops, + .symmetric_rates = 1, +}; + +static int nau8822_suspend(struct snd_soc_component *component) +{ + struct nau8822 *nau8822 = snd_soc_component_get_drvdata(component); + + snd_soc_component_force_bias_level(component, SND_SOC_BIAS_OFF); + + regcache_mark_dirty(nau8822->regmap); + + return 0; +} + +static int nau8822_resume(struct snd_soc_component *component) +{ + struct nau8822 *nau8822 = snd_soc_component_get_drvdata(component); + + regcache_sync(nau8822->regmap); + + snd_soc_component_force_bias_level(component, SND_SOC_BIAS_STANDBY); + + return 0; +} + +/* + * These registers contain an "update" bit - bit 8. This means, for example, + * that one can write new DAC digital volume for both channels, but only when + * the update bit is set, will also the volume be updated - simultaneously for + * both channels. + */ +static const int update_reg[] = { + NAU8822_REG_LEFT_DAC_DIGITAL_VOLUME, + NAU8822_REG_RIGHT_DAC_DIGITAL_VOLUME, + NAU8822_REG_LEFT_ADC_DIGITAL_VOLUME, + NAU8822_REG_RIGHT_ADC_DIGITAL_VOLUME, + NAU8822_REG_LEFT_INP_PGA_CONTROL, + NAU8822_REG_RIGHT_INP_PGA_CONTROL, + NAU8822_REG_LHP_VOLUME, + NAU8822_REG_RHP_VOLUME, + NAU8822_REG_LSPKOUT_VOLUME, + NAU8822_REG_RSPKOUT_VOLUME, +}; + +static int nau8822_probe(struct snd_soc_component *component) +{ + int i; + + /* + * Set the update bit in all registers, that have one. This way all + * writes to those registers will also cause the update bit to be + * written. + */ + for (i = 0; i < ARRAY_SIZE(update_reg); i++) + snd_soc_component_update_bits(component, + update_reg[i], 0x100, 0x100); + + return 0; +} + +static const struct snd_soc_component_driver soc_component_dev_nau8822 = { + .probe = nau8822_probe, + .suspend = nau8822_suspend, + .resume = nau8822_resume, + .set_bias_level = nau8822_set_bias_level, + .controls = nau8822_snd_controls, + .num_controls = ARRAY_SIZE(nau8822_snd_controls), + .dapm_widgets = nau8822_dapm_widgets, + .num_dapm_widgets = ARRAY_SIZE(nau8822_dapm_widgets), + .dapm_routes = nau8822_dapm_routes, + .num_dapm_routes = ARRAY_SIZE(nau8822_dapm_routes), + .idle_bias_on = 1, + .use_pmdown_time = 1, + .endianness = 1, + .non_legacy_dai_naming = 1, +}; + +static const struct regmap_config nau8822_regmap_config = { + .reg_bits = 7, + .val_bits = 9, + + .max_register = NAU8822_REG_MAX_REGISTER, + .volatile_reg = nau8822_volatile, + + .readable_reg = nau8822_readable_reg, + .writeable_reg = nau8822_writeable_reg, + + .cache_type = REGCACHE_RBTREE, + .reg_defaults = nau8822_reg_defaults, + .num_reg_defaults = ARRAY_SIZE(nau8822_reg_defaults), +}; + +static int nau8822_i2c_probe(struct i2c_client *i2c, + const struct i2c_device_id *id) +{ + struct device *dev = &i2c->dev; + struct nau8822 *nau8822 = dev_get_platdata(dev); + int ret; + + if (!nau8822) { + nau8822 = devm_kzalloc(dev, sizeof(*nau8822), GFP_KERNEL); + if (nau8822 == NULL) + return -ENOMEM; + } + i2c_set_clientdata(i2c, nau8822); + + nau8822->regmap = devm_regmap_init_i2c(i2c, &nau8822_regmap_config); + if (IS_ERR(nau8822->regmap)) { + ret = PTR_ERR(nau8822->regmap); + dev_err(&i2c->dev, "Failed to allocate regmap: %d\n", ret); + return ret; + } + nau8822->dev = dev; + + /* Reset the codec */ + ret = regmap_write(nau8822->regmap, NAU8822_REG_RESET, 0x00); + if (ret != 0) { + dev_err(&i2c->dev, "Failed to issue reset: %d\n", ret); + return ret; + } + + ret = devm_snd_soc_register_component(dev, &soc_component_dev_nau8822, + &nau8822_dai, 1); + if (ret != 0) { + dev_err(&i2c->dev, "Failed to register CODEC: %d\n", ret); + return ret; + } + + return 0; +} + +static const struct i2c_device_id nau8822_i2c_id[] = { + { "nau8822", 0 }, + { } +}; +MODULE_DEVICE_TABLE(i2c, nau8822_i2c_id); + +#ifdef CONFIG_OF +static const struct of_device_id nau8822_of_match[] = { + { .compatible = "nuvoton,nau8822", }, + { } +}; +MODULE_DEVICE_TABLE(of, nau8822_of_match); +#endif + +static struct i2c_driver nau8822_i2c_driver = { + .driver = { + .name = "nau8822", + .of_match_table = of_match_ptr(nau8822_of_match), + }, + .probe = nau8822_i2c_probe, + .id_table = nau8822_i2c_id, +}; +module_i2c_driver(nau8822_i2c_driver); + +MODULE_DESCRIPTION("ASoC NAU8822 codec driver"); +MODULE_AUTHOR("David Lin "); +MODULE_LICENSE("GPL v2"); diff --git a/sound/soc/codecs/nau8822.h b/sound/soc/codecs/nau8822.h new file mode 100644 index 000000000000..aa79c969cd44 --- /dev/null +++ b/sound/soc/codecs/nau8822.h @@ -0,0 +1,204 @@ +/* + * nau8822.h -- NAU8822 Soc Audio Codec driver + * + * Author: David Lin + * Co-author: John Hsu + * Co-author: Seven Li + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#ifndef __NAU8822_H__ +#define __NAU8822_H__ + +#define NAU8822_REG_RESET 0x00 +#define NAU8822_REG_POWER_MANAGEMENT_1 0x01 +#define NAU8822_REG_POWER_MANAGEMENT_2 0x02 +#define NAU8822_REG_POWER_MANAGEMENT_3 0x03 +#define NAU8822_REG_AUDIO_INTERFACE 0x04 +#define NAU8822_REG_COMPANDING_CONTROL 0x05 +#define NAU8822_REG_CLOCKING 0x06 +#define NAU8822_REG_ADDITIONAL_CONTROL 0x07 +#define NAU8822_REG_GPIO_CONTROL 0x08 +#define NAU8822_REG_JACK_DETECT_CONTROL_1 0x09 +#define NAU8822_REG_DAC_CONTROL 0x0A +#define NAU8822_REG_LEFT_DAC_DIGITAL_VOLUME 0x0B +#define NAU8822_REG_RIGHT_DAC_DIGITAL_VOLUME 0x0C +#define NAU8822_REG_JACK_DETECT_CONTROL_2 0x0D +#define NAU8822_REG_ADC_CONTROL 0x0E +#define NAU8822_REG_LEFT_ADC_DIGITAL_VOLUME 0x0F +#define NAU8822_REG_RIGHT_ADC_DIGITAL_VOLUME 0x10 +#define NAU8822_REG_EQ1 0x12 +#define NAU8822_REG_EQ2 0x13 +#define NAU8822_REG_EQ3 0x14 +#define NAU8822_REG_EQ4 0x15 +#define NAU8822_REG_EQ5 0x16 +#define NAU8822_REG_DAC_LIMITER_1 0x18 +#define NAU8822_REG_DAC_LIMITER_2 0x19 +#define NAU8822_REG_NOTCH_FILTER_1 0x1B +#define NAU8822_REG_NOTCH_FILTER_2 0x1C +#define NAU8822_REG_NOTCH_FILTER_3 0x1D +#define NAU8822_REG_NOTCH_FILTER_4 0x1E +#define NAU8822_REG_ALC_CONTROL_1 0x20 +#define NAU8822_REG_ALC_CONTROL_2 0x21 +#define NAU8822_REG_ALC_CONTROL_3 0x22 +#define NAU8822_REG_NOISE_GATE 0x23 +#define NAU8822_REG_PLL_N 0x24 +#define NAU8822_REG_PLL_K1 0x25 +#define NAU8822_REG_PLL_K2 0x26 +#define NAU8822_REG_PLL_K3 0x27 +#define NAU8822_REG_3D_CONTROL 0x29 +#define NAU8822_REG_RIGHT_SPEAKER_CONTROL 0x2B +#define NAU8822_REG_INPUT_CONTROL 0x2C +#define NAU8822_REG_LEFT_INP_PGA_CONTROL 0x2D +#define NAU8822_REG_RIGHT_INP_PGA_CONTROL 0x2E +#define NAU8822_REG_LEFT_ADC_BOOST_CONTROL 0x2F +#define NAU8822_REG_RIGHT_ADC_BOOST_CONTROL 0x30 +#define NAU8822_REG_OUTPUT_CONTROL 0x31 +#define NAU8822_REG_LEFT_MIXER_CONTROL 0x32 +#define NAU8822_REG_RIGHT_MIXER_CONTROL 0x33 +#define NAU8822_REG_LHP_VOLUME 0x34 +#define NAU8822_REG_RHP_VOLUME 0x35 +#define NAU8822_REG_LSPKOUT_VOLUME 0x36 +#define NAU8822_REG_RSPKOUT_VOLUME 0x37 +#define NAU8822_REG_AUX2_MIXER 0x38 +#define NAU8822_REG_AUX1_MIXER 0x39 +#define NAU8822_REG_POWER_MANAGEMENT_4 0x3A +#define NAU8822_REG_LEFT_TIME_SLOT 0x3B +#define NAU8822_REG_MISC 0x3C +#define NAU8822_REG_RIGHT_TIME_SLOT 0x3D +#define NAU8822_REG_DEVICE_REVISION 0x3E +#define NAU8822_REG_DEVICE_ID 0x3F +#define NAU8822_REG_DAC_DITHER 0x41 +#define NAU8822_REG_ALC_ENHANCE_1 0x46 +#define NAU8822_REG_ALC_ENHANCE_2 0x47 +#define NAU8822_REG_192KHZ_SAMPLING 0x48 +#define NAU8822_REG_MISC_CONTROL 0x49 +#define NAU8822_REG_INPUT_TIEOFF 0x4A +#define NAU8822_REG_POWER_REDUCTION 0x4B +#define NAU8822_REG_AGC_PEAK2PEAK 0x4C +#define NAU8822_REG_AGC_PEAK_DETECT 0x4D +#define NAU8822_REG_AUTOMUTE_CONTROL 0x4E +#define NAU8822_REG_OUTPUT_TIEOFF 0x4F +#define NAU8822_REG_MAX_REGISTER NAU8822_REG_OUTPUT_TIEOFF + +/* NAU8822_REG_POWER_MANAGEMENT_1 (0x1) */ +#define NAU8822_REFIMP_MASK 0x3 +#define NAU8822_REFIMP_80K 0x1 +#define NAU8822_REFIMP_300K 0x2 +#define NAU8822_REFIMP_3K 0x3 +#define NAU8822_IOBUF_EN (0x1 << 2) +#define NAU8822_ABIAS_EN (0x1 << 3) + +/* NAU8822_REG_AUDIO_INTERFACE (0x4) */ +#define NAU8822_AIFMT_MASK (0x3 << 3) +#define NAU8822_WLEN_MASK (0x3 << 5) +#define NAU8822_WLEN_20 (0x1 << 5) +#define NAU8822_WLEN_24 (0x2 << 5) +#define NAU8822_WLEN_32 (0x3 << 5) +#define NAU8822_LRP_MASK (0x1 << 7) +#define NAU8822_BCLKP_MASK (0x1 << 8) + +/* NAU8822_REG_COMPANDING_CONTROL (0x5) */ +#define NAU8822_ADDAP_SFT 0 +#define NAU8822_ADCCM_SFT 1 +#define NAU8822_DACCM_SFT 3 + +/* NAU8822_REG_CLOCKING (0x6) */ +#define NAU8822_CLKIOEN_MASK 0x1 +#define NAU8822_MCLKSEL_SFT 5 +#define NAU8822_MCLKSEL_MASK (0x7 << 5) +#define NAU8822_BCLKSEL_SFT 2 +#define NAU8822_BCLKSEL_MASK (0x7 << 2) +#define NAU8822_CLKM_MASK (0x1 << 8) +#define NAU8822_CLKM_MCLK (0x0 << 8) +#define NAU8822_CLKM_PLL (0x1 << 8) + +/* NAU8822_REG_ADDITIONAL_CONTROL (0x08) */ +#define NAU8822_SMPLR_SFT 1 +#define NAU8822_SMPLR_MASK (0x7 << 1) +#define NAU8822_SMPLR_48K (0x0 << 1) +#define NAU8822_SMPLR_32K (0x1 << 1) +#define NAU8822_SMPLR_24K (0x2 << 1) +#define NAU8822_SMPLR_16K (0x3 << 1) +#define NAU8822_SMPLR_12K (0x4 << 1) +#define NAU8822_SMPLR_8K (0x5 << 1) + +/* NAU8822_REG_EQ1 (0x12) */ +#define NAU8822_EQ1GC_SFT 0 +#define NAU8822_EQ1CF_SFT 5 +#define NAU8822_EQM_SFT 8 + +/* NAU8822_REG_EQ2 (0x13) */ +#define NAU8822_EQ2GC_SFT 0 +#define NAU8822_EQ2CF_SFT 5 +#define NAU8822_EQ2BW_SFT 8 + +/* NAU8822_REG_EQ3 (0x14) */ +#define NAU8822_EQ3GC_SFT 0 +#define NAU8822_EQ3CF_SFT 5 +#define NAU8822_EQ3BW_SFT 8 + +/* NAU8822_REG_EQ4 (0x15) */ +#define NAU8822_EQ4GC_SFT 0 +#define NAU8822_EQ4CF_SFT 5 +#define NAU8822_EQ4BW_SFT 8 + +/* NAU8822_REG_EQ5 (0x16) */ +#define NAU8822_EQ5GC_SFT 0 +#define NAU8822_EQ5CF_SFT 5 + +/* NAU8822_REG_ALC_CONTROL_1 (0x20) */ +#define NAU8822_ALCMINGAIN_SFT 0 +#define NAU8822_ALCMXGAIN_SFT 3 +#define NAU8822_ALCEN_SFT 7 + +/* NAU8822_REG_ALC_CONTROL_2 (0x21) */ +#define NAU8822_ALCSL_SFT 0 +#define NAU8822_ALCHT_SFT 4 + +/* NAU8822_REG_ALC_CONTROL_3 (0x22) */ +#define NAU8822_ALCATK_SFT 0 +#define NAU8822_ALCDCY_SFT 4 +#define NAU8822_ALCM_SFT 8 + +/* NAU8822_REG_PLL_N (0x24) */ +#define NAU8822_PLLMCLK_DIV2 (0x1 << 4) +#define NAU8822_PLLN_MASK 0xF + +#define NAU8822_PLLK1_SFT 18 +#define NAU8822_PLLK1_MASK 0x3F + +/* NAU8822_REG_PLL_K2 (0x26) */ +#define NAU8822_PLLK2_SFT 9 +#define NAU8822_PLLK2_MASK 0x1FF + +/* NAU8822_REG_PLL_K3 (0x27) */ +#define NAU8822_PLLK3_MASK 0x1FF + +/* System Clock Source */ +enum { + NAU8822_CLK_MCLK, + NAU8822_CLK_PLL, +}; + +struct nau8822_pll { + int pre_factor; + int mclk_scaler; + int pll_frac; + int pll_int; +}; + +/* Codec Private Data */ +struct nau8822 { + struct device *dev; + struct regmap *regmap; + int mclk_idx; + struct nau8822_pll pll; + int sysclk; + int div_id; +}; + +#endif /* __NAU8822_H__ */ From fce9ec954a8af7e04cbf5b9daa8bec9c1df5cfe6 Mon Sep 17 00:00:00 2001 From: Daniel Mack Date: Wed, 17 Oct 2018 13:37:03 +0200 Subject: [PATCH 279/299] ASoC: sta32x: Add support for XTI clock The STA32x chips feature an XTI clock input that needs to be stable before the reset signal is released. Therefore, the chip driver needs to get a handle to the clock. Instead of relying on other parts of the system to enable the clock, let the codec driver grab a handle itself. In order to keep existing boards working, clock support is made optional. Signed-off-by: Daniel Mack Signed-off-by: Mark Brown --- .../devicetree/bindings/sound/st,sta32x.txt | 6 ++++ sound/soc/codecs/sta32x.c | 28 +++++++++++++++++++ 2 files changed, 34 insertions(+) diff --git a/Documentation/devicetree/bindings/sound/st,sta32x.txt b/Documentation/devicetree/bindings/sound/st,sta32x.txt index ff4a685a4303..52265fb757c5 100644 --- a/Documentation/devicetree/bindings/sound/st,sta32x.txt +++ b/Documentation/devicetree/bindings/sound/st,sta32x.txt @@ -19,6 +19,10 @@ Required properties: Optional properties: + - clocks, clock-names: Clock specifier for XTI input clock. + If specified, the clock will be enabled when the codec is probed, + and disabled when it is removed. The 'clock-names' must be set to 'xti'. + - st,output-conf: number, Selects the output configuration: 0: 2-channel (full-bridge) power, 2-channel data-out 1: 2 (half-bridge). 1 (full-bridge) on-board power @@ -79,6 +83,8 @@ Example: codec: sta32x@38 { compatible = "st,sta32x"; reg = <0x1c>; + clocks = <&clock>; + clock-names = "xti"; reset-gpios = <&gpio1 19 0>; power-down-gpios = <&gpio1 16 0>; st,output-conf = /bits/ 8 <0x3>; // set output to 2-channel diff --git a/sound/soc/codecs/sta32x.c b/sound/soc/codecs/sta32x.c index 22de1593443c..f753d2db0a5a 100644 --- a/sound/soc/codecs/sta32x.c +++ b/sound/soc/codecs/sta32x.c @@ -21,6 +21,7 @@ #include #include #include +#include #include #include #include @@ -142,6 +143,7 @@ static const char *sta32x_supply_names[] = { /* codec private data */ struct sta32x_priv { struct regmap *regmap; + struct clk *xti_clk; struct regulator_bulk_data supplies[ARRAY_SIZE(sta32x_supply_names)]; struct snd_soc_component *component; struct sta32x_platform_data *pdata; @@ -879,6 +881,18 @@ static int sta32x_probe(struct snd_soc_component *component) struct sta32x_priv *sta32x = snd_soc_component_get_drvdata(component); struct sta32x_platform_data *pdata = sta32x->pdata; int i, ret = 0, thermal = 0; + + sta32x->component = component; + + if (sta32x->xti_clk) { + ret = clk_prepare_enable(sta32x->xti_clk); + if (ret != 0) { + dev_err(component->dev, + "Failed to enable clock: %d\n", ret); + return ret; + } + } + ret = regulator_bulk_enable(ARRAY_SIZE(sta32x->supplies), sta32x->supplies); if (ret != 0) { @@ -981,6 +995,9 @@ static void sta32x_remove(struct snd_soc_component *component) sta32x_watchdog_stop(sta32x); regulator_bulk_disable(ARRAY_SIZE(sta32x->supplies), sta32x->supplies); + + if (sta32x->xti_clk) + clk_disable_unprepare(sta32x->xti_clk); } static const struct snd_soc_component_driver sta32x_component = { @@ -1097,6 +1114,17 @@ static int sta32x_i2c_probe(struct i2c_client *i2c, } #endif + /* Clock */ + sta32x->xti_clk = devm_clk_get(dev, "xti"); + if (IS_ERR(sta32x->xti_clk)) { + ret = PTR_ERR(sta32x->xti_clk); + + if (ret == -EPROBE_DEFER) + return ret; + + sta32x->xti_clk = NULL; + } + /* GPIOs */ sta32x->gpiod_nreset = devm_gpiod_get_optional(dev, "reset", GPIOD_OUT_LOW); From 4e9e07c5675706983ed649cfb92521a4d8aa1d6d Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Wed, 17 Oct 2018 01:54:33 +0000 Subject: [PATCH 280/299] ASoC: pcm3168a: add hw constraint for capture channel LEFT_J / I2S only can use TDM. commit 594680ea4a394 ("ASoC: pcm3168a: add hw constraint for channel") commit 3809688980205 ("ASoC: pcm3168a: add HW constraint for non RIGHT_J") added channel constraint for it, but, it was only for playback. This patch adds constraint for capture. Signed-off-by: Kuninori Morimoto Signed-off-by: Mark Brown --- sound/soc/codecs/pcm3168a.c | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/sound/soc/codecs/pcm3168a.c b/sound/soc/codecs/pcm3168a.c index 63aa02592bc0..52cc950c9fd1 100644 --- a/sound/soc/codecs/pcm3168a.c +++ b/sound/soc/codecs/pcm3168a.c @@ -529,11 +529,17 @@ static int pcm3168a_startup(struct snd_pcm_substream *substream, break; case PCM3168A_FMT_LEFT_J: sample_min = 24; - channel_max = 8; + if (tx) + channel_max = 8; + else + channel_max = 6; break; case PCM3168A_FMT_I2S: sample_min = 24; - channel_max = 8; + if (tx) + channel_max = 8; + else + channel_max = 6; break; default: sample_min = 24; @@ -559,6 +565,7 @@ static const struct snd_soc_dai_ops pcm3168a_dac_dai_ops = { }; static const struct snd_soc_dai_ops pcm3168a_adc_dai_ops = { + .startup = pcm3168a_startup, .set_fmt = pcm3168a_set_dai_fmt_adc, .set_sysclk = pcm3168a_set_dai_sysclk, .hw_params = pcm3168a_hw_params From 6817d7593f3e3c8a9c11e7a07cb5646c70371f0a Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Wed, 17 Oct 2018 01:55:37 +0000 Subject: [PATCH 281/299] ASoC: rsnd: enable TDM settings for SSI parent Some SSIs are sharing each pins (= WS/CLK pin for playback/capture). Then, SSI parent needs control WS/CLK setting for SSI slave. In such case, SSI parent needs TDM settings if SSI slave is working as TDM mode. But it is not cared in current driver. It can't capture TDM sound without this patch if SSIs were pin sharing. This patch is tested on R-Car H3 ulcb-kf board, SSI3/4 with TDM sound. Signed-off-by: Kuninori Morimoto Signed-off-by: Mark Brown --- sound/soc/sh/rcar/ssi.c | 21 +++++++++++---------- 1 file changed, 11 insertions(+), 10 deletions(-) diff --git a/sound/soc/sh/rcar/ssi.c b/sound/soc/sh/rcar/ssi.c index 3adcc4f778f7..b42a0e0feab7 100644 --- a/sound/soc/sh/rcar/ssi.c +++ b/sound/soc/sh/rcar/ssi.c @@ -399,6 +399,17 @@ static void rsnd_ssi_config_init(struct rsnd_mod *mod, if (rdai->sys_delay) cr_own |= DEL; + /* + * TDM Mode + * see + * rsnd_ssiu_init_gen2() + */ + wsr = ssi->wsr; + if (is_tdm) { + wsr |= WS_MODE; + cr_own |= CHNL_8; + } + /* * We shouldn't exchange SWSP after running. * This means, parent needs to care it. @@ -429,16 +440,6 @@ static void rsnd_ssi_config_init(struct rsnd_mod *mod, cr_mode = DIEN; /* PIO : enable Data interrupt */ } - /* - * TDM Extend Mode - * see - * rsnd_ssiu_init_gen2() - */ - wsr = ssi->wsr; - if (is_tdm) { - wsr |= WS_MODE; - cr_own |= CHNL_8; - } init_end: ssi->cr_own = cr_own; ssi->cr_mode = cr_mode; From 2eaa6e233091f51d8a629e423ad0bc080ffcb5d6 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Wed, 17 Oct 2018 01:55:57 +0000 Subject: [PATCH 282/299] ASoC: rsnd: tidyup SSICR::SWSP for TDM R-Car datasheet is indicating that WS output settings of SSICR::SWSP is inverted on TDM mode from non TDM mode settings. But, it is meaning that TDM should use 0 here. Without this patch, sound input/output 1ch will be 2ch, 2ch will be 3ch ..., be jumbled on I2S + TDM settings. This patch fixup it. This patch is tested on R-Car H3 ulcb-kf board, SSI3/4 TDM sound. Signed-off-by: Kuninori Morimoto Signed-off-by: Mark Brown --- sound/soc/sh/rcar/ssi.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sound/soc/sh/rcar/ssi.c b/sound/soc/sh/rcar/ssi.c index b42a0e0feab7..fcb4df23248c 100644 --- a/sound/soc/sh/rcar/ssi.c +++ b/sound/soc/sh/rcar/ssi.c @@ -392,7 +392,7 @@ static void rsnd_ssi_config_init(struct rsnd_mod *mod, if (rdai->bit_clk_inv) cr_own |= SCKP; - if (rdai->frm_clk_inv ^ is_tdm) + if (rdai->frm_clk_inv && !is_tdm) cr_own |= SWSP; if (rdai->data_alignment) cr_own |= SDTA; From f90afe7955141d122883b27e56e27b686033db22 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Thu, 20 Sep 2018 16:42:09 +0200 Subject: [PATCH 283/299] ALSA: doc: Brush up the old writing-an-alsa-driver Slightly brushing up and throw the old dust away from my ancient writing-an-alsa-driver document. The contents aren't changed so much but the obsoleted parts are dropped. Also, remove the date and the version number. It's useless. Reviewed-by: Takashi Sakamoto Signed-off-by: Takashi Iwai --- .../kernel-api/writing-an-alsa-driver.rst | 307 +++++++++--------- 1 file changed, 149 insertions(+), 158 deletions(-) diff --git a/Documentation/sound/kernel-api/writing-an-alsa-driver.rst b/Documentation/sound/kernel-api/writing-an-alsa-driver.rst index a0b268466cb1..b37234afdfa1 100644 --- a/Documentation/sound/kernel-api/writing-an-alsa-driver.rst +++ b/Documentation/sound/kernel-api/writing-an-alsa-driver.rst @@ -3,8 +3,6 @@ Writing an ALSA Driver ====================== :Author: Takashi Iwai -:Date: Oct 15, 2007 -:Edition: 0.3.7 Preface ======= @@ -21,11 +19,6 @@ explain the general topic of linux kernel coding and doesn't cover low-level driver implementation details. It only describes the standard way to write a PCI sound driver on ALSA. -If you are already familiar with the older ALSA ver.0.5.x API, you can -check the drivers such as ``sound/pci/es1938.c`` or -``sound/pci/maestro3.c`` which have also almost the same code-base in -the ALSA 0.5.x tree, so you can compare the differences. - This document is still a draft version. Any feedback and corrections, please!! @@ -35,24 +28,7 @@ File Tree Structure General ------- -The ALSA drivers are provided in two ways. - -One is the trees provided as a tarball or via cvs from the ALSA's ftp -site, and another is the 2.6 (or later) Linux kernel tree. To -synchronize both, the ALSA driver tree is split into two different -trees: alsa-kernel and alsa-driver. The former contains purely the -source code for the Linux 2.6 (or later) tree. This tree is designed -only for compilation on 2.6 or later environment. The latter, -alsa-driver, contains many subtle files for compiling ALSA drivers -outside of the Linux kernel tree, wrapper functions for older 2.2 and -2.4 kernels, to adapt the latest kernel API, and additional drivers -which are still in development or in tests. The drivers in alsa-driver -tree will be moved to alsa-kernel (and eventually to the 2.6 kernel -tree) when they are finished and confirmed to work fine. - -The file tree structure of ALSA driver is depicted below. Both -alsa-kernel and alsa-driver have almost the same file structure, except -for “core” directory. It's named as “acore” in alsa-driver tree. +The file tree structure of ALSA driver is depicted below. :: @@ -61,14 +37,11 @@ for “core” directory. It's named as “acore” in alsa-driver tree. /oss /seq /oss - /instr - /ioctl32 /include /drivers /mpu401 /opl3 /i2c - /l3 /synth /emux /pci @@ -80,6 +53,7 @@ for “core” directory. It's named as “acore” in alsa-driver tree. /sparc /usb /pcmcia /(cards) + /soc /oss @@ -99,13 +73,6 @@ directory. The rawmidi OSS emulation is included in the ALSA rawmidi code since it's quite small. The sequencer code is stored in ``core/seq/oss`` directory (see `below <#core-seq-oss>`__). -core/ioctl32 -~~~~~~~~~~~~ - -This directory contains the 32bit-ioctl wrappers for 64bit architectures -such like x86-64, ppc64 and sparc64. For 32bit and alpha architectures, -these are not compiled. - core/seq ~~~~~~~~ @@ -119,11 +86,6 @@ core/seq/oss This contains the OSS sequencer emulation codes. -core/seq/instr -~~~~~~~~~~~~~~ - -This directory contains the modules for the sequencer instrument layer. - include directory ----------------- @@ -161,11 +123,6 @@ Although there is a standard i2c layer on Linux, ALSA has its own i2c code for some cards, because the soundcard needs only a simple operation and the standard i2c API is too complicated for such a purpose. -i2c/l3 -~~~~~~ - -This is a sub-directory for ARM L3 i2c. - synth directory --------------- @@ -209,11 +166,19 @@ The PCMCIA, especially PCCard drivers will go here. CardBus drivers will be in the pci directory, because their API is identical to that of standard PCI cards. +soc directory +------------- + +This directory contains the codes for ASoC (ALSA System on Chip) +layer including ASoC core, codec and machine drivers. + oss directory ------------- -The OSS/Lite source files are stored here in Linux 2.6 (or later) tree. -In the ALSA driver tarball, this directory is empty, of course :) +Here contains OSS/Lite codes. +All codes have been deprecated except for dmasound on m68k as of +writing this. + Basic Flow for PCI Drivers ========================== @@ -352,10 +317,8 @@ to details explained in the following section. /* (3) */ err = snd_mychip_create(card, pci, &chip); - if (err < 0) { - snd_card_free(card); - return err; - } + if (err < 0) + goto error; /* (4) */ strcpy(card->driver, "My Chip"); @@ -368,22 +331,23 @@ to details explained in the following section. /* (6) */ err = snd_card_register(card); - if (err < 0) { - snd_card_free(card); - return err; - } + if (err < 0) + goto error; /* (7) */ pci_set_drvdata(pci, card); dev++; return 0; + + error: + snd_card_free(card); + return err; } /* destructor -- see the "Destructor" sub-section */ static void snd_mychip_remove(struct pci_dev *pci) { snd_card_free(pci_get_drvdata(pci)); - pci_set_drvdata(pci, NULL); } @@ -445,14 +409,26 @@ In this part, the PCI resources are allocated. struct mychip *chip; .... err = snd_mychip_create(card, pci, &chip); - if (err < 0) { - snd_card_free(card); - return err; - } + if (err < 0) + goto error; The details will be explained in the section `PCI Resource Management`_. +When something goes wrong, the probe function needs to deal with the +error. In this example, we have a single error handling path placed +at the end of the function. + +:: + + error: + snd_card_free(card); + return err; + +Since each component can be properly freed, the single +:c:func:`snd_card_free()` call should suffice in most cases. + + 4) Set the driver ID and name strings. ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ @@ -486,10 +462,8 @@ too. :: err = snd_card_register(card); - if (err < 0) { - snd_card_free(card); - return err; - } + if (err < 0) + goto error; Will be explained in the section `Management of Cards and Components`_, too. @@ -513,14 +487,13 @@ The destructor, remove callback, simply releases the card instance. Then the ALSA middle layer will release all the attached components automatically. -It would be typically like the following: +It would be typically just :c:func:`calling snd_card_free()`: :: static void snd_mychip_remove(struct pci_dev *pci) { snd_card_free(pci_get_drvdata(pci)); - pci_set_drvdata(pci, NULL); } @@ -546,7 +519,7 @@ in the source file. If the code is split into several files, the files without module options don't need them. In addition to these headers, you'll need ```` for -interrupt handling, and ```` for I/O access. If you use the +interrupt handling, and ```` for I/O access. If you use the :c:func:`mdelay()` or :c:func:`udelay()` functions, you'll need to include ```` too. @@ -720,6 +693,13 @@ function, which will call the real destructor. where :c:func:`snd_mychip_free()` is the real destructor. +The demerit of this method is the obviously more amount of codes. +The merit is, however, you can trigger the own callback at registering +and disconnecting the card via setting in snd_device_ops. +About the registering and disconnecting the card, see the subsections +below. + + Registration and Release ------------------------ @@ -905,10 +885,8 @@ Resource Allocation ------------------- The allocation of I/O ports and irqs is done via standard kernel -functions. Unlike ALSA ver.0.5.x., there are no helpers for that. And -these resources must be released in the destructor function (see below). -Also, on ALSA 0.9.x, you don't need to allocate (pseudo-)DMA for PCI -like in ALSA 0.5.x. +functions. These resources must be released in the destructor +function (see below). Now assume that the PCI device has an I/O port with 8 bytes and an interrupt. Then :c:type:`struct mychip ` will have the @@ -1064,7 +1042,8 @@ and the allocation would be like below: :: - if ((err = pci_request_regions(pci, "My Chip")) < 0) { + err = pci_request_regions(pci, "My Chip"); + if (err < 0) { kfree(chip); return err; } @@ -1086,6 +1065,21 @@ and the corresponding destructor would be: .... } +Of course, a modern way with :c:func:`pci_iomap()` will make things a +bit easier, too. + +:: + + err = pci_request_regions(pci, "My Chip"); + if (err < 0) { + kfree(chip); + return err; + } + chip->iobase_virt = pci_iomap(pci, 0, 0); + +which is paired with :c:func:`pci_iounmap()` at destructor. + + PCI Entries ----------- @@ -1154,13 +1148,6 @@ And at last, the module entries: Note that these module entries are tagged with ``__init`` and ``__exit`` prefixes. -Oh, one thing was forgotten. If you have no exported symbols, you need -to declare it in 2.2 or 2.4 kernels (it's not necessary in 2.6 kernels). - -:: - - EXPORT_NO_SYMBOLS; - That's all! PCM Interface @@ -2113,6 +2100,16 @@ non-contiguous buffers. The mmap calls this callback to get the page address. Some examples will be explained in the later section `Buffer and Memory Management`_, too. +mmap calllback +~~~~~~~~~~~~~~ + +This is another optional callback for controlling mmap behavior. +Once when defined, PCM core calls this callback when a page is +memory-mapped instead of dealing via the standard helper. +If you need special handling (due to some architecture or +device-specific issues), implement everything here as you like. + + PCM Interrupt Handler --------------------- @@ -2370,6 +2367,27 @@ to define the inverse rule: hw_rule_format_by_channels, NULL, SNDRV_PCM_HW_PARAM_CHANNELS, -1); +One typical usage of the hw constraints is to align the buffer size +with the period size. As default, ALSA PCM core doesn't enforce the +buffer size to be aligned with the period size. For example, it'd be +possible to have a combination like 256 period bytes with 999 buffer +bytes. + +Many device chips, however, require the buffer to be a multiple of +periods. In such a case, call +:c:func:`snd_pcm_hw_constraint_integer()` for +``SNDRV_PCM_HW_PARAM_PERIODS``. + +:: + + snd_pcm_hw_constraint_integer(substream->runtime, + SNDRV_PCM_HW_PARAM_PERIODS); + +This assures that the number of periods is integer, hence the buffer +size is aligned with the period size. + +The hw constraint is a very much powerful mechanism to define the +preferred PCM configuration, and there are relevant helpers. I won't give more details here, rather I would like to say, “Luke, use the source.” @@ -3712,7 +3730,14 @@ example, for an intermediate buffer. Since the allocated pages are not contiguous, you need to set the ``page`` callback to obtain the physical address at every offset. -The implementation of ``page`` callback would be like this: +The easiest way to achieve it would be to use +:c:func:`snd_pcm_lib_alloc_vmalloc_buffer()` for allocating the buffer +via :c:func:`vmalloc()`, and set :c:func:`snd_pcm_sgbuf_ops_page()` to +the ``page`` callback. At release, you need to call +:c:func:`snd_pcm_lib_free_vmalloc_buffer()`. + +If you want to implementation the ``page`` manually, it would be like +this: :: @@ -3848,7 +3873,9 @@ Power Management If the chip is supposed to work with suspend/resume functions, you need to add power-management code to the driver. The additional code for -power-management should be ifdef-ed with ``CONFIG_PM``. +power-management should be ifdef-ed with ``CONFIG_PM``, or annotated +with __maybe_unused attribute; otherwise the compiler will complain +you. If the driver *fully* supports suspend/resume that is, the device can be properly resumed to its state when suspend was called, you can set the @@ -3879,18 +3906,16 @@ the case of PCI drivers, the callbacks look like below: :: - #ifdef CONFIG_PM - static int snd_my_suspend(struct pci_dev *pci, pm_message_t state) + static int __maybe_unused snd_my_suspend(struct device *dev) { .... /* do things for suspend */ return 0; } - static int snd_my_resume(struct pci_dev *pci) + static int __maybe_unused snd_my_resume(struct device *dev) { .... /* do things for suspend */ return 0; } - #endif The scheme of the real suspend job is as follows. @@ -3909,18 +3934,14 @@ The scheme of the real suspend job is as follows. 6. Stop the hardware if necessary. -7. Disable the PCI device by calling - :c:func:`pci_disable_device()`. Then, call - :c:func:`pci_save_state()` at last. - A typical code would be like: :: - static int mychip_suspend(struct pci_dev *pci, pm_message_t state) + static int __maybe_unused mychip_suspend(struct device *dev) { /* (1) */ - struct snd_card *card = pci_get_drvdata(pci); + struct snd_card *card = dev_get_drvdata(dev); struct mychip *chip = card->private_data; /* (2) */ snd_power_change_state(card, SNDRV_CTL_POWER_D3hot); @@ -3932,9 +3953,6 @@ A typical code would be like: snd_mychip_save_registers(chip); /* (6) */ snd_mychip_stop_hardware(chip); - /* (7) */ - pci_disable_device(pci); - pci_save_state(pci); return 0; } @@ -3943,44 +3961,35 @@ The scheme of the real resume job is as follows. 1. Retrieve the card and the chip data. -2. Set up PCI. First, call :c:func:`pci_restore_state()`. Then - enable the pci device again by calling - :c:func:`pci_enable_device()`. Call - :c:func:`pci_set_master()` if necessary, too. +2. Re-initialize the chip. -3. Re-initialize the chip. +3. Restore the saved registers if necessary. -4. Restore the saved registers if necessary. +4. Resume the mixer, e.g. calling :c:func:`snd_ac97_resume()`. -5. Resume the mixer, e.g. calling :c:func:`snd_ac97_resume()`. +5. Restart the hardware (if any). -6. Restart the hardware (if any). - -7. Call :c:func:`snd_power_change_state()` with +6. Call :c:func:`snd_power_change_state()` with ``SNDRV_CTL_POWER_D0`` to notify the processes. A typical code would be like: :: - static int mychip_resume(struct pci_dev *pci) + static int __maybe_unused mychip_resume(struct pci_dev *pci) { /* (1) */ - struct snd_card *card = pci_get_drvdata(pci); + struct snd_card *card = dev_get_drvdata(dev); struct mychip *chip = card->private_data; /* (2) */ - pci_restore_state(pci); - pci_enable_device(pci); - pci_set_master(pci); - /* (3) */ snd_mychip_reinit_chip(chip); - /* (4) */ + /* (3) */ snd_mychip_restore_registers(chip); - /* (5) */ + /* (4) */ snd_ac97_resume(chip->ac97); - /* (6) */ + /* (5) */ snd_mychip_restart_chip(chip); - /* (7) */ + /* (6) */ snd_power_change_state(card, SNDRV_CTL_POWER_D0); return 0; } @@ -4046,15 +4055,14 @@ And next, set suspend/resume callbacks to the pci_driver. :: + static SIMPLE_DEV_PM_OPS(snd_my_pm_ops, mychip_suspend, mychip_resume); + static struct pci_driver driver = { .name = KBUILD_MODNAME, .id_table = snd_my_ids, .probe = snd_my_probe, .remove = snd_my_remove, - #ifdef CONFIG_PM - .suspend = snd_my_suspend, - .resume = snd_my_resume, - #endif + .driver.pm = &snd_my_pm_ops, }; Module Parameters @@ -4078,7 +4086,7 @@ variables, instead. ``enable`` option is not always necessary in this case, but it would be better to have a dummy option for compatibility. The module parameters must be declared with the standard -``module_param()()``, ``module_param_array()()`` and +``module_param()``, ``module_param_array()`` and :c:func:`MODULE_PARM_DESC()` macros. The typical coding would be like below: @@ -4094,15 +4102,14 @@ The typical coding would be like below: module_param_array(enable, bool, NULL, 0444); MODULE_PARM_DESC(enable, "Enable " CARD_NAME " soundcard."); -Also, don't forget to define the module description, classes, license -and devices. Especially, the recent modprobe requires to define the +Also, don't forget to define the module description and the license. +Especially, the recent modprobe requires to define the module license as GPL, etc., otherwise the system is shown as “tainted”. :: - MODULE_DESCRIPTION("My Chip"); + MODULE_DESCRIPTION("Sound driver for My Chip"); MODULE_LICENSE("GPL"); - MODULE_SUPPORTED_DEVICE("{{Vendor,My Chip Name}}"); How To Put Your Driver Into ALSA Tree @@ -4117,21 +4124,17 @@ a question now: how to put my own driver into the ALSA driver tree? Here Suppose that you create a new PCI driver for the card “xyz”. The card module name would be snd-xyz. The new driver is usually put into the -alsa-driver tree, ``alsa-driver/pci`` directory in the case of PCI -cards. Then the driver is evaluated, audited and tested by developers -and users. After a certain time, the driver will go to the alsa-kernel -tree (to the corresponding directory, such as ``alsa-kernel/pci``) and -eventually will be integrated into the Linux 2.6 tree (the directory -would be ``linux/sound/pci``). +alsa-driver tree, ``sound/pci`` directory in the case of PCI +cards. In the following sections, the driver code is supposed to be put into -alsa-driver tree. The two cases are covered: a driver consisting of a +Linux kernel tree. The two cases are covered: a driver consisting of a single source file and one consisting of several source files. Driver with A Single Source File -------------------------------- -1. Modify alsa-driver/pci/Makefile +1. Modify sound/pci/Makefile Suppose you have a file xyz.c. Add the following two lines @@ -4160,52 +4163,43 @@ Driver with A Single Source File For the details of Kconfig script, refer to the kbuild documentation. -3. Run cvscompile script to re-generate the configure script and build - the whole stuff again. - Drivers with Several Source Files --------------------------------- Suppose that the driver snd-xyz have several source files. They are -located in the new subdirectory, pci/xyz. +located in the new subdirectory, sound/pci/xyz. -1. Add a new directory (``xyz``) in ``alsa-driver/pci/Makefile`` as - below +1. Add a new directory (``sound/pci/xyz``) in ``sound/pci/Makefile`` + as below :: - obj-$(CONFIG_SND) += xyz/ + obj-$(CONFIG_SND) += sound/pci/xyz/ -2. Under the directory ``xyz``, create a Makefile +2. Under the directory ``sound/pci/xyz``, create a Makefile :: - ifndef SND_TOPDIR - SND_TOPDIR=../.. - endif - - include $(SND_TOPDIR)/toplevel.config - include $(SND_TOPDIR)/Makefile.conf - snd-xyz-objs := xyz.o abc.o def.o - obj-$(CONFIG_SND_XYZ) += snd-xyz.o - include $(SND_TOPDIR)/Rules.make - 3. Create the Kconfig entry This procedure is as same as in the last section. -4. Run cvscompile script to re-generate the configure script and build - the whole stuff again. Useful Functions ================ :c:func:`snd_printk()` and friends ---------------------------------------- +---------------------------------- + +.. note:: This subsection describes a few helper functions for + decorating a bit more on the standard :c:func:`printk()` & co. + However, in general, the use of such helpers is no longer recommended. + If possible, try to stick with the standard functions like + :c:func:`dev_err()` or :c:func:`pr_err()`. ALSA provides a verbose version of the :c:func:`printk()` function. If a kernel config ``CONFIG_SND_VERBOSE_PRINTK`` is set, this function @@ -4221,13 +4215,10 @@ just like :c:func:`snd_printk()`. If the ALSA is compiled without the debugging flag, it's ignored. :c:func:`snd_printdd()` is compiled in only when -``CONFIG_SND_DEBUG_VERBOSE`` is set. Please note that -``CONFIG_SND_DEBUG_VERBOSE`` is not set as default even if you configure -the alsa-driver with ``--with-debug=full`` option. You need to give -explicitly ``--with-debug=detect`` option instead. +``CONFIG_SND_DEBUG_VERBOSE`` is set. :c:func:`snd_BUG()` ------------------------- +------------------- It shows the ``BUG?`` message and stack trace as well as :c:func:`snd_BUG_ON()` at the point. It's useful to show that a @@ -4236,7 +4227,7 @@ fatal error happens there. When no debug flag is set, this macro is ignored. :c:func:`snd_BUG_ON()` ----------------------------- +---------------------- :c:func:`snd_BUG_ON()` macro is similar with :c:func:`WARN_ON()` macro. For example, snd_BUG_ON(!pointer); or From eb7ebfa3c1989aa8e59d5e68ab3cddd7df1bfb27 Mon Sep 17 00:00:00 2001 From: Philipp Klocke Date: Thu, 18 Oct 2018 12:33:02 +0200 Subject: [PATCH 284/299] ALSA: i2c/cs8427: Fix int to char conversion Compiling with clang yields the following warning: sound/i2c/cs8427.c:140:31: warning: implicit conversion from 'int' to 'char' changes value from 160 to -96 [-Wconstant-conversion] data[0] = CS8427_REG_AUTOINC | CS8427_REG_CORU_DATABUF; ~ ~~~~~~~~~~~~~~~~~~~^~~~~~~~~~~~~~~~~~~~~~~~~ Because CS8427_REG_AUTOINC is defined as 128, it is too big for a char field. So change data from char to unsigned char, that it can hold the value. This patch does not change the generated code. Signed-off-by: Philipp Klocke Signed-off-by: Takashi Iwai --- sound/i2c/cs8427.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sound/i2c/cs8427.c b/sound/i2c/cs8427.c index 2647309bc675..8afa2f888466 100644 --- a/sound/i2c/cs8427.c +++ b/sound/i2c/cs8427.c @@ -118,7 +118,7 @@ static int snd_cs8427_send_corudata(struct snd_i2c_device *device, struct cs8427 *chip = device->private_data; char *hw_data = udata ? chip->playback.hw_udata : chip->playback.hw_status; - char data[32]; + unsigned char data[32]; int err, idx; if (!memcmp(hw_data, ndata, count)) From 9ab2a1bd81f7eaef4b496168dd93e0f23e8906fe Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Thu, 18 Oct 2018 10:34:30 +0300 Subject: [PATCH 285/299] ASoC: Intel: kbl_da7219_max98927: minor white space clean up I just added a couple missing tabs. Signed-off-by: Dan Carpenter Signed-off-by: Mark Brown --- sound/soc/intel/boards/kbl_da7219_max98927.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/sound/soc/intel/boards/kbl_da7219_max98927.c b/sound/soc/intel/boards/kbl_da7219_max98927.c index 3ab96ee7bd3c..3fa1c3ca6d37 100644 --- a/sound/soc/intel/boards/kbl_da7219_max98927.c +++ b/sound/soc/intel/boards/kbl_da7219_max98927.c @@ -180,14 +180,14 @@ static int kabylake_ssp0_hw_params(struct snd_pcm_substream *substream, ret = snd_soc_dai_set_tdm_slot(codec_dai, 0x30, 3, 8, 16); if (ret < 0) { dev_err(runtime->dev, "DEV0 TDM slot err:%d\n", ret); - return ret; + return ret; } } if (!strcmp(codec_dai->component->name, MAXIM_DEV1_NAME)) { ret = snd_soc_dai_set_tdm_slot(codec_dai, 0xC0, 3, 8, 16); if (ret < 0) { dev_err(runtime->dev, "DEV1 TDM slot err:%d\n", ret); - return ret; + return ret; } } } From 3c01b0e129e9486c8004e43eba3a70de7393f645 Mon Sep 17 00:00:00 2001 From: Charles Keepax Date: Thu, 11 Oct 2018 17:28:28 +0100 Subject: [PATCH 286/299] ASoC: dapm: Add support for hw_free on CODEC to CODEC links Currently, on power down for a CODEC to CODEC DAI link we only call digital_mute and shutdown. Provide a little more flexibility for drivers by adding a call to hw_free as well. Signed-off-by: Charles Keepax Signed-off-by: Mark Brown --- sound/soc/soc-dapm.c | 17 +++++++++++------ 1 file changed, 11 insertions(+), 6 deletions(-) diff --git a/sound/soc/soc-dapm.c b/sound/soc/soc-dapm.c index 8c5b065c8880..a5178845065b 100644 --- a/sound/soc/soc-dapm.c +++ b/sound/soc/soc-dapm.c @@ -3737,25 +3737,30 @@ static int snd_soc_dai_link_event(struct snd_soc_dapm_widget *w, ret = 0; } + substream.stream = SNDRV_PCM_STREAM_CAPTURE; snd_soc_dapm_widget_for_each_source_path(w, path) { source = path->source->priv; + if (source->driver->ops->hw_free) + source->driver->ops->hw_free(&substream, + source); + source->active--; - if (source->driver->ops->shutdown) { - substream.stream = SNDRV_PCM_STREAM_CAPTURE; + if (source->driver->ops->shutdown) source->driver->ops->shutdown(&substream, source); - } } + substream.stream = SNDRV_PCM_STREAM_PLAYBACK; snd_soc_dapm_widget_for_each_sink_path(w, path) { sink = path->sink->priv; + if (sink->driver->ops->hw_free) + sink->driver->ops->hw_free(&substream, sink); + sink->active--; - if (sink->driver->ops->shutdown) { - substream.stream = SNDRV_PCM_STREAM_PLAYBACK; + if (sink->driver->ops->shutdown) sink->driver->ops->shutdown(&substream, sink); - } } break; From 2c7b696a7589ab14854c132dc732973fbd498d5a Mon Sep 17 00:00:00 2001 From: Marcel Ziswiler Date: Thu, 18 Oct 2018 13:18:28 +0200 Subject: [PATCH 287/299] ASoC: soc-core: fix trivial checkpatch issues Fix a few trivial aka cosmetic only checkpatch issues like long lines, wrong indentations, spurious blanks and newlines, missing newlines, multi-line comments etc. Signed-off-by: Marcel Ziswiler Signed-off-by: Mark Brown --- sound/soc/soc-core.c | 146 ++++++++++++++++++++++++++----------------- 1 file changed, 88 insertions(+), 58 deletions(-) diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c index 62e8e36062df..6ddcf12bc030 100644 --- a/sound/soc/soc-core.c +++ b/sound/soc/soc-core.c @@ -66,8 +66,9 @@ static int pmdown_time = 5000; module_param(pmdown_time, int, 0); MODULE_PARM_DESC(pmdown_time, "DAPM stream powerdown time (msecs)"); -/* If a DMI filed contain strings in this blacklist (e.g. - * "Type2 - Board Manufacturer" or "Type1 - TBD by OEM"), it will be taken +/* + * If a DMI filed contain strings in this blacklist (e.g. + * "Type2 - Board Manufacturer" or "Type1 - TBD by OEM"), it will be taken * as invalid and dropped when setting the card long name from DMI info. */ static const char * const dmi_blacklist[] = { @@ -222,7 +223,7 @@ static void soc_init_card_debugfs(struct snd_soc_card *card) &card->pop_time); if (!card->debugfs_pop_time) dev_warn(card->dev, - "ASoC: Failed to create pop time debugfs file\n"); + "ASoC: Failed to create pop time debugfs file\n"); } static void soc_cleanup_card_debugfs(struct snd_soc_card *card) @@ -426,7 +427,8 @@ EXPORT_SYMBOL_GPL(snd_soc_get_pcm_runtime); static void codec2codec_close_delayed_work(struct work_struct *work) { - /* Currently nothing to do for c2c links + /* + * Currently nothing to do for c2c links * Since c2c links are internal nodes in the DAPM graph and * don't interface with the outside world or application layer * we don't have to do any special handling on close. @@ -446,8 +448,9 @@ int snd_soc_suspend(struct device *dev) if (!card->instantiated) return 0; - /* Due to the resume being scheduled into a workqueue we could - * suspend before that's finished - wait for it to complete. + /* + * Due to the resume being scheduled into a workqueue we could + * suspend before that's finished - wait for it to complete. */ snd_power_wait(card->snd_card, SNDRV_CTL_POWER_D0); @@ -514,10 +517,13 @@ int snd_soc_suspend(struct device *dev) /* suspend all COMPONENTs */ for_each_card_components(card, component) { - struct snd_soc_dapm_context *dapm = snd_soc_component_get_dapm(component); + struct snd_soc_dapm_context *dapm = + snd_soc_component_get_dapm(component); - /* If there are paths active then the COMPONENT will be held with - * bias _ON and should not be suspended. */ + /* + * If there are paths active then the COMPONENT will be held + * with bias _ON and should not be suspended. + */ if (!component->suspended) { switch (snd_soc_dapm_get_bias_level(dapm)) { case SND_SOC_BIAS_STANDBY: @@ -571,18 +577,21 @@ int snd_soc_suspend(struct device *dev) } EXPORT_SYMBOL_GPL(snd_soc_suspend); -/* deferred resume work, so resume can complete before we finished +/* + * deferred resume work, so resume can complete before we finished * setting our codec back up, which can be very slow on I2C */ static void soc_resume_deferred(struct work_struct *work) { struct snd_soc_card *card = - container_of(work, struct snd_soc_card, deferred_resume_work); + container_of(work, struct snd_soc_card, + deferred_resume_work); struct snd_soc_pcm_runtime *rtd; struct snd_soc_component *component; int i; - /* our power state is still SNDRV_CTL_POWER_D3hot from suspend time, + /* + * our power state is still SNDRV_CTL_POWER_D3hot from suspend time, * so userspace apps are blocked from touching us */ @@ -699,6 +708,7 @@ int snd_soc_resume(struct device *dev) */ for_each_card_rtds(card, rtd) { struct snd_soc_dai *cpu_dai = rtd->cpu_dai; + bus_control |= cpu_dai->driver->bus_control; } if (bus_control) { @@ -777,7 +787,7 @@ struct snd_soc_dai *snd_soc_find_dai( lockdep_assert_held(&client_mutex); - /* Find CPU DAI from registered DAIs*/ + /* Find CPU DAI from registered DAIs */ for_each_component(component) { if (!snd_soc_is_matching_component(dlc, component)) continue; @@ -795,7 +805,6 @@ struct snd_soc_dai *snd_soc_find_dai( } EXPORT_SYMBOL_GPL(snd_soc_find_dai); - /** * snd_soc_find_dai_link - Find a DAI link * @@ -918,7 +927,7 @@ static int soc_bind_dai_link(struct snd_soc_card *card, _err_defer: soc_free_pcm_runtime(rtd); - return -EPROBE_DEFER; + return -EPROBE_DEFER; } static void soc_remove_component(struct snd_soc_component *component) @@ -1074,7 +1083,7 @@ static int snd_soc_init_multicodec(struct snd_soc_card *card, } static int soc_init_dai_link(struct snd_soc_card *card, - struct snd_soc_dai_link *link) + struct snd_soc_dai_link *link) { int i, ret; struct snd_soc_dai_link_component *codec; @@ -1148,7 +1157,8 @@ static int soc_init_dai_link(struct snd_soc_card *card, void snd_soc_disconnect_sync(struct device *dev) { - struct snd_soc_component *component = snd_soc_lookup_component(dev, NULL); + struct snd_soc_component *component = + snd_soc_lookup_component(dev, NULL); if (!component || !component->card) return; @@ -1179,7 +1189,8 @@ int snd_soc_add_dai_link(struct snd_soc_card *card, } lockdep_assert_held(&client_mutex); - /* Notify the machine driver for extra initialization + /* + * Notify the machine driver for extra initialization * on the link created by topology. */ if (dai_link->dobj.type && card->add_dai_link) @@ -1214,7 +1225,8 @@ void snd_soc_remove_dai_link(struct snd_soc_card *card, } lockdep_assert_held(&client_mutex); - /* Notify the machine driver for extra destruction + /* + * Notify the machine driver for extra destruction * on the link created by topology. */ if (dai_link->dobj.type && card->remove_dai_link) @@ -1274,7 +1286,8 @@ static void soc_set_name_prefix(struct snd_soc_card *card, static int soc_probe_component(struct snd_soc_card *card, struct snd_soc_component *component) { - struct snd_soc_dapm_context *dapm = snd_soc_component_get_dapm(component); + struct snd_soc_dapm_context *dapm = + snd_soc_component_get_dapm(component); struct snd_soc_dai *dai; int ret; @@ -1406,8 +1419,7 @@ static int soc_post_component_init(struct snd_soc_pcm_runtime *rtd, } static int soc_probe_link_components(struct snd_soc_card *card, - struct snd_soc_pcm_runtime *rtd, - int order) + struct snd_soc_pcm_runtime *rtd, int order) { struct snd_soc_component *component; struct snd_soc_rtdcom_list *rtdcom; @@ -1434,6 +1446,7 @@ static int soc_probe_dai(struct snd_soc_dai *dai, int order) if (dai->driver->probe) { int ret = dai->driver->probe(dai); + if (ret < 0) { dev_err(dai->dev, "ASoC: failed to probe DAI %s: %d\n", dai->name, ret); @@ -1541,7 +1554,7 @@ static int soc_probe_link_dais(struct snd_soc_card *card, } if (cpu_dai->driver->compress_new) { - /*create compress_device"*/ + /* create compress_device" */ ret = cpu_dai->driver->compress_new(rtd, num); if (ret < 0) { dev_err(card->dev, "ASoC: can't create compress %s\n", @@ -1555,7 +1568,7 @@ static int soc_probe_link_dais(struct snd_soc_card *card, ret = soc_new_pcm(rtd, num); if (ret < 0) { dev_err(card->dev, "ASoC: can't create pcm %s :%d\n", - dai_link->stream_name, ret); + dai_link->stream_name, ret); return ret; } ret = soc_link_dai_pcm_new(&cpu_dai, 1, rtd); @@ -1683,8 +1696,10 @@ int snd_soc_runtime_set_dai_fmt(struct snd_soc_pcm_runtime *rtd, } } - /* Flip the polarity for the "CPU" end of a CODEC<->CODEC link */ - /* the component which has non_legacy_dai_naming is Codec */ + /* + * Flip the polarity for the "CPU" end of a CODEC<->CODEC link + * the component which has non_legacy_dai_naming is Codec + */ if (cpu_dai->component->driver->non_legacy_dai_naming) { unsigned int inv_dai_fmt; @@ -1718,9 +1733,9 @@ int snd_soc_runtime_set_dai_fmt(struct snd_soc_pcm_runtime *rtd, } EXPORT_SYMBOL_GPL(snd_soc_runtime_set_dai_fmt); - #ifdef CONFIG_DMI -/* Trim special characters, and replace '-' with '_' since '-' is used to +/* + * Trim special characters, and replace '-' with '_' since '-' is used to * separate different DMI fields in the card long name. Only number and * alphabet characters and a few separator characters are kept. */ @@ -1739,7 +1754,8 @@ static void cleanup_dmi_name(char *name) name[j] = '\0'; } -/* Check if a DMI field is valid, i.e. not containing any string +/* + * Check if a DMI field is valid, i.e. not containing any string * in the black list. */ static int is_dmi_valid(const char *field) @@ -1802,7 +1818,6 @@ int snd_soc_set_dmi_name(struct snd_soc_card *card, const char *flavour) return 0; } - snprintf(card->dmi_longname, sizeof(card->snd_card->longname), "%s", vendor); cleanup_dmi_name(card->dmi_longname); @@ -1818,7 +1833,8 @@ int snd_soc_set_dmi_name(struct snd_soc_card *card, const char *flavour) if (len < longname_buf_size) cleanup_dmi_name(card->dmi_longname + len); - /* some vendors like Lenovo may only put a self-explanatory + /* + * some vendors like Lenovo may only put a self-explanatory * name in the product version field */ product_version = dmi_get_system_info(DMI_PRODUCT_VERSION); @@ -1914,7 +1930,8 @@ static void soc_check_tplg_fes(struct snd_soc_card *card) dai_link->be_hw_params_fixup = component->driver->be_hw_params_fixup; - /* most BE links don't set stream name, so set it to + /* + * most BE links don't set stream name, so set it to * dai link name if it's NULL to help bind widgets. */ if (!dai_link->stream_name) @@ -1924,7 +1941,7 @@ static void soc_check_tplg_fes(struct snd_soc_card *card) /* Inform userspace we are using alternate topology */ if (component->driver->topology_name_prefix) { - /* topology shortname created ? */ + /* topology shortname created? */ if (!card->topology_shortname_created) { comp_drv = component->driver; @@ -2029,7 +2046,8 @@ static int snd_soc_instantiate_card(struct snd_soc_card *card) if (ret < 0) goto probe_dai_err; - /* Find new DAI links added during probing components and bind them. + /* + * Find new DAI links added during probing components and bind them. * Components with topology may bring new DAIs and DAI links. */ for_each_card_links(card, dai_link) { @@ -2061,7 +2079,8 @@ static int snd_soc_instantiate_card(struct snd_soc_card *card) snd_soc_dapm_connect_dai_link_widgets(card); if (card->controls) - snd_soc_add_card_controls(card, card->controls, card->num_controls); + snd_soc_add_card_controls(card, card->controls, + card->num_controls); if (card->dapm_routes) snd_soc_dapm_add_routes(&card->dapm, card->dapm_routes, @@ -2207,8 +2226,10 @@ int snd_soc_poweroff(struct device *dev) if (!card->instantiated) return 0; - /* Flush out pmdown_time work - we actually do want to run it - * now, we're shutting down so no imminent restart. */ + /* + * Flush out pmdown_time work - we actually do want to run it + * now, we're shutting down so no imminent restart. + */ for_each_card_rtds(card, rtd) flush_delayed_work(&rtd->delayed_work); @@ -2301,6 +2322,7 @@ static int snd_soc_add_controls(struct snd_card *card, struct device *dev, for (i = 0; i < num_controls; i++) { const struct snd_kcontrol_new *control = &controls[i]; + err = snd_ctl_add(card, snd_soc_cnew(control, data, control->name, prefix)); if (err < 0) { @@ -2418,8 +2440,9 @@ EXPORT_SYMBOL_GPL(snd_soc_dai_set_sysclk); * * Configures the CODEC master (MCLK) or system (SYSCLK) clocking. */ -int snd_soc_component_set_sysclk(struct snd_soc_component *component, int clk_id, - int source, unsigned int freq, int dir) +int snd_soc_component_set_sysclk(struct snd_soc_component *component, + int clk_id, int source, unsigned int freq, + int dir) { if (component->driver->set_sysclk) return component->driver->set_sysclk(component, clk_id, source, @@ -2487,7 +2510,7 @@ int snd_soc_component_set_pll(struct snd_soc_component *component, int pll_id, { if (component->driver->set_pll) return component->driver->set_pll(component, pll_id, source, - freq_in, freq_out); + freq_in, freq_out); return -EINVAL; } @@ -2533,8 +2556,8 @@ EXPORT_SYMBOL_GPL(snd_soc_dai_set_fmt); * Generates the TDM tx and rx slot default masks for DAI. */ static int snd_soc_xlate_tdm_slot_mask(unsigned int slots, - unsigned int *tx_mask, - unsigned int *rx_mask) + unsigned int *tx_mask, + unsigned int *rx_mask) { if (*tx_mask || *rx_mask) return 0; @@ -2684,7 +2707,7 @@ static int snd_soc_bind_card(struct snd_soc_card *card) return ret; /* deactivate pins to sleep state */ - for_each_card_rtds(card, rtd) { + for_each_card_rtds(card, rtd) { struct snd_soc_dai *cpu_dai = rtd->cpu_dai; struct snd_soc_dai *codec_dai; int j; @@ -2799,7 +2822,7 @@ static char *fmt_single_name(struct device *dev, int *id) } } else { - /* I2C component devices are named "bus-addr" */ + /* I2C component devices are named "bus-addr" */ if (sscanf(name, "%x-%x", &id1, &id2) == 2) { char tmp[NAME_SIZE]; @@ -2807,7 +2830,8 @@ static char *fmt_single_name(struct device *dev, int *id) *id = ((id1 & 0xffff) << 16) + id2; /* sanitize component name for DAI link creation */ - snprintf(tmp, NAME_SIZE, "%s.%s", dev->driver->name, name); + snprintf(tmp, NAME_SIZE, "%s.%s", dev->driver->name, + name); strlcpy(name, tmp, NAME_SIZE); } else *id = 0; @@ -2874,7 +2898,7 @@ static struct snd_soc_dai *soc_add_dai(struct snd_soc_component *component, * component-less anymore. */ if (legacy_dai_naming && - (dai_drv->id == 0 || dai_drv->name == NULL)) { + (dai_drv->id == 0 || dai_drv->name == NULL)) { dai->name = fmt_single_name(dev, &dai->id); } else { dai->name = fmt_multiple_name(dev, dai_drv); @@ -2910,7 +2934,8 @@ static struct snd_soc_dai *soc_add_dai(struct snd_soc_component *component, * @count: Number of DAIs */ static int snd_soc_register_dais(struct snd_soc_component *component, - struct snd_soc_dai_driver *dai_drv, size_t count) + struct snd_soc_dai_driver *dai_drv, + size_t count) { struct device *dev = component->dev; struct snd_soc_dai *dai; @@ -2921,8 +2946,8 @@ static int snd_soc_register_dais(struct snd_soc_component *component, for (i = 0; i < count; i++) { - dai = soc_add_dai(component, dai_drv + i, - count == 1 && !component->driver->non_legacy_dai_naming); + dai = soc_add_dai(component, dai_drv + i, count == 1 && + !component->driver->non_legacy_dai_naming); if (dai == NULL) { ret = -ENOMEM; goto err; @@ -2966,7 +2991,8 @@ int snd_soc_register_dai(struct snd_soc_component *component, if (!dai) return -ENOMEM; - /* Create the DAI widgets here. After adding DAIs, topology may + /* + * Create the DAI widgets here. After adding DAIs, topology may * also add routes that need these widgets as source or sink. */ ret = snd_soc_dapm_new_dai_widgets(dapm, dai); @@ -3048,7 +3074,8 @@ static void snd_soc_component_setup_regmap(struct snd_soc_component *component) #ifdef CONFIG_REGMAP /** - * snd_soc_component_init_regmap() - Initialize regmap instance for the component + * snd_soc_component_init_regmap() - Initialize regmap instance for the + * component * @component: The component for which to initialize the regmap instance * @regmap: The regmap instance that should be used by the component * @@ -3066,7 +3093,8 @@ void snd_soc_component_init_regmap(struct snd_soc_component *component, EXPORT_SYMBOL_GPL(snd_soc_component_init_regmap); /** - * snd_soc_component_exit_regmap() - De-initialize regmap instance for the component + * snd_soc_component_exit_regmap() - De-initialize regmap instance for the + * component * @component: The component for which to de-initialize the regmap instance * * Calls regmap_exit() on the regmap instance associated to the component and @@ -3090,7 +3118,8 @@ static void snd_soc_component_add(struct snd_soc_component *component) if (!component->driver->write && !component->driver->read) { if (!component->regmap) - component->regmap = dev_get_regmap(component->dev, NULL); + component->regmap = dev_get_regmap(component->dev, + NULL); if (component->regmap) snd_soc_component_setup_regmap(component); } @@ -3235,23 +3264,24 @@ static int __snd_soc_unregister_component(struct device *dev) if (dev != component->dev) continue; - snd_soc_tplg_component_remove(component, SND_SOC_TPLG_INDEX_ALL); + snd_soc_tplg_component_remove(component, + SND_SOC_TPLG_INDEX_ALL); snd_soc_component_del_unlocked(component); found = 1; break; } mutex_unlock(&client_mutex); - if (found) { + if (found) snd_soc_component_cleanup(component); - } return found; } void snd_soc_unregister_component(struct device *dev) { - while (__snd_soc_unregister_component(dev)); + while (__snd_soc_unregister_component(dev)) + ; } EXPORT_SYMBOL_GPL(snd_soc_unregister_component); @@ -3832,7 +3862,7 @@ int snd_soc_of_get_dai_link_codecs(struct device *dev, for_each_link_codecs(dai_link, index, component) { ret = of_parse_phandle_with_args(of_node, name, "#sound-dai-cells", - index, &args); + index, &args); if (ret) goto err; component->of_node = args.np; From af16112457d8175b444baa9aac02558a1e1154b5 Mon Sep 17 00:00:00 2001 From: Olivier Moysan Date: Mon, 15 Oct 2018 16:03:33 +0200 Subject: [PATCH 288/299] ASoC: dt-bindings: add mclk provider support to stm32 sai add mclk provider support to stm32 sai Signed-off-by: Olivier Moysan Signed-off-by: Mark Brown --- Documentation/devicetree/bindings/sound/st,stm32-sai.txt | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/Documentation/devicetree/bindings/sound/st,stm32-sai.txt b/Documentation/devicetree/bindings/sound/st,stm32-sai.txt index 3a3fc506e43a..3f4467ff0aa2 100644 --- a/Documentation/devicetree/bindings/sound/st,stm32-sai.txt +++ b/Documentation/devicetree/bindings/sound/st,stm32-sai.txt @@ -31,7 +31,11 @@ SAI subnodes required properties: - reg: Base address and size of SAI sub-block register set. - clocks: Must contain one phandle and clock specifier pair for sai_ck which feeds the internal clock generator. + If the SAI shares a master clock, with another SAI set as MCLK + clock provider, SAI provider phandle must be specified here. - clock-names: Must contain "sai_ck". + Must also contain "MCLK", if SAI shares a master clock, + with a SAI set as MCLK clock provider. - dmas: see Documentation/devicetree/bindings/dma/stm32-dma.txt - dma-names: identifier string for each DMA request line "tx": if sai sub-block is configured as playback DAI @@ -51,6 +55,9 @@ SAI subnodes Optional properties: configured according to protocol defined in related DAI link node, such as i2s, left justified, right justified, dsp and pdm protocols. Note: ac97 protocol is not supported by SAI driver + - #clock-cells: should be 0. This property must be present if the SAI device + is a master clock provider, according to clocks bindings, described in + Documentation/devicetree/bindings/clock/clock-bindings.txt. The device node should contain one 'port' child node with one child 'endpoint' node, according to the bindings defined in Documentation/devicetree/bindings/ From 1c5083b37deaa99e07cc3082e190a509efd2a225 Mon Sep 17 00:00:00 2001 From: Olivier Moysan Date: Mon, 15 Oct 2018 16:03:34 +0200 Subject: [PATCH 289/299] ASoC: dt-bindings: add mclk support to cs42l51 Add clocks properties to cs42l51 Cirrus codec, to support master clock provider. Signed-off-by: Olivier Moysan Signed-off-by: Mark Brown --- .../devicetree/bindings/sound/cs42l51.txt | 17 +++++++++++++++++ .../devicetree/bindings/trivial-devices.txt | 1 - 2 files changed, 17 insertions(+), 1 deletion(-) create mode 100644 Documentation/devicetree/bindings/sound/cs42l51.txt diff --git a/Documentation/devicetree/bindings/sound/cs42l51.txt b/Documentation/devicetree/bindings/sound/cs42l51.txt new file mode 100644 index 000000000000..4b5de33ce377 --- /dev/null +++ b/Documentation/devicetree/bindings/sound/cs42l51.txt @@ -0,0 +1,17 @@ +CS42L51 audio CODEC + +Optional properties: + + - clocks : a list of phandles + clock-specifiers, one for each entry in + clock-names + + - clock-names : must contain "MCLK" + +Example: + +cs42l51: cs42l51@4a { + compatible = "cirrus,cs42l51"; + reg = <0x4a>; + clocks = <&mclk_prov>; + clock-names = "MCLK"; +}; diff --git a/Documentation/devicetree/bindings/trivial-devices.txt b/Documentation/devicetree/bindings/trivial-devices.txt index 763a2808a95c..69c934aec13b 100644 --- a/Documentation/devicetree/bindings/trivial-devices.txt +++ b/Documentation/devicetree/bindings/trivial-devices.txt @@ -35,7 +35,6 @@ at,24c08 i2c serial eeprom (24cxx) atmel,at97sc3204t i2c trusted platform module (TPM) capella,cm32181 CM32181: Ambient Light Sensor capella,cm3232 CM3232: Ambient Light Sensor -cirrus,cs42l51 Cirrus Logic CS42L51 audio codec dallas,ds1374 I2C, 32-Bit Binary Counter Watchdog RTC with Trickle Charger and Reset Input/Output dallas,ds1631 High-Precision Digital Thermometer dallas,ds1672 Dallas DS1672 Real-time Clock From 8307b2afd386ccce369821daa2196068c47fe8cd Mon Sep 17 00:00:00 2001 From: Olivier Moysan Date: Mon, 15 Oct 2018 16:03:35 +0200 Subject: [PATCH 290/299] ASoC: stm32: sai: set sai as mclk clock provider Add master clock generation support in STM32 SAI. The master clock provided by SAI can be used to feed a codec. Signed-off-by: Olivier Moysan Signed-off-by: Mark Brown --- sound/soc/stm/stm32_sai.h | 3 + sound/soc/stm/stm32_sai_sub.c | 275 +++++++++++++++++++++++++++++----- 2 files changed, 242 insertions(+), 36 deletions(-) diff --git a/sound/soc/stm/stm32_sai.h b/sound/soc/stm/stm32_sai.h index f25422174909..08de899c766b 100644 --- a/sound/soc/stm/stm32_sai.h +++ b/sound/soc/stm/stm32_sai.h @@ -91,6 +91,9 @@ #define SAI_XCR1_OSR_SHIFT 26 #define SAI_XCR1_OSR BIT(SAI_XCR1_OSR_SHIFT) +#define SAI_XCR1_MCKEN_SHIFT 27 +#define SAI_XCR1_MCKEN BIT(SAI_XCR1_MCKEN_SHIFT) + /******************* Bit definition for SAI_XCR2 register *******************/ #define SAI_XCR2_FTH_SHIFT 0 #define SAI_XCR2_FTH_MASK GENMASK(2, SAI_XCR2_FTH_SHIFT) diff --git a/sound/soc/stm/stm32_sai_sub.c b/sound/soc/stm/stm32_sai_sub.c index 56a227e0bd71..31d22abd3204 100644 --- a/sound/soc/stm/stm32_sai_sub.c +++ b/sound/soc/stm/stm32_sai_sub.c @@ -17,6 +17,7 @@ */ #include +#include #include #include #include @@ -68,6 +69,8 @@ #define SAI_IEC60958_BLOCK_FRAMES 192 #define SAI_IEC60958_STATUS_BYTES 24 +#define SAI_MCLK_NAME_LEN 32 + /** * struct stm32_sai_sub_data - private data of SAI sub block (block A or B) * @pdev: device data pointer @@ -80,6 +83,7 @@ * @pdata: SAI block parent data pointer * @np_sync_provider: synchronization provider node * @sai_ck: kernel clock feeding the SAI clock generator + * @sai_mclk: master clock from SAI mclk provider * @phys_addr: SAI registers physical base address * @mclk_rate: SAI block master clock frequency (Hz). set at init * @id: SAI sub block id corresponding to sub-block A or B @@ -110,6 +114,7 @@ struct stm32_sai_sub_data { struct stm32_sai_data *pdata; struct device_node *np_sync_provider; struct clk *sai_ck; + struct clk *sai_mclk; dma_addr_t phys_addr; unsigned int mclk_rate; unsigned int id; @@ -251,6 +256,177 @@ static const struct snd_kcontrol_new iec958_ctls = { .put = snd_pcm_iec958_put, }; +struct stm32_sai_mclk_data { + struct clk_hw hw; + unsigned long freq; + struct stm32_sai_sub_data *sai_data; +}; + +#define to_mclk_data(_hw) container_of(_hw, struct stm32_sai_mclk_data, hw) +#define STM32_SAI_MAX_CLKS 1 + +static int stm32_sai_get_clk_div(struct stm32_sai_sub_data *sai, + unsigned long input_rate, + unsigned long output_rate) +{ + int version = sai->pdata->conf->version; + int div; + + div = DIV_ROUND_CLOSEST(input_rate, output_rate); + if (div > SAI_XCR1_MCKDIV_MAX(version)) { + dev_err(&sai->pdev->dev, "Divider %d out of range\n", div); + return -EINVAL; + } + dev_dbg(&sai->pdev->dev, "SAI divider %d\n", div); + + if (input_rate % div) + dev_dbg(&sai->pdev->dev, + "Rate not accurate. requested (%ld), actual (%ld)\n", + output_rate, input_rate / div); + + return div; +} + +static int stm32_sai_set_clk_div(struct stm32_sai_sub_data *sai, + unsigned int div) +{ + int version = sai->pdata->conf->version; + int ret, cr1, mask; + + if (div > SAI_XCR1_MCKDIV_MAX(version)) { + dev_err(&sai->pdev->dev, "Divider %d out of range\n", div); + return -EINVAL; + } + + mask = SAI_XCR1_MCKDIV_MASK(SAI_XCR1_MCKDIV_WIDTH(version)); + cr1 = SAI_XCR1_MCKDIV_SET(div); + ret = regmap_update_bits(sai->regmap, STM_SAI_CR1_REGX, mask, cr1); + if (ret < 0) + dev_err(&sai->pdev->dev, "Failed to update CR1 register\n"); + + return ret; +} + +static long stm32_sai_mclk_round_rate(struct clk_hw *hw, unsigned long rate, + unsigned long *prate) +{ + struct stm32_sai_mclk_data *mclk = to_mclk_data(hw); + struct stm32_sai_sub_data *sai = mclk->sai_data; + int div; + + div = stm32_sai_get_clk_div(sai, *prate, rate); + if (div < 0) + return div; + + mclk->freq = *prate / div; + + return mclk->freq; +} + +static unsigned long stm32_sai_mclk_recalc_rate(struct clk_hw *hw, + unsigned long parent_rate) +{ + struct stm32_sai_mclk_data *mclk = to_mclk_data(hw); + + return mclk->freq; +} + +static int stm32_sai_mclk_set_rate(struct clk_hw *hw, unsigned long rate, + unsigned long parent_rate) +{ + struct stm32_sai_mclk_data *mclk = to_mclk_data(hw); + struct stm32_sai_sub_data *sai = mclk->sai_data; + unsigned int div; + int ret; + + div = stm32_sai_get_clk_div(sai, parent_rate, rate); + if (div < 0) + return div; + + ret = stm32_sai_set_clk_div(sai, div); + if (ret) + return ret; + + mclk->freq = rate; + + return 0; +} + +static int stm32_sai_mclk_enable(struct clk_hw *hw) +{ + struct stm32_sai_mclk_data *mclk = to_mclk_data(hw); + struct stm32_sai_sub_data *sai = mclk->sai_data; + + dev_dbg(&sai->pdev->dev, "Enable master clock\n"); + + return regmap_update_bits(sai->regmap, STM_SAI_CR1_REGX, + SAI_XCR1_MCKEN, SAI_XCR1_MCKEN); +} + +static void stm32_sai_mclk_disable(struct clk_hw *hw) +{ + struct stm32_sai_mclk_data *mclk = to_mclk_data(hw); + struct stm32_sai_sub_data *sai = mclk->sai_data; + + dev_dbg(&sai->pdev->dev, "Disable master clock\n"); + + regmap_update_bits(sai->regmap, STM_SAI_CR1_REGX, SAI_XCR1_MCKEN, 0); +} + +static const struct clk_ops mclk_ops = { + .enable = stm32_sai_mclk_enable, + .disable = stm32_sai_mclk_disable, + .recalc_rate = stm32_sai_mclk_recalc_rate, + .round_rate = stm32_sai_mclk_round_rate, + .set_rate = stm32_sai_mclk_set_rate, +}; + +static int stm32_sai_add_mclk_provider(struct stm32_sai_sub_data *sai) +{ + struct clk_hw *hw; + struct stm32_sai_mclk_data *mclk; + struct device *dev = &sai->pdev->dev; + const char *pname = __clk_get_name(sai->sai_ck); + char *mclk_name, *p, *s = (char *)pname; + int ret, i = 0; + + mclk = devm_kzalloc(dev, sizeof(mclk), GFP_KERNEL); + if (!mclk) + return -ENOMEM; + + mclk_name = devm_kcalloc(dev, sizeof(char), + SAI_MCLK_NAME_LEN, GFP_KERNEL); + if (!mclk_name) + return -ENOMEM; + + /* + * Forge mclk clock name from parent clock name and suffix. + * String after "_" char is stripped in parent name. + */ + p = mclk_name; + while (*s && *s != '_' && (i < (SAI_MCLK_NAME_LEN - 6))) { + *p++ = *s++; + i++; + } + STM_SAI_IS_SUB_A(sai) ? + strncat(p, "a_mclk", 6) : strncat(p, "b_mclk", 6); + + mclk->hw.init = CLK_HW_INIT(mclk_name, pname, &mclk_ops, 0); + mclk->sai_data = sai; + hw = &mclk->hw; + + dev_dbg(dev, "Register master clock %s\n", mclk_name); + ret = devm_clk_hw_register(&sai->pdev->dev, hw); + if (ret) { + dev_err(dev, "mclk register returned %d\n", ret); + return ret; + } + sai->sai_mclk = hw->clk; + + /* register mclk provider */ + return devm_of_clk_add_hw_provider(dev, of_clk_hw_simple_get, hw); +} + static irqreturn_t stm32_sai_isr(int irq, void *devid) { struct stm32_sai_sub_data *sai = (struct stm32_sai_sub_data *)devid; @@ -312,15 +488,25 @@ static int stm32_sai_set_sysclk(struct snd_soc_dai *cpu_dai, struct stm32_sai_sub_data *sai = snd_soc_dai_get_drvdata(cpu_dai); int ret; - if ((dir == SND_SOC_CLOCK_OUT) && sai->master) { + if (dir == SND_SOC_CLOCK_OUT) { ret = regmap_update_bits(sai->regmap, STM_SAI_CR1_REGX, SAI_XCR1_NODIV, (unsigned int)~SAI_XCR1_NODIV); if (ret < 0) return ret; - sai->mclk_rate = freq; dev_dbg(cpu_dai->dev, "SAI MCLK frequency is %uHz\n", freq); + sai->mclk_rate = freq; + + if (sai->sai_mclk) { + ret = clk_set_rate_exclusive(sai->sai_mclk, + sai->mclk_rate); + if (ret) { + dev_err(cpu_dai->dev, + "Could not set mclk rate\n"); + return ret; + } + } } return 0; @@ -715,15 +901,9 @@ static int stm32_sai_configure_clock(struct snd_soc_dai *cpu_dai, { struct stm32_sai_sub_data *sai = snd_soc_dai_get_drvdata(cpu_dai); int cr1, mask, div = 0; - int sai_clk_rate, mclk_ratio, den, ret; - int version = sai->pdata->conf->version; + int sai_clk_rate, mclk_ratio, den; unsigned int rate = params_rate(params); - if (!sai->mclk_rate) { - dev_err(cpu_dai->dev, "Mclk rate is null\n"); - return -EINVAL; - } - if (!(rate % 11025)) clk_set_parent(sai->sai_ck, sai->pdata->clk_x11k); else @@ -731,14 +911,22 @@ static int stm32_sai_configure_clock(struct snd_soc_dai *cpu_dai, sai_clk_rate = clk_get_rate(sai->sai_ck); if (STM_SAI_IS_F4(sai->pdata)) { - /* - * mclk_rate = 256 * fs - * MCKDIV = 0 if sai_ck < 3/2 * mclk_rate - * MCKDIV = sai_ck / (2 * mclk_rate) otherwise + /* mclk on (NODIV=0) + * mclk_rate = 256 * fs + * MCKDIV = 0 if sai_ck < 3/2 * mclk_rate + * MCKDIV = sai_ck / (2 * mclk_rate) otherwise + * mclk off (NODIV=1) + * MCKDIV ignored. sck = sai_ck */ - if (2 * sai_clk_rate >= 3 * sai->mclk_rate) - div = DIV_ROUND_CLOSEST(sai_clk_rate, - 2 * sai->mclk_rate); + if (!sai->mclk_rate) + return 0; + + if (2 * sai_clk_rate >= 3 * sai->mclk_rate) { + div = stm32_sai_get_clk_div(sai, sai_clk_rate, + 2 * sai->mclk_rate); + if (div < 0) + return div; + } } else { /* * TDM mode : @@ -750,8 +938,10 @@ static int stm32_sai_configure_clock(struct snd_soc_dai *cpu_dai, * Note: NOMCK/NODIV correspond to same bit. */ if (STM_SAI_PROTOCOL_IS_SPDIF(sai)) { - div = DIV_ROUND_CLOSEST(sai_clk_rate, - (params_rate(params) * 128)); + div = stm32_sai_get_clk_div(sai, sai_clk_rate, + rate * 128); + if (div < 0) + return div; } else { if (sai->mclk_rate) { mclk_ratio = sai->mclk_rate / rate; @@ -764,31 +954,22 @@ static int stm32_sai_configure_clock(struct snd_soc_dai *cpu_dai, mclk_ratio); return -EINVAL; } - div = DIV_ROUND_CLOSEST(sai_clk_rate, - sai->mclk_rate); + div = stm32_sai_get_clk_div(sai, sai_clk_rate, + sai->mclk_rate); + if (div < 0) + return div; } else { /* mclk-fs not set, master clock not active */ den = sai->fs_length * params_rate(params); - div = DIV_ROUND_CLOSEST(sai_clk_rate, den); + div = stm32_sai_get_clk_div(sai, sai_clk_rate, + den); + if (div < 0) + return div; } } } - if (div > SAI_XCR1_MCKDIV_MAX(version)) { - dev_err(cpu_dai->dev, "Divider %d out of range\n", div); - return -EINVAL; - } - dev_dbg(cpu_dai->dev, "SAI clock %d, divider %d\n", sai_clk_rate, div); - - mask = SAI_XCR1_MCKDIV_MASK(SAI_XCR1_MCKDIV_WIDTH(version)); - cr1 = SAI_XCR1_MCKDIV_SET(div); - ret = regmap_update_bits(sai->regmap, STM_SAI_CR1_REGX, mask, cr1); - if (ret < 0) { - dev_err(cpu_dai->dev, "Failed to update CR1 register\n"); - return ret; - } - - return 0; + return stm32_sai_set_clk_div(sai, div); } static int stm32_sai_hw_params(struct snd_pcm_substream *substream, @@ -881,6 +1062,9 @@ static void stm32_sai_shutdown(struct snd_pcm_substream *substream, SAI_XCR1_NODIV); clk_disable_unprepare(sai->sai_ck); + + clk_rate_exclusive_put(sai->sai_mclk); + sai->substream = NULL; } @@ -903,6 +1087,8 @@ static int stm32_sai_dai_probe(struct snd_soc_dai *cpu_dai) struct stm32_sai_sub_data *sai = dev_get_drvdata(cpu_dai->dev); int cr1 = 0, cr1_mask; + sai->cpu_dai = cpu_dai; + sai->dma_params.addr = (dma_addr_t)(sai->phys_addr + STM_SAI_DR_REGX); /* * DMA supports 4, 8 or 16 burst sizes. Burst size 4 is the best choice, @@ -1181,6 +1367,23 @@ static int stm32_sai_sub_parse_of(struct platform_device *pdev, return PTR_ERR(sai->sai_ck); } + if (STM_SAI_IS_F4(sai->pdata)) + return 0; + + /* Register mclk provider if requested */ + if (of_find_property(np, "#clock-cells", NULL)) { + ret = stm32_sai_add_mclk_provider(sai); + if (ret < 0) + return ret; + } else { + sai->sai_mclk = devm_clk_get(&pdev->dev, "MCLK"); + if (IS_ERR(sai->sai_mclk)) { + if (PTR_ERR(sai->sai_mclk) != -ENOENT) + return PTR_ERR(sai->sai_mclk); + sai->sai_mclk = NULL; + } + } + return 0; } From 5e8d63a726f8f2fef089515e9a501785cc67dcdc Mon Sep 17 00:00:00 2001 From: Olivier Moysan Date: Mon, 15 Oct 2018 16:03:36 +0200 Subject: [PATCH 291/299] ASoC: cs42l51: add mclk support Add MCLK dapm to allow configuration of cirrus CS42l51 codec as a master clock consumer. Signed-off-by: Olivier Moysan Signed-off-by: Mark Brown --- sound/soc/codecs/cs42l51.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/sound/soc/codecs/cs42l51.c b/sound/soc/codecs/cs42l51.c index 5080d7a3c279..eb40bff54cec 100644 --- a/sound/soc/codecs/cs42l51.c +++ b/sound/soc/codecs/cs42l51.c @@ -237,6 +237,10 @@ static const struct snd_soc_dapm_widget cs42l51_dapm_widgets[] = { &cs42l51_adcr_mux_controls), }; +static const struct snd_soc_dapm_widget cs42l51_dapm_mclk_widgets[] = { + SND_SOC_DAPM_CLOCK_SUPPLY("MCLK") +}; + static const struct snd_soc_dapm_route cs42l51_routes[] = { {"HPL", NULL, "Left DAC"}, {"HPR", NULL, "Right DAC"}, @@ -487,6 +491,10 @@ static struct snd_soc_dai_driver cs42l51_dai = { static int cs42l51_component_probe(struct snd_soc_component *component) { int ret, reg; + struct snd_soc_dapm_context *dapm; + + dapm = snd_soc_component_get_dapm(component); + snd_soc_dapm_new_controls(dapm, cs42l51_dapm_mclk_widgets, 1); /* * DAC configuration From 2a2aefa41ce48ace8e1e963cb10c3f5ff43aa994 Mon Sep 17 00:00:00 2001 From: Richard Fitzgerald Date: Fri, 19 Oct 2018 13:25:15 +0100 Subject: [PATCH 292/299] ASoC: wm_adsp: Rename memory fields in wm_adsp_buffer The wm_adsp_buffer struct is the control header of a circular buffer used to transfer data from the firmware over the control interface to an ALSA compressed stream. The original names of the fields pointing to the data buffer were based on ADSP2V2 memory layout where they correspond to {XM, XM, YM}. But this circular buffer could be used on other types of DSP core that have different memory region types. Also the names and description of the size fields were not very clear. The field names and descriptions have been changed to be generic and not imply any particular memory types. This patch updates the wm_adsp driver to the new field names. Signed-off-by: Richard Fitzgerald Signed-off-by: Mark Brown --- sound/soc/codecs/wm_adsp.c | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/sound/soc/codecs/wm_adsp.c b/sound/soc/codecs/wm_adsp.c index f61656070225..7ae10c632614 100644 --- a/sound/soc/codecs/wm_adsp.c +++ b/sound/soc/codecs/wm_adsp.c @@ -311,12 +311,12 @@ struct wm_adsp_alg_xm_struct { }; struct wm_adsp_buffer { - __be32 X_buf_base; /* XM base addr of first X area */ - __be32 X_buf_size; /* Size of 1st X area in words */ - __be32 X_buf_base2; /* XM base addr of 2nd X area */ - __be32 X_buf_brk; /* Total X size in words */ - __be32 Y_buf_base; /* YM base addr of Y area */ - __be32 wrap; /* Total size X and Y in words */ + __be32 buf1_base; /* Base addr of first buffer area */ + __be32 buf1_size; /* Size of buf1 area in DSP words */ + __be32 buf2_base; /* Base addr of 2nd buffer area */ + __be32 buf1_buf2_size; /* Size of buf1+buf2 in DSP words */ + __be32 buf3_base; /* Base addr of buf3 area */ + __be32 buf_total_size; /* Size of buf1+buf2+buf3 in DSP words */ __be32 high_water_mark; /* Point at which IRQ is asserted */ __be32 irq_count; /* bits 1-31 count IRQ assertions */ __be32 irq_ack; /* acked IRQ count, bit 0 enables IRQ */ @@ -393,18 +393,18 @@ struct wm_adsp_buffer_region_def { static const struct wm_adsp_buffer_region_def default_regions[] = { { .mem_type = WMFW_ADSP2_XM, - .base_offset = HOST_BUFFER_FIELD(X_buf_base), - .size_offset = HOST_BUFFER_FIELD(X_buf_size), + .base_offset = HOST_BUFFER_FIELD(buf1_base), + .size_offset = HOST_BUFFER_FIELD(buf1_size), }, { .mem_type = WMFW_ADSP2_XM, - .base_offset = HOST_BUFFER_FIELD(X_buf_base2), - .size_offset = HOST_BUFFER_FIELD(X_buf_brk), + .base_offset = HOST_BUFFER_FIELD(buf2_base), + .size_offset = HOST_BUFFER_FIELD(buf1_buf2_size), }, { .mem_type = WMFW_ADSP2_YM, - .base_offset = HOST_BUFFER_FIELD(Y_buf_base), - .size_offset = HOST_BUFFER_FIELD(wrap), + .base_offset = HOST_BUFFER_FIELD(buf3_base), + .size_offset = HOST_BUFFER_FIELD(buf_total_size), }, }; From e3a360b8cdede74d25807fc405e5d8bfb025692f Mon Sep 17 00:00:00 2001 From: Richard Fitzgerald Date: Fri, 19 Oct 2018 13:25:16 +0100 Subject: [PATCH 293/299] ASoC: wm_adsp: Log addresses as 8 digits in wm_adsp_buffer_populate Increase the address value width in the debug log from 4 digits to 8 digits to allow for DSP cores with larger memory address ranges. Signed-off-by: Richard Fitzgerald Signed-off-by: Mark Brown --- sound/soc/codecs/wm_adsp.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sound/soc/codecs/wm_adsp.c b/sound/soc/codecs/wm_adsp.c index 7ae10c632614..a53dc174bbf0 100644 --- a/sound/soc/codecs/wm_adsp.c +++ b/sound/soc/codecs/wm_adsp.c @@ -3345,7 +3345,7 @@ static int wm_adsp_buffer_populate(struct wm_adsp_compr_buf *buf) region->cumulative_size = offset; adsp_dbg(buf->dsp, - "region=%d type=%d base=%04x off=%04x size=%04x\n", + "region=%d type=%d base=%08x off=%08x size=%08x\n", i, region->mem_type, region->base_addr, region->offset, region->cumulative_size); } From 318e741ee13b5a72f3051d9bb6852b1f4d02d0bb Mon Sep 17 00:00:00 2001 From: Olivier Moysan Date: Fri, 19 Oct 2018 17:56:35 +0200 Subject: [PATCH 294/299] ASoC: cs42l51: fix mclk support The MCLK clock is made optional for cs42l51 codec. However, ASoC DAPM clock supply widget, expects the clock to be defined unconditionally. Register MCLK DAPM conditionally in codec driver, depending on clock presence in DT. Fixes: 5e8d63a726f8 ("ASoC: cs42l51: add mclk support") Signed-off-by: Olivier Moysan Signed-off-by: Mark Brown --- sound/soc/codecs/cs42l51.c | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/sound/soc/codecs/cs42l51.c b/sound/soc/codecs/cs42l51.c index eb40bff54cec..fd2bd74024c1 100644 --- a/sound/soc/codecs/cs42l51.c +++ b/sound/soc/codecs/cs42l51.c @@ -21,6 +21,7 @@ * - master mode *NOT* supported */ +#include #include #include #include @@ -41,6 +42,7 @@ enum master_slave_mode { struct cs42l51_private { unsigned int mclk; + struct clk *mclk_handle; unsigned int audio_mode; /* The mode (I2S or left-justified) */ enum master_slave_mode func; }; @@ -492,9 +494,13 @@ static int cs42l51_component_probe(struct snd_soc_component *component) { int ret, reg; struct snd_soc_dapm_context *dapm; + struct cs42l51_private *cs42l51; + cs42l51 = snd_soc_component_get_drvdata(component); dapm = snd_soc_component_get_dapm(component); - snd_soc_dapm_new_controls(dapm, cs42l51_dapm_mclk_widgets, 1); + + if (cs42l51->mclk_handle) + snd_soc_dapm_new_controls(dapm, cs42l51_dapm_mclk_widgets, 1); /* * DAC configuration @@ -548,6 +554,13 @@ int cs42l51_probe(struct device *dev, struct regmap *regmap) dev_set_drvdata(dev, cs42l51); + cs42l51->mclk_handle = devm_clk_get(dev, "MCLK"); + if (IS_ERR(cs42l51->mclk_handle)) { + if (PTR_ERR(cs42l51->mclk_handle) != -ENOENT) + return PTR_ERR(cs42l51->mclk_handle); + cs42l51->mclk_handle = NULL; + } + /* Verify that we have a CS42L51 */ ret = regmap_read(regmap, CS42L51_CHIP_REV_ID, &val); if (ret < 0) { From c5d09485def41cab9e75ba23abbf87080183183c Mon Sep 17 00:00:00 2001 From: Lucas Tanure Date: Fri, 19 Oct 2018 17:44:22 +0100 Subject: [PATCH 295/299] ASoC: wm2000: Remove wm2000_read helper function The return type "unsigned int" was used by the wm2000_read() function despite of the aspect that it will eventually return a negative error code. The resulting function doesn't add much to the code, so replace wm2000_read with regmap_read. Signed-off-by: Lucas Tanure Acked-by: Charles Keepax Signed-off-by: Mark Brown --- sound/soc/codecs/wm2000.c | 54 ++++++++++++++++++++++----------------- 1 file changed, 30 insertions(+), 24 deletions(-) diff --git a/sound/soc/codecs/wm2000.c b/sound/soc/codecs/wm2000.c index c5ae07234a00..bba330e30162 100644 --- a/sound/soc/codecs/wm2000.c +++ b/sound/soc/codecs/wm2000.c @@ -88,19 +88,6 @@ static int wm2000_write(struct i2c_client *i2c, unsigned int reg, return regmap_write(wm2000->regmap, reg, value); } -static unsigned int wm2000_read(struct i2c_client *i2c, unsigned int r) -{ - struct wm2000_priv *wm2000 = i2c_get_clientdata(i2c); - unsigned int val; - int ret; - - ret = regmap_read(wm2000->regmap, r, &val); - if (ret < 0) - return -1; - - return val; -} - static void wm2000_reset(struct wm2000_priv *wm2000) { struct i2c_client *i2c = wm2000->i2c; @@ -115,14 +102,15 @@ static void wm2000_reset(struct wm2000_priv *wm2000) static int wm2000_poll_bit(struct i2c_client *i2c, unsigned int reg, u8 mask) { + struct wm2000_priv *wm2000 = i2c_get_clientdata(i2c); int timeout = 4000; - int val; + unsigned int val; - val = wm2000_read(i2c, reg); + regmap_read(wm2000->regmap, reg, &val); while (!(val & mask) && --timeout) { msleep(1); - val = wm2000_read(i2c, reg); + regmap_read(wm2000->regmap, reg, &val); } if (timeout == 0) @@ -135,6 +123,7 @@ static int wm2000_power_up(struct i2c_client *i2c, int analogue) { struct wm2000_priv *wm2000 = dev_get_drvdata(&i2c->dev); unsigned long rate; + unsigned int val; int ret; if (WARN_ON(wm2000->anc_mode != ANC_OFF)) @@ -213,12 +202,17 @@ static int wm2000_power_up(struct i2c_client *i2c, int analogue) WM2000_MODE_THERMAL_ENABLE); } - ret = wm2000_read(i2c, WM2000_REG_SPEECH_CLARITY); + ret = regmap_read(wm2000->regmap, WM2000_REG_SPEECH_CLARITY, &val); + if (ret != 0) { + dev_err(&i2c->dev, "Unable to read Speech Clarity: %d\n", ret); + regulator_bulk_disable(WM2000_NUM_SUPPLIES, wm2000->supplies); + return ret; + } if (wm2000->speech_clarity) - ret |= WM2000_SPEECH_CLARITY; + val |= WM2000_SPEECH_CLARITY; else - ret &= ~WM2000_SPEECH_CLARITY; - wm2000_write(i2c, WM2000_REG_SPEECH_CLARITY, ret); + val &= ~WM2000_SPEECH_CLARITY; + wm2000_write(i2c, WM2000_REG_SPEECH_CLARITY, val); wm2000_write(i2c, WM2000_REG_SYS_START0, 0x33); wm2000_write(i2c, WM2000_REG_SYS_START1, 0x02); @@ -824,7 +818,7 @@ static int wm2000_i2c_probe(struct i2c_client *i2c, const char *filename; const struct firmware *fw = NULL; int ret, i; - int reg; + unsigned int reg; u16 id; wm2000 = devm_kzalloc(&i2c->dev, sizeof(*wm2000), GFP_KERNEL); @@ -860,9 +854,17 @@ static int wm2000_i2c_probe(struct i2c_client *i2c, } /* Verify that this is a WM2000 */ - reg = wm2000_read(i2c, WM2000_REG_ID1); + ret = regmap_read(wm2000->regmap, WM2000_REG_ID1, ®); + if (ret != 0) { + dev_err(&i2c->dev, "Unable to read ID1: %d\n", ret); + return ret; + } id = reg << 8; - reg = wm2000_read(i2c, WM2000_REG_ID2); + ret = regmap_read(wm2000->regmap, WM2000_REG_ID2, ®); + if (ret != 0) { + dev_err(&i2c->dev, "Unable to read ID2: %d\n", ret); + return ret; + } id |= reg & 0xff; if (id != 0x2000) { @@ -871,7 +873,11 @@ static int wm2000_i2c_probe(struct i2c_client *i2c, goto err_supplies; } - reg = wm2000_read(i2c, WM2000_REG_REVISON); + ret = regmap_read(wm2000->regmap, WM2000_REG_REVISON, ®); + if (ret != 0) { + dev_err(&i2c->dev, "Unable to read Revision: %d\n", ret); + return ret; + } dev_info(&i2c->dev, "revision %c\n", reg + 'A'); wm2000->mclk = devm_clk_get(&i2c->dev, "MCLK"); From 7f91e2af1a4a2c34fc2e8fb046c722e1a9c85399 Mon Sep 17 00:00:00 2001 From: Vasily Khoruzhick Date: Sun, 21 Oct 2018 08:39:11 -0700 Subject: [PATCH 296/299] ASoC: sun4i-i2s: move code from startup/shutdown hooks into pm_runtime hooks startup() and shutdown() hooks are called for both substreams, so stopping either substream when another is running breaks the latter. E.g. playback breaks if capture is stopped when playback is running. Move code from startup() and shutdown() to resume() and suspend() hooks respectively to fix this issue Signed-off-by: Vasily Khoruzhick Acked-by: Maxime Ripard Signed-off-by: Mark Brown --- sound/soc/sunxi/sun4i-i2s.c | 61 +++++++++++++++---------------------- 1 file changed, 25 insertions(+), 36 deletions(-) diff --git a/sound/soc/sunxi/sun4i-i2s.c b/sound/soc/sunxi/sun4i-i2s.c index c63d226e2436..d5ec1a20499d 100644 --- a/sound/soc/sunxi/sun4i-i2s.c +++ b/sound/soc/sunxi/sun4i-i2s.c @@ -644,40 +644,6 @@ static int sun4i_i2s_trigger(struct snd_pcm_substream *substream, int cmd, return 0; } -static int sun4i_i2s_startup(struct snd_pcm_substream *substream, - struct snd_soc_dai *dai) -{ - struct sun4i_i2s *i2s = snd_soc_dai_get_drvdata(dai); - - /* Enable the whole hardware block */ - regmap_update_bits(i2s->regmap, SUN4I_I2S_CTRL_REG, - SUN4I_I2S_CTRL_GL_EN, SUN4I_I2S_CTRL_GL_EN); - - /* Enable the first output line */ - regmap_update_bits(i2s->regmap, SUN4I_I2S_CTRL_REG, - SUN4I_I2S_CTRL_SDO_EN_MASK, - SUN4I_I2S_CTRL_SDO_EN(0)); - - - return clk_prepare_enable(i2s->mod_clk); -} - -static void sun4i_i2s_shutdown(struct snd_pcm_substream *substream, - struct snd_soc_dai *dai) -{ - struct sun4i_i2s *i2s = snd_soc_dai_get_drvdata(dai); - - clk_disable_unprepare(i2s->mod_clk); - - /* Disable our output lines */ - regmap_update_bits(i2s->regmap, SUN4I_I2S_CTRL_REG, - SUN4I_I2S_CTRL_SDO_EN_MASK, 0); - - /* Disable the whole hardware block */ - regmap_update_bits(i2s->regmap, SUN4I_I2S_CTRL_REG, - SUN4I_I2S_CTRL_GL_EN, 0); -} - static int sun4i_i2s_set_sysclk(struct snd_soc_dai *dai, int clk_id, unsigned int freq, int dir) { @@ -695,8 +661,6 @@ static const struct snd_soc_dai_ops sun4i_i2s_dai_ops = { .hw_params = sun4i_i2s_hw_params, .set_fmt = sun4i_i2s_set_fmt, .set_sysclk = sun4i_i2s_set_sysclk, - .shutdown = sun4i_i2s_shutdown, - .startup = sun4i_i2s_startup, .trigger = sun4i_i2s_trigger, }; @@ -869,6 +833,21 @@ static int sun4i_i2s_runtime_resume(struct device *dev) goto err_disable_clk; } + /* Enable the whole hardware block */ + regmap_update_bits(i2s->regmap, SUN4I_I2S_CTRL_REG, + SUN4I_I2S_CTRL_GL_EN, SUN4I_I2S_CTRL_GL_EN); + + /* Enable the first output line */ + regmap_update_bits(i2s->regmap, SUN4I_I2S_CTRL_REG, + SUN4I_I2S_CTRL_SDO_EN_MASK, + SUN4I_I2S_CTRL_SDO_EN(0)); + + ret = clk_prepare_enable(i2s->mod_clk); + if (ret) { + dev_err(dev, "Failed to enable module clock\n"); + goto err_disable_clk; + } + return 0; err_disable_clk: @@ -880,6 +859,16 @@ static int sun4i_i2s_runtime_suspend(struct device *dev) { struct sun4i_i2s *i2s = dev_get_drvdata(dev); + clk_disable_unprepare(i2s->mod_clk); + + /* Disable our output lines */ + regmap_update_bits(i2s->regmap, SUN4I_I2S_CTRL_REG, + SUN4I_I2S_CTRL_SDO_EN_MASK, 0); + + /* Disable the whole hardware block */ + regmap_update_bits(i2s->regmap, SUN4I_I2S_CTRL_REG, + SUN4I_I2S_CTRL_GL_EN, 0); + regcache_cache_only(i2s->regmap, true); clk_disable_unprepare(i2s->bus_clk); From b5a229350b72b929edac5ba77c825f8ebb413533 Mon Sep 17 00:00:00 2001 From: Connor McAdams Date: Sun, 21 Oct 2018 13:53:03 -0400 Subject: [PATCH 297/299] ALSA: hda/ca0132 - Actually fix microphone issue This patch fixes the microphone issue for all cards. The previous fix worked on the ZxR, but not on the AE-5 or Z. This patch has been tested to work for all cards. Signed-off-by: Connor McAdams Signed-off-by: Takashi Iwai --- sound/pci/hda/patch_ca0132.c | 73 ++++++++++++++++++------------------ 1 file changed, 37 insertions(+), 36 deletions(-) diff --git a/sound/pci/hda/patch_ca0132.c b/sound/pci/hda/patch_ca0132.c index 1a13ceae261e..f0ef52eb22a9 100644 --- a/sound/pci/hda/patch_ca0132.c +++ b/sound/pci/hda/patch_ca0132.c @@ -6983,37 +6983,44 @@ static void sbz_chipio_startup_data(struct hda_codec *codec) static void ca0132_alt_dsp_scp_startup(struct hda_codec *codec) { struct ca0132_spec *spec = codec->spec; - unsigned int tmp; + unsigned int tmp, i; - switch (spec->quirk) { - case QUIRK_SBZ: - case QUIRK_AE5: - tmp = 0x00000003; - dspio_set_uint_param_no_source(codec, 0x80, 0x0C, tmp); - tmp = 0x00000000; - dspio_set_uint_param_no_source(codec, 0x80, 0x0A, tmp); - tmp = 0x00000001; - dspio_set_uint_param_no_source(codec, 0x80, 0x0B, tmp); - tmp = 0x00000004; - dspio_set_uint_param_no_source(codec, 0x80, 0x0C, tmp); - tmp = 0x00000005; - dspio_set_uint_param_no_source(codec, 0x80, 0x0C, tmp); - tmp = 0x00000000; - dspio_set_uint_param_no_source(codec, 0x80, 0x0C, tmp); - break; - case QUIRK_R3D: - case QUIRK_R3DI: - tmp = 0x00000000; - dspio_set_uint_param_no_source(codec, 0x80, 0x0A, tmp); - tmp = 0x00000001; - dspio_set_uint_param_no_source(codec, 0x80, 0x0B, tmp); - tmp = 0x00000004; - dspio_set_uint_param_no_source(codec, 0x80, 0x0C, tmp); - tmp = 0x00000005; - dspio_set_uint_param_no_source(codec, 0x80, 0x0C, tmp); - tmp = 0x00000000; - dspio_set_uint_param_no_source(codec, 0x80, 0x0C, tmp); - break; + /* + * Gotta run these twice, or else mic works inconsistently. Not clear + * why this is, but multiple tests have confirmed it. + */ + for (i = 0; i < 2; i++) { + switch (spec->quirk) { + case QUIRK_SBZ: + case QUIRK_AE5: + tmp = 0x00000003; + dspio_set_uint_param_no_source(codec, 0x80, 0x0C, tmp); + tmp = 0x00000000; + dspio_set_uint_param_no_source(codec, 0x80, 0x0A, tmp); + tmp = 0x00000001; + dspio_set_uint_param_no_source(codec, 0x80, 0x0B, tmp); + tmp = 0x00000004; + dspio_set_uint_param_no_source(codec, 0x80, 0x0C, tmp); + tmp = 0x00000005; + dspio_set_uint_param_no_source(codec, 0x80, 0x0C, tmp); + tmp = 0x00000000; + dspio_set_uint_param_no_source(codec, 0x80, 0x0C, tmp); + break; + case QUIRK_R3D: + case QUIRK_R3DI: + tmp = 0x00000000; + dspio_set_uint_param_no_source(codec, 0x80, 0x0A, tmp); + tmp = 0x00000001; + dspio_set_uint_param_no_source(codec, 0x80, 0x0B, tmp); + tmp = 0x00000004; + dspio_set_uint_param_no_source(codec, 0x80, 0x0C, tmp); + tmp = 0x00000005; + dspio_set_uint_param_no_source(codec, 0x80, 0x0C, tmp); + tmp = 0x00000000; + dspio_set_uint_param_no_source(codec, 0x80, 0x0C, tmp); + break; + } + msleep(100); } } @@ -7246,8 +7253,6 @@ static void r3d_setup_defaults(struct hda_codec *codec) int num_fx; int idx, i; - msleep(100); - if (spec->dsp_state != DSP_DOWNLOADED) return; @@ -7292,8 +7297,6 @@ static void sbz_setup_defaults(struct hda_codec *codec) int num_fx; int idx, i; - msleep(100); - if (spec->dsp_state != DSP_DOWNLOADED) return; @@ -7351,8 +7354,6 @@ static void ae5_setup_defaults(struct hda_codec *codec) int num_fx; int idx, i; - msleep(100); - if (spec->dsp_state != DSP_DOWNLOADED) return; From e6d7942ce602e99d506a7c08f1935a274645dfda Mon Sep 17 00:00:00 2001 From: Olivier Moysan Date: Mon, 22 Oct 2018 17:10:45 +0200 Subject: [PATCH 298/299] ASoC: stm32: add clock dependency for sai Fixes: 8307b2afd386 ("ASoC: stm32: sai: set sai as mclk clock provider") Add COMMON_CLK dependency for STM32 SAI, as it is required by clock provider. Signed-off-by: Olivier Moysan Signed-off-by: Mark Brown --- sound/soc/stm/Kconfig | 1 + 1 file changed, 1 insertion(+) diff --git a/sound/soc/stm/Kconfig b/sound/soc/stm/Kconfig index 9b2681397dba..c66ffa72057e 100644 --- a/sound/soc/stm/Kconfig +++ b/sound/soc/stm/Kconfig @@ -3,6 +3,7 @@ menu "STMicroelectronics STM32 SOC audio support" config SND_SOC_STM32_SAI tristate "STM32 SAI interface (Serial Audio Interface) support" depends on (ARCH_STM32 && OF) || COMPILE_TEST + depends on COMMON_CLK depends on SND_SOC select SND_SOC_GENERIC_DMAENGINE_PCM select REGMAP_MMIO From 6be0f96d799f487f05eb412d362d5a1747d665c2 Mon Sep 17 00:00:00 2001 From: Olivier Moysan Date: Mon, 22 Oct 2018 17:10:46 +0200 Subject: [PATCH 299/299] ASoC: stm32: sai: fix master clock naming Fixes: 8307b2afd386 ("ASoC: stm32: sai: set sai as mclk clock provider") Fix warning issued by strncat when bound equals to source length. Signed-off-by: Olivier Moysan Signed-off-by: Mark Brown --- sound/soc/stm/stm32_sai_sub.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/sound/soc/stm/stm32_sai_sub.c b/sound/soc/stm/stm32_sai_sub.c index 31d22abd3204..ea05cc91aa05 100644 --- a/sound/soc/stm/stm32_sai_sub.c +++ b/sound/soc/stm/stm32_sai_sub.c @@ -404,12 +404,11 @@ static int stm32_sai_add_mclk_provider(struct stm32_sai_sub_data *sai) * String after "_" char is stripped in parent name. */ p = mclk_name; - while (*s && *s != '_' && (i < (SAI_MCLK_NAME_LEN - 6))) { + while (*s && *s != '_' && (i < (SAI_MCLK_NAME_LEN - 7))) { *p++ = *s++; i++; } - STM_SAI_IS_SUB_A(sai) ? - strncat(p, "a_mclk", 6) : strncat(p, "b_mclk", 6); + STM_SAI_IS_SUB_A(sai) ? strcat(p, "a_mclk") : strcat(p, "b_mclk"); mclk->hw.init = CLK_HW_INIT(mclk_name, pname, &mclk_ops, 0); mclk->sai_data = sai;