diff options
author | Mark Brown <broonie@kernel.org> | 2018-12-18 07:23:59 -0500 |
---|---|---|
committer | Mark Brown <broonie@kernel.org> | 2018-12-18 07:23:59 -0500 |
commit | a7a850dba82498a1e050d8d153cae67ce0edb3b2 (patch) | |
tree | f2b50444022ad27f407e087a820ae5ff248e0492 /sound | |
parent | c5fd9e77be44360b4827069c59f524815517917b (diff) | |
parent | 0f4967bc21de0bb9e107f9ad3ced852daf66acd2 (diff) |
Merge branch 'asoc-4.21' into asoc-next
Diffstat (limited to 'sound')
153 files changed, 8769 insertions, 3812 deletions
diff --git a/sound/core/compress_offload.c b/sound/core/compress_offload.c index 26b5e245b074..a5b09e75e787 100644 --- a/sound/core/compress_offload.c +++ b/sound/core/compress_offload.c | |||
@@ -171,7 +171,8 @@ static int snd_compr_free(struct inode *inode, struct file *f) | |||
171 | } | 171 | } |
172 | 172 | ||
173 | data->stream.ops->free(&data->stream); | 173 | data->stream.ops->free(&data->stream); |
174 | kfree(data->stream.runtime->buffer); | 174 | if (!data->stream.runtime->dma_buffer_p) |
175 | kfree(data->stream.runtime->buffer); | ||
175 | kfree(data->stream.runtime); | 176 | kfree(data->stream.runtime); |
176 | kfree(data); | 177 | kfree(data); |
177 | return 0; | 178 | return 0; |
@@ -505,7 +506,7 @@ static int snd_compr_allocate_buffer(struct snd_compr_stream *stream, | |||
505 | struct snd_compr_params *params) | 506 | struct snd_compr_params *params) |
506 | { | 507 | { |
507 | unsigned int buffer_size; | 508 | unsigned int buffer_size; |
508 | void *buffer; | 509 | void *buffer = NULL; |
509 | 510 | ||
510 | buffer_size = params->buffer.fragment_size * params->buffer.fragments; | 511 | buffer_size = params->buffer.fragment_size * params->buffer.fragments; |
511 | if (stream->ops->copy) { | 512 | if (stream->ops->copy) { |
@@ -514,7 +515,18 @@ static int snd_compr_allocate_buffer(struct snd_compr_stream *stream, | |||
514 | * the data from core | 515 | * the data from core |
515 | */ | 516 | */ |
516 | } else { | 517 | } else { |
517 | buffer = kmalloc(buffer_size, GFP_KERNEL); | 518 | if (stream->runtime->dma_buffer_p) { |
519 | |||
520 | if (buffer_size > stream->runtime->dma_buffer_p->bytes) | ||
521 | dev_err(&stream->device->dev, | ||
522 | "Not enough DMA buffer"); | ||
523 | else | ||
524 | buffer = stream->runtime->dma_buffer_p->area; | ||
525 | |||
526 | } else { | ||
527 | buffer = kmalloc(buffer_size, GFP_KERNEL); | ||
528 | } | ||
529 | |||
518 | if (!buffer) | 530 | if (!buffer) |
519 | return -ENOMEM; | 531 | return -ENOMEM; |
520 | } | 532 | } |
diff --git a/sound/soc/Kconfig b/sound/soc/Kconfig index 1cf11cf51e1d..6592a422a047 100644 --- a/sound/soc/Kconfig +++ b/sound/soc/Kconfig | |||
@@ -46,13 +46,11 @@ source "sound/soc/atmel/Kconfig" | |||
46 | source "sound/soc/au1x/Kconfig" | 46 | source "sound/soc/au1x/Kconfig" |
47 | source "sound/soc/bcm/Kconfig" | 47 | source "sound/soc/bcm/Kconfig" |
48 | source "sound/soc/cirrus/Kconfig" | 48 | source "sound/soc/cirrus/Kconfig" |
49 | source "sound/soc/davinci/Kconfig" | ||
50 | source "sound/soc/dwc/Kconfig" | 49 | source "sound/soc/dwc/Kconfig" |
51 | source "sound/soc/fsl/Kconfig" | 50 | source "sound/soc/fsl/Kconfig" |
52 | source "sound/soc/hisilicon/Kconfig" | 51 | source "sound/soc/hisilicon/Kconfig" |
53 | source "sound/soc/jz4740/Kconfig" | 52 | source "sound/soc/jz4740/Kconfig" |
54 | source "sound/soc/nuc900/Kconfig" | 53 | source "sound/soc/nuc900/Kconfig" |
55 | source "sound/soc/omap/Kconfig" | ||
56 | source "sound/soc/kirkwood/Kconfig" | 54 | source "sound/soc/kirkwood/Kconfig" |
57 | source "sound/soc/img/Kconfig" | 55 | source "sound/soc/img/Kconfig" |
58 | source "sound/soc/intel/Kconfig" | 56 | source "sound/soc/intel/Kconfig" |
@@ -70,9 +68,11 @@ source "sound/soc/sti/Kconfig" | |||
70 | source "sound/soc/stm/Kconfig" | 68 | source "sound/soc/stm/Kconfig" |
71 | source "sound/soc/sunxi/Kconfig" | 69 | source "sound/soc/sunxi/Kconfig" |
72 | source "sound/soc/tegra/Kconfig" | 70 | source "sound/soc/tegra/Kconfig" |
71 | source "sound/soc/ti/Kconfig" | ||
73 | source "sound/soc/txx9/Kconfig" | 72 | source "sound/soc/txx9/Kconfig" |
74 | source "sound/soc/uniphier/Kconfig" | 73 | source "sound/soc/uniphier/Kconfig" |
75 | source "sound/soc/ux500/Kconfig" | 74 | source "sound/soc/ux500/Kconfig" |
75 | source "sound/soc/xilinx/Kconfig" | ||
76 | source "sound/soc/xtensa/Kconfig" | 76 | source "sound/soc/xtensa/Kconfig" |
77 | source "sound/soc/zte/Kconfig" | 77 | source "sound/soc/zte/Kconfig" |
78 | 78 | ||
diff --git a/sound/soc/Makefile b/sound/soc/Makefile index 62a5f87c3cfc..48c48c1c893c 100644 --- a/sound/soc/Makefile +++ b/sound/soc/Makefile | |||
@@ -30,7 +30,6 @@ obj-$(CONFIG_SND_SOC) += atmel/ | |||
30 | obj-$(CONFIG_SND_SOC) += au1x/ | 30 | obj-$(CONFIG_SND_SOC) += au1x/ |
31 | obj-$(CONFIG_SND_SOC) += bcm/ | 31 | obj-$(CONFIG_SND_SOC) += bcm/ |
32 | obj-$(CONFIG_SND_SOC) += cirrus/ | 32 | obj-$(CONFIG_SND_SOC) += cirrus/ |
33 | obj-$(CONFIG_SND_SOC) += davinci/ | ||
34 | obj-$(CONFIG_SND_SOC) += dwc/ | 33 | obj-$(CONFIG_SND_SOC) += dwc/ |
35 | obj-$(CONFIG_SND_SOC) += fsl/ | 34 | obj-$(CONFIG_SND_SOC) += fsl/ |
36 | obj-$(CONFIG_SND_SOC) += hisilicon/ | 35 | obj-$(CONFIG_SND_SOC) += hisilicon/ |
@@ -41,7 +40,6 @@ obj-$(CONFIG_SND_SOC) += mediatek/ | |||
41 | obj-$(CONFIG_SND_SOC) += meson/ | 40 | obj-$(CONFIG_SND_SOC) += meson/ |
42 | obj-$(CONFIG_SND_SOC) += mxs/ | 41 | obj-$(CONFIG_SND_SOC) += mxs/ |
43 | obj-$(CONFIG_SND_SOC) += nuc900/ | 42 | obj-$(CONFIG_SND_SOC) += nuc900/ |
44 | obj-$(CONFIG_SND_SOC) += omap/ | ||
45 | obj-$(CONFIG_SND_SOC) += kirkwood/ | 43 | obj-$(CONFIG_SND_SOC) += kirkwood/ |
46 | obj-$(CONFIG_SND_SOC) += pxa/ | 44 | obj-$(CONFIG_SND_SOC) += pxa/ |
47 | obj-$(CONFIG_SND_SOC) += qcom/ | 45 | obj-$(CONFIG_SND_SOC) += qcom/ |
@@ -54,8 +52,10 @@ obj-$(CONFIG_SND_SOC) += sti/ | |||
54 | obj-$(CONFIG_SND_SOC) += stm/ | 52 | obj-$(CONFIG_SND_SOC) += stm/ |
55 | obj-$(CONFIG_SND_SOC) += sunxi/ | 53 | obj-$(CONFIG_SND_SOC) += sunxi/ |
56 | obj-$(CONFIG_SND_SOC) += tegra/ | 54 | obj-$(CONFIG_SND_SOC) += tegra/ |
55 | obj-$(CONFIG_SND_SOC) += ti/ | ||
57 | obj-$(CONFIG_SND_SOC) += txx9/ | 56 | obj-$(CONFIG_SND_SOC) += txx9/ |
58 | obj-$(CONFIG_SND_SOC) += uniphier/ | 57 | obj-$(CONFIG_SND_SOC) += uniphier/ |
59 | obj-$(CONFIG_SND_SOC) += ux500/ | 58 | obj-$(CONFIG_SND_SOC) += ux500/ |
59 | obj-$(CONFIG_SND_SOC) += xilinx/ | ||
60 | obj-$(CONFIG_SND_SOC) += xtensa/ | 60 | obj-$(CONFIG_SND_SOC) += xtensa/ |
61 | obj-$(CONFIG_SND_SOC) += zte/ | 61 | obj-$(CONFIG_SND_SOC) += zte/ |
diff --git a/sound/soc/amd/Kconfig b/sound/soc/amd/Kconfig index 58c1dcb4d255..33ebec990c2f 100644 --- a/sound/soc/amd/Kconfig +++ b/sound/soc/amd/Kconfig | |||
@@ -19,3 +19,9 @@ config SND_SOC_AMD_CZ_RT5645_MACH | |||
19 | depends on SND_SOC_AMD_ACP && I2C | 19 | depends on SND_SOC_AMD_ACP && I2C |
20 | help | 20 | help |
21 | This option enables machine driver for rt5645. | 21 | This option enables machine driver for rt5645. |
22 | |||
23 | config SND_SOC_AMD_ACP3x | ||
24 | tristate "AMD Audio Coprocessor-v3.x support" | ||
25 | depends on X86 && PCI | ||
26 | help | ||
27 | This option enables ACP v3.x I2S support on AMD platform | ||
diff --git a/sound/soc/amd/Makefile b/sound/soc/amd/Makefile index 79b0622fa5d3..8e1c571c3161 100644 --- a/sound/soc/amd/Makefile +++ b/sound/soc/amd/Makefile | |||
@@ -5,3 +5,4 @@ snd-soc-acp-rt5645-mach-objs := acp-rt5645.o | |||
5 | obj-$(CONFIG_SND_SOC_AMD_ACP) += acp_audio_dma.o | 5 | obj-$(CONFIG_SND_SOC_AMD_ACP) += acp_audio_dma.o |
6 | obj-$(CONFIG_SND_SOC_AMD_CZ_DA7219MX98357_MACH) += snd-soc-acp-da7219mx98357-mach.o | 6 | obj-$(CONFIG_SND_SOC_AMD_CZ_DA7219MX98357_MACH) += snd-soc-acp-da7219mx98357-mach.o |
7 | obj-$(CONFIG_SND_SOC_AMD_CZ_RT5645_MACH) += snd-soc-acp-rt5645-mach.o | 7 | obj-$(CONFIG_SND_SOC_AMD_CZ_RT5645_MACH) += snd-soc-acp-rt5645-mach.o |
8 | obj-$(CONFIG_SND_SOC_AMD_ACP3x) += raven/ | ||
diff --git a/sound/soc/amd/acp-da7219-max98357a.c b/sound/soc/amd/acp-da7219-max98357a.c index 3f813ea5210a..a5daad973ce5 100644 --- a/sound/soc/amd/acp-da7219-max98357a.c +++ b/sound/soc/amd/acp-da7219-max98357a.c | |||
@@ -403,7 +403,7 @@ static struct regulator_config acp_da7219_cfg = { | |||
403 | static struct regulator_ops acp_da7219_ops = { | 403 | static struct regulator_ops acp_da7219_ops = { |
404 | }; | 404 | }; |
405 | 405 | ||
406 | static struct regulator_desc acp_da7219_desc = { | 406 | static const struct regulator_desc acp_da7219_desc = { |
407 | .name = "reg-fixed-1.8V", | 407 | .name = "reg-fixed-1.8V", |
408 | .type = REGULATOR_VOLTAGE, | 408 | .type = REGULATOR_VOLTAGE, |
409 | .owner = THIS_MODULE, | 409 | .owner = THIS_MODULE, |
diff --git a/sound/soc/amd/acp-pcm-dma.c b/sound/soc/amd/acp-pcm-dma.c index cdebab2f8ce5..f4011bebc7ec 100644 --- a/sound/soc/amd/acp-pcm-dma.c +++ b/sound/soc/amd/acp-pcm-dma.c | |||
@@ -303,11 +303,10 @@ static void set_acp_to_i2s_dma_descriptors(void __iomem *acp_mmio, u32 size, | |||
303 | } | 303 | } |
304 | 304 | ||
305 | /* Create page table entries in ACP SRAM for the allocated memory */ | 305 | /* Create page table entries in ACP SRAM for the allocated memory */ |
306 | static void acp_pte_config(void __iomem *acp_mmio, struct page *pg, | 306 | static void acp_pte_config(void __iomem *acp_mmio, dma_addr_t addr, |
307 | u16 num_of_pages, u32 pte_offset) | 307 | u16 num_of_pages, u32 pte_offset) |
308 | { | 308 | { |
309 | u16 page_idx; | 309 | u16 page_idx; |
310 | u64 addr; | ||
311 | u32 low; | 310 | u32 low; |
312 | u32 high; | 311 | u32 high; |
313 | u32 offset; | 312 | u32 offset; |
@@ -317,7 +316,6 @@ static void acp_pte_config(void __iomem *acp_mmio, struct page *pg, | |||
317 | /* Load the low address of page int ACP SRAM through SRBM */ | 316 | /* Load the low address of page int ACP SRAM through SRBM */ |
318 | acp_reg_write((offset + (page_idx * 8)), | 317 | acp_reg_write((offset + (page_idx * 8)), |
319 | acp_mmio, mmACP_SRBM_Targ_Idx_Addr); | 318 | acp_mmio, mmACP_SRBM_Targ_Idx_Addr); |
320 | addr = page_to_phys(pg); | ||
321 | 319 | ||
322 | low = lower_32_bits(addr); | 320 | low = lower_32_bits(addr); |
323 | high = upper_32_bits(addr); | 321 | high = upper_32_bits(addr); |
@@ -333,7 +331,7 @@ static void acp_pte_config(void __iomem *acp_mmio, struct page *pg, | |||
333 | acp_reg_write(high, acp_mmio, mmACP_SRBM_Targ_Idx_Data); | 331 | acp_reg_write(high, acp_mmio, mmACP_SRBM_Targ_Idx_Data); |
334 | 332 | ||
335 | /* Move to next physically contiguos page */ | 333 | /* Move to next physically contiguos page */ |
336 | pg++; | 334 | addr += PAGE_SIZE; |
337 | } | 335 | } |
338 | } | 336 | } |
339 | 337 | ||
@@ -343,7 +341,7 @@ static void config_acp_dma(void __iomem *acp_mmio, | |||
343 | { | 341 | { |
344 | u16 ch_acp_sysmem, ch_acp_i2s; | 342 | u16 ch_acp_sysmem, ch_acp_i2s; |
345 | 343 | ||
346 | acp_pte_config(acp_mmio, rtd->pg, rtd->num_of_pages, | 344 | acp_pte_config(acp_mmio, rtd->dma_addr, rtd->num_of_pages, |
347 | rtd->pte_offset); | 345 | rtd->pte_offset); |
348 | 346 | ||
349 | if (rtd->direction == SNDRV_PCM_STREAM_PLAYBACK) { | 347 | if (rtd->direction == SNDRV_PCM_STREAM_PLAYBACK) { |
@@ -850,7 +848,6 @@ static int acp_dma_hw_params(struct snd_pcm_substream *substream, | |||
850 | int status; | 848 | int status; |
851 | uint64_t size; | 849 | uint64_t size; |
852 | u32 val = 0; | 850 | u32 val = 0; |
853 | struct page *pg; | ||
854 | struct snd_pcm_runtime *runtime; | 851 | struct snd_pcm_runtime *runtime; |
855 | struct audio_substream_data *rtd; | 852 | struct audio_substream_data *rtd; |
856 | struct snd_soc_pcm_runtime *prtd = substream->private_data; | 853 | struct snd_soc_pcm_runtime *prtd = substream->private_data; |
@@ -986,16 +983,14 @@ static int acp_dma_hw_params(struct snd_pcm_substream *substream, | |||
986 | return status; | 983 | return status; |
987 | 984 | ||
988 | memset(substream->runtime->dma_area, 0, params_buffer_bytes(params)); | 985 | memset(substream->runtime->dma_area, 0, params_buffer_bytes(params)); |
989 | pg = virt_to_page(substream->dma_buffer.area); | ||
990 | 986 | ||
991 | if (pg) { | 987 | if (substream->dma_buffer.area) { |
992 | acp_set_sram_bank_state(rtd->acp_mmio, 0, true); | 988 | acp_set_sram_bank_state(rtd->acp_mmio, 0, true); |
993 | /* Save for runtime private data */ | 989 | /* Save for runtime private data */ |
994 | rtd->pg = pg; | 990 | rtd->dma_addr = substream->dma_buffer.addr; |
995 | rtd->order = get_order(size); | 991 | rtd->order = get_order(size); |
996 | 992 | ||
997 | /* Fill the page table entries in ACP SRAM */ | 993 | /* Fill the page table entries in ACP SRAM */ |
998 | rtd->pg = pg; | ||
999 | rtd->size = size; | 994 | rtd->size = size; |
1000 | rtd->num_of_pages = PAGE_ALIGN(size) >> PAGE_SHIFT; | 995 | rtd->num_of_pages = PAGE_ALIGN(size) >> PAGE_SHIFT; |
1001 | rtd->direction = substream->stream; | 996 | rtd->direction = substream->stream; |
@@ -1151,18 +1146,21 @@ static int acp_dma_new(struct snd_soc_pcm_runtime *rtd) | |||
1151 | struct snd_soc_component *component = snd_soc_rtdcom_lookup(rtd, | 1146 | struct snd_soc_component *component = snd_soc_rtdcom_lookup(rtd, |
1152 | DRV_NAME); | 1147 | DRV_NAME); |
1153 | struct audio_drv_data *adata = dev_get_drvdata(component->dev); | 1148 | struct audio_drv_data *adata = dev_get_drvdata(component->dev); |
1149 | struct device *parent = component->dev->parent; | ||
1154 | 1150 | ||
1155 | switch (adata->asic_type) { | 1151 | switch (adata->asic_type) { |
1156 | case CHIP_STONEY: | 1152 | case CHIP_STONEY: |
1157 | ret = snd_pcm_lib_preallocate_pages_for_all(rtd->pcm, | 1153 | ret = snd_pcm_lib_preallocate_pages_for_all(rtd->pcm, |
1158 | SNDRV_DMA_TYPE_DEV, | 1154 | SNDRV_DMA_TYPE_DEV, |
1159 | NULL, ST_MIN_BUFFER, | 1155 | parent, |
1156 | ST_MIN_BUFFER, | ||
1160 | ST_MAX_BUFFER); | 1157 | ST_MAX_BUFFER); |
1161 | break; | 1158 | break; |
1162 | default: | 1159 | default: |
1163 | ret = snd_pcm_lib_preallocate_pages_for_all(rtd->pcm, | 1160 | ret = snd_pcm_lib_preallocate_pages_for_all(rtd->pcm, |
1164 | SNDRV_DMA_TYPE_DEV, | 1161 | SNDRV_DMA_TYPE_DEV, |
1165 | NULL, MIN_BUFFER, | 1162 | parent, |
1163 | MIN_BUFFER, | ||
1166 | MAX_BUFFER); | 1164 | MAX_BUFFER); |
1167 | break; | 1165 | break; |
1168 | } | 1166 | } |
diff --git a/sound/soc/amd/acp.h b/sound/soc/amd/acp.h index dbbb1a85638d..e5ab6c6040a6 100644 --- a/sound/soc/amd/acp.h +++ b/sound/soc/amd/acp.h | |||
@@ -123,7 +123,7 @@ enum acp_dma_priority_level { | |||
123 | }; | 123 | }; |
124 | 124 | ||
125 | struct audio_substream_data { | 125 | struct audio_substream_data { |
126 | struct page *pg; | 126 | dma_addr_t dma_addr; |
127 | unsigned int order; | 127 | unsigned int order; |
128 | u16 num_of_pages; | 128 | u16 num_of_pages; |
129 | u16 i2s_instance; | 129 | u16 i2s_instance; |
diff --git a/sound/soc/amd/raven/Makefile b/sound/soc/amd/raven/Makefile new file mode 100644 index 000000000000..108d1acf189b --- /dev/null +++ b/sound/soc/amd/raven/Makefile | |||
@@ -0,0 +1,6 @@ | |||
1 | # SPDX-License-Identifier: GPL-2.0+ | ||
2 | # Raven Ridge platform Support | ||
3 | snd-pci-acp3x-objs := pci-acp3x.o | ||
4 | snd-acp3x-pcm-dma-objs := acp3x-pcm-dma.o | ||
5 | obj-$(CONFIG_SND_SOC_AMD_ACP3x) += snd-pci-acp3x.o | ||
6 | obj-$(CONFIG_SND_SOC_AMD_ACP3x) += snd-acp3x-pcm-dma.o | ||
diff --git a/sound/soc/amd/raven/acp3x-pcm-dma.c b/sound/soc/amd/raven/acp3x-pcm-dma.c new file mode 100644 index 000000000000..022a8912c8a2 --- /dev/null +++ b/sound/soc/amd/raven/acp3x-pcm-dma.c | |||
@@ -0,0 +1,777 @@ | |||
1 | // SPDX-License-Identifier: GPL-2.0+ | ||
2 | // | ||
3 | // AMD ALSA SoC PCM Driver | ||
4 | // | ||
5 | //Copyright 2016 Advanced Micro Devices, Inc. | ||
6 | |||
7 | #include <linux/platform_device.h> | ||
8 | #include <linux/module.h> | ||
9 | #include <linux/err.h> | ||
10 | #include <linux/io.h> | ||
11 | #include <linux/pm_runtime.h> | ||
12 | #include <sound/pcm.h> | ||
13 | #include <sound/pcm_params.h> | ||
14 | #include <sound/soc.h> | ||
15 | #include <sound/soc-dai.h> | ||
16 | |||
17 | #include "acp3x.h" | ||
18 | |||
19 | #define DRV_NAME "acp3x-i2s-audio" | ||
20 | |||
21 | struct i2s_dev_data { | ||
22 | bool tdm_mode; | ||
23 | unsigned int i2s_irq; | ||
24 | u32 tdm_fmt; | ||
25 | void __iomem *acp3x_base; | ||
26 | struct snd_pcm_substream *play_stream; | ||
27 | struct snd_pcm_substream *capture_stream; | ||
28 | }; | ||
29 | |||
30 | struct i2s_stream_instance { | ||
31 | u16 num_pages; | ||
32 | u16 channels; | ||
33 | u32 xfer_resolution; | ||
34 | struct page *pg; | ||
35 | void __iomem *acp3x_base; | ||
36 | }; | ||
37 | |||
38 | static const struct snd_pcm_hardware acp3x_pcm_hardware_playback = { | ||
39 | .info = SNDRV_PCM_INFO_INTERLEAVED | | ||
40 | SNDRV_PCM_INFO_BLOCK_TRANSFER | | ||
41 | SNDRV_PCM_INFO_BATCH | | ||
42 | SNDRV_PCM_INFO_PAUSE | SNDRV_PCM_INFO_RESUME, | ||
43 | .formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S8 | | ||
44 | SNDRV_PCM_FMTBIT_U8 | SNDRV_PCM_FMTBIT_S24_LE | | ||
45 | SNDRV_PCM_FMTBIT_S32_LE, | ||
46 | .channels_min = 2, | ||
47 | .channels_max = 8, | ||
48 | .rates = SNDRV_PCM_RATE_8000_96000, | ||
49 | .rate_min = 8000, | ||
50 | .rate_max = 96000, | ||
51 | .buffer_bytes_max = PLAYBACK_MAX_NUM_PERIODS * PLAYBACK_MAX_PERIOD_SIZE, | ||
52 | .period_bytes_min = PLAYBACK_MIN_PERIOD_SIZE, | ||
53 | .period_bytes_max = PLAYBACK_MAX_PERIOD_SIZE, | ||
54 | .periods_min = PLAYBACK_MIN_NUM_PERIODS, | ||
55 | .periods_max = PLAYBACK_MAX_NUM_PERIODS, | ||
56 | }; | ||
57 | |||
58 | static const struct snd_pcm_hardware acp3x_pcm_hardware_capture = { | ||
59 | .info = SNDRV_PCM_INFO_INTERLEAVED | | ||
60 | SNDRV_PCM_INFO_BLOCK_TRANSFER | | ||
61 | SNDRV_PCM_INFO_BATCH | | ||
62 | SNDRV_PCM_INFO_PAUSE | SNDRV_PCM_INFO_RESUME, | ||
63 | .formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S8 | | ||
64 | SNDRV_PCM_FMTBIT_U8 | SNDRV_PCM_FMTBIT_S24_LE | | ||
65 | SNDRV_PCM_FMTBIT_S32_LE, | ||
66 | .channels_min = 2, | ||
67 | .channels_max = 2, | ||
68 | .rates = SNDRV_PCM_RATE_8000_48000, | ||
69 | .rate_min = 8000, | ||
70 | .rate_max = 48000, | ||
71 | .buffer_bytes_max = CAPTURE_MAX_NUM_PERIODS * CAPTURE_MAX_PERIOD_SIZE, | ||
72 | .period_bytes_min = CAPTURE_MIN_PERIOD_SIZE, | ||
73 | .period_bytes_max = CAPTURE_MAX_PERIOD_SIZE, | ||
74 | .periods_min = CAPTURE_MIN_NUM_PERIODS, | ||
75 | .periods_max = CAPTURE_MAX_NUM_PERIODS, | ||
76 | }; | ||
77 | |||
78 | static int acp3x_power_on(void __iomem *acp3x_base, bool on) | ||
79 | { | ||
80 | u16 val, mask; | ||
81 | u32 timeout; | ||
82 | |||
83 | if (on == true) { | ||
84 | val = 1; | ||
85 | mask = ACP3x_POWER_ON; | ||
86 | } else { | ||
87 | val = 0; | ||
88 | mask = ACP3x_POWER_OFF; | ||
89 | } | ||
90 | |||
91 | rv_writel(val, acp3x_base + mmACP_PGFSM_CONTROL); | ||
92 | timeout = 0; | ||
93 | while (true) { | ||
94 | val = rv_readl(acp3x_base + mmACP_PGFSM_STATUS); | ||
95 | if ((val & ACP3x_POWER_OFF_IN_PROGRESS) == mask) | ||
96 | break; | ||
97 | if (timeout > 100) { | ||
98 | pr_err("ACP3x power state change failure\n"); | ||
99 | return -ENODEV; | ||
100 | } | ||
101 | timeout++; | ||
102 | cpu_relax(); | ||
103 | } | ||
104 | return 0; | ||
105 | } | ||
106 | |||
107 | static int acp3x_reset(void __iomem *acp3x_base) | ||
108 | { | ||
109 | u32 val, timeout; | ||
110 | |||
111 | rv_writel(1, acp3x_base + mmACP_SOFT_RESET); | ||
112 | timeout = 0; | ||
113 | while (true) { | ||
114 | val = rv_readl(acp3x_base + mmACP_SOFT_RESET); | ||
115 | if ((val & ACP3x_SOFT_RESET__SoftResetAudDone_MASK) || | ||
116 | timeout > 100) { | ||
117 | if (val & ACP3x_SOFT_RESET__SoftResetAudDone_MASK) | ||
118 | break; | ||
119 | return -ENODEV; | ||
120 | } | ||
121 | timeout++; | ||
122 | cpu_relax(); | ||
123 | } | ||
124 | |||
125 | rv_writel(0, acp3x_base + mmACP_SOFT_RESET); | ||
126 | timeout = 0; | ||
127 | while (true) { | ||
128 | val = rv_readl(acp3x_base + mmACP_SOFT_RESET); | ||
129 | if (!val || timeout > 100) { | ||
130 | if (!val) | ||
131 | break; | ||
132 | return -ENODEV; | ||
133 | } | ||
134 | timeout++; | ||
135 | cpu_relax(); | ||
136 | } | ||
137 | return 0; | ||
138 | } | ||
139 | |||
140 | static int acp3x_init(void __iomem *acp3x_base) | ||
141 | { | ||
142 | int ret; | ||
143 | |||
144 | /* power on */ | ||
145 | ret = acp3x_power_on(acp3x_base, true); | ||
146 | if (ret) { | ||
147 | pr_err("ACP3x power on failed\n"); | ||
148 | return ret; | ||
149 | } | ||
150 | /* Reset */ | ||
151 | ret = acp3x_reset(acp3x_base); | ||
152 | if (ret) { | ||
153 | pr_err("ACP3x reset failed\n"); | ||
154 | return ret; | ||
155 | } | ||
156 | return 0; | ||
157 | } | ||
158 | |||
159 | static int acp3x_deinit(void __iomem *acp3x_base) | ||
160 | { | ||
161 | int ret; | ||
162 | |||
163 | /* Reset */ | ||
164 | ret = acp3x_reset(acp3x_base); | ||
165 | if (ret) { | ||
166 | pr_err("ACP3x reset failed\n"); | ||
167 | return ret; | ||
168 | } | ||
169 | /* power off */ | ||
170 | ret = acp3x_power_on(acp3x_base, false); | ||
171 | if (ret) { | ||
172 | pr_err("ACP3x power off failed\n"); | ||
173 | return ret; | ||
174 | } | ||
175 | return 0; | ||
176 | } | ||
177 | |||
178 | static irqreturn_t i2s_irq_handler(int irq, void *dev_id) | ||
179 | { | ||
180 | u16 play_flag, cap_flag; | ||
181 | u32 val; | ||
182 | struct i2s_dev_data *rv_i2s_data = dev_id; | ||
183 | |||
184 | if (!rv_i2s_data) | ||
185 | return IRQ_NONE; | ||
186 | |||
187 | play_flag = 0; | ||
188 | cap_flag = 0; | ||
189 | val = rv_readl(rv_i2s_data->acp3x_base + mmACP_EXTERNAL_INTR_STAT); | ||
190 | if ((val & BIT(BT_TX_THRESHOLD)) && rv_i2s_data->play_stream) { | ||
191 | rv_writel(BIT(BT_TX_THRESHOLD), rv_i2s_data->acp3x_base + | ||
192 | mmACP_EXTERNAL_INTR_STAT); | ||
193 | snd_pcm_period_elapsed(rv_i2s_data->play_stream); | ||
194 | play_flag = 1; | ||
195 | } | ||
196 | |||
197 | if ((val & BIT(BT_RX_THRESHOLD)) && rv_i2s_data->capture_stream) { | ||
198 | rv_writel(BIT(BT_RX_THRESHOLD), rv_i2s_data->acp3x_base + | ||
199 | mmACP_EXTERNAL_INTR_STAT); | ||
200 | snd_pcm_period_elapsed(rv_i2s_data->capture_stream); | ||
201 | cap_flag = 1; | ||
202 | } | ||
203 | |||
204 | if (play_flag | cap_flag) | ||
205 | return IRQ_HANDLED; | ||
206 | else | ||
207 | return IRQ_NONE; | ||
208 | } | ||
209 | |||
210 | static void config_acp3x_dma(struct i2s_stream_instance *rtd, int direction) | ||
211 | { | ||
212 | u16 page_idx; | ||
213 | u64 addr; | ||
214 | u32 low, high, val, acp_fifo_addr; | ||
215 | struct page *pg = rtd->pg; | ||
216 | |||
217 | /* 8 scratch registers used to map one 64 bit address */ | ||
218 | if (direction == SNDRV_PCM_STREAM_PLAYBACK) | ||
219 | val = 0; | ||
220 | else | ||
221 | val = rtd->num_pages * 8; | ||
222 | |||
223 | /* Group Enable */ | ||
224 | rv_writel(ACP_SRAM_PTE_OFFSET | BIT(31), rtd->acp3x_base + | ||
225 | mmACPAXI2AXI_ATU_BASE_ADDR_GRP_1); | ||
226 | rv_writel(PAGE_SIZE_4K_ENABLE, rtd->acp3x_base + | ||
227 | mmACPAXI2AXI_ATU_PAGE_SIZE_GRP_1); | ||
228 | |||
229 | for (page_idx = 0; page_idx < rtd->num_pages; page_idx++) { | ||
230 | /* Load the low address of page int ACP SRAM through SRBM */ | ||
231 | addr = page_to_phys(pg); | ||
232 | low = lower_32_bits(addr); | ||
233 | high = upper_32_bits(addr); | ||
234 | |||
235 | rv_writel(low, rtd->acp3x_base + mmACP_SCRATCH_REG_0 + val); | ||
236 | high |= BIT(31); | ||
237 | rv_writel(high, rtd->acp3x_base + mmACP_SCRATCH_REG_0 + val | ||
238 | + 4); | ||
239 | /* Move to next physically contiguos page */ | ||
240 | val += 8; | ||
241 | pg++; | ||
242 | } | ||
243 | |||
244 | if (direction == SNDRV_PCM_STREAM_PLAYBACK) { | ||
245 | /* Config ringbuffer */ | ||
246 | rv_writel(MEM_WINDOW_START, rtd->acp3x_base + | ||
247 | mmACP_BT_TX_RINGBUFADDR); | ||
248 | rv_writel(MAX_BUFFER, rtd->acp3x_base + | ||
249 | mmACP_BT_TX_RINGBUFSIZE); | ||
250 | rv_writel(DMA_SIZE, rtd->acp3x_base + mmACP_BT_TX_DMA_SIZE); | ||
251 | |||
252 | /* Config audio fifo */ | ||
253 | acp_fifo_addr = ACP_SRAM_PTE_OFFSET + (rtd->num_pages * 8) | ||
254 | + PLAYBACK_FIFO_ADDR_OFFSET; | ||
255 | rv_writel(acp_fifo_addr, rtd->acp3x_base + | ||
256 | mmACP_BT_TX_FIFOADDR); | ||
257 | rv_writel(FIFO_SIZE, rtd->acp3x_base + mmACP_BT_TX_FIFOSIZE); | ||
258 | } else { | ||
259 | /* Config ringbuffer */ | ||
260 | rv_writel(MEM_WINDOW_START + MAX_BUFFER, rtd->acp3x_base + | ||
261 | mmACP_BT_RX_RINGBUFADDR); | ||
262 | rv_writel(MAX_BUFFER, rtd->acp3x_base + | ||
263 | mmACP_BT_RX_RINGBUFSIZE); | ||
264 | rv_writel(DMA_SIZE, rtd->acp3x_base + mmACP_BT_RX_DMA_SIZE); | ||
265 | |||
266 | /* Config audio fifo */ | ||
267 | acp_fifo_addr = ACP_SRAM_PTE_OFFSET + | ||
268 | (rtd->num_pages * 8) + CAPTURE_FIFO_ADDR_OFFSET; | ||
269 | rv_writel(acp_fifo_addr, rtd->acp3x_base + | ||
270 | mmACP_BT_RX_FIFOADDR); | ||
271 | rv_writel(FIFO_SIZE, rtd->acp3x_base + mmACP_BT_RX_FIFOSIZE); | ||
272 | } | ||
273 | |||
274 | /* Enable watermark/period interrupt to host */ | ||
275 | rv_writel(BIT(BT_TX_THRESHOLD) | BIT(BT_RX_THRESHOLD), | ||
276 | rtd->acp3x_base + mmACP_EXTERNAL_INTR_CNTL); | ||
277 | } | ||
278 | |||
279 | static int acp3x_dma_open(struct snd_pcm_substream *substream) | ||
280 | { | ||
281 | int ret = 0; | ||
282 | |||
283 | struct snd_pcm_runtime *runtime = substream->runtime; | ||
284 | struct snd_soc_pcm_runtime *prtd = substream->private_data; | ||
285 | struct snd_soc_component *component = snd_soc_rtdcom_lookup(prtd, | ||
286 | DRV_NAME); | ||
287 | struct i2s_dev_data *adata = dev_get_drvdata(component->dev); | ||
288 | |||
289 | struct i2s_stream_instance *i2s_data = kzalloc(sizeof(struct i2s_stream_instance), | ||
290 | GFP_KERNEL); | ||
291 | if (!i2s_data) | ||
292 | return -EINVAL; | ||
293 | |||
294 | if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) | ||
295 | runtime->hw = acp3x_pcm_hardware_playback; | ||
296 | else | ||
297 | runtime->hw = acp3x_pcm_hardware_capture; | ||
298 | |||
299 | ret = snd_pcm_hw_constraint_integer(runtime, | ||
300 | SNDRV_PCM_HW_PARAM_PERIODS); | ||
301 | if (ret < 0) { | ||
302 | dev_err(component->dev, "set integer constraint failed\n"); | ||
303 | kfree(i2s_data); | ||
304 | return ret; | ||
305 | } | ||
306 | |||
307 | if (!adata->play_stream && !adata->capture_stream) | ||
308 | rv_writel(1, adata->acp3x_base + mmACP_EXTERNAL_INTR_ENB); | ||
309 | |||
310 | if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) | ||
311 | adata->play_stream = substream; | ||
312 | else | ||
313 | adata->capture_stream = substream; | ||
314 | |||
315 | i2s_data->acp3x_base = adata->acp3x_base; | ||
316 | runtime->private_data = i2s_data; | ||
317 | return 0; | ||
318 | } | ||
319 | |||
320 | static int acp3x_dma_hw_params(struct snd_pcm_substream *substream, | ||
321 | struct snd_pcm_hw_params *params) | ||
322 | { | ||
323 | int status; | ||
324 | u64 size; | ||
325 | struct page *pg; | ||
326 | struct snd_pcm_runtime *runtime = substream->runtime; | ||
327 | struct i2s_stream_instance *rtd = runtime->private_data; | ||
328 | |||
329 | if (!rtd) | ||
330 | return -EINVAL; | ||
331 | |||
332 | size = params_buffer_bytes(params); | ||
333 | status = snd_pcm_lib_malloc_pages(substream, size); | ||
334 | if (status < 0) | ||
335 | return status; | ||
336 | |||
337 | memset(substream->runtime->dma_area, 0, params_buffer_bytes(params)); | ||
338 | pg = virt_to_page(substream->dma_buffer.area); | ||
339 | if (pg) { | ||
340 | rtd->pg = pg; | ||
341 | rtd->num_pages = (PAGE_ALIGN(size) >> PAGE_SHIFT); | ||
342 | config_acp3x_dma(rtd, substream->stream); | ||
343 | status = 0; | ||
344 | } else { | ||
345 | status = -ENOMEM; | ||
346 | } | ||
347 | return status; | ||
348 | } | ||
349 | |||
350 | static snd_pcm_uframes_t acp3x_dma_pointer(struct snd_pcm_substream *substream) | ||
351 | { | ||
352 | u32 pos = 0; | ||
353 | struct i2s_stream_instance *rtd = substream->runtime->private_data; | ||
354 | |||
355 | if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) | ||
356 | pos = rv_readl(rtd->acp3x_base + | ||
357 | mmACP_BT_TX_LINKPOSITIONCNTR); | ||
358 | else | ||
359 | pos = rv_readl(rtd->acp3x_base + | ||
360 | mmACP_BT_RX_LINKPOSITIONCNTR); | ||
361 | |||
362 | if (pos >= MAX_BUFFER) | ||
363 | pos = 0; | ||
364 | |||
365 | return bytes_to_frames(substream->runtime, pos); | ||
366 | } | ||
367 | |||
368 | static int acp3x_dma_new(struct snd_soc_pcm_runtime *rtd) | ||
369 | { | ||
370 | return snd_pcm_lib_preallocate_pages_for_all(rtd->pcm, | ||
371 | SNDRV_DMA_TYPE_DEV, | ||
372 | NULL, MIN_BUFFER, | ||
373 | MAX_BUFFER); | ||
374 | } | ||
375 | |||
376 | static int acp3x_dma_hw_free(struct snd_pcm_substream *substream) | ||
377 | { | ||
378 | return snd_pcm_lib_free_pages(substream); | ||
379 | } | ||
380 | |||
381 | static int acp3x_dma_mmap(struct snd_pcm_substream *substream, | ||
382 | struct vm_area_struct *vma) | ||
383 | { | ||
384 | return snd_pcm_lib_default_mmap(substream, vma); | ||
385 | } | ||
386 | |||
387 | static int acp3x_dma_close(struct snd_pcm_substream *substream) | ||
388 | { | ||
389 | struct snd_soc_pcm_runtime *prtd = substream->private_data; | ||
390 | struct i2s_stream_instance *rtd = substream->runtime->private_data; | ||
391 | struct snd_soc_component *component = snd_soc_rtdcom_lookup(prtd, | ||
392 | DRV_NAME); | ||
393 | struct i2s_dev_data *adata = dev_get_drvdata(component->dev); | ||
394 | |||
395 | if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) | ||
396 | adata->play_stream = NULL; | ||
397 | else | ||
398 | adata->capture_stream = NULL; | ||
399 | |||
400 | /* Disable ACP irq, when the current stream is being closed and | ||
401 | * another stream is also not active. | ||
402 | */ | ||
403 | if (!adata->play_stream && !adata->capture_stream) | ||
404 | rv_writel(0, adata->acp3x_base + mmACP_EXTERNAL_INTR_ENB); | ||
405 | kfree(rtd); | ||
406 | return 0; | ||
407 | } | ||
408 | |||
409 | static struct snd_pcm_ops acp3x_dma_ops = { | ||
410 | .open = acp3x_dma_open, | ||
411 | .close = acp3x_dma_close, | ||
412 | .ioctl = snd_pcm_lib_ioctl, | ||
413 | .hw_params = acp3x_dma_hw_params, | ||
414 | .hw_free = acp3x_dma_hw_free, | ||
415 | .pointer = acp3x_dma_pointer, | ||
416 | .mmap = acp3x_dma_mmap, | ||
417 | }; | ||
418 | |||
419 | |||
420 | static int acp3x_dai_i2s_set_fmt(struct snd_soc_dai *cpu_dai, unsigned int fmt) | ||
421 | { | ||
422 | |||
423 | struct i2s_dev_data *adata = snd_soc_dai_get_drvdata(cpu_dai); | ||
424 | |||
425 | switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) { | ||
426 | case SND_SOC_DAIFMT_I2S: | ||
427 | adata->tdm_mode = false; | ||
428 | break; | ||
429 | case SND_SOC_DAIFMT_DSP_A: | ||
430 | adata->tdm_mode = true; | ||
431 | break; | ||
432 | default: | ||
433 | return -EINVAL; | ||
434 | } | ||
435 | |||
436 | return 0; | ||
437 | } | ||
438 | |||
439 | static int acp3x_dai_set_tdm_slot(struct snd_soc_dai *cpu_dai, u32 tx_mask, | ||
440 | u32 rx_mask, int slots, int slot_width) | ||
441 | { | ||
442 | u32 val = 0; | ||
443 | u16 slot_len; | ||
444 | |||
445 | struct i2s_dev_data *adata = snd_soc_dai_get_drvdata(cpu_dai); | ||
446 | |||
447 | switch (slot_width) { | ||
448 | case SLOT_WIDTH_8: | ||
449 | slot_len = 8; | ||
450 | break; | ||
451 | case SLOT_WIDTH_16: | ||
452 | slot_len = 16; | ||
453 | break; | ||
454 | case SLOT_WIDTH_24: | ||
455 | slot_len = 24; | ||
456 | break; | ||
457 | case SLOT_WIDTH_32: | ||
458 | slot_len = 0; | ||
459 | break; | ||
460 | default: | ||
461 | return -EINVAL; | ||
462 | } | ||
463 | |||
464 | val = rv_readl(adata->acp3x_base + mmACP_BTTDM_ITER); | ||
465 | rv_writel((val | 0x2), adata->acp3x_base + mmACP_BTTDM_ITER); | ||
466 | val = rv_readl(adata->acp3x_base + mmACP_BTTDM_IRER); | ||
467 | rv_writel((val | 0x2), adata->acp3x_base + mmACP_BTTDM_IRER); | ||
468 | |||
469 | val = (FRM_LEN | (slots << 15) | (slot_len << 18)); | ||
470 | rv_writel(val, adata->acp3x_base + mmACP_BTTDM_TXFRMT); | ||
471 | rv_writel(val, adata->acp3x_base + mmACP_BTTDM_RXFRMT); | ||
472 | |||
473 | adata->tdm_fmt = val; | ||
474 | return 0; | ||
475 | } | ||
476 | |||
477 | static int acp3x_dai_i2s_hwparams(struct snd_pcm_substream *substream, | ||
478 | struct snd_pcm_hw_params *params, | ||
479 | struct snd_soc_dai *dai) | ||
480 | { | ||
481 | u32 val = 0; | ||
482 | struct i2s_stream_instance *rtd = substream->runtime->private_data; | ||
483 | |||
484 | switch (params_format(params)) { | ||
485 | case SNDRV_PCM_FORMAT_U8: | ||
486 | case SNDRV_PCM_FORMAT_S8: | ||
487 | rtd->xfer_resolution = 0x0; | ||
488 | break; | ||
489 | case SNDRV_PCM_FORMAT_S16_LE: | ||
490 | rtd->xfer_resolution = 0x02; | ||
491 | break; | ||
492 | case SNDRV_PCM_FORMAT_S24_LE: | ||
493 | rtd->xfer_resolution = 0x04; | ||
494 | break; | ||
495 | case SNDRV_PCM_FORMAT_S32_LE: | ||
496 | rtd->xfer_resolution = 0x05; | ||
497 | break; | ||
498 | default: | ||
499 | return -EINVAL; | ||
500 | } | ||
501 | val = rv_readl(rtd->acp3x_base + mmACP_BTTDM_ITER); | ||
502 | val = val | (rtd->xfer_resolution << 3); | ||
503 | if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) | ||
504 | rv_writel(val, rtd->acp3x_base + mmACP_BTTDM_ITER); | ||
505 | else | ||
506 | rv_writel(val, rtd->acp3x_base + mmACP_BTTDM_IRER); | ||
507 | |||
508 | return 0; | ||
509 | } | ||
510 | |||
511 | static int acp3x_dai_i2s_trigger(struct snd_pcm_substream *substream, | ||
512 | int cmd, struct snd_soc_dai *dai) | ||
513 | { | ||
514 | int ret = 0; | ||
515 | struct i2s_stream_instance *rtd = substream->runtime->private_data; | ||
516 | u32 val, period_bytes; | ||
517 | |||
518 | period_bytes = frames_to_bytes(substream->runtime, | ||
519 | substream->runtime->period_size); | ||
520 | switch (cmd) { | ||
521 | case SNDRV_PCM_TRIGGER_START: | ||
522 | case SNDRV_PCM_TRIGGER_RESUME: | ||
523 | case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: | ||
524 | if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { | ||
525 | rv_writel(period_bytes, rtd->acp3x_base + | ||
526 | mmACP_BT_TX_INTR_WATERMARK_SIZE); | ||
527 | val = rv_readl(rtd->acp3x_base + mmACP_BTTDM_ITER); | ||
528 | val = val | BIT(0); | ||
529 | rv_writel(val, rtd->acp3x_base + mmACP_BTTDM_ITER); | ||
530 | } else { | ||
531 | rv_writel(period_bytes, rtd->acp3x_base + | ||
532 | mmACP_BT_RX_INTR_WATERMARK_SIZE); | ||
533 | val = rv_readl(rtd->acp3x_base + mmACP_BTTDM_IRER); | ||
534 | val = val | BIT(0); | ||
535 | rv_writel(val, rtd->acp3x_base + mmACP_BTTDM_IRER); | ||
536 | } | ||
537 | rv_writel(1, rtd->acp3x_base + mmACP_BTTDM_IER); | ||
538 | break; | ||
539 | case SNDRV_PCM_TRIGGER_STOP: | ||
540 | case SNDRV_PCM_TRIGGER_SUSPEND: | ||
541 | case SNDRV_PCM_TRIGGER_PAUSE_PUSH: | ||
542 | if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { | ||
543 | val = rv_readl(rtd->acp3x_base + mmACP_BTTDM_ITER); | ||
544 | val = val & ~BIT(0); | ||
545 | rv_writel(val, rtd->acp3x_base + mmACP_BTTDM_ITER); | ||
546 | } else { | ||
547 | val = rv_readl(rtd->acp3x_base + mmACP_BTTDM_IRER); | ||
548 | val = val & ~BIT(0); | ||
549 | rv_writel(val, rtd->acp3x_base + mmACP_BTTDM_IRER); | ||
550 | } | ||
551 | rv_writel(0, rtd->acp3x_base + mmACP_BTTDM_IER); | ||
552 | break; | ||
553 | default: | ||
554 | ret = -EINVAL; | ||
555 | break; | ||
556 | } | ||
557 | |||
558 | return ret; | ||
559 | } | ||
560 | |||
561 | struct snd_soc_dai_ops acp3x_dai_i2s_ops = { | ||
562 | .hw_params = acp3x_dai_i2s_hwparams, | ||
563 | .trigger = acp3x_dai_i2s_trigger, | ||
564 | .set_fmt = acp3x_dai_i2s_set_fmt, | ||
565 | .set_tdm_slot = acp3x_dai_set_tdm_slot, | ||
566 | }; | ||
567 | |||
568 | static struct snd_soc_dai_driver acp3x_i2s_dai_driver = { | ||
569 | .playback = { | ||
570 | .rates = SNDRV_PCM_RATE_8000_96000, | ||
571 | .formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S8 | | ||
572 | SNDRV_PCM_FMTBIT_U8 | | ||
573 | SNDRV_PCM_FMTBIT_S24_LE | | ||
574 | SNDRV_PCM_FMTBIT_S32_LE, | ||
575 | .channels_min = 2, | ||
576 | .channels_max = 8, | ||
577 | |||
578 | .rate_min = 8000, | ||
579 | .rate_max = 96000, | ||
580 | }, | ||
581 | .capture = { | ||
582 | .rates = SNDRV_PCM_RATE_8000_48000, | ||
583 | .formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S8 | | ||
584 | SNDRV_PCM_FMTBIT_U8 | | ||
585 | SNDRV_PCM_FMTBIT_S24_LE | | ||
586 | SNDRV_PCM_FMTBIT_S32_LE, | ||
587 | .channels_min = 2, | ||
588 | .channels_max = 2, | ||
589 | .rate_min = 8000, | ||
590 | .rate_max = 48000, | ||
591 | }, | ||
592 | .ops = &acp3x_dai_i2s_ops, | ||
593 | }; | ||
594 | |||
595 | static const struct snd_soc_component_driver acp3x_i2s_component = { | ||
596 | .name = DRV_NAME, | ||
597 | .ops = &acp3x_dma_ops, | ||
598 | .pcm_new = acp3x_dma_new, | ||
599 | }; | ||
600 | |||
601 | static int acp3x_audio_probe(struct platform_device *pdev) | ||
602 | { | ||
603 | int status; | ||
604 | struct resource *res; | ||
605 | struct i2s_dev_data *adata; | ||
606 | unsigned int irqflags; | ||
607 | |||
608 | if (!pdev->dev.platform_data) { | ||
609 | dev_err(&pdev->dev, "platform_data not retrieved\n"); | ||
610 | return -ENODEV; | ||
611 | } | ||
612 | irqflags = *((unsigned int *)(pdev->dev.platform_data)); | ||
613 | |||
614 | adata = devm_kzalloc(&pdev->dev, sizeof(struct i2s_dev_data), | ||
615 | GFP_KERNEL); | ||
616 | res = platform_get_resource(pdev, IORESOURCE_MEM, 0); | ||
617 | if (!res) { | ||
618 | dev_err(&pdev->dev, "IORESOURCE_IRQ FAILED\n"); | ||
619 | return -ENODEV; | ||
620 | } | ||
621 | |||
622 | adata->acp3x_base = devm_ioremap(&pdev->dev, res->start, | ||
623 | resource_size(res)); | ||
624 | |||
625 | res = platform_get_resource(pdev, IORESOURCE_IRQ, 0); | ||
626 | if (!res) { | ||
627 | dev_err(&pdev->dev, "IORESOURCE_IRQ FAILED\n"); | ||
628 | return -ENODEV; | ||
629 | } | ||
630 | |||
631 | adata->i2s_irq = res->start; | ||
632 | adata->play_stream = NULL; | ||
633 | adata->capture_stream = NULL; | ||
634 | |||
635 | dev_set_drvdata(&pdev->dev, adata); | ||
636 | /* Initialize ACP */ | ||
637 | status = acp3x_init(adata->acp3x_base); | ||
638 | if (status) | ||
639 | return -ENODEV; | ||
640 | status = devm_snd_soc_register_component(&pdev->dev, | ||
641 | &acp3x_i2s_component, | ||
642 | &acp3x_i2s_dai_driver, 1); | ||
643 | if (status) { | ||
644 | dev_err(&pdev->dev, "Fail to register acp i2s dai\n"); | ||
645 | goto dev_err; | ||
646 | } | ||
647 | status = devm_request_irq(&pdev->dev, adata->i2s_irq, i2s_irq_handler, | ||
648 | irqflags, "ACP3x_I2S_IRQ", adata); | ||
649 | if (status) { | ||
650 | dev_err(&pdev->dev, "ACP3x I2S IRQ request failed\n"); | ||
651 | goto dev_err; | ||
652 | } | ||
653 | |||
654 | pm_runtime_set_autosuspend_delay(&pdev->dev, 10000); | ||
655 | pm_runtime_use_autosuspend(&pdev->dev); | ||
656 | pm_runtime_enable(&pdev->dev); | ||
657 | return 0; | ||
658 | dev_err: | ||
659 | status = acp3x_deinit(adata->acp3x_base); | ||
660 | if (status) | ||
661 | dev_err(&pdev->dev, "ACP de-init failed\n"); | ||
662 | else | ||
663 | dev_info(&pdev->dev, "ACP de-initialized\n"); | ||
664 | /*ignore device status and return driver probe error*/ | ||
665 | return -ENODEV; | ||
666 | } | ||
667 | |||
668 | static int acp3x_audio_remove(struct platform_device *pdev) | ||
669 | { | ||
670 | int ret; | ||
671 | struct i2s_dev_data *adata = dev_get_drvdata(&pdev->dev); | ||
672 | |||
673 | ret = acp3x_deinit(adata->acp3x_base); | ||
674 | if (ret) | ||
675 | dev_err(&pdev->dev, "ACP de-init failed\n"); | ||
676 | else | ||
677 | dev_info(&pdev->dev, "ACP de-initialized\n"); | ||
678 | |||
679 | pm_runtime_disable(&pdev->dev); | ||
680 | return 0; | ||
681 | } | ||
682 | |||
683 | static int acp3x_resume(struct device *dev) | ||
684 | { | ||
685 | int status; | ||
686 | u32 val; | ||
687 | struct i2s_dev_data *adata = dev_get_drvdata(dev); | ||
688 | |||
689 | status = acp3x_init(adata->acp3x_base); | ||
690 | if (status) | ||
691 | return -ENODEV; | ||
692 | |||
693 | if (adata->play_stream && adata->play_stream->runtime) { | ||
694 | struct i2s_stream_instance *rtd = | ||
695 | adata->play_stream->runtime->private_data; | ||
696 | config_acp3x_dma(rtd, SNDRV_PCM_STREAM_PLAYBACK); | ||
697 | rv_writel((rtd->xfer_resolution << 3), | ||
698 | rtd->acp3x_base + mmACP_BTTDM_ITER); | ||
699 | if (adata->tdm_mode == true) { | ||
700 | rv_writel(adata->tdm_fmt, adata->acp3x_base + | ||
701 | mmACP_BTTDM_TXFRMT); | ||
702 | val = rv_readl(adata->acp3x_base + mmACP_BTTDM_ITER); | ||
703 | rv_writel((val | 0x2), adata->acp3x_base + | ||
704 | mmACP_BTTDM_ITER); | ||
705 | } | ||
706 | } | ||
707 | |||
708 | if (adata->capture_stream && adata->capture_stream->runtime) { | ||
709 | struct i2s_stream_instance *rtd = | ||
710 | adata->capture_stream->runtime->private_data; | ||
711 | config_acp3x_dma(rtd, SNDRV_PCM_STREAM_CAPTURE); | ||
712 | rv_writel((rtd->xfer_resolution << 3), | ||
713 | rtd->acp3x_base + mmACP_BTTDM_IRER); | ||
714 | if (adata->tdm_mode == true) { | ||
715 | rv_writel(adata->tdm_fmt, adata->acp3x_base + | ||
716 | mmACP_BTTDM_RXFRMT); | ||
717 | val = rv_readl(adata->acp3x_base + mmACP_BTTDM_IRER); | ||
718 | rv_writel((val | 0x2), adata->acp3x_base + | ||
719 | mmACP_BTTDM_IRER); | ||
720 | } | ||
721 | } | ||
722 | |||
723 | rv_writel(1, adata->acp3x_base + mmACP_EXTERNAL_INTR_ENB); | ||
724 | return 0; | ||
725 | } | ||
726 | |||
727 | |||
728 | static int acp3x_pcm_runtime_suspend(struct device *dev) | ||
729 | { | ||
730 | int status; | ||
731 | struct i2s_dev_data *adata = dev_get_drvdata(dev); | ||
732 | |||
733 | status = acp3x_deinit(adata->acp3x_base); | ||
734 | if (status) | ||
735 | dev_err(dev, "ACP de-init failed\n"); | ||
736 | else | ||
737 | dev_info(dev, "ACP de-initialized\n"); | ||
738 | |||
739 | rv_writel(0, adata->acp3x_base + mmACP_EXTERNAL_INTR_ENB); | ||
740 | |||
741 | return 0; | ||
742 | } | ||
743 | |||
744 | static int acp3x_pcm_runtime_resume(struct device *dev) | ||
745 | { | ||
746 | int status; | ||
747 | struct i2s_dev_data *adata = dev_get_drvdata(dev); | ||
748 | |||
749 | status = acp3x_init(adata->acp3x_base); | ||
750 | if (status) | ||
751 | return -ENODEV; | ||
752 | rv_writel(1, adata->acp3x_base + mmACP_EXTERNAL_INTR_ENB); | ||
753 | return 0; | ||
754 | } | ||
755 | |||
756 | static const struct dev_pm_ops acp3x_pm_ops = { | ||
757 | .runtime_suspend = acp3x_pcm_runtime_suspend, | ||
758 | .runtime_resume = acp3x_pcm_runtime_resume, | ||
759 | .resume = acp3x_resume, | ||
760 | }; | ||
761 | |||
762 | static struct platform_driver acp3x_dma_driver = { | ||
763 | .probe = acp3x_audio_probe, | ||
764 | .remove = acp3x_audio_remove, | ||
765 | .driver = { | ||
766 | .name = "acp3x_rv_i2s", | ||
767 | .pm = &acp3x_pm_ops, | ||
768 | }, | ||
769 | }; | ||
770 | |||
771 | module_platform_driver(acp3x_dma_driver); | ||
772 | |||
773 | MODULE_AUTHOR("Maruthi.Bayyavarapu@amd.com"); | ||
774 | MODULE_AUTHOR("Vijendar.Mukunda@amd.com"); | ||
775 | MODULE_DESCRIPTION("AMD ACP 3.x PCM Driver"); | ||
776 | MODULE_LICENSE("GPL v2"); | ||
777 | MODULE_ALIAS("platform:" DRV_NAME); | ||
diff --git a/sound/soc/amd/raven/acp3x.h b/sound/soc/amd/raven/acp3x.h new file mode 100644 index 000000000000..4f2cadd90a87 --- /dev/null +++ b/sound/soc/amd/raven/acp3x.h | |||
@@ -0,0 +1,58 @@ | |||
1 | /* SPDX-License-Identifier: GPL-2.0+ */ | ||
2 | /* | ||
3 | * AMD ALSA SoC PCM Driver | ||
4 | * | ||
5 | * Copyright 2016 Advanced Micro Devices, Inc. | ||
6 | */ | ||
7 | |||
8 | #include "chip_offset_byte.h" | ||
9 | |||
10 | #define ACP3x_PHY_BASE_ADDRESS 0x1240000 | ||
11 | #define ACP3x_I2S_MODE 0 | ||
12 | #define ACP3x_REG_START 0x1240000 | ||
13 | #define ACP3x_REG_END 0x1250200 | ||
14 | #define I2S_MODE 0x04 | ||
15 | #define BT_TX_THRESHOLD 26 | ||
16 | #define BT_RX_THRESHOLD 25 | ||
17 | #define ACP3x_POWER_ON 0x00 | ||
18 | #define ACP3x_POWER_ON_IN_PROGRESS 0x01 | ||
19 | #define ACP3x_POWER_OFF 0x02 | ||
20 | #define ACP3x_POWER_OFF_IN_PROGRESS 0x03 | ||
21 | #define ACP3x_SOFT_RESET__SoftResetAudDone_MASK 0x00010001 | ||
22 | |||
23 | #define ACP_SRAM_PTE_OFFSET 0x02050000 | ||
24 | #define PAGE_SIZE_4K_ENABLE 0x2 | ||
25 | #define MEM_WINDOW_START 0x4000000 | ||
26 | #define PLAYBACK_FIFO_ADDR_OFFSET 0x400 | ||
27 | #define CAPTURE_FIFO_ADDR_OFFSET 0x500 | ||
28 | |||
29 | #define PLAYBACK_MIN_NUM_PERIODS 2 | ||
30 | #define PLAYBACK_MAX_NUM_PERIODS 8 | ||
31 | #define PLAYBACK_MAX_PERIOD_SIZE 16384 | ||
32 | #define PLAYBACK_MIN_PERIOD_SIZE 4096 | ||
33 | #define CAPTURE_MIN_NUM_PERIODS 2 | ||
34 | #define CAPTURE_MAX_NUM_PERIODS 8 | ||
35 | #define CAPTURE_MAX_PERIOD_SIZE 16384 | ||
36 | #define CAPTURE_MIN_PERIOD_SIZE 4096 | ||
37 | |||
38 | #define MAX_BUFFER (PLAYBACK_MAX_PERIOD_SIZE * PLAYBACK_MAX_NUM_PERIODS) | ||
39 | #define MIN_BUFFER MAX_BUFFER | ||
40 | #define FIFO_SIZE 0x100 | ||
41 | #define DMA_SIZE 0x40 | ||
42 | #define FRM_LEN 0x100 | ||
43 | |||
44 | #define SLOT_WIDTH_8 0x08 | ||
45 | #define SLOT_WIDTH_16 0x10 | ||
46 | #define SLOT_WIDTH_24 0x18 | ||
47 | #define SLOT_WIDTH_32 0x20 | ||
48 | |||
49 | |||
50 | static inline u32 rv_readl(void __iomem *base_addr) | ||
51 | { | ||
52 | return readl(base_addr - ACP3x_PHY_BASE_ADDRESS); | ||
53 | } | ||
54 | |||
55 | static inline void rv_writel(u32 val, void __iomem *base_addr) | ||
56 | { | ||
57 | writel(val, base_addr - ACP3x_PHY_BASE_ADDRESS); | ||
58 | } | ||
diff --git a/sound/soc/amd/raven/chip_offset_byte.h b/sound/soc/amd/raven/chip_offset_byte.h new file mode 100644 index 000000000000..9c1fac58fb2a --- /dev/null +++ b/sound/soc/amd/raven/chip_offset_byte.h | |||
@@ -0,0 +1,639 @@ | |||
1 | /* SPDX-License-Identifier: GPL-2.0+ */ | ||
2 | /* | ||
3 | * AMD ACP 3.0 Register Documentation | ||
4 | * | ||
5 | * Copyright 2016 Advanced Micro Devices, Inc. | ||
6 | */ | ||
7 | |||
8 | #ifndef _acp_ip_OFFSET_HEADER | ||
9 | #define _acp_ip_OFFSET_HEADER | ||
10 | // Registers from ACP_DMA block | ||
11 | |||
12 | #define mmACP_DMA_CNTL_0 0x1240000 | ||
13 | #define mmACP_DMA_CNTL_1 0x1240004 | ||
14 | #define mmACP_DMA_CNTL_2 0x1240008 | ||
15 | #define mmACP_DMA_CNTL_3 0x124000C | ||
16 | #define mmACP_DMA_CNTL_4 0x1240010 | ||
17 | #define mmACP_DMA_CNTL_5 0x1240014 | ||
18 | #define mmACP_DMA_CNTL_6 0x1240018 | ||
19 | #define mmACP_DMA_CNTL_7 0x124001C | ||
20 | #define mmACP_DMA_DSCR_STRT_IDX_0 0x1240020 | ||
21 | #define mmACP_DMA_DSCR_STRT_IDX_1 0x1240024 | ||
22 | #define mmACP_DMA_DSCR_STRT_IDX_2 0x1240028 | ||
23 | #define mmACP_DMA_DSCR_STRT_IDX_3 0x124002C | ||
24 | #define mmACP_DMA_DSCR_STRT_IDX_4 0x1240030 | ||
25 | #define mmACP_DMA_DSCR_STRT_IDX_5 0x1240034 | ||
26 | #define mmACP_DMA_DSCR_STRT_IDX_6 0x1240038 | ||
27 | #define mmACP_DMA_DSCR_STRT_IDX_7 0x124003C | ||
28 | #define mmACP_DMA_DSCR_CNT_0 0x1240040 | ||
29 | #define mmACP_DMA_DSCR_CNT_1 0x1240044 | ||
30 | #define mmACP_DMA_DSCR_CNT_2 0x1240048 | ||
31 | #define mmACP_DMA_DSCR_CNT_3 0x124004C | ||
32 | #define mmACP_DMA_DSCR_CNT_4 0x1240050 | ||
33 | #define mmACP_DMA_DSCR_CNT_5 0x1240054 | ||
34 | #define mmACP_DMA_DSCR_CNT_6 0x1240058 | ||
35 | #define mmACP_DMA_DSCR_CNT_7 0x124005C | ||
36 | #define mmACP_DMA_PRIO_0 0x1240060 | ||
37 | #define mmACP_DMA_PRIO_1 0x1240064 | ||
38 | #define mmACP_DMA_PRIO_2 0x1240068 | ||
39 | #define mmACP_DMA_PRIO_3 0x124006C | ||
40 | #define mmACP_DMA_PRIO_4 0x1240070 | ||
41 | #define mmACP_DMA_PRIO_5 0x1240074 | ||
42 | #define mmACP_DMA_PRIO_6 0x1240078 | ||
43 | #define mmACP_DMA_PRIO_7 0x124007C | ||
44 | #define mmACP_DMA_CUR_DSCR_0 0x1240080 | ||
45 | #define mmACP_DMA_CUR_DSCR_1 0x1240084 | ||
46 | #define mmACP_DMA_CUR_DSCR_2 0x1240088 | ||
47 | #define mmACP_DMA_CUR_DSCR_3 0x124008C | ||
48 | #define mmACP_DMA_CUR_DSCR_4 0x1240090 | ||
49 | #define mmACP_DMA_CUR_DSCR_5 0x1240094 | ||
50 | #define mmACP_DMA_CUR_DSCR_6 0x1240098 | ||
51 | #define mmACP_DMA_CUR_DSCR_7 0x124009C | ||
52 | #define mmACP_DMA_CUR_TRANS_CNT_0 0x12400A0 | ||
53 | #define mmACP_DMA_CUR_TRANS_CNT_1 0x12400A4 | ||
54 | #define mmACP_DMA_CUR_TRANS_CNT_2 0x12400A8 | ||
55 | #define mmACP_DMA_CUR_TRANS_CNT_3 0x12400AC | ||
56 | #define mmACP_DMA_CUR_TRANS_CNT_4 0x12400B0 | ||
57 | #define mmACP_DMA_CUR_TRANS_CNT_5 0x12400B4 | ||
58 | #define mmACP_DMA_CUR_TRANS_CNT_6 0x12400B8 | ||
59 | #define mmACP_DMA_CUR_TRANS_CNT_7 0x12400BC | ||
60 | #define mmACP_DMA_ERR_STS_0 0x12400C0 | ||
61 | #define mmACP_DMA_ERR_STS_1 0x12400C4 | ||
62 | #define mmACP_DMA_ERR_STS_2 0x12400C8 | ||
63 | #define mmACP_DMA_ERR_STS_3 0x12400CC | ||
64 | #define mmACP_DMA_ERR_STS_4 0x12400D0 | ||
65 | #define mmACP_DMA_ERR_STS_5 0x12400D4 | ||
66 | #define mmACP_DMA_ERR_STS_6 0x12400D8 | ||
67 | #define mmACP_DMA_ERR_STS_7 0x12400DC | ||
68 | #define mmACP_DMA_DESC_BASE_ADDR 0x12400E0 | ||
69 | #define mmACP_DMA_DESC_MAX_NUM_DSCR 0x12400E4 | ||
70 | #define mmACP_DMA_CH_STS 0x12400E8 | ||
71 | #define mmACP_DMA_CH_GROUP 0x12400EC | ||
72 | #define mmACP_DMA_CH_RST_STS 0x12400F0 | ||
73 | |||
74 | |||
75 | // Registers from ACP_AXI2AXIATU block | ||
76 | |||
77 | #define mmACPAXI2AXI_ATU_PAGE_SIZE_GRP_1 0x1240C00 | ||
78 | #define mmACPAXI2AXI_ATU_BASE_ADDR_GRP_1 0x1240C04 | ||
79 | #define mmACPAXI2AXI_ATU_PAGE_SIZE_GRP_2 0x1240C08 | ||
80 | #define mmACPAXI2AXI_ATU_BASE_ADDR_GRP_2 0x1240C0C | ||
81 | #define mmACPAXI2AXI_ATU_PAGE_SIZE_GRP_3 0x1240C10 | ||
82 | #define mmACPAXI2AXI_ATU_BASE_ADDR_GRP_3 0x1240C14 | ||
83 | #define mmACPAXI2AXI_ATU_PAGE_SIZE_GRP_4 0x1240C18 | ||
84 | #define mmACPAXI2AXI_ATU_BASE_ADDR_GRP_4 0x1240C1C | ||
85 | #define mmACPAXI2AXI_ATU_PAGE_SIZE_GRP_5 0x1240C20 | ||
86 | #define mmACPAXI2AXI_ATU_BASE_ADDR_GRP_5 0x1240C24 | ||
87 | #define mmACPAXI2AXI_ATU_PAGE_SIZE_GRP_6 0x1240C28 | ||
88 | #define mmACPAXI2AXI_ATU_BASE_ADDR_GRP_6 0x1240C2C | ||
89 | #define mmACPAXI2AXI_ATU_PAGE_SIZE_GRP_7 0x1240C30 | ||
90 | #define mmACPAXI2AXI_ATU_BASE_ADDR_GRP_7 0x1240C34 | ||
91 | #define mmACPAXI2AXI_ATU_PAGE_SIZE_GRP_8 0x1240C38 | ||
92 | #define mmACPAXI2AXI_ATU_BASE_ADDR_GRP_8 0x1240C3C | ||
93 | #define mmACPAXI2AXI_ATU_CTRL 0x1240C40 | ||
94 | |||
95 | |||
96 | // Registers from ACP_CLKRST block | ||
97 | |||
98 | #define mmACP_SOFT_RESET 0x1241000 | ||
99 | #define mmACP_CONTROL 0x1241004 | ||
100 | #define mmACP_STATUS 0x1241008 | ||
101 | #define mmACP_DSP0_OCD_HALT_ON_RST 0x124100C | ||
102 | #define mmACP_DYNAMIC_CG_MASTER_CONTROL 0x1241010 | ||
103 | |||
104 | |||
105 | // Registers from ACP_MISC block | ||
106 | |||
107 | #define mmACP_EXTERNAL_INTR_ENB 0x1241800 | ||
108 | #define mmACP_EXTERNAL_INTR_CNTL 0x1241804 | ||
109 | #define mmACP_EXTERNAL_INTR_STAT 0x1241808 | ||
110 | #define mmACP_DSP0_INTR_CNTL 0x124180C | ||
111 | #define mmACP_DSP0_INTR_STAT 0x1241810 | ||
112 | #define mmACP_DSP_SW_INTR_CNTL 0x1241814 | ||
113 | #define mmACP_DSP_SW_INTR_STAT 0x1241818 | ||
114 | #define mmACP_SW_INTR_TRIG 0x124181C | ||
115 | #define mmACP_SMU_MAILBOX 0x1241820 | ||
116 | #define mmDSP_INTERRUPT_ROUTING_CTRL 0x1241824 | ||
117 | #define mmACP_DSP0_WATCHDOG_TIMER_CNTL 0x1241828 | ||
118 | #define mmACP_DSP0_EXT_TIMER1_CNTL 0x124182C | ||
119 | #define mmACP_DSP0_EXT_TIMER2_CNTL 0x1241830 | ||
120 | #define mmACP_DSP0_EXT_TIMER3_CNTL 0x1241834 | ||
121 | #define mmACP_DSP0_EXT_TIMER4_CNTL 0x1241838 | ||
122 | #define mmACP_DSP0_EXT_TIMER5_CNTL 0x124183C | ||
123 | #define mmACP_DSP0_EXT_TIMER6_CNTL 0x1241840 | ||
124 | #define mmACP_DSP0_EXT_TIMER1_CURR_VALUE 0x1241844 | ||
125 | #define mmACP_DSP0_EXT_TIMER2_CURR_VALUE 0x1241848 | ||
126 | #define mmACP_DSP0_EXT_TIMER3_CURR_VALUE 0x124184C | ||
127 | #define mmACP_DSP0_EXT_TIMER4_CURR_VALUE 0x1241850 | ||
128 | #define mmACP_DSP0_EXT_TIMER5_CURR_VALUE 0x1241854 | ||
129 | #define mmACP_DSP0_EXT_TIMER6_CURR_VALUE 0x1241858 | ||
130 | #define mmACP_FW_STATUS 0x124185C | ||
131 | #define mmACP_TIMER 0x1241874 | ||
132 | #define mmACP_TIMER_CNTL 0x1241878 | ||
133 | #define mmACP_PGMEM_CTRL 0x12418C0 | ||
134 | #define mmACP_ERROR_STATUS 0x12418C4 | ||
135 | #define mmACP_SW_I2S_ERROR_REASON 0x12418C8 | ||
136 | #define mmACP_MEM_PG_STS 0x12418CC | ||
137 | |||
138 | |||
139 | // Registers from ACP_PGFSM block | ||
140 | |||
141 | #define mmACP_I2S_PIN_CONFIG 0x1241400 | ||
142 | #define mmACP_PAD_PULLUP_PULLDOWN_CTRL 0x1241404 | ||
143 | #define mmACP_PAD_DRIVE_STRENGTH_CTRL 0x1241408 | ||
144 | #define mmACP_SW_PAD_KEEPER_EN 0x124140C | ||
145 | #define mmACP_SW_WAKE_EN 0x1241410 | ||
146 | #define mmACP_I2S_WAKE_EN 0x1241414 | ||
147 | #define mmACP_PME_EN 0x1241418 | ||
148 | #define mmACP_PGFSM_CONTROL 0x124141C | ||
149 | #define mmACP_PGFSM_STATUS 0x1241420 | ||
150 | |||
151 | |||
152 | // Registers from ACP_SCRATCH block | ||
153 | |||
154 | #define mmACP_SCRATCH_REG_0 0x1250000 | ||
155 | #define mmACP_SCRATCH_REG_1 0x1250004 | ||
156 | #define mmACP_SCRATCH_REG_2 0x1250008 | ||
157 | #define mmACP_SCRATCH_REG_3 0x125000C | ||
158 | #define mmACP_SCRATCH_REG_4 0x1250010 | ||
159 | #define mmACP_SCRATCH_REG_5 0x1250014 | ||
160 | #define mmACP_SCRATCH_REG_6 0x1250018 | ||
161 | #define mmACP_SCRATCH_REG_7 0x125001C | ||
162 | #define mmACP_SCRATCH_REG_8 0x1250020 | ||
163 | #define mmACP_SCRATCH_REG_9 0x1250024 | ||
164 | #define mmACP_SCRATCH_REG_10 0x1250028 | ||
165 | #define mmACP_SCRATCH_REG_11 0x125002C | ||
166 | #define mmACP_SCRATCH_REG_12 0x1250030 | ||
167 | #define mmACP_SCRATCH_REG_13 0x1250034 | ||
168 | #define mmACP_SCRATCH_REG_14 0x1250038 | ||
169 | #define mmACP_SCRATCH_REG_15 0x125003C | ||
170 | #define mmACP_SCRATCH_REG_16 0x1250040 | ||
171 | #define mmACP_SCRATCH_REG_17 0x1250044 | ||
172 | #define mmACP_SCRATCH_REG_18 0x1250048 | ||
173 | #define mmACP_SCRATCH_REG_19 0x125004C | ||
174 | #define mmACP_SCRATCH_REG_20 0x1250050 | ||
175 | #define mmACP_SCRATCH_REG_21 0x1250054 | ||
176 | #define mmACP_SCRATCH_REG_22 0x1250058 | ||
177 | #define mmACP_SCRATCH_REG_23 0x125005C | ||
178 | #define mmACP_SCRATCH_REG_24 0x1250060 | ||
179 | #define mmACP_SCRATCH_REG_25 0x1250064 | ||
180 | #define mmACP_SCRATCH_REG_26 0x1250068 | ||
181 | #define mmACP_SCRATCH_REG_27 0x125006C | ||
182 | #define mmACP_SCRATCH_REG_28 0x1250070 | ||
183 | #define mmACP_SCRATCH_REG_29 0x1250074 | ||
184 | #define mmACP_SCRATCH_REG_30 0x1250078 | ||
185 | #define mmACP_SCRATCH_REG_31 0x125007C | ||
186 | #define mmACP_SCRATCH_REG_32 0x1250080 | ||
187 | #define mmACP_SCRATCH_REG_33 0x1250084 | ||
188 | #define mmACP_SCRATCH_REG_34 0x1250088 | ||
189 | #define mmACP_SCRATCH_REG_35 0x125008C | ||
190 | #define mmACP_SCRATCH_REG_36 0x1250090 | ||
191 | #define mmACP_SCRATCH_REG_37 0x1250094 | ||
192 | #define mmACP_SCRATCH_REG_38 0x1250098 | ||
193 | #define mmACP_SCRATCH_REG_39 0x125009C | ||
194 | #define mmACP_SCRATCH_REG_40 0x12500A0 | ||
195 | #define mmACP_SCRATCH_REG_41 0x12500A4 | ||
196 | #define mmACP_SCRATCH_REG_42 0x12500A8 | ||
197 | #define mmACP_SCRATCH_REG_43 0x12500AC | ||
198 | #define mmACP_SCRATCH_REG_44 0x12500B0 | ||
199 | #define mmACP_SCRATCH_REG_45 0x12500B4 | ||
200 | #define mmACP_SCRATCH_REG_46 0x12500B8 | ||
201 | #define mmACP_SCRATCH_REG_47 0x12500BC | ||
202 | #define mmACP_SCRATCH_REG_48 0x12500C0 | ||
203 | #define mmACP_SCRATCH_REG_49 0x12500C4 | ||
204 | #define mmACP_SCRATCH_REG_50 0x12500C8 | ||
205 | #define mmACP_SCRATCH_REG_51 0x12500CC | ||
206 | #define mmACP_SCRATCH_REG_52 0x12500D0 | ||
207 | #define mmACP_SCRATCH_REG_53 0x12500D4 | ||
208 | #define mmACP_SCRATCH_REG_54 0x12500D8 | ||
209 | #define mmACP_SCRATCH_REG_55 0x12500DC | ||
210 | #define mmACP_SCRATCH_REG_56 0x12500E0 | ||
211 | #define mmACP_SCRATCH_REG_57 0x12500E4 | ||
212 | #define mmACP_SCRATCH_REG_58 0x12500E8 | ||
213 | #define mmACP_SCRATCH_REG_59 0x12500EC | ||
214 | #define mmACP_SCRATCH_REG_60 0x12500F0 | ||
215 | #define mmACP_SCRATCH_REG_61 0x12500F4 | ||
216 | #define mmACP_SCRATCH_REG_62 0x12500F8 | ||
217 | #define mmACP_SCRATCH_REG_63 0x12500FC | ||
218 | #define mmACP_SCRATCH_REG_64 0x1250100 | ||
219 | #define mmACP_SCRATCH_REG_65 0x1250104 | ||
220 | #define mmACP_SCRATCH_REG_66 0x1250108 | ||
221 | #define mmACP_SCRATCH_REG_67 0x125010C | ||
222 | #define mmACP_SCRATCH_REG_68 0x1250110 | ||
223 | #define mmACP_SCRATCH_REG_69 0x1250114 | ||
224 | #define mmACP_SCRATCH_REG_70 0x1250118 | ||
225 | #define mmACP_SCRATCH_REG_71 0x125011C | ||
226 | #define mmACP_SCRATCH_REG_72 0x1250120 | ||
227 | #define mmACP_SCRATCH_REG_73 0x1250124 | ||
228 | #define mmACP_SCRATCH_REG_74 0x1250128 | ||
229 | #define mmACP_SCRATCH_REG_75 0x125012C | ||
230 | #define mmACP_SCRATCH_REG_76 0x1250130 | ||
231 | #define mmACP_SCRATCH_REG_77 0x1250134 | ||
232 | #define mmACP_SCRATCH_REG_78 0x1250138 | ||
233 | #define mmACP_SCRATCH_REG_79 0x125013C | ||
234 | #define mmACP_SCRATCH_REG_80 0x1250140 | ||
235 | #define mmACP_SCRATCH_REG_81 0x1250144 | ||
236 | #define mmACP_SCRATCH_REG_82 0x1250148 | ||
237 | #define mmACP_SCRATCH_REG_83 0x125014C | ||
238 | #define mmACP_SCRATCH_REG_84 0x1250150 | ||
239 | #define mmACP_SCRATCH_REG_85 0x1250154 | ||
240 | #define mmACP_SCRATCH_REG_86 0x1250158 | ||
241 | #define mmACP_SCRATCH_REG_87 0x125015C | ||
242 | #define mmACP_SCRATCH_REG_88 0x1250160 | ||
243 | #define mmACP_SCRATCH_REG_89 0x1250164 | ||
244 | #define mmACP_SCRATCH_REG_90 0x1250168 | ||
245 | #define mmACP_SCRATCH_REG_91 0x125016C | ||
246 | #define mmACP_SCRATCH_REG_92 0x1250170 | ||
247 | #define mmACP_SCRATCH_REG_93 0x1250174 | ||
248 | #define mmACP_SCRATCH_REG_94 0x1250178 | ||
249 | #define mmACP_SCRATCH_REG_95 0x125017C | ||
250 | #define mmACP_SCRATCH_REG_96 0x1250180 | ||
251 | #define mmACP_SCRATCH_REG_97 0x1250184 | ||
252 | #define mmACP_SCRATCH_REG_98 0x1250188 | ||
253 | #define mmACP_SCRATCH_REG_99 0x125018C | ||
254 | #define mmACP_SCRATCH_REG_100 0x1250190 | ||
255 | #define mmACP_SCRATCH_REG_101 0x1250194 | ||
256 | #define mmACP_SCRATCH_REG_102 0x1250198 | ||
257 | #define mmACP_SCRATCH_REG_103 0x125019C | ||
258 | #define mmACP_SCRATCH_REG_104 0x12501A0 | ||
259 | #define mmACP_SCRATCH_REG_105 0x12501A4 | ||
260 | #define mmACP_SCRATCH_REG_106 0x12501A8 | ||
261 | #define mmACP_SCRATCH_REG_107 0x12501AC | ||
262 | #define mmACP_SCRATCH_REG_108 0x12501B0 | ||
263 | #define mmACP_SCRATCH_REG_109 0x12501B4 | ||
264 | #define mmACP_SCRATCH_REG_110 0x12501B8 | ||
265 | #define mmACP_SCRATCH_REG_111 0x12501BC | ||
266 | #define mmACP_SCRATCH_REG_112 0x12501C0 | ||
267 | #define mmACP_SCRATCH_REG_113 0x12501C4 | ||
268 | #define mmACP_SCRATCH_REG_114 0x12501C8 | ||
269 | #define mmACP_SCRATCH_REG_115 0x12501CC | ||
270 | #define mmACP_SCRATCH_REG_116 0x12501D0 | ||
271 | #define mmACP_SCRATCH_REG_117 0x12501D4 | ||
272 | #define mmACP_SCRATCH_REG_118 0x12501D8 | ||
273 | #define mmACP_SCRATCH_REG_119 0x12501DC | ||
274 | #define mmACP_SCRATCH_REG_120 0x12501E0 | ||
275 | #define mmACP_SCRATCH_REG_121 0x12501E4 | ||
276 | #define mmACP_SCRATCH_REG_122 0x12501E8 | ||
277 | #define mmACP_SCRATCH_REG_123 0x12501EC | ||
278 | #define mmACP_SCRATCH_REG_124 0x12501F0 | ||
279 | #define mmACP_SCRATCH_REG_125 0x12501F4 | ||
280 | #define mmACP_SCRATCH_REG_126 0x12501F8 | ||
281 | #define mmACP_SCRATCH_REG_127 0x12501FC | ||
282 | #define mmACP_SCRATCH_REG_128 0x1250200 | ||
283 | |||
284 | |||
285 | // Registers from ACP_SW_ACLK block | ||
286 | |||
287 | #define mmSW_CORB_Base_Address 0x1243200 | ||
288 | #define mmSW_CORB_Write_Pointer 0x1243204 | ||
289 | #define mmSW_CORB_Read_Pointer 0x1243208 | ||
290 | #define mmSW_CORB_Control 0x124320C | ||
291 | #define mmSW_CORB_Size 0x1243214 | ||
292 | #define mmSW_RIRB_Base_Address 0x1243218 | ||
293 | #define mmSW_RIRB_Write_Pointer 0x124321C | ||
294 | #define mmSW_RIRB_Response_Interrupt_Count 0x1243220 | ||
295 | #define mmSW_RIRB_Control 0x1243224 | ||
296 | #define mmSW_RIRB_Size 0x1243228 | ||
297 | #define mmSW_RIRB_FIFO_MIN_THDL 0x124322C | ||
298 | #define mmSW_imm_cmd_UPPER_WORD 0x1243230 | ||
299 | #define mmSW_imm_cmd_LOWER_QWORD 0x1243234 | ||
300 | #define mmSW_imm_resp_UPPER_WORD 0x1243238 | ||
301 | #define mmSW_imm_resp_LOWER_QWORD 0x124323C | ||
302 | #define mmSW_imm_cmd_sts 0x1243240 | ||
303 | #define mmSW_BRA_BASE_ADDRESS 0x1243244 | ||
304 | #define mmSW_BRA_TRANSFER_SIZE 0x1243248 | ||
305 | #define mmSW_BRA_DMA_BUSY 0x124324C | ||
306 | #define mmSW_BRA_RESP 0x1243250 | ||
307 | #define mmSW_BRA_RESP_FRAME_ADDR 0x1243254 | ||
308 | #define mmSW_BRA_CURRENT_TRANSFER_SIZE 0x1243258 | ||
309 | #define mmSW_STATE_CHANGE_STATUS_0TO7 0x124325C | ||
310 | #define mmSW_STATE_CHANGE_STATUS_8TO11 0x1243260 | ||
311 | #define mmSW_STATE_CHANGE_STATUS_MASK_0to7 0x1243264 | ||
312 | #define mmSW_STATE_CHANGE_STATUS_MASK_8to11 0x1243268 | ||
313 | #define mmSW_CLK_FREQUENCY_CTRL 0x124326C | ||
314 | #define mmSW_ERROR_INTR_MASK 0x1243270 | ||
315 | #define mmSW_PHY_TEST_MODE_DATA_OFF 0x1243274 | ||
316 | |||
317 | |||
318 | // Registers from ACP_SW_SWCLK block | ||
319 | |||
320 | #define mmACP_SW_EN 0x1243000 | ||
321 | #define mmACP_SW_EN_STATUS 0x1243004 | ||
322 | #define mmACP_SW_FRAMESIZE 0x1243008 | ||
323 | #define mmACP_SW_SSP_Counter 0x124300C | ||
324 | #define mmACP_SW_Audio_TX_EN 0x1243010 | ||
325 | #define mmACP_SW_Audio_TX_EN_STATUS 0x1243014 | ||
326 | #define mmACP_SW_Audio_TX_Frame_Format 0x1243018 | ||
327 | #define mmACP_SW_Audio_TX_SampleInterval 0x124301C | ||
328 | #define mmACP_SW_Audio_TX_Hctrl_DP0 0x1243020 | ||
329 | #define mmACP_SW_Audio_TX_Hctrl_DP1 0x1243024 | ||
330 | #define mmACP_SW_Audio_TX_Hctrl_DP2 0x1243028 | ||
331 | #define mmACP_SW_Audio_TX_Hctrl_DP3 0x124302C | ||
332 | #define mmACP_SW_Audio_TX_offset_DP0 0x1243030 | ||
333 | #define mmACP_SW_Audio_TX_offset_DP1 0x1243034 | ||
334 | #define mmACP_SW_Audio_TX_offset_DP2 0x1243038 | ||
335 | #define mmACP_SW_Audio_TX_offset_DP3 0x124303C | ||
336 | #define mmACP_SW_Audio_TX_Channel_Enable_DP0 0x1243040 | ||
337 | #define mmACP_SW_Audio_TX_Channel_Enable_DP1 0x1243044 | ||
338 | #define mmACP_SW_Audio_TX_Channel_Enable_DP2 0x1243048 | ||
339 | #define mmACP_SW_Audio_TX_Channel_Enable_DP3 0x124304C | ||
340 | #define mmACP_SW_BT_TX_EN 0x1243050 | ||
341 | #define mmACP_SW_BT_TX_EN_STATUS 0x1243054 | ||
342 | #define mmACP_SW_BT_TX_Frame_Format 0x1243058 | ||
343 | #define mmACP_SW_BT_TX_SampleInterval 0x124305C | ||
344 | #define mmACP_SW_BT_TX_Hctrl 0x1243060 | ||
345 | #define mmACP_SW_BT_TX_offset 0x1243064 | ||
346 | #define mmACP_SW_BT_TX_Channel_Enable_DP0 0x1243068 | ||
347 | #define mmACP_SW_Headset_TX_EN 0x124306C | ||
348 | #define mmACP_SW_Headset_TX_EN_STATUS 0x1243070 | ||
349 | #define mmACP_SW_Headset_TX_Frame_Format 0x1243074 | ||
350 | #define mmACP_SW_Headset_TX_SampleInterval 0x1243078 | ||
351 | #define mmACP_SW_Headset_TX_Hctrl 0x124307C | ||
352 | #define mmACP_SW_Headset_TX_offset 0x1243080 | ||
353 | #define mmACP_SW_Headset_TX_Channel_Enable_DP0 0x1243084 | ||
354 | #define mmACP_SW_Audio_RX_EN 0x1243088 | ||
355 | #define mmACP_SW_Audio_RX_EN_STATUS 0x124308C | ||
356 | #define mmACP_SW_Audio_RX_Frame_Format 0x1243090 | ||
357 | #define mmACP_SW_Audio_RX_SampleInterval 0x1243094 | ||
358 | #define mmACP_SW_Audio_RX_Hctrl_DP0 0x1243098 | ||
359 | #define mmACP_SW_Audio_RX_Hctrl_DP1 0x124309C | ||
360 | #define mmACP_SW_Audio_RX_Hctrl_DP2 0x1243100 | ||
361 | #define mmACP_SW_Audio_RX_Hctrl_DP3 0x1243104 | ||
362 | #define mmACP_SW_Audio_RX_offset_DP0 0x1243108 | ||
363 | #define mmACP_SW_Audio_RX_offset_DP1 0x124310C | ||
364 | #define mmACP_SW_Audio_RX_offset_DP2 0x1243110 | ||
365 | #define mmACP_SW_Audio_RX_offset_DP3 0x1243114 | ||
366 | #define mmACP_SW_Audio_RX_Channel_Enable_DP0 0x1243118 | ||
367 | #define mmACP_SW_Audio_RX_Channel_Enable_DP1 0x124311C | ||
368 | #define mmACP_SW_Audio_RX_Channel_Enable_DP2 0x1243120 | ||
369 | #define mmACP_SW_Audio_RX_Channel_Enable_DP3 0x1243124 | ||
370 | #define mmACP_SW_BT_RX_EN 0x1243128 | ||
371 | #define mmACP_SW_BT_RX_EN_STATUS 0x124312C | ||
372 | #define mmACP_SW_BT_RX_Frame_Format 0x1243130 | ||
373 | #define mmACP_SW_BT_RX_SampleInterval 0x1243134 | ||
374 | #define mmACP_SW_BT_RX_Hctrl 0x1243138 | ||
375 | #define mmACP_SW_BT_RX_offset 0x124313C | ||
376 | #define mmACP_SW_BT_RX_Channel_Enable_DP0 0x1243140 | ||
377 | #define mmACP_SW_Headset_RX_EN 0x1243144 | ||
378 | #define mmACP_SW_Headset_RX_EN_STATUS 0x1243148 | ||
379 | #define mmACP_SW_Headset_RX_Frame_Format 0x124314C | ||
380 | #define mmACP_SW_Headset_RX_SampleInterval 0x1243150 | ||
381 | #define mmACP_SW_Headset_RX_Hctrl 0x1243154 | ||
382 | #define mmACP_SW_Headset_RX_offset 0x1243158 | ||
383 | #define mmACP_SW_Headset_RX_Channel_Enable_DP0 0x124315C | ||
384 | #define mmACP_SW_BPT_PORT_EN 0x1243160 | ||
385 | #define mmACP_SW_BPT_PORT_EN_STATUS 0x1243164 | ||
386 | #define mmACP_SW_BPT_PORT_Frame_Format 0x1243168 | ||
387 | #define mmACP_SW_BPT_PORT_SampleInterval 0x124316C | ||
388 | #define mmACP_SW_BPT_PORT_Hctrl 0x1243170 | ||
389 | #define mmACP_SW_BPT_PORT_offset 0x1243174 | ||
390 | #define mmACP_SW_BPT_PORT_Channel_Enable 0x1243178 | ||
391 | #define mmACP_SW_BPT_PORT_First_byte_addr 0x124317C | ||
392 | #define mmACP_SW_CLK_RESUME_CTRL 0x1243180 | ||
393 | #define mmACP_SW_CLK_RESUME_Delay_Cntr 0x1243184 | ||
394 | #define mmACP_SW_BUS_RESET_CTRL 0x1243188 | ||
395 | #define mmACP_SW_PRBS_ERR_STATUS 0x124318C | ||
396 | |||
397 | |||
398 | // Registers from ACP_AUDIO_BUFFERS block | ||
399 | |||
400 | #define mmACP_I2S_RX_RINGBUFADDR 0x1242000 | ||
401 | #define mmACP_I2S_RX_RINGBUFSIZE 0x1242004 | ||
402 | #define mmACP_I2S_RX_LINKPOSITIONCNTR 0x1242008 | ||
403 | #define mmACP_I2S_RX_FIFOADDR 0x124200C | ||
404 | #define mmACP_I2S_RX_FIFOSIZE 0x1242010 | ||
405 | #define mmACP_I2S_RX_DMA_SIZE 0x1242014 | ||
406 | #define mmACP_I2S_RX_LINEARPOSITIONCNTR_HIGH 0x1242018 | ||
407 | #define mmACP_I2S_RX_LINEARPOSITIONCNTR_LOW 0x124201C | ||
408 | #define mmACP_I2S_RX_INTR_WATERMARK_SIZE 0x1242020 | ||
409 | #define mmACP_I2S_TX_RINGBUFADDR 0x1242024 | ||
410 | #define mmACP_I2S_TX_RINGBUFSIZE 0x1242028 | ||
411 | #define mmACP_I2S_TX_LINKPOSITIONCNTR 0x124202C | ||
412 | #define mmACP_I2S_TX_FIFOADDR 0x1242030 | ||
413 | #define mmACP_I2S_TX_FIFOSIZE 0x1242034 | ||
414 | #define mmACP_I2S_TX_DMA_SIZE 0x1242038 | ||
415 | #define mmACP_I2S_TX_LINEARPOSITIONCNTR_HIGH 0x124203C | ||
416 | #define mmACP_I2S_TX_LINEARPOSITIONCNTR_LOW 0x1242040 | ||
417 | #define mmACP_I2S_TX_INTR_WATERMARK_SIZE 0x1242044 | ||
418 | #define mmACP_BT_RX_RINGBUFADDR 0x1242048 | ||
419 | #define mmACP_BT_RX_RINGBUFSIZE 0x124204C | ||
420 | #define mmACP_BT_RX_LINKPOSITIONCNTR 0x1242050 | ||
421 | #define mmACP_BT_RX_FIFOADDR 0x1242054 | ||
422 | #define mmACP_BT_RX_FIFOSIZE 0x1242058 | ||
423 | #define mmACP_BT_RX_DMA_SIZE 0x124205C | ||
424 | #define mmACP_BT_RX_LINEARPOSITIONCNTR_HIGH 0x1242060 | ||
425 | #define mmACP_BT_RX_LINEARPOSITIONCNTR_LOW 0x1242064 | ||
426 | #define mmACP_BT_RX_INTR_WATERMARK_SIZE 0x1242068 | ||
427 | #define mmACP_BT_TX_RINGBUFADDR 0x124206C | ||
428 | #define mmACP_BT_TX_RINGBUFSIZE 0x1242070 | ||
429 | #define mmACP_BT_TX_LINKPOSITIONCNTR 0x1242074 | ||
430 | #define mmACP_BT_TX_FIFOADDR 0x1242078 | ||
431 | #define mmACP_BT_TX_FIFOSIZE 0x124207C | ||
432 | #define mmACP_BT_TX_DMA_SIZE 0x1242080 | ||
433 | #define mmACP_BT_TX_LINEARPOSITIONCNTR_HIGH 0x1242084 | ||
434 | #define mmACP_BT_TX_LINEARPOSITIONCNTR_LOW 0x1242088 | ||
435 | #define mmACP_BT_TX_INTR_WATERMARK_SIZE 0x124208C | ||
436 | #define mmACP_HS_RX_RINGBUFADDR 0x1242090 | ||
437 | #define mmACP_HS_RX_RINGBUFSIZE 0x1242094 | ||
438 | #define mmACP_HS_RX_LINKPOSITIONCNTR 0x1242098 | ||
439 | #define mmACP_HS_RX_FIFOADDR 0x124209C | ||
440 | #define mmACP_HS_RX_FIFOSIZE 0x12420A0 | ||
441 | #define mmACP_HS_RX_DMA_SIZE 0x12420A4 | ||
442 | #define mmACP_HS_RX_LINEARPOSITIONCNTR_HIGH 0x12420A8 | ||
443 | #define mmACP_HS_RX_LINEARPOSITIONCNTR_LOW 0x12420AC | ||
444 | #define mmACP_HS_RX_INTR_WATERMARK_SIZE 0x12420B0 | ||
445 | #define mmACP_HS_TX_RINGBUFADDR 0x12420B4 | ||
446 | #define mmACP_HS_TX_RINGBUFSIZE 0x12420B8 | ||
447 | #define mmACP_HS_TX_LINKPOSITIONCNTR 0x12420BC | ||
448 | #define mmACP_HS_TX_FIFOADDR 0x12420C0 | ||
449 | #define mmACP_HS_TX_FIFOSIZE 0x12420C4 | ||
450 | #define mmACP_HS_TX_DMA_SIZE 0x12420C8 | ||
451 | #define mmACP_HS_TX_LINEARPOSITIONCNTR_HIGH 0x12420CC | ||
452 | #define mmACP_HS_TX_LINEARPOSITIONCNTR_LOW 0x12420D0 | ||
453 | #define mmACP_HS_TX_INTR_WATERMARK_SIZE 0x12420D4 | ||
454 | |||
455 | |||
456 | // Registers from ACP_I2S_TDM block | ||
457 | |||
458 | #define mmACP_I2STDM_IER 0x1242400 | ||
459 | #define mmACP_I2STDM_IRER 0x1242404 | ||
460 | #define mmACP_I2STDM_RXFRMT 0x1242408 | ||
461 | #define mmACP_I2STDM_ITER 0x124240C | ||
462 | #define mmACP_I2STDM_TXFRMT 0x1242410 | ||
463 | |||
464 | |||
465 | // Registers from ACP_BT_TDM block | ||
466 | |||
467 | #define mmACP_BTTDM_IER 0x1242800 | ||
468 | #define mmACP_BTTDM_IRER 0x1242804 | ||
469 | #define mmACP_BTTDM_RXFRMT 0x1242808 | ||
470 | #define mmACP_BTTDM_ITER 0x124280C | ||
471 | #define mmACP_BTTDM_TXFRMT 0x1242810 | ||
472 | |||
473 | |||
474 | // Registers from AZALIA_IP block | ||
475 | |||
476 | #define mmAudio_Az_Global_Capabilities 0x1200000 | ||
477 | #define mmAudio_Az_Minor_Version 0x1200002 | ||
478 | #define mmAudio_Az_Major_Version 0x1200003 | ||
479 | #define mmAudio_Az_Output_Payload_Capability 0x1200004 | ||
480 | #define mmAudio_Az_Input_Payload_Capability 0x1200006 | ||
481 | #define mmAudio_Az_Global_Control 0x1200008 | ||
482 | #define mmAudio_Az_Wake_Enable 0x120000C | ||
483 | #define mmAudio_Az_State_Change_Status 0x120000E | ||
484 | #define mmAudio_Az_Global_Status 0x1200010 | ||
485 | #define mmAudio_Az_Linked_List_Capability_Header 0x1200014 | ||
486 | #define mmAudio_Az_Output_Stream_Payload_Capability 0x1200018 | ||
487 | #define mmAudio_Az_Input_Stream_Payload_Capability 0x120001A | ||
488 | #define mmAudio_Az_Interrupt_Control 0x1200020 | ||
489 | #define mmAudio_Az_Interrupt_Status 0x1200024 | ||
490 | #define mmAudio_Az_Wall_Clock_Counter 0x1200030 | ||
491 | #define mmAudio_Az_Stream_Synchronization 0x1200038 | ||
492 | #define mmAudio_Az_CORB_Lower_Base_Address 0x1200040 | ||
493 | #define mmAudio_Az_CORB_Upper_Base_Address 0x1200044 | ||
494 | #define mmAudio_Az_CORB_Write_Pointer 0x1200048 | ||
495 | #define mmAudio_Az_CORB_Read_Pointer 0x120004A | ||
496 | #define mmAudio_Az_CORB_Control 0x120004C | ||
497 | #define mmAudio_Az_CORB_Status 0x120004D | ||
498 | #define mmAudio_Az_CORB_Size 0x120004E | ||
499 | #define mmAudio_Az_RIRB_Lower_Base_Address 0x1200050 | ||
500 | #define mmAudio_Az_RIRB_Upper_Base_Address 0x1200054 | ||
501 | #define mmAudio_Az_RIRB_Write_Pointer 0x1200058 | ||
502 | #define mmAudio_Az_RIRB_Response_Interrupt_Count 0x120005A | ||
503 | #define mmAudio_Az_RIRB_Control 0x120005C | ||
504 | #define mmAudio_Az_RIRB_Status 0x120005D | ||
505 | #define mmAudio_Az_RIRB_Size 0x120005E | ||
506 | #define mmAudio_Az_Immediate_Command_Output_Interface 0x1200060 | ||
507 | #define mmAudio_Az_Immediate_Response_Input_Interface 0x1200064 | ||
508 | #define mmAudio_Az_Immediate_Command_Status 0x1200068 | ||
509 | #define mmAudio_Az_DPLBASE 0x1200070 | ||
510 | #define mmAudio_Az_DPUBASE 0x1200074 | ||
511 | #define mmAudio_Az_Input_SD0CTL_and_STS 0x1200080 | ||
512 | #define mmAudio_Az_Input_SD0LPIB 0x1200084 | ||
513 | #define mmAudio_Az_Input_SD0CBL 0x1200088 | ||
514 | #define mmAudio_Az_Input_SD0LVI 0x120008C | ||
515 | #define mmAudio_Az_Input_SD0FIFOS 0x1200090 | ||
516 | #define mmAudio_Az_Input_SD0FMT 0x1200092 | ||
517 | #define mmAudio_Az_Input_SD0BDPL 0x1200098 | ||
518 | #define mmAudio_Az_Input_SD0BDPU 0x120009C | ||
519 | #define mmAudio_Az_Input_SD1CTL_and_STS 0x12000A0 | ||
520 | #define mmAudio_Az_Input_SD1LPIB 0x12000A4 | ||
521 | #define mmAudio_Az_Input_SD1CBL 0x12000A8 | ||
522 | #define mmAudio_Az_Input_SD1LVI 0x12000AC | ||
523 | #define mmAudio_Az_Input_SD1FIFOS 0x12000B0 | ||
524 | #define mmAudio_Az_Input_SD1FMT 0x12000B2 | ||
525 | #define mmAudio_Az_Input_SD1BDPL 0x12000B8 | ||
526 | #define mmAudio_Az_Input_SD1BDPU 0x12000BC | ||
527 | #define mmAudio_Az_Input_SD2CTL_and_STS 0x12000C0 | ||
528 | #define mmAudio_Az_Input_SD2LPIB 0x12000C4 | ||
529 | #define mmAudio_Az_Input_SD2CBL 0x12000C8 | ||
530 | #define mmAudio_Az_Input_SD2LVI 0x12000CC | ||
531 | #define mmAudio_Az_Input_SD2FIFOS 0x12000D0 | ||
532 | #define mmAudio_Az_Input_SD2FMT 0x12000D2 | ||
533 | #define mmAudio_Az_Input_SD2BDPL 0x12000D8 | ||
534 | #define mmAudio_Az_Input_SD2BDPU 0x12000DC | ||
535 | #define mmAudio_Az_Input_SD3CTL_and_STS 0x12000E0 | ||
536 | #define mmAudio_Az_Input_SD3LPIB 0x12000E4 | ||
537 | #define mmAudio_Az_Input_SD3CBL 0x12000E8 | ||
538 | #define mmAudio_Az_Input_SD3LVI 0x12000EC | ||
539 | #define mmAudio_Az_Input_SD3FIFOS 0x12000F0 | ||
540 | #define mmAudio_Az_Input_SD3FMT 0x12000F2 | ||
541 | #define mmAudio_Az_Input_SD3BDPL 0x12000F8 | ||
542 | #define mmAudio_Az_Input_SD3BDPU 0x12000FC | ||
543 | #define mmAudio_Az_Output_SD0CTL_and_STS 0x1200100 | ||
544 | #define mmAudio_Az_Output_SD0LPIB 0x1200104 | ||
545 | #define mmAudio_Az_Output_SD0CBL 0x1200108 | ||
546 | #define mmAudio_Az_Output_SD0LVI 0x120010C | ||
547 | #define mmAudio_Az_Output_SD0FIFOS 0x1200110 | ||
548 | #define mmAudio_Az_Output_SD0FMT 0x1200112 | ||
549 | #define mmAudio_Az_Output_SD0BDPL 0x1200118 | ||
550 | #define mmAudio_Az_Output_SD0BDPU 0x120011C | ||
551 | #define mmAudio_Az_Output_SD1CTL_and_STS 0x1200120 | ||
552 | #define mmAudio_Az_Output_SD1LPIB 0x1200124 | ||
553 | #define mmAudio_Az_Output_SD1CBL 0x1200128 | ||
554 | #define mmAudio_Az_Output_SD1LVI 0x120012C | ||
555 | #define mmAudio_Az_Output_SD1FIFOS 0x1200130 | ||
556 | #define mmAudio_Az_Output_SD1FMT 0x1200132 | ||
557 | #define mmAudio_Az_Output_SD1BDPL 0x1200138 | ||
558 | #define mmAudio_Az_Output_SD1BDPU 0x120013C | ||
559 | #define mmAudio_Az_Output_SD2CTL_and_STS 0x1200140 | ||
560 | #define mmAudio_Az_Output_SD2LPIB 0x1200144 | ||
561 | #define mmAudio_Az_Output_SD2CBL 0x1200148 | ||
562 | #define mmAudio_Az_Output_SD2LVI 0x120014C | ||
563 | #define mmAudio_Az_Output_SD2FIFOS 0x1200150 | ||
564 | #define mmAudio_Az_Output_SD2FMT 0x1200152 | ||
565 | #define mmAudio_Az_Output_SD2BDPL 0x1200158 | ||
566 | #define mmAudio_Az_Output_SD2BDPU 0x120015C | ||
567 | #define mmAudio_Az_Output_SD3CTL_and_STS 0x1200160 | ||
568 | #define mmAudio_Az_Output_SD3LPIB 0x1200164 | ||
569 | #define mmAudio_Az_Output_SD3CBL 0x1200168 | ||
570 | #define mmAudio_Az_Output_SD3LVI 0x120016C | ||
571 | #define mmAudio_Az_Output_SD3FIFOS 0x1200170 | ||
572 | #define mmAudio_Az_Output_SD3FMT 0x1200172 | ||
573 | #define mmAudio_Az_Output_SD3BDPL 0x1200178 | ||
574 | #define mmAudio_Az_Output_SD3BDPU 0x120017C | ||
575 | #define mmAudioAZ_Misc_Control_Register_1 0x1200180 | ||
576 | #define mmAudioAZ_Misc_Control_Register_2 0x1200182 | ||
577 | #define mmAudioAZ_Misc_Control_Register_3 0x1200183 | ||
578 | #define mmAudio_AZ_Multiple_Links_Capability_Header 0x1200200 | ||
579 | #define mmAudio_AZ_Multiple_Links_Capability_Declaration 0x1200204 | ||
580 | #define mmAudio_AZ_Link0_Capabilities 0x1200240 | ||
581 | #define mmAudio_AZ_Link0_Control 0x1200244 | ||
582 | #define mmAudio_AZ_Link0_Output_Stream_ID 0x1200248 | ||
583 | #define mmAudio_AZ_Link0_SDI_Identifier 0x120024C | ||
584 | #define mmAudio_AZ_Link0_Per_Stream_Overhead 0x1200250 | ||
585 | #define mmAudio_AZ_Link0_Wall_Frame_Counter 0x1200258 | ||
586 | #define mmAudio_AZ_Link0_Output_Payload_Capability_L 0x1200260 | ||
587 | #define mmAudio_AZ_Link0_Output_Payload_Capability_U 0x1200264 | ||
588 | #define mmAudio_AZ_Link0_Input_Payload_Capability_L 0x1200270 | ||
589 | #define mmAudio_AZ_Link0_Input_Payload_Capability_U 0x1200274 | ||
590 | #define mmAudio_Az_Input_SD0LICBA 0x1202084 | ||
591 | #define mmAudio_Az_Input_SD1LICBA 0x12020A4 | ||
592 | #define mmAudio_Az_Input_SD2LICBA 0x12020C4 | ||
593 | #define mmAudio_Az_Input_SD3LICBA 0x12020E4 | ||
594 | #define mmAudio_Az_Output_SD0LICBA 0x1202104 | ||
595 | #define mmAudio_Az_Output_SD1LICBA 0x1202124 | ||
596 | #define mmAudio_Az_Output_SD2LICBA 0x1202144 | ||
597 | #define mmAudio_Az_Output_SD3LICBA 0x1202164 | ||
598 | #define mmAUDIO_AZ_POWER_MANAGEMENT_CONTROL 0x1204000 | ||
599 | #define mmAUDIO_AZ_IOC_SOFTRST_CONTROL 0x1204004 | ||
600 | #define mmAUDIO_AZ_IOC_CLKGATE_CONTROL 0x1204008 | ||
601 | |||
602 | |||
603 | // Registers from ACP_AZALIA block | ||
604 | |||
605 | #define mmACP_AZ_PAGE0_LBASE_ADDR 0x1243800 | ||
606 | #define mmACP_AZ_PAGE0_UBASE_ADDR 0x1243804 | ||
607 | #define mmACP_AZ_PAGE0_PGEN_SIZE 0x1243808 | ||
608 | #define mmACP_AZ_PAGE0_OFFSET 0x124380C | ||
609 | #define mmACP_AZ_PAGE1_LBASE_ADDR 0x1243810 | ||
610 | #define mmACP_AZ_PAGE1_UBASE_ADDR 0x1243814 | ||
611 | #define mmACP_AZ_PAGE1_PGEN_SIZE 0x1243818 | ||
612 | #define mmACP_AZ_PAGE1_OFFSET 0x124381C | ||
613 | #define mmACP_AZ_PAGE2_LBASE_ADDR 0x1243820 | ||
614 | #define mmACP_AZ_PAGE2_UBASE_ADDR 0x1243824 | ||
615 | #define mmACP_AZ_PAGE2_PGEN_SIZE 0x1243828 | ||
616 | #define mmACP_AZ_PAGE2_OFFSET 0x124382C | ||
617 | #define mmACP_AZ_PAGE3_LBASE_ADDR 0x1243830 | ||
618 | #define mmACP_AZ_PAGE3_UBASE_ADDR 0x1243834 | ||
619 | #define mmACP_AZ_PAGE3_PGEN_SIZE 0x1243838 | ||
620 | #define mmACP_AZ_PAGE3_OFFSET 0x124383C | ||
621 | #define mmACP_AZ_PAGE4_LBASE_ADDR 0x1243840 | ||
622 | #define mmACP_AZ_PAGE4_UBASE_ADDR 0x1243844 | ||
623 | #define mmACP_AZ_PAGE4_PGEN_SIZE 0x1243848 | ||
624 | #define mmACP_AZ_PAGE4_OFFSET 0x124384C | ||
625 | #define mmACP_AZ_PAGE5_LBASE_ADDR 0x1243850 | ||
626 | #define mmACP_AZ_PAGE5_UBASE_ADDR 0x1243854 | ||
627 | #define mmACP_AZ_PAGE5_PGEN_SIZE 0x1243858 | ||
628 | #define mmACP_AZ_PAGE5_OFFSET 0x124385C | ||
629 | #define mmACP_AZ_PAGE6_LBASE_ADDR 0x1243860 | ||
630 | #define mmACP_AZ_PAGE6_UBASE_ADDR 0x1243864 | ||
631 | #define mmACP_AZ_PAGE6_PGEN_SIZE 0x1243868 | ||
632 | #define mmACP_AZ_PAGE6_OFFSET 0x124386C | ||
633 | #define mmACP_AZ_PAGE7_LBASE_ADDR 0x1243870 | ||
634 | #define mmACP_AZ_PAGE7_UBASE_ADDR 0x1243874 | ||
635 | #define mmACP_AZ_PAGE7_PGEN_SIZE 0x1243878 | ||
636 | #define mmACP_AZ_PAGE7_OFFSET 0x124387C | ||
637 | |||
638 | |||
639 | #endif | ||
diff --git a/sound/soc/amd/raven/pci-acp3x.c b/sound/soc/amd/raven/pci-acp3x.c new file mode 100644 index 000000000000..facec2472b34 --- /dev/null +++ b/sound/soc/amd/raven/pci-acp3x.c | |||
@@ -0,0 +1,156 @@ | |||
1 | // SPDX-License-Identifier: GPL-2.0+ | ||
2 | // | ||
3 | // AMD ACP PCI Driver | ||
4 | // | ||
5 | //Copyright 2016 Advanced Micro Devices, Inc. | ||
6 | |||
7 | #include <linux/pci.h> | ||
8 | #include <linux/module.h> | ||
9 | #include <linux/io.h> | ||
10 | #include <linux/platform_device.h> | ||
11 | #include <linux/interrupt.h> | ||
12 | |||
13 | #include "acp3x.h" | ||
14 | |||
15 | struct acp3x_dev_data { | ||
16 | void __iomem *acp3x_base; | ||
17 | bool acp3x_audio_mode; | ||
18 | struct resource *res; | ||
19 | struct platform_device *pdev; | ||
20 | }; | ||
21 | |||
22 | static int snd_acp3x_probe(struct pci_dev *pci, | ||
23 | const struct pci_device_id *pci_id) | ||
24 | { | ||
25 | int ret; | ||
26 | u32 addr, val; | ||
27 | struct acp3x_dev_data *adata; | ||
28 | struct platform_device_info pdevinfo; | ||
29 | unsigned int irqflags; | ||
30 | |||
31 | if (pci_enable_device(pci)) { | ||
32 | dev_err(&pci->dev, "pci_enable_device failed\n"); | ||
33 | return -ENODEV; | ||
34 | } | ||
35 | |||
36 | ret = pci_request_regions(pci, "AMD ACP3x audio"); | ||
37 | if (ret < 0) { | ||
38 | dev_err(&pci->dev, "pci_request_regions failed\n"); | ||
39 | goto disable_pci; | ||
40 | } | ||
41 | |||
42 | adata = devm_kzalloc(&pci->dev, sizeof(struct acp3x_dev_data), | ||
43 | GFP_KERNEL); | ||
44 | if (!adata) { | ||
45 | ret = -ENOMEM; | ||
46 | goto release_regions; | ||
47 | } | ||
48 | |||
49 | /* check for msi interrupt support */ | ||
50 | ret = pci_enable_msi(pci); | ||
51 | if (ret) | ||
52 | /* msi is not enabled */ | ||
53 | irqflags = IRQF_SHARED; | ||
54 | else | ||
55 | /* msi is enabled */ | ||
56 | irqflags = 0; | ||
57 | |||
58 | addr = pci_resource_start(pci, 0); | ||
59 | adata->acp3x_base = ioremap(addr, pci_resource_len(pci, 0)); | ||
60 | if (!adata->acp3x_base) { | ||
61 | ret = -ENOMEM; | ||
62 | goto release_regions; | ||
63 | } | ||
64 | pci_set_master(pci); | ||
65 | pci_set_drvdata(pci, adata); | ||
66 | |||
67 | val = rv_readl(adata->acp3x_base + mmACP_I2S_PIN_CONFIG); | ||
68 | switch (val) { | ||
69 | case I2S_MODE: | ||
70 | adata->res = devm_kzalloc(&pci->dev, | ||
71 | sizeof(struct resource) * 2, | ||
72 | GFP_KERNEL); | ||
73 | if (!adata->res) { | ||
74 | ret = -ENOMEM; | ||
75 | goto unmap_mmio; | ||
76 | } | ||
77 | |||
78 | adata->res[0].name = "acp3x_i2s_iomem"; | ||
79 | adata->res[0].flags = IORESOURCE_MEM; | ||
80 | adata->res[0].start = addr; | ||
81 | adata->res[0].end = addr + (ACP3x_REG_END - ACP3x_REG_START); | ||
82 | |||
83 | adata->res[1].name = "acp3x_i2s_irq"; | ||
84 | adata->res[1].flags = IORESOURCE_IRQ; | ||
85 | adata->res[1].start = pci->irq; | ||
86 | adata->res[1].end = pci->irq; | ||
87 | |||
88 | adata->acp3x_audio_mode = ACP3x_I2S_MODE; | ||
89 | |||
90 | memset(&pdevinfo, 0, sizeof(pdevinfo)); | ||
91 | pdevinfo.name = "acp3x_rv_i2s"; | ||
92 | pdevinfo.id = 0; | ||
93 | pdevinfo.parent = &pci->dev; | ||
94 | pdevinfo.num_res = 2; | ||
95 | pdevinfo.res = adata->res; | ||
96 | pdevinfo.data = &irqflags; | ||
97 | pdevinfo.size_data = sizeof(irqflags); | ||
98 | |||
99 | adata->pdev = platform_device_register_full(&pdevinfo); | ||
100 | if (IS_ERR(adata->pdev)) { | ||
101 | dev_err(&pci->dev, "cannot register %s device\n", | ||
102 | pdevinfo.name); | ||
103 | ret = PTR_ERR(adata->pdev); | ||
104 | goto unmap_mmio; | ||
105 | } | ||
106 | break; | ||
107 | default: | ||
108 | dev_err(&pci->dev, "Invalid ACP audio mode : %d\n", val); | ||
109 | ret = -ENODEV; | ||
110 | goto unmap_mmio; | ||
111 | } | ||
112 | return 0; | ||
113 | |||
114 | unmap_mmio: | ||
115 | pci_disable_msi(pci); | ||
116 | iounmap(adata->acp3x_base); | ||
117 | release_regions: | ||
118 | pci_release_regions(pci); | ||
119 | disable_pci: | ||
120 | pci_disable_device(pci); | ||
121 | |||
122 | return ret; | ||
123 | } | ||
124 | |||
125 | static void snd_acp3x_remove(struct pci_dev *pci) | ||
126 | { | ||
127 | struct acp3x_dev_data *adata = pci_get_drvdata(pci); | ||
128 | |||
129 | platform_device_unregister(adata->pdev); | ||
130 | iounmap(adata->acp3x_base); | ||
131 | |||
132 | pci_disable_msi(pci); | ||
133 | pci_release_regions(pci); | ||
134 | pci_disable_device(pci); | ||
135 | } | ||
136 | |||
137 | static const struct pci_device_id snd_acp3x_ids[] = { | ||
138 | { PCI_DEVICE(PCI_VENDOR_ID_AMD, 0x15e2), | ||
139 | .class = PCI_CLASS_MULTIMEDIA_OTHER << 8, | ||
140 | .class_mask = 0xffffff }, | ||
141 | { 0, }, | ||
142 | }; | ||
143 | MODULE_DEVICE_TABLE(pci, snd_acp3x_ids); | ||
144 | |||
145 | static struct pci_driver acp3x_driver = { | ||
146 | .name = KBUILD_MODNAME, | ||
147 | .id_table = snd_acp3x_ids, | ||
148 | .probe = snd_acp3x_probe, | ||
149 | .remove = snd_acp3x_remove, | ||
150 | }; | ||
151 | |||
152 | module_pci_driver(acp3x_driver); | ||
153 | |||
154 | MODULE_AUTHOR("Maruthi.Bayyavarapu@amd.com"); | ||
155 | MODULE_DESCRIPTION("AMD ACP3x PCI driver"); | ||
156 | MODULE_LICENSE("GPL v2"); | ||
diff --git a/sound/soc/codecs/Kconfig b/sound/soc/codecs/Kconfig index 9cc4f1848c9b..62bdb7e333b8 100644 --- a/sound/soc/codecs/Kconfig +++ b/sound/soc/codecs/Kconfig | |||
@@ -35,6 +35,7 @@ config SND_SOC_ALL_CODECS | |||
35 | select SND_SOC_ADAU7002 | 35 | select SND_SOC_ADAU7002 |
36 | select SND_SOC_ADS117X | 36 | select SND_SOC_ADS117X |
37 | select SND_SOC_AK4104 if SPI_MASTER | 37 | select SND_SOC_AK4104 if SPI_MASTER |
38 | select SND_SOC_AK4118 if I2C | ||
38 | select SND_SOC_AK4458 if I2C | 39 | select SND_SOC_AK4458 if I2C |
39 | select SND_SOC_AK4535 if I2C | 40 | select SND_SOC_AK4535 if I2C |
40 | select SND_SOC_AK4554 | 41 | select SND_SOC_AK4554 |
@@ -392,6 +393,11 @@ config SND_SOC_AK4104 | |||
392 | tristate "AKM AK4104 CODEC" | 393 | tristate "AKM AK4104 CODEC" |
393 | depends on SPI_MASTER | 394 | depends on SPI_MASTER |
394 | 395 | ||
396 | config SND_SOC_AK4118 | ||
397 | tristate "AKM AK4118 CODEC" | ||
398 | depends on I2C | ||
399 | select REGMAP_I2C | ||
400 | |||
395 | config SND_SOC_AK4458 | 401 | config SND_SOC_AK4458 |
396 | tristate "AKM AK4458 CODEC" | 402 | tristate "AKM AK4458 CODEC" |
397 | depends on I2C | 403 | depends on I2C |
diff --git a/sound/soc/codecs/Makefile b/sound/soc/codecs/Makefile index 8ffab8c8dbfa..66f55d185620 100644 --- a/sound/soc/codecs/Makefile +++ b/sound/soc/codecs/Makefile | |||
@@ -27,6 +27,7 @@ snd-soc-adav801-objs := adav801.o | |||
27 | snd-soc-adav803-objs := adav803.o | 27 | snd-soc-adav803-objs := adav803.o |
28 | snd-soc-ads117x-objs := ads117x.o | 28 | snd-soc-ads117x-objs := ads117x.o |
29 | snd-soc-ak4104-objs := ak4104.o | 29 | snd-soc-ak4104-objs := ak4104.o |
30 | snd-soc-ak4118-objs := ak4118.o | ||
30 | snd-soc-ak4458-objs := ak4458.o | 31 | snd-soc-ak4458-objs := ak4458.o |
31 | snd-soc-ak4535-objs := ak4535.o | 32 | snd-soc-ak4535-objs := ak4535.o |
32 | snd-soc-ak4554-objs := ak4554.o | 33 | snd-soc-ak4554-objs := ak4554.o |
@@ -290,6 +291,7 @@ obj-$(CONFIG_SND_SOC_ADAV801) += snd-soc-adav801.o | |||
290 | obj-$(CONFIG_SND_SOC_ADAV803) += snd-soc-adav803.o | 291 | obj-$(CONFIG_SND_SOC_ADAV803) += snd-soc-adav803.o |
291 | obj-$(CONFIG_SND_SOC_ADS117X) += snd-soc-ads117x.o | 292 | obj-$(CONFIG_SND_SOC_ADS117X) += snd-soc-ads117x.o |
292 | obj-$(CONFIG_SND_SOC_AK4104) += snd-soc-ak4104.o | 293 | obj-$(CONFIG_SND_SOC_AK4104) += snd-soc-ak4104.o |
294 | obj-$(CONFIG_SND_SOC_AK4118) += snd-soc-ak4118.o | ||
293 | obj-$(CONFIG_SND_SOC_AK4458) += snd-soc-ak4458.o | 295 | obj-$(CONFIG_SND_SOC_AK4458) += snd-soc-ak4458.o |
294 | obj-$(CONFIG_SND_SOC_AK4535) += snd-soc-ak4535.o | 296 | obj-$(CONFIG_SND_SOC_AK4535) += snd-soc-ak4535.o |
295 | obj-$(CONFIG_SND_SOC_AK4554) += snd-soc-ak4554.o | 297 | obj-$(CONFIG_SND_SOC_AK4554) += snd-soc-ak4554.o |
diff --git a/sound/soc/codecs/ak4104.c b/sound/soc/codecs/ak4104.c index 32bc545c19cf..6dec8a65eafc 100644 --- a/sound/soc/codecs/ak4104.c +++ b/sound/soc/codecs/ak4104.c | |||
@@ -13,7 +13,7 @@ | |||
13 | #include <linux/slab.h> | 13 | #include <linux/slab.h> |
14 | #include <linux/spi/spi.h> | 14 | #include <linux/spi/spi.h> |
15 | #include <linux/of_device.h> | 15 | #include <linux/of_device.h> |
16 | #include <linux/of_gpio.h> | 16 | #include <linux/gpio/consumer.h> |
17 | #include <linux/regulator/consumer.h> | 17 | #include <linux/regulator/consumer.h> |
18 | #include <sound/asoundef.h> | 18 | #include <sound/asoundef.h> |
19 | #include <sound/core.h> | 19 | #include <sound/core.h> |
@@ -268,8 +268,8 @@ static const struct regmap_config ak4104_regmap = { | |||
268 | 268 | ||
269 | static int ak4104_spi_probe(struct spi_device *spi) | 269 | static int ak4104_spi_probe(struct spi_device *spi) |
270 | { | 270 | { |
271 | struct device_node *np = spi->dev.of_node; | ||
272 | struct ak4104_private *ak4104; | 271 | struct ak4104_private *ak4104; |
272 | struct gpio_desc *reset_gpiod; | ||
273 | unsigned int val; | 273 | unsigned int val; |
274 | int ret; | 274 | int ret; |
275 | 275 | ||
@@ -297,19 +297,11 @@ static int ak4104_spi_probe(struct spi_device *spi) | |||
297 | return ret; | 297 | return ret; |
298 | } | 298 | } |
299 | 299 | ||
300 | if (np) { | 300 | reset_gpiod = devm_gpiod_get_optional(&spi->dev, "reset", |
301 | enum of_gpio_flags flags; | 301 | GPIOD_OUT_HIGH); |
302 | int gpio = of_get_named_gpio_flags(np, "reset-gpio", 0, &flags); | 302 | if (IS_ERR(reset_gpiod) && |
303 | 303 | PTR_ERR(reset_gpiod) == -EPROBE_DEFER) | |
304 | if (gpio_is_valid(gpio)) { | 304 | return -EPROBE_DEFER; |
305 | ret = devm_gpio_request_one(&spi->dev, gpio, | ||
306 | flags & OF_GPIO_ACTIVE_LOW ? | ||
307 | GPIOF_OUT_INIT_LOW : GPIOF_OUT_INIT_HIGH, | ||
308 | "ak4104 reset"); | ||
309 | if (ret < 0) | ||
310 | return ret; | ||
311 | } | ||
312 | } | ||
313 | 305 | ||
314 | /* read the 'reserved' register - according to the datasheet, it | 306 | /* read the 'reserved' register - according to the datasheet, it |
315 | * should contain 0x5b. Not a good way to verify the presence of | 307 | * should contain 0x5b. Not a good way to verify the presence of |
diff --git a/sound/soc/codecs/ak4118.c b/sound/soc/codecs/ak4118.c new file mode 100644 index 000000000000..238ab29f2bf4 --- /dev/null +++ b/sound/soc/codecs/ak4118.c | |||
@@ -0,0 +1,438 @@ | |||
1 | // SPDX-License-Identifier: GPL-2.0 | ||
2 | /* | ||
3 | * ak4118.c -- Asahi Kasei ALSA Soc Audio driver | ||
4 | * | ||
5 | * Copyright 2018 DEVIALET | ||
6 | */ | ||
7 | |||
8 | #include <linux/i2c.h> | ||
9 | #include <linux/module.h> | ||
10 | #include <linux/of_device.h> | ||
11 | #include <linux/of_gpio.h> | ||
12 | #include <linux/regmap.h> | ||
13 | #include <linux/slab.h> | ||
14 | |||
15 | #include <sound/asoundef.h> | ||
16 | #include <sound/core.h> | ||
17 | #include <sound/initval.h> | ||
18 | #include <sound/soc.h> | ||
19 | |||
20 | #define AK4118_REG_CLK_PWR_CTL 0x00 | ||
21 | #define AK4118_REG_FORMAT_CTL 0x01 | ||
22 | #define AK4118_REG_IO_CTL0 0x02 | ||
23 | #define AK4118_REG_IO_CTL1 0x03 | ||
24 | #define AK4118_REG_INT0_MASK 0x04 | ||
25 | #define AK4118_REG_INT1_MASK 0x05 | ||
26 | #define AK4118_REG_RCV_STATUS0 0x06 | ||
27 | #define AK4118_REG_RCV_STATUS1 0x07 | ||
28 | #define AK4118_REG_RXCHAN_STATUS0 0x08 | ||
29 | #define AK4118_REG_RXCHAN_STATUS1 0x09 | ||
30 | #define AK4118_REG_RXCHAN_STATUS2 0x0a | ||
31 | #define AK4118_REG_RXCHAN_STATUS3 0x0b | ||
32 | #define AK4118_REG_RXCHAN_STATUS4 0x0c | ||
33 | #define AK4118_REG_TXCHAN_STATUS0 0x0d | ||
34 | #define AK4118_REG_TXCHAN_STATUS1 0x0e | ||
35 | #define AK4118_REG_TXCHAN_STATUS2 0x0f | ||
36 | #define AK4118_REG_TXCHAN_STATUS3 0x10 | ||
37 | #define AK4118_REG_TXCHAN_STATUS4 0x11 | ||
38 | #define AK4118_REG_BURST_PREAMB_PC0 0x12 | ||
39 | #define AK4118_REG_BURST_PREAMB_PC1 0x13 | ||
40 | #define AK4118_REG_BURST_PREAMB_PD0 0x14 | ||
41 | #define AK4118_REG_BURST_PREAMB_PD1 0x15 | ||
42 | #define AK4118_REG_QSUB_CTL 0x16 | ||
43 | #define AK4118_REG_QSUB_TRACK 0x17 | ||
44 | #define AK4118_REG_QSUB_INDEX 0x18 | ||
45 | #define AK4118_REG_QSUB_MIN 0x19 | ||
46 | #define AK4118_REG_QSUB_SEC 0x1a | ||
47 | #define AK4118_REG_QSUB_FRAME 0x1b | ||
48 | #define AK4118_REG_QSUB_ZERO 0x1c | ||
49 | #define AK4118_REG_QSUB_ABS_MIN 0x1d | ||
50 | #define AK4118_REG_QSUB_ABS_SEC 0x1e | ||
51 | #define AK4118_REG_QSUB_ABS_FRAME 0x1f | ||
52 | #define AK4118_REG_GPE 0x20 | ||
53 | #define AK4118_REG_GPDR 0x21 | ||
54 | #define AK4118_REG_GPSCR 0x22 | ||
55 | #define AK4118_REG_GPLR 0x23 | ||
56 | #define AK4118_REG_DAT_MASK_DTS 0x24 | ||
57 | #define AK4118_REG_RX_DETECT 0x25 | ||
58 | #define AK4118_REG_STC_DAT_DETECT 0x26 | ||
59 | #define AK4118_REG_RXCHAN_STATUS5 0x27 | ||
60 | #define AK4118_REG_TXCHAN_STATUS5 0x28 | ||
61 | #define AK4118_REG_MAX 0x29 | ||
62 | |||
63 | #define AK4118_REG_FORMAT_CTL_DIF0 (1 << 4) | ||
64 | #define AK4118_REG_FORMAT_CTL_DIF1 (1 << 5) | ||
65 | #define AK4118_REG_FORMAT_CTL_DIF2 (1 << 6) | ||
66 | |||
67 | struct ak4118_priv { | ||
68 | struct regmap *regmap; | ||
69 | struct gpio_desc *reset; | ||
70 | struct gpio_desc *irq; | ||
71 | struct snd_soc_component *component; | ||
72 | }; | ||
73 | |||
74 | static const struct reg_default ak4118_reg_defaults[] = { | ||
75 | {AK4118_REG_CLK_PWR_CTL, 0x43}, | ||
76 | {AK4118_REG_FORMAT_CTL, 0x6a}, | ||
77 | {AK4118_REG_IO_CTL0, 0x88}, | ||
78 | {AK4118_REG_IO_CTL1, 0x48}, | ||
79 | {AK4118_REG_INT0_MASK, 0xee}, | ||
80 | {AK4118_REG_INT1_MASK, 0xb5}, | ||
81 | {AK4118_REG_RCV_STATUS0, 0x00}, | ||
82 | {AK4118_REG_RCV_STATUS1, 0x10}, | ||
83 | {AK4118_REG_TXCHAN_STATUS0, 0x00}, | ||
84 | {AK4118_REG_TXCHAN_STATUS1, 0x00}, | ||
85 | {AK4118_REG_TXCHAN_STATUS2, 0x00}, | ||
86 | {AK4118_REG_TXCHAN_STATUS3, 0x00}, | ||
87 | {AK4118_REG_TXCHAN_STATUS4, 0x00}, | ||
88 | {AK4118_REG_GPE, 0x77}, | ||
89 | {AK4118_REG_GPDR, 0x00}, | ||
90 | {AK4118_REG_GPSCR, 0x00}, | ||
91 | {AK4118_REG_GPLR, 0x00}, | ||
92 | {AK4118_REG_DAT_MASK_DTS, 0x3f}, | ||
93 | {AK4118_REG_RX_DETECT, 0x00}, | ||
94 | {AK4118_REG_STC_DAT_DETECT, 0x00}, | ||
95 | {AK4118_REG_TXCHAN_STATUS5, 0x00}, | ||
96 | }; | ||
97 | |||
98 | static const char * const ak4118_input_select_txt[] = { | ||
99 | "RX0", "RX1", "RX2", "RX3", "RX4", "RX5", "RX6", "RX7", | ||
100 | }; | ||
101 | static SOC_ENUM_SINGLE_DECL(ak4118_insel_enum, AK4118_REG_IO_CTL1, 0x0, | ||
102 | ak4118_input_select_txt); | ||
103 | |||
104 | static const struct snd_kcontrol_new ak4118_input_mux_controls = | ||
105 | SOC_DAPM_ENUM("Input Select", ak4118_insel_enum); | ||
106 | |||
107 | static const char * const ak4118_iec958_fs_txt[] = { | ||
108 | "44100", "48000", "32000", "22050", "11025", "24000", "16000", "88200", | ||
109 | "8000", "96000", "64000", "176400", "192000", | ||
110 | }; | ||
111 | |||
112 | static const int ak4118_iec958_fs_val[] = { | ||
113 | 0x0, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7, 0x8, 0x9, 0xA, 0xB, 0xC, 0xE, | ||
114 | }; | ||
115 | |||
116 | static SOC_VALUE_ENUM_SINGLE_DECL(ak4118_iec958_fs_enum, AK4118_REG_RCV_STATUS1, | ||
117 | 0x4, 0x4, ak4118_iec958_fs_txt, | ||
118 | ak4118_iec958_fs_val); | ||
119 | |||
120 | static struct snd_kcontrol_new ak4118_iec958_controls[] = { | ||
121 | SOC_SINGLE("IEC958 Parity Errors", AK4118_REG_RCV_STATUS0, 0, 1, 0), | ||
122 | SOC_SINGLE("IEC958 No Audio", AK4118_REG_RCV_STATUS0, 1, 1, 0), | ||
123 | SOC_SINGLE("IEC958 PLL Lock", AK4118_REG_RCV_STATUS0, 4, 1, 1), | ||
124 | SOC_SINGLE("IEC958 Non PCM", AK4118_REG_RCV_STATUS0, 6, 1, 0), | ||
125 | SOC_ENUM("IEC958 Sampling Freq", ak4118_iec958_fs_enum), | ||
126 | }; | ||
127 | |||
128 | static const struct snd_soc_dapm_widget ak4118_dapm_widgets[] = { | ||
129 | SND_SOC_DAPM_INPUT("INRX0"), | ||
130 | SND_SOC_DAPM_INPUT("INRX1"), | ||
131 | SND_SOC_DAPM_INPUT("INRX2"), | ||
132 | SND_SOC_DAPM_INPUT("INRX3"), | ||
133 | SND_SOC_DAPM_INPUT("INRX4"), | ||
134 | SND_SOC_DAPM_INPUT("INRX5"), | ||
135 | SND_SOC_DAPM_INPUT("INRX6"), | ||
136 | SND_SOC_DAPM_INPUT("INRX7"), | ||
137 | SND_SOC_DAPM_MUX("Input Mux", SND_SOC_NOPM, 0, 0, | ||
138 | &ak4118_input_mux_controls), | ||
139 | }; | ||
140 | |||
141 | static const struct snd_soc_dapm_route ak4118_dapm_routes[] = { | ||
142 | {"Input Mux", "RX0", "INRX0"}, | ||
143 | {"Input Mux", "RX1", "INRX1"}, | ||
144 | {"Input Mux", "RX2", "INRX2"}, | ||
145 | {"Input Mux", "RX3", "INRX3"}, | ||
146 | {"Input Mux", "RX4", "INRX4"}, | ||
147 | {"Input Mux", "RX5", "INRX5"}, | ||
148 | {"Input Mux", "RX6", "INRX6"}, | ||
149 | {"Input Mux", "RX7", "INRX7"}, | ||
150 | }; | ||
151 | |||
152 | |||
153 | static int ak4118_set_dai_fmt_master(struct ak4118_priv *ak4118, | ||
154 | unsigned int format) | ||
155 | { | ||
156 | int dif; | ||
157 | |||
158 | switch (format & SND_SOC_DAIFMT_FORMAT_MASK) { | ||
159 | case SND_SOC_DAIFMT_I2S: | ||
160 | dif = AK4118_REG_FORMAT_CTL_DIF0 | AK4118_REG_FORMAT_CTL_DIF2; | ||
161 | break; | ||
162 | case SND_SOC_DAIFMT_RIGHT_J: | ||
163 | dif = AK4118_REG_FORMAT_CTL_DIF0 | AK4118_REG_FORMAT_CTL_DIF1; | ||
164 | break; | ||
165 | case SND_SOC_DAIFMT_LEFT_J: | ||
166 | dif = AK4118_REG_FORMAT_CTL_DIF2; | ||
167 | break; | ||
168 | default: | ||
169 | return -ENOTSUPP; | ||
170 | } | ||
171 | |||
172 | return dif; | ||
173 | } | ||
174 | |||
175 | static int ak4118_set_dai_fmt_slave(struct ak4118_priv *ak4118, | ||
176 | unsigned int format) | ||
177 | { | ||
178 | int dif; | ||
179 | |||
180 | switch (format & SND_SOC_DAIFMT_FORMAT_MASK) { | ||
181 | case SND_SOC_DAIFMT_I2S: | ||
182 | dif = AK4118_REG_FORMAT_CTL_DIF0 | AK4118_REG_FORMAT_CTL_DIF1 | | ||
183 | AK4118_REG_FORMAT_CTL_DIF2; | ||
184 | break; | ||
185 | case SND_SOC_DAIFMT_LEFT_J: | ||
186 | dif = AK4118_REG_FORMAT_CTL_DIF1 | AK4118_REG_FORMAT_CTL_DIF2; | ||
187 | break; | ||
188 | default: | ||
189 | return -ENOTSUPP; | ||
190 | } | ||
191 | |||
192 | return dif; | ||
193 | } | ||
194 | |||
195 | static int ak4118_set_dai_fmt(struct snd_soc_dai *dai, | ||
196 | unsigned int format) | ||
197 | { | ||
198 | struct snd_soc_component *component = dai->component; | ||
199 | struct ak4118_priv *ak4118 = snd_soc_component_get_drvdata(component); | ||
200 | int dif; | ||
201 | int ret = 0; | ||
202 | |||
203 | switch (format & SND_SOC_DAIFMT_MASTER_MASK) { | ||
204 | case SND_SOC_DAIFMT_CBM_CFM: | ||
205 | /* component is master */ | ||
206 | dif = ak4118_set_dai_fmt_master(ak4118, format); | ||
207 | break; | ||
208 | case SND_SOC_DAIFMT_CBS_CFS: | ||
209 | /*component is slave */ | ||
210 | dif = ak4118_set_dai_fmt_slave(ak4118, format); | ||
211 | break; | ||
212 | default: | ||
213 | ret = -ENOTSUPP; | ||
214 | goto exit; | ||
215 | } | ||
216 | |||
217 | /* format not supported */ | ||
218 | if (dif < 0) { | ||
219 | ret = dif; | ||
220 | goto exit; | ||
221 | } | ||
222 | |||
223 | ret = regmap_update_bits(ak4118->regmap, AK4118_REG_FORMAT_CTL, | ||
224 | AK4118_REG_FORMAT_CTL_DIF0 | | ||
225 | AK4118_REG_FORMAT_CTL_DIF1 | | ||
226 | AK4118_REG_FORMAT_CTL_DIF2, dif); | ||
227 | if (ret < 0) | ||
228 | goto exit; | ||
229 | |||
230 | exit: | ||
231 | return ret; | ||
232 | } | ||
233 | |||
234 | static int ak4118_hw_params(struct snd_pcm_substream *substream, | ||
235 | struct snd_pcm_hw_params *params, | ||
236 | struct snd_soc_dai *dai) | ||
237 | { | ||
238 | return 0; | ||
239 | } | ||
240 | |||
241 | static const struct snd_soc_dai_ops ak4118_dai_ops = { | ||
242 | .hw_params = ak4118_hw_params, | ||
243 | .set_fmt = ak4118_set_dai_fmt, | ||
244 | }; | ||
245 | |||
246 | static struct snd_soc_dai_driver ak4118_dai = { | ||
247 | .name = "ak4118-hifi", | ||
248 | .capture = { | ||
249 | .stream_name = "Capture", | ||
250 | .channels_min = 2, | ||
251 | .channels_max = 2, | ||
252 | .rates = SNDRV_PCM_RATE_22050 | SNDRV_PCM_RATE_32000 | | ||
253 | SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000 | | ||
254 | SNDRV_PCM_RATE_88200 | SNDRV_PCM_RATE_96000 | | ||
255 | SNDRV_PCM_RATE_176400 | SNDRV_PCM_RATE_192000, | ||
256 | .formats = SNDRV_PCM_FMTBIT_S16_LE | | ||
257 | SNDRV_PCM_FMTBIT_S24_3LE | | ||
258 | SNDRV_PCM_FMTBIT_S24_LE | ||
259 | }, | ||
260 | .ops = &ak4118_dai_ops, | ||
261 | }; | ||
262 | |||
263 | static irqreturn_t ak4118_irq_handler(int irq, void *data) | ||
264 | { | ||
265 | struct ak4118_priv *ak4118 = data; | ||
266 | struct snd_soc_component *component = ak4118->component; | ||
267 | struct snd_kcontrol_new *kctl_new; | ||
268 | struct snd_kcontrol *kctl; | ||
269 | struct snd_ctl_elem_id *id; | ||
270 | unsigned int i; | ||
271 | |||
272 | if (!component) | ||
273 | return IRQ_NONE; | ||
274 | |||
275 | for (i = 0; i < ARRAY_SIZE(ak4118_iec958_controls); i++) { | ||
276 | kctl_new = &ak4118_iec958_controls[i]; | ||
277 | kctl = snd_soc_card_get_kcontrol(component->card, | ||
278 | kctl_new->name); | ||
279 | if (!kctl) | ||
280 | continue; | ||
281 | id = &kctl->id; | ||
282 | snd_ctl_notify(component->card->snd_card, | ||
283 | SNDRV_CTL_EVENT_MASK_VALUE, id); | ||
284 | } | ||
285 | |||
286 | return IRQ_HANDLED; | ||
287 | } | ||
288 | |||
289 | static int ak4118_probe(struct snd_soc_component *component) | ||
290 | { | ||
291 | struct ak4118_priv *ak4118 = snd_soc_component_get_drvdata(component); | ||
292 | int ret = 0; | ||
293 | |||
294 | ak4118->component = component; | ||
295 | |||
296 | /* release reset */ | ||
297 | gpiod_set_value(ak4118->reset, 0); | ||
298 | |||
299 | /* unmask all int1 sources */ | ||
300 | ret = regmap_write(ak4118->regmap, AK4118_REG_INT1_MASK, 0x00); | ||
301 | if (ret < 0) { | ||
302 | dev_err(component->dev, | ||
303 | "failed to write regmap 0x%x 0x%x: %d\n", | ||
304 | AK4118_REG_INT1_MASK, 0x00, ret); | ||
305 | return ret; | ||
306 | } | ||
307 | |||
308 | /* rx detect enable on all channels */ | ||
309 | ret = regmap_write(ak4118->regmap, AK4118_REG_RX_DETECT, 0xff); | ||
310 | if (ret < 0) { | ||
311 | dev_err(component->dev, | ||
312 | "failed to write regmap 0x%x 0x%x: %d\n", | ||
313 | AK4118_REG_RX_DETECT, 0xff, ret); | ||
314 | return ret; | ||
315 | } | ||
316 | |||
317 | ret = snd_soc_add_component_controls(component, ak4118_iec958_controls, | ||
318 | ARRAY_SIZE(ak4118_iec958_controls)); | ||
319 | if (ret) { | ||
320 | dev_err(component->dev, | ||
321 | "failed to add component kcontrols: %d\n", ret); | ||
322 | return ret; | ||
323 | } | ||
324 | |||
325 | return 0; | ||
326 | } | ||
327 | |||
328 | static void ak4118_remove(struct snd_soc_component *component) | ||
329 | { | ||
330 | struct ak4118_priv *ak4118 = snd_soc_component_get_drvdata(component); | ||
331 | |||
332 | /* hold reset */ | ||
333 | gpiod_set_value(ak4118->reset, 1); | ||
334 | } | ||
335 | |||
336 | static const struct snd_soc_component_driver soc_component_drv_ak4118 = { | ||
337 | .probe = ak4118_probe, | ||
338 | .remove = ak4118_remove, | ||
339 | .dapm_widgets = ak4118_dapm_widgets, | ||
340 | .num_dapm_widgets = ARRAY_SIZE(ak4118_dapm_widgets), | ||
341 | .dapm_routes = ak4118_dapm_routes, | ||
342 | .num_dapm_routes = ARRAY_SIZE(ak4118_dapm_routes), | ||
343 | .idle_bias_on = 1, | ||
344 | .use_pmdown_time = 1, | ||
345 | .endianness = 1, | ||
346 | .non_legacy_dai_naming = 1, | ||
347 | }; | ||
348 | |||
349 | static const struct regmap_config ak4118_regmap = { | ||
350 | .reg_bits = 8, | ||
351 | .val_bits = 8, | ||
352 | |||
353 | .reg_defaults = ak4118_reg_defaults, | ||
354 | .num_reg_defaults = ARRAY_SIZE(ak4118_reg_defaults), | ||
355 | |||
356 | .cache_type = REGCACHE_NONE, | ||
357 | .max_register = AK4118_REG_MAX - 1, | ||
358 | }; | ||
359 | |||
360 | static int ak4118_i2c_probe(struct i2c_client *i2c, | ||
361 | const struct i2c_device_id *id) | ||
362 | { | ||
363 | struct ak4118_priv *ak4118; | ||
364 | int ret; | ||
365 | |||
366 | ak4118 = devm_kzalloc(&i2c->dev, sizeof(struct ak4118_priv), | ||
367 | GFP_KERNEL); | ||
368 | if (ak4118 == NULL) | ||
369 | return -ENOMEM; | ||
370 | |||
371 | ak4118->regmap = devm_regmap_init_i2c(i2c, &ak4118_regmap); | ||
372 | if (IS_ERR(ak4118->regmap)) | ||
373 | return PTR_ERR(ak4118->regmap); | ||
374 | |||
375 | i2c_set_clientdata(i2c, ak4118); | ||
376 | |||
377 | ak4118->reset = devm_gpiod_get(&i2c->dev, "reset", GPIOD_OUT_HIGH); | ||
378 | if (IS_ERR(ak4118->reset)) { | ||
379 | ret = PTR_ERR(ak4118->reset); | ||
380 | if (ret != -EPROBE_DEFER) | ||
381 | dev_err(&i2c->dev, "Failed to get reset: %d\n", ret); | ||
382 | return ret; | ||
383 | } | ||
384 | |||
385 | ak4118->irq = devm_gpiod_get(&i2c->dev, "irq", GPIOD_IN); | ||
386 | if (IS_ERR(ak4118->irq)) { | ||
387 | ret = PTR_ERR(ak4118->irq); | ||
388 | if (ret != -EPROBE_DEFER) | ||
389 | dev_err(&i2c->dev, "Failed to get IRQ: %d\n", ret); | ||
390 | return ret; | ||
391 | } | ||
392 | |||
393 | ret = devm_request_threaded_irq(&i2c->dev, gpiod_to_irq(ak4118->irq), | ||
394 | NULL, ak4118_irq_handler, | ||
395 | IRQF_TRIGGER_RISING | IRQF_ONESHOT, | ||
396 | "ak4118-irq", ak4118); | ||
397 | if (ret < 0) { | ||
398 | dev_err(&i2c->dev, "Fail to request_irq: %d\n", ret); | ||
399 | return ret; | ||
400 | } | ||
401 | |||
402 | return snd_soc_register_component(&i2c->dev, &soc_component_drv_ak4118, | ||
403 | &ak4118_dai, 1); | ||
404 | } | ||
405 | |||
406 | static int ak4118_i2c_remove(struct i2c_client *i2c) | ||
407 | { | ||
408 | snd_soc_unregister_component(&i2c->dev); | ||
409 | return 0; | ||
410 | } | ||
411 | |||
412 | static const struct of_device_id ak4118_of_match[] = { | ||
413 | { .compatible = "asahi-kasei,ak4118", }, | ||
414 | {} | ||
415 | }; | ||
416 | MODULE_DEVICE_TABLE(of, ak4118_of_match); | ||
417 | |||
418 | static const struct i2c_device_id ak4118_id_table[] = { | ||
419 | { "ak4118", 0 }, | ||
420 | {} | ||
421 | }; | ||
422 | MODULE_DEVICE_TABLE(i2c, ak4118_id_table); | ||
423 | |||
424 | static struct i2c_driver ak4118_i2c_driver = { | ||
425 | .driver = { | ||
426 | .name = "ak4118", | ||
427 | .of_match_table = of_match_ptr(ak4118_of_match), | ||
428 | }, | ||
429 | .id_table = ak4118_id_table, | ||
430 | .probe = ak4118_i2c_probe, | ||
431 | .remove = ak4118_i2c_remove, | ||
432 | }; | ||
433 | |||
434 | module_i2c_driver(ak4118_i2c_driver); | ||
435 | |||
436 | MODULE_DESCRIPTION("Asahi Kasei AK4118 ALSA SoC driver"); | ||
437 | MODULE_AUTHOR("Adrien Charruel <adrien.charruel@devialet.com>"); | ||
438 | MODULE_LICENSE("GPL"); | ||
diff --git a/sound/soc/codecs/ak4458.c b/sound/soc/codecs/ak4458.c index 299ada4dfaa0..70d4c89bd6fc 100644 --- a/sound/soc/codecs/ak4458.c +++ b/sound/soc/codecs/ak4458.c | |||
@@ -456,7 +456,7 @@ static int ak4458_startup(struct snd_pcm_substream *substream, | |||
456 | return ret; | 456 | return ret; |
457 | } | 457 | } |
458 | 458 | ||
459 | static struct snd_soc_dai_ops ak4458_dai_ops = { | 459 | static const struct snd_soc_dai_ops ak4458_dai_ops = { |
460 | .startup = ak4458_startup, | 460 | .startup = ak4458_startup, |
461 | .hw_params = ak4458_hw_params, | 461 | .hw_params = ak4458_hw_params, |
462 | .set_fmt = ak4458_set_dai_fmt, | 462 | .set_fmt = ak4458_set_dai_fmt, |
diff --git a/sound/soc/codecs/ak5558.c b/sound/soc/codecs/ak5558.c index 448bb90c9c8e..8179512129d3 100644 --- a/sound/soc/codecs/ak5558.c +++ b/sound/soc/codecs/ak5558.c | |||
@@ -130,16 +130,12 @@ static int ak5558_hw_params(struct snd_pcm_substream *substream, | |||
130 | u8 bits; | 130 | u8 bits; |
131 | int pcm_width = max(params_physical_width(params), ak5558->slot_width); | 131 | int pcm_width = max(params_physical_width(params), ak5558->slot_width); |
132 | 132 | ||
133 | /* set master/slave audio interface */ | ||
134 | bits = snd_soc_component_read32(component, AK5558_02_CONTROL1); | ||
135 | bits &= ~AK5558_BITS; | ||
136 | |||
137 | switch (pcm_width) { | 133 | switch (pcm_width) { |
138 | case 16: | 134 | case 16: |
139 | bits |= AK5558_DIF_24BIT_MODE; | 135 | bits = AK5558_DIF_24BIT_MODE; |
140 | break; | 136 | break; |
141 | case 32: | 137 | case 32: |
142 | bits |= AK5558_DIF_32BIT_MODE; | 138 | bits = AK5558_DIF_32BIT_MODE; |
143 | break; | 139 | break; |
144 | default: | 140 | default: |
145 | return -EINVAL; | 141 | return -EINVAL; |
@@ -168,18 +164,15 @@ static int ak5558_set_dai_fmt(struct snd_soc_dai *dai, unsigned int fmt) | |||
168 | } | 164 | } |
169 | 165 | ||
170 | /* set master/slave audio interface */ | 166 | /* set master/slave audio interface */ |
171 | format = snd_soc_component_read32(component, AK5558_02_CONTROL1); | ||
172 | format &= ~AK5558_DIF; | ||
173 | |||
174 | switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) { | 167 | switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) { |
175 | case SND_SOC_DAIFMT_I2S: | 168 | case SND_SOC_DAIFMT_I2S: |
176 | format |= AK5558_DIF_I2S_MODE; | 169 | format = AK5558_DIF_I2S_MODE; |
177 | break; | 170 | break; |
178 | case SND_SOC_DAIFMT_LEFT_J: | 171 | case SND_SOC_DAIFMT_LEFT_J: |
179 | format |= AK5558_DIF_MSB_MODE; | 172 | format = AK5558_DIF_MSB_MODE; |
180 | break; | 173 | break; |
181 | case SND_SOC_DAIFMT_DSP_B: | 174 | case SND_SOC_DAIFMT_DSP_B: |
182 | format |= AK5558_DIF_MSB_MODE; | 175 | format = AK5558_DIF_MSB_MODE; |
183 | break; | 176 | break; |
184 | default: | 177 | default: |
185 | return -EINVAL; | 178 | return -EINVAL; |
@@ -246,7 +239,7 @@ static int ak5558_startup(struct snd_pcm_substream *substream, | |||
246 | &ak5558_rate_constraints); | 239 | &ak5558_rate_constraints); |
247 | } | 240 | } |
248 | 241 | ||
249 | static struct snd_soc_dai_ops ak5558_dai_ops = { | 242 | static const struct snd_soc_dai_ops ak5558_dai_ops = { |
250 | .startup = ak5558_startup, | 243 | .startup = ak5558_startup, |
251 | .hw_params = ak5558_hw_params, | 244 | .hw_params = ak5558_hw_params, |
252 | 245 | ||
diff --git a/sound/soc/codecs/cs4270.c b/sound/soc/codecs/cs4270.c index 3c266eeb89bf..33d74f163bd7 100644 --- a/sound/soc/codecs/cs4270.c +++ b/sound/soc/codecs/cs4270.c | |||
@@ -29,8 +29,8 @@ | |||
29 | #include <linux/i2c.h> | 29 | #include <linux/i2c.h> |
30 | #include <linux/delay.h> | 30 | #include <linux/delay.h> |
31 | #include <linux/regulator/consumer.h> | 31 | #include <linux/regulator/consumer.h> |
32 | #include <linux/gpio/consumer.h> | ||
32 | #include <linux/of_device.h> | 33 | #include <linux/of_device.h> |
33 | #include <linux/of_gpio.h> | ||
34 | 34 | ||
35 | /* | 35 | /* |
36 | * The codec isn't really big-endian or little-endian, since the I2S | 36 | * The codec isn't really big-endian or little-endian, since the I2S |
@@ -658,8 +658,8 @@ static const struct regmap_config cs4270_regmap = { | |||
658 | static int cs4270_i2c_probe(struct i2c_client *i2c_client, | 658 | static int cs4270_i2c_probe(struct i2c_client *i2c_client, |
659 | const struct i2c_device_id *id) | 659 | const struct i2c_device_id *id) |
660 | { | 660 | { |
661 | struct device_node *np = i2c_client->dev.of_node; | ||
662 | struct cs4270_private *cs4270; | 661 | struct cs4270_private *cs4270; |
662 | struct gpio_desc *reset_gpiod; | ||
663 | unsigned int val; | 663 | unsigned int val; |
664 | int ret, i; | 664 | int ret, i; |
665 | 665 | ||
@@ -678,20 +678,11 @@ static int cs4270_i2c_probe(struct i2c_client *i2c_client, | |||
678 | if (ret < 0) | 678 | if (ret < 0) |
679 | return ret; | 679 | return ret; |
680 | 680 | ||
681 | /* See if we have a way to bring the codec out of reset */ | 681 | reset_gpiod = devm_gpiod_get_optional(&i2c_client->dev, "reset", |
682 | if (np) { | 682 | GPIOD_OUT_HIGH); |
683 | enum of_gpio_flags flags; | 683 | if (IS_ERR(reset_gpiod) && |
684 | int gpio = of_get_named_gpio_flags(np, "reset-gpio", 0, &flags); | 684 | PTR_ERR(reset_gpiod) == -EPROBE_DEFER) |
685 | 685 | return -EPROBE_DEFER; | |
686 | if (gpio_is_valid(gpio)) { | ||
687 | ret = devm_gpio_request_one(&i2c_client->dev, gpio, | ||
688 | flags & OF_GPIO_ACTIVE_LOW ? | ||
689 | GPIOF_OUT_INIT_LOW : GPIOF_OUT_INIT_HIGH, | ||
690 | "cs4270 reset"); | ||
691 | if (ret < 0) | ||
692 | return ret; | ||
693 | } | ||
694 | } | ||
695 | 686 | ||
696 | cs4270->regmap = devm_regmap_init_i2c(i2c_client, &cs4270_regmap); | 687 | cs4270->regmap = devm_regmap_init_i2c(i2c_client, &cs4270_regmap); |
697 | if (IS_ERR(cs4270->regmap)) | 688 | if (IS_ERR(cs4270->regmap)) |
diff --git a/sound/soc/codecs/dmic.c b/sound/soc/codecs/dmic.c index 71322e0410ee..da921da50ef0 100644 --- a/sound/soc/codecs/dmic.c +++ b/sound/soc/codecs/dmic.c | |||
@@ -30,9 +30,39 @@ | |||
30 | #include <sound/soc.h> | 30 | #include <sound/soc.h> |
31 | #include <sound/soc-dapm.h> | 31 | #include <sound/soc-dapm.h> |
32 | 32 | ||
33 | #define MAX_MODESWITCH_DELAY 70 | ||
34 | static int modeswitch_delay; | ||
35 | module_param(modeswitch_delay, uint, 0644); | ||
36 | |||
37 | static int wakeup_delay; | ||
38 | module_param(wakeup_delay, uint, 0644); | ||
39 | |||
33 | struct dmic { | 40 | struct dmic { |
34 | struct gpio_desc *gpio_en; | 41 | struct gpio_desc *gpio_en; |
35 | int wakeup_delay; | 42 | int wakeup_delay; |
43 | /* Delay after DMIC mode switch */ | ||
44 | int modeswitch_delay; | ||
45 | }; | ||
46 | |||
47 | int dmic_daiops_trigger(struct snd_pcm_substream *substream, | ||
48 | int cmd, struct snd_soc_dai *dai) | ||
49 | { | ||
50 | struct snd_soc_component *component = dai->component; | ||
51 | struct dmic *dmic = snd_soc_component_get_drvdata(component); | ||
52 | |||
53 | switch (cmd) { | ||
54 | case SNDRV_PCM_TRIGGER_STOP: | ||
55 | if (dmic->modeswitch_delay) | ||
56 | mdelay(dmic->modeswitch_delay); | ||
57 | |||
58 | break; | ||
59 | } | ||
60 | |||
61 | return 0; | ||
62 | } | ||
63 | |||
64 | static const struct snd_soc_dai_ops dmic_dai_ops = { | ||
65 | .trigger = dmic_daiops_trigger, | ||
36 | }; | 66 | }; |
37 | 67 | ||
38 | static int dmic_aif_event(struct snd_soc_dapm_widget *w, | 68 | static int dmic_aif_event(struct snd_soc_dapm_widget *w, |
@@ -68,6 +98,7 @@ static struct snd_soc_dai_driver dmic_dai = { | |||
68 | | SNDRV_PCM_FMTBIT_S24_LE | 98 | | SNDRV_PCM_FMTBIT_S24_LE |
69 | | SNDRV_PCM_FMTBIT_S16_LE, | 99 | | SNDRV_PCM_FMTBIT_S16_LE, |
70 | }, | 100 | }, |
101 | .ops = &dmic_dai_ops, | ||
71 | }; | 102 | }; |
72 | 103 | ||
73 | static int dmic_component_probe(struct snd_soc_component *component) | 104 | static int dmic_component_probe(struct snd_soc_component *component) |
@@ -85,6 +116,15 @@ static int dmic_component_probe(struct snd_soc_component *component) | |||
85 | 116 | ||
86 | device_property_read_u32(component->dev, "wakeup-delay-ms", | 117 | device_property_read_u32(component->dev, "wakeup-delay-ms", |
87 | &dmic->wakeup_delay); | 118 | &dmic->wakeup_delay); |
119 | device_property_read_u32(component->dev, "modeswitch-delay-ms", | ||
120 | &dmic->modeswitch_delay); | ||
121 | if (wakeup_delay) | ||
122 | dmic->wakeup_delay = wakeup_delay; | ||
123 | if (modeswitch_delay) | ||
124 | dmic->modeswitch_delay = modeswitch_delay; | ||
125 | |||
126 | if (dmic->modeswitch_delay > MAX_MODESWITCH_DELAY) | ||
127 | dmic->modeswitch_delay = MAX_MODESWITCH_DELAY; | ||
88 | 128 | ||
89 | snd_soc_component_set_drvdata(component, dmic); | 129 | snd_soc_component_set_drvdata(component, dmic); |
90 | 130 | ||
diff --git a/sound/soc/codecs/hdac_hda.c b/sound/soc/codecs/hdac_hda.c index 2aaa83028e55..ffecdaaa8cf2 100644 --- a/sound/soc/codecs/hdac_hda.c +++ b/sound/soc/codecs/hdac_hda.c | |||
@@ -46,7 +46,7 @@ static int hdac_hda_dai_set_tdm_slot(struct snd_soc_dai *dai, | |||
46 | static struct hda_pcm *snd_soc_find_pcm_from_dai(struct hdac_hda_priv *hda_pvt, | 46 | static struct hda_pcm *snd_soc_find_pcm_from_dai(struct hdac_hda_priv *hda_pvt, |
47 | struct snd_soc_dai *dai); | 47 | struct snd_soc_dai *dai); |
48 | 48 | ||
49 | static struct snd_soc_dai_ops hdac_hda_dai_ops = { | 49 | static const struct snd_soc_dai_ops hdac_hda_dai_ops = { |
50 | .startup = hdac_hda_dai_open, | 50 | .startup = hdac_hda_dai_open, |
51 | .shutdown = hdac_hda_dai_close, | 51 | .shutdown = hdac_hda_dai_close, |
52 | .prepare = hdac_hda_dai_prepare, | 52 | .prepare = hdac_hda_dai_prepare, |
diff --git a/sound/soc/codecs/hdac_hdmi.c b/sound/soc/codecs/hdac_hdmi.c index e63d6e33df48..db709eeb019c 100644 --- a/sound/soc/codecs/hdac_hdmi.c +++ b/sound/soc/codecs/hdac_hdmi.c | |||
@@ -121,8 +121,16 @@ struct hdac_hdmi_dai_port_map { | |||
121 | struct hdac_hdmi_cvt *cvt; | 121 | struct hdac_hdmi_cvt *cvt; |
122 | }; | 122 | }; |
123 | 123 | ||
124 | /* | ||
125 | * pin to port mapping table where the value indicate the pin number and | ||
126 | * the index indicate the port number with 1 base. | ||
127 | */ | ||
128 | static const int icl_pin2port_map[] = {0x4, 0x6, 0x8, 0xa, 0xb}; | ||
129 | |||
124 | struct hdac_hdmi_drv_data { | 130 | struct hdac_hdmi_drv_data { |
125 | unsigned int vendor_nid; | 131 | unsigned int vendor_nid; |
132 | const int *port_map; /* pin to port mapping table */ | ||
133 | int port_num; | ||
126 | }; | 134 | }; |
127 | 135 | ||
128 | struct hdac_hdmi_priv { | 136 | struct hdac_hdmi_priv { |
@@ -1329,11 +1337,12 @@ static int hdac_hdmi_add_pin(struct hdac_device *hdev, hda_nid_t nid) | |||
1329 | return 0; | 1337 | return 0; |
1330 | } | 1338 | } |
1331 | 1339 | ||
1332 | #define INTEL_VENDOR_NID 0x08 | 1340 | #define INTEL_VENDOR_NID_0x2 0x02 |
1333 | #define INTEL_GLK_VENDOR_NID 0x0b | 1341 | #define INTEL_VENDOR_NID_0x8 0x08 |
1342 | #define INTEL_VENDOR_NID_0xb 0x0b | ||
1334 | #define INTEL_GET_VENDOR_VERB 0xf81 | 1343 | #define INTEL_GET_VENDOR_VERB 0xf81 |
1335 | #define INTEL_SET_VENDOR_VERB 0x781 | 1344 | #define INTEL_SET_VENDOR_VERB 0x781 |
1336 | #define INTEL_EN_DP12 0x02 /* enable DP 1.2 features */ | 1345 | #define INTEL_EN_DP12 0x02 /* enable DP 1.2 features */ |
1337 | #define INTEL_EN_ALL_PIN_CVTS 0x01 /* enable 2nd & 3rd pins and convertors */ | 1346 | #define INTEL_EN_ALL_PIN_CVTS 0x01 /* enable 2nd & 3rd pins and convertors */ |
1338 | 1347 | ||
1339 | static void hdac_hdmi_skl_enable_all_pins(struct hdac_device *hdev) | 1348 | static void hdac_hdmi_skl_enable_all_pins(struct hdac_device *hdev) |
@@ -1538,7 +1547,26 @@ free_widgets: | |||
1538 | 1547 | ||
1539 | static int hdac_hdmi_pin2port(void *aptr, int pin) | 1548 | static int hdac_hdmi_pin2port(void *aptr, int pin) |
1540 | { | 1549 | { |
1541 | return pin - 4; /* map NID 0x05 -> port #1 */ | 1550 | struct hdac_device *hdev = aptr; |
1551 | struct hdac_hdmi_priv *hdmi = hdev_to_hdmi_priv(hdev); | ||
1552 | const int *map = hdmi->drv_data->port_map; | ||
1553 | int i; | ||
1554 | |||
1555 | if (!hdmi->drv_data->port_num) | ||
1556 | return pin - 4; /* map NID 0x05 -> port #1 */ | ||
1557 | |||
1558 | /* | ||
1559 | * looking for the pin number in the mapping table and return | ||
1560 | * the index which indicate the port number | ||
1561 | */ | ||
1562 | for (i = 0; i < hdmi->drv_data->port_num; i++) { | ||
1563 | if (pin == map[i]) | ||
1564 | return i + 1; | ||
1565 | } | ||
1566 | |||
1567 | /* return -1 if pin number exceeds our expectation */ | ||
1568 | dev_err(&hdev->dev, "Can't find the port for pin %d\n", pin); | ||
1569 | return -1; | ||
1542 | } | 1570 | } |
1543 | 1571 | ||
1544 | static void hdac_hdmi_eld_notify_cb(void *aptr, int port, int pipe) | 1572 | static void hdac_hdmi_eld_notify_cb(void *aptr, int port, int pipe) |
@@ -1549,9 +1577,18 @@ static void hdac_hdmi_eld_notify_cb(void *aptr, int port, int pipe) | |||
1549 | struct hdac_hdmi_port *hport = NULL; | 1577 | struct hdac_hdmi_port *hport = NULL; |
1550 | struct snd_soc_component *component = hdmi->component; | 1578 | struct snd_soc_component *component = hdmi->component; |
1551 | int i; | 1579 | int i; |
1552 | 1580 | hda_nid_t pin_nid; | |
1553 | /* Don't know how this mapping is derived */ | 1581 | |
1554 | hda_nid_t pin_nid = port + 0x04; | 1582 | if (!hdmi->drv_data->port_num) { |
1583 | /* for legacy platforms */ | ||
1584 | pin_nid = port + 0x04; | ||
1585 | } else if (port < hdmi->drv_data->port_num) { | ||
1586 | /* get pin number from the pin2port mapping table */ | ||
1587 | pin_nid = hdmi->drv_data->port_map[port - 1]; | ||
1588 | } else { | ||
1589 | dev_err(&hdev->dev, "Can't find the pin for port %d\n", port); | ||
1590 | return; | ||
1591 | } | ||
1555 | 1592 | ||
1556 | dev_dbg(&hdev->dev, "%s: for pin:%d port=%d\n", __func__, | 1593 | dev_dbg(&hdev->dev, "%s: for pin:%d port=%d\n", __func__, |
1557 | pin_nid, pipe); | 1594 | pin_nid, pipe); |
@@ -1973,12 +2010,18 @@ static int hdac_hdmi_get_spk_alloc(struct hdac_device *hdev, int pcm_idx) | |||
1973 | return port->eld.info.spk_alloc; | 2010 | return port->eld.info.spk_alloc; |
1974 | } | 2011 | } |
1975 | 2012 | ||
2013 | static struct hdac_hdmi_drv_data intel_icl_drv_data = { | ||
2014 | .vendor_nid = INTEL_VENDOR_NID_0x2, | ||
2015 | .port_map = icl_pin2port_map, | ||
2016 | .port_num = ARRAY_SIZE(icl_pin2port_map), | ||
2017 | }; | ||
2018 | |||
1976 | static struct hdac_hdmi_drv_data intel_glk_drv_data = { | 2019 | static struct hdac_hdmi_drv_data intel_glk_drv_data = { |
1977 | .vendor_nid = INTEL_GLK_VENDOR_NID, | 2020 | .vendor_nid = INTEL_VENDOR_NID_0xb, |
1978 | }; | 2021 | }; |
1979 | 2022 | ||
1980 | static struct hdac_hdmi_drv_data intel_drv_data = { | 2023 | static struct hdac_hdmi_drv_data intel_drv_data = { |
1981 | .vendor_nid = INTEL_VENDOR_NID, | 2024 | .vendor_nid = INTEL_VENDOR_NID_0x8, |
1982 | }; | 2025 | }; |
1983 | 2026 | ||
1984 | static int hdac_hdmi_dev_probe(struct hdac_device *hdev) | 2027 | static int hdac_hdmi_dev_probe(struct hdac_device *hdev) |
@@ -2258,6 +2301,8 @@ static const struct hda_device_id hdmi_list[] = { | |||
2258 | &intel_glk_drv_data), | 2301 | &intel_glk_drv_data), |
2259 | HDA_CODEC_EXT_ENTRY(0x8086280d, 0x100000, "Geminilake HDMI", | 2302 | HDA_CODEC_EXT_ENTRY(0x8086280d, 0x100000, "Geminilake HDMI", |
2260 | &intel_glk_drv_data), | 2303 | &intel_glk_drv_data), |
2304 | HDA_CODEC_EXT_ENTRY(0x8086280f, 0x100000, "Icelake HDMI", | ||
2305 | &intel_icl_drv_data), | ||
2261 | {} | 2306 | {} |
2262 | }; | 2307 | }; |
2263 | 2308 | ||
diff --git a/sound/soc/codecs/max98373.c b/sound/soc/codecs/max98373.c index a09d01318f79..9c8616a7b61c 100644 --- a/sound/soc/codecs/max98373.c +++ b/sound/soc/codecs/max98373.c | |||
@@ -724,14 +724,39 @@ static struct snd_soc_dai_driver max98373_dai[] = { | |||
724 | } | 724 | } |
725 | }; | 725 | }; |
726 | 726 | ||
727 | static void max98373_reset(struct max98373_priv *max98373, struct device *dev) | ||
728 | { | ||
729 | int ret, reg, count; | ||
730 | |||
731 | /* Software Reset */ | ||
732 | ret = regmap_update_bits(max98373->regmap, | ||
733 | MAX98373_R2000_SW_RESET, | ||
734 | MAX98373_SOFT_RESET, | ||
735 | MAX98373_SOFT_RESET); | ||
736 | if (ret) | ||
737 | dev_err(dev, "Reset command failed. (ret:%d)\n", ret); | ||
738 | |||
739 | count = 0; | ||
740 | while (count < 3) { | ||
741 | usleep_range(10000, 11000); | ||
742 | /* Software Reset Verification */ | ||
743 | ret = regmap_read(max98373->regmap, | ||
744 | MAX98373_R21FF_REV_ID, ®); | ||
745 | if (!ret) { | ||
746 | dev_info(dev, "Reset completed (retry:%d)\n", count); | ||
747 | return; | ||
748 | } | ||
749 | count++; | ||
750 | } | ||
751 | dev_err(dev, "Reset failed. (ret:%d)\n", ret); | ||
752 | } | ||
753 | |||
727 | static int max98373_probe(struct snd_soc_component *component) | 754 | static int max98373_probe(struct snd_soc_component *component) |
728 | { | 755 | { |
729 | struct max98373_priv *max98373 = snd_soc_component_get_drvdata(component); | 756 | struct max98373_priv *max98373 = snd_soc_component_get_drvdata(component); |
730 | 757 | ||
731 | /* Software Reset */ | 758 | /* Software Reset */ |
732 | regmap_write(max98373->regmap, | 759 | max98373_reset(max98373, component->dev); |
733 | MAX98373_R2000_SW_RESET, MAX98373_SOFT_RESET); | ||
734 | usleep_range(10000, 11000); | ||
735 | 760 | ||
736 | /* IV default slot configuration */ | 761 | /* IV default slot configuration */ |
737 | regmap_write(max98373->regmap, | 762 | regmap_write(max98373->regmap, |
@@ -818,9 +843,7 @@ static int max98373_resume(struct device *dev) | |||
818 | { | 843 | { |
819 | struct max98373_priv *max98373 = dev_get_drvdata(dev); | 844 | struct max98373_priv *max98373 = dev_get_drvdata(dev); |
820 | 845 | ||
821 | regmap_write(max98373->regmap, | 846 | max98373_reset(max98373, dev); |
822 | MAX98373_R2000_SW_RESET, MAX98373_SOFT_RESET); | ||
823 | usleep_range(10000, 11000); | ||
824 | regcache_cache_only(max98373->regmap, false); | 847 | regcache_cache_only(max98373->regmap, false); |
825 | regcache_sync(max98373->regmap); | 848 | regcache_sync(max98373->regmap); |
826 | return 0; | 849 | return 0; |
diff --git a/sound/soc/codecs/max9867.c b/sound/soc/codecs/max9867.c index 4ea3287162ad..8600c5439e1e 100644 --- a/sound/soc/codecs/max9867.c +++ b/sound/soc/codecs/max9867.c | |||
@@ -1,12 +1,10 @@ | |||
1 | /* | 1 | // SPDX-License-Identifier: GPL-2.0 |
2 | * max9867.c -- max9867 ALSA SoC Audio driver | 2 | // |
3 | * | 3 | // MAX9867 ALSA SoC codec driver |
4 | * Copyright 2013-15 Maxim Integrated Products | 4 | // |
5 | * | 5 | // Copyright 2013-2015 Maxim Integrated Products |
6 | * This program is free software; you can redistribute it and/or modify | 6 | // Copyright 2018 Ladislav Michl <ladis@linux-mips.org> |
7 | * it under the terms of the GNU General Public License version 2 as | 7 | // |
8 | * published by the Free Software Foundation. | ||
9 | */ | ||
10 | 8 | ||
11 | #include <linux/delay.h> | 9 | #include <linux/delay.h> |
12 | #include <linux/i2c.h> | 10 | #include <linux/i2c.h> |
@@ -23,254 +21,237 @@ static const char *const max9867_spmode[] = { | |||
23 | "Stereo Single", "Mono Single", | 21 | "Stereo Single", "Mono Single", |
24 | "Stereo Single Fast", "Mono Single Fast" | 22 | "Stereo Single Fast", "Mono Single Fast" |
25 | }; | 23 | }; |
26 | static const char *const max9867_sidetone_text[] = { | ||
27 | "None", "Left", "Right", "LeftRight", "LeftRightDiv2", | ||
28 | }; | ||
29 | static const char *const max9867_filter_text[] = {"IIR", "FIR"}; | 24 | static const char *const max9867_filter_text[] = {"IIR", "FIR"}; |
30 | 25 | ||
31 | static SOC_ENUM_SINGLE_DECL(max9867_filter, MAX9867_CODECFLTR, 7, | 26 | static SOC_ENUM_SINGLE_DECL(max9867_filter, MAX9867_CODECFLTR, 7, |
32 | max9867_filter_text); | 27 | max9867_filter_text); |
33 | static SOC_ENUM_SINGLE_DECL(max9867_spkmode, MAX9867_MODECONFIG, 0, | 28 | static SOC_ENUM_SINGLE_DECL(max9867_spkmode, MAX9867_MODECONFIG, 0, |
34 | max9867_spmode); | 29 | max9867_spmode); |
35 | static SOC_ENUM_SINGLE_DECL(max9867_sidetone, MAX9867_DACGAIN, 6, | 30 | static const SNDRV_CTL_TLVD_DECLARE_DB_RANGE(max9867_master_tlv, |
36 | max9867_sidetone_text); | 31 | 0, 2, TLV_DB_SCALE_ITEM(-8600, 200, 1), |
37 | static DECLARE_TLV_DB_SCALE(max9860_capture_tlv, -600, 200, 0); | 32 | 3, 17, TLV_DB_SCALE_ITEM(-7800, 400, 0), |
38 | static DECLARE_TLV_DB_SCALE(max9860_mic_tlv, 2000, 100, 1); | 33 | 18, 25, TLV_DB_SCALE_ITEM(-2000, 200, 0), |
39 | static DECLARE_TLV_DB_SCALE(max9860_adc_left_tlv, -1200, 100, 1); | 34 | 26, 34, TLV_DB_SCALE_ITEM( -500, 100, 0), |
40 | static DECLARE_TLV_DB_SCALE(max9860_adc_right_tlv, -1200, 100, 1); | 35 | 35, 40, TLV_DB_SCALE_ITEM( 350, 50, 0), |
41 | static const SNDRV_CTL_TLVD_DECLARE_DB_RANGE(max98088_micboost_tlv, | 36 | ); |
42 | 0, 1, TLV_DB_SCALE_ITEM(0, 2000, 0), | 37 | static DECLARE_TLV_DB_SCALE(max9867_mic_tlv, 0, 100, 0); |
43 | 2, 2, TLV_DB_SCALE_ITEM(3000, 0, 0), | 38 | static DECLARE_TLV_DB_SCALE(max9867_line_tlv, -600, 200, 0); |
39 | static DECLARE_TLV_DB_SCALE(max9867_adc_tlv, -1200, 100, 0); | ||
40 | static DECLARE_TLV_DB_SCALE(max9867_dac_tlv, -1500, 100, 0); | ||
41 | static DECLARE_TLV_DB_SCALE(max9867_dacboost_tlv, 0, 600, 0); | ||
42 | static const SNDRV_CTL_TLVD_DECLARE_DB_RANGE(max9867_micboost_tlv, | ||
43 | 0, 2, TLV_DB_SCALE_ITEM(-2000, 2000, 1), | ||
44 | 3, 3, TLV_DB_SCALE_ITEM(3000, 0, 0), | ||
44 | ); | 45 | ); |
45 | 46 | ||
46 | static const struct snd_kcontrol_new max9867_snd_controls[] = { | 47 | static const struct snd_kcontrol_new max9867_snd_controls[] = { |
47 | SOC_DOUBLE_R("Master Playback Volume", MAX9867_LEFTVOL, | 48 | SOC_DOUBLE_R_TLV("Master Playback Volume", MAX9867_LEFTVOL, |
48 | MAX9867_RIGHTVOL, 0, 63, 1), | 49 | MAX9867_RIGHTVOL, 0, 41, 1, max9867_master_tlv), |
49 | SOC_DOUBLE_R_TLV("Capture Volume", MAX9867_LEFTMICGAIN, | 50 | SOC_DOUBLE_R_TLV("Line Capture Volume", MAX9867_LEFTLINELVL, |
50 | MAX9867_RIGHTMICGAIN, | 51 | MAX9867_RIGHTLINELVL, 0, 15, 1, max9867_line_tlv), |
51 | 0, 15, 1, max9860_capture_tlv), | 52 | SOC_DOUBLE_R_TLV("Mic Capture Volume", MAX9867_LEFTMICGAIN, |
52 | SOC_DOUBLE_R_TLV("Mic Volume", MAX9867_LEFTMICGAIN, | 53 | MAX9867_RIGHTMICGAIN, 0, 20, 1, max9867_mic_tlv), |
53 | MAX9867_RIGHTMICGAIN, 0, 31, 1, max9860_mic_tlv), | 54 | SOC_DOUBLE_R_TLV("Mic Boost Capture Volume", MAX9867_LEFTMICGAIN, |
54 | SOC_DOUBLE_R_TLV("Mic Boost Volume", MAX9867_LEFTMICGAIN, | 55 | MAX9867_RIGHTMICGAIN, 5, 4, 0, max9867_micboost_tlv), |
55 | MAX9867_RIGHTMICGAIN, 5, 3, 0, max98088_micboost_tlv), | 56 | SOC_SINGLE("Digital Sidetone Volume", MAX9867_SIDETONE, 0, 31, 1), |
56 | SOC_ENUM("Digital Sidetone Src", max9867_sidetone), | 57 | SOC_SINGLE_TLV("Digital Playback Volume", MAX9867_DACLEVEL, 0, 15, 1, |
57 | SOC_SINGLE("Sidetone Volume", MAX9867_DACGAIN, 0, 31, 1), | 58 | max9867_dac_tlv), |
58 | SOC_SINGLE("DAC Volume", MAX9867_DACLEVEL, 4, 3, 0), | 59 | SOC_SINGLE_TLV("Digital Boost Playback Volume", MAX9867_DACLEVEL, 4, 3, 0, |
59 | SOC_SINGLE("DAC Attenuation", MAX9867_DACLEVEL, 0, 15, 1), | 60 | max9867_dacboost_tlv), |
60 | SOC_SINGLE_TLV("ADC Left Volume", MAX9867_ADCLEVEL, | 61 | SOC_DOUBLE_TLV("Digital Capture Volume", MAX9867_ADCLEVEL, 0, 4, 15, 1, |
61 | 4, 15, 1, max9860_adc_left_tlv), | 62 | max9867_adc_tlv), |
62 | SOC_SINGLE_TLV("ADC Right Volume", MAX9867_ADCLEVEL, | ||
63 | 0, 15, 1, max9860_adc_right_tlv), | ||
64 | SOC_ENUM("Speaker Mode", max9867_spkmode), | 63 | SOC_ENUM("Speaker Mode", max9867_spkmode), |
65 | SOC_SINGLE("Volume Smoothing Switch", MAX9867_MODECONFIG, 6, 1, 0), | 64 | SOC_SINGLE("Volume Smoothing Switch", MAX9867_MODECONFIG, 6, 1, 0), |
66 | SOC_SINGLE("ZCD Switch", MAX9867_MODECONFIG, 5, 1, 0), | 65 | SOC_SINGLE("Line ZC Switch", MAX9867_MODECONFIG, 5, 1, 0), |
67 | SOC_ENUM("DSP Filter", max9867_filter), | 66 | SOC_ENUM("DSP Filter", max9867_filter), |
68 | }; | 67 | }; |
69 | 68 | ||
70 | static const char *const max9867_mux[] = {"None", "Mic", "Line", "Mic_Line"}; | 69 | /* Input mixer */ |
70 | static const struct snd_kcontrol_new max9867_input_mixer_controls[] = { | ||
71 | SOC_DAPM_DOUBLE("Line Capture Switch", MAX9867_INPUTCONFIG, 7, 5, 1, 0), | ||
72 | SOC_DAPM_DOUBLE("Mic Capture Switch", MAX9867_INPUTCONFIG, 6, 4, 1, 0), | ||
73 | }; | ||
74 | |||
75 | /* Output mixer */ | ||
76 | static const struct snd_kcontrol_new max9867_output_mixer_controls[] = { | ||
77 | SOC_DAPM_DOUBLE_R("Line Bypass Switch", | ||
78 | MAX9867_LEFTLINELVL, MAX9867_RIGHTLINELVL, 6, 1, 1), | ||
79 | }; | ||
71 | 80 | ||
72 | static SOC_ENUM_SINGLE_DECL(max9867_mux_enum, | 81 | /* Sidetone mixer */ |
73 | MAX9867_INPUTCONFIG, MAX9867_INPUT_SHIFT, | 82 | static const struct snd_kcontrol_new max9867_sidetone_mixer_controls[] = { |
74 | max9867_mux); | 83 | SOC_DAPM_DOUBLE("Sidetone Switch", MAX9867_SIDETONE, 6, 7, 1, 0), |
84 | }; | ||
75 | 85 | ||
76 | static const struct snd_kcontrol_new max9867_dapm_mux_controls = | 86 | /* Line out switch */ |
77 | SOC_DAPM_ENUM("Route", max9867_mux_enum); | 87 | static const struct snd_kcontrol_new max9867_line_out_control = |
88 | SOC_DAPM_DOUBLE_R("Switch", | ||
89 | MAX9867_LEFTVOL, MAX9867_RIGHTVOL, 6, 1, 1); | ||
78 | 90 | ||
79 | static const struct snd_kcontrol_new max9867_left_dapm_control = | ||
80 | SOC_DAPM_SINGLE("Switch", MAX9867_PWRMAN, 6, 1, 0); | ||
81 | static const struct snd_kcontrol_new max9867_right_dapm_control = | ||
82 | SOC_DAPM_SINGLE("Switch", MAX9867_PWRMAN, 5, 1, 0); | ||
83 | static const struct snd_kcontrol_new max9867_line_dapm_control = | ||
84 | SOC_DAPM_SINGLE("Switch", MAX9867_LEFTLINELVL, 6, 1, 1); | ||
85 | 91 | ||
86 | static const struct snd_soc_dapm_widget max9867_dapm_widgets[] = { | 92 | static const struct snd_soc_dapm_widget max9867_dapm_widgets[] = { |
87 | SND_SOC_DAPM_AIF_IN("DAI_OUT", "HiFi Playback", 0, SND_SOC_NOPM, 0, 0), | 93 | SND_SOC_DAPM_INPUT("MICL"), |
88 | SND_SOC_DAPM_DAC("Left DAC", NULL, MAX9867_PWRMAN, 3, 0), | 94 | SND_SOC_DAPM_INPUT("MICR"), |
89 | SND_SOC_DAPM_DAC("Right DAC", NULL, MAX9867_PWRMAN, 2, 0), | 95 | SND_SOC_DAPM_INPUT("LINL"), |
90 | SND_SOC_DAPM_MIXER("Output Mixer", SND_SOC_NOPM, 0, 0, NULL, 0), | 96 | SND_SOC_DAPM_INPUT("LINR"), |
91 | SND_SOC_DAPM_OUTPUT("HPOUT"), | 97 | |
92 | 98 | SND_SOC_DAPM_PGA("Left Line Input", MAX9867_PWRMAN, 6, 0, NULL, 0), | |
93 | SND_SOC_DAPM_AIF_IN("DAI_IN", "HiFi Capture", 0, SND_SOC_NOPM, 0, 0), | 99 | SND_SOC_DAPM_PGA("Right Line Input", MAX9867_PWRMAN, 5, 0, NULL, 0), |
94 | SND_SOC_DAPM_ADC("Left ADC", "HiFi Capture", MAX9867_PWRMAN, 1, 0), | 100 | SND_SOC_DAPM_MIXER_NAMED_CTL("Input Mixer", SND_SOC_NOPM, 0, 0, |
95 | SND_SOC_DAPM_ADC("Right ADC", "HiFi Capture", MAX9867_PWRMAN, 0, 0), | 101 | max9867_input_mixer_controls, |
96 | SND_SOC_DAPM_MUX("Input Mux", SND_SOC_NOPM, 0, 0, | 102 | ARRAY_SIZE(max9867_input_mixer_controls)), |
97 | &max9867_dapm_mux_controls), | 103 | SND_SOC_DAPM_ADC("ADCL", "HiFi Capture", MAX9867_PWRMAN, 1, 0), |
98 | 104 | SND_SOC_DAPM_ADC("ADCR", "HiFi Capture", MAX9867_PWRMAN, 0, 0), | |
99 | SND_SOC_DAPM_MIXER("Input Mixer", SND_SOC_NOPM, 0, 0, NULL, 0), | 105 | |
100 | SND_SOC_DAPM_SWITCH("Left Line", MAX9867_LEFTLINELVL, 6, 1, | 106 | SND_SOC_DAPM_MIXER("Digital", SND_SOC_NOPM, 0, 0, |
101 | &max9867_left_dapm_control), | 107 | max9867_sidetone_mixer_controls, |
102 | SND_SOC_DAPM_SWITCH("Right Line", MAX9867_RIGTHLINELVL, 6, 1, | 108 | ARRAY_SIZE(max9867_sidetone_mixer_controls)), |
103 | &max9867_right_dapm_control), | 109 | SND_SOC_DAPM_MIXER_NAMED_CTL("Output Mixer", SND_SOC_NOPM, 0, 0, |
104 | SND_SOC_DAPM_SWITCH("Line Mixer", SND_SOC_NOPM, 0, 0, | 110 | max9867_output_mixer_controls, |
105 | &max9867_line_dapm_control), | 111 | ARRAY_SIZE(max9867_output_mixer_controls)), |
106 | SND_SOC_DAPM_INPUT("LINE_IN"), | 112 | SND_SOC_DAPM_DAC("DACL", "HiFi Playback", MAX9867_PWRMAN, 3, 0), |
113 | SND_SOC_DAPM_DAC("DACR", "HiFi Playback", MAX9867_PWRMAN, 2, 0), | ||
114 | SND_SOC_DAPM_SWITCH("Master Playback", SND_SOC_NOPM, 0, 0, | ||
115 | &max9867_line_out_control), | ||
116 | SND_SOC_DAPM_OUTPUT("LOUT"), | ||
117 | SND_SOC_DAPM_OUTPUT("ROUT"), | ||
107 | }; | 118 | }; |
108 | 119 | ||
109 | static const struct snd_soc_dapm_route max9867_audio_map[] = { | 120 | static const struct snd_soc_dapm_route max9867_audio_map[] = { |
110 | {"Left DAC", NULL, "DAI_OUT"}, | 121 | {"Left Line Input", NULL, "LINL"}, |
111 | {"Right DAC", NULL, "DAI_OUT"}, | 122 | {"Right Line Input", NULL, "LINR"}, |
112 | {"Output Mixer", NULL, "Left DAC"}, | 123 | {"Input Mixer", "Mic Capture Switch", "MICL"}, |
113 | {"Output Mixer", NULL, "Right DAC"}, | 124 | {"Input Mixer", "Mic Capture Switch", "MICR"}, |
114 | {"HPOUT", NULL, "Output Mixer"}, | 125 | {"Input Mixer", "Line Capture Switch", "Left Line Input"}, |
115 | 126 | {"Input Mixer", "Line Capture Switch", "Right Line Input"}, | |
116 | {"Left ADC", NULL, "DAI_IN"}, | 127 | {"ADCL", NULL, "Input Mixer"}, |
117 | {"Right ADC", NULL, "DAI_IN"}, | 128 | {"ADCR", NULL, "Input Mixer"}, |
118 | {"Input Mixer", NULL, "Left ADC"}, | 129 | |
119 | {"Input Mixer", NULL, "Right ADC"}, | 130 | {"Digital", "Sidetone Switch", "ADCL"}, |
120 | {"Input Mux", "Line", "Input Mixer"}, | 131 | {"Digital", "Sidetone Switch", "ADCR"}, |
121 | {"Input Mux", "Mic", "Input Mixer"}, | 132 | {"DACL", NULL, "Digital"}, |
122 | {"Input Mux", "Mic_Line", "Input Mixer"}, | 133 | {"DACR", NULL, "Digital"}, |
123 | {"Right Line", "Switch", "Input Mux"}, | 134 | |
124 | {"Left Line", "Switch", "Input Mux"}, | 135 | {"Output Mixer", "Line Bypass Switch", "Left Line Input"}, |
125 | {"LINE_IN", NULL, "Left Line"}, | 136 | {"Output Mixer", "Line Bypass Switch", "Right Line Input"}, |
126 | {"LINE_IN", NULL, "Right Line"}, | 137 | {"Output Mixer", NULL, "DACL"}, |
138 | {"Output Mixer", NULL, "DACR"}, | ||
139 | {"Master Playback", "Switch", "Output Mixer"}, | ||
140 | {"LOUT", NULL, "Master Playback"}, | ||
141 | {"ROUT", NULL, "Master Playback"}, | ||
142 | }; | ||
143 | |||
144 | static const unsigned int max9867_rates_44k1[] = { | ||
145 | 11025, 22050, 44100, | ||
146 | }; | ||
147 | |||
148 | static const struct snd_pcm_hw_constraint_list max9867_constraints_44k1 = { | ||
149 | .list = max9867_rates_44k1, | ||
150 | .count = ARRAY_SIZE(max9867_rates_44k1), | ||
127 | }; | 151 | }; |
128 | 152 | ||
129 | enum rates { | 153 | static const unsigned int max9867_rates_48k[] = { |
130 | pcm_rate_8, pcm_rate_16, pcm_rate_24, | 154 | 8000, 16000, 32000, 48000, |
131 | pcm_rate_32, pcm_rate_44, | ||
132 | pcm_rate_48, max_pcm_rate, | ||
133 | }; | 155 | }; |
134 | 156 | ||
135 | static const struct ni_div_rates { | 157 | static const struct snd_pcm_hw_constraint_list max9867_constraints_48k = { |
136 | u32 mclk; | 158 | .list = max9867_rates_48k, |
137 | u16 ni[max_pcm_rate]; | 159 | .count = ARRAY_SIZE(max9867_rates_48k), |
138 | } ni_div[] = { | ||
139 | {11289600, {0x116A, 0x22D4, 0x343F, 0x45A9, 0x6000, 0x687D} }, | ||
140 | {12000000, {0x1062, 0x20C5, 0x3127, 0x4189, 0x5A51, 0x624E} }, | ||
141 | {12288000, {0x1000, 0x2000, 0x3000, 0x4000, 0x5833, 0x6000} }, | ||
142 | {13000000, {0x0F20, 0x1E3F, 0x2D5F, 0x3C7F, 0x535F, 0x5ABE} }, | ||
143 | {19200000, {0x0A3D, 0x147B, 0x1EB8, 0x28F6, 0x3873, 0x3D71} }, | ||
144 | {24000000, {0x1062, 0x20C5, 0x1893, 0x4189, 0x5A51, 0x624E} }, | ||
145 | {26000000, {0x0F20, 0x1E3F, 0x16AF, 0x3C7F, 0x535F, 0x5ABE} }, | ||
146 | {27000000, {0x0E90, 0x1D21, 0x15D8, 0x3A41, 0x5048, 0x5762} }, | ||
147 | }; | 160 | }; |
148 | 161 | ||
149 | static inline int get_ni_value(int mclk, int rate) | 162 | struct max9867_priv { |
163 | struct regmap *regmap; | ||
164 | const struct snd_pcm_hw_constraint_list *constraints; | ||
165 | unsigned int sysclk, pclk; | ||
166 | bool master, dsp_a; | ||
167 | }; | ||
168 | |||
169 | static int max9867_startup(struct snd_pcm_substream *substream, | ||
170 | struct snd_soc_dai *dai) | ||
150 | { | 171 | { |
151 | int i, ret = 0; | 172 | struct max9867_priv *max9867 = |
173 | snd_soc_component_get_drvdata(dai->component); | ||
152 | 174 | ||
153 | /* find the closest rate index*/ | 175 | if (max9867->constraints) |
154 | for (i = 0; i < ARRAY_SIZE(ni_div); i++) { | 176 | snd_pcm_hw_constraint_list(substream->runtime, 0, |
155 | if (ni_div[i].mclk >= mclk) | 177 | SNDRV_PCM_HW_PARAM_RATE, max9867->constraints); |
156 | break; | ||
157 | } | ||
158 | if (i == ARRAY_SIZE(ni_div)) | ||
159 | return -EINVAL; | ||
160 | 178 | ||
161 | switch (rate) { | 179 | return 0; |
162 | case 8000: | ||
163 | return ni_div[i].ni[pcm_rate_8]; | ||
164 | case 16000: | ||
165 | return ni_div[i].ni[pcm_rate_16]; | ||
166 | case 32000: | ||
167 | return ni_div[i].ni[pcm_rate_32]; | ||
168 | case 44100: | ||
169 | return ni_div[i].ni[pcm_rate_44]; | ||
170 | case 48000: | ||
171 | return ni_div[i].ni[pcm_rate_48]; | ||
172 | default: | ||
173 | pr_err("%s wrong rate %d\n", __func__, rate); | ||
174 | ret = -EINVAL; | ||
175 | } | ||
176 | return ret; | ||
177 | } | 180 | } |
178 | 181 | ||
179 | static int max9867_dai_hw_params(struct snd_pcm_substream *substream, | 182 | static int max9867_dai_hw_params(struct snd_pcm_substream *substream, |
180 | struct snd_pcm_hw_params *params, struct snd_soc_dai *dai) | 183 | struct snd_pcm_hw_params *params, struct snd_soc_dai *dai) |
181 | { | 184 | { |
185 | int value; | ||
186 | unsigned long int rate, ratio; | ||
182 | struct snd_soc_component *component = dai->component; | 187 | struct snd_soc_component *component = dai->component; |
183 | struct max9867_priv *max9867 = snd_soc_component_get_drvdata(component); | 188 | struct max9867_priv *max9867 = snd_soc_component_get_drvdata(component); |
184 | unsigned int ni_h, ni_l; | 189 | unsigned int ni = DIV_ROUND_CLOSEST_ULL(96ULL * 0x10000 * params_rate(params), |
185 | int value; | 190 | max9867->pclk); |
186 | 191 | ||
187 | value = get_ni_value(max9867->sysclk, params_rate(params)); | ||
188 | if (value < 0) | ||
189 | return value; | ||
190 | |||
191 | ni_h = (0xFF00 & value) >> 8; | ||
192 | ni_l = 0x00FF & value; | ||
193 | /* set up the ni value */ | 192 | /* set up the ni value */ |
194 | regmap_update_bits(max9867->regmap, MAX9867_AUDIOCLKHIGH, | 193 | regmap_update_bits(max9867->regmap, MAX9867_AUDIOCLKHIGH, |
195 | MAX9867_NI_HIGH_MASK, ni_h); | 194 | MAX9867_NI_HIGH_MASK, (0xFF00 & ni) >> 8); |
196 | regmap_update_bits(max9867->regmap, MAX9867_AUDIOCLKLOW, | 195 | regmap_update_bits(max9867->regmap, MAX9867_AUDIOCLKLOW, |
197 | MAX9867_NI_LOW_MASK, ni_l); | 196 | MAX9867_NI_LOW_MASK, 0x00FF & ni); |
198 | if (!max9867->master) { | 197 | if (max9867->master) { |
199 | /* | 198 | if (max9867->dsp_a) { |
200 | * digital pll locks on to any externally supplied LRCLK signal | 199 | value = MAX9867_IFC1B_48X; |
201 | * and also enable rapid lock mode. | 200 | } else { |
202 | */ | 201 | rate = params_rate(params) * 2 * params_width(params); |
203 | regmap_update_bits(max9867->regmap, MAX9867_AUDIOCLKLOW, | 202 | ratio = max9867->pclk / rate; |
204 | MAX9867_RAPID_LOCK, MAX9867_RAPID_LOCK); | 203 | switch (params_width(params)) { |
205 | regmap_update_bits(max9867->regmap, MAX9867_AUDIOCLKHIGH, | ||
206 | MAX9867_PLL, MAX9867_PLL); | ||
207 | } else { | ||
208 | unsigned long int bclk_rate, pclk_bclk_ratio; | ||
209 | int bclk_value; | ||
210 | |||
211 | bclk_rate = params_rate(params) * 2 * params_width(params); | ||
212 | pclk_bclk_ratio = max9867->pclk/bclk_rate; | ||
213 | switch (params_width(params)) { | ||
214 | case 8: | ||
215 | case 16: | ||
216 | switch (pclk_bclk_ratio) { | ||
217 | case 2: | ||
218 | bclk_value = MAX9867_IFC1B_PCLK_2; | ||
219 | break; | ||
220 | case 4: | ||
221 | bclk_value = MAX9867_IFC1B_PCLK_4; | ||
222 | break; | ||
223 | case 8: | 204 | case 8: |
224 | bclk_value = MAX9867_IFC1B_PCLK_8; | ||
225 | break; | ||
226 | case 16: | 205 | case 16: |
227 | bclk_value = MAX9867_IFC1B_PCLK_16; | 206 | switch (ratio) { |
207 | case 2: | ||
208 | value = MAX9867_IFC1B_PCLK_2; | ||
209 | break; | ||
210 | case 4: | ||
211 | value = MAX9867_IFC1B_PCLK_4; | ||
212 | break; | ||
213 | case 8: | ||
214 | value = MAX9867_IFC1B_PCLK_8; | ||
215 | break; | ||
216 | case 16: | ||
217 | value = MAX9867_IFC1B_PCLK_16; | ||
218 | break; | ||
219 | default: | ||
220 | return -EINVAL; | ||
221 | } | ||
222 | break; | ||
223 | case 24: | ||
224 | value = MAX9867_IFC1B_48X; | ||
225 | break; | ||
226 | case 32: | ||
227 | value = MAX9867_IFC1B_64X; | ||
228 | break; | 228 | break; |
229 | default: | 229 | default: |
230 | dev_err(component->dev, | ||
231 | "unsupported sampling rate\n"); | ||
232 | return -EINVAL; | 230 | return -EINVAL; |
233 | } | 231 | } |
234 | break; | ||
235 | case 24: | ||
236 | bclk_value = MAX9867_IFC1B_24BIT; | ||
237 | break; | ||
238 | case 32: | ||
239 | bclk_value = MAX9867_IFC1B_32BIT; | ||
240 | break; | ||
241 | default: | ||
242 | dev_err(component->dev, "unsupported sampling rate\n"); | ||
243 | return -EINVAL; | ||
244 | } | 232 | } |
245 | regmap_update_bits(max9867->regmap, MAX9867_IFC1B, | 233 | regmap_update_bits(max9867->regmap, MAX9867_IFC1B, |
246 | MAX9867_IFC1B_BCLK_MASK, bclk_value); | 234 | MAX9867_IFC1B_BCLK_MASK, value); |
235 | } else { | ||
236 | /* | ||
237 | * digital pll locks on to any externally supplied LRCLK signal | ||
238 | * and also enable rapid lock mode. | ||
239 | */ | ||
240 | regmap_update_bits(max9867->regmap, MAX9867_AUDIOCLKLOW, | ||
241 | MAX9867_RAPID_LOCK, MAX9867_RAPID_LOCK); | ||
242 | regmap_update_bits(max9867->regmap, MAX9867_AUDIOCLKHIGH, | ||
243 | MAX9867_PLL, MAX9867_PLL); | ||
247 | } | 244 | } |
248 | return 0; | 245 | return 0; |
249 | } | 246 | } |
250 | 247 | ||
251 | static int max9867_prepare(struct snd_pcm_substream *substream, | ||
252 | struct snd_soc_dai *dai) | ||
253 | { | ||
254 | struct snd_soc_component *component = dai->component; | ||
255 | struct max9867_priv *max9867 = snd_soc_component_get_drvdata(component); | ||
256 | |||
257 | regmap_update_bits(max9867->regmap, MAX9867_PWRMAN, | ||
258 | MAX9867_SHTDOWN_MASK, MAX9867_SHTDOWN_MASK); | ||
259 | return 0; | ||
260 | } | ||
261 | |||
262 | static int max9867_mute(struct snd_soc_dai *dai, int mute) | 248 | static int max9867_mute(struct snd_soc_dai *dai, int mute) |
263 | { | 249 | { |
264 | struct snd_soc_component *component = dai->component; | 250 | struct snd_soc_component *component = dai->component; |
265 | struct max9867_priv *max9867 = snd_soc_component_get_drvdata(component); | 251 | struct max9867_priv *max9867 = snd_soc_component_get_drvdata(component); |
266 | 252 | ||
267 | if (mute) | 253 | return regmap_update_bits(max9867->regmap, MAX9867_DACLEVEL, |
268 | regmap_update_bits(max9867->regmap, MAX9867_DACLEVEL, | 254 | 1 << 6, !!mute << 6); |
269 | MAX9867_DAC_MUTE_MASK, MAX9867_DAC_MUTE_MASK); | ||
270 | else | ||
271 | regmap_update_bits(max9867->regmap, MAX9867_DACLEVEL, | ||
272 | MAX9867_DAC_MUTE_MASK, 0); | ||
273 | return 0; | ||
274 | } | 255 | } |
275 | 256 | ||
276 | static int max9867_set_dai_sysclk(struct snd_soc_dai *codec_dai, | 257 | static int max9867_set_dai_sysclk(struct snd_soc_dai *codec_dai, |
@@ -283,21 +264,29 @@ static int max9867_set_dai_sysclk(struct snd_soc_dai *codec_dai, | |||
283 | /* Set the prescaler based on the master clock frequency*/ | 264 | /* Set the prescaler based on the master clock frequency*/ |
284 | if (freq >= 10000000 && freq <= 20000000) { | 265 | if (freq >= 10000000 && freq <= 20000000) { |
285 | value |= MAX9867_PSCLK_10_20; | 266 | value |= MAX9867_PSCLK_10_20; |
286 | max9867->pclk = freq; | 267 | max9867->pclk = freq; |
287 | } else if (freq >= 20000000 && freq <= 40000000) { | 268 | } else if (freq >= 20000000 && freq <= 40000000) { |
288 | value |= MAX9867_PSCLK_20_40; | 269 | value |= MAX9867_PSCLK_20_40; |
289 | max9867->pclk = freq/2; | 270 | max9867->pclk = freq / 2; |
290 | } else if (freq >= 40000000 && freq <= 60000000) { | 271 | } else if (freq >= 40000000 && freq <= 60000000) { |
291 | value |= MAX9867_PSCLK_40_60; | 272 | value |= MAX9867_PSCLK_40_60; |
292 | max9867->pclk = freq/4; | 273 | max9867->pclk = freq / 4; |
293 | } else { | 274 | } else { |
294 | dev_err(component->dev, | 275 | dev_err(component->dev, |
295 | "Invalid clock frequency %uHz (required 10-60MHz)\n", | 276 | "Invalid clock frequency %uHz (required 10-60MHz)\n", |
296 | freq); | 277 | freq); |
297 | return -EINVAL; | 278 | return -EINVAL; |
298 | } | 279 | } |
299 | value = value << MAX9867_PSCLK_SHIFT; | 280 | if (freq % 48000 == 0) |
281 | max9867->constraints = &max9867_constraints_48k; | ||
282 | else if (freq % 44100 == 0) | ||
283 | max9867->constraints = &max9867_constraints_44k1; | ||
284 | else | ||
285 | dev_warn(component->dev, | ||
286 | "Unable to set exact rate with %uHz clock frequency\n", | ||
287 | freq); | ||
300 | max9867->sysclk = freq; | 288 | max9867->sysclk = freq; |
289 | value = value << MAX9867_PSCLK_SHIFT; | ||
301 | /* exact integer mode is not supported */ | 290 | /* exact integer mode is not supported */ |
302 | value &= ~MAX9867_FREQ_MASK; | 291 | value &= ~MAX9867_FREQ_MASK; |
303 | regmap_update_bits(max9867->regmap, MAX9867_SYSCLK, | 292 | regmap_update_bits(max9867->regmap, MAX9867_SYSCLK, |
@@ -310,16 +299,17 @@ static int max9867_dai_set_fmt(struct snd_soc_dai *codec_dai, | |||
310 | { | 299 | { |
311 | struct snd_soc_component *component = codec_dai->component; | 300 | struct snd_soc_component *component = codec_dai->component; |
312 | struct max9867_priv *max9867 = snd_soc_component_get_drvdata(component); | 301 | struct max9867_priv *max9867 = snd_soc_component_get_drvdata(component); |
313 | u8 iface1A = 0, iface1B = 0; | 302 | u8 iface1A, iface1B; |
314 | 303 | ||
315 | switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { | 304 | switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { |
316 | case SND_SOC_DAIFMT_CBM_CFM: | 305 | case SND_SOC_DAIFMT_CBM_CFM: |
317 | max9867->master = 1; | 306 | max9867->master = true; |
318 | iface1A |= MAX9867_MASTER; | 307 | iface1A = MAX9867_MASTER; |
308 | iface1B = MAX9867_IFC1B_48X; | ||
319 | break; | 309 | break; |
320 | case SND_SOC_DAIFMT_CBS_CFS: | 310 | case SND_SOC_DAIFMT_CBS_CFS: |
321 | max9867->master = 0; | 311 | max9867->master = false; |
322 | iface1A &= ~MAX9867_MASTER; | 312 | iface1A = iface1B = 0; |
323 | break; | 313 | break; |
324 | default: | 314 | default: |
325 | return -EINVAL; | 315 | return -EINVAL; |
@@ -327,9 +317,11 @@ static int max9867_dai_set_fmt(struct snd_soc_dai *codec_dai, | |||
327 | 317 | ||
328 | switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) { | 318 | switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) { |
329 | case SND_SOC_DAIFMT_I2S: | 319 | case SND_SOC_DAIFMT_I2S: |
320 | max9867->dsp_a = false; | ||
330 | iface1A |= MAX9867_I2S_DLY; | 321 | iface1A |= MAX9867_I2S_DLY; |
331 | break; | 322 | break; |
332 | case SND_SOC_DAIFMT_DSP_A: | 323 | case SND_SOC_DAIFMT_DSP_A: |
324 | max9867->dsp_a = true; | ||
333 | iface1A |= MAX9867_TDM_MODE | MAX9867_SDOUT_HIZ; | 325 | iface1A |= MAX9867_TDM_MODE | MAX9867_SDOUT_HIZ; |
334 | break; | 326 | break; |
335 | default: | 327 | default: |
@@ -355,21 +347,18 @@ static int max9867_dai_set_fmt(struct snd_soc_dai *codec_dai, | |||
355 | 347 | ||
356 | regmap_write(max9867->regmap, MAX9867_IFC1A, iface1A); | 348 | regmap_write(max9867->regmap, MAX9867_IFC1A, iface1A); |
357 | regmap_write(max9867->regmap, MAX9867_IFC1B, iface1B); | 349 | regmap_write(max9867->regmap, MAX9867_IFC1B, iface1B); |
350 | |||
358 | return 0; | 351 | return 0; |
359 | } | 352 | } |
360 | 353 | ||
361 | static const struct snd_soc_dai_ops max9867_dai_ops = { | 354 | static const struct snd_soc_dai_ops max9867_dai_ops = { |
362 | .set_fmt = max9867_dai_set_fmt, | ||
363 | .set_sysclk = max9867_set_dai_sysclk, | 355 | .set_sysclk = max9867_set_dai_sysclk, |
364 | .prepare = max9867_prepare, | 356 | .set_fmt = max9867_dai_set_fmt, |
365 | .digital_mute = max9867_mute, | 357 | .digital_mute = max9867_mute, |
366 | .hw_params = max9867_dai_hw_params, | 358 | .startup = max9867_startup, |
359 | .hw_params = max9867_dai_hw_params, | ||
367 | }; | 360 | }; |
368 | 361 | ||
369 | #define MAX9867_RATES (SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000 |\ | ||
370 | SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000) | ||
371 | #define MAX9867_FORMATS (SNDRV_PCM_FMTBIT_S16_LE) | ||
372 | |||
373 | static struct snd_soc_dai_driver max9867_dai[] = { | 362 | static struct snd_soc_dai_driver max9867_dai[] = { |
374 | { | 363 | { |
375 | .name = "max9867-aif1", | 364 | .name = "max9867-aif1", |
@@ -377,42 +366,74 @@ static struct snd_soc_dai_driver max9867_dai[] = { | |||
377 | .stream_name = "HiFi Playback", | 366 | .stream_name = "HiFi Playback", |
378 | .channels_min = 2, | 367 | .channels_min = 2, |
379 | .channels_max = 2, | 368 | .channels_max = 2, |
380 | .rates = MAX9867_RATES, | 369 | .rates = SNDRV_PCM_RATE_8000_48000, |
381 | .formats = MAX9867_FORMATS, | 370 | .formats = SNDRV_PCM_FMTBIT_S16_LE, |
382 | }, | 371 | }, |
383 | .capture = { | 372 | .capture = { |
384 | .stream_name = "HiFi Capture", | 373 | .stream_name = "HiFi Capture", |
385 | .channels_min = 2, | 374 | .channels_min = 2, |
386 | .channels_max = 2, | 375 | .channels_max = 2, |
387 | .rates = MAX9867_RATES, | 376 | .rates = SNDRV_PCM_RATE_8000_48000, |
388 | .formats = MAX9867_FORMATS, | 377 | .formats = SNDRV_PCM_FMTBIT_S16_LE, |
389 | }, | 378 | }, |
390 | .ops = &max9867_dai_ops, | 379 | .ops = &max9867_dai_ops, |
391 | .symmetric_rates = 1, | 380 | .symmetric_rates = 1, |
392 | } | 381 | } |
393 | }; | 382 | }; |
394 | 383 | ||
395 | #ifdef CONFIG_PM_SLEEP | 384 | #ifdef CONFIG_PM |
396 | static int max9867_suspend(struct device *dev) | 385 | static int max9867_suspend(struct snd_soc_component *component) |
397 | { | 386 | { |
398 | struct max9867_priv *max9867 = dev_get_drvdata(dev); | 387 | snd_soc_component_force_bias_level(component, SND_SOC_BIAS_OFF); |
399 | 388 | ||
400 | /* Drop down to power saving mode when system is suspended */ | ||
401 | regmap_update_bits(max9867->regmap, MAX9867_PWRMAN, | ||
402 | MAX9867_SHTDOWN_MASK, ~MAX9867_SHTDOWN_MASK); | ||
403 | return 0; | 389 | return 0; |
404 | } | 390 | } |
405 | 391 | ||
406 | static int max9867_resume(struct device *dev) | 392 | static int max9867_resume(struct snd_soc_component *component) |
407 | { | 393 | { |
408 | struct max9867_priv *max9867 = dev_get_drvdata(dev); | 394 | snd_soc_component_force_bias_level(component, SND_SOC_BIAS_STANDBY); |
409 | 395 | ||
410 | regmap_update_bits(max9867->regmap, MAX9867_PWRMAN, | ||
411 | MAX9867_SHTDOWN_MASK, MAX9867_SHTDOWN_MASK); | ||
412 | return 0; | 396 | return 0; |
413 | } | 397 | } |
398 | #else | ||
399 | #define max9867_suspend NULL | ||
400 | #define max9867_resume NULL | ||
414 | #endif | 401 | #endif |
415 | 402 | ||
403 | static int max9867_set_bias_level(struct snd_soc_component *component, | ||
404 | enum snd_soc_bias_level level) | ||
405 | { | ||
406 | int err; | ||
407 | struct max9867_priv *max9867 = snd_soc_component_get_drvdata(component); | ||
408 | |||
409 | switch (level) { | ||
410 | case SND_SOC_BIAS_STANDBY: | ||
411 | if (snd_soc_component_get_bias_level(component) == SND_SOC_BIAS_OFF) { | ||
412 | err = regcache_sync(max9867->regmap); | ||
413 | if (err) | ||
414 | return err; | ||
415 | |||
416 | err = regmap_update_bits(max9867->regmap, MAX9867_PWRMAN, | ||
417 | MAX9867_SHTDOWN, MAX9867_SHTDOWN); | ||
418 | if (err) | ||
419 | return err; | ||
420 | } | ||
421 | break; | ||
422 | case SND_SOC_BIAS_OFF: | ||
423 | err = regmap_update_bits(max9867->regmap, MAX9867_PWRMAN, | ||
424 | MAX9867_SHTDOWN, 0); | ||
425 | if (err) | ||
426 | return err; | ||
427 | |||
428 | regcache_mark_dirty(max9867->regmap); | ||
429 | break; | ||
430 | default: | ||
431 | break; | ||
432 | } | ||
433 | |||
434 | return 0; | ||
435 | } | ||
436 | |||
416 | static const struct snd_soc_component_driver max9867_component = { | 437 | static const struct snd_soc_component_driver max9867_component = { |
417 | .controls = max9867_snd_controls, | 438 | .controls = max9867_snd_controls, |
418 | .num_controls = ARRAY_SIZE(max9867_snd_controls), | 439 | .num_controls = ARRAY_SIZE(max9867_snd_controls), |
@@ -420,6 +441,9 @@ static const struct snd_soc_component_driver max9867_component = { | |||
420 | .num_dapm_routes = ARRAY_SIZE(max9867_audio_map), | 441 | .num_dapm_routes = ARRAY_SIZE(max9867_audio_map), |
421 | .dapm_widgets = max9867_dapm_widgets, | 442 | .dapm_widgets = max9867_dapm_widgets, |
422 | .num_dapm_widgets = ARRAY_SIZE(max9867_dapm_widgets), | 443 | .num_dapm_widgets = ARRAY_SIZE(max9867_dapm_widgets), |
444 | .suspend = max9867_suspend, | ||
445 | .resume = max9867_resume, | ||
446 | .set_bias_level = max9867_set_bias_level, | ||
423 | .idle_bias_on = 1, | 447 | .idle_bias_on = 1, |
424 | .use_pmdown_time = 1, | 448 | .use_pmdown_time = 1, |
425 | .endianness = 1, | 449 | .endianness = 1, |
@@ -450,8 +474,8 @@ static const struct reg_default max9867_reg[] = { | |||
450 | { 0x0B, 0x00 }, | 474 | { 0x0B, 0x00 }, |
451 | { 0x0C, 0x00 }, | 475 | { 0x0C, 0x00 }, |
452 | { 0x0D, 0x00 }, | 476 | { 0x0D, 0x00 }, |
453 | { 0x0E, 0x00 }, | 477 | { 0x0E, 0x40 }, |
454 | { 0x0F, 0x00 }, | 478 | { 0x0F, 0x40 }, |
455 | { 0x10, 0x00 }, | 479 | { 0x10, 0x00 }, |
456 | { 0x11, 0x00 }, | 480 | { 0x11, 0x00 }, |
457 | { 0x12, 0x00 }, | 481 | { 0x12, 0x00 }, |
@@ -476,10 +500,9 @@ static int max9867_i2c_probe(struct i2c_client *i2c, | |||
476 | const struct i2c_device_id *id) | 500 | const struct i2c_device_id *id) |
477 | { | 501 | { |
478 | struct max9867_priv *max9867; | 502 | struct max9867_priv *max9867; |
479 | int ret = 0, reg; | 503 | int ret, reg; |
480 | 504 | ||
481 | max9867 = devm_kzalloc(&i2c->dev, | 505 | max9867 = devm_kzalloc(&i2c->dev, sizeof(*max9867), GFP_KERNEL); |
482 | sizeof(*max9867), GFP_KERNEL); | ||
483 | if (!max9867) | 506 | if (!max9867) |
484 | return -ENOMEM; | 507 | return -ENOMEM; |
485 | 508 | ||
@@ -490,8 +513,7 @@ static int max9867_i2c_probe(struct i2c_client *i2c, | |||
490 | dev_err(&i2c->dev, "Failed to allocate regmap: %d\n", ret); | 513 | dev_err(&i2c->dev, "Failed to allocate regmap: %d\n", ret); |
491 | return ret; | 514 | return ret; |
492 | } | 515 | } |
493 | ret = regmap_read(max9867->regmap, | 516 | ret = regmap_read(max9867->regmap, MAX9867_REVISION, ®); |
494 | MAX9867_REVISION, ®); | ||
495 | if (ret < 0) { | 517 | if (ret < 0) { |
496 | dev_err(&i2c->dev, "Failed to read: %d\n", ret); | 518 | dev_err(&i2c->dev, "Failed to read: %d\n", ret); |
497 | return ret; | 519 | return ret; |
@@ -499,10 +521,8 @@ static int max9867_i2c_probe(struct i2c_client *i2c, | |||
499 | dev_info(&i2c->dev, "device revision: %x\n", reg); | 521 | dev_info(&i2c->dev, "device revision: %x\n", reg); |
500 | ret = devm_snd_soc_register_component(&i2c->dev, &max9867_component, | 522 | ret = devm_snd_soc_register_component(&i2c->dev, &max9867_component, |
501 | max9867_dai, ARRAY_SIZE(max9867_dai)); | 523 | max9867_dai, ARRAY_SIZE(max9867_dai)); |
502 | if (ret < 0) { | 524 | if (ret < 0) |
503 | dev_err(&i2c->dev, "Failed to register component: %d\n", ret); | 525 | dev_err(&i2c->dev, "Failed to register component: %d\n", ret); |
504 | return ret; | ||
505 | } | ||
506 | return ret; | 526 | return ret; |
507 | } | 527 | } |
508 | 528 | ||
@@ -518,15 +538,10 @@ static const struct of_device_id max9867_of_match[] = { | |||
518 | }; | 538 | }; |
519 | MODULE_DEVICE_TABLE(of, max9867_of_match); | 539 | MODULE_DEVICE_TABLE(of, max9867_of_match); |
520 | 540 | ||
521 | static const struct dev_pm_ops max9867_pm_ops = { | ||
522 | SET_SYSTEM_SLEEP_PM_OPS(max9867_suspend, max9867_resume) | ||
523 | }; | ||
524 | |||
525 | static struct i2c_driver max9867_i2c_driver = { | 541 | static struct i2c_driver max9867_i2c_driver = { |
526 | .driver = { | 542 | .driver = { |
527 | .name = "max9867", | 543 | .name = "max9867", |
528 | .of_match_table = of_match_ptr(max9867_of_match), | 544 | .of_match_table = of_match_ptr(max9867_of_match), |
529 | .pm = &max9867_pm_ops, | ||
530 | }, | 545 | }, |
531 | .probe = max9867_i2c_probe, | 546 | .probe = max9867_i2c_probe, |
532 | .id_table = max9867_i2c_id, | 547 | .id_table = max9867_i2c_id, |
@@ -534,6 +549,6 @@ static struct i2c_driver max9867_i2c_driver = { | |||
534 | 549 | ||
535 | module_i2c_driver(max9867_i2c_driver); | 550 | module_i2c_driver(max9867_i2c_driver); |
536 | 551 | ||
537 | MODULE_AUTHOR("anish kumar <yesanishhere@gmail.com>"); | 552 | MODULE_AUTHOR("Ladislav Michl <ladis@linux-mips.org>"); |
538 | MODULE_DESCRIPTION("ALSA SoC MAX9867 driver"); | 553 | MODULE_DESCRIPTION("ASoC MAX9867 driver"); |
539 | MODULE_LICENSE("GPL"); | 554 | MODULE_LICENSE("GPL"); |
diff --git a/sound/soc/codecs/max9867.h b/sound/soc/codecs/max9867.h index 55cd9976ff47..2277798291a1 100644 --- a/sound/soc/codecs/max9867.h +++ b/sound/soc/codecs/max9867.h | |||
@@ -26,13 +26,11 @@ | |||
26 | #define MAX9867_PSCLK_10_20 0x1 | 26 | #define MAX9867_PSCLK_10_20 0x1 |
27 | #define MAX9867_PSCLK_20_40 0x2 | 27 | #define MAX9867_PSCLK_20_40 0x2 |
28 | #define MAX9867_PSCLK_40_60 0x3 | 28 | #define MAX9867_PSCLK_40_60 0x3 |
29 | #define MAX9867_AUDIOCLKHIGH 0x06 | 29 | #define MAX9867_AUDIOCLKHIGH 0x06 |
30 | #define MAX9867_NI_HIGH_WIDTH 0x7 | 30 | #define MAX9867_NI_HIGH_MASK 0x7F |
31 | #define MAX9867_NI_HIGH_MASK 0x7F | 31 | #define MAX9867_NI_LOW_MASK 0xFE |
32 | #define MAX9867_NI_LOW_MASK 0x7F | 32 | #define MAX9867_PLL (1<<7) |
33 | #define MAX9867_NI_LOW_SHIFT 0x1 | 33 | #define MAX9867_AUDIOCLKLOW 0x07 |
34 | #define MAX9867_PLL (1<<7) | ||
35 | #define MAX9867_AUDIOCLKLOW 0x07 | ||
36 | #define MAX9867_RAPID_LOCK 0x01 | 34 | #define MAX9867_RAPID_LOCK 0x01 |
37 | #define MAX9867_IFC1A 0x08 | 35 | #define MAX9867_IFC1A 0x08 |
38 | #define MAX9867_MASTER (1<<7) | 36 | #define MAX9867_MASTER (1<<7) |
@@ -43,40 +41,29 @@ | |||
43 | #define MAX9867_BCI_MODE (1<<5) | 41 | #define MAX9867_BCI_MODE (1<<5) |
44 | #define MAX9867_IFC1B 0x09 | 42 | #define MAX9867_IFC1B 0x09 |
45 | #define MAX9867_IFC1B_BCLK_MASK 7 | 43 | #define MAX9867_IFC1B_BCLK_MASK 7 |
46 | #define MAX9867_IFC1B_32BIT 0x01 | 44 | #define MAX9867_IFC1B_64X 0x01 |
47 | #define MAX9867_IFC1B_24BIT 0x02 | 45 | #define MAX9867_IFC1B_48X 0x02 |
48 | #define MAX9867_IFC1B_PCLK_2 4 | 46 | #define MAX9867_IFC1B_PCLK_2 0x04 |
49 | #define MAX9867_IFC1B_PCLK_4 5 | 47 | #define MAX9867_IFC1B_PCLK_4 0x05 |
50 | #define MAX9867_IFC1B_PCLK_8 6 | 48 | #define MAX9867_IFC1B_PCLK_8 0x06 |
51 | #define MAX9867_IFC1B_PCLK_16 7 | 49 | #define MAX9867_IFC1B_PCLK_16 0x07 |
52 | #define MAX9867_CODECFLTR 0x0a | 50 | #define MAX9867_CODECFLTR 0x0a |
53 | #define MAX9867_DACGAIN 0x0b | 51 | #define MAX9867_SIDETONE 0x0b |
54 | #define MAX9867_DACLEVEL 0x0c | 52 | #define MAX9867_DACLEVEL 0x0c |
55 | #define MAX9867_DAC_MUTE_SHIFT 0x6 | ||
56 | #define MAX9867_DAC_MUTE_WIDTH 0x1 | ||
57 | #define MAX9867_DAC_MUTE_MASK (0x1<<MAX9867_DAC_MUTE_SHIFT) | ||
58 | #define MAX9867_ADCLEVEL 0x0d | 53 | #define MAX9867_ADCLEVEL 0x0d |
59 | #define MAX9867_LEFTLINELVL 0x0e | 54 | #define MAX9867_LEFTLINELVL 0x0e |
60 | #define MAX9867_RIGTHLINELVL 0x0f | 55 | #define MAX9867_RIGHTLINELVL 0x0f |
61 | #define MAX9867_LEFTVOL 0x10 | 56 | #define MAX9867_LEFTVOL 0x10 |
62 | #define MAX9867_RIGHTVOL 0x11 | 57 | #define MAX9867_RIGHTVOL 0x11 |
63 | #define MAX9867_LEFTMICGAIN 0x12 | 58 | #define MAX9867_LEFTMICGAIN 0x12 |
64 | #define MAX9867_RIGHTMICGAIN 0x13 | 59 | #define MAX9867_RIGHTMICGAIN 0x13 |
65 | #define MAX9867_INPUTCONFIG 0x14 | 60 | #define MAX9867_INPUTCONFIG 0x14 |
66 | #define MAX9867_INPUT_SHIFT 0x6 | ||
67 | #define MAX9867_MICCONFIG 0x15 | 61 | #define MAX9867_MICCONFIG 0x15 |
68 | #define MAX9867_MODECONFIG 0x16 | 62 | #define MAX9867_MODECONFIG 0x16 |
69 | #define MAX9867_PWRMAN 0x17 | 63 | #define MAX9867_PWRMAN 0x17 |
70 | #define MAX9867_SHTDOWN_MASK (1<<7) | 64 | #define MAX9867_SHTDOWN 0x80 |
71 | #define MAX9867_REVISION 0xff | 65 | #define MAX9867_REVISION 0xff |
72 | 66 | ||
73 | #define MAX9867_CACHEREGNUM 10 | 67 | #define MAX9867_CACHEREGNUM 10 |
74 | 68 | ||
75 | /* codec private data */ | ||
76 | struct max9867_priv { | ||
77 | struct regmap *regmap; | ||
78 | unsigned int sysclk; | ||
79 | unsigned int pclk; | ||
80 | unsigned int master; | ||
81 | }; | ||
82 | #endif | 69 | #endif |
diff --git a/sound/soc/codecs/nau8540.c b/sound/soc/codecs/nau8540.c index e3c8cd17daf2..4dd1a609756b 100644 --- a/sound/soc/codecs/nau8540.c +++ b/sound/soc/codecs/nau8540.c | |||
@@ -585,7 +585,7 @@ static int nau8540_calc_fll_param(unsigned int fll_in, | |||
585 | fvco_max = 0; | 585 | fvco_max = 0; |
586 | fvco_sel = ARRAY_SIZE(mclk_src_scaling); | 586 | fvco_sel = ARRAY_SIZE(mclk_src_scaling); |
587 | for (i = 0; i < ARRAY_SIZE(mclk_src_scaling); i++) { | 587 | for (i = 0; i < ARRAY_SIZE(mclk_src_scaling); i++) { |
588 | fvco = 256 * fs * 2 * mclk_src_scaling[i].param; | 588 | fvco = 256ULL * fs * 2 * mclk_src_scaling[i].param; |
589 | if (fvco > NAU_FVCO_MIN && fvco < NAU_FVCO_MAX && | 589 | if (fvco > NAU_FVCO_MIN && fvco < NAU_FVCO_MAX && |
590 | fvco_max < fvco) { | 590 | fvco_max < fvco) { |
591 | fvco_max = fvco; | 591 | fvco_max = fvco; |
diff --git a/sound/soc/codecs/nau8822.c b/sound/soc/codecs/nau8822.c index 622ce947f134..c6152a044416 100644 --- a/sound/soc/codecs/nau8822.c +++ b/sound/soc/codecs/nau8822.c | |||
@@ -1,18 +1,14 @@ | |||
1 | /* | 1 | // SPDX-License-Identifier: GPL-2.0 |
2 | * nau8822.c -- NAU8822 ALSA Soc Audio Codec driver | 2 | // |
3 | * | 3 | // nau8822.c -- NAU8822 ALSA Soc Audio driver |
4 | * Copyright 2017 Nuvoton Technology Corp. | 4 | // |
5 | * | 5 | // Copyright 2017 Nuvoton Technology Crop. |
6 | * Author: David Lin <ctlin0@nuvoton.com> | 6 | // |
7 | * Co-author: John Hsu <kchsu0@nuvoton.com> | 7 | // Author: David Lin <ctlin0@nuvoton.com> |
8 | * Co-author: Seven Li <wtli@nuvoton.com> | 8 | // Co-author: John Hsu <kchsu0@nuvoton.com> |
9 | * | 9 | // Co-author: Seven Li <wtli@nuvoton.com> |
10 | * Based on WM8974.c | 10 | // |
11 | * | 11 | // Based on WM8974.c |
12 | * This program is free software; you can redistribute it and/or modify | ||
13 | * it under the terms of the GNU General Public License version 2 as | ||
14 | * published by the Free Software Foundation. | ||
15 | */ | ||
16 | 12 | ||
17 | #include <linux/module.h> | 13 | #include <linux/module.h> |
18 | #include <linux/moduleparam.h> | 14 | #include <linux/moduleparam.h> |
diff --git a/sound/soc/codecs/nau8822.h b/sound/soc/codecs/nau8822.h index aa79c969cd44..9c552983a293 100644 --- a/sound/soc/codecs/nau8822.h +++ b/sound/soc/codecs/nau8822.h | |||
@@ -1,13 +1,12 @@ | |||
1 | /* SPDX-License-Identifier: GPL-2.0 */ | ||
1 | /* | 2 | /* |
2 | * nau8822.h -- NAU8822 Soc Audio Codec driver | 3 | * nau8822.h -- NAU8822 ALSA SoC Audio driver |
4 | * | ||
5 | * Copyright 2017 Nuvoton Technology Crop. | ||
3 | * | 6 | * |
4 | * Author: David Lin <ctlin0@nuvoton.com> | 7 | * Author: David Lin <ctlin0@nuvoton.com> |
5 | * Co-author: John Hsu <kchsu0@nuvoton.com> | 8 | * Co-author: John Hsu <kchsu0@nuvoton.com> |
6 | * Co-author: Seven Li <wtli@nuvoton.com> | 9 | * Co-author: Seven Li <wtli@nuvoton.com> |
7 | * | ||
8 | * This program is free software; you can redistribute it and/or modify | ||
9 | * it under the terms of the GNU General Public License version 2 as | ||
10 | * published by the Free Software Foundation. | ||
11 | */ | 10 | */ |
12 | 11 | ||
13 | #ifndef __NAU8822_H__ | 12 | #ifndef __NAU8822_H__ |
diff --git a/sound/soc/codecs/nau8825.c b/sound/soc/codecs/nau8825.c index b9fed99d8b5e..7bbcbf5f05c8 100644 --- a/sound/soc/codecs/nau8825.c +++ b/sound/soc/codecs/nau8825.c | |||
@@ -424,10 +424,8 @@ static u32 nau8825_xtalk_sidetone(u32 sig_org, u32 sig_cros) | |||
424 | { | 424 | { |
425 | u32 gain, sidetone; | 425 | u32 gain, sidetone; |
426 | 426 | ||
427 | if (unlikely(sig_org == 0) || unlikely(sig_cros == 0)) { | 427 | if (WARN_ON(sig_org == 0 || sig_cros == 0)) |
428 | WARN_ON(1); | ||
429 | return 0; | 428 | return 0; |
430 | } | ||
431 | 429 | ||
432 | sig_org = nau8825_intlog10_dec3(sig_org); | 430 | sig_org = nau8825_intlog10_dec3(sig_org); |
433 | sig_cros = nau8825_intlog10_dec3(sig_cros); | 431 | sig_cros = nau8825_intlog10_dec3(sig_cros); |
diff --git a/sound/soc/codecs/pcm3060.c b/sound/soc/codecs/pcm3060.c index 771b46e1974b..6714aa8d9026 100644 --- a/sound/soc/codecs/pcm3060.c +++ b/sound/soc/codecs/pcm3060.c | |||
@@ -198,19 +198,25 @@ static const struct snd_kcontrol_new pcm3060_dapm_controls[] = { | |||
198 | }; | 198 | }; |
199 | 199 | ||
200 | static const struct snd_soc_dapm_widget pcm3060_dapm_widgets[] = { | 200 | static const struct snd_soc_dapm_widget pcm3060_dapm_widgets[] = { |
201 | SND_SOC_DAPM_DAC("DAC", "Playback", PCM3060_REG64, | ||
202 | PCM3060_REG_SHIFT_DAPSV, 1), | ||
203 | |||
201 | SND_SOC_DAPM_OUTPUT("OUTL"), | 204 | SND_SOC_DAPM_OUTPUT("OUTL"), |
202 | SND_SOC_DAPM_OUTPUT("OUTR"), | 205 | SND_SOC_DAPM_OUTPUT("OUTR"), |
203 | 206 | ||
204 | SND_SOC_DAPM_INPUT("INL"), | 207 | SND_SOC_DAPM_INPUT("INL"), |
205 | SND_SOC_DAPM_INPUT("INR"), | 208 | SND_SOC_DAPM_INPUT("INR"), |
209 | |||
210 | SND_SOC_DAPM_ADC("ADC", "Capture", PCM3060_REG64, | ||
211 | PCM3060_REG_SHIFT_ADPSV, 1), | ||
206 | }; | 212 | }; |
207 | 213 | ||
208 | static const struct snd_soc_dapm_route pcm3060_dapm_map[] = { | 214 | static const struct snd_soc_dapm_route pcm3060_dapm_map[] = { |
209 | { "OUTL", NULL, "Playback" }, | 215 | { "OUTL", NULL, "DAC" }, |
210 | { "OUTR", NULL, "Playback" }, | 216 | { "OUTR", NULL, "DAC" }, |
211 | 217 | ||
212 | { "Capture", NULL, "INL" }, | 218 | { "ADC", NULL, "INL" }, |
213 | { "Capture", NULL, "INR" }, | 219 | { "ADC", NULL, "INR" }, |
214 | }; | 220 | }; |
215 | 221 | ||
216 | /* soc component */ | 222 | /* soc component */ |
@@ -270,9 +276,23 @@ EXPORT_SYMBOL(pcm3060_regmap); | |||
270 | 276 | ||
271 | /* device */ | 277 | /* device */ |
272 | 278 | ||
279 | static void pcm3060_parse_dt(const struct device_node *np, | ||
280 | struct pcm3060_priv *priv) | ||
281 | { | ||
282 | priv->out_se = of_property_read_bool(np, "ti,out-single-ended"); | ||
283 | } | ||
284 | |||
273 | int pcm3060_probe(struct device *dev) | 285 | int pcm3060_probe(struct device *dev) |
274 | { | 286 | { |
275 | int rc; | 287 | int rc; |
288 | struct pcm3060_priv *priv = dev_get_drvdata(dev); | ||
289 | |||
290 | if (dev->of_node) | ||
291 | pcm3060_parse_dt(dev->of_node, priv); | ||
292 | |||
293 | if (priv->out_se) | ||
294 | regmap_update_bits(priv->regmap, PCM3060_REG64, | ||
295 | PCM3060_REG_SE, PCM3060_REG_SE); | ||
276 | 296 | ||
277 | rc = devm_snd_soc_register_component(dev, &pcm3060_soc_comp_driver, | 297 | rc = devm_snd_soc_register_component(dev, &pcm3060_soc_comp_driver, |
278 | pcm3060_dai, | 298 | pcm3060_dai, |
diff --git a/sound/soc/codecs/pcm3060.h b/sound/soc/codecs/pcm3060.h index fd89a68aa8a7..6a027b4a845d 100644 --- a/sound/soc/codecs/pcm3060.h +++ b/sound/soc/codecs/pcm3060.h | |||
@@ -25,6 +25,7 @@ struct pcm3060_priv_dai { | |||
25 | struct pcm3060_priv { | 25 | struct pcm3060_priv { |
26 | struct regmap *regmap; | 26 | struct regmap *regmap; |
27 | struct pcm3060_priv_dai dai[PCM3060_DAI_IDS_NUM]; | 27 | struct pcm3060_priv_dai dai[PCM3060_DAI_IDS_NUM]; |
28 | u8 out_se: 1; | ||
28 | }; | 29 | }; |
29 | 30 | ||
30 | int pcm3060_probe(struct device *dev); | 31 | int pcm3060_probe(struct device *dev); |
@@ -36,7 +37,9 @@ int pcm3060_remove(struct device *dev); | |||
36 | #define PCM3060_REG_MRST 0x80 | 37 | #define PCM3060_REG_MRST 0x80 |
37 | #define PCM3060_REG_SRST 0x40 | 38 | #define PCM3060_REG_SRST 0x40 |
38 | #define PCM3060_REG_ADPSV 0x20 | 39 | #define PCM3060_REG_ADPSV 0x20 |
40 | #define PCM3060_REG_SHIFT_ADPSV 0x05 | ||
39 | #define PCM3060_REG_DAPSV 0x10 | 41 | #define PCM3060_REG_DAPSV 0x10 |
42 | #define PCM3060_REG_SHIFT_DAPSV 0x04 | ||
40 | #define PCM3060_REG_SE 0x01 | 43 | #define PCM3060_REG_SE 0x01 |
41 | 44 | ||
42 | #define PCM3060_REG65 0x41 | 45 | #define PCM3060_REG65 0x41 |
diff --git a/sound/soc/codecs/pcm3168a.c b/sound/soc/codecs/pcm3168a.c index 445d025e1409..08d3fe192e65 100644 --- a/sound/soc/codecs/pcm3168a.c +++ b/sound/soc/codecs/pcm3168a.c | |||
@@ -133,10 +133,6 @@ static const struct snd_kcontrol_new pcm3168a_snd_controls[] = { | |||
133 | SOC_DOUBLE("DAC2 Invert Switch", PCM3168A_DAC_INV, 2, 3, 1, 0), | 133 | SOC_DOUBLE("DAC2 Invert Switch", PCM3168A_DAC_INV, 2, 3, 1, 0), |
134 | SOC_DOUBLE("DAC3 Invert Switch", PCM3168A_DAC_INV, 4, 5, 1, 0), | 134 | SOC_DOUBLE("DAC3 Invert Switch", PCM3168A_DAC_INV, 4, 5, 1, 0), |
135 | SOC_DOUBLE("DAC4 Invert Switch", PCM3168A_DAC_INV, 6, 7, 1, 0), | 135 | SOC_DOUBLE("DAC4 Invert Switch", PCM3168A_DAC_INV, 6, 7, 1, 0), |
136 | SOC_DOUBLE_STS("DAC1 Zero Flag", PCM3168A_DAC_ZERO, 0, 1, 1, 0), | ||
137 | SOC_DOUBLE_STS("DAC2 Zero Flag", PCM3168A_DAC_ZERO, 2, 3, 1, 0), | ||
138 | SOC_DOUBLE_STS("DAC3 Zero Flag", PCM3168A_DAC_ZERO, 4, 5, 1, 0), | ||
139 | SOC_DOUBLE_STS("DAC4 Zero Flag", PCM3168A_DAC_ZERO, 6, 7, 1, 0), | ||
140 | SOC_ENUM("DAC Volume Control Type", pcm3168a_dac_volume_type), | 136 | SOC_ENUM("DAC Volume Control Type", pcm3168a_dac_volume_type), |
141 | SOC_ENUM("DAC Volume Rate Multiplier", pcm3168a_dac_att_mult), | 137 | SOC_ENUM("DAC Volume Rate Multiplier", pcm3168a_dac_att_mult), |
142 | SOC_ENUM("DAC De-Emphasis", pcm3168a_dac_demp), | 138 | SOC_ENUM("DAC De-Emphasis", pcm3168a_dac_demp), |
@@ -176,9 +172,6 @@ static const struct snd_kcontrol_new pcm3168a_snd_controls[] = { | |||
176 | SOC_DOUBLE("ADC1 Mute Switch", PCM3168A_ADC_MUTE, 0, 1, 1, 0), | 172 | SOC_DOUBLE("ADC1 Mute Switch", PCM3168A_ADC_MUTE, 0, 1, 1, 0), |
177 | SOC_DOUBLE("ADC2 Mute Switch", PCM3168A_ADC_MUTE, 2, 3, 1, 0), | 173 | SOC_DOUBLE("ADC2 Mute Switch", PCM3168A_ADC_MUTE, 2, 3, 1, 0), |
178 | SOC_DOUBLE("ADC3 Mute Switch", PCM3168A_ADC_MUTE, 4, 5, 1, 0), | 174 | SOC_DOUBLE("ADC3 Mute Switch", PCM3168A_ADC_MUTE, 4, 5, 1, 0), |
179 | SOC_DOUBLE_STS("ADC1 Overflow Flag", PCM3168A_ADC_OV, 0, 1, 1, 0), | ||
180 | SOC_DOUBLE_STS("ADC2 Overflow Flag", PCM3168A_ADC_OV, 2, 3, 1, 0), | ||
181 | SOC_DOUBLE_STS("ADC3 Overflow Flag", PCM3168A_ADC_OV, 4, 5, 1, 0), | ||
182 | SOC_ENUM("ADC Volume Control Type", pcm3168a_adc_volume_type), | 175 | SOC_ENUM("ADC Volume Control Type", pcm3168a_adc_volume_type), |
183 | SOC_ENUM("ADC Volume Rate Multiplier", pcm3168a_adc_att_mult), | 176 | SOC_ENUM("ADC Volume Rate Multiplier", pcm3168a_adc_att_mult), |
184 | SOC_ENUM("ADC Overflow Flag Polarity", pcm3168a_adc_ov_pol), | 177 | SOC_ENUM("ADC Overflow Flag Polarity", pcm3168a_adc_ov_pol), |
@@ -504,6 +497,10 @@ static int pcm3168a_startup(struct snd_pcm_substream *substream, | |||
504 | unsigned int fmt; | 497 | unsigned int fmt; |
505 | unsigned int sample_min; | 498 | unsigned int sample_min; |
506 | unsigned int channel_max; | 499 | unsigned int channel_max; |
500 | unsigned int channel_maxs[] = { | ||
501 | 6, /* rx */ | ||
502 | 8 /* tx */ | ||
503 | }; | ||
507 | 504 | ||
508 | if (tx) | 505 | if (tx) |
509 | fmt = pcm3168a->dac_fmt; | 506 | fmt = pcm3168a->dac_fmt; |
@@ -528,18 +525,9 @@ static int pcm3168a_startup(struct snd_pcm_substream *substream, | |||
528 | channel_max = 2; | 525 | channel_max = 2; |
529 | break; | 526 | break; |
530 | case PCM3168A_FMT_LEFT_J: | 527 | case PCM3168A_FMT_LEFT_J: |
531 | sample_min = 24; | ||
532 | if (tx) | ||
533 | channel_max = 8; | ||
534 | else | ||
535 | channel_max = 6; | ||
536 | break; | ||
537 | case PCM3168A_FMT_I2S: | 528 | case PCM3168A_FMT_I2S: |
538 | sample_min = 24; | 529 | sample_min = 24; |
539 | if (tx) | 530 | channel_max = channel_maxs[tx]; |
540 | channel_max = 8; | ||
541 | else | ||
542 | channel_max = 6; | ||
543 | break; | 531 | break; |
544 | default: | 532 | default: |
545 | sample_min = 24; | 533 | sample_min = 24; |
diff --git a/sound/soc/codecs/pcm512x.c b/sound/soc/codecs/pcm512x.c index f0f2d4fd3769..6cb1653be804 100644 --- a/sound/soc/codecs/pcm512x.c +++ b/sound/soc/codecs/pcm512x.c | |||
@@ -53,6 +53,8 @@ struct pcm512x_priv { | |||
53 | unsigned long overclock_pll; | 53 | unsigned long overclock_pll; |
54 | unsigned long overclock_dac; | 54 | unsigned long overclock_dac; |
55 | unsigned long overclock_dsp; | 55 | unsigned long overclock_dsp; |
56 | int mute; | ||
57 | struct mutex mutex; | ||
56 | }; | 58 | }; |
57 | 59 | ||
58 | /* | 60 | /* |
@@ -384,6 +386,61 @@ static const struct soc_enum pcm512x_veds = | |||
384 | SOC_ENUM_SINGLE(PCM512x_DIGITAL_MUTE_2, PCM512x_VEDS_SHIFT, 4, | 386 | SOC_ENUM_SINGLE(PCM512x_DIGITAL_MUTE_2, PCM512x_VEDS_SHIFT, 4, |
385 | pcm512x_ramp_step_text); | 387 | pcm512x_ramp_step_text); |
386 | 388 | ||
389 | static int pcm512x_update_mute(struct pcm512x_priv *pcm512x) | ||
390 | { | ||
391 | return regmap_update_bits( | ||
392 | pcm512x->regmap, PCM512x_MUTE, PCM512x_RQML | PCM512x_RQMR, | ||
393 | (!!(pcm512x->mute & 0x5) << PCM512x_RQML_SHIFT) | ||
394 | | (!!(pcm512x->mute & 0x3) << PCM512x_RQMR_SHIFT)); | ||
395 | } | ||
396 | |||
397 | static int pcm512x_digital_playback_switch_get(struct snd_kcontrol *kcontrol, | ||
398 | struct snd_ctl_elem_value *ucontrol) | ||
399 | { | ||
400 | struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol); | ||
401 | struct pcm512x_priv *pcm512x = snd_soc_component_get_drvdata(component); | ||
402 | |||
403 | mutex_lock(&pcm512x->mutex); | ||
404 | ucontrol->value.integer.value[0] = !(pcm512x->mute & 0x4); | ||
405 | ucontrol->value.integer.value[1] = !(pcm512x->mute & 0x2); | ||
406 | mutex_unlock(&pcm512x->mutex); | ||
407 | |||
408 | return 0; | ||
409 | } | ||
410 | |||
411 | static int pcm512x_digital_playback_switch_put(struct snd_kcontrol *kcontrol, | ||
412 | struct snd_ctl_elem_value *ucontrol) | ||
413 | { | ||
414 | struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol); | ||
415 | struct pcm512x_priv *pcm512x = snd_soc_component_get_drvdata(component); | ||
416 | int ret, changed = 0; | ||
417 | |||
418 | mutex_lock(&pcm512x->mutex); | ||
419 | |||
420 | if ((pcm512x->mute & 0x4) == (ucontrol->value.integer.value[0] << 2)) { | ||
421 | pcm512x->mute ^= 0x4; | ||
422 | changed = 1; | ||
423 | } | ||
424 | if ((pcm512x->mute & 0x2) == (ucontrol->value.integer.value[1] << 1)) { | ||
425 | pcm512x->mute ^= 0x2; | ||
426 | changed = 1; | ||
427 | } | ||
428 | |||
429 | if (changed) { | ||
430 | ret = pcm512x_update_mute(pcm512x); | ||
431 | if (ret != 0) { | ||
432 | dev_err(component->dev, | ||
433 | "Failed to update digital mute: %d\n", ret); | ||
434 | mutex_unlock(&pcm512x->mutex); | ||
435 | return ret; | ||
436 | } | ||
437 | } | ||
438 | |||
439 | mutex_unlock(&pcm512x->mutex); | ||
440 | |||
441 | return changed; | ||
442 | } | ||
443 | |||
387 | static const struct snd_kcontrol_new pcm512x_controls[] = { | 444 | static const struct snd_kcontrol_new pcm512x_controls[] = { |
388 | SOC_DOUBLE_R_TLV("Digital Playback Volume", PCM512x_DIGITAL_VOLUME_2, | 445 | SOC_DOUBLE_R_TLV("Digital Playback Volume", PCM512x_DIGITAL_VOLUME_2, |
389 | PCM512x_DIGITAL_VOLUME_3, 0, 255, 1, digital_tlv), | 446 | PCM512x_DIGITAL_VOLUME_3, 0, 255, 1, digital_tlv), |
@@ -391,8 +448,15 @@ SOC_DOUBLE_TLV("Analogue Playback Volume", PCM512x_ANALOG_GAIN_CTRL, | |||
391 | PCM512x_LAGN_SHIFT, PCM512x_RAGN_SHIFT, 1, 1, analog_tlv), | 448 | PCM512x_LAGN_SHIFT, PCM512x_RAGN_SHIFT, 1, 1, analog_tlv), |
392 | SOC_DOUBLE_TLV("Analogue Playback Boost Volume", PCM512x_ANALOG_GAIN_BOOST, | 449 | SOC_DOUBLE_TLV("Analogue Playback Boost Volume", PCM512x_ANALOG_GAIN_BOOST, |
393 | PCM512x_AGBL_SHIFT, PCM512x_AGBR_SHIFT, 1, 0, boost_tlv), | 450 | PCM512x_AGBL_SHIFT, PCM512x_AGBR_SHIFT, 1, 0, boost_tlv), |
394 | SOC_DOUBLE("Digital Playback Switch", PCM512x_MUTE, PCM512x_RQML_SHIFT, | 451 | { |
395 | PCM512x_RQMR_SHIFT, 1, 1), | 452 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, |
453 | .name = "Digital Playback Switch", | ||
454 | .index = 0, | ||
455 | .access = SNDRV_CTL_ELEM_ACCESS_READWRITE, | ||
456 | .info = snd_ctl_boolean_stereo_info, | ||
457 | .get = pcm512x_digital_playback_switch_get, | ||
458 | .put = pcm512x_digital_playback_switch_put | ||
459 | }, | ||
396 | 460 | ||
397 | SOC_SINGLE("Deemphasis Switch", PCM512x_DSP, PCM512x_DEMP_SHIFT, 1, 1), | 461 | SOC_SINGLE("Deemphasis Switch", PCM512x_DSP, PCM512x_DEMP_SHIFT, 1, 1), |
398 | SOC_ENUM("DSP Program", pcm512x_dsp_program), | 462 | SOC_ENUM("DSP Program", pcm512x_dsp_program), |
@@ -1319,10 +1383,61 @@ static int pcm512x_set_fmt(struct snd_soc_dai *dai, unsigned int fmt) | |||
1319 | return 0; | 1383 | return 0; |
1320 | } | 1384 | } |
1321 | 1385 | ||
1386 | static int pcm512x_digital_mute(struct snd_soc_dai *dai, int mute) | ||
1387 | { | ||
1388 | struct snd_soc_component *component = dai->component; | ||
1389 | struct pcm512x_priv *pcm512x = snd_soc_component_get_drvdata(component); | ||
1390 | int ret; | ||
1391 | unsigned int mute_det; | ||
1392 | |||
1393 | mutex_lock(&pcm512x->mutex); | ||
1394 | |||
1395 | if (mute) { | ||
1396 | pcm512x->mute |= 0x1; | ||
1397 | ret = regmap_update_bits(pcm512x->regmap, PCM512x_MUTE, | ||
1398 | PCM512x_RQML | PCM512x_RQMR, | ||
1399 | PCM512x_RQML | PCM512x_RQMR); | ||
1400 | if (ret != 0) { | ||
1401 | dev_err(component->dev, | ||
1402 | "Failed to set digital mute: %d\n", ret); | ||
1403 | mutex_unlock(&pcm512x->mutex); | ||
1404 | return ret; | ||
1405 | } | ||
1406 | |||
1407 | regmap_read_poll_timeout(pcm512x->regmap, | ||
1408 | PCM512x_ANALOG_MUTE_DET, | ||
1409 | mute_det, (mute_det & 0x3) == 0, | ||
1410 | 200, 10000); | ||
1411 | |||
1412 | mutex_unlock(&pcm512x->mutex); | ||
1413 | } else { | ||
1414 | pcm512x->mute &= ~0x1; | ||
1415 | ret = pcm512x_update_mute(pcm512x); | ||
1416 | if (ret != 0) { | ||
1417 | dev_err(component->dev, | ||
1418 | "Failed to update digital mute: %d\n", ret); | ||
1419 | mutex_unlock(&pcm512x->mutex); | ||
1420 | return ret; | ||
1421 | } | ||
1422 | |||
1423 | regmap_read_poll_timeout(pcm512x->regmap, | ||
1424 | PCM512x_ANALOG_MUTE_DET, | ||
1425 | mute_det, | ||
1426 | (mute_det & 0x3) | ||
1427 | == ((~pcm512x->mute >> 1) & 0x3), | ||
1428 | 200, 10000); | ||
1429 | } | ||
1430 | |||
1431 | mutex_unlock(&pcm512x->mutex); | ||
1432 | |||
1433 | return 0; | ||
1434 | } | ||
1435 | |||
1322 | static const struct snd_soc_dai_ops pcm512x_dai_ops = { | 1436 | static const struct snd_soc_dai_ops pcm512x_dai_ops = { |
1323 | .startup = pcm512x_dai_startup, | 1437 | .startup = pcm512x_dai_startup, |
1324 | .hw_params = pcm512x_hw_params, | 1438 | .hw_params = pcm512x_hw_params, |
1325 | .set_fmt = pcm512x_set_fmt, | 1439 | .set_fmt = pcm512x_set_fmt, |
1440 | .digital_mute = pcm512x_digital_mute, | ||
1326 | }; | 1441 | }; |
1327 | 1442 | ||
1328 | static struct snd_soc_dai_driver pcm512x_dai = { | 1443 | static struct snd_soc_dai_driver pcm512x_dai = { |
@@ -1388,6 +1503,8 @@ int pcm512x_probe(struct device *dev, struct regmap *regmap) | |||
1388 | if (!pcm512x) | 1503 | if (!pcm512x) |
1389 | return -ENOMEM; | 1504 | return -ENOMEM; |
1390 | 1505 | ||
1506 | mutex_init(&pcm512x->mutex); | ||
1507 | |||
1391 | dev_set_drvdata(dev, pcm512x); | 1508 | dev_set_drvdata(dev, pcm512x); |
1392 | pcm512x->regmap = regmap; | 1509 | pcm512x->regmap = regmap; |
1393 | 1510 | ||
diff --git a/sound/soc/codecs/pcm512x.h b/sound/soc/codecs/pcm512x.h index d70d9c0c2088..9dda8693498e 100644 --- a/sound/soc/codecs/pcm512x.h +++ b/sound/soc/codecs/pcm512x.h | |||
@@ -112,7 +112,9 @@ | |||
112 | #define PCM512x_RQST_SHIFT 4 | 112 | #define PCM512x_RQST_SHIFT 4 |
113 | 113 | ||
114 | /* Page 0, Register 3 - mute */ | 114 | /* Page 0, Register 3 - mute */ |
115 | #define PCM512x_RQMR (1 << 0) | ||
115 | #define PCM512x_RQMR_SHIFT 0 | 116 | #define PCM512x_RQMR_SHIFT 0 |
117 | #define PCM512x_RQML (1 << 4) | ||
116 | #define PCM512x_RQML_SHIFT 4 | 118 | #define PCM512x_RQML_SHIFT 4 |
117 | 119 | ||
118 | /* Page 0, Register 4 - PLL */ | 120 | /* Page 0, Register 4 - PLL */ |
diff --git a/sound/soc/codecs/rt5663.c b/sound/soc/codecs/rt5663.c index 7eb2cbd39d6e..da6647015708 100644 --- a/sound/soc/codecs/rt5663.c +++ b/sound/soc/codecs/rt5663.c | |||
@@ -17,6 +17,7 @@ | |||
17 | #include <linux/platform_device.h> | 17 | #include <linux/platform_device.h> |
18 | #include <linux/spi/spi.h> | 18 | #include <linux/spi/spi.h> |
19 | #include <linux/acpi.h> | 19 | #include <linux/acpi.h> |
20 | #include <linux/regulator/consumer.h> | ||
20 | #include <linux/workqueue.h> | 21 | #include <linux/workqueue.h> |
21 | #include <sound/core.h> | 22 | #include <sound/core.h> |
22 | #include <sound/pcm.h> | 23 | #include <sound/pcm.h> |
@@ -33,6 +34,9 @@ | |||
33 | #define RT5663_DEVICE_ID_2 0x6451 | 34 | #define RT5663_DEVICE_ID_2 0x6451 |
34 | #define RT5663_DEVICE_ID_1 0x6406 | 35 | #define RT5663_DEVICE_ID_1 0x6406 |
35 | 36 | ||
37 | #define RT5663_POWER_ON_DELAY_MS 300 | ||
38 | #define RT5663_SUPPLY_CURRENT_UA 500000 | ||
39 | |||
36 | enum { | 40 | enum { |
37 | CODEC_VER_1, | 41 | CODEC_VER_1, |
38 | CODEC_VER_0, | 42 | CODEC_VER_0, |
@@ -48,6 +52,11 @@ struct impedance_mapping_table { | |||
48 | unsigned int dc_offset_r_manual_mic; | 52 | unsigned int dc_offset_r_manual_mic; |
49 | }; | 53 | }; |
50 | 54 | ||
55 | static const char *const rt5663_supply_names[] = { | ||
56 | "avdd", | ||
57 | "cpvdd", | ||
58 | }; | ||
59 | |||
51 | struct rt5663_priv { | 60 | struct rt5663_priv { |
52 | struct snd_soc_component *component; | 61 | struct snd_soc_component *component; |
53 | struct rt5663_platform_data pdata; | 62 | struct rt5663_platform_data pdata; |
@@ -56,6 +65,7 @@ struct rt5663_priv { | |||
56 | struct snd_soc_jack *hs_jack; | 65 | struct snd_soc_jack *hs_jack; |
57 | struct timer_list btn_check_timer; | 66 | struct timer_list btn_check_timer; |
58 | struct impedance_mapping_table *imp_table; | 67 | struct impedance_mapping_table *imp_table; |
68 | struct regulator_bulk_data supplies[ARRAY_SIZE(rt5663_supply_names)]; | ||
59 | 69 | ||
60 | int codec_ver; | 70 | int codec_ver; |
61 | int sysclk; | 71 | int sysclk; |
@@ -3483,7 +3493,7 @@ static int rt5663_i2c_probe(struct i2c_client *i2c, | |||
3483 | { | 3493 | { |
3484 | struct rt5663_platform_data *pdata = dev_get_platdata(&i2c->dev); | 3494 | struct rt5663_platform_data *pdata = dev_get_platdata(&i2c->dev); |
3485 | struct rt5663_priv *rt5663; | 3495 | struct rt5663_priv *rt5663; |
3486 | int ret; | 3496 | int ret, i; |
3487 | unsigned int val; | 3497 | unsigned int val; |
3488 | struct regmap *regmap; | 3498 | struct regmap *regmap; |
3489 | 3499 | ||
@@ -3500,12 +3510,44 @@ static int rt5663_i2c_probe(struct i2c_client *i2c, | |||
3500 | else | 3510 | else |
3501 | rt5663_parse_dp(rt5663, &i2c->dev); | 3511 | rt5663_parse_dp(rt5663, &i2c->dev); |
3502 | 3512 | ||
3513 | for (i = 0; i < ARRAY_SIZE(rt5663->supplies); i++) | ||
3514 | rt5663->supplies[i].supply = rt5663_supply_names[i]; | ||
3515 | |||
3516 | ret = devm_regulator_bulk_get(&i2c->dev, | ||
3517 | ARRAY_SIZE(rt5663->supplies), | ||
3518 | rt5663->supplies); | ||
3519 | if (ret) { | ||
3520 | dev_err(&i2c->dev, "Failed to request supplies: %d\n", ret); | ||
3521 | return ret; | ||
3522 | } | ||
3523 | |||
3524 | /* Set load for regulator. */ | ||
3525 | for (i = 0; i < ARRAY_SIZE(rt5663->supplies); i++) { | ||
3526 | ret = regulator_set_load(rt5663->supplies[i].consumer, | ||
3527 | RT5663_SUPPLY_CURRENT_UA); | ||
3528 | if (ret < 0) { | ||
3529 | dev_err(&i2c->dev, | ||
3530 | "Failed to set regulator load on %s, ret: %d\n", | ||
3531 | rt5663->supplies[i].supply, ret); | ||
3532 | return ret; | ||
3533 | } | ||
3534 | } | ||
3535 | |||
3536 | ret = regulator_bulk_enable(ARRAY_SIZE(rt5663->supplies), | ||
3537 | rt5663->supplies); | ||
3538 | |||
3539 | if (ret) { | ||
3540 | dev_err(&i2c->dev, "Failed to enable supplies: %d\n", ret); | ||
3541 | return ret; | ||
3542 | } | ||
3543 | msleep(RT5663_POWER_ON_DELAY_MS); | ||
3544 | |||
3503 | regmap = devm_regmap_init_i2c(i2c, &temp_regmap); | 3545 | regmap = devm_regmap_init_i2c(i2c, &temp_regmap); |
3504 | if (IS_ERR(regmap)) { | 3546 | if (IS_ERR(regmap)) { |
3505 | ret = PTR_ERR(regmap); | 3547 | ret = PTR_ERR(regmap); |
3506 | dev_err(&i2c->dev, "Failed to allocate temp register map: %d\n", | 3548 | dev_err(&i2c->dev, "Failed to allocate temp register map: %d\n", |
3507 | ret); | 3549 | ret); |
3508 | return ret; | 3550 | goto err_enable; |
3509 | } | 3551 | } |
3510 | 3552 | ||
3511 | ret = regmap_read(regmap, RT5663_VENDOR_ID_2, &val); | 3553 | ret = regmap_read(regmap, RT5663_VENDOR_ID_2, &val); |
@@ -3530,14 +3572,15 @@ static int rt5663_i2c_probe(struct i2c_client *i2c, | |||
3530 | dev_err(&i2c->dev, | 3572 | dev_err(&i2c->dev, |
3531 | "Device with ID register %#x is not rt5663\n", | 3573 | "Device with ID register %#x is not rt5663\n", |
3532 | val); | 3574 | val); |
3533 | return -ENODEV; | 3575 | ret = -ENODEV; |
3576 | goto err_enable; | ||
3534 | } | 3577 | } |
3535 | 3578 | ||
3536 | if (IS_ERR(rt5663->regmap)) { | 3579 | if (IS_ERR(rt5663->regmap)) { |
3537 | ret = PTR_ERR(rt5663->regmap); | 3580 | ret = PTR_ERR(rt5663->regmap); |
3538 | dev_err(&i2c->dev, "Failed to allocate register map: %d\n", | 3581 | dev_err(&i2c->dev, "Failed to allocate register map: %d\n", |
3539 | ret); | 3582 | ret); |
3540 | return ret; | 3583 | goto err_enable; |
3541 | } | 3584 | } |
3542 | 3585 | ||
3543 | /* reset and calibrate */ | 3586 | /* reset and calibrate */ |
@@ -3635,20 +3678,32 @@ static int rt5663_i2c_probe(struct i2c_client *i2c, | |||
3635 | ret = request_irq(i2c->irq, rt5663_irq, | 3678 | ret = request_irq(i2c->irq, rt5663_irq, |
3636 | IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING | 3679 | IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING |
3637 | | IRQF_ONESHOT, "rt5663", rt5663); | 3680 | | IRQF_ONESHOT, "rt5663", rt5663); |
3638 | if (ret) | 3681 | if (ret) { |
3639 | dev_err(&i2c->dev, "%s Failed to reguest IRQ: %d\n", | 3682 | dev_err(&i2c->dev, "%s Failed to reguest IRQ: %d\n", |
3640 | __func__, ret); | 3683 | __func__, ret); |
3684 | goto err_enable; | ||
3685 | } | ||
3641 | } | 3686 | } |
3642 | 3687 | ||
3643 | ret = devm_snd_soc_register_component(&i2c->dev, | 3688 | ret = devm_snd_soc_register_component(&i2c->dev, |
3644 | &soc_component_dev_rt5663, | 3689 | &soc_component_dev_rt5663, |
3645 | rt5663_dai, ARRAY_SIZE(rt5663_dai)); | 3690 | rt5663_dai, ARRAY_SIZE(rt5663_dai)); |
3646 | 3691 | ||
3647 | if (ret) { | 3692 | if (ret) |
3648 | if (i2c->irq) | 3693 | goto err_enable; |
3649 | free_irq(i2c->irq, rt5663); | ||
3650 | } | ||
3651 | 3694 | ||
3695 | return 0; | ||
3696 | |||
3697 | |||
3698 | /* | ||
3699 | * Error after enabling regulators should goto err_enable | ||
3700 | * to disable regulators. | ||
3701 | */ | ||
3702 | err_enable: | ||
3703 | if (i2c->irq) | ||
3704 | free_irq(i2c->irq, rt5663); | ||
3705 | |||
3706 | regulator_bulk_disable(ARRAY_SIZE(rt5663->supplies), rt5663->supplies); | ||
3652 | return ret; | 3707 | return ret; |
3653 | } | 3708 | } |
3654 | 3709 | ||
@@ -3659,6 +3714,8 @@ static int rt5663_i2c_remove(struct i2c_client *i2c) | |||
3659 | if (i2c->irq) | 3714 | if (i2c->irq) |
3660 | free_irq(i2c->irq, rt5663); | 3715 | free_irq(i2c->irq, rt5663); |
3661 | 3716 | ||
3717 | regulator_bulk_disable(ARRAY_SIZE(rt5663->supplies), rt5663->supplies); | ||
3718 | |||
3662 | return 0; | 3719 | return 0; |
3663 | } | 3720 | } |
3664 | 3721 | ||
diff --git a/sound/soc/codecs/simple-amplifier.c b/sound/soc/codecs/simple-amplifier.c index 85524acf3e9c..c07e8a80b4b7 100644 --- a/sound/soc/codecs/simple-amplifier.c +++ b/sound/soc/codecs/simple-amplifier.c | |||
@@ -19,6 +19,7 @@ | |||
19 | 19 | ||
20 | #include <linux/gpio/consumer.h> | 20 | #include <linux/gpio/consumer.h> |
21 | #include <linux/module.h> | 21 | #include <linux/module.h> |
22 | #include <linux/regulator/consumer.h> | ||
22 | #include <sound/soc.h> | 23 | #include <sound/soc.h> |
23 | 24 | ||
24 | #define DRV_NAME "simple-amplifier" | 25 | #define DRV_NAME "simple-amplifier" |
@@ -58,11 +59,14 @@ static const struct snd_soc_dapm_widget simple_amp_dapm_widgets[] = { | |||
58 | (SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD)), | 59 | (SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD)), |
59 | SND_SOC_DAPM_OUTPUT("OUTL"), | 60 | SND_SOC_DAPM_OUTPUT("OUTL"), |
60 | SND_SOC_DAPM_OUTPUT("OUTR"), | 61 | SND_SOC_DAPM_OUTPUT("OUTR"), |
62 | SND_SOC_DAPM_REGULATOR_SUPPLY("VCC", 20, 0), | ||
61 | }; | 63 | }; |
62 | 64 | ||
63 | static const struct snd_soc_dapm_route simple_amp_dapm_routes[] = { | 65 | static const struct snd_soc_dapm_route simple_amp_dapm_routes[] = { |
64 | { "DRV", NULL, "INL" }, | 66 | { "DRV", NULL, "INL" }, |
65 | { "DRV", NULL, "INR" }, | 67 | { "DRV", NULL, "INR" }, |
68 | { "OUTL", NULL, "VCC" }, | ||
69 | { "OUTR", NULL, "VCC" }, | ||
66 | { "OUTL", NULL, "DRV" }, | 70 | { "OUTL", NULL, "DRV" }, |
67 | { "OUTR", NULL, "DRV" }, | 71 | { "OUTR", NULL, "DRV" }, |
68 | }; | 72 | }; |
diff --git a/sound/soc/codecs/tas6424.c b/sound/soc/codecs/tas6424.c index 36aebdb8f55c..aaba39295079 100644 --- a/sound/soc/codecs/tas6424.c +++ b/sound/soc/codecs/tas6424.c | |||
@@ -378,7 +378,7 @@ static struct snd_soc_component_driver soc_codec_dev_tas6424 = { | |||
378 | .non_legacy_dai_naming = 1, | 378 | .non_legacy_dai_naming = 1, |
379 | }; | 379 | }; |
380 | 380 | ||
381 | static struct snd_soc_dai_ops tas6424_speaker_dai_ops = { | 381 | static const struct snd_soc_dai_ops tas6424_speaker_dai_ops = { |
382 | .hw_params = tas6424_hw_params, | 382 | .hw_params = tas6424_hw_params, |
383 | .set_fmt = tas6424_set_dai_fmt, | 383 | .set_fmt = tas6424_set_dai_fmt, |
384 | .set_tdm_slot = tas6424_set_dai_tdm_slot, | 384 | .set_tdm_slot = tas6424_set_dai_tdm_slot, |
diff --git a/sound/soc/codecs/tlv320aic31xx.c b/sound/soc/codecs/tlv320aic31xx.c index 608ad49ad978..c6048d95c6d3 100644 --- a/sound/soc/codecs/tlv320aic31xx.c +++ b/sound/soc/codecs/tlv320aic31xx.c | |||
@@ -1095,7 +1095,7 @@ static int aic31xx_set_dai_sysclk(struct snd_soc_dai *codec_dai, | |||
1095 | if (freq/i > 20000000) { | 1095 | if (freq/i > 20000000) { |
1096 | dev_err(aic31xx->dev, "%s: Too high mclk frequency %u\n", | 1096 | dev_err(aic31xx->dev, "%s: Too high mclk frequency %u\n", |
1097 | __func__, freq); | 1097 | __func__, freq); |
1098 | return -EINVAL; | 1098 | return -EINVAL; |
1099 | } | 1099 | } |
1100 | aic31xx->p_div = i; | 1100 | aic31xx->p_div = i; |
1101 | 1101 | ||
diff --git a/sound/soc/codecs/tlv320aic3x.c b/sound/soc/codecs/tlv320aic3x.c index 6a271e6e6b8f..6aa0edf8c5ef 100644 --- a/sound/soc/codecs/tlv320aic3x.c +++ b/sound/soc/codecs/tlv320aic3x.c | |||
@@ -1260,6 +1260,16 @@ static int aic3x_set_dai_fmt(struct snd_soc_dai *codec_dai, | |||
1260 | aic3x->master = 0; | 1260 | aic3x->master = 0; |
1261 | iface_areg &= ~(BIT_CLK_MASTER | WORD_CLK_MASTER); | 1261 | iface_areg &= ~(BIT_CLK_MASTER | WORD_CLK_MASTER); |
1262 | break; | 1262 | break; |
1263 | case SND_SOC_DAIFMT_CBM_CFS: | ||
1264 | aic3x->master = 1; | ||
1265 | iface_areg |= BIT_CLK_MASTER; | ||
1266 | iface_areg &= ~WORD_CLK_MASTER; | ||
1267 | break; | ||
1268 | case SND_SOC_DAIFMT_CBS_CFM: | ||
1269 | aic3x->master = 1; | ||
1270 | iface_areg |= WORD_CLK_MASTER; | ||
1271 | iface_areg &= ~BIT_CLK_MASTER; | ||
1272 | break; | ||
1263 | default: | 1273 | default: |
1264 | return -EINVAL; | 1274 | return -EINVAL; |
1265 | } | 1275 | } |
diff --git a/sound/soc/codecs/tlv320dac33.c b/sound/soc/codecs/tlv320dac33.c index a957eaeb7bc1..32907b1e20cf 100644 --- a/sound/soc/codecs/tlv320dac33.c +++ b/sound/soc/codecs/tlv320dac33.c | |||
@@ -394,7 +394,7 @@ static int dac33_hard_power(struct snd_soc_component *component, int power) | |||
394 | if (ret != 0) { | 394 | if (ret != 0) { |
395 | dev_err(component->dev, | 395 | dev_err(component->dev, |
396 | "Failed to enable supplies: %d\n", ret); | 396 | "Failed to enable supplies: %d\n", ret); |
397 | goto exit; | 397 | goto exit; |
398 | } | 398 | } |
399 | 399 | ||
400 | if (dac33->power_gpio >= 0) | 400 | if (dac33->power_gpio >= 0) |
diff --git a/sound/soc/codecs/wm8998.c b/sound/soc/codecs/wm8998.c index 61294c787f27..409bed30a4e4 100644 --- a/sound/soc/codecs/wm8998.c +++ b/sound/soc/codecs/wm8998.c | |||
@@ -60,7 +60,7 @@ static int wm8998_asrc_ev(struct snd_soc_dapm_widget *w, | |||
60 | dev_warn(component->dev, | 60 | dev_warn(component->dev, |
61 | "Unsupported ASRC rate1 (%s)\n", | 61 | "Unsupported ASRC rate1 (%s)\n", |
62 | arizona_sample_rate_val_to_name(val)); | 62 | arizona_sample_rate_val_to_name(val)); |
63 | return -EINVAL; | 63 | return -EINVAL; |
64 | } | 64 | } |
65 | break; | 65 | break; |
66 | default: | 66 | default: |
diff --git a/sound/soc/codecs/wm9705.c b/sound/soc/codecs/wm9705.c index ccdf088461b7..54c306707c02 100644 --- a/sound/soc/codecs/wm9705.c +++ b/sound/soc/codecs/wm9705.c | |||
@@ -325,8 +325,7 @@ static int wm9705_soc_probe(struct snd_soc_component *component) | |||
325 | if (wm9705->mfd_pdata) { | 325 | if (wm9705->mfd_pdata) { |
326 | wm9705->ac97 = wm9705->mfd_pdata->ac97; | 326 | wm9705->ac97 = wm9705->mfd_pdata->ac97; |
327 | regmap = wm9705->mfd_pdata->regmap; | 327 | regmap = wm9705->mfd_pdata->regmap; |
328 | } else { | 328 | } else if (IS_ENABLED(CONFIG_SND_SOC_AC97_BUS)) { |
329 | #ifdef CONFIG_SND_SOC_AC97_BUS | ||
330 | wm9705->ac97 = snd_soc_new_ac97_component(component, WM9705_VENDOR_ID, | 329 | wm9705->ac97 = snd_soc_new_ac97_component(component, WM9705_VENDOR_ID, |
331 | WM9705_VENDOR_ID_MASK); | 330 | WM9705_VENDOR_ID_MASK); |
332 | if (IS_ERR(wm9705->ac97)) { | 331 | if (IS_ERR(wm9705->ac97)) { |
@@ -339,7 +338,8 @@ static int wm9705_soc_probe(struct snd_soc_component *component) | |||
339 | snd_soc_free_ac97_component(wm9705->ac97); | 338 | snd_soc_free_ac97_component(wm9705->ac97); |
340 | return PTR_ERR(regmap); | 339 | return PTR_ERR(regmap); |
341 | } | 340 | } |
342 | #endif | 341 | } else { |
342 | return -ENXIO; | ||
343 | } | 343 | } |
344 | 344 | ||
345 | snd_soc_component_set_drvdata(component, wm9705->ac97); | 345 | snd_soc_component_set_drvdata(component, wm9705->ac97); |
@@ -350,14 +350,12 @@ static int wm9705_soc_probe(struct snd_soc_component *component) | |||
350 | 350 | ||
351 | static void wm9705_soc_remove(struct snd_soc_component *component) | 351 | static void wm9705_soc_remove(struct snd_soc_component *component) |
352 | { | 352 | { |
353 | #ifdef CONFIG_SND_SOC_AC97_BUS | ||
354 | struct wm9705_priv *wm9705 = snd_soc_component_get_drvdata(component); | 353 | struct wm9705_priv *wm9705 = snd_soc_component_get_drvdata(component); |
355 | 354 | ||
356 | if (!wm9705->mfd_pdata) { | 355 | if (IS_ENABLED(CONFIG_SND_SOC_AC97_BUS) && !wm9705->mfd_pdata) { |
357 | snd_soc_component_exit_regmap(component); | 356 | snd_soc_component_exit_regmap(component); |
358 | snd_soc_free_ac97_component(wm9705->ac97); | 357 | snd_soc_free_ac97_component(wm9705->ac97); |
359 | } | 358 | } |
360 | #endif | ||
361 | } | 359 | } |
362 | 360 | ||
363 | static const struct snd_soc_component_driver soc_component_dev_wm9705 = { | 361 | static const struct snd_soc_component_driver soc_component_dev_wm9705 = { |
diff --git a/sound/soc/codecs/wm9712.c b/sound/soc/codecs/wm9712.c index e873baa9e778..01949eaba4fd 100644 --- a/sound/soc/codecs/wm9712.c +++ b/sound/soc/codecs/wm9712.c | |||
@@ -642,8 +642,7 @@ static int wm9712_soc_probe(struct snd_soc_component *component) | |||
642 | if (wm9712->mfd_pdata) { | 642 | if (wm9712->mfd_pdata) { |
643 | wm9712->ac97 = wm9712->mfd_pdata->ac97; | 643 | wm9712->ac97 = wm9712->mfd_pdata->ac97; |
644 | regmap = wm9712->mfd_pdata->regmap; | 644 | regmap = wm9712->mfd_pdata->regmap; |
645 | } else { | 645 | } else if (IS_ENABLED(CONFIG_SND_SOC_AC97_BUS)) { |
646 | #ifdef CONFIG_SND_SOC_AC97_BUS | ||
647 | int ret; | 646 | int ret; |
648 | 647 | ||
649 | wm9712->ac97 = snd_soc_new_ac97_component(component, WM9712_VENDOR_ID, | 648 | wm9712->ac97 = snd_soc_new_ac97_component(component, WM9712_VENDOR_ID, |
@@ -660,7 +659,8 @@ static int wm9712_soc_probe(struct snd_soc_component *component) | |||
660 | snd_soc_free_ac97_component(wm9712->ac97); | 659 | snd_soc_free_ac97_component(wm9712->ac97); |
661 | return PTR_ERR(regmap); | 660 | return PTR_ERR(regmap); |
662 | } | 661 | } |
663 | #endif | 662 | } else { |
663 | return -ENXIO; | ||
664 | } | 664 | } |
665 | 665 | ||
666 | snd_soc_component_init_regmap(component, regmap); | 666 | snd_soc_component_init_regmap(component, regmap); |
@@ -673,14 +673,12 @@ static int wm9712_soc_probe(struct snd_soc_component *component) | |||
673 | 673 | ||
674 | static void wm9712_soc_remove(struct snd_soc_component *component) | 674 | static void wm9712_soc_remove(struct snd_soc_component *component) |
675 | { | 675 | { |
676 | #ifdef CONFIG_SND_SOC_AC97_BUS | ||
677 | struct wm9712_priv *wm9712 = snd_soc_component_get_drvdata(component); | 676 | struct wm9712_priv *wm9712 = snd_soc_component_get_drvdata(component); |
678 | 677 | ||
679 | if (!wm9712->mfd_pdata) { | 678 | if (IS_ENABLED(CONFIG_SND_SOC_AC97_BUS) && !wm9712->mfd_pdata) { |
680 | snd_soc_component_exit_regmap(component); | 679 | snd_soc_component_exit_regmap(component); |
681 | snd_soc_free_ac97_component(wm9712->ac97); | 680 | snd_soc_free_ac97_component(wm9712->ac97); |
682 | } | 681 | } |
683 | #endif | ||
684 | } | 682 | } |
685 | 683 | ||
686 | static const struct snd_soc_component_driver soc_component_dev_wm9712 = { | 684 | static const struct snd_soc_component_driver soc_component_dev_wm9712 = { |
diff --git a/sound/soc/codecs/wm9713.c b/sound/soc/codecs/wm9713.c index 643863bb32e0..5a2fdf4f69bf 100644 --- a/sound/soc/codecs/wm9713.c +++ b/sound/soc/codecs/wm9713.c | |||
@@ -1214,8 +1214,7 @@ static int wm9713_soc_probe(struct snd_soc_component *component) | |||
1214 | if (wm9713->mfd_pdata) { | 1214 | if (wm9713->mfd_pdata) { |
1215 | wm9713->ac97 = wm9713->mfd_pdata->ac97; | 1215 | wm9713->ac97 = wm9713->mfd_pdata->ac97; |
1216 | regmap = wm9713->mfd_pdata->regmap; | 1216 | regmap = wm9713->mfd_pdata->regmap; |
1217 | } else { | 1217 | } else if (IS_ENABLED(CONFIG_SND_SOC_AC97_BUS)) { |
1218 | #ifdef CONFIG_SND_SOC_AC97_BUS | ||
1219 | wm9713->ac97 = snd_soc_new_ac97_component(component, WM9713_VENDOR_ID, | 1218 | wm9713->ac97 = snd_soc_new_ac97_component(component, WM9713_VENDOR_ID, |
1220 | WM9713_VENDOR_ID_MASK); | 1219 | WM9713_VENDOR_ID_MASK); |
1221 | if (IS_ERR(wm9713->ac97)) | 1220 | if (IS_ERR(wm9713->ac97)) |
@@ -1225,7 +1224,8 @@ static int wm9713_soc_probe(struct snd_soc_component *component) | |||
1225 | snd_soc_free_ac97_component(wm9713->ac97); | 1224 | snd_soc_free_ac97_component(wm9713->ac97); |
1226 | return PTR_ERR(regmap); | 1225 | return PTR_ERR(regmap); |
1227 | } | 1226 | } |
1228 | #endif | 1227 | } else { |
1228 | return -ENXIO; | ||
1229 | } | 1229 | } |
1230 | 1230 | ||
1231 | snd_soc_component_init_regmap(component, regmap); | 1231 | snd_soc_component_init_regmap(component, regmap); |
@@ -1238,14 +1238,12 @@ static int wm9713_soc_probe(struct snd_soc_component *component) | |||
1238 | 1238 | ||
1239 | static void wm9713_soc_remove(struct snd_soc_component *component) | 1239 | static void wm9713_soc_remove(struct snd_soc_component *component) |
1240 | { | 1240 | { |
1241 | #ifdef CONFIG_SND_SOC_AC97_BUS | ||
1242 | struct wm9713_priv *wm9713 = snd_soc_component_get_drvdata(component); | 1241 | struct wm9713_priv *wm9713 = snd_soc_component_get_drvdata(component); |
1243 | 1242 | ||
1244 | if (!wm9713->mfd_pdata) { | 1243 | if (IS_ENABLED(CONFIG_SND_SOC_AC97_BUS) && !wm9713->mfd_pdata) { |
1245 | snd_soc_component_exit_regmap(component); | 1244 | snd_soc_component_exit_regmap(component); |
1246 | snd_soc_free_ac97_component(wm9713->ac97); | 1245 | snd_soc_free_ac97_component(wm9713->ac97); |
1247 | } | 1246 | } |
1248 | #endif | ||
1249 | } | 1247 | } |
1250 | 1248 | ||
1251 | static const struct snd_soc_component_driver soc_component_dev_wm9713 = { | 1249 | static const struct snd_soc_component_driver soc_component_dev_wm9713 = { |
diff --git a/sound/soc/codecs/wm_adsp.c b/sound/soc/codecs/wm_adsp.c index 66501b8dc46f..1dd291cebe67 100644 --- a/sound/soc/codecs/wm_adsp.c +++ b/sound/soc/codecs/wm_adsp.c | |||
@@ -2419,7 +2419,7 @@ static int wm_adsp_create_name(struct wm_adsp *dsp) | |||
2419 | return 0; | 2419 | return 0; |
2420 | } | 2420 | } |
2421 | 2421 | ||
2422 | int wm_adsp1_init(struct wm_adsp *dsp) | 2422 | static int wm_adsp_common_init(struct wm_adsp *dsp) |
2423 | { | 2423 | { |
2424 | int ret; | 2424 | int ret; |
2425 | 2425 | ||
@@ -2428,11 +2428,17 @@ int wm_adsp1_init(struct wm_adsp *dsp) | |||
2428 | return ret; | 2428 | return ret; |
2429 | 2429 | ||
2430 | INIT_LIST_HEAD(&dsp->alg_regions); | 2430 | INIT_LIST_HEAD(&dsp->alg_regions); |
2431 | INIT_LIST_HEAD(&dsp->ctl_list); | ||
2431 | 2432 | ||
2432 | mutex_init(&dsp->pwr_lock); | 2433 | mutex_init(&dsp->pwr_lock); |
2433 | 2434 | ||
2434 | return 0; | 2435 | return 0; |
2435 | } | 2436 | } |
2437 | |||
2438 | int wm_adsp1_init(struct wm_adsp *dsp) | ||
2439 | { | ||
2440 | return wm_adsp_common_init(dsp); | ||
2441 | } | ||
2436 | EXPORT_SYMBOL_GPL(wm_adsp1_init); | 2442 | EXPORT_SYMBOL_GPL(wm_adsp1_init); |
2437 | 2443 | ||
2438 | int wm_adsp1_event(struct snd_soc_dapm_widget *w, | 2444 | int wm_adsp1_event(struct snd_soc_dapm_widget *w, |
@@ -2917,7 +2923,7 @@ int wm_adsp2_init(struct wm_adsp *dsp) | |||
2917 | { | 2923 | { |
2918 | int ret; | 2924 | int ret; |
2919 | 2925 | ||
2920 | ret = wm_adsp_create_name(dsp); | 2926 | ret = wm_adsp_common_init(dsp); |
2921 | if (ret) | 2927 | if (ret) |
2922 | return ret; | 2928 | return ret; |
2923 | 2929 | ||
@@ -2939,12 +2945,8 @@ int wm_adsp2_init(struct wm_adsp *dsp) | |||
2939 | break; | 2945 | break; |
2940 | } | 2946 | } |
2941 | 2947 | ||
2942 | INIT_LIST_HEAD(&dsp->alg_regions); | ||
2943 | INIT_LIST_HEAD(&dsp->ctl_list); | ||
2944 | INIT_WORK(&dsp->boot_work, wm_adsp2_boot_work); | 2948 | INIT_WORK(&dsp->boot_work, wm_adsp2_boot_work); |
2945 | 2949 | ||
2946 | mutex_init(&dsp->pwr_lock); | ||
2947 | |||
2948 | return 0; | 2950 | return 0; |
2949 | } | 2951 | } |
2950 | EXPORT_SYMBOL_GPL(wm_adsp2_init); | 2952 | EXPORT_SYMBOL_GPL(wm_adsp2_init); |
diff --git a/sound/soc/davinci/Kconfig b/sound/soc/davinci/Kconfig deleted file mode 100644 index 778faff28e0e..000000000000 --- a/sound/soc/davinci/Kconfig +++ /dev/null | |||
@@ -1,106 +0,0 @@ | |||
1 | config SND_DAVINCI_SOC | ||
2 | tristate | ||
3 | depends on ARCH_DAVINCI | ||
4 | select SND_EDMA_SOC | ||
5 | |||
6 | config SND_EDMA_SOC | ||
7 | tristate "SoC Audio for Texas Instruments chips using eDMA" | ||
8 | depends on TI_EDMA | ||
9 | select SND_SOC_GENERIC_DMAENGINE_PCM | ||
10 | help | ||
11 | Say Y or M here if you want audio support for TI SoC which uses eDMA. | ||
12 | The following line of SoCs are supported by this platform driver: | ||
13 | - daVinci devices | ||
14 | - AM335x | ||
15 | - AM437x/AM438x | ||
16 | - DRA7xx family | ||
17 | |||
18 | config SND_DAVINCI_SOC_I2S | ||
19 | tristate "DaVinci Multichannel Buffered Serial Port (McBSP) support" | ||
20 | depends on SND_EDMA_SOC | ||
21 | help | ||
22 | Say Y or M here if you want to have support for McBSP IP found in | ||
23 | Texas Instruments DaVinci DA850 SoCs. | ||
24 | |||
25 | config SND_DAVINCI_SOC_MCASP | ||
26 | tristate "Multichannel Audio Serial Port (McASP) support" | ||
27 | depends on SND_SDMA_SOC || SND_EDMA_SOC | ||
28 | help | ||
29 | Say Y or M here if you want to have support for McASP IP found in | ||
30 | various Texas Instruments SoCs like: | ||
31 | - daVinci devices | ||
32 | - Sitara line of SoCs (AM335x, AM438x, etc) | ||
33 | - DRA7x devices | ||
34 | |||
35 | config SND_DAVINCI_SOC_VCIF | ||
36 | tristate | ||
37 | |||
38 | config SND_DAVINCI_SOC_GENERIC_EVM | ||
39 | tristate | ||
40 | select SND_SOC_TLV320AIC3X | ||
41 | select SND_DAVINCI_SOC_MCASP | ||
42 | |||
43 | config SND_AM33XX_SOC_EVM | ||
44 | tristate "SoC Audio for the AM33XX chip based boards" | ||
45 | depends on SND_EDMA_SOC && SOC_AM33XX && I2C | ||
46 | select SND_DAVINCI_SOC_GENERIC_EVM | ||
47 | help | ||
48 | Say Y or M if you want to add support for SoC audio on AM33XX | ||
49 | boards using McASP and TLV320AIC3X codec. For example AM335X-EVM, | ||
50 | AM335X-EVMSK, and BeagelBone with AudioCape boards have this | ||
51 | setup. | ||
52 | |||
53 | config SND_DAVINCI_SOC_EVM | ||
54 | tristate "SoC Audio support for DaVinci DM6446, DM355 or DM365 EVM" | ||
55 | depends on SND_EDMA_SOC && I2C | ||
56 | depends on MACH_DAVINCI_EVM || MACH_DAVINCI_DM355_EVM || MACH_DAVINCI_DM365_EVM | ||
57 | select SND_DAVINCI_SOC_GENERIC_EVM | ||
58 | help | ||
59 | Say Y if you want to add support for SoC audio on TI | ||
60 | DaVinci DM6446, DM355 or DM365 EVM platforms. | ||
61 | |||
62 | choice | ||
63 | prompt "DM365 codec select" | ||
64 | depends on SND_DAVINCI_SOC_EVM | ||
65 | depends on MACH_DAVINCI_DM365_EVM | ||
66 | |||
67 | config SND_DM365_AIC3X_CODEC | ||
68 | tristate "Audio Codec - AIC3101" | ||
69 | help | ||
70 | Say Y if you want to add support for AIC3101 audio codec | ||
71 | |||
72 | config SND_DM365_VOICE_CODEC | ||
73 | tristate "Voice Codec - CQ93VC" | ||
74 | select MFD_DAVINCI_VOICECODEC | ||
75 | select SND_DAVINCI_SOC_VCIF | ||
76 | select SND_SOC_CQ0093VC | ||
77 | help | ||
78 | Say Y if you want to add support for SoC On-chip voice codec | ||
79 | endchoice | ||
80 | |||
81 | config SND_DM6467_SOC_EVM | ||
82 | tristate "SoC Audio support for DaVinci DM6467 EVM" | ||
83 | depends on SND_EDMA_SOC && MACH_DAVINCI_DM6467_EVM && I2C | ||
84 | select SND_DAVINCI_SOC_GENERIC_EVM | ||
85 | select SND_SOC_SPDIF | ||
86 | |||
87 | help | ||
88 | Say Y if you want to add support for SoC audio on TI | ||
89 | |||
90 | config SND_DA830_SOC_EVM | ||
91 | tristate "SoC Audio support for DA830/OMAP-L137 EVM" | ||
92 | depends on SND_EDMA_SOC && MACH_DAVINCI_DA830_EVM && I2C | ||
93 | select SND_DAVINCI_SOC_GENERIC_EVM | ||
94 | |||
95 | help | ||
96 | Say Y if you want to add support for SoC audio on TI | ||
97 | DA830/OMAP-L137 EVM | ||
98 | |||
99 | config SND_DA850_SOC_EVM | ||
100 | tristate "SoC Audio support for DA850/OMAP-L138 EVM" | ||
101 | depends on SND_EDMA_SOC && MACH_DAVINCI_DA850_EVM && I2C | ||
102 | select SND_DAVINCI_SOC_GENERIC_EVM | ||
103 | help | ||
104 | Say Y if you want to add support for SoC audio on TI | ||
105 | DA850/OMAP-L138 EVM | ||
106 | |||
diff --git a/sound/soc/davinci/Makefile b/sound/soc/davinci/Makefile deleted file mode 100644 index 23c6592eb31a..000000000000 --- a/sound/soc/davinci/Makefile +++ /dev/null | |||
@@ -1,16 +0,0 @@ | |||
1 | # SPDX-License-Identifier: GPL-2.0 | ||
2 | # DAVINCI Platform Support | ||
3 | snd-soc-edma-objs := edma-pcm.o | ||
4 | snd-soc-davinci-i2s-objs := davinci-i2s.o | ||
5 | snd-soc-davinci-mcasp-objs:= davinci-mcasp.o | ||
6 | snd-soc-davinci-vcif-objs:= davinci-vcif.o | ||
7 | |||
8 | obj-$(CONFIG_SND_EDMA_SOC) += snd-soc-edma.o | ||
9 | obj-$(CONFIG_SND_DAVINCI_SOC_I2S) += snd-soc-davinci-i2s.o | ||
10 | obj-$(CONFIG_SND_DAVINCI_SOC_MCASP) += snd-soc-davinci-mcasp.o | ||
11 | obj-$(CONFIG_SND_DAVINCI_SOC_VCIF) += snd-soc-davinci-vcif.o | ||
12 | |||
13 | # Generic DAVINCI/AM33xx Machine Support | ||
14 | snd-soc-evm-objs := davinci-evm.o | ||
15 | |||
16 | obj-$(CONFIG_SND_DAVINCI_SOC_GENERIC_EVM) += snd-soc-evm.o | ||
diff --git a/sound/soc/fsl/Kconfig b/sound/soc/fsl/Kconfig index 6ec19fb4a934..2e75b5bc5f1d 100644 --- a/sound/soc/fsl/Kconfig +++ b/sound/soc/fsl/Kconfig | |||
@@ -221,7 +221,7 @@ config SND_SOC_PHYCORE_AC97 | |||
221 | 221 | ||
222 | config SND_SOC_EUKREA_TLV320 | 222 | config SND_SOC_EUKREA_TLV320 |
223 | tristate "Eukrea TLV320" | 223 | tristate "Eukrea TLV320" |
224 | depends on ARCH_MXC && I2C | 224 | depends on ARCH_MXC && !ARM64 && I2C |
225 | select SND_SOC_TLV320AIC23_I2C | 225 | select SND_SOC_TLV320AIC23_I2C |
226 | select SND_SOC_IMX_AUDMUX | 226 | select SND_SOC_IMX_AUDMUX |
227 | select SND_SOC_IMX_SSI | 227 | select SND_SOC_IMX_SSI |
diff --git a/sound/soc/fsl/fsl-asoc-card.c b/sound/soc/fsl/fsl-asoc-card.c index 44433b20435c..81f2fe2c6d23 100644 --- a/sound/soc/fsl/fsl-asoc-card.c +++ b/sound/soc/fsl/fsl-asoc-card.c | |||
@@ -571,17 +571,17 @@ static int fsl_asoc_card_probe(struct platform_device *pdev) | |||
571 | } | 571 | } |
572 | 572 | ||
573 | /* Common settings for corresponding Freescale CPU DAI driver */ | 573 | /* Common settings for corresponding Freescale CPU DAI driver */ |
574 | if (strstr(cpu_np->name, "ssi")) { | 574 | if (of_node_name_eq(cpu_np, "ssi")) { |
575 | /* Only SSI needs to configure AUDMUX */ | 575 | /* Only SSI needs to configure AUDMUX */ |
576 | ret = fsl_asoc_card_audmux_init(np, priv); | 576 | ret = fsl_asoc_card_audmux_init(np, priv); |
577 | if (ret) { | 577 | if (ret) { |
578 | dev_err(&pdev->dev, "failed to init audmux\n"); | 578 | dev_err(&pdev->dev, "failed to init audmux\n"); |
579 | goto asrc_fail; | 579 | goto asrc_fail; |
580 | } | 580 | } |
581 | } else if (strstr(cpu_np->name, "esai")) { | 581 | } else if (of_node_name_eq(cpu_np, "esai")) { |
582 | priv->cpu_priv.sysclk_id[1] = ESAI_HCKT_EXTAL; | 582 | priv->cpu_priv.sysclk_id[1] = ESAI_HCKT_EXTAL; |
583 | priv->cpu_priv.sysclk_id[0] = ESAI_HCKR_EXTAL; | 583 | priv->cpu_priv.sysclk_id[0] = ESAI_HCKR_EXTAL; |
584 | } else if (strstr(cpu_np->name, "sai")) { | 584 | } else if (of_node_name_eq(cpu_np, "sai")) { |
585 | priv->cpu_priv.sysclk_id[1] = FSL_SAI_CLK_MAST1; | 585 | priv->cpu_priv.sysclk_id[1] = FSL_SAI_CLK_MAST1; |
586 | priv->cpu_priv.sysclk_id[0] = FSL_SAI_CLK_MAST1; | 586 | priv->cpu_priv.sysclk_id[0] = FSL_SAI_CLK_MAST1; |
587 | } | 587 | } |
diff --git a/sound/soc/fsl/fsl_ssi_dbg.c b/sound/soc/fsl/fsl_ssi_dbg.c index 1255dfe19eef..6f6294149476 100644 --- a/sound/soc/fsl/fsl_ssi_dbg.c +++ b/sound/soc/fsl/fsl_ssi_dbg.c | |||
@@ -124,17 +124,7 @@ static int fsl_ssi_stats_show(struct seq_file *s, void *unused) | |||
124 | return 0; | 124 | return 0; |
125 | } | 125 | } |
126 | 126 | ||
127 | static int fsl_ssi_stats_open(struct inode *inode, struct file *file) | 127 | DEFINE_SHOW_ATTRIBUTE(fsl_ssi_stats); |
128 | { | ||
129 | return single_open(file, fsl_ssi_stats_show, inode->i_private); | ||
130 | } | ||
131 | |||
132 | static const struct file_operations fsl_ssi_stats_ops = { | ||
133 | .open = fsl_ssi_stats_open, | ||
134 | .read = seq_read, | ||
135 | .llseek = seq_lseek, | ||
136 | .release = single_release, | ||
137 | }; | ||
138 | 128 | ||
139 | int fsl_ssi_debugfs_create(struct fsl_ssi_dbg *ssi_dbg, struct device *dev) | 129 | int fsl_ssi_debugfs_create(struct fsl_ssi_dbg *ssi_dbg, struct device *dev) |
140 | { | 130 | { |
@@ -144,7 +134,7 @@ int fsl_ssi_debugfs_create(struct fsl_ssi_dbg *ssi_dbg, struct device *dev) | |||
144 | 134 | ||
145 | ssi_dbg->dbg_stats = debugfs_create_file("stats", 0444, | 135 | ssi_dbg->dbg_stats = debugfs_create_file("stats", 0444, |
146 | ssi_dbg->dbg_dir, ssi_dbg, | 136 | ssi_dbg->dbg_dir, ssi_dbg, |
147 | &fsl_ssi_stats_ops); | 137 | &fsl_ssi_stats_fops); |
148 | if (!ssi_dbg->dbg_stats) { | 138 | if (!ssi_dbg->dbg_stats) { |
149 | debugfs_remove(ssi_dbg->dbg_dir); | 139 | debugfs_remove(ssi_dbg->dbg_dir); |
150 | return -ENOMEM; | 140 | return -ENOMEM; |
diff --git a/sound/soc/generic/Kconfig b/sound/soc/generic/Kconfig index c954be0a0f96..92c2cf06f40a 100644 --- a/sound/soc/generic/Kconfig +++ b/sound/soc/generic/Kconfig | |||
@@ -6,6 +6,7 @@ config SND_SIMPLE_CARD | |||
6 | select SND_SIMPLE_CARD_UTILS | 6 | select SND_SIMPLE_CARD_UTILS |
7 | help | 7 | help |
8 | This option enables generic simple sound card support | 8 | This option enables generic simple sound card support |
9 | It also support DPCM of multi CPU single Codec ststem. | ||
9 | 10 | ||
10 | config SND_SIMPLE_SCU_CARD | 11 | config SND_SIMPLE_SCU_CARD |
11 | tristate "ASoC Simple SCU sound card support" | 12 | tristate "ASoC Simple SCU sound card support" |
@@ -20,8 +21,9 @@ config SND_AUDIO_GRAPH_CARD | |||
20 | depends on OF | 21 | depends on OF |
21 | select SND_SIMPLE_CARD_UTILS | 22 | select SND_SIMPLE_CARD_UTILS |
22 | help | 23 | help |
23 | This option enables generic simple simple sound card support | 24 | This option enables generic simple sound card support |
24 | with OF-graph DT bindings. | 25 | with OF-graph DT bindings. |
26 | It also support DPCM of multi CPU single Codec ststem. | ||
25 | 27 | ||
26 | config SND_AUDIO_GRAPH_SCU_CARD | 28 | config SND_AUDIO_GRAPH_SCU_CARD |
27 | tristate "ASoC Audio Graph SCU sound card support" | 29 | tristate "ASoC Audio Graph SCU sound card support" |
diff --git a/sound/soc/generic/audio-graph-card.c b/sound/soc/generic/audio-graph-card.c index 25c819e402e1..0d6144560a1e 100644 --- a/sound/soc/generic/audio-graph-card.c +++ b/sound/soc/generic/audio-graph-card.c | |||
@@ -23,19 +23,29 @@ | |||
23 | struct graph_card_data { | 23 | struct graph_card_data { |
24 | struct snd_soc_card snd_card; | 24 | struct snd_soc_card snd_card; |
25 | struct graph_dai_props { | 25 | struct graph_dai_props { |
26 | struct asoc_simple_dai cpu_dai; | 26 | struct asoc_simple_dai *cpu_dai; |
27 | struct asoc_simple_dai codec_dai; | 27 | struct asoc_simple_dai *codec_dai; |
28 | struct snd_soc_dai_link_component codecs; /* single codec */ | 28 | struct snd_soc_dai_link_component codecs; /* single codec */ |
29 | struct snd_soc_dai_link_component platform; | 29 | struct snd_soc_dai_link_component platform; |
30 | struct asoc_simple_card_data adata; | ||
31 | struct snd_soc_codec_conf *codec_conf; | ||
30 | unsigned int mclk_fs; | 32 | unsigned int mclk_fs; |
31 | } *dai_props; | 33 | } *dai_props; |
32 | unsigned int mclk_fs; | ||
33 | struct asoc_simple_jack hp_jack; | 34 | struct asoc_simple_jack hp_jack; |
34 | struct asoc_simple_jack mic_jack; | 35 | struct asoc_simple_jack mic_jack; |
35 | struct snd_soc_dai_link *dai_link; | 36 | struct snd_soc_dai_link *dai_link; |
37 | struct asoc_simple_dai *dais; | ||
38 | struct snd_soc_codec_conf *codec_conf; | ||
36 | struct gpio_desc *pa_gpio; | 39 | struct gpio_desc *pa_gpio; |
37 | }; | 40 | }; |
38 | 41 | ||
42 | #define graph_priv_to_card(priv) (&(priv)->snd_card) | ||
43 | #define graph_priv_to_props(priv, i) ((priv)->dai_props + (i)) | ||
44 | #define graph_priv_to_dev(priv) (graph_priv_to_card(priv)->dev) | ||
45 | #define graph_priv_to_link(priv, i) (graph_priv_to_card(priv)->dai_link + (i)) | ||
46 | |||
47 | #define PREFIX "audio-graph-card," | ||
48 | |||
39 | static int asoc_graph_card_outdrv_event(struct snd_soc_dapm_widget *w, | 49 | static int asoc_graph_card_outdrv_event(struct snd_soc_dapm_widget *w, |
40 | struct snd_kcontrol *kcontrol, | 50 | struct snd_kcontrol *kcontrol, |
41 | int event) | 51 | int event) |
@@ -63,11 +73,6 @@ static const struct snd_soc_dapm_widget asoc_graph_card_dapm_widgets[] = { | |||
63 | SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD), | 73 | SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD), |
64 | }; | 74 | }; |
65 | 75 | ||
66 | #define graph_priv_to_card(priv) (&(priv)->snd_card) | ||
67 | #define graph_priv_to_props(priv, i) ((priv)->dai_props + (i)) | ||
68 | #define graph_priv_to_dev(priv) (graph_priv_to_card(priv)->dev) | ||
69 | #define graph_priv_to_link(priv, i) (graph_priv_to_card(priv)->dai_link + (i)) | ||
70 | |||
71 | static int asoc_graph_card_startup(struct snd_pcm_substream *substream) | 76 | static int asoc_graph_card_startup(struct snd_pcm_substream *substream) |
72 | { | 77 | { |
73 | struct snd_soc_pcm_runtime *rtd = substream->private_data; | 78 | struct snd_soc_pcm_runtime *rtd = substream->private_data; |
@@ -75,13 +80,13 @@ static int asoc_graph_card_startup(struct snd_pcm_substream *substream) | |||
75 | struct graph_dai_props *dai_props = graph_priv_to_props(priv, rtd->num); | 80 | struct graph_dai_props *dai_props = graph_priv_to_props(priv, rtd->num); |
76 | int ret; | 81 | int ret; |
77 | 82 | ||
78 | ret = asoc_simple_card_clk_enable(&dai_props->cpu_dai); | 83 | ret = asoc_simple_card_clk_enable(dai_props->cpu_dai); |
79 | if (ret) | 84 | if (ret) |
80 | return ret; | 85 | return ret; |
81 | 86 | ||
82 | ret = asoc_simple_card_clk_enable(&dai_props->codec_dai); | 87 | ret = asoc_simple_card_clk_enable(dai_props->codec_dai); |
83 | if (ret) | 88 | if (ret) |
84 | asoc_simple_card_clk_disable(&dai_props->cpu_dai); | 89 | asoc_simple_card_clk_disable(dai_props->cpu_dai); |
85 | 90 | ||
86 | return ret; | 91 | return ret; |
87 | } | 92 | } |
@@ -92,9 +97,9 @@ static void asoc_graph_card_shutdown(struct snd_pcm_substream *substream) | |||
92 | struct graph_card_data *priv = snd_soc_card_get_drvdata(rtd->card); | 97 | struct graph_card_data *priv = snd_soc_card_get_drvdata(rtd->card); |
93 | struct graph_dai_props *dai_props = graph_priv_to_props(priv, rtd->num); | 98 | struct graph_dai_props *dai_props = graph_priv_to_props(priv, rtd->num); |
94 | 99 | ||
95 | asoc_simple_card_clk_disable(&dai_props->cpu_dai); | 100 | asoc_simple_card_clk_disable(dai_props->cpu_dai); |
96 | 101 | ||
97 | asoc_simple_card_clk_disable(&dai_props->codec_dai); | 102 | asoc_simple_card_clk_disable(dai_props->codec_dai); |
98 | } | 103 | } |
99 | 104 | ||
100 | static int asoc_graph_card_hw_params(struct snd_pcm_substream *substream, | 105 | static int asoc_graph_card_hw_params(struct snd_pcm_substream *substream, |
@@ -108,9 +113,7 @@ static int asoc_graph_card_hw_params(struct snd_pcm_substream *substream, | |||
108 | unsigned int mclk, mclk_fs = 0; | 113 | unsigned int mclk, mclk_fs = 0; |
109 | int ret = 0; | 114 | int ret = 0; |
110 | 115 | ||
111 | if (priv->mclk_fs) | 116 | if (dai_props->mclk_fs) |
112 | mclk_fs = priv->mclk_fs; | ||
113 | else if (dai_props->mclk_fs) | ||
114 | mclk_fs = dai_props->mclk_fs; | 117 | mclk_fs = dai_props->mclk_fs; |
115 | 118 | ||
116 | if (mclk_fs) { | 119 | if (mclk_fs) { |
@@ -139,86 +142,238 @@ static const struct snd_soc_ops asoc_graph_card_ops = { | |||
139 | static int asoc_graph_card_dai_init(struct snd_soc_pcm_runtime *rtd) | 142 | static int asoc_graph_card_dai_init(struct snd_soc_pcm_runtime *rtd) |
140 | { | 143 | { |
141 | struct graph_card_data *priv = snd_soc_card_get_drvdata(rtd->card); | 144 | struct graph_card_data *priv = snd_soc_card_get_drvdata(rtd->card); |
142 | struct snd_soc_dai *codec = rtd->codec_dai; | 145 | struct graph_dai_props *dai_props = graph_priv_to_props(priv, rtd->num); |
143 | struct snd_soc_dai *cpu = rtd->cpu_dai; | 146 | int ret = 0; |
144 | struct graph_dai_props *dai_props = | ||
145 | graph_priv_to_props(priv, rtd->num); | ||
146 | int ret; | ||
147 | 147 | ||
148 | ret = asoc_simple_card_init_dai(codec, &dai_props->codec_dai); | 148 | ret = asoc_simple_card_init_dai(rtd->codec_dai, |
149 | dai_props->codec_dai); | ||
149 | if (ret < 0) | 150 | if (ret < 0) |
150 | return ret; | 151 | return ret; |
151 | 152 | ||
152 | ret = asoc_simple_card_init_dai(cpu, &dai_props->cpu_dai); | 153 | ret = asoc_simple_card_init_dai(rtd->cpu_dai, |
154 | dai_props->cpu_dai); | ||
153 | if (ret < 0) | 155 | if (ret < 0) |
154 | return ret; | 156 | return ret; |
155 | 157 | ||
156 | return 0; | 158 | return 0; |
157 | } | 159 | } |
158 | 160 | ||
159 | static int asoc_graph_card_dai_link_of(struct device_node *cpu_port, | 161 | static int asoc_graph_card_be_hw_params_fixup(struct snd_soc_pcm_runtime *rtd, |
160 | struct graph_card_data *priv, | 162 | struct snd_pcm_hw_params *params) |
161 | int idx) | 163 | { |
164 | struct graph_card_data *priv = snd_soc_card_get_drvdata(rtd->card); | ||
165 | struct graph_dai_props *dai_props = graph_priv_to_props(priv, rtd->num); | ||
166 | |||
167 | asoc_simple_card_convert_fixup(&dai_props->adata, params); | ||
168 | |||
169 | return 0; | ||
170 | } | ||
171 | |||
172 | static int asoc_graph_card_dai_link_of_dpcm(struct device_node *top, | ||
173 | struct device_node *cpu_ep, | ||
174 | struct device_node *codec_ep, | ||
175 | struct graph_card_data *priv, | ||
176 | int *dai_idx, int link_idx, | ||
177 | int *conf_idx, int is_cpu) | ||
162 | { | 178 | { |
163 | struct device *dev = graph_priv_to_dev(priv); | 179 | struct device *dev = graph_priv_to_dev(priv); |
164 | struct snd_soc_dai_link *dai_link = graph_priv_to_link(priv, idx); | 180 | struct snd_soc_dai_link *dai_link = graph_priv_to_link(priv, link_idx); |
165 | struct graph_dai_props *dai_props = graph_priv_to_props(priv, idx); | 181 | struct graph_dai_props *dai_props = graph_priv_to_props(priv, link_idx); |
166 | struct asoc_simple_dai *cpu_dai = &dai_props->cpu_dai; | 182 | struct device_node *ep = is_cpu ? cpu_ep : codec_ep; |
167 | struct asoc_simple_dai *codec_dai = &dai_props->codec_dai; | 183 | struct device_node *port = of_get_parent(ep); |
168 | struct device_node *cpu_ep = of_get_next_child(cpu_port, NULL); | 184 | struct device_node *ports = of_get_parent(port); |
169 | struct device_node *codec_ep = of_graph_get_remote_endpoint(cpu_ep); | 185 | struct device_node *node = of_graph_get_port_parent(ep); |
170 | struct device_node *rcpu_ep = of_graph_get_remote_endpoint(codec_ep); | 186 | struct asoc_simple_dai *dai; |
187 | struct snd_soc_dai_link_component *codecs = dai_link->codecs; | ||
171 | int ret; | 188 | int ret; |
172 | 189 | ||
173 | if (rcpu_ep != cpu_ep) { | 190 | dev_dbg(dev, "link_of DPCM (for %s)\n", is_cpu ? "CPU" : "Codec"); |
174 | dev_err(dev, "remote-endpoint mismatch (%s/%s/%s)\n", | 191 | |
175 | cpu_ep->name, codec_ep->name, rcpu_ep->name); | 192 | of_property_read_u32(top, "mclk-fs", &dai_props->mclk_fs); |
176 | ret = -EINVAL; | 193 | of_property_read_u32(ports, "mclk-fs", &dai_props->mclk_fs); |
177 | goto dai_link_of_err; | 194 | of_property_read_u32(port, "mclk-fs", &dai_props->mclk_fs); |
195 | of_property_read_u32(ep, "mclk-fs", &dai_props->mclk_fs); | ||
196 | |||
197 | asoc_simple_card_parse_convert(dev, top, NULL, &dai_props->adata); | ||
198 | asoc_simple_card_parse_convert(dev, node, PREFIX, &dai_props->adata); | ||
199 | asoc_simple_card_parse_convert(dev, ports, NULL, &dai_props->adata); | ||
200 | asoc_simple_card_parse_convert(dev, port, NULL, &dai_props->adata); | ||
201 | asoc_simple_card_parse_convert(dev, ep, NULL, &dai_props->adata); | ||
202 | |||
203 | of_node_put(ports); | ||
204 | of_node_put(port); | ||
205 | |||
206 | if (is_cpu) { | ||
207 | |||
208 | /* BE is dummy */ | ||
209 | codecs->of_node = NULL; | ||
210 | codecs->dai_name = "snd-soc-dummy-dai"; | ||
211 | codecs->name = "snd-soc-dummy"; | ||
212 | |||
213 | /* FE settings */ | ||
214 | dai_link->dynamic = 1; | ||
215 | dai_link->dpcm_merged_format = 1; | ||
216 | |||
217 | dai = | ||
218 | dai_props->cpu_dai = &priv->dais[(*dai_idx)++]; | ||
219 | |||
220 | ret = asoc_simple_card_parse_graph_cpu(ep, dai_link); | ||
221 | if (ret) | ||
222 | return ret; | ||
223 | |||
224 | ret = asoc_simple_card_parse_clk_cpu(dev, ep, dai_link, dai); | ||
225 | if (ret < 0) | ||
226 | return ret; | ||
227 | |||
228 | ret = asoc_simple_card_set_dailink_name(dev, dai_link, | ||
229 | "fe.%s", | ||
230 | dai_link->cpu_dai_name); | ||
231 | if (ret < 0) | ||
232 | return ret; | ||
233 | |||
234 | /* card->num_links includes Codec */ | ||
235 | asoc_simple_card_canonicalize_cpu(dai_link, | ||
236 | of_graph_get_endpoint_count(dai_link->cpu_of_node) == 1); | ||
237 | } else { | ||
238 | struct snd_soc_codec_conf *cconf; | ||
239 | |||
240 | /* FE is dummy */ | ||
241 | dai_link->cpu_of_node = NULL; | ||
242 | dai_link->cpu_dai_name = "snd-soc-dummy-dai"; | ||
243 | dai_link->cpu_name = "snd-soc-dummy"; | ||
244 | |||
245 | /* BE settings */ | ||
246 | dai_link->no_pcm = 1; | ||
247 | dai_link->be_hw_params_fixup = asoc_graph_card_be_hw_params_fixup; | ||
248 | |||
249 | dai = | ||
250 | dai_props->codec_dai = &priv->dais[(*dai_idx)++]; | ||
251 | |||
252 | cconf = | ||
253 | dai_props->codec_conf = &priv->codec_conf[(*conf_idx)++]; | ||
254 | |||
255 | ret = asoc_simple_card_parse_graph_codec(ep, dai_link); | ||
256 | if (ret < 0) | ||
257 | return ret; | ||
258 | |||
259 | ret = asoc_simple_card_parse_clk_codec(dev, ep, dai_link, dai); | ||
260 | if (ret < 0) | ||
261 | return ret; | ||
262 | |||
263 | ret = asoc_simple_card_set_dailink_name(dev, dai_link, | ||
264 | "be.%s", | ||
265 | codecs->dai_name); | ||
266 | if (ret < 0) | ||
267 | return ret; | ||
268 | |||
269 | /* check "prefix" from top node */ | ||
270 | snd_soc_of_parse_node_prefix(top, cconf, codecs->of_node, | ||
271 | "prefix"); | ||
272 | snd_soc_of_parse_node_prefix(node, cconf, codecs->of_node, | ||
273 | PREFIX "prefix"); | ||
274 | snd_soc_of_parse_node_prefix(ports, cconf, codecs->of_node, | ||
275 | "prefix"); | ||
276 | snd_soc_of_parse_node_prefix(port, cconf, codecs->of_node, | ||
277 | "prefix"); | ||
178 | } | 278 | } |
179 | 279 | ||
280 | ret = asoc_simple_card_of_parse_tdm(ep, dai); | ||
281 | if (ret) | ||
282 | return ret; | ||
283 | |||
284 | ret = asoc_simple_card_canonicalize_dailink(dai_link); | ||
285 | if (ret < 0) | ||
286 | return ret; | ||
287 | |||
180 | ret = asoc_simple_card_parse_daifmt(dev, cpu_ep, codec_ep, | 288 | ret = asoc_simple_card_parse_daifmt(dev, cpu_ep, codec_ep, |
181 | NULL, &dai_link->dai_fmt); | 289 | NULL, &dai_link->dai_fmt); |
182 | if (ret < 0) | 290 | if (ret < 0) |
183 | goto dai_link_of_err; | 291 | return ret; |
292 | |||
293 | dai_link->dpcm_playback = 1; | ||
294 | dai_link->dpcm_capture = 1; | ||
295 | dai_link->ops = &asoc_graph_card_ops; | ||
296 | dai_link->init = asoc_graph_card_dai_init; | ||
297 | |||
298 | return 0; | ||
299 | } | ||
300 | |||
301 | static int asoc_graph_card_dai_link_of(struct device_node *top, | ||
302 | struct device_node *cpu_ep, | ||
303 | struct device_node *codec_ep, | ||
304 | struct graph_card_data *priv, | ||
305 | int *dai_idx, int link_idx) | ||
306 | { | ||
307 | struct device *dev = graph_priv_to_dev(priv); | ||
308 | struct snd_soc_dai_link *dai_link = graph_priv_to_link(priv, link_idx); | ||
309 | struct graph_dai_props *dai_props = graph_priv_to_props(priv, link_idx); | ||
310 | struct device_node *cpu_port = of_get_parent(cpu_ep); | ||
311 | struct device_node *codec_port = of_get_parent(codec_ep); | ||
312 | struct device_node *cpu_ports = of_get_parent(cpu_port); | ||
313 | struct device_node *codec_ports = of_get_parent(codec_port); | ||
314 | struct asoc_simple_dai *cpu_dai; | ||
315 | struct asoc_simple_dai *codec_dai; | ||
316 | int ret; | ||
317 | |||
318 | dev_dbg(dev, "link_of\n"); | ||
319 | |||
320 | cpu_dai = | ||
321 | dai_props->cpu_dai = &priv->dais[(*dai_idx)++]; | ||
322 | codec_dai = | ||
323 | dai_props->codec_dai = &priv->dais[(*dai_idx)++]; | ||
184 | 324 | ||
185 | of_property_read_u32(cpu_ep, "mclk-fs", &dai_props->mclk_fs); | 325 | /* Factor to mclk, used in hw_params() */ |
186 | of_property_read_u32(codec_ep, "mclk-fs", &dai_props->mclk_fs); | 326 | of_property_read_u32(top, "mclk-fs", &dai_props->mclk_fs); |
327 | of_property_read_u32(cpu_ports, "mclk-fs", &dai_props->mclk_fs); | ||
328 | of_property_read_u32(codec_ports, "mclk-fs", &dai_props->mclk_fs); | ||
329 | of_property_read_u32(cpu_port, "mclk-fs", &dai_props->mclk_fs); | ||
330 | of_property_read_u32(codec_port, "mclk-fs", &dai_props->mclk_fs); | ||
331 | of_property_read_u32(cpu_ep, "mclk-fs", &dai_props->mclk_fs); | ||
332 | of_property_read_u32(codec_ep, "mclk-fs", &dai_props->mclk_fs); | ||
333 | of_node_put(cpu_port); | ||
334 | of_node_put(cpu_ports); | ||
335 | of_node_put(codec_port); | ||
336 | of_node_put(codec_ports); | ||
337 | |||
338 | ret = asoc_simple_card_parse_daifmt(dev, cpu_ep, codec_ep, | ||
339 | NULL, &dai_link->dai_fmt); | ||
340 | if (ret < 0) | ||
341 | return ret; | ||
187 | 342 | ||
188 | ret = asoc_simple_card_parse_graph_cpu(cpu_ep, dai_link); | 343 | ret = asoc_simple_card_parse_graph_cpu(cpu_ep, dai_link); |
189 | if (ret < 0) | 344 | if (ret < 0) |
190 | goto dai_link_of_err; | 345 | return ret; |
191 | 346 | ||
192 | ret = asoc_simple_card_parse_graph_codec(codec_ep, dai_link); | 347 | ret = asoc_simple_card_parse_graph_codec(codec_ep, dai_link); |
193 | if (ret < 0) | 348 | if (ret < 0) |
194 | goto dai_link_of_err; | 349 | return ret; |
195 | 350 | ||
196 | ret = asoc_simple_card_of_parse_tdm(cpu_ep, cpu_dai); | 351 | ret = asoc_simple_card_of_parse_tdm(cpu_ep, cpu_dai); |
197 | if (ret < 0) | 352 | if (ret < 0) |
198 | goto dai_link_of_err; | 353 | return ret; |
199 | 354 | ||
200 | ret = asoc_simple_card_of_parse_tdm(codec_ep, codec_dai); | 355 | ret = asoc_simple_card_of_parse_tdm(codec_ep, codec_dai); |
201 | if (ret < 0) | 356 | if (ret < 0) |
202 | goto dai_link_of_err; | 357 | return ret; |
203 | 358 | ||
204 | ret = asoc_simple_card_parse_clk_cpu(dev, cpu_ep, dai_link, cpu_dai); | 359 | ret = asoc_simple_card_parse_clk_cpu(dev, cpu_ep, dai_link, cpu_dai); |
205 | if (ret < 0) | 360 | if (ret < 0) |
206 | goto dai_link_of_err; | 361 | return ret; |
207 | 362 | ||
208 | ret = asoc_simple_card_parse_clk_codec(dev, codec_ep, dai_link, codec_dai); | 363 | ret = asoc_simple_card_parse_clk_codec(dev, codec_ep, dai_link, codec_dai); |
209 | if (ret < 0) | 364 | if (ret < 0) |
210 | goto dai_link_of_err; | 365 | return ret; |
211 | 366 | ||
212 | ret = asoc_simple_card_canonicalize_dailink(dai_link); | 367 | ret = asoc_simple_card_canonicalize_dailink(dai_link); |
213 | if (ret < 0) | 368 | if (ret < 0) |
214 | goto dai_link_of_err; | 369 | return ret; |
215 | 370 | ||
216 | ret = asoc_simple_card_set_dailink_name(dev, dai_link, | 371 | ret = asoc_simple_card_set_dailink_name(dev, dai_link, |
217 | "%s-%s", | 372 | "%s-%s", |
218 | dai_link->cpu_dai_name, | 373 | dai_link->cpu_dai_name, |
219 | dai_link->codecs->dai_name); | 374 | dai_link->codecs->dai_name); |
220 | if (ret < 0) | 375 | if (ret < 0) |
221 | goto dai_link_of_err; | 376 | return ret; |
222 | 377 | ||
223 | dai_link->ops = &asoc_graph_card_ops; | 378 | dai_link->ops = &asoc_graph_card_ops; |
224 | dai_link->init = asoc_graph_card_dai_init; | 379 | dai_link->init = asoc_graph_card_dai_init; |
@@ -226,12 +381,7 @@ static int asoc_graph_card_dai_link_of(struct device_node *cpu_port, | |||
226 | asoc_simple_card_canonicalize_cpu(dai_link, | 381 | asoc_simple_card_canonicalize_cpu(dai_link, |
227 | of_graph_get_endpoint_count(dai_link->cpu_of_node) == 1); | 382 | of_graph_get_endpoint_count(dai_link->cpu_of_node) == 1); |
228 | 383 | ||
229 | dai_link_of_err: | 384 | return 0; |
230 | of_node_put(cpu_ep); | ||
231 | of_node_put(rcpu_ep); | ||
232 | of_node_put(codec_ep); | ||
233 | |||
234 | return ret; | ||
235 | } | 385 | } |
236 | 386 | ||
237 | static int asoc_graph_card_parse_of(struct graph_card_data *priv) | 387 | static int asoc_graph_card_parse_of(struct graph_card_data *priv) |
@@ -239,44 +389,173 @@ static int asoc_graph_card_parse_of(struct graph_card_data *priv) | |||
239 | struct of_phandle_iterator it; | 389 | struct of_phandle_iterator it; |
240 | struct device *dev = graph_priv_to_dev(priv); | 390 | struct device *dev = graph_priv_to_dev(priv); |
241 | struct snd_soc_card *card = graph_priv_to_card(priv); | 391 | struct snd_soc_card *card = graph_priv_to_card(priv); |
242 | struct device_node *node = dev->of_node; | 392 | struct device_node *top = dev->of_node; |
243 | int rc, idx = 0; | 393 | struct device_node *node = top; |
244 | int ret; | 394 | struct device_node *cpu_port; |
395 | struct device_node *cpu_ep = NULL; | ||
396 | struct device_node *codec_ep = NULL; | ||
397 | struct device_node *codec_port = NULL; | ||
398 | struct device_node *codec_port_old = NULL; | ||
399 | int rc, ret; | ||
400 | int link_idx, dai_idx, conf_idx; | ||
401 | int cpu; | ||
245 | 402 | ||
246 | ret = asoc_simple_card_of_parse_widgets(card, NULL); | 403 | ret = asoc_simple_card_of_parse_widgets(card, NULL); |
247 | if (ret < 0) | 404 | if (ret < 0) |
248 | return ret; | 405 | return ret; |
249 | 406 | ||
250 | ret = asoc_simple_card_of_parse_routing(card, NULL, 1); | 407 | ret = asoc_simple_card_of_parse_routing(card, NULL); |
251 | if (ret < 0) | 408 | if (ret < 0) |
252 | return ret; | 409 | return ret; |
253 | 410 | ||
254 | /* Factor to mclk, used in hw_params() */ | 411 | link_idx = 0; |
255 | of_property_read_u32(node, "mclk-fs", &priv->mclk_fs); | 412 | dai_idx = 0; |
256 | 413 | conf_idx = 0; | |
257 | of_for_each_phandle(&it, rc, node, "dais", NULL, 0) { | 414 | codec_port_old = NULL; |
258 | ret = asoc_graph_card_dai_link_of(it.node, priv, idx++); | 415 | for (cpu = 1; cpu >= 0; cpu--) { |
259 | if (ret < 0) { | 416 | /* |
260 | of_node_put(it.node); | 417 | * Detect all CPU first, and Detect all Codec 2nd. |
261 | 418 | * | |
262 | return ret; | 419 | * In Normal sound case, all DAIs are detected |
420 | * as "CPU-Codec". | ||
421 | * | ||
422 | * In DPCM sound case, | ||
423 | * all CPUs are detected as "CPU-dummy", and | ||
424 | * all Codecs are detected as "dummy-Codec". | ||
425 | * To avoid random sub-device numbering, | ||
426 | * detect "dummy-Codec" in last; | ||
427 | */ | ||
428 | of_for_each_phandle(&it, rc, node, "dais", NULL, 0) { | ||
429 | cpu_port = it.node; | ||
430 | cpu_ep = NULL; | ||
431 | while (1) { | ||
432 | cpu_ep = of_get_next_child(cpu_port, cpu_ep); | ||
433 | if (!cpu_ep) | ||
434 | break; | ||
435 | |||
436 | codec_ep = of_graph_get_remote_endpoint(cpu_ep); | ||
437 | codec_port = of_get_parent(codec_ep); | ||
438 | |||
439 | of_node_put(codec_ep); | ||
440 | of_node_put(codec_port); | ||
441 | |||
442 | dev_dbg(dev, "%pOFf <-> %pOFf\n", cpu_ep, codec_ep); | ||
443 | |||
444 | if (of_get_child_count(codec_port) > 1) { | ||
445 | /* | ||
446 | * for DPCM sound | ||
447 | */ | ||
448 | if (!cpu) { | ||
449 | if (codec_port_old == codec_port) | ||
450 | continue; | ||
451 | codec_port_old = codec_port; | ||
452 | } | ||
453 | ret = asoc_graph_card_dai_link_of_dpcm( | ||
454 | top, cpu_ep, codec_ep, priv, | ||
455 | &dai_idx, link_idx++, | ||
456 | &conf_idx, cpu); | ||
457 | } else if (cpu) { | ||
458 | /* | ||
459 | * for Normal sound | ||
460 | */ | ||
461 | ret = asoc_graph_card_dai_link_of( | ||
462 | top, cpu_ep, codec_ep, priv, | ||
463 | &dai_idx, link_idx++); | ||
464 | } | ||
465 | if (ret < 0) | ||
466 | return ret; | ||
467 | } | ||
263 | } | 468 | } |
264 | } | 469 | } |
265 | 470 | ||
266 | return asoc_simple_card_parse_card_name(card, NULL); | 471 | return asoc_simple_card_parse_card_name(card, NULL); |
267 | } | 472 | } |
268 | 473 | ||
269 | static int asoc_graph_get_dais_count(struct device *dev) | 474 | static void asoc_graph_get_dais_count(struct device *dev, |
475 | int *link_num, | ||
476 | int *dais_num, | ||
477 | int *ccnf_num) | ||
270 | { | 478 | { |
271 | struct of_phandle_iterator it; | 479 | struct of_phandle_iterator it; |
272 | struct device_node *node = dev->of_node; | 480 | struct device_node *node = dev->of_node; |
273 | int count = 0; | 481 | struct device_node *cpu_port; |
482 | struct device_node *cpu_ep; | ||
483 | struct device_node *codec_ep; | ||
484 | struct device_node *codec_port; | ||
485 | struct device_node *codec_port_old; | ||
486 | struct device_node *codec_port_old2; | ||
274 | int rc; | 487 | int rc; |
275 | 488 | ||
276 | of_for_each_phandle(&it, rc, node, "dais", NULL, 0) | 489 | /* |
277 | count++; | 490 | * link_num : number of links. |
278 | 491 | * CPU-Codec / CPU-dummy / dummy-Codec | |
279 | return count; | 492 | * dais_num : number of DAIs |
493 | * ccnf_num : number of codec_conf | ||
494 | * same number for "dummy-Codec" | ||
495 | * | ||
496 | * ex1) | ||
497 | * CPU0 --- Codec0 link : 5 | ||
498 | * CPU1 --- Codec1 dais : 7 | ||
499 | * CPU2 -/ ccnf : 1 | ||
500 | * CPU3 --- Codec2 | ||
501 | * | ||
502 | * => 5 links = 2xCPU-Codec + 2xCPU-dummy + 1xdummy-Codec | ||
503 | * => 7 DAIs = 4xCPU + 3xCodec | ||
504 | * => 1 ccnf = 1xdummy-Codec | ||
505 | * | ||
506 | * ex2) | ||
507 | * CPU0 --- Codec0 link : 5 | ||
508 | * CPU1 --- Codec1 dais : 6 | ||
509 | * CPU2 -/ ccnf : 1 | ||
510 | * CPU3 -/ | ||
511 | * | ||
512 | * => 5 links = 1xCPU-Codec + 3xCPU-dummy + 1xdummy-Codec | ||
513 | * => 6 DAIs = 4xCPU + 2xCodec | ||
514 | * => 1 ccnf = 1xdummy-Codec | ||
515 | * | ||
516 | * ex3) | ||
517 | * CPU0 --- Codec0 link : 6 | ||
518 | * CPU1 -/ dais : 6 | ||
519 | * CPU2 --- Codec1 ccnf : 2 | ||
520 | * CPU3 -/ | ||
521 | * | ||
522 | * => 6 links = 0xCPU-Codec + 4xCPU-dummy + 2xdummy-Codec | ||
523 | * => 6 DAIs = 4xCPU + 2xCodec | ||
524 | * => 2 ccnf = 2xdummy-Codec | ||
525 | */ | ||
526 | codec_port_old = NULL; | ||
527 | codec_port_old2 = NULL; | ||
528 | of_for_each_phandle(&it, rc, node, "dais", NULL, 0) { | ||
529 | cpu_port = it.node; | ||
530 | cpu_ep = NULL; | ||
531 | while (1) { | ||
532 | cpu_ep = of_get_next_child(cpu_port, cpu_ep); | ||
533 | if (!cpu_ep) | ||
534 | break; | ||
535 | |||
536 | codec_ep = of_graph_get_remote_endpoint(cpu_ep); | ||
537 | codec_port = of_get_parent(codec_ep); | ||
538 | |||
539 | of_node_put(codec_ep); | ||
540 | of_node_put(codec_port); | ||
541 | |||
542 | (*link_num)++; | ||
543 | (*dais_num)++; | ||
544 | |||
545 | if (codec_port_old == codec_port) { | ||
546 | if (codec_port_old2 != codec_port_old) { | ||
547 | (*link_num)++; | ||
548 | (*ccnf_num)++; | ||
549 | } | ||
550 | |||
551 | codec_port_old2 = codec_port_old; | ||
552 | continue; | ||
553 | } | ||
554 | |||
555 | (*dais_num)++; | ||
556 | codec_port_old = codec_port; | ||
557 | } | ||
558 | } | ||
280 | } | 559 | } |
281 | 560 | ||
282 | static int asoc_graph_soc_card_probe(struct snd_soc_card *card) | 561 | static int asoc_graph_soc_card_probe(struct snd_soc_card *card) |
@@ -300,22 +579,27 @@ static int asoc_graph_card_probe(struct platform_device *pdev) | |||
300 | struct graph_card_data *priv; | 579 | struct graph_card_data *priv; |
301 | struct snd_soc_dai_link *dai_link; | 580 | struct snd_soc_dai_link *dai_link; |
302 | struct graph_dai_props *dai_props; | 581 | struct graph_dai_props *dai_props; |
582 | struct asoc_simple_dai *dais; | ||
303 | struct device *dev = &pdev->dev; | 583 | struct device *dev = &pdev->dev; |
304 | struct snd_soc_card *card; | 584 | struct snd_soc_card *card; |
305 | int num, ret, i; | 585 | struct snd_soc_codec_conf *cconf; |
586 | int lnum = 0, dnum = 0, cnum = 0; | ||
587 | int ret, i; | ||
306 | 588 | ||
307 | /* Allocate the private data and the DAI link array */ | 589 | /* Allocate the private data and the DAI link array */ |
308 | priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL); | 590 | priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL); |
309 | if (!priv) | 591 | if (!priv) |
310 | return -ENOMEM; | 592 | return -ENOMEM; |
311 | 593 | ||
312 | num = asoc_graph_get_dais_count(dev); | 594 | asoc_graph_get_dais_count(dev, &lnum, &dnum, &cnum); |
313 | if (num == 0) | 595 | if (!lnum || !dnum) |
314 | return -EINVAL; | 596 | return -EINVAL; |
315 | 597 | ||
316 | dai_props = devm_kcalloc(dev, num, sizeof(*dai_props), GFP_KERNEL); | 598 | dai_props = devm_kcalloc(dev, lnum, sizeof(*dai_props), GFP_KERNEL); |
317 | dai_link = devm_kcalloc(dev, num, sizeof(*dai_link), GFP_KERNEL); | 599 | dai_link = devm_kcalloc(dev, lnum, sizeof(*dai_link), GFP_KERNEL); |
318 | if (!dai_props || !dai_link) | 600 | dais = devm_kcalloc(dev, dnum, sizeof(*dais), GFP_KERNEL); |
601 | cconf = devm_kcalloc(dev, cnum, sizeof(*cconf), GFP_KERNEL); | ||
602 | if (!dai_props || !dai_link || !dais) | ||
319 | return -ENOMEM; | 603 | return -ENOMEM; |
320 | 604 | ||
321 | /* | 605 | /* |
@@ -324,7 +608,7 @@ static int asoc_graph_card_probe(struct platform_device *pdev) | |||
324 | * see | 608 | * see |
325 | * soc-core.c :: snd_soc_init_multicodec() | 609 | * soc-core.c :: snd_soc_init_multicodec() |
326 | */ | 610 | */ |
327 | for (i = 0; i < num; i++) { | 611 | for (i = 0; i < lnum; i++) { |
328 | dai_link[i].codecs = &dai_props[i].codecs; | 612 | dai_link[i].codecs = &dai_props[i].codecs; |
329 | dai_link[i].num_codecs = 1; | 613 | dai_link[i].num_codecs = 1; |
330 | dai_link[i].platform = &dai_props[i].platform; | 614 | dai_link[i].platform = &dai_props[i].platform; |
@@ -339,16 +623,20 @@ static int asoc_graph_card_probe(struct platform_device *pdev) | |||
339 | 623 | ||
340 | priv->dai_props = dai_props; | 624 | priv->dai_props = dai_props; |
341 | priv->dai_link = dai_link; | 625 | priv->dai_link = dai_link; |
626 | priv->dais = dais; | ||
627 | priv->codec_conf = cconf; | ||
342 | 628 | ||
343 | /* Init snd_soc_card */ | 629 | /* Init snd_soc_card */ |
344 | card = graph_priv_to_card(priv); | 630 | card = graph_priv_to_card(priv); |
345 | card->owner = THIS_MODULE; | 631 | card->owner = THIS_MODULE; |
346 | card->dev = dev; | 632 | card->dev = dev; |
347 | card->dai_link = dai_link; | 633 | card->dai_link = dai_link; |
348 | card->num_links = num; | 634 | card->num_links = lnum; |
349 | card->dapm_widgets = asoc_graph_card_dapm_widgets; | 635 | card->dapm_widgets = asoc_graph_card_dapm_widgets; |
350 | card->num_dapm_widgets = ARRAY_SIZE(asoc_graph_card_dapm_widgets); | 636 | card->num_dapm_widgets = ARRAY_SIZE(asoc_graph_card_dapm_widgets); |
351 | card->probe = asoc_graph_soc_card_probe; | 637 | card->probe = asoc_graph_soc_card_probe; |
638 | card->codec_conf = cconf; | ||
639 | card->num_configs = cnum; | ||
352 | 640 | ||
353 | ret = asoc_graph_card_parse_of(priv); | 641 | ret = asoc_graph_card_parse_of(priv); |
354 | if (ret < 0) { | 642 | if (ret < 0) { |
@@ -379,6 +667,7 @@ static int asoc_graph_card_remove(struct platform_device *pdev) | |||
379 | 667 | ||
380 | static const struct of_device_id asoc_graph_of_match[] = { | 668 | static const struct of_device_id asoc_graph_of_match[] = { |
381 | { .compatible = "audio-graph-card", }, | 669 | { .compatible = "audio-graph-card", }, |
670 | { .compatible = "audio-graph-scu-card", }, | ||
382 | {}, | 671 | {}, |
383 | }; | 672 | }; |
384 | MODULE_DEVICE_TABLE(of, asoc_graph_of_match); | 673 | MODULE_DEVICE_TABLE(of, asoc_graph_of_match); |
diff --git a/sound/soc/generic/audio-graph-scu-card.c b/sound/soc/generic/audio-graph-scu-card.c index b83bb31021a9..e1b192ea147b 100644 --- a/sound/soc/generic/audio-graph-scu-card.c +++ b/sound/soc/generic/audio-graph-scu-card.c | |||
@@ -24,14 +24,18 @@ | |||
24 | 24 | ||
25 | struct graph_card_data { | 25 | struct graph_card_data { |
26 | struct snd_soc_card snd_card; | 26 | struct snd_soc_card snd_card; |
27 | struct snd_soc_codec_conf codec_conf; | ||
28 | struct graph_dai_props { | 27 | struct graph_dai_props { |
29 | struct asoc_simple_dai dai; | 28 | struct asoc_simple_dai *cpu_dai; |
29 | struct asoc_simple_dai *codec_dai; | ||
30 | struct snd_soc_dai_link_component codecs; | 30 | struct snd_soc_dai_link_component codecs; |
31 | struct snd_soc_dai_link_component platform; | 31 | struct snd_soc_dai_link_component platform; |
32 | struct asoc_simple_card_data adata; | ||
33 | struct snd_soc_codec_conf *codec_conf; | ||
32 | } *dai_props; | 34 | } *dai_props; |
33 | struct snd_soc_dai_link *dai_link; | 35 | struct snd_soc_dai_link *dai_link; |
36 | struct asoc_simple_dai *dais; | ||
34 | struct asoc_simple_card_data adata; | 37 | struct asoc_simple_card_data adata; |
38 | struct snd_soc_codec_conf *codec_conf; | ||
35 | }; | 39 | }; |
36 | 40 | ||
37 | #define graph_priv_to_card(priv) (&(priv)->snd_card) | 41 | #define graph_priv_to_card(priv) (&(priv)->snd_card) |
@@ -39,13 +43,24 @@ struct graph_card_data { | |||
39 | #define graph_priv_to_dev(priv) (graph_priv_to_card(priv)->dev) | 43 | #define graph_priv_to_dev(priv) (graph_priv_to_card(priv)->dev) |
40 | #define graph_priv_to_link(priv, i) (graph_priv_to_card(priv)->dai_link + (i)) | 44 | #define graph_priv_to_link(priv, i) (graph_priv_to_card(priv)->dai_link + (i)) |
41 | 45 | ||
46 | #define PREFIX "audio-graph-card," | ||
47 | |||
42 | static int asoc_graph_card_startup(struct snd_pcm_substream *substream) | 48 | static int asoc_graph_card_startup(struct snd_pcm_substream *substream) |
43 | { | 49 | { |
44 | struct snd_soc_pcm_runtime *rtd = substream->private_data; | 50 | struct snd_soc_pcm_runtime *rtd = substream->private_data; |
45 | struct graph_card_data *priv = snd_soc_card_get_drvdata(rtd->card); | 51 | struct graph_card_data *priv = snd_soc_card_get_drvdata(rtd->card); |
46 | struct graph_dai_props *dai_props = graph_priv_to_props(priv, rtd->num); | 52 | struct graph_dai_props *dai_props = graph_priv_to_props(priv, rtd->num); |
53 | int ret = 0; | ||
54 | |||
55 | ret = asoc_simple_card_clk_enable(dai_props->cpu_dai); | ||
56 | if (ret) | ||
57 | return ret; | ||
47 | 58 | ||
48 | return asoc_simple_card_clk_enable(&dai_props->dai); | 59 | ret = asoc_simple_card_clk_enable(dai_props->codec_dai); |
60 | if (ret) | ||
61 | asoc_simple_card_clk_disable(dai_props->cpu_dai); | ||
62 | |||
63 | return ret; | ||
49 | } | 64 | } |
50 | 65 | ||
51 | static void asoc_graph_card_shutdown(struct snd_pcm_substream *substream) | 66 | static void asoc_graph_card_shutdown(struct snd_pcm_substream *substream) |
@@ -54,7 +69,9 @@ static void asoc_graph_card_shutdown(struct snd_pcm_substream *substream) | |||
54 | struct graph_card_data *priv = snd_soc_card_get_drvdata(rtd->card); | 69 | struct graph_card_data *priv = snd_soc_card_get_drvdata(rtd->card); |
55 | struct graph_dai_props *dai_props = graph_priv_to_props(priv, rtd->num); | 70 | struct graph_dai_props *dai_props = graph_priv_to_props(priv, rtd->num); |
56 | 71 | ||
57 | asoc_simple_card_clk_disable(&dai_props->dai); | 72 | asoc_simple_card_clk_disable(dai_props->cpu_dai); |
73 | |||
74 | asoc_simple_card_clk_disable(dai_props->codec_dai); | ||
58 | } | 75 | } |
59 | 76 | ||
60 | static const struct snd_soc_ops asoc_graph_card_ops = { | 77 | static const struct snd_soc_ops asoc_graph_card_ops = { |
@@ -65,39 +82,49 @@ static const struct snd_soc_ops asoc_graph_card_ops = { | |||
65 | static int asoc_graph_card_dai_init(struct snd_soc_pcm_runtime *rtd) | 82 | static int asoc_graph_card_dai_init(struct snd_soc_pcm_runtime *rtd) |
66 | { | 83 | { |
67 | struct graph_card_data *priv = snd_soc_card_get_drvdata(rtd->card); | 84 | struct graph_card_data *priv = snd_soc_card_get_drvdata(rtd->card); |
68 | struct snd_soc_dai *dai; | 85 | struct graph_dai_props *dai_props = graph_priv_to_props(priv, rtd->num); |
69 | struct snd_soc_dai_link *dai_link; | 86 | int ret = 0; |
70 | struct graph_dai_props *dai_props; | ||
71 | int num = rtd->num; | ||
72 | 87 | ||
73 | dai_link = graph_priv_to_link(priv, num); | 88 | ret = asoc_simple_card_init_dai(rtd->codec_dai, |
74 | dai_props = graph_priv_to_props(priv, num); | 89 | dai_props->codec_dai); |
75 | dai = dai_link->dynamic ? | 90 | if (ret < 0) |
76 | rtd->cpu_dai : | 91 | return ret; |
77 | rtd->codec_dai; | ||
78 | 92 | ||
79 | return asoc_simple_card_init_dai(dai, &dai_props->dai); | 93 | ret = asoc_simple_card_init_dai(rtd->cpu_dai, |
94 | dai_props->cpu_dai); | ||
95 | if (ret < 0) | ||
96 | return ret; | ||
97 | |||
98 | return 0; | ||
80 | } | 99 | } |
81 | 100 | ||
82 | static int asoc_graph_card_be_hw_params_fixup(struct snd_soc_pcm_runtime *rtd, | 101 | static int asoc_graph_card_be_hw_params_fixup(struct snd_soc_pcm_runtime *rtd, |
83 | struct snd_pcm_hw_params *params) | 102 | struct snd_pcm_hw_params *params) |
84 | { | 103 | { |
85 | struct graph_card_data *priv = snd_soc_card_get_drvdata(rtd->card); | 104 | struct graph_card_data *priv = snd_soc_card_get_drvdata(rtd->card); |
105 | struct graph_dai_props *dai_props = graph_priv_to_props(priv, rtd->num); | ||
106 | |||
107 | asoc_simple_card_convert_fixup(&dai_props->adata, params); | ||
86 | 108 | ||
109 | /* overwrite by top level adata if exist */ | ||
87 | asoc_simple_card_convert_fixup(&priv->adata, params); | 110 | asoc_simple_card_convert_fixup(&priv->adata, params); |
88 | 111 | ||
89 | return 0; | 112 | return 0; |
90 | } | 113 | } |
91 | 114 | ||
92 | static int asoc_graph_card_dai_link_of(struct device_node *ep, | 115 | static int asoc_graph_card_dai_link_of(struct device_node *cpu_ep, |
116 | struct device_node *codec_ep, | ||
93 | struct graph_card_data *priv, | 117 | struct graph_card_data *priv, |
94 | unsigned int daifmt, | 118 | int *dai_idx, int link_idx, |
95 | int idx, int is_fe) | 119 | int *conf_idx, int is_fe) |
96 | { | 120 | { |
97 | struct device *dev = graph_priv_to_dev(priv); | 121 | struct device *dev = graph_priv_to_dev(priv); |
98 | struct snd_soc_dai_link *dai_link = graph_priv_to_link(priv, idx); | 122 | struct snd_soc_dai_link *dai_link = graph_priv_to_link(priv, link_idx); |
99 | struct graph_dai_props *dai_props = graph_priv_to_props(priv, idx); | 123 | struct graph_dai_props *dai_props = graph_priv_to_props(priv, link_idx); |
100 | struct snd_soc_card *card = graph_priv_to_card(priv); | 124 | struct snd_soc_card *card = graph_priv_to_card(priv); |
125 | struct device_node *ep = is_fe ? cpu_ep : codec_ep; | ||
126 | struct device_node *node = of_graph_get_port_parent(ep); | ||
127 | struct asoc_simple_dai *dai; | ||
101 | int ret; | 128 | int ret; |
102 | 129 | ||
103 | if (is_fe) { | 130 | if (is_fe) { |
@@ -113,11 +140,14 @@ static int asoc_graph_card_dai_link_of(struct device_node *ep, | |||
113 | dai_link->dynamic = 1; | 140 | dai_link->dynamic = 1; |
114 | dai_link->dpcm_merged_format = 1; | 141 | dai_link->dpcm_merged_format = 1; |
115 | 142 | ||
143 | dai = | ||
144 | dai_props->cpu_dai = &priv->dais[(*dai_idx)++]; | ||
145 | |||
116 | ret = asoc_simple_card_parse_graph_cpu(ep, dai_link); | 146 | ret = asoc_simple_card_parse_graph_cpu(ep, dai_link); |
117 | if (ret) | 147 | if (ret) |
118 | return ret; | 148 | return ret; |
119 | 149 | ||
120 | ret = asoc_simple_card_parse_clk_cpu(dev, ep, dai_link, &dai_props->dai); | 150 | ret = asoc_simple_card_parse_clk_cpu(dev, ep, dai_link, dai); |
121 | if (ret < 0) | 151 | if (ret < 0) |
122 | return ret; | 152 | return ret; |
123 | 153 | ||
@@ -131,6 +161,8 @@ static int asoc_graph_card_dai_link_of(struct device_node *ep, | |||
131 | asoc_simple_card_canonicalize_cpu(dai_link, | 161 | asoc_simple_card_canonicalize_cpu(dai_link, |
132 | of_graph_get_endpoint_count(dai_link->cpu_of_node) == 1); | 162 | of_graph_get_endpoint_count(dai_link->cpu_of_node) == 1); |
133 | } else { | 163 | } else { |
164 | struct snd_soc_codec_conf *cconf; | ||
165 | |||
134 | /* FE is dummy */ | 166 | /* FE is dummy */ |
135 | dai_link->cpu_of_node = NULL; | 167 | dai_link->cpu_of_node = NULL; |
136 | dai_link->cpu_dai_name = "snd-soc-dummy-dai"; | 168 | dai_link->cpu_dai_name = "snd-soc-dummy-dai"; |
@@ -140,11 +172,17 @@ static int asoc_graph_card_dai_link_of(struct device_node *ep, | |||
140 | dai_link->no_pcm = 1; | 172 | dai_link->no_pcm = 1; |
141 | dai_link->be_hw_params_fixup = asoc_graph_card_be_hw_params_fixup; | 173 | dai_link->be_hw_params_fixup = asoc_graph_card_be_hw_params_fixup; |
142 | 174 | ||
175 | dai = | ||
176 | dai_props->codec_dai = &priv->dais[(*dai_idx)++]; | ||
177 | |||
178 | cconf = | ||
179 | dai_props->codec_conf = &priv->codec_conf[(*conf_idx)++]; | ||
180 | |||
143 | ret = asoc_simple_card_parse_graph_codec(ep, dai_link); | 181 | ret = asoc_simple_card_parse_graph_codec(ep, dai_link); |
144 | if (ret < 0) | 182 | if (ret < 0) |
145 | return ret; | 183 | return ret; |
146 | 184 | ||
147 | ret = asoc_simple_card_parse_clk_codec(dev, ep, dai_link, &dai_props->dai); | 185 | ret = asoc_simple_card_parse_clk_codec(dev, ep, dai_link, dai); |
148 | if (ret < 0) | 186 | if (ret < 0) |
149 | return ret; | 187 | return ret; |
150 | 188 | ||
@@ -154,13 +192,20 @@ static int asoc_graph_card_dai_link_of(struct device_node *ep, | |||
154 | if (ret < 0) | 192 | if (ret < 0) |
155 | return ret; | 193 | return ret; |
156 | 194 | ||
157 | snd_soc_of_parse_audio_prefix(card, | 195 | /* check "prefix" from top node */ |
158 | &priv->codec_conf, | 196 | snd_soc_of_parse_audio_prefix(card, cconf, |
159 | dai_link->codecs->of_node, | 197 | dai_link->codecs->of_node, |
160 | "prefix"); | 198 | "prefix"); |
199 | /* check "prefix" from each node if top doesn't have */ | ||
200 | if (!cconf->of_node) | ||
201 | snd_soc_of_parse_node_prefix(node, cconf, | ||
202 | dai_link->codecs->of_node, | ||
203 | PREFIX "prefix"); | ||
161 | } | 204 | } |
162 | 205 | ||
163 | ret = asoc_simple_card_of_parse_tdm(ep, &dai_props->dai); | 206 | asoc_simple_card_parse_convert(dev, node, PREFIX, &dai_props->adata); |
207 | |||
208 | ret = asoc_simple_card_of_parse_tdm(ep, dai); | ||
164 | if (ret) | 209 | if (ret) |
165 | return ret; | 210 | return ret; |
166 | 211 | ||
@@ -168,7 +213,11 @@ static int asoc_graph_card_dai_link_of(struct device_node *ep, | |||
168 | if (ret < 0) | 213 | if (ret < 0) |
169 | return ret; | 214 | return ret; |
170 | 215 | ||
171 | dai_link->dai_fmt = daifmt; | 216 | ret = asoc_simple_card_parse_daifmt(dev, cpu_ep, codec_ep, |
217 | NULL, &dai_link->dai_fmt); | ||
218 | if (ret < 0) | ||
219 | return ret; | ||
220 | |||
172 | dai_link->dpcm_playback = 1; | 221 | dai_link->dpcm_playback = 1; |
173 | dai_link->dpcm_capture = 1; | 222 | dai_link->dpcm_capture = 1; |
174 | dai_link->ops = &asoc_graph_card_ops; | 223 | dai_link->ops = &asoc_graph_card_ops; |
@@ -186,11 +235,9 @@ static int asoc_graph_card_parse_of(struct graph_card_data *priv) | |||
186 | struct device_node *cpu_port; | 235 | struct device_node *cpu_port; |
187 | struct device_node *cpu_ep; | 236 | struct device_node *cpu_ep; |
188 | struct device_node *codec_ep; | 237 | struct device_node *codec_ep; |
189 | struct device_node *rcpu_ep; | ||
190 | struct device_node *codec_port; | 238 | struct device_node *codec_port; |
191 | struct device_node *codec_port_old; | 239 | struct device_node *codec_port_old; |
192 | unsigned int daifmt = 0; | 240 | int dai_idx, link_idx, conf_idx, ret; |
193 | int dai_idx, ret; | ||
194 | int rc, codec; | 241 | int rc, codec; |
195 | 242 | ||
196 | if (!node) | 243 | if (!node) |
@@ -201,47 +248,20 @@ static int asoc_graph_card_parse_of(struct graph_card_data *priv) | |||
201 | * see simple-card | 248 | * see simple-card |
202 | */ | 249 | */ |
203 | 250 | ||
204 | ret = asoc_simple_card_of_parse_routing(card, NULL, 0); | 251 | ret = asoc_simple_card_of_parse_routing(card, NULL); |
205 | if (ret < 0) | 252 | if (ret < 0) |
206 | return ret; | 253 | return ret; |
207 | 254 | ||
208 | asoc_simple_card_parse_convert(dev, NULL, &priv->adata); | 255 | asoc_simple_card_parse_convert(dev, node, NULL, &priv->adata); |
209 | 256 | ||
210 | /* | 257 | /* |
211 | * it supports multi CPU, single CODEC only here | 258 | * it supports multi CPU, single CODEC only here |
212 | * see asoc_graph_get_dais_count | 259 | * see asoc_graph_get_dais_count |
213 | */ | 260 | */ |
214 | 261 | ||
215 | /* find 1st codec */ | 262 | link_idx = 0; |
216 | of_for_each_phandle(&it, rc, node, "dais", NULL, 0) { | ||
217 | cpu_port = it.node; | ||
218 | cpu_ep = of_get_next_child(cpu_port, NULL); | ||
219 | codec_ep = of_graph_get_remote_endpoint(cpu_ep); | ||
220 | rcpu_ep = of_graph_get_remote_endpoint(codec_ep); | ||
221 | |||
222 | of_node_put(cpu_ep); | ||
223 | of_node_put(codec_ep); | ||
224 | of_node_put(rcpu_ep); | ||
225 | |||
226 | if (!codec_ep) | ||
227 | continue; | ||
228 | |||
229 | if (rcpu_ep != cpu_ep) { | ||
230 | dev_err(dev, "remote-endpoint missmatch (%s/%s/%s)\n", | ||
231 | cpu_ep->name, codec_ep->name, rcpu_ep->name); | ||
232 | ret = -EINVAL; | ||
233 | goto parse_of_err; | ||
234 | } | ||
235 | |||
236 | ret = asoc_simple_card_parse_daifmt(dev, cpu_ep, codec_ep, | ||
237 | NULL, &daifmt); | ||
238 | if (ret < 0) { | ||
239 | of_node_put(cpu_port); | ||
240 | goto parse_of_err; | ||
241 | } | ||
242 | } | ||
243 | |||
244 | dai_idx = 0; | 263 | dai_idx = 0; |
264 | conf_idx = 0; | ||
245 | codec_port_old = NULL; | 265 | codec_port_old = NULL; |
246 | for (codec = 0; codec < 2; codec++) { | 266 | for (codec = 0; codec < 2; codec++) { |
247 | /* | 267 | /* |
@@ -257,31 +277,23 @@ static int asoc_graph_card_parse_of(struct graph_card_data *priv) | |||
257 | 277 | ||
258 | of_node_put(cpu_ep); | 278 | of_node_put(cpu_ep); |
259 | of_node_put(codec_ep); | 279 | of_node_put(codec_ep); |
280 | of_node_put(cpu_port); | ||
260 | of_node_put(codec_port); | 281 | of_node_put(codec_port); |
282 | it.node = NULL; | ||
261 | 283 | ||
262 | if (codec) { | 284 | if (codec) { |
263 | if (!codec_port) | ||
264 | continue; | ||
265 | |||
266 | if (codec_port_old == codec_port) | 285 | if (codec_port_old == codec_port) |
267 | continue; | 286 | continue; |
268 | 287 | ||
269 | codec_port_old = codec_port; | 288 | codec_port_old = codec_port; |
270 | |||
271 | /* Back-End (= Codec) */ | ||
272 | ret = asoc_graph_card_dai_link_of(codec_ep, priv, daifmt, dai_idx++, 0); | ||
273 | if (ret < 0) { | ||
274 | of_node_put(cpu_port); | ||
275 | goto parse_of_err; | ||
276 | } | ||
277 | } else { | ||
278 | /* Front-End (= CPU) */ | ||
279 | ret = asoc_graph_card_dai_link_of(cpu_ep, priv, daifmt, dai_idx++, 1); | ||
280 | if (ret < 0) { | ||
281 | of_node_put(cpu_port); | ||
282 | goto parse_of_err; | ||
283 | } | ||
284 | } | 289 | } |
290 | |||
291 | ret = asoc_graph_card_dai_link_of(cpu_ep, codec_ep, | ||
292 | priv, &dai_idx, | ||
293 | link_idx++, &conf_idx, | ||
294 | !codec); | ||
295 | if (ret < 0) | ||
296 | goto parse_of_err; | ||
285 | } | 297 | } |
286 | } | 298 | } |
287 | 299 | ||
@@ -289,13 +301,24 @@ static int asoc_graph_card_parse_of(struct graph_card_data *priv) | |||
289 | if (ret) | 301 | if (ret) |
290 | goto parse_of_err; | 302 | goto parse_of_err; |
291 | 303 | ||
304 | if ((card->num_links != link_idx) || | ||
305 | (card->num_configs != conf_idx)) { | ||
306 | dev_err(dev, "dai_link or codec_config wrong (%d/%d, %d/%d)\n", | ||
307 | card->num_links, link_idx, card->num_configs, conf_idx); | ||
308 | ret = -EINVAL; | ||
309 | goto parse_of_err; | ||
310 | } | ||
311 | |||
292 | ret = 0; | 312 | ret = 0; |
293 | 313 | ||
294 | parse_of_err: | 314 | parse_of_err: |
295 | return ret; | 315 | return ret; |
296 | } | 316 | } |
297 | 317 | ||
298 | static int asoc_graph_get_dais_count(struct device *dev) | 318 | static void asoc_graph_get_dais_count(struct device *dev, |
319 | int *link_num, | ||
320 | int *dais_num, | ||
321 | int *ccnf_num) | ||
299 | { | 322 | { |
300 | struct of_phandle_iterator it; | 323 | struct of_phandle_iterator it; |
301 | struct device_node *node = dev->of_node; | 324 | struct device_node *node = dev->of_node; |
@@ -304,10 +327,48 @@ static int asoc_graph_get_dais_count(struct device *dev) | |||
304 | struct device_node *codec_ep; | 327 | struct device_node *codec_ep; |
305 | struct device_node *codec_port; | 328 | struct device_node *codec_port; |
306 | struct device_node *codec_port_old; | 329 | struct device_node *codec_port_old; |
307 | int count = 0; | 330 | struct device_node *codec_port_old2; |
308 | int rc; | 331 | int rc; |
309 | 332 | ||
333 | /* | ||
334 | * link_num : number of links. | ||
335 | * CPU-Codec / CPU-dummy / dummy-Codec | ||
336 | * dais_num : number of DAIs | ||
337 | * ccnf_num : number of codec_conf | ||
338 | * same number for dummy-Codec | ||
339 | * | ||
340 | * ex1) | ||
341 | * CPU0 --- Codec0 link : 5 | ||
342 | * CPU1 --- Codec1 dais : 7 | ||
343 | * CPU2 -/ ccnf : 1 | ||
344 | * CPU3 --- Codec2 | ||
345 | * | ||
346 | * => 5 links = 2xCPU-Codec + 2xCPU-dummy + 1xdummy-Codec | ||
347 | * => 7 DAIs = 4xCPU + 3xCodec | ||
348 | * => 1 ccnf = 1xdummy-Codec | ||
349 | * | ||
350 | * ex2) | ||
351 | * CPU0 --- Codec0 link : 5 | ||
352 | * CPU1 --- Codec1 dais : 6 | ||
353 | * CPU2 -/ ccnf : 1 | ||
354 | * CPU3 -/ | ||
355 | * | ||
356 | * => 5 links = 1xCPU-Codec + 3xCPU-dummy + 1xdummy-Codec | ||
357 | * => 6 DAIs = 4xCPU + 2xCodec | ||
358 | * => 1 ccnf = 1xdummy-Codec | ||
359 | * | ||
360 | * ex3) | ||
361 | * CPU0 --- Codec0 link : 6 | ||
362 | * CPU1 -/ dais : 6 | ||
363 | * CPU2 --- Codec1 ccnf : 2 | ||
364 | * CPU3 -/ | ||
365 | * | ||
366 | * => 6 links = 0xCPU-Codec + 4xCPU-dummy + 2xdummy-Codec | ||
367 | * => 6 DAIs = 4xCPU + 2xCodec | ||
368 | * => 2 ccnf = 2xdummy-Codec | ||
369 | */ | ||
310 | codec_port_old = NULL; | 370 | codec_port_old = NULL; |
371 | codec_port_old2 = NULL; | ||
311 | of_for_each_phandle(&it, rc, node, "dais", NULL, 0) { | 372 | of_for_each_phandle(&it, rc, node, "dais", NULL, 0) { |
312 | cpu_port = it.node; | 373 | cpu_port = it.node; |
313 | cpu_ep = of_get_next_child(cpu_port, NULL); | 374 | cpu_ep = of_get_next_child(cpu_port, NULL); |
@@ -318,20 +379,22 @@ static int asoc_graph_get_dais_count(struct device *dev) | |||
318 | of_node_put(codec_ep); | 379 | of_node_put(codec_ep); |
319 | of_node_put(codec_port); | 380 | of_node_put(codec_port); |
320 | 381 | ||
321 | if (cpu_ep) | 382 | (*link_num)++; |
322 | count++; | 383 | (*dais_num)++; |
323 | 384 | ||
324 | if (!codec_port) | 385 | if (codec_port_old == codec_port) { |
325 | continue; | 386 | if (codec_port_old2 != codec_port_old) { |
387 | (*link_num)++; | ||
388 | (*ccnf_num)++; | ||
389 | } | ||
326 | 390 | ||
327 | if (codec_port_old == codec_port) | 391 | codec_port_old2 = codec_port_old; |
328 | continue; | 392 | continue; |
393 | } | ||
329 | 394 | ||
330 | count++; | 395 | (*dais_num)++; |
331 | codec_port_old = codec_port; | 396 | codec_port_old = codec_port; |
332 | } | 397 | } |
333 | |||
334 | return count; | ||
335 | } | 398 | } |
336 | 399 | ||
337 | static int asoc_graph_card_probe(struct platform_device *pdev) | 400 | static int asoc_graph_card_probe(struct platform_device *pdev) |
@@ -339,22 +402,27 @@ static int asoc_graph_card_probe(struct platform_device *pdev) | |||
339 | struct graph_card_data *priv; | 402 | struct graph_card_data *priv; |
340 | struct snd_soc_dai_link *dai_link; | 403 | struct snd_soc_dai_link *dai_link; |
341 | struct graph_dai_props *dai_props; | 404 | struct graph_dai_props *dai_props; |
405 | struct asoc_simple_dai *dais; | ||
342 | struct device *dev = &pdev->dev; | 406 | struct device *dev = &pdev->dev; |
343 | struct snd_soc_card *card; | 407 | struct snd_soc_card *card; |
344 | int num, ret, i; | 408 | struct snd_soc_codec_conf *cconf; |
409 | int lnum = 0, dnum = 0, cnum = 0; | ||
410 | int ret, i; | ||
345 | 411 | ||
346 | /* Allocate the private data and the DAI link array */ | 412 | /* Allocate the private data and the DAI link array */ |
347 | priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL); | 413 | priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL); |
348 | if (!priv) | 414 | if (!priv) |
349 | return -ENOMEM; | 415 | return -ENOMEM; |
350 | 416 | ||
351 | num = asoc_graph_get_dais_count(dev); | 417 | asoc_graph_get_dais_count(dev, &lnum, &dnum, &cnum); |
352 | if (num == 0) | 418 | if (!lnum || !dnum) |
353 | return -EINVAL; | 419 | return -EINVAL; |
354 | 420 | ||
355 | dai_props = devm_kcalloc(dev, num, sizeof(*dai_props), GFP_KERNEL); | 421 | dai_props = devm_kcalloc(dev, lnum, sizeof(*dai_props), GFP_KERNEL); |
356 | dai_link = devm_kcalloc(dev, num, sizeof(*dai_link), GFP_KERNEL); | 422 | dai_link = devm_kcalloc(dev, lnum, sizeof(*dai_link), GFP_KERNEL); |
357 | if (!dai_props || !dai_link) | 423 | dais = devm_kcalloc(dev, dnum, sizeof(*dais), GFP_KERNEL); |
424 | cconf = devm_kcalloc(dev, cnum, sizeof(*cconf), GFP_KERNEL); | ||
425 | if (!dai_props || !dai_link || !dais) | ||
358 | return -ENOMEM; | 426 | return -ENOMEM; |
359 | 427 | ||
360 | /* | 428 | /* |
@@ -363,7 +431,7 @@ static int asoc_graph_card_probe(struct platform_device *pdev) | |||
363 | * see | 431 | * see |
364 | * soc-core.c :: snd_soc_init_multicodec() | 432 | * soc-core.c :: snd_soc_init_multicodec() |
365 | */ | 433 | */ |
366 | for (i = 0; i < num; i++) { | 434 | for (i = 0; i < lnum; i++) { |
367 | dai_link[i].codecs = &dai_props[i].codecs; | 435 | dai_link[i].codecs = &dai_props[i].codecs; |
368 | dai_link[i].num_codecs = 1; | 436 | dai_link[i].num_codecs = 1; |
369 | dai_link[i].platform = &dai_props[i].platform; | 437 | dai_link[i].platform = &dai_props[i].platform; |
@@ -371,15 +439,17 @@ static int asoc_graph_card_probe(struct platform_device *pdev) | |||
371 | 439 | ||
372 | priv->dai_props = dai_props; | 440 | priv->dai_props = dai_props; |
373 | priv->dai_link = dai_link; | 441 | priv->dai_link = dai_link; |
442 | priv->dais = dais; | ||
443 | priv->codec_conf = cconf; | ||
374 | 444 | ||
375 | /* Init snd_soc_card */ | 445 | /* Init snd_soc_card */ |
376 | card = graph_priv_to_card(priv); | 446 | card = graph_priv_to_card(priv); |
377 | card->owner = THIS_MODULE; | 447 | card->owner = THIS_MODULE; |
378 | card->dev = dev; | 448 | card->dev = dev; |
379 | card->dai_link = priv->dai_link; | 449 | card->dai_link = priv->dai_link; |
380 | card->num_links = num; | 450 | card->num_links = lnum; |
381 | card->codec_conf = &priv->codec_conf; | 451 | card->codec_conf = cconf; |
382 | card->num_configs = 1; | 452 | card->num_configs = cnum; |
383 | 453 | ||
384 | ret = asoc_graph_card_parse_of(priv); | 454 | ret = asoc_graph_card_parse_of(priv); |
385 | if (ret < 0) { | 455 | if (ret < 0) { |
diff --git a/sound/soc/generic/simple-card-utils.c b/sound/soc/generic/simple-card-utils.c index f34cc6cddfa2..b807a47515eb 100644 --- a/sound/soc/generic/simple-card-utils.c +++ b/sound/soc/generic/simple-card-utils.c | |||
@@ -32,10 +32,11 @@ void asoc_simple_card_convert_fixup(struct asoc_simple_card_data *data, | |||
32 | } | 32 | } |
33 | EXPORT_SYMBOL_GPL(asoc_simple_card_convert_fixup); | 33 | EXPORT_SYMBOL_GPL(asoc_simple_card_convert_fixup); |
34 | 34 | ||
35 | void asoc_simple_card_parse_convert(struct device *dev, char *prefix, | 35 | void asoc_simple_card_parse_convert(struct device *dev, |
36 | struct device_node *np, | ||
37 | char *prefix, | ||
36 | struct asoc_simple_card_data *data) | 38 | struct asoc_simple_card_data *data) |
37 | { | 39 | { |
38 | struct device_node *np = dev->of_node; | ||
39 | char prop[128]; | 40 | char prop[128]; |
40 | 41 | ||
41 | if (!prefix) | 42 | if (!prefix) |
@@ -151,21 +152,19 @@ int asoc_simple_card_parse_card_name(struct snd_soc_card *card, | |||
151 | } | 152 | } |
152 | EXPORT_SYMBOL_GPL(asoc_simple_card_parse_card_name); | 153 | EXPORT_SYMBOL_GPL(asoc_simple_card_parse_card_name); |
153 | 154 | ||
154 | static void asoc_simple_card_clk_register(struct asoc_simple_dai *dai, | ||
155 | struct clk *clk) | ||
156 | { | ||
157 | dai->clk = clk; | ||
158 | } | ||
159 | |||
160 | int asoc_simple_card_clk_enable(struct asoc_simple_dai *dai) | 155 | int asoc_simple_card_clk_enable(struct asoc_simple_dai *dai) |
161 | { | 156 | { |
162 | return clk_prepare_enable(dai->clk); | 157 | if (dai) |
158 | return clk_prepare_enable(dai->clk); | ||
159 | |||
160 | return 0; | ||
163 | } | 161 | } |
164 | EXPORT_SYMBOL_GPL(asoc_simple_card_clk_enable); | 162 | EXPORT_SYMBOL_GPL(asoc_simple_card_clk_enable); |
165 | 163 | ||
166 | void asoc_simple_card_clk_disable(struct asoc_simple_dai *dai) | 164 | void asoc_simple_card_clk_disable(struct asoc_simple_dai *dai) |
167 | { | 165 | { |
168 | clk_disable_unprepare(dai->clk); | 166 | if (dai) |
167 | clk_disable_unprepare(dai->clk); | ||
169 | } | 168 | } |
170 | EXPORT_SYMBOL_GPL(asoc_simple_card_clk_disable); | 169 | EXPORT_SYMBOL_GPL(asoc_simple_card_clk_disable); |
171 | 170 | ||
@@ -200,7 +199,7 @@ int asoc_simple_card_parse_clk(struct device *dev, | |||
200 | if (!IS_ERR(clk)) { | 199 | if (!IS_ERR(clk)) { |
201 | simple_dai->sysclk = clk_get_rate(clk); | 200 | simple_dai->sysclk = clk_get_rate(clk); |
202 | 201 | ||
203 | asoc_simple_card_clk_register(simple_dai, clk); | 202 | simple_dai->clk = clk; |
204 | } else if (!of_property_read_u32(node, "system-clock-frequency", &val)) { | 203 | } else if (!of_property_read_u32(node, "system-clock-frequency", &val)) { |
205 | simple_dai->sysclk = val; | 204 | simple_dai->sysclk = val; |
206 | } else { | 205 | } else { |
@@ -272,13 +271,24 @@ static int asoc_simple_card_get_dai_id(struct device_node *ep) | |||
272 | { | 271 | { |
273 | struct device_node *node; | 272 | struct device_node *node; |
274 | struct device_node *endpoint; | 273 | struct device_node *endpoint; |
274 | struct of_endpoint info; | ||
275 | int i, id; | 275 | int i, id; |
276 | int ret; | 276 | int ret; |
277 | 277 | ||
278 | /* use driver specified DAI ID if exist */ | ||
278 | ret = snd_soc_get_dai_id(ep); | 279 | ret = snd_soc_get_dai_id(ep); |
279 | if (ret != -ENOTSUPP) | 280 | if (ret != -ENOTSUPP) |
280 | return ret; | 281 | return ret; |
281 | 282 | ||
283 | /* use endpoint/port reg if exist */ | ||
284 | ret = of_graph_parse_endpoint(ep, &info); | ||
285 | if (ret == 0) { | ||
286 | if (info.id) | ||
287 | return info.id; | ||
288 | if (info.port) | ||
289 | return info.port; | ||
290 | } | ||
291 | |||
282 | node = of_graph_get_port_parent(ep); | 292 | node = of_graph_get_port_parent(ep); |
283 | 293 | ||
284 | /* | 294 | /* |
@@ -348,6 +358,9 @@ int asoc_simple_card_init_dai(struct snd_soc_dai *dai, | |||
348 | { | 358 | { |
349 | int ret; | 359 | int ret; |
350 | 360 | ||
361 | if (!simple_dai) | ||
362 | return 0; | ||
363 | |||
351 | if (simple_dai->sysclk) { | 364 | if (simple_dai->sysclk) { |
352 | ret = snd_soc_dai_set_sysclk(dai, 0, simple_dai->sysclk, | 365 | ret = snd_soc_dai_set_sysclk(dai, 0, simple_dai->sysclk, |
353 | simple_dai->clk_direction); | 366 | simple_dai->clk_direction); |
@@ -415,8 +428,7 @@ int asoc_simple_card_clean_reference(struct snd_soc_card *card) | |||
415 | EXPORT_SYMBOL_GPL(asoc_simple_card_clean_reference); | 428 | EXPORT_SYMBOL_GPL(asoc_simple_card_clean_reference); |
416 | 429 | ||
417 | int asoc_simple_card_of_parse_routing(struct snd_soc_card *card, | 430 | int asoc_simple_card_of_parse_routing(struct snd_soc_card *card, |
418 | char *prefix, | 431 | char *prefix) |
419 | int optional) | ||
420 | { | 432 | { |
421 | struct device_node *node = card->dev->of_node; | 433 | struct device_node *node = card->dev->of_node; |
422 | char prop[128]; | 434 | char prop[128]; |
@@ -426,11 +438,8 @@ int asoc_simple_card_of_parse_routing(struct snd_soc_card *card, | |||
426 | 438 | ||
427 | snprintf(prop, sizeof(prop), "%s%s", prefix, "routing"); | 439 | snprintf(prop, sizeof(prop), "%s%s", prefix, "routing"); |
428 | 440 | ||
429 | if (!of_property_read_bool(node, prop)) { | 441 | if (!of_property_read_bool(node, prop)) |
430 | if (optional) | 442 | return 0; |
431 | return 0; | ||
432 | return -EINVAL; | ||
433 | } | ||
434 | 443 | ||
435 | return snd_soc_of_parse_audio_routing(card, prop); | 444 | return snd_soc_of_parse_audio_routing(card, prop); |
436 | } | 445 | } |
diff --git a/sound/soc/generic/simple-card.c b/sound/soc/generic/simple-card.c index 5a3f59aa4ba5..37e001cf9cd1 100644 --- a/sound/soc/generic/simple-card.c +++ b/sound/soc/generic/simple-card.c | |||
@@ -18,16 +18,19 @@ | |||
18 | struct simple_card_data { | 18 | struct simple_card_data { |
19 | struct snd_soc_card snd_card; | 19 | struct snd_soc_card snd_card; |
20 | struct simple_dai_props { | 20 | struct simple_dai_props { |
21 | struct asoc_simple_dai cpu_dai; | 21 | struct asoc_simple_dai *cpu_dai; |
22 | struct asoc_simple_dai codec_dai; | 22 | struct asoc_simple_dai *codec_dai; |
23 | struct snd_soc_dai_link_component codecs; /* single codec */ | 23 | struct snd_soc_dai_link_component codecs; /* single codec */ |
24 | struct snd_soc_dai_link_component platform; | 24 | struct snd_soc_dai_link_component platform; |
25 | struct asoc_simple_card_data adata; | ||
26 | struct snd_soc_codec_conf *codec_conf; | ||
25 | unsigned int mclk_fs; | 27 | unsigned int mclk_fs; |
26 | } *dai_props; | 28 | } *dai_props; |
27 | unsigned int mclk_fs; | ||
28 | struct asoc_simple_jack hp_jack; | 29 | struct asoc_simple_jack hp_jack; |
29 | struct asoc_simple_jack mic_jack; | 30 | struct asoc_simple_jack mic_jack; |
30 | struct snd_soc_dai_link *dai_link; | 31 | struct snd_soc_dai_link *dai_link; |
32 | struct asoc_simple_dai *dais; | ||
33 | struct snd_soc_codec_conf *codec_conf; | ||
31 | }; | 34 | }; |
32 | 35 | ||
33 | #define simple_priv_to_card(priv) (&(priv)->snd_card) | 36 | #define simple_priv_to_card(priv) (&(priv)->snd_card) |
@@ -47,13 +50,13 @@ static int asoc_simple_card_startup(struct snd_pcm_substream *substream) | |||
47 | simple_priv_to_props(priv, rtd->num); | 50 | simple_priv_to_props(priv, rtd->num); |
48 | int ret; | 51 | int ret; |
49 | 52 | ||
50 | ret = asoc_simple_card_clk_enable(&dai_props->cpu_dai); | 53 | ret = asoc_simple_card_clk_enable(dai_props->cpu_dai); |
51 | if (ret) | 54 | if (ret) |
52 | return ret; | 55 | return ret; |
53 | 56 | ||
54 | ret = asoc_simple_card_clk_enable(&dai_props->codec_dai); | 57 | ret = asoc_simple_card_clk_enable(dai_props->codec_dai); |
55 | if (ret) | 58 | if (ret) |
56 | asoc_simple_card_clk_disable(&dai_props->cpu_dai); | 59 | asoc_simple_card_clk_disable(dai_props->cpu_dai); |
57 | 60 | ||
58 | return ret; | 61 | return ret; |
59 | } | 62 | } |
@@ -65,14 +68,17 @@ static void asoc_simple_card_shutdown(struct snd_pcm_substream *substream) | |||
65 | struct simple_dai_props *dai_props = | 68 | struct simple_dai_props *dai_props = |
66 | simple_priv_to_props(priv, rtd->num); | 69 | simple_priv_to_props(priv, rtd->num); |
67 | 70 | ||
68 | asoc_simple_card_clk_disable(&dai_props->cpu_dai); | 71 | asoc_simple_card_clk_disable(dai_props->cpu_dai); |
69 | 72 | ||
70 | asoc_simple_card_clk_disable(&dai_props->codec_dai); | 73 | asoc_simple_card_clk_disable(dai_props->codec_dai); |
71 | } | 74 | } |
72 | 75 | ||
73 | static int asoc_simple_set_clk_rate(struct asoc_simple_dai *simple_dai, | 76 | static int asoc_simple_set_clk_rate(struct asoc_simple_dai *simple_dai, |
74 | unsigned long rate) | 77 | unsigned long rate) |
75 | { | 78 | { |
79 | if (!simple_dai) | ||
80 | return 0; | ||
81 | |||
76 | if (!simple_dai->clk) | 82 | if (!simple_dai->clk) |
77 | return 0; | 83 | return 0; |
78 | 84 | ||
@@ -94,19 +100,17 @@ static int asoc_simple_card_hw_params(struct snd_pcm_substream *substream, | |||
94 | unsigned int mclk, mclk_fs = 0; | 100 | unsigned int mclk, mclk_fs = 0; |
95 | int ret = 0; | 101 | int ret = 0; |
96 | 102 | ||
97 | if (priv->mclk_fs) | 103 | if (dai_props->mclk_fs) |
98 | mclk_fs = priv->mclk_fs; | ||
99 | else if (dai_props->mclk_fs) | ||
100 | mclk_fs = dai_props->mclk_fs; | 104 | mclk_fs = dai_props->mclk_fs; |
101 | 105 | ||
102 | if (mclk_fs) { | 106 | if (mclk_fs) { |
103 | mclk = params_rate(params) * mclk_fs; | 107 | mclk = params_rate(params) * mclk_fs; |
104 | 108 | ||
105 | ret = asoc_simple_set_clk_rate(&dai_props->codec_dai, mclk); | 109 | ret = asoc_simple_set_clk_rate(dai_props->codec_dai, mclk); |
106 | if (ret < 0) | 110 | if (ret < 0) |
107 | return ret; | 111 | return ret; |
108 | 112 | ||
109 | ret = asoc_simple_set_clk_rate(&dai_props->cpu_dai, mclk); | 113 | ret = asoc_simple_set_clk_rate(dai_props->cpu_dai, mclk); |
110 | if (ret < 0) | 114 | if (ret < 0) |
111 | return ret; | 115 | return ret; |
112 | 116 | ||
@@ -134,33 +138,169 @@ static const struct snd_soc_ops asoc_simple_card_ops = { | |||
134 | static int asoc_simple_card_dai_init(struct snd_soc_pcm_runtime *rtd) | 138 | static int asoc_simple_card_dai_init(struct snd_soc_pcm_runtime *rtd) |
135 | { | 139 | { |
136 | struct simple_card_data *priv = snd_soc_card_get_drvdata(rtd->card); | 140 | struct simple_card_data *priv = snd_soc_card_get_drvdata(rtd->card); |
137 | struct snd_soc_dai *codec = rtd->codec_dai; | 141 | struct simple_dai_props *dai_props = simple_priv_to_props(priv, rtd->num); |
138 | struct snd_soc_dai *cpu = rtd->cpu_dai; | ||
139 | struct simple_dai_props *dai_props = | ||
140 | simple_priv_to_props(priv, rtd->num); | ||
141 | int ret; | 142 | int ret; |
142 | 143 | ||
143 | ret = asoc_simple_card_init_dai(codec, &dai_props->codec_dai); | 144 | ret = asoc_simple_card_init_dai(rtd->codec_dai, |
145 | dai_props->codec_dai); | ||
144 | if (ret < 0) | 146 | if (ret < 0) |
145 | return ret; | 147 | return ret; |
146 | 148 | ||
147 | ret = asoc_simple_card_init_dai(cpu, &dai_props->cpu_dai); | 149 | ret = asoc_simple_card_init_dai(rtd->cpu_dai, |
150 | dai_props->cpu_dai); | ||
148 | if (ret < 0) | 151 | if (ret < 0) |
149 | return ret; | 152 | return ret; |
150 | 153 | ||
151 | return 0; | 154 | return 0; |
152 | } | 155 | } |
153 | 156 | ||
154 | static int asoc_simple_card_dai_link_of(struct device_node *node, | 157 | static int asoc_simple_card_be_hw_params_fixup(struct snd_soc_pcm_runtime *rtd, |
158 | struct snd_pcm_hw_params *params) | ||
159 | { | ||
160 | struct simple_card_data *priv = snd_soc_card_get_drvdata(rtd->card); | ||
161 | struct simple_dai_props *dai_props = simple_priv_to_props(priv, rtd->num); | ||
162 | |||
163 | asoc_simple_card_convert_fixup(&dai_props->adata, params); | ||
164 | |||
165 | return 0; | ||
166 | } | ||
167 | |||
168 | static int asoc_simple_card_dai_link_of_dpcm(struct device_node *top, | ||
169 | struct device_node *node, | ||
170 | struct device_node *np, | ||
171 | struct device_node *codec, | ||
172 | struct simple_card_data *priv, | ||
173 | int *dai_idx, int link_idx, | ||
174 | int *conf_idx, int is_fe, | ||
175 | bool is_top_level_node) | ||
176 | { | ||
177 | struct device *dev = simple_priv_to_dev(priv); | ||
178 | struct snd_soc_dai_link *dai_link = simple_priv_to_link(priv, link_idx); | ||
179 | struct simple_dai_props *dai_props = simple_priv_to_props(priv, link_idx); | ||
180 | struct asoc_simple_dai *dai; | ||
181 | struct snd_soc_dai_link_component *codecs = dai_link->codecs; | ||
182 | |||
183 | char prop[128]; | ||
184 | char *prefix = ""; | ||
185 | int ret; | ||
186 | |||
187 | /* For single DAI link & old style of DT node */ | ||
188 | if (is_top_level_node) | ||
189 | prefix = PREFIX; | ||
190 | |||
191 | if (is_fe) { | ||
192 | int is_single_links = 0; | ||
193 | |||
194 | /* BE is dummy */ | ||
195 | codecs->of_node = NULL; | ||
196 | codecs->dai_name = "snd-soc-dummy-dai"; | ||
197 | codecs->name = "snd-soc-dummy"; | ||
198 | |||
199 | /* FE settings */ | ||
200 | dai_link->dynamic = 1; | ||
201 | dai_link->dpcm_merged_format = 1; | ||
202 | |||
203 | dai = | ||
204 | dai_props->cpu_dai = &priv->dais[(*dai_idx)++]; | ||
205 | |||
206 | ret = asoc_simple_card_parse_cpu(np, dai_link, DAI, CELL, | ||
207 | &is_single_links); | ||
208 | if (ret) | ||
209 | return ret; | ||
210 | |||
211 | ret = asoc_simple_card_parse_clk_cpu(dev, np, dai_link, dai); | ||
212 | if (ret < 0) | ||
213 | return ret; | ||
214 | |||
215 | ret = asoc_simple_card_set_dailink_name(dev, dai_link, | ||
216 | "fe.%s", | ||
217 | dai_link->cpu_dai_name); | ||
218 | if (ret < 0) | ||
219 | return ret; | ||
220 | |||
221 | asoc_simple_card_canonicalize_cpu(dai_link, is_single_links); | ||
222 | } else { | ||
223 | struct snd_soc_codec_conf *cconf; | ||
224 | |||
225 | /* FE is dummy */ | ||
226 | dai_link->cpu_of_node = NULL; | ||
227 | dai_link->cpu_dai_name = "snd-soc-dummy-dai"; | ||
228 | dai_link->cpu_name = "snd-soc-dummy"; | ||
229 | |||
230 | /* BE settings */ | ||
231 | dai_link->no_pcm = 1; | ||
232 | dai_link->be_hw_params_fixup = asoc_simple_card_be_hw_params_fixup; | ||
233 | |||
234 | dai = | ||
235 | dai_props->codec_dai = &priv->dais[(*dai_idx)++]; | ||
236 | |||
237 | cconf = | ||
238 | dai_props->codec_conf = &priv->codec_conf[(*conf_idx)++]; | ||
239 | |||
240 | ret = asoc_simple_card_parse_codec(np, dai_link, DAI, CELL); | ||
241 | if (ret < 0) | ||
242 | return ret; | ||
243 | |||
244 | ret = asoc_simple_card_parse_clk_codec(dev, np, dai_link, dai); | ||
245 | if (ret < 0) | ||
246 | return ret; | ||
247 | |||
248 | ret = asoc_simple_card_set_dailink_name(dev, dai_link, | ||
249 | "be.%s", | ||
250 | codecs->dai_name); | ||
251 | if (ret < 0) | ||
252 | return ret; | ||
253 | |||
254 | /* check "prefix" from top node */ | ||
255 | snd_soc_of_parse_node_prefix(top, cconf, codecs->of_node, | ||
256 | PREFIX "prefix"); | ||
257 | snd_soc_of_parse_node_prefix(node, cconf, codecs->of_node, | ||
258 | "prefix"); | ||
259 | snd_soc_of_parse_node_prefix(np, cconf, codecs->of_node, | ||
260 | "prefix"); | ||
261 | } | ||
262 | |||
263 | asoc_simple_card_parse_convert(dev, top, PREFIX, &dai_props->adata); | ||
264 | asoc_simple_card_parse_convert(dev, node, prefix, &dai_props->adata); | ||
265 | asoc_simple_card_parse_convert(dev, np, NULL, &dai_props->adata); | ||
266 | |||
267 | ret = asoc_simple_card_of_parse_tdm(np, dai); | ||
268 | if (ret) | ||
269 | return ret; | ||
270 | |||
271 | ret = asoc_simple_card_canonicalize_dailink(dai_link); | ||
272 | if (ret < 0) | ||
273 | return ret; | ||
274 | |||
275 | snprintf(prop, sizeof(prop), "%smclk-fs", prefix); | ||
276 | of_property_read_u32(top, PREFIX "mclk-fs", &dai_props->mclk_fs); | ||
277 | of_property_read_u32(node, prop, &dai_props->mclk_fs); | ||
278 | of_property_read_u32(np, prop, &dai_props->mclk_fs); | ||
279 | |||
280 | ret = asoc_simple_card_parse_daifmt(dev, node, codec, | ||
281 | prefix, &dai_link->dai_fmt); | ||
282 | if (ret < 0) | ||
283 | return ret; | ||
284 | |||
285 | dai_link->dpcm_playback = 1; | ||
286 | dai_link->dpcm_capture = 1; | ||
287 | dai_link->ops = &asoc_simple_card_ops; | ||
288 | dai_link->init = asoc_simple_card_dai_init; | ||
289 | |||
290 | return 0; | ||
291 | } | ||
292 | |||
293 | static int asoc_simple_card_dai_link_of(struct device_node *top, | ||
294 | struct device_node *node, | ||
155 | struct simple_card_data *priv, | 295 | struct simple_card_data *priv, |
156 | int idx, | 296 | int *dai_idx, int link_idx, |
157 | bool is_top_level_node) | 297 | bool is_top_level_node) |
158 | { | 298 | { |
159 | struct device *dev = simple_priv_to_dev(priv); | 299 | struct device *dev = simple_priv_to_dev(priv); |
160 | struct snd_soc_dai_link *dai_link = simple_priv_to_link(priv, idx); | 300 | struct snd_soc_dai_link *dai_link = simple_priv_to_link(priv, link_idx); |
161 | struct simple_dai_props *dai_props = simple_priv_to_props(priv, idx); | 301 | struct simple_dai_props *dai_props = simple_priv_to_props(priv, link_idx); |
162 | struct asoc_simple_dai *cpu_dai = &dai_props->cpu_dai; | 302 | struct asoc_simple_dai *cpu_dai; |
163 | struct asoc_simple_dai *codec_dai = &dai_props->codec_dai; | 303 | struct asoc_simple_dai *codec_dai; |
164 | struct device_node *cpu = NULL; | 304 | struct device_node *cpu = NULL; |
165 | struct device_node *plat = NULL; | 305 | struct device_node *plat = NULL; |
166 | struct device_node *codec = NULL; | 306 | struct device_node *codec = NULL; |
@@ -193,12 +333,21 @@ static int asoc_simple_card_dai_link_of(struct device_node *node, | |||
193 | goto dai_link_of_err; | 333 | goto dai_link_of_err; |
194 | } | 334 | } |
195 | 335 | ||
336 | cpu_dai = | ||
337 | dai_props->cpu_dai = &priv->dais[(*dai_idx)++]; | ||
338 | codec_dai = | ||
339 | dai_props->codec_dai = &priv->dais[(*dai_idx)++]; | ||
340 | |||
196 | ret = asoc_simple_card_parse_daifmt(dev, node, codec, | 341 | ret = asoc_simple_card_parse_daifmt(dev, node, codec, |
197 | prefix, &dai_link->dai_fmt); | 342 | prefix, &dai_link->dai_fmt); |
198 | if (ret < 0) | 343 | if (ret < 0) |
199 | goto dai_link_of_err; | 344 | goto dai_link_of_err; |
200 | 345 | ||
201 | of_property_read_u32(node, "mclk-fs", &dai_props->mclk_fs); | 346 | snprintf(prop, sizeof(prop), "%smclk-fs", prefix); |
347 | of_property_read_u32(top, PREFIX "mclk-fs", &dai_props->mclk_fs); | ||
348 | of_property_read_u32(node, prop, &dai_props->mclk_fs); | ||
349 | of_property_read_u32(cpu, prop, &dai_props->mclk_fs); | ||
350 | of_property_read_u32(codec, prop, &dai_props->mclk_fs); | ||
202 | 351 | ||
203 | ret = asoc_simple_card_parse_cpu(cpu, dai_link, | 352 | ret = asoc_simple_card_parse_cpu(cpu, dai_link, |
204 | DAI, CELL, &single_cpu); | 353 | DAI, CELL, &single_cpu); |
@@ -286,61 +435,148 @@ static int asoc_simple_card_parse_aux_devs(struct device_node *node, | |||
286 | static int asoc_simple_card_parse_of(struct simple_card_data *priv) | 435 | static int asoc_simple_card_parse_of(struct simple_card_data *priv) |
287 | { | 436 | { |
288 | struct device *dev = simple_priv_to_dev(priv); | 437 | struct device *dev = simple_priv_to_dev(priv); |
438 | struct device_node *top = dev->of_node; | ||
289 | struct snd_soc_card *card = simple_priv_to_card(priv); | 439 | struct snd_soc_card *card = simple_priv_to_card(priv); |
290 | struct device_node *dai_link; | 440 | struct device_node *node; |
291 | struct device_node *node = dev->of_node; | 441 | struct device_node *np; |
292 | int ret; | 442 | struct device_node *codec; |
293 | 443 | bool is_fe; | |
294 | if (!node) | 444 | int ret, loop; |
445 | int dai_idx, link_idx, conf_idx; | ||
446 | |||
447 | if (!top) | ||
295 | return -EINVAL; | 448 | return -EINVAL; |
296 | 449 | ||
297 | dai_link = of_get_child_by_name(node, PREFIX "dai-link"); | ||
298 | |||
299 | ret = asoc_simple_card_of_parse_widgets(card, PREFIX); | 450 | ret = asoc_simple_card_of_parse_widgets(card, PREFIX); |
300 | if (ret < 0) | 451 | if (ret < 0) |
301 | goto card_parse_end; | 452 | return ret; |
302 | 453 | ||
303 | ret = asoc_simple_card_of_parse_routing(card, PREFIX, 1); | 454 | ret = asoc_simple_card_of_parse_routing(card, PREFIX); |
304 | if (ret < 0) | 455 | if (ret < 0) |
305 | goto card_parse_end; | 456 | return ret; |
306 | |||
307 | /* Factor to mclk, used in hw_params() */ | ||
308 | of_property_read_u32(node, PREFIX "mclk-fs", &priv->mclk_fs); | ||
309 | 457 | ||
310 | /* Single/Muti DAI link(s) & New style of DT node */ | 458 | /* Single/Muti DAI link(s) & New style of DT node */ |
311 | if (dai_link) { | 459 | loop = 1; |
312 | struct device_node *np = NULL; | 460 | link_idx = 0; |
313 | int i = 0; | 461 | dai_idx = 0; |
314 | 462 | conf_idx = 0; | |
315 | for_each_child_of_node(node, np) { | 463 | node = of_get_child_by_name(top, PREFIX "dai-link"); |
316 | dev_dbg(dev, "\tlink %d:\n", i); | 464 | if (!node) { |
317 | ret = asoc_simple_card_dai_link_of(np, priv, | 465 | node = dev->of_node; |
318 | i, false); | 466 | loop = 0; |
319 | if (ret < 0) { | 467 | } |
320 | of_node_put(np); | 468 | |
321 | goto card_parse_end; | 469 | do { |
470 | /* DPCM */ | ||
471 | if (of_get_child_count(node) > 2) { | ||
472 | for_each_child_of_node(node, np) { | ||
473 | codec = of_get_child_by_name(node, | ||
474 | loop ? "codec" : | ||
475 | PREFIX "codec"); | ||
476 | if (!codec) | ||
477 | return -ENODEV; | ||
478 | |||
479 | is_fe = (np != codec); | ||
480 | |||
481 | ret = asoc_simple_card_dai_link_of_dpcm( | ||
482 | top, node, np, codec, priv, | ||
483 | &dai_idx, link_idx++, &conf_idx, | ||
484 | is_fe, !loop); | ||
322 | } | 485 | } |
323 | i++; | 486 | } else { |
487 | ret = asoc_simple_card_dai_link_of( | ||
488 | top, node, priv, | ||
489 | &dai_idx, link_idx++, !loop); | ||
324 | } | 490 | } |
325 | } else { | ||
326 | /* For single DAI link & old style of DT node */ | ||
327 | ret = asoc_simple_card_dai_link_of(node, priv, 0, true); | ||
328 | if (ret < 0) | 491 | if (ret < 0) |
329 | goto card_parse_end; | 492 | return ret; |
330 | } | 493 | |
494 | node = of_get_next_child(top, node); | ||
495 | } while (loop && node); | ||
331 | 496 | ||
332 | ret = asoc_simple_card_parse_card_name(card, PREFIX); | 497 | ret = asoc_simple_card_parse_card_name(card, PREFIX); |
333 | if (ret < 0) | 498 | if (ret < 0) |
334 | goto card_parse_end; | 499 | return ret; |
335 | |||
336 | ret = asoc_simple_card_parse_aux_devs(node, priv); | ||
337 | 500 | ||
338 | card_parse_end: | 501 | ret = asoc_simple_card_parse_aux_devs(top, priv); |
339 | of_node_put(dai_link); | ||
340 | 502 | ||
341 | return ret; | 503 | return ret; |
342 | } | 504 | } |
343 | 505 | ||
506 | static void asoc_simple_card_get_dais_count(struct device *dev, | ||
507 | int *link_num, | ||
508 | int *dais_num, | ||
509 | int *ccnf_num) | ||
510 | { | ||
511 | struct device_node *top = dev->of_node; | ||
512 | struct device_node *node; | ||
513 | int loop; | ||
514 | int num; | ||
515 | |||
516 | /* | ||
517 | * link_num : number of links. | ||
518 | * CPU-Codec / CPU-dummy / dummy-Codec | ||
519 | * dais_num : number of DAIs | ||
520 | * ccnf_num : number of codec_conf | ||
521 | * same number for "dummy-Codec" | ||
522 | * | ||
523 | * ex1) | ||
524 | * CPU0 --- Codec0 link : 5 | ||
525 | * CPU1 --- Codec1 dais : 7 | ||
526 | * CPU2 -/ ccnf : 1 | ||
527 | * CPU3 --- Codec2 | ||
528 | * | ||
529 | * => 5 links = 2xCPU-Codec + 2xCPU-dummy + 1xdummy-Codec | ||
530 | * => 7 DAIs = 4xCPU + 3xCodec | ||
531 | * => 1 ccnf = 1xdummy-Codec | ||
532 | * | ||
533 | * ex2) | ||
534 | * CPU0 --- Codec0 link : 5 | ||
535 | * CPU1 --- Codec1 dais : 6 | ||
536 | * CPU2 -/ ccnf : 1 | ||
537 | * CPU3 -/ | ||
538 | * | ||
539 | * => 5 links = 1xCPU-Codec + 3xCPU-dummy + 1xdummy-Codec | ||
540 | * => 6 DAIs = 4xCPU + 2xCodec | ||
541 | * => 1 ccnf = 1xdummy-Codec | ||
542 | * | ||
543 | * ex3) | ||
544 | * CPU0 --- Codec0 link : 6 | ||
545 | * CPU1 -/ dais : 6 | ||
546 | * CPU2 --- Codec1 ccnf : 2 | ||
547 | * CPU3 -/ | ||
548 | * | ||
549 | * => 6 links = 0xCPU-Codec + 4xCPU-dummy + 2xdummy-Codec | ||
550 | * => 6 DAIs = 4xCPU + 2xCodec | ||
551 | * => 2 ccnf = 2xdummy-Codec | ||
552 | */ | ||
553 | if (!top) { | ||
554 | (*link_num) = 1; | ||
555 | (*dais_num) = 2; | ||
556 | (*ccnf_num) = 0; | ||
557 | return; | ||
558 | } | ||
559 | |||
560 | loop = 1; | ||
561 | node = of_get_child_by_name(top, PREFIX "dai-link"); | ||
562 | if (!node) { | ||
563 | node = top; | ||
564 | loop = 0; | ||
565 | } | ||
566 | |||
567 | do { | ||
568 | num = of_get_child_count(node); | ||
569 | (*dais_num) += num; | ||
570 | if (num > 2) { | ||
571 | (*link_num) += num; | ||
572 | (*ccnf_num)++; | ||
573 | } else { | ||
574 | (*link_num)++; | ||
575 | } | ||
576 | node = of_get_next_child(top, node); | ||
577 | } while (loop && node); | ||
578 | } | ||
579 | |||
344 | static int asoc_simple_soc_card_probe(struct snd_soc_card *card) | 580 | static int asoc_simple_soc_card_probe(struct snd_soc_card *card) |
345 | { | 581 | { |
346 | struct simple_card_data *priv = snd_soc_card_get_drvdata(card); | 582 | struct simple_card_data *priv = snd_soc_card_get_drvdata(card); |
@@ -362,25 +598,28 @@ static int asoc_simple_card_probe(struct platform_device *pdev) | |||
362 | struct simple_card_data *priv; | 598 | struct simple_card_data *priv; |
363 | struct snd_soc_dai_link *dai_link; | 599 | struct snd_soc_dai_link *dai_link; |
364 | struct simple_dai_props *dai_props; | 600 | struct simple_dai_props *dai_props; |
601 | struct asoc_simple_dai *dais; | ||
365 | struct device *dev = &pdev->dev; | 602 | struct device *dev = &pdev->dev; |
366 | struct device_node *np = dev->of_node; | 603 | struct device_node *np = dev->of_node; |
367 | struct snd_soc_card *card; | 604 | struct snd_soc_card *card; |
368 | int num, ret, i; | 605 | struct snd_soc_codec_conf *cconf; |
369 | 606 | int lnum = 0, dnum = 0, cnum = 0; | |
370 | /* Get the number of DAI links */ | 607 | int ret, i; |
371 | if (np && of_get_child_by_name(np, PREFIX "dai-link")) | ||
372 | num = of_get_child_count(np); | ||
373 | else | ||
374 | num = 1; | ||
375 | 608 | ||
376 | /* Allocate the private data and the DAI link array */ | 609 | /* Allocate the private data and the DAI link array */ |
377 | priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL); | 610 | priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL); |
378 | if (!priv) | 611 | if (!priv) |
379 | return -ENOMEM; | 612 | return -ENOMEM; |
380 | 613 | ||
381 | dai_props = devm_kcalloc(dev, num, sizeof(*dai_props), GFP_KERNEL); | 614 | asoc_simple_card_get_dais_count(dev, &lnum, &dnum, &cnum); |
382 | dai_link = devm_kcalloc(dev, num, sizeof(*dai_link), GFP_KERNEL); | 615 | if (!lnum || !dnum) |
383 | if (!dai_props || !dai_link) | 616 | return -EINVAL; |
617 | |||
618 | dai_props = devm_kcalloc(dev, lnum, sizeof(*dai_props), GFP_KERNEL); | ||
619 | dai_link = devm_kcalloc(dev, lnum, sizeof(*dai_link), GFP_KERNEL); | ||
620 | dais = devm_kcalloc(dev, dnum, sizeof(*dais), GFP_KERNEL); | ||
621 | cconf = devm_kcalloc(dev, cnum, sizeof(*cconf), GFP_KERNEL); | ||
622 | if (!dai_props || !dai_link || !dais) | ||
384 | return -ENOMEM; | 623 | return -ENOMEM; |
385 | 624 | ||
386 | /* | 625 | /* |
@@ -389,7 +628,7 @@ static int asoc_simple_card_probe(struct platform_device *pdev) | |||
389 | * see | 628 | * see |
390 | * soc-core.c :: snd_soc_init_multicodec() | 629 | * soc-core.c :: snd_soc_init_multicodec() |
391 | */ | 630 | */ |
392 | for (i = 0; i < num; i++) { | 631 | for (i = 0; i < lnum; i++) { |
393 | dai_link[i].codecs = &dai_props[i].codecs; | 632 | dai_link[i].codecs = &dai_props[i].codecs; |
394 | dai_link[i].num_codecs = 1; | 633 | dai_link[i].num_codecs = 1; |
395 | dai_link[i].platform = &dai_props[i].platform; | 634 | dai_link[i].platform = &dai_props[i].platform; |
@@ -397,13 +636,17 @@ static int asoc_simple_card_probe(struct platform_device *pdev) | |||
397 | 636 | ||
398 | priv->dai_props = dai_props; | 637 | priv->dai_props = dai_props; |
399 | priv->dai_link = dai_link; | 638 | priv->dai_link = dai_link; |
639 | priv->dais = dais; | ||
640 | priv->codec_conf = cconf; | ||
400 | 641 | ||
401 | /* Init snd_soc_card */ | 642 | /* Init snd_soc_card */ |
402 | card = simple_priv_to_card(priv); | 643 | card = simple_priv_to_card(priv); |
403 | card->owner = THIS_MODULE; | 644 | card->owner = THIS_MODULE; |
404 | card->dev = dev; | 645 | card->dev = dev; |
405 | card->dai_link = priv->dai_link; | 646 | card->dai_link = priv->dai_link; |
406 | card->num_links = num; | 647 | card->num_links = lnum; |
648 | card->codec_conf = cconf; | ||
649 | card->num_configs = cnum; | ||
407 | card->probe = asoc_simple_soc_card_probe; | 650 | card->probe = asoc_simple_soc_card_probe; |
408 | 651 | ||
409 | if (np && of_device_is_available(np)) { | 652 | if (np && of_device_is_available(np)) { |
@@ -419,6 +662,7 @@ static int asoc_simple_card_probe(struct platform_device *pdev) | |||
419 | struct asoc_simple_card_info *cinfo; | 662 | struct asoc_simple_card_info *cinfo; |
420 | struct snd_soc_dai_link_component *codecs; | 663 | struct snd_soc_dai_link_component *codecs; |
421 | struct snd_soc_dai_link_component *platform; | 664 | struct snd_soc_dai_link_component *platform; |
665 | int dai_idx = 0; | ||
422 | 666 | ||
423 | cinfo = dev->platform_data; | 667 | cinfo = dev->platform_data; |
424 | if (!cinfo) { | 668 | if (!cinfo) { |
@@ -435,6 +679,9 @@ static int asoc_simple_card_probe(struct platform_device *pdev) | |||
435 | return -EINVAL; | 679 | return -EINVAL; |
436 | } | 680 | } |
437 | 681 | ||
682 | dai_props->cpu_dai = &priv->dais[dai_idx++]; | ||
683 | dai_props->codec_dai = &priv->dais[dai_idx++]; | ||
684 | |||
438 | codecs = dai_link->codecs; | 685 | codecs = dai_link->codecs; |
439 | codecs->name = cinfo->codec; | 686 | codecs->name = cinfo->codec; |
440 | codecs->dai_name = cinfo->codec_dai.name; | 687 | codecs->dai_name = cinfo->codec_dai.name; |
@@ -448,10 +695,10 @@ static int asoc_simple_card_probe(struct platform_device *pdev) | |||
448 | dai_link->cpu_dai_name = cinfo->cpu_dai.name; | 695 | dai_link->cpu_dai_name = cinfo->cpu_dai.name; |
449 | dai_link->dai_fmt = cinfo->daifmt; | 696 | dai_link->dai_fmt = cinfo->daifmt; |
450 | dai_link->init = asoc_simple_card_dai_init; | 697 | dai_link->init = asoc_simple_card_dai_init; |
451 | memcpy(&priv->dai_props->cpu_dai, &cinfo->cpu_dai, | 698 | memcpy(priv->dai_props->cpu_dai, &cinfo->cpu_dai, |
452 | sizeof(priv->dai_props->cpu_dai)); | 699 | sizeof(*priv->dai_props->cpu_dai)); |
453 | memcpy(&priv->dai_props->codec_dai, &cinfo->codec_dai, | 700 | memcpy(priv->dai_props->codec_dai, &cinfo->codec_dai, |
454 | sizeof(priv->dai_props->codec_dai)); | 701 | sizeof(*priv->dai_props->codec_dai)); |
455 | } | 702 | } |
456 | 703 | ||
457 | snd_soc_card_set_drvdata(card, priv); | 704 | snd_soc_card_set_drvdata(card, priv); |
@@ -476,6 +723,7 @@ static int asoc_simple_card_remove(struct platform_device *pdev) | |||
476 | 723 | ||
477 | static const struct of_device_id asoc_simple_of_match[] = { | 724 | static const struct of_device_id asoc_simple_of_match[] = { |
478 | { .compatible = "simple-audio-card", }, | 725 | { .compatible = "simple-audio-card", }, |
726 | { .compatible = "simple-scu-audio-card", }, | ||
479 | {}, | 727 | {}, |
480 | }; | 728 | }; |
481 | MODULE_DEVICE_TABLE(of, asoc_simple_of_match); | 729 | MODULE_DEVICE_TABLE(of, asoc_simple_of_match); |
diff --git a/sound/soc/generic/simple-scu-card.c b/sound/soc/generic/simple-scu-card.c index 85b46f0eae0f..9d7299d536a8 100644 --- a/sound/soc/generic/simple-scu-card.c +++ b/sound/soc/generic/simple-scu-card.c | |||
@@ -21,14 +21,18 @@ | |||
21 | 21 | ||
22 | struct simple_card_data { | 22 | struct simple_card_data { |
23 | struct snd_soc_card snd_card; | 23 | struct snd_soc_card snd_card; |
24 | struct snd_soc_codec_conf codec_conf; | ||
25 | struct simple_dai_props { | 24 | struct simple_dai_props { |
26 | struct asoc_simple_dai dai; | 25 | struct asoc_simple_dai *cpu_dai; |
26 | struct asoc_simple_dai *codec_dai; | ||
27 | struct snd_soc_dai_link_component codecs; | 27 | struct snd_soc_dai_link_component codecs; |
28 | struct snd_soc_dai_link_component platform; | 28 | struct snd_soc_dai_link_component platform; |
29 | struct asoc_simple_card_data adata; | ||
30 | struct snd_soc_codec_conf *codec_conf; | ||
29 | } *dai_props; | 31 | } *dai_props; |
30 | struct snd_soc_dai_link *dai_link; | 32 | struct snd_soc_dai_link *dai_link; |
33 | struct asoc_simple_dai *dais; | ||
31 | struct asoc_simple_card_data adata; | 34 | struct asoc_simple_card_data adata; |
35 | struct snd_soc_codec_conf *codec_conf; | ||
32 | }; | 36 | }; |
33 | 37 | ||
34 | #define simple_priv_to_card(priv) (&(priv)->snd_card) | 38 | #define simple_priv_to_card(priv) (&(priv)->snd_card) |
@@ -46,8 +50,17 @@ static int asoc_simple_card_startup(struct snd_pcm_substream *substream) | |||
46 | struct simple_card_data *priv = snd_soc_card_get_drvdata(rtd->card); | 50 | struct simple_card_data *priv = snd_soc_card_get_drvdata(rtd->card); |
47 | struct simple_dai_props *dai_props = | 51 | struct simple_dai_props *dai_props = |
48 | simple_priv_to_props(priv, rtd->num); | 52 | simple_priv_to_props(priv, rtd->num); |
53 | int ret; | ||
54 | |||
55 | ret = asoc_simple_card_clk_enable(dai_props->cpu_dai); | ||
56 | if (ret) | ||
57 | return ret; | ||
58 | |||
59 | ret = asoc_simple_card_clk_enable(dai_props->codec_dai); | ||
60 | if (ret) | ||
61 | asoc_simple_card_clk_disable(dai_props->cpu_dai); | ||
49 | 62 | ||
50 | return asoc_simple_card_clk_enable(&dai_props->dai); | 63 | return ret; |
51 | } | 64 | } |
52 | 65 | ||
53 | static void asoc_simple_card_shutdown(struct snd_pcm_substream *substream) | 66 | static void asoc_simple_card_shutdown(struct snd_pcm_substream *substream) |
@@ -57,7 +70,9 @@ static void asoc_simple_card_shutdown(struct snd_pcm_substream *substream) | |||
57 | struct simple_dai_props *dai_props = | 70 | struct simple_dai_props *dai_props = |
58 | simple_priv_to_props(priv, rtd->num); | 71 | simple_priv_to_props(priv, rtd->num); |
59 | 72 | ||
60 | asoc_simple_card_clk_disable(&dai_props->dai); | 73 | asoc_simple_card_clk_disable(dai_props->cpu_dai); |
74 | |||
75 | asoc_simple_card_clk_disable(dai_props->codec_dai); | ||
61 | } | 76 | } |
62 | 77 | ||
63 | static const struct snd_soc_ops asoc_simple_card_ops = { | 78 | static const struct snd_soc_ops asoc_simple_card_ops = { |
@@ -67,42 +82,57 @@ static const struct snd_soc_ops asoc_simple_card_ops = { | |||
67 | 82 | ||
68 | static int asoc_simple_card_dai_init(struct snd_soc_pcm_runtime *rtd) | 83 | static int asoc_simple_card_dai_init(struct snd_soc_pcm_runtime *rtd) |
69 | { | 84 | { |
70 | struct simple_card_data *priv = snd_soc_card_get_drvdata(rtd->card); | 85 | struct simple_card_data *priv = snd_soc_card_get_drvdata(rtd->card); |
71 | struct snd_soc_dai *dai; | 86 | struct simple_dai_props *dai_props = simple_priv_to_props(priv, rtd->num); |
72 | struct snd_soc_dai_link *dai_link; | 87 | int ret; |
73 | struct simple_dai_props *dai_props; | 88 | |
74 | int num = rtd->num; | 89 | ret = asoc_simple_card_init_dai(rtd->codec_dai, |
90 | dai_props->codec_dai); | ||
91 | if (ret < 0) | ||
92 | return ret; | ||
75 | 93 | ||
76 | dai_link = simple_priv_to_link(priv, num); | 94 | ret = asoc_simple_card_init_dai(rtd->cpu_dai, |
77 | dai_props = simple_priv_to_props(priv, num); | 95 | dai_props->cpu_dai); |
78 | dai = dai_link->dynamic ? | 96 | if (ret < 0) |
79 | rtd->cpu_dai : | 97 | return ret; |
80 | rtd->codec_dai; | ||
81 | 98 | ||
82 | return asoc_simple_card_init_dai(dai, &dai_props->dai); | 99 | return 0; |
83 | } | 100 | } |
84 | 101 | ||
85 | static int asoc_simple_card_be_hw_params_fixup(struct snd_soc_pcm_runtime *rtd, | 102 | static int asoc_simple_card_be_hw_params_fixup(struct snd_soc_pcm_runtime *rtd, |
86 | struct snd_pcm_hw_params *params) | 103 | struct snd_pcm_hw_params *params) |
87 | { | 104 | { |
88 | struct simple_card_data *priv = snd_soc_card_get_drvdata(rtd->card); | 105 | struct simple_card_data *priv = snd_soc_card_get_drvdata(rtd->card); |
106 | struct simple_dai_props *dai_props = simple_priv_to_props(priv, rtd->num); | ||
107 | |||
108 | asoc_simple_card_convert_fixup(&dai_props->adata, params); | ||
89 | 109 | ||
110 | /* overwrite by top level adata if exist */ | ||
90 | asoc_simple_card_convert_fixup(&priv->adata, params); | 111 | asoc_simple_card_convert_fixup(&priv->adata, params); |
91 | 112 | ||
92 | return 0; | 113 | return 0; |
93 | } | 114 | } |
94 | 115 | ||
95 | static int asoc_simple_card_dai_link_of(struct device_node *np, | 116 | static int asoc_simple_card_dai_link_of(struct device_node *link, |
117 | struct device_node *np, | ||
118 | struct device_node *codec, | ||
96 | struct simple_card_data *priv, | 119 | struct simple_card_data *priv, |
97 | unsigned int daifmt, | 120 | int *dai_idx, int link_idx, |
98 | int idx, bool is_fe) | 121 | int *conf_idx, int is_fe, |
122 | bool is_top_level_node) | ||
99 | { | 123 | { |
100 | struct device *dev = simple_priv_to_dev(priv); | 124 | struct device *dev = simple_priv_to_dev(priv); |
101 | struct snd_soc_dai_link *dai_link = simple_priv_to_link(priv, idx); | 125 | struct snd_soc_dai_link *dai_link = simple_priv_to_link(priv, link_idx); |
102 | struct simple_dai_props *dai_props = simple_priv_to_props(priv, idx); | 126 | struct simple_dai_props *dai_props = simple_priv_to_props(priv, link_idx); |
103 | struct snd_soc_card *card = simple_priv_to_card(priv); | 127 | struct snd_soc_card *card = simple_priv_to_card(priv); |
128 | struct asoc_simple_dai *dai; | ||
129 | char *prefix = ""; | ||
104 | int ret; | 130 | int ret; |
105 | 131 | ||
132 | /* For single DAI link & old style of DT node */ | ||
133 | if (is_top_level_node) | ||
134 | prefix = PREFIX; | ||
135 | |||
106 | if (is_fe) { | 136 | if (is_fe) { |
107 | int is_single_links = 0; | 137 | int is_single_links = 0; |
108 | struct snd_soc_dai_link_component *codecs; | 138 | struct snd_soc_dai_link_component *codecs; |
@@ -117,12 +147,15 @@ static int asoc_simple_card_dai_link_of(struct device_node *np, | |||
117 | dai_link->dynamic = 1; | 147 | dai_link->dynamic = 1; |
118 | dai_link->dpcm_merged_format = 1; | 148 | dai_link->dpcm_merged_format = 1; |
119 | 149 | ||
150 | dai = | ||
151 | dai_props->cpu_dai = &priv->dais[(*dai_idx)++]; | ||
152 | |||
120 | ret = asoc_simple_card_parse_cpu(np, dai_link, DAI, CELL, | 153 | ret = asoc_simple_card_parse_cpu(np, dai_link, DAI, CELL, |
121 | &is_single_links); | 154 | &is_single_links); |
122 | if (ret) | 155 | if (ret) |
123 | return ret; | 156 | return ret; |
124 | 157 | ||
125 | ret = asoc_simple_card_parse_clk_cpu(dev, np, dai_link, &dai_props->dai); | 158 | ret = asoc_simple_card_parse_clk_cpu(dev, np, dai_link, dai); |
126 | if (ret < 0) | 159 | if (ret < 0) |
127 | return ret; | 160 | return ret; |
128 | 161 | ||
@@ -134,6 +167,8 @@ static int asoc_simple_card_dai_link_of(struct device_node *np, | |||
134 | 167 | ||
135 | asoc_simple_card_canonicalize_cpu(dai_link, is_single_links); | 168 | asoc_simple_card_canonicalize_cpu(dai_link, is_single_links); |
136 | } else { | 169 | } else { |
170 | struct snd_soc_codec_conf *cconf; | ||
171 | |||
137 | /* FE is dummy */ | 172 | /* FE is dummy */ |
138 | dai_link->cpu_of_node = NULL; | 173 | dai_link->cpu_of_node = NULL; |
139 | dai_link->cpu_dai_name = "snd-soc-dummy-dai"; | 174 | dai_link->cpu_dai_name = "snd-soc-dummy-dai"; |
@@ -143,11 +178,17 @@ static int asoc_simple_card_dai_link_of(struct device_node *np, | |||
143 | dai_link->no_pcm = 1; | 178 | dai_link->no_pcm = 1; |
144 | dai_link->be_hw_params_fixup = asoc_simple_card_be_hw_params_fixup; | 179 | dai_link->be_hw_params_fixup = asoc_simple_card_be_hw_params_fixup; |
145 | 180 | ||
181 | dai = | ||
182 | dai_props->codec_dai = &priv->dais[(*dai_idx)++]; | ||
183 | |||
184 | cconf = | ||
185 | dai_props->codec_conf = &priv->codec_conf[(*conf_idx)++]; | ||
186 | |||
146 | ret = asoc_simple_card_parse_codec(np, dai_link, DAI, CELL); | 187 | ret = asoc_simple_card_parse_codec(np, dai_link, DAI, CELL); |
147 | if (ret < 0) | 188 | if (ret < 0) |
148 | return ret; | 189 | return ret; |
149 | 190 | ||
150 | ret = asoc_simple_card_parse_clk_codec(dev, np, dai_link, &dai_props->dai); | 191 | ret = asoc_simple_card_parse_clk_codec(dev, np, dai_link, dai); |
151 | if (ret < 0) | 192 | if (ret < 0) |
152 | return ret; | 193 | return ret; |
153 | 194 | ||
@@ -157,13 +198,20 @@ static int asoc_simple_card_dai_link_of(struct device_node *np, | |||
157 | if (ret < 0) | 198 | if (ret < 0) |
158 | return ret; | 199 | return ret; |
159 | 200 | ||
160 | snd_soc_of_parse_audio_prefix(card, | 201 | /* check "prefix" from top node */ |
161 | &priv->codec_conf, | 202 | snd_soc_of_parse_audio_prefix(card, cconf, |
162 | dai_link->codecs->of_node, | 203 | dai_link->codecs->of_node, |
163 | PREFIX "prefix"); | 204 | PREFIX "prefix"); |
205 | /* check "prefix" from each node if top doesn't have */ | ||
206 | if (!cconf->of_node) | ||
207 | snd_soc_of_parse_node_prefix(np, cconf, | ||
208 | dai_link->codecs->of_node, | ||
209 | "prefix"); | ||
164 | } | 210 | } |
165 | 211 | ||
166 | ret = asoc_simple_card_of_parse_tdm(np, &dai_props->dai); | 212 | asoc_simple_card_parse_convert(dev, link, prefix, &dai_props->adata); |
213 | |||
214 | ret = asoc_simple_card_of_parse_tdm(np, dai); | ||
167 | if (ret) | 215 | if (ret) |
168 | return ret; | 216 | return ret; |
169 | 217 | ||
@@ -171,7 +219,11 @@ static int asoc_simple_card_dai_link_of(struct device_node *np, | |||
171 | if (ret < 0) | 219 | if (ret < 0) |
172 | return ret; | 220 | return ret; |
173 | 221 | ||
174 | dai_link->dai_fmt = daifmt; | 222 | ret = asoc_simple_card_parse_daifmt(dev, link, codec, |
223 | prefix, &dai_link->dai_fmt); | ||
224 | if (ret < 0) | ||
225 | return ret; | ||
226 | |||
175 | dai_link->dpcm_playback = 1; | 227 | dai_link->dpcm_playback = 1; |
176 | dai_link->dpcm_capture = 1; | 228 | dai_link->dpcm_capture = 1; |
177 | dai_link->ops = &asoc_simple_card_ops; | 229 | dai_link->ops = &asoc_simple_card_ops; |
@@ -184,52 +236,136 @@ static int asoc_simple_card_parse_of(struct simple_card_data *priv) | |||
184 | 236 | ||
185 | { | 237 | { |
186 | struct device *dev = simple_priv_to_dev(priv); | 238 | struct device *dev = simple_priv_to_dev(priv); |
239 | struct device_node *top = dev->of_node; | ||
240 | struct device_node *node; | ||
187 | struct device_node *np; | 241 | struct device_node *np; |
242 | struct device_node *codec; | ||
188 | struct snd_soc_card *card = simple_priv_to_card(priv); | 243 | struct snd_soc_card *card = simple_priv_to_card(priv); |
189 | struct device_node *node = dev->of_node; | ||
190 | unsigned int daifmt = 0; | ||
191 | bool is_fe; | 244 | bool is_fe; |
192 | int ret, i; | 245 | int ret, loop; |
246 | int dai_idx, link_idx, conf_idx; | ||
193 | 247 | ||
194 | if (!node) | 248 | if (!top) |
195 | return -EINVAL; | 249 | return -EINVAL; |
196 | 250 | ||
197 | ret = asoc_simple_card_of_parse_widgets(card, PREFIX); | 251 | ret = asoc_simple_card_of_parse_widgets(card, PREFIX); |
198 | if (ret < 0) | 252 | if (ret < 0) |
199 | return ret; | 253 | return ret; |
200 | 254 | ||
201 | ret = asoc_simple_card_of_parse_routing(card, PREFIX, 0); | 255 | ret = asoc_simple_card_of_parse_routing(card, PREFIX); |
202 | if (ret < 0) | 256 | if (ret < 0) |
203 | return ret; | 257 | return ret; |
204 | 258 | ||
205 | asoc_simple_card_parse_convert(dev, PREFIX, &priv->adata); | 259 | asoc_simple_card_parse_convert(dev, top, PREFIX, &priv->adata); |
206 | 260 | ||
207 | /* find 1st codec */ | 261 | loop = 1; |
208 | np = of_get_child_by_name(node, PREFIX "codec"); | 262 | link_idx = 0; |
209 | if (!np) | 263 | dai_idx = 0; |
210 | return -ENODEV; | 264 | conf_idx = 0; |
265 | node = of_get_child_by_name(top, PREFIX "dai-link"); | ||
266 | if (!node) { | ||
267 | node = dev->of_node; | ||
268 | loop = 0; | ||
269 | } | ||
270 | |||
271 | do { | ||
272 | codec = of_get_child_by_name(node, | ||
273 | loop ? "codec" : PREFIX "codec"); | ||
274 | if (!codec) | ||
275 | return -ENODEV; | ||
276 | |||
277 | for_each_child_of_node(node, np) { | ||
278 | is_fe = (np != codec); | ||
279 | |||
280 | ret = asoc_simple_card_dai_link_of(node, np, codec, priv, | ||
281 | &dai_idx, link_idx++, | ||
282 | &conf_idx, | ||
283 | is_fe, !loop); | ||
284 | if (ret < 0) | ||
285 | return ret; | ||
286 | } | ||
287 | node = of_get_next_child(top, node); | ||
288 | } while (loop && node); | ||
211 | 289 | ||
212 | ret = asoc_simple_card_parse_daifmt(dev, node, np, PREFIX, &daifmt); | 290 | ret = asoc_simple_card_parse_card_name(card, PREFIX); |
213 | if (ret < 0) | 291 | if (ret < 0) |
214 | return ret; | 292 | return ret; |
215 | 293 | ||
216 | i = 0; | 294 | return 0; |
217 | for_each_child_of_node(node, np) { | 295 | } |
218 | is_fe = false; | ||
219 | if (strcmp(np->name, PREFIX "cpu") == 0) | ||
220 | is_fe = true; | ||
221 | 296 | ||
222 | ret = asoc_simple_card_dai_link_of(np, priv, daifmt, i, is_fe); | 297 | static void asoc_simple_card_get_dais_count(struct device *dev, |
223 | if (ret < 0) | 298 | int *link_num, |
224 | return ret; | 299 | int *dais_num, |
225 | i++; | 300 | int *ccnf_num) |
301 | { | ||
302 | struct device_node *top = dev->of_node; | ||
303 | struct device_node *node; | ||
304 | int loop; | ||
305 | int num; | ||
306 | |||
307 | /* | ||
308 | * link_num : number of links. | ||
309 | * CPU-Codec / CPU-dummy / dummy-Codec | ||
310 | * dais_num : number of DAIs | ||
311 | * ccnf_num : number of codec_conf | ||
312 | * same number for "dummy-Codec" | ||
313 | * | ||
314 | * ex1) | ||
315 | * CPU0 --- Codec0 link : 5 | ||
316 | * CPU1 --- Codec1 dais : 7 | ||
317 | * CPU2 -/ ccnf : 1 | ||
318 | * CPU3 --- Codec2 | ||
319 | * | ||
320 | * => 5 links = 2xCPU-Codec + 2xCPU-dummy + 1xdummy-Codec | ||
321 | * => 7 DAIs = 4xCPU + 3xCodec | ||
322 | * => 1 ccnf = 1xdummy-Codec | ||
323 | * | ||
324 | * ex2) | ||
325 | * CPU0 --- Codec0 link : 5 | ||
326 | * CPU1 --- Codec1 dais : 6 | ||
327 | * CPU2 -/ ccnf : 1 | ||
328 | * CPU3 -/ | ||
329 | * | ||
330 | * => 5 links = 1xCPU-Codec + 3xCPU-dummy + 1xdummy-Codec | ||
331 | * => 6 DAIs = 4xCPU + 2xCodec | ||
332 | * => 1 ccnf = 1xdummy-Codec | ||
333 | * | ||
334 | * ex3) | ||
335 | * CPU0 --- Codec0 link : 6 | ||
336 | * CPU1 -/ dais : 6 | ||
337 | * CPU2 --- Codec1 ccnf : 2 | ||
338 | * CPU3 -/ | ||
339 | * | ||
340 | * => 6 links = 0xCPU-Codec + 4xCPU-dummy + 2xdummy-Codec | ||
341 | * => 6 DAIs = 4xCPU + 2xCodec | ||
342 | * => 2 ccnf = 2xdummy-Codec | ||
343 | */ | ||
344 | if (!top) { | ||
345 | (*link_num) = 1; | ||
346 | (*dais_num) = 2; | ||
347 | (*ccnf_num) = 0; | ||
348 | return; | ||
226 | } | 349 | } |
227 | 350 | ||
228 | ret = asoc_simple_card_parse_card_name(card, PREFIX); | 351 | loop = 1; |
229 | if (ret < 0) | 352 | node = of_get_child_by_name(top, PREFIX "dai-link"); |
230 | return ret; | 353 | if (!node) { |
354 | node = top; | ||
355 | loop = 0; | ||
356 | } | ||
231 | 357 | ||
232 | return 0; | 358 | do { |
359 | num = of_get_child_count(node); | ||
360 | (*dais_num) += num; | ||
361 | if (num > 2) { | ||
362 | (*link_num) += num; | ||
363 | (*ccnf_num)++; | ||
364 | } else { | ||
365 | (*link_num)++; | ||
366 | } | ||
367 | node = of_get_next_child(top, node); | ||
368 | } while (loop && node); | ||
233 | } | 369 | } |
234 | 370 | ||
235 | static int asoc_simple_card_probe(struct platform_device *pdev) | 371 | static int asoc_simple_card_probe(struct platform_device *pdev) |
@@ -237,21 +373,27 @@ static int asoc_simple_card_probe(struct platform_device *pdev) | |||
237 | struct simple_card_data *priv; | 373 | struct simple_card_data *priv; |
238 | struct snd_soc_dai_link *dai_link; | 374 | struct snd_soc_dai_link *dai_link; |
239 | struct simple_dai_props *dai_props; | 375 | struct simple_dai_props *dai_props; |
376 | struct asoc_simple_dai *dais; | ||
240 | struct snd_soc_card *card; | 377 | struct snd_soc_card *card; |
378 | struct snd_soc_codec_conf *cconf; | ||
241 | struct device *dev = &pdev->dev; | 379 | struct device *dev = &pdev->dev; |
242 | struct device_node *np = dev->of_node; | 380 | int ret, i; |
243 | int num, ret, i; | 381 | int lnum = 0, dnum = 0, cnum = 0; |
244 | 382 | ||
245 | /* Allocate the private data */ | 383 | /* Allocate the private data */ |
246 | priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL); | 384 | priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL); |
247 | if (!priv) | 385 | if (!priv) |
248 | return -ENOMEM; | 386 | return -ENOMEM; |
249 | 387 | ||
250 | num = of_get_child_count(np); | 388 | asoc_simple_card_get_dais_count(dev, &lnum, &dnum, &cnum); |
389 | if (!lnum || !dnum) | ||
390 | return -EINVAL; | ||
251 | 391 | ||
252 | dai_props = devm_kcalloc(dev, num, sizeof(*dai_props), GFP_KERNEL); | 392 | dai_props = devm_kcalloc(dev, lnum, sizeof(*dai_props), GFP_KERNEL); |
253 | dai_link = devm_kcalloc(dev, num, sizeof(*dai_link), GFP_KERNEL); | 393 | dai_link = devm_kcalloc(dev, lnum, sizeof(*dai_link), GFP_KERNEL); |
254 | if (!dai_props || !dai_link) | 394 | dais = devm_kcalloc(dev, dnum, sizeof(*dais), GFP_KERNEL); |
395 | cconf = devm_kcalloc(dev, cnum, sizeof(*cconf), GFP_KERNEL); | ||
396 | if (!dai_props || !dai_link || !dais) | ||
255 | return -ENOMEM; | 397 | return -ENOMEM; |
256 | 398 | ||
257 | /* | 399 | /* |
@@ -260,7 +402,7 @@ static int asoc_simple_card_probe(struct platform_device *pdev) | |||
260 | * see | 402 | * see |
261 | * soc-core.c :: snd_soc_init_multicodec() | 403 | * soc-core.c :: snd_soc_init_multicodec() |
262 | */ | 404 | */ |
263 | for (i = 0; i < num; i++) { | 405 | for (i = 0; i < lnum; i++) { |
264 | dai_link[i].codecs = &dai_props[i].codecs; | 406 | dai_link[i].codecs = &dai_props[i].codecs; |
265 | dai_link[i].num_codecs = 1; | 407 | dai_link[i].num_codecs = 1; |
266 | dai_link[i].platform = &dai_props[i].platform; | 408 | dai_link[i].platform = &dai_props[i].platform; |
@@ -268,15 +410,17 @@ static int asoc_simple_card_probe(struct platform_device *pdev) | |||
268 | 410 | ||
269 | priv->dai_props = dai_props; | 411 | priv->dai_props = dai_props; |
270 | priv->dai_link = dai_link; | 412 | priv->dai_link = dai_link; |
413 | priv->dais = dais; | ||
414 | priv->codec_conf = cconf; | ||
271 | 415 | ||
272 | /* Init snd_soc_card */ | 416 | /* Init snd_soc_card */ |
273 | card = simple_priv_to_card(priv); | 417 | card = simple_priv_to_card(priv); |
274 | card->owner = THIS_MODULE; | 418 | card->owner = THIS_MODULE; |
275 | card->dev = dev; | 419 | card->dev = dev; |
276 | card->dai_link = priv->dai_link; | 420 | card->dai_link = priv->dai_link; |
277 | card->num_links = num; | 421 | card->num_links = lnum; |
278 | card->codec_conf = &priv->codec_conf; | 422 | card->codec_conf = cconf; |
279 | card->num_configs = 1; | 423 | card->num_configs = cnum; |
280 | 424 | ||
281 | ret = asoc_simple_card_parse_of(priv); | 425 | ret = asoc_simple_card_parse_of(priv); |
282 | if (ret < 0) { | 426 | if (ret < 0) { |
diff --git a/sound/soc/intel/Kconfig b/sound/soc/intel/Kconfig index 18e717703685..99a62ba409df 100644 --- a/sound/soc/intel/Kconfig +++ b/sound/soc/intel/Kconfig | |||
@@ -102,15 +102,74 @@ config SND_SST_ATOM_HIFI2_PLATFORM_ACPI | |||
102 | recommended option | 102 | recommended option |
103 | 103 | ||
104 | config SND_SOC_INTEL_SKYLAKE | 104 | config SND_SOC_INTEL_SKYLAKE |
105 | tristate "SKL/BXT/KBL/GLK/CNL... Platforms" | 105 | tristate "All Skylake/SST Platforms" |
106 | depends on PCI && ACPI | 106 | depends on PCI && ACPI |
107 | select SND_SOC_INTEL_SKYLAKE_COMMON | 107 | select SND_SOC_INTEL_SKL |
108 | select SND_SOC_INTEL_APL | ||
109 | select SND_SOC_INTEL_KBL | ||
110 | select SND_SOC_INTEL_GLK | ||
111 | select SND_SOC_INTEL_CNL | ||
112 | select SND_SOC_INTEL_CFL | ||
108 | help | 113 | help |
109 | If you have a Intel Skylake/Broxton/ApolloLake/KabyLake/ | 114 | This is a backwards-compatible option to select all devices |
110 | GeminiLake or CannonLake platform with the DSP enabled in the BIOS | 115 | supported by the Intel SST/Skylake driver. This option is no |
111 | then enable this option by saying Y or m. | 116 | longer recommended and will be deprecated when the SOF |
117 | driver is introduced. Distributions should explicitly | ||
118 | select which platform uses this driver. | ||
119 | |||
120 | config SND_SOC_INTEL_SKL | ||
121 | tristate "Skylake Platforms" | ||
122 | depends on PCI && ACPI | ||
123 | select SND_SOC_INTEL_SKYLAKE_FAMILY | ||
124 | help | ||
125 | If you have a Intel Skylake platform with the DSP enabled | ||
126 | in the BIOS then enable this option by saying Y or m. | ||
127 | |||
128 | config SND_SOC_INTEL_APL | ||
129 | tristate "Broxton/ApolloLake Platforms" | ||
130 | depends on PCI && ACPI | ||
131 | select SND_SOC_INTEL_SKYLAKE_FAMILY | ||
132 | help | ||
133 | If you have a Intel Broxton/ApolloLake platform with the DSP | ||
134 | enabled in the BIOS then enable this option by saying Y or m. | ||
135 | |||
136 | config SND_SOC_INTEL_KBL | ||
137 | tristate "Kabylake Platforms" | ||
138 | depends on PCI && ACPI | ||
139 | select SND_SOC_INTEL_SKYLAKE_FAMILY | ||
140 | help | ||
141 | If you have a Intel Kabylake platform with the DSP | ||
142 | enabled in the BIOS then enable this option by saying Y or m. | ||
143 | |||
144 | config SND_SOC_INTEL_GLK | ||
145 | tristate "GeminiLake Platforms" | ||
146 | depends on PCI && ACPI | ||
147 | select SND_SOC_INTEL_SKYLAKE_FAMILY | ||
148 | help | ||
149 | If you have a Intel GeminiLake platform with the DSP | ||
150 | enabled in the BIOS then enable this option by saying Y or m. | ||
151 | |||
152 | config SND_SOC_INTEL_CNL | ||
153 | tristate "CannonLake/WhiskyLake Platforms" | ||
154 | depends on PCI && ACPI | ||
155 | select SND_SOC_INTEL_SKYLAKE_FAMILY | ||
156 | help | ||
157 | If you have a Intel CNL/WHL platform with the DSP | ||
158 | enabled in the BIOS then enable this option by saying Y or m. | ||
159 | |||
160 | config SND_SOC_INTEL_CFL | ||
161 | tristate "CoffeeLake Platforms" | ||
162 | depends on PCI && ACPI | ||
163 | select SND_SOC_INTEL_SKYLAKE_FAMILY | ||
164 | help | ||
165 | If you have a Intel CoffeeLake platform with the DSP | ||
166 | enabled in the BIOS then enable this option by saying Y or m. | ||
167 | |||
168 | config SND_SOC_INTEL_SKYLAKE_FAMILY | ||
169 | tristate | ||
170 | select SND_SOC_INTEL_SKYLAKE_COMMON | ||
112 | 171 | ||
113 | if SND_SOC_INTEL_SKYLAKE | 172 | if SND_SOC_INTEL_SKYLAKE_FAMILY |
114 | 173 | ||
115 | config SND_SOC_INTEL_SKYLAKE_SSP_CLK | 174 | config SND_SOC_INTEL_SKYLAKE_SSP_CLK |
116 | tristate | 175 | tristate |
@@ -135,7 +194,7 @@ config SND_SOC_INTEL_SKYLAKE_COMMON | |||
135 | GeminiLake or CannonLake platform with the DSP enabled in the BIOS | 194 | GeminiLake or CannonLake platform with the DSP enabled in the BIOS |
136 | then enable this option by saying Y or m. | 195 | then enable this option by saying Y or m. |
137 | 196 | ||
138 | endif ## SND_SOC_INTEL_SKYLAKE | 197 | endif ## SND_SOC_INTEL_SKYLAKE_FAMILY |
139 | 198 | ||
140 | config SND_SOC_ACPI_INTEL_MATCH | 199 | config SND_SOC_ACPI_INTEL_MATCH |
141 | tristate | 200 | tristate |
diff --git a/sound/soc/intel/atom/sst/sst_acpi.c b/sound/soc/intel/atom/sst/sst_acpi.c index c90b04cc071d..ac542535b9d5 100644 --- a/sound/soc/intel/atom/sst/sst_acpi.c +++ b/sound/soc/intel/atom/sst/sst_acpi.c | |||
@@ -341,6 +341,10 @@ static int sst_acpi_probe(struct platform_device *pdev) | |||
341 | byt_rvp_platform_data.res_info = &bytcr_res_info; | 341 | byt_rvp_platform_data.res_info = &bytcr_res_info; |
342 | } | 342 | } |
343 | 343 | ||
344 | /* update machine parameters */ | ||
345 | mach->mach_params.acpi_ipc_irq_index = | ||
346 | pdata->res_info->acpi_ipc_irq_index; | ||
347 | |||
344 | plat_dev = platform_device_register_data(dev, pdata->platform, -1, | 348 | plat_dev = platform_device_register_data(dev, pdata->platform, -1, |
345 | NULL, 0); | 349 | NULL, 0); |
346 | if (IS_ERR(plat_dev)) { | 350 | if (IS_ERR(plat_dev)) { |
diff --git a/sound/soc/intel/atom/sst/sst_loader.c b/sound/soc/intel/atom/sst/sst_loader.c index 27413ebae956..b8c456753f01 100644 --- a/sound/soc/intel/atom/sst/sst_loader.c +++ b/sound/soc/intel/atom/sst/sst_loader.c | |||
@@ -354,14 +354,14 @@ static int sst_request_fw(struct intel_sst_drv *sst) | |||
354 | const struct firmware *fw; | 354 | const struct firmware *fw; |
355 | 355 | ||
356 | retval = request_firmware(&fw, sst->firmware_name, sst->dev); | 356 | retval = request_firmware(&fw, sst->firmware_name, sst->dev); |
357 | if (fw == NULL) { | ||
358 | dev_err(sst->dev, "fw is returning as null\n"); | ||
359 | return -EINVAL; | ||
360 | } | ||
361 | if (retval) { | 357 | if (retval) { |
362 | dev_err(sst->dev, "request fw failed %d\n", retval); | 358 | dev_err(sst->dev, "request fw failed %d\n", retval); |
363 | return retval; | 359 | return retval; |
364 | } | 360 | } |
361 | if (fw == NULL) { | ||
362 | dev_err(sst->dev, "fw is returning as null\n"); | ||
363 | return -EINVAL; | ||
364 | } | ||
365 | mutex_lock(&sst->sst_lock); | 365 | mutex_lock(&sst->sst_lock); |
366 | retval = sst_cache_and_parse_fw(sst, fw); | 366 | retval = sst_cache_and_parse_fw(sst, fw); |
367 | mutex_unlock(&sst->sst_lock); | 367 | mutex_unlock(&sst->sst_lock); |
diff --git a/sound/soc/intel/atom/sst/sst_pvt.c b/sound/soc/intel/atom/sst/sst_pvt.c index af93244b4868..00a37a09dc9b 100644 --- a/sound/soc/intel/atom/sst/sst_pvt.c +++ b/sound/soc/intel/atom/sst/sst_pvt.c | |||
@@ -166,11 +166,11 @@ int sst_create_ipc_msg(struct ipc_post **arg, bool large) | |||
166 | { | 166 | { |
167 | struct ipc_post *msg; | 167 | struct ipc_post *msg; |
168 | 168 | ||
169 | msg = kzalloc(sizeof(struct ipc_post), GFP_ATOMIC); | 169 | msg = kzalloc(sizeof(*msg), GFP_KERNEL); |
170 | if (!msg) | 170 | if (!msg) |
171 | return -ENOMEM; | 171 | return -ENOMEM; |
172 | if (large) { | 172 | if (large) { |
173 | msg->mailbox_data = kzalloc(SST_MAILBOX_SIZE, GFP_ATOMIC); | 173 | msg->mailbox_data = kzalloc(SST_MAILBOX_SIZE, GFP_KERNEL); |
174 | if (!msg->mailbox_data) { | 174 | if (!msg->mailbox_data) { |
175 | kfree(msg); | 175 | kfree(msg); |
176 | return -ENOMEM; | 176 | return -ENOMEM; |
diff --git a/sound/soc/intel/boards/Kconfig b/sound/soc/intel/boards/Kconfig index b177db2a0dbb..0a7e40d06395 100644 --- a/sound/soc/intel/boards/Kconfig +++ b/sound/soc/intel/boards/Kconfig | |||
@@ -172,7 +172,7 @@ config SND_SOC_INTEL_BYT_CHT_NOCODEC_MACH | |||
172 | 172 | ||
173 | endif ## SND_SST_ATOM_HIFI2_PLATFORM | 173 | endif ## SND_SST_ATOM_HIFI2_PLATFORM |
174 | 174 | ||
175 | if SND_SOC_INTEL_SKYLAKE | 175 | if SND_SOC_INTEL_SKL |
176 | 176 | ||
177 | config SND_SOC_INTEL_SKL_RT286_MACH | 177 | config SND_SOC_INTEL_SKL_RT286_MACH |
178 | tristate "SKL with RT286 I2S mode" | 178 | tristate "SKL with RT286 I2S mode" |
@@ -212,6 +212,10 @@ config SND_SOC_INTEL_SKL_NAU88L25_MAX98357A_MACH | |||
212 | Say Y or m if you have such a device. This is a recommended option. | 212 | Say Y or m if you have such a device. This is a recommended option. |
213 | If unsure select "N". | 213 | If unsure select "N". |
214 | 214 | ||
215 | endif ## SND_SOC_INTEL_SKL | ||
216 | |||
217 | if SND_SOC_INTEL_APL | ||
218 | |||
215 | config SND_SOC_INTEL_BXT_DA7219_MAX98357A_MACH | 219 | config SND_SOC_INTEL_BXT_DA7219_MAX98357A_MACH |
216 | tristate "Broxton with DA7219 and MAX98357A in I2S Mode" | 220 | tristate "Broxton with DA7219 and MAX98357A in I2S Mode" |
217 | depends on MFD_INTEL_LPSS && I2C && ACPI | 221 | depends on MFD_INTEL_LPSS && I2C && ACPI |
@@ -239,6 +243,10 @@ config SND_SOC_INTEL_BXT_RT298_MACH | |||
239 | Say Y or m if you have such a device. This is a recommended option. | 243 | Say Y or m if you have such a device. This is a recommended option. |
240 | If unsure select "N". | 244 | If unsure select "N". |
241 | 245 | ||
246 | endif ## SND_SOC_INTEL_APL | ||
247 | |||
248 | if SND_SOC_INTEL_KBL | ||
249 | |||
242 | config SND_SOC_INTEL_KBL_RT5663_MAX98927_MACH | 250 | config SND_SOC_INTEL_KBL_RT5663_MAX98927_MACH |
243 | tristate "KBL with RT5663 and MAX98927 in I2S Mode" | 251 | tristate "KBL with RT5663 and MAX98927 in I2S Mode" |
244 | depends on MFD_INTEL_LPSS && I2C && ACPI | 252 | depends on MFD_INTEL_LPSS && I2C && ACPI |
@@ -293,6 +301,20 @@ config SND_SOC_INTEL_KBL_DA7219_MAX98927_MACH | |||
293 | Say Y if you have such a device. | 301 | Say Y if you have such a device. |
294 | If unsure select "N". | 302 | If unsure select "N". |
295 | 303 | ||
304 | config SND_SOC_INTEL_KBL_RT5660_MACH | ||
305 | tristate "KBL with RT5660 in I2S Mode" | ||
306 | depends on MFD_INTEL_LPSS && I2C && ACPI | ||
307 | select SND_SOC_RT5660 | ||
308 | select SND_SOC_HDAC_HDMI | ||
309 | help | ||
310 | This adds support for ASoC Onboard Codec I2S machine driver. This will | ||
311 | create an alsa sound card for RT5660 I2S audio codec. | ||
312 | Say Y if you have such a device. | ||
313 | |||
314 | endif ## SND_SOC_INTEL_KBL | ||
315 | |||
316 | if SND_SOC_INTEL_GLK | ||
317 | |||
296 | config SND_SOC_INTEL_GLK_RT5682_MAX98357A_MACH | 318 | config SND_SOC_INTEL_GLK_RT5682_MAX98357A_MACH |
297 | tristate "GLK with RT5682 and MAX98357A in I2S Mode" | 319 | tristate "GLK with RT5682 and MAX98357A in I2S Mode" |
298 | depends on MFD_INTEL_LPSS && I2C && ACPI | 320 | depends on MFD_INTEL_LPSS && I2C && ACPI |
@@ -307,7 +329,7 @@ config SND_SOC_INTEL_GLK_RT5682_MAX98357A_MACH | |||
307 | Say Y if you have such a device. | 329 | Say Y if you have such a device. |
308 | If unsure select "N". | 330 | If unsure select "N". |
309 | 331 | ||
310 | endif ## SND_SOC_INTEL_SKYLAKE | 332 | endif ## SND_SOC_INTEL_GLK |
311 | 333 | ||
312 | if SND_SOC_INTEL_SKYLAKE_HDAUDIO_CODEC | 334 | if SND_SOC_INTEL_SKYLAKE_HDAUDIO_CODEC |
313 | 335 | ||
diff --git a/sound/soc/intel/boards/Makefile b/sound/soc/intel/boards/Makefile index 5381e27df9cc..bf072ea299b7 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 | |||
20 | snd-soc-kbl_da7219_max98927-objs := kbl_da7219_max98927.o | 20 | snd-soc-kbl_da7219_max98927-objs := kbl_da7219_max98927.o |
21 | snd-soc-kbl_rt5663_max98927-objs := kbl_rt5663_max98927.o | 21 | snd-soc-kbl_rt5663_max98927-objs := kbl_rt5663_max98927.o |
22 | snd-soc-kbl_rt5663_rt5514_max98927-objs := kbl_rt5663_rt5514_max98927.o | 22 | snd-soc-kbl_rt5663_rt5514_max98927-objs := kbl_rt5663_rt5514_max98927.o |
23 | snd-soc-kbl_rt5660-objs := kbl_rt5660.o | ||
23 | snd-soc-skl_rt286-objs := skl_rt286.o | 24 | snd-soc-skl_rt286-objs := skl_rt286.o |
24 | snd-soc-skl_hda_dsp-objs := skl_hda_dsp_generic.o skl_hda_dsp_common.o | 25 | snd-soc-skl_hda_dsp-objs := skl_hda_dsp_generic.o skl_hda_dsp_common.o |
25 | snd-skl_nau88l25_max98357a-objs := skl_nau88l25_max98357a.o | 26 | snd-skl_nau88l25_max98357a-objs := skl_nau88l25_max98357a.o |
@@ -46,6 +47,7 @@ obj-$(CONFIG_SND_SOC_INTEL_KBL_DA7219_MAX98357A_MACH) += snd-soc-kbl_da7219_max9 | |||
46 | obj-$(CONFIG_SND_SOC_INTEL_KBL_DA7219_MAX98927_MACH) += snd-soc-kbl_da7219_max98927.o | 47 | obj-$(CONFIG_SND_SOC_INTEL_KBL_DA7219_MAX98927_MACH) += snd-soc-kbl_da7219_max98927.o |
47 | obj-$(CONFIG_SND_SOC_INTEL_KBL_RT5663_MAX98927_MACH) += snd-soc-kbl_rt5663_max98927.o | 48 | obj-$(CONFIG_SND_SOC_INTEL_KBL_RT5663_MAX98927_MACH) += snd-soc-kbl_rt5663_max98927.o |
48 | obj-$(CONFIG_SND_SOC_INTEL_KBL_RT5663_RT5514_MAX98927_MACH) += snd-soc-kbl_rt5663_rt5514_max98927.o | 49 | obj-$(CONFIG_SND_SOC_INTEL_KBL_RT5663_RT5514_MAX98927_MACH) += snd-soc-kbl_rt5663_rt5514_max98927.o |
50 | obj-$(CONFIG_SND_SOC_INTEL_KBL_RT5660_MACH) += snd-soc-kbl_rt5660.o | ||
49 | obj-$(CONFIG_SND_SOC_INTEL_SKL_RT286_MACH) += snd-soc-skl_rt286.o | 51 | obj-$(CONFIG_SND_SOC_INTEL_SKL_RT286_MACH) += snd-soc-skl_rt286.o |
50 | obj-$(CONFIG_SND_SOC_INTEL_SKL_NAU88L25_MAX98357A_MACH) += snd-skl_nau88l25_max98357a.o | 52 | obj-$(CONFIG_SND_SOC_INTEL_SKL_NAU88L25_MAX98357A_MACH) += snd-skl_nau88l25_max98357a.o |
51 | obj-$(CONFIG_SND_SOC_INTEL_SKL_NAU88L25_SSM4567_MACH) += snd-soc-skl_nau88l25_ssm4567.o | 53 | obj-$(CONFIG_SND_SOC_INTEL_SKL_NAU88L25_SSM4567_MACH) += snd-soc-skl_nau88l25_ssm4567.o |
diff --git a/sound/soc/intel/boards/bytcr_rt5640.c b/sound/soc/intel/boards/bytcr_rt5640.c index 8587bd3d1cc1..a22366ce33c4 100644 --- a/sound/soc/intel/boards/bytcr_rt5640.c +++ b/sound/soc/intel/boards/bytcr_rt5640.c | |||
@@ -29,7 +29,6 @@ | |||
29 | #include <linux/input.h> | 29 | #include <linux/input.h> |
30 | #include <linux/slab.h> | 30 | #include <linux/slab.h> |
31 | #include <asm/cpu_device_id.h> | 31 | #include <asm/cpu_device_id.h> |
32 | #include <asm/platform_sst_audio.h> | ||
33 | #include <sound/pcm.h> | 32 | #include <sound/pcm.h> |
34 | #include <sound/pcm_params.h> | 33 | #include <sound/pcm_params.h> |
35 | #include <sound/soc.h> | 34 | #include <sound/soc.h> |
@@ -674,6 +673,33 @@ static const struct dmi_system_id byt_rt5640_quirk_table[] = { | |||
674 | BYT_RT5640_SSP0_AIF2 | | 673 | BYT_RT5640_SSP0_AIF2 | |
675 | BYT_RT5640_MCLK_EN), | 674 | BYT_RT5640_MCLK_EN), |
676 | }, | 675 | }, |
676 | { /* Point of View Mobii TAB-P1005W-232 (V2.0) */ | ||
677 | .matches = { | ||
678 | DMI_EXACT_MATCH(DMI_BOARD_VENDOR, "POV"), | ||
679 | DMI_EXACT_MATCH(DMI_BOARD_NAME, "I102A"), | ||
680 | }, | ||
681 | .driver_data = (void *)(BYT_RT5640_IN1_MAP | | ||
682 | BYT_RT5640_JD_SRC_JD2_IN4N | | ||
683 | BYT_RT5640_OVCD_TH_2000UA | | ||
684 | BYT_RT5640_OVCD_SF_0P75 | | ||
685 | BYT_RT5640_DIFF_MIC | | ||
686 | BYT_RT5640_SSP0_AIF1 | | ||
687 | BYT_RT5640_MCLK_EN), | ||
688 | }, | ||
689 | { | ||
690 | /* Prowise PT301 */ | ||
691 | .matches = { | ||
692 | DMI_MATCH(DMI_SYS_VENDOR, "Prowise"), | ||
693 | DMI_MATCH(DMI_PRODUCT_NAME, "PT301"), | ||
694 | }, | ||
695 | .driver_data = (void *)(BYT_RT5640_IN1_MAP | | ||
696 | BYT_RT5640_JD_SRC_JD2_IN4N | | ||
697 | BYT_RT5640_OVCD_TH_2000UA | | ||
698 | BYT_RT5640_OVCD_SF_0P75 | | ||
699 | BYT_RT5640_DIFF_MIC | | ||
700 | BYT_RT5640_SSP0_AIF1 | | ||
701 | BYT_RT5640_MCLK_EN), | ||
702 | }, | ||
677 | { | 703 | { |
678 | .matches = { | 704 | .matches = { |
679 | DMI_MATCH(DMI_BOARD_VENDOR, "TECLAST"), | 705 | DMI_MATCH(DMI_BOARD_VENDOR, "TECLAST"), |
@@ -1152,10 +1178,7 @@ static int snd_byt_rt5640_mc_probe(struct platform_device *pdev) | |||
1152 | * (will be overridden if DMI quirk is detected) | 1178 | * (will be overridden if DMI quirk is detected) |
1153 | */ | 1179 | */ |
1154 | if (is_valleyview()) { | 1180 | if (is_valleyview()) { |
1155 | struct sst_platform_info *p_info = mach->pdata; | 1181 | if (mach->mach_params.acpi_ipc_irq_index == 0) |
1156 | const struct sst_res_info *res_info = p_info->res_info; | ||
1157 | |||
1158 | if (res_info->acpi_ipc_irq_index == 0) | ||
1159 | is_bytcr = true; | 1182 | is_bytcr = true; |
1160 | } | 1183 | } |
1161 | 1184 | ||
diff --git a/sound/soc/intel/boards/bytcr_rt5651.c b/sound/soc/intel/boards/bytcr_rt5651.c index c44298130720..e528995668b7 100644 --- a/sound/soc/intel/boards/bytcr_rt5651.c +++ b/sound/soc/intel/boards/bytcr_rt5651.c | |||
@@ -32,7 +32,6 @@ | |||
32 | #include <linux/slab.h> | 32 | #include <linux/slab.h> |
33 | #include <asm/cpu_device_id.h> | 33 | #include <asm/cpu_device_id.h> |
34 | #include <asm/intel-family.h> | 34 | #include <asm/intel-family.h> |
35 | #include <asm/platform_sst_audio.h> | ||
36 | #include <sound/pcm.h> | 35 | #include <sound/pcm.h> |
37 | #include <sound/pcm_params.h> | 36 | #include <sound/pcm_params.h> |
38 | #include <sound/soc.h> | 37 | #include <sound/soc.h> |
@@ -920,10 +919,7 @@ static int snd_byt_rt5651_mc_probe(struct platform_device *pdev) | |||
920 | * (will be overridden if DMI quirk is detected) | 919 | * (will be overridden if DMI quirk is detected) |
921 | */ | 920 | */ |
922 | if (x86_match_cpu(baytrail_cpu_ids)) { | 921 | if (x86_match_cpu(baytrail_cpu_ids)) { |
923 | struct sst_platform_info *p_info = mach->pdata; | 922 | if (mach->mach_params.acpi_ipc_irq_index == 0) |
924 | const struct sst_res_info *res_info = p_info->res_info; | ||
925 | |||
926 | if (res_info->acpi_ipc_irq_index == 0) | ||
927 | is_bytcr = true; | 923 | is_bytcr = true; |
928 | } | 924 | } |
929 | 925 | ||
diff --git a/sound/soc/intel/boards/cht_bsw_rt5645.c b/sound/soc/intel/boards/cht_bsw_rt5645.c index f5a5ea6a093c..250a356a0cbf 100644 --- a/sound/soc/intel/boards/cht_bsw_rt5645.c +++ b/sound/soc/intel/boards/cht_bsw_rt5645.c | |||
@@ -27,7 +27,6 @@ | |||
27 | #include <linux/dmi.h> | 27 | #include <linux/dmi.h> |
28 | #include <linux/slab.h> | 28 | #include <linux/slab.h> |
29 | #include <asm/cpu_device_id.h> | 29 | #include <asm/cpu_device_id.h> |
30 | #include <asm/platform_sst_audio.h> | ||
31 | #include <sound/pcm.h> | 30 | #include <sound/pcm.h> |
32 | #include <sound/pcm_params.h> | 31 | #include <sound/pcm_params.h> |
33 | #include <sound/soc.h> | 32 | #include <sound/soc.h> |
@@ -585,10 +584,7 @@ static int snd_cht_mc_probe(struct platform_device *pdev) | |||
585 | * (will be overridden if DMI quirk is detected) | 584 | * (will be overridden if DMI quirk is detected) |
586 | */ | 585 | */ |
587 | if (is_valleyview()) { | 586 | if (is_valleyview()) { |
588 | struct sst_platform_info *p_info = mach->pdata; | 587 | if (mach->mach_params.acpi_ipc_irq_index == 0) |
589 | const struct sst_res_info *res_info = p_info->res_info; | ||
590 | |||
591 | if (res_info->acpi_ipc_irq_index == 0) | ||
592 | is_bytcr = true; | 588 | is_bytcr = true; |
593 | } | 589 | } |
594 | 590 | ||
diff --git a/sound/soc/intel/boards/cht_bsw_rt5672.c b/sound/soc/intel/boards/cht_bsw_rt5672.c index 51f0d45d6f8f..9de64f447e7b 100644 --- a/sound/soc/intel/boards/cht_bsw_rt5672.c +++ b/sound/soc/intel/boards/cht_bsw_rt5672.c | |||
@@ -403,7 +403,7 @@ static int snd_cht_mc_probe(struct platform_device *pdev) | |||
403 | const char *i2c_name; | 403 | const char *i2c_name; |
404 | int i; | 404 | int i; |
405 | 405 | ||
406 | drv = devm_kzalloc(&pdev->dev, sizeof(*drv), GFP_ATOMIC); | 406 | drv = devm_kzalloc(&pdev->dev, sizeof(*drv), GFP_KERNEL); |
407 | if (!drv) | 407 | if (!drv) |
408 | return -ENOMEM; | 408 | return -ENOMEM; |
409 | 409 | ||
diff --git a/sound/soc/intel/boards/glk_rt5682_max98357a.c b/sound/soc/intel/boards/glk_rt5682_max98357a.c index c4b94e2617c5..c74c4f17316f 100644 --- a/sound/soc/intel/boards/glk_rt5682_max98357a.c +++ b/sound/soc/intel/boards/glk_rt5682_max98357a.c | |||
@@ -603,7 +603,7 @@ static int geminilake_audio_probe(struct platform_device *pdev) | |||
603 | { | 603 | { |
604 | struct glk_card_private *ctx; | 604 | struct glk_card_private *ctx; |
605 | 605 | ||
606 | ctx = devm_kzalloc(&pdev->dev, sizeof(*ctx), GFP_ATOMIC); | 606 | ctx = devm_kzalloc(&pdev->dev, sizeof(*ctx), GFP_KERNEL); |
607 | if (!ctx) | 607 | if (!ctx) |
608 | return -ENOMEM; | 608 | return -ENOMEM; |
609 | 609 | ||
diff --git a/sound/soc/intel/boards/kbl_da7219_max98927.c b/sound/soc/intel/boards/kbl_da7219_max98927.c index 3fa1c3ca6d37..723a4935ed76 100644 --- a/sound/soc/intel/boards/kbl_da7219_max98927.c +++ b/sound/soc/intel/boards/kbl_da7219_max98927.c | |||
@@ -262,9 +262,9 @@ static int kabylake_da7219_codec_init(struct snd_soc_pcm_runtime *rtd) | |||
262 | 262 | ||
263 | jack = &ctx->kabylake_headset; | 263 | jack = &ctx->kabylake_headset; |
264 | snd_jack_set_key(jack->jack, SND_JACK_BTN_0, KEY_PLAYPAUSE); | 264 | snd_jack_set_key(jack->jack, SND_JACK_BTN_0, KEY_PLAYPAUSE); |
265 | snd_jack_set_key(jack->jack, SND_JACK_BTN_1, KEY_VOICECOMMAND); | 265 | snd_jack_set_key(jack->jack, SND_JACK_BTN_1, KEY_VOLUMEUP); |
266 | snd_jack_set_key(jack->jack, SND_JACK_BTN_2, KEY_VOLUMEUP); | 266 | snd_jack_set_key(jack->jack, SND_JACK_BTN_2, KEY_VOLUMEDOWN); |
267 | snd_jack_set_key(jack->jack, SND_JACK_BTN_3, KEY_VOLUMEDOWN); | 267 | snd_jack_set_key(jack->jack, SND_JACK_BTN_3, KEY_VOICECOMMAND); |
268 | 268 | ||
269 | da7219_aad_jack_det(component, &ctx->kabylake_headset); | 269 | da7219_aad_jack_det(component, &ctx->kabylake_headset); |
270 | 270 | ||
@@ -441,7 +441,7 @@ static int kabylake_refcap_startup(struct snd_pcm_substream *substream) | |||
441 | } | 441 | } |
442 | 442 | ||
443 | 443 | ||
444 | static struct snd_soc_ops skylaye_refcap_ops = { | 444 | static struct snd_soc_ops skylake_refcap_ops = { |
445 | .startup = kabylake_refcap_startup, | 445 | .startup = kabylake_refcap_startup, |
446 | }; | 446 | }; |
447 | 447 | ||
@@ -525,7 +525,7 @@ static struct snd_soc_dai_link kabylake_dais[] = { | |||
525 | .dpcm_capture = 1, | 525 | .dpcm_capture = 1, |
526 | .nonatomic = 1, | 526 | .nonatomic = 1, |
527 | .dynamic = 1, | 527 | .dynamic = 1, |
528 | .ops = &skylaye_refcap_ops, | 528 | .ops = &skylake_refcap_ops, |
529 | }, | 529 | }, |
530 | [KBL_DPCM_AUDIO_DMIC_CP] = { | 530 | [KBL_DPCM_AUDIO_DMIC_CP] = { |
531 | .name = "Kbl Audio DMIC cap", | 531 | .name = "Kbl Audio DMIC cap", |
@@ -736,7 +736,7 @@ static struct snd_soc_dai_link kabylake_max98927_dais[] = { | |||
736 | .dpcm_capture = 1, | 736 | .dpcm_capture = 1, |
737 | .nonatomic = 1, | 737 | .nonatomic = 1, |
738 | .dynamic = 1, | 738 | .dynamic = 1, |
739 | .ops = &skylaye_refcap_ops, | 739 | .ops = &skylake_refcap_ops, |
740 | }, | 740 | }, |
741 | [KBL_DPCM_AUDIO_DMIC_CP] = { | 741 | [KBL_DPCM_AUDIO_DMIC_CP] = { |
742 | .name = "Kbl Audio DMIC cap", | 742 | .name = "Kbl Audio DMIC cap", |
@@ -935,7 +935,7 @@ static int kabylake_audio_probe(struct platform_device *pdev) | |||
935 | { | 935 | { |
936 | struct kbl_codec_private *ctx; | 936 | struct kbl_codec_private *ctx; |
937 | 937 | ||
938 | ctx = devm_kzalloc(&pdev->dev, sizeof(*ctx), GFP_ATOMIC); | 938 | ctx = devm_kzalloc(&pdev->dev, sizeof(*ctx), GFP_KERNEL); |
939 | if (!ctx) | 939 | if (!ctx) |
940 | return -ENOMEM; | 940 | return -ENOMEM; |
941 | 941 | ||
diff --git a/sound/soc/intel/boards/kbl_rt5660.c b/sound/soc/intel/boards/kbl_rt5660.c new file mode 100644 index 000000000000..3255e0029276 --- /dev/null +++ b/sound/soc/intel/boards/kbl_rt5660.c | |||
@@ -0,0 +1,543 @@ | |||
1 | // SPDX-License-Identifier: GPL-2.0 | ||
2 | // Copyright(c) 2018-19 Canonical Corporation. | ||
3 | |||
4 | /* | ||
5 | * Intel Kabylake I2S Machine Driver with RT5660 Codec | ||
6 | * | ||
7 | * Modified from: | ||
8 | * Intel Kabylake I2S Machine driver supporting MAXIM98357a and | ||
9 | * DA7219 codecs | ||
10 | * Also referred to: | ||
11 | * Intel Broadwell I2S Machine driver supporting RT5677 codec | ||
12 | */ | ||
13 | |||
14 | #include <linux/module.h> | ||
15 | #include <linux/platform_device.h> | ||
16 | #include <linux/gpio/consumer.h> | ||
17 | #include <linux/acpi.h> | ||
18 | #include <sound/core.h> | ||
19 | #include <sound/jack.h> | ||
20 | #include <sound/pcm.h> | ||
21 | #include <sound/pcm_params.h> | ||
22 | #include <sound/soc.h> | ||
23 | |||
24 | #include "../../codecs/hdac_hdmi.h" | ||
25 | #include "../../codecs/rt5660.h" | ||
26 | |||
27 | #define KBL_RT5660_CODEC_DAI "rt5660-aif1" | ||
28 | #define DUAL_CHANNEL 2 | ||
29 | |||
30 | static struct snd_soc_card *kabylake_audio_card; | ||
31 | static struct snd_soc_jack skylake_hdmi[3]; | ||
32 | static struct snd_soc_jack lineout_jack; | ||
33 | static struct snd_soc_jack mic_jack; | ||
34 | |||
35 | struct kbl_hdmi_pcm { | ||
36 | struct list_head head; | ||
37 | struct snd_soc_dai *codec_dai; | ||
38 | int device; | ||
39 | }; | ||
40 | |||
41 | struct kbl_codec_private { | ||
42 | struct gpio_desc *gpio_lo_mute; | ||
43 | struct list_head hdmi_pcm_list; | ||
44 | }; | ||
45 | |||
46 | enum { | ||
47 | KBL_DPCM_AUDIO_PB = 0, | ||
48 | KBL_DPCM_AUDIO_CP, | ||
49 | KBL_DPCM_AUDIO_HDMI1_PB, | ||
50 | KBL_DPCM_AUDIO_HDMI2_PB, | ||
51 | KBL_DPCM_AUDIO_HDMI3_PB, | ||
52 | }; | ||
53 | |||
54 | #define GPIO_LINEOUT_MUTE_INDEX 0 | ||
55 | #define GPIO_LINEOUT_DET_INDEX 3 | ||
56 | #define GPIO_LINEIN_DET_INDEX 4 | ||
57 | |||
58 | static const struct acpi_gpio_params lineout_mute_gpio = { GPIO_LINEOUT_MUTE_INDEX, 0, true }; | ||
59 | static const struct acpi_gpio_params lineout_det_gpio = { GPIO_LINEOUT_DET_INDEX, 0, false }; | ||
60 | static const struct acpi_gpio_params mic_det_gpio = { GPIO_LINEIN_DET_INDEX, 0, false }; | ||
61 | |||
62 | |||
63 | static const struct acpi_gpio_mapping acpi_rt5660_gpios[] = { | ||
64 | { "lineout-mute-gpios", &lineout_mute_gpio, 1 }, | ||
65 | { "lineout-det-gpios", &lineout_det_gpio, 1 }, | ||
66 | { "mic-det-gpios", &mic_det_gpio, 1 }, | ||
67 | { NULL }, | ||
68 | }; | ||
69 | |||
70 | static struct snd_soc_jack_pin lineout_jack_pin = { | ||
71 | .pin = "Line Out", | ||
72 | .mask = SND_JACK_LINEOUT, | ||
73 | }; | ||
74 | |||
75 | static struct snd_soc_jack_pin mic_jack_pin = { | ||
76 | .pin = "Line In", | ||
77 | .mask = SND_JACK_MICROPHONE, | ||
78 | }; | ||
79 | |||
80 | static struct snd_soc_jack_gpio lineout_jack_gpio = { | ||
81 | .name = "lineout-det", | ||
82 | .report = SND_JACK_LINEOUT, | ||
83 | .debounce_time = 200, | ||
84 | }; | ||
85 | |||
86 | static struct snd_soc_jack_gpio mic_jack_gpio = { | ||
87 | .name = "mic-det", | ||
88 | .report = SND_JACK_MICROPHONE, | ||
89 | .debounce_time = 200, | ||
90 | }; | ||
91 | |||
92 | static int kabylake_5660_event_lineout(struct snd_soc_dapm_widget *w, | ||
93 | struct snd_kcontrol *k, int event) | ||
94 | { | ||
95 | struct snd_soc_dapm_context *dapm = w->dapm; | ||
96 | struct kbl_codec_private *priv = snd_soc_card_get_drvdata(dapm->card); | ||
97 | |||
98 | gpiod_set_value_cansleep(priv->gpio_lo_mute, | ||
99 | !(SND_SOC_DAPM_EVENT_ON(event))); | ||
100 | |||
101 | return 0; | ||
102 | } | ||
103 | |||
104 | static const struct snd_kcontrol_new kabylake_rt5660_controls[] = { | ||
105 | SOC_DAPM_PIN_SWITCH("Line In"), | ||
106 | SOC_DAPM_PIN_SWITCH("Line Out"), | ||
107 | }; | ||
108 | |||
109 | static const struct snd_soc_dapm_widget kabylake_rt5660_widgets[] = { | ||
110 | SND_SOC_DAPM_MIC("Line In", NULL), | ||
111 | SND_SOC_DAPM_LINE("Line Out", kabylake_5660_event_lineout), | ||
112 | }; | ||
113 | |||
114 | static const struct snd_soc_dapm_route kabylake_rt5660_map[] = { | ||
115 | /* other jacks */ | ||
116 | {"IN1P", NULL, "Line In"}, | ||
117 | {"IN2P", NULL, "Line In"}, | ||
118 | {"Line Out", NULL, "LOUTR"}, | ||
119 | {"Line Out", NULL, "LOUTL"}, | ||
120 | |||
121 | /* CODEC BE connections */ | ||
122 | { "AIF1 Playback", NULL, "ssp0 Tx"}, | ||
123 | { "ssp0 Tx", NULL, "codec0_out"}, | ||
124 | |||
125 | { "codec0_in", NULL, "ssp0 Rx" }, | ||
126 | { "ssp0 Rx", NULL, "AIF1 Capture" }, | ||
127 | |||
128 | { "hifi1", NULL, "iDisp1 Tx"}, | ||
129 | { "iDisp1 Tx", NULL, "iDisp1_out"}, | ||
130 | { "hifi2", NULL, "iDisp2 Tx"}, | ||
131 | { "iDisp2 Tx", NULL, "iDisp2_out"}, | ||
132 | { "hifi3", NULL, "iDisp3 Tx"}, | ||
133 | { "iDisp3 Tx", NULL, "iDisp3_out"}, | ||
134 | }; | ||
135 | |||
136 | static int kabylake_ssp0_fixup(struct snd_soc_pcm_runtime *rtd, | ||
137 | struct snd_pcm_hw_params *params) | ||
138 | { | ||
139 | struct snd_interval *rate = hw_param_interval(params, | ||
140 | SNDRV_PCM_HW_PARAM_RATE); | ||
141 | struct snd_interval *channels = hw_param_interval(params, | ||
142 | SNDRV_PCM_HW_PARAM_CHANNELS); | ||
143 | struct snd_mask *fmt = hw_param_mask(params, SNDRV_PCM_HW_PARAM_FORMAT); | ||
144 | |||
145 | /* The ADSP will convert the FE rate to 48k, stereo */ | ||
146 | rate->min = rate->max = 48000; | ||
147 | channels->min = channels->max = DUAL_CHANNEL; | ||
148 | |||
149 | /* set SSP0 to 24 bit */ | ||
150 | snd_mask_none(fmt); | ||
151 | snd_mask_set_format(fmt, SNDRV_PCM_FORMAT_S24_LE); | ||
152 | |||
153 | return 0; | ||
154 | } | ||
155 | |||
156 | static int kabylake_rt5660_codec_init(struct snd_soc_pcm_runtime *rtd) | ||
157 | { | ||
158 | int ret; | ||
159 | struct kbl_codec_private *ctx = snd_soc_card_get_drvdata(rtd->card); | ||
160 | struct snd_soc_component *component = rtd->codec_dai->component; | ||
161 | struct snd_soc_dapm_context *dapm = snd_soc_component_get_dapm(component); | ||
162 | |||
163 | ret = devm_acpi_dev_add_driver_gpios(component->dev, acpi_rt5660_gpios); | ||
164 | if (ret) | ||
165 | dev_warn(component->dev, "Failed to add driver gpios\n"); | ||
166 | |||
167 | /* Request rt5660 GPIO for lineout mute control, return if fails */ | ||
168 | ctx->gpio_lo_mute = devm_gpiod_get(component->dev, "lineout-mute", | ||
169 | GPIOD_OUT_HIGH); | ||
170 | if (IS_ERR(ctx->gpio_lo_mute)) { | ||
171 | dev_err(component->dev, "Can't find GPIO_MUTE# gpio\n"); | ||
172 | return PTR_ERR(ctx->gpio_lo_mute); | ||
173 | } | ||
174 | |||
175 | /* Create and initialize headphone jack, this jack is not mandatory, don't return if fails */ | ||
176 | ret = snd_soc_card_jack_new(rtd->card, "Lineout Jack", | ||
177 | SND_JACK_LINEOUT, &lineout_jack, | ||
178 | &lineout_jack_pin, 1); | ||
179 | if (ret) | ||
180 | dev_warn(component->dev, "Can't create Lineout jack\n"); | ||
181 | else { | ||
182 | lineout_jack_gpio.gpiod_dev = component->dev; | ||
183 | ret = snd_soc_jack_add_gpios(&lineout_jack, 1, | ||
184 | &lineout_jack_gpio); | ||
185 | if (ret) | ||
186 | dev_warn(component->dev, "Can't add Lineout jack gpio\n"); | ||
187 | } | ||
188 | |||
189 | /* Create and initialize mic jack, this jack is not mandatory, don't return if fails */ | ||
190 | ret = snd_soc_card_jack_new(rtd->card, "Mic Jack", | ||
191 | SND_JACK_MICROPHONE, &mic_jack, | ||
192 | &mic_jack_pin, 1); | ||
193 | if (ret) | ||
194 | dev_warn(component->dev, "Can't create mic jack\n"); | ||
195 | else { | ||
196 | mic_jack_gpio.gpiod_dev = component->dev; | ||
197 | ret = snd_soc_jack_add_gpios(&mic_jack, 1, &mic_jack_gpio); | ||
198 | if (ret) | ||
199 | dev_warn(component->dev, "Can't add mic jack gpio\n"); | ||
200 | } | ||
201 | |||
202 | /* Here we enable some dapms in advance to reduce the pop noise for recording via line-in */ | ||
203 | snd_soc_dapm_force_enable_pin(dapm, "MICBIAS1"); | ||
204 | snd_soc_dapm_force_enable_pin(dapm, "BST1"); | ||
205 | snd_soc_dapm_force_enable_pin(dapm, "BST2"); | ||
206 | |||
207 | return 0; | ||
208 | } | ||
209 | |||
210 | static int kabylake_hdmi_init(struct snd_soc_pcm_runtime *rtd, int device) | ||
211 | { | ||
212 | struct kbl_codec_private *ctx = snd_soc_card_get_drvdata(rtd->card); | ||
213 | struct snd_soc_dai *dai = rtd->codec_dai; | ||
214 | struct kbl_hdmi_pcm *pcm; | ||
215 | |||
216 | pcm = devm_kzalloc(rtd->card->dev, sizeof(*pcm), GFP_KERNEL); | ||
217 | if (!pcm) | ||
218 | return -ENOMEM; | ||
219 | |||
220 | pcm->device = device; | ||
221 | pcm->codec_dai = dai; | ||
222 | |||
223 | list_add_tail(&pcm->head, &ctx->hdmi_pcm_list); | ||
224 | |||
225 | return 0; | ||
226 | } | ||
227 | |||
228 | static int kabylake_hdmi1_init(struct snd_soc_pcm_runtime *rtd) | ||
229 | { | ||
230 | return kabylake_hdmi_init(rtd, KBL_DPCM_AUDIO_HDMI1_PB); | ||
231 | } | ||
232 | |||
233 | static int kabylake_hdmi2_init(struct snd_soc_pcm_runtime *rtd) | ||
234 | { | ||
235 | return kabylake_hdmi_init(rtd, KBL_DPCM_AUDIO_HDMI2_PB); | ||
236 | } | ||
237 | |||
238 | static int kabylake_hdmi3_init(struct snd_soc_pcm_runtime *rtd) | ||
239 | { | ||
240 | return kabylake_hdmi_init(rtd, KBL_DPCM_AUDIO_HDMI3_PB); | ||
241 | } | ||
242 | |||
243 | static int kabylake_rt5660_hw_params(struct snd_pcm_substream *substream, | ||
244 | struct snd_pcm_hw_params *params) | ||
245 | { | ||
246 | struct snd_soc_pcm_runtime *rtd = substream->private_data; | ||
247 | struct snd_soc_dai *codec_dai = rtd->codec_dai; | ||
248 | int ret; | ||
249 | |||
250 | ret = snd_soc_dai_set_sysclk(codec_dai, | ||
251 | RT5660_SCLK_S_PLL1, params_rate(params) * 512, | ||
252 | SND_SOC_CLOCK_IN); | ||
253 | if (ret < 0) { | ||
254 | dev_err(rtd->dev, "snd_soc_dai_set_sysclk err = %d\n", ret); | ||
255 | return ret; | ||
256 | } | ||
257 | |||
258 | ret = snd_soc_dai_set_pll(codec_dai, 0, | ||
259 | RT5660_PLL1_S_BCLK, | ||
260 | params_rate(params) * 50, | ||
261 | params_rate(params) * 512); | ||
262 | if (ret < 0) | ||
263 | dev_err(codec_dai->dev, "can't set codec pll: %d\n", ret); | ||
264 | |||
265 | return ret; | ||
266 | } | ||
267 | |||
268 | static struct snd_soc_ops kabylake_rt5660_ops = { | ||
269 | .hw_params = kabylake_rt5660_hw_params, | ||
270 | }; | ||
271 | |||
272 | static const unsigned int rates[] = { | ||
273 | 48000, | ||
274 | }; | ||
275 | |||
276 | static const struct snd_pcm_hw_constraint_list constraints_rates = { | ||
277 | .count = ARRAY_SIZE(rates), | ||
278 | .list = rates, | ||
279 | .mask = 0, | ||
280 | }; | ||
281 | |||
282 | static const unsigned int channels[] = { | ||
283 | DUAL_CHANNEL, | ||
284 | }; | ||
285 | |||
286 | static const struct snd_pcm_hw_constraint_list constraints_channels = { | ||
287 | .count = ARRAY_SIZE(channels), | ||
288 | .list = channels, | ||
289 | .mask = 0, | ||
290 | }; | ||
291 | |||
292 | static int kbl_fe_startup(struct snd_pcm_substream *substream) | ||
293 | { | ||
294 | struct snd_pcm_runtime *runtime = substream->runtime; | ||
295 | |||
296 | /* | ||
297 | * On this platform for PCM device we support, | ||
298 | * 48Khz | ||
299 | * stereo | ||
300 | * 16 bit audio | ||
301 | */ | ||
302 | |||
303 | runtime->hw.channels_max = DUAL_CHANNEL; | ||
304 | snd_pcm_hw_constraint_list(runtime, 0, SNDRV_PCM_HW_PARAM_CHANNELS, | ||
305 | &constraints_channels); | ||
306 | |||
307 | runtime->hw.formats = SNDRV_PCM_FMTBIT_S16_LE; | ||
308 | snd_pcm_hw_constraint_msbits(runtime, 0, 16, 16); | ||
309 | |||
310 | snd_pcm_hw_constraint_list(runtime, 0, | ||
311 | SNDRV_PCM_HW_PARAM_RATE, &constraints_rates); | ||
312 | |||
313 | return 0; | ||
314 | } | ||
315 | |||
316 | static const struct snd_soc_ops kabylake_rt5660_fe_ops = { | ||
317 | .startup = kbl_fe_startup, | ||
318 | }; | ||
319 | |||
320 | /* kabylake digital audio interface glue - connects rt5660 codec <--> CPU */ | ||
321 | static struct snd_soc_dai_link kabylake_rt5660_dais[] = { | ||
322 | /* Front End DAI links */ | ||
323 | [KBL_DPCM_AUDIO_PB] = { | ||
324 | .name = "Kbl Audio Port", | ||
325 | .stream_name = "Audio", | ||
326 | .cpu_dai_name = "System Pin", | ||
327 | .platform_name = "0000:00:1f.3", | ||
328 | .dynamic = 1, | ||
329 | .codec_name = "snd-soc-dummy", | ||
330 | .codec_dai_name = "snd-soc-dummy-dai", | ||
331 | .nonatomic = 1, | ||
332 | .trigger = { | ||
333 | SND_SOC_DPCM_TRIGGER_POST, SND_SOC_DPCM_TRIGGER_POST}, | ||
334 | .dpcm_playback = 1, | ||
335 | .ops = &kabylake_rt5660_fe_ops, | ||
336 | }, | ||
337 | [KBL_DPCM_AUDIO_CP] = { | ||
338 | .name = "Kbl Audio Capture Port", | ||
339 | .stream_name = "Audio Record", | ||
340 | .cpu_dai_name = "System Pin", | ||
341 | .platform_name = "0000:00:1f.3", | ||
342 | .dynamic = 1, | ||
343 | .codec_name = "snd-soc-dummy", | ||
344 | .codec_dai_name = "snd-soc-dummy-dai", | ||
345 | .nonatomic = 1, | ||
346 | .trigger = { | ||
347 | SND_SOC_DPCM_TRIGGER_POST, SND_SOC_DPCM_TRIGGER_POST}, | ||
348 | .dpcm_capture = 1, | ||
349 | .ops = &kabylake_rt5660_fe_ops, | ||
350 | }, | ||
351 | [KBL_DPCM_AUDIO_HDMI1_PB] = { | ||
352 | .name = "Kbl HDMI Port1", | ||
353 | .stream_name = "Hdmi1", | ||
354 | .cpu_dai_name = "HDMI1 Pin", | ||
355 | .codec_name = "snd-soc-dummy", | ||
356 | .codec_dai_name = "snd-soc-dummy-dai", | ||
357 | .platform_name = "0000:00:1f.3", | ||
358 | .dpcm_playback = 1, | ||
359 | .init = NULL, | ||
360 | .trigger = { | ||
361 | SND_SOC_DPCM_TRIGGER_POST, SND_SOC_DPCM_TRIGGER_POST}, | ||
362 | .nonatomic = 1, | ||
363 | .dynamic = 1, | ||
364 | }, | ||
365 | [KBL_DPCM_AUDIO_HDMI2_PB] = { | ||
366 | .name = "Kbl HDMI Port2", | ||
367 | .stream_name = "Hdmi2", | ||
368 | .cpu_dai_name = "HDMI2 Pin", | ||
369 | .codec_name = "snd-soc-dummy", | ||
370 | .codec_dai_name = "snd-soc-dummy-dai", | ||
371 | .platform_name = "0000:00:1f.3", | ||
372 | .dpcm_playback = 1, | ||
373 | .init = NULL, | ||
374 | .trigger = { | ||
375 | SND_SOC_DPCM_TRIGGER_POST, SND_SOC_DPCM_TRIGGER_POST}, | ||
376 | .nonatomic = 1, | ||
377 | .dynamic = 1, | ||
378 | }, | ||
379 | [KBL_DPCM_AUDIO_HDMI3_PB] = { | ||
380 | .name = "Kbl HDMI Port3", | ||
381 | .stream_name = "Hdmi3", | ||
382 | .cpu_dai_name = "HDMI3 Pin", | ||
383 | .codec_name = "snd-soc-dummy", | ||
384 | .codec_dai_name = "snd-soc-dummy-dai", | ||
385 | .platform_name = "0000:00:1f.3", | ||
386 | .trigger = { | ||
387 | SND_SOC_DPCM_TRIGGER_POST, SND_SOC_DPCM_TRIGGER_POST}, | ||
388 | .dpcm_playback = 1, | ||
389 | .init = NULL, | ||
390 | .nonatomic = 1, | ||
391 | .dynamic = 1, | ||
392 | }, | ||
393 | |||
394 | /* Back End DAI links */ | ||
395 | { | ||
396 | /* SSP0 - Codec */ | ||
397 | .name = "SSP0-Codec", | ||
398 | .id = 0, | ||
399 | .cpu_dai_name = "SSP0 Pin", | ||
400 | .platform_name = "0000:00:1f.3", | ||
401 | .no_pcm = 1, | ||
402 | .codec_name = "i2c-10EC3277:00", | ||
403 | .codec_dai_name = KBL_RT5660_CODEC_DAI, | ||
404 | .init = kabylake_rt5660_codec_init, | ||
405 | .dai_fmt = SND_SOC_DAIFMT_I2S | | ||
406 | SND_SOC_DAIFMT_NB_NF | | ||
407 | SND_SOC_DAIFMT_CBS_CFS, | ||
408 | .ignore_pmdown_time = 1, | ||
409 | .be_hw_params_fixup = kabylake_ssp0_fixup, | ||
410 | .ops = &kabylake_rt5660_ops, | ||
411 | .dpcm_playback = 1, | ||
412 | .dpcm_capture = 1, | ||
413 | }, | ||
414 | { | ||
415 | .name = "iDisp1", | ||
416 | .id = 1, | ||
417 | .cpu_dai_name = "iDisp1 Pin", | ||
418 | .codec_name = "ehdaudio0D2", | ||
419 | .codec_dai_name = "intel-hdmi-hifi1", | ||
420 | .platform_name = "0000:00:1f.3", | ||
421 | .dpcm_playback = 1, | ||
422 | .init = kabylake_hdmi1_init, | ||
423 | .no_pcm = 1, | ||
424 | }, | ||
425 | { | ||
426 | .name = "iDisp2", | ||
427 | .id = 2, | ||
428 | .cpu_dai_name = "iDisp2 Pin", | ||
429 | .codec_name = "ehdaudio0D2", | ||
430 | .codec_dai_name = "intel-hdmi-hifi2", | ||
431 | .platform_name = "0000:00:1f.3", | ||
432 | .init = kabylake_hdmi2_init, | ||
433 | .dpcm_playback = 1, | ||
434 | .no_pcm = 1, | ||
435 | }, | ||
436 | { | ||
437 | .name = "iDisp3", | ||
438 | .id = 3, | ||
439 | .cpu_dai_name = "iDisp3 Pin", | ||
440 | .codec_name = "ehdaudio0D2", | ||
441 | .codec_dai_name = "intel-hdmi-hifi3", | ||
442 | .platform_name = "0000:00:1f.3", | ||
443 | .init = kabylake_hdmi3_init, | ||
444 | .dpcm_playback = 1, | ||
445 | .no_pcm = 1, | ||
446 | }, | ||
447 | }; | ||
448 | |||
449 | |||
450 | #define NAME_SIZE 32 | ||
451 | static int kabylake_card_late_probe(struct snd_soc_card *card) | ||
452 | { | ||
453 | struct kbl_codec_private *ctx = snd_soc_card_get_drvdata(card); | ||
454 | struct kbl_hdmi_pcm *pcm; | ||
455 | struct snd_soc_component *component = NULL; | ||
456 | int err, i = 0; | ||
457 | char jack_name[NAME_SIZE]; | ||
458 | |||
459 | list_for_each_entry(pcm, &ctx->hdmi_pcm_list, head) { | ||
460 | component = pcm->codec_dai->component; | ||
461 | snprintf(jack_name, sizeof(jack_name), | ||
462 | "HDMI/DP, pcm=%d Jack", pcm->device); | ||
463 | err = snd_soc_card_jack_new(card, jack_name, | ||
464 | SND_JACK_AVOUT, &skylake_hdmi[i], | ||
465 | NULL, 0); | ||
466 | |||
467 | if (err) | ||
468 | return err; | ||
469 | |||
470 | err = hdac_hdmi_jack_init(pcm->codec_dai, pcm->device, | ||
471 | &skylake_hdmi[i]); | ||
472 | if (err < 0) | ||
473 | return err; | ||
474 | |||
475 | i++; | ||
476 | |||
477 | } | ||
478 | |||
479 | if (!component) | ||
480 | return -EINVAL; | ||
481 | |||
482 | return hdac_hdmi_jack_port_init(component, &card->dapm); | ||
483 | } | ||
484 | |||
485 | /* kabylake audio machine driver for rt5660 */ | ||
486 | static struct snd_soc_card kabylake_audio_card_rt5660 = { | ||
487 | .name = "kblrt5660", | ||
488 | .owner = THIS_MODULE, | ||
489 | .dai_link = kabylake_rt5660_dais, | ||
490 | .num_links = ARRAY_SIZE(kabylake_rt5660_dais), | ||
491 | .controls = kabylake_rt5660_controls, | ||
492 | .num_controls = ARRAY_SIZE(kabylake_rt5660_controls), | ||
493 | .dapm_widgets = kabylake_rt5660_widgets, | ||
494 | .num_dapm_widgets = ARRAY_SIZE(kabylake_rt5660_widgets), | ||
495 | .dapm_routes = kabylake_rt5660_map, | ||
496 | .num_dapm_routes = ARRAY_SIZE(kabylake_rt5660_map), | ||
497 | .fully_routed = true, | ||
498 | .late_probe = kabylake_card_late_probe, | ||
499 | }; | ||
500 | |||
501 | static int kabylake_audio_probe(struct platform_device *pdev) | ||
502 | { | ||
503 | struct kbl_codec_private *ctx; | ||
504 | |||
505 | ctx = devm_kzalloc(&pdev->dev, sizeof(*ctx), GFP_KERNEL); | ||
506 | if (!ctx) | ||
507 | return -ENOMEM; | ||
508 | |||
509 | INIT_LIST_HEAD(&ctx->hdmi_pcm_list); | ||
510 | |||
511 | kabylake_audio_card = | ||
512 | (struct snd_soc_card *)pdev->id_entry->driver_data; | ||
513 | |||
514 | kabylake_audio_card->dev = &pdev->dev; | ||
515 | snd_soc_card_set_drvdata(kabylake_audio_card, ctx); | ||
516 | return devm_snd_soc_register_card(&pdev->dev, kabylake_audio_card); | ||
517 | } | ||
518 | |||
519 | static const struct platform_device_id kbl_board_ids[] = { | ||
520 | { | ||
521 | .name = "kbl_rt5660", | ||
522 | .driver_data = | ||
523 | (kernel_ulong_t)&kabylake_audio_card_rt5660, | ||
524 | }, | ||
525 | { } | ||
526 | }; | ||
527 | |||
528 | static struct platform_driver kabylake_audio = { | ||
529 | .probe = kabylake_audio_probe, | ||
530 | .driver = { | ||
531 | .name = "kbl_rt5660", | ||
532 | .pm = &snd_soc_pm_ops, | ||
533 | }, | ||
534 | .id_table = kbl_board_ids, | ||
535 | }; | ||
536 | |||
537 | module_platform_driver(kabylake_audio) | ||
538 | |||
539 | /* Module information */ | ||
540 | MODULE_DESCRIPTION("Audio Machine driver-RT5660 in I2S mode"); | ||
541 | MODULE_AUTHOR("Hui Wang <hui.wang@canonical.com>"); | ||
542 | MODULE_LICENSE("GPL v2"); | ||
543 | MODULE_ALIAS("platform:kbl_rt5660"); | ||
diff --git a/sound/soc/intel/boards/kbl_rt5663_max98927.c b/sound/soc/intel/boards/kbl_rt5663_max98927.c index 99e1320c485f..d71475200b08 100644 --- a/sound/soc/intel/boards/kbl_rt5663_max98927.c +++ b/sound/soc/intel/boards/kbl_rt5663_max98927.c | |||
@@ -25,9 +25,9 @@ | |||
25 | #include <sound/pcm.h> | 25 | #include <sound/pcm.h> |
26 | #include <sound/pcm_params.h> | 26 | #include <sound/pcm_params.h> |
27 | #include <sound/soc.h> | 27 | #include <sound/soc.h> |
28 | #include <sound/soc-acpi.h> | ||
28 | #include "../../codecs/rt5663.h" | 29 | #include "../../codecs/rt5663.h" |
29 | #include "../../codecs/hdac_hdmi.h" | 30 | #include "../../codecs/hdac_hdmi.h" |
30 | #include "../skylake/skl.h" | ||
31 | #include <linux/clk.h> | 31 | #include <linux/clk.h> |
32 | #include <linux/clk-provider.h> | 32 | #include <linux/clk-provider.h> |
33 | #include <linux/clkdev.h> | 33 | #include <linux/clkdev.h> |
@@ -586,7 +586,7 @@ static int kabylake_refcap_startup(struct snd_pcm_substream *substream) | |||
586 | &constraints_16000); | 586 | &constraints_16000); |
587 | } | 587 | } |
588 | 588 | ||
589 | static struct snd_soc_ops skylaye_refcap_ops = { | 589 | static struct snd_soc_ops skylake_refcap_ops = { |
590 | .startup = kabylake_refcap_startup, | 590 | .startup = kabylake_refcap_startup, |
591 | }; | 591 | }; |
592 | 592 | ||
@@ -655,7 +655,7 @@ static struct snd_soc_dai_link kabylake_dais[] = { | |||
655 | .dpcm_capture = 1, | 655 | .dpcm_capture = 1, |
656 | .nonatomic = 1, | 656 | .nonatomic = 1, |
657 | .dynamic = 1, | 657 | .dynamic = 1, |
658 | .ops = &skylaye_refcap_ops, | 658 | .ops = &skylake_refcap_ops, |
659 | }, | 659 | }, |
660 | [KBL_DPCM_AUDIO_DMIC_CP] = { | 660 | [KBL_DPCM_AUDIO_DMIC_CP] = { |
661 | .name = "Kbl Audio DMIC cap", | 661 | .name = "Kbl Audio DMIC cap", |
@@ -969,7 +969,7 @@ static struct snd_soc_card kabylake_audio_card_rt5663 = { | |||
969 | static int kabylake_audio_probe(struct platform_device *pdev) | 969 | static int kabylake_audio_probe(struct platform_device *pdev) |
970 | { | 970 | { |
971 | struct kbl_rt5663_private *ctx; | 971 | struct kbl_rt5663_private *ctx; |
972 | struct skl_machine_pdata *pdata; | 972 | struct snd_soc_acpi_mach *mach; |
973 | int ret; | 973 | int ret; |
974 | 974 | ||
975 | ctx = devm_kzalloc(&pdev->dev, sizeof(*ctx), GFP_KERNEL); | 975 | ctx = devm_kzalloc(&pdev->dev, sizeof(*ctx), GFP_KERNEL); |
@@ -984,9 +984,9 @@ static int kabylake_audio_probe(struct platform_device *pdev) | |||
984 | kabylake_audio_card->dev = &pdev->dev; | 984 | kabylake_audio_card->dev = &pdev->dev; |
985 | snd_soc_card_set_drvdata(kabylake_audio_card, ctx); | 985 | snd_soc_card_set_drvdata(kabylake_audio_card, ctx); |
986 | 986 | ||
987 | pdata = dev_get_drvdata(&pdev->dev); | 987 | mach = (&pdev->dev)->platform_data; |
988 | if (pdata) | 988 | if (mach) |
989 | dmic_constraints = pdata->dmic_num == 2 ? | 989 | dmic_constraints = mach->mach_params.dmic_num == 2 ? |
990 | &constraints_dmic_2ch : &constraints_dmic_channels; | 990 | &constraints_dmic_2ch : &constraints_dmic_channels; |
991 | 991 | ||
992 | ctx->mclk = devm_clk_get(&pdev->dev, "ssp1_mclk"); | 992 | ctx->mclk = devm_clk_get(&pdev->dev, "ssp1_mclk"); |
diff --git a/sound/soc/intel/boards/kbl_rt5663_rt5514_max98927.c b/sound/soc/intel/boards/kbl_rt5663_rt5514_max98927.c index a737c915d46a..7044d8c2b187 100644 --- a/sound/soc/intel/boards/kbl_rt5663_rt5514_max98927.c +++ b/sound/soc/intel/boards/kbl_rt5663_rt5514_max98927.c | |||
@@ -26,10 +26,10 @@ | |||
26 | #include <sound/pcm.h> | 26 | #include <sound/pcm.h> |
27 | #include <sound/pcm_params.h> | 27 | #include <sound/pcm_params.h> |
28 | #include <sound/soc.h> | 28 | #include <sound/soc.h> |
29 | #include <sound/soc-acpi.h> | ||
29 | #include "../../codecs/rt5514.h" | 30 | #include "../../codecs/rt5514.h" |
30 | #include "../../codecs/rt5663.h" | 31 | #include "../../codecs/rt5663.h" |
31 | #include "../../codecs/hdac_hdmi.h" | 32 | #include "../../codecs/hdac_hdmi.h" |
32 | #include "../skylake/skl.h" | ||
33 | 33 | ||
34 | #define KBL_REALTEK_CODEC_DAI "rt5663-aif" | 34 | #define KBL_REALTEK_CODEC_DAI "rt5663-aif" |
35 | #define KBL_REALTEK_DMIC_CODEC_DAI "rt5514-aif1" | 35 | #define KBL_REALTEK_DMIC_CODEC_DAI "rt5514-aif1" |
@@ -648,7 +648,7 @@ static struct snd_soc_card kabylake_audio_card = { | |||
648 | static int kabylake_audio_probe(struct platform_device *pdev) | 648 | static int kabylake_audio_probe(struct platform_device *pdev) |
649 | { | 649 | { |
650 | struct kbl_codec_private *ctx; | 650 | struct kbl_codec_private *ctx; |
651 | struct skl_machine_pdata *pdata; | 651 | struct snd_soc_acpi_mach *mach; |
652 | 652 | ||
653 | ctx = devm_kzalloc(&pdev->dev, sizeof(*ctx), GFP_KERNEL); | 653 | ctx = devm_kzalloc(&pdev->dev, sizeof(*ctx), GFP_KERNEL); |
654 | if (!ctx) | 654 | if (!ctx) |
@@ -659,9 +659,9 @@ static int kabylake_audio_probe(struct platform_device *pdev) | |||
659 | kabylake_audio_card.dev = &pdev->dev; | 659 | kabylake_audio_card.dev = &pdev->dev; |
660 | snd_soc_card_set_drvdata(&kabylake_audio_card, ctx); | 660 | snd_soc_card_set_drvdata(&kabylake_audio_card, ctx); |
661 | 661 | ||
662 | pdata = dev_get_drvdata(&pdev->dev); | 662 | mach = (&pdev->dev)->platform_data; |
663 | if (pdata) | 663 | if (mach) |
664 | dmic_constraints = pdata->dmic_num == 2 ? | 664 | dmic_constraints = mach->mach_params.dmic_num == 2 ? |
665 | &constraints_dmic_2ch : &constraints_dmic_channels; | 665 | &constraints_dmic_2ch : &constraints_dmic_channels; |
666 | 666 | ||
667 | return devm_snd_soc_register_card(&pdev->dev, &kabylake_audio_card); | 667 | return devm_snd_soc_register_card(&pdev->dev, &kabylake_audio_card); |
diff --git a/sound/soc/intel/boards/skl_hda_dsp_generic.c b/sound/soc/intel/boards/skl_hda_dsp_generic.c index b415dd4c85f5..b9a21e64ead2 100644 --- a/sound/soc/intel/boards/skl_hda_dsp_generic.c +++ b/sound/soc/intel/boards/skl_hda_dsp_generic.c | |||
@@ -12,8 +12,8 @@ | |||
12 | #include <sound/pcm.h> | 12 | #include <sound/pcm.h> |
13 | #include <sound/pcm_params.h> | 13 | #include <sound/pcm_params.h> |
14 | #include <sound/soc.h> | 14 | #include <sound/soc.h> |
15 | #include <sound/soc-acpi.h> | ||
15 | #include "../../codecs/hdac_hdmi.h" | 16 | #include "../../codecs/hdac_hdmi.h" |
16 | #include "../skylake/skl.h" | ||
17 | #include "skl_hda_dsp_common.h" | 17 | #include "skl_hda_dsp_common.h" |
18 | 18 | ||
19 | static const struct snd_soc_dapm_widget skl_hda_widgets[] = { | 19 | static const struct snd_soc_dapm_widget skl_hda_widgets[] = { |
@@ -101,17 +101,17 @@ static struct snd_soc_card hda_soc_card = { | |||
101 | #define IDISP_ROUTE_COUNT (IDISP_DAI_COUNT * 2) | 101 | #define IDISP_ROUTE_COUNT (IDISP_DAI_COUNT * 2) |
102 | #define IDISP_CODEC_MASK 0x4 | 102 | #define IDISP_CODEC_MASK 0x4 |
103 | 103 | ||
104 | static int skl_hda_fill_card_info(struct skl_machine_pdata *pdata) | 104 | static int skl_hda_fill_card_info(struct snd_soc_acpi_mach_params *mach_params) |
105 | { | 105 | { |
106 | struct snd_soc_card *card = &hda_soc_card; | 106 | struct snd_soc_card *card = &hda_soc_card; |
107 | struct snd_soc_dai_link *dai_link; | 107 | struct snd_soc_dai_link *dai_link; |
108 | u32 codec_count, codec_mask; | 108 | u32 codec_count, codec_mask; |
109 | int i, num_links, num_route; | 109 | int i, num_links, num_route; |
110 | 110 | ||
111 | codec_mask = pdata->codec_mask; | 111 | codec_mask = mach_params->codec_mask; |
112 | codec_count = hweight_long(codec_mask); | 112 | codec_count = hweight_long(codec_mask); |
113 | 113 | ||
114 | if (codec_count == 1 && pdata->codec_mask & IDISP_CODEC_MASK) { | 114 | if (codec_count == 1 && codec_mask & IDISP_CODEC_MASK) { |
115 | num_links = IDISP_DAI_COUNT; | 115 | num_links = IDISP_DAI_COUNT; |
116 | num_route = IDISP_ROUTE_COUNT; | 116 | num_route = IDISP_ROUTE_COUNT; |
117 | } else if (codec_count == 2 && codec_mask & IDISP_CODEC_MASK) { | 117 | } else if (codec_count == 2 && codec_mask & IDISP_CODEC_MASK) { |
@@ -127,30 +127,30 @@ static int skl_hda_fill_card_info(struct skl_machine_pdata *pdata) | |||
127 | card->num_dapm_routes = num_route; | 127 | card->num_dapm_routes = num_route; |
128 | 128 | ||
129 | for_each_card_prelinks(card, i, dai_link) | 129 | for_each_card_prelinks(card, i, dai_link) |
130 | dai_link->platform_name = pdata->platform; | 130 | dai_link->platform_name = mach_params->platform; |
131 | 131 | ||
132 | return 0; | 132 | return 0; |
133 | } | 133 | } |
134 | 134 | ||
135 | static int skl_hda_audio_probe(struct platform_device *pdev) | 135 | static int skl_hda_audio_probe(struct platform_device *pdev) |
136 | { | 136 | { |
137 | struct skl_machine_pdata *pdata; | 137 | struct snd_soc_acpi_mach *mach; |
138 | struct skl_hda_private *ctx; | 138 | struct skl_hda_private *ctx; |
139 | int ret; | 139 | int ret; |
140 | 140 | ||
141 | dev_dbg(&pdev->dev, "%s: entry\n", __func__); | 141 | dev_dbg(&pdev->dev, "%s: entry\n", __func__); |
142 | 142 | ||
143 | ctx = devm_kzalloc(&pdev->dev, sizeof(*ctx), GFP_ATOMIC); | 143 | ctx = devm_kzalloc(&pdev->dev, sizeof(*ctx), GFP_KERNEL); |
144 | if (!ctx) | 144 | if (!ctx) |
145 | return -ENOMEM; | 145 | return -ENOMEM; |
146 | 146 | ||
147 | INIT_LIST_HEAD(&ctx->hdmi_pcm_list); | 147 | INIT_LIST_HEAD(&ctx->hdmi_pcm_list); |
148 | 148 | ||
149 | pdata = dev_get_drvdata(&pdev->dev); | 149 | mach = (&pdev->dev)->platform_data; |
150 | if (!pdata) | 150 | if (!mach) |
151 | return -EINVAL; | 151 | return -EINVAL; |
152 | 152 | ||
153 | ret = skl_hda_fill_card_info(pdata); | 153 | ret = skl_hda_fill_card_info(&mach->mach_params); |
154 | if (ret < 0) { | 154 | if (ret < 0) { |
155 | dev_err(&pdev->dev, "Unsupported HDAudio/iDisp configuration found\n"); | 155 | dev_err(&pdev->dev, "Unsupported HDAudio/iDisp configuration found\n"); |
156 | return ret; | 156 | return ret; |
@@ -158,7 +158,7 @@ static int skl_hda_audio_probe(struct platform_device *pdev) | |||
158 | 158 | ||
159 | ctx->pcm_count = hda_soc_card.num_links; | 159 | ctx->pcm_count = hda_soc_card.num_links; |
160 | ctx->dai_index = 1; /* hdmi codec dai name starts from index 1 */ | 160 | ctx->dai_index = 1; /* hdmi codec dai name starts from index 1 */ |
161 | ctx->platform_name = pdata->platform; | 161 | ctx->platform_name = mach->mach_params.platform; |
162 | 162 | ||
163 | hda_soc_card.dev = &pdev->dev; | 163 | hda_soc_card.dev = &pdev->dev; |
164 | snd_soc_card_set_drvdata(&hda_soc_card, ctx); | 164 | snd_soc_card_set_drvdata(&hda_soc_card, ctx); |
diff --git a/sound/soc/intel/boards/skl_nau88l25_max98357a.c b/sound/soc/intel/boards/skl_nau88l25_max98357a.c index d31482b8c9bb..0922106bd323 100644 --- a/sound/soc/intel/boards/skl_nau88l25_max98357a.c +++ b/sound/soc/intel/boards/skl_nau88l25_max98357a.c | |||
@@ -21,9 +21,9 @@ | |||
21 | #include <sound/pcm.h> | 21 | #include <sound/pcm.h> |
22 | #include <sound/pcm_params.h> | 22 | #include <sound/pcm_params.h> |
23 | #include <sound/soc.h> | 23 | #include <sound/soc.h> |
24 | #include <sound/soc-acpi.h> | ||
24 | #include "../../codecs/nau8825.h" | 25 | #include "../../codecs/nau8825.h" |
25 | #include "../../codecs/hdac_hdmi.h" | 26 | #include "../../codecs/hdac_hdmi.h" |
26 | #include "../skylake/skl.h" | ||
27 | 27 | ||
28 | #define SKL_NUVOTON_CODEC_DAI "nau8825-hifi" | 28 | #define SKL_NUVOTON_CODEC_DAI "nau8825-hifi" |
29 | #define SKL_MAXIM_CODEC_DAI "HiFi" | 29 | #define SKL_MAXIM_CODEC_DAI "HiFi" |
@@ -400,7 +400,7 @@ static int skylake_refcap_startup(struct snd_pcm_substream *substream) | |||
400 | &constraints_16000); | 400 | &constraints_16000); |
401 | } | 401 | } |
402 | 402 | ||
403 | static const struct snd_soc_ops skylaye_refcap_ops = { | 403 | static const struct snd_soc_ops skylake_refcap_ops = { |
404 | .startup = skylake_refcap_startup, | 404 | .startup = skylake_refcap_startup, |
405 | }; | 405 | }; |
406 | 406 | ||
@@ -447,7 +447,7 @@ static struct snd_soc_dai_link skylake_dais[] = { | |||
447 | .dpcm_capture = 1, | 447 | .dpcm_capture = 1, |
448 | .nonatomic = 1, | 448 | .nonatomic = 1, |
449 | .dynamic = 1, | 449 | .dynamic = 1, |
450 | .ops = &skylaye_refcap_ops, | 450 | .ops = &skylake_refcap_ops, |
451 | }, | 451 | }, |
452 | [SKL_DPCM_AUDIO_DMIC_CP] = { | 452 | [SKL_DPCM_AUDIO_DMIC_CP] = { |
453 | .name = "Skl Audio DMIC cap", | 453 | .name = "Skl Audio DMIC cap", |
@@ -641,7 +641,7 @@ static struct snd_soc_card skylake_audio_card = { | |||
641 | static int skylake_audio_probe(struct platform_device *pdev) | 641 | static int skylake_audio_probe(struct platform_device *pdev) |
642 | { | 642 | { |
643 | struct skl_nau8825_private *ctx; | 643 | struct skl_nau8825_private *ctx; |
644 | struct skl_machine_pdata *pdata; | 644 | struct snd_soc_acpi_mach *mach; |
645 | 645 | ||
646 | ctx = devm_kzalloc(&pdev->dev, sizeof(*ctx), GFP_KERNEL); | 646 | ctx = devm_kzalloc(&pdev->dev, sizeof(*ctx), GFP_KERNEL); |
647 | if (!ctx) | 647 | if (!ctx) |
@@ -652,9 +652,9 @@ static int skylake_audio_probe(struct platform_device *pdev) | |||
652 | skylake_audio_card.dev = &pdev->dev; | 652 | skylake_audio_card.dev = &pdev->dev; |
653 | snd_soc_card_set_drvdata(&skylake_audio_card, ctx); | 653 | snd_soc_card_set_drvdata(&skylake_audio_card, ctx); |
654 | 654 | ||
655 | pdata = dev_get_drvdata(&pdev->dev); | 655 | mach = (&pdev->dev)->platform_data; |
656 | if (pdata) | 656 | if (mach) |
657 | dmic_constraints = pdata->dmic_num == 2 ? | 657 | dmic_constraints = mach->mach_params.dmic_num == 2 ? |
658 | &constraints_dmic_2ch : &constraints_dmic_channels; | 658 | &constraints_dmic_2ch : &constraints_dmic_channels; |
659 | 659 | ||
660 | return devm_snd_soc_register_card(&pdev->dev, &skylake_audio_card); | 660 | return devm_snd_soc_register_card(&pdev->dev, &skylake_audio_card); |
diff --git a/sound/soc/intel/boards/skl_nau88l25_ssm4567.c b/sound/soc/intel/boards/skl_nau88l25_ssm4567.c index e877bb60beb1..8433c521d39f 100644 --- a/sound/soc/intel/boards/skl_nau88l25_ssm4567.c +++ b/sound/soc/intel/boards/skl_nau88l25_ssm4567.c | |||
@@ -23,11 +23,11 @@ | |||
23 | #include <sound/core.h> | 23 | #include <sound/core.h> |
24 | #include <sound/pcm.h> | 24 | #include <sound/pcm.h> |
25 | #include <sound/soc.h> | 25 | #include <sound/soc.h> |
26 | #include <sound/soc-acpi.h> | ||
26 | #include <sound/jack.h> | 27 | #include <sound/jack.h> |
27 | #include <sound/pcm_params.h> | 28 | #include <sound/pcm_params.h> |
28 | #include "../../codecs/nau8825.h" | 29 | #include "../../codecs/nau8825.h" |
29 | #include "../../codecs/hdac_hdmi.h" | 30 | #include "../../codecs/hdac_hdmi.h" |
30 | #include "../skylake/skl.h" | ||
31 | 31 | ||
32 | #define SKL_NUVOTON_CODEC_DAI "nau8825-hifi" | 32 | #define SKL_NUVOTON_CODEC_DAI "nau8825-hifi" |
33 | #define SKL_SSM_CODEC_DAI "ssm4567-hifi" | 33 | #define SKL_SSM_CODEC_DAI "ssm4567-hifi" |
@@ -449,7 +449,7 @@ static int skylake_refcap_startup(struct snd_pcm_substream *substream) | |||
449 | &constraints_16000); | 449 | &constraints_16000); |
450 | } | 450 | } |
451 | 451 | ||
452 | static const struct snd_soc_ops skylaye_refcap_ops = { | 452 | static const struct snd_soc_ops skylake_refcap_ops = { |
453 | .startup = skylake_refcap_startup, | 453 | .startup = skylake_refcap_startup, |
454 | }; | 454 | }; |
455 | 455 | ||
@@ -496,7 +496,7 @@ static struct snd_soc_dai_link skylake_dais[] = { | |||
496 | .dpcm_capture = 1, | 496 | .dpcm_capture = 1, |
497 | .nonatomic = 1, | 497 | .nonatomic = 1, |
498 | .dynamic = 1, | 498 | .dynamic = 1, |
499 | .ops = &skylaye_refcap_ops, | 499 | .ops = &skylake_refcap_ops, |
500 | }, | 500 | }, |
501 | [SKL_DPCM_AUDIO_DMIC_CP] = { | 501 | [SKL_DPCM_AUDIO_DMIC_CP] = { |
502 | .name = "Skl Audio DMIC cap", | 502 | .name = "Skl Audio DMIC cap", |
@@ -694,7 +694,7 @@ static struct snd_soc_card skylake_audio_card = { | |||
694 | static int skylake_audio_probe(struct platform_device *pdev) | 694 | static int skylake_audio_probe(struct platform_device *pdev) |
695 | { | 695 | { |
696 | struct skl_nau88125_private *ctx; | 696 | struct skl_nau88125_private *ctx; |
697 | struct skl_machine_pdata *pdata; | 697 | struct snd_soc_acpi_mach *mach; |
698 | 698 | ||
699 | ctx = devm_kzalloc(&pdev->dev, sizeof(*ctx), GFP_KERNEL); | 699 | ctx = devm_kzalloc(&pdev->dev, sizeof(*ctx), GFP_KERNEL); |
700 | if (!ctx) | 700 | if (!ctx) |
@@ -705,9 +705,9 @@ static int skylake_audio_probe(struct platform_device *pdev) | |||
705 | skylake_audio_card.dev = &pdev->dev; | 705 | skylake_audio_card.dev = &pdev->dev; |
706 | snd_soc_card_set_drvdata(&skylake_audio_card, ctx); | 706 | snd_soc_card_set_drvdata(&skylake_audio_card, ctx); |
707 | 707 | ||
708 | pdata = dev_get_drvdata(&pdev->dev); | 708 | mach = (&pdev->dev)->platform_data; |
709 | if (pdata) | 709 | if (mach) |
710 | dmic_constraints = pdata->dmic_num == 2 ? | 710 | dmic_constraints = mach->mach_params.dmic_num == 2 ? |
711 | &constraints_dmic_2ch : &constraints_dmic_channels; | 711 | &constraints_dmic_2ch : &constraints_dmic_channels; |
712 | 712 | ||
713 | return devm_snd_soc_register_card(&pdev->dev, &skylake_audio_card); | 713 | return devm_snd_soc_register_card(&pdev->dev, &skylake_audio_card); |
diff --git a/sound/soc/intel/common/Makefile b/sound/soc/intel/common/Makefile index c1f50a079d34..56c81e20b5bf 100644 --- a/sound/soc/intel/common/Makefile +++ b/sound/soc/intel/common/Makefile | |||
@@ -7,7 +7,7 @@ snd-soc-acpi-intel-match-objs := soc-acpi-intel-byt-match.o soc-acpi-intel-cht-m | |||
7 | soc-acpi-intel-hsw-bdw-match.o \ | 7 | soc-acpi-intel-hsw-bdw-match.o \ |
8 | soc-acpi-intel-skl-match.o soc-acpi-intel-kbl-match.o \ | 8 | soc-acpi-intel-skl-match.o soc-acpi-intel-kbl-match.o \ |
9 | soc-acpi-intel-bxt-match.o soc-acpi-intel-glk-match.o \ | 9 | soc-acpi-intel-bxt-match.o soc-acpi-intel-glk-match.o \ |
10 | soc-acpi-intel-cnl-match.o \ | 10 | soc-acpi-intel-cnl-match.o soc-acpi-intel-icl-match.o \ |
11 | soc-acpi-intel-hda-match.o | 11 | soc-acpi-intel-hda-match.o |
12 | 12 | ||
13 | obj-$(CONFIG_SND_SOC_INTEL_SST) += snd-soc-sst-dsp.o snd-soc-sst-ipc.o | 13 | obj-$(CONFIG_SND_SOC_INTEL_SST) += snd-soc-sst-dsp.o snd-soc-sst-ipc.o |
diff --git a/sound/soc/intel/common/soc-acpi-intel-bxt-match.c b/sound/soc/intel/common/soc-acpi-intel-bxt-match.c index f39386e540d3..61dedc103b19 100644 --- a/sound/soc/intel/common/soc-acpi-intel-bxt-match.c +++ b/sound/soc/intel/common/soc-acpi-intel-bxt-match.c | |||
@@ -6,9 +6,41 @@ | |||
6 | * | 6 | * |
7 | */ | 7 | */ |
8 | 8 | ||
9 | #include <linux/dmi.h> | ||
9 | #include <sound/soc-acpi.h> | 10 | #include <sound/soc-acpi.h> |
10 | #include <sound/soc-acpi-intel-match.h> | 11 | #include <sound/soc-acpi-intel-match.h> |
11 | 12 | ||
13 | enum { | ||
14 | APL_RVP, | ||
15 | }; | ||
16 | |||
17 | static const struct dmi_system_id apl_table[] = { | ||
18 | { | ||
19 | .matches = { | ||
20 | DMI_MATCH(DMI_SYS_VENDOR, "Intel Corp."), | ||
21 | DMI_MATCH(DMI_BOARD_NAME, "Apollolake RVP1A"), | ||
22 | }, | ||
23 | .driver_data = (void *)(APL_RVP), | ||
24 | }, | ||
25 | {} | ||
26 | }; | ||
27 | |||
28 | static struct snd_soc_acpi_mach *apl_quirk(void *arg) | ||
29 | { | ||
30 | struct snd_soc_acpi_mach *mach = arg; | ||
31 | const struct dmi_system_id *dmi_id; | ||
32 | unsigned long apl_machine_id; | ||
33 | |||
34 | dmi_id = dmi_first_match(apl_table); | ||
35 | if (dmi_id) { | ||
36 | apl_machine_id = (unsigned long)dmi_id->driver_data; | ||
37 | if (apl_machine_id == APL_RVP) | ||
38 | return NULL; | ||
39 | } | ||
40 | |||
41 | return mach; | ||
42 | } | ||
43 | |||
12 | static struct snd_soc_acpi_codecs bxt_codecs = { | 44 | static struct snd_soc_acpi_codecs bxt_codecs = { |
13 | .num_codecs = 1, | 45 | .num_codecs = 1, |
14 | .codecs = {"MX98357A"} | 46 | .codecs = {"MX98357A"} |
@@ -19,6 +51,9 @@ struct snd_soc_acpi_mach snd_soc_acpi_intel_bxt_machines[] = { | |||
19 | .id = "INT343A", | 51 | .id = "INT343A", |
20 | .drv_name = "bxt_alc298s_i2s", | 52 | .drv_name = "bxt_alc298s_i2s", |
21 | .fw_filename = "intel/dsp_fw_bxtn.bin", | 53 | .fw_filename = "intel/dsp_fw_bxtn.bin", |
54 | .sof_fw_filename = "intel/sof-apl.ri", | ||
55 | .sof_tplg_filename = "intel/sof-apl-rt298.tplg", | ||
56 | .asoc_plat_name = "0000:00:0e.0", | ||
22 | }, | 57 | }, |
23 | { | 58 | { |
24 | .id = "DLGS7219", | 59 | .id = "DLGS7219", |
@@ -47,6 +82,7 @@ struct snd_soc_acpi_mach snd_soc_acpi_intel_bxt_machines[] = { | |||
47 | { | 82 | { |
48 | .id = "INT34C3", | 83 | .id = "INT34C3", |
49 | .drv_name = "bxt_tdf8532", | 84 | .drv_name = "bxt_tdf8532", |
85 | .machine_quirk = apl_quirk, | ||
50 | .sof_fw_filename = "intel/sof-apl.ri", | 86 | .sof_fw_filename = "intel/sof-apl.ri", |
51 | .sof_tplg_filename = "intel/sof-apl-tdf8532.tplg", | 87 | .sof_tplg_filename = "intel/sof-apl-tdf8532.tplg", |
52 | .asoc_plat_name = "0000:00:0e.0", | 88 | .asoc_plat_name = "0000:00:0e.0", |
diff --git a/sound/soc/intel/common/soc-acpi-intel-icl-match.c b/sound/soc/intel/common/soc-acpi-intel-icl-match.c new file mode 100644 index 000000000000..33b441dca4d3 --- /dev/null +++ b/sound/soc/intel/common/soc-acpi-intel-icl-match.c | |||
@@ -0,0 +1,32 @@ | |||
1 | // SPDX-License-Identifier: GPL-2.0 | ||
2 | /* | ||
3 | * soc-apci-intel-icl-match.c - tables and support for ICL ACPI enumeration. | ||
4 | * | ||
5 | * Copyright (c) 2018, Intel Corporation. | ||
6 | * | ||
7 | */ | ||
8 | |||
9 | #include <sound/soc-acpi.h> | ||
10 | #include <sound/soc-acpi-intel-match.h> | ||
11 | #include "../skylake/skl.h" | ||
12 | |||
13 | static struct skl_machine_pdata icl_pdata = { | ||
14 | .use_tplg_pcm = true, | ||
15 | }; | ||
16 | |||
17 | struct snd_soc_acpi_mach snd_soc_acpi_intel_icl_machines[] = { | ||
18 | { | ||
19 | .id = "INT34C2", | ||
20 | .drv_name = "icl_rt274", | ||
21 | .fw_filename = "intel/dsp_fw_icl.bin", | ||
22 | .pdata = &icl_pdata, | ||
23 | .sof_fw_filename = "intel/sof-icl.ri", | ||
24 | .sof_tplg_filename = "intel/sof-icl-rt274.tplg", | ||
25 | .asoc_plat_name = "0000:00:1f.3", | ||
26 | }, | ||
27 | {}, | ||
28 | }; | ||
29 | EXPORT_SYMBOL_GPL(snd_soc_acpi_intel_icl_machines); | ||
30 | |||
31 | MODULE_LICENSE("GPL v2"); | ||
32 | MODULE_DESCRIPTION("Intel Common ACPI Match module"); | ||
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 a317b7790fce..e6fa6f470526 100644 --- a/sound/soc/intel/common/soc-acpi-intel-kbl-match.c +++ b/sound/soc/intel/common/soc-acpi-intel-kbl-match.c | |||
@@ -96,6 +96,16 @@ struct snd_soc_acpi_mach snd_soc_acpi_intel_kbl_machines[] = { | |||
96 | .quirk_data = &kbl_7219_98927_codecs, | 96 | .quirk_data = &kbl_7219_98927_codecs, |
97 | .pdata = &skl_dmic_data | 97 | .pdata = &skl_dmic_data |
98 | }, | 98 | }, |
99 | { | ||
100 | .id = "10EC5660", | ||
101 | .drv_name = "kbl_rt5660", | ||
102 | .fw_filename = "intel/dsp_fw_kbl.bin", | ||
103 | }, | ||
104 | { | ||
105 | .id = "10EC3277", | ||
106 | .drv_name = "kbl_rt5660", | ||
107 | .fw_filename = "intel/dsp_fw_kbl.bin", | ||
108 | }, | ||
99 | {}, | 109 | {}, |
100 | }; | 110 | }; |
101 | EXPORT_SYMBOL_GPL(snd_soc_acpi_intel_kbl_machines); | 111 | EXPORT_SYMBOL_GPL(snd_soc_acpi_intel_kbl_machines); |
diff --git a/sound/soc/intel/skylake/skl-messages.c b/sound/soc/intel/skylake/skl-messages.c index 8bfb8b0fa3d5..b0e6fb93eaf8 100644 --- a/sound/soc/intel/skylake/skl-messages.c +++ b/sound/soc/intel/skylake/skl-messages.c | |||
@@ -247,6 +247,14 @@ static const struct skl_dsp_ops dsp_ops[] = { | |||
247 | .init_fw = cnl_sst_init_fw, | 247 | .init_fw = cnl_sst_init_fw, |
248 | .cleanup = cnl_sst_dsp_cleanup | 248 | .cleanup = cnl_sst_dsp_cleanup |
249 | }, | 249 | }, |
250 | { | ||
251 | .id = 0xa348, | ||
252 | .num_cores = 4, | ||
253 | .loader_ops = bxt_get_loader_ops, | ||
254 | .init = cnl_sst_dsp_init, | ||
255 | .init_fw = cnl_sst_init_fw, | ||
256 | .cleanup = cnl_sst_dsp_cleanup | ||
257 | }, | ||
250 | }; | 258 | }; |
251 | 259 | ||
252 | const struct skl_dsp_ops *skl_get_dsp_ops(int pci_id) | 260 | const struct skl_dsp_ops *skl_get_dsp_ops(int pci_id) |
diff --git a/sound/soc/intel/skylake/skl-nhlt.c b/sound/soc/intel/skylake/skl-nhlt.c index 01a050cf8775..5d125a3df527 100644 --- a/sound/soc/intel/skylake/skl-nhlt.c +++ b/sound/soc/intel/skylake/skl-nhlt.c | |||
@@ -180,6 +180,9 @@ int skl_get_dmic_geo(struct skl *skl) | |||
180 | unsigned int dmic_geo = 0; | 180 | unsigned int dmic_geo = 0; |
181 | u8 j; | 181 | u8 j; |
182 | 182 | ||
183 | if (!nhlt) | ||
184 | return 0; | ||
185 | |||
183 | epnt = (struct nhlt_endpoint *)nhlt->desc; | 186 | epnt = (struct nhlt_endpoint *)nhlt->desc; |
184 | 187 | ||
185 | for (j = 0; j < nhlt->endpoint_count; j++) { | 188 | for (j = 0; j < nhlt->endpoint_count; j++) { |
diff --git a/sound/soc/intel/skylake/skl-sst-ipc.c b/sound/soc/intel/skylake/skl-sst-ipc.c index 5234fafb758a..9f3ce73593ae 100644 --- a/sound/soc/intel/skylake/skl-sst-ipc.c +++ b/sound/soc/intel/skylake/skl-sst-ipc.c | |||
@@ -249,6 +249,8 @@ enum skl_ipc_glb_reply { | |||
249 | IPC_GLB_REPLY_INVALID_CONFIG_DATA_LEN = 121, | 249 | IPC_GLB_REPLY_INVALID_CONFIG_DATA_LEN = 121, |
250 | IPC_GLB_REPLY_GATEWAY_NOT_INITIALIZED = 140, | 250 | IPC_GLB_REPLY_GATEWAY_NOT_INITIALIZED = 140, |
251 | IPC_GLB_REPLY_GATEWAY_NOT_EXIST = 141, | 251 | IPC_GLB_REPLY_GATEWAY_NOT_EXIST = 141, |
252 | IPC_GLB_REPLY_SCLK_ALREADY_RUNNING = 150, | ||
253 | IPC_GLB_REPLY_MCLK_ALREADY_RUNNING = 151, | ||
252 | 254 | ||
253 | IPC_GLB_REPLY_PPL_NOT_INITIALIZED = 160, | 255 | IPC_GLB_REPLY_PPL_NOT_INITIALIZED = 160, |
254 | IPC_GLB_REPLY_PPL_NOT_EXIST = 161, | 256 | IPC_GLB_REPLY_PPL_NOT_EXIST = 161, |
@@ -392,18 +394,47 @@ int skl_ipc_process_notification(struct sst_generic_ipc *ipc, | |||
392 | return 0; | 394 | return 0; |
393 | } | 395 | } |
394 | 396 | ||
395 | static int skl_ipc_set_reply_error_code(u32 reply) | 397 | struct skl_ipc_err_map { |
398 | const char *msg; | ||
399 | enum skl_ipc_glb_reply reply; | ||
400 | int err; | ||
401 | }; | ||
402 | |||
403 | static struct skl_ipc_err_map skl_err_map[] = { | ||
404 | {"DSP out of memory", IPC_GLB_REPLY_OUT_OF_MEMORY, -ENOMEM}, | ||
405 | {"DSP busy", IPC_GLB_REPLY_BUSY, -EBUSY}, | ||
406 | {"SCLK already running", IPC_GLB_REPLY_SCLK_ALREADY_RUNNING, | ||
407 | IPC_GLB_REPLY_SCLK_ALREADY_RUNNING}, | ||
408 | {"MCLK already running", IPC_GLB_REPLY_MCLK_ALREADY_RUNNING, | ||
409 | IPC_GLB_REPLY_MCLK_ALREADY_RUNNING}, | ||
410 | }; | ||
411 | |||
412 | static int skl_ipc_set_reply_error_code(struct sst_generic_ipc *ipc, u32 reply) | ||
396 | { | 413 | { |
397 | switch (reply) { | 414 | int i; |
398 | case IPC_GLB_REPLY_OUT_OF_MEMORY: | ||
399 | return -ENOMEM; | ||
400 | 415 | ||
401 | case IPC_GLB_REPLY_BUSY: | 416 | for (i = 0; i < ARRAY_SIZE(skl_err_map); i++) { |
402 | return -EBUSY; | 417 | if (skl_err_map[i].reply == reply) |
418 | break; | ||
419 | } | ||
403 | 420 | ||
404 | default: | 421 | if (i == ARRAY_SIZE(skl_err_map)) { |
422 | dev_err(ipc->dev, "ipc FW reply: %d FW Error Code: %u\n", | ||
423 | reply, | ||
424 | ipc->dsp->fw_ops.get_fw_errcode(ipc->dsp)); | ||
405 | return -EINVAL; | 425 | return -EINVAL; |
406 | } | 426 | } |
427 | |||
428 | if (skl_err_map[i].err < 0) | ||
429 | dev_err(ipc->dev, "ipc FW reply: %s FW Error Code: %u\n", | ||
430 | skl_err_map[i].msg, | ||
431 | ipc->dsp->fw_ops.get_fw_errcode(ipc->dsp)); | ||
432 | else | ||
433 | dev_info(ipc->dev, "ipc FW reply: %s FW Error Code: %u\n", | ||
434 | skl_err_map[i].msg, | ||
435 | ipc->dsp->fw_ops.get_fw_errcode(ipc->dsp)); | ||
436 | |||
437 | return skl_err_map[i].err; | ||
407 | } | 438 | } |
408 | 439 | ||
409 | void skl_ipc_process_reply(struct sst_generic_ipc *ipc, | 440 | void skl_ipc_process_reply(struct sst_generic_ipc *ipc, |
@@ -441,10 +472,7 @@ void skl_ipc_process_reply(struct sst_generic_ipc *ipc, | |||
441 | 472 | ||
442 | } | 473 | } |
443 | } else { | 474 | } else { |
444 | msg->errno = skl_ipc_set_reply_error_code(reply); | 475 | msg->errno = skl_ipc_set_reply_error_code(ipc, reply); |
445 | dev_err(ipc->dev, "ipc FW reply: reply=%d\n", reply); | ||
446 | dev_err(ipc->dev, "FW Error Code: %u\n", | ||
447 | ipc->dsp->fw_ops.get_fw_errcode(ipc->dsp)); | ||
448 | switch (IPC_GLB_NOTIFY_MSG_TYPE(header.primary)) { | 476 | switch (IPC_GLB_NOTIFY_MSG_TYPE(header.primary)) { |
449 | case IPC_GLB_LOAD_MULTIPLE_MODS: | 477 | case IPC_GLB_LOAD_MULTIPLE_MODS: |
450 | case IPC_GLB_LOAD_LIBRARY: | 478 | case IPC_GLB_LOAD_LIBRARY: |
diff --git a/sound/soc/intel/skylake/skl.c b/sound/soc/intel/skylake/skl.c index 7487f388e65d..5abd35ca4e41 100644 --- a/sound/soc/intel/skylake/skl.c +++ b/sound/soc/intel/skylake/skl.c | |||
@@ -517,7 +517,7 @@ static int skl_find_machine(struct skl *skl, void *driver_data) | |||
517 | 517 | ||
518 | if (pdata) { | 518 | if (pdata) { |
519 | skl->use_tplg_pcm = pdata->use_tplg_pcm; | 519 | skl->use_tplg_pcm = pdata->use_tplg_pcm; |
520 | pdata->dmic_num = skl_get_dmic_geo(skl); | 520 | mach->mach_params.dmic_num = skl_get_dmic_geo(skl); |
521 | } | 521 | } |
522 | 522 | ||
523 | return 0; | 523 | return 0; |
@@ -527,7 +527,6 @@ static int skl_machine_device_register(struct skl *skl) | |||
527 | { | 527 | { |
528 | struct snd_soc_acpi_mach *mach = skl->mach; | 528 | struct snd_soc_acpi_mach *mach = skl->mach; |
529 | struct hdac_bus *bus = skl_to_bus(skl); | 529 | struct hdac_bus *bus = skl_to_bus(skl); |
530 | struct skl_machine_pdata *pdata; | ||
531 | struct platform_device *pdev; | 530 | struct platform_device *pdev; |
532 | int ret; | 531 | int ret; |
533 | 532 | ||
@@ -537,6 +536,16 @@ static int skl_machine_device_register(struct skl *skl) | |||
537 | return -EIO; | 536 | return -EIO; |
538 | } | 537 | } |
539 | 538 | ||
539 | mach->mach_params.platform = dev_name(bus->dev); | ||
540 | mach->mach_params.codec_mask = bus->codec_mask; | ||
541 | |||
542 | ret = platform_device_add_data(pdev, (const void *)mach, sizeof(*mach)); | ||
543 | if (ret) { | ||
544 | dev_err(bus->dev, "failed to add machine device platform data\n"); | ||
545 | platform_device_put(pdev); | ||
546 | return ret; | ||
547 | } | ||
548 | |||
540 | ret = platform_device_add(pdev); | 549 | ret = platform_device_add(pdev); |
541 | if (ret) { | 550 | if (ret) { |
542 | dev_err(bus->dev, "failed to add machine device\n"); | 551 | dev_err(bus->dev, "failed to add machine device\n"); |
@@ -544,12 +553,6 @@ static int skl_machine_device_register(struct skl *skl) | |||
544 | return -EIO; | 553 | return -EIO; |
545 | } | 554 | } |
546 | 555 | ||
547 | if (mach->pdata) { | ||
548 | pdata = (struct skl_machine_pdata *)mach->pdata; | ||
549 | pdata->platform = dev_name(bus->dev); | ||
550 | pdata->codec_mask = bus->codec_mask; | ||
551 | dev_set_drvdata(&pdev->dev, mach->pdata); | ||
552 | } | ||
553 | 556 | ||
554 | skl->i2s_dev = pdev; | 557 | skl->i2s_dev = pdev; |
555 | 558 | ||
@@ -823,12 +826,10 @@ static void skl_probe_work(struct work_struct *work) | |||
823 | return; | 826 | return; |
824 | } | 827 | } |
825 | 828 | ||
826 | if (bus->ppcap) { | 829 | err = skl_machine_device_register(skl); |
827 | err = skl_machine_device_register(skl); | 830 | if (err < 0) { |
828 | if (err < 0) { | 831 | dev_err(bus->dev, "machine register failed: %d\n", err); |
829 | dev_err(bus->dev, "machine register failed: %d\n", err); | 832 | goto out_err; |
830 | goto out_err; | ||
831 | } | ||
832 | } | 833 | } |
833 | 834 | ||
834 | /* | 835 | /* |
@@ -913,6 +914,21 @@ static int skl_first_init(struct hdac_bus *bus) | |||
913 | unsigned short gcap; | 914 | unsigned short gcap; |
914 | int cp_streams, pb_streams, start_idx; | 915 | int cp_streams, pb_streams, start_idx; |
915 | 916 | ||
917 | /* | ||
918 | * detect DSP by checking class/subclass/prog-id information | ||
919 | * class=04 subclass 03 prog-if 00: no DSP, legacy driver needs to be used | ||
920 | * class=04 subclass 01 prog-if 00: DSP is present (and may be required e.g. for DMIC or SSP support) | ||
921 | * class=04 subclass 03 prog-if 80: either of DSP or legacy mode can be used | ||
922 | */ | ||
923 | if (pci->class == 0x040300) { | ||
924 | dev_err(bus->dev, "The DSP is not enabled on this platform, aborting probe\n"); | ||
925 | return -ENODEV; | ||
926 | } else if (pci->class != 0x040100 && pci->class != 0x040380) { | ||
927 | dev_err(bus->dev, "Unknown PCI class/subclass/prog-if information (0x%06x) found, aborting probe\n", pci->class); | ||
928 | return -ENODEV; | ||
929 | } | ||
930 | dev_info(bus->dev, "DSP detected with PCI class/subclass/prog-if info 0x%06x\n", pci->class); | ||
931 | |||
916 | err = pci_request_regions(pci, "Skylake HD audio"); | 932 | err = pci_request_regions(pci, "Skylake HD audio"); |
917 | if (err < 0) | 933 | if (err < 0) |
918 | return err; | 934 | return err; |
@@ -928,6 +944,12 @@ static int skl_first_init(struct hdac_bus *bus) | |||
928 | 944 | ||
929 | snd_hdac_bus_parse_capabilities(bus); | 945 | snd_hdac_bus_parse_capabilities(bus); |
930 | 946 | ||
947 | /* check if PPCAP exists */ | ||
948 | if (!bus->ppcap) { | ||
949 | dev_err(bus->dev, "bus ppcap not set, HDaudio or DSP not present?\n"); | ||
950 | return -ENODEV; | ||
951 | } | ||
952 | |||
931 | if (skl_acquire_irq(bus, 0) < 0) | 953 | if (skl_acquire_irq(bus, 0) < 0) |
932 | return -EBUSY; | 954 | return -EBUSY; |
933 | 955 | ||
@@ -937,23 +959,25 @@ static int skl_first_init(struct hdac_bus *bus) | |||
937 | gcap = snd_hdac_chip_readw(bus, GCAP); | 959 | gcap = snd_hdac_chip_readw(bus, GCAP); |
938 | dev_dbg(bus->dev, "chipset global capabilities = 0x%x\n", gcap); | 960 | dev_dbg(bus->dev, "chipset global capabilities = 0x%x\n", gcap); |
939 | 961 | ||
940 | /* allow 64bit DMA address if supported by H/W */ | ||
941 | if (!dma_set_mask(bus->dev, DMA_BIT_MASK(64))) { | ||
942 | dma_set_coherent_mask(bus->dev, DMA_BIT_MASK(64)); | ||
943 | } else { | ||
944 | dma_set_mask(bus->dev, DMA_BIT_MASK(32)); | ||
945 | dma_set_coherent_mask(bus->dev, DMA_BIT_MASK(32)); | ||
946 | } | ||
947 | |||
948 | /* read number of streams from GCAP register */ | 962 | /* read number of streams from GCAP register */ |
949 | cp_streams = (gcap >> 8) & 0x0f; | 963 | cp_streams = (gcap >> 8) & 0x0f; |
950 | pb_streams = (gcap >> 12) & 0x0f; | 964 | pb_streams = (gcap >> 12) & 0x0f; |
951 | 965 | ||
952 | if (!pb_streams && !cp_streams) | 966 | if (!pb_streams && !cp_streams) { |
967 | dev_err(bus->dev, "no streams found in GCAP definitions?\n"); | ||
953 | return -EIO; | 968 | return -EIO; |
969 | } | ||
954 | 970 | ||
955 | bus->num_streams = cp_streams + pb_streams; | 971 | bus->num_streams = cp_streams + pb_streams; |
956 | 972 | ||
973 | /* allow 64bit DMA address if supported by H/W */ | ||
974 | if (!dma_set_mask(bus->dev, DMA_BIT_MASK(64))) { | ||
975 | dma_set_coherent_mask(bus->dev, DMA_BIT_MASK(64)); | ||
976 | } else { | ||
977 | dma_set_mask(bus->dev, DMA_BIT_MASK(32)); | ||
978 | dma_set_coherent_mask(bus->dev, DMA_BIT_MASK(32)); | ||
979 | } | ||
980 | |||
957 | /* initialize streams */ | 981 | /* initialize streams */ |
958 | snd_hdac_ext_stream_init_all | 982 | snd_hdac_ext_stream_init_all |
959 | (bus, 0, cp_streams, SNDRV_PCM_STREAM_CAPTURE); | 983 | (bus, 0, cp_streams, SNDRV_PCM_STREAM_CAPTURE); |
@@ -986,8 +1010,10 @@ static int skl_probe(struct pci_dev *pci, | |||
986 | bus = skl_to_bus(skl); | 1010 | bus = skl_to_bus(skl); |
987 | 1011 | ||
988 | err = skl_first_init(bus); | 1012 | err = skl_first_init(bus); |
989 | if (err < 0) | 1013 | if (err < 0) { |
1014 | dev_err(bus->dev, "skl_first_init failed with err: %d\n", err); | ||
990 | goto out_free; | 1015 | goto out_free; |
1016 | } | ||
991 | 1017 | ||
992 | skl->pci_id = pci->device; | 1018 | skl->pci_id = pci->device; |
993 | 1019 | ||
@@ -996,37 +1022,48 @@ static int skl_probe(struct pci_dev *pci, | |||
996 | skl->nhlt = skl_nhlt_init(bus->dev); | 1022 | skl->nhlt = skl_nhlt_init(bus->dev); |
997 | 1023 | ||
998 | if (skl->nhlt == NULL) { | 1024 | if (skl->nhlt == NULL) { |
1025 | #if !IS_ENABLED(CONFIG_SND_SOC_INTEL_SKYLAKE_HDAUDIO_CODEC) | ||
1026 | dev_err(bus->dev, "no nhlt info found\n"); | ||
999 | err = -ENODEV; | 1027 | err = -ENODEV; |
1000 | goto out_free; | 1028 | goto out_free; |
1001 | } | 1029 | #else |
1002 | 1030 | dev_warn(bus->dev, "no nhlt info found, continuing to try to enable HDaudio codec\n"); | |
1003 | err = skl_nhlt_create_sysfs(skl); | 1031 | #endif |
1004 | if (err < 0) | 1032 | } else { |
1005 | goto out_nhlt_free; | ||
1006 | 1033 | ||
1007 | skl_nhlt_update_topology_bin(skl); | 1034 | err = skl_nhlt_create_sysfs(skl); |
1035 | if (err < 0) { | ||
1036 | dev_err(bus->dev, "skl_nhlt_create_sysfs failed with err: %d\n", err); | ||
1037 | goto out_nhlt_free; | ||
1038 | } | ||
1008 | 1039 | ||
1009 | pci_set_drvdata(skl->pci, bus); | 1040 | skl_nhlt_update_topology_bin(skl); |
1010 | 1041 | ||
1011 | /* check if dsp is there */ | ||
1012 | if (bus->ppcap) { | ||
1013 | /* create device for dsp clk */ | 1042 | /* create device for dsp clk */ |
1014 | err = skl_clock_device_register(skl); | 1043 | err = skl_clock_device_register(skl); |
1015 | if (err < 0) | 1044 | if (err < 0) { |
1045 | dev_err(bus->dev, "skl_clock_device_register failed with err: %d\n", err); | ||
1016 | goto out_clk_free; | 1046 | goto out_clk_free; |
1047 | } | ||
1048 | } | ||
1017 | 1049 | ||
1018 | err = skl_find_machine(skl, (void *)pci_id->driver_data); | 1050 | pci_set_drvdata(skl->pci, bus); |
1019 | if (err < 0) | ||
1020 | goto out_nhlt_free; | ||
1021 | 1051 | ||
1022 | err = skl_init_dsp(skl); | 1052 | |
1023 | if (err < 0) { | 1053 | err = skl_find_machine(skl, (void *)pci_id->driver_data); |
1024 | dev_dbg(bus->dev, "error failed to register dsp\n"); | 1054 | if (err < 0) { |
1025 | goto out_nhlt_free; | 1055 | dev_err(bus->dev, "skl_find_machine failed with err: %d\n", err); |
1026 | } | 1056 | goto out_nhlt_free; |
1027 | skl->skl_sst->enable_miscbdcge = skl_enable_miscbdcge; | 1057 | } |
1028 | skl->skl_sst->clock_power_gating = skl_clock_power_gating; | 1058 | |
1059 | err = skl_init_dsp(skl); | ||
1060 | if (err < 0) { | ||
1061 | dev_dbg(bus->dev, "error failed to register dsp\n"); | ||
1062 | goto out_nhlt_free; | ||
1029 | } | 1063 | } |
1064 | skl->skl_sst->enable_miscbdcge = skl_enable_miscbdcge; | ||
1065 | skl->skl_sst->clock_power_gating = skl_clock_power_gating; | ||
1066 | |||
1030 | if (bus->mlcap) | 1067 | if (bus->mlcap) |
1031 | snd_hdac_ext_bus_get_ml_capabilities(bus); | 1068 | snd_hdac_ext_bus_get_ml_capabilities(bus); |
1032 | 1069 | ||
@@ -1034,8 +1071,10 @@ static int skl_probe(struct pci_dev *pci, | |||
1034 | 1071 | ||
1035 | /* create device for soc dmic */ | 1072 | /* create device for soc dmic */ |
1036 | err = skl_dmic_device_register(skl); | 1073 | err = skl_dmic_device_register(skl); |
1037 | if (err < 0) | 1074 | if (err < 0) { |
1075 | dev_err(bus->dev, "skl_dmic_device_register failed with err: %d\n", err); | ||
1038 | goto out_dsp_free; | 1076 | goto out_dsp_free; |
1077 | } | ||
1039 | 1078 | ||
1040 | schedule_work(&skl->probe_work); | 1079 | schedule_work(&skl->probe_work); |
1041 | 1080 | ||
@@ -1103,21 +1142,36 @@ static void skl_remove(struct pci_dev *pci) | |||
1103 | 1142 | ||
1104 | /* PCI IDs */ | 1143 | /* PCI IDs */ |
1105 | static const struct pci_device_id skl_ids[] = { | 1144 | static const struct pci_device_id skl_ids[] = { |
1145 | #if IS_ENABLED(CONFIG_SND_SOC_INTEL_SKL) | ||
1106 | /* Sunrise Point-LP */ | 1146 | /* Sunrise Point-LP */ |
1107 | { PCI_DEVICE(0x8086, 0x9d70), | 1147 | { PCI_DEVICE(0x8086, 0x9d70), |
1108 | .driver_data = (unsigned long)&snd_soc_acpi_intel_skl_machines}, | 1148 | .driver_data = (unsigned long)&snd_soc_acpi_intel_skl_machines}, |
1149 | #endif | ||
1150 | #if IS_ENABLED(CONFIG_SND_SOC_INTEL_APL) | ||
1109 | /* BXT-P */ | 1151 | /* BXT-P */ |
1110 | { PCI_DEVICE(0x8086, 0x5a98), | 1152 | { PCI_DEVICE(0x8086, 0x5a98), |
1111 | .driver_data = (unsigned long)&snd_soc_acpi_intel_bxt_machines}, | 1153 | .driver_data = (unsigned long)&snd_soc_acpi_intel_bxt_machines}, |
1154 | #endif | ||
1155 | #if IS_ENABLED(CONFIG_SND_SOC_INTEL_KBL) | ||
1112 | /* KBL */ | 1156 | /* KBL */ |
1113 | { PCI_DEVICE(0x8086, 0x9D71), | 1157 | { PCI_DEVICE(0x8086, 0x9D71), |
1114 | .driver_data = (unsigned long)&snd_soc_acpi_intel_kbl_machines}, | 1158 | .driver_data = (unsigned long)&snd_soc_acpi_intel_kbl_machines}, |
1159 | #endif | ||
1160 | #if IS_ENABLED(CONFIG_SND_SOC_INTEL_GLK) | ||
1115 | /* GLK */ | 1161 | /* GLK */ |
1116 | { PCI_DEVICE(0x8086, 0x3198), | 1162 | { PCI_DEVICE(0x8086, 0x3198), |
1117 | .driver_data = (unsigned long)&snd_soc_acpi_intel_glk_machines}, | 1163 | .driver_data = (unsigned long)&snd_soc_acpi_intel_glk_machines}, |
1164 | #endif | ||
1165 | #if IS_ENABLED(CONFIG_SND_SOC_INTEL_CNL) | ||
1118 | /* CNL */ | 1166 | /* CNL */ |
1119 | { PCI_DEVICE(0x8086, 0x9dc8), | 1167 | { PCI_DEVICE(0x8086, 0x9dc8), |
1120 | .driver_data = (unsigned long)&snd_soc_acpi_intel_cnl_machines}, | 1168 | .driver_data = (unsigned long)&snd_soc_acpi_intel_cnl_machines}, |
1169 | #endif | ||
1170 | #if IS_ENABLED(CONFIG_SND_SOC_INTEL_CFL) | ||
1171 | /* CFL */ | ||
1172 | { PCI_DEVICE(0x8086, 0xa348), | ||
1173 | .driver_data = (unsigned long)&snd_soc_acpi_intel_cnl_machines}, | ||
1174 | #endif | ||
1121 | { 0, } | 1175 | { 0, } |
1122 | }; | 1176 | }; |
1123 | MODULE_DEVICE_TABLE(pci, skl_ids); | 1177 | MODULE_DEVICE_TABLE(pci, skl_ids); |
diff --git a/sound/soc/intel/skylake/skl.h b/sound/soc/intel/skylake/skl.h index 8d48cd7c56c8..85f8bb6687dc 100644 --- a/sound/soc/intel/skylake/skl.h +++ b/sound/soc/intel/skylake/skl.h | |||
@@ -119,10 +119,7 @@ struct skl_dma_params { | |||
119 | }; | 119 | }; |
120 | 120 | ||
121 | struct skl_machine_pdata { | 121 | struct skl_machine_pdata { |
122 | u32 dmic_num; | ||
123 | bool use_tplg_pcm; /* use dais and dai links from topology */ | 122 | bool use_tplg_pcm; /* use dais and dai links from topology */ |
124 | const char *platform; | ||
125 | u32 codec_mask; | ||
126 | }; | 123 | }; |
127 | 124 | ||
128 | struct skl_dsp_ops { | 125 | struct skl_dsp_ops { |
diff --git a/sound/soc/mediatek/mt6797/mt6797-afe-pcm.c b/sound/soc/mediatek/mt6797/mt6797-afe-pcm.c index 192f4d7b37b6..bff7d71d0742 100644 --- a/sound/soc/mediatek/mt6797/mt6797-afe-pcm.c +++ b/sound/soc/mediatek/mt6797/mt6797-afe-pcm.c | |||
@@ -828,7 +828,7 @@ static int mt6797_afe_pcm_dev_probe(struct platform_device *pdev) | |||
828 | /* request irq */ | 828 | /* request irq */ |
829 | irq_id = platform_get_irq(pdev, 0); | 829 | irq_id = platform_get_irq(pdev, 0); |
830 | if (!irq_id) { | 830 | if (!irq_id) { |
831 | dev_err(dev, "%s no irq found\n", dev->of_node->name); | 831 | dev_err(dev, "%pOFn no irq found\n", dev->of_node); |
832 | return -ENXIO; | 832 | return -ENXIO; |
833 | } | 833 | } |
834 | ret = devm_request_irq(dev, irq_id, mt6797_afe_irq_handler, | 834 | ret = devm_request_irq(dev, irq_id, mt6797_afe_irq_handler, |
diff --git a/sound/soc/mediatek/mt8173/mt8173-afe-pcm.c b/sound/soc/mediatek/mt8173/mt8173-afe-pcm.c index c0b6697503fd..166aed28330d 100644 --- a/sound/soc/mediatek/mt8173/mt8173-afe-pcm.c +++ b/sound/soc/mediatek/mt8173/mt8173-afe-pcm.c | |||
@@ -1092,7 +1092,7 @@ static int mt8173_afe_pcm_dev_probe(struct platform_device *pdev) | |||
1092 | 1092 | ||
1093 | irq_id = platform_get_irq(pdev, 0); | 1093 | irq_id = platform_get_irq(pdev, 0); |
1094 | if (irq_id <= 0) { | 1094 | if (irq_id <= 0) { |
1095 | dev_err(afe->dev, "np %s no irq\n", afe->dev->of_node->name); | 1095 | dev_err(afe->dev, "np %pOFn no irq\n", afe->dev->of_node); |
1096 | return irq_id < 0 ? irq_id : -ENXIO; | 1096 | return irq_id < 0 ? irq_id : -ENXIO; |
1097 | } | 1097 | } |
1098 | ret = devm_request_irq(afe->dev, irq_id, mt8173_afe_irq_handler, | 1098 | ret = devm_request_irq(afe->dev, irq_id, mt8173_afe_irq_handler, |
diff --git a/sound/soc/meson/Kconfig b/sound/soc/meson/Kconfig index 8b8426ed2363..8779fe23671d 100644 --- a/sound/soc/meson/Kconfig +++ b/sound/soc/meson/Kconfig | |||
@@ -54,6 +54,7 @@ config SND_MESON_AXG_SOUND_CARD | |||
54 | imply SND_MESON_AXG_TDMIN | 54 | imply SND_MESON_AXG_TDMIN |
55 | imply SND_MESON_AXG_TDMOUT | 55 | imply SND_MESON_AXG_TDMOUT |
56 | imply SND_MESON_AXG_SPDIFOUT | 56 | imply SND_MESON_AXG_SPDIFOUT |
57 | imply SND_MESON_AXG_SPDIFIN | ||
57 | imply SND_MESON_AXG_PDM | 58 | imply SND_MESON_AXG_PDM |
58 | help | 59 | help |
59 | Select Y or M to add support for the AXG SoC sound card | 60 | Select Y or M to add support for the AXG SoC sound card |
@@ -67,6 +68,13 @@ config SND_MESON_AXG_SPDIFOUT | |||
67 | Select Y or M to add support for SPDIF output serializer embedded | 68 | Select Y or M to add support for SPDIF output serializer embedded |
68 | in the Amlogic AXG SoC family | 69 | in the Amlogic AXG SoC family |
69 | 70 | ||
71 | config SND_MESON_AXG_SPDIFIN | ||
72 | tristate "Amlogic AXG SPDIF Input Support" | ||
73 | imply SND_SOC_SPDIF | ||
74 | help | ||
75 | Select Y or M to add support for SPDIF input embedded | ||
76 | in the Amlogic AXG SoC family | ||
77 | |||
70 | config SND_MESON_AXG_PDM | 78 | config SND_MESON_AXG_PDM |
71 | tristate "Amlogic AXG PDM Input Support" | 79 | tristate "Amlogic AXG PDM Input Support" |
72 | imply SND_SOC_DMIC | 80 | imply SND_SOC_DMIC |
@@ -74,5 +82,4 @@ config SND_MESON_AXG_PDM | |||
74 | help | 82 | help |
75 | Select Y or M to add support for PDM input embedded | 83 | Select Y or M to add support for PDM input embedded |
76 | in the Amlogic AXG SoC family | 84 | in the Amlogic AXG SoC family |
77 | |||
78 | endmenu | 85 | endmenu |
diff --git a/sound/soc/meson/Makefile b/sound/soc/meson/Makefile index 4cd25104029d..b45dfb9e2f88 100644 --- a/sound/soc/meson/Makefile +++ b/sound/soc/meson/Makefile | |||
@@ -8,6 +8,7 @@ snd-soc-meson-axg-tdm-interface-objs := axg-tdm-interface.o | |||
8 | snd-soc-meson-axg-tdmin-objs := axg-tdmin.o | 8 | snd-soc-meson-axg-tdmin-objs := axg-tdmin.o |
9 | snd-soc-meson-axg-tdmout-objs := axg-tdmout.o | 9 | snd-soc-meson-axg-tdmout-objs := axg-tdmout.o |
10 | snd-soc-meson-axg-sound-card-objs := axg-card.o | 10 | snd-soc-meson-axg-sound-card-objs := axg-card.o |
11 | snd-soc-meson-axg-spdifin-objs := axg-spdifin.o | ||
11 | snd-soc-meson-axg-spdifout-objs := axg-spdifout.o | 12 | snd-soc-meson-axg-spdifout-objs := axg-spdifout.o |
12 | snd-soc-meson-axg-pdm-objs := axg-pdm.o | 13 | snd-soc-meson-axg-pdm-objs := axg-pdm.o |
13 | 14 | ||
@@ -19,5 +20,6 @@ obj-$(CONFIG_SND_MESON_AXG_TDM_INTERFACE) += snd-soc-meson-axg-tdm-interface.o | |||
19 | obj-$(CONFIG_SND_MESON_AXG_TDMIN) += snd-soc-meson-axg-tdmin.o | 20 | obj-$(CONFIG_SND_MESON_AXG_TDMIN) += snd-soc-meson-axg-tdmin.o |
20 | obj-$(CONFIG_SND_MESON_AXG_TDMOUT) += snd-soc-meson-axg-tdmout.o | 21 | obj-$(CONFIG_SND_MESON_AXG_TDMOUT) += snd-soc-meson-axg-tdmout.o |
21 | obj-$(CONFIG_SND_MESON_AXG_SOUND_CARD) += snd-soc-meson-axg-sound-card.o | 22 | obj-$(CONFIG_SND_MESON_AXG_SOUND_CARD) += snd-soc-meson-axg-sound-card.o |
23 | obj-$(CONFIG_SND_MESON_AXG_SPDIFIN) += snd-soc-meson-axg-spdifin.o | ||
22 | obj-$(CONFIG_SND_MESON_AXG_SPDIFOUT) += snd-soc-meson-axg-spdifout.o | 24 | obj-$(CONFIG_SND_MESON_AXG_SPDIFOUT) += snd-soc-meson-axg-spdifout.o |
23 | obj-$(CONFIG_SND_MESON_AXG_PDM) += snd-soc-meson-axg-pdm.o | 25 | obj-$(CONFIG_SND_MESON_AXG_PDM) += snd-soc-meson-axg-pdm.o |
diff --git a/sound/soc/meson/axg-fifo.h b/sound/soc/meson/axg-fifo.h index cb6c4013ca33..d9f516cfbeda 100644 --- a/sound/soc/meson/axg-fifo.h +++ b/sound/soc/meson/axg-fifo.h | |||
@@ -25,7 +25,8 @@ struct snd_soc_pcm_runtime; | |||
25 | SNDRV_PCM_FMTBIT_S16_LE | \ | 25 | SNDRV_PCM_FMTBIT_S16_LE | \ |
26 | SNDRV_PCM_FMTBIT_S20_LE | \ | 26 | SNDRV_PCM_FMTBIT_S20_LE | \ |
27 | SNDRV_PCM_FMTBIT_S24_LE | \ | 27 | SNDRV_PCM_FMTBIT_S24_LE | \ |
28 | SNDRV_PCM_FMTBIT_S32_LE) | 28 | SNDRV_PCM_FMTBIT_S32_LE | \ |
29 | SNDRV_PCM_FMTBIT_IEC958_SUBFRAME_LE) | ||
29 | 30 | ||
30 | #define AXG_FIFO_BURST 8 | 31 | #define AXG_FIFO_BURST 8 |
31 | #define AXG_FIFO_MIN_CNT 64 | 32 | #define AXG_FIFO_MIN_CNT 64 |
diff --git a/sound/soc/meson/axg-spdifin.c b/sound/soc/meson/axg-spdifin.c new file mode 100644 index 000000000000..01b2035fa841 --- /dev/null +++ b/sound/soc/meson/axg-spdifin.c | |||
@@ -0,0 +1,521 @@ | |||
1 | // SPDX-License-Identifier: (GPL-2.0 OR MIT) | ||
2 | // | ||
3 | // Copyright (c) 2018 BayLibre, SAS. | ||
4 | // Author: Jerome Brunet <jbrunet@baylibre.com> | ||
5 | |||
6 | #include <linux/bitfield.h> | ||
7 | #include <linux/clk.h> | ||
8 | #include <linux/module.h> | ||
9 | #include <linux/of_platform.h> | ||
10 | #include <linux/regmap.h> | ||
11 | #include <sound/soc.h> | ||
12 | #include <sound/soc-dai.h> | ||
13 | #include <sound/pcm_params.h> | ||
14 | |||
15 | #define SPDIFIN_CTRL0 0x00 | ||
16 | #define SPDIFIN_CTRL0_EN BIT(31) | ||
17 | #define SPDIFIN_CTRL0_RST_OUT BIT(29) | ||
18 | #define SPDIFIN_CTRL0_RST_IN BIT(28) | ||
19 | #define SPDIFIN_CTRL0_WIDTH_SEL BIT(24) | ||
20 | #define SPDIFIN_CTRL0_STATUS_CH_SHIFT 11 | ||
21 | #define SPDIFIN_CTRL0_STATUS_SEL GENMASK(10, 8) | ||
22 | #define SPDIFIN_CTRL0_SRC_SEL GENMASK(5, 4) | ||
23 | #define SPDIFIN_CTRL0_CHK_VALID BIT(3) | ||
24 | #define SPDIFIN_CTRL1 0x04 | ||
25 | #define SPDIFIN_CTRL1_BASE_TIMER GENMASK(19, 0) | ||
26 | #define SPDIFIN_CTRL1_IRQ_MASK GENMASK(27, 20) | ||
27 | #define SPDIFIN_CTRL2 0x08 | ||
28 | #define SPDIFIN_THRES_PER_REG 3 | ||
29 | #define SPDIFIN_THRES_WIDTH 10 | ||
30 | #define SPDIFIN_CTRL3 0x0c | ||
31 | #define SPDIFIN_CTRL4 0x10 | ||
32 | #define SPDIFIN_TIMER_PER_REG 4 | ||
33 | #define SPDIFIN_TIMER_WIDTH 8 | ||
34 | #define SPDIFIN_CTRL5 0x14 | ||
35 | #define SPDIFIN_CTRL6 0x18 | ||
36 | #define SPDIFIN_STAT0 0x1c | ||
37 | #define SPDIFIN_STAT0_MODE GENMASK(30, 28) | ||
38 | #define SPDIFIN_STAT0_MAXW GENMASK(17, 8) | ||
39 | #define SPDIFIN_STAT0_IRQ GENMASK(7, 0) | ||
40 | #define SPDIFIN_IRQ_MODE_CHANGED BIT(2) | ||
41 | #define SPDIFIN_STAT1 0x20 | ||
42 | #define SPDIFIN_STAT2 0x24 | ||
43 | #define SPDIFIN_MUTE_VAL 0x28 | ||
44 | |||
45 | #define SPDIFIN_MODE_NUM 7 | ||
46 | |||
47 | struct axg_spdifin_cfg { | ||
48 | const unsigned int *mode_rates; | ||
49 | unsigned int ref_rate; | ||
50 | }; | ||
51 | |||
52 | struct axg_spdifin { | ||
53 | const struct axg_spdifin_cfg *conf; | ||
54 | struct regmap *map; | ||
55 | struct clk *refclk; | ||
56 | struct clk *pclk; | ||
57 | }; | ||
58 | |||
59 | /* | ||
60 | * TODO: | ||
61 | * It would have been nice to check the actual rate against the sample rate | ||
62 | * requested in hw_params(). Unfortunately, I was not able to make the mode | ||
63 | * detection and IRQ work reliably: | ||
64 | * | ||
65 | * 1. IRQs are generated on mode change only, so there is no notification | ||
66 | * on transition between no signal and mode 0 (32kHz). | ||
67 | * 2. Mode detection very often has glitches, and may detects the | ||
68 | * lowest or the highest mode before zeroing in on the actual mode. | ||
69 | * | ||
70 | * This makes calling snd_pcm_stop() difficult to get right. Even notifying | ||
71 | * the kcontrol would be very unreliable at this point. | ||
72 | * Let's keep things simple until the magic spell that makes this work is | ||
73 | * found. | ||
74 | */ | ||
75 | |||
76 | static unsigned int axg_spdifin_get_rate(struct axg_spdifin *priv) | ||
77 | { | ||
78 | unsigned int stat, mode, rate = 0; | ||
79 | |||
80 | regmap_read(priv->map, SPDIFIN_STAT0, &stat); | ||
81 | mode = FIELD_GET(SPDIFIN_STAT0_MODE, stat); | ||
82 | |||
83 | /* | ||
84 | * If max width is zero, we are not capturing anything. | ||
85 | * Also Sometimes, when the capture is on but there is no data, | ||
86 | * mode is SPDIFIN_MODE_NUM, but not always ... | ||
87 | */ | ||
88 | if (FIELD_GET(SPDIFIN_STAT0_MAXW, stat) && | ||
89 | mode < SPDIFIN_MODE_NUM) | ||
90 | rate = priv->conf->mode_rates[mode]; | ||
91 | |||
92 | return rate; | ||
93 | } | ||
94 | |||
95 | static int axg_spdifin_prepare(struct snd_pcm_substream *substream, | ||
96 | struct snd_soc_dai *dai) | ||
97 | { | ||
98 | struct axg_spdifin *priv = snd_soc_dai_get_drvdata(dai); | ||
99 | |||
100 | /* Apply both reset */ | ||
101 | regmap_update_bits(priv->map, SPDIFIN_CTRL0, | ||
102 | SPDIFIN_CTRL0_RST_OUT | | ||
103 | SPDIFIN_CTRL0_RST_IN, | ||
104 | 0); | ||
105 | |||
106 | /* Clear out reset before in reset */ | ||
107 | regmap_update_bits(priv->map, SPDIFIN_CTRL0, | ||
108 | SPDIFIN_CTRL0_RST_OUT, SPDIFIN_CTRL0_RST_OUT); | ||
109 | regmap_update_bits(priv->map, SPDIFIN_CTRL0, | ||
110 | SPDIFIN_CTRL0_RST_IN, SPDIFIN_CTRL0_RST_IN); | ||
111 | |||
112 | return 0; | ||
113 | } | ||
114 | |||
115 | static int axg_spdifin_startup(struct snd_pcm_substream *substream, | ||
116 | struct snd_soc_dai *dai) | ||
117 | { | ||
118 | struct axg_spdifin *priv = snd_soc_dai_get_drvdata(dai); | ||
119 | int ret; | ||
120 | |||
121 | ret = clk_prepare_enable(priv->refclk); | ||
122 | if (ret) { | ||
123 | dev_err(dai->dev, | ||
124 | "failed to enable spdifin reference clock\n"); | ||
125 | return ret; | ||
126 | } | ||
127 | |||
128 | regmap_update_bits(priv->map, SPDIFIN_CTRL0, SPDIFIN_CTRL0_EN, | ||
129 | SPDIFIN_CTRL0_EN); | ||
130 | |||
131 | return 0; | ||
132 | } | ||
133 | |||
134 | static void axg_spdifin_shutdown(struct snd_pcm_substream *substream, | ||
135 | struct snd_soc_dai *dai) | ||
136 | { | ||
137 | struct axg_spdifin *priv = snd_soc_dai_get_drvdata(dai); | ||
138 | |||
139 | regmap_update_bits(priv->map, SPDIFIN_CTRL0, SPDIFIN_CTRL0_EN, 0); | ||
140 | clk_disable_unprepare(priv->refclk); | ||
141 | } | ||
142 | |||
143 | static void axg_spdifin_write_mode_param(struct regmap *map, int mode, | ||
144 | unsigned int val, | ||
145 | unsigned int num_per_reg, | ||
146 | unsigned int base_reg, | ||
147 | unsigned int width) | ||
148 | { | ||
149 | uint64_t offset = mode; | ||
150 | unsigned int reg, shift, rem; | ||
151 | |||
152 | rem = do_div(offset, num_per_reg); | ||
153 | |||
154 | reg = offset * regmap_get_reg_stride(map) + base_reg; | ||
155 | shift = width * (num_per_reg - 1 - rem); | ||
156 | |||
157 | regmap_update_bits(map, reg, GENMASK(width - 1, 0) << shift, | ||
158 | val << shift); | ||
159 | } | ||
160 | |||
161 | static void axg_spdifin_write_timer(struct regmap *map, int mode, | ||
162 | unsigned int val) | ||
163 | { | ||
164 | axg_spdifin_write_mode_param(map, mode, val, SPDIFIN_TIMER_PER_REG, | ||
165 | SPDIFIN_CTRL4, SPDIFIN_TIMER_WIDTH); | ||
166 | } | ||
167 | |||
168 | static void axg_spdifin_write_threshold(struct regmap *map, int mode, | ||
169 | unsigned int val) | ||
170 | { | ||
171 | axg_spdifin_write_mode_param(map, mode, val, SPDIFIN_THRES_PER_REG, | ||
172 | SPDIFIN_CTRL2, SPDIFIN_THRES_WIDTH); | ||
173 | } | ||
174 | |||
175 | static unsigned int axg_spdifin_mode_timer(struct axg_spdifin *priv, | ||
176 | int mode, | ||
177 | unsigned int rate) | ||
178 | { | ||
179 | /* | ||
180 | * Number of period of the reference clock during a period of the | ||
181 | * input signal reference clock | ||
182 | */ | ||
183 | return rate / (128 * priv->conf->mode_rates[mode]); | ||
184 | } | ||
185 | |||
186 | static int axg_spdifin_sample_mode_config(struct snd_soc_dai *dai, | ||
187 | struct axg_spdifin *priv) | ||
188 | { | ||
189 | unsigned int rate, t_next; | ||
190 | int ret, i = SPDIFIN_MODE_NUM - 1; | ||
191 | |||
192 | /* Set spdif input reference clock */ | ||
193 | ret = clk_set_rate(priv->refclk, priv->conf->ref_rate); | ||
194 | if (ret) { | ||
195 | dev_err(dai->dev, "reference clock rate set failed\n"); | ||
196 | return ret; | ||
197 | } | ||
198 | |||
199 | /* | ||
200 | * The rate actually set might be slightly different, get | ||
201 | * the actual rate for the following mode calculation | ||
202 | */ | ||
203 | rate = clk_get_rate(priv->refclk); | ||
204 | |||
205 | /* HW will update mode every 1ms */ | ||
206 | regmap_update_bits(priv->map, SPDIFIN_CTRL1, | ||
207 | SPDIFIN_CTRL1_BASE_TIMER, | ||
208 | FIELD_PREP(SPDIFIN_CTRL1_BASE_TIMER, rate / 1000)); | ||
209 | |||
210 | /* Threshold based on the minimum width between two edges */ | ||
211 | regmap_update_bits(priv->map, SPDIFIN_CTRL0, | ||
212 | SPDIFIN_CTRL0_WIDTH_SEL, SPDIFIN_CTRL0_WIDTH_SEL); | ||
213 | |||
214 | /* Calculate the last timer which has no threshold */ | ||
215 | t_next = axg_spdifin_mode_timer(priv, i, rate); | ||
216 | axg_spdifin_write_timer(priv->map, i, t_next); | ||
217 | |||
218 | do { | ||
219 | unsigned int t; | ||
220 | |||
221 | i -= 1; | ||
222 | |||
223 | /* Calculate the timer */ | ||
224 | t = axg_spdifin_mode_timer(priv, i, rate); | ||
225 | |||
226 | /* Set the timer value */ | ||
227 | axg_spdifin_write_timer(priv->map, i, t); | ||
228 | |||
229 | /* Set the threshold value */ | ||
230 | axg_spdifin_write_threshold(priv->map, i, t + t_next); | ||
231 | |||
232 | /* Save the current timer for the next threshold calculation */ | ||
233 | t_next = t; | ||
234 | |||
235 | } while (i > 0); | ||
236 | |||
237 | return 0; | ||
238 | } | ||
239 | |||
240 | static int axg_spdifin_dai_probe(struct snd_soc_dai *dai) | ||
241 | { | ||
242 | struct axg_spdifin *priv = snd_soc_dai_get_drvdata(dai); | ||
243 | int ret; | ||
244 | |||
245 | ret = clk_prepare_enable(priv->pclk); | ||
246 | if (ret) { | ||
247 | dev_err(dai->dev, "failed to enable pclk\n"); | ||
248 | return ret; | ||
249 | } | ||
250 | |||
251 | ret = axg_spdifin_sample_mode_config(dai, priv); | ||
252 | if (ret) { | ||
253 | dev_err(dai->dev, "mode configuration failed\n"); | ||
254 | clk_disable_unprepare(priv->pclk); | ||
255 | return ret; | ||
256 | } | ||
257 | |||
258 | return 0; | ||
259 | } | ||
260 | |||
261 | static int axg_spdifin_dai_remove(struct snd_soc_dai *dai) | ||
262 | { | ||
263 | struct axg_spdifin *priv = snd_soc_dai_get_drvdata(dai); | ||
264 | |||
265 | clk_disable_unprepare(priv->pclk); | ||
266 | return 0; | ||
267 | } | ||
268 | |||
269 | static const struct snd_soc_dai_ops axg_spdifin_ops = { | ||
270 | .prepare = axg_spdifin_prepare, | ||
271 | .startup = axg_spdifin_startup, | ||
272 | .shutdown = axg_spdifin_shutdown, | ||
273 | }; | ||
274 | |||
275 | static int axg_spdifin_iec958_info(struct snd_kcontrol *kcontrol, | ||
276 | struct snd_ctl_elem_info *uinfo) | ||
277 | { | ||
278 | uinfo->type = SNDRV_CTL_ELEM_TYPE_IEC958; | ||
279 | uinfo->count = 1; | ||
280 | |||
281 | return 0; | ||
282 | } | ||
283 | |||
284 | static int axg_spdifin_get_status_mask(struct snd_kcontrol *kcontrol, | ||
285 | struct snd_ctl_elem_value *ucontrol) | ||
286 | { | ||
287 | int i; | ||
288 | |||
289 | for (i = 0; i < 24; i++) | ||
290 | ucontrol->value.iec958.status[i] = 0xff; | ||
291 | |||
292 | return 0; | ||
293 | } | ||
294 | |||
295 | static int axg_spdifin_get_status(struct snd_kcontrol *kcontrol, | ||
296 | struct snd_ctl_elem_value *ucontrol) | ||
297 | { | ||
298 | struct snd_soc_component *c = snd_kcontrol_chip(kcontrol); | ||
299 | struct axg_spdifin *priv = snd_soc_component_get_drvdata(c); | ||
300 | int i, j; | ||
301 | |||
302 | for (i = 0; i < 6; i++) { | ||
303 | unsigned int val; | ||
304 | |||
305 | regmap_update_bits(priv->map, SPDIFIN_CTRL0, | ||
306 | SPDIFIN_CTRL0_STATUS_SEL, | ||
307 | FIELD_PREP(SPDIFIN_CTRL0_STATUS_SEL, i)); | ||
308 | |||
309 | regmap_read(priv->map, SPDIFIN_STAT1, &val); | ||
310 | |||
311 | for (j = 0; j < 4; j++) { | ||
312 | unsigned int offset = i * 4 + j; | ||
313 | |||
314 | ucontrol->value.iec958.status[offset] = | ||
315 | (val >> (j * 8)) & 0xff; | ||
316 | } | ||
317 | } | ||
318 | |||
319 | return 0; | ||
320 | } | ||
321 | |||
322 | #define AXG_SPDIFIN_IEC958_MASK \ | ||
323 | { \ | ||
324 | .access = SNDRV_CTL_ELEM_ACCESS_READ, \ | ||
325 | .iface = SNDRV_CTL_ELEM_IFACE_PCM, \ | ||
326 | .name = SNDRV_CTL_NAME_IEC958("", CAPTURE, MASK), \ | ||
327 | .info = axg_spdifin_iec958_info, \ | ||
328 | .get = axg_spdifin_get_status_mask, \ | ||
329 | } | ||
330 | |||
331 | #define AXG_SPDIFIN_IEC958_STATUS \ | ||
332 | { \ | ||
333 | .access = (SNDRV_CTL_ELEM_ACCESS_READ | \ | ||
334 | SNDRV_CTL_ELEM_ACCESS_VOLATILE), \ | ||
335 | .iface = SNDRV_CTL_ELEM_IFACE_PCM, \ | ||
336 | .name = SNDRV_CTL_NAME_IEC958("", CAPTURE, NONE), \ | ||
337 | .info = axg_spdifin_iec958_info, \ | ||
338 | .get = axg_spdifin_get_status, \ | ||
339 | } | ||
340 | |||
341 | static const char * const spdifin_chsts_src_texts[] = { | ||
342 | "A", "B", | ||
343 | }; | ||
344 | |||
345 | static SOC_ENUM_SINGLE_DECL(axg_spdifin_chsts_src_enum, SPDIFIN_CTRL0, | ||
346 | SPDIFIN_CTRL0_STATUS_CH_SHIFT, | ||
347 | spdifin_chsts_src_texts); | ||
348 | |||
349 | static int axg_spdifin_rate_lock_info(struct snd_kcontrol *kcontrol, | ||
350 | struct snd_ctl_elem_info *uinfo) | ||
351 | { | ||
352 | uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; | ||
353 | uinfo->count = 1; | ||
354 | uinfo->value.integer.min = 0; | ||
355 | uinfo->value.integer.max = 192000; | ||
356 | |||
357 | return 0; | ||
358 | } | ||
359 | |||
360 | static int axg_spdifin_rate_lock_get(struct snd_kcontrol *kcontrol, | ||
361 | struct snd_ctl_elem_value *ucontrol) | ||
362 | { | ||
363 | struct snd_soc_component *c = snd_kcontrol_chip(kcontrol); | ||
364 | struct axg_spdifin *priv = snd_soc_component_get_drvdata(c); | ||
365 | |||
366 | ucontrol->value.integer.value[0] = axg_spdifin_get_rate(priv); | ||
367 | |||
368 | return 0; | ||
369 | } | ||
370 | |||
371 | #define AXG_SPDIFIN_LOCK_RATE(xname) \ | ||
372 | { \ | ||
373 | .iface = SNDRV_CTL_ELEM_IFACE_PCM, \ | ||
374 | .access = (SNDRV_CTL_ELEM_ACCESS_READ | \ | ||
375 | SNDRV_CTL_ELEM_ACCESS_VOLATILE), \ | ||
376 | .get = axg_spdifin_rate_lock_get, \ | ||
377 | .info = axg_spdifin_rate_lock_info, \ | ||
378 | .name = xname, \ | ||
379 | } | ||
380 | |||
381 | static const struct snd_kcontrol_new axg_spdifin_controls[] = { | ||
382 | AXG_SPDIFIN_LOCK_RATE("Capture Rate Lock"), | ||
383 | SOC_DOUBLE("Capture Switch", SPDIFIN_CTRL0, 7, 6, 1, 1), | ||
384 | SOC_ENUM(SNDRV_CTL_NAME_IEC958("", CAPTURE, NONE) "Src", | ||
385 | axg_spdifin_chsts_src_enum), | ||
386 | AXG_SPDIFIN_IEC958_MASK, | ||
387 | AXG_SPDIFIN_IEC958_STATUS, | ||
388 | }; | ||
389 | |||
390 | static const struct snd_soc_component_driver axg_spdifin_component_drv = { | ||
391 | .controls = axg_spdifin_controls, | ||
392 | .num_controls = ARRAY_SIZE(axg_spdifin_controls), | ||
393 | }; | ||
394 | |||
395 | static const struct regmap_config axg_spdifin_regmap_cfg = { | ||
396 | .reg_bits = 32, | ||
397 | .val_bits = 32, | ||
398 | .reg_stride = 4, | ||
399 | .max_register = SPDIFIN_MUTE_VAL, | ||
400 | }; | ||
401 | |||
402 | static const unsigned int axg_spdifin_mode_rates[SPDIFIN_MODE_NUM] = { | ||
403 | 32000, 44100, 48000, 88200, 96000, 176400, 192000, | ||
404 | }; | ||
405 | |||
406 | static const struct axg_spdifin_cfg axg_cfg = { | ||
407 | .mode_rates = axg_spdifin_mode_rates, | ||
408 | .ref_rate = 333333333, | ||
409 | }; | ||
410 | |||
411 | static const struct of_device_id axg_spdifin_of_match[] = { | ||
412 | { | ||
413 | .compatible = "amlogic,axg-spdifin", | ||
414 | .data = &axg_cfg, | ||
415 | }, {} | ||
416 | }; | ||
417 | MODULE_DEVICE_TABLE(of, axg_spdifin_of_match); | ||
418 | |||
419 | static struct snd_soc_dai_driver * | ||
420 | axg_spdifin_get_dai_drv(struct device *dev, struct axg_spdifin *priv) | ||
421 | { | ||
422 | struct snd_soc_dai_driver *drv; | ||
423 | int i; | ||
424 | |||
425 | drv = devm_kzalloc(dev, sizeof(*drv), GFP_KERNEL); | ||
426 | if (!drv) | ||
427 | return ERR_PTR(-ENOMEM); | ||
428 | |||
429 | drv->name = "SPDIF Input"; | ||
430 | drv->ops = &axg_spdifin_ops; | ||
431 | drv->probe = axg_spdifin_dai_probe; | ||
432 | drv->remove = axg_spdifin_dai_remove; | ||
433 | drv->capture.stream_name = "Capture"; | ||
434 | drv->capture.channels_min = 1; | ||
435 | drv->capture.channels_max = 2; | ||
436 | drv->capture.formats = SNDRV_PCM_FMTBIT_IEC958_SUBFRAME_LE; | ||
437 | |||
438 | for (i = 0; i < SPDIFIN_MODE_NUM; i++) { | ||
439 | unsigned int rb = | ||
440 | snd_pcm_rate_to_rate_bit(priv->conf->mode_rates[i]); | ||
441 | |||
442 | if (rb == SNDRV_PCM_RATE_KNOT) | ||
443 | return ERR_PTR(-EINVAL); | ||
444 | |||
445 | drv->capture.rates |= rb; | ||
446 | } | ||
447 | |||
448 | return drv; | ||
449 | } | ||
450 | |||
451 | static int axg_spdifin_probe(struct platform_device *pdev) | ||
452 | { | ||
453 | struct device *dev = &pdev->dev; | ||
454 | struct axg_spdifin *priv; | ||
455 | struct snd_soc_dai_driver *dai_drv; | ||
456 | struct resource *res; | ||
457 | void __iomem *regs; | ||
458 | int ret; | ||
459 | |||
460 | priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL); | ||
461 | if (!priv) | ||
462 | return -ENOMEM; | ||
463 | platform_set_drvdata(pdev, priv); | ||
464 | |||
465 | priv->conf = of_device_get_match_data(dev); | ||
466 | if (!priv->conf) { | ||
467 | dev_err(dev, "failed to match device\n"); | ||
468 | return -ENODEV; | ||
469 | } | ||
470 | |||
471 | res = platform_get_resource(pdev, IORESOURCE_MEM, 0); | ||
472 | regs = devm_ioremap_resource(dev, res); | ||
473 | if (IS_ERR(regs)) | ||
474 | return PTR_ERR(regs); | ||
475 | |||
476 | priv->map = devm_regmap_init_mmio(dev, regs, &axg_spdifin_regmap_cfg); | ||
477 | if (IS_ERR(priv->map)) { | ||
478 | dev_err(dev, "failed to init regmap: %ld\n", | ||
479 | PTR_ERR(priv->map)); | ||
480 | return PTR_ERR(priv->map); | ||
481 | } | ||
482 | |||
483 | priv->pclk = devm_clk_get(dev, "pclk"); | ||
484 | if (IS_ERR(priv->pclk)) { | ||
485 | ret = PTR_ERR(priv->pclk); | ||
486 | if (ret != -EPROBE_DEFER) | ||
487 | dev_err(dev, "failed to get pclk: %d\n", ret); | ||
488 | return ret; | ||
489 | } | ||
490 | |||
491 | priv->refclk = devm_clk_get(dev, "refclk"); | ||
492 | if (IS_ERR(priv->refclk)) { | ||
493 | ret = PTR_ERR(priv->refclk); | ||
494 | if (ret != -EPROBE_DEFER) | ||
495 | dev_err(dev, "failed to get mclk: %d\n", ret); | ||
496 | return ret; | ||
497 | } | ||
498 | |||
499 | dai_drv = axg_spdifin_get_dai_drv(dev, priv); | ||
500 | if (IS_ERR(dai_drv)) { | ||
501 | dev_err(dev, "failed to get dai driver: %ld\n", | ||
502 | PTR_ERR(dai_drv)); | ||
503 | return PTR_ERR(dai_drv); | ||
504 | } | ||
505 | |||
506 | return devm_snd_soc_register_component(dev, &axg_spdifin_component_drv, | ||
507 | dai_drv, 1); | ||
508 | } | ||
509 | |||
510 | static struct platform_driver axg_spdifin_pdrv = { | ||
511 | .probe = axg_spdifin_probe, | ||
512 | .driver = { | ||
513 | .name = "axg-spdifin", | ||
514 | .of_match_table = axg_spdifin_of_match, | ||
515 | }, | ||
516 | }; | ||
517 | module_platform_driver(axg_spdifin_pdrv); | ||
518 | |||
519 | MODULE_DESCRIPTION("Amlogic AXG SPDIF Input driver"); | ||
520 | MODULE_AUTHOR("Jerome Brunet <jbrunet@baylibre.com>"); | ||
521 | MODULE_LICENSE("GPL v2"); | ||
diff --git a/sound/soc/meson/axg-toddr.c b/sound/soc/meson/axg-toddr.c index c2c9bb312586..0e9ca3882ae5 100644 --- a/sound/soc/meson/axg-toddr.c +++ b/sound/soc/meson/axg-toddr.c | |||
@@ -25,6 +25,8 @@ | |||
25 | #define CTRL0_TODDR_LSB_POS_MASK GENMASK(7, 3) | 25 | #define CTRL0_TODDR_LSB_POS_MASK GENMASK(7, 3) |
26 | #define CTRL0_TODDR_LSB_POS(x) ((x) << 3) | 26 | #define CTRL0_TODDR_LSB_POS(x) ((x) << 3) |
27 | 27 | ||
28 | #define TODDR_MSB_POS 31 | ||
29 | |||
28 | static int axg_toddr_pcm_new(struct snd_soc_pcm_runtime *rtd, | 30 | static int axg_toddr_pcm_new(struct snd_soc_pcm_runtime *rtd, |
29 | struct snd_soc_dai *dai) | 31 | struct snd_soc_dai *dai) |
30 | { | 32 | { |
@@ -36,14 +38,7 @@ static int axg_toddr_dai_hw_params(struct snd_pcm_substream *substream, | |||
36 | struct snd_soc_dai *dai) | 38 | struct snd_soc_dai *dai) |
37 | { | 39 | { |
38 | struct axg_fifo *fifo = snd_soc_dai_get_drvdata(dai); | 40 | struct axg_fifo *fifo = snd_soc_dai_get_drvdata(dai); |
39 | unsigned int type, width, msb = 31; | 41 | unsigned int type, width; |
40 | |||
41 | /* | ||
42 | * NOTE: | ||
43 | * Almost all backend will place the MSB at bit 31, except SPDIF Input | ||
44 | * which will put it at index 28. When adding support for the SPDIF | ||
45 | * Input, we'll need to find which type of backend we are connected to. | ||
46 | */ | ||
47 | 42 | ||
48 | switch (params_physical_width(params)) { | 43 | switch (params_physical_width(params)) { |
49 | case 8: | 44 | case 8: |
@@ -66,8 +61,8 @@ static int axg_toddr_dai_hw_params(struct snd_pcm_substream *substream, | |||
66 | CTRL0_TODDR_MSB_POS_MASK | | 61 | CTRL0_TODDR_MSB_POS_MASK | |
67 | CTRL0_TODDR_LSB_POS_MASK, | 62 | CTRL0_TODDR_LSB_POS_MASK, |
68 | CTRL0_TODDR_TYPE(type) | | 63 | CTRL0_TODDR_TYPE(type) | |
69 | CTRL0_TODDR_MSB_POS(msb) | | 64 | CTRL0_TODDR_MSB_POS(TODDR_MSB_POS) | |
70 | CTRL0_TODDR_LSB_POS(msb - (width - 1))); | 65 | CTRL0_TODDR_LSB_POS(TODDR_MSB_POS - (width - 1))); |
71 | 66 | ||
72 | return 0; | 67 | return 0; |
73 | } | 68 | } |
diff --git a/sound/soc/omap/Kconfig b/sound/soc/omap/Kconfig deleted file mode 100644 index 6dccea6fdaeb..000000000000 --- a/sound/soc/omap/Kconfig +++ /dev/null | |||
@@ -1,129 +0,0 @@ | |||
1 | config SND_OMAP_SOC | ||
2 | tristate "SoC Audio for Texas Instruments OMAP chips (deprecated)" | ||
3 | depends on (ARCH_OMAP && DMA_OMAP) || (ARM && COMPILE_TEST) | ||
4 | select SND_SDMA_SOC | ||
5 | |||
6 | config SND_SDMA_SOC | ||
7 | tristate "SoC Audio for Texas Instruments chips using sDMA" | ||
8 | depends on DMA_OMAP || COMPILE_TEST | ||
9 | select SND_SOC_GENERIC_DMAENGINE_PCM | ||
10 | |||
11 | config SND_OMAP_SOC_DMIC | ||
12 | tristate | ||
13 | |||
14 | config SND_OMAP_SOC_MCBSP | ||
15 | tristate | ||
16 | |||
17 | config SND_OMAP_SOC_MCPDM | ||
18 | tristate | ||
19 | |||
20 | config SND_OMAP_SOC_HDMI_AUDIO | ||
21 | tristate "HDMI audio support for OMAP4+ based SoCs" | ||
22 | depends on SND_SDMA_SOC | ||
23 | help | ||
24 | For HDMI audio to work OMAPDSS HDMI support should be | ||
25 | enabled. | ||
26 | The hdmi audio driver implements cpu-dai component using the | ||
27 | callbacks provided by OMAPDSS and registers the component | ||
28 | under DSS HDMI device. Omap-pcm is registered for platform | ||
29 | component also under DSS HDMI device. Dummy codec is used as | ||
30 | as codec component. The hdmi audio driver implements also | ||
31 | the card and registers it under its own platform device. | ||
32 | The device for the driver is registered by OMAPDSS hdmi | ||
33 | driver. | ||
34 | |||
35 | config SND_OMAP_SOC_N810 | ||
36 | tristate "SoC Audio support for Nokia N810" | ||
37 | depends on SND_SDMA_SOC && MACH_NOKIA_N810 && I2C | ||
38 | select SND_OMAP_SOC_MCBSP | ||
39 | select SND_SOC_TLV320AIC3X | ||
40 | help | ||
41 | Say Y if you want to add support for SoC audio on Nokia N810. | ||
42 | |||
43 | config SND_OMAP_SOC_RX51 | ||
44 | tristate "SoC Audio support for Nokia N900 (RX-51)" | ||
45 | depends on SND_SDMA_SOC && ARM && I2C | ||
46 | select SND_OMAP_SOC_MCBSP | ||
47 | select SND_SOC_TLV320AIC3X | ||
48 | select SND_SOC_TPA6130A2 | ||
49 | depends on GPIOLIB | ||
50 | help | ||
51 | Say Y if you want to add support for SoC audio on Nokia N900 | ||
52 | cellphone. | ||
53 | |||
54 | config SND_OMAP_SOC_AMS_DELTA | ||
55 | tristate "SoC Audio support for Amstrad E3 (Delta) videophone" | ||
56 | depends on SND_SDMA_SOC && MACH_AMS_DELTA && TTY | ||
57 | select SND_OMAP_SOC_MCBSP | ||
58 | select SND_SOC_CX20442 | ||
59 | help | ||
60 | Say Y if you want to add support for SoC audio device connected to | ||
61 | a handset and a speakerphone found on Amstrad E3 (Delta) videophone. | ||
62 | |||
63 | Note that in order to get those devices fully supported, you have to | ||
64 | build the kernel with standard serial port driver included and | ||
65 | configured for at least 4 ports. Then, from userspace, you must load | ||
66 | a line discipline #19 on the modem (ttyS3) serial line. The simplest | ||
67 | way to achieve this is to install util-linux-ng and use the included | ||
68 | ldattach utility. This can be started automatically from udev, | ||
69 | a simple rule like this one should do the trick (it does for me): | ||
70 | ACTION=="add", KERNEL=="controlC0", \ | ||
71 | RUN+="/usr/sbin/ldattach 19 /dev/ttyS3" | ||
72 | |||
73 | config SND_OMAP_SOC_OSK5912 | ||
74 | tristate "SoC Audio support for omap osk5912" | ||
75 | depends on SND_SDMA_SOC && MACH_OMAP_OSK && I2C | ||
76 | select SND_OMAP_SOC_MCBSP | ||
77 | select SND_SOC_TLV320AIC23_I2C | ||
78 | help | ||
79 | Say Y if you want to add support for SoC audio on osk5912. | ||
80 | |||
81 | config SND_OMAP_SOC_AM3517EVM | ||
82 | tristate "SoC Audio support for OMAP3517 / AM3517 EVM" | ||
83 | depends on SND_SDMA_SOC && MACH_OMAP3517EVM && I2C | ||
84 | select SND_OMAP_SOC_MCBSP | ||
85 | select SND_SOC_TLV320AIC23_I2C | ||
86 | help | ||
87 | Say Y if you want to add support for SoC audio on the OMAP3517 / AM3517 | ||
88 | EVM. | ||
89 | |||
90 | config SND_OMAP_SOC_OMAP_TWL4030 | ||
91 | tristate "SoC Audio support for TI SoC based boards with twl4030 codec" | ||
92 | depends on TWL4030_CORE && SND_SDMA_SOC | ||
93 | select SND_OMAP_SOC_MCBSP | ||
94 | select SND_SOC_TWL4030 | ||
95 | help | ||
96 | Say Y if you want to add support for SoC audio on TI SoC based boards | ||
97 | using twl4030 as c codec. This driver currently supports: | ||
98 | - Beagleboard or Devkit8000 | ||
99 | - Gumstix Overo or CompuLab CM-T35/CM-T3730 | ||
100 | - IGEP v2 | ||
101 | - OMAP3EVM | ||
102 | - SDP3430 | ||
103 | - Zoom2 | ||
104 | |||
105 | config SND_OMAP_SOC_OMAP_ABE_TWL6040 | ||
106 | tristate "SoC Audio support for OMAP boards using ABE and twl6040 codec" | ||
107 | depends on TWL6040_CORE && SND_SDMA_SOC && COMMON_CLK | ||
108 | depends on ARCH_OMAP4 || (SOC_OMAP5 && MFD_PALMAS) || COMPILE_TEST | ||
109 | select SND_OMAP_SOC_DMIC | ||
110 | select SND_OMAP_SOC_MCPDM | ||
111 | select SND_SOC_TWL6040 | ||
112 | select SND_SOC_DMIC | ||
113 | select COMMON_CLK_PALMAS if (SOC_OMAP5 && MFD_PALMAS) | ||
114 | select CLK_TWL6040 | ||
115 | help | ||
116 | Say Y if you want to add support for SoC audio on OMAP boards using | ||
117 | ABE and twl6040 codec. This driver currently supports: | ||
118 | - SDP4430/Blaze boards | ||
119 | - PandaBoard (4430) | ||
120 | - PandaBoardES (4460) | ||
121 | - omap5-uevm (5432) | ||
122 | |||
123 | config SND_OMAP_SOC_OMAP3_PANDORA | ||
124 | tristate "SoC Audio support for OMAP3 Pandora" | ||
125 | depends on TWL4030_CORE && SND_SDMA_SOC && MACH_OMAP3_PANDORA | ||
126 | select SND_OMAP_SOC_MCBSP | ||
127 | select SND_SOC_TWL4030 | ||
128 | help | ||
129 | Say Y if you want to add support for SoC audio on the OMAP3 Pandora. | ||
diff --git a/sound/soc/omap/Makefile b/sound/soc/omap/Makefile deleted file mode 100644 index 53eba3413485..000000000000 --- a/sound/soc/omap/Makefile +++ /dev/null | |||
@@ -1,32 +0,0 @@ | |||
1 | # SPDX-License-Identifier: GPL-2.0 | ||
2 | # OMAP Platform Support | ||
3 | snd-soc-sdma-objs := sdma-pcm.o | ||
4 | snd-soc-omap-dmic-objs := omap-dmic.o | ||
5 | snd-soc-omap-mcbsp-objs := omap-mcbsp.o mcbsp.o | ||
6 | snd-soc-omap-mcpdm-objs := omap-mcpdm.o | ||
7 | snd-soc-omap-hdmi-audio-objs := omap-hdmi-audio.o | ||
8 | |||
9 | obj-$(CONFIG_SND_SDMA_SOC) += snd-soc-sdma.o | ||
10 | obj-$(CONFIG_SND_OMAP_SOC_DMIC) += snd-soc-omap-dmic.o | ||
11 | obj-$(CONFIG_SND_OMAP_SOC_MCBSP) += snd-soc-omap-mcbsp.o | ||
12 | obj-$(CONFIG_SND_OMAP_SOC_MCPDM) += snd-soc-omap-mcpdm.o | ||
13 | obj-$(CONFIG_SND_OMAP_SOC_HDMI_AUDIO) += snd-soc-omap-hdmi-audio.o | ||
14 | |||
15 | # OMAP Machine Support | ||
16 | snd-soc-n810-objs := n810.o | ||
17 | snd-soc-rx51-objs := rx51.o | ||
18 | snd-soc-ams-delta-objs := ams-delta.o | ||
19 | snd-soc-osk5912-objs := osk5912.o | ||
20 | snd-soc-am3517evm-objs := am3517evm.o | ||
21 | snd-soc-omap-abe-twl6040-objs := omap-abe-twl6040.o | ||
22 | snd-soc-omap-twl4030-objs := omap-twl4030.o | ||
23 | snd-soc-omap3pandora-objs := omap3pandora.o | ||
24 | |||
25 | obj-$(CONFIG_SND_OMAP_SOC_N810) += snd-soc-n810.o | ||
26 | obj-$(CONFIG_SND_OMAP_SOC_RX51) += snd-soc-rx51.o | ||
27 | obj-$(CONFIG_SND_OMAP_SOC_AMS_DELTA) += snd-soc-ams-delta.o | ||
28 | obj-$(CONFIG_SND_OMAP_SOC_OSK5912) += snd-soc-osk5912.o | ||
29 | obj-$(CONFIG_SND_OMAP_SOC_AM3517EVM) += snd-soc-am3517evm.o | ||
30 | obj-$(CONFIG_SND_OMAP_SOC_OMAP_ABE_TWL6040) += snd-soc-omap-abe-twl6040.o | ||
31 | obj-$(CONFIG_SND_OMAP_SOC_OMAP_TWL4030) += snd-soc-omap-twl4030.o | ||
32 | obj-$(CONFIG_SND_OMAP_SOC_OMAP3_PANDORA) += snd-soc-omap3pandora.o | ||
diff --git a/sound/soc/omap/am3517evm.c b/sound/soc/omap/am3517evm.c deleted file mode 100644 index d5651026ec10..000000000000 --- a/sound/soc/omap/am3517evm.c +++ /dev/null | |||
@@ -1,141 +0,0 @@ | |||
1 | /* | ||
2 | * am3517evm.c -- ALSA SoC support for OMAP3517 / AM3517 EVM | ||
3 | * | ||
4 | * Author: Anuj Aggarwal <anuj.aggarwal@ti.com> | ||
5 | * | ||
6 | * Based on sound/soc/omap/beagle.c by Steve Sakoman | ||
7 | * | ||
8 | * Copyright (C) 2009 Texas Instruments Incorporated | ||
9 | * | ||
10 | * This program is free software; you can redistribute it and/or modify it | ||
11 | * under the terms of the GNU General Public License as published by the | ||
12 | * Free Software Foundation version 2. | ||
13 | * | ||
14 | * This program is distributed "as is" WITHOUT ANY WARRANTY of any kind, | ||
15 | * whether express or implied; without even the implied warranty of | ||
16 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
17 | * General Public License for more details. | ||
18 | */ | ||
19 | |||
20 | #include <linux/clk.h> | ||
21 | #include <linux/platform_device.h> | ||
22 | #include <linux/module.h> | ||
23 | #include <sound/core.h> | ||
24 | #include <sound/pcm.h> | ||
25 | #include <sound/soc.h> | ||
26 | |||
27 | #include <asm/mach-types.h> | ||
28 | #include <linux/platform_data/asoc-ti-mcbsp.h> | ||
29 | |||
30 | #include "omap-mcbsp.h" | ||
31 | |||
32 | #include "../codecs/tlv320aic23.h" | ||
33 | |||
34 | #define CODEC_CLOCK 12000000 | ||
35 | |||
36 | static int am3517evm_hw_params(struct snd_pcm_substream *substream, | ||
37 | struct snd_pcm_hw_params *params) | ||
38 | { | ||
39 | struct snd_soc_pcm_runtime *rtd = substream->private_data; | ||
40 | struct snd_soc_dai *codec_dai = rtd->codec_dai; | ||
41 | int ret; | ||
42 | |||
43 | /* Set the codec system clock for DAC and ADC */ | ||
44 | ret = snd_soc_dai_set_sysclk(codec_dai, 0, | ||
45 | CODEC_CLOCK, SND_SOC_CLOCK_IN); | ||
46 | if (ret < 0) | ||
47 | printk(KERN_ERR "can't set codec system clock\n"); | ||
48 | |||
49 | return ret; | ||
50 | } | ||
51 | |||
52 | static const struct snd_soc_ops am3517evm_ops = { | ||
53 | .hw_params = am3517evm_hw_params, | ||
54 | }; | ||
55 | |||
56 | /* am3517evm machine dapm widgets */ | ||
57 | static const struct snd_soc_dapm_widget tlv320aic23_dapm_widgets[] = { | ||
58 | SND_SOC_DAPM_HP("Line Out", NULL), | ||
59 | SND_SOC_DAPM_LINE("Line In", NULL), | ||
60 | SND_SOC_DAPM_MIC("Mic In", NULL), | ||
61 | }; | ||
62 | |||
63 | static const struct snd_soc_dapm_route audio_map[] = { | ||
64 | /* Line Out connected to LLOUT, RLOUT */ | ||
65 | {"Line Out", NULL, "LOUT"}, | ||
66 | {"Line Out", NULL, "ROUT"}, | ||
67 | |||
68 | {"LLINEIN", NULL, "Line In"}, | ||
69 | {"RLINEIN", NULL, "Line In"}, | ||
70 | |||
71 | {"MICIN", NULL, "Mic In"}, | ||
72 | }; | ||
73 | |||
74 | /* Digital audio interface glue - connects codec <--> CPU */ | ||
75 | static struct snd_soc_dai_link am3517evm_dai = { | ||
76 | .name = "TLV320AIC23", | ||
77 | .stream_name = "AIC23", | ||
78 | .cpu_dai_name = "omap-mcbsp.1", | ||
79 | .codec_dai_name = "tlv320aic23-hifi", | ||
80 | .platform_name = "omap-mcbsp.1", | ||
81 | .codec_name = "tlv320aic23-codec.2-001a", | ||
82 | .dai_fmt = SND_SOC_DAIFMT_DSP_B | SND_SOC_DAIFMT_NB_NF | | ||
83 | SND_SOC_DAIFMT_CBM_CFM, | ||
84 | .ops = &am3517evm_ops, | ||
85 | }; | ||
86 | |||
87 | /* Audio machine driver */ | ||
88 | static struct snd_soc_card snd_soc_am3517evm = { | ||
89 | .name = "am3517evm", | ||
90 | .owner = THIS_MODULE, | ||
91 | .dai_link = &am3517evm_dai, | ||
92 | .num_links = 1, | ||
93 | |||
94 | .dapm_widgets = tlv320aic23_dapm_widgets, | ||
95 | .num_dapm_widgets = ARRAY_SIZE(tlv320aic23_dapm_widgets), | ||
96 | .dapm_routes = audio_map, | ||
97 | .num_dapm_routes = ARRAY_SIZE(audio_map), | ||
98 | }; | ||
99 | |||
100 | static struct platform_device *am3517evm_snd_device; | ||
101 | |||
102 | static int __init am3517evm_soc_init(void) | ||
103 | { | ||
104 | int ret; | ||
105 | |||
106 | if (!machine_is_omap3517evm()) | ||
107 | return -ENODEV; | ||
108 | pr_info("OMAP3517 / AM3517 EVM SoC init\n"); | ||
109 | |||
110 | am3517evm_snd_device = platform_device_alloc("soc-audio", -1); | ||
111 | if (!am3517evm_snd_device) { | ||
112 | printk(KERN_ERR "Platform device allocation failed\n"); | ||
113 | return -ENOMEM; | ||
114 | } | ||
115 | |||
116 | platform_set_drvdata(am3517evm_snd_device, &snd_soc_am3517evm); | ||
117 | |||
118 | ret = platform_device_add(am3517evm_snd_device); | ||
119 | if (ret) | ||
120 | goto err1; | ||
121 | |||
122 | return 0; | ||
123 | |||
124 | err1: | ||
125 | printk(KERN_ERR "Unable to add platform device\n"); | ||
126 | platform_device_put(am3517evm_snd_device); | ||
127 | |||
128 | return ret; | ||
129 | } | ||
130 | |||
131 | static void __exit am3517evm_soc_exit(void) | ||
132 | { | ||
133 | platform_device_unregister(am3517evm_snd_device); | ||
134 | } | ||
135 | |||
136 | module_init(am3517evm_soc_init); | ||
137 | module_exit(am3517evm_soc_exit); | ||
138 | |||
139 | MODULE_AUTHOR("Anuj Aggarwal <anuj.aggarwal@ti.com>"); | ||
140 | MODULE_DESCRIPTION("ALSA SoC OMAP3517 / AM3517 EVM"); | ||
141 | MODULE_LICENSE("GPL v2"); | ||
diff --git a/sound/soc/omap/mcbsp.c b/sound/soc/omap/mcbsp.c deleted file mode 100644 index 79d4dc785e5c..000000000000 --- a/sound/soc/omap/mcbsp.c +++ /dev/null | |||
@@ -1,1104 +0,0 @@ | |||
1 | /* | ||
2 | * sound/soc/omap/mcbsp.c | ||
3 | * | ||
4 | * Copyright (C) 2004 Nokia Corporation | ||
5 | * Author: Samuel Ortiz <samuel.ortiz@nokia.com> | ||
6 | * | ||
7 | * Contact: Jarkko Nikula <jarkko.nikula@bitmer.com> | ||
8 | * Peter Ujfalusi <peter.ujfalusi@ti.com> | ||
9 | * | ||
10 | * This program is free software; you can redistribute it and/or modify | ||
11 | * it under the terms of the GNU General Public License version 2 as | ||
12 | * published by the Free Software Foundation. | ||
13 | * | ||
14 | * Multichannel mode not supported. | ||
15 | */ | ||
16 | |||
17 | #include <linux/module.h> | ||
18 | #include <linux/init.h> | ||
19 | #include <linux/device.h> | ||
20 | #include <linux/platform_device.h> | ||
21 | #include <linux/interrupt.h> | ||
22 | #include <linux/err.h> | ||
23 | #include <linux/clk.h> | ||
24 | #include <linux/delay.h> | ||
25 | #include <linux/io.h> | ||
26 | #include <linux/slab.h> | ||
27 | #include <linux/pm_runtime.h> | ||
28 | |||
29 | #include <linux/platform_data/asoc-ti-mcbsp.h> | ||
30 | |||
31 | #include "mcbsp.h" | ||
32 | |||
33 | static void omap_mcbsp_write(struct omap_mcbsp *mcbsp, u16 reg, u32 val) | ||
34 | { | ||
35 | void __iomem *addr = mcbsp->io_base + reg * mcbsp->pdata->reg_step; | ||
36 | |||
37 | if (mcbsp->pdata->reg_size == 2) { | ||
38 | ((u16 *)mcbsp->reg_cache)[reg] = (u16)val; | ||
39 | writew_relaxed((u16)val, addr); | ||
40 | } else { | ||
41 | ((u32 *)mcbsp->reg_cache)[reg] = val; | ||
42 | writel_relaxed(val, addr); | ||
43 | } | ||
44 | } | ||
45 | |||
46 | static int omap_mcbsp_read(struct omap_mcbsp *mcbsp, u16 reg, bool from_cache) | ||
47 | { | ||
48 | void __iomem *addr = mcbsp->io_base + reg * mcbsp->pdata->reg_step; | ||
49 | |||
50 | if (mcbsp->pdata->reg_size == 2) { | ||
51 | return !from_cache ? readw_relaxed(addr) : | ||
52 | ((u16 *)mcbsp->reg_cache)[reg]; | ||
53 | } else { | ||
54 | return !from_cache ? readl_relaxed(addr) : | ||
55 | ((u32 *)mcbsp->reg_cache)[reg]; | ||
56 | } | ||
57 | } | ||
58 | |||
59 | static void omap_mcbsp_st_write(struct omap_mcbsp *mcbsp, u16 reg, u32 val) | ||
60 | { | ||
61 | writel_relaxed(val, mcbsp->st_data->io_base_st + reg); | ||
62 | } | ||
63 | |||
64 | static int omap_mcbsp_st_read(struct omap_mcbsp *mcbsp, u16 reg) | ||
65 | { | ||
66 | return readl_relaxed(mcbsp->st_data->io_base_st + reg); | ||
67 | } | ||
68 | |||
69 | #define MCBSP_READ(mcbsp, reg) \ | ||
70 | omap_mcbsp_read(mcbsp, OMAP_MCBSP_REG_##reg, 0) | ||
71 | #define MCBSP_WRITE(mcbsp, reg, val) \ | ||
72 | omap_mcbsp_write(mcbsp, OMAP_MCBSP_REG_##reg, val) | ||
73 | #define MCBSP_READ_CACHE(mcbsp, reg) \ | ||
74 | omap_mcbsp_read(mcbsp, OMAP_MCBSP_REG_##reg, 1) | ||
75 | |||
76 | #define MCBSP_ST_READ(mcbsp, reg) \ | ||
77 | omap_mcbsp_st_read(mcbsp, OMAP_ST_REG_##reg) | ||
78 | #define MCBSP_ST_WRITE(mcbsp, reg, val) \ | ||
79 | omap_mcbsp_st_write(mcbsp, OMAP_ST_REG_##reg, val) | ||
80 | |||
81 | static void omap_mcbsp_dump_reg(struct omap_mcbsp *mcbsp) | ||
82 | { | ||
83 | dev_dbg(mcbsp->dev, "**** McBSP%d regs ****\n", mcbsp->id); | ||
84 | dev_dbg(mcbsp->dev, "DRR2: 0x%04x\n", | ||
85 | MCBSP_READ(mcbsp, DRR2)); | ||
86 | dev_dbg(mcbsp->dev, "DRR1: 0x%04x\n", | ||
87 | MCBSP_READ(mcbsp, DRR1)); | ||
88 | dev_dbg(mcbsp->dev, "DXR2: 0x%04x\n", | ||
89 | MCBSP_READ(mcbsp, DXR2)); | ||
90 | dev_dbg(mcbsp->dev, "DXR1: 0x%04x\n", | ||
91 | MCBSP_READ(mcbsp, DXR1)); | ||
92 | dev_dbg(mcbsp->dev, "SPCR2: 0x%04x\n", | ||
93 | MCBSP_READ(mcbsp, SPCR2)); | ||
94 | dev_dbg(mcbsp->dev, "SPCR1: 0x%04x\n", | ||
95 | MCBSP_READ(mcbsp, SPCR1)); | ||
96 | dev_dbg(mcbsp->dev, "RCR2: 0x%04x\n", | ||
97 | MCBSP_READ(mcbsp, RCR2)); | ||
98 | dev_dbg(mcbsp->dev, "RCR1: 0x%04x\n", | ||
99 | MCBSP_READ(mcbsp, RCR1)); | ||
100 | dev_dbg(mcbsp->dev, "XCR2: 0x%04x\n", | ||
101 | MCBSP_READ(mcbsp, XCR2)); | ||
102 | dev_dbg(mcbsp->dev, "XCR1: 0x%04x\n", | ||
103 | MCBSP_READ(mcbsp, XCR1)); | ||
104 | dev_dbg(mcbsp->dev, "SRGR2: 0x%04x\n", | ||
105 | MCBSP_READ(mcbsp, SRGR2)); | ||
106 | dev_dbg(mcbsp->dev, "SRGR1: 0x%04x\n", | ||
107 | MCBSP_READ(mcbsp, SRGR1)); | ||
108 | dev_dbg(mcbsp->dev, "PCR0: 0x%04x\n", | ||
109 | MCBSP_READ(mcbsp, PCR0)); | ||
110 | dev_dbg(mcbsp->dev, "***********************\n"); | ||
111 | } | ||
112 | |||
113 | static irqreturn_t omap_mcbsp_irq_handler(int irq, void *dev_id) | ||
114 | { | ||
115 | struct omap_mcbsp *mcbsp = dev_id; | ||
116 | u16 irqst; | ||
117 | |||
118 | irqst = MCBSP_READ(mcbsp, IRQST); | ||
119 | dev_dbg(mcbsp->dev, "IRQ callback : 0x%x\n", irqst); | ||
120 | |||
121 | if (irqst & RSYNCERREN) | ||
122 | dev_err(mcbsp->dev, "RX Frame Sync Error!\n"); | ||
123 | if (irqst & RFSREN) | ||
124 | dev_dbg(mcbsp->dev, "RX Frame Sync\n"); | ||
125 | if (irqst & REOFEN) | ||
126 | dev_dbg(mcbsp->dev, "RX End Of Frame\n"); | ||
127 | if (irqst & RRDYEN) | ||
128 | dev_dbg(mcbsp->dev, "RX Buffer Threshold Reached\n"); | ||
129 | if (irqst & RUNDFLEN) | ||
130 | dev_err(mcbsp->dev, "RX Buffer Underflow!\n"); | ||
131 | if (irqst & ROVFLEN) | ||
132 | dev_err(mcbsp->dev, "RX Buffer Overflow!\n"); | ||
133 | |||
134 | if (irqst & XSYNCERREN) | ||
135 | dev_err(mcbsp->dev, "TX Frame Sync Error!\n"); | ||
136 | if (irqst & XFSXEN) | ||
137 | dev_dbg(mcbsp->dev, "TX Frame Sync\n"); | ||
138 | if (irqst & XEOFEN) | ||
139 | dev_dbg(mcbsp->dev, "TX End Of Frame\n"); | ||
140 | if (irqst & XRDYEN) | ||
141 | dev_dbg(mcbsp->dev, "TX Buffer threshold Reached\n"); | ||
142 | if (irqst & XUNDFLEN) | ||
143 | dev_err(mcbsp->dev, "TX Buffer Underflow!\n"); | ||
144 | if (irqst & XOVFLEN) | ||
145 | dev_err(mcbsp->dev, "TX Buffer Overflow!\n"); | ||
146 | if (irqst & XEMPTYEOFEN) | ||
147 | dev_dbg(mcbsp->dev, "TX Buffer empty at end of frame\n"); | ||
148 | |||
149 | MCBSP_WRITE(mcbsp, IRQST, irqst); | ||
150 | |||
151 | return IRQ_HANDLED; | ||
152 | } | ||
153 | |||
154 | static irqreturn_t omap_mcbsp_tx_irq_handler(int irq, void *dev_id) | ||
155 | { | ||
156 | struct omap_mcbsp *mcbsp_tx = dev_id; | ||
157 | u16 irqst_spcr2; | ||
158 | |||
159 | irqst_spcr2 = MCBSP_READ(mcbsp_tx, SPCR2); | ||
160 | dev_dbg(mcbsp_tx->dev, "TX IRQ callback : 0x%x\n", irqst_spcr2); | ||
161 | |||
162 | if (irqst_spcr2 & XSYNC_ERR) { | ||
163 | dev_err(mcbsp_tx->dev, "TX Frame Sync Error! : 0x%x\n", | ||
164 | irqst_spcr2); | ||
165 | /* Writing zero to XSYNC_ERR clears the IRQ */ | ||
166 | MCBSP_WRITE(mcbsp_tx, SPCR2, MCBSP_READ_CACHE(mcbsp_tx, SPCR2)); | ||
167 | } | ||
168 | |||
169 | return IRQ_HANDLED; | ||
170 | } | ||
171 | |||
172 | static irqreturn_t omap_mcbsp_rx_irq_handler(int irq, void *dev_id) | ||
173 | { | ||
174 | struct omap_mcbsp *mcbsp_rx = dev_id; | ||
175 | u16 irqst_spcr1; | ||
176 | |||
177 | irqst_spcr1 = MCBSP_READ(mcbsp_rx, SPCR1); | ||
178 | dev_dbg(mcbsp_rx->dev, "RX IRQ callback : 0x%x\n", irqst_spcr1); | ||
179 | |||
180 | if (irqst_spcr1 & RSYNC_ERR) { | ||
181 | dev_err(mcbsp_rx->dev, "RX Frame Sync Error! : 0x%x\n", | ||
182 | irqst_spcr1); | ||
183 | /* Writing zero to RSYNC_ERR clears the IRQ */ | ||
184 | MCBSP_WRITE(mcbsp_rx, SPCR1, MCBSP_READ_CACHE(mcbsp_rx, SPCR1)); | ||
185 | } | ||
186 | |||
187 | return IRQ_HANDLED; | ||
188 | } | ||
189 | |||
190 | /* | ||
191 | * omap_mcbsp_config simply write a config to the | ||
192 | * appropriate McBSP. | ||
193 | * You either call this function or set the McBSP registers | ||
194 | * by yourself before calling omap_mcbsp_start(). | ||
195 | */ | ||
196 | void omap_mcbsp_config(struct omap_mcbsp *mcbsp, | ||
197 | const struct omap_mcbsp_reg_cfg *config) | ||
198 | { | ||
199 | dev_dbg(mcbsp->dev, "Configuring McBSP%d phys_base: 0x%08lx\n", | ||
200 | mcbsp->id, mcbsp->phys_base); | ||
201 | |||
202 | /* We write the given config */ | ||
203 | MCBSP_WRITE(mcbsp, SPCR2, config->spcr2); | ||
204 | MCBSP_WRITE(mcbsp, SPCR1, config->spcr1); | ||
205 | MCBSP_WRITE(mcbsp, RCR2, config->rcr2); | ||
206 | MCBSP_WRITE(mcbsp, RCR1, config->rcr1); | ||
207 | MCBSP_WRITE(mcbsp, XCR2, config->xcr2); | ||
208 | MCBSP_WRITE(mcbsp, XCR1, config->xcr1); | ||
209 | MCBSP_WRITE(mcbsp, SRGR2, config->srgr2); | ||
210 | MCBSP_WRITE(mcbsp, SRGR1, config->srgr1); | ||
211 | MCBSP_WRITE(mcbsp, MCR2, config->mcr2); | ||
212 | MCBSP_WRITE(mcbsp, MCR1, config->mcr1); | ||
213 | MCBSP_WRITE(mcbsp, PCR0, config->pcr0); | ||
214 | if (mcbsp->pdata->has_ccr) { | ||
215 | MCBSP_WRITE(mcbsp, XCCR, config->xccr); | ||
216 | MCBSP_WRITE(mcbsp, RCCR, config->rccr); | ||
217 | } | ||
218 | /* Enable wakeup behavior */ | ||
219 | if (mcbsp->pdata->has_wakeup) | ||
220 | MCBSP_WRITE(mcbsp, WAKEUPEN, XRDYEN | RRDYEN); | ||
221 | |||
222 | /* Enable TX/RX sync error interrupts by default */ | ||
223 | if (mcbsp->irq) | ||
224 | MCBSP_WRITE(mcbsp, IRQEN, RSYNCERREN | XSYNCERREN | | ||
225 | RUNDFLEN | ROVFLEN | XUNDFLEN | XOVFLEN); | ||
226 | } | ||
227 | |||
228 | /** | ||
229 | * omap_mcbsp_dma_reg_params - returns the address of mcbsp data register | ||
230 | * @id - mcbsp id | ||
231 | * @stream - indicates the direction of data flow (rx or tx) | ||
232 | * | ||
233 | * Returns the address of mcbsp data transmit register or data receive register | ||
234 | * to be used by DMA for transferring/receiving data based on the value of | ||
235 | * @stream for the requested mcbsp given by @id | ||
236 | */ | ||
237 | static int omap_mcbsp_dma_reg_params(struct omap_mcbsp *mcbsp, | ||
238 | unsigned int stream) | ||
239 | { | ||
240 | int data_reg; | ||
241 | |||
242 | if (mcbsp->pdata->reg_size == 2) { | ||
243 | if (stream) | ||
244 | data_reg = OMAP_MCBSP_REG_DRR1; | ||
245 | else | ||
246 | data_reg = OMAP_MCBSP_REG_DXR1; | ||
247 | } else { | ||
248 | if (stream) | ||
249 | data_reg = OMAP_MCBSP_REG_DRR; | ||
250 | else | ||
251 | data_reg = OMAP_MCBSP_REG_DXR; | ||
252 | } | ||
253 | |||
254 | return mcbsp->phys_dma_base + data_reg * mcbsp->pdata->reg_step; | ||
255 | } | ||
256 | |||
257 | static void omap_st_on(struct omap_mcbsp *mcbsp) | ||
258 | { | ||
259 | unsigned int w; | ||
260 | |||
261 | if (mcbsp->pdata->force_ick_on) | ||
262 | mcbsp->pdata->force_ick_on(mcbsp->st_data->mcbsp_iclk, true); | ||
263 | |||
264 | /* Disable Sidetone clock auto-gating for normal operation */ | ||
265 | w = MCBSP_ST_READ(mcbsp, SYSCONFIG); | ||
266 | MCBSP_ST_WRITE(mcbsp, SYSCONFIG, w & ~(ST_AUTOIDLE)); | ||
267 | |||
268 | /* Enable McBSP Sidetone */ | ||
269 | w = MCBSP_READ(mcbsp, SSELCR); | ||
270 | MCBSP_WRITE(mcbsp, SSELCR, w | SIDETONEEN); | ||
271 | |||
272 | /* Enable Sidetone from Sidetone Core */ | ||
273 | w = MCBSP_ST_READ(mcbsp, SSELCR); | ||
274 | MCBSP_ST_WRITE(mcbsp, SSELCR, w | ST_SIDETONEEN); | ||
275 | } | ||
276 | |||
277 | static void omap_st_off(struct omap_mcbsp *mcbsp) | ||
278 | { | ||
279 | unsigned int w; | ||
280 | |||
281 | w = MCBSP_ST_READ(mcbsp, SSELCR); | ||
282 | MCBSP_ST_WRITE(mcbsp, SSELCR, w & ~(ST_SIDETONEEN)); | ||
283 | |||
284 | w = MCBSP_READ(mcbsp, SSELCR); | ||
285 | MCBSP_WRITE(mcbsp, SSELCR, w & ~(SIDETONEEN)); | ||
286 | |||
287 | /* Enable Sidetone clock auto-gating to reduce power consumption */ | ||
288 | w = MCBSP_ST_READ(mcbsp, SYSCONFIG); | ||
289 | MCBSP_ST_WRITE(mcbsp, SYSCONFIG, w | ST_AUTOIDLE); | ||
290 | |||
291 | if (mcbsp->pdata->force_ick_on) | ||
292 | mcbsp->pdata->force_ick_on(mcbsp->st_data->mcbsp_iclk, false); | ||
293 | } | ||
294 | |||
295 | static void omap_st_fir_write(struct omap_mcbsp *mcbsp, s16 *fir) | ||
296 | { | ||
297 | u16 val, i; | ||
298 | |||
299 | val = MCBSP_ST_READ(mcbsp, SSELCR); | ||
300 | |||
301 | if (val & ST_COEFFWREN) | ||
302 | MCBSP_ST_WRITE(mcbsp, SSELCR, val & ~(ST_COEFFWREN)); | ||
303 | |||
304 | MCBSP_ST_WRITE(mcbsp, SSELCR, val | ST_COEFFWREN); | ||
305 | |||
306 | for (i = 0; i < 128; i++) | ||
307 | MCBSP_ST_WRITE(mcbsp, SFIRCR, fir[i]); | ||
308 | |||
309 | i = 0; | ||
310 | |||
311 | val = MCBSP_ST_READ(mcbsp, SSELCR); | ||
312 | while (!(val & ST_COEFFWRDONE) && (++i < 1000)) | ||
313 | val = MCBSP_ST_READ(mcbsp, SSELCR); | ||
314 | |||
315 | MCBSP_ST_WRITE(mcbsp, SSELCR, val & ~(ST_COEFFWREN)); | ||
316 | |||
317 | if (i == 1000) | ||
318 | dev_err(mcbsp->dev, "McBSP FIR load error!\n"); | ||
319 | } | ||
320 | |||
321 | static void omap_st_chgain(struct omap_mcbsp *mcbsp) | ||
322 | { | ||
323 | u16 w; | ||
324 | struct omap_mcbsp_st_data *st_data = mcbsp->st_data; | ||
325 | |||
326 | w = MCBSP_ST_READ(mcbsp, SSELCR); | ||
327 | |||
328 | MCBSP_ST_WRITE(mcbsp, SGAINCR, ST_CH0GAIN(st_data->ch0gain) | \ | ||
329 | ST_CH1GAIN(st_data->ch1gain)); | ||
330 | } | ||
331 | |||
332 | int omap_st_set_chgain(struct omap_mcbsp *mcbsp, int channel, s16 chgain) | ||
333 | { | ||
334 | struct omap_mcbsp_st_data *st_data = mcbsp->st_data; | ||
335 | int ret = 0; | ||
336 | |||
337 | if (!st_data) | ||
338 | return -ENOENT; | ||
339 | |||
340 | spin_lock_irq(&mcbsp->lock); | ||
341 | if (channel == 0) | ||
342 | st_data->ch0gain = chgain; | ||
343 | else if (channel == 1) | ||
344 | st_data->ch1gain = chgain; | ||
345 | else | ||
346 | ret = -EINVAL; | ||
347 | |||
348 | if (st_data->enabled) | ||
349 | omap_st_chgain(mcbsp); | ||
350 | spin_unlock_irq(&mcbsp->lock); | ||
351 | |||
352 | return ret; | ||
353 | } | ||
354 | |||
355 | int omap_st_get_chgain(struct omap_mcbsp *mcbsp, int channel, s16 *chgain) | ||
356 | { | ||
357 | struct omap_mcbsp_st_data *st_data = mcbsp->st_data; | ||
358 | int ret = 0; | ||
359 | |||
360 | if (!st_data) | ||
361 | return -ENOENT; | ||
362 | |||
363 | spin_lock_irq(&mcbsp->lock); | ||
364 | if (channel == 0) | ||
365 | *chgain = st_data->ch0gain; | ||
366 | else if (channel == 1) | ||
367 | *chgain = st_data->ch1gain; | ||
368 | else | ||
369 | ret = -EINVAL; | ||
370 | spin_unlock_irq(&mcbsp->lock); | ||
371 | |||
372 | return ret; | ||
373 | } | ||
374 | |||
375 | static int omap_st_start(struct omap_mcbsp *mcbsp) | ||
376 | { | ||
377 | struct omap_mcbsp_st_data *st_data = mcbsp->st_data; | ||
378 | |||
379 | if (st_data->enabled && !st_data->running) { | ||
380 | omap_st_fir_write(mcbsp, st_data->taps); | ||
381 | omap_st_chgain(mcbsp); | ||
382 | |||
383 | if (!mcbsp->free) { | ||
384 | omap_st_on(mcbsp); | ||
385 | st_data->running = 1; | ||
386 | } | ||
387 | } | ||
388 | |||
389 | return 0; | ||
390 | } | ||
391 | |||
392 | int omap_st_enable(struct omap_mcbsp *mcbsp) | ||
393 | { | ||
394 | struct omap_mcbsp_st_data *st_data = mcbsp->st_data; | ||
395 | |||
396 | if (!st_data) | ||
397 | return -ENODEV; | ||
398 | |||
399 | spin_lock_irq(&mcbsp->lock); | ||
400 | st_data->enabled = 1; | ||
401 | omap_st_start(mcbsp); | ||
402 | spin_unlock_irq(&mcbsp->lock); | ||
403 | |||
404 | return 0; | ||
405 | } | ||
406 | |||
407 | static int omap_st_stop(struct omap_mcbsp *mcbsp) | ||
408 | { | ||
409 | struct omap_mcbsp_st_data *st_data = mcbsp->st_data; | ||
410 | |||
411 | if (st_data->running) { | ||
412 | if (!mcbsp->free) { | ||
413 | omap_st_off(mcbsp); | ||
414 | st_data->running = 0; | ||
415 | } | ||
416 | } | ||
417 | |||
418 | return 0; | ||
419 | } | ||
420 | |||
421 | int omap_st_disable(struct omap_mcbsp *mcbsp) | ||
422 | { | ||
423 | struct omap_mcbsp_st_data *st_data = mcbsp->st_data; | ||
424 | int ret = 0; | ||
425 | |||
426 | if (!st_data) | ||
427 | return -ENODEV; | ||
428 | |||
429 | spin_lock_irq(&mcbsp->lock); | ||
430 | omap_st_stop(mcbsp); | ||
431 | st_data->enabled = 0; | ||
432 | spin_unlock_irq(&mcbsp->lock); | ||
433 | |||
434 | return ret; | ||
435 | } | ||
436 | |||
437 | int omap_st_is_enabled(struct omap_mcbsp *mcbsp) | ||
438 | { | ||
439 | struct omap_mcbsp_st_data *st_data = mcbsp->st_data; | ||
440 | |||
441 | if (!st_data) | ||
442 | return -ENODEV; | ||
443 | |||
444 | return st_data->enabled; | ||
445 | } | ||
446 | |||
447 | /* | ||
448 | * omap_mcbsp_set_rx_threshold configures the transmit threshold in words. | ||
449 | * The threshold parameter is 1 based, and it is converted (threshold - 1) | ||
450 | * for the THRSH2 register. | ||
451 | */ | ||
452 | void omap_mcbsp_set_tx_threshold(struct omap_mcbsp *mcbsp, u16 threshold) | ||
453 | { | ||
454 | if (mcbsp->pdata->buffer_size == 0) | ||
455 | return; | ||
456 | |||
457 | if (threshold && threshold <= mcbsp->max_tx_thres) | ||
458 | MCBSP_WRITE(mcbsp, THRSH2, threshold - 1); | ||
459 | } | ||
460 | |||
461 | /* | ||
462 | * omap_mcbsp_set_rx_threshold configures the receive threshold in words. | ||
463 | * The threshold parameter is 1 based, and it is converted (threshold - 1) | ||
464 | * for the THRSH1 register. | ||
465 | */ | ||
466 | void omap_mcbsp_set_rx_threshold(struct omap_mcbsp *mcbsp, u16 threshold) | ||
467 | { | ||
468 | if (mcbsp->pdata->buffer_size == 0) | ||
469 | return; | ||
470 | |||
471 | if (threshold && threshold <= mcbsp->max_rx_thres) | ||
472 | MCBSP_WRITE(mcbsp, THRSH1, threshold - 1); | ||
473 | } | ||
474 | |||
475 | /* | ||
476 | * omap_mcbsp_get_tx_delay returns the number of used slots in the McBSP FIFO | ||
477 | */ | ||
478 | u16 omap_mcbsp_get_tx_delay(struct omap_mcbsp *mcbsp) | ||
479 | { | ||
480 | u16 buffstat; | ||
481 | |||
482 | if (mcbsp->pdata->buffer_size == 0) | ||
483 | return 0; | ||
484 | |||
485 | /* Returns the number of free locations in the buffer */ | ||
486 | buffstat = MCBSP_READ(mcbsp, XBUFFSTAT); | ||
487 | |||
488 | /* Number of slots are different in McBSP ports */ | ||
489 | return mcbsp->pdata->buffer_size - buffstat; | ||
490 | } | ||
491 | |||
492 | /* | ||
493 | * omap_mcbsp_get_rx_delay returns the number of free slots in the McBSP FIFO | ||
494 | * to reach the threshold value (when the DMA will be triggered to read it) | ||
495 | */ | ||
496 | u16 omap_mcbsp_get_rx_delay(struct omap_mcbsp *mcbsp) | ||
497 | { | ||
498 | u16 buffstat, threshold; | ||
499 | |||
500 | if (mcbsp->pdata->buffer_size == 0) | ||
501 | return 0; | ||
502 | |||
503 | /* Returns the number of used locations in the buffer */ | ||
504 | buffstat = MCBSP_READ(mcbsp, RBUFFSTAT); | ||
505 | /* RX threshold */ | ||
506 | threshold = MCBSP_READ(mcbsp, THRSH1); | ||
507 | |||
508 | /* Return the number of location till we reach the threshold limit */ | ||
509 | if (threshold <= buffstat) | ||
510 | return 0; | ||
511 | else | ||
512 | return threshold - buffstat; | ||
513 | } | ||
514 | |||
515 | int omap_mcbsp_request(struct omap_mcbsp *mcbsp) | ||
516 | { | ||
517 | void *reg_cache; | ||
518 | int err; | ||
519 | |||
520 | reg_cache = kzalloc(mcbsp->reg_cache_size, GFP_KERNEL); | ||
521 | if (!reg_cache) { | ||
522 | return -ENOMEM; | ||
523 | } | ||
524 | |||
525 | spin_lock(&mcbsp->lock); | ||
526 | if (!mcbsp->free) { | ||
527 | dev_err(mcbsp->dev, "McBSP%d is currently in use\n", | ||
528 | mcbsp->id); | ||
529 | err = -EBUSY; | ||
530 | goto err_kfree; | ||
531 | } | ||
532 | |||
533 | mcbsp->free = false; | ||
534 | mcbsp->reg_cache = reg_cache; | ||
535 | spin_unlock(&mcbsp->lock); | ||
536 | |||
537 | if (mcbsp->pdata && mcbsp->pdata->ops && mcbsp->pdata->ops->request) | ||
538 | mcbsp->pdata->ops->request(mcbsp->id - 1); | ||
539 | |||
540 | /* | ||
541 | * Make sure that transmitter, receiver and sample-rate generator are | ||
542 | * not running before activating IRQs. | ||
543 | */ | ||
544 | MCBSP_WRITE(mcbsp, SPCR1, 0); | ||
545 | MCBSP_WRITE(mcbsp, SPCR2, 0); | ||
546 | |||
547 | if (mcbsp->irq) { | ||
548 | err = request_irq(mcbsp->irq, omap_mcbsp_irq_handler, 0, | ||
549 | "McBSP", (void *)mcbsp); | ||
550 | if (err != 0) { | ||
551 | dev_err(mcbsp->dev, "Unable to request IRQ\n"); | ||
552 | goto err_clk_disable; | ||
553 | } | ||
554 | } else { | ||
555 | err = request_irq(mcbsp->tx_irq, omap_mcbsp_tx_irq_handler, 0, | ||
556 | "McBSP TX", (void *)mcbsp); | ||
557 | if (err != 0) { | ||
558 | dev_err(mcbsp->dev, "Unable to request TX IRQ\n"); | ||
559 | goto err_clk_disable; | ||
560 | } | ||
561 | |||
562 | err = request_irq(mcbsp->rx_irq, omap_mcbsp_rx_irq_handler, 0, | ||
563 | "McBSP RX", (void *)mcbsp); | ||
564 | if (err != 0) { | ||
565 | dev_err(mcbsp->dev, "Unable to request RX IRQ\n"); | ||
566 | goto err_free_irq; | ||
567 | } | ||
568 | } | ||
569 | |||
570 | return 0; | ||
571 | err_free_irq: | ||
572 | free_irq(mcbsp->tx_irq, (void *)mcbsp); | ||
573 | err_clk_disable: | ||
574 | if (mcbsp->pdata && mcbsp->pdata->ops && mcbsp->pdata->ops->free) | ||
575 | mcbsp->pdata->ops->free(mcbsp->id - 1); | ||
576 | |||
577 | /* Disable wakeup behavior */ | ||
578 | if (mcbsp->pdata->has_wakeup) | ||
579 | MCBSP_WRITE(mcbsp, WAKEUPEN, 0); | ||
580 | |||
581 | spin_lock(&mcbsp->lock); | ||
582 | mcbsp->free = true; | ||
583 | mcbsp->reg_cache = NULL; | ||
584 | err_kfree: | ||
585 | spin_unlock(&mcbsp->lock); | ||
586 | kfree(reg_cache); | ||
587 | |||
588 | return err; | ||
589 | } | ||
590 | |||
591 | void omap_mcbsp_free(struct omap_mcbsp *mcbsp) | ||
592 | { | ||
593 | void *reg_cache; | ||
594 | |||
595 | if (mcbsp->pdata && mcbsp->pdata->ops && mcbsp->pdata->ops->free) | ||
596 | mcbsp->pdata->ops->free(mcbsp->id - 1); | ||
597 | |||
598 | /* Disable wakeup behavior */ | ||
599 | if (mcbsp->pdata->has_wakeup) | ||
600 | MCBSP_WRITE(mcbsp, WAKEUPEN, 0); | ||
601 | |||
602 | /* Disable interrupt requests */ | ||
603 | if (mcbsp->irq) | ||
604 | MCBSP_WRITE(mcbsp, IRQEN, 0); | ||
605 | |||
606 | if (mcbsp->irq) { | ||
607 | free_irq(mcbsp->irq, (void *)mcbsp); | ||
608 | } else { | ||
609 | free_irq(mcbsp->rx_irq, (void *)mcbsp); | ||
610 | free_irq(mcbsp->tx_irq, (void *)mcbsp); | ||
611 | } | ||
612 | |||
613 | reg_cache = mcbsp->reg_cache; | ||
614 | |||
615 | /* | ||
616 | * Select CLKS source from internal source unconditionally before | ||
617 | * marking the McBSP port as free. | ||
618 | * If the external clock source via MCBSP_CLKS pin has been selected the | ||
619 | * system will refuse to enter idle if the CLKS pin source is not reset | ||
620 | * back to internal source. | ||
621 | */ | ||
622 | if (!mcbsp_omap1()) | ||
623 | omap2_mcbsp_set_clks_src(mcbsp, MCBSP_CLKS_PRCM_SRC); | ||
624 | |||
625 | spin_lock(&mcbsp->lock); | ||
626 | if (mcbsp->free) | ||
627 | dev_err(mcbsp->dev, "McBSP%d was not reserved\n", mcbsp->id); | ||
628 | else | ||
629 | mcbsp->free = true; | ||
630 | mcbsp->reg_cache = NULL; | ||
631 | spin_unlock(&mcbsp->lock); | ||
632 | |||
633 | kfree(reg_cache); | ||
634 | } | ||
635 | |||
636 | /* | ||
637 | * Here we start the McBSP, by enabling transmitter, receiver or both. | ||
638 | * If no transmitter or receiver is active prior calling, then sample-rate | ||
639 | * generator and frame sync are started. | ||
640 | */ | ||
641 | void omap_mcbsp_start(struct omap_mcbsp *mcbsp, int tx, int rx) | ||
642 | { | ||
643 | int enable_srg = 0; | ||
644 | u16 w; | ||
645 | |||
646 | if (mcbsp->st_data) | ||
647 | omap_st_start(mcbsp); | ||
648 | |||
649 | /* Only enable SRG, if McBSP is master */ | ||
650 | w = MCBSP_READ_CACHE(mcbsp, PCR0); | ||
651 | if (w & (FSXM | FSRM | CLKXM | CLKRM)) | ||
652 | enable_srg = !((MCBSP_READ_CACHE(mcbsp, SPCR2) | | ||
653 | MCBSP_READ_CACHE(mcbsp, SPCR1)) & 1); | ||
654 | |||
655 | if (enable_srg) { | ||
656 | /* Start the sample generator */ | ||
657 | w = MCBSP_READ_CACHE(mcbsp, SPCR2); | ||
658 | MCBSP_WRITE(mcbsp, SPCR2, w | (1 << 6)); | ||
659 | } | ||
660 | |||
661 | /* Enable transmitter and receiver */ | ||
662 | tx &= 1; | ||
663 | w = MCBSP_READ_CACHE(mcbsp, SPCR2); | ||
664 | MCBSP_WRITE(mcbsp, SPCR2, w | tx); | ||
665 | |||
666 | rx &= 1; | ||
667 | w = MCBSP_READ_CACHE(mcbsp, SPCR1); | ||
668 | MCBSP_WRITE(mcbsp, SPCR1, w | rx); | ||
669 | |||
670 | /* | ||
671 | * Worst case: CLKSRG*2 = 8000khz: (1/8000) * 2 * 2 usec | ||
672 | * REVISIT: 100us may give enough time for two CLKSRG, however | ||
673 | * due to some unknown PM related, clock gating etc. reason it | ||
674 | * is now at 500us. | ||
675 | */ | ||
676 | udelay(500); | ||
677 | |||
678 | if (enable_srg) { | ||
679 | /* Start frame sync */ | ||
680 | w = MCBSP_READ_CACHE(mcbsp, SPCR2); | ||
681 | MCBSP_WRITE(mcbsp, SPCR2, w | (1 << 7)); | ||
682 | } | ||
683 | |||
684 | if (mcbsp->pdata->has_ccr) { | ||
685 | /* Release the transmitter and receiver */ | ||
686 | w = MCBSP_READ_CACHE(mcbsp, XCCR); | ||
687 | w &= ~(tx ? XDISABLE : 0); | ||
688 | MCBSP_WRITE(mcbsp, XCCR, w); | ||
689 | w = MCBSP_READ_CACHE(mcbsp, RCCR); | ||
690 | w &= ~(rx ? RDISABLE : 0); | ||
691 | MCBSP_WRITE(mcbsp, RCCR, w); | ||
692 | } | ||
693 | |||
694 | /* Dump McBSP Regs */ | ||
695 | omap_mcbsp_dump_reg(mcbsp); | ||
696 | } | ||
697 | |||
698 | void omap_mcbsp_stop(struct omap_mcbsp *mcbsp, int tx, int rx) | ||
699 | { | ||
700 | int idle; | ||
701 | u16 w; | ||
702 | |||
703 | /* Reset transmitter */ | ||
704 | tx &= 1; | ||
705 | if (mcbsp->pdata->has_ccr) { | ||
706 | w = MCBSP_READ_CACHE(mcbsp, XCCR); | ||
707 | w |= (tx ? XDISABLE : 0); | ||
708 | MCBSP_WRITE(mcbsp, XCCR, w); | ||
709 | } | ||
710 | w = MCBSP_READ_CACHE(mcbsp, SPCR2); | ||
711 | MCBSP_WRITE(mcbsp, SPCR2, w & ~tx); | ||
712 | |||
713 | /* Reset receiver */ | ||
714 | rx &= 1; | ||
715 | if (mcbsp->pdata->has_ccr) { | ||
716 | w = MCBSP_READ_CACHE(mcbsp, RCCR); | ||
717 | w |= (rx ? RDISABLE : 0); | ||
718 | MCBSP_WRITE(mcbsp, RCCR, w); | ||
719 | } | ||
720 | w = MCBSP_READ_CACHE(mcbsp, SPCR1); | ||
721 | MCBSP_WRITE(mcbsp, SPCR1, w & ~rx); | ||
722 | |||
723 | idle = !((MCBSP_READ_CACHE(mcbsp, SPCR2) | | ||
724 | MCBSP_READ_CACHE(mcbsp, SPCR1)) & 1); | ||
725 | |||
726 | if (idle) { | ||
727 | /* Reset the sample rate generator */ | ||
728 | w = MCBSP_READ_CACHE(mcbsp, SPCR2); | ||
729 | MCBSP_WRITE(mcbsp, SPCR2, w & ~(1 << 6)); | ||
730 | } | ||
731 | |||
732 | if (mcbsp->st_data) | ||
733 | omap_st_stop(mcbsp); | ||
734 | } | ||
735 | |||
736 | int omap2_mcbsp_set_clks_src(struct omap_mcbsp *mcbsp, u8 fck_src_id) | ||
737 | { | ||
738 | struct clk *fck_src; | ||
739 | const char *src; | ||
740 | int r; | ||
741 | |||
742 | if (fck_src_id == MCBSP_CLKS_PAD_SRC) | ||
743 | src = "pad_fck"; | ||
744 | else if (fck_src_id == MCBSP_CLKS_PRCM_SRC) | ||
745 | src = "prcm_fck"; | ||
746 | else | ||
747 | return -EINVAL; | ||
748 | |||
749 | fck_src = clk_get(mcbsp->dev, src); | ||
750 | if (IS_ERR(fck_src)) { | ||
751 | dev_err(mcbsp->dev, "CLKS: could not clk_get() %s\n", src); | ||
752 | return -EINVAL; | ||
753 | } | ||
754 | |||
755 | pm_runtime_put_sync(mcbsp->dev); | ||
756 | |||
757 | r = clk_set_parent(mcbsp->fclk, fck_src); | ||
758 | if (r) { | ||
759 | dev_err(mcbsp->dev, "CLKS: could not clk_set_parent() to %s\n", | ||
760 | src); | ||
761 | clk_put(fck_src); | ||
762 | return r; | ||
763 | } | ||
764 | |||
765 | pm_runtime_get_sync(mcbsp->dev); | ||
766 | |||
767 | clk_put(fck_src); | ||
768 | |||
769 | return 0; | ||
770 | |||
771 | } | ||
772 | |||
773 | #define max_thres(m) (mcbsp->pdata->buffer_size) | ||
774 | #define valid_threshold(m, val) ((val) <= max_thres(m)) | ||
775 | #define THRESHOLD_PROP_BUILDER(prop) \ | ||
776 | static ssize_t prop##_show(struct device *dev, \ | ||
777 | struct device_attribute *attr, char *buf) \ | ||
778 | { \ | ||
779 | struct omap_mcbsp *mcbsp = dev_get_drvdata(dev); \ | ||
780 | \ | ||
781 | return sprintf(buf, "%u\n", mcbsp->prop); \ | ||
782 | } \ | ||
783 | \ | ||
784 | static ssize_t prop##_store(struct device *dev, \ | ||
785 | struct device_attribute *attr, \ | ||
786 | const char *buf, size_t size) \ | ||
787 | { \ | ||
788 | struct omap_mcbsp *mcbsp = dev_get_drvdata(dev); \ | ||
789 | unsigned long val; \ | ||
790 | int status; \ | ||
791 | \ | ||
792 | status = kstrtoul(buf, 0, &val); \ | ||
793 | if (status) \ | ||
794 | return status; \ | ||
795 | \ | ||
796 | if (!valid_threshold(mcbsp, val)) \ | ||
797 | return -EDOM; \ | ||
798 | \ | ||
799 | mcbsp->prop = val; \ | ||
800 | return size; \ | ||
801 | } \ | ||
802 | \ | ||
803 | static DEVICE_ATTR(prop, 0644, prop##_show, prop##_store); | ||
804 | |||
805 | THRESHOLD_PROP_BUILDER(max_tx_thres); | ||
806 | THRESHOLD_PROP_BUILDER(max_rx_thres); | ||
807 | |||
808 | static const char *dma_op_modes[] = { | ||
809 | "element", "threshold", | ||
810 | }; | ||
811 | |||
812 | static ssize_t dma_op_mode_show(struct device *dev, | ||
813 | struct device_attribute *attr, char *buf) | ||
814 | { | ||
815 | struct omap_mcbsp *mcbsp = dev_get_drvdata(dev); | ||
816 | int dma_op_mode, i = 0; | ||
817 | ssize_t len = 0; | ||
818 | const char * const *s; | ||
819 | |||
820 | dma_op_mode = mcbsp->dma_op_mode; | ||
821 | |||
822 | for (s = &dma_op_modes[i]; i < ARRAY_SIZE(dma_op_modes); s++, i++) { | ||
823 | if (dma_op_mode == i) | ||
824 | len += sprintf(buf + len, "[%s] ", *s); | ||
825 | else | ||
826 | len += sprintf(buf + len, "%s ", *s); | ||
827 | } | ||
828 | len += sprintf(buf + len, "\n"); | ||
829 | |||
830 | return len; | ||
831 | } | ||
832 | |||
833 | static ssize_t dma_op_mode_store(struct device *dev, | ||
834 | struct device_attribute *attr, | ||
835 | const char *buf, size_t size) | ||
836 | { | ||
837 | struct omap_mcbsp *mcbsp = dev_get_drvdata(dev); | ||
838 | int i; | ||
839 | |||
840 | i = sysfs_match_string(dma_op_modes, buf); | ||
841 | if (i < 0) | ||
842 | return i; | ||
843 | |||
844 | spin_lock_irq(&mcbsp->lock); | ||
845 | if (!mcbsp->free) { | ||
846 | size = -EBUSY; | ||
847 | goto unlock; | ||
848 | } | ||
849 | mcbsp->dma_op_mode = i; | ||
850 | |||
851 | unlock: | ||
852 | spin_unlock_irq(&mcbsp->lock); | ||
853 | |||
854 | return size; | ||
855 | } | ||
856 | |||
857 | static DEVICE_ATTR_RW(dma_op_mode); | ||
858 | |||
859 | static const struct attribute *additional_attrs[] = { | ||
860 | &dev_attr_max_tx_thres.attr, | ||
861 | &dev_attr_max_rx_thres.attr, | ||
862 | &dev_attr_dma_op_mode.attr, | ||
863 | NULL, | ||
864 | }; | ||
865 | |||
866 | static const struct attribute_group additional_attr_group = { | ||
867 | .attrs = (struct attribute **)additional_attrs, | ||
868 | }; | ||
869 | |||
870 | static ssize_t st_taps_show(struct device *dev, | ||
871 | struct device_attribute *attr, char *buf) | ||
872 | { | ||
873 | struct omap_mcbsp *mcbsp = dev_get_drvdata(dev); | ||
874 | struct omap_mcbsp_st_data *st_data = mcbsp->st_data; | ||
875 | ssize_t status = 0; | ||
876 | int i; | ||
877 | |||
878 | spin_lock_irq(&mcbsp->lock); | ||
879 | for (i = 0; i < st_data->nr_taps; i++) | ||
880 | status += sprintf(&buf[status], (i ? ", %d" : "%d"), | ||
881 | st_data->taps[i]); | ||
882 | if (i) | ||
883 | status += sprintf(&buf[status], "\n"); | ||
884 | spin_unlock_irq(&mcbsp->lock); | ||
885 | |||
886 | return status; | ||
887 | } | ||
888 | |||
889 | static ssize_t st_taps_store(struct device *dev, | ||
890 | struct device_attribute *attr, | ||
891 | const char *buf, size_t size) | ||
892 | { | ||
893 | struct omap_mcbsp *mcbsp = dev_get_drvdata(dev); | ||
894 | struct omap_mcbsp_st_data *st_data = mcbsp->st_data; | ||
895 | int val, tmp, status, i = 0; | ||
896 | |||
897 | spin_lock_irq(&mcbsp->lock); | ||
898 | memset(st_data->taps, 0, sizeof(st_data->taps)); | ||
899 | st_data->nr_taps = 0; | ||
900 | |||
901 | do { | ||
902 | status = sscanf(buf, "%d%n", &val, &tmp); | ||
903 | if (status < 0 || status == 0) { | ||
904 | size = -EINVAL; | ||
905 | goto out; | ||
906 | } | ||
907 | if (val < -32768 || val > 32767) { | ||
908 | size = -EINVAL; | ||
909 | goto out; | ||
910 | } | ||
911 | st_data->taps[i++] = val; | ||
912 | buf += tmp; | ||
913 | if (*buf != ',') | ||
914 | break; | ||
915 | buf++; | ||
916 | } while (1); | ||
917 | |||
918 | st_data->nr_taps = i; | ||
919 | |||
920 | out: | ||
921 | spin_unlock_irq(&mcbsp->lock); | ||
922 | |||
923 | return size; | ||
924 | } | ||
925 | |||
926 | static DEVICE_ATTR_RW(st_taps); | ||
927 | |||
928 | static const struct attribute *sidetone_attrs[] = { | ||
929 | &dev_attr_st_taps.attr, | ||
930 | NULL, | ||
931 | }; | ||
932 | |||
933 | static const struct attribute_group sidetone_attr_group = { | ||
934 | .attrs = (struct attribute **)sidetone_attrs, | ||
935 | }; | ||
936 | |||
937 | static int omap_st_add(struct omap_mcbsp *mcbsp, struct resource *res) | ||
938 | { | ||
939 | struct omap_mcbsp_st_data *st_data; | ||
940 | int err; | ||
941 | |||
942 | st_data = devm_kzalloc(mcbsp->dev, sizeof(*mcbsp->st_data), GFP_KERNEL); | ||
943 | if (!st_data) | ||
944 | return -ENOMEM; | ||
945 | |||
946 | st_data->mcbsp_iclk = clk_get(mcbsp->dev, "ick"); | ||
947 | if (IS_ERR(st_data->mcbsp_iclk)) { | ||
948 | dev_warn(mcbsp->dev, | ||
949 | "Failed to get ick, sidetone might be broken\n"); | ||
950 | st_data->mcbsp_iclk = NULL; | ||
951 | } | ||
952 | |||
953 | st_data->io_base_st = devm_ioremap(mcbsp->dev, res->start, | ||
954 | resource_size(res)); | ||
955 | if (!st_data->io_base_st) | ||
956 | return -ENOMEM; | ||
957 | |||
958 | err = sysfs_create_group(&mcbsp->dev->kobj, &sidetone_attr_group); | ||
959 | if (err) | ||
960 | return err; | ||
961 | |||
962 | mcbsp->st_data = st_data; | ||
963 | return 0; | ||
964 | } | ||
965 | |||
966 | /* | ||
967 | * McBSP1 and McBSP3 are directly mapped on 1610 and 1510. | ||
968 | * 730 has only 2 McBSP, and both of them are MPU peripherals. | ||
969 | */ | ||
970 | int omap_mcbsp_init(struct platform_device *pdev) | ||
971 | { | ||
972 | struct omap_mcbsp *mcbsp = platform_get_drvdata(pdev); | ||
973 | struct resource *res; | ||
974 | int ret = 0; | ||
975 | |||
976 | spin_lock_init(&mcbsp->lock); | ||
977 | mcbsp->free = true; | ||
978 | |||
979 | res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "mpu"); | ||
980 | if (!res) | ||
981 | res = platform_get_resource(pdev, IORESOURCE_MEM, 0); | ||
982 | |||
983 | mcbsp->io_base = devm_ioremap_resource(&pdev->dev, res); | ||
984 | if (IS_ERR(mcbsp->io_base)) | ||
985 | return PTR_ERR(mcbsp->io_base); | ||
986 | |||
987 | mcbsp->phys_base = res->start; | ||
988 | mcbsp->reg_cache_size = resource_size(res); | ||
989 | |||
990 | res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "dma"); | ||
991 | if (!res) | ||
992 | mcbsp->phys_dma_base = mcbsp->phys_base; | ||
993 | else | ||
994 | mcbsp->phys_dma_base = res->start; | ||
995 | |||
996 | /* | ||
997 | * OMAP1, 2 uses two interrupt lines: TX, RX | ||
998 | * OMAP2430, OMAP3 SoC have combined IRQ line as well. | ||
999 | * OMAP4 and newer SoC only have the combined IRQ line. | ||
1000 | * Use the combined IRQ if available since it gives better debugging | ||
1001 | * possibilities. | ||
1002 | */ | ||
1003 | mcbsp->irq = platform_get_irq_byname(pdev, "common"); | ||
1004 | if (mcbsp->irq == -ENXIO) { | ||
1005 | mcbsp->tx_irq = platform_get_irq_byname(pdev, "tx"); | ||
1006 | |||
1007 | if (mcbsp->tx_irq == -ENXIO) { | ||
1008 | mcbsp->irq = platform_get_irq(pdev, 0); | ||
1009 | mcbsp->tx_irq = 0; | ||
1010 | } else { | ||
1011 | mcbsp->rx_irq = platform_get_irq_byname(pdev, "rx"); | ||
1012 | mcbsp->irq = 0; | ||
1013 | } | ||
1014 | } | ||
1015 | |||
1016 | if (!pdev->dev.of_node) { | ||
1017 | res = platform_get_resource_byname(pdev, IORESOURCE_DMA, "tx"); | ||
1018 | if (!res) { | ||
1019 | dev_err(&pdev->dev, "invalid tx DMA channel\n"); | ||
1020 | return -ENODEV; | ||
1021 | } | ||
1022 | mcbsp->dma_req[0] = res->start; | ||
1023 | mcbsp->dma_data[0].filter_data = &mcbsp->dma_req[0]; | ||
1024 | |||
1025 | res = platform_get_resource_byname(pdev, IORESOURCE_DMA, "rx"); | ||
1026 | if (!res) { | ||
1027 | dev_err(&pdev->dev, "invalid rx DMA channel\n"); | ||
1028 | return -ENODEV; | ||
1029 | } | ||
1030 | mcbsp->dma_req[1] = res->start; | ||
1031 | mcbsp->dma_data[1].filter_data = &mcbsp->dma_req[1]; | ||
1032 | } else { | ||
1033 | mcbsp->dma_data[0].filter_data = "tx"; | ||
1034 | mcbsp->dma_data[1].filter_data = "rx"; | ||
1035 | } | ||
1036 | |||
1037 | mcbsp->dma_data[0].addr = omap_mcbsp_dma_reg_params(mcbsp, 0); | ||
1038 | mcbsp->dma_data[0].maxburst = 4; | ||
1039 | |||
1040 | mcbsp->dma_data[1].addr = omap_mcbsp_dma_reg_params(mcbsp, 1); | ||
1041 | mcbsp->dma_data[1].maxburst = 4; | ||
1042 | |||
1043 | mcbsp->fclk = clk_get(&pdev->dev, "fck"); | ||
1044 | if (IS_ERR(mcbsp->fclk)) { | ||
1045 | ret = PTR_ERR(mcbsp->fclk); | ||
1046 | dev_err(mcbsp->dev, "unable to get fck: %d\n", ret); | ||
1047 | return ret; | ||
1048 | } | ||
1049 | |||
1050 | mcbsp->dma_op_mode = MCBSP_DMA_MODE_ELEMENT; | ||
1051 | if (mcbsp->pdata->buffer_size) { | ||
1052 | /* | ||
1053 | * Initially configure the maximum thresholds to a safe value. | ||
1054 | * The McBSP FIFO usage with these values should not go under | ||
1055 | * 16 locations. | ||
1056 | * If the whole FIFO without safety buffer is used, than there | ||
1057 | * is a possibility that the DMA will be not able to push the | ||
1058 | * new data on time, causing channel shifts in runtime. | ||
1059 | */ | ||
1060 | mcbsp->max_tx_thres = max_thres(mcbsp) - 0x10; | ||
1061 | mcbsp->max_rx_thres = max_thres(mcbsp) - 0x10; | ||
1062 | |||
1063 | ret = sysfs_create_group(&mcbsp->dev->kobj, | ||
1064 | &additional_attr_group); | ||
1065 | if (ret) { | ||
1066 | dev_err(mcbsp->dev, | ||
1067 | "Unable to create additional controls\n"); | ||
1068 | goto err_thres; | ||
1069 | } | ||
1070 | } else { | ||
1071 | mcbsp->max_tx_thres = -EINVAL; | ||
1072 | mcbsp->max_rx_thres = -EINVAL; | ||
1073 | } | ||
1074 | |||
1075 | res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "sidetone"); | ||
1076 | if (res) { | ||
1077 | ret = omap_st_add(mcbsp, res); | ||
1078 | if (ret) { | ||
1079 | dev_err(mcbsp->dev, | ||
1080 | "Unable to create sidetone controls\n"); | ||
1081 | goto err_st; | ||
1082 | } | ||
1083 | } | ||
1084 | |||
1085 | return 0; | ||
1086 | |||
1087 | err_st: | ||
1088 | if (mcbsp->pdata->buffer_size) | ||
1089 | sysfs_remove_group(&mcbsp->dev->kobj, &additional_attr_group); | ||
1090 | err_thres: | ||
1091 | clk_put(mcbsp->fclk); | ||
1092 | return ret; | ||
1093 | } | ||
1094 | |||
1095 | void omap_mcbsp_cleanup(struct omap_mcbsp *mcbsp) | ||
1096 | { | ||
1097 | if (mcbsp->pdata->buffer_size) | ||
1098 | sysfs_remove_group(&mcbsp->dev->kobj, &additional_attr_group); | ||
1099 | |||
1100 | if (mcbsp->st_data) { | ||
1101 | sysfs_remove_group(&mcbsp->dev->kobj, &sidetone_attr_group); | ||
1102 | clk_put(mcbsp->st_data->mcbsp_iclk); | ||
1103 | } | ||
1104 | } | ||
diff --git a/sound/soc/pxa/Kconfig b/sound/soc/pxa/Kconfig index 943b44de1464..67159a6b90a8 100644 --- a/sound/soc/pxa/Kconfig +++ b/sound/soc/pxa/Kconfig | |||
@@ -79,7 +79,7 @@ config SND_PXA2XX_SOC_TOSA | |||
79 | tristate "SoC AC97 Audio support for Tosa" | 79 | tristate "SoC AC97 Audio support for Tosa" |
80 | depends on SND_PXA2XX_SOC && MACH_TOSA | 80 | depends on SND_PXA2XX_SOC && MACH_TOSA |
81 | depends on MFD_TC6393XB | 81 | depends on MFD_TC6393XB |
82 | depends on !AC97_BUS | 82 | depends on AC97_BUS=n |
83 | select SND_PXA2XX_SOC_AC97 | 83 | select SND_PXA2XX_SOC_AC97 |
84 | select SND_SOC_WM9712 | 84 | select SND_SOC_WM9712 |
85 | help | 85 | help |
@@ -89,7 +89,7 @@ config SND_PXA2XX_SOC_TOSA | |||
89 | config SND_PXA2XX_SOC_E740 | 89 | config SND_PXA2XX_SOC_E740 |
90 | tristate "SoC AC97 Audio support for e740" | 90 | tristate "SoC AC97 Audio support for e740" |
91 | depends on SND_PXA2XX_SOC && MACH_E740 | 91 | depends on SND_PXA2XX_SOC && MACH_E740 |
92 | depends on !AC97_BUS | 92 | depends on AC97_BUS=n |
93 | select SND_SOC_WM9705 | 93 | select SND_SOC_WM9705 |
94 | select SND_PXA2XX_SOC_AC97 | 94 | select SND_PXA2XX_SOC_AC97 |
95 | help | 95 | help |
@@ -99,7 +99,7 @@ config SND_PXA2XX_SOC_E740 | |||
99 | config SND_PXA2XX_SOC_E750 | 99 | config SND_PXA2XX_SOC_E750 |
100 | tristate "SoC AC97 Audio support for e750" | 100 | tristate "SoC AC97 Audio support for e750" |
101 | depends on SND_PXA2XX_SOC && MACH_E750 | 101 | depends on SND_PXA2XX_SOC && MACH_E750 |
102 | depends on !AC97_BUS | 102 | depends on AC97_BUS=n |
103 | select SND_SOC_WM9705 | 103 | select SND_SOC_WM9705 |
104 | select SND_PXA2XX_SOC_AC97 | 104 | select SND_PXA2XX_SOC_AC97 |
105 | help | 105 | help |
@@ -109,7 +109,7 @@ config SND_PXA2XX_SOC_E750 | |||
109 | config SND_PXA2XX_SOC_E800 | 109 | config SND_PXA2XX_SOC_E800 |
110 | tristate "SoC AC97 Audio support for e800" | 110 | tristate "SoC AC97 Audio support for e800" |
111 | depends on SND_PXA2XX_SOC && MACH_E800 | 111 | depends on SND_PXA2XX_SOC && MACH_E800 |
112 | depends on !AC97_BUS | 112 | depends on AC97_BUS=n |
113 | select SND_SOC_WM9712 | 113 | select SND_SOC_WM9712 |
114 | select SND_PXA2XX_SOC_AC97 | 114 | select SND_PXA2XX_SOC_AC97 |
115 | help | 115 | help |
@@ -120,7 +120,7 @@ config SND_PXA2XX_SOC_EM_X270 | |||
120 | tristate "SoC Audio support for CompuLab EM-x270, eXeda and CM-X300" | 120 | tristate "SoC Audio support for CompuLab EM-x270, eXeda and CM-X300" |
121 | depends on SND_PXA2XX_SOC && (MACH_EM_X270 || MACH_EXEDA || \ | 121 | depends on SND_PXA2XX_SOC && (MACH_EM_X270 || MACH_EXEDA || \ |
122 | MACH_CM_X300) | 122 | MACH_CM_X300) |
123 | depends on !AC97_BUS | 123 | depends on AC97_BUS=n |
124 | select SND_PXA2XX_SOC_AC97 | 124 | select SND_PXA2XX_SOC_AC97 |
125 | select SND_SOC_WM9712 | 125 | select SND_SOC_WM9712 |
126 | help | 126 | help |
@@ -131,7 +131,7 @@ config SND_PXA2XX_SOC_PALM27X | |||
131 | bool "SoC Audio support for Palm T|X, T5, E2 and LifeDrive" | 131 | bool "SoC Audio support for Palm T|X, T5, E2 and LifeDrive" |
132 | depends on SND_PXA2XX_SOC && (MACH_PALMLD || MACH_PALMTX || \ | 132 | depends on SND_PXA2XX_SOC && (MACH_PALMLD || MACH_PALMTX || \ |
133 | MACH_PALMT5 || MACH_PALMTE2) | 133 | MACH_PALMT5 || MACH_PALMTE2) |
134 | depends on !AC97_BUS | 134 | depends on AC97_BUS=n |
135 | select SND_PXA2XX_SOC_AC97 | 135 | select SND_PXA2XX_SOC_AC97 |
136 | select SND_SOC_WM9712 | 136 | select SND_SOC_WM9712 |
137 | help | 137 | help |
@@ -161,7 +161,7 @@ config SND_SOC_TTC_DKB | |||
161 | config SND_SOC_ZYLONITE | 161 | config SND_SOC_ZYLONITE |
162 | tristate "SoC Audio support for Marvell Zylonite" | 162 | tristate "SoC Audio support for Marvell Zylonite" |
163 | depends on SND_PXA2XX_SOC && MACH_ZYLONITE | 163 | depends on SND_PXA2XX_SOC && MACH_ZYLONITE |
164 | depends on !AC97_BUS | 164 | depends on AC97_BUS=n |
165 | select SND_PXA2XX_SOC_AC97 | 165 | select SND_PXA2XX_SOC_AC97 |
166 | select SND_PXA_SOC_SSP | 166 | select SND_PXA_SOC_SSP |
167 | select SND_SOC_WM9713 | 167 | select SND_SOC_WM9713 |
@@ -169,16 +169,6 @@ config SND_SOC_ZYLONITE | |||
169 | Say Y if you want to add support for SoC audio on the | 169 | Say Y if you want to add support for SoC audio on the |
170 | Marvell Zylonite reference platform. | 170 | Marvell Zylonite reference platform. |
171 | 171 | ||
172 | config SND_SOC_RAUMFELD | ||
173 | tristate "SoC Audio support Raumfeld audio adapter" | ||
174 | depends on SND_PXA2XX_SOC && (MACH_RAUMFELD_SPEAKER || MACH_RAUMFELD_CONNECTOR) | ||
175 | depends on I2C && SPI_MASTER | ||
176 | select SND_PXA_SOC_SSP | ||
177 | select SND_SOC_CS4270 | ||
178 | select SND_SOC_AK4104 | ||
179 | help | ||
180 | Say Y if you want to add support for SoC audio on Raumfeld devices | ||
181 | |||
182 | config SND_PXA2XX_SOC_HX4700 | 172 | config SND_PXA2XX_SOC_HX4700 |
183 | tristate "SoC Audio support for HP iPAQ hx4700" | 173 | tristate "SoC Audio support for HP iPAQ hx4700" |
184 | depends on SND_PXA2XX_SOC && MACH_H4700 && I2C | 174 | depends on SND_PXA2XX_SOC && MACH_H4700 && I2C |
@@ -201,7 +191,7 @@ config SND_PXA2XX_SOC_MAGICIAN | |||
201 | config SND_PXA2XX_SOC_MIOA701 | 191 | config SND_PXA2XX_SOC_MIOA701 |
202 | tristate "SoC Audio support for MIO A701" | 192 | tristate "SoC Audio support for MIO A701" |
203 | depends on SND_PXA2XX_SOC && MACH_MIOA701 | 193 | depends on SND_PXA2XX_SOC && MACH_MIOA701 |
204 | depends on !AC97_BUS | 194 | depends on AC97_BUS=n |
205 | select SND_PXA2XX_SOC_AC97 | 195 | select SND_PXA2XX_SOC_AC97 |
206 | select SND_SOC_WM9713 | 196 | select SND_SOC_WM9713 |
207 | help | 197 | help |
diff --git a/sound/soc/pxa/Makefile b/sound/soc/pxa/Makefile index 5b265662f04f..0ab2a9dcb720 100644 --- a/sound/soc/pxa/Makefile +++ b/sound/soc/pxa/Makefile | |||
@@ -49,6 +49,5 @@ obj-$(CONFIG_SND_PXA2XX_SOC_MIOA701) += snd-soc-mioa701.o | |||
49 | obj-$(CONFIG_SND_PXA2XX_SOC_Z2) += snd-soc-z2.o | 49 | obj-$(CONFIG_SND_PXA2XX_SOC_Z2) += snd-soc-z2.o |
50 | obj-$(CONFIG_SND_SOC_ZYLONITE) += snd-soc-zylonite.o | 50 | obj-$(CONFIG_SND_SOC_ZYLONITE) += snd-soc-zylonite.o |
51 | obj-$(CONFIG_SND_PXA2XX_SOC_IMOTE2) += snd-soc-imote2.o | 51 | obj-$(CONFIG_SND_PXA2XX_SOC_IMOTE2) += snd-soc-imote2.o |
52 | obj-$(CONFIG_SND_SOC_RAUMFELD) += snd-soc-raumfeld.o | ||
53 | obj-$(CONFIG_SND_MMP_SOC_BROWNSTONE) += snd-soc-brownstone.o | 52 | obj-$(CONFIG_SND_MMP_SOC_BROWNSTONE) += snd-soc-brownstone.o |
54 | obj-$(CONFIG_SND_SOC_TTC_DKB) += snd-soc-ttc-dkb.o | 53 | obj-$(CONFIG_SND_SOC_TTC_DKB) += snd-soc-ttc-dkb.o |
diff --git a/sound/soc/pxa/raumfeld.c b/sound/soc/pxa/raumfeld.c deleted file mode 100644 index 111a907c4eb9..000000000000 --- a/sound/soc/pxa/raumfeld.c +++ /dev/null | |||
@@ -1,318 +0,0 @@ | |||
1 | /* | ||
2 | * raumfeld_audio.c -- SoC audio for Raumfeld audio devices | ||
3 | * | ||
4 | * Copyright (c) 2009 Daniel Mack <daniel@caiaq.de> | ||
5 | * | ||
6 | * based on code from: | ||
7 | * | ||
8 | * Wolfson Microelectronics PLC. | ||
9 | * Openedhand Ltd. | ||
10 | * Liam Girdwood <lrg@slimlogic.co.uk> | ||
11 | * Richard Purdie <richard@openedhand.com> | ||
12 | * | ||
13 | * This program is free software; you can redistribute it and/or modify it | ||
14 | * under the terms of the GNU General Public License as published by the | ||
15 | * Free Software Foundation; either version 2 of the License, or (at your | ||
16 | * option) any later version. | ||
17 | */ | ||
18 | |||
19 | #include <linux/module.h> | ||
20 | #include <linux/i2c.h> | ||
21 | #include <linux/delay.h> | ||
22 | #include <linux/gpio.h> | ||
23 | #include <sound/pcm.h> | ||
24 | #include <sound/soc.h> | ||
25 | |||
26 | #include <asm/mach-types.h> | ||
27 | |||
28 | #include "pxa-ssp.h" | ||
29 | |||
30 | #define GPIO_SPDIF_RESET (38) | ||
31 | #define GPIO_MCLK_RESET (111) | ||
32 | #define GPIO_CODEC_RESET (120) | ||
33 | |||
34 | static struct i2c_client *max9486_client; | ||
35 | static struct i2c_board_info max9486_hwmon_info = { | ||
36 | I2C_BOARD_INFO("max9485", 0x63), | ||
37 | }; | ||
38 | |||
39 | #define MAX9485_MCLK_FREQ_112896 0x22 | ||
40 | #define MAX9485_MCLK_FREQ_122880 0x23 | ||
41 | #define MAX9485_MCLK_FREQ_225792 0x32 | ||
42 | #define MAX9485_MCLK_FREQ_245760 0x33 | ||
43 | |||
44 | static void set_max9485_clk(char clk) | ||
45 | { | ||
46 | i2c_master_send(max9486_client, &clk, 1); | ||
47 | } | ||
48 | |||
49 | static void raumfeld_enable_audio(bool en) | ||
50 | { | ||
51 | if (en) { | ||
52 | gpio_set_value(GPIO_MCLK_RESET, 1); | ||
53 | |||
54 | /* wait some time to let the clocks become stable */ | ||
55 | msleep(100); | ||
56 | |||
57 | gpio_set_value(GPIO_SPDIF_RESET, 1); | ||
58 | gpio_set_value(GPIO_CODEC_RESET, 1); | ||
59 | } else { | ||
60 | gpio_set_value(GPIO_MCLK_RESET, 0); | ||
61 | gpio_set_value(GPIO_SPDIF_RESET, 0); | ||
62 | gpio_set_value(GPIO_CODEC_RESET, 0); | ||
63 | } | ||
64 | } | ||
65 | |||
66 | /* CS4270 */ | ||
67 | static int raumfeld_cs4270_startup(struct snd_pcm_substream *substream) | ||
68 | { | ||
69 | struct snd_soc_pcm_runtime *rtd = substream->private_data; | ||
70 | struct snd_soc_dai *codec_dai = rtd->codec_dai; | ||
71 | |||
72 | /* set freq to 0 to enable all possible codec sample rates */ | ||
73 | return snd_soc_dai_set_sysclk(codec_dai, 0, 0, 0); | ||
74 | } | ||
75 | |||
76 | static void raumfeld_cs4270_shutdown(struct snd_pcm_substream *substream) | ||
77 | { | ||
78 | struct snd_soc_pcm_runtime *rtd = substream->private_data; | ||
79 | struct snd_soc_dai *codec_dai = rtd->codec_dai; | ||
80 | |||
81 | /* set freq to 0 to enable all possible codec sample rates */ | ||
82 | snd_soc_dai_set_sysclk(codec_dai, 0, 0, 0); | ||
83 | } | ||
84 | |||
85 | static int raumfeld_cs4270_hw_params(struct snd_pcm_substream *substream, | ||
86 | struct snd_pcm_hw_params *params) | ||
87 | { | ||
88 | struct snd_soc_pcm_runtime *rtd = substream->private_data; | ||
89 | struct snd_soc_dai *codec_dai = rtd->codec_dai; | ||
90 | struct snd_soc_dai *cpu_dai = rtd->cpu_dai; | ||
91 | unsigned int clk = 0; | ||
92 | int ret = 0; | ||
93 | |||
94 | switch (params_rate(params)) { | ||
95 | case 44100: | ||
96 | set_max9485_clk(MAX9485_MCLK_FREQ_112896); | ||
97 | clk = 11289600; | ||
98 | break; | ||
99 | case 48000: | ||
100 | set_max9485_clk(MAX9485_MCLK_FREQ_122880); | ||
101 | clk = 12288000; | ||
102 | break; | ||
103 | case 88200: | ||
104 | set_max9485_clk(MAX9485_MCLK_FREQ_225792); | ||
105 | clk = 22579200; | ||
106 | break; | ||
107 | case 96000: | ||
108 | set_max9485_clk(MAX9485_MCLK_FREQ_245760); | ||
109 | clk = 24576000; | ||
110 | break; | ||
111 | default: | ||
112 | return -EINVAL; | ||
113 | } | ||
114 | |||
115 | ret = snd_soc_dai_set_sysclk(codec_dai, 0, clk, 0); | ||
116 | if (ret < 0) | ||
117 | return ret; | ||
118 | |||
119 | /* setup the CPU DAI */ | ||
120 | ret = snd_soc_dai_set_pll(cpu_dai, 0, 0, 0, clk); | ||
121 | if (ret < 0) | ||
122 | return ret; | ||
123 | |||
124 | ret = snd_soc_dai_set_clkdiv(cpu_dai, PXA_SSP_DIV_SCR, 4); | ||
125 | if (ret < 0) | ||
126 | return ret; | ||
127 | |||
128 | ret = snd_soc_dai_set_sysclk(cpu_dai, PXA_SSP_CLK_EXT, clk, 1); | ||
129 | if (ret < 0) | ||
130 | return ret; | ||
131 | |||
132 | return 0; | ||
133 | } | ||
134 | |||
135 | static const struct snd_soc_ops raumfeld_cs4270_ops = { | ||
136 | .startup = raumfeld_cs4270_startup, | ||
137 | .shutdown = raumfeld_cs4270_shutdown, | ||
138 | .hw_params = raumfeld_cs4270_hw_params, | ||
139 | }; | ||
140 | |||
141 | static int raumfeld_analog_suspend(struct snd_soc_card *card) | ||
142 | { | ||
143 | raumfeld_enable_audio(false); | ||
144 | return 0; | ||
145 | } | ||
146 | |||
147 | static int raumfeld_analog_resume(struct snd_soc_card *card) | ||
148 | { | ||
149 | raumfeld_enable_audio(true); | ||
150 | return 0; | ||
151 | } | ||
152 | |||
153 | /* AK4104 */ | ||
154 | |||
155 | static int raumfeld_ak4104_hw_params(struct snd_pcm_substream *substream, | ||
156 | struct snd_pcm_hw_params *params) | ||
157 | { | ||
158 | struct snd_soc_pcm_runtime *rtd = substream->private_data; | ||
159 | struct snd_soc_dai *cpu_dai = rtd->cpu_dai; | ||
160 | int ret = 0, clk = 0; | ||
161 | |||
162 | switch (params_rate(params)) { | ||
163 | case 44100: | ||
164 | set_max9485_clk(MAX9485_MCLK_FREQ_112896); | ||
165 | clk = 11289600; | ||
166 | break; | ||
167 | case 48000: | ||
168 | set_max9485_clk(MAX9485_MCLK_FREQ_122880); | ||
169 | clk = 12288000; | ||
170 | break; | ||
171 | case 88200: | ||
172 | set_max9485_clk(MAX9485_MCLK_FREQ_225792); | ||
173 | clk = 22579200; | ||
174 | break; | ||
175 | case 96000: | ||
176 | set_max9485_clk(MAX9485_MCLK_FREQ_245760); | ||
177 | clk = 24576000; | ||
178 | break; | ||
179 | default: | ||
180 | return -EINVAL; | ||
181 | } | ||
182 | |||
183 | /* setup the CPU DAI */ | ||
184 | ret = snd_soc_dai_set_pll(cpu_dai, 0, 0, 0, clk); | ||
185 | if (ret < 0) | ||
186 | return ret; | ||
187 | |||
188 | ret = snd_soc_dai_set_clkdiv(cpu_dai, PXA_SSP_DIV_SCR, 4); | ||
189 | if (ret < 0) | ||
190 | return ret; | ||
191 | |||
192 | ret = snd_soc_dai_set_sysclk(cpu_dai, PXA_SSP_CLK_EXT, clk, 1); | ||
193 | if (ret < 0) | ||
194 | return ret; | ||
195 | |||
196 | return 0; | ||
197 | } | ||
198 | |||
199 | static struct snd_soc_ops raumfeld_ak4104_ops = { | ||
200 | .hw_params = raumfeld_ak4104_hw_params, | ||
201 | }; | ||
202 | |||
203 | #define DAI_LINK_CS4270 \ | ||
204 | { \ | ||
205 | .name = "CS4270", \ | ||
206 | .stream_name = "CS4270", \ | ||
207 | .cpu_dai_name = "pxa-ssp-dai.0", \ | ||
208 | .platform_name = "pxa-pcm-audio", \ | ||
209 | .codec_dai_name = "cs4270-hifi", \ | ||
210 | .codec_name = "cs4270.0-0048", \ | ||
211 | .dai_fmt = SND_SOC_DAIFMT_I2S | \ | ||
212 | SND_SOC_DAIFMT_NB_NF | \ | ||
213 | SND_SOC_DAIFMT_CBS_CFS, \ | ||
214 | .ops = &raumfeld_cs4270_ops, \ | ||
215 | } | ||
216 | |||
217 | #define DAI_LINK_AK4104 \ | ||
218 | { \ | ||
219 | .name = "ak4104", \ | ||
220 | .stream_name = "Playback", \ | ||
221 | .cpu_dai_name = "pxa-ssp-dai.1", \ | ||
222 | .codec_dai_name = "ak4104-hifi", \ | ||
223 | .platform_name = "pxa-pcm-audio", \ | ||
224 | .dai_fmt = SND_SOC_DAIFMT_I2S | \ | ||
225 | SND_SOC_DAIFMT_NB_NF | \ | ||
226 | SND_SOC_DAIFMT_CBS_CFS, \ | ||
227 | .ops = &raumfeld_ak4104_ops, \ | ||
228 | .codec_name = "spi0.0", \ | ||
229 | } | ||
230 | |||
231 | static struct snd_soc_dai_link snd_soc_raumfeld_connector_dai[] = { | ||
232 | DAI_LINK_CS4270, | ||
233 | DAI_LINK_AK4104, | ||
234 | }; | ||
235 | |||
236 | static struct snd_soc_dai_link snd_soc_raumfeld_speaker_dai[] = { | ||
237 | DAI_LINK_CS4270, | ||
238 | }; | ||
239 | |||
240 | static struct snd_soc_card snd_soc_raumfeld_connector = { | ||
241 | .name = "Raumfeld Connector", | ||
242 | .owner = THIS_MODULE, | ||
243 | .dai_link = snd_soc_raumfeld_connector_dai, | ||
244 | .num_links = ARRAY_SIZE(snd_soc_raumfeld_connector_dai), | ||
245 | .suspend_post = raumfeld_analog_suspend, | ||
246 | .resume_pre = raumfeld_analog_resume, | ||
247 | }; | ||
248 | |||
249 | static struct snd_soc_card snd_soc_raumfeld_speaker = { | ||
250 | .name = "Raumfeld Speaker", | ||
251 | .owner = THIS_MODULE, | ||
252 | .dai_link = snd_soc_raumfeld_speaker_dai, | ||
253 | .num_links = ARRAY_SIZE(snd_soc_raumfeld_speaker_dai), | ||
254 | .suspend_post = raumfeld_analog_suspend, | ||
255 | .resume_pre = raumfeld_analog_resume, | ||
256 | }; | ||
257 | |||
258 | static struct platform_device *raumfeld_audio_device; | ||
259 | |||
260 | static int __init raumfeld_audio_init(void) | ||
261 | { | ||
262 | int ret; | ||
263 | |||
264 | if (!machine_is_raumfeld_speaker() && | ||
265 | !machine_is_raumfeld_connector()) | ||
266 | return 0; | ||
267 | |||
268 | max9486_client = i2c_new_device(i2c_get_adapter(0), | ||
269 | &max9486_hwmon_info); | ||
270 | |||
271 | if (!max9486_client) | ||
272 | return -ENOMEM; | ||
273 | |||
274 | set_max9485_clk(MAX9485_MCLK_FREQ_122880); | ||
275 | |||
276 | /* Register analog device */ | ||
277 | raumfeld_audio_device = platform_device_alloc("soc-audio", 0); | ||
278 | if (!raumfeld_audio_device) | ||
279 | return -ENOMEM; | ||
280 | |||
281 | if (machine_is_raumfeld_speaker()) | ||
282 | platform_set_drvdata(raumfeld_audio_device, | ||
283 | &snd_soc_raumfeld_speaker); | ||
284 | |||
285 | if (machine_is_raumfeld_connector()) | ||
286 | platform_set_drvdata(raumfeld_audio_device, | ||
287 | &snd_soc_raumfeld_connector); | ||
288 | |||
289 | ret = platform_device_add(raumfeld_audio_device); | ||
290 | if (ret < 0) { | ||
291 | platform_device_put(raumfeld_audio_device); | ||
292 | return ret; | ||
293 | } | ||
294 | |||
295 | raumfeld_enable_audio(true); | ||
296 | return 0; | ||
297 | } | ||
298 | |||
299 | static void __exit raumfeld_audio_exit(void) | ||
300 | { | ||
301 | raumfeld_enable_audio(false); | ||
302 | |||
303 | platform_device_unregister(raumfeld_audio_device); | ||
304 | |||
305 | i2c_unregister_device(max9486_client); | ||
306 | |||
307 | gpio_free(GPIO_MCLK_RESET); | ||
308 | gpio_free(GPIO_CODEC_RESET); | ||
309 | gpio_free(GPIO_SPDIF_RESET); | ||
310 | } | ||
311 | |||
312 | module_init(raumfeld_audio_init); | ||
313 | module_exit(raumfeld_audio_exit); | ||
314 | |||
315 | /* Module information */ | ||
316 | MODULE_AUTHOR("Daniel Mack <daniel@caiaq.de>"); | ||
317 | MODULE_DESCRIPTION("Raumfeld audio SoC"); | ||
318 | MODULE_LICENSE("GPL"); | ||
diff --git a/sound/soc/qcom/Kconfig b/sound/soc/qcom/Kconfig index 2a4c912d1e48..804ae0d93058 100644 --- a/sound/soc/qcom/Kconfig +++ b/sound/soc/qcom/Kconfig | |||
@@ -66,6 +66,7 @@ config SND_SOC_QDSP6_ASM | |||
66 | tristate | 66 | tristate |
67 | 67 | ||
68 | config SND_SOC_QDSP6_ASM_DAI | 68 | config SND_SOC_QDSP6_ASM_DAI |
69 | select SND_SOC_COMPRESS | ||
69 | tristate | 70 | tristate |
70 | 71 | ||
71 | config SND_SOC_QDSP6 | 72 | config SND_SOC_QDSP6 |
@@ -100,6 +101,7 @@ config SND_SOC_SDM845 | |||
100 | depends on QCOM_APR | 101 | depends on QCOM_APR |
101 | select SND_SOC_QDSP6 | 102 | select SND_SOC_QDSP6 |
102 | select SND_SOC_QCOM_COMMON | 103 | select SND_SOC_QCOM_COMMON |
104 | select SND_SOC_RT5663 | ||
103 | help | 105 | help |
104 | To add support for audio on Qualcomm Technologies Inc. | 106 | To add support for audio on Qualcomm Technologies Inc. |
105 | SDM845 SoC-based systems. | 107 | SDM845 SoC-based systems. |
diff --git a/sound/soc/qcom/lpass-platform.c b/sound/soc/qcom/lpass-platform.c index d07271ea4c45..028bce671cbc 100644 --- a/sound/soc/qcom/lpass-platform.c +++ b/sound/soc/qcom/lpass-platform.c | |||
@@ -91,7 +91,7 @@ static int lpass_platform_pcmops_open(struct snd_pcm_substream *substream) | |||
91 | if (ret) { | 91 | if (ret) { |
92 | dev_err(soc_runtime->dev, | 92 | dev_err(soc_runtime->dev, |
93 | "error writing to rdmactl reg: %d\n", ret); | 93 | "error writing to rdmactl reg: %d\n", ret); |
94 | return ret; | 94 | return ret; |
95 | } | 95 | } |
96 | 96 | ||
97 | data->dma_ch = dma_ch; | 97 | data->dma_ch = dma_ch; |
diff --git a/sound/soc/qcom/qdsp6/q6afe-dai.c b/sound/soc/qcom/qdsp6/q6afe-dai.c index 8f6c8fc073a9..dc645ba4d8d0 100644 --- a/sound/soc/qcom/qdsp6/q6afe-dai.c +++ b/sound/soc/qcom/qdsp6/q6afe-dai.c | |||
@@ -341,6 +341,7 @@ static int q6afe_dai_prepare(struct snd_pcm_substream *substream, | |||
341 | 341 | ||
342 | switch (dai->id) { | 342 | switch (dai->id) { |
343 | case HDMI_RX: | 343 | case HDMI_RX: |
344 | case DISPLAY_PORT_RX: | ||
344 | q6afe_hdmi_port_prepare(dai_data->port[dai->id], | 345 | q6afe_hdmi_port_prepare(dai_data->port[dai->id], |
345 | &dai_data->port_config[dai->id].hdmi); | 346 | &dai_data->port_config[dai->id].hdmi); |
346 | break; | 347 | break; |
@@ -445,6 +446,7 @@ static int q6afe_mi2s_set_sysclk(struct snd_soc_dai *dai, | |||
445 | 446 | ||
446 | static const struct snd_soc_dapm_route q6afe_dapm_routes[] = { | 447 | static const struct snd_soc_dapm_route q6afe_dapm_routes[] = { |
447 | {"HDMI Playback", NULL, "HDMI_RX"}, | 448 | {"HDMI Playback", NULL, "HDMI_RX"}, |
449 | {"Display Port Playback", NULL, "DISPLAY_PORT_RX"}, | ||
448 | {"Slimbus1 Playback", NULL, "SLIMBUS_1_RX"}, | 450 | {"Slimbus1 Playback", NULL, "SLIMBUS_1_RX"}, |
449 | {"Slimbus2 Playback", NULL, "SLIMBUS_2_RX"}, | 451 | {"Slimbus2 Playback", NULL, "SLIMBUS_2_RX"}, |
450 | {"Slimbus3 Playback", NULL, "SLIMBUS_3_RX"}, | 452 | {"Slimbus3 Playback", NULL, "SLIMBUS_3_RX"}, |
@@ -561,13 +563,13 @@ static const struct snd_soc_dapm_route q6afe_dapm_routes[] = { | |||
561 | {"QUAT_MI2S_TX", NULL, "Quaternary MI2S Capture"}, | 563 | {"QUAT_MI2S_TX", NULL, "Quaternary MI2S Capture"}, |
562 | }; | 564 | }; |
563 | 565 | ||
564 | static struct snd_soc_dai_ops q6hdmi_ops = { | 566 | static const struct snd_soc_dai_ops q6hdmi_ops = { |
565 | .prepare = q6afe_dai_prepare, | 567 | .prepare = q6afe_dai_prepare, |
566 | .hw_params = q6hdmi_hw_params, | 568 | .hw_params = q6hdmi_hw_params, |
567 | .shutdown = q6afe_dai_shutdown, | 569 | .shutdown = q6afe_dai_shutdown, |
568 | }; | 570 | }; |
569 | 571 | ||
570 | static struct snd_soc_dai_ops q6i2s_ops = { | 572 | static const struct snd_soc_dai_ops q6i2s_ops = { |
571 | .prepare = q6afe_dai_prepare, | 573 | .prepare = q6afe_dai_prepare, |
572 | .hw_params = q6i2s_hw_params, | 574 | .hw_params = q6i2s_hw_params, |
573 | .set_fmt = q6i2s_set_fmt, | 575 | .set_fmt = q6i2s_set_fmt, |
@@ -575,14 +577,14 @@ static struct snd_soc_dai_ops q6i2s_ops = { | |||
575 | .set_sysclk = q6afe_mi2s_set_sysclk, | 577 | .set_sysclk = q6afe_mi2s_set_sysclk, |
576 | }; | 578 | }; |
577 | 579 | ||
578 | static struct snd_soc_dai_ops q6slim_ops = { | 580 | static const struct snd_soc_dai_ops q6slim_ops = { |
579 | .prepare = q6afe_dai_prepare, | 581 | .prepare = q6afe_dai_prepare, |
580 | .hw_params = q6slim_hw_params, | 582 | .hw_params = q6slim_hw_params, |
581 | .shutdown = q6afe_dai_shutdown, | 583 | .shutdown = q6afe_dai_shutdown, |
582 | .set_channel_map = q6slim_set_channel_map, | 584 | .set_channel_map = q6slim_set_channel_map, |
583 | }; | 585 | }; |
584 | 586 | ||
585 | static struct snd_soc_dai_ops q6tdm_ops = { | 587 | static const struct snd_soc_dai_ops q6tdm_ops = { |
586 | .prepare = q6afe_dai_prepare, | 588 | .prepare = q6afe_dai_prepare, |
587 | .shutdown = q6afe_dai_shutdown, | 589 | .shutdown = q6afe_dai_shutdown, |
588 | .set_sysclk = q6afe_mi2s_set_sysclk, | 590 | .set_sysclk = q6afe_mi2s_set_sysclk, |
@@ -1090,6 +1092,25 @@ static struct snd_soc_dai_driver q6afe_dais[] = { | |||
1090 | Q6AFE_TDM_CAP_DAI("Quinary", 5, QUINARY_TDM_TX_5), | 1092 | Q6AFE_TDM_CAP_DAI("Quinary", 5, QUINARY_TDM_TX_5), |
1091 | Q6AFE_TDM_CAP_DAI("Quinary", 6, QUINARY_TDM_TX_6), | 1093 | Q6AFE_TDM_CAP_DAI("Quinary", 6, QUINARY_TDM_TX_6), |
1092 | Q6AFE_TDM_CAP_DAI("Quinary", 7, QUINARY_TDM_TX_7), | 1094 | Q6AFE_TDM_CAP_DAI("Quinary", 7, QUINARY_TDM_TX_7), |
1095 | { | ||
1096 | .playback = { | ||
1097 | .stream_name = "Display Port Playback", | ||
1098 | .rates = SNDRV_PCM_RATE_48000 | | ||
1099 | SNDRV_PCM_RATE_96000 | | ||
1100 | SNDRV_PCM_RATE_192000, | ||
1101 | .formats = SNDRV_PCM_FMTBIT_S16_LE | | ||
1102 | SNDRV_PCM_FMTBIT_S24_LE, | ||
1103 | .channels_min = 2, | ||
1104 | .channels_max = 8, | ||
1105 | .rate_max = 192000, | ||
1106 | .rate_min = 48000, | ||
1107 | }, | ||
1108 | .ops = &q6hdmi_ops, | ||
1109 | .id = DISPLAY_PORT_RX, | ||
1110 | .name = "DISPLAY_PORT", | ||
1111 | .probe = msm_dai_q6_dai_probe, | ||
1112 | .remove = msm_dai_q6_dai_remove, | ||
1113 | }, | ||
1093 | }; | 1114 | }; |
1094 | 1115 | ||
1095 | static int q6afe_of_xlate_dai_name(struct snd_soc_component *component, | 1116 | static int q6afe_of_xlate_dai_name(struct snd_soc_component *component, |
@@ -1311,6 +1332,7 @@ static const struct snd_soc_dapm_widget q6afe_dai_widgets[] = { | |||
1311 | 0, 0, 0, 0), | 1332 | 0, 0, 0, 0), |
1312 | SND_SOC_DAPM_AIF_OUT("QUIN_TDM_TX_7", NULL, | 1333 | SND_SOC_DAPM_AIF_OUT("QUIN_TDM_TX_7", NULL, |
1313 | 0, 0, 0, 0), | 1334 | 0, 0, 0, 0), |
1335 | SND_SOC_DAPM_AIF_OUT("DISPLAY_PORT_RX", "NULL", 0, 0, 0, 0), | ||
1314 | }; | 1336 | }; |
1315 | 1337 | ||
1316 | static const struct snd_soc_component_driver q6afe_dai_component = { | 1338 | static const struct snd_soc_component_driver q6afe_dai_component = { |
diff --git a/sound/soc/qcom/qdsp6/q6afe.c b/sound/soc/qcom/qdsp6/q6afe.c index 829b5e987b2a..e0945f7a58c8 100644 --- a/sound/soc/qcom/qdsp6/q6afe.c +++ b/sound/soc/qcom/qdsp6/q6afe.c | |||
@@ -71,6 +71,7 @@ | |||
71 | /* Port IDs */ | 71 | /* Port IDs */ |
72 | #define AFE_API_VERSION_HDMI_CONFIG 0x1 | 72 | #define AFE_API_VERSION_HDMI_CONFIG 0x1 |
73 | #define AFE_PORT_ID_MULTICHAN_HDMI_RX 0x100E | 73 | #define AFE_PORT_ID_MULTICHAN_HDMI_RX 0x100E |
74 | #define AFE_PORT_ID_HDMI_OVER_DP_RX 0x6020 | ||
74 | 75 | ||
75 | #define AFE_API_VERSION_SLIMBUS_CONFIG 0x1 | 76 | #define AFE_API_VERSION_SLIMBUS_CONFIG 0x1 |
76 | /* Clock set API version */ | 77 | /* Clock set API version */ |
@@ -704,6 +705,8 @@ static struct afe_port_map port_maps[AFE_PORT_MAX] = { | |||
704 | QUINARY_TDM_RX_7, 1, 1}, | 705 | QUINARY_TDM_RX_7, 1, 1}, |
705 | [QUINARY_TDM_TX_7] = { AFE_PORT_ID_QUINARY_TDM_TX_7, | 706 | [QUINARY_TDM_TX_7] = { AFE_PORT_ID_QUINARY_TDM_TX_7, |
706 | QUINARY_TDM_TX_7, 0, 1}, | 707 | QUINARY_TDM_TX_7, 0, 1}, |
708 | [DISPLAY_PORT_RX] = { AFE_PORT_ID_HDMI_OVER_DP_RX, | ||
709 | DISPLAY_PORT_RX, 1, 1}, | ||
707 | }; | 710 | }; |
708 | 711 | ||
709 | static void q6afe_port_free(struct kref *ref) | 712 | static void q6afe_port_free(struct kref *ref) |
@@ -1384,6 +1387,7 @@ struct q6afe_port *q6afe_port_get_from_id(struct device *dev, int id) | |||
1384 | 1387 | ||
1385 | switch (port_id) { | 1388 | switch (port_id) { |
1386 | case AFE_PORT_ID_MULTICHAN_HDMI_RX: | 1389 | case AFE_PORT_ID_MULTICHAN_HDMI_RX: |
1390 | case AFE_PORT_ID_HDMI_OVER_DP_RX: | ||
1387 | cfg_type = AFE_PARAM_ID_HDMI_CONFIG; | 1391 | cfg_type = AFE_PARAM_ID_HDMI_CONFIG; |
1388 | break; | 1392 | break; |
1389 | case AFE_PORT_ID_SLIMBUS_MULTI_CHAN_0_TX: | 1393 | case AFE_PORT_ID_SLIMBUS_MULTI_CHAN_0_TX: |
diff --git a/sound/soc/qcom/qdsp6/q6asm-dai.c b/sound/soc/qcom/qdsp6/q6asm-dai.c index 86115de5c1b2..5b986b74dd36 100644 --- a/sound/soc/qcom/qdsp6/q6asm-dai.c +++ b/sound/soc/qcom/qdsp6/q6asm-dai.c | |||
@@ -10,6 +10,8 @@ | |||
10 | #include <sound/soc.h> | 10 | #include <sound/soc.h> |
11 | #include <sound/soc-dapm.h> | 11 | #include <sound/soc-dapm.h> |
12 | #include <sound/pcm.h> | 12 | #include <sound/pcm.h> |
13 | #include <linux/spinlock.h> | ||
14 | #include <sound/compress_driver.h> | ||
13 | #include <asm/dma.h> | 15 | #include <asm/dma.h> |
14 | #include <linux/dma-mapping.h> | 16 | #include <linux/dma-mapping.h> |
15 | #include <linux/of_device.h> | 17 | #include <linux/of_device.h> |
@@ -30,6 +32,15 @@ | |||
30 | #define CAPTURE_MIN_PERIOD_SIZE 320 | 32 | #define CAPTURE_MIN_PERIOD_SIZE 320 |
31 | #define SID_MASK_DEFAULT 0xF | 33 | #define SID_MASK_DEFAULT 0xF |
32 | 34 | ||
35 | /* Default values used if user space does not set */ | ||
36 | #define COMPR_PLAYBACK_MIN_FRAGMENT_SIZE (8 * 1024) | ||
37 | #define COMPR_PLAYBACK_MAX_FRAGMENT_SIZE (128 * 1024) | ||
38 | #define COMPR_PLAYBACK_MIN_NUM_FRAGMENTS (4) | ||
39 | #define COMPR_PLAYBACK_MAX_NUM_FRAGMENTS (16 * 4) | ||
40 | #define Q6ASM_DAI_TX_RX 0 | ||
41 | #define Q6ASM_DAI_TX 1 | ||
42 | #define Q6ASM_DAI_RX 2 | ||
43 | |||
33 | enum stream_state { | 44 | enum stream_state { |
34 | Q6ASM_STREAM_IDLE = 0, | 45 | Q6ASM_STREAM_IDLE = 0, |
35 | Q6ASM_STREAM_STOPPED, | 46 | Q6ASM_STREAM_STOPPED, |
@@ -38,11 +49,18 @@ enum stream_state { | |||
38 | 49 | ||
39 | struct q6asm_dai_rtd { | 50 | struct q6asm_dai_rtd { |
40 | struct snd_pcm_substream *substream; | 51 | struct snd_pcm_substream *substream; |
52 | struct snd_compr_stream *cstream; | ||
53 | struct snd_compr_params codec_param; | ||
54 | struct snd_dma_buffer dma_buffer; | ||
55 | spinlock_t lock; | ||
41 | phys_addr_t phys; | 56 | phys_addr_t phys; |
42 | unsigned int pcm_size; | 57 | unsigned int pcm_size; |
43 | unsigned int pcm_count; | 58 | unsigned int pcm_count; |
44 | unsigned int pcm_irq_pos; /* IRQ position */ | 59 | unsigned int pcm_irq_pos; /* IRQ position */ |
45 | unsigned int periods; | 60 | unsigned int periods; |
61 | unsigned int bytes_sent; | ||
62 | unsigned int bytes_received; | ||
63 | unsigned int copied_total; | ||
46 | uint16_t bits_per_sample; | 64 | uint16_t bits_per_sample; |
47 | uint16_t source; /* Encoding source bit mask */ | 65 | uint16_t source; /* Encoding source bit mask */ |
48 | struct audio_client *audio_client; | 66 | struct audio_client *audio_client; |
@@ -137,6 +155,21 @@ static struct snd_pcm_hw_constraint_list constraints_sample_rates = { | |||
137 | .mask = 0, | 155 | .mask = 0, |
138 | }; | 156 | }; |
139 | 157 | ||
158 | static const struct snd_compr_codec_caps q6asm_compr_caps = { | ||
159 | .num_descriptors = 1, | ||
160 | .descriptor[0].max_ch = 2, | ||
161 | .descriptor[0].sample_rates = { 8000, 11025, 12000, 16000, 22050, | ||
162 | 24000, 32000, 44100, 48000, 88200, | ||
163 | 96000, 176400, 192000 }, | ||
164 | .descriptor[0].num_sample_rates = 13, | ||
165 | .descriptor[0].bit_rate[0] = 320, | ||
166 | .descriptor[0].bit_rate[1] = 128, | ||
167 | .descriptor[0].num_bitrates = 2, | ||
168 | .descriptor[0].profiles = 0, | ||
169 | .descriptor[0].modes = SND_AUDIOCHANMODE_MP3_STEREO, | ||
170 | .descriptor[0].formats = 0, | ||
171 | }; | ||
172 | |||
140 | static void event_handler(uint32_t opcode, uint32_t token, | 173 | static void event_handler(uint32_t opcode, uint32_t token, |
141 | uint32_t *payload, void *priv) | 174 | uint32_t *payload, void *priv) |
142 | { | 175 | { |
@@ -460,6 +493,306 @@ static struct snd_pcm_ops q6asm_dai_ops = { | |||
460 | .mmap = q6asm_dai_mmap, | 493 | .mmap = q6asm_dai_mmap, |
461 | }; | 494 | }; |
462 | 495 | ||
496 | static void compress_event_handler(uint32_t opcode, uint32_t token, | ||
497 | uint32_t *payload, void *priv) | ||
498 | { | ||
499 | struct q6asm_dai_rtd *prtd = priv; | ||
500 | struct snd_compr_stream *substream = prtd->cstream; | ||
501 | unsigned long flags; | ||
502 | uint64_t avail; | ||
503 | |||
504 | switch (opcode) { | ||
505 | case ASM_CLIENT_EVENT_CMD_RUN_DONE: | ||
506 | spin_lock_irqsave(&prtd->lock, flags); | ||
507 | if (!prtd->bytes_sent) { | ||
508 | q6asm_write_async(prtd->audio_client, prtd->pcm_count, | ||
509 | 0, 0, NO_TIMESTAMP); | ||
510 | prtd->bytes_sent += prtd->pcm_count; | ||
511 | } | ||
512 | |||
513 | spin_unlock_irqrestore(&prtd->lock, flags); | ||
514 | break; | ||
515 | |||
516 | case ASM_CLIENT_EVENT_CMD_EOS_DONE: | ||
517 | prtd->state = Q6ASM_STREAM_STOPPED; | ||
518 | break; | ||
519 | |||
520 | case ASM_CLIENT_EVENT_DATA_WRITE_DONE: | ||
521 | spin_lock_irqsave(&prtd->lock, flags); | ||
522 | |||
523 | prtd->copied_total += prtd->pcm_count; | ||
524 | snd_compr_fragment_elapsed(substream); | ||
525 | |||
526 | if (prtd->state != Q6ASM_STREAM_RUNNING) { | ||
527 | spin_unlock_irqrestore(&prtd->lock, flags); | ||
528 | break; | ||
529 | } | ||
530 | |||
531 | avail = prtd->bytes_received - prtd->bytes_sent; | ||
532 | |||
533 | if (avail >= prtd->pcm_count) { | ||
534 | q6asm_write_async(prtd->audio_client, | ||
535 | prtd->pcm_count, 0, 0, NO_TIMESTAMP); | ||
536 | prtd->bytes_sent += prtd->pcm_count; | ||
537 | } | ||
538 | |||
539 | spin_unlock_irqrestore(&prtd->lock, flags); | ||
540 | break; | ||
541 | |||
542 | default: | ||
543 | break; | ||
544 | } | ||
545 | } | ||
546 | |||
547 | static int q6asm_dai_compr_open(struct snd_compr_stream *stream) | ||
548 | { | ||
549 | struct snd_soc_pcm_runtime *rtd = stream->private_data; | ||
550 | struct snd_soc_component *c = snd_soc_rtdcom_lookup(rtd, DRV_NAME); | ||
551 | struct snd_compr_runtime *runtime = stream->runtime; | ||
552 | struct snd_soc_dai *cpu_dai = rtd->cpu_dai; | ||
553 | struct q6asm_dai_data *pdata; | ||
554 | struct device *dev = c->dev; | ||
555 | struct q6asm_dai_rtd *prtd; | ||
556 | int stream_id, size, ret; | ||
557 | |||
558 | stream_id = cpu_dai->driver->id; | ||
559 | pdata = snd_soc_component_get_drvdata(c); | ||
560 | if (!pdata) { | ||
561 | dev_err(dev, "Drv data not found ..\n"); | ||
562 | return -EINVAL; | ||
563 | } | ||
564 | |||
565 | prtd = kzalloc(sizeof(*prtd), GFP_KERNEL); | ||
566 | if (!prtd) | ||
567 | return -ENOMEM; | ||
568 | |||
569 | prtd->cstream = stream; | ||
570 | prtd->audio_client = q6asm_audio_client_alloc(dev, | ||
571 | (q6asm_cb)compress_event_handler, | ||
572 | prtd, stream_id, LEGACY_PCM_MODE); | ||
573 | if (!prtd->audio_client) { | ||
574 | dev_err(dev, "Could not allocate memory\n"); | ||
575 | kfree(prtd); | ||
576 | return -ENOMEM; | ||
577 | } | ||
578 | |||
579 | size = COMPR_PLAYBACK_MAX_FRAGMENT_SIZE * | ||
580 | COMPR_PLAYBACK_MAX_NUM_FRAGMENTS; | ||
581 | ret = snd_dma_alloc_pages(SNDRV_DMA_TYPE_DEV, dev, size, | ||
582 | &prtd->dma_buffer); | ||
583 | if (ret) { | ||
584 | dev_err(dev, "Cannot allocate buffer(s)\n"); | ||
585 | return ret; | ||
586 | } | ||
587 | |||
588 | if (pdata->sid < 0) | ||
589 | prtd->phys = prtd->dma_buffer.addr; | ||
590 | else | ||
591 | prtd->phys = prtd->dma_buffer.addr | (pdata->sid << 32); | ||
592 | |||
593 | snd_compr_set_runtime_buffer(stream, &prtd->dma_buffer); | ||
594 | spin_lock_init(&prtd->lock); | ||
595 | runtime->private_data = prtd; | ||
596 | |||
597 | return 0; | ||
598 | } | ||
599 | |||
600 | static int q6asm_dai_compr_free(struct snd_compr_stream *stream) | ||
601 | { | ||
602 | struct snd_compr_runtime *runtime = stream->runtime; | ||
603 | struct q6asm_dai_rtd *prtd = runtime->private_data; | ||
604 | struct snd_soc_pcm_runtime *rtd = stream->private_data; | ||
605 | |||
606 | if (prtd->audio_client) { | ||
607 | if (prtd->state) | ||
608 | q6asm_cmd(prtd->audio_client, CMD_CLOSE); | ||
609 | |||
610 | snd_dma_free_pages(&prtd->dma_buffer); | ||
611 | q6asm_unmap_memory_regions(stream->direction, | ||
612 | prtd->audio_client); | ||
613 | q6asm_audio_client_free(prtd->audio_client); | ||
614 | prtd->audio_client = NULL; | ||
615 | } | ||
616 | q6routing_stream_close(rtd->dai_link->id, stream->direction); | ||
617 | kfree(prtd); | ||
618 | |||
619 | return 0; | ||
620 | } | ||
621 | |||
622 | static int q6asm_dai_compr_set_params(struct snd_compr_stream *stream, | ||
623 | struct snd_compr_params *params) | ||
624 | { | ||
625 | struct snd_compr_runtime *runtime = stream->runtime; | ||
626 | struct q6asm_dai_rtd *prtd = runtime->private_data; | ||
627 | struct snd_soc_pcm_runtime *rtd = stream->private_data; | ||
628 | struct snd_soc_component *c = snd_soc_rtdcom_lookup(rtd, DRV_NAME); | ||
629 | int dir = stream->direction; | ||
630 | struct q6asm_dai_data *pdata; | ||
631 | struct device *dev = c->dev; | ||
632 | int ret; | ||
633 | |||
634 | memcpy(&prtd->codec_param, params, sizeof(*params)); | ||
635 | |||
636 | pdata = snd_soc_component_get_drvdata(c); | ||
637 | if (!pdata) | ||
638 | return -EINVAL; | ||
639 | |||
640 | if (!prtd || !prtd->audio_client) { | ||
641 | dev_err(dev, "private data null or audio client freed\n"); | ||
642 | return -EINVAL; | ||
643 | } | ||
644 | |||
645 | prtd->periods = runtime->fragments; | ||
646 | prtd->pcm_count = runtime->fragment_size; | ||
647 | prtd->pcm_size = runtime->fragments * runtime->fragment_size; | ||
648 | prtd->bits_per_sample = 16; | ||
649 | if (dir == SND_COMPRESS_PLAYBACK) { | ||
650 | ret = q6asm_open_write(prtd->audio_client, params->codec.id, | ||
651 | prtd->bits_per_sample); | ||
652 | |||
653 | if (ret < 0) { | ||
654 | dev_err(dev, "q6asm_open_write failed\n"); | ||
655 | q6asm_audio_client_free(prtd->audio_client); | ||
656 | prtd->audio_client = NULL; | ||
657 | return ret; | ||
658 | } | ||
659 | } | ||
660 | |||
661 | prtd->session_id = q6asm_get_session_id(prtd->audio_client); | ||
662 | ret = q6routing_stream_open(rtd->dai_link->id, LEGACY_PCM_MODE, | ||
663 | prtd->session_id, dir); | ||
664 | if (ret) { | ||
665 | dev_err(dev, "Stream reg failed ret:%d\n", ret); | ||
666 | return ret; | ||
667 | } | ||
668 | |||
669 | ret = q6asm_map_memory_regions(dir, prtd->audio_client, prtd->phys, | ||
670 | (prtd->pcm_size / prtd->periods), | ||
671 | prtd->periods); | ||
672 | |||
673 | if (ret < 0) { | ||
674 | dev_err(dev, "Buffer Mapping failed ret:%d\n", ret); | ||
675 | return -ENOMEM; | ||
676 | } | ||
677 | |||
678 | prtd->state = Q6ASM_STREAM_RUNNING; | ||
679 | |||
680 | return 0; | ||
681 | } | ||
682 | |||
683 | static int q6asm_dai_compr_trigger(struct snd_compr_stream *stream, int cmd) | ||
684 | { | ||
685 | struct snd_compr_runtime *runtime = stream->runtime; | ||
686 | struct q6asm_dai_rtd *prtd = runtime->private_data; | ||
687 | int ret = 0; | ||
688 | |||
689 | switch (cmd) { | ||
690 | case SNDRV_PCM_TRIGGER_START: | ||
691 | case SNDRV_PCM_TRIGGER_RESUME: | ||
692 | case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: | ||
693 | ret = q6asm_run_nowait(prtd->audio_client, 0, 0, 0); | ||
694 | break; | ||
695 | case SNDRV_PCM_TRIGGER_STOP: | ||
696 | prtd->state = Q6ASM_STREAM_STOPPED; | ||
697 | ret = q6asm_cmd_nowait(prtd->audio_client, CMD_EOS); | ||
698 | break; | ||
699 | case SNDRV_PCM_TRIGGER_SUSPEND: | ||
700 | case SNDRV_PCM_TRIGGER_PAUSE_PUSH: | ||
701 | ret = q6asm_cmd_nowait(prtd->audio_client, CMD_PAUSE); | ||
702 | break; | ||
703 | default: | ||
704 | ret = -EINVAL; | ||
705 | break; | ||
706 | } | ||
707 | |||
708 | return ret; | ||
709 | } | ||
710 | |||
711 | static int q6asm_dai_compr_pointer(struct snd_compr_stream *stream, | ||
712 | struct snd_compr_tstamp *tstamp) | ||
713 | { | ||
714 | struct snd_compr_runtime *runtime = stream->runtime; | ||
715 | struct q6asm_dai_rtd *prtd = runtime->private_data; | ||
716 | unsigned long flags; | ||
717 | |||
718 | spin_lock_irqsave(&prtd->lock, flags); | ||
719 | |||
720 | tstamp->copied_total = prtd->copied_total; | ||
721 | tstamp->byte_offset = prtd->copied_total % prtd->pcm_size; | ||
722 | |||
723 | spin_unlock_irqrestore(&prtd->lock, flags); | ||
724 | |||
725 | return 0; | ||
726 | } | ||
727 | |||
728 | static int q6asm_dai_compr_ack(struct snd_compr_stream *stream, | ||
729 | size_t count) | ||
730 | { | ||
731 | struct snd_compr_runtime *runtime = stream->runtime; | ||
732 | struct q6asm_dai_rtd *prtd = runtime->private_data; | ||
733 | unsigned long flags; | ||
734 | |||
735 | spin_lock_irqsave(&prtd->lock, flags); | ||
736 | prtd->bytes_received += count; | ||
737 | spin_unlock_irqrestore(&prtd->lock, flags); | ||
738 | |||
739 | return count; | ||
740 | } | ||
741 | |||
742 | static int q6asm_dai_compr_mmap(struct snd_compr_stream *stream, | ||
743 | struct vm_area_struct *vma) | ||
744 | { | ||
745 | struct snd_compr_runtime *runtime = stream->runtime; | ||
746 | struct q6asm_dai_rtd *prtd = runtime->private_data; | ||
747 | struct snd_soc_pcm_runtime *rtd = stream->private_data; | ||
748 | struct snd_soc_component *c = snd_soc_rtdcom_lookup(rtd, DRV_NAME); | ||
749 | struct device *dev = c->dev; | ||
750 | |||
751 | return dma_mmap_coherent(dev, vma, | ||
752 | prtd->dma_buffer.area, prtd->dma_buffer.addr, | ||
753 | prtd->dma_buffer.bytes); | ||
754 | } | ||
755 | |||
756 | static int q6asm_dai_compr_get_caps(struct snd_compr_stream *stream, | ||
757 | struct snd_compr_caps *caps) | ||
758 | { | ||
759 | caps->direction = SND_COMPRESS_PLAYBACK; | ||
760 | caps->min_fragment_size = COMPR_PLAYBACK_MIN_FRAGMENT_SIZE; | ||
761 | caps->max_fragment_size = COMPR_PLAYBACK_MAX_FRAGMENT_SIZE; | ||
762 | caps->min_fragments = COMPR_PLAYBACK_MIN_NUM_FRAGMENTS; | ||
763 | caps->max_fragments = COMPR_PLAYBACK_MAX_NUM_FRAGMENTS; | ||
764 | caps->num_codecs = 1; | ||
765 | caps->codecs[0] = SND_AUDIOCODEC_MP3; | ||
766 | |||
767 | return 0; | ||
768 | } | ||
769 | |||
770 | static int q6asm_dai_compr_get_codec_caps(struct snd_compr_stream *stream, | ||
771 | struct snd_compr_codec_caps *codec) | ||
772 | { | ||
773 | switch (codec->codec) { | ||
774 | case SND_AUDIOCODEC_MP3: | ||
775 | *codec = q6asm_compr_caps; | ||
776 | break; | ||
777 | default: | ||
778 | break; | ||
779 | } | ||
780 | |||
781 | return 0; | ||
782 | } | ||
783 | |||
784 | static struct snd_compr_ops q6asm_dai_compr_ops = { | ||
785 | .open = q6asm_dai_compr_open, | ||
786 | .free = q6asm_dai_compr_free, | ||
787 | .set_params = q6asm_dai_compr_set_params, | ||
788 | .pointer = q6asm_dai_compr_pointer, | ||
789 | .trigger = q6asm_dai_compr_trigger, | ||
790 | .get_caps = q6asm_dai_compr_get_caps, | ||
791 | .get_codec_caps = q6asm_dai_compr_get_codec_caps, | ||
792 | .mmap = q6asm_dai_compr_mmap, | ||
793 | .ack = q6asm_dai_compr_ack, | ||
794 | }; | ||
795 | |||
463 | static int q6asm_dai_pcm_new(struct snd_soc_pcm_runtime *rtd) | 796 | static int q6asm_dai_pcm_new(struct snd_soc_pcm_runtime *rtd) |
464 | { | 797 | { |
465 | struct snd_pcm_substream *psubstream, *csubstream; | 798 | struct snd_pcm_substream *psubstream, *csubstream; |
@@ -515,7 +848,7 @@ static const struct snd_soc_component_driver q6asm_fe_dai_component = { | |||
515 | .ops = &q6asm_dai_ops, | 848 | .ops = &q6asm_dai_ops, |
516 | .pcm_new = q6asm_dai_pcm_new, | 849 | .pcm_new = q6asm_dai_pcm_new, |
517 | .pcm_free = q6asm_dai_pcm_free, | 850 | .pcm_free = q6asm_dai_pcm_free, |
518 | 851 | .compr_ops = &q6asm_dai_compr_ops, | |
519 | }; | 852 | }; |
520 | 853 | ||
521 | static struct snd_soc_dai_driver q6asm_fe_dais[] = { | 854 | static struct snd_soc_dai_driver q6asm_fe_dais[] = { |
@@ -529,6 +862,41 @@ static struct snd_soc_dai_driver q6asm_fe_dais[] = { | |||
529 | Q6ASM_FEDAI_DRIVER(8), | 862 | Q6ASM_FEDAI_DRIVER(8), |
530 | }; | 863 | }; |
531 | 864 | ||
865 | static int of_q6asm_parse_dai_data(struct device *dev, | ||
866 | struct q6asm_dai_data *pdata) | ||
867 | { | ||
868 | static struct snd_soc_dai_driver *dai_drv; | ||
869 | struct snd_soc_pcm_stream empty_stream; | ||
870 | struct device_node *node; | ||
871 | int ret, id, dir; | ||
872 | |||
873 | memset(&empty_stream, 0, sizeof(empty_stream)); | ||
874 | |||
875 | for_each_child_of_node(dev->of_node, node) { | ||
876 | ret = of_property_read_u32(node, "reg", &id); | ||
877 | if (ret || id > MAX_SESSIONS || id < 0) { | ||
878 | dev_err(dev, "valid dai id not found:%d\n", ret); | ||
879 | continue; | ||
880 | } | ||
881 | |||
882 | dai_drv = &q6asm_fe_dais[id]; | ||
883 | |||
884 | ret = of_property_read_u32(node, "direction", &dir); | ||
885 | if (ret) | ||
886 | continue; | ||
887 | |||
888 | if (dir == Q6ASM_DAI_RX) | ||
889 | dai_drv->capture = empty_stream; | ||
890 | else if (dir == Q6ASM_DAI_TX) | ||
891 | dai_drv->playback = empty_stream; | ||
892 | |||
893 | if (of_property_read_bool(node, "is-compress-dai")) | ||
894 | dai_drv->compress_new = snd_soc_new_compress; | ||
895 | } | ||
896 | |||
897 | return 0; | ||
898 | } | ||
899 | |||
532 | static int q6asm_dai_probe(struct platform_device *pdev) | 900 | static int q6asm_dai_probe(struct platform_device *pdev) |
533 | { | 901 | { |
534 | struct device *dev = &pdev->dev; | 902 | struct device *dev = &pdev->dev; |
@@ -549,6 +917,8 @@ static int q6asm_dai_probe(struct platform_device *pdev) | |||
549 | 917 | ||
550 | dev_set_drvdata(dev, pdata); | 918 | dev_set_drvdata(dev, pdata); |
551 | 919 | ||
920 | of_q6asm_parse_dai_data(dev, pdata); | ||
921 | |||
552 | return devm_snd_soc_register_component(dev, &q6asm_fe_dai_component, | 922 | return devm_snd_soc_register_component(dev, &q6asm_fe_dai_component, |
553 | q6asm_fe_dais, | 923 | q6asm_fe_dais, |
554 | ARRAY_SIZE(q6asm_fe_dais)); | 924 | ARRAY_SIZE(q6asm_fe_dais)); |
diff --git a/sound/soc/qcom/qdsp6/q6asm.c b/sound/soc/qcom/qdsp6/q6asm.c index e1cfa846a1dc..4f85cb19a309 100644 --- a/sound/soc/qcom/qdsp6/q6asm.c +++ b/sound/soc/qcom/qdsp6/q6asm.c | |||
@@ -12,6 +12,7 @@ | |||
12 | #include <linux/kref.h> | 12 | #include <linux/kref.h> |
13 | #include <linux/of.h> | 13 | #include <linux/of.h> |
14 | #include <uapi/sound/asound.h> | 14 | #include <uapi/sound/asound.h> |
15 | #include <uapi/sound/compress_params.h> | ||
15 | #include <linux/delay.h> | 16 | #include <linux/delay.h> |
16 | #include <linux/slab.h> | 17 | #include <linux/slab.h> |
17 | #include <linux/mm.h> | 18 | #include <linux/mm.h> |
@@ -36,6 +37,7 @@ | |||
36 | #define ASM_PARAM_ID_ENCDEC_ENC_CFG_BLK_V2 0x00010DA3 | 37 | #define ASM_PARAM_ID_ENCDEC_ENC_CFG_BLK_V2 0x00010DA3 |
37 | #define ASM_SESSION_CMD_RUN_V2 0x00010DAA | 38 | #define ASM_SESSION_CMD_RUN_V2 0x00010DAA |
38 | #define ASM_MEDIA_FMT_MULTI_CHANNEL_PCM_V2 0x00010DA5 | 39 | #define ASM_MEDIA_FMT_MULTI_CHANNEL_PCM_V2 0x00010DA5 |
40 | #define ASM_MEDIA_FMT_MP3 0x00010BE9 | ||
39 | #define ASM_DATA_CMD_WRITE_V2 0x00010DAB | 41 | #define ASM_DATA_CMD_WRITE_V2 0x00010DAB |
40 | #define ASM_DATA_CMD_READ_V2 0x00010DAC | 42 | #define ASM_DATA_CMD_READ_V2 0x00010DAC |
41 | #define ASM_SESSION_CMD_SUSPEND 0x00010DEC | 43 | #define ASM_SESSION_CMD_SUSPEND 0x00010DEC |
@@ -868,6 +870,9 @@ int q6asm_open_write(struct audio_client *ac, uint32_t format, | |||
868 | open->postprocopo_id = ASM_NULL_POPP_TOPOLOGY; | 870 | open->postprocopo_id = ASM_NULL_POPP_TOPOLOGY; |
869 | 871 | ||
870 | switch (format) { | 872 | switch (format) { |
873 | case SND_AUDIOCODEC_MP3: | ||
874 | open->dec_fmt_id = ASM_MEDIA_FMT_MP3; | ||
875 | break; | ||
871 | case FORMAT_LINEAR_PCM: | 876 | case FORMAT_LINEAR_PCM: |
872 | open->dec_fmt_id = ASM_MEDIA_FMT_MULTI_CHANNEL_PCM_V2; | 877 | open->dec_fmt_id = ASM_MEDIA_FMT_MULTI_CHANNEL_PCM_V2; |
873 | break; | 878 | break; |
diff --git a/sound/soc/qcom/qdsp6/q6routing.c b/sound/soc/qcom/qdsp6/q6routing.c index d61b8404f7da..ddcd9978cf57 100644 --- a/sound/soc/qcom/qdsp6/q6routing.c +++ b/sound/soc/qcom/qdsp6/q6routing.c | |||
@@ -453,6 +453,9 @@ static int msm_routing_put_audio_mixer(struct snd_kcontrol *kcontrol, | |||
453 | static const struct snd_kcontrol_new hdmi_mixer_controls[] = { | 453 | static const struct snd_kcontrol_new hdmi_mixer_controls[] = { |
454 | Q6ROUTING_RX_MIXERS(HDMI_RX) }; | 454 | Q6ROUTING_RX_MIXERS(HDMI_RX) }; |
455 | 455 | ||
456 | static const struct snd_kcontrol_new display_port_mixer_controls[] = { | ||
457 | Q6ROUTING_RX_MIXERS(DISPLAY_PORT_RX) }; | ||
458 | |||
456 | static const struct snd_kcontrol_new primary_mi2s_rx_mixer_controls[] = { | 459 | static const struct snd_kcontrol_new primary_mi2s_rx_mixer_controls[] = { |
457 | Q6ROUTING_RX_MIXERS(PRIMARY_MI2S_RX) }; | 460 | Q6ROUTING_RX_MIXERS(PRIMARY_MI2S_RX) }; |
458 | 461 | ||
@@ -655,6 +658,10 @@ static const struct snd_soc_dapm_widget msm_qdsp6_widgets[] = { | |||
655 | hdmi_mixer_controls, | 658 | hdmi_mixer_controls, |
656 | ARRAY_SIZE(hdmi_mixer_controls)), | 659 | ARRAY_SIZE(hdmi_mixer_controls)), |
657 | 660 | ||
661 | SND_SOC_DAPM_MIXER("DISPLAY_PORT_RX Audio Mixer", SND_SOC_NOPM, 0, 0, | ||
662 | display_port_mixer_controls, | ||
663 | ARRAY_SIZE(display_port_mixer_controls)), | ||
664 | |||
658 | SND_SOC_DAPM_MIXER("SLIMBUS_0_RX Audio Mixer", SND_SOC_NOPM, 0, 0, | 665 | SND_SOC_DAPM_MIXER("SLIMBUS_0_RX Audio Mixer", SND_SOC_NOPM, 0, 0, |
659 | slimbus_rx_mixer_controls, | 666 | slimbus_rx_mixer_controls, |
660 | ARRAY_SIZE(slimbus_rx_mixer_controls)), | 667 | ARRAY_SIZE(slimbus_rx_mixer_controls)), |
@@ -833,6 +840,8 @@ static const struct snd_soc_dapm_widget msm_qdsp6_widgets[] = { | |||
833 | 840 | ||
834 | static const struct snd_soc_dapm_route intercon[] = { | 841 | static const struct snd_soc_dapm_route intercon[] = { |
835 | Q6ROUTING_RX_DAPM_ROUTE("HDMI Mixer", "HDMI_RX"), | 842 | Q6ROUTING_RX_DAPM_ROUTE("HDMI Mixer", "HDMI_RX"), |
843 | Q6ROUTING_RX_DAPM_ROUTE("DISPLAY_PORT_RX Audio Mixer", | ||
844 | "DISPLAY_PORT_RX"), | ||
836 | Q6ROUTING_RX_DAPM_ROUTE("SLIMBUS_0_RX Audio Mixer", "SLIMBUS_0_RX"), | 845 | Q6ROUTING_RX_DAPM_ROUTE("SLIMBUS_0_RX Audio Mixer", "SLIMBUS_0_RX"), |
837 | Q6ROUTING_RX_DAPM_ROUTE("SLIMBUS_1_RX Audio Mixer", "SLIMBUS_1_RX"), | 846 | Q6ROUTING_RX_DAPM_ROUTE("SLIMBUS_1_RX Audio Mixer", "SLIMBUS_1_RX"), |
838 | Q6ROUTING_RX_DAPM_ROUTE("SLIMBUS_2_RX Audio Mixer", "SLIMBUS_2_RX"), | 847 | Q6ROUTING_RX_DAPM_ROUTE("SLIMBUS_2_RX Audio Mixer", "SLIMBUS_2_RX"), |
diff --git a/sound/soc/qcom/sdm845.c b/sound/soc/qcom/sdm845.c index 9effbecc571f..1db8ef668223 100644 --- a/sound/soc/qcom/sdm845.c +++ b/sound/soc/qcom/sdm845.c | |||
@@ -6,18 +6,31 @@ | |||
6 | #include <linux/module.h> | 6 | #include <linux/module.h> |
7 | #include <linux/platform_device.h> | 7 | #include <linux/platform_device.h> |
8 | #include <linux/of_device.h> | 8 | #include <linux/of_device.h> |
9 | #include <sound/core.h> | ||
9 | #include <sound/pcm.h> | 10 | #include <sound/pcm.h> |
10 | #include <sound/pcm_params.h> | 11 | #include <sound/pcm_params.h> |
12 | #include <sound/jack.h> | ||
13 | #include <sound/soc.h> | ||
14 | #include <uapi/linux/input-event-codes.h> | ||
11 | #include "common.h" | 15 | #include "common.h" |
12 | #include "qdsp6/q6afe.h" | 16 | #include "qdsp6/q6afe.h" |
17 | #include "../codecs/rt5663.h" | ||
13 | 18 | ||
14 | #define DEFAULT_SAMPLE_RATE_48K 48000 | 19 | #define DEFAULT_SAMPLE_RATE_48K 48000 |
15 | #define DEFAULT_MCLK_RATE 24576000 | 20 | #define DEFAULT_MCLK_RATE 24576000 |
16 | #define DEFAULT_BCLK_RATE 12288000 | 21 | #define TDM_BCLK_RATE 6144000 |
22 | #define MI2S_BCLK_RATE 1536000 | ||
23 | #define LEFT_SPK_TDM_TX_MASK 0x30 | ||
24 | #define RIGHT_SPK_TDM_TX_MASK 0xC0 | ||
25 | #define SPK_TDM_RX_MASK 0x03 | ||
26 | #define NUM_TDM_SLOTS 8 | ||
17 | 27 | ||
18 | struct sdm845_snd_data { | 28 | struct sdm845_snd_data { |
29 | struct snd_soc_jack jack; | ||
30 | bool jack_setup; | ||
19 | struct snd_soc_card *card; | 31 | struct snd_soc_card *card; |
20 | uint32_t pri_mi2s_clk_count; | 32 | uint32_t pri_mi2s_clk_count; |
33 | uint32_t sec_mi2s_clk_count; | ||
21 | uint32_t quat_tdm_clk_count; | 34 | uint32_t quat_tdm_clk_count; |
22 | }; | 35 | }; |
23 | 36 | ||
@@ -28,12 +41,12 @@ static int sdm845_tdm_snd_hw_params(struct snd_pcm_substream *substream, | |||
28 | { | 41 | { |
29 | struct snd_soc_pcm_runtime *rtd = substream->private_data; | 42 | struct snd_soc_pcm_runtime *rtd = substream->private_data; |
30 | struct snd_soc_dai *cpu_dai = rtd->cpu_dai; | 43 | struct snd_soc_dai *cpu_dai = rtd->cpu_dai; |
31 | int ret = 0; | 44 | int ret = 0, j; |
32 | int channels, slot_width; | 45 | int channels, slot_width; |
33 | 46 | ||
34 | switch (params_format(params)) { | 47 | switch (params_format(params)) { |
35 | case SNDRV_PCM_FORMAT_S16_LE: | 48 | case SNDRV_PCM_FORMAT_S16_LE: |
36 | slot_width = 32; | 49 | slot_width = 16; |
37 | break; | 50 | break; |
38 | default: | 51 | default: |
39 | dev_err(rtd->dev, "%s: invalid param format 0x%x\n", | 52 | dev_err(rtd->dev, "%s: invalid param format 0x%x\n", |
@@ -75,6 +88,35 @@ static int sdm845_tdm_snd_hw_params(struct snd_pcm_substream *substream, | |||
75 | goto end; | 88 | goto end; |
76 | } | 89 | } |
77 | } | 90 | } |
91 | |||
92 | for (j = 0; j < rtd->num_codecs; j++) { | ||
93 | struct snd_soc_dai *codec_dai = rtd->codec_dais[j]; | ||
94 | |||
95 | if (!strcmp(codec_dai->component->name_prefix, "Left")) { | ||
96 | ret = snd_soc_dai_set_tdm_slot( | ||
97 | codec_dai, LEFT_SPK_TDM_TX_MASK, | ||
98 | SPK_TDM_RX_MASK, NUM_TDM_SLOTS, | ||
99 | slot_width); | ||
100 | if (ret < 0) { | ||
101 | dev_err(rtd->dev, | ||
102 | "DEV0 TDM slot err:%d\n", ret); | ||
103 | return ret; | ||
104 | } | ||
105 | } | ||
106 | |||
107 | if (!strcmp(codec_dai->component->name_prefix, "Right")) { | ||
108 | ret = snd_soc_dai_set_tdm_slot( | ||
109 | codec_dai, RIGHT_SPK_TDM_TX_MASK, | ||
110 | SPK_TDM_RX_MASK, NUM_TDM_SLOTS, | ||
111 | slot_width); | ||
112 | if (ret < 0) { | ||
113 | dev_err(rtd->dev, | ||
114 | "DEV1 TDM slot err:%d\n", ret); | ||
115 | return ret; | ||
116 | } | ||
117 | } | ||
118 | } | ||
119 | |||
78 | end: | 120 | end: |
79 | return ret; | 121 | return ret; |
80 | } | 122 | } |
@@ -84,9 +126,27 @@ static int sdm845_snd_hw_params(struct snd_pcm_substream *substream, | |||
84 | { | 126 | { |
85 | struct snd_soc_pcm_runtime *rtd = substream->private_data; | 127 | struct snd_soc_pcm_runtime *rtd = substream->private_data; |
86 | struct snd_soc_dai *cpu_dai = rtd->cpu_dai; | 128 | struct snd_soc_dai *cpu_dai = rtd->cpu_dai; |
129 | struct snd_soc_dai *codec_dai = rtd->codec_dai; | ||
87 | int ret = 0; | 130 | int ret = 0; |
88 | 131 | ||
89 | switch (cpu_dai->id) { | 132 | switch (cpu_dai->id) { |
133 | case PRIMARY_MI2S_RX: | ||
134 | case PRIMARY_MI2S_TX: | ||
135 | /* | ||
136 | * Use ASRC for internal clocks, as PLL rate isn't multiple | ||
137 | * of BCLK. | ||
138 | */ | ||
139 | rt5663_sel_asrc_clk_src( | ||
140 | codec_dai->component, | ||
141 | RT5663_DA_STEREO_FILTER | RT5663_AD_STEREO_FILTER, | ||
142 | RT5663_CLK_SEL_I2S1_ASRC); | ||
143 | ret = snd_soc_dai_set_sysclk( | ||
144 | codec_dai, RT5663_SCLK_S_MCLK, DEFAULT_MCLK_RATE, | ||
145 | SND_SOC_CLOCK_IN); | ||
146 | if (ret < 0) | ||
147 | dev_err(rtd->dev, | ||
148 | "snd_soc_dai_set_sysclk err = %d\n", ret); | ||
149 | break; | ||
90 | case QUATERNARY_TDM_RX_0: | 150 | case QUATERNARY_TDM_RX_0: |
91 | case QUATERNARY_TDM_TX_0: | 151 | case QUATERNARY_TDM_TX_0: |
92 | ret = sdm845_tdm_snd_hw_params(substream, params); | 152 | ret = sdm845_tdm_snd_hw_params(substream, params); |
@@ -98,24 +158,87 @@ static int sdm845_snd_hw_params(struct snd_pcm_substream *substream, | |||
98 | return ret; | 158 | return ret; |
99 | } | 159 | } |
100 | 160 | ||
161 | static int sdm845_dai_init(struct snd_soc_pcm_runtime *rtd) | ||
162 | { | ||
163 | struct snd_soc_component *component; | ||
164 | struct snd_soc_dai_link *dai_link = rtd->dai_link; | ||
165 | struct snd_soc_card *card = rtd->card; | ||
166 | struct sdm845_snd_data *pdata = snd_soc_card_get_drvdata(card); | ||
167 | int i, rval; | ||
168 | |||
169 | if (!pdata->jack_setup) { | ||
170 | struct snd_jack *jack; | ||
171 | |||
172 | rval = snd_soc_card_jack_new(card, "Headset Jack", | ||
173 | SND_JACK_HEADSET | | ||
174 | SND_JACK_HEADPHONE | | ||
175 | SND_JACK_BTN_0 | SND_JACK_BTN_1 | | ||
176 | SND_JACK_BTN_2 | SND_JACK_BTN_3, | ||
177 | &pdata->jack, NULL, 0); | ||
178 | |||
179 | if (rval < 0) { | ||
180 | dev_err(card->dev, "Unable to add Headphone Jack\n"); | ||
181 | return rval; | ||
182 | } | ||
183 | |||
184 | jack = pdata->jack.jack; | ||
185 | |||
186 | snd_jack_set_key(jack, SND_JACK_BTN_0, KEY_PLAYPAUSE); | ||
187 | snd_jack_set_key(jack, SND_JACK_BTN_1, KEY_VOICECOMMAND); | ||
188 | snd_jack_set_key(jack, SND_JACK_BTN_2, KEY_VOLUMEUP); | ||
189 | snd_jack_set_key(jack, SND_JACK_BTN_3, KEY_VOLUMEDOWN); | ||
190 | pdata->jack_setup = true; | ||
191 | } | ||
192 | |||
193 | for (i = 0 ; i < dai_link->num_codecs; i++) { | ||
194 | struct snd_soc_dai *dai = rtd->codec_dais[i]; | ||
195 | |||
196 | component = dai->component; | ||
197 | rval = snd_soc_component_set_jack( | ||
198 | component, &pdata->jack, NULL); | ||
199 | if (rval != 0 && rval != -ENOTSUPP) { | ||
200 | dev_warn(card->dev, "Failed to set jack: %d\n", rval); | ||
201 | return rval; | ||
202 | } | ||
203 | } | ||
204 | |||
205 | return 0; | ||
206 | } | ||
207 | |||
208 | |||
101 | static int sdm845_snd_startup(struct snd_pcm_substream *substream) | 209 | static int sdm845_snd_startup(struct snd_pcm_substream *substream) |
102 | { | 210 | { |
103 | unsigned int fmt = SND_SOC_DAIFMT_CBS_CFS; | 211 | unsigned int fmt = SND_SOC_DAIFMT_CBS_CFS; |
212 | unsigned int codec_dai_fmt = SND_SOC_DAIFMT_CBS_CFS; | ||
104 | struct snd_soc_pcm_runtime *rtd = substream->private_data; | 213 | struct snd_soc_pcm_runtime *rtd = substream->private_data; |
105 | struct snd_soc_card *card = rtd->card; | 214 | struct snd_soc_card *card = rtd->card; |
106 | struct sdm845_snd_data *data = snd_soc_card_get_drvdata(card); | 215 | struct sdm845_snd_data *data = snd_soc_card_get_drvdata(card); |
107 | struct snd_soc_dai *cpu_dai = rtd->cpu_dai; | 216 | struct snd_soc_dai *cpu_dai = rtd->cpu_dai; |
217 | struct snd_soc_dai *codec_dai = rtd->codec_dai; | ||
218 | int j; | ||
219 | int ret; | ||
108 | 220 | ||
109 | switch (cpu_dai->id) { | 221 | switch (cpu_dai->id) { |
110 | case PRIMARY_MI2S_RX: | 222 | case PRIMARY_MI2S_RX: |
111 | case PRIMARY_MI2S_TX: | 223 | case PRIMARY_MI2S_TX: |
224 | codec_dai_fmt |= SND_SOC_DAIFMT_NB_NF; | ||
112 | if (++(data->pri_mi2s_clk_count) == 1) { | 225 | if (++(data->pri_mi2s_clk_count) == 1) { |
113 | snd_soc_dai_set_sysclk(cpu_dai, | 226 | snd_soc_dai_set_sysclk(cpu_dai, |
114 | Q6AFE_LPASS_CLK_ID_MCLK_1, | 227 | Q6AFE_LPASS_CLK_ID_MCLK_1, |
115 | DEFAULT_MCLK_RATE, SNDRV_PCM_STREAM_PLAYBACK); | 228 | DEFAULT_MCLK_RATE, SNDRV_PCM_STREAM_PLAYBACK); |
116 | snd_soc_dai_set_sysclk(cpu_dai, | 229 | snd_soc_dai_set_sysclk(cpu_dai, |
117 | Q6AFE_LPASS_CLK_ID_PRI_MI2S_IBIT, | 230 | Q6AFE_LPASS_CLK_ID_PRI_MI2S_IBIT, |
118 | DEFAULT_BCLK_RATE, SNDRV_PCM_STREAM_PLAYBACK); | 231 | MI2S_BCLK_RATE, SNDRV_PCM_STREAM_PLAYBACK); |
232 | } | ||
233 | snd_soc_dai_set_fmt(cpu_dai, fmt); | ||
234 | snd_soc_dai_set_fmt(codec_dai, codec_dai_fmt); | ||
235 | break; | ||
236 | |||
237 | case SECONDARY_MI2S_TX: | ||
238 | if (++(data->sec_mi2s_clk_count) == 1) { | ||
239 | snd_soc_dai_set_sysclk(cpu_dai, | ||
240 | Q6AFE_LPASS_CLK_ID_SEC_MI2S_IBIT, | ||
241 | MI2S_BCLK_RATE, SNDRV_PCM_STREAM_CAPTURE); | ||
119 | } | 242 | } |
120 | snd_soc_dai_set_fmt(cpu_dai, fmt); | 243 | snd_soc_dai_set_fmt(cpu_dai, fmt); |
121 | break; | 244 | break; |
@@ -125,7 +248,35 @@ static int sdm845_snd_startup(struct snd_pcm_substream *substream) | |||
125 | if (++(data->quat_tdm_clk_count) == 1) { | 248 | if (++(data->quat_tdm_clk_count) == 1) { |
126 | snd_soc_dai_set_sysclk(cpu_dai, | 249 | snd_soc_dai_set_sysclk(cpu_dai, |
127 | Q6AFE_LPASS_CLK_ID_QUAD_TDM_IBIT, | 250 | Q6AFE_LPASS_CLK_ID_QUAD_TDM_IBIT, |
128 | DEFAULT_BCLK_RATE, SNDRV_PCM_STREAM_PLAYBACK); | 251 | TDM_BCLK_RATE, SNDRV_PCM_STREAM_PLAYBACK); |
252 | } | ||
253 | |||
254 | codec_dai_fmt |= SND_SOC_DAIFMT_IB_NF | SND_SOC_DAIFMT_DSP_B; | ||
255 | |||
256 | for (j = 0; j < rtd->num_codecs; j++) { | ||
257 | codec_dai = rtd->codec_dais[j]; | ||
258 | |||
259 | if (!strcmp(codec_dai->component->name_prefix, | ||
260 | "Left")) { | ||
261 | ret = snd_soc_dai_set_fmt( | ||
262 | codec_dai, codec_dai_fmt); | ||
263 | if (ret < 0) { | ||
264 | dev_err(rtd->dev, | ||
265 | "Left TDM fmt err:%d\n", ret); | ||
266 | return ret; | ||
267 | } | ||
268 | } | ||
269 | |||
270 | if (!strcmp(codec_dai->component->name_prefix, | ||
271 | "Right")) { | ||
272 | ret = snd_soc_dai_set_fmt( | ||
273 | codec_dai, codec_dai_fmt); | ||
274 | if (ret < 0) { | ||
275 | dev_err(rtd->dev, | ||
276 | "Right TDM slot err:%d\n", ret); | ||
277 | return ret; | ||
278 | } | ||
279 | } | ||
129 | } | 280 | } |
130 | break; | 281 | break; |
131 | 282 | ||
@@ -156,6 +307,14 @@ static void sdm845_snd_shutdown(struct snd_pcm_substream *substream) | |||
156 | }; | 307 | }; |
157 | break; | 308 | break; |
158 | 309 | ||
310 | case SECONDARY_MI2S_TX: | ||
311 | if (--(data->sec_mi2s_clk_count) == 0) { | ||
312 | snd_soc_dai_set_sysclk(cpu_dai, | ||
313 | Q6AFE_LPASS_CLK_ID_SEC_MI2S_IBIT, | ||
314 | 0, SNDRV_PCM_STREAM_CAPTURE); | ||
315 | } | ||
316 | break; | ||
317 | |||
159 | case QUATERNARY_TDM_RX_0: | 318 | case QUATERNARY_TDM_RX_0: |
160 | case QUATERNARY_TDM_TX_0: | 319 | case QUATERNARY_TDM_TX_0: |
161 | if (--(data->quat_tdm_clk_count) == 0) { | 320 | if (--(data->quat_tdm_clk_count) == 0) { |
@@ -171,7 +330,7 @@ static void sdm845_snd_shutdown(struct snd_pcm_substream *substream) | |||
171 | } | 330 | } |
172 | } | 331 | } |
173 | 332 | ||
174 | static struct snd_soc_ops sdm845_be_ops = { | 333 | static const struct snd_soc_ops sdm845_be_ops = { |
175 | .hw_params = sdm845_snd_hw_params, | 334 | .hw_params = sdm845_snd_hw_params, |
176 | .startup = sdm845_snd_startup, | 335 | .startup = sdm845_snd_startup, |
177 | .shutdown = sdm845_snd_shutdown, | 336 | .shutdown = sdm845_snd_shutdown, |
@@ -193,7 +352,15 @@ static int sdm845_be_hw_params_fixup(struct snd_soc_pcm_runtime *rtd, | |||
193 | return 0; | 352 | return 0; |
194 | } | 353 | } |
195 | 354 | ||
196 | static void sdm845_add_be_ops(struct snd_soc_card *card) | 355 | static const struct snd_soc_dapm_widget sdm845_snd_widgets[] = { |
356 | SND_SOC_DAPM_HP("Headphone Jack", NULL), | ||
357 | SND_SOC_DAPM_MIC("Headset Mic", NULL), | ||
358 | SND_SOC_DAPM_SPK("Left Spk", NULL), | ||
359 | SND_SOC_DAPM_SPK("Right Spk", NULL), | ||
360 | SND_SOC_DAPM_MIC("Int Mic", NULL), | ||
361 | }; | ||
362 | |||
363 | static void sdm845_add_ops(struct snd_soc_card *card) | ||
197 | { | 364 | { |
198 | struct snd_soc_dai_link *link; | 365 | struct snd_soc_dai_link *link; |
199 | int i; | 366 | int i; |
@@ -203,6 +370,7 @@ static void sdm845_add_be_ops(struct snd_soc_card *card) | |||
203 | link->ops = &sdm845_be_ops; | 370 | link->ops = &sdm845_be_ops; |
204 | link->be_hw_params_fixup = sdm845_be_hw_params_fixup; | 371 | link->be_hw_params_fixup = sdm845_be_hw_params_fixup; |
205 | } | 372 | } |
373 | link->init = sdm845_dai_init; | ||
206 | } | 374 | } |
207 | } | 375 | } |
208 | 376 | ||
@@ -224,6 +392,8 @@ static int sdm845_snd_platform_probe(struct platform_device *pdev) | |||
224 | goto data_alloc_fail; | 392 | goto data_alloc_fail; |
225 | } | 393 | } |
226 | 394 | ||
395 | card->dapm_widgets = sdm845_snd_widgets; | ||
396 | card->num_dapm_widgets = ARRAY_SIZE(sdm845_snd_widgets); | ||
227 | card->dev = dev; | 397 | card->dev = dev; |
228 | dev_set_drvdata(dev, card); | 398 | dev_set_drvdata(dev, card); |
229 | ret = qcom_snd_parse_of(card); | 399 | ret = qcom_snd_parse_of(card); |
@@ -235,7 +405,7 @@ static int sdm845_snd_platform_probe(struct platform_device *pdev) | |||
235 | data->card = card; | 405 | data->card = card; |
236 | snd_soc_card_set_drvdata(card, data); | 406 | snd_soc_card_set_drvdata(card, data); |
237 | 407 | ||
238 | sdm845_add_be_ops(card); | 408 | sdm845_add_ops(card); |
239 | ret = snd_soc_register_card(card); | 409 | ret = snd_soc_register_card(card); |
240 | if (ret) { | 410 | if (ret) { |
241 | dev_err(dev, "Sound card registration failed\n"); | 411 | dev_err(dev, "Sound card registration failed\n"); |
diff --git a/sound/soc/sh/rcar/adg.c b/sound/soc/sh/rcar/adg.c index 28327dd2c6cb..e821ccc70f47 100644 --- a/sound/soc/sh/rcar/adg.c +++ b/sound/soc/sh/rcar/adg.c | |||
@@ -249,28 +249,8 @@ int rsnd_adg_set_src_timesel_gen2(struct rsnd_mod *src_mod, | |||
249 | out = out << shift; | 249 | out = out << shift; |
250 | mask = 0x0f1f << shift; | 250 | mask = 0x0f1f << shift; |
251 | 251 | ||
252 | switch (id / 2) { | 252 | rsnd_mod_bset(adg_mod, SRCIN_TIMSEL(id / 2), mask, in); |
253 | case 0: | 253 | rsnd_mod_bset(adg_mod, SRCOUT_TIMSEL(id / 2), mask, out); |
254 | rsnd_mod_bset(adg_mod, SRCIN_TIMSEL0, mask, in); | ||
255 | rsnd_mod_bset(adg_mod, SRCOUT_TIMSEL0, mask, out); | ||
256 | break; | ||
257 | case 1: | ||
258 | rsnd_mod_bset(adg_mod, SRCIN_TIMSEL1, mask, in); | ||
259 | rsnd_mod_bset(adg_mod, SRCOUT_TIMSEL1, mask, out); | ||
260 | break; | ||
261 | case 2: | ||
262 | rsnd_mod_bset(adg_mod, SRCIN_TIMSEL2, mask, in); | ||
263 | rsnd_mod_bset(adg_mod, SRCOUT_TIMSEL2, mask, out); | ||
264 | break; | ||
265 | case 3: | ||
266 | rsnd_mod_bset(adg_mod, SRCIN_TIMSEL3, mask, in); | ||
267 | rsnd_mod_bset(adg_mod, SRCOUT_TIMSEL3, mask, out); | ||
268 | break; | ||
269 | case 4: | ||
270 | rsnd_mod_bset(adg_mod, SRCIN_TIMSEL4, mask, in); | ||
271 | rsnd_mod_bset(adg_mod, SRCOUT_TIMSEL4, mask, out); | ||
272 | break; | ||
273 | } | ||
274 | 254 | ||
275 | if (en) | 255 | if (en) |
276 | rsnd_mod_bset(adg_mod, DIV_EN, en, en); | 256 | rsnd_mod_bset(adg_mod, DIV_EN, en, en); |
@@ -299,17 +279,7 @@ static void rsnd_adg_set_ssi_clk(struct rsnd_mod *ssi_mod, u32 val) | |||
299 | if (id == 8) | 279 | if (id == 8) |
300 | return; | 280 | return; |
301 | 281 | ||
302 | switch (id / 4) { | 282 | rsnd_mod_bset(adg_mod, AUDIO_CLK_SEL(id / 4), mask, val); |
303 | case 0: | ||
304 | rsnd_mod_bset(adg_mod, AUDIO_CLK_SEL0, mask, val); | ||
305 | break; | ||
306 | case 1: | ||
307 | rsnd_mod_bset(adg_mod, AUDIO_CLK_SEL1, mask, val); | ||
308 | break; | ||
309 | case 2: | ||
310 | rsnd_mod_bset(adg_mod, AUDIO_CLK_SEL2, mask, val); | ||
311 | break; | ||
312 | } | ||
313 | 283 | ||
314 | dev_dbg(dev, "AUDIO_CLK_SEL is 0x%x\n", val); | 284 | dev_dbg(dev, "AUDIO_CLK_SEL is 0x%x\n", val); |
315 | } | 285 | } |
@@ -613,7 +583,7 @@ int rsnd_adg_probe(struct rsnd_priv *priv) | |||
613 | return -ENOMEM; | 583 | return -ENOMEM; |
614 | 584 | ||
615 | ret = rsnd_mod_init(priv, &adg->mod, &adg_ops, | 585 | ret = rsnd_mod_init(priv, &adg->mod, &adg_ops, |
616 | NULL, NULL, 0, 0); | 586 | NULL, 0, 0); |
617 | if (ret) | 587 | if (ret) |
618 | return ret; | 588 | return ret; |
619 | 589 | ||
diff --git a/sound/soc/sh/rcar/cmd.c b/sound/soc/sh/rcar/cmd.c index cc191cd5fb82..e6bb6a9a0684 100644 --- a/sound/soc/sh/rcar/cmd.c +++ b/sound/soc/sh/rcar/cmd.c | |||
@@ -116,10 +116,11 @@ static int rsnd_cmd_stop(struct rsnd_mod *mod, | |||
116 | } | 116 | } |
117 | 117 | ||
118 | static struct rsnd_mod_ops rsnd_cmd_ops = { | 118 | static struct rsnd_mod_ops rsnd_cmd_ops = { |
119 | .name = CMD_NAME, | 119 | .name = CMD_NAME, |
120 | .init = rsnd_cmd_init, | 120 | .init = rsnd_cmd_init, |
121 | .start = rsnd_cmd_start, | 121 | .start = rsnd_cmd_start, |
122 | .stop = rsnd_cmd_stop, | 122 | .stop = rsnd_cmd_stop, |
123 | .get_status = rsnd_mod_get_status, | ||
123 | }; | 124 | }; |
124 | 125 | ||
125 | static struct rsnd_mod *rsnd_cmd_mod_get(struct rsnd_priv *priv, int id) | 126 | static struct rsnd_mod *rsnd_cmd_mod_get(struct rsnd_priv *priv, int id) |
@@ -162,7 +163,7 @@ int rsnd_cmd_probe(struct rsnd_priv *priv) | |||
162 | for_each_rsnd_cmd(cmd, priv, i) { | 163 | for_each_rsnd_cmd(cmd, priv, i) { |
163 | ret = rsnd_mod_init(priv, rsnd_mod_get(cmd), | 164 | ret = rsnd_mod_init(priv, rsnd_mod_get(cmd), |
164 | &rsnd_cmd_ops, NULL, | 165 | &rsnd_cmd_ops, NULL, |
165 | rsnd_mod_get_status, RSND_MOD_CMD, i); | 166 | RSND_MOD_CMD, i); |
166 | if (ret) | 167 | if (ret) |
167 | return ret; | 168 | return ret; |
168 | } | 169 | } |
diff --git a/sound/soc/sh/rcar/core.c b/sound/soc/sh/rcar/core.c index 114f8f233764..59e250cc2e9d 100644 --- a/sound/soc/sh/rcar/core.c +++ b/sound/soc/sh/rcar/core.c | |||
@@ -123,8 +123,8 @@ void rsnd_mod_make_sure(struct rsnd_mod *mod, enum rsnd_mod_type type) | |||
123 | struct rsnd_priv *priv = rsnd_mod_to_priv(mod); | 123 | struct rsnd_priv *priv = rsnd_mod_to_priv(mod); |
124 | struct device *dev = rsnd_priv_to_dev(priv); | 124 | struct device *dev = rsnd_priv_to_dev(priv); |
125 | 125 | ||
126 | dev_warn(dev, "%s[%d] is not your expected module\n", | 126 | dev_warn(dev, "%s is not your expected module\n", |
127 | rsnd_mod_name(mod), rsnd_mod_id(mod)); | 127 | rsnd_mod_name(mod)); |
128 | } | 128 | } |
129 | } | 129 | } |
130 | 130 | ||
@@ -137,20 +137,69 @@ struct dma_chan *rsnd_mod_dma_req(struct rsnd_dai_stream *io, | |||
137 | return mod->ops->dma_req(io, mod); | 137 | return mod->ops->dma_req(io, mod); |
138 | } | 138 | } |
139 | 139 | ||
140 | u32 *rsnd_mod_get_status(struct rsnd_dai_stream *io, | 140 | #define MOD_NAME_NUM 5 |
141 | struct rsnd_mod *mod, | 141 | #define MOD_NAME_SIZE 16 |
142 | char *rsnd_mod_name(struct rsnd_mod *mod) | ||
143 | { | ||
144 | static char names[MOD_NAME_NUM][MOD_NAME_SIZE]; | ||
145 | static int num; | ||
146 | char *name = names[num]; | ||
147 | |||
148 | num++; | ||
149 | if (num >= MOD_NAME_NUM) | ||
150 | num = 0; | ||
151 | |||
152 | /* | ||
153 | * Let's use same char to avoid pointlessness memory | ||
154 | * Thus, rsnd_mod_name() should be used immediately | ||
155 | * Don't keep pointer | ||
156 | */ | ||
157 | if ((mod)->ops->id_sub) { | ||
158 | snprintf(name, MOD_NAME_SIZE, "%s[%d%d]", | ||
159 | mod->ops->name, | ||
160 | rsnd_mod_id(mod), | ||
161 | rsnd_mod_id_sub(mod)); | ||
162 | } else { | ||
163 | snprintf(name, MOD_NAME_SIZE, "%s[%d]", | ||
164 | mod->ops->name, | ||
165 | rsnd_mod_id(mod)); | ||
166 | } | ||
167 | |||
168 | return name; | ||
169 | } | ||
170 | |||
171 | u32 *rsnd_mod_get_status(struct rsnd_mod *mod, | ||
172 | struct rsnd_dai_stream *io, | ||
142 | enum rsnd_mod_type type) | 173 | enum rsnd_mod_type type) |
143 | { | 174 | { |
144 | return &mod->status; | 175 | return &mod->status; |
145 | } | 176 | } |
146 | 177 | ||
178 | int rsnd_mod_id_raw(struct rsnd_mod *mod) | ||
179 | { | ||
180 | return mod->id; | ||
181 | } | ||
182 | |||
183 | int rsnd_mod_id(struct rsnd_mod *mod) | ||
184 | { | ||
185 | if ((mod)->ops->id) | ||
186 | return (mod)->ops->id(mod); | ||
187 | |||
188 | return rsnd_mod_id_raw(mod); | ||
189 | } | ||
190 | |||
191 | int rsnd_mod_id_sub(struct rsnd_mod *mod) | ||
192 | { | ||
193 | if ((mod)->ops->id_sub) | ||
194 | return (mod)->ops->id_sub(mod); | ||
195 | |||
196 | return 0; | ||
197 | } | ||
198 | |||
147 | int rsnd_mod_init(struct rsnd_priv *priv, | 199 | int rsnd_mod_init(struct rsnd_priv *priv, |
148 | struct rsnd_mod *mod, | 200 | struct rsnd_mod *mod, |
149 | struct rsnd_mod_ops *ops, | 201 | struct rsnd_mod_ops *ops, |
150 | struct clk *clk, | 202 | struct clk *clk, |
151 | u32* (*get_status)(struct rsnd_dai_stream *io, | ||
152 | struct rsnd_mod *mod, | ||
153 | enum rsnd_mod_type type), | ||
154 | enum rsnd_mod_type type, | 203 | enum rsnd_mod_type type, |
155 | int id) | 204 | int id) |
156 | { | 205 | { |
@@ -164,7 +213,6 @@ int rsnd_mod_init(struct rsnd_priv *priv, | |||
164 | mod->type = type; | 213 | mod->type = type; |
165 | mod->clk = clk; | 214 | mod->clk = clk; |
166 | mod->priv = priv; | 215 | mod->priv = priv; |
167 | mod->get_status = get_status; | ||
168 | 216 | ||
169 | return ret; | 217 | return ret; |
170 | } | 218 | } |
@@ -228,7 +276,20 @@ int rsnd_runtime_channel_after_ctu_with_params(struct rsnd_dai_stream *io, | |||
228 | struct rsnd_mod *ctu_mod = rsnd_io_to_mod_ctu(io); | 276 | struct rsnd_mod *ctu_mod = rsnd_io_to_mod_ctu(io); |
229 | 277 | ||
230 | if (ctu_mod) { | 278 | if (ctu_mod) { |
231 | u32 converted_chan = rsnd_ctu_converted_channel(ctu_mod); | 279 | u32 converted_chan = rsnd_io_converted_chan(io); |
280 | |||
281 | /* | ||
282 | * !! Note !! | ||
283 | * | ||
284 | * converted_chan will be used for CTU, | ||
285 | * or TDM Split mode. | ||
286 | * User shouldn't use CTU with TDM Split mode. | ||
287 | */ | ||
288 | if (rsnd_runtime_is_tdm_split(io)) { | ||
289 | struct device *dev = rsnd_priv_to_dev(rsnd_io_to_priv(io)); | ||
290 | |||
291 | dev_err(dev, "CTU and TDM Split should be used\n"); | ||
292 | } | ||
232 | 293 | ||
233 | if (converted_chan) | 294 | if (converted_chan) |
234 | return converted_chan; | 295 | return converted_chan; |
@@ -246,7 +307,7 @@ int rsnd_runtime_channel_for_ssi_with_params(struct rsnd_dai_stream *io, | |||
246 | rsnd_runtime_channel_original_with_params(io, params); | 307 | rsnd_runtime_channel_original_with_params(io, params); |
247 | 308 | ||
248 | /* Use Multi SSI */ | 309 | /* Use Multi SSI */ |
249 | if (rsnd_runtime_is_ssi_multi(io)) | 310 | if (rsnd_runtime_is_multi_ssi(io)) |
250 | chan /= rsnd_rdai_ssi_lane_get(rdai); | 311 | chan /= rsnd_rdai_ssi_lane_get(rdai); |
251 | 312 | ||
252 | /* TDM Extend Mode needs 8ch */ | 313 | /* TDM Extend Mode needs 8ch */ |
@@ -256,7 +317,7 @@ int rsnd_runtime_channel_for_ssi_with_params(struct rsnd_dai_stream *io, | |||
256 | return chan; | 317 | return chan; |
257 | } | 318 | } |
258 | 319 | ||
259 | int rsnd_runtime_is_ssi_multi(struct rsnd_dai_stream *io) | 320 | int rsnd_runtime_is_multi_ssi(struct rsnd_dai_stream *io) |
260 | { | 321 | { |
261 | struct rsnd_dai *rdai = rsnd_io_to_rdai(io); | 322 | struct rsnd_dai *rdai = rsnd_io_to_rdai(io); |
262 | int lane = rsnd_rdai_ssi_lane_get(rdai); | 323 | int lane = rsnd_rdai_ssi_lane_get(rdai); |
@@ -267,11 +328,16 @@ int rsnd_runtime_is_ssi_multi(struct rsnd_dai_stream *io) | |||
267 | return (chan > 2) && (lane > 1); | 328 | return (chan > 2) && (lane > 1); |
268 | } | 329 | } |
269 | 330 | ||
270 | int rsnd_runtime_is_ssi_tdm(struct rsnd_dai_stream *io) | 331 | int rsnd_runtime_is_tdm(struct rsnd_dai_stream *io) |
271 | { | 332 | { |
272 | return rsnd_runtime_channel_for_ssi(io) >= 6; | 333 | return rsnd_runtime_channel_for_ssi(io) >= 6; |
273 | } | 334 | } |
274 | 335 | ||
336 | int rsnd_runtime_is_tdm_split(struct rsnd_dai_stream *io) | ||
337 | { | ||
338 | return !!rsnd_flags_has(io, RSND_STREAM_TDM_SPLIT); | ||
339 | } | ||
340 | |||
275 | /* | 341 | /* |
276 | * ADINR function | 342 | * ADINR function |
277 | */ | 343 | */ |
@@ -472,20 +538,19 @@ static int rsnd_status_update(u32 *status, | |||
472 | enum rsnd_mod_type *types = rsnd_mod_sequence[is_play]; \ | 538 | enum rsnd_mod_type *types = rsnd_mod_sequence[is_play]; \ |
473 | for_each_rsnd_mod_arrays(i, mod, io, types, RSND_MOD_MAX) { \ | 539 | for_each_rsnd_mod_arrays(i, mod, io, types, RSND_MOD_MAX) { \ |
474 | int tmp = 0; \ | 540 | int tmp = 0; \ |
475 | u32 *status = mod->get_status(io, mod, types[i]); \ | 541 | u32 *status = mod->ops->get_status(mod, io, types[i]); \ |
476 | int func_call = rsnd_status_update(status, \ | 542 | int func_call = rsnd_status_update(status, \ |
477 | __rsnd_mod_shift_##fn, \ | 543 | __rsnd_mod_shift_##fn, \ |
478 | __rsnd_mod_add_##fn, \ | 544 | __rsnd_mod_add_##fn, \ |
479 | __rsnd_mod_call_##fn); \ | 545 | __rsnd_mod_call_##fn); \ |
480 | rsnd_dbg_dai_call(dev, "%s[%d]\t0x%08x %s\n", \ | 546 | rsnd_dbg_dai_call(dev, "%s\t0x%08x %s\n", \ |
481 | rsnd_mod_name(mod), rsnd_mod_id(mod), *status, \ | 547 | rsnd_mod_name(mod), *status, \ |
482 | (func_call && (mod)->ops->fn) ? #fn : ""); \ | 548 | (func_call && (mod)->ops->fn) ? #fn : ""); \ |
483 | if (func_call && (mod)->ops->fn) \ | 549 | if (func_call && (mod)->ops->fn) \ |
484 | tmp = (mod)->ops->fn(mod, io, param); \ | 550 | tmp = (mod)->ops->fn(mod, io, param); \ |
485 | if (tmp && (tmp != -EPROBE_DEFER)) \ | 551 | if (tmp && (tmp != -EPROBE_DEFER)) \ |
486 | dev_err(dev, "%s[%d] : %s error %d\n", \ | 552 | dev_err(dev, "%s : %s error %d\n", \ |
487 | rsnd_mod_name(mod), rsnd_mod_id(mod), \ | 553 | rsnd_mod_name(mod), #fn, tmp); \ |
488 | #fn, tmp); \ | ||
489 | ret |= tmp; \ | 554 | ret |= tmp; \ |
490 | } \ | 555 | } \ |
491 | ret; \ | 556 | ret; \ |
@@ -512,8 +577,8 @@ int rsnd_dai_connect(struct rsnd_mod *mod, | |||
512 | 577 | ||
513 | io->mod[type] = mod; | 578 | io->mod[type] = mod; |
514 | 579 | ||
515 | dev_dbg(dev, "%s[%d] is connected to io (%s)\n", | 580 | dev_dbg(dev, "%s is connected to io (%s)\n", |
516 | rsnd_mod_name(mod), rsnd_mod_id(mod), | 581 | rsnd_mod_name(mod), |
517 | rsnd_io_is_play(io) ? "Playback" : "Capture"); | 582 | rsnd_io_is_play(io) ? "Playback" : "Capture"); |
518 | 583 | ||
519 | return 0; | 584 | return 0; |
@@ -750,6 +815,7 @@ static int rsnd_soc_set_dai_tdm_slot(struct snd_soc_dai *dai, | |||
750 | 815 | ||
751 | switch (slots) { | 816 | switch (slots) { |
752 | case 2: | 817 | case 2: |
818 | /* TDM Split Mode */ | ||
753 | case 6: | 819 | case 6: |
754 | case 8: | 820 | case 8: |
755 | /* TDM Extend Mode */ | 821 | /* TDM Extend Mode */ |
@@ -965,6 +1031,82 @@ static const struct snd_soc_dai_ops rsnd_soc_dai_ops = { | |||
965 | .prepare = rsnd_soc_dai_prepare, | 1031 | .prepare = rsnd_soc_dai_prepare, |
966 | }; | 1032 | }; |
967 | 1033 | ||
1034 | static void rsnd_parse_connect_simple(struct rsnd_priv *priv, | ||
1035 | struct device_node *dai_np, | ||
1036 | int dai_i, int is_play) | ||
1037 | { | ||
1038 | struct device *dev = rsnd_priv_to_dev(priv); | ||
1039 | struct rsnd_dai *rdai = rsnd_rdai_get(priv, dai_i); | ||
1040 | struct rsnd_dai_stream *io = is_play ? | ||
1041 | &rdai->playback : | ||
1042 | &rdai->capture; | ||
1043 | struct device_node *ssiu_np = rsnd_ssiu_of_node(priv); | ||
1044 | struct device_node *np; | ||
1045 | int i, j; | ||
1046 | |||
1047 | if (!ssiu_np) | ||
1048 | return; | ||
1049 | |||
1050 | if (!rsnd_io_to_mod_ssi(io)) | ||
1051 | return; | ||
1052 | |||
1053 | /* | ||
1054 | * This driver assumes that it is TDM Split mode | ||
1055 | * if it includes ssiu node | ||
1056 | */ | ||
1057 | for (i = 0;; i++) { | ||
1058 | struct device_node *node = is_play ? | ||
1059 | of_parse_phandle(dai_np, "playback", i) : | ||
1060 | of_parse_phandle(dai_np, "capture", i); | ||
1061 | |||
1062 | if (!node) | ||
1063 | break; | ||
1064 | |||
1065 | j = 0; | ||
1066 | for_each_child_of_node(ssiu_np, np) { | ||
1067 | if (np == node) { | ||
1068 | rsnd_flags_set(io, RSND_STREAM_TDM_SPLIT); | ||
1069 | dev_dbg(dev, "%s is part of TDM Split\n", io->name); | ||
1070 | } | ||
1071 | j++; | ||
1072 | } | ||
1073 | |||
1074 | } | ||
1075 | } | ||
1076 | |||
1077 | static void rsnd_parse_connect_graph(struct rsnd_priv *priv, | ||
1078 | struct rsnd_dai_stream *io, | ||
1079 | struct device_node *endpoint) | ||
1080 | { | ||
1081 | struct device *dev = rsnd_priv_to_dev(priv); | ||
1082 | struct device_node *remote_port = of_graph_get_remote_port(endpoint); | ||
1083 | struct device_node *remote_node = of_graph_get_remote_port_parent(endpoint); | ||
1084 | |||
1085 | if (!rsnd_io_to_mod_ssi(io)) | ||
1086 | return; | ||
1087 | |||
1088 | /* HDMI0 */ | ||
1089 | if (strstr(remote_node->full_name, "hdmi@fead0000")) { | ||
1090 | rsnd_flags_set(io, RSND_STREAM_HDMI0); | ||
1091 | dev_dbg(dev, "%s connected to HDMI0\n", io->name); | ||
1092 | } | ||
1093 | |||
1094 | /* HDMI1 */ | ||
1095 | if (strstr(remote_node->full_name, "hdmi@feae0000")) { | ||
1096 | rsnd_flags_set(io, RSND_STREAM_HDMI1); | ||
1097 | dev_dbg(dev, "%s connected to HDMI1\n", io->name); | ||
1098 | } | ||
1099 | |||
1100 | /* | ||
1101 | * This driver assumes that it is TDM Split mode | ||
1102 | * if remote node has multi endpoint | ||
1103 | */ | ||
1104 | if (of_get_child_count(remote_port) > 1) { | ||
1105 | rsnd_flags_set(io, RSND_STREAM_TDM_SPLIT); | ||
1106 | dev_dbg(dev, "%s is part of TDM Split\n", io->name); | ||
1107 | } | ||
1108 | } | ||
1109 | |||
968 | void rsnd_parse_connect_common(struct rsnd_dai *rdai, | 1110 | void rsnd_parse_connect_common(struct rsnd_dai *rdai, |
969 | struct rsnd_mod* (*mod_get)(struct rsnd_priv *priv, int id), | 1111 | struct rsnd_mod* (*mod_get)(struct rsnd_priv *priv, int id), |
970 | struct device_node *node, | 1112 | struct device_node *node, |
@@ -1051,24 +1193,24 @@ static void __rsnd_dai_probe(struct rsnd_priv *priv, | |||
1051 | drv->name = rdai->name; | 1193 | drv->name = rdai->name; |
1052 | drv->ops = &rsnd_soc_dai_ops; | 1194 | drv->ops = &rsnd_soc_dai_ops; |
1053 | 1195 | ||
1054 | snprintf(rdai->playback.name, RSND_DAI_NAME_SIZE, | 1196 | snprintf(io_playback->name, RSND_DAI_NAME_SIZE, |
1055 | "DAI%d Playback", dai_i); | 1197 | "DAI%d Playback", dai_i); |
1056 | drv->playback.rates = RSND_RATES; | 1198 | drv->playback.rates = RSND_RATES; |
1057 | drv->playback.formats = RSND_FMTS; | 1199 | drv->playback.formats = RSND_FMTS; |
1058 | drv->playback.channels_min = 2; | 1200 | drv->playback.channels_min = 2; |
1059 | drv->playback.channels_max = 8; | 1201 | drv->playback.channels_max = 8; |
1060 | drv->playback.stream_name = rdai->playback.name; | 1202 | drv->playback.stream_name = io_playback->name; |
1061 | 1203 | ||
1062 | snprintf(rdai->capture.name, RSND_DAI_NAME_SIZE, | 1204 | snprintf(io_capture->name, RSND_DAI_NAME_SIZE, |
1063 | "DAI%d Capture", dai_i); | 1205 | "DAI%d Capture", dai_i); |
1064 | drv->capture.rates = RSND_RATES; | 1206 | drv->capture.rates = RSND_RATES; |
1065 | drv->capture.formats = RSND_FMTS; | 1207 | drv->capture.formats = RSND_FMTS; |
1066 | drv->capture.channels_min = 2; | 1208 | drv->capture.channels_min = 2; |
1067 | drv->capture.channels_max = 8; | 1209 | drv->capture.channels_max = 8; |
1068 | drv->capture.stream_name = rdai->capture.name; | 1210 | drv->capture.stream_name = io_capture->name; |
1069 | 1211 | ||
1070 | rdai->playback.rdai = rdai; | 1212 | io_playback->rdai = rdai; |
1071 | rdai->capture.rdai = rdai; | 1213 | io_capture->rdai = rdai; |
1072 | rsnd_rdai_channels_set(rdai, 2); /* default 2ch */ | 1214 | rsnd_rdai_channels_set(rdai, 2); /* default 2ch */ |
1073 | rsnd_rdai_ssi_lane_set(rdai, 1); /* default 1lane */ | 1215 | rsnd_rdai_ssi_lane_set(rdai, 1); /* default 1lane */ |
1074 | rsnd_rdai_width_set(rdai, 32); /* default 32bit width */ | 1216 | rsnd_rdai_width_set(rdai, 32); /* default 32bit width */ |
@@ -1081,6 +1223,7 @@ static void __rsnd_dai_probe(struct rsnd_priv *priv, | |||
1081 | break; | 1223 | break; |
1082 | 1224 | ||
1083 | rsnd_parse_connect_ssi(rdai, playback, capture); | 1225 | rsnd_parse_connect_ssi(rdai, playback, capture); |
1226 | rsnd_parse_connect_ssiu(rdai, playback, capture); | ||
1084 | rsnd_parse_connect_src(rdai, playback, capture); | 1227 | rsnd_parse_connect_src(rdai, playback, capture); |
1085 | rsnd_parse_connect_ctu(rdai, playback, capture); | 1228 | rsnd_parse_connect_ctu(rdai, playback, capture); |
1086 | rsnd_parse_connect_mix(rdai, playback, capture); | 1229 | rsnd_parse_connect_mix(rdai, playback, capture); |
@@ -1137,12 +1280,23 @@ static int rsnd_dai_probe(struct rsnd_priv *priv) | |||
1137 | if (is_graph) { | 1280 | if (is_graph) { |
1138 | for_each_endpoint_of_node(dai_node, dai_np) { | 1281 | for_each_endpoint_of_node(dai_node, dai_np) { |
1139 | __rsnd_dai_probe(priv, dai_np, dai_i); | 1282 | __rsnd_dai_probe(priv, dai_np, dai_i); |
1140 | rsnd_ssi_parse_hdmi_connection(priv, dai_np, dai_i); | 1283 | if (rsnd_is_gen3(priv)) { |
1284 | struct rsnd_dai *rdai = rsnd_rdai_get(priv, dai_i); | ||
1285 | |||
1286 | rsnd_parse_connect_graph(priv, &rdai->playback, dai_np); | ||
1287 | rsnd_parse_connect_graph(priv, &rdai->capture, dai_np); | ||
1288 | } | ||
1141 | dai_i++; | 1289 | dai_i++; |
1142 | } | 1290 | } |
1143 | } else { | 1291 | } else { |
1144 | for_each_child_of_node(dai_node, dai_np) | 1292 | for_each_child_of_node(dai_node, dai_np) { |
1145 | __rsnd_dai_probe(priv, dai_np, dai_i++); | 1293 | __rsnd_dai_probe(priv, dai_np, dai_i); |
1294 | if (rsnd_is_gen3(priv)) { | ||
1295 | rsnd_parse_connect_simple(priv, dai_np, dai_i, 1); | ||
1296 | rsnd_parse_connect_simple(priv, dai_np, dai_i, 0); | ||
1297 | } | ||
1298 | dai_i++; | ||
1299 | } | ||
1146 | } | 1300 | } |
1147 | 1301 | ||
1148 | return 0; | 1302 | return 0; |
@@ -1157,8 +1311,40 @@ static int rsnd_hw_params(struct snd_pcm_substream *substream, | |||
1157 | struct snd_soc_dai *dai = rsnd_substream_to_dai(substream); | 1311 | struct snd_soc_dai *dai = rsnd_substream_to_dai(substream); |
1158 | struct rsnd_dai *rdai = rsnd_dai_to_rdai(dai); | 1312 | struct rsnd_dai *rdai = rsnd_dai_to_rdai(dai); |
1159 | struct rsnd_dai_stream *io = rsnd_rdai_to_io(rdai, substream); | 1313 | struct rsnd_dai_stream *io = rsnd_rdai_to_io(rdai, substream); |
1314 | struct snd_soc_pcm_runtime *fe = substream->private_data; | ||
1160 | int ret; | 1315 | int ret; |
1161 | 1316 | ||
1317 | /* | ||
1318 | * rsnd assumes that it might be used under DPCM if user want to use | ||
1319 | * channel / rate convert. Then, rsnd should be FE. | ||
1320 | * And then, this function will be called *after* BE settings. | ||
1321 | * this means, each BE already has fixuped hw_params. | ||
1322 | * see | ||
1323 | * dpcm_fe_dai_hw_params() | ||
1324 | * dpcm_be_dai_hw_params() | ||
1325 | */ | ||
1326 | io->converted_rate = 0; | ||
1327 | io->converted_chan = 0; | ||
1328 | if (fe->dai_link->dynamic) { | ||
1329 | struct rsnd_priv *priv = rsnd_io_to_priv(io); | ||
1330 | struct device *dev = rsnd_priv_to_dev(priv); | ||
1331 | struct snd_soc_dpcm *dpcm; | ||
1332 | struct snd_pcm_hw_params *be_params; | ||
1333 | int stream = substream->stream; | ||
1334 | |||
1335 | for_each_dpcm_be(fe, stream, dpcm) { | ||
1336 | be_params = &dpcm->hw_params; | ||
1337 | if (params_channels(hw_params) != params_channels(be_params)) | ||
1338 | io->converted_chan = params_channels(be_params); | ||
1339 | if (params_rate(hw_params) != params_rate(be_params)) | ||
1340 | io->converted_rate = params_rate(be_params); | ||
1341 | } | ||
1342 | if (io->converted_chan) | ||
1343 | dev_dbg(dev, "convert channels = %d\n", io->converted_chan); | ||
1344 | if (io->converted_rate) | ||
1345 | dev_dbg(dev, "convert rate = %d\n", io->converted_rate); | ||
1346 | } | ||
1347 | |||
1162 | ret = rsnd_dai_call(hw_params, io, substream, hw_params); | 1348 | ret = rsnd_dai_call(hw_params, io, substream, hw_params); |
1163 | if (ret) | 1349 | if (ret) |
1164 | return ret; | 1350 | return ret; |
diff --git a/sound/soc/sh/rcar/ctu.c b/sound/soc/sh/rcar/ctu.c index ad702377a6c3..8cb06dab234e 100644 --- a/sound/soc/sh/rcar/ctu.c +++ b/sound/soc/sh/rcar/ctu.c | |||
@@ -72,10 +72,7 @@ | |||
72 | struct rsnd_ctu { | 72 | struct rsnd_ctu { |
73 | struct rsnd_mod mod; | 73 | struct rsnd_mod mod; |
74 | struct rsnd_kctrl_cfg_m pass; | 74 | struct rsnd_kctrl_cfg_m pass; |
75 | struct rsnd_kctrl_cfg_m sv0; | 75 | struct rsnd_kctrl_cfg_m sv[4]; |
76 | struct rsnd_kctrl_cfg_m sv1; | ||
77 | struct rsnd_kctrl_cfg_m sv2; | ||
78 | struct rsnd_kctrl_cfg_m sv3; | ||
79 | struct rsnd_kctrl_cfg_s reset; | 76 | struct rsnd_kctrl_cfg_s reset; |
80 | int channels; | 77 | int channels; |
81 | u32 flags; | 78 | u32 flags; |
@@ -107,13 +104,6 @@ static void rsnd_ctu_halt(struct rsnd_mod *mod) | |||
107 | rsnd_mod_write(mod, CTU_SWRSR, 0); | 104 | rsnd_mod_write(mod, CTU_SWRSR, 0); |
108 | } | 105 | } |
109 | 106 | ||
110 | int rsnd_ctu_converted_channel(struct rsnd_mod *mod) | ||
111 | { | ||
112 | struct rsnd_ctu *ctu = rsnd_mod_to_ctu(mod); | ||
113 | |||
114 | return ctu->channels; | ||
115 | } | ||
116 | |||
117 | static int rsnd_ctu_probe_(struct rsnd_mod *mod, | 107 | static int rsnd_ctu_probe_(struct rsnd_mod *mod, |
118 | struct rsnd_dai_stream *io, | 108 | struct rsnd_dai_stream *io, |
119 | struct rsnd_priv *priv) | 109 | struct rsnd_priv *priv) |
@@ -127,7 +117,7 @@ static void rsnd_ctu_value_init(struct rsnd_dai_stream *io, | |||
127 | struct rsnd_ctu *ctu = rsnd_mod_to_ctu(mod); | 117 | struct rsnd_ctu *ctu = rsnd_mod_to_ctu(mod); |
128 | u32 cpmdr = 0; | 118 | u32 cpmdr = 0; |
129 | u32 scmdr = 0; | 119 | u32 scmdr = 0; |
130 | int i; | 120 | int i, j; |
131 | 121 | ||
132 | for (i = 0; i < RSND_MAX_CHANNELS; i++) { | 122 | for (i = 0; i < RSND_MAX_CHANNELS; i++) { |
133 | u32 val = rsnd_kctrl_valm(ctu->pass, i); | 123 | u32 val = rsnd_kctrl_valm(ctu->pass, i); |
@@ -146,45 +136,13 @@ static void rsnd_ctu_value_init(struct rsnd_dai_stream *io, | |||
146 | 136 | ||
147 | rsnd_mod_write(mod, CTU_SCMDR, scmdr); | 137 | rsnd_mod_write(mod, CTU_SCMDR, scmdr); |
148 | 138 | ||
149 | if (scmdr > 0) { | 139 | for (i = 0; i < 4; i++) { |
150 | rsnd_mod_write(mod, CTU_SV00R, rsnd_kctrl_valm(ctu->sv0, 0)); | 140 | |
151 | rsnd_mod_write(mod, CTU_SV01R, rsnd_kctrl_valm(ctu->sv0, 1)); | 141 | if (i >= scmdr) |
152 | rsnd_mod_write(mod, CTU_SV02R, rsnd_kctrl_valm(ctu->sv0, 2)); | 142 | break; |
153 | rsnd_mod_write(mod, CTU_SV03R, rsnd_kctrl_valm(ctu->sv0, 3)); | 143 | |
154 | rsnd_mod_write(mod, CTU_SV04R, rsnd_kctrl_valm(ctu->sv0, 4)); | 144 | for (j = 0; j < RSND_MAX_CHANNELS; j++) |
155 | rsnd_mod_write(mod, CTU_SV05R, rsnd_kctrl_valm(ctu->sv0, 5)); | 145 | rsnd_mod_write(mod, CTU_SVxxR(i, j), rsnd_kctrl_valm(ctu->sv[i], j)); |
156 | rsnd_mod_write(mod, CTU_SV06R, rsnd_kctrl_valm(ctu->sv0, 6)); | ||
157 | rsnd_mod_write(mod, CTU_SV07R, rsnd_kctrl_valm(ctu->sv0, 7)); | ||
158 | } | ||
159 | if (scmdr > 1) { | ||
160 | rsnd_mod_write(mod, CTU_SV10R, rsnd_kctrl_valm(ctu->sv1, 0)); | ||
161 | rsnd_mod_write(mod, CTU_SV11R, rsnd_kctrl_valm(ctu->sv1, 1)); | ||
162 | rsnd_mod_write(mod, CTU_SV12R, rsnd_kctrl_valm(ctu->sv1, 2)); | ||
163 | rsnd_mod_write(mod, CTU_SV13R, rsnd_kctrl_valm(ctu->sv1, 3)); | ||
164 | rsnd_mod_write(mod, CTU_SV14R, rsnd_kctrl_valm(ctu->sv1, 4)); | ||
165 | rsnd_mod_write(mod, CTU_SV15R, rsnd_kctrl_valm(ctu->sv1, 5)); | ||
166 | rsnd_mod_write(mod, CTU_SV16R, rsnd_kctrl_valm(ctu->sv1, 6)); | ||
167 | rsnd_mod_write(mod, CTU_SV17R, rsnd_kctrl_valm(ctu->sv1, 7)); | ||
168 | } | ||
169 | if (scmdr > 2) { | ||
170 | rsnd_mod_write(mod, CTU_SV20R, rsnd_kctrl_valm(ctu->sv2, 0)); | ||
171 | rsnd_mod_write(mod, CTU_SV21R, rsnd_kctrl_valm(ctu->sv2, 1)); | ||
172 | rsnd_mod_write(mod, CTU_SV22R, rsnd_kctrl_valm(ctu->sv2, 2)); | ||
173 | rsnd_mod_write(mod, CTU_SV23R, rsnd_kctrl_valm(ctu->sv2, 3)); | ||
174 | rsnd_mod_write(mod, CTU_SV24R, rsnd_kctrl_valm(ctu->sv2, 4)); | ||
175 | rsnd_mod_write(mod, CTU_SV25R, rsnd_kctrl_valm(ctu->sv2, 5)); | ||
176 | rsnd_mod_write(mod, CTU_SV26R, rsnd_kctrl_valm(ctu->sv2, 6)); | ||
177 | rsnd_mod_write(mod, CTU_SV27R, rsnd_kctrl_valm(ctu->sv2, 7)); | ||
178 | } | ||
179 | if (scmdr > 3) { | ||
180 | rsnd_mod_write(mod, CTU_SV30R, rsnd_kctrl_valm(ctu->sv3, 0)); | ||
181 | rsnd_mod_write(mod, CTU_SV31R, rsnd_kctrl_valm(ctu->sv3, 1)); | ||
182 | rsnd_mod_write(mod, CTU_SV32R, rsnd_kctrl_valm(ctu->sv3, 2)); | ||
183 | rsnd_mod_write(mod, CTU_SV33R, rsnd_kctrl_valm(ctu->sv3, 3)); | ||
184 | rsnd_mod_write(mod, CTU_SV34R, rsnd_kctrl_valm(ctu->sv3, 4)); | ||
185 | rsnd_mod_write(mod, CTU_SV35R, rsnd_kctrl_valm(ctu->sv3, 5)); | ||
186 | rsnd_mod_write(mod, CTU_SV36R, rsnd_kctrl_valm(ctu->sv3, 6)); | ||
187 | rsnd_mod_write(mod, CTU_SV37R, rsnd_kctrl_valm(ctu->sv3, 7)); | ||
188 | } | 146 | } |
189 | 147 | ||
190 | rsnd_mod_write(mod, CTU_CTUIR, 0); | 148 | rsnd_mod_write(mod, CTU_CTUIR, 0); |
@@ -201,10 +159,10 @@ static void rsnd_ctu_value_reset(struct rsnd_dai_stream *io, | |||
201 | 159 | ||
202 | for (i = 0; i < RSND_MAX_CHANNELS; i++) { | 160 | for (i = 0; i < RSND_MAX_CHANNELS; i++) { |
203 | rsnd_kctrl_valm(ctu->pass, i) = 0; | 161 | rsnd_kctrl_valm(ctu->pass, i) = 0; |
204 | rsnd_kctrl_valm(ctu->sv0, i) = 0; | 162 | rsnd_kctrl_valm(ctu->sv[0], i) = 0; |
205 | rsnd_kctrl_valm(ctu->sv1, i) = 0; | 163 | rsnd_kctrl_valm(ctu->sv[1], i) = 0; |
206 | rsnd_kctrl_valm(ctu->sv2, i) = 0; | 164 | rsnd_kctrl_valm(ctu->sv[2], i) = 0; |
207 | rsnd_kctrl_valm(ctu->sv3, i) = 0; | 165 | rsnd_kctrl_valm(ctu->sv[3], i) = 0; |
208 | } | 166 | } |
209 | rsnd_kctrl_vals(ctu->reset) = 0; | 167 | rsnd_kctrl_vals(ctu->reset) = 0; |
210 | } | 168 | } |
@@ -233,43 +191,6 @@ static int rsnd_ctu_quit(struct rsnd_mod *mod, | |||
233 | return 0; | 191 | return 0; |
234 | } | 192 | } |
235 | 193 | ||
236 | static int rsnd_ctu_hw_params(struct rsnd_mod *mod, | ||
237 | struct rsnd_dai_stream *io, | ||
238 | struct snd_pcm_substream *substream, | ||
239 | struct snd_pcm_hw_params *fe_params) | ||
240 | { | ||
241 | struct rsnd_ctu *ctu = rsnd_mod_to_ctu(mod); | ||
242 | struct snd_soc_pcm_runtime *fe = substream->private_data; | ||
243 | |||
244 | /* | ||
245 | * CTU assumes that it is used under DPCM if user want to use | ||
246 | * channel transfer. Then, CTU should be FE. | ||
247 | * And then, this function will be called *after* BE settings. | ||
248 | * this means, each BE already has fixuped hw_params. | ||
249 | * see | ||
250 | * dpcm_fe_dai_hw_params() | ||
251 | * dpcm_be_dai_hw_params() | ||
252 | */ | ||
253 | ctu->channels = 0; | ||
254 | if (fe->dai_link->dynamic) { | ||
255 | struct rsnd_priv *priv = rsnd_mod_to_priv(mod); | ||
256 | struct device *dev = rsnd_priv_to_dev(priv); | ||
257 | struct snd_soc_dpcm *dpcm; | ||
258 | struct snd_pcm_hw_params *be_params; | ||
259 | int stream = substream->stream; | ||
260 | |||
261 | for_each_dpcm_be(fe, stream, dpcm) { | ||
262 | be_params = &dpcm->hw_params; | ||
263 | if (params_channels(fe_params) != params_channels(be_params)) | ||
264 | ctu->channels = params_channels(be_params); | ||
265 | } | ||
266 | |||
267 | dev_dbg(dev, "CTU convert channels %d\n", ctu->channels); | ||
268 | } | ||
269 | |||
270 | return 0; | ||
271 | } | ||
272 | |||
273 | static int rsnd_ctu_pcm_new(struct rsnd_mod *mod, | 194 | static int rsnd_ctu_pcm_new(struct rsnd_mod *mod, |
274 | struct rsnd_dai_stream *io, | 195 | struct rsnd_dai_stream *io, |
275 | struct snd_soc_pcm_runtime *rtd) | 196 | struct snd_soc_pcm_runtime *rtd) |
@@ -291,7 +212,7 @@ static int rsnd_ctu_pcm_new(struct rsnd_mod *mod, | |||
291 | ret = rsnd_kctrl_new_m(mod, io, rtd, "CTU SV0", | 212 | ret = rsnd_kctrl_new_m(mod, io, rtd, "CTU SV0", |
292 | rsnd_kctrl_accept_anytime, | 213 | rsnd_kctrl_accept_anytime, |
293 | NULL, | 214 | NULL, |
294 | &ctu->sv0, RSND_MAX_CHANNELS, | 215 | &ctu->sv[0], RSND_MAX_CHANNELS, |
295 | 0x00FFFFFF); | 216 | 0x00FFFFFF); |
296 | if (ret < 0) | 217 | if (ret < 0) |
297 | return ret; | 218 | return ret; |
@@ -300,7 +221,7 @@ static int rsnd_ctu_pcm_new(struct rsnd_mod *mod, | |||
300 | ret = rsnd_kctrl_new_m(mod, io, rtd, "CTU SV1", | 221 | ret = rsnd_kctrl_new_m(mod, io, rtd, "CTU SV1", |
301 | rsnd_kctrl_accept_anytime, | 222 | rsnd_kctrl_accept_anytime, |
302 | NULL, | 223 | NULL, |
303 | &ctu->sv1, RSND_MAX_CHANNELS, | 224 | &ctu->sv[1], RSND_MAX_CHANNELS, |
304 | 0x00FFFFFF); | 225 | 0x00FFFFFF); |
305 | if (ret < 0) | 226 | if (ret < 0) |
306 | return ret; | 227 | return ret; |
@@ -309,7 +230,7 @@ static int rsnd_ctu_pcm_new(struct rsnd_mod *mod, | |||
309 | ret = rsnd_kctrl_new_m(mod, io, rtd, "CTU SV2", | 230 | ret = rsnd_kctrl_new_m(mod, io, rtd, "CTU SV2", |
310 | rsnd_kctrl_accept_anytime, | 231 | rsnd_kctrl_accept_anytime, |
311 | NULL, | 232 | NULL, |
312 | &ctu->sv2, RSND_MAX_CHANNELS, | 233 | &ctu->sv[2], RSND_MAX_CHANNELS, |
313 | 0x00FFFFFF); | 234 | 0x00FFFFFF); |
314 | if (ret < 0) | 235 | if (ret < 0) |
315 | return ret; | 236 | return ret; |
@@ -318,7 +239,7 @@ static int rsnd_ctu_pcm_new(struct rsnd_mod *mod, | |||
318 | ret = rsnd_kctrl_new_m(mod, io, rtd, "CTU SV3", | 239 | ret = rsnd_kctrl_new_m(mod, io, rtd, "CTU SV3", |
319 | rsnd_kctrl_accept_anytime, | 240 | rsnd_kctrl_accept_anytime, |
320 | NULL, | 241 | NULL, |
321 | &ctu->sv3, RSND_MAX_CHANNELS, | 242 | &ctu->sv[3], RSND_MAX_CHANNELS, |
322 | 0x00FFFFFF); | 243 | 0x00FFFFFF); |
323 | if (ret < 0) | 244 | if (ret < 0) |
324 | return ret; | 245 | return ret; |
@@ -334,13 +255,34 @@ static int rsnd_ctu_pcm_new(struct rsnd_mod *mod, | |||
334 | return ret; | 255 | return ret; |
335 | } | 256 | } |
336 | 257 | ||
258 | static int rsnd_ctu_id(struct rsnd_mod *mod) | ||
259 | { | ||
260 | /* | ||
261 | * ctu00: -> 0, ctu01: -> 0, ctu02: -> 0, ctu03: -> 0 | ||
262 | * ctu10: -> 1, ctu11: -> 1, ctu12: -> 1, ctu13: -> 1 | ||
263 | */ | ||
264 | return mod->id / 4; | ||
265 | } | ||
266 | |||
267 | static int rsnd_ctu_id_sub(struct rsnd_mod *mod) | ||
268 | { | ||
269 | /* | ||
270 | * ctu00: -> 0, ctu01: -> 1, ctu02: -> 2, ctu03: -> 3 | ||
271 | * ctu10: -> 0, ctu11: -> 1, ctu12: -> 2, ctu13: -> 3 | ||
272 | */ | ||
273 | return mod->id % 4; | ||
274 | } | ||
275 | |||
337 | static struct rsnd_mod_ops rsnd_ctu_ops = { | 276 | static struct rsnd_mod_ops rsnd_ctu_ops = { |
338 | .name = CTU_NAME, | 277 | .name = CTU_NAME, |
339 | .probe = rsnd_ctu_probe_, | 278 | .probe = rsnd_ctu_probe_, |
340 | .init = rsnd_ctu_init, | 279 | .init = rsnd_ctu_init, |
341 | .quit = rsnd_ctu_quit, | 280 | .quit = rsnd_ctu_quit, |
342 | .hw_params = rsnd_ctu_hw_params, | ||
343 | .pcm_new = rsnd_ctu_pcm_new, | 281 | .pcm_new = rsnd_ctu_pcm_new, |
282 | .get_status = rsnd_mod_get_status, | ||
283 | .id = rsnd_ctu_id, | ||
284 | .id_sub = rsnd_ctu_id_sub, | ||
285 | .id_cmd = rsnd_mod_id_raw, | ||
344 | }; | 286 | }; |
345 | 287 | ||
346 | struct rsnd_mod *rsnd_ctu_mod_get(struct rsnd_priv *priv, int id) | 288 | struct rsnd_mod *rsnd_ctu_mod_get(struct rsnd_priv *priv, int id) |
@@ -404,7 +346,7 @@ int rsnd_ctu_probe(struct rsnd_priv *priv) | |||
404 | } | 346 | } |
405 | 347 | ||
406 | ret = rsnd_mod_init(priv, rsnd_mod_get(ctu), &rsnd_ctu_ops, | 348 | ret = rsnd_mod_init(priv, rsnd_mod_get(ctu), &rsnd_ctu_ops, |
407 | clk, rsnd_mod_get_status, RSND_MOD_CTU, i); | 349 | clk, RSND_MOD_CTU, i); |
408 | if (ret) { | 350 | if (ret) { |
409 | of_node_put(np); | 351 | of_node_put(np); |
410 | goto rsnd_ctu_probe_done; | 352 | goto rsnd_ctu_probe_done; |
diff --git a/sound/soc/sh/rcar/dma.c b/sound/soc/sh/rcar/dma.c index 6d1947515dc8..0324a5c39619 100644 --- a/sound/soc/sh/rcar/dma.c +++ b/sound/soc/sh/rcar/dma.c | |||
@@ -174,8 +174,8 @@ static int rsnd_dmaen_start(struct rsnd_mod *mod, | |||
174 | cfg.src_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES; | 174 | cfg.src_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES; |
175 | cfg.dst_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES; | 175 | cfg.dst_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES; |
176 | 176 | ||
177 | dev_dbg(dev, "%s[%d] %pad -> %pad\n", | 177 | dev_dbg(dev, "%s %pad -> %pad\n", |
178 | rsnd_mod_name(mod), rsnd_mod_id(mod), | 178 | rsnd_mod_name(mod), |
179 | &cfg.src_addr, &cfg.dst_addr); | 179 | &cfg.src_addr, &cfg.dst_addr); |
180 | 180 | ||
181 | ret = dmaengine_slave_config(dmaen->chan, &cfg); | 181 | ret = dmaengine_slave_config(dmaen->chan, &cfg); |
@@ -218,7 +218,7 @@ struct dma_chan *rsnd_dma_request_channel(struct device_node *of_node, | |||
218 | int i = 0; | 218 | int i = 0; |
219 | 219 | ||
220 | for_each_child_of_node(of_node, np) { | 220 | for_each_child_of_node(of_node, np) { |
221 | if (i == rsnd_mod_id(mod) && (!chan)) | 221 | if (i == rsnd_mod_id_raw(mod) && (!chan)) |
222 | chan = of_dma_request_slave_channel(np, name); | 222 | chan = of_dma_request_slave_channel(np, name); |
223 | i++; | 223 | i++; |
224 | } | 224 | } |
@@ -289,12 +289,13 @@ static int rsnd_dmaen_pointer(struct rsnd_mod *mod, | |||
289 | } | 289 | } |
290 | 290 | ||
291 | static struct rsnd_mod_ops rsnd_dmaen_ops = { | 291 | static struct rsnd_mod_ops rsnd_dmaen_ops = { |
292 | .name = "audmac", | 292 | .name = "audmac", |
293 | .prepare = rsnd_dmaen_prepare, | 293 | .prepare = rsnd_dmaen_prepare, |
294 | .cleanup = rsnd_dmaen_cleanup, | 294 | .cleanup = rsnd_dmaen_cleanup, |
295 | .start = rsnd_dmaen_start, | 295 | .start = rsnd_dmaen_start, |
296 | .stop = rsnd_dmaen_stop, | 296 | .stop = rsnd_dmaen_stop, |
297 | .pointer= rsnd_dmaen_pointer, | 297 | .pointer = rsnd_dmaen_pointer, |
298 | .get_status = rsnd_mod_get_status, | ||
298 | }; | 299 | }; |
299 | 300 | ||
300 | /* | 301 | /* |
@@ -343,14 +344,16 @@ static u32 rsnd_dmapp_get_id(struct rsnd_dai_stream *io, | |||
343 | struct rsnd_mod *mod) | 344 | struct rsnd_mod *mod) |
344 | { | 345 | { |
345 | struct rsnd_mod *ssi = rsnd_io_to_mod_ssi(io); | 346 | struct rsnd_mod *ssi = rsnd_io_to_mod_ssi(io); |
347 | struct rsnd_mod *ssiu = rsnd_io_to_mod_ssiu(io); | ||
346 | struct rsnd_mod *src = rsnd_io_to_mod_src(io); | 348 | struct rsnd_mod *src = rsnd_io_to_mod_src(io); |
347 | struct rsnd_mod *dvc = rsnd_io_to_mod_dvc(io); | 349 | struct rsnd_mod *dvc = rsnd_io_to_mod_dvc(io); |
348 | const u8 *entry = NULL; | 350 | const u8 *entry = NULL; |
349 | int id = 255; | 351 | int id = 255; |
350 | int size = 0; | 352 | int size = 0; |
351 | 353 | ||
352 | if (mod == ssi) { | 354 | if ((mod == ssi) || |
353 | int busif = rsnd_ssi_get_busif(io); | 355 | (mod == ssiu)) { |
356 | int busif = rsnd_mod_id_sub(ssiu); | ||
354 | 357 | ||
355 | entry = gen2_id_table_ssiu; | 358 | entry = gen2_id_table_ssiu; |
356 | size = ARRAY_SIZE(gen2_id_table_ssiu); | 359 | size = ARRAY_SIZE(gen2_id_table_ssiu); |
@@ -368,8 +371,7 @@ static u32 rsnd_dmapp_get_id(struct rsnd_dai_stream *io, | |||
368 | if ((!entry) || (size <= id)) { | 371 | if ((!entry) || (size <= id)) { |
369 | struct device *dev = rsnd_priv_to_dev(rsnd_io_to_priv(io)); | 372 | struct device *dev = rsnd_priv_to_dev(rsnd_io_to_priv(io)); |
370 | 373 | ||
371 | dev_err(dev, "unknown connection (%s[%d])\n", | 374 | dev_err(dev, "unknown connection (%s)\n", rsnd_mod_name(mod)); |
372 | rsnd_mod_name(mod), rsnd_mod_id(mod)); | ||
373 | 375 | ||
374 | /* use non-prohibited SRS number as error */ | 376 | /* use non-prohibited SRS number as error */ |
375 | return 0x00; /* SSI00 */ | 377 | return 0x00; /* SSI00 */ |
@@ -477,10 +479,11 @@ static int rsnd_dmapp_attach(struct rsnd_dai_stream *io, | |||
477 | } | 479 | } |
478 | 480 | ||
479 | static struct rsnd_mod_ops rsnd_dmapp_ops = { | 481 | static struct rsnd_mod_ops rsnd_dmapp_ops = { |
480 | .name = "audmac-pp", | 482 | .name = "audmac-pp", |
481 | .start = rsnd_dmapp_start, | 483 | .start = rsnd_dmapp_start, |
482 | .stop = rsnd_dmapp_stop, | 484 | .stop = rsnd_dmapp_stop, |
483 | .quit = rsnd_dmapp_stop, | 485 | .quit = rsnd_dmapp_stop, |
486 | .get_status = rsnd_mod_get_status, | ||
484 | }; | 487 | }; |
485 | 488 | ||
486 | /* | 489 | /* |
@@ -529,13 +532,14 @@ rsnd_gen2_dma_addr(struct rsnd_dai_stream *io, | |||
529 | struct device *dev = rsnd_priv_to_dev(priv); | 532 | struct device *dev = rsnd_priv_to_dev(priv); |
530 | phys_addr_t ssi_reg = rsnd_gen_get_phy_addr(priv, RSND_GEN2_SSI); | 533 | phys_addr_t ssi_reg = rsnd_gen_get_phy_addr(priv, RSND_GEN2_SSI); |
531 | phys_addr_t src_reg = rsnd_gen_get_phy_addr(priv, RSND_GEN2_SCU); | 534 | phys_addr_t src_reg = rsnd_gen_get_phy_addr(priv, RSND_GEN2_SCU); |
532 | int is_ssi = !!(rsnd_io_to_mod_ssi(io) == mod); | 535 | int is_ssi = !!(rsnd_io_to_mod_ssi(io) == mod) || |
536 | !!(rsnd_io_to_mod_ssiu(io) == mod); | ||
533 | int use_src = !!rsnd_io_to_mod_src(io); | 537 | int use_src = !!rsnd_io_to_mod_src(io); |
534 | int use_cmd = !!rsnd_io_to_mod_dvc(io) || | 538 | int use_cmd = !!rsnd_io_to_mod_dvc(io) || |
535 | !!rsnd_io_to_mod_mix(io) || | 539 | !!rsnd_io_to_mod_mix(io) || |
536 | !!rsnd_io_to_mod_ctu(io); | 540 | !!rsnd_io_to_mod_ctu(io); |
537 | int id = rsnd_mod_id(mod); | 541 | int id = rsnd_mod_id(mod); |
538 | int busif = rsnd_ssi_get_busif(io); | 542 | int busif = rsnd_mod_id_sub(rsnd_io_to_mod_ssiu(io)); |
539 | struct dma_addr { | 543 | struct dma_addr { |
540 | dma_addr_t out_addr; | 544 | dma_addr_t out_addr; |
541 | dma_addr_t in_addr; | 545 | dma_addr_t in_addr; |
@@ -619,7 +623,7 @@ static void rsnd_dma_of_path(struct rsnd_mod *this, | |||
619 | struct rsnd_mod **mod_from, | 623 | struct rsnd_mod **mod_from, |
620 | struct rsnd_mod **mod_to) | 624 | struct rsnd_mod **mod_to) |
621 | { | 625 | { |
622 | struct rsnd_mod *ssi = rsnd_io_to_mod_ssi(io); | 626 | struct rsnd_mod *ssi; |
623 | struct rsnd_mod *src = rsnd_io_to_mod_src(io); | 627 | struct rsnd_mod *src = rsnd_io_to_mod_src(io); |
624 | struct rsnd_mod *ctu = rsnd_io_to_mod_ctu(io); | 628 | struct rsnd_mod *ctu = rsnd_io_to_mod_ctu(io); |
625 | struct rsnd_mod *mix = rsnd_io_to_mod_mix(io); | 629 | struct rsnd_mod *mix = rsnd_io_to_mod_mix(io); |
@@ -630,6 +634,28 @@ static void rsnd_dma_of_path(struct rsnd_mod *this, | |||
630 | struct device *dev = rsnd_priv_to_dev(priv); | 634 | struct device *dev = rsnd_priv_to_dev(priv); |
631 | int nr, i, idx; | 635 | int nr, i, idx; |
632 | 636 | ||
637 | /* | ||
638 | * It should use "rcar_sound,ssiu" on DT. | ||
639 | * But, we need to keep compatibility for old version. | ||
640 | * | ||
641 | * If it has "rcar_sound.ssiu", it will be used. | ||
642 | * If not, "rcar_sound.ssi" will be used. | ||
643 | * see | ||
644 | * rsnd_ssiu_dma_req() | ||
645 | * rsnd_ssi_dma_req() | ||
646 | */ | ||
647 | if (rsnd_ssiu_of_node(priv)) { | ||
648 | struct rsnd_mod *ssiu = rsnd_io_to_mod_ssiu(io); | ||
649 | |||
650 | /* use SSIU */ | ||
651 | ssi = ssiu; | ||
652 | if (this == rsnd_io_to_mod_ssi(io)) | ||
653 | this = ssiu; | ||
654 | } else { | ||
655 | /* keep compatible, use SSI */ | ||
656 | ssi = rsnd_io_to_mod_ssi(io); | ||
657 | } | ||
658 | |||
633 | if (!ssi) | 659 | if (!ssi) |
634 | return; | 660 | return; |
635 | 661 | ||
@@ -690,12 +716,10 @@ static void rsnd_dma_of_path(struct rsnd_mod *this, | |||
690 | *mod_to = mod[1]; | 716 | *mod_to = mod[1]; |
691 | } | 717 | } |
692 | 718 | ||
693 | dev_dbg(dev, "module connection (this is %s[%d])\n", | 719 | dev_dbg(dev, "module connection (this is %s)\n", rsnd_mod_name(this)); |
694 | rsnd_mod_name(this), rsnd_mod_id(this)); | ||
695 | for (i = 0; i <= idx; i++) { | 720 | for (i = 0; i <= idx; i++) { |
696 | dev_dbg(dev, " %s[%d]%s\n", | 721 | dev_dbg(dev, " %s%s\n", |
697 | rsnd_mod_name(mod[i] ? mod[i] : &mem), | 722 | rsnd_mod_name(mod[i] ? mod[i] : &mem), |
698 | rsnd_mod_id (mod[i] ? mod[i] : &mem), | ||
699 | (mod[i] == *mod_from) ? " from" : | 723 | (mod[i] == *mod_from) ? " from" : |
700 | (mod[i] == *mod_to) ? " to" : ""); | 724 | (mod[i] == *mod_to) ? " to" : ""); |
701 | } | 725 | } |
@@ -756,16 +780,14 @@ static int rsnd_dma_alloc(struct rsnd_dai_stream *io, struct rsnd_mod *mod, | |||
756 | *dma_mod = rsnd_mod_get(dma); | 780 | *dma_mod = rsnd_mod_get(dma); |
757 | 781 | ||
758 | ret = rsnd_mod_init(priv, *dma_mod, ops, NULL, | 782 | ret = rsnd_mod_init(priv, *dma_mod, ops, NULL, |
759 | rsnd_mod_get_status, type, dma_id); | 783 | type, dma_id); |
760 | if (ret < 0) | 784 | if (ret < 0) |
761 | return ret; | 785 | return ret; |
762 | 786 | ||
763 | dev_dbg(dev, "%s[%d] %s[%d] -> %s[%d]\n", | 787 | dev_dbg(dev, "%s %s -> %s\n", |
764 | rsnd_mod_name(*dma_mod), rsnd_mod_id(*dma_mod), | 788 | rsnd_mod_name(*dma_mod), |
765 | rsnd_mod_name(mod_from ? mod_from : &mem), | 789 | rsnd_mod_name(mod_from ? mod_from : &mem), |
766 | rsnd_mod_id (mod_from ? mod_from : &mem), | 790 | rsnd_mod_name(mod_to ? mod_to : &mem)); |
767 | rsnd_mod_name(mod_to ? mod_to : &mem), | ||
768 | rsnd_mod_id (mod_to ? mod_to : &mem)); | ||
769 | 791 | ||
770 | ret = attach(io, dma, mod_from, mod_to); | 792 | ret = attach(io, dma, mod_from, mod_to); |
771 | if (ret < 0) | 793 | if (ret < 0) |
@@ -823,5 +845,5 @@ int rsnd_dma_probe(struct rsnd_priv *priv) | |||
823 | priv->dma = dmac; | 845 | priv->dma = dmac; |
824 | 846 | ||
825 | /* dummy mem mod for debug */ | 847 | /* dummy mem mod for debug */ |
826 | return rsnd_mod_init(NULL, &mem, &mem_ops, NULL, NULL, 0, 0); | 848 | return rsnd_mod_init(NULL, &mem, &mem_ops, NULL, 0, 0); |
827 | } | 849 | } |
diff --git a/sound/soc/sh/rcar/dvc.c b/sound/soc/sh/rcar/dvc.c index 024ece46bf68..8d91c0eb0880 100644 --- a/sound/soc/sh/rcar/dvc.c +++ b/sound/soc/sh/rcar/dvc.c | |||
@@ -86,14 +86,8 @@ static void rsnd_dvc_volume_parameter(struct rsnd_dai_stream *io, | |||
86 | val[i] = rsnd_kctrl_valm(dvc->volume, i); | 86 | val[i] = rsnd_kctrl_valm(dvc->volume, i); |
87 | 87 | ||
88 | /* Enable Digital Volume */ | 88 | /* Enable Digital Volume */ |
89 | rsnd_mod_write(mod, DVC_VOL0R, val[0]); | 89 | for (i = 0; i < RSND_MAX_CHANNELS; i++) |
90 | rsnd_mod_write(mod, DVC_VOL1R, val[1]); | 90 | rsnd_mod_write(mod, DVC_VOLxR(i), val[i]); |
91 | rsnd_mod_write(mod, DVC_VOL2R, val[2]); | ||
92 | rsnd_mod_write(mod, DVC_VOL3R, val[3]); | ||
93 | rsnd_mod_write(mod, DVC_VOL4R, val[4]); | ||
94 | rsnd_mod_write(mod, DVC_VOL5R, val[5]); | ||
95 | rsnd_mod_write(mod, DVC_VOL6R, val[6]); | ||
96 | rsnd_mod_write(mod, DVC_VOL7R, val[7]); | ||
97 | } | 91 | } |
98 | 92 | ||
99 | static void rsnd_dvc_volume_init(struct rsnd_dai_stream *io, | 93 | static void rsnd_dvc_volume_init(struct rsnd_dai_stream *io, |
@@ -298,6 +292,7 @@ static struct rsnd_mod_ops rsnd_dvc_ops = { | |||
298 | .init = rsnd_dvc_init, | 292 | .init = rsnd_dvc_init, |
299 | .quit = rsnd_dvc_quit, | 293 | .quit = rsnd_dvc_quit, |
300 | .pcm_new = rsnd_dvc_pcm_new, | 294 | .pcm_new = rsnd_dvc_pcm_new, |
295 | .get_status = rsnd_mod_get_status, | ||
301 | }; | 296 | }; |
302 | 297 | ||
303 | struct rsnd_mod *rsnd_dvc_mod_get(struct rsnd_priv *priv, int id) | 298 | struct rsnd_mod *rsnd_dvc_mod_get(struct rsnd_priv *priv, int id) |
@@ -357,7 +352,7 @@ int rsnd_dvc_probe(struct rsnd_priv *priv) | |||
357 | } | 352 | } |
358 | 353 | ||
359 | ret = rsnd_mod_init(priv, rsnd_mod_get(dvc), &rsnd_dvc_ops, | 354 | ret = rsnd_mod_init(priv, rsnd_mod_get(dvc), &rsnd_dvc_ops, |
360 | clk, rsnd_mod_get_status, RSND_MOD_DVC, i); | 355 | clk, RSND_MOD_DVC, i); |
361 | if (ret) { | 356 | if (ret) { |
362 | of_node_put(np); | 357 | of_node_put(np); |
363 | goto rsnd_dvc_probe_done; | 358 | goto rsnd_dvc_probe_done; |
diff --git a/sound/soc/sh/rcar/gen.c b/sound/soc/sh/rcar/gen.c index 1f7881cc16b2..7cda60188f41 100644 --- a/sound/soc/sh/rcar/gen.c +++ b/sound/soc/sh/rcar/gen.c | |||
@@ -26,8 +26,8 @@ struct rsnd_gen { | |||
26 | struct regmap *regmap[RSND_BASE_MAX]; | 26 | struct regmap *regmap[RSND_BASE_MAX]; |
27 | 27 | ||
28 | /* RSND_REG_MAX base */ | 28 | /* RSND_REG_MAX base */ |
29 | struct regmap_field *regs[RSND_REG_MAX]; | 29 | struct regmap_field *regs[REG_MAX]; |
30 | const char *reg_name[RSND_REG_MAX]; | 30 | const char *reg_name[REG_MAX]; |
31 | }; | 31 | }; |
32 | 32 | ||
33 | #define rsnd_priv_to_gen(p) ((struct rsnd_gen *)(p)->gen) | 33 | #define rsnd_priv_to_gen(p) ((struct rsnd_gen *)(p)->gen) |
@@ -49,11 +49,11 @@ struct rsnd_regmap_field_conf { | |||
49 | } | 49 | } |
50 | /* single address mapping */ | 50 | /* single address mapping */ |
51 | #define RSND_GEN_S_REG(id, offset) \ | 51 | #define RSND_GEN_S_REG(id, offset) \ |
52 | RSND_REG_SET(RSND_REG_##id, offset, 0, #id) | 52 | RSND_REG_SET(id, offset, 0, #id) |
53 | 53 | ||
54 | /* multi address mapping */ | 54 | /* multi address mapping */ |
55 | #define RSND_GEN_M_REG(id, offset, _id_offset) \ | 55 | #define RSND_GEN_M_REG(id, offset, _id_offset) \ |
56 | RSND_REG_SET(RSND_REG_##id, offset, _id_offset, #id) | 56 | RSND_REG_SET(id, offset, _id_offset, #id) |
57 | 57 | ||
58 | /* | 58 | /* |
59 | * basic function | 59 | * basic function |
@@ -71,9 +71,17 @@ static int rsnd_is_accessible_reg(struct rsnd_priv *priv, | |||
71 | return 1; | 71 | return 1; |
72 | } | 72 | } |
73 | 73 | ||
74 | u32 rsnd_read(struct rsnd_priv *priv, | 74 | static int rsnd_mod_id_cmd(struct rsnd_mod *mod) |
75 | struct rsnd_mod *mod, enum rsnd_reg reg) | ||
76 | { | 75 | { |
76 | if (mod->ops->id_cmd) | ||
77 | return mod->ops->id_cmd(mod); | ||
78 | |||
79 | return rsnd_mod_id(mod); | ||
80 | } | ||
81 | |||
82 | u32 rsnd_mod_read(struct rsnd_mod *mod, enum rsnd_reg reg) | ||
83 | { | ||
84 | struct rsnd_priv *priv = rsnd_mod_to_priv(mod); | ||
77 | struct device *dev = rsnd_priv_to_dev(priv); | 85 | struct device *dev = rsnd_priv_to_dev(priv); |
78 | struct rsnd_gen *gen = rsnd_priv_to_gen(priv); | 86 | struct rsnd_gen *gen = rsnd_priv_to_gen(priv); |
79 | u32 val; | 87 | u32 val; |
@@ -81,35 +89,36 @@ u32 rsnd_read(struct rsnd_priv *priv, | |||
81 | if (!rsnd_is_accessible_reg(priv, gen, reg)) | 89 | if (!rsnd_is_accessible_reg(priv, gen, reg)) |
82 | return 0; | 90 | return 0; |
83 | 91 | ||
84 | regmap_fields_read(gen->regs[reg], rsnd_mod_id(mod), &val); | 92 | regmap_fields_read(gen->regs[reg], rsnd_mod_id_cmd(mod), &val); |
85 | 93 | ||
86 | dev_dbg(dev, "r %s[%d] - %-18s (%4d) : %08x\n", | 94 | dev_dbg(dev, "r %s - %-18s (%4d) : %08x\n", |
87 | rsnd_mod_name(mod), rsnd_mod_id(mod), | 95 | rsnd_mod_name(mod), |
88 | rsnd_reg_name(gen, reg), reg, val); | 96 | rsnd_reg_name(gen, reg), reg, val); |
89 | 97 | ||
90 | return val; | 98 | return val; |
91 | } | 99 | } |
92 | 100 | ||
93 | void rsnd_write(struct rsnd_priv *priv, | 101 | void rsnd_mod_write(struct rsnd_mod *mod, |
94 | struct rsnd_mod *mod, | 102 | enum rsnd_reg reg, u32 data) |
95 | enum rsnd_reg reg, u32 data) | ||
96 | { | 103 | { |
104 | struct rsnd_priv *priv = rsnd_mod_to_priv(mod); | ||
97 | struct device *dev = rsnd_priv_to_dev(priv); | 105 | struct device *dev = rsnd_priv_to_dev(priv); |
98 | struct rsnd_gen *gen = rsnd_priv_to_gen(priv); | 106 | struct rsnd_gen *gen = rsnd_priv_to_gen(priv); |
99 | 107 | ||
100 | if (!rsnd_is_accessible_reg(priv, gen, reg)) | 108 | if (!rsnd_is_accessible_reg(priv, gen, reg)) |
101 | return; | 109 | return; |
102 | 110 | ||
103 | regmap_fields_force_write(gen->regs[reg], rsnd_mod_id(mod), data); | 111 | regmap_fields_force_write(gen->regs[reg], rsnd_mod_id_cmd(mod), data); |
104 | 112 | ||
105 | dev_dbg(dev, "w %s[%d] - %-18s (%4d) : %08x\n", | 113 | dev_dbg(dev, "w %s - %-18s (%4d) : %08x\n", |
106 | rsnd_mod_name(mod), rsnd_mod_id(mod), | 114 | rsnd_mod_name(mod), |
107 | rsnd_reg_name(gen, reg), reg, data); | 115 | rsnd_reg_name(gen, reg), reg, data); |
108 | } | 116 | } |
109 | 117 | ||
110 | void rsnd_bset(struct rsnd_priv *priv, struct rsnd_mod *mod, | 118 | void rsnd_mod_bset(struct rsnd_mod *mod, |
111 | enum rsnd_reg reg, u32 mask, u32 data) | 119 | enum rsnd_reg reg, u32 mask, u32 data) |
112 | { | 120 | { |
121 | struct rsnd_priv *priv = rsnd_mod_to_priv(mod); | ||
113 | struct device *dev = rsnd_priv_to_dev(priv); | 122 | struct device *dev = rsnd_priv_to_dev(priv); |
114 | struct rsnd_gen *gen = rsnd_priv_to_gen(priv); | 123 | struct rsnd_gen *gen = rsnd_priv_to_gen(priv); |
115 | 124 | ||
@@ -117,10 +126,10 @@ void rsnd_bset(struct rsnd_priv *priv, struct rsnd_mod *mod, | |||
117 | return; | 126 | return; |
118 | 127 | ||
119 | regmap_fields_force_update_bits(gen->regs[reg], | 128 | regmap_fields_force_update_bits(gen->regs[reg], |
120 | rsnd_mod_id(mod), mask, data); | 129 | rsnd_mod_id_cmd(mod), mask, data); |
121 | 130 | ||
122 | dev_dbg(dev, "b %s[%d] - %-18s (%4d) : %08x/%08x\n", | 131 | dev_dbg(dev, "b %s - %-18s (%4d) : %08x/%08x\n", |
123 | rsnd_mod_name(mod), rsnd_mod_id(mod), | 132 | rsnd_mod_name(mod), |
124 | rsnd_reg_name(gen, reg), reg, data, mask); | 133 | rsnd_reg_name(gen, reg), reg, data, mask); |
125 | 134 | ||
126 | } | 135 | } |
diff --git a/sound/soc/sh/rcar/mix.c b/sound/soc/sh/rcar/mix.c index 8e3b57eaa708..a3e0370f5704 100644 --- a/sound/soc/sh/rcar/mix.c +++ b/sound/soc/sh/rcar/mix.c | |||
@@ -256,6 +256,7 @@ static struct rsnd_mod_ops rsnd_mix_ops = { | |||
256 | .init = rsnd_mix_init, | 256 | .init = rsnd_mix_init, |
257 | .quit = rsnd_mix_quit, | 257 | .quit = rsnd_mix_quit, |
258 | .pcm_new = rsnd_mix_pcm_new, | 258 | .pcm_new = rsnd_mix_pcm_new, |
259 | .get_status = rsnd_mod_get_status, | ||
259 | }; | 260 | }; |
260 | 261 | ||
261 | struct rsnd_mod *rsnd_mix_mod_get(struct rsnd_priv *priv, int id) | 262 | struct rsnd_mod *rsnd_mix_mod_get(struct rsnd_priv *priv, int id) |
@@ -315,7 +316,7 @@ int rsnd_mix_probe(struct rsnd_priv *priv) | |||
315 | } | 316 | } |
316 | 317 | ||
317 | ret = rsnd_mod_init(priv, rsnd_mod_get(mix), &rsnd_mix_ops, | 318 | ret = rsnd_mod_init(priv, rsnd_mod_get(mix), &rsnd_mix_ops, |
318 | clk, rsnd_mod_get_status, RSND_MOD_MIX, i); | 319 | clk, RSND_MOD_MIX, i); |
319 | if (ret) { | 320 | if (ret) { |
320 | of_node_put(np); | 321 | of_node_put(np); |
321 | goto rsnd_mix_probe_done; | 322 | goto rsnd_mix_probe_done; |
diff --git a/sound/soc/sh/rcar/rsnd.h b/sound/soc/sh/rcar/rsnd.h index 4464d1d0a042..605e4b934982 100644 --- a/sound/soc/sh/rcar/rsnd.h +++ b/sound/soc/sh/rcar/rsnd.h | |||
@@ -42,165 +42,175 @@ | |||
42 | */ | 42 | */ |
43 | enum rsnd_reg { | 43 | enum rsnd_reg { |
44 | /* SCU (MIX/CTU/DVC) */ | 44 | /* SCU (MIX/CTU/DVC) */ |
45 | RSND_REG_SRC_I_BUSIF_MODE, | 45 | SRC_I_BUSIF_MODE, |
46 | RSND_REG_SRC_O_BUSIF_MODE, | 46 | SRC_O_BUSIF_MODE, |
47 | RSND_REG_SRC_ROUTE_MODE0, | 47 | SRC_ROUTE_MODE0, |
48 | RSND_REG_SRC_SWRSR, | 48 | SRC_SWRSR, |
49 | RSND_REG_SRC_SRCIR, | 49 | SRC_SRCIR, |
50 | RSND_REG_SRC_ADINR, | 50 | SRC_ADINR, |
51 | RSND_REG_SRC_IFSCR, | 51 | SRC_IFSCR, |
52 | RSND_REG_SRC_IFSVR, | 52 | SRC_IFSVR, |
53 | RSND_REG_SRC_SRCCR, | 53 | SRC_SRCCR, |
54 | RSND_REG_SRC_CTRL, | 54 | SRC_CTRL, |
55 | RSND_REG_SRC_BSDSR, | 55 | SRC_BSDSR, |
56 | RSND_REG_SRC_BSISR, | 56 | SRC_BSISR, |
57 | RSND_REG_SRC_INT_ENABLE0, | 57 | SRC_INT_ENABLE0, |
58 | RSND_REG_SRC_BUSIF_DALIGN, | 58 | SRC_BUSIF_DALIGN, |
59 | RSND_REG_SRCIN_TIMSEL0, | 59 | SRCIN_TIMSEL0, |
60 | RSND_REG_SRCIN_TIMSEL1, | 60 | SRCIN_TIMSEL1, |
61 | RSND_REG_SRCIN_TIMSEL2, | 61 | SRCIN_TIMSEL2, |
62 | RSND_REG_SRCIN_TIMSEL3, | 62 | SRCIN_TIMSEL3, |
63 | RSND_REG_SRCIN_TIMSEL4, | 63 | SRCIN_TIMSEL4, |
64 | RSND_REG_SRCOUT_TIMSEL0, | 64 | SRCOUT_TIMSEL0, |
65 | RSND_REG_SRCOUT_TIMSEL1, | 65 | SRCOUT_TIMSEL1, |
66 | RSND_REG_SRCOUT_TIMSEL2, | 66 | SRCOUT_TIMSEL2, |
67 | RSND_REG_SRCOUT_TIMSEL3, | 67 | SRCOUT_TIMSEL3, |
68 | RSND_REG_SRCOUT_TIMSEL4, | 68 | SRCOUT_TIMSEL4, |
69 | RSND_REG_SCU_SYS_STATUS0, | 69 | SCU_SYS_STATUS0, |
70 | RSND_REG_SCU_SYS_STATUS1, | 70 | SCU_SYS_STATUS1, |
71 | RSND_REG_SCU_SYS_INT_EN0, | 71 | SCU_SYS_INT_EN0, |
72 | RSND_REG_SCU_SYS_INT_EN1, | 72 | SCU_SYS_INT_EN1, |
73 | RSND_REG_CMD_CTRL, | 73 | CMD_CTRL, |
74 | RSND_REG_CMD_BUSIF_MODE, | 74 | CMD_BUSIF_MODE, |
75 | RSND_REG_CMD_BUSIF_DALIGN, | 75 | CMD_BUSIF_DALIGN, |
76 | RSND_REG_CMD_ROUTE_SLCT, | 76 | CMD_ROUTE_SLCT, |
77 | RSND_REG_CMDOUT_TIMSEL, | 77 | CMDOUT_TIMSEL, |
78 | RSND_REG_CTU_SWRSR, | 78 | CTU_SWRSR, |
79 | RSND_REG_CTU_CTUIR, | 79 | CTU_CTUIR, |
80 | RSND_REG_CTU_ADINR, | 80 | CTU_ADINR, |
81 | RSND_REG_CTU_CPMDR, | 81 | CTU_CPMDR, |
82 | RSND_REG_CTU_SCMDR, | 82 | CTU_SCMDR, |
83 | RSND_REG_CTU_SV00R, | 83 | CTU_SV00R, |
84 | RSND_REG_CTU_SV01R, | 84 | CTU_SV01R, |
85 | RSND_REG_CTU_SV02R, | 85 | CTU_SV02R, |
86 | RSND_REG_CTU_SV03R, | 86 | CTU_SV03R, |
87 | RSND_REG_CTU_SV04R, | 87 | CTU_SV04R, |
88 | RSND_REG_CTU_SV05R, | 88 | CTU_SV05R, |
89 | RSND_REG_CTU_SV06R, | 89 | CTU_SV06R, |
90 | RSND_REG_CTU_SV07R, | 90 | CTU_SV07R, |
91 | RSND_REG_CTU_SV10R, | 91 | CTU_SV10R, |
92 | RSND_REG_CTU_SV11R, | 92 | CTU_SV11R, |
93 | RSND_REG_CTU_SV12R, | 93 | CTU_SV12R, |
94 | RSND_REG_CTU_SV13R, | 94 | CTU_SV13R, |
95 | RSND_REG_CTU_SV14R, | 95 | CTU_SV14R, |
96 | RSND_REG_CTU_SV15R, | 96 | CTU_SV15R, |
97 | RSND_REG_CTU_SV16R, | 97 | CTU_SV16R, |
98 | RSND_REG_CTU_SV17R, | 98 | CTU_SV17R, |
99 | RSND_REG_CTU_SV20R, | 99 | CTU_SV20R, |
100 | RSND_REG_CTU_SV21R, | 100 | CTU_SV21R, |
101 | RSND_REG_CTU_SV22R, | 101 | CTU_SV22R, |
102 | RSND_REG_CTU_SV23R, | 102 | CTU_SV23R, |
103 | RSND_REG_CTU_SV24R, | 103 | CTU_SV24R, |
104 | RSND_REG_CTU_SV25R, | 104 | CTU_SV25R, |
105 | RSND_REG_CTU_SV26R, | 105 | CTU_SV26R, |
106 | RSND_REG_CTU_SV27R, | 106 | CTU_SV27R, |
107 | RSND_REG_CTU_SV30R, | 107 | CTU_SV30R, |
108 | RSND_REG_CTU_SV31R, | 108 | CTU_SV31R, |
109 | RSND_REG_CTU_SV32R, | 109 | CTU_SV32R, |
110 | RSND_REG_CTU_SV33R, | 110 | CTU_SV33R, |
111 | RSND_REG_CTU_SV34R, | 111 | CTU_SV34R, |
112 | RSND_REG_CTU_SV35R, | 112 | CTU_SV35R, |
113 | RSND_REG_CTU_SV36R, | 113 | CTU_SV36R, |
114 | RSND_REG_CTU_SV37R, | 114 | CTU_SV37R, |
115 | RSND_REG_MIX_SWRSR, | 115 | MIX_SWRSR, |
116 | RSND_REG_MIX_MIXIR, | 116 | MIX_MIXIR, |
117 | RSND_REG_MIX_ADINR, | 117 | MIX_ADINR, |
118 | RSND_REG_MIX_MIXMR, | 118 | MIX_MIXMR, |
119 | RSND_REG_MIX_MVPDR, | 119 | MIX_MVPDR, |
120 | RSND_REG_MIX_MDBAR, | 120 | MIX_MDBAR, |
121 | RSND_REG_MIX_MDBBR, | 121 | MIX_MDBBR, |
122 | RSND_REG_MIX_MDBCR, | 122 | MIX_MDBCR, |
123 | RSND_REG_MIX_MDBDR, | 123 | MIX_MDBDR, |
124 | RSND_REG_MIX_MDBER, | 124 | MIX_MDBER, |
125 | RSND_REG_DVC_SWRSR, | 125 | DVC_SWRSR, |
126 | RSND_REG_DVC_DVUIR, | 126 | DVC_DVUIR, |
127 | RSND_REG_DVC_ADINR, | 127 | DVC_ADINR, |
128 | RSND_REG_DVC_DVUCR, | 128 | DVC_DVUCR, |
129 | RSND_REG_DVC_ZCMCR, | 129 | DVC_ZCMCR, |
130 | RSND_REG_DVC_VOL0R, | 130 | DVC_VOL0R, |
131 | RSND_REG_DVC_VOL1R, | 131 | DVC_VOL1R, |
132 | RSND_REG_DVC_VOL2R, | 132 | DVC_VOL2R, |
133 | RSND_REG_DVC_VOL3R, | 133 | DVC_VOL3R, |
134 | RSND_REG_DVC_VOL4R, | 134 | DVC_VOL4R, |
135 | RSND_REG_DVC_VOL5R, | 135 | DVC_VOL5R, |
136 | RSND_REG_DVC_VOL6R, | 136 | DVC_VOL6R, |
137 | RSND_REG_DVC_VOL7R, | 137 | DVC_VOL7R, |
138 | RSND_REG_DVC_DVUER, | 138 | DVC_DVUER, |
139 | RSND_REG_DVC_VRCTR, | 139 | DVC_VRCTR, |
140 | RSND_REG_DVC_VRPDR, | 140 | DVC_VRPDR, |
141 | RSND_REG_DVC_VRDBR, | 141 | DVC_VRDBR, |
142 | 142 | ||
143 | /* ADG */ | 143 | /* ADG */ |
144 | RSND_REG_BRRA, | 144 | BRRA, |
145 | RSND_REG_BRRB, | 145 | BRRB, |
146 | RSND_REG_BRGCKR, | 146 | BRGCKR, |
147 | RSND_REG_DIV_EN, | 147 | DIV_EN, |
148 | RSND_REG_AUDIO_CLK_SEL0, | 148 | AUDIO_CLK_SEL0, |
149 | RSND_REG_AUDIO_CLK_SEL1, | 149 | AUDIO_CLK_SEL1, |
150 | RSND_REG_AUDIO_CLK_SEL2, | 150 | AUDIO_CLK_SEL2, |
151 | 151 | ||
152 | /* SSIU */ | 152 | /* SSIU */ |
153 | RSND_REG_SSI_MODE, | 153 | SSI_MODE, |
154 | RSND_REG_SSI_MODE0, | 154 | SSI_MODE0, |
155 | RSND_REG_SSI_MODE1, | 155 | SSI_MODE1, |
156 | RSND_REG_SSI_MODE2, | 156 | SSI_MODE2, |
157 | RSND_REG_SSI_CONTROL, | 157 | SSI_CONTROL, |
158 | RSND_REG_SSI_CTRL, | 158 | SSI_CTRL, |
159 | RSND_REG_SSI_BUSIF0_MODE, | 159 | SSI_BUSIF0_MODE, |
160 | RSND_REG_SSI_BUSIF0_ADINR, | 160 | SSI_BUSIF1_MODE, |
161 | RSND_REG_SSI_BUSIF0_DALIGN, | 161 | SSI_BUSIF2_MODE, |
162 | RSND_REG_SSI_BUSIF1_MODE, | 162 | SSI_BUSIF3_MODE, |
163 | RSND_REG_SSI_BUSIF1_ADINR, | 163 | SSI_BUSIF4_MODE, |
164 | RSND_REG_SSI_BUSIF1_DALIGN, | 164 | SSI_BUSIF5_MODE, |
165 | RSND_REG_SSI_BUSIF2_MODE, | 165 | SSI_BUSIF6_MODE, |
166 | RSND_REG_SSI_BUSIF2_ADINR, | 166 | SSI_BUSIF7_MODE, |
167 | RSND_REG_SSI_BUSIF2_DALIGN, | 167 | SSI_BUSIF0_ADINR, |
168 | RSND_REG_SSI_BUSIF3_MODE, | 168 | SSI_BUSIF1_ADINR, |
169 | RSND_REG_SSI_BUSIF3_ADINR, | 169 | SSI_BUSIF2_ADINR, |
170 | RSND_REG_SSI_BUSIF3_DALIGN, | 170 | SSI_BUSIF3_ADINR, |
171 | RSND_REG_SSI_BUSIF4_MODE, | 171 | SSI_BUSIF4_ADINR, |
172 | RSND_REG_SSI_BUSIF4_ADINR, | 172 | SSI_BUSIF5_ADINR, |
173 | RSND_REG_SSI_BUSIF4_DALIGN, | 173 | SSI_BUSIF6_ADINR, |
174 | RSND_REG_SSI_BUSIF5_MODE, | 174 | SSI_BUSIF7_ADINR, |
175 | RSND_REG_SSI_BUSIF5_ADINR, | 175 | SSI_BUSIF0_DALIGN, |
176 | RSND_REG_SSI_BUSIF5_DALIGN, | 176 | SSI_BUSIF1_DALIGN, |
177 | RSND_REG_SSI_BUSIF6_MODE, | 177 | SSI_BUSIF2_DALIGN, |
178 | RSND_REG_SSI_BUSIF6_ADINR, | 178 | SSI_BUSIF3_DALIGN, |
179 | RSND_REG_SSI_BUSIF6_DALIGN, | 179 | SSI_BUSIF4_DALIGN, |
180 | RSND_REG_SSI_BUSIF7_MODE, | 180 | SSI_BUSIF5_DALIGN, |
181 | RSND_REG_SSI_BUSIF7_ADINR, | 181 | SSI_BUSIF6_DALIGN, |
182 | RSND_REG_SSI_BUSIF7_DALIGN, | 182 | SSI_BUSIF7_DALIGN, |
183 | RSND_REG_SSI_INT_ENABLE, | 183 | SSI_INT_ENABLE, |
184 | RSND_REG_SSI_SYS_STATUS0, | 184 | SSI_SYS_STATUS0, |
185 | RSND_REG_SSI_SYS_STATUS1, | 185 | SSI_SYS_STATUS1, |
186 | RSND_REG_SSI_SYS_STATUS2, | 186 | SSI_SYS_STATUS2, |
187 | RSND_REG_SSI_SYS_STATUS3, | 187 | SSI_SYS_STATUS3, |
188 | RSND_REG_SSI_SYS_STATUS4, | 188 | SSI_SYS_STATUS4, |
189 | RSND_REG_SSI_SYS_STATUS5, | 189 | SSI_SYS_STATUS5, |
190 | RSND_REG_SSI_SYS_STATUS6, | 190 | SSI_SYS_STATUS6, |
191 | RSND_REG_SSI_SYS_STATUS7, | 191 | SSI_SYS_STATUS7, |
192 | RSND_REG_HDMI0_SEL, | 192 | HDMI0_SEL, |
193 | RSND_REG_HDMI1_SEL, | 193 | HDMI1_SEL, |
194 | 194 | ||
195 | /* SSI */ | 195 | /* SSI */ |
196 | RSND_REG_SSICR, | 196 | SSICR, |
197 | RSND_REG_SSISR, | 197 | SSISR, |
198 | RSND_REG_SSITDR, | 198 | SSITDR, |
199 | RSND_REG_SSIRDR, | 199 | SSIRDR, |
200 | RSND_REG_SSIWSR, | 200 | SSIWSR, |
201 | 201 | ||
202 | RSND_REG_MAX, | 202 | REG_MAX, |
203 | }; | 203 | }; |
204 | #define SRCIN_TIMSEL(i) (SRCIN_TIMSEL0 + (i)) | ||
205 | #define SRCOUT_TIMSEL(i) (SRCOUT_TIMSEL0 + (i)) | ||
206 | #define CTU_SVxxR(i, j) (CTU_SV00R + (i * 8) + (j)) | ||
207 | #define DVC_VOLxR(i) (DVC_VOL0R + (i)) | ||
208 | #define AUDIO_CLK_SEL(i) (AUDIO_CLK_SEL0 + (i)) | ||
209 | #define SSI_BUSIF_MODE(i) (SSI_BUSIF0_MODE + (i)) | ||
210 | #define SSI_BUSIF_ADINR(i) (SSI_BUSIF0_ADINR + (i)) | ||
211 | #define SSI_BUSIF_DALIGN(i) (SSI_BUSIF0_DALIGN + (i)) | ||
212 | #define SSI_SYS_STATUS(i) (SSI_SYS_STATUS0 + (i)) | ||
213 | |||
204 | 214 | ||
205 | struct rsnd_priv; | 215 | struct rsnd_priv; |
206 | struct rsnd_mod; | 216 | struct rsnd_mod; |
@@ -210,20 +220,9 @@ struct rsnd_dai_stream; | |||
210 | /* | 220 | /* |
211 | * R-Car basic functions | 221 | * R-Car basic functions |
212 | */ | 222 | */ |
213 | #define rsnd_mod_read(m, r) \ | 223 | u32 rsnd_mod_read(struct rsnd_mod *mod, enum rsnd_reg reg); |
214 | rsnd_read(rsnd_mod_to_priv(m), m, RSND_REG_##r) | 224 | void rsnd_mod_write(struct rsnd_mod *mod, enum rsnd_reg reg, u32 data); |
215 | #define rsnd_mod_write(m, r, d) \ | 225 | void rsnd_mod_bset(struct rsnd_mod *mod, enum rsnd_reg reg, u32 mask, u32 data); |
216 | rsnd_write(rsnd_mod_to_priv(m), m, RSND_REG_##r, d) | ||
217 | #define rsnd_mod_bset(m, r, s, d) \ | ||
218 | rsnd_bset(rsnd_mod_to_priv(m), m, RSND_REG_##r, s, d) | ||
219 | |||
220 | u32 rsnd_read(struct rsnd_priv *priv, struct rsnd_mod *mod, enum rsnd_reg reg); | ||
221 | void rsnd_write(struct rsnd_priv *priv, struct rsnd_mod *mod, | ||
222 | enum rsnd_reg reg, u32 data); | ||
223 | void rsnd_force_write(struct rsnd_priv *priv, struct rsnd_mod *mod, | ||
224 | enum rsnd_reg reg, u32 data); | ||
225 | void rsnd_bset(struct rsnd_priv *priv, struct rsnd_mod *mod, enum rsnd_reg reg, | ||
226 | u32 mask, u32 data); | ||
227 | u32 rsnd_get_adinr_bit(struct rsnd_mod *mod, struct rsnd_dai_stream *io); | 226 | u32 rsnd_get_adinr_bit(struct rsnd_mod *mod, struct rsnd_dai_stream *io); |
228 | u32 rsnd_get_dalign(struct rsnd_mod *mod, struct rsnd_dai_stream *io); | 227 | u32 rsnd_get_dalign(struct rsnd_mod *mod, struct rsnd_dai_stream *io); |
229 | u32 rsnd_get_busif_shift(struct rsnd_dai_stream *io, struct rsnd_mod *mod); | 228 | u32 rsnd_get_busif_shift(struct rsnd_dai_stream *io, struct rsnd_mod *mod); |
@@ -301,6 +300,12 @@ struct rsnd_mod_ops { | |||
301 | int (*cleanup)(struct rsnd_mod *mod, | 300 | int (*cleanup)(struct rsnd_mod *mod, |
302 | struct rsnd_dai_stream *io, | 301 | struct rsnd_dai_stream *io, |
303 | struct rsnd_priv *priv); | 302 | struct rsnd_priv *priv); |
303 | u32 *(*get_status)(struct rsnd_mod *mod, | ||
304 | struct rsnd_dai_stream *io, | ||
305 | enum rsnd_mod_type type); | ||
306 | int (*id)(struct rsnd_mod *mod); | ||
307 | int (*id_sub)(struct rsnd_mod *mod); | ||
308 | int (*id_cmd)(struct rsnd_mod *mod); | ||
304 | }; | 309 | }; |
305 | 310 | ||
306 | struct rsnd_dai_stream; | 311 | struct rsnd_dai_stream; |
@@ -310,9 +315,6 @@ struct rsnd_mod { | |||
310 | struct rsnd_mod_ops *ops; | 315 | struct rsnd_mod_ops *ops; |
311 | struct rsnd_priv *priv; | 316 | struct rsnd_priv *priv; |
312 | struct clk *clk; | 317 | struct clk *clk; |
313 | u32 *(*get_status)(struct rsnd_dai_stream *io, | ||
314 | struct rsnd_mod *mod, | ||
315 | enum rsnd_mod_type type); | ||
316 | u32 status; | 318 | u32 status; |
317 | }; | 319 | }; |
318 | /* | 320 | /* |
@@ -375,8 +377,6 @@ struct rsnd_mod { | |||
375 | #define __rsnd_mod_call_pointer 0 | 377 | #define __rsnd_mod_call_pointer 0 |
376 | 378 | ||
377 | #define rsnd_mod_to_priv(mod) ((mod)->priv) | 379 | #define rsnd_mod_to_priv(mod) ((mod)->priv) |
378 | #define rsnd_mod_name(mod) ((mod)->ops->name) | ||
379 | #define rsnd_mod_id(mod) ((mod)->id) | ||
380 | #define rsnd_mod_power_on(mod) clk_enable((mod)->clk) | 380 | #define rsnd_mod_power_on(mod) clk_enable((mod)->clk) |
381 | #define rsnd_mod_power_off(mod) clk_disable((mod)->clk) | 381 | #define rsnd_mod_power_off(mod) clk_disable((mod)->clk) |
382 | #define rsnd_mod_get(ip) (&(ip)->mod) | 382 | #define rsnd_mod_get(ip) (&(ip)->mod) |
@@ -385,9 +385,6 @@ int rsnd_mod_init(struct rsnd_priv *priv, | |||
385 | struct rsnd_mod *mod, | 385 | struct rsnd_mod *mod, |
386 | struct rsnd_mod_ops *ops, | 386 | struct rsnd_mod_ops *ops, |
387 | struct clk *clk, | 387 | struct clk *clk, |
388 | u32* (*get_status)(struct rsnd_dai_stream *io, | ||
389 | struct rsnd_mod *mod, | ||
390 | enum rsnd_mod_type type), | ||
391 | enum rsnd_mod_type type, | 388 | enum rsnd_mod_type type, |
392 | int id); | 389 | int id); |
393 | void rsnd_mod_quit(struct rsnd_mod *mod); | 390 | void rsnd_mod_quit(struct rsnd_mod *mod); |
@@ -396,9 +393,13 @@ struct dma_chan *rsnd_mod_dma_req(struct rsnd_dai_stream *io, | |||
396 | void rsnd_mod_interrupt(struct rsnd_mod *mod, | 393 | void rsnd_mod_interrupt(struct rsnd_mod *mod, |
397 | void (*callback)(struct rsnd_mod *mod, | 394 | void (*callback)(struct rsnd_mod *mod, |
398 | struct rsnd_dai_stream *io)); | 395 | struct rsnd_dai_stream *io)); |
399 | u32 *rsnd_mod_get_status(struct rsnd_dai_stream *io, | 396 | u32 *rsnd_mod_get_status(struct rsnd_mod *mod, |
400 | struct rsnd_mod *mod, | 397 | struct rsnd_dai_stream *io, |
401 | enum rsnd_mod_type type); | 398 | enum rsnd_mod_type type); |
399 | int rsnd_mod_id(struct rsnd_mod *mod); | ||
400 | int rsnd_mod_id_raw(struct rsnd_mod *mod); | ||
401 | int rsnd_mod_id_sub(struct rsnd_mod *mod); | ||
402 | char *rsnd_mod_name(struct rsnd_mod *mod); | ||
402 | struct rsnd_mod *rsnd_mod_next(int *iterator, | 403 | struct rsnd_mod *rsnd_mod_next(int *iterator, |
403 | struct rsnd_dai_stream *io, | 404 | struct rsnd_dai_stream *io, |
404 | enum rsnd_mod_type *array, | 405 | enum rsnd_mod_type *array, |
@@ -430,8 +431,9 @@ int rsnd_runtime_channel_after_ctu_with_params(struct rsnd_dai_stream *io, | |||
430 | rsnd_runtime_channel_for_ssi_with_params(io, NULL) | 431 | rsnd_runtime_channel_for_ssi_with_params(io, NULL) |
431 | int rsnd_runtime_channel_for_ssi_with_params(struct rsnd_dai_stream *io, | 432 | int rsnd_runtime_channel_for_ssi_with_params(struct rsnd_dai_stream *io, |
432 | struct snd_pcm_hw_params *params); | 433 | struct snd_pcm_hw_params *params); |
433 | int rsnd_runtime_is_ssi_multi(struct rsnd_dai_stream *io); | 434 | int rsnd_runtime_is_multi_ssi(struct rsnd_dai_stream *io); |
434 | int rsnd_runtime_is_ssi_tdm(struct rsnd_dai_stream *io); | 435 | int rsnd_runtime_is_tdm(struct rsnd_dai_stream *io); |
436 | int rsnd_runtime_is_tdm_split(struct rsnd_dai_stream *io); | ||
435 | 437 | ||
436 | /* | 438 | /* |
437 | * DT | 439 | * DT |
@@ -440,6 +442,7 @@ int rsnd_runtime_is_ssi_tdm(struct rsnd_dai_stream *io); | |||
440 | of_get_child_by_name(rsnd_priv_to_dev(priv)->of_node, node) | 442 | of_get_child_by_name(rsnd_priv_to_dev(priv)->of_node, node) |
441 | #define RSND_NODE_DAI "rcar_sound,dai" | 443 | #define RSND_NODE_DAI "rcar_sound,dai" |
442 | #define RSND_NODE_SSI "rcar_sound,ssi" | 444 | #define RSND_NODE_SSI "rcar_sound,ssi" |
445 | #define RSND_NODE_SSIU "rcar_sound,ssiu" | ||
443 | #define RSND_NODE_SRC "rcar_sound,src" | 446 | #define RSND_NODE_SRC "rcar_sound,src" |
444 | #define RSND_NODE_CTU "rcar_sound,ctu" | 447 | #define RSND_NODE_CTU "rcar_sound,ctu" |
445 | #define RSND_NODE_MIX "rcar_sound,mix" | 448 | #define RSND_NODE_MIX "rcar_sound,mix" |
@@ -456,8 +459,17 @@ struct rsnd_dai_stream { | |||
456 | struct rsnd_mod *dma; | 459 | struct rsnd_mod *dma; |
457 | struct rsnd_dai *rdai; | 460 | struct rsnd_dai *rdai; |
458 | struct device *dmac_dev; /* for IPMMU */ | 461 | struct device *dmac_dev; /* for IPMMU */ |
462 | u32 converted_rate; /* converted sampling rate */ | ||
463 | int converted_chan; /* converted channels */ | ||
459 | u32 parent_ssi_status; | 464 | u32 parent_ssi_status; |
465 | u32 flags; | ||
460 | }; | 466 | }; |
467 | |||
468 | /* flags */ | ||
469 | #define RSND_STREAM_HDMI0 (1 << 0) /* for HDMI0 */ | ||
470 | #define RSND_STREAM_HDMI1 (1 << 1) /* for HDMI1 */ | ||
471 | #define RSND_STREAM_TDM_SPLIT (1 << 2) /* for TDM split mode */ | ||
472 | |||
461 | #define rsnd_io_to_mod(io, i) ((i) < RSND_MOD_MAX ? (io)->mod[(i)] : NULL) | 473 | #define rsnd_io_to_mod(io, i) ((i) < RSND_MOD_MAX ? (io)->mod[(i)] : NULL) |
462 | #define rsnd_io_to_mod_ssi(io) rsnd_io_to_mod((io), RSND_MOD_SSI) | 474 | #define rsnd_io_to_mod_ssi(io) rsnd_io_to_mod((io), RSND_MOD_SSI) |
463 | #define rsnd_io_to_mod_ssiu(io) rsnd_io_to_mod((io), RSND_MOD_SSIU) | 475 | #define rsnd_io_to_mod_ssiu(io) rsnd_io_to_mod((io), RSND_MOD_SSIU) |
@@ -472,6 +484,8 @@ struct rsnd_dai_stream { | |||
472 | #define rsnd_io_is_play(io) (&rsnd_io_to_rdai(io)->playback == io) | 484 | #define rsnd_io_is_play(io) (&rsnd_io_to_rdai(io)->playback == io) |
473 | #define rsnd_io_to_runtime(io) ((io)->substream ? \ | 485 | #define rsnd_io_to_runtime(io) ((io)->substream ? \ |
474 | (io)->substream->runtime : NULL) | 486 | (io)->substream->runtime : NULL) |
487 | #define rsnd_io_converted_rate(io) ((io)->converted_rate) | ||
488 | #define rsnd_io_converted_chan(io) ((io)->converted_chan) | ||
475 | int rsnd_io_is_working(struct rsnd_dai_stream *io); | 489 | int rsnd_io_is_working(struct rsnd_dai_stream *io); |
476 | 490 | ||
477 | struct rsnd_dai { | 491 | struct rsnd_dai { |
@@ -712,18 +726,9 @@ extern const char * const volume_ramp_rate[]; | |||
712 | int rsnd_ssi_probe(struct rsnd_priv *priv); | 726 | int rsnd_ssi_probe(struct rsnd_priv *priv); |
713 | void rsnd_ssi_remove(struct rsnd_priv *priv); | 727 | void rsnd_ssi_remove(struct rsnd_priv *priv); |
714 | struct rsnd_mod *rsnd_ssi_mod_get(struct rsnd_priv *priv, int id); | 728 | struct rsnd_mod *rsnd_ssi_mod_get(struct rsnd_priv *priv, int id); |
715 | int rsnd_ssi_is_dma_mode(struct rsnd_mod *mod); | ||
716 | int rsnd_ssi_use_busif(struct rsnd_dai_stream *io); | 729 | int rsnd_ssi_use_busif(struct rsnd_dai_stream *io); |
717 | int rsnd_ssi_get_busif(struct rsnd_dai_stream *io); | ||
718 | u32 rsnd_ssi_multi_slaves_runtime(struct rsnd_dai_stream *io); | 730 | u32 rsnd_ssi_multi_slaves_runtime(struct rsnd_dai_stream *io); |
719 | 731 | ||
720 | #define RSND_SSI_HDMI_PORT0 0xf0 | ||
721 | #define RSND_SSI_HDMI_PORT1 0xf1 | ||
722 | int rsnd_ssi_hdmi_port(struct rsnd_dai_stream *io); | ||
723 | void rsnd_ssi_parse_hdmi_connection(struct rsnd_priv *priv, | ||
724 | struct device_node *endpoint, | ||
725 | int dai_i); | ||
726 | |||
727 | #define rsnd_ssi_is_pin_sharing(io) \ | 732 | #define rsnd_ssi_is_pin_sharing(io) \ |
728 | __rsnd_ssi_is_pin_sharing(rsnd_io_to_mod_ssi(io)) | 733 | __rsnd_ssi_is_pin_sharing(rsnd_io_to_mod_ssi(io)) |
729 | int __rsnd_ssi_is_pin_sharing(struct rsnd_mod *mod); | 734 | int __rsnd_ssi_is_pin_sharing(struct rsnd_mod *mod); |
@@ -742,6 +747,10 @@ int rsnd_ssiu_attach(struct rsnd_dai_stream *io, | |||
742 | struct rsnd_mod *mod); | 747 | struct rsnd_mod *mod); |
743 | int rsnd_ssiu_probe(struct rsnd_priv *priv); | 748 | int rsnd_ssiu_probe(struct rsnd_priv *priv); |
744 | void rsnd_ssiu_remove(struct rsnd_priv *priv); | 749 | void rsnd_ssiu_remove(struct rsnd_priv *priv); |
750 | void rsnd_parse_connect_ssiu(struct rsnd_dai *rdai, | ||
751 | struct device_node *playback, | ||
752 | struct device_node *capture); | ||
753 | #define rsnd_ssiu_of_node(priv) rsnd_parse_of_node(priv, RSND_NODE_SSIU) | ||
745 | 754 | ||
746 | /* | 755 | /* |
747 | * R-Car SRC | 756 | * R-Car SRC |
@@ -767,7 +776,6 @@ unsigned int rsnd_src_get_rate(struct rsnd_priv *priv, | |||
767 | */ | 776 | */ |
768 | int rsnd_ctu_probe(struct rsnd_priv *priv); | 777 | int rsnd_ctu_probe(struct rsnd_priv *priv); |
769 | void rsnd_ctu_remove(struct rsnd_priv *priv); | 778 | void rsnd_ctu_remove(struct rsnd_priv *priv); |
770 | int rsnd_ctu_converted_channel(struct rsnd_mod *mod); | ||
771 | struct rsnd_mod *rsnd_ctu_mod_get(struct rsnd_priv *priv, int id); | 779 | struct rsnd_mod *rsnd_ctu_mod_get(struct rsnd_priv *priv, int id); |
772 | #define rsnd_ctu_of_node(priv) rsnd_parse_of_node(priv, RSND_NODE_CTU) | 780 | #define rsnd_ctu_of_node(priv) rsnd_parse_of_node(priv, RSND_NODE_CTU) |
773 | #define rsnd_parse_connect_ctu(rdai, playback, capture) \ | 781 | #define rsnd_parse_connect_ctu(rdai, playback, capture) \ |
diff --git a/sound/soc/sh/rcar/src.c b/sound/soc/sh/rcar/src.c index cd38a43b976f..50348a2c9203 100644 --- a/sound/soc/sh/rcar/src.c +++ b/sound/soc/sh/rcar/src.c | |||
@@ -25,7 +25,6 @@ struct rsnd_src { | |||
25 | struct rsnd_mod *dma; | 25 | struct rsnd_mod *dma; |
26 | struct rsnd_kctrl_cfg_s sen; /* sync convert enable */ | 26 | struct rsnd_kctrl_cfg_s sen; /* sync convert enable */ |
27 | struct rsnd_kctrl_cfg_s sync; /* sync convert */ | 27 | struct rsnd_kctrl_cfg_s sync; /* sync convert */ |
28 | u32 convert_rate; /* sampling rate convert */ | ||
29 | int irq; | 28 | int irq; |
30 | }; | 29 | }; |
31 | 30 | ||
@@ -89,12 +88,12 @@ static u32 rsnd_src_convert_rate(struct rsnd_dai_stream *io, | |||
89 | return 0; | 88 | return 0; |
90 | 89 | ||
91 | if (!rsnd_src_sync_is_enabled(mod)) | 90 | if (!rsnd_src_sync_is_enabled(mod)) |
92 | return src->convert_rate; | 91 | return rsnd_io_converted_rate(io); |
93 | 92 | ||
94 | convert_rate = src->sync.val; | 93 | convert_rate = src->sync.val; |
95 | 94 | ||
96 | if (!convert_rate) | 95 | if (!convert_rate) |
97 | convert_rate = src->convert_rate; | 96 | convert_rate = rsnd_io_converted_rate(io); |
98 | 97 | ||
99 | if (!convert_rate) | 98 | if (!convert_rate) |
100 | convert_rate = runtime->rate; | 99 | convert_rate = runtime->rate; |
@@ -135,40 +134,6 @@ unsigned int rsnd_src_get_rate(struct rsnd_priv *priv, | |||
135 | return rate; | 134 | return rate; |
136 | } | 135 | } |
137 | 136 | ||
138 | static int rsnd_src_hw_params(struct rsnd_mod *mod, | ||
139 | struct rsnd_dai_stream *io, | ||
140 | struct snd_pcm_substream *substream, | ||
141 | struct snd_pcm_hw_params *fe_params) | ||
142 | { | ||
143 | struct rsnd_src *src = rsnd_mod_to_src(mod); | ||
144 | struct snd_soc_pcm_runtime *fe = substream->private_data; | ||
145 | |||
146 | /* | ||
147 | * SRC assumes that it is used under DPCM if user want to use | ||
148 | * sampling rate convert. Then, SRC should be FE. | ||
149 | * And then, this function will be called *after* BE settings. | ||
150 | * this means, each BE already has fixuped hw_params. | ||
151 | * see | ||
152 | * dpcm_fe_dai_hw_params() | ||
153 | * dpcm_be_dai_hw_params() | ||
154 | */ | ||
155 | src->convert_rate = 0; | ||
156 | if (fe->dai_link->dynamic) { | ||
157 | int stream = substream->stream; | ||
158 | struct snd_soc_dpcm *dpcm; | ||
159 | struct snd_pcm_hw_params *be_params; | ||
160 | |||
161 | for_each_dpcm_be(fe, stream, dpcm) { | ||
162 | be_params = &dpcm->hw_params; | ||
163 | |||
164 | if (params_rate(fe_params) != params_rate(be_params)) | ||
165 | src->convert_rate = params_rate(be_params); | ||
166 | } | ||
167 | } | ||
168 | |||
169 | return 0; | ||
170 | } | ||
171 | |||
172 | static void rsnd_src_set_convert_rate(struct rsnd_dai_stream *io, | 137 | static void rsnd_src_set_convert_rate(struct rsnd_dai_stream *io, |
173 | struct rsnd_mod *mod) | 138 | struct rsnd_mod *mod) |
174 | { | 139 | { |
@@ -349,9 +314,8 @@ static bool rsnd_src_error_occurred(struct rsnd_mod *mod) | |||
349 | status0 = rsnd_mod_read(mod, SCU_SYS_STATUS0); | 314 | status0 = rsnd_mod_read(mod, SCU_SYS_STATUS0); |
350 | status1 = rsnd_mod_read(mod, SCU_SYS_STATUS1); | 315 | status1 = rsnd_mod_read(mod, SCU_SYS_STATUS1); |
351 | if ((status0 & val0) || (status1 & val1)) { | 316 | if ((status0 & val0) || (status1 & val1)) { |
352 | rsnd_dbg_irq_status(dev, "%s[%d] err status : 0x%08x, 0x%08x\n", | 317 | rsnd_dbg_irq_status(dev, "%s err status : 0x%08x, 0x%08x\n", |
353 | rsnd_mod_name(mod), rsnd_mod_id(mod), | 318 | rsnd_mod_name(mod), status0, status1); |
354 | status0, status1); | ||
355 | 319 | ||
356 | ret = true; | 320 | ret = true; |
357 | } | 321 | } |
@@ -527,16 +491,16 @@ static int rsnd_src_pcm_new(struct rsnd_mod *mod, | |||
527 | } | 491 | } |
528 | 492 | ||
529 | static struct rsnd_mod_ops rsnd_src_ops = { | 493 | static struct rsnd_mod_ops rsnd_src_ops = { |
530 | .name = SRC_NAME, | 494 | .name = SRC_NAME, |
531 | .dma_req = rsnd_src_dma_req, | 495 | .dma_req = rsnd_src_dma_req, |
532 | .probe = rsnd_src_probe_, | 496 | .probe = rsnd_src_probe_, |
533 | .init = rsnd_src_init, | 497 | .init = rsnd_src_init, |
534 | .quit = rsnd_src_quit, | 498 | .quit = rsnd_src_quit, |
535 | .start = rsnd_src_start, | 499 | .start = rsnd_src_start, |
536 | .stop = rsnd_src_stop, | 500 | .stop = rsnd_src_stop, |
537 | .irq = rsnd_src_irq, | 501 | .irq = rsnd_src_irq, |
538 | .hw_params = rsnd_src_hw_params, | 502 | .pcm_new = rsnd_src_pcm_new, |
539 | .pcm_new = rsnd_src_pcm_new, | 503 | .get_status = rsnd_mod_get_status, |
540 | }; | 504 | }; |
541 | 505 | ||
542 | struct rsnd_mod *rsnd_src_mod_get(struct rsnd_priv *priv, int id) | 506 | struct rsnd_mod *rsnd_src_mod_get(struct rsnd_priv *priv, int id) |
@@ -605,8 +569,7 @@ int rsnd_src_probe(struct rsnd_priv *priv) | |||
605 | } | 569 | } |
606 | 570 | ||
607 | ret = rsnd_mod_init(priv, rsnd_mod_get(src), | 571 | ret = rsnd_mod_init(priv, rsnd_mod_get(src), |
608 | &rsnd_src_ops, clk, rsnd_mod_get_status, | 572 | &rsnd_src_ops, clk, RSND_MOD_SRC, i); |
609 | RSND_MOD_SRC, i); | ||
610 | if (ret) { | 573 | if (ret) { |
611 | of_node_put(np); | 574 | of_node_put(np); |
612 | goto rsnd_src_probe_done; | 575 | goto rsnd_src_probe_done; |
diff --git a/sound/soc/sh/rcar/ssi.c b/sound/soc/sh/rcar/ssi.c index 6ec78f3096dd..45ef295743ec 100644 --- a/sound/soc/sh/rcar/ssi.c +++ b/sound/soc/sh/rcar/ssi.c | |||
@@ -99,9 +99,7 @@ struct rsnd_ssi { | |||
99 | /* flags */ | 99 | /* flags */ |
100 | #define RSND_SSI_CLK_PIN_SHARE (1 << 0) | 100 | #define RSND_SSI_CLK_PIN_SHARE (1 << 0) |
101 | #define RSND_SSI_NO_BUSIF (1 << 1) /* SSI+DMA without BUSIF */ | 101 | #define RSND_SSI_NO_BUSIF (1 << 1) /* SSI+DMA without BUSIF */ |
102 | #define RSND_SSI_HDMI0 (1 << 2) /* for HDMI0 */ | 102 | #define RSND_SSI_PROBED (1 << 2) |
103 | #define RSND_SSI_HDMI1 (1 << 3) /* for HDMI1 */ | ||
104 | #define RSND_SSI_PROBED (1 << 4) | ||
105 | 103 | ||
106 | #define for_each_rsnd_ssi(pos, priv, i) \ | 104 | #define for_each_rsnd_ssi(pos, priv, i) \ |
107 | for (i = 0; \ | 105 | for (i = 0; \ |
@@ -119,19 +117,7 @@ struct rsnd_ssi { | |||
119 | (rsnd_ssi_run_mods(io) & (1 << rsnd_mod_id(mod))) | 117 | (rsnd_ssi_run_mods(io) & (1 << rsnd_mod_id(mod))) |
120 | #define rsnd_ssi_can_output_clk(mod) (!__rsnd_ssi_is_pin_sharing(mod)) | 118 | #define rsnd_ssi_can_output_clk(mod) (!__rsnd_ssi_is_pin_sharing(mod)) |
121 | 119 | ||
122 | int rsnd_ssi_hdmi_port(struct rsnd_dai_stream *io) | 120 | static int rsnd_ssi_is_dma_mode(struct rsnd_mod *mod); |
123 | { | ||
124 | struct rsnd_mod *mod = rsnd_io_to_mod_ssi(io); | ||
125 | struct rsnd_ssi *ssi = rsnd_mod_to_ssi(mod); | ||
126 | |||
127 | if (rsnd_flags_has(ssi, RSND_SSI_HDMI0)) | ||
128 | return RSND_SSI_HDMI_PORT0; | ||
129 | |||
130 | if (rsnd_flags_has(ssi, RSND_SSI_HDMI1)) | ||
131 | return RSND_SSI_HDMI_PORT1; | ||
132 | |||
133 | return 0; | ||
134 | } | ||
135 | 121 | ||
136 | int rsnd_ssi_use_busif(struct rsnd_dai_stream *io) | 122 | int rsnd_ssi_use_busif(struct rsnd_dai_stream *io) |
137 | { | 123 | { |
@@ -150,11 +136,6 @@ int rsnd_ssi_use_busif(struct rsnd_dai_stream *io) | |||
150 | return use_busif; | 136 | return use_busif; |
151 | } | 137 | } |
152 | 138 | ||
153 | int rsnd_ssi_get_busif(struct rsnd_dai_stream *io) | ||
154 | { | ||
155 | return 0; /* BUSIF0 only for now */ | ||
156 | } | ||
157 | |||
158 | static void rsnd_ssi_status_clear(struct rsnd_mod *mod) | 139 | static void rsnd_ssi_status_clear(struct rsnd_mod *mod) |
159 | { | 140 | { |
160 | rsnd_mod_write(mod, SSISR, 0); | 141 | rsnd_mod_write(mod, SSISR, 0); |
@@ -181,8 +162,7 @@ static void rsnd_ssi_status_check(struct rsnd_mod *mod, | |||
181 | udelay(5); | 162 | udelay(5); |
182 | } | 163 | } |
183 | 164 | ||
184 | dev_warn(dev, "%s[%d] status check failed\n", | 165 | dev_warn(dev, "%s status check failed\n", rsnd_mod_name(mod)); |
185 | rsnd_mod_name(mod), rsnd_mod_id(mod)); | ||
186 | } | 166 | } |
187 | 167 | ||
188 | static u32 rsnd_ssi_multi_slaves(struct rsnd_dai_stream *io) | 168 | static u32 rsnd_ssi_multi_slaves(struct rsnd_dai_stream *io) |
@@ -224,7 +204,7 @@ static u32 rsnd_ssi_run_mods(struct rsnd_dai_stream *io) | |||
224 | 204 | ||
225 | u32 rsnd_ssi_multi_slaves_runtime(struct rsnd_dai_stream *io) | 205 | u32 rsnd_ssi_multi_slaves_runtime(struct rsnd_dai_stream *io) |
226 | { | 206 | { |
227 | if (rsnd_runtime_is_ssi_multi(io)) | 207 | if (rsnd_runtime_is_multi_ssi(io)) |
228 | return rsnd_ssi_multi_slaves(io); | 208 | return rsnd_ssi_multi_slaves(io); |
229 | 209 | ||
230 | return 0; | 210 | return 0; |
@@ -320,6 +300,9 @@ static int rsnd_ssi_master_clk_start(struct rsnd_mod *mod, | |||
320 | return 0; | 300 | return 0; |
321 | } | 301 | } |
322 | 302 | ||
303 | if (rsnd_runtime_is_tdm_split(io)) | ||
304 | chan = rsnd_io_converted_chan(io); | ||
305 | |||
323 | main_rate = rsnd_ssi_clk_query(rdai, rate, chan, &idx); | 306 | main_rate = rsnd_ssi_clk_query(rdai, rate, chan, &idx); |
324 | if (!main_rate) { | 307 | if (!main_rate) { |
325 | dev_err(dev, "unsupported clock rate\n"); | 308 | dev_err(dev, "unsupported clock rate\n"); |
@@ -346,9 +329,8 @@ static int rsnd_ssi_master_clk_start(struct rsnd_mod *mod, | |||
346 | ssi->rate = rate; | 329 | ssi->rate = rate; |
347 | ssi->chan = chan; | 330 | ssi->chan = chan; |
348 | 331 | ||
349 | dev_dbg(dev, "%s[%d] outputs %u Hz\n", | 332 | dev_dbg(dev, "%s outputs %d chan %u Hz\n", |
350 | rsnd_mod_name(mod), | 333 | rsnd_mod_name(mod), chan, rate); |
351 | rsnd_mod_id(mod), rate); | ||
352 | 334 | ||
353 | return 0; | 335 | return 0; |
354 | } | 336 | } |
@@ -379,14 +361,23 @@ static void rsnd_ssi_config_init(struct rsnd_mod *mod, | |||
379 | struct rsnd_dai_stream *io) | 361 | struct rsnd_dai_stream *io) |
380 | { | 362 | { |
381 | struct rsnd_dai *rdai = rsnd_io_to_rdai(io); | 363 | struct rsnd_dai *rdai = rsnd_io_to_rdai(io); |
364 | struct rsnd_priv *priv = rsnd_rdai_to_priv(rdai); | ||
365 | struct device *dev = rsnd_priv_to_dev(priv); | ||
382 | struct snd_pcm_runtime *runtime = rsnd_io_to_runtime(io); | 366 | struct snd_pcm_runtime *runtime = rsnd_io_to_runtime(io); |
383 | struct rsnd_ssi *ssi = rsnd_mod_to_ssi(mod); | 367 | struct rsnd_ssi *ssi = rsnd_mod_to_ssi(mod); |
384 | u32 cr_own = ssi->cr_own; | 368 | u32 cr_own = ssi->cr_own; |
385 | u32 cr_mode = ssi->cr_mode; | 369 | u32 cr_mode = ssi->cr_mode; |
386 | u32 wsr = ssi->wsr; | 370 | u32 wsr = ssi->wsr; |
387 | int is_tdm; | 371 | int width; |
372 | int is_tdm, is_tdm_split; | ||
373 | |||
374 | is_tdm = rsnd_runtime_is_tdm(io); | ||
375 | is_tdm_split = rsnd_runtime_is_tdm_split(io); | ||
388 | 376 | ||
389 | is_tdm = rsnd_runtime_is_ssi_tdm(io); | 377 | if (is_tdm) |
378 | dev_dbg(dev, "TDM mode\n"); | ||
379 | if (is_tdm_split) | ||
380 | dev_dbg(dev, "TDM Split mode\n"); | ||
390 | 381 | ||
391 | cr_own |= FORCE | rsnd_rdai_width_to_swl(rdai); | 382 | cr_own |= FORCE | rsnd_rdai_width_to_swl(rdai); |
392 | 383 | ||
@@ -405,7 +396,7 @@ static void rsnd_ssi_config_init(struct rsnd_mod *mod, | |||
405 | * rsnd_ssiu_init_gen2() | 396 | * rsnd_ssiu_init_gen2() |
406 | */ | 397 | */ |
407 | wsr = ssi->wsr; | 398 | wsr = ssi->wsr; |
408 | if (is_tdm) { | 399 | if (is_tdm || is_tdm_split) { |
409 | wsr |= WS_MODE; | 400 | wsr |= WS_MODE; |
410 | cr_own |= CHNL_8; | 401 | cr_own |= CHNL_8; |
411 | } | 402 | } |
@@ -421,7 +412,18 @@ static void rsnd_ssi_config_init(struct rsnd_mod *mod, | |||
421 | cr_own |= TRMD; | 412 | cr_own |= TRMD; |
422 | 413 | ||
423 | cr_own &= ~DWL_MASK; | 414 | cr_own &= ~DWL_MASK; |
424 | switch (snd_pcm_format_width(runtime->format)) { | 415 | width = snd_pcm_format_width(runtime->format); |
416 | if (is_tdm_split) { | ||
417 | /* | ||
418 | * The SWL and DWL bits in SSICR should be fixed at 32-bit | ||
419 | * setting when TDM split mode. | ||
420 | * see datasheet | ||
421 | * Operation :: TDM Format Split Function (TDM Split Mode) | ||
422 | */ | ||
423 | width = 32; | ||
424 | } | ||
425 | |||
426 | switch (width) { | ||
425 | case 8: | 427 | case 8: |
426 | cr_own |= DWL_8; | 428 | cr_own |= DWL_8; |
427 | break; | 429 | break; |
@@ -431,6 +433,9 @@ static void rsnd_ssi_config_init(struct rsnd_mod *mod, | |||
431 | case 24: | 433 | case 24: |
432 | cr_own |= DWL_24; | 434 | cr_own |= DWL_24; |
433 | break; | 435 | break; |
436 | case 32: | ||
437 | cr_own |= DWL_32; | ||
438 | break; | ||
434 | } | 439 | } |
435 | 440 | ||
436 | if (rsnd_ssi_is_dma_mode(mod)) { | 441 | if (rsnd_ssi_is_dma_mode(mod)) { |
@@ -494,8 +499,7 @@ static int rsnd_ssi_quit(struct rsnd_mod *mod, | |||
494 | return 0; | 499 | return 0; |
495 | 500 | ||
496 | if (!ssi->usrcnt) { | 501 | if (!ssi->usrcnt) { |
497 | dev_err(dev, "%s[%d] usrcnt error\n", | 502 | dev_err(dev, "%s usrcnt error\n", rsnd_mod_name(mod)); |
498 | rsnd_mod_name(mod), rsnd_mod_id(mod)); | ||
499 | return -EIO; | 503 | return -EIO; |
500 | } | 504 | } |
501 | 505 | ||
@@ -654,8 +658,8 @@ static void __rsnd_ssi_interrupt(struct rsnd_mod *mod, | |||
654 | 658 | ||
655 | /* DMA only */ | 659 | /* DMA only */ |
656 | if (is_dma && (status & (UIRQ | OIRQ))) { | 660 | if (is_dma && (status & (UIRQ | OIRQ))) { |
657 | rsnd_dbg_irq_status(dev, "%s[%d] err status : 0x%08x\n", | 661 | rsnd_dbg_irq_status(dev, "%s err status : 0x%08x\n", |
658 | rsnd_mod_name(mod), rsnd_mod_id(mod), status); | 662 | rsnd_mod_name(mod), status); |
659 | 663 | ||
660 | stop = true; | 664 | stop = true; |
661 | } | 665 | } |
@@ -681,6 +685,41 @@ static irqreturn_t rsnd_ssi_interrupt(int irq, void *data) | |||
681 | return IRQ_HANDLED; | 685 | return IRQ_HANDLED; |
682 | } | 686 | } |
683 | 687 | ||
688 | static u32 *rsnd_ssi_get_status(struct rsnd_mod *mod, | ||
689 | struct rsnd_dai_stream *io, | ||
690 | enum rsnd_mod_type type) | ||
691 | { | ||
692 | /* | ||
693 | * SSIP (= SSI parent) needs to be special, otherwise, | ||
694 | * 2nd SSI might doesn't start. see also rsnd_mod_call() | ||
695 | * | ||
696 | * We can't include parent SSI status on SSI, because we don't know | ||
697 | * how many SSI requests parent SSI. Thus, it is localed on "io" now. | ||
698 | * ex) trouble case | ||
699 | * Playback: SSI0 | ||
700 | * Capture : SSI1 (needs SSI0) | ||
701 | * | ||
702 | * 1) start Capture -> SSI0/SSI1 are started. | ||
703 | * 2) start Playback -> SSI0 doesn't work, because it is already | ||
704 | * marked as "started" on 1) | ||
705 | * | ||
706 | * OTOH, using each mod's status is good for MUX case. | ||
707 | * It doesn't need to start in 2nd start | ||
708 | * ex) | ||
709 | * IO-0: SRC0 -> CTU1 -+-> MUX -> DVC -> SSIU -> SSI0 | ||
710 | * | | ||
711 | * IO-1: SRC1 -> CTU2 -+ | ||
712 | * | ||
713 | * 1) start IO-0 -> start SSI0 | ||
714 | * 2) start IO-1 -> SSI0 doesn't need to start, because it is | ||
715 | * already started on 1) | ||
716 | */ | ||
717 | if (type == RSND_MOD_SSIP) | ||
718 | return &io->parent_ssi_status; | ||
719 | |||
720 | return rsnd_mod_get_status(mod, io, type); | ||
721 | } | ||
722 | |||
684 | /* | 723 | /* |
685 | * SSI PIO | 724 | * SSI PIO |
686 | */ | 725 | */ |
@@ -730,7 +769,7 @@ static int rsnd_ssi_common_probe(struct rsnd_mod *mod, | |||
730 | { | 769 | { |
731 | struct device *dev = rsnd_priv_to_dev(priv); | 770 | struct device *dev = rsnd_priv_to_dev(priv); |
732 | struct rsnd_ssi *ssi = rsnd_mod_to_ssi(mod); | 771 | struct rsnd_ssi *ssi = rsnd_mod_to_ssi(mod); |
733 | int ret; | 772 | int ret = 0; |
734 | 773 | ||
735 | /* | 774 | /* |
736 | * SSIP/SSIU/IRQ are not needed on | 775 | * SSIP/SSIU/IRQ are not needed on |
@@ -744,10 +783,6 @@ static int rsnd_ssi_common_probe(struct rsnd_mod *mod, | |||
744 | * see rsnd_ssi_pcm_new() | 783 | * see rsnd_ssi_pcm_new() |
745 | */ | 784 | */ |
746 | 785 | ||
747 | ret = rsnd_ssiu_attach(io, mod); | ||
748 | if (ret < 0) | ||
749 | return ret; | ||
750 | |||
751 | /* | 786 | /* |
752 | * SSI might be called again as PIO fallback | 787 | * SSI might be called again as PIO fallback |
753 | * It is easy to manual handling for IRQ request/free | 788 | * It is easy to manual handling for IRQ request/free |
@@ -876,18 +911,19 @@ static int rsnd_ssi_prepare(struct rsnd_mod *mod, | |||
876 | } | 911 | } |
877 | 912 | ||
878 | static struct rsnd_mod_ops rsnd_ssi_pio_ops = { | 913 | static struct rsnd_mod_ops rsnd_ssi_pio_ops = { |
879 | .name = SSI_NAME, | 914 | .name = SSI_NAME, |
880 | .probe = rsnd_ssi_common_probe, | 915 | .probe = rsnd_ssi_common_probe, |
881 | .remove = rsnd_ssi_common_remove, | 916 | .remove = rsnd_ssi_common_remove, |
882 | .init = rsnd_ssi_pio_init, | 917 | .init = rsnd_ssi_pio_init, |
883 | .quit = rsnd_ssi_quit, | 918 | .quit = rsnd_ssi_quit, |
884 | .start = rsnd_ssi_start, | 919 | .start = rsnd_ssi_start, |
885 | .stop = rsnd_ssi_stop, | 920 | .stop = rsnd_ssi_stop, |
886 | .irq = rsnd_ssi_irq, | 921 | .irq = rsnd_ssi_irq, |
887 | .pointer = rsnd_ssi_pio_pointer, | 922 | .pointer = rsnd_ssi_pio_pointer, |
888 | .pcm_new = rsnd_ssi_pcm_new, | 923 | .pcm_new = rsnd_ssi_pcm_new, |
889 | .hw_params = rsnd_ssi_hw_params, | 924 | .hw_params = rsnd_ssi_hw_params, |
890 | .prepare = rsnd_ssi_prepare, | 925 | .prepare = rsnd_ssi_prepare, |
926 | .get_status = rsnd_ssi_get_status, | ||
891 | }; | 927 | }; |
892 | 928 | ||
893 | static int rsnd_ssi_dma_probe(struct rsnd_mod *mod, | 929 | static int rsnd_ssi_dma_probe(struct rsnd_mod *mod, |
@@ -928,8 +964,7 @@ static int rsnd_ssi_fallback(struct rsnd_mod *mod, | |||
928 | */ | 964 | */ |
929 | mod->ops = &rsnd_ssi_pio_ops; | 965 | mod->ops = &rsnd_ssi_pio_ops; |
930 | 966 | ||
931 | dev_info(dev, "%s[%d] fallback to PIO mode\n", | 967 | dev_info(dev, "%s fallback to PIO mode\n", rsnd_mod_name(mod)); |
932 | rsnd_mod_name(mod), rsnd_mod_id(mod)); | ||
933 | 968 | ||
934 | return 0; | 969 | return 0; |
935 | } | 970 | } |
@@ -941,6 +976,17 @@ static struct dma_chan *rsnd_ssi_dma_req(struct rsnd_dai_stream *io, | |||
941 | int is_play = rsnd_io_is_play(io); | 976 | int is_play = rsnd_io_is_play(io); |
942 | char *name; | 977 | char *name; |
943 | 978 | ||
979 | /* | ||
980 | * It should use "rcar_sound,ssiu" on DT. | ||
981 | * But, we need to keep compatibility for old version. | ||
982 | * | ||
983 | * If it has "rcar_sound.ssiu", it will be used. | ||
984 | * If not, "rcar_sound.ssi" will be used. | ||
985 | * see | ||
986 | * rsnd_ssiu_dma_req() | ||
987 | * rsnd_dma_of_path() | ||
988 | */ | ||
989 | |||
944 | if (rsnd_ssi_use_busif(io)) | 990 | if (rsnd_ssi_use_busif(io)) |
945 | name = is_play ? "rxu" : "txu"; | 991 | name = is_play ? "rxu" : "txu"; |
946 | else | 992 | else |
@@ -951,27 +997,27 @@ static struct dma_chan *rsnd_ssi_dma_req(struct rsnd_dai_stream *io, | |||
951 | } | 997 | } |
952 | 998 | ||
953 | static struct rsnd_mod_ops rsnd_ssi_dma_ops = { | 999 | static struct rsnd_mod_ops rsnd_ssi_dma_ops = { |
954 | .name = SSI_NAME, | 1000 | .name = SSI_NAME, |
955 | .dma_req = rsnd_ssi_dma_req, | 1001 | .dma_req = rsnd_ssi_dma_req, |
956 | .probe = rsnd_ssi_dma_probe, | 1002 | .probe = rsnd_ssi_dma_probe, |
957 | .remove = rsnd_ssi_common_remove, | 1003 | .remove = rsnd_ssi_common_remove, |
958 | .init = rsnd_ssi_init, | 1004 | .init = rsnd_ssi_init, |
959 | .quit = rsnd_ssi_quit, | 1005 | .quit = rsnd_ssi_quit, |
960 | .start = rsnd_ssi_start, | 1006 | .start = rsnd_ssi_start, |
961 | .stop = rsnd_ssi_stop, | 1007 | .stop = rsnd_ssi_stop, |
962 | .irq = rsnd_ssi_irq, | 1008 | .irq = rsnd_ssi_irq, |
963 | .pcm_new = rsnd_ssi_pcm_new, | 1009 | .pcm_new = rsnd_ssi_pcm_new, |
964 | .fallback = rsnd_ssi_fallback, | 1010 | .fallback = rsnd_ssi_fallback, |
965 | .hw_params = rsnd_ssi_hw_params, | 1011 | .hw_params = rsnd_ssi_hw_params, |
966 | .prepare = rsnd_ssi_prepare, | 1012 | .prepare = rsnd_ssi_prepare, |
1013 | .get_status = rsnd_ssi_get_status, | ||
967 | }; | 1014 | }; |
968 | 1015 | ||
969 | int rsnd_ssi_is_dma_mode(struct rsnd_mod *mod) | 1016 | static int rsnd_ssi_is_dma_mode(struct rsnd_mod *mod) |
970 | { | 1017 | { |
971 | return mod->ops == &rsnd_ssi_dma_ops; | 1018 | return mod->ops == &rsnd_ssi_dma_ops; |
972 | } | 1019 | } |
973 | 1020 | ||
974 | |||
975 | /* | 1021 | /* |
976 | * ssi mod function | 1022 | * ssi mod function |
977 | */ | 1023 | */ |
@@ -1027,54 +1073,6 @@ void rsnd_parse_connect_ssi(struct rsnd_dai *rdai, | |||
1027 | of_node_put(node); | 1073 | of_node_put(node); |
1028 | } | 1074 | } |
1029 | 1075 | ||
1030 | static void __rsnd_ssi_parse_hdmi_connection(struct rsnd_priv *priv, | ||
1031 | struct rsnd_dai_stream *io, | ||
1032 | struct device_node *remote_ep) | ||
1033 | { | ||
1034 | struct device *dev = rsnd_priv_to_dev(priv); | ||
1035 | struct rsnd_mod *mod = rsnd_io_to_mod_ssi(io); | ||
1036 | struct rsnd_ssi *ssi; | ||
1037 | struct device_node *remote_node = of_graph_get_port_parent(remote_ep); | ||
1038 | |||
1039 | /* support Gen3 only */ | ||
1040 | if (!rsnd_is_gen3(priv)) | ||
1041 | return; | ||
1042 | |||
1043 | if (!mod) | ||
1044 | return; | ||
1045 | |||
1046 | ssi = rsnd_mod_to_ssi(mod); | ||
1047 | |||
1048 | /* HDMI0 */ | ||
1049 | if (strstr(remote_node->full_name, "hdmi@fead0000")) { | ||
1050 | rsnd_flags_set(ssi, RSND_SSI_HDMI0); | ||
1051 | dev_dbg(dev, "%s[%d] connected to HDMI0\n", | ||
1052 | rsnd_mod_name(mod), rsnd_mod_id(mod)); | ||
1053 | } | ||
1054 | |||
1055 | /* HDMI1 */ | ||
1056 | if (strstr(remote_node->full_name, "hdmi@feae0000")) { | ||
1057 | rsnd_flags_set(ssi, RSND_SSI_HDMI1); | ||
1058 | dev_dbg(dev, "%s[%d] connected to HDMI1\n", | ||
1059 | rsnd_mod_name(mod), rsnd_mod_id(mod)); | ||
1060 | } | ||
1061 | } | ||
1062 | |||
1063 | void rsnd_ssi_parse_hdmi_connection(struct rsnd_priv *priv, | ||
1064 | struct device_node *endpoint, | ||
1065 | int dai_i) | ||
1066 | { | ||
1067 | struct rsnd_dai *rdai = rsnd_rdai_get(priv, dai_i); | ||
1068 | struct device_node *remote_ep; | ||
1069 | |||
1070 | remote_ep = of_graph_get_remote_endpoint(endpoint); | ||
1071 | if (!remote_ep) | ||
1072 | return; | ||
1073 | |||
1074 | __rsnd_ssi_parse_hdmi_connection(priv, &rdai->playback, remote_ep); | ||
1075 | __rsnd_ssi_parse_hdmi_connection(priv, &rdai->capture, remote_ep); | ||
1076 | } | ||
1077 | |||
1078 | struct rsnd_mod *rsnd_ssi_mod_get(struct rsnd_priv *priv, int id) | 1076 | struct rsnd_mod *rsnd_ssi_mod_get(struct rsnd_priv *priv, int id) |
1079 | { | 1077 | { |
1080 | if (WARN_ON(id < 0 || id >= rsnd_ssi_nr(priv))) | 1078 | if (WARN_ON(id < 0 || id >= rsnd_ssi_nr(priv))) |
@@ -1091,41 +1089,6 @@ int __rsnd_ssi_is_pin_sharing(struct rsnd_mod *mod) | |||
1091 | return !!(rsnd_flags_has(rsnd_mod_to_ssi(mod), RSND_SSI_CLK_PIN_SHARE)); | 1089 | return !!(rsnd_flags_has(rsnd_mod_to_ssi(mod), RSND_SSI_CLK_PIN_SHARE)); |
1092 | } | 1090 | } |
1093 | 1091 | ||
1094 | static u32 *rsnd_ssi_get_status(struct rsnd_dai_stream *io, | ||
1095 | struct rsnd_mod *mod, | ||
1096 | enum rsnd_mod_type type) | ||
1097 | { | ||
1098 | /* | ||
1099 | * SSIP (= SSI parent) needs to be special, otherwise, | ||
1100 | * 2nd SSI might doesn't start. see also rsnd_mod_call() | ||
1101 | * | ||
1102 | * We can't include parent SSI status on SSI, because we don't know | ||
1103 | * how many SSI requests parent SSI. Thus, it is localed on "io" now. | ||
1104 | * ex) trouble case | ||
1105 | * Playback: SSI0 | ||
1106 | * Capture : SSI1 (needs SSI0) | ||
1107 | * | ||
1108 | * 1) start Capture -> SSI0/SSI1 are started. | ||
1109 | * 2) start Playback -> SSI0 doesn't work, because it is already | ||
1110 | * marked as "started" on 1) | ||
1111 | * | ||
1112 | * OTOH, using each mod's status is good for MUX case. | ||
1113 | * It doesn't need to start in 2nd start | ||
1114 | * ex) | ||
1115 | * IO-0: SRC0 -> CTU1 -+-> MUX -> DVC -> SSIU -> SSI0 | ||
1116 | * | | ||
1117 | * IO-1: SRC1 -> CTU2 -+ | ||
1118 | * | ||
1119 | * 1) start IO-0 -> start SSI0 | ||
1120 | * 2) start IO-1 -> SSI0 doesn't need to start, because it is | ||
1121 | * already started on 1) | ||
1122 | */ | ||
1123 | if (type == RSND_MOD_SSIP) | ||
1124 | return &io->parent_ssi_status; | ||
1125 | |||
1126 | return rsnd_mod_get_status(io, mod, type); | ||
1127 | } | ||
1128 | |||
1129 | int rsnd_ssi_probe(struct rsnd_priv *priv) | 1092 | int rsnd_ssi_probe(struct rsnd_priv *priv) |
1130 | { | 1093 | { |
1131 | struct device_node *node; | 1094 | struct device_node *node; |
@@ -1192,7 +1155,7 @@ int rsnd_ssi_probe(struct rsnd_priv *priv) | |||
1192 | ops = &rsnd_ssi_dma_ops; | 1155 | ops = &rsnd_ssi_dma_ops; |
1193 | 1156 | ||
1194 | ret = rsnd_mod_init(priv, rsnd_mod_get(ssi), ops, clk, | 1157 | ret = rsnd_mod_init(priv, rsnd_mod_get(ssi), ops, clk, |
1195 | rsnd_ssi_get_status, RSND_MOD_SSI, i); | 1158 | RSND_MOD_SSI, i); |
1196 | if (ret) { | 1159 | if (ret) { |
1197 | of_node_put(np); | 1160 | of_node_put(np); |
1198 | goto rsnd_ssi_probe_done; | 1161 | goto rsnd_ssi_probe_done; |
diff --git a/sound/soc/sh/rcar/ssiu.c b/sound/soc/sh/rcar/ssiu.c index 39b67643b5dc..c5934adcfd01 100644 --- a/sound/soc/sh/rcar/ssiu.c +++ b/sound/soc/sh/rcar/ssiu.c | |||
@@ -12,8 +12,14 @@ struct rsnd_ssiu { | |||
12 | struct rsnd_mod mod; | 12 | struct rsnd_mod mod; |
13 | u32 busif_status[8]; /* for BUSIF0 - BUSIF7 */ | 13 | u32 busif_status[8]; /* for BUSIF0 - BUSIF7 */ |
14 | unsigned int usrcnt; | 14 | unsigned int usrcnt; |
15 | int id; | ||
16 | int id_sub; | ||
15 | }; | 17 | }; |
16 | 18 | ||
19 | /* SSI_MODE */ | ||
20 | #define TDM_EXT (1 << 0) | ||
21 | #define TDM_SPLIT (1 << 8) | ||
22 | |||
17 | #define rsnd_ssiu_nr(priv) ((priv)->ssiu_nr) | 23 | #define rsnd_ssiu_nr(priv) ((priv)->ssiu_nr) |
18 | #define rsnd_mod_to_ssiu(_mod) container_of((_mod), struct rsnd_ssiu, mod) | 24 | #define rsnd_mod_to_ssiu(_mod) container_of((_mod), struct rsnd_ssiu, mod) |
19 | #define for_each_rsnd_ssiu(pos, priv, i) \ | 25 | #define for_each_rsnd_ssiu(pos, priv, i) \ |
@@ -22,6 +28,33 @@ struct rsnd_ssiu { | |||
22 | ((pos) = ((struct rsnd_ssiu *)(priv)->ssiu + i)); \ | 28 | ((pos) = ((struct rsnd_ssiu *)(priv)->ssiu + i)); \ |
23 | i++) | 29 | i++) |
24 | 30 | ||
31 | /* | ||
32 | * SSI Gen2 Gen3 | ||
33 | * 0 BUSIF0-3 BUSIF0-7 | ||
34 | * 1 BUSIF0-3 BUSIF0-7 | ||
35 | * 2 BUSIF0-3 BUSIF0-7 | ||
36 | * 3 BUSIF0 BUSIF0-7 | ||
37 | * 4 BUSIF0 BUSIF0-7 | ||
38 | * 5 BUSIF0 BUSIF0 | ||
39 | * 6 BUSIF0 BUSIF0 | ||
40 | * 7 BUSIF0 BUSIF0 | ||
41 | * 8 BUSIF0 BUSIF0 | ||
42 | * 9 BUSIF0-3 BUSIF0-7 | ||
43 | * total 22 52 | ||
44 | */ | ||
45 | static const int gen2_id[] = { 0, 4, 8, 12, 13, 14, 15, 16, 17, 18 }; | ||
46 | static const int gen3_id[] = { 0, 8, 16, 24, 32, 40, 41, 42, 43, 44 }; | ||
47 | |||
48 | static u32 *rsnd_ssiu_get_status(struct rsnd_mod *mod, | ||
49 | struct rsnd_dai_stream *io, | ||
50 | enum rsnd_mod_type type) | ||
51 | { | ||
52 | struct rsnd_ssiu *ssiu = rsnd_mod_to_ssiu(mod); | ||
53 | int busif = rsnd_mod_id_sub(mod); | ||
54 | |||
55 | return &ssiu->busif_status[busif]; | ||
56 | } | ||
57 | |||
25 | static int rsnd_ssiu_init(struct rsnd_mod *mod, | 58 | static int rsnd_ssiu_init(struct rsnd_mod *mod, |
26 | struct rsnd_dai_stream *io, | 59 | struct rsnd_dai_stream *io, |
27 | struct rsnd_priv *priv) | 60 | struct rsnd_priv *priv) |
@@ -32,6 +65,7 @@ static int rsnd_ssiu_init(struct rsnd_mod *mod, | |||
32 | int id = rsnd_mod_id(mod); | 65 | int id = rsnd_mod_id(mod); |
33 | u32 mask1, val1; | 66 | u32 mask1, val1; |
34 | u32 mask2, val2; | 67 | u32 mask2, val2; |
68 | int i; | ||
35 | 69 | ||
36 | /* clear status */ | 70 | /* clear status */ |
37 | switch (id) { | 71 | switch (id) { |
@@ -40,16 +74,12 @@ static int rsnd_ssiu_init(struct rsnd_mod *mod, | |||
40 | case 2: | 74 | case 2: |
41 | case 3: | 75 | case 3: |
42 | case 4: | 76 | case 4: |
43 | rsnd_mod_write(mod, SSI_SYS_STATUS0, 0xf << (id * 4)); | 77 | for (i = 0; i < 4; i++) |
44 | rsnd_mod_write(mod, SSI_SYS_STATUS2, 0xf << (id * 4)); | 78 | rsnd_mod_write(mod, SSI_SYS_STATUS(i * 2), 0xf << (id * 4)); |
45 | rsnd_mod_write(mod, SSI_SYS_STATUS4, 0xf << (id * 4)); | ||
46 | rsnd_mod_write(mod, SSI_SYS_STATUS6, 0xf << (id * 4)); | ||
47 | break; | 79 | break; |
48 | case 9: | 80 | case 9: |
49 | rsnd_mod_write(mod, SSI_SYS_STATUS1, 0xf << 4); | 81 | for (i = 0; i < 4; i++) |
50 | rsnd_mod_write(mod, SSI_SYS_STATUS3, 0xf << 4); | 82 | rsnd_mod_write(mod, SSI_SYS_STATUS((i * 2) + 1), 0xf << (id * 4)); |
51 | rsnd_mod_write(mod, SSI_SYS_STATUS5, 0xf << 4); | ||
52 | rsnd_mod_write(mod, SSI_SYS_STATUS7, 0xf << 4); | ||
53 | break; | 83 | break; |
54 | } | 84 | } |
55 | 85 | ||
@@ -115,8 +145,9 @@ static int rsnd_ssiu_init(struct rsnd_mod *mod, | |||
115 | } | 145 | } |
116 | 146 | ||
117 | static struct rsnd_mod_ops rsnd_ssiu_ops_gen1 = { | 147 | static struct rsnd_mod_ops rsnd_ssiu_ops_gen1 = { |
118 | .name = SSIU_NAME, | 148 | .name = SSIU_NAME, |
119 | .init = rsnd_ssiu_init, | 149 | .init = rsnd_ssiu_init, |
150 | .get_status = rsnd_ssiu_get_status, | ||
120 | }; | 151 | }; |
121 | 152 | ||
122 | static int rsnd_ssiu_init_gen2(struct rsnd_mod *mod, | 153 | static int rsnd_ssiu_init_gen2(struct rsnd_mod *mod, |
@@ -124,7 +155,8 @@ static int rsnd_ssiu_init_gen2(struct rsnd_mod *mod, | |||
124 | struct rsnd_priv *priv) | 155 | struct rsnd_priv *priv) |
125 | { | 156 | { |
126 | struct rsnd_ssiu *ssiu = rsnd_mod_to_ssiu(mod); | 157 | struct rsnd_ssiu *ssiu = rsnd_mod_to_ssiu(mod); |
127 | int hdmi = rsnd_ssi_hdmi_port(io); | 158 | u32 has_hdmi0 = rsnd_flags_has(io, RSND_STREAM_HDMI0); |
159 | u32 has_hdmi1 = rsnd_flags_has(io, RSND_STREAM_HDMI1); | ||
128 | int ret; | 160 | int ret; |
129 | u32 mode = 0; | 161 | u32 mode = 0; |
130 | 162 | ||
@@ -134,20 +166,21 @@ static int rsnd_ssiu_init_gen2(struct rsnd_mod *mod, | |||
134 | 166 | ||
135 | ssiu->usrcnt++; | 167 | ssiu->usrcnt++; |
136 | 168 | ||
137 | if (rsnd_runtime_is_ssi_tdm(io)) { | 169 | /* |
138 | /* | 170 | * TDM Extend/Split Mode |
139 | * TDM Extend Mode | 171 | * see |
140 | * see | 172 | * rsnd_ssi_config_init() |
141 | * rsnd_ssi_config_init() | 173 | */ |
142 | */ | 174 | if (rsnd_runtime_is_tdm(io)) |
143 | mode = 0x1; | 175 | mode = TDM_EXT; |
144 | } | 176 | else if (rsnd_runtime_is_tdm_split(io)) |
177 | mode = TDM_SPLIT; | ||
145 | 178 | ||
146 | rsnd_mod_write(mod, SSI_MODE, mode); | 179 | rsnd_mod_write(mod, SSI_MODE, mode); |
147 | 180 | ||
148 | if (rsnd_ssi_use_busif(io)) { | 181 | if (rsnd_ssi_use_busif(io)) { |
149 | int id = rsnd_mod_id(mod); | 182 | int id = rsnd_mod_id(mod); |
150 | int busif = rsnd_ssi_get_busif(io); | 183 | int busif = rsnd_mod_id_sub(mod); |
151 | 184 | ||
152 | /* | 185 | /* |
153 | * FIXME | 186 | * FIXME |
@@ -162,46 +195,18 @@ static int rsnd_ssiu_init_gen2(struct rsnd_mod *mod, | |||
162 | id, busif); | 195 | id, busif); |
163 | } | 196 | } |
164 | 197 | ||
165 | #define RSND_WRITE_BUSIF(i) \ | 198 | rsnd_mod_write(mod, SSI_BUSIF_ADINR(busif), |
166 | rsnd_mod_write(mod, SSI_BUSIF##i##_ADINR, \ | 199 | rsnd_get_adinr_bit(mod, io) | |
167 | rsnd_get_adinr_bit(mod, io) | \ | 200 | (rsnd_io_is_play(io) ? |
168 | (rsnd_io_is_play(io) ? \ | 201 | rsnd_runtime_channel_after_ctu(io) : |
169 | rsnd_runtime_channel_after_ctu(io) : \ | 202 | rsnd_runtime_channel_original(io))); |
170 | rsnd_runtime_channel_original(io))); \ | 203 | rsnd_mod_write(mod, SSI_BUSIF_MODE(busif), |
171 | rsnd_mod_write(mod, SSI_BUSIF##i##_MODE, \ | 204 | rsnd_get_busif_shift(io, mod) | 1); |
172 | rsnd_get_busif_shift(io, mod) | 1); \ | 205 | rsnd_mod_write(mod, SSI_BUSIF_DALIGN(busif), |
173 | rsnd_mod_write(mod, SSI_BUSIF##i##_DALIGN, \ | 206 | rsnd_get_dalign(mod, io)); |
174 | rsnd_get_dalign(mod, io)) | ||
175 | |||
176 | switch (busif) { | ||
177 | case 0: | ||
178 | RSND_WRITE_BUSIF(0); | ||
179 | break; | ||
180 | case 1: | ||
181 | RSND_WRITE_BUSIF(1); | ||
182 | break; | ||
183 | case 2: | ||
184 | RSND_WRITE_BUSIF(2); | ||
185 | break; | ||
186 | case 3: | ||
187 | RSND_WRITE_BUSIF(3); | ||
188 | break; | ||
189 | case 4: | ||
190 | RSND_WRITE_BUSIF(4); | ||
191 | break; | ||
192 | case 5: | ||
193 | RSND_WRITE_BUSIF(5); | ||
194 | break; | ||
195 | case 6: | ||
196 | RSND_WRITE_BUSIF(6); | ||
197 | break; | ||
198 | case 7: | ||
199 | RSND_WRITE_BUSIF(7); | ||
200 | break; | ||
201 | } | ||
202 | } | 207 | } |
203 | 208 | ||
204 | if (hdmi) { | 209 | if (has_hdmi0 || has_hdmi1) { |
205 | enum rsnd_mod_type rsnd_ssi_array[] = { | 210 | enum rsnd_mod_type rsnd_ssi_array[] = { |
206 | RSND_MOD_SSIM1, | 211 | RSND_MOD_SSIM1, |
207 | RSND_MOD_SSIM2, | 212 | RSND_MOD_SSIM2, |
@@ -227,14 +232,10 @@ static int rsnd_ssiu_init_gen2(struct rsnd_mod *mod, | |||
227 | rsnd_mod_id(pos) << shift; | 232 | rsnd_mod_id(pos) << shift; |
228 | } | 233 | } |
229 | 234 | ||
230 | switch (hdmi) { | 235 | if (has_hdmi0) |
231 | case RSND_SSI_HDMI_PORT0: | ||
232 | rsnd_mod_write(mod, HDMI0_SEL, val); | 236 | rsnd_mod_write(mod, HDMI0_SEL, val); |
233 | break; | 237 | if (has_hdmi1) |
234 | case RSND_SSI_HDMI_PORT1: | ||
235 | rsnd_mod_write(mod, HDMI1_SEL, val); | 238 | rsnd_mod_write(mod, HDMI1_SEL, val); |
236 | break; | ||
237 | } | ||
238 | } | 239 | } |
239 | 240 | ||
240 | return 0; | 241 | return 0; |
@@ -244,7 +245,7 @@ static int rsnd_ssiu_start_gen2(struct rsnd_mod *mod, | |||
244 | struct rsnd_dai_stream *io, | 245 | struct rsnd_dai_stream *io, |
245 | struct rsnd_priv *priv) | 246 | struct rsnd_priv *priv) |
246 | { | 247 | { |
247 | int busif = rsnd_ssi_get_busif(io); | 248 | int busif = rsnd_mod_id_sub(mod); |
248 | 249 | ||
249 | if (!rsnd_ssi_use_busif(io)) | 250 | if (!rsnd_ssi_use_busif(io)) |
250 | return 0; | 251 | return 0; |
@@ -262,7 +263,7 @@ static int rsnd_ssiu_stop_gen2(struct rsnd_mod *mod, | |||
262 | struct rsnd_priv *priv) | 263 | struct rsnd_priv *priv) |
263 | { | 264 | { |
264 | struct rsnd_ssiu *ssiu = rsnd_mod_to_ssiu(mod); | 265 | struct rsnd_ssiu *ssiu = rsnd_mod_to_ssiu(mod); |
265 | int busif = rsnd_ssi_get_busif(io); | 266 | int busif = rsnd_mod_id_sub(mod); |
266 | 267 | ||
267 | if (!rsnd_ssi_use_busif(io)) | 268 | if (!rsnd_ssi_use_busif(io)) |
268 | return 0; | 269 | return 0; |
@@ -278,11 +279,53 @@ static int rsnd_ssiu_stop_gen2(struct rsnd_mod *mod, | |||
278 | return 0; | 279 | return 0; |
279 | } | 280 | } |
280 | 281 | ||
282 | static int rsnd_ssiu_id(struct rsnd_mod *mod) | ||
283 | { | ||
284 | struct rsnd_ssiu *ssiu = rsnd_mod_to_ssiu(mod); | ||
285 | |||
286 | /* see rsnd_ssiu_probe() */ | ||
287 | return ssiu->id; | ||
288 | } | ||
289 | |||
290 | static int rsnd_ssiu_id_sub(struct rsnd_mod *mod) | ||
291 | { | ||
292 | struct rsnd_ssiu *ssiu = rsnd_mod_to_ssiu(mod); | ||
293 | |||
294 | /* see rsnd_ssiu_probe() */ | ||
295 | return ssiu->id_sub; | ||
296 | } | ||
297 | |||
298 | static struct dma_chan *rsnd_ssiu_dma_req(struct rsnd_dai_stream *io, | ||
299 | struct rsnd_mod *mod) | ||
300 | { | ||
301 | struct rsnd_priv *priv = rsnd_mod_to_priv(mod); | ||
302 | int is_play = rsnd_io_is_play(io); | ||
303 | char *name; | ||
304 | |||
305 | /* | ||
306 | * It should use "rcar_sound,ssiu" on DT. | ||
307 | * But, we need to keep compatibility for old version. | ||
308 | * | ||
309 | * If it has "rcar_sound.ssiu", it will be used. | ||
310 | * If not, "rcar_sound.ssi" will be used. | ||
311 | * see | ||
312 | * rsnd_ssi_dma_req() | ||
313 | * rsnd_dma_of_path() | ||
314 | */ | ||
315 | |||
316 | name = is_play ? "rx" : "tx"; | ||
317 | |||
318 | return rsnd_dma_request_channel(rsnd_ssiu_of_node(priv), | ||
319 | mod, name); | ||
320 | } | ||
321 | |||
281 | static struct rsnd_mod_ops rsnd_ssiu_ops_gen2 = { | 322 | static struct rsnd_mod_ops rsnd_ssiu_ops_gen2 = { |
282 | .name = SSIU_NAME, | 323 | .name = SSIU_NAME, |
283 | .init = rsnd_ssiu_init_gen2, | 324 | .dma_req = rsnd_ssiu_dma_req, |
284 | .start = rsnd_ssiu_start_gen2, | 325 | .init = rsnd_ssiu_init_gen2, |
285 | .stop = rsnd_ssiu_stop_gen2, | 326 | .start = rsnd_ssiu_start_gen2, |
327 | .stop = rsnd_ssiu_stop_gen2, | ||
328 | .get_status = rsnd_ssiu_get_status, | ||
286 | }; | 329 | }; |
287 | 330 | ||
288 | static struct rsnd_mod *rsnd_ssiu_mod_get(struct rsnd_priv *priv, int id) | 331 | static struct rsnd_mod *rsnd_ssiu_mod_get(struct rsnd_priv *priv, int id) |
@@ -293,36 +336,85 @@ static struct rsnd_mod *rsnd_ssiu_mod_get(struct rsnd_priv *priv, int id) | |||
293 | return rsnd_mod_get((struct rsnd_ssiu *)(priv->ssiu) + id); | 336 | return rsnd_mod_get((struct rsnd_ssiu *)(priv->ssiu) + id); |
294 | } | 337 | } |
295 | 338 | ||
296 | int rsnd_ssiu_attach(struct rsnd_dai_stream *io, | 339 | static void rsnd_parse_connect_ssiu_compatible(struct rsnd_priv *priv, |
297 | struct rsnd_mod *ssi_mod) | 340 | struct rsnd_dai_stream *io) |
298 | { | 341 | { |
299 | struct rsnd_priv *priv = rsnd_io_to_priv(io); | 342 | struct rsnd_mod *ssi_mod = rsnd_io_to_mod_ssi(io); |
300 | struct rsnd_mod *mod = rsnd_ssiu_mod_get(priv, rsnd_mod_id(ssi_mod)); | 343 | struct rsnd_mod *mod; |
344 | struct rsnd_ssiu *ssiu; | ||
345 | int i; | ||
301 | 346 | ||
302 | rsnd_mod_confirm_ssi(ssi_mod); | 347 | if (!ssi_mod) |
348 | return; | ||
303 | 349 | ||
304 | return rsnd_dai_connect(mod, io, mod->type); | 350 | /* select BUSIF0 */ |
351 | for_each_rsnd_ssiu(ssiu, priv, i) { | ||
352 | mod = rsnd_mod_get(ssiu); | ||
353 | |||
354 | if ((rsnd_mod_id(ssi_mod) == rsnd_mod_id(mod)) && | ||
355 | (rsnd_mod_id_sub(mod) == 0)) { | ||
356 | rsnd_dai_connect(mod, io, mod->type); | ||
357 | return; | ||
358 | } | ||
359 | } | ||
305 | } | 360 | } |
306 | 361 | ||
307 | static u32 *rsnd_ssiu_get_status(struct rsnd_dai_stream *io, | 362 | void rsnd_parse_connect_ssiu(struct rsnd_dai *rdai, |
308 | struct rsnd_mod *mod, | 363 | struct device_node *playback, |
309 | enum rsnd_mod_type type) | 364 | struct device_node *capture) |
310 | { | 365 | { |
311 | struct rsnd_ssiu *ssiu = rsnd_mod_to_ssiu(mod); | 366 | struct rsnd_priv *priv = rsnd_rdai_to_priv(rdai); |
312 | int busif = rsnd_ssi_get_busif(io); | 367 | struct device_node *node = rsnd_ssiu_of_node(priv); |
368 | struct device_node *np; | ||
369 | struct rsnd_mod *mod; | ||
370 | struct rsnd_dai_stream *io_p = &rdai->playback; | ||
371 | struct rsnd_dai_stream *io_c = &rdai->capture; | ||
372 | int i; | ||
313 | 373 | ||
314 | return &ssiu->busif_status[busif]; | 374 | /* use rcar_sound,ssiu if exist */ |
375 | if (node) { | ||
376 | i = 0; | ||
377 | for_each_child_of_node(node, np) { | ||
378 | mod = rsnd_ssiu_mod_get(priv, i); | ||
379 | if (np == playback) | ||
380 | rsnd_dai_connect(mod, io_p, mod->type); | ||
381 | if (np == capture) | ||
382 | rsnd_dai_connect(mod, io_c, mod->type); | ||
383 | i++; | ||
384 | } | ||
385 | |||
386 | of_node_put(node); | ||
387 | } | ||
388 | |||
389 | /* Keep DT compatibility */ | ||
390 | if (!rsnd_io_to_mod_ssiu(io_p)) | ||
391 | rsnd_parse_connect_ssiu_compatible(priv, io_p); | ||
392 | if (!rsnd_io_to_mod_ssiu(io_c)) | ||
393 | rsnd_parse_connect_ssiu_compatible(priv, io_c); | ||
315 | } | 394 | } |
316 | 395 | ||
317 | int rsnd_ssiu_probe(struct rsnd_priv *priv) | 396 | int rsnd_ssiu_probe(struct rsnd_priv *priv) |
318 | { | 397 | { |
319 | struct device *dev = rsnd_priv_to_dev(priv); | 398 | struct device *dev = rsnd_priv_to_dev(priv); |
399 | struct device_node *node; | ||
320 | struct rsnd_ssiu *ssiu; | 400 | struct rsnd_ssiu *ssiu; |
321 | struct rsnd_mod_ops *ops; | 401 | struct rsnd_mod_ops *ops; |
402 | const int *list = NULL; | ||
322 | int i, nr, ret; | 403 | int i, nr, ret; |
323 | 404 | ||
324 | /* same number to SSI */ | 405 | /* |
325 | nr = priv->ssi_nr; | 406 | * Keep DT compatibility. |
407 | * if it has "rcar_sound,ssiu", use it. | ||
408 | * if not, use "rcar_sound,ssi" | ||
409 | * see | ||
410 | * rsnd_ssiu_bufsif_to_id() | ||
411 | */ | ||
412 | node = rsnd_ssiu_of_node(priv); | ||
413 | if (node) | ||
414 | nr = of_get_child_count(node); | ||
415 | else | ||
416 | nr = priv->ssi_nr; | ||
417 | |||
326 | ssiu = devm_kcalloc(dev, nr, sizeof(*ssiu), GFP_KERNEL); | 418 | ssiu = devm_kcalloc(dev, nr, sizeof(*ssiu), GFP_KERNEL); |
327 | if (!ssiu) | 419 | if (!ssiu) |
328 | return -ENOMEM; | 420 | return -ENOMEM; |
@@ -335,10 +427,46 @@ int rsnd_ssiu_probe(struct rsnd_priv *priv) | |||
335 | else | 427 | else |
336 | ops = &rsnd_ssiu_ops_gen2; | 428 | ops = &rsnd_ssiu_ops_gen2; |
337 | 429 | ||
430 | /* Keep compatibility */ | ||
431 | nr = 0; | ||
432 | if ((node) && | ||
433 | (ops == &rsnd_ssiu_ops_gen2)) { | ||
434 | ops->id = rsnd_ssiu_id; | ||
435 | ops->id_sub = rsnd_ssiu_id_sub; | ||
436 | |||
437 | if (rsnd_is_gen2(priv)) { | ||
438 | list = gen2_id; | ||
439 | nr = ARRAY_SIZE(gen2_id); | ||
440 | } else if (rsnd_is_gen3(priv)) { | ||
441 | list = gen3_id; | ||
442 | nr = ARRAY_SIZE(gen3_id); | ||
443 | } else { | ||
444 | dev_err(dev, "unknown SSIU\n"); | ||
445 | return -ENODEV; | ||
446 | } | ||
447 | } | ||
448 | |||
338 | for_each_rsnd_ssiu(ssiu, priv, i) { | 449 | for_each_rsnd_ssiu(ssiu, priv, i) { |
450 | if (node) { | ||
451 | int j; | ||
452 | |||
453 | /* | ||
454 | * see | ||
455 | * rsnd_ssiu_get_id() | ||
456 | * rsnd_ssiu_get_id_sub() | ||
457 | */ | ||
458 | for (j = 0; j < nr; j++) { | ||
459 | if (list[j] > i) | ||
460 | break; | ||
461 | ssiu->id = j; | ||
462 | ssiu->id_sub = i - list[ssiu->id]; | ||
463 | } | ||
464 | } else { | ||
465 | ssiu->id = i; | ||
466 | } | ||
467 | |||
339 | ret = rsnd_mod_init(priv, rsnd_mod_get(ssiu), | 468 | ret = rsnd_mod_init(priv, rsnd_mod_get(ssiu), |
340 | ops, NULL, rsnd_ssiu_get_status, | 469 | ops, NULL, RSND_MOD_SSIU, i); |
341 | RSND_MOD_SSIU, i); | ||
342 | if (ret) | 470 | if (ret) |
343 | return ret; | 471 | return ret; |
344 | } | 472 | } |
diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c index b29d0f65611e..0462b3ec977a 100644 --- a/sound/soc/soc-core.c +++ b/sound/soc/soc-core.c | |||
@@ -1467,7 +1467,7 @@ static int soc_link_dai_pcm_new(struct snd_soc_dai **dais, int num_dais, | |||
1467 | for (i = 0; i < num_dais; ++i) { | 1467 | for (i = 0; i < num_dais; ++i) { |
1468 | struct snd_soc_dai_driver *drv = dais[i]->driver; | 1468 | struct snd_soc_dai_driver *drv = dais[i]->driver; |
1469 | 1469 | ||
1470 | if (!rtd->dai_link->no_pcm && drv->pcm_new) | 1470 | if (drv->pcm_new) |
1471 | ret = drv->pcm_new(rtd, dais[i]); | 1471 | ret = drv->pcm_new(rtd, dais[i]); |
1472 | if (ret < 0) { | 1472 | if (ret < 0) { |
1473 | dev_err(dais[i]->dev, | 1473 | dev_err(dais[i]->dev, |
@@ -3485,12 +3485,11 @@ int snd_soc_of_parse_tdm_slot(struct device_node *np, | |||
3485 | } | 3485 | } |
3486 | EXPORT_SYMBOL_GPL(snd_soc_of_parse_tdm_slot); | 3486 | EXPORT_SYMBOL_GPL(snd_soc_of_parse_tdm_slot); |
3487 | 3487 | ||
3488 | void snd_soc_of_parse_audio_prefix(struct snd_soc_card *card, | 3488 | void snd_soc_of_parse_node_prefix(struct device_node *np, |
3489 | struct snd_soc_codec_conf *codec_conf, | 3489 | struct snd_soc_codec_conf *codec_conf, |
3490 | struct device_node *of_node, | 3490 | struct device_node *of_node, |
3491 | const char *propname) | 3491 | const char *propname) |
3492 | { | 3492 | { |
3493 | struct device_node *np = card->dev->of_node; | ||
3494 | const char *str; | 3493 | const char *str; |
3495 | int ret; | 3494 | int ret; |
3496 | 3495 | ||
@@ -3503,7 +3502,7 @@ void snd_soc_of_parse_audio_prefix(struct snd_soc_card *card, | |||
3503 | codec_conf->of_node = of_node; | 3502 | codec_conf->of_node = of_node; |
3504 | codec_conf->name_prefix = str; | 3503 | codec_conf->name_prefix = str; |
3505 | } | 3504 | } |
3506 | EXPORT_SYMBOL_GPL(snd_soc_of_parse_audio_prefix); | 3505 | EXPORT_SYMBOL_GPL(snd_soc_of_parse_node_prefix); |
3507 | 3506 | ||
3508 | int snd_soc_of_parse_audio_routing(struct snd_soc_card *card, | 3507 | int snd_soc_of_parse_audio_routing(struct snd_soc_card *card, |
3509 | const char *propname) | 3508 | const char *propname) |
diff --git a/sound/soc/stm/stm32_sai.c b/sound/soc/stm/stm32_sai.c index d597eba61992..bcb35cae2a2c 100644 --- a/sound/soc/stm/stm32_sai.c +++ b/sound/soc/stm/stm32_sai.c | |||
@@ -74,14 +74,14 @@ static int stm32_sai_sync_conf_provider(struct stm32_sai_data *sai, int synco) | |||
74 | return ret; | 74 | return ret; |
75 | } | 75 | } |
76 | 76 | ||
77 | dev_dbg(&sai->pdev->dev, "Set %s%s as synchro provider\n", | 77 | dev_dbg(&sai->pdev->dev, "Set %pOFn%s as synchro provider\n", |
78 | sai->pdev->dev.of_node->name, | 78 | sai->pdev->dev.of_node, |
79 | synco == STM_SAI_SYNC_OUT_A ? "A" : "B"); | 79 | synco == STM_SAI_SYNC_OUT_A ? "A" : "B"); |
80 | 80 | ||
81 | prev_synco = FIELD_GET(SAI_GCR_SYNCOUT_MASK, readl_relaxed(sai->base)); | 81 | prev_synco = FIELD_GET(SAI_GCR_SYNCOUT_MASK, readl_relaxed(sai->base)); |
82 | if (prev_synco != STM_SAI_SYNC_OUT_NONE && synco != prev_synco) { | 82 | if (prev_synco != STM_SAI_SYNC_OUT_NONE && synco != prev_synco) { |
83 | dev_err(&sai->pdev->dev, "%s%s already set as sync provider\n", | 83 | dev_err(&sai->pdev->dev, "%pOFn%s already set as sync provider\n", |
84 | sai->pdev->dev.of_node->name, | 84 | sai->pdev->dev.of_node, |
85 | prev_synco == STM_SAI_SYNC_OUT_A ? "A" : "B"); | 85 | prev_synco == STM_SAI_SYNC_OUT_A ? "A" : "B"); |
86 | clk_disable_unprepare(sai->pclk); | 86 | clk_disable_unprepare(sai->pclk); |
87 | return -EINVAL; | 87 | return -EINVAL; |
diff --git a/sound/soc/stm/stm32_sai_sub.c b/sound/soc/stm/stm32_sai_sub.c index 211589b0b2ef..d4825700b63f 100644 --- a/sound/soc/stm/stm32_sai_sub.c +++ b/sound/soc/stm/stm32_sai_sub.c | |||
@@ -336,8 +336,7 @@ static int stm32_sai_mclk_set_rate(struct clk_hw *hw, unsigned long rate, | |||
336 | { | 336 | { |
337 | struct stm32_sai_mclk_data *mclk = to_mclk_data(hw); | 337 | struct stm32_sai_mclk_data *mclk = to_mclk_data(hw); |
338 | struct stm32_sai_sub_data *sai = mclk->sai_data; | 338 | struct stm32_sai_sub_data *sai = mclk->sai_data; |
339 | unsigned int div; | 339 | int div, ret; |
340 | int ret; | ||
341 | 340 | ||
342 | div = stm32_sai_get_clk_div(sai, parent_rate, rate); | 341 | div = stm32_sai_get_clk_div(sai, parent_rate, rate); |
343 | if (div < 0) | 342 | if (div < 0) |
diff --git a/sound/soc/sunxi/sun50i-codec-analog.c b/sound/soc/sunxi/sun50i-codec-analog.c index 8f5f999df631..df1fed0aa001 100644 --- a/sound/soc/sunxi/sun50i-codec-analog.c +++ b/sound/soc/sunxi/sun50i-codec-analog.c | |||
@@ -274,6 +274,7 @@ static const struct snd_soc_dapm_widget sun50i_a64_codec_widgets[] = { | |||
274 | * stream widgets at the card level. | 274 | * stream widgets at the card level. |
275 | */ | 275 | */ |
276 | 276 | ||
277 | SND_SOC_DAPM_REGULATOR_SUPPLY("hpvcc", 0, 0), | ||
277 | SND_SOC_DAPM_MUX("Headphone Source Playback Route", | 278 | SND_SOC_DAPM_MUX("Headphone Source Playback Route", |
278 | SND_SOC_NOPM, 0, 0, sun50i_codec_hp_src), | 279 | SND_SOC_NOPM, 0, 0, sun50i_codec_hp_src), |
279 | SND_SOC_DAPM_OUT_DRV("Headphone Amp", SUN50I_ADDA_HP_CTRL, | 280 | SND_SOC_DAPM_OUT_DRV("Headphone Amp", SUN50I_ADDA_HP_CTRL, |
@@ -361,6 +362,7 @@ static const struct snd_soc_dapm_route sun50i_a64_codec_routes[] = { | |||
361 | { "Headphone Source Playback Route", "Mixer", "Left Mixer" }, | 362 | { "Headphone Source Playback Route", "Mixer", "Left Mixer" }, |
362 | { "Headphone Source Playback Route", "Mixer", "Right Mixer" }, | 363 | { "Headphone Source Playback Route", "Mixer", "Right Mixer" }, |
363 | { "Headphone Amp", NULL, "Headphone Source Playback Route" }, | 364 | { "Headphone Amp", NULL, "Headphone Source Playback Route" }, |
365 | { "Headphone Amp", NULL, "hpvcc" }, | ||
364 | { "HP", NULL, "Headphone Amp" }, | 366 | { "HP", NULL, "Headphone Amp" }, |
365 | 367 | ||
366 | /* Microphone Routes */ | 368 | /* Microphone Routes */ |
diff --git a/sound/soc/ti/Kconfig b/sound/soc/ti/Kconfig new file mode 100644 index 000000000000..4bf3c15d4e51 --- /dev/null +++ b/sound/soc/ti/Kconfig | |||
@@ -0,0 +1,209 @@ | |||
1 | menu "Audio support for Texas Instruments SoCs" | ||
2 | depends on DMA_OMAP || TI_EDMA || COMPILE_TEST | ||
3 | |||
4 | config SND_SOC_TI_EDMA_PCM | ||
5 | tristate | ||
6 | select SND_SOC_GENERIC_DMAENGINE_PCM | ||
7 | |||
8 | config SND_SOC_TI_SDMA_PCM | ||
9 | tristate | ||
10 | select SND_SOC_GENERIC_DMAENGINE_PCM | ||
11 | |||
12 | comment "Texas Instruments DAI support for:" | ||
13 | config SND_SOC_DAVINCI_ASP | ||
14 | tristate "daVinci Audio Serial Port (ASP) or McBSP suport" | ||
15 | depends on ARCH_DAVINCI || COMPILE_TEST | ||
16 | select SND_SOC_TI_EDMA_PCM | ||
17 | help | ||
18 | Say Y or M here if you want audio support via daVinci ASP or McBSP. | ||
19 | The driver only implements the ASP support which is a subset of | ||
20 | daVinci McBSP (w/o the multichannel support). | ||
21 | |||
22 | config SND_SOC_DAVINCI_MCASP | ||
23 | tristate "Multichannel Audio Serial Port (McASP) support" | ||
24 | select SND_SOC_TI_EDMA_PCM if TI_EDMA | ||
25 | select SND_SOC_TI_SDMA_PCM if DMA_OMAP | ||
26 | help | ||
27 | Say Y or M here if you want to have support for McASP IP found in | ||
28 | various Texas Instruments SoCs like: | ||
29 | - daVinci devices | ||
30 | - Sitara line of SoCs (AM335x, AM438x, etc) | ||
31 | - DRA7x devices | ||
32 | - Keystone devices | ||
33 | |||
34 | config SND_SOC_DAVINCI_VCIF | ||
35 | tristate "daVinci Voice Interface (VCIF) suport" | ||
36 | depends on ARCH_DAVINCI || COMPILE_TEST | ||
37 | select SND_SOC_TI_EDMA_PCM | ||
38 | help | ||
39 | Say Y or M here if you want audio support via daVinci VCIF. | ||
40 | |||
41 | config SND_SOC_OMAP_DMIC | ||
42 | tristate "Digital Microphone Module (DMIC) support" | ||
43 | depends on ARCH_OMAP4 || SOC_OMAP5 || COMPILE_TEST | ||
44 | select SND_SOC_TI_SDMA_PCM | ||
45 | help | ||
46 | Say Y or M here if you want to have support for DMIC IP found in | ||
47 | OMAP4 and OMAP5. | ||
48 | |||
49 | config SND_SOC_OMAP_MCBSP | ||
50 | tristate "Multichannel Buffered Serial Port (McBSP) support" | ||
51 | depends on ARCH_OMAP || ARCH_OMAP1 || COMPILE_TEST | ||
52 | select SND_SOC_TI_SDMA_PCM | ||
53 | help | ||
54 | Say Y or M here if you want to have support for McBSP IP found in | ||
55 | Texas Instruments OMAP1/2/3/4/5 SoCs. | ||
56 | |||
57 | config SND_SOC_OMAP_MCPDM | ||
58 | tristate "Multichannel PDM Controller (McPDM) support" | ||
59 | depends on ARCH_OMAP4 || SOC_OMAP5 || COMPILE_TEST | ||
60 | select SND_SOC_TI_SDMA_PCM | ||
61 | help | ||
62 | Say Y or M here if you want to have support for McPDM IP found in | ||
63 | OMAP4 and OMAP5. | ||
64 | |||
65 | comment "Audio support for boards with Texas Instruments SoCs" | ||
66 | config SND_SOC_NOKIA_N810 | ||
67 | tristate "SoC Audio support for Nokia N810" | ||
68 | depends on MACH_NOKIA_N810 && I2C | ||
69 | select SND_SOC_OMAP_MCBSP | ||
70 | select SND_SOC_TLV320AIC3X | ||
71 | help | ||
72 | Say Y or M if you want to add support for SoC audio on Nokia N810. | ||
73 | |||
74 | config SND_SOC_NOKIA_RX51 | ||
75 | tristate "SoC Audio support for Nokia RX-51" | ||
76 | depends on ARCH_OMAP3 && I2C && GPIOLIB | ||
77 | select SND_SOC_OMAP_MCBSP | ||
78 | select SND_SOC_TLV320AIC3X | ||
79 | select SND_SOC_TPA6130A2 | ||
80 | help | ||
81 | Say Y or M if you want to add support for SoC audio on Nokia RX-51 | ||
82 | hardware. This is also known as Nokia N900 product. | ||
83 | |||
84 | config SND_SOC_OMAP3_PANDORA | ||
85 | tristate "SoC Audio support for OMAP3 Pandora" | ||
86 | depends on ARCH_OMAP3 | ||
87 | depends on TWL4030_CORE | ||
88 | select SND_SOC_OMAP_MCBSP | ||
89 | select SND_SOC_TWL4030 | ||
90 | help | ||
91 | Say Y or M if you want to add support for SoC audio on the OMAP3 Pandora. | ||
92 | |||
93 | config SND_SOC_OMAP3_TWL4030 | ||
94 | tristate "SoC Audio support for OMAP3 based boards with twl4030 codec" | ||
95 | depends on ARCH_OMAP3 || COMPILE_TEST | ||
96 | depends on TWL4030_CORE | ||
97 | select SND_SOC_OMAP_MCBSP | ||
98 | select SND_SOC_TWL4030 | ||
99 | help | ||
100 | Say Y or M if you want to add support for SoC audio on OMAP3 based | ||
101 | boards using twl4030 as codec. This driver currently supports: | ||
102 | - Beagleboard or Devkit8000 | ||
103 | - Gumstix Overo or CompuLab CM-T35/CM-T3730 | ||
104 | - IGEP v2 | ||
105 | - OMAP3EVM | ||
106 | - SDP3430 | ||
107 | - Zoom2 | ||
108 | |||
109 | config SND_SOC_OMAP_ABE_TWL6040 | ||
110 | tristate "SoC Audio support for OMAP boards using ABE and twl6040 codec" | ||
111 | depends on TWL6040_CORE && COMMON_CLK | ||
112 | depends on ARCH_OMAP4 || (SOC_OMAP5 && MFD_PALMAS) || COMPILE_TEST | ||
113 | select SND_SOC_OMAP_DMIC | ||
114 | select SND_SOC_OMAP_MCPDM | ||
115 | select SND_SOC_TWL6040 | ||
116 | help | ||
117 | Say Y or M if you want to add support for SoC audio on OMAP boards | ||
118 | using ABE and twl6040 codec. This driver currently supports: | ||
119 | - SDP4430/Blaze boards | ||
120 | - PandaBoard (4430) | ||
121 | - PandaBoardES (4460) | ||
122 | - OMAP5 uEVM | ||
123 | |||
124 | config SND_SOC_OMAP_AMS_DELTA | ||
125 | tristate "SoC Audio support for Amstrad E3 (Delta) videophone" | ||
126 | depends on MACH_AMS_DELTA && TTY | ||
127 | select SND_SOC_OMAP_MCBSP | ||
128 | select SND_SOC_CX20442 | ||
129 | help | ||
130 | Say Y or M if you want to add support for SoC audio device | ||
131 | connected to a handset and a speakerphone found on Amstrad E3 (Delta) | ||
132 | videophone. | ||
133 | |||
134 | Note that in order to get those devices fully supported, you have to | ||
135 | build the kernel with standard serial port driver included and | ||
136 | configured for at least 4 ports. Then, from userspace, you must load | ||
137 | a line discipline #19 on the modem (ttyS3) serial line. The simplest | ||
138 | way to achieve this is to install util-linux-ng and use the included | ||
139 | ldattach utility. This can be started automatically from udev, | ||
140 | a simple rule like this one should do the trick (it does for me): | ||
141 | ACTION=="add", KERNEL=="controlC0", \ | ||
142 | RUN+="/usr/sbin/ldattach 19 /dev/ttyS3" | ||
143 | |||
144 | config SND_SOC_OMAP_HDMI | ||
145 | tristate "OMAP4/5 HDMI audio support" | ||
146 | depends on OMAP4_DSS_HDMI || OMAP5_DSS_HDMI || COMPILE_TEST | ||
147 | select SND_SOC_TI_SDMA_PCM | ||
148 | help | ||
149 | For HDMI audio to work OMAPDSS HDMI support should be | ||
150 | enabled. | ||
151 | The hdmi audio driver implements cpu-dai component using the | ||
152 | callbacks provided by OMAPDSS and registers the component | ||
153 | under DSS HDMI device. Omap-pcm is registered for platform | ||
154 | component also under DSS HDMI device. Dummy codec is used as | ||
155 | as codec component. The hdmi audio driver implements also | ||
156 | the card and registers it under its own platform device. | ||
157 | The device for the driver is registered by OMAPDSS hdmi | ||
158 | driver. | ||
159 | |||
160 | config SND_SOC_OMAP_OSK5912 | ||
161 | tristate "SoC Audio support for omap osk5912" | ||
162 | depends on MACH_OMAP_OSK && I2C | ||
163 | select SND_SOC_OMAP_MCBSP | ||
164 | select SND_SOC_TLV320AIC23_I2C | ||
165 | help | ||
166 | Say Y or M if you want to add support for SoC audio on osk5912. | ||
167 | |||
168 | config SND_SOC_DAVINCI_EVM | ||
169 | tristate "SoC Audio support for DaVinci EVMs" | ||
170 | depends on ARCH_DAVINCI && I2C | ||
171 | select SND_SOC_DAVINCI_ASP if MACH_DAVINCI_DM355_EVM | ||
172 | select SND_SOC_DAVINCI_ASP if SND_SOC_DM365_AIC3X_CODEC | ||
173 | select SND_SOC_DAVINCI_VCIF if SND_SOC_DM365_VOICE_CODEC | ||
174 | select SND_SOC_DAVINCI_ASP if MACH_DAVINCI_EVM # DM6446 | ||
175 | select SND_SOC_DAVINCI_MCASP if MACH_DAVINCI_DM6467_EVM | ||
176 | select SND_SOC_SPDIF if MACH_DAVINCI_DM6467_EVM | ||
177 | select SND_SOC_DAVINCI_MCASP if MACH_DAVINCI_DA830_EVM | ||
178 | select SND_SOC_DAVINCI_MCASP if MACH_DAVINCI_DA850_EVM | ||
179 | select SND_SOC_TLV320AIC3X | ||
180 | help | ||
181 | Say Y if you want to add support for SoC audio on the following TI | ||
182 | DaVinci EVM platforms: | ||
183 | - DM355 | ||
184 | - DM365 | ||
185 | - DM6446 | ||
186 | - DM6447 | ||
187 | - DM830 | ||
188 | - DM850 | ||
189 | |||
190 | choice | ||
191 | prompt "DM365 codec select" | ||
192 | depends on SND_SOC_DAVINCI_EVM | ||
193 | depends on MACH_DAVINCI_DM365_EVM | ||
194 | |||
195 | config SND_SOC_DM365_AIC3X_CODEC | ||
196 | bool "Audio Codec - AIC3101" | ||
197 | help | ||
198 | Say Y if you want to add support for AIC3101 audio codec | ||
199 | |||
200 | config SND_SOC_DM365_VOICE_CODEC | ||
201 | bool "Voice Codec - CQ93VC" | ||
202 | select MFD_DAVINCI_VOICECODEC | ||
203 | select SND_SOC_CQ0093VC | ||
204 | help | ||
205 | Say Y if you want to add support for SoC On-chip voice codec | ||
206 | endchoice | ||
207 | |||
208 | endmenu | ||
209 | |||
diff --git a/sound/soc/ti/Makefile b/sound/soc/ti/Makefile new file mode 100644 index 000000000000..08c44d56ef3e --- /dev/null +++ b/sound/soc/ti/Makefile | |||
@@ -0,0 +1,44 @@ | |||
1 | # SPDX-License-Identifier: GPL-2.0 | ||
2 | |||
3 | # Platform drivers | ||
4 | snd-soc-ti-edma-objs := edma-pcm.o | ||
5 | snd-soc-ti-sdma-objs := sdma-pcm.o | ||
6 | |||
7 | obj-$(CONFIG_SND_SOC_TI_EDMA_PCM) += snd-soc-ti-edma.o | ||
8 | obj-$(CONFIG_SND_SOC_TI_SDMA_PCM) += snd-soc-ti-sdma.o | ||
9 | |||
10 | # CPU DAI drivers | ||
11 | snd-soc-davinci-asp-objs := davinci-i2s.o | ||
12 | snd-soc-davinci-mcasp-objs := davinci-mcasp.o | ||
13 | snd-soc-davinci-vcif-objs := davinci-vcif.o | ||
14 | snd-soc-omap-dmic-objs := omap-dmic.o | ||
15 | snd-soc-omap-mcbsp-objs := omap-mcbsp.o omap-mcbsp-st.o | ||
16 | snd-soc-omap-mcpdm-objs := omap-mcpdm.o | ||
17 | |||
18 | obj-$(CONFIG_SND_SOC_DAVINCI_ASP) += snd-soc-davinci-asp.o | ||
19 | obj-$(CONFIG_SND_SOC_DAVINCI_MCASP) += snd-soc-davinci-mcasp.o | ||
20 | obj-$(CONFIG_SND_SOC_DAVINCI_VCIF) += snd-soc-davinci-vcif.o | ||
21 | obj-$(CONFIG_SND_SOC_OMAP_DMIC) += snd-soc-omap-dmic.o | ||
22 | obj-$(CONFIG_SND_SOC_OMAP_MCBSP) += snd-soc-omap-mcbsp.o | ||
23 | obj-$(CONFIG_SND_SOC_OMAP_MCPDM) += snd-soc-omap-mcpdm.o | ||
24 | |||
25 | # Machine drivers | ||
26 | snd-soc-davinci-evm-objs := davinci-evm.o | ||
27 | snd-soc-n810-objs := n810.o | ||
28 | snd-soc-rx51-objs := rx51.o | ||
29 | snd-soc-omap3pandora-objs := omap3pandora.o | ||
30 | snd-soc-omap-twl4030-objs := omap-twl4030.o | ||
31 | snd-soc-omap-abe-twl6040-objs := omap-abe-twl6040.o | ||
32 | snd-soc-ams-delta-objs := ams-delta.o | ||
33 | snd-soc-omap-hdmi-objs := omap-hdmi.o | ||
34 | snd-soc-osk5912-objs := osk5912.o | ||
35 | |||
36 | obj-$(CONFIG_SND_SOC_DAVINCI_EVM) += snd-soc-davinci-evm.o | ||
37 | obj-$(CONFIG_SND_SOC_NOKIA_N810) += snd-soc-n810.o | ||
38 | obj-$(CONFIG_SND_SOC_NOKIA_RX51) += snd-soc-rx51.o | ||
39 | obj-$(CONFIG_SND_SOC_OMAP3_PANDORA) += snd-soc-omap3pandora.o | ||
40 | obj-$(CONFIG_SND_SOC_OMAP3_TWL4030) += snd-soc-omap-twl4030.o | ||
41 | obj-$(CONFIG_SND_SOC_OMAP_ABE_TWL6040) += snd-soc-omap-abe-twl6040.o | ||
42 | obj-$(CONFIG_SND_SOC_OMAP_AMS_DELTA) += snd-soc-ams-delta.o | ||
43 | obj-$(CONFIG_SND_SOC_OMAP_HDMI) += snd-soc-omap-hdmi.o | ||
44 | obj-$(CONFIG_SND_SOC_OMAP_OSK5912) += snd-soc-osk5912.o | ||
diff --git a/sound/soc/omap/ams-delta.c b/sound/soc/ti/ams-delta.c index 4dce494dfbd3..4dce494dfbd3 100644 --- a/sound/soc/omap/ams-delta.c +++ b/sound/soc/ti/ams-delta.c | |||
diff --git a/sound/soc/davinci/davinci-evm.c b/sound/soc/ti/davinci-evm.c index 7a369e0f2093..4869d6311510 100644 --- a/sound/soc/davinci/davinci-evm.c +++ b/sound/soc/ti/davinci-evm.c | |||
@@ -170,7 +170,7 @@ static struct snd_soc_dai_link dm355_evm_dai = { | |||
170 | }; | 170 | }; |
171 | 171 | ||
172 | static struct snd_soc_dai_link dm365_evm_dai = { | 172 | static struct snd_soc_dai_link dm365_evm_dai = { |
173 | #ifdef CONFIG_SND_DM365_AIC3X_CODEC | 173 | #ifdef CONFIG_SND_SOC_DM365_AIC3X_CODEC |
174 | .name = "TLV320AIC3X", | 174 | .name = "TLV320AIC3X", |
175 | .stream_name = "AIC3X", | 175 | .stream_name = "AIC3X", |
176 | .cpu_dai_name = "davinci-mcbsp", | 176 | .cpu_dai_name = "davinci-mcbsp", |
@@ -181,7 +181,7 @@ static struct snd_soc_dai_link dm365_evm_dai = { | |||
181 | .ops = &evm_ops, | 181 | .ops = &evm_ops, |
182 | .dai_fmt = SND_SOC_DAIFMT_DSP_B | SND_SOC_DAIFMT_CBM_CFM | | 182 | .dai_fmt = SND_SOC_DAIFMT_DSP_B | SND_SOC_DAIFMT_CBM_CFM | |
183 | SND_SOC_DAIFMT_IB_NF, | 183 | SND_SOC_DAIFMT_IB_NF, |
184 | #elif defined(CONFIG_SND_DM365_VOICE_CODEC) | 184 | #elif defined(CONFIG_SND_SOC_DM365_VOICE_CODEC) |
185 | .name = "Voice Codec - CQ93VC", | 185 | .name = "Voice Codec - CQ93VC", |
186 | .stream_name = "CQ93", | 186 | .stream_name = "CQ93", |
187 | .cpu_dai_name = "davinci-vcif", | 187 | .cpu_dai_name = "davinci-vcif", |
diff --git a/sound/soc/davinci/davinci-i2s.c b/sound/soc/ti/davinci-i2s.c index a3206e65e5e5..a3206e65e5e5 100644 --- a/sound/soc/davinci/davinci-i2s.c +++ b/sound/soc/ti/davinci-i2s.c | |||
diff --git a/sound/soc/davinci/davinci-i2s.h b/sound/soc/ti/davinci-i2s.h index 48dac3e2521a..48dac3e2521a 100644 --- a/sound/soc/davinci/davinci-i2s.h +++ b/sound/soc/ti/davinci-i2s.h | |||
diff --git a/sound/soc/davinci/davinci-mcasp.c b/sound/soc/ti/davinci-mcasp.c index 267aee776b2d..eeda6d5565bc 100644 --- a/sound/soc/davinci/davinci-mcasp.c +++ b/sound/soc/ti/davinci-mcasp.c | |||
@@ -28,6 +28,7 @@ | |||
28 | #include <linux/of_device.h> | 28 | #include <linux/of_device.h> |
29 | #include <linux/platform_data/davinci_asp.h> | 29 | #include <linux/platform_data/davinci_asp.h> |
30 | #include <linux/math64.h> | 30 | #include <linux/math64.h> |
31 | #include <linux/bitmap.h> | ||
31 | 32 | ||
32 | #include <sound/asoundef.h> | 33 | #include <sound/asoundef.h> |
33 | #include <sound/core.h> | 34 | #include <sound/core.h> |
@@ -38,7 +39,7 @@ | |||
38 | #include <sound/dmaengine_pcm.h> | 39 | #include <sound/dmaengine_pcm.h> |
39 | 40 | ||
40 | #include "edma-pcm.h" | 41 | #include "edma-pcm.h" |
41 | #include "../omap/sdma-pcm.h" | 42 | #include "sdma-pcm.h" |
42 | #include "davinci-mcasp.h" | 43 | #include "davinci-mcasp.h" |
43 | 44 | ||
44 | #define MCASP_MAX_AFIFO_DEPTH 64 | 45 | #define MCASP_MAX_AFIFO_DEPTH 64 |
@@ -84,6 +85,7 @@ struct davinci_mcasp { | |||
84 | u32 tdm_mask[2]; | 85 | u32 tdm_mask[2]; |
85 | int slot_width; | 86 | int slot_width; |
86 | u8 op_mode; | 87 | u8 op_mode; |
88 | u8 dismod; | ||
87 | u8 num_serializer; | 89 | u8 num_serializer; |
88 | u8 *serial_dir; | 90 | u8 *serial_dir; |
89 | u8 version; | 91 | u8 version; |
@@ -95,6 +97,8 @@ struct davinci_mcasp { | |||
95 | int sysclk_freq; | 97 | int sysclk_freq; |
96 | bool bclk_master; | 98 | bool bclk_master; |
97 | 99 | ||
100 | unsigned long pdir; /* Pin direction bitfield */ | ||
101 | |||
98 | /* McASP FIFO related */ | 102 | /* McASP FIFO related */ |
99 | u8 txnumevt; | 103 | u8 txnumevt; |
100 | u8 rxnumevt; | 104 | u8 rxnumevt; |
@@ -169,6 +173,30 @@ static bool mcasp_is_synchronous(struct davinci_mcasp *mcasp) | |||
169 | return !(aclkxctl & TX_ASYNC) && rxfmctl & AFSRE; | 173 | return !(aclkxctl & TX_ASYNC) && rxfmctl & AFSRE; |
170 | } | 174 | } |
171 | 175 | ||
176 | static inline void mcasp_set_clk_pdir(struct davinci_mcasp *mcasp, bool enable) | ||
177 | { | ||
178 | u32 bit = PIN_BIT_AMUTE; | ||
179 | |||
180 | for_each_set_bit_from(bit, &mcasp->pdir, PIN_BIT_AFSR + 1) { | ||
181 | if (enable) | ||
182 | mcasp_set_bits(mcasp, DAVINCI_MCASP_PDIR_REG, BIT(bit)); | ||
183 | else | ||
184 | mcasp_clr_bits(mcasp, DAVINCI_MCASP_PDIR_REG, BIT(bit)); | ||
185 | } | ||
186 | } | ||
187 | |||
188 | static inline void mcasp_set_axr_pdir(struct davinci_mcasp *mcasp, bool enable) | ||
189 | { | ||
190 | u32 bit; | ||
191 | |||
192 | for_each_set_bit(bit, &mcasp->pdir, PIN_BIT_AFSR) { | ||
193 | if (enable) | ||
194 | mcasp_set_bits(mcasp, DAVINCI_MCASP_PDIR_REG, BIT(bit)); | ||
195 | else | ||
196 | mcasp_clr_bits(mcasp, DAVINCI_MCASP_PDIR_REG, BIT(bit)); | ||
197 | } | ||
198 | } | ||
199 | |||
172 | static void mcasp_start_rx(struct davinci_mcasp *mcasp) | 200 | static void mcasp_start_rx(struct davinci_mcasp *mcasp) |
173 | { | 201 | { |
174 | if (mcasp->rxnumevt) { /* enable FIFO */ | 202 | if (mcasp->rxnumevt) { /* enable FIFO */ |
@@ -192,6 +220,7 @@ static void mcasp_start_rx(struct davinci_mcasp *mcasp) | |||
192 | } | 220 | } |
193 | 221 | ||
194 | /* Activate serializer(s) */ | 222 | /* Activate serializer(s) */ |
223 | mcasp_set_reg(mcasp, DAVINCI_MCASP_RXSTAT_REG, 0xFFFFFFFF); | ||
195 | mcasp_set_ctl_reg(mcasp, DAVINCI_MCASP_GBLCTLR_REG, RXSERCLR); | 224 | mcasp_set_ctl_reg(mcasp, DAVINCI_MCASP_GBLCTLR_REG, RXSERCLR); |
196 | /* Release RX state machine */ | 225 | /* Release RX state machine */ |
197 | mcasp_set_ctl_reg(mcasp, DAVINCI_MCASP_GBLCTLR_REG, RXSMRST); | 226 | mcasp_set_ctl_reg(mcasp, DAVINCI_MCASP_GBLCTLR_REG, RXSMRST); |
@@ -219,7 +248,10 @@ static void mcasp_start_tx(struct davinci_mcasp *mcasp) | |||
219 | /* Start clocks */ | 248 | /* Start clocks */ |
220 | mcasp_set_ctl_reg(mcasp, DAVINCI_MCASP_GBLCTLX_REG, TXHCLKRST); | 249 | mcasp_set_ctl_reg(mcasp, DAVINCI_MCASP_GBLCTLX_REG, TXHCLKRST); |
221 | mcasp_set_ctl_reg(mcasp, DAVINCI_MCASP_GBLCTLX_REG, TXCLKRST); | 250 | mcasp_set_ctl_reg(mcasp, DAVINCI_MCASP_GBLCTLX_REG, TXCLKRST); |
251 | mcasp_set_clk_pdir(mcasp, true); | ||
252 | |||
222 | /* Activate serializer(s) */ | 253 | /* Activate serializer(s) */ |
254 | mcasp_set_reg(mcasp, DAVINCI_MCASP_TXSTAT_REG, 0xFFFFFFFF); | ||
223 | mcasp_set_ctl_reg(mcasp, DAVINCI_MCASP_GBLCTLX_REG, TXSERCLR); | 255 | mcasp_set_ctl_reg(mcasp, DAVINCI_MCASP_GBLCTLX_REG, TXSERCLR); |
224 | 256 | ||
225 | /* wait for XDATA to be cleared */ | 257 | /* wait for XDATA to be cleared */ |
@@ -228,6 +260,8 @@ static void mcasp_start_tx(struct davinci_mcasp *mcasp) | |||
228 | (cnt < 100000)) | 260 | (cnt < 100000)) |
229 | cnt++; | 261 | cnt++; |
230 | 262 | ||
263 | mcasp_set_axr_pdir(mcasp, true); | ||
264 | |||
231 | /* Release TX state machine */ | 265 | /* Release TX state machine */ |
232 | mcasp_set_ctl_reg(mcasp, DAVINCI_MCASP_GBLCTLX_REG, TXSMRST); | 266 | mcasp_set_ctl_reg(mcasp, DAVINCI_MCASP_GBLCTLX_REG, TXSMRST); |
233 | /* Release Frame Sync generator */ | 267 | /* Release Frame Sync generator */ |
@@ -258,8 +292,10 @@ static void mcasp_stop_rx(struct davinci_mcasp *mcasp) | |||
258 | * In synchronous mode stop the TX clocks if no other stream is | 292 | * In synchronous mode stop the TX clocks if no other stream is |
259 | * running | 293 | * running |
260 | */ | 294 | */ |
261 | if (mcasp_is_synchronous(mcasp) && !mcasp->streams) | 295 | if (mcasp_is_synchronous(mcasp) && !mcasp->streams) { |
296 | mcasp_set_clk_pdir(mcasp, false); | ||
262 | mcasp_set_reg(mcasp, DAVINCI_MCASP_GBLCTLX_REG, 0); | 297 | mcasp_set_reg(mcasp, DAVINCI_MCASP_GBLCTLX_REG, 0); |
298 | } | ||
263 | 299 | ||
264 | mcasp_set_reg(mcasp, DAVINCI_MCASP_GBLCTLR_REG, 0); | 300 | mcasp_set_reg(mcasp, DAVINCI_MCASP_GBLCTLR_REG, 0); |
265 | mcasp_set_reg(mcasp, DAVINCI_MCASP_RXSTAT_REG, 0xFFFFFFFF); | 301 | mcasp_set_reg(mcasp, DAVINCI_MCASP_RXSTAT_REG, 0xFFFFFFFF); |
@@ -285,6 +321,9 @@ static void mcasp_stop_tx(struct davinci_mcasp *mcasp) | |||
285 | */ | 321 | */ |
286 | if (mcasp_is_synchronous(mcasp) && mcasp->streams) | 322 | if (mcasp_is_synchronous(mcasp) && mcasp->streams) |
287 | val = TXHCLKRST | TXCLKRST | TXFSRST; | 323 | val = TXHCLKRST | TXCLKRST | TXFSRST; |
324 | else | ||
325 | mcasp_set_clk_pdir(mcasp, false); | ||
326 | |||
288 | 327 | ||
289 | mcasp_set_reg(mcasp, DAVINCI_MCASP_GBLCTLX_REG, val); | 328 | mcasp_set_reg(mcasp, DAVINCI_MCASP_GBLCTLX_REG, val); |
290 | mcasp_set_reg(mcasp, DAVINCI_MCASP_TXSTAT_REG, 0xFFFFFFFF); | 329 | mcasp_set_reg(mcasp, DAVINCI_MCASP_TXSTAT_REG, 0xFFFFFFFF); |
@@ -294,6 +333,8 @@ static void mcasp_stop_tx(struct davinci_mcasp *mcasp) | |||
294 | 333 | ||
295 | mcasp_clr_bits(mcasp, reg, FIFO_ENABLE); | 334 | mcasp_clr_bits(mcasp, reg, FIFO_ENABLE); |
296 | } | 335 | } |
336 | |||
337 | mcasp_set_axr_pdir(mcasp, false); | ||
297 | } | 338 | } |
298 | 339 | ||
299 | static void davinci_mcasp_stop(struct davinci_mcasp *mcasp, int stream) | 340 | static void davinci_mcasp_stop(struct davinci_mcasp *mcasp, int stream) |
@@ -444,8 +485,13 @@ static int davinci_mcasp_set_dai_fmt(struct snd_soc_dai *cpu_dai, | |||
444 | mcasp_set_bits(mcasp, DAVINCI_MCASP_ACLKRCTL_REG, ACLKRE); | 485 | mcasp_set_bits(mcasp, DAVINCI_MCASP_ACLKRCTL_REG, ACLKRE); |
445 | mcasp_set_bits(mcasp, DAVINCI_MCASP_RXFMCTL_REG, AFSRE); | 486 | mcasp_set_bits(mcasp, DAVINCI_MCASP_RXFMCTL_REG, AFSRE); |
446 | 487 | ||
447 | mcasp_set_bits(mcasp, DAVINCI_MCASP_PDIR_REG, ACLKX | ACLKR); | 488 | /* BCLK */ |
448 | mcasp_set_bits(mcasp, DAVINCI_MCASP_PDIR_REG, AFSX | AFSR); | 489 | set_bit(PIN_BIT_ACLKX, &mcasp->pdir); |
490 | set_bit(PIN_BIT_ACLKR, &mcasp->pdir); | ||
491 | /* Frame Sync */ | ||
492 | set_bit(PIN_BIT_AFSX, &mcasp->pdir); | ||
493 | set_bit(PIN_BIT_AFSR, &mcasp->pdir); | ||
494 | |||
449 | mcasp->bclk_master = 1; | 495 | mcasp->bclk_master = 1; |
450 | break; | 496 | break; |
451 | case SND_SOC_DAIFMT_CBS_CFM: | 497 | case SND_SOC_DAIFMT_CBS_CFM: |
@@ -456,8 +502,13 @@ static int davinci_mcasp_set_dai_fmt(struct snd_soc_dai *cpu_dai, | |||
456 | mcasp_set_bits(mcasp, DAVINCI_MCASP_ACLKRCTL_REG, ACLKRE); | 502 | mcasp_set_bits(mcasp, DAVINCI_MCASP_ACLKRCTL_REG, ACLKRE); |
457 | mcasp_clr_bits(mcasp, DAVINCI_MCASP_RXFMCTL_REG, AFSRE); | 503 | mcasp_clr_bits(mcasp, DAVINCI_MCASP_RXFMCTL_REG, AFSRE); |
458 | 504 | ||
459 | mcasp_set_bits(mcasp, DAVINCI_MCASP_PDIR_REG, ACLKX | ACLKR); | 505 | /* BCLK */ |
460 | mcasp_clr_bits(mcasp, DAVINCI_MCASP_PDIR_REG, AFSX | AFSR); | 506 | set_bit(PIN_BIT_ACLKX, &mcasp->pdir); |
507 | set_bit(PIN_BIT_ACLKR, &mcasp->pdir); | ||
508 | /* Frame Sync */ | ||
509 | clear_bit(PIN_BIT_AFSX, &mcasp->pdir); | ||
510 | clear_bit(PIN_BIT_AFSR, &mcasp->pdir); | ||
511 | |||
461 | mcasp->bclk_master = 1; | 512 | mcasp->bclk_master = 1; |
462 | break; | 513 | break; |
463 | case SND_SOC_DAIFMT_CBM_CFS: | 514 | case SND_SOC_DAIFMT_CBM_CFS: |
@@ -468,8 +519,13 @@ static int davinci_mcasp_set_dai_fmt(struct snd_soc_dai *cpu_dai, | |||
468 | mcasp_clr_bits(mcasp, DAVINCI_MCASP_ACLKRCTL_REG, ACLKRE); | 519 | mcasp_clr_bits(mcasp, DAVINCI_MCASP_ACLKRCTL_REG, ACLKRE); |
469 | mcasp_set_bits(mcasp, DAVINCI_MCASP_RXFMCTL_REG, AFSRE); | 520 | mcasp_set_bits(mcasp, DAVINCI_MCASP_RXFMCTL_REG, AFSRE); |
470 | 521 | ||
471 | mcasp_clr_bits(mcasp, DAVINCI_MCASP_PDIR_REG, ACLKX | ACLKR); | 522 | /* BCLK */ |
472 | mcasp_set_bits(mcasp, DAVINCI_MCASP_PDIR_REG, AFSX | AFSR); | 523 | clear_bit(PIN_BIT_ACLKX, &mcasp->pdir); |
524 | clear_bit(PIN_BIT_ACLKR, &mcasp->pdir); | ||
525 | /* Frame Sync */ | ||
526 | set_bit(PIN_BIT_AFSX, &mcasp->pdir); | ||
527 | set_bit(PIN_BIT_AFSR, &mcasp->pdir); | ||
528 | |||
473 | mcasp->bclk_master = 0; | 529 | mcasp->bclk_master = 0; |
474 | break; | 530 | break; |
475 | case SND_SOC_DAIFMT_CBM_CFM: | 531 | case SND_SOC_DAIFMT_CBM_CFM: |
@@ -480,8 +536,13 @@ static int davinci_mcasp_set_dai_fmt(struct snd_soc_dai *cpu_dai, | |||
480 | mcasp_clr_bits(mcasp, DAVINCI_MCASP_ACLKRCTL_REG, ACLKRE); | 536 | mcasp_clr_bits(mcasp, DAVINCI_MCASP_ACLKRCTL_REG, ACLKRE); |
481 | mcasp_clr_bits(mcasp, DAVINCI_MCASP_RXFMCTL_REG, AFSRE); | 537 | mcasp_clr_bits(mcasp, DAVINCI_MCASP_RXFMCTL_REG, AFSRE); |
482 | 538 | ||
483 | mcasp_clr_bits(mcasp, DAVINCI_MCASP_PDIR_REG, | 539 | /* BCLK */ |
484 | ACLKX | AFSX | ACLKR | AHCLKR | AFSR); | 540 | clear_bit(PIN_BIT_ACLKX, &mcasp->pdir); |
541 | clear_bit(PIN_BIT_ACLKR, &mcasp->pdir); | ||
542 | /* Frame Sync */ | ||
543 | clear_bit(PIN_BIT_AFSX, &mcasp->pdir); | ||
544 | clear_bit(PIN_BIT_AFSR, &mcasp->pdir); | ||
545 | |||
485 | mcasp->bclk_master = 0; | 546 | mcasp->bclk_master = 0; |
486 | break; | 547 | break; |
487 | default: | 548 | default: |
@@ -596,11 +657,11 @@ static int davinci_mcasp_set_sysclk(struct snd_soc_dai *dai, int clk_id, | |||
596 | if (dir == SND_SOC_CLOCK_OUT) { | 657 | if (dir == SND_SOC_CLOCK_OUT) { |
597 | mcasp_set_bits(mcasp, DAVINCI_MCASP_AHCLKXCTL_REG, AHCLKXE); | 658 | mcasp_set_bits(mcasp, DAVINCI_MCASP_AHCLKXCTL_REG, AHCLKXE); |
598 | mcasp_set_bits(mcasp, DAVINCI_MCASP_AHCLKRCTL_REG, AHCLKRE); | 659 | mcasp_set_bits(mcasp, DAVINCI_MCASP_AHCLKRCTL_REG, AHCLKRE); |
599 | mcasp_set_bits(mcasp, DAVINCI_MCASP_PDIR_REG, AHCLKX); | 660 | set_bit(PIN_BIT_AHCLKX, &mcasp->pdir); |
600 | } else { | 661 | } else { |
601 | mcasp_clr_bits(mcasp, DAVINCI_MCASP_AHCLKXCTL_REG, AHCLKXE); | 662 | mcasp_clr_bits(mcasp, DAVINCI_MCASP_AHCLKXCTL_REG, AHCLKXE); |
602 | mcasp_clr_bits(mcasp, DAVINCI_MCASP_AHCLKRCTL_REG, AHCLKRE); | 663 | mcasp_clr_bits(mcasp, DAVINCI_MCASP_AHCLKRCTL_REG, AHCLKRE); |
603 | mcasp_clr_bits(mcasp, DAVINCI_MCASP_PDIR_REG, AHCLKX); | 664 | clear_bit(PIN_BIT_AHCLKX, &mcasp->pdir); |
604 | } | 665 | } |
605 | 666 | ||
606 | mcasp->sysclk_freq = freq; | 667 | mcasp->sysclk_freq = freq; |
@@ -773,17 +834,23 @@ static int mcasp_common_hw_param(struct davinci_mcasp *mcasp, int stream, | |||
773 | mcasp->serial_dir[i]); | 834 | mcasp->serial_dir[i]); |
774 | if (mcasp->serial_dir[i] == TX_MODE && | 835 | if (mcasp->serial_dir[i] == TX_MODE && |
775 | tx_ser < max_active_serializers) { | 836 | tx_ser < max_active_serializers) { |
776 | mcasp_set_bits(mcasp, DAVINCI_MCASP_PDIR_REG, AXR(i)); | ||
777 | mcasp_mod_bits(mcasp, DAVINCI_MCASP_XRSRCTL_REG(i), | 837 | mcasp_mod_bits(mcasp, DAVINCI_MCASP_XRSRCTL_REG(i), |
778 | DISMOD_LOW, DISMOD_MASK); | 838 | mcasp->dismod, DISMOD_MASK); |
839 | set_bit(PIN_BIT_AXR(i), &mcasp->pdir); | ||
779 | tx_ser++; | 840 | tx_ser++; |
780 | } else if (mcasp->serial_dir[i] == RX_MODE && | 841 | } else if (mcasp->serial_dir[i] == RX_MODE && |
781 | rx_ser < max_active_serializers) { | 842 | rx_ser < max_active_serializers) { |
782 | mcasp_clr_bits(mcasp, DAVINCI_MCASP_PDIR_REG, AXR(i)); | 843 | clear_bit(PIN_BIT_AXR(i), &mcasp->pdir); |
783 | rx_ser++; | 844 | rx_ser++; |
784 | } else if (mcasp->serial_dir[i] == INACTIVE_MODE) { | 845 | } else if (mcasp->serial_dir[i] == INACTIVE_MODE) { |
785 | mcasp_mod_bits(mcasp, DAVINCI_MCASP_XRSRCTL_REG(i), | 846 | mcasp_mod_bits(mcasp, DAVINCI_MCASP_XRSRCTL_REG(i), |
786 | SRMOD_INACTIVE, SRMOD_MASK); | 847 | SRMOD_INACTIVE, SRMOD_MASK); |
848 | clear_bit(PIN_BIT_AXR(i), &mcasp->pdir); | ||
849 | } else if (mcasp->serial_dir[i] == TX_MODE) { | ||
850 | /* Unused TX pins, clear PDIR */ | ||
851 | mcasp_mod_bits(mcasp, DAVINCI_MCASP_XRSRCTL_REG(i), | ||
852 | mcasp->dismod, DISMOD_MASK); | ||
853 | clear_bit(PIN_BIT_AXR(i), &mcasp->pdir); | ||
787 | } | 854 | } |
788 | } | 855 | } |
789 | 856 | ||
@@ -1645,6 +1712,7 @@ static struct davinci_mcasp_pdata *davinci_mcasp_set_pdata_from_of( | |||
1645 | 1712 | ||
1646 | if (pdev->dev.platform_data) { | 1713 | if (pdev->dev.platform_data) { |
1647 | pdata = pdev->dev.platform_data; | 1714 | pdata = pdev->dev.platform_data; |
1715 | pdata->dismod = DISMOD_LOW; | ||
1648 | return pdata; | 1716 | return pdata; |
1649 | } else if (match) { | 1717 | } else if (match) { |
1650 | pdata = devm_kmemdup(&pdev->dev, match->data, sizeof(*pdata), | 1718 | pdata = devm_kmemdup(&pdev->dev, match->data, sizeof(*pdata), |
@@ -1734,6 +1802,18 @@ static struct davinci_mcasp_pdata *davinci_mcasp_set_pdata_from_of( | |||
1734 | if (ret >= 0) | 1802 | if (ret >= 0) |
1735 | pdata->sram_size_capture = val; | 1803 | pdata->sram_size_capture = val; |
1736 | 1804 | ||
1805 | ret = of_property_read_u32(np, "dismod", &val); | ||
1806 | if (ret >= 0) { | ||
1807 | if (val == 0 || val == 2 || val == 3) { | ||
1808 | pdata->dismod = DISMOD_VAL(val); | ||
1809 | } else { | ||
1810 | dev_warn(&pdev->dev, "Invalid dismod value: %u\n", val); | ||
1811 | pdata->dismod = DISMOD_LOW; | ||
1812 | } | ||
1813 | } else { | ||
1814 | pdata->dismod = DISMOD_LOW; | ||
1815 | } | ||
1816 | |||
1737 | return pdata; | 1817 | return pdata; |
1738 | 1818 | ||
1739 | nodata: | 1819 | nodata: |
@@ -1909,6 +1989,7 @@ static int davinci_mcasp_probe(struct platform_device *pdev) | |||
1909 | mcasp->version = pdata->version; | 1989 | mcasp->version = pdata->version; |
1910 | mcasp->txnumevt = pdata->txnumevt; | 1990 | mcasp->txnumevt = pdata->txnumevt; |
1911 | mcasp->rxnumevt = pdata->rxnumevt; | 1991 | mcasp->rxnumevt = pdata->rxnumevt; |
1992 | mcasp->dismod = pdata->dismod; | ||
1912 | 1993 | ||
1913 | mcasp->dev = &pdev->dev; | 1994 | mcasp->dev = &pdev->dev; |
1914 | 1995 | ||
@@ -2068,9 +2149,9 @@ static int davinci_mcasp_probe(struct platform_device *pdev) | |||
2068 | ret = davinci_mcasp_get_dma_type(mcasp); | 2149 | ret = davinci_mcasp_get_dma_type(mcasp); |
2069 | switch (ret) { | 2150 | switch (ret) { |
2070 | case PCM_EDMA: | 2151 | case PCM_EDMA: |
2071 | #if IS_BUILTIN(CONFIG_SND_EDMA_SOC) || \ | 2152 | #if IS_BUILTIN(CONFIG_SND_SOC_TI_EDMA_PCM) || \ |
2072 | (IS_MODULE(CONFIG_SND_DAVINCI_SOC_MCASP) && \ | 2153 | (IS_MODULE(CONFIG_SND_SOC_DAVINCI_MCASP) && \ |
2073 | IS_MODULE(CONFIG_SND_EDMA_SOC)) | 2154 | IS_MODULE(CONFIG_SND_SOC_TI_EDMA_PCM)) |
2074 | ret = edma_pcm_platform_register(&pdev->dev); | 2155 | ret = edma_pcm_platform_register(&pdev->dev); |
2075 | #else | 2156 | #else |
2076 | dev_err(&pdev->dev, "Missing SND_EDMA_SOC\n"); | 2157 | dev_err(&pdev->dev, "Missing SND_EDMA_SOC\n"); |
@@ -2079,9 +2160,9 @@ static int davinci_mcasp_probe(struct platform_device *pdev) | |||
2079 | #endif | 2160 | #endif |
2080 | break; | 2161 | break; |
2081 | case PCM_SDMA: | 2162 | case PCM_SDMA: |
2082 | #if IS_BUILTIN(CONFIG_SND_SDMA_SOC) || \ | 2163 | #if IS_BUILTIN(CONFIG_SND_SOC_TI_SDMA_PCM) || \ |
2083 | (IS_MODULE(CONFIG_SND_DAVINCI_SOC_MCASP) && \ | 2164 | (IS_MODULE(CONFIG_SND_SOC_DAVINCI_MCASP) && \ |
2084 | IS_MODULE(CONFIG_SND_SDMA_SOC)) | 2165 | IS_MODULE(CONFIG_SND_SOC_TI_SDMA_PCM)) |
2085 | ret = sdma_pcm_platform_register(&pdev->dev, NULL, NULL); | 2166 | ret = sdma_pcm_platform_register(&pdev->dev, NULL, NULL); |
2086 | #else | 2167 | #else |
2087 | dev_err(&pdev->dev, "Missing SND_SDMA_SOC\n"); | 2168 | dev_err(&pdev->dev, "Missing SND_SDMA_SOC\n"); |
diff --git a/sound/soc/davinci/davinci-mcasp.h b/sound/soc/ti/davinci-mcasp.h index afddc8010c54..5e4060d8fe56 100644 --- a/sound/soc/davinci/davinci-mcasp.h +++ b/sound/soc/ti/davinci-mcasp.h | |||
@@ -108,27 +108,18 @@ | |||
108 | 108 | ||
109 | /* | 109 | /* |
110 | * DAVINCI_MCASP_PFUNC_REG - Pin Function / GPIO Enable Register Bits | 110 | * DAVINCI_MCASP_PFUNC_REG - Pin Function / GPIO Enable Register Bits |
111 | */ | ||
112 | #define AXR(n) (1<<n) | ||
113 | #define PFUNC_AMUTE BIT(25) | ||
114 | #define ACLKX BIT(26) | ||
115 | #define AHCLKX BIT(27) | ||
116 | #define AFSX BIT(28) | ||
117 | #define ACLKR BIT(29) | ||
118 | #define AHCLKR BIT(30) | ||
119 | #define AFSR BIT(31) | ||
120 | |||
121 | /* | ||
122 | * DAVINCI_MCASP_PDIR_REG - Pin Direction Register Bits | 111 | * DAVINCI_MCASP_PDIR_REG - Pin Direction Register Bits |
112 | * DAVINCI_MCASP_PDOUT_REG - Pin output in GPIO mode | ||
113 | * DAVINCI_MCASP_PDSET_REG - Pin input in GPIO mode | ||
123 | */ | 114 | */ |
124 | #define AXR(n) (1<<n) | 115 | #define PIN_BIT_AXR(n) (n) |
125 | #define PDIR_AMUTE BIT(25) | 116 | #define PIN_BIT_AMUTE 25 |
126 | #define ACLKX BIT(26) | 117 | #define PIN_BIT_ACLKX 26 |
127 | #define AHCLKX BIT(27) | 118 | #define PIN_BIT_AHCLKX 27 |
128 | #define AFSX BIT(28) | 119 | #define PIN_BIT_AFSX 28 |
129 | #define ACLKR BIT(29) | 120 | #define PIN_BIT_ACLKR 29 |
130 | #define AHCLKR BIT(30) | 121 | #define PIN_BIT_AHCLKR 30 |
131 | #define AFSR BIT(31) | 122 | #define PIN_BIT_AFSR 31 |
132 | 123 | ||
133 | /* | 124 | /* |
134 | * DAVINCI_MCASP_TXDITCTL_REG - Transmit DIT Control Register Bits | 125 | * DAVINCI_MCASP_TXDITCTL_REG - Transmit DIT Control Register Bits |
@@ -218,6 +209,7 @@ | |||
218 | #define DISMOD_3STATE (0x0) | 209 | #define DISMOD_3STATE (0x0) |
219 | #define DISMOD_LOW (0x2 << 2) | 210 | #define DISMOD_LOW (0x2 << 2) |
220 | #define DISMOD_HIGH (0x3 << 2) | 211 | #define DISMOD_HIGH (0x3 << 2) |
212 | #define DISMOD_VAL(x) ((x) << 2) | ||
221 | #define DISMOD_MASK DISMOD_HIGH | 213 | #define DISMOD_MASK DISMOD_HIGH |
222 | #define TXSTATE BIT(4) | 214 | #define TXSTATE BIT(4) |
223 | #define RXSTATE BIT(5) | 215 | #define RXSTATE BIT(5) |
diff --git a/sound/soc/davinci/davinci-vcif.c b/sound/soc/ti/davinci-vcif.c index 5415b72393fa..5415b72393fa 100644 --- a/sound/soc/davinci/davinci-vcif.c +++ b/sound/soc/ti/davinci-vcif.c | |||
diff --git a/sound/soc/davinci/edma-pcm.c b/sound/soc/ti/edma-pcm.c index 59e588abe54b..59e588abe54b 100644 --- a/sound/soc/davinci/edma-pcm.c +++ b/sound/soc/ti/edma-pcm.c | |||
diff --git a/sound/soc/davinci/edma-pcm.h b/sound/soc/ti/edma-pcm.h index b0957744851c..8058bdb0f032 100644 --- a/sound/soc/davinci/edma-pcm.h +++ b/sound/soc/ti/edma-pcm.h | |||
@@ -20,13 +20,13 @@ | |||
20 | #ifndef __EDMA_PCM_H__ | 20 | #ifndef __EDMA_PCM_H__ |
21 | #define __EDMA_PCM_H__ | 21 | #define __EDMA_PCM_H__ |
22 | 22 | ||
23 | #if IS_ENABLED(CONFIG_SND_EDMA_SOC) | 23 | #if IS_ENABLED(CONFIG_SND_SOC_TI_EDMA_PCM) |
24 | int edma_pcm_platform_register(struct device *dev); | 24 | int edma_pcm_platform_register(struct device *dev); |
25 | #else | 25 | #else |
26 | static inline int edma_pcm_platform_register(struct device *dev) | 26 | static inline int edma_pcm_platform_register(struct device *dev) |
27 | { | 27 | { |
28 | return 0; | 28 | return 0; |
29 | } | 29 | } |
30 | #endif /* CONFIG_SND_EDMA_SOC */ | 30 | #endif /* CONFIG_SND_SOC_TI_EDMA_PCM */ |
31 | 31 | ||
32 | #endif /* __EDMA_PCM_H__ */ | 32 | #endif /* __EDMA_PCM_H__ */ |
diff --git a/sound/soc/omap/n810.c b/sound/soc/ti/n810.c index 9cfefe44a75f..9cfefe44a75f 100644 --- a/sound/soc/omap/n810.c +++ b/sound/soc/ti/n810.c | |||
diff --git a/sound/soc/omap/omap-abe-twl6040.c b/sound/soc/ti/omap-abe-twl6040.c index fed45b41f9d3..fed45b41f9d3 100644 --- a/sound/soc/omap/omap-abe-twl6040.c +++ b/sound/soc/ti/omap-abe-twl6040.c | |||
diff --git a/sound/soc/omap/omap-dmic.c b/sound/soc/ti/omap-dmic.c index cba9645b6487..cba9645b6487 100644 --- a/sound/soc/omap/omap-dmic.c +++ b/sound/soc/ti/omap-dmic.c | |||
diff --git a/sound/soc/omap/omap-dmic.h b/sound/soc/ti/omap-dmic.h index 231e728bff0e..231e728bff0e 100644 --- a/sound/soc/omap/omap-dmic.h +++ b/sound/soc/ti/omap-dmic.h | |||
diff --git a/sound/soc/omap/omap-hdmi-audio.c b/sound/soc/ti/omap-hdmi.c index 673a9eb153b2..673a9eb153b2 100644 --- a/sound/soc/omap/omap-hdmi-audio.c +++ b/sound/soc/ti/omap-hdmi.c | |||
diff --git a/sound/soc/omap/mcbsp.h b/sound/soc/ti/omap-mcbsp-priv.h index 46ae1269a698..7865cda4bf0a 100644 --- a/sound/soc/omap/mcbsp.h +++ b/sound/soc/ti/omap-mcbsp-priv.h | |||
@@ -1,28 +1,15 @@ | |||
1 | /* SPDX-License-Identifier: GPL-2.0 */ | ||
1 | /* | 2 | /* |
2 | * sound/soc/omap/mcbsp.h | ||
3 | * | ||
4 | * OMAP Multi-Channel Buffered Serial Port | 3 | * OMAP Multi-Channel Buffered Serial Port |
5 | * | 4 | * |
6 | * Contact: Jarkko Nikula <jarkko.nikula@bitmer.com> | 5 | * Contact: Jarkko Nikula <jarkko.nikula@bitmer.com> |
7 | * Peter Ujfalusi <peter.ujfalusi@ti.com> | 6 | * Peter Ujfalusi <peter.ujfalusi@ti.com> |
8 | * | ||
9 | * This program is free software; you can redistribute it and/or modify | ||
10 | * it under the terms of the GNU General Public License as published by | ||
11 | * the Free Software Foundation; either version 2 of the License, or | ||
12 | * (at your option) any later version. | ||
13 | * | ||
14 | * This program is distributed in the hope that it will be useful, | ||
15 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
16 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
17 | * GNU General Public License for more details. | ||
18 | * | ||
19 | * You should have received a copy of the GNU General Public License | ||
20 | * along with this program; if not, write to the Free Software | ||
21 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
22 | * | ||
23 | */ | 7 | */ |
24 | #ifndef __ASOC_MCBSP_H | 8 | |
25 | #define __ASOC_MCBSP_H | 9 | #ifndef __OMAP_MCBSP_PRIV_H__ |
10 | #define __OMAP_MCBSP_PRIV_H__ | ||
11 | |||
12 | #include <linux/platform_data/asoc-ti-mcbsp.h> | ||
26 | 13 | ||
27 | #ifdef CONFIG_ARCH_OMAP1 | 14 | #ifdef CONFIG_ARCH_OMAP1 |
28 | #define mcbsp_omap1() 1 | 15 | #define mcbsp_omap1() 1 |
@@ -30,8 +17,6 @@ | |||
30 | #define mcbsp_omap1() 0 | 17 | #define mcbsp_omap1() 0 |
31 | #endif | 18 | #endif |
32 | 19 | ||
33 | #include <sound/dmaengine_pcm.h> | ||
34 | |||
35 | /* McBSP register numbers. Register address offset = num * reg_step */ | 20 | /* McBSP register numbers. Register address offset = num * reg_step */ |
36 | enum { | 21 | enum { |
37 | /* Common registers */ | 22 | /* Common registers */ |
@@ -85,15 +70,6 @@ enum { | |||
85 | OMAP_MCBSP_REG_SSELCR, | 70 | OMAP_MCBSP_REG_SSELCR, |
86 | }; | 71 | }; |
87 | 72 | ||
88 | /* OMAP3 sidetone control registers */ | ||
89 | #define OMAP_ST_REG_REV 0x00 | ||
90 | #define OMAP_ST_REG_SYSCONFIG 0x10 | ||
91 | #define OMAP_ST_REG_IRQSTATUS 0x18 | ||
92 | #define OMAP_ST_REG_IRQENABLE 0x1C | ||
93 | #define OMAP_ST_REG_SGAINCR 0x24 | ||
94 | #define OMAP_ST_REG_SFIRCR 0x28 | ||
95 | #define OMAP_ST_REG_SSELCR 0x2C | ||
96 | |||
97 | /************************** McBSP SPCR1 bit definitions ***********************/ | 73 | /************************** McBSP SPCR1 bit definitions ***********************/ |
98 | #define RRST BIT(0) | 74 | #define RRST BIT(0) |
99 | #define RRDY BIT(1) | 75 | #define RRDY BIT(1) |
@@ -202,24 +178,6 @@ enum { | |||
202 | #define SIDLEMODE(value) (((value) & 0x3) << 3) | 178 | #define SIDLEMODE(value) (((value) & 0x3) << 3) |
203 | #define CLOCKACTIVITY(value) (((value) & 0x3) << 8) | 179 | #define CLOCKACTIVITY(value) (((value) & 0x3) << 8) |
204 | 180 | ||
205 | /********************** McBSP SSELCR bit definitions ***********************/ | ||
206 | #define SIDETONEEN BIT(10) | ||
207 | |||
208 | /********************** McBSP Sidetone SYSCONFIG bit definitions ***********/ | ||
209 | #define ST_AUTOIDLE BIT(0) | ||
210 | |||
211 | /********************** McBSP Sidetone SGAINCR bit definitions *************/ | ||
212 | #define ST_CH0GAIN(value) ((value) & 0xffff) /* Bits 0:15 */ | ||
213 | #define ST_CH1GAIN(value) (((value) & 0xffff) << 16) /* Bits 16:31 */ | ||
214 | |||
215 | /********************** McBSP Sidetone SFIRCR bit definitions **************/ | ||
216 | #define ST_FIRCOEFF(value) ((value) & 0xffff) /* Bits 0:15 */ | ||
217 | |||
218 | /********************** McBSP Sidetone SSELCR bit definitions **************/ | ||
219 | #define ST_SIDETONEEN BIT(0) | ||
220 | #define ST_COEFFWREN BIT(1) | ||
221 | #define ST_COEFFWRDONE BIT(2) | ||
222 | |||
223 | /********************** McBSP DMA operating modes **************************/ | 181 | /********************** McBSP DMA operating modes **************************/ |
224 | #define MCBSP_DMA_MODE_ELEMENT 0 | 182 | #define MCBSP_DMA_MODE_ELEMENT 0 |
225 | #define MCBSP_DMA_MODE_THRESHOLD 1 | 183 | #define MCBSP_DMA_MODE_THRESHOLD 1 |
@@ -278,16 +236,7 @@ struct omap_mcbsp_reg_cfg { | |||
278 | u16 rccr; | 236 | u16 rccr; |
279 | }; | 237 | }; |
280 | 238 | ||
281 | struct omap_mcbsp_st_data { | 239 | struct omap_mcbsp_st_data; |
282 | void __iomem *io_base_st; | ||
283 | struct clk *mcbsp_iclk; | ||
284 | bool running; | ||
285 | bool enabled; | ||
286 | s16 taps[128]; /* Sidetone filter coefficients */ | ||
287 | int nr_taps; /* Number of filter coefficients in use */ | ||
288 | s16 ch0gain; | ||
289 | s16 ch1gain; | ||
290 | }; | ||
291 | 240 | ||
292 | struct omap_mcbsp { | 241 | struct omap_mcbsp { |
293 | struct device *dev; | 242 | struct device *dev; |
@@ -330,29 +279,46 @@ struct omap_mcbsp { | |||
330 | struct pm_qos_request pm_qos_req; | 279 | struct pm_qos_request pm_qos_req; |
331 | }; | 280 | }; |
332 | 281 | ||
333 | void omap_mcbsp_config(struct omap_mcbsp *mcbsp, | 282 | static inline void omap_mcbsp_write(struct omap_mcbsp *mcbsp, u16 reg, u32 val) |
334 | const struct omap_mcbsp_reg_cfg *config); | 283 | { |
335 | void omap_mcbsp_set_tx_threshold(struct omap_mcbsp *mcbsp, u16 threshold); | 284 | void __iomem *addr = mcbsp->io_base + reg * mcbsp->pdata->reg_step; |
336 | void omap_mcbsp_set_rx_threshold(struct omap_mcbsp *mcbsp, u16 threshold); | 285 | |
337 | u16 omap_mcbsp_get_tx_delay(struct omap_mcbsp *mcbsp); | 286 | if (mcbsp->pdata->reg_size == 2) { |
338 | u16 omap_mcbsp_get_rx_delay(struct omap_mcbsp *mcbsp); | 287 | ((u16 *)mcbsp->reg_cache)[reg] = (u16)val; |
339 | int omap_mcbsp_get_dma_op_mode(struct omap_mcbsp *mcbsp); | 288 | writew_relaxed((u16)val, addr); |
340 | int omap_mcbsp_request(struct omap_mcbsp *mcbsp); | 289 | } else { |
341 | void omap_mcbsp_free(struct omap_mcbsp *mcbsp); | 290 | ((u32 *)mcbsp->reg_cache)[reg] = val; |
342 | void omap_mcbsp_start(struct omap_mcbsp *mcbsp, int tx, int rx); | 291 | writel_relaxed(val, addr); |
343 | void omap_mcbsp_stop(struct omap_mcbsp *mcbsp, int tx, int rx); | 292 | } |
344 | 293 | } | |
345 | /* McBSP functional clock source changing function */ | 294 | |
346 | int omap2_mcbsp_set_clks_src(struct omap_mcbsp *mcbsp, u8 fck_src_id); | 295 | static inline int omap_mcbsp_read(struct omap_mcbsp *mcbsp, u16 reg, |
296 | bool from_cache) | ||
297 | { | ||
298 | void __iomem *addr = mcbsp->io_base + reg * mcbsp->pdata->reg_step; | ||
299 | |||
300 | if (mcbsp->pdata->reg_size == 2) { | ||
301 | return !from_cache ? readw_relaxed(addr) : | ||
302 | ((u16 *)mcbsp->reg_cache)[reg]; | ||
303 | } else { | ||
304 | return !from_cache ? readl_relaxed(addr) : | ||
305 | ((u32 *)mcbsp->reg_cache)[reg]; | ||
306 | } | ||
307 | } | ||
308 | |||
309 | #define MCBSP_READ(mcbsp, reg) \ | ||
310 | omap_mcbsp_read(mcbsp, OMAP_MCBSP_REG_##reg, 0) | ||
311 | #define MCBSP_WRITE(mcbsp, reg, val) \ | ||
312 | omap_mcbsp_write(mcbsp, OMAP_MCBSP_REG_##reg, val) | ||
313 | #define MCBSP_READ_CACHE(mcbsp, reg) \ | ||
314 | omap_mcbsp_read(mcbsp, OMAP_MCBSP_REG_##reg, 1) | ||
315 | |||
347 | 316 | ||
348 | /* Sidetone specific API */ | 317 | /* Sidetone specific API */ |
349 | int omap_st_set_chgain(struct omap_mcbsp *mcbsp, int channel, s16 chgain); | 318 | int omap_mcbsp_st_init(struct platform_device *pdev); |
350 | int omap_st_get_chgain(struct omap_mcbsp *mcbsp, int channel, s16 *chgain); | 319 | void omap_mcbsp_st_cleanup(struct platform_device *pdev); |
351 | int omap_st_enable(struct omap_mcbsp *mcbsp); | ||
352 | int omap_st_disable(struct omap_mcbsp *mcbsp); | ||
353 | int omap_st_is_enabled(struct omap_mcbsp *mcbsp); | ||
354 | 320 | ||
355 | int omap_mcbsp_init(struct platform_device *pdev); | 321 | int omap_mcbsp_st_start(struct omap_mcbsp *mcbsp); |
356 | void omap_mcbsp_cleanup(struct omap_mcbsp *mcbsp); | 322 | int omap_mcbsp_st_stop(struct omap_mcbsp *mcbsp); |
357 | 323 | ||
358 | #endif /* __ASOC_MCBSP_H */ | 324 | #endif /* __OMAP_MCBSP_PRIV_H__ */ |
diff --git a/sound/soc/ti/omap-mcbsp-st.c b/sound/soc/ti/omap-mcbsp-st.c new file mode 100644 index 000000000000..1a3fe854e856 --- /dev/null +++ b/sound/soc/ti/omap-mcbsp-st.c | |||
@@ -0,0 +1,516 @@ | |||
1 | // SPDX-License-Identifier: GPL-2.0 | ||
2 | /* | ||
3 | * McBSP Sidetone support | ||
4 | * | ||
5 | * Copyright (C) 2004 Nokia Corporation | ||
6 | * Author: Samuel Ortiz <samuel.ortiz@nokia.com> | ||
7 | * | ||
8 | * Contact: Jarkko Nikula <jarkko.nikula@bitmer.com> | ||
9 | * Peter Ujfalusi <peter.ujfalusi@ti.com> | ||
10 | */ | ||
11 | |||
12 | #include <linux/module.h> | ||
13 | #include <linux/init.h> | ||
14 | #include <linux/device.h> | ||
15 | #include <linux/platform_device.h> | ||
16 | #include <linux/interrupt.h> | ||
17 | #include <linux/err.h> | ||
18 | #include <linux/clk.h> | ||
19 | #include <linux/delay.h> | ||
20 | #include <linux/io.h> | ||
21 | #include <linux/slab.h> | ||
22 | #include <linux/pm_runtime.h> | ||
23 | |||
24 | #include "omap-mcbsp.h" | ||
25 | #include "omap-mcbsp-priv.h" | ||
26 | |||
27 | /* OMAP3 sidetone control registers */ | ||
28 | #define OMAP_ST_REG_REV 0x00 | ||
29 | #define OMAP_ST_REG_SYSCONFIG 0x10 | ||
30 | #define OMAP_ST_REG_IRQSTATUS 0x18 | ||
31 | #define OMAP_ST_REG_IRQENABLE 0x1C | ||
32 | #define OMAP_ST_REG_SGAINCR 0x24 | ||
33 | #define OMAP_ST_REG_SFIRCR 0x28 | ||
34 | #define OMAP_ST_REG_SSELCR 0x2C | ||
35 | |||
36 | /********************** McBSP SSELCR bit definitions ***********************/ | ||
37 | #define SIDETONEEN BIT(10) | ||
38 | |||
39 | /********************** McBSP Sidetone SYSCONFIG bit definitions ***********/ | ||
40 | #define ST_AUTOIDLE BIT(0) | ||
41 | |||
42 | /********************** McBSP Sidetone SGAINCR bit definitions *************/ | ||
43 | #define ST_CH0GAIN(value) ((value) & 0xffff) /* Bits 0:15 */ | ||
44 | #define ST_CH1GAIN(value) (((value) & 0xffff) << 16) /* Bits 16:31 */ | ||
45 | |||
46 | /********************** McBSP Sidetone SFIRCR bit definitions **************/ | ||
47 | #define ST_FIRCOEFF(value) ((value) & 0xffff) /* Bits 0:15 */ | ||
48 | |||
49 | /********************** McBSP Sidetone SSELCR bit definitions **************/ | ||
50 | #define ST_SIDETONEEN BIT(0) | ||
51 | #define ST_COEFFWREN BIT(1) | ||
52 | #define ST_COEFFWRDONE BIT(2) | ||
53 | |||
54 | struct omap_mcbsp_st_data { | ||
55 | void __iomem *io_base_st; | ||
56 | struct clk *mcbsp_iclk; | ||
57 | bool running; | ||
58 | bool enabled; | ||
59 | s16 taps[128]; /* Sidetone filter coefficients */ | ||
60 | int nr_taps; /* Number of filter coefficients in use */ | ||
61 | s16 ch0gain; | ||
62 | s16 ch1gain; | ||
63 | }; | ||
64 | |||
65 | static void omap_mcbsp_st_write(struct omap_mcbsp *mcbsp, u16 reg, u32 val) | ||
66 | { | ||
67 | writel_relaxed(val, mcbsp->st_data->io_base_st + reg); | ||
68 | } | ||
69 | |||
70 | static int omap_mcbsp_st_read(struct omap_mcbsp *mcbsp, u16 reg) | ||
71 | { | ||
72 | return readl_relaxed(mcbsp->st_data->io_base_st + reg); | ||
73 | } | ||
74 | |||
75 | #define MCBSP_ST_READ(mcbsp, reg) omap_mcbsp_st_read(mcbsp, OMAP_ST_REG_##reg) | ||
76 | #define MCBSP_ST_WRITE(mcbsp, reg, val) \ | ||
77 | omap_mcbsp_st_write(mcbsp, OMAP_ST_REG_##reg, val) | ||
78 | |||
79 | static void omap_mcbsp_st_on(struct omap_mcbsp *mcbsp) | ||
80 | { | ||
81 | unsigned int w; | ||
82 | |||
83 | if (mcbsp->pdata->force_ick_on) | ||
84 | mcbsp->pdata->force_ick_on(mcbsp->st_data->mcbsp_iclk, true); | ||
85 | |||
86 | /* Disable Sidetone clock auto-gating for normal operation */ | ||
87 | w = MCBSP_ST_READ(mcbsp, SYSCONFIG); | ||
88 | MCBSP_ST_WRITE(mcbsp, SYSCONFIG, w & ~(ST_AUTOIDLE)); | ||
89 | |||
90 | /* Enable McBSP Sidetone */ | ||
91 | w = MCBSP_READ(mcbsp, SSELCR); | ||
92 | MCBSP_WRITE(mcbsp, SSELCR, w | SIDETONEEN); | ||
93 | |||
94 | /* Enable Sidetone from Sidetone Core */ | ||
95 | w = MCBSP_ST_READ(mcbsp, SSELCR); | ||
96 | MCBSP_ST_WRITE(mcbsp, SSELCR, w | ST_SIDETONEEN); | ||
97 | } | ||
98 | |||
99 | static void omap_mcbsp_st_off(struct omap_mcbsp *mcbsp) | ||
100 | { | ||
101 | unsigned int w; | ||
102 | |||
103 | w = MCBSP_ST_READ(mcbsp, SSELCR); | ||
104 | MCBSP_ST_WRITE(mcbsp, SSELCR, w & ~(ST_SIDETONEEN)); | ||
105 | |||
106 | w = MCBSP_READ(mcbsp, SSELCR); | ||
107 | MCBSP_WRITE(mcbsp, SSELCR, w & ~(SIDETONEEN)); | ||
108 | |||
109 | /* Enable Sidetone clock auto-gating to reduce power consumption */ | ||
110 | w = MCBSP_ST_READ(mcbsp, SYSCONFIG); | ||
111 | MCBSP_ST_WRITE(mcbsp, SYSCONFIG, w | ST_AUTOIDLE); | ||
112 | |||
113 | if (mcbsp->pdata->force_ick_on) | ||
114 | mcbsp->pdata->force_ick_on(mcbsp->st_data->mcbsp_iclk, false); | ||
115 | } | ||
116 | |||
117 | static void omap_mcbsp_st_fir_write(struct omap_mcbsp *mcbsp, s16 *fir) | ||
118 | { | ||
119 | u16 val, i; | ||
120 | |||
121 | val = MCBSP_ST_READ(mcbsp, SSELCR); | ||
122 | |||
123 | if (val & ST_COEFFWREN) | ||
124 | MCBSP_ST_WRITE(mcbsp, SSELCR, val & ~(ST_COEFFWREN)); | ||
125 | |||
126 | MCBSP_ST_WRITE(mcbsp, SSELCR, val | ST_COEFFWREN); | ||
127 | |||
128 | for (i = 0; i < 128; i++) | ||
129 | MCBSP_ST_WRITE(mcbsp, SFIRCR, fir[i]); | ||
130 | |||
131 | i = 0; | ||
132 | |||
133 | val = MCBSP_ST_READ(mcbsp, SSELCR); | ||
134 | while (!(val & ST_COEFFWRDONE) && (++i < 1000)) | ||
135 | val = MCBSP_ST_READ(mcbsp, SSELCR); | ||
136 | |||
137 | MCBSP_ST_WRITE(mcbsp, SSELCR, val & ~(ST_COEFFWREN)); | ||
138 | |||
139 | if (i == 1000) | ||
140 | dev_err(mcbsp->dev, "McBSP FIR load error!\n"); | ||
141 | } | ||
142 | |||
143 | static void omap_mcbsp_st_chgain(struct omap_mcbsp *mcbsp) | ||
144 | { | ||
145 | u16 w; | ||
146 | struct omap_mcbsp_st_data *st_data = mcbsp->st_data; | ||
147 | |||
148 | w = MCBSP_ST_READ(mcbsp, SSELCR); | ||
149 | |||
150 | MCBSP_ST_WRITE(mcbsp, SGAINCR, ST_CH0GAIN(st_data->ch0gain) | | ||
151 | ST_CH1GAIN(st_data->ch1gain)); | ||
152 | } | ||
153 | |||
154 | static int omap_mcbsp_st_set_chgain(struct omap_mcbsp *mcbsp, int channel, | ||
155 | s16 chgain) | ||
156 | { | ||
157 | struct omap_mcbsp_st_data *st_data = mcbsp->st_data; | ||
158 | int ret = 0; | ||
159 | |||
160 | if (!st_data) | ||
161 | return -ENOENT; | ||
162 | |||
163 | spin_lock_irq(&mcbsp->lock); | ||
164 | if (channel == 0) | ||
165 | st_data->ch0gain = chgain; | ||
166 | else if (channel == 1) | ||
167 | st_data->ch1gain = chgain; | ||
168 | else | ||
169 | ret = -EINVAL; | ||
170 | |||
171 | if (st_data->enabled) | ||
172 | omap_mcbsp_st_chgain(mcbsp); | ||
173 | spin_unlock_irq(&mcbsp->lock); | ||
174 | |||
175 | return ret; | ||
176 | } | ||
177 | |||
178 | static int omap_mcbsp_st_get_chgain(struct omap_mcbsp *mcbsp, int channel, | ||
179 | s16 *chgain) | ||
180 | { | ||
181 | struct omap_mcbsp_st_data *st_data = mcbsp->st_data; | ||
182 | int ret = 0; | ||
183 | |||
184 | if (!st_data) | ||
185 | return -ENOENT; | ||
186 | |||
187 | spin_lock_irq(&mcbsp->lock); | ||
188 | if (channel == 0) | ||
189 | *chgain = st_data->ch0gain; | ||
190 | else if (channel == 1) | ||
191 | *chgain = st_data->ch1gain; | ||
192 | else | ||
193 | ret = -EINVAL; | ||
194 | spin_unlock_irq(&mcbsp->lock); | ||
195 | |||
196 | return ret; | ||
197 | } | ||
198 | |||
199 | static int omap_mcbsp_st_enable(struct omap_mcbsp *mcbsp) | ||
200 | { | ||
201 | struct omap_mcbsp_st_data *st_data = mcbsp->st_data; | ||
202 | |||
203 | if (!st_data) | ||
204 | return -ENODEV; | ||
205 | |||
206 | spin_lock_irq(&mcbsp->lock); | ||
207 | st_data->enabled = 1; | ||
208 | omap_mcbsp_st_start(mcbsp); | ||
209 | spin_unlock_irq(&mcbsp->lock); | ||
210 | |||
211 | return 0; | ||
212 | } | ||
213 | |||
214 | static int omap_mcbsp_st_disable(struct omap_mcbsp *mcbsp) | ||
215 | { | ||
216 | struct omap_mcbsp_st_data *st_data = mcbsp->st_data; | ||
217 | int ret = 0; | ||
218 | |||
219 | if (!st_data) | ||
220 | return -ENODEV; | ||
221 | |||
222 | spin_lock_irq(&mcbsp->lock); | ||
223 | omap_mcbsp_st_stop(mcbsp); | ||
224 | st_data->enabled = 0; | ||
225 | spin_unlock_irq(&mcbsp->lock); | ||
226 | |||
227 | return ret; | ||
228 | } | ||
229 | |||
230 | static int omap_mcbsp_st_is_enabled(struct omap_mcbsp *mcbsp) | ||
231 | { | ||
232 | struct omap_mcbsp_st_data *st_data = mcbsp->st_data; | ||
233 | |||
234 | if (!st_data) | ||
235 | return -ENODEV; | ||
236 | |||
237 | return st_data->enabled; | ||
238 | } | ||
239 | |||
240 | static ssize_t st_taps_show(struct device *dev, | ||
241 | struct device_attribute *attr, char *buf) | ||
242 | { | ||
243 | struct omap_mcbsp *mcbsp = dev_get_drvdata(dev); | ||
244 | struct omap_mcbsp_st_data *st_data = mcbsp->st_data; | ||
245 | ssize_t status = 0; | ||
246 | int i; | ||
247 | |||
248 | spin_lock_irq(&mcbsp->lock); | ||
249 | for (i = 0; i < st_data->nr_taps; i++) | ||
250 | status += sprintf(&buf[status], (i ? ", %d" : "%d"), | ||
251 | st_data->taps[i]); | ||
252 | if (i) | ||
253 | status += sprintf(&buf[status], "\n"); | ||
254 | spin_unlock_irq(&mcbsp->lock); | ||
255 | |||
256 | return status; | ||
257 | } | ||
258 | |||
259 | static ssize_t st_taps_store(struct device *dev, | ||
260 | struct device_attribute *attr, | ||
261 | const char *buf, size_t size) | ||
262 | { | ||
263 | struct omap_mcbsp *mcbsp = dev_get_drvdata(dev); | ||
264 | struct omap_mcbsp_st_data *st_data = mcbsp->st_data; | ||
265 | int val, tmp, status, i = 0; | ||
266 | |||
267 | spin_lock_irq(&mcbsp->lock); | ||
268 | memset(st_data->taps, 0, sizeof(st_data->taps)); | ||
269 | st_data->nr_taps = 0; | ||
270 | |||
271 | do { | ||
272 | status = sscanf(buf, "%d%n", &val, &tmp); | ||
273 | if (status < 0 || status == 0) { | ||
274 | size = -EINVAL; | ||
275 | goto out; | ||
276 | } | ||
277 | if (val < -32768 || val > 32767) { | ||
278 | size = -EINVAL; | ||
279 | goto out; | ||
280 | } | ||
281 | st_data->taps[i++] = val; | ||
282 | buf += tmp; | ||
283 | if (*buf != ',') | ||
284 | break; | ||
285 | buf++; | ||
286 | } while (1); | ||
287 | |||
288 | st_data->nr_taps = i; | ||
289 | |||
290 | out: | ||
291 | spin_unlock_irq(&mcbsp->lock); | ||
292 | |||
293 | return size; | ||
294 | } | ||
295 | |||
296 | static DEVICE_ATTR_RW(st_taps); | ||
297 | |||
298 | static const struct attribute *sidetone_attrs[] = { | ||
299 | &dev_attr_st_taps.attr, | ||
300 | NULL, | ||
301 | }; | ||
302 | |||
303 | static const struct attribute_group sidetone_attr_group = { | ||
304 | .attrs = (struct attribute **)sidetone_attrs, | ||
305 | }; | ||
306 | |||
307 | int omap_mcbsp_st_start(struct omap_mcbsp *mcbsp) | ||
308 | { | ||
309 | struct omap_mcbsp_st_data *st_data = mcbsp->st_data; | ||
310 | |||
311 | if (st_data->enabled && !st_data->running) { | ||
312 | omap_mcbsp_st_fir_write(mcbsp, st_data->taps); | ||
313 | omap_mcbsp_st_chgain(mcbsp); | ||
314 | |||
315 | if (!mcbsp->free) { | ||
316 | omap_mcbsp_st_on(mcbsp); | ||
317 | st_data->running = 1; | ||
318 | } | ||
319 | } | ||
320 | |||
321 | return 0; | ||
322 | } | ||
323 | |||
324 | int omap_mcbsp_st_stop(struct omap_mcbsp *mcbsp) | ||
325 | { | ||
326 | struct omap_mcbsp_st_data *st_data = mcbsp->st_data; | ||
327 | |||
328 | if (st_data->running) { | ||
329 | if (!mcbsp->free) { | ||
330 | omap_mcbsp_st_off(mcbsp); | ||
331 | st_data->running = 0; | ||
332 | } | ||
333 | } | ||
334 | |||
335 | return 0; | ||
336 | } | ||
337 | |||
338 | int omap_mcbsp_st_init(struct platform_device *pdev) | ||
339 | { | ||
340 | struct omap_mcbsp *mcbsp = platform_get_drvdata(pdev); | ||
341 | struct omap_mcbsp_st_data *st_data; | ||
342 | struct resource *res; | ||
343 | int ret; | ||
344 | |||
345 | res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "sidetone"); | ||
346 | if (!res) | ||
347 | return 0; | ||
348 | |||
349 | st_data = devm_kzalloc(mcbsp->dev, sizeof(*mcbsp->st_data), GFP_KERNEL); | ||
350 | if (!st_data) | ||
351 | return -ENOMEM; | ||
352 | |||
353 | st_data->mcbsp_iclk = clk_get(mcbsp->dev, "ick"); | ||
354 | if (IS_ERR(st_data->mcbsp_iclk)) { | ||
355 | dev_warn(mcbsp->dev, | ||
356 | "Failed to get ick, sidetone might be broken\n"); | ||
357 | st_data->mcbsp_iclk = NULL; | ||
358 | } | ||
359 | |||
360 | st_data->io_base_st = devm_ioremap(mcbsp->dev, res->start, | ||
361 | resource_size(res)); | ||
362 | if (!st_data->io_base_st) | ||
363 | return -ENOMEM; | ||
364 | |||
365 | ret = sysfs_create_group(&mcbsp->dev->kobj, &sidetone_attr_group); | ||
366 | if (ret) | ||
367 | return ret; | ||
368 | |||
369 | mcbsp->st_data = st_data; | ||
370 | |||
371 | return 0; | ||
372 | } | ||
373 | |||
374 | void omap_mcbsp_st_cleanup(struct platform_device *pdev) | ||
375 | { | ||
376 | struct omap_mcbsp *mcbsp = platform_get_drvdata(pdev); | ||
377 | |||
378 | if (mcbsp->st_data) { | ||
379 | sysfs_remove_group(&mcbsp->dev->kobj, &sidetone_attr_group); | ||
380 | clk_put(mcbsp->st_data->mcbsp_iclk); | ||
381 | } | ||
382 | } | ||
383 | |||
384 | static int omap_mcbsp_st_info_volsw(struct snd_kcontrol *kcontrol, | ||
385 | struct snd_ctl_elem_info *uinfo) | ||
386 | { | ||
387 | struct soc_mixer_control *mc = | ||
388 | (struct soc_mixer_control *)kcontrol->private_value; | ||
389 | int max = mc->max; | ||
390 | int min = mc->min; | ||
391 | |||
392 | uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; | ||
393 | uinfo->count = 1; | ||
394 | uinfo->value.integer.min = min; | ||
395 | uinfo->value.integer.max = max; | ||
396 | return 0; | ||
397 | } | ||
398 | |||
399 | #define OMAP_MCBSP_ST_CHANNEL_VOLUME(channel) \ | ||
400 | static int \ | ||
401 | omap_mcbsp_set_st_ch##channel##_volume(struct snd_kcontrol *kc, \ | ||
402 | struct snd_ctl_elem_value *uc) \ | ||
403 | { \ | ||
404 | struct snd_soc_dai *cpu_dai = snd_kcontrol_chip(kc); \ | ||
405 | struct omap_mcbsp *mcbsp = snd_soc_dai_get_drvdata(cpu_dai); \ | ||
406 | struct soc_mixer_control *mc = \ | ||
407 | (struct soc_mixer_control *)kc->private_value; \ | ||
408 | int max = mc->max; \ | ||
409 | int min = mc->min; \ | ||
410 | int val = uc->value.integer.value[0]; \ | ||
411 | \ | ||
412 | if (val < min || val > max) \ | ||
413 | return -EINVAL; \ | ||
414 | \ | ||
415 | /* OMAP McBSP implementation uses index values 0..4 */ \ | ||
416 | return omap_mcbsp_st_set_chgain(mcbsp, channel, val); \ | ||
417 | } \ | ||
418 | \ | ||
419 | static int \ | ||
420 | omap_mcbsp_get_st_ch##channel##_volume(struct snd_kcontrol *kc, \ | ||
421 | struct snd_ctl_elem_value *uc) \ | ||
422 | { \ | ||
423 | struct snd_soc_dai *cpu_dai = snd_kcontrol_chip(kc); \ | ||
424 | struct omap_mcbsp *mcbsp = snd_soc_dai_get_drvdata(cpu_dai); \ | ||
425 | s16 chgain; \ | ||
426 | \ | ||
427 | if (omap_mcbsp_st_get_chgain(mcbsp, channel, &chgain)) \ | ||
428 | return -EAGAIN; \ | ||
429 | \ | ||
430 | uc->value.integer.value[0] = chgain; \ | ||
431 | return 0; \ | ||
432 | } | ||
433 | |||
434 | OMAP_MCBSP_ST_CHANNEL_VOLUME(0) | ||
435 | OMAP_MCBSP_ST_CHANNEL_VOLUME(1) | ||
436 | |||
437 | static int omap_mcbsp_st_put_mode(struct snd_kcontrol *kcontrol, | ||
438 | struct snd_ctl_elem_value *ucontrol) | ||
439 | { | ||
440 | struct snd_soc_dai *cpu_dai = snd_kcontrol_chip(kcontrol); | ||
441 | struct omap_mcbsp *mcbsp = snd_soc_dai_get_drvdata(cpu_dai); | ||
442 | u8 value = ucontrol->value.integer.value[0]; | ||
443 | |||
444 | if (value == omap_mcbsp_st_is_enabled(mcbsp)) | ||
445 | return 0; | ||
446 | |||
447 | if (value) | ||
448 | omap_mcbsp_st_enable(mcbsp); | ||
449 | else | ||
450 | omap_mcbsp_st_disable(mcbsp); | ||
451 | |||
452 | return 1; | ||
453 | } | ||
454 | |||
455 | static int omap_mcbsp_st_get_mode(struct snd_kcontrol *kcontrol, | ||
456 | struct snd_ctl_elem_value *ucontrol) | ||
457 | { | ||
458 | struct snd_soc_dai *cpu_dai = snd_kcontrol_chip(kcontrol); | ||
459 | struct omap_mcbsp *mcbsp = snd_soc_dai_get_drvdata(cpu_dai); | ||
460 | |||
461 | ucontrol->value.integer.value[0] = omap_mcbsp_st_is_enabled(mcbsp); | ||
462 | return 0; | ||
463 | } | ||
464 | |||
465 | #define OMAP_MCBSP_SOC_SINGLE_S16_EXT(xname, xmin, xmax, \ | ||
466 | xhandler_get, xhandler_put) \ | ||
467 | { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, \ | ||
468 | .info = omap_mcbsp_st_info_volsw, \ | ||
469 | .get = xhandler_get, .put = xhandler_put, \ | ||
470 | .private_value = (unsigned long)&(struct soc_mixer_control) \ | ||
471 | {.min = xmin, .max = xmax} } | ||
472 | |||
473 | #define OMAP_MCBSP_ST_CONTROLS(port) \ | ||
474 | static const struct snd_kcontrol_new omap_mcbsp##port##_st_controls[] = { \ | ||
475 | SOC_SINGLE_EXT("McBSP" #port " Sidetone Switch", 1, 0, 1, 0, \ | ||
476 | omap_mcbsp_st_get_mode, omap_mcbsp_st_put_mode), \ | ||
477 | OMAP_MCBSP_SOC_SINGLE_S16_EXT("McBSP" #port " Sidetone Channel 0 Volume", \ | ||
478 | -32768, 32767, \ | ||
479 | omap_mcbsp_get_st_ch0_volume, \ | ||
480 | omap_mcbsp_set_st_ch0_volume), \ | ||
481 | OMAP_MCBSP_SOC_SINGLE_S16_EXT("McBSP" #port " Sidetone Channel 1 Volume", \ | ||
482 | -32768, 32767, \ | ||
483 | omap_mcbsp_get_st_ch1_volume, \ | ||
484 | omap_mcbsp_set_st_ch1_volume), \ | ||
485 | } | ||
486 | |||
487 | OMAP_MCBSP_ST_CONTROLS(2); | ||
488 | OMAP_MCBSP_ST_CONTROLS(3); | ||
489 | |||
490 | int omap_mcbsp_st_add_controls(struct snd_soc_pcm_runtime *rtd, int port_id) | ||
491 | { | ||
492 | struct snd_soc_dai *cpu_dai = rtd->cpu_dai; | ||
493 | struct omap_mcbsp *mcbsp = snd_soc_dai_get_drvdata(cpu_dai); | ||
494 | |||
495 | if (!mcbsp->st_data) { | ||
496 | dev_warn(mcbsp->dev, "No sidetone data for port\n"); | ||
497 | return 0; | ||
498 | } | ||
499 | |||
500 | switch (port_id) { | ||
501 | case 2: /* McBSP 2 */ | ||
502 | return snd_soc_add_dai_controls(cpu_dai, | ||
503 | omap_mcbsp2_st_controls, | ||
504 | ARRAY_SIZE(omap_mcbsp2_st_controls)); | ||
505 | case 3: /* McBSP 3 */ | ||
506 | return snd_soc_add_dai_controls(cpu_dai, | ||
507 | omap_mcbsp3_st_controls, | ||
508 | ARRAY_SIZE(omap_mcbsp3_st_controls)); | ||
509 | default: | ||
510 | dev_err(mcbsp->dev, "Port %d not supported\n", port_id); | ||
511 | break; | ||
512 | } | ||
513 | |||
514 | return -EINVAL; | ||
515 | } | ||
516 | EXPORT_SYMBOL_GPL(omap_mcbsp_st_add_controls); | ||
diff --git a/sound/soc/omap/omap-mcbsp.c b/sound/soc/ti/omap-mcbsp.c index 2d6decbfc99e..a395598f1f20 100644 --- a/sound/soc/omap/omap-mcbsp.c +++ b/sound/soc/ti/omap-mcbsp.c | |||
@@ -35,21 +35,12 @@ | |||
35 | #include <sound/soc.h> | 35 | #include <sound/soc.h> |
36 | #include <sound/dmaengine_pcm.h> | 36 | #include <sound/dmaengine_pcm.h> |
37 | 37 | ||
38 | #include <linux/platform_data/asoc-ti-mcbsp.h> | 38 | #include "omap-mcbsp-priv.h" |
39 | #include "mcbsp.h" | ||
40 | #include "omap-mcbsp.h" | 39 | #include "omap-mcbsp.h" |
41 | #include "sdma-pcm.h" | 40 | #include "sdma-pcm.h" |
42 | 41 | ||
43 | #define OMAP_MCBSP_RATES (SNDRV_PCM_RATE_8000_96000) | 42 | #define OMAP_MCBSP_RATES (SNDRV_PCM_RATE_8000_96000) |
44 | 43 | ||
45 | #define OMAP_MCBSP_SOC_SINGLE_S16_EXT(xname, xmin, xmax, \ | ||
46 | xhandler_get, xhandler_put) \ | ||
47 | { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, \ | ||
48 | .info = omap_mcbsp_st_info_volsw, \ | ||
49 | .get = xhandler_get, .put = xhandler_put, \ | ||
50 | .private_value = (unsigned long) &(struct soc_mixer_control) \ | ||
51 | {.min = xmin, .max = xmax} } | ||
52 | |||
53 | enum { | 44 | enum { |
54 | OMAP_MCBSP_WORD_8 = 0, | 45 | OMAP_MCBSP_WORD_8 = 0, |
55 | OMAP_MCBSP_WORD_12, | 46 | OMAP_MCBSP_WORD_12, |
@@ -59,6 +50,699 @@ enum { | |||
59 | OMAP_MCBSP_WORD_32, | 50 | OMAP_MCBSP_WORD_32, |
60 | }; | 51 | }; |
61 | 52 | ||
53 | static void omap_mcbsp_dump_reg(struct omap_mcbsp *mcbsp) | ||
54 | { | ||
55 | dev_dbg(mcbsp->dev, "**** McBSP%d regs ****\n", mcbsp->id); | ||
56 | dev_dbg(mcbsp->dev, "DRR2: 0x%04x\n", MCBSP_READ(mcbsp, DRR2)); | ||
57 | dev_dbg(mcbsp->dev, "DRR1: 0x%04x\n", MCBSP_READ(mcbsp, DRR1)); | ||
58 | dev_dbg(mcbsp->dev, "DXR2: 0x%04x\n", MCBSP_READ(mcbsp, DXR2)); | ||
59 | dev_dbg(mcbsp->dev, "DXR1: 0x%04x\n", MCBSP_READ(mcbsp, DXR1)); | ||
60 | dev_dbg(mcbsp->dev, "SPCR2: 0x%04x\n", MCBSP_READ(mcbsp, SPCR2)); | ||
61 | dev_dbg(mcbsp->dev, "SPCR1: 0x%04x\n", MCBSP_READ(mcbsp, SPCR1)); | ||
62 | dev_dbg(mcbsp->dev, "RCR2: 0x%04x\n", MCBSP_READ(mcbsp, RCR2)); | ||
63 | dev_dbg(mcbsp->dev, "RCR1: 0x%04x\n", MCBSP_READ(mcbsp, RCR1)); | ||
64 | dev_dbg(mcbsp->dev, "XCR2: 0x%04x\n", MCBSP_READ(mcbsp, XCR2)); | ||
65 | dev_dbg(mcbsp->dev, "XCR1: 0x%04x\n", MCBSP_READ(mcbsp, XCR1)); | ||
66 | dev_dbg(mcbsp->dev, "SRGR2: 0x%04x\n", MCBSP_READ(mcbsp, SRGR2)); | ||
67 | dev_dbg(mcbsp->dev, "SRGR1: 0x%04x\n", MCBSP_READ(mcbsp, SRGR1)); | ||
68 | dev_dbg(mcbsp->dev, "PCR0: 0x%04x\n", MCBSP_READ(mcbsp, PCR0)); | ||
69 | dev_dbg(mcbsp->dev, "***********************\n"); | ||
70 | } | ||
71 | |||
72 | static int omap2_mcbsp_set_clks_src(struct omap_mcbsp *mcbsp, u8 fck_src_id) | ||
73 | { | ||
74 | struct clk *fck_src; | ||
75 | const char *src; | ||
76 | int r; | ||
77 | |||
78 | if (fck_src_id == MCBSP_CLKS_PAD_SRC) | ||
79 | src = "pad_fck"; | ||
80 | else if (fck_src_id == MCBSP_CLKS_PRCM_SRC) | ||
81 | src = "prcm_fck"; | ||
82 | else | ||
83 | return -EINVAL; | ||
84 | |||
85 | fck_src = clk_get(mcbsp->dev, src); | ||
86 | if (IS_ERR(fck_src)) { | ||
87 | dev_err(mcbsp->dev, "CLKS: could not clk_get() %s\n", src); | ||
88 | return -EINVAL; | ||
89 | } | ||
90 | |||
91 | pm_runtime_put_sync(mcbsp->dev); | ||
92 | |||
93 | r = clk_set_parent(mcbsp->fclk, fck_src); | ||
94 | if (r) { | ||
95 | dev_err(mcbsp->dev, "CLKS: could not clk_set_parent() to %s\n", | ||
96 | src); | ||
97 | clk_put(fck_src); | ||
98 | return r; | ||
99 | } | ||
100 | |||
101 | pm_runtime_get_sync(mcbsp->dev); | ||
102 | |||
103 | clk_put(fck_src); | ||
104 | |||
105 | return 0; | ||
106 | } | ||
107 | |||
108 | static irqreturn_t omap_mcbsp_irq_handler(int irq, void *data) | ||
109 | { | ||
110 | struct omap_mcbsp *mcbsp = data; | ||
111 | u16 irqst; | ||
112 | |||
113 | irqst = MCBSP_READ(mcbsp, IRQST); | ||
114 | dev_dbg(mcbsp->dev, "IRQ callback : 0x%x\n", irqst); | ||
115 | |||
116 | if (irqst & RSYNCERREN) | ||
117 | dev_err(mcbsp->dev, "RX Frame Sync Error!\n"); | ||
118 | if (irqst & RFSREN) | ||
119 | dev_dbg(mcbsp->dev, "RX Frame Sync\n"); | ||
120 | if (irqst & REOFEN) | ||
121 | dev_dbg(mcbsp->dev, "RX End Of Frame\n"); | ||
122 | if (irqst & RRDYEN) | ||
123 | dev_dbg(mcbsp->dev, "RX Buffer Threshold Reached\n"); | ||
124 | if (irqst & RUNDFLEN) | ||
125 | dev_err(mcbsp->dev, "RX Buffer Underflow!\n"); | ||
126 | if (irqst & ROVFLEN) | ||
127 | dev_err(mcbsp->dev, "RX Buffer Overflow!\n"); | ||
128 | |||
129 | if (irqst & XSYNCERREN) | ||
130 | dev_err(mcbsp->dev, "TX Frame Sync Error!\n"); | ||
131 | if (irqst & XFSXEN) | ||
132 | dev_dbg(mcbsp->dev, "TX Frame Sync\n"); | ||
133 | if (irqst & XEOFEN) | ||
134 | dev_dbg(mcbsp->dev, "TX End Of Frame\n"); | ||
135 | if (irqst & XRDYEN) | ||
136 | dev_dbg(mcbsp->dev, "TX Buffer threshold Reached\n"); | ||
137 | if (irqst & XUNDFLEN) | ||
138 | dev_err(mcbsp->dev, "TX Buffer Underflow!\n"); | ||
139 | if (irqst & XOVFLEN) | ||
140 | dev_err(mcbsp->dev, "TX Buffer Overflow!\n"); | ||
141 | if (irqst & XEMPTYEOFEN) | ||
142 | dev_dbg(mcbsp->dev, "TX Buffer empty at end of frame\n"); | ||
143 | |||
144 | MCBSP_WRITE(mcbsp, IRQST, irqst); | ||
145 | |||
146 | return IRQ_HANDLED; | ||
147 | } | ||
148 | |||
149 | static irqreturn_t omap_mcbsp_tx_irq_handler(int irq, void *data) | ||
150 | { | ||
151 | struct omap_mcbsp *mcbsp = data; | ||
152 | u16 irqst_spcr2; | ||
153 | |||
154 | irqst_spcr2 = MCBSP_READ(mcbsp, SPCR2); | ||
155 | dev_dbg(mcbsp->dev, "TX IRQ callback : 0x%x\n", irqst_spcr2); | ||
156 | |||
157 | if (irqst_spcr2 & XSYNC_ERR) { | ||
158 | dev_err(mcbsp->dev, "TX Frame Sync Error! : 0x%x\n", | ||
159 | irqst_spcr2); | ||
160 | /* Writing zero to XSYNC_ERR clears the IRQ */ | ||
161 | MCBSP_WRITE(mcbsp, SPCR2, MCBSP_READ_CACHE(mcbsp, SPCR2)); | ||
162 | } | ||
163 | |||
164 | return IRQ_HANDLED; | ||
165 | } | ||
166 | |||
167 | static irqreturn_t omap_mcbsp_rx_irq_handler(int irq, void *data) | ||
168 | { | ||
169 | struct omap_mcbsp *mcbsp = data; | ||
170 | u16 irqst_spcr1; | ||
171 | |||
172 | irqst_spcr1 = MCBSP_READ(mcbsp, SPCR1); | ||
173 | dev_dbg(mcbsp->dev, "RX IRQ callback : 0x%x\n", irqst_spcr1); | ||
174 | |||
175 | if (irqst_spcr1 & RSYNC_ERR) { | ||
176 | dev_err(mcbsp->dev, "RX Frame Sync Error! : 0x%x\n", | ||
177 | irqst_spcr1); | ||
178 | /* Writing zero to RSYNC_ERR clears the IRQ */ | ||
179 | MCBSP_WRITE(mcbsp, SPCR1, MCBSP_READ_CACHE(mcbsp, SPCR1)); | ||
180 | } | ||
181 | |||
182 | return IRQ_HANDLED; | ||
183 | } | ||
184 | |||
185 | /* | ||
186 | * omap_mcbsp_config simply write a config to the | ||
187 | * appropriate McBSP. | ||
188 | * You either call this function or set the McBSP registers | ||
189 | * by yourself before calling omap_mcbsp_start(). | ||
190 | */ | ||
191 | static void omap_mcbsp_config(struct omap_mcbsp *mcbsp, | ||
192 | const struct omap_mcbsp_reg_cfg *config) | ||
193 | { | ||
194 | dev_dbg(mcbsp->dev, "Configuring McBSP%d phys_base: 0x%08lx\n", | ||
195 | mcbsp->id, mcbsp->phys_base); | ||
196 | |||
197 | /* We write the given config */ | ||
198 | MCBSP_WRITE(mcbsp, SPCR2, config->spcr2); | ||
199 | MCBSP_WRITE(mcbsp, SPCR1, config->spcr1); | ||
200 | MCBSP_WRITE(mcbsp, RCR2, config->rcr2); | ||
201 | MCBSP_WRITE(mcbsp, RCR1, config->rcr1); | ||
202 | MCBSP_WRITE(mcbsp, XCR2, config->xcr2); | ||
203 | MCBSP_WRITE(mcbsp, XCR1, config->xcr1); | ||
204 | MCBSP_WRITE(mcbsp, SRGR2, config->srgr2); | ||
205 | MCBSP_WRITE(mcbsp, SRGR1, config->srgr1); | ||
206 | MCBSP_WRITE(mcbsp, MCR2, config->mcr2); | ||
207 | MCBSP_WRITE(mcbsp, MCR1, config->mcr1); | ||
208 | MCBSP_WRITE(mcbsp, PCR0, config->pcr0); | ||
209 | if (mcbsp->pdata->has_ccr) { | ||
210 | MCBSP_WRITE(mcbsp, XCCR, config->xccr); | ||
211 | MCBSP_WRITE(mcbsp, RCCR, config->rccr); | ||
212 | } | ||
213 | /* Enable wakeup behavior */ | ||
214 | if (mcbsp->pdata->has_wakeup) | ||
215 | MCBSP_WRITE(mcbsp, WAKEUPEN, XRDYEN | RRDYEN); | ||
216 | |||
217 | /* Enable TX/RX sync error interrupts by default */ | ||
218 | if (mcbsp->irq) | ||
219 | MCBSP_WRITE(mcbsp, IRQEN, RSYNCERREN | XSYNCERREN | | ||
220 | RUNDFLEN | ROVFLEN | XUNDFLEN | XOVFLEN); | ||
221 | } | ||
222 | |||
223 | /** | ||
224 | * omap_mcbsp_dma_reg_params - returns the address of mcbsp data register | ||
225 | * @mcbsp: omap_mcbsp struct for the McBSP instance | ||
226 | * @stream: Stream direction (playback/capture) | ||
227 | * | ||
228 | * Returns the address of mcbsp data transmit register or data receive register | ||
229 | * to be used by DMA for transferring/receiving data | ||
230 | */ | ||
231 | static int omap_mcbsp_dma_reg_params(struct omap_mcbsp *mcbsp, | ||
232 | unsigned int stream) | ||
233 | { | ||
234 | int data_reg; | ||
235 | |||
236 | if (stream == SNDRV_PCM_STREAM_PLAYBACK) { | ||
237 | if (mcbsp->pdata->reg_size == 2) | ||
238 | data_reg = OMAP_MCBSP_REG_DXR1; | ||
239 | else | ||
240 | data_reg = OMAP_MCBSP_REG_DXR; | ||
241 | } else { | ||
242 | if (mcbsp->pdata->reg_size == 2) | ||
243 | data_reg = OMAP_MCBSP_REG_DRR1; | ||
244 | else | ||
245 | data_reg = OMAP_MCBSP_REG_DRR; | ||
246 | } | ||
247 | |||
248 | return mcbsp->phys_dma_base + data_reg * mcbsp->pdata->reg_step; | ||
249 | } | ||
250 | |||
251 | /* | ||
252 | * omap_mcbsp_set_rx_threshold configures the transmit threshold in words. | ||
253 | * The threshold parameter is 1 based, and it is converted (threshold - 1) | ||
254 | * for the THRSH2 register. | ||
255 | */ | ||
256 | static void omap_mcbsp_set_tx_threshold(struct omap_mcbsp *mcbsp, u16 threshold) | ||
257 | { | ||
258 | if (threshold && threshold <= mcbsp->max_tx_thres) | ||
259 | MCBSP_WRITE(mcbsp, THRSH2, threshold - 1); | ||
260 | } | ||
261 | |||
262 | /* | ||
263 | * omap_mcbsp_set_rx_threshold configures the receive threshold in words. | ||
264 | * The threshold parameter is 1 based, and it is converted (threshold - 1) | ||
265 | * for the THRSH1 register. | ||
266 | */ | ||
267 | static void omap_mcbsp_set_rx_threshold(struct omap_mcbsp *mcbsp, u16 threshold) | ||
268 | { | ||
269 | if (threshold && threshold <= mcbsp->max_rx_thres) | ||
270 | MCBSP_WRITE(mcbsp, THRSH1, threshold - 1); | ||
271 | } | ||
272 | |||
273 | /* | ||
274 | * omap_mcbsp_get_tx_delay returns the number of used slots in the McBSP FIFO | ||
275 | */ | ||
276 | static u16 omap_mcbsp_get_tx_delay(struct omap_mcbsp *mcbsp) | ||
277 | { | ||
278 | u16 buffstat; | ||
279 | |||
280 | /* Returns the number of free locations in the buffer */ | ||
281 | buffstat = MCBSP_READ(mcbsp, XBUFFSTAT); | ||
282 | |||
283 | /* Number of slots are different in McBSP ports */ | ||
284 | return mcbsp->pdata->buffer_size - buffstat; | ||
285 | } | ||
286 | |||
287 | /* | ||
288 | * omap_mcbsp_get_rx_delay returns the number of free slots in the McBSP FIFO | ||
289 | * to reach the threshold value (when the DMA will be triggered to read it) | ||
290 | */ | ||
291 | static u16 omap_mcbsp_get_rx_delay(struct omap_mcbsp *mcbsp) | ||
292 | { | ||
293 | u16 buffstat, threshold; | ||
294 | |||
295 | /* Returns the number of used locations in the buffer */ | ||
296 | buffstat = MCBSP_READ(mcbsp, RBUFFSTAT); | ||
297 | /* RX threshold */ | ||
298 | threshold = MCBSP_READ(mcbsp, THRSH1); | ||
299 | |||
300 | /* Return the number of location till we reach the threshold limit */ | ||
301 | if (threshold <= buffstat) | ||
302 | return 0; | ||
303 | else | ||
304 | return threshold - buffstat; | ||
305 | } | ||
306 | |||
307 | static int omap_mcbsp_request(struct omap_mcbsp *mcbsp) | ||
308 | { | ||
309 | void *reg_cache; | ||
310 | int err; | ||
311 | |||
312 | reg_cache = kzalloc(mcbsp->reg_cache_size, GFP_KERNEL); | ||
313 | if (!reg_cache) | ||
314 | return -ENOMEM; | ||
315 | |||
316 | spin_lock(&mcbsp->lock); | ||
317 | if (!mcbsp->free) { | ||
318 | dev_err(mcbsp->dev, "McBSP%d is currently in use\n", mcbsp->id); | ||
319 | err = -EBUSY; | ||
320 | goto err_kfree; | ||
321 | } | ||
322 | |||
323 | mcbsp->free = false; | ||
324 | mcbsp->reg_cache = reg_cache; | ||
325 | spin_unlock(&mcbsp->lock); | ||
326 | |||
327 | if(mcbsp->pdata->ops && mcbsp->pdata->ops->request) | ||
328 | mcbsp->pdata->ops->request(mcbsp->id - 1); | ||
329 | |||
330 | /* | ||
331 | * Make sure that transmitter, receiver and sample-rate generator are | ||
332 | * not running before activating IRQs. | ||
333 | */ | ||
334 | MCBSP_WRITE(mcbsp, SPCR1, 0); | ||
335 | MCBSP_WRITE(mcbsp, SPCR2, 0); | ||
336 | |||
337 | if (mcbsp->irq) { | ||
338 | err = request_irq(mcbsp->irq, omap_mcbsp_irq_handler, 0, | ||
339 | "McBSP", (void *)mcbsp); | ||
340 | if (err != 0) { | ||
341 | dev_err(mcbsp->dev, "Unable to request IRQ\n"); | ||
342 | goto err_clk_disable; | ||
343 | } | ||
344 | } else { | ||
345 | err = request_irq(mcbsp->tx_irq, omap_mcbsp_tx_irq_handler, 0, | ||
346 | "McBSP TX", (void *)mcbsp); | ||
347 | if (err != 0) { | ||
348 | dev_err(mcbsp->dev, "Unable to request TX IRQ\n"); | ||
349 | goto err_clk_disable; | ||
350 | } | ||
351 | |||
352 | err = request_irq(mcbsp->rx_irq, omap_mcbsp_rx_irq_handler, 0, | ||
353 | "McBSP RX", (void *)mcbsp); | ||
354 | if (err != 0) { | ||
355 | dev_err(mcbsp->dev, "Unable to request RX IRQ\n"); | ||
356 | goto err_free_irq; | ||
357 | } | ||
358 | } | ||
359 | |||
360 | return 0; | ||
361 | err_free_irq: | ||
362 | free_irq(mcbsp->tx_irq, (void *)mcbsp); | ||
363 | err_clk_disable: | ||
364 | if(mcbsp->pdata->ops && mcbsp->pdata->ops->free) | ||
365 | mcbsp->pdata->ops->free(mcbsp->id - 1); | ||
366 | |||
367 | /* Disable wakeup behavior */ | ||
368 | if (mcbsp->pdata->has_wakeup) | ||
369 | MCBSP_WRITE(mcbsp, WAKEUPEN, 0); | ||
370 | |||
371 | spin_lock(&mcbsp->lock); | ||
372 | mcbsp->free = true; | ||
373 | mcbsp->reg_cache = NULL; | ||
374 | err_kfree: | ||
375 | spin_unlock(&mcbsp->lock); | ||
376 | kfree(reg_cache); | ||
377 | |||
378 | return err; | ||
379 | } | ||
380 | |||
381 | static void omap_mcbsp_free(struct omap_mcbsp *mcbsp) | ||
382 | { | ||
383 | void *reg_cache; | ||
384 | |||
385 | if(mcbsp->pdata->ops && mcbsp->pdata->ops->free) | ||
386 | mcbsp->pdata->ops->free(mcbsp->id - 1); | ||
387 | |||
388 | /* Disable wakeup behavior */ | ||
389 | if (mcbsp->pdata->has_wakeup) | ||
390 | MCBSP_WRITE(mcbsp, WAKEUPEN, 0); | ||
391 | |||
392 | /* Disable interrupt requests */ | ||
393 | if (mcbsp->irq) | ||
394 | MCBSP_WRITE(mcbsp, IRQEN, 0); | ||
395 | |||
396 | if (mcbsp->irq) { | ||
397 | free_irq(mcbsp->irq, (void *)mcbsp); | ||
398 | } else { | ||
399 | free_irq(mcbsp->rx_irq, (void *)mcbsp); | ||
400 | free_irq(mcbsp->tx_irq, (void *)mcbsp); | ||
401 | } | ||
402 | |||
403 | reg_cache = mcbsp->reg_cache; | ||
404 | |||
405 | /* | ||
406 | * Select CLKS source from internal source unconditionally before | ||
407 | * marking the McBSP port as free. | ||
408 | * If the external clock source via MCBSP_CLKS pin has been selected the | ||
409 | * system will refuse to enter idle if the CLKS pin source is not reset | ||
410 | * back to internal source. | ||
411 | */ | ||
412 | if (!mcbsp_omap1()) | ||
413 | omap2_mcbsp_set_clks_src(mcbsp, MCBSP_CLKS_PRCM_SRC); | ||
414 | |||
415 | spin_lock(&mcbsp->lock); | ||
416 | if (mcbsp->free) | ||
417 | dev_err(mcbsp->dev, "McBSP%d was not reserved\n", mcbsp->id); | ||
418 | else | ||
419 | mcbsp->free = true; | ||
420 | mcbsp->reg_cache = NULL; | ||
421 | spin_unlock(&mcbsp->lock); | ||
422 | |||
423 | kfree(reg_cache); | ||
424 | } | ||
425 | |||
426 | /* | ||
427 | * Here we start the McBSP, by enabling transmitter, receiver or both. | ||
428 | * If no transmitter or receiver is active prior calling, then sample-rate | ||
429 | * generator and frame sync are started. | ||
430 | */ | ||
431 | static void omap_mcbsp_start(struct omap_mcbsp *mcbsp, int stream) | ||
432 | { | ||
433 | int tx = (stream == SNDRV_PCM_STREAM_PLAYBACK); | ||
434 | int rx = !tx; | ||
435 | int enable_srg = 0; | ||
436 | u16 w; | ||
437 | |||
438 | if (mcbsp->st_data) | ||
439 | omap_mcbsp_st_start(mcbsp); | ||
440 | |||
441 | /* Only enable SRG, if McBSP is master */ | ||
442 | w = MCBSP_READ_CACHE(mcbsp, PCR0); | ||
443 | if (w & (FSXM | FSRM | CLKXM | CLKRM)) | ||
444 | enable_srg = !((MCBSP_READ_CACHE(mcbsp, SPCR2) | | ||
445 | MCBSP_READ_CACHE(mcbsp, SPCR1)) & 1); | ||
446 | |||
447 | if (enable_srg) { | ||
448 | /* Start the sample generator */ | ||
449 | w = MCBSP_READ_CACHE(mcbsp, SPCR2); | ||
450 | MCBSP_WRITE(mcbsp, SPCR2, w | (1 << 6)); | ||
451 | } | ||
452 | |||
453 | /* Enable transmitter and receiver */ | ||
454 | tx &= 1; | ||
455 | w = MCBSP_READ_CACHE(mcbsp, SPCR2); | ||
456 | MCBSP_WRITE(mcbsp, SPCR2, w | tx); | ||
457 | |||
458 | rx &= 1; | ||
459 | w = MCBSP_READ_CACHE(mcbsp, SPCR1); | ||
460 | MCBSP_WRITE(mcbsp, SPCR1, w | rx); | ||
461 | |||
462 | /* | ||
463 | * Worst case: CLKSRG*2 = 8000khz: (1/8000) * 2 * 2 usec | ||
464 | * REVISIT: 100us may give enough time for two CLKSRG, however | ||
465 | * due to some unknown PM related, clock gating etc. reason it | ||
466 | * is now at 500us. | ||
467 | */ | ||
468 | udelay(500); | ||
469 | |||
470 | if (enable_srg) { | ||
471 | /* Start frame sync */ | ||
472 | w = MCBSP_READ_CACHE(mcbsp, SPCR2); | ||
473 | MCBSP_WRITE(mcbsp, SPCR2, w | (1 << 7)); | ||
474 | } | ||
475 | |||
476 | if (mcbsp->pdata->has_ccr) { | ||
477 | /* Release the transmitter and receiver */ | ||
478 | w = MCBSP_READ_CACHE(mcbsp, XCCR); | ||
479 | w &= ~(tx ? XDISABLE : 0); | ||
480 | MCBSP_WRITE(mcbsp, XCCR, w); | ||
481 | w = MCBSP_READ_CACHE(mcbsp, RCCR); | ||
482 | w &= ~(rx ? RDISABLE : 0); | ||
483 | MCBSP_WRITE(mcbsp, RCCR, w); | ||
484 | } | ||
485 | |||
486 | /* Dump McBSP Regs */ | ||
487 | omap_mcbsp_dump_reg(mcbsp); | ||
488 | } | ||
489 | |||
490 | static void omap_mcbsp_stop(struct omap_mcbsp *mcbsp, int stream) | ||
491 | { | ||
492 | int tx = (stream == SNDRV_PCM_STREAM_PLAYBACK); | ||
493 | int rx = !tx; | ||
494 | int idle; | ||
495 | u16 w; | ||
496 | |||
497 | /* Reset transmitter */ | ||
498 | tx &= 1; | ||
499 | if (mcbsp->pdata->has_ccr) { | ||
500 | w = MCBSP_READ_CACHE(mcbsp, XCCR); | ||
501 | w |= (tx ? XDISABLE : 0); | ||
502 | MCBSP_WRITE(mcbsp, XCCR, w); | ||
503 | } | ||
504 | w = MCBSP_READ_CACHE(mcbsp, SPCR2); | ||
505 | MCBSP_WRITE(mcbsp, SPCR2, w & ~tx); | ||
506 | |||
507 | /* Reset receiver */ | ||
508 | rx &= 1; | ||
509 | if (mcbsp->pdata->has_ccr) { | ||
510 | w = MCBSP_READ_CACHE(mcbsp, RCCR); | ||
511 | w |= (rx ? RDISABLE : 0); | ||
512 | MCBSP_WRITE(mcbsp, RCCR, w); | ||
513 | } | ||
514 | w = MCBSP_READ_CACHE(mcbsp, SPCR1); | ||
515 | MCBSP_WRITE(mcbsp, SPCR1, w & ~rx); | ||
516 | |||
517 | idle = !((MCBSP_READ_CACHE(mcbsp, SPCR2) | | ||
518 | MCBSP_READ_CACHE(mcbsp, SPCR1)) & 1); | ||
519 | |||
520 | if (idle) { | ||
521 | /* Reset the sample rate generator */ | ||
522 | w = MCBSP_READ_CACHE(mcbsp, SPCR2); | ||
523 | MCBSP_WRITE(mcbsp, SPCR2, w & ~(1 << 6)); | ||
524 | } | ||
525 | |||
526 | if (mcbsp->st_data) | ||
527 | omap_mcbsp_st_stop(mcbsp); | ||
528 | } | ||
529 | |||
530 | #define max_thres(m) (mcbsp->pdata->buffer_size) | ||
531 | #define valid_threshold(m, val) ((val) <= max_thres(m)) | ||
532 | #define THRESHOLD_PROP_BUILDER(prop) \ | ||
533 | static ssize_t prop##_show(struct device *dev, \ | ||
534 | struct device_attribute *attr, char *buf) \ | ||
535 | { \ | ||
536 | struct omap_mcbsp *mcbsp = dev_get_drvdata(dev); \ | ||
537 | \ | ||
538 | return sprintf(buf, "%u\n", mcbsp->prop); \ | ||
539 | } \ | ||
540 | \ | ||
541 | static ssize_t prop##_store(struct device *dev, \ | ||
542 | struct device_attribute *attr, \ | ||
543 | const char *buf, size_t size) \ | ||
544 | { \ | ||
545 | struct omap_mcbsp *mcbsp = dev_get_drvdata(dev); \ | ||
546 | unsigned long val; \ | ||
547 | int status; \ | ||
548 | \ | ||
549 | status = kstrtoul(buf, 0, &val); \ | ||
550 | if (status) \ | ||
551 | return status; \ | ||
552 | \ | ||
553 | if (!valid_threshold(mcbsp, val)) \ | ||
554 | return -EDOM; \ | ||
555 | \ | ||
556 | mcbsp->prop = val; \ | ||
557 | return size; \ | ||
558 | } \ | ||
559 | \ | ||
560 | static DEVICE_ATTR(prop, 0644, prop##_show, prop##_store) | ||
561 | |||
562 | THRESHOLD_PROP_BUILDER(max_tx_thres); | ||
563 | THRESHOLD_PROP_BUILDER(max_rx_thres); | ||
564 | |||
565 | static const char * const dma_op_modes[] = { | ||
566 | "element", "threshold", | ||
567 | }; | ||
568 | |||
569 | static ssize_t dma_op_mode_show(struct device *dev, | ||
570 | struct device_attribute *attr, char *buf) | ||
571 | { | ||
572 | struct omap_mcbsp *mcbsp = dev_get_drvdata(dev); | ||
573 | int dma_op_mode, i = 0; | ||
574 | ssize_t len = 0; | ||
575 | const char * const *s; | ||
576 | |||
577 | dma_op_mode = mcbsp->dma_op_mode; | ||
578 | |||
579 | for (s = &dma_op_modes[i]; i < ARRAY_SIZE(dma_op_modes); s++, i++) { | ||
580 | if (dma_op_mode == i) | ||
581 | len += sprintf(buf + len, "[%s] ", *s); | ||
582 | else | ||
583 | len += sprintf(buf + len, "%s ", *s); | ||
584 | } | ||
585 | len += sprintf(buf + len, "\n"); | ||
586 | |||
587 | return len; | ||
588 | } | ||
589 | |||
590 | static ssize_t dma_op_mode_store(struct device *dev, | ||
591 | struct device_attribute *attr, const char *buf, | ||
592 | size_t size) | ||
593 | { | ||
594 | struct omap_mcbsp *mcbsp = dev_get_drvdata(dev); | ||
595 | int i; | ||
596 | |||
597 | i = sysfs_match_string(dma_op_modes, buf); | ||
598 | if (i < 0) | ||
599 | return i; | ||
600 | |||
601 | spin_lock_irq(&mcbsp->lock); | ||
602 | if (!mcbsp->free) { | ||
603 | size = -EBUSY; | ||
604 | goto unlock; | ||
605 | } | ||
606 | mcbsp->dma_op_mode = i; | ||
607 | |||
608 | unlock: | ||
609 | spin_unlock_irq(&mcbsp->lock); | ||
610 | |||
611 | return size; | ||
612 | } | ||
613 | |||
614 | static DEVICE_ATTR_RW(dma_op_mode); | ||
615 | |||
616 | static const struct attribute *additional_attrs[] = { | ||
617 | &dev_attr_max_tx_thres.attr, | ||
618 | &dev_attr_max_rx_thres.attr, | ||
619 | &dev_attr_dma_op_mode.attr, | ||
620 | NULL, | ||
621 | }; | ||
622 | |||
623 | static const struct attribute_group additional_attr_group = { | ||
624 | .attrs = (struct attribute **)additional_attrs, | ||
625 | }; | ||
626 | |||
627 | /* | ||
628 | * McBSP1 and McBSP3 are directly mapped on 1610 and 1510. | ||
629 | * 730 has only 2 McBSP, and both of them are MPU peripherals. | ||
630 | */ | ||
631 | static int omap_mcbsp_init(struct platform_device *pdev) | ||
632 | { | ||
633 | struct omap_mcbsp *mcbsp = platform_get_drvdata(pdev); | ||
634 | struct resource *res; | ||
635 | int ret = 0; | ||
636 | |||
637 | spin_lock_init(&mcbsp->lock); | ||
638 | mcbsp->free = true; | ||
639 | |||
640 | res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "mpu"); | ||
641 | if (!res) | ||
642 | res = platform_get_resource(pdev, IORESOURCE_MEM, 0); | ||
643 | |||
644 | mcbsp->io_base = devm_ioremap_resource(&pdev->dev, res); | ||
645 | if (IS_ERR(mcbsp->io_base)) | ||
646 | return PTR_ERR(mcbsp->io_base); | ||
647 | |||
648 | mcbsp->phys_base = res->start; | ||
649 | mcbsp->reg_cache_size = resource_size(res); | ||
650 | |||
651 | res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "dma"); | ||
652 | if (!res) | ||
653 | mcbsp->phys_dma_base = mcbsp->phys_base; | ||
654 | else | ||
655 | mcbsp->phys_dma_base = res->start; | ||
656 | |||
657 | /* | ||
658 | * OMAP1, 2 uses two interrupt lines: TX, RX | ||
659 | * OMAP2430, OMAP3 SoC have combined IRQ line as well. | ||
660 | * OMAP4 and newer SoC only have the combined IRQ line. | ||
661 | * Use the combined IRQ if available since it gives better debugging | ||
662 | * possibilities. | ||
663 | */ | ||
664 | mcbsp->irq = platform_get_irq_byname(pdev, "common"); | ||
665 | if (mcbsp->irq == -ENXIO) { | ||
666 | mcbsp->tx_irq = platform_get_irq_byname(pdev, "tx"); | ||
667 | |||
668 | if (mcbsp->tx_irq == -ENXIO) { | ||
669 | mcbsp->irq = platform_get_irq(pdev, 0); | ||
670 | mcbsp->tx_irq = 0; | ||
671 | } else { | ||
672 | mcbsp->rx_irq = platform_get_irq_byname(pdev, "rx"); | ||
673 | mcbsp->irq = 0; | ||
674 | } | ||
675 | } | ||
676 | |||
677 | if (!pdev->dev.of_node) { | ||
678 | res = platform_get_resource_byname(pdev, IORESOURCE_DMA, "tx"); | ||
679 | if (!res) { | ||
680 | dev_err(&pdev->dev, "invalid tx DMA channel\n"); | ||
681 | return -ENODEV; | ||
682 | } | ||
683 | mcbsp->dma_req[0] = res->start; | ||
684 | mcbsp->dma_data[0].filter_data = &mcbsp->dma_req[0]; | ||
685 | |||
686 | res = platform_get_resource_byname(pdev, IORESOURCE_DMA, "rx"); | ||
687 | if (!res) { | ||
688 | dev_err(&pdev->dev, "invalid rx DMA channel\n"); | ||
689 | return -ENODEV; | ||
690 | } | ||
691 | mcbsp->dma_req[1] = res->start; | ||
692 | mcbsp->dma_data[1].filter_data = &mcbsp->dma_req[1]; | ||
693 | } else { | ||
694 | mcbsp->dma_data[0].filter_data = "tx"; | ||
695 | mcbsp->dma_data[1].filter_data = "rx"; | ||
696 | } | ||
697 | |||
698 | mcbsp->dma_data[0].addr = omap_mcbsp_dma_reg_params(mcbsp, | ||
699 | SNDRV_PCM_STREAM_PLAYBACK); | ||
700 | mcbsp->dma_data[1].addr = omap_mcbsp_dma_reg_params(mcbsp, | ||
701 | SNDRV_PCM_STREAM_CAPTURE); | ||
702 | |||
703 | mcbsp->fclk = clk_get(&pdev->dev, "fck"); | ||
704 | if (IS_ERR(mcbsp->fclk)) { | ||
705 | ret = PTR_ERR(mcbsp->fclk); | ||
706 | dev_err(mcbsp->dev, "unable to get fck: %d\n", ret); | ||
707 | return ret; | ||
708 | } | ||
709 | |||
710 | mcbsp->dma_op_mode = MCBSP_DMA_MODE_ELEMENT; | ||
711 | if (mcbsp->pdata->buffer_size) { | ||
712 | /* | ||
713 | * Initially configure the maximum thresholds to a safe value. | ||
714 | * The McBSP FIFO usage with these values should not go under | ||
715 | * 16 locations. | ||
716 | * If the whole FIFO without safety buffer is used, than there | ||
717 | * is a possibility that the DMA will be not able to push the | ||
718 | * new data on time, causing channel shifts in runtime. | ||
719 | */ | ||
720 | mcbsp->max_tx_thres = max_thres(mcbsp) - 0x10; | ||
721 | mcbsp->max_rx_thres = max_thres(mcbsp) - 0x10; | ||
722 | |||
723 | ret = sysfs_create_group(&mcbsp->dev->kobj, | ||
724 | &additional_attr_group); | ||
725 | if (ret) { | ||
726 | dev_err(mcbsp->dev, | ||
727 | "Unable to create additional controls\n"); | ||
728 | goto err_thres; | ||
729 | } | ||
730 | } | ||
731 | |||
732 | ret = omap_mcbsp_st_init(pdev); | ||
733 | if (ret) | ||
734 | goto err_st; | ||
735 | |||
736 | return 0; | ||
737 | |||
738 | err_st: | ||
739 | if (mcbsp->pdata->buffer_size) | ||
740 | sysfs_remove_group(&mcbsp->dev->kobj, &additional_attr_group); | ||
741 | err_thres: | ||
742 | clk_put(mcbsp->fclk); | ||
743 | return ret; | ||
744 | } | ||
745 | |||
62 | /* | 746 | /* |
63 | * Stream DMA parameters. DMA request line and port address are set runtime | 747 | * Stream DMA parameters. DMA request line and port address are set runtime |
64 | * since they are different between OMAP1 and later OMAPs | 748 | * since they are different between OMAP1 and later OMAPs |
@@ -71,6 +755,10 @@ static void omap_mcbsp_set_threshold(struct snd_pcm_substream *substream, | |||
71 | struct omap_mcbsp *mcbsp = snd_soc_dai_get_drvdata(cpu_dai); | 755 | struct omap_mcbsp *mcbsp = snd_soc_dai_get_drvdata(cpu_dai); |
72 | int words; | 756 | int words; |
73 | 757 | ||
758 | /* No need to proceed further if McBSP does not have FIFO */ | ||
759 | if (mcbsp->pdata->buffer_size == 0) | ||
760 | return; | ||
761 | |||
74 | /* | 762 | /* |
75 | * Configure McBSP threshold based on either: | 763 | * Configure McBSP threshold based on either: |
76 | * packet_size, when the sDMA is in packet mode, or based on the | 764 | * packet_size, when the sDMA is in packet mode, or based on the |
@@ -201,27 +889,26 @@ static int omap_mcbsp_dai_trigger(struct snd_pcm_substream *substream, int cmd, | |||
201 | struct snd_soc_dai *cpu_dai) | 889 | struct snd_soc_dai *cpu_dai) |
202 | { | 890 | { |
203 | struct omap_mcbsp *mcbsp = snd_soc_dai_get_drvdata(cpu_dai); | 891 | struct omap_mcbsp *mcbsp = snd_soc_dai_get_drvdata(cpu_dai); |
204 | int err = 0, play = (substream->stream == SNDRV_PCM_STREAM_PLAYBACK); | ||
205 | 892 | ||
206 | switch (cmd) { | 893 | switch (cmd) { |
207 | case SNDRV_PCM_TRIGGER_START: | 894 | case SNDRV_PCM_TRIGGER_START: |
208 | case SNDRV_PCM_TRIGGER_RESUME: | 895 | case SNDRV_PCM_TRIGGER_RESUME: |
209 | case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: | 896 | case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: |
210 | mcbsp->active++; | 897 | mcbsp->active++; |
211 | omap_mcbsp_start(mcbsp, play, !play); | 898 | omap_mcbsp_start(mcbsp, substream->stream); |
212 | break; | 899 | break; |
213 | 900 | ||
214 | case SNDRV_PCM_TRIGGER_STOP: | 901 | case SNDRV_PCM_TRIGGER_STOP: |
215 | case SNDRV_PCM_TRIGGER_SUSPEND: | 902 | case SNDRV_PCM_TRIGGER_SUSPEND: |
216 | case SNDRV_PCM_TRIGGER_PAUSE_PUSH: | 903 | case SNDRV_PCM_TRIGGER_PAUSE_PUSH: |
217 | omap_mcbsp_stop(mcbsp, play, !play); | 904 | omap_mcbsp_stop(mcbsp, substream->stream); |
218 | mcbsp->active--; | 905 | mcbsp->active--; |
219 | break; | 906 | break; |
220 | default: | 907 | default: |
221 | err = -EINVAL; | 908 | return -EINVAL; |
222 | } | 909 | } |
223 | 910 | ||
224 | return err; | 911 | return 0; |
225 | } | 912 | } |
226 | 913 | ||
227 | static snd_pcm_sframes_t omap_mcbsp_dai_delay( | 914 | static snd_pcm_sframes_t omap_mcbsp_dai_delay( |
@@ -234,6 +921,10 @@ static snd_pcm_sframes_t omap_mcbsp_dai_delay( | |||
234 | u16 fifo_use; | 921 | u16 fifo_use; |
235 | snd_pcm_sframes_t delay; | 922 | snd_pcm_sframes_t delay; |
236 | 923 | ||
924 | /* No need to proceed further if McBSP does not have FIFO */ | ||
925 | if (mcbsp->pdata->buffer_size == 0) | ||
926 | return 0; | ||
927 | |||
237 | if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) | 928 | if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) |
238 | fifo_use = omap_mcbsp_get_tx_delay(mcbsp); | 929 | fifo_use = omap_mcbsp_get_tx_delay(mcbsp); |
239 | else | 930 | else |
@@ -649,132 +1340,6 @@ static const struct snd_soc_component_driver omap_mcbsp_component = { | |||
649 | .name = "omap-mcbsp", | 1340 | .name = "omap-mcbsp", |
650 | }; | 1341 | }; |
651 | 1342 | ||
652 | static int omap_mcbsp_st_info_volsw(struct snd_kcontrol *kcontrol, | ||
653 | struct snd_ctl_elem_info *uinfo) | ||
654 | { | ||
655 | struct soc_mixer_control *mc = | ||
656 | (struct soc_mixer_control *)kcontrol->private_value; | ||
657 | int max = mc->max; | ||
658 | int min = mc->min; | ||
659 | |||
660 | uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; | ||
661 | uinfo->count = 1; | ||
662 | uinfo->value.integer.min = min; | ||
663 | uinfo->value.integer.max = max; | ||
664 | return 0; | ||
665 | } | ||
666 | |||
667 | #define OMAP_MCBSP_ST_CHANNEL_VOLUME(channel) \ | ||
668 | static int \ | ||
669 | omap_mcbsp_set_st_ch##channel##_volume(struct snd_kcontrol *kc, \ | ||
670 | struct snd_ctl_elem_value *uc) \ | ||
671 | { \ | ||
672 | struct snd_soc_dai *cpu_dai = snd_kcontrol_chip(kc); \ | ||
673 | struct omap_mcbsp *mcbsp = snd_soc_dai_get_drvdata(cpu_dai); \ | ||
674 | struct soc_mixer_control *mc = \ | ||
675 | (struct soc_mixer_control *)kc->private_value; \ | ||
676 | int max = mc->max; \ | ||
677 | int min = mc->min; \ | ||
678 | int val = uc->value.integer.value[0]; \ | ||
679 | \ | ||
680 | if (val < min || val > max) \ | ||
681 | return -EINVAL; \ | ||
682 | \ | ||
683 | /* OMAP McBSP implementation uses index values 0..4 */ \ | ||
684 | return omap_st_set_chgain(mcbsp, channel, val); \ | ||
685 | } \ | ||
686 | \ | ||
687 | static int \ | ||
688 | omap_mcbsp_get_st_ch##channel##_volume(struct snd_kcontrol *kc, \ | ||
689 | struct snd_ctl_elem_value *uc) \ | ||
690 | { \ | ||
691 | struct snd_soc_dai *cpu_dai = snd_kcontrol_chip(kc); \ | ||
692 | struct omap_mcbsp *mcbsp = snd_soc_dai_get_drvdata(cpu_dai); \ | ||
693 | s16 chgain; \ | ||
694 | \ | ||
695 | if (omap_st_get_chgain(mcbsp, channel, &chgain)) \ | ||
696 | return -EAGAIN; \ | ||
697 | \ | ||
698 | uc->value.integer.value[0] = chgain; \ | ||
699 | return 0; \ | ||
700 | } | ||
701 | |||
702 | OMAP_MCBSP_ST_CHANNEL_VOLUME(0) | ||
703 | OMAP_MCBSP_ST_CHANNEL_VOLUME(1) | ||
704 | |||
705 | static int omap_mcbsp_st_put_mode(struct snd_kcontrol *kcontrol, | ||
706 | struct snd_ctl_elem_value *ucontrol) | ||
707 | { | ||
708 | struct snd_soc_dai *cpu_dai = snd_kcontrol_chip(kcontrol); | ||
709 | struct omap_mcbsp *mcbsp = snd_soc_dai_get_drvdata(cpu_dai); | ||
710 | u8 value = ucontrol->value.integer.value[0]; | ||
711 | |||
712 | if (value == omap_st_is_enabled(mcbsp)) | ||
713 | return 0; | ||
714 | |||
715 | if (value) | ||
716 | omap_st_enable(mcbsp); | ||
717 | else | ||
718 | omap_st_disable(mcbsp); | ||
719 | |||
720 | return 1; | ||
721 | } | ||
722 | |||
723 | static int omap_mcbsp_st_get_mode(struct snd_kcontrol *kcontrol, | ||
724 | struct snd_ctl_elem_value *ucontrol) | ||
725 | { | ||
726 | struct snd_soc_dai *cpu_dai = snd_kcontrol_chip(kcontrol); | ||
727 | struct omap_mcbsp *mcbsp = snd_soc_dai_get_drvdata(cpu_dai); | ||
728 | |||
729 | ucontrol->value.integer.value[0] = omap_st_is_enabled(mcbsp); | ||
730 | return 0; | ||
731 | } | ||
732 | |||
733 | #define OMAP_MCBSP_ST_CONTROLS(port) \ | ||
734 | static const struct snd_kcontrol_new omap_mcbsp##port##_st_controls[] = { \ | ||
735 | SOC_SINGLE_EXT("McBSP" #port " Sidetone Switch", 1, 0, 1, 0, \ | ||
736 | omap_mcbsp_st_get_mode, omap_mcbsp_st_put_mode), \ | ||
737 | OMAP_MCBSP_SOC_SINGLE_S16_EXT("McBSP" #port " Sidetone Channel 0 Volume", \ | ||
738 | -32768, 32767, \ | ||
739 | omap_mcbsp_get_st_ch0_volume, \ | ||
740 | omap_mcbsp_set_st_ch0_volume), \ | ||
741 | OMAP_MCBSP_SOC_SINGLE_S16_EXT("McBSP" #port " Sidetone Channel 1 Volume", \ | ||
742 | -32768, 32767, \ | ||
743 | omap_mcbsp_get_st_ch1_volume, \ | ||
744 | omap_mcbsp_set_st_ch1_volume), \ | ||
745 | } | ||
746 | |||
747 | OMAP_MCBSP_ST_CONTROLS(2); | ||
748 | OMAP_MCBSP_ST_CONTROLS(3); | ||
749 | |||
750 | int omap_mcbsp_st_add_controls(struct snd_soc_pcm_runtime *rtd, int port_id) | ||
751 | { | ||
752 | struct snd_soc_dai *cpu_dai = rtd->cpu_dai; | ||
753 | struct omap_mcbsp *mcbsp = snd_soc_dai_get_drvdata(cpu_dai); | ||
754 | |||
755 | if (!mcbsp->st_data) { | ||
756 | dev_warn(mcbsp->dev, "No sidetone data for port\n"); | ||
757 | return 0; | ||
758 | } | ||
759 | |||
760 | switch (port_id) { | ||
761 | case 2: /* McBSP 2 */ | ||
762 | return snd_soc_add_dai_controls(cpu_dai, | ||
763 | omap_mcbsp2_st_controls, | ||
764 | ARRAY_SIZE(omap_mcbsp2_st_controls)); | ||
765 | case 3: /* McBSP 3 */ | ||
766 | return snd_soc_add_dai_controls(cpu_dai, | ||
767 | omap_mcbsp3_st_controls, | ||
768 | ARRAY_SIZE(omap_mcbsp3_st_controls)); | ||
769 | default: | ||
770 | dev_err(mcbsp->dev, "Port %d not supported\n", port_id); | ||
771 | break; | ||
772 | } | ||
773 | |||
774 | return -EINVAL; | ||
775 | } | ||
776 | EXPORT_SYMBOL_GPL(omap_mcbsp_st_add_controls); | ||
777 | |||
778 | static struct omap_mcbsp_platform_data omap2420_pdata = { | 1343 | static struct omap_mcbsp_platform_data omap2420_pdata = { |
779 | .reg_step = 4, | 1344 | .reg_step = 4, |
780 | .reg_size = 2, | 1345 | .reg_size = 2, |
@@ -862,6 +1427,11 @@ static int asoc_mcbsp_probe(struct platform_device *pdev) | |||
862 | if (ret) | 1427 | if (ret) |
863 | return ret; | 1428 | return ret; |
864 | 1429 | ||
1430 | if (mcbsp->pdata->reg_size == 2) { | ||
1431 | omap_mcbsp_dai.playback.formats = SNDRV_PCM_FMTBIT_S16_LE; | ||
1432 | omap_mcbsp_dai.capture.formats = SNDRV_PCM_FMTBIT_S16_LE; | ||
1433 | } | ||
1434 | |||
865 | ret = devm_snd_soc_register_component(&pdev->dev, | 1435 | ret = devm_snd_soc_register_component(&pdev->dev, |
866 | &omap_mcbsp_component, | 1436 | &omap_mcbsp_component, |
867 | &omap_mcbsp_dai, 1); | 1437 | &omap_mcbsp_dai, 1); |
@@ -881,7 +1451,10 @@ static int asoc_mcbsp_remove(struct platform_device *pdev) | |||
881 | if (pm_qos_request_active(&mcbsp->pm_qos_req)) | 1451 | if (pm_qos_request_active(&mcbsp->pm_qos_req)) |
882 | pm_qos_remove_request(&mcbsp->pm_qos_req); | 1452 | pm_qos_remove_request(&mcbsp->pm_qos_req); |
883 | 1453 | ||
884 | omap_mcbsp_cleanup(mcbsp); | 1454 | if (mcbsp->pdata->buffer_size) |
1455 | sysfs_remove_group(&mcbsp->dev->kobj, &additional_attr_group); | ||
1456 | |||
1457 | omap_mcbsp_st_cleanup(pdev); | ||
885 | 1458 | ||
886 | clk_put(mcbsp->fclk); | 1459 | clk_put(mcbsp->fclk); |
887 | 1460 | ||
diff --git a/sound/soc/omap/omap-mcbsp.h b/sound/soc/ti/omap-mcbsp.h index 2e3369c27be3..7911d24898c9 100644 --- a/sound/soc/omap/omap-mcbsp.h +++ b/sound/soc/ti/omap-mcbsp.h | |||
@@ -22,8 +22,10 @@ | |||
22 | * | 22 | * |
23 | */ | 23 | */ |
24 | 24 | ||
25 | #ifndef __OMAP_I2S_H__ | 25 | #ifndef __OMAP_MCBSP_H__ |
26 | #define __OMAP_I2S_H__ | 26 | #define __OMAP_MCBSP_H__ |
27 | |||
28 | #include <sound/dmaengine_pcm.h> | ||
27 | 29 | ||
28 | /* Source clocks for McBSP sample rate generator */ | 30 | /* Source clocks for McBSP sample rate generator */ |
29 | enum omap_mcbsp_clksrg_clk { | 31 | enum omap_mcbsp_clksrg_clk { |
@@ -41,4 +43,4 @@ enum omap_mcbsp_div { | |||
41 | 43 | ||
42 | int omap_mcbsp_st_add_controls(struct snd_soc_pcm_runtime *rtd, int port_id); | 44 | int omap_mcbsp_st_add_controls(struct snd_soc_pcm_runtime *rtd, int port_id); |
43 | 45 | ||
44 | #endif | 46 | #endif /* __OMAP_MCBSP_H__ */ |
diff --git a/sound/soc/omap/omap-mcpdm.c b/sound/soc/ti/omap-mcpdm.c index 7d5bdc5a2890..7d5bdc5a2890 100644 --- a/sound/soc/omap/omap-mcpdm.c +++ b/sound/soc/ti/omap-mcpdm.c | |||
diff --git a/sound/soc/omap/omap-mcpdm.h b/sound/soc/ti/omap-mcpdm.h index de8cf26595b1..de8cf26595b1 100644 --- a/sound/soc/omap/omap-mcpdm.h +++ b/sound/soc/ti/omap-mcpdm.h | |||
diff --git a/sound/soc/omap/omap-twl4030.c b/sound/soc/ti/omap-twl4030.c index cccc316743fa..cccc316743fa 100644 --- a/sound/soc/omap/omap-twl4030.c +++ b/sound/soc/ti/omap-twl4030.c | |||
diff --git a/sound/soc/omap/omap3pandora.c b/sound/soc/ti/omap3pandora.c index 4e3de712159c..4e3de712159c 100644 --- a/sound/soc/omap/omap3pandora.c +++ b/sound/soc/ti/omap3pandora.c | |||
diff --git a/sound/soc/omap/osk5912.c b/sound/soc/ti/osk5912.c index e4096779ca05..e4096779ca05 100644 --- a/sound/soc/omap/osk5912.c +++ b/sound/soc/ti/osk5912.c | |||
diff --git a/sound/soc/omap/rx51.c b/sound/soc/ti/rx51.c index 57448bd5ad77..57448bd5ad77 100644 --- a/sound/soc/omap/rx51.c +++ b/sound/soc/ti/rx51.c | |||
diff --git a/sound/soc/omap/sdma-pcm.c b/sound/soc/ti/sdma-pcm.c index 21a9c2499d48..21a9c2499d48 100644 --- a/sound/soc/omap/sdma-pcm.c +++ b/sound/soc/ti/sdma-pcm.c | |||
diff --git a/sound/soc/omap/sdma-pcm.h b/sound/soc/ti/sdma-pcm.h index 34a7f90b2587..cb0627c8dd34 100644 --- a/sound/soc/omap/sdma-pcm.h +++ b/sound/soc/ti/sdma-pcm.h | |||
@@ -7,7 +7,7 @@ | |||
7 | #ifndef __SDMA_PCM_H__ | 7 | #ifndef __SDMA_PCM_H__ |
8 | #define __SDMA_PCM_H__ | 8 | #define __SDMA_PCM_H__ |
9 | 9 | ||
10 | #if IS_ENABLED(CONFIG_SND_SDMA_SOC) | 10 | #if IS_ENABLED(CONFIG_SND_SOC_TI_SDMA_PCM) |
11 | int sdma_pcm_platform_register(struct device *dev, | 11 | int sdma_pcm_platform_register(struct device *dev, |
12 | char *txdmachan, char *rxdmachan); | 12 | char *txdmachan, char *rxdmachan); |
13 | #else | 13 | #else |
@@ -16,6 +16,6 @@ static inline int sdma_pcm_platform_register(struct device *dev, | |||
16 | { | 16 | { |
17 | return -ENODEV; | 17 | return -ENODEV; |
18 | } | 18 | } |
19 | #endif /* CONFIG_SND_SDMA_SOC */ | 19 | #endif /* CONFIG_SND_SOC_TI_SDMA_PCM */ |
20 | 20 | ||
21 | #endif /* __SDMA_PCM_H__ */ | 21 | #endif /* __SDMA_PCM_H__ */ |
diff --git a/sound/soc/xilinx/Kconfig b/sound/soc/xilinx/Kconfig new file mode 100644 index 000000000000..25e287feb58c --- /dev/null +++ b/sound/soc/xilinx/Kconfig | |||
@@ -0,0 +1,8 @@ | |||
1 | config SND_SOC_XILINX_I2S | ||
2 | tristate "Audio support for the the Xilinx I2S" | ||
3 | help | ||
4 | Select this option to enable Xilinx I2S Audio. This enables | ||
5 | I2S playback and capture using xilinx soft IP. In transmitter | ||
6 | mode, IP receives audio in AES format, extracts PCM and sends | ||
7 | PCM data. In receiver mode, IP receives PCM audio and | ||
8 | encapsulates PCM in AES format and sends AES data. | ||
diff --git a/sound/soc/xilinx/Makefile b/sound/soc/xilinx/Makefile new file mode 100644 index 000000000000..6c1209b9ee75 --- /dev/null +++ b/sound/soc/xilinx/Makefile | |||
@@ -0,0 +1,2 @@ | |||
1 | snd-soc-xlnx-i2s-objs := xlnx_i2s.o | ||
2 | obj-$(CONFIG_SND_SOC_XILINX_I2S) += snd-soc-xlnx-i2s.o | ||
diff --git a/sound/soc/xilinx/xlnx_i2s.c b/sound/soc/xilinx/xlnx_i2s.c new file mode 100644 index 000000000000..d4ae9eff41ce --- /dev/null +++ b/sound/soc/xilinx/xlnx_i2s.c | |||
@@ -0,0 +1,185 @@ | |||
1 | // SPDX-License-Identifier: GPL-2.0 | ||
2 | /* | ||
3 | * Xilinx ASoC I2S audio support | ||
4 | * | ||
5 | * Copyright (C) 2018 Xilinx, Inc. | ||
6 | * | ||
7 | * Author: Praveen Vuppala <praveenv@xilinx.com> | ||
8 | * Author: Maruthi Srinivas Bayyavarapu <maruthis@xilinx.com> | ||
9 | */ | ||
10 | |||
11 | #include <linux/io.h> | ||
12 | #include <linux/module.h> | ||
13 | #include <linux/of.h> | ||
14 | #include <linux/of_platform.h> | ||
15 | #include <linux/platform_device.h> | ||
16 | #include <sound/pcm_params.h> | ||
17 | #include <sound/soc.h> | ||
18 | |||
19 | #define DRV_NAME "xlnx_i2s" | ||
20 | |||
21 | #define I2S_CORE_CTRL_OFFSET 0x08 | ||
22 | #define I2S_I2STIM_OFFSET 0x20 | ||
23 | #define I2S_CH0_OFFSET 0x30 | ||
24 | #define I2S_I2STIM_VALID_MASK GENMASK(7, 0) | ||
25 | |||
26 | static int xlnx_i2s_set_sclkout_div(struct snd_soc_dai *cpu_dai, | ||
27 | int div_id, int div) | ||
28 | { | ||
29 | void __iomem *base = snd_soc_dai_get_drvdata(cpu_dai); | ||
30 | |||
31 | if (!div || (div & ~I2S_I2STIM_VALID_MASK)) | ||
32 | return -EINVAL; | ||
33 | |||
34 | writel(div, base + I2S_I2STIM_OFFSET); | ||
35 | |||
36 | return 0; | ||
37 | } | ||
38 | |||
39 | static int xlnx_i2s_hw_params(struct snd_pcm_substream *substream, | ||
40 | struct snd_pcm_hw_params *params, | ||
41 | struct snd_soc_dai *i2s_dai) | ||
42 | { | ||
43 | u32 reg_off, chan_id; | ||
44 | void __iomem *base = snd_soc_dai_get_drvdata(i2s_dai); | ||
45 | |||
46 | chan_id = params_channels(params) / 2; | ||
47 | |||
48 | while (chan_id > 0) { | ||
49 | reg_off = I2S_CH0_OFFSET + ((chan_id - 1) * 4); | ||
50 | writel(chan_id, base + reg_off); | ||
51 | chan_id--; | ||
52 | } | ||
53 | |||
54 | return 0; | ||
55 | } | ||
56 | |||
57 | static int xlnx_i2s_trigger(struct snd_pcm_substream *substream, int cmd, | ||
58 | struct snd_soc_dai *i2s_dai) | ||
59 | { | ||
60 | void __iomem *base = snd_soc_dai_get_drvdata(i2s_dai); | ||
61 | |||
62 | switch (cmd) { | ||
63 | case SNDRV_PCM_TRIGGER_START: | ||
64 | case SNDRV_PCM_TRIGGER_RESUME: | ||
65 | case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: | ||
66 | writel(1, base + I2S_CORE_CTRL_OFFSET); | ||
67 | break; | ||
68 | case SNDRV_PCM_TRIGGER_STOP: | ||
69 | case SNDRV_PCM_TRIGGER_SUSPEND: | ||
70 | case SNDRV_PCM_TRIGGER_PAUSE_PUSH: | ||
71 | writel(0, base + I2S_CORE_CTRL_OFFSET); | ||
72 | break; | ||
73 | default: | ||
74 | return -EINVAL; | ||
75 | } | ||
76 | |||
77 | return 0; | ||
78 | } | ||
79 | |||
80 | static const struct snd_soc_dai_ops xlnx_i2s_dai_ops = { | ||
81 | .trigger = xlnx_i2s_trigger, | ||
82 | .set_clkdiv = xlnx_i2s_set_sclkout_div, | ||
83 | .hw_params = xlnx_i2s_hw_params | ||
84 | }; | ||
85 | |||
86 | static const struct snd_soc_component_driver xlnx_i2s_component = { | ||
87 | .name = DRV_NAME, | ||
88 | }; | ||
89 | |||
90 | static const struct of_device_id xlnx_i2s_of_match[] = { | ||
91 | { .compatible = "xlnx,i2s-transmitter-1.0", }, | ||
92 | { .compatible = "xlnx,i2s-receiver-1.0", }, | ||
93 | {}, | ||
94 | }; | ||
95 | MODULE_DEVICE_TABLE(of, xlnx_i2s_of_match); | ||
96 | |||
97 | static int xlnx_i2s_probe(struct platform_device *pdev) | ||
98 | { | ||
99 | struct resource *res; | ||
100 | void __iomem *base; | ||
101 | struct snd_soc_dai_driver *dai_drv; | ||
102 | int ret; | ||
103 | u32 ch, format, data_width; | ||
104 | struct device *dev = &pdev->dev; | ||
105 | struct device_node *node = dev->of_node; | ||
106 | |||
107 | dai_drv = devm_kzalloc(&pdev->dev, sizeof(*dai_drv), GFP_KERNEL); | ||
108 | if (!dai_drv) | ||
109 | return -ENOMEM; | ||
110 | |||
111 | res = platform_get_resource(pdev, IORESOURCE_MEM, 0); | ||
112 | base = devm_ioremap_resource(&pdev->dev, res); | ||
113 | if (IS_ERR(base)) | ||
114 | return PTR_ERR(base); | ||
115 | |||
116 | ret = of_property_read_u32(node, "xlnx,num-channels", &ch); | ||
117 | if (ret < 0) { | ||
118 | dev_err(dev, "cannot get supported channels\n"); | ||
119 | return ret; | ||
120 | } | ||
121 | ch = ch * 2; | ||
122 | |||
123 | ret = of_property_read_u32(node, "xlnx,dwidth", &data_width); | ||
124 | if (ret < 0) { | ||
125 | dev_err(dev, "cannot get data width\n"); | ||
126 | return ret; | ||
127 | } | ||
128 | switch (data_width) { | ||
129 | case 16: | ||
130 | format = SNDRV_PCM_FMTBIT_S16_LE; | ||
131 | break; | ||
132 | case 24: | ||
133 | format = SNDRV_PCM_FMTBIT_S24_LE; | ||
134 | break; | ||
135 | default: | ||
136 | return -EINVAL; | ||
137 | } | ||
138 | |||
139 | if (of_device_is_compatible(node, "xlnx,i2s-transmitter-1.0")) { | ||
140 | dai_drv->name = "xlnx_i2s_playback"; | ||
141 | dai_drv->playback.stream_name = "Playback"; | ||
142 | dai_drv->playback.formats = format; | ||
143 | dai_drv->playback.channels_min = ch; | ||
144 | dai_drv->playback.channels_max = ch; | ||
145 | dai_drv->playback.rates = SNDRV_PCM_RATE_8000_192000; | ||
146 | dai_drv->ops = &xlnx_i2s_dai_ops; | ||
147 | } else if (of_device_is_compatible(node, "xlnx,i2s-receiver-1.0")) { | ||
148 | dai_drv->name = "xlnx_i2s_capture"; | ||
149 | dai_drv->capture.stream_name = "Capture"; | ||
150 | dai_drv->capture.formats = format; | ||
151 | dai_drv->capture.channels_min = ch; | ||
152 | dai_drv->capture.channels_max = ch; | ||
153 | dai_drv->capture.rates = SNDRV_PCM_RATE_8000_192000; | ||
154 | dai_drv->ops = &xlnx_i2s_dai_ops; | ||
155 | } else { | ||
156 | return -ENODEV; | ||
157 | } | ||
158 | |||
159 | dev_set_drvdata(&pdev->dev, base); | ||
160 | |||
161 | ret = devm_snd_soc_register_component(&pdev->dev, &xlnx_i2s_component, | ||
162 | dai_drv, 1); | ||
163 | if (ret) { | ||
164 | dev_err(&pdev->dev, "i2s component registration failed\n"); | ||
165 | return ret; | ||
166 | } | ||
167 | |||
168 | dev_info(&pdev->dev, "%s DAI registered\n", dai_drv->name); | ||
169 | |||
170 | return ret; | ||
171 | } | ||
172 | |||
173 | static struct platform_driver xlnx_i2s_aud_driver = { | ||
174 | .driver = { | ||
175 | .name = DRV_NAME, | ||
176 | .of_match_table = xlnx_i2s_of_match, | ||
177 | }, | ||
178 | .probe = xlnx_i2s_probe, | ||
179 | }; | ||
180 | |||
181 | module_platform_driver(xlnx_i2s_aud_driver); | ||
182 | |||
183 | MODULE_LICENSE("GPL v2"); | ||
184 | MODULE_AUTHOR("Praveen Vuppala <praveenv@xilinx.com>"); | ||
185 | MODULE_AUTHOR("Maruthi Srinivas Bayyavarapu <maruthis@xilinx.com>"); | ||