diff options
Diffstat (limited to 'sound')
240 files changed, 11989 insertions, 3017 deletions
diff --git a/sound/atmel/ac97c.c b/sound/atmel/ac97c.c index cf4cedf2b420..6dad042630d8 100644 --- a/sound/atmel/ac97c.c +++ b/sound/atmel/ac97c.c | |||
@@ -916,7 +916,6 @@ static struct ac97c_platform_data *atmel_ac97c_probe_dt(struct device *dev) | |||
916 | { | 916 | { |
917 | struct ac97c_platform_data *pdata; | 917 | struct ac97c_platform_data *pdata; |
918 | struct device_node *node = dev->of_node; | 918 | struct device_node *node = dev->of_node; |
919 | const struct of_device_id *match; | ||
920 | 919 | ||
921 | if (!node) { | 920 | if (!node) { |
922 | dev_err(dev, "Device does not have associated DT data\n"); | 921 | dev_err(dev, "Device does not have associated DT data\n"); |
diff --git a/sound/core/pcm_lib.c b/sound/core/pcm_lib.c index ac6b33f3779c..7d45645f10ba 100644 --- a/sound/core/pcm_lib.c +++ b/sound/core/pcm_lib.c | |||
@@ -339,7 +339,7 @@ static int snd_pcm_update_hw_ptr0(struct snd_pcm_substream *substream, | |||
339 | if (delta > new_hw_ptr) { | 339 | if (delta > new_hw_ptr) { |
340 | /* check for double acknowledged interrupts */ | 340 | /* check for double acknowledged interrupts */ |
341 | hdelta = curr_jiffies - runtime->hw_ptr_jiffies; | 341 | hdelta = curr_jiffies - runtime->hw_ptr_jiffies; |
342 | if (hdelta > runtime->hw_ptr_buffer_jiffies/2) { | 342 | if (hdelta > runtime->hw_ptr_buffer_jiffies/2 + 1) { |
343 | hw_base += runtime->buffer_size; | 343 | hw_base += runtime->buffer_size; |
344 | if (hw_base >= runtime->boundary) { | 344 | if (hw_base >= runtime->boundary) { |
345 | hw_base = 0; | 345 | hw_base = 0; |
diff --git a/sound/hda/hdac_regmap.c b/sound/hda/hdac_regmap.c index 7371e0c3926f..1eabcdf69457 100644 --- a/sound/hda/hdac_regmap.c +++ b/sound/hda/hdac_regmap.c | |||
@@ -246,6 +246,9 @@ static int hda_reg_read(void *context, unsigned int reg, unsigned int *val) | |||
246 | return hda_reg_read_stereo_amp(codec, reg, val); | 246 | return hda_reg_read_stereo_amp(codec, reg, val); |
247 | if (verb == AC_VERB_GET_PROC_COEF) | 247 | if (verb == AC_VERB_GET_PROC_COEF) |
248 | return hda_reg_read_coef(codec, reg, val); | 248 | return hda_reg_read_coef(codec, reg, val); |
249 | if ((verb & 0x700) == AC_VERB_SET_AMP_GAIN_MUTE) | ||
250 | reg &= ~AC_AMP_FAKE_MUTE; | ||
251 | |||
249 | err = snd_hdac_exec_verb(codec, reg, 0, val); | 252 | err = snd_hdac_exec_verb(codec, reg, 0, val); |
250 | if (err < 0) | 253 | if (err < 0) |
251 | return err; | 254 | return err; |
@@ -265,6 +268,9 @@ static int hda_reg_write(void *context, unsigned int reg, unsigned int val) | |||
265 | unsigned int verb; | 268 | unsigned int verb; |
266 | int i, bytes, err; | 269 | int i, bytes, err; |
267 | 270 | ||
271 | if (codec->caps_overwriting) | ||
272 | return 0; | ||
273 | |||
268 | reg &= ~0x00080000U; /* drop GET bit */ | 274 | reg &= ~0x00080000U; /* drop GET bit */ |
269 | reg |= (codec->addr << 28); | 275 | reg |= (codec->addr << 28); |
270 | verb = get_verb(reg); | 276 | verb = get_verb(reg); |
@@ -280,6 +286,8 @@ static int hda_reg_write(void *context, unsigned int reg, unsigned int val) | |||
280 | 286 | ||
281 | switch (verb & 0xf00) { | 287 | switch (verb & 0xf00) { |
282 | case AC_VERB_SET_AMP_GAIN_MUTE: | 288 | case AC_VERB_SET_AMP_GAIN_MUTE: |
289 | if ((reg & AC_AMP_FAKE_MUTE) && (val & AC_AMP_MUTE)) | ||
290 | val = 0; | ||
283 | verb = AC_VERB_SET_AMP_GAIN_MUTE; | 291 | verb = AC_VERB_SET_AMP_GAIN_MUTE; |
284 | if (reg & AC_AMP_GET_LEFT) | 292 | if (reg & AC_AMP_GET_LEFT) |
285 | verb |= AC_AMP_SET_LEFT >> 8; | 293 | verb |= AC_AMP_SET_LEFT >> 8; |
diff --git a/sound/pci/emu10k1/emu10k1.c b/sound/pci/emu10k1/emu10k1.c index 37d0220a094c..db7a2e5e4a14 100644 --- a/sound/pci/emu10k1/emu10k1.c +++ b/sound/pci/emu10k1/emu10k1.c | |||
@@ -183,8 +183,10 @@ static int snd_card_emu10k1_probe(struct pci_dev *pci, | |||
183 | } | 183 | } |
184 | #endif | 184 | #endif |
185 | 185 | ||
186 | strcpy(card->driver, emu->card_capabilities->driver); | 186 | strlcpy(card->driver, emu->card_capabilities->driver, |
187 | strcpy(card->shortname, emu->card_capabilities->name); | 187 | sizeof(card->driver)); |
188 | strlcpy(card->shortname, emu->card_capabilities->name, | ||
189 | sizeof(card->shortname)); | ||
188 | snprintf(card->longname, sizeof(card->longname), | 190 | snprintf(card->longname, sizeof(card->longname), |
189 | "%s (rev.%d, serial:0x%x) at 0x%lx, irq %i", | 191 | "%s (rev.%d, serial:0x%x) at 0x%lx, irq %i", |
190 | card->shortname, emu->revision, emu->serial, emu->port, emu->irq); | 192 | card->shortname, emu->revision, emu->serial, emu->port, emu->irq); |
diff --git a/sound/pci/emu10k1/emu10k1_callback.c b/sound/pci/emu10k1/emu10k1_callback.c index 874cd76c7b7f..d2c7ea3a7610 100644 --- a/sound/pci/emu10k1/emu10k1_callback.c +++ b/sound/pci/emu10k1/emu10k1_callback.c | |||
@@ -415,7 +415,7 @@ start_voice(struct snd_emux_voice *vp) | |||
415 | snd_emu10k1_ptr_write(hw, Z2, ch, 0); | 415 | snd_emu10k1_ptr_write(hw, Z2, ch, 0); |
416 | 416 | ||
417 | /* invalidate maps */ | 417 | /* invalidate maps */ |
418 | temp = (hw->silent_page.addr << 1) | MAP_PTI_MASK; | 418 | temp = (hw->silent_page.addr << hw->address_mode) | (hw->address_mode ? MAP_PTI_MASK1 : MAP_PTI_MASK0); |
419 | snd_emu10k1_ptr_write(hw, MAPA, ch, temp); | 419 | snd_emu10k1_ptr_write(hw, MAPA, ch, temp); |
420 | snd_emu10k1_ptr_write(hw, MAPB, ch, temp); | 420 | snd_emu10k1_ptr_write(hw, MAPB, ch, temp); |
421 | #if 0 | 421 | #if 0 |
@@ -436,7 +436,7 @@ start_voice(struct snd_emux_voice *vp) | |||
436 | snd_emu10k1_ptr_write(hw, CDF, ch, sample); | 436 | snd_emu10k1_ptr_write(hw, CDF, ch, sample); |
437 | 437 | ||
438 | /* invalidate maps */ | 438 | /* invalidate maps */ |
439 | temp = ((unsigned int)hw->silent_page.addr << 1) | MAP_PTI_MASK; | 439 | temp = ((unsigned int)hw->silent_page.addr << hw_address_mode) | (hw->address_mode ? MAP_PTI_MASK1 : MAP_PTI_MASK0); |
440 | snd_emu10k1_ptr_write(hw, MAPA, ch, temp); | 440 | snd_emu10k1_ptr_write(hw, MAPA, ch, temp); |
441 | snd_emu10k1_ptr_write(hw, MAPB, ch, temp); | 441 | snd_emu10k1_ptr_write(hw, MAPB, ch, temp); |
442 | 442 | ||
diff --git a/sound/pci/emu10k1/emu10k1_main.c b/sound/pci/emu10k1/emu10k1_main.c index 54079f5d5673..a4548147c621 100644 --- a/sound/pci/emu10k1/emu10k1_main.c +++ b/sound/pci/emu10k1/emu10k1_main.c | |||
@@ -282,7 +282,7 @@ static int snd_emu10k1_init(struct snd_emu10k1 *emu, int enable_ir, int resume) | |||
282 | snd_emu10k1_ptr_write(emu, TCB, 0, 0); /* taken from original driver */ | 282 | snd_emu10k1_ptr_write(emu, TCB, 0, 0); /* taken from original driver */ |
283 | snd_emu10k1_ptr_write(emu, TCBS, 0, 4); /* taken from original driver */ | 283 | snd_emu10k1_ptr_write(emu, TCBS, 0, 4); /* taken from original driver */ |
284 | 284 | ||
285 | silent_page = (emu->silent_page.addr << 1) | MAP_PTI_MASK; | 285 | silent_page = (emu->silent_page.addr << emu->address_mode) | (emu->address_mode ? MAP_PTI_MASK1 : MAP_PTI_MASK0); |
286 | for (ch = 0; ch < NUM_G; ch++) { | 286 | for (ch = 0; ch < NUM_G; ch++) { |
287 | snd_emu10k1_ptr_write(emu, MAPA, ch, silent_page); | 287 | snd_emu10k1_ptr_write(emu, MAPA, ch, silent_page); |
288 | snd_emu10k1_ptr_write(emu, MAPB, ch, silent_page); | 288 | snd_emu10k1_ptr_write(emu, MAPB, ch, silent_page); |
@@ -348,6 +348,11 @@ static int snd_emu10k1_init(struct snd_emu10k1 *emu, int enable_ir, int resume) | |||
348 | outl(reg | A_IOCFG_GPOUT0, emu->port + A_IOCFG); | 348 | outl(reg | A_IOCFG_GPOUT0, emu->port + A_IOCFG); |
349 | } | 349 | } |
350 | 350 | ||
351 | if (emu->address_mode == 0) { | ||
352 | /* use 16M in 4G */ | ||
353 | outl(inl(emu->port + HCFG) | HCFG_EXPANDED_MEM, emu->port + HCFG); | ||
354 | } | ||
355 | |||
351 | return 0; | 356 | return 0; |
352 | } | 357 | } |
353 | 358 | ||
@@ -1446,7 +1451,7 @@ static struct snd_emu_chip_details emu_chip_details[] = { | |||
1446 | * | 1451 | * |
1447 | */ | 1452 | */ |
1448 | {.vendor = 0x1102, .device = 0x0008, .subsystem = 0x20011102, | 1453 | {.vendor = 0x1102, .device = 0x0008, .subsystem = 0x20011102, |
1449 | .driver = "Audigy2", .name = "SB Audigy 2 ZS Notebook [SB0530]", | 1454 | .driver = "Audigy2", .name = "Audigy 2 ZS Notebook [SB0530]", |
1450 | .id = "Audigy2", | 1455 | .id = "Audigy2", |
1451 | .emu10k2_chip = 1, | 1456 | .emu10k2_chip = 1, |
1452 | .ca0108_chip = 1, | 1457 | .ca0108_chip = 1, |
@@ -1596,7 +1601,7 @@ static struct snd_emu_chip_details emu_chip_details[] = { | |||
1596 | .adc_1361t = 1, /* 24 bit capture instead of 16bit */ | 1601 | .adc_1361t = 1, /* 24 bit capture instead of 16bit */ |
1597 | .ac97_chip = 1} , | 1602 | .ac97_chip = 1} , |
1598 | {.vendor = 0x1102, .device = 0x0004, .subsystem = 0x10051102, | 1603 | {.vendor = 0x1102, .device = 0x0004, .subsystem = 0x10051102, |
1599 | .driver = "Audigy2", .name = "SB Audigy 2 Platinum EX [SB0280]", | 1604 | .driver = "Audigy2", .name = "Audigy 2 Platinum EX [SB0280]", |
1600 | .id = "Audigy2", | 1605 | .id = "Audigy2", |
1601 | .emu10k2_chip = 1, | 1606 | .emu10k2_chip = 1, |
1602 | .ca0102_chip = 1, | 1607 | .ca0102_chip = 1, |
@@ -1902,8 +1907,10 @@ int snd_emu10k1_create(struct snd_card *card, | |||
1902 | 1907 | ||
1903 | is_audigy = emu->audigy = c->emu10k2_chip; | 1908 | is_audigy = emu->audigy = c->emu10k2_chip; |
1904 | 1909 | ||
1910 | /* set addressing mode */ | ||
1911 | emu->address_mode = is_audigy ? 0 : 1; | ||
1905 | /* set the DMA transfer mask */ | 1912 | /* set the DMA transfer mask */ |
1906 | emu->dma_mask = is_audigy ? AUDIGY_DMA_MASK : EMU10K1_DMA_MASK; | 1913 | emu->dma_mask = emu->address_mode ? EMU10K1_DMA_MASK : AUDIGY_DMA_MASK; |
1907 | if (pci_set_dma_mask(pci, emu->dma_mask) < 0 || | 1914 | if (pci_set_dma_mask(pci, emu->dma_mask) < 0 || |
1908 | pci_set_consistent_dma_mask(pci, emu->dma_mask) < 0) { | 1915 | pci_set_consistent_dma_mask(pci, emu->dma_mask) < 0) { |
1909 | dev_err(card->dev, | 1916 | dev_err(card->dev, |
@@ -1928,7 +1935,7 @@ int snd_emu10k1_create(struct snd_card *card, | |||
1928 | 1935 | ||
1929 | emu->max_cache_pages = max_cache_bytes >> PAGE_SHIFT; | 1936 | emu->max_cache_pages = max_cache_bytes >> PAGE_SHIFT; |
1930 | if (snd_dma_alloc_pages(SNDRV_DMA_TYPE_DEV, snd_dma_pci_data(pci), | 1937 | if (snd_dma_alloc_pages(SNDRV_DMA_TYPE_DEV, snd_dma_pci_data(pci), |
1931 | 32 * 1024, &emu->ptb_pages) < 0) { | 1938 | (emu->address_mode ? 32 : 16) * 1024, &emu->ptb_pages) < 0) { |
1932 | err = -ENOMEM; | 1939 | err = -ENOMEM; |
1933 | goto error; | 1940 | goto error; |
1934 | } | 1941 | } |
@@ -2027,8 +2034,8 @@ int snd_emu10k1_create(struct snd_card *card, | |||
2027 | 2034 | ||
2028 | /* Clear silent pages and set up pointers */ | 2035 | /* Clear silent pages and set up pointers */ |
2029 | memset(emu->silent_page.area, 0, PAGE_SIZE); | 2036 | memset(emu->silent_page.area, 0, PAGE_SIZE); |
2030 | silent_page = emu->silent_page.addr << 1; | 2037 | silent_page = emu->silent_page.addr << emu->address_mode; |
2031 | for (idx = 0; idx < MAXPAGES; idx++) | 2038 | for (idx = 0; idx < (emu->address_mode ? MAXPAGES1 : MAXPAGES0); idx++) |
2032 | ((u32 *)emu->ptb_pages.area)[idx] = cpu_to_le32(silent_page | idx); | 2039 | ((u32 *)emu->ptb_pages.area)[idx] = cpu_to_le32(silent_page | idx); |
2033 | 2040 | ||
2034 | /* set up voice indices */ | 2041 | /* set up voice indices */ |
diff --git a/sound/pci/emu10k1/emupcm.c b/sound/pci/emu10k1/emupcm.c index 0dc07385af0e..14a305bd8a98 100644 --- a/sound/pci/emu10k1/emupcm.c +++ b/sound/pci/emu10k1/emupcm.c | |||
@@ -380,7 +380,7 @@ static void snd_emu10k1_pcm_init_voice(struct snd_emu10k1 *emu, | |||
380 | snd_emu10k1_ptr_write(emu, Z1, voice, 0); | 380 | snd_emu10k1_ptr_write(emu, Z1, voice, 0); |
381 | snd_emu10k1_ptr_write(emu, Z2, voice, 0); | 381 | snd_emu10k1_ptr_write(emu, Z2, voice, 0); |
382 | /* invalidate maps */ | 382 | /* invalidate maps */ |
383 | silent_page = ((unsigned int)emu->silent_page.addr << 1) | MAP_PTI_MASK; | 383 | silent_page = ((unsigned int)emu->silent_page.addr << emu->address_mode) | (emu->address_mode ? MAP_PTI_MASK1 : MAP_PTI_MASK0); |
384 | snd_emu10k1_ptr_write(emu, MAPA, voice, silent_page); | 384 | snd_emu10k1_ptr_write(emu, MAPA, voice, silent_page); |
385 | snd_emu10k1_ptr_write(emu, MAPB, voice, silent_page); | 385 | snd_emu10k1_ptr_write(emu, MAPB, voice, silent_page); |
386 | /* modulation envelope */ | 386 | /* modulation envelope */ |
diff --git a/sound/pci/emu10k1/memory.c b/sound/pci/emu10k1/memory.c index c68e6dd2fa67..4f1f69be1865 100644 --- a/sound/pci/emu10k1/memory.c +++ b/sound/pci/emu10k1/memory.c | |||
@@ -34,10 +34,11 @@ | |||
34 | * aligned pages in others | 34 | * aligned pages in others |
35 | */ | 35 | */ |
36 | #define __set_ptb_entry(emu,page,addr) \ | 36 | #define __set_ptb_entry(emu,page,addr) \ |
37 | (((u32 *)(emu)->ptb_pages.area)[page] = cpu_to_le32(((addr) << 1) | (page))) | 37 | (((u32 *)(emu)->ptb_pages.area)[page] = cpu_to_le32(((addr) << (emu->address_mode)) | (page))) |
38 | 38 | ||
39 | #define UNIT_PAGES (PAGE_SIZE / EMUPAGESIZE) | 39 | #define UNIT_PAGES (PAGE_SIZE / EMUPAGESIZE) |
40 | #define MAX_ALIGN_PAGES (MAXPAGES / UNIT_PAGES) | 40 | #define MAX_ALIGN_PAGES0 (MAXPAGES0 / UNIT_PAGES) |
41 | #define MAX_ALIGN_PAGES1 (MAXPAGES1 / UNIT_PAGES) | ||
41 | /* get aligned page from offset address */ | 42 | /* get aligned page from offset address */ |
42 | #define get_aligned_page(offset) ((offset) >> PAGE_SHIFT) | 43 | #define get_aligned_page(offset) ((offset) >> PAGE_SHIFT) |
43 | /* get offset address from aligned page */ | 44 | /* get offset address from aligned page */ |
@@ -124,7 +125,7 @@ static int search_empty_map_area(struct snd_emu10k1 *emu, int npages, struct lis | |||
124 | } | 125 | } |
125 | page = blk->mapped_page + blk->pages; | 126 | page = blk->mapped_page + blk->pages; |
126 | } | 127 | } |
127 | size = MAX_ALIGN_PAGES - page; | 128 | size = (emu->address_mode ? MAX_ALIGN_PAGES1 : MAX_ALIGN_PAGES0) - page; |
128 | if (size >= max_size) { | 129 | if (size >= max_size) { |
129 | *nextp = pos; | 130 | *nextp = pos; |
130 | return page; | 131 | return page; |
@@ -181,7 +182,7 @@ static int unmap_memblk(struct snd_emu10k1 *emu, struct snd_emu10k1_memblk *blk) | |||
181 | q = get_emu10k1_memblk(p, mapped_link); | 182 | q = get_emu10k1_memblk(p, mapped_link); |
182 | end_page = q->mapped_page; | 183 | end_page = q->mapped_page; |
183 | } else | 184 | } else |
184 | end_page = MAX_ALIGN_PAGES; | 185 | end_page = (emu->address_mode ? MAX_ALIGN_PAGES1 : MAX_ALIGN_PAGES0); |
185 | 186 | ||
186 | /* remove links */ | 187 | /* remove links */ |
187 | list_del(&blk->mapped_link); | 188 | list_del(&blk->mapped_link); |
@@ -307,7 +308,7 @@ snd_emu10k1_alloc_pages(struct snd_emu10k1 *emu, struct snd_pcm_substream *subst | |||
307 | if (snd_BUG_ON(!emu)) | 308 | if (snd_BUG_ON(!emu)) |
308 | return NULL; | 309 | return NULL; |
309 | if (snd_BUG_ON(runtime->dma_bytes <= 0 || | 310 | if (snd_BUG_ON(runtime->dma_bytes <= 0 || |
310 | runtime->dma_bytes >= MAXPAGES * EMUPAGESIZE)) | 311 | runtime->dma_bytes >= (emu->address_mode ? MAXPAGES1 : MAXPAGES0) * EMUPAGESIZE)) |
311 | return NULL; | 312 | return NULL; |
312 | hdr = emu->memhdr; | 313 | hdr = emu->memhdr; |
313 | if (snd_BUG_ON(!hdr)) | 314 | if (snd_BUG_ON(!hdr)) |
diff --git a/sound/pci/hda/hda_codec.c b/sound/pci/hda/hda_codec.c index 873ed1bce12b..5645481af3d9 100644 --- a/sound/pci/hda/hda_codec.c +++ b/sound/pci/hda/hda_codec.c | |||
@@ -436,7 +436,7 @@ static unsigned int get_num_devices(struct hda_codec *codec, hda_nid_t nid) | |||
436 | get_wcaps_type(wcaps) != AC_WID_PIN) | 436 | get_wcaps_type(wcaps) != AC_WID_PIN) |
437 | return 0; | 437 | return 0; |
438 | 438 | ||
439 | parm = snd_hda_param_read(codec, nid, AC_PAR_DEVLIST_LEN); | 439 | parm = snd_hdac_read_parm_uncached(&codec->core, nid, AC_PAR_DEVLIST_LEN); |
440 | if (parm == -1 && codec->bus->rirb_error) | 440 | if (parm == -1 && codec->bus->rirb_error) |
441 | parm = 0; | 441 | parm = 0; |
442 | return parm & AC_DEV_LIST_LEN_MASK; | 442 | return parm & AC_DEV_LIST_LEN_MASK; |
@@ -873,14 +873,15 @@ struct hda_pcm *snd_hda_codec_pcm_new(struct hda_codec *codec, | |||
873 | struct hda_pcm *pcm; | 873 | struct hda_pcm *pcm; |
874 | va_list args; | 874 | va_list args; |
875 | 875 | ||
876 | va_start(args, fmt); | ||
877 | pcm = kzalloc(sizeof(*pcm), GFP_KERNEL); | 876 | pcm = kzalloc(sizeof(*pcm), GFP_KERNEL); |
878 | if (!pcm) | 877 | if (!pcm) |
879 | return NULL; | 878 | return NULL; |
880 | 879 | ||
881 | pcm->codec = codec; | 880 | pcm->codec = codec; |
882 | kref_init(&pcm->kref); | 881 | kref_init(&pcm->kref); |
882 | va_start(args, fmt); | ||
883 | pcm->name = kvasprintf(GFP_KERNEL, fmt, args); | 883 | pcm->name = kvasprintf(GFP_KERNEL, fmt, args); |
884 | va_end(args); | ||
884 | if (!pcm->name) { | 885 | if (!pcm->name) { |
885 | kfree(pcm); | 886 | kfree(pcm); |
886 | return NULL; | 887 | return NULL; |
@@ -1375,6 +1376,31 @@ int snd_hda_override_amp_caps(struct hda_codec *codec, hda_nid_t nid, int dir, | |||
1375 | EXPORT_SYMBOL_GPL(snd_hda_override_amp_caps); | 1376 | EXPORT_SYMBOL_GPL(snd_hda_override_amp_caps); |
1376 | 1377 | ||
1377 | /** | 1378 | /** |
1379 | * snd_hda_codec_amp_update - update the AMP mono value | ||
1380 | * @codec: HD-audio codec | ||
1381 | * @nid: NID to read the AMP value | ||
1382 | * @ch: channel to update (0 or 1) | ||
1383 | * @dir: #HDA_INPUT or #HDA_OUTPUT | ||
1384 | * @idx: the index value (only for input direction) | ||
1385 | * @mask: bit mask to set | ||
1386 | * @val: the bits value to set | ||
1387 | * | ||
1388 | * Update the AMP values for the given channel, direction and index. | ||
1389 | */ | ||
1390 | int snd_hda_codec_amp_update(struct hda_codec *codec, hda_nid_t nid, | ||
1391 | int ch, int dir, int idx, int mask, int val) | ||
1392 | { | ||
1393 | unsigned int cmd = snd_hdac_regmap_encode_amp(nid, ch, dir, idx); | ||
1394 | |||
1395 | /* enable fake mute if no h/w mute but min=mute */ | ||
1396 | if ((query_amp_caps(codec, nid, dir) & | ||
1397 | (AC_AMPCAP_MUTE | AC_AMPCAP_MIN_MUTE)) == AC_AMPCAP_MIN_MUTE) | ||
1398 | cmd |= AC_AMP_FAKE_MUTE; | ||
1399 | return snd_hdac_regmap_update_raw(&codec->core, cmd, mask, val); | ||
1400 | } | ||
1401 | EXPORT_SYMBOL_GPL(snd_hda_codec_amp_update); | ||
1402 | |||
1403 | /** | ||
1378 | * snd_hda_codec_amp_stereo - update the AMP stereo values | 1404 | * snd_hda_codec_amp_stereo - update the AMP stereo values |
1379 | * @codec: HD-audio codec | 1405 | * @codec: HD-audio codec |
1380 | * @nid: NID to read the AMP value | 1406 | * @nid: NID to read the AMP value |
@@ -2082,6 +2108,16 @@ static struct snd_kcontrol_new vmaster_mute_mode = { | |||
2082 | .put = vmaster_mute_mode_put, | 2108 | .put = vmaster_mute_mode_put, |
2083 | }; | 2109 | }; |
2084 | 2110 | ||
2111 | /* meta hook to call each driver's vmaster hook */ | ||
2112 | static void vmaster_hook(void *private_data, int enabled) | ||
2113 | { | ||
2114 | struct hda_vmaster_mute_hook *hook = private_data; | ||
2115 | |||
2116 | if (hook->mute_mode != HDA_VMUTE_FOLLOW_MASTER) | ||
2117 | enabled = hook->mute_mode; | ||
2118 | hook->hook(hook->codec, enabled); | ||
2119 | } | ||
2120 | |||
2085 | /** | 2121 | /** |
2086 | * snd_hda_add_vmaster_hook - Add a vmaster hook for mute-LED | 2122 | * snd_hda_add_vmaster_hook - Add a vmaster hook for mute-LED |
2087 | * @codec: the HDA codec | 2123 | * @codec: the HDA codec |
@@ -2100,9 +2136,9 @@ int snd_hda_add_vmaster_hook(struct hda_codec *codec, | |||
2100 | 2136 | ||
2101 | if (!hook->hook || !hook->sw_kctl) | 2137 | if (!hook->hook || !hook->sw_kctl) |
2102 | return 0; | 2138 | return 0; |
2103 | snd_ctl_add_vmaster_hook(hook->sw_kctl, hook->hook, codec); | ||
2104 | hook->codec = codec; | 2139 | hook->codec = codec; |
2105 | hook->mute_mode = HDA_VMUTE_FOLLOW_MASTER; | 2140 | hook->mute_mode = HDA_VMUTE_FOLLOW_MASTER; |
2141 | snd_ctl_add_vmaster_hook(hook->sw_kctl, vmaster_hook, hook); | ||
2106 | if (!expose_enum_ctl) | 2142 | if (!expose_enum_ctl) |
2107 | return 0; | 2143 | return 0; |
2108 | kctl = snd_ctl_new1(&vmaster_mute_mode, hook); | 2144 | kctl = snd_ctl_new1(&vmaster_mute_mode, hook); |
@@ -2128,14 +2164,7 @@ void snd_hda_sync_vmaster_hook(struct hda_vmaster_mute_hook *hook) | |||
2128 | */ | 2164 | */ |
2129 | if (hook->codec->bus->shutdown) | 2165 | if (hook->codec->bus->shutdown) |
2130 | return; | 2166 | return; |
2131 | switch (hook->mute_mode) { | 2167 | snd_ctl_sync_vmaster_hook(hook->sw_kctl); |
2132 | case HDA_VMUTE_FOLLOW_MASTER: | ||
2133 | snd_ctl_sync_vmaster_hook(hook->sw_kctl); | ||
2134 | break; | ||
2135 | default: | ||
2136 | hook->hook(hook->codec, hook->mute_mode); | ||
2137 | break; | ||
2138 | } | ||
2139 | } | 2168 | } |
2140 | EXPORT_SYMBOL_GPL(snd_hda_sync_vmaster_hook); | 2169 | EXPORT_SYMBOL_GPL(snd_hda_sync_vmaster_hook); |
2141 | 2170 | ||
diff --git a/sound/pci/hda/hda_generic.c b/sound/pci/hda/hda_generic.c index 3d2597b7037b..ac0db1679f09 100644 --- a/sound/pci/hda/hda_generic.c +++ b/sound/pci/hda/hda_generic.c | |||
@@ -844,8 +844,16 @@ static hda_nid_t path_power_update(struct hda_codec *codec, | |||
844 | snd_hda_codec_write(codec, nid, 0, | 844 | snd_hda_codec_write(codec, nid, 0, |
845 | AC_VERB_SET_POWER_STATE, state); | 845 | AC_VERB_SET_POWER_STATE, state); |
846 | changed = nid; | 846 | changed = nid; |
847 | /* all known codecs seem to be capable to handl | ||
848 | * widgets state even in D3, so far. | ||
849 | * if any new codecs need to restore the widget | ||
850 | * states after D0 transition, call the function | ||
851 | * below. | ||
852 | */ | ||
853 | #if 0 /* disabled */ | ||
847 | if (state == AC_PWRST_D0) | 854 | if (state == AC_PWRST_D0) |
848 | snd_hdac_regmap_sync_node(&codec->core, nid); | 855 | snd_hdac_regmap_sync_node(&codec->core, nid); |
856 | #endif | ||
849 | } | 857 | } |
850 | } | 858 | } |
851 | return changed; | 859 | return changed; |
@@ -3259,7 +3267,8 @@ static int create_input_ctls(struct hda_codec *codec) | |||
3259 | val = PIN_IN; | 3267 | val = PIN_IN; |
3260 | if (cfg->inputs[i].type == AUTO_PIN_MIC) | 3268 | if (cfg->inputs[i].type == AUTO_PIN_MIC) |
3261 | val |= snd_hda_get_default_vref(codec, pin); | 3269 | val |= snd_hda_get_default_vref(codec, pin); |
3262 | if (pin != spec->hp_mic_pin) | 3270 | if (pin != spec->hp_mic_pin && |
3271 | !snd_hda_codec_get_pin_target(codec, pin)) | ||
3263 | set_pin_target(codec, pin, val, false); | 3272 | set_pin_target(codec, pin, val, false); |
3264 | 3273 | ||
3265 | if (mixer) { | 3274 | if (mixer) { |
@@ -4917,9 +4926,12 @@ int snd_hda_gen_parse_auto_config(struct hda_codec *codec, | |||
4917 | dig_only: | 4926 | dig_only: |
4918 | parse_digital(codec); | 4927 | parse_digital(codec); |
4919 | 4928 | ||
4920 | if (spec->power_down_unused || codec->power_save_node) | 4929 | if (spec->power_down_unused || codec->power_save_node) { |
4921 | if (!codec->power_filter) | 4930 | if (!codec->power_filter) |
4922 | codec->power_filter = snd_hda_gen_path_power_filter; | 4931 | codec->power_filter = snd_hda_gen_path_power_filter; |
4932 | if (!codec->patch_ops.stream_pm) | ||
4933 | codec->patch_ops.stream_pm = snd_hda_gen_stream_pm; | ||
4934 | } | ||
4923 | 4935 | ||
4924 | if (!spec->no_analog && spec->beep_nid) { | 4936 | if (!spec->no_analog && spec->beep_nid) { |
4925 | err = snd_hda_attach_beep_device(codec, spec->beep_nid); | 4937 | err = snd_hda_attach_beep_device(codec, spec->beep_nid); |
diff --git a/sound/pci/hda/hda_intel.c b/sound/pci/hda/hda_intel.c index 34040d26c94f..a244ba706317 100644 --- a/sound/pci/hda/hda_intel.c +++ b/sound/pci/hda/hda_intel.c | |||
@@ -340,6 +340,11 @@ enum { | |||
340 | #define use_vga_switcheroo(chip) 0 | 340 | #define use_vga_switcheroo(chip) 0 |
341 | #endif | 341 | #endif |
342 | 342 | ||
343 | #define CONTROLLER_IN_GPU(pci) (((pci)->device == 0x0a0c) || \ | ||
344 | ((pci)->device == 0x0c0c) || \ | ||
345 | ((pci)->device == 0x0d0c) || \ | ||
346 | ((pci)->device == 0x160c)) | ||
347 | |||
343 | static char *driver_short_names[] = { | 348 | static char *driver_short_names[] = { |
344 | [AZX_DRIVER_ICH] = "HDA Intel", | 349 | [AZX_DRIVER_ICH] = "HDA Intel", |
345 | [AZX_DRIVER_PCH] = "HDA Intel PCH", | 350 | [AZX_DRIVER_PCH] = "HDA Intel PCH", |
@@ -1854,8 +1859,17 @@ static int azx_probe_continue(struct azx *chip) | |||
1854 | if (chip->driver_caps & AZX_DCAPS_I915_POWERWELL) { | 1859 | if (chip->driver_caps & AZX_DCAPS_I915_POWERWELL) { |
1855 | #ifdef CONFIG_SND_HDA_I915 | 1860 | #ifdef CONFIG_SND_HDA_I915 |
1856 | err = hda_i915_init(hda); | 1861 | err = hda_i915_init(hda); |
1857 | if (err < 0) | 1862 | if (err < 0) { |
1858 | goto out_free; | 1863 | /* if the controller is bound only with HDMI/DP |
1864 | * (for HSW and BDW), we need to abort the probe; | ||
1865 | * for other chips, still continue probing as other | ||
1866 | * codecs can be on the same link. | ||
1867 | */ | ||
1868 | if (CONTROLLER_IN_GPU(pci)) | ||
1869 | goto out_free; | ||
1870 | else | ||
1871 | goto skip_i915; | ||
1872 | } | ||
1859 | err = hda_display_power(hda, true); | 1873 | err = hda_display_power(hda, true); |
1860 | if (err < 0) { | 1874 | if (err < 0) { |
1861 | dev_err(chip->card->dev, | 1875 | dev_err(chip->card->dev, |
@@ -1865,6 +1879,7 @@ static int azx_probe_continue(struct azx *chip) | |||
1865 | #endif | 1879 | #endif |
1866 | } | 1880 | } |
1867 | 1881 | ||
1882 | skip_i915: | ||
1868 | err = azx_first_init(chip); | 1883 | err = azx_first_init(chip); |
1869 | if (err < 0) | 1884 | if (err < 0) |
1870 | goto out_free; | 1885 | goto out_free; |
@@ -2089,6 +2104,8 @@ static const struct pci_device_id azx_ids[] = { | |||
2089 | .driver_data = AZX_DRIVER_ATIHDMI_NS | AZX_DCAPS_PRESET_ATI_HDMI_NS }, | 2104 | .driver_data = AZX_DRIVER_ATIHDMI_NS | AZX_DCAPS_PRESET_ATI_HDMI_NS }, |
2090 | { PCI_DEVICE(0x1002, 0xaab0), | 2105 | { PCI_DEVICE(0x1002, 0xaab0), |
2091 | .driver_data = AZX_DRIVER_ATIHDMI_NS | AZX_DCAPS_PRESET_ATI_HDMI_NS }, | 2106 | .driver_data = AZX_DRIVER_ATIHDMI_NS | AZX_DCAPS_PRESET_ATI_HDMI_NS }, |
2107 | { PCI_DEVICE(0x1002, 0xaac8), | ||
2108 | .driver_data = AZX_DRIVER_ATIHDMI_NS | AZX_DCAPS_PRESET_ATI_HDMI_NS }, | ||
2092 | /* VIA VT8251/VT8237A */ | 2109 | /* VIA VT8251/VT8237A */ |
2093 | { PCI_DEVICE(0x1106, 0x3288), | 2110 | { PCI_DEVICE(0x1106, 0x3288), |
2094 | .driver_data = AZX_DRIVER_VIA | AZX_DCAPS_POSFIX_VIA }, | 2111 | .driver_data = AZX_DRIVER_VIA | AZX_DCAPS_POSFIX_VIA }, |
diff --git a/sound/pci/hda/hda_local.h b/sound/pci/hda/hda_local.h index 3b567f42296b..bed66c314431 100644 --- a/sound/pci/hda/hda_local.h +++ b/sound/pci/hda/hda_local.h | |||
@@ -129,8 +129,8 @@ int snd_hda_mixer_amp_switch_put_beep(struct snd_kcontrol *kcontrol, | |||
129 | /* lowlevel accessor with caching; use carefully */ | 129 | /* lowlevel accessor with caching; use carefully */ |
130 | #define snd_hda_codec_amp_read(codec, nid, ch, dir, idx) \ | 130 | #define snd_hda_codec_amp_read(codec, nid, ch, dir, idx) \ |
131 | snd_hdac_regmap_get_amp(&(codec)->core, nid, ch, dir, idx) | 131 | snd_hdac_regmap_get_amp(&(codec)->core, nid, ch, dir, idx) |
132 | #define snd_hda_codec_amp_update(codec, nid, ch, dir, idx, mask, val) \ | 132 | int snd_hda_codec_amp_update(struct hda_codec *codec, hda_nid_t nid, |
133 | snd_hdac_regmap_update_amp(&(codec)->core, nid, ch, dir, idx, mask, val) | 133 | int ch, int dir, int idx, int mask, int val); |
134 | int snd_hda_codec_amp_stereo(struct hda_codec *codec, hda_nid_t nid, | 134 | int snd_hda_codec_amp_stereo(struct hda_codec *codec, hda_nid_t nid, |
135 | int dir, int idx, int mask, int val); | 135 | int dir, int idx, int mask, int val); |
136 | int snd_hda_codec_amp_init(struct hda_codec *codec, hda_nid_t nid, int ch, | 136 | int snd_hda_codec_amp_init(struct hda_codec *codec, hda_nid_t nid, int ch, |
diff --git a/sound/pci/hda/patch_conexant.c b/sound/pci/hda/patch_conexant.c index f8f0dfbef149..78b719b5b34d 100644 --- a/sound/pci/hda/patch_conexant.c +++ b/sound/pci/hda/patch_conexant.c | |||
@@ -968,6 +968,14 @@ static const struct hda_codec_preset snd_hda_preset_conexant[] = { | |||
968 | .patch = patch_conexant_auto }, | 968 | .patch = patch_conexant_auto }, |
969 | { .id = 0x14f150b9, .name = "CX20665", | 969 | { .id = 0x14f150b9, .name = "CX20665", |
970 | .patch = patch_conexant_auto }, | 970 | .patch = patch_conexant_auto }, |
971 | { .id = 0x14f150f1, .name = "CX20721", | ||
972 | .patch = patch_conexant_auto }, | ||
973 | { .id = 0x14f150f2, .name = "CX20722", | ||
974 | .patch = patch_conexant_auto }, | ||
975 | { .id = 0x14f150f3, .name = "CX20723", | ||
976 | .patch = patch_conexant_auto }, | ||
977 | { .id = 0x14f150f4, .name = "CX20724", | ||
978 | .patch = patch_conexant_auto }, | ||
971 | { .id = 0x14f1510f, .name = "CX20751/2", | 979 | { .id = 0x14f1510f, .name = "CX20751/2", |
972 | .patch = patch_conexant_auto }, | 980 | .patch = patch_conexant_auto }, |
973 | { .id = 0x14f15110, .name = "CX20751/2", | 981 | { .id = 0x14f15110, .name = "CX20751/2", |
@@ -1002,6 +1010,10 @@ MODULE_ALIAS("snd-hda-codec-id:14f150ab"); | |||
1002 | MODULE_ALIAS("snd-hda-codec-id:14f150ac"); | 1010 | MODULE_ALIAS("snd-hda-codec-id:14f150ac"); |
1003 | MODULE_ALIAS("snd-hda-codec-id:14f150b8"); | 1011 | MODULE_ALIAS("snd-hda-codec-id:14f150b8"); |
1004 | MODULE_ALIAS("snd-hda-codec-id:14f150b9"); | 1012 | MODULE_ALIAS("snd-hda-codec-id:14f150b9"); |
1013 | MODULE_ALIAS("snd-hda-codec-id:14f150f1"); | ||
1014 | MODULE_ALIAS("snd-hda-codec-id:14f150f2"); | ||
1015 | MODULE_ALIAS("snd-hda-codec-id:14f150f3"); | ||
1016 | MODULE_ALIAS("snd-hda-codec-id:14f150f4"); | ||
1005 | MODULE_ALIAS("snd-hda-codec-id:14f1510f"); | 1017 | MODULE_ALIAS("snd-hda-codec-id:14f1510f"); |
1006 | MODULE_ALIAS("snd-hda-codec-id:14f15110"); | 1018 | MODULE_ALIAS("snd-hda-codec-id:14f15110"); |
1007 | MODULE_ALIAS("snd-hda-codec-id:14f15111"); | 1019 | MODULE_ALIAS("snd-hda-codec-id:14f15111"); |
diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c index 06199e4e930f..0320cb523d9e 100644 --- a/sound/pci/hda/patch_realtek.c +++ b/sound/pci/hda/patch_realtek.c | |||
@@ -883,6 +883,8 @@ static struct alc_codec_rename_pci_table rename_pci_tbl[] = { | |||
883 | { 0x10ec0668, 0x1028, 0, "ALC3661" }, | 883 | { 0x10ec0668, 0x1028, 0, "ALC3661" }, |
884 | { 0x10ec0275, 0x1028, 0, "ALC3260" }, | 884 | { 0x10ec0275, 0x1028, 0, "ALC3260" }, |
885 | { 0x10ec0899, 0x1028, 0, "ALC3861" }, | 885 | { 0x10ec0899, 0x1028, 0, "ALC3861" }, |
886 | { 0x10ec0298, 0x1028, 0, "ALC3266" }, | ||
887 | { 0x10ec0256, 0x1028, 0, "ALC3246" }, | ||
886 | { 0x10ec0670, 0x1025, 0, "ALC669X" }, | 888 | { 0x10ec0670, 0x1025, 0, "ALC669X" }, |
887 | { 0x10ec0676, 0x1025, 0, "ALC679X" }, | 889 | { 0x10ec0676, 0x1025, 0, "ALC679X" }, |
888 | { 0x10ec0282, 0x1043, 0, "ALC3229" }, | 890 | { 0x10ec0282, 0x1043, 0, "ALC3229" }, |
@@ -2166,6 +2168,7 @@ static const struct hda_fixup alc882_fixups[] = { | |||
2166 | static const struct snd_pci_quirk alc882_fixup_tbl[] = { | 2168 | static const struct snd_pci_quirk alc882_fixup_tbl[] = { |
2167 | SND_PCI_QUIRK(0x1025, 0x006c, "Acer Aspire 9810", ALC883_FIXUP_ACER_EAPD), | 2169 | SND_PCI_QUIRK(0x1025, 0x006c, "Acer Aspire 9810", ALC883_FIXUP_ACER_EAPD), |
2168 | SND_PCI_QUIRK(0x1025, 0x0090, "Acer Aspire", ALC883_FIXUP_ACER_EAPD), | 2170 | SND_PCI_QUIRK(0x1025, 0x0090, "Acer Aspire", ALC883_FIXUP_ACER_EAPD), |
2171 | SND_PCI_QUIRK(0x1025, 0x0107, "Acer Aspire", ALC883_FIXUP_ACER_EAPD), | ||
2169 | SND_PCI_QUIRK(0x1025, 0x010a, "Acer Ferrari 5000", ALC883_FIXUP_ACER_EAPD), | 2172 | SND_PCI_QUIRK(0x1025, 0x010a, "Acer Ferrari 5000", ALC883_FIXUP_ACER_EAPD), |
2170 | SND_PCI_QUIRK(0x1025, 0x0110, "Acer Aspire", ALC883_FIXUP_ACER_EAPD), | 2173 | SND_PCI_QUIRK(0x1025, 0x0110, "Acer Aspire", ALC883_FIXUP_ACER_EAPD), |
2171 | SND_PCI_QUIRK(0x1025, 0x0112, "Acer Aspire 9303", ALC883_FIXUP_ACER_EAPD), | 2174 | SND_PCI_QUIRK(0x1025, 0x0112, "Acer Aspire 9303", ALC883_FIXUP_ACER_EAPD), |
@@ -3673,6 +3676,10 @@ static void alc_headset_mode_mic_in(struct hda_codec *codec, hda_nid_t hp_pin, | |||
3673 | alc_process_coef_fw(codec, coef0293); | 3676 | alc_process_coef_fw(codec, coef0293); |
3674 | snd_hda_set_pin_ctl_cache(codec, mic_pin, PIN_VREF50); | 3677 | snd_hda_set_pin_ctl_cache(codec, mic_pin, PIN_VREF50); |
3675 | break; | 3678 | break; |
3679 | case 0x10ec0662: | ||
3680 | snd_hda_set_pin_ctl_cache(codec, hp_pin, 0); | ||
3681 | snd_hda_set_pin_ctl_cache(codec, mic_pin, PIN_VREF50); | ||
3682 | break; | ||
3676 | case 0x10ec0668: | 3683 | case 0x10ec0668: |
3677 | alc_write_coef_idx(codec, 0x11, 0x0001); | 3684 | alc_write_coef_idx(codec, 0x11, 0x0001); |
3678 | snd_hda_set_pin_ctl_cache(codec, hp_pin, 0); | 3685 | snd_hda_set_pin_ctl_cache(codec, hp_pin, 0); |
@@ -3738,7 +3745,6 @@ static void alc_headset_mode_default(struct hda_codec *codec) | |||
3738 | case 0x10ec0288: | 3745 | case 0x10ec0288: |
3739 | alc_process_coef_fw(codec, coef0288); | 3746 | alc_process_coef_fw(codec, coef0288); |
3740 | break; | 3747 | break; |
3741 | break; | ||
3742 | case 0x10ec0292: | 3748 | case 0x10ec0292: |
3743 | alc_process_coef_fw(codec, coef0292); | 3749 | alc_process_coef_fw(codec, coef0292); |
3744 | break; | 3750 | break; |
@@ -4012,7 +4018,7 @@ static void alc_update_headset_mode(struct hda_codec *codec) | |||
4012 | if (new_headset_mode != ALC_HEADSET_MODE_MIC) { | 4018 | if (new_headset_mode != ALC_HEADSET_MODE_MIC) { |
4013 | snd_hda_set_pin_ctl_cache(codec, hp_pin, | 4019 | snd_hda_set_pin_ctl_cache(codec, hp_pin, |
4014 | AC_PINCTL_OUT_EN | AC_PINCTL_HP_EN); | 4020 | AC_PINCTL_OUT_EN | AC_PINCTL_HP_EN); |
4015 | if (spec->headphone_mic_pin) | 4021 | if (spec->headphone_mic_pin && spec->headphone_mic_pin != hp_pin) |
4016 | snd_hda_set_pin_ctl_cache(codec, spec->headphone_mic_pin, | 4022 | snd_hda_set_pin_ctl_cache(codec, spec->headphone_mic_pin, |
4017 | PIN_VREFHIZ); | 4023 | PIN_VREFHIZ); |
4018 | } | 4024 | } |
@@ -4190,11 +4196,18 @@ static void alc_shutup_dell_xps13(struct hda_codec *codec) | |||
4190 | static void alc_fixup_dell_xps13(struct hda_codec *codec, | 4196 | static void alc_fixup_dell_xps13(struct hda_codec *codec, |
4191 | const struct hda_fixup *fix, int action) | 4197 | const struct hda_fixup *fix, int action) |
4192 | { | 4198 | { |
4193 | if (action == HDA_FIXUP_ACT_PROBE) { | 4199 | struct alc_spec *spec = codec->spec; |
4194 | struct alc_spec *spec = codec->spec; | 4200 | struct hda_input_mux *imux = &spec->gen.input_mux; |
4195 | struct hda_input_mux *imux = &spec->gen.input_mux; | 4201 | int i; |
4196 | int i; | ||
4197 | 4202 | ||
4203 | switch (action) { | ||
4204 | case HDA_FIXUP_ACT_PRE_PROBE: | ||
4205 | /* mic pin 0x19 must be initialized with Vref Hi-Z, otherwise | ||
4206 | * it causes a click noise at start up | ||
4207 | */ | ||
4208 | snd_hda_codec_set_pin_target(codec, 0x19, PIN_VREFHIZ); | ||
4209 | break; | ||
4210 | case HDA_FIXUP_ACT_PROBE: | ||
4198 | spec->shutup = alc_shutup_dell_xps13; | 4211 | spec->shutup = alc_shutup_dell_xps13; |
4199 | 4212 | ||
4200 | /* Make the internal mic the default input source. */ | 4213 | /* Make the internal mic the default input source. */ |
@@ -4204,9 +4217,27 @@ static void alc_fixup_dell_xps13(struct hda_codec *codec, | |||
4204 | break; | 4217 | break; |
4205 | } | 4218 | } |
4206 | } | 4219 | } |
4220 | break; | ||
4207 | } | 4221 | } |
4208 | } | 4222 | } |
4209 | 4223 | ||
4224 | static void alc_fixup_headset_mode_alc662(struct hda_codec *codec, | ||
4225 | const struct hda_fixup *fix, int action) | ||
4226 | { | ||
4227 | struct alc_spec *spec = codec->spec; | ||
4228 | |||
4229 | if (action == HDA_FIXUP_ACT_PRE_PROBE) { | ||
4230 | spec->parse_flags |= HDA_PINCFG_HEADSET_MIC; | ||
4231 | spec->gen.hp_mic = 1; /* Mic-in is same pin as headphone */ | ||
4232 | |||
4233 | /* Disable boost for mic-in permanently. (This code is only called | ||
4234 | from quirks that guarantee that the headphone is at NID 0x1b.) */ | ||
4235 | snd_hda_codec_write(codec, 0x1b, 0, AC_VERB_SET_AMP_GAIN_MUTE, 0x7000); | ||
4236 | snd_hda_override_wcaps(codec, 0x1b, get_wcaps(codec, 0x1b) & ~AC_WCAP_IN_AMP); | ||
4237 | } else | ||
4238 | alc_fixup_headset_mode(codec, fix, action); | ||
4239 | } | ||
4240 | |||
4210 | static void alc_fixup_headset_mode_alc668(struct hda_codec *codec, | 4241 | static void alc_fixup_headset_mode_alc668(struct hda_codec *codec, |
4211 | const struct hda_fixup *fix, int action) | 4242 | const struct hda_fixup *fix, int action) |
4212 | { | 4243 | { |
@@ -5111,6 +5142,7 @@ static const struct snd_pci_quirk alc269_fixup_tbl[] = { | |||
5111 | SND_PCI_QUIRK(0x104d, 0x9099, "Sony VAIO S13", ALC275_FIXUP_SONY_DISABLE_AAMIX), | 5142 | SND_PCI_QUIRK(0x104d, 0x9099, "Sony VAIO S13", ALC275_FIXUP_SONY_DISABLE_AAMIX), |
5112 | SND_PCI_QUIRK(0x10cf, 0x1475, "Lifebook", ALC269_FIXUP_LIFEBOOK), | 5143 | SND_PCI_QUIRK(0x10cf, 0x1475, "Lifebook", ALC269_FIXUP_LIFEBOOK), |
5113 | SND_PCI_QUIRK(0x10cf, 0x15dc, "Lifebook T731", ALC269_FIXUP_LIFEBOOK_HP_PIN), | 5144 | SND_PCI_QUIRK(0x10cf, 0x15dc, "Lifebook T731", ALC269_FIXUP_LIFEBOOK_HP_PIN), |
5145 | SND_PCI_QUIRK(0x10cf, 0x1757, "Lifebook E752", ALC269_FIXUP_LIFEBOOK_HP_PIN), | ||
5114 | SND_PCI_QUIRK(0x10cf, 0x1845, "Lifebook U904", ALC269_FIXUP_LIFEBOOK_EXTMIC), | 5146 | SND_PCI_QUIRK(0x10cf, 0x1845, "Lifebook U904", ALC269_FIXUP_LIFEBOOK_EXTMIC), |
5115 | SND_PCI_QUIRK(0x144d, 0xc109, "Samsung Ativ book 9 (NP900X3G)", ALC269_FIXUP_INV_DMIC), | 5147 | SND_PCI_QUIRK(0x144d, 0xc109, "Samsung Ativ book 9 (NP900X3G)", ALC269_FIXUP_INV_DMIC), |
5116 | SND_PCI_QUIRK(0x1458, 0xfa53, "Gigabyte BXBT-2807", ALC283_FIXUP_BXBT2807_MIC), | 5148 | SND_PCI_QUIRK(0x1458, 0xfa53, "Gigabyte BXBT-2807", ALC283_FIXUP_BXBT2807_MIC), |
@@ -5140,6 +5172,7 @@ static const struct snd_pci_quirk alc269_fixup_tbl[] = { | |||
5140 | SND_PCI_QUIRK(0x17aa, 0x5026, "Thinkpad", ALC269_FIXUP_LIMIT_INT_MIC_BOOST), | 5172 | SND_PCI_QUIRK(0x17aa, 0x5026, "Thinkpad", ALC269_FIXUP_LIMIT_INT_MIC_BOOST), |
5141 | SND_PCI_QUIRK(0x17aa, 0x5034, "Thinkpad T450", ALC292_FIXUP_TPT440_DOCK), | 5173 | SND_PCI_QUIRK(0x17aa, 0x5034, "Thinkpad T450", ALC292_FIXUP_TPT440_DOCK), |
5142 | SND_PCI_QUIRK(0x17aa, 0x5036, "Thinkpad T450s", ALC292_FIXUP_TPT440_DOCK), | 5174 | SND_PCI_QUIRK(0x17aa, 0x5036, "Thinkpad T450s", ALC292_FIXUP_TPT440_DOCK), |
5175 | SND_PCI_QUIRK(0x17aa, 0x503c, "Thinkpad L450", ALC292_FIXUP_TPT440_DOCK), | ||
5143 | SND_PCI_QUIRK(0x17aa, 0x5109, "Thinkpad", ALC269_FIXUP_LIMIT_INT_MIC_BOOST), | 5176 | SND_PCI_QUIRK(0x17aa, 0x5109, "Thinkpad", ALC269_FIXUP_LIMIT_INT_MIC_BOOST), |
5144 | SND_PCI_QUIRK(0x17aa, 0x3bf8, "Quanta FL1", ALC269_FIXUP_PCM_44K), | 5177 | SND_PCI_QUIRK(0x17aa, 0x3bf8, "Quanta FL1", ALC269_FIXUP_PCM_44K), |
5145 | SND_PCI_QUIRK(0x17aa, 0x9e54, "LENOVO NB", ALC269_FIXUP_LENOVO_EAPD), | 5178 | SND_PCI_QUIRK(0x17aa, 0x9e54, "LENOVO NB", ALC269_FIXUP_LENOVO_EAPD), |
@@ -5337,6 +5370,20 @@ static const struct snd_hda_pin_quirk alc269_pin_fixup_tbl[] = { | |||
5337 | {0x17, 0x40000000}, | 5370 | {0x17, 0x40000000}, |
5338 | {0x1d, 0x40700001}, | 5371 | {0x1d, 0x40700001}, |
5339 | {0x21, 0x02211050}), | 5372 | {0x21, 0x02211050}), |
5373 | SND_HDA_PIN_QUIRK(0x10ec0255, 0x1028, "Dell Inspiron 5548", ALC255_FIXUP_DELL1_MIC_NO_PRESENCE, | ||
5374 | ALC255_STANDARD_PINS, | ||
5375 | {0x12, 0x90a60180}, | ||
5376 | {0x14, 0x90170130}, | ||
5377 | {0x17, 0x40000000}, | ||
5378 | {0x1d, 0x40700001}, | ||
5379 | {0x21, 0x02211040}), | ||
5380 | SND_HDA_PIN_QUIRK(0x10ec0256, 0x1028, "Dell", ALC255_FIXUP_DELL1_MIC_NO_PRESENCE, | ||
5381 | ALC255_STANDARD_PINS, | ||
5382 | {0x12, 0x90a60160}, | ||
5383 | {0x14, 0x90170120}, | ||
5384 | {0x17, 0x40000000}, | ||
5385 | {0x1d, 0x40700001}, | ||
5386 | {0x21, 0x02211030}), | ||
5340 | SND_HDA_PIN_QUIRK(0x10ec0256, 0x1028, "Dell", ALC255_FIXUP_DELL1_MIC_NO_PRESENCE, | 5387 | SND_HDA_PIN_QUIRK(0x10ec0256, 0x1028, "Dell", ALC255_FIXUP_DELL1_MIC_NO_PRESENCE, |
5341 | ALC256_STANDARD_PINS, | 5388 | ALC256_STANDARD_PINS, |
5342 | {0x13, 0x40000000}), | 5389 | {0x13, 0x40000000}), |
@@ -5590,7 +5637,8 @@ static int patch_alc269(struct hda_codec *codec) | |||
5590 | 5637 | ||
5591 | spec = codec->spec; | 5638 | spec = codec->spec; |
5592 | spec->gen.shared_mic_vref_pin = 0x18; | 5639 | spec->gen.shared_mic_vref_pin = 0x18; |
5593 | codec->power_save_node = 1; | 5640 | if (codec->core.vendor_id != 0x10ec0292) |
5641 | codec->power_save_node = 1; | ||
5594 | 5642 | ||
5595 | snd_hda_pick_fixup(codec, alc269_fixup_models, | 5643 | snd_hda_pick_fixup(codec, alc269_fixup_models, |
5596 | alc269_fixup_tbl, alc269_fixups); | 5644 | alc269_fixup_tbl, alc269_fixups); |
@@ -6071,7 +6119,9 @@ enum { | |||
6071 | ALC662_FIXUP_NO_JACK_DETECT, | 6119 | ALC662_FIXUP_NO_JACK_DETECT, |
6072 | ALC662_FIXUP_ZOTAC_Z68, | 6120 | ALC662_FIXUP_ZOTAC_Z68, |
6073 | ALC662_FIXUP_INV_DMIC, | 6121 | ALC662_FIXUP_INV_DMIC, |
6122 | ALC662_FIXUP_DELL_MIC_NO_PRESENCE, | ||
6074 | ALC668_FIXUP_DELL_MIC_NO_PRESENCE, | 6123 | ALC668_FIXUP_DELL_MIC_NO_PRESENCE, |
6124 | ALC662_FIXUP_HEADSET_MODE, | ||
6075 | ALC668_FIXUP_HEADSET_MODE, | 6125 | ALC668_FIXUP_HEADSET_MODE, |
6076 | ALC662_FIXUP_BASS_MODE4_CHMAP, | 6126 | ALC662_FIXUP_BASS_MODE4_CHMAP, |
6077 | ALC662_FIXUP_BASS_16, | 6127 | ALC662_FIXUP_BASS_16, |
@@ -6264,6 +6314,20 @@ static const struct hda_fixup alc662_fixups[] = { | |||
6264 | .chained = true, | 6314 | .chained = true, |
6265 | .chain_id = ALC668_FIXUP_DELL_MIC_NO_PRESENCE | 6315 | .chain_id = ALC668_FIXUP_DELL_MIC_NO_PRESENCE |
6266 | }, | 6316 | }, |
6317 | [ALC662_FIXUP_DELL_MIC_NO_PRESENCE] = { | ||
6318 | .type = HDA_FIXUP_PINS, | ||
6319 | .v.pins = (const struct hda_pintbl[]) { | ||
6320 | { 0x19, 0x03a1113c }, /* use as headset mic, without its own jack detect */ | ||
6321 | /* headphone mic by setting pin control of 0x1b (headphone out) to in + vref_50 */ | ||
6322 | { } | ||
6323 | }, | ||
6324 | .chained = true, | ||
6325 | .chain_id = ALC662_FIXUP_HEADSET_MODE | ||
6326 | }, | ||
6327 | [ALC662_FIXUP_HEADSET_MODE] = { | ||
6328 | .type = HDA_FIXUP_FUNC, | ||
6329 | .v.func = alc_fixup_headset_mode_alc662, | ||
6330 | }, | ||
6267 | [ALC668_FIXUP_DELL_MIC_NO_PRESENCE] = { | 6331 | [ALC668_FIXUP_DELL_MIC_NO_PRESENCE] = { |
6268 | .type = HDA_FIXUP_PINS, | 6332 | .type = HDA_FIXUP_PINS, |
6269 | .v.pins = (const struct hda_pintbl[]) { | 6333 | .v.pins = (const struct hda_pintbl[]) { |
@@ -6415,6 +6479,18 @@ static const struct hda_model_fixup alc662_fixup_models[] = { | |||
6415 | }; | 6479 | }; |
6416 | 6480 | ||
6417 | static const struct snd_hda_pin_quirk alc662_pin_fixup_tbl[] = { | 6481 | static const struct snd_hda_pin_quirk alc662_pin_fixup_tbl[] = { |
6482 | SND_HDA_PIN_QUIRK(0x10ec0662, 0x1028, "Dell", ALC662_FIXUP_DELL_MIC_NO_PRESENCE, | ||
6483 | {0x12, 0x4004c000}, | ||
6484 | {0x14, 0x01014010}, | ||
6485 | {0x15, 0x411111f0}, | ||
6486 | {0x16, 0x411111f0}, | ||
6487 | {0x18, 0x01a19020}, | ||
6488 | {0x19, 0x411111f0}, | ||
6489 | {0x1a, 0x0181302f}, | ||
6490 | {0x1b, 0x0221401f}, | ||
6491 | {0x1c, 0x411111f0}, | ||
6492 | {0x1d, 0x4054c601}, | ||
6493 | {0x1e, 0x411111f0}), | ||
6418 | SND_HDA_PIN_QUIRK(0x10ec0668, 0x1028, "Dell", ALC668_FIXUP_AUTO_MUTE, | 6494 | SND_HDA_PIN_QUIRK(0x10ec0668, 0x1028, "Dell", ALC668_FIXUP_AUTO_MUTE, |
6419 | {0x12, 0x99a30130}, | 6495 | {0x12, 0x99a30130}, |
6420 | {0x14, 0x90170110}, | 6496 | {0x14, 0x90170110}, |
diff --git a/sound/pci/hda/patch_sigmatel.c b/sound/pci/hda/patch_sigmatel.c index 43c99ce4a520..6833c74ed6ff 100644 --- a/sound/pci/hda/patch_sigmatel.c +++ b/sound/pci/hda/patch_sigmatel.c | |||
@@ -4403,7 +4403,6 @@ static const struct hda_codec_ops stac_patch_ops = { | |||
4403 | #ifdef CONFIG_PM | 4403 | #ifdef CONFIG_PM |
4404 | .suspend = stac_suspend, | 4404 | .suspend = stac_suspend, |
4405 | #endif | 4405 | #endif |
4406 | .stream_pm = snd_hda_gen_stream_pm, | ||
4407 | .reboot_notify = stac_shutup, | 4406 | .reboot_notify = stac_shutup, |
4408 | }; | 4407 | }; |
4409 | 4408 | ||
@@ -4697,7 +4696,8 @@ static int patch_stac92hd71bxx(struct hda_codec *codec) | |||
4697 | return err; | 4696 | return err; |
4698 | 4697 | ||
4699 | spec = codec->spec; | 4698 | spec = codec->spec; |
4700 | codec->power_save_node = 1; | 4699 | /* disabled power_save_node since it causes noises on a Dell machine */ |
4700 | /* codec->power_save_node = 1; */ | ||
4701 | spec->linear_tone_beep = 0; | 4701 | spec->linear_tone_beep = 0; |
4702 | spec->gen.own_eapd_ctl = 1; | 4702 | spec->gen.own_eapd_ctl = 1; |
4703 | spec->gen.power_down_unused = 1; | 4703 | spec->gen.power_down_unused = 1; |
diff --git a/sound/pci/hda/patch_via.c b/sound/pci/hda/patch_via.c index 31a95cca015d..bab6c04932aa 100644 --- a/sound/pci/hda/patch_via.c +++ b/sound/pci/hda/patch_via.c | |||
@@ -449,6 +449,15 @@ static int via_suspend(struct hda_codec *codec) | |||
449 | 449 | ||
450 | return 0; | 450 | return 0; |
451 | } | 451 | } |
452 | |||
453 | static int via_resume(struct hda_codec *codec) | ||
454 | { | ||
455 | /* some delay here to make jack detection working (bko#98921) */ | ||
456 | msleep(10); | ||
457 | codec->patch_ops.init(codec); | ||
458 | regcache_sync(codec->core.regmap); | ||
459 | return 0; | ||
460 | } | ||
452 | #endif | 461 | #endif |
453 | 462 | ||
454 | #ifdef CONFIG_PM | 463 | #ifdef CONFIG_PM |
@@ -475,6 +484,7 @@ static const struct hda_codec_ops via_patch_ops = { | |||
475 | .stream_pm = snd_hda_gen_stream_pm, | 484 | .stream_pm = snd_hda_gen_stream_pm, |
476 | #ifdef CONFIG_PM | 485 | #ifdef CONFIG_PM |
477 | .suspend = via_suspend, | 486 | .suspend = via_suspend, |
487 | .resume = via_resume, | ||
478 | .check_power_status = via_check_power_status, | 488 | .check_power_status = via_check_power_status, |
479 | #endif | 489 | #endif |
480 | }; | 490 | }; |
diff --git a/sound/soc/Kconfig b/sound/soc/Kconfig index 3ba52da18bc6..2ae9619443d1 100644 --- a/sound/soc/Kconfig +++ b/sound/soc/Kconfig | |||
@@ -45,6 +45,7 @@ source "sound/soc/nuc900/Kconfig" | |||
45 | source "sound/soc/omap/Kconfig" | 45 | source "sound/soc/omap/Kconfig" |
46 | source "sound/soc/kirkwood/Kconfig" | 46 | source "sound/soc/kirkwood/Kconfig" |
47 | source "sound/soc/intel/Kconfig" | 47 | source "sound/soc/intel/Kconfig" |
48 | source "sound/soc/mediatek/Kconfig" | ||
48 | source "sound/soc/mxs/Kconfig" | 49 | source "sound/soc/mxs/Kconfig" |
49 | source "sound/soc/pxa/Kconfig" | 50 | source "sound/soc/pxa/Kconfig" |
50 | source "sound/soc/qcom/Kconfig" | 51 | source "sound/soc/qcom/Kconfig" |
@@ -57,6 +58,7 @@ source "sound/soc/tegra/Kconfig" | |||
57 | source "sound/soc/txx9/Kconfig" | 58 | source "sound/soc/txx9/Kconfig" |
58 | source "sound/soc/ux500/Kconfig" | 59 | source "sound/soc/ux500/Kconfig" |
59 | source "sound/soc/xtensa/Kconfig" | 60 | source "sound/soc/xtensa/Kconfig" |
61 | source "sound/soc/zte/Kconfig" | ||
60 | 62 | ||
61 | # Supported codecs | 63 | # Supported codecs |
62 | source "sound/soc/codecs/Kconfig" | 64 | source "sound/soc/codecs/Kconfig" |
diff --git a/sound/soc/Makefile b/sound/soc/Makefile index 974ba708b482..e189903fabf4 100644 --- a/sound/soc/Makefile +++ b/sound/soc/Makefile | |||
@@ -1,5 +1,6 @@ | |||
1 | snd-soc-core-objs := soc-core.o soc-dapm.o soc-jack.o soc-cache.o soc-utils.o | 1 | snd-soc-core-objs := soc-core.o soc-dapm.o soc-jack.o soc-cache.o soc-utils.o |
2 | snd-soc-core-objs += soc-pcm.o soc-compress.o soc-io.o soc-devres.o soc-ops.o | 2 | snd-soc-core-objs += soc-pcm.o soc-compress.o soc-io.o soc-devres.o soc-ops.o |
3 | snd-soc-core-objs += soc-topology.o | ||
3 | 4 | ||
4 | ifneq ($(CONFIG_SND_SOC_GENERIC_DMAENGINE_PCM),) | 5 | ifneq ($(CONFIG_SND_SOC_GENERIC_DMAENGINE_PCM),) |
5 | snd-soc-core-objs += soc-generic-dmaengine-pcm.o | 6 | snd-soc-core-objs += soc-generic-dmaengine-pcm.o |
@@ -23,6 +24,7 @@ obj-$(CONFIG_SND_SOC) += dwc/ | |||
23 | obj-$(CONFIG_SND_SOC) += fsl/ | 24 | obj-$(CONFIG_SND_SOC) += fsl/ |
24 | obj-$(CONFIG_SND_SOC) += jz4740/ | 25 | obj-$(CONFIG_SND_SOC) += jz4740/ |
25 | obj-$(CONFIG_SND_SOC) += intel/ | 26 | obj-$(CONFIG_SND_SOC) += intel/ |
27 | obj-$(CONFIG_SND_SOC) += mediatek/ | ||
26 | obj-$(CONFIG_SND_SOC) += mxs/ | 28 | obj-$(CONFIG_SND_SOC) += mxs/ |
27 | obj-$(CONFIG_SND_SOC) += nuc900/ | 29 | obj-$(CONFIG_SND_SOC) += nuc900/ |
28 | obj-$(CONFIG_SND_SOC) += omap/ | 30 | obj-$(CONFIG_SND_SOC) += omap/ |
@@ -38,3 +40,4 @@ obj-$(CONFIG_SND_SOC) += tegra/ | |||
38 | obj-$(CONFIG_SND_SOC) += txx9/ | 40 | obj-$(CONFIG_SND_SOC) += txx9/ |
39 | obj-$(CONFIG_SND_SOC) += ux500/ | 41 | obj-$(CONFIG_SND_SOC) += ux500/ |
40 | obj-$(CONFIG_SND_SOC) += xtensa/ | 42 | obj-$(CONFIG_SND_SOC) += xtensa/ |
43 | obj-$(CONFIG_SND_SOC) += zte/ | ||
diff --git a/sound/soc/atmel/Kconfig b/sound/soc/atmel/Kconfig index e7d08806f3e9..1489cd461aec 100644 --- a/sound/soc/atmel/Kconfig +++ b/sound/soc/atmel/Kconfig | |||
@@ -6,29 +6,35 @@ config SND_ATMEL_SOC | |||
6 | the ATMEL SSC interface. You will also need | 6 | the ATMEL SSC interface. You will also need |
7 | to select the audio interfaces to support below. | 7 | to select the audio interfaces to support below. |
8 | 8 | ||
9 | if SND_ATMEL_SOC | ||
10 | |||
9 | config SND_ATMEL_SOC_PDC | 11 | config SND_ATMEL_SOC_PDC |
10 | tristate | 12 | tristate |
11 | depends on SND_ATMEL_SOC | 13 | default m if SND_ATMEL_SOC_SSC_PDC=m && SND_ATMEL_SOC_SSC=m |
14 | default y if SND_ATMEL_SOC_SSC_PDC=y || (SND_ATMEL_SOC_SSC_PDC=m && SND_ATMEL_SOC_SSC=y) | ||
15 | |||
16 | config SND_ATMEL_SOC_SSC_PDC | ||
17 | tristate | ||
12 | 18 | ||
13 | config SND_ATMEL_SOC_DMA | 19 | config SND_ATMEL_SOC_DMA |
14 | tristate | 20 | tristate |
15 | depends on SND_ATMEL_SOC | ||
16 | select SND_SOC_GENERIC_DMAENGINE_PCM | 21 | select SND_SOC_GENERIC_DMAENGINE_PCM |
22 | default m if SND_ATMEL_SOC_SSC_DMA=m && SND_ATMEL_SOC_SSC=m | ||
23 | default y if SND_ATMEL_SOC_SSC_DMA=y || (SND_ATMEL_SOC_SSC_DMA=m && SND_ATMEL_SOC_SSC=y) | ||
24 | |||
25 | config SND_ATMEL_SOC_SSC_DMA | ||
26 | tristate | ||
17 | 27 | ||
18 | config SND_ATMEL_SOC_SSC | 28 | config SND_ATMEL_SOC_SSC |
19 | tristate | 29 | tristate |
20 | depends on SND_ATMEL_SOC | 30 | default y if SND_ATMEL_SOC_SSC_DMA=y || SND_ATMEL_SOC_SSC_PDC=y |
21 | help | 31 | default m if SND_ATMEL_SOC_SSC_DMA=m || SND_ATMEL_SOC_SSC_PDC=m |
22 | Say Y or M if you want to add support for codecs the | ||
23 | ATMEL SSC interface. You will also needs to select the individual | ||
24 | machine drivers to support below. | ||
25 | 32 | ||
26 | config SND_AT91_SOC_SAM9G20_WM8731 | 33 | config SND_AT91_SOC_SAM9G20_WM8731 |
27 | tristate "SoC Audio support for WM8731-based At91sam9g20 evaluation board" | 34 | tristate "SoC Audio support for WM8731-based At91sam9g20 evaluation board" |
28 | depends on ARCH_AT91 || COMPILE_TEST | 35 | depends on ARCH_AT91 || COMPILE_TEST |
29 | depends on ATMEL_SSC && SND_ATMEL_SOC && SND_SOC_I2C_AND_SPI | 36 | depends on ATMEL_SSC && SND_SOC_I2C_AND_SPI |
30 | select SND_ATMEL_SOC_PDC | 37 | select SND_ATMEL_SOC_SSC_PDC |
31 | select SND_ATMEL_SOC_SSC | ||
32 | select SND_SOC_WM8731 | 38 | select SND_SOC_WM8731 |
33 | help | 39 | help |
34 | Say Y if you want to add support for SoC audio on WM8731-based | 40 | Say Y if you want to add support for SoC audio on WM8731-based |
@@ -37,9 +43,8 @@ config SND_AT91_SOC_SAM9G20_WM8731 | |||
37 | config SND_ATMEL_SOC_WM8904 | 43 | config SND_ATMEL_SOC_WM8904 |
38 | tristate "Atmel ASoC driver for boards using WM8904 codec" | 44 | tristate "Atmel ASoC driver for boards using WM8904 codec" |
39 | depends on ARCH_AT91 || COMPILE_TEST | 45 | depends on ARCH_AT91 || COMPILE_TEST |
40 | depends on ATMEL_SSC && SND_ATMEL_SOC && I2C | 46 | depends on ATMEL_SSC && I2C |
41 | select SND_ATMEL_SOC_SSC | 47 | select SND_ATMEL_SOC_SSC_DMA |
42 | select SND_ATMEL_SOC_DMA | ||
43 | select SND_SOC_WM8904 | 48 | select SND_SOC_WM8904 |
44 | help | 49 | help |
45 | Say Y if you want to add support for Atmel ASoC driver for boards using | 50 | Say Y if you want to add support for Atmel ASoC driver for boards using |
@@ -48,10 +53,10 @@ config SND_ATMEL_SOC_WM8904 | |||
48 | config SND_AT91_SOC_SAM9X5_WM8731 | 53 | config SND_AT91_SOC_SAM9X5_WM8731 |
49 | tristate "SoC Audio support for WM8731-based at91sam9x5 board" | 54 | tristate "SoC Audio support for WM8731-based at91sam9x5 board" |
50 | depends on ARCH_AT91 || COMPILE_TEST | 55 | depends on ARCH_AT91 || COMPILE_TEST |
51 | depends on ATMEL_SSC && SND_ATMEL_SOC && SND_SOC_I2C_AND_SPI | 56 | depends on ATMEL_SSC && SND_SOC_I2C_AND_SPI |
52 | select SND_ATMEL_SOC_SSC | 57 | select SND_ATMEL_SOC_SSC_DMA |
53 | select SND_ATMEL_SOC_DMA | ||
54 | select SND_SOC_WM8731 | 58 | select SND_SOC_WM8731 |
55 | help | 59 | help |
56 | Say Y if you want to add support for audio SoC on an | 60 | Say Y if you want to add support for audio SoC on an |
57 | at91sam9x5 based board that is using WM8731 codec. | 61 | at91sam9x5 based board that is using WM8731 codec. |
62 | endif | ||
diff --git a/sound/soc/atmel/atmel-pcm-dma.c b/sound/soc/atmel/atmel-pcm-dma.c index b6625c8c411b..dd57a9eac171 100644 --- a/sound/soc/atmel/atmel-pcm-dma.c +++ b/sound/soc/atmel/atmel-pcm-dma.c | |||
@@ -124,8 +124,7 @@ static const struct snd_dmaengine_pcm_config atmel_dmaengine_pcm_config = { | |||
124 | 124 | ||
125 | int atmel_pcm_dma_platform_register(struct device *dev) | 125 | int atmel_pcm_dma_platform_register(struct device *dev) |
126 | { | 126 | { |
127 | return snd_dmaengine_pcm_register(dev, &atmel_dmaengine_pcm_config, | 127 | return snd_dmaengine_pcm_register(dev, &atmel_dmaengine_pcm_config, 0); |
128 | SND_DMAENGINE_PCM_FLAG_NO_RESIDUE); | ||
129 | } | 128 | } |
130 | EXPORT_SYMBOL(atmel_pcm_dma_platform_register); | 129 | EXPORT_SYMBOL(atmel_pcm_dma_platform_register); |
131 | 130 | ||
diff --git a/sound/soc/atmel/sam9g20_wm8731.c b/sound/soc/atmel/sam9g20_wm8731.c index 8de836165cf2..d7469cdd90dc 100644 --- a/sound/soc/atmel/sam9g20_wm8731.c +++ b/sound/soc/atmel/sam9g20_wm8731.c | |||
@@ -95,8 +95,9 @@ static const struct snd_soc_dapm_widget at91sam9g20ek_dapm_widgets[] = { | |||
95 | 95 | ||
96 | static const struct snd_soc_dapm_route intercon[] = { | 96 | static const struct snd_soc_dapm_route intercon[] = { |
97 | 97 | ||
98 | /* speaker connected to LHPOUT */ | 98 | /* speaker connected to LHPOUT/RHPOUT */ |
99 | {"Ext Spk", NULL, "LHPOUT"}, | 99 | {"Ext Spk", NULL, "LHPOUT"}, |
100 | {"Ext Spk", NULL, "RHPOUT"}, | ||
100 | 101 | ||
101 | /* mic is connected to Mic Jack, with WM8731 Mic Bias */ | 102 | /* mic is connected to Mic Jack, with WM8731 Mic Bias */ |
102 | {"MICIN", NULL, "Mic Bias"}, | 103 | {"MICIN", NULL, "Mic Bias"}, |
@@ -108,9 +109,7 @@ static const struct snd_soc_dapm_route intercon[] = { | |||
108 | */ | 109 | */ |
109 | static int at91sam9g20ek_wm8731_init(struct snd_soc_pcm_runtime *rtd) | 110 | static int at91sam9g20ek_wm8731_init(struct snd_soc_pcm_runtime *rtd) |
110 | { | 111 | { |
111 | struct snd_soc_codec *codec = rtd->codec; | ||
112 | struct snd_soc_dai *codec_dai = rtd->codec_dai; | 112 | struct snd_soc_dai *codec_dai = rtd->codec_dai; |
113 | struct snd_soc_dapm_context *dapm = &codec->dapm; | ||
114 | int ret; | 113 | int ret; |
115 | 114 | ||
116 | printk(KERN_DEBUG | 115 | printk(KERN_DEBUG |
@@ -124,10 +123,6 @@ static int at91sam9g20ek_wm8731_init(struct snd_soc_pcm_runtime *rtd) | |||
124 | return ret; | 123 | return ret; |
125 | } | 124 | } |
126 | 125 | ||
127 | /* not connected */ | ||
128 | snd_soc_dapm_nc_pin(dapm, "RLINEIN"); | ||
129 | snd_soc_dapm_nc_pin(dapm, "LLINEIN"); | ||
130 | |||
131 | #ifndef ENABLE_MIC_INPUT | 126 | #ifndef ENABLE_MIC_INPUT |
132 | snd_soc_dapm_nc_pin(&rtd->card->dapm, "Int Mic"); | 127 | snd_soc_dapm_nc_pin(&rtd->card->dapm, "Int Mic"); |
133 | #endif | 128 | #endif |
@@ -158,6 +153,7 @@ static struct snd_soc_card snd_soc_at91sam9g20ek = { | |||
158 | .num_dapm_widgets = ARRAY_SIZE(at91sam9g20ek_dapm_widgets), | 153 | .num_dapm_widgets = ARRAY_SIZE(at91sam9g20ek_dapm_widgets), |
159 | .dapm_routes = intercon, | 154 | .dapm_routes = intercon, |
160 | .num_dapm_routes = ARRAY_SIZE(intercon), | 155 | .num_dapm_routes = ARRAY_SIZE(intercon), |
156 | .fully_routed = true, | ||
161 | }; | 157 | }; |
162 | 158 | ||
163 | static int at91sam9g20ek_audio_probe(struct platform_device *pdev) | 159 | static int at91sam9g20ek_audio_probe(struct platform_device *pdev) |
diff --git a/sound/soc/au1x/db1200.c b/sound/soc/au1x/db1200.c index c75995f2779c..58c3164802b8 100644 --- a/sound/soc/au1x/db1200.c +++ b/sound/soc/au1x/db1200.c | |||
@@ -21,7 +21,7 @@ | |||
21 | #include "../codecs/wm8731.h" | 21 | #include "../codecs/wm8731.h" |
22 | #include "psc.h" | 22 | #include "psc.h" |
23 | 23 | ||
24 | static struct platform_device_id db1200_pids[] = { | 24 | static const struct platform_device_id db1200_pids[] = { |
25 | { | 25 | { |
26 | .name = "db1200-ac97", | 26 | .name = "db1200-ac97", |
27 | .driver_data = 0, | 27 | .driver_data = 0, |
diff --git a/sound/soc/cirrus/ep93xx-pcm.c b/sound/soc/cirrus/ep93xx-pcm.c index 5f664471d99e..67a73330db5e 100644 --- a/sound/soc/cirrus/ep93xx-pcm.c +++ b/sound/soc/cirrus/ep93xx-pcm.c | |||
@@ -60,7 +60,6 @@ int devm_ep93xx_pcm_platform_register(struct device *dev) | |||
60 | { | 60 | { |
61 | return devm_snd_dmaengine_pcm_register(dev, | 61 | return devm_snd_dmaengine_pcm_register(dev, |
62 | &ep93xx_dmaengine_pcm_config, | 62 | &ep93xx_dmaengine_pcm_config, |
63 | SND_DMAENGINE_PCM_FLAG_NO_RESIDUE | | ||
64 | SND_DMAENGINE_PCM_FLAG_NO_DT | | 63 | SND_DMAENGINE_PCM_FLAG_NO_DT | |
65 | SND_DMAENGINE_PCM_FLAG_COMPAT); | 64 | SND_DMAENGINE_PCM_FLAG_COMPAT); |
66 | } | 65 | } |
diff --git a/sound/soc/codecs/88pm860x-codec.c b/sound/soc/codecs/88pm860x-codec.c index a0f265327fdf..38b3dad9d48a 100644 --- a/sound/soc/codecs/88pm860x-codec.c +++ b/sound/soc/codecs/88pm860x-codec.c | |||
@@ -1140,7 +1140,7 @@ static int pm860x_set_bias_level(struct snd_soc_codec *codec, | |||
1140 | break; | 1140 | break; |
1141 | 1141 | ||
1142 | case SND_SOC_BIAS_STANDBY: | 1142 | case SND_SOC_BIAS_STANDBY: |
1143 | if (codec->dapm.bias_level == SND_SOC_BIAS_OFF) { | 1143 | if (snd_soc_codec_get_bias_level(codec) == SND_SOC_BIAS_OFF) { |
1144 | /* Enable Audio PLL & Audio section */ | 1144 | /* Enable Audio PLL & Audio section */ |
1145 | data = AUDIO_PLL | AUDIO_SECTION_ON; | 1145 | data = AUDIO_PLL | AUDIO_SECTION_ON; |
1146 | pm860x_reg_write(pm860x->i2c, REG_MISC2, data); | 1146 | pm860x_reg_write(pm860x->i2c, REG_MISC2, data); |
@@ -1156,7 +1156,6 @@ static int pm860x_set_bias_level(struct snd_soc_codec *codec, | |||
1156 | pm860x_set_bits(pm860x->i2c, REG_MISC2, data, 0); | 1156 | pm860x_set_bits(pm860x->i2c, REG_MISC2, data, 0); |
1157 | break; | 1157 | break; |
1158 | } | 1158 | } |
1159 | codec->dapm.bias_level = level; | ||
1160 | return 0; | 1159 | return 0; |
1161 | } | 1160 | } |
1162 | 1161 | ||
@@ -1187,16 +1186,16 @@ static struct snd_soc_dai_driver pm860x_dai[] = { | |||
1187 | .channels_min = 2, | 1186 | .channels_min = 2, |
1188 | .channels_max = 2, | 1187 | .channels_max = 2, |
1189 | .rates = PM860X_RATES, | 1188 | .rates = PM860X_RATES, |
1190 | .formats = SNDRV_PCM_FORMAT_S16_LE | \ | 1189 | .formats = SNDRV_PCM_FMTBIT_S16_LE | \ |
1191 | SNDRV_PCM_FORMAT_S18_3LE, | 1190 | SNDRV_PCM_FMTBIT_S18_3LE, |
1192 | }, | 1191 | }, |
1193 | .capture = { | 1192 | .capture = { |
1194 | .stream_name = "PCM Capture", | 1193 | .stream_name = "PCM Capture", |
1195 | .channels_min = 2, | 1194 | .channels_min = 2, |
1196 | .channels_max = 2, | 1195 | .channels_max = 2, |
1197 | .rates = PM860X_RATES, | 1196 | .rates = PM860X_RATES, |
1198 | .formats = SNDRV_PCM_FORMAT_S16_LE | \ | 1197 | .formats = SNDRV_PCM_FMTBIT_S16_LE | \ |
1199 | SNDRV_PCM_FORMAT_S18_3LE, | 1198 | SNDRV_PCM_FMTBIT_S18_3LE, |
1200 | }, | 1199 | }, |
1201 | .ops = &pm860x_pcm_dai_ops, | 1200 | .ops = &pm860x_pcm_dai_ops, |
1202 | }, { | 1201 | }, { |
@@ -1208,16 +1207,16 @@ static struct snd_soc_dai_driver pm860x_dai[] = { | |||
1208 | .channels_min = 2, | 1207 | .channels_min = 2, |
1209 | .channels_max = 2, | 1208 | .channels_max = 2, |
1210 | .rates = SNDRV_PCM_RATE_8000_48000, | 1209 | .rates = SNDRV_PCM_RATE_8000_48000, |
1211 | .formats = SNDRV_PCM_FORMAT_S16_LE | \ | 1210 | .formats = SNDRV_PCM_FMTBIT_S16_LE | \ |
1212 | SNDRV_PCM_FORMAT_S18_3LE, | 1211 | SNDRV_PCM_FMTBIT_S18_3LE, |
1213 | }, | 1212 | }, |
1214 | .capture = { | 1213 | .capture = { |
1215 | .stream_name = "I2S Capture", | 1214 | .stream_name = "I2S Capture", |
1216 | .channels_min = 2, | 1215 | .channels_min = 2, |
1217 | .channels_max = 2, | 1216 | .channels_max = 2, |
1218 | .rates = SNDRV_PCM_RATE_8000_48000, | 1217 | .rates = SNDRV_PCM_RATE_8000_48000, |
1219 | .formats = SNDRV_PCM_FORMAT_S16_LE | \ | 1218 | .formats = SNDRV_PCM_FMTBIT_S16_LE | \ |
1220 | SNDRV_PCM_FORMAT_S18_3LE, | 1219 | SNDRV_PCM_FMTBIT_S18_3LE, |
1221 | }, | 1220 | }, |
1222 | .ops = &pm860x_i2s_dai_ops, | 1221 | .ops = &pm860x_i2s_dai_ops, |
1223 | }, | 1222 | }, |
diff --git a/sound/soc/codecs/Kconfig b/sound/soc/codecs/Kconfig index 061c46587628..efaafce8ba38 100644 --- a/sound/soc/codecs/Kconfig +++ b/sound/soc/codecs/Kconfig | |||
@@ -16,7 +16,7 @@ config SND_SOC_ALL_CODECS | |||
16 | select SND_SOC_88PM860X if MFD_88PM860X | 16 | select SND_SOC_88PM860X if MFD_88PM860X |
17 | select SND_SOC_L3 | 17 | select SND_SOC_L3 |
18 | select SND_SOC_AB8500_CODEC if ABX500_CORE | 18 | select SND_SOC_AB8500_CODEC if ABX500_CORE |
19 | select SND_SOC_AC97_CODEC if SND_SOC_AC97_BUS | 19 | select SND_SOC_AC97_CODEC |
20 | select SND_SOC_AD1836 if SPI_MASTER | 20 | select SND_SOC_AD1836 if SPI_MASTER |
21 | select SND_SOC_AD193X_SPI if SPI_MASTER | 21 | select SND_SOC_AD193X_SPI if SPI_MASTER |
22 | select SND_SOC_AD193X_I2C if I2C | 22 | select SND_SOC_AD193X_I2C if I2C |
@@ -54,7 +54,7 @@ config SND_SOC_ALL_CODECS | |||
54 | select SND_SOC_CS4271_SPI if SPI_MASTER | 54 | select SND_SOC_CS4271_SPI if SPI_MASTER |
55 | select SND_SOC_CS42XX8_I2C if I2C | 55 | select SND_SOC_CS42XX8_I2C if I2C |
56 | select SND_SOC_CX20442 if TTY | 56 | select SND_SOC_CX20442 if TTY |
57 | select SND_SOC_DA7210 if I2C | 57 | select SND_SOC_DA7210 if SND_SOC_I2C_AND_SPI |
58 | select SND_SOC_DA7213 if I2C | 58 | select SND_SOC_DA7213 if I2C |
59 | select SND_SOC_DA732X if I2C | 59 | select SND_SOC_DA732X if I2C |
60 | select SND_SOC_DA9055 if I2C | 60 | select SND_SOC_DA9055 if I2C |
@@ -104,6 +104,7 @@ config SND_SOC_ALL_CODECS | |||
104 | select SND_SOC_STAC9766 if SND_SOC_AC97_BUS | 104 | select SND_SOC_STAC9766 if SND_SOC_AC97_BUS |
105 | select SND_SOC_TAS2552 if I2C | 105 | select SND_SOC_TAS2552 if I2C |
106 | select SND_SOC_TAS5086 if I2C | 106 | select SND_SOC_TAS5086 if I2C |
107 | select SND_SOC_TAS571X if I2C | ||
107 | select SND_SOC_TFA9879 if I2C | 108 | select SND_SOC_TFA9879 if I2C |
108 | select SND_SOC_TLV320AIC23_I2C if I2C | 109 | select SND_SOC_TLV320AIC23_I2C if I2C |
109 | select SND_SOC_TLV320AIC23_SPI if SPI_MASTER | 110 | select SND_SOC_TLV320AIC23_SPI if SPI_MASTER |
@@ -211,8 +212,9 @@ config SND_SOC_AB8500_CODEC | |||
211 | tristate | 212 | tristate |
212 | 213 | ||
213 | config SND_SOC_AC97_CODEC | 214 | config SND_SOC_AC97_CODEC |
214 | tristate | 215 | tristate "Build generic ASoC AC97 CODEC driver" |
215 | select SND_AC97_CODEC | 216 | select SND_AC97_CODEC |
217 | select SND_SOC_AC97_BUS | ||
216 | 218 | ||
217 | config SND_SOC_AD1836 | 219 | config SND_SOC_AD1836 |
218 | tristate | 220 | tristate |
@@ -507,6 +509,11 @@ config SND_SOC_RL6231 | |||
507 | default m if SND_SOC_RT5670=m | 509 | default m if SND_SOC_RT5670=m |
508 | default m if SND_SOC_RT5677=m | 510 | default m if SND_SOC_RT5677=m |
509 | 511 | ||
512 | config SND_SOC_RL6347A | ||
513 | tristate | ||
514 | default y if SND_SOC_RT286=y | ||
515 | default m if SND_SOC_RT286=m | ||
516 | |||
510 | config SND_SOC_RT286 | 517 | config SND_SOC_RT286 |
511 | tristate | 518 | tristate |
512 | depends on I2C | 519 | depends on I2C |
@@ -611,6 +618,10 @@ config SND_SOC_TAS5086 | |||
611 | tristate "Texas Instruments TAS5086 speaker amplifier" | 618 | tristate "Texas Instruments TAS5086 speaker amplifier" |
612 | depends on I2C | 619 | depends on I2C |
613 | 620 | ||
621 | config SND_SOC_TAS571X | ||
622 | tristate "Texas Instruments TAS5711/TAS5717/TAS5719 power amplifiers" | ||
623 | depends on I2C | ||
624 | |||
614 | config SND_SOC_TFA9879 | 625 | config SND_SOC_TFA9879 |
615 | tristate "NXP Semiconductors TFA9879 amplifier" | 626 | tristate "NXP Semiconductors TFA9879 amplifier" |
616 | depends on I2C | 627 | depends on I2C |
diff --git a/sound/soc/codecs/Makefile b/sound/soc/codecs/Makefile index abe2d7edf65c..cf160d972cb3 100644 --- a/sound/soc/codecs/Makefile +++ b/sound/soc/codecs/Makefile | |||
@@ -77,6 +77,7 @@ snd-soc-pcm512x-objs := pcm512x.o | |||
77 | snd-soc-pcm512x-i2c-objs := pcm512x-i2c.o | 77 | snd-soc-pcm512x-i2c-objs := pcm512x-i2c.o |
78 | snd-soc-pcm512x-spi-objs := pcm512x-spi.o | 78 | snd-soc-pcm512x-spi-objs := pcm512x-spi.o |
79 | snd-soc-rl6231-objs := rl6231.o | 79 | snd-soc-rl6231-objs := rl6231.o |
80 | snd-soc-rl6347a-objs := rl6347a.o | ||
80 | snd-soc-rt286-objs := rt286.o | 81 | snd-soc-rt286-objs := rt286.o |
81 | snd-soc-rt5631-objs := rt5631.o | 82 | snd-soc-rt5631-objs := rt5631.o |
82 | snd-soc-rt5640-objs := rt5640.o | 83 | snd-soc-rt5640-objs := rt5640.o |
@@ -106,6 +107,7 @@ snd-soc-sta350-objs := sta350.o | |||
106 | snd-soc-sta529-objs := sta529.o | 107 | snd-soc-sta529-objs := sta529.o |
107 | snd-soc-stac9766-objs := stac9766.o | 108 | snd-soc-stac9766-objs := stac9766.o |
108 | snd-soc-tas5086-objs := tas5086.o | 109 | snd-soc-tas5086-objs := tas5086.o |
110 | snd-soc-tas571x-objs := tas571x.o | ||
109 | snd-soc-tfa9879-objs := tfa9879.o | 111 | snd-soc-tfa9879-objs := tfa9879.o |
110 | snd-soc-tlv320aic23-objs := tlv320aic23.o | 112 | snd-soc-tlv320aic23-objs := tlv320aic23.o |
111 | snd-soc-tlv320aic23-i2c-objs := tlv320aic23-i2c.o | 113 | snd-soc-tlv320aic23-i2c-objs := tlv320aic23-i2c.o |
@@ -262,6 +264,7 @@ obj-$(CONFIG_SND_SOC_PCM512x) += snd-soc-pcm512x.o | |||
262 | obj-$(CONFIG_SND_SOC_PCM512x_I2C) += snd-soc-pcm512x-i2c.o | 264 | obj-$(CONFIG_SND_SOC_PCM512x_I2C) += snd-soc-pcm512x-i2c.o |
263 | obj-$(CONFIG_SND_SOC_PCM512x_SPI) += snd-soc-pcm512x-spi.o | 265 | obj-$(CONFIG_SND_SOC_PCM512x_SPI) += snd-soc-pcm512x-spi.o |
264 | obj-$(CONFIG_SND_SOC_RL6231) += snd-soc-rl6231.o | 266 | obj-$(CONFIG_SND_SOC_RL6231) += snd-soc-rl6231.o |
267 | obj-$(CONFIG_SND_SOC_RL6347A) += snd-soc-rl6347a.o | ||
265 | obj-$(CONFIG_SND_SOC_RT286) += snd-soc-rt286.o | 268 | obj-$(CONFIG_SND_SOC_RT286) += snd-soc-rt286.o |
266 | obj-$(CONFIG_SND_SOC_RT5631) += snd-soc-rt5631.o | 269 | obj-$(CONFIG_SND_SOC_RT5631) += snd-soc-rt5631.o |
267 | obj-$(CONFIG_SND_SOC_RT5640) += snd-soc-rt5640.o | 270 | obj-$(CONFIG_SND_SOC_RT5640) += snd-soc-rt5640.o |
@@ -288,6 +291,7 @@ obj-$(CONFIG_SND_SOC_STA529) += snd-soc-sta529.o | |||
288 | obj-$(CONFIG_SND_SOC_STAC9766) += snd-soc-stac9766.o | 291 | obj-$(CONFIG_SND_SOC_STAC9766) += snd-soc-stac9766.o |
289 | obj-$(CONFIG_SND_SOC_TAS2552) += snd-soc-tas2552.o | 292 | obj-$(CONFIG_SND_SOC_TAS2552) += snd-soc-tas2552.o |
290 | obj-$(CONFIG_SND_SOC_TAS5086) += snd-soc-tas5086.o | 293 | obj-$(CONFIG_SND_SOC_TAS5086) += snd-soc-tas5086.o |
294 | obj-$(CONFIG_SND_SOC_TAS571X) += snd-soc-tas571x.o | ||
291 | obj-$(CONFIG_SND_SOC_TFA9879) += snd-soc-tfa9879.o | 295 | obj-$(CONFIG_SND_SOC_TFA9879) += snd-soc-tfa9879.o |
292 | obj-$(CONFIG_SND_SOC_TLV320AIC23) += snd-soc-tlv320aic23.o | 296 | obj-$(CONFIG_SND_SOC_TLV320AIC23) += snd-soc-tlv320aic23.o |
293 | obj-$(CONFIG_SND_SOC_TLV320AIC23_I2C) += snd-soc-tlv320aic23-i2c.o | 297 | obj-$(CONFIG_SND_SOC_TLV320AIC23_I2C) += snd-soc-tlv320aic23-i2c.o |
diff --git a/sound/soc/codecs/ab8500-codec.c b/sound/soc/codecs/ab8500-codec.c index 88ca9cb0ce79..c7d243db010a 100644 --- a/sound/soc/codecs/ab8500-codec.c +++ b/sound/soc/codecs/ab8500-codec.c | |||
@@ -1209,6 +1209,7 @@ static int anc_status_control_put(struct snd_kcontrol *kcontrol, | |||
1209 | struct snd_ctl_elem_value *ucontrol) | 1209 | struct snd_ctl_elem_value *ucontrol) |
1210 | { | 1210 | { |
1211 | struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol); | 1211 | struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol); |
1212 | struct snd_soc_dapm_context *dapm = snd_soc_codec_get_dapm(codec); | ||
1212 | struct ab8500_codec_drvdata *drvdata = dev_get_drvdata(codec->dev); | 1213 | struct ab8500_codec_drvdata *drvdata = dev_get_drvdata(codec->dev); |
1213 | struct device *dev = codec->dev; | 1214 | struct device *dev = codec->dev; |
1214 | bool apply_fir, apply_iir; | 1215 | bool apply_fir, apply_iir; |
@@ -1234,15 +1235,14 @@ static int anc_status_control_put(struct snd_kcontrol *kcontrol, | |||
1234 | apply_fir = req == ANC_APPLY_FIR || req == ANC_APPLY_FIR_IIR; | 1235 | apply_fir = req == ANC_APPLY_FIR || req == ANC_APPLY_FIR_IIR; |
1235 | apply_iir = req == ANC_APPLY_IIR || req == ANC_APPLY_FIR_IIR; | 1236 | apply_iir = req == ANC_APPLY_IIR || req == ANC_APPLY_FIR_IIR; |
1236 | 1237 | ||
1237 | status = snd_soc_dapm_force_enable_pin(&codec->dapm, | 1238 | status = snd_soc_dapm_force_enable_pin(dapm, "ANC Configure Input"); |
1238 | "ANC Configure Input"); | ||
1239 | if (status < 0) { | 1239 | if (status < 0) { |
1240 | dev_err(dev, | 1240 | dev_err(dev, |
1241 | "%s: ERROR: Failed to enable power (status = %d)!\n", | 1241 | "%s: ERROR: Failed to enable power (status = %d)!\n", |
1242 | __func__, status); | 1242 | __func__, status); |
1243 | goto cleanup; | 1243 | goto cleanup; |
1244 | } | 1244 | } |
1245 | snd_soc_dapm_sync(&codec->dapm); | 1245 | snd_soc_dapm_sync(dapm); |
1246 | 1246 | ||
1247 | anc_configure(codec, apply_fir, apply_iir); | 1247 | anc_configure(codec, apply_fir, apply_iir); |
1248 | 1248 | ||
@@ -1259,8 +1259,8 @@ static int anc_status_control_put(struct snd_kcontrol *kcontrol, | |||
1259 | drvdata->anc_status = ANC_IIR_CONFIGURED; | 1259 | drvdata->anc_status = ANC_IIR_CONFIGURED; |
1260 | } | 1260 | } |
1261 | 1261 | ||
1262 | status = snd_soc_dapm_disable_pin(&codec->dapm, "ANC Configure Input"); | 1262 | status = snd_soc_dapm_disable_pin(dapm, "ANC Configure Input"); |
1263 | snd_soc_dapm_sync(&codec->dapm); | 1263 | snd_soc_dapm_sync(dapm); |
1264 | 1264 | ||
1265 | cleanup: | 1265 | cleanup: |
1266 | mutex_unlock(&drvdata->ctrl_lock); | 1266 | mutex_unlock(&drvdata->ctrl_lock); |
@@ -1947,6 +1947,7 @@ static int ab8500_audio_init_audioblock(struct snd_soc_codec *codec) | |||
1947 | static int ab8500_audio_setup_mics(struct snd_soc_codec *codec, | 1947 | static int ab8500_audio_setup_mics(struct snd_soc_codec *codec, |
1948 | struct amic_settings *amics) | 1948 | struct amic_settings *amics) |
1949 | { | 1949 | { |
1950 | struct snd_soc_dapm_context *dapm = snd_soc_codec_get_dapm(codec); | ||
1950 | u8 value8; | 1951 | u8 value8; |
1951 | unsigned int value; | 1952 | unsigned int value; |
1952 | int status; | 1953 | int status; |
@@ -1973,15 +1974,15 @@ static int ab8500_audio_setup_mics(struct snd_soc_codec *codec, | |||
1973 | dev_dbg(codec->dev, "%s: Mic 1a regulator: %s\n", __func__, | 1974 | dev_dbg(codec->dev, "%s: Mic 1a regulator: %s\n", __func__, |
1974 | amic_micbias_str(amics->mic1a_micbias)); | 1975 | amic_micbias_str(amics->mic1a_micbias)); |
1975 | route = &ab8500_dapm_routes_mic1a_vamicx[amics->mic1a_micbias]; | 1976 | route = &ab8500_dapm_routes_mic1a_vamicx[amics->mic1a_micbias]; |
1976 | status = snd_soc_dapm_add_routes(&codec->dapm, route, 1); | 1977 | status = snd_soc_dapm_add_routes(dapm, route, 1); |
1977 | dev_dbg(codec->dev, "%s: Mic 1b regulator: %s\n", __func__, | 1978 | dev_dbg(codec->dev, "%s: Mic 1b regulator: %s\n", __func__, |
1978 | amic_micbias_str(amics->mic1b_micbias)); | 1979 | amic_micbias_str(amics->mic1b_micbias)); |
1979 | route = &ab8500_dapm_routes_mic1b_vamicx[amics->mic1b_micbias]; | 1980 | route = &ab8500_dapm_routes_mic1b_vamicx[amics->mic1b_micbias]; |
1980 | status |= snd_soc_dapm_add_routes(&codec->dapm, route, 1); | 1981 | status |= snd_soc_dapm_add_routes(dapm, route, 1); |
1981 | dev_dbg(codec->dev, "%s: Mic 2 regulator: %s\n", __func__, | 1982 | dev_dbg(codec->dev, "%s: Mic 2 regulator: %s\n", __func__, |
1982 | amic_micbias_str(amics->mic2_micbias)); | 1983 | amic_micbias_str(amics->mic2_micbias)); |
1983 | route = &ab8500_dapm_routes_mic2_vamicx[amics->mic2_micbias]; | 1984 | route = &ab8500_dapm_routes_mic2_vamicx[amics->mic2_micbias]; |
1984 | status |= snd_soc_dapm_add_routes(&codec->dapm, route, 1); | 1985 | status |= snd_soc_dapm_add_routes(dapm, route, 1); |
1985 | if (status < 0) { | 1986 | if (status < 0) { |
1986 | dev_err(codec->dev, | 1987 | dev_err(codec->dev, |
1987 | "%s: Failed to add AMic-regulator DAPM-routes (%d).\n", | 1988 | "%s: Failed to add AMic-regulator DAPM-routes (%d).\n", |
@@ -2461,6 +2462,7 @@ static void ab8500_codec_of_probe(struct device *dev, struct device_node *np, | |||
2461 | 2462 | ||
2462 | static int ab8500_codec_probe(struct snd_soc_codec *codec) | 2463 | static int ab8500_codec_probe(struct snd_soc_codec *codec) |
2463 | { | 2464 | { |
2465 | struct snd_soc_dapm_context *dapm = snd_soc_codec_get_dapm(codec); | ||
2464 | struct device *dev = codec->dev; | 2466 | struct device *dev = codec->dev; |
2465 | struct device_node *np = dev->of_node; | 2467 | struct device_node *np = dev->of_node; |
2466 | struct ab8500_codec_drvdata *drvdata = dev_get_drvdata(dev); | 2468 | struct ab8500_codec_drvdata *drvdata = dev_get_drvdata(dev); |
@@ -2541,7 +2543,7 @@ static int ab8500_codec_probe(struct snd_soc_codec *codec) | |||
2541 | &ab8500_filter_controls[AB8500_FILTER_SID_FIR].private_value; | 2543 | &ab8500_filter_controls[AB8500_FILTER_SID_FIR].private_value; |
2542 | drvdata->sid_fir_values = (long *)fc->value; | 2544 | drvdata->sid_fir_values = (long *)fc->value; |
2543 | 2545 | ||
2544 | (void)snd_soc_dapm_disable_pin(&codec->dapm, "ANC Configure Input"); | 2546 | snd_soc_dapm_disable_pin(dapm, "ANC Configure Input"); |
2545 | 2547 | ||
2546 | mutex_init(&drvdata->ctrl_lock); | 2548 | mutex_init(&drvdata->ctrl_lock); |
2547 | 2549 | ||
diff --git a/sound/soc/codecs/ac97.c b/sound/soc/codecs/ac97.c index d0ac723eee32..5b3224c63943 100644 --- a/sound/soc/codecs/ac97.c +++ b/sound/soc/codecs/ac97.c | |||
@@ -44,10 +44,6 @@ static int ac97_prepare(struct snd_pcm_substream *substream, | |||
44 | return snd_ac97_set_rate(ac97, reg, substream->runtime->rate); | 44 | return snd_ac97_set_rate(ac97, reg, substream->runtime->rate); |
45 | } | 45 | } |
46 | 46 | ||
47 | #define STD_AC97_RATES (SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_11025 |\ | ||
48 | SNDRV_PCM_RATE_22050 | SNDRV_PCM_RATE_44100 |\ | ||
49 | SNDRV_PCM_RATE_48000) | ||
50 | |||
51 | static const struct snd_soc_dai_ops ac97_dai_ops = { | 47 | static const struct snd_soc_dai_ops ac97_dai_ops = { |
52 | .prepare = ac97_prepare, | 48 | .prepare = ac97_prepare, |
53 | }; | 49 | }; |
@@ -58,13 +54,13 @@ static struct snd_soc_dai_driver ac97_dai = { | |||
58 | .stream_name = "AC97 Playback", | 54 | .stream_name = "AC97 Playback", |
59 | .channels_min = 1, | 55 | .channels_min = 1, |
60 | .channels_max = 2, | 56 | .channels_max = 2, |
61 | .rates = STD_AC97_RATES, | 57 | .rates = SNDRV_PCM_RATE_KNOT, |
62 | .formats = SND_SOC_STD_AC97_FMTS,}, | 58 | .formats = SND_SOC_STD_AC97_FMTS,}, |
63 | .capture = { | 59 | .capture = { |
64 | .stream_name = "AC97 Capture", | 60 | .stream_name = "AC97 Capture", |
65 | .channels_min = 1, | 61 | .channels_min = 1, |
66 | .channels_max = 2, | 62 | .channels_max = 2, |
67 | .rates = STD_AC97_RATES, | 63 | .rates = SNDRV_PCM_RATE_KNOT, |
68 | .formats = SND_SOC_STD_AC97_FMTS,}, | 64 | .formats = SND_SOC_STD_AC97_FMTS,}, |
69 | .ops = &ac97_dai_ops, | 65 | .ops = &ac97_dai_ops, |
70 | }; | 66 | }; |
diff --git a/sound/soc/codecs/ad1836.c b/sound/soc/codecs/ad1836.c index 685998dd086e..95f0bec26a1b 100644 --- a/sound/soc/codecs/ad1836.c +++ b/sound/soc/codecs/ad1836.c | |||
@@ -251,7 +251,7 @@ static int ad1836_resume(struct snd_soc_codec *codec) | |||
251 | static int ad1836_probe(struct snd_soc_codec *codec) | 251 | static int ad1836_probe(struct snd_soc_codec *codec) |
252 | { | 252 | { |
253 | struct ad1836_priv *ad1836 = snd_soc_codec_get_drvdata(codec); | 253 | struct ad1836_priv *ad1836 = snd_soc_codec_get_drvdata(codec); |
254 | struct snd_soc_dapm_context *dapm = &codec->dapm; | 254 | struct snd_soc_dapm_context *dapm = snd_soc_codec_get_dapm(codec); |
255 | int num_dacs, num_adcs; | 255 | int num_dacs, num_adcs; |
256 | int ret = 0; | 256 | int ret = 0; |
257 | int i; | 257 | int i; |
diff --git a/sound/soc/codecs/adau1373.c b/sound/soc/codecs/adau1373.c index 783dcb57043a..a43160254929 100644 --- a/sound/soc/codecs/adau1373.c +++ b/sound/soc/codecs/adau1373.c | |||
@@ -1444,7 +1444,6 @@ static int adau1373_set_bias_level(struct snd_soc_codec *codec, | |||
1444 | ADAU1373_PWDN_CTRL3_PWR_EN, 0); | 1444 | ADAU1373_PWDN_CTRL3_PWR_EN, 0); |
1445 | break; | 1445 | break; |
1446 | } | 1446 | } |
1447 | codec->dapm.bias_level = level; | ||
1448 | return 0; | 1447 | return 0; |
1449 | } | 1448 | } |
1450 | 1449 | ||
diff --git a/sound/soc/codecs/adau1701.c b/sound/soc/codecs/adau1701.c index d4e219b6b98f..ff7f846e3b76 100644 --- a/sound/soc/codecs/adau1701.c +++ b/sound/soc/codecs/adau1701.c | |||
@@ -16,6 +16,7 @@ | |||
16 | #include <linux/of.h> | 16 | #include <linux/of.h> |
17 | #include <linux/of_gpio.h> | 17 | #include <linux/of_gpio.h> |
18 | #include <linux/of_device.h> | 18 | #include <linux/of_device.h> |
19 | #include <linux/regulator/consumer.h> | ||
19 | #include <linux/regmap.h> | 20 | #include <linux/regmap.h> |
20 | #include <sound/core.h> | 21 | #include <sound/core.h> |
21 | #include <sound/pcm.h> | 22 | #include <sound/pcm.h> |
@@ -101,6 +102,10 @@ | |||
101 | 102 | ||
102 | #define ADAU1701_FIRMWARE "adau1701.bin" | 103 | #define ADAU1701_FIRMWARE "adau1701.bin" |
103 | 104 | ||
105 | static const char * const supply_names[] = { | ||
106 | "dvdd", "avdd" | ||
107 | }; | ||
108 | |||
104 | struct adau1701 { | 109 | struct adau1701 { |
105 | int gpio_nreset; | 110 | int gpio_nreset; |
106 | int gpio_pll_mode[2]; | 111 | int gpio_pll_mode[2]; |
@@ -112,6 +117,7 @@ struct adau1701 { | |||
112 | u8 pin_config[12]; | 117 | u8 pin_config[12]; |
113 | 118 | ||
114 | struct sigmadsp *sigmadsp; | 119 | struct sigmadsp *sigmadsp; |
120 | struct regulator_bulk_data supplies[ARRAY_SIZE(supply_names)]; | ||
115 | }; | 121 | }; |
116 | 122 | ||
117 | static const struct snd_kcontrol_new adau1701_controls[] = { | 123 | static const struct snd_kcontrol_new adau1701_controls[] = { |
@@ -565,7 +571,6 @@ static int adau1701_set_bias_level(struct snd_soc_codec *codec, | |||
565 | break; | 571 | break; |
566 | } | 572 | } |
567 | 573 | ||
568 | codec->dapm.bias_level = level; | ||
569 | return 0; | 574 | return 0; |
570 | } | 575 | } |
571 | 576 | ||
@@ -669,6 +674,13 @@ static int adau1701_probe(struct snd_soc_codec *codec) | |||
669 | if (ret) | 674 | if (ret) |
670 | return ret; | 675 | return ret; |
671 | 676 | ||
677 | ret = regulator_bulk_enable(ARRAY_SIZE(adau1701->supplies), | ||
678 | adau1701->supplies); | ||
679 | if (ret < 0) { | ||
680 | dev_err(codec->dev, "Failed to enable regulators: %d\n", ret); | ||
681 | return ret; | ||
682 | } | ||
683 | |||
672 | /* | 684 | /* |
673 | * Let the pll_clkdiv variable default to something that won't happen | 685 | * Let the pll_clkdiv variable default to something that won't happen |
674 | * at runtime. That way, we can postpone the firmware download from | 686 | * at runtime. That way, we can postpone the firmware download from |
@@ -680,7 +692,7 @@ static int adau1701_probe(struct snd_soc_codec *codec) | |||
680 | /* initalize with pre-configured pll mode settings */ | 692 | /* initalize with pre-configured pll mode settings */ |
681 | ret = adau1701_reset(codec, adau1701->pll_clkdiv, 0); | 693 | ret = adau1701_reset(codec, adau1701->pll_clkdiv, 0); |
682 | if (ret < 0) | 694 | if (ret < 0) |
683 | return ret; | 695 | goto exit_regulators_disable; |
684 | 696 | ||
685 | /* set up pin config */ | 697 | /* set up pin config */ |
686 | val = 0; | 698 | val = 0; |
@@ -696,10 +708,60 @@ static int adau1701_probe(struct snd_soc_codec *codec) | |||
696 | regmap_write(adau1701->regmap, ADAU1701_PINCONF_1, val); | 708 | regmap_write(adau1701->regmap, ADAU1701_PINCONF_1, val); |
697 | 709 | ||
698 | return 0; | 710 | return 0; |
711 | |||
712 | exit_regulators_disable: | ||
713 | |||
714 | regulator_bulk_disable(ARRAY_SIZE(adau1701->supplies), adau1701->supplies); | ||
715 | return ret; | ||
699 | } | 716 | } |
700 | 717 | ||
718 | static int adau1701_remove(struct snd_soc_codec *codec) | ||
719 | { | ||
720 | struct adau1701 *adau1701 = snd_soc_codec_get_drvdata(codec); | ||
721 | |||
722 | if (gpio_is_valid(adau1701->gpio_nreset)) | ||
723 | gpio_set_value_cansleep(adau1701->gpio_nreset, 0); | ||
724 | |||
725 | regulator_bulk_disable(ARRAY_SIZE(adau1701->supplies), adau1701->supplies); | ||
726 | |||
727 | return 0; | ||
728 | } | ||
729 | |||
730 | #ifdef CONFIG_PM | ||
731 | static int adau1701_suspend(struct snd_soc_codec *codec) | ||
732 | { | ||
733 | struct adau1701 *adau1701 = snd_soc_codec_get_drvdata(codec); | ||
734 | |||
735 | regulator_bulk_disable(ARRAY_SIZE(adau1701->supplies), | ||
736 | adau1701->supplies); | ||
737 | |||
738 | return 0; | ||
739 | } | ||
740 | |||
741 | static int adau1701_resume(struct snd_soc_codec *codec) | ||
742 | { | ||
743 | struct adau1701 *adau1701 = snd_soc_codec_get_drvdata(codec); | ||
744 | int ret; | ||
745 | |||
746 | ret = regulator_bulk_enable(ARRAY_SIZE(adau1701->supplies), | ||
747 | adau1701->supplies); | ||
748 | if (ret < 0) { | ||
749 | dev_err(codec->dev, "Failed to enable regulators: %d\n", ret); | ||
750 | return ret; | ||
751 | } | ||
752 | |||
753 | return adau1701_reset(codec, adau1701->pll_clkdiv, 0); | ||
754 | } | ||
755 | #else | ||
756 | #define adau1701_resume NULL | ||
757 | #define adau1701_suspend NULL | ||
758 | #endif /* CONFIG_PM */ | ||
759 | |||
701 | static struct snd_soc_codec_driver adau1701_codec_drv = { | 760 | static struct snd_soc_codec_driver adau1701_codec_drv = { |
702 | .probe = adau1701_probe, | 761 | .probe = adau1701_probe, |
762 | .remove = adau1701_remove, | ||
763 | .resume = adau1701_resume, | ||
764 | .suspend = adau1701_suspend, | ||
703 | .set_bias_level = adau1701_set_bias_level, | 765 | .set_bias_level = adau1701_set_bias_level, |
704 | .idle_bias_off = true, | 766 | .idle_bias_off = true, |
705 | 767 | ||
@@ -730,32 +792,58 @@ static int adau1701_i2c_probe(struct i2c_client *client, | |||
730 | struct device *dev = &client->dev; | 792 | struct device *dev = &client->dev; |
731 | int gpio_nreset = -EINVAL; | 793 | int gpio_nreset = -EINVAL; |
732 | int gpio_pll_mode[2] = { -EINVAL, -EINVAL }; | 794 | int gpio_pll_mode[2] = { -EINVAL, -EINVAL }; |
733 | int ret; | 795 | int ret, i; |
734 | 796 | ||
735 | adau1701 = devm_kzalloc(dev, sizeof(*adau1701), GFP_KERNEL); | 797 | adau1701 = devm_kzalloc(dev, sizeof(*adau1701), GFP_KERNEL); |
736 | if (!adau1701) | 798 | if (!adau1701) |
737 | return -ENOMEM; | 799 | return -ENOMEM; |
738 | 800 | ||
801 | for (i = 0; i < ARRAY_SIZE(supply_names); i++) | ||
802 | adau1701->supplies[i].supply = supply_names[i]; | ||
803 | |||
804 | ret = devm_regulator_bulk_get(dev, ARRAY_SIZE(adau1701->supplies), | ||
805 | adau1701->supplies); | ||
806 | if (ret < 0) { | ||
807 | dev_err(dev, "Failed to get regulators: %d\n", ret); | ||
808 | return ret; | ||
809 | } | ||
810 | |||
811 | ret = regulator_bulk_enable(ARRAY_SIZE(adau1701->supplies), | ||
812 | adau1701->supplies); | ||
813 | if (ret < 0) { | ||
814 | dev_err(dev, "Failed to enable regulators: %d\n", ret); | ||
815 | return ret; | ||
816 | } | ||
817 | |||
739 | adau1701->client = client; | 818 | adau1701->client = client; |
740 | adau1701->regmap = devm_regmap_init(dev, NULL, client, | 819 | adau1701->regmap = devm_regmap_init(dev, NULL, client, |
741 | &adau1701_regmap); | 820 | &adau1701_regmap); |
742 | if (IS_ERR(adau1701->regmap)) | 821 | if (IS_ERR(adau1701->regmap)) { |
743 | return PTR_ERR(adau1701->regmap); | 822 | ret = PTR_ERR(adau1701->regmap); |
823 | goto exit_regulators_disable; | ||
824 | } | ||
825 | |||
744 | 826 | ||
745 | if (dev->of_node) { | 827 | if (dev->of_node) { |
746 | gpio_nreset = of_get_named_gpio(dev->of_node, "reset-gpio", 0); | 828 | gpio_nreset = of_get_named_gpio(dev->of_node, "reset-gpio", 0); |
747 | if (gpio_nreset < 0 && gpio_nreset != -ENOENT) | 829 | if (gpio_nreset < 0 && gpio_nreset != -ENOENT) { |
748 | return gpio_nreset; | 830 | ret = gpio_nreset; |
831 | goto exit_regulators_disable; | ||
832 | } | ||
749 | 833 | ||
750 | gpio_pll_mode[0] = of_get_named_gpio(dev->of_node, | 834 | gpio_pll_mode[0] = of_get_named_gpio(dev->of_node, |
751 | "adi,pll-mode-gpios", 0); | 835 | "adi,pll-mode-gpios", 0); |
752 | if (gpio_pll_mode[0] < 0 && gpio_pll_mode[0] != -ENOENT) | 836 | if (gpio_pll_mode[0] < 0 && gpio_pll_mode[0] != -ENOENT) { |
753 | return gpio_pll_mode[0]; | 837 | ret = gpio_pll_mode[0]; |
838 | goto exit_regulators_disable; | ||
839 | } | ||
754 | 840 | ||
755 | gpio_pll_mode[1] = of_get_named_gpio(dev->of_node, | 841 | gpio_pll_mode[1] = of_get_named_gpio(dev->of_node, |
756 | "adi,pll-mode-gpios", 1); | 842 | "adi,pll-mode-gpios", 1); |
757 | if (gpio_pll_mode[1] < 0 && gpio_pll_mode[1] != -ENOENT) | 843 | if (gpio_pll_mode[1] < 0 && gpio_pll_mode[1] != -ENOENT) { |
758 | return gpio_pll_mode[1]; | 844 | ret = gpio_pll_mode[1]; |
845 | goto exit_regulators_disable; | ||
846 | } | ||
759 | 847 | ||
760 | of_property_read_u32(dev->of_node, "adi,pll-clkdiv", | 848 | of_property_read_u32(dev->of_node, "adi,pll-clkdiv", |
761 | &adau1701->pll_clkdiv); | 849 | &adau1701->pll_clkdiv); |
@@ -769,7 +857,7 @@ static int adau1701_i2c_probe(struct i2c_client *client, | |||
769 | ret = devm_gpio_request_one(dev, gpio_nreset, GPIOF_OUT_INIT_LOW, | 857 | ret = devm_gpio_request_one(dev, gpio_nreset, GPIOF_OUT_INIT_LOW, |
770 | "ADAU1701 Reset"); | 858 | "ADAU1701 Reset"); |
771 | if (ret < 0) | 859 | if (ret < 0) |
772 | return ret; | 860 | goto exit_regulators_disable; |
773 | } | 861 | } |
774 | 862 | ||
775 | if (gpio_is_valid(gpio_pll_mode[0]) && | 863 | if (gpio_is_valid(gpio_pll_mode[0]) && |
@@ -778,13 +866,13 @@ static int adau1701_i2c_probe(struct i2c_client *client, | |||
778 | GPIOF_OUT_INIT_LOW, | 866 | GPIOF_OUT_INIT_LOW, |
779 | "ADAU1701 PLL mode 0"); | 867 | "ADAU1701 PLL mode 0"); |
780 | if (ret < 0) | 868 | if (ret < 0) |
781 | return ret; | 869 | goto exit_regulators_disable; |
782 | 870 | ||
783 | ret = devm_gpio_request_one(dev, gpio_pll_mode[1], | 871 | ret = devm_gpio_request_one(dev, gpio_pll_mode[1], |
784 | GPIOF_OUT_INIT_LOW, | 872 | GPIOF_OUT_INIT_LOW, |
785 | "ADAU1701 PLL mode 1"); | 873 | "ADAU1701 PLL mode 1"); |
786 | if (ret < 0) | 874 | if (ret < 0) |
787 | return ret; | 875 | goto exit_regulators_disable; |
788 | } | 876 | } |
789 | 877 | ||
790 | adau1701->gpio_nreset = gpio_nreset; | 878 | adau1701->gpio_nreset = gpio_nreset; |
@@ -795,11 +883,17 @@ static int adau1701_i2c_probe(struct i2c_client *client, | |||
795 | 883 | ||
796 | adau1701->sigmadsp = devm_sigmadsp_init_i2c(client, | 884 | adau1701->sigmadsp = devm_sigmadsp_init_i2c(client, |
797 | &adau1701_sigmadsp_ops, ADAU1701_FIRMWARE); | 885 | &adau1701_sigmadsp_ops, ADAU1701_FIRMWARE); |
798 | if (IS_ERR(adau1701->sigmadsp)) | 886 | if (IS_ERR(adau1701->sigmadsp)) { |
799 | return PTR_ERR(adau1701->sigmadsp); | 887 | ret = PTR_ERR(adau1701->sigmadsp); |
888 | goto exit_regulators_disable; | ||
889 | } | ||
800 | 890 | ||
801 | ret = snd_soc_register_codec(&client->dev, &adau1701_codec_drv, | 891 | ret = snd_soc_register_codec(&client->dev, &adau1701_codec_drv, |
802 | &adau1701_dai, 1); | 892 | &adau1701_dai, 1); |
893 | |||
894 | exit_regulators_disable: | ||
895 | |||
896 | regulator_bulk_disable(ARRAY_SIZE(adau1701->supplies), adau1701->supplies); | ||
803 | return ret; | 897 | return ret; |
804 | } | 898 | } |
805 | 899 | ||
diff --git a/sound/soc/codecs/adau1761.c b/sound/soc/codecs/adau1761.c index a1baeee160f4..2f12477e539e 100644 --- a/sound/soc/codecs/adau1761.c +++ b/sound/soc/codecs/adau1761.c | |||
@@ -466,7 +466,6 @@ static int adau1761_set_bias_level(struct snd_soc_codec *codec, | |||
466 | break; | 466 | break; |
467 | 467 | ||
468 | } | 468 | } |
469 | codec->dapm.bias_level = level; | ||
470 | return 0; | 469 | return 0; |
471 | } | 470 | } |
472 | 471 | ||
@@ -483,6 +482,7 @@ static enum adau1761_output_mode adau1761_get_lineout_mode( | |||
483 | 482 | ||
484 | static int adau1761_setup_digmic_jackdetect(struct snd_soc_codec *codec) | 483 | static int adau1761_setup_digmic_jackdetect(struct snd_soc_codec *codec) |
485 | { | 484 | { |
485 | struct snd_soc_dapm_context *dapm = snd_soc_codec_get_dapm(codec); | ||
486 | struct adau1761_platform_data *pdata = codec->dev->platform_data; | 486 | struct adau1761_platform_data *pdata = codec->dev->platform_data; |
487 | struct adau *adau = snd_soc_codec_get_drvdata(codec); | 487 | struct adau *adau = snd_soc_codec_get_drvdata(codec); |
488 | enum adau1761_digmic_jackdet_pin_mode mode; | 488 | enum adau1761_digmic_jackdet_pin_mode mode; |
@@ -515,21 +515,18 @@ static int adau1761_setup_digmic_jackdetect(struct snd_soc_codec *codec) | |||
515 | if (ret) | 515 | if (ret) |
516 | return ret; | 516 | return ret; |
517 | case ADAU1761_DIGMIC_JACKDET_PIN_MODE_NONE: /* fallthrough */ | 517 | case ADAU1761_DIGMIC_JACKDET_PIN_MODE_NONE: /* fallthrough */ |
518 | ret = snd_soc_dapm_add_routes(&codec->dapm, | 518 | ret = snd_soc_dapm_add_routes(dapm, adau1761_no_dmic_routes, |
519 | adau1761_no_dmic_routes, | ||
520 | ARRAY_SIZE(adau1761_no_dmic_routes)); | 519 | ARRAY_SIZE(adau1761_no_dmic_routes)); |
521 | if (ret) | 520 | if (ret) |
522 | return ret; | 521 | return ret; |
523 | break; | 522 | break; |
524 | case ADAU1761_DIGMIC_JACKDET_PIN_MODE_DIGMIC: | 523 | case ADAU1761_DIGMIC_JACKDET_PIN_MODE_DIGMIC: |
525 | ret = snd_soc_dapm_new_controls(&codec->dapm, | 524 | ret = snd_soc_dapm_new_controls(dapm, adau1761_dmic_widgets, |
526 | adau1761_dmic_widgets, | ||
527 | ARRAY_SIZE(adau1761_dmic_widgets)); | 525 | ARRAY_SIZE(adau1761_dmic_widgets)); |
528 | if (ret) | 526 | if (ret) |
529 | return ret; | 527 | return ret; |
530 | 528 | ||
531 | ret = snd_soc_dapm_add_routes(&codec->dapm, | 529 | ret = snd_soc_dapm_add_routes(dapm, adau1761_dmic_routes, |
532 | adau1761_dmic_routes, | ||
533 | ARRAY_SIZE(adau1761_dmic_routes)); | 530 | ARRAY_SIZE(adau1761_dmic_routes)); |
534 | if (ret) | 531 | if (ret) |
535 | return ret; | 532 | return ret; |
@@ -547,6 +544,7 @@ static int adau1761_setup_digmic_jackdetect(struct snd_soc_codec *codec) | |||
547 | 544 | ||
548 | static int adau1761_setup_headphone_mode(struct snd_soc_codec *codec) | 545 | static int adau1761_setup_headphone_mode(struct snd_soc_codec *codec) |
549 | { | 546 | { |
547 | struct snd_soc_dapm_context *dapm = snd_soc_codec_get_dapm(codec); | ||
550 | struct adau *adau = snd_soc_codec_get_drvdata(codec); | 548 | struct adau *adau = snd_soc_codec_get_drvdata(codec); |
551 | struct adau1761_platform_data *pdata = codec->dev->platform_data; | 549 | struct adau1761_platform_data *pdata = codec->dev->platform_data; |
552 | enum adau1761_output_mode mode; | 550 | enum adau1761_output_mode mode; |
@@ -577,12 +575,12 @@ static int adau1761_setup_headphone_mode(struct snd_soc_codec *codec) | |||
577 | } | 575 | } |
578 | 576 | ||
579 | if (mode == ADAU1761_OUTPUT_MODE_HEADPHONE_CAPLESS) { | 577 | if (mode == ADAU1761_OUTPUT_MODE_HEADPHONE_CAPLESS) { |
580 | ret = snd_soc_dapm_new_controls(&codec->dapm, | 578 | ret = snd_soc_dapm_new_controls(dapm, |
581 | adau1761_capless_dapm_widgets, | 579 | adau1761_capless_dapm_widgets, |
582 | ARRAY_SIZE(adau1761_capless_dapm_widgets)); | 580 | ARRAY_SIZE(adau1761_capless_dapm_widgets)); |
583 | if (ret) | 581 | if (ret) |
584 | return ret; | 582 | return ret; |
585 | ret = snd_soc_dapm_add_routes(&codec->dapm, | 583 | ret = snd_soc_dapm_add_routes(dapm, |
586 | adau1761_capless_dapm_routes, | 584 | adau1761_capless_dapm_routes, |
587 | ARRAY_SIZE(adau1761_capless_dapm_routes)); | 585 | ARRAY_SIZE(adau1761_capless_dapm_routes)); |
588 | } else { | 586 | } else { |
@@ -590,12 +588,12 @@ static int adau1761_setup_headphone_mode(struct snd_soc_codec *codec) | |||
590 | ARRAY_SIZE(adau1761_mono_controls)); | 588 | ARRAY_SIZE(adau1761_mono_controls)); |
591 | if (ret) | 589 | if (ret) |
592 | return ret; | 590 | return ret; |
593 | ret = snd_soc_dapm_new_controls(&codec->dapm, | 591 | ret = snd_soc_dapm_new_controls(dapm, |
594 | adau1761_mono_dapm_widgets, | 592 | adau1761_mono_dapm_widgets, |
595 | ARRAY_SIZE(adau1761_mono_dapm_widgets)); | 593 | ARRAY_SIZE(adau1761_mono_dapm_widgets)); |
596 | if (ret) | 594 | if (ret) |
597 | return ret; | 595 | return ret; |
598 | ret = snd_soc_dapm_add_routes(&codec->dapm, | 596 | ret = snd_soc_dapm_add_routes(dapm, |
599 | adau1761_mono_dapm_routes, | 597 | adau1761_mono_dapm_routes, |
600 | ARRAY_SIZE(adau1761_mono_dapm_routes)); | 598 | ARRAY_SIZE(adau1761_mono_dapm_routes)); |
601 | } | 599 | } |
@@ -640,6 +638,7 @@ static bool adau1761_readable_register(struct device *dev, unsigned int reg) | |||
640 | 638 | ||
641 | static int adau1761_codec_probe(struct snd_soc_codec *codec) | 639 | static int adau1761_codec_probe(struct snd_soc_codec *codec) |
642 | { | 640 | { |
641 | struct snd_soc_dapm_context *dapm = snd_soc_codec_get_dapm(codec); | ||
643 | struct adau1761_platform_data *pdata = codec->dev->platform_data; | 642 | struct adau1761_platform_data *pdata = codec->dev->platform_data; |
644 | struct adau *adau = snd_soc_codec_get_drvdata(codec); | 643 | struct adau *adau = snd_soc_codec_get_drvdata(codec); |
645 | int ret; | 644 | int ret; |
@@ -692,14 +691,12 @@ static int adau1761_codec_probe(struct snd_soc_codec *codec) | |||
692 | return ret; | 691 | return ret; |
693 | 692 | ||
694 | if (adau->type == ADAU1761) { | 693 | if (adau->type == ADAU1761) { |
695 | ret = snd_soc_dapm_new_controls(&codec->dapm, | 694 | ret = snd_soc_dapm_new_controls(dapm, adau1761_dapm_widgets, |
696 | adau1761_dapm_widgets, | ||
697 | ARRAY_SIZE(adau1761_dapm_widgets)); | 695 | ARRAY_SIZE(adau1761_dapm_widgets)); |
698 | if (ret) | 696 | if (ret) |
699 | return ret; | 697 | return ret; |
700 | 698 | ||
701 | ret = snd_soc_dapm_add_routes(&codec->dapm, | 699 | ret = snd_soc_dapm_add_routes(dapm, adau1761_dapm_routes, |
702 | adau1761_dapm_routes, | ||
703 | ARRAY_SIZE(adau1761_dapm_routes)); | 700 | ARRAY_SIZE(adau1761_dapm_routes)); |
704 | if (ret) | 701 | if (ret) |
705 | return ret; | 702 | return ret; |
diff --git a/sound/soc/codecs/adau1781.c b/sound/soc/codecs/adau1781.c index 35581f43fa6d..fde9068550a6 100644 --- a/sound/soc/codecs/adau1781.c +++ b/sound/soc/codecs/adau1781.c | |||
@@ -339,7 +339,6 @@ static int adau1781_set_bias_level(struct snd_soc_codec *codec, | |||
339 | break; | 339 | break; |
340 | } | 340 | } |
341 | 341 | ||
342 | codec->dapm.bias_level = level; | ||
343 | return 0; | 342 | return 0; |
344 | } | 343 | } |
345 | 344 | ||
@@ -383,6 +382,7 @@ static int adau1781_set_input_mode(struct adau *adau, unsigned int reg, | |||
383 | 382 | ||
384 | static int adau1781_codec_probe(struct snd_soc_codec *codec) | 383 | static int adau1781_codec_probe(struct snd_soc_codec *codec) |
385 | { | 384 | { |
385 | struct snd_soc_dapm_context *dapm = snd_soc_codec_get_dapm(codec); | ||
386 | struct adau1781_platform_data *pdata = dev_get_platdata(codec->dev); | 386 | struct adau1781_platform_data *pdata = dev_get_platdata(codec->dev); |
387 | struct adau *adau = snd_soc_codec_get_drvdata(codec); | 387 | struct adau *adau = snd_soc_codec_get_drvdata(codec); |
388 | int ret; | 388 | int ret; |
@@ -403,19 +403,17 @@ static int adau1781_codec_probe(struct snd_soc_codec *codec) | |||
403 | } | 403 | } |
404 | 404 | ||
405 | if (pdata && pdata->use_dmic) { | 405 | if (pdata && pdata->use_dmic) { |
406 | ret = snd_soc_dapm_new_controls(&codec->dapm, | 406 | ret = snd_soc_dapm_new_controls(dapm, |
407 | adau1781_dmic_dapm_widgets, | 407 | adau1781_dmic_dapm_widgets, |
408 | ARRAY_SIZE(adau1781_dmic_dapm_widgets)); | 408 | ARRAY_SIZE(adau1781_dmic_dapm_widgets)); |
409 | if (ret) | 409 | if (ret) |
410 | return ret; | 410 | return ret; |
411 | ret = snd_soc_dapm_add_routes(&codec->dapm, | 411 | ret = snd_soc_dapm_add_routes(dapm, adau1781_dmic_dapm_routes, |
412 | adau1781_dmic_dapm_routes, | ||
413 | ARRAY_SIZE(adau1781_dmic_dapm_routes)); | 412 | ARRAY_SIZE(adau1781_dmic_dapm_routes)); |
414 | if (ret) | 413 | if (ret) |
415 | return ret; | 414 | return ret; |
416 | } else { | 415 | } else { |
417 | ret = snd_soc_dapm_add_routes(&codec->dapm, | 416 | ret = snd_soc_dapm_add_routes(dapm, adau1781_adc_dapm_routes, |
418 | adau1781_adc_dapm_routes, | ||
419 | ARRAY_SIZE(adau1781_adc_dapm_routes)); | 417 | ARRAY_SIZE(adau1781_adc_dapm_routes)); |
420 | if (ret) | 418 | if (ret) |
421 | return ret; | 419 | return ret; |
diff --git a/sound/soc/codecs/adau17x1.c b/sound/soc/codecs/adau17x1.c index fa2e690e51c8..fcf05b254ecd 100644 --- a/sound/soc/codecs/adau17x1.c +++ b/sound/soc/codecs/adau17x1.c | |||
@@ -155,6 +155,7 @@ static int adau17x1_dsp_mux_enum_put(struct snd_kcontrol *kcontrol, | |||
155 | struct snd_ctl_elem_value *ucontrol) | 155 | struct snd_ctl_elem_value *ucontrol) |
156 | { | 156 | { |
157 | struct snd_soc_codec *codec = snd_soc_dapm_kcontrol_codec(kcontrol); | 157 | struct snd_soc_codec *codec = snd_soc_dapm_kcontrol_codec(kcontrol); |
158 | struct snd_soc_dapm_context *dapm = snd_soc_codec_get_dapm(codec); | ||
158 | struct adau *adau = snd_soc_codec_get_drvdata(codec); | 159 | struct adau *adau = snd_soc_codec_get_drvdata(codec); |
159 | struct soc_enum *e = (struct soc_enum *)kcontrol->private_value; | 160 | struct soc_enum *e = (struct soc_enum *)kcontrol->private_value; |
160 | struct snd_soc_dapm_update update; | 161 | struct snd_soc_dapm_update update; |
@@ -188,7 +189,7 @@ static int adau17x1_dsp_mux_enum_put(struct snd_kcontrol *kcontrol, | |||
188 | update.reg = reg; | 189 | update.reg = reg; |
189 | update.val = val; | 190 | update.val = val; |
190 | 191 | ||
191 | snd_soc_dapm_mux_update_power(&codec->dapm, kcontrol, | 192 | snd_soc_dapm_mux_update_power(dapm, kcontrol, |
192 | ucontrol->value.enumerated.item[0], e, &update); | 193 | ucontrol->value.enumerated.item[0], e, &update); |
193 | } | 194 | } |
194 | 195 | ||
@@ -444,8 +445,8 @@ static int adau17x1_set_dai_pll(struct snd_soc_dai *dai, int pll_id, | |||
444 | static int adau17x1_set_dai_sysclk(struct snd_soc_dai *dai, | 445 | static int adau17x1_set_dai_sysclk(struct snd_soc_dai *dai, |
445 | int clk_id, unsigned int freq, int dir) | 446 | int clk_id, unsigned int freq, int dir) |
446 | { | 447 | { |
448 | struct snd_soc_dapm_context *dapm = snd_soc_codec_get_dapm(dai->codec); | ||
447 | struct adau *adau = snd_soc_codec_get_drvdata(dai->codec); | 449 | struct adau *adau = snd_soc_codec_get_drvdata(dai->codec); |
448 | struct snd_soc_dapm_context *dapm = &dai->codec->dapm; | ||
449 | 450 | ||
450 | switch (clk_id) { | 451 | switch (clk_id) { |
451 | case ADAU17X1_CLK_SRC_MCLK: | 452 | case ADAU17X1_CLK_SRC_MCLK: |
@@ -804,6 +805,7 @@ EXPORT_SYMBOL_GPL(adau17x1_setup_firmware); | |||
804 | 805 | ||
805 | int adau17x1_add_widgets(struct snd_soc_codec *codec) | 806 | int adau17x1_add_widgets(struct snd_soc_codec *codec) |
806 | { | 807 | { |
808 | struct snd_soc_dapm_context *dapm = snd_soc_codec_get_dapm(codec); | ||
807 | struct adau *adau = snd_soc_codec_get_drvdata(codec); | 809 | struct adau *adau = snd_soc_codec_get_drvdata(codec); |
808 | int ret; | 810 | int ret; |
809 | 811 | ||
@@ -811,14 +813,13 @@ int adau17x1_add_widgets(struct snd_soc_codec *codec) | |||
811 | ARRAY_SIZE(adau17x1_controls)); | 813 | ARRAY_SIZE(adau17x1_controls)); |
812 | if (ret) | 814 | if (ret) |
813 | return ret; | 815 | return ret; |
814 | ret = snd_soc_dapm_new_controls(&codec->dapm, adau17x1_dapm_widgets, | 816 | ret = snd_soc_dapm_new_controls(dapm, adau17x1_dapm_widgets, |
815 | ARRAY_SIZE(adau17x1_dapm_widgets)); | 817 | ARRAY_SIZE(adau17x1_dapm_widgets)); |
816 | if (ret) | 818 | if (ret) |
817 | return ret; | 819 | return ret; |
818 | 820 | ||
819 | if (adau17x1_has_dsp(adau)) { | 821 | if (adau17x1_has_dsp(adau)) { |
820 | ret = snd_soc_dapm_new_controls(&codec->dapm, | 822 | ret = snd_soc_dapm_new_controls(dapm, adau17x1_dsp_dapm_widgets, |
821 | adau17x1_dsp_dapm_widgets, | ||
822 | ARRAY_SIZE(adau17x1_dsp_dapm_widgets)); | 823 | ARRAY_SIZE(adau17x1_dsp_dapm_widgets)); |
823 | if (ret) | 824 | if (ret) |
824 | return ret; | 825 | return ret; |
@@ -840,21 +841,20 @@ EXPORT_SYMBOL_GPL(adau17x1_add_widgets); | |||
840 | 841 | ||
841 | int adau17x1_add_routes(struct snd_soc_codec *codec) | 842 | int adau17x1_add_routes(struct snd_soc_codec *codec) |
842 | { | 843 | { |
844 | struct snd_soc_dapm_context *dapm = snd_soc_codec_get_dapm(codec); | ||
843 | struct adau *adau = snd_soc_codec_get_drvdata(codec); | 845 | struct adau *adau = snd_soc_codec_get_drvdata(codec); |
844 | int ret; | 846 | int ret; |
845 | 847 | ||
846 | ret = snd_soc_dapm_add_routes(&codec->dapm, adau17x1_dapm_routes, | 848 | ret = snd_soc_dapm_add_routes(dapm, adau17x1_dapm_routes, |
847 | ARRAY_SIZE(adau17x1_dapm_routes)); | 849 | ARRAY_SIZE(adau17x1_dapm_routes)); |
848 | if (ret) | 850 | if (ret) |
849 | return ret; | 851 | return ret; |
850 | 852 | ||
851 | if (adau17x1_has_dsp(adau)) { | 853 | if (adau17x1_has_dsp(adau)) { |
852 | ret = snd_soc_dapm_add_routes(&codec->dapm, | 854 | ret = snd_soc_dapm_add_routes(dapm, adau17x1_dsp_dapm_routes, |
853 | adau17x1_dsp_dapm_routes, | ||
854 | ARRAY_SIZE(adau17x1_dsp_dapm_routes)); | 855 | ARRAY_SIZE(adau17x1_dsp_dapm_routes)); |
855 | } else { | 856 | } else { |
856 | ret = snd_soc_dapm_add_routes(&codec->dapm, | 857 | ret = snd_soc_dapm_add_routes(dapm, adau17x1_no_dsp_dapm_routes, |
857 | adau17x1_no_dsp_dapm_routes, | ||
858 | ARRAY_SIZE(adau17x1_no_dsp_dapm_routes)); | 858 | ARRAY_SIZE(adau17x1_no_dsp_dapm_routes)); |
859 | } | 859 | } |
860 | return ret; | 860 | return ret; |
diff --git a/sound/soc/codecs/adau1977.c b/sound/soc/codecs/adau1977.c index 7ad8e156e2df..9bdd15f408c1 100644 --- a/sound/soc/codecs/adau1977.c +++ b/sound/soc/codecs/adau1977.c | |||
@@ -202,7 +202,7 @@ static const struct snd_soc_dapm_route adau1977_dapm_routes[] = { | |||
202 | ADAU1977_REG_DC_HPF_CAL, (x) - 1, 1, 0) | 202 | ADAU1977_REG_DC_HPF_CAL, (x) - 1, 1, 0) |
203 | 203 | ||
204 | #define ADAU1977_DC_SUB_SWITCH(x) \ | 204 | #define ADAU1977_DC_SUB_SWITCH(x) \ |
205 | SOC_SINGLE("ADC" #x " DC Substraction Capture Switch", \ | 205 | SOC_SINGLE("ADC" #x " DC Subtraction Capture Switch", \ |
206 | ADAU1977_REG_DC_HPF_CAL, (x) + 3, 1, 0) | 206 | ADAU1977_REG_DC_HPF_CAL, (x) + 3, 1, 0) |
207 | 207 | ||
208 | static const struct snd_kcontrol_new adau1977_snd_controls[] = { | 208 | static const struct snd_kcontrol_new adau1977_snd_controls[] = { |
@@ -485,7 +485,7 @@ static int adau1977_set_bias_level(struct snd_soc_codec *codec, | |||
485 | case SND_SOC_BIAS_PREPARE: | 485 | case SND_SOC_BIAS_PREPARE: |
486 | break; | 486 | break; |
487 | case SND_SOC_BIAS_STANDBY: | 487 | case SND_SOC_BIAS_STANDBY: |
488 | if (codec->dapm.bias_level == SND_SOC_BIAS_OFF) | 488 | if (snd_soc_codec_get_bias_level(codec) == SND_SOC_BIAS_OFF) |
489 | ret = adau1977_power_enable(adau1977); | 489 | ret = adau1977_power_enable(adau1977); |
490 | break; | 490 | break; |
491 | case SND_SOC_BIAS_OFF: | 491 | case SND_SOC_BIAS_OFF: |
@@ -493,12 +493,7 @@ static int adau1977_set_bias_level(struct snd_soc_codec *codec, | |||
493 | break; | 493 | break; |
494 | } | 494 | } |
495 | 495 | ||
496 | if (ret) | 496 | return ret; |
497 | return ret; | ||
498 | |||
499 | codec->dapm.bias_level = level; | ||
500 | |||
501 | return 0; | ||
502 | } | 497 | } |
503 | 498 | ||
504 | static int adau1977_set_tdm_slot(struct snd_soc_dai *dai, unsigned int tx_mask, | 499 | static int adau1977_set_tdm_slot(struct snd_soc_dai *dai, unsigned int tx_mask, |
@@ -853,12 +848,13 @@ static int adau1977_set_sysclk(struct snd_soc_codec *codec, | |||
853 | 848 | ||
854 | static int adau1977_codec_probe(struct snd_soc_codec *codec) | 849 | static int adau1977_codec_probe(struct snd_soc_codec *codec) |
855 | { | 850 | { |
851 | struct snd_soc_dapm_context *dapm = snd_soc_codec_get_dapm(codec); | ||
856 | struct adau1977 *adau1977 = snd_soc_codec_get_drvdata(codec); | 852 | struct adau1977 *adau1977 = snd_soc_codec_get_drvdata(codec); |
857 | int ret; | 853 | int ret; |
858 | 854 | ||
859 | switch (adau1977->type) { | 855 | switch (adau1977->type) { |
860 | case ADAU1977: | 856 | case ADAU1977: |
861 | ret = snd_soc_dapm_new_controls(&codec->dapm, | 857 | ret = snd_soc_dapm_new_controls(dapm, |
862 | adau1977_micbias_dapm_widgets, | 858 | adau1977_micbias_dapm_widgets, |
863 | ARRAY_SIZE(adau1977_micbias_dapm_widgets)); | 859 | ARRAY_SIZE(adau1977_micbias_dapm_widgets)); |
864 | if (ret < 0) | 860 | if (ret < 0) |
diff --git a/sound/soc/codecs/adav80x.c b/sound/soc/codecs/adav80x.c index 4373ada95648..36d842570745 100644 --- a/sound/soc/codecs/adav80x.c +++ b/sound/soc/codecs/adav80x.c | |||
@@ -539,7 +539,7 @@ static int adav80x_set_sysclk(struct snd_soc_codec *codec, | |||
539 | unsigned int freq, int dir) | 539 | unsigned int freq, int dir) |
540 | { | 540 | { |
541 | struct adav80x *adav80x = snd_soc_codec_get_drvdata(codec); | 541 | struct adav80x *adav80x = snd_soc_codec_get_drvdata(codec); |
542 | struct snd_soc_dapm_context *dapm = &codec->dapm; | 542 | struct snd_soc_dapm_context *dapm = snd_soc_codec_get_dapm(codec); |
543 | 543 | ||
544 | if (dir == SND_SOC_CLOCK_IN) { | 544 | if (dir == SND_SOC_CLOCK_IN) { |
545 | switch (clk_id) { | 545 | switch (clk_id) { |
@@ -622,6 +622,7 @@ static int adav80x_set_sysclk(struct snd_soc_codec *codec, | |||
622 | static int adav80x_set_pll(struct snd_soc_codec *codec, int pll_id, | 622 | static int adav80x_set_pll(struct snd_soc_codec *codec, int pll_id, |
623 | int source, unsigned int freq_in, unsigned int freq_out) | 623 | int source, unsigned int freq_in, unsigned int freq_out) |
624 | { | 624 | { |
625 | struct snd_soc_dapm_context *dapm = snd_soc_codec_get_dapm(codec); | ||
625 | struct adav80x *adav80x = snd_soc_codec_get_drvdata(codec); | 626 | struct adav80x *adav80x = snd_soc_codec_get_drvdata(codec); |
626 | unsigned int pll_ctrl1 = 0; | 627 | unsigned int pll_ctrl1 = 0; |
627 | unsigned int pll_ctrl2 = 0; | 628 | unsigned int pll_ctrl2 = 0; |
@@ -687,7 +688,7 @@ static int adav80x_set_pll(struct snd_soc_codec *codec, int pll_id, | |||
687 | 688 | ||
688 | adav80x->pll_src = source; | 689 | adav80x->pll_src = source; |
689 | 690 | ||
690 | snd_soc_dapm_sync(&codec->dapm); | 691 | snd_soc_dapm_sync(dapm); |
691 | } | 692 | } |
692 | 693 | ||
693 | return 0; | 694 | return 0; |
@@ -714,7 +715,6 @@ static int adav80x_set_bias_level(struct snd_soc_codec *codec, | |||
714 | break; | 715 | break; |
715 | } | 716 | } |
716 | 717 | ||
717 | codec->dapm.bias_level = level; | ||
718 | return 0; | 718 | return 0; |
719 | } | 719 | } |
720 | 720 | ||
@@ -801,11 +801,12 @@ static struct snd_soc_dai_driver adav80x_dais[] = { | |||
801 | 801 | ||
802 | static int adav80x_probe(struct snd_soc_codec *codec) | 802 | static int adav80x_probe(struct snd_soc_codec *codec) |
803 | { | 803 | { |
804 | struct snd_soc_dapm_context *dapm = snd_soc_codec_get_dapm(codec); | ||
804 | struct adav80x *adav80x = snd_soc_codec_get_drvdata(codec); | 805 | struct adav80x *adav80x = snd_soc_codec_get_drvdata(codec); |
805 | 806 | ||
806 | /* Force PLLs on for SYSCLK output */ | 807 | /* Force PLLs on for SYSCLK output */ |
807 | snd_soc_dapm_force_enable_pin(&codec->dapm, "PLL1"); | 808 | snd_soc_dapm_force_enable_pin(dapm, "PLL1"); |
808 | snd_soc_dapm_force_enable_pin(&codec->dapm, "PLL2"); | 809 | snd_soc_dapm_force_enable_pin(dapm, "PLL2"); |
809 | 810 | ||
810 | /* Power down S/PDIF receiver, since it is currently not supported */ | 811 | /* Power down S/PDIF receiver, since it is currently not supported */ |
811 | regmap_write(adav80x->regmap, ADAV80X_PLL_OUTE, 0x20); | 812 | regmap_write(adav80x->regmap, ADAV80X_PLL_OUTE, 0x20); |
diff --git a/sound/soc/codecs/ak4535.c b/sound/soc/codecs/ak4535.c index 9130d916f2f4..8670861e5bec 100644 --- a/sound/soc/codecs/ak4535.c +++ b/sound/soc/codecs/ak4535.c | |||
@@ -341,7 +341,6 @@ static int ak4535_set_bias_level(struct snd_soc_codec *codec, | |||
341 | snd_soc_update_bits(codec, AK4535_PM1, 0x80, 0); | 341 | snd_soc_update_bits(codec, AK4535_PM1, 0x80, 0); |
342 | break; | 342 | break; |
343 | } | 343 | } |
344 | codec->dapm.bias_level = level; | ||
345 | return 0; | 344 | return 0; |
346 | } | 345 | } |
347 | 346 | ||
diff --git a/sound/soc/codecs/ak4641.c b/sound/soc/codecs/ak4641.c index 81b54a270bd8..2d0ff4595ea0 100644 --- a/sound/soc/codecs/ak4641.c +++ b/sound/soc/codecs/ak4641.c | |||
@@ -412,7 +412,7 @@ static int ak4641_set_bias_level(struct snd_soc_codec *codec, | |||
412 | snd_soc_update_bits(codec, AK4641_DAC, 0x20, 0x20); | 412 | snd_soc_update_bits(codec, AK4641_DAC, 0x20, 0x20); |
413 | break; | 413 | break; |
414 | case SND_SOC_BIAS_STANDBY: | 414 | case SND_SOC_BIAS_STANDBY: |
415 | if (codec->dapm.bias_level == SND_SOC_BIAS_OFF) { | 415 | if (snd_soc_codec_get_bias_level(codec) == SND_SOC_BIAS_OFF) { |
416 | if (pdata && gpio_is_valid(pdata->gpio_power)) | 416 | if (pdata && gpio_is_valid(pdata->gpio_power)) |
417 | gpio_set_value(pdata->gpio_power, 1); | 417 | gpio_set_value(pdata->gpio_power, 1); |
418 | mdelay(1); | 418 | mdelay(1); |
@@ -439,7 +439,6 @@ static int ak4641_set_bias_level(struct snd_soc_codec *codec, | |||
439 | regcache_mark_dirty(ak4641->regmap); | 439 | regcache_mark_dirty(ak4641->regmap); |
440 | break; | 440 | break; |
441 | } | 441 | } |
442 | codec->dapm.bias_level = level; | ||
443 | return 0; | 442 | return 0; |
444 | } | 443 | } |
445 | 444 | ||
diff --git a/sound/soc/codecs/ak4642.c b/sound/soc/codecs/ak4642.c index 13585e88f597..7c0f6552c229 100644 --- a/sound/soc/codecs/ak4642.c +++ b/sound/soc/codecs/ak4642.c | |||
@@ -482,7 +482,6 @@ static int ak4642_set_bias_level(struct snd_soc_codec *codec, | |||
482 | snd_soc_update_bits(codec, PW_MGMT1, PMVCM, PMVCM); | 482 | snd_soc_update_bits(codec, PW_MGMT1, PMVCM, PMVCM); |
483 | break; | 483 | break; |
484 | } | 484 | } |
485 | codec->dapm.bias_level = level; | ||
486 | 485 | ||
487 | return 0; | 486 | return 0; |
488 | } | 487 | } |
diff --git a/sound/soc/codecs/ak4671.c b/sound/soc/codecs/ak4671.c index 2a58b1dccd2f..0e59063aeb6f 100644 --- a/sound/soc/codecs/ak4671.c +++ b/sound/soc/codecs/ak4671.c | |||
@@ -577,7 +577,6 @@ static int ak4671_set_bias_level(struct snd_soc_codec *codec, | |||
577 | snd_soc_write(codec, AK4671_AD_DA_POWER_MANAGEMENT, 0x00); | 577 | snd_soc_write(codec, AK4671_AD_DA_POWER_MANAGEMENT, 0x00); |
578 | break; | 578 | break; |
579 | } | 579 | } |
580 | codec->dapm.bias_level = level; | ||
581 | return 0; | 580 | return 0; |
582 | } | 581 | } |
583 | 582 | ||
diff --git a/sound/soc/codecs/alc5623.c b/sound/soc/codecs/alc5623.c index 0e357996864b..0fc24e0d518c 100644 --- a/sound/soc/codecs/alc5623.c +++ b/sound/soc/codecs/alc5623.c | |||
@@ -826,7 +826,6 @@ static int alc5623_set_bias_level(struct snd_soc_codec *codec, | |||
826 | snd_soc_write(codec, ALC5623_PWR_MANAG_ADD1, 0); | 826 | snd_soc_write(codec, ALC5623_PWR_MANAG_ADD1, 0); |
827 | break; | 827 | break; |
828 | } | 828 | } |
829 | codec->dapm.bias_level = level; | ||
830 | return 0; | 829 | return 0; |
831 | } | 830 | } |
832 | 831 | ||
@@ -894,7 +893,7 @@ static int alc5623_resume(struct snd_soc_codec *codec) | |||
894 | static int alc5623_probe(struct snd_soc_codec *codec) | 893 | static int alc5623_probe(struct snd_soc_codec *codec) |
895 | { | 894 | { |
896 | struct alc5623_priv *alc5623 = snd_soc_codec_get_drvdata(codec); | 895 | struct alc5623_priv *alc5623 = snd_soc_codec_get_drvdata(codec); |
897 | struct snd_soc_dapm_context *dapm = &codec->dapm; | 896 | struct snd_soc_dapm_context *dapm = snd_soc_codec_get_dapm(codec); |
898 | 897 | ||
899 | alc5623_reset(codec); | 898 | alc5623_reset(codec); |
900 | 899 | ||
diff --git a/sound/soc/codecs/alc5632.c b/sound/soc/codecs/alc5632.c index db3283abbe18..607a63b9705f 100644 --- a/sound/soc/codecs/alc5632.c +++ b/sound/soc/codecs/alc5632.c | |||
@@ -1000,7 +1000,6 @@ static int alc5632_set_bias_level(struct snd_soc_codec *codec, | |||
1000 | ALC5632_PWR_MANAG_ADD1_MASK, 0); | 1000 | ALC5632_PWR_MANAG_ADD1_MASK, 0); |
1001 | break; | 1001 | break; |
1002 | } | 1002 | } |
1003 | codec->dapm.bias_level = level; | ||
1004 | return 0; | 1003 | return 0; |
1005 | } | 1004 | } |
1006 | 1005 | ||
diff --git a/sound/soc/codecs/arizona.c b/sound/soc/codecs/arizona.c index eff4b4d512b7..88f6df21ad95 100644 --- a/sound/soc/codecs/arizona.c +++ b/sound/soc/codecs/arizona.c | |||
@@ -208,11 +208,12 @@ static const struct snd_soc_dapm_widget arizona_spkr = | |||
208 | 208 | ||
209 | int arizona_init_spk(struct snd_soc_codec *codec) | 209 | int arizona_init_spk(struct snd_soc_codec *codec) |
210 | { | 210 | { |
211 | struct snd_soc_dapm_context *dapm = snd_soc_codec_get_dapm(codec); | ||
211 | struct arizona_priv *priv = snd_soc_codec_get_drvdata(codec); | 212 | struct arizona_priv *priv = snd_soc_codec_get_drvdata(codec); |
212 | struct arizona *arizona = priv->arizona; | 213 | struct arizona *arizona = priv->arizona; |
213 | int ret; | 214 | int ret; |
214 | 215 | ||
215 | ret = snd_soc_dapm_new_controls(&codec->dapm, &arizona_spkl, 1); | 216 | ret = snd_soc_dapm_new_controls(dapm, &arizona_spkl, 1); |
216 | if (ret != 0) | 217 | if (ret != 0) |
217 | return ret; | 218 | return ret; |
218 | 219 | ||
@@ -220,8 +221,7 @@ int arizona_init_spk(struct snd_soc_codec *codec) | |||
220 | case WM8997: | 221 | case WM8997: |
221 | break; | 222 | break; |
222 | default: | 223 | default: |
223 | ret = snd_soc_dapm_new_controls(&codec->dapm, | 224 | ret = snd_soc_dapm_new_controls(dapm, &arizona_spkr, 1); |
224 | &arizona_spkr, 1); | ||
225 | if (ret != 0) | 225 | if (ret != 0) |
226 | return ret; | 226 | return ret; |
227 | break; | 227 | break; |
@@ -258,13 +258,14 @@ static const struct snd_soc_dapm_route arizona_mono_routes[] = { | |||
258 | 258 | ||
259 | int arizona_init_mono(struct snd_soc_codec *codec) | 259 | int arizona_init_mono(struct snd_soc_codec *codec) |
260 | { | 260 | { |
261 | struct snd_soc_dapm_context *dapm = snd_soc_codec_get_dapm(codec); | ||
261 | struct arizona_priv *priv = snd_soc_codec_get_drvdata(codec); | 262 | struct arizona_priv *priv = snd_soc_codec_get_drvdata(codec); |
262 | struct arizona *arizona = priv->arizona; | 263 | struct arizona *arizona = priv->arizona; |
263 | int i; | 264 | int i; |
264 | 265 | ||
265 | for (i = 0; i < ARIZONA_MAX_OUTPUT; ++i) { | 266 | for (i = 0; i < ARIZONA_MAX_OUTPUT; ++i) { |
266 | if (arizona->pdata.out_mono[i]) | 267 | if (arizona->pdata.out_mono[i]) |
267 | snd_soc_dapm_add_routes(&codec->dapm, | 268 | snd_soc_dapm_add_routes(dapm, |
268 | &arizona_mono_routes[i], 1); | 269 | &arizona_mono_routes[i], 1); |
269 | } | 270 | } |
270 | 271 | ||
@@ -274,6 +275,7 @@ EXPORT_SYMBOL_GPL(arizona_init_mono); | |||
274 | 275 | ||
275 | int arizona_init_gpio(struct snd_soc_codec *codec) | 276 | int arizona_init_gpio(struct snd_soc_codec *codec) |
276 | { | 277 | { |
278 | struct snd_soc_dapm_context *dapm = snd_soc_codec_get_dapm(codec); | ||
277 | struct arizona_priv *priv = snd_soc_codec_get_drvdata(codec); | 279 | struct arizona_priv *priv = snd_soc_codec_get_drvdata(codec); |
278 | struct arizona *arizona = priv->arizona; | 280 | struct arizona *arizona = priv->arizona; |
279 | int i; | 281 | int i; |
@@ -281,23 +283,21 @@ int arizona_init_gpio(struct snd_soc_codec *codec) | |||
281 | switch (arizona->type) { | 283 | switch (arizona->type) { |
282 | case WM5110: | 284 | case WM5110: |
283 | case WM8280: | 285 | case WM8280: |
284 | snd_soc_dapm_disable_pin(&codec->dapm, "DRC2 Signal Activity"); | 286 | snd_soc_dapm_disable_pin(dapm, "DRC2 Signal Activity"); |
285 | break; | 287 | break; |
286 | default: | 288 | default: |
287 | break; | 289 | break; |
288 | } | 290 | } |
289 | 291 | ||
290 | snd_soc_dapm_disable_pin(&codec->dapm, "DRC1 Signal Activity"); | 292 | snd_soc_dapm_disable_pin(dapm, "DRC1 Signal Activity"); |
291 | 293 | ||
292 | for (i = 0; i < ARRAY_SIZE(arizona->pdata.gpio_defaults); i++) { | 294 | for (i = 0; i < ARRAY_SIZE(arizona->pdata.gpio_defaults); i++) { |
293 | switch (arizona->pdata.gpio_defaults[i] & ARIZONA_GPN_FN_MASK) { | 295 | switch (arizona->pdata.gpio_defaults[i] & ARIZONA_GPN_FN_MASK) { |
294 | case ARIZONA_GP_FN_DRC1_SIGNAL_DETECT: | 296 | case ARIZONA_GP_FN_DRC1_SIGNAL_DETECT: |
295 | snd_soc_dapm_enable_pin(&codec->dapm, | 297 | snd_soc_dapm_enable_pin(dapm, "DRC1 Signal Activity"); |
296 | "DRC1 Signal Activity"); | ||
297 | break; | 298 | break; |
298 | case ARIZONA_GP_FN_DRC2_SIGNAL_DETECT: | 299 | case ARIZONA_GP_FN_DRC2_SIGNAL_DETECT: |
299 | snd_soc_dapm_enable_pin(&codec->dapm, | 300 | snd_soc_dapm_enable_pin(dapm, "DRC2 Signal Activity"); |
300 | "DRC2 Signal Activity"); | ||
301 | break; | 301 | break; |
302 | default: | 302 | default: |
303 | break; | 303 | break; |
@@ -851,6 +851,134 @@ int arizona_hp_ev(struct snd_soc_dapm_widget *w, | |||
851 | } | 851 | } |
852 | EXPORT_SYMBOL_GPL(arizona_hp_ev); | 852 | EXPORT_SYMBOL_GPL(arizona_hp_ev); |
853 | 853 | ||
854 | static int arizona_dvfs_enable(struct snd_soc_codec *codec) | ||
855 | { | ||
856 | const struct arizona_priv *priv = snd_soc_codec_get_drvdata(codec); | ||
857 | struct arizona *arizona = priv->arizona; | ||
858 | int ret; | ||
859 | |||
860 | ret = regulator_set_voltage(arizona->dcvdd, 1800000, 1800000); | ||
861 | if (ret) { | ||
862 | dev_err(codec->dev, "Failed to boost DCVDD: %d\n", ret); | ||
863 | return ret; | ||
864 | } | ||
865 | |||
866 | ret = regmap_update_bits(arizona->regmap, | ||
867 | ARIZONA_DYNAMIC_FREQUENCY_SCALING_1, | ||
868 | ARIZONA_SUBSYS_MAX_FREQ, | ||
869 | ARIZONA_SUBSYS_MAX_FREQ); | ||
870 | if (ret) { | ||
871 | dev_err(codec->dev, "Failed to enable subsys max: %d\n", ret); | ||
872 | regulator_set_voltage(arizona->dcvdd, 1200000, 1800000); | ||
873 | return ret; | ||
874 | } | ||
875 | |||
876 | return 0; | ||
877 | } | ||
878 | |||
879 | static int arizona_dvfs_disable(struct snd_soc_codec *codec) | ||
880 | { | ||
881 | const struct arizona_priv *priv = snd_soc_codec_get_drvdata(codec); | ||
882 | struct arizona *arizona = priv->arizona; | ||
883 | int ret; | ||
884 | |||
885 | ret = regmap_update_bits(arizona->regmap, | ||
886 | ARIZONA_DYNAMIC_FREQUENCY_SCALING_1, | ||
887 | ARIZONA_SUBSYS_MAX_FREQ, 0); | ||
888 | if (ret) { | ||
889 | dev_err(codec->dev, "Failed to disable subsys max: %d\n", ret); | ||
890 | return ret; | ||
891 | } | ||
892 | |||
893 | ret = regulator_set_voltage(arizona->dcvdd, 1200000, 1800000); | ||
894 | if (ret) { | ||
895 | dev_err(codec->dev, "Failed to unboost DCVDD: %d\n", ret); | ||
896 | return ret; | ||
897 | } | ||
898 | |||
899 | return 0; | ||
900 | } | ||
901 | |||
902 | int arizona_dvfs_up(struct snd_soc_codec *codec, unsigned int flags) | ||
903 | { | ||
904 | struct arizona_priv *priv = snd_soc_codec_get_drvdata(codec); | ||
905 | int ret = 0; | ||
906 | |||
907 | mutex_lock(&priv->dvfs_lock); | ||
908 | |||
909 | if (!priv->dvfs_cached && !priv->dvfs_reqs) { | ||
910 | ret = arizona_dvfs_enable(codec); | ||
911 | if (ret) | ||
912 | goto err; | ||
913 | } | ||
914 | |||
915 | priv->dvfs_reqs |= flags; | ||
916 | err: | ||
917 | mutex_unlock(&priv->dvfs_lock); | ||
918 | return ret; | ||
919 | } | ||
920 | EXPORT_SYMBOL_GPL(arizona_dvfs_up); | ||
921 | |||
922 | int arizona_dvfs_down(struct snd_soc_codec *codec, unsigned int flags) | ||
923 | { | ||
924 | struct arizona_priv *priv = snd_soc_codec_get_drvdata(codec); | ||
925 | unsigned int old_reqs; | ||
926 | int ret = 0; | ||
927 | |||
928 | mutex_lock(&priv->dvfs_lock); | ||
929 | |||
930 | old_reqs = priv->dvfs_reqs; | ||
931 | priv->dvfs_reqs &= ~flags; | ||
932 | |||
933 | if (!priv->dvfs_cached && old_reqs && !priv->dvfs_reqs) | ||
934 | ret = arizona_dvfs_disable(codec); | ||
935 | |||
936 | mutex_unlock(&priv->dvfs_lock); | ||
937 | return ret; | ||
938 | } | ||
939 | EXPORT_SYMBOL_GPL(arizona_dvfs_down); | ||
940 | |||
941 | int arizona_dvfs_sysclk_ev(struct snd_soc_dapm_widget *w, | ||
942 | struct snd_kcontrol *kcontrol, int event) | ||
943 | { | ||
944 | struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm); | ||
945 | struct arizona_priv *priv = snd_soc_codec_get_drvdata(codec); | ||
946 | int ret = 0; | ||
947 | |||
948 | mutex_lock(&priv->dvfs_lock); | ||
949 | |||
950 | switch (event) { | ||
951 | case SND_SOC_DAPM_POST_PMU: | ||
952 | if (priv->dvfs_reqs) | ||
953 | ret = arizona_dvfs_enable(codec); | ||
954 | |||
955 | priv->dvfs_cached = false; | ||
956 | break; | ||
957 | case SND_SOC_DAPM_PRE_PMD: | ||
958 | /* We must ensure DVFS is disabled before the codec goes into | ||
959 | * suspend so that we are never in an illegal state of DVFS | ||
960 | * enabled without enough DCVDD | ||
961 | */ | ||
962 | priv->dvfs_cached = true; | ||
963 | |||
964 | if (priv->dvfs_reqs) | ||
965 | ret = arizona_dvfs_disable(codec); | ||
966 | break; | ||
967 | default: | ||
968 | break; | ||
969 | } | ||
970 | |||
971 | mutex_unlock(&priv->dvfs_lock); | ||
972 | return ret; | ||
973 | } | ||
974 | EXPORT_SYMBOL_GPL(arizona_dvfs_sysclk_ev); | ||
975 | |||
976 | void arizona_init_dvfs(struct arizona_priv *priv) | ||
977 | { | ||
978 | mutex_init(&priv->dvfs_lock); | ||
979 | } | ||
980 | EXPORT_SYMBOL_GPL(arizona_init_dvfs); | ||
981 | |||
854 | static unsigned int arizona_sysclk_48k_rates[] = { | 982 | static unsigned int arizona_sysclk_48k_rates[] = { |
855 | 6144000, | 983 | 6144000, |
856 | 12288000, | 984 | 12288000, |
@@ -1266,7 +1394,7 @@ static int arizona_hw_params_rate(struct snd_pcm_substream *substream, | |||
1266 | struct arizona_priv *priv = snd_soc_codec_get_drvdata(codec); | 1394 | struct arizona_priv *priv = snd_soc_codec_get_drvdata(codec); |
1267 | struct arizona_dai_priv *dai_priv = &priv->dai[dai->id - 1]; | 1395 | struct arizona_dai_priv *dai_priv = &priv->dai[dai->id - 1]; |
1268 | int base = dai->driver->base; | 1396 | int base = dai->driver->base; |
1269 | int i, sr_val; | 1397 | int i, sr_val, ret; |
1270 | 1398 | ||
1271 | /* | 1399 | /* |
1272 | * We will need to be more flexible than this in future, | 1400 | * We will need to be more flexible than this in future, |
@@ -1282,6 +1410,23 @@ static int arizona_hw_params_rate(struct snd_pcm_substream *substream, | |||
1282 | } | 1410 | } |
1283 | sr_val = i; | 1411 | sr_val = i; |
1284 | 1412 | ||
1413 | switch (priv->arizona->type) { | ||
1414 | case WM5102: | ||
1415 | case WM8997: | ||
1416 | if (arizona_sr_vals[sr_val] >= 88200) | ||
1417 | ret = arizona_dvfs_up(codec, ARIZONA_DVFS_SR1_RQ); | ||
1418 | else | ||
1419 | ret = arizona_dvfs_down(codec, ARIZONA_DVFS_SR1_RQ); | ||
1420 | |||
1421 | if (ret) { | ||
1422 | arizona_aif_err(dai, "Failed to change DVFS %d\n", ret); | ||
1423 | return ret; | ||
1424 | } | ||
1425 | break; | ||
1426 | default: | ||
1427 | break; | ||
1428 | } | ||
1429 | |||
1285 | switch (dai_priv->clk) { | 1430 | switch (dai_priv->clk) { |
1286 | case ARIZONA_CLK_SYSCLK: | 1431 | case ARIZONA_CLK_SYSCLK: |
1287 | switch (priv->arizona->type) { | 1432 | switch (priv->arizona->type) { |
@@ -1474,6 +1619,7 @@ static int arizona_dai_set_sysclk(struct snd_soc_dai *dai, | |||
1474 | int clk_id, unsigned int freq, int dir) | 1619 | int clk_id, unsigned int freq, int dir) |
1475 | { | 1620 | { |
1476 | struct snd_soc_codec *codec = dai->codec; | 1621 | struct snd_soc_codec *codec = dai->codec; |
1622 | struct snd_soc_dapm_context *dapm = snd_soc_codec_get_dapm(codec); | ||
1477 | struct arizona_priv *priv = snd_soc_codec_get_drvdata(codec); | 1623 | struct arizona_priv *priv = snd_soc_codec_get_drvdata(codec); |
1478 | struct arizona_dai_priv *dai_priv = &priv->dai[dai->id - 1]; | 1624 | struct arizona_dai_priv *dai_priv = &priv->dai[dai->id - 1]; |
1479 | struct snd_soc_dapm_route routes[2]; | 1625 | struct snd_soc_dapm_route routes[2]; |
@@ -1504,15 +1650,15 @@ static int arizona_dai_set_sysclk(struct snd_soc_dai *dai, | |||
1504 | 1650 | ||
1505 | routes[0].source = arizona_dai_clk_str(dai_priv->clk); | 1651 | routes[0].source = arizona_dai_clk_str(dai_priv->clk); |
1506 | routes[1].source = arizona_dai_clk_str(dai_priv->clk); | 1652 | routes[1].source = arizona_dai_clk_str(dai_priv->clk); |
1507 | snd_soc_dapm_del_routes(&codec->dapm, routes, ARRAY_SIZE(routes)); | 1653 | snd_soc_dapm_del_routes(dapm, routes, ARRAY_SIZE(routes)); |
1508 | 1654 | ||
1509 | routes[0].source = arizona_dai_clk_str(clk_id); | 1655 | routes[0].source = arizona_dai_clk_str(clk_id); |
1510 | routes[1].source = arizona_dai_clk_str(clk_id); | 1656 | routes[1].source = arizona_dai_clk_str(clk_id); |
1511 | snd_soc_dapm_add_routes(&codec->dapm, routes, ARRAY_SIZE(routes)); | 1657 | snd_soc_dapm_add_routes(dapm, routes, ARRAY_SIZE(routes)); |
1512 | 1658 | ||
1513 | dai_priv->clk = clk_id; | 1659 | dai_priv->clk = clk_id; |
1514 | 1660 | ||
1515 | return snd_soc_dapm_sync(&codec->dapm); | 1661 | return snd_soc_dapm_sync(dapm); |
1516 | } | 1662 | } |
1517 | 1663 | ||
1518 | static int arizona_set_tristate(struct snd_soc_dai *dai, int tristate) | 1664 | static int arizona_set_tristate(struct snd_soc_dai *dai, int tristate) |
diff --git a/sound/soc/codecs/arizona.h b/sound/soc/codecs/arizona.h index 11ff899b0272..84e119a56515 100644 --- a/sound/soc/codecs/arizona.h +++ b/sound/soc/codecs/arizona.h | |||
@@ -60,6 +60,9 @@ | |||
60 | #define ARIZONA_MAX_DAI 6 | 60 | #define ARIZONA_MAX_DAI 6 |
61 | #define ARIZONA_MAX_ADSP 4 | 61 | #define ARIZONA_MAX_ADSP 4 |
62 | 62 | ||
63 | #define ARIZONA_DVFS_SR1_RQ 0x001 | ||
64 | #define ARIZONA_DVFS_ADSP1_RQ 0x100 | ||
65 | |||
63 | struct arizona; | 66 | struct arizona; |
64 | struct wm_adsp; | 67 | struct wm_adsp; |
65 | 68 | ||
@@ -84,6 +87,10 @@ struct arizona_priv { | |||
84 | 87 | ||
85 | unsigned int spk_ena:2; | 88 | unsigned int spk_ena:2; |
86 | unsigned int spk_ena_pending:1; | 89 | unsigned int spk_ena_pending:1; |
90 | |||
91 | unsigned int dvfs_reqs; | ||
92 | struct mutex dvfs_lock; | ||
93 | bool dvfs_cached; | ||
87 | }; | 94 | }; |
88 | 95 | ||
89 | #define ARIZONA_NUM_MIXER_INPUTS 103 | 96 | #define ARIZONA_NUM_MIXER_INPUTS 103 |
@@ -107,8 +114,8 @@ extern int arizona_mixer_values[ARIZONA_NUM_MIXER_INPUTS]; | |||
107 | arizona_mixer_tlv) | 114 | arizona_mixer_tlv) |
108 | 115 | ||
109 | #define ARIZONA_MUX_ENUM_DECL(name, reg) \ | 116 | #define ARIZONA_MUX_ENUM_DECL(name, reg) \ |
110 | SOC_VALUE_ENUM_SINGLE_DECL(name, reg, 0, 0xff, \ | 117 | SOC_VALUE_ENUM_SINGLE_AUTODISABLE_DECL( \ |
111 | arizona_mixer_texts, arizona_mixer_values) | 118 | name, reg, 0, 0xff, arizona_mixer_texts, arizona_mixer_values) |
112 | 119 | ||
113 | #define ARIZONA_MUX_CTL_DECL(name) \ | 120 | #define ARIZONA_MUX_CTL_DECL(name) \ |
114 | const struct snd_kcontrol_new name##_mux = \ | 121 | const struct snd_kcontrol_new name##_mux = \ |
@@ -245,6 +252,12 @@ struct arizona_fll { | |||
245 | char clock_ok_name[ARIZONA_FLL_NAME_LEN]; | 252 | char clock_ok_name[ARIZONA_FLL_NAME_LEN]; |
246 | }; | 253 | }; |
247 | 254 | ||
255 | extern int arizona_dvfs_up(struct snd_soc_codec *codec, unsigned int flags); | ||
256 | extern int arizona_dvfs_down(struct snd_soc_codec *codec, unsigned int flags); | ||
257 | extern int arizona_dvfs_sysclk_ev(struct snd_soc_dapm_widget *w, | ||
258 | struct snd_kcontrol *kcontrol, int event); | ||
259 | extern void arizona_init_dvfs(struct arizona_priv *priv); | ||
260 | |||
248 | extern int arizona_init_fll(struct arizona *arizona, int id, int base, | 261 | extern int arizona_init_fll(struct arizona *arizona, int id, int base, |
249 | int lock_irq, int ok_irq, struct arizona_fll *fll); | 262 | int lock_irq, int ok_irq, struct arizona_fll *fll); |
250 | extern int arizona_set_fll_refclk(struct arizona_fll *fll, int source, | 263 | extern int arizona_set_fll_refclk(struct arizona_fll *fll, int source, |
diff --git a/sound/soc/codecs/bt-sco.c b/sound/soc/codecs/bt-sco.c index e7238b8904bc..b084ad113e96 100644 --- a/sound/soc/codecs/bt-sco.c +++ b/sound/soc/codecs/bt-sco.c | |||
@@ -63,7 +63,7 @@ static int bt_sco_remove(struct platform_device *pdev) | |||
63 | return 0; | 63 | return 0; |
64 | } | 64 | } |
65 | 65 | ||
66 | static struct platform_device_id bt_sco_driver_ids[] = { | 66 | static const struct platform_device_id bt_sco_driver_ids[] = { |
67 | { | 67 | { |
68 | .name = "dfbmcs320", | 68 | .name = "dfbmcs320", |
69 | }, | 69 | }, |
@@ -74,9 +74,18 @@ static struct platform_device_id bt_sco_driver_ids[] = { | |||
74 | }; | 74 | }; |
75 | MODULE_DEVICE_TABLE(platform, bt_sco_driver_ids); | 75 | MODULE_DEVICE_TABLE(platform, bt_sco_driver_ids); |
76 | 76 | ||
77 | #if defined(CONFIG_OF) | ||
78 | static const struct of_device_id bt_sco_codec_of_match[] = { | ||
79 | { .compatible = "delta,dfbmcs320", }, | ||
80 | {}, | ||
81 | }; | ||
82 | MODULE_DEVICE_TABLE(of, bt_sco_codec_of_match); | ||
83 | #endif | ||
84 | |||
77 | static struct platform_driver bt_sco_driver = { | 85 | static struct platform_driver bt_sco_driver = { |
78 | .driver = { | 86 | .driver = { |
79 | .name = "bt-sco", | 87 | .name = "bt-sco", |
88 | .of_match_table = of_match_ptr(bt_sco_codec_of_match), | ||
80 | }, | 89 | }, |
81 | .probe = bt_sco_probe, | 90 | .probe = bt_sco_probe, |
82 | .remove = bt_sco_remove, | 91 | .remove = bt_sco_remove, |
diff --git a/sound/soc/codecs/cq93vc.c b/sound/soc/codecs/cq93vc.c index d6dedd4eab29..1c895a53001d 100644 --- a/sound/soc/codecs/cq93vc.c +++ b/sound/soc/codecs/cq93vc.c | |||
@@ -92,7 +92,6 @@ static int cq93vc_set_bias_level(struct snd_soc_codec *codec, | |||
92 | DAVINCI_VC_REG12_POWER_ALL_OFF); | 92 | DAVINCI_VC_REG12_POWER_ALL_OFF); |
93 | break; | 93 | break; |
94 | } | 94 | } |
95 | codec->dapm.bias_level = level; | ||
96 | 95 | ||
97 | return 0; | 96 | return 0; |
98 | } | 97 | } |
diff --git a/sound/soc/codecs/cs35l32.c b/sound/soc/codecs/cs35l32.c index 60598b230341..8f40025b7e7c 100644 --- a/sound/soc/codecs/cs35l32.c +++ b/sound/soc/codecs/cs35l32.c | |||
@@ -13,7 +13,6 @@ | |||
13 | 13 | ||
14 | #include <linux/module.h> | 14 | #include <linux/module.h> |
15 | #include <linux/moduleparam.h> | 15 | #include <linux/moduleparam.h> |
16 | #include <linux/version.h> | ||
17 | #include <linux/kernel.h> | 16 | #include <linux/kernel.h> |
18 | #include <linux/init.h> | 17 | #include <linux/init.h> |
19 | #include <linux/delay.h> | 18 | #include <linux/delay.h> |
diff --git a/sound/soc/codecs/cs4265.c b/sound/soc/codecs/cs4265.c index cac48ddf3ba6..d7ec4756e45b 100644 --- a/sound/soc/codecs/cs4265.c +++ b/sound/soc/codecs/cs4265.c | |||
@@ -503,7 +503,6 @@ static int cs4265_set_bias_level(struct snd_soc_codec *codec, | |||
503 | CS4265_PWRCTL_PDN); | 503 | CS4265_PWRCTL_PDN); |
504 | break; | 504 | break; |
505 | } | 505 | } |
506 | codec->dapm.bias_level = level; | ||
507 | return 0; | 506 | return 0; |
508 | } | 507 | } |
509 | 508 | ||
diff --git a/sound/soc/codecs/cs42l52.c b/sound/soc/codecs/cs42l52.c index 1589e7a881d8..4de52c9957ac 100644 --- a/sound/soc/codecs/cs42l52.c +++ b/sound/soc/codecs/cs42l52.c | |||
@@ -897,7 +897,7 @@ static int cs42l52_set_bias_level(struct snd_soc_codec *codec, | |||
897 | CS42L52_PWRCTL1_PDN_CODEC, 0); | 897 | CS42L52_PWRCTL1_PDN_CODEC, 0); |
898 | break; | 898 | break; |
899 | case SND_SOC_BIAS_STANDBY: | 899 | case SND_SOC_BIAS_STANDBY: |
900 | if (codec->dapm.bias_level == SND_SOC_BIAS_OFF) { | 900 | if (snd_soc_codec_get_bias_level(codec) == SND_SOC_BIAS_OFF) { |
901 | regcache_cache_only(cs42l52->regmap, false); | 901 | regcache_cache_only(cs42l52->regmap, false); |
902 | regcache_sync(cs42l52->regmap); | 902 | regcache_sync(cs42l52->regmap); |
903 | } | 903 | } |
@@ -908,7 +908,6 @@ static int cs42l52_set_bias_level(struct snd_soc_codec *codec, | |||
908 | regcache_cache_only(cs42l52->regmap, true); | 908 | regcache_cache_only(cs42l52->regmap, true); |
909 | break; | 909 | break; |
910 | } | 910 | } |
911 | codec->dapm.bias_level = level; | ||
912 | 911 | ||
913 | return 0; | 912 | return 0; |
914 | } | 913 | } |
@@ -956,7 +955,7 @@ static void cs42l52_beep_work(struct work_struct *work) | |||
956 | struct cs42l52_private *cs42l52 = | 955 | struct cs42l52_private *cs42l52 = |
957 | container_of(work, struct cs42l52_private, beep_work); | 956 | container_of(work, struct cs42l52_private, beep_work); |
958 | struct snd_soc_codec *codec = cs42l52->codec; | 957 | struct snd_soc_codec *codec = cs42l52->codec; |
959 | struct snd_soc_dapm_context *dapm = &codec->dapm; | 958 | struct snd_soc_dapm_context *dapm = snd_soc_codec_get_dapm(codec); |
960 | int i; | 959 | int i; |
961 | int val = 0; | 960 | int val = 0; |
962 | int best = 0; | 961 | int best = 0; |
diff --git a/sound/soc/codecs/cs42l56.c b/sound/soc/codecs/cs42l56.c index cbc654fe48c7..1e11ba45a79f 100644 --- a/sound/soc/codecs/cs42l56.c +++ b/sound/soc/codecs/cs42l56.c | |||
@@ -953,7 +953,7 @@ static int cs42l56_set_bias_level(struct snd_soc_codec *codec, | |||
953 | CS42L56_PDN_ALL_MASK, 0); | 953 | CS42L56_PDN_ALL_MASK, 0); |
954 | break; | 954 | break; |
955 | case SND_SOC_BIAS_STANDBY: | 955 | case SND_SOC_BIAS_STANDBY: |
956 | if (codec->dapm.bias_level == SND_SOC_BIAS_OFF) { | 956 | if (snd_soc_codec_get_bias_level(codec) == SND_SOC_BIAS_OFF) { |
957 | regcache_cache_only(cs42l56->regmap, false); | 957 | regcache_cache_only(cs42l56->regmap, false); |
958 | regcache_sync(cs42l56->regmap); | 958 | regcache_sync(cs42l56->regmap); |
959 | ret = regulator_bulk_enable(ARRAY_SIZE(cs42l56->supplies), | 959 | ret = regulator_bulk_enable(ARRAY_SIZE(cs42l56->supplies), |
@@ -978,7 +978,6 @@ static int cs42l56_set_bias_level(struct snd_soc_codec *codec, | |||
978 | cs42l56->supplies); | 978 | cs42l56->supplies); |
979 | break; | 979 | break; |
980 | } | 980 | } |
981 | codec->dapm.bias_level = level; | ||
982 | 981 | ||
983 | return 0; | 982 | return 0; |
984 | } | 983 | } |
@@ -1026,7 +1025,7 @@ static void cs42l56_beep_work(struct work_struct *work) | |||
1026 | struct cs42l56_private *cs42l56 = | 1025 | struct cs42l56_private *cs42l56 = |
1027 | container_of(work, struct cs42l56_private, beep_work); | 1026 | container_of(work, struct cs42l56_private, beep_work); |
1028 | struct snd_soc_codec *codec = cs42l56->codec; | 1027 | struct snd_soc_codec *codec = cs42l56->codec; |
1029 | struct snd_soc_dapm_context *dapm = &codec->dapm; | 1028 | struct snd_soc_dapm_context *dapm = snd_soc_codec_get_dapm(codec); |
1030 | int i; | 1029 | int i; |
1031 | int val = 0; | 1030 | int val = 0; |
1032 | int best = 0; | 1031 | int best = 0; |
diff --git a/sound/soc/codecs/cs42l73.c b/sound/soc/codecs/cs42l73.c index 8ecedba79606..b7853b9d3a60 100644 --- a/sound/soc/codecs/cs42l73.c +++ b/sound/soc/codecs/cs42l73.c | |||
@@ -1208,7 +1208,7 @@ static int cs42l73_set_bias_level(struct snd_soc_codec *codec, | |||
1208 | break; | 1208 | break; |
1209 | 1209 | ||
1210 | case SND_SOC_BIAS_STANDBY: | 1210 | case SND_SOC_BIAS_STANDBY: |
1211 | if (codec->dapm.bias_level == SND_SOC_BIAS_OFF) { | 1211 | if (snd_soc_codec_get_bias_level(codec) == SND_SOC_BIAS_OFF) { |
1212 | regcache_cache_only(cs42l73->regmap, false); | 1212 | regcache_cache_only(cs42l73->regmap, false); |
1213 | regcache_sync(cs42l73->regmap); | 1213 | regcache_sync(cs42l73->regmap); |
1214 | } | 1214 | } |
@@ -1228,7 +1228,6 @@ static int cs42l73_set_bias_level(struct snd_soc_codec *codec, | |||
1228 | snd_soc_update_bits(codec, CS42L73_DMMCC, CS42L73_MCLKDIS, 1); | 1228 | snd_soc_update_bits(codec, CS42L73_DMMCC, CS42L73_MCLKDIS, 1); |
1229 | break; | 1229 | break; |
1230 | } | 1230 | } |
1231 | codec->dapm.bias_level = level; | ||
1232 | return 0; | 1231 | return 0; |
1233 | } | 1232 | } |
1234 | 1233 | ||
diff --git a/sound/soc/codecs/cs42xx8.c b/sound/soc/codecs/cs42xx8.c index 670ebfe12903..e1d46862e81f 100644 --- a/sound/soc/codecs/cs42xx8.c +++ b/sound/soc/codecs/cs42xx8.c | |||
@@ -380,7 +380,7 @@ EXPORT_SYMBOL_GPL(cs42xx8_regmap_config); | |||
380 | static int cs42xx8_codec_probe(struct snd_soc_codec *codec) | 380 | static int cs42xx8_codec_probe(struct snd_soc_codec *codec) |
381 | { | 381 | { |
382 | struct cs42xx8_priv *cs42xx8 = snd_soc_codec_get_drvdata(codec); | 382 | struct cs42xx8_priv *cs42xx8 = snd_soc_codec_get_drvdata(codec); |
383 | struct snd_soc_dapm_context *dapm = &codec->dapm; | 383 | struct snd_soc_dapm_context *dapm = snd_soc_codec_get_dapm(codec); |
384 | 384 | ||
385 | switch (cs42xx8->drvdata->num_adcs) { | 385 | switch (cs42xx8->drvdata->num_adcs) { |
386 | case 3: | 386 | case 3: |
diff --git a/sound/soc/codecs/cx20442.c b/sound/soc/codecs/cx20442.c index 0f334bc1b63c..d6f4abbbf8a7 100644 --- a/sound/soc/codecs/cx20442.c +++ b/sound/soc/codecs/cx20442.c | |||
@@ -333,7 +333,7 @@ static int cx20442_set_bias_level(struct snd_soc_codec *codec, | |||
333 | 333 | ||
334 | switch (level) { | 334 | switch (level) { |
335 | case SND_SOC_BIAS_PREPARE: | 335 | case SND_SOC_BIAS_PREPARE: |
336 | if (codec->dapm.bias_level != SND_SOC_BIAS_STANDBY) | 336 | if (snd_soc_codec_get_bias_level(codec) != SND_SOC_BIAS_STANDBY) |
337 | break; | 337 | break; |
338 | if (IS_ERR(cx20442->por)) | 338 | if (IS_ERR(cx20442->por)) |
339 | err = PTR_ERR(cx20442->por); | 339 | err = PTR_ERR(cx20442->por); |
@@ -341,7 +341,7 @@ static int cx20442_set_bias_level(struct snd_soc_codec *codec, | |||
341 | err = regulator_enable(cx20442->por); | 341 | err = regulator_enable(cx20442->por); |
342 | break; | 342 | break; |
343 | case SND_SOC_BIAS_STANDBY: | 343 | case SND_SOC_BIAS_STANDBY: |
344 | if (codec->dapm.bias_level != SND_SOC_BIAS_PREPARE) | 344 | if (snd_soc_codec_get_bias_level(codec) != SND_SOC_BIAS_PREPARE) |
345 | break; | 345 | break; |
346 | if (IS_ERR(cx20442->por)) | 346 | if (IS_ERR(cx20442->por)) |
347 | err = PTR_ERR(cx20442->por); | 347 | err = PTR_ERR(cx20442->por); |
@@ -351,8 +351,6 @@ static int cx20442_set_bias_level(struct snd_soc_codec *codec, | |||
351 | default: | 351 | default: |
352 | break; | 352 | break; |
353 | } | 353 | } |
354 | if (!err) | ||
355 | codec->dapm.bias_level = level; | ||
356 | 354 | ||
357 | return err; | 355 | return err; |
358 | } | 356 | } |
diff --git a/sound/soc/codecs/da7213.c b/sound/soc/codecs/da7213.c index 9ec577f0edb4..238e48a3a4fe 100644 --- a/sound/soc/codecs/da7213.c +++ b/sound/soc/codecs/da7213.c | |||
@@ -1374,7 +1374,7 @@ static int da7213_set_bias_level(struct snd_soc_codec *codec, | |||
1374 | case SND_SOC_BIAS_PREPARE: | 1374 | case SND_SOC_BIAS_PREPARE: |
1375 | break; | 1375 | break; |
1376 | case SND_SOC_BIAS_STANDBY: | 1376 | case SND_SOC_BIAS_STANDBY: |
1377 | if (codec->dapm.bias_level == SND_SOC_BIAS_OFF) { | 1377 | if (snd_soc_codec_get_bias_level(codec) == SND_SOC_BIAS_OFF) { |
1378 | /* Enable VMID reference & master bias */ | 1378 | /* Enable VMID reference & master bias */ |
1379 | snd_soc_update_bits(codec, DA7213_REFERENCES, | 1379 | snd_soc_update_bits(codec, DA7213_REFERENCES, |
1380 | DA7213_VMID_EN | DA7213_BIAS_EN, | 1380 | DA7213_VMID_EN | DA7213_BIAS_EN, |
@@ -1387,7 +1387,6 @@ static int da7213_set_bias_level(struct snd_soc_codec *codec, | |||
1387 | DA7213_VMID_EN | DA7213_BIAS_EN, 0); | 1387 | DA7213_VMID_EN | DA7213_BIAS_EN, 0); |
1388 | break; | 1388 | break; |
1389 | } | 1389 | } |
1390 | codec->dapm.bias_level = level; | ||
1391 | return 0; | 1390 | return 0; |
1392 | } | 1391 | } |
1393 | 1392 | ||
diff --git a/sound/soc/codecs/da732x.c b/sound/soc/codecs/da732x.c index 911c26c705fc..207523686bd5 100644 --- a/sound/soc/codecs/da732x.c +++ b/sound/soc/codecs/da732x.c | |||
@@ -1432,7 +1432,7 @@ static int da732x_set_bias_level(struct snd_soc_codec *codec, | |||
1432 | case SND_SOC_BIAS_PREPARE: | 1432 | case SND_SOC_BIAS_PREPARE: |
1433 | break; | 1433 | break; |
1434 | case SND_SOC_BIAS_STANDBY: | 1434 | case SND_SOC_BIAS_STANDBY: |
1435 | if (codec->dapm.bias_level == SND_SOC_BIAS_OFF) { | 1435 | if (snd_soc_codec_get_bias_level(codec) == SND_SOC_BIAS_OFF) { |
1436 | /* Init Codec */ | 1436 | /* Init Codec */ |
1437 | snd_soc_write(codec, DA732X_REG_REF1, | 1437 | snd_soc_write(codec, DA732X_REG_REF1, |
1438 | DA732X_VMID_FASTCHG); | 1438 | DA732X_VMID_FASTCHG); |
@@ -1502,8 +1502,6 @@ static int da732x_set_bias_level(struct snd_soc_codec *codec, | |||
1502 | break; | 1502 | break; |
1503 | } | 1503 | } |
1504 | 1504 | ||
1505 | codec->dapm.bias_level = level; | ||
1506 | |||
1507 | return 0; | 1505 | return 0; |
1508 | } | 1506 | } |
1509 | 1507 | ||
diff --git a/sound/soc/codecs/da9055.c b/sound/soc/codecs/da9055.c index ad19cc56702b..66bb446473b8 100644 --- a/sound/soc/codecs/da9055.c +++ b/sound/soc/codecs/da9055.c | |||
@@ -1364,7 +1364,7 @@ static int da9055_set_bias_level(struct snd_soc_codec *codec, | |||
1364 | case SND_SOC_BIAS_PREPARE: | 1364 | case SND_SOC_BIAS_PREPARE: |
1365 | break; | 1365 | break; |
1366 | case SND_SOC_BIAS_STANDBY: | 1366 | case SND_SOC_BIAS_STANDBY: |
1367 | if (codec->dapm.bias_level == SND_SOC_BIAS_OFF) { | 1367 | if (snd_soc_codec_get_bias_level(codec) == SND_SOC_BIAS_OFF) { |
1368 | /* Enable VMID reference & master bias */ | 1368 | /* Enable VMID reference & master bias */ |
1369 | snd_soc_update_bits(codec, DA9055_REFERENCES, | 1369 | snd_soc_update_bits(codec, DA9055_REFERENCES, |
1370 | DA9055_VMID_EN | DA9055_BIAS_EN, | 1370 | DA9055_VMID_EN | DA9055_BIAS_EN, |
@@ -1377,7 +1377,6 @@ static int da9055_set_bias_level(struct snd_soc_codec *codec, | |||
1377 | DA9055_VMID_EN | DA9055_BIAS_EN, 0); | 1377 | DA9055_VMID_EN | DA9055_BIAS_EN, 0); |
1378 | break; | 1378 | break; |
1379 | } | 1379 | } |
1380 | codec->dapm.bias_level = level; | ||
1381 | return 0; | 1380 | return 0; |
1382 | } | 1381 | } |
1383 | 1382 | ||
diff --git a/sound/soc/codecs/es8328.c b/sound/soc/codecs/es8328.c index c5f35a07e8e4..6a091016e0fc 100644 --- a/sound/soc/codecs/es8328.c +++ b/sound/soc/codecs/es8328.c | |||
@@ -536,7 +536,7 @@ static int es8328_set_bias_level(struct snd_soc_codec *codec, | |||
536 | break; | 536 | break; |
537 | 537 | ||
538 | case SND_SOC_BIAS_STANDBY: | 538 | case SND_SOC_BIAS_STANDBY: |
539 | if (codec->dapm.bias_level == SND_SOC_BIAS_OFF) { | 539 | if (snd_soc_codec_get_bias_level(codec) == SND_SOC_BIAS_OFF) { |
540 | snd_soc_update_bits(codec, ES8328_CONTROL1, | 540 | snd_soc_update_bits(codec, ES8328_CONTROL1, |
541 | ES8328_CONTROL1_VMIDSEL_MASK | | 541 | ES8328_CONTROL1_VMIDSEL_MASK | |
542 | ES8328_CONTROL1_ENREF, | 542 | ES8328_CONTROL1_ENREF, |
@@ -566,7 +566,6 @@ static int es8328_set_bias_level(struct snd_soc_codec *codec, | |||
566 | 0); | 566 | 0); |
567 | break; | 567 | break; |
568 | } | 568 | } |
569 | codec->dapm.bias_level = level; | ||
570 | return 0; | 569 | return 0; |
571 | } | 570 | } |
572 | 571 | ||
diff --git a/sound/soc/codecs/isabelle.c b/sound/soc/codecs/isabelle.c index 3a89ce66d51d..ebd90283c960 100644 --- a/sound/soc/codecs/isabelle.c +++ b/sound/soc/codecs/isabelle.c | |||
@@ -909,8 +909,6 @@ static int isabelle_set_bias_level(struct snd_soc_codec *codec, | |||
909 | break; | 909 | break; |
910 | } | 910 | } |
911 | 911 | ||
912 | codec->dapm.bias_level = level; | ||
913 | |||
914 | return 0; | 912 | return 0; |
915 | } | 913 | } |
916 | 914 | ||
diff --git a/sound/soc/codecs/jz4740.c b/sound/soc/codecs/jz4740.c index 933f4476d76c..9363fdbca9cd 100644 --- a/sound/soc/codecs/jz4740.c +++ b/sound/soc/codecs/jz4740.c | |||
@@ -258,7 +258,7 @@ static int jz4740_codec_set_bias_level(struct snd_soc_codec *codec, | |||
258 | break; | 258 | break; |
259 | case SND_SOC_BIAS_STANDBY: | 259 | case SND_SOC_BIAS_STANDBY: |
260 | /* The only way to clear the suspend flag is to reset the codec */ | 260 | /* The only way to clear the suspend flag is to reset the codec */ |
261 | if (codec->dapm.bias_level == SND_SOC_BIAS_OFF) | 261 | if (snd_soc_codec_get_bias_level(codec) == SND_SOC_BIAS_OFF) |
262 | jz4740_codec_wakeup(regmap); | 262 | jz4740_codec_wakeup(regmap); |
263 | 263 | ||
264 | mask = JZ4740_CODEC_1_VREF_DISABLE | | 264 | mask = JZ4740_CODEC_1_VREF_DISABLE | |
@@ -281,8 +281,6 @@ static int jz4740_codec_set_bias_level(struct snd_soc_codec *codec, | |||
281 | break; | 281 | break; |
282 | } | 282 | } |
283 | 283 | ||
284 | codec->dapm.bias_level = level; | ||
285 | |||
286 | return 0; | 284 | return 0; |
287 | } | 285 | } |
288 | 286 | ||
diff --git a/sound/soc/codecs/lm4857.c b/sound/soc/codecs/lm4857.c index a924bb9d7886..99ffc49aa779 100644 --- a/sound/soc/codecs/lm4857.c +++ b/sound/soc/codecs/lm4857.c | |||
@@ -23,11 +23,6 @@ | |||
23 | #include <sound/soc.h> | 23 | #include <sound/soc.h> |
24 | #include <sound/tlv.h> | 24 | #include <sound/tlv.h> |
25 | 25 | ||
26 | struct lm4857 { | ||
27 | struct regmap *regmap; | ||
28 | uint8_t mode; | ||
29 | }; | ||
30 | |||
31 | static const struct reg_default lm4857_default_regs[] = { | 26 | static const struct reg_default lm4857_default_regs[] = { |
32 | { 0x0, 0x00 }, | 27 | { 0x0, 0x00 }, |
33 | { 0x1, 0x00 }, | 28 | { 0x1, 0x00 }, |
@@ -46,66 +41,33 @@ static const struct reg_default lm4857_default_regs[] = { | |||
46 | #define LM4857_WAKEUP 5 | 41 | #define LM4857_WAKEUP 5 |
47 | #define LM4857_EPGAIN 4 | 42 | #define LM4857_EPGAIN 4 |
48 | 43 | ||
49 | static int lm4857_get_mode(struct snd_kcontrol *kcontrol, | 44 | static const unsigned int lm4857_mode_values[] = { |
50 | struct snd_ctl_elem_value *ucontrol) | 45 | 0, |
51 | { | 46 | 6, |
52 | struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol); | 47 | 7, |
53 | struct lm4857 *lm4857 = snd_soc_codec_get_drvdata(codec); | 48 | 8, |
54 | 49 | 9, | |
55 | ucontrol->value.integer.value[0] = lm4857->mode; | 50 | }; |
56 | |||
57 | return 0; | ||
58 | } | ||
59 | |||
60 | static int lm4857_set_mode(struct snd_kcontrol *kcontrol, | ||
61 | struct snd_ctl_elem_value *ucontrol) | ||
62 | { | ||
63 | struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol); | ||
64 | struct lm4857 *lm4857 = snd_soc_codec_get_drvdata(codec); | ||
65 | uint8_t value = ucontrol->value.integer.value[0]; | ||
66 | |||
67 | lm4857->mode = value; | ||
68 | |||
69 | if (codec->dapm.bias_level == SND_SOC_BIAS_ON) | ||
70 | regmap_update_bits(lm4857->regmap, LM4857_CTRL, 0x0F, value + 6); | ||
71 | |||
72 | return 1; | ||
73 | } | ||
74 | |||
75 | static int lm4857_set_bias_level(struct snd_soc_codec *codec, | ||
76 | enum snd_soc_bias_level level) | ||
77 | { | ||
78 | struct lm4857 *lm4857 = snd_soc_codec_get_drvdata(codec); | ||
79 | |||
80 | switch (level) { | ||
81 | case SND_SOC_BIAS_ON: | ||
82 | regmap_update_bits(lm4857->regmap, LM4857_CTRL, 0x0F, | ||
83 | lm4857->mode + 6); | ||
84 | break; | ||
85 | case SND_SOC_BIAS_STANDBY: | ||
86 | regmap_update_bits(lm4857->regmap, LM4857_CTRL, 0x0F, 0); | ||
87 | break; | ||
88 | default: | ||
89 | break; | ||
90 | } | ||
91 | |||
92 | codec->dapm.bias_level = level; | ||
93 | |||
94 | return 0; | ||
95 | } | ||
96 | 51 | ||
97 | static const char *lm4857_mode[] = { | 52 | static const char * const lm4857_mode_texts[] = { |
53 | "Off", | ||
98 | "Earpiece", | 54 | "Earpiece", |
99 | "Loudspeaker", | 55 | "Loudspeaker", |
100 | "Loudspeaker + Headphone", | 56 | "Loudspeaker + Headphone", |
101 | "Headphone", | 57 | "Headphone", |
102 | }; | 58 | }; |
103 | 59 | ||
104 | static SOC_ENUM_SINGLE_EXT_DECL(lm4857_mode_enum, lm4857_mode); | 60 | static SOC_VALUE_ENUM_SINGLE_AUTODISABLE_DECL(lm4857_mode_enum, |
61 | LM4857_CTRL, 0, 0xf, lm4857_mode_texts, lm4857_mode_values); | ||
62 | |||
63 | static const struct snd_kcontrol_new lm4857_mode_ctrl = | ||
64 | SOC_DAPM_ENUM("Mode", lm4857_mode_enum); | ||
105 | 65 | ||
106 | static const struct snd_soc_dapm_widget lm4857_dapm_widgets[] = { | 66 | static const struct snd_soc_dapm_widget lm4857_dapm_widgets[] = { |
107 | SND_SOC_DAPM_INPUT("IN"), | 67 | SND_SOC_DAPM_INPUT("IN"), |
108 | 68 | ||
69 | SND_SOC_DAPM_DEMUX("Mode", SND_SOC_NOPM, 0, 0, &lm4857_mode_ctrl), | ||
70 | |||
109 | SND_SOC_DAPM_OUTPUT("LS"), | 71 | SND_SOC_DAPM_OUTPUT("LS"), |
110 | SND_SOC_DAPM_OUTPUT("HP"), | 72 | SND_SOC_DAPM_OUTPUT("HP"), |
111 | SND_SOC_DAPM_OUTPUT("EP"), | 73 | SND_SOC_DAPM_OUTPUT("EP"), |
@@ -127,24 +89,18 @@ static const struct snd_kcontrol_new lm4857_controls[] = { | |||
127 | LM4857_WAKEUP, 1, 0), | 89 | LM4857_WAKEUP, 1, 0), |
128 | SOC_SINGLE("Earpiece 6dB Playback Switch", LM4857_CTRL, | 90 | SOC_SINGLE("Earpiece 6dB Playback Switch", LM4857_CTRL, |
129 | LM4857_EPGAIN, 1, 0), | 91 | LM4857_EPGAIN, 1, 0), |
130 | |||
131 | SOC_ENUM_EXT("Mode", lm4857_mode_enum, | ||
132 | lm4857_get_mode, lm4857_set_mode), | ||
133 | }; | 92 | }; |
134 | 93 | ||
135 | /* There is a demux between the input signal and the output signals. | ||
136 | * Currently there is no easy way to model it in ASoC and since it does not make | ||
137 | * much of a difference in practice simply connect the input direclty to the | ||
138 | * outputs. */ | ||
139 | static const struct snd_soc_dapm_route lm4857_routes[] = { | 94 | static const struct snd_soc_dapm_route lm4857_routes[] = { |
140 | {"LS", NULL, "IN"}, | 95 | { "Mode", NULL, "IN" }, |
141 | {"HP", NULL, "IN"}, | 96 | { "LS", "Loudspeaker", "Mode" }, |
142 | {"EP", NULL, "IN"}, | 97 | { "LS", "Loudspeaker + Headphone", "Mode" }, |
98 | { "HP", "Headphone", "Mode" }, | ||
99 | { "HP", "Loudspeaker + Headphone", "Mode" }, | ||
100 | { "EP", "Earpiece", "Mode" }, | ||
143 | }; | 101 | }; |
144 | 102 | ||
145 | static struct snd_soc_codec_driver soc_codec_dev_lm4857 = { | 103 | static struct snd_soc_component_driver lm4857_component_driver = { |
146 | .set_bias_level = lm4857_set_bias_level, | ||
147 | |||
148 | .controls = lm4857_controls, | 104 | .controls = lm4857_controls, |
149 | .num_controls = ARRAY_SIZE(lm4857_controls), | 105 | .num_controls = ARRAY_SIZE(lm4857_controls), |
150 | .dapm_widgets = lm4857_dapm_widgets, | 106 | .dapm_widgets = lm4857_dapm_widgets, |
@@ -167,25 +123,14 @@ static const struct regmap_config lm4857_regmap_config = { | |||
167 | static int lm4857_i2c_probe(struct i2c_client *i2c, | 123 | static int lm4857_i2c_probe(struct i2c_client *i2c, |
168 | const struct i2c_device_id *id) | 124 | const struct i2c_device_id *id) |
169 | { | 125 | { |
170 | struct lm4857 *lm4857; | 126 | struct regmap *regmap; |
171 | |||
172 | lm4857 = devm_kzalloc(&i2c->dev, sizeof(*lm4857), GFP_KERNEL); | ||
173 | if (!lm4857) | ||
174 | return -ENOMEM; | ||
175 | |||
176 | i2c_set_clientdata(i2c, lm4857); | ||
177 | |||
178 | lm4857->regmap = devm_regmap_init_i2c(i2c, &lm4857_regmap_config); | ||
179 | if (IS_ERR(lm4857->regmap)) | ||
180 | return PTR_ERR(lm4857->regmap); | ||
181 | 127 | ||
182 | return snd_soc_register_codec(&i2c->dev, &soc_codec_dev_lm4857, NULL, 0); | 128 | regmap = devm_regmap_init_i2c(i2c, &lm4857_regmap_config); |
183 | } | 129 | if (IS_ERR(regmap)) |
130 | return PTR_ERR(regmap); | ||
184 | 131 | ||
185 | static int lm4857_i2c_remove(struct i2c_client *i2c) | 132 | return devm_snd_soc_register_component(&i2c->dev, |
186 | { | 133 | &lm4857_component_driver, NULL, 0); |
187 | snd_soc_unregister_codec(&i2c->dev); | ||
188 | return 0; | ||
189 | } | 134 | } |
190 | 135 | ||
191 | static const struct i2c_device_id lm4857_i2c_id[] = { | 136 | static const struct i2c_device_id lm4857_i2c_id[] = { |
@@ -200,7 +145,6 @@ static struct i2c_driver lm4857_i2c_driver = { | |||
200 | .owner = THIS_MODULE, | 145 | .owner = THIS_MODULE, |
201 | }, | 146 | }, |
202 | .probe = lm4857_i2c_probe, | 147 | .probe = lm4857_i2c_probe, |
203 | .remove = lm4857_i2c_remove, | ||
204 | .id_table = lm4857_i2c_id, | 148 | .id_table = lm4857_i2c_id, |
205 | }; | 149 | }; |
206 | 150 | ||
diff --git a/sound/soc/codecs/lm49453.c b/sound/soc/codecs/lm49453.c index c4dfde9bdf1c..6600aa0a33dc 100644 --- a/sound/soc/codecs/lm49453.c +++ b/sound/soc/codecs/lm49453.c | |||
@@ -1271,7 +1271,7 @@ static int lm49453_set_bias_level(struct snd_soc_codec *codec, | |||
1271 | break; | 1271 | break; |
1272 | 1272 | ||
1273 | case SND_SOC_BIAS_STANDBY: | 1273 | case SND_SOC_BIAS_STANDBY: |
1274 | if (codec->dapm.bias_level == SND_SOC_BIAS_OFF) | 1274 | if (snd_soc_codec_get_bias_level(codec) == SND_SOC_BIAS_OFF) |
1275 | regcache_sync(lm49453->regmap); | 1275 | regcache_sync(lm49453->regmap); |
1276 | 1276 | ||
1277 | snd_soc_update_bits(codec, LM49453_P0_PMC_SETUP_REG, | 1277 | snd_soc_update_bits(codec, LM49453_P0_PMC_SETUP_REG, |
@@ -1284,8 +1284,6 @@ static int lm49453_set_bias_level(struct snd_soc_codec *codec, | |||
1284 | break; | 1284 | break; |
1285 | } | 1285 | } |
1286 | 1286 | ||
1287 | codec->dapm.bias_level = level; | ||
1288 | |||
1289 | return 0; | 1287 | return 0; |
1290 | } | 1288 | } |
1291 | 1289 | ||
diff --git a/sound/soc/codecs/max98088.c b/sound/soc/codecs/max98088.c index 805b3f8cd39d..d0f45348bfbb 100644 --- a/sound/soc/codecs/max98088.c +++ b/sound/soc/codecs/max98088.c | |||
@@ -1571,7 +1571,7 @@ static int max98088_set_bias_level(struct snd_soc_codec *codec, | |||
1571 | break; | 1571 | break; |
1572 | 1572 | ||
1573 | case SND_SOC_BIAS_STANDBY: | 1573 | case SND_SOC_BIAS_STANDBY: |
1574 | if (codec->dapm.bias_level == SND_SOC_BIAS_OFF) | 1574 | if (snd_soc_codec_get_bias_level(codec) == SND_SOC_BIAS_OFF) |
1575 | regcache_sync(max98088->regmap); | 1575 | regcache_sync(max98088->regmap); |
1576 | 1576 | ||
1577 | snd_soc_update_bits(codec, M98088_REG_4C_PWR_EN_IN, | 1577 | snd_soc_update_bits(codec, M98088_REG_4C_PWR_EN_IN, |
@@ -1584,7 +1584,6 @@ static int max98088_set_bias_level(struct snd_soc_codec *codec, | |||
1584 | regcache_mark_dirty(max98088->regmap); | 1584 | regcache_mark_dirty(max98088->regmap); |
1585 | break; | 1585 | break; |
1586 | } | 1586 | } |
1587 | codec->dapm.bias_level = level; | ||
1588 | return 0; | 1587 | return 0; |
1589 | } | 1588 | } |
1590 | 1589 | ||
diff --git a/sound/soc/codecs/max98090.c b/sound/soc/codecs/max98090.c index 3e33ef2acf3c..78268f0514e9 100644 --- a/sound/soc/codecs/max98090.c +++ b/sound/soc/codecs/max98090.c | |||
@@ -27,7 +27,7 @@ | |||
27 | #include "max98090.h" | 27 | #include "max98090.h" |
28 | 28 | ||
29 | /* Allows for sparsely populated register maps */ | 29 | /* Allows for sparsely populated register maps */ |
30 | static struct reg_default max98090_reg[] = { | 30 | static const struct reg_default max98090_reg[] = { |
31 | { 0x00, 0x00 }, /* 00 Software Reset */ | 31 | { 0x00, 0x00 }, /* 00 Software Reset */ |
32 | { 0x03, 0x04 }, /* 03 Interrupt Masks */ | 32 | { 0x03, 0x04 }, /* 03 Interrupt Masks */ |
33 | { 0x04, 0x00 }, /* 04 System Clock Quick */ | 33 | { 0x04, 0x00 }, /* 04 System Clock Quick */ |
@@ -1500,7 +1500,7 @@ static const struct snd_soc_dapm_route max98091_dapm_routes[] = { | |||
1500 | static int max98090_add_widgets(struct snd_soc_codec *codec) | 1500 | static int max98090_add_widgets(struct snd_soc_codec *codec) |
1501 | { | 1501 | { |
1502 | struct max98090_priv *max98090 = snd_soc_codec_get_drvdata(codec); | 1502 | struct max98090_priv *max98090 = snd_soc_codec_get_drvdata(codec); |
1503 | struct snd_soc_dapm_context *dapm = &codec->dapm; | 1503 | struct snd_soc_dapm_context *dapm = snd_soc_codec_get_dapm(codec); |
1504 | 1504 | ||
1505 | snd_soc_add_codec_controls(codec, max98090_snd_controls, | 1505 | snd_soc_add_codec_controls(codec, max98090_snd_controls, |
1506 | ARRAY_SIZE(max98090_snd_controls)); | 1506 | ARRAY_SIZE(max98090_snd_controls)); |
@@ -1798,16 +1798,17 @@ static int max98090_set_bias_level(struct snd_soc_codec *codec, | |||
1798 | * away from ON. Disable the clock in that case, otherwise | 1798 | * away from ON. Disable the clock in that case, otherwise |
1799 | * enable it. | 1799 | * enable it. |
1800 | */ | 1800 | */ |
1801 | if (!IS_ERR(max98090->mclk)) { | 1801 | if (IS_ERR(max98090->mclk)) |
1802 | if (codec->dapm.bias_level == SND_SOC_BIAS_ON) | 1802 | break; |
1803 | clk_disable_unprepare(max98090->mclk); | 1803 | |
1804 | else | 1804 | if (snd_soc_codec_get_bias_level(codec) == SND_SOC_BIAS_ON) |
1805 | clk_prepare_enable(max98090->mclk); | 1805 | clk_disable_unprepare(max98090->mclk); |
1806 | } | 1806 | else |
1807 | clk_prepare_enable(max98090->mclk); | ||
1807 | break; | 1808 | break; |
1808 | 1809 | ||
1809 | case SND_SOC_BIAS_STANDBY: | 1810 | case SND_SOC_BIAS_STANDBY: |
1810 | if (codec->dapm.bias_level == SND_SOC_BIAS_OFF) { | 1811 | if (snd_soc_codec_get_bias_level(codec) == SND_SOC_BIAS_OFF) { |
1811 | ret = regcache_sync(max98090->regmap); | 1812 | ret = regcache_sync(max98090->regmap); |
1812 | if (ret != 0) { | 1813 | if (ret != 0) { |
1813 | dev_err(codec->dev, | 1814 | dev_err(codec->dev, |
@@ -1824,7 +1825,6 @@ static int max98090_set_bias_level(struct snd_soc_codec *codec, | |||
1824 | regcache_mark_dirty(max98090->regmap); | 1825 | regcache_mark_dirty(max98090->regmap); |
1825 | break; | 1826 | break; |
1826 | } | 1827 | } |
1827 | codec->dapm.bias_level = level; | ||
1828 | return 0; | 1828 | return 0; |
1829 | } | 1829 | } |
1830 | 1830 | ||
@@ -2187,7 +2187,6 @@ static void max98090_jack_work(struct work_struct *work) | |||
2187 | struct max98090_priv, | 2187 | struct max98090_priv, |
2188 | jack_work.work); | 2188 | jack_work.work); |
2189 | struct snd_soc_codec *codec = max98090->codec; | 2189 | struct snd_soc_codec *codec = max98090->codec; |
2190 | struct snd_soc_dapm_context *dapm = &codec->dapm; | ||
2191 | int status = 0; | 2190 | int status = 0; |
2192 | int reg; | 2191 | int reg; |
2193 | 2192 | ||
@@ -2266,8 +2265,6 @@ static void max98090_jack_work(struct work_struct *work) | |||
2266 | 2265 | ||
2267 | snd_soc_jack_report(max98090->jack, status, | 2266 | snd_soc_jack_report(max98090->jack, status, |
2268 | SND_JACK_HEADSET | SND_JACK_BTN_0); | 2267 | SND_JACK_HEADSET | SND_JACK_BTN_0); |
2269 | |||
2270 | snd_soc_dapm_sync(dapm); | ||
2271 | } | 2268 | } |
2272 | 2269 | ||
2273 | static irqreturn_t max98090_interrupt(int irq, void *data) | 2270 | static irqreturn_t max98090_interrupt(int irq, void *data) |
@@ -2422,6 +2419,8 @@ static int max98090_probe(struct snd_soc_codec *codec) | |||
2422 | struct max98090_cdata *cdata; | 2419 | struct max98090_cdata *cdata; |
2423 | enum max98090_type devtype; | 2420 | enum max98090_type devtype; |
2424 | int ret = 0; | 2421 | int ret = 0; |
2422 | int err; | ||
2423 | unsigned int micbias; | ||
2425 | 2424 | ||
2426 | dev_dbg(codec->dev, "max98090_probe\n"); | 2425 | dev_dbg(codec->dev, "max98090_probe\n"); |
2427 | 2426 | ||
@@ -2506,8 +2505,17 @@ static int max98090_probe(struct snd_soc_codec *codec) | |||
2506 | snd_soc_write(codec, M98090_REG_BIAS_CONTROL, | 2505 | snd_soc_write(codec, M98090_REG_BIAS_CONTROL, |
2507 | M98090_VCM_MODE_MASK); | 2506 | M98090_VCM_MODE_MASK); |
2508 | 2507 | ||
2508 | err = device_property_read_u32(codec->dev, "maxim,micbias", &micbias); | ||
2509 | if (err) { | ||
2510 | micbias = M98090_MBVSEL_2V8; | ||
2511 | dev_info(codec->dev, "use default 2.8v micbias\n"); | ||
2512 | } else if (micbias < M98090_MBVSEL_2V2 || micbias > M98090_MBVSEL_2V8) { | ||
2513 | dev_err(codec->dev, "micbias out of range 0x%x\n", micbias); | ||
2514 | micbias = M98090_MBVSEL_2V8; | ||
2515 | } | ||
2516 | |||
2509 | snd_soc_update_bits(codec, M98090_REG_MIC_BIAS_VOLTAGE, | 2517 | snd_soc_update_bits(codec, M98090_REG_MIC_BIAS_VOLTAGE, |
2510 | M98090_MBVSEL_MASK, M98090_MBVSEL_2V8); | 2518 | M98090_MBVSEL_MASK, micbias); |
2511 | 2519 | ||
2512 | max98090_add_widgets(codec); | 2520 | max98090_add_widgets(codec); |
2513 | 2521 | ||
@@ -2696,7 +2704,7 @@ static const struct of_device_id max98090_of_match[] = { | |||
2696 | MODULE_DEVICE_TABLE(of, max98090_of_match); | 2704 | MODULE_DEVICE_TABLE(of, max98090_of_match); |
2697 | 2705 | ||
2698 | #ifdef CONFIG_ACPI | 2706 | #ifdef CONFIG_ACPI |
2699 | static struct acpi_device_id max98090_acpi_match[] = { | 2707 | static const struct acpi_device_id max98090_acpi_match[] = { |
2700 | { "193C9890", MAX98090 }, | 2708 | { "193C9890", MAX98090 }, |
2701 | { } | 2709 | { } |
2702 | }; | 2710 | }; |
diff --git a/sound/soc/codecs/max98095.c b/sound/soc/codecs/max98095.c index 8fba0c3db798..9a46d3dcf703 100644 --- a/sound/soc/codecs/max98095.c +++ b/sound/soc/codecs/max98095.c | |||
@@ -1650,16 +1650,17 @@ static int max98095_set_bias_level(struct snd_soc_codec *codec, | |||
1650 | * away from ON. Disable the clock in that case, otherwise | 1650 | * away from ON. Disable the clock in that case, otherwise |
1651 | * enable it. | 1651 | * enable it. |
1652 | */ | 1652 | */ |
1653 | if (!IS_ERR(max98095->mclk)) { | 1653 | if (IS_ERR(max98095->mclk)) |
1654 | if (codec->dapm.bias_level == SND_SOC_BIAS_ON) | 1654 | break; |
1655 | clk_disable_unprepare(max98095->mclk); | 1655 | |
1656 | else | 1656 | if (snd_soc_codec_get_bias_level(codec) == SND_SOC_BIAS_ON) |
1657 | clk_prepare_enable(max98095->mclk); | 1657 | clk_disable_unprepare(max98095->mclk); |
1658 | } | 1658 | else |
1659 | clk_prepare_enable(max98095->mclk); | ||
1659 | break; | 1660 | break; |
1660 | 1661 | ||
1661 | case SND_SOC_BIAS_STANDBY: | 1662 | case SND_SOC_BIAS_STANDBY: |
1662 | if (codec->dapm.bias_level == SND_SOC_BIAS_OFF) { | 1663 | if (snd_soc_codec_get_bias_level(codec) == SND_SOC_BIAS_OFF) { |
1663 | ret = regcache_sync(max98095->regmap); | 1664 | ret = regcache_sync(max98095->regmap); |
1664 | 1665 | ||
1665 | if (ret != 0) { | 1666 | if (ret != 0) { |
@@ -1678,7 +1679,6 @@ static int max98095_set_bias_level(struct snd_soc_codec *codec, | |||
1678 | regcache_mark_dirty(max98095->regmap); | 1679 | regcache_mark_dirty(max98095->regmap); |
1679 | break; | 1680 | break; |
1680 | } | 1681 | } |
1681 | codec->dapm.bias_level = level; | ||
1682 | return 0; | 1682 | return 0; |
1683 | } | 1683 | } |
1684 | 1684 | ||
@@ -2198,7 +2198,7 @@ static int max98095_suspend(struct snd_soc_codec *codec) | |||
2198 | if (max98095->headphone_jack || max98095->mic_jack) | 2198 | if (max98095->headphone_jack || max98095->mic_jack) |
2199 | max98095_jack_detect_disable(codec); | 2199 | max98095_jack_detect_disable(codec); |
2200 | 2200 | ||
2201 | max98095_set_bias_level(codec, SND_SOC_BIAS_OFF); | 2201 | snd_soc_codec_force_bias_level(codec, SND_SOC_BIAS_OFF); |
2202 | 2202 | ||
2203 | return 0; | 2203 | return 0; |
2204 | } | 2204 | } |
@@ -2208,7 +2208,7 @@ static int max98095_resume(struct snd_soc_codec *codec) | |||
2208 | struct max98095_priv *max98095 = snd_soc_codec_get_drvdata(codec); | 2208 | struct max98095_priv *max98095 = snd_soc_codec_get_drvdata(codec); |
2209 | struct i2c_client *client = to_i2c_client(codec->dev); | 2209 | struct i2c_client *client = to_i2c_client(codec->dev); |
2210 | 2210 | ||
2211 | max98095_set_bias_level(codec, SND_SOC_BIAS_STANDBY); | 2211 | snd_soc_codec_force_bias_level(codec, SND_SOC_BIAS_STANDBY); |
2212 | 2212 | ||
2213 | if (max98095->headphone_jack || max98095->mic_jack) { | 2213 | if (max98095->headphone_jack || max98095->mic_jack) { |
2214 | max98095_jack_detect_enable(codec); | 2214 | max98095_jack_detect_enable(codec); |
@@ -2301,8 +2301,8 @@ static int max98095_probe(struct snd_soc_codec *codec) | |||
2301 | /* register an audio interrupt */ | 2301 | /* register an audio interrupt */ |
2302 | ret = request_threaded_irq(client->irq, NULL, | 2302 | ret = request_threaded_irq(client->irq, NULL, |
2303 | max98095_report_jack, | 2303 | max98095_report_jack, |
2304 | IRQF_TRIGGER_FALLING | IRQF_TRIGGER_RISING, | 2304 | IRQF_TRIGGER_FALLING | IRQF_TRIGGER_RISING | |
2305 | "max98095", codec); | 2305 | IRQF_ONESHOT, "max98095", codec); |
2306 | if (ret) { | 2306 | if (ret) { |
2307 | dev_err(codec->dev, "Failed to request IRQ: %d\n", ret); | 2307 | dev_err(codec->dev, "Failed to request IRQ: %d\n", ret); |
2308 | goto err_access; | 2308 | goto err_access; |
diff --git a/sound/soc/codecs/max98357a.c b/sound/soc/codecs/max98357a.c index bf3e933ee895..3a2fda08a893 100644 --- a/sound/soc/codecs/max98357a.c +++ b/sound/soc/codecs/max98357a.c | |||
@@ -60,13 +60,12 @@ static int max98357a_codec_probe(struct snd_soc_codec *codec) | |||
60 | { | 60 | { |
61 | struct gpio_desc *sdmode; | 61 | struct gpio_desc *sdmode; |
62 | 62 | ||
63 | sdmode = devm_gpiod_get(codec->dev, "sdmode"); | 63 | sdmode = devm_gpiod_get(codec->dev, "sdmode", GPIOD_OUT_LOW); |
64 | if (IS_ERR(sdmode)) { | 64 | if (IS_ERR(sdmode)) { |
65 | dev_err(codec->dev, "%s() unable to get sdmode GPIO: %ld\n", | 65 | dev_err(codec->dev, "%s() unable to get sdmode GPIO: %ld\n", |
66 | __func__, PTR_ERR(sdmode)); | 66 | __func__, PTR_ERR(sdmode)); |
67 | return PTR_ERR(sdmode); | 67 | return PTR_ERR(sdmode); |
68 | } | 68 | } |
69 | gpiod_direction_output(sdmode, 0); | ||
70 | snd_soc_codec_set_drvdata(codec, sdmode); | 69 | snd_soc_codec_set_drvdata(codec, sdmode); |
71 | 70 | ||
72 | return 0; | 71 | return 0; |
diff --git a/sound/soc/codecs/max9850.c b/sound/soc/codecs/max9850.c index 10f8e47ce2c2..481d58f1cb3f 100644 --- a/sound/soc/codecs/max9850.c +++ b/sound/soc/codecs/max9850.c | |||
@@ -252,7 +252,7 @@ static int max9850_set_bias_level(struct snd_soc_codec *codec, | |||
252 | case SND_SOC_BIAS_PREPARE: | 252 | case SND_SOC_BIAS_PREPARE: |
253 | break; | 253 | break; |
254 | case SND_SOC_BIAS_STANDBY: | 254 | case SND_SOC_BIAS_STANDBY: |
255 | if (codec->dapm.bias_level == SND_SOC_BIAS_OFF) { | 255 | if (snd_soc_codec_get_bias_level(codec) == SND_SOC_BIAS_OFF) { |
256 | ret = regcache_sync(max9850->regmap); | 256 | ret = regcache_sync(max9850->regmap); |
257 | if (ret) { | 257 | if (ret) { |
258 | dev_err(codec->dev, | 258 | dev_err(codec->dev, |
@@ -264,7 +264,6 @@ static int max9850_set_bias_level(struct snd_soc_codec *codec, | |||
264 | case SND_SOC_BIAS_OFF: | 264 | case SND_SOC_BIAS_OFF: |
265 | break; | 265 | break; |
266 | } | 266 | } |
267 | codec->dapm.bias_level = level; | ||
268 | return 0; | 267 | return 0; |
269 | } | 268 | } |
270 | 269 | ||
diff --git a/sound/soc/codecs/max98925.c b/sound/soc/codecs/max98925.c index 9b5a17de4690..aad664225dc3 100644 --- a/sound/soc/codecs/max98925.c +++ b/sound/soc/codecs/max98925.c | |||
@@ -346,7 +346,7 @@ static int max98925_dai_set_fmt(struct snd_soc_dai *codec_dai, | |||
346 | } | 346 | } |
347 | 347 | ||
348 | regmap_update_bits(max98925->regmap, MAX98925_FORMAT, | 348 | regmap_update_bits(max98925->regmap, MAX98925_FORMAT, |
349 | M98925_DAI_BCI_MASK, invert); | 349 | M98925_DAI_BCI_MASK | M98925_DAI_WCI_MASK, invert); |
350 | return 0; | 350 | return 0; |
351 | } | 351 | } |
352 | 352 | ||
diff --git a/sound/soc/codecs/mc13783.c b/sound/soc/codecs/mc13783.c index 2ffb9a0570dc..3d44fc50e4d0 100644 --- a/sound/soc/codecs/mc13783.c +++ b/sound/soc/codecs/mc13783.c | |||
@@ -623,14 +623,14 @@ static int mc13783_probe(struct snd_soc_codec *codec) | |||
623 | AUDIO_SSI_SEL, 0); | 623 | AUDIO_SSI_SEL, 0); |
624 | else | 624 | else |
625 | mc13xxx_reg_rmw(priv->mc13xxx, MC13783_AUDIO_CODEC, | 625 | mc13xxx_reg_rmw(priv->mc13xxx, MC13783_AUDIO_CODEC, |
626 | 0, AUDIO_SSI_SEL); | 626 | AUDIO_SSI_SEL, AUDIO_SSI_SEL); |
627 | 627 | ||
628 | if (priv->dac_ssi_port == MC13783_SSI1_PORT) | 628 | if (priv->dac_ssi_port == MC13783_SSI1_PORT) |
629 | mc13xxx_reg_rmw(priv->mc13xxx, MC13783_AUDIO_DAC, | 629 | mc13xxx_reg_rmw(priv->mc13xxx, MC13783_AUDIO_DAC, |
630 | AUDIO_SSI_SEL, 0); | 630 | AUDIO_SSI_SEL, 0); |
631 | else | 631 | else |
632 | mc13xxx_reg_rmw(priv->mc13xxx, MC13783_AUDIO_DAC, | 632 | mc13xxx_reg_rmw(priv->mc13xxx, MC13783_AUDIO_DAC, |
633 | 0, AUDIO_SSI_SEL); | 633 | AUDIO_SSI_SEL, AUDIO_SSI_SEL); |
634 | 634 | ||
635 | return 0; | 635 | return 0; |
636 | } | 636 | } |
diff --git a/sound/soc/codecs/ml26124.c b/sound/soc/codecs/ml26124.c index 711f55039522..b74118e019fb 100644 --- a/sound/soc/codecs/ml26124.c +++ b/sound/soc/codecs/ml26124.c | |||
@@ -341,6 +341,7 @@ static int ml26124_hw_params(struct snd_pcm_substream *substream, | |||
341 | struct snd_soc_codec *codec = dai->codec; | 341 | struct snd_soc_codec *codec = dai->codec; |
342 | struct ml26124_priv *priv = snd_soc_codec_get_drvdata(codec); | 342 | struct ml26124_priv *priv = snd_soc_codec_get_drvdata(codec); |
343 | int i = get_coeff(priv->mclk, params_rate(hw_params)); | 343 | int i = get_coeff(priv->mclk, params_rate(hw_params)); |
344 | int srate; | ||
344 | 345 | ||
345 | if (i < 0) | 346 | if (i < 0) |
346 | return i; | 347 | return i; |
@@ -370,53 +371,16 @@ static int ml26124_hw_params(struct snd_pcm_substream *substream, | |||
370 | BIT(0) | BIT(1), 0); | 371 | BIT(0) | BIT(1), 0); |
371 | } | 372 | } |
372 | 373 | ||
373 | switch (params_rate(hw_params)) { | 374 | srate = get_srate(params_rate(hw_params)); |
374 | case 16000: | 375 | if (srate < 0) |
375 | snd_soc_update_bits(codec, ML26124_SMPLING_RATE, 0xf, | 376 | return srate; |
376 | get_srate(params_rate(hw_params))); | 377 | |
377 | snd_soc_update_bits(codec, ML26124_PLLNL, 0xff, | 378 | snd_soc_update_bits(codec, ML26124_SMPLING_RATE, 0xf, srate); |
378 | coeff_div[i].pllnl); | 379 | snd_soc_update_bits(codec, ML26124_PLLNL, 0xff, coeff_div[i].pllnl); |
379 | snd_soc_update_bits(codec, ML26124_PLLNH, 0x1, | 380 | snd_soc_update_bits(codec, ML26124_PLLNH, 0x1, coeff_div[i].pllnh); |
380 | coeff_div[i].pllnh); | 381 | snd_soc_update_bits(codec, ML26124_PLLML, 0xff, coeff_div[i].pllml); |
381 | snd_soc_update_bits(codec, ML26124_PLLML, 0xff, | 382 | snd_soc_update_bits(codec, ML26124_PLLMH, 0x3f, coeff_div[i].pllmh); |
382 | coeff_div[i].pllml); | 383 | snd_soc_update_bits(codec, ML26124_PLLDIV, 0x1f, coeff_div[i].plldiv); |
383 | snd_soc_update_bits(codec, ML26124_PLLMH, 0x3f, | ||
384 | coeff_div[i].pllmh); | ||
385 | snd_soc_update_bits(codec, ML26124_PLLDIV, 0x1f, | ||
386 | coeff_div[i].plldiv); | ||
387 | break; | ||
388 | case 32000: | ||
389 | snd_soc_update_bits(codec, ML26124_SMPLING_RATE, 0xf, | ||
390 | get_srate(params_rate(hw_params))); | ||
391 | snd_soc_update_bits(codec, ML26124_PLLNL, 0xff, | ||
392 | coeff_div[i].pllnl); | ||
393 | snd_soc_update_bits(codec, ML26124_PLLNH, 0x1, | ||
394 | coeff_div[i].pllnh); | ||
395 | snd_soc_update_bits(codec, ML26124_PLLML, 0xff, | ||
396 | coeff_div[i].pllml); | ||
397 | snd_soc_update_bits(codec, ML26124_PLLMH, 0x3f, | ||
398 | coeff_div[i].pllmh); | ||
399 | snd_soc_update_bits(codec, ML26124_PLLDIV, 0x1f, | ||
400 | coeff_div[i].plldiv); | ||
401 | break; | ||
402 | case 48000: | ||
403 | snd_soc_update_bits(codec, ML26124_SMPLING_RATE, 0xf, | ||
404 | get_srate(params_rate(hw_params))); | ||
405 | snd_soc_update_bits(codec, ML26124_PLLNL, 0xff, | ||
406 | coeff_div[i].pllnl); | ||
407 | snd_soc_update_bits(codec, ML26124_PLLNH, 0x1, | ||
408 | coeff_div[i].pllnh); | ||
409 | snd_soc_update_bits(codec, ML26124_PLLML, 0xff, | ||
410 | coeff_div[i].pllml); | ||
411 | snd_soc_update_bits(codec, ML26124_PLLMH, 0x3f, | ||
412 | coeff_div[i].pllmh); | ||
413 | snd_soc_update_bits(codec, ML26124_PLLDIV, 0x1f, | ||
414 | coeff_div[i].plldiv); | ||
415 | break; | ||
416 | default: | ||
417 | pr_err("%s:this rate is no support for ml26124\n", __func__); | ||
418 | return -EINVAL; | ||
419 | } | ||
420 | 384 | ||
421 | return 0; | 385 | return 0; |
422 | } | 386 | } |
@@ -523,7 +487,7 @@ static int ml26124_set_bias_level(struct snd_soc_codec *codec, | |||
523 | break; | 487 | break; |
524 | case SND_SOC_BIAS_STANDBY: | 488 | case SND_SOC_BIAS_STANDBY: |
525 | /* VMID ON */ | 489 | /* VMID ON */ |
526 | if (codec->dapm.bias_level == SND_SOC_BIAS_OFF) { | 490 | if (snd_soc_codec_get_bias_level(codec) == SND_SOC_BIAS_OFF) { |
527 | snd_soc_update_bits(codec, ML26124_PW_REF_PW_MNG, | 491 | snd_soc_update_bits(codec, ML26124_PW_REF_PW_MNG, |
528 | ML26124_VMID, ML26124_VMID); | 492 | ML26124_VMID, ML26124_VMID); |
529 | msleep(500); | 493 | msleep(500); |
@@ -536,7 +500,6 @@ static int ml26124_set_bias_level(struct snd_soc_codec *codec, | |||
536 | ML26124_VMID, 0); | 500 | ML26124_VMID, 0); |
537 | break; | 501 | break; |
538 | } | 502 | } |
539 | codec->dapm.bias_level = level; | ||
540 | return 0; | 503 | return 0; |
541 | } | 504 | } |
542 | 505 | ||
diff --git a/sound/soc/codecs/pcm512x.c b/sound/soc/codecs/pcm512x.c index e12764d15431..de16429f0a43 100644 --- a/sound/soc/codecs/pcm512x.c +++ b/sound/soc/codecs/pcm512x.c | |||
@@ -242,7 +242,7 @@ static int pcm512x_overclock_pll_put(struct snd_kcontrol *kcontrol, | |||
242 | struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol); | 242 | struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol); |
243 | struct pcm512x_priv *pcm512x = snd_soc_codec_get_drvdata(codec); | 243 | struct pcm512x_priv *pcm512x = snd_soc_codec_get_drvdata(codec); |
244 | 244 | ||
245 | switch (codec->dapm.bias_level) { | 245 | switch (snd_soc_codec_get_bias_level(codec)) { |
246 | case SND_SOC_BIAS_OFF: | 246 | case SND_SOC_BIAS_OFF: |
247 | case SND_SOC_BIAS_STANDBY: | 247 | case SND_SOC_BIAS_STANDBY: |
248 | break; | 248 | break; |
@@ -270,7 +270,7 @@ static int pcm512x_overclock_dsp_put(struct snd_kcontrol *kcontrol, | |||
270 | struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol); | 270 | struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol); |
271 | struct pcm512x_priv *pcm512x = snd_soc_codec_get_drvdata(codec); | 271 | struct pcm512x_priv *pcm512x = snd_soc_codec_get_drvdata(codec); |
272 | 272 | ||
273 | switch (codec->dapm.bias_level) { | 273 | switch (snd_soc_codec_get_bias_level(codec)) { |
274 | case SND_SOC_BIAS_OFF: | 274 | case SND_SOC_BIAS_OFF: |
275 | case SND_SOC_BIAS_STANDBY: | 275 | case SND_SOC_BIAS_STANDBY: |
276 | break; | 276 | break; |
@@ -298,7 +298,7 @@ static int pcm512x_overclock_dac_put(struct snd_kcontrol *kcontrol, | |||
298 | struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol); | 298 | struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol); |
299 | struct pcm512x_priv *pcm512x = snd_soc_codec_get_drvdata(codec); | 299 | struct pcm512x_priv *pcm512x = snd_soc_codec_get_drvdata(codec); |
300 | 300 | ||
301 | switch (codec->dapm.bias_level) { | 301 | switch (snd_soc_codec_get_bias_level(codec)) { |
302 | case SND_SOC_BIAS_OFF: | 302 | case SND_SOC_BIAS_OFF: |
303 | case SND_SOC_BIAS_STANDBY: | 303 | case SND_SOC_BIAS_STANDBY: |
304 | break; | 304 | break; |
@@ -641,8 +641,6 @@ static int pcm512x_set_bias_level(struct snd_soc_codec *codec, | |||
641 | break; | 641 | break; |
642 | } | 642 | } |
643 | 643 | ||
644 | codec->dapm.bias_level = level; | ||
645 | |||
646 | return 0; | 644 | return 0; |
647 | } | 645 | } |
648 | 646 | ||
diff --git a/sound/soc/codecs/rl6347a.c b/sound/soc/codecs/rl6347a.c new file mode 100644 index 000000000000..91d5166bd3a1 --- /dev/null +++ b/sound/soc/codecs/rl6347a.c | |||
@@ -0,0 +1,128 @@ | |||
1 | /* | ||
2 | * rl6347a.c - RL6347A class device shared support | ||
3 | * | ||
4 | * Copyright 2015 Realtek Semiconductor Corp. | ||
5 | * | ||
6 | * Author: Oder Chiou <oder_chiou@realtek.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 | */ | ||
12 | |||
13 | #include <linux/module.h> | ||
14 | #include <linux/moduleparam.h> | ||
15 | #include <linux/init.h> | ||
16 | #include <linux/delay.h> | ||
17 | #include <linux/pm.h> | ||
18 | #include <linux/i2c.h> | ||
19 | #include <linux/platform_device.h> | ||
20 | #include <linux/spi/spi.h> | ||
21 | #include <linux/dmi.h> | ||
22 | #include <linux/acpi.h> | ||
23 | #include <sound/core.h> | ||
24 | #include <sound/pcm.h> | ||
25 | #include <sound/pcm_params.h> | ||
26 | #include <sound/soc.h> | ||
27 | #include <sound/soc-dapm.h> | ||
28 | #include <sound/initval.h> | ||
29 | #include <sound/tlv.h> | ||
30 | #include <sound/jack.h> | ||
31 | #include <linux/workqueue.h> | ||
32 | #include <sound/hda_verbs.h> | ||
33 | |||
34 | #include "rl6347a.h" | ||
35 | |||
36 | int rl6347a_hw_write(void *context, unsigned int reg, unsigned int value) | ||
37 | { | ||
38 | struct i2c_client *client = context; | ||
39 | struct rl6347a_priv *rl6347a = i2c_get_clientdata(client); | ||
40 | u8 data[4]; | ||
41 | int ret, i; | ||
42 | |||
43 | /* handle index registers */ | ||
44 | if (reg <= 0xff) { | ||
45 | rl6347a_hw_write(client, RL6347A_COEF_INDEX, reg); | ||
46 | for (i = 0; i < rl6347a->index_cache_size; i++) { | ||
47 | if (reg == rl6347a->index_cache[i].reg) { | ||
48 | rl6347a->index_cache[i].def = value; | ||
49 | break; | ||
50 | } | ||
51 | |||
52 | } | ||
53 | reg = RL6347A_PROC_COEF; | ||
54 | } | ||
55 | |||
56 | data[0] = (reg >> 24) & 0xff; | ||
57 | data[1] = (reg >> 16) & 0xff; | ||
58 | /* | ||
59 | * 4 bit VID: reg should be 0 | ||
60 | * 12 bit VID: value should be 0 | ||
61 | * So we use an OR operator to handle it rather than use if condition. | ||
62 | */ | ||
63 | data[2] = ((reg >> 8) & 0xff) | ((value >> 8) & 0xff); | ||
64 | data[3] = value & 0xff; | ||
65 | |||
66 | ret = i2c_master_send(client, data, 4); | ||
67 | |||
68 | if (ret == 4) | ||
69 | return 0; | ||
70 | else | ||
71 | pr_err("ret=%d\n", ret); | ||
72 | if (ret < 0) | ||
73 | return ret; | ||
74 | else | ||
75 | return -EIO; | ||
76 | } | ||
77 | EXPORT_SYMBOL_GPL(rl6347a_hw_write); | ||
78 | |||
79 | int rl6347a_hw_read(void *context, unsigned int reg, unsigned int *value) | ||
80 | { | ||
81 | struct i2c_client *client = context; | ||
82 | struct i2c_msg xfer[2]; | ||
83 | int ret; | ||
84 | __be32 be_reg; | ||
85 | unsigned int index, vid, buf = 0x0; | ||
86 | |||
87 | /* handle index registers */ | ||
88 | if (reg <= 0xff) { | ||
89 | rl6347a_hw_write(client, RL6347A_COEF_INDEX, reg); | ||
90 | reg = RL6347A_PROC_COEF; | ||
91 | } | ||
92 | |||
93 | reg = reg | 0x80000; | ||
94 | vid = (reg >> 8) & 0xfff; | ||
95 | |||
96 | if (AC_VERB_GET_AMP_GAIN_MUTE == (vid & 0xf00)) { | ||
97 | index = (reg >> 8) & 0xf; | ||
98 | reg = (reg & ~0xf0f) | index; | ||
99 | } | ||
100 | be_reg = cpu_to_be32(reg); | ||
101 | |||
102 | /* Write register */ | ||
103 | xfer[0].addr = client->addr; | ||
104 | xfer[0].flags = 0; | ||
105 | xfer[0].len = 4; | ||
106 | xfer[0].buf = (u8 *)&be_reg; | ||
107 | |||
108 | /* Read data */ | ||
109 | xfer[1].addr = client->addr; | ||
110 | xfer[1].flags = I2C_M_RD; | ||
111 | xfer[1].len = 4; | ||
112 | xfer[1].buf = (u8 *)&buf; | ||
113 | |||
114 | ret = i2c_transfer(client->adapter, xfer, 2); | ||
115 | if (ret < 0) | ||
116 | return ret; | ||
117 | else if (ret != 2) | ||
118 | return -EIO; | ||
119 | |||
120 | *value = be32_to_cpu(buf); | ||
121 | |||
122 | return 0; | ||
123 | } | ||
124 | EXPORT_SYMBOL_GPL(rl6347a_hw_read); | ||
125 | |||
126 | MODULE_DESCRIPTION("RL6347A class device shared support"); | ||
127 | MODULE_AUTHOR("Oder Chiou <oder_chiou@realtek.com>"); | ||
128 | MODULE_LICENSE("GPL v2"); | ||
diff --git a/sound/soc/codecs/rl6347a.h b/sound/soc/codecs/rl6347a.h new file mode 100644 index 000000000000..1cb56e50b7f3 --- /dev/null +++ b/sound/soc/codecs/rl6347a.h | |||
@@ -0,0 +1,32 @@ | |||
1 | /* | ||
2 | * rl6347a.h - RL6347A class device shared support | ||
3 | * | ||
4 | * Copyright 2015 Realtek Semiconductor Corp. | ||
5 | * | ||
6 | * Author: Oder Chiou <oder_chiou@realtek.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 | */ | ||
12 | #ifndef __RL6347A_H__ | ||
13 | #define __RL6347A_H__ | ||
14 | |||
15 | #define VERB_CMD(V, N, D) ((N << 20) | (V << 8) | D) | ||
16 | |||
17 | #define RL6347A_VENDOR_REGISTERS 0x20 | ||
18 | |||
19 | #define RL6347A_COEF_INDEX\ | ||
20 | VERB_CMD(AC_VERB_SET_COEF_INDEX, RL6347A_VENDOR_REGISTERS, 0) | ||
21 | #define RL6347A_PROC_COEF\ | ||
22 | VERB_CMD(AC_VERB_SET_PROC_COEF, RL6347A_VENDOR_REGISTERS, 0) | ||
23 | |||
24 | struct rl6347a_priv { | ||
25 | struct reg_default *index_cache; | ||
26 | int index_cache_size; | ||
27 | }; | ||
28 | |||
29 | int rl6347a_hw_write(void *context, unsigned int reg, unsigned int value); | ||
30 | int rl6347a_hw_read(void *context, unsigned int reg, unsigned int *value); | ||
31 | |||
32 | #endif /* __RL6347A_H__ */ | ||
diff --git a/sound/soc/codecs/rt286.c b/sound/soc/codecs/rt286.c index 0fcda35a3a93..5c43e263b2c1 100644 --- a/sound/soc/codecs/rt286.c +++ b/sound/soc/codecs/rt286.c | |||
@@ -31,12 +31,15 @@ | |||
31 | #include <sound/rt286.h> | 31 | #include <sound/rt286.h> |
32 | #include <sound/hda_verbs.h> | 32 | #include <sound/hda_verbs.h> |
33 | 33 | ||
34 | #include "rl6347a.h" | ||
34 | #include "rt286.h" | 35 | #include "rt286.h" |
35 | 36 | ||
36 | #define RT286_VENDOR_ID 0x10ec0286 | 37 | #define RT286_VENDOR_ID 0x10ec0286 |
37 | #define RT288_VENDOR_ID 0x10ec0288 | 38 | #define RT288_VENDOR_ID 0x10ec0288 |
38 | 39 | ||
39 | struct rt286_priv { | 40 | struct rt286_priv { |
41 | struct reg_default *index_cache; | ||
42 | int index_cache_size; | ||
40 | struct regmap *regmap; | 43 | struct regmap *regmap; |
41 | struct snd_soc_codec *codec; | 44 | struct snd_soc_codec *codec; |
42 | struct rt286_platform_data pdata; | 45 | struct rt286_platform_data pdata; |
@@ -45,7 +48,6 @@ struct rt286_priv { | |||
45 | struct delayed_work jack_detect_work; | 48 | struct delayed_work jack_detect_work; |
46 | int sys_clk; | 49 | int sys_clk; |
47 | int clk_id; | 50 | int clk_id; |
48 | struct reg_default *index_cache; | ||
49 | }; | 51 | }; |
50 | 52 | ||
51 | static struct reg_default rt286_index_def[] = { | 53 | static struct reg_default rt286_index_def[] = { |
@@ -185,94 +187,6 @@ static bool rt286_readable_register(struct device *dev, unsigned int reg) | |||
185 | } | 187 | } |
186 | } | 188 | } |
187 | 189 | ||
188 | static int rt286_hw_write(void *context, unsigned int reg, unsigned int value) | ||
189 | { | ||
190 | struct i2c_client *client = context; | ||
191 | struct rt286_priv *rt286 = i2c_get_clientdata(client); | ||
192 | u8 data[4]; | ||
193 | int ret, i; | ||
194 | |||
195 | /* handle index registers */ | ||
196 | if (reg <= 0xff) { | ||
197 | rt286_hw_write(client, RT286_COEF_INDEX, reg); | ||
198 | for (i = 0; i < INDEX_CACHE_SIZE; i++) { | ||
199 | if (reg == rt286->index_cache[i].reg) { | ||
200 | rt286->index_cache[i].def = value; | ||
201 | break; | ||
202 | } | ||
203 | |||
204 | } | ||
205 | reg = RT286_PROC_COEF; | ||
206 | } | ||
207 | |||
208 | data[0] = (reg >> 24) & 0xff; | ||
209 | data[1] = (reg >> 16) & 0xff; | ||
210 | /* | ||
211 | * 4 bit VID: reg should be 0 | ||
212 | * 12 bit VID: value should be 0 | ||
213 | * So we use an OR operator to handle it rather than use if condition. | ||
214 | */ | ||
215 | data[2] = ((reg >> 8) & 0xff) | ((value >> 8) & 0xff); | ||
216 | data[3] = value & 0xff; | ||
217 | |||
218 | ret = i2c_master_send(client, data, 4); | ||
219 | |||
220 | if (ret == 4) | ||
221 | return 0; | ||
222 | else | ||
223 | pr_err("ret=%d\n", ret); | ||
224 | if (ret < 0) | ||
225 | return ret; | ||
226 | else | ||
227 | return -EIO; | ||
228 | } | ||
229 | |||
230 | static int rt286_hw_read(void *context, unsigned int reg, unsigned int *value) | ||
231 | { | ||
232 | struct i2c_client *client = context; | ||
233 | struct i2c_msg xfer[2]; | ||
234 | int ret; | ||
235 | __be32 be_reg; | ||
236 | unsigned int index, vid, buf = 0x0; | ||
237 | |||
238 | /* handle index registers */ | ||
239 | if (reg <= 0xff) { | ||
240 | rt286_hw_write(client, RT286_COEF_INDEX, reg); | ||
241 | reg = RT286_PROC_COEF; | ||
242 | } | ||
243 | |||
244 | reg = reg | 0x80000; | ||
245 | vid = (reg >> 8) & 0xfff; | ||
246 | |||
247 | if (AC_VERB_GET_AMP_GAIN_MUTE == (vid & 0xf00)) { | ||
248 | index = (reg >> 8) & 0xf; | ||
249 | reg = (reg & ~0xf0f) | index; | ||
250 | } | ||
251 | be_reg = cpu_to_be32(reg); | ||
252 | |||
253 | /* Write register */ | ||
254 | xfer[0].addr = client->addr; | ||
255 | xfer[0].flags = 0; | ||
256 | xfer[0].len = 4; | ||
257 | xfer[0].buf = (u8 *)&be_reg; | ||
258 | |||
259 | /* Read data */ | ||
260 | xfer[1].addr = client->addr; | ||
261 | xfer[1].flags = I2C_M_RD; | ||
262 | xfer[1].len = 4; | ||
263 | xfer[1].buf = (u8 *)&buf; | ||
264 | |||
265 | ret = i2c_transfer(client->adapter, xfer, 2); | ||
266 | if (ret < 0) | ||
267 | return ret; | ||
268 | else if (ret != 2) | ||
269 | return -EIO; | ||
270 | |||
271 | *value = be32_to_cpu(buf); | ||
272 | |||
273 | return 0; | ||
274 | } | ||
275 | |||
276 | #ifdef CONFIG_PM | 190 | #ifdef CONFIG_PM |
277 | static void rt286_index_sync(struct snd_soc_codec *codec) | 191 | static void rt286_index_sync(struct snd_soc_codec *codec) |
278 | { | 192 | { |
@@ -301,6 +215,7 @@ static int rt286_support_power_controls[] = { | |||
301 | 215 | ||
302 | static int rt286_jack_detect(struct rt286_priv *rt286, bool *hp, bool *mic) | 216 | static int rt286_jack_detect(struct rt286_priv *rt286, bool *hp, bool *mic) |
303 | { | 217 | { |
218 | struct snd_soc_dapm_context *dapm; | ||
304 | unsigned int val, buf; | 219 | unsigned int val, buf; |
305 | 220 | ||
306 | *hp = false; | 221 | *hp = false; |
@@ -308,6 +223,9 @@ static int rt286_jack_detect(struct rt286_priv *rt286, bool *hp, bool *mic) | |||
308 | 223 | ||
309 | if (!rt286->codec) | 224 | if (!rt286->codec) |
310 | return -EINVAL; | 225 | return -EINVAL; |
226 | |||
227 | dapm = snd_soc_codec_get_dapm(rt286->codec); | ||
228 | |||
311 | if (rt286->pdata.cbj_en) { | 229 | if (rt286->pdata.cbj_en) { |
312 | regmap_read(rt286->regmap, RT286_GET_HP_SENSE, &buf); | 230 | regmap_read(rt286->regmap, RT286_GET_HP_SENSE, &buf); |
313 | *hp = buf & 0x80000000; | 231 | *hp = buf & 0x80000000; |
@@ -316,14 +234,11 @@ static int rt286_jack_detect(struct rt286_priv *rt286, bool *hp, bool *mic) | |||
316 | regmap_update_bits(rt286->regmap, | 234 | regmap_update_bits(rt286->regmap, |
317 | RT286_DC_GAIN, 0x200, 0x200); | 235 | RT286_DC_GAIN, 0x200, 0x200); |
318 | 236 | ||
319 | snd_soc_dapm_force_enable_pin(&rt286->codec->dapm, | 237 | snd_soc_dapm_force_enable_pin(dapm, "HV"); |
320 | "HV"); | 238 | snd_soc_dapm_force_enable_pin(dapm, "VREF"); |
321 | snd_soc_dapm_force_enable_pin(&rt286->codec->dapm, | ||
322 | "VREF"); | ||
323 | /* power LDO1 */ | 239 | /* power LDO1 */ |
324 | snd_soc_dapm_force_enable_pin(&rt286->codec->dapm, | 240 | snd_soc_dapm_force_enable_pin(dapm, "LDO1"); |
325 | "LDO1"); | 241 | snd_soc_dapm_sync(dapm); |
326 | snd_soc_dapm_sync(&rt286->codec->dapm); | ||
327 | 242 | ||
328 | regmap_write(rt286->regmap, RT286_SET_MIC1, 0x24); | 243 | regmap_write(rt286->regmap, RT286_SET_MIC1, 0x24); |
329 | msleep(50); | 244 | msleep(50); |
@@ -360,11 +275,11 @@ static int rt286_jack_detect(struct rt286_priv *rt286, bool *hp, bool *mic) | |||
360 | *mic = buf & 0x80000000; | 275 | *mic = buf & 0x80000000; |
361 | } | 276 | } |
362 | 277 | ||
363 | snd_soc_dapm_disable_pin(&rt286->codec->dapm, "HV"); | 278 | snd_soc_dapm_disable_pin(dapm, "HV"); |
364 | snd_soc_dapm_disable_pin(&rt286->codec->dapm, "VREF"); | 279 | snd_soc_dapm_disable_pin(dapm, "VREF"); |
365 | if (!*hp) | 280 | if (!*hp) |
366 | snd_soc_dapm_disable_pin(&rt286->codec->dapm, "LDO1"); | 281 | snd_soc_dapm_disable_pin(dapm, "LDO1"); |
367 | snd_soc_dapm_sync(&rt286->codec->dapm); | 282 | snd_soc_dapm_sync(dapm); |
368 | 283 | ||
369 | return 0; | 284 | return 0; |
370 | } | 285 | } |
@@ -391,6 +306,7 @@ static void rt286_jack_detect_work(struct work_struct *work) | |||
391 | 306 | ||
392 | int rt286_mic_detect(struct snd_soc_codec *codec, struct snd_soc_jack *jack) | 307 | int rt286_mic_detect(struct snd_soc_codec *codec, struct snd_soc_jack *jack) |
393 | { | 308 | { |
309 | struct snd_soc_dapm_context *dapm = snd_soc_codec_get_dapm(codec); | ||
394 | struct rt286_priv *rt286 = snd_soc_codec_get_drvdata(codec); | 310 | struct rt286_priv *rt286 = snd_soc_codec_get_drvdata(codec); |
395 | 311 | ||
396 | rt286->jack = jack; | 312 | rt286->jack = jack; |
@@ -398,7 +314,7 @@ int rt286_mic_detect(struct snd_soc_codec *codec, struct snd_soc_jack *jack) | |||
398 | if (jack) { | 314 | if (jack) { |
399 | /* enable IRQ */ | 315 | /* enable IRQ */ |
400 | if (rt286->jack->status & SND_JACK_HEADPHONE) | 316 | if (rt286->jack->status & SND_JACK_HEADPHONE) |
401 | snd_soc_dapm_force_enable_pin(&codec->dapm, "LDO1"); | 317 | snd_soc_dapm_force_enable_pin(dapm, "LDO1"); |
402 | regmap_update_bits(rt286->regmap, RT286_IRQ_CTRL, 0x2, 0x2); | 318 | regmap_update_bits(rt286->regmap, RT286_IRQ_CTRL, 0x2, 0x2); |
403 | /* Send an initial empty report */ | 319 | /* Send an initial empty report */ |
404 | snd_soc_jack_report(rt286->jack, rt286->jack->status, | 320 | snd_soc_jack_report(rt286->jack, rt286->jack->status, |
@@ -406,9 +322,9 @@ int rt286_mic_detect(struct snd_soc_codec *codec, struct snd_soc_jack *jack) | |||
406 | } else { | 322 | } else { |
407 | /* disable IRQ */ | 323 | /* disable IRQ */ |
408 | regmap_update_bits(rt286->regmap, RT286_IRQ_CTRL, 0x2, 0x0); | 324 | regmap_update_bits(rt286->regmap, RT286_IRQ_CTRL, 0x2, 0x0); |
409 | snd_soc_dapm_disable_pin(&codec->dapm, "LDO1"); | 325 | snd_soc_dapm_disable_pin(dapm, "LDO1"); |
410 | } | 326 | } |
411 | snd_soc_dapm_sync(&codec->dapm); | 327 | snd_soc_dapm_sync(dapm); |
412 | 328 | ||
413 | return 0; | 329 | return 0; |
414 | } | 330 | } |
@@ -985,7 +901,7 @@ static int rt286_set_bias_level(struct snd_soc_codec *codec, | |||
985 | { | 901 | { |
986 | switch (level) { | 902 | switch (level) { |
987 | case SND_SOC_BIAS_PREPARE: | 903 | case SND_SOC_BIAS_PREPARE: |
988 | if (SND_SOC_BIAS_STANDBY == codec->dapm.bias_level) { | 904 | if (SND_SOC_BIAS_STANDBY == snd_soc_codec_get_bias_level(codec)) { |
989 | snd_soc_write(codec, | 905 | snd_soc_write(codec, |
990 | RT286_SET_AUDIO_POWER, AC_PWRST_D0); | 906 | RT286_SET_AUDIO_POWER, AC_PWRST_D0); |
991 | snd_soc_update_bits(codec, | 907 | snd_soc_update_bits(codec, |
@@ -1012,7 +928,6 @@ static int rt286_set_bias_level(struct snd_soc_codec *codec, | |||
1012 | default: | 928 | default: |
1013 | break; | 929 | break; |
1014 | } | 930 | } |
1015 | codec->dapm.bias_level = level; | ||
1016 | 931 | ||
1017 | return 0; | 932 | return 0; |
1018 | } | 933 | } |
@@ -1173,8 +1088,8 @@ static const struct regmap_config rt286_regmap = { | |||
1173 | .max_register = 0x02370100, | 1088 | .max_register = 0x02370100, |
1174 | .volatile_reg = rt286_volatile_register, | 1089 | .volatile_reg = rt286_volatile_register, |
1175 | .readable_reg = rt286_readable_register, | 1090 | .readable_reg = rt286_readable_register, |
1176 | .reg_write = rt286_hw_write, | 1091 | .reg_write = rl6347a_hw_write, |
1177 | .reg_read = rt286_hw_read, | 1092 | .reg_read = rl6347a_hw_read, |
1178 | .cache_type = REGCACHE_RBTREE, | 1093 | .cache_type = REGCACHE_RBTREE, |
1179 | .reg_defaults = rt286_reg, | 1094 | .reg_defaults = rt286_reg, |
1180 | .num_reg_defaults = ARRAY_SIZE(rt286_reg), | 1095 | .num_reg_defaults = ARRAY_SIZE(rt286_reg), |
@@ -1247,6 +1162,7 @@ static int rt286_i2c_probe(struct i2c_client *i2c, | |||
1247 | } | 1162 | } |
1248 | 1163 | ||
1249 | rt286->index_cache = rt286_index_def; | 1164 | rt286->index_cache = rt286_index_def; |
1165 | rt286->index_cache_size = INDEX_CACHE_SIZE; | ||
1250 | rt286->i2c = i2c; | 1166 | rt286->i2c = i2c; |
1251 | i2c_set_clientdata(i2c, rt286); | 1167 | i2c_set_clientdata(i2c, rt286); |
1252 | 1168 | ||
diff --git a/sound/soc/codecs/rt5631.c b/sound/soc/codecs/rt5631.c index 2c10d77727af..058167c80d71 100644 --- a/sound/soc/codecs/rt5631.c +++ b/sound/soc/codecs/rt5631.c | |||
@@ -1546,7 +1546,7 @@ static int rt5631_set_bias_level(struct snd_soc_codec *codec, | |||
1546 | break; | 1546 | break; |
1547 | 1547 | ||
1548 | case SND_SOC_BIAS_STANDBY: | 1548 | case SND_SOC_BIAS_STANDBY: |
1549 | if (codec->dapm.bias_level == SND_SOC_BIAS_OFF) { | 1549 | if (snd_soc_codec_get_bias_level(codec) == SND_SOC_BIAS_OFF) { |
1550 | snd_soc_update_bits(codec, RT5631_PWR_MANAG_ADD3, | 1550 | snd_soc_update_bits(codec, RT5631_PWR_MANAG_ADD3, |
1551 | RT5631_PWR_VREF | RT5631_PWR_MAIN_BIAS, | 1551 | RT5631_PWR_VREF | RT5631_PWR_MAIN_BIAS, |
1552 | RT5631_PWR_VREF | RT5631_PWR_MAIN_BIAS); | 1552 | RT5631_PWR_VREF | RT5631_PWR_MAIN_BIAS); |
@@ -1569,7 +1569,6 @@ static int rt5631_set_bias_level(struct snd_soc_codec *codec, | |||
1569 | default: | 1569 | default: |
1570 | break; | 1570 | break; |
1571 | } | 1571 | } |
1572 | codec->dapm.bias_level = level; | ||
1573 | 1572 | ||
1574 | return 0; | 1573 | return 0; |
1575 | } | 1574 | } |
@@ -1615,7 +1614,7 @@ static int rt5631_probe(struct snd_soc_codec *codec) | |||
1615 | RT5631_DMIC_R_CH_LATCH_RISING); | 1614 | RT5631_DMIC_R_CH_LATCH_RISING); |
1616 | } | 1615 | } |
1617 | 1616 | ||
1618 | codec->dapm.bias_level = SND_SOC_BIAS_STANDBY; | 1617 | snd_soc_codec_init_bias_level(codec, SND_SOC_BIAS_STANDBY); |
1619 | 1618 | ||
1620 | return 0; | 1619 | return 0; |
1621 | } | 1620 | } |
diff --git a/sound/soc/codecs/rt5640.c b/sound/soc/codecs/rt5640.c index 914681978222..9bc78e57513d 100644 --- a/sound/soc/codecs/rt5640.c +++ b/sound/soc/codecs/rt5640.c | |||
@@ -1869,7 +1869,7 @@ static int rt5640_set_bias_level(struct snd_soc_codec *codec, | |||
1869 | { | 1869 | { |
1870 | switch (level) { | 1870 | switch (level) { |
1871 | case SND_SOC_BIAS_STANDBY: | 1871 | case SND_SOC_BIAS_STANDBY: |
1872 | if (SND_SOC_BIAS_OFF == codec->dapm.bias_level) { | 1872 | if (SND_SOC_BIAS_OFF == snd_soc_codec_get_bias_level(codec)) { |
1873 | snd_soc_update_bits(codec, RT5640_PWR_ANLG1, | 1873 | snd_soc_update_bits(codec, RT5640_PWR_ANLG1, |
1874 | RT5640_PWR_VREF1 | RT5640_PWR_MB | | 1874 | RT5640_PWR_VREF1 | RT5640_PWR_MB | |
1875 | RT5640_PWR_BG | RT5640_PWR_VREF2, | 1875 | RT5640_PWR_BG | RT5640_PWR_VREF2, |
@@ -1901,7 +1901,6 @@ static int rt5640_set_bias_level(struct snd_soc_codec *codec, | |||
1901 | default: | 1901 | default: |
1902 | break; | 1902 | break; |
1903 | } | 1903 | } |
1904 | codec->dapm.bias_level = level; | ||
1905 | 1904 | ||
1906 | return 0; | 1905 | return 0; |
1907 | } | 1906 | } |
@@ -1934,11 +1933,12 @@ EXPORT_SYMBOL_GPL(rt5640_dmic_enable); | |||
1934 | 1933 | ||
1935 | static int rt5640_probe(struct snd_soc_codec *codec) | 1934 | static int rt5640_probe(struct snd_soc_codec *codec) |
1936 | { | 1935 | { |
1936 | struct snd_soc_dapm_context *dapm = snd_soc_codec_get_dapm(codec); | ||
1937 | struct rt5640_priv *rt5640 = snd_soc_codec_get_drvdata(codec); | 1937 | struct rt5640_priv *rt5640 = snd_soc_codec_get_drvdata(codec); |
1938 | 1938 | ||
1939 | rt5640->codec = codec; | 1939 | rt5640->codec = codec; |
1940 | 1940 | ||
1941 | rt5640_set_bias_level(codec, SND_SOC_BIAS_OFF); | 1941 | snd_soc_codec_force_bias_level(codec, SND_SOC_BIAS_OFF); |
1942 | 1942 | ||
1943 | snd_soc_update_bits(codec, RT5640_DUMMY1, 0x0301, 0x0301); | 1943 | snd_soc_update_bits(codec, RT5640_DUMMY1, 0x0301, 0x0301); |
1944 | snd_soc_update_bits(codec, RT5640_MICBIAS, 0x0030, 0x0030); | 1944 | snd_soc_update_bits(codec, RT5640_MICBIAS, 0x0030, 0x0030); |
@@ -1950,18 +1950,18 @@ static int rt5640_probe(struct snd_soc_codec *codec) | |||
1950 | snd_soc_add_codec_controls(codec, | 1950 | snd_soc_add_codec_controls(codec, |
1951 | rt5640_specific_snd_controls, | 1951 | rt5640_specific_snd_controls, |
1952 | ARRAY_SIZE(rt5640_specific_snd_controls)); | 1952 | ARRAY_SIZE(rt5640_specific_snd_controls)); |
1953 | snd_soc_dapm_new_controls(&codec->dapm, | 1953 | snd_soc_dapm_new_controls(dapm, |
1954 | rt5640_specific_dapm_widgets, | 1954 | rt5640_specific_dapm_widgets, |
1955 | ARRAY_SIZE(rt5640_specific_dapm_widgets)); | 1955 | ARRAY_SIZE(rt5640_specific_dapm_widgets)); |
1956 | snd_soc_dapm_add_routes(&codec->dapm, | 1956 | snd_soc_dapm_add_routes(dapm, |
1957 | rt5640_specific_dapm_routes, | 1957 | rt5640_specific_dapm_routes, |
1958 | ARRAY_SIZE(rt5640_specific_dapm_routes)); | 1958 | ARRAY_SIZE(rt5640_specific_dapm_routes)); |
1959 | break; | 1959 | break; |
1960 | case RT5640_ID_5639: | 1960 | case RT5640_ID_5639: |
1961 | snd_soc_dapm_new_controls(&codec->dapm, | 1961 | snd_soc_dapm_new_controls(dapm, |
1962 | rt5639_specific_dapm_widgets, | 1962 | rt5639_specific_dapm_widgets, |
1963 | ARRAY_SIZE(rt5639_specific_dapm_widgets)); | 1963 | ARRAY_SIZE(rt5639_specific_dapm_widgets)); |
1964 | snd_soc_dapm_add_routes(&codec->dapm, | 1964 | snd_soc_dapm_add_routes(dapm, |
1965 | rt5639_specific_dapm_routes, | 1965 | rt5639_specific_dapm_routes, |
1966 | ARRAY_SIZE(rt5639_specific_dapm_routes)); | 1966 | ARRAY_SIZE(rt5639_specific_dapm_routes)); |
1967 | break; | 1967 | break; |
@@ -1990,7 +1990,7 @@ static int rt5640_suspend(struct snd_soc_codec *codec) | |||
1990 | { | 1990 | { |
1991 | struct rt5640_priv *rt5640 = snd_soc_codec_get_drvdata(codec); | 1991 | struct rt5640_priv *rt5640 = snd_soc_codec_get_drvdata(codec); |
1992 | 1992 | ||
1993 | rt5640_set_bias_level(codec, SND_SOC_BIAS_OFF); | 1993 | snd_soc_codec_force_bias_level(codec, SND_SOC_BIAS_OFF); |
1994 | rt5640_reset(codec); | 1994 | rt5640_reset(codec); |
1995 | regcache_cache_only(rt5640->regmap, true); | 1995 | regcache_cache_only(rt5640->regmap, true); |
1996 | regcache_mark_dirty(rt5640->regmap); | 1996 | regcache_mark_dirty(rt5640->regmap); |
diff --git a/sound/soc/codecs/rt5645.c b/sound/soc/codecs/rt5645.c index 69528ae5410c..9ce311e088fc 100644 --- a/sound/soc/codecs/rt5645.c +++ b/sound/soc/codecs/rt5645.c | |||
@@ -18,6 +18,9 @@ | |||
18 | #include <linux/platform_device.h> | 18 | #include <linux/platform_device.h> |
19 | #include <linux/spi/spi.h> | 19 | #include <linux/spi/spi.h> |
20 | #include <linux/gpio.h> | 20 | #include <linux/gpio.h> |
21 | #include <linux/gpio/consumer.h> | ||
22 | #include <linux/acpi.h> | ||
23 | #include <linux/dmi.h> | ||
21 | #include <sound/core.h> | 24 | #include <sound/core.h> |
22 | #include <sound/pcm.h> | 25 | #include <sound/pcm.h> |
23 | #include <sound/pcm_params.h> | 26 | #include <sound/pcm_params.h> |
@@ -346,6 +349,7 @@ static bool rt5645_readable_register(struct device *dev, unsigned int reg) | |||
346 | case RT5645_TDM_CTRL_1: | 349 | case RT5645_TDM_CTRL_1: |
347 | case RT5645_TDM_CTRL_2: | 350 | case RT5645_TDM_CTRL_2: |
348 | case RT5645_TDM_CTRL_3: | 351 | case RT5645_TDM_CTRL_3: |
352 | case RT5650_TDM_CTRL_4: | ||
349 | case RT5645_GLB_CLK: | 353 | case RT5645_GLB_CLK: |
350 | case RT5645_PLL_CTRL1: | 354 | case RT5645_PLL_CTRL1: |
351 | case RT5645_PLL_CTRL2: | 355 | case RT5645_PLL_CTRL2: |
@@ -414,9 +418,9 @@ static bool rt5645_readable_register(struct device *dev, unsigned int reg) | |||
414 | } | 418 | } |
415 | 419 | ||
416 | static const DECLARE_TLV_DB_SCALE(out_vol_tlv, -4650, 150, 0); | 420 | static const DECLARE_TLV_DB_SCALE(out_vol_tlv, -4650, 150, 0); |
417 | static const DECLARE_TLV_DB_SCALE(dac_vol_tlv, -65625, 375, 0); | 421 | static const DECLARE_TLV_DB_SCALE(dac_vol_tlv, -6525, 75, 0); |
418 | static const DECLARE_TLV_DB_SCALE(in_vol_tlv, -3450, 150, 0); | 422 | static const DECLARE_TLV_DB_SCALE(in_vol_tlv, -3450, 150, 0); |
419 | static const DECLARE_TLV_DB_SCALE(adc_vol_tlv, -17625, 375, 0); | 423 | static const DECLARE_TLV_DB_SCALE(adc_vol_tlv, -1725, 75, 0); |
420 | static const DECLARE_TLV_DB_SCALE(adc_bst_tlv, 0, 1200, 0); | 424 | static const DECLARE_TLV_DB_SCALE(adc_bst_tlv, 0, 1200, 0); |
421 | 425 | ||
422 | /* {0, +20, +24, +30, +35, +40, +44, +50, +52} dB */ | 426 | /* {0, +20, +24, +30, +35, +40, +44, +50, +52} dB */ |
@@ -431,30 +435,6 @@ static unsigned int bst_tlv[] = { | |||
431 | 8, 8, TLV_DB_SCALE_ITEM(5200, 0, 0), | 435 | 8, 8, TLV_DB_SCALE_ITEM(5200, 0, 0), |
432 | }; | 436 | }; |
433 | 437 | ||
434 | static const char * const rt5645_tdm_data_swap_select[] = { | ||
435 | "L/R", "R/L", "L/L", "R/R" | ||
436 | }; | ||
437 | |||
438 | static SOC_ENUM_SINGLE_DECL(rt5645_tdm_adc_slot0_1_enum, | ||
439 | RT5645_TDM_CTRL_1, 6, rt5645_tdm_data_swap_select); | ||
440 | |||
441 | static SOC_ENUM_SINGLE_DECL(rt5645_tdm_adc_slot2_3_enum, | ||
442 | RT5645_TDM_CTRL_1, 4, rt5645_tdm_data_swap_select); | ||
443 | |||
444 | static SOC_ENUM_SINGLE_DECL(rt5645_tdm_adc_slot4_5_enum, | ||
445 | RT5645_TDM_CTRL_1, 2, rt5645_tdm_data_swap_select); | ||
446 | |||
447 | static SOC_ENUM_SINGLE_DECL(rt5645_tdm_adc_slot6_7_enum, | ||
448 | RT5645_TDM_CTRL_1, 0, rt5645_tdm_data_swap_select); | ||
449 | |||
450 | static const char * const rt5645_tdm_adc_data_select[] = { | ||
451 | "1/2/R", "2/1/R", "R/1/2", "R/2/1" | ||
452 | }; | ||
453 | |||
454 | static SOC_ENUM_SINGLE_DECL(rt5645_tdm_adc_sel_enum, | ||
455 | RT5645_TDM_CTRL_1, 8, | ||
456 | rt5645_tdm_adc_data_select); | ||
457 | |||
458 | static const struct snd_kcontrol_new rt5645_snd_controls[] = { | 438 | static const struct snd_kcontrol_new rt5645_snd_controls[] = { |
459 | /* Speaker Output Volume */ | 439 | /* Speaker Output Volume */ |
460 | SOC_DOUBLE("Speaker Channel Switch", RT5645_SPK_VOL, | 440 | SOC_DOUBLE("Speaker Channel Switch", RT5645_SPK_VOL, |
@@ -463,9 +443,9 @@ static const struct snd_kcontrol_new rt5645_snd_controls[] = { | |||
463 | RT5645_L_VOL_SFT, RT5645_R_VOL_SFT, 39, 1, out_vol_tlv), | 443 | RT5645_L_VOL_SFT, RT5645_R_VOL_SFT, 39, 1, out_vol_tlv), |
464 | 444 | ||
465 | /* Headphone Output Volume */ | 445 | /* Headphone Output Volume */ |
466 | SOC_DOUBLE("HP Channel Switch", RT5645_HP_VOL, | 446 | SOC_DOUBLE("Headphone Channel Switch", RT5645_HP_VOL, |
467 | RT5645_VOL_L_SFT, RT5645_VOL_R_SFT, 1, 1), | 447 | RT5645_VOL_L_SFT, RT5645_VOL_R_SFT, 1, 1), |
468 | SOC_DOUBLE_TLV("HP Playback Volume", RT5645_HP_VOL, | 448 | SOC_DOUBLE_TLV("Headphone Playback Volume", RT5645_HP_VOL, |
469 | RT5645_L_VOL_SFT, RT5645_R_VOL_SFT, 39, 1, out_vol_tlv), | 449 | RT5645_L_VOL_SFT, RT5645_R_VOL_SFT, 39, 1, out_vol_tlv), |
470 | 450 | ||
471 | /* OUTPUT Control */ | 451 | /* OUTPUT Control */ |
@@ -480,9 +460,9 @@ static const struct snd_kcontrol_new rt5645_snd_controls[] = { | |||
480 | SOC_DOUBLE("DAC2 Playback Switch", RT5645_DAC_CTRL, | 460 | SOC_DOUBLE("DAC2 Playback Switch", RT5645_DAC_CTRL, |
481 | RT5645_M_DAC_L2_VOL_SFT, RT5645_M_DAC_R2_VOL_SFT, 1, 1), | 461 | RT5645_M_DAC_L2_VOL_SFT, RT5645_M_DAC_R2_VOL_SFT, 1, 1), |
482 | SOC_DOUBLE_TLV("DAC1 Playback Volume", RT5645_DAC1_DIG_VOL, | 462 | SOC_DOUBLE_TLV("DAC1 Playback Volume", RT5645_DAC1_DIG_VOL, |
483 | RT5645_L_VOL_SFT, RT5645_R_VOL_SFT, 175, 0, dac_vol_tlv), | 463 | RT5645_L_VOL_SFT + 1, RT5645_R_VOL_SFT + 1, 87, 0, dac_vol_tlv), |
484 | SOC_DOUBLE_TLV("Mono DAC Playback Volume", RT5645_DAC2_DIG_VOL, | 464 | SOC_DOUBLE_TLV("Mono DAC Playback Volume", RT5645_DAC2_DIG_VOL, |
485 | RT5645_L_VOL_SFT, RT5645_R_VOL_SFT, 175, 0, dac_vol_tlv), | 465 | RT5645_L_VOL_SFT + 1, RT5645_R_VOL_SFT + 1, 87, 0, dac_vol_tlv), |
486 | 466 | ||
487 | /* IN1/IN2 Control */ | 467 | /* IN1/IN2 Control */ |
488 | SOC_SINGLE_TLV("IN1 Boost", RT5645_IN1_CTRL1, | 468 | SOC_SINGLE_TLV("IN1 Boost", RT5645_IN1_CTRL1, |
@@ -498,11 +478,11 @@ static const struct snd_kcontrol_new rt5645_snd_controls[] = { | |||
498 | SOC_DOUBLE("ADC Capture Switch", RT5645_STO1_ADC_DIG_VOL, | 478 | SOC_DOUBLE("ADC Capture Switch", RT5645_STO1_ADC_DIG_VOL, |
499 | RT5645_L_MUTE_SFT, RT5645_R_MUTE_SFT, 1, 1), | 479 | RT5645_L_MUTE_SFT, RT5645_R_MUTE_SFT, 1, 1), |
500 | SOC_DOUBLE_TLV("ADC Capture Volume", RT5645_STO1_ADC_DIG_VOL, | 480 | SOC_DOUBLE_TLV("ADC Capture Volume", RT5645_STO1_ADC_DIG_VOL, |
501 | RT5645_L_VOL_SFT, RT5645_R_VOL_SFT, 127, 0, adc_vol_tlv), | 481 | RT5645_L_VOL_SFT + 1, RT5645_R_VOL_SFT + 1, 63, 0, adc_vol_tlv), |
502 | SOC_DOUBLE("Mono ADC Capture Switch", RT5645_MONO_ADC_DIG_VOL, | 482 | SOC_DOUBLE("Mono ADC Capture Switch", RT5645_MONO_ADC_DIG_VOL, |
503 | RT5645_L_MUTE_SFT, RT5645_R_MUTE_SFT, 1, 1), | 483 | RT5645_L_MUTE_SFT, RT5645_R_MUTE_SFT, 1, 1), |
504 | SOC_DOUBLE_TLV("Mono ADC Capture Volume", RT5645_MONO_ADC_DIG_VOL, | 484 | SOC_DOUBLE_TLV("Mono ADC Capture Volume", RT5645_MONO_ADC_DIG_VOL, |
505 | RT5645_L_VOL_SFT, RT5645_R_VOL_SFT, 127, 0, adc_vol_tlv), | 485 | RT5645_L_VOL_SFT + 1, RT5645_R_VOL_SFT + 1, 63, 0, adc_vol_tlv), |
506 | 486 | ||
507 | /* ADC Boost Volume Control */ | 487 | /* ADC Boost Volume Control */ |
508 | SOC_DOUBLE_TLV("STO1 ADC Boost Gain", RT5645_ADC_BST_VOL1, | 488 | SOC_DOUBLE_TLV("STO1 ADC Boost Gain", RT5645_ADC_BST_VOL1, |
@@ -515,17 +495,6 @@ static const struct snd_kcontrol_new rt5645_snd_controls[] = { | |||
515 | /* I2S2 function select */ | 495 | /* I2S2 function select */ |
516 | SOC_SINGLE("I2S2 Func Switch", RT5645_GPIO_CTRL1, RT5645_I2S2_SEL_SFT, | 496 | SOC_SINGLE("I2S2 Func Switch", RT5645_GPIO_CTRL1, RT5645_I2S2_SEL_SFT, |
517 | 1, 1), | 497 | 1, 1), |
518 | |||
519 | /* TDM */ | ||
520 | SOC_ENUM("TDM Adc Slot0 1 Data", rt5645_tdm_adc_slot0_1_enum), | ||
521 | SOC_ENUM("TDM Adc Slot2 3 Data", rt5645_tdm_adc_slot2_3_enum), | ||
522 | SOC_ENUM("TDM Adc Slot4 5 Data", rt5645_tdm_adc_slot4_5_enum), | ||
523 | SOC_ENUM("TDM Adc Slot6 7 Data", rt5645_tdm_adc_slot6_7_enum), | ||
524 | SOC_ENUM("TDM IF1 ADC DATA Sel", rt5645_tdm_adc_sel_enum), | ||
525 | SOC_SINGLE("TDM IF1_DAC1_L Sel", RT5645_TDM_CTRL_3, 12, 7, 0), | ||
526 | SOC_SINGLE("TDM IF1_DAC1_R Sel", RT5645_TDM_CTRL_3, 8, 7, 0), | ||
527 | SOC_SINGLE("TDM IF1_DAC2_L Sel", RT5645_TDM_CTRL_3, 4, 7, 0), | ||
528 | SOC_SINGLE("TDM IF1_DAC2_R Sel", RT5645_TDM_CTRL_3, 0, 7, 0), | ||
529 | }; | 498 | }; |
530 | 499 | ||
531 | /** | 500 | /** |
@@ -1092,7 +1061,8 @@ static const struct snd_kcontrol_new rt5645_mono_adc_r2_mux = | |||
1092 | 1061 | ||
1093 | /* MX-77 [9:8] */ | 1062 | /* MX-77 [9:8] */ |
1094 | static const char * const rt5645_if1_adc_in_src[] = { | 1063 | static const char * const rt5645_if1_adc_in_src[] = { |
1095 | "IF_ADC1", "IF_ADC2", "VAD_ADC" | 1064 | "IF_ADC1/IF_ADC2/VAD_ADC", "IF_ADC2/IF_ADC1/VAD_ADC", |
1065 | "VAD_ADC/IF_ADC1/IF_ADC2", "VAD_ADC/IF_ADC2/IF_ADC1" | ||
1096 | }; | 1066 | }; |
1097 | 1067 | ||
1098 | static SOC_ENUM_SINGLE_DECL( | 1068 | static SOC_ENUM_SINGLE_DECL( |
@@ -1102,6 +1072,140 @@ static SOC_ENUM_SINGLE_DECL( | |||
1102 | static const struct snd_kcontrol_new rt5645_if1_adc_in_mux = | 1072 | static const struct snd_kcontrol_new rt5645_if1_adc_in_mux = |
1103 | SOC_DAPM_ENUM("IF1 ADC IN source", rt5645_if1_adc_in_enum); | 1073 | SOC_DAPM_ENUM("IF1 ADC IN source", rt5645_if1_adc_in_enum); |
1104 | 1074 | ||
1075 | /* MX-78 [4:0] */ | ||
1076 | static const char * const rt5650_if1_adc_in_src[] = { | ||
1077 | "IF_ADC1/IF_ADC2/DAC_REF/Null", | ||
1078 | "IF_ADC1/IF_ADC2/Null/DAC_REF", | ||
1079 | "IF_ADC1/DAC_REF/IF_ADC2/Null", | ||
1080 | "IF_ADC1/DAC_REF/Null/IF_ADC2", | ||
1081 | "IF_ADC1/Null/DAC_REF/IF_ADC2", | ||
1082 | "IF_ADC1/Null/IF_ADC2/DAC_REF", | ||
1083 | |||
1084 | "IF_ADC2/IF_ADC1/DAC_REF/Null", | ||
1085 | "IF_ADC2/IF_ADC1/Null/DAC_REF", | ||
1086 | "IF_ADC2/DAC_REF/IF_ADC1/Null", | ||
1087 | "IF_ADC2/DAC_REF/Null/IF_ADC1", | ||
1088 | "IF_ADC2/Null/DAC_REF/IF_ADC1", | ||
1089 | "IF_ADC2/Null/IF_ADC1/DAC_REF", | ||
1090 | |||
1091 | "DAC_REF/IF_ADC1/IF_ADC2/Null", | ||
1092 | "DAC_REF/IF_ADC1/Null/IF_ADC2", | ||
1093 | "DAC_REF/IF_ADC2/IF_ADC1/Null", | ||
1094 | "DAC_REF/IF_ADC2/Null/IF_ADC1", | ||
1095 | "DAC_REF/Null/IF_ADC1/IF_ADC2", | ||
1096 | "DAC_REF/Null/IF_ADC2/IF_ADC1", | ||
1097 | |||
1098 | "Null/IF_ADC1/IF_ADC2/DAC_REF", | ||
1099 | "Null/IF_ADC1/DAC_REF/IF_ADC2", | ||
1100 | "Null/IF_ADC2/IF_ADC1/DAC_REF", | ||
1101 | "Null/IF_ADC2/DAC_REF/IF_ADC1", | ||
1102 | "Null/DAC_REF/IF_ADC1/IF_ADC2", | ||
1103 | "Null/DAC_REF/IF_ADC2/IF_ADC1", | ||
1104 | }; | ||
1105 | |||
1106 | static SOC_ENUM_SINGLE_DECL( | ||
1107 | rt5650_if1_adc_in_enum, RT5645_TDM_CTRL_2, | ||
1108 | 0, rt5650_if1_adc_in_src); | ||
1109 | |||
1110 | static const struct snd_kcontrol_new rt5650_if1_adc_in_mux = | ||
1111 | SOC_DAPM_ENUM("IF1 ADC IN source", rt5650_if1_adc_in_enum); | ||
1112 | |||
1113 | /* MX-78 [15:14][13:12][11:10] */ | ||
1114 | static const char * const rt5645_tdm_adc_swap_select[] = { | ||
1115 | "L/R", "R/L", "L/L", "R/R" | ||
1116 | }; | ||
1117 | |||
1118 | static SOC_ENUM_SINGLE_DECL(rt5650_tdm_adc_slot0_1_enum, | ||
1119 | RT5645_TDM_CTRL_2, 14, rt5645_tdm_adc_swap_select); | ||
1120 | |||
1121 | static const struct snd_kcontrol_new rt5650_if1_adc1_in_mux = | ||
1122 | SOC_DAPM_ENUM("IF1 ADC1 IN source", rt5650_tdm_adc_slot0_1_enum); | ||
1123 | |||
1124 | static SOC_ENUM_SINGLE_DECL(rt5650_tdm_adc_slot2_3_enum, | ||
1125 | RT5645_TDM_CTRL_2, 12, rt5645_tdm_adc_swap_select); | ||
1126 | |||
1127 | static const struct snd_kcontrol_new rt5650_if1_adc2_in_mux = | ||
1128 | SOC_DAPM_ENUM("IF1 ADC2 IN source", rt5650_tdm_adc_slot2_3_enum); | ||
1129 | |||
1130 | static SOC_ENUM_SINGLE_DECL(rt5650_tdm_adc_slot4_5_enum, | ||
1131 | RT5645_TDM_CTRL_2, 10, rt5645_tdm_adc_swap_select); | ||
1132 | |||
1133 | static const struct snd_kcontrol_new rt5650_if1_adc3_in_mux = | ||
1134 | SOC_DAPM_ENUM("IF1 ADC3 IN source", rt5650_tdm_adc_slot4_5_enum); | ||
1135 | |||
1136 | /* MX-77 [7:6][5:4][3:2] */ | ||
1137 | static SOC_ENUM_SINGLE_DECL(rt5645_tdm_adc_slot0_1_enum, | ||
1138 | RT5645_TDM_CTRL_1, 6, rt5645_tdm_adc_swap_select); | ||
1139 | |||
1140 | static const struct snd_kcontrol_new rt5645_if1_adc1_in_mux = | ||
1141 | SOC_DAPM_ENUM("IF1 ADC1 IN source", rt5645_tdm_adc_slot0_1_enum); | ||
1142 | |||
1143 | static SOC_ENUM_SINGLE_DECL(rt5645_tdm_adc_slot2_3_enum, | ||
1144 | RT5645_TDM_CTRL_1, 4, rt5645_tdm_adc_swap_select); | ||
1145 | |||
1146 | static const struct snd_kcontrol_new rt5645_if1_adc2_in_mux = | ||
1147 | SOC_DAPM_ENUM("IF1 ADC2 IN source", rt5645_tdm_adc_slot2_3_enum); | ||
1148 | |||
1149 | static SOC_ENUM_SINGLE_DECL(rt5645_tdm_adc_slot4_5_enum, | ||
1150 | RT5645_TDM_CTRL_1, 2, rt5645_tdm_adc_swap_select); | ||
1151 | |||
1152 | static const struct snd_kcontrol_new rt5645_if1_adc3_in_mux = | ||
1153 | SOC_DAPM_ENUM("IF1 ADC3 IN source", rt5645_tdm_adc_slot4_5_enum); | ||
1154 | |||
1155 | /* MX-79 [14:12][10:8][6:4][2:0] */ | ||
1156 | static const char * const rt5645_tdm_dac_swap_select[] = { | ||
1157 | "Slot0", "Slot1", "Slot2", "Slot3" | ||
1158 | }; | ||
1159 | |||
1160 | static SOC_ENUM_SINGLE_DECL(rt5645_tdm_dac0_enum, | ||
1161 | RT5645_TDM_CTRL_3, 12, rt5645_tdm_dac_swap_select); | ||
1162 | |||
1163 | static const struct snd_kcontrol_new rt5645_if1_dac0_tdm_sel_mux = | ||
1164 | SOC_DAPM_ENUM("IF1 DAC0 source", rt5645_tdm_dac0_enum); | ||
1165 | |||
1166 | static SOC_ENUM_SINGLE_DECL(rt5645_tdm_dac1_enum, | ||
1167 | RT5645_TDM_CTRL_3, 8, rt5645_tdm_dac_swap_select); | ||
1168 | |||
1169 | static const struct snd_kcontrol_new rt5645_if1_dac1_tdm_sel_mux = | ||
1170 | SOC_DAPM_ENUM("IF1 DAC1 source", rt5645_tdm_dac1_enum); | ||
1171 | |||
1172 | static SOC_ENUM_SINGLE_DECL(rt5645_tdm_dac2_enum, | ||
1173 | RT5645_TDM_CTRL_3, 4, rt5645_tdm_dac_swap_select); | ||
1174 | |||
1175 | static const struct snd_kcontrol_new rt5645_if1_dac2_tdm_sel_mux = | ||
1176 | SOC_DAPM_ENUM("IF1 DAC2 source", rt5645_tdm_dac2_enum); | ||
1177 | |||
1178 | static SOC_ENUM_SINGLE_DECL(rt5645_tdm_dac3_enum, | ||
1179 | RT5645_TDM_CTRL_3, 0, rt5645_tdm_dac_swap_select); | ||
1180 | |||
1181 | static const struct snd_kcontrol_new rt5645_if1_dac3_tdm_sel_mux = | ||
1182 | SOC_DAPM_ENUM("IF1 DAC3 source", rt5645_tdm_dac3_enum); | ||
1183 | |||
1184 | /* MX-7a [14:12][10:8][6:4][2:0] */ | ||
1185 | static SOC_ENUM_SINGLE_DECL(rt5650_tdm_dac0_enum, | ||
1186 | RT5650_TDM_CTRL_4, 12, rt5645_tdm_dac_swap_select); | ||
1187 | |||
1188 | static const struct snd_kcontrol_new rt5650_if1_dac0_tdm_sel_mux = | ||
1189 | SOC_DAPM_ENUM("IF1 DAC0 source", rt5650_tdm_dac0_enum); | ||
1190 | |||
1191 | static SOC_ENUM_SINGLE_DECL(rt5650_tdm_dac1_enum, | ||
1192 | RT5650_TDM_CTRL_4, 8, rt5645_tdm_dac_swap_select); | ||
1193 | |||
1194 | static const struct snd_kcontrol_new rt5650_if1_dac1_tdm_sel_mux = | ||
1195 | SOC_DAPM_ENUM("IF1 DAC1 source", rt5650_tdm_dac1_enum); | ||
1196 | |||
1197 | static SOC_ENUM_SINGLE_DECL(rt5650_tdm_dac2_enum, | ||
1198 | RT5650_TDM_CTRL_4, 4, rt5645_tdm_dac_swap_select); | ||
1199 | |||
1200 | static const struct snd_kcontrol_new rt5650_if1_dac2_tdm_sel_mux = | ||
1201 | SOC_DAPM_ENUM("IF1 DAC2 source", rt5650_tdm_dac2_enum); | ||
1202 | |||
1203 | static SOC_ENUM_SINGLE_DECL(rt5650_tdm_dac3_enum, | ||
1204 | RT5650_TDM_CTRL_4, 0, rt5645_tdm_dac_swap_select); | ||
1205 | |||
1206 | static const struct snd_kcontrol_new rt5650_if1_dac3_tdm_sel_mux = | ||
1207 | SOC_DAPM_ENUM("IF1 DAC3 source", rt5650_tdm_dac3_enum); | ||
1208 | |||
1105 | /* MX-2d [3] [2] */ | 1209 | /* MX-2d [3] [2] */ |
1106 | static const char * const rt5650_a_dac1_src[] = { | 1210 | static const char * const rt5650_a_dac1_src[] = { |
1107 | "DAC1", "Stereo DAC Mixer" | 1211 | "DAC1", "Stereo DAC Mixer" |
@@ -1226,52 +1330,79 @@ static void hp_amp_power(struct snd_soc_codec *codec, int on) | |||
1226 | 1330 | ||
1227 | if (on) { | 1331 | if (on) { |
1228 | if (hp_amp_power_count <= 0) { | 1332 | if (hp_amp_power_count <= 0) { |
1229 | /* depop parameters */ | 1333 | if (rt5645->codec_type == CODEC_TYPE_RT5650) { |
1230 | snd_soc_update_bits(codec, RT5645_DEPOP_M2, | 1334 | snd_soc_write(codec, RT5645_CHARGE_PUMP, |
1231 | RT5645_DEPOP_MASK, RT5645_DEPOP_MAN); | 1335 | 0x0e06); |
1232 | snd_soc_write(codec, RT5645_DEPOP_M1, 0x000d); | 1336 | snd_soc_write(codec, RT5645_DEPOP_M1, 0x001d); |
1233 | regmap_write(rt5645->regmap, RT5645_PR_BASE + | 1337 | regmap_write(rt5645->regmap, RT5645_PR_BASE + |
1234 | RT5645_HP_DCC_INT1, 0x9f01); | 1338 | 0x3e, 0x7400); |
1235 | mdelay(150); | 1339 | snd_soc_write(codec, RT5645_DEPOP_M3, 0x0737); |
1236 | /* headphone amp power on */ | 1340 | regmap_write(rt5645->regmap, RT5645_PR_BASE + |
1237 | snd_soc_update_bits(codec, RT5645_PWR_ANLG1, | 1341 | RT5645_MAMP_INT_REG2, 0xfc00); |
1238 | RT5645_PWR_FV1 | RT5645_PWR_FV2 , 0); | 1342 | snd_soc_write(codec, RT5645_DEPOP_M2, 0x1140); |
1239 | snd_soc_update_bits(codec, RT5645_PWR_VOL, | 1343 | } else { |
1240 | RT5645_PWR_HV_L | RT5645_PWR_HV_R, | 1344 | /* depop parameters */ |
1241 | RT5645_PWR_HV_L | RT5645_PWR_HV_R); | 1345 | snd_soc_update_bits(codec, RT5645_DEPOP_M2, |
1242 | snd_soc_update_bits(codec, RT5645_PWR_ANLG1, | 1346 | RT5645_DEPOP_MASK, RT5645_DEPOP_MAN); |
1243 | RT5645_PWR_HP_L | RT5645_PWR_HP_R | | 1347 | snd_soc_write(codec, RT5645_DEPOP_M1, 0x000d); |
1244 | RT5645_PWR_HA, | 1348 | regmap_write(rt5645->regmap, RT5645_PR_BASE + |
1245 | RT5645_PWR_HP_L | RT5645_PWR_HP_R | | 1349 | RT5645_HP_DCC_INT1, 0x9f01); |
1246 | RT5645_PWR_HA); | 1350 | mdelay(150); |
1247 | mdelay(5); | 1351 | /* headphone amp power on */ |
1248 | snd_soc_update_bits(codec, RT5645_PWR_ANLG1, | 1352 | snd_soc_update_bits(codec, RT5645_PWR_ANLG1, |
1249 | RT5645_PWR_FV1 | RT5645_PWR_FV2, | 1353 | RT5645_PWR_FV1 | RT5645_PWR_FV2, 0); |
1250 | RT5645_PWR_FV1 | RT5645_PWR_FV2); | 1354 | snd_soc_update_bits(codec, RT5645_PWR_VOL, |
1251 | 1355 | RT5645_PWR_HV_L | RT5645_PWR_HV_R, | |
1252 | snd_soc_update_bits(codec, RT5645_DEPOP_M1, | 1356 | RT5645_PWR_HV_L | RT5645_PWR_HV_R); |
1253 | RT5645_HP_CO_MASK | RT5645_HP_SG_MASK, | 1357 | snd_soc_update_bits(codec, RT5645_PWR_ANLG1, |
1254 | RT5645_HP_CO_EN | RT5645_HP_SG_EN); | 1358 | RT5645_PWR_HP_L | RT5645_PWR_HP_R | |
1255 | regmap_write(rt5645->regmap, RT5645_PR_BASE + | 1359 | RT5645_PWR_HA, |
1256 | 0x14, 0x1aaa); | 1360 | RT5645_PWR_HP_L | RT5645_PWR_HP_R | |
1257 | regmap_write(rt5645->regmap, RT5645_PR_BASE + | 1361 | RT5645_PWR_HA); |
1258 | 0x24, 0x0430); | 1362 | mdelay(5); |
1363 | snd_soc_update_bits(codec, RT5645_PWR_ANLG1, | ||
1364 | RT5645_PWR_FV1 | RT5645_PWR_FV2, | ||
1365 | RT5645_PWR_FV1 | RT5645_PWR_FV2); | ||
1366 | |||
1367 | snd_soc_update_bits(codec, RT5645_DEPOP_M1, | ||
1368 | RT5645_HP_CO_MASK | RT5645_HP_SG_MASK, | ||
1369 | RT5645_HP_CO_EN | RT5645_HP_SG_EN); | ||
1370 | regmap_write(rt5645->regmap, RT5645_PR_BASE + | ||
1371 | 0x14, 0x1aaa); | ||
1372 | regmap_write(rt5645->regmap, RT5645_PR_BASE + | ||
1373 | 0x24, 0x0430); | ||
1374 | } | ||
1259 | } | 1375 | } |
1260 | hp_amp_power_count++; | 1376 | hp_amp_power_count++; |
1261 | } else { | 1377 | } else { |
1262 | hp_amp_power_count--; | 1378 | hp_amp_power_count--; |
1263 | if (hp_amp_power_count <= 0) { | 1379 | if (hp_amp_power_count <= 0) { |
1264 | snd_soc_update_bits(codec, RT5645_DEPOP_M1, | 1380 | if (rt5645->codec_type == CODEC_TYPE_RT5650) { |
1265 | RT5645_HP_SG_MASK | RT5645_HP_L_SMT_MASK | | 1381 | regmap_write(rt5645->regmap, RT5645_PR_BASE + |
1266 | RT5645_HP_R_SMT_MASK, RT5645_HP_SG_DIS | | 1382 | 0x3e, 0x7400); |
1267 | RT5645_HP_L_SMT_DIS | RT5645_HP_R_SMT_DIS); | 1383 | snd_soc_write(codec, RT5645_DEPOP_M3, 0x0737); |
1268 | /* headphone amp power down */ | 1384 | regmap_write(rt5645->regmap, RT5645_PR_BASE + |
1269 | snd_soc_write(codec, RT5645_DEPOP_M1, 0x0000); | 1385 | RT5645_MAMP_INT_REG2, 0xfc00); |
1270 | snd_soc_update_bits(codec, RT5645_PWR_ANLG1, | 1386 | snd_soc_write(codec, RT5645_DEPOP_M2, 0x1140); |
1271 | RT5645_PWR_HP_L | RT5645_PWR_HP_R | | 1387 | msleep(100); |
1272 | RT5645_PWR_HA, 0); | 1388 | snd_soc_write(codec, RT5645_DEPOP_M1, 0x0001); |
1273 | snd_soc_update_bits(codec, RT5645_DEPOP_M2, | 1389 | |
1274 | RT5645_DEPOP_MASK, 0); | 1390 | } else { |
1391 | snd_soc_update_bits(codec, RT5645_DEPOP_M1, | ||
1392 | RT5645_HP_SG_MASK | | ||
1393 | RT5645_HP_L_SMT_MASK | | ||
1394 | RT5645_HP_R_SMT_MASK, | ||
1395 | RT5645_HP_SG_DIS | | ||
1396 | RT5645_HP_L_SMT_DIS | | ||
1397 | RT5645_HP_R_SMT_DIS); | ||
1398 | /* headphone amp power down */ | ||
1399 | snd_soc_write(codec, RT5645_DEPOP_M1, 0x0000); | ||
1400 | snd_soc_update_bits(codec, RT5645_PWR_ANLG1, | ||
1401 | RT5645_PWR_HP_L | RT5645_PWR_HP_R | | ||
1402 | RT5645_PWR_HA, 0); | ||
1403 | snd_soc_update_bits(codec, RT5645_DEPOP_M2, | ||
1404 | RT5645_DEPOP_MASK, 0); | ||
1405 | } | ||
1275 | } | 1406 | } |
1276 | } | 1407 | } |
1277 | } | 1408 | } |
@@ -1286,56 +1417,52 @@ static int rt5645_hp_event(struct snd_soc_dapm_widget *w, | |||
1286 | case SND_SOC_DAPM_POST_PMU: | 1417 | case SND_SOC_DAPM_POST_PMU: |
1287 | hp_amp_power(codec, 1); | 1418 | hp_amp_power(codec, 1); |
1288 | /* headphone unmute sequence */ | 1419 | /* headphone unmute sequence */ |
1289 | if (rt5645->codec_type == CODEC_TYPE_RT5650) { | 1420 | if (rt5645->codec_type == CODEC_TYPE_RT5645) { |
1290 | snd_soc_write(codec, RT5645_DEPOP_M3, 0x0737); | ||
1291 | } else { | ||
1292 | snd_soc_update_bits(codec, RT5645_DEPOP_M3, | 1421 | snd_soc_update_bits(codec, RT5645_DEPOP_M3, |
1293 | RT5645_CP_FQ1_MASK | RT5645_CP_FQ2_MASK | | 1422 | RT5645_CP_FQ1_MASK | RT5645_CP_FQ2_MASK | |
1294 | RT5645_CP_FQ3_MASK, | 1423 | RT5645_CP_FQ3_MASK, |
1295 | (RT5645_CP_FQ_192_KHZ << RT5645_CP_FQ1_SFT) | | 1424 | (RT5645_CP_FQ_192_KHZ << RT5645_CP_FQ1_SFT) | |
1296 | (RT5645_CP_FQ_12_KHZ << RT5645_CP_FQ2_SFT) | | 1425 | (RT5645_CP_FQ_12_KHZ << RT5645_CP_FQ2_SFT) | |
1297 | (RT5645_CP_FQ_192_KHZ << RT5645_CP_FQ3_SFT)); | 1426 | (RT5645_CP_FQ_192_KHZ << RT5645_CP_FQ3_SFT)); |
1427 | regmap_write(rt5645->regmap, RT5645_PR_BASE + | ||
1428 | RT5645_MAMP_INT_REG2, 0xfc00); | ||
1429 | snd_soc_update_bits(codec, RT5645_DEPOP_M1, | ||
1430 | RT5645_SMT_TRIG_MASK, RT5645_SMT_TRIG_EN); | ||
1431 | snd_soc_update_bits(codec, RT5645_DEPOP_M1, | ||
1432 | RT5645_RSTN_MASK, RT5645_RSTN_EN); | ||
1433 | snd_soc_update_bits(codec, RT5645_DEPOP_M1, | ||
1434 | RT5645_RSTN_MASK | RT5645_HP_L_SMT_MASK | | ||
1435 | RT5645_HP_R_SMT_MASK, RT5645_RSTN_DIS | | ||
1436 | RT5645_HP_L_SMT_EN | RT5645_HP_R_SMT_EN); | ||
1437 | msleep(40); | ||
1438 | snd_soc_update_bits(codec, RT5645_DEPOP_M1, | ||
1439 | RT5645_HP_SG_MASK | RT5645_HP_L_SMT_MASK | | ||
1440 | RT5645_HP_R_SMT_MASK, RT5645_HP_SG_DIS | | ||
1441 | RT5645_HP_L_SMT_DIS | RT5645_HP_R_SMT_DIS); | ||
1298 | } | 1442 | } |
1299 | regmap_write(rt5645->regmap, | ||
1300 | RT5645_PR_BASE + RT5645_MAMP_INT_REG2, 0xfc00); | ||
1301 | snd_soc_update_bits(codec, RT5645_DEPOP_M1, | ||
1302 | RT5645_SMT_TRIG_MASK, RT5645_SMT_TRIG_EN); | ||
1303 | snd_soc_update_bits(codec, RT5645_DEPOP_M1, | ||
1304 | RT5645_RSTN_MASK, RT5645_RSTN_EN); | ||
1305 | snd_soc_update_bits(codec, RT5645_DEPOP_M1, | ||
1306 | RT5645_RSTN_MASK | RT5645_HP_L_SMT_MASK | | ||
1307 | RT5645_HP_R_SMT_MASK, RT5645_RSTN_DIS | | ||
1308 | RT5645_HP_L_SMT_EN | RT5645_HP_R_SMT_EN); | ||
1309 | msleep(40); | ||
1310 | snd_soc_update_bits(codec, RT5645_DEPOP_M1, | ||
1311 | RT5645_HP_SG_MASK | RT5645_HP_L_SMT_MASK | | ||
1312 | RT5645_HP_R_SMT_MASK, RT5645_HP_SG_DIS | | ||
1313 | RT5645_HP_L_SMT_DIS | RT5645_HP_R_SMT_DIS); | ||
1314 | break; | 1443 | break; |
1315 | 1444 | ||
1316 | case SND_SOC_DAPM_PRE_PMD: | 1445 | case SND_SOC_DAPM_PRE_PMD: |
1317 | /* headphone mute sequence */ | 1446 | /* headphone mute sequence */ |
1318 | if (rt5645->codec_type == CODEC_TYPE_RT5650) { | 1447 | if (rt5645->codec_type == CODEC_TYPE_RT5645) { |
1319 | snd_soc_write(codec, RT5645_DEPOP_M3, 0x0737); | ||
1320 | } else { | ||
1321 | snd_soc_update_bits(codec, RT5645_DEPOP_M3, | 1448 | snd_soc_update_bits(codec, RT5645_DEPOP_M3, |
1322 | RT5645_CP_FQ1_MASK | RT5645_CP_FQ2_MASK | | 1449 | RT5645_CP_FQ1_MASK | RT5645_CP_FQ2_MASK | |
1323 | RT5645_CP_FQ3_MASK, | 1450 | RT5645_CP_FQ3_MASK, |
1324 | (RT5645_CP_FQ_96_KHZ << RT5645_CP_FQ1_SFT) | | 1451 | (RT5645_CP_FQ_96_KHZ << RT5645_CP_FQ1_SFT) | |
1325 | (RT5645_CP_FQ_12_KHZ << RT5645_CP_FQ2_SFT) | | 1452 | (RT5645_CP_FQ_12_KHZ << RT5645_CP_FQ2_SFT) | |
1326 | (RT5645_CP_FQ_96_KHZ << RT5645_CP_FQ3_SFT)); | 1453 | (RT5645_CP_FQ_96_KHZ << RT5645_CP_FQ3_SFT)); |
1454 | regmap_write(rt5645->regmap, RT5645_PR_BASE + | ||
1455 | RT5645_MAMP_INT_REG2, 0xfc00); | ||
1456 | snd_soc_update_bits(codec, RT5645_DEPOP_M1, | ||
1457 | RT5645_HP_SG_MASK, RT5645_HP_SG_EN); | ||
1458 | snd_soc_update_bits(codec, RT5645_DEPOP_M1, | ||
1459 | RT5645_RSTP_MASK, RT5645_RSTP_EN); | ||
1460 | snd_soc_update_bits(codec, RT5645_DEPOP_M1, | ||
1461 | RT5645_RSTP_MASK | RT5645_HP_L_SMT_MASK | | ||
1462 | RT5645_HP_R_SMT_MASK, RT5645_RSTP_DIS | | ||
1463 | RT5645_HP_L_SMT_EN | RT5645_HP_R_SMT_EN); | ||
1464 | msleep(30); | ||
1327 | } | 1465 | } |
1328 | regmap_write(rt5645->regmap, | ||
1329 | RT5645_PR_BASE + RT5645_MAMP_INT_REG2, 0xfc00); | ||
1330 | snd_soc_update_bits(codec, RT5645_DEPOP_M1, | ||
1331 | RT5645_HP_SG_MASK, RT5645_HP_SG_EN); | ||
1332 | snd_soc_update_bits(codec, RT5645_DEPOP_M1, | ||
1333 | RT5645_RSTP_MASK, RT5645_RSTP_EN); | ||
1334 | snd_soc_update_bits(codec, RT5645_DEPOP_M1, | ||
1335 | RT5645_RSTP_MASK | RT5645_HP_L_SMT_MASK | | ||
1336 | RT5645_HP_R_SMT_MASK, RT5645_RSTP_DIS | | ||
1337 | RT5645_HP_L_SMT_EN | RT5645_HP_R_SMT_EN); | ||
1338 | msleep(30); | ||
1339 | hp_amp_power(codec, 0); | 1466 | hp_amp_power(codec, 0); |
1340 | break; | 1467 | break; |
1341 | 1468 | ||
@@ -1570,20 +1697,33 @@ static const struct snd_soc_dapm_widget rt5645_dapm_widgets[] = { | |||
1570 | SND_SOC_DAPM_PGA("IF1_ADC4", SND_SOC_NOPM, 0, 0, NULL, 0), | 1697 | SND_SOC_DAPM_PGA("IF1_ADC4", SND_SOC_NOPM, 0, 0, NULL, 0), |
1571 | 1698 | ||
1572 | /* IF1 2 Mux */ | 1699 | /* IF1 2 Mux */ |
1573 | SND_SOC_DAPM_MUX("IF1 ADC Mux", SND_SOC_NOPM, | 1700 | SND_SOC_DAPM_MUX("RT5645 IF1 ADC1 Swap Mux", SND_SOC_NOPM, |
1701 | 0, 0, &rt5645_if1_adc1_in_mux), | ||
1702 | SND_SOC_DAPM_MUX("RT5645 IF1 ADC2 Swap Mux", SND_SOC_NOPM, | ||
1703 | 0, 0, &rt5645_if1_adc2_in_mux), | ||
1704 | SND_SOC_DAPM_MUX("RT5645 IF1 ADC3 Swap Mux", SND_SOC_NOPM, | ||
1705 | 0, 0, &rt5645_if1_adc3_in_mux), | ||
1706 | SND_SOC_DAPM_MUX("RT5645 IF1 ADC Mux", SND_SOC_NOPM, | ||
1574 | 0, 0, &rt5645_if1_adc_in_mux), | 1707 | 0, 0, &rt5645_if1_adc_in_mux), |
1708 | |||
1575 | SND_SOC_DAPM_MUX("IF2 ADC Mux", SND_SOC_NOPM, | 1709 | SND_SOC_DAPM_MUX("IF2 ADC Mux", SND_SOC_NOPM, |
1576 | 0, 0, &rt5645_if2_adc_in_mux), | 1710 | 0, 0, &rt5645_if2_adc_in_mux), |
1577 | 1711 | ||
1578 | /* Digital Interface */ | 1712 | /* Digital Interface */ |
1579 | SND_SOC_DAPM_SUPPLY("I2S1", RT5645_PWR_DIG1, | 1713 | SND_SOC_DAPM_SUPPLY("I2S1", RT5645_PWR_DIG1, |
1580 | RT5645_PWR_I2S1_BIT, 0, NULL, 0), | 1714 | RT5645_PWR_I2S1_BIT, 0, NULL, 0), |
1715 | SND_SOC_DAPM_PGA("IF1 DAC0", SND_SOC_NOPM, 0, 0, NULL, 0), | ||
1581 | SND_SOC_DAPM_PGA("IF1 DAC1", SND_SOC_NOPM, 0, 0, NULL, 0), | 1716 | SND_SOC_DAPM_PGA("IF1 DAC1", SND_SOC_NOPM, 0, 0, NULL, 0), |
1582 | SND_SOC_DAPM_PGA("IF1 DAC2", SND_SOC_NOPM, 0, 0, NULL, 0), | 1717 | SND_SOC_DAPM_PGA("IF1 DAC2", SND_SOC_NOPM, 0, 0, NULL, 0), |
1583 | SND_SOC_DAPM_PGA("IF1 DAC1 L", SND_SOC_NOPM, 0, 0, NULL, 0), | 1718 | SND_SOC_DAPM_PGA("IF1 DAC3", SND_SOC_NOPM, 0, 0, NULL, 0), |
1584 | SND_SOC_DAPM_PGA("IF1 DAC1 R", SND_SOC_NOPM, 0, 0, NULL, 0), | 1719 | SND_SOC_DAPM_MUX("RT5645 IF1 DAC1 L Mux", SND_SOC_NOPM, 0, 0, |
1585 | SND_SOC_DAPM_PGA("IF1 DAC2 L", SND_SOC_NOPM, 0, 0, NULL, 0), | 1720 | &rt5645_if1_dac0_tdm_sel_mux), |
1586 | SND_SOC_DAPM_PGA("IF1 DAC2 R", SND_SOC_NOPM, 0, 0, NULL, 0), | 1721 | SND_SOC_DAPM_MUX("RT5645 IF1 DAC1 R Mux", SND_SOC_NOPM, 0, 0, |
1722 | &rt5645_if1_dac1_tdm_sel_mux), | ||
1723 | SND_SOC_DAPM_MUX("RT5645 IF1 DAC2 L Mux", SND_SOC_NOPM, 0, 0, | ||
1724 | &rt5645_if1_dac2_tdm_sel_mux), | ||
1725 | SND_SOC_DAPM_MUX("RT5645 IF1 DAC2 R Mux", SND_SOC_NOPM, 0, 0, | ||
1726 | &rt5645_if1_dac3_tdm_sel_mux), | ||
1587 | SND_SOC_DAPM_PGA("IF1 ADC", SND_SOC_NOPM, 0, 0, NULL, 0), | 1727 | SND_SOC_DAPM_PGA("IF1 ADC", SND_SOC_NOPM, 0, 0, NULL, 0), |
1588 | SND_SOC_DAPM_PGA("IF1 ADC L", SND_SOC_NOPM, 0, 0, NULL, 0), | 1728 | SND_SOC_DAPM_PGA("IF1 ADC L", SND_SOC_NOPM, 0, 0, NULL, 0), |
1589 | SND_SOC_DAPM_PGA("IF1 ADC R", SND_SOC_NOPM, 0, 0, NULL, 0), | 1729 | SND_SOC_DAPM_PGA("IF1 ADC R", SND_SOC_NOPM, 0, 0, NULL, 0), |
@@ -1725,6 +1865,24 @@ static const struct snd_soc_dapm_widget rt5650_specific_dapm_widgets[] = { | |||
1725 | 0, 0, &rt5650_a_dac2_l_mux), | 1865 | 0, 0, &rt5650_a_dac2_l_mux), |
1726 | SND_SOC_DAPM_MUX("A DAC2 R Mux", SND_SOC_NOPM, | 1866 | SND_SOC_DAPM_MUX("A DAC2 R Mux", SND_SOC_NOPM, |
1727 | 0, 0, &rt5650_a_dac2_r_mux), | 1867 | 0, 0, &rt5650_a_dac2_r_mux), |
1868 | |||
1869 | SND_SOC_DAPM_MUX("RT5650 IF1 ADC1 Swap Mux", SND_SOC_NOPM, | ||
1870 | 0, 0, &rt5650_if1_adc1_in_mux), | ||
1871 | SND_SOC_DAPM_MUX("RT5650 IF1 ADC2 Swap Mux", SND_SOC_NOPM, | ||
1872 | 0, 0, &rt5650_if1_adc2_in_mux), | ||
1873 | SND_SOC_DAPM_MUX("RT5650 IF1 ADC3 Swap Mux", SND_SOC_NOPM, | ||
1874 | 0, 0, &rt5650_if1_adc3_in_mux), | ||
1875 | SND_SOC_DAPM_MUX("RT5650 IF1 ADC Mux", SND_SOC_NOPM, | ||
1876 | 0, 0, &rt5650_if1_adc_in_mux), | ||
1877 | |||
1878 | SND_SOC_DAPM_MUX("RT5650 IF1 DAC1 L Mux", SND_SOC_NOPM, 0, 0, | ||
1879 | &rt5650_if1_dac0_tdm_sel_mux), | ||
1880 | SND_SOC_DAPM_MUX("RT5650 IF1 DAC1 R Mux", SND_SOC_NOPM, 0, 0, | ||
1881 | &rt5650_if1_dac1_tdm_sel_mux), | ||
1882 | SND_SOC_DAPM_MUX("RT5650 IF1 DAC2 L Mux", SND_SOC_NOPM, 0, 0, | ||
1883 | &rt5650_if1_dac2_tdm_sel_mux), | ||
1884 | SND_SOC_DAPM_MUX("RT5650 IF1 DAC2 R Mux", SND_SOC_NOPM, 0, 0, | ||
1885 | &rt5650_if1_dac3_tdm_sel_mux), | ||
1728 | }; | 1886 | }; |
1729 | 1887 | ||
1730 | static const struct snd_soc_dapm_route rt5645_dapm_routes[] = { | 1888 | static const struct snd_soc_dapm_route rt5645_dapm_routes[] = { |
@@ -1847,42 +2005,32 @@ static const struct snd_soc_dapm_route rt5645_dapm_routes[] = { | |||
1847 | { "IF_ADC2", NULL, "Mono ADC MIXR" }, | 2005 | { "IF_ADC2", NULL, "Mono ADC MIXR" }, |
1848 | { "VAD_ADC", NULL, "VAD ADC Mux" }, | 2006 | { "VAD_ADC", NULL, "VAD ADC Mux" }, |
1849 | 2007 | ||
1850 | { "IF1 ADC Mux", "IF_ADC1", "IF_ADC1" }, | ||
1851 | { "IF1 ADC Mux", "IF_ADC2", "IF_ADC2" }, | ||
1852 | { "IF1 ADC Mux", "VAD_ADC", "VAD_ADC" }, | ||
1853 | |||
1854 | { "IF2 ADC Mux", "IF_ADC1", "IF_ADC1" }, | 2008 | { "IF2 ADC Mux", "IF_ADC1", "IF_ADC1" }, |
1855 | { "IF2 ADC Mux", "IF_ADC2", "IF_ADC2" }, | 2009 | { "IF2 ADC Mux", "IF_ADC2", "IF_ADC2" }, |
1856 | { "IF2 ADC Mux", "VAD_ADC", "VAD_ADC" }, | 2010 | { "IF2 ADC Mux", "VAD_ADC", "VAD_ADC" }, |
1857 | 2011 | ||
1858 | { "IF1 ADC", NULL, "I2S1" }, | 2012 | { "IF1 ADC", NULL, "I2S1" }, |
1859 | { "IF1 ADC", NULL, "IF1 ADC Mux" }, | ||
1860 | { "IF2 ADC", NULL, "I2S2" }, | 2013 | { "IF2 ADC", NULL, "I2S2" }, |
1861 | { "IF2 ADC", NULL, "IF2 ADC Mux" }, | 2014 | { "IF2 ADC", NULL, "IF2 ADC Mux" }, |
1862 | 2015 | ||
1863 | { "AIF1TX", NULL, "IF1 ADC" }, | ||
1864 | { "AIF1TX", NULL, "IF2 ADC" }, | ||
1865 | { "AIF2TX", NULL, "IF2 ADC" }, | 2016 | { "AIF2TX", NULL, "IF2 ADC" }, |
1866 | 2017 | ||
2018 | { "IF1 DAC0", NULL, "AIF1RX" }, | ||
1867 | { "IF1 DAC1", NULL, "AIF1RX" }, | 2019 | { "IF1 DAC1", NULL, "AIF1RX" }, |
1868 | { "IF1 DAC2", NULL, "AIF1RX" }, | 2020 | { "IF1 DAC2", NULL, "AIF1RX" }, |
2021 | { "IF1 DAC3", NULL, "AIF1RX" }, | ||
1869 | { "IF2 DAC", NULL, "AIF2RX" }, | 2022 | { "IF2 DAC", NULL, "AIF2RX" }, |
1870 | 2023 | ||
2024 | { "IF1 DAC0", NULL, "I2S1" }, | ||
1871 | { "IF1 DAC1", NULL, "I2S1" }, | 2025 | { "IF1 DAC1", NULL, "I2S1" }, |
1872 | { "IF1 DAC2", NULL, "I2S1" }, | 2026 | { "IF1 DAC2", NULL, "I2S1" }, |
2027 | { "IF1 DAC3", NULL, "I2S1" }, | ||
1873 | { "IF2 DAC", NULL, "I2S2" }, | 2028 | { "IF2 DAC", NULL, "I2S2" }, |
1874 | 2029 | ||
1875 | { "IF1 DAC2 L", NULL, "IF1 DAC2" }, | ||
1876 | { "IF1 DAC2 R", NULL, "IF1 DAC2" }, | ||
1877 | { "IF1 DAC1 L", NULL, "IF1 DAC1" }, | ||
1878 | { "IF1 DAC1 R", NULL, "IF1 DAC1" }, | ||
1879 | { "IF2 DAC L", NULL, "IF2 DAC" }, | 2030 | { "IF2 DAC L", NULL, "IF2 DAC" }, |
1880 | { "IF2 DAC R", NULL, "IF2 DAC" }, | 2031 | { "IF2 DAC R", NULL, "IF2 DAC" }, |
1881 | 2032 | ||
1882 | { "DAC1 L Mux", "IF1 DAC", "IF1 DAC1 L" }, | ||
1883 | { "DAC1 L Mux", "IF2 DAC", "IF2 DAC L" }, | 2033 | { "DAC1 L Mux", "IF2 DAC", "IF2 DAC L" }, |
1884 | |||
1885 | { "DAC1 R Mux", "IF1 DAC", "IF1 DAC1 R" }, | ||
1886 | { "DAC1 R Mux", "IF2 DAC", "IF2 DAC R" }, | 2034 | { "DAC1 R Mux", "IF2 DAC", "IF2 DAC R" }, |
1887 | 2035 | ||
1888 | { "DAC1 MIXL", "Stereo ADC Switch", "Stereo1 ADC MIXL" }, | 2036 | { "DAC1 MIXL", "Stereo ADC Switch", "Stereo1 ADC MIXL" }, |
@@ -1892,14 +2040,12 @@ static const struct snd_soc_dapm_route rt5645_dapm_routes[] = { | |||
1892 | { "DAC1 MIXR", "DAC1 Switch", "DAC1 R Mux" }, | 2040 | { "DAC1 MIXR", "DAC1 Switch", "DAC1 R Mux" }, |
1893 | { "DAC1 MIXR", NULL, "dac stereo1 filter" }, | 2041 | { "DAC1 MIXR", NULL, "dac stereo1 filter" }, |
1894 | 2042 | ||
1895 | { "DAC L2 Mux", "IF1 DAC", "IF1 DAC2 L" }, | ||
1896 | { "DAC L2 Mux", "IF2 DAC", "IF2 DAC L" }, | 2043 | { "DAC L2 Mux", "IF2 DAC", "IF2 DAC L" }, |
1897 | { "DAC L2 Mux", "Mono ADC", "Mono ADC MIXL" }, | 2044 | { "DAC L2 Mux", "Mono ADC", "Mono ADC MIXL" }, |
1898 | { "DAC L2 Mux", "VAD_ADC", "VAD_ADC" }, | 2045 | { "DAC L2 Mux", "VAD_ADC", "VAD_ADC" }, |
1899 | { "DAC L2 Volume", NULL, "DAC L2 Mux" }, | 2046 | { "DAC L2 Volume", NULL, "DAC L2 Mux" }, |
1900 | { "DAC L2 Volume", NULL, "dac mono left filter" }, | 2047 | { "DAC L2 Volume", NULL, "dac mono left filter" }, |
1901 | 2048 | ||
1902 | { "DAC R2 Mux", "IF1 DAC", "IF1 DAC2 R" }, | ||
1903 | { "DAC R2 Mux", "IF2 DAC", "IF2 DAC R" }, | 2049 | { "DAC R2 Mux", "IF2 DAC", "IF2 DAC R" }, |
1904 | { "DAC R2 Mux", "Mono ADC", "Mono ADC MIXR" }, | 2050 | { "DAC R2 Mux", "Mono ADC", "Mono ADC MIXR" }, |
1905 | { "DAC R2 Mux", "Haptic", "Haptic Generator" }, | 2051 | { "DAC R2 Mux", "Haptic", "Haptic Generator" }, |
@@ -2037,6 +2183,80 @@ static const struct snd_soc_dapm_route rt5650_specific_dapm_routes[] = { | |||
2037 | { "DAC R1", NULL, "A DAC1 R Mux" }, | 2183 | { "DAC R1", NULL, "A DAC1 R Mux" }, |
2038 | { "DAC L2", NULL, "A DAC2 L Mux" }, | 2184 | { "DAC L2", NULL, "A DAC2 L Mux" }, |
2039 | { "DAC R2", NULL, "A DAC2 R Mux" }, | 2185 | { "DAC R2", NULL, "A DAC2 R Mux" }, |
2186 | |||
2187 | { "RT5650 IF1 ADC1 Swap Mux", "L/R", "IF_ADC1" }, | ||
2188 | { "RT5650 IF1 ADC1 Swap Mux", "R/L", "IF_ADC1" }, | ||
2189 | { "RT5650 IF1 ADC1 Swap Mux", "L/L", "IF_ADC1" }, | ||
2190 | { "RT5650 IF1 ADC1 Swap Mux", "R/R", "IF_ADC1" }, | ||
2191 | |||
2192 | { "RT5650 IF1 ADC2 Swap Mux", "L/R", "IF_ADC2" }, | ||
2193 | { "RT5650 IF1 ADC2 Swap Mux", "R/L", "IF_ADC2" }, | ||
2194 | { "RT5650 IF1 ADC2 Swap Mux", "L/L", "IF_ADC2" }, | ||
2195 | { "RT5650 IF1 ADC2 Swap Mux", "R/R", "IF_ADC2" }, | ||
2196 | |||
2197 | { "RT5650 IF1 ADC3 Swap Mux", "L/R", "VAD_ADC" }, | ||
2198 | { "RT5650 IF1 ADC3 Swap Mux", "R/L", "VAD_ADC" }, | ||
2199 | { "RT5650 IF1 ADC3 Swap Mux", "L/L", "VAD_ADC" }, | ||
2200 | { "RT5650 IF1 ADC3 Swap Mux", "R/R", "VAD_ADC" }, | ||
2201 | |||
2202 | { "IF1 ADC", NULL, "RT5650 IF1 ADC1 Swap Mux" }, | ||
2203 | { "IF1 ADC", NULL, "RT5650 IF1 ADC2 Swap Mux" }, | ||
2204 | { "IF1 ADC", NULL, "RT5650 IF1 ADC3 Swap Mux" }, | ||
2205 | |||
2206 | { "RT5650 IF1 ADC Mux", "IF_ADC1/IF_ADC2/DAC_REF/Null", "IF1 ADC" }, | ||
2207 | { "RT5650 IF1 ADC Mux", "IF_ADC1/IF_ADC2/Null/DAC_REF", "IF1 ADC" }, | ||
2208 | { "RT5650 IF1 ADC Mux", "IF_ADC1/DAC_REF/IF_ADC2/Null", "IF1 ADC" }, | ||
2209 | { "RT5650 IF1 ADC Mux", "IF_ADC1/DAC_REF/Null/IF_ADC2", "IF1 ADC" }, | ||
2210 | { "RT5650 IF1 ADC Mux", "IF_ADC1/Null/DAC_REF/IF_ADC2", "IF1 ADC" }, | ||
2211 | { "RT5650 IF1 ADC Mux", "IF_ADC1/Null/IF_ADC2/DAC_REF", "IF1 ADC" }, | ||
2212 | |||
2213 | { "RT5650 IF1 ADC Mux", "IF_ADC2/IF_ADC1/DAC_REF/Null", "IF1 ADC" }, | ||
2214 | { "RT5650 IF1 ADC Mux", "IF_ADC2/IF_ADC1/Null/DAC_REF", "IF1 ADC" }, | ||
2215 | { "RT5650 IF1 ADC Mux", "IF_ADC2/DAC_REF/IF_ADC1/Null", "IF1 ADC" }, | ||
2216 | { "RT5650 IF1 ADC Mux", "IF_ADC2/DAC_REF/Null/IF_ADC1", "IF1 ADC" }, | ||
2217 | { "RT5650 IF1 ADC Mux", "IF_ADC2/Null/DAC_REF/IF_ADC1", "IF1 ADC" }, | ||
2218 | { "RT5650 IF1 ADC Mux", "IF_ADC2/Null/IF_ADC1/DAC_REF", "IF1 ADC" }, | ||
2219 | |||
2220 | { "RT5650 IF1 ADC Mux", "DAC_REF/IF_ADC1/IF_ADC2/Null", "IF1 ADC" }, | ||
2221 | { "RT5650 IF1 ADC Mux", "DAC_REF/IF_ADC1/Null/IF_ADC2", "IF1 ADC" }, | ||
2222 | { "RT5650 IF1 ADC Mux", "DAC_REF/IF_ADC2/IF_ADC1/Null", "IF1 ADC" }, | ||
2223 | { "RT5650 IF1 ADC Mux", "DAC_REF/IF_ADC2/Null/IF_ADC1", "IF1 ADC" }, | ||
2224 | { "RT5650 IF1 ADC Mux", "DAC_REF/Null/IF_ADC1/IF_ADC2", "IF1 ADC" }, | ||
2225 | { "RT5650 IF1 ADC Mux", "DAC_REF/Null/IF_ADC2/IF_ADC1", "IF1 ADC" }, | ||
2226 | |||
2227 | { "RT5650 IF1 ADC Mux", "Null/IF_ADC1/IF_ADC2/DAC_REF", "IF1 ADC" }, | ||
2228 | { "RT5650 IF1 ADC Mux", "Null/IF_ADC1/DAC_REF/IF_ADC2", "IF1 ADC" }, | ||
2229 | { "RT5650 IF1 ADC Mux", "Null/IF_ADC2/IF_ADC1/DAC_REF", "IF1 ADC" }, | ||
2230 | { "RT5650 IF1 ADC Mux", "Null/IF_ADC2/DAC_REF/IF_ADC1", "IF1 ADC" }, | ||
2231 | { "RT5650 IF1 ADC Mux", "Null/DAC_REF/IF_ADC1/IF_ADC2", "IF1 ADC" }, | ||
2232 | { "RT5650 IF1 ADC Mux", "Null/DAC_REF/IF_ADC2/IF_ADC1", "IF1 ADC" }, | ||
2233 | { "AIF1TX", NULL, "RT5650 IF1 ADC Mux" }, | ||
2234 | |||
2235 | { "RT5650 IF1 DAC1 L Mux", "Slot0", "IF1 DAC0" }, | ||
2236 | { "RT5650 IF1 DAC1 L Mux", "Slot1", "IF1 DAC1" }, | ||
2237 | { "RT5650 IF1 DAC1 L Mux", "Slot2", "IF1 DAC2" }, | ||
2238 | { "RT5650 IF1 DAC1 L Mux", "Slot3", "IF1 DAC3" }, | ||
2239 | |||
2240 | { "RT5650 IF1 DAC1 R Mux", "Slot0", "IF1 DAC0" }, | ||
2241 | { "RT5650 IF1 DAC1 R Mux", "Slot1", "IF1 DAC1" }, | ||
2242 | { "RT5650 IF1 DAC1 R Mux", "Slot2", "IF1 DAC2" }, | ||
2243 | { "RT5650 IF1 DAC1 R Mux", "Slot3", "IF1 DAC3" }, | ||
2244 | |||
2245 | { "RT5650 IF1 DAC2 L Mux", "Slot0", "IF1 DAC0" }, | ||
2246 | { "RT5650 IF1 DAC2 L Mux", "Slot1", "IF1 DAC1" }, | ||
2247 | { "RT5650 IF1 DAC2 L Mux", "Slot2", "IF1 DAC2" }, | ||
2248 | { "RT5650 IF1 DAC2 L Mux", "Slot3", "IF1 DAC3" }, | ||
2249 | |||
2250 | { "RT5650 IF1 DAC2 R Mux", "Slot0", "IF1 DAC0" }, | ||
2251 | { "RT5650 IF1 DAC2 R Mux", "Slot1", "IF1 DAC1" }, | ||
2252 | { "RT5650 IF1 DAC2 R Mux", "Slot2", "IF1 DAC2" }, | ||
2253 | { "RT5650 IF1 DAC2 R Mux", "Slot3", "IF1 DAC3" }, | ||
2254 | |||
2255 | { "DAC1 L Mux", "IF1 DAC", "RT5650 IF1 DAC1 L Mux" }, | ||
2256 | { "DAC1 R Mux", "IF1 DAC", "RT5650 IF1 DAC1 R Mux" }, | ||
2257 | |||
2258 | { "DAC L2 Mux", "IF1 DAC", "RT5650 IF1 DAC2 L Mux" }, | ||
2259 | { "DAC R2 Mux", "IF1 DAC", "RT5650 IF1 DAC2 R Mux" }, | ||
2040 | }; | 2260 | }; |
2041 | 2261 | ||
2042 | static const struct snd_soc_dapm_route rt5645_specific_dapm_routes[] = { | 2262 | static const struct snd_soc_dapm_route rt5645_specific_dapm_routes[] = { |
@@ -2044,6 +2264,57 @@ static const struct snd_soc_dapm_route rt5645_specific_dapm_routes[] = { | |||
2044 | { "DAC R1", NULL, "Stereo DAC MIXR" }, | 2264 | { "DAC R1", NULL, "Stereo DAC MIXR" }, |
2045 | { "DAC L2", NULL, "Mono DAC MIXL" }, | 2265 | { "DAC L2", NULL, "Mono DAC MIXL" }, |
2046 | { "DAC R2", NULL, "Mono DAC MIXR" }, | 2266 | { "DAC R2", NULL, "Mono DAC MIXR" }, |
2267 | |||
2268 | { "RT5645 IF1 ADC1 Swap Mux", "L/R", "IF_ADC1" }, | ||
2269 | { "RT5645 IF1 ADC1 Swap Mux", "R/L", "IF_ADC1" }, | ||
2270 | { "RT5645 IF1 ADC1 Swap Mux", "L/L", "IF_ADC1" }, | ||
2271 | { "RT5645 IF1 ADC1 Swap Mux", "R/R", "IF_ADC1" }, | ||
2272 | |||
2273 | { "RT5645 IF1 ADC2 Swap Mux", "L/R", "IF_ADC2" }, | ||
2274 | { "RT5645 IF1 ADC2 Swap Mux", "R/L", "IF_ADC2" }, | ||
2275 | { "RT5645 IF1 ADC2 Swap Mux", "L/L", "IF_ADC2" }, | ||
2276 | { "RT5645 IF1 ADC2 Swap Mux", "R/R", "IF_ADC2" }, | ||
2277 | |||
2278 | { "RT5645 IF1 ADC3 Swap Mux", "L/R", "VAD_ADC" }, | ||
2279 | { "RT5645 IF1 ADC3 Swap Mux", "R/L", "VAD_ADC" }, | ||
2280 | { "RT5645 IF1 ADC3 Swap Mux", "L/L", "VAD_ADC" }, | ||
2281 | { "RT5645 IF1 ADC3 Swap Mux", "R/R", "VAD_ADC" }, | ||
2282 | |||
2283 | { "IF1 ADC", NULL, "RT5645 IF1 ADC1 Swap Mux" }, | ||
2284 | { "IF1 ADC", NULL, "RT5645 IF1 ADC2 Swap Mux" }, | ||
2285 | { "IF1 ADC", NULL, "RT5645 IF1 ADC3 Swap Mux" }, | ||
2286 | |||
2287 | { "RT5645 IF1 ADC Mux", "IF_ADC1/IF_ADC2/VAD_ADC", "IF1 ADC" }, | ||
2288 | { "RT5645 IF1 ADC Mux", "IF_ADC2/IF_ADC1/VAD_ADC", "IF1 ADC" }, | ||
2289 | { "RT5645 IF1 ADC Mux", "VAD_ADC/IF_ADC1/IF_ADC2", "IF1 ADC" }, | ||
2290 | { "RT5645 IF1 ADC Mux", "VAD_ADC/IF_ADC2/IF_ADC1", "IF1 ADC" }, | ||
2291 | { "AIF1TX", NULL, "RT5645 IF1 ADC Mux" }, | ||
2292 | |||
2293 | { "RT5645 IF1 DAC1 L Mux", "Slot0", "IF1 DAC0" }, | ||
2294 | { "RT5645 IF1 DAC1 L Mux", "Slot1", "IF1 DAC1" }, | ||
2295 | { "RT5645 IF1 DAC1 L Mux", "Slot2", "IF1 DAC2" }, | ||
2296 | { "RT5645 IF1 DAC1 L Mux", "Slot3", "IF1 DAC3" }, | ||
2297 | |||
2298 | { "RT5645 IF1 DAC1 R Mux", "Slot0", "IF1 DAC0" }, | ||
2299 | { "RT5645 IF1 DAC1 R Mux", "Slot1", "IF1 DAC1" }, | ||
2300 | { "RT5645 IF1 DAC1 R Mux", "Slot2", "IF1 DAC2" }, | ||
2301 | { "RT5645 IF1 DAC1 R Mux", "Slot3", "IF1 DAC3" }, | ||
2302 | |||
2303 | { "RT5645 IF1 DAC2 L Mux", "Slot0", "IF1 DAC0" }, | ||
2304 | { "RT5645 IF1 DAC2 L Mux", "Slot1", "IF1 DAC1" }, | ||
2305 | { "RT5645 IF1 DAC2 L Mux", "Slot2", "IF1 DAC2" }, | ||
2306 | { "RT5645 IF1 DAC2 L Mux", "Slot3", "IF1 DAC3" }, | ||
2307 | |||
2308 | { "RT5645 IF1 DAC2 R Mux", "Slot0", "IF1 DAC0" }, | ||
2309 | { "RT5645 IF1 DAC2 R Mux", "Slot1", "IF1 DAC1" }, | ||
2310 | { "RT5645 IF1 DAC2 R Mux", "Slot2", "IF1 DAC2" }, | ||
2311 | { "RT5645 IF1 DAC2 R Mux", "Slot3", "IF1 DAC3" }, | ||
2312 | |||
2313 | { "DAC1 L Mux", "IF1 DAC", "RT5645 IF1 DAC1 L Mux" }, | ||
2314 | { "DAC1 R Mux", "IF1 DAC", "RT5645 IF1 DAC1 R Mux" }, | ||
2315 | |||
2316 | { "DAC L2 Mux", "IF1 DAC", "RT5645 IF1 DAC2 L Mux" }, | ||
2317 | { "DAC R2 Mux", "IF1 DAC", "RT5645 IF1 DAC2 R Mux" }, | ||
2047 | }; | 2318 | }; |
2048 | 2319 | ||
2049 | static int rt5645_hw_params(struct snd_pcm_substream *substream, | 2320 | static int rt5645_hw_params(struct snd_pcm_substream *substream, |
@@ -2101,9 +2372,8 @@ static int rt5645_hw_params(struct snd_pcm_substream *substream, | |||
2101 | 2372 | ||
2102 | switch (dai->id) { | 2373 | switch (dai->id) { |
2103 | case RT5645_AIF1: | 2374 | case RT5645_AIF1: |
2104 | mask_clk = RT5645_I2S_BCLK_MS1_MASK | RT5645_I2S_PD1_MASK; | 2375 | mask_clk = RT5645_I2S_PD1_MASK; |
2105 | val_clk = bclk_ms << RT5645_I2S_BCLK_MS1_SFT | | 2376 | val_clk = pre_div << RT5645_I2S_PD1_SFT; |
2106 | pre_div << RT5645_I2S_PD1_SFT; | ||
2107 | snd_soc_update_bits(codec, RT5645_I2S1_SDP, | 2377 | snd_soc_update_bits(codec, RT5645_I2S1_SDP, |
2108 | (0x3 << dl_sft), (val_len << dl_sft)); | 2378 | (0x3 << dl_sft), (val_len << dl_sft)); |
2109 | snd_soc_update_bits(codec, RT5645_ADDA_CLK1, mask_clk, val_clk); | 2379 | snd_soc_update_bits(codec, RT5645_ADDA_CLK1, mask_clk, val_clk); |
@@ -2368,6 +2638,8 @@ static int rt5645_set_tdm_slot(struct snd_soc_dai *dai, unsigned int tx_mask, | |||
2368 | static int rt5645_set_bias_level(struct snd_soc_codec *codec, | 2638 | static int rt5645_set_bias_level(struct snd_soc_codec *codec, |
2369 | enum snd_soc_bias_level level) | 2639 | enum snd_soc_bias_level level) |
2370 | { | 2640 | { |
2641 | struct rt5645_priv *rt5645 = snd_soc_codec_get_drvdata(codec); | ||
2642 | |||
2371 | switch (level) { | 2643 | switch (level) { |
2372 | case SND_SOC_BIAS_PREPARE: | 2644 | case SND_SOC_BIAS_PREPARE: |
2373 | if (SND_SOC_BIAS_STANDBY == codec->dapm.bias_level) { | 2645 | if (SND_SOC_BIAS_STANDBY == codec->dapm.bias_level) { |
@@ -2398,8 +2670,9 @@ static int rt5645_set_bias_level(struct snd_soc_codec *codec, | |||
2398 | 2670 | ||
2399 | case SND_SOC_BIAS_OFF: | 2671 | case SND_SOC_BIAS_OFF: |
2400 | snd_soc_write(codec, RT5645_DEPOP_M2, 0x1100); | 2672 | snd_soc_write(codec, RT5645_DEPOP_M2, 0x1100); |
2401 | snd_soc_update_bits(codec, RT5645_GEN_CTRL1, | 2673 | if (!rt5645->en_button_func) |
2402 | RT5645_DIG_GATE_CTRL, 0); | 2674 | snd_soc_update_bits(codec, RT5645_GEN_CTRL1, |
2675 | RT5645_DIG_GATE_CTRL, 0); | ||
2403 | snd_soc_update_bits(codec, RT5645_PWR_ANLG1, | 2676 | snd_soc_update_bits(codec, RT5645_PWR_ANLG1, |
2404 | RT5645_PWR_VREF1 | RT5645_PWR_MB | | 2677 | RT5645_PWR_VREF1 | RT5645_PWR_MB | |
2405 | RT5645_PWR_BG | RT5645_PWR_VREF2 | | 2678 | RT5645_PWR_BG | RT5645_PWR_VREF2 | |
@@ -2409,72 +2682,228 @@ static int rt5645_set_bias_level(struct snd_soc_codec *codec, | |||
2409 | default: | 2682 | default: |
2410 | break; | 2683 | break; |
2411 | } | 2684 | } |
2412 | codec->dapm.bias_level = level; | ||
2413 | 2685 | ||
2414 | return 0; | 2686 | return 0; |
2415 | } | 2687 | } |
2416 | 2688 | ||
2417 | static int rt5645_jack_detect(struct snd_soc_codec *codec) | 2689 | static int rt5650_calibration(struct rt5645_priv *rt5645) |
2418 | { | 2690 | { |
2419 | struct rt5645_priv *rt5645 = snd_soc_codec_get_drvdata(codec); | 2691 | int val, i; |
2420 | int gpio_state, jack_type = 0; | 2692 | int ret = -1; |
2421 | unsigned int val; | ||
2422 | 2693 | ||
2423 | if (!gpio_is_valid(rt5645->pdata.hp_det_gpio)) { | 2694 | regcache_cache_bypass(rt5645->regmap, true); |
2424 | dev_err(codec->dev, "invalid gpio\n"); | 2695 | regmap_write(rt5645->regmap, RT5645_RESET, 0); |
2425 | return -EINVAL; | 2696 | regmap_write(rt5645->regmap, RT5645_GEN_CTRL3, 0x0800); |
2697 | regmap_write(rt5645->regmap, RT5645_PR_BASE + RT5645_CHOP_DAC_ADC, | ||
2698 | 0x3600); | ||
2699 | regmap_write(rt5645->regmap, RT5645_PR_BASE + 0x25, 0x7000); | ||
2700 | regmap_write(rt5645->regmap, RT5645_I2S1_SDP, 0x8008); | ||
2701 | /* headset type */ | ||
2702 | regmap_write(rt5645->regmap, RT5645_GEN_CTRL1, 0x2061); | ||
2703 | regmap_write(rt5645->regmap, RT5645_CHARGE_PUMP, 0x0006); | ||
2704 | regmap_write(rt5645->regmap, RT5645_PWR_ANLG1, 0x2012); | ||
2705 | regmap_write(rt5645->regmap, RT5645_PWR_MIXER, 0x0002); | ||
2706 | regmap_write(rt5645->regmap, RT5645_PWR_VOL, 0x0020); | ||
2707 | regmap_write(rt5645->regmap, RT5645_JD_CTRL3, 0x00f0); | ||
2708 | regmap_write(rt5645->regmap, RT5645_IN1_CTRL1, 0x0006); | ||
2709 | regmap_write(rt5645->regmap, RT5645_IN1_CTRL2, 0x1827); | ||
2710 | regmap_write(rt5645->regmap, RT5645_IN1_CTRL2, 0x0827); | ||
2711 | msleep(400); | ||
2712 | /* Inline command */ | ||
2713 | regmap_write(rt5645->regmap, RT5645_DEPOP_M1, 0x0001); | ||
2714 | regmap_write(rt5645->regmap, RT5650_4BTN_IL_CMD2, 0xc000); | ||
2715 | regmap_write(rt5645->regmap, RT5650_4BTN_IL_CMD1, 0x0008); | ||
2716 | /* Calbration */ | ||
2717 | regmap_write(rt5645->regmap, RT5645_GLB_CLK, 0x8000); | ||
2718 | regmap_write(rt5645->regmap, RT5645_DEPOP_M1, 0x0000); | ||
2719 | regmap_write(rt5645->regmap, RT5650_4BTN_IL_CMD2, 0xc000); | ||
2720 | regmap_write(rt5645->regmap, RT5650_4BTN_IL_CMD1, 0x0008); | ||
2721 | regmap_write(rt5645->regmap, RT5645_PWR_DIG2, 0x8800); | ||
2722 | regmap_write(rt5645->regmap, RT5645_PWR_ANLG1, 0xe8fa); | ||
2723 | regmap_write(rt5645->regmap, RT5645_PWR_ANLG2, 0x8c04); | ||
2724 | regmap_write(rt5645->regmap, RT5645_DEPOP_M2, 0x3100); | ||
2725 | regmap_write(rt5645->regmap, RT5645_CHARGE_PUMP, 0x0e06); | ||
2726 | regmap_write(rt5645->regmap, RT5645_BASS_BACK, 0x8a13); | ||
2727 | regmap_write(rt5645->regmap, RT5645_GEN_CTRL3, 0x0820); | ||
2728 | regmap_write(rt5645->regmap, RT5645_DEPOP_M1, 0x000d); | ||
2729 | /* Power on and Calbration */ | ||
2730 | regmap_write(rt5645->regmap, RT5645_PR_BASE + RT5645_HP_DCC_INT1, | ||
2731 | 0x9f01); | ||
2732 | msleep(200); | ||
2733 | for (i = 0; i < 5; i++) { | ||
2734 | regmap_read(rt5645->regmap, RT5645_PR_BASE + 0x7a, &val); | ||
2735 | if (val != 0 && val != 0x3f3f) { | ||
2736 | ret = 0; | ||
2737 | break; | ||
2738 | } | ||
2739 | msleep(50); | ||
2426 | } | 2740 | } |
2427 | gpio_state = gpio_get_value(rt5645->pdata.hp_det_gpio); | 2741 | pr_debug("%s: PR-7A = 0x%x\n", __func__, val); |
2742 | |||
2743 | /* mute */ | ||
2744 | regmap_write(rt5645->regmap, RT5645_PR_BASE + 0x3e, 0x7400); | ||
2745 | regmap_write(rt5645->regmap, RT5645_DEPOP_M3, 0x0737); | ||
2746 | regmap_write(rt5645->regmap, RT5645_PR_BASE + RT5645_MAMP_INT_REG2, | ||
2747 | 0xfc00); | ||
2748 | regmap_write(rt5645->regmap, RT5645_DEPOP_M2, 0x1140); | ||
2749 | regmap_write(rt5645->regmap, RT5645_DEPOP_M1, 0x0000); | ||
2750 | regmap_write(rt5645->regmap, RT5645_GEN_CTRL2, 0x4020); | ||
2751 | regmap_write(rt5645->regmap, RT5645_PWR_ANLG2, 0x0006); | ||
2752 | regmap_write(rt5645->regmap, RT5645_PWR_DIG2, 0x0000); | ||
2753 | msleep(350); | ||
2754 | |||
2755 | regcache_cache_bypass(rt5645->regmap, false); | ||
2756 | |||
2757 | return ret; | ||
2758 | } | ||
2428 | 2759 | ||
2429 | dev_dbg(codec->dev, "gpio = %d(%d)\n", rt5645->pdata.hp_det_gpio, | 2760 | static void rt5645_enable_push_button_irq(struct snd_soc_codec *codec, |
2430 | gpio_state); | 2761 | bool enable) |
2762 | { | ||
2763 | struct rt5645_priv *rt5645 = snd_soc_codec_get_drvdata(codec); | ||
2431 | 2764 | ||
2432 | if ((rt5645->pdata.gpio_hp_det_active_high && gpio_state) || | 2765 | if (enable) { |
2433 | (!rt5645->pdata.gpio_hp_det_active_high && !gpio_state)) { | 2766 | snd_soc_dapm_mutex_lock(&codec->dapm); |
2434 | snd_soc_dapm_force_enable_pin(&codec->dapm, "micbias1"); | 2767 | snd_soc_dapm_force_enable_pin_unlocked(&codec->dapm, |
2435 | snd_soc_dapm_force_enable_pin(&codec->dapm, "micbias2"); | 2768 | "ADC L power"); |
2436 | snd_soc_dapm_force_enable_pin(&codec->dapm, "LDO2"); | 2769 | snd_soc_dapm_force_enable_pin_unlocked(&codec->dapm, |
2437 | snd_soc_dapm_force_enable_pin(&codec->dapm, "Mic Det Power"); | 2770 | "ADC R power"); |
2438 | snd_soc_dapm_sync(&codec->dapm); | 2771 | snd_soc_dapm_force_enable_pin_unlocked(&codec->dapm, |
2772 | "LDO2"); | ||
2773 | snd_soc_dapm_force_enable_pin_unlocked(&codec->dapm, | ||
2774 | "Mic Det Power"); | ||
2775 | snd_soc_dapm_sync_unlocked(&codec->dapm); | ||
2776 | snd_soc_dapm_mutex_unlock(&codec->dapm); | ||
2777 | |||
2778 | snd_soc_update_bits(codec, | ||
2779 | RT5645_INT_IRQ_ST, 0x8, 0x8); | ||
2780 | snd_soc_update_bits(codec, | ||
2781 | RT5650_4BTN_IL_CMD2, 0x8000, 0x8000); | ||
2782 | snd_soc_read(codec, RT5650_4BTN_IL_CMD1); | ||
2783 | pr_debug("%s read %x = %x\n", __func__, RT5650_4BTN_IL_CMD1, | ||
2784 | snd_soc_read(codec, RT5650_4BTN_IL_CMD1)); | ||
2785 | } else { | ||
2786 | snd_soc_update_bits(codec, RT5650_4BTN_IL_CMD2, 0x8000, 0x0); | ||
2787 | snd_soc_update_bits(codec, RT5645_INT_IRQ_ST, 0x8, 0x0); | ||
2788 | |||
2789 | snd_soc_dapm_mutex_lock(&codec->dapm); | ||
2790 | snd_soc_dapm_disable_pin_unlocked(&codec->dapm, | ||
2791 | "ADC L power"); | ||
2792 | snd_soc_dapm_disable_pin_unlocked(&codec->dapm, | ||
2793 | "ADC R power"); | ||
2794 | if (rt5645->pdata.jd_mode == 0) | ||
2795 | snd_soc_dapm_disable_pin_unlocked(&codec->dapm, | ||
2796 | "LDO2"); | ||
2797 | snd_soc_dapm_disable_pin_unlocked(&codec->dapm, | ||
2798 | "Mic Det Power"); | ||
2799 | snd_soc_dapm_sync_unlocked(&codec->dapm); | ||
2800 | snd_soc_dapm_mutex_unlock(&codec->dapm); | ||
2801 | } | ||
2802 | } | ||
2439 | 2803 | ||
2440 | snd_soc_write(codec, RT5645_IN1_CTRL1, 0x0006); | 2804 | static int rt5645_jack_detect(struct snd_soc_codec *codec, int jack_insert) |
2441 | snd_soc_write(codec, RT5645_JD_CTRL3, 0x00b0); | 2805 | { |
2806 | struct rt5645_priv *rt5645 = snd_soc_codec_get_drvdata(codec); | ||
2807 | unsigned int val; | ||
2442 | 2808 | ||
2443 | snd_soc_update_bits(codec, RT5645_IN1_CTRL2, | 2809 | if (jack_insert) { |
2444 | RT5645_CBJ_MN_JD, 0); | 2810 | regmap_write(rt5645->regmap, RT5645_CHARGE_PUMP, 0x0006); |
2445 | snd_soc_update_bits(codec, RT5645_IN1_CTRL2, | 2811 | |
2446 | RT5645_CBJ_MN_JD, RT5645_CBJ_MN_JD); | 2812 | if (codec->component.card->instantiated) { |
2813 | /* for jack type detect */ | ||
2814 | snd_soc_dapm_force_enable_pin(&codec->dapm, "LDO2"); | ||
2815 | snd_soc_dapm_force_enable_pin(&codec->dapm, | ||
2816 | "Mic Det Power"); | ||
2817 | snd_soc_dapm_sync(&codec->dapm); | ||
2818 | } else { | ||
2819 | /* Power up necessary bits for JD if dapm is | ||
2820 | not ready yet */ | ||
2821 | regmap_update_bits(rt5645->regmap, RT5645_PWR_ANLG1, | ||
2822 | RT5645_PWR_MB | RT5645_PWR_VREF2, | ||
2823 | RT5645_PWR_MB | RT5645_PWR_VREF2); | ||
2824 | regmap_update_bits(rt5645->regmap, RT5645_PWR_MIXER, | ||
2825 | RT5645_PWR_LDO2, RT5645_PWR_LDO2); | ||
2826 | regmap_update_bits(rt5645->regmap, RT5645_PWR_VOL, | ||
2827 | RT5645_PWR_MIC_DET, RT5645_PWR_MIC_DET); | ||
2828 | } | ||
2447 | 2829 | ||
2448 | msleep(400); | 2830 | regmap_write(rt5645->regmap, RT5645_JD_CTRL3, 0x00f0); |
2449 | val = snd_soc_read(codec, RT5645_IN1_CTRL3) & 0x7; | 2831 | regmap_write(rt5645->regmap, RT5645_IN1_CTRL1, 0x0006); |
2832 | regmap_update_bits(rt5645->regmap, | ||
2833 | RT5645_IN1_CTRL2, 0x1000, 0x1000); | ||
2834 | msleep(100); | ||
2835 | regmap_update_bits(rt5645->regmap, | ||
2836 | RT5645_IN1_CTRL2, 0x1000, 0x0000); | ||
2837 | |||
2838 | msleep(450); | ||
2839 | regmap_read(rt5645->regmap, RT5645_IN1_CTRL3, &val); | ||
2840 | val &= 0x7; | ||
2450 | dev_dbg(codec->dev, "val = %d\n", val); | 2841 | dev_dbg(codec->dev, "val = %d\n", val); |
2451 | 2842 | ||
2452 | if (val == 1 || val == 2) | 2843 | if (val == 1 || val == 2) { |
2453 | jack_type = SND_JACK_HEADSET; | 2844 | rt5645->jack_type = SND_JACK_HEADSET; |
2454 | else | 2845 | if (rt5645->en_button_func) { |
2455 | jack_type = SND_JACK_HEADPHONE; | 2846 | rt5645_enable_push_button_irq(codec, true); |
2847 | } | ||
2848 | } else { | ||
2849 | if (codec->component.card->instantiated) { | ||
2850 | snd_soc_dapm_disable_pin(&codec->dapm, | ||
2851 | "Mic Det Power"); | ||
2852 | snd_soc_dapm_sync(&codec->dapm); | ||
2853 | } else | ||
2854 | regmap_update_bits(rt5645->regmap, | ||
2855 | RT5645_PWR_VOL, RT5645_PWR_MIC_DET, 0); | ||
2856 | rt5645->jack_type = SND_JACK_HEADPHONE; | ||
2857 | } | ||
2456 | 2858 | ||
2457 | snd_soc_dapm_disable_pin(&codec->dapm, "micbias1"); | 2859 | } else { /* jack out */ |
2458 | snd_soc_dapm_disable_pin(&codec->dapm, "micbias2"); | 2860 | rt5645->jack_type = 0; |
2459 | if (rt5645->pdata.jd_mode == 0) | 2861 | if (rt5645->en_button_func) |
2460 | snd_soc_dapm_disable_pin(&codec->dapm, "LDO2"); | 2862 | rt5645_enable_push_button_irq(codec, false); |
2461 | snd_soc_dapm_disable_pin(&codec->dapm, "Mic Det Power"); | 2863 | else { |
2462 | snd_soc_dapm_sync(&codec->dapm); | 2864 | if (codec->component.card->instantiated) { |
2865 | if (rt5645->pdata.jd_mode == 0) | ||
2866 | snd_soc_dapm_disable_pin(&codec->dapm, | ||
2867 | "LDO2"); | ||
2868 | snd_soc_dapm_disable_pin(&codec->dapm, | ||
2869 | "Mic Det Power"); | ||
2870 | snd_soc_dapm_sync(&codec->dapm); | ||
2871 | } else { | ||
2872 | if (rt5645->pdata.jd_mode == 0) | ||
2873 | regmap_update_bits(rt5645->regmap, | ||
2874 | RT5645_PWR_MIXER, | ||
2875 | RT5645_PWR_LDO2, 0); | ||
2876 | regmap_update_bits(rt5645->regmap, | ||
2877 | RT5645_PWR_VOL, RT5645_PWR_MIC_DET, 0); | ||
2878 | } | ||
2879 | } | ||
2463 | } | 2880 | } |
2464 | 2881 | ||
2465 | snd_soc_jack_report(rt5645->hp_jack, jack_type, SND_JACK_HEADPHONE); | 2882 | return rt5645->jack_type; |
2466 | snd_soc_jack_report(rt5645->mic_jack, jack_type, SND_JACK_MICROPHONE); | ||
2467 | return 0; | ||
2468 | } | 2883 | } |
2469 | 2884 | ||
2885 | static int rt5645_irq_detection(struct rt5645_priv *rt5645); | ||
2886 | static irqreturn_t rt5645_irq(int irq, void *data); | ||
2887 | |||
2470 | int rt5645_set_jack_detect(struct snd_soc_codec *codec, | 2888 | int rt5645_set_jack_detect(struct snd_soc_codec *codec, |
2471 | struct snd_soc_jack *hp_jack, struct snd_soc_jack *mic_jack) | 2889 | struct snd_soc_jack *hp_jack, struct snd_soc_jack *mic_jack, |
2890 | struct snd_soc_jack *btn_jack) | ||
2472 | { | 2891 | { |
2473 | struct rt5645_priv *rt5645 = snd_soc_codec_get_drvdata(codec); | 2892 | struct rt5645_priv *rt5645 = snd_soc_codec_get_drvdata(codec); |
2474 | 2893 | ||
2475 | rt5645->hp_jack = hp_jack; | 2894 | rt5645->hp_jack = hp_jack; |
2476 | rt5645->mic_jack = mic_jack; | 2895 | rt5645->mic_jack = mic_jack; |
2477 | rt5645_jack_detect(codec); | 2896 | rt5645->btn_jack = btn_jack; |
2897 | if (rt5645->btn_jack && rt5645->codec_type == CODEC_TYPE_RT5650) { | ||
2898 | rt5645->en_button_func = true; | ||
2899 | regmap_update_bits(rt5645->regmap, RT5645_GPIO_CTRL1, | ||
2900 | RT5645_GP1_PIN_IRQ, RT5645_GP1_PIN_IRQ); | ||
2901 | regmap_update_bits(rt5645->regmap, RT5645_DEPOP_M1, | ||
2902 | RT5645_HP_CB_MASK, RT5645_HP_CB_PU); | ||
2903 | regmap_update_bits(rt5645->regmap, RT5645_GEN_CTRL1, | ||
2904 | RT5645_DIG_GATE_CTRL, RT5645_DIG_GATE_CTRL); | ||
2905 | } | ||
2906 | rt5645_irq(0, rt5645); | ||
2478 | 2907 | ||
2479 | return 0; | 2908 | return 0; |
2480 | } | 2909 | } |
@@ -2485,7 +2914,7 @@ static void rt5645_jack_detect_work(struct work_struct *work) | |||
2485 | struct rt5645_priv *rt5645 = | 2914 | struct rt5645_priv *rt5645 = |
2486 | container_of(work, struct rt5645_priv, jack_detect_work.work); | 2915 | container_of(work, struct rt5645_priv, jack_detect_work.work); |
2487 | 2916 | ||
2488 | rt5645_jack_detect(rt5645->codec); | 2917 | rt5645_irq_detection(rt5645); |
2489 | } | 2918 | } |
2490 | 2919 | ||
2491 | static irqreturn_t rt5645_irq(int irq, void *data) | 2920 | static irqreturn_t rt5645_irq(int irq, void *data) |
@@ -2498,6 +2927,120 @@ static irqreturn_t rt5645_irq(int irq, void *data) | |||
2498 | return IRQ_HANDLED; | 2927 | return IRQ_HANDLED; |
2499 | } | 2928 | } |
2500 | 2929 | ||
2930 | static int rt5645_button_detect(struct snd_soc_codec *codec) | ||
2931 | { | ||
2932 | int btn_type, val; | ||
2933 | |||
2934 | val = snd_soc_read(codec, RT5650_4BTN_IL_CMD1); | ||
2935 | pr_debug("val=0x%x\n", val); | ||
2936 | btn_type = val & 0xfff0; | ||
2937 | snd_soc_write(codec, RT5650_4BTN_IL_CMD1, val); | ||
2938 | |||
2939 | return btn_type; | ||
2940 | } | ||
2941 | |||
2942 | static int rt5645_irq_detection(struct rt5645_priv *rt5645) | ||
2943 | { | ||
2944 | int val, btn_type, gpio_state = 0, report = 0; | ||
2945 | |||
2946 | switch (rt5645->pdata.jd_mode) { | ||
2947 | case 0: /* Not using rt5645 JD */ | ||
2948 | if (rt5645->gpiod_hp_det) { | ||
2949 | gpio_state = gpiod_get_value(rt5645->gpiod_hp_det); | ||
2950 | dev_dbg(rt5645->codec->dev, "gpio_state = %d\n", | ||
2951 | gpio_state); | ||
2952 | report = rt5645_jack_detect(rt5645->codec, gpio_state); | ||
2953 | } | ||
2954 | snd_soc_jack_report(rt5645->hp_jack, | ||
2955 | report, SND_JACK_HEADPHONE); | ||
2956 | snd_soc_jack_report(rt5645->mic_jack, | ||
2957 | report, SND_JACK_MICROPHONE); | ||
2958 | return report; | ||
2959 | case 1: /* 2 port */ | ||
2960 | val = snd_soc_read(rt5645->codec, RT5645_A_JD_CTRL1) & 0x0070; | ||
2961 | break; | ||
2962 | default: /* 1 port */ | ||
2963 | val = snd_soc_read(rt5645->codec, RT5645_A_JD_CTRL1) & 0x0020; | ||
2964 | break; | ||
2965 | |||
2966 | } | ||
2967 | |||
2968 | switch (val) { | ||
2969 | /* jack in */ | ||
2970 | case 0x30: /* 2 port */ | ||
2971 | case 0x0: /* 1 port or 2 port */ | ||
2972 | if (rt5645->jack_type == 0) { | ||
2973 | report = rt5645_jack_detect(rt5645->codec, 1); | ||
2974 | /* for push button and jack out */ | ||
2975 | break; | ||
2976 | } | ||
2977 | btn_type = 0; | ||
2978 | if (snd_soc_read(rt5645->codec, RT5645_INT_IRQ_ST) & 0x4) { | ||
2979 | /* button pressed */ | ||
2980 | report = SND_JACK_HEADSET; | ||
2981 | btn_type = rt5645_button_detect(rt5645->codec); | ||
2982 | /* rt5650 can report three kinds of button behavior, | ||
2983 | one click, double click and hold. However, | ||
2984 | currently we will report button pressed/released | ||
2985 | event. So all the three button behaviors are | ||
2986 | treated as button pressed. */ | ||
2987 | switch (btn_type) { | ||
2988 | case 0x8000: | ||
2989 | case 0x4000: | ||
2990 | case 0x2000: | ||
2991 | report |= SND_JACK_BTN_0; | ||
2992 | break; | ||
2993 | case 0x1000: | ||
2994 | case 0x0800: | ||
2995 | case 0x0400: | ||
2996 | report |= SND_JACK_BTN_1; | ||
2997 | break; | ||
2998 | case 0x0200: | ||
2999 | case 0x0100: | ||
3000 | case 0x0080: | ||
3001 | report |= SND_JACK_BTN_2; | ||
3002 | break; | ||
3003 | case 0x0040: | ||
3004 | case 0x0020: | ||
3005 | case 0x0010: | ||
3006 | report |= SND_JACK_BTN_3; | ||
3007 | break; | ||
3008 | case 0x0000: /* unpressed */ | ||
3009 | break; | ||
3010 | default: | ||
3011 | dev_err(rt5645->codec->dev, | ||
3012 | "Unexpected button code 0x%04x\n", | ||
3013 | btn_type); | ||
3014 | break; | ||
3015 | } | ||
3016 | } | ||
3017 | if (btn_type == 0)/* button release */ | ||
3018 | report = rt5645->jack_type; | ||
3019 | |||
3020 | break; | ||
3021 | /* jack out */ | ||
3022 | case 0x70: /* 2 port */ | ||
3023 | case 0x10: /* 2 port */ | ||
3024 | case 0x20: /* 1 port */ | ||
3025 | report = 0; | ||
3026 | snd_soc_update_bits(rt5645->codec, | ||
3027 | RT5645_INT_IRQ_ST, 0x1, 0x0); | ||
3028 | rt5645_jack_detect(rt5645->codec, 0); | ||
3029 | break; | ||
3030 | default: | ||
3031 | break; | ||
3032 | } | ||
3033 | |||
3034 | snd_soc_jack_report(rt5645->hp_jack, report, SND_JACK_HEADPHONE); | ||
3035 | snd_soc_jack_report(rt5645->mic_jack, report, SND_JACK_MICROPHONE); | ||
3036 | if (rt5645->en_button_func) | ||
3037 | snd_soc_jack_report(rt5645->btn_jack, | ||
3038 | report, SND_JACK_BTN_0 | SND_JACK_BTN_1 | | ||
3039 | SND_JACK_BTN_2 | SND_JACK_BTN_3); | ||
3040 | |||
3041 | return report; | ||
3042 | } | ||
3043 | |||
2501 | static int rt5645_probe(struct snd_soc_codec *codec) | 3044 | static int rt5645_probe(struct snd_soc_codec *codec) |
2502 | { | 3045 | { |
2503 | struct rt5645_priv *rt5645 = snd_soc_codec_get_drvdata(codec); | 3046 | struct rt5645_priv *rt5645 = snd_soc_codec_get_drvdata(codec); |
@@ -2520,12 +3063,10 @@ static int rt5645_probe(struct snd_soc_codec *codec) | |||
2520 | break; | 3063 | break; |
2521 | } | 3064 | } |
2522 | 3065 | ||
2523 | rt5645_set_bias_level(codec, SND_SOC_BIAS_OFF); | 3066 | snd_soc_codec_force_bias_level(codec, SND_SOC_BIAS_OFF); |
2524 | |||
2525 | snd_soc_update_bits(codec, RT5645_CHARGE_PUMP, 0x0300, 0x0200); | ||
2526 | 3067 | ||
2527 | /* for JD function */ | 3068 | /* for JD function */ |
2528 | if (rt5645->pdata.en_jd_func) { | 3069 | if (rt5645->pdata.jd_mode) { |
2529 | snd_soc_dapm_force_enable_pin(&codec->dapm, "JD Power"); | 3070 | snd_soc_dapm_force_enable_pin(&codec->dapm, "JD Power"); |
2530 | snd_soc_dapm_force_enable_pin(&codec->dapm, "LDO2"); | 3071 | snd_soc_dapm_force_enable_pin(&codec->dapm, "LDO2"); |
2531 | snd_soc_dapm_sync(&codec->dapm); | 3072 | snd_soc_dapm_sync(&codec->dapm); |
@@ -2656,6 +3197,55 @@ static const struct i2c_device_id rt5645_i2c_id[] = { | |||
2656 | }; | 3197 | }; |
2657 | MODULE_DEVICE_TABLE(i2c, rt5645_i2c_id); | 3198 | MODULE_DEVICE_TABLE(i2c, rt5645_i2c_id); |
2658 | 3199 | ||
3200 | #ifdef CONFIG_ACPI | ||
3201 | static struct acpi_device_id rt5645_acpi_match[] = { | ||
3202 | { "10EC5645", 0 }, | ||
3203 | { "10EC5650", 0 }, | ||
3204 | {}, | ||
3205 | }; | ||
3206 | MODULE_DEVICE_TABLE(acpi, rt5645_acpi_match); | ||
3207 | #endif | ||
3208 | |||
3209 | static struct rt5645_platform_data *rt5645_pdata; | ||
3210 | |||
3211 | static struct rt5645_platform_data strago_platform_data = { | ||
3212 | .dmic1_data_pin = RT5645_DMIC1_DISABLE, | ||
3213 | .dmic2_data_pin = RT5645_DMIC_DATA_IN2P, | ||
3214 | .jd_mode = 3, | ||
3215 | }; | ||
3216 | |||
3217 | static int strago_quirk_cb(const struct dmi_system_id *id) | ||
3218 | { | ||
3219 | rt5645_pdata = &strago_platform_data; | ||
3220 | |||
3221 | return 1; | ||
3222 | } | ||
3223 | |||
3224 | static struct dmi_system_id dmi_platform_intel_braswell[] = { | ||
3225 | { | ||
3226 | .ident = "Intel Strago", | ||
3227 | .callback = strago_quirk_cb, | ||
3228 | .matches = { | ||
3229 | DMI_MATCH(DMI_PRODUCT_NAME, "Strago"), | ||
3230 | }, | ||
3231 | }, | ||
3232 | { } | ||
3233 | }; | ||
3234 | |||
3235 | static int rt5645_parse_dt(struct rt5645_priv *rt5645, struct device *dev) | ||
3236 | { | ||
3237 | rt5645->pdata.in2_diff = device_property_read_bool(dev, | ||
3238 | "realtek,in2-differential"); | ||
3239 | device_property_read_u32(dev, | ||
3240 | "realtek,dmic1-data-pin", &rt5645->pdata.dmic1_data_pin); | ||
3241 | device_property_read_u32(dev, | ||
3242 | "realtek,dmic2-data-pin", &rt5645->pdata.dmic2_data_pin); | ||
3243 | device_property_read_u32(dev, | ||
3244 | "realtek,jd-mode", &rt5645->pdata.jd_mode); | ||
3245 | |||
3246 | return 0; | ||
3247 | } | ||
3248 | |||
2659 | static int rt5645_i2c_probe(struct i2c_client *i2c, | 3249 | static int rt5645_i2c_probe(struct i2c_client *i2c, |
2660 | const struct i2c_device_id *id) | 3250 | const struct i2c_device_id *id) |
2661 | { | 3251 | { |
@@ -2674,6 +3264,18 @@ static int rt5645_i2c_probe(struct i2c_client *i2c, | |||
2674 | 3264 | ||
2675 | if (pdata) | 3265 | if (pdata) |
2676 | rt5645->pdata = *pdata; | 3266 | rt5645->pdata = *pdata; |
3267 | else if (dmi_check_system(dmi_platform_intel_braswell)) | ||
3268 | rt5645->pdata = *rt5645_pdata; | ||
3269 | else | ||
3270 | rt5645_parse_dt(rt5645, &i2c->dev); | ||
3271 | |||
3272 | rt5645->gpiod_hp_det = devm_gpiod_get_optional(&i2c->dev, "hp-detect", | ||
3273 | GPIOD_IN); | ||
3274 | |||
3275 | if (IS_ERR(rt5645->gpiod_hp_det)) { | ||
3276 | dev_err(&i2c->dev, "failed to initialize gpiod\n"); | ||
3277 | return PTR_ERR(rt5645->gpiod_hp_det); | ||
3278 | } | ||
2677 | 3279 | ||
2678 | rt5645->regmap = devm_regmap_init_i2c(i2c, &rt5645_regmap); | 3280 | rt5645->regmap = devm_regmap_init_i2c(i2c, &rt5645_regmap); |
2679 | if (IS_ERR(rt5645->regmap)) { | 3281 | if (IS_ERR(rt5645->regmap)) { |
@@ -2699,6 +3301,13 @@ static int rt5645_i2c_probe(struct i2c_client *i2c, | |||
2699 | return -ENODEV; | 3301 | return -ENODEV; |
2700 | } | 3302 | } |
2701 | 3303 | ||
3304 | if (rt5645->codec_type == CODEC_TYPE_RT5650) { | ||
3305 | ret = rt5650_calibration(rt5645); | ||
3306 | |||
3307 | if (ret < 0) | ||
3308 | pr_err("calibration failed!\n"); | ||
3309 | } | ||
3310 | |||
2702 | regmap_write(rt5645->regmap, RT5645_RESET, 0); | 3311 | regmap_write(rt5645->regmap, RT5645_RESET, 0); |
2703 | 3312 | ||
2704 | ret = regmap_register_patch(rt5645->regmap, init_list, | 3313 | ret = regmap_register_patch(rt5645->regmap, init_list, |
@@ -2718,84 +3327,76 @@ static int rt5645_i2c_probe(struct i2c_client *i2c, | |||
2718 | regmap_update_bits(rt5645->regmap, RT5645_IN2_CTRL, | 3327 | regmap_update_bits(rt5645->regmap, RT5645_IN2_CTRL, |
2719 | RT5645_IN_DF2, RT5645_IN_DF2); | 3328 | RT5645_IN_DF2, RT5645_IN_DF2); |
2720 | 3329 | ||
2721 | if (rt5645->pdata.dmic_en) { | 3330 | if (rt5645->pdata.dmic1_data_pin || rt5645->pdata.dmic2_data_pin) { |
2722 | regmap_update_bits(rt5645->regmap, RT5645_GPIO_CTRL1, | 3331 | regmap_update_bits(rt5645->regmap, RT5645_GPIO_CTRL1, |
2723 | RT5645_GP2_PIN_MASK, RT5645_GP2_PIN_DMIC1_SCL); | 3332 | RT5645_GP2_PIN_MASK, RT5645_GP2_PIN_DMIC1_SCL); |
3333 | } | ||
3334 | switch (rt5645->pdata.dmic1_data_pin) { | ||
3335 | case RT5645_DMIC_DATA_IN2N: | ||
3336 | regmap_update_bits(rt5645->regmap, RT5645_DMIC_CTRL1, | ||
3337 | RT5645_DMIC_1_DP_MASK, RT5645_DMIC_1_DP_IN2N); | ||
3338 | break; | ||
2724 | 3339 | ||
2725 | switch (rt5645->pdata.dmic1_data_pin) { | 3340 | case RT5645_DMIC_DATA_GPIO5: |
2726 | case RT5645_DMIC_DATA_IN2N: | 3341 | regmap_update_bits(rt5645->regmap, RT5645_DMIC_CTRL1, |
2727 | regmap_update_bits(rt5645->regmap, RT5645_DMIC_CTRL1, | 3342 | RT5645_DMIC_1_DP_MASK, RT5645_DMIC_1_DP_GPIO5); |
2728 | RT5645_DMIC_1_DP_MASK, RT5645_DMIC_1_DP_IN2N); | 3343 | regmap_update_bits(rt5645->regmap, RT5645_GPIO_CTRL1, |
2729 | break; | 3344 | RT5645_GP5_PIN_MASK, RT5645_GP5_PIN_DMIC1_SDA); |
2730 | 3345 | break; | |
2731 | case RT5645_DMIC_DATA_GPIO5: | ||
2732 | regmap_update_bits(rt5645->regmap, RT5645_DMIC_CTRL1, | ||
2733 | RT5645_DMIC_1_DP_MASK, RT5645_DMIC_1_DP_GPIO5); | ||
2734 | regmap_update_bits(rt5645->regmap, RT5645_GPIO_CTRL1, | ||
2735 | RT5645_GP5_PIN_MASK, RT5645_GP5_PIN_DMIC1_SDA); | ||
2736 | break; | ||
2737 | |||
2738 | case RT5645_DMIC_DATA_GPIO11: | ||
2739 | regmap_update_bits(rt5645->regmap, RT5645_DMIC_CTRL1, | ||
2740 | RT5645_DMIC_1_DP_MASK, RT5645_DMIC_1_DP_GPIO11); | ||
2741 | regmap_update_bits(rt5645->regmap, RT5645_GPIO_CTRL1, | ||
2742 | RT5645_GP11_PIN_MASK, | ||
2743 | RT5645_GP11_PIN_DMIC1_SDA); | ||
2744 | break; | ||
2745 | 3346 | ||
2746 | default: | 3347 | case RT5645_DMIC_DATA_GPIO11: |
2747 | break; | 3348 | regmap_update_bits(rt5645->regmap, RT5645_DMIC_CTRL1, |
2748 | } | 3349 | RT5645_DMIC_1_DP_MASK, RT5645_DMIC_1_DP_GPIO11); |
3350 | regmap_update_bits(rt5645->regmap, RT5645_GPIO_CTRL1, | ||
3351 | RT5645_GP11_PIN_MASK, | ||
3352 | RT5645_GP11_PIN_DMIC1_SDA); | ||
3353 | break; | ||
2749 | 3354 | ||
2750 | switch (rt5645->pdata.dmic2_data_pin) { | 3355 | default: |
2751 | case RT5645_DMIC_DATA_IN2P: | 3356 | break; |
2752 | regmap_update_bits(rt5645->regmap, RT5645_DMIC_CTRL1, | 3357 | } |
2753 | RT5645_DMIC_2_DP_MASK, RT5645_DMIC_2_DP_IN2P); | ||
2754 | break; | ||
2755 | 3358 | ||
2756 | case RT5645_DMIC_DATA_GPIO6: | 3359 | switch (rt5645->pdata.dmic2_data_pin) { |
2757 | regmap_update_bits(rt5645->regmap, RT5645_DMIC_CTRL1, | 3360 | case RT5645_DMIC_DATA_IN2P: |
2758 | RT5645_DMIC_2_DP_MASK, RT5645_DMIC_2_DP_GPIO6); | 3361 | regmap_update_bits(rt5645->regmap, RT5645_DMIC_CTRL1, |
2759 | regmap_update_bits(rt5645->regmap, RT5645_GPIO_CTRL1, | 3362 | RT5645_DMIC_2_DP_MASK, RT5645_DMIC_2_DP_IN2P); |
2760 | RT5645_GP6_PIN_MASK, RT5645_GP6_PIN_DMIC2_SDA); | 3363 | break; |
2761 | break; | ||
2762 | 3364 | ||
2763 | case RT5645_DMIC_DATA_GPIO10: | 3365 | case RT5645_DMIC_DATA_GPIO6: |
2764 | regmap_update_bits(rt5645->regmap, RT5645_DMIC_CTRL1, | 3366 | regmap_update_bits(rt5645->regmap, RT5645_DMIC_CTRL1, |
2765 | RT5645_DMIC_2_DP_MASK, RT5645_DMIC_2_DP_GPIO10); | 3367 | RT5645_DMIC_2_DP_MASK, RT5645_DMIC_2_DP_GPIO6); |
2766 | regmap_update_bits(rt5645->regmap, RT5645_GPIO_CTRL1, | 3368 | regmap_update_bits(rt5645->regmap, RT5645_GPIO_CTRL1, |
2767 | RT5645_GP10_PIN_MASK, | 3369 | RT5645_GP6_PIN_MASK, RT5645_GP6_PIN_DMIC2_SDA); |
2768 | RT5645_GP10_PIN_DMIC2_SDA); | 3370 | break; |
2769 | break; | ||
2770 | 3371 | ||
2771 | case RT5645_DMIC_DATA_GPIO12: | 3372 | case RT5645_DMIC_DATA_GPIO10: |
2772 | regmap_update_bits(rt5645->regmap, RT5645_DMIC_CTRL1, | 3373 | regmap_update_bits(rt5645->regmap, RT5645_DMIC_CTRL1, |
2773 | RT5645_DMIC_1_DP_MASK, RT5645_DMIC_2_DP_GPIO12); | 3374 | RT5645_DMIC_2_DP_MASK, RT5645_DMIC_2_DP_GPIO10); |
2774 | regmap_update_bits(rt5645->regmap, RT5645_GPIO_CTRL1, | 3375 | regmap_update_bits(rt5645->regmap, RT5645_GPIO_CTRL1, |
2775 | RT5645_GP12_PIN_MASK, | 3376 | RT5645_GP10_PIN_MASK, |
2776 | RT5645_GP12_PIN_DMIC2_SDA); | 3377 | RT5645_GP10_PIN_DMIC2_SDA); |
2777 | break; | 3378 | break; |
2778 | 3379 | ||
2779 | default: | 3380 | case RT5645_DMIC_DATA_GPIO12: |
2780 | break; | 3381 | regmap_update_bits(rt5645->regmap, RT5645_DMIC_CTRL1, |
2781 | } | 3382 | RT5645_DMIC_2_DP_MASK, RT5645_DMIC_2_DP_GPIO12); |
3383 | regmap_update_bits(rt5645->regmap, RT5645_GPIO_CTRL1, | ||
3384 | RT5645_GP12_PIN_MASK, | ||
3385 | RT5645_GP12_PIN_DMIC2_SDA); | ||
3386 | break; | ||
2782 | 3387 | ||
3388 | default: | ||
3389 | break; | ||
2783 | } | 3390 | } |
2784 | 3391 | ||
2785 | if (rt5645->pdata.en_jd_func) { | 3392 | if (rt5645->pdata.jd_mode) { |
2786 | regmap_update_bits(rt5645->regmap, RT5645_GEN_CTRL3, | 3393 | regmap_update_bits(rt5645->regmap, RT5645_GEN_CTRL3, |
2787 | RT5645_IRQ_CLK_GATE_CTRL | RT5645_MICINDET_MANU, | 3394 | RT5645_IRQ_CLK_GATE_CTRL, |
2788 | RT5645_IRQ_CLK_GATE_CTRL | RT5645_MICINDET_MANU); | 3395 | RT5645_IRQ_CLK_GATE_CTRL); |
2789 | regmap_update_bits(rt5645->regmap, RT5645_IN1_CTRL1, | 3396 | regmap_update_bits(rt5645->regmap, RT5645_IN1_CTRL1, |
2790 | RT5645_CBJ_BST1_EN, RT5645_CBJ_BST1_EN); | 3397 | RT5645_CBJ_BST1_EN, RT5645_CBJ_BST1_EN); |
2791 | regmap_update_bits(rt5645->regmap, RT5645_JD_CTRL3, | ||
2792 | RT5645_JD_CBJ_EN | RT5645_JD_CBJ_POL, | ||
2793 | RT5645_JD_CBJ_EN | RT5645_JD_CBJ_POL); | ||
2794 | regmap_update_bits(rt5645->regmap, RT5645_MICBIAS, | 3398 | regmap_update_bits(rt5645->regmap, RT5645_MICBIAS, |
2795 | RT5645_IRQ_CLK_INT, RT5645_IRQ_CLK_INT); | 3399 | RT5645_IRQ_CLK_INT, RT5645_IRQ_CLK_INT); |
2796 | } | ||
2797 | |||
2798 | if (rt5645->pdata.jd_mode) { | ||
2799 | regmap_update_bits(rt5645->regmap, RT5645_IRQ_CTRL2, | 3400 | regmap_update_bits(rt5645->regmap, RT5645_IRQ_CTRL2, |
2800 | RT5645_IRQ_JD_1_1_EN, RT5645_IRQ_JD_1_1_EN); | 3401 | RT5645_IRQ_JD_1_1_EN, RT5645_IRQ_JD_1_1_EN); |
2801 | regmap_update_bits(rt5645->regmap, RT5645_GEN_CTRL3, | 3402 | regmap_update_bits(rt5645->regmap, RT5645_GEN_CTRL3, |
@@ -2827,6 +3428,8 @@ static int rt5645_i2c_probe(struct i2c_client *i2c, | |||
2827 | } | 3428 | } |
2828 | } | 3429 | } |
2829 | 3430 | ||
3431 | INIT_DELAYED_WORK(&rt5645->jack_detect_work, rt5645_jack_detect_work); | ||
3432 | |||
2830 | if (rt5645->i2c->irq) { | 3433 | if (rt5645->i2c->irq) { |
2831 | ret = request_threaded_irq(rt5645->i2c->irq, NULL, rt5645_irq, | 3434 | ret = request_threaded_irq(rt5645->i2c->irq, NULL, rt5645_irq, |
2832 | IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING | 3435 | IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING |
@@ -2835,18 +3438,6 @@ static int rt5645_i2c_probe(struct i2c_client *i2c, | |||
2835 | dev_err(&i2c->dev, "Failed to reguest IRQ: %d\n", ret); | 3438 | dev_err(&i2c->dev, "Failed to reguest IRQ: %d\n", ret); |
2836 | } | 3439 | } |
2837 | 3440 | ||
2838 | if (gpio_is_valid(rt5645->pdata.hp_det_gpio)) { | ||
2839 | ret = gpio_request(rt5645->pdata.hp_det_gpio, "rt5645"); | ||
2840 | if (ret) | ||
2841 | dev_err(&i2c->dev, "Fail gpio_request hp_det_gpio\n"); | ||
2842 | |||
2843 | ret = gpio_direction_input(rt5645->pdata.hp_det_gpio); | ||
2844 | if (ret) | ||
2845 | dev_err(&i2c->dev, "Fail gpio_direction hp_det_gpio\n"); | ||
2846 | } | ||
2847 | |||
2848 | INIT_DELAYED_WORK(&rt5645->jack_detect_work, rt5645_jack_detect_work); | ||
2849 | |||
2850 | return snd_soc_register_codec(&i2c->dev, &soc_codec_dev_rt5645, | 3441 | return snd_soc_register_codec(&i2c->dev, &soc_codec_dev_rt5645, |
2851 | rt5645_dai, ARRAY_SIZE(rt5645_dai)); | 3442 | rt5645_dai, ARRAY_SIZE(rt5645_dai)); |
2852 | } | 3443 | } |
@@ -2860,9 +3451,6 @@ static int rt5645_i2c_remove(struct i2c_client *i2c) | |||
2860 | 3451 | ||
2861 | cancel_delayed_work_sync(&rt5645->jack_detect_work); | 3452 | cancel_delayed_work_sync(&rt5645->jack_detect_work); |
2862 | 3453 | ||
2863 | if (gpio_is_valid(rt5645->pdata.hp_det_gpio)) | ||
2864 | gpio_free(rt5645->pdata.hp_det_gpio); | ||
2865 | |||
2866 | snd_soc_unregister_codec(&i2c->dev); | 3454 | snd_soc_unregister_codec(&i2c->dev); |
2867 | 3455 | ||
2868 | return 0; | 3456 | return 0; |
@@ -2872,6 +3460,7 @@ static struct i2c_driver rt5645_i2c_driver = { | |||
2872 | .driver = { | 3460 | .driver = { |
2873 | .name = "rt5645", | 3461 | .name = "rt5645", |
2874 | .owner = THIS_MODULE, | 3462 | .owner = THIS_MODULE, |
3463 | .acpi_match_table = ACPI_PTR(rt5645_acpi_match), | ||
2875 | }, | 3464 | }, |
2876 | .probe = rt5645_i2c_probe, | 3465 | .probe = rt5645_i2c_probe, |
2877 | .remove = rt5645_i2c_remove, | 3466 | .remove = rt5645_i2c_remove, |
diff --git a/sound/soc/codecs/rt5645.h b/sound/soc/codecs/rt5645.h index db78e9462876..0353a6a273ab 100644 --- a/sound/soc/codecs/rt5645.h +++ b/sound/soc/codecs/rt5645.h | |||
@@ -105,6 +105,7 @@ | |||
105 | #define RT5645_TDM_CTRL_1 0x77 | 105 | #define RT5645_TDM_CTRL_1 0x77 |
106 | #define RT5645_TDM_CTRL_2 0x78 | 106 | #define RT5645_TDM_CTRL_2 0x78 |
107 | #define RT5645_TDM_CTRL_3 0x79 | 107 | #define RT5645_TDM_CTRL_3 0x79 |
108 | #define RT5650_TDM_CTRL_4 0x7a | ||
108 | 109 | ||
109 | /* Function - Analog */ | 110 | /* Function - Analog */ |
110 | #define RT5645_GLB_CLK 0x80 | 111 | #define RT5645_GLB_CLK 0x80 |
@@ -942,10 +943,6 @@ | |||
942 | #define RT5645_I2S2_SDI_I2S2 (0x1 << 6) | 943 | #define RT5645_I2S2_SDI_I2S2 (0x1 << 6) |
943 | 944 | ||
944 | /* ADC/DAC Clock Control 1 (0x73) */ | 945 | /* ADC/DAC Clock Control 1 (0x73) */ |
945 | #define RT5645_I2S_BCLK_MS1_MASK (0x1 << 15) | ||
946 | #define RT5645_I2S_BCLK_MS1_SFT 15 | ||
947 | #define RT5645_I2S_BCLK_MS1_32 (0x0 << 15) | ||
948 | #define RT5645_I2S_BCLK_MS1_64 (0x1 << 15) | ||
949 | #define RT5645_I2S_PD1_MASK (0x7 << 12) | 946 | #define RT5645_I2S_PD1_MASK (0x7 << 12) |
950 | #define RT5645_I2S_PD1_SFT 12 | 947 | #define RT5645_I2S_PD1_SFT 12 |
951 | #define RT5645_I2S_PD1_1 (0x0 << 12) | 948 | #define RT5645_I2S_PD1_1 (0x0 << 12) |
@@ -1067,13 +1064,14 @@ | |||
1067 | #define RT5645_SCLK_SRC_SFT 14 | 1064 | #define RT5645_SCLK_SRC_SFT 14 |
1068 | #define RT5645_SCLK_SRC_MCLK (0x0 << 14) | 1065 | #define RT5645_SCLK_SRC_MCLK (0x0 << 14) |
1069 | #define RT5645_SCLK_SRC_PLL1 (0x1 << 14) | 1066 | #define RT5645_SCLK_SRC_PLL1 (0x1 << 14) |
1070 | #define RT5645_SCLK_SRC_RCCLK (0x2 << 14) /* 15MHz */ | 1067 | #define RT5645_SCLK_SRC_RCCLK (0x2 << 14) |
1071 | #define RT5645_PLL1_SRC_MASK (0x3 << 12) | 1068 | #define RT5645_PLL1_SRC_MASK (0x7 << 11) |
1072 | #define RT5645_PLL1_SRC_SFT 12 | 1069 | #define RT5645_PLL1_SRC_SFT 11 |
1073 | #define RT5645_PLL1_SRC_MCLK (0x0 << 12) | 1070 | #define RT5645_PLL1_SRC_MCLK (0x0 << 11) |
1074 | #define RT5645_PLL1_SRC_BCLK1 (0x1 << 12) | 1071 | #define RT5645_PLL1_SRC_BCLK1 (0x1 << 11) |
1075 | #define RT5645_PLL1_SRC_BCLK2 (0x2 << 12) | 1072 | #define RT5645_PLL1_SRC_BCLK2 (0x2 << 11) |
1076 | #define RT5645_PLL1_SRC_BCLK3 (0x3 << 12) | 1073 | #define RT5645_PLL1_SRC_BCLK3 (0x3 << 11) |
1074 | #define RT5645_PLL1_SRC_RCCLK (0x4 << 11) | ||
1077 | #define RT5645_PLL1_PD_MASK (0x1 << 3) | 1075 | #define RT5645_PLL1_PD_MASK (0x1 << 3) |
1078 | #define RT5645_PLL1_PD_SFT 3 | 1076 | #define RT5645_PLL1_PD_SFT 3 |
1079 | #define RT5645_PLL1_PD_1 (0x0 << 3) | 1077 | #define RT5645_PLL1_PD_1 (0x0 << 3) |
@@ -2147,6 +2145,7 @@ enum { | |||
2147 | }; | 2145 | }; |
2148 | 2146 | ||
2149 | enum { | 2147 | enum { |
2148 | RT5645_DMIC1_DISABLE, | ||
2150 | RT5645_DMIC_DATA_IN2P, | 2149 | RT5645_DMIC_DATA_IN2P, |
2151 | RT5645_DMIC_DATA_GPIO6, | 2150 | RT5645_DMIC_DATA_GPIO6, |
2152 | RT5645_DMIC_DATA_GPIO10, | 2151 | RT5645_DMIC_DATA_GPIO10, |
@@ -2154,6 +2153,7 @@ enum { | |||
2154 | }; | 2153 | }; |
2155 | 2154 | ||
2156 | enum { | 2155 | enum { |
2156 | RT5645_DMIC2_DISABLE, | ||
2157 | RT5645_DMIC_DATA_IN2N, | 2157 | RT5645_DMIC_DATA_IN2N, |
2158 | RT5645_DMIC_DATA_GPIO5, | 2158 | RT5645_DMIC_DATA_GPIO5, |
2159 | RT5645_DMIC_DATA_GPIO11, | 2159 | RT5645_DMIC_DATA_GPIO11, |
@@ -2182,8 +2182,10 @@ struct rt5645_priv { | |||
2182 | struct rt5645_platform_data pdata; | 2182 | struct rt5645_platform_data pdata; |
2183 | struct regmap *regmap; | 2183 | struct regmap *regmap; |
2184 | struct i2c_client *i2c; | 2184 | struct i2c_client *i2c; |
2185 | struct gpio_desc *gpiod_hp_det; | ||
2185 | struct snd_soc_jack *hp_jack; | 2186 | struct snd_soc_jack *hp_jack; |
2186 | struct snd_soc_jack *mic_jack; | 2187 | struct snd_soc_jack *mic_jack; |
2188 | struct snd_soc_jack *btn_jack; | ||
2187 | struct delayed_work jack_detect_work; | 2189 | struct delayed_work jack_detect_work; |
2188 | 2190 | ||
2189 | int codec_type; | 2191 | int codec_type; |
@@ -2196,9 +2198,12 @@ struct rt5645_priv { | |||
2196 | int pll_src; | 2198 | int pll_src; |
2197 | int pll_in; | 2199 | int pll_in; |
2198 | int pll_out; | 2200 | int pll_out; |
2201 | |||
2202 | int jack_type; | ||
2203 | bool en_button_func; | ||
2199 | }; | 2204 | }; |
2200 | 2205 | ||
2201 | int rt5645_set_jack_detect(struct snd_soc_codec *codec, | 2206 | int rt5645_set_jack_detect(struct snd_soc_codec *codec, |
2202 | struct snd_soc_jack *hp_jack, struct snd_soc_jack *mic_jack); | 2207 | struct snd_soc_jack *hp_jack, struct snd_soc_jack *mic_jack, |
2203 | 2208 | struct snd_soc_jack *btn_jack); | |
2204 | #endif /* __RT5645_H__ */ | 2209 | #endif /* __RT5645_H__ */ |
diff --git a/sound/soc/codecs/rt5651.c b/sound/soc/codecs/rt5651.c index 9f4c7be6d798..a3506e193abc 100644 --- a/sound/soc/codecs/rt5651.c +++ b/sound/soc/codecs/rt5651.c | |||
@@ -1571,7 +1571,7 @@ static int rt5651_set_bias_level(struct snd_soc_codec *codec, | |||
1571 | { | 1571 | { |
1572 | switch (level) { | 1572 | switch (level) { |
1573 | case SND_SOC_BIAS_PREPARE: | 1573 | case SND_SOC_BIAS_PREPARE: |
1574 | if (SND_SOC_BIAS_STANDBY == codec->dapm.bias_level) { | 1574 | if (SND_SOC_BIAS_STANDBY == snd_soc_codec_get_bias_level(codec)) { |
1575 | snd_soc_update_bits(codec, RT5651_PWR_ANLG1, | 1575 | snd_soc_update_bits(codec, RT5651_PWR_ANLG1, |
1576 | RT5651_PWR_VREF1 | RT5651_PWR_MB | | 1576 | RT5651_PWR_VREF1 | RT5651_PWR_MB | |
1577 | RT5651_PWR_BG | RT5651_PWR_VREF2, | 1577 | RT5651_PWR_BG | RT5651_PWR_VREF2, |
@@ -1604,7 +1604,6 @@ static int rt5651_set_bias_level(struct snd_soc_codec *codec, | |||
1604 | default: | 1604 | default: |
1605 | break; | 1605 | break; |
1606 | } | 1606 | } |
1607 | codec->dapm.bias_level = level; | ||
1608 | 1607 | ||
1609 | return 0; | 1608 | return 0; |
1610 | } | 1609 | } |
@@ -1625,7 +1624,7 @@ static int rt5651_probe(struct snd_soc_codec *codec) | |||
1625 | RT5651_PWR_FV1 | RT5651_PWR_FV2, | 1624 | RT5651_PWR_FV1 | RT5651_PWR_FV2, |
1626 | RT5651_PWR_FV1 | RT5651_PWR_FV2); | 1625 | RT5651_PWR_FV1 | RT5651_PWR_FV2); |
1627 | 1626 | ||
1628 | rt5651_set_bias_level(codec, SND_SOC_BIAS_OFF); | 1627 | snd_soc_codec_force_bias_level(codec, SND_SOC_BIAS_OFF); |
1629 | 1628 | ||
1630 | return 0; | 1629 | return 0; |
1631 | } | 1630 | } |
diff --git a/sound/soc/codecs/rt5670.c b/sound/soc/codecs/rt5670.c index cc7f84a150a7..a9123d414178 100644 --- a/sound/soc/codecs/rt5670.c +++ b/sound/soc/codecs/rt5670.c | |||
@@ -51,12 +51,11 @@ static const struct regmap_range_cfg rt5670_ranges[] = { | |||
51 | .window_len = 0x1, }, | 51 | .window_len = 0x1, }, |
52 | }; | 52 | }; |
53 | 53 | ||
54 | static struct reg_default init_list[] = { | 54 | static const struct reg_default init_list[] = { |
55 | { RT5670_PR_BASE + 0x14, 0x9a8a }, | 55 | { RT5670_PR_BASE + 0x14, 0x9a8a }, |
56 | { RT5670_PR_BASE + 0x38, 0x3ba1 }, | 56 | { RT5670_PR_BASE + 0x38, 0x3ba1 }, |
57 | { RT5670_PR_BASE + 0x3d, 0x3640 }, | 57 | { RT5670_PR_BASE + 0x3d, 0x3640 }, |
58 | }; | 58 | }; |
59 | #define RT5670_INIT_REG_LEN ARRAY_SIZE(init_list) | ||
60 | 59 | ||
61 | static const struct reg_default rt5670_reg[] = { | 60 | static const struct reg_default rt5670_reg[] = { |
62 | { 0x00, 0x0000 }, | 61 | { 0x00, 0x0000 }, |
@@ -416,12 +415,12 @@ static bool rt5670_readable_register(struct device *dev, unsigned int reg) | |||
416 | static int rt5670_headset_detect(struct snd_soc_codec *codec, int jack_insert) | 415 | static int rt5670_headset_detect(struct snd_soc_codec *codec, int jack_insert) |
417 | { | 416 | { |
418 | int val; | 417 | int val; |
418 | struct snd_soc_dapm_context *dapm = snd_soc_codec_get_dapm(codec); | ||
419 | struct rt5670_priv *rt5670 = snd_soc_codec_get_drvdata(codec); | 419 | struct rt5670_priv *rt5670 = snd_soc_codec_get_drvdata(codec); |
420 | 420 | ||
421 | if (jack_insert) { | 421 | if (jack_insert) { |
422 | snd_soc_dapm_force_enable_pin(&codec->dapm, | 422 | snd_soc_dapm_force_enable_pin(dapm, "Mic Det Power"); |
423 | "Mic Det Power"); | 423 | snd_soc_dapm_sync(dapm); |
424 | snd_soc_dapm_sync(&codec->dapm); | ||
425 | snd_soc_update_bits(codec, RT5670_GEN_CTRL3, 0x4, 0x0); | 424 | snd_soc_update_bits(codec, RT5670_GEN_CTRL3, 0x4, 0x0); |
426 | snd_soc_update_bits(codec, RT5670_CJ_CTRL2, | 425 | snd_soc_update_bits(codec, RT5670_CJ_CTRL2, |
427 | RT5670_CBJ_DET_MODE | RT5670_CBJ_MN_JD, | 426 | RT5670_CBJ_DET_MODE | RT5670_CBJ_MN_JD, |
@@ -447,15 +446,15 @@ static int rt5670_headset_detect(struct snd_soc_codec *codec, int jack_insert) | |||
447 | } else { | 446 | } else { |
448 | snd_soc_update_bits(codec, RT5670_GEN_CTRL3, 0x4, 0x4); | 447 | snd_soc_update_bits(codec, RT5670_GEN_CTRL3, 0x4, 0x4); |
449 | rt5670->jack_type = SND_JACK_HEADPHONE; | 448 | rt5670->jack_type = SND_JACK_HEADPHONE; |
450 | snd_soc_dapm_disable_pin(&codec->dapm, "Mic Det Power"); | 449 | snd_soc_dapm_disable_pin(dapm, "Mic Det Power"); |
451 | snd_soc_dapm_sync(&codec->dapm); | 450 | snd_soc_dapm_sync(dapm); |
452 | } | 451 | } |
453 | } else { | 452 | } else { |
454 | snd_soc_update_bits(codec, RT5670_INT_IRQ_ST, 0x8, 0x0); | 453 | snd_soc_update_bits(codec, RT5670_INT_IRQ_ST, 0x8, 0x0); |
455 | snd_soc_update_bits(codec, RT5670_GEN_CTRL3, 0x4, 0x4); | 454 | snd_soc_update_bits(codec, RT5670_GEN_CTRL3, 0x4, 0x4); |
456 | rt5670->jack_type = 0; | 455 | rt5670->jack_type = 0; |
457 | snd_soc_dapm_disable_pin(&codec->dapm, "Mic Det Power"); | 456 | snd_soc_dapm_disable_pin(dapm, "Mic Det Power"); |
458 | snd_soc_dapm_sync(&codec->dapm); | 457 | snd_soc_dapm_sync(dapm); |
459 | } | 458 | } |
460 | 459 | ||
461 | return rt5670->jack_type; | 460 | return rt5670->jack_type; |
@@ -2603,7 +2602,7 @@ static int rt5670_set_bias_level(struct snd_soc_codec *codec, | |||
2603 | 2602 | ||
2604 | switch (level) { | 2603 | switch (level) { |
2605 | case SND_SOC_BIAS_PREPARE: | 2604 | case SND_SOC_BIAS_PREPARE: |
2606 | if (SND_SOC_BIAS_STANDBY == codec->dapm.bias_level) { | 2605 | if (SND_SOC_BIAS_STANDBY == snd_soc_codec_get_bias_level(codec)) { |
2607 | snd_soc_update_bits(codec, RT5670_PWR_ANLG1, | 2606 | snd_soc_update_bits(codec, RT5670_PWR_ANLG1, |
2608 | RT5670_PWR_VREF1 | RT5670_PWR_MB | | 2607 | RT5670_PWR_VREF1 | RT5670_PWR_MB | |
2609 | RT5670_PWR_BG | RT5670_PWR_VREF2, | 2608 | RT5670_PWR_BG | RT5670_PWR_VREF2, |
@@ -2647,30 +2646,30 @@ static int rt5670_set_bias_level(struct snd_soc_codec *codec, | |||
2647 | default: | 2646 | default: |
2648 | break; | 2647 | break; |
2649 | } | 2648 | } |
2650 | codec->dapm.bias_level = level; | ||
2651 | 2649 | ||
2652 | return 0; | 2650 | return 0; |
2653 | } | 2651 | } |
2654 | 2652 | ||
2655 | static int rt5670_probe(struct snd_soc_codec *codec) | 2653 | static int rt5670_probe(struct snd_soc_codec *codec) |
2656 | { | 2654 | { |
2655 | struct snd_soc_dapm_context *dapm = snd_soc_codec_get_dapm(codec); | ||
2657 | struct rt5670_priv *rt5670 = snd_soc_codec_get_drvdata(codec); | 2656 | struct rt5670_priv *rt5670 = snd_soc_codec_get_drvdata(codec); |
2658 | 2657 | ||
2659 | switch (snd_soc_read(codec, RT5670_RESET) & RT5670_ID_MASK) { | 2658 | switch (snd_soc_read(codec, RT5670_RESET) & RT5670_ID_MASK) { |
2660 | case RT5670_ID_5670: | 2659 | case RT5670_ID_5670: |
2661 | case RT5670_ID_5671: | 2660 | case RT5670_ID_5671: |
2662 | snd_soc_dapm_new_controls(&codec->dapm, | 2661 | snd_soc_dapm_new_controls(dapm, |
2663 | rt5670_specific_dapm_widgets, | 2662 | rt5670_specific_dapm_widgets, |
2664 | ARRAY_SIZE(rt5670_specific_dapm_widgets)); | 2663 | ARRAY_SIZE(rt5670_specific_dapm_widgets)); |
2665 | snd_soc_dapm_add_routes(&codec->dapm, | 2664 | snd_soc_dapm_add_routes(dapm, |
2666 | rt5670_specific_dapm_routes, | 2665 | rt5670_specific_dapm_routes, |
2667 | ARRAY_SIZE(rt5670_specific_dapm_routes)); | 2666 | ARRAY_SIZE(rt5670_specific_dapm_routes)); |
2668 | break; | 2667 | break; |
2669 | case RT5670_ID_5672: | 2668 | case RT5670_ID_5672: |
2670 | snd_soc_dapm_new_controls(&codec->dapm, | 2669 | snd_soc_dapm_new_controls(dapm, |
2671 | rt5672_specific_dapm_widgets, | 2670 | rt5672_specific_dapm_widgets, |
2672 | ARRAY_SIZE(rt5672_specific_dapm_widgets)); | 2671 | ARRAY_SIZE(rt5672_specific_dapm_widgets)); |
2673 | snd_soc_dapm_add_routes(&codec->dapm, | 2672 | snd_soc_dapm_add_routes(dapm, |
2674 | rt5672_specific_dapm_routes, | 2673 | rt5672_specific_dapm_routes, |
2675 | ARRAY_SIZE(rt5672_specific_dapm_routes)); | 2674 | ARRAY_SIZE(rt5672_specific_dapm_routes)); |
2676 | break; | 2675 | break; |
@@ -2809,7 +2808,7 @@ static const struct i2c_device_id rt5670_i2c_id[] = { | |||
2809 | MODULE_DEVICE_TABLE(i2c, rt5670_i2c_id); | 2808 | MODULE_DEVICE_TABLE(i2c, rt5670_i2c_id); |
2810 | 2809 | ||
2811 | #ifdef CONFIG_ACPI | 2810 | #ifdef CONFIG_ACPI |
2812 | static struct acpi_device_id rt5670_acpi_match[] = { | 2811 | static const struct acpi_device_id rt5670_acpi_match[] = { |
2813 | { "10EC5670", 0}, | 2812 | { "10EC5670", 0}, |
2814 | { }, | 2813 | { }, |
2815 | }; | 2814 | }; |
diff --git a/sound/soc/codecs/rt5677.c b/sound/soc/codecs/rt5677.c index af182586712d..31d969ac1192 100644 --- a/sound/soc/codecs/rt5677.c +++ b/sound/soc/codecs/rt5677.c | |||
@@ -62,6 +62,9 @@ static const struct reg_default init_list[] = { | |||
62 | {RT5677_PR_BASE + 0x1e, 0x0000}, | 62 | {RT5677_PR_BASE + 0x1e, 0x0000}, |
63 | {RT5677_PR_BASE + 0x12, 0x0eaa}, | 63 | {RT5677_PR_BASE + 0x12, 0x0eaa}, |
64 | {RT5677_PR_BASE + 0x14, 0x018a}, | 64 | {RT5677_PR_BASE + 0x14, 0x018a}, |
65 | {RT5677_PR_BASE + 0x15, 0x0490}, | ||
66 | {RT5677_PR_BASE + 0x38, 0x0f71}, | ||
67 | {RT5677_PR_BASE + 0x39, 0x0f71}, | ||
65 | }; | 68 | }; |
66 | #define RT5677_INIT_REG_LEN ARRAY_SIZE(init_list) | 69 | #define RT5677_INIT_REG_LEN ARRAY_SIZE(init_list) |
67 | 70 | ||
@@ -817,7 +820,7 @@ static int rt5677_dsp_vad_put(struct snd_kcontrol *kcontrol, | |||
817 | 820 | ||
818 | rt5677->dsp_vad_en = !!ucontrol->value.integer.value[0]; | 821 | rt5677->dsp_vad_en = !!ucontrol->value.integer.value[0]; |
819 | 822 | ||
820 | if (codec->dapm.bias_level == SND_SOC_BIAS_OFF) | 823 | if (snd_soc_codec_get_bias_level(codec) == SND_SOC_BIAS_OFF) |
821 | rt5677_set_dsp_vad(codec, rt5677->dsp_vad_en); | 824 | rt5677_set_dsp_vad(codec, rt5677->dsp_vad_en); |
822 | 825 | ||
823 | return 0; | 826 | return 0; |
@@ -914,7 +917,7 @@ static int set_dmic_clk(struct snd_soc_dapm_widget *w, | |||
914 | { | 917 | { |
915 | struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm); | 918 | struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm); |
916 | struct rt5677_priv *rt5677 = snd_soc_codec_get_drvdata(codec); | 919 | struct rt5677_priv *rt5677 = snd_soc_codec_get_drvdata(codec); |
917 | int idx = rl6231_calc_dmic_clk(rt5677->sysclk); | 920 | int idx = rl6231_calc_dmic_clk(rt5677->lrck[RT5677_AIF1] << 8); |
918 | 921 | ||
919 | if (idx < 0) | 922 | if (idx < 0) |
920 | dev_err(codec->dev, "Failed to set DMIC clock\n"); | 923 | dev_err(codec->dev, "Failed to set DMIC clock\n"); |
@@ -1057,6 +1060,7 @@ int rt5677_sel_asrc_clk_src(struct snd_soc_codec *codec, | |||
1057 | unsigned int asrc5_mask = 0, asrc5_value = 0; | 1060 | unsigned int asrc5_mask = 0, asrc5_value = 0; |
1058 | unsigned int asrc6_mask = 0, asrc6_value = 0; | 1061 | unsigned int asrc6_mask = 0, asrc6_value = 0; |
1059 | unsigned int asrc7_mask = 0, asrc7_value = 0; | 1062 | unsigned int asrc7_mask = 0, asrc7_value = 0; |
1063 | unsigned int asrc8_mask = 0, asrc8_value = 0; | ||
1060 | 1064 | ||
1061 | switch (clk_src) { | 1065 | switch (clk_src) { |
1062 | case RT5677_CLK_SEL_SYS: | 1066 | case RT5677_CLK_SEL_SYS: |
@@ -1193,10 +1197,108 @@ int rt5677_sel_asrc_clk_src(struct snd_soc_codec *codec, | |||
1193 | regmap_update_bits(rt5677->regmap, RT5677_ASRC_7, asrc7_mask, | 1197 | regmap_update_bits(rt5677->regmap, RT5677_ASRC_7, asrc7_mask, |
1194 | asrc7_value); | 1198 | asrc7_value); |
1195 | 1199 | ||
1200 | /* ASRC 8 */ | ||
1201 | if (filter_mask & RT5677_I2S1_SOURCE) { | ||
1202 | asrc8_mask |= RT5677_I2S1_CLK_SEL_MASK; | ||
1203 | asrc8_value = (asrc8_value & ~RT5677_I2S1_CLK_SEL_MASK) | ||
1204 | | ((clk_src - 1) << RT5677_I2S1_CLK_SEL_SFT); | ||
1205 | } | ||
1206 | |||
1207 | if (filter_mask & RT5677_I2S2_SOURCE) { | ||
1208 | asrc8_mask |= RT5677_I2S2_CLK_SEL_MASK; | ||
1209 | asrc8_value = (asrc8_value & ~RT5677_I2S2_CLK_SEL_MASK) | ||
1210 | | ((clk_src - 1) << RT5677_I2S2_CLK_SEL_SFT); | ||
1211 | } | ||
1212 | |||
1213 | if (filter_mask & RT5677_I2S3_SOURCE) { | ||
1214 | asrc8_mask |= RT5677_I2S3_CLK_SEL_MASK; | ||
1215 | asrc8_value = (asrc8_value & ~RT5677_I2S3_CLK_SEL_MASK) | ||
1216 | | ((clk_src - 1) << RT5677_I2S3_CLK_SEL_SFT); | ||
1217 | } | ||
1218 | |||
1219 | if (filter_mask & RT5677_I2S4_SOURCE) { | ||
1220 | asrc8_mask |= RT5677_I2S4_CLK_SEL_MASK; | ||
1221 | asrc8_value = (asrc8_value & ~RT5677_I2S4_CLK_SEL_MASK) | ||
1222 | | ((clk_src - 1) << RT5677_I2S4_CLK_SEL_SFT); | ||
1223 | } | ||
1224 | |||
1225 | if (asrc8_mask) | ||
1226 | regmap_update_bits(rt5677->regmap, RT5677_ASRC_8, asrc8_mask, | ||
1227 | asrc8_value); | ||
1228 | |||
1196 | return 0; | 1229 | return 0; |
1197 | } | 1230 | } |
1198 | EXPORT_SYMBOL_GPL(rt5677_sel_asrc_clk_src); | 1231 | EXPORT_SYMBOL_GPL(rt5677_sel_asrc_clk_src); |
1199 | 1232 | ||
1233 | static int rt5677_dmic_use_asrc(struct snd_soc_dapm_widget *source, | ||
1234 | struct snd_soc_dapm_widget *sink) | ||
1235 | { | ||
1236 | struct snd_soc_codec *codec = snd_soc_dapm_to_codec(source->dapm); | ||
1237 | struct rt5677_priv *rt5677 = snd_soc_codec_get_drvdata(codec); | ||
1238 | unsigned int asrc_setting; | ||
1239 | |||
1240 | switch (source->shift) { | ||
1241 | case 11: | ||
1242 | regmap_read(rt5677->regmap, RT5677_ASRC_5, &asrc_setting); | ||
1243 | asrc_setting = (asrc_setting & RT5677_AD_STO1_CLK_SEL_MASK) >> | ||
1244 | RT5677_AD_STO1_CLK_SEL_SFT; | ||
1245 | if (asrc_setting >= RT5677_CLK_SEL_I2S1_ASRC && | ||
1246 | asrc_setting <= RT5677_CLK_SEL_I2S6_ASRC) | ||
1247 | return 1; | ||
1248 | break; | ||
1249 | |||
1250 | case 10: | ||
1251 | regmap_read(rt5677->regmap, RT5677_ASRC_5, &asrc_setting); | ||
1252 | asrc_setting = (asrc_setting & RT5677_AD_STO2_CLK_SEL_MASK) >> | ||
1253 | RT5677_AD_STO2_CLK_SEL_SFT; | ||
1254 | if (asrc_setting >= RT5677_CLK_SEL_I2S1_ASRC && | ||
1255 | asrc_setting <= RT5677_CLK_SEL_I2S6_ASRC) | ||
1256 | return 1; | ||
1257 | break; | ||
1258 | |||
1259 | case 9: | ||
1260 | regmap_read(rt5677->regmap, RT5677_ASRC_5, &asrc_setting); | ||
1261 | asrc_setting = (asrc_setting & RT5677_AD_STO3_CLK_SEL_MASK) >> | ||
1262 | RT5677_AD_STO3_CLK_SEL_SFT; | ||
1263 | if (asrc_setting >= RT5677_CLK_SEL_I2S1_ASRC && | ||
1264 | asrc_setting <= RT5677_CLK_SEL_I2S6_ASRC) | ||
1265 | return 1; | ||
1266 | break; | ||
1267 | |||
1268 | case 8: | ||
1269 | regmap_read(rt5677->regmap, RT5677_ASRC_5, &asrc_setting); | ||
1270 | asrc_setting = (asrc_setting & RT5677_AD_STO4_CLK_SEL_MASK) >> | ||
1271 | RT5677_AD_STO4_CLK_SEL_SFT; | ||
1272 | if (asrc_setting >= RT5677_CLK_SEL_I2S1_ASRC && | ||
1273 | asrc_setting <= RT5677_CLK_SEL_I2S6_ASRC) | ||
1274 | return 1; | ||
1275 | break; | ||
1276 | |||
1277 | case 7: | ||
1278 | regmap_read(rt5677->regmap, RT5677_ASRC_6, &asrc_setting); | ||
1279 | asrc_setting = (asrc_setting & RT5677_AD_MONOL_CLK_SEL_MASK) >> | ||
1280 | RT5677_AD_MONOL_CLK_SEL_SFT; | ||
1281 | if (asrc_setting >= RT5677_CLK_SEL_I2S1_ASRC && | ||
1282 | asrc_setting <= RT5677_CLK_SEL_I2S6_ASRC) | ||
1283 | return 1; | ||
1284 | break; | ||
1285 | |||
1286 | case 6: | ||
1287 | regmap_read(rt5677->regmap, RT5677_ASRC_6, &asrc_setting); | ||
1288 | asrc_setting = (asrc_setting & RT5677_AD_MONOR_CLK_SEL_MASK) >> | ||
1289 | RT5677_AD_MONOR_CLK_SEL_SFT; | ||
1290 | if (asrc_setting >= RT5677_CLK_SEL_I2S1_ASRC && | ||
1291 | asrc_setting <= RT5677_CLK_SEL_I2S6_ASRC) | ||
1292 | return 1; | ||
1293 | break; | ||
1294 | |||
1295 | default: | ||
1296 | break; | ||
1297 | } | ||
1298 | |||
1299 | return 0; | ||
1300 | } | ||
1301 | |||
1200 | /* Digital Mixer */ | 1302 | /* Digital Mixer */ |
1201 | static const struct snd_kcontrol_new rt5677_sto1_adc_l_mix[] = { | 1303 | static const struct snd_kcontrol_new rt5677_sto1_adc_l_mix[] = { |
1202 | SOC_DAPM_SINGLE("ADC1 Switch", RT5677_STO1_ADC_MIXER, | 1304 | SOC_DAPM_SINGLE("ADC1 Switch", RT5677_STO1_ADC_MIXER, |
@@ -2476,7 +2578,7 @@ static int rt5677_vref_event(struct snd_soc_dapm_widget *w, | |||
2476 | 2578 | ||
2477 | switch (event) { | 2579 | switch (event) { |
2478 | case SND_SOC_DAPM_POST_PMU: | 2580 | case SND_SOC_DAPM_POST_PMU: |
2479 | if (codec->dapm.bias_level != SND_SOC_BIAS_ON && | 2581 | if (snd_soc_codec_get_bias_level(codec) != SND_SOC_BIAS_ON && |
2480 | !rt5677->is_vref_slow) { | 2582 | !rt5677->is_vref_slow) { |
2481 | mdelay(20); | 2583 | mdelay(20); |
2482 | regmap_update_bits(rt5677->regmap, RT5677_PWR_ANLG1, | 2584 | regmap_update_bits(rt5677->regmap, RT5677_PWR_ANLG1, |
@@ -3054,12 +3156,12 @@ static const struct snd_soc_dapm_widget rt5677_dapm_widgets[] = { | |||
3054 | }; | 3156 | }; |
3055 | 3157 | ||
3056 | static const struct snd_soc_dapm_route rt5677_dapm_routes[] = { | 3158 | static const struct snd_soc_dapm_route rt5677_dapm_routes[] = { |
3057 | { "Stereo1 DMIC Mux", NULL, "DMIC STO1 ASRC", can_use_asrc }, | 3159 | { "Stereo1 DMIC Mux", NULL, "DMIC STO1 ASRC", rt5677_dmic_use_asrc }, |
3058 | { "Stereo2 DMIC Mux", NULL, "DMIC STO2 ASRC", can_use_asrc }, | 3160 | { "Stereo2 DMIC Mux", NULL, "DMIC STO2 ASRC", rt5677_dmic_use_asrc }, |
3059 | { "Stereo3 DMIC Mux", NULL, "DMIC STO3 ASRC", can_use_asrc }, | 3161 | { "Stereo3 DMIC Mux", NULL, "DMIC STO3 ASRC", rt5677_dmic_use_asrc }, |
3060 | { "Stereo4 DMIC Mux", NULL, "DMIC STO4 ASRC", can_use_asrc }, | 3162 | { "Stereo4 DMIC Mux", NULL, "DMIC STO4 ASRC", rt5677_dmic_use_asrc }, |
3061 | { "Mono DMIC L Mux", NULL, "DMIC MONO L ASRC", can_use_asrc }, | 3163 | { "Mono DMIC L Mux", NULL, "DMIC MONO L ASRC", rt5677_dmic_use_asrc }, |
3062 | { "Mono DMIC R Mux", NULL, "DMIC MONO R ASRC", can_use_asrc }, | 3164 | { "Mono DMIC R Mux", NULL, "DMIC MONO R ASRC", rt5677_dmic_use_asrc }, |
3063 | { "I2S1", NULL, "I2S1 ASRC", can_use_asrc}, | 3165 | { "I2S1", NULL, "I2S1 ASRC", can_use_asrc}, |
3064 | { "I2S2", NULL, "I2S2 ASRC", can_use_asrc}, | 3166 | { "I2S2", NULL, "I2S2 ASRC", can_use_asrc}, |
3065 | { "I2S3", NULL, "I2S3 ASRC", can_use_asrc}, | 3167 | { "I2S3", NULL, "I2S3 ASRC", can_use_asrc}, |
@@ -4350,7 +4452,7 @@ static int rt5677_set_bias_level(struct snd_soc_codec *codec, | |||
4350 | break; | 4452 | break; |
4351 | 4453 | ||
4352 | case SND_SOC_BIAS_PREPARE: | 4454 | case SND_SOC_BIAS_PREPARE: |
4353 | if (codec->dapm.bias_level == SND_SOC_BIAS_STANDBY) { | 4455 | if (snd_soc_codec_get_bias_level(codec) == SND_SOC_BIAS_STANDBY) { |
4354 | rt5677_set_dsp_vad(codec, false); | 4456 | rt5677_set_dsp_vad(codec, false); |
4355 | 4457 | ||
4356 | regmap_update_bits(rt5677->regmap, RT5677_PWR_ANLG1, | 4458 | regmap_update_bits(rt5677->regmap, RT5677_PWR_ANLG1, |
@@ -4392,7 +4494,6 @@ static int rt5677_set_bias_level(struct snd_soc_codec *codec, | |||
4392 | default: | 4494 | default: |
4393 | break; | 4495 | break; |
4394 | } | 4496 | } |
4395 | codec->dapm.bias_level = level; | ||
4396 | 4497 | ||
4397 | return 0; | 4498 | return 0; |
4398 | } | 4499 | } |
@@ -4603,22 +4704,23 @@ static void rt5677_free_gpio(struct i2c_client *i2c) | |||
4603 | 4704 | ||
4604 | static int rt5677_probe(struct snd_soc_codec *codec) | 4705 | static int rt5677_probe(struct snd_soc_codec *codec) |
4605 | { | 4706 | { |
4707 | struct snd_soc_dapm_context *dapm = snd_soc_codec_get_dapm(codec); | ||
4606 | struct rt5677_priv *rt5677 = snd_soc_codec_get_drvdata(codec); | 4708 | struct rt5677_priv *rt5677 = snd_soc_codec_get_drvdata(codec); |
4607 | int i; | 4709 | int i; |
4608 | 4710 | ||
4609 | rt5677->codec = codec; | 4711 | rt5677->codec = codec; |
4610 | 4712 | ||
4611 | if (rt5677->pdata.dmic2_clk_pin == RT5677_DMIC_CLK2) { | 4713 | if (rt5677->pdata.dmic2_clk_pin == RT5677_DMIC_CLK2) { |
4612 | snd_soc_dapm_add_routes(&codec->dapm, | 4714 | snd_soc_dapm_add_routes(dapm, |
4613 | rt5677_dmic2_clk_2, | 4715 | rt5677_dmic2_clk_2, |
4614 | ARRAY_SIZE(rt5677_dmic2_clk_2)); | 4716 | ARRAY_SIZE(rt5677_dmic2_clk_2)); |
4615 | } else { /*use dmic1 clock by default*/ | 4717 | } else { /*use dmic1 clock by default*/ |
4616 | snd_soc_dapm_add_routes(&codec->dapm, | 4718 | snd_soc_dapm_add_routes(dapm, |
4617 | rt5677_dmic2_clk_1, | 4719 | rt5677_dmic2_clk_1, |
4618 | ARRAY_SIZE(rt5677_dmic2_clk_1)); | 4720 | ARRAY_SIZE(rt5677_dmic2_clk_1)); |
4619 | } | 4721 | } |
4620 | 4722 | ||
4621 | rt5677_set_bias_level(codec, SND_SOC_BIAS_OFF); | 4723 | snd_soc_codec_force_bias_level(codec, SND_SOC_BIAS_OFF); |
4622 | 4724 | ||
4623 | regmap_write(rt5677->regmap, RT5677_DIG_MISC, 0x0020); | 4725 | regmap_write(rt5677->regmap, RT5677_DIG_MISC, 0x0020); |
4624 | regmap_write(rt5677->regmap, RT5677_PWR_DSP2, 0x0c00); | 4726 | regmap_write(rt5677->regmap, RT5677_PWR_DSP2, 0x0c00); |
@@ -4664,6 +4766,8 @@ static int rt5677_remove(struct snd_soc_codec *codec) | |||
4664 | regmap_write(rt5677->regmap, RT5677_RESET, 0x10ec); | 4766 | regmap_write(rt5677->regmap, RT5677_RESET, 0x10ec); |
4665 | if (gpio_is_valid(rt5677->pow_ldo2)) | 4767 | if (gpio_is_valid(rt5677->pow_ldo2)) |
4666 | gpio_set_value_cansleep(rt5677->pow_ldo2, 0); | 4768 | gpio_set_value_cansleep(rt5677->pow_ldo2, 0); |
4769 | if (gpio_is_valid(rt5677->reset_pin)) | ||
4770 | gpio_set_value_cansleep(rt5677->reset_pin, 0); | ||
4667 | 4771 | ||
4668 | return 0; | 4772 | return 0; |
4669 | } | 4773 | } |
@@ -4679,6 +4783,8 @@ static int rt5677_suspend(struct snd_soc_codec *codec) | |||
4679 | 4783 | ||
4680 | if (gpio_is_valid(rt5677->pow_ldo2)) | 4784 | if (gpio_is_valid(rt5677->pow_ldo2)) |
4681 | gpio_set_value_cansleep(rt5677->pow_ldo2, 0); | 4785 | gpio_set_value_cansleep(rt5677->pow_ldo2, 0); |
4786 | if (gpio_is_valid(rt5677->reset_pin)) | ||
4787 | gpio_set_value_cansleep(rt5677->reset_pin, 0); | ||
4682 | } | 4788 | } |
4683 | 4789 | ||
4684 | return 0; | 4790 | return 0; |
@@ -4689,10 +4795,13 @@ static int rt5677_resume(struct snd_soc_codec *codec) | |||
4689 | struct rt5677_priv *rt5677 = snd_soc_codec_get_drvdata(codec); | 4795 | struct rt5677_priv *rt5677 = snd_soc_codec_get_drvdata(codec); |
4690 | 4796 | ||
4691 | if (!rt5677->dsp_vad_en) { | 4797 | if (!rt5677->dsp_vad_en) { |
4692 | if (gpio_is_valid(rt5677->pow_ldo2)) { | 4798 | if (gpio_is_valid(rt5677->pow_ldo2)) |
4693 | gpio_set_value_cansleep(rt5677->pow_ldo2, 1); | 4799 | gpio_set_value_cansleep(rt5677->pow_ldo2, 1); |
4800 | if (gpio_is_valid(rt5677->reset_pin)) | ||
4801 | gpio_set_value_cansleep(rt5677->reset_pin, 1); | ||
4802 | if (gpio_is_valid(rt5677->pow_ldo2) || | ||
4803 | gpio_is_valid(rt5677->reset_pin)) | ||
4694 | msleep(10); | 4804 | msleep(10); |
4695 | } | ||
4696 | 4805 | ||
4697 | regcache_cache_only(rt5677->regmap, false); | 4806 | regcache_cache_only(rt5677->regmap, false); |
4698 | regcache_sync(rt5677->regmap); | 4807 | regcache_sync(rt5677->regmap); |
@@ -4930,6 +5039,8 @@ static int rt5677_parse_dt(struct rt5677_priv *rt5677, struct device_node *np) | |||
4930 | 5039 | ||
4931 | rt5677->pow_ldo2 = of_get_named_gpio(np, | 5040 | rt5677->pow_ldo2 = of_get_named_gpio(np, |
4932 | "realtek,pow-ldo2-gpio", 0); | 5041 | "realtek,pow-ldo2-gpio", 0); |
5042 | rt5677->reset_pin = of_get_named_gpio(np, | ||
5043 | "realtek,reset-gpio", 0); | ||
4933 | 5044 | ||
4934 | /* | 5045 | /* |
4935 | * POW_LDO2 is optional (it may be statically tied on the board). | 5046 | * POW_LDO2 is optional (it may be statically tied on the board). |
@@ -4940,6 +5051,9 @@ static int rt5677_parse_dt(struct rt5677_priv *rt5677, struct device_node *np) | |||
4940 | if (!gpio_is_valid(rt5677->pow_ldo2) && | 5051 | if (!gpio_is_valid(rt5677->pow_ldo2) && |
4941 | (rt5677->pow_ldo2 != -ENOENT)) | 5052 | (rt5677->pow_ldo2 != -ENOENT)) |
4942 | return rt5677->pow_ldo2; | 5053 | return rt5677->pow_ldo2; |
5054 | if (!gpio_is_valid(rt5677->reset_pin) && | ||
5055 | (rt5677->reset_pin != -ENOENT)) | ||
5056 | return rt5677->reset_pin; | ||
4943 | 5057 | ||
4944 | of_property_read_u8_array(np, "realtek,gpio-config", | 5058 | of_property_read_u8_array(np, "realtek,gpio-config", |
4945 | rt5677->pdata.gpio_config, RT5677_GPIO_NUM); | 5059 | rt5677->pdata.gpio_config, RT5677_GPIO_NUM); |
@@ -5041,6 +5155,7 @@ static int rt5677_i2c_probe(struct i2c_client *i2c, | |||
5041 | } | 5155 | } |
5042 | } else { | 5156 | } else { |
5043 | rt5677->pow_ldo2 = -EINVAL; | 5157 | rt5677->pow_ldo2 = -EINVAL; |
5158 | rt5677->reset_pin = -EINVAL; | ||
5044 | } | 5159 | } |
5045 | 5160 | ||
5046 | if (gpio_is_valid(rt5677->pow_ldo2)) { | 5161 | if (gpio_is_valid(rt5677->pow_ldo2)) { |
@@ -5052,6 +5167,21 @@ static int rt5677_i2c_probe(struct i2c_client *i2c, | |||
5052 | rt5677->pow_ldo2, ret); | 5167 | rt5677->pow_ldo2, ret); |
5053 | return ret; | 5168 | return ret; |
5054 | } | 5169 | } |
5170 | } | ||
5171 | |||
5172 | if (gpio_is_valid(rt5677->reset_pin)) { | ||
5173 | ret = devm_gpio_request_one(&i2c->dev, rt5677->reset_pin, | ||
5174 | GPIOF_OUT_INIT_HIGH, | ||
5175 | "RT5677 RESET"); | ||
5176 | if (ret < 0) { | ||
5177 | dev_err(&i2c->dev, "Failed to request RESET %d: %d\n", | ||
5178 | rt5677->reset_pin, ret); | ||
5179 | return ret; | ||
5180 | } | ||
5181 | } | ||
5182 | |||
5183 | if (gpio_is_valid(rt5677->pow_ldo2) || | ||
5184 | gpio_is_valid(rt5677->reset_pin)) { | ||
5055 | /* Wait a while until I2C bus becomes available. The datasheet | 5185 | /* Wait a while until I2C bus becomes available. The datasheet |
5056 | * does not specify the exact we should wait but startup | 5186 | * does not specify the exact we should wait but startup |
5057 | * sequence mentiones at least a few milliseconds. | 5187 | * sequence mentiones at least a few milliseconds. |
diff --git a/sound/soc/codecs/rt5677.h b/sound/soc/codecs/rt5677.h index 9dceb41d18ea..7eca38a23255 100644 --- a/sound/soc/codecs/rt5677.h +++ b/sound/soc/codecs/rt5677.h | |||
@@ -1446,6 +1446,16 @@ | |||
1446 | #define RT5677_DSP_OB_4_7_CLK_SEL_MASK (0xf << 8) | 1446 | #define RT5677_DSP_OB_4_7_CLK_SEL_MASK (0xf << 8) |
1447 | #define RT5677_DSP_OB_4_7_CLK_SEL_SFT 8 | 1447 | #define RT5677_DSP_OB_4_7_CLK_SEL_SFT 8 |
1448 | 1448 | ||
1449 | /* ASRC Control 8 (0x8a) */ | ||
1450 | #define RT5677_I2S1_CLK_SEL_MASK (0xf << 12) | ||
1451 | #define RT5677_I2S1_CLK_SEL_SFT 12 | ||
1452 | #define RT5677_I2S2_CLK_SEL_MASK (0xf << 8) | ||
1453 | #define RT5677_I2S2_CLK_SEL_SFT 8 | ||
1454 | #define RT5677_I2S3_CLK_SEL_MASK (0xf << 4) | ||
1455 | #define RT5677_I2S3_CLK_SEL_SFT 4 | ||
1456 | #define RT5677_I2S4_CLK_SEL_MASK (0xf) | ||
1457 | #define RT5677_I2S4_CLK_SEL_SFT 0 | ||
1458 | |||
1449 | /* VAD Function Control 4 (0x9f) */ | 1459 | /* VAD Function Control 4 (0x9f) */ |
1450 | #define RT5677_VAD_SRC_MASK (0x7 << 8) | 1460 | #define RT5677_VAD_SRC_MASK (0x7 << 8) |
1451 | #define RT5677_VAD_SRC_SFT 8 | 1461 | #define RT5677_VAD_SRC_SFT 8 |
@@ -1744,6 +1754,10 @@ enum { | |||
1744 | RT5677_AD_MONO_R_FILTER = (0x1 << 12), | 1754 | RT5677_AD_MONO_R_FILTER = (0x1 << 12), |
1745 | RT5677_DSP_OB_0_3_FILTER = (0x1 << 13), | 1755 | RT5677_DSP_OB_0_3_FILTER = (0x1 << 13), |
1746 | RT5677_DSP_OB_4_7_FILTER = (0x1 << 14), | 1756 | RT5677_DSP_OB_4_7_FILTER = (0x1 << 14), |
1757 | RT5677_I2S1_SOURCE = (0x1 << 15), | ||
1758 | RT5677_I2S2_SOURCE = (0x1 << 16), | ||
1759 | RT5677_I2S3_SOURCE = (0x1 << 17), | ||
1760 | RT5677_I2S4_SOURCE = (0x1 << 18), | ||
1747 | }; | 1761 | }; |
1748 | 1762 | ||
1749 | struct rt5677_priv { | 1763 | struct rt5677_priv { |
@@ -1762,6 +1776,7 @@ struct rt5677_priv { | |||
1762 | int pll_in; | 1776 | int pll_in; |
1763 | int pll_out; | 1777 | int pll_out; |
1764 | int pow_ldo2; /* POW_LDO2 pin */ | 1778 | int pow_ldo2; /* POW_LDO2 pin */ |
1779 | int reset_pin; /* RESET pin */ | ||
1765 | enum rt5677_type type; | 1780 | enum rt5677_type type; |
1766 | #ifdef CONFIG_GPIOLIB | 1781 | #ifdef CONFIG_GPIOLIB |
1767 | struct gpio_chip gpio_chip; | 1782 | struct gpio_chip gpio_chip; |
diff --git a/sound/soc/codecs/sgtl5000.c b/sound/soc/codecs/sgtl5000.c index 3593a1496056..e673f6ceb521 100644 --- a/sound/soc/codecs/sgtl5000.c +++ b/sound/soc/codecs/sgtl5000.c | |||
@@ -948,7 +948,7 @@ static int sgtl5000_set_bias_level(struct snd_soc_codec *codec, | |||
948 | case SND_SOC_BIAS_PREPARE: | 948 | case SND_SOC_BIAS_PREPARE: |
949 | break; | 949 | break; |
950 | case SND_SOC_BIAS_STANDBY: | 950 | case SND_SOC_BIAS_STANDBY: |
951 | if (codec->dapm.bias_level == SND_SOC_BIAS_OFF) { | 951 | if (snd_soc_codec_get_bias_level(codec) == SND_SOC_BIAS_OFF) { |
952 | ret = regulator_bulk_enable( | 952 | ret = regulator_bulk_enable( |
953 | ARRAY_SIZE(sgtl5000->supplies), | 953 | ARRAY_SIZE(sgtl5000->supplies), |
954 | sgtl5000->supplies); | 954 | sgtl5000->supplies); |
@@ -979,7 +979,6 @@ static int sgtl5000_set_bias_level(struct snd_soc_codec *codec, | |||
979 | break; | 979 | break; |
980 | } | 980 | } |
981 | 981 | ||
982 | codec->dapm.bias_level = level; | ||
983 | return 0; | 982 | return 0; |
984 | } | 983 | } |
985 | 984 | ||
@@ -1092,6 +1091,19 @@ static bool sgtl5000_readable(struct device *dev, unsigned int reg) | |||
1092 | } | 1091 | } |
1093 | 1092 | ||
1094 | /* | 1093 | /* |
1094 | * This precalculated table contains all (vag_val * 100 / lo_calcntrl) results | ||
1095 | * to select an appropriate lo_vol_* in SGTL5000_CHIP_LINE_OUT_VOL | ||
1096 | * The calculatation was done for all possible register values which | ||
1097 | * is the array index and the following formula: 10^((idx−15)/40) * 100 | ||
1098 | */ | ||
1099 | static const u8 vol_quot_table[] = { | ||
1100 | 42, 45, 47, 50, 53, 56, 60, 63, | ||
1101 | 67, 71, 75, 79, 84, 89, 94, 100, | ||
1102 | 106, 112, 119, 126, 133, 141, 150, 158, | ||
1103 | 168, 178, 188, 200, 211, 224, 237, 251 | ||
1104 | }; | ||
1105 | |||
1106 | /* | ||
1095 | * sgtl5000 has 3 internal power supplies: | 1107 | * sgtl5000 has 3 internal power supplies: |
1096 | * 1. VAG, normally set to vdda/2 | 1108 | * 1. VAG, normally set to vdda/2 |
1097 | * 2. charge pump, set to different value | 1109 | * 2. charge pump, set to different value |
@@ -1111,6 +1123,10 @@ static int sgtl5000_set_power_regs(struct snd_soc_codec *codec) | |||
1111 | u16 ana_pwr; | 1123 | u16 ana_pwr; |
1112 | u16 lreg_ctrl; | 1124 | u16 lreg_ctrl; |
1113 | int vag; | 1125 | int vag; |
1126 | int lo_vag; | ||
1127 | int vol_quot; | ||
1128 | int lo_vol; | ||
1129 | size_t i; | ||
1114 | struct sgtl5000_priv *sgtl5000 = snd_soc_codec_get_drvdata(codec); | 1130 | struct sgtl5000_priv *sgtl5000 = snd_soc_codec_get_drvdata(codec); |
1115 | 1131 | ||
1116 | vdda = regulator_get_voltage(sgtl5000->supplies[VDDA].consumer); | 1132 | vdda = regulator_get_voltage(sgtl5000->supplies[VDDA].consumer); |
@@ -1198,23 +1214,45 @@ static int sgtl5000_set_power_regs(struct snd_soc_codec *codec) | |||
1198 | SGTL5000_ANA_GND_MASK, vag << SGTL5000_ANA_GND_SHIFT); | 1214 | SGTL5000_ANA_GND_MASK, vag << SGTL5000_ANA_GND_SHIFT); |
1199 | 1215 | ||
1200 | /* set line out VAG to vddio / 2, in range (0.8v, 1.675v) */ | 1216 | /* set line out VAG to vddio / 2, in range (0.8v, 1.675v) */ |
1201 | vag = vddio / 2; | 1217 | lo_vag = vddio / 2; |
1202 | if (vag <= SGTL5000_LINE_OUT_GND_BASE) | 1218 | if (lo_vag <= SGTL5000_LINE_OUT_GND_BASE) |
1203 | vag = 0; | 1219 | lo_vag = 0; |
1204 | else if (vag >= SGTL5000_LINE_OUT_GND_BASE + | 1220 | else if (lo_vag >= SGTL5000_LINE_OUT_GND_BASE + |
1205 | SGTL5000_LINE_OUT_GND_STP * SGTL5000_LINE_OUT_GND_MAX) | 1221 | SGTL5000_LINE_OUT_GND_STP * SGTL5000_LINE_OUT_GND_MAX) |
1206 | vag = SGTL5000_LINE_OUT_GND_MAX; | 1222 | lo_vag = SGTL5000_LINE_OUT_GND_MAX; |
1207 | else | 1223 | else |
1208 | vag = (vag - SGTL5000_LINE_OUT_GND_BASE) / | 1224 | lo_vag = (lo_vag - SGTL5000_LINE_OUT_GND_BASE) / |
1209 | SGTL5000_LINE_OUT_GND_STP; | 1225 | SGTL5000_LINE_OUT_GND_STP; |
1210 | 1226 | ||
1211 | snd_soc_update_bits(codec, SGTL5000_CHIP_LINE_OUT_CTRL, | 1227 | snd_soc_update_bits(codec, SGTL5000_CHIP_LINE_OUT_CTRL, |
1212 | SGTL5000_LINE_OUT_CURRENT_MASK | | 1228 | SGTL5000_LINE_OUT_CURRENT_MASK | |
1213 | SGTL5000_LINE_OUT_GND_MASK, | 1229 | SGTL5000_LINE_OUT_GND_MASK, |
1214 | vag << SGTL5000_LINE_OUT_GND_SHIFT | | 1230 | lo_vag << SGTL5000_LINE_OUT_GND_SHIFT | |
1215 | SGTL5000_LINE_OUT_CURRENT_360u << | 1231 | SGTL5000_LINE_OUT_CURRENT_360u << |
1216 | SGTL5000_LINE_OUT_CURRENT_SHIFT); | 1232 | SGTL5000_LINE_OUT_CURRENT_SHIFT); |
1217 | 1233 | ||
1234 | /* | ||
1235 | * Set lineout output level in range (0..31) | ||
1236 | * the same value is used for right and left channel | ||
1237 | * | ||
1238 | * Searching for a suitable index solving this formula: | ||
1239 | * idx = 40 * log10(vag_val / lo_cagcntrl) + 15 | ||
1240 | */ | ||
1241 | vol_quot = (vag * 100) / lo_vag; | ||
1242 | lo_vol = 0; | ||
1243 | for (i = 0; i < ARRAY_SIZE(vol_quot_table); i++) { | ||
1244 | if (vol_quot >= vol_quot_table[i]) | ||
1245 | lo_vol = i; | ||
1246 | else | ||
1247 | break; | ||
1248 | } | ||
1249 | |||
1250 | snd_soc_update_bits(codec, SGTL5000_CHIP_LINE_OUT_VOL, | ||
1251 | SGTL5000_LINE_OUT_VOL_RIGHT_MASK | | ||
1252 | SGTL5000_LINE_OUT_VOL_LEFT_MASK, | ||
1253 | lo_vol << SGTL5000_LINE_OUT_VOL_RIGHT_SHIFT | | ||
1254 | lo_vol << SGTL5000_LINE_OUT_VOL_LEFT_SHIFT); | ||
1255 | |||
1218 | return 0; | 1256 | return 0; |
1219 | } | 1257 | } |
1220 | 1258 | ||
diff --git a/sound/soc/codecs/sirf-audio-codec.c b/sound/soc/codecs/sirf-audio-codec.c index 0a8e43c98a07..29cb44256044 100644 --- a/sound/soc/codecs/sirf-audio-codec.c +++ b/sound/soc/codecs/sirf-audio-codec.c | |||
@@ -395,7 +395,7 @@ struct snd_soc_dai_driver sirf_audio_codec_dai = { | |||
395 | 395 | ||
396 | static int sirf_audio_codec_probe(struct snd_soc_codec *codec) | 396 | static int sirf_audio_codec_probe(struct snd_soc_codec *codec) |
397 | { | 397 | { |
398 | struct snd_soc_dapm_context *dapm = &codec->dapm; | 398 | struct snd_soc_dapm_context *dapm = snd_soc_codec_get_dapm(codec); |
399 | 399 | ||
400 | pm_runtime_enable(codec->dev); | 400 | pm_runtime_enable(codec->dev); |
401 | 401 | ||
diff --git a/sound/soc/codecs/sn95031.c b/sound/soc/codecs/sn95031.c index 7947c0ebb1ed..3a7de0159f24 100644 --- a/sound/soc/codecs/sn95031.c +++ b/sound/soc/codecs/sn95031.c | |||
@@ -194,7 +194,7 @@ static int sn95031_set_vaud_bias(struct snd_soc_codec *codec, | |||
194 | break; | 194 | break; |
195 | 195 | ||
196 | case SND_SOC_BIAS_PREPARE: | 196 | case SND_SOC_BIAS_PREPARE: |
197 | if (codec->dapm.bias_level == SND_SOC_BIAS_STANDBY) { | 197 | if (snd_soc_codec_get_bias_level(codec) == SND_SOC_BIAS_STANDBY) { |
198 | pr_debug("vaud_bias powering up pll\n"); | 198 | pr_debug("vaud_bias powering up pll\n"); |
199 | /* power up the pll */ | 199 | /* power up the pll */ |
200 | snd_soc_write(codec, SN95031_AUDPLLCTRL, BIT(5)); | 200 | snd_soc_write(codec, SN95031_AUDPLLCTRL, BIT(5)); |
@@ -205,17 +205,22 @@ static int sn95031_set_vaud_bias(struct snd_soc_codec *codec, | |||
205 | break; | 205 | break; |
206 | 206 | ||
207 | case SND_SOC_BIAS_STANDBY: | 207 | case SND_SOC_BIAS_STANDBY: |
208 | if (codec->dapm.bias_level == SND_SOC_BIAS_OFF) { | 208 | switch (snd_soc_codec_get_bias_level(codec)) { |
209 | case SND_SOC_BIAS_OFF: | ||
209 | pr_debug("vaud_bias power up rail\n"); | 210 | pr_debug("vaud_bias power up rail\n"); |
210 | /* power up the rail */ | 211 | /* power up the rail */ |
211 | snd_soc_write(codec, SN95031_VAUD, | 212 | snd_soc_write(codec, SN95031_VAUD, |
212 | BIT(2)|BIT(1)|BIT(0)); | 213 | BIT(2)|BIT(1)|BIT(0)); |
213 | msleep(1); | 214 | msleep(1); |
214 | } else if (codec->dapm.bias_level == SND_SOC_BIAS_PREPARE) { | 215 | break; |
216 | case SND_SOC_BIAS_PREPARE: | ||
215 | /* turn off pcm */ | 217 | /* turn off pcm */ |
216 | pr_debug("vaud_bias power dn pcm\n"); | 218 | pr_debug("vaud_bias power dn pcm\n"); |
217 | snd_soc_update_bits(codec, SN95031_PCM2C2, BIT(0), 0); | 219 | snd_soc_update_bits(codec, SN95031_PCM2C2, BIT(0), 0); |
218 | snd_soc_write(codec, SN95031_AUDPLLCTRL, 0); | 220 | snd_soc_write(codec, SN95031_AUDPLLCTRL, 0); |
221 | break; | ||
222 | default: | ||
223 | break; | ||
219 | } | 224 | } |
220 | break; | 225 | break; |
221 | 226 | ||
@@ -226,7 +231,6 @@ static int sn95031_set_vaud_bias(struct snd_soc_codec *codec, | |||
226 | break; | 231 | break; |
227 | } | 232 | } |
228 | 233 | ||
229 | codec->dapm.bias_level = level; | ||
230 | return 0; | 234 | return 0; |
231 | } | 235 | } |
232 | 236 | ||
diff --git a/sound/soc/codecs/ssm2518.c b/sound/soc/codecs/ssm2518.c index 67ea55adb307..f30de7639bb9 100644 --- a/sound/soc/codecs/ssm2518.c +++ b/sound/soc/codecs/ssm2518.c | |||
@@ -510,7 +510,7 @@ static int ssm2518_set_bias_level(struct snd_soc_codec *codec, | |||
510 | case SND_SOC_BIAS_PREPARE: | 510 | case SND_SOC_BIAS_PREPARE: |
511 | break; | 511 | break; |
512 | case SND_SOC_BIAS_STANDBY: | 512 | case SND_SOC_BIAS_STANDBY: |
513 | if (codec->dapm.bias_level == SND_SOC_BIAS_OFF) | 513 | if (snd_soc_codec_get_bias_level(codec) == SND_SOC_BIAS_OFF) |
514 | ret = ssm2518_set_power(ssm2518, true); | 514 | ret = ssm2518_set_power(ssm2518, true); |
515 | break; | 515 | break; |
516 | case SND_SOC_BIAS_OFF: | 516 | case SND_SOC_BIAS_OFF: |
@@ -518,12 +518,7 @@ static int ssm2518_set_bias_level(struct snd_soc_codec *codec, | |||
518 | break; | 518 | break; |
519 | } | 519 | } |
520 | 520 | ||
521 | if (ret) | 521 | return ret; |
522 | return ret; | ||
523 | |||
524 | codec->dapm.bias_level = level; | ||
525 | |||
526 | return 0; | ||
527 | } | 522 | } |
528 | 523 | ||
529 | static int ssm2518_set_tdm_slot(struct snd_soc_dai *dai, unsigned int tx_mask, | 524 | static int ssm2518_set_tdm_slot(struct snd_soc_dai *dai, unsigned int tx_mask, |
diff --git a/sound/soc/codecs/ssm2602.c b/sound/soc/codecs/ssm2602.c index 314eaece1b7d..69a773aeb13d 100644 --- a/sound/soc/codecs/ssm2602.c +++ b/sound/soc/codecs/ssm2602.c | |||
@@ -473,7 +473,6 @@ static int ssm2602_set_bias_level(struct snd_soc_codec *codec, | |||
473 | break; | 473 | break; |
474 | 474 | ||
475 | } | 475 | } |
476 | codec->dapm.bias_level = level; | ||
477 | return 0; | 476 | return 0; |
478 | } | 477 | } |
479 | 478 | ||
@@ -524,8 +523,8 @@ static int ssm2602_resume(struct snd_soc_codec *codec) | |||
524 | 523 | ||
525 | static int ssm2602_codec_probe(struct snd_soc_codec *codec) | 524 | static int ssm2602_codec_probe(struct snd_soc_codec *codec) |
526 | { | 525 | { |
526 | struct snd_soc_dapm_context *dapm = snd_soc_codec_get_dapm(codec); | ||
527 | struct ssm2602_priv *ssm2602 = snd_soc_codec_get_drvdata(codec); | 527 | struct ssm2602_priv *ssm2602 = snd_soc_codec_get_drvdata(codec); |
528 | struct snd_soc_dapm_context *dapm = &codec->dapm; | ||
529 | int ret; | 528 | int ret; |
530 | 529 | ||
531 | regmap_update_bits(ssm2602->regmap, SSM2602_LOUT1V, | 530 | regmap_update_bits(ssm2602->regmap, SSM2602_LOUT1V, |
@@ -549,7 +548,7 @@ static int ssm2602_codec_probe(struct snd_soc_codec *codec) | |||
549 | 548 | ||
550 | static int ssm2604_codec_probe(struct snd_soc_codec *codec) | 549 | static int ssm2604_codec_probe(struct snd_soc_codec *codec) |
551 | { | 550 | { |
552 | struct snd_soc_dapm_context *dapm = &codec->dapm; | 551 | struct snd_soc_dapm_context *dapm = snd_soc_codec_get_dapm(codec); |
553 | int ret; | 552 | int ret; |
554 | 553 | ||
555 | ret = snd_soc_dapm_new_controls(dapm, ssm2604_dapm_widgets, | 554 | ret = snd_soc_dapm_new_controls(dapm, ssm2604_dapm_widgets, |
diff --git a/sound/soc/codecs/ssm4567.c b/sound/soc/codecs/ssm4567.c index a984485108cd..938d2cb6d78b 100644 --- a/sound/soc/codecs/ssm4567.c +++ b/sound/soc/codecs/ssm4567.c | |||
@@ -353,7 +353,7 @@ static int ssm4567_set_bias_level(struct snd_soc_codec *codec, | |||
353 | case SND_SOC_BIAS_PREPARE: | 353 | case SND_SOC_BIAS_PREPARE: |
354 | break; | 354 | break; |
355 | case SND_SOC_BIAS_STANDBY: | 355 | case SND_SOC_BIAS_STANDBY: |
356 | if (codec->dapm.bias_level == SND_SOC_BIAS_OFF) | 356 | if (snd_soc_codec_get_bias_level(codec) == SND_SOC_BIAS_OFF) |
357 | ret = ssm4567_set_power(ssm4567, true); | 357 | ret = ssm4567_set_power(ssm4567, true); |
358 | break; | 358 | break; |
359 | case SND_SOC_BIAS_OFF: | 359 | case SND_SOC_BIAS_OFF: |
@@ -361,12 +361,7 @@ static int ssm4567_set_bias_level(struct snd_soc_codec *codec, | |||
361 | break; | 361 | break; |
362 | } | 362 | } |
363 | 363 | ||
364 | if (ret) | 364 | return ret; |
365 | return ret; | ||
366 | |||
367 | codec->dapm.bias_level = level; | ||
368 | |||
369 | return 0; | ||
370 | } | 365 | } |
371 | 366 | ||
372 | static const struct snd_soc_dai_ops ssm4567_dai_ops = { | 367 | static const struct snd_soc_dai_ops ssm4567_dai_ops = { |
diff --git a/sound/soc/codecs/sta32x.c b/sound/soc/codecs/sta32x.c index 007a0e3bc273..60eff36260cb 100644 --- a/sound/soc/codecs/sta32x.c +++ b/sound/soc/codecs/sta32x.c | |||
@@ -819,7 +819,7 @@ static int sta32x_set_bias_level(struct snd_soc_codec *codec, | |||
819 | break; | 819 | break; |
820 | 820 | ||
821 | case SND_SOC_BIAS_STANDBY: | 821 | case SND_SOC_BIAS_STANDBY: |
822 | if (codec->dapm.bias_level == SND_SOC_BIAS_OFF) { | 822 | if (snd_soc_codec_get_bias_level(codec) == SND_SOC_BIAS_OFF) { |
823 | ret = regulator_bulk_enable(ARRAY_SIZE(sta32x->supplies), | 823 | ret = regulator_bulk_enable(ARRAY_SIZE(sta32x->supplies), |
824 | sta32x->supplies); | 824 | sta32x->supplies); |
825 | if (ret != 0) { | 825 | if (ret != 0) { |
@@ -854,7 +854,6 @@ static int sta32x_set_bias_level(struct snd_soc_codec *codec, | |||
854 | sta32x->supplies); | 854 | sta32x->supplies); |
855 | break; | 855 | break; |
856 | } | 856 | } |
857 | codec->dapm.bias_level = level; | ||
858 | return 0; | 857 | return 0; |
859 | } | 858 | } |
860 | 859 | ||
@@ -970,7 +969,7 @@ static int sta32x_probe(struct snd_soc_codec *codec) | |||
970 | if (sta32x->pdata->needs_esd_watchdog) | 969 | if (sta32x->pdata->needs_esd_watchdog) |
971 | INIT_DELAYED_WORK(&sta32x->watchdog_work, sta32x_watchdog); | 970 | INIT_DELAYED_WORK(&sta32x->watchdog_work, sta32x_watchdog); |
972 | 971 | ||
973 | sta32x_set_bias_level(codec, SND_SOC_BIAS_STANDBY); | 972 | snd_soc_codec_force_bias_level(codec, SND_SOC_BIAS_STANDBY); |
974 | /* Bias level configuration will have done an extra enable */ | 973 | /* Bias level configuration will have done an extra enable */ |
975 | regulator_bulk_disable(ARRAY_SIZE(sta32x->supplies), sta32x->supplies); | 974 | regulator_bulk_disable(ARRAY_SIZE(sta32x->supplies), sta32x->supplies); |
976 | 975 | ||
@@ -1096,16 +1095,10 @@ static int sta32x_i2c_probe(struct i2c_client *i2c, | |||
1096 | #endif | 1095 | #endif |
1097 | 1096 | ||
1098 | /* GPIOs */ | 1097 | /* GPIOs */ |
1099 | sta32x->gpiod_nreset = devm_gpiod_get(dev, "reset"); | 1098 | sta32x->gpiod_nreset = devm_gpiod_get_optional(dev, "reset", |
1100 | if (IS_ERR(sta32x->gpiod_nreset)) { | 1099 | GPIOD_OUT_LOW); |
1101 | ret = PTR_ERR(sta32x->gpiod_nreset); | 1100 | if (IS_ERR(sta32x->gpiod_nreset)) |
1102 | if (ret != -ENOENT && ret != -ENOSYS) | 1101 | return PTR_ERR(sta32x->gpiod_nreset); |
1103 | return ret; | ||
1104 | |||
1105 | sta32x->gpiod_nreset = NULL; | ||
1106 | } else { | ||
1107 | gpiod_direction_output(sta32x->gpiod_nreset, 0); | ||
1108 | } | ||
1109 | 1102 | ||
1110 | /* regulators */ | 1103 | /* regulators */ |
1111 | for (i = 0; i < ARRAY_SIZE(sta32x->supplies); i++) | 1104 | for (i = 0; i < ARRAY_SIZE(sta32x->supplies); i++) |
diff --git a/sound/soc/codecs/sta350.c b/sound/soc/codecs/sta350.c index 669e3228241e..bd819a3f205a 100644 --- a/sound/soc/codecs/sta350.c +++ b/sound/soc/codecs/sta350.c | |||
@@ -853,7 +853,7 @@ static int sta350_set_bias_level(struct snd_soc_codec *codec, | |||
853 | break; | 853 | break; |
854 | 854 | ||
855 | case SND_SOC_BIAS_STANDBY: | 855 | case SND_SOC_BIAS_STANDBY: |
856 | if (codec->dapm.bias_level == SND_SOC_BIAS_OFF) { | 856 | if (snd_soc_codec_get_bias_level(codec) == SND_SOC_BIAS_OFF) { |
857 | ret = regulator_bulk_enable( | 857 | ret = regulator_bulk_enable( |
858 | ARRAY_SIZE(sta350->supplies), | 858 | ARRAY_SIZE(sta350->supplies), |
859 | sta350->supplies); | 859 | sta350->supplies); |
@@ -890,7 +890,6 @@ static int sta350_set_bias_level(struct snd_soc_codec *codec, | |||
890 | sta350->supplies); | 890 | sta350->supplies); |
891 | break; | 891 | break; |
892 | } | 892 | } |
893 | codec->dapm.bias_level = level; | ||
894 | return 0; | 893 | return 0; |
895 | } | 894 | } |
896 | 895 | ||
@@ -1037,7 +1036,7 @@ static int sta350_probe(struct snd_soc_codec *codec) | |||
1037 | sta350->coef_shadow[60] = 0x400000; | 1036 | sta350->coef_shadow[60] = 0x400000; |
1038 | sta350->coef_shadow[61] = 0x400000; | 1037 | sta350->coef_shadow[61] = 0x400000; |
1039 | 1038 | ||
1040 | sta350_set_bias_level(codec, SND_SOC_BIAS_STANDBY); | 1039 | snd_soc_codec_force_bias_level(codec, SND_SOC_BIAS_STANDBY); |
1041 | /* Bias level configuration will have done an extra enable */ | 1040 | /* Bias level configuration will have done an extra enable */ |
1042 | regulator_bulk_disable(ARRAY_SIZE(sta350->supplies), sta350->supplies); | 1041 | regulator_bulk_disable(ARRAY_SIZE(sta350->supplies), sta350->supplies); |
1043 | 1042 | ||
@@ -1218,8 +1217,8 @@ static int sta350_i2c_probe(struct i2c_client *i2c, | |||
1218 | if (IS_ERR(sta350->gpiod_nreset)) | 1217 | if (IS_ERR(sta350->gpiod_nreset)) |
1219 | return PTR_ERR(sta350->gpiod_nreset); | 1218 | return PTR_ERR(sta350->gpiod_nreset); |
1220 | 1219 | ||
1221 | sta350->gpiod_power_down = devm_gpiod_get(dev, "power-down", | 1220 | sta350->gpiod_power_down = devm_gpiod_get_optional(dev, "power-down", |
1222 | GPIOD_OUT_LOW); | 1221 | GPIOD_OUT_LOW); |
1223 | if (IS_ERR(sta350->gpiod_power_down)) | 1222 | if (IS_ERR(sta350->gpiod_power_down)) |
1224 | return PTR_ERR(sta350->gpiod_power_down); | 1223 | return PTR_ERR(sta350->gpiod_power_down); |
1225 | 1224 | ||
diff --git a/sound/soc/codecs/sta529.c b/sound/soc/codecs/sta529.c index b0f436d10125..4f70378b2cfb 100644 --- a/sound/soc/codecs/sta529.c +++ b/sound/soc/codecs/sta529.c | |||
@@ -165,7 +165,7 @@ static int sta529_set_bias_level(struct snd_soc_codec *codec, enum | |||
165 | FFX_CLK_ENB); | 165 | FFX_CLK_ENB); |
166 | break; | 166 | break; |
167 | case SND_SOC_BIAS_STANDBY: | 167 | case SND_SOC_BIAS_STANDBY: |
168 | if (codec->dapm.bias_level == SND_SOC_BIAS_OFF) | 168 | if (snd_soc_codec_get_bias_level(codec) == SND_SOC_BIAS_OFF) |
169 | regcache_sync(sta529->regmap); | 169 | regcache_sync(sta529->regmap); |
170 | snd_soc_update_bits(codec, STA529_FFXCFG0, | 170 | snd_soc_update_bits(codec, STA529_FFXCFG0, |
171 | POWER_CNTLMSAK, POWER_STDBY); | 171 | POWER_CNTLMSAK, POWER_STDBY); |
@@ -179,12 +179,6 @@ static int sta529_set_bias_level(struct snd_soc_codec *codec, enum | |||
179 | break; | 179 | break; |
180 | } | 180 | } |
181 | 181 | ||
182 | /* | ||
183 | * store the label for powers down audio subsystem for suspend.This is | ||
184 | * used by soc core layer | ||
185 | */ | ||
186 | codec->dapm.bias_level = level; | ||
187 | |||
188 | return 0; | 182 | return 0; |
189 | 183 | ||
190 | } | 184 | } |
diff --git a/sound/soc/codecs/stac9766.c b/sound/soc/codecs/stac9766.c index 6464caf72b21..ed4cca7f6779 100644 --- a/sound/soc/codecs/stac9766.c +++ b/sound/soc/codecs/stac9766.c | |||
@@ -236,7 +236,6 @@ static int stac9766_set_bias_level(struct snd_soc_codec *codec, | |||
236 | stac9766_ac97_write(codec, AC97_POWERDOWN, 0xffff); | 236 | stac9766_ac97_write(codec, AC97_POWERDOWN, 0xffff); |
237 | break; | 237 | break; |
238 | } | 238 | } |
239 | codec->dapm.bias_level = level; | ||
240 | return 0; | 239 | return 0; |
241 | } | 240 | } |
242 | 241 | ||
@@ -321,7 +320,7 @@ static struct snd_soc_dai_driver stac9766_dai[] = { | |||
321 | .channels_max = 2, | 320 | .channels_max = 2, |
322 | .rates = SNDRV_PCM_RATE_32000 | \ | 321 | .rates = SNDRV_PCM_RATE_32000 | \ |
323 | SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000, | 322 | SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000, |
324 | .formats = SNDRV_PCM_FORMAT_IEC958_SUBFRAME_BE, | 323 | .formats = SNDRV_PCM_FMTBIT_IEC958_SUBFRAME_BE, |
325 | }, | 324 | }, |
326 | /* alsa ops */ | 325 | /* alsa ops */ |
327 | .ops = &stac9766_dai_ops_digital, | 326 | .ops = &stac9766_dai_ops_digital, |
diff --git a/sound/soc/codecs/tas2552.c b/sound/soc/codecs/tas2552.c index dfb4ff5cc9ea..891e2c529df3 100644 --- a/sound/soc/codecs/tas2552.c +++ b/sound/soc/codecs/tas2552.c | |||
@@ -34,6 +34,7 @@ | |||
34 | #include <sound/soc-dapm.h> | 34 | #include <sound/soc-dapm.h> |
35 | #include <sound/tlv.h> | 35 | #include <sound/tlv.h> |
36 | #include <sound/tas2552-plat.h> | 36 | #include <sound/tas2552-plat.h> |
37 | #include <dt-bindings/sound/tas2552.h> | ||
37 | 38 | ||
38 | #include "tas2552.h" | 39 | #include "tas2552.h" |
39 | 40 | ||
@@ -45,7 +46,7 @@ static struct reg_default tas2552_reg_defs[] = { | |||
45 | {TAS2552_PDM_CFG, 0x01}, | 46 | {TAS2552_PDM_CFG, 0x01}, |
46 | {TAS2552_PGA_GAIN, 0x00}, | 47 | {TAS2552_PGA_GAIN, 0x00}, |
47 | {TAS2552_BOOST_PT_CTRL, 0x0f}, | 48 | {TAS2552_BOOST_PT_CTRL, 0x0f}, |
48 | {TAS2552_RESERVED_0D, 0x00}, | 49 | {TAS2552_RESERVED_0D, 0xbe}, |
49 | {TAS2552_LIMIT_RATE_HYS, 0x08}, | 50 | {TAS2552_LIMIT_RATE_HYS, 0x08}, |
50 | {TAS2552_CFG_2, 0xef}, | 51 | {TAS2552_CFG_2, 0xef}, |
51 | {TAS2552_SER_CTRL_1, 0x00}, | 52 | {TAS2552_SER_CTRL_1, 0x00}, |
@@ -75,20 +76,45 @@ struct tas2552_data { | |||
75 | struct regulator_bulk_data supplies[TAS2552_NUM_SUPPLIES]; | 76 | struct regulator_bulk_data supplies[TAS2552_NUM_SUPPLIES]; |
76 | struct gpio_desc *enable_gpio; | 77 | struct gpio_desc *enable_gpio; |
77 | unsigned char regs[TAS2552_VBAT_DATA]; | 78 | unsigned char regs[TAS2552_VBAT_DATA]; |
78 | unsigned int mclk; | 79 | unsigned int pll_clkin; |
79 | }; | 80 | unsigned int pdm_clk; |
80 | 81 | ||
81 | /* Input mux controls */ | 82 | unsigned int dai_fmt; |
82 | static const char *tas2552_input_texts[] = { | 83 | unsigned int tdm_delay; |
83 | "Digital", "Analog" | ||
84 | }; | 84 | }; |
85 | 85 | ||
86 | static int tas2552_post_event(struct snd_soc_dapm_widget *w, | ||
87 | struct snd_kcontrol *kcontrol, int event) | ||
88 | { | ||
89 | struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm); | ||
90 | |||
91 | switch (event) { | ||
92 | case SND_SOC_DAPM_POST_PMU: | ||
93 | snd_soc_write(codec, TAS2552_RESERVED_0D, 0xc0); | ||
94 | snd_soc_update_bits(codec, TAS2552_LIMIT_RATE_HYS, (1 << 5), | ||
95 | (1 << 5)); | ||
96 | snd_soc_update_bits(codec, TAS2552_CFG_2, 1, 0); | ||
97 | snd_soc_update_bits(codec, TAS2552_CFG_1, TAS2552_SWS, 0); | ||
98 | break; | ||
99 | case SND_SOC_DAPM_POST_PMD: | ||
100 | snd_soc_update_bits(codec, TAS2552_CFG_1, TAS2552_SWS, | ||
101 | TAS2552_SWS); | ||
102 | snd_soc_update_bits(codec, TAS2552_CFG_2, 1, 1); | ||
103 | snd_soc_update_bits(codec, TAS2552_LIMIT_RATE_HYS, (1 << 5), 0); | ||
104 | snd_soc_write(codec, TAS2552_RESERVED_0D, 0xbe); | ||
105 | break; | ||
106 | } | ||
107 | return 0; | ||
108 | } | ||
109 | |||
110 | /* Input mux controls */ | ||
111 | static const char * const tas2552_input_texts[] = { | ||
112 | "Digital", "Analog" }; | ||
86 | static SOC_ENUM_SINGLE_DECL(tas2552_input_mux_enum, TAS2552_CFG_3, 7, | 113 | static SOC_ENUM_SINGLE_DECL(tas2552_input_mux_enum, TAS2552_CFG_3, 7, |
87 | tas2552_input_texts); | 114 | tas2552_input_texts); |
88 | 115 | ||
89 | static const struct snd_kcontrol_new tas2552_input_mux_control[] = { | 116 | static const struct snd_kcontrol_new tas2552_input_mux_control = |
90 | SOC_DAPM_ENUM("Input selection", tas2552_input_mux_enum) | 117 | SOC_DAPM_ENUM("Route", tas2552_input_mux_enum); |
91 | }; | ||
92 | 118 | ||
93 | static const struct snd_soc_dapm_widget tas2552_dapm_widgets[] = | 119 | static const struct snd_soc_dapm_widget tas2552_dapm_widgets[] = |
94 | { | 120 | { |
@@ -96,12 +122,13 @@ static const struct snd_soc_dapm_widget tas2552_dapm_widgets[] = | |||
96 | 122 | ||
97 | /* MUX Controls */ | 123 | /* MUX Controls */ |
98 | SND_SOC_DAPM_MUX("Input selection", SND_SOC_NOPM, 0, 0, | 124 | SND_SOC_DAPM_MUX("Input selection", SND_SOC_NOPM, 0, 0, |
99 | tas2552_input_mux_control), | 125 | &tas2552_input_mux_control), |
100 | 126 | ||
101 | SND_SOC_DAPM_AIF_IN("DAC IN", "DAC Playback", 0, SND_SOC_NOPM, 0, 0), | 127 | SND_SOC_DAPM_AIF_IN("DAC IN", "DAC Playback", 0, SND_SOC_NOPM, 0, 0), |
102 | SND_SOC_DAPM_DAC("DAC", NULL, SND_SOC_NOPM, 0, 0), | 128 | SND_SOC_DAPM_DAC("DAC", NULL, SND_SOC_NOPM, 0, 0), |
103 | SND_SOC_DAPM_OUT_DRV("ClassD", TAS2552_CFG_2, 7, 0, NULL, 0), | 129 | SND_SOC_DAPM_OUT_DRV("ClassD", TAS2552_CFG_2, 7, 0, NULL, 0), |
104 | SND_SOC_DAPM_SUPPLY("PLL", TAS2552_CFG_2, 3, 0, NULL, 0), | 130 | SND_SOC_DAPM_SUPPLY("PLL", TAS2552_CFG_2, 3, 0, NULL, 0), |
131 | SND_SOC_DAPM_POST("Post Event", tas2552_post_event), | ||
105 | 132 | ||
106 | SND_SOC_DAPM_OUTPUT("OUT") | 133 | SND_SOC_DAPM_OUTPUT("OUT") |
107 | }; | 134 | }; |
@@ -118,15 +145,16 @@ static const struct snd_soc_dapm_route tas2552_audio_map[] = { | |||
118 | #ifdef CONFIG_PM | 145 | #ifdef CONFIG_PM |
119 | static void tas2552_sw_shutdown(struct tas2552_data *tas_data, int sw_shutdown) | 146 | static void tas2552_sw_shutdown(struct tas2552_data *tas_data, int sw_shutdown) |
120 | { | 147 | { |
121 | u8 cfg1_reg; | 148 | u8 cfg1_reg = 0; |
149 | |||
150 | if (!tas_data->codec) | ||
151 | return; | ||
122 | 152 | ||
123 | if (sw_shutdown) | 153 | if (sw_shutdown) |
124 | cfg1_reg = 0; | 154 | cfg1_reg = TAS2552_SWS; |
125 | else | ||
126 | cfg1_reg = TAS2552_SWS_MASK; | ||
127 | 155 | ||
128 | snd_soc_update_bits(tas_data->codec, TAS2552_CFG_1, | 156 | snd_soc_update_bits(tas_data->codec, TAS2552_CFG_1, TAS2552_SWS, |
129 | TAS2552_SWS_MASK, cfg1_reg); | 157 | cfg1_reg); |
130 | } | 158 | } |
131 | #endif | 159 | #endif |
132 | 160 | ||
@@ -138,15 +166,92 @@ static int tas2552_hw_params(struct snd_pcm_substream *substream, | |||
138 | struct tas2552_data *tas2552 = dev_get_drvdata(codec->dev); | 166 | struct tas2552_data *tas2552 = dev_get_drvdata(codec->dev); |
139 | int sample_rate, pll_clk; | 167 | int sample_rate, pll_clk; |
140 | int d; | 168 | int d; |
169 | int cpf; | ||
141 | u8 p, j; | 170 | u8 p, j; |
171 | u8 ser_ctrl1_reg, wclk_rate; | ||
142 | 172 | ||
143 | if (!tas2552->mclk) | 173 | switch (params_width(params)) { |
174 | case 16: | ||
175 | ser_ctrl1_reg = TAS2552_WORDLENGTH_16BIT; | ||
176 | cpf = 32 + tas2552->tdm_delay; | ||
177 | break; | ||
178 | case 20: | ||
179 | ser_ctrl1_reg = TAS2552_WORDLENGTH_20BIT; | ||
180 | cpf = 64 + tas2552->tdm_delay; | ||
181 | break; | ||
182 | case 24: | ||
183 | ser_ctrl1_reg = TAS2552_WORDLENGTH_24BIT; | ||
184 | cpf = 64 + tas2552->tdm_delay; | ||
185 | break; | ||
186 | case 32: | ||
187 | ser_ctrl1_reg = TAS2552_WORDLENGTH_32BIT; | ||
188 | cpf = 64 + tas2552->tdm_delay; | ||
189 | break; | ||
190 | default: | ||
191 | dev_err(codec->dev, "Not supported sample size: %d\n", | ||
192 | params_width(params)); | ||
193 | return -EINVAL; | ||
194 | } | ||
195 | |||
196 | if (cpf <= 32) | ||
197 | ser_ctrl1_reg |= TAS2552_CLKSPERFRAME_32; | ||
198 | else if (cpf <= 64) | ||
199 | ser_ctrl1_reg |= TAS2552_CLKSPERFRAME_64; | ||
200 | else if (cpf <= 128) | ||
201 | ser_ctrl1_reg |= TAS2552_CLKSPERFRAME_128; | ||
202 | else | ||
203 | ser_ctrl1_reg |= TAS2552_CLKSPERFRAME_256; | ||
204 | |||
205 | snd_soc_update_bits(codec, TAS2552_SER_CTRL_1, | ||
206 | TAS2552_WORDLENGTH_MASK | TAS2552_CLKSPERFRAME_MASK, | ||
207 | ser_ctrl1_reg); | ||
208 | |||
209 | switch (params_rate(params)) { | ||
210 | case 8000: | ||
211 | wclk_rate = TAS2552_WCLK_FREQ_8KHZ; | ||
212 | break; | ||
213 | case 11025: | ||
214 | case 12000: | ||
215 | wclk_rate = TAS2552_WCLK_FREQ_11_12KHZ; | ||
216 | break; | ||
217 | case 16000: | ||
218 | wclk_rate = TAS2552_WCLK_FREQ_16KHZ; | ||
219 | break; | ||
220 | case 22050: | ||
221 | case 24000: | ||
222 | wclk_rate = TAS2552_WCLK_FREQ_22_24KHZ; | ||
223 | break; | ||
224 | case 32000: | ||
225 | wclk_rate = TAS2552_WCLK_FREQ_32KHZ; | ||
226 | break; | ||
227 | case 44100: | ||
228 | case 48000: | ||
229 | wclk_rate = TAS2552_WCLK_FREQ_44_48KHZ; | ||
230 | break; | ||
231 | case 88200: | ||
232 | case 96000: | ||
233 | wclk_rate = TAS2552_WCLK_FREQ_88_96KHZ; | ||
234 | break; | ||
235 | case 176400: | ||
236 | case 192000: | ||
237 | wclk_rate = TAS2552_WCLK_FREQ_176_192KHZ; | ||
238 | break; | ||
239 | default: | ||
240 | dev_err(codec->dev, "Not supported sample rate: %d\n", | ||
241 | params_rate(params)); | ||
242 | return -EINVAL; | ||
243 | } | ||
244 | |||
245 | snd_soc_update_bits(codec, TAS2552_CFG_3, TAS2552_WCLK_FREQ_MASK, | ||
246 | wclk_rate); | ||
247 | |||
248 | if (!tas2552->pll_clkin) | ||
144 | return -EINVAL; | 249 | return -EINVAL; |
145 | 250 | ||
146 | snd_soc_update_bits(codec, TAS2552_CFG_2, TAS2552_PLL_ENABLE, 0); | 251 | snd_soc_update_bits(codec, TAS2552_CFG_2, TAS2552_PLL_ENABLE, 0); |
147 | 252 | ||
148 | if (tas2552->mclk == TAS2552_245MHZ_CLK || | 253 | if (tas2552->pll_clkin == TAS2552_245MHZ_CLK || |
149 | tas2552->mclk == TAS2552_225MHZ_CLK) { | 254 | tas2552->pll_clkin == TAS2552_225MHZ_CLK) { |
150 | /* By pass the PLL configuration */ | 255 | /* By pass the PLL configuration */ |
151 | snd_soc_update_bits(codec, TAS2552_PLL_CTRL_2, | 256 | snd_soc_update_bits(codec, TAS2552_PLL_CTRL_2, |
152 | TAS2552_PLL_BYPASS_MASK, | 257 | TAS2552_PLL_BYPASS_MASK, |
@@ -170,8 +275,8 @@ static int tas2552_hw_params(struct snd_pcm_substream *substream, | |||
170 | return -EINVAL; | 275 | return -EINVAL; |
171 | } | 276 | } |
172 | 277 | ||
173 | j = (pll_clk * 2 * (1 << p)) / tas2552->mclk; | 278 | j = (pll_clk * 2 * (1 << p)) / tas2552->pll_clkin; |
174 | d = (pll_clk * 2 * (1 << p)) % tas2552->mclk; | 279 | d = (pll_clk * 2 * (1 << p)) % tas2552->pll_clkin; |
175 | 280 | ||
176 | snd_soc_update_bits(codec, TAS2552_PLL_CTRL_1, | 281 | snd_soc_update_bits(codec, TAS2552_PLL_CTRL_1, |
177 | TAS2552_PLL_J_MASK, j); | 282 | TAS2552_PLL_J_MASK, j); |
@@ -185,56 +290,74 @@ static int tas2552_hw_params(struct snd_pcm_substream *substream, | |||
185 | return 0; | 290 | return 0; |
186 | } | 291 | } |
187 | 292 | ||
293 | #define TAS2552_DAI_FMT_MASK (TAS2552_BCLKDIR | \ | ||
294 | TAS2552_WCLKDIR | \ | ||
295 | TAS2552_DATAFORMAT_MASK) | ||
296 | static int tas2552_prepare(struct snd_pcm_substream *substream, | ||
297 | struct snd_soc_dai *dai) | ||
298 | { | ||
299 | struct snd_soc_codec *codec = dai->codec; | ||
300 | struct tas2552_data *tas2552 = snd_soc_codec_get_drvdata(codec); | ||
301 | int delay = 0; | ||
302 | |||
303 | /* TDM slot selection only valid in DSP_A/_B mode */ | ||
304 | if (tas2552->dai_fmt == SND_SOC_DAIFMT_DSP_A) | ||
305 | delay += (tas2552->tdm_delay + 1); | ||
306 | else if (tas2552->dai_fmt == SND_SOC_DAIFMT_DSP_B) | ||
307 | delay += tas2552->tdm_delay; | ||
308 | |||
309 | /* Configure data delay */ | ||
310 | snd_soc_write(codec, TAS2552_SER_CTRL_2, delay); | ||
311 | |||
312 | return 0; | ||
313 | } | ||
314 | |||
188 | static int tas2552_set_dai_fmt(struct snd_soc_dai *dai, unsigned int fmt) | 315 | static int tas2552_set_dai_fmt(struct snd_soc_dai *dai, unsigned int fmt) |
189 | { | 316 | { |
190 | struct snd_soc_codec *codec = dai->codec; | 317 | struct snd_soc_codec *codec = dai->codec; |
318 | struct tas2552_data *tas2552 = dev_get_drvdata(codec->dev); | ||
191 | u8 serial_format; | 319 | u8 serial_format; |
192 | u8 serial_control_mask; | ||
193 | 320 | ||
194 | switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { | 321 | switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { |
195 | case SND_SOC_DAIFMT_CBS_CFS: | 322 | case SND_SOC_DAIFMT_CBS_CFS: |
196 | serial_format = 0x00; | 323 | serial_format = 0x00; |
197 | break; | 324 | break; |
198 | case SND_SOC_DAIFMT_CBS_CFM: | 325 | case SND_SOC_DAIFMT_CBS_CFM: |
199 | serial_format = TAS2552_WORD_CLK_MASK; | 326 | serial_format = TAS2552_WCLKDIR; |
200 | break; | 327 | break; |
201 | case SND_SOC_DAIFMT_CBM_CFS: | 328 | case SND_SOC_DAIFMT_CBM_CFS: |
202 | serial_format = TAS2552_BIT_CLK_MASK; | 329 | serial_format = TAS2552_BCLKDIR; |
203 | break; | 330 | break; |
204 | case SND_SOC_DAIFMT_CBM_CFM: | 331 | case SND_SOC_DAIFMT_CBM_CFM: |
205 | serial_format = (TAS2552_BIT_CLK_MASK | TAS2552_WORD_CLK_MASK); | 332 | serial_format = (TAS2552_BCLKDIR | TAS2552_WCLKDIR); |
206 | break; | 333 | break; |
207 | default: | 334 | default: |
208 | dev_vdbg(codec->dev, "DAI Format master is not found\n"); | 335 | dev_vdbg(codec->dev, "DAI Format master is not found\n"); |
209 | return -EINVAL; | 336 | return -EINVAL; |
210 | } | 337 | } |
211 | 338 | ||
212 | serial_control_mask = TAS2552_BIT_CLK_MASK | TAS2552_WORD_CLK_MASK; | 339 | switch (fmt & (SND_SOC_DAIFMT_FORMAT_MASK | |
213 | 340 | SND_SOC_DAIFMT_INV_MASK)) { | |
214 | switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) { | 341 | case (SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF): |
215 | case SND_SOC_DAIFMT_I2S: | ||
216 | serial_format &= TAS2552_DAIFMT_I2S_MASK; | ||
217 | break; | 342 | break; |
218 | case SND_SOC_DAIFMT_DSP_A: | 343 | case (SND_SOC_DAIFMT_DSP_A | SND_SOC_DAIFMT_IB_NF): |
219 | serial_format |= TAS2552_DAIFMT_DSP; | 344 | case (SND_SOC_DAIFMT_DSP_B | SND_SOC_DAIFMT_IB_NF): |
345 | serial_format |= TAS2552_DATAFORMAT_DSP; | ||
220 | break; | 346 | break; |
221 | case SND_SOC_DAIFMT_RIGHT_J: | 347 | case (SND_SOC_DAIFMT_RIGHT_J | SND_SOC_DAIFMT_NB_NF): |
222 | serial_format |= TAS2552_DAIFMT_RIGHT_J; | 348 | serial_format |= TAS2552_DATAFORMAT_RIGHT_J; |
223 | break; | 349 | break; |
224 | case SND_SOC_DAIFMT_LEFT_J: | 350 | case (SND_SOC_DAIFMT_LEFT_J | SND_SOC_DAIFMT_NB_NF): |
225 | serial_format |= TAS2552_DAIFMT_LEFT_J; | 351 | serial_format |= TAS2552_DATAFORMAT_LEFT_J; |
226 | break; | 352 | break; |
227 | default: | 353 | default: |
228 | dev_vdbg(codec->dev, "DAI Format is not found\n"); | 354 | dev_vdbg(codec->dev, "DAI Format is not found\n"); |
229 | return -EINVAL; | 355 | return -EINVAL; |
230 | } | 356 | } |
357 | tas2552->dai_fmt = fmt & SND_SOC_DAIFMT_FORMAT_MASK; | ||
231 | 358 | ||
232 | if (fmt & SND_SOC_DAIFMT_FORMAT_MASK) | 359 | snd_soc_update_bits(codec, TAS2552_SER_CTRL_1, TAS2552_DAI_FMT_MASK, |
233 | serial_control_mask |= TAS2552_DATA_FORMAT_MASK; | 360 | serial_format); |
234 | |||
235 | snd_soc_update_bits(codec, TAS2552_SER_CTRL_1, serial_control_mask, | ||
236 | serial_format); | ||
237 | |||
238 | return 0; | 361 | return 0; |
239 | } | 362 | } |
240 | 363 | ||
@@ -243,23 +366,75 @@ static int tas2552_set_dai_sysclk(struct snd_soc_dai *dai, int clk_id, | |||
243 | { | 366 | { |
244 | struct snd_soc_codec *codec = dai->codec; | 367 | struct snd_soc_codec *codec = dai->codec; |
245 | struct tas2552_data *tas2552 = dev_get_drvdata(codec->dev); | 368 | struct tas2552_data *tas2552 = dev_get_drvdata(codec->dev); |
369 | u8 reg, mask, val; | ||
370 | |||
371 | switch (clk_id) { | ||
372 | case TAS2552_PLL_CLKIN_MCLK: | ||
373 | case TAS2552_PLL_CLKIN_BCLK: | ||
374 | case TAS2552_PLL_CLKIN_IVCLKIN: | ||
375 | case TAS2552_PLL_CLKIN_1_8_FIXED: | ||
376 | mask = TAS2552_PLL_SRC_MASK; | ||
377 | val = (clk_id << 3) & mask; /* bit 4:5 in the register */ | ||
378 | reg = TAS2552_CFG_1; | ||
379 | tas2552->pll_clkin = freq; | ||
380 | break; | ||
381 | case TAS2552_PDM_CLK_PLL: | ||
382 | case TAS2552_PDM_CLK_IVCLKIN: | ||
383 | case TAS2552_PDM_CLK_BCLK: | ||
384 | case TAS2552_PDM_CLK_MCLK: | ||
385 | mask = TAS2552_PDM_CLK_SEL_MASK; | ||
386 | val = (clk_id >> 1) & mask; /* bit 0:1 in the register */ | ||
387 | reg = TAS2552_PDM_CFG; | ||
388 | tas2552->pdm_clk = freq; | ||
389 | break; | ||
390 | default: | ||
391 | dev_err(codec->dev, "Invalid clk id: %d\n", clk_id); | ||
392 | return -EINVAL; | ||
393 | } | ||
394 | |||
395 | snd_soc_update_bits(codec, reg, mask, val); | ||
396 | |||
397 | return 0; | ||
398 | } | ||
399 | |||
400 | static int tas2552_set_dai_tdm_slot(struct snd_soc_dai *dai, | ||
401 | unsigned int tx_mask, unsigned int rx_mask, | ||
402 | int slots, int slot_width) | ||
403 | { | ||
404 | struct snd_soc_codec *codec = dai->codec; | ||
405 | struct tas2552_data *tas2552 = snd_soc_codec_get_drvdata(codec); | ||
406 | unsigned int lsb; | ||
407 | |||
408 | if (unlikely(!tx_mask)) { | ||
409 | dev_err(codec->dev, "tx masks need to be non 0\n"); | ||
410 | return -EINVAL; | ||
411 | } | ||
412 | |||
413 | /* TDM based on DSP mode requires slots to be adjacent */ | ||
414 | lsb = __ffs(tx_mask); | ||
415 | if ((lsb + 1) != __fls(tx_mask)) { | ||
416 | dev_err(codec->dev, "Invalid mask, slots must be adjacent\n"); | ||
417 | return -EINVAL; | ||
418 | } | ||
419 | |||
420 | tas2552->tdm_delay = lsb * slot_width; | ||
246 | 421 | ||
247 | tas2552->mclk = freq; | 422 | /* DOUT in high-impedance on inactive bit clocks */ |
423 | snd_soc_update_bits(codec, TAS2552_DOUT, | ||
424 | TAS2552_SDOUT_TRISTATE, TAS2552_SDOUT_TRISTATE); | ||
248 | 425 | ||
249 | return 0; | 426 | return 0; |
250 | } | 427 | } |
251 | 428 | ||
252 | static int tas2552_mute(struct snd_soc_dai *dai, int mute) | 429 | static int tas2552_mute(struct snd_soc_dai *dai, int mute) |
253 | { | 430 | { |
254 | u8 cfg1_reg; | 431 | u8 cfg1_reg = 0; |
255 | struct snd_soc_codec *codec = dai->codec; | 432 | struct snd_soc_codec *codec = dai->codec; |
256 | 433 | ||
257 | if (mute) | 434 | if (mute) |
258 | cfg1_reg = TAS2552_MUTE_MASK; | 435 | cfg1_reg |= TAS2552_MUTE; |
259 | else | ||
260 | cfg1_reg = ~TAS2552_MUTE_MASK; | ||
261 | 436 | ||
262 | snd_soc_update_bits(codec, TAS2552_CFG_1, TAS2552_MUTE_MASK, cfg1_reg); | 437 | snd_soc_update_bits(codec, TAS2552_CFG_1, TAS2552_MUTE, cfg1_reg); |
263 | 438 | ||
264 | return 0; | 439 | return 0; |
265 | } | 440 | } |
@@ -269,7 +444,7 @@ static int tas2552_runtime_suspend(struct device *dev) | |||
269 | { | 444 | { |
270 | struct tas2552_data *tas2552 = dev_get_drvdata(dev); | 445 | struct tas2552_data *tas2552 = dev_get_drvdata(dev); |
271 | 446 | ||
272 | tas2552_sw_shutdown(tas2552, 0); | 447 | tas2552_sw_shutdown(tas2552, 1); |
273 | 448 | ||
274 | regcache_cache_only(tas2552->regmap, true); | 449 | regcache_cache_only(tas2552->regmap, true); |
275 | regcache_mark_dirty(tas2552->regmap); | 450 | regcache_mark_dirty(tas2552->regmap); |
@@ -287,7 +462,7 @@ static int tas2552_runtime_resume(struct device *dev) | |||
287 | if (tas2552->enable_gpio) | 462 | if (tas2552->enable_gpio) |
288 | gpiod_set_value(tas2552->enable_gpio, 1); | 463 | gpiod_set_value(tas2552->enable_gpio, 1); |
289 | 464 | ||
290 | tas2552_sw_shutdown(tas2552, 1); | 465 | tas2552_sw_shutdown(tas2552, 0); |
291 | 466 | ||
292 | regcache_cache_only(tas2552->regmap, false); | 467 | regcache_cache_only(tas2552->regmap, false); |
293 | regcache_sync(tas2552->regmap); | 468 | regcache_sync(tas2552->regmap); |
@@ -303,8 +478,10 @@ static const struct dev_pm_ops tas2552_pm = { | |||
303 | 478 | ||
304 | static struct snd_soc_dai_ops tas2552_speaker_dai_ops = { | 479 | static struct snd_soc_dai_ops tas2552_speaker_dai_ops = { |
305 | .hw_params = tas2552_hw_params, | 480 | .hw_params = tas2552_hw_params, |
481 | .prepare = tas2552_prepare, | ||
306 | .set_sysclk = tas2552_set_dai_sysclk, | 482 | .set_sysclk = tas2552_set_dai_sysclk, |
307 | .set_fmt = tas2552_set_dai_fmt, | 483 | .set_fmt = tas2552_set_dai_fmt, |
484 | .set_tdm_slot = tas2552_set_dai_tdm_slot, | ||
308 | .digital_mute = tas2552_mute, | 485 | .digital_mute = tas2552_mute, |
309 | }; | 486 | }; |
310 | 487 | ||
@@ -330,16 +507,11 @@ static struct snd_soc_dai_driver tas2552_dai[] = { | |||
330 | /* | 507 | /* |
331 | * DAC digital volumes. From -7 to 24 dB in 1 dB steps | 508 | * DAC digital volumes. From -7 to 24 dB in 1 dB steps |
332 | */ | 509 | */ |
333 | static DECLARE_TLV_DB_SCALE(dac_tlv, -7, 100, 24); | 510 | static DECLARE_TLV_DB_SCALE(dac_tlv, -7, 100, 0); |
334 | 511 | ||
335 | static const struct snd_kcontrol_new tas2552_snd_controls[] = { | 512 | static const struct snd_kcontrol_new tas2552_snd_controls[] = { |
336 | SOC_SINGLE_TLV("Speaker Driver Playback Volume", | 513 | SOC_SINGLE_TLV("Speaker Driver Playback Volume", |
337 | TAS2552_PGA_GAIN, 0, 0x1f, 1, dac_tlv), | 514 | TAS2552_PGA_GAIN, 0, 0x1f, 0, dac_tlv), |
338 | SOC_DAPM_SINGLE("Playback AMP", SND_SOC_NOPM, 0, 1, 0), | ||
339 | }; | ||
340 | |||
341 | static const struct reg_default tas2552_init_regs[] = { | ||
342 | { TAS2552_RESERVED_0D, 0xc0 }, | ||
343 | }; | 515 | }; |
344 | 516 | ||
345 | static int tas2552_codec_probe(struct snd_soc_codec *codec) | 517 | static int tas2552_codec_probe(struct snd_soc_codec *codec) |
@@ -368,31 +540,19 @@ static int tas2552_codec_probe(struct snd_soc_codec *codec) | |||
368 | goto probe_fail; | 540 | goto probe_fail; |
369 | } | 541 | } |
370 | 542 | ||
371 | snd_soc_write(codec, TAS2552_CFG_1, TAS2552_MUTE_MASK | | 543 | snd_soc_update_bits(codec, TAS2552_CFG_1, TAS2552_MUTE, TAS2552_MUTE); |
372 | TAS2552_PLL_SRC_BCLK); | ||
373 | snd_soc_write(codec, TAS2552_CFG_3, TAS2552_I2S_OUT_SEL | | 544 | snd_soc_write(codec, TAS2552_CFG_3, TAS2552_I2S_OUT_SEL | |
374 | TAS2552_DIN_SRC_SEL_AVG_L_R | TAS2552_88_96KHZ); | 545 | TAS2552_DIN_SRC_SEL_AVG_L_R); |
375 | snd_soc_write(codec, TAS2552_DOUT, TAS2552_PDM_DATA_I); | 546 | snd_soc_write(codec, TAS2552_DOUT, TAS2552_PDM_DATA_I); |
376 | snd_soc_write(codec, TAS2552_OUTPUT_DATA, TAS2552_PDM_DATA_V_I | 0x8); | 547 | snd_soc_write(codec, TAS2552_OUTPUT_DATA, TAS2552_PDM_DATA_V_I | 0x8); |
377 | snd_soc_write(codec, TAS2552_PDM_CFG, TAS2552_PDM_BCLK_SEL); | ||
378 | snd_soc_write(codec, TAS2552_BOOST_PT_CTRL, TAS2552_APT_DELAY_200 | | 548 | snd_soc_write(codec, TAS2552_BOOST_PT_CTRL, TAS2552_APT_DELAY_200 | |
379 | TAS2552_APT_THRESH_2_1_7); | 549 | TAS2552_APT_THRESH_2_1_7); |
380 | 550 | ||
381 | ret = regmap_register_patch(tas2552->regmap, tas2552_init_regs, | ||
382 | ARRAY_SIZE(tas2552_init_regs)); | ||
383 | if (ret != 0) { | ||
384 | dev_err(codec->dev, "Failed to write init registers: %d\n", | ||
385 | ret); | ||
386 | goto patch_fail; | ||
387 | } | ||
388 | |||
389 | snd_soc_write(codec, TAS2552_CFG_2, TAS2552_BOOST_EN | | 551 | snd_soc_write(codec, TAS2552_CFG_2, TAS2552_BOOST_EN | |
390 | TAS2552_APT_EN | TAS2552_LIM_EN); | 552 | TAS2552_APT_EN | TAS2552_LIM_EN); |
391 | 553 | ||
392 | return 0; | 554 | return 0; |
393 | 555 | ||
394 | patch_fail: | ||
395 | pm_runtime_put(codec->dev); | ||
396 | probe_fail: | 556 | probe_fail: |
397 | if (tas2552->enable_gpio) | 557 | if (tas2552->enable_gpio) |
398 | gpiod_set_value(tas2552->enable_gpio, 0); | 558 | gpiod_set_value(tas2552->enable_gpio, 0); |
@@ -454,6 +614,8 @@ static struct snd_soc_codec_driver soc_codec_dev_tas2552 = { | |||
454 | .remove = tas2552_codec_remove, | 614 | .remove = tas2552_codec_remove, |
455 | .suspend = tas2552_suspend, | 615 | .suspend = tas2552_suspend, |
456 | .resume = tas2552_resume, | 616 | .resume = tas2552_resume, |
617 | .ignore_pmdown_time = true, | ||
618 | |||
457 | .controls = tas2552_snd_controls, | 619 | .controls = tas2552_snd_controls, |
458 | .num_controls = ARRAY_SIZE(tas2552_snd_controls), | 620 | .num_controls = ARRAY_SIZE(tas2552_snd_controls), |
459 | .dapm_widgets = tas2552_dapm_widgets, | 621 | .dapm_widgets = tas2552_dapm_widgets, |
@@ -486,8 +648,12 @@ static int tas2552_probe(struct i2c_client *client, | |||
486 | return -ENOMEM; | 648 | return -ENOMEM; |
487 | 649 | ||
488 | data->enable_gpio = devm_gpiod_get(dev, "enable", GPIOD_OUT_LOW); | 650 | data->enable_gpio = devm_gpiod_get(dev, "enable", GPIOD_OUT_LOW); |
489 | if (IS_ERR(data->enable_gpio)) | 651 | if (IS_ERR(data->enable_gpio)) { |
490 | return PTR_ERR(data->enable_gpio); | 652 | if (PTR_ERR(data->enable_gpio) == -EPROBE_DEFER) |
653 | return -EPROBE_DEFER; | ||
654 | |||
655 | data->enable_gpio = NULL;; | ||
656 | } | ||
491 | 657 | ||
492 | data->tas2552_client = client; | 658 | data->tas2552_client = client; |
493 | data->regmap = devm_regmap_init_i2c(client, &tas2552_regmap_config); | 659 | data->regmap = devm_regmap_init_i2c(client, &tas2552_regmap_config); |
diff --git a/sound/soc/codecs/tas2552.h b/sound/soc/codecs/tas2552.h index 6cea8f31bf88..bbb820495516 100644 --- a/sound/soc/codecs/tas2552.h +++ b/sound/soc/codecs/tas2552.h | |||
@@ -45,10 +45,14 @@ | |||
45 | #define TAS2552_MAX_REG 0x20 | 45 | #define TAS2552_MAX_REG 0x20 |
46 | 46 | ||
47 | /* CFG1 Register Masks */ | 47 | /* CFG1 Register Masks */ |
48 | #define TAS2552_MUTE_MASK (1 << 2) | 48 | #define TAS2552_DEV_RESET (1 << 0) |
49 | #define TAS2552_SWS_MASK (1 << 1) | 49 | #define TAS2552_SWS (1 << 1) |
50 | #define TAS2552_WCLK_MASK 0x07 | 50 | #define TAS2552_MUTE (1 << 2) |
51 | #define TAS2552_CLASSD_EN_MASK (1 << 7) | 51 | #define TAS2552_PLL_SRC_MCLK (0x0 << 4) |
52 | #define TAS2552_PLL_SRC_BCLK (0x1 << 4) | ||
53 | #define TAS2552_PLL_SRC_IVCLKIN (0x2 << 4) | ||
54 | #define TAS2552_PLL_SRC_1_8_FIXED (0x3 << 4) | ||
55 | #define TAS2552_PLL_SRC_MASK TAS2552_PLL_SRC_1_8_FIXED | ||
52 | 56 | ||
53 | /* CFG2 Register Masks */ | 57 | /* CFG2 Register Masks */ |
54 | #define TAS2552_CLASSD_EN (1 << 7) | 58 | #define TAS2552_CLASSD_EN (1 << 7) |
@@ -59,38 +63,44 @@ | |||
59 | #define TAS2552_IVSENSE_EN (1 << 1) | 63 | #define TAS2552_IVSENSE_EN (1 << 1) |
60 | 64 | ||
61 | /* CFG3 Register Masks */ | 65 | /* CFG3 Register Masks */ |
62 | #define TAS2552_WORD_CLK_MASK (1 << 7) | 66 | #define TAS2552_WCLK_FREQ_8KHZ (0x0 << 0) |
63 | #define TAS2552_BIT_CLK_MASK (1 << 6) | 67 | #define TAS2552_WCLK_FREQ_11_12KHZ (0x1 << 0) |
64 | #define TAS2552_DATA_FORMAT_MASK (0x11 << 2) | 68 | #define TAS2552_WCLK_FREQ_16KHZ (0x2 << 0) |
65 | 69 | #define TAS2552_WCLK_FREQ_22_24KHZ (0x3 << 0) | |
66 | #define TAS2552_DAIFMT_I2S_MASK 0xf3 | 70 | #define TAS2552_WCLK_FREQ_32KHZ (0x4 << 0) |
67 | #define TAS2552_DAIFMT_DSP (1 << 3) | 71 | #define TAS2552_WCLK_FREQ_44_48KHZ (0x5 << 0) |
68 | #define TAS2552_DAIFMT_RIGHT_J (1 << 4) | 72 | #define TAS2552_WCLK_FREQ_88_96KHZ (0x6 << 0) |
69 | #define TAS2552_DAIFMT_LEFT_J (0x11 << 3) | 73 | #define TAS2552_WCLK_FREQ_176_192KHZ (0x7 << 0) |
70 | 74 | #define TAS2552_WCLK_FREQ_MASK TAS2552_WCLK_FREQ_176_192KHZ | |
71 | #define TAS2552_PLL_SRC_MCLK 0x00 | 75 | #define TAS2552_DIN_SRC_SEL_MUTED (0x0 << 3) |
72 | #define TAS2552_PLL_SRC_BCLK (1 << 3) | 76 | #define TAS2552_DIN_SRC_SEL_LEFT (0x1 << 3) |
73 | #define TAS2552_PLL_SRC_IVCLKIN (1 << 4) | 77 | #define TAS2552_DIN_SRC_SEL_RIGHT (0x2 << 3) |
74 | #define TAS2552_PLL_SRC_1_8_FIXED (0x11 << 3) | 78 | #define TAS2552_DIN_SRC_SEL_AVG_L_R (0x3 << 3) |
75 | |||
76 | #define TAS2552_DIN_SRC_SEL_MUTED 0x00 | ||
77 | #define TAS2552_DIN_SRC_SEL_LEFT (1 << 4) | ||
78 | #define TAS2552_DIN_SRC_SEL_RIGHT (1 << 5) | ||
79 | #define TAS2552_DIN_SRC_SEL_AVG_L_R (0x11 << 4) | ||
80 | |||
81 | #define TAS2552_PDM_IN_SEL (1 << 5) | 79 | #define TAS2552_PDM_IN_SEL (1 << 5) |
82 | #define TAS2552_I2S_OUT_SEL (1 << 6) | 80 | #define TAS2552_I2S_OUT_SEL (1 << 6) |
83 | #define TAS2552_ANALOG_IN_SEL (1 << 7) | 81 | #define TAS2552_ANALOG_IN_SEL (1 << 7) |
84 | 82 | ||
85 | /* CFG3 WCLK Dividers */ | 83 | /* DOUT Register Masks */ |
86 | #define TAS2552_8KHZ 0x00 | 84 | #define TAS2552_SDOUT_TRISTATE (1 << 2) |
87 | #define TAS2552_11_12KHZ (1 << 1) | 85 | |
88 | #define TAS2552_16KHZ (1 << 2) | 86 | /* Serial Interface Control Register Masks */ |
89 | #define TAS2552_22_24KHZ (1 << 3) | 87 | #define TAS2552_WORDLENGTH_16BIT (0x0 << 0) |
90 | #define TAS2552_32KHZ (1 << 4) | 88 | #define TAS2552_WORDLENGTH_20BIT (0x1 << 0) |
91 | #define TAS2552_44_48KHZ (1 << 5) | 89 | #define TAS2552_WORDLENGTH_24BIT (0x2 << 0) |
92 | #define TAS2552_88_96KHZ (1 << 6) | 90 | #define TAS2552_WORDLENGTH_32BIT (0x3 << 0) |
93 | #define TAS2552_176_192KHZ (1 << 7) | 91 | #define TAS2552_WORDLENGTH_MASK TAS2552_WORDLENGTH_32BIT |
92 | #define TAS2552_DATAFORMAT_I2S (0x0 << 2) | ||
93 | #define TAS2552_DATAFORMAT_DSP (0x1 << 2) | ||
94 | #define TAS2552_DATAFORMAT_RIGHT_J (0x2 << 2) | ||
95 | #define TAS2552_DATAFORMAT_LEFT_J (0x3 << 2) | ||
96 | #define TAS2552_DATAFORMAT_MASK TAS2552_DATAFORMAT_LEFT_J | ||
97 | #define TAS2552_CLKSPERFRAME_32 (0x0 << 4) | ||
98 | #define TAS2552_CLKSPERFRAME_64 (0x1 << 4) | ||
99 | #define TAS2552_CLKSPERFRAME_128 (0x2 << 4) | ||
100 | #define TAS2552_CLKSPERFRAME_256 (0x3 << 4) | ||
101 | #define TAS2552_CLKSPERFRAME_MASK TAS2552_CLKSPERFRAME_256 | ||
102 | #define TAS2552_BCLKDIR (1 << 6) | ||
103 | #define TAS2552_WCLKDIR (1 << 7) | ||
94 | 104 | ||
95 | /* OUTPUT_DATA register */ | 105 | /* OUTPUT_DATA register */ |
96 | #define TAS2552_PDM_DATA_I 0x00 | 106 | #define TAS2552_PDM_DATA_I 0x00 |
@@ -99,12 +109,12 @@ | |||
99 | #define TAS2552_PDM_DATA_V_I (0x11 << 6) | 109 | #define TAS2552_PDM_DATA_V_I (0x11 << 6) |
100 | 110 | ||
101 | /* PDM CFG Register */ | 111 | /* PDM CFG Register */ |
102 | #define TAS2552_PDM_DATA_ES_RISE 0x4 | 112 | #define TAS2552_PDM_CLK_SEL_PLL (0x0 << 0) |
103 | 113 | #define TAS2552_PDM_CLK_SEL_IVCLKIN (0x1 << 0) | |
104 | #define TAS2552_PDM_PLL_CLK_SEL 0x00 | 114 | #define TAS2552_PDM_CLK_SEL_BCLK (0x2 << 0) |
105 | #define TAS2552_PDM_IV_CLK_SEL (1 << 1) | 115 | #define TAS2552_PDM_CLK_SEL_MCLK (0x3 << 0) |
106 | #define TAS2552_PDM_BCLK_SEL (1 << 2) | 116 | #define TAS2552_PDM_CLK_SEL_MASK TAS2552_PDM_CLK_SEL_MCLK |
107 | #define TAS2552_PDM_MCLK_SEL (1 << 3) | 117 | #define TAS2552_PDM_DATA_ES (1 << 2) |
108 | 118 | ||
109 | /* Boost pass-through register */ | 119 | /* Boost pass-through register */ |
110 | #define TAS2552_APT_DELAY_50 0x00 | 120 | #define TAS2552_APT_DELAY_50 0x00 |
diff --git a/sound/soc/codecs/tas571x.c b/sound/soc/codecs/tas571x.c new file mode 100644 index 000000000000..85bcc374c8e8 --- /dev/null +++ b/sound/soc/codecs/tas571x.c | |||
@@ -0,0 +1,514 @@ | |||
1 | /* | ||
2 | * TAS571x amplifier audio driver | ||
3 | * | ||
4 | * Copyright (C) 2015 Google, Inc. | ||
5 | * Copyright (c) 2013 Daniel Mack <zonque@gmail.com> | ||
6 | * | ||
7 | * This program is free software; you can redistribute it and/or modify | ||
8 | * it under the terms of the GNU General Public License as published by | ||
9 | * the Free Software Foundation; either version 2 of the License, or | ||
10 | * (at your option) any later version. | ||
11 | */ | ||
12 | |||
13 | #include <linux/clk.h> | ||
14 | #include <linux/delay.h> | ||
15 | #include <linux/device.h> | ||
16 | #include <linux/gpio/consumer.h> | ||
17 | #include <linux/i2c.h> | ||
18 | #include <linux/init.h> | ||
19 | #include <linux/kernel.h> | ||
20 | #include <linux/module.h> | ||
21 | #include <linux/of_device.h> | ||
22 | #include <linux/regmap.h> | ||
23 | #include <linux/regulator/consumer.h> | ||
24 | #include <linux/stddef.h> | ||
25 | #include <sound/pcm_params.h> | ||
26 | #include <sound/soc.h> | ||
27 | #include <sound/tlv.h> | ||
28 | |||
29 | #include "tas571x.h" | ||
30 | |||
31 | #define TAS571X_MAX_SUPPLIES 6 | ||
32 | |||
33 | struct tas571x_chip { | ||
34 | const char *const *supply_names; | ||
35 | int num_supply_names; | ||
36 | const struct snd_kcontrol_new *controls; | ||
37 | int num_controls; | ||
38 | const struct regmap_config *regmap_config; | ||
39 | int vol_reg_size; | ||
40 | }; | ||
41 | |||
42 | struct tas571x_private { | ||
43 | const struct tas571x_chip *chip; | ||
44 | struct regmap *regmap; | ||
45 | struct regulator_bulk_data supplies[TAS571X_MAX_SUPPLIES]; | ||
46 | struct clk *mclk; | ||
47 | unsigned int format; | ||
48 | struct gpio_desc *reset_gpio; | ||
49 | struct gpio_desc *pdn_gpio; | ||
50 | struct snd_soc_codec_driver codec_driver; | ||
51 | }; | ||
52 | |||
53 | static int tas571x_register_size(struct tas571x_private *priv, unsigned int reg) | ||
54 | { | ||
55 | switch (reg) { | ||
56 | case TAS571X_MVOL_REG: | ||
57 | case TAS571X_CH1_VOL_REG: | ||
58 | case TAS571X_CH2_VOL_REG: | ||
59 | return priv->chip->vol_reg_size; | ||
60 | default: | ||
61 | return 1; | ||
62 | } | ||
63 | } | ||
64 | |||
65 | static int tas571x_reg_write(void *context, unsigned int reg, | ||
66 | unsigned int value) | ||
67 | { | ||
68 | struct i2c_client *client = context; | ||
69 | struct tas571x_private *priv = i2c_get_clientdata(client); | ||
70 | unsigned int i, size; | ||
71 | uint8_t buf[5]; | ||
72 | int ret; | ||
73 | |||
74 | size = tas571x_register_size(priv, reg); | ||
75 | buf[0] = reg; | ||
76 | |||
77 | for (i = size; i >= 1; --i) { | ||
78 | buf[i] = value; | ||
79 | value >>= 8; | ||
80 | } | ||
81 | |||
82 | ret = i2c_master_send(client, buf, size + 1); | ||
83 | if (ret == size + 1) | ||
84 | return 0; | ||
85 | else if (ret < 0) | ||
86 | return ret; | ||
87 | else | ||
88 | return -EIO; | ||
89 | } | ||
90 | |||
91 | static int tas571x_reg_read(void *context, unsigned int reg, | ||
92 | unsigned int *value) | ||
93 | { | ||
94 | struct i2c_client *client = context; | ||
95 | struct tas571x_private *priv = i2c_get_clientdata(client); | ||
96 | uint8_t send_buf, recv_buf[4]; | ||
97 | struct i2c_msg msgs[2]; | ||
98 | unsigned int size; | ||
99 | unsigned int i; | ||
100 | int ret; | ||
101 | |||
102 | size = tas571x_register_size(priv, reg); | ||
103 | send_buf = reg; | ||
104 | |||
105 | msgs[0].addr = client->addr; | ||
106 | msgs[0].len = sizeof(send_buf); | ||
107 | msgs[0].buf = &send_buf; | ||
108 | msgs[0].flags = 0; | ||
109 | |||
110 | msgs[1].addr = client->addr; | ||
111 | msgs[1].len = size; | ||
112 | msgs[1].buf = recv_buf; | ||
113 | msgs[1].flags = I2C_M_RD; | ||
114 | |||
115 | ret = i2c_transfer(client->adapter, msgs, ARRAY_SIZE(msgs)); | ||
116 | if (ret < 0) | ||
117 | return ret; | ||
118 | else if (ret != ARRAY_SIZE(msgs)) | ||
119 | return -EIO; | ||
120 | |||
121 | *value = 0; | ||
122 | |||
123 | for (i = 0; i < size; i++) { | ||
124 | *value <<= 8; | ||
125 | *value |= recv_buf[i]; | ||
126 | } | ||
127 | |||
128 | return 0; | ||
129 | } | ||
130 | |||
131 | static int tas571x_set_dai_fmt(struct snd_soc_dai *dai, unsigned int format) | ||
132 | { | ||
133 | struct tas571x_private *priv = snd_soc_codec_get_drvdata(dai->codec); | ||
134 | |||
135 | priv->format = format; | ||
136 | |||
137 | return 0; | ||
138 | } | ||
139 | |||
140 | static int tas571x_hw_params(struct snd_pcm_substream *substream, | ||
141 | struct snd_pcm_hw_params *params, | ||
142 | struct snd_soc_dai *dai) | ||
143 | { | ||
144 | struct tas571x_private *priv = snd_soc_codec_get_drvdata(dai->codec); | ||
145 | u32 val; | ||
146 | |||
147 | switch (priv->format & SND_SOC_DAIFMT_FORMAT_MASK) { | ||
148 | case SND_SOC_DAIFMT_RIGHT_J: | ||
149 | val = 0x00; | ||
150 | break; | ||
151 | case SND_SOC_DAIFMT_I2S: | ||
152 | val = 0x03; | ||
153 | break; | ||
154 | case SND_SOC_DAIFMT_LEFT_J: | ||
155 | val = 0x06; | ||
156 | break; | ||
157 | default: | ||
158 | return -EINVAL; | ||
159 | } | ||
160 | |||
161 | if (params_width(params) >= 24) | ||
162 | val += 2; | ||
163 | else if (params_width(params) >= 20) | ||
164 | val += 1; | ||
165 | |||
166 | return regmap_update_bits(priv->regmap, TAS571X_SDI_REG, | ||
167 | TAS571X_SDI_FMT_MASK, val); | ||
168 | } | ||
169 | |||
170 | static int tas571x_set_bias_level(struct snd_soc_codec *codec, | ||
171 | enum snd_soc_bias_level level) | ||
172 | { | ||
173 | struct tas571x_private *priv = snd_soc_codec_get_drvdata(codec); | ||
174 | int ret; | ||
175 | |||
176 | switch (level) { | ||
177 | case SND_SOC_BIAS_ON: | ||
178 | break; | ||
179 | case SND_SOC_BIAS_PREPARE: | ||
180 | break; | ||
181 | case SND_SOC_BIAS_STANDBY: | ||
182 | if (codec->dapm.bias_level == SND_SOC_BIAS_OFF) { | ||
183 | if (!IS_ERR(priv->mclk)) { | ||
184 | ret = clk_prepare_enable(priv->mclk); | ||
185 | if (ret) { | ||
186 | dev_err(codec->dev, | ||
187 | "Failed to enable master clock: %d\n", | ||
188 | ret); | ||
189 | return ret; | ||
190 | } | ||
191 | } | ||
192 | |||
193 | gpiod_set_value(priv->pdn_gpio, 0); | ||
194 | usleep_range(5000, 6000); | ||
195 | |||
196 | regcache_cache_only(priv->regmap, false); | ||
197 | ret = regcache_sync(priv->regmap); | ||
198 | if (ret) | ||
199 | return ret; | ||
200 | } | ||
201 | break; | ||
202 | case SND_SOC_BIAS_OFF: | ||
203 | regcache_cache_only(priv->regmap, true); | ||
204 | gpiod_set_value(priv->pdn_gpio, 1); | ||
205 | |||
206 | if (!IS_ERR(priv->mclk)) | ||
207 | clk_disable_unprepare(priv->mclk); | ||
208 | break; | ||
209 | } | ||
210 | |||
211 | return 0; | ||
212 | } | ||
213 | |||
214 | static const struct snd_soc_dai_ops tas571x_dai_ops = { | ||
215 | .set_fmt = tas571x_set_dai_fmt, | ||
216 | .hw_params = tas571x_hw_params, | ||
217 | }; | ||
218 | |||
219 | static const char *const tas5711_supply_names[] = { | ||
220 | "AVDD", | ||
221 | "DVDD", | ||
222 | "PVDD_A", | ||
223 | "PVDD_B", | ||
224 | "PVDD_C", | ||
225 | "PVDD_D", | ||
226 | }; | ||
227 | |||
228 | static const DECLARE_TLV_DB_SCALE(tas5711_volume_tlv, -10350, 50, 1); | ||
229 | |||
230 | static const struct snd_kcontrol_new tas5711_controls[] = { | ||
231 | SOC_SINGLE_TLV("Master Volume", | ||
232 | TAS571X_MVOL_REG, | ||
233 | 0, 0xff, 1, tas5711_volume_tlv), | ||
234 | SOC_DOUBLE_R_TLV("Speaker Volume", | ||
235 | TAS571X_CH1_VOL_REG, | ||
236 | TAS571X_CH2_VOL_REG, | ||
237 | 0, 0xff, 1, tas5711_volume_tlv), | ||
238 | SOC_DOUBLE("Speaker Switch", | ||
239 | TAS571X_SOFT_MUTE_REG, | ||
240 | TAS571X_SOFT_MUTE_CH1_SHIFT, TAS571X_SOFT_MUTE_CH2_SHIFT, | ||
241 | 1, 1), | ||
242 | }; | ||
243 | |||
244 | static const struct reg_default tas5711_reg_defaults[] = { | ||
245 | { 0x04, 0x05 }, | ||
246 | { 0x05, 0x40 }, | ||
247 | { 0x06, 0x00 }, | ||
248 | { 0x07, 0xff }, | ||
249 | { 0x08, 0x30 }, | ||
250 | { 0x09, 0x30 }, | ||
251 | { 0x1b, 0x82 }, | ||
252 | }; | ||
253 | |||
254 | static const struct regmap_config tas5711_regmap_config = { | ||
255 | .reg_bits = 8, | ||
256 | .val_bits = 32, | ||
257 | .max_register = 0xff, | ||
258 | .reg_read = tas571x_reg_read, | ||
259 | .reg_write = tas571x_reg_write, | ||
260 | .reg_defaults = tas5711_reg_defaults, | ||
261 | .num_reg_defaults = ARRAY_SIZE(tas5711_reg_defaults), | ||
262 | .cache_type = REGCACHE_RBTREE, | ||
263 | }; | ||
264 | |||
265 | static const struct tas571x_chip tas5711_chip = { | ||
266 | .supply_names = tas5711_supply_names, | ||
267 | .num_supply_names = ARRAY_SIZE(tas5711_supply_names), | ||
268 | .controls = tas5711_controls, | ||
269 | .num_controls = ARRAY_SIZE(tas5711_controls), | ||
270 | .regmap_config = &tas5711_regmap_config, | ||
271 | .vol_reg_size = 1, | ||
272 | }; | ||
273 | |||
274 | static const char *const tas5717_supply_names[] = { | ||
275 | "AVDD", | ||
276 | "DVDD", | ||
277 | "HPVDD", | ||
278 | "PVDD_AB", | ||
279 | "PVDD_CD", | ||
280 | }; | ||
281 | |||
282 | static const DECLARE_TLV_DB_SCALE(tas5717_volume_tlv, -10375, 25, 0); | ||
283 | |||
284 | static const struct snd_kcontrol_new tas5717_controls[] = { | ||
285 | /* MVOL LSB is ignored - see comments in tas571x_i2c_probe() */ | ||
286 | SOC_SINGLE_TLV("Master Volume", | ||
287 | TAS571X_MVOL_REG, 1, 0x1ff, 1, | ||
288 | tas5717_volume_tlv), | ||
289 | SOC_DOUBLE_R_TLV("Speaker Volume", | ||
290 | TAS571X_CH1_VOL_REG, TAS571X_CH2_VOL_REG, | ||
291 | 1, 0x1ff, 1, tas5717_volume_tlv), | ||
292 | SOC_DOUBLE("Speaker Switch", | ||
293 | TAS571X_SOFT_MUTE_REG, | ||
294 | TAS571X_SOFT_MUTE_CH1_SHIFT, TAS571X_SOFT_MUTE_CH2_SHIFT, | ||
295 | 1, 1), | ||
296 | }; | ||
297 | |||
298 | static const struct reg_default tas5717_reg_defaults[] = { | ||
299 | { 0x04, 0x05 }, | ||
300 | { 0x05, 0x40 }, | ||
301 | { 0x06, 0x00 }, | ||
302 | { 0x07, 0x03ff }, | ||
303 | { 0x08, 0x00c0 }, | ||
304 | { 0x09, 0x00c0 }, | ||
305 | { 0x1b, 0x82 }, | ||
306 | }; | ||
307 | |||
308 | static const struct regmap_config tas5717_regmap_config = { | ||
309 | .reg_bits = 8, | ||
310 | .val_bits = 32, | ||
311 | .max_register = 0xff, | ||
312 | .reg_read = tas571x_reg_read, | ||
313 | .reg_write = tas571x_reg_write, | ||
314 | .reg_defaults = tas5717_reg_defaults, | ||
315 | .num_reg_defaults = ARRAY_SIZE(tas5717_reg_defaults), | ||
316 | .cache_type = REGCACHE_RBTREE, | ||
317 | }; | ||
318 | |||
319 | /* This entry is reused for tas5719 as the software interface is identical. */ | ||
320 | static const struct tas571x_chip tas5717_chip = { | ||
321 | .supply_names = tas5717_supply_names, | ||
322 | .num_supply_names = ARRAY_SIZE(tas5717_supply_names), | ||
323 | .controls = tas5717_controls, | ||
324 | .num_controls = ARRAY_SIZE(tas5717_controls), | ||
325 | .regmap_config = &tas5717_regmap_config, | ||
326 | .vol_reg_size = 2, | ||
327 | }; | ||
328 | |||
329 | static const struct snd_soc_dapm_widget tas571x_dapm_widgets[] = { | ||
330 | SND_SOC_DAPM_DAC("DACL", NULL, SND_SOC_NOPM, 0, 0), | ||
331 | SND_SOC_DAPM_DAC("DACR", NULL, SND_SOC_NOPM, 0, 0), | ||
332 | |||
333 | SND_SOC_DAPM_OUTPUT("OUT_A"), | ||
334 | SND_SOC_DAPM_OUTPUT("OUT_B"), | ||
335 | SND_SOC_DAPM_OUTPUT("OUT_C"), | ||
336 | SND_SOC_DAPM_OUTPUT("OUT_D"), | ||
337 | }; | ||
338 | |||
339 | static const struct snd_soc_dapm_route tas571x_dapm_routes[] = { | ||
340 | { "DACL", NULL, "Playback" }, | ||
341 | { "DACR", NULL, "Playback" }, | ||
342 | |||
343 | { "OUT_A", NULL, "DACL" }, | ||
344 | { "OUT_B", NULL, "DACL" }, | ||
345 | { "OUT_C", NULL, "DACR" }, | ||
346 | { "OUT_D", NULL, "DACR" }, | ||
347 | }; | ||
348 | |||
349 | static const struct snd_soc_codec_driver tas571x_codec = { | ||
350 | .set_bias_level = tas571x_set_bias_level, | ||
351 | .idle_bias_off = true, | ||
352 | |||
353 | .dapm_widgets = tas571x_dapm_widgets, | ||
354 | .num_dapm_widgets = ARRAY_SIZE(tas571x_dapm_widgets), | ||
355 | .dapm_routes = tas571x_dapm_routes, | ||
356 | .num_dapm_routes = ARRAY_SIZE(tas571x_dapm_routes), | ||
357 | }; | ||
358 | |||
359 | static struct snd_soc_dai_driver tas571x_dai = { | ||
360 | .name = "tas571x-hifi", | ||
361 | .playback = { | ||
362 | .stream_name = "Playback", | ||
363 | .channels_min = 2, | ||
364 | .channels_max = 2, | ||
365 | .rates = SNDRV_PCM_RATE_8000_48000, | ||
366 | .formats = SNDRV_PCM_FMTBIT_S32_LE | | ||
367 | SNDRV_PCM_FMTBIT_S24_LE | | ||
368 | SNDRV_PCM_FMTBIT_S16_LE, | ||
369 | }, | ||
370 | .ops = &tas571x_dai_ops, | ||
371 | }; | ||
372 | |||
373 | static const struct of_device_id tas571x_of_match[]; | ||
374 | |||
375 | static int tas571x_i2c_probe(struct i2c_client *client, | ||
376 | const struct i2c_device_id *id) | ||
377 | { | ||
378 | struct tas571x_private *priv; | ||
379 | struct device *dev = &client->dev; | ||
380 | const struct of_device_id *of_id; | ||
381 | int i, ret; | ||
382 | |||
383 | priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL); | ||
384 | if (!priv) | ||
385 | return -ENOMEM; | ||
386 | i2c_set_clientdata(client, priv); | ||
387 | |||
388 | of_id = of_match_device(tas571x_of_match, dev); | ||
389 | if (!of_id) { | ||
390 | dev_err(dev, "Unknown device type\n"); | ||
391 | return -EINVAL; | ||
392 | } | ||
393 | priv->chip = of_id->data; | ||
394 | |||
395 | priv->mclk = devm_clk_get(dev, "mclk"); | ||
396 | if (IS_ERR(priv->mclk) && PTR_ERR(priv->mclk) != -ENOENT) { | ||
397 | dev_err(dev, "Failed to request mclk: %ld\n", | ||
398 | PTR_ERR(priv->mclk)); | ||
399 | return PTR_ERR(priv->mclk); | ||
400 | } | ||
401 | |||
402 | BUG_ON(priv->chip->num_supply_names > TAS571X_MAX_SUPPLIES); | ||
403 | for (i = 0; i < priv->chip->num_supply_names; i++) | ||
404 | priv->supplies[i].supply = priv->chip->supply_names[i]; | ||
405 | |||
406 | ret = devm_regulator_bulk_get(dev, priv->chip->num_supply_names, | ||
407 | priv->supplies); | ||
408 | if (ret) { | ||
409 | dev_err(dev, "Failed to get supplies: %d\n", ret); | ||
410 | return ret; | ||
411 | } | ||
412 | ret = regulator_bulk_enable(priv->chip->num_supply_names, | ||
413 | priv->supplies); | ||
414 | if (ret) { | ||
415 | dev_err(dev, "Failed to enable supplies: %d\n", ret); | ||
416 | return ret; | ||
417 | } | ||
418 | |||
419 | priv->regmap = devm_regmap_init(dev, NULL, client, | ||
420 | priv->chip->regmap_config); | ||
421 | if (IS_ERR(priv->regmap)) | ||
422 | return PTR_ERR(priv->regmap); | ||
423 | |||
424 | priv->pdn_gpio = devm_gpiod_get_optional(dev, "pdn", GPIOD_OUT_LOW); | ||
425 | if (IS_ERR(priv->pdn_gpio)) { | ||
426 | dev_err(dev, "error requesting pdn_gpio: %ld\n", | ||
427 | PTR_ERR(priv->pdn_gpio)); | ||
428 | return PTR_ERR(priv->pdn_gpio); | ||
429 | } | ||
430 | |||
431 | priv->reset_gpio = devm_gpiod_get_optional(dev, "reset", | ||
432 | GPIOD_OUT_HIGH); | ||
433 | if (IS_ERR(priv->reset_gpio)) { | ||
434 | dev_err(dev, "error requesting reset_gpio: %ld\n", | ||
435 | PTR_ERR(priv->reset_gpio)); | ||
436 | return PTR_ERR(priv->reset_gpio); | ||
437 | } else if (priv->reset_gpio) { | ||
438 | /* pulse the active low reset line for ~100us */ | ||
439 | usleep_range(100, 200); | ||
440 | gpiod_set_value(priv->reset_gpio, 0); | ||
441 | usleep_range(12000, 20000); | ||
442 | } | ||
443 | |||
444 | ret = regmap_write(priv->regmap, TAS571X_OSC_TRIM_REG, 0); | ||
445 | if (ret) | ||
446 | return ret; | ||
447 | |||
448 | ret = regmap_update_bits(priv->regmap, TAS571X_SYS_CTRL_2_REG, | ||
449 | TAS571X_SYS_CTRL_2_SDN_MASK, 0); | ||
450 | if (ret) | ||
451 | return ret; | ||
452 | |||
453 | memcpy(&priv->codec_driver, &tas571x_codec, sizeof(priv->codec_driver)); | ||
454 | priv->codec_driver.controls = priv->chip->controls; | ||
455 | priv->codec_driver.num_controls = priv->chip->num_controls; | ||
456 | |||
457 | if (priv->chip->vol_reg_size == 2) { | ||
458 | /* | ||
459 | * The master volume defaults to 0x3ff (mute), but we ignore | ||
460 | * (zero) the LSB because the hardware step size is 0.125 dB | ||
461 | * and TLV_DB_SCALE_ITEM has a resolution of 0.01 dB. | ||
462 | */ | ||
463 | ret = regmap_update_bits(priv->regmap, TAS571X_MVOL_REG, 1, 0); | ||
464 | if (ret) | ||
465 | return ret; | ||
466 | } | ||
467 | |||
468 | regcache_cache_only(priv->regmap, true); | ||
469 | gpiod_set_value(priv->pdn_gpio, 1); | ||
470 | |||
471 | return snd_soc_register_codec(&client->dev, &priv->codec_driver, | ||
472 | &tas571x_dai, 1); | ||
473 | } | ||
474 | |||
475 | static int tas571x_i2c_remove(struct i2c_client *client) | ||
476 | { | ||
477 | struct tas571x_private *priv = i2c_get_clientdata(client); | ||
478 | |||
479 | snd_soc_unregister_codec(&client->dev); | ||
480 | regulator_bulk_disable(priv->chip->num_supply_names, priv->supplies); | ||
481 | |||
482 | return 0; | ||
483 | } | ||
484 | |||
485 | static const struct of_device_id tas571x_of_match[] = { | ||
486 | { .compatible = "ti,tas5711", .data = &tas5711_chip, }, | ||
487 | { .compatible = "ti,tas5717", .data = &tas5717_chip, }, | ||
488 | { .compatible = "ti,tas5719", .data = &tas5717_chip, }, | ||
489 | { } | ||
490 | }; | ||
491 | MODULE_DEVICE_TABLE(of, tas571x_of_match); | ||
492 | |||
493 | static const struct i2c_device_id tas571x_i2c_id[] = { | ||
494 | { "tas5711", 0 }, | ||
495 | { "tas5717", 0 }, | ||
496 | { "tas5719", 0 }, | ||
497 | { } | ||
498 | }; | ||
499 | MODULE_DEVICE_TABLE(i2c, tas571x_i2c_id); | ||
500 | |||
501 | static struct i2c_driver tas571x_i2c_driver = { | ||
502 | .driver = { | ||
503 | .name = "tas571x", | ||
504 | .of_match_table = of_match_ptr(tas571x_of_match), | ||
505 | }, | ||
506 | .probe = tas571x_i2c_probe, | ||
507 | .remove = tas571x_i2c_remove, | ||
508 | .id_table = tas571x_i2c_id, | ||
509 | }; | ||
510 | module_i2c_driver(tas571x_i2c_driver); | ||
511 | |||
512 | MODULE_DESCRIPTION("ASoC TAS571x driver"); | ||
513 | MODULE_AUTHOR("Kevin Cernekee <cernekee@chromium.org>"); | ||
514 | MODULE_LICENSE("GPL"); | ||
diff --git a/sound/soc/codecs/tas571x.h b/sound/soc/codecs/tas571x.h new file mode 100644 index 000000000000..0aee471232cd --- /dev/null +++ b/sound/soc/codecs/tas571x.h | |||
@@ -0,0 +1,33 @@ | |||
1 | /* | ||
2 | * TAS571x amplifier audio driver | ||
3 | * | ||
4 | * Copyright (C) 2015 Google, Inc. | ||
5 | * | ||
6 | * This program is free software; you can redistribute it and/or modify | ||
7 | * it under the terms of the GNU General Public License as published by | ||
8 | * the Free Software Foundation; either version 2 of the License, or | ||
9 | * (at your option) any later version. | ||
10 | */ | ||
11 | |||
12 | #ifndef _TAS571X_H | ||
13 | #define _TAS571X_H | ||
14 | |||
15 | /* device registers */ | ||
16 | #define TAS571X_SDI_REG 0x04 | ||
17 | #define TAS571X_SDI_FMT_MASK 0x0f | ||
18 | |||
19 | #define TAS571X_SYS_CTRL_2_REG 0x05 | ||
20 | #define TAS571X_SYS_CTRL_2_SDN_MASK 0x40 | ||
21 | |||
22 | #define TAS571X_SOFT_MUTE_REG 0x06 | ||
23 | #define TAS571X_SOFT_MUTE_CH1_SHIFT 0 | ||
24 | #define TAS571X_SOFT_MUTE_CH2_SHIFT 1 | ||
25 | #define TAS571X_SOFT_MUTE_CH3_SHIFT 2 | ||
26 | |||
27 | #define TAS571X_MVOL_REG 0x07 | ||
28 | #define TAS571X_CH1_VOL_REG 0x08 | ||
29 | #define TAS571X_CH2_VOL_REG 0x09 | ||
30 | |||
31 | #define TAS571X_OSC_TRIM_REG 0x1b | ||
32 | |||
33 | #endif /* _TAS571X_H */ | ||
diff --git a/sound/soc/codecs/tfa9879.c b/sound/soc/codecs/tfa9879.c index 16f1b71edb55..aab0af681e8c 100644 --- a/sound/soc/codecs/tfa9879.c +++ b/sound/soc/codecs/tfa9879.c | |||
@@ -280,8 +280,8 @@ static int tfa9879_i2c_probe(struct i2c_client *i2c, | |||
280 | int i; | 280 | int i; |
281 | 281 | ||
282 | tfa9879 = devm_kzalloc(&i2c->dev, sizeof(*tfa9879), GFP_KERNEL); | 282 | tfa9879 = devm_kzalloc(&i2c->dev, sizeof(*tfa9879), GFP_KERNEL); |
283 | if (IS_ERR(tfa9879)) | 283 | if (!tfa9879) |
284 | return PTR_ERR(tfa9879); | 284 | return -ENOMEM; |
285 | 285 | ||
286 | i2c_set_clientdata(i2c, tfa9879); | 286 | i2c_set_clientdata(i2c, tfa9879); |
287 | 287 | ||
diff --git a/sound/soc/codecs/tlv320aic23.c b/sound/soc/codecs/tlv320aic23.c index cc17e7e5126e..cd8c02b6e4de 100644 --- a/sound/soc/codecs/tlv320aic23.c +++ b/sound/soc/codecs/tlv320aic23.c | |||
@@ -506,7 +506,6 @@ static int tlv320aic23_set_bias_level(struct snd_soc_codec *codec, | |||
506 | snd_soc_write(codec, TLV320AIC23_PWR, 0x1ff); | 506 | snd_soc_write(codec, TLV320AIC23_PWR, 0x1ff); |
507 | break; | 507 | break; |
508 | } | 508 | } |
509 | codec->dapm.bias_level = level; | ||
510 | return 0; | 509 | return 0; |
511 | } | 510 | } |
512 | 511 | ||
diff --git a/sound/soc/codecs/tlv320aic31xx.c b/sound/soc/codecs/tlv320aic31xx.c index c86dd9aae157..c4c960f592a1 100644 --- a/sound/soc/codecs/tlv320aic31xx.c +++ b/sound/soc/codecs/tlv320aic31xx.c | |||
@@ -646,7 +646,7 @@ static int aic31xx_add_controls(struct snd_soc_codec *codec) | |||
646 | 646 | ||
647 | static int aic31xx_add_widgets(struct snd_soc_codec *codec) | 647 | static int aic31xx_add_widgets(struct snd_soc_codec *codec) |
648 | { | 648 | { |
649 | struct snd_soc_dapm_context *dapm = &codec->dapm; | 649 | struct snd_soc_dapm_context *dapm = snd_soc_codec_get_dapm(codec); |
650 | struct aic31xx_priv *aic31xx = snd_soc_codec_get_drvdata(codec); | 650 | struct aic31xx_priv *aic31xx = snd_soc_codec_get_drvdata(codec); |
651 | int ret = 0; | 651 | int ret = 0; |
652 | 652 | ||
@@ -1027,17 +1027,17 @@ static int aic31xx_set_bias_level(struct snd_soc_codec *codec, | |||
1027 | enum snd_soc_bias_level level) | 1027 | enum snd_soc_bias_level level) |
1028 | { | 1028 | { |
1029 | dev_dbg(codec->dev, "## %s: %d -> %d\n", __func__, | 1029 | dev_dbg(codec->dev, "## %s: %d -> %d\n", __func__, |
1030 | codec->dapm.bias_level, level); | 1030 | snd_soc_codec_get_bias_level(codec), level); |
1031 | 1031 | ||
1032 | switch (level) { | 1032 | switch (level) { |
1033 | case SND_SOC_BIAS_ON: | 1033 | case SND_SOC_BIAS_ON: |
1034 | break; | 1034 | break; |
1035 | case SND_SOC_BIAS_PREPARE: | 1035 | case SND_SOC_BIAS_PREPARE: |
1036 | if (codec->dapm.bias_level == SND_SOC_BIAS_STANDBY) | 1036 | if (snd_soc_codec_get_bias_level(codec) == SND_SOC_BIAS_STANDBY) |
1037 | aic31xx_clk_on(codec); | 1037 | aic31xx_clk_on(codec); |
1038 | break; | 1038 | break; |
1039 | case SND_SOC_BIAS_STANDBY: | 1039 | case SND_SOC_BIAS_STANDBY: |
1040 | switch (codec->dapm.bias_level) { | 1040 | switch (snd_soc_codec_get_bias_level(codec)) { |
1041 | case SND_SOC_BIAS_OFF: | 1041 | case SND_SOC_BIAS_OFF: |
1042 | aic31xx_power_on(codec); | 1042 | aic31xx_power_on(codec); |
1043 | break; | 1043 | break; |
@@ -1049,11 +1049,10 @@ static int aic31xx_set_bias_level(struct snd_soc_codec *codec, | |||
1049 | } | 1049 | } |
1050 | break; | 1050 | break; |
1051 | case SND_SOC_BIAS_OFF: | 1051 | case SND_SOC_BIAS_OFF: |
1052 | if (codec->dapm.bias_level == SND_SOC_BIAS_STANDBY) | 1052 | if (snd_soc_codec_get_bias_level(codec) == SND_SOC_BIAS_STANDBY) |
1053 | aic31xx_power_off(codec); | 1053 | aic31xx_power_off(codec); |
1054 | break; | 1054 | break; |
1055 | } | 1055 | } |
1056 | codec->dapm.bias_level = level; | ||
1057 | 1056 | ||
1058 | return 0; | 1057 | return 0; |
1059 | } | 1058 | } |
diff --git a/sound/soc/codecs/tlv320aic32x4.c b/sound/soc/codecs/tlv320aic32x4.c index 015467ed606b..ad6cb90e5f9b 100644 --- a/sound/soc/codecs/tlv320aic32x4.c +++ b/sound/soc/codecs/tlv320aic32x4.c | |||
@@ -564,7 +564,6 @@ static int aic32x4_set_bias_level(struct snd_soc_codec *codec, | |||
564 | case SND_SOC_BIAS_OFF: | 564 | case SND_SOC_BIAS_OFF: |
565 | break; | 565 | break; |
566 | } | 566 | } |
567 | codec->dapm.bias_level = level; | ||
568 | return 0; | 567 | return 0; |
569 | } | 568 | } |
570 | 569 | ||
diff --git a/sound/soc/codecs/tlv320aic3x.c b/sound/soc/codecs/tlv320aic3x.c index 51c4713ac6e3..a7cf19b53fb2 100644 --- a/sound/soc/codecs/tlv320aic3x.c +++ b/sound/soc/codecs/tlv320aic3x.c | |||
@@ -147,6 +147,7 @@ static int snd_soc_dapm_put_volsw_aic3x(struct snd_kcontrol *kcontrol, | |||
147 | struct snd_ctl_elem_value *ucontrol) | 147 | struct snd_ctl_elem_value *ucontrol) |
148 | { | 148 | { |
149 | struct snd_soc_codec *codec = snd_soc_dapm_kcontrol_codec(kcontrol); | 149 | struct snd_soc_codec *codec = snd_soc_dapm_kcontrol_codec(kcontrol); |
150 | struct snd_soc_dapm_context *dapm = snd_soc_codec_get_dapm(codec); | ||
150 | struct soc_mixer_control *mc = | 151 | struct soc_mixer_control *mc = |
151 | (struct soc_mixer_control *)kcontrol->private_value; | 152 | (struct soc_mixer_control *)kcontrol->private_value; |
152 | unsigned int reg = mc->reg; | 153 | unsigned int reg = mc->reg; |
@@ -179,7 +180,7 @@ static int snd_soc_dapm_put_volsw_aic3x(struct snd_kcontrol *kcontrol, | |||
179 | update.mask = mask; | 180 | update.mask = mask; |
180 | update.val = val; | 181 | update.val = val; |
181 | 182 | ||
182 | snd_soc_dapm_mixer_update_power(&codec->dapm, kcontrol, connect, | 183 | snd_soc_dapm_mixer_update_power(dapm, kcontrol, connect, |
183 | &update); | 184 | &update); |
184 | } | 185 | } |
185 | 186 | ||
@@ -979,7 +980,7 @@ static const struct snd_soc_dapm_route intercon_3007[] = { | |||
979 | static int aic3x_add_widgets(struct snd_soc_codec *codec) | 980 | static int aic3x_add_widgets(struct snd_soc_codec *codec) |
980 | { | 981 | { |
981 | struct aic3x_priv *aic3x = snd_soc_codec_get_drvdata(codec); | 982 | struct aic3x_priv *aic3x = snd_soc_codec_get_drvdata(codec); |
982 | struct snd_soc_dapm_context *dapm = &codec->dapm; | 983 | struct snd_soc_dapm_context *dapm = snd_soc_codec_get_dapm(codec); |
983 | 984 | ||
984 | switch (aic3x->model) { | 985 | switch (aic3x->model) { |
985 | case AIC3X_MODEL_3X: | 986 | case AIC3X_MODEL_3X: |
@@ -1384,7 +1385,7 @@ static int aic3x_set_bias_level(struct snd_soc_codec *codec, | |||
1384 | case SND_SOC_BIAS_ON: | 1385 | case SND_SOC_BIAS_ON: |
1385 | break; | 1386 | break; |
1386 | case SND_SOC_BIAS_PREPARE: | 1387 | case SND_SOC_BIAS_PREPARE: |
1387 | if (codec->dapm.bias_level == SND_SOC_BIAS_STANDBY && | 1388 | if (snd_soc_codec_get_bias_level(codec) == SND_SOC_BIAS_STANDBY && |
1388 | aic3x->master) { | 1389 | aic3x->master) { |
1389 | /* enable pll */ | 1390 | /* enable pll */ |
1390 | snd_soc_update_bits(codec, AIC3X_PLL_PROGA_REG, | 1391 | snd_soc_update_bits(codec, AIC3X_PLL_PROGA_REG, |
@@ -1394,7 +1395,7 @@ static int aic3x_set_bias_level(struct snd_soc_codec *codec, | |||
1394 | case SND_SOC_BIAS_STANDBY: | 1395 | case SND_SOC_BIAS_STANDBY: |
1395 | if (!aic3x->power) | 1396 | if (!aic3x->power) |
1396 | aic3x_set_power(codec, 1); | 1397 | aic3x_set_power(codec, 1); |
1397 | if (codec->dapm.bias_level == SND_SOC_BIAS_PREPARE && | 1398 | if (snd_soc_codec_get_bias_level(codec) == SND_SOC_BIAS_PREPARE && |
1398 | aic3x->master) { | 1399 | aic3x->master) { |
1399 | /* disable pll */ | 1400 | /* disable pll */ |
1400 | snd_soc_update_bits(codec, AIC3X_PLL_PROGA_REG, | 1401 | snd_soc_update_bits(codec, AIC3X_PLL_PROGA_REG, |
@@ -1406,7 +1407,6 @@ static int aic3x_set_bias_level(struct snd_soc_codec *codec, | |||
1406 | aic3x_set_power(codec, 0); | 1407 | aic3x_set_power(codec, 0); |
1407 | break; | 1408 | break; |
1408 | } | 1409 | } |
1409 | codec->dapm.bias_level = level; | ||
1410 | 1410 | ||
1411 | return 0; | 1411 | return 0; |
1412 | } | 1412 | } |
diff --git a/sound/soc/codecs/tlv320dac33.c b/sound/soc/codecs/tlv320dac33.c index 4e3e607dec13..d67a311f0e75 100644 --- a/sound/soc/codecs/tlv320dac33.c +++ b/sound/soc/codecs/tlv320dac33.c | |||
@@ -633,7 +633,7 @@ static int dac33_set_bias_level(struct snd_soc_codec *codec, | |||
633 | case SND_SOC_BIAS_PREPARE: | 633 | case SND_SOC_BIAS_PREPARE: |
634 | break; | 634 | break; |
635 | case SND_SOC_BIAS_STANDBY: | 635 | case SND_SOC_BIAS_STANDBY: |
636 | if (codec->dapm.bias_level == SND_SOC_BIAS_OFF) { | 636 | if (snd_soc_codec_get_bias_level(codec) == SND_SOC_BIAS_OFF) { |
637 | /* Coming from OFF, switch on the codec */ | 637 | /* Coming from OFF, switch on the codec */ |
638 | ret = dac33_hard_power(codec, 1); | 638 | ret = dac33_hard_power(codec, 1); |
639 | if (ret != 0) | 639 | if (ret != 0) |
@@ -644,14 +644,13 @@ static int dac33_set_bias_level(struct snd_soc_codec *codec, | |||
644 | break; | 644 | break; |
645 | case SND_SOC_BIAS_OFF: | 645 | case SND_SOC_BIAS_OFF: |
646 | /* Do not power off, when the codec is already off */ | 646 | /* Do not power off, when the codec is already off */ |
647 | if (codec->dapm.bias_level == SND_SOC_BIAS_OFF) | 647 | if (snd_soc_codec_get_bias_level(codec) == SND_SOC_BIAS_OFF) |
648 | return 0; | 648 | return 0; |
649 | ret = dac33_hard_power(codec, 0); | 649 | ret = dac33_hard_power(codec, 0); |
650 | if (ret != 0) | 650 | if (ret != 0) |
651 | return ret; | 651 | return ret; |
652 | break; | 652 | break; |
653 | } | 653 | } |
654 | codec->dapm.bias_level = level; | ||
655 | 654 | ||
656 | return 0; | 655 | return 0; |
657 | } | 656 | } |
diff --git a/sound/soc/codecs/ts3a227e.c b/sound/soc/codecs/ts3a227e.c index 9fd80ac1897f..12232d7db4c5 100644 --- a/sound/soc/codecs/ts3a227e.c +++ b/sound/soc/codecs/ts3a227e.c | |||
@@ -254,12 +254,13 @@ static const struct regmap_config ts3a227e_regmap_config = { | |||
254 | .num_reg_defaults = ARRAY_SIZE(ts3a227e_reg_defaults), | 254 | .num_reg_defaults = ARRAY_SIZE(ts3a227e_reg_defaults), |
255 | }; | 255 | }; |
256 | 256 | ||
257 | static int ts3a227e_parse_dt(struct ts3a227e *ts3a227e, struct device_node *np) | 257 | static int ts3a227e_parse_device_property(struct ts3a227e *ts3a227e, |
258 | struct device *dev) | ||
258 | { | 259 | { |
259 | u32 micbias; | 260 | u32 micbias; |
260 | int err; | 261 | int err; |
261 | 262 | ||
262 | err = of_property_read_u32(np, "ti,micbias", &micbias); | 263 | err = device_property_read_u32(dev, "ti,micbias", &micbias); |
263 | if (!err) { | 264 | if (!err) { |
264 | regmap_update_bits(ts3a227e->regmap, TS3A227E_REG_SETTING_3, | 265 | regmap_update_bits(ts3a227e->regmap, TS3A227E_REG_SETTING_3, |
265 | MICBIAS_SETTING_MASK, | 266 | MICBIAS_SETTING_MASK, |
@@ -287,12 +288,10 @@ static int ts3a227e_i2c_probe(struct i2c_client *i2c, | |||
287 | if (IS_ERR(ts3a227e->regmap)) | 288 | if (IS_ERR(ts3a227e->regmap)) |
288 | return PTR_ERR(ts3a227e->regmap); | 289 | return PTR_ERR(ts3a227e->regmap); |
289 | 290 | ||
290 | if (dev->of_node) { | 291 | ret = ts3a227e_parse_device_property(ts3a227e, dev); |
291 | ret = ts3a227e_parse_dt(ts3a227e, dev->of_node); | 292 | if (ret) { |
292 | if (ret) { | 293 | dev_err(dev, "Failed to parse device property: %d\n", ret); |
293 | dev_err(dev, "Failed to parse device tree: %d\n", ret); | 294 | return ret; |
294 | return ret; | ||
295 | } | ||
296 | } | 295 | } |
297 | 296 | ||
298 | ret = devm_request_threaded_irq(dev, i2c->irq, NULL, ts3a227e_interrupt, | 297 | ret = devm_request_threaded_irq(dev, i2c->irq, NULL, ts3a227e_interrupt, |
diff --git a/sound/soc/codecs/twl4030.c b/sound/soc/codecs/twl4030.c index d04693e9cf9f..90f5f04eca2d 100644 --- a/sound/soc/codecs/twl4030.c +++ b/sound/soc/codecs/twl4030.c | |||
@@ -1588,14 +1588,13 @@ static int twl4030_set_bias_level(struct snd_soc_codec *codec, | |||
1588 | case SND_SOC_BIAS_PREPARE: | 1588 | case SND_SOC_BIAS_PREPARE: |
1589 | break; | 1589 | break; |
1590 | case SND_SOC_BIAS_STANDBY: | 1590 | case SND_SOC_BIAS_STANDBY: |
1591 | if (codec->dapm.bias_level == SND_SOC_BIAS_OFF) | 1591 | if (snd_soc_codec_get_bias_level(codec) == SND_SOC_BIAS_OFF) |
1592 | twl4030_codec_enable(codec, 1); | 1592 | twl4030_codec_enable(codec, 1); |
1593 | break; | 1593 | break; |
1594 | case SND_SOC_BIAS_OFF: | 1594 | case SND_SOC_BIAS_OFF: |
1595 | twl4030_codec_enable(codec, 0); | 1595 | twl4030_codec_enable(codec, 0); |
1596 | break; | 1596 | break; |
1597 | } | 1597 | } |
1598 | codec->dapm.bias_level = level; | ||
1599 | 1598 | ||
1600 | return 0; | 1599 | return 0; |
1601 | } | 1600 | } |
diff --git a/sound/soc/codecs/twl6040.c b/sound/soc/codecs/twl6040.c index aeec27b6f1af..4cad8929d262 100644 --- a/sound/soc/codecs/twl6040.c +++ b/sound/soc/codecs/twl6040.c | |||
@@ -533,7 +533,7 @@ static int twl6040_pll_put_enum(struct snd_kcontrol *kcontrol, | |||
533 | 533 | ||
534 | int twl6040_get_dl1_gain(struct snd_soc_codec *codec) | 534 | int twl6040_get_dl1_gain(struct snd_soc_codec *codec) |
535 | { | 535 | { |
536 | struct snd_soc_dapm_context *dapm = &codec->dapm; | 536 | struct snd_soc_dapm_context *dapm = snd_soc_codec_get_dapm(codec); |
537 | 537 | ||
538 | if (snd_soc_dapm_get_pin_status(dapm, "EP")) | 538 | if (snd_soc_dapm_get_pin_status(dapm, "EP")) |
539 | return -1; /* -1dB */ | 539 | return -1; /* -1dB */ |
@@ -853,8 +853,6 @@ static int twl6040_set_bias_level(struct snd_soc_codec *codec, | |||
853 | break; | 853 | break; |
854 | } | 854 | } |
855 | 855 | ||
856 | codec->dapm.bias_level = level; | ||
857 | |||
858 | return 0; | 856 | return 0; |
859 | } | 857 | } |
860 | 858 | ||
@@ -1123,14 +1121,15 @@ static int twl6040_probe(struct snd_soc_codec *codec) | |||
1123 | mutex_init(&priv->mutex); | 1121 | mutex_init(&priv->mutex); |
1124 | 1122 | ||
1125 | ret = request_threaded_irq(priv->plug_irq, NULL, | 1123 | ret = request_threaded_irq(priv->plug_irq, NULL, |
1126 | twl6040_audio_handler, IRQF_NO_SUSPEND, | 1124 | twl6040_audio_handler, |
1125 | IRQF_NO_SUSPEND | IRQF_ONESHOT, | ||
1127 | "twl6040_irq_plug", codec); | 1126 | "twl6040_irq_plug", codec); |
1128 | if (ret) { | 1127 | if (ret) { |
1129 | dev_err(codec->dev, "PLUG IRQ request failed: %d\n", ret); | 1128 | dev_err(codec->dev, "PLUG IRQ request failed: %d\n", ret); |
1130 | return ret; | 1129 | return ret; |
1131 | } | 1130 | } |
1132 | 1131 | ||
1133 | twl6040_set_bias_level(codec, SND_SOC_BIAS_STANDBY); | 1132 | snd_soc_codec_force_bias_level(codec, SND_SOC_BIAS_STANDBY); |
1134 | twl6040_init_chip(codec); | 1133 | twl6040_init_chip(codec); |
1135 | 1134 | ||
1136 | return 0; | 1135 | return 0; |
diff --git a/sound/soc/codecs/uda134x.c b/sound/soc/codecs/uda134x.c index f883308c00de..913edf283239 100644 --- a/sound/soc/codecs/uda134x.c +++ b/sound/soc/codecs/uda134x.c | |||
@@ -350,7 +350,6 @@ static int uda134x_set_bias_level(struct snd_soc_codec *codec, | |||
350 | pd->power(0); | 350 | pd->power(0); |
351 | break; | 351 | break; |
352 | } | 352 | } |
353 | codec->dapm.bias_level = level; | ||
354 | return 0; | 353 | return 0; |
355 | } | 354 | } |
356 | 355 | ||
@@ -478,6 +477,7 @@ static struct snd_soc_dai_driver uda134x_dai = { | |||
478 | 477 | ||
479 | static int uda134x_soc_probe(struct snd_soc_codec *codec) | 478 | static int uda134x_soc_probe(struct snd_soc_codec *codec) |
480 | { | 479 | { |
480 | struct snd_soc_dapm_context *dapm = snd_soc_codec_get_dapm(codec); | ||
481 | struct uda134x_priv *uda134x; | 481 | struct uda134x_priv *uda134x; |
482 | struct uda134x_platform_data *pd = codec->component.card->dev->platform_data; | 482 | struct uda134x_platform_data *pd = codec->component.card->dev->platform_data; |
483 | const struct snd_soc_dapm_widget *widgets; | 483 | const struct snd_soc_dapm_widget *widgets; |
@@ -526,7 +526,7 @@ static int uda134x_soc_probe(struct snd_soc_codec *codec) | |||
526 | num_widgets = ARRAY_SIZE(uda1340_dapm_widgets); | 526 | num_widgets = ARRAY_SIZE(uda1340_dapm_widgets); |
527 | } | 527 | } |
528 | 528 | ||
529 | ret = snd_soc_dapm_new_controls(&codec->dapm, widgets, num_widgets); | 529 | ret = snd_soc_dapm_new_controls(dapm, widgets, num_widgets); |
530 | if (ret) { | 530 | if (ret) { |
531 | printk(KERN_ERR "%s failed to register dapm controls: %d", | 531 | printk(KERN_ERR "%s failed to register dapm controls: %d", |
532 | __func__, ret); | 532 | __func__, ret); |
diff --git a/sound/soc/codecs/uda1380.c b/sound/soc/codecs/uda1380.c index dc7778b6dd7f..6e159f59d219 100644 --- a/sound/soc/codecs/uda1380.c +++ b/sound/soc/codecs/uda1380.c | |||
@@ -437,7 +437,7 @@ static int uda1380_set_dai_fmt_both(struct snd_soc_dai *codec_dai, | |||
437 | if ((fmt & SND_SOC_DAIFMT_MASTER_MASK) != SND_SOC_DAIFMT_CBS_CFS) | 437 | if ((fmt & SND_SOC_DAIFMT_MASTER_MASK) != SND_SOC_DAIFMT_CBS_CFS) |
438 | return -EINVAL; | 438 | return -EINVAL; |
439 | 439 | ||
440 | uda1380_write(codec, UDA1380_IFACE, iface); | 440 | uda1380_write_reg_cache(codec, UDA1380_IFACE, iface); |
441 | 441 | ||
442 | return 0; | 442 | return 0; |
443 | } | 443 | } |
@@ -590,9 +590,6 @@ static int uda1380_set_bias_level(struct snd_soc_codec *codec, | |||
590 | int reg; | 590 | int reg; |
591 | struct uda1380_platform_data *pdata = codec->dev->platform_data; | 591 | struct uda1380_platform_data *pdata = codec->dev->platform_data; |
592 | 592 | ||
593 | if (codec->dapm.bias_level == level) | ||
594 | return 0; | ||
595 | |||
596 | switch (level) { | 593 | switch (level) { |
597 | case SND_SOC_BIAS_ON: | 594 | case SND_SOC_BIAS_ON: |
598 | case SND_SOC_BIAS_PREPARE: | 595 | case SND_SOC_BIAS_PREPARE: |
@@ -600,7 +597,7 @@ static int uda1380_set_bias_level(struct snd_soc_codec *codec, | |||
600 | uda1380_write(codec, UDA1380_PM, R02_PON_BIAS | pm); | 597 | uda1380_write(codec, UDA1380_PM, R02_PON_BIAS | pm); |
601 | break; | 598 | break; |
602 | case SND_SOC_BIAS_STANDBY: | 599 | case SND_SOC_BIAS_STANDBY: |
603 | if (codec->dapm.bias_level == SND_SOC_BIAS_OFF) { | 600 | if (snd_soc_codec_get_bias_level(codec) == SND_SOC_BIAS_OFF) { |
604 | if (gpio_is_valid(pdata->gpio_power)) { | 601 | if (gpio_is_valid(pdata->gpio_power)) { |
605 | gpio_set_value(pdata->gpio_power, 1); | 602 | gpio_set_value(pdata->gpio_power, 1); |
606 | mdelay(1); | 603 | mdelay(1); |
@@ -623,7 +620,6 @@ static int uda1380_set_bias_level(struct snd_soc_codec *codec, | |||
623 | for (reg = UDA1380_MVOL; reg < UDA1380_CACHEREGNUM; reg++) | 620 | for (reg = UDA1380_MVOL; reg < UDA1380_CACHEREGNUM; reg++) |
624 | set_bit(reg - 0x10, &uda1380_cache_dirty); | 621 | set_bit(reg - 0x10, &uda1380_cache_dirty); |
625 | } | 622 | } |
626 | codec->dapm.bias_level = level; | ||
627 | return 0; | 623 | return 0; |
628 | } | 624 | } |
629 | 625 | ||
diff --git a/sound/soc/codecs/wm0010.c b/sound/soc/codecs/wm0010.c index f37989ec7cba..6560a66b3f35 100644 --- a/sound/soc/codecs/wm0010.c +++ b/sound/soc/codecs/wm0010.c | |||
@@ -751,13 +751,13 @@ static int wm0010_set_bias_level(struct snd_soc_codec *codec, | |||
751 | 751 | ||
752 | switch (level) { | 752 | switch (level) { |
753 | case SND_SOC_BIAS_ON: | 753 | case SND_SOC_BIAS_ON: |
754 | if (codec->dapm.bias_level == SND_SOC_BIAS_PREPARE) | 754 | if (snd_soc_codec_get_bias_level(codec) == SND_SOC_BIAS_PREPARE) |
755 | wm0010_boot(codec); | 755 | wm0010_boot(codec); |
756 | break; | 756 | break; |
757 | case SND_SOC_BIAS_PREPARE: | 757 | case SND_SOC_BIAS_PREPARE: |
758 | break; | 758 | break; |
759 | case SND_SOC_BIAS_STANDBY: | 759 | case SND_SOC_BIAS_STANDBY: |
760 | if (codec->dapm.bias_level == SND_SOC_BIAS_PREPARE) { | 760 | if (snd_soc_codec_get_bias_level(codec) == SND_SOC_BIAS_PREPARE) { |
761 | mutex_lock(&wm0010->lock); | 761 | mutex_lock(&wm0010->lock); |
762 | wm0010_halt(codec); | 762 | wm0010_halt(codec); |
763 | mutex_unlock(&wm0010->lock); | 763 | mutex_unlock(&wm0010->lock); |
@@ -767,8 +767,6 @@ static int wm0010_set_bias_level(struct snd_soc_codec *codec, | |||
767 | break; | 767 | break; |
768 | } | 768 | } |
769 | 769 | ||
770 | codec->dapm.bias_level = level; | ||
771 | |||
772 | return 0; | 770 | return 0; |
773 | } | 771 | } |
774 | 772 | ||
diff --git a/sound/soc/codecs/wm1250-ev1.c b/sound/soc/codecs/wm1250-ev1.c index 8011f75fb6cb..048f00568260 100644 --- a/sound/soc/codecs/wm1250-ev1.c +++ b/sound/soc/codecs/wm1250-ev1.c | |||
@@ -61,8 +61,6 @@ static int wm1250_ev1_set_bias_level(struct snd_soc_codec *codec, | |||
61 | break; | 61 | break; |
62 | } | 62 | } |
63 | 63 | ||
64 | codec->dapm.bias_level = level; | ||
65 | |||
66 | return 0; | 64 | return 0; |
67 | } | 65 | } |
68 | 66 | ||
diff --git a/sound/soc/codecs/wm5100.c b/sound/soc/codecs/wm5100.c index 96740379b711..4c10cd88c1af 100644 --- a/sound/soc/codecs/wm5100.c +++ b/sound/soc/codecs/wm5100.c | |||
@@ -2101,7 +2101,7 @@ static void wm5100_micd_irq(struct wm5100_priv *wm5100) | |||
2101 | int wm5100_detect(struct snd_soc_codec *codec, struct snd_soc_jack *jack) | 2101 | int wm5100_detect(struct snd_soc_codec *codec, struct snd_soc_jack *jack) |
2102 | { | 2102 | { |
2103 | struct wm5100_priv *wm5100 = snd_soc_codec_get_drvdata(codec); | 2103 | struct wm5100_priv *wm5100 = snd_soc_codec_get_drvdata(codec); |
2104 | struct snd_soc_dapm_context *dapm = &codec->dapm; | 2104 | struct snd_soc_dapm_context *dapm = snd_soc_codec_get_dapm(codec); |
2105 | 2105 | ||
2106 | if (jack) { | 2106 | if (jack) { |
2107 | wm5100->jack = jack; | 2107 | wm5100->jack = jack; |
@@ -2336,6 +2336,7 @@ static void wm5100_free_gpio(struct i2c_client *i2c) | |||
2336 | 2336 | ||
2337 | static int wm5100_probe(struct snd_soc_codec *codec) | 2337 | static int wm5100_probe(struct snd_soc_codec *codec) |
2338 | { | 2338 | { |
2339 | struct snd_soc_dapm_context *dapm = snd_soc_codec_get_dapm(codec); | ||
2339 | struct i2c_client *i2c = to_i2c_client(codec->dev); | 2340 | struct i2c_client *i2c = to_i2c_client(codec->dev); |
2340 | struct wm5100_priv *wm5100 = snd_soc_codec_get_drvdata(codec); | 2341 | struct wm5100_priv *wm5100 = snd_soc_codec_get_drvdata(codec); |
2341 | int ret, i; | 2342 | int ret, i; |
@@ -2353,8 +2354,7 @@ static int wm5100_probe(struct snd_soc_codec *codec) | |||
2353 | /* TODO: check if we're symmetric */ | 2354 | /* TODO: check if we're symmetric */ |
2354 | 2355 | ||
2355 | if (i2c->irq) | 2356 | if (i2c->irq) |
2356 | snd_soc_dapm_new_controls(&codec->dapm, | 2357 | snd_soc_dapm_new_controls(dapm, wm5100_dapm_widgets_noirq, |
2357 | wm5100_dapm_widgets_noirq, | ||
2358 | ARRAY_SIZE(wm5100_dapm_widgets_noirq)); | 2358 | ARRAY_SIZE(wm5100_dapm_widgets_noirq)); |
2359 | 2359 | ||
2360 | if (wm5100->pdata.hp_pol) { | 2360 | if (wm5100->pdata.hp_pol) { |
@@ -2570,11 +2570,13 @@ static int wm5100_i2c_probe(struct i2c_client *i2c, | |||
2570 | 2570 | ||
2571 | if (irq_flags & (IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING)) | 2571 | if (irq_flags & (IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING)) |
2572 | ret = request_threaded_irq(i2c->irq, NULL, | 2572 | ret = request_threaded_irq(i2c->irq, NULL, |
2573 | wm5100_edge_irq, irq_flags, | 2573 | wm5100_edge_irq, |
2574 | irq_flags | IRQF_ONESHOT, | ||
2574 | "wm5100", wm5100); | 2575 | "wm5100", wm5100); |
2575 | else | 2576 | else |
2576 | ret = request_threaded_irq(i2c->irq, NULL, wm5100_irq, | 2577 | ret = request_threaded_irq(i2c->irq, NULL, wm5100_irq, |
2577 | irq_flags, "wm5100", | 2578 | irq_flags | IRQF_ONESHOT, |
2579 | "wm5100", | ||
2578 | wm5100); | 2580 | wm5100); |
2579 | 2581 | ||
2580 | if (ret != 0) { | 2582 | if (ret != 0) { |
diff --git a/sound/soc/codecs/wm5102.c b/sound/soc/codecs/wm5102.c index 0c6d1bc0526e..c5ec519d34be 100644 --- a/sound/soc/codecs/wm5102.c +++ b/sound/soc/codecs/wm5102.c | |||
@@ -42,7 +42,7 @@ struct wm5102_priv { | |||
42 | static DECLARE_TLV_DB_SCALE(ana_tlv, 0, 100, 0); | 42 | static DECLARE_TLV_DB_SCALE(ana_tlv, 0, 100, 0); |
43 | static DECLARE_TLV_DB_SCALE(eq_tlv, -1200, 100, 0); | 43 | static DECLARE_TLV_DB_SCALE(eq_tlv, -1200, 100, 0); |
44 | static DECLARE_TLV_DB_SCALE(digital_tlv, -6400, 50, 0); | 44 | static DECLARE_TLV_DB_SCALE(digital_tlv, -6400, 50, 0); |
45 | static DECLARE_TLV_DB_SCALE(noise_tlv, 0, 600, 0); | 45 | static DECLARE_TLV_DB_SCALE(noise_tlv, -13200, 600, 0); |
46 | static DECLARE_TLV_DB_SCALE(ng_tlv, -10200, 600, 0); | 46 | static DECLARE_TLV_DB_SCALE(ng_tlv, -10200, 600, 0); |
47 | 47 | ||
48 | static const struct wm_adsp_region wm5102_dsp1_regions[] = { | 48 | static const struct wm_adsp_region wm5102_dsp1_regions[] = { |
@@ -605,12 +605,56 @@ static int wm5102_sysclk_ev(struct snd_soc_dapm_widget *w, | |||
605 | regmap_write_async(regmap, patch[i].reg, | 605 | regmap_write_async(regmap, patch[i].reg, |
606 | patch[i].def); | 606 | patch[i].def); |
607 | break; | 607 | break; |
608 | case SND_SOC_DAPM_PRE_PMD: | ||
609 | break; | ||
610 | default: | ||
611 | return 0; | ||
612 | } | ||
613 | |||
614 | return arizona_dvfs_sysclk_ev(w, kcontrol, event); | ||
615 | } | ||
616 | |||
617 | static int wm5102_adsp_power_ev(struct snd_soc_dapm_widget *w, | ||
618 | struct snd_kcontrol *kcontrol, int event) | ||
619 | { | ||
620 | struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm); | ||
621 | struct arizona *arizona = dev_get_drvdata(codec->dev->parent); | ||
622 | unsigned int v; | ||
623 | int ret; | ||
624 | |||
625 | switch (event) { | ||
626 | case SND_SOC_DAPM_PRE_PMU: | ||
627 | ret = regmap_read(arizona->regmap, ARIZONA_SYSTEM_CLOCK_1, &v); | ||
628 | if (ret != 0) { | ||
629 | dev_err(codec->dev, | ||
630 | "Failed to read SYSCLK state: %d\n", ret); | ||
631 | return -EIO; | ||
632 | } | ||
633 | |||
634 | v = (v & ARIZONA_SYSCLK_FREQ_MASK) >> ARIZONA_SYSCLK_FREQ_SHIFT; | ||
635 | |||
636 | if (v >= 3) { | ||
637 | ret = arizona_dvfs_up(codec, ARIZONA_DVFS_ADSP1_RQ); | ||
638 | if (ret) { | ||
639 | dev_err(codec->dev, | ||
640 | "Failed to raise DVFS: %d\n", ret); | ||
641 | return ret; | ||
642 | } | ||
643 | } | ||
644 | break; | ||
645 | |||
646 | case SND_SOC_DAPM_POST_PMD: | ||
647 | ret = arizona_dvfs_down(codec, ARIZONA_DVFS_ADSP1_RQ); | ||
648 | if (ret) | ||
649 | dev_warn(codec->dev, | ||
650 | "Failed to lower DVFS: %d\n", ret); | ||
651 | break; | ||
608 | 652 | ||
609 | default: | 653 | default: |
610 | break; | 654 | break; |
611 | } | 655 | } |
612 | 656 | ||
613 | return 0; | 657 | return wm_adsp2_early_event(w, kcontrol, event); |
614 | } | 658 | } |
615 | 659 | ||
616 | static int wm5102_out_comp_coeff_get(struct snd_kcontrol *kcontrol, | 660 | static int wm5102_out_comp_coeff_get(struct snd_kcontrol *kcontrol, |
@@ -1036,7 +1080,8 @@ static const struct snd_kcontrol_new wm5102_aec_loopback_mux = | |||
1036 | 1080 | ||
1037 | static const struct snd_soc_dapm_widget wm5102_dapm_widgets[] = { | 1081 | static const struct snd_soc_dapm_widget wm5102_dapm_widgets[] = { |
1038 | SND_SOC_DAPM_SUPPLY("SYSCLK", ARIZONA_SYSTEM_CLOCK_1, ARIZONA_SYSCLK_ENA_SHIFT, | 1082 | SND_SOC_DAPM_SUPPLY("SYSCLK", ARIZONA_SYSTEM_CLOCK_1, ARIZONA_SYSCLK_ENA_SHIFT, |
1039 | 0, wm5102_sysclk_ev, SND_SOC_DAPM_POST_PMU), | 1083 | 0, wm5102_sysclk_ev, |
1084 | SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD), | ||
1040 | SND_SOC_DAPM_SUPPLY("ASYNCCLK", ARIZONA_ASYNC_CLOCK_1, | 1085 | SND_SOC_DAPM_SUPPLY("ASYNCCLK", ARIZONA_ASYNC_CLOCK_1, |
1041 | ARIZONA_ASYNC_CLK_ENA_SHIFT, 0, NULL, 0), | 1086 | ARIZONA_ASYNC_CLK_ENA_SHIFT, 0, NULL, 0), |
1042 | SND_SOC_DAPM_SUPPLY("OPCLK", ARIZONA_OUTPUT_SYSTEM_CLOCK, | 1087 | SND_SOC_DAPM_SUPPLY("OPCLK", ARIZONA_OUTPUT_SYSTEM_CLOCK, |
@@ -1367,7 +1412,7 @@ ARIZONA_MUX_WIDGETS(ISRC2DEC2, "ISRC2DEC2"), | |||
1367 | ARIZONA_MUX_WIDGETS(ISRC2INT1, "ISRC2INT1"), | 1412 | ARIZONA_MUX_WIDGETS(ISRC2INT1, "ISRC2INT1"), |
1368 | ARIZONA_MUX_WIDGETS(ISRC2INT2, "ISRC2INT2"), | 1413 | ARIZONA_MUX_WIDGETS(ISRC2INT2, "ISRC2INT2"), |
1369 | 1414 | ||
1370 | WM_ADSP2("DSP1", 0), | 1415 | WM_ADSP2_E("DSP1", 0, wm5102_adsp_power_ev), |
1371 | 1416 | ||
1372 | SND_SOC_DAPM_OUTPUT("HPOUT1L"), | 1417 | SND_SOC_DAPM_OUTPUT("HPOUT1L"), |
1373 | SND_SOC_DAPM_OUTPUT("HPOUT1R"), | 1418 | SND_SOC_DAPM_OUTPUT("HPOUT1R"), |
@@ -1827,19 +1872,20 @@ static struct snd_soc_dai_driver wm5102_dai[] = { | |||
1827 | 1872 | ||
1828 | static int wm5102_codec_probe(struct snd_soc_codec *codec) | 1873 | static int wm5102_codec_probe(struct snd_soc_codec *codec) |
1829 | { | 1874 | { |
1875 | struct snd_soc_dapm_context *dapm = snd_soc_codec_get_dapm(codec); | ||
1830 | struct wm5102_priv *priv = snd_soc_codec_get_drvdata(codec); | 1876 | struct wm5102_priv *priv = snd_soc_codec_get_drvdata(codec); |
1831 | int ret; | 1877 | int ret; |
1832 | 1878 | ||
1833 | ret = snd_soc_add_codec_controls(codec, wm_adsp2_fw_controls, 2); | 1879 | ret = wm_adsp2_codec_probe(&priv->core.adsp[0], codec); |
1834 | if (ret != 0) | 1880 | if (ret) |
1835 | return ret; | 1881 | return ret; |
1836 | 1882 | ||
1837 | arizona_init_spk(codec); | 1883 | arizona_init_spk(codec); |
1838 | arizona_init_gpio(codec); | 1884 | arizona_init_gpio(codec); |
1839 | 1885 | ||
1840 | snd_soc_dapm_disable_pin(&codec->dapm, "HAPTICS"); | 1886 | snd_soc_dapm_disable_pin(dapm, "HAPTICS"); |
1841 | 1887 | ||
1842 | priv->core.arizona->dapm = &codec->dapm; | 1888 | priv->core.arizona->dapm = dapm; |
1843 | 1889 | ||
1844 | return 0; | 1890 | return 0; |
1845 | } | 1891 | } |
@@ -1848,6 +1894,8 @@ static int wm5102_codec_remove(struct snd_soc_codec *codec) | |||
1848 | { | 1894 | { |
1849 | struct wm5102_priv *priv = snd_soc_codec_get_drvdata(codec); | 1895 | struct wm5102_priv *priv = snd_soc_codec_get_drvdata(codec); |
1850 | 1896 | ||
1897 | wm_adsp2_codec_remove(&priv->core.adsp[0], codec); | ||
1898 | |||
1851 | priv->core.arizona->dapm = NULL; | 1899 | priv->core.arizona->dapm = NULL; |
1852 | 1900 | ||
1853 | return 0; | 1901 | return 0; |
@@ -1909,6 +1957,8 @@ static int wm5102_probe(struct platform_device *pdev) | |||
1909 | wm5102->core.arizona = arizona; | 1957 | wm5102->core.arizona = arizona; |
1910 | wm5102->core.num_inputs = 6; | 1958 | wm5102->core.num_inputs = 6; |
1911 | 1959 | ||
1960 | arizona_init_dvfs(&wm5102->core); | ||
1961 | |||
1912 | wm5102->core.adsp[0].part = "wm5102"; | 1962 | wm5102->core.adsp[0].part = "wm5102"; |
1913 | wm5102->core.adsp[0].num = 1; | 1963 | wm5102->core.adsp[0].num = 1; |
1914 | wm5102->core.adsp[0].type = WMFW_ADSP2; | 1964 | wm5102->core.adsp[0].type = WMFW_ADSP2; |
@@ -1918,7 +1968,7 @@ static int wm5102_probe(struct platform_device *pdev) | |||
1918 | wm5102->core.adsp[0].mem = wm5102_dsp1_regions; | 1968 | wm5102->core.adsp[0].mem = wm5102_dsp1_regions; |
1919 | wm5102->core.adsp[0].num_mems = ARRAY_SIZE(wm5102_dsp1_regions); | 1969 | wm5102->core.adsp[0].num_mems = ARRAY_SIZE(wm5102_dsp1_regions); |
1920 | 1970 | ||
1921 | ret = wm_adsp2_init(&wm5102->core.adsp[0], true); | 1971 | ret = wm_adsp2_init(&wm5102->core.adsp[0]); |
1922 | if (ret != 0) | 1972 | if (ret != 0) |
1923 | return ret; | 1973 | return ret; |
1924 | 1974 | ||
diff --git a/sound/soc/codecs/wm5110.c b/sound/soc/codecs/wm5110.c index fbaeddb3e903..5f032a37b61f 100644 --- a/sound/soc/codecs/wm5110.c +++ b/sound/soc/codecs/wm5110.c | |||
@@ -167,7 +167,7 @@ static int wm5110_sysclk_ev(struct snd_soc_dapm_widget *w, | |||
167 | static DECLARE_TLV_DB_SCALE(ana_tlv, 0, 100, 0); | 167 | static DECLARE_TLV_DB_SCALE(ana_tlv, 0, 100, 0); |
168 | static DECLARE_TLV_DB_SCALE(eq_tlv, -1200, 100, 0); | 168 | static DECLARE_TLV_DB_SCALE(eq_tlv, -1200, 100, 0); |
169 | static DECLARE_TLV_DB_SCALE(digital_tlv, -6400, 50, 0); | 169 | static DECLARE_TLV_DB_SCALE(digital_tlv, -6400, 50, 0); |
170 | static DECLARE_TLV_DB_SCALE(noise_tlv, 0, 600, 0); | 170 | static DECLARE_TLV_DB_SCALE(noise_tlv, -13200, 600, 0); |
171 | static DECLARE_TLV_DB_SCALE(ng_tlv, -10200, 600, 0); | 171 | static DECLARE_TLV_DB_SCALE(ng_tlv, -10200, 600, 0); |
172 | 172 | ||
173 | #define WM5110_NG_SRC(name, base) \ | 173 | #define WM5110_NG_SRC(name, base) \ |
@@ -1598,22 +1598,23 @@ static struct snd_soc_dai_driver wm5110_dai[] = { | |||
1598 | 1598 | ||
1599 | static int wm5110_codec_probe(struct snd_soc_codec *codec) | 1599 | static int wm5110_codec_probe(struct snd_soc_codec *codec) |
1600 | { | 1600 | { |
1601 | struct snd_soc_dapm_context *dapm = snd_soc_codec_get_dapm(codec); | ||
1601 | struct wm5110_priv *priv = snd_soc_codec_get_drvdata(codec); | 1602 | struct wm5110_priv *priv = snd_soc_codec_get_drvdata(codec); |
1602 | int ret; | 1603 | int i, ret; |
1603 | 1604 | ||
1604 | priv->core.arizona->dapm = &codec->dapm; | 1605 | priv->core.arizona->dapm = dapm; |
1605 | 1606 | ||
1606 | arizona_init_spk(codec); | 1607 | arizona_init_spk(codec); |
1607 | arizona_init_gpio(codec); | 1608 | arizona_init_gpio(codec); |
1608 | arizona_init_mono(codec); | 1609 | arizona_init_mono(codec); |
1609 | 1610 | ||
1610 | ret = snd_soc_add_codec_controls(codec, wm_adsp2_fw_controls, 8); | 1611 | for (i = 0; i < WM5110_NUM_ADSP; ++i) { |
1611 | if (ret != 0) | 1612 | ret = wm_adsp2_codec_probe(&priv->core.adsp[i], codec); |
1612 | return ret; | 1613 | if (ret) |
1613 | 1614 | return ret; | |
1614 | snd_soc_dapm_disable_pin(&codec->dapm, "HAPTICS"); | 1615 | } |
1615 | 1616 | ||
1616 | priv->core.arizona->dapm = &codec->dapm; | 1617 | snd_soc_dapm_disable_pin(dapm, "HAPTICS"); |
1617 | 1618 | ||
1618 | return 0; | 1619 | return 0; |
1619 | } | 1620 | } |
@@ -1621,6 +1622,10 @@ static int wm5110_codec_probe(struct snd_soc_codec *codec) | |||
1621 | static int wm5110_codec_remove(struct snd_soc_codec *codec) | 1622 | static int wm5110_codec_remove(struct snd_soc_codec *codec) |
1622 | { | 1623 | { |
1623 | struct wm5110_priv *priv = snd_soc_codec_get_drvdata(codec); | 1624 | struct wm5110_priv *priv = snd_soc_codec_get_drvdata(codec); |
1625 | int i; | ||
1626 | |||
1627 | for (i = 0; i < WM5110_NUM_ADSP; ++i) | ||
1628 | wm_adsp2_codec_remove(&priv->core.adsp[i], codec); | ||
1624 | 1629 | ||
1625 | priv->core.arizona->dapm = NULL; | 1630 | priv->core.arizona->dapm = NULL; |
1626 | 1631 | ||
@@ -1697,7 +1702,7 @@ static int wm5110_probe(struct platform_device *pdev) | |||
1697 | wm5110->core.adsp[i].num_mems | 1702 | wm5110->core.adsp[i].num_mems |
1698 | = ARRAY_SIZE(wm5110_dsp1_regions); | 1703 | = ARRAY_SIZE(wm5110_dsp1_regions); |
1699 | 1704 | ||
1700 | ret = wm_adsp2_init(&wm5110->core.adsp[i], false); | 1705 | ret = wm_adsp2_init(&wm5110->core.adsp[i]); |
1701 | if (ret != 0) | 1706 | if (ret != 0) |
1702 | return ret; | 1707 | return ret; |
1703 | } | 1708 | } |
diff --git a/sound/soc/codecs/wm8350.c b/sound/soc/codecs/wm8350.c index c65e5a75fc1a..41c62c1e62db 100644 --- a/sound/soc/codecs/wm8350.c +++ b/sound/soc/codecs/wm8350.c | |||
@@ -1102,7 +1102,7 @@ static int wm8350_set_bias_level(struct snd_soc_codec *codec, | |||
1102 | break; | 1102 | break; |
1103 | 1103 | ||
1104 | case SND_SOC_BIAS_STANDBY: | 1104 | case SND_SOC_BIAS_STANDBY: |
1105 | if (codec->dapm.bias_level == SND_SOC_BIAS_OFF) { | 1105 | if (snd_soc_codec_get_bias_level(codec) == SND_SOC_BIAS_OFF) { |
1106 | ret = regulator_bulk_enable(ARRAY_SIZE(priv->supplies), | 1106 | ret = regulator_bulk_enable(ARRAY_SIZE(priv->supplies), |
1107 | priv->supplies); | 1107 | priv->supplies); |
1108 | if (ret != 0) | 1108 | if (ret != 0) |
@@ -1235,7 +1235,6 @@ static int wm8350_set_bias_level(struct snd_soc_codec *codec, | |||
1235 | priv->supplies); | 1235 | priv->supplies); |
1236 | break; | 1236 | break; |
1237 | } | 1237 | } |
1238 | codec->dapm.bias_level = level; | ||
1239 | return 0; | 1238 | return 0; |
1240 | } | 1239 | } |
1241 | 1240 | ||
diff --git a/sound/soc/codecs/wm8400.c b/sound/soc/codecs/wm8400.c index b0d84e552fca..d7555085e7f4 100644 --- a/sound/soc/codecs/wm8400.c +++ b/sound/soc/codecs/wm8400.c | |||
@@ -1145,7 +1145,7 @@ static int wm8400_set_bias_level(struct snd_soc_codec *codec, | |||
1145 | break; | 1145 | break; |
1146 | 1146 | ||
1147 | case SND_SOC_BIAS_STANDBY: | 1147 | case SND_SOC_BIAS_STANDBY: |
1148 | if (codec->dapm.bias_level == SND_SOC_BIAS_OFF) { | 1148 | if (snd_soc_codec_get_bias_level(codec) == SND_SOC_BIAS_OFF) { |
1149 | ret = regulator_bulk_enable(ARRAY_SIZE(power), | 1149 | ret = regulator_bulk_enable(ARRAY_SIZE(power), |
1150 | &power[0]); | 1150 | &power[0]); |
1151 | if (ret != 0) { | 1151 | if (ret != 0) { |
@@ -1232,7 +1232,6 @@ static int wm8400_set_bias_level(struct snd_soc_codec *codec, | |||
1232 | break; | 1232 | break; |
1233 | } | 1233 | } |
1234 | 1234 | ||
1235 | codec->dapm.bias_level = level; | ||
1236 | return 0; | 1235 | return 0; |
1237 | } | 1236 | } |
1238 | 1237 | ||
diff --git a/sound/soc/codecs/wm8510.c b/sound/soc/codecs/wm8510.c index 8736ad094b24..dac5beb4d023 100644 --- a/sound/soc/codecs/wm8510.c +++ b/sound/soc/codecs/wm8510.c | |||
@@ -519,7 +519,7 @@ static int wm8510_set_bias_level(struct snd_soc_codec *codec, | |||
519 | case SND_SOC_BIAS_STANDBY: | 519 | case SND_SOC_BIAS_STANDBY: |
520 | power1 |= WM8510_POWER1_BIASEN | WM8510_POWER1_BUFIOEN; | 520 | power1 |= WM8510_POWER1_BIASEN | WM8510_POWER1_BUFIOEN; |
521 | 521 | ||
522 | if (codec->dapm.bias_level == SND_SOC_BIAS_OFF) { | 522 | if (snd_soc_codec_get_bias_level(codec) == SND_SOC_BIAS_OFF) { |
523 | regcache_sync(wm8510->regmap); | 523 | regcache_sync(wm8510->regmap); |
524 | 524 | ||
525 | /* Initial cap charge at VMID 5k */ | 525 | /* Initial cap charge at VMID 5k */ |
@@ -538,7 +538,6 @@ static int wm8510_set_bias_level(struct snd_soc_codec *codec, | |||
538 | break; | 538 | break; |
539 | } | 539 | } |
540 | 540 | ||
541 | codec->dapm.bias_level = level; | ||
542 | return 0; | 541 | return 0; |
543 | } | 542 | } |
544 | 543 | ||
diff --git a/sound/soc/codecs/wm8523.c b/sound/soc/codecs/wm8523.c index b1cc94f5fc4b..8c5b9df3e542 100644 --- a/sound/soc/codecs/wm8523.c +++ b/sound/soc/codecs/wm8523.c | |||
@@ -308,7 +308,7 @@ static int wm8523_set_bias_level(struct snd_soc_codec *codec, | |||
308 | break; | 308 | break; |
309 | 309 | ||
310 | case SND_SOC_BIAS_STANDBY: | 310 | case SND_SOC_BIAS_STANDBY: |
311 | if (codec->dapm.bias_level == SND_SOC_BIAS_OFF) { | 311 | if (snd_soc_codec_get_bias_level(codec) == SND_SOC_BIAS_OFF) { |
312 | ret = regulator_bulk_enable(ARRAY_SIZE(wm8523->supplies), | 312 | ret = regulator_bulk_enable(ARRAY_SIZE(wm8523->supplies), |
313 | wm8523->supplies); | 313 | wm8523->supplies); |
314 | if (ret != 0) { | 314 | if (ret != 0) { |
@@ -344,7 +344,6 @@ static int wm8523_set_bias_level(struct snd_soc_codec *codec, | |||
344 | wm8523->supplies); | 344 | wm8523->supplies); |
345 | break; | 345 | break; |
346 | } | 346 | } |
347 | codec->dapm.bias_level = level; | ||
348 | return 0; | 347 | return 0; |
349 | } | 348 | } |
350 | 349 | ||
diff --git a/sound/soc/codecs/wm8580.c b/sound/soc/codecs/wm8580.c index 0a887c5ec83a..759a7928ac3e 100644 --- a/sound/soc/codecs/wm8580.c +++ b/sound/soc/codecs/wm8580.c | |||
@@ -795,7 +795,7 @@ static int wm8580_set_bias_level(struct snd_soc_codec *codec, | |||
795 | break; | 795 | break; |
796 | 796 | ||
797 | case SND_SOC_BIAS_STANDBY: | 797 | case SND_SOC_BIAS_STANDBY: |
798 | if (codec->dapm.bias_level == SND_SOC_BIAS_OFF) { | 798 | if (snd_soc_codec_get_bias_level(codec) == SND_SOC_BIAS_OFF) { |
799 | /* Power up and get individual control of the DACs */ | 799 | /* Power up and get individual control of the DACs */ |
800 | snd_soc_update_bits(codec, WM8580_PWRDN1, | 800 | snd_soc_update_bits(codec, WM8580_PWRDN1, |
801 | WM8580_PWRDN1_PWDN | | 801 | WM8580_PWRDN1_PWDN | |
@@ -812,7 +812,6 @@ static int wm8580_set_bias_level(struct snd_soc_codec *codec, | |||
812 | WM8580_PWRDN1_PWDN, WM8580_PWRDN1_PWDN); | 812 | WM8580_PWRDN1_PWDN, WM8580_PWRDN1_PWDN); |
813 | break; | 813 | break; |
814 | } | 814 | } |
815 | codec->dapm.bias_level = level; | ||
816 | return 0; | 815 | return 0; |
817 | } | 816 | } |
818 | 817 | ||
diff --git a/sound/soc/codecs/wm8711.c b/sound/soc/codecs/wm8711.c index 121e46d53779..cc8251f09f8a 100644 --- a/sound/soc/codecs/wm8711.c +++ b/sound/soc/codecs/wm8711.c | |||
@@ -310,7 +310,7 @@ static int wm8711_set_bias_level(struct snd_soc_codec *codec, | |||
310 | case SND_SOC_BIAS_PREPARE: | 310 | case SND_SOC_BIAS_PREPARE: |
311 | break; | 311 | break; |
312 | case SND_SOC_BIAS_STANDBY: | 312 | case SND_SOC_BIAS_STANDBY: |
313 | if (codec->dapm.bias_level == SND_SOC_BIAS_OFF) | 313 | if (snd_soc_codec_get_bias_level(codec) == SND_SOC_BIAS_OFF) |
314 | regcache_sync(wm8711->regmap); | 314 | regcache_sync(wm8711->regmap); |
315 | 315 | ||
316 | snd_soc_write(codec, WM8711_PWR, reg | 0x0040); | 316 | snd_soc_write(codec, WM8711_PWR, reg | 0x0040); |
@@ -320,7 +320,6 @@ static int wm8711_set_bias_level(struct snd_soc_codec *codec, | |||
320 | snd_soc_write(codec, WM8711_PWR, 0xffff); | 320 | snd_soc_write(codec, WM8711_PWR, 0xffff); |
321 | break; | 321 | break; |
322 | } | 322 | } |
323 | codec->dapm.bias_level = level; | ||
324 | return 0; | 323 | return 0; |
325 | } | 324 | } |
326 | 325 | ||
diff --git a/sound/soc/codecs/wm8728.c b/sound/soc/codecs/wm8728.c index 55c7fb4fc786..f1a173e6ec33 100644 --- a/sound/soc/codecs/wm8728.c +++ b/sound/soc/codecs/wm8728.c | |||
@@ -170,7 +170,7 @@ static int wm8728_set_bias_level(struct snd_soc_codec *codec, | |||
170 | case SND_SOC_BIAS_ON: | 170 | case SND_SOC_BIAS_ON: |
171 | case SND_SOC_BIAS_PREPARE: | 171 | case SND_SOC_BIAS_PREPARE: |
172 | case SND_SOC_BIAS_STANDBY: | 172 | case SND_SOC_BIAS_STANDBY: |
173 | if (codec->dapm.bias_level == SND_SOC_BIAS_OFF) { | 173 | if (snd_soc_codec_get_bias_level(codec) == SND_SOC_BIAS_OFF) { |
174 | /* Power everything up... */ | 174 | /* Power everything up... */ |
175 | reg = snd_soc_read(codec, WM8728_DACCTL); | 175 | reg = snd_soc_read(codec, WM8728_DACCTL); |
176 | snd_soc_write(codec, WM8728_DACCTL, reg & ~0x4); | 176 | snd_soc_write(codec, WM8728_DACCTL, reg & ~0x4); |
@@ -185,7 +185,6 @@ static int wm8728_set_bias_level(struct snd_soc_codec *codec, | |||
185 | snd_soc_write(codec, WM8728_DACCTL, reg | 0x4); | 185 | snd_soc_write(codec, WM8728_DACCTL, reg | 0x4); |
186 | break; | 186 | break; |
187 | } | 187 | } |
188 | codec->dapm.bias_level = level; | ||
189 | return 0; | 188 | return 0; |
190 | } | 189 | } |
191 | 190 | ||
diff --git a/sound/soc/codecs/wm8731.c b/sound/soc/codecs/wm8731.c index 2245b6a32f3d..915ea11ad4b6 100644 --- a/sound/soc/codecs/wm8731.c +++ b/sound/soc/codecs/wm8731.c | |||
@@ -387,6 +387,7 @@ static int wm8731_set_dai_sysclk(struct snd_soc_dai *codec_dai, | |||
387 | int clk_id, unsigned int freq, int dir) | 387 | int clk_id, unsigned int freq, int dir) |
388 | { | 388 | { |
389 | struct snd_soc_codec *codec = codec_dai->codec; | 389 | struct snd_soc_codec *codec = codec_dai->codec; |
390 | struct snd_soc_dapm_context *dapm = snd_soc_codec_get_dapm(codec); | ||
390 | struct wm8731_priv *wm8731 = snd_soc_codec_get_drvdata(codec); | 391 | struct wm8731_priv *wm8731 = snd_soc_codec_get_drvdata(codec); |
391 | 392 | ||
392 | switch (clk_id) { | 393 | switch (clk_id) { |
@@ -421,7 +422,7 @@ static int wm8731_set_dai_sysclk(struct snd_soc_dai *codec_dai, | |||
421 | 422 | ||
422 | wm8731->sysclk = freq; | 423 | wm8731->sysclk = freq; |
423 | 424 | ||
424 | snd_soc_dapm_sync(&codec->dapm); | 425 | snd_soc_dapm_sync(dapm); |
425 | 426 | ||
426 | return 0; | 427 | return 0; |
427 | } | 428 | } |
@@ -501,7 +502,7 @@ static int wm8731_set_bias_level(struct snd_soc_codec *codec, | |||
501 | case SND_SOC_BIAS_PREPARE: | 502 | case SND_SOC_BIAS_PREPARE: |
502 | break; | 503 | break; |
503 | case SND_SOC_BIAS_STANDBY: | 504 | case SND_SOC_BIAS_STANDBY: |
504 | if (codec->dapm.bias_level == SND_SOC_BIAS_OFF) { | 505 | if (snd_soc_codec_get_bias_level(codec) == SND_SOC_BIAS_OFF) { |
505 | ret = regulator_bulk_enable(ARRAY_SIZE(wm8731->supplies), | 506 | ret = regulator_bulk_enable(ARRAY_SIZE(wm8731->supplies), |
506 | wm8731->supplies); | 507 | wm8731->supplies); |
507 | if (ret != 0) | 508 | if (ret != 0) |
@@ -523,7 +524,6 @@ static int wm8731_set_bias_level(struct snd_soc_codec *codec, | |||
523 | regcache_mark_dirty(wm8731->regmap); | 524 | regcache_mark_dirty(wm8731->regmap); |
524 | break; | 525 | break; |
525 | } | 526 | } |
526 | codec->dapm.bias_level = level; | ||
527 | return 0; | 527 | return 0; |
528 | } | 528 | } |
529 | 529 | ||
@@ -599,7 +599,7 @@ static int wm8731_probe(struct snd_soc_codec *codec) | |||
599 | goto err_regulator_enable; | 599 | goto err_regulator_enable; |
600 | } | 600 | } |
601 | 601 | ||
602 | wm8731_set_bias_level(codec, SND_SOC_BIAS_STANDBY); | 602 | snd_soc_codec_force_bias_level(codec, SND_SOC_BIAS_STANDBY); |
603 | 603 | ||
604 | /* Latch the update bits */ | 604 | /* Latch the update bits */ |
605 | snd_soc_update_bits(codec, WM8731_LOUT1V, 0x100, 0); | 605 | snd_soc_update_bits(codec, WM8731_LOUT1V, 0x100, 0); |
diff --git a/sound/soc/codecs/wm8737.c b/sound/soc/codecs/wm8737.c index ada9ac1ba2c6..6ad606fd8b69 100644 --- a/sound/soc/codecs/wm8737.c +++ b/sound/soc/codecs/wm8737.c | |||
@@ -469,7 +469,7 @@ static int wm8737_set_bias_level(struct snd_soc_codec *codec, | |||
469 | break; | 469 | break; |
470 | 470 | ||
471 | case SND_SOC_BIAS_STANDBY: | 471 | case SND_SOC_BIAS_STANDBY: |
472 | if (codec->dapm.bias_level == SND_SOC_BIAS_OFF) { | 472 | if (snd_soc_codec_get_bias_level(codec) == SND_SOC_BIAS_OFF) { |
473 | ret = regulator_bulk_enable(ARRAY_SIZE(wm8737->supplies), | 473 | ret = regulator_bulk_enable(ARRAY_SIZE(wm8737->supplies), |
474 | wm8737->supplies); | 474 | wm8737->supplies); |
475 | if (ret != 0) { | 475 | if (ret != 0) { |
@@ -483,7 +483,8 @@ static int wm8737_set_bias_level(struct snd_soc_codec *codec, | |||
483 | 483 | ||
484 | /* Fast VMID ramp at 2*2.5k */ | 484 | /* Fast VMID ramp at 2*2.5k */ |
485 | snd_soc_update_bits(codec, WM8737_MISC_BIAS_CONTROL, | 485 | snd_soc_update_bits(codec, WM8737_MISC_BIAS_CONTROL, |
486 | WM8737_VMIDSEL_MASK, 0x4); | 486 | WM8737_VMIDSEL_MASK, |
487 | 2 << WM8737_VMIDSEL_SHIFT); | ||
487 | 488 | ||
488 | /* Bring VMID up */ | 489 | /* Bring VMID up */ |
489 | snd_soc_update_bits(codec, WM8737_POWER_MANAGEMENT, | 490 | snd_soc_update_bits(codec, WM8737_POWER_MANAGEMENT, |
@@ -497,7 +498,8 @@ static int wm8737_set_bias_level(struct snd_soc_codec *codec, | |||
497 | 498 | ||
498 | /* VMID at 2*300k */ | 499 | /* VMID at 2*300k */ |
499 | snd_soc_update_bits(codec, WM8737_MISC_BIAS_CONTROL, | 500 | snd_soc_update_bits(codec, WM8737_MISC_BIAS_CONTROL, |
500 | WM8737_VMIDSEL_MASK, 2); | 501 | WM8737_VMIDSEL_MASK, |
502 | 1 << WM8737_VMIDSEL_SHIFT); | ||
501 | 503 | ||
502 | break; | 504 | break; |
503 | 505 | ||
@@ -510,7 +512,6 @@ static int wm8737_set_bias_level(struct snd_soc_codec *codec, | |||
510 | break; | 512 | break; |
511 | } | 513 | } |
512 | 514 | ||
513 | codec->dapm.bias_level = level; | ||
514 | return 0; | 515 | return 0; |
515 | } | 516 | } |
516 | 517 | ||
@@ -560,7 +561,7 @@ static int wm8737_probe(struct snd_soc_codec *codec) | |||
560 | snd_soc_update_bits(codec, WM8737_RIGHT_PGA_VOLUME, WM8737_RVU, | 561 | snd_soc_update_bits(codec, WM8737_RIGHT_PGA_VOLUME, WM8737_RVU, |
561 | WM8737_RVU); | 562 | WM8737_RVU); |
562 | 563 | ||
563 | wm8737_set_bias_level(codec, SND_SOC_BIAS_STANDBY); | 564 | snd_soc_codec_force_bias_level(codec, SND_SOC_BIAS_STANDBY); |
564 | 565 | ||
565 | /* Bias level configuration will have done an extra enable */ | 566 | /* Bias level configuration will have done an extra enable */ |
566 | regulator_bulk_disable(ARRAY_SIZE(wm8737->supplies), wm8737->supplies); | 567 | regulator_bulk_disable(ARRAY_SIZE(wm8737->supplies), wm8737->supplies); |
diff --git a/sound/soc/codecs/wm8741.c b/sound/soc/codecs/wm8741.c index 9e71c768966f..09ff01f2fc1e 100644 --- a/sound/soc/codecs/wm8741.c +++ b/sound/soc/codecs/wm8741.c | |||
@@ -41,6 +41,7 @@ static const char *wm8741_supply_names[WM8741_NUM_SUPPLIES] = { | |||
41 | 41 | ||
42 | /* codec private data */ | 42 | /* codec private data */ |
43 | struct wm8741_priv { | 43 | struct wm8741_priv { |
44 | struct wm8741_platform_data pdata; | ||
44 | struct regmap *regmap; | 45 | struct regmap *regmap; |
45 | struct regulator_bulk_data supplies[WM8741_NUM_SUPPLIES]; | 46 | struct regulator_bulk_data supplies[WM8741_NUM_SUPPLIES]; |
46 | unsigned int sysclk; | 47 | unsigned int sysclk; |
@@ -87,13 +88,27 @@ static int wm8741_reset(struct snd_soc_codec *codec) | |||
87 | static const DECLARE_TLV_DB_SCALE(dac_tlv_fine, -12700, 13, 0); | 88 | static const DECLARE_TLV_DB_SCALE(dac_tlv_fine, -12700, 13, 0); |
88 | static const DECLARE_TLV_DB_SCALE(dac_tlv, -12700, 400, 0); | 89 | static const DECLARE_TLV_DB_SCALE(dac_tlv, -12700, 400, 0); |
89 | 90 | ||
90 | static const struct snd_kcontrol_new wm8741_snd_controls[] = { | 91 | static const struct snd_kcontrol_new wm8741_snd_controls_stereo[] = { |
91 | SOC_DOUBLE_R_TLV("Fine Playback Volume", WM8741_DACLLSB_ATTENUATION, | 92 | SOC_DOUBLE_R_TLV("Fine Playback Volume", WM8741_DACLLSB_ATTENUATION, |
92 | WM8741_DACRLSB_ATTENUATION, 1, 255, 1, dac_tlv_fine), | 93 | WM8741_DACRLSB_ATTENUATION, 1, 255, 1, dac_tlv_fine), |
93 | SOC_DOUBLE_R_TLV("Playback Volume", WM8741_DACLMSB_ATTENUATION, | 94 | SOC_DOUBLE_R_TLV("Playback Volume", WM8741_DACLMSB_ATTENUATION, |
94 | WM8741_DACRMSB_ATTENUATION, 0, 511, 1, dac_tlv), | 95 | WM8741_DACRMSB_ATTENUATION, 0, 511, 1, dac_tlv), |
95 | }; | 96 | }; |
96 | 97 | ||
98 | static const struct snd_kcontrol_new wm8741_snd_controls_mono_left[] = { | ||
99 | SOC_SINGLE_TLV("Fine Playback Volume", WM8741_DACLLSB_ATTENUATION, | ||
100 | 1, 255, 1, dac_tlv_fine), | ||
101 | SOC_SINGLE_TLV("Playback Volume", WM8741_DACLMSB_ATTENUATION, | ||
102 | 0, 511, 1, dac_tlv), | ||
103 | }; | ||
104 | |||
105 | static const struct snd_kcontrol_new wm8741_snd_controls_mono_right[] = { | ||
106 | SOC_SINGLE_TLV("Fine Playback Volume", WM8741_DACRLSB_ATTENUATION, | ||
107 | 1, 255, 1, dac_tlv_fine), | ||
108 | SOC_SINGLE_TLV("Playback Volume", WM8741_DACRMSB_ATTENUATION, | ||
109 | 0, 511, 1, dac_tlv), | ||
110 | }; | ||
111 | |||
97 | static const struct snd_soc_dapm_widget wm8741_dapm_widgets[] = { | 112 | static const struct snd_soc_dapm_widget wm8741_dapm_widgets[] = { |
98 | SND_SOC_DAPM_DAC("DACL", "Playback", SND_SOC_NOPM, 0, 0), | 113 | SND_SOC_DAPM_DAC("DACL", "Playback", SND_SOC_NOPM, 0, 0), |
99 | SND_SOC_DAPM_DAC("DACR", "Playback", SND_SOC_NOPM, 0, 0), | 114 | SND_SOC_DAPM_DAC("DACR", "Playback", SND_SOC_NOPM, 0, 0), |
@@ -398,7 +413,7 @@ static struct snd_soc_dai_driver wm8741_dai = { | |||
398 | .name = "wm8741", | 413 | .name = "wm8741", |
399 | .playback = { | 414 | .playback = { |
400 | .stream_name = "Playback", | 415 | .stream_name = "Playback", |
401 | .channels_min = 2, /* Mono modes not yet supported */ | 416 | .channels_min = 2, |
402 | .channels_max = 2, | 417 | .channels_max = 2, |
403 | .rates = WM8741_RATES, | 418 | .rates = WM8741_RATES, |
404 | .formats = WM8741_FORMATS, | 419 | .formats = WM8741_FORMATS, |
@@ -416,6 +431,65 @@ static int wm8741_resume(struct snd_soc_codec *codec) | |||
416 | #define wm8741_resume NULL | 431 | #define wm8741_resume NULL |
417 | #endif | 432 | #endif |
418 | 433 | ||
434 | static int wm8741_configure(struct snd_soc_codec *codec) | ||
435 | { | ||
436 | struct wm8741_priv *wm8741 = snd_soc_codec_get_drvdata(codec); | ||
437 | |||
438 | /* Configure differential mode */ | ||
439 | switch (wm8741->pdata.diff_mode) { | ||
440 | case WM8741_DIFF_MODE_STEREO: | ||
441 | case WM8741_DIFF_MODE_STEREO_REVERSED: | ||
442 | case WM8741_DIFF_MODE_MONO_LEFT: | ||
443 | case WM8741_DIFF_MODE_MONO_RIGHT: | ||
444 | snd_soc_update_bits(codec, WM8741_MODE_CONTROL_2, | ||
445 | WM8741_DIFF_MASK, | ||
446 | wm8741->pdata.diff_mode << WM8741_DIFF_SHIFT); | ||
447 | break; | ||
448 | default: | ||
449 | return -EINVAL; | ||
450 | } | ||
451 | |||
452 | /* Change some default settings - latch VU */ | ||
453 | snd_soc_update_bits(codec, WM8741_DACLLSB_ATTENUATION, | ||
454 | WM8741_UPDATELL, WM8741_UPDATELL); | ||
455 | snd_soc_update_bits(codec, WM8741_DACLMSB_ATTENUATION, | ||
456 | WM8741_UPDATELM, WM8741_UPDATELM); | ||
457 | snd_soc_update_bits(codec, WM8741_DACRLSB_ATTENUATION, | ||
458 | WM8741_UPDATERL, WM8741_UPDATERL); | ||
459 | snd_soc_update_bits(codec, WM8741_DACRMSB_ATTENUATION, | ||
460 | WM8741_UPDATERM, WM8741_UPDATERM); | ||
461 | |||
462 | return 0; | ||
463 | } | ||
464 | |||
465 | static int wm8741_add_controls(struct snd_soc_codec *codec) | ||
466 | { | ||
467 | struct wm8741_priv *wm8741 = snd_soc_codec_get_drvdata(codec); | ||
468 | |||
469 | switch (wm8741->pdata.diff_mode) { | ||
470 | case WM8741_DIFF_MODE_STEREO: | ||
471 | case WM8741_DIFF_MODE_STEREO_REVERSED: | ||
472 | snd_soc_add_codec_controls(codec, | ||
473 | wm8741_snd_controls_stereo, | ||
474 | ARRAY_SIZE(wm8741_snd_controls_stereo)); | ||
475 | break; | ||
476 | case WM8741_DIFF_MODE_MONO_LEFT: | ||
477 | snd_soc_add_codec_controls(codec, | ||
478 | wm8741_snd_controls_mono_left, | ||
479 | ARRAY_SIZE(wm8741_snd_controls_mono_left)); | ||
480 | break; | ||
481 | case WM8741_DIFF_MODE_MONO_RIGHT: | ||
482 | snd_soc_add_codec_controls(codec, | ||
483 | wm8741_snd_controls_mono_right, | ||
484 | ARRAY_SIZE(wm8741_snd_controls_mono_right)); | ||
485 | break; | ||
486 | default: | ||
487 | return -EINVAL; | ||
488 | } | ||
489 | |||
490 | return 0; | ||
491 | } | ||
492 | |||
419 | static int wm8741_probe(struct snd_soc_codec *codec) | 493 | static int wm8741_probe(struct snd_soc_codec *codec) |
420 | { | 494 | { |
421 | struct wm8741_priv *wm8741 = snd_soc_codec_get_drvdata(codec); | 495 | struct wm8741_priv *wm8741 = snd_soc_codec_get_drvdata(codec); |
@@ -434,15 +508,17 @@ static int wm8741_probe(struct snd_soc_codec *codec) | |||
434 | goto err_enable; | 508 | goto err_enable; |
435 | } | 509 | } |
436 | 510 | ||
437 | /* Change some default settings - latch VU */ | 511 | ret = wm8741_configure(codec); |
438 | snd_soc_update_bits(codec, WM8741_DACLLSB_ATTENUATION, | 512 | if (ret < 0) { |
439 | WM8741_UPDATELL, WM8741_UPDATELL); | 513 | dev_err(codec->dev, "Failed to change default settings\n"); |
440 | snd_soc_update_bits(codec, WM8741_DACLMSB_ATTENUATION, | 514 | goto err_enable; |
441 | WM8741_UPDATELM, WM8741_UPDATELM); | 515 | } |
442 | snd_soc_update_bits(codec, WM8741_DACRLSB_ATTENUATION, | 516 | |
443 | WM8741_UPDATERL, WM8741_UPDATERL); | 517 | ret = wm8741_add_controls(codec); |
444 | snd_soc_update_bits(codec, WM8741_DACRMSB_ATTENUATION, | 518 | if (ret < 0) { |
445 | WM8741_UPDATERM, WM8741_UPDATERM); | 519 | dev_err(codec->dev, "Failed to add controls\n"); |
520 | goto err_enable; | ||
521 | } | ||
446 | 522 | ||
447 | dev_dbg(codec->dev, "Successful registration\n"); | 523 | dev_dbg(codec->dev, "Successful registration\n"); |
448 | return ret; | 524 | return ret; |
@@ -467,8 +543,6 @@ static struct snd_soc_codec_driver soc_codec_dev_wm8741 = { | |||
467 | .remove = wm8741_remove, | 543 | .remove = wm8741_remove, |
468 | .resume = wm8741_resume, | 544 | .resume = wm8741_resume, |
469 | 545 | ||
470 | .controls = wm8741_snd_controls, | ||
471 | .num_controls = ARRAY_SIZE(wm8741_snd_controls), | ||
472 | .dapm_widgets = wm8741_dapm_widgets, | 546 | .dapm_widgets = wm8741_dapm_widgets, |
473 | .num_dapm_widgets = ARRAY_SIZE(wm8741_dapm_widgets), | 547 | .num_dapm_widgets = ARRAY_SIZE(wm8741_dapm_widgets), |
474 | .dapm_routes = wm8741_dapm_routes, | 548 | .dapm_routes = wm8741_dapm_routes, |
@@ -493,6 +567,23 @@ static const struct regmap_config wm8741_regmap = { | |||
493 | .readable_reg = wm8741_readable, | 567 | .readable_reg = wm8741_readable, |
494 | }; | 568 | }; |
495 | 569 | ||
570 | static int wm8741_set_pdata(struct device *dev, struct wm8741_priv *wm8741) | ||
571 | { | ||
572 | const struct wm8741_platform_data *pdata = dev_get_platdata(dev); | ||
573 | u32 diff_mode; | ||
574 | |||
575 | if (dev->of_node) { | ||
576 | if (of_property_read_u32(dev->of_node, "diff-mode", &diff_mode) | ||
577 | >= 0) | ||
578 | wm8741->pdata.diff_mode = diff_mode; | ||
579 | } else { | ||
580 | if (pdata != NULL) | ||
581 | memcpy(&wm8741->pdata, pdata, sizeof(wm8741->pdata)); | ||
582 | } | ||
583 | |||
584 | return 0; | ||
585 | } | ||
586 | |||
496 | #if IS_ENABLED(CONFIG_I2C) | 587 | #if IS_ENABLED(CONFIG_I2C) |
497 | static int wm8741_i2c_probe(struct i2c_client *i2c, | 588 | static int wm8741_i2c_probe(struct i2c_client *i2c, |
498 | const struct i2c_device_id *id) | 589 | const struct i2c_device_id *id) |
@@ -522,6 +613,12 @@ static int wm8741_i2c_probe(struct i2c_client *i2c, | |||
522 | return ret; | 613 | return ret; |
523 | } | 614 | } |
524 | 615 | ||
616 | ret = wm8741_set_pdata(&i2c->dev, wm8741); | ||
617 | if (ret != 0) { | ||
618 | dev_err(&i2c->dev, "Failed to set pdata: %d\n", ret); | ||
619 | return ret; | ||
620 | } | ||
621 | |||
525 | i2c_set_clientdata(i2c, wm8741); | 622 | i2c_set_clientdata(i2c, wm8741); |
526 | 623 | ||
527 | ret = snd_soc_register_codec(&i2c->dev, | 624 | ret = snd_soc_register_codec(&i2c->dev, |
@@ -582,6 +679,12 @@ static int wm8741_spi_probe(struct spi_device *spi) | |||
582 | return ret; | 679 | return ret; |
583 | } | 680 | } |
584 | 681 | ||
682 | ret = wm8741_set_pdata(&spi->dev, wm8741); | ||
683 | if (ret != 0) { | ||
684 | dev_err(&spi->dev, "Failed to set pdata: %d\n", ret); | ||
685 | return ret; | ||
686 | } | ||
687 | |||
585 | spi_set_drvdata(spi, wm8741); | 688 | spi_set_drvdata(spi, wm8741); |
586 | 689 | ||
587 | ret = snd_soc_register_codec(&spi->dev, | 690 | ret = snd_soc_register_codec(&spi->dev, |
diff --git a/sound/soc/codecs/wm8741.h b/sound/soc/codecs/wm8741.h index 56c1b1d4a681..c8835f65f342 100644 --- a/sound/soc/codecs/wm8741.h +++ b/sound/soc/codecs/wm8741.h | |||
@@ -194,6 +194,12 @@ | |||
194 | #define WM8741_DITHER_SHIFT 0 /* DITHER - [1:0] */ | 194 | #define WM8741_DITHER_SHIFT 0 /* DITHER - [1:0] */ |
195 | #define WM8741_DITHER_WIDTH 2 /* DITHER - [1:0] */ | 195 | #define WM8741_DITHER_WIDTH 2 /* DITHER - [1:0] */ |
196 | 196 | ||
197 | /* DIFF field values */ | ||
198 | #define WM8741_DIFF_MODE_STEREO 0 /* stereo normal */ | ||
199 | #define WM8741_DIFF_MODE_STEREO_REVERSED 2 /* stereo reversed */ | ||
200 | #define WM8741_DIFF_MODE_MONO_LEFT 1 /* mono left */ | ||
201 | #define WM8741_DIFF_MODE_MONO_RIGHT 3 /* mono right */ | ||
202 | |||
197 | /* | 203 | /* |
198 | * R32 (0x20) - ADDITONAL_CONTROL_1 | 204 | * R32 (0x20) - ADDITONAL_CONTROL_1 |
199 | */ | 205 | */ |
@@ -208,4 +214,8 @@ | |||
208 | 214 | ||
209 | #define WM8741_SYSCLK 0 | 215 | #define WM8741_SYSCLK 0 |
210 | 216 | ||
217 | struct wm8741_platform_data { | ||
218 | u32 diff_mode; /* Differential Output Mode */ | ||
219 | }; | ||
220 | |||
211 | #endif | 221 | #endif |
diff --git a/sound/soc/codecs/wm8750.c b/sound/soc/codecs/wm8750.c index eb0a1644ba11..56d89b0865fa 100644 --- a/sound/soc/codecs/wm8750.c +++ b/sound/soc/codecs/wm8750.c | |||
@@ -634,7 +634,7 @@ static int wm8750_set_bias_level(struct snd_soc_codec *codec, | |||
634 | case SND_SOC_BIAS_PREPARE: | 634 | case SND_SOC_BIAS_PREPARE: |
635 | break; | 635 | break; |
636 | case SND_SOC_BIAS_STANDBY: | 636 | case SND_SOC_BIAS_STANDBY: |
637 | if (codec->dapm.bias_level == SND_SOC_BIAS_OFF) { | 637 | if (snd_soc_codec_get_bias_level(codec) == SND_SOC_BIAS_OFF) { |
638 | snd_soc_cache_sync(codec); | 638 | snd_soc_cache_sync(codec); |
639 | 639 | ||
640 | /* Set VMID to 5k */ | 640 | /* Set VMID to 5k */ |
@@ -651,7 +651,6 @@ static int wm8750_set_bias_level(struct snd_soc_codec *codec, | |||
651 | snd_soc_write(codec, WM8750_PWR1, 0x0001); | 651 | snd_soc_write(codec, WM8750_PWR1, 0x0001); |
652 | break; | 652 | break; |
653 | } | 653 | } |
654 | codec->dapm.bias_level = level; | ||
655 | return 0; | 654 | return 0; |
656 | } | 655 | } |
657 | 656 | ||
diff --git a/sound/soc/codecs/wm8753.c b/sound/soc/codecs/wm8753.c index c50a5959345f..feb2997a377a 100644 --- a/sound/soc/codecs/wm8753.c +++ b/sound/soc/codecs/wm8753.c | |||
@@ -1352,7 +1352,7 @@ static int wm8753_set_bias_level(struct snd_soc_codec *codec, | |||
1352 | flush_delayed_work(&wm8753->charge_work); | 1352 | flush_delayed_work(&wm8753->charge_work); |
1353 | break; | 1353 | break; |
1354 | case SND_SOC_BIAS_STANDBY: | 1354 | case SND_SOC_BIAS_STANDBY: |
1355 | if (codec->dapm.bias_level == SND_SOC_BIAS_OFF) { | 1355 | if (snd_soc_codec_get_bias_level(codec) == SND_SOC_BIAS_OFF) { |
1356 | /* set vmid to 5k for quick power up */ | 1356 | /* set vmid to 5k for quick power up */ |
1357 | snd_soc_write(codec, WM8753_PWR1, pwr_reg | 0x01c1); | 1357 | snd_soc_write(codec, WM8753_PWR1, pwr_reg | 0x01c1); |
1358 | schedule_delayed_work(&wm8753->charge_work, | 1358 | schedule_delayed_work(&wm8753->charge_work, |
@@ -1367,7 +1367,6 @@ static int wm8753_set_bias_level(struct snd_soc_codec *codec, | |||
1367 | snd_soc_write(codec, WM8753_PWR1, 0x0001); | 1367 | snd_soc_write(codec, WM8753_PWR1, 0x0001); |
1368 | break; | 1368 | break; |
1369 | } | 1369 | } |
1370 | codec->dapm.bias_level = level; | ||
1371 | return 0; | 1370 | return 0; |
1372 | } | 1371 | } |
1373 | 1372 | ||
diff --git a/sound/soc/codecs/wm8770.c b/sound/soc/codecs/wm8770.c index 53e977da2f86..66c1f151071d 100644 --- a/sound/soc/codecs/wm8770.c +++ b/sound/soc/codecs/wm8770.c | |||
@@ -510,7 +510,7 @@ static int wm8770_set_bias_level(struct snd_soc_codec *codec, | |||
510 | case SND_SOC_BIAS_PREPARE: | 510 | case SND_SOC_BIAS_PREPARE: |
511 | break; | 511 | break; |
512 | case SND_SOC_BIAS_STANDBY: | 512 | case SND_SOC_BIAS_STANDBY: |
513 | if (codec->dapm.bias_level == SND_SOC_BIAS_OFF) { | 513 | if (snd_soc_codec_get_bias_level(codec) == SND_SOC_BIAS_OFF) { |
514 | ret = regulator_bulk_enable(ARRAY_SIZE(wm8770->supplies), | 514 | ret = regulator_bulk_enable(ARRAY_SIZE(wm8770->supplies), |
515 | wm8770->supplies); | 515 | wm8770->supplies); |
516 | if (ret) { | 516 | if (ret) { |
@@ -534,7 +534,6 @@ static int wm8770_set_bias_level(struct snd_soc_codec *codec, | |||
534 | break; | 534 | break; |
535 | } | 535 | } |
536 | 536 | ||
537 | codec->dapm.bias_level = level; | ||
538 | return 0; | 537 | return 0; |
539 | } | 538 | } |
540 | 539 | ||
diff --git a/sound/soc/codecs/wm8776.c b/sound/soc/codecs/wm8776.c index c13050b77931..ece9b4456767 100644 --- a/sound/soc/codecs/wm8776.c +++ b/sound/soc/codecs/wm8776.c | |||
@@ -344,7 +344,7 @@ static int wm8776_set_bias_level(struct snd_soc_codec *codec, | |||
344 | case SND_SOC_BIAS_PREPARE: | 344 | case SND_SOC_BIAS_PREPARE: |
345 | break; | 345 | break; |
346 | case SND_SOC_BIAS_STANDBY: | 346 | case SND_SOC_BIAS_STANDBY: |
347 | if (codec->dapm.bias_level == SND_SOC_BIAS_OFF) { | 347 | if (snd_soc_codec_get_bias_level(codec) == SND_SOC_BIAS_OFF) { |
348 | regcache_sync(wm8776->regmap); | 348 | regcache_sync(wm8776->regmap); |
349 | 349 | ||
350 | /* Disable the global powerdown; DAPM does the rest */ | 350 | /* Disable the global powerdown; DAPM does the rest */ |
@@ -357,7 +357,6 @@ static int wm8776_set_bias_level(struct snd_soc_codec *codec, | |||
357 | break; | 357 | break; |
358 | } | 358 | } |
359 | 359 | ||
360 | codec->dapm.bias_level = level; | ||
361 | return 0; | 360 | return 0; |
362 | } | 361 | } |
363 | 362 | ||
diff --git a/sound/soc/codecs/wm8804.c b/sound/soc/codecs/wm8804.c index 1e403f67cf16..c195c2e8af07 100644 --- a/sound/soc/codecs/wm8804.c +++ b/sound/soc/codecs/wm8804.c | |||
@@ -162,7 +162,7 @@ static int txsrc_put(struct snd_kcontrol *kcontrol, | |||
162 | struct snd_ctl_elem_value *ucontrol) | 162 | struct snd_ctl_elem_value *ucontrol) |
163 | { | 163 | { |
164 | struct snd_soc_codec *codec = snd_soc_dapm_kcontrol_codec(kcontrol); | 164 | struct snd_soc_codec *codec = snd_soc_dapm_kcontrol_codec(kcontrol); |
165 | struct snd_soc_dapm_context *dapm = &codec->dapm; | 165 | struct snd_soc_dapm_context *dapm = snd_soc_codec_get_dapm(codec); |
166 | struct soc_enum *e = (struct soc_enum *)kcontrol->private_value; | 166 | struct soc_enum *e = (struct soc_enum *)kcontrol->private_value; |
167 | unsigned int val = ucontrol->value.enumerated.item[0] << e->shift_l; | 167 | unsigned int val = ucontrol->value.enumerated.item[0] << e->shift_l; |
168 | unsigned int mask = 1 << e->shift_l; | 168 | unsigned int mask = 1 << e->shift_l; |
diff --git a/sound/soc/codecs/wm8900.c b/sound/soc/codecs/wm8900.c index 2eb986c19b88..f3759ec5a863 100644 --- a/sound/soc/codecs/wm8900.c +++ b/sound/soc/codecs/wm8900.c | |||
@@ -998,8 +998,8 @@ static int wm8900_digital_mute(struct snd_soc_dai *codec_dai, int mute) | |||
998 | SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000) | 998 | SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000) |
999 | 999 | ||
1000 | #define WM8900_PCM_FORMATS \ | 1000 | #define WM8900_PCM_FORMATS \ |
1001 | (SNDRV_PCM_FORMAT_S16_LE | SNDRV_PCM_FORMAT_S20_3LE | \ | 1001 | (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE | \ |
1002 | SNDRV_PCM_FORMAT_S24_LE) | 1002 | SNDRV_PCM_FMTBIT_S24_LE) |
1003 | 1003 | ||
1004 | static const struct snd_soc_dai_ops wm8900_dai_ops = { | 1004 | static const struct snd_soc_dai_ops wm8900_dai_ops = { |
1005 | .hw_params = wm8900_hw_params, | 1005 | .hw_params = wm8900_hw_params, |
@@ -1049,7 +1049,7 @@ static int wm8900_set_bias_level(struct snd_soc_codec *codec, | |||
1049 | 1049 | ||
1050 | case SND_SOC_BIAS_STANDBY: | 1050 | case SND_SOC_BIAS_STANDBY: |
1051 | /* Charge capacitors if initial power up */ | 1051 | /* Charge capacitors if initial power up */ |
1052 | if (codec->dapm.bias_level == SND_SOC_BIAS_OFF) { | 1052 | if (snd_soc_codec_get_bias_level(codec) == SND_SOC_BIAS_OFF) { |
1053 | /* STARTUP_BIAS_ENA on */ | 1053 | /* STARTUP_BIAS_ENA on */ |
1054 | snd_soc_write(codec, WM8900_REG_POWER1, | 1054 | snd_soc_write(codec, WM8900_REG_POWER1, |
1055 | WM8900_REG_POWER1_STARTUP_BIAS_ENA); | 1055 | WM8900_REG_POWER1_STARTUP_BIAS_ENA); |
@@ -1117,7 +1117,6 @@ static int wm8900_set_bias_level(struct snd_soc_codec *codec, | |||
1117 | WM8900_REG_POWER2_SYSCLK_ENA); | 1117 | WM8900_REG_POWER2_SYSCLK_ENA); |
1118 | break; | 1118 | break; |
1119 | } | 1119 | } |
1120 | codec->dapm.bias_level = level; | ||
1121 | return 0; | 1120 | return 0; |
1122 | } | 1121 | } |
1123 | 1122 | ||
@@ -1138,7 +1137,7 @@ static int wm8900_suspend(struct snd_soc_codec *codec) | |||
1138 | wm8900->fll_out = fll_out; | 1137 | wm8900->fll_out = fll_out; |
1139 | wm8900->fll_in = fll_in; | 1138 | wm8900->fll_in = fll_in; |
1140 | 1139 | ||
1141 | wm8900_set_bias_level(codec, SND_SOC_BIAS_OFF); | 1140 | snd_soc_codec_force_bias_level(codec, SND_SOC_BIAS_OFF); |
1142 | 1141 | ||
1143 | return 0; | 1142 | return 0; |
1144 | } | 1143 | } |
@@ -1156,7 +1155,7 @@ static int wm8900_resume(struct snd_soc_codec *codec) | |||
1156 | return ret; | 1155 | return ret; |
1157 | } | 1156 | } |
1158 | 1157 | ||
1159 | wm8900_set_bias_level(codec, SND_SOC_BIAS_STANDBY); | 1158 | snd_soc_codec_force_bias_level(codec, SND_SOC_BIAS_STANDBY); |
1160 | 1159 | ||
1161 | /* Restart the FLL? */ | 1160 | /* Restart the FLL? */ |
1162 | if (wm8900->fll_out) { | 1161 | if (wm8900->fll_out) { |
@@ -1189,7 +1188,7 @@ static int wm8900_probe(struct snd_soc_codec *codec) | |||
1189 | wm8900_reset(codec); | 1188 | wm8900_reset(codec); |
1190 | 1189 | ||
1191 | /* Turn the chip on */ | 1190 | /* Turn the chip on */ |
1192 | wm8900_set_bias_level(codec, SND_SOC_BIAS_STANDBY); | 1191 | snd_soc_codec_force_bias_level(codec, SND_SOC_BIAS_STANDBY); |
1193 | 1192 | ||
1194 | /* Latch the volume update bits */ | 1193 | /* Latch the volume update bits */ |
1195 | snd_soc_update_bits(codec, WM8900_REG_LINVOL, 0x100, 0x100); | 1194 | snd_soc_update_bits(codec, WM8900_REG_LINVOL, 0x100, 0x100); |
diff --git a/sound/soc/codecs/wm8903.c b/sound/soc/codecs/wm8903.c index 04b04f8e147c..b5322c1544fb 100644 --- a/sound/soc/codecs/wm8903.c +++ b/sound/soc/codecs/wm8903.c | |||
@@ -1105,7 +1105,7 @@ static int wm8903_set_bias_level(struct snd_soc_codec *codec, | |||
1105 | break; | 1105 | break; |
1106 | 1106 | ||
1107 | case SND_SOC_BIAS_STANDBY: | 1107 | case SND_SOC_BIAS_STANDBY: |
1108 | if (codec->dapm.bias_level == SND_SOC_BIAS_OFF) { | 1108 | if (snd_soc_codec_get_bias_level(codec) == SND_SOC_BIAS_OFF) { |
1109 | snd_soc_update_bits(codec, WM8903_BIAS_CONTROL_0, | 1109 | snd_soc_update_bits(codec, WM8903_BIAS_CONTROL_0, |
1110 | WM8903_POBCTRL | WM8903_ISEL_MASK | | 1110 | WM8903_POBCTRL | WM8903_ISEL_MASK | |
1111 | WM8903_STARTUP_BIAS_ENA | | 1111 | WM8903_STARTUP_BIAS_ENA | |
@@ -1200,8 +1200,6 @@ static int wm8903_set_bias_level(struct snd_soc_codec *codec, | |||
1200 | break; | 1200 | break; |
1201 | } | 1201 | } |
1202 | 1202 | ||
1203 | codec->dapm.bias_level = level; | ||
1204 | |||
1205 | return 0; | 1203 | return 0; |
1206 | } | 1204 | } |
1207 | 1205 | ||
diff --git a/sound/soc/codecs/wm8903.h b/sound/soc/codecs/wm8903.h index db949311c0f2..0bb4a647755d 100644 --- a/sound/soc/codecs/wm8903.h +++ b/sound/soc/codecs/wm8903.h | |||
@@ -172,7 +172,7 @@ extern int wm8903_mic_detect(struct snd_soc_codec *codec, | |||
172 | #define WM8903_VMID_BUF_ENA_WIDTH 1 /* VMID_BUF_ENA */ | 172 | #define WM8903_VMID_BUF_ENA_WIDTH 1 /* VMID_BUF_ENA */ |
173 | 173 | ||
174 | #define WM8903_VMID_RES_50K 2 | 174 | #define WM8903_VMID_RES_50K 2 |
175 | #define WM8903_VMID_RES_250K 3 | 175 | #define WM8903_VMID_RES_250K 4 |
176 | #define WM8903_VMID_RES_5K 6 | 176 | #define WM8903_VMID_RES_5K 6 |
177 | 177 | ||
178 | /* | 178 | /* |
diff --git a/sound/soc/codecs/wm8904.c b/sound/soc/codecs/wm8904.c index 215e93c1ddf0..265a4a58a2d1 100644 --- a/sound/soc/codecs/wm8904.c +++ b/sound/soc/codecs/wm8904.c | |||
@@ -1168,7 +1168,7 @@ static const struct snd_soc_dapm_route wm8912_intercon[] = { | |||
1168 | static int wm8904_add_widgets(struct snd_soc_codec *codec) | 1168 | static int wm8904_add_widgets(struct snd_soc_codec *codec) |
1169 | { | 1169 | { |
1170 | struct wm8904_priv *wm8904 = snd_soc_codec_get_drvdata(codec); | 1170 | struct wm8904_priv *wm8904 = snd_soc_codec_get_drvdata(codec); |
1171 | struct snd_soc_dapm_context *dapm = &codec->dapm; | 1171 | struct snd_soc_dapm_context *dapm = snd_soc_codec_get_dapm(codec); |
1172 | 1172 | ||
1173 | snd_soc_dapm_new_controls(dapm, wm8904_core_dapm_widgets, | 1173 | snd_soc_dapm_new_controls(dapm, wm8904_core_dapm_widgets, |
1174 | ARRAY_SIZE(wm8904_core_dapm_widgets)); | 1174 | ARRAY_SIZE(wm8904_core_dapm_widgets)); |
@@ -1852,7 +1852,7 @@ static int wm8904_set_bias_level(struct snd_soc_codec *codec, | |||
1852 | break; | 1852 | break; |
1853 | 1853 | ||
1854 | case SND_SOC_BIAS_STANDBY: | 1854 | case SND_SOC_BIAS_STANDBY: |
1855 | if (codec->dapm.bias_level == SND_SOC_BIAS_OFF) { | 1855 | if (snd_soc_codec_get_bias_level(codec) == SND_SOC_BIAS_OFF) { |
1856 | ret = regulator_bulk_enable(ARRAY_SIZE(wm8904->supplies), | 1856 | ret = regulator_bulk_enable(ARRAY_SIZE(wm8904->supplies), |
1857 | wm8904->supplies); | 1857 | wm8904->supplies); |
1858 | if (ret != 0) { | 1858 | if (ret != 0) { |
@@ -1907,7 +1907,6 @@ static int wm8904_set_bias_level(struct snd_soc_codec *codec, | |||
1907 | clk_disable_unprepare(wm8904->mclk); | 1907 | clk_disable_unprepare(wm8904->mclk); |
1908 | break; | 1908 | break; |
1909 | } | 1909 | } |
1910 | codec->dapm.bias_level = level; | ||
1911 | return 0; | 1910 | return 0; |
1912 | } | 1911 | } |
1913 | 1912 | ||
diff --git a/sound/soc/codecs/wm8940.c b/sound/soc/codecs/wm8940.c index e4142b4309eb..98ef0ba5c2a4 100644 --- a/sound/soc/codecs/wm8940.c +++ b/sound/soc/codecs/wm8940.c | |||
@@ -492,7 +492,7 @@ static int wm8940_set_bias_level(struct snd_soc_codec *codec, | |||
492 | ret = snd_soc_write(codec, WM8940_POWER1, pwr_reg | 0x1); | 492 | ret = snd_soc_write(codec, WM8940_POWER1, pwr_reg | 0x1); |
493 | break; | 493 | break; |
494 | case SND_SOC_BIAS_STANDBY: | 494 | case SND_SOC_BIAS_STANDBY: |
495 | if (codec->dapm.bias_level == SND_SOC_BIAS_OFF) { | 495 | if (snd_soc_codec_get_bias_level(codec) == SND_SOC_BIAS_OFF) { |
496 | ret = regcache_sync(wm8940->regmap); | 496 | ret = regcache_sync(wm8940->regmap); |
497 | if (ret < 0) { | 497 | if (ret < 0) { |
498 | dev_err(codec->dev, "Failed to sync cache: %d\n", ret); | 498 | dev_err(codec->dev, "Failed to sync cache: %d\n", ret); |
@@ -510,8 +510,6 @@ static int wm8940_set_bias_level(struct snd_soc_codec *codec, | |||
510 | break; | 510 | break; |
511 | } | 511 | } |
512 | 512 | ||
513 | codec->dapm.bias_level = level; | ||
514 | |||
515 | return ret; | 513 | return ret; |
516 | } | 514 | } |
517 | 515 | ||
@@ -707,7 +705,7 @@ static int wm8940_probe(struct snd_soc_codec *codec) | |||
707 | return ret; | 705 | return ret; |
708 | } | 706 | } |
709 | 707 | ||
710 | wm8940_set_bias_level(codec, SND_SOC_BIAS_STANDBY); | 708 | snd_soc_codec_force_bias_level(codec, SND_SOC_BIAS_STANDBY); |
711 | 709 | ||
712 | ret = snd_soc_write(codec, WM8940_POWER1, 0x180); | 710 | ret = snd_soc_write(codec, WM8940_POWER1, 0x180); |
713 | if (ret < 0) | 711 | if (ret < 0) |
diff --git a/sound/soc/codecs/wm8955.c b/sound/soc/codecs/wm8955.c index 00bec915d652..2d591c24704b 100644 --- a/sound/soc/codecs/wm8955.c +++ b/sound/soc/codecs/wm8955.c | |||
@@ -298,7 +298,7 @@ static int wm8955_configure_clocking(struct snd_soc_codec *codec) | |||
298 | snd_soc_update_bits(codec, WM8955_PLL_CONTROL_2, | 298 | snd_soc_update_bits(codec, WM8955_PLL_CONTROL_2, |
299 | WM8955_K_17_9_MASK, | 299 | WM8955_K_17_9_MASK, |
300 | (pll.k >> 9) & WM8955_K_17_9_MASK); | 300 | (pll.k >> 9) & WM8955_K_17_9_MASK); |
301 | snd_soc_update_bits(codec, WM8955_PLL_CONTROL_2, | 301 | snd_soc_update_bits(codec, WM8955_PLL_CONTROL_3, |
302 | WM8955_K_8_0_MASK, | 302 | WM8955_K_8_0_MASK, |
303 | pll.k & WM8955_K_8_0_MASK); | 303 | pll.k & WM8955_K_8_0_MASK); |
304 | if (pll.k) | 304 | if (pll.k) |
@@ -785,7 +785,7 @@ static int wm8955_set_bias_level(struct snd_soc_codec *codec, | |||
785 | break; | 785 | break; |
786 | 786 | ||
787 | case SND_SOC_BIAS_STANDBY: | 787 | case SND_SOC_BIAS_STANDBY: |
788 | if (codec->dapm.bias_level == SND_SOC_BIAS_OFF) { | 788 | if (snd_soc_codec_get_bias_level(codec) == SND_SOC_BIAS_OFF) { |
789 | ret = regulator_bulk_enable(ARRAY_SIZE(wm8955->supplies), | 789 | ret = regulator_bulk_enable(ARRAY_SIZE(wm8955->supplies), |
790 | wm8955->supplies); | 790 | wm8955->supplies); |
791 | if (ret != 0) { | 791 | if (ret != 0) { |
@@ -838,7 +838,6 @@ static int wm8955_set_bias_level(struct snd_soc_codec *codec, | |||
838 | wm8955->supplies); | 838 | wm8955->supplies); |
839 | break; | 839 | break; |
840 | } | 840 | } |
841 | codec->dapm.bias_level = level; | ||
842 | return 0; | 841 | return 0; |
843 | } | 842 | } |
844 | 843 | ||
@@ -929,7 +928,7 @@ static int wm8955_probe(struct snd_soc_codec *codec) | |||
929 | WM8955_DMEN, WM8955_DMEN); | 928 | WM8955_DMEN, WM8955_DMEN); |
930 | } | 929 | } |
931 | 930 | ||
932 | wm8955_set_bias_level(codec, SND_SOC_BIAS_STANDBY); | 931 | snd_soc_codec_force_bias_level(codec, SND_SOC_BIAS_STANDBY); |
933 | 932 | ||
934 | /* Bias level configuration will have done an extra enable */ | 933 | /* Bias level configuration will have done an extra enable */ |
935 | regulator_bulk_disable(ARRAY_SIZE(wm8955->supplies), wm8955->supplies); | 934 | regulator_bulk_disable(ARRAY_SIZE(wm8955->supplies), wm8955->supplies); |
diff --git a/sound/soc/codecs/wm8960.c b/sound/soc/codecs/wm8960.c index 3035d9856415..94c5c4681ce5 100644 --- a/sound/soc/codecs/wm8960.c +++ b/sound/soc/codecs/wm8960.c | |||
@@ -127,6 +127,8 @@ struct wm8960_priv { | |||
127 | struct snd_soc_dapm_widget *out3; | 127 | struct snd_soc_dapm_widget *out3; |
128 | bool deemph; | 128 | bool deemph; |
129 | int playback_fs; | 129 | int playback_fs; |
130 | int bclk; | ||
131 | int sysclk; | ||
130 | struct wm8960_data pdata; | 132 | struct wm8960_data pdata; |
131 | }; | 133 | }; |
132 | 134 | ||
@@ -245,7 +247,7 @@ SOC_SINGLE("PCM Playback -6dB Switch", WM8960_DACCTL1, 7, 1, 0), | |||
245 | SOC_ENUM("ADC Polarity", wm8960_enum[0]), | 247 | SOC_ENUM("ADC Polarity", wm8960_enum[0]), |
246 | SOC_SINGLE("ADC High Pass Filter Switch", WM8960_DACCTL1, 0, 1, 0), | 248 | SOC_SINGLE("ADC High Pass Filter Switch", WM8960_DACCTL1, 0, 1, 0), |
247 | 249 | ||
248 | SOC_ENUM("DAC Polarity", wm8960_enum[2]), | 250 | SOC_ENUM("DAC Polarity", wm8960_enum[1]), |
249 | SOC_SINGLE_BOOL_EXT("DAC Deemphasis Switch", 0, | 251 | SOC_SINGLE_BOOL_EXT("DAC Deemphasis Switch", 0, |
250 | wm8960_get_deemph, wm8960_put_deemph), | 252 | wm8960_get_deemph, wm8960_put_deemph), |
251 | 253 | ||
@@ -395,7 +397,7 @@ static const struct snd_soc_dapm_route audio_paths[] = { | |||
395 | { "Right Input Mixer", "Boost Switch", "Right Boost Mixer", }, | 397 | { "Right Input Mixer", "Boost Switch", "Right Boost Mixer", }, |
396 | { "Right Input Mixer", NULL, "RINPUT1", }, /* Really Boost Switch */ | 398 | { "Right Input Mixer", NULL, "RINPUT1", }, /* Really Boost Switch */ |
397 | { "Right Input Mixer", NULL, "RINPUT2" }, | 399 | { "Right Input Mixer", NULL, "RINPUT2" }, |
398 | { "Right Input Mixer", NULL, "LINPUT3" }, | 400 | { "Right Input Mixer", NULL, "RINPUT3" }, |
399 | 401 | ||
400 | { "Left ADC", NULL, "Left Input Mixer" }, | 402 | { "Left ADC", NULL, "Left Input Mixer" }, |
401 | { "Right ADC", NULL, "Right Input Mixer" }, | 403 | { "Right ADC", NULL, "Right Input Mixer" }, |
@@ -445,7 +447,7 @@ static int wm8960_add_widgets(struct snd_soc_codec *codec) | |||
445 | { | 447 | { |
446 | struct wm8960_priv *wm8960 = snd_soc_codec_get_drvdata(codec); | 448 | struct wm8960_priv *wm8960 = snd_soc_codec_get_drvdata(codec); |
447 | struct wm8960_data *pdata = &wm8960->pdata; | 449 | struct wm8960_data *pdata = &wm8960->pdata; |
448 | struct snd_soc_dapm_context *dapm = &codec->dapm; | 450 | struct snd_soc_dapm_context *dapm = snd_soc_codec_get_dapm(codec); |
449 | struct snd_soc_dapm_widget *w; | 451 | struct snd_soc_dapm_widget *w; |
450 | 452 | ||
451 | snd_soc_dapm_new_controls(dapm, wm8960_dapm_widgets, | 453 | snd_soc_dapm_new_controls(dapm, wm8960_dapm_widgets, |
@@ -476,7 +478,7 @@ static int wm8960_add_widgets(struct snd_soc_codec *codec) | |||
476 | * and save the result. | 478 | * and save the result. |
477 | */ | 479 | */ |
478 | list_for_each_entry(w, &codec->component.card->widgets, list) { | 480 | list_for_each_entry(w, &codec->component.card->widgets, list) { |
479 | if (w->dapm != &codec->dapm) | 481 | if (w->dapm != dapm) |
480 | continue; | 482 | continue; |
481 | if (strcmp(w->name, "LOUT1 PGA") == 0) | 483 | if (strcmp(w->name, "LOUT1 PGA") == 0) |
482 | wm8960->lout1 = w; | 484 | wm8960->lout1 = w; |
@@ -563,6 +565,72 @@ static struct { | |||
563 | { 8000, 5 }, | 565 | { 8000, 5 }, |
564 | }; | 566 | }; |
565 | 567 | ||
568 | /* Multiply 256 for internal 256 div */ | ||
569 | static const int dac_divs[] = { 256, 384, 512, 768, 1024, 1408, 1536 }; | ||
570 | |||
571 | /* Multiply 10 to eliminate decimials */ | ||
572 | static const int bclk_divs[] = { | ||
573 | 10, 15, 20, 30, 40, 55, 60, 80, 110, | ||
574 | 120, 160, 220, 240, 320, 320, 320 | ||
575 | }; | ||
576 | |||
577 | static void wm8960_configure_clocking(struct snd_soc_codec *codec, | ||
578 | bool tx, int lrclk) | ||
579 | { | ||
580 | struct wm8960_priv *wm8960 = snd_soc_codec_get_drvdata(codec); | ||
581 | u16 iface1 = snd_soc_read(codec, WM8960_IFACE1); | ||
582 | u16 iface2 = snd_soc_read(codec, WM8960_IFACE2); | ||
583 | u32 sysclk; | ||
584 | int i, j; | ||
585 | |||
586 | if (!(iface1 & (1<<6))) { | ||
587 | dev_dbg(codec->dev, | ||
588 | "Codec is slave mode, no need to configure clock\n"); | ||
589 | return; | ||
590 | } | ||
591 | |||
592 | if (!wm8960->sysclk) { | ||
593 | dev_dbg(codec->dev, "No SYSCLK configured\n"); | ||
594 | return; | ||
595 | } | ||
596 | |||
597 | if (!wm8960->bclk || !lrclk) { | ||
598 | dev_dbg(codec->dev, "No audio clocks configured\n"); | ||
599 | return; | ||
600 | } | ||
601 | |||
602 | for (i = 0; i < ARRAY_SIZE(dac_divs); ++i) { | ||
603 | if (wm8960->sysclk == lrclk * dac_divs[i]) { | ||
604 | for (j = 0; j < ARRAY_SIZE(bclk_divs); ++j) { | ||
605 | sysclk = wm8960->bclk * bclk_divs[j] / 10; | ||
606 | if (wm8960->sysclk == sysclk) | ||
607 | break; | ||
608 | } | ||
609 | if(j != ARRAY_SIZE(bclk_divs)) | ||
610 | break; | ||
611 | } | ||
612 | } | ||
613 | |||
614 | if (i == ARRAY_SIZE(dac_divs)) { | ||
615 | dev_err(codec->dev, "Unsupported sysclk %d\n", wm8960->sysclk); | ||
616 | return; | ||
617 | } | ||
618 | |||
619 | /* | ||
620 | * configure frame clock. If ADCLRC configure as GPIO pin, DACLRC | ||
621 | * pin is used as a frame clock for ADCs and DACs. | ||
622 | */ | ||
623 | if (iface2 & (1<<6)) | ||
624 | snd_soc_update_bits(codec, WM8960_CLOCK1, 0x7 << 3, i << 3); | ||
625 | else if (tx) | ||
626 | snd_soc_update_bits(codec, WM8960_CLOCK1, 0x7 << 3, i << 3); | ||
627 | else if (!tx) | ||
628 | snd_soc_update_bits(codec, WM8960_CLOCK1, 0x7 << 6, i << 6); | ||
629 | |||
630 | /* configure bit clock */ | ||
631 | snd_soc_update_bits(codec, WM8960_CLOCK2, 0xf, j); | ||
632 | } | ||
633 | |||
566 | static int wm8960_hw_params(struct snd_pcm_substream *substream, | 634 | static int wm8960_hw_params(struct snd_pcm_substream *substream, |
567 | struct snd_pcm_hw_params *params, | 635 | struct snd_pcm_hw_params *params, |
568 | struct snd_soc_dai *dai) | 636 | struct snd_soc_dai *dai) |
@@ -570,8 +638,13 @@ static int wm8960_hw_params(struct snd_pcm_substream *substream, | |||
570 | struct snd_soc_codec *codec = dai->codec; | 638 | struct snd_soc_codec *codec = dai->codec; |
571 | struct wm8960_priv *wm8960 = snd_soc_codec_get_drvdata(codec); | 639 | struct wm8960_priv *wm8960 = snd_soc_codec_get_drvdata(codec); |
572 | u16 iface = snd_soc_read(codec, WM8960_IFACE1) & 0xfff3; | 640 | u16 iface = snd_soc_read(codec, WM8960_IFACE1) & 0xfff3; |
641 | bool tx = substream->stream == SNDRV_PCM_STREAM_PLAYBACK; | ||
573 | int i; | 642 | int i; |
574 | 643 | ||
644 | wm8960->bclk = snd_soc_params_to_bclk(params); | ||
645 | if (params_channels(params) == 1) | ||
646 | wm8960->bclk *= 2; | ||
647 | |||
575 | /* bit size */ | 648 | /* bit size */ |
576 | switch (params_width(params)) { | 649 | switch (params_width(params)) { |
577 | case 16: | 650 | case 16: |
@@ -582,6 +655,12 @@ static int wm8960_hw_params(struct snd_pcm_substream *substream, | |||
582 | case 24: | 655 | case 24: |
583 | iface |= 0x0008; | 656 | iface |= 0x0008; |
584 | break; | 657 | break; |
658 | case 32: | ||
659 | /* right justify mode does not support 32 word length */ | ||
660 | if ((iface & 0x3) != 0) { | ||
661 | iface |= 0x000c; | ||
662 | break; | ||
663 | } | ||
585 | default: | 664 | default: |
586 | dev_err(codec->dev, "unsupported width %d\n", | 665 | dev_err(codec->dev, "unsupported width %d\n", |
587 | params_width(params)); | 666 | params_width(params)); |
@@ -602,6 +681,9 @@ static int wm8960_hw_params(struct snd_pcm_substream *substream, | |||
602 | 681 | ||
603 | /* set iface */ | 682 | /* set iface */ |
604 | snd_soc_write(codec, WM8960_IFACE1, iface); | 683 | snd_soc_write(codec, WM8960_IFACE1, iface); |
684 | |||
685 | wm8960_configure_clocking(codec, tx, params_rate(params)); | ||
686 | |||
605 | return 0; | 687 | return 0; |
606 | } | 688 | } |
607 | 689 | ||
@@ -627,7 +709,7 @@ static int wm8960_set_bias_level_out3(struct snd_soc_codec *codec, | |||
627 | break; | 709 | break; |
628 | 710 | ||
629 | case SND_SOC_BIAS_PREPARE: | 711 | case SND_SOC_BIAS_PREPARE: |
630 | switch (codec->dapm.bias_level) { | 712 | switch (snd_soc_codec_get_bias_level(codec)) { |
631 | case SND_SOC_BIAS_STANDBY: | 713 | case SND_SOC_BIAS_STANDBY: |
632 | if (!IS_ERR(wm8960->mclk)) { | 714 | if (!IS_ERR(wm8960->mclk)) { |
633 | ret = clk_prepare_enable(wm8960->mclk); | 715 | ret = clk_prepare_enable(wm8960->mclk); |
@@ -655,7 +737,7 @@ static int wm8960_set_bias_level_out3(struct snd_soc_codec *codec, | |||
655 | break; | 737 | break; |
656 | 738 | ||
657 | case SND_SOC_BIAS_STANDBY: | 739 | case SND_SOC_BIAS_STANDBY: |
658 | if (codec->dapm.bias_level == SND_SOC_BIAS_OFF) { | 740 | if (snd_soc_codec_get_bias_level(codec) == SND_SOC_BIAS_OFF) { |
659 | regcache_sync(wm8960->regmap); | 741 | regcache_sync(wm8960->regmap); |
660 | 742 | ||
661 | /* Enable anti-pop features */ | 743 | /* Enable anti-pop features */ |
@@ -691,8 +773,6 @@ static int wm8960_set_bias_level_out3(struct snd_soc_codec *codec, | |||
691 | break; | 773 | break; |
692 | } | 774 | } |
693 | 775 | ||
694 | codec->dapm.bias_level = level; | ||
695 | |||
696 | return 0; | 776 | return 0; |
697 | } | 777 | } |
698 | 778 | ||
@@ -707,7 +787,7 @@ static int wm8960_set_bias_level_capless(struct snd_soc_codec *codec, | |||
707 | break; | 787 | break; |
708 | 788 | ||
709 | case SND_SOC_BIAS_PREPARE: | 789 | case SND_SOC_BIAS_PREPARE: |
710 | switch (codec->dapm.bias_level) { | 790 | switch (snd_soc_codec_get_bias_level(codec)) { |
711 | case SND_SOC_BIAS_STANDBY: | 791 | case SND_SOC_BIAS_STANDBY: |
712 | /* Enable anti pop mode */ | 792 | /* Enable anti pop mode */ |
713 | snd_soc_update_bits(codec, WM8960_APOP1, | 793 | snd_soc_update_bits(codec, WM8960_APOP1, |
@@ -778,7 +858,7 @@ static int wm8960_set_bias_level_capless(struct snd_soc_codec *codec, | |||
778 | break; | 858 | break; |
779 | 859 | ||
780 | case SND_SOC_BIAS_STANDBY: | 860 | case SND_SOC_BIAS_STANDBY: |
781 | switch (codec->dapm.bias_level) { | 861 | switch (snd_soc_codec_get_bias_level(codec)) { |
782 | case SND_SOC_BIAS_PREPARE: | 862 | case SND_SOC_BIAS_PREPARE: |
783 | /* Disable HP discharge */ | 863 | /* Disable HP discharge */ |
784 | snd_soc_update_bits(codec, WM8960_APOP2, | 864 | snd_soc_update_bits(codec, WM8960_APOP2, |
@@ -802,8 +882,6 @@ static int wm8960_set_bias_level_capless(struct snd_soc_codec *codec, | |||
802 | break; | 882 | break; |
803 | } | 883 | } |
804 | 884 | ||
805 | codec->dapm.bias_level = level; | ||
806 | |||
807 | return 0; | 885 | return 0; |
808 | } | 886 | } |
809 | 887 | ||
@@ -950,11 +1028,35 @@ static int wm8960_set_bias_level(struct snd_soc_codec *codec, | |||
950 | return wm8960->set_bias_level(codec, level); | 1028 | return wm8960->set_bias_level(codec, level); |
951 | } | 1029 | } |
952 | 1030 | ||
1031 | static int wm8960_set_dai_sysclk(struct snd_soc_dai *dai, int clk_id, | ||
1032 | unsigned int freq, int dir) | ||
1033 | { | ||
1034 | struct snd_soc_codec *codec = dai->codec; | ||
1035 | struct wm8960_priv *wm8960 = snd_soc_codec_get_drvdata(codec); | ||
1036 | |||
1037 | switch (clk_id) { | ||
1038 | case WM8960_SYSCLK_MCLK: | ||
1039 | snd_soc_update_bits(codec, WM8960_CLOCK1, | ||
1040 | 0x1, WM8960_SYSCLK_MCLK); | ||
1041 | break; | ||
1042 | case WM8960_SYSCLK_PLL: | ||
1043 | snd_soc_update_bits(codec, WM8960_CLOCK1, | ||
1044 | 0x1, WM8960_SYSCLK_PLL); | ||
1045 | break; | ||
1046 | default: | ||
1047 | return -EINVAL; | ||
1048 | } | ||
1049 | |||
1050 | wm8960->sysclk = freq; | ||
1051 | |||
1052 | return 0; | ||
1053 | } | ||
1054 | |||
953 | #define WM8960_RATES SNDRV_PCM_RATE_8000_48000 | 1055 | #define WM8960_RATES SNDRV_PCM_RATE_8000_48000 |
954 | 1056 | ||
955 | #define WM8960_FORMATS \ | 1057 | #define WM8960_FORMATS \ |
956 | (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE | \ | 1058 | (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE | \ |
957 | SNDRV_PCM_FMTBIT_S24_LE) | 1059 | SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S32_LE) |
958 | 1060 | ||
959 | static const struct snd_soc_dai_ops wm8960_dai_ops = { | 1061 | static const struct snd_soc_dai_ops wm8960_dai_ops = { |
960 | .hw_params = wm8960_hw_params, | 1062 | .hw_params = wm8960_hw_params, |
@@ -962,6 +1064,7 @@ static const struct snd_soc_dai_ops wm8960_dai_ops = { | |||
962 | .set_fmt = wm8960_set_dai_fmt, | 1064 | .set_fmt = wm8960_set_dai_fmt, |
963 | .set_clkdiv = wm8960_set_dai_clkdiv, | 1065 | .set_clkdiv = wm8960_set_dai_clkdiv, |
964 | .set_pll = wm8960_set_dai_pll, | 1066 | .set_pll = wm8960_set_dai_pll, |
1067 | .set_sysclk = wm8960_set_dai_sysclk, | ||
965 | }; | 1068 | }; |
966 | 1069 | ||
967 | static struct snd_soc_dai_driver wm8960_dai = { | 1070 | static struct snd_soc_dai_driver wm8960_dai = { |
diff --git a/sound/soc/codecs/wm8961.c b/sound/soc/codecs/wm8961.c index 95e2c1bfc809..a057662632ff 100644 --- a/sound/soc/codecs/wm8961.c +++ b/sound/soc/codecs/wm8961.c | |||
@@ -758,7 +758,7 @@ static int wm8961_set_bias_level(struct snd_soc_codec *codec, | |||
758 | break; | 758 | break; |
759 | 759 | ||
760 | case SND_SOC_BIAS_PREPARE: | 760 | case SND_SOC_BIAS_PREPARE: |
761 | if (codec->dapm.bias_level == SND_SOC_BIAS_STANDBY) { | 761 | if (snd_soc_codec_get_bias_level(codec) == SND_SOC_BIAS_STANDBY) { |
762 | /* Enable bias generation */ | 762 | /* Enable bias generation */ |
763 | reg = snd_soc_read(codec, WM8961_ANTI_POP); | 763 | reg = snd_soc_read(codec, WM8961_ANTI_POP); |
764 | reg |= WM8961_BUFIOEN | WM8961_BUFDCOPEN; | 764 | reg |= WM8961_BUFIOEN | WM8961_BUFDCOPEN; |
@@ -773,7 +773,7 @@ static int wm8961_set_bias_level(struct snd_soc_codec *codec, | |||
773 | break; | 773 | break; |
774 | 774 | ||
775 | case SND_SOC_BIAS_STANDBY: | 775 | case SND_SOC_BIAS_STANDBY: |
776 | if (codec->dapm.bias_level == SND_SOC_BIAS_PREPARE) { | 776 | if (snd_soc_codec_get_bias_level(codec) == SND_SOC_BIAS_PREPARE) { |
777 | /* VREF off */ | 777 | /* VREF off */ |
778 | reg = snd_soc_read(codec, WM8961_PWR_MGMT_1); | 778 | reg = snd_soc_read(codec, WM8961_PWR_MGMT_1); |
779 | reg &= ~WM8961_VREF; | 779 | reg &= ~WM8961_VREF; |
@@ -795,8 +795,6 @@ static int wm8961_set_bias_level(struct snd_soc_codec *codec, | |||
795 | break; | 795 | break; |
796 | } | 796 | } |
797 | 797 | ||
798 | codec->dapm.bias_level = level; | ||
799 | |||
800 | return 0; | 798 | return 0; |
801 | } | 799 | } |
802 | 800 | ||
diff --git a/sound/soc/codecs/wm8962.c b/sound/soc/codecs/wm8962.c index 118b0034ba23..c5748fd4f296 100644 --- a/sound/soc/codecs/wm8962.c +++ b/sound/soc/codecs/wm8962.c | |||
@@ -2361,7 +2361,7 @@ static int wm8962_add_widgets(struct snd_soc_codec *codec) | |||
2361 | { | 2361 | { |
2362 | struct wm8962_priv *wm8962 = snd_soc_codec_get_drvdata(codec); | 2362 | struct wm8962_priv *wm8962 = snd_soc_codec_get_drvdata(codec); |
2363 | struct wm8962_pdata *pdata = &wm8962->pdata; | 2363 | struct wm8962_pdata *pdata = &wm8962->pdata; |
2364 | struct snd_soc_dapm_context *dapm = &codec->dapm; | 2364 | struct snd_soc_dapm_context *dapm = snd_soc_codec_get_dapm(codec); |
2365 | 2365 | ||
2366 | snd_soc_add_codec_controls(codec, wm8962_snd_controls, | 2366 | snd_soc_add_codec_controls(codec, wm8962_snd_controls, |
2367 | ARRAY_SIZE(wm8962_snd_controls)); | 2367 | ARRAY_SIZE(wm8962_snd_controls)); |
@@ -2446,13 +2446,13 @@ static void wm8962_configure_bclk(struct snd_soc_codec *codec) | |||
2446 | * So we here provisionally enable it and then disable it afterward | 2446 | * So we here provisionally enable it and then disable it afterward |
2447 | * if current bias_level hasn't reached SND_SOC_BIAS_ON. | 2447 | * if current bias_level hasn't reached SND_SOC_BIAS_ON. |
2448 | */ | 2448 | */ |
2449 | if (codec->dapm.bias_level != SND_SOC_BIAS_ON) | 2449 | if (snd_soc_codec_get_bias_level(codec) != SND_SOC_BIAS_ON) |
2450 | snd_soc_update_bits(codec, WM8962_CLOCKING2, | 2450 | snd_soc_update_bits(codec, WM8962_CLOCKING2, |
2451 | WM8962_SYSCLK_ENA_MASK, WM8962_SYSCLK_ENA); | 2451 | WM8962_SYSCLK_ENA_MASK, WM8962_SYSCLK_ENA); |
2452 | 2452 | ||
2453 | dspclk = snd_soc_read(codec, WM8962_CLOCKING1); | 2453 | dspclk = snd_soc_read(codec, WM8962_CLOCKING1); |
2454 | 2454 | ||
2455 | if (codec->dapm.bias_level != SND_SOC_BIAS_ON) | 2455 | if (snd_soc_codec_get_bias_level(codec) != SND_SOC_BIAS_ON) |
2456 | snd_soc_update_bits(codec, WM8962_CLOCKING2, | 2456 | snd_soc_update_bits(codec, WM8962_CLOCKING2, |
2457 | WM8962_SYSCLK_ENA_MASK, 0); | 2457 | WM8962_SYSCLK_ENA_MASK, 0); |
2458 | 2458 | ||
@@ -2510,9 +2510,6 @@ static void wm8962_configure_bclk(struct snd_soc_codec *codec) | |||
2510 | static int wm8962_set_bias_level(struct snd_soc_codec *codec, | 2510 | static int wm8962_set_bias_level(struct snd_soc_codec *codec, |
2511 | enum snd_soc_bias_level level) | 2511 | enum snd_soc_bias_level level) |
2512 | { | 2512 | { |
2513 | if (level == codec->dapm.bias_level) | ||
2514 | return 0; | ||
2515 | |||
2516 | switch (level) { | 2513 | switch (level) { |
2517 | case SND_SOC_BIAS_ON: | 2514 | case SND_SOC_BIAS_ON: |
2518 | break; | 2515 | break; |
@@ -2530,7 +2527,7 @@ static int wm8962_set_bias_level(struct snd_soc_codec *codec, | |||
2530 | snd_soc_update_bits(codec, WM8962_PWR_MGMT_1, | 2527 | snd_soc_update_bits(codec, WM8962_PWR_MGMT_1, |
2531 | WM8962_VMID_SEL_MASK, 0x100); | 2528 | WM8962_VMID_SEL_MASK, 0x100); |
2532 | 2529 | ||
2533 | if (codec->dapm.bias_level == SND_SOC_BIAS_OFF) | 2530 | if (snd_soc_codec_get_bias_level(codec) == SND_SOC_BIAS_OFF) |
2534 | msleep(100); | 2531 | msleep(100); |
2535 | break; | 2532 | break; |
2536 | 2533 | ||
@@ -2538,7 +2535,6 @@ static int wm8962_set_bias_level(struct snd_soc_codec *codec, | |||
2538 | break; | 2535 | break; |
2539 | } | 2536 | } |
2540 | 2537 | ||
2541 | codec->dapm.bias_level = level; | ||
2542 | return 0; | 2538 | return 0; |
2543 | } | 2539 | } |
2544 | 2540 | ||
@@ -2614,7 +2610,7 @@ static int wm8962_hw_params(struct snd_pcm_substream *substream, | |||
2614 | dev_dbg(codec->dev, "hw_params set BCLK %dHz LRCLK %dHz\n", | 2610 | dev_dbg(codec->dev, "hw_params set BCLK %dHz LRCLK %dHz\n", |
2615 | wm8962->bclk, wm8962->lrclk); | 2611 | wm8962->bclk, wm8962->lrclk); |
2616 | 2612 | ||
2617 | if (codec->dapm.bias_level == SND_SOC_BIAS_ON) | 2613 | if (snd_soc_codec_get_bias_level(codec) == SND_SOC_BIAS_ON) |
2618 | wm8962_configure_bclk(codec); | 2614 | wm8962_configure_bclk(codec); |
2619 | 2615 | ||
2620 | return 0; | 2616 | return 0; |
@@ -3118,7 +3114,7 @@ static irqreturn_t wm8962_irq(int irq, void *data) | |||
3118 | int wm8962_mic_detect(struct snd_soc_codec *codec, struct snd_soc_jack *jack) | 3114 | int wm8962_mic_detect(struct snd_soc_codec *codec, struct snd_soc_jack *jack) |
3119 | { | 3115 | { |
3120 | struct wm8962_priv *wm8962 = snd_soc_codec_get_drvdata(codec); | 3116 | struct wm8962_priv *wm8962 = snd_soc_codec_get_drvdata(codec); |
3121 | struct snd_soc_dapm_context *dapm = &codec->dapm; | 3117 | struct snd_soc_dapm_context *dapm = snd_soc_codec_get_dapm(codec); |
3122 | int irq_mask, enable; | 3118 | int irq_mask, enable; |
3123 | 3119 | ||
3124 | wm8962->jack = jack; | 3120 | wm8962->jack = jack; |
@@ -3164,7 +3160,7 @@ static void wm8962_beep_work(struct work_struct *work) | |||
3164 | struct wm8962_priv *wm8962 = | 3160 | struct wm8962_priv *wm8962 = |
3165 | container_of(work, struct wm8962_priv, beep_work); | 3161 | container_of(work, struct wm8962_priv, beep_work); |
3166 | struct snd_soc_codec *codec = wm8962->codec; | 3162 | struct snd_soc_codec *codec = wm8962->codec; |
3167 | struct snd_soc_dapm_context *dapm = &codec->dapm; | 3163 | struct snd_soc_dapm_context *dapm = snd_soc_codec_get_dapm(codec); |
3168 | int i; | 3164 | int i; |
3169 | int reg = 0; | 3165 | int reg = 0; |
3170 | int best = 0; | 3166 | int best = 0; |
@@ -3415,6 +3411,7 @@ static void wm8962_free_gpio(struct snd_soc_codec *codec) | |||
3415 | 3411 | ||
3416 | static int wm8962_probe(struct snd_soc_codec *codec) | 3412 | static int wm8962_probe(struct snd_soc_codec *codec) |
3417 | { | 3413 | { |
3414 | struct snd_soc_dapm_context *dapm = snd_soc_codec_get_dapm(codec); | ||
3418 | int ret; | 3415 | int ret; |
3419 | struct wm8962_priv *wm8962 = snd_soc_codec_get_drvdata(codec); | 3416 | struct wm8962_priv *wm8962 = snd_soc_codec_get_drvdata(codec); |
3420 | int i; | 3417 | int i; |
@@ -3462,7 +3459,7 @@ static int wm8962_probe(struct snd_soc_codec *codec) | |||
3462 | } | 3459 | } |
3463 | if (!dmicclk || !dmicdat) { | 3460 | if (!dmicclk || !dmicdat) { |
3464 | dev_dbg(codec->dev, "DMIC not in use, disabling\n"); | 3461 | dev_dbg(codec->dev, "DMIC not in use, disabling\n"); |
3465 | snd_soc_dapm_nc_pin(&codec->dapm, "DMICDAT"); | 3462 | snd_soc_dapm_nc_pin(dapm, "DMICDAT"); |
3466 | } | 3463 | } |
3467 | if (dmicclk != dmicdat) | 3464 | if (dmicclk != dmicdat) |
3468 | dev_warn(codec->dev, "DMIC GPIOs partially configured\n"); | 3465 | dev_warn(codec->dev, "DMIC GPIOs partially configured\n"); |
diff --git a/sound/soc/codecs/wm8971.c b/sound/soc/codecs/wm8971.c index f9cbabdc6238..b51184c4e816 100644 --- a/sound/soc/codecs/wm8971.c +++ b/sound/soc/codecs/wm8971.c | |||
@@ -577,7 +577,7 @@ static int wm8971_set_bias_level(struct snd_soc_codec *codec, | |||
577 | flush_delayed_work(&wm8971->charge_work); | 577 | flush_delayed_work(&wm8971->charge_work); |
578 | break; | 578 | break; |
579 | case SND_SOC_BIAS_STANDBY: | 579 | case SND_SOC_BIAS_STANDBY: |
580 | if (codec->dapm.bias_level == SND_SOC_BIAS_OFF) { | 580 | if (snd_soc_codec_get_bias_level(codec) == SND_SOC_BIAS_OFF) { |
581 | snd_soc_cache_sync(codec); | 581 | snd_soc_cache_sync(codec); |
582 | /* charge output caps - set vmid to 5k for quick power up */ | 582 | /* charge output caps - set vmid to 5k for quick power up */ |
583 | snd_soc_write(codec, WM8971_PWR1, pwr_reg | 0x01c0); | 583 | snd_soc_write(codec, WM8971_PWR1, pwr_reg | 0x01c0); |
@@ -594,7 +594,6 @@ static int wm8971_set_bias_level(struct snd_soc_codec *codec, | |||
594 | snd_soc_write(codec, WM8971_PWR1, 0x0001); | 594 | snd_soc_write(codec, WM8971_PWR1, 0x0001); |
595 | break; | 595 | break; |
596 | } | 596 | } |
597 | codec->dapm.bias_level = level; | ||
598 | return 0; | 597 | return 0; |
599 | } | 598 | } |
600 | 599 | ||
diff --git a/sound/soc/codecs/wm8974.c b/sound/soc/codecs/wm8974.c index ff0e4646b934..33b16a7ba82e 100644 --- a/sound/soc/codecs/wm8974.c +++ b/sound/soc/codecs/wm8974.c | |||
@@ -514,7 +514,7 @@ static int wm8974_set_bias_level(struct snd_soc_codec *codec, | |||
514 | case SND_SOC_BIAS_STANDBY: | 514 | case SND_SOC_BIAS_STANDBY: |
515 | power1 |= WM8974_POWER1_BIASEN | WM8974_POWER1_BUFIOEN; | 515 | power1 |= WM8974_POWER1_BIASEN | WM8974_POWER1_BUFIOEN; |
516 | 516 | ||
517 | if (codec->dapm.bias_level == SND_SOC_BIAS_OFF) { | 517 | if (snd_soc_codec_get_bias_level(codec) == SND_SOC_BIAS_OFF) { |
518 | regcache_sync(dev_get_regmap(codec->dev, NULL)); | 518 | regcache_sync(dev_get_regmap(codec->dev, NULL)); |
519 | 519 | ||
520 | /* Initial cap charge at VMID 5k */ | 520 | /* Initial cap charge at VMID 5k */ |
@@ -533,7 +533,6 @@ static int wm8974_set_bias_level(struct snd_soc_codec *codec, | |||
533 | break; | 533 | break; |
534 | } | 534 | } |
535 | 535 | ||
536 | codec->dapm.bias_level = level; | ||
537 | return 0; | 536 | return 0; |
538 | } | 537 | } |
539 | 538 | ||
diff --git a/sound/soc/codecs/wm8978.c b/sound/soc/codecs/wm8978.c index cf7032911721..cfc8cdf49970 100644 --- a/sound/soc/codecs/wm8978.c +++ b/sound/soc/codecs/wm8978.c | |||
@@ -868,7 +868,7 @@ static int wm8978_set_bias_level(struct snd_soc_codec *codec, | |||
868 | /* bit 3: enable bias, bit 2: enable I/O tie off buffer */ | 868 | /* bit 3: enable bias, bit 2: enable I/O tie off buffer */ |
869 | power1 |= 0xc; | 869 | power1 |= 0xc; |
870 | 870 | ||
871 | if (codec->dapm.bias_level == SND_SOC_BIAS_OFF) { | 871 | if (snd_soc_codec_get_bias_level(codec) == SND_SOC_BIAS_OFF) { |
872 | /* Initial cap charge at VMID 5k */ | 872 | /* Initial cap charge at VMID 5k */ |
873 | snd_soc_write(codec, WM8978_POWER_MANAGEMENT_1, | 873 | snd_soc_write(codec, WM8978_POWER_MANAGEMENT_1, |
874 | power1 | 0x3); | 874 | power1 | 0x3); |
@@ -888,7 +888,6 @@ static int wm8978_set_bias_level(struct snd_soc_codec *codec, | |||
888 | 888 | ||
889 | dev_dbg(codec->dev, "%s: %d, %x\n", __func__, level, power1); | 889 | dev_dbg(codec->dev, "%s: %d, %x\n", __func__, level, power1); |
890 | 890 | ||
891 | codec->dapm.bias_level = level; | ||
892 | return 0; | 891 | return 0; |
893 | } | 892 | } |
894 | 893 | ||
@@ -928,7 +927,7 @@ static int wm8978_suspend(struct snd_soc_codec *codec) | |||
928 | { | 927 | { |
929 | struct wm8978_priv *wm8978 = snd_soc_codec_get_drvdata(codec); | 928 | struct wm8978_priv *wm8978 = snd_soc_codec_get_drvdata(codec); |
930 | 929 | ||
931 | wm8978_set_bias_level(codec, SND_SOC_BIAS_OFF); | 930 | snd_soc_codec_force_bias_level(codec, SND_SOC_BIAS_OFF); |
932 | /* Also switch PLL off */ | 931 | /* Also switch PLL off */ |
933 | snd_soc_write(codec, WM8978_POWER_MANAGEMENT_1, 0); | 932 | snd_soc_write(codec, WM8978_POWER_MANAGEMENT_1, 0); |
934 | 933 | ||
@@ -944,7 +943,7 @@ static int wm8978_resume(struct snd_soc_codec *codec) | |||
944 | /* Sync reg_cache with the hardware */ | 943 | /* Sync reg_cache with the hardware */ |
945 | regcache_sync(wm8978->regmap); | 944 | regcache_sync(wm8978->regmap); |
946 | 945 | ||
947 | wm8978_set_bias_level(codec, SND_SOC_BIAS_STANDBY); | 946 | snd_soc_codec_force_bias_level(codec, SND_SOC_BIAS_STANDBY); |
948 | 947 | ||
949 | if (wm8978->f_pllout) | 948 | if (wm8978->f_pllout) |
950 | /* Switch PLL on */ | 949 | /* Switch PLL on */ |
diff --git a/sound/soc/codecs/wm8983.c b/sound/soc/codecs/wm8983.c index 5d1cf08a72b8..2fdd2c6cc09d 100644 --- a/sound/soc/codecs/wm8983.c +++ b/sound/soc/codecs/wm8983.c | |||
@@ -915,7 +915,7 @@ static int wm8983_set_bias_level(struct snd_soc_codec *codec, | |||
915 | 1 << WM8983_VMIDSEL_SHIFT); | 915 | 1 << WM8983_VMIDSEL_SHIFT); |
916 | break; | 916 | break; |
917 | case SND_SOC_BIAS_STANDBY: | 917 | case SND_SOC_BIAS_STANDBY: |
918 | if (codec->dapm.bias_level == SND_SOC_BIAS_OFF) { | 918 | if (snd_soc_codec_get_bias_level(codec) == SND_SOC_BIAS_OFF) { |
919 | ret = regcache_sync(wm8983->regmap); | 919 | ret = regcache_sync(wm8983->regmap); |
920 | if (ret < 0) { | 920 | if (ret < 0) { |
921 | dev_err(codec->dev, "Failed to sync cache: %d\n", ret); | 921 | dev_err(codec->dev, "Failed to sync cache: %d\n", ret); |
@@ -963,7 +963,6 @@ static int wm8983_set_bias_level(struct snd_soc_codec *codec, | |||
963 | break; | 963 | break; |
964 | } | 964 | } |
965 | 965 | ||
966 | codec->dapm.bias_level = level; | ||
967 | return 0; | 966 | return 0; |
968 | } | 967 | } |
969 | 968 | ||
diff --git a/sound/soc/codecs/wm8985.c b/sound/soc/codecs/wm8985.c index 0b3b54c9971d..8a85f5004d41 100644 --- a/sound/soc/codecs/wm8985.c +++ b/sound/soc/codecs/wm8985.c | |||
@@ -897,7 +897,7 @@ static int wm8985_set_bias_level(struct snd_soc_codec *codec, | |||
897 | 1 << WM8985_VMIDSEL_SHIFT); | 897 | 1 << WM8985_VMIDSEL_SHIFT); |
898 | break; | 898 | break; |
899 | case SND_SOC_BIAS_STANDBY: | 899 | case SND_SOC_BIAS_STANDBY: |
900 | if (codec->dapm.bias_level == SND_SOC_BIAS_OFF) { | 900 | if (snd_soc_codec_get_bias_level(codec) == SND_SOC_BIAS_OFF) { |
901 | ret = regulator_bulk_enable(ARRAY_SIZE(wm8985->supplies), | 901 | ret = regulator_bulk_enable(ARRAY_SIZE(wm8985->supplies), |
902 | wm8985->supplies); | 902 | wm8985->supplies); |
903 | if (ret) { | 903 | if (ret) { |
@@ -957,7 +957,6 @@ static int wm8985_set_bias_level(struct snd_soc_codec *codec, | |||
957 | break; | 957 | break; |
958 | } | 958 | } |
959 | 959 | ||
960 | codec->dapm.bias_level = level; | ||
961 | return 0; | 960 | return 0; |
962 | } | 961 | } |
963 | 962 | ||
diff --git a/sound/soc/codecs/wm8988.c b/sound/soc/codecs/wm8988.c index 24968aa8618a..f13a995af277 100644 --- a/sound/soc/codecs/wm8988.c +++ b/sound/soc/codecs/wm8988.c | |||
@@ -738,7 +738,7 @@ static int wm8988_set_bias_level(struct snd_soc_codec *codec, | |||
738 | break; | 738 | break; |
739 | 739 | ||
740 | case SND_SOC_BIAS_STANDBY: | 740 | case SND_SOC_BIAS_STANDBY: |
741 | if (codec->dapm.bias_level == SND_SOC_BIAS_OFF) { | 741 | if (snd_soc_codec_get_bias_level(codec) == SND_SOC_BIAS_OFF) { |
742 | regcache_sync(wm8988->regmap); | 742 | regcache_sync(wm8988->regmap); |
743 | 743 | ||
744 | /* VREF, VMID=2x5k */ | 744 | /* VREF, VMID=2x5k */ |
@@ -756,7 +756,6 @@ static int wm8988_set_bias_level(struct snd_soc_codec *codec, | |||
756 | snd_soc_write(codec, WM8988_PWR1, 0x0000); | 756 | snd_soc_write(codec, WM8988_PWR1, 0x0000); |
757 | break; | 757 | break; |
758 | } | 758 | } |
759 | codec->dapm.bias_level = level; | ||
760 | return 0; | 759 | return 0; |
761 | } | 760 | } |
762 | 761 | ||
diff --git a/sound/soc/codecs/wm8990.c b/sound/soc/codecs/wm8990.c index c93bffcb3cfb..1993fd2a6f15 100644 --- a/sound/soc/codecs/wm8990.c +++ b/sound/soc/codecs/wm8990.c | |||
@@ -1124,7 +1124,7 @@ static int wm8990_set_bias_level(struct snd_soc_codec *codec, | |||
1124 | break; | 1124 | break; |
1125 | 1125 | ||
1126 | case SND_SOC_BIAS_STANDBY: | 1126 | case SND_SOC_BIAS_STANDBY: |
1127 | if (codec->dapm.bias_level == SND_SOC_BIAS_OFF) { | 1127 | if (snd_soc_codec_get_bias_level(codec) == SND_SOC_BIAS_OFF) { |
1128 | ret = regcache_sync(wm8990->regmap); | 1128 | ret = regcache_sync(wm8990->regmap); |
1129 | if (ret < 0) { | 1129 | if (ret < 0) { |
1130 | dev_err(codec->dev, "Failed to sync cache: %d\n", ret); | 1130 | dev_err(codec->dev, "Failed to sync cache: %d\n", ret); |
@@ -1227,7 +1227,6 @@ static int wm8990_set_bias_level(struct snd_soc_codec *codec, | |||
1227 | break; | 1227 | break; |
1228 | } | 1228 | } |
1229 | 1229 | ||
1230 | codec->dapm.bias_level = level; | ||
1231 | return 0; | 1230 | return 0; |
1232 | } | 1231 | } |
1233 | 1232 | ||
@@ -1281,7 +1280,7 @@ static int wm8990_probe(struct snd_soc_codec *codec) | |||
1281 | wm8990_reset(codec); | 1280 | wm8990_reset(codec); |
1282 | 1281 | ||
1283 | /* charge output caps */ | 1282 | /* charge output caps */ |
1284 | wm8990_set_bias_level(codec, SND_SOC_BIAS_STANDBY); | 1283 | snd_soc_codec_force_bias_level(codec, SND_SOC_BIAS_STANDBY); |
1285 | 1284 | ||
1286 | snd_soc_update_bits(codec, WM8990_AUDIO_INTERFACE_4, | 1285 | snd_soc_update_bits(codec, WM8990_AUDIO_INTERFACE_4, |
1287 | WM8990_ALRCGPIO1, WM8990_ALRCGPIO1); | 1286 | WM8990_ALRCGPIO1, WM8990_ALRCGPIO1); |
diff --git a/sound/soc/codecs/wm8991.c b/sound/soc/codecs/wm8991.c index 49df0dc607e6..44a677720828 100644 --- a/sound/soc/codecs/wm8991.c +++ b/sound/soc/codecs/wm8991.c | |||
@@ -1131,7 +1131,7 @@ static int wm8991_set_bias_level(struct snd_soc_codec *codec, | |||
1131 | break; | 1131 | break; |
1132 | 1132 | ||
1133 | case SND_SOC_BIAS_STANDBY: | 1133 | case SND_SOC_BIAS_STANDBY: |
1134 | if (codec->dapm.bias_level == SND_SOC_BIAS_OFF) { | 1134 | if (snd_soc_codec_get_bias_level(codec) == SND_SOC_BIAS_OFF) { |
1135 | regcache_sync(wm8991->regmap); | 1135 | regcache_sync(wm8991->regmap); |
1136 | /* Enable all output discharge bits */ | 1136 | /* Enable all output discharge bits */ |
1137 | snd_soc_write(codec, WM8991_ANTIPOP1, WM8991_DIS_LLINE | | 1137 | snd_soc_write(codec, WM8991_ANTIPOP1, WM8991_DIS_LLINE | |
@@ -1224,7 +1224,6 @@ static int wm8991_set_bias_level(struct snd_soc_codec *codec, | |||
1224 | break; | 1224 | break; |
1225 | } | 1225 | } |
1226 | 1226 | ||
1227 | codec->dapm.bias_level = level; | ||
1228 | return 0; | 1227 | return 0; |
1229 | } | 1228 | } |
1230 | 1229 | ||
diff --git a/sound/soc/codecs/wm8993.c b/sound/soc/codecs/wm8993.c index 2e70a270eb28..8a8db8605dc2 100644 --- a/sound/soc/codecs/wm8993.c +++ b/sound/soc/codecs/wm8993.c | |||
@@ -992,7 +992,7 @@ static int wm8993_set_bias_level(struct snd_soc_codec *codec, | |||
992 | break; | 992 | break; |
993 | 993 | ||
994 | case SND_SOC_BIAS_STANDBY: | 994 | case SND_SOC_BIAS_STANDBY: |
995 | if (codec->dapm.bias_level == SND_SOC_BIAS_OFF) { | 995 | if (snd_soc_codec_get_bias_level(codec) == SND_SOC_BIAS_OFF) { |
996 | ret = regulator_bulk_enable(ARRAY_SIZE(wm8993->supplies), | 996 | ret = regulator_bulk_enable(ARRAY_SIZE(wm8993->supplies), |
997 | wm8993->supplies); | 997 | wm8993->supplies); |
998 | if (ret != 0) | 998 | if (ret != 0) |
@@ -1065,8 +1065,6 @@ static int wm8993_set_bias_level(struct snd_soc_codec *codec, | |||
1065 | break; | 1065 | break; |
1066 | } | 1066 | } |
1067 | 1067 | ||
1068 | codec->dapm.bias_level = level; | ||
1069 | |||
1070 | return 0; | 1068 | return 0; |
1071 | } | 1069 | } |
1072 | 1070 | ||
@@ -1485,7 +1483,7 @@ static struct snd_soc_dai_driver wm8993_dai = { | |||
1485 | static int wm8993_probe(struct snd_soc_codec *codec) | 1483 | static int wm8993_probe(struct snd_soc_codec *codec) |
1486 | { | 1484 | { |
1487 | struct wm8993_priv *wm8993 = snd_soc_codec_get_drvdata(codec); | 1485 | struct wm8993_priv *wm8993 = snd_soc_codec_get_drvdata(codec); |
1488 | struct snd_soc_dapm_context *dapm = &codec->dapm; | 1486 | struct snd_soc_dapm_context *dapm = snd_soc_codec_get_dapm(codec); |
1489 | 1487 | ||
1490 | wm8993->hubs_data.hp_startup_mode = 1; | 1488 | wm8993->hubs_data.hp_startup_mode = 1; |
1491 | wm8993->hubs_data.dcs_codes_l = -2; | 1489 | wm8993->hubs_data.dcs_codes_l = -2; |
@@ -1539,7 +1537,7 @@ static int wm8993_probe(struct snd_soc_codec *codec) | |||
1539 | * VMID as an output and can disable it. | 1537 | * VMID as an output and can disable it. |
1540 | */ | 1538 | */ |
1541 | if (wm8993->pdata.lineout1_diff && wm8993->pdata.lineout2_diff) | 1539 | if (wm8993->pdata.lineout1_diff && wm8993->pdata.lineout2_diff) |
1542 | codec->dapm.idle_bias_off = 1; | 1540 | dapm->idle_bias_off = 1; |
1543 | 1541 | ||
1544 | return 0; | 1542 | return 0; |
1545 | 1543 | ||
@@ -1563,7 +1561,7 @@ static int wm8993_suspend(struct snd_soc_codec *codec) | |||
1563 | wm8993->fll_fout = fll_fout; | 1561 | wm8993->fll_fout = fll_fout; |
1564 | wm8993->fll_fref = fll_fref; | 1562 | wm8993->fll_fref = fll_fref; |
1565 | 1563 | ||
1566 | wm8993_set_bias_level(codec, SND_SOC_BIAS_OFF); | 1564 | snd_soc_codec_force_bias_level(codec, SND_SOC_BIAS_OFF); |
1567 | 1565 | ||
1568 | return 0; | 1566 | return 0; |
1569 | } | 1567 | } |
@@ -1573,7 +1571,7 @@ static int wm8993_resume(struct snd_soc_codec *codec) | |||
1573 | struct wm8993_priv *wm8993 = snd_soc_codec_get_drvdata(codec); | 1571 | struct wm8993_priv *wm8993 = snd_soc_codec_get_drvdata(codec); |
1574 | int ret; | 1572 | int ret; |
1575 | 1573 | ||
1576 | wm8993_set_bias_level(codec, SND_SOC_BIAS_STANDBY); | 1574 | snd_soc_codec_force_bias_level(codec, SND_SOC_BIAS_STANDBY); |
1577 | 1575 | ||
1578 | /* Restart the FLL? */ | 1576 | /* Restart the FLL? */ |
1579 | if (wm8993->fll_fout) { | 1577 | if (wm8993->fll_fout) { |
diff --git a/sound/soc/codecs/wm8994.c b/sound/soc/codecs/wm8994.c index 4fbc7689339a..962e1d31a629 100644 --- a/sound/soc/codecs/wm8994.c +++ b/sound/soc/codecs/wm8994.c | |||
@@ -212,6 +212,7 @@ static int configure_aif_clock(struct snd_soc_codec *codec, int aif) | |||
212 | 212 | ||
213 | static int configure_clock(struct snd_soc_codec *codec) | 213 | static int configure_clock(struct snd_soc_codec *codec) |
214 | { | 214 | { |
215 | struct snd_soc_dapm_context *dapm = snd_soc_codec_get_dapm(codec); | ||
215 | struct wm8994_priv *wm8994 = snd_soc_codec_get_drvdata(codec); | 216 | struct wm8994_priv *wm8994 = snd_soc_codec_get_drvdata(codec); |
216 | int change, new; | 217 | int change, new; |
217 | 218 | ||
@@ -239,7 +240,7 @@ static int configure_clock(struct snd_soc_codec *codec) | |||
239 | change = snd_soc_update_bits(codec, WM8994_CLOCKING_1, | 240 | change = snd_soc_update_bits(codec, WM8994_CLOCKING_1, |
240 | WM8994_SYSCLK_SRC, new); | 241 | WM8994_SYSCLK_SRC, new); |
241 | if (change) | 242 | if (change) |
242 | snd_soc_dapm_sync(&codec->dapm); | 243 | snd_soc_dapm_sync(dapm); |
243 | 244 | ||
244 | wm8958_micd_set_rate(codec); | 245 | wm8958_micd_set_rate(codec); |
245 | 246 | ||
@@ -2492,12 +2493,12 @@ static int wm8994_set_bias_level(struct snd_soc_codec *codec, | |||
2492 | break; | 2493 | break; |
2493 | } | 2494 | } |
2494 | 2495 | ||
2495 | if (codec->dapm.bias_level == SND_SOC_BIAS_STANDBY) | 2496 | if (snd_soc_codec_get_bias_level(codec) == SND_SOC_BIAS_STANDBY) |
2496 | active_reference(codec); | 2497 | active_reference(codec); |
2497 | break; | 2498 | break; |
2498 | 2499 | ||
2499 | case SND_SOC_BIAS_STANDBY: | 2500 | case SND_SOC_BIAS_STANDBY: |
2500 | if (codec->dapm.bias_level == SND_SOC_BIAS_OFF) { | 2501 | if (snd_soc_codec_get_bias_level(codec) == SND_SOC_BIAS_OFF) { |
2501 | switch (control->type) { | 2502 | switch (control->type) { |
2502 | case WM8958: | 2503 | case WM8958: |
2503 | if (control->revision == 0) { | 2504 | if (control->revision == 0) { |
@@ -2521,7 +2522,7 @@ static int wm8994_set_bias_level(struct snd_soc_codec *codec, | |||
2521 | WM8994_LINEOUT2_DISCH); | 2522 | WM8994_LINEOUT2_DISCH); |
2522 | } | 2523 | } |
2523 | 2524 | ||
2524 | if (codec->dapm.bias_level == SND_SOC_BIAS_PREPARE) | 2525 | if (snd_soc_codec_get_bias_level(codec) == SND_SOC_BIAS_PREPARE) |
2525 | active_dereference(codec); | 2526 | active_dereference(codec); |
2526 | 2527 | ||
2527 | /* MICBIAS into bypass mode on newer devices */ | 2528 | /* MICBIAS into bypass mode on newer devices */ |
@@ -2541,20 +2542,18 @@ static int wm8994_set_bias_level(struct snd_soc_codec *codec, | |||
2541 | break; | 2542 | break; |
2542 | 2543 | ||
2543 | case SND_SOC_BIAS_OFF: | 2544 | case SND_SOC_BIAS_OFF: |
2544 | if (codec->dapm.bias_level == SND_SOC_BIAS_STANDBY) | 2545 | if (snd_soc_codec_get_bias_level(codec) == SND_SOC_BIAS_STANDBY) |
2545 | wm8994->cur_fw = NULL; | 2546 | wm8994->cur_fw = NULL; |
2546 | break; | 2547 | break; |
2547 | } | 2548 | } |
2548 | 2549 | ||
2549 | codec->dapm.bias_level = level; | ||
2550 | |||
2551 | return 0; | 2550 | return 0; |
2552 | } | 2551 | } |
2553 | 2552 | ||
2554 | int wm8994_vmid_mode(struct snd_soc_codec *codec, enum wm8994_vmid_mode mode) | 2553 | int wm8994_vmid_mode(struct snd_soc_codec *codec, enum wm8994_vmid_mode mode) |
2555 | { | 2554 | { |
2556 | struct wm8994_priv *wm8994 = snd_soc_codec_get_drvdata(codec); | 2555 | struct wm8994_priv *wm8994 = snd_soc_codec_get_drvdata(codec); |
2557 | struct snd_soc_dapm_context *dapm = &codec->dapm; | 2556 | struct snd_soc_dapm_context *dapm = snd_soc_codec_get_dapm(codec); |
2558 | 2557 | ||
2559 | switch (mode) { | 2558 | switch (mode) { |
2560 | case WM8994_VMID_NORMAL: | 2559 | case WM8994_VMID_NORMAL: |
@@ -2754,7 +2753,7 @@ static struct { | |||
2754 | }; | 2753 | }; |
2755 | 2754 | ||
2756 | static int fs_ratios[] = { | 2755 | static int fs_ratios[] = { |
2757 | 64, 128, 192, 256, 348, 512, 768, 1024, 1408, 1536 | 2756 | 64, 128, 192, 256, 384, 512, 768, 1024, 1408, 1536 |
2758 | }; | 2757 | }; |
2759 | 2758 | ||
2760 | static int bclk_divs[] = { | 2759 | static int bclk_divs[] = { |
@@ -3163,7 +3162,7 @@ static int wm8994_codec_suspend(struct snd_soc_codec *codec) | |||
3163 | i + 1, ret); | 3162 | i + 1, ret); |
3164 | } | 3163 | } |
3165 | 3164 | ||
3166 | wm8994_set_bias_level(codec, SND_SOC_BIAS_OFF); | 3165 | snd_soc_codec_force_bias_level(codec, SND_SOC_BIAS_OFF); |
3167 | 3166 | ||
3168 | return 0; | 3167 | return 0; |
3169 | } | 3168 | } |
@@ -3356,6 +3355,7 @@ static void wm8994_handle_pdata(struct wm8994_priv *wm8994) | |||
3356 | int wm8994_mic_detect(struct snd_soc_codec *codec, struct snd_soc_jack *jack, | 3355 | int wm8994_mic_detect(struct snd_soc_codec *codec, struct snd_soc_jack *jack, |
3357 | int micbias) | 3356 | int micbias) |
3358 | { | 3357 | { |
3358 | struct snd_soc_dapm_context *dapm = snd_soc_codec_get_dapm(codec); | ||
3359 | struct wm8994_priv *wm8994 = snd_soc_codec_get_drvdata(codec); | 3359 | struct wm8994_priv *wm8994 = snd_soc_codec_get_drvdata(codec); |
3360 | struct wm8994_micdet *micdet; | 3360 | struct wm8994_micdet *micdet; |
3361 | struct wm8994 *control = wm8994->wm8994; | 3361 | struct wm8994 *control = wm8994->wm8994; |
@@ -3370,20 +3370,16 @@ int wm8994_mic_detect(struct snd_soc_codec *codec, struct snd_soc_jack *jack, | |||
3370 | case 1: | 3370 | case 1: |
3371 | micdet = &wm8994->micdet[0]; | 3371 | micdet = &wm8994->micdet[0]; |
3372 | if (jack) | 3372 | if (jack) |
3373 | ret = snd_soc_dapm_force_enable_pin(&codec->dapm, | 3373 | ret = snd_soc_dapm_force_enable_pin(dapm, "MICBIAS1"); |
3374 | "MICBIAS1"); | ||
3375 | else | 3374 | else |
3376 | ret = snd_soc_dapm_disable_pin(&codec->dapm, | 3375 | ret = snd_soc_dapm_disable_pin(dapm, "MICBIAS1"); |
3377 | "MICBIAS1"); | ||
3378 | break; | 3376 | break; |
3379 | case 2: | 3377 | case 2: |
3380 | micdet = &wm8994->micdet[1]; | 3378 | micdet = &wm8994->micdet[1]; |
3381 | if (jack) | 3379 | if (jack) |
3382 | ret = snd_soc_dapm_force_enable_pin(&codec->dapm, | 3380 | ret = snd_soc_dapm_force_enable_pin(dapm, "MICBIAS1"); |
3383 | "MICBIAS1"); | ||
3384 | else | 3381 | else |
3385 | ret = snd_soc_dapm_disable_pin(&codec->dapm, | 3382 | ret = snd_soc_dapm_disable_pin(dapm, "MICBIAS1"); |
3386 | "MICBIAS1"); | ||
3387 | break; | 3383 | break; |
3388 | default: | 3384 | default: |
3389 | dev_warn(codec->dev, "Invalid MICBIAS %d\n", micbias); | 3385 | dev_warn(codec->dev, "Invalid MICBIAS %d\n", micbias); |
@@ -3415,7 +3411,7 @@ int wm8994_mic_detect(struct snd_soc_codec *codec, struct snd_soc_jack *jack, | |||
3415 | WM8994_MIC2_DET_DB_MASK | WM8994_MIC2_SHRT_DB_MASK, | 3411 | WM8994_MIC2_DET_DB_MASK | WM8994_MIC2_SHRT_DB_MASK, |
3416 | WM8994_MIC1_DET_DB | WM8994_MIC1_SHRT_DB); | 3412 | WM8994_MIC1_DET_DB | WM8994_MIC1_SHRT_DB); |
3417 | 3413 | ||
3418 | snd_soc_dapm_sync(&codec->dapm); | 3414 | snd_soc_dapm_sync(dapm); |
3419 | 3415 | ||
3420 | return 0; | 3416 | return 0; |
3421 | } | 3417 | } |
@@ -3505,6 +3501,7 @@ static irqreturn_t wm8994_mic_irq(int irq, void *data) | |||
3505 | /* Should be called with accdet_lock held */ | 3501 | /* Should be called with accdet_lock held */ |
3506 | static void wm1811_micd_stop(struct snd_soc_codec *codec) | 3502 | static void wm1811_micd_stop(struct snd_soc_codec *codec) |
3507 | { | 3503 | { |
3504 | struct snd_soc_dapm_context *dapm = snd_soc_codec_get_dapm(codec); | ||
3508 | struct wm8994_priv *wm8994 = snd_soc_codec_get_drvdata(codec); | 3505 | struct wm8994_priv *wm8994 = snd_soc_codec_get_drvdata(codec); |
3509 | 3506 | ||
3510 | if (!wm8994->jackdet) | 3507 | if (!wm8994->jackdet) |
@@ -3515,8 +3512,7 @@ static void wm1811_micd_stop(struct snd_soc_codec *codec) | |||
3515 | wm1811_jackdet_set_mode(codec, WM1811_JACKDET_MODE_JACK); | 3512 | wm1811_jackdet_set_mode(codec, WM1811_JACKDET_MODE_JACK); |
3516 | 3513 | ||
3517 | if (wm8994->wm8994->pdata.jd_ext_cap) | 3514 | if (wm8994->wm8994->pdata.jd_ext_cap) |
3518 | snd_soc_dapm_disable_pin(&codec->dapm, | 3515 | snd_soc_dapm_disable_pin(dapm, "MICBIAS2"); |
3519 | "MICBIAS2"); | ||
3520 | } | 3516 | } |
3521 | 3517 | ||
3522 | static void wm8958_button_det(struct snd_soc_codec *codec, u16 status) | 3518 | static void wm8958_button_det(struct snd_soc_codec *codec, u16 status) |
@@ -3625,14 +3621,14 @@ static void wm1811_mic_work(struct work_struct *work) | |||
3625 | mic_work.work); | 3621 | mic_work.work); |
3626 | struct wm8994 *control = wm8994->wm8994; | 3622 | struct wm8994 *control = wm8994->wm8994; |
3627 | struct snd_soc_codec *codec = wm8994->hubs.codec; | 3623 | struct snd_soc_codec *codec = wm8994->hubs.codec; |
3624 | struct snd_soc_dapm_context *dapm = snd_soc_codec_get_dapm(codec); | ||
3628 | 3625 | ||
3629 | pm_runtime_get_sync(codec->dev); | 3626 | pm_runtime_get_sync(codec->dev); |
3630 | 3627 | ||
3631 | /* If required for an external cap force MICBIAS on */ | 3628 | /* If required for an external cap force MICBIAS on */ |
3632 | if (control->pdata.jd_ext_cap) { | 3629 | if (control->pdata.jd_ext_cap) { |
3633 | snd_soc_dapm_force_enable_pin(&codec->dapm, | 3630 | snd_soc_dapm_force_enable_pin(dapm, "MICBIAS2"); |
3634 | "MICBIAS2"); | 3631 | snd_soc_dapm_sync(dapm); |
3635 | snd_soc_dapm_sync(&codec->dapm); | ||
3636 | } | 3632 | } |
3637 | 3633 | ||
3638 | mutex_lock(&wm8994->accdet_lock); | 3634 | mutex_lock(&wm8994->accdet_lock); |
@@ -3664,6 +3660,7 @@ static irqreturn_t wm1811_jackdet_irq(int irq, void *data) | |||
3664 | struct wm8994_priv *wm8994 = data; | 3660 | struct wm8994_priv *wm8994 = data; |
3665 | struct wm8994 *control = wm8994->wm8994; | 3661 | struct wm8994 *control = wm8994->wm8994; |
3666 | struct snd_soc_codec *codec = wm8994->hubs.codec; | 3662 | struct snd_soc_codec *codec = wm8994->hubs.codec; |
3663 | struct snd_soc_dapm_context *dapm = snd_soc_codec_get_dapm(codec); | ||
3667 | int reg, delay; | 3664 | int reg, delay; |
3668 | bool present; | 3665 | bool present; |
3669 | 3666 | ||
@@ -3724,7 +3721,7 @@ static irqreturn_t wm1811_jackdet_irq(int irq, void *data) | |||
3724 | 3721 | ||
3725 | /* Turn off MICBIAS if it was on for an external cap */ | 3722 | /* Turn off MICBIAS if it was on for an external cap */ |
3726 | if (control->pdata.jd_ext_cap && !present) | 3723 | if (control->pdata.jd_ext_cap && !present) |
3727 | snd_soc_dapm_disable_pin(&codec->dapm, "MICBIAS2"); | 3724 | snd_soc_dapm_disable_pin(dapm, "MICBIAS2"); |
3728 | 3725 | ||
3729 | if (present) | 3726 | if (present) |
3730 | snd_soc_jack_report(wm8994->micdet[0].jack, | 3727 | snd_soc_jack_report(wm8994->micdet[0].jack, |
@@ -3770,6 +3767,7 @@ int wm8958_mic_detect(struct snd_soc_codec *codec, struct snd_soc_jack *jack, | |||
3770 | wm1811_micdet_cb det_cb, void *det_cb_data, | 3767 | wm1811_micdet_cb det_cb, void *det_cb_data, |
3771 | wm1811_mic_id_cb id_cb, void *id_cb_data) | 3768 | wm1811_mic_id_cb id_cb, void *id_cb_data) |
3772 | { | 3769 | { |
3770 | struct snd_soc_dapm_context *dapm = snd_soc_codec_get_dapm(codec); | ||
3773 | struct wm8994_priv *wm8994 = snd_soc_codec_get_drvdata(codec); | 3771 | struct wm8994_priv *wm8994 = snd_soc_codec_get_drvdata(codec); |
3774 | struct wm8994 *control = wm8994->wm8994; | 3772 | struct wm8994 *control = wm8994->wm8994; |
3775 | u16 micd_lvl_sel; | 3773 | u16 micd_lvl_sel; |
@@ -3783,8 +3781,8 @@ int wm8958_mic_detect(struct snd_soc_codec *codec, struct snd_soc_jack *jack, | |||
3783 | } | 3781 | } |
3784 | 3782 | ||
3785 | if (jack) { | 3783 | if (jack) { |
3786 | snd_soc_dapm_force_enable_pin(&codec->dapm, "CLK_SYS"); | 3784 | snd_soc_dapm_force_enable_pin(dapm, "CLK_SYS"); |
3787 | snd_soc_dapm_sync(&codec->dapm); | 3785 | snd_soc_dapm_sync(dapm); |
3788 | 3786 | ||
3789 | wm8994->micdet[0].jack = jack; | 3787 | wm8994->micdet[0].jack = jack; |
3790 | 3788 | ||
@@ -3819,7 +3817,7 @@ int wm8958_mic_detect(struct snd_soc_codec *codec, struct snd_soc_jack *jack, | |||
3819 | snd_soc_update_bits(codec, WM8958_MIC_DETECT_2, | 3817 | snd_soc_update_bits(codec, WM8958_MIC_DETECT_2, |
3820 | WM8958_MICD_LVL_SEL_MASK, micd_lvl_sel); | 3818 | WM8958_MICD_LVL_SEL_MASK, micd_lvl_sel); |
3821 | 3819 | ||
3822 | WARN_ON(codec->dapm.bias_level > SND_SOC_BIAS_STANDBY); | 3820 | WARN_ON(snd_soc_codec_get_bias_level(codec) > SND_SOC_BIAS_STANDBY); |
3823 | 3821 | ||
3824 | /* | 3822 | /* |
3825 | * If we can use jack detection start off with that, | 3823 | * If we can use jack detection start off with that, |
@@ -3846,8 +3844,8 @@ int wm8958_mic_detect(struct snd_soc_codec *codec, struct snd_soc_jack *jack, | |||
3846 | snd_soc_update_bits(codec, WM8958_MIC_DETECT_1, | 3844 | snd_soc_update_bits(codec, WM8958_MIC_DETECT_1, |
3847 | WM8958_MICD_ENA, 0); | 3845 | WM8958_MICD_ENA, 0); |
3848 | wm1811_jackdet_set_mode(codec, WM1811_JACKDET_MODE_NONE); | 3846 | wm1811_jackdet_set_mode(codec, WM1811_JACKDET_MODE_NONE); |
3849 | snd_soc_dapm_disable_pin(&codec->dapm, "CLK_SYS"); | 3847 | snd_soc_dapm_disable_pin(dapm, "CLK_SYS"); |
3850 | snd_soc_dapm_sync(&codec->dapm); | 3848 | snd_soc_dapm_sync(dapm); |
3851 | } | 3849 | } |
3852 | 3850 | ||
3853 | return 0; | 3851 | return 0; |
@@ -3985,9 +3983,9 @@ static irqreturn_t wm8994_temp_shut(int irq, void *data) | |||
3985 | 3983 | ||
3986 | static int wm8994_codec_probe(struct snd_soc_codec *codec) | 3984 | static int wm8994_codec_probe(struct snd_soc_codec *codec) |
3987 | { | 3985 | { |
3986 | struct snd_soc_dapm_context *dapm = snd_soc_codec_get_dapm(codec); | ||
3988 | struct wm8994 *control = dev_get_drvdata(codec->dev->parent); | 3987 | struct wm8994 *control = dev_get_drvdata(codec->dev->parent); |
3989 | struct wm8994_priv *wm8994 = snd_soc_codec_get_drvdata(codec); | 3988 | struct wm8994_priv *wm8994 = snd_soc_codec_get_drvdata(codec); |
3990 | struct snd_soc_dapm_context *dapm = &codec->dapm; | ||
3991 | unsigned int reg; | 3989 | unsigned int reg; |
3992 | int ret, i; | 3990 | int ret, i; |
3993 | 3991 | ||
@@ -4018,7 +4016,7 @@ static int wm8994_codec_probe(struct snd_soc_codec *codec) | |||
4018 | wm8994->micdet_irq = control->pdata.micdet_irq; | 4016 | wm8994->micdet_irq = control->pdata.micdet_irq; |
4019 | 4017 | ||
4020 | /* By default use idle_bias_off, will override for WM8994 */ | 4018 | /* By default use idle_bias_off, will override for WM8994 */ |
4021 | codec->dapm.idle_bias_off = 1; | 4019 | dapm->idle_bias_off = 1; |
4022 | 4020 | ||
4023 | /* Set revision-specific configuration */ | 4021 | /* Set revision-specific configuration */ |
4024 | switch (control->type) { | 4022 | switch (control->type) { |
@@ -4026,7 +4024,7 @@ static int wm8994_codec_probe(struct snd_soc_codec *codec) | |||
4026 | /* Single ended line outputs should have VMID on. */ | 4024 | /* Single ended line outputs should have VMID on. */ |
4027 | if (!control->pdata.lineout1_diff || | 4025 | if (!control->pdata.lineout1_diff || |
4028 | !control->pdata.lineout2_diff) | 4026 | !control->pdata.lineout2_diff) |
4029 | codec->dapm.idle_bias_off = 0; | 4027 | dapm->idle_bias_off = 0; |
4030 | 4028 | ||
4031 | switch (control->revision) { | 4029 | switch (control->revision) { |
4032 | case 2: | 4030 | case 2: |
@@ -4086,7 +4084,8 @@ static int wm8994_codec_probe(struct snd_soc_codec *codec) | |||
4086 | if (wm8994->micdet_irq) | 4084 | if (wm8994->micdet_irq) |
4087 | ret = request_threaded_irq(wm8994->micdet_irq, NULL, | 4085 | ret = request_threaded_irq(wm8994->micdet_irq, NULL, |
4088 | wm8994_mic_irq, | 4086 | wm8994_mic_irq, |
4089 | IRQF_TRIGGER_RISING, | 4087 | IRQF_TRIGGER_RISING | |
4088 | IRQF_ONESHOT, | ||
4090 | "Mic1 detect", | 4089 | "Mic1 detect", |
4091 | wm8994); | 4090 | wm8994); |
4092 | else | 4091 | else |
@@ -4134,7 +4133,8 @@ static int wm8994_codec_probe(struct snd_soc_codec *codec) | |||
4134 | if (wm8994->micdet_irq) { | 4133 | if (wm8994->micdet_irq) { |
4135 | ret = request_threaded_irq(wm8994->micdet_irq, NULL, | 4134 | ret = request_threaded_irq(wm8994->micdet_irq, NULL, |
4136 | wm8958_mic_irq, | 4135 | wm8958_mic_irq, |
4137 | IRQF_TRIGGER_RISING, | 4136 | IRQF_TRIGGER_RISING | |
4137 | IRQF_ONESHOT, | ||
4138 | "Mic detect", | 4138 | "Mic detect", |
4139 | wm8994); | 4139 | wm8994); |
4140 | if (ret != 0) | 4140 | if (ret != 0) |
diff --git a/sound/soc/codecs/wm8995.c b/sound/soc/codecs/wm8995.c index 66103c2b012e..687c4dd7ec99 100644 --- a/sound/soc/codecs/wm8995.c +++ b/sound/soc/codecs/wm8995.c | |||
@@ -721,6 +721,7 @@ static int configure_aif_clock(struct snd_soc_codec *codec, int aif) | |||
721 | 721 | ||
722 | static int configure_clock(struct snd_soc_codec *codec) | 722 | static int configure_clock(struct snd_soc_codec *codec) |
723 | { | 723 | { |
724 | struct snd_soc_dapm_context *dapm = snd_soc_codec_get_dapm(codec); | ||
724 | struct wm8995_priv *wm8995; | 725 | struct wm8995_priv *wm8995; |
725 | int change, new; | 726 | int change, new; |
726 | 727 | ||
@@ -751,7 +752,7 @@ static int configure_clock(struct snd_soc_codec *codec) | |||
751 | if (!change) | 752 | if (!change) |
752 | return 0; | 753 | return 0; |
753 | 754 | ||
754 | snd_soc_dapm_sync(&codec->dapm); | 755 | snd_soc_dapm_sync(dapm); |
755 | 756 | ||
756 | return 0; | 757 | return 0; |
757 | } | 758 | } |
@@ -1965,7 +1966,7 @@ static int wm8995_set_bias_level(struct snd_soc_codec *codec, | |||
1965 | case SND_SOC_BIAS_PREPARE: | 1966 | case SND_SOC_BIAS_PREPARE: |
1966 | break; | 1967 | break; |
1967 | case SND_SOC_BIAS_STANDBY: | 1968 | case SND_SOC_BIAS_STANDBY: |
1968 | if (codec->dapm.bias_level == SND_SOC_BIAS_OFF) { | 1969 | if (snd_soc_codec_get_bias_level(codec) == SND_SOC_BIAS_OFF) { |
1969 | ret = regulator_bulk_enable(ARRAY_SIZE(wm8995->supplies), | 1970 | ret = regulator_bulk_enable(ARRAY_SIZE(wm8995->supplies), |
1970 | wm8995->supplies); | 1971 | wm8995->supplies); |
1971 | if (ret) | 1972 | if (ret) |
@@ -1990,7 +1991,6 @@ static int wm8995_set_bias_level(struct snd_soc_codec *codec, | |||
1990 | break; | 1991 | break; |
1991 | } | 1992 | } |
1992 | 1993 | ||
1993 | codec->dapm.bias_level = level; | ||
1994 | return 0; | 1994 | return 0; |
1995 | } | 1995 | } |
1996 | 1996 | ||
diff --git a/sound/soc/codecs/wm8996.c b/sound/soc/codecs/wm8996.c index 308748a022c5..3dd063f682b2 100644 --- a/sound/soc/codecs/wm8996.c +++ b/sound/soc/codecs/wm8996.c | |||
@@ -1590,7 +1590,7 @@ static int wm8996_set_bias_level(struct snd_soc_codec *codec, | |||
1590 | break; | 1590 | break; |
1591 | 1591 | ||
1592 | case SND_SOC_BIAS_STANDBY: | 1592 | case SND_SOC_BIAS_STANDBY: |
1593 | if (codec->dapm.bias_level == SND_SOC_BIAS_OFF) { | 1593 | if (snd_soc_codec_get_bias_level(codec) == SND_SOC_BIAS_OFF) { |
1594 | ret = regulator_bulk_enable(ARRAY_SIZE(wm8996->supplies), | 1594 | ret = regulator_bulk_enable(ARRAY_SIZE(wm8996->supplies), |
1595 | wm8996->supplies); | 1595 | wm8996->supplies); |
1596 | if (ret != 0) { | 1596 | if (ret != 0) { |
@@ -1628,8 +1628,6 @@ static int wm8996_set_bias_level(struct snd_soc_codec *codec, | |||
1628 | break; | 1628 | break; |
1629 | } | 1629 | } |
1630 | 1630 | ||
1631 | codec->dapm.bias_level = level; | ||
1632 | |||
1633 | return 0; | 1631 | return 0; |
1634 | } | 1632 | } |
1635 | 1633 | ||
@@ -2247,7 +2245,7 @@ int wm8996_detect(struct snd_soc_codec *codec, struct snd_soc_jack *jack, | |||
2247 | wm8996_polarity_fn polarity_cb) | 2245 | wm8996_polarity_fn polarity_cb) |
2248 | { | 2246 | { |
2249 | struct wm8996_priv *wm8996 = snd_soc_codec_get_drvdata(codec); | 2247 | struct wm8996_priv *wm8996 = snd_soc_codec_get_drvdata(codec); |
2250 | struct snd_soc_dapm_context *dapm = &codec->dapm; | 2248 | struct snd_soc_dapm_context *dapm = snd_soc_codec_get_dapm(codec); |
2251 | 2249 | ||
2252 | wm8996->jack = jack; | 2250 | wm8996->jack = jack; |
2253 | wm8996->detecting = true; | 2251 | wm8996->detecting = true; |
@@ -2292,6 +2290,7 @@ EXPORT_SYMBOL_GPL(wm8996_detect); | |||
2292 | 2290 | ||
2293 | static void wm8996_hpdet_irq(struct snd_soc_codec *codec) | 2291 | static void wm8996_hpdet_irq(struct snd_soc_codec *codec) |
2294 | { | 2292 | { |
2293 | struct snd_soc_dapm_context *dapm = snd_soc_codec_get_dapm(codec); | ||
2295 | struct wm8996_priv *wm8996 = snd_soc_codec_get_drvdata(codec); | 2294 | struct wm8996_priv *wm8996 = snd_soc_codec_get_drvdata(codec); |
2296 | int val, reg, report; | 2295 | int val, reg, report; |
2297 | 2296 | ||
@@ -2345,12 +2344,14 @@ out: | |||
2345 | snd_soc_update_bits(codec, WM8996_MIC_DETECT_1, WM8996_MICD_ENA, | 2344 | snd_soc_update_bits(codec, WM8996_MIC_DETECT_1, WM8996_MICD_ENA, |
2346 | WM8996_MICD_ENA); | 2345 | WM8996_MICD_ENA); |
2347 | 2346 | ||
2348 | snd_soc_dapm_disable_pin(&codec->dapm, "Bandgap"); | 2347 | snd_soc_dapm_disable_pin(dapm, "Bandgap"); |
2349 | snd_soc_dapm_sync(&codec->dapm); | 2348 | snd_soc_dapm_sync(dapm); |
2350 | } | 2349 | } |
2351 | 2350 | ||
2352 | static void wm8996_hpdet_start(struct snd_soc_codec *codec) | 2351 | static void wm8996_hpdet_start(struct snd_soc_codec *codec) |
2353 | { | 2352 | { |
2353 | struct snd_soc_dapm_context *dapm = snd_soc_codec_get_dapm(codec); | ||
2354 | |||
2354 | /* Unclamp the output, we can't measure while we're shorting it */ | 2355 | /* Unclamp the output, we can't measure while we're shorting it */ |
2355 | snd_soc_update_bits(codec, WM8996_ANALOGUE_HP_1, | 2356 | snd_soc_update_bits(codec, WM8996_ANALOGUE_HP_1, |
2356 | WM8996_HPOUT1L_RMV_SHORT | | 2357 | WM8996_HPOUT1L_RMV_SHORT | |
@@ -2359,8 +2360,8 @@ static void wm8996_hpdet_start(struct snd_soc_codec *codec) | |||
2359 | WM8996_HPOUT1R_RMV_SHORT); | 2360 | WM8996_HPOUT1R_RMV_SHORT); |
2360 | 2361 | ||
2361 | /* We need bandgap for HPDET */ | 2362 | /* We need bandgap for HPDET */ |
2362 | snd_soc_dapm_force_enable_pin(&codec->dapm, "Bandgap"); | 2363 | snd_soc_dapm_force_enable_pin(dapm, "Bandgap"); |
2363 | snd_soc_dapm_sync(&codec->dapm); | 2364 | snd_soc_dapm_sync(dapm); |
2364 | 2365 | ||
2365 | /* Go into headphone detect left mode */ | 2366 | /* Go into headphone detect left mode */ |
2366 | snd_soc_update_bits(codec, WM8996_MIC_DETECT_1, WM8996_MICD_ENA, 0); | 2367 | snd_soc_update_bits(codec, WM8996_MIC_DETECT_1, WM8996_MICD_ENA, 0); |
@@ -2646,10 +2647,12 @@ static int wm8996_probe(struct snd_soc_codec *codec) | |||
2646 | if (irq_flags & (IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING)) | 2647 | if (irq_flags & (IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING)) |
2647 | ret = request_threaded_irq(i2c->irq, NULL, | 2648 | ret = request_threaded_irq(i2c->irq, NULL, |
2648 | wm8996_edge_irq, | 2649 | wm8996_edge_irq, |
2649 | irq_flags, "wm8996", codec); | 2650 | irq_flags | IRQF_ONESHOT, |
2651 | "wm8996", codec); | ||
2650 | else | 2652 | else |
2651 | ret = request_threaded_irq(i2c->irq, NULL, wm8996_irq, | 2653 | ret = request_threaded_irq(i2c->irq, NULL, wm8996_irq, |
2652 | irq_flags, "wm8996", codec); | 2654 | irq_flags | IRQF_ONESHOT, |
2655 | "wm8996", codec); | ||
2653 | 2656 | ||
2654 | if (ret == 0) { | 2657 | if (ret == 0) { |
2655 | /* Unmask the interrupt */ | 2658 | /* Unmask the interrupt */ |
diff --git a/sound/soc/codecs/wm8997.c b/sound/soc/codecs/wm8997.c index a4d11770630c..4134dc7e1243 100644 --- a/sound/soc/codecs/wm8997.c +++ b/sound/soc/codecs/wm8997.c | |||
@@ -40,7 +40,7 @@ struct wm8997_priv { | |||
40 | static DECLARE_TLV_DB_SCALE(ana_tlv, 0, 100, 0); | 40 | static DECLARE_TLV_DB_SCALE(ana_tlv, 0, 100, 0); |
41 | static DECLARE_TLV_DB_SCALE(eq_tlv, -1200, 100, 0); | 41 | static DECLARE_TLV_DB_SCALE(eq_tlv, -1200, 100, 0); |
42 | static DECLARE_TLV_DB_SCALE(digital_tlv, -6400, 50, 0); | 42 | static DECLARE_TLV_DB_SCALE(digital_tlv, -6400, 50, 0); |
43 | static DECLARE_TLV_DB_SCALE(noise_tlv, 0, 600, 0); | 43 | static DECLARE_TLV_DB_SCALE(noise_tlv, -13200, 600, 0); |
44 | static DECLARE_TLV_DB_SCALE(ng_tlv, -10200, 600, 0); | 44 | static DECLARE_TLV_DB_SCALE(ng_tlv, -10200, 600, 0); |
45 | 45 | ||
46 | static const struct reg_default wm8997_sysclk_reva_patch[] = { | 46 | static const struct reg_default wm8997_sysclk_reva_patch[] = { |
@@ -106,11 +106,13 @@ static int wm8997_sysclk_ev(struct snd_soc_dapm_widget *w, | |||
106 | regmap_write_async(regmap, patch[i].reg, | 106 | regmap_write_async(regmap, patch[i].reg, |
107 | patch[i].def); | 107 | patch[i].def); |
108 | break; | 108 | break; |
109 | default: | 109 | case SND_SOC_DAPM_PRE_PMD: |
110 | break; | 110 | break; |
111 | default: | ||
112 | return 0; | ||
111 | } | 113 | } |
112 | 114 | ||
113 | return 0; | 115 | return arizona_dvfs_sysclk_ev(w, kcontrol, event); |
114 | } | 116 | } |
115 | 117 | ||
116 | static const char *wm8997_osr_text[] = { | 118 | static const char *wm8997_osr_text[] = { |
@@ -409,7 +411,8 @@ static const struct snd_kcontrol_new wm8997_aec_loopback_mux = | |||
409 | 411 | ||
410 | static const struct snd_soc_dapm_widget wm8997_dapm_widgets[] = { | 412 | static const struct snd_soc_dapm_widget wm8997_dapm_widgets[] = { |
411 | SND_SOC_DAPM_SUPPLY("SYSCLK", ARIZONA_SYSTEM_CLOCK_1, ARIZONA_SYSCLK_ENA_SHIFT, | 413 | SND_SOC_DAPM_SUPPLY("SYSCLK", ARIZONA_SYSTEM_CLOCK_1, ARIZONA_SYSCLK_ENA_SHIFT, |
412 | 0, wm8997_sysclk_ev, SND_SOC_DAPM_POST_PMU), | 414 | 0, wm8997_sysclk_ev, |
415 | SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD), | ||
413 | SND_SOC_DAPM_SUPPLY("ASYNCCLK", ARIZONA_ASYNC_CLOCK_1, | 416 | SND_SOC_DAPM_SUPPLY("ASYNCCLK", ARIZONA_ASYNC_CLOCK_1, |
414 | ARIZONA_ASYNC_CLK_ENA_SHIFT, 0, NULL, 0), | 417 | ARIZONA_ASYNC_CLK_ENA_SHIFT, 0, NULL, 0), |
415 | SND_SOC_DAPM_SUPPLY("OPCLK", ARIZONA_OUTPUT_SYSTEM_CLOCK, | 418 | SND_SOC_DAPM_SUPPLY("OPCLK", ARIZONA_OUTPUT_SYSTEM_CLOCK, |
@@ -1055,13 +1058,14 @@ static struct snd_soc_dai_driver wm8997_dai[] = { | |||
1055 | 1058 | ||
1056 | static int wm8997_codec_probe(struct snd_soc_codec *codec) | 1059 | static int wm8997_codec_probe(struct snd_soc_codec *codec) |
1057 | { | 1060 | { |
1061 | struct snd_soc_dapm_context *dapm = snd_soc_codec_get_dapm(codec); | ||
1058 | struct wm8997_priv *priv = snd_soc_codec_get_drvdata(codec); | 1062 | struct wm8997_priv *priv = snd_soc_codec_get_drvdata(codec); |
1059 | 1063 | ||
1060 | arizona_init_spk(codec); | 1064 | arizona_init_spk(codec); |
1061 | 1065 | ||
1062 | snd_soc_dapm_disable_pin(&codec->dapm, "HAPTICS"); | 1066 | snd_soc_dapm_disable_pin(dapm, "HAPTICS"); |
1063 | 1067 | ||
1064 | priv->core.arizona->dapm = &codec->dapm; | 1068 | priv->core.arizona->dapm = dapm; |
1065 | 1069 | ||
1066 | return 0; | 1070 | return 0; |
1067 | } | 1071 | } |
@@ -1126,6 +1130,8 @@ static int wm8997_probe(struct platform_device *pdev) | |||
1126 | wm8997->core.arizona = arizona; | 1130 | wm8997->core.arizona = arizona; |
1127 | wm8997->core.num_inputs = 4; | 1131 | wm8997->core.num_inputs = 4; |
1128 | 1132 | ||
1133 | arizona_init_dvfs(&wm8997->core); | ||
1134 | |||
1129 | for (i = 0; i < ARRAY_SIZE(wm8997->fll); i++) | 1135 | for (i = 0; i < ARRAY_SIZE(wm8997->fll); i++) |
1130 | wm8997->fll[i].vco_mult = 1; | 1136 | wm8997->fll[i].vco_mult = 1; |
1131 | 1137 | ||
diff --git a/sound/soc/codecs/wm9081.c b/sound/soc/codecs/wm9081.c index 13a3f335ea5b..8a8b1c0f9142 100644 --- a/sound/soc/codecs/wm9081.c +++ b/sound/soc/codecs/wm9081.c | |||
@@ -838,7 +838,7 @@ static int wm9081_set_bias_level(struct snd_soc_codec *codec, | |||
838 | 838 | ||
839 | case SND_SOC_BIAS_STANDBY: | 839 | case SND_SOC_BIAS_STANDBY: |
840 | /* Initial cold start */ | 840 | /* Initial cold start */ |
841 | if (codec->dapm.bias_level == SND_SOC_BIAS_OFF) { | 841 | if (snd_soc_codec_get_bias_level(codec) == SND_SOC_BIAS_OFF) { |
842 | regcache_cache_only(wm9081->regmap, false); | 842 | regcache_cache_only(wm9081->regmap, false); |
843 | regcache_sync(wm9081->regmap); | 843 | regcache_sync(wm9081->regmap); |
844 | 844 | ||
@@ -898,8 +898,6 @@ static int wm9081_set_bias_level(struct snd_soc_codec *codec, | |||
898 | break; | 898 | break; |
899 | } | 899 | } |
900 | 900 | ||
901 | codec->dapm.bias_level = level; | ||
902 | |||
903 | return 0; | 901 | return 0; |
904 | } | 902 | } |
905 | 903 | ||
diff --git a/sound/soc/codecs/wm9090.c b/sound/soc/codecs/wm9090.c index 60d243c904f5..13d23fc797db 100644 --- a/sound/soc/codecs/wm9090.c +++ b/sound/soc/codecs/wm9090.c | |||
@@ -425,7 +425,7 @@ static const struct snd_soc_dapm_route audio_map_in2_diff[] = { | |||
425 | static int wm9090_add_controls(struct snd_soc_codec *codec) | 425 | static int wm9090_add_controls(struct snd_soc_codec *codec) |
426 | { | 426 | { |
427 | struct wm9090_priv *wm9090 = snd_soc_codec_get_drvdata(codec); | 427 | struct wm9090_priv *wm9090 = snd_soc_codec_get_drvdata(codec); |
428 | struct snd_soc_dapm_context *dapm = &codec->dapm; | 428 | struct snd_soc_dapm_context *dapm = snd_soc_codec_get_dapm(codec); |
429 | int i; | 429 | int i; |
430 | 430 | ||
431 | snd_soc_dapm_new_controls(dapm, wm9090_dapm_widgets, | 431 | snd_soc_dapm_new_controls(dapm, wm9090_dapm_widgets, |
@@ -496,7 +496,7 @@ static int wm9090_set_bias_level(struct snd_soc_codec *codec, | |||
496 | break; | 496 | break; |
497 | 497 | ||
498 | case SND_SOC_BIAS_STANDBY: | 498 | case SND_SOC_BIAS_STANDBY: |
499 | if (codec->dapm.bias_level == SND_SOC_BIAS_OFF) { | 499 | if (snd_soc_codec_get_bias_level(codec) == SND_SOC_BIAS_OFF) { |
500 | /* Restore the register cache */ | 500 | /* Restore the register cache */ |
501 | regcache_sync(wm9090->regmap); | 501 | regcache_sync(wm9090->regmap); |
502 | } | 502 | } |
@@ -515,8 +515,6 @@ static int wm9090_set_bias_level(struct snd_soc_codec *codec, | |||
515 | break; | 515 | break; |
516 | } | 516 | } |
517 | 517 | ||
518 | codec->dapm.bias_level = level; | ||
519 | |||
520 | return 0; | 518 | return 0; |
521 | } | 519 | } |
522 | 520 | ||
diff --git a/sound/soc/codecs/wm9712.c b/sound/soc/codecs/wm9712.c index 98c9525bd751..1fda104dfc45 100644 --- a/sound/soc/codecs/wm9712.c +++ b/sound/soc/codecs/wm9712.c | |||
@@ -610,7 +610,6 @@ static int wm9712_set_bias_level(struct snd_soc_codec *codec, | |||
610 | ac97_write(codec, AC97_POWERDOWN, 0xffff); | 610 | ac97_write(codec, AC97_POWERDOWN, 0xffff); |
611 | break; | 611 | break; |
612 | } | 612 | } |
613 | codec->dapm.bias_level = level; | ||
614 | return 0; | 613 | return 0; |
615 | } | 614 | } |
616 | 615 | ||
@@ -646,7 +645,7 @@ static int wm9712_soc_resume(struct snd_soc_codec *codec) | |||
646 | if (ret < 0) | 645 | if (ret < 0) |
647 | return ret; | 646 | return ret; |
648 | 647 | ||
649 | wm9712_set_bias_level(codec, SND_SOC_BIAS_STANDBY); | 648 | snd_soc_codec_force_bias_level(codec, SND_SOC_BIAS_STANDBY); |
650 | 649 | ||
651 | if (ret == 0) { | 650 | if (ret == 0) { |
652 | /* Sync reg_cache with the hardware after cold reset */ | 651 | /* Sync reg_cache with the hardware after cold reset */ |
diff --git a/sound/soc/codecs/wm9713.c b/sound/soc/codecs/wm9713.c index 79552953e1bd..89cd2d6f57c0 100644 --- a/sound/soc/codecs/wm9713.c +++ b/sound/soc/codecs/wm9713.c | |||
@@ -1054,8 +1054,8 @@ static int ac97_aux_prepare(struct snd_pcm_substream *substream, | |||
1054 | SNDRV_PCM_RATE_48000) | 1054 | SNDRV_PCM_RATE_48000) |
1055 | 1055 | ||
1056 | #define WM9713_PCM_FORMATS \ | 1056 | #define WM9713_PCM_FORMATS \ |
1057 | (SNDRV_PCM_FORMAT_S16_LE | SNDRV_PCM_FORMAT_S20_3LE | \ | 1057 | (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE | \ |
1058 | SNDRV_PCM_FORMAT_S24_LE) | 1058 | SNDRV_PCM_FMTBIT_S24_LE) |
1059 | 1059 | ||
1060 | static const struct snd_soc_dai_ops wm9713_dai_ops_hifi = { | 1060 | static const struct snd_soc_dai_ops wm9713_dai_ops_hifi = { |
1061 | .prepare = ac97_hifi_prepare, | 1061 | .prepare = ac97_hifi_prepare, |
@@ -1171,7 +1171,6 @@ static int wm9713_set_bias_level(struct snd_soc_codec *codec, | |||
1171 | ac97_write(codec, AC97_POWERDOWN, 0xffff); | 1171 | ac97_write(codec, AC97_POWERDOWN, 0xffff); |
1172 | break; | 1172 | break; |
1173 | } | 1173 | } |
1174 | codec->dapm.bias_level = level; | ||
1175 | return 0; | 1174 | return 0; |
1176 | } | 1175 | } |
1177 | 1176 | ||
@@ -1201,7 +1200,7 @@ static int wm9713_soc_resume(struct snd_soc_codec *codec) | |||
1201 | if (ret < 0) | 1200 | if (ret < 0) |
1202 | return ret; | 1201 | return ret; |
1203 | 1202 | ||
1204 | wm9713_set_bias_level(codec, SND_SOC_BIAS_STANDBY); | 1203 | snd_soc_codec_force_bias_level(codec, SND_SOC_BIAS_STANDBY); |
1205 | 1204 | ||
1206 | /* do we need to re-start the PLL ? */ | 1205 | /* do we need to re-start the PLL ? */ |
1207 | if (wm9713->pll_in) | 1206 | if (wm9713->pll_in) |
diff --git a/sound/soc/codecs/wm_adsp.c b/sound/soc/codecs/wm_adsp.c index d01c2095452f..f9f90b0f5db4 100644 --- a/sound/soc/codecs/wm_adsp.c +++ b/sound/soc/codecs/wm_adsp.c | |||
@@ -23,6 +23,7 @@ | |||
23 | #include <linux/slab.h> | 23 | #include <linux/slab.h> |
24 | #include <linux/vmalloc.h> | 24 | #include <linux/vmalloc.h> |
25 | #include <linux/workqueue.h> | 25 | #include <linux/workqueue.h> |
26 | #include <linux/debugfs.h> | ||
26 | #include <sound/core.h> | 27 | #include <sound/core.h> |
27 | #include <sound/pcm.h> | 28 | #include <sound/pcm.h> |
28 | #include <sound/pcm_params.h> | 29 | #include <sound/pcm_params.h> |
@@ -121,6 +122,11 @@ | |||
121 | #define ADSP2_WDMA_CONFIG_2 0x31 | 122 | #define ADSP2_WDMA_CONFIG_2 0x31 |
122 | #define ADSP2_RDMA_CONFIG_1 0x34 | 123 | #define ADSP2_RDMA_CONFIG_1 0x34 |
123 | 124 | ||
125 | #define ADSP2_SCRATCH0 0x40 | ||
126 | #define ADSP2_SCRATCH1 0x41 | ||
127 | #define ADSP2_SCRATCH2 0x42 | ||
128 | #define ADSP2_SCRATCH3 0x43 | ||
129 | |||
124 | /* | 130 | /* |
125 | * ADSP2 Control | 131 | * ADSP2 Control |
126 | */ | 132 | */ |
@@ -229,26 +235,197 @@ struct wm_coeff_ctl_ops { | |||
229 | 235 | ||
230 | struct wm_coeff_ctl { | 236 | struct wm_coeff_ctl { |
231 | const char *name; | 237 | const char *name; |
232 | struct wm_adsp_alg_region region; | 238 | const char *fw_name; |
239 | struct wm_adsp_alg_region alg_region; | ||
233 | struct wm_coeff_ctl_ops ops; | 240 | struct wm_coeff_ctl_ops ops; |
234 | struct wm_adsp *adsp; | 241 | struct wm_adsp *dsp; |
235 | void *private; | ||
236 | unsigned int enabled:1; | 242 | unsigned int enabled:1; |
237 | struct list_head list; | 243 | struct list_head list; |
238 | void *cache; | 244 | void *cache; |
245 | unsigned int offset; | ||
239 | size_t len; | 246 | size_t len; |
240 | unsigned int set:1; | 247 | unsigned int set:1; |
241 | struct snd_kcontrol *kcontrol; | 248 | struct snd_kcontrol *kcontrol; |
249 | unsigned int flags; | ||
242 | }; | 250 | }; |
243 | 251 | ||
252 | #ifdef CONFIG_DEBUG_FS | ||
253 | static void wm_adsp_debugfs_save_wmfwname(struct wm_adsp *dsp, const char *s) | ||
254 | { | ||
255 | char *tmp = kasprintf(GFP_KERNEL, "%s\n", s); | ||
256 | |||
257 | mutex_lock(&dsp->debugfs_lock); | ||
258 | kfree(dsp->wmfw_file_name); | ||
259 | dsp->wmfw_file_name = tmp; | ||
260 | mutex_unlock(&dsp->debugfs_lock); | ||
261 | } | ||
262 | |||
263 | static void wm_adsp_debugfs_save_binname(struct wm_adsp *dsp, const char *s) | ||
264 | { | ||
265 | char *tmp = kasprintf(GFP_KERNEL, "%s\n", s); | ||
266 | |||
267 | mutex_lock(&dsp->debugfs_lock); | ||
268 | kfree(dsp->bin_file_name); | ||
269 | dsp->bin_file_name = tmp; | ||
270 | mutex_unlock(&dsp->debugfs_lock); | ||
271 | } | ||
272 | |||
273 | static void wm_adsp_debugfs_clear(struct wm_adsp *dsp) | ||
274 | { | ||
275 | mutex_lock(&dsp->debugfs_lock); | ||
276 | kfree(dsp->wmfw_file_name); | ||
277 | kfree(dsp->bin_file_name); | ||
278 | dsp->wmfw_file_name = NULL; | ||
279 | dsp->bin_file_name = NULL; | ||
280 | mutex_unlock(&dsp->debugfs_lock); | ||
281 | } | ||
282 | |||
283 | static ssize_t wm_adsp_debugfs_wmfw_read(struct file *file, | ||
284 | char __user *user_buf, | ||
285 | size_t count, loff_t *ppos) | ||
286 | { | ||
287 | struct wm_adsp *dsp = file->private_data; | ||
288 | ssize_t ret; | ||
289 | |||
290 | mutex_lock(&dsp->debugfs_lock); | ||
291 | |||
292 | if (!dsp->wmfw_file_name || !dsp->running) | ||
293 | ret = 0; | ||
294 | else | ||
295 | ret = simple_read_from_buffer(user_buf, count, ppos, | ||
296 | dsp->wmfw_file_name, | ||
297 | strlen(dsp->wmfw_file_name)); | ||
298 | |||
299 | mutex_unlock(&dsp->debugfs_lock); | ||
300 | return ret; | ||
301 | } | ||
302 | |||
303 | static ssize_t wm_adsp_debugfs_bin_read(struct file *file, | ||
304 | char __user *user_buf, | ||
305 | size_t count, loff_t *ppos) | ||
306 | { | ||
307 | struct wm_adsp *dsp = file->private_data; | ||
308 | ssize_t ret; | ||
309 | |||
310 | mutex_lock(&dsp->debugfs_lock); | ||
311 | |||
312 | if (!dsp->bin_file_name || !dsp->running) | ||
313 | ret = 0; | ||
314 | else | ||
315 | ret = simple_read_from_buffer(user_buf, count, ppos, | ||
316 | dsp->bin_file_name, | ||
317 | strlen(dsp->bin_file_name)); | ||
318 | |||
319 | mutex_unlock(&dsp->debugfs_lock); | ||
320 | return ret; | ||
321 | } | ||
322 | |||
323 | static const struct { | ||
324 | const char *name; | ||
325 | const struct file_operations fops; | ||
326 | } wm_adsp_debugfs_fops[] = { | ||
327 | { | ||
328 | .name = "wmfw_file_name", | ||
329 | .fops = { | ||
330 | .open = simple_open, | ||
331 | .read = wm_adsp_debugfs_wmfw_read, | ||
332 | }, | ||
333 | }, | ||
334 | { | ||
335 | .name = "bin_file_name", | ||
336 | .fops = { | ||
337 | .open = simple_open, | ||
338 | .read = wm_adsp_debugfs_bin_read, | ||
339 | }, | ||
340 | }, | ||
341 | }; | ||
342 | |||
343 | static void wm_adsp2_init_debugfs(struct wm_adsp *dsp, | ||
344 | struct snd_soc_codec *codec) | ||
345 | { | ||
346 | struct dentry *root = NULL; | ||
347 | char *root_name; | ||
348 | int i; | ||
349 | |||
350 | if (!codec->component.debugfs_root) { | ||
351 | adsp_err(dsp, "No codec debugfs root\n"); | ||
352 | goto err; | ||
353 | } | ||
354 | |||
355 | root_name = kmalloc(PAGE_SIZE, GFP_KERNEL); | ||
356 | if (!root_name) | ||
357 | goto err; | ||
358 | |||
359 | snprintf(root_name, PAGE_SIZE, "dsp%d", dsp->num); | ||
360 | root = debugfs_create_dir(root_name, codec->component.debugfs_root); | ||
361 | kfree(root_name); | ||
362 | |||
363 | if (!root) | ||
364 | goto err; | ||
365 | |||
366 | if (!debugfs_create_bool("running", S_IRUGO, root, &dsp->running)) | ||
367 | goto err; | ||
368 | |||
369 | if (!debugfs_create_x32("fw_id", S_IRUGO, root, &dsp->fw_id)) | ||
370 | goto err; | ||
371 | |||
372 | if (!debugfs_create_x32("fw_version", S_IRUGO, root, | ||
373 | &dsp->fw_id_version)) | ||
374 | goto err; | ||
375 | |||
376 | for (i = 0; i < ARRAY_SIZE(wm_adsp_debugfs_fops); ++i) { | ||
377 | if (!debugfs_create_file(wm_adsp_debugfs_fops[i].name, | ||
378 | S_IRUGO, root, dsp, | ||
379 | &wm_adsp_debugfs_fops[i].fops)) | ||
380 | goto err; | ||
381 | } | ||
382 | |||
383 | dsp->debugfs_root = root; | ||
384 | return; | ||
385 | |||
386 | err: | ||
387 | debugfs_remove_recursive(root); | ||
388 | adsp_err(dsp, "Failed to create debugfs\n"); | ||
389 | } | ||
390 | |||
391 | static void wm_adsp2_cleanup_debugfs(struct wm_adsp *dsp) | ||
392 | { | ||
393 | wm_adsp_debugfs_clear(dsp); | ||
394 | debugfs_remove_recursive(dsp->debugfs_root); | ||
395 | } | ||
396 | #else | ||
397 | static inline void wm_adsp2_init_debugfs(struct wm_adsp *dsp, | ||
398 | struct snd_soc_codec *codec) | ||
399 | { | ||
400 | } | ||
401 | |||
402 | static inline void wm_adsp2_cleanup_debugfs(struct wm_adsp *dsp) | ||
403 | { | ||
404 | } | ||
405 | |||
406 | static inline void wm_adsp_debugfs_save_wmfwname(struct wm_adsp *dsp, | ||
407 | const char *s) | ||
408 | { | ||
409 | } | ||
410 | |||
411 | static inline void wm_adsp_debugfs_save_binname(struct wm_adsp *dsp, | ||
412 | const char *s) | ||
413 | { | ||
414 | } | ||
415 | |||
416 | static inline void wm_adsp_debugfs_clear(struct wm_adsp *dsp) | ||
417 | { | ||
418 | } | ||
419 | #endif | ||
420 | |||
244 | static int wm_adsp_fw_get(struct snd_kcontrol *kcontrol, | 421 | static int wm_adsp_fw_get(struct snd_kcontrol *kcontrol, |
245 | struct snd_ctl_elem_value *ucontrol) | 422 | struct snd_ctl_elem_value *ucontrol) |
246 | { | 423 | { |
247 | struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol); | 424 | struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol); |
248 | struct soc_enum *e = (struct soc_enum *)kcontrol->private_value; | 425 | struct soc_enum *e = (struct soc_enum *)kcontrol->private_value; |
249 | struct wm_adsp *adsp = snd_soc_codec_get_drvdata(codec); | 426 | struct wm_adsp *dsp = snd_soc_codec_get_drvdata(codec); |
250 | 427 | ||
251 | ucontrol->value.integer.value[0] = adsp[e->shift_l].fw; | 428 | ucontrol->value.integer.value[0] = dsp[e->shift_l].fw; |
252 | 429 | ||
253 | return 0; | 430 | return 0; |
254 | } | 431 | } |
@@ -258,18 +435,18 @@ static int wm_adsp_fw_put(struct snd_kcontrol *kcontrol, | |||
258 | { | 435 | { |
259 | struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol); | 436 | struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol); |
260 | struct soc_enum *e = (struct soc_enum *)kcontrol->private_value; | 437 | struct soc_enum *e = (struct soc_enum *)kcontrol->private_value; |
261 | struct wm_adsp *adsp = snd_soc_codec_get_drvdata(codec); | 438 | struct wm_adsp *dsp = snd_soc_codec_get_drvdata(codec); |
262 | 439 | ||
263 | if (ucontrol->value.integer.value[0] == adsp[e->shift_l].fw) | 440 | if (ucontrol->value.integer.value[0] == dsp[e->shift_l].fw) |
264 | return 0; | 441 | return 0; |
265 | 442 | ||
266 | if (ucontrol->value.integer.value[0] >= WM_ADSP_NUM_FW) | 443 | if (ucontrol->value.integer.value[0] >= WM_ADSP_NUM_FW) |
267 | return -EINVAL; | 444 | return -EINVAL; |
268 | 445 | ||
269 | if (adsp[e->shift_l].running) | 446 | if (dsp[e->shift_l].running) |
270 | return -EBUSY; | 447 | return -EBUSY; |
271 | 448 | ||
272 | adsp[e->shift_l].fw = ucontrol->value.integer.value[0]; | 449 | dsp[e->shift_l].fw = ucontrol->value.integer.value[0]; |
273 | 450 | ||
274 | return 0; | 451 | return 0; |
275 | } | 452 | } |
@@ -291,7 +468,6 @@ const struct snd_kcontrol_new wm_adsp1_fw_controls[] = { | |||
291 | }; | 468 | }; |
292 | EXPORT_SYMBOL_GPL(wm_adsp1_fw_controls); | 469 | EXPORT_SYMBOL_GPL(wm_adsp1_fw_controls); |
293 | 470 | ||
294 | #if IS_ENABLED(CONFIG_SND_SOC_ARIZONA) | ||
295 | static const struct soc_enum wm_adsp2_rate_enum[] = { | 471 | static const struct soc_enum wm_adsp2_rate_enum[] = { |
296 | SOC_VALUE_ENUM_SINGLE(ARIZONA_DSP1_CONTROL_1, | 472 | SOC_VALUE_ENUM_SINGLE(ARIZONA_DSP1_CONTROL_1, |
297 | ARIZONA_DSP1_RATE_SHIFT, 0xf, | 473 | ARIZONA_DSP1_RATE_SHIFT, 0xf, |
@@ -311,22 +487,28 @@ static const struct soc_enum wm_adsp2_rate_enum[] = { | |||
311 | arizona_rate_text, arizona_rate_val), | 487 | arizona_rate_text, arizona_rate_val), |
312 | }; | 488 | }; |
313 | 489 | ||
314 | const struct snd_kcontrol_new wm_adsp2_fw_controls[] = { | 490 | static const struct snd_kcontrol_new wm_adsp2_fw_controls[4][2] = { |
315 | SOC_ENUM_EXT("DSP1 Firmware", wm_adsp_fw_enum[0], | 491 | { |
316 | wm_adsp_fw_get, wm_adsp_fw_put), | 492 | SOC_ENUM_EXT("DSP1 Firmware", wm_adsp_fw_enum[0], |
317 | SOC_ENUM("DSP1 Rate", wm_adsp2_rate_enum[0]), | 493 | wm_adsp_fw_get, wm_adsp_fw_put), |
318 | SOC_ENUM_EXT("DSP2 Firmware", wm_adsp_fw_enum[1], | 494 | SOC_ENUM("DSP1 Rate", wm_adsp2_rate_enum[0]), |
319 | wm_adsp_fw_get, wm_adsp_fw_put), | 495 | }, |
320 | SOC_ENUM("DSP2 Rate", wm_adsp2_rate_enum[1]), | 496 | { |
321 | SOC_ENUM_EXT("DSP3 Firmware", wm_adsp_fw_enum[2], | 497 | SOC_ENUM_EXT("DSP2 Firmware", wm_adsp_fw_enum[1], |
322 | wm_adsp_fw_get, wm_adsp_fw_put), | 498 | wm_adsp_fw_get, wm_adsp_fw_put), |
323 | SOC_ENUM("DSP3 Rate", wm_adsp2_rate_enum[2]), | 499 | SOC_ENUM("DSP2 Rate", wm_adsp2_rate_enum[1]), |
324 | SOC_ENUM_EXT("DSP4 Firmware", wm_adsp_fw_enum[3], | 500 | }, |
325 | wm_adsp_fw_get, wm_adsp_fw_put), | 501 | { |
326 | SOC_ENUM("DSP4 Rate", wm_adsp2_rate_enum[3]), | 502 | SOC_ENUM_EXT("DSP3 Firmware", wm_adsp_fw_enum[2], |
503 | wm_adsp_fw_get, wm_adsp_fw_put), | ||
504 | SOC_ENUM("DSP3 Rate", wm_adsp2_rate_enum[2]), | ||
505 | }, | ||
506 | { | ||
507 | SOC_ENUM_EXT("DSP4 Firmware", wm_adsp_fw_enum[3], | ||
508 | wm_adsp_fw_get, wm_adsp_fw_put), | ||
509 | SOC_ENUM("DSP4 Rate", wm_adsp2_rate_enum[3]), | ||
510 | }, | ||
327 | }; | 511 | }; |
328 | EXPORT_SYMBOL_GPL(wm_adsp2_fw_controls); | ||
329 | #endif | ||
330 | 512 | ||
331 | static struct wm_adsp_region const *wm_adsp_find_region(struct wm_adsp *dsp, | 513 | static struct wm_adsp_region const *wm_adsp_find_region(struct wm_adsp *dsp, |
332 | int type) | 514 | int type) |
@@ -340,28 +522,47 @@ static struct wm_adsp_region const *wm_adsp_find_region(struct wm_adsp *dsp, | |||
340 | return NULL; | 522 | return NULL; |
341 | } | 523 | } |
342 | 524 | ||
343 | static unsigned int wm_adsp_region_to_reg(struct wm_adsp_region const *region, | 525 | static unsigned int wm_adsp_region_to_reg(struct wm_adsp_region const *mem, |
344 | unsigned int offset) | 526 | unsigned int offset) |
345 | { | 527 | { |
346 | if (WARN_ON(!region)) | 528 | if (WARN_ON(!mem)) |
347 | return offset; | 529 | return offset; |
348 | switch (region->type) { | 530 | switch (mem->type) { |
349 | case WMFW_ADSP1_PM: | 531 | case WMFW_ADSP1_PM: |
350 | return region->base + (offset * 3); | 532 | return mem->base + (offset * 3); |
351 | case WMFW_ADSP1_DM: | 533 | case WMFW_ADSP1_DM: |
352 | return region->base + (offset * 2); | 534 | return mem->base + (offset * 2); |
353 | case WMFW_ADSP2_XM: | 535 | case WMFW_ADSP2_XM: |
354 | return region->base + (offset * 2); | 536 | return mem->base + (offset * 2); |
355 | case WMFW_ADSP2_YM: | 537 | case WMFW_ADSP2_YM: |
356 | return region->base + (offset * 2); | 538 | return mem->base + (offset * 2); |
357 | case WMFW_ADSP1_ZM: | 539 | case WMFW_ADSP1_ZM: |
358 | return region->base + (offset * 2); | 540 | return mem->base + (offset * 2); |
359 | default: | 541 | default: |
360 | WARN(1, "Unknown memory region type"); | 542 | WARN(1, "Unknown memory region type"); |
361 | return offset; | 543 | return offset; |
362 | } | 544 | } |
363 | } | 545 | } |
364 | 546 | ||
547 | static void wm_adsp2_show_fw_status(struct wm_adsp *dsp) | ||
548 | { | ||
549 | u16 scratch[4]; | ||
550 | int ret; | ||
551 | |||
552 | ret = regmap_raw_read(dsp->regmap, dsp->base + ADSP2_SCRATCH0, | ||
553 | scratch, sizeof(scratch)); | ||
554 | if (ret) { | ||
555 | adsp_err(dsp, "Failed to read SCRATCH regs: %d\n", ret); | ||
556 | return; | ||
557 | } | ||
558 | |||
559 | adsp_dbg(dsp, "FW SCRATCH 0:0x%x 1:0x%x 2:0x%x 3:0x%x\n", | ||
560 | be16_to_cpu(scratch[0]), | ||
561 | be16_to_cpu(scratch[1]), | ||
562 | be16_to_cpu(scratch[2]), | ||
563 | be16_to_cpu(scratch[3])); | ||
564 | } | ||
565 | |||
365 | static int wm_coeff_info(struct snd_kcontrol *kcontrol, | 566 | static int wm_coeff_info(struct snd_kcontrol *kcontrol, |
366 | struct snd_ctl_elem_info *uinfo) | 567 | struct snd_ctl_elem_info *uinfo) |
367 | { | 568 | { |
@@ -372,40 +573,39 @@ static int wm_coeff_info(struct snd_kcontrol *kcontrol, | |||
372 | return 0; | 573 | return 0; |
373 | } | 574 | } |
374 | 575 | ||
375 | static int wm_coeff_write_control(struct snd_kcontrol *kcontrol, | 576 | static int wm_coeff_write_control(struct wm_coeff_ctl *ctl, |
376 | const void *buf, size_t len) | 577 | const void *buf, size_t len) |
377 | { | 578 | { |
378 | struct wm_coeff_ctl *ctl = (struct wm_coeff_ctl *)kcontrol->private_value; | 579 | struct wm_adsp_alg_region *alg_region = &ctl->alg_region; |
379 | struct wm_adsp_alg_region *region = &ctl->region; | ||
380 | const struct wm_adsp_region *mem; | 580 | const struct wm_adsp_region *mem; |
381 | struct wm_adsp *adsp = ctl->adsp; | 581 | struct wm_adsp *dsp = ctl->dsp; |
382 | void *scratch; | 582 | void *scratch; |
383 | int ret; | 583 | int ret; |
384 | unsigned int reg; | 584 | unsigned int reg; |
385 | 585 | ||
386 | mem = wm_adsp_find_region(adsp, region->type); | 586 | mem = wm_adsp_find_region(dsp, alg_region->type); |
387 | if (!mem) { | 587 | if (!mem) { |
388 | adsp_err(adsp, "No base for region %x\n", | 588 | adsp_err(dsp, "No base for region %x\n", |
389 | region->type); | 589 | alg_region->type); |
390 | return -EINVAL; | 590 | return -EINVAL; |
391 | } | 591 | } |
392 | 592 | ||
393 | reg = ctl->region.base; | 593 | reg = ctl->alg_region.base + ctl->offset; |
394 | reg = wm_adsp_region_to_reg(mem, reg); | 594 | reg = wm_adsp_region_to_reg(mem, reg); |
395 | 595 | ||
396 | scratch = kmemdup(buf, ctl->len, GFP_KERNEL | GFP_DMA); | 596 | scratch = kmemdup(buf, ctl->len, GFP_KERNEL | GFP_DMA); |
397 | if (!scratch) | 597 | if (!scratch) |
398 | return -ENOMEM; | 598 | return -ENOMEM; |
399 | 599 | ||
400 | ret = regmap_raw_write(adsp->regmap, reg, scratch, | 600 | ret = regmap_raw_write(dsp->regmap, reg, scratch, |
401 | ctl->len); | 601 | ctl->len); |
402 | if (ret) { | 602 | if (ret) { |
403 | adsp_err(adsp, "Failed to write %zu bytes to %x: %d\n", | 603 | adsp_err(dsp, "Failed to write %zu bytes to %x: %d\n", |
404 | ctl->len, reg, ret); | 604 | ctl->len, reg, ret); |
405 | kfree(scratch); | 605 | kfree(scratch); |
406 | return ret; | 606 | return ret; |
407 | } | 607 | } |
408 | adsp_dbg(adsp, "Wrote %zu bytes to %x\n", ctl->len, reg); | 608 | adsp_dbg(dsp, "Wrote %zu bytes to %x\n", ctl->len, reg); |
409 | 609 | ||
410 | kfree(scratch); | 610 | kfree(scratch); |
411 | 611 | ||
@@ -424,42 +624,41 @@ static int wm_coeff_put(struct snd_kcontrol *kcontrol, | |||
424 | if (!ctl->enabled) | 624 | if (!ctl->enabled) |
425 | return 0; | 625 | return 0; |
426 | 626 | ||
427 | return wm_coeff_write_control(kcontrol, p, ctl->len); | 627 | return wm_coeff_write_control(ctl, p, ctl->len); |
428 | } | 628 | } |
429 | 629 | ||
430 | static int wm_coeff_read_control(struct snd_kcontrol *kcontrol, | 630 | static int wm_coeff_read_control(struct wm_coeff_ctl *ctl, |
431 | void *buf, size_t len) | 631 | void *buf, size_t len) |
432 | { | 632 | { |
433 | struct wm_coeff_ctl *ctl = (struct wm_coeff_ctl *)kcontrol->private_value; | 633 | struct wm_adsp_alg_region *alg_region = &ctl->alg_region; |
434 | struct wm_adsp_alg_region *region = &ctl->region; | ||
435 | const struct wm_adsp_region *mem; | 634 | const struct wm_adsp_region *mem; |
436 | struct wm_adsp *adsp = ctl->adsp; | 635 | struct wm_adsp *dsp = ctl->dsp; |
437 | void *scratch; | 636 | void *scratch; |
438 | int ret; | 637 | int ret; |
439 | unsigned int reg; | 638 | unsigned int reg; |
440 | 639 | ||
441 | mem = wm_adsp_find_region(adsp, region->type); | 640 | mem = wm_adsp_find_region(dsp, alg_region->type); |
442 | if (!mem) { | 641 | if (!mem) { |
443 | adsp_err(adsp, "No base for region %x\n", | 642 | adsp_err(dsp, "No base for region %x\n", |
444 | region->type); | 643 | alg_region->type); |
445 | return -EINVAL; | 644 | return -EINVAL; |
446 | } | 645 | } |
447 | 646 | ||
448 | reg = ctl->region.base; | 647 | reg = ctl->alg_region.base + ctl->offset; |
449 | reg = wm_adsp_region_to_reg(mem, reg); | 648 | reg = wm_adsp_region_to_reg(mem, reg); |
450 | 649 | ||
451 | scratch = kmalloc(ctl->len, GFP_KERNEL | GFP_DMA); | 650 | scratch = kmalloc(ctl->len, GFP_KERNEL | GFP_DMA); |
452 | if (!scratch) | 651 | if (!scratch) |
453 | return -ENOMEM; | 652 | return -ENOMEM; |
454 | 653 | ||
455 | ret = regmap_raw_read(adsp->regmap, reg, scratch, ctl->len); | 654 | ret = regmap_raw_read(dsp->regmap, reg, scratch, ctl->len); |
456 | if (ret) { | 655 | if (ret) { |
457 | adsp_err(adsp, "Failed to read %zu bytes from %x: %d\n", | 656 | adsp_err(dsp, "Failed to read %zu bytes from %x: %d\n", |
458 | ctl->len, reg, ret); | 657 | ctl->len, reg, ret); |
459 | kfree(scratch); | 658 | kfree(scratch); |
460 | return ret; | 659 | return ret; |
461 | } | 660 | } |
462 | adsp_dbg(adsp, "Read %zu bytes from %x\n", ctl->len, reg); | 661 | adsp_dbg(dsp, "Read %zu bytes from %x\n", ctl->len, reg); |
463 | 662 | ||
464 | memcpy(buf, scratch, ctl->len); | 663 | memcpy(buf, scratch, ctl->len); |
465 | kfree(scratch); | 664 | kfree(scratch); |
@@ -473,17 +672,25 @@ static int wm_coeff_get(struct snd_kcontrol *kcontrol, | |||
473 | struct wm_coeff_ctl *ctl = (struct wm_coeff_ctl *)kcontrol->private_value; | 672 | struct wm_coeff_ctl *ctl = (struct wm_coeff_ctl *)kcontrol->private_value; |
474 | char *p = ucontrol->value.bytes.data; | 673 | char *p = ucontrol->value.bytes.data; |
475 | 674 | ||
675 | if (ctl->flags & WMFW_CTL_FLAG_VOLATILE) { | ||
676 | if (ctl->enabled) | ||
677 | return wm_coeff_read_control(ctl, p, ctl->len); | ||
678 | else | ||
679 | return -EPERM; | ||
680 | } | ||
681 | |||
476 | memcpy(p, ctl->cache, ctl->len); | 682 | memcpy(p, ctl->cache, ctl->len); |
683 | |||
477 | return 0; | 684 | return 0; |
478 | } | 685 | } |
479 | 686 | ||
480 | struct wmfw_ctl_work { | 687 | struct wmfw_ctl_work { |
481 | struct wm_adsp *adsp; | 688 | struct wm_adsp *dsp; |
482 | struct wm_coeff_ctl *ctl; | 689 | struct wm_coeff_ctl *ctl; |
483 | struct work_struct work; | 690 | struct work_struct work; |
484 | }; | 691 | }; |
485 | 692 | ||
486 | static int wmfw_add_ctl(struct wm_adsp *adsp, struct wm_coeff_ctl *ctl) | 693 | static int wmfw_add_ctl(struct wm_adsp *dsp, struct wm_coeff_ctl *ctl) |
487 | { | 694 | { |
488 | struct snd_kcontrol_new *kcontrol; | 695 | struct snd_kcontrol_new *kcontrol; |
489 | int ret; | 696 | int ret; |
@@ -502,17 +709,25 @@ static int wmfw_add_ctl(struct wm_adsp *adsp, struct wm_coeff_ctl *ctl) | |||
502 | kcontrol->put = wm_coeff_put; | 709 | kcontrol->put = wm_coeff_put; |
503 | kcontrol->private_value = (unsigned long)ctl; | 710 | kcontrol->private_value = (unsigned long)ctl; |
504 | 711 | ||
505 | ret = snd_soc_add_card_controls(adsp->card, | 712 | if (ctl->flags) { |
713 | if (ctl->flags & WMFW_CTL_FLAG_WRITEABLE) | ||
714 | kcontrol->access |= SNDRV_CTL_ELEM_ACCESS_WRITE; | ||
715 | if (ctl->flags & WMFW_CTL_FLAG_READABLE) | ||
716 | kcontrol->access |= SNDRV_CTL_ELEM_ACCESS_READ; | ||
717 | if (ctl->flags & WMFW_CTL_FLAG_VOLATILE) | ||
718 | kcontrol->access |= SNDRV_CTL_ELEM_ACCESS_VOLATILE; | ||
719 | } | ||
720 | |||
721 | ret = snd_soc_add_card_controls(dsp->card, | ||
506 | kcontrol, 1); | 722 | kcontrol, 1); |
507 | if (ret < 0) | 723 | if (ret < 0) |
508 | goto err_kcontrol; | 724 | goto err_kcontrol; |
509 | 725 | ||
510 | kfree(kcontrol); | 726 | kfree(kcontrol); |
511 | 727 | ||
512 | ctl->kcontrol = snd_soc_card_get_kcontrol(adsp->card, | 728 | ctl->kcontrol = snd_soc_card_get_kcontrol(dsp->card, |
513 | ctl->name); | 729 | ctl->name); |
514 | 730 | ||
515 | list_add(&ctl->list, &adsp->ctl_list); | ||
516 | return 0; | 731 | return 0; |
517 | 732 | ||
518 | err_kcontrol: | 733 | err_kcontrol: |
@@ -520,6 +735,358 @@ err_kcontrol: | |||
520 | return ret; | 735 | return ret; |
521 | } | 736 | } |
522 | 737 | ||
738 | static int wm_coeff_init_control_caches(struct wm_adsp *dsp) | ||
739 | { | ||
740 | struct wm_coeff_ctl *ctl; | ||
741 | int ret; | ||
742 | |||
743 | list_for_each_entry(ctl, &dsp->ctl_list, list) { | ||
744 | if (!ctl->enabled || ctl->set) | ||
745 | continue; | ||
746 | if (ctl->flags & WMFW_CTL_FLAG_VOLATILE) | ||
747 | continue; | ||
748 | |||
749 | ret = wm_coeff_read_control(ctl, | ||
750 | ctl->cache, | ||
751 | ctl->len); | ||
752 | if (ret < 0) | ||
753 | return ret; | ||
754 | } | ||
755 | |||
756 | return 0; | ||
757 | } | ||
758 | |||
759 | static int wm_coeff_sync_controls(struct wm_adsp *dsp) | ||
760 | { | ||
761 | struct wm_coeff_ctl *ctl; | ||
762 | int ret; | ||
763 | |||
764 | list_for_each_entry(ctl, &dsp->ctl_list, list) { | ||
765 | if (!ctl->enabled) | ||
766 | continue; | ||
767 | if (ctl->set && !(ctl->flags & WMFW_CTL_FLAG_VOLATILE)) { | ||
768 | ret = wm_coeff_write_control(ctl, | ||
769 | ctl->cache, | ||
770 | ctl->len); | ||
771 | if (ret < 0) | ||
772 | return ret; | ||
773 | } | ||
774 | } | ||
775 | |||
776 | return 0; | ||
777 | } | ||
778 | |||
779 | static void wm_adsp_ctl_work(struct work_struct *work) | ||
780 | { | ||
781 | struct wmfw_ctl_work *ctl_work = container_of(work, | ||
782 | struct wmfw_ctl_work, | ||
783 | work); | ||
784 | |||
785 | wmfw_add_ctl(ctl_work->dsp, ctl_work->ctl); | ||
786 | kfree(ctl_work); | ||
787 | } | ||
788 | |||
789 | static int wm_adsp_create_control(struct wm_adsp *dsp, | ||
790 | const struct wm_adsp_alg_region *alg_region, | ||
791 | unsigned int offset, unsigned int len, | ||
792 | const char *subname, unsigned int subname_len, | ||
793 | unsigned int flags) | ||
794 | { | ||
795 | struct wm_coeff_ctl *ctl; | ||
796 | struct wmfw_ctl_work *ctl_work; | ||
797 | char name[SNDRV_CTL_ELEM_ID_NAME_MAXLEN]; | ||
798 | char *region_name; | ||
799 | int ret; | ||
800 | |||
801 | if (flags & WMFW_CTL_FLAG_SYS) | ||
802 | return 0; | ||
803 | |||
804 | switch (alg_region->type) { | ||
805 | case WMFW_ADSP1_PM: | ||
806 | region_name = "PM"; | ||
807 | break; | ||
808 | case WMFW_ADSP1_DM: | ||
809 | region_name = "DM"; | ||
810 | break; | ||
811 | case WMFW_ADSP2_XM: | ||
812 | region_name = "XM"; | ||
813 | break; | ||
814 | case WMFW_ADSP2_YM: | ||
815 | region_name = "YM"; | ||
816 | break; | ||
817 | case WMFW_ADSP1_ZM: | ||
818 | region_name = "ZM"; | ||
819 | break; | ||
820 | default: | ||
821 | adsp_err(dsp, "Unknown region type: %d\n", alg_region->type); | ||
822 | return -EINVAL; | ||
823 | } | ||
824 | |||
825 | switch (dsp->fw_ver) { | ||
826 | case 0: | ||
827 | case 1: | ||
828 | snprintf(name, SNDRV_CTL_ELEM_ID_NAME_MAXLEN, "DSP%d %s %x", | ||
829 | dsp->num, region_name, alg_region->alg); | ||
830 | break; | ||
831 | default: | ||
832 | ret = snprintf(name, SNDRV_CTL_ELEM_ID_NAME_MAXLEN, | ||
833 | "DSP%d%c %.12s %x", dsp->num, *region_name, | ||
834 | wm_adsp_fw_text[dsp->fw], alg_region->alg); | ||
835 | |||
836 | /* Truncate the subname from the start if it is too long */ | ||
837 | if (subname) { | ||
838 | int avail = SNDRV_CTL_ELEM_ID_NAME_MAXLEN - ret - 2; | ||
839 | int skip = 0; | ||
840 | |||
841 | if (subname_len > avail) | ||
842 | skip = subname_len - avail; | ||
843 | |||
844 | snprintf(name + ret, | ||
845 | SNDRV_CTL_ELEM_ID_NAME_MAXLEN - ret, " %.*s", | ||
846 | subname_len - skip, subname + skip); | ||
847 | } | ||
848 | break; | ||
849 | } | ||
850 | |||
851 | list_for_each_entry(ctl, &dsp->ctl_list, | ||
852 | list) { | ||
853 | if (!strcmp(ctl->name, name)) { | ||
854 | if (!ctl->enabled) | ||
855 | ctl->enabled = 1; | ||
856 | return 0; | ||
857 | } | ||
858 | } | ||
859 | |||
860 | ctl = kzalloc(sizeof(*ctl), GFP_KERNEL); | ||
861 | if (!ctl) | ||
862 | return -ENOMEM; | ||
863 | ctl->fw_name = wm_adsp_fw_text[dsp->fw]; | ||
864 | ctl->alg_region = *alg_region; | ||
865 | ctl->name = kmemdup(name, strlen(name) + 1, GFP_KERNEL); | ||
866 | if (!ctl->name) { | ||
867 | ret = -ENOMEM; | ||
868 | goto err_ctl; | ||
869 | } | ||
870 | ctl->enabled = 1; | ||
871 | ctl->set = 0; | ||
872 | ctl->ops.xget = wm_coeff_get; | ||
873 | ctl->ops.xput = wm_coeff_put; | ||
874 | ctl->dsp = dsp; | ||
875 | |||
876 | ctl->flags = flags; | ||
877 | ctl->offset = offset; | ||
878 | if (len > 512) { | ||
879 | adsp_warn(dsp, "Truncating control %s from %d\n", | ||
880 | ctl->name, len); | ||
881 | len = 512; | ||
882 | } | ||
883 | ctl->len = len; | ||
884 | ctl->cache = kzalloc(ctl->len, GFP_KERNEL); | ||
885 | if (!ctl->cache) { | ||
886 | ret = -ENOMEM; | ||
887 | goto err_ctl_name; | ||
888 | } | ||
889 | |||
890 | list_add(&ctl->list, &dsp->ctl_list); | ||
891 | |||
892 | ctl_work = kzalloc(sizeof(*ctl_work), GFP_KERNEL); | ||
893 | if (!ctl_work) { | ||
894 | ret = -ENOMEM; | ||
895 | goto err_ctl_cache; | ||
896 | } | ||
897 | |||
898 | ctl_work->dsp = dsp; | ||
899 | ctl_work->ctl = ctl; | ||
900 | INIT_WORK(&ctl_work->work, wm_adsp_ctl_work); | ||
901 | schedule_work(&ctl_work->work); | ||
902 | |||
903 | return 0; | ||
904 | |||
905 | err_ctl_cache: | ||
906 | kfree(ctl->cache); | ||
907 | err_ctl_name: | ||
908 | kfree(ctl->name); | ||
909 | err_ctl: | ||
910 | kfree(ctl); | ||
911 | |||
912 | return ret; | ||
913 | } | ||
914 | |||
915 | struct wm_coeff_parsed_alg { | ||
916 | int id; | ||
917 | const u8 *name; | ||
918 | int name_len; | ||
919 | int ncoeff; | ||
920 | }; | ||
921 | |||
922 | struct wm_coeff_parsed_coeff { | ||
923 | int offset; | ||
924 | int mem_type; | ||
925 | const u8 *name; | ||
926 | int name_len; | ||
927 | int ctl_type; | ||
928 | int flags; | ||
929 | int len; | ||
930 | }; | ||
931 | |||
932 | static int wm_coeff_parse_string(int bytes, const u8 **pos, const u8 **str) | ||
933 | { | ||
934 | int length; | ||
935 | |||
936 | switch (bytes) { | ||
937 | case 1: | ||
938 | length = **pos; | ||
939 | break; | ||
940 | case 2: | ||
941 | length = le16_to_cpu(*((__le16 *)*pos)); | ||
942 | break; | ||
943 | default: | ||
944 | return 0; | ||
945 | } | ||
946 | |||
947 | if (str) | ||
948 | *str = *pos + bytes; | ||
949 | |||
950 | *pos += ((length + bytes) + 3) & ~0x03; | ||
951 | |||
952 | return length; | ||
953 | } | ||
954 | |||
955 | static int wm_coeff_parse_int(int bytes, const u8 **pos) | ||
956 | { | ||
957 | int val = 0; | ||
958 | |||
959 | switch (bytes) { | ||
960 | case 2: | ||
961 | val = le16_to_cpu(*((__le16 *)*pos)); | ||
962 | break; | ||
963 | case 4: | ||
964 | val = le32_to_cpu(*((__le32 *)*pos)); | ||
965 | break; | ||
966 | default: | ||
967 | break; | ||
968 | } | ||
969 | |||
970 | *pos += bytes; | ||
971 | |||
972 | return val; | ||
973 | } | ||
974 | |||
975 | static inline void wm_coeff_parse_alg(struct wm_adsp *dsp, const u8 **data, | ||
976 | struct wm_coeff_parsed_alg *blk) | ||
977 | { | ||
978 | const struct wmfw_adsp_alg_data *raw; | ||
979 | |||
980 | switch (dsp->fw_ver) { | ||
981 | case 0: | ||
982 | case 1: | ||
983 | raw = (const struct wmfw_adsp_alg_data *)*data; | ||
984 | *data = raw->data; | ||
985 | |||
986 | blk->id = le32_to_cpu(raw->id); | ||
987 | blk->name = raw->name; | ||
988 | blk->name_len = strlen(raw->name); | ||
989 | blk->ncoeff = le32_to_cpu(raw->ncoeff); | ||
990 | break; | ||
991 | default: | ||
992 | blk->id = wm_coeff_parse_int(sizeof(raw->id), data); | ||
993 | blk->name_len = wm_coeff_parse_string(sizeof(u8), data, | ||
994 | &blk->name); | ||
995 | wm_coeff_parse_string(sizeof(u16), data, NULL); | ||
996 | blk->ncoeff = wm_coeff_parse_int(sizeof(raw->ncoeff), data); | ||
997 | break; | ||
998 | } | ||
999 | |||
1000 | adsp_dbg(dsp, "Algorithm ID: %#x\n", blk->id); | ||
1001 | adsp_dbg(dsp, "Algorithm name: %.*s\n", blk->name_len, blk->name); | ||
1002 | adsp_dbg(dsp, "# of coefficient descriptors: %#x\n", blk->ncoeff); | ||
1003 | } | ||
1004 | |||
1005 | static inline void wm_coeff_parse_coeff(struct wm_adsp *dsp, const u8 **data, | ||
1006 | struct wm_coeff_parsed_coeff *blk) | ||
1007 | { | ||
1008 | const struct wmfw_adsp_coeff_data *raw; | ||
1009 | const u8 *tmp; | ||
1010 | int length; | ||
1011 | |||
1012 | switch (dsp->fw_ver) { | ||
1013 | case 0: | ||
1014 | case 1: | ||
1015 | raw = (const struct wmfw_adsp_coeff_data *)*data; | ||
1016 | *data = *data + sizeof(raw->hdr) + le32_to_cpu(raw->hdr.size); | ||
1017 | |||
1018 | blk->offset = le16_to_cpu(raw->hdr.offset); | ||
1019 | blk->mem_type = le16_to_cpu(raw->hdr.type); | ||
1020 | blk->name = raw->name; | ||
1021 | blk->name_len = strlen(raw->name); | ||
1022 | blk->ctl_type = le16_to_cpu(raw->ctl_type); | ||
1023 | blk->flags = le16_to_cpu(raw->flags); | ||
1024 | blk->len = le32_to_cpu(raw->len); | ||
1025 | break; | ||
1026 | default: | ||
1027 | tmp = *data; | ||
1028 | blk->offset = wm_coeff_parse_int(sizeof(raw->hdr.offset), &tmp); | ||
1029 | blk->mem_type = wm_coeff_parse_int(sizeof(raw->hdr.type), &tmp); | ||
1030 | length = wm_coeff_parse_int(sizeof(raw->hdr.size), &tmp); | ||
1031 | blk->name_len = wm_coeff_parse_string(sizeof(u8), &tmp, | ||
1032 | &blk->name); | ||
1033 | wm_coeff_parse_string(sizeof(u8), &tmp, NULL); | ||
1034 | wm_coeff_parse_string(sizeof(u16), &tmp, NULL); | ||
1035 | blk->ctl_type = wm_coeff_parse_int(sizeof(raw->ctl_type), &tmp); | ||
1036 | blk->flags = wm_coeff_parse_int(sizeof(raw->flags), &tmp); | ||
1037 | blk->len = wm_coeff_parse_int(sizeof(raw->len), &tmp); | ||
1038 | |||
1039 | *data = *data + sizeof(raw->hdr) + length; | ||
1040 | break; | ||
1041 | } | ||
1042 | |||
1043 | adsp_dbg(dsp, "\tCoefficient type: %#x\n", blk->mem_type); | ||
1044 | adsp_dbg(dsp, "\tCoefficient offset: %#x\n", blk->offset); | ||
1045 | adsp_dbg(dsp, "\tCoefficient name: %.*s\n", blk->name_len, blk->name); | ||
1046 | adsp_dbg(dsp, "\tCoefficient flags: %#x\n", blk->flags); | ||
1047 | adsp_dbg(dsp, "\tALSA control type: %#x\n", blk->ctl_type); | ||
1048 | adsp_dbg(dsp, "\tALSA control len: %#x\n", blk->len); | ||
1049 | } | ||
1050 | |||
1051 | static int wm_adsp_parse_coeff(struct wm_adsp *dsp, | ||
1052 | const struct wmfw_region *region) | ||
1053 | { | ||
1054 | struct wm_adsp_alg_region alg_region = {}; | ||
1055 | struct wm_coeff_parsed_alg alg_blk; | ||
1056 | struct wm_coeff_parsed_coeff coeff_blk; | ||
1057 | const u8 *data = region->data; | ||
1058 | int i, ret; | ||
1059 | |||
1060 | wm_coeff_parse_alg(dsp, &data, &alg_blk); | ||
1061 | for (i = 0; i < alg_blk.ncoeff; i++) { | ||
1062 | wm_coeff_parse_coeff(dsp, &data, &coeff_blk); | ||
1063 | |||
1064 | switch (coeff_blk.ctl_type) { | ||
1065 | case SNDRV_CTL_ELEM_TYPE_BYTES: | ||
1066 | break; | ||
1067 | default: | ||
1068 | adsp_err(dsp, "Unknown control type: %d\n", | ||
1069 | coeff_blk.ctl_type); | ||
1070 | return -EINVAL; | ||
1071 | } | ||
1072 | |||
1073 | alg_region.type = coeff_blk.mem_type; | ||
1074 | alg_region.alg = alg_blk.id; | ||
1075 | |||
1076 | ret = wm_adsp_create_control(dsp, &alg_region, | ||
1077 | coeff_blk.offset, | ||
1078 | coeff_blk.len, | ||
1079 | coeff_blk.name, | ||
1080 | coeff_blk.name_len, | ||
1081 | coeff_blk.flags); | ||
1082 | if (ret < 0) | ||
1083 | adsp_err(dsp, "Failed to create control: %.*s, %d\n", | ||
1084 | coeff_blk.name_len, coeff_blk.name, ret); | ||
1085 | } | ||
1086 | |||
1087 | return 0; | ||
1088 | } | ||
1089 | |||
523 | static int wm_adsp_load(struct wm_adsp *dsp) | 1090 | static int wm_adsp_load(struct wm_adsp *dsp) |
524 | { | 1091 | { |
525 | LIST_HEAD(buf_list); | 1092 | LIST_HEAD(buf_list); |
@@ -568,12 +1135,22 @@ static int wm_adsp_load(struct wm_adsp *dsp) | |||
568 | goto out_fw; | 1135 | goto out_fw; |
569 | } | 1136 | } |
570 | 1137 | ||
571 | if (header->ver != 0) { | 1138 | switch (header->ver) { |
1139 | case 0: | ||
1140 | adsp_warn(dsp, "%s: Depreciated file format %d\n", | ||
1141 | file, header->ver); | ||
1142 | break; | ||
1143 | case 1: | ||
1144 | case 2: | ||
1145 | break; | ||
1146 | default: | ||
572 | adsp_err(dsp, "%s: unknown file format %d\n", | 1147 | adsp_err(dsp, "%s: unknown file format %d\n", |
573 | file, header->ver); | 1148 | file, header->ver); |
574 | goto out_fw; | 1149 | goto out_fw; |
575 | } | 1150 | } |
1151 | |||
576 | adsp_info(dsp, "Firmware version: %d\n", header->ver); | 1152 | adsp_info(dsp, "Firmware version: %d\n", header->ver); |
1153 | dsp->fw_ver = header->ver; | ||
577 | 1154 | ||
578 | if (header->core != dsp->type) { | 1155 | if (header->core != dsp->type) { |
579 | adsp_err(dsp, "%s: invalid core %d != %d\n", | 1156 | adsp_err(dsp, "%s: invalid core %d != %d\n", |
@@ -638,6 +1215,12 @@ static int wm_adsp_load(struct wm_adsp *dsp) | |||
638 | text = kzalloc(le32_to_cpu(region->len) + 1, | 1215 | text = kzalloc(le32_to_cpu(region->len) + 1, |
639 | GFP_KERNEL); | 1216 | GFP_KERNEL); |
640 | break; | 1217 | break; |
1218 | case WMFW_ALGORITHM_DATA: | ||
1219 | region_name = "Algorithm"; | ||
1220 | ret = wm_adsp_parse_coeff(dsp, region); | ||
1221 | if (ret != 0) | ||
1222 | goto out_fw; | ||
1223 | break; | ||
641 | case WMFW_INFO_TEXT: | 1224 | case WMFW_INFO_TEXT: |
642 | region_name = "Information"; | 1225 | region_name = "Information"; |
643 | text = kzalloc(le32_to_cpu(region->len) + 1, | 1226 | text = kzalloc(le32_to_cpu(region->len) + 1, |
@@ -720,6 +1303,8 @@ static int wm_adsp_load(struct wm_adsp *dsp) | |||
720 | adsp_warn(dsp, "%s.%d: %zu bytes at end of file\n", | 1303 | adsp_warn(dsp, "%s.%d: %zu bytes at end of file\n", |
721 | file, regions, pos - firmware->size); | 1304 | file, regions, pos - firmware->size); |
722 | 1305 | ||
1306 | wm_adsp_debugfs_save_wmfwname(dsp, file); | ||
1307 | |||
723 | out_fw: | 1308 | out_fw: |
724 | regmap_async_complete(regmap); | 1309 | regmap_async_complete(regmap); |
725 | wm_adsp_buf_free(&buf_list); | 1310 | wm_adsp_buf_free(&buf_list); |
@@ -730,444 +1315,317 @@ out: | |||
730 | return ret; | 1315 | return ret; |
731 | } | 1316 | } |
732 | 1317 | ||
733 | static int wm_coeff_init_control_caches(struct wm_adsp *adsp) | 1318 | static void wm_adsp_ctl_fixup_base(struct wm_adsp *dsp, |
1319 | const struct wm_adsp_alg_region *alg_region) | ||
734 | { | 1320 | { |
735 | struct wm_coeff_ctl *ctl; | 1321 | struct wm_coeff_ctl *ctl; |
736 | int ret; | ||
737 | 1322 | ||
738 | list_for_each_entry(ctl, &adsp->ctl_list, list) { | 1323 | list_for_each_entry(ctl, &dsp->ctl_list, list) { |
739 | if (!ctl->enabled || ctl->set) | 1324 | if (ctl->fw_name == wm_adsp_fw_text[dsp->fw] && |
740 | continue; | 1325 | alg_region->alg == ctl->alg_region.alg && |
741 | ret = wm_coeff_read_control(ctl->kcontrol, | 1326 | alg_region->type == ctl->alg_region.type) { |
742 | ctl->cache, | 1327 | ctl->alg_region.base = alg_region->base; |
743 | ctl->len); | 1328 | } |
744 | if (ret < 0) | ||
745 | return ret; | ||
746 | } | 1329 | } |
747 | |||
748 | return 0; | ||
749 | } | 1330 | } |
750 | 1331 | ||
751 | static int wm_coeff_sync_controls(struct wm_adsp *adsp) | 1332 | static void *wm_adsp_read_algs(struct wm_adsp *dsp, size_t n_algs, |
1333 | unsigned int pos, unsigned int len) | ||
752 | { | 1334 | { |
753 | struct wm_coeff_ctl *ctl; | 1335 | void *alg; |
754 | int ret; | 1336 | int ret; |
1337 | __be32 val; | ||
755 | 1338 | ||
756 | list_for_each_entry(ctl, &adsp->ctl_list, list) { | 1339 | if (n_algs == 0) { |
757 | if (!ctl->enabled) | 1340 | adsp_err(dsp, "No algorithms\n"); |
758 | continue; | 1341 | return ERR_PTR(-EINVAL); |
759 | if (ctl->set) { | ||
760 | ret = wm_coeff_write_control(ctl->kcontrol, | ||
761 | ctl->cache, | ||
762 | ctl->len); | ||
763 | if (ret < 0) | ||
764 | return ret; | ||
765 | } | ||
766 | } | 1342 | } |
767 | 1343 | ||
768 | return 0; | 1344 | if (n_algs > 1024) { |
769 | } | 1345 | adsp_err(dsp, "Algorithm count %zx excessive\n", n_algs); |
770 | 1346 | return ERR_PTR(-EINVAL); | |
771 | static void wm_adsp_ctl_work(struct work_struct *work) | 1347 | } |
772 | { | ||
773 | struct wmfw_ctl_work *ctl_work = container_of(work, | ||
774 | struct wmfw_ctl_work, | ||
775 | work); | ||
776 | |||
777 | wmfw_add_ctl(ctl_work->adsp, ctl_work->ctl); | ||
778 | kfree(ctl_work); | ||
779 | } | ||
780 | |||
781 | static int wm_adsp_create_control(struct wm_adsp *dsp, | ||
782 | const struct wm_adsp_alg_region *region) | ||
783 | |||
784 | { | ||
785 | struct wm_coeff_ctl *ctl; | ||
786 | struct wmfw_ctl_work *ctl_work; | ||
787 | char *name; | ||
788 | char *region_name; | ||
789 | int ret; | ||
790 | |||
791 | name = kmalloc(PAGE_SIZE, GFP_KERNEL); | ||
792 | if (!name) | ||
793 | return -ENOMEM; | ||
794 | 1348 | ||
795 | switch (region->type) { | 1349 | /* Read the terminator first to validate the length */ |
796 | case WMFW_ADSP1_PM: | 1350 | ret = regmap_raw_read(dsp->regmap, pos + len, &val, sizeof(val)); |
797 | region_name = "PM"; | 1351 | if (ret != 0) { |
798 | break; | 1352 | adsp_err(dsp, "Failed to read algorithm list end: %d\n", |
799 | case WMFW_ADSP1_DM: | 1353 | ret); |
800 | region_name = "DM"; | 1354 | return ERR_PTR(ret); |
801 | break; | ||
802 | case WMFW_ADSP2_XM: | ||
803 | region_name = "XM"; | ||
804 | break; | ||
805 | case WMFW_ADSP2_YM: | ||
806 | region_name = "YM"; | ||
807 | break; | ||
808 | case WMFW_ADSP1_ZM: | ||
809 | region_name = "ZM"; | ||
810 | break; | ||
811 | default: | ||
812 | ret = -EINVAL; | ||
813 | goto err_name; | ||
814 | } | 1355 | } |
815 | 1356 | ||
816 | snprintf(name, PAGE_SIZE, "DSP%d %s %x", | 1357 | if (be32_to_cpu(val) != 0xbedead) |
817 | dsp->num, region_name, region->alg); | 1358 | adsp_warn(dsp, "Algorithm list end %x 0x%x != 0xbeadead\n", |
1359 | pos + len, be32_to_cpu(val)); | ||
818 | 1360 | ||
819 | list_for_each_entry(ctl, &dsp->ctl_list, | 1361 | alg = kzalloc(len * 2, GFP_KERNEL | GFP_DMA); |
820 | list) { | 1362 | if (!alg) |
821 | if (!strcmp(ctl->name, name)) { | 1363 | return ERR_PTR(-ENOMEM); |
822 | if (!ctl->enabled) | ||
823 | ctl->enabled = 1; | ||
824 | goto found; | ||
825 | } | ||
826 | } | ||
827 | 1364 | ||
828 | ctl = kzalloc(sizeof(*ctl), GFP_KERNEL); | 1365 | ret = regmap_raw_read(dsp->regmap, pos, alg, len * 2); |
829 | if (!ctl) { | 1366 | if (ret != 0) { |
830 | ret = -ENOMEM; | 1367 | adsp_err(dsp, "Failed to read algorithm list: %d\n", |
831 | goto err_name; | 1368 | ret); |
832 | } | 1369 | kfree(alg); |
833 | ctl->region = *region; | 1370 | return ERR_PTR(ret); |
834 | ctl->name = kmemdup(name, strlen(name) + 1, GFP_KERNEL); | ||
835 | if (!ctl->name) { | ||
836 | ret = -ENOMEM; | ||
837 | goto err_ctl; | ||
838 | } | 1371 | } |
839 | ctl->enabled = 1; | ||
840 | ctl->set = 0; | ||
841 | ctl->ops.xget = wm_coeff_get; | ||
842 | ctl->ops.xput = wm_coeff_put; | ||
843 | ctl->adsp = dsp; | ||
844 | 1372 | ||
845 | ctl->len = region->len; | 1373 | return alg; |
846 | ctl->cache = kzalloc(ctl->len, GFP_KERNEL); | 1374 | } |
847 | if (!ctl->cache) { | ||
848 | ret = -ENOMEM; | ||
849 | goto err_ctl_name; | ||
850 | } | ||
851 | 1375 | ||
852 | ctl_work = kzalloc(sizeof(*ctl_work), GFP_KERNEL); | 1376 | static struct wm_adsp_alg_region *wm_adsp_create_region(struct wm_adsp *dsp, |
853 | if (!ctl_work) { | 1377 | int type, __be32 id, |
854 | ret = -ENOMEM; | 1378 | __be32 base) |
855 | goto err_ctl_cache; | 1379 | { |
856 | } | 1380 | struct wm_adsp_alg_region *alg_region; |
857 | 1381 | ||
858 | ctl_work->adsp = dsp; | 1382 | alg_region = kzalloc(sizeof(*alg_region), GFP_KERNEL); |
859 | ctl_work->ctl = ctl; | 1383 | if (!alg_region) |
860 | INIT_WORK(&ctl_work->work, wm_adsp_ctl_work); | 1384 | return ERR_PTR(-ENOMEM); |
861 | schedule_work(&ctl_work->work); | ||
862 | 1385 | ||
863 | found: | 1386 | alg_region->type = type; |
864 | kfree(name); | 1387 | alg_region->alg = be32_to_cpu(id); |
1388 | alg_region->base = be32_to_cpu(base); | ||
865 | 1389 | ||
866 | return 0; | 1390 | list_add_tail(&alg_region->list, &dsp->alg_regions); |
867 | 1391 | ||
868 | err_ctl_cache: | 1392 | if (dsp->fw_ver > 0) |
869 | kfree(ctl->cache); | 1393 | wm_adsp_ctl_fixup_base(dsp, alg_region); |
870 | err_ctl_name: | 1394 | |
871 | kfree(ctl->name); | 1395 | return alg_region; |
872 | err_ctl: | ||
873 | kfree(ctl); | ||
874 | err_name: | ||
875 | kfree(name); | ||
876 | return ret; | ||
877 | } | 1396 | } |
878 | 1397 | ||
879 | static int wm_adsp_setup_algs(struct wm_adsp *dsp) | 1398 | static int wm_adsp1_setup_algs(struct wm_adsp *dsp) |
880 | { | 1399 | { |
881 | struct regmap *regmap = dsp->regmap; | ||
882 | struct wmfw_adsp1_id_hdr adsp1_id; | 1400 | struct wmfw_adsp1_id_hdr adsp1_id; |
883 | struct wmfw_adsp2_id_hdr adsp2_id; | ||
884 | struct wmfw_adsp1_alg_hdr *adsp1_alg; | 1401 | struct wmfw_adsp1_alg_hdr *adsp1_alg; |
885 | struct wmfw_adsp2_alg_hdr *adsp2_alg; | 1402 | struct wm_adsp_alg_region *alg_region; |
886 | void *alg, *buf; | ||
887 | struct wm_adsp_alg_region *region; | ||
888 | const struct wm_adsp_region *mem; | 1403 | const struct wm_adsp_region *mem; |
889 | unsigned int pos, term; | 1404 | unsigned int pos, len; |
890 | size_t algs, buf_size; | 1405 | size_t n_algs; |
891 | __be32 val; | ||
892 | int i, ret; | 1406 | int i, ret; |
893 | 1407 | ||
894 | switch (dsp->type) { | 1408 | mem = wm_adsp_find_region(dsp, WMFW_ADSP1_DM); |
895 | case WMFW_ADSP1: | ||
896 | mem = wm_adsp_find_region(dsp, WMFW_ADSP1_DM); | ||
897 | break; | ||
898 | case WMFW_ADSP2: | ||
899 | mem = wm_adsp_find_region(dsp, WMFW_ADSP2_XM); | ||
900 | break; | ||
901 | default: | ||
902 | mem = NULL; | ||
903 | break; | ||
904 | } | ||
905 | |||
906 | if (WARN_ON(!mem)) | 1409 | if (WARN_ON(!mem)) |
907 | return -EINVAL; | 1410 | return -EINVAL; |
908 | 1411 | ||
909 | switch (dsp->type) { | 1412 | ret = regmap_raw_read(dsp->regmap, mem->base, &adsp1_id, |
910 | case WMFW_ADSP1: | 1413 | sizeof(adsp1_id)); |
911 | ret = regmap_raw_read(regmap, mem->base, &adsp1_id, | ||
912 | sizeof(adsp1_id)); | ||
913 | if (ret != 0) { | ||
914 | adsp_err(dsp, "Failed to read algorithm info: %d\n", | ||
915 | ret); | ||
916 | return ret; | ||
917 | } | ||
918 | |||
919 | buf = &adsp1_id; | ||
920 | buf_size = sizeof(adsp1_id); | ||
921 | |||
922 | algs = be32_to_cpu(adsp1_id.algs); | ||
923 | dsp->fw_id = be32_to_cpu(adsp1_id.fw.id); | ||
924 | adsp_info(dsp, "Firmware: %x v%d.%d.%d, %zu algorithms\n", | ||
925 | dsp->fw_id, | ||
926 | (be32_to_cpu(adsp1_id.fw.ver) & 0xff0000) >> 16, | ||
927 | (be32_to_cpu(adsp1_id.fw.ver) & 0xff00) >> 8, | ||
928 | be32_to_cpu(adsp1_id.fw.ver) & 0xff, | ||
929 | algs); | ||
930 | |||
931 | region = kzalloc(sizeof(*region), GFP_KERNEL); | ||
932 | if (!region) | ||
933 | return -ENOMEM; | ||
934 | region->type = WMFW_ADSP1_ZM; | ||
935 | region->alg = be32_to_cpu(adsp1_id.fw.id); | ||
936 | region->base = be32_to_cpu(adsp1_id.zm); | ||
937 | list_add_tail(®ion->list, &dsp->alg_regions); | ||
938 | |||
939 | region = kzalloc(sizeof(*region), GFP_KERNEL); | ||
940 | if (!region) | ||
941 | return -ENOMEM; | ||
942 | region->type = WMFW_ADSP1_DM; | ||
943 | region->alg = be32_to_cpu(adsp1_id.fw.id); | ||
944 | region->base = be32_to_cpu(adsp1_id.dm); | ||
945 | list_add_tail(®ion->list, &dsp->alg_regions); | ||
946 | |||
947 | pos = sizeof(adsp1_id) / 2; | ||
948 | term = pos + ((sizeof(*adsp1_alg) * algs) / 2); | ||
949 | break; | ||
950 | |||
951 | case WMFW_ADSP2: | ||
952 | ret = regmap_raw_read(regmap, mem->base, &adsp2_id, | ||
953 | sizeof(adsp2_id)); | ||
954 | if (ret != 0) { | ||
955 | adsp_err(dsp, "Failed to read algorithm info: %d\n", | ||
956 | ret); | ||
957 | return ret; | ||
958 | } | ||
959 | |||
960 | buf = &adsp2_id; | ||
961 | buf_size = sizeof(adsp2_id); | ||
962 | |||
963 | algs = be32_to_cpu(adsp2_id.algs); | ||
964 | dsp->fw_id = be32_to_cpu(adsp2_id.fw.id); | ||
965 | adsp_info(dsp, "Firmware: %x v%d.%d.%d, %zu algorithms\n", | ||
966 | dsp->fw_id, | ||
967 | (be32_to_cpu(adsp2_id.fw.ver) & 0xff0000) >> 16, | ||
968 | (be32_to_cpu(adsp2_id.fw.ver) & 0xff00) >> 8, | ||
969 | be32_to_cpu(adsp2_id.fw.ver) & 0xff, | ||
970 | algs); | ||
971 | |||
972 | region = kzalloc(sizeof(*region), GFP_KERNEL); | ||
973 | if (!region) | ||
974 | return -ENOMEM; | ||
975 | region->type = WMFW_ADSP2_XM; | ||
976 | region->alg = be32_to_cpu(adsp2_id.fw.id); | ||
977 | region->base = be32_to_cpu(adsp2_id.xm); | ||
978 | list_add_tail(®ion->list, &dsp->alg_regions); | ||
979 | |||
980 | region = kzalloc(sizeof(*region), GFP_KERNEL); | ||
981 | if (!region) | ||
982 | return -ENOMEM; | ||
983 | region->type = WMFW_ADSP2_YM; | ||
984 | region->alg = be32_to_cpu(adsp2_id.fw.id); | ||
985 | region->base = be32_to_cpu(adsp2_id.ym); | ||
986 | list_add_tail(®ion->list, &dsp->alg_regions); | ||
987 | |||
988 | region = kzalloc(sizeof(*region), GFP_KERNEL); | ||
989 | if (!region) | ||
990 | return -ENOMEM; | ||
991 | region->type = WMFW_ADSP2_ZM; | ||
992 | region->alg = be32_to_cpu(adsp2_id.fw.id); | ||
993 | region->base = be32_to_cpu(adsp2_id.zm); | ||
994 | list_add_tail(®ion->list, &dsp->alg_regions); | ||
995 | |||
996 | pos = sizeof(adsp2_id) / 2; | ||
997 | term = pos + ((sizeof(*adsp2_alg) * algs) / 2); | ||
998 | break; | ||
999 | |||
1000 | default: | ||
1001 | WARN(1, "Unknown DSP type"); | ||
1002 | return -EINVAL; | ||
1003 | } | ||
1004 | |||
1005 | if (algs == 0) { | ||
1006 | adsp_err(dsp, "No algorithms\n"); | ||
1007 | return -EINVAL; | ||
1008 | } | ||
1009 | |||
1010 | if (algs > 1024) { | ||
1011 | adsp_err(dsp, "Algorithm count %zx excessive\n", algs); | ||
1012 | print_hex_dump_bytes(dev_name(dsp->dev), DUMP_PREFIX_OFFSET, | ||
1013 | buf, buf_size); | ||
1014 | return -EINVAL; | ||
1015 | } | ||
1016 | |||
1017 | /* Read the terminator first to validate the length */ | ||
1018 | ret = regmap_raw_read(regmap, mem->base + term, &val, sizeof(val)); | ||
1019 | if (ret != 0) { | 1414 | if (ret != 0) { |
1020 | adsp_err(dsp, "Failed to read algorithm list end: %d\n", | 1415 | adsp_err(dsp, "Failed to read algorithm info: %d\n", |
1021 | ret); | 1416 | ret); |
1022 | return ret; | 1417 | return ret; |
1023 | } | 1418 | } |
1024 | 1419 | ||
1025 | if (be32_to_cpu(val) != 0xbedead) | 1420 | n_algs = be32_to_cpu(adsp1_id.n_algs); |
1026 | adsp_warn(dsp, "Algorithm list end %x 0x%x != 0xbeadead\n", | 1421 | dsp->fw_id = be32_to_cpu(adsp1_id.fw.id); |
1027 | term, be32_to_cpu(val)); | 1422 | adsp_info(dsp, "Firmware: %x v%d.%d.%d, %zu algorithms\n", |
1028 | 1423 | dsp->fw_id, | |
1029 | alg = kzalloc((term - pos) * 2, GFP_KERNEL | GFP_DMA); | 1424 | (be32_to_cpu(adsp1_id.fw.ver) & 0xff0000) >> 16, |
1030 | if (!alg) | 1425 | (be32_to_cpu(adsp1_id.fw.ver) & 0xff00) >> 8, |
1031 | return -ENOMEM; | 1426 | be32_to_cpu(adsp1_id.fw.ver) & 0xff, |
1032 | 1427 | n_algs); | |
1033 | ret = regmap_raw_read(regmap, mem->base + pos, alg, (term - pos) * 2); | 1428 | |
1034 | if (ret != 0) { | 1429 | alg_region = wm_adsp_create_region(dsp, WMFW_ADSP1_ZM, |
1035 | adsp_err(dsp, "Failed to read algorithm list: %d\n", | 1430 | adsp1_id.fw.id, adsp1_id.zm); |
1036 | ret); | 1431 | if (IS_ERR(alg_region)) |
1037 | goto out; | 1432 | return PTR_ERR(alg_region); |
1038 | } | 1433 | |
1039 | 1434 | alg_region = wm_adsp_create_region(dsp, WMFW_ADSP1_DM, | |
1040 | adsp1_alg = alg; | 1435 | adsp1_id.fw.id, adsp1_id.dm); |
1041 | adsp2_alg = alg; | 1436 | if (IS_ERR(alg_region)) |
1042 | 1437 | return PTR_ERR(alg_region); | |
1043 | for (i = 0; i < algs; i++) { | 1438 | |
1044 | switch (dsp->type) { | 1439 | pos = sizeof(adsp1_id) / 2; |
1045 | case WMFW_ADSP1: | 1440 | len = (sizeof(*adsp1_alg) * n_algs) / 2; |
1046 | adsp_info(dsp, "%d: ID %x v%d.%d.%d DM@%x ZM@%x\n", | 1441 | |
1047 | i, be32_to_cpu(adsp1_alg[i].alg.id), | 1442 | adsp1_alg = wm_adsp_read_algs(dsp, n_algs, mem->base + pos, len); |
1048 | (be32_to_cpu(adsp1_alg[i].alg.ver) & 0xff0000) >> 16, | 1443 | if (IS_ERR(adsp1_alg)) |
1049 | (be32_to_cpu(adsp1_alg[i].alg.ver) & 0xff00) >> 8, | 1444 | return PTR_ERR(adsp1_alg); |
1050 | be32_to_cpu(adsp1_alg[i].alg.ver) & 0xff, | 1445 | |
1051 | be32_to_cpu(adsp1_alg[i].dm), | 1446 | for (i = 0; i < n_algs; i++) { |
1052 | be32_to_cpu(adsp1_alg[i].zm)); | 1447 | adsp_info(dsp, "%d: ID %x v%d.%d.%d DM@%x ZM@%x\n", |
1053 | 1448 | i, be32_to_cpu(adsp1_alg[i].alg.id), | |
1054 | region = kzalloc(sizeof(*region), GFP_KERNEL); | 1449 | (be32_to_cpu(adsp1_alg[i].alg.ver) & 0xff0000) >> 16, |
1055 | if (!region) { | 1450 | (be32_to_cpu(adsp1_alg[i].alg.ver) & 0xff00) >> 8, |
1056 | ret = -ENOMEM; | 1451 | be32_to_cpu(adsp1_alg[i].alg.ver) & 0xff, |
1057 | goto out; | 1452 | be32_to_cpu(adsp1_alg[i].dm), |
1058 | } | 1453 | be32_to_cpu(adsp1_alg[i].zm)); |
1059 | region->type = WMFW_ADSP1_DM; | 1454 | |
1060 | region->alg = be32_to_cpu(adsp1_alg[i].alg.id); | 1455 | alg_region = wm_adsp_create_region(dsp, WMFW_ADSP1_DM, |
1061 | region->base = be32_to_cpu(adsp1_alg[i].dm); | 1456 | adsp1_alg[i].alg.id, |
1062 | region->len = 0; | 1457 | adsp1_alg[i].dm); |
1063 | list_add_tail(®ion->list, &dsp->alg_regions); | 1458 | if (IS_ERR(alg_region)) { |
1064 | if (i + 1 < algs) { | 1459 | ret = PTR_ERR(alg_region); |
1065 | region->len = be32_to_cpu(adsp1_alg[i + 1].dm); | 1460 | goto out; |
1066 | region->len -= be32_to_cpu(adsp1_alg[i].dm); | 1461 | } |
1067 | region->len *= 4; | 1462 | if (dsp->fw_ver == 0) { |
1068 | wm_adsp_create_control(dsp, region); | 1463 | if (i + 1 < n_algs) { |
1464 | len = be32_to_cpu(adsp1_alg[i + 1].dm); | ||
1465 | len -= be32_to_cpu(adsp1_alg[i].dm); | ||
1466 | len *= 4; | ||
1467 | wm_adsp_create_control(dsp, alg_region, 0, | ||
1468 | len, NULL, 0, 0); | ||
1069 | } else { | 1469 | } else { |
1070 | adsp_warn(dsp, "Missing length info for region DM with ID %x\n", | 1470 | adsp_warn(dsp, "Missing length info for region DM with ID %x\n", |
1071 | be32_to_cpu(adsp1_alg[i].alg.id)); | 1471 | be32_to_cpu(adsp1_alg[i].alg.id)); |
1072 | } | 1472 | } |
1473 | } | ||
1073 | 1474 | ||
1074 | region = kzalloc(sizeof(*region), GFP_KERNEL); | 1475 | alg_region = wm_adsp_create_region(dsp, WMFW_ADSP1_ZM, |
1075 | if (!region) { | 1476 | adsp1_alg[i].alg.id, |
1076 | ret = -ENOMEM; | 1477 | adsp1_alg[i].zm); |
1077 | goto out; | 1478 | if (IS_ERR(alg_region)) { |
1078 | } | 1479 | ret = PTR_ERR(alg_region); |
1079 | region->type = WMFW_ADSP1_ZM; | 1480 | goto out; |
1080 | region->alg = be32_to_cpu(adsp1_alg[i].alg.id); | 1481 | } |
1081 | region->base = be32_to_cpu(adsp1_alg[i].zm); | 1482 | if (dsp->fw_ver == 0) { |
1082 | region->len = 0; | 1483 | if (i + 1 < n_algs) { |
1083 | list_add_tail(®ion->list, &dsp->alg_regions); | 1484 | len = be32_to_cpu(adsp1_alg[i + 1].zm); |
1084 | if (i + 1 < algs) { | 1485 | len -= be32_to_cpu(adsp1_alg[i].zm); |
1085 | region->len = be32_to_cpu(adsp1_alg[i + 1].zm); | 1486 | len *= 4; |
1086 | region->len -= be32_to_cpu(adsp1_alg[i].zm); | 1487 | wm_adsp_create_control(dsp, alg_region, 0, |
1087 | region->len *= 4; | 1488 | len, NULL, 0, 0); |
1088 | wm_adsp_create_control(dsp, region); | ||
1089 | } else { | 1489 | } else { |
1090 | adsp_warn(dsp, "Missing length info for region ZM with ID %x\n", | 1490 | adsp_warn(dsp, "Missing length info for region ZM with ID %x\n", |
1091 | be32_to_cpu(adsp1_alg[i].alg.id)); | 1491 | be32_to_cpu(adsp1_alg[i].alg.id)); |
1092 | } | 1492 | } |
1093 | break; | 1493 | } |
1494 | } | ||
1094 | 1495 | ||
1095 | case WMFW_ADSP2: | 1496 | out: |
1096 | adsp_info(dsp, | 1497 | kfree(adsp1_alg); |
1097 | "%d: ID %x v%d.%d.%d XM@%x YM@%x ZM@%x\n", | 1498 | return ret; |
1098 | i, be32_to_cpu(adsp2_alg[i].alg.id), | 1499 | } |
1099 | (be32_to_cpu(adsp2_alg[i].alg.ver) & 0xff0000) >> 16, | 1500 | |
1100 | (be32_to_cpu(adsp2_alg[i].alg.ver) & 0xff00) >> 8, | 1501 | static int wm_adsp2_setup_algs(struct wm_adsp *dsp) |
1101 | be32_to_cpu(adsp2_alg[i].alg.ver) & 0xff, | 1502 | { |
1102 | be32_to_cpu(adsp2_alg[i].xm), | 1503 | struct wmfw_adsp2_id_hdr adsp2_id; |
1103 | be32_to_cpu(adsp2_alg[i].ym), | 1504 | struct wmfw_adsp2_alg_hdr *adsp2_alg; |
1104 | be32_to_cpu(adsp2_alg[i].zm)); | 1505 | struct wm_adsp_alg_region *alg_region; |
1105 | 1506 | const struct wm_adsp_region *mem; | |
1106 | region = kzalloc(sizeof(*region), GFP_KERNEL); | 1507 | unsigned int pos, len; |
1107 | if (!region) { | 1508 | size_t n_algs; |
1108 | ret = -ENOMEM; | 1509 | int i, ret; |
1109 | goto out; | 1510 | |
1110 | } | 1511 | mem = wm_adsp_find_region(dsp, WMFW_ADSP2_XM); |
1111 | region->type = WMFW_ADSP2_XM; | 1512 | if (WARN_ON(!mem)) |
1112 | region->alg = be32_to_cpu(adsp2_alg[i].alg.id); | 1513 | return -EINVAL; |
1113 | region->base = be32_to_cpu(adsp2_alg[i].xm); | 1514 | |
1114 | region->len = 0; | 1515 | ret = regmap_raw_read(dsp->regmap, mem->base, &adsp2_id, |
1115 | list_add_tail(®ion->list, &dsp->alg_regions); | 1516 | sizeof(adsp2_id)); |
1116 | if (i + 1 < algs) { | 1517 | if (ret != 0) { |
1117 | region->len = be32_to_cpu(adsp2_alg[i + 1].xm); | 1518 | adsp_err(dsp, "Failed to read algorithm info: %d\n", |
1118 | region->len -= be32_to_cpu(adsp2_alg[i].xm); | 1519 | ret); |
1119 | region->len *= 4; | 1520 | return ret; |
1120 | wm_adsp_create_control(dsp, region); | 1521 | } |
1522 | |||
1523 | n_algs = be32_to_cpu(adsp2_id.n_algs); | ||
1524 | dsp->fw_id = be32_to_cpu(adsp2_id.fw.id); | ||
1525 | dsp->fw_id_version = be32_to_cpu(adsp2_id.fw.ver); | ||
1526 | adsp_info(dsp, "Firmware: %x v%d.%d.%d, %zu algorithms\n", | ||
1527 | dsp->fw_id, | ||
1528 | (dsp->fw_id_version & 0xff0000) >> 16, | ||
1529 | (dsp->fw_id_version & 0xff00) >> 8, | ||
1530 | dsp->fw_id_version & 0xff, | ||
1531 | n_algs); | ||
1532 | |||
1533 | alg_region = wm_adsp_create_region(dsp, WMFW_ADSP2_XM, | ||
1534 | adsp2_id.fw.id, adsp2_id.xm); | ||
1535 | if (IS_ERR(alg_region)) | ||
1536 | return PTR_ERR(alg_region); | ||
1537 | |||
1538 | alg_region = wm_adsp_create_region(dsp, WMFW_ADSP2_YM, | ||
1539 | adsp2_id.fw.id, adsp2_id.ym); | ||
1540 | if (IS_ERR(alg_region)) | ||
1541 | return PTR_ERR(alg_region); | ||
1542 | |||
1543 | alg_region = wm_adsp_create_region(dsp, WMFW_ADSP2_ZM, | ||
1544 | adsp2_id.fw.id, adsp2_id.zm); | ||
1545 | if (IS_ERR(alg_region)) | ||
1546 | return PTR_ERR(alg_region); | ||
1547 | |||
1548 | pos = sizeof(adsp2_id) / 2; | ||
1549 | len = (sizeof(*adsp2_alg) * n_algs) / 2; | ||
1550 | |||
1551 | adsp2_alg = wm_adsp_read_algs(dsp, n_algs, mem->base + pos, len); | ||
1552 | if (IS_ERR(adsp2_alg)) | ||
1553 | return PTR_ERR(adsp2_alg); | ||
1554 | |||
1555 | for (i = 0; i < n_algs; i++) { | ||
1556 | adsp_info(dsp, | ||
1557 | "%d: ID %x v%d.%d.%d XM@%x YM@%x ZM@%x\n", | ||
1558 | i, be32_to_cpu(adsp2_alg[i].alg.id), | ||
1559 | (be32_to_cpu(adsp2_alg[i].alg.ver) & 0xff0000) >> 16, | ||
1560 | (be32_to_cpu(adsp2_alg[i].alg.ver) & 0xff00) >> 8, | ||
1561 | be32_to_cpu(adsp2_alg[i].alg.ver) & 0xff, | ||
1562 | be32_to_cpu(adsp2_alg[i].xm), | ||
1563 | be32_to_cpu(adsp2_alg[i].ym), | ||
1564 | be32_to_cpu(adsp2_alg[i].zm)); | ||
1565 | |||
1566 | alg_region = wm_adsp_create_region(dsp, WMFW_ADSP2_XM, | ||
1567 | adsp2_alg[i].alg.id, | ||
1568 | adsp2_alg[i].xm); | ||
1569 | if (IS_ERR(alg_region)) { | ||
1570 | ret = PTR_ERR(alg_region); | ||
1571 | goto out; | ||
1572 | } | ||
1573 | if (dsp->fw_ver == 0) { | ||
1574 | if (i + 1 < n_algs) { | ||
1575 | len = be32_to_cpu(adsp2_alg[i + 1].xm); | ||
1576 | len -= be32_to_cpu(adsp2_alg[i].xm); | ||
1577 | len *= 4; | ||
1578 | wm_adsp_create_control(dsp, alg_region, 0, | ||
1579 | len, NULL, 0, 0); | ||
1121 | } else { | 1580 | } else { |
1122 | adsp_warn(dsp, "Missing length info for region XM with ID %x\n", | 1581 | adsp_warn(dsp, "Missing length info for region XM with ID %x\n", |
1123 | be32_to_cpu(adsp2_alg[i].alg.id)); | 1582 | be32_to_cpu(adsp2_alg[i].alg.id)); |
1124 | } | 1583 | } |
1584 | } | ||
1125 | 1585 | ||
1126 | region = kzalloc(sizeof(*region), GFP_KERNEL); | 1586 | alg_region = wm_adsp_create_region(dsp, WMFW_ADSP2_YM, |
1127 | if (!region) { | 1587 | adsp2_alg[i].alg.id, |
1128 | ret = -ENOMEM; | 1588 | adsp2_alg[i].ym); |
1129 | goto out; | 1589 | if (IS_ERR(alg_region)) { |
1130 | } | 1590 | ret = PTR_ERR(alg_region); |
1131 | region->type = WMFW_ADSP2_YM; | 1591 | goto out; |
1132 | region->alg = be32_to_cpu(adsp2_alg[i].alg.id); | 1592 | } |
1133 | region->base = be32_to_cpu(adsp2_alg[i].ym); | 1593 | if (dsp->fw_ver == 0) { |
1134 | region->len = 0; | 1594 | if (i + 1 < n_algs) { |
1135 | list_add_tail(®ion->list, &dsp->alg_regions); | 1595 | len = be32_to_cpu(adsp2_alg[i + 1].ym); |
1136 | if (i + 1 < algs) { | 1596 | len -= be32_to_cpu(adsp2_alg[i].ym); |
1137 | region->len = be32_to_cpu(adsp2_alg[i + 1].ym); | 1597 | len *= 4; |
1138 | region->len -= be32_to_cpu(adsp2_alg[i].ym); | 1598 | wm_adsp_create_control(dsp, alg_region, 0, |
1139 | region->len *= 4; | 1599 | len, NULL, 0, 0); |
1140 | wm_adsp_create_control(dsp, region); | ||
1141 | } else { | 1600 | } else { |
1142 | adsp_warn(dsp, "Missing length info for region YM with ID %x\n", | 1601 | adsp_warn(dsp, "Missing length info for region YM with ID %x\n", |
1143 | be32_to_cpu(adsp2_alg[i].alg.id)); | 1602 | be32_to_cpu(adsp2_alg[i].alg.id)); |
1144 | } | 1603 | } |
1604 | } | ||
1145 | 1605 | ||
1146 | region = kzalloc(sizeof(*region), GFP_KERNEL); | 1606 | alg_region = wm_adsp_create_region(dsp, WMFW_ADSP2_ZM, |
1147 | if (!region) { | 1607 | adsp2_alg[i].alg.id, |
1148 | ret = -ENOMEM; | 1608 | adsp2_alg[i].zm); |
1149 | goto out; | 1609 | if (IS_ERR(alg_region)) { |
1150 | } | 1610 | ret = PTR_ERR(alg_region); |
1151 | region->type = WMFW_ADSP2_ZM; | 1611 | goto out; |
1152 | region->alg = be32_to_cpu(adsp2_alg[i].alg.id); | 1612 | } |
1153 | region->base = be32_to_cpu(adsp2_alg[i].zm); | 1613 | if (dsp->fw_ver == 0) { |
1154 | region->len = 0; | 1614 | if (i + 1 < n_algs) { |
1155 | list_add_tail(®ion->list, &dsp->alg_regions); | 1615 | len = be32_to_cpu(adsp2_alg[i + 1].zm); |
1156 | if (i + 1 < algs) { | 1616 | len -= be32_to_cpu(adsp2_alg[i].zm); |
1157 | region->len = be32_to_cpu(adsp2_alg[i + 1].zm); | 1617 | len *= 4; |
1158 | region->len -= be32_to_cpu(adsp2_alg[i].zm); | 1618 | wm_adsp_create_control(dsp, alg_region, 0, |
1159 | region->len *= 4; | 1619 | len, NULL, 0, 0); |
1160 | wm_adsp_create_control(dsp, region); | ||
1161 | } else { | 1620 | } else { |
1162 | adsp_warn(dsp, "Missing length info for region ZM with ID %x\n", | 1621 | adsp_warn(dsp, "Missing length info for region ZM with ID %x\n", |
1163 | be32_to_cpu(adsp2_alg[i].alg.id)); | 1622 | be32_to_cpu(adsp2_alg[i].alg.id)); |
1164 | } | 1623 | } |
1165 | break; | ||
1166 | } | 1624 | } |
1167 | } | 1625 | } |
1168 | 1626 | ||
1169 | out: | 1627 | out: |
1170 | kfree(alg); | 1628 | kfree(adsp2_alg); |
1171 | return ret; | 1629 | return ret; |
1172 | } | 1630 | } |
1173 | 1631 | ||
@@ -1345,6 +1803,8 @@ static int wm_adsp_load_coeff(struct wm_adsp *dsp) | |||
1345 | adsp_warn(dsp, "%s.%d: %zu bytes at end of file\n", | 1803 | adsp_warn(dsp, "%s.%d: %zu bytes at end of file\n", |
1346 | file, blocks, pos - firmware->size); | 1804 | file, blocks, pos - firmware->size); |
1347 | 1805 | ||
1806 | wm_adsp_debugfs_save_binname(dsp, file); | ||
1807 | |||
1348 | out_fw: | 1808 | out_fw: |
1349 | regmap_async_complete(regmap); | 1809 | regmap_async_complete(regmap); |
1350 | release_firmware(firmware); | 1810 | release_firmware(firmware); |
@@ -1354,10 +1814,13 @@ out: | |||
1354 | return ret; | 1814 | return ret; |
1355 | } | 1815 | } |
1356 | 1816 | ||
1357 | int wm_adsp1_init(struct wm_adsp *adsp) | 1817 | int wm_adsp1_init(struct wm_adsp *dsp) |
1358 | { | 1818 | { |
1359 | INIT_LIST_HEAD(&adsp->alg_regions); | 1819 | INIT_LIST_HEAD(&dsp->alg_regions); |
1360 | 1820 | ||
1821 | #ifdef CONFIG_DEBUG_FS | ||
1822 | mutex_init(&dsp->debugfs_lock); | ||
1823 | #endif | ||
1361 | return 0; | 1824 | return 0; |
1362 | } | 1825 | } |
1363 | EXPORT_SYMBOL_GPL(wm_adsp1_init); | 1826 | EXPORT_SYMBOL_GPL(wm_adsp1_init); |
@@ -1410,7 +1873,7 @@ int wm_adsp1_event(struct snd_soc_dapm_widget *w, | |||
1410 | if (ret != 0) | 1873 | if (ret != 0) |
1411 | goto err; | 1874 | goto err; |
1412 | 1875 | ||
1413 | ret = wm_adsp_setup_algs(dsp); | 1876 | ret = wm_adsp1_setup_algs(dsp); |
1414 | if (ret != 0) | 1877 | if (ret != 0) |
1415 | goto err; | 1878 | goto err; |
1416 | 1879 | ||
@@ -1531,35 +1994,6 @@ static void wm_adsp2_boot_work(struct work_struct *work) | |||
1531 | return; | 1994 | return; |
1532 | } | 1995 | } |
1533 | 1996 | ||
1534 | if (dsp->dvfs) { | ||
1535 | ret = regmap_read(dsp->regmap, | ||
1536 | dsp->base + ADSP2_CLOCKING, &val); | ||
1537 | if (ret != 0) { | ||
1538 | adsp_err(dsp, "Failed to read clocking: %d\n", ret); | ||
1539 | return; | ||
1540 | } | ||
1541 | |||
1542 | if ((val & ADSP2_CLK_SEL_MASK) >= 3) { | ||
1543 | ret = regulator_enable(dsp->dvfs); | ||
1544 | if (ret != 0) { | ||
1545 | adsp_err(dsp, | ||
1546 | "Failed to enable supply: %d\n", | ||
1547 | ret); | ||
1548 | return; | ||
1549 | } | ||
1550 | |||
1551 | ret = regulator_set_voltage(dsp->dvfs, | ||
1552 | 1800000, | ||
1553 | 1800000); | ||
1554 | if (ret != 0) { | ||
1555 | adsp_err(dsp, | ||
1556 | "Failed to raise supply: %d\n", | ||
1557 | ret); | ||
1558 | return; | ||
1559 | } | ||
1560 | } | ||
1561 | } | ||
1562 | |||
1563 | ret = wm_adsp2_ena(dsp); | 1997 | ret = wm_adsp2_ena(dsp); |
1564 | if (ret != 0) | 1998 | if (ret != 0) |
1565 | return; | 1999 | return; |
@@ -1568,7 +2002,7 @@ static void wm_adsp2_boot_work(struct work_struct *work) | |||
1568 | if (ret != 0) | 2002 | if (ret != 0) |
1569 | goto err; | 2003 | goto err; |
1570 | 2004 | ||
1571 | ret = wm_adsp_setup_algs(dsp); | 2005 | ret = wm_adsp2_setup_algs(dsp); |
1572 | if (ret != 0) | 2006 | if (ret != 0) |
1573 | goto err; | 2007 | goto err; |
1574 | 2008 | ||
@@ -1642,6 +2076,13 @@ int wm_adsp2_event(struct snd_soc_dapm_widget *w, | |||
1642 | break; | 2076 | break; |
1643 | 2077 | ||
1644 | case SND_SOC_DAPM_PRE_PMD: | 2078 | case SND_SOC_DAPM_PRE_PMD: |
2079 | /* Log firmware state, it can be useful for analysis */ | ||
2080 | wm_adsp2_show_fw_status(dsp); | ||
2081 | |||
2082 | wm_adsp_debugfs_clear(dsp); | ||
2083 | |||
2084 | dsp->fw_id = 0; | ||
2085 | dsp->fw_id_version = 0; | ||
1645 | dsp->running = false; | 2086 | dsp->running = false; |
1646 | 2087 | ||
1647 | regmap_update_bits(dsp->regmap, dsp->base + ADSP2_CONTROL, | 2088 | regmap_update_bits(dsp->regmap, dsp->base + ADSP2_CONTROL, |
@@ -1653,21 +2094,6 @@ int wm_adsp2_event(struct snd_soc_dapm_widget *w, | |||
1653 | regmap_write(dsp->regmap, dsp->base + ADSP2_WDMA_CONFIG_2, 0); | 2094 | regmap_write(dsp->regmap, dsp->base + ADSP2_WDMA_CONFIG_2, 0); |
1654 | regmap_write(dsp->regmap, dsp->base + ADSP2_RDMA_CONFIG_1, 0); | 2095 | regmap_write(dsp->regmap, dsp->base + ADSP2_RDMA_CONFIG_1, 0); |
1655 | 2096 | ||
1656 | if (dsp->dvfs) { | ||
1657 | ret = regulator_set_voltage(dsp->dvfs, 1200000, | ||
1658 | 1800000); | ||
1659 | if (ret != 0) | ||
1660 | adsp_warn(dsp, | ||
1661 | "Failed to lower supply: %d\n", | ||
1662 | ret); | ||
1663 | |||
1664 | ret = regulator_disable(dsp->dvfs); | ||
1665 | if (ret != 0) | ||
1666 | adsp_err(dsp, | ||
1667 | "Failed to enable supply: %d\n", | ||
1668 | ret); | ||
1669 | } | ||
1670 | |||
1671 | list_for_each_entry(ctl, &dsp->ctl_list, list) | 2097 | list_for_each_entry(ctl, &dsp->ctl_list, list) |
1672 | ctl->enabled = 0; | 2098 | ctl->enabled = 0; |
1673 | 2099 | ||
@@ -1694,7 +2120,25 @@ err: | |||
1694 | } | 2120 | } |
1695 | EXPORT_SYMBOL_GPL(wm_adsp2_event); | 2121 | EXPORT_SYMBOL_GPL(wm_adsp2_event); |
1696 | 2122 | ||
1697 | int wm_adsp2_init(struct wm_adsp *adsp, bool dvfs) | 2123 | int wm_adsp2_codec_probe(struct wm_adsp *dsp, struct snd_soc_codec *codec) |
2124 | { | ||
2125 | wm_adsp2_init_debugfs(dsp, codec); | ||
2126 | |||
2127 | return snd_soc_add_codec_controls(codec, | ||
2128 | wm_adsp2_fw_controls[dsp->num - 1], | ||
2129 | ARRAY_SIZE(wm_adsp2_fw_controls[0])); | ||
2130 | } | ||
2131 | EXPORT_SYMBOL_GPL(wm_adsp2_codec_probe); | ||
2132 | |||
2133 | int wm_adsp2_codec_remove(struct wm_adsp *dsp, struct snd_soc_codec *codec) | ||
2134 | { | ||
2135 | wm_adsp2_cleanup_debugfs(dsp); | ||
2136 | |||
2137 | return 0; | ||
2138 | } | ||
2139 | EXPORT_SYMBOL_GPL(wm_adsp2_codec_remove); | ||
2140 | |||
2141 | int wm_adsp2_init(struct wm_adsp *dsp) | ||
1698 | { | 2142 | { |
1699 | int ret; | 2143 | int ret; |
1700 | 2144 | ||
@@ -1702,44 +2146,20 @@ int wm_adsp2_init(struct wm_adsp *adsp, bool dvfs) | |||
1702 | * Disable the DSP memory by default when in reset for a small | 2146 | * Disable the DSP memory by default when in reset for a small |
1703 | * power saving. | 2147 | * power saving. |
1704 | */ | 2148 | */ |
1705 | ret = regmap_update_bits(adsp->regmap, adsp->base + ADSP2_CONTROL, | 2149 | ret = regmap_update_bits(dsp->regmap, dsp->base + ADSP2_CONTROL, |
1706 | ADSP2_MEM_ENA, 0); | 2150 | ADSP2_MEM_ENA, 0); |
1707 | if (ret != 0) { | 2151 | if (ret != 0) { |
1708 | adsp_err(adsp, "Failed to clear memory retention: %d\n", ret); | 2152 | adsp_err(dsp, "Failed to clear memory retention: %d\n", ret); |
1709 | return ret; | 2153 | return ret; |
1710 | } | 2154 | } |
1711 | 2155 | ||
1712 | INIT_LIST_HEAD(&adsp->alg_regions); | 2156 | INIT_LIST_HEAD(&dsp->alg_regions); |
1713 | INIT_LIST_HEAD(&adsp->ctl_list); | 2157 | INIT_LIST_HEAD(&dsp->ctl_list); |
1714 | INIT_WORK(&adsp->boot_work, wm_adsp2_boot_work); | 2158 | INIT_WORK(&dsp->boot_work, wm_adsp2_boot_work); |
1715 | |||
1716 | if (dvfs) { | ||
1717 | adsp->dvfs = devm_regulator_get(adsp->dev, "DCVDD"); | ||
1718 | if (IS_ERR(adsp->dvfs)) { | ||
1719 | ret = PTR_ERR(adsp->dvfs); | ||
1720 | adsp_err(adsp, "Failed to get DCVDD: %d\n", ret); | ||
1721 | return ret; | ||
1722 | } | ||
1723 | |||
1724 | ret = regulator_enable(adsp->dvfs); | ||
1725 | if (ret != 0) { | ||
1726 | adsp_err(adsp, "Failed to enable DCVDD: %d\n", ret); | ||
1727 | return ret; | ||
1728 | } | ||
1729 | |||
1730 | ret = regulator_set_voltage(adsp->dvfs, 1200000, 1800000); | ||
1731 | if (ret != 0) { | ||
1732 | adsp_err(adsp, "Failed to initialise DVFS: %d\n", ret); | ||
1733 | return ret; | ||
1734 | } | ||
1735 | |||
1736 | ret = regulator_disable(adsp->dvfs); | ||
1737 | if (ret != 0) { | ||
1738 | adsp_err(adsp, "Failed to disable DCVDD: %d\n", ret); | ||
1739 | return ret; | ||
1740 | } | ||
1741 | } | ||
1742 | 2159 | ||
2160 | #ifdef CONFIG_DEBUG_FS | ||
2161 | mutex_init(&dsp->debugfs_lock); | ||
2162 | #endif | ||
1743 | return 0; | 2163 | return 0; |
1744 | } | 2164 | } |
1745 | EXPORT_SYMBOL_GPL(wm_adsp2_init); | 2165 | EXPORT_SYMBOL_GPL(wm_adsp2_init); |
diff --git a/sound/soc/codecs/wm_adsp.h b/sound/soc/codecs/wm_adsp.h index a4f6b64deb61..5042cbd39e54 100644 --- a/sound/soc/codecs/wm_adsp.h +++ b/sound/soc/codecs/wm_adsp.h | |||
@@ -18,8 +18,6 @@ | |||
18 | 18 | ||
19 | #include "wmfw.h" | 19 | #include "wmfw.h" |
20 | 20 | ||
21 | struct regulator; | ||
22 | |||
23 | struct wm_adsp_region { | 21 | struct wm_adsp_region { |
24 | int type; | 22 | int type; |
25 | unsigned int base; | 23 | unsigned int base; |
@@ -30,7 +28,6 @@ struct wm_adsp_alg_region { | |||
30 | unsigned int alg; | 28 | unsigned int alg; |
31 | int type; | 29 | int type; |
32 | unsigned int base; | 30 | unsigned int base; |
33 | size_t len; | ||
34 | }; | 31 | }; |
35 | 32 | ||
36 | struct wm_adsp { | 33 | struct wm_adsp { |
@@ -49,37 +46,49 @@ struct wm_adsp { | |||
49 | struct list_head alg_regions; | 46 | struct list_head alg_regions; |
50 | 47 | ||
51 | int fw_id; | 48 | int fw_id; |
49 | int fw_id_version; | ||
52 | 50 | ||
53 | const struct wm_adsp_region *mem; | 51 | const struct wm_adsp_region *mem; |
54 | int num_mems; | 52 | int num_mems; |
55 | 53 | ||
56 | int fw; | 54 | int fw; |
57 | bool running; | 55 | int fw_ver; |
58 | 56 | u32 running; | |
59 | struct regulator *dvfs; | ||
60 | 57 | ||
61 | struct list_head ctl_list; | 58 | struct list_head ctl_list; |
62 | 59 | ||
63 | struct work_struct boot_work; | 60 | struct work_struct boot_work; |
61 | |||
62 | #ifdef CONFIG_DEBUG_FS | ||
63 | struct dentry *debugfs_root; | ||
64 | struct mutex debugfs_lock; | ||
65 | char *wmfw_file_name; | ||
66 | char *bin_file_name; | ||
67 | #endif | ||
68 | |||
64 | }; | 69 | }; |
65 | 70 | ||
66 | #define WM_ADSP1(wname, num) \ | 71 | #define WM_ADSP1(wname, num) \ |
67 | SND_SOC_DAPM_PGA_E(wname, SND_SOC_NOPM, num, 0, NULL, 0, \ | 72 | SND_SOC_DAPM_PGA_E(wname, SND_SOC_NOPM, num, 0, NULL, 0, \ |
68 | wm_adsp1_event, SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD) | 73 | wm_adsp1_event, SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD) |
69 | 74 | ||
70 | #define WM_ADSP2(wname, num) \ | 75 | #define WM_ADSP2_E(wname, num, event_fn) \ |
71 | { .id = snd_soc_dapm_dai_link, .name = wname " Preloader", \ | 76 | { .id = snd_soc_dapm_dai_link, .name = wname " Preloader", \ |
72 | .reg = SND_SOC_NOPM, .shift = num, .event = wm_adsp2_early_event, \ | 77 | .reg = SND_SOC_NOPM, .shift = num, .event = event_fn, \ |
73 | .event_flags = SND_SOC_DAPM_PRE_PMU }, \ | 78 | .event_flags = SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD }, \ |
74 | { .id = snd_soc_dapm_out_drv, .name = wname, \ | 79 | { .id = snd_soc_dapm_out_drv, .name = wname, \ |
75 | .reg = SND_SOC_NOPM, .shift = num, .event = wm_adsp2_event, \ | 80 | .reg = SND_SOC_NOPM, .shift = num, .event = wm_adsp2_event, \ |
76 | .event_flags = SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD } | 81 | .event_flags = SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD } |
77 | 82 | ||
83 | #define WM_ADSP2(wname, num) \ | ||
84 | WM_ADSP2_E(wname, num, wm_adsp2_early_event) | ||
85 | |||
78 | extern const struct snd_kcontrol_new wm_adsp1_fw_controls[]; | 86 | extern const struct snd_kcontrol_new wm_adsp1_fw_controls[]; |
79 | extern const struct snd_kcontrol_new wm_adsp2_fw_controls[]; | ||
80 | 87 | ||
81 | int wm_adsp1_init(struct wm_adsp *adsp); | 88 | int wm_adsp1_init(struct wm_adsp *dsp); |
82 | int wm_adsp2_init(struct wm_adsp *adsp, bool dvfs); | 89 | int wm_adsp2_init(struct wm_adsp *dsp); |
90 | int wm_adsp2_codec_probe(struct wm_adsp *dsp, struct snd_soc_codec *codec); | ||
91 | int wm_adsp2_codec_remove(struct wm_adsp *dsp, struct snd_soc_codec *codec); | ||
83 | int wm_adsp1_event(struct snd_soc_dapm_widget *w, | 92 | int wm_adsp1_event(struct snd_soc_dapm_widget *w, |
84 | struct snd_kcontrol *kcontrol, int event); | 93 | struct snd_kcontrol *kcontrol, int event); |
85 | int wm_adsp2_early_event(struct snd_soc_dapm_widget *w, | 94 | int wm_adsp2_early_event(struct snd_soc_dapm_widget *w, |
diff --git a/sound/soc/codecs/wm_hubs.c b/sound/soc/codecs/wm_hubs.c index 8366e19657a7..fd86bd105460 100644 --- a/sound/soc/codecs/wm_hubs.c +++ b/sound/soc/codecs/wm_hubs.c | |||
@@ -1116,7 +1116,7 @@ static const struct snd_soc_dapm_route lineout2_se_routes[] = { | |||
1116 | 1116 | ||
1117 | int wm_hubs_add_analogue_controls(struct snd_soc_codec *codec) | 1117 | int wm_hubs_add_analogue_controls(struct snd_soc_codec *codec) |
1118 | { | 1118 | { |
1119 | struct snd_soc_dapm_context *dapm = &codec->dapm; | 1119 | struct snd_soc_dapm_context *dapm = snd_soc_codec_get_dapm(codec); |
1120 | 1120 | ||
1121 | /* Latch volume update bits & default ZC on */ | 1121 | /* Latch volume update bits & default ZC on */ |
1122 | snd_soc_update_bits(codec, WM8993_LEFT_LINE_INPUT_1_2_VOLUME, | 1122 | snd_soc_update_bits(codec, WM8993_LEFT_LINE_INPUT_1_2_VOLUME, |
@@ -1160,7 +1160,7 @@ int wm_hubs_add_analogue_routes(struct snd_soc_codec *codec, | |||
1160 | int lineout1_diff, int lineout2_diff) | 1160 | int lineout1_diff, int lineout2_diff) |
1161 | { | 1161 | { |
1162 | struct wm_hubs_data *hubs = snd_soc_codec_get_drvdata(codec); | 1162 | struct wm_hubs_data *hubs = snd_soc_codec_get_drvdata(codec); |
1163 | struct snd_soc_dapm_context *dapm = &codec->dapm; | 1163 | struct snd_soc_dapm_context *dapm = snd_soc_codec_get_dapm(codec); |
1164 | 1164 | ||
1165 | hubs->codec = codec; | 1165 | hubs->codec = codec; |
1166 | 1166 | ||
diff --git a/sound/soc/codecs/wmfw.h b/sound/soc/codecs/wmfw.h index ef163360a745..7613d60d62ea 100644 --- a/sound/soc/codecs/wmfw.h +++ b/sound/soc/codecs/wmfw.h | |||
@@ -15,6 +15,17 @@ | |||
15 | 15 | ||
16 | #include <linux/types.h> | 16 | #include <linux/types.h> |
17 | 17 | ||
18 | #define WMFW_MAX_ALG_NAME 256 | ||
19 | #define WMFW_MAX_ALG_DESCR_NAME 256 | ||
20 | |||
21 | #define WMFW_MAX_COEFF_NAME 256 | ||
22 | #define WMFW_MAX_COEFF_DESCR_NAME 256 | ||
23 | |||
24 | #define WMFW_CTL_FLAG_SYS 0x8000 | ||
25 | #define WMFW_CTL_FLAG_VOLATILE 0x0004 | ||
26 | #define WMFW_CTL_FLAG_WRITEABLE 0x0002 | ||
27 | #define WMFW_CTL_FLAG_READABLE 0x0001 | ||
28 | |||
18 | struct wmfw_header { | 29 | struct wmfw_header { |
19 | char magic[4]; | 30 | char magic[4]; |
20 | __le32 len; | 31 | __le32 len; |
@@ -61,7 +72,7 @@ struct wmfw_adsp1_id_hdr { | |||
61 | struct wmfw_id_hdr fw; | 72 | struct wmfw_id_hdr fw; |
62 | __be32 zm; | 73 | __be32 zm; |
63 | __be32 dm; | 74 | __be32 dm; |
64 | __be32 algs; | 75 | __be32 n_algs; |
65 | } __packed; | 76 | } __packed; |
66 | 77 | ||
67 | struct wmfw_adsp2_id_hdr { | 78 | struct wmfw_adsp2_id_hdr { |
@@ -69,7 +80,7 @@ struct wmfw_adsp2_id_hdr { | |||
69 | __be32 zm; | 80 | __be32 zm; |
70 | __be32 xm; | 81 | __be32 xm; |
71 | __be32 ym; | 82 | __be32 ym; |
72 | __be32 algs; | 83 | __be32 n_algs; |
73 | } __packed; | 84 | } __packed; |
74 | 85 | ||
75 | struct wmfw_alg_hdr { | 86 | struct wmfw_alg_hdr { |
@@ -90,6 +101,28 @@ struct wmfw_adsp2_alg_hdr { | |||
90 | __be32 ym; | 101 | __be32 ym; |
91 | } __packed; | 102 | } __packed; |
92 | 103 | ||
104 | struct wmfw_adsp_alg_data { | ||
105 | __le32 id; | ||
106 | u8 name[WMFW_MAX_ALG_NAME]; | ||
107 | u8 descr[WMFW_MAX_ALG_DESCR_NAME]; | ||
108 | __le32 ncoeff; | ||
109 | u8 data[]; | ||
110 | } __packed; | ||
111 | |||
112 | struct wmfw_adsp_coeff_data { | ||
113 | struct { | ||
114 | __le16 offset; | ||
115 | __le16 type; | ||
116 | __le32 size; | ||
117 | } hdr; | ||
118 | u8 name[WMFW_MAX_COEFF_NAME]; | ||
119 | u8 descr[WMFW_MAX_COEFF_DESCR_NAME]; | ||
120 | __le16 ctl_type; | ||
121 | __le16 flags; | ||
122 | __le32 len; | ||
123 | u8 data[]; | ||
124 | } __packed; | ||
125 | |||
93 | struct wmfw_coeff_hdr { | 126 | struct wmfw_coeff_hdr { |
94 | u8 magic[4]; | 127 | u8 magic[4]; |
95 | __le32 len; | 128 | __le32 len; |
@@ -117,9 +150,10 @@ struct wmfw_coeff_item { | |||
117 | #define WMFW_ADSP1 1 | 150 | #define WMFW_ADSP1 1 |
118 | #define WMFW_ADSP2 2 | 151 | #define WMFW_ADSP2 2 |
119 | 152 | ||
120 | #define WMFW_ABSOLUTE 0xf0 | 153 | #define WMFW_ABSOLUTE 0xf0 |
121 | #define WMFW_NAME_TEXT 0xfe | 154 | #define WMFW_ALGORITHM_DATA 0xf2 |
122 | #define WMFW_INFO_TEXT 0xff | 155 | #define WMFW_NAME_TEXT 0xfe |
156 | #define WMFW_INFO_TEXT 0xff | ||
123 | 157 | ||
124 | #define WMFW_ADSP1_PM 2 | 158 | #define WMFW_ADSP1_PM 2 |
125 | #define WMFW_ADSP1_DM 3 | 159 | #define WMFW_ADSP1_DM 3 |
diff --git a/sound/soc/davinci/davinci-mcasp.c b/sound/soc/davinci/davinci-mcasp.c index bb4b78eada58..b960e626dad9 100644 --- a/sound/soc/davinci/davinci-mcasp.c +++ b/sound/soc/davinci/davinci-mcasp.c | |||
@@ -107,6 +107,7 @@ struct davinci_mcasp { | |||
107 | #endif | 107 | #endif |
108 | 108 | ||
109 | struct davinci_mcasp_ruledata ruledata[2]; | 109 | struct davinci_mcasp_ruledata ruledata[2]; |
110 | struct snd_pcm_hw_constraint_list chconstr[2]; | ||
110 | }; | 111 | }; |
111 | 112 | ||
112 | static inline void mcasp_set_bits(struct davinci_mcasp *mcasp, u32 offset, | 113 | static inline void mcasp_set_bits(struct davinci_mcasp *mcasp, u32 offset, |
@@ -685,6 +686,8 @@ static int mcasp_common_hw_param(struct davinci_mcasp *mcasp, int stream, | |||
685 | if (mcasp->serial_dir[i] == TX_MODE && | 686 | if (mcasp->serial_dir[i] == TX_MODE && |
686 | tx_ser < max_active_serializers) { | 687 | tx_ser < max_active_serializers) { |
687 | mcasp_set_bits(mcasp, DAVINCI_MCASP_PDIR_REG, AXR(i)); | 688 | mcasp_set_bits(mcasp, DAVINCI_MCASP_PDIR_REG, AXR(i)); |
689 | mcasp_mod_bits(mcasp, DAVINCI_MCASP_XRSRCTL_REG(i), | ||
690 | DISMOD_LOW, DISMOD_MASK); | ||
688 | tx_ser++; | 691 | tx_ser++; |
689 | } else if (mcasp->serial_dir[i] == RX_MODE && | 692 | } else if (mcasp->serial_dir[i] == RX_MODE && |
690 | rx_ser < max_active_serializers) { | 693 | rx_ser < max_active_serializers) { |
@@ -915,15 +918,12 @@ static int davinci_mcasp_hw_params(struct snd_pcm_substream *substream, | |||
915 | * the machine driver, we need to calculate the ratio. | 918 | * the machine driver, we need to calculate the ratio. |
916 | */ | 919 | */ |
917 | if (mcasp->bclk_master && mcasp->bclk_div == 0 && mcasp->sysclk_freq) { | 920 | if (mcasp->bclk_master && mcasp->bclk_div == 0 && mcasp->sysclk_freq) { |
918 | int channels = params_channels(params); | 921 | int slots = mcasp->tdm_slots; |
919 | int rate = params_rate(params); | 922 | int rate = params_rate(params); |
920 | int sbits = params_width(params); | 923 | int sbits = params_width(params); |
921 | int ppm, div; | 924 | int ppm, div; |
922 | 925 | ||
923 | if (channels > mcasp->tdm_slots) | 926 | div = davinci_mcasp_calc_clk_div(mcasp, rate*sbits*slots, |
924 | channels = mcasp->tdm_slots; | ||
925 | |||
926 | div = davinci_mcasp_calc_clk_div(mcasp, rate*sbits*channels, | ||
927 | &ppm); | 927 | &ppm); |
928 | if (ppm) | 928 | if (ppm) |
929 | dev_info(mcasp->dev, "Sample-rate is off by %d PPM\n", | 929 | dev_info(mcasp->dev, "Sample-rate is off by %d PPM\n", |
@@ -1024,31 +1024,36 @@ static int davinci_mcasp_hw_rule_rate(struct snd_pcm_hw_params *params, | |||
1024 | struct snd_interval *ri = | 1024 | struct snd_interval *ri = |
1025 | hw_param_interval(params, SNDRV_PCM_HW_PARAM_RATE); | 1025 | hw_param_interval(params, SNDRV_PCM_HW_PARAM_RATE); |
1026 | int sbits = params_width(params); | 1026 | int sbits = params_width(params); |
1027 | int channels = params_channels(params); | 1027 | int slots = rd->mcasp->tdm_slots; |
1028 | unsigned int list[ARRAY_SIZE(davinci_mcasp_dai_rates)]; | 1028 | struct snd_interval range; |
1029 | int i, count = 0; | 1029 | int i; |
1030 | 1030 | ||
1031 | if (channels > rd->mcasp->tdm_slots) | 1031 | snd_interval_any(&range); |
1032 | channels = rd->mcasp->tdm_slots; | 1032 | range.empty = 1; |
1033 | 1033 | ||
1034 | for (i = 0; i < ARRAY_SIZE(davinci_mcasp_dai_rates); i++) { | 1034 | for (i = 0; i < ARRAY_SIZE(davinci_mcasp_dai_rates); i++) { |
1035 | if (ri->min <= davinci_mcasp_dai_rates[i] && | 1035 | if (snd_interval_test(ri, davinci_mcasp_dai_rates[i])) { |
1036 | ri->max >= davinci_mcasp_dai_rates[i]) { | 1036 | uint bclk_freq = sbits*slots* |
1037 | uint bclk_freq = sbits*channels* | ||
1038 | davinci_mcasp_dai_rates[i]; | 1037 | davinci_mcasp_dai_rates[i]; |
1039 | int ppm; | 1038 | int ppm; |
1040 | 1039 | ||
1041 | davinci_mcasp_calc_clk_div(rd->mcasp, bclk_freq, &ppm); | 1040 | davinci_mcasp_calc_clk_div(rd->mcasp, bclk_freq, &ppm); |
1042 | if (abs(ppm) < DAVINCI_MAX_RATE_ERROR_PPM) | 1041 | if (abs(ppm) < DAVINCI_MAX_RATE_ERROR_PPM) { |
1043 | list[count++] = davinci_mcasp_dai_rates[i]; | 1042 | if (range.empty) { |
1043 | range.min = davinci_mcasp_dai_rates[i]; | ||
1044 | range.empty = 0; | ||
1045 | } | ||
1046 | range.max = davinci_mcasp_dai_rates[i]; | ||
1047 | } | ||
1044 | } | 1048 | } |
1045 | } | 1049 | } |
1050 | |||
1046 | dev_dbg(rd->mcasp->dev, | 1051 | dev_dbg(rd->mcasp->dev, |
1047 | "%d frequencies (%d-%d) for %d sbits and %d channels\n", | 1052 | "Frequencies %d-%d -> %d-%d for %d sbits and %d tdm slots\n", |
1048 | count, ri->min, ri->max, sbits, channels); | 1053 | ri->min, ri->max, range.min, range.max, sbits, slots); |
1049 | 1054 | ||
1050 | return snd_interval_list(hw_param_interval(params, rule->var), | 1055 | return snd_interval_refine(hw_param_interval(params, rule->var), |
1051 | count, list, 0); | 1056 | &range); |
1052 | } | 1057 | } |
1053 | 1058 | ||
1054 | static int davinci_mcasp_hw_rule_format(struct snd_pcm_hw_params *params, | 1059 | static int davinci_mcasp_hw_rule_format(struct snd_pcm_hw_params *params, |
@@ -1058,17 +1063,14 @@ static int davinci_mcasp_hw_rule_format(struct snd_pcm_hw_params *params, | |||
1058 | struct snd_mask *fmt = hw_param_mask(params, SNDRV_PCM_HW_PARAM_FORMAT); | 1063 | struct snd_mask *fmt = hw_param_mask(params, SNDRV_PCM_HW_PARAM_FORMAT); |
1059 | struct snd_mask nfmt; | 1064 | struct snd_mask nfmt; |
1060 | int rate = params_rate(params); | 1065 | int rate = params_rate(params); |
1061 | int channels = params_channels(params); | 1066 | int slots = rd->mcasp->tdm_slots; |
1062 | int i, count = 0; | 1067 | int i, count = 0; |
1063 | 1068 | ||
1064 | snd_mask_none(&nfmt); | 1069 | snd_mask_none(&nfmt); |
1065 | 1070 | ||
1066 | if (channels > rd->mcasp->tdm_slots) | ||
1067 | channels = rd->mcasp->tdm_slots; | ||
1068 | |||
1069 | for (i = 0; i < SNDRV_PCM_FORMAT_LAST; i++) { | 1071 | for (i = 0; i < SNDRV_PCM_FORMAT_LAST; i++) { |
1070 | if (snd_mask_test(fmt, i)) { | 1072 | if (snd_mask_test(fmt, i)) { |
1071 | uint bclk_freq = snd_pcm_format_width(i)*channels*rate; | 1073 | uint bclk_freq = snd_pcm_format_width(i)*slots*rate; |
1072 | int ppm; | 1074 | int ppm; |
1073 | 1075 | ||
1074 | davinci_mcasp_calc_clk_div(rd->mcasp, bclk_freq, &ppm); | 1076 | davinci_mcasp_calc_clk_div(rd->mcasp, bclk_freq, &ppm); |
@@ -1079,51 +1081,12 @@ static int davinci_mcasp_hw_rule_format(struct snd_pcm_hw_params *params, | |||
1079 | } | 1081 | } |
1080 | } | 1082 | } |
1081 | dev_dbg(rd->mcasp->dev, | 1083 | dev_dbg(rd->mcasp->dev, |
1082 | "%d possible sample format for %d Hz and %d channels\n", | 1084 | "%d possible sample format for %d Hz and %d tdm slots\n", |
1083 | count, rate, channels); | 1085 | count, rate, slots); |
1084 | 1086 | ||
1085 | return snd_mask_refine(fmt, &nfmt); | 1087 | return snd_mask_refine(fmt, &nfmt); |
1086 | } | 1088 | } |
1087 | 1089 | ||
1088 | static int davinci_mcasp_hw_rule_channels(struct snd_pcm_hw_params *params, | ||
1089 | struct snd_pcm_hw_rule *rule) | ||
1090 | { | ||
1091 | struct davinci_mcasp_ruledata *rd = rule->private; | ||
1092 | struct snd_interval *ci = | ||
1093 | hw_param_interval(params, SNDRV_PCM_HW_PARAM_CHANNELS); | ||
1094 | int sbits = params_width(params); | ||
1095 | int rate = params_rate(params); | ||
1096 | int max_chan_per_wire = rd->mcasp->tdm_slots < ci->max ? | ||
1097 | rd->mcasp->tdm_slots : ci->max; | ||
1098 | unsigned int list[ci->max - ci->min + 1]; | ||
1099 | int c1, c, count = 0; | ||
1100 | |||
1101 | for (c1 = ci->min; c1 <= max_chan_per_wire; c1++) { | ||
1102 | uint bclk_freq = c1*sbits*rate; | ||
1103 | int ppm; | ||
1104 | |||
1105 | davinci_mcasp_calc_clk_div(rd->mcasp, bclk_freq, &ppm); | ||
1106 | if (abs(ppm) < DAVINCI_MAX_RATE_ERROR_PPM) { | ||
1107 | /* If we can use all tdm_slots, we can put any | ||
1108 | amount of channels to remaining wires as | ||
1109 | long as they fit in. */ | ||
1110 | if (c1 == rd->mcasp->tdm_slots) { | ||
1111 | for (c = c1; c <= rd->serializers*c1 && | ||
1112 | c <= ci->max; c++) | ||
1113 | list[count++] = c; | ||
1114 | } else { | ||
1115 | list[count++] = c1; | ||
1116 | } | ||
1117 | } | ||
1118 | } | ||
1119 | dev_dbg(rd->mcasp->dev, | ||
1120 | "%d possible channel counts (%d-%d) for %d Hz and %d sbits\n", | ||
1121 | count, ci->min, ci->max, rate, sbits); | ||
1122 | |||
1123 | return snd_interval_list(hw_param_interval(params, rule->var), | ||
1124 | count, list, 0); | ||
1125 | } | ||
1126 | |||
1127 | static int davinci_mcasp_startup(struct snd_pcm_substream *substream, | 1090 | static int davinci_mcasp_startup(struct snd_pcm_substream *substream, |
1128 | struct snd_soc_dai *cpu_dai) | 1091 | struct snd_soc_dai *cpu_dai) |
1129 | { | 1092 | { |
@@ -1167,6 +1130,11 @@ static int davinci_mcasp_startup(struct snd_pcm_substream *substream, | |||
1167 | SNDRV_PCM_HW_PARAM_CHANNELS, | 1130 | SNDRV_PCM_HW_PARAM_CHANNELS, |
1168 | 2, max_channels); | 1131 | 2, max_channels); |
1169 | 1132 | ||
1133 | if (mcasp->chconstr[substream->stream].count) | ||
1134 | snd_pcm_hw_constraint_list(substream->runtime, | ||
1135 | 0, SNDRV_PCM_HW_PARAM_CHANNELS, | ||
1136 | &mcasp->chconstr[substream->stream]); | ||
1137 | |||
1170 | /* | 1138 | /* |
1171 | * If we rely on implicit BCLK divider setting we should | 1139 | * If we rely on implicit BCLK divider setting we should |
1172 | * set constraints based on what we can provide. | 1140 | * set constraints based on what we can provide. |
@@ -1180,24 +1148,14 @@ static int davinci_mcasp_startup(struct snd_pcm_substream *substream, | |||
1180 | SNDRV_PCM_HW_PARAM_RATE, | 1148 | SNDRV_PCM_HW_PARAM_RATE, |
1181 | davinci_mcasp_hw_rule_rate, | 1149 | davinci_mcasp_hw_rule_rate, |
1182 | ruledata, | 1150 | ruledata, |
1183 | SNDRV_PCM_HW_PARAM_FORMAT, | 1151 | SNDRV_PCM_HW_PARAM_FORMAT, -1); |
1184 | SNDRV_PCM_HW_PARAM_CHANNELS, -1); | ||
1185 | if (ret) | 1152 | if (ret) |
1186 | return ret; | 1153 | return ret; |
1187 | ret = snd_pcm_hw_rule_add(substream->runtime, 0, | 1154 | ret = snd_pcm_hw_rule_add(substream->runtime, 0, |
1188 | SNDRV_PCM_HW_PARAM_FORMAT, | 1155 | SNDRV_PCM_HW_PARAM_FORMAT, |
1189 | davinci_mcasp_hw_rule_format, | 1156 | davinci_mcasp_hw_rule_format, |
1190 | ruledata, | 1157 | ruledata, |
1191 | SNDRV_PCM_HW_PARAM_RATE, | 1158 | SNDRV_PCM_HW_PARAM_RATE, -1); |
1192 | SNDRV_PCM_HW_PARAM_CHANNELS, -1); | ||
1193 | if (ret) | ||
1194 | return ret; | ||
1195 | ret = snd_pcm_hw_rule_add(substream->runtime, 0, | ||
1196 | SNDRV_PCM_HW_PARAM_CHANNELS, | ||
1197 | davinci_mcasp_hw_rule_channels, | ||
1198 | ruledata, | ||
1199 | SNDRV_PCM_HW_PARAM_RATE, | ||
1200 | SNDRV_PCM_HW_PARAM_FORMAT, -1); | ||
1201 | if (ret) | 1159 | if (ret) |
1202 | return ret; | 1160 | return ret; |
1203 | } | 1161 | } |
@@ -1247,7 +1205,7 @@ static int davinci_mcasp_suspend(struct snd_soc_dai *dai) | |||
1247 | u32 reg; | 1205 | u32 reg; |
1248 | int i; | 1206 | int i; |
1249 | 1207 | ||
1250 | context->pm_state = pm_runtime_enabled(mcasp->dev); | 1208 | context->pm_state = pm_runtime_active(mcasp->dev); |
1251 | if (!context->pm_state) | 1209 | if (!context->pm_state) |
1252 | pm_runtime_get_sync(mcasp->dev); | 1210 | pm_runtime_get_sync(mcasp->dev); |
1253 | 1211 | ||
@@ -1556,6 +1514,102 @@ nodata: | |||
1556 | return pdata; | 1514 | return pdata; |
1557 | } | 1515 | } |
1558 | 1516 | ||
1517 | /* All serializers must have equal number of channels */ | ||
1518 | static int davinci_mcasp_ch_constraint(struct davinci_mcasp *mcasp, | ||
1519 | struct snd_pcm_hw_constraint_list *cl, | ||
1520 | int serializers) | ||
1521 | { | ||
1522 | unsigned int *list; | ||
1523 | int i, count = 0; | ||
1524 | |||
1525 | if (serializers <= 1) | ||
1526 | return 0; | ||
1527 | |||
1528 | list = devm_kzalloc(mcasp->dev, sizeof(unsigned int) * | ||
1529 | (mcasp->tdm_slots + serializers - 2), | ||
1530 | GFP_KERNEL); | ||
1531 | if (!list) | ||
1532 | return -ENOMEM; | ||
1533 | |||
1534 | for (i = 2; i <= mcasp->tdm_slots; i++) | ||
1535 | list[count++] = i; | ||
1536 | |||
1537 | for (i = 2; i <= serializers; i++) | ||
1538 | list[count++] = i*mcasp->tdm_slots; | ||
1539 | |||
1540 | cl->count = count; | ||
1541 | cl->list = list; | ||
1542 | |||
1543 | return 0; | ||
1544 | } | ||
1545 | |||
1546 | |||
1547 | static int davinci_mcasp_init_ch_constraints(struct davinci_mcasp *mcasp) | ||
1548 | { | ||
1549 | int rx_serializers = 0, tx_serializers = 0, ret, i; | ||
1550 | |||
1551 | for (i = 0; i < mcasp->num_serializer; i++) | ||
1552 | if (mcasp->serial_dir[i] == TX_MODE) | ||
1553 | tx_serializers++; | ||
1554 | else if (mcasp->serial_dir[i] == RX_MODE) | ||
1555 | rx_serializers++; | ||
1556 | |||
1557 | ret = davinci_mcasp_ch_constraint(mcasp, &mcasp->chconstr[ | ||
1558 | SNDRV_PCM_STREAM_PLAYBACK], | ||
1559 | tx_serializers); | ||
1560 | if (ret) | ||
1561 | return ret; | ||
1562 | |||
1563 | ret = davinci_mcasp_ch_constraint(mcasp, &mcasp->chconstr[ | ||
1564 | SNDRV_PCM_STREAM_CAPTURE], | ||
1565 | rx_serializers); | ||
1566 | |||
1567 | return ret; | ||
1568 | } | ||
1569 | |||
1570 | enum { | ||
1571 | PCM_EDMA, | ||
1572 | PCM_SDMA, | ||
1573 | }; | ||
1574 | static const char *sdma_prefix = "ti,omap"; | ||
1575 | |||
1576 | static int davinci_mcasp_get_dma_type(struct davinci_mcasp *mcasp) | ||
1577 | { | ||
1578 | struct dma_chan *chan; | ||
1579 | const char *tmp; | ||
1580 | int ret = PCM_EDMA; | ||
1581 | |||
1582 | if (!mcasp->dev->of_node) | ||
1583 | return PCM_EDMA; | ||
1584 | |||
1585 | tmp = mcasp->dma_data[SNDRV_PCM_STREAM_PLAYBACK].filter_data; | ||
1586 | chan = dma_request_slave_channel_reason(mcasp->dev, tmp); | ||
1587 | if (IS_ERR(chan)) { | ||
1588 | if (PTR_ERR(chan) != -EPROBE_DEFER) | ||
1589 | dev_err(mcasp->dev, | ||
1590 | "Can't verify DMA configuration (%ld)\n", | ||
1591 | PTR_ERR(chan)); | ||
1592 | return PTR_ERR(chan); | ||
1593 | } | ||
1594 | BUG_ON(!chan->device || !chan->device->dev); | ||
1595 | |||
1596 | if (chan->device->dev->of_node) | ||
1597 | ret = of_property_read_string(chan->device->dev->of_node, | ||
1598 | "compatible", &tmp); | ||
1599 | else | ||
1600 | dev_dbg(mcasp->dev, "DMA controller has no of-node\n"); | ||
1601 | |||
1602 | dma_release_channel(chan); | ||
1603 | if (ret) | ||
1604 | return ret; | ||
1605 | |||
1606 | dev_dbg(mcasp->dev, "DMA controller compatible = \"%s\"\n", tmp); | ||
1607 | if (!strncmp(tmp, sdma_prefix, strlen(sdma_prefix))) | ||
1608 | return PCM_SDMA; | ||
1609 | |||
1610 | return PCM_EDMA; | ||
1611 | } | ||
1612 | |||
1559 | static int davinci_mcasp_probe(struct platform_device *pdev) | 1613 | static int davinci_mcasp_probe(struct platform_device *pdev) |
1560 | { | 1614 | { |
1561 | struct snd_dmaengine_dai_dma_data *dma_data; | 1615 | struct snd_dmaengine_dai_dma_data *dma_data; |
@@ -1739,6 +1793,10 @@ static int davinci_mcasp_probe(struct platform_device *pdev) | |||
1739 | mcasp->fifo_base = DAVINCI_MCASP_V3_AFIFO_BASE; | 1793 | mcasp->fifo_base = DAVINCI_MCASP_V3_AFIFO_BASE; |
1740 | } | 1794 | } |
1741 | 1795 | ||
1796 | ret = davinci_mcasp_init_ch_constraints(mcasp); | ||
1797 | if (ret) | ||
1798 | goto err; | ||
1799 | |||
1742 | dev_set_drvdata(&pdev->dev, mcasp); | 1800 | dev_set_drvdata(&pdev->dev, mcasp); |
1743 | 1801 | ||
1744 | mcasp_reparent_fck(pdev); | 1802 | mcasp_reparent_fck(pdev); |
@@ -1750,27 +1808,34 @@ static int davinci_mcasp_probe(struct platform_device *pdev) | |||
1750 | if (ret != 0) | 1808 | if (ret != 0) |
1751 | goto err; | 1809 | goto err; |
1752 | 1810 | ||
1753 | switch (mcasp->version) { | 1811 | ret = davinci_mcasp_get_dma_type(mcasp); |
1812 | switch (ret) { | ||
1813 | case PCM_EDMA: | ||
1754 | #if IS_BUILTIN(CONFIG_SND_EDMA_SOC) || \ | 1814 | #if IS_BUILTIN(CONFIG_SND_EDMA_SOC) || \ |
1755 | (IS_MODULE(CONFIG_SND_DAVINCI_SOC_MCASP) && \ | 1815 | (IS_MODULE(CONFIG_SND_DAVINCI_SOC_MCASP) && \ |
1756 | IS_MODULE(CONFIG_SND_EDMA_SOC)) | 1816 | IS_MODULE(CONFIG_SND_EDMA_SOC)) |
1757 | case MCASP_VERSION_1: | ||
1758 | case MCASP_VERSION_2: | ||
1759 | case MCASP_VERSION_3: | ||
1760 | ret = edma_pcm_platform_register(&pdev->dev); | 1817 | ret = edma_pcm_platform_register(&pdev->dev); |
1761 | break; | 1818 | #else |
1819 | dev_err(&pdev->dev, "Missing SND_EDMA_SOC\n"); | ||
1820 | ret = -EINVAL; | ||
1821 | goto err; | ||
1762 | #endif | 1822 | #endif |
1823 | break; | ||
1824 | case PCM_SDMA: | ||
1763 | #if IS_BUILTIN(CONFIG_SND_OMAP_SOC) || \ | 1825 | #if IS_BUILTIN(CONFIG_SND_OMAP_SOC) || \ |
1764 | (IS_MODULE(CONFIG_SND_DAVINCI_SOC_MCASP) && \ | 1826 | (IS_MODULE(CONFIG_SND_DAVINCI_SOC_MCASP) && \ |
1765 | IS_MODULE(CONFIG_SND_OMAP_SOC)) | 1827 | IS_MODULE(CONFIG_SND_OMAP_SOC)) |
1766 | case MCASP_VERSION_4: | ||
1767 | ret = omap_pcm_platform_register(&pdev->dev); | 1828 | ret = omap_pcm_platform_register(&pdev->dev); |
1768 | break; | 1829 | #else |
1830 | dev_err(&pdev->dev, "Missing SND_SDMA_SOC\n"); | ||
1831 | ret = -EINVAL; | ||
1832 | goto err; | ||
1769 | #endif | 1833 | #endif |
1834 | break; | ||
1770 | default: | 1835 | default: |
1771 | dev_err(&pdev->dev, "Invalid McASP version: %d\n", | 1836 | dev_err(&pdev->dev, "No DMA controller found (%d)\n", ret); |
1772 | mcasp->version); | 1837 | case -EPROBE_DEFER: |
1773 | ret = -EINVAL; | 1838 | goto err; |
1774 | break; | 1839 | break; |
1775 | } | 1840 | } |
1776 | 1841 | ||
diff --git a/sound/soc/davinci/davinci-mcasp.h b/sound/soc/davinci/davinci-mcasp.h index 79dc511180bf..a3be108a8c17 100644 --- a/sound/soc/davinci/davinci-mcasp.h +++ b/sound/soc/davinci/davinci-mcasp.h | |||
@@ -215,7 +215,10 @@ | |||
215 | * DAVINCI_MCASP_XRSRCTL_BASE_REG - Serializer Control Register Bits | 215 | * DAVINCI_MCASP_XRSRCTL_BASE_REG - Serializer Control Register Bits |
216 | */ | 216 | */ |
217 | #define MODE(val) (val) | 217 | #define MODE(val) (val) |
218 | #define DISMOD (val)(val<<2) | 218 | #define DISMOD_3STATE (0x0) |
219 | #define DISMOD_LOW (0x2 << 2) | ||
220 | #define DISMOD_HIGH (0x3 << 2) | ||
221 | #define DISMOD_MASK DISMOD_HIGH | ||
219 | #define TXSTATE BIT(4) | 222 | #define TXSTATE BIT(4) |
220 | #define RXSTATE BIT(5) | 223 | #define RXSTATE BIT(5) |
221 | #define SRMOD_MASK 3 | 224 | #define SRMOD_MASK 3 |
diff --git a/sound/soc/fsl/fsl_dma.c b/sound/soc/fsl/fsl_dma.c index 93d7e56c6066..ccadefceeff2 100644 --- a/sound/soc/fsl/fsl_dma.c +++ b/sound/soc/fsl/fsl_dma.c | |||
@@ -445,7 +445,7 @@ static int fsl_dma_open(struct snd_pcm_substream *substream) | |||
445 | return ret; | 445 | return ret; |
446 | } | 446 | } |
447 | 447 | ||
448 | dma->assigned = 1; | 448 | dma->assigned = true; |
449 | 449 | ||
450 | snd_pcm_set_runtime_buffer(substream, &substream->dma_buffer); | 450 | snd_pcm_set_runtime_buffer(substream, &substream->dma_buffer); |
451 | snd_soc_set_runtime_hwparams(substream, &fsl_dma_hardware); | 451 | snd_soc_set_runtime_hwparams(substream, &fsl_dma_hardware); |
@@ -814,7 +814,7 @@ static int fsl_dma_close(struct snd_pcm_substream *substream) | |||
814 | substream->runtime->private_data = NULL; | 814 | substream->runtime->private_data = NULL; |
815 | } | 815 | } |
816 | 816 | ||
817 | dma->assigned = 0; | 817 | dma->assigned = false; |
818 | 818 | ||
819 | return 0; | 819 | return 0; |
820 | } | 820 | } |
diff --git a/sound/soc/fsl/fsl_sai.c b/sound/soc/fsl/fsl_sai.c index ec79c3d5e65e..5c73bea7b11e 100644 --- a/sound/soc/fsl/fsl_sai.c +++ b/sound/soc/fsl/fsl_sai.c | |||
@@ -1,7 +1,7 @@ | |||
1 | /* | 1 | /* |
2 | * Freescale ALSA SoC Digital Audio Interface (SAI) driver. | 2 | * Freescale ALSA SoC Digital Audio Interface (SAI) driver. |
3 | * | 3 | * |
4 | * Copyright 2012-2013 Freescale Semiconductor, Inc. | 4 | * Copyright 2012-2015 Freescale Semiconductor, Inc. |
5 | * | 5 | * |
6 | * This program is free software, you can redistribute it and/or modify it | 6 | * This program is free software, you can redistribute it and/or modify it |
7 | * under the terms of the GNU General Public License as published by the | 7 | * under the terms of the GNU General Public License as published by the |
@@ -27,6 +27,17 @@ | |||
27 | #define FSL_SAI_FLAGS (FSL_SAI_CSR_SEIE |\ | 27 | #define FSL_SAI_FLAGS (FSL_SAI_CSR_SEIE |\ |
28 | FSL_SAI_CSR_FEIE) | 28 | FSL_SAI_CSR_FEIE) |
29 | 29 | ||
30 | static u32 fsl_sai_rates[] = { | ||
31 | 8000, 11025, 12000, 16000, 22050, | ||
32 | 24000, 32000, 44100, 48000, 64000, | ||
33 | 88200, 96000, 176400, 192000 | ||
34 | }; | ||
35 | |||
36 | static struct snd_pcm_hw_constraint_list fsl_sai_rate_constraints = { | ||
37 | .count = ARRAY_SIZE(fsl_sai_rates), | ||
38 | .list = fsl_sai_rates, | ||
39 | }; | ||
40 | |||
30 | static irqreturn_t fsl_sai_isr(int irq, void *devid) | 41 | static irqreturn_t fsl_sai_isr(int irq, void *devid) |
31 | { | 42 | { |
32 | struct fsl_sai *sai = (struct fsl_sai *)devid; | 43 | struct fsl_sai *sai = (struct fsl_sai *)devid; |
@@ -251,12 +262,14 @@ static int fsl_sai_set_dai_fmt_tr(struct snd_soc_dai *cpu_dai, | |||
251 | val_cr4 |= FSL_SAI_CR4_FSD_MSTR; | 262 | val_cr4 |= FSL_SAI_CR4_FSD_MSTR; |
252 | break; | 263 | break; |
253 | case SND_SOC_DAIFMT_CBM_CFM: | 264 | case SND_SOC_DAIFMT_CBM_CFM: |
265 | sai->is_slave_mode = true; | ||
254 | break; | 266 | break; |
255 | case SND_SOC_DAIFMT_CBS_CFM: | 267 | case SND_SOC_DAIFMT_CBS_CFM: |
256 | val_cr2 |= FSL_SAI_CR2_BCD_MSTR; | 268 | val_cr2 |= FSL_SAI_CR2_BCD_MSTR; |
257 | break; | 269 | break; |
258 | case SND_SOC_DAIFMT_CBM_CFS: | 270 | case SND_SOC_DAIFMT_CBM_CFS: |
259 | val_cr4 |= FSL_SAI_CR4_FSD_MSTR; | 271 | val_cr4 |= FSL_SAI_CR4_FSD_MSTR; |
272 | sai->is_slave_mode = true; | ||
260 | break; | 273 | break; |
261 | default: | 274 | default: |
262 | return -EINVAL; | 275 | return -EINVAL; |
@@ -288,6 +301,79 @@ static int fsl_sai_set_dai_fmt(struct snd_soc_dai *cpu_dai, unsigned int fmt) | |||
288 | return ret; | 301 | return ret; |
289 | } | 302 | } |
290 | 303 | ||
304 | static int fsl_sai_set_bclk(struct snd_soc_dai *dai, bool tx, u32 freq) | ||
305 | { | ||
306 | struct fsl_sai *sai = snd_soc_dai_get_drvdata(dai); | ||
307 | unsigned long clk_rate; | ||
308 | u32 savediv = 0, ratio, savesub = freq; | ||
309 | u32 id; | ||
310 | int ret = 0; | ||
311 | |||
312 | /* Don't apply to slave mode */ | ||
313 | if (sai->is_slave_mode) | ||
314 | return 0; | ||
315 | |||
316 | for (id = 0; id < FSL_SAI_MCLK_MAX; id++) { | ||
317 | clk_rate = clk_get_rate(sai->mclk_clk[id]); | ||
318 | if (!clk_rate) | ||
319 | continue; | ||
320 | |||
321 | ratio = clk_rate / freq; | ||
322 | |||
323 | ret = clk_rate - ratio * freq; | ||
324 | |||
325 | /* | ||
326 | * Drop the source that can not be | ||
327 | * divided into the required rate. | ||
328 | */ | ||
329 | if (ret != 0 && clk_rate / ret < 1000) | ||
330 | continue; | ||
331 | |||
332 | dev_dbg(dai->dev, | ||
333 | "ratio %d for freq %dHz based on clock %ldHz\n", | ||
334 | ratio, freq, clk_rate); | ||
335 | |||
336 | if (ratio % 2 == 0 && ratio >= 2 && ratio <= 512) | ||
337 | ratio /= 2; | ||
338 | else | ||
339 | continue; | ||
340 | |||
341 | if (ret < savesub) { | ||
342 | savediv = ratio; | ||
343 | sai->mclk_id[tx] = id; | ||
344 | savesub = ret; | ||
345 | } | ||
346 | |||
347 | if (ret == 0) | ||
348 | break; | ||
349 | } | ||
350 | |||
351 | if (savediv == 0) { | ||
352 | dev_err(dai->dev, "failed to derive required %cx rate: %d\n", | ||
353 | tx ? 'T' : 'R', freq); | ||
354 | return -EINVAL; | ||
355 | } | ||
356 | |||
357 | if ((tx && sai->synchronous[TX]) || (!tx && !sai->synchronous[RX])) { | ||
358 | regmap_update_bits(sai->regmap, FSL_SAI_RCR2, | ||
359 | FSL_SAI_CR2_MSEL_MASK, | ||
360 | FSL_SAI_CR2_MSEL(sai->mclk_id[tx])); | ||
361 | regmap_update_bits(sai->regmap, FSL_SAI_RCR2, | ||
362 | FSL_SAI_CR2_DIV_MASK, savediv - 1); | ||
363 | } else { | ||
364 | regmap_update_bits(sai->regmap, FSL_SAI_TCR2, | ||
365 | FSL_SAI_CR2_MSEL_MASK, | ||
366 | FSL_SAI_CR2_MSEL(sai->mclk_id[tx])); | ||
367 | regmap_update_bits(sai->regmap, FSL_SAI_TCR2, | ||
368 | FSL_SAI_CR2_DIV_MASK, savediv - 1); | ||
369 | } | ||
370 | |||
371 | dev_dbg(dai->dev, "best fit: clock id=%d, div=%d, deviation =%d\n", | ||
372 | sai->mclk_id[tx], savediv, savesub); | ||
373 | |||
374 | return 0; | ||
375 | } | ||
376 | |||
291 | static int fsl_sai_hw_params(struct snd_pcm_substream *substream, | 377 | static int fsl_sai_hw_params(struct snd_pcm_substream *substream, |
292 | struct snd_pcm_hw_params *params, | 378 | struct snd_pcm_hw_params *params, |
293 | struct snd_soc_dai *cpu_dai) | 379 | struct snd_soc_dai *cpu_dai) |
@@ -297,6 +383,24 @@ static int fsl_sai_hw_params(struct snd_pcm_substream *substream, | |||
297 | unsigned int channels = params_channels(params); | 383 | unsigned int channels = params_channels(params); |
298 | u32 word_width = snd_pcm_format_width(params_format(params)); | 384 | u32 word_width = snd_pcm_format_width(params_format(params)); |
299 | u32 val_cr4 = 0, val_cr5 = 0; | 385 | u32 val_cr4 = 0, val_cr5 = 0; |
386 | int ret; | ||
387 | |||
388 | if (!sai->is_slave_mode) { | ||
389 | ret = fsl_sai_set_bclk(cpu_dai, tx, | ||
390 | 2 * word_width * params_rate(params)); | ||
391 | if (ret) | ||
392 | return ret; | ||
393 | |||
394 | /* Do not enable the clock if it is already enabled */ | ||
395 | if (!(sai->mclk_streams & BIT(substream->stream))) { | ||
396 | ret = clk_prepare_enable(sai->mclk_clk[sai->mclk_id[tx]]); | ||
397 | if (ret) | ||
398 | return ret; | ||
399 | |||
400 | sai->mclk_streams |= BIT(substream->stream); | ||
401 | } | ||
402 | |||
403 | } | ||
300 | 404 | ||
301 | if (!sai->is_dsp_mode) | 405 | if (!sai->is_dsp_mode) |
302 | val_cr4 |= FSL_SAI_CR4_SYWD(word_width); | 406 | val_cr4 |= FSL_SAI_CR4_SYWD(word_width); |
@@ -322,6 +426,22 @@ static int fsl_sai_hw_params(struct snd_pcm_substream *substream, | |||
322 | return 0; | 426 | return 0; |
323 | } | 427 | } |
324 | 428 | ||
429 | static int fsl_sai_hw_free(struct snd_pcm_substream *substream, | ||
430 | struct snd_soc_dai *cpu_dai) | ||
431 | { | ||
432 | struct fsl_sai *sai = snd_soc_dai_get_drvdata(cpu_dai); | ||
433 | bool tx = substream->stream == SNDRV_PCM_STREAM_PLAYBACK; | ||
434 | |||
435 | if (!sai->is_slave_mode && | ||
436 | sai->mclk_streams & BIT(substream->stream)) { | ||
437 | clk_disable_unprepare(sai->mclk_clk[sai->mclk_id[tx]]); | ||
438 | sai->mclk_streams &= ~BIT(substream->stream); | ||
439 | } | ||
440 | |||
441 | return 0; | ||
442 | } | ||
443 | |||
444 | |||
325 | static int fsl_sai_trigger(struct snd_pcm_substream *substream, int cmd, | 445 | static int fsl_sai_trigger(struct snd_pcm_substream *substream, int cmd, |
326 | struct snd_soc_dai *cpu_dai) | 446 | struct snd_soc_dai *cpu_dai) |
327 | { | 447 | { |
@@ -410,7 +530,10 @@ static int fsl_sai_startup(struct snd_pcm_substream *substream, | |||
410 | regmap_update_bits(sai->regmap, FSL_SAI_xCR3(tx), FSL_SAI_CR3_TRCE, | 530 | regmap_update_bits(sai->regmap, FSL_SAI_xCR3(tx), FSL_SAI_CR3_TRCE, |
411 | FSL_SAI_CR3_TRCE); | 531 | FSL_SAI_CR3_TRCE); |
412 | 532 | ||
413 | return 0; | 533 | ret = snd_pcm_hw_constraint_list(substream->runtime, 0, |
534 | SNDRV_PCM_HW_PARAM_RATE, &fsl_sai_rate_constraints); | ||
535 | |||
536 | return ret; | ||
414 | } | 537 | } |
415 | 538 | ||
416 | static void fsl_sai_shutdown(struct snd_pcm_substream *substream, | 539 | static void fsl_sai_shutdown(struct snd_pcm_substream *substream, |
@@ -428,6 +551,7 @@ static const struct snd_soc_dai_ops fsl_sai_pcm_dai_ops = { | |||
428 | .set_sysclk = fsl_sai_set_dai_sysclk, | 551 | .set_sysclk = fsl_sai_set_dai_sysclk, |
429 | .set_fmt = fsl_sai_set_dai_fmt, | 552 | .set_fmt = fsl_sai_set_dai_fmt, |
430 | .hw_params = fsl_sai_hw_params, | 553 | .hw_params = fsl_sai_hw_params, |
554 | .hw_free = fsl_sai_hw_free, | ||
431 | .trigger = fsl_sai_trigger, | 555 | .trigger = fsl_sai_trigger, |
432 | .startup = fsl_sai_startup, | 556 | .startup = fsl_sai_startup, |
433 | .shutdown = fsl_sai_shutdown, | 557 | .shutdown = fsl_sai_shutdown, |
@@ -463,14 +587,18 @@ static struct snd_soc_dai_driver fsl_sai_dai = { | |||
463 | .stream_name = "CPU-Playback", | 587 | .stream_name = "CPU-Playback", |
464 | .channels_min = 1, | 588 | .channels_min = 1, |
465 | .channels_max = 2, | 589 | .channels_max = 2, |
466 | .rates = SNDRV_PCM_RATE_8000_96000, | 590 | .rate_min = 8000, |
591 | .rate_max = 192000, | ||
592 | .rates = SNDRV_PCM_RATE_KNOT, | ||
467 | .formats = FSL_SAI_FORMATS, | 593 | .formats = FSL_SAI_FORMATS, |
468 | }, | 594 | }, |
469 | .capture = { | 595 | .capture = { |
470 | .stream_name = "CPU-Capture", | 596 | .stream_name = "CPU-Capture", |
471 | .channels_min = 1, | 597 | .channels_min = 1, |
472 | .channels_max = 2, | 598 | .channels_max = 2, |
473 | .rates = SNDRV_PCM_RATE_8000_96000, | 599 | .rate_min = 8000, |
600 | .rate_max = 192000, | ||
601 | .rates = SNDRV_PCM_RATE_KNOT, | ||
474 | .formats = FSL_SAI_FORMATS, | 602 | .formats = FSL_SAI_FORMATS, |
475 | }, | 603 | }, |
476 | .ops = &fsl_sai_pcm_dai_ops, | 604 | .ops = &fsl_sai_pcm_dai_ops, |
@@ -600,8 +728,9 @@ static int fsl_sai_probe(struct platform_device *pdev) | |||
600 | sai->bus_clk = NULL; | 728 | sai->bus_clk = NULL; |
601 | } | 729 | } |
602 | 730 | ||
603 | for (i = 0; i < FSL_SAI_MCLK_MAX; i++) { | 731 | sai->mclk_clk[0] = sai->bus_clk; |
604 | sprintf(tmp, "mclk%d", i + 1); | 732 | for (i = 1; i < FSL_SAI_MCLK_MAX; i++) { |
733 | sprintf(tmp, "mclk%d", i); | ||
605 | sai->mclk_clk[i] = devm_clk_get(&pdev->dev, tmp); | 734 | sai->mclk_clk[i] = devm_clk_get(&pdev->dev, tmp); |
606 | if (IS_ERR(sai->mclk_clk[i])) { | 735 | if (IS_ERR(sai->mclk_clk[i])) { |
607 | dev_err(&pdev->dev, "failed to get mclk%d clock: %ld\n", | 736 | dev_err(&pdev->dev, "failed to get mclk%d clock: %ld\n", |
@@ -664,8 +793,7 @@ static int fsl_sai_probe(struct platform_device *pdev) | |||
664 | if (sai->sai_on_imx) | 793 | if (sai->sai_on_imx) |
665 | return imx_pcm_dma_init(pdev); | 794 | return imx_pcm_dma_init(pdev); |
666 | else | 795 | else |
667 | return devm_snd_dmaengine_pcm_register(&pdev->dev, NULL, | 796 | return devm_snd_dmaengine_pcm_register(&pdev->dev, NULL, 0); |
668 | SND_DMAENGINE_PCM_FLAG_NO_RESIDUE); | ||
669 | } | 797 | } |
670 | 798 | ||
671 | static const struct of_device_id fsl_sai_ids[] = { | 799 | static const struct of_device_id fsl_sai_ids[] = { |
diff --git a/sound/soc/fsl/fsl_sai.h b/sound/soc/fsl/fsl_sai.h index 34667209b607..066280953c85 100644 --- a/sound/soc/fsl/fsl_sai.h +++ b/sound/soc/fsl/fsl_sai.h | |||
@@ -72,13 +72,15 @@ | |||
72 | 72 | ||
73 | /* SAI Transmit and Recieve Configuration 2 Register */ | 73 | /* SAI Transmit and Recieve Configuration 2 Register */ |
74 | #define FSL_SAI_CR2_SYNC BIT(30) | 74 | #define FSL_SAI_CR2_SYNC BIT(30) |
75 | #define FSL_SAI_CR2_MSEL_MASK (0xff << 26) | 75 | #define FSL_SAI_CR2_MSEL_MASK (0x3 << 26) |
76 | #define FSL_SAI_CR2_MSEL_BUS 0 | 76 | #define FSL_SAI_CR2_MSEL_BUS 0 |
77 | #define FSL_SAI_CR2_MSEL_MCLK1 BIT(26) | 77 | #define FSL_SAI_CR2_MSEL_MCLK1 BIT(26) |
78 | #define FSL_SAI_CR2_MSEL_MCLK2 BIT(27) | 78 | #define FSL_SAI_CR2_MSEL_MCLK2 BIT(27) |
79 | #define FSL_SAI_CR2_MSEL_MCLK3 (BIT(26) | BIT(27)) | 79 | #define FSL_SAI_CR2_MSEL_MCLK3 (BIT(26) | BIT(27)) |
80 | #define FSL_SAI_CR2_MSEL(ID) ((ID) << 26) | ||
80 | #define FSL_SAI_CR2_BCP BIT(25) | 81 | #define FSL_SAI_CR2_BCP BIT(25) |
81 | #define FSL_SAI_CR2_BCD_MSTR BIT(24) | 82 | #define FSL_SAI_CR2_BCD_MSTR BIT(24) |
83 | #define FSL_SAI_CR2_DIV_MASK 0xff | ||
82 | 84 | ||
83 | /* SAI Transmit and Recieve Configuration 3 Register */ | 85 | /* SAI Transmit and Recieve Configuration 3 Register */ |
84 | #define FSL_SAI_CR3_TRCE BIT(16) | 86 | #define FSL_SAI_CR3_TRCE BIT(16) |
@@ -120,7 +122,7 @@ | |||
120 | #define FSL_SAI_CLK_MAST2 2 | 122 | #define FSL_SAI_CLK_MAST2 2 |
121 | #define FSL_SAI_CLK_MAST3 3 | 123 | #define FSL_SAI_CLK_MAST3 3 |
122 | 124 | ||
123 | #define FSL_SAI_MCLK_MAX 3 | 125 | #define FSL_SAI_MCLK_MAX 4 |
124 | 126 | ||
125 | /* SAI data transfer numbers per DMA request */ | 127 | /* SAI data transfer numbers per DMA request */ |
126 | #define FSL_SAI_MAXBURST_TX 6 | 128 | #define FSL_SAI_MAXBURST_TX 6 |
@@ -132,11 +134,14 @@ struct fsl_sai { | |||
132 | struct clk *bus_clk; | 134 | struct clk *bus_clk; |
133 | struct clk *mclk_clk[FSL_SAI_MCLK_MAX]; | 135 | struct clk *mclk_clk[FSL_SAI_MCLK_MAX]; |
134 | 136 | ||
137 | bool is_slave_mode; | ||
135 | bool is_lsb_first; | 138 | bool is_lsb_first; |
136 | bool is_dsp_mode; | 139 | bool is_dsp_mode; |
137 | bool sai_on_imx; | 140 | bool sai_on_imx; |
138 | bool synchronous[2]; | 141 | bool synchronous[2]; |
139 | 142 | ||
143 | unsigned int mclk_id[2]; | ||
144 | unsigned int mclk_streams; | ||
140 | struct snd_dmaengine_dai_dma_data dma_params_rx; | 145 | struct snd_dmaengine_dai_dma_data dma_params_rx; |
141 | struct snd_dmaengine_dai_dma_data dma_params_tx; | 146 | struct snd_dmaengine_dai_dma_data dma_params_tx; |
142 | }; | 147 | }; |
diff --git a/sound/soc/fsl/fsl_spdif.c b/sound/soc/fsl/fsl_spdif.c index 91eb3aef7f02..8e932219cb3a 100644 --- a/sound/soc/fsl/fsl_spdif.c +++ b/sound/soc/fsl/fsl_spdif.c | |||
@@ -417,11 +417,9 @@ static int spdif_set_sample_rate(struct snd_pcm_substream *substream, | |||
417 | if (clk != STC_TXCLK_SPDIF_ROOT) | 417 | if (clk != STC_TXCLK_SPDIF_ROOT) |
418 | goto clk_set_bypass; | 418 | goto clk_set_bypass; |
419 | 419 | ||
420 | /* | 420 | /* The S/PDIF block needs a clock of 64 * fs * txclk_df */ |
421 | * The S/PDIF block needs a clock of 64 * fs * txclk_df. | 421 | ret = clk_set_rate(spdif_priv->txclk[rate], |
422 | * So request 64 * fs * (txclk_df + 1) to get rounded. | 422 | 64 * sample_rate * txclk_df); |
423 | */ | ||
424 | ret = clk_set_rate(spdif_priv->txclk[rate], 64 * sample_rate * (txclk_df + 1)); | ||
425 | if (ret) { | 423 | if (ret) { |
426 | dev_err(&pdev->dev, "failed to set tx clock rate\n"); | 424 | dev_err(&pdev->dev, "failed to set tx clock rate\n"); |
427 | return ret; | 425 | return ret; |
@@ -1060,7 +1058,7 @@ static u32 fsl_spdif_txclk_caldiv(struct fsl_spdif_priv *spdif_priv, | |||
1060 | 1058 | ||
1061 | for (sysclk_df = sysclk_dfmin; sysclk_df <= sysclk_dfmax; sysclk_df++) { | 1059 | for (sysclk_df = sysclk_dfmin; sysclk_df <= sysclk_dfmax; sysclk_df++) { |
1062 | for (txclk_df = 1; txclk_df <= 128; txclk_df++) { | 1060 | for (txclk_df = 1; txclk_df <= 128; txclk_df++) { |
1063 | rate_ideal = rate[index] * (txclk_df + 1) * 64; | 1061 | rate_ideal = rate[index] * txclk_df * 64; |
1064 | if (round) | 1062 | if (round) |
1065 | rate_actual = clk_round_rate(clk, rate_ideal); | 1063 | rate_actual = clk_round_rate(clk, rate_ideal); |
1066 | else | 1064 | else |
diff --git a/sound/soc/fsl/fsl_ssi.c b/sound/soc/fsl/fsl_ssi.c index e8bb8eef1d16..c7647e066cfd 100644 --- a/sound/soc/fsl/fsl_ssi.c +++ b/sound/soc/fsl/fsl_ssi.c | |||
@@ -1292,13 +1292,6 @@ static int fsl_ssi_probe(struct platform_device *pdev) | |||
1292 | void __iomem *iomem; | 1292 | void __iomem *iomem; |
1293 | char name[64]; | 1293 | char name[64]; |
1294 | 1294 | ||
1295 | /* SSIs that are not connected on the board should have a | ||
1296 | * status = "disabled" | ||
1297 | * property in their device tree nodes. | ||
1298 | */ | ||
1299 | if (!of_device_is_available(np)) | ||
1300 | return -ENODEV; | ||
1301 | |||
1302 | of_id = of_match_device(fsl_ssi_ids, &pdev->dev); | 1295 | of_id = of_match_device(fsl_ssi_ids, &pdev->dev); |
1303 | if (!of_id || !of_id->data) | 1296 | if (!of_id || !of_id->data) |
1304 | return -EINVAL; | 1297 | return -EINVAL; |
@@ -1357,7 +1350,7 @@ static int fsl_ssi_probe(struct platform_device *pdev) | |||
1357 | } | 1350 | } |
1358 | 1351 | ||
1359 | ssi_private->irq = platform_get_irq(pdev, 0); | 1352 | ssi_private->irq = platform_get_irq(pdev, 0); |
1360 | if (!ssi_private->irq) { | 1353 | if (ssi_private->irq < 0) { |
1361 | dev_err(&pdev->dev, "no irq for node %s\n", pdev->name); | 1354 | dev_err(&pdev->dev, "no irq for node %s\n", pdev->name); |
1362 | return ssi_private->irq; | 1355 | return ssi_private->irq; |
1363 | } | 1356 | } |
diff --git a/sound/soc/fsl/imx-audmux.c b/sound/soc/fsl/imx-audmux.c index d9050d946ae7..fc57da341d61 100644 --- a/sound/soc/fsl/imx-audmux.c +++ b/sound/soc/fsl/imx-audmux.c | |||
@@ -184,7 +184,7 @@ static enum imx_audmux_type { | |||
184 | IMX31_AUDMUX, | 184 | IMX31_AUDMUX, |
185 | } audmux_type; | 185 | } audmux_type; |
186 | 186 | ||
187 | static struct platform_device_id imx_audmux_ids[] = { | 187 | static const struct platform_device_id imx_audmux_ids[] = { |
188 | { | 188 | { |
189 | .name = "imx21-audmux", | 189 | .name = "imx21-audmux", |
190 | .driver_data = IMX21_AUDMUX, | 190 | .driver_data = IMX21_AUDMUX, |
diff --git a/sound/soc/fsl/imx-mc13783.c b/sound/soc/fsl/imx-mc13783.c index 9e6493d4e7ff..bb0459018b45 100644 --- a/sound/soc/fsl/imx-mc13783.c +++ b/sound/soc/fsl/imx-mc13783.c | |||
@@ -45,11 +45,7 @@ static int imx_mc13783_hifi_hw_params(struct snd_pcm_substream *substream, | |||
45 | if (ret) | 45 | if (ret) |
46 | return ret; | 46 | return ret; |
47 | 47 | ||
48 | ret = snd_soc_dai_set_tdm_slot(cpu_dai, 0x3, 0x3, 2, 16); | 48 | return snd_soc_dai_set_tdm_slot(cpu_dai, 0x3, 0x3, 2, 16); |
49 | if (ret) | ||
50 | return ret; | ||
51 | |||
52 | return 0; | ||
53 | } | 49 | } |
54 | 50 | ||
55 | static struct snd_soc_ops imx_mc13783_hifi_ops = { | 51 | static struct snd_soc_ops imx_mc13783_hifi_ops = { |
diff --git a/sound/soc/fsl/imx-wm8962.c b/sound/soc/fsl/imx-wm8962.c index cd146d4fa805..b38b98cae855 100644 --- a/sound/soc/fsl/imx-wm8962.c +++ b/sound/soc/fsl/imx-wm8962.c | |||
@@ -190,7 +190,7 @@ static int imx_wm8962_probe(struct platform_device *pdev) | |||
190 | dev_err(&pdev->dev, "audmux internal port setup failed\n"); | 190 | dev_err(&pdev->dev, "audmux internal port setup failed\n"); |
191 | return ret; | 191 | return ret; |
192 | } | 192 | } |
193 | imx_audmux_v2_configure_port(ext_port, | 193 | ret = imx_audmux_v2_configure_port(ext_port, |
194 | IMX_AUDMUX_V2_PTCR_SYN, | 194 | IMX_AUDMUX_V2_PTCR_SYN, |
195 | IMX_AUDMUX_V2_PDCR_RXDSEL(int_port)); | 195 | IMX_AUDMUX_V2_PDCR_RXDSEL(int_port)); |
196 | if (ret) { | 196 | if (ret) { |
diff --git a/sound/soc/generic/simple-card.c b/sound/soc/generic/simple-card.c index 33feee9ca8c3..c87e58504a62 100644 --- a/sound/soc/generic/simple-card.c +++ b/sound/soc/generic/simple-card.c | |||
@@ -307,6 +307,7 @@ static int asoc_simple_card_dai_link_of(struct device_node *node, | |||
307 | struct snd_soc_dai_link *dai_link = simple_priv_to_link(priv, idx); | 307 | struct snd_soc_dai_link *dai_link = simple_priv_to_link(priv, idx); |
308 | struct simple_dai_props *dai_props = simple_priv_to_props(priv, idx); | 308 | struct simple_dai_props *dai_props = simple_priv_to_props(priv, idx); |
309 | struct device_node *cpu = NULL; | 309 | struct device_node *cpu = NULL; |
310 | struct device_node *plat = NULL; | ||
310 | struct device_node *codec = NULL; | 311 | struct device_node *codec = NULL; |
311 | char *name; | 312 | char *name; |
312 | char prop[128]; | 313 | char prop[128]; |
@@ -320,6 +321,9 @@ static int asoc_simple_card_dai_link_of(struct device_node *node, | |||
320 | snprintf(prop, sizeof(prop), "%scpu", prefix); | 321 | snprintf(prop, sizeof(prop), "%scpu", prefix); |
321 | cpu = of_get_child_by_name(node, prop); | 322 | cpu = of_get_child_by_name(node, prop); |
322 | 323 | ||
324 | snprintf(prop, sizeof(prop), "%splat", prefix); | ||
325 | plat = of_get_child_by_name(node, prop); | ||
326 | |||
323 | snprintf(prop, sizeof(prop), "%scodec", prefix); | 327 | snprintf(prop, sizeof(prop), "%scodec", prefix); |
324 | codec = of_get_child_by_name(node, prop); | 328 | codec = of_get_child_by_name(node, prop); |
325 | 329 | ||
@@ -352,8 +356,16 @@ static int asoc_simple_card_dai_link_of(struct device_node *node, | |||
352 | goto dai_link_of_err; | 356 | goto dai_link_of_err; |
353 | } | 357 | } |
354 | 358 | ||
355 | /* Simple Card assumes platform == cpu */ | 359 | if (plat) { |
356 | dai_link->platform_of_node = dai_link->cpu_of_node; | 360 | struct of_phandle_args args; |
361 | |||
362 | ret = of_parse_phandle_with_args(plat, "sound-dai", | ||
363 | "#sound-dai-cells", 0, &args); | ||
364 | dai_link->platform_of_node = args.np; | ||
365 | } else { | ||
366 | /* Assumes platform == cpu */ | ||
367 | dai_link->platform_of_node = dai_link->cpu_of_node; | ||
368 | } | ||
357 | 369 | ||
358 | /* DAI link name is created from CPU/CODEC dai name */ | 370 | /* DAI link name is created from CPU/CODEC dai name */ |
359 | name = devm_kzalloc(dev, | 371 | name = devm_kzalloc(dev, |
diff --git a/sound/soc/intel/Kconfig b/sound/soc/intel/Kconfig index ee03dbdda235..f3060a4ca040 100644 --- a/sound/soc/intel/Kconfig +++ b/sound/soc/intel/Kconfig | |||
@@ -79,7 +79,6 @@ config SND_SOC_INTEL_BROADWELL_MACH | |||
79 | depends on SND_SOC_INTEL_SST && X86_INTEL_LPSS && DW_DMAC && \ | 79 | depends on SND_SOC_INTEL_SST && X86_INTEL_LPSS && DW_DMAC && \ |
80 | I2C_DESIGNWARE_PLATFORM | 80 | I2C_DESIGNWARE_PLATFORM |
81 | select SND_SOC_INTEL_HASWELL | 81 | select SND_SOC_INTEL_HASWELL |
82 | select SND_COMPRESS_OFFLOAD | ||
83 | select SND_SOC_RT286 | 82 | select SND_SOC_RT286 |
84 | help | 83 | help |
85 | This adds support for the Wilcatpoint Audio DSP on Intel(R) Broadwell | 84 | This adds support for the Wilcatpoint Audio DSP on Intel(R) Broadwell |
@@ -112,12 +111,24 @@ config SND_SOC_INTEL_CHT_BSW_RT5672_MACH | |||
112 | If unsure select "N". | 111 | If unsure select "N". |
113 | 112 | ||
114 | config SND_SOC_INTEL_CHT_BSW_RT5645_MACH | 113 | config SND_SOC_INTEL_CHT_BSW_RT5645_MACH |
115 | tristate "ASoC Audio driver for Intel Cherrytrail & Braswell with RT5645 codec" | 114 | tristate "ASoC Audio driver for Intel Cherrytrail & Braswell with RT5645/5650 codec" |
116 | depends on X86_INTEL_LPSS | 115 | depends on X86_INTEL_LPSS && I2C |
117 | select SND_SOC_RT5645 | 116 | select SND_SOC_RT5645 |
118 | select SND_SST_MFLD_PLATFORM | 117 | select SND_SST_MFLD_PLATFORM |
119 | select SND_SST_IPC_ACPI | 118 | select SND_SST_IPC_ACPI |
120 | help | 119 | help |
121 | This adds support for ASoC machine driver for Intel(R) Cherrytrail & Braswell | 120 | This adds support for ASoC machine driver for Intel(R) Cherrytrail & Braswell |
122 | platforms with RT5645 audio codec. | 121 | platforms with RT5645/5650 audio codec. |
123 | If unsure select "N". | 122 | If unsure select "N". |
123 | |||
124 | config SND_SOC_INTEL_CHT_BSW_MAX98090_TI_MACH | ||
125 | tristate "ASoC Audio driver for Intel Cherrytrail & Braswell with MAX98090 & TI codec" | ||
126 | depends on X86_INTEL_LPSS && I2C | ||
127 | select SND_SOC_MAX98090 | ||
128 | select SND_SOC_TS3A227E | ||
129 | select SND_SST_MFLD_PLATFORM | ||
130 | select SND_SST_IPC_ACPI | ||
131 | help | ||
132 | This adds support for ASoC machine driver for Intel(R) Cherrytrail & Braswell | ||
133 | platforms with MAX98090 audio codec it also can support TI jack chip as aux device. | ||
134 | If unsure select "N". | ||
diff --git a/sound/soc/intel/Makefile b/sound/soc/intel/Makefile index cd9aee9871a3..3853ec2ddbc7 100644 --- a/sound/soc/intel/Makefile +++ b/sound/soc/intel/Makefile | |||
@@ -4,7 +4,7 @@ obj-$(CONFIG_SND_SOC_INTEL_SST) += common/ | |||
4 | # Platform Support | 4 | # Platform Support |
5 | obj-$(CONFIG_SND_SOC_INTEL_HASWELL) += haswell/ | 5 | obj-$(CONFIG_SND_SOC_INTEL_HASWELL) += haswell/ |
6 | obj-$(CONFIG_SND_SOC_INTEL_BAYTRAIL) += baytrail/ | 6 | obj-$(CONFIG_SND_SOC_INTEL_BAYTRAIL) += baytrail/ |
7 | obj-$(CONFIG_SND_SOC_INTEL_BAYTRAIL) += atom/ | 7 | obj-$(CONFIG_SND_SST_MFLD_PLATFORM) += atom/ |
8 | 8 | ||
9 | # Machine support | 9 | # Machine support |
10 | obj-$(CONFIG_SND_SOC_INTEL_SST) += boards/ | 10 | obj-$(CONFIG_SND_SOC_INTEL_SST) += boards/ |
diff --git a/sound/soc/intel/atom/sst-atom-controls.c b/sound/soc/intel/atom/sst-atom-controls.c index 90aa5c0476f3..31e9b9ecbb8a 100644 --- a/sound/soc/intel/atom/sst-atom-controls.c +++ b/sound/soc/intel/atom/sst-atom-controls.c | |||
@@ -774,8 +774,120 @@ int sst_handle_vb_timer(struct snd_soc_dai *dai, bool enable) | |||
774 | return ret; | 774 | return ret; |
775 | } | 775 | } |
776 | 776 | ||
777 | int sst_fill_ssp_slot(struct snd_soc_dai *dai, unsigned int tx_mask, | ||
778 | unsigned int rx_mask, int slots, int slot_width) | ||
779 | { | ||
780 | struct sst_data *ctx = snd_soc_dai_get_drvdata(dai); | ||
781 | |||
782 | ctx->ssp_cmd.nb_slots = slots; | ||
783 | ctx->ssp_cmd.active_tx_slot_map = tx_mask; | ||
784 | ctx->ssp_cmd.active_rx_slot_map = rx_mask; | ||
785 | ctx->ssp_cmd.nb_bits_per_slots = slot_width; | ||
786 | |||
787 | return 0; | ||
788 | } | ||
789 | |||
790 | static int sst_get_frame_sync_polarity(struct snd_soc_dai *dai, | ||
791 | unsigned int fmt) | ||
792 | { | ||
793 | int format; | ||
794 | |||
795 | format = fmt & SND_SOC_DAIFMT_INV_MASK; | ||
796 | dev_dbg(dai->dev, "Enter:%s, format=%x\n", __func__, format); | ||
797 | |||
798 | switch (format) { | ||
799 | case SND_SOC_DAIFMT_NB_NF: | ||
800 | return SSP_FS_ACTIVE_LOW; | ||
801 | case SND_SOC_DAIFMT_NB_IF: | ||
802 | return SSP_FS_ACTIVE_HIGH; | ||
803 | case SND_SOC_DAIFMT_IB_IF: | ||
804 | return SSP_FS_ACTIVE_LOW; | ||
805 | case SND_SOC_DAIFMT_IB_NF: | ||
806 | return SSP_FS_ACTIVE_HIGH; | ||
807 | default: | ||
808 | dev_err(dai->dev, "Invalid frame sync polarity %d\n", format); | ||
809 | } | ||
810 | |||
811 | return -EINVAL; | ||
812 | } | ||
813 | |||
814 | static int sst_get_ssp_mode(struct snd_soc_dai *dai, unsigned int fmt) | ||
815 | { | ||
816 | int format; | ||
817 | |||
818 | format = (fmt & SND_SOC_DAIFMT_MASTER_MASK); | ||
819 | dev_dbg(dai->dev, "Enter:%s, format=%x\n", __func__, format); | ||
820 | |||
821 | switch (format) { | ||
822 | case SND_SOC_DAIFMT_CBS_CFS: | ||
823 | return SSP_MODE_MASTER; | ||
824 | case SND_SOC_DAIFMT_CBM_CFM: | ||
825 | return SSP_MODE_SLAVE; | ||
826 | default: | ||
827 | dev_err(dai->dev, "Invalid ssp protocol: %d\n", format); | ||
828 | } | ||
829 | |||
830 | return -EINVAL; | ||
831 | } | ||
832 | |||
833 | |||
834 | int sst_fill_ssp_config(struct snd_soc_dai *dai, unsigned int fmt) | ||
835 | { | ||
836 | unsigned int mode; | ||
837 | int fs_polarity; | ||
838 | struct sst_data *ctx = snd_soc_dai_get_drvdata(dai); | ||
839 | |||
840 | mode = fmt & SND_SOC_DAIFMT_FORMAT_MASK; | ||
841 | |||
842 | switch (mode) { | ||
843 | case SND_SOC_DAIFMT_DSP_B: | ||
844 | ctx->ssp_cmd.ssp_protocol = SSP_MODE_PCM; | ||
845 | ctx->ssp_cmd.mode = sst_get_ssp_mode(dai, fmt) | (SSP_PCM_MODE_NETWORK << 1); | ||
846 | ctx->ssp_cmd.start_delay = 0; | ||
847 | ctx->ssp_cmd.data_polarity = 1; | ||
848 | ctx->ssp_cmd.frame_sync_width = 1; | ||
849 | break; | ||
850 | |||
851 | case SND_SOC_DAIFMT_DSP_A: | ||
852 | ctx->ssp_cmd.ssp_protocol = SSP_MODE_PCM; | ||
853 | ctx->ssp_cmd.mode = sst_get_ssp_mode(dai, fmt) | (SSP_PCM_MODE_NETWORK << 1); | ||
854 | ctx->ssp_cmd.start_delay = 1; | ||
855 | ctx->ssp_cmd.data_polarity = 1; | ||
856 | ctx->ssp_cmd.frame_sync_width = 1; | ||
857 | break; | ||
858 | |||
859 | case SND_SOC_DAIFMT_I2S: | ||
860 | ctx->ssp_cmd.ssp_protocol = SSP_MODE_I2S; | ||
861 | ctx->ssp_cmd.mode = sst_get_ssp_mode(dai, fmt) | (SSP_PCM_MODE_NORMAL << 1); | ||
862 | ctx->ssp_cmd.start_delay = 1; | ||
863 | ctx->ssp_cmd.data_polarity = 0; | ||
864 | ctx->ssp_cmd.frame_sync_width = ctx->ssp_cmd.nb_bits_per_slots; | ||
865 | break; | ||
866 | |||
867 | case SND_SOC_DAIFMT_LEFT_J: | ||
868 | ctx->ssp_cmd.ssp_protocol = SSP_MODE_I2S; | ||
869 | ctx->ssp_cmd.mode = sst_get_ssp_mode(dai, fmt) | (SSP_PCM_MODE_NORMAL << 1); | ||
870 | ctx->ssp_cmd.start_delay = 0; | ||
871 | ctx->ssp_cmd.data_polarity = 0; | ||
872 | ctx->ssp_cmd.frame_sync_width = ctx->ssp_cmd.nb_bits_per_slots; | ||
873 | break; | ||
874 | |||
875 | default: | ||
876 | dev_dbg(dai->dev, "using default ssp configs\n"); | ||
877 | } | ||
878 | |||
879 | fs_polarity = sst_get_frame_sync_polarity(dai, fmt); | ||
880 | if (fs_polarity < 0) | ||
881 | return fs_polarity; | ||
882 | |||
883 | ctx->ssp_cmd.frame_sync_polarity = fs_polarity; | ||
884 | |||
885 | return 0; | ||
886 | } | ||
887 | |||
777 | /** | 888 | /** |
778 | * sst_ssp_config - contains SSP configuration for media UC | 889 | * sst_ssp_config - contains SSP configuration for media UC |
890 | * this can be overwritten by set_dai_xxx APIs | ||
779 | */ | 891 | */ |
780 | static const struct sst_ssp_config sst_ssp_configs = { | 892 | static const struct sst_ssp_config sst_ssp_configs = { |
781 | .ssp_id = SSP_CODEC, | 893 | .ssp_id = SSP_CODEC, |
@@ -789,47 +901,56 @@ static const struct sst_ssp_config sst_ssp_configs = { | |||
789 | .fs_frequency = SSP_FS_48_KHZ, | 901 | .fs_frequency = SSP_FS_48_KHZ, |
790 | .active_slot_map = 0xF, | 902 | .active_slot_map = 0xF, |
791 | .start_delay = 0, | 903 | .start_delay = 0, |
904 | .frame_sync_polarity = SSP_FS_ACTIVE_HIGH, | ||
905 | .data_polarity = 1, | ||
792 | }; | 906 | }; |
793 | 907 | ||
908 | void sst_fill_ssp_defaults(struct snd_soc_dai *dai) | ||
909 | { | ||
910 | const struct sst_ssp_config *config; | ||
911 | struct sst_data *ctx = snd_soc_dai_get_drvdata(dai); | ||
912 | |||
913 | config = &sst_ssp_configs; | ||
914 | |||
915 | ctx->ssp_cmd.selection = config->ssp_id; | ||
916 | ctx->ssp_cmd.nb_bits_per_slots = config->bits_per_slot; | ||
917 | ctx->ssp_cmd.nb_slots = config->slots; | ||
918 | ctx->ssp_cmd.mode = config->ssp_mode | (config->pcm_mode << 1); | ||
919 | ctx->ssp_cmd.duplex = config->duplex; | ||
920 | ctx->ssp_cmd.active_tx_slot_map = config->active_slot_map; | ||
921 | ctx->ssp_cmd.active_rx_slot_map = config->active_slot_map; | ||
922 | ctx->ssp_cmd.frame_sync_frequency = config->fs_frequency; | ||
923 | ctx->ssp_cmd.frame_sync_polarity = config->frame_sync_polarity; | ||
924 | ctx->ssp_cmd.data_polarity = config->data_polarity; | ||
925 | ctx->ssp_cmd.frame_sync_width = config->fs_width; | ||
926 | ctx->ssp_cmd.ssp_protocol = config->ssp_protocol; | ||
927 | ctx->ssp_cmd.start_delay = config->start_delay; | ||
928 | ctx->ssp_cmd.reserved1 = ctx->ssp_cmd.reserved2 = 0xFF; | ||
929 | } | ||
930 | |||
794 | int send_ssp_cmd(struct snd_soc_dai *dai, const char *id, bool enable) | 931 | int send_ssp_cmd(struct snd_soc_dai *dai, const char *id, bool enable) |
795 | { | 932 | { |
796 | struct sst_cmd_sba_hw_set_ssp cmd; | ||
797 | struct sst_data *drv = snd_soc_dai_get_drvdata(dai); | 933 | struct sst_data *drv = snd_soc_dai_get_drvdata(dai); |
798 | const struct sst_ssp_config *config; | 934 | const struct sst_ssp_config *config; |
799 | 935 | ||
800 | dev_info(dai->dev, "Enter: enable=%d port_name=%s\n", enable, id); | 936 | dev_info(dai->dev, "Enter: enable=%d port_name=%s\n", enable, id); |
801 | 937 | ||
802 | SST_FILL_DEFAULT_DESTINATION(cmd.header.dst); | 938 | SST_FILL_DEFAULT_DESTINATION(drv->ssp_cmd.header.dst); |
803 | cmd.header.command_id = SBA_HW_SET_SSP; | 939 | drv->ssp_cmd.header.command_id = SBA_HW_SET_SSP; |
804 | cmd.header.length = sizeof(struct sst_cmd_sba_hw_set_ssp) | 940 | drv->ssp_cmd.header.length = sizeof(struct sst_cmd_sba_hw_set_ssp) |
805 | - sizeof(struct sst_dsp_header); | 941 | - sizeof(struct sst_dsp_header); |
806 | 942 | ||
807 | config = &sst_ssp_configs; | 943 | config = &sst_ssp_configs; |
808 | dev_dbg(dai->dev, "ssp_id: %u\n", config->ssp_id); | 944 | dev_dbg(dai->dev, "ssp_id: %u\n", config->ssp_id); |
809 | 945 | ||
810 | if (enable) | 946 | if (enable) |
811 | cmd.switch_state = SST_SWITCH_ON; | 947 | drv->ssp_cmd.switch_state = SST_SWITCH_ON; |
812 | else | 948 | else |
813 | cmd.switch_state = SST_SWITCH_OFF; | 949 | drv->ssp_cmd.switch_state = SST_SWITCH_OFF; |
814 | |||
815 | cmd.selection = config->ssp_id; | ||
816 | cmd.nb_bits_per_slots = config->bits_per_slot; | ||
817 | cmd.nb_slots = config->slots; | ||
818 | cmd.mode = config->ssp_mode | (config->pcm_mode << 1); | ||
819 | cmd.duplex = config->duplex; | ||
820 | cmd.active_tx_slot_map = config->active_slot_map; | ||
821 | cmd.active_rx_slot_map = config->active_slot_map; | ||
822 | cmd.frame_sync_frequency = config->fs_frequency; | ||
823 | cmd.frame_sync_polarity = SSP_FS_ACTIVE_HIGH; | ||
824 | cmd.data_polarity = 1; | ||
825 | cmd.frame_sync_width = config->fs_width; | ||
826 | cmd.ssp_protocol = config->ssp_protocol; | ||
827 | cmd.start_delay = config->start_delay; | ||
828 | cmd.reserved1 = cmd.reserved2 = 0xFF; | ||
829 | 950 | ||
830 | return sst_fill_and_send_cmd(drv, SST_IPC_IA_CMD, SST_FLAG_BLOCKED, | 951 | return sst_fill_and_send_cmd(drv, SST_IPC_IA_CMD, SST_FLAG_BLOCKED, |
831 | SST_TASK_SBA, 0, &cmd, | 952 | SST_TASK_SBA, 0, &drv->ssp_cmd, |
832 | sizeof(cmd.header) + cmd.header.length); | 953 | sizeof(drv->ssp_cmd.header) + drv->ssp_cmd.header.length); |
833 | } | 954 | } |
834 | 955 | ||
835 | static int sst_set_be_modules(struct snd_soc_dapm_widget *w, | 956 | static int sst_set_be_modules(struct snd_soc_dapm_widget *w, |
@@ -1280,36 +1401,32 @@ static int sst_fill_widget_module_info(struct snd_soc_dapm_widget *w, | |||
1280 | down_read(&card->controls_rwsem); | 1401 | down_read(&card->controls_rwsem); |
1281 | 1402 | ||
1282 | list_for_each_entry(kctl, &card->controls, list) { | 1403 | list_for_each_entry(kctl, &card->controls, list) { |
1283 | idx = strstr(kctl->id.name, " "); | 1404 | idx = strchr(kctl->id.name, ' '); |
1284 | if (idx == NULL) | 1405 | if (idx == NULL) |
1285 | continue; | 1406 | continue; |
1286 | index = strlen(kctl->id.name) - strlen(idx); | 1407 | index = idx - (char*)kctl->id.name; |
1408 | if (strncmp(kctl->id.name, w->name, index)) | ||
1409 | continue; | ||
1287 | 1410 | ||
1288 | if (strstr(kctl->id.name, "Volume") && | 1411 | if (strstr(kctl->id.name, "Volume")) |
1289 | !strncmp(kctl->id.name, w->name, index)) | ||
1290 | ret = sst_fill_module_list(kctl, w, SST_MODULE_GAIN); | 1412 | ret = sst_fill_module_list(kctl, w, SST_MODULE_GAIN); |
1291 | 1413 | ||
1292 | else if (strstr(kctl->id.name, "params") && | 1414 | else if (strstr(kctl->id.name, "params")) |
1293 | !strncmp(kctl->id.name, w->name, index)) | ||
1294 | ret = sst_fill_module_list(kctl, w, SST_MODULE_ALGO); | 1415 | ret = sst_fill_module_list(kctl, w, SST_MODULE_ALGO); |
1295 | 1416 | ||
1296 | else if (strstr(kctl->id.name, "Switch") && | 1417 | else if (strstr(kctl->id.name, "Switch") && |
1297 | !strncmp(kctl->id.name, w->name, index) && | ||
1298 | strstr(kctl->id.name, "Gain")) { | 1418 | strstr(kctl->id.name, "Gain")) { |
1299 | struct sst_gain_mixer_control *mc = | 1419 | struct sst_gain_mixer_control *mc = |
1300 | (void *)kctl->private_value; | 1420 | (void *)kctl->private_value; |
1301 | 1421 | ||
1302 | mc->w = w; | 1422 | mc->w = w; |
1303 | 1423 | ||
1304 | } else if (strstr(kctl->id.name, "interleaver") && | 1424 | } else if (strstr(kctl->id.name, "interleaver")) { |
1305 | !strncmp(kctl->id.name, w->name, index)) { | ||
1306 | struct sst_enum *e = (void *)kctl->private_value; | 1425 | struct sst_enum *e = (void *)kctl->private_value; |
1307 | 1426 | ||
1308 | e->w = w; | 1427 | e->w = w; |
1309 | 1428 | ||
1310 | } else if (strstr(kctl->id.name, "deinterleaver") && | 1429 | } else if (strstr(kctl->id.name, "deinterleaver")) { |
1311 | !strncmp(kctl->id.name, w->name, index)) { | ||
1312 | |||
1313 | struct sst_enum *e = (void *)kctl->private_value; | 1430 | struct sst_enum *e = (void *)kctl->private_value; |
1314 | 1431 | ||
1315 | e->w = w; | 1432 | e->w = w; |
diff --git a/sound/soc/intel/atom/sst-atom-controls.h b/sound/soc/intel/atom/sst-atom-controls.h index daecc58f28af..93de8045d4e1 100644 --- a/sound/soc/intel/atom/sst-atom-controls.h +++ b/sound/soc/intel/atom/sst-atom-controls.h | |||
@@ -562,6 +562,8 @@ struct sst_ssp_config { | |||
562 | u8 active_slot_map; | 562 | u8 active_slot_map; |
563 | u8 start_delay; | 563 | u8 start_delay; |
564 | u16 fs_width; | 564 | u16 fs_width; |
565 | u8 frame_sync_polarity; | ||
566 | u8 data_polarity; | ||
565 | }; | 567 | }; |
566 | 568 | ||
567 | struct sst_ssp_cfg { | 569 | struct sst_ssp_cfg { |
@@ -695,7 +697,7 @@ struct sst_gain_mixer_control { | |||
695 | u16 module_id; | 697 | u16 module_id; |
696 | u16 pipe_id; | 698 | u16 pipe_id; |
697 | u16 task_id; | 699 | u16 task_id; |
698 | char pname[44]; | 700 | char pname[SNDRV_CTL_ELEM_ID_NAME_MAXLEN]; |
699 | struct snd_soc_dapm_widget *w; | 701 | struct snd_soc_dapm_widget *w; |
700 | }; | 702 | }; |
701 | 703 | ||
@@ -867,4 +869,9 @@ struct sst_enum { | |||
867 | SOC_DAPM_ENUM(SST_MUX_CTL_NAME(xpname, xinstance), \ | 869 | SOC_DAPM_ENUM(SST_MUX_CTL_NAME(xpname, xinstance), \ |
868 | SST_SSP_MUX_ENUM(xreg, xshift, xtexts)) | 870 | SST_SSP_MUX_ENUM(xreg, xshift, xtexts)) |
869 | 871 | ||
872 | int sst_fill_ssp_slot(struct snd_soc_dai *dai, unsigned int tx_mask, | ||
873 | unsigned int rx_mask, int slots, int slot_width); | ||
874 | int sst_fill_ssp_config(struct snd_soc_dai *dai, unsigned int fmt); | ||
875 | void sst_fill_ssp_defaults(struct snd_soc_dai *dai); | ||
876 | |||
870 | #endif | 877 | #endif |
diff --git a/sound/soc/intel/atom/sst-mfld-platform-pcm.c b/sound/soc/intel/atom/sst-mfld-platform-pcm.c index 2fbaf2c75d17..641ebe61dc08 100644 --- a/sound/soc/intel/atom/sst-mfld-platform-pcm.c +++ b/sound/soc/intel/atom/sst-mfld-platform-pcm.c | |||
@@ -434,13 +434,51 @@ static int sst_enable_ssp(struct snd_pcm_substream *substream, | |||
434 | 434 | ||
435 | if (!dai->active) { | 435 | if (!dai->active) { |
436 | ret = sst_handle_vb_timer(dai, true); | 436 | ret = sst_handle_vb_timer(dai, true); |
437 | if (ret) | 437 | sst_fill_ssp_defaults(dai); |
438 | return ret; | ||
439 | ret = send_ssp_cmd(dai, dai->name, 1); | ||
440 | } | 438 | } |
441 | return ret; | 439 | return ret; |
442 | } | 440 | } |
443 | 441 | ||
442 | static int sst_be_hw_params(struct snd_pcm_substream *substream, | ||
443 | struct snd_pcm_hw_params *params, | ||
444 | struct snd_soc_dai *dai) | ||
445 | { | ||
446 | int ret = 0; | ||
447 | |||
448 | if (dai->active == 1) | ||
449 | ret = send_ssp_cmd(dai, dai->name, 1); | ||
450 | return ret; | ||
451 | } | ||
452 | |||
453 | static int sst_set_format(struct snd_soc_dai *dai, unsigned int fmt) | ||
454 | { | ||
455 | int ret = 0; | ||
456 | |||
457 | if (!dai->active) | ||
458 | return 0; | ||
459 | |||
460 | ret = sst_fill_ssp_config(dai, fmt); | ||
461 | if (ret < 0) | ||
462 | dev_err(dai->dev, "sst_set_format failed..\n"); | ||
463 | |||
464 | return ret; | ||
465 | } | ||
466 | |||
467 | static int sst_platform_set_ssp_slot(struct snd_soc_dai *dai, | ||
468 | unsigned int tx_mask, unsigned int rx_mask, | ||
469 | int slots, int slot_width) { | ||
470 | int ret = 0; | ||
471 | |||
472 | if (!dai->active) | ||
473 | return ret; | ||
474 | |||
475 | ret = sst_fill_ssp_slot(dai, tx_mask, rx_mask, slots, slot_width); | ||
476 | if (ret < 0) | ||
477 | dev_err(dai->dev, "sst_fill_ssp_slot failed..%d\n", ret); | ||
478 | |||
479 | return ret; | ||
480 | } | ||
481 | |||
444 | static void sst_disable_ssp(struct snd_pcm_substream *substream, | 482 | static void sst_disable_ssp(struct snd_pcm_substream *substream, |
445 | struct snd_soc_dai *dai) | 483 | struct snd_soc_dai *dai) |
446 | { | 484 | { |
@@ -465,6 +503,9 @@ static struct snd_soc_dai_ops sst_compr_dai_ops = { | |||
465 | 503 | ||
466 | static struct snd_soc_dai_ops sst_be_dai_ops = { | 504 | static struct snd_soc_dai_ops sst_be_dai_ops = { |
467 | .startup = sst_enable_ssp, | 505 | .startup = sst_enable_ssp, |
506 | .hw_params = sst_be_hw_params, | ||
507 | .set_fmt = sst_set_format, | ||
508 | .set_tdm_slot = sst_platform_set_ssp_slot, | ||
468 | .shutdown = sst_disable_ssp, | 509 | .shutdown = sst_disable_ssp, |
469 | }; | 510 | }; |
470 | 511 | ||
diff --git a/sound/soc/intel/atom/sst-mfld-platform.h b/sound/soc/intel/atom/sst-mfld-platform.h index 9094314be2b0..2409b23eeacf 100644 --- a/sound/soc/intel/atom/sst-mfld-platform.h +++ b/sound/soc/intel/atom/sst-mfld-platform.h | |||
@@ -22,6 +22,7 @@ | |||
22 | #define __SST_PLATFORMDRV_H__ | 22 | #define __SST_PLATFORMDRV_H__ |
23 | 23 | ||
24 | #include "sst-mfld-dsp.h" | 24 | #include "sst-mfld-dsp.h" |
25 | #include "sst-atom-controls.h" | ||
25 | 26 | ||
26 | extern struct sst_device *sst; | 27 | extern struct sst_device *sst; |
27 | 28 | ||
@@ -175,6 +176,7 @@ struct sst_data { | |||
175 | struct snd_sst_bytes_v2 *byte_stream; | 176 | struct snd_sst_bytes_v2 *byte_stream; |
176 | struct mutex lock; | 177 | struct mutex lock; |
177 | struct snd_soc_card *soc_card; | 178 | struct snd_soc_card *soc_card; |
179 | struct sst_cmd_sba_hw_set_ssp ssp_cmd; | ||
178 | }; | 180 | }; |
179 | int sst_register_dsp(struct sst_device *sst); | 181 | int sst_register_dsp(struct sst_device *sst); |
180 | int sst_unregister_dsp(struct sst_device *sst); | 182 | int sst_unregister_dsp(struct sst_device *sst); |
diff --git a/sound/soc/intel/atom/sst/sst.c b/sound/soc/intel/atom/sst/sst.c index 96c2e420cce6..a4b458e77089 100644 --- a/sound/soc/intel/atom/sst/sst.c +++ b/sound/soc/intel/atom/sst/sst.c | |||
@@ -368,8 +368,8 @@ static inline void sst_restore_shim64(struct intel_sst_drv *ctx, | |||
368 | * initialize by FW or driver when firmware is loaded | 368 | * initialize by FW or driver when firmware is loaded |
369 | */ | 369 | */ |
370 | spin_lock_irqsave(&ctx->ipc_spin_lock, irq_flags); | 370 | spin_lock_irqsave(&ctx->ipc_spin_lock, irq_flags); |
371 | sst_shim_write64(shim, SST_IMRX, shim_regs->imrx), | 371 | sst_shim_write64(shim, SST_IMRX, shim_regs->imrx); |
372 | sst_shim_write64(shim, SST_CSR, shim_regs->csr), | 372 | sst_shim_write64(shim, SST_CSR, shim_regs->csr); |
373 | spin_unlock_irqrestore(&ctx->ipc_spin_lock, irq_flags); | 373 | spin_unlock_irqrestore(&ctx->ipc_spin_lock, irq_flags); |
374 | } | 374 | } |
375 | 375 | ||
diff --git a/sound/soc/intel/atom/sst/sst_acpi.c b/sound/soc/intel/atom/sst/sst_acpi.c index 05f693083911..bb19b5801466 100644 --- a/sound/soc/intel/atom/sst/sst_acpi.c +++ b/sound/soc/intel/atom/sst/sst_acpi.c | |||
@@ -354,6 +354,10 @@ static struct sst_machines sst_acpi_chv[] = { | |||
354 | &chv_platform_data }, | 354 | &chv_platform_data }, |
355 | {"10EC5645", "cht-bsw", "cht-bsw-rt5645", NULL, "intel/fw_sst_22a8.bin", | 355 | {"10EC5645", "cht-bsw", "cht-bsw-rt5645", NULL, "intel/fw_sst_22a8.bin", |
356 | &chv_platform_data }, | 356 | &chv_platform_data }, |
357 | {"10EC5650", "cht-bsw", "cht-bsw-rt5645", NULL, "intel/fw_sst_22a8.bin", | ||
358 | &chv_platform_data }, | ||
359 | {"193C9890", "cht-bsw", "cht-bsw-max98090", NULL, | ||
360 | "intel/fw_sst_22a8.bin", &chv_platform_data }, | ||
357 | {}, | 361 | {}, |
358 | }; | 362 | }; |
359 | 363 | ||
diff --git a/sound/soc/intel/atom/sst/sst_drv_interface.c b/sound/soc/intel/atom/sst/sst_drv_interface.c index 7b50a9d17ec1..620da1d1b9e3 100644 --- a/sound/soc/intel/atom/sst/sst_drv_interface.c +++ b/sound/soc/intel/atom/sst/sst_drv_interface.c | |||
@@ -533,7 +533,7 @@ static inline int sst_calc_tstamp(struct intel_sst_drv *ctx, | |||
533 | 533 | ||
534 | info->buffer_ptr = pointer_samples / substream->runtime->channels; | 534 | info->buffer_ptr = pointer_samples / substream->runtime->channels; |
535 | 535 | ||
536 | info->pcm_delay = delay_frames / substream->runtime->channels; | 536 | info->pcm_delay = delay_frames; |
537 | dev_dbg(ctx->dev, "buffer ptr %llu pcm_delay rep: %llu\n", | 537 | dev_dbg(ctx->dev, "buffer ptr %llu pcm_delay rep: %llu\n", |
538 | info->buffer_ptr, info->pcm_delay); | 538 | info->buffer_ptr, info->pcm_delay); |
539 | return 0; | 539 | return 0; |
diff --git a/sound/soc/intel/baytrail/sst-baytrail-ipc.c b/sound/soc/intel/baytrail/sst-baytrail-ipc.c index 1efb33b36303..4c01bb43928d 100644 --- a/sound/soc/intel/baytrail/sst-baytrail-ipc.c +++ b/sound/soc/intel/baytrail/sst-baytrail-ipc.c | |||
@@ -679,6 +679,14 @@ static u64 byt_reply_msg_match(u64 header, u64 *mask) | |||
679 | return header; | 679 | return header; |
680 | } | 680 | } |
681 | 681 | ||
682 | static bool byt_is_dsp_busy(struct sst_dsp *dsp) | ||
683 | { | ||
684 | u64 ipcx; | ||
685 | |||
686 | ipcx = sst_dsp_shim_read_unlocked(dsp, SST_IPCX); | ||
687 | return (ipcx & (SST_IPCX_BUSY | SST_IPCX_DONE)); | ||
688 | } | ||
689 | |||
682 | int sst_byt_dsp_init(struct device *dev, struct sst_pdata *pdata) | 690 | int sst_byt_dsp_init(struct device *dev, struct sst_pdata *pdata) |
683 | { | 691 | { |
684 | struct sst_byt *byt; | 692 | struct sst_byt *byt; |
@@ -699,6 +707,9 @@ int sst_byt_dsp_init(struct device *dev, struct sst_pdata *pdata) | |||
699 | ipc->ops.shim_dbg = byt_shim_dbg; | 707 | ipc->ops.shim_dbg = byt_shim_dbg; |
700 | ipc->ops.tx_data_copy = byt_tx_data_copy; | 708 | ipc->ops.tx_data_copy = byt_tx_data_copy; |
701 | ipc->ops.reply_msg_match = byt_reply_msg_match; | 709 | ipc->ops.reply_msg_match = byt_reply_msg_match; |
710 | ipc->ops.is_dsp_busy = byt_is_dsp_busy; | ||
711 | ipc->tx_data_max_size = IPC_MAX_MAILBOX_BYTES; | ||
712 | ipc->rx_data_max_size = IPC_MAX_MAILBOX_BYTES; | ||
702 | 713 | ||
703 | err = sst_ipc_init(ipc); | 714 | err = sst_ipc_init(ipc); |
704 | if (err != 0) | 715 | if (err != 0) |
@@ -759,7 +770,6 @@ fw_err: | |||
759 | dsp_new_err: | 770 | dsp_new_err: |
760 | sst_ipc_fini(ipc); | 771 | sst_ipc_fini(ipc); |
761 | ipc_init_err: | 772 | ipc_init_err: |
762 | kfree(byt); | ||
763 | 773 | ||
764 | return err; | 774 | return err; |
765 | } | 775 | } |
diff --git a/sound/soc/intel/boards/Makefile b/sound/soc/intel/boards/Makefile index f8237f0044eb..cb94895c9edb 100644 --- a/sound/soc/intel/boards/Makefile +++ b/sound/soc/intel/boards/Makefile | |||
@@ -5,6 +5,7 @@ snd-soc-sst-broadwell-objs := broadwell.o | |||
5 | snd-soc-sst-bytcr-rt5640-objs := bytcr_rt5640.o | 5 | snd-soc-sst-bytcr-rt5640-objs := bytcr_rt5640.o |
6 | snd-soc-sst-cht-bsw-rt5672-objs := cht_bsw_rt5672.o | 6 | snd-soc-sst-cht-bsw-rt5672-objs := cht_bsw_rt5672.o |
7 | snd-soc-sst-cht-bsw-rt5645-objs := cht_bsw_rt5645.o | 7 | snd-soc-sst-cht-bsw-rt5645-objs := cht_bsw_rt5645.o |
8 | snd-soc-sst-cht-bsw-max98090_ti-objs := cht_bsw_max98090_ti.o | ||
8 | 9 | ||
9 | obj-$(CONFIG_SND_SOC_INTEL_HASWELL_MACH) += snd-soc-sst-haswell.o | 10 | obj-$(CONFIG_SND_SOC_INTEL_HASWELL_MACH) += snd-soc-sst-haswell.o |
10 | obj-$(CONFIG_SND_SOC_INTEL_BYT_RT5640_MACH) += snd-soc-sst-byt-rt5640-mach.o | 11 | obj-$(CONFIG_SND_SOC_INTEL_BYT_RT5640_MACH) += snd-soc-sst-byt-rt5640-mach.o |
@@ -13,3 +14,4 @@ obj-$(CONFIG_SND_SOC_INTEL_BROADWELL_MACH) += snd-soc-sst-broadwell.o | |||
13 | obj-$(CONFIG_SND_SOC_INTEL_BYTCR_RT5640_MACH) += snd-soc-sst-bytcr-rt5640.o | 14 | obj-$(CONFIG_SND_SOC_INTEL_BYTCR_RT5640_MACH) += snd-soc-sst-bytcr-rt5640.o |
14 | obj-$(CONFIG_SND_SOC_INTEL_CHT_BSW_RT5672_MACH) += snd-soc-sst-cht-bsw-rt5672.o | 15 | obj-$(CONFIG_SND_SOC_INTEL_CHT_BSW_RT5672_MACH) += snd-soc-sst-cht-bsw-rt5672.o |
15 | obj-$(CONFIG_SND_SOC_INTEL_CHT_BSW_RT5645_MACH) += snd-soc-sst-cht-bsw-rt5645.o | 16 | obj-$(CONFIG_SND_SOC_INTEL_CHT_BSW_RT5645_MACH) += snd-soc-sst-cht-bsw-rt5645.o |
17 | obj-$(CONFIG_SND_SOC_INTEL_CHT_BSW_MAX98090_TI_MACH) += snd-soc-sst-cht-bsw-max98090_ti.o | ||
diff --git a/sound/soc/intel/boards/cht_bsw_max98090_ti.c b/sound/soc/intel/boards/cht_bsw_max98090_ti.c new file mode 100644 index 000000000000..d604ee80eda4 --- /dev/null +++ b/sound/soc/intel/boards/cht_bsw_max98090_ti.c | |||
@@ -0,0 +1,348 @@ | |||
1 | /* | ||
2 | * cht-bsw-max98090.c - ASoc Machine driver for Intel Cherryview-based | ||
3 | * platforms Cherrytrail and Braswell, with max98090 & TI codec. | ||
4 | * | ||
5 | * Copyright (C) 2015 Intel Corp | ||
6 | * Author: Fang, Yang A <yang.a.fang@intel.com> | ||
7 | * This file is modified from cht_bsw_rt5645.c | ||
8 | * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ | ||
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 as published by | ||
12 | * the Free Software Foundation; version 2 of the License. | ||
13 | * | ||
14 | * This program is distributed in the hope that it will be useful, but | ||
15 | * WITHOUT ANY WARRANTY; 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 | */ | ||
21 | |||
22 | #include <linux/module.h> | ||
23 | #include <linux/platform_device.h> | ||
24 | #include <linux/slab.h> | ||
25 | #include <linux/acpi.h> | ||
26 | #include <sound/pcm.h> | ||
27 | #include <sound/pcm_params.h> | ||
28 | #include <sound/soc.h> | ||
29 | #include <sound/jack.h> | ||
30 | #include "../../codecs/max98090.h" | ||
31 | #include "../atom/sst-atom-controls.h" | ||
32 | #include "../../codecs/ts3a227e.h" | ||
33 | |||
34 | #define CHT_PLAT_CLK_3_HZ 19200000 | ||
35 | #define CHT_CODEC_DAI "HiFi" | ||
36 | |||
37 | struct cht_mc_private { | ||
38 | struct snd_soc_jack jack; | ||
39 | bool ts3a227e_present; | ||
40 | }; | ||
41 | |||
42 | static inline struct snd_soc_dai *cht_get_codec_dai(struct snd_soc_card *card) | ||
43 | { | ||
44 | int i; | ||
45 | |||
46 | for (i = 0; i < card->num_rtd; i++) { | ||
47 | struct snd_soc_pcm_runtime *rtd; | ||
48 | |||
49 | rtd = card->rtd + i; | ||
50 | if (!strncmp(rtd->codec_dai->name, CHT_CODEC_DAI, | ||
51 | strlen(CHT_CODEC_DAI))) | ||
52 | return rtd->codec_dai; | ||
53 | } | ||
54 | return NULL; | ||
55 | } | ||
56 | |||
57 | static const struct snd_soc_dapm_widget cht_dapm_widgets[] = { | ||
58 | SND_SOC_DAPM_HP("Headphone", NULL), | ||
59 | SND_SOC_DAPM_MIC("Headset Mic", NULL), | ||
60 | SND_SOC_DAPM_MIC("Int Mic", NULL), | ||
61 | SND_SOC_DAPM_SPK("Ext Spk", NULL), | ||
62 | }; | ||
63 | |||
64 | static const struct snd_soc_dapm_route cht_audio_map[] = { | ||
65 | {"IN34", NULL, "Headset Mic"}, | ||
66 | {"Headset Mic", NULL, "MICBIAS"}, | ||
67 | {"DMICL", NULL, "Int Mic"}, | ||
68 | {"Headphone", NULL, "HPL"}, | ||
69 | {"Headphone", NULL, "HPR"}, | ||
70 | {"Ext Spk", NULL, "SPKL"}, | ||
71 | {"Ext Spk", NULL, "SPKR"}, | ||
72 | {"AIF1 Playback", NULL, "ssp2 Tx"}, | ||
73 | {"ssp2 Tx", NULL, "codec_out0"}, | ||
74 | {"ssp2 Tx", NULL, "codec_out1"}, | ||
75 | {"codec_in0", NULL, "ssp2 Rx" }, | ||
76 | {"codec_in1", NULL, "ssp2 Rx" }, | ||
77 | {"ssp2 Rx", NULL, "AIF1 Capture"}, | ||
78 | }; | ||
79 | |||
80 | static const struct snd_kcontrol_new cht_mc_controls[] = { | ||
81 | SOC_DAPM_PIN_SWITCH("Headphone"), | ||
82 | SOC_DAPM_PIN_SWITCH("Headset Mic"), | ||
83 | SOC_DAPM_PIN_SWITCH("Int Mic"), | ||
84 | SOC_DAPM_PIN_SWITCH("Ext Spk"), | ||
85 | }; | ||
86 | |||
87 | static int cht_aif1_hw_params(struct snd_pcm_substream *substream, | ||
88 | struct snd_pcm_hw_params *params) | ||
89 | { | ||
90 | struct snd_soc_pcm_runtime *rtd = substream->private_data; | ||
91 | struct snd_soc_dai *codec_dai = rtd->codec_dai; | ||
92 | int ret; | ||
93 | |||
94 | ret = snd_soc_dai_set_sysclk(codec_dai, M98090_REG_SYSTEM_CLOCK, | ||
95 | CHT_PLAT_CLK_3_HZ, SND_SOC_CLOCK_IN); | ||
96 | if (ret < 0) { | ||
97 | dev_err(rtd->dev, "can't set codec sysclk: %d\n", ret); | ||
98 | return ret; | ||
99 | } | ||
100 | |||
101 | return 0; | ||
102 | } | ||
103 | |||
104 | static int cht_ti_jack_event(struct notifier_block *nb, | ||
105 | unsigned long event, void *data) | ||
106 | { | ||
107 | |||
108 | struct snd_soc_jack *jack = (struct snd_soc_jack *)data; | ||
109 | struct snd_soc_dai *codec_dai = jack->card->rtd->codec_dai; | ||
110 | struct snd_soc_codec *codec = codec_dai->codec; | ||
111 | |||
112 | if (event & SND_JACK_MICROPHONE) { | ||
113 | |||
114 | snd_soc_dapm_force_enable_pin(&codec->dapm, "SHDN"); | ||
115 | snd_soc_dapm_force_enable_pin(&codec->dapm, "MICBIAS"); | ||
116 | snd_soc_dapm_sync(&codec->dapm); | ||
117 | } else { | ||
118 | |||
119 | snd_soc_dapm_disable_pin(&codec->dapm, "MICBIAS"); | ||
120 | snd_soc_dapm_disable_pin(&codec->dapm, "SHDN"); | ||
121 | snd_soc_dapm_sync(&codec->dapm); | ||
122 | } | ||
123 | |||
124 | return 0; | ||
125 | } | ||
126 | |||
127 | static struct notifier_block cht_jack_nb = { | ||
128 | .notifier_call = cht_ti_jack_event, | ||
129 | }; | ||
130 | |||
131 | static int cht_codec_init(struct snd_soc_pcm_runtime *runtime) | ||
132 | { | ||
133 | int ret; | ||
134 | int jack_type; | ||
135 | struct cht_mc_private *ctx = snd_soc_card_get_drvdata(runtime->card); | ||
136 | struct snd_soc_jack *jack = &ctx->jack; | ||
137 | |||
138 | /** | ||
139 | * TI supports 4 butons headset detection | ||
140 | * KEY_MEDIA | ||
141 | * KEY_VOICECOMMAND | ||
142 | * KEY_VOLUMEUP | ||
143 | * KEY_VOLUMEDOWN | ||
144 | */ | ||
145 | if (ctx->ts3a227e_present) | ||
146 | jack_type = SND_JACK_HEADPHONE | SND_JACK_MICROPHONE | | ||
147 | SND_JACK_BTN_0 | SND_JACK_BTN_1 | | ||
148 | SND_JACK_BTN_2 | SND_JACK_BTN_3; | ||
149 | else | ||
150 | jack_type = SND_JACK_HEADPHONE | SND_JACK_MICROPHONE; | ||
151 | |||
152 | ret = snd_soc_card_jack_new(runtime->card, "Headset Jack", | ||
153 | jack_type, jack, NULL, 0); | ||
154 | |||
155 | if (ret) { | ||
156 | dev_err(runtime->dev, "Headset Jack creation failed %d\n", ret); | ||
157 | return ret; | ||
158 | } | ||
159 | |||
160 | if (ctx->ts3a227e_present) | ||
161 | snd_soc_jack_notifier_register(jack, &cht_jack_nb); | ||
162 | |||
163 | return ret; | ||
164 | } | ||
165 | |||
166 | static int cht_codec_fixup(struct snd_soc_pcm_runtime *rtd, | ||
167 | struct snd_pcm_hw_params *params) | ||
168 | { | ||
169 | struct snd_interval *rate = hw_param_interval(params, | ||
170 | SNDRV_PCM_HW_PARAM_RATE); | ||
171 | struct snd_interval *channels = hw_param_interval(params, | ||
172 | SNDRV_PCM_HW_PARAM_CHANNELS); | ||
173 | int ret = 0; | ||
174 | unsigned int fmt = 0; | ||
175 | |||
176 | ret = snd_soc_dai_set_tdm_slot(rtd->cpu_dai, 0x3, 0x3, 2, 16); | ||
177 | if (ret < 0) { | ||
178 | dev_err(rtd->dev, "can't set cpu_dai slot fmt: %d\n", ret); | ||
179 | return ret; | ||
180 | } | ||
181 | |||
182 | fmt = SND_SOC_DAIFMT_LEFT_J | SND_SOC_DAIFMT_NB_NF | ||
183 | | SND_SOC_DAIFMT_CBS_CFS; | ||
184 | |||
185 | ret = snd_soc_dai_set_fmt(rtd->cpu_dai, fmt); | ||
186 | if (ret < 0) { | ||
187 | dev_err(rtd->dev, "can't set cpu_dai set fmt: %d\n", ret); | ||
188 | return ret; | ||
189 | } | ||
190 | |||
191 | /* The DSP will covert the FE rate to 48k, stereo, 24bits */ | ||
192 | rate->min = rate->max = 48000; | ||
193 | channels->min = channels->max = 2; | ||
194 | |||
195 | /* set SSP2 to 24-bit */ | ||
196 | params_set_format(params, SNDRV_PCM_FORMAT_S24_LE); | ||
197 | return 0; | ||
198 | } | ||
199 | |||
200 | static unsigned int rates_48000[] = { | ||
201 | 48000, | ||
202 | }; | ||
203 | |||
204 | static struct snd_pcm_hw_constraint_list constraints_48000 = { | ||
205 | .count = ARRAY_SIZE(rates_48000), | ||
206 | .list = rates_48000, | ||
207 | }; | ||
208 | |||
209 | static int cht_aif1_startup(struct snd_pcm_substream *substream) | ||
210 | { | ||
211 | return snd_pcm_hw_constraint_list(substream->runtime, 0, | ||
212 | SNDRV_PCM_HW_PARAM_RATE, | ||
213 | &constraints_48000); | ||
214 | } | ||
215 | |||
216 | static int cht_max98090_headset_init(struct snd_soc_component *component) | ||
217 | { | ||
218 | struct snd_soc_card *card = component->card; | ||
219 | struct cht_mc_private *ctx = snd_soc_card_get_drvdata(card); | ||
220 | |||
221 | return ts3a227e_enable_jack_detect(component, &ctx->jack); | ||
222 | } | ||
223 | |||
224 | static struct snd_soc_ops cht_aif1_ops = { | ||
225 | .startup = cht_aif1_startup, | ||
226 | }; | ||
227 | |||
228 | static struct snd_soc_ops cht_be_ssp2_ops = { | ||
229 | .hw_params = cht_aif1_hw_params, | ||
230 | }; | ||
231 | |||
232 | static struct snd_soc_aux_dev cht_max98090_headset_dev = { | ||
233 | .name = "Headset Chip", | ||
234 | .init = cht_max98090_headset_init, | ||
235 | .codec_name = "i2c-104C227E:00", | ||
236 | }; | ||
237 | |||
238 | static struct snd_soc_dai_link cht_dailink[] = { | ||
239 | [MERR_DPCM_AUDIO] = { | ||
240 | .name = "Audio Port", | ||
241 | .stream_name = "Audio", | ||
242 | .cpu_dai_name = "media-cpu-dai", | ||
243 | .codec_dai_name = "snd-soc-dummy-dai", | ||
244 | .codec_name = "snd-soc-dummy", | ||
245 | .platform_name = "sst-mfld-platform", | ||
246 | .nonatomic = true, | ||
247 | .dynamic = 1, | ||
248 | .dpcm_playback = 1, | ||
249 | .dpcm_capture = 1, | ||
250 | .ops = &cht_aif1_ops, | ||
251 | }, | ||
252 | [MERR_DPCM_COMPR] = { | ||
253 | .name = "Compressed Port", | ||
254 | .stream_name = "Compress", | ||
255 | .cpu_dai_name = "compress-cpu-dai", | ||
256 | .codec_dai_name = "snd-soc-dummy-dai", | ||
257 | .codec_name = "snd-soc-dummy", | ||
258 | .platform_name = "sst-mfld-platform", | ||
259 | }, | ||
260 | /* back ends */ | ||
261 | { | ||
262 | .name = "SSP2-Codec", | ||
263 | .be_id = 1, | ||
264 | .cpu_dai_name = "ssp2-port", | ||
265 | .platform_name = "sst-mfld-platform", | ||
266 | .no_pcm = 1, | ||
267 | .codec_dai_name = "HiFi", | ||
268 | .codec_name = "i2c-193C9890:00", | ||
269 | .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF | ||
270 | | SND_SOC_DAIFMT_CBS_CFS, | ||
271 | .init = cht_codec_init, | ||
272 | .be_hw_params_fixup = cht_codec_fixup, | ||
273 | .dpcm_playback = 1, | ||
274 | .dpcm_capture = 1, | ||
275 | .ops = &cht_be_ssp2_ops, | ||
276 | }, | ||
277 | }; | ||
278 | |||
279 | /* SoC card */ | ||
280 | static struct snd_soc_card snd_soc_card_cht = { | ||
281 | .name = "chtmax98090", | ||
282 | .dai_link = cht_dailink, | ||
283 | .num_links = ARRAY_SIZE(cht_dailink), | ||
284 | .aux_dev = &cht_max98090_headset_dev, | ||
285 | .num_aux_devs = 1, | ||
286 | .dapm_widgets = cht_dapm_widgets, | ||
287 | .num_dapm_widgets = ARRAY_SIZE(cht_dapm_widgets), | ||
288 | .dapm_routes = cht_audio_map, | ||
289 | .num_dapm_routes = ARRAY_SIZE(cht_audio_map), | ||
290 | .controls = cht_mc_controls, | ||
291 | .num_controls = ARRAY_SIZE(cht_mc_controls), | ||
292 | }; | ||
293 | |||
294 | static acpi_status snd_acpi_codec_match(acpi_handle handle, u32 level, | ||
295 | void *context, void **ret) | ||
296 | { | ||
297 | *(bool *)context = true; | ||
298 | return AE_OK; | ||
299 | } | ||
300 | |||
301 | static int snd_cht_mc_probe(struct platform_device *pdev) | ||
302 | { | ||
303 | int ret_val = 0; | ||
304 | bool found = false; | ||
305 | struct cht_mc_private *drv; | ||
306 | |||
307 | drv = devm_kzalloc(&pdev->dev, sizeof(*drv), GFP_ATOMIC); | ||
308 | if (!drv) | ||
309 | return -ENOMEM; | ||
310 | |||
311 | if (ACPI_SUCCESS(acpi_get_devices( | ||
312 | "104C227E", | ||
313 | snd_acpi_codec_match, | ||
314 | &found, NULL)) && found) { | ||
315 | drv->ts3a227e_present = true; | ||
316 | } else { | ||
317 | /* no need probe TI jack detection chip */ | ||
318 | snd_soc_card_cht.aux_dev = NULL; | ||
319 | snd_soc_card_cht.num_aux_devs = 0; | ||
320 | drv->ts3a227e_present = false; | ||
321 | } | ||
322 | |||
323 | /* register the soc card */ | ||
324 | snd_soc_card_cht.dev = &pdev->dev; | ||
325 | snd_soc_card_set_drvdata(&snd_soc_card_cht, drv); | ||
326 | ret_val = devm_snd_soc_register_card(&pdev->dev, &snd_soc_card_cht); | ||
327 | if (ret_val) { | ||
328 | dev_err(&pdev->dev, | ||
329 | "snd_soc_register_card failed %d\n", ret_val); | ||
330 | return ret_val; | ||
331 | } | ||
332 | platform_set_drvdata(pdev, &snd_soc_card_cht); | ||
333 | return ret_val; | ||
334 | } | ||
335 | |||
336 | static struct platform_driver snd_cht_mc_driver = { | ||
337 | .driver = { | ||
338 | .name = "cht-bsw-max98090", | ||
339 | }, | ||
340 | .probe = snd_cht_mc_probe, | ||
341 | }; | ||
342 | |||
343 | module_platform_driver(snd_cht_mc_driver) | ||
344 | |||
345 | MODULE_DESCRIPTION("ASoC Intel(R) Braswell Machine driver"); | ||
346 | MODULE_AUTHOR("Fang, Yang A <yang.a.fang@intel.com>"); | ||
347 | MODULE_LICENSE("GPL v2"); | ||
348 | MODULE_ALIAS("platform:cht-bsw-max98090"); | ||
diff --git a/sound/soc/intel/boards/cht_bsw_rt5645.c b/sound/soc/intel/boards/cht_bsw_rt5645.c index 20a28b22e30f..bdcaf467842a 100644 --- a/sound/soc/intel/boards/cht_bsw_rt5645.c +++ b/sound/soc/intel/boards/cht_bsw_rt5645.c | |||
@@ -21,6 +21,7 @@ | |||
21 | */ | 21 | */ |
22 | 22 | ||
23 | #include <linux/module.h> | 23 | #include <linux/module.h> |
24 | #include <linux/acpi.h> | ||
24 | #include <linux/platform_device.h> | 25 | #include <linux/platform_device.h> |
25 | #include <linux/slab.h> | 26 | #include <linux/slab.h> |
26 | #include <sound/pcm.h> | 27 | #include <sound/pcm.h> |
@@ -33,9 +34,15 @@ | |||
33 | #define CHT_PLAT_CLK_3_HZ 19200000 | 34 | #define CHT_PLAT_CLK_3_HZ 19200000 |
34 | #define CHT_CODEC_DAI "rt5645-aif1" | 35 | #define CHT_CODEC_DAI "rt5645-aif1" |
35 | 36 | ||
37 | struct cht_acpi_card { | ||
38 | char *codec_id; | ||
39 | int codec_type; | ||
40 | struct snd_soc_card *soc_card; | ||
41 | }; | ||
42 | |||
36 | struct cht_mc_private { | 43 | struct cht_mc_private { |
37 | struct snd_soc_jack hp_jack; | 44 | struct snd_soc_jack jack; |
38 | struct snd_soc_jack mic_jack; | 45 | struct cht_acpi_card *acpi_card; |
39 | }; | 46 | }; |
40 | 47 | ||
41 | static inline struct snd_soc_dai *cht_get_codec_dai(struct snd_soc_card *card) | 48 | static inline struct snd_soc_dai *cht_get_codec_dai(struct snd_soc_card *card) |
@@ -94,7 +101,7 @@ static const struct snd_soc_dapm_widget cht_dapm_widgets[] = { | |||
94 | platform_clock_control, SND_SOC_DAPM_POST_PMD), | 101 | platform_clock_control, SND_SOC_DAPM_POST_PMD), |
95 | }; | 102 | }; |
96 | 103 | ||
97 | static const struct snd_soc_dapm_route cht_audio_map[] = { | 104 | static const struct snd_soc_dapm_route cht_rt5645_audio_map[] = { |
98 | {"IN1P", NULL, "Headset Mic"}, | 105 | {"IN1P", NULL, "Headset Mic"}, |
99 | {"IN1N", NULL, "Headset Mic"}, | 106 | {"IN1N", NULL, "Headset Mic"}, |
100 | {"DMIC L1", NULL, "Int Mic"}, | 107 | {"DMIC L1", NULL, "Int Mic"}, |
@@ -115,6 +122,27 @@ static const struct snd_soc_dapm_route cht_audio_map[] = { | |||
115 | {"Ext Spk", NULL, "Platform Clock"}, | 122 | {"Ext Spk", NULL, "Platform Clock"}, |
116 | }; | 123 | }; |
117 | 124 | ||
125 | static const struct snd_soc_dapm_route cht_rt5650_audio_map[] = { | ||
126 | {"IN1P", NULL, "Headset Mic"}, | ||
127 | {"IN1N", NULL, "Headset Mic"}, | ||
128 | {"DMIC L2", NULL, "Int Mic"}, | ||
129 | {"DMIC R2", NULL, "Int Mic"}, | ||
130 | {"Headphone", NULL, "HPOL"}, | ||
131 | {"Headphone", NULL, "HPOR"}, | ||
132 | {"Ext Spk", NULL, "SPOL"}, | ||
133 | {"Ext Spk", NULL, "SPOR"}, | ||
134 | {"AIF1 Playback", NULL, "ssp2 Tx"}, | ||
135 | {"ssp2 Tx", NULL, "codec_out0"}, | ||
136 | {"ssp2 Tx", NULL, "codec_out1"}, | ||
137 | {"codec_in0", NULL, "ssp2 Rx" }, | ||
138 | {"codec_in1", NULL, "ssp2 Rx" }, | ||
139 | {"ssp2 Rx", NULL, "AIF1 Capture"}, | ||
140 | {"Headphone", NULL, "Platform Clock"}, | ||
141 | {"Headset Mic", NULL, "Platform Clock"}, | ||
142 | {"Int Mic", NULL, "Platform Clock"}, | ||
143 | {"Ext Spk", NULL, "Platform Clock"}, | ||
144 | }; | ||
145 | |||
118 | static const struct snd_kcontrol_new cht_mc_controls[] = { | 146 | static const struct snd_kcontrol_new cht_mc_controls[] = { |
119 | SOC_DAPM_PIN_SWITCH("Headphone"), | 147 | SOC_DAPM_PIN_SWITCH("Headphone"), |
120 | SOC_DAPM_PIN_SWITCH("Headset Mic"), | 148 | SOC_DAPM_PIN_SWITCH("Headset Mic"), |
@@ -150,6 +178,7 @@ static int cht_aif1_hw_params(struct snd_pcm_substream *substream, | |||
150 | static int cht_codec_init(struct snd_soc_pcm_runtime *runtime) | 178 | static int cht_codec_init(struct snd_soc_pcm_runtime *runtime) |
151 | { | 179 | { |
152 | int ret; | 180 | int ret; |
181 | int jack_type; | ||
153 | struct snd_soc_codec *codec = runtime->codec; | 182 | struct snd_soc_codec *codec = runtime->codec; |
154 | struct snd_soc_dai *codec_dai = runtime->codec_dai; | 183 | struct snd_soc_dai *codec_dai = runtime->codec_dai; |
155 | struct cht_mc_private *ctx = snd_soc_card_get_drvdata(runtime->card); | 184 | struct cht_mc_private *ctx = snd_soc_card_get_drvdata(runtime->card); |
@@ -169,23 +198,22 @@ static int cht_codec_init(struct snd_soc_pcm_runtime *runtime) | |||
169 | return ret; | 198 | return ret; |
170 | } | 199 | } |
171 | 200 | ||
172 | ret = snd_soc_card_jack_new(runtime->card, "Headphone Jack", | 201 | if (ctx->acpi_card->codec_type == CODEC_TYPE_RT5650) |
173 | SND_JACK_HEADPHONE, &ctx->hp_jack, | 202 | jack_type = SND_JACK_HEADPHONE | SND_JACK_MICROPHONE | |
174 | NULL, 0); | 203 | SND_JACK_BTN_0 | SND_JACK_BTN_1 | |
175 | if (ret) { | 204 | SND_JACK_BTN_2 | SND_JACK_BTN_3; |
176 | dev_err(runtime->dev, "HP jack creation failed %d\n", ret); | 205 | else |
177 | return ret; | 206 | jack_type = SND_JACK_HEADPHONE | SND_JACK_MICROPHONE; |
178 | } | ||
179 | 207 | ||
180 | ret = snd_soc_card_jack_new(runtime->card, "Mic Jack", | 208 | ret = snd_soc_card_jack_new(runtime->card, "Headset Jack", |
181 | SND_JACK_MICROPHONE, &ctx->mic_jack, | 209 | jack_type, &ctx->jack, |
182 | NULL, 0); | 210 | NULL, 0); |
183 | if (ret) { | 211 | if (ret) { |
184 | dev_err(runtime->dev, "Mic jack creation failed %d\n", ret); | 212 | dev_err(runtime->dev, "Headset jack creation failed %d\n", ret); |
185 | return ret; | 213 | return ret; |
186 | } | 214 | } |
187 | 215 | ||
188 | rt5645_set_jack_detect(codec, &ctx->hp_jack, &ctx->mic_jack); | 216 | rt5645_set_jack_detect(codec, &ctx->jack, &ctx->jack, &ctx->jack); |
189 | 217 | ||
190 | return ret; | 218 | return ret; |
191 | } | 219 | } |
@@ -239,7 +267,7 @@ static struct snd_soc_dai_link cht_dailink[] = { | |||
239 | .codec_dai_name = "snd-soc-dummy-dai", | 267 | .codec_dai_name = "snd-soc-dummy-dai", |
240 | .codec_name = "snd-soc-dummy", | 268 | .codec_name = "snd-soc-dummy", |
241 | .platform_name = "sst-mfld-platform", | 269 | .platform_name = "sst-mfld-platform", |
242 | .ignore_suspend = 1, | 270 | .nonatomic = true, |
243 | .dynamic = 1, | 271 | .dynamic = 1, |
244 | .dpcm_playback = 1, | 272 | .dpcm_playback = 1, |
245 | .dpcm_capture = 1, | 273 | .dpcm_capture = 1, |
@@ -267,7 +295,7 @@ static struct snd_soc_dai_link cht_dailink[] = { | |||
267 | | SND_SOC_DAIFMT_CBS_CFS, | 295 | | SND_SOC_DAIFMT_CBS_CFS, |
268 | .init = cht_codec_init, | 296 | .init = cht_codec_init, |
269 | .be_hw_params_fixup = cht_codec_fixup, | 297 | .be_hw_params_fixup = cht_codec_fixup, |
270 | .ignore_suspend = 1, | 298 | .nonatomic = true, |
271 | .dpcm_playback = 1, | 299 | .dpcm_playback = 1, |
272 | .dpcm_capture = 1, | 300 | .dpcm_capture = 1, |
273 | .ops = &cht_be_ssp2_ops, | 301 | .ops = &cht_be_ssp2_ops, |
@@ -275,43 +303,85 @@ static struct snd_soc_dai_link cht_dailink[] = { | |||
275 | }; | 303 | }; |
276 | 304 | ||
277 | /* SoC card */ | 305 | /* SoC card */ |
278 | static struct snd_soc_card snd_soc_card_cht = { | 306 | static struct snd_soc_card snd_soc_card_chtrt5645 = { |
279 | .name = "chtrt5645", | 307 | .name = "chtrt5645", |
280 | .dai_link = cht_dailink, | 308 | .dai_link = cht_dailink, |
281 | .num_links = ARRAY_SIZE(cht_dailink), | 309 | .num_links = ARRAY_SIZE(cht_dailink), |
282 | .dapm_widgets = cht_dapm_widgets, | 310 | .dapm_widgets = cht_dapm_widgets, |
283 | .num_dapm_widgets = ARRAY_SIZE(cht_dapm_widgets), | 311 | .num_dapm_widgets = ARRAY_SIZE(cht_dapm_widgets), |
284 | .dapm_routes = cht_audio_map, | 312 | .dapm_routes = cht_rt5645_audio_map, |
285 | .num_dapm_routes = ARRAY_SIZE(cht_audio_map), | 313 | .num_dapm_routes = ARRAY_SIZE(cht_rt5645_audio_map), |
286 | .controls = cht_mc_controls, | 314 | .controls = cht_mc_controls, |
287 | .num_controls = ARRAY_SIZE(cht_mc_controls), | 315 | .num_controls = ARRAY_SIZE(cht_mc_controls), |
288 | }; | 316 | }; |
289 | 317 | ||
318 | static struct snd_soc_card snd_soc_card_chtrt5650 = { | ||
319 | .name = "chtrt5650", | ||
320 | .dai_link = cht_dailink, | ||
321 | .num_links = ARRAY_SIZE(cht_dailink), | ||
322 | .dapm_widgets = cht_dapm_widgets, | ||
323 | .num_dapm_widgets = ARRAY_SIZE(cht_dapm_widgets), | ||
324 | .dapm_routes = cht_rt5650_audio_map, | ||
325 | .num_dapm_routes = ARRAY_SIZE(cht_rt5650_audio_map), | ||
326 | .controls = cht_mc_controls, | ||
327 | .num_controls = ARRAY_SIZE(cht_mc_controls), | ||
328 | }; | ||
329 | |||
330 | static struct cht_acpi_card snd_soc_cards[] = { | ||
331 | {"10EC5645", CODEC_TYPE_RT5645, &snd_soc_card_chtrt5645}, | ||
332 | {"10EC5650", CODEC_TYPE_RT5650, &snd_soc_card_chtrt5650}, | ||
333 | }; | ||
334 | |||
335 | static acpi_status snd_acpi_codec_match(acpi_handle handle, u32 level, | ||
336 | void *context, void **ret) | ||
337 | { | ||
338 | *(bool *)context = true; | ||
339 | return AE_OK; | ||
340 | } | ||
341 | |||
290 | static int snd_cht_mc_probe(struct platform_device *pdev) | 342 | static int snd_cht_mc_probe(struct platform_device *pdev) |
291 | { | 343 | { |
292 | int ret_val = 0; | 344 | int ret_val = 0; |
345 | int i; | ||
293 | struct cht_mc_private *drv; | 346 | struct cht_mc_private *drv; |
347 | struct snd_soc_card *card = snd_soc_cards[0].soc_card; | ||
348 | bool found = false; | ||
349 | char codec_name[16]; | ||
294 | 350 | ||
295 | drv = devm_kzalloc(&pdev->dev, sizeof(*drv), GFP_ATOMIC); | 351 | drv = devm_kzalloc(&pdev->dev, sizeof(*drv), GFP_ATOMIC); |
296 | if (!drv) | 352 | if (!drv) |
297 | return -ENOMEM; | 353 | return -ENOMEM; |
298 | 354 | ||
299 | snd_soc_card_cht.dev = &pdev->dev; | 355 | for (i = 0; i < ARRAY_SIZE(snd_soc_cards); i++) { |
300 | snd_soc_card_set_drvdata(&snd_soc_card_cht, drv); | 356 | if (ACPI_SUCCESS(acpi_get_devices( |
301 | ret_val = devm_snd_soc_register_card(&pdev->dev, &snd_soc_card_cht); | 357 | snd_soc_cards[i].codec_id, |
358 | snd_acpi_codec_match, | ||
359 | &found, NULL)) && found) { | ||
360 | dev_dbg(&pdev->dev, | ||
361 | "found codec %s\n", snd_soc_cards[i].codec_id); | ||
362 | card = snd_soc_cards[i].soc_card; | ||
363 | drv->acpi_card = &snd_soc_cards[i]; | ||
364 | break; | ||
365 | } | ||
366 | } | ||
367 | card->dev = &pdev->dev; | ||
368 | sprintf(codec_name, "i2c-%s:00", drv->acpi_card->codec_id); | ||
369 | /* set correct codec name */ | ||
370 | strcpy((char *)card->dai_link[2].codec_name, codec_name); | ||
371 | snd_soc_card_set_drvdata(card, drv); | ||
372 | ret_val = devm_snd_soc_register_card(&pdev->dev, card); | ||
302 | if (ret_val) { | 373 | if (ret_val) { |
303 | dev_err(&pdev->dev, | 374 | dev_err(&pdev->dev, |
304 | "snd_soc_register_card failed %d\n", ret_val); | 375 | "snd_soc_register_card failed %d\n", ret_val); |
305 | return ret_val; | 376 | return ret_val; |
306 | } | 377 | } |
307 | platform_set_drvdata(pdev, &snd_soc_card_cht); | 378 | platform_set_drvdata(pdev, card); |
308 | return ret_val; | 379 | return ret_val; |
309 | } | 380 | } |
310 | 381 | ||
311 | static struct platform_driver snd_cht_mc_driver = { | 382 | static struct platform_driver snd_cht_mc_driver = { |
312 | .driver = { | 383 | .driver = { |
313 | .name = "cht-bsw-rt5645", | 384 | .name = "cht-bsw-rt5645", |
314 | .pm = &snd_soc_pm_ops, | ||
315 | }, | 385 | }, |
316 | .probe = snd_cht_mc_probe, | 386 | .probe = snd_cht_mc_probe, |
317 | }; | 387 | }; |
diff --git a/sound/soc/intel/common/sst-acpi.c b/sound/soc/intel/common/sst-acpi.c index 42f293f9c6e2..67b6d3d52f57 100644 --- a/sound/soc/intel/common/sst-acpi.c +++ b/sound/soc/intel/common/sst-acpi.c | |||
@@ -263,7 +263,7 @@ static struct sst_acpi_desc sst_acpi_baytrail_desc = { | |||
263 | .resindex_dma_base = -1, | 263 | .resindex_dma_base = -1, |
264 | }; | 264 | }; |
265 | 265 | ||
266 | static struct acpi_device_id sst_acpi_match[] = { | 266 | static const struct acpi_device_id sst_acpi_match[] = { |
267 | { "INT33C8", (unsigned long)&sst_acpi_haswell_desc }, | 267 | { "INT33C8", (unsigned long)&sst_acpi_haswell_desc }, |
268 | { "INT3438", (unsigned long)&sst_acpi_broadwell_desc }, | 268 | { "INT3438", (unsigned long)&sst_acpi_broadwell_desc }, |
269 | { "80860F28", (unsigned long)&sst_acpi_baytrail_desc }, | 269 | { "80860F28", (unsigned long)&sst_acpi_baytrail_desc }, |
diff --git a/sound/soc/intel/common/sst-ipc.c b/sound/soc/intel/common/sst-ipc.c index 4b62a553823c..a12c7bb08d3b 100644 --- a/sound/soc/intel/common/sst-ipc.c +++ b/sound/soc/intel/common/sst-ipc.c | |||
@@ -129,11 +129,31 @@ static int msg_empty_list_init(struct sst_generic_ipc *ipc) | |||
129 | return -ENOMEM; | 129 | return -ENOMEM; |
130 | 130 | ||
131 | for (i = 0; i < IPC_EMPTY_LIST_SIZE; i++) { | 131 | for (i = 0; i < IPC_EMPTY_LIST_SIZE; i++) { |
132 | ipc->msg[i].tx_data = kzalloc(ipc->tx_data_max_size, GFP_KERNEL); | ||
133 | if (ipc->msg[i].tx_data == NULL) | ||
134 | goto free_mem; | ||
135 | |||
136 | ipc->msg[i].rx_data = kzalloc(ipc->rx_data_max_size, GFP_KERNEL); | ||
137 | if (ipc->msg[i].rx_data == NULL) { | ||
138 | kfree(ipc->msg[i].tx_data); | ||
139 | goto free_mem; | ||
140 | } | ||
141 | |||
132 | init_waitqueue_head(&ipc->msg[i].waitq); | 142 | init_waitqueue_head(&ipc->msg[i].waitq); |
133 | list_add(&ipc->msg[i].list, &ipc->empty_list); | 143 | list_add(&ipc->msg[i].list, &ipc->empty_list); |
134 | } | 144 | } |
135 | 145 | ||
136 | return 0; | 146 | return 0; |
147 | |||
148 | free_mem: | ||
149 | while (i > 0) { | ||
150 | kfree(ipc->msg[i-1].tx_data); | ||
151 | kfree(ipc->msg[i-1].rx_data); | ||
152 | --i; | ||
153 | } | ||
154 | kfree(ipc->msg); | ||
155 | |||
156 | return -ENOMEM; | ||
137 | } | 157 | } |
138 | 158 | ||
139 | static void ipc_tx_msgs(struct kthread_work *work) | 159 | static void ipc_tx_msgs(struct kthread_work *work) |
@@ -142,7 +162,6 @@ static void ipc_tx_msgs(struct kthread_work *work) | |||
142 | container_of(work, struct sst_generic_ipc, kwork); | 162 | container_of(work, struct sst_generic_ipc, kwork); |
143 | struct ipc_message *msg; | 163 | struct ipc_message *msg; |
144 | unsigned long flags; | 164 | unsigned long flags; |
145 | u64 ipcx; | ||
146 | 165 | ||
147 | spin_lock_irqsave(&ipc->dsp->spinlock, flags); | 166 | spin_lock_irqsave(&ipc->dsp->spinlock, flags); |
148 | 167 | ||
@@ -153,8 +172,8 @@ static void ipc_tx_msgs(struct kthread_work *work) | |||
153 | 172 | ||
154 | /* if the DSP is busy, we will TX messages after IRQ. | 173 | /* if the DSP is busy, we will TX messages after IRQ. |
155 | * also postpone if we are in the middle of procesing completion irq*/ | 174 | * also postpone if we are in the middle of procesing completion irq*/ |
156 | ipcx = sst_dsp_shim_read_unlocked(ipc->dsp, SST_IPCX); | 175 | if (ipc->ops.is_dsp_busy && ipc->ops.is_dsp_busy(ipc->dsp)) { |
157 | if (ipcx & (SST_IPCX_BUSY | SST_IPCX_DONE)) { | 176 | dev_dbg(ipc->dev, "ipc_tx_msgs dsp busy\n"); |
158 | spin_unlock_irqrestore(&ipc->dsp->spinlock, flags); | 177 | spin_unlock_irqrestore(&ipc->dsp->spinlock, flags); |
159 | return; | 178 | return; |
160 | } | 179 | } |
@@ -280,11 +299,18 @@ EXPORT_SYMBOL_GPL(sst_ipc_init); | |||
280 | 299 | ||
281 | void sst_ipc_fini(struct sst_generic_ipc *ipc) | 300 | void sst_ipc_fini(struct sst_generic_ipc *ipc) |
282 | { | 301 | { |
302 | int i; | ||
303 | |||
283 | if (ipc->tx_thread) | 304 | if (ipc->tx_thread) |
284 | kthread_stop(ipc->tx_thread); | 305 | kthread_stop(ipc->tx_thread); |
285 | 306 | ||
286 | if (ipc->msg) | 307 | if (ipc->msg) { |
308 | for (i = 0; i < IPC_EMPTY_LIST_SIZE; i++) { | ||
309 | kfree(ipc->msg[i].tx_data); | ||
310 | kfree(ipc->msg[i].rx_data); | ||
311 | } | ||
287 | kfree(ipc->msg); | 312 | kfree(ipc->msg); |
313 | } | ||
288 | } | 314 | } |
289 | EXPORT_SYMBOL_GPL(sst_ipc_fini); | 315 | EXPORT_SYMBOL_GPL(sst_ipc_fini); |
290 | 316 | ||
diff --git a/sound/soc/intel/common/sst-ipc.h b/sound/soc/intel/common/sst-ipc.h index 125ea451a373..ceb7e468a3fa 100644 --- a/sound/soc/intel/common/sst-ipc.h +++ b/sound/soc/intel/common/sst-ipc.h | |||
@@ -32,9 +32,9 @@ struct ipc_message { | |||
32 | u64 header; | 32 | u64 header; |
33 | 33 | ||
34 | /* direction wrt host CPU */ | 34 | /* direction wrt host CPU */ |
35 | char tx_data[IPC_MAX_MAILBOX_BYTES]; | 35 | char *tx_data; |
36 | size_t tx_size; | 36 | size_t tx_size; |
37 | char rx_data[IPC_MAX_MAILBOX_BYTES]; | 37 | char *rx_data; |
38 | size_t rx_size; | 38 | size_t rx_size; |
39 | 39 | ||
40 | wait_queue_head_t waitq; | 40 | wait_queue_head_t waitq; |
@@ -51,6 +51,7 @@ struct sst_plat_ipc_ops { | |||
51 | void (*shim_dbg)(struct sst_generic_ipc *, const char *); | 51 | void (*shim_dbg)(struct sst_generic_ipc *, const char *); |
52 | void (*tx_data_copy)(struct ipc_message *, char *, size_t); | 52 | void (*tx_data_copy)(struct ipc_message *, char *, size_t); |
53 | u64 (*reply_msg_match)(u64 header, u64 *mask); | 53 | u64 (*reply_msg_match)(u64 header, u64 *mask); |
54 | bool (*is_dsp_busy)(struct sst_dsp *dsp); | ||
54 | }; | 55 | }; |
55 | 56 | ||
56 | /* SST generic IPC data */ | 57 | /* SST generic IPC data */ |
@@ -68,6 +69,8 @@ struct sst_generic_ipc { | |||
68 | struct kthread_work kwork; | 69 | struct kthread_work kwork; |
69 | bool pending; | 70 | bool pending; |
70 | struct ipc_message *msg; | 71 | struct ipc_message *msg; |
72 | int tx_data_max_size; | ||
73 | int rx_data_max_size; | ||
71 | 74 | ||
72 | struct sst_plat_ipc_ops ops; | 75 | struct sst_plat_ipc_ops ops; |
73 | }; | 76 | }; |
diff --git a/sound/soc/intel/haswell/sst-haswell-ipc.c b/sound/soc/intel/haswell/sst-haswell-ipc.c index 344a1e9bbce5..f95f271aab0c 100644 --- a/sound/soc/intel/haswell/sst-haswell-ipc.c +++ b/sound/soc/intel/haswell/sst-haswell-ipc.c | |||
@@ -2098,6 +2098,14 @@ static u64 hsw_reply_msg_match(u64 header, u64 *mask) | |||
2098 | return header; | 2098 | return header; |
2099 | } | 2099 | } |
2100 | 2100 | ||
2101 | static bool hsw_is_dsp_busy(struct sst_dsp *dsp) | ||
2102 | { | ||
2103 | u64 ipcx; | ||
2104 | |||
2105 | ipcx = sst_dsp_shim_read_unlocked(dsp, SST_IPCX); | ||
2106 | return (ipcx & (SST_IPCX_BUSY | SST_IPCX_DONE)); | ||
2107 | } | ||
2108 | |||
2101 | int sst_hsw_dsp_init(struct device *dev, struct sst_pdata *pdata) | 2109 | int sst_hsw_dsp_init(struct device *dev, struct sst_pdata *pdata) |
2102 | { | 2110 | { |
2103 | struct sst_hsw_ipc_fw_version version; | 2111 | struct sst_hsw_ipc_fw_version version; |
@@ -2117,6 +2125,10 @@ int sst_hsw_dsp_init(struct device *dev, struct sst_pdata *pdata) | |||
2117 | ipc->ops.shim_dbg = hsw_shim_dbg; | 2125 | ipc->ops.shim_dbg = hsw_shim_dbg; |
2118 | ipc->ops.tx_data_copy = hsw_tx_data_copy; | 2126 | ipc->ops.tx_data_copy = hsw_tx_data_copy; |
2119 | ipc->ops.reply_msg_match = hsw_reply_msg_match; | 2127 | ipc->ops.reply_msg_match = hsw_reply_msg_match; |
2128 | ipc->ops.is_dsp_busy = hsw_is_dsp_busy; | ||
2129 | |||
2130 | ipc->tx_data_max_size = IPC_MAX_MAILBOX_BYTES; | ||
2131 | ipc->rx_data_max_size = IPC_MAX_MAILBOX_BYTES; | ||
2120 | 2132 | ||
2121 | ret = sst_ipc_init(ipc); | 2133 | ret = sst_ipc_init(ipc); |
2122 | if (ret != 0) | 2134 | if (ret != 0) |
@@ -2201,7 +2213,6 @@ dma_err: | |||
2201 | dsp_new_err: | 2213 | dsp_new_err: |
2202 | sst_ipc_fini(ipc); | 2214 | sst_ipc_fini(ipc); |
2203 | ipc_init_err: | 2215 | ipc_init_err: |
2204 | kfree(hsw); | ||
2205 | return ret; | 2216 | return ret; |
2206 | } | 2217 | } |
2207 | EXPORT_SYMBOL_GPL(sst_hsw_dsp_init); | 2218 | EXPORT_SYMBOL_GPL(sst_hsw_dsp_init); |
diff --git a/sound/soc/intel/haswell/sst-haswell-pcm.c b/sound/soc/intel/haswell/sst-haswell-pcm.c index 23ae0400d6db..e593e7a4b7a7 100644 --- a/sound/soc/intel/haswell/sst-haswell-pcm.c +++ b/sound/soc/intel/haswell/sst-haswell-pcm.c | |||
@@ -928,10 +928,15 @@ static void hsw_pcm_free_modules(struct hsw_priv_data *pdata) | |||
928 | 928 | ||
929 | for (i = 0; i < ARRAY_SIZE(mod_map); i++) { | 929 | for (i = 0; i < ARRAY_SIZE(mod_map); i++) { |
930 | pcm_data = &pdata->pcm[mod_map[i].dai_id][mod_map[i].stream]; | 930 | pcm_data = &pdata->pcm[mod_map[i].dai_id][mod_map[i].stream]; |
931 | sst_hsw_runtime_module_free(pcm_data->runtime); | 931 | if (pcm_data->runtime){ |
932 | sst_hsw_runtime_module_free(pcm_data->runtime); | ||
933 | pcm_data->runtime = NULL; | ||
934 | } | ||
932 | } | 935 | } |
933 | if (sst_hsw_is_module_loaded(hsw, SST_HSW_MODULE_WAVES)) { | 936 | if (sst_hsw_is_module_loaded(hsw, SST_HSW_MODULE_WAVES) && |
937 | pdata->runtime_waves) { | ||
934 | sst_hsw_runtime_module_free(pdata->runtime_waves); | 938 | sst_hsw_runtime_module_free(pdata->runtime_waves); |
939 | pdata->runtime_waves = NULL; | ||
935 | } | 940 | } |
936 | } | 941 | } |
937 | 942 | ||
@@ -1204,6 +1209,20 @@ static int hsw_pcm_runtime_idle(struct device *dev) | |||
1204 | return 0; | 1209 | return 0; |
1205 | } | 1210 | } |
1206 | 1211 | ||
1212 | static int hsw_pcm_suspend(struct device *dev) | ||
1213 | { | ||
1214 | struct hsw_priv_data *pdata = dev_get_drvdata(dev); | ||
1215 | struct sst_hsw *hsw = pdata->hsw; | ||
1216 | |||
1217 | /* enter D3 state and stall */ | ||
1218 | sst_hsw_dsp_runtime_suspend(hsw); | ||
1219 | /* free all runtime modules */ | ||
1220 | hsw_pcm_free_modules(pdata); | ||
1221 | /* put the DSP to sleep, fw unloaded after runtime modules freed */ | ||
1222 | sst_hsw_dsp_runtime_sleep(hsw); | ||
1223 | return 0; | ||
1224 | } | ||
1225 | |||
1207 | static int hsw_pcm_runtime_suspend(struct device *dev) | 1226 | static int hsw_pcm_runtime_suspend(struct device *dev) |
1208 | { | 1227 | { |
1209 | struct hsw_priv_data *pdata = dev_get_drvdata(dev); | 1228 | struct hsw_priv_data *pdata = dev_get_drvdata(dev); |
@@ -1220,8 +1239,7 @@ static int hsw_pcm_runtime_suspend(struct device *dev) | |||
1220 | return ret; | 1239 | return ret; |
1221 | sst_hsw_set_module_enabled_rtd3(hsw, SST_HSW_MODULE_WAVES); | 1240 | sst_hsw_set_module_enabled_rtd3(hsw, SST_HSW_MODULE_WAVES); |
1222 | } | 1241 | } |
1223 | sst_hsw_dsp_runtime_suspend(hsw); | 1242 | hsw_pcm_suspend(dev); |
1224 | sst_hsw_dsp_runtime_sleep(hsw); | ||
1225 | pdata->pm_state = HSW_PM_STATE_RTD3; | 1243 | pdata->pm_state = HSW_PM_STATE_RTD3; |
1226 | 1244 | ||
1227 | return 0; | 1245 | return 0; |
@@ -1361,10 +1379,7 @@ static int hsw_pcm_prepare(struct device *dev) | |||
1361 | if (err < 0) | 1379 | if (err < 0) |
1362 | dev_err(dev, "failed to save context for PCM %d\n", i); | 1380 | dev_err(dev, "failed to save context for PCM %d\n", i); |
1363 | } | 1381 | } |
1364 | /* enter D3 state and stall */ | 1382 | hsw_pcm_suspend(dev); |
1365 | sst_hsw_dsp_runtime_suspend(hsw); | ||
1366 | /* put the DSP to sleep */ | ||
1367 | sst_hsw_dsp_runtime_sleep(hsw); | ||
1368 | } | 1383 | } |
1369 | 1384 | ||
1370 | snd_soc_suspend(pdata->soc_card->dev); | 1385 | snd_soc_suspend(pdata->soc_card->dev); |
diff --git a/sound/soc/mediatek/Kconfig b/sound/soc/mediatek/Kconfig new file mode 100644 index 000000000000..15c04e2eae34 --- /dev/null +++ b/sound/soc/mediatek/Kconfig | |||
@@ -0,0 +1,30 @@ | |||
1 | config SND_SOC_MEDIATEK | ||
2 | tristate "ASoC support for Mediatek chip" | ||
3 | depends on ARCH_MEDIATEK | ||
4 | help | ||
5 | This adds ASoC platform driver support for Mediatek chip | ||
6 | that can be used with other codecs. | ||
7 | Select Y if you have such device. | ||
8 | Ex: MT8173 | ||
9 | |||
10 | config SND_SOC_MT8173_MAX98090 | ||
11 | tristate "ASoC Audio driver for MT8173 with MAX98090 codec" | ||
12 | depends on SND_SOC_MEDIATEK | ||
13 | select SND_SOC_MAX98090 | ||
14 | help | ||
15 | This adds ASoC driver for Mediatek MT8173 boards | ||
16 | with the MAX98090 audio codec. | ||
17 | Select Y if you have such device. | ||
18 | If unsure select "N". | ||
19 | |||
20 | config SND_SOC_MT8173_RT5650_RT5676 | ||
21 | tristate "ASoC Audio driver for MT8173 with RT5650 RT5676 codecs" | ||
22 | depends on SND_SOC_MEDIATEK | ||
23 | select SND_SOC_RT5645 | ||
24 | select SND_SOC_RT5677 | ||
25 | help | ||
26 | This adds ASoC driver for Mediatek MT8173 boards | ||
27 | with the RT5650 and RT5676 codecs. | ||
28 | Select Y if you have such device. | ||
29 | If unsure select "N". | ||
30 | |||
diff --git a/sound/soc/mediatek/Makefile b/sound/soc/mediatek/Makefile new file mode 100644 index 000000000000..75effbec438d --- /dev/null +++ b/sound/soc/mediatek/Makefile | |||
@@ -0,0 +1,5 @@ | |||
1 | # MTK Platform Support | ||
2 | obj-$(CONFIG_SND_SOC_MEDIATEK) += mtk-afe-pcm.o | ||
3 | # Machine support | ||
4 | obj-$(CONFIG_SND_SOC_MT8173_MAX98090) += mt8173-max98090.o | ||
5 | obj-$(CONFIG_SND_SOC_MT8173_RT5650_RT5676) += mt8173-rt5650-rt5676.o | ||
diff --git a/sound/soc/mediatek/mt8173-max98090.c b/sound/soc/mediatek/mt8173-max98090.c new file mode 100644 index 000000000000..4d44b5803e55 --- /dev/null +++ b/sound/soc/mediatek/mt8173-max98090.c | |||
@@ -0,0 +1,213 @@ | |||
1 | /* | ||
2 | * mt8173-max98090.c -- MT8173 MAX98090 ALSA SoC machine driver | ||
3 | * | ||
4 | * Copyright (c) 2015 MediaTek Inc. | ||
5 | * Author: Koro Chen <koro.chen@mediatek.com> | ||
6 | * | ||
7 | * This program is free software; you can redistribute it and/or modify | ||
8 | * it under the terms of the GNU General Public License version 2 and | ||
9 | * only version 2 as published by the Free Software Foundation. | ||
10 | * | ||
11 | * This program is distributed in the hope that it will be useful, | ||
12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
14 | * GNU General Public License for more details. | ||
15 | */ | ||
16 | |||
17 | #include <linux/module.h> | ||
18 | #include <sound/soc.h> | ||
19 | #include <sound/jack.h> | ||
20 | #include <linux/gpio.h> | ||
21 | #include "../codecs/max98090.h" | ||
22 | |||
23 | static struct snd_soc_jack mt8173_max98090_jack; | ||
24 | |||
25 | static struct snd_soc_jack_pin mt8173_max98090_jack_pins[] = { | ||
26 | { | ||
27 | .pin = "Headphone", | ||
28 | .mask = SND_JACK_HEADPHONE, | ||
29 | }, | ||
30 | { | ||
31 | .pin = "Headset Mic", | ||
32 | .mask = SND_JACK_MICROPHONE, | ||
33 | }, | ||
34 | }; | ||
35 | |||
36 | static const struct snd_soc_dapm_widget mt8173_max98090_widgets[] = { | ||
37 | SND_SOC_DAPM_SPK("Speaker", NULL), | ||
38 | SND_SOC_DAPM_MIC("Int Mic", NULL), | ||
39 | SND_SOC_DAPM_HP("Headphone", NULL), | ||
40 | SND_SOC_DAPM_MIC("Headset Mic", NULL), | ||
41 | }; | ||
42 | |||
43 | static const struct snd_soc_dapm_route mt8173_max98090_routes[] = { | ||
44 | {"Speaker", NULL, "SPKL"}, | ||
45 | {"Speaker", NULL, "SPKR"}, | ||
46 | {"DMICL", NULL, "Int Mic"}, | ||
47 | {"Headphone", NULL, "HPL"}, | ||
48 | {"Headphone", NULL, "HPR"}, | ||
49 | {"Headset Mic", NULL, "MICBIAS"}, | ||
50 | {"IN34", NULL, "Headset Mic"}, | ||
51 | }; | ||
52 | |||
53 | static const struct snd_kcontrol_new mt8173_max98090_controls[] = { | ||
54 | SOC_DAPM_PIN_SWITCH("Speaker"), | ||
55 | SOC_DAPM_PIN_SWITCH("Int Mic"), | ||
56 | SOC_DAPM_PIN_SWITCH("Headphone"), | ||
57 | SOC_DAPM_PIN_SWITCH("Headset Mic"), | ||
58 | }; | ||
59 | |||
60 | static int mt8173_max98090_hw_params(struct snd_pcm_substream *substream, | ||
61 | struct snd_pcm_hw_params *params) | ||
62 | { | ||
63 | struct snd_soc_pcm_runtime *rtd = substream->private_data; | ||
64 | struct snd_soc_dai *codec_dai = rtd->codec_dai; | ||
65 | |||
66 | return snd_soc_dai_set_sysclk(codec_dai, 0, params_rate(params) * 256, | ||
67 | SND_SOC_CLOCK_IN); | ||
68 | } | ||
69 | |||
70 | static struct snd_soc_ops mt8173_max98090_ops = { | ||
71 | .hw_params = mt8173_max98090_hw_params, | ||
72 | }; | ||
73 | |||
74 | static int mt8173_max98090_init(struct snd_soc_pcm_runtime *runtime) | ||
75 | { | ||
76 | int ret; | ||
77 | struct snd_soc_card *card = runtime->card; | ||
78 | struct snd_soc_codec *codec = runtime->codec; | ||
79 | |||
80 | /* enable jack detection */ | ||
81 | ret = snd_soc_card_jack_new(card, "Headphone", SND_JACK_HEADPHONE, | ||
82 | &mt8173_max98090_jack, NULL, 0); | ||
83 | if (ret) { | ||
84 | dev_err(card->dev, "Can't snd_soc_jack_new %d\n", ret); | ||
85 | return ret; | ||
86 | } | ||
87 | |||
88 | ret = snd_soc_jack_add_pins(&mt8173_max98090_jack, | ||
89 | ARRAY_SIZE(mt8173_max98090_jack_pins), | ||
90 | mt8173_max98090_jack_pins); | ||
91 | if (ret) { | ||
92 | dev_err(card->dev, "Can't snd_soc_jack_add_pins %d\n", ret); | ||
93 | return ret; | ||
94 | } | ||
95 | |||
96 | return max98090_mic_detect(codec, &mt8173_max98090_jack); | ||
97 | } | ||
98 | |||
99 | /* Digital audio interface glue - connects codec <---> CPU */ | ||
100 | static struct snd_soc_dai_link mt8173_max98090_dais[] = { | ||
101 | /* Front End DAI links */ | ||
102 | { | ||
103 | .name = "MAX98090 Playback", | ||
104 | .stream_name = "MAX98090 Playback", | ||
105 | .cpu_dai_name = "DL1", | ||
106 | .platform_name = "11220000.mt8173-afe-pcm", | ||
107 | .codec_name = "snd-soc-dummy", | ||
108 | .codec_dai_name = "snd-soc-dummy-dai", | ||
109 | .trigger = {SND_SOC_DPCM_TRIGGER_POST, SND_SOC_DPCM_TRIGGER_POST}, | ||
110 | .dynamic = 1, | ||
111 | .dpcm_playback = 1, | ||
112 | }, | ||
113 | { | ||
114 | .name = "MAX98090 Capture", | ||
115 | .stream_name = "MAX98090 Capture", | ||
116 | .cpu_dai_name = "VUL", | ||
117 | .platform_name = "11220000.mt8173-afe-pcm", | ||
118 | .codec_name = "snd-soc-dummy", | ||
119 | .codec_dai_name = "snd-soc-dummy-dai", | ||
120 | .trigger = {SND_SOC_DPCM_TRIGGER_POST, SND_SOC_DPCM_TRIGGER_POST}, | ||
121 | .dynamic = 1, | ||
122 | .dpcm_capture = 1, | ||
123 | }, | ||
124 | /* Back End DAI links */ | ||
125 | { | ||
126 | .name = "Codec", | ||
127 | .cpu_dai_name = "I2S", | ||
128 | .platform_name = "11220000.mt8173-afe-pcm", | ||
129 | .no_pcm = 1, | ||
130 | .codec_dai_name = "HiFi", | ||
131 | .init = mt8173_max98090_init, | ||
132 | .ops = &mt8173_max98090_ops, | ||
133 | .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF | | ||
134 | SND_SOC_DAIFMT_CBS_CFS, | ||
135 | .dpcm_playback = 1, | ||
136 | .dpcm_capture = 1, | ||
137 | }, | ||
138 | }; | ||
139 | |||
140 | static struct snd_soc_card mt8173_max98090_card = { | ||
141 | .name = "mt8173-max98090", | ||
142 | .dai_link = mt8173_max98090_dais, | ||
143 | .num_links = ARRAY_SIZE(mt8173_max98090_dais), | ||
144 | .controls = mt8173_max98090_controls, | ||
145 | .num_controls = ARRAY_SIZE(mt8173_max98090_controls), | ||
146 | .dapm_widgets = mt8173_max98090_widgets, | ||
147 | .num_dapm_widgets = ARRAY_SIZE(mt8173_max98090_widgets), | ||
148 | .dapm_routes = mt8173_max98090_routes, | ||
149 | .num_dapm_routes = ARRAY_SIZE(mt8173_max98090_routes), | ||
150 | }; | ||
151 | |||
152 | static int mt8173_max98090_dev_probe(struct platform_device *pdev) | ||
153 | { | ||
154 | struct snd_soc_card *card = &mt8173_max98090_card; | ||
155 | struct device_node *codec_node; | ||
156 | int ret, i; | ||
157 | |||
158 | codec_node = of_parse_phandle(pdev->dev.of_node, | ||
159 | "mediatek,audio-codec", 0); | ||
160 | if (!codec_node) { | ||
161 | dev_err(&pdev->dev, | ||
162 | "Property 'audio-codec' missing or invalid\n"); | ||
163 | return -EINVAL; | ||
164 | } | ||
165 | for (i = 0; i < card->num_links; i++) { | ||
166 | if (mt8173_max98090_dais[i].codec_name) | ||
167 | continue; | ||
168 | mt8173_max98090_dais[i].codec_of_node = codec_node; | ||
169 | } | ||
170 | card->dev = &pdev->dev; | ||
171 | |||
172 | ret = snd_soc_register_card(card); | ||
173 | if (ret) | ||
174 | dev_err(&pdev->dev, "%s snd_soc_register_card fail %d\n", | ||
175 | __func__, ret); | ||
176 | return ret; | ||
177 | } | ||
178 | |||
179 | static int mt8173_max98090_dev_remove(struct platform_device *pdev) | ||
180 | { | ||
181 | struct snd_soc_card *card = platform_get_drvdata(pdev); | ||
182 | |||
183 | snd_soc_unregister_card(card); | ||
184 | return 0; | ||
185 | } | ||
186 | |||
187 | static const struct of_device_id mt8173_max98090_dt_match[] = { | ||
188 | { .compatible = "mediatek,mt8173-max98090", }, | ||
189 | { } | ||
190 | }; | ||
191 | MODULE_DEVICE_TABLE(of, mt8173_max98090_dt_match); | ||
192 | |||
193 | static struct platform_driver mt8173_max98090_driver = { | ||
194 | .driver = { | ||
195 | .name = "mt8173-max98090", | ||
196 | .owner = THIS_MODULE, | ||
197 | .of_match_table = mt8173_max98090_dt_match, | ||
198 | #ifdef CONFIG_PM | ||
199 | .pm = &snd_soc_pm_ops, | ||
200 | #endif | ||
201 | }, | ||
202 | .probe = mt8173_max98090_dev_probe, | ||
203 | .remove = mt8173_max98090_dev_remove, | ||
204 | }; | ||
205 | |||
206 | module_platform_driver(mt8173_max98090_driver); | ||
207 | |||
208 | /* Module information */ | ||
209 | MODULE_DESCRIPTION("MT8173 MAX98090 ALSA SoC machine driver"); | ||
210 | MODULE_AUTHOR("Koro Chen <koro.chen@mediatek.com>"); | ||
211 | MODULE_LICENSE("GPL v2"); | ||
212 | MODULE_ALIAS("platform:mt8173-max98090"); | ||
213 | |||
diff --git a/sound/soc/mediatek/mt8173-rt5650-rt5676.c b/sound/soc/mediatek/mt8173-rt5650-rt5676.c new file mode 100644 index 000000000000..094055323059 --- /dev/null +++ b/sound/soc/mediatek/mt8173-rt5650-rt5676.c | |||
@@ -0,0 +1,278 @@ | |||
1 | /* | ||
2 | * mt8173-rt5650-rt5676.c -- MT8173 machine driver with RT5650/5676 codecs | ||
3 | * | ||
4 | * Copyright (c) 2015 MediaTek Inc. | ||
5 | * Author: Koro Chen <koro.chen@mediatek.com> | ||
6 | * | ||
7 | * This program is free software; you can redistribute it and/or modify | ||
8 | * it under the terms of the GNU General Public License version 2 and | ||
9 | * only version 2 as published by the Free Software Foundation. | ||
10 | * | ||
11 | * This program is distributed in the hope that it will be useful, | ||
12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
14 | * GNU General Public License for more details. | ||
15 | */ | ||
16 | |||
17 | #include <linux/module.h> | ||
18 | #include <linux/gpio.h> | ||
19 | #include <linux/of_gpio.h> | ||
20 | #include <sound/soc.h> | ||
21 | #include <sound/jack.h> | ||
22 | #include "../codecs/rt5645.h" | ||
23 | #include "../codecs/rt5677.h" | ||
24 | |||
25 | #define MCLK_FOR_CODECS 12288000 | ||
26 | |||
27 | static const struct snd_soc_dapm_widget mt8173_rt5650_rt5676_widgets[] = { | ||
28 | SND_SOC_DAPM_SPK("Speaker", NULL), | ||
29 | SND_SOC_DAPM_MIC("Int Mic", NULL), | ||
30 | SND_SOC_DAPM_HP("Headphone", NULL), | ||
31 | SND_SOC_DAPM_MIC("Headset Mic", NULL), | ||
32 | }; | ||
33 | |||
34 | static const struct snd_soc_dapm_route mt8173_rt5650_rt5676_routes[] = { | ||
35 | {"Speaker", NULL, "SPOL"}, | ||
36 | {"Speaker", NULL, "SPOR"}, | ||
37 | {"Speaker", NULL, "Sub AIF2TX"}, /* IF2 ADC to 5650 */ | ||
38 | {"Sub DMIC L1", NULL, "Int Mic"}, /* DMIC from 5676 */ | ||
39 | {"Sub DMIC R1", NULL, "Int Mic"}, | ||
40 | {"Headphone", NULL, "HPOL"}, | ||
41 | {"Headphone", NULL, "HPOR"}, | ||
42 | {"Headphone", NULL, "Sub AIF2TX"}, /* IF2 ADC to 5650 */ | ||
43 | {"Headset Mic", NULL, "micbias1"}, | ||
44 | {"Headset Mic", NULL, "micbias2"}, | ||
45 | {"IN1P", NULL, "Headset Mic"}, | ||
46 | {"IN1N", NULL, "Headset Mic"}, | ||
47 | {"Sub AIF2RX", NULL, "Headset Mic"}, /* IF2 DAC from 5650 */ | ||
48 | }; | ||
49 | |||
50 | static const struct snd_kcontrol_new mt8173_rt5650_rt5676_controls[] = { | ||
51 | SOC_DAPM_PIN_SWITCH("Speaker"), | ||
52 | SOC_DAPM_PIN_SWITCH("Int Mic"), | ||
53 | SOC_DAPM_PIN_SWITCH("Headphone"), | ||
54 | SOC_DAPM_PIN_SWITCH("Headset Mic"), | ||
55 | }; | ||
56 | |||
57 | static int mt8173_rt5650_rt5676_hw_params(struct snd_pcm_substream *substream, | ||
58 | struct snd_pcm_hw_params *params) | ||
59 | { | ||
60 | struct snd_soc_pcm_runtime *rtd = substream->private_data; | ||
61 | int i, ret; | ||
62 | |||
63 | for (i = 0; i < rtd->num_codecs; i++) { | ||
64 | struct snd_soc_dai *codec_dai = rtd->codec_dais[i]; | ||
65 | |||
66 | /* pll from mclk 12.288M */ | ||
67 | ret = snd_soc_dai_set_pll(codec_dai, 0, 0, MCLK_FOR_CODECS, | ||
68 | params_rate(params) * 512); | ||
69 | if (ret) | ||
70 | return ret; | ||
71 | |||
72 | /* sysclk from pll */ | ||
73 | ret = snd_soc_dai_set_sysclk(codec_dai, 1, | ||
74 | params_rate(params) * 512, | ||
75 | SND_SOC_CLOCK_IN); | ||
76 | if (ret) | ||
77 | return ret; | ||
78 | } | ||
79 | return 0; | ||
80 | } | ||
81 | |||
82 | static struct snd_soc_ops mt8173_rt5650_rt5676_ops = { | ||
83 | .hw_params = mt8173_rt5650_rt5676_hw_params, | ||
84 | }; | ||
85 | |||
86 | static struct snd_soc_jack mt8173_rt5650_rt5676_jack; | ||
87 | |||
88 | static int mt8173_rt5650_rt5676_init(struct snd_soc_pcm_runtime *runtime) | ||
89 | { | ||
90 | struct snd_soc_card *card = runtime->card; | ||
91 | struct snd_soc_codec *codec = runtime->codec_dais[0]->codec; | ||
92 | struct snd_soc_codec *codec_sub = runtime->codec_dais[1]->codec; | ||
93 | int ret; | ||
94 | |||
95 | rt5645_sel_asrc_clk_src(codec, | ||
96 | RT5645_DA_STEREO_FILTER | | ||
97 | RT5645_AD_STEREO_FILTER, | ||
98 | RT5645_CLK_SEL_I2S1_ASRC); | ||
99 | rt5677_sel_asrc_clk_src(codec_sub, | ||
100 | RT5677_DA_STEREO_FILTER | | ||
101 | RT5677_AD_STEREO1_FILTER, | ||
102 | RT5677_CLK_SEL_I2S1_ASRC); | ||
103 | rt5677_sel_asrc_clk_src(codec_sub, | ||
104 | RT5677_AD_STEREO2_FILTER | | ||
105 | RT5677_I2S2_SOURCE, | ||
106 | RT5677_CLK_SEL_I2S2_ASRC); | ||
107 | |||
108 | /* enable jack detection */ | ||
109 | ret = snd_soc_card_jack_new(card, "Headset Jack", | ||
110 | SND_JACK_HEADPHONE | SND_JACK_MICROPHONE | | ||
111 | SND_JACK_BTN_0 | SND_JACK_BTN_1 | | ||
112 | SND_JACK_BTN_2 | SND_JACK_BTN_3, | ||
113 | &mt8173_rt5650_rt5676_jack, NULL, 0); | ||
114 | if (ret) { | ||
115 | dev_err(card->dev, "Can't new Headset Jack %d\n", ret); | ||
116 | return ret; | ||
117 | } | ||
118 | |||
119 | return rt5645_set_jack_detect(codec, | ||
120 | &mt8173_rt5650_rt5676_jack, | ||
121 | &mt8173_rt5650_rt5676_jack, | ||
122 | &mt8173_rt5650_rt5676_jack); | ||
123 | } | ||
124 | |||
125 | static struct snd_soc_dai_link_component mt8173_rt5650_rt5676_codecs[] = { | ||
126 | { | ||
127 | .dai_name = "rt5645-aif1", | ||
128 | }, | ||
129 | { | ||
130 | .dai_name = "rt5677-aif1", | ||
131 | }, | ||
132 | }; | ||
133 | |||
134 | /* Digital audio interface glue - connects codec <---> CPU */ | ||
135 | static struct snd_soc_dai_link mt8173_rt5650_rt5676_dais[] = { | ||
136 | /* Front End DAI links */ | ||
137 | { | ||
138 | .name = "rt5650_rt5676 Playback", | ||
139 | .stream_name = "rt5650_rt5676 Playback", | ||
140 | .cpu_dai_name = "DL1", | ||
141 | .platform_name = "11220000.mt8173-afe-pcm", | ||
142 | .codec_name = "snd-soc-dummy", | ||
143 | .codec_dai_name = "snd-soc-dummy-dai", | ||
144 | .trigger = {SND_SOC_DPCM_TRIGGER_POST, SND_SOC_DPCM_TRIGGER_POST}, | ||
145 | .dynamic = 1, | ||
146 | .dpcm_playback = 1, | ||
147 | }, | ||
148 | { | ||
149 | .name = "rt5650_rt5676 Capture", | ||
150 | .stream_name = "rt5650_rt5676 Capture", | ||
151 | .cpu_dai_name = "VUL", | ||
152 | .platform_name = "11220000.mt8173-afe-pcm", | ||
153 | .codec_name = "snd-soc-dummy", | ||
154 | .codec_dai_name = "snd-soc-dummy-dai", | ||
155 | .trigger = {SND_SOC_DPCM_TRIGGER_POST, SND_SOC_DPCM_TRIGGER_POST}, | ||
156 | .dynamic = 1, | ||
157 | .dpcm_capture = 1, | ||
158 | }, | ||
159 | |||
160 | /* Back End DAI links */ | ||
161 | { | ||
162 | .name = "Codec", | ||
163 | .cpu_dai_name = "I2S", | ||
164 | .platform_name = "11220000.mt8173-afe-pcm", | ||
165 | .no_pcm = 1, | ||
166 | .codecs = mt8173_rt5650_rt5676_codecs, | ||
167 | .num_codecs = 2, | ||
168 | .init = mt8173_rt5650_rt5676_init, | ||
169 | .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF | | ||
170 | SND_SOC_DAIFMT_CBS_CFS, | ||
171 | .ops = &mt8173_rt5650_rt5676_ops, | ||
172 | .ignore_pmdown_time = 1, | ||
173 | .dpcm_playback = 1, | ||
174 | .dpcm_capture = 1, | ||
175 | }, | ||
176 | { /* rt5676 <-> rt5650 intercodec link: Sets rt5676 I2S2 as master */ | ||
177 | .name = "rt5650_rt5676 intercodec", | ||
178 | .stream_name = "rt5650_rt5676 intercodec", | ||
179 | .cpu_dai_name = "snd-soc-dummy-dai", | ||
180 | .platform_name = "snd-soc-dummy", | ||
181 | .no_pcm = 1, | ||
182 | .codec_dai_name = "rt5677-aif2", | ||
183 | .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF | | ||
184 | SND_SOC_DAIFMT_CBM_CFM, | ||
185 | }, | ||
186 | |||
187 | }; | ||
188 | |||
189 | static struct snd_soc_codec_conf mt8173_rt5650_rt5676_codec_conf[] = { | ||
190 | { | ||
191 | .name_prefix = "Sub", | ||
192 | }, | ||
193 | }; | ||
194 | |||
195 | static struct snd_soc_card mt8173_rt5650_rt5676_card = { | ||
196 | .name = "mtk-rt5650-rt5676", | ||
197 | .dai_link = mt8173_rt5650_rt5676_dais, | ||
198 | .num_links = ARRAY_SIZE(mt8173_rt5650_rt5676_dais), | ||
199 | .codec_conf = mt8173_rt5650_rt5676_codec_conf, | ||
200 | .num_configs = ARRAY_SIZE(mt8173_rt5650_rt5676_codec_conf), | ||
201 | .controls = mt8173_rt5650_rt5676_controls, | ||
202 | .num_controls = ARRAY_SIZE(mt8173_rt5650_rt5676_controls), | ||
203 | .dapm_widgets = mt8173_rt5650_rt5676_widgets, | ||
204 | .num_dapm_widgets = ARRAY_SIZE(mt8173_rt5650_rt5676_widgets), | ||
205 | .dapm_routes = mt8173_rt5650_rt5676_routes, | ||
206 | .num_dapm_routes = ARRAY_SIZE(mt8173_rt5650_rt5676_routes), | ||
207 | }; | ||
208 | |||
209 | static int mt8173_rt5650_rt5676_dev_probe(struct platform_device *pdev) | ||
210 | { | ||
211 | struct snd_soc_card *card = &mt8173_rt5650_rt5676_card; | ||
212 | int ret; | ||
213 | |||
214 | mt8173_rt5650_rt5676_codecs[0].of_node = | ||
215 | of_parse_phandle(pdev->dev.of_node, "mediatek,audio-codec", 0); | ||
216 | if (!mt8173_rt5650_rt5676_codecs[0].of_node) { | ||
217 | dev_err(&pdev->dev, | ||
218 | "Property 'audio-codec' missing or invalid\n"); | ||
219 | return -EINVAL; | ||
220 | } | ||
221 | mt8173_rt5650_rt5676_codecs[1].of_node = | ||
222 | of_parse_phandle(pdev->dev.of_node, "mediatek,audio-codec", 1); | ||
223 | if (!mt8173_rt5650_rt5676_codecs[1].of_node) { | ||
224 | dev_err(&pdev->dev, | ||
225 | "Property 'audio-codec' missing or invalid\n"); | ||
226 | return -EINVAL; | ||
227 | } | ||
228 | mt8173_rt5650_rt5676_codec_conf[0].of_node = | ||
229 | mt8173_rt5650_rt5676_codecs[1].of_node; | ||
230 | |||
231 | mt8173_rt5650_rt5676_dais[3].codec_of_node = | ||
232 | mt8173_rt5650_rt5676_codecs[1].of_node; | ||
233 | |||
234 | card->dev = &pdev->dev; | ||
235 | platform_set_drvdata(pdev, card); | ||
236 | |||
237 | ret = snd_soc_register_card(card); | ||
238 | if (ret) | ||
239 | dev_err(&pdev->dev, "%s snd_soc_register_card fail %d\n", | ||
240 | __func__, ret); | ||
241 | return ret; | ||
242 | } | ||
243 | |||
244 | static int mt8173_rt5650_rt5676_dev_remove(struct platform_device *pdev) | ||
245 | { | ||
246 | struct snd_soc_card *card = platform_get_drvdata(pdev); | ||
247 | |||
248 | snd_soc_unregister_card(card); | ||
249 | return 0; | ||
250 | } | ||
251 | |||
252 | static const struct of_device_id mt8173_rt5650_rt5676_dt_match[] = { | ||
253 | { .compatible = "mediatek,mt8173-rt5650-rt5676", }, | ||
254 | { } | ||
255 | }; | ||
256 | MODULE_DEVICE_TABLE(of, mt8173_rt5650_rt5676_dt_match); | ||
257 | |||
258 | static struct platform_driver mt8173_rt5650_rt5676_driver = { | ||
259 | .driver = { | ||
260 | .name = "mtk-rt5650-rt5676", | ||
261 | .owner = THIS_MODULE, | ||
262 | .of_match_table = mt8173_rt5650_rt5676_dt_match, | ||
263 | #ifdef CONFIG_PM | ||
264 | .pm = &snd_soc_pm_ops, | ||
265 | #endif | ||
266 | }, | ||
267 | .probe = mt8173_rt5650_rt5676_dev_probe, | ||
268 | .remove = mt8173_rt5650_rt5676_dev_remove, | ||
269 | }; | ||
270 | |||
271 | module_platform_driver(mt8173_rt5650_rt5676_driver); | ||
272 | |||
273 | /* Module information */ | ||
274 | MODULE_DESCRIPTION("MT8173 RT5650 and RT5676 SoC machine driver"); | ||
275 | MODULE_AUTHOR("Koro Chen <koro.chen@mediatek.com>"); | ||
276 | MODULE_LICENSE("GPL v2"); | ||
277 | MODULE_ALIAS("platform:mtk-rt5650-rt5676"); | ||
278 | |||
diff --git a/sound/soc/mediatek/mtk-afe-common.h b/sound/soc/mediatek/mtk-afe-common.h new file mode 100644 index 000000000000..a88b17511fdf --- /dev/null +++ b/sound/soc/mediatek/mtk-afe-common.h | |||
@@ -0,0 +1,109 @@ | |||
1 | /* | ||
2 | * mtk_afe_common.h -- Mediatek audio driver common definitions | ||
3 | * | ||
4 | * Copyright (c) 2015 MediaTek Inc. | ||
5 | * Author: Koro Chen <koro.chen@mediatek.com> | ||
6 | * Sascha Hauer <s.hauer@pengutronix.de> | ||
7 | * Hidalgo Huang <hidalgo.huang@mediatek.com> | ||
8 | * Ir Lian <ir.lian@mediatek.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 and | ||
12 | * only version 2 as published by the Free Software Foundation. | ||
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 | |||
20 | #ifndef _MTK_AFE_COMMON_H_ | ||
21 | #define _MTK_AFE_COMMON_H_ | ||
22 | |||
23 | #include <linux/clk.h> | ||
24 | #include <linux/regmap.h> | ||
25 | |||
26 | enum { | ||
27 | MTK_AFE_MEMIF_DL1, | ||
28 | MTK_AFE_MEMIF_DL2, | ||
29 | MTK_AFE_MEMIF_VUL, | ||
30 | MTK_AFE_MEMIF_DAI, | ||
31 | MTK_AFE_MEMIF_AWB, | ||
32 | MTK_AFE_MEMIF_MOD_DAI, | ||
33 | MTK_AFE_MEMIF_HDMI, | ||
34 | MTK_AFE_MEMIF_NUM, | ||
35 | MTK_AFE_IO_MOD_PCM1 = MTK_AFE_MEMIF_NUM, | ||
36 | MTK_AFE_IO_MOD_PCM2, | ||
37 | MTK_AFE_IO_PMIC, | ||
38 | MTK_AFE_IO_I2S, | ||
39 | MTK_AFE_IO_2ND_I2S, | ||
40 | MTK_AFE_IO_HW_GAIN1, | ||
41 | MTK_AFE_IO_HW_GAIN2, | ||
42 | MTK_AFE_IO_MRG_O, | ||
43 | MTK_AFE_IO_MRG_I, | ||
44 | MTK_AFE_IO_DAIBT, | ||
45 | MTK_AFE_IO_HDMI, | ||
46 | }; | ||
47 | |||
48 | enum { | ||
49 | MTK_AFE_IRQ_1, | ||
50 | MTK_AFE_IRQ_2, | ||
51 | MTK_AFE_IRQ_3, | ||
52 | MTK_AFE_IRQ_4, | ||
53 | MTK_AFE_IRQ_5, | ||
54 | MTK_AFE_IRQ_6, | ||
55 | MTK_AFE_IRQ_7, | ||
56 | MTK_AFE_IRQ_8, | ||
57 | MTK_AFE_IRQ_NUM, | ||
58 | }; | ||
59 | |||
60 | enum { | ||
61 | MTK_CLK_INFRASYS_AUD, | ||
62 | MTK_CLK_TOP_PDN_AUD, | ||
63 | MTK_CLK_TOP_PDN_AUD_BUS, | ||
64 | MTK_CLK_I2S0_M, | ||
65 | MTK_CLK_I2S1_M, | ||
66 | MTK_CLK_I2S2_M, | ||
67 | MTK_CLK_I2S3_M, | ||
68 | MTK_CLK_I2S3_B, | ||
69 | MTK_CLK_BCK0, | ||
70 | MTK_CLK_BCK1, | ||
71 | MTK_CLK_NUM | ||
72 | }; | ||
73 | |||
74 | struct mtk_afe; | ||
75 | struct snd_pcm_substream; | ||
76 | |||
77 | struct mtk_afe_memif_data { | ||
78 | int id; | ||
79 | const char *name; | ||
80 | int reg_ofs_base; | ||
81 | int reg_ofs_cur; | ||
82 | int fs_shift; | ||
83 | int mono_shift; | ||
84 | int enable_shift; | ||
85 | int irq_reg_cnt; | ||
86 | int irq_cnt_shift; | ||
87 | int irq_en_shift; | ||
88 | int irq_fs_shift; | ||
89 | int irq_clr_shift; | ||
90 | }; | ||
91 | |||
92 | struct mtk_afe_memif { | ||
93 | unsigned int phys_buf_addr; | ||
94 | int buffer_size; | ||
95 | unsigned int hw_ptr; /* Previous IRQ's HW ptr */ | ||
96 | struct snd_pcm_substream *substream; | ||
97 | const struct mtk_afe_memif_data *data; | ||
98 | const struct mtk_afe_irq_data *irqdata; | ||
99 | }; | ||
100 | |||
101 | struct mtk_afe { | ||
102 | /* address for ioremap audio hardware register */ | ||
103 | void __iomem *base_addr; | ||
104 | struct device *dev; | ||
105 | struct regmap *regmap; | ||
106 | struct mtk_afe_memif memif[MTK_AFE_MEMIF_NUM]; | ||
107 | struct clk *clocks[MTK_CLK_NUM]; | ||
108 | }; | ||
109 | #endif | ||
diff --git a/sound/soc/mediatek/mtk-afe-pcm.c b/sound/soc/mediatek/mtk-afe-pcm.c new file mode 100644 index 000000000000..cc228db5fb76 --- /dev/null +++ b/sound/soc/mediatek/mtk-afe-pcm.c | |||
@@ -0,0 +1,1233 @@ | |||
1 | /* | ||
2 | * Mediatek ALSA SoC AFE platform driver | ||
3 | * | ||
4 | * Copyright (c) 2015 MediaTek Inc. | ||
5 | * Author: Koro Chen <koro.chen@mediatek.com> | ||
6 | * Sascha Hauer <s.hauer@pengutronix.de> | ||
7 | * Hidalgo Huang <hidalgo.huang@mediatek.com> | ||
8 | * Ir Lian <ir.lian@mediatek.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 and | ||
12 | * only version 2 as published by the Free Software Foundation. | ||
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 | |||
20 | #include <linux/delay.h> | ||
21 | #include <linux/module.h> | ||
22 | #include <linux/of.h> | ||
23 | #include <linux/of_address.h> | ||
24 | #include <linux/pm_runtime.h> | ||
25 | #include <sound/soc.h> | ||
26 | #include "mtk-afe-common.h" | ||
27 | |||
28 | /***************************************************************************** | ||
29 | * R E G I S T E R D E F I N I T I O N | ||
30 | *****************************************************************************/ | ||
31 | #define AUDIO_TOP_CON0 0x0000 | ||
32 | #define AUDIO_TOP_CON1 0x0004 | ||
33 | #define AFE_DAC_CON0 0x0010 | ||
34 | #define AFE_DAC_CON1 0x0014 | ||
35 | #define AFE_I2S_CON1 0x0034 | ||
36 | #define AFE_I2S_CON2 0x0038 | ||
37 | #define AFE_CONN_24BIT 0x006c | ||
38 | |||
39 | #define AFE_CONN1 0x0024 | ||
40 | #define AFE_CONN2 0x0028 | ||
41 | #define AFE_CONN7 0x0460 | ||
42 | #define AFE_CONN8 0x0464 | ||
43 | #define AFE_HDMI_CONN0 0x0390 | ||
44 | |||
45 | /* Memory interface */ | ||
46 | #define AFE_DL1_BASE 0x0040 | ||
47 | #define AFE_DL1_CUR 0x0044 | ||
48 | #define AFE_DL2_BASE 0x0050 | ||
49 | #define AFE_DL2_CUR 0x0054 | ||
50 | #define AFE_AWB_BASE 0x0070 | ||
51 | #define AFE_AWB_CUR 0x007c | ||
52 | #define AFE_VUL_BASE 0x0080 | ||
53 | #define AFE_VUL_CUR 0x008c | ||
54 | #define AFE_DAI_BASE 0x0090 | ||
55 | #define AFE_DAI_CUR 0x009c | ||
56 | #define AFE_MOD_PCM_BASE 0x0330 | ||
57 | #define AFE_MOD_PCM_CUR 0x033c | ||
58 | #define AFE_HDMI_OUT_BASE 0x0374 | ||
59 | #define AFE_HDMI_OUT_CUR 0x0378 | ||
60 | |||
61 | #define AFE_ADDA2_TOP_CON0 0x0600 | ||
62 | |||
63 | #define AFE_HDMI_OUT_CON0 0x0370 | ||
64 | |||
65 | #define AFE_IRQ_MCU_CON 0x03a0 | ||
66 | #define AFE_IRQ_STATUS 0x03a4 | ||
67 | #define AFE_IRQ_CLR 0x03a8 | ||
68 | #define AFE_IRQ_CNT1 0x03ac | ||
69 | #define AFE_IRQ_CNT2 0x03b0 | ||
70 | #define AFE_IRQ_MCU_EN 0x03b4 | ||
71 | #define AFE_IRQ_CNT5 0x03bc | ||
72 | #define AFE_IRQ_CNT7 0x03dc | ||
73 | |||
74 | #define AFE_TDM_CON1 0x0548 | ||
75 | #define AFE_TDM_CON2 0x054c | ||
76 | |||
77 | #define AFE_BASE_END_OFFSET 8 | ||
78 | #define AFE_IRQ_STATUS_BITS 0xff | ||
79 | |||
80 | /* AUDIO_TOP_CON0 (0x0000) */ | ||
81 | #define AUD_TCON0_PDN_SPDF (0x1 << 21) | ||
82 | #define AUD_TCON0_PDN_HDMI (0x1 << 20) | ||
83 | #define AUD_TCON0_PDN_24M (0x1 << 9) | ||
84 | #define AUD_TCON0_PDN_22M (0x1 << 8) | ||
85 | #define AUD_TCON0_PDN_AFE (0x1 << 2) | ||
86 | |||
87 | /* AFE_I2S_CON1 (0x0034) */ | ||
88 | #define AFE_I2S_CON1_LOW_JITTER_CLK (0x1 << 12) | ||
89 | #define AFE_I2S_CON1_RATE(x) (((x) & 0xf) << 8) | ||
90 | #define AFE_I2S_CON1_FORMAT_I2S (0x1 << 3) | ||
91 | #define AFE_I2S_CON1_EN (0x1 << 0) | ||
92 | |||
93 | /* AFE_I2S_CON2 (0x0038) */ | ||
94 | #define AFE_I2S_CON2_LOW_JITTER_CLK (0x1 << 12) | ||
95 | #define AFE_I2S_CON2_RATE(x) (((x) & 0xf) << 8) | ||
96 | #define AFE_I2S_CON2_FORMAT_I2S (0x1 << 3) | ||
97 | #define AFE_I2S_CON2_EN (0x1 << 0) | ||
98 | |||
99 | /* AFE_CONN_24BIT (0x006c) */ | ||
100 | #define AFE_CONN_24BIT_O04 (0x1 << 4) | ||
101 | #define AFE_CONN_24BIT_O03 (0x1 << 3) | ||
102 | |||
103 | /* AFE_HDMI_CONN0 (0x0390) */ | ||
104 | #define AFE_HDMI_CONN0_O37_I37 (0x7 << 21) | ||
105 | #define AFE_HDMI_CONN0_O36_I36 (0x6 << 18) | ||
106 | #define AFE_HDMI_CONN0_O35_I33 (0x3 << 15) | ||
107 | #define AFE_HDMI_CONN0_O34_I32 (0x2 << 12) | ||
108 | #define AFE_HDMI_CONN0_O33_I35 (0x5 << 9) | ||
109 | #define AFE_HDMI_CONN0_O32_I34 (0x4 << 6) | ||
110 | #define AFE_HDMI_CONN0_O31_I31 (0x1 << 3) | ||
111 | #define AFE_HDMI_CONN0_O30_I30 (0x0 << 0) | ||
112 | |||
113 | /* AFE_TDM_CON1 (0x0548) */ | ||
114 | #define AFE_TDM_CON1_LRCK_WIDTH(x) (((x) - 1) << 24) | ||
115 | #define AFE_TDM_CON1_32_BCK_CYCLES (0x2 << 12) | ||
116 | #define AFE_TDM_CON1_WLEN_32BIT (0x2 << 8) | ||
117 | #define AFE_TDM_CON1_MSB_ALIGNED (0x1 << 4) | ||
118 | #define AFE_TDM_CON1_1_BCK_DELAY (0x1 << 3) | ||
119 | #define AFE_TDM_CON1_BCK_INV (0x1 << 1) | ||
120 | #define AFE_TDM_CON1_EN (0x1 << 0) | ||
121 | |||
122 | enum afe_tdm_ch_start { | ||
123 | AFE_TDM_CH_START_O30_O31 = 0, | ||
124 | AFE_TDM_CH_START_O32_O33, | ||
125 | AFE_TDM_CH_START_O34_O35, | ||
126 | AFE_TDM_CH_START_O36_O37, | ||
127 | AFE_TDM_CH_ZERO, | ||
128 | }; | ||
129 | |||
130 | static const struct snd_pcm_hardware mtk_afe_hardware = { | ||
131 | .info = (SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_INTERLEAVED | | ||
132 | SNDRV_PCM_INFO_MMAP_VALID), | ||
133 | .buffer_bytes_max = 256 * 1024, | ||
134 | .period_bytes_min = 512, | ||
135 | .period_bytes_max = 128 * 1024, | ||
136 | .periods_min = 2, | ||
137 | .periods_max = 256, | ||
138 | .fifo_size = 0, | ||
139 | }; | ||
140 | |||
141 | static snd_pcm_uframes_t mtk_afe_pcm_pointer | ||
142 | (struct snd_pcm_substream *substream) | ||
143 | { | ||
144 | struct snd_soc_pcm_runtime *rtd = substream->private_data; | ||
145 | struct mtk_afe *afe = snd_soc_platform_get_drvdata(rtd->platform); | ||
146 | struct mtk_afe_memif *memif = &afe->memif[rtd->cpu_dai->id]; | ||
147 | |||
148 | return bytes_to_frames(substream->runtime, memif->hw_ptr); | ||
149 | } | ||
150 | |||
151 | static const struct snd_pcm_ops mtk_afe_pcm_ops = { | ||
152 | .ioctl = snd_pcm_lib_ioctl, | ||
153 | .pointer = mtk_afe_pcm_pointer, | ||
154 | }; | ||
155 | |||
156 | static int mtk_afe_pcm_new(struct snd_soc_pcm_runtime *rtd) | ||
157 | { | ||
158 | size_t size; | ||
159 | struct snd_card *card = rtd->card->snd_card; | ||
160 | struct snd_pcm *pcm = rtd->pcm; | ||
161 | |||
162 | size = mtk_afe_hardware.buffer_bytes_max; | ||
163 | |||
164 | return snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV, | ||
165 | card->dev, size, size); | ||
166 | } | ||
167 | |||
168 | static void mtk_afe_pcm_free(struct snd_pcm *pcm) | ||
169 | { | ||
170 | snd_pcm_lib_preallocate_free_for_all(pcm); | ||
171 | } | ||
172 | |||
173 | static const struct snd_soc_platform_driver mtk_afe_pcm_platform = { | ||
174 | .ops = &mtk_afe_pcm_ops, | ||
175 | .pcm_new = mtk_afe_pcm_new, | ||
176 | .pcm_free = mtk_afe_pcm_free, | ||
177 | }; | ||
178 | |||
179 | struct mtk_afe_rate { | ||
180 | unsigned int rate; | ||
181 | unsigned int regvalue; | ||
182 | }; | ||
183 | |||
184 | static const struct mtk_afe_rate mtk_afe_i2s_rates[] = { | ||
185 | { .rate = 8000, .regvalue = 0 }, | ||
186 | { .rate = 11025, .regvalue = 1 }, | ||
187 | { .rate = 12000, .regvalue = 2 }, | ||
188 | { .rate = 16000, .regvalue = 4 }, | ||
189 | { .rate = 22050, .regvalue = 5 }, | ||
190 | { .rate = 24000, .regvalue = 6 }, | ||
191 | { .rate = 32000, .regvalue = 8 }, | ||
192 | { .rate = 44100, .regvalue = 9 }, | ||
193 | { .rate = 48000, .regvalue = 10 }, | ||
194 | { .rate = 88000, .regvalue = 11 }, | ||
195 | { .rate = 96000, .regvalue = 12 }, | ||
196 | { .rate = 174000, .regvalue = 13 }, | ||
197 | { .rate = 192000, .regvalue = 14 }, | ||
198 | }; | ||
199 | |||
200 | static int mtk_afe_i2s_fs(unsigned int sample_rate) | ||
201 | { | ||
202 | int i; | ||
203 | |||
204 | for (i = 0; i < ARRAY_SIZE(mtk_afe_i2s_rates); i++) | ||
205 | if (mtk_afe_i2s_rates[i].rate == sample_rate) | ||
206 | return mtk_afe_i2s_rates[i].regvalue; | ||
207 | |||
208 | return -EINVAL; | ||
209 | } | ||
210 | |||
211 | static int mtk_afe_set_i2s(struct mtk_afe *afe, unsigned int rate) | ||
212 | { | ||
213 | unsigned int val; | ||
214 | int fs = mtk_afe_i2s_fs(rate); | ||
215 | |||
216 | if (fs < 0) | ||
217 | return -EINVAL; | ||
218 | |||
219 | /* from external ADC */ | ||
220 | regmap_update_bits(afe->regmap, AFE_ADDA2_TOP_CON0, 0x1, 0x1); | ||
221 | |||
222 | /* set input */ | ||
223 | val = AFE_I2S_CON2_LOW_JITTER_CLK | | ||
224 | AFE_I2S_CON2_RATE(fs) | | ||
225 | AFE_I2S_CON2_FORMAT_I2S; | ||
226 | |||
227 | regmap_update_bits(afe->regmap, AFE_I2S_CON2, ~AFE_I2S_CON2_EN, val); | ||
228 | |||
229 | /* set output */ | ||
230 | val = AFE_I2S_CON1_LOW_JITTER_CLK | | ||
231 | AFE_I2S_CON1_RATE(fs) | | ||
232 | AFE_I2S_CON1_FORMAT_I2S; | ||
233 | |||
234 | regmap_update_bits(afe->regmap, AFE_I2S_CON1, ~AFE_I2S_CON1_EN, val); | ||
235 | return 0; | ||
236 | } | ||
237 | |||
238 | static void mtk_afe_set_i2s_enable(struct mtk_afe *afe, bool enable) | ||
239 | { | ||
240 | unsigned int val; | ||
241 | |||
242 | regmap_read(afe->regmap, AFE_I2S_CON2, &val); | ||
243 | if (!!(val & AFE_I2S_CON2_EN) == enable) | ||
244 | return; /* must skip soft reset */ | ||
245 | |||
246 | /* I2S soft reset begin */ | ||
247 | regmap_update_bits(afe->regmap, AUDIO_TOP_CON1, 0x4, 0x4); | ||
248 | |||
249 | /* input */ | ||
250 | regmap_update_bits(afe->regmap, AFE_I2S_CON2, 0x1, enable); | ||
251 | |||
252 | /* output */ | ||
253 | regmap_update_bits(afe->regmap, AFE_I2S_CON1, 0x1, enable); | ||
254 | |||
255 | /* I2S soft reset end */ | ||
256 | udelay(1); | ||
257 | regmap_update_bits(afe->regmap, AUDIO_TOP_CON1, 0x4, 0); | ||
258 | } | ||
259 | |||
260 | static int mtk_afe_dais_enable_clks(struct mtk_afe *afe, | ||
261 | struct clk *m_ck, struct clk *b_ck) | ||
262 | { | ||
263 | int ret; | ||
264 | |||
265 | if (m_ck) { | ||
266 | ret = clk_prepare_enable(m_ck); | ||
267 | if (ret) { | ||
268 | dev_err(afe->dev, "Failed to enable m_ck\n"); | ||
269 | return ret; | ||
270 | } | ||
271 | regmap_update_bits(afe->regmap, AUDIO_TOP_CON0, | ||
272 | AUD_TCON0_PDN_22M | AUD_TCON0_PDN_24M, 0); | ||
273 | } | ||
274 | |||
275 | if (b_ck) { | ||
276 | ret = clk_prepare_enable(b_ck); | ||
277 | if (ret) { | ||
278 | dev_err(afe->dev, "Failed to enable b_ck\n"); | ||
279 | return ret; | ||
280 | } | ||
281 | } | ||
282 | return 0; | ||
283 | } | ||
284 | |||
285 | static int mtk_afe_dais_set_clks(struct mtk_afe *afe, | ||
286 | struct clk *m_ck, unsigned int mck_rate, | ||
287 | struct clk *b_ck, unsigned int bck_rate) | ||
288 | { | ||
289 | int ret; | ||
290 | |||
291 | if (m_ck) { | ||
292 | ret = clk_set_rate(m_ck, mck_rate); | ||
293 | if (ret) { | ||
294 | dev_err(afe->dev, "Failed to set m_ck rate\n"); | ||
295 | return ret; | ||
296 | } | ||
297 | } | ||
298 | |||
299 | if (b_ck) { | ||
300 | ret = clk_set_rate(b_ck, bck_rate); | ||
301 | if (ret) { | ||
302 | dev_err(afe->dev, "Failed to set b_ck rate\n"); | ||
303 | return ret; | ||
304 | } | ||
305 | } | ||
306 | return 0; | ||
307 | } | ||
308 | |||
309 | static void mtk_afe_dais_disable_clks(struct mtk_afe *afe, | ||
310 | struct clk *m_ck, struct clk *b_ck) | ||
311 | { | ||
312 | if (m_ck) { | ||
313 | regmap_update_bits(afe->regmap, AUDIO_TOP_CON0, | ||
314 | AUD_TCON0_PDN_22M | AUD_TCON0_PDN_24M, | ||
315 | AUD_TCON0_PDN_22M | AUD_TCON0_PDN_24M); | ||
316 | clk_disable_unprepare(m_ck); | ||
317 | } | ||
318 | if (b_ck) | ||
319 | clk_disable_unprepare(b_ck); | ||
320 | } | ||
321 | |||
322 | static int mtk_afe_i2s_startup(struct snd_pcm_substream *substream, | ||
323 | struct snd_soc_dai *dai) | ||
324 | { | ||
325 | struct snd_soc_pcm_runtime *rtd = substream->private_data; | ||
326 | struct mtk_afe *afe = snd_soc_platform_get_drvdata(rtd->platform); | ||
327 | |||
328 | if (dai->active) | ||
329 | return 0; | ||
330 | |||
331 | mtk_afe_dais_enable_clks(afe, afe->clocks[MTK_CLK_I2S1_M], NULL); | ||
332 | return 0; | ||
333 | } | ||
334 | |||
335 | static void mtk_afe_i2s_shutdown(struct snd_pcm_substream *substream, | ||
336 | struct snd_soc_dai *dai) | ||
337 | { | ||
338 | struct snd_soc_pcm_runtime *rtd = substream->private_data; | ||
339 | struct mtk_afe *afe = snd_soc_platform_get_drvdata(rtd->platform); | ||
340 | |||
341 | if (dai->active) | ||
342 | return; | ||
343 | |||
344 | mtk_afe_set_i2s_enable(afe, false); | ||
345 | mtk_afe_dais_disable_clks(afe, afe->clocks[MTK_CLK_I2S1_M], NULL); | ||
346 | |||
347 | /* disable AFE */ | ||
348 | regmap_update_bits(afe->regmap, AFE_DAC_CON0, 0x1, 0); | ||
349 | } | ||
350 | |||
351 | static int mtk_afe_i2s_prepare(struct snd_pcm_substream *substream, | ||
352 | struct snd_soc_dai *dai) | ||
353 | { | ||
354 | struct snd_soc_pcm_runtime *rtd = substream->private_data; | ||
355 | struct snd_pcm_runtime * const runtime = substream->runtime; | ||
356 | struct mtk_afe *afe = snd_soc_platform_get_drvdata(rtd->platform); | ||
357 | int ret; | ||
358 | |||
359 | mtk_afe_dais_set_clks(afe, | ||
360 | afe->clocks[MTK_CLK_I2S1_M], runtime->rate * 256, | ||
361 | NULL, 0); | ||
362 | /* config I2S */ | ||
363 | ret = mtk_afe_set_i2s(afe, substream->runtime->rate); | ||
364 | if (ret) | ||
365 | return ret; | ||
366 | |||
367 | mtk_afe_set_i2s_enable(afe, true); | ||
368 | |||
369 | return 0; | ||
370 | } | ||
371 | |||
372 | static int mtk_afe_hdmi_startup(struct snd_pcm_substream *substream, | ||
373 | struct snd_soc_dai *dai) | ||
374 | { | ||
375 | struct snd_soc_pcm_runtime *rtd = substream->private_data; | ||
376 | struct mtk_afe *afe = snd_soc_platform_get_drvdata(rtd->platform); | ||
377 | |||
378 | if (dai->active) | ||
379 | return 0; | ||
380 | |||
381 | mtk_afe_dais_enable_clks(afe, afe->clocks[MTK_CLK_I2S3_M], | ||
382 | afe->clocks[MTK_CLK_I2S3_B]); | ||
383 | return 0; | ||
384 | } | ||
385 | |||
386 | static void mtk_afe_hdmi_shutdown(struct snd_pcm_substream *substream, | ||
387 | struct snd_soc_dai *dai) | ||
388 | { | ||
389 | struct snd_soc_pcm_runtime *rtd = substream->private_data; | ||
390 | struct mtk_afe *afe = snd_soc_platform_get_drvdata(rtd->platform); | ||
391 | |||
392 | if (dai->active) | ||
393 | return; | ||
394 | |||
395 | mtk_afe_dais_disable_clks(afe, afe->clocks[MTK_CLK_I2S3_M], | ||
396 | afe->clocks[MTK_CLK_I2S3_B]); | ||
397 | |||
398 | /* disable AFE */ | ||
399 | regmap_update_bits(afe->regmap, AFE_DAC_CON0, 0x1, 0); | ||
400 | } | ||
401 | |||
402 | static int mtk_afe_hdmi_prepare(struct snd_pcm_substream *substream, | ||
403 | struct snd_soc_dai *dai) | ||
404 | { | ||
405 | struct snd_soc_pcm_runtime *rtd = substream->private_data; | ||
406 | struct snd_pcm_runtime * const runtime = substream->runtime; | ||
407 | struct mtk_afe *afe = snd_soc_platform_get_drvdata(rtd->platform); | ||
408 | unsigned int val; | ||
409 | |||
410 | mtk_afe_dais_set_clks(afe, | ||
411 | afe->clocks[MTK_CLK_I2S3_M], runtime->rate * 128, | ||
412 | afe->clocks[MTK_CLK_I2S3_B], | ||
413 | runtime->rate * runtime->channels * 32); | ||
414 | |||
415 | val = AFE_TDM_CON1_BCK_INV | | ||
416 | AFE_TDM_CON1_1_BCK_DELAY | | ||
417 | AFE_TDM_CON1_MSB_ALIGNED | /* I2S mode */ | ||
418 | AFE_TDM_CON1_WLEN_32BIT | | ||
419 | AFE_TDM_CON1_32_BCK_CYCLES | | ||
420 | AFE_TDM_CON1_LRCK_WIDTH(32); | ||
421 | regmap_update_bits(afe->regmap, AFE_TDM_CON1, ~AFE_TDM_CON1_EN, val); | ||
422 | |||
423 | /* set tdm2 config */ | ||
424 | switch (runtime->channels) { | ||
425 | case 1: | ||
426 | case 2: | ||
427 | val = AFE_TDM_CH_START_O30_O31; | ||
428 | val |= (AFE_TDM_CH_ZERO << 4); | ||
429 | val |= (AFE_TDM_CH_ZERO << 8); | ||
430 | val |= (AFE_TDM_CH_ZERO << 12); | ||
431 | break; | ||
432 | case 3: | ||
433 | case 4: | ||
434 | val = AFE_TDM_CH_START_O30_O31; | ||
435 | val |= (AFE_TDM_CH_START_O32_O33 << 4); | ||
436 | val |= (AFE_TDM_CH_ZERO << 8); | ||
437 | val |= (AFE_TDM_CH_ZERO << 12); | ||
438 | break; | ||
439 | case 5: | ||
440 | case 6: | ||
441 | val = AFE_TDM_CH_START_O30_O31; | ||
442 | val |= (AFE_TDM_CH_START_O32_O33 << 4); | ||
443 | val |= (AFE_TDM_CH_START_O34_O35 << 8); | ||
444 | val |= (AFE_TDM_CH_ZERO << 12); | ||
445 | break; | ||
446 | case 7: | ||
447 | case 8: | ||
448 | val = AFE_TDM_CH_START_O30_O31; | ||
449 | val |= (AFE_TDM_CH_START_O32_O33 << 4); | ||
450 | val |= (AFE_TDM_CH_START_O34_O35 << 8); | ||
451 | val |= (AFE_TDM_CH_START_O36_O37 << 12); | ||
452 | break; | ||
453 | default: | ||
454 | val = 0; | ||
455 | } | ||
456 | regmap_update_bits(afe->regmap, AFE_TDM_CON2, 0x0000ffff, val); | ||
457 | |||
458 | regmap_update_bits(afe->regmap, AFE_HDMI_OUT_CON0, | ||
459 | 0x000000f0, runtime->channels << 4); | ||
460 | return 0; | ||
461 | } | ||
462 | |||
463 | static int mtk_afe_hdmi_trigger(struct snd_pcm_substream *substream, int cmd, | ||
464 | struct snd_soc_dai *dai) | ||
465 | { | ||
466 | struct snd_soc_pcm_runtime *rtd = substream->private_data; | ||
467 | struct mtk_afe *afe = snd_soc_platform_get_drvdata(rtd->platform); | ||
468 | |||
469 | dev_info(afe->dev, "%s cmd=%d %s\n", __func__, cmd, dai->name); | ||
470 | |||
471 | switch (cmd) { | ||
472 | case SNDRV_PCM_TRIGGER_START: | ||
473 | case SNDRV_PCM_TRIGGER_RESUME: | ||
474 | regmap_update_bits(afe->regmap, AUDIO_TOP_CON0, | ||
475 | AUD_TCON0_PDN_HDMI | AUD_TCON0_PDN_SPDF, 0); | ||
476 | |||
477 | /* set connections: O30~O37: L/R/LS/RS/C/LFE/CH7/CH8 */ | ||
478 | regmap_write(afe->regmap, AFE_HDMI_CONN0, | ||
479 | AFE_HDMI_CONN0_O30_I30 | AFE_HDMI_CONN0_O31_I31 | | ||
480 | AFE_HDMI_CONN0_O32_I34 | AFE_HDMI_CONN0_O33_I35 | | ||
481 | AFE_HDMI_CONN0_O34_I32 | AFE_HDMI_CONN0_O35_I33 | | ||
482 | AFE_HDMI_CONN0_O36_I36 | AFE_HDMI_CONN0_O37_I37); | ||
483 | |||
484 | /* enable Out control */ | ||
485 | regmap_update_bits(afe->regmap, AFE_HDMI_OUT_CON0, 0x1, 0x1); | ||
486 | |||
487 | /* enable tdm */ | ||
488 | regmap_update_bits(afe->regmap, AFE_TDM_CON1, 0x1, 0x1); | ||
489 | |||
490 | return 0; | ||
491 | case SNDRV_PCM_TRIGGER_STOP: | ||
492 | case SNDRV_PCM_TRIGGER_SUSPEND: | ||
493 | /* disable tdm */ | ||
494 | regmap_update_bits(afe->regmap, AFE_TDM_CON1, 0x1, 0); | ||
495 | |||
496 | /* disable Out control */ | ||
497 | regmap_update_bits(afe->regmap, AFE_HDMI_OUT_CON0, 0x1, 0); | ||
498 | |||
499 | regmap_update_bits(afe->regmap, AUDIO_TOP_CON0, | ||
500 | AUD_TCON0_PDN_HDMI | AUD_TCON0_PDN_SPDF, | ||
501 | AUD_TCON0_PDN_HDMI | AUD_TCON0_PDN_SPDF); | ||
502 | |||
503 | return 0; | ||
504 | default: | ||
505 | return -EINVAL; | ||
506 | } | ||
507 | } | ||
508 | |||
509 | static int mtk_afe_dais_startup(struct snd_pcm_substream *substream, | ||
510 | struct snd_soc_dai *dai) | ||
511 | { | ||
512 | struct snd_soc_pcm_runtime *rtd = substream->private_data; | ||
513 | struct mtk_afe *afe = snd_soc_platform_get_drvdata(rtd->platform); | ||
514 | struct snd_pcm_runtime *runtime = substream->runtime; | ||
515 | struct mtk_afe_memif *memif = &afe->memif[rtd->cpu_dai->id]; | ||
516 | int ret; | ||
517 | |||
518 | memif->substream = substream; | ||
519 | |||
520 | snd_soc_set_runtime_hwparams(substream, &mtk_afe_hardware); | ||
521 | ret = snd_pcm_hw_constraint_integer(runtime, | ||
522 | SNDRV_PCM_HW_PARAM_PERIODS); | ||
523 | if (ret < 0) | ||
524 | dev_err(afe->dev, "snd_pcm_hw_constraint_integer failed\n"); | ||
525 | return ret; | ||
526 | } | ||
527 | |||
528 | static void mtk_afe_dais_shutdown(struct snd_pcm_substream *substream, | ||
529 | struct snd_soc_dai *dai) | ||
530 | { | ||
531 | struct snd_soc_pcm_runtime *rtd = substream->private_data; | ||
532 | struct mtk_afe *afe = snd_soc_platform_get_drvdata(rtd->platform); | ||
533 | struct mtk_afe_memif *memif = &afe->memif[rtd->cpu_dai->id]; | ||
534 | |||
535 | memif->substream = NULL; | ||
536 | } | ||
537 | |||
538 | static int mtk_afe_dais_hw_params(struct snd_pcm_substream *substream, | ||
539 | struct snd_pcm_hw_params *params, | ||
540 | struct snd_soc_dai *dai) | ||
541 | { | ||
542 | struct snd_soc_pcm_runtime *rtd = substream->private_data; | ||
543 | struct mtk_afe *afe = snd_soc_platform_get_drvdata(rtd->platform); | ||
544 | struct mtk_afe_memif *memif = &afe->memif[rtd->cpu_dai->id]; | ||
545 | int ret; | ||
546 | |||
547 | dev_dbg(afe->dev, | ||
548 | "%s period = %u, rate= %u, channels=%u\n", | ||
549 | __func__, params_period_size(params), params_rate(params), | ||
550 | params_channels(params)); | ||
551 | |||
552 | ret = snd_pcm_lib_malloc_pages(substream, params_buffer_bytes(params)); | ||
553 | if (ret < 0) | ||
554 | return ret; | ||
555 | |||
556 | memif->phys_buf_addr = substream->runtime->dma_addr; | ||
557 | memif->buffer_size = substream->runtime->dma_bytes; | ||
558 | memif->hw_ptr = 0; | ||
559 | |||
560 | /* start */ | ||
561 | regmap_write(afe->regmap, | ||
562 | memif->data->reg_ofs_base, memif->phys_buf_addr); | ||
563 | /* end */ | ||
564 | regmap_write(afe->regmap, | ||
565 | memif->data->reg_ofs_base + AFE_BASE_END_OFFSET, | ||
566 | memif->phys_buf_addr + memif->buffer_size - 1); | ||
567 | |||
568 | /* set channel */ | ||
569 | if (memif->data->mono_shift >= 0) { | ||
570 | unsigned int mono = (params_channels(params) == 1) ? 1 : 0; | ||
571 | |||
572 | regmap_update_bits(afe->regmap, AFE_DAC_CON1, | ||
573 | 1 << memif->data->mono_shift, | ||
574 | mono << memif->data->mono_shift); | ||
575 | } | ||
576 | |||
577 | /* set rate */ | ||
578 | if (memif->data->fs_shift < 0) | ||
579 | return 0; | ||
580 | if (memif->data->id == MTK_AFE_MEMIF_DAI || | ||
581 | memif->data->id == MTK_AFE_MEMIF_MOD_DAI) { | ||
582 | unsigned int val; | ||
583 | |||
584 | switch (params_rate(params)) { | ||
585 | case 8000: | ||
586 | val = 0; | ||
587 | break; | ||
588 | case 16000: | ||
589 | val = 1; | ||
590 | break; | ||
591 | case 32000: | ||
592 | val = 2; | ||
593 | break; | ||
594 | default: | ||
595 | return -EINVAL; | ||
596 | } | ||
597 | |||
598 | if (memif->data->id == MTK_AFE_MEMIF_DAI) | ||
599 | regmap_update_bits(afe->regmap, AFE_DAC_CON0, | ||
600 | 0x3 << memif->data->fs_shift, | ||
601 | val << memif->data->fs_shift); | ||
602 | else | ||
603 | regmap_update_bits(afe->regmap, AFE_DAC_CON1, | ||
604 | 0x3 << memif->data->fs_shift, | ||
605 | val << memif->data->fs_shift); | ||
606 | |||
607 | } else { | ||
608 | int fs = mtk_afe_i2s_fs(params_rate(params)); | ||
609 | |||
610 | if (fs < 0) | ||
611 | return -EINVAL; | ||
612 | |||
613 | regmap_update_bits(afe->regmap, AFE_DAC_CON1, | ||
614 | 0xf << memif->data->fs_shift, | ||
615 | fs << memif->data->fs_shift); | ||
616 | } | ||
617 | |||
618 | return 0; | ||
619 | } | ||
620 | |||
621 | static int mtk_afe_dais_hw_free(struct snd_pcm_substream *substream, | ||
622 | struct snd_soc_dai *dai) | ||
623 | { | ||
624 | return snd_pcm_lib_free_pages(substream); | ||
625 | } | ||
626 | |||
627 | static int mtk_afe_dais_prepare(struct snd_pcm_substream *substream, | ||
628 | struct snd_soc_dai *dai) | ||
629 | { | ||
630 | struct snd_soc_pcm_runtime *rtd = substream->private_data; | ||
631 | struct mtk_afe *afe = snd_soc_platform_get_drvdata(rtd->platform); | ||
632 | |||
633 | /* enable AFE */ | ||
634 | regmap_update_bits(afe->regmap, AFE_DAC_CON0, 0x1, 0x1); | ||
635 | return 0; | ||
636 | } | ||
637 | |||
638 | static int mtk_afe_dais_trigger(struct snd_pcm_substream *substream, int cmd, | ||
639 | struct snd_soc_dai *dai) | ||
640 | { | ||
641 | struct snd_soc_pcm_runtime *rtd = substream->private_data; | ||
642 | struct snd_pcm_runtime * const runtime = substream->runtime; | ||
643 | struct mtk_afe *afe = snd_soc_platform_get_drvdata(rtd->platform); | ||
644 | struct mtk_afe_memif *memif = &afe->memif[rtd->cpu_dai->id]; | ||
645 | unsigned int counter = runtime->period_size; | ||
646 | |||
647 | dev_info(afe->dev, "%s %s cmd=%d\n", __func__, memif->data->name, cmd); | ||
648 | |||
649 | switch (cmd) { | ||
650 | case SNDRV_PCM_TRIGGER_START: | ||
651 | case SNDRV_PCM_TRIGGER_RESUME: | ||
652 | if (memif->data->enable_shift >= 0) | ||
653 | regmap_update_bits(afe->regmap, AFE_DAC_CON0, | ||
654 | 1 << memif->data->enable_shift, | ||
655 | 1 << memif->data->enable_shift); | ||
656 | |||
657 | /* set irq counter */ | ||
658 | regmap_update_bits(afe->regmap, | ||
659 | memif->data->irq_reg_cnt, | ||
660 | 0x3ffff << memif->data->irq_cnt_shift, | ||
661 | counter << memif->data->irq_cnt_shift); | ||
662 | |||
663 | /* set irq fs */ | ||
664 | if (memif->data->irq_fs_shift >= 0) { | ||
665 | int fs = mtk_afe_i2s_fs(runtime->rate); | ||
666 | |||
667 | if (fs < 0) | ||
668 | return -EINVAL; | ||
669 | |||
670 | regmap_update_bits(afe->regmap, | ||
671 | AFE_IRQ_MCU_CON, | ||
672 | 0xf << memif->data->irq_fs_shift, | ||
673 | fs << memif->data->irq_fs_shift); | ||
674 | } | ||
675 | /* enable interrupt */ | ||
676 | regmap_update_bits(afe->regmap, AFE_IRQ_MCU_CON, | ||
677 | 1 << memif->data->irq_en_shift, | ||
678 | 1 << memif->data->irq_en_shift); | ||
679 | |||
680 | return 0; | ||
681 | case SNDRV_PCM_TRIGGER_STOP: | ||
682 | case SNDRV_PCM_TRIGGER_SUSPEND: | ||
683 | if (memif->data->enable_shift >= 0) | ||
684 | regmap_update_bits(afe->regmap, AFE_DAC_CON0, | ||
685 | 1 << memif->data->enable_shift, 0); | ||
686 | /* disable interrupt */ | ||
687 | regmap_update_bits(afe->regmap, AFE_IRQ_MCU_CON, | ||
688 | 1 << memif->data->irq_en_shift, | ||
689 | 0 << memif->data->irq_en_shift); | ||
690 | /* and clear pending IRQ */ | ||
691 | regmap_write(afe->regmap, AFE_IRQ_CLR, | ||
692 | 1 << memif->data->irq_clr_shift); | ||
693 | memif->hw_ptr = 0; | ||
694 | return 0; | ||
695 | default: | ||
696 | return -EINVAL; | ||
697 | } | ||
698 | } | ||
699 | |||
700 | /* FE DAIs */ | ||
701 | static const struct snd_soc_dai_ops mtk_afe_dai_ops = { | ||
702 | .startup = mtk_afe_dais_startup, | ||
703 | .shutdown = mtk_afe_dais_shutdown, | ||
704 | .hw_params = mtk_afe_dais_hw_params, | ||
705 | .hw_free = mtk_afe_dais_hw_free, | ||
706 | .prepare = mtk_afe_dais_prepare, | ||
707 | .trigger = mtk_afe_dais_trigger, | ||
708 | }; | ||
709 | |||
710 | /* BE DAIs */ | ||
711 | static const struct snd_soc_dai_ops mtk_afe_i2s_ops = { | ||
712 | .startup = mtk_afe_i2s_startup, | ||
713 | .shutdown = mtk_afe_i2s_shutdown, | ||
714 | .prepare = mtk_afe_i2s_prepare, | ||
715 | }; | ||
716 | |||
717 | static const struct snd_soc_dai_ops mtk_afe_hdmi_ops = { | ||
718 | .startup = mtk_afe_hdmi_startup, | ||
719 | .shutdown = mtk_afe_hdmi_shutdown, | ||
720 | .prepare = mtk_afe_hdmi_prepare, | ||
721 | .trigger = mtk_afe_hdmi_trigger, | ||
722 | |||
723 | }; | ||
724 | |||
725 | static struct snd_soc_dai_driver mtk_afe_pcm_dais[] = { | ||
726 | /* FE DAIs: memory intefaces to CPU */ | ||
727 | { | ||
728 | .name = "DL1", /* downlink 1 */ | ||
729 | .id = MTK_AFE_MEMIF_DL1, | ||
730 | .playback = { | ||
731 | .stream_name = "DL1", | ||
732 | .channels_min = 1, | ||
733 | .channels_max = 2, | ||
734 | .rates = SNDRV_PCM_RATE_8000_48000, | ||
735 | .formats = SNDRV_PCM_FMTBIT_S16_LE, | ||
736 | }, | ||
737 | .ops = &mtk_afe_dai_ops, | ||
738 | }, { | ||
739 | .name = "VUL", /* voice uplink */ | ||
740 | .id = MTK_AFE_MEMIF_VUL, | ||
741 | .capture = { | ||
742 | .stream_name = "VUL", | ||
743 | .channels_min = 1, | ||
744 | .channels_max = 2, | ||
745 | .rates = SNDRV_PCM_RATE_8000_48000, | ||
746 | .formats = SNDRV_PCM_FMTBIT_S16_LE, | ||
747 | }, | ||
748 | .ops = &mtk_afe_dai_ops, | ||
749 | }, { | ||
750 | /* BE DAIs */ | ||
751 | .name = "I2S", | ||
752 | .id = MTK_AFE_IO_I2S, | ||
753 | .playback = { | ||
754 | .stream_name = "I2S Playback", | ||
755 | .channels_min = 1, | ||
756 | .channels_max = 2, | ||
757 | .rates = SNDRV_PCM_RATE_8000_48000, | ||
758 | .formats = SNDRV_PCM_FMTBIT_S16_LE, | ||
759 | }, | ||
760 | .capture = { | ||
761 | .stream_name = "I2S Capture", | ||
762 | .channels_min = 1, | ||
763 | .channels_max = 2, | ||
764 | .rates = SNDRV_PCM_RATE_8000_48000, | ||
765 | .formats = SNDRV_PCM_FMTBIT_S16_LE, | ||
766 | }, | ||
767 | .ops = &mtk_afe_i2s_ops, | ||
768 | .symmetric_rates = 1, | ||
769 | }, | ||
770 | }; | ||
771 | |||
772 | static struct snd_soc_dai_driver mtk_afe_hdmi_dais[] = { | ||
773 | /* FE DAIs */ | ||
774 | { | ||
775 | .name = "HDMI", | ||
776 | .id = MTK_AFE_MEMIF_HDMI, | ||
777 | .playback = { | ||
778 | .stream_name = "HDMI", | ||
779 | .channels_min = 2, | ||
780 | .channels_max = 8, | ||
781 | .rates = SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_44100 | | ||
782 | SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_88200 | | ||
783 | SNDRV_PCM_RATE_96000 | SNDRV_PCM_RATE_176400 | | ||
784 | SNDRV_PCM_RATE_192000, | ||
785 | .formats = SNDRV_PCM_FMTBIT_S16_LE, | ||
786 | }, | ||
787 | .ops = &mtk_afe_dai_ops, | ||
788 | }, { | ||
789 | /* BE DAIs */ | ||
790 | .name = "HDMIO", | ||
791 | .id = MTK_AFE_IO_HDMI, | ||
792 | .playback = { | ||
793 | .stream_name = "HDMIO Playback", | ||
794 | .channels_min = 2, | ||
795 | .channels_max = 8, | ||
796 | .rates = SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_44100 | | ||
797 | SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_88200 | | ||
798 | SNDRV_PCM_RATE_96000 | SNDRV_PCM_RATE_176400 | | ||
799 | SNDRV_PCM_RATE_192000, | ||
800 | .formats = SNDRV_PCM_FMTBIT_S16_LE, | ||
801 | }, | ||
802 | .ops = &mtk_afe_hdmi_ops, | ||
803 | }, | ||
804 | }; | ||
805 | |||
806 | static const struct snd_kcontrol_new mtk_afe_o03_mix[] = { | ||
807 | SOC_DAPM_SINGLE_AUTODISABLE("I05 Switch", AFE_CONN1, 21, 1, 0), | ||
808 | }; | ||
809 | |||
810 | static const struct snd_kcontrol_new mtk_afe_o04_mix[] = { | ||
811 | SOC_DAPM_SINGLE_AUTODISABLE("I06 Switch", AFE_CONN2, 6, 1, 0), | ||
812 | }; | ||
813 | |||
814 | static const struct snd_kcontrol_new mtk_afe_o09_mix[] = { | ||
815 | SOC_DAPM_SINGLE_AUTODISABLE("I17 Switch", AFE_CONN7, 30, 1, 0), | ||
816 | }; | ||
817 | |||
818 | static const struct snd_kcontrol_new mtk_afe_o10_mix[] = { | ||
819 | SOC_DAPM_SINGLE_AUTODISABLE("I18 Switch", AFE_CONN8, 0, 1, 0), | ||
820 | }; | ||
821 | |||
822 | static const struct snd_soc_dapm_widget mtk_afe_pcm_widgets[] = { | ||
823 | /* Backend DAIs */ | ||
824 | SND_SOC_DAPM_AIF_IN("I2S Capture", NULL, 0, SND_SOC_NOPM, 0, 0), | ||
825 | SND_SOC_DAPM_AIF_OUT("I2S Playback", NULL, 0, SND_SOC_NOPM, 0, 0), | ||
826 | |||
827 | /* inter-connections */ | ||
828 | SND_SOC_DAPM_MIXER("I05", SND_SOC_NOPM, 0, 0, NULL, 0), | ||
829 | SND_SOC_DAPM_MIXER("I06", SND_SOC_NOPM, 0, 0, NULL, 0), | ||
830 | SND_SOC_DAPM_MIXER("I17", SND_SOC_NOPM, 0, 0, NULL, 0), | ||
831 | SND_SOC_DAPM_MIXER("I18", SND_SOC_NOPM, 0, 0, NULL, 0), | ||
832 | |||
833 | SND_SOC_DAPM_MIXER("O03", SND_SOC_NOPM, 0, 0, | ||
834 | mtk_afe_o03_mix, ARRAY_SIZE(mtk_afe_o03_mix)), | ||
835 | SND_SOC_DAPM_MIXER("O04", SND_SOC_NOPM, 0, 0, | ||
836 | mtk_afe_o04_mix, ARRAY_SIZE(mtk_afe_o04_mix)), | ||
837 | SND_SOC_DAPM_MIXER("O09", SND_SOC_NOPM, 0, 0, | ||
838 | mtk_afe_o09_mix, ARRAY_SIZE(mtk_afe_o09_mix)), | ||
839 | SND_SOC_DAPM_MIXER("O10", SND_SOC_NOPM, 0, 0, | ||
840 | mtk_afe_o10_mix, ARRAY_SIZE(mtk_afe_o10_mix)), | ||
841 | }; | ||
842 | |||
843 | static const struct snd_soc_dapm_route mtk_afe_pcm_routes[] = { | ||
844 | {"I05", NULL, "DL1"}, | ||
845 | {"I06", NULL, "DL1"}, | ||
846 | {"I2S Playback", NULL, "O03"}, | ||
847 | {"I2S Playback", NULL, "O04"}, | ||
848 | {"VUL", NULL, "O09"}, | ||
849 | {"VUL", NULL, "O10"}, | ||
850 | {"I17", NULL, "I2S Capture"}, | ||
851 | {"I18", NULL, "I2S Capture"}, | ||
852 | { "O03", "I05 Switch", "I05" }, | ||
853 | { "O04", "I06 Switch", "I06" }, | ||
854 | { "O09", "I17 Switch", "I17" }, | ||
855 | { "O10", "I18 Switch", "I18" }, | ||
856 | }; | ||
857 | |||
858 | static const struct snd_soc_dapm_widget mtk_afe_hdmi_widgets[] = { | ||
859 | /* Backend DAIs */ | ||
860 | SND_SOC_DAPM_AIF_OUT("HDMIO Playback", NULL, 0, SND_SOC_NOPM, 0, 0), | ||
861 | }; | ||
862 | |||
863 | static const struct snd_soc_dapm_route mtk_afe_hdmi_routes[] = { | ||
864 | {"HDMIO Playback", NULL, "HDMI"}, | ||
865 | }; | ||
866 | |||
867 | static const struct snd_soc_component_driver mtk_afe_pcm_dai_component = { | ||
868 | .name = "mtk-afe-pcm-dai", | ||
869 | .dapm_widgets = mtk_afe_pcm_widgets, | ||
870 | .num_dapm_widgets = ARRAY_SIZE(mtk_afe_pcm_widgets), | ||
871 | .dapm_routes = mtk_afe_pcm_routes, | ||
872 | .num_dapm_routes = ARRAY_SIZE(mtk_afe_pcm_routes), | ||
873 | }; | ||
874 | |||
875 | static const struct snd_soc_component_driver mtk_afe_hdmi_dai_component = { | ||
876 | .name = "mtk-afe-hdmi-dai", | ||
877 | .dapm_widgets = mtk_afe_hdmi_widgets, | ||
878 | .num_dapm_widgets = ARRAY_SIZE(mtk_afe_hdmi_widgets), | ||
879 | .dapm_routes = mtk_afe_hdmi_routes, | ||
880 | .num_dapm_routes = ARRAY_SIZE(mtk_afe_hdmi_routes), | ||
881 | }; | ||
882 | |||
883 | static const char *aud_clks[MTK_CLK_NUM] = { | ||
884 | [MTK_CLK_INFRASYS_AUD] = "infra_sys_audio_clk", | ||
885 | [MTK_CLK_TOP_PDN_AUD] = "top_pdn_audio", | ||
886 | [MTK_CLK_TOP_PDN_AUD_BUS] = "top_pdn_aud_intbus", | ||
887 | [MTK_CLK_I2S0_M] = "i2s0_m", | ||
888 | [MTK_CLK_I2S1_M] = "i2s1_m", | ||
889 | [MTK_CLK_I2S2_M] = "i2s2_m", | ||
890 | [MTK_CLK_I2S3_M] = "i2s3_m", | ||
891 | [MTK_CLK_I2S3_B] = "i2s3_b", | ||
892 | [MTK_CLK_BCK0] = "bck0", | ||
893 | [MTK_CLK_BCK1] = "bck1", | ||
894 | }; | ||
895 | |||
896 | static const struct mtk_afe_memif_data memif_data[MTK_AFE_MEMIF_NUM] = { | ||
897 | { | ||
898 | .name = "DL1", | ||
899 | .id = MTK_AFE_MEMIF_DL1, | ||
900 | .reg_ofs_base = AFE_DL1_BASE, | ||
901 | .reg_ofs_cur = AFE_DL1_CUR, | ||
902 | .fs_shift = 0, | ||
903 | .mono_shift = 21, | ||
904 | .enable_shift = 1, | ||
905 | .irq_reg_cnt = AFE_IRQ_CNT1, | ||
906 | .irq_cnt_shift = 0, | ||
907 | .irq_en_shift = 0, | ||
908 | .irq_fs_shift = 4, | ||
909 | .irq_clr_shift = 0, | ||
910 | }, { | ||
911 | .name = "DL2", | ||
912 | .id = MTK_AFE_MEMIF_DL2, | ||
913 | .reg_ofs_base = AFE_DL2_BASE, | ||
914 | .reg_ofs_cur = AFE_DL2_CUR, | ||
915 | .fs_shift = 4, | ||
916 | .mono_shift = 22, | ||
917 | .enable_shift = 2, | ||
918 | .irq_reg_cnt = AFE_IRQ_CNT1, | ||
919 | .irq_cnt_shift = 20, | ||
920 | .irq_en_shift = 2, | ||
921 | .irq_fs_shift = 16, | ||
922 | .irq_clr_shift = 2, | ||
923 | }, { | ||
924 | .name = "VUL", | ||
925 | .id = MTK_AFE_MEMIF_VUL, | ||
926 | .reg_ofs_base = AFE_VUL_BASE, | ||
927 | .reg_ofs_cur = AFE_VUL_CUR, | ||
928 | .fs_shift = 16, | ||
929 | .mono_shift = 27, | ||
930 | .enable_shift = 3, | ||
931 | .irq_reg_cnt = AFE_IRQ_CNT2, | ||
932 | .irq_cnt_shift = 0, | ||
933 | .irq_en_shift = 1, | ||
934 | .irq_fs_shift = 8, | ||
935 | .irq_clr_shift = 1, | ||
936 | }, { | ||
937 | .name = "DAI", | ||
938 | .id = MTK_AFE_MEMIF_DAI, | ||
939 | .reg_ofs_base = AFE_DAI_BASE, | ||
940 | .reg_ofs_cur = AFE_DAI_CUR, | ||
941 | .fs_shift = 24, | ||
942 | .mono_shift = -1, | ||
943 | .enable_shift = 4, | ||
944 | .irq_reg_cnt = AFE_IRQ_CNT2, | ||
945 | .irq_cnt_shift = 20, | ||
946 | .irq_en_shift = 3, | ||
947 | .irq_fs_shift = 20, | ||
948 | .irq_clr_shift = 3, | ||
949 | }, { | ||
950 | .name = "AWB", | ||
951 | .id = MTK_AFE_MEMIF_AWB, | ||
952 | .reg_ofs_base = AFE_AWB_BASE, | ||
953 | .reg_ofs_cur = AFE_AWB_CUR, | ||
954 | .fs_shift = 12, | ||
955 | .mono_shift = 24, | ||
956 | .enable_shift = 6, | ||
957 | .irq_reg_cnt = AFE_IRQ_CNT7, | ||
958 | .irq_cnt_shift = 0, | ||
959 | .irq_en_shift = 14, | ||
960 | .irq_fs_shift = 24, | ||
961 | .irq_clr_shift = 6, | ||
962 | }, { | ||
963 | .name = "MOD_DAI", | ||
964 | .id = MTK_AFE_MEMIF_MOD_DAI, | ||
965 | .reg_ofs_base = AFE_MOD_PCM_BASE, | ||
966 | .reg_ofs_cur = AFE_MOD_PCM_CUR, | ||
967 | .fs_shift = 30, | ||
968 | .mono_shift = 30, | ||
969 | .enable_shift = 7, | ||
970 | .irq_reg_cnt = AFE_IRQ_CNT2, | ||
971 | .irq_cnt_shift = 20, | ||
972 | .irq_en_shift = 3, | ||
973 | .irq_fs_shift = 20, | ||
974 | .irq_clr_shift = 3, | ||
975 | }, { | ||
976 | .name = "HDMI", | ||
977 | .id = MTK_AFE_MEMIF_HDMI, | ||
978 | .reg_ofs_base = AFE_HDMI_OUT_BASE, | ||
979 | .reg_ofs_cur = AFE_HDMI_OUT_CUR, | ||
980 | .fs_shift = -1, | ||
981 | .mono_shift = -1, | ||
982 | .enable_shift = -1, | ||
983 | .irq_reg_cnt = AFE_IRQ_CNT5, | ||
984 | .irq_cnt_shift = 0, | ||
985 | .irq_en_shift = 12, | ||
986 | .irq_fs_shift = -1, | ||
987 | .irq_clr_shift = 4, | ||
988 | }, | ||
989 | }; | ||
990 | |||
991 | static const struct regmap_config mtk_afe_regmap_config = { | ||
992 | .reg_bits = 32, | ||
993 | .reg_stride = 4, | ||
994 | .val_bits = 32, | ||
995 | .max_register = AFE_ADDA2_TOP_CON0, | ||
996 | .cache_type = REGCACHE_NONE, | ||
997 | }; | ||
998 | |||
999 | static irqreturn_t mtk_afe_irq_handler(int irq, void *dev_id) | ||
1000 | { | ||
1001 | struct mtk_afe *afe = dev_id; | ||
1002 | unsigned int reg_value, hw_ptr; | ||
1003 | int i, ret; | ||
1004 | |||
1005 | ret = regmap_read(afe->regmap, AFE_IRQ_STATUS, ®_value); | ||
1006 | if (ret) { | ||
1007 | dev_err(afe->dev, "%s irq status err\n", __func__); | ||
1008 | reg_value = AFE_IRQ_STATUS_BITS; | ||
1009 | goto err_irq; | ||
1010 | } | ||
1011 | |||
1012 | for (i = 0; i < MTK_AFE_MEMIF_NUM; i++) { | ||
1013 | struct mtk_afe_memif *memif = &afe->memif[i]; | ||
1014 | |||
1015 | if (!(reg_value & (1 << memif->data->irq_clr_shift))) | ||
1016 | continue; | ||
1017 | |||
1018 | ret = regmap_read(afe->regmap, memif->data->reg_ofs_cur, | ||
1019 | &hw_ptr); | ||
1020 | if (ret || hw_ptr == 0) { | ||
1021 | dev_err(afe->dev, "%s hw_ptr err\n", __func__); | ||
1022 | hw_ptr = memif->phys_buf_addr; | ||
1023 | } | ||
1024 | memif->hw_ptr = hw_ptr - memif->phys_buf_addr; | ||
1025 | snd_pcm_period_elapsed(memif->substream); | ||
1026 | } | ||
1027 | |||
1028 | err_irq: | ||
1029 | /* clear irq */ | ||
1030 | regmap_write(afe->regmap, AFE_IRQ_CLR, reg_value & AFE_IRQ_STATUS_BITS); | ||
1031 | |||
1032 | return IRQ_HANDLED; | ||
1033 | } | ||
1034 | |||
1035 | static int mtk_afe_runtime_suspend(struct device *dev) | ||
1036 | { | ||
1037 | struct mtk_afe *afe = dev_get_drvdata(dev); | ||
1038 | |||
1039 | /* disable AFE clk */ | ||
1040 | regmap_update_bits(afe->regmap, AUDIO_TOP_CON0, | ||
1041 | AUD_TCON0_PDN_AFE, AUD_TCON0_PDN_AFE); | ||
1042 | |||
1043 | clk_disable_unprepare(afe->clocks[MTK_CLK_BCK0]); | ||
1044 | clk_disable_unprepare(afe->clocks[MTK_CLK_BCK1]); | ||
1045 | clk_disable_unprepare(afe->clocks[MTK_CLK_TOP_PDN_AUD]); | ||
1046 | clk_disable_unprepare(afe->clocks[MTK_CLK_TOP_PDN_AUD_BUS]); | ||
1047 | clk_disable_unprepare(afe->clocks[MTK_CLK_INFRASYS_AUD]); | ||
1048 | return 0; | ||
1049 | } | ||
1050 | |||
1051 | static int mtk_afe_runtime_resume(struct device *dev) | ||
1052 | { | ||
1053 | struct mtk_afe *afe = dev_get_drvdata(dev); | ||
1054 | int ret; | ||
1055 | |||
1056 | ret = clk_prepare_enable(afe->clocks[MTK_CLK_INFRASYS_AUD]); | ||
1057 | if (ret) | ||
1058 | return ret; | ||
1059 | |||
1060 | ret = clk_prepare_enable(afe->clocks[MTK_CLK_TOP_PDN_AUD_BUS]); | ||
1061 | if (ret) | ||
1062 | goto err_infra; | ||
1063 | |||
1064 | ret = clk_prepare_enable(afe->clocks[MTK_CLK_TOP_PDN_AUD]); | ||
1065 | if (ret) | ||
1066 | goto err_top_aud_bus; | ||
1067 | |||
1068 | ret = clk_prepare_enable(afe->clocks[MTK_CLK_BCK0]); | ||
1069 | if (ret) | ||
1070 | goto err_top_aud; | ||
1071 | |||
1072 | ret = clk_prepare_enable(afe->clocks[MTK_CLK_BCK1]); | ||
1073 | if (ret) | ||
1074 | goto err_bck0; | ||
1075 | |||
1076 | /* enable AFE clk */ | ||
1077 | regmap_update_bits(afe->regmap, AUDIO_TOP_CON0, AUD_TCON0_PDN_AFE, 0); | ||
1078 | |||
1079 | /* set O3/O4 16bits */ | ||
1080 | regmap_update_bits(afe->regmap, AFE_CONN_24BIT, | ||
1081 | AFE_CONN_24BIT_O03 | AFE_CONN_24BIT_O04, 0); | ||
1082 | |||
1083 | /* unmask all IRQs */ | ||
1084 | regmap_update_bits(afe->regmap, AFE_IRQ_MCU_EN, 0xff, 0xff); | ||
1085 | return 0; | ||
1086 | |||
1087 | err_bck0: | ||
1088 | clk_disable_unprepare(afe->clocks[MTK_CLK_BCK0]); | ||
1089 | err_top_aud: | ||
1090 | clk_disable_unprepare(afe->clocks[MTK_CLK_TOP_PDN_AUD]); | ||
1091 | err_top_aud_bus: | ||
1092 | clk_disable_unprepare(afe->clocks[MTK_CLK_TOP_PDN_AUD_BUS]); | ||
1093 | err_infra: | ||
1094 | clk_disable_unprepare(afe->clocks[MTK_CLK_INFRASYS_AUD]); | ||
1095 | return ret; | ||
1096 | } | ||
1097 | |||
1098 | static int mtk_afe_init_audio_clk(struct mtk_afe *afe) | ||
1099 | { | ||
1100 | size_t i; | ||
1101 | |||
1102 | for (i = 0; i < ARRAY_SIZE(aud_clks); i++) { | ||
1103 | afe->clocks[i] = devm_clk_get(afe->dev, aud_clks[i]); | ||
1104 | if (IS_ERR(afe->clocks[i])) { | ||
1105 | dev_err(afe->dev, "%s devm_clk_get %s fail\n", | ||
1106 | __func__, aud_clks[i]); | ||
1107 | return PTR_ERR(afe->clocks[i]); | ||
1108 | } | ||
1109 | } | ||
1110 | clk_set_rate(afe->clocks[MTK_CLK_BCK0], 22579200); /* 22M */ | ||
1111 | clk_set_rate(afe->clocks[MTK_CLK_BCK1], 24576000); /* 24M */ | ||
1112 | return 0; | ||
1113 | } | ||
1114 | |||
1115 | static int mtk_afe_pcm_dev_probe(struct platform_device *pdev) | ||
1116 | { | ||
1117 | int ret, i; | ||
1118 | unsigned int irq_id; | ||
1119 | struct mtk_afe *afe; | ||
1120 | struct resource *res; | ||
1121 | |||
1122 | afe = devm_kzalloc(&pdev->dev, sizeof(*afe), GFP_KERNEL); | ||
1123 | if (!afe) | ||
1124 | return -ENOMEM; | ||
1125 | |||
1126 | afe->dev = &pdev->dev; | ||
1127 | |||
1128 | irq_id = platform_get_irq(pdev, 0); | ||
1129 | if (!irq_id) { | ||
1130 | dev_err(afe->dev, "np %s no irq\n", afe->dev->of_node->name); | ||
1131 | return -ENXIO; | ||
1132 | } | ||
1133 | ret = devm_request_irq(afe->dev, irq_id, mtk_afe_irq_handler, | ||
1134 | 0, "Afe_ISR_Handle", (void *)afe); | ||
1135 | if (ret) { | ||
1136 | dev_err(afe->dev, "could not request_irq\n"); | ||
1137 | return ret; | ||
1138 | } | ||
1139 | |||
1140 | res = platform_get_resource(pdev, IORESOURCE_MEM, 0); | ||
1141 | afe->base_addr = devm_ioremap_resource(&pdev->dev, res); | ||
1142 | if (IS_ERR(afe->base_addr)) | ||
1143 | return PTR_ERR(afe->base_addr); | ||
1144 | |||
1145 | afe->regmap = devm_regmap_init_mmio(&pdev->dev, afe->base_addr, | ||
1146 | &mtk_afe_regmap_config); | ||
1147 | if (IS_ERR(afe->regmap)) | ||
1148 | return PTR_ERR(afe->regmap); | ||
1149 | |||
1150 | /* initial audio related clock */ | ||
1151 | ret = mtk_afe_init_audio_clk(afe); | ||
1152 | if (ret) { | ||
1153 | dev_err(afe->dev, "mtk_afe_init_audio_clk fail\n"); | ||
1154 | return ret; | ||
1155 | } | ||
1156 | |||
1157 | for (i = 0; i < MTK_AFE_MEMIF_NUM; i++) | ||
1158 | afe->memif[i].data = &memif_data[i]; | ||
1159 | |||
1160 | platform_set_drvdata(pdev, afe); | ||
1161 | |||
1162 | pm_runtime_enable(&pdev->dev); | ||
1163 | if (!pm_runtime_enabled(&pdev->dev)) { | ||
1164 | ret = mtk_afe_runtime_resume(&pdev->dev); | ||
1165 | if (ret) | ||
1166 | goto err_pm_disable; | ||
1167 | } | ||
1168 | |||
1169 | ret = snd_soc_register_platform(&pdev->dev, &mtk_afe_pcm_platform); | ||
1170 | if (ret) | ||
1171 | goto err_pm_disable; | ||
1172 | |||
1173 | ret = snd_soc_register_component(&pdev->dev, | ||
1174 | &mtk_afe_pcm_dai_component, | ||
1175 | mtk_afe_pcm_dais, | ||
1176 | ARRAY_SIZE(mtk_afe_pcm_dais)); | ||
1177 | if (ret) | ||
1178 | goto err_platform; | ||
1179 | |||
1180 | ret = snd_soc_register_component(&pdev->dev, | ||
1181 | &mtk_afe_hdmi_dai_component, | ||
1182 | mtk_afe_hdmi_dais, | ||
1183 | ARRAY_SIZE(mtk_afe_hdmi_dais)); | ||
1184 | if (ret) | ||
1185 | goto err_comp; | ||
1186 | |||
1187 | dev_info(&pdev->dev, "MTK AFE driver initialized.\n"); | ||
1188 | return 0; | ||
1189 | |||
1190 | err_comp: | ||
1191 | snd_soc_unregister_component(&pdev->dev); | ||
1192 | err_platform: | ||
1193 | snd_soc_unregister_platform(&pdev->dev); | ||
1194 | err_pm_disable: | ||
1195 | pm_runtime_disable(&pdev->dev); | ||
1196 | return ret; | ||
1197 | } | ||
1198 | |||
1199 | static int mtk_afe_pcm_dev_remove(struct platform_device *pdev) | ||
1200 | { | ||
1201 | pm_runtime_disable(&pdev->dev); | ||
1202 | snd_soc_unregister_component(&pdev->dev); | ||
1203 | snd_soc_unregister_platform(&pdev->dev); | ||
1204 | return 0; | ||
1205 | } | ||
1206 | |||
1207 | static const struct of_device_id mtk_afe_pcm_dt_match[] = { | ||
1208 | { .compatible = "mediatek,mt8173-afe-pcm", }, | ||
1209 | { } | ||
1210 | }; | ||
1211 | MODULE_DEVICE_TABLE(of, mtk_afe_pcm_dt_match); | ||
1212 | |||
1213 | static const struct dev_pm_ops mtk_afe_pm_ops = { | ||
1214 | SET_RUNTIME_PM_OPS(mtk_afe_runtime_suspend, mtk_afe_runtime_resume, | ||
1215 | NULL) | ||
1216 | }; | ||
1217 | |||
1218 | static struct platform_driver mtk_afe_pcm_driver = { | ||
1219 | .driver = { | ||
1220 | .name = "mtk-afe-pcm", | ||
1221 | .owner = THIS_MODULE, | ||
1222 | .of_match_table = mtk_afe_pcm_dt_match, | ||
1223 | .pm = &mtk_afe_pm_ops, | ||
1224 | }, | ||
1225 | .probe = mtk_afe_pcm_dev_probe, | ||
1226 | .remove = mtk_afe_pcm_dev_remove, | ||
1227 | }; | ||
1228 | |||
1229 | module_platform_driver(mtk_afe_pcm_driver); | ||
1230 | |||
1231 | MODULE_DESCRIPTION("Mediatek ALSA SoC AFE platform driver"); | ||
1232 | MODULE_AUTHOR("Koro Chen <koro.chen@mediatek.com>"); | ||
1233 | MODULE_LICENSE("GPL v2"); | ||
diff --git a/sound/soc/omap/Kconfig b/sound/soc/omap/Kconfig index 6768e4f7d7d0..30d0109703a9 100644 --- a/sound/soc/omap/Kconfig +++ b/sound/soc/omap/Kconfig | |||
@@ -100,12 +100,13 @@ config SND_OMAP_SOC_OMAP_TWL4030 | |||
100 | 100 | ||
101 | config SND_OMAP_SOC_OMAP_ABE_TWL6040 | 101 | config SND_OMAP_SOC_OMAP_ABE_TWL6040 |
102 | tristate "SoC Audio support for OMAP boards using ABE and twl6040 codec" | 102 | tristate "SoC Audio support for OMAP boards using ABE and twl6040 codec" |
103 | depends on TWL6040_CORE && SND_OMAP_SOC && (ARCH_OMAP4 || SOC_OMAP5 || COMPILE_TEST) | 103 | depends on TWL6040_CORE && SND_OMAP_SOC |
104 | depends on ARCH_OMAP4 || (SOC_OMAP5 && MFD_PALMAS) || COMPILE_TEST | ||
104 | select SND_OMAP_SOC_DMIC | 105 | select SND_OMAP_SOC_DMIC |
105 | select SND_OMAP_SOC_MCPDM | 106 | select SND_OMAP_SOC_MCPDM |
106 | select SND_SOC_TWL6040 | 107 | select SND_SOC_TWL6040 |
107 | select SND_SOC_DMIC | 108 | select SND_SOC_DMIC |
108 | select COMMON_CLK_PALMAS if MFD_PALMAS | 109 | select COMMON_CLK_PALMAS if (SOC_OMAP5 && MFD_PALMAS) |
109 | help | 110 | help |
110 | Say Y if you want to add support for SoC audio on OMAP boards using | 111 | Say Y if you want to add support for SoC audio on OMAP boards using |
111 | ABE and twl6040 codec. This driver currently supports: | 112 | ABE and twl6040 codec. This driver currently supports: |
diff --git a/sound/soc/omap/omap-twl4030.c b/sound/soc/omap/omap-twl4030.c index 3673ada43bfb..743131473056 100644 --- a/sound/soc/omap/omap-twl4030.c +++ b/sound/soc/omap/omap-twl4030.c | |||
@@ -159,9 +159,8 @@ static inline void twl4030_disconnect_pin(struct snd_soc_dapm_context *dapm, | |||
159 | 159 | ||
160 | static int omap_twl4030_init(struct snd_soc_pcm_runtime *rtd) | 160 | static int omap_twl4030_init(struct snd_soc_pcm_runtime *rtd) |
161 | { | 161 | { |
162 | struct snd_soc_codec *codec = rtd->codec; | ||
163 | struct snd_soc_card *card = rtd->card; | 162 | struct snd_soc_card *card = rtd->card; |
164 | struct snd_soc_dapm_context *dapm = &codec->dapm; | 163 | struct snd_soc_dapm_context *dapm = &card->dapm; |
165 | struct omap_tw4030_pdata *pdata = dev_get_platdata(card->dev); | 164 | struct omap_tw4030_pdata *pdata = dev_get_platdata(card->dev); |
166 | struct omap_twl4030 *priv = snd_soc_card_get_drvdata(card); | 165 | struct omap_twl4030 *priv = snd_soc_card_get_drvdata(card); |
167 | int ret = 0; | 166 | int ret = 0; |
diff --git a/sound/soc/omap/rx51.c b/sound/soc/omap/rx51.c index c2ddf0fbfa28..3bebfb1d3a6f 100644 --- a/sound/soc/omap/rx51.c +++ b/sound/soc/omap/rx51.c | |||
@@ -245,6 +245,8 @@ static const struct snd_soc_dapm_widget aic34_dapm_widgets[] = { | |||
245 | static const struct snd_soc_dapm_route audio_map[] = { | 245 | static const struct snd_soc_dapm_route audio_map[] = { |
246 | {"Ext Spk", NULL, "HPLOUT"}, | 246 | {"Ext Spk", NULL, "HPLOUT"}, |
247 | {"Ext Spk", NULL, "HPROUT"}, | 247 | {"Ext Spk", NULL, "HPROUT"}, |
248 | {"Ext Spk", NULL, "HPLCOM"}, | ||
249 | {"Ext Spk", NULL, "HPRCOM"}, | ||
248 | {"Headphone Jack", NULL, "LLOUT"}, | 250 | {"Headphone Jack", NULL, "LLOUT"}, |
249 | {"Headphone Jack", NULL, "RLOUT"}, | 251 | {"Headphone Jack", NULL, "RLOUT"}, |
250 | {"FM Transmitter", NULL, "LLOUT"}, | 252 | {"FM Transmitter", NULL, "LLOUT"}, |
@@ -288,15 +290,8 @@ static int rx51_aic34_init(struct snd_soc_pcm_runtime *rtd) | |||
288 | struct snd_soc_codec *codec = rtd->codec; | 290 | struct snd_soc_codec *codec = rtd->codec; |
289 | struct snd_soc_card *card = rtd->card; | 291 | struct snd_soc_card *card = rtd->card; |
290 | struct rx51_audio_pdata *pdata = snd_soc_card_get_drvdata(card); | 292 | struct rx51_audio_pdata *pdata = snd_soc_card_get_drvdata(card); |
291 | |||
292 | struct snd_soc_dapm_context *dapm = &codec->dapm; | ||
293 | int err; | 293 | int err; |
294 | 294 | ||
295 | /* Set up NC codec pins */ | ||
296 | snd_soc_dapm_nc_pin(dapm, "MIC3L"); | ||
297 | snd_soc_dapm_nc_pin(dapm, "MIC3R"); | ||
298 | snd_soc_dapm_nc_pin(dapm, "LINE1R"); | ||
299 | |||
300 | err = tpa6130a2_add_controls(codec); | 295 | err = tpa6130a2_add_controls(codec); |
301 | if (err < 0) { | 296 | if (err < 0) { |
302 | dev_err(card->dev, "Failed to add TPA6130A2 controls\n"); | 297 | dev_err(card->dev, "Failed to add TPA6130A2 controls\n"); |
@@ -383,6 +378,7 @@ static struct snd_soc_card rx51_sound_card = { | |||
383 | .num_aux_devs = ARRAY_SIZE(rx51_aux_dev), | 378 | .num_aux_devs = ARRAY_SIZE(rx51_aux_dev), |
384 | .codec_conf = rx51_codec_conf, | 379 | .codec_conf = rx51_codec_conf, |
385 | .num_configs = ARRAY_SIZE(rx51_codec_conf), | 380 | .num_configs = ARRAY_SIZE(rx51_codec_conf), |
381 | .fully_routed = true, | ||
386 | 382 | ||
387 | .controls = aic34_rx51_controls, | 383 | .controls = aic34_rx51_controls, |
388 | .num_controls = ARRAY_SIZE(aic34_rx51_controls), | 384 | .num_controls = ARRAY_SIZE(aic34_rx51_controls), |
@@ -455,50 +451,36 @@ static int rx51_soc_probe(struct platform_device *pdev) | |||
455 | snd_soc_card_set_drvdata(card, pdata); | 451 | snd_soc_card_set_drvdata(card, pdata); |
456 | 452 | ||
457 | pdata->tvout_selection_gpio = devm_gpiod_get(card->dev, | 453 | pdata->tvout_selection_gpio = devm_gpiod_get(card->dev, |
458 | "tvout-selection"); | 454 | "tvout-selection", |
455 | GPIOD_OUT_LOW); | ||
459 | if (IS_ERR(pdata->tvout_selection_gpio)) { | 456 | if (IS_ERR(pdata->tvout_selection_gpio)) { |
460 | dev_err(card->dev, "could not get tvout selection gpio\n"); | 457 | dev_err(card->dev, "could not get tvout selection gpio\n"); |
461 | return PTR_ERR(pdata->tvout_selection_gpio); | 458 | return PTR_ERR(pdata->tvout_selection_gpio); |
462 | } | 459 | } |
463 | 460 | ||
464 | err = gpiod_direction_output(pdata->tvout_selection_gpio, 0); | ||
465 | if (err) { | ||
466 | dev_err(card->dev, "could not setup tvout selection gpio\n"); | ||
467 | return err; | ||
468 | } | ||
469 | |||
470 | pdata->jack_detection_gpio = devm_gpiod_get(card->dev, | 461 | pdata->jack_detection_gpio = devm_gpiod_get(card->dev, |
471 | "jack-detection"); | 462 | "jack-detection", |
463 | GPIOD_ASIS); | ||
472 | if (IS_ERR(pdata->jack_detection_gpio)) { | 464 | if (IS_ERR(pdata->jack_detection_gpio)) { |
473 | dev_err(card->dev, "could not get jack detection gpio\n"); | 465 | dev_err(card->dev, "could not get jack detection gpio\n"); |
474 | return PTR_ERR(pdata->jack_detection_gpio); | 466 | return PTR_ERR(pdata->jack_detection_gpio); |
475 | } | 467 | } |
476 | 468 | ||
477 | pdata->eci_sw_gpio = devm_gpiod_get(card->dev, "eci-switch"); | 469 | pdata->eci_sw_gpio = devm_gpiod_get(card->dev, "eci-switch", |
470 | GPIOD_OUT_HIGH); | ||
478 | if (IS_ERR(pdata->eci_sw_gpio)) { | 471 | if (IS_ERR(pdata->eci_sw_gpio)) { |
479 | dev_err(card->dev, "could not get eci switch gpio\n"); | 472 | dev_err(card->dev, "could not get eci switch gpio\n"); |
480 | return PTR_ERR(pdata->eci_sw_gpio); | 473 | return PTR_ERR(pdata->eci_sw_gpio); |
481 | } | 474 | } |
482 | 475 | ||
483 | err = gpiod_direction_output(pdata->eci_sw_gpio, 1); | ||
484 | if (err) { | ||
485 | dev_err(card->dev, "could not setup eci switch gpio\n"); | ||
486 | return err; | ||
487 | } | ||
488 | |||
489 | pdata->speaker_amp_gpio = devm_gpiod_get(card->dev, | 476 | pdata->speaker_amp_gpio = devm_gpiod_get(card->dev, |
490 | "speaker-amplifier"); | 477 | "speaker-amplifier", |
478 | GPIOD_OUT_LOW); | ||
491 | if (IS_ERR(pdata->speaker_amp_gpio)) { | 479 | if (IS_ERR(pdata->speaker_amp_gpio)) { |
492 | dev_err(card->dev, "could not get speaker enable gpio\n"); | 480 | dev_err(card->dev, "could not get speaker enable gpio\n"); |
493 | return PTR_ERR(pdata->speaker_amp_gpio); | 481 | return PTR_ERR(pdata->speaker_amp_gpio); |
494 | } | 482 | } |
495 | 483 | ||
496 | err = gpiod_direction_output(pdata->speaker_amp_gpio, 0); | ||
497 | if (err) { | ||
498 | dev_err(card->dev, "could not setup speaker enable gpio\n"); | ||
499 | return err; | ||
500 | } | ||
501 | |||
502 | err = devm_snd_soc_register_card(card->dev, card); | 484 | err = devm_snd_soc_register_card(card->dev, card); |
503 | if (err) { | 485 | if (err) { |
504 | dev_err(&pdev->dev, "snd_soc_register_card failed (%d)\n", err); | 486 | dev_err(&pdev->dev, "snd_soc_register_card failed (%d)\n", err); |
diff --git a/sound/soc/pxa/brownstone.c b/sound/soc/pxa/brownstone.c index 79936e3e80e7..2b26318bc200 100644 --- a/sound/soc/pxa/brownstone.c +++ b/sound/soc/pxa/brownstone.c | |||
@@ -45,29 +45,6 @@ static const struct snd_soc_dapm_route brownstone_audio_map[] = { | |||
45 | {"MICBIAS1", NULL, "Main Mic"}, | 45 | {"MICBIAS1", NULL, "Main Mic"}, |
46 | }; | 46 | }; |
47 | 47 | ||
48 | static int brownstone_wm8994_init(struct snd_soc_pcm_runtime *rtd) | ||
49 | { | ||
50 | struct snd_soc_codec *codec = rtd->codec; | ||
51 | struct snd_soc_dapm_context *dapm = &codec->dapm; | ||
52 | |||
53 | /* set endpoints to not connected */ | ||
54 | snd_soc_dapm_nc_pin(dapm, "HPOUT2P"); | ||
55 | snd_soc_dapm_nc_pin(dapm, "HPOUT2N"); | ||
56 | snd_soc_dapm_nc_pin(dapm, "LINEOUT1N"); | ||
57 | snd_soc_dapm_nc_pin(dapm, "LINEOUT1P"); | ||
58 | snd_soc_dapm_nc_pin(dapm, "LINEOUT2N"); | ||
59 | snd_soc_dapm_nc_pin(dapm, "LINEOUT2P"); | ||
60 | snd_soc_dapm_nc_pin(dapm, "IN1LN"); | ||
61 | snd_soc_dapm_nc_pin(dapm, "IN1LP"); | ||
62 | snd_soc_dapm_nc_pin(dapm, "IN1RP"); | ||
63 | snd_soc_dapm_nc_pin(dapm, "IN2LP:VXRN"); | ||
64 | snd_soc_dapm_nc_pin(dapm, "IN2RN"); | ||
65 | snd_soc_dapm_nc_pin(dapm, "IN2RP:VXRP"); | ||
66 | snd_soc_dapm_nc_pin(dapm, "IN2LN"); | ||
67 | |||
68 | return 0; | ||
69 | } | ||
70 | |||
71 | static int brownstone_wm8994_hw_params(struct snd_pcm_substream *substream, | 48 | static int brownstone_wm8994_hw_params(struct snd_pcm_substream *substream, |
72 | struct snd_pcm_hw_params *params) | 49 | struct snd_pcm_hw_params *params) |
73 | { | 50 | { |
@@ -115,7 +92,6 @@ static struct snd_soc_dai_link brownstone_wm8994_dai[] = { | |||
115 | .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF | | 92 | .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF | |
116 | SND_SOC_DAIFMT_CBS_CFS, | 93 | SND_SOC_DAIFMT_CBS_CFS, |
117 | .ops = &brownstone_ops, | 94 | .ops = &brownstone_ops, |
118 | .init = brownstone_wm8994_init, | ||
119 | }, | 95 | }, |
120 | }; | 96 | }; |
121 | 97 | ||
@@ -132,6 +108,7 @@ static struct snd_soc_card brownstone = { | |||
132 | .num_dapm_widgets = ARRAY_SIZE(brownstone_dapm_widgets), | 108 | .num_dapm_widgets = ARRAY_SIZE(brownstone_dapm_widgets), |
133 | .dapm_routes = brownstone_audio_map, | 109 | .dapm_routes = brownstone_audio_map, |
134 | .num_dapm_routes = ARRAY_SIZE(brownstone_audio_map), | 110 | .num_dapm_routes = ARRAY_SIZE(brownstone_audio_map), |
111 | .fully_routed = true, | ||
135 | }; | 112 | }; |
136 | 113 | ||
137 | static int brownstone_probe(struct platform_device *pdev) | 114 | static int brownstone_probe(struct platform_device *pdev) |
diff --git a/sound/soc/pxa/poodle.c b/sound/soc/pxa/poodle.c index 0fce8c420e96..80b457ac522a 100644 --- a/sound/soc/pxa/poodle.c +++ b/sound/soc/pxa/poodle.c | |||
@@ -192,6 +192,7 @@ static int poodle_amp_event(struct snd_soc_dapm_widget *w, | |||
192 | static const struct snd_soc_dapm_widget wm8731_dapm_widgets[] = { | 192 | static const struct snd_soc_dapm_widget wm8731_dapm_widgets[] = { |
193 | SND_SOC_DAPM_HP("Headphone Jack", NULL), | 193 | SND_SOC_DAPM_HP("Headphone Jack", NULL), |
194 | SND_SOC_DAPM_SPK("Ext Spk", poodle_amp_event), | 194 | SND_SOC_DAPM_SPK("Ext Spk", poodle_amp_event), |
195 | SND_SOC_DAPM_MIC("Microphone", NULL), | ||
195 | }; | 196 | }; |
196 | 197 | ||
197 | /* Corgi machine connections to the codec pins */ | 198 | /* Corgi machine connections to the codec pins */ |
@@ -204,6 +205,8 @@ static const struct snd_soc_dapm_route poodle_audio_map[] = { | |||
204 | /* speaker connected to LOUT, ROUT */ | 205 | /* speaker connected to LOUT, ROUT */ |
205 | {"Ext Spk", NULL, "ROUT"}, | 206 | {"Ext Spk", NULL, "ROUT"}, |
206 | {"Ext Spk", NULL, "LOUT"}, | 207 | {"Ext Spk", NULL, "LOUT"}, |
208 | |||
209 | {"MICIN", NULL, "Microphone"}, | ||
207 | }; | 210 | }; |
208 | 211 | ||
209 | static const char *jack_function[] = {"Off", "Headphone"}; | 212 | static const char *jack_function[] = {"Off", "Headphone"}; |
@@ -220,20 +223,6 @@ static const struct snd_kcontrol_new wm8731_poodle_controls[] = { | |||
220 | poodle_set_spk), | 223 | poodle_set_spk), |
221 | }; | 224 | }; |
222 | 225 | ||
223 | /* | ||
224 | * Logic for a wm8731 as connected on a Sharp SL-C7x0 Device | ||
225 | */ | ||
226 | static int poodle_wm8731_init(struct snd_soc_pcm_runtime *rtd) | ||
227 | { | ||
228 | struct snd_soc_codec *codec = rtd->codec; | ||
229 | struct snd_soc_dapm_context *dapm = &codec->dapm; | ||
230 | |||
231 | snd_soc_dapm_nc_pin(dapm, "LLINEIN"); | ||
232 | snd_soc_dapm_nc_pin(dapm, "RLINEIN"); | ||
233 | |||
234 | return 0; | ||
235 | } | ||
236 | |||
237 | /* poodle digital audio interface glue - connects codec <--> CPU */ | 226 | /* poodle digital audio interface glue - connects codec <--> CPU */ |
238 | static struct snd_soc_dai_link poodle_dai = { | 227 | static struct snd_soc_dai_link poodle_dai = { |
239 | .name = "WM8731", | 228 | .name = "WM8731", |
@@ -242,7 +231,6 @@ static struct snd_soc_dai_link poodle_dai = { | |||
242 | .codec_dai_name = "wm8731-hifi", | 231 | .codec_dai_name = "wm8731-hifi", |
243 | .platform_name = "pxa-pcm-audio", | 232 | .platform_name = "pxa-pcm-audio", |
244 | .codec_name = "wm8731.0-001b", | 233 | .codec_name = "wm8731.0-001b", |
245 | .init = poodle_wm8731_init, | ||
246 | .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF | | 234 | .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF | |
247 | SND_SOC_DAIFMT_CBS_CFS, | 235 | SND_SOC_DAIFMT_CBS_CFS, |
248 | .ops = &poodle_ops, | 236 | .ops = &poodle_ops, |
@@ -261,6 +249,7 @@ static struct snd_soc_card poodle = { | |||
261 | .num_dapm_widgets = ARRAY_SIZE(wm8731_dapm_widgets), | 249 | .num_dapm_widgets = ARRAY_SIZE(wm8731_dapm_widgets), |
262 | .dapm_routes = poodle_audio_map, | 250 | .dapm_routes = poodle_audio_map, |
263 | .num_dapm_routes = ARRAY_SIZE(poodle_audio_map), | 251 | .num_dapm_routes = ARRAY_SIZE(poodle_audio_map), |
252 | .fully_routed = true, | ||
264 | }; | 253 | }; |
265 | 254 | ||
266 | static int poodle_probe(struct platform_device *pdev) | 255 | static int poodle_probe(struct platform_device *pdev) |
diff --git a/sound/soc/pxa/tosa.c b/sound/soc/pxa/tosa.c index cb49284e853a..f59f566551ef 100644 --- a/sound/soc/pxa/tosa.c +++ b/sound/soc/pxa/tosa.c | |||
@@ -185,17 +185,6 @@ static const struct snd_kcontrol_new tosa_controls[] = { | |||
185 | tosa_set_spk), | 185 | tosa_set_spk), |
186 | }; | 186 | }; |
187 | 187 | ||
188 | static int tosa_ac97_init(struct snd_soc_pcm_runtime *rtd) | ||
189 | { | ||
190 | struct snd_soc_codec *codec = rtd->codec; | ||
191 | struct snd_soc_dapm_context *dapm = &codec->dapm; | ||
192 | |||
193 | snd_soc_dapm_nc_pin(dapm, "OUT3"); | ||
194 | snd_soc_dapm_nc_pin(dapm, "MONOOUT"); | ||
195 | |||
196 | return 0; | ||
197 | } | ||
198 | |||
199 | static struct snd_soc_dai_link tosa_dai[] = { | 188 | static struct snd_soc_dai_link tosa_dai[] = { |
200 | { | 189 | { |
201 | .name = "AC97", | 190 | .name = "AC97", |
@@ -204,7 +193,6 @@ static struct snd_soc_dai_link tosa_dai[] = { | |||
204 | .codec_dai_name = "wm9712-hifi", | 193 | .codec_dai_name = "wm9712-hifi", |
205 | .platform_name = "pxa-pcm-audio", | 194 | .platform_name = "pxa-pcm-audio", |
206 | .codec_name = "wm9712-codec", | 195 | .codec_name = "wm9712-codec", |
207 | .init = tosa_ac97_init, | ||
208 | .ops = &tosa_ops, | 196 | .ops = &tosa_ops, |
209 | }, | 197 | }, |
210 | { | 198 | { |
@@ -230,6 +218,7 @@ static struct snd_soc_card tosa = { | |||
230 | .num_dapm_widgets = ARRAY_SIZE(tosa_dapm_widgets), | 218 | .num_dapm_widgets = ARRAY_SIZE(tosa_dapm_widgets), |
231 | .dapm_routes = audio_map, | 219 | .dapm_routes = audio_map, |
232 | .num_dapm_routes = ARRAY_SIZE(audio_map), | 220 | .num_dapm_routes = ARRAY_SIZE(audio_map), |
221 | .fully_routed = true, | ||
233 | }; | 222 | }; |
234 | 223 | ||
235 | static int tosa_probe(struct platform_device *pdev) | 224 | static int tosa_probe(struct platform_device *pdev) |
diff --git a/sound/soc/pxa/z2.c b/sound/soc/pxa/z2.c index bcbfbe8303f7..990b1aa6d7f6 100644 --- a/sound/soc/pxa/z2.c +++ b/sound/soc/pxa/z2.c | |||
@@ -132,16 +132,8 @@ static const struct snd_soc_dapm_route z2_audio_map[] = { | |||
132 | */ | 132 | */ |
133 | static int z2_wm8750_init(struct snd_soc_pcm_runtime *rtd) | 133 | static int z2_wm8750_init(struct snd_soc_pcm_runtime *rtd) |
134 | { | 134 | { |
135 | struct snd_soc_codec *codec = rtd->codec; | ||
136 | struct snd_soc_dapm_context *dapm = &codec->dapm; | ||
137 | int ret; | 135 | int ret; |
138 | 136 | ||
139 | /* NC codec pins */ | ||
140 | snd_soc_dapm_disable_pin(dapm, "LINPUT3"); | ||
141 | snd_soc_dapm_disable_pin(dapm, "RINPUT3"); | ||
142 | snd_soc_dapm_disable_pin(dapm, "OUT3"); | ||
143 | snd_soc_dapm_disable_pin(dapm, "MONO1"); | ||
144 | |||
145 | /* Jack detection API stuff */ | 137 | /* Jack detection API stuff */ |
146 | ret = snd_soc_card_jack_new(rtd->card, "Headset Jack", SND_JACK_HEADSET, | 138 | ret = snd_soc_card_jack_new(rtd->card, "Headset Jack", SND_JACK_HEADSET, |
147 | &hs_jack, hs_jack_pins, | 139 | &hs_jack, hs_jack_pins, |
@@ -189,6 +181,7 @@ static struct snd_soc_card snd_soc_z2 = { | |||
189 | .num_dapm_widgets = ARRAY_SIZE(wm8750_dapm_widgets), | 181 | .num_dapm_widgets = ARRAY_SIZE(wm8750_dapm_widgets), |
190 | .dapm_routes = z2_audio_map, | 182 | .dapm_routes = z2_audio_map, |
191 | .num_dapm_routes = ARRAY_SIZE(z2_audio_map), | 183 | .num_dapm_routes = ARRAY_SIZE(z2_audio_map), |
184 | .fully_routed = true, | ||
192 | }; | 185 | }; |
193 | 186 | ||
194 | static struct platform_device *z2_snd_device; | 187 | static struct platform_device *z2_snd_device; |
diff --git a/sound/soc/qcom/Kconfig b/sound/soc/qcom/Kconfig index 5f58e4f1bca9..807fedfa1c76 100644 --- a/sound/soc/qcom/Kconfig +++ b/sound/soc/qcom/Kconfig | |||
@@ -6,20 +6,38 @@ config SND_SOC_QCOM | |||
6 | 6 | ||
7 | config SND_SOC_LPASS_CPU | 7 | config SND_SOC_LPASS_CPU |
8 | tristate | 8 | tristate |
9 | depends on SND_SOC_QCOM | ||
10 | select REGMAP_MMIO | 9 | select REGMAP_MMIO |
11 | 10 | ||
12 | config SND_SOC_LPASS_PLATFORM | 11 | config SND_SOC_LPASS_PLATFORM |
13 | tristate | 12 | tristate |
14 | depends on SND_SOC_QCOM | ||
15 | select REGMAP_MMIO | 13 | select REGMAP_MMIO |
16 | 14 | ||
17 | config SND_SOC_STORM | 15 | config SND_SOC_LPASS_IPQ806X |
18 | tristate "ASoC I2S support for Storm boards" | 16 | tristate |
19 | depends on (ARCH_QCOM && SND_SOC_QCOM) || COMPILE_TEST | 17 | depends on SND_SOC_QCOM |
18 | select SND_SOC_LPASS_CPU | ||
19 | select SND_SOC_LPASS_PLATFORM | ||
20 | |||
21 | config SND_SOC_LPASS_APQ8016 | ||
22 | tristate | ||
23 | depends on SND_SOC_QCOM | ||
20 | select SND_SOC_LPASS_CPU | 24 | select SND_SOC_LPASS_CPU |
21 | select SND_SOC_LPASS_PLATFORM | 25 | select SND_SOC_LPASS_PLATFORM |
26 | |||
27 | config SND_SOC_STORM | ||
28 | tristate "ASoC I2S support for Storm boards" | ||
29 | depends on SND_SOC_QCOM && (ARCH_QCOM || COMPILE_TEST) | ||
30 | select SND_SOC_LPASS_IPQ806X | ||
22 | select SND_SOC_MAX98357A | 31 | select SND_SOC_MAX98357A |
23 | help | 32 | help |
24 | Say Y or M if you want add support for SoC audio on the | 33 | Say Y or M if you want add support for SoC audio on the |
25 | Qualcomm Technologies IPQ806X-based Storm board. | 34 | Qualcomm Technologies IPQ806X-based Storm board. |
35 | |||
36 | config SND_SOC_APQ8016_SBC | ||
37 | tristate "SoC Audio support for APQ8016 SBC platforms" | ||
38 | depends on SND_SOC_QCOM && (ARCH_QCOM || COMPILE_TEST) | ||
39 | select SND_SOC_LPASS_APQ8016 | ||
40 | help | ||
41 | Support for Qualcomm Technologies LPASS audio block in | ||
42 | APQ8016 SOC-based systems. | ||
43 | Say Y if you want to use audio devices on MI2S. | ||
diff --git a/sound/soc/qcom/Makefile b/sound/soc/qcom/Makefile index c5ce96c761c4..79e5c50a8f71 100644 --- a/sound/soc/qcom/Makefile +++ b/sound/soc/qcom/Makefile | |||
@@ -1,11 +1,17 @@ | |||
1 | # Platform | 1 | # Platform |
2 | snd-soc-lpass-cpu-objs := lpass-cpu.o | 2 | snd-soc-lpass-cpu-objs := lpass-cpu.o |
3 | snd-soc-lpass-platform-objs := lpass-platform.o | 3 | snd-soc-lpass-platform-objs := lpass-platform.o |
4 | snd-soc-lpass-ipq806x-objs := lpass-ipq806x.o | ||
5 | snd-soc-lpass-apq8016-objs := lpass-apq8016.o | ||
4 | 6 | ||
5 | obj-$(CONFIG_SND_SOC_LPASS_CPU) += snd-soc-lpass-cpu.o | 7 | obj-$(CONFIG_SND_SOC_LPASS_CPU) += snd-soc-lpass-cpu.o |
6 | obj-$(CONFIG_SND_SOC_LPASS_PLATFORM) += snd-soc-lpass-platform.o | 8 | obj-$(CONFIG_SND_SOC_LPASS_PLATFORM) += snd-soc-lpass-platform.o |
9 | obj-$(CONFIG_SND_SOC_LPASS_IPQ806X) += snd-soc-lpass-ipq806x.o | ||
10 | obj-$(CONFIG_SND_SOC_LPASS_APQ8016) += snd-soc-lpass-apq8016.o | ||
7 | 11 | ||
8 | # Machine | 12 | # Machine |
9 | snd-soc-storm-objs := storm.o | 13 | snd-soc-storm-objs := storm.o |
14 | snd-soc-apq8016-sbc-objs := apq8016_sbc.o | ||
10 | 15 | ||
11 | obj-$(CONFIG_SND_SOC_STORM) += snd-soc-storm.o | 16 | obj-$(CONFIG_SND_SOC_STORM) += snd-soc-storm.o |
17 | obj-$(CONFIG_SND_SOC_APQ8016_SBC) += snd-soc-apq8016-sbc.o | ||
diff --git a/sound/soc/qcom/apq8016_sbc.c b/sound/soc/qcom/apq8016_sbc.c new file mode 100644 index 000000000000..1efdf0088ecd --- /dev/null +++ b/sound/soc/qcom/apq8016_sbc.c | |||
@@ -0,0 +1,198 @@ | |||
1 | /* | ||
2 | * Copyright (c) 2015 The Linux Foundation. All rights reserved. | ||
3 | * | ||
4 | * This program is free software; you can redistribute it and/or modify | ||
5 | * it under the terms of the GNU General Public License version 2 and | ||
6 | * only version 2 as published by the Free Software Foundation. | ||
7 | * | ||
8 | * This program is distributed in the hope that it will be useful, | ||
9 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
10 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
11 | * GNU General Public License for more details. | ||
12 | * | ||
13 | */ | ||
14 | |||
15 | #include <linux/device.h> | ||
16 | #include <linux/module.h> | ||
17 | #include <linux/kernel.h> | ||
18 | #include <linux/io.h> | ||
19 | #include <linux/of.h> | ||
20 | #include <linux/clk.h> | ||
21 | #include <linux/platform_device.h> | ||
22 | #include <sound/pcm.h> | ||
23 | #include <sound/pcm_params.h> | ||
24 | #include <sound/soc.h> | ||
25 | #include <dt-bindings/sound/apq8016-lpass.h> | ||
26 | |||
27 | struct apq8016_sbc_data { | ||
28 | void __iomem *mic_iomux; | ||
29 | void __iomem *spkr_iomux; | ||
30 | struct snd_soc_dai_link dai_link[]; /* dynamically allocated */ | ||
31 | }; | ||
32 | |||
33 | #define MIC_CTRL_QUA_WS_SLAVE_SEL_10 BIT(17) | ||
34 | #define MIC_CTRL_TLMM_SCLK_EN BIT(1) | ||
35 | #define SPKR_CTL_PRI_WS_SLAVE_SEL_11 (BIT(17) | BIT(16)) | ||
36 | |||
37 | static int apq8016_sbc_dai_init(struct snd_soc_pcm_runtime *rtd) | ||
38 | { | ||
39 | struct snd_soc_dai *cpu_dai = rtd->cpu_dai; | ||
40 | struct snd_soc_card *card = rtd->card; | ||
41 | struct apq8016_sbc_data *pdata = snd_soc_card_get_drvdata(card); | ||
42 | int rval = 0; | ||
43 | |||
44 | switch (cpu_dai->id) { | ||
45 | case MI2S_PRIMARY: | ||
46 | writel(readl(pdata->spkr_iomux) | SPKR_CTL_PRI_WS_SLAVE_SEL_11, | ||
47 | pdata->spkr_iomux); | ||
48 | break; | ||
49 | |||
50 | case MI2S_QUATERNARY: | ||
51 | /* Configure the Quat MI2S to TLMM */ | ||
52 | writel(readl(pdata->mic_iomux) | MIC_CTRL_QUA_WS_SLAVE_SEL_10 | | ||
53 | MIC_CTRL_TLMM_SCLK_EN, | ||
54 | pdata->mic_iomux); | ||
55 | break; | ||
56 | |||
57 | default: | ||
58 | dev_err(card->dev, "unsupported cpu dai configuration\n"); | ||
59 | rval = -EINVAL; | ||
60 | break; | ||
61 | |||
62 | } | ||
63 | |||
64 | return rval; | ||
65 | } | ||
66 | |||
67 | static struct apq8016_sbc_data *apq8016_sbc_parse_of(struct snd_soc_card *card) | ||
68 | { | ||
69 | struct device *dev = card->dev; | ||
70 | struct snd_soc_dai_link *link; | ||
71 | struct device_node *np, *codec, *cpu, *node = dev->of_node; | ||
72 | struct apq8016_sbc_data *data; | ||
73 | int ret, num_links; | ||
74 | |||
75 | ret = snd_soc_of_parse_card_name(card, "qcom,model"); | ||
76 | if (ret) { | ||
77 | dev_err(dev, "Error parsing card name: %d\n", ret); | ||
78 | return ERR_PTR(ret); | ||
79 | } | ||
80 | |||
81 | /* Populate links */ | ||
82 | num_links = of_get_child_count(node); | ||
83 | |||
84 | /* Allocate the private data and the DAI link array */ | ||
85 | data = devm_kzalloc(dev, sizeof(*data) + sizeof(*link) * num_links, | ||
86 | GFP_KERNEL); | ||
87 | if (!data) | ||
88 | return ERR_PTR(-ENOMEM); | ||
89 | |||
90 | card->dai_link = &data->dai_link[0]; | ||
91 | card->num_links = num_links; | ||
92 | |||
93 | link = data->dai_link; | ||
94 | |||
95 | for_each_child_of_node(node, np) { | ||
96 | cpu = of_get_child_by_name(np, "cpu"); | ||
97 | codec = of_get_child_by_name(np, "codec"); | ||
98 | |||
99 | if (!cpu || !codec) { | ||
100 | dev_err(dev, "Can't find cpu/codec DT node\n"); | ||
101 | return ERR_PTR(-EINVAL); | ||
102 | } | ||
103 | |||
104 | link->cpu_of_node = of_parse_phandle(cpu, "sound-dai", 0); | ||
105 | if (!link->cpu_of_node) { | ||
106 | dev_err(card->dev, "error getting cpu phandle\n"); | ||
107 | return ERR_PTR(-EINVAL); | ||
108 | } | ||
109 | |||
110 | link->codec_of_node = of_parse_phandle(codec, "sound-dai", 0); | ||
111 | if (!link->codec_of_node) { | ||
112 | dev_err(card->dev, "error getting codec phandle\n"); | ||
113 | return ERR_PTR(-EINVAL); | ||
114 | } | ||
115 | |||
116 | ret = snd_soc_of_get_dai_name(cpu, &link->cpu_dai_name); | ||
117 | if (ret) { | ||
118 | dev_err(card->dev, "error getting cpu dai name\n"); | ||
119 | return ERR_PTR(ret); | ||
120 | } | ||
121 | |||
122 | ret = snd_soc_of_get_dai_name(codec, &link->codec_dai_name); | ||
123 | if (ret) { | ||
124 | dev_err(card->dev, "error getting codec dai name\n"); | ||
125 | return ERR_PTR(ret); | ||
126 | } | ||
127 | |||
128 | link->platform_of_node = link->cpu_of_node; | ||
129 | /* For now we only support playback */ | ||
130 | link->playback_only = true; | ||
131 | |||
132 | ret = of_property_read_string(np, "link-name", &link->name); | ||
133 | if (ret) { | ||
134 | dev_err(card->dev, "error getting codec dai_link name\n"); | ||
135 | return ERR_PTR(ret); | ||
136 | } | ||
137 | |||
138 | link->stream_name = link->name; | ||
139 | link->init = apq8016_sbc_dai_init; | ||
140 | link++; | ||
141 | } | ||
142 | |||
143 | return data; | ||
144 | } | ||
145 | |||
146 | static int apq8016_sbc_platform_probe(struct platform_device *pdev) | ||
147 | { | ||
148 | struct device *dev = &pdev->dev; | ||
149 | struct snd_soc_card *card; | ||
150 | struct apq8016_sbc_data *data; | ||
151 | struct resource *res; | ||
152 | |||
153 | card = devm_kzalloc(dev, sizeof(*card), GFP_KERNEL); | ||
154 | if (!card) | ||
155 | return -ENOMEM; | ||
156 | |||
157 | card->dev = dev; | ||
158 | data = apq8016_sbc_parse_of(card); | ||
159 | if (IS_ERR(data)) { | ||
160 | dev_err(&pdev->dev, "Error resolving dai links: %ld\n", | ||
161 | PTR_ERR(data)); | ||
162 | return PTR_ERR(data); | ||
163 | } | ||
164 | |||
165 | res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "mic-iomux"); | ||
166 | data->mic_iomux = devm_ioremap_resource(dev, res); | ||
167 | if (IS_ERR(data->mic_iomux)) | ||
168 | return PTR_ERR(data->mic_iomux); | ||
169 | |||
170 | res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "spkr-iomux"); | ||
171 | data->spkr_iomux = devm_ioremap_resource(dev, res); | ||
172 | if (IS_ERR(data->spkr_iomux)) | ||
173 | return PTR_ERR(data->spkr_iomux); | ||
174 | |||
175 | platform_set_drvdata(pdev, data); | ||
176 | snd_soc_card_set_drvdata(card, data); | ||
177 | |||
178 | return devm_snd_soc_register_card(&pdev->dev, card); | ||
179 | } | ||
180 | |||
181 | static const struct of_device_id apq8016_sbc_device_id[] = { | ||
182 | { .compatible = "qcom,apq8016-sbc-sndcard" }, | ||
183 | {}, | ||
184 | }; | ||
185 | MODULE_DEVICE_TABLE(of, apq8016_sbc_device_id); | ||
186 | |||
187 | static struct platform_driver apq8016_sbc_platform_driver = { | ||
188 | .driver = { | ||
189 | .name = "qcom-apq8016-sbc", | ||
190 | .of_match_table = of_match_ptr(apq8016_sbc_device_id), | ||
191 | }, | ||
192 | .probe = apq8016_sbc_platform_probe, | ||
193 | }; | ||
194 | module_platform_driver(apq8016_sbc_platform_driver); | ||
195 | |||
196 | MODULE_AUTHOR("Srinivas Kandagatla <srinivas.kandagatla@linaro.org"); | ||
197 | MODULE_DESCRIPTION("APQ8016 ASoC Machine Driver"); | ||
198 | MODULE_LICENSE("GPL v2"); | ||
diff --git a/sound/soc/qcom/lpass-apq8016.c b/sound/soc/qcom/lpass-apq8016.c new file mode 100644 index 000000000000..94efc01020c4 --- /dev/null +++ b/sound/soc/qcom/lpass-apq8016.c | |||
@@ -0,0 +1,242 @@ | |||
1 | /* | ||
2 | * Copyright (c) 2010-2011,2013-2015 The Linux Foundation. All rights reserved. | ||
3 | * | ||
4 | * This program is free software; you can redistribute it and/or modify | ||
5 | * it under the terms of the GNU General Public License version 2 and | ||
6 | * only version 2 as published by the Free Software Foundation. | ||
7 | * | ||
8 | * This program is distributed in the hope that it will be useful, | ||
9 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
10 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
11 | * GNU General Public License for more details. | ||
12 | * | ||
13 | * lpass-apq8016.c -- ALSA SoC CPU DAI driver for APQ8016 LPASS | ||
14 | * | ||
15 | */ | ||
16 | |||
17 | |||
18 | #include <linux/clk.h> | ||
19 | #include <linux/device.h> | ||
20 | #include <linux/err.h> | ||
21 | #include <linux/kernel.h> | ||
22 | #include <linux/module.h> | ||
23 | #include <linux/of.h> | ||
24 | #include <linux/platform_device.h> | ||
25 | #include <sound/pcm.h> | ||
26 | #include <sound/pcm_params.h> | ||
27 | #include <sound/soc.h> | ||
28 | #include <sound/soc-dai.h> | ||
29 | |||
30 | #include <dt-bindings/sound/apq8016-lpass.h> | ||
31 | #include "lpass-lpaif-reg.h" | ||
32 | #include "lpass.h" | ||
33 | |||
34 | static struct snd_soc_dai_driver apq8016_lpass_cpu_dai_driver[] = { | ||
35 | [MI2S_PRIMARY] = { | ||
36 | .id = MI2S_PRIMARY, | ||
37 | .name = "Primary MI2S", | ||
38 | .playback = { | ||
39 | .stream_name = "Primary Playback", | ||
40 | .formats = SNDRV_PCM_FMTBIT_S16 | | ||
41 | SNDRV_PCM_FMTBIT_S24 | | ||
42 | SNDRV_PCM_FMTBIT_S32, | ||
43 | .rates = SNDRV_PCM_RATE_8000 | | ||
44 | SNDRV_PCM_RATE_16000 | | ||
45 | SNDRV_PCM_RATE_32000 | | ||
46 | SNDRV_PCM_RATE_48000 | | ||
47 | SNDRV_PCM_RATE_96000, | ||
48 | .rate_min = 8000, | ||
49 | .rate_max = 96000, | ||
50 | .channels_min = 1, | ||
51 | .channels_max = 8, | ||
52 | }, | ||
53 | .probe = &asoc_qcom_lpass_cpu_dai_probe, | ||
54 | .ops = &asoc_qcom_lpass_cpu_dai_ops, | ||
55 | }, | ||
56 | [MI2S_SECONDARY] = { | ||
57 | .id = MI2S_SECONDARY, | ||
58 | .name = "Secondary MI2S", | ||
59 | .playback = { | ||
60 | .stream_name = "Secondary Playback", | ||
61 | .formats = SNDRV_PCM_FMTBIT_S16 | | ||
62 | SNDRV_PCM_FMTBIT_S24 | | ||
63 | SNDRV_PCM_FMTBIT_S32, | ||
64 | .rates = SNDRV_PCM_RATE_8000 | | ||
65 | SNDRV_PCM_RATE_16000 | | ||
66 | SNDRV_PCM_RATE_32000 | | ||
67 | SNDRV_PCM_RATE_48000 | | ||
68 | SNDRV_PCM_RATE_96000, | ||
69 | .rate_min = 8000, | ||
70 | .rate_max = 96000, | ||
71 | .channels_min = 1, | ||
72 | .channels_max = 8, | ||
73 | }, | ||
74 | .probe = &asoc_qcom_lpass_cpu_dai_probe, | ||
75 | .ops = &asoc_qcom_lpass_cpu_dai_ops, | ||
76 | }, | ||
77 | [MI2S_TERTIARY] = { | ||
78 | .id = MI2S_TERTIARY, | ||
79 | .name = "Tertiary MI2S", | ||
80 | .capture = { | ||
81 | .stream_name = "Tertiary Capture", | ||
82 | .formats = SNDRV_PCM_FMTBIT_S16 | | ||
83 | SNDRV_PCM_FMTBIT_S24 | | ||
84 | SNDRV_PCM_FMTBIT_S32, | ||
85 | .rates = SNDRV_PCM_RATE_8000 | | ||
86 | SNDRV_PCM_RATE_16000 | | ||
87 | SNDRV_PCM_RATE_32000 | | ||
88 | SNDRV_PCM_RATE_48000 | | ||
89 | SNDRV_PCM_RATE_96000, | ||
90 | .rate_min = 8000, | ||
91 | .rate_max = 96000, | ||
92 | .channels_min = 1, | ||
93 | .channels_max = 8, | ||
94 | }, | ||
95 | .probe = &asoc_qcom_lpass_cpu_dai_probe, | ||
96 | .ops = &asoc_qcom_lpass_cpu_dai_ops, | ||
97 | }, | ||
98 | [MI2S_QUATERNARY] = { | ||
99 | .id = MI2S_QUATERNARY, | ||
100 | .name = "Quatenary MI2S", | ||
101 | .playback = { | ||
102 | .stream_name = "Quatenary Playback", | ||
103 | .formats = SNDRV_PCM_FMTBIT_S16 | | ||
104 | SNDRV_PCM_FMTBIT_S24 | | ||
105 | SNDRV_PCM_FMTBIT_S32, | ||
106 | .rates = SNDRV_PCM_RATE_8000 | | ||
107 | SNDRV_PCM_RATE_16000 | | ||
108 | SNDRV_PCM_RATE_32000 | | ||
109 | SNDRV_PCM_RATE_48000 | | ||
110 | SNDRV_PCM_RATE_96000, | ||
111 | .rate_min = 8000, | ||
112 | .rate_max = 96000, | ||
113 | .channels_min = 1, | ||
114 | .channels_max = 8, | ||
115 | }, | ||
116 | .capture = { | ||
117 | .stream_name = "Quatenary Capture", | ||
118 | .formats = SNDRV_PCM_FMTBIT_S16 | | ||
119 | SNDRV_PCM_FMTBIT_S24 | | ||
120 | SNDRV_PCM_FMTBIT_S32, | ||
121 | .rates = SNDRV_PCM_RATE_8000 | | ||
122 | SNDRV_PCM_RATE_16000 | | ||
123 | SNDRV_PCM_RATE_32000 | | ||
124 | SNDRV_PCM_RATE_48000 | | ||
125 | SNDRV_PCM_RATE_96000, | ||
126 | .rate_min = 8000, | ||
127 | .rate_max = 96000, | ||
128 | .channels_min = 1, | ||
129 | .channels_max = 8, | ||
130 | }, | ||
131 | .probe = &asoc_qcom_lpass_cpu_dai_probe, | ||
132 | .ops = &asoc_qcom_lpass_cpu_dai_ops, | ||
133 | }, | ||
134 | }; | ||
135 | |||
136 | static int apq8016_lpass_alloc_dma_channel(struct lpass_data *drvdata) | ||
137 | { | ||
138 | struct lpass_variant *v = drvdata->variant; | ||
139 | int chan = find_first_zero_bit(&drvdata->rdma_ch_bit_map, | ||
140 | v->rdma_channels); | ||
141 | |||
142 | if (chan >= v->rdma_channels) | ||
143 | return -EBUSY; | ||
144 | |||
145 | set_bit(chan, &drvdata->rdma_ch_bit_map); | ||
146 | |||
147 | return chan; | ||
148 | } | ||
149 | |||
150 | static int apq8016_lpass_free_dma_channel(struct lpass_data *drvdata, int chan) | ||
151 | { | ||
152 | clear_bit(chan, &drvdata->rdma_ch_bit_map); | ||
153 | |||
154 | return 0; | ||
155 | } | ||
156 | |||
157 | static int apq8016_lpass_init(struct platform_device *pdev) | ||
158 | { | ||
159 | struct lpass_data *drvdata = platform_get_drvdata(pdev); | ||
160 | struct device *dev = &pdev->dev; | ||
161 | int ret; | ||
162 | |||
163 | drvdata->pcnoc_mport_clk = devm_clk_get(dev, "pcnoc-mport-clk"); | ||
164 | if (IS_ERR(drvdata->pcnoc_mport_clk)) { | ||
165 | dev_err(&pdev->dev, "%s() error getting pcnoc-mport-clk: %ld\n", | ||
166 | __func__, PTR_ERR(drvdata->pcnoc_mport_clk)); | ||
167 | return PTR_ERR(drvdata->pcnoc_mport_clk); | ||
168 | } | ||
169 | |||
170 | ret = clk_prepare_enable(drvdata->pcnoc_mport_clk); | ||
171 | if (ret) { | ||
172 | dev_err(&pdev->dev, "%s() Error enabling pcnoc-mport-clk: %d\n", | ||
173 | __func__, ret); | ||
174 | return ret; | ||
175 | } | ||
176 | |||
177 | drvdata->pcnoc_sway_clk = devm_clk_get(dev, "pcnoc-sway-clk"); | ||
178 | if (IS_ERR(drvdata->pcnoc_sway_clk)) { | ||
179 | dev_err(&pdev->dev, "%s() error getting pcnoc-sway-clk: %ld\n", | ||
180 | __func__, PTR_ERR(drvdata->pcnoc_sway_clk)); | ||
181 | return PTR_ERR(drvdata->pcnoc_sway_clk); | ||
182 | } | ||
183 | |||
184 | ret = clk_prepare_enable(drvdata->pcnoc_sway_clk); | ||
185 | if (ret) { | ||
186 | dev_err(&pdev->dev, "%s() Error enabling pcnoc_sway_clk: %d\n", | ||
187 | __func__, ret); | ||
188 | return ret; | ||
189 | } | ||
190 | |||
191 | return 0; | ||
192 | } | ||
193 | |||
194 | static int apq8016_lpass_exit(struct platform_device *pdev) | ||
195 | { | ||
196 | struct lpass_data *drvdata = platform_get_drvdata(pdev); | ||
197 | |||
198 | clk_disable_unprepare(drvdata->pcnoc_mport_clk); | ||
199 | clk_disable_unprepare(drvdata->pcnoc_sway_clk); | ||
200 | |||
201 | return 0; | ||
202 | } | ||
203 | |||
204 | |||
205 | static struct lpass_variant apq8016_data = { | ||
206 | .i2sctrl_reg_base = 0x1000, | ||
207 | .i2sctrl_reg_stride = 0x1000, | ||
208 | .i2s_ports = 4, | ||
209 | .irq_reg_base = 0x6000, | ||
210 | .irq_reg_stride = 0x1000, | ||
211 | .irq_ports = 3, | ||
212 | .rdma_reg_base = 0x8400, | ||
213 | .rdma_reg_stride = 0x1000, | ||
214 | .rdma_channels = 2, | ||
215 | .rdmactl_audif_start = 1, | ||
216 | .dai_driver = apq8016_lpass_cpu_dai_driver, | ||
217 | .num_dai = ARRAY_SIZE(apq8016_lpass_cpu_dai_driver), | ||
218 | .init = apq8016_lpass_init, | ||
219 | .exit = apq8016_lpass_exit, | ||
220 | .alloc_dma_channel = apq8016_lpass_alloc_dma_channel, | ||
221 | .free_dma_channel = apq8016_lpass_free_dma_channel, | ||
222 | }; | ||
223 | |||
224 | static const struct of_device_id apq8016_lpass_cpu_device_id[] = { | ||
225 | { .compatible = "qcom,lpass-cpu-apq8016", .data = &apq8016_data }, | ||
226 | {} | ||
227 | }; | ||
228 | MODULE_DEVICE_TABLE(of, apq8016_lpass_cpu_device_id); | ||
229 | |||
230 | static struct platform_driver apq8016_lpass_cpu_platform_driver = { | ||
231 | .driver = { | ||
232 | .name = "apq8016-lpass-cpu", | ||
233 | .of_match_table = of_match_ptr(apq8016_lpass_cpu_device_id), | ||
234 | }, | ||
235 | .probe = asoc_qcom_lpass_cpu_platform_probe, | ||
236 | .remove = asoc_qcom_lpass_cpu_platform_remove, | ||
237 | }; | ||
238 | module_platform_driver(apq8016_lpass_cpu_platform_driver); | ||
239 | |||
240 | MODULE_DESCRIPTION("APQ8016 LPASS CPU Driver"); | ||
241 | MODULE_LICENSE("GPL v2"); | ||
242 | |||
diff --git a/sound/soc/qcom/lpass-cpu.c b/sound/soc/qcom/lpass-cpu.c index 6698d058de29..23f3d59e6d09 100644 --- a/sound/soc/qcom/lpass-cpu.c +++ b/sound/soc/qcom/lpass-cpu.c | |||
@@ -14,21 +14,17 @@ | |||
14 | */ | 14 | */ |
15 | 15 | ||
16 | #include <linux/clk.h> | 16 | #include <linux/clk.h> |
17 | #include <linux/compiler.h> | ||
18 | #include <linux/device.h> | ||
19 | #include <linux/err.h> | ||
20 | #include <linux/ioport.h> | ||
21 | #include <linux/kernel.h> | 17 | #include <linux/kernel.h> |
22 | #include <linux/mod_devicetable.h> | ||
23 | #include <linux/module.h> | 18 | #include <linux/module.h> |
24 | #include <linux/of.h> | 19 | #include <linux/of.h> |
20 | #include <linux/of_device.h> | ||
25 | #include <linux/platform_device.h> | 21 | #include <linux/platform_device.h> |
26 | #include <sound/pcm.h> | 22 | #include <sound/pcm.h> |
27 | #include <sound/pcm_params.h> | 23 | #include <sound/pcm_params.h> |
28 | #include <linux/regmap.h> | 24 | #include <linux/regmap.h> |
29 | #include <sound/soc.h> | 25 | #include <sound/soc.h> |
30 | #include <sound/soc-dai.h> | 26 | #include <sound/soc-dai.h> |
31 | #include "lpass-lpaif-ipq806x.h" | 27 | #include "lpass-lpaif-reg.h" |
32 | #include "lpass.h" | 28 | #include "lpass.h" |
33 | 29 | ||
34 | static int lpass_cpu_daiops_set_sysclk(struct snd_soc_dai *dai, int clk_id, | 30 | static int lpass_cpu_daiops_set_sysclk(struct snd_soc_dai *dai, int clk_id, |
@@ -37,7 +33,10 @@ static int lpass_cpu_daiops_set_sysclk(struct snd_soc_dai *dai, int clk_id, | |||
37 | struct lpass_data *drvdata = snd_soc_dai_get_drvdata(dai); | 33 | struct lpass_data *drvdata = snd_soc_dai_get_drvdata(dai); |
38 | int ret; | 34 | int ret; |
39 | 35 | ||
40 | ret = clk_set_rate(drvdata->mi2s_osr_clk, freq); | 36 | if (IS_ERR(drvdata->mi2s_osr_clk[dai->driver->id])) |
37 | return 0; | ||
38 | |||
39 | ret = clk_set_rate(drvdata->mi2s_osr_clk[dai->driver->id], freq); | ||
41 | if (ret) | 40 | if (ret) |
42 | dev_err(dai->dev, "%s() error setting mi2s osrclk to %u: %d\n", | 41 | dev_err(dai->dev, "%s() error setting mi2s osrclk to %u: %d\n", |
43 | __func__, freq, ret); | 42 | __func__, freq, ret); |
@@ -51,18 +50,23 @@ static int lpass_cpu_daiops_startup(struct snd_pcm_substream *substream, | |||
51 | struct lpass_data *drvdata = snd_soc_dai_get_drvdata(dai); | 50 | struct lpass_data *drvdata = snd_soc_dai_get_drvdata(dai); |
52 | int ret; | 51 | int ret; |
53 | 52 | ||
54 | ret = clk_prepare_enable(drvdata->mi2s_osr_clk); | 53 | if (!IS_ERR(drvdata->mi2s_osr_clk[dai->driver->id])) { |
55 | if (ret) { | 54 | ret = clk_prepare_enable( |
56 | dev_err(dai->dev, "%s() error in enabling mi2s osr clk: %d\n", | 55 | drvdata->mi2s_osr_clk[dai->driver->id]); |
57 | __func__, ret); | 56 | if (ret) { |
58 | return ret; | 57 | dev_err(dai->dev, "%s() error in enabling mi2s osr clk: %d\n", |
58 | __func__, ret); | ||
59 | return ret; | ||
60 | } | ||
59 | } | 61 | } |
60 | 62 | ||
61 | ret = clk_prepare_enable(drvdata->mi2s_bit_clk); | 63 | ret = clk_prepare_enable(drvdata->mi2s_bit_clk[dai->driver->id]); |
62 | if (ret) { | 64 | if (ret) { |
63 | dev_err(dai->dev, "%s() error in enabling mi2s bit clk: %d\n", | 65 | dev_err(dai->dev, "%s() error in enabling mi2s bit clk: %d\n", |
64 | __func__, ret); | 66 | __func__, ret); |
65 | clk_disable_unprepare(drvdata->mi2s_osr_clk); | 67 | if (!IS_ERR(drvdata->mi2s_osr_clk[dai->driver->id])) |
68 | clk_disable_unprepare( | ||
69 | drvdata->mi2s_osr_clk[dai->driver->id]); | ||
66 | return ret; | 70 | return ret; |
67 | } | 71 | } |
68 | 72 | ||
@@ -74,8 +78,10 @@ static void lpass_cpu_daiops_shutdown(struct snd_pcm_substream *substream, | |||
74 | { | 78 | { |
75 | struct lpass_data *drvdata = snd_soc_dai_get_drvdata(dai); | 79 | struct lpass_data *drvdata = snd_soc_dai_get_drvdata(dai); |
76 | 80 | ||
77 | clk_disable_unprepare(drvdata->mi2s_bit_clk); | 81 | clk_disable_unprepare(drvdata->mi2s_bit_clk[dai->driver->id]); |
78 | clk_disable_unprepare(drvdata->mi2s_osr_clk); | 82 | |
83 | if (!IS_ERR(drvdata->mi2s_osr_clk[dai->driver->id])) | ||
84 | clk_disable_unprepare(drvdata->mi2s_osr_clk[dai->driver->id]); | ||
79 | } | 85 | } |
80 | 86 | ||
81 | static int lpass_cpu_daiops_hw_params(struct snd_pcm_substream *substream, | 87 | static int lpass_cpu_daiops_hw_params(struct snd_pcm_substream *substream, |
@@ -142,14 +148,16 @@ static int lpass_cpu_daiops_hw_params(struct snd_pcm_substream *substream, | |||
142 | } | 148 | } |
143 | 149 | ||
144 | ret = regmap_write(drvdata->lpaif_map, | 150 | ret = regmap_write(drvdata->lpaif_map, |
145 | LPAIF_I2SCTL_REG(LPAIF_I2S_PORT_MI2S), regval); | 151 | LPAIF_I2SCTL_REG(drvdata->variant, dai->driver->id), |
152 | regval); | ||
146 | if (ret) { | 153 | if (ret) { |
147 | dev_err(dai->dev, "%s() error writing to i2sctl reg: %d\n", | 154 | dev_err(dai->dev, "%s() error writing to i2sctl reg: %d\n", |
148 | __func__, ret); | 155 | __func__, ret); |
149 | return ret; | 156 | return ret; |
150 | } | 157 | } |
151 | 158 | ||
152 | ret = clk_set_rate(drvdata->mi2s_bit_clk, rate * bitwidth * 2); | 159 | ret = clk_set_rate(drvdata->mi2s_bit_clk[dai->driver->id], |
160 | rate * bitwidth * 2); | ||
153 | if (ret) { | 161 | if (ret) { |
154 | dev_err(dai->dev, "%s() error setting mi2s bitclk to %u: %d\n", | 162 | dev_err(dai->dev, "%s() error setting mi2s bitclk to %u: %d\n", |
155 | __func__, rate * bitwidth * 2, ret); | 163 | __func__, rate * bitwidth * 2, ret); |
@@ -166,7 +174,8 @@ static int lpass_cpu_daiops_hw_free(struct snd_pcm_substream *substream, | |||
166 | int ret; | 174 | int ret; |
167 | 175 | ||
168 | ret = regmap_write(drvdata->lpaif_map, | 176 | ret = regmap_write(drvdata->lpaif_map, |
169 | LPAIF_I2SCTL_REG(LPAIF_I2S_PORT_MI2S), 0); | 177 | LPAIF_I2SCTL_REG(drvdata->variant, dai->driver->id), |
178 | 0); | ||
170 | if (ret) | 179 | if (ret) |
171 | dev_err(dai->dev, "%s() error writing to i2sctl reg: %d\n", | 180 | dev_err(dai->dev, "%s() error writing to i2sctl reg: %d\n", |
172 | __func__, ret); | 181 | __func__, ret); |
@@ -181,7 +190,7 @@ static int lpass_cpu_daiops_prepare(struct snd_pcm_substream *substream, | |||
181 | int ret; | 190 | int ret; |
182 | 191 | ||
183 | ret = regmap_update_bits(drvdata->lpaif_map, | 192 | ret = regmap_update_bits(drvdata->lpaif_map, |
184 | LPAIF_I2SCTL_REG(LPAIF_I2S_PORT_MI2S), | 193 | LPAIF_I2SCTL_REG(drvdata->variant, dai->driver->id), |
185 | LPAIF_I2SCTL_SPKEN_MASK, LPAIF_I2SCTL_SPKEN_ENABLE); | 194 | LPAIF_I2SCTL_SPKEN_MASK, LPAIF_I2SCTL_SPKEN_ENABLE); |
186 | if (ret) | 195 | if (ret) |
187 | dev_err(dai->dev, "%s() error writing to i2sctl reg: %d\n", | 196 | dev_err(dai->dev, "%s() error writing to i2sctl reg: %d\n", |
@@ -194,14 +203,15 @@ static int lpass_cpu_daiops_trigger(struct snd_pcm_substream *substream, | |||
194 | int cmd, struct snd_soc_dai *dai) | 203 | int cmd, struct snd_soc_dai *dai) |
195 | { | 204 | { |
196 | struct lpass_data *drvdata = snd_soc_dai_get_drvdata(dai); | 205 | struct lpass_data *drvdata = snd_soc_dai_get_drvdata(dai); |
197 | int ret; | 206 | int ret = -EINVAL; |
198 | 207 | ||
199 | switch (cmd) { | 208 | switch (cmd) { |
200 | case SNDRV_PCM_TRIGGER_START: | 209 | case SNDRV_PCM_TRIGGER_START: |
201 | case SNDRV_PCM_TRIGGER_RESUME: | 210 | case SNDRV_PCM_TRIGGER_RESUME: |
202 | case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: | 211 | case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: |
203 | ret = regmap_update_bits(drvdata->lpaif_map, | 212 | ret = regmap_update_bits(drvdata->lpaif_map, |
204 | LPAIF_I2SCTL_REG(LPAIF_I2S_PORT_MI2S), | 213 | LPAIF_I2SCTL_REG(drvdata->variant, |
214 | dai->driver->id), | ||
205 | LPAIF_I2SCTL_SPKEN_MASK, | 215 | LPAIF_I2SCTL_SPKEN_MASK, |
206 | LPAIF_I2SCTL_SPKEN_ENABLE); | 216 | LPAIF_I2SCTL_SPKEN_ENABLE); |
207 | if (ret) | 217 | if (ret) |
@@ -212,7 +222,8 @@ static int lpass_cpu_daiops_trigger(struct snd_pcm_substream *substream, | |||
212 | case SNDRV_PCM_TRIGGER_SUSPEND: | 222 | case SNDRV_PCM_TRIGGER_SUSPEND: |
213 | case SNDRV_PCM_TRIGGER_PAUSE_PUSH: | 223 | case SNDRV_PCM_TRIGGER_PAUSE_PUSH: |
214 | ret = regmap_update_bits(drvdata->lpaif_map, | 224 | ret = regmap_update_bits(drvdata->lpaif_map, |
215 | LPAIF_I2SCTL_REG(LPAIF_I2S_PORT_MI2S), | 225 | LPAIF_I2SCTL_REG(drvdata->variant, |
226 | dai->driver->id), | ||
216 | LPAIF_I2SCTL_SPKEN_MASK, | 227 | LPAIF_I2SCTL_SPKEN_MASK, |
217 | LPAIF_I2SCTL_SPKEN_DISABLE); | 228 | LPAIF_I2SCTL_SPKEN_DISABLE); |
218 | if (ret) | 229 | if (ret) |
@@ -224,7 +235,7 @@ static int lpass_cpu_daiops_trigger(struct snd_pcm_substream *substream, | |||
224 | return ret; | 235 | return ret; |
225 | } | 236 | } |
226 | 237 | ||
227 | static struct snd_soc_dai_ops lpass_cpu_dai_ops = { | 238 | struct snd_soc_dai_ops asoc_qcom_lpass_cpu_dai_ops = { |
228 | .set_sysclk = lpass_cpu_daiops_set_sysclk, | 239 | .set_sysclk = lpass_cpu_daiops_set_sysclk, |
229 | .startup = lpass_cpu_daiops_startup, | 240 | .startup = lpass_cpu_daiops_startup, |
230 | .shutdown = lpass_cpu_daiops_shutdown, | 241 | .shutdown = lpass_cpu_daiops_shutdown, |
@@ -233,41 +244,23 @@ static struct snd_soc_dai_ops lpass_cpu_dai_ops = { | |||
233 | .prepare = lpass_cpu_daiops_prepare, | 244 | .prepare = lpass_cpu_daiops_prepare, |
234 | .trigger = lpass_cpu_daiops_trigger, | 245 | .trigger = lpass_cpu_daiops_trigger, |
235 | }; | 246 | }; |
247 | EXPORT_SYMBOL_GPL(asoc_qcom_lpass_cpu_dai_ops); | ||
236 | 248 | ||
237 | static int lpass_cpu_dai_probe(struct snd_soc_dai *dai) | 249 | int asoc_qcom_lpass_cpu_dai_probe(struct snd_soc_dai *dai) |
238 | { | 250 | { |
239 | struct lpass_data *drvdata = snd_soc_dai_get_drvdata(dai); | 251 | struct lpass_data *drvdata = snd_soc_dai_get_drvdata(dai); |
240 | int ret; | 252 | int ret; |
241 | 253 | ||
242 | /* ensure audio hardware is disabled */ | 254 | /* ensure audio hardware is disabled */ |
243 | ret = regmap_write(drvdata->lpaif_map, | 255 | ret = regmap_write(drvdata->lpaif_map, |
244 | LPAIF_I2SCTL_REG(LPAIF_I2S_PORT_MI2S), 0); | 256 | LPAIF_I2SCTL_REG(drvdata->variant, dai->driver->id), 0); |
245 | if (ret) | 257 | if (ret) |
246 | dev_err(dai->dev, "%s() error writing to i2sctl reg: %d\n", | 258 | dev_err(dai->dev, "%s() error writing to i2sctl reg: %d\n", |
247 | __func__, ret); | 259 | __func__, ret); |
248 | 260 | ||
249 | return ret; | 261 | return ret; |
250 | } | 262 | } |
251 | 263 | EXPORT_SYMBOL_GPL(asoc_qcom_lpass_cpu_dai_probe); | |
252 | static struct snd_soc_dai_driver lpass_cpu_dai_driver = { | ||
253 | .playback = { | ||
254 | .stream_name = "lpass-cpu-playback", | ||
255 | .formats = SNDRV_PCM_FMTBIT_S16 | | ||
256 | SNDRV_PCM_FMTBIT_S24 | | ||
257 | SNDRV_PCM_FMTBIT_S32, | ||
258 | .rates = SNDRV_PCM_RATE_8000 | | ||
259 | SNDRV_PCM_RATE_16000 | | ||
260 | SNDRV_PCM_RATE_32000 | | ||
261 | SNDRV_PCM_RATE_48000 | | ||
262 | SNDRV_PCM_RATE_96000, | ||
263 | .rate_min = 8000, | ||
264 | .rate_max = 96000, | ||
265 | .channels_min = 1, | ||
266 | .channels_max = 8, | ||
267 | }, | ||
268 | .probe = &lpass_cpu_dai_probe, | ||
269 | .ops = &lpass_cpu_dai_ops, | ||
270 | }; | ||
271 | 264 | ||
272 | static const struct snd_soc_component_driver lpass_cpu_comp_driver = { | 265 | static const struct snd_soc_component_driver lpass_cpu_comp_driver = { |
273 | .name = "lpass-cpu", | 266 | .name = "lpass-cpu", |
@@ -275,27 +268,29 @@ static const struct snd_soc_component_driver lpass_cpu_comp_driver = { | |||
275 | 268 | ||
276 | static bool lpass_cpu_regmap_writeable(struct device *dev, unsigned int reg) | 269 | static bool lpass_cpu_regmap_writeable(struct device *dev, unsigned int reg) |
277 | { | 270 | { |
271 | struct lpass_data *drvdata = dev_get_drvdata(dev); | ||
272 | struct lpass_variant *v = drvdata->variant; | ||
278 | int i; | 273 | int i; |
279 | 274 | ||
280 | for (i = 0; i < LPAIF_I2S_PORT_NUM; ++i) | 275 | for (i = 0; i < v->i2s_ports; ++i) |
281 | if (reg == LPAIF_I2SCTL_REG(i)) | 276 | if (reg == LPAIF_I2SCTL_REG(v, i)) |
282 | return true; | 277 | return true; |
283 | 278 | ||
284 | for (i = 0; i < LPAIF_IRQ_PORT_NUM; ++i) { | 279 | for (i = 0; i < v->irq_ports; ++i) { |
285 | if (reg == LPAIF_IRQEN_REG(i)) | 280 | if (reg == LPAIF_IRQEN_REG(v, i)) |
286 | return true; | 281 | return true; |
287 | if (reg == LPAIF_IRQCLEAR_REG(i)) | 282 | if (reg == LPAIF_IRQCLEAR_REG(v, i)) |
288 | return true; | 283 | return true; |
289 | } | 284 | } |
290 | 285 | ||
291 | for (i = 0; i < LPAIF_RDMA_CHAN_NUM; ++i) { | 286 | for (i = 0; i < v->rdma_channels; ++i) { |
292 | if (reg == LPAIF_RDMACTL_REG(i)) | 287 | if (reg == LPAIF_RDMACTL_REG(v, i)) |
293 | return true; | 288 | return true; |
294 | if (reg == LPAIF_RDMABASE_REG(i)) | 289 | if (reg == LPAIF_RDMABASE_REG(v, i)) |
295 | return true; | 290 | return true; |
296 | if (reg == LPAIF_RDMABUFF_REG(i)) | 291 | if (reg == LPAIF_RDMABUFF_REG(v, i)) |
297 | return true; | 292 | return true; |
298 | if (reg == LPAIF_RDMAPER_REG(i)) | 293 | if (reg == LPAIF_RDMAPER_REG(v, i)) |
299 | return true; | 294 | return true; |
300 | } | 295 | } |
301 | 296 | ||
@@ -304,29 +299,31 @@ static bool lpass_cpu_regmap_writeable(struct device *dev, unsigned int reg) | |||
304 | 299 | ||
305 | static bool lpass_cpu_regmap_readable(struct device *dev, unsigned int reg) | 300 | static bool lpass_cpu_regmap_readable(struct device *dev, unsigned int reg) |
306 | { | 301 | { |
302 | struct lpass_data *drvdata = dev_get_drvdata(dev); | ||
303 | struct lpass_variant *v = drvdata->variant; | ||
307 | int i; | 304 | int i; |
308 | 305 | ||
309 | for (i = 0; i < LPAIF_I2S_PORT_NUM; ++i) | 306 | for (i = 0; i < v->i2s_ports; ++i) |
310 | if (reg == LPAIF_I2SCTL_REG(i)) | 307 | if (reg == LPAIF_I2SCTL_REG(v, i)) |
311 | return true; | 308 | return true; |
312 | 309 | ||
313 | for (i = 0; i < LPAIF_IRQ_PORT_NUM; ++i) { | 310 | for (i = 0; i < v->irq_ports; ++i) { |
314 | if (reg == LPAIF_IRQEN_REG(i)) | 311 | if (reg == LPAIF_IRQEN_REG(v, i)) |
315 | return true; | 312 | return true; |
316 | if (reg == LPAIF_IRQSTAT_REG(i)) | 313 | if (reg == LPAIF_IRQSTAT_REG(v, i)) |
317 | return true; | 314 | return true; |
318 | } | 315 | } |
319 | 316 | ||
320 | for (i = 0; i < LPAIF_RDMA_CHAN_NUM; ++i) { | 317 | for (i = 0; i < v->rdma_channels; ++i) { |
321 | if (reg == LPAIF_RDMACTL_REG(i)) | 318 | if (reg == LPAIF_RDMACTL_REG(v, i)) |
322 | return true; | 319 | return true; |
323 | if (reg == LPAIF_RDMABASE_REG(i)) | 320 | if (reg == LPAIF_RDMABASE_REG(v, i)) |
324 | return true; | 321 | return true; |
325 | if (reg == LPAIF_RDMABUFF_REG(i)) | 322 | if (reg == LPAIF_RDMABUFF_REG(v, i)) |
326 | return true; | 323 | return true; |
327 | if (reg == LPAIF_RDMACURR_REG(i)) | 324 | if (reg == LPAIF_RDMACURR_REG(v, i)) |
328 | return true; | 325 | return true; |
329 | if (reg == LPAIF_RDMAPER_REG(i)) | 326 | if (reg == LPAIF_RDMAPER_REG(v, i)) |
330 | return true; | 327 | return true; |
331 | } | 328 | } |
332 | 329 | ||
@@ -335,36 +332,41 @@ static bool lpass_cpu_regmap_readable(struct device *dev, unsigned int reg) | |||
335 | 332 | ||
336 | static bool lpass_cpu_regmap_volatile(struct device *dev, unsigned int reg) | 333 | static bool lpass_cpu_regmap_volatile(struct device *dev, unsigned int reg) |
337 | { | 334 | { |
335 | struct lpass_data *drvdata = dev_get_drvdata(dev); | ||
336 | struct lpass_variant *v = drvdata->variant; | ||
338 | int i; | 337 | int i; |
339 | 338 | ||
340 | for (i = 0; i < LPAIF_IRQ_PORT_NUM; ++i) | 339 | for (i = 0; i < v->irq_ports; ++i) |
341 | if (reg == LPAIF_IRQSTAT_REG(i)) | 340 | if (reg == LPAIF_IRQSTAT_REG(v, i)) |
342 | return true; | 341 | return true; |
343 | 342 | ||
344 | for (i = 0; i < LPAIF_RDMA_CHAN_NUM; ++i) | 343 | for (i = 0; i < v->rdma_channels; ++i) |
345 | if (reg == LPAIF_RDMACURR_REG(i)) | 344 | if (reg == LPAIF_RDMACURR_REG(v, i)) |
346 | return true; | 345 | return true; |
347 | 346 | ||
348 | return false; | 347 | return false; |
349 | } | 348 | } |
350 | 349 | ||
351 | static const struct regmap_config lpass_cpu_regmap_config = { | 350 | static struct regmap_config lpass_cpu_regmap_config = { |
352 | .reg_bits = 32, | 351 | .reg_bits = 32, |
353 | .reg_stride = 4, | 352 | .reg_stride = 4, |
354 | .val_bits = 32, | 353 | .val_bits = 32, |
355 | .max_register = LPAIF_RDMAPER_REG(LPAIF_RDMA_CHAN_MAX), | ||
356 | .writeable_reg = lpass_cpu_regmap_writeable, | 354 | .writeable_reg = lpass_cpu_regmap_writeable, |
357 | .readable_reg = lpass_cpu_regmap_readable, | 355 | .readable_reg = lpass_cpu_regmap_readable, |
358 | .volatile_reg = lpass_cpu_regmap_volatile, | 356 | .volatile_reg = lpass_cpu_regmap_volatile, |
359 | .cache_type = REGCACHE_FLAT, | 357 | .cache_type = REGCACHE_FLAT, |
360 | }; | 358 | }; |
361 | 359 | ||
362 | static int lpass_cpu_platform_probe(struct platform_device *pdev) | 360 | int asoc_qcom_lpass_cpu_platform_probe(struct platform_device *pdev) |
363 | { | 361 | { |
364 | struct lpass_data *drvdata; | 362 | struct lpass_data *drvdata; |
365 | struct device_node *dsp_of_node; | 363 | struct device_node *dsp_of_node; |
366 | struct resource *res; | 364 | struct resource *res; |
367 | int ret; | 365 | struct lpass_variant *variant; |
366 | struct device *dev = &pdev->dev; | ||
367 | const struct of_device_id *match; | ||
368 | char clk_name[16]; | ||
369 | int ret, i, dai_id; | ||
368 | 370 | ||
369 | dsp_of_node = of_parse_phandle(pdev->dev.of_node, "qcom,adsp", 0); | 371 | dsp_of_node = of_parse_phandle(pdev->dev.of_node, "qcom,adsp", 0); |
370 | if (dsp_of_node) { | 372 | if (dsp_of_node) { |
@@ -379,11 +381,14 @@ static int lpass_cpu_platform_probe(struct platform_device *pdev) | |||
379 | return -ENOMEM; | 381 | return -ENOMEM; |
380 | platform_set_drvdata(pdev, drvdata); | 382 | platform_set_drvdata(pdev, drvdata); |
381 | 383 | ||
384 | match = of_match_device(dev->driver->of_match_table, dev); | ||
385 | if (!match || !match->data) | ||
386 | return -EINVAL; | ||
387 | |||
388 | drvdata->variant = (struct lpass_variant *)match->data; | ||
389 | variant = drvdata->variant; | ||
390 | |||
382 | res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "lpass-lpaif"); | 391 | res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "lpass-lpaif"); |
383 | if (!res) { | ||
384 | dev_err(&pdev->dev, "%s() error getting resource\n", __func__); | ||
385 | return -ENODEV; | ||
386 | } | ||
387 | 392 | ||
388 | drvdata->lpaif = devm_ioremap_resource(&pdev->dev, res); | 393 | drvdata->lpaif = devm_ioremap_resource(&pdev->dev, res); |
389 | if (IS_ERR((void const __force *)drvdata->lpaif)) { | 394 | if (IS_ERR((void const __force *)drvdata->lpaif)) { |
@@ -393,6 +398,9 @@ static int lpass_cpu_platform_probe(struct platform_device *pdev) | |||
393 | return PTR_ERR((void const __force *)drvdata->lpaif); | 398 | return PTR_ERR((void const __force *)drvdata->lpaif); |
394 | } | 399 | } |
395 | 400 | ||
401 | lpass_cpu_regmap_config.max_register = LPAIF_RDMAPER_REG(variant, | ||
402 | variant->rdma_channels); | ||
403 | |||
396 | drvdata->lpaif_map = devm_regmap_init_mmio(&pdev->dev, drvdata->lpaif, | 404 | drvdata->lpaif_map = devm_regmap_init_mmio(&pdev->dev, drvdata->lpaif, |
397 | &lpass_cpu_regmap_config); | 405 | &lpass_cpu_regmap_config); |
398 | if (IS_ERR(drvdata->lpaif_map)) { | 406 | if (IS_ERR(drvdata->lpaif_map)) { |
@@ -401,18 +409,38 @@ static int lpass_cpu_platform_probe(struct platform_device *pdev) | |||
401 | return PTR_ERR(drvdata->lpaif_map); | 409 | return PTR_ERR(drvdata->lpaif_map); |
402 | } | 410 | } |
403 | 411 | ||
404 | drvdata->mi2s_osr_clk = devm_clk_get(&pdev->dev, "mi2s-osr-clk"); | 412 | if (variant->init) |
405 | if (IS_ERR(drvdata->mi2s_osr_clk)) { | 413 | variant->init(pdev); |
406 | dev_err(&pdev->dev, "%s() error getting mi2s-osr-clk: %ld\n", | 414 | |
407 | __func__, PTR_ERR(drvdata->mi2s_osr_clk)); | 415 | for (i = 0; i < variant->num_dai; i++) { |
408 | return PTR_ERR(drvdata->mi2s_osr_clk); | 416 | dai_id = variant->dai_driver[i].id; |
409 | } | 417 | if (variant->num_dai > 1) |
410 | 418 | sprintf(clk_name, "mi2s-osr-clk%d", i); | |
411 | drvdata->mi2s_bit_clk = devm_clk_get(&pdev->dev, "mi2s-bit-clk"); | 419 | else |
412 | if (IS_ERR(drvdata->mi2s_bit_clk)) { | 420 | sprintf(clk_name, "mi2s-osr-clk"); |
413 | dev_err(&pdev->dev, "%s() error getting mi2s-bit-clk: %ld\n", | 421 | |
414 | __func__, PTR_ERR(drvdata->mi2s_bit_clk)); | 422 | drvdata->mi2s_osr_clk[dai_id] = devm_clk_get(&pdev->dev, |
415 | return PTR_ERR(drvdata->mi2s_bit_clk); | 423 | clk_name); |
424 | if (IS_ERR(drvdata->mi2s_osr_clk[dai_id])) { | ||
425 | dev_warn(&pdev->dev, | ||
426 | "%s() error getting mi2s-osr-clk: %ld\n", | ||
427 | __func__, | ||
428 | PTR_ERR(drvdata->mi2s_osr_clk[dai_id])); | ||
429 | } | ||
430 | |||
431 | if (variant->num_dai > 1) | ||
432 | sprintf(clk_name, "mi2s-bit-clk%d", i); | ||
433 | else | ||
434 | sprintf(clk_name, "mi2s-bit-clk"); | ||
435 | |||
436 | drvdata->mi2s_bit_clk[dai_id] = devm_clk_get(&pdev->dev, | ||
437 | clk_name); | ||
438 | if (IS_ERR(drvdata->mi2s_bit_clk[dai_id])) { | ||
439 | dev_err(&pdev->dev, | ||
440 | "%s() error getting mi2s-bit-clk: %ld\n", | ||
441 | __func__, PTR_ERR(drvdata->mi2s_bit_clk[i])); | ||
442 | return PTR_ERR(drvdata->mi2s_bit_clk[dai_id]); | ||
443 | } | ||
416 | } | 444 | } |
417 | 445 | ||
418 | drvdata->ahbix_clk = devm_clk_get(&pdev->dev, "ahbix-clk"); | 446 | drvdata->ahbix_clk = devm_clk_get(&pdev->dev, "ahbix-clk"); |
@@ -439,7 +467,9 @@ static int lpass_cpu_platform_probe(struct platform_device *pdev) | |||
439 | } | 467 | } |
440 | 468 | ||
441 | ret = devm_snd_soc_register_component(&pdev->dev, | 469 | ret = devm_snd_soc_register_component(&pdev->dev, |
442 | &lpass_cpu_comp_driver, &lpass_cpu_dai_driver, 1); | 470 | &lpass_cpu_comp_driver, |
471 | variant->dai_driver, | ||
472 | variant->num_dai); | ||
443 | if (ret) { | 473 | if (ret) { |
444 | dev_err(&pdev->dev, "%s() error registering cpu driver: %d\n", | 474 | dev_err(&pdev->dev, "%s() error registering cpu driver: %d\n", |
445 | __func__, ret); | 475 | __func__, ret); |
@@ -459,33 +489,17 @@ err_clk: | |||
459 | clk_disable_unprepare(drvdata->ahbix_clk); | 489 | clk_disable_unprepare(drvdata->ahbix_clk); |
460 | return ret; | 490 | return ret; |
461 | } | 491 | } |
492 | EXPORT_SYMBOL_GPL(asoc_qcom_lpass_cpu_platform_probe); | ||
462 | 493 | ||
463 | static int lpass_cpu_platform_remove(struct platform_device *pdev) | 494 | int asoc_qcom_lpass_cpu_platform_remove(struct platform_device *pdev) |
464 | { | 495 | { |
465 | struct lpass_data *drvdata = platform_get_drvdata(pdev); | 496 | struct lpass_data *drvdata = platform_get_drvdata(pdev); |
466 | 497 | ||
498 | if (drvdata->variant->exit) | ||
499 | drvdata->variant->exit(pdev); | ||
500 | |||
467 | clk_disable_unprepare(drvdata->ahbix_clk); | 501 | clk_disable_unprepare(drvdata->ahbix_clk); |
468 | 502 | ||
469 | return 0; | 503 | return 0; |
470 | } | 504 | } |
471 | 505 | EXPORT_SYMBOL_GPL(asoc_qcom_lpass_cpu_platform_remove); | |
472 | #ifdef CONFIG_OF | ||
473 | static const struct of_device_id lpass_cpu_device_id[] = { | ||
474 | { .compatible = "qcom,lpass-cpu" }, | ||
475 | {} | ||
476 | }; | ||
477 | MODULE_DEVICE_TABLE(of, lpass_cpu_device_id); | ||
478 | #endif | ||
479 | |||
480 | static struct platform_driver lpass_cpu_platform_driver = { | ||
481 | .driver = { | ||
482 | .name = "lpass-cpu", | ||
483 | .of_match_table = of_match_ptr(lpass_cpu_device_id), | ||
484 | }, | ||
485 | .probe = lpass_cpu_platform_probe, | ||
486 | .remove = lpass_cpu_platform_remove, | ||
487 | }; | ||
488 | module_platform_driver(lpass_cpu_platform_driver); | ||
489 | |||
490 | MODULE_DESCRIPTION("QTi LPASS CPU Driver"); | ||
491 | MODULE_LICENSE("GPL v2"); | ||
diff --git a/sound/soc/qcom/lpass-ipq806x.c b/sound/soc/qcom/lpass-ipq806x.c new file mode 100644 index 000000000000..7356d3a766d6 --- /dev/null +++ b/sound/soc/qcom/lpass-ipq806x.c | |||
@@ -0,0 +1,109 @@ | |||
1 | /* | ||
2 | * Copyright (c) 2010-2011,2013-2015 The Linux Foundation. All rights reserved. | ||
3 | * | ||
4 | * This program is free software; you can redistribute it and/or modify | ||
5 | * it under the terms of the GNU General Public License version 2 and | ||
6 | * only version 2 as published by the Free Software Foundation. | ||
7 | * | ||
8 | * This program is distributed in the hope that it will be useful, | ||
9 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
10 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
11 | * GNU General Public License for more details. | ||
12 | * | ||
13 | * lpass-ipq806x.c -- ALSA SoC CPU DAI driver for QTi LPASS | ||
14 | * Splited out the IPQ8064 soc specific from lpass-cpu.c | ||
15 | */ | ||
16 | |||
17 | #include <linux/clk.h> | ||
18 | #include <linux/device.h> | ||
19 | #include <linux/err.h> | ||
20 | #include <linux/kernel.h> | ||
21 | #include <linux/module.h> | ||
22 | #include <linux/of.h> | ||
23 | #include <linux/platform_device.h> | ||
24 | #include <sound/pcm.h> | ||
25 | #include <sound/soc.h> | ||
26 | #include <sound/soc-dai.h> | ||
27 | |||
28 | #include "lpass-lpaif-reg.h" | ||
29 | #include "lpass.h" | ||
30 | |||
31 | enum lpaif_i2s_ports { | ||
32 | IPQ806X_LPAIF_I2S_PORT_CODEC_SPK, | ||
33 | IPQ806X_LPAIF_I2S_PORT_CODEC_MIC, | ||
34 | IPQ806X_LPAIF_I2S_PORT_SEC_SPK, | ||
35 | IPQ806X_LPAIF_I2S_PORT_SEC_MIC, | ||
36 | IPQ806X_LPAIF_I2S_PORT_MI2S, | ||
37 | }; | ||
38 | |||
39 | enum lpaif_dma_channels { | ||
40 | IPQ806X_LPAIF_RDMA_CHAN_MI2S, | ||
41 | IPQ806X_LPAIF_RDMA_CHAN_PCM0, | ||
42 | IPQ806X_LPAIF_RDMA_CHAN_PCM1, | ||
43 | }; | ||
44 | |||
45 | static struct snd_soc_dai_driver ipq806x_lpass_cpu_dai_driver = { | ||
46 | .id = IPQ806X_LPAIF_I2S_PORT_MI2S, | ||
47 | .playback = { | ||
48 | .stream_name = "lpass-cpu-playback", | ||
49 | .formats = SNDRV_PCM_FMTBIT_S16 | | ||
50 | SNDRV_PCM_FMTBIT_S24 | | ||
51 | SNDRV_PCM_FMTBIT_S32, | ||
52 | .rates = SNDRV_PCM_RATE_8000 | | ||
53 | SNDRV_PCM_RATE_16000 | | ||
54 | SNDRV_PCM_RATE_32000 | | ||
55 | SNDRV_PCM_RATE_48000 | | ||
56 | SNDRV_PCM_RATE_96000, | ||
57 | .rate_min = 8000, | ||
58 | .rate_max = 96000, | ||
59 | .channels_min = 1, | ||
60 | .channels_max = 8, | ||
61 | }, | ||
62 | .probe = &asoc_qcom_lpass_cpu_dai_probe, | ||
63 | .ops = &asoc_qcom_lpass_cpu_dai_ops, | ||
64 | }; | ||
65 | |||
66 | static int ipq806x_lpass_alloc_dma_channel(struct lpass_data *drvdata) | ||
67 | { | ||
68 | return IPQ806X_LPAIF_RDMA_CHAN_MI2S; | ||
69 | } | ||
70 | |||
71 | static int ipq806x_lpass_free_dma_channel(struct lpass_data *drvdata, int chan) | ||
72 | { | ||
73 | return 0; | ||
74 | } | ||
75 | |||
76 | struct lpass_variant ipq806x_data = { | ||
77 | .i2sctrl_reg_base = 0x0010, | ||
78 | .i2sctrl_reg_stride = 0x04, | ||
79 | .i2s_ports = 5, | ||
80 | .irq_reg_base = 0x3000, | ||
81 | .irq_reg_stride = 0x1000, | ||
82 | .irq_ports = 3, | ||
83 | .rdma_reg_base = 0x6000, | ||
84 | .rdma_reg_stride = 0x1000, | ||
85 | .rdma_channels = 4, | ||
86 | .dai_driver = &ipq806x_lpass_cpu_dai_driver, | ||
87 | .num_dai = 1, | ||
88 | .alloc_dma_channel = ipq806x_lpass_alloc_dma_channel, | ||
89 | .free_dma_channel = ipq806x_lpass_free_dma_channel, | ||
90 | }; | ||
91 | |||
92 | static const struct of_device_id ipq806x_lpass_cpu_device_id[] = { | ||
93 | { .compatible = "qcom,lpass-cpu", .data = &ipq806x_data }, | ||
94 | {} | ||
95 | }; | ||
96 | MODULE_DEVICE_TABLE(of, ipq806x_lpass_cpu_device_id); | ||
97 | |||
98 | static struct platform_driver ipq806x_lpass_cpu_platform_driver = { | ||
99 | .driver = { | ||
100 | .name = "lpass-cpu", | ||
101 | .of_match_table = of_match_ptr(ipq806x_lpass_cpu_device_id), | ||
102 | }, | ||
103 | .probe = asoc_qcom_lpass_cpu_platform_probe, | ||
104 | .remove = asoc_qcom_lpass_cpu_platform_remove, | ||
105 | }; | ||
106 | module_platform_driver(ipq806x_lpass_cpu_platform_driver); | ||
107 | |||
108 | MODULE_DESCRIPTION("QTi LPASS CPU Driver"); | ||
109 | MODULE_LICENSE("GPL v2"); | ||
diff --git a/sound/soc/qcom/lpass-lpaif-ipq806x.h b/sound/soc/qcom/lpass-lpaif-reg.h index dc423b888842..95e22f131052 100644 --- a/sound/soc/qcom/lpass-lpaif-ipq806x.h +++ b/sound/soc/qcom/lpass-lpaif-reg.h | |||
@@ -9,37 +9,17 @@ | |||
9 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | 9 | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
10 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | 10 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
11 | * GNU General Public License for more details. | 11 | * GNU General Public License for more details. |
12 | * | ||
13 | * lpass-lpaif-ipq806x.h -- Definitions for the QTi LPAIF in the ipq806x LPASS | ||
14 | */ | 12 | */ |
15 | 13 | ||
16 | #ifndef __LPASS_LPAIF_H__ | 14 | #ifndef __LPASS_LPAIF_REG_H__ |
17 | #define __LPASS_LPAIF_H__ | 15 | #define __LPASS_LPAIF_REG_H__ |
18 | |||
19 | #define LPAIF_BANK_OFFSET 0x1000 | ||
20 | 16 | ||
21 | /* LPAIF I2S */ | 17 | /* LPAIF I2S */ |
22 | 18 | ||
23 | #define LPAIF_I2SCTL_REG_BASE 0x0010 | 19 | #define LPAIF_I2SCTL_REG_ADDR(v, addr, port) \ |
24 | #define LPAIF_I2SCTL_REG_STRIDE 0x4 | 20 | (v->i2sctrl_reg_base + (addr) + v->i2sctrl_reg_stride * (port)) |
25 | #define LPAIF_I2SCTL_REG_ADDR(addr, port) \ | ||
26 | (LPAIF_I2SCTL_REG_BASE + (addr) + (LPAIF_I2SCTL_REG_STRIDE * (port))) | ||
27 | |||
28 | enum lpaif_i2s_ports { | ||
29 | LPAIF_I2S_PORT_MIN = 0, | ||
30 | |||
31 | LPAIF_I2S_PORT_CODEC_SPK = 0, | ||
32 | LPAIF_I2S_PORT_CODEC_MIC = 1, | ||
33 | LPAIF_I2S_PORT_SEC_SPK = 2, | ||
34 | LPAIF_I2S_PORT_SEC_MIC = 3, | ||
35 | LPAIF_I2S_PORT_MI2S = 4, | ||
36 | |||
37 | LPAIF_I2S_PORT_MAX = 4, | ||
38 | LPAIF_I2S_PORT_NUM = 5, | ||
39 | }; | ||
40 | |||
41 | #define LPAIF_I2SCTL_REG(port) LPAIF_I2SCTL_REG_ADDR(0x0, (port)) | ||
42 | 21 | ||
22 | #define LPAIF_I2SCTL_REG(v, port) LPAIF_I2SCTL_REG_ADDR(v, 0x0, (port)) | ||
43 | #define LPAIF_I2SCTL_LOOPBACK_MASK 0x8000 | 23 | #define LPAIF_I2SCTL_LOOPBACK_MASK 0x8000 |
44 | #define LPAIF_I2SCTL_LOOPBACK_SHIFT 15 | 24 | #define LPAIF_I2SCTL_LOOPBACK_SHIFT 15 |
45 | #define LPAIF_I2SCTL_LOOPBACK_DISABLE (0 << LPAIF_I2SCTL_LOOPBACK_SHIFT) | 25 | #define LPAIF_I2SCTL_LOOPBACK_DISABLE (0 << LPAIF_I2SCTL_LOOPBACK_SHIFT) |
@@ -79,55 +59,36 @@ enum lpaif_i2s_ports { | |||
79 | #define LPAIF_I2SCTL_BITWIDTH_32 (2 << LPAIF_I2SCTL_BITWIDTH_SHIFT) | 59 | #define LPAIF_I2SCTL_BITWIDTH_32 (2 << LPAIF_I2SCTL_BITWIDTH_SHIFT) |
80 | 60 | ||
81 | /* LPAIF IRQ */ | 61 | /* LPAIF IRQ */ |
62 | #define LPAIF_IRQ_REG_ADDR(v, addr, port) \ | ||
63 | (v->irq_reg_base + (addr) + v->irq_reg_stride * (port)) | ||
82 | 64 | ||
83 | #define LPAIF_IRQ_REG_BASE 0x3000 | 65 | #define LPAIF_IRQ_PORT_HOST 0 |
84 | #define LPAIF_IRQ_REG_STRIDE 0x1000 | ||
85 | #define LPAIF_IRQ_REG_ADDR(addr, port) \ | ||
86 | (LPAIF_IRQ_REG_BASE + (addr) + (LPAIF_IRQ_REG_STRIDE * (port))) | ||
87 | |||
88 | enum lpaif_irq_ports { | ||
89 | LPAIF_IRQ_PORT_MIN = 0, | ||
90 | 66 | ||
91 | LPAIF_IRQ_PORT_HOST = 0, | 67 | #define LPAIF_IRQEN_REG(v, port) LPAIF_IRQ_REG_ADDR(v, 0x0, (port)) |
92 | LPAIF_IRQ_PORT_ADSP = 1, | 68 | #define LPAIF_IRQSTAT_REG(v, port) LPAIF_IRQ_REG_ADDR(v, 0x4, (port)) |
93 | 69 | #define LPAIF_IRQCLEAR_REG(v, port) LPAIF_IRQ_REG_ADDR(v, 0xC, (port)) | |
94 | LPAIF_IRQ_PORT_MAX = 2, | ||
95 | LPAIF_IRQ_PORT_NUM = 3, | ||
96 | }; | ||
97 | |||
98 | #define LPAIF_IRQEN_REG(port) LPAIF_IRQ_REG_ADDR(0x0, (port)) | ||
99 | #define LPAIF_IRQSTAT_REG(port) LPAIF_IRQ_REG_ADDR(0x4, (port)) | ||
100 | #define LPAIF_IRQCLEAR_REG(port) LPAIF_IRQ_REG_ADDR(0xC, (port)) | ||
101 | 70 | ||
102 | #define LPAIF_IRQ_BITSTRIDE 3 | 71 | #define LPAIF_IRQ_BITSTRIDE 3 |
72 | |||
103 | #define LPAIF_IRQ_PER(chan) (1 << (LPAIF_IRQ_BITSTRIDE * (chan))) | 73 | #define LPAIF_IRQ_PER(chan) (1 << (LPAIF_IRQ_BITSTRIDE * (chan))) |
104 | #define LPAIF_IRQ_XRUN(chan) (2 << (LPAIF_IRQ_BITSTRIDE * (chan))) | 74 | #define LPAIF_IRQ_XRUN(chan) (2 << (LPAIF_IRQ_BITSTRIDE * (chan))) |
105 | #define LPAIF_IRQ_ERR(chan) (4 << (LPAIF_IRQ_BITSTRIDE * (chan))) | 75 | #define LPAIF_IRQ_ERR(chan) (4 << (LPAIF_IRQ_BITSTRIDE * (chan))) |
76 | |||
106 | #define LPAIF_IRQ_ALL(chan) (7 << (LPAIF_IRQ_BITSTRIDE * (chan))) | 77 | #define LPAIF_IRQ_ALL(chan) (7 << (LPAIF_IRQ_BITSTRIDE * (chan))) |
107 | 78 | ||
108 | /* LPAIF DMA */ | 79 | /* LPAIF DMA */ |
109 | 80 | ||
110 | #define LPAIF_RDMA_REG_BASE 0x6000 | 81 | #define LPAIF_RDMA_REG_ADDR(v, addr, chan) \ |
111 | #define LPAIF_RDMA_REG_STRIDE 0x1000 | 82 | (v->rdma_reg_base + (addr) + v->rdma_reg_stride * (chan)) |
112 | #define LPAIF_RDMA_REG_ADDR(addr, chan) \ | ||
113 | (LPAIF_RDMA_REG_BASE + (addr) + (LPAIF_RDMA_REG_STRIDE * (chan))) | ||
114 | |||
115 | enum lpaif_dma_channels { | ||
116 | LPAIF_RDMA_CHAN_MIN = 0, | ||
117 | |||
118 | LPAIF_RDMA_CHAN_MI2S = 0, | ||
119 | LPAIF_RDMA_CHAN_PCM0 = 1, | ||
120 | LPAIF_RDMA_CHAN_PCM1 = 2, | ||
121 | 83 | ||
122 | LPAIF_RDMA_CHAN_MAX = 4, | 84 | #define LPAIF_RDMACTL_AUDINTF(id) (id << LPAIF_RDMACTL_AUDINTF_SHIFT) |
123 | LPAIF_RDMA_CHAN_NUM = 5, | ||
124 | }; | ||
125 | 85 | ||
126 | #define LPAIF_RDMACTL_REG(chan) LPAIF_RDMA_REG_ADDR(0x00, (chan)) | 86 | #define LPAIF_RDMACTL_REG(v, chan) LPAIF_RDMA_REG_ADDR(v, 0x00, (chan)) |
127 | #define LPAIF_RDMABASE_REG(chan) LPAIF_RDMA_REG_ADDR(0x04, (chan)) | 87 | #define LPAIF_RDMABASE_REG(v, chan) LPAIF_RDMA_REG_ADDR(v, 0x04, (chan)) |
128 | #define LPAIF_RDMABUFF_REG(chan) LPAIF_RDMA_REG_ADDR(0x08, (chan)) | 88 | #define LPAIF_RDMABUFF_REG(v, chan) LPAIF_RDMA_REG_ADDR(v, 0x08, (chan)) |
129 | #define LPAIF_RDMACURR_REG(chan) LPAIF_RDMA_REG_ADDR(0x0C, (chan)) | 89 | #define LPAIF_RDMACURR_REG(v, chan) LPAIF_RDMA_REG_ADDR(v, 0x0C, (chan)) |
130 | #define LPAIF_RDMAPER_REG(chan) LPAIF_RDMA_REG_ADDR(0x10, (chan)) | 90 | #define LPAIF_RDMAPER_REG(v, chan) LPAIF_RDMA_REG_ADDR(v, 0x10, (chan)) |
91 | #define LPAIF_RDMAPERCNT_REG(v, chan) LPAIF_RDMA_REG_ADDR(v, 0x14, (chan)) | ||
131 | 92 | ||
132 | #define LPAIF_RDMACTL_BURSTEN_MASK 0x800 | 93 | #define LPAIF_RDMACTL_BURSTEN_MASK 0x800 |
133 | #define LPAIF_RDMACTL_BURSTEN_SHIFT 11 | 94 | #define LPAIF_RDMACTL_BURSTEN_SHIFT 11 |
@@ -145,13 +106,6 @@ enum lpaif_dma_channels { | |||
145 | 106 | ||
146 | #define LPAIF_RDMACTL_AUDINTF_MASK 0x0F0 | 107 | #define LPAIF_RDMACTL_AUDINTF_MASK 0x0F0 |
147 | #define LPAIF_RDMACTL_AUDINTF_SHIFT 4 | 108 | #define LPAIF_RDMACTL_AUDINTF_SHIFT 4 |
148 | #define LPAIF_RDMACTL_AUDINTF_NONE (0 << LPAIF_RDMACTL_AUDINTF_SHIFT) | ||
149 | #define LPAIF_RDMACTL_AUDINTF_CODEC (1 << LPAIF_RDMACTL_AUDINTF_SHIFT) | ||
150 | #define LPAIF_RDMACTL_AUDINTF_PCM (2 << LPAIF_RDMACTL_AUDINTF_SHIFT) | ||
151 | #define LPAIF_RDMACTL_AUDINTF_SEC_I2S (3 << LPAIF_RDMACTL_AUDINTF_SHIFT) | ||
152 | #define LPAIF_RDMACTL_AUDINTF_MI2S (4 << LPAIF_RDMACTL_AUDINTF_SHIFT) | ||
153 | #define LPAIF_RDMACTL_AUDINTF_HDMI (5 << LPAIF_RDMACTL_AUDINTF_SHIFT) | ||
154 | #define LPAIF_RDMACTL_AUDINTF_SEC_PCM (7 << LPAIF_RDMACTL_AUDINTF_SHIFT) | ||
155 | 109 | ||
156 | #define LPAIF_RDMACTL_FIFOWM_MASK 0x00E | 110 | #define LPAIF_RDMACTL_FIFOWM_MASK 0x00E |
157 | #define LPAIF_RDMACTL_FIFOWM_SHIFT 1 | 111 | #define LPAIF_RDMACTL_FIFOWM_SHIFT 1 |
@@ -169,4 +123,4 @@ enum lpaif_dma_channels { | |||
169 | #define LPAIF_RDMACTL_ENABLE_OFF (0 << LPAIF_RDMACTL_ENABLE_SHIFT) | 123 | #define LPAIF_RDMACTL_ENABLE_OFF (0 << LPAIF_RDMACTL_ENABLE_SHIFT) |
170 | #define LPAIF_RDMACTL_ENABLE_ON (1 << LPAIF_RDMACTL_ENABLE_SHIFT) | 124 | #define LPAIF_RDMACTL_ENABLE_ON (1 << LPAIF_RDMACTL_ENABLE_SHIFT) |
171 | 125 | ||
172 | #endif /* __LPASS_LPAIF_H__ */ | 126 | #endif /* __LPASS_LPAIF_REG_H__ */ |
diff --git a/sound/soc/qcom/lpass-platform.c b/sound/soc/qcom/lpass-platform.c index 2fa6280dfb23..79688aa1941a 100644 --- a/sound/soc/qcom/lpass-platform.c +++ b/sound/soc/qcom/lpass-platform.c | |||
@@ -13,23 +13,22 @@ | |||
13 | * lpass-platform.c -- ALSA SoC platform driver for QTi LPASS | 13 | * lpass-platform.c -- ALSA SoC platform driver for QTi LPASS |
14 | */ | 14 | */ |
15 | 15 | ||
16 | #include <linux/compiler.h> | ||
17 | #include <linux/device.h> | ||
18 | #include <linux/dma-mapping.h> | 16 | #include <linux/dma-mapping.h> |
19 | #include <linux/err.h> | ||
20 | #include <linux/export.h> | 17 | #include <linux/export.h> |
21 | #include <linux/kernel.h> | 18 | #include <linux/kernel.h> |
22 | #include <linux/module.h> | 19 | #include <linux/module.h> |
23 | #include <linux/io.h> | ||
24 | #include <linux/platform_device.h> | 20 | #include <linux/platform_device.h> |
25 | #include <sound/memalloc.h> | ||
26 | #include <sound/pcm.h> | ||
27 | #include <sound/pcm_params.h> | 21 | #include <sound/pcm_params.h> |
28 | #include <linux/regmap.h> | 22 | #include <linux/regmap.h> |
29 | #include <sound/soc.h> | 23 | #include <sound/soc.h> |
30 | #include "lpass-lpaif-ipq806x.h" | 24 | #include "lpass-lpaif-reg.h" |
31 | #include "lpass.h" | 25 | #include "lpass.h" |
32 | 26 | ||
27 | struct lpass_pcm_data { | ||
28 | int rdma_ch; | ||
29 | int i2s_port; | ||
30 | }; | ||
31 | |||
33 | #define LPASS_PLATFORM_BUFFER_SIZE (16 * 1024) | 32 | #define LPASS_PLATFORM_BUFFER_SIZE (16 * 1024) |
34 | #define LPASS_PLATFORM_PERIODS 2 | 33 | #define LPASS_PLATFORM_PERIODS 2 |
35 | 34 | ||
@@ -84,13 +83,15 @@ static int lpass_platform_pcmops_hw_params(struct snd_pcm_substream *substream, | |||
84 | struct snd_pcm_hw_params *params) | 83 | struct snd_pcm_hw_params *params) |
85 | { | 84 | { |
86 | struct snd_soc_pcm_runtime *soc_runtime = substream->private_data; | 85 | struct snd_soc_pcm_runtime *soc_runtime = substream->private_data; |
86 | struct lpass_pcm_data *pcm_data = snd_soc_pcm_get_drvdata(soc_runtime); | ||
87 | struct lpass_data *drvdata = | 87 | struct lpass_data *drvdata = |
88 | snd_soc_platform_get_drvdata(soc_runtime->platform); | 88 | snd_soc_platform_get_drvdata(soc_runtime->platform); |
89 | struct lpass_variant *v = drvdata->variant; | ||
89 | snd_pcm_format_t format = params_format(params); | 90 | snd_pcm_format_t format = params_format(params); |
90 | unsigned int channels = params_channels(params); | 91 | unsigned int channels = params_channels(params); |
91 | unsigned int regval; | 92 | unsigned int regval; |
92 | int bitwidth; | 93 | int bitwidth; |
93 | int ret; | 94 | int ret, rdma_port = pcm_data->i2s_port + v->rdmactl_audif_start; |
94 | 95 | ||
95 | bitwidth = snd_pcm_format_width(format); | 96 | bitwidth = snd_pcm_format_width(format); |
96 | if (bitwidth < 0) { | 97 | if (bitwidth < 0) { |
@@ -100,7 +101,7 @@ static int lpass_platform_pcmops_hw_params(struct snd_pcm_substream *substream, | |||
100 | } | 101 | } |
101 | 102 | ||
102 | regval = LPAIF_RDMACTL_BURSTEN_INCR4 | | 103 | regval = LPAIF_RDMACTL_BURSTEN_INCR4 | |
103 | LPAIF_RDMACTL_AUDINTF_MI2S | | 104 | LPAIF_RDMACTL_AUDINTF(rdma_port) | |
104 | LPAIF_RDMACTL_FIFOWM_8; | 105 | LPAIF_RDMACTL_FIFOWM_8; |
105 | 106 | ||
106 | switch (bitwidth) { | 107 | switch (bitwidth) { |
@@ -156,7 +157,7 @@ static int lpass_platform_pcmops_hw_params(struct snd_pcm_substream *substream, | |||
156 | } | 157 | } |
157 | 158 | ||
158 | ret = regmap_write(drvdata->lpaif_map, | 159 | ret = regmap_write(drvdata->lpaif_map, |
159 | LPAIF_RDMACTL_REG(LPAIF_RDMA_CHAN_MI2S), regval); | 160 | LPAIF_RDMACTL_REG(v, pcm_data->rdma_ch), regval); |
160 | if (ret) { | 161 | if (ret) { |
161 | dev_err(soc_runtime->dev, "%s() error writing to rdmactl reg: %d\n", | 162 | dev_err(soc_runtime->dev, "%s() error writing to rdmactl reg: %d\n", |
162 | __func__, ret); | 163 | __func__, ret); |
@@ -169,12 +170,14 @@ static int lpass_platform_pcmops_hw_params(struct snd_pcm_substream *substream, | |||
169 | static int lpass_platform_pcmops_hw_free(struct snd_pcm_substream *substream) | 170 | static int lpass_platform_pcmops_hw_free(struct snd_pcm_substream *substream) |
170 | { | 171 | { |
171 | struct snd_soc_pcm_runtime *soc_runtime = substream->private_data; | 172 | struct snd_soc_pcm_runtime *soc_runtime = substream->private_data; |
173 | struct lpass_pcm_data *pcm_data = snd_soc_pcm_get_drvdata(soc_runtime); | ||
172 | struct lpass_data *drvdata = | 174 | struct lpass_data *drvdata = |
173 | snd_soc_platform_get_drvdata(soc_runtime->platform); | 175 | snd_soc_platform_get_drvdata(soc_runtime->platform); |
176 | struct lpass_variant *v = drvdata->variant; | ||
174 | int ret; | 177 | int ret; |
175 | 178 | ||
176 | ret = regmap_write(drvdata->lpaif_map, | 179 | ret = regmap_write(drvdata->lpaif_map, |
177 | LPAIF_RDMACTL_REG(LPAIF_RDMA_CHAN_MI2S), 0); | 180 | LPAIF_RDMACTL_REG(v, pcm_data->rdma_ch), 0); |
178 | if (ret) | 181 | if (ret) |
179 | dev_err(soc_runtime->dev, "%s() error writing to rdmactl reg: %d\n", | 182 | dev_err(soc_runtime->dev, "%s() error writing to rdmactl reg: %d\n", |
180 | __func__, ret); | 183 | __func__, ret); |
@@ -186,12 +189,14 @@ static int lpass_platform_pcmops_prepare(struct snd_pcm_substream *substream) | |||
186 | { | 189 | { |
187 | struct snd_pcm_runtime *runtime = substream->runtime; | 190 | struct snd_pcm_runtime *runtime = substream->runtime; |
188 | struct snd_soc_pcm_runtime *soc_runtime = substream->private_data; | 191 | struct snd_soc_pcm_runtime *soc_runtime = substream->private_data; |
192 | struct lpass_pcm_data *pcm_data = snd_soc_pcm_get_drvdata(soc_runtime); | ||
189 | struct lpass_data *drvdata = | 193 | struct lpass_data *drvdata = |
190 | snd_soc_platform_get_drvdata(soc_runtime->platform); | 194 | snd_soc_platform_get_drvdata(soc_runtime->platform); |
191 | int ret; | 195 | struct lpass_variant *v = drvdata->variant; |
196 | int ret, ch = pcm_data->rdma_ch; | ||
192 | 197 | ||
193 | ret = regmap_write(drvdata->lpaif_map, | 198 | ret = regmap_write(drvdata->lpaif_map, |
194 | LPAIF_RDMABASE_REG(LPAIF_RDMA_CHAN_MI2S), | 199 | LPAIF_RDMABASE_REG(v, ch), |
195 | runtime->dma_addr); | 200 | runtime->dma_addr); |
196 | if (ret) { | 201 | if (ret) { |
197 | dev_err(soc_runtime->dev, "%s() error writing to rdmabase reg: %d\n", | 202 | dev_err(soc_runtime->dev, "%s() error writing to rdmabase reg: %d\n", |
@@ -200,7 +205,7 @@ static int lpass_platform_pcmops_prepare(struct snd_pcm_substream *substream) | |||
200 | } | 205 | } |
201 | 206 | ||
202 | ret = regmap_write(drvdata->lpaif_map, | 207 | ret = regmap_write(drvdata->lpaif_map, |
203 | LPAIF_RDMABUFF_REG(LPAIF_RDMA_CHAN_MI2S), | 208 | LPAIF_RDMABUFF_REG(v, ch), |
204 | (snd_pcm_lib_buffer_bytes(substream) >> 2) - 1); | 209 | (snd_pcm_lib_buffer_bytes(substream) >> 2) - 1); |
205 | if (ret) { | 210 | if (ret) { |
206 | dev_err(soc_runtime->dev, "%s() error writing to rdmabuff reg: %d\n", | 211 | dev_err(soc_runtime->dev, "%s() error writing to rdmabuff reg: %d\n", |
@@ -209,7 +214,7 @@ static int lpass_platform_pcmops_prepare(struct snd_pcm_substream *substream) | |||
209 | } | 214 | } |
210 | 215 | ||
211 | ret = regmap_write(drvdata->lpaif_map, | 216 | ret = regmap_write(drvdata->lpaif_map, |
212 | LPAIF_RDMAPER_REG(LPAIF_RDMA_CHAN_MI2S), | 217 | LPAIF_RDMAPER_REG(v, ch), |
213 | (snd_pcm_lib_period_bytes(substream) >> 2) - 1); | 218 | (snd_pcm_lib_period_bytes(substream) >> 2) - 1); |
214 | if (ret) { | 219 | if (ret) { |
215 | dev_err(soc_runtime->dev, "%s() error writing to rdmaper reg: %d\n", | 220 | dev_err(soc_runtime->dev, "%s() error writing to rdmaper reg: %d\n", |
@@ -218,7 +223,7 @@ static int lpass_platform_pcmops_prepare(struct snd_pcm_substream *substream) | |||
218 | } | 223 | } |
219 | 224 | ||
220 | ret = regmap_update_bits(drvdata->lpaif_map, | 225 | ret = regmap_update_bits(drvdata->lpaif_map, |
221 | LPAIF_RDMACTL_REG(LPAIF_RDMA_CHAN_MI2S), | 226 | LPAIF_RDMACTL_REG(v, ch), |
222 | LPAIF_RDMACTL_ENABLE_MASK, LPAIF_RDMACTL_ENABLE_ON); | 227 | LPAIF_RDMACTL_ENABLE_MASK, LPAIF_RDMACTL_ENABLE_ON); |
223 | if (ret) { | 228 | if (ret) { |
224 | dev_err(soc_runtime->dev, "%s() error writing to rdmactl reg: %d\n", | 229 | dev_err(soc_runtime->dev, "%s() error writing to rdmactl reg: %d\n", |
@@ -233,9 +238,11 @@ static int lpass_platform_pcmops_trigger(struct snd_pcm_substream *substream, | |||
233 | int cmd) | 238 | int cmd) |
234 | { | 239 | { |
235 | struct snd_soc_pcm_runtime *soc_runtime = substream->private_data; | 240 | struct snd_soc_pcm_runtime *soc_runtime = substream->private_data; |
241 | struct lpass_pcm_data *pcm_data = snd_soc_pcm_get_drvdata(soc_runtime); | ||
236 | struct lpass_data *drvdata = | 242 | struct lpass_data *drvdata = |
237 | snd_soc_platform_get_drvdata(soc_runtime->platform); | 243 | snd_soc_platform_get_drvdata(soc_runtime->platform); |
238 | int ret; | 244 | struct lpass_variant *v = drvdata->variant; |
245 | int ret, ch = pcm_data->rdma_ch; | ||
239 | 246 | ||
240 | switch (cmd) { | 247 | switch (cmd) { |
241 | case SNDRV_PCM_TRIGGER_START: | 248 | case SNDRV_PCM_TRIGGER_START: |
@@ -243,8 +250,8 @@ static int lpass_platform_pcmops_trigger(struct snd_pcm_substream *substream, | |||
243 | case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: | 250 | case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: |
244 | /* clear status before enabling interrupts */ | 251 | /* clear status before enabling interrupts */ |
245 | ret = regmap_write(drvdata->lpaif_map, | 252 | ret = regmap_write(drvdata->lpaif_map, |
246 | LPAIF_IRQCLEAR_REG(LPAIF_IRQ_PORT_HOST), | 253 | LPAIF_IRQCLEAR_REG(v, LPAIF_IRQ_PORT_HOST), |
247 | LPAIF_IRQ_ALL(LPAIF_RDMA_CHAN_MI2S)); | 254 | LPAIF_IRQ_ALL(ch)); |
248 | if (ret) { | 255 | if (ret) { |
249 | dev_err(soc_runtime->dev, "%s() error writing to irqclear reg: %d\n", | 256 | dev_err(soc_runtime->dev, "%s() error writing to irqclear reg: %d\n", |
250 | __func__, ret); | 257 | __func__, ret); |
@@ -252,9 +259,9 @@ static int lpass_platform_pcmops_trigger(struct snd_pcm_substream *substream, | |||
252 | } | 259 | } |
253 | 260 | ||
254 | ret = regmap_update_bits(drvdata->lpaif_map, | 261 | ret = regmap_update_bits(drvdata->lpaif_map, |
255 | LPAIF_IRQEN_REG(LPAIF_IRQ_PORT_HOST), | 262 | LPAIF_IRQEN_REG(v, LPAIF_IRQ_PORT_HOST), |
256 | LPAIF_IRQ_ALL(LPAIF_RDMA_CHAN_MI2S), | 263 | LPAIF_IRQ_ALL(ch), |
257 | LPAIF_IRQ_ALL(LPAIF_RDMA_CHAN_MI2S)); | 264 | LPAIF_IRQ_ALL(ch)); |
258 | if (ret) { | 265 | if (ret) { |
259 | dev_err(soc_runtime->dev, "%s() error writing to irqen reg: %d\n", | 266 | dev_err(soc_runtime->dev, "%s() error writing to irqen reg: %d\n", |
260 | __func__, ret); | 267 | __func__, ret); |
@@ -262,7 +269,7 @@ static int lpass_platform_pcmops_trigger(struct snd_pcm_substream *substream, | |||
262 | } | 269 | } |
263 | 270 | ||
264 | ret = regmap_update_bits(drvdata->lpaif_map, | 271 | ret = regmap_update_bits(drvdata->lpaif_map, |
265 | LPAIF_RDMACTL_REG(LPAIF_RDMA_CHAN_MI2S), | 272 | LPAIF_RDMACTL_REG(v, ch), |
266 | LPAIF_RDMACTL_ENABLE_MASK, | 273 | LPAIF_RDMACTL_ENABLE_MASK, |
267 | LPAIF_RDMACTL_ENABLE_ON); | 274 | LPAIF_RDMACTL_ENABLE_ON); |
268 | if (ret) { | 275 | if (ret) { |
@@ -275,7 +282,7 @@ static int lpass_platform_pcmops_trigger(struct snd_pcm_substream *substream, | |||
275 | case SNDRV_PCM_TRIGGER_SUSPEND: | 282 | case SNDRV_PCM_TRIGGER_SUSPEND: |
276 | case SNDRV_PCM_TRIGGER_PAUSE_PUSH: | 283 | case SNDRV_PCM_TRIGGER_PAUSE_PUSH: |
277 | ret = regmap_update_bits(drvdata->lpaif_map, | 284 | ret = regmap_update_bits(drvdata->lpaif_map, |
278 | LPAIF_RDMACTL_REG(LPAIF_RDMA_CHAN_MI2S), | 285 | LPAIF_RDMACTL_REG(v, ch), |
279 | LPAIF_RDMACTL_ENABLE_MASK, | 286 | LPAIF_RDMACTL_ENABLE_MASK, |
280 | LPAIF_RDMACTL_ENABLE_OFF); | 287 | LPAIF_RDMACTL_ENABLE_OFF); |
281 | if (ret) { | 288 | if (ret) { |
@@ -285,8 +292,8 @@ static int lpass_platform_pcmops_trigger(struct snd_pcm_substream *substream, | |||
285 | } | 292 | } |
286 | 293 | ||
287 | ret = regmap_update_bits(drvdata->lpaif_map, | 294 | ret = regmap_update_bits(drvdata->lpaif_map, |
288 | LPAIF_IRQEN_REG(LPAIF_IRQ_PORT_HOST), | 295 | LPAIF_IRQEN_REG(v, LPAIF_IRQ_PORT_HOST), |
289 | LPAIF_IRQ_ALL(LPAIF_RDMA_CHAN_MI2S), 0); | 296 | LPAIF_IRQ_ALL(ch), 0); |
290 | if (ret) { | 297 | if (ret) { |
291 | dev_err(soc_runtime->dev, "%s() error writing to irqen reg: %d\n", | 298 | dev_err(soc_runtime->dev, "%s() error writing to irqen reg: %d\n", |
292 | __func__, ret); | 299 | __func__, ret); |
@@ -302,13 +309,15 @@ static snd_pcm_uframes_t lpass_platform_pcmops_pointer( | |||
302 | struct snd_pcm_substream *substream) | 309 | struct snd_pcm_substream *substream) |
303 | { | 310 | { |
304 | struct snd_soc_pcm_runtime *soc_runtime = substream->private_data; | 311 | struct snd_soc_pcm_runtime *soc_runtime = substream->private_data; |
312 | struct lpass_pcm_data *pcm_data = snd_soc_pcm_get_drvdata(soc_runtime); | ||
305 | struct lpass_data *drvdata = | 313 | struct lpass_data *drvdata = |
306 | snd_soc_platform_get_drvdata(soc_runtime->platform); | 314 | snd_soc_platform_get_drvdata(soc_runtime->platform); |
315 | struct lpass_variant *v = drvdata->variant; | ||
307 | unsigned int base_addr, curr_addr; | 316 | unsigned int base_addr, curr_addr; |
308 | int ret; | 317 | int ret, ch = pcm_data->rdma_ch; |
309 | 318 | ||
310 | ret = regmap_read(drvdata->lpaif_map, | 319 | ret = regmap_read(drvdata->lpaif_map, |
311 | LPAIF_RDMABASE_REG(LPAIF_RDMA_CHAN_MI2S), &base_addr); | 320 | LPAIF_RDMABASE_REG(v, ch), &base_addr); |
312 | if (ret) { | 321 | if (ret) { |
313 | dev_err(soc_runtime->dev, "%s() error reading from rdmabase reg: %d\n", | 322 | dev_err(soc_runtime->dev, "%s() error reading from rdmabase reg: %d\n", |
314 | __func__, ret); | 323 | __func__, ret); |
@@ -316,7 +325,7 @@ static snd_pcm_uframes_t lpass_platform_pcmops_pointer( | |||
316 | } | 325 | } |
317 | 326 | ||
318 | ret = regmap_read(drvdata->lpaif_map, | 327 | ret = regmap_read(drvdata->lpaif_map, |
319 | LPAIF_RDMACURR_REG(LPAIF_RDMA_CHAN_MI2S), &curr_addr); | 328 | LPAIF_RDMACURR_REG(v, ch), &curr_addr); |
320 | if (ret) { | 329 | if (ret) { |
321 | dev_err(soc_runtime->dev, "%s() error reading from rdmacurr reg: %d\n", | 330 | dev_err(soc_runtime->dev, "%s() error reading from rdmacurr reg: %d\n", |
322 | __func__, ret); | 331 | __func__, ret); |
@@ -347,29 +356,20 @@ static struct snd_pcm_ops lpass_platform_pcm_ops = { | |||
347 | .mmap = lpass_platform_pcmops_mmap, | 356 | .mmap = lpass_platform_pcmops_mmap, |
348 | }; | 357 | }; |
349 | 358 | ||
350 | static irqreturn_t lpass_platform_lpaif_irq(int irq, void *data) | 359 | static irqreturn_t lpass_dma_interrupt_handler( |
360 | struct snd_pcm_substream *substream, | ||
361 | struct lpass_data *drvdata, | ||
362 | int chan, u32 interrupts) | ||
351 | { | 363 | { |
352 | struct snd_pcm_substream *substream = data; | ||
353 | struct snd_soc_pcm_runtime *soc_runtime = substream->private_data; | 364 | struct snd_soc_pcm_runtime *soc_runtime = substream->private_data; |
354 | struct lpass_data *drvdata = | 365 | struct lpass_variant *v = drvdata->variant; |
355 | snd_soc_platform_get_drvdata(soc_runtime->platform); | ||
356 | unsigned int interrupts; | ||
357 | irqreturn_t ret = IRQ_NONE; | 366 | irqreturn_t ret = IRQ_NONE; |
358 | int rv; | 367 | int rv; |
359 | 368 | ||
360 | rv = regmap_read(drvdata->lpaif_map, | 369 | if (interrupts & LPAIF_IRQ_PER(chan)) { |
361 | LPAIF_IRQSTAT_REG(LPAIF_IRQ_PORT_HOST), &interrupts); | ||
362 | if (rv) { | ||
363 | dev_err(soc_runtime->dev, "%s() error reading from irqstat reg: %d\n", | ||
364 | __func__, rv); | ||
365 | return IRQ_NONE; | ||
366 | } | ||
367 | interrupts &= LPAIF_IRQ_ALL(LPAIF_RDMA_CHAN_MI2S); | ||
368 | |||
369 | if (interrupts & LPAIF_IRQ_PER(LPAIF_RDMA_CHAN_MI2S)) { | ||
370 | rv = regmap_write(drvdata->lpaif_map, | 370 | rv = regmap_write(drvdata->lpaif_map, |
371 | LPAIF_IRQCLEAR_REG(LPAIF_IRQ_PORT_HOST), | 371 | LPAIF_IRQCLEAR_REG(v, LPAIF_IRQ_PORT_HOST), |
372 | LPAIF_IRQ_PER(LPAIF_RDMA_CHAN_MI2S)); | 372 | LPAIF_IRQ_PER(chan)); |
373 | if (rv) { | 373 | if (rv) { |
374 | dev_err(soc_runtime->dev, "%s() error writing to irqclear reg: %d\n", | 374 | dev_err(soc_runtime->dev, "%s() error writing to irqclear reg: %d\n", |
375 | __func__, rv); | 375 | __func__, rv); |
@@ -379,10 +379,10 @@ static irqreturn_t lpass_platform_lpaif_irq(int irq, void *data) | |||
379 | ret = IRQ_HANDLED; | 379 | ret = IRQ_HANDLED; |
380 | } | 380 | } |
381 | 381 | ||
382 | if (interrupts & LPAIF_IRQ_XRUN(LPAIF_RDMA_CHAN_MI2S)) { | 382 | if (interrupts & LPAIF_IRQ_XRUN(chan)) { |
383 | rv = regmap_write(drvdata->lpaif_map, | 383 | rv = regmap_write(drvdata->lpaif_map, |
384 | LPAIF_IRQCLEAR_REG(LPAIF_IRQ_PORT_HOST), | 384 | LPAIF_IRQCLEAR_REG(v, LPAIF_IRQ_PORT_HOST), |
385 | LPAIF_IRQ_XRUN(LPAIF_RDMA_CHAN_MI2S)); | 385 | LPAIF_IRQ_XRUN(chan)); |
386 | if (rv) { | 386 | if (rv) { |
387 | dev_err(soc_runtime->dev, "%s() error writing to irqclear reg: %d\n", | 387 | dev_err(soc_runtime->dev, "%s() error writing to irqclear reg: %d\n", |
388 | __func__, rv); | 388 | __func__, rv); |
@@ -393,10 +393,10 @@ static irqreturn_t lpass_platform_lpaif_irq(int irq, void *data) | |||
393 | ret = IRQ_HANDLED; | 393 | ret = IRQ_HANDLED; |
394 | } | 394 | } |
395 | 395 | ||
396 | if (interrupts & LPAIF_IRQ_ERR(LPAIF_RDMA_CHAN_MI2S)) { | 396 | if (interrupts & LPAIF_IRQ_ERR(chan)) { |
397 | rv = regmap_write(drvdata->lpaif_map, | 397 | rv = regmap_write(drvdata->lpaif_map, |
398 | LPAIF_IRQCLEAR_REG(LPAIF_IRQ_PORT_HOST), | 398 | LPAIF_IRQCLEAR_REG(v, LPAIF_IRQ_PORT_HOST), |
399 | LPAIF_IRQ_ERR(LPAIF_RDMA_CHAN_MI2S)); | 399 | LPAIF_IRQ_ERR(chan)); |
400 | if (rv) { | 400 | if (rv) { |
401 | dev_err(soc_runtime->dev, "%s() error writing to irqclear reg: %d\n", | 401 | dev_err(soc_runtime->dev, "%s() error writing to irqclear reg: %d\n", |
402 | __func__, rv); | 402 | __func__, rv); |
@@ -410,6 +410,35 @@ static irqreturn_t lpass_platform_lpaif_irq(int irq, void *data) | |||
410 | return ret; | 410 | return ret; |
411 | } | 411 | } |
412 | 412 | ||
413 | static irqreturn_t lpass_platform_lpaif_irq(int irq, void *data) | ||
414 | { | ||
415 | struct lpass_data *drvdata = data; | ||
416 | struct lpass_variant *v = drvdata->variant; | ||
417 | unsigned int irqs; | ||
418 | int rv, chan; | ||
419 | |||
420 | rv = regmap_read(drvdata->lpaif_map, | ||
421 | LPAIF_IRQSTAT_REG(v, LPAIF_IRQ_PORT_HOST), &irqs); | ||
422 | if (rv) { | ||
423 | pr_err("%s() error reading from irqstat reg: %d\n", | ||
424 | __func__, rv); | ||
425 | return IRQ_NONE; | ||
426 | } | ||
427 | |||
428 | /* Handle per channel interrupts */ | ||
429 | for (chan = 0; chan < LPASS_MAX_DMA_CHANNELS; chan++) { | ||
430 | if (irqs & LPAIF_IRQ_ALL(chan) && drvdata->substream[chan]) { | ||
431 | rv = lpass_dma_interrupt_handler( | ||
432 | drvdata->substream[chan], | ||
433 | drvdata, chan, irqs); | ||
434 | if (rv != IRQ_HANDLED) | ||
435 | return rv; | ||
436 | } | ||
437 | } | ||
438 | |||
439 | return IRQ_HANDLED; | ||
440 | } | ||
441 | |||
413 | static int lpass_platform_alloc_buffer(struct snd_pcm_substream *substream, | 442 | static int lpass_platform_alloc_buffer(struct snd_pcm_substream *substream, |
414 | struct snd_soc_pcm_runtime *soc_runtime) | 443 | struct snd_soc_pcm_runtime *soc_runtime) |
415 | { | 444 | { |
@@ -448,9 +477,27 @@ static int lpass_platform_pcm_new(struct snd_soc_pcm_runtime *soc_runtime) | |||
448 | struct snd_pcm *pcm = soc_runtime->pcm; | 477 | struct snd_pcm *pcm = soc_runtime->pcm; |
449 | struct snd_pcm_substream *substream = | 478 | struct snd_pcm_substream *substream = |
450 | pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream; | 479 | pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream; |
480 | struct snd_soc_dai *cpu_dai = soc_runtime->cpu_dai; | ||
451 | struct lpass_data *drvdata = | 481 | struct lpass_data *drvdata = |
452 | snd_soc_platform_get_drvdata(soc_runtime->platform); | 482 | snd_soc_platform_get_drvdata(soc_runtime->platform); |
483 | struct lpass_variant *v = drvdata->variant; | ||
453 | int ret; | 484 | int ret; |
485 | struct lpass_pcm_data *data; | ||
486 | |||
487 | data = devm_kzalloc(soc_runtime->dev, sizeof(*data), GFP_KERNEL); | ||
488 | if (!data) | ||
489 | return -ENOMEM; | ||
490 | |||
491 | if (v->alloc_dma_channel) | ||
492 | data->rdma_ch = v->alloc_dma_channel(drvdata); | ||
493 | |||
494 | if (IS_ERR_VALUE(data->rdma_ch)) | ||
495 | return data->rdma_ch; | ||
496 | |||
497 | drvdata->substream[data->rdma_ch] = substream; | ||
498 | data->i2s_port = cpu_dai->driver->id; | ||
499 | |||
500 | snd_soc_pcm_set_drvdata(soc_runtime, data); | ||
454 | 501 | ||
455 | soc_runtime->dev->coherent_dma_mask = DMA_BIT_MASK(32); | 502 | soc_runtime->dev->coherent_dma_mask = DMA_BIT_MASK(32); |
456 | soc_runtime->dev->dma_mask = &soc_runtime->dev->coherent_dma_mask; | 503 | soc_runtime->dev->dma_mask = &soc_runtime->dev->coherent_dma_mask; |
@@ -459,29 +506,12 @@ static int lpass_platform_pcm_new(struct snd_soc_pcm_runtime *soc_runtime) | |||
459 | if (ret) | 506 | if (ret) |
460 | return ret; | 507 | return ret; |
461 | 508 | ||
462 | ret = devm_request_irq(soc_runtime->dev, drvdata->lpaif_irq, | ||
463 | lpass_platform_lpaif_irq, IRQF_TRIGGER_RISING, | ||
464 | "lpass-irq-lpaif", substream); | ||
465 | if (ret) { | ||
466 | dev_err(soc_runtime->dev, "%s() irq request failed: %d\n", | ||
467 | __func__, ret); | ||
468 | goto err_buf; | ||
469 | } | ||
470 | |||
471 | /* ensure audio hardware is disabled */ | ||
472 | ret = regmap_write(drvdata->lpaif_map, | 509 | ret = regmap_write(drvdata->lpaif_map, |
473 | LPAIF_IRQEN_REG(LPAIF_IRQ_PORT_HOST), 0); | 510 | LPAIF_RDMACTL_REG(v, data->rdma_ch), 0); |
474 | if (ret) { | ||
475 | dev_err(soc_runtime->dev, "%s() error writing to irqen reg: %d\n", | ||
476 | __func__, ret); | ||
477 | return ret; | ||
478 | } | ||
479 | ret = regmap_write(drvdata->lpaif_map, | ||
480 | LPAIF_RDMACTL_REG(LPAIF_RDMA_CHAN_MI2S), 0); | ||
481 | if (ret) { | 511 | if (ret) { |
482 | dev_err(soc_runtime->dev, "%s() error writing to rdmactl reg: %d\n", | 512 | dev_err(soc_runtime->dev, "%s() error writing to rdmactl reg: %d\n", |
483 | __func__, ret); | 513 | __func__, ret); |
484 | return ret; | 514 | goto err_buf; |
485 | } | 515 | } |
486 | 516 | ||
487 | return 0; | 517 | return 0; |
@@ -496,6 +526,15 @@ static void lpass_platform_pcm_free(struct snd_pcm *pcm) | |||
496 | struct snd_pcm_substream *substream = | 526 | struct snd_pcm_substream *substream = |
497 | pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream; | 527 | pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream; |
498 | struct snd_soc_pcm_runtime *soc_runtime = substream->private_data; | 528 | struct snd_soc_pcm_runtime *soc_runtime = substream->private_data; |
529 | struct lpass_data *drvdata = | ||
530 | snd_soc_platform_get_drvdata(soc_runtime->platform); | ||
531 | struct lpass_pcm_data *data = snd_soc_pcm_get_drvdata(soc_runtime); | ||
532 | struct lpass_variant *v = drvdata->variant; | ||
533 | |||
534 | drvdata->substream[data->rdma_ch] = NULL; | ||
535 | |||
536 | if (v->free_dma_channel) | ||
537 | v->free_dma_channel(drvdata, data->rdma_ch); | ||
499 | 538 | ||
500 | lpass_platform_free_buffer(substream, soc_runtime); | 539 | lpass_platform_free_buffer(substream, soc_runtime); |
501 | } | 540 | } |
@@ -509,6 +548,8 @@ static struct snd_soc_platform_driver lpass_platform_driver = { | |||
509 | int asoc_qcom_lpass_platform_register(struct platform_device *pdev) | 548 | int asoc_qcom_lpass_platform_register(struct platform_device *pdev) |
510 | { | 549 | { |
511 | struct lpass_data *drvdata = platform_get_drvdata(pdev); | 550 | struct lpass_data *drvdata = platform_get_drvdata(pdev); |
551 | struct lpass_variant *v = drvdata->variant; | ||
552 | int ret; | ||
512 | 553 | ||
513 | drvdata->lpaif_irq = platform_get_irq_byname(pdev, "lpass-irq-lpaif"); | 554 | drvdata->lpaif_irq = platform_get_irq_byname(pdev, "lpass-irq-lpaif"); |
514 | if (drvdata->lpaif_irq < 0) { | 555 | if (drvdata->lpaif_irq < 0) { |
@@ -517,6 +558,25 @@ int asoc_qcom_lpass_platform_register(struct platform_device *pdev) | |||
517 | return -ENODEV; | 558 | return -ENODEV; |
518 | } | 559 | } |
519 | 560 | ||
561 | /* ensure audio hardware is disabled */ | ||
562 | ret = regmap_write(drvdata->lpaif_map, | ||
563 | LPAIF_IRQEN_REG(v, LPAIF_IRQ_PORT_HOST), 0); | ||
564 | if (ret) { | ||
565 | dev_err(&pdev->dev, "%s() error writing to irqen reg: %d\n", | ||
566 | __func__, ret); | ||
567 | return ret; | ||
568 | } | ||
569 | |||
570 | ret = devm_request_irq(&pdev->dev, drvdata->lpaif_irq, | ||
571 | lpass_platform_lpaif_irq, IRQF_TRIGGER_RISING, | ||
572 | "lpass-irq-lpaif", drvdata); | ||
573 | if (ret) { | ||
574 | dev_err(&pdev->dev, "%s() irq request failed: %d\n", | ||
575 | __func__, ret); | ||
576 | return ret; | ||
577 | } | ||
578 | |||
579 | |||
520 | return devm_snd_soc_register_platform(&pdev->dev, | 580 | return devm_snd_soc_register_platform(&pdev->dev, |
521 | &lpass_platform_driver); | 581 | &lpass_platform_driver); |
522 | } | 582 | } |
diff --git a/sound/soc/qcom/lpass.h b/sound/soc/qcom/lpass.h index 5c99b3dace86..d6e86c119e74 100644 --- a/sound/soc/qcom/lpass.h +++ b/sound/soc/qcom/lpass.h | |||
@@ -22,6 +22,8 @@ | |||
22 | #include <linux/regmap.h> | 22 | #include <linux/regmap.h> |
23 | 23 | ||
24 | #define LPASS_AHBIX_CLOCK_FREQUENCY 131072000 | 24 | #define LPASS_AHBIX_CLOCK_FREQUENCY 131072000 |
25 | #define LPASS_MAX_MI2S_PORTS (8) | ||
26 | #define LPASS_MAX_DMA_CHANNELS (8) | ||
25 | 27 | ||
26 | /* Both the CPU DAI and platform drivers will access this data */ | 28 | /* Both the CPU DAI and platform drivers will access this data */ |
27 | struct lpass_data { | 29 | struct lpass_data { |
@@ -30,10 +32,10 @@ struct lpass_data { | |||
30 | struct clk *ahbix_clk; | 32 | struct clk *ahbix_clk; |
31 | 33 | ||
32 | /* MI2S system clock */ | 34 | /* MI2S system clock */ |
33 | struct clk *mi2s_osr_clk; | 35 | struct clk *mi2s_osr_clk[LPASS_MAX_MI2S_PORTS]; |
34 | 36 | ||
35 | /* MI2S bit clock (derived from system clock by a divider */ | 37 | /* MI2S bit clock (derived from system clock by a divider */ |
36 | struct clk *mi2s_bit_clk; | 38 | struct clk *mi2s_bit_clk[LPASS_MAX_MI2S_PORTS]; |
37 | 39 | ||
38 | /* low-power audio interface (LPAIF) registers */ | 40 | /* low-power audio interface (LPAIF) registers */ |
39 | void __iomem *lpaif; | 41 | void __iomem *lpaif; |
@@ -43,9 +45,54 @@ struct lpass_data { | |||
43 | 45 | ||
44 | /* interrupts from the low-power audio interface (LPAIF) */ | 46 | /* interrupts from the low-power audio interface (LPAIF) */ |
45 | int lpaif_irq; | 47 | int lpaif_irq; |
48 | |||
49 | /* SOC specific variations in the LPASS IP integration */ | ||
50 | struct lpass_variant *variant; | ||
51 | |||
52 | /* bit map to keep track of static channel allocations */ | ||
53 | unsigned long rdma_ch_bit_map; | ||
54 | |||
55 | /* used it for handling interrupt per dma channel */ | ||
56 | struct snd_pcm_substream *substream[LPASS_MAX_DMA_CHANNELS]; | ||
57 | |||
58 | /* 8016 specific */ | ||
59 | struct clk *pcnoc_mport_clk; | ||
60 | struct clk *pcnoc_sway_clk; | ||
61 | }; | ||
62 | |||
63 | /* Vairant data per each SOC */ | ||
64 | struct lpass_variant { | ||
65 | u32 i2sctrl_reg_base; | ||
66 | u32 i2sctrl_reg_stride; | ||
67 | u32 i2s_ports; | ||
68 | u32 irq_reg_base; | ||
69 | u32 irq_reg_stride; | ||
70 | u32 irq_ports; | ||
71 | u32 rdma_reg_base; | ||
72 | u32 rdma_reg_stride; | ||
73 | u32 rdma_channels; | ||
74 | |||
75 | /** | ||
76 | * on SOCs like APQ8016 the channel control bits start | ||
77 | * at different offset to ipq806x | ||
78 | **/ | ||
79 | u32 rdmactl_audif_start; | ||
80 | /* SOC specific intialization like clocks */ | ||
81 | int (*init)(struct platform_device *pdev); | ||
82 | int (*exit)(struct platform_device *pdev); | ||
83 | int (*alloc_dma_channel)(struct lpass_data *data); | ||
84 | int (*free_dma_channel)(struct lpass_data *data, int ch); | ||
85 | |||
86 | /* SOC specific dais */ | ||
87 | struct snd_soc_dai_driver *dai_driver; | ||
88 | int num_dai; | ||
46 | }; | 89 | }; |
47 | 90 | ||
48 | /* register the platform driver from the CPU DAI driver */ | 91 | /* register the platform driver from the CPU DAI driver */ |
49 | int asoc_qcom_lpass_platform_register(struct platform_device *); | 92 | int asoc_qcom_lpass_platform_register(struct platform_device *); |
93 | int asoc_qcom_lpass_cpu_platform_remove(struct platform_device *pdev); | ||
94 | int asoc_qcom_lpass_cpu_platform_probe(struct platform_device *pdev); | ||
95 | int asoc_qcom_lpass_cpu_dai_probe(struct snd_soc_dai *dai); | ||
96 | extern struct snd_soc_dai_ops asoc_qcom_lpass_cpu_dai_ops; | ||
50 | 97 | ||
51 | #endif /* __LPASS_H__ */ | 98 | #endif /* __LPASS_H__ */ |
diff --git a/sound/soc/qcom/storm.c b/sound/soc/qcom/storm.c index b8bd296190ad..2d833bffdba0 100644 --- a/sound/soc/qcom/storm.c +++ b/sound/soc/qcom/storm.c | |||
@@ -69,11 +69,6 @@ static struct snd_soc_dai_link storm_dai_link = { | |||
69 | .ops = &storm_soc_ops, | 69 | .ops = &storm_soc_ops, |
70 | }; | 70 | }; |
71 | 71 | ||
72 | static struct snd_soc_card storm_soc_card = { | ||
73 | .name = "ipq806x-storm", | ||
74 | .dev = NULL, | ||
75 | }; | ||
76 | |||
77 | static int storm_parse_of(struct snd_soc_card *card) | 72 | static int storm_parse_of(struct snd_soc_card *card) |
78 | { | 73 | { |
79 | struct snd_soc_dai_link *dai_link = card->dai_link; | 74 | struct snd_soc_dai_link *dai_link = card->dai_link; |
@@ -99,14 +94,13 @@ static int storm_parse_of(struct snd_soc_card *card) | |||
99 | 94 | ||
100 | static int storm_platform_probe(struct platform_device *pdev) | 95 | static int storm_platform_probe(struct platform_device *pdev) |
101 | { | 96 | { |
102 | struct snd_soc_card *card = &storm_soc_card; | 97 | struct snd_soc_card *card; |
103 | int ret; | 98 | int ret; |
104 | 99 | ||
105 | if (card->dev) { | 100 | card = devm_kzalloc(&pdev->dev, sizeof(*card), GFP_KERNEL); |
106 | dev_err(&pdev->dev, "%s() error, existing soundcard\n", | 101 | if (!card) |
107 | __func__); | 102 | return -ENOMEM; |
108 | return -ENODEV; | 103 | |
109 | } | ||
110 | card->dev = &pdev->dev; | 104 | card->dev = &pdev->dev; |
111 | platform_set_drvdata(pdev, card); | 105 | platform_set_drvdata(pdev, card); |
112 | 106 | ||
@@ -128,16 +122,12 @@ static int storm_platform_probe(struct platform_device *pdev) | |||
128 | } | 122 | } |
129 | 123 | ||
130 | ret = devm_snd_soc_register_card(&pdev->dev, card); | 124 | ret = devm_snd_soc_register_card(&pdev->dev, card); |
131 | if (ret == -EPROBE_DEFER) { | 125 | if (ret) |
132 | card->dev = NULL; | ||
133 | return ret; | ||
134 | } else if (ret) { | ||
135 | dev_err(&pdev->dev, "%s() error registering soundcard: %d\n", | 126 | dev_err(&pdev->dev, "%s() error registering soundcard: %d\n", |
136 | __func__, ret); | 127 | __func__, ret); |
137 | return ret; | ||
138 | } | ||
139 | 128 | ||
140 | return 0; | 129 | return ret; |
130 | |||
141 | } | 131 | } |
142 | 132 | ||
143 | #ifdef CONFIG_OF | 133 | #ifdef CONFIG_OF |
diff --git a/sound/soc/samsung/Kconfig b/sound/soc/samsung/Kconfig index 0632a36852c8..3744c9ed5370 100644 --- a/sound/soc/samsung/Kconfig +++ b/sound/soc/samsung/Kconfig | |||
@@ -174,7 +174,8 @@ config SND_SOC_SMDK_WM8994_PCM | |||
174 | 174 | ||
175 | config SND_SOC_SPEYSIDE | 175 | config SND_SOC_SPEYSIDE |
176 | tristate "Audio support for Wolfson Speyside" | 176 | tristate "Audio support for Wolfson Speyside" |
177 | depends on SND_SOC_SAMSUNG && MACH_WLF_CRAGG_6410 && I2C && SPI_MASTER | 177 | depends on SND_SOC_SAMSUNG && I2C && SPI_MASTER |
178 | depends on MACH_WLF_CRAGG_6410 || COMPILE_TEST | ||
178 | select SND_SAMSUNG_I2S | 179 | select SND_SAMSUNG_I2S |
179 | select SND_SOC_WM8996 | 180 | select SND_SOC_WM8996 |
180 | select SND_SOC_WM9081 | 181 | select SND_SOC_WM9081 |
@@ -183,13 +184,15 @@ config SND_SOC_SPEYSIDE | |||
183 | 184 | ||
184 | config SND_SOC_TOBERMORY | 185 | config SND_SOC_TOBERMORY |
185 | tristate "Audio support for Wolfson Tobermory" | 186 | tristate "Audio support for Wolfson Tobermory" |
186 | depends on SND_SOC_SAMSUNG && MACH_WLF_CRAGG_6410 && INPUT && I2C | 187 | depends on SND_SOC_SAMSUNG && INPUT && I2C |
188 | depends on MACH_WLF_CRAGG_6410 || COMPILE_TEST | ||
187 | select SND_SAMSUNG_I2S | 189 | select SND_SAMSUNG_I2S |
188 | select SND_SOC_WM8962 | 190 | select SND_SOC_WM8962 |
189 | 191 | ||
190 | config SND_SOC_BELLS | 192 | config SND_SOC_BELLS |
191 | tristate "Audio support for Wolfson Bells" | 193 | tristate "Audio support for Wolfson Bells" |
192 | depends on SND_SOC_SAMSUNG && MACH_WLF_CRAGG_6410 && MFD_ARIZONA && I2C && SPI_MASTER | 194 | depends on SND_SOC_SAMSUNG && MFD_ARIZONA && I2C && SPI_MASTER |
195 | depends on MACH_WLF_CRAGG_6410 || COMPILE_TEST | ||
193 | select SND_SAMSUNG_I2S | 196 | select SND_SAMSUNG_I2S |
194 | select SND_SOC_WM5102 | 197 | select SND_SOC_WM5102 |
195 | select SND_SOC_WM5110 | 198 | select SND_SOC_WM5110 |
@@ -199,14 +202,16 @@ config SND_SOC_BELLS | |||
199 | 202 | ||
200 | config SND_SOC_LOWLAND | 203 | config SND_SOC_LOWLAND |
201 | tristate "Audio support for Wolfson Lowland" | 204 | tristate "Audio support for Wolfson Lowland" |
202 | depends on SND_SOC_SAMSUNG && MACH_WLF_CRAGG_6410 && I2C | 205 | depends on SND_SOC_SAMSUNG && I2C |
206 | depends on MACH_WLF_CRAGG_6410 || COMPILE_TEST | ||
203 | select SND_SAMSUNG_I2S | 207 | select SND_SAMSUNG_I2S |
204 | select SND_SOC_WM5100 | 208 | select SND_SOC_WM5100 |
205 | select SND_SOC_WM9081 | 209 | select SND_SOC_WM9081 |
206 | 210 | ||
207 | config SND_SOC_LITTLEMILL | 211 | config SND_SOC_LITTLEMILL |
208 | tristate "Audio support for Wolfson Littlemill" | 212 | tristate "Audio support for Wolfson Littlemill" |
209 | depends on SND_SOC_SAMSUNG && MACH_WLF_CRAGG_6410 && I2C | 213 | depends on SND_SOC_SAMSUNG && I2C |
214 | depends on MACH_WLF_CRAGG_6410 || COMPILE_TEST | ||
210 | select SND_SAMSUNG_I2S | 215 | select SND_SAMSUNG_I2S |
211 | select MFD_WM8994 | 216 | select MFD_WM8994 |
212 | select SND_SOC_WM8994 | 217 | select SND_SOC_WM8994 |
diff --git a/sound/soc/samsung/i2s.c b/sound/soc/samsung/i2s.c index b92ab40d2be6..ea4ab374a223 100644 --- a/sound/soc/samsung/i2s.c +++ b/sound/soc/samsung/i2s.c | |||
@@ -1493,7 +1493,7 @@ static const struct samsung_i2s_dai_data samsung_dai_type_sec = { | |||
1493 | .dai_type = TYPE_SEC, | 1493 | .dai_type = TYPE_SEC, |
1494 | }; | 1494 | }; |
1495 | 1495 | ||
1496 | static struct platform_device_id samsung_i2s_driver_ids[] = { | 1496 | static const struct platform_device_id samsung_i2s_driver_ids[] = { |
1497 | { | 1497 | { |
1498 | .name = "samsung-i2s", | 1498 | .name = "samsung-i2s", |
1499 | .driver_data = (kernel_ulong_t)&i2sv3_dai_type, | 1499 | .driver_data = (kernel_ulong_t)&i2sv3_dai_type, |
diff --git a/sound/soc/samsung/lowland.c b/sound/soc/samsung/lowland.c index 5f156093101e..0d0f58208b75 100644 --- a/sound/soc/samsung/lowland.c +++ b/sound/soc/samsung/lowland.c | |||
@@ -72,7 +72,7 @@ static int lowland_wm9081_init(struct snd_soc_pcm_runtime *rtd) | |||
72 | { | 72 | { |
73 | struct snd_soc_codec *codec = rtd->codec; | 73 | struct snd_soc_codec *codec = rtd->codec; |
74 | 74 | ||
75 | snd_soc_dapm_nc_pin(&codec->dapm, "LINEOUT"); | 75 | snd_soc_dapm_nc_pin(&rtd->card->dapm, "LINEOUT"); |
76 | 76 | ||
77 | /* At any time the WM9081 is active it will have this clock */ | 77 | /* At any time the WM9081 is active it will have this clock */ |
78 | return snd_soc_codec_set_sysclk(codec, WM9081_SYSCLK_MCLK, 0, | 78 | return snd_soc_codec_set_sysclk(codec, WM9081_SYSCLK_MCLK, 0, |
diff --git a/sound/soc/samsung/s3c24xx-i2s.c b/sound/soc/samsung/s3c24xx-i2s.c index 326d3c3804e3..5bf723689692 100644 --- a/sound/soc/samsung/s3c24xx-i2s.c +++ b/sound/soc/samsung/s3c24xx-i2s.c | |||
@@ -461,8 +461,8 @@ static int s3c24xx_iis_dev_probe(struct platform_device *pdev) | |||
461 | return -ENOENT; | 461 | return -ENOENT; |
462 | } | 462 | } |
463 | s3c24xx_i2s.regs = devm_ioremap_resource(&pdev->dev, res); | 463 | s3c24xx_i2s.regs = devm_ioremap_resource(&pdev->dev, res); |
464 | if (s3c24xx_i2s.regs == NULL) | 464 | if (IS_ERR(s3c24xx_i2s.regs)) |
465 | return -ENXIO; | 465 | return PTR_ERR(s3c24xx_i2s.regs); |
466 | 466 | ||
467 | s3c24xx_i2s_pcm_stereo_out.dma_addr = res->start + S3C2410_IISFIFO; | 467 | s3c24xx_i2s_pcm_stereo_out.dma_addr = res->start + S3C2410_IISFIFO; |
468 | s3c24xx_i2s_pcm_stereo_in.dma_addr = res->start + S3C2410_IISFIFO; | 468 | s3c24xx_i2s_pcm_stereo_in.dma_addr = res->start + S3C2410_IISFIFO; |
diff --git a/sound/soc/samsung/smartq_wm8987.c b/sound/soc/samsung/smartq_wm8987.c index dfbe2db1c407..a0fe37fbed9f 100644 --- a/sound/soc/samsung/smartq_wm8987.c +++ b/sound/soc/samsung/smartq_wm8987.c | |||
@@ -137,8 +137,7 @@ static const struct snd_soc_dapm_route audio_map[] = { | |||
137 | 137 | ||
138 | static int smartq_wm8987_init(struct snd_soc_pcm_runtime *rtd) | 138 | static int smartq_wm8987_init(struct snd_soc_pcm_runtime *rtd) |
139 | { | 139 | { |
140 | struct snd_soc_codec *codec = rtd->codec; | 140 | struct snd_soc_dapm_context *dapm = &rtd->card->dapm; |
141 | struct snd_soc_dapm_context *dapm = &codec->dapm; | ||
142 | int err = 0; | 141 | int err = 0; |
143 | 142 | ||
144 | /* set endpoints to not connected */ | 143 | /* set endpoints to not connected */ |
@@ -147,9 +146,6 @@ static int smartq_wm8987_init(struct snd_soc_pcm_runtime *rtd) | |||
147 | snd_soc_dapm_nc_pin(dapm, "OUT3"); | 146 | snd_soc_dapm_nc_pin(dapm, "OUT3"); |
148 | snd_soc_dapm_nc_pin(dapm, "ROUT1"); | 147 | snd_soc_dapm_nc_pin(dapm, "ROUT1"); |
149 | 148 | ||
150 | /* set endpoints to default off mode */ | ||
151 | snd_soc_dapm_disable_pin(dapm, "Headphone Jack"); | ||
152 | |||
153 | /* Headphone jack detection */ | 149 | /* Headphone jack detection */ |
154 | err = snd_soc_card_jack_new(rtd->card, "Headphone Jack", | 150 | err = snd_soc_card_jack_new(rtd->card, "Headphone Jack", |
155 | SND_JACK_HEADPHONE, &smartq_jack, | 151 | SND_JACK_HEADPHONE, &smartq_jack, |
diff --git a/sound/soc/samsung/smdk_wm8994.c b/sound/soc/samsung/smdk_wm8994.c index d38595fbdab7..ff57b192d37d 100644 --- a/sound/soc/samsung/smdk_wm8994.c +++ b/sound/soc/samsung/smdk_wm8994.c | |||
@@ -86,8 +86,7 @@ static struct snd_soc_ops smdk_ops = { | |||
86 | 86 | ||
87 | static int smdk_wm8994_init_paiftx(struct snd_soc_pcm_runtime *rtd) | 87 | static int smdk_wm8994_init_paiftx(struct snd_soc_pcm_runtime *rtd) |
88 | { | 88 | { |
89 | struct snd_soc_codec *codec = rtd->codec; | 89 | struct snd_soc_dapm_context *dapm = &rtd->card->dapm; |
90 | struct snd_soc_dapm_context *dapm = &codec->dapm; | ||
91 | 90 | ||
92 | /* Other pins NC */ | 91 | /* Other pins NC */ |
93 | snd_soc_dapm_nc_pin(dapm, "HPOUT2P"); | 92 | snd_soc_dapm_nc_pin(dapm, "HPOUT2P"); |
diff --git a/sound/soc/samsung/speyside.c b/sound/soc/samsung/speyside.c index 2dcb988bdff2..d1ae21c5e253 100644 --- a/sound/soc/samsung/speyside.c +++ b/sound/soc/samsung/speyside.c | |||
@@ -123,7 +123,7 @@ static void speyside_set_polarity(struct snd_soc_codec *codec, | |||
123 | gpio_direction_output(WM8996_HPSEL_GPIO, speyside_jack_polarity); | 123 | gpio_direction_output(WM8996_HPSEL_GPIO, speyside_jack_polarity); |
124 | 124 | ||
125 | /* Re-run DAPM to make sure we're using the correct mic bias */ | 125 | /* Re-run DAPM to make sure we're using the correct mic bias */ |
126 | snd_soc_dapm_sync(&codec->dapm); | 126 | snd_soc_dapm_sync(snd_soc_codec_get_dapm(codec)); |
127 | } | 127 | } |
128 | 128 | ||
129 | static int speyside_wm0010_init(struct snd_soc_pcm_runtime *rtd) | 129 | static int speyside_wm0010_init(struct snd_soc_pcm_runtime *rtd) |
diff --git a/sound/soc/sh/rcar/core.c b/sound/soc/sh/rcar/core.c index 9f48d75fa992..f1e5920654f6 100644 --- a/sound/soc/sh/rcar/core.c +++ b/sound/soc/sh/rcar/core.c | |||
@@ -137,15 +137,17 @@ char *rsnd_mod_name(struct rsnd_mod *mod) | |||
137 | return mod->ops->name; | 137 | return mod->ops->name; |
138 | } | 138 | } |
139 | 139 | ||
140 | struct dma_chan *rsnd_mod_dma_req(struct rsnd_mod *mod) | 140 | struct dma_chan *rsnd_mod_dma_req(struct rsnd_dai_stream *io, |
141 | struct rsnd_mod *mod) | ||
141 | { | 142 | { |
142 | if (!mod || !mod->ops || !mod->ops->dma_req) | 143 | if (!mod || !mod->ops || !mod->ops->dma_req) |
143 | return NULL; | 144 | return NULL; |
144 | 145 | ||
145 | return mod->ops->dma_req(mod); | 146 | return mod->ops->dma_req(io, mod); |
146 | } | 147 | } |
147 | 148 | ||
148 | int rsnd_mod_init(struct rsnd_mod *mod, | 149 | int rsnd_mod_init(struct rsnd_priv *priv, |
150 | struct rsnd_mod *mod, | ||
149 | struct rsnd_mod_ops *ops, | 151 | struct rsnd_mod_ops *ops, |
150 | struct clk *clk, | 152 | struct clk *clk, |
151 | enum rsnd_mod_type type, | 153 | enum rsnd_mod_type type, |
@@ -160,6 +162,7 @@ int rsnd_mod_init(struct rsnd_mod *mod, | |||
160 | mod->ops = ops; | 162 | mod->ops = ops; |
161 | mod->type = type; | 163 | mod->type = type; |
162 | mod->clk = clk; | 164 | mod->clk = clk; |
165 | mod->priv = priv; | ||
163 | 166 | ||
164 | return ret; | 167 | return ret; |
165 | } | 168 | } |
@@ -170,13 +173,41 @@ void rsnd_mod_quit(struct rsnd_mod *mod) | |||
170 | clk_unprepare(mod->clk); | 173 | clk_unprepare(mod->clk); |
171 | } | 174 | } |
172 | 175 | ||
176 | void rsnd_mod_interrupt(struct rsnd_mod *mod, | ||
177 | void (*callback)(struct rsnd_mod *mod, | ||
178 | struct rsnd_dai_stream *io)) | ||
179 | { | ||
180 | struct rsnd_priv *priv = rsnd_mod_to_priv(mod); | ||
181 | struct rsnd_dai_stream *io; | ||
182 | struct rsnd_dai *rdai; | ||
183 | int i, j; | ||
184 | |||
185 | for_each_rsnd_dai(rdai, priv, j) { | ||
186 | |||
187 | for (i = 0; i < RSND_MOD_MAX; i++) { | ||
188 | io = &rdai->playback; | ||
189 | if (mod == io->mod[i]) | ||
190 | callback(mod, io); | ||
191 | |||
192 | io = &rdai->capture; | ||
193 | if (mod == io->mod[i]) | ||
194 | callback(mod, io); | ||
195 | } | ||
196 | } | ||
197 | } | ||
198 | |||
199 | int rsnd_io_is_working(struct rsnd_dai_stream *io) | ||
200 | { | ||
201 | /* see rsnd_dai_stream_init/quit() */ | ||
202 | return !!io->substream; | ||
203 | } | ||
204 | |||
173 | /* | 205 | /* |
174 | * settting function | 206 | * settting function |
175 | */ | 207 | */ |
176 | u32 rsnd_get_adinr(struct rsnd_mod *mod) | 208 | u32 rsnd_get_adinr(struct rsnd_mod *mod, struct rsnd_dai_stream *io) |
177 | { | 209 | { |
178 | struct rsnd_priv *priv = rsnd_mod_to_priv(mod); | 210 | struct rsnd_priv *priv = rsnd_mod_to_priv(mod); |
179 | struct rsnd_dai_stream *io = rsnd_mod_to_io(mod); | ||
180 | struct snd_pcm_runtime *runtime = rsnd_io_to_runtime(io); | 211 | struct snd_pcm_runtime *runtime = rsnd_io_to_runtime(io); |
181 | struct device *dev = rsnd_priv_to_dev(priv); | 212 | struct device *dev = rsnd_priv_to_dev(priv); |
182 | u32 adinr = runtime->channels; | 213 | u32 adinr = runtime->channels; |
@@ -199,26 +230,31 @@ u32 rsnd_get_adinr(struct rsnd_mod *mod) | |||
199 | /* | 230 | /* |
200 | * rsnd_dai functions | 231 | * rsnd_dai functions |
201 | */ | 232 | */ |
202 | #define __rsnd_mod_call(mod, func, param...) \ | 233 | #define __rsnd_mod_call(mod, io, func, param...) \ |
203 | ({ \ | 234 | ({ \ |
204 | struct rsnd_priv *priv = rsnd_mod_to_priv(mod); \ | 235 | struct rsnd_priv *priv = rsnd_mod_to_priv(mod); \ |
205 | struct device *dev = rsnd_priv_to_dev(priv); \ | 236 | struct device *dev = rsnd_priv_to_dev(priv); \ |
206 | u32 mask = (1 << __rsnd_mod_shift_##func) & ~(1 << 31); \ | 237 | u32 mask = 0xF << __rsnd_mod_shift_##func; \ |
207 | u32 call = __rsnd_mod_call_##func << __rsnd_mod_shift_##func; \ | 238 | u8 val = (mod->status >> __rsnd_mod_shift_##func) & 0xF; \ |
239 | u8 add = ((val + __rsnd_mod_add_##func) & 0xF); \ | ||
208 | int ret = 0; \ | 240 | int ret = 0; \ |
209 | if ((mod->status & mask) == call) { \ | 241 | int called = 0; \ |
210 | dev_dbg(dev, "%s[%d] %s\n", \ | 242 | if (val == __rsnd_mod_call_##func) { \ |
211 | rsnd_mod_name(mod), rsnd_mod_id(mod), #func); \ | 243 | called = 1; \ |
212 | ret = (mod)->ops->func(mod, param); \ | 244 | ret = (mod)->ops->func(mod, io, param); \ |
213 | mod->status = (mod->status & ~mask) | (~call & mask); \ | 245 | mod->status = (mod->status & ~mask) + \ |
246 | (add << __rsnd_mod_shift_##func); \ | ||
214 | } \ | 247 | } \ |
248 | dev_dbg(dev, "%s[%d] 0x%08x %s\n", \ | ||
249 | rsnd_mod_name(mod), rsnd_mod_id(mod), mod->status, \ | ||
250 | called ? #func : ""); \ | ||
215 | ret; \ | 251 | ret; \ |
216 | }) | 252 | }) |
217 | 253 | ||
218 | #define rsnd_mod_call(mod, func, param...) \ | 254 | #define rsnd_mod_call(mod, io, func, param...) \ |
219 | (!(mod) ? -ENODEV : \ | 255 | (!(mod) ? -ENODEV : \ |
220 | !((mod)->ops->func) ? 0 : \ | 256 | !((mod)->ops->func) ? 0 : \ |
221 | __rsnd_mod_call(mod, func, param)) | 257 | __rsnd_mod_call(mod, io, func, param)) |
222 | 258 | ||
223 | #define rsnd_dai_call(fn, io, param...) \ | 259 | #define rsnd_dai_call(fn, io, param...) \ |
224 | ({ \ | 260 | ({ \ |
@@ -228,7 +264,7 @@ u32 rsnd_get_adinr(struct rsnd_mod *mod) | |||
228 | mod = (io)->mod[i]; \ | 264 | mod = (io)->mod[i]; \ |
229 | if (!mod) \ | 265 | if (!mod) \ |
230 | continue; \ | 266 | continue; \ |
231 | ret = rsnd_mod_call(mod, fn, param); \ | 267 | ret = rsnd_mod_call(mod, io, fn, param); \ |
232 | if (ret < 0) \ | 268 | if (ret < 0) \ |
233 | break; \ | 269 | break; \ |
234 | } \ | 270 | } \ |
@@ -252,7 +288,6 @@ static int rsnd_dai_connect(struct rsnd_mod *mod, | |||
252 | } | 288 | } |
253 | 289 | ||
254 | io->mod[mod->type] = mod; | 290 | io->mod[mod->type] = mod; |
255 | mod->io = io; | ||
256 | 291 | ||
257 | return 0; | 292 | return 0; |
258 | } | 293 | } |
@@ -260,7 +295,6 @@ static int rsnd_dai_connect(struct rsnd_mod *mod, | |||
260 | static void rsnd_dai_disconnect(struct rsnd_mod *mod, | 295 | static void rsnd_dai_disconnect(struct rsnd_mod *mod, |
261 | struct rsnd_dai_stream *io) | 296 | struct rsnd_dai_stream *io) |
262 | { | 297 | { |
263 | mod->io = NULL; | ||
264 | io->mod[mod->type] = NULL; | 298 | io->mod[mod->type] = NULL; |
265 | } | 299 | } |
266 | 300 | ||
@@ -272,9 +306,10 @@ struct rsnd_dai *rsnd_rdai_get(struct rsnd_priv *priv, int id) | |||
272 | return priv->rdai + id; | 306 | return priv->rdai + id; |
273 | } | 307 | } |
274 | 308 | ||
309 | #define rsnd_dai_to_priv(dai) snd_soc_dai_get_drvdata(dai) | ||
275 | static struct rsnd_dai *rsnd_dai_to_rdai(struct snd_soc_dai *dai) | 310 | static struct rsnd_dai *rsnd_dai_to_rdai(struct snd_soc_dai *dai) |
276 | { | 311 | { |
277 | struct rsnd_priv *priv = snd_soc_dai_get_drvdata(dai); | 312 | struct rsnd_priv *priv = rsnd_dai_to_priv(dai); |
278 | 313 | ||
279 | return rsnd_rdai_get(priv, dai->id); | 314 | return rsnd_rdai_get(priv, dai->id); |
280 | } | 315 | } |
@@ -293,7 +328,7 @@ int rsnd_dai_pointer_offset(struct rsnd_dai_stream *io, int additional) | |||
293 | return pos; | 328 | return pos; |
294 | } | 329 | } |
295 | 330 | ||
296 | void rsnd_dai_pointer_update(struct rsnd_dai_stream *io, int byte) | 331 | bool rsnd_dai_pointer_update(struct rsnd_dai_stream *io, int byte) |
297 | { | 332 | { |
298 | io->byte_pos += byte; | 333 | io->byte_pos += byte; |
299 | 334 | ||
@@ -310,11 +345,27 @@ void rsnd_dai_pointer_update(struct rsnd_dai_stream *io, int byte) | |||
310 | io->next_period_byte = io->byte_per_period; | 345 | io->next_period_byte = io->byte_per_period; |
311 | } | 346 | } |
312 | 347 | ||
313 | snd_pcm_period_elapsed(substream); | 348 | return true; |
314 | } | 349 | } |
350 | |||
351 | return false; | ||
315 | } | 352 | } |
316 | 353 | ||
317 | static int rsnd_dai_stream_init(struct rsnd_dai_stream *io, | 354 | void rsnd_dai_period_elapsed(struct rsnd_dai_stream *io) |
355 | { | ||
356 | struct snd_pcm_substream *substream = io->substream; | ||
357 | |||
358 | /* | ||
359 | * this function should be called... | ||
360 | * | ||
361 | * - if rsnd_dai_pointer_update() returns true | ||
362 | * - without spin lock | ||
363 | */ | ||
364 | |||
365 | snd_pcm_period_elapsed(substream); | ||
366 | } | ||
367 | |||
368 | static void rsnd_dai_stream_init(struct rsnd_dai_stream *io, | ||
318 | struct snd_pcm_substream *substream) | 369 | struct snd_pcm_substream *substream) |
319 | { | 370 | { |
320 | struct snd_pcm_runtime *runtime = substream->runtime; | 371 | struct snd_pcm_runtime *runtime = substream->runtime; |
@@ -326,8 +377,11 @@ static int rsnd_dai_stream_init(struct rsnd_dai_stream *io, | |||
326 | runtime->channels * | 377 | runtime->channels * |
327 | samples_to_bytes(runtime, 1); | 378 | samples_to_bytes(runtime, 1); |
328 | io->next_period_byte = io->byte_per_period; | 379 | io->next_period_byte = io->byte_per_period; |
380 | } | ||
329 | 381 | ||
330 | return 0; | 382 | static void rsnd_dai_stream_quit(struct rsnd_dai_stream *io) |
383 | { | ||
384 | io->substream = NULL; | ||
331 | } | 385 | } |
332 | 386 | ||
333 | static | 387 | static |
@@ -351,20 +405,18 @@ struct rsnd_dai_stream *rsnd_rdai_to_io(struct rsnd_dai *rdai, | |||
351 | static int rsnd_soc_dai_trigger(struct snd_pcm_substream *substream, int cmd, | 405 | static int rsnd_soc_dai_trigger(struct snd_pcm_substream *substream, int cmd, |
352 | struct snd_soc_dai *dai) | 406 | struct snd_soc_dai *dai) |
353 | { | 407 | { |
354 | struct rsnd_priv *priv = snd_soc_dai_get_drvdata(dai); | 408 | struct rsnd_priv *priv = rsnd_dai_to_priv(dai); |
355 | struct rsnd_dai *rdai = rsnd_dai_to_rdai(dai); | 409 | struct rsnd_dai *rdai = rsnd_dai_to_rdai(dai); |
356 | struct rsnd_dai_stream *io = rsnd_rdai_to_io(rdai, substream); | 410 | struct rsnd_dai_stream *io = rsnd_rdai_to_io(rdai, substream); |
357 | int ssi_id = rsnd_mod_id(rsnd_io_to_mod_ssi(io)); | 411 | int ssi_id = rsnd_mod_id(rsnd_io_to_mod_ssi(io)); |
358 | int ret; | 412 | int ret; |
359 | unsigned long flags; | 413 | unsigned long flags; |
360 | 414 | ||
361 | rsnd_lock(priv, flags); | 415 | spin_lock_irqsave(&priv->lock, flags); |
362 | 416 | ||
363 | switch (cmd) { | 417 | switch (cmd) { |
364 | case SNDRV_PCM_TRIGGER_START: | 418 | case SNDRV_PCM_TRIGGER_START: |
365 | ret = rsnd_dai_stream_init(io, substream); | 419 | rsnd_dai_stream_init(io, substream); |
366 | if (ret < 0) | ||
367 | goto dai_trigger_end; | ||
368 | 420 | ||
369 | ret = rsnd_platform_call(priv, dai, start, ssi_id); | 421 | ret = rsnd_platform_call(priv, dai, start, ssi_id); |
370 | if (ret < 0) | 422 | if (ret < 0) |
@@ -390,13 +442,15 @@ static int rsnd_soc_dai_trigger(struct snd_pcm_substream *substream, int cmd, | |||
390 | ret = rsnd_platform_call(priv, dai, stop, ssi_id); | 442 | ret = rsnd_platform_call(priv, dai, stop, ssi_id); |
391 | if (ret < 0) | 443 | if (ret < 0) |
392 | goto dai_trigger_end; | 444 | goto dai_trigger_end; |
445 | |||
446 | rsnd_dai_stream_quit(io); | ||
393 | break; | 447 | break; |
394 | default: | 448 | default: |
395 | ret = -EINVAL; | 449 | ret = -EINVAL; |
396 | } | 450 | } |
397 | 451 | ||
398 | dai_trigger_end: | 452 | dai_trigger_end: |
399 | rsnd_unlock(priv, flags); | 453 | spin_unlock_irqrestore(&priv->lock, flags); |
400 | 454 | ||
401 | return ret; | 455 | return ret; |
402 | } | 456 | } |
@@ -822,23 +876,27 @@ static int rsnd_kctrl_put(struct snd_kcontrol *kctrl, | |||
822 | } | 876 | } |
823 | 877 | ||
824 | if (change) | 878 | if (change) |
825 | cfg->update(mod); | 879 | cfg->update(cfg->io, mod); |
826 | 880 | ||
827 | return change; | 881 | return change; |
828 | } | 882 | } |
829 | 883 | ||
830 | static int __rsnd_kctrl_new(struct rsnd_mod *mod, | 884 | static int __rsnd_kctrl_new(struct rsnd_mod *mod, |
885 | struct rsnd_dai_stream *io, | ||
831 | struct snd_soc_pcm_runtime *rtd, | 886 | struct snd_soc_pcm_runtime *rtd, |
832 | const unsigned char *name, | 887 | const unsigned char *name, |
833 | struct rsnd_kctrl_cfg *cfg, | 888 | struct rsnd_kctrl_cfg *cfg, |
834 | void (*update)(struct rsnd_mod *mod)) | 889 | void (*update)(struct rsnd_dai_stream *io, |
890 | struct rsnd_mod *mod)) | ||
835 | { | 891 | { |
892 | struct snd_soc_card *soc_card = rtd->card; | ||
836 | struct snd_card *card = rtd->card->snd_card; | 893 | struct snd_card *card = rtd->card->snd_card; |
837 | struct snd_kcontrol *kctrl; | 894 | struct snd_kcontrol *kctrl; |
838 | struct snd_kcontrol_new knew = { | 895 | struct snd_kcontrol_new knew = { |
839 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | 896 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, |
840 | .name = name, | 897 | .name = name, |
841 | .info = rsnd_kctrl_info, | 898 | .info = rsnd_kctrl_info, |
899 | .index = rtd - soc_card->rtd, | ||
842 | .get = rsnd_kctrl_get, | 900 | .get = rsnd_kctrl_get, |
843 | .put = rsnd_kctrl_put, | 901 | .put = rsnd_kctrl_put, |
844 | .private_value = (unsigned long)cfg, | 902 | .private_value = (unsigned long)cfg, |
@@ -858,6 +916,7 @@ static int __rsnd_kctrl_new(struct rsnd_mod *mod, | |||
858 | cfg->update = update; | 916 | cfg->update = update; |
859 | cfg->card = card; | 917 | cfg->card = card; |
860 | cfg->kctrl = kctrl; | 918 | cfg->kctrl = kctrl; |
919 | cfg->io = io; | ||
861 | 920 | ||
862 | return 0; | 921 | return 0; |
863 | } | 922 | } |
@@ -868,36 +927,42 @@ void _rsnd_kctrl_remove(struct rsnd_kctrl_cfg *cfg) | |||
868 | } | 927 | } |
869 | 928 | ||
870 | int rsnd_kctrl_new_m(struct rsnd_mod *mod, | 929 | int rsnd_kctrl_new_m(struct rsnd_mod *mod, |
930 | struct rsnd_dai_stream *io, | ||
871 | struct snd_soc_pcm_runtime *rtd, | 931 | struct snd_soc_pcm_runtime *rtd, |
872 | const unsigned char *name, | 932 | const unsigned char *name, |
873 | void (*update)(struct rsnd_mod *mod), | 933 | void (*update)(struct rsnd_dai_stream *io, |
934 | struct rsnd_mod *mod), | ||
874 | struct rsnd_kctrl_cfg_m *_cfg, | 935 | struct rsnd_kctrl_cfg_m *_cfg, |
875 | u32 max) | 936 | u32 max) |
876 | { | 937 | { |
877 | _cfg->cfg.max = max; | 938 | _cfg->cfg.max = max; |
878 | _cfg->cfg.size = RSND_DVC_CHANNELS; | 939 | _cfg->cfg.size = RSND_DVC_CHANNELS; |
879 | _cfg->cfg.val = _cfg->val; | 940 | _cfg->cfg.val = _cfg->val; |
880 | return __rsnd_kctrl_new(mod, rtd, name, &_cfg->cfg, update); | 941 | return __rsnd_kctrl_new(mod, io, rtd, name, &_cfg->cfg, update); |
881 | } | 942 | } |
882 | 943 | ||
883 | int rsnd_kctrl_new_s(struct rsnd_mod *mod, | 944 | int rsnd_kctrl_new_s(struct rsnd_mod *mod, |
945 | struct rsnd_dai_stream *io, | ||
884 | struct snd_soc_pcm_runtime *rtd, | 946 | struct snd_soc_pcm_runtime *rtd, |
885 | const unsigned char *name, | 947 | const unsigned char *name, |
886 | void (*update)(struct rsnd_mod *mod), | 948 | void (*update)(struct rsnd_dai_stream *io, |
949 | struct rsnd_mod *mod), | ||
887 | struct rsnd_kctrl_cfg_s *_cfg, | 950 | struct rsnd_kctrl_cfg_s *_cfg, |
888 | u32 max) | 951 | u32 max) |
889 | { | 952 | { |
890 | _cfg->cfg.max = max; | 953 | _cfg->cfg.max = max; |
891 | _cfg->cfg.size = 1; | 954 | _cfg->cfg.size = 1; |
892 | _cfg->cfg.val = &_cfg->val; | 955 | _cfg->cfg.val = &_cfg->val; |
893 | return __rsnd_kctrl_new(mod, rtd, name, &_cfg->cfg, update); | 956 | return __rsnd_kctrl_new(mod, io, rtd, name, &_cfg->cfg, update); |
894 | } | 957 | } |
895 | 958 | ||
896 | int rsnd_kctrl_new_e(struct rsnd_mod *mod, | 959 | int rsnd_kctrl_new_e(struct rsnd_mod *mod, |
960 | struct rsnd_dai_stream *io, | ||
897 | struct snd_soc_pcm_runtime *rtd, | 961 | struct snd_soc_pcm_runtime *rtd, |
898 | const unsigned char *name, | 962 | const unsigned char *name, |
899 | struct rsnd_kctrl_cfg_s *_cfg, | 963 | struct rsnd_kctrl_cfg_s *_cfg, |
900 | void (*update)(struct rsnd_mod *mod), | 964 | void (*update)(struct rsnd_dai_stream *io, |
965 | struct rsnd_mod *mod), | ||
901 | const char * const *texts, | 966 | const char * const *texts, |
902 | u32 max) | 967 | u32 max) |
903 | { | 968 | { |
@@ -905,7 +970,7 @@ int rsnd_kctrl_new_e(struct rsnd_mod *mod, | |||
905 | _cfg->cfg.size = 1; | 970 | _cfg->cfg.size = 1; |
906 | _cfg->cfg.val = &_cfg->val; | 971 | _cfg->cfg.val = &_cfg->val; |
907 | _cfg->cfg.texts = texts; | 972 | _cfg->cfg.texts = texts; |
908 | return __rsnd_kctrl_new(mod, rtd, name, &_cfg->cfg, update); | 973 | return __rsnd_kctrl_new(mod, io, rtd, name, &_cfg->cfg, update); |
909 | } | 974 | } |
910 | 975 | ||
911 | /* | 976 | /* |
diff --git a/sound/soc/sh/rcar/dma.c b/sound/soc/sh/rcar/dma.c index ac3756f6af60..d306e298c63d 100644 --- a/sound/soc/sh/rcar/dma.c +++ b/sound/soc/sh/rcar/dma.c | |||
@@ -32,11 +32,12 @@ struct rsnd_dma_ctrl { | |||
32 | /* | 32 | /* |
33 | * Audio DMAC | 33 | * Audio DMAC |
34 | */ | 34 | */ |
35 | static void rsnd_dmaen_complete(void *data) | 35 | static void __rsnd_dmaen_complete(struct rsnd_mod *mod, |
36 | struct rsnd_dai_stream *io) | ||
36 | { | 37 | { |
37 | struct rsnd_dma *dma = (struct rsnd_dma *)data; | 38 | struct rsnd_priv *priv = rsnd_mod_to_priv(mod); |
38 | struct rsnd_mod *mod = rsnd_dma_to_mod(dma); | 39 | bool elapsed = false; |
39 | struct rsnd_dai_stream *io = rsnd_mod_to_io(mod); | 40 | unsigned long flags; |
40 | 41 | ||
41 | /* | 42 | /* |
42 | * Renesas sound Gen1 needs 1 DMAC, | 43 | * Renesas sound Gen1 needs 1 DMAC, |
@@ -49,23 +50,36 @@ static void rsnd_dmaen_complete(void *data) | |||
49 | * rsnd_dai_pointer_update() will be called twice, | 50 | * rsnd_dai_pointer_update() will be called twice, |
50 | * ant it will breaks io->byte_pos | 51 | * ant it will breaks io->byte_pos |
51 | */ | 52 | */ |
53 | spin_lock_irqsave(&priv->lock, flags); | ||
54 | |||
55 | if (rsnd_io_is_working(io)) | ||
56 | elapsed = rsnd_dai_pointer_update(io, io->byte_per_period); | ||
52 | 57 | ||
53 | rsnd_dai_pointer_update(io, io->byte_per_period); | 58 | spin_unlock_irqrestore(&priv->lock, flags); |
59 | |||
60 | if (elapsed) | ||
61 | rsnd_dai_period_elapsed(io); | ||
54 | } | 62 | } |
55 | 63 | ||
56 | static void rsnd_dmaen_stop(struct rsnd_dma *dma) | 64 | static void rsnd_dmaen_complete(void *data) |
65 | { | ||
66 | struct rsnd_mod *mod = data; | ||
67 | |||
68 | rsnd_mod_interrupt(mod, __rsnd_dmaen_complete); | ||
69 | } | ||
70 | |||
71 | static void rsnd_dmaen_stop(struct rsnd_dai_stream *io, struct rsnd_dma *dma) | ||
57 | { | 72 | { |
58 | struct rsnd_dmaen *dmaen = rsnd_dma_to_dmaen(dma); | 73 | struct rsnd_dmaen *dmaen = rsnd_dma_to_dmaen(dma); |
59 | 74 | ||
60 | dmaengine_terminate_all(dmaen->chan); | 75 | dmaengine_terminate_all(dmaen->chan); |
61 | } | 76 | } |
62 | 77 | ||
63 | static void rsnd_dmaen_start(struct rsnd_dma *dma) | 78 | static void rsnd_dmaen_start(struct rsnd_dai_stream *io, struct rsnd_dma *dma) |
64 | { | 79 | { |
65 | struct rsnd_dmaen *dmaen = rsnd_dma_to_dmaen(dma); | 80 | struct rsnd_dmaen *dmaen = rsnd_dma_to_dmaen(dma); |
66 | struct rsnd_mod *mod = rsnd_dma_to_mod(dma); | 81 | struct rsnd_mod *mod = rsnd_dma_to_mod(dma); |
67 | struct rsnd_priv *priv = rsnd_mod_to_priv(mod); | 82 | struct rsnd_priv *priv = rsnd_mod_to_priv(mod); |
68 | struct rsnd_dai_stream *io = rsnd_mod_to_io(mod); | ||
69 | struct snd_pcm_substream *substream = io->substream; | 83 | struct snd_pcm_substream *substream = io->substream; |
70 | struct device *dev = rsnd_priv_to_dev(priv); | 84 | struct device *dev = rsnd_priv_to_dev(priv); |
71 | struct dma_async_tx_descriptor *desc; | 85 | struct dma_async_tx_descriptor *desc; |
@@ -84,7 +98,7 @@ static void rsnd_dmaen_start(struct rsnd_dma *dma) | |||
84 | } | 98 | } |
85 | 99 | ||
86 | desc->callback = rsnd_dmaen_complete; | 100 | desc->callback = rsnd_dmaen_complete; |
87 | desc->callback_param = dma; | 101 | desc->callback_param = mod; |
88 | 102 | ||
89 | if (dmaengine_submit(desc) < 0) { | 103 | if (dmaengine_submit(desc) < 0) { |
90 | dev_err(dev, "dmaengine_submit() fail\n"); | 104 | dev_err(dev, "dmaengine_submit() fail\n"); |
@@ -115,7 +129,8 @@ struct dma_chan *rsnd_dma_request_channel(struct device_node *of_node, | |||
115 | return chan; | 129 | return chan; |
116 | } | 130 | } |
117 | 131 | ||
118 | static struct dma_chan *rsnd_dmaen_request_channel(struct rsnd_mod *mod_from, | 132 | static struct dma_chan *rsnd_dmaen_request_channel(struct rsnd_dai_stream *io, |
133 | struct rsnd_mod *mod_from, | ||
119 | struct rsnd_mod *mod_to) | 134 | struct rsnd_mod *mod_to) |
120 | { | 135 | { |
121 | if ((!mod_from && !mod_to) || | 136 | if ((!mod_from && !mod_to) || |
@@ -123,19 +138,19 @@ static struct dma_chan *rsnd_dmaen_request_channel(struct rsnd_mod *mod_from, | |||
123 | return NULL; | 138 | return NULL; |
124 | 139 | ||
125 | if (mod_from) | 140 | if (mod_from) |
126 | return rsnd_mod_dma_req(mod_from); | 141 | return rsnd_mod_dma_req(io, mod_from); |
127 | else | 142 | else |
128 | return rsnd_mod_dma_req(mod_to); | 143 | return rsnd_mod_dma_req(io, mod_to); |
129 | } | 144 | } |
130 | 145 | ||
131 | static int rsnd_dmaen_init(struct rsnd_priv *priv, struct rsnd_dma *dma, int id, | 146 | static int rsnd_dmaen_init(struct rsnd_dai_stream *io, |
147 | struct rsnd_dma *dma, int id, | ||
132 | struct rsnd_mod *mod_from, struct rsnd_mod *mod_to) | 148 | struct rsnd_mod *mod_from, struct rsnd_mod *mod_to) |
133 | { | 149 | { |
134 | struct rsnd_dmaen *dmaen = rsnd_dma_to_dmaen(dma); | 150 | struct rsnd_dmaen *dmaen = rsnd_dma_to_dmaen(dma); |
151 | struct rsnd_priv *priv = rsnd_io_to_priv(io); | ||
135 | struct device *dev = rsnd_priv_to_dev(priv); | 152 | struct device *dev = rsnd_priv_to_dev(priv); |
136 | struct dma_slave_config cfg = {}; | 153 | struct dma_slave_config cfg = {}; |
137 | struct rsnd_mod *mod = rsnd_dma_to_mod(dma); | ||
138 | struct rsnd_dai_stream *io = rsnd_mod_to_io(mod); | ||
139 | int is_play = rsnd_io_is_play(io); | 154 | int is_play = rsnd_io_is_play(io); |
140 | int ret; | 155 | int ret; |
141 | 156 | ||
@@ -145,7 +160,7 @@ static int rsnd_dmaen_init(struct rsnd_priv *priv, struct rsnd_dma *dma, int id, | |||
145 | } | 160 | } |
146 | 161 | ||
147 | if (dev->of_node) { | 162 | if (dev->of_node) { |
148 | dmaen->chan = rsnd_dmaen_request_channel(mod_from, mod_to); | 163 | dmaen->chan = rsnd_dmaen_request_channel(io, mod_from, mod_to); |
149 | } else { | 164 | } else { |
150 | dma_cap_mask_t mask; | 165 | dma_cap_mask_t mask; |
151 | 166 | ||
@@ -156,6 +171,7 @@ static int rsnd_dmaen_init(struct rsnd_priv *priv, struct rsnd_dma *dma, int id, | |||
156 | (void *)id); | 171 | (void *)id); |
157 | } | 172 | } |
158 | if (IS_ERR_OR_NULL(dmaen->chan)) { | 173 | if (IS_ERR_OR_NULL(dmaen->chan)) { |
174 | dmaen->chan = NULL; | ||
159 | dev_err(dev, "can't get dma channel\n"); | 175 | dev_err(dev, "can't get dma channel\n"); |
160 | goto rsnd_dma_channel_err; | 176 | goto rsnd_dma_channel_err; |
161 | } | 177 | } |
@@ -176,7 +192,7 @@ static int rsnd_dmaen_init(struct rsnd_priv *priv, struct rsnd_dma *dma, int id, | |||
176 | return 0; | 192 | return 0; |
177 | 193 | ||
178 | rsnd_dma_init_err: | 194 | rsnd_dma_init_err: |
179 | rsnd_dma_quit(dma); | 195 | rsnd_dma_quit(io, dma); |
180 | rsnd_dma_channel_err: | 196 | rsnd_dma_channel_err: |
181 | 197 | ||
182 | /* | 198 | /* |
@@ -188,7 +204,7 @@ rsnd_dma_channel_err: | |||
188 | return -EAGAIN; | 204 | return -EAGAIN; |
189 | } | 205 | } |
190 | 206 | ||
191 | static void rsnd_dmaen_quit(struct rsnd_dma *dma) | 207 | static void rsnd_dmaen_quit(struct rsnd_dai_stream *io, struct rsnd_dma *dma) |
192 | { | 208 | { |
193 | struct rsnd_dmaen *dmaen = rsnd_dma_to_dmaen(dma); | 209 | struct rsnd_dmaen *dmaen = rsnd_dma_to_dmaen(dma); |
194 | 210 | ||
@@ -237,9 +253,9 @@ static const u8 gen2_id_table_cmd[] = { | |||
237 | 0x38, /* SCU_CMD1 */ | 253 | 0x38, /* SCU_CMD1 */ |
238 | }; | 254 | }; |
239 | 255 | ||
240 | static u32 rsnd_dmapp_get_id(struct rsnd_mod *mod) | 256 | static u32 rsnd_dmapp_get_id(struct rsnd_dai_stream *io, |
257 | struct rsnd_mod *mod) | ||
241 | { | 258 | { |
242 | struct rsnd_dai_stream *io = rsnd_mod_to_io(mod); | ||
243 | struct rsnd_mod *ssi = rsnd_io_to_mod_ssi(io); | 259 | struct rsnd_mod *ssi = rsnd_io_to_mod_ssi(io); |
244 | struct rsnd_mod *src = rsnd_io_to_mod_src(io); | 260 | struct rsnd_mod *src = rsnd_io_to_mod_src(io); |
245 | struct rsnd_mod *dvc = rsnd_io_to_mod_dvc(io); | 261 | struct rsnd_mod *dvc = rsnd_io_to_mod_dvc(io); |
@@ -267,11 +283,12 @@ static u32 rsnd_dmapp_get_id(struct rsnd_mod *mod) | |||
267 | return entry[id]; | 283 | return entry[id]; |
268 | } | 284 | } |
269 | 285 | ||
270 | static u32 rsnd_dmapp_get_chcr(struct rsnd_mod *mod_from, | 286 | static u32 rsnd_dmapp_get_chcr(struct rsnd_dai_stream *io, |
287 | struct rsnd_mod *mod_from, | ||
271 | struct rsnd_mod *mod_to) | 288 | struct rsnd_mod *mod_to) |
272 | { | 289 | { |
273 | return (rsnd_dmapp_get_id(mod_from) << 24) + | 290 | return (rsnd_dmapp_get_id(io, mod_from) << 24) + |
274 | (rsnd_dmapp_get_id(mod_to) << 16); | 291 | (rsnd_dmapp_get_id(io, mod_to) << 16); |
275 | } | 292 | } |
276 | 293 | ||
277 | #define rsnd_dmapp_addr(dmac, dma, reg) \ | 294 | #define rsnd_dmapp_addr(dmac, dma, reg) \ |
@@ -298,7 +315,7 @@ static u32 rsnd_dmapp_read(struct rsnd_dma *dma, u32 reg) | |||
298 | return ioread32(rsnd_dmapp_addr(dmac, dma, reg)); | 315 | return ioread32(rsnd_dmapp_addr(dmac, dma, reg)); |
299 | } | 316 | } |
300 | 317 | ||
301 | static void rsnd_dmapp_stop(struct rsnd_dma *dma) | 318 | static void rsnd_dmapp_stop(struct rsnd_dai_stream *io, struct rsnd_dma *dma) |
302 | { | 319 | { |
303 | int i; | 320 | int i; |
304 | 321 | ||
@@ -311,7 +328,7 @@ static void rsnd_dmapp_stop(struct rsnd_dma *dma) | |||
311 | } | 328 | } |
312 | } | 329 | } |
313 | 330 | ||
314 | static void rsnd_dmapp_start(struct rsnd_dma *dma) | 331 | static void rsnd_dmapp_start(struct rsnd_dai_stream *io, struct rsnd_dma *dma) |
315 | { | 332 | { |
316 | struct rsnd_dmapp *dmapp = rsnd_dma_to_dmapp(dma); | 333 | struct rsnd_dmapp *dmapp = rsnd_dma_to_dmapp(dma); |
317 | 334 | ||
@@ -320,19 +337,21 @@ static void rsnd_dmapp_start(struct rsnd_dma *dma) | |||
320 | rsnd_dmapp_write(dma, dmapp->chcr, PDMACHCR); | 337 | rsnd_dmapp_write(dma, dmapp->chcr, PDMACHCR); |
321 | } | 338 | } |
322 | 339 | ||
323 | static int rsnd_dmapp_init(struct rsnd_priv *priv, struct rsnd_dma *dma, int id, | 340 | static int rsnd_dmapp_init(struct rsnd_dai_stream *io, |
341 | struct rsnd_dma *dma, int id, | ||
324 | struct rsnd_mod *mod_from, struct rsnd_mod *mod_to) | 342 | struct rsnd_mod *mod_from, struct rsnd_mod *mod_to) |
325 | { | 343 | { |
326 | struct rsnd_dmapp *dmapp = rsnd_dma_to_dmapp(dma); | 344 | struct rsnd_dmapp *dmapp = rsnd_dma_to_dmapp(dma); |
345 | struct rsnd_priv *priv = rsnd_io_to_priv(io); | ||
327 | struct rsnd_dma_ctrl *dmac = rsnd_priv_to_dmac(priv); | 346 | struct rsnd_dma_ctrl *dmac = rsnd_priv_to_dmac(priv); |
328 | struct device *dev = rsnd_priv_to_dev(priv); | 347 | struct device *dev = rsnd_priv_to_dev(priv); |
329 | 348 | ||
330 | dmapp->dmapp_id = dmac->dmapp_num; | 349 | dmapp->dmapp_id = dmac->dmapp_num; |
331 | dmapp->chcr = rsnd_dmapp_get_chcr(mod_from, mod_to) | PDMACHCR_DE; | 350 | dmapp->chcr = rsnd_dmapp_get_chcr(io, mod_from, mod_to) | PDMACHCR_DE; |
332 | 351 | ||
333 | dmac->dmapp_num++; | 352 | dmac->dmapp_num++; |
334 | 353 | ||
335 | rsnd_dmapp_stop(dma); | 354 | rsnd_dmapp_stop(io, dma); |
336 | 355 | ||
337 | dev_dbg(dev, "id/src/dst/chcr = %d/%pad/%pad/%08x\n", | 356 | dev_dbg(dev, "id/src/dst/chcr = %d/%pad/%pad/%08x\n", |
338 | dmapp->dmapp_id, &dma->src_addr, &dma->dst_addr, dmapp->chcr); | 357 | dmapp->dmapp_id, &dma->src_addr, &dma->dst_addr, dmapp->chcr); |
@@ -385,12 +404,12 @@ static struct rsnd_dma_ops rsnd_dmapp_ops = { | |||
385 | #define RDMA_CMD_O_P(addr, i) (addr ##_reg - 0x001f8000 + (0x400 * i)) | 404 | #define RDMA_CMD_O_P(addr, i) (addr ##_reg - 0x001f8000 + (0x400 * i)) |
386 | 405 | ||
387 | static dma_addr_t | 406 | static dma_addr_t |
388 | rsnd_gen2_dma_addr(struct rsnd_priv *priv, | 407 | rsnd_gen2_dma_addr(struct rsnd_dai_stream *io, |
389 | struct rsnd_mod *mod, | 408 | struct rsnd_mod *mod, |
390 | int is_play, int is_from) | 409 | int is_play, int is_from) |
391 | { | 410 | { |
411 | struct rsnd_priv *priv = rsnd_io_to_priv(io); | ||
392 | struct device *dev = rsnd_priv_to_dev(priv); | 412 | struct device *dev = rsnd_priv_to_dev(priv); |
393 | struct rsnd_dai_stream *io = rsnd_mod_to_io(mod); | ||
394 | phys_addr_t ssi_reg = rsnd_gen_get_phy_addr(priv, RSND_GEN2_SSI); | 413 | phys_addr_t ssi_reg = rsnd_gen_get_phy_addr(priv, RSND_GEN2_SSI); |
395 | phys_addr_t src_reg = rsnd_gen_get_phy_addr(priv, RSND_GEN2_SCU); | 414 | phys_addr_t src_reg = rsnd_gen_get_phy_addr(priv, RSND_GEN2_SCU); |
396 | int is_ssi = !!(rsnd_io_to_mod_ssi(io) == mod); | 415 | int is_ssi = !!(rsnd_io_to_mod_ssi(io) == mod); |
@@ -437,7 +456,7 @@ rsnd_gen2_dma_addr(struct rsnd_priv *priv, | |||
437 | dev_err(dev, "DVC is selected without SRC\n"); | 456 | dev_err(dev, "DVC is selected without SRC\n"); |
438 | 457 | ||
439 | /* use SSIU or SSI ? */ | 458 | /* use SSIU or SSI ? */ |
440 | if (is_ssi && rsnd_ssi_use_busif(mod)) | 459 | if (is_ssi && rsnd_ssi_use_busif(io, mod)) |
441 | is_ssi++; | 460 | is_ssi++; |
442 | 461 | ||
443 | return (is_from) ? | 462 | return (is_from) ? |
@@ -445,10 +464,12 @@ rsnd_gen2_dma_addr(struct rsnd_priv *priv, | |||
445 | dma_addrs[is_ssi][is_play][use_src + use_dvc].in_addr; | 464 | dma_addrs[is_ssi][is_play][use_src + use_dvc].in_addr; |
446 | } | 465 | } |
447 | 466 | ||
448 | static dma_addr_t rsnd_dma_addr(struct rsnd_priv *priv, | 467 | static dma_addr_t rsnd_dma_addr(struct rsnd_dai_stream *io, |
449 | struct rsnd_mod *mod, | 468 | struct rsnd_mod *mod, |
450 | int is_play, int is_from) | 469 | int is_play, int is_from) |
451 | { | 470 | { |
471 | struct rsnd_priv *priv = rsnd_io_to_priv(io); | ||
472 | |||
452 | /* | 473 | /* |
453 | * gen1 uses default DMA addr | 474 | * gen1 uses default DMA addr |
454 | */ | 475 | */ |
@@ -458,17 +479,17 @@ static dma_addr_t rsnd_dma_addr(struct rsnd_priv *priv, | |||
458 | if (!mod) | 479 | if (!mod) |
459 | return 0; | 480 | return 0; |
460 | 481 | ||
461 | return rsnd_gen2_dma_addr(priv, mod, is_play, is_from); | 482 | return rsnd_gen2_dma_addr(io, mod, is_play, is_from); |
462 | } | 483 | } |
463 | 484 | ||
464 | #define MOD_MAX 4 /* MEM/SSI/SRC/DVC */ | 485 | #define MOD_MAX 4 /* MEM/SSI/SRC/DVC */ |
465 | static void rsnd_dma_of_path(struct rsnd_dma *dma, | 486 | static void rsnd_dma_of_path(struct rsnd_dma *dma, |
487 | struct rsnd_dai_stream *io, | ||
466 | int is_play, | 488 | int is_play, |
467 | struct rsnd_mod **mod_from, | 489 | struct rsnd_mod **mod_from, |
468 | struct rsnd_mod **mod_to) | 490 | struct rsnd_mod **mod_to) |
469 | { | 491 | { |
470 | struct rsnd_mod *this = rsnd_dma_to_mod(dma); | 492 | struct rsnd_mod *this = rsnd_dma_to_mod(dma); |
471 | struct rsnd_dai_stream *io = rsnd_mod_to_io(this); | ||
472 | struct rsnd_mod *ssi = rsnd_io_to_mod_ssi(io); | 493 | struct rsnd_mod *ssi = rsnd_io_to_mod_ssi(io); |
473 | struct rsnd_mod *src = rsnd_io_to_mod_src(io); | 494 | struct rsnd_mod *src = rsnd_io_to_mod_src(io); |
474 | struct rsnd_mod *dvc = rsnd_io_to_mod_dvc(io); | 495 | struct rsnd_mod *dvc = rsnd_io_to_mod_dvc(io); |
@@ -523,17 +544,17 @@ static void rsnd_dma_of_path(struct rsnd_dma *dma, | |||
523 | } | 544 | } |
524 | } | 545 | } |
525 | 546 | ||
526 | void rsnd_dma_stop(struct rsnd_dma *dma) | 547 | void rsnd_dma_stop(struct rsnd_dai_stream *io, struct rsnd_dma *dma) |
527 | { | 548 | { |
528 | dma->ops->stop(dma); | 549 | dma->ops->stop(io, dma); |
529 | } | 550 | } |
530 | 551 | ||
531 | void rsnd_dma_start(struct rsnd_dma *dma) | 552 | void rsnd_dma_start(struct rsnd_dai_stream *io, struct rsnd_dma *dma) |
532 | { | 553 | { |
533 | dma->ops->start(dma); | 554 | dma->ops->start(io, dma); |
534 | } | 555 | } |
535 | 556 | ||
536 | void rsnd_dma_quit(struct rsnd_dma *dma) | 557 | void rsnd_dma_quit(struct rsnd_dai_stream *io, struct rsnd_dma *dma) |
537 | { | 558 | { |
538 | struct rsnd_mod *mod = rsnd_dma_to_mod(dma); | 559 | struct rsnd_mod *mod = rsnd_dma_to_mod(dma); |
539 | struct rsnd_priv *priv = rsnd_mod_to_priv(mod); | 560 | struct rsnd_priv *priv = rsnd_mod_to_priv(mod); |
@@ -542,15 +563,14 @@ void rsnd_dma_quit(struct rsnd_dma *dma) | |||
542 | if (!dmac) | 563 | if (!dmac) |
543 | return; | 564 | return; |
544 | 565 | ||
545 | dma->ops->quit(dma); | 566 | dma->ops->quit(io, dma); |
546 | } | 567 | } |
547 | 568 | ||
548 | int rsnd_dma_init(struct rsnd_priv *priv, struct rsnd_dma *dma, int id) | 569 | int rsnd_dma_init(struct rsnd_dai_stream *io, struct rsnd_dma *dma, int id) |
549 | { | 570 | { |
550 | struct rsnd_mod *mod = rsnd_dma_to_mod(dma); | ||
551 | struct rsnd_mod *mod_from; | 571 | struct rsnd_mod *mod_from; |
552 | struct rsnd_mod *mod_to; | 572 | struct rsnd_mod *mod_to; |
553 | struct rsnd_dai_stream *io = rsnd_mod_to_io(mod); | 573 | struct rsnd_priv *priv = rsnd_io_to_priv(io); |
554 | struct rsnd_dma_ctrl *dmac = rsnd_priv_to_dmac(priv); | 574 | struct rsnd_dma_ctrl *dmac = rsnd_priv_to_dmac(priv); |
555 | int is_play = rsnd_io_is_play(io); | 575 | int is_play = rsnd_io_is_play(io); |
556 | 576 | ||
@@ -563,10 +583,10 @@ int rsnd_dma_init(struct rsnd_priv *priv, struct rsnd_dma *dma, int id) | |||
563 | if (!dmac) | 583 | if (!dmac) |
564 | return -EAGAIN; | 584 | return -EAGAIN; |
565 | 585 | ||
566 | rsnd_dma_of_path(dma, is_play, &mod_from, &mod_to); | 586 | rsnd_dma_of_path(dma, io, is_play, &mod_from, &mod_to); |
567 | 587 | ||
568 | dma->src_addr = rsnd_dma_addr(priv, mod_from, is_play, 1); | 588 | dma->src_addr = rsnd_dma_addr(io, mod_from, is_play, 1); |
569 | dma->dst_addr = rsnd_dma_addr(priv, mod_to, is_play, 0); | 589 | dma->dst_addr = rsnd_dma_addr(io, mod_to, is_play, 0); |
570 | 590 | ||
571 | /* for Gen2 */ | 591 | /* for Gen2 */ |
572 | if (mod_from && mod_to) | 592 | if (mod_from && mod_to) |
@@ -578,7 +598,7 @@ int rsnd_dma_init(struct rsnd_priv *priv, struct rsnd_dma *dma, int id) | |||
578 | if (rsnd_is_gen1(priv)) | 598 | if (rsnd_is_gen1(priv)) |
579 | dma->ops = &rsnd_dmaen_ops; | 599 | dma->ops = &rsnd_dmaen_ops; |
580 | 600 | ||
581 | return dma->ops->init(priv, dma, id, mod_from, mod_to); | 601 | return dma->ops->init(io, dma, id, mod_from, mod_to); |
582 | } | 602 | } |
583 | 603 | ||
584 | int rsnd_dma_probe(struct platform_device *pdev, | 604 | int rsnd_dma_probe(struct platform_device *pdev, |
diff --git a/sound/soc/sh/rcar/dvc.c b/sound/soc/sh/rcar/dvc.c index e5fcb062ad77..36fc020cbc18 100644 --- a/sound/soc/sh/rcar/dvc.c +++ b/sound/soc/sh/rcar/dvc.c | |||
@@ -63,7 +63,8 @@ static const char * const dvc_ramp_rate[] = { | |||
63 | "0.125 dB/8192 steps", /* 10111 */ | 63 | "0.125 dB/8192 steps", /* 10111 */ |
64 | }; | 64 | }; |
65 | 65 | ||
66 | static void rsnd_dvc_volume_update(struct rsnd_mod *mod) | 66 | static void rsnd_dvc_volume_update(struct rsnd_dai_stream *io, |
67 | struct rsnd_mod *mod) | ||
67 | { | 68 | { |
68 | struct rsnd_dvc *dvc = rsnd_mod_to_dvc(mod); | 69 | struct rsnd_dvc *dvc = rsnd_mod_to_dvc(mod); |
69 | u32 val[RSND_DVC_CHANNELS]; | 70 | u32 val[RSND_DVC_CHANNELS]; |
@@ -120,6 +121,7 @@ static void rsnd_dvc_volume_update(struct rsnd_mod *mod) | |||
120 | } | 121 | } |
121 | 122 | ||
122 | static int rsnd_dvc_remove_gen2(struct rsnd_mod *mod, | 123 | static int rsnd_dvc_remove_gen2(struct rsnd_mod *mod, |
124 | struct rsnd_dai_stream *io, | ||
123 | struct rsnd_priv *priv) | 125 | struct rsnd_priv *priv) |
124 | { | 126 | { |
125 | struct rsnd_dvc *dvc = rsnd_mod_to_dvc(mod); | 127 | struct rsnd_dvc *dvc = rsnd_mod_to_dvc(mod); |
@@ -134,9 +136,9 @@ static int rsnd_dvc_remove_gen2(struct rsnd_mod *mod, | |||
134 | } | 136 | } |
135 | 137 | ||
136 | static int rsnd_dvc_init(struct rsnd_mod *dvc_mod, | 138 | static int rsnd_dvc_init(struct rsnd_mod *dvc_mod, |
139 | struct rsnd_dai_stream *io, | ||
137 | struct rsnd_priv *priv) | 140 | struct rsnd_priv *priv) |
138 | { | 141 | { |
139 | struct rsnd_dai_stream *io = rsnd_mod_to_io(dvc_mod); | ||
140 | struct rsnd_mod *src_mod = rsnd_io_to_mod_src(io); | 142 | struct rsnd_mod *src_mod = rsnd_io_to_mod_src(io); |
141 | struct device *dev = rsnd_priv_to_dev(priv); | 143 | struct device *dev = rsnd_priv_to_dev(priv); |
142 | int dvc_id = rsnd_mod_id(dvc_mod); | 144 | int dvc_id = rsnd_mod_id(dvc_mod); |
@@ -168,10 +170,10 @@ static int rsnd_dvc_init(struct rsnd_mod *dvc_mod, | |||
168 | 170 | ||
169 | rsnd_mod_write(dvc_mod, DVC_DVUIR, 1); | 171 | rsnd_mod_write(dvc_mod, DVC_DVUIR, 1); |
170 | 172 | ||
171 | rsnd_mod_write(dvc_mod, DVC_ADINR, rsnd_get_adinr(dvc_mod)); | 173 | rsnd_mod_write(dvc_mod, DVC_ADINR, rsnd_get_adinr(dvc_mod, io)); |
172 | 174 | ||
173 | /* ch0/ch1 Volume */ | 175 | /* ch0/ch1 Volume */ |
174 | rsnd_dvc_volume_update(dvc_mod); | 176 | rsnd_dvc_volume_update(io, dvc_mod); |
175 | 177 | ||
176 | rsnd_mod_write(dvc_mod, DVC_DVUIR, 0); | 178 | rsnd_mod_write(dvc_mod, DVC_DVUIR, 0); |
177 | 179 | ||
@@ -181,6 +183,7 @@ static int rsnd_dvc_init(struct rsnd_mod *dvc_mod, | |||
181 | } | 183 | } |
182 | 184 | ||
183 | static int rsnd_dvc_quit(struct rsnd_mod *mod, | 185 | static int rsnd_dvc_quit(struct rsnd_mod *mod, |
186 | struct rsnd_dai_stream *io, | ||
184 | struct rsnd_priv *priv) | 187 | struct rsnd_priv *priv) |
185 | { | 188 | { |
186 | rsnd_mod_hw_stop(mod); | 189 | rsnd_mod_hw_stop(mod); |
@@ -189,6 +192,7 @@ static int rsnd_dvc_quit(struct rsnd_mod *mod, | |||
189 | } | 192 | } |
190 | 193 | ||
191 | static int rsnd_dvc_start(struct rsnd_mod *mod, | 194 | static int rsnd_dvc_start(struct rsnd_mod *mod, |
195 | struct rsnd_dai_stream *io, | ||
192 | struct rsnd_priv *priv) | 196 | struct rsnd_priv *priv) |
193 | { | 197 | { |
194 | rsnd_mod_write(mod, CMD_CTRL, 0x10); | 198 | rsnd_mod_write(mod, CMD_CTRL, 0x10); |
@@ -197,6 +201,7 @@ static int rsnd_dvc_start(struct rsnd_mod *mod, | |||
197 | } | 201 | } |
198 | 202 | ||
199 | static int rsnd_dvc_stop(struct rsnd_mod *mod, | 203 | static int rsnd_dvc_stop(struct rsnd_mod *mod, |
204 | struct rsnd_dai_stream *io, | ||
200 | struct rsnd_priv *priv) | 205 | struct rsnd_priv *priv) |
201 | { | 206 | { |
202 | rsnd_mod_write(mod, CMD_CTRL, 0); | 207 | rsnd_mod_write(mod, CMD_CTRL, 0); |
@@ -205,15 +210,15 @@ static int rsnd_dvc_stop(struct rsnd_mod *mod, | |||
205 | } | 210 | } |
206 | 211 | ||
207 | static int rsnd_dvc_pcm_new(struct rsnd_mod *mod, | 212 | static int rsnd_dvc_pcm_new(struct rsnd_mod *mod, |
213 | struct rsnd_dai_stream *io, | ||
208 | struct snd_soc_pcm_runtime *rtd) | 214 | struct snd_soc_pcm_runtime *rtd) |
209 | { | 215 | { |
210 | struct rsnd_dai_stream *io = rsnd_mod_to_io(mod); | ||
211 | struct rsnd_dvc *dvc = rsnd_mod_to_dvc(mod); | 216 | struct rsnd_dvc *dvc = rsnd_mod_to_dvc(mod); |
212 | int is_play = rsnd_io_is_play(io); | 217 | int is_play = rsnd_io_is_play(io); |
213 | int ret; | 218 | int ret; |
214 | 219 | ||
215 | /* Volume */ | 220 | /* Volume */ |
216 | ret = rsnd_kctrl_new_m(mod, rtd, | 221 | ret = rsnd_kctrl_new_m(mod, io, rtd, |
217 | is_play ? | 222 | is_play ? |
218 | "DVC Out Playback Volume" : "DVC In Capture Volume", | 223 | "DVC Out Playback Volume" : "DVC In Capture Volume", |
219 | rsnd_dvc_volume_update, | 224 | rsnd_dvc_volume_update, |
@@ -222,7 +227,7 @@ static int rsnd_dvc_pcm_new(struct rsnd_mod *mod, | |||
222 | return ret; | 227 | return ret; |
223 | 228 | ||
224 | /* Mute */ | 229 | /* Mute */ |
225 | ret = rsnd_kctrl_new_m(mod, rtd, | 230 | ret = rsnd_kctrl_new_m(mod, io, rtd, |
226 | is_play ? | 231 | is_play ? |
227 | "DVC Out Mute Switch" : "DVC In Mute Switch", | 232 | "DVC Out Mute Switch" : "DVC In Mute Switch", |
228 | rsnd_dvc_volume_update, | 233 | rsnd_dvc_volume_update, |
@@ -231,7 +236,7 @@ static int rsnd_dvc_pcm_new(struct rsnd_mod *mod, | |||
231 | return ret; | 236 | return ret; |
232 | 237 | ||
233 | /* Ramp */ | 238 | /* Ramp */ |
234 | ret = rsnd_kctrl_new_s(mod, rtd, | 239 | ret = rsnd_kctrl_new_s(mod, io, rtd, |
235 | is_play ? | 240 | is_play ? |
236 | "DVC Out Ramp Switch" : "DVC In Ramp Switch", | 241 | "DVC Out Ramp Switch" : "DVC In Ramp Switch", |
237 | rsnd_dvc_volume_update, | 242 | rsnd_dvc_volume_update, |
@@ -239,7 +244,7 @@ static int rsnd_dvc_pcm_new(struct rsnd_mod *mod, | |||
239 | if (ret < 0) | 244 | if (ret < 0) |
240 | return ret; | 245 | return ret; |
241 | 246 | ||
242 | ret = rsnd_kctrl_new_e(mod, rtd, | 247 | ret = rsnd_kctrl_new_e(mod, io, rtd, |
243 | is_play ? | 248 | is_play ? |
244 | "DVC Out Ramp Up Rate" : "DVC In Ramp Up Rate", | 249 | "DVC Out Ramp Up Rate" : "DVC In Ramp Up Rate", |
245 | &dvc->rup, | 250 | &dvc->rup, |
@@ -248,7 +253,7 @@ static int rsnd_dvc_pcm_new(struct rsnd_mod *mod, | |||
248 | if (ret < 0) | 253 | if (ret < 0) |
249 | return ret; | 254 | return ret; |
250 | 255 | ||
251 | ret = rsnd_kctrl_new_e(mod, rtd, | 256 | ret = rsnd_kctrl_new_e(mod, io, rtd, |
252 | is_play ? | 257 | is_play ? |
253 | "DVC Out Ramp Down Rate" : "DVC In Ramp Down Rate", | 258 | "DVC Out Ramp Down Rate" : "DVC In Ramp Down Rate", |
254 | &dvc->rdown, | 259 | &dvc->rdown, |
@@ -261,7 +266,8 @@ static int rsnd_dvc_pcm_new(struct rsnd_mod *mod, | |||
261 | return 0; | 266 | return 0; |
262 | } | 267 | } |
263 | 268 | ||
264 | static struct dma_chan *rsnd_dvc_dma_req(struct rsnd_mod *mod) | 269 | static struct dma_chan *rsnd_dvc_dma_req(struct rsnd_dai_stream *io, |
270 | struct rsnd_mod *mod) | ||
265 | { | 271 | { |
266 | struct rsnd_priv *priv = rsnd_mod_to_priv(mod); | 272 | struct rsnd_priv *priv = rsnd_mod_to_priv(mod); |
267 | 273 | ||
@@ -366,7 +372,7 @@ int rsnd_dvc_probe(struct platform_device *pdev, | |||
366 | 372 | ||
367 | dvc->info = &info->dvc_info[i]; | 373 | dvc->info = &info->dvc_info[i]; |
368 | 374 | ||
369 | ret = rsnd_mod_init(&dvc->mod, &rsnd_dvc_ops, | 375 | ret = rsnd_mod_init(priv, &dvc->mod, &rsnd_dvc_ops, |
370 | clk, RSND_MOD_DVC, i); | 376 | clk, RSND_MOD_DVC, i); |
371 | if (ret) | 377 | if (ret) |
372 | return ret; | 378 | return ret; |
diff --git a/sound/soc/sh/rcar/rsnd.h b/sound/soc/sh/rcar/rsnd.h index 4e6de6804cfb..09fcc54a8ee0 100644 --- a/sound/soc/sh/rcar/rsnd.h +++ b/sound/soc/sh/rcar/rsnd.h | |||
@@ -165,18 +165,18 @@ void rsnd_write(struct rsnd_priv *priv, struct rsnd_mod *mod, | |||
165 | enum rsnd_reg reg, u32 data); | 165 | enum rsnd_reg reg, u32 data); |
166 | void rsnd_bset(struct rsnd_priv *priv, struct rsnd_mod *mod, enum rsnd_reg reg, | 166 | void rsnd_bset(struct rsnd_priv *priv, struct rsnd_mod *mod, enum rsnd_reg reg, |
167 | u32 mask, u32 data); | 167 | u32 mask, u32 data); |
168 | u32 rsnd_get_adinr(struct rsnd_mod *mod); | 168 | u32 rsnd_get_adinr(struct rsnd_mod *mod, struct rsnd_dai_stream *io); |
169 | 169 | ||
170 | /* | 170 | /* |
171 | * R-Car DMA | 171 | * R-Car DMA |
172 | */ | 172 | */ |
173 | struct rsnd_dma; | 173 | struct rsnd_dma; |
174 | struct rsnd_dma_ops { | 174 | struct rsnd_dma_ops { |
175 | void (*start)(struct rsnd_dma *dma); | 175 | void (*start)(struct rsnd_dai_stream *io, struct rsnd_dma *dma); |
176 | void (*stop)(struct rsnd_dma *dma); | 176 | void (*stop)(struct rsnd_dai_stream *io, struct rsnd_dma *dma); |
177 | int (*init)(struct rsnd_priv *priv, struct rsnd_dma *dma, int id, | 177 | int (*init)(struct rsnd_dai_stream *io, struct rsnd_dma *dma, int id, |
178 | struct rsnd_mod *mod_from, struct rsnd_mod *mod_to); | 178 | struct rsnd_mod *mod_from, struct rsnd_mod *mod_to); |
179 | void (*quit)(struct rsnd_dma *dma); | 179 | void (*quit)(struct rsnd_dai_stream *io, struct rsnd_dma *dma); |
180 | }; | 180 | }; |
181 | 181 | ||
182 | struct rsnd_dmaen { | 182 | struct rsnd_dmaen { |
@@ -200,10 +200,10 @@ struct rsnd_dma { | |||
200 | #define rsnd_dma_to_dmaen(dma) (&(dma)->dma.en) | 200 | #define rsnd_dma_to_dmaen(dma) (&(dma)->dma.en) |
201 | #define rsnd_dma_to_dmapp(dma) (&(dma)->dma.pp) | 201 | #define rsnd_dma_to_dmapp(dma) (&(dma)->dma.pp) |
202 | 202 | ||
203 | void rsnd_dma_start(struct rsnd_dma *dma); | 203 | void rsnd_dma_start(struct rsnd_dai_stream *io, struct rsnd_dma *dma); |
204 | void rsnd_dma_stop(struct rsnd_dma *dma); | 204 | void rsnd_dma_stop(struct rsnd_dai_stream *io, struct rsnd_dma *dma); |
205 | int rsnd_dma_init(struct rsnd_priv *priv, struct rsnd_dma *dma, int id); | 205 | int rsnd_dma_init(struct rsnd_dai_stream *io, struct rsnd_dma *dma, int id); |
206 | void rsnd_dma_quit(struct rsnd_dma *dma); | 206 | void rsnd_dma_quit(struct rsnd_dai_stream *io, struct rsnd_dma *dma); |
207 | int rsnd_dma_probe(struct platform_device *pdev, | 207 | int rsnd_dma_probe(struct platform_device *pdev, |
208 | const struct rsnd_of_data *of_data, | 208 | const struct rsnd_of_data *of_data, |
209 | struct rsnd_priv *priv); | 209 | struct rsnd_priv *priv); |
@@ -224,25 +224,35 @@ enum rsnd_mod_type { | |||
224 | 224 | ||
225 | struct rsnd_mod_ops { | 225 | struct rsnd_mod_ops { |
226 | char *name; | 226 | char *name; |
227 | struct dma_chan* (*dma_req)(struct rsnd_mod *mod); | 227 | struct dma_chan* (*dma_req)(struct rsnd_dai_stream *io, |
228 | struct rsnd_mod *mod); | ||
228 | int (*probe)(struct rsnd_mod *mod, | 229 | int (*probe)(struct rsnd_mod *mod, |
230 | struct rsnd_dai_stream *io, | ||
229 | struct rsnd_priv *priv); | 231 | struct rsnd_priv *priv); |
230 | int (*remove)(struct rsnd_mod *mod, | 232 | int (*remove)(struct rsnd_mod *mod, |
233 | struct rsnd_dai_stream *io, | ||
231 | struct rsnd_priv *priv); | 234 | struct rsnd_priv *priv); |
232 | int (*init)(struct rsnd_mod *mod, | 235 | int (*init)(struct rsnd_mod *mod, |
236 | struct rsnd_dai_stream *io, | ||
233 | struct rsnd_priv *priv); | 237 | struct rsnd_priv *priv); |
234 | int (*quit)(struct rsnd_mod *mod, | 238 | int (*quit)(struct rsnd_mod *mod, |
239 | struct rsnd_dai_stream *io, | ||
235 | struct rsnd_priv *priv); | 240 | struct rsnd_priv *priv); |
236 | int (*start)(struct rsnd_mod *mod, | 241 | int (*start)(struct rsnd_mod *mod, |
242 | struct rsnd_dai_stream *io, | ||
237 | struct rsnd_priv *priv); | 243 | struct rsnd_priv *priv); |
238 | int (*stop)(struct rsnd_mod *mod, | 244 | int (*stop)(struct rsnd_mod *mod, |
245 | struct rsnd_dai_stream *io, | ||
239 | struct rsnd_priv *priv); | 246 | struct rsnd_priv *priv); |
240 | int (*pcm_new)(struct rsnd_mod *mod, | 247 | int (*pcm_new)(struct rsnd_mod *mod, |
248 | struct rsnd_dai_stream *io, | ||
241 | struct snd_soc_pcm_runtime *rtd); | 249 | struct snd_soc_pcm_runtime *rtd); |
242 | int (*hw_params)(struct rsnd_mod *mod, | 250 | int (*hw_params)(struct rsnd_mod *mod, |
251 | struct rsnd_dai_stream *io, | ||
243 | struct snd_pcm_substream *substream, | 252 | struct snd_pcm_substream *substream, |
244 | struct snd_pcm_hw_params *hw_params); | 253 | struct snd_pcm_hw_params *hw_params); |
245 | int (*fallback)(struct rsnd_mod *mod, | 254 | int (*fallback)(struct rsnd_mod *mod, |
255 | struct rsnd_dai_stream *io, | ||
246 | struct rsnd_priv *priv); | 256 | struct rsnd_priv *priv); |
247 | }; | 257 | }; |
248 | 258 | ||
@@ -252,32 +262,43 @@ struct rsnd_mod { | |||
252 | enum rsnd_mod_type type; | 262 | enum rsnd_mod_type type; |
253 | struct rsnd_mod_ops *ops; | 263 | struct rsnd_mod_ops *ops; |
254 | struct rsnd_dma dma; | 264 | struct rsnd_dma dma; |
255 | struct rsnd_dai_stream *io; | 265 | struct rsnd_priv *priv; |
256 | struct clk *clk; | 266 | struct clk *clk; |
257 | u32 status; | 267 | u32 status; |
258 | }; | 268 | }; |
259 | /* | 269 | /* |
260 | * status | 270 | * status |
261 | * | 271 | * |
262 | * bit | 272 | * 0xH0000CBA |
263 | * 0 0: probe 1: remove | 273 | * |
264 | * 1 0: init 1: quit | 274 | * A 0: probe 1: remove |
265 | * 2 0: start 1: stop | 275 | * B 0: init 1: quit |
266 | * 3 0: pcm_new | 276 | * C 0: start 1: stop |
267 | * 4 0: fallback | ||
268 | * | 277 | * |
269 | * 31 bit is always called (see __rsnd_mod_call) | 278 | * H is always called (see __rsnd_mod_call) |
270 | * 31 0: hw_params | 279 | * H 0: pcm_new |
280 | * H 0: fallback | ||
281 | * H 0: hw_params | ||
271 | */ | 282 | */ |
272 | #define __rsnd_mod_shift_probe 0 | 283 | #define __rsnd_mod_shift_probe 0 |
273 | #define __rsnd_mod_shift_remove 0 | 284 | #define __rsnd_mod_shift_remove 0 |
274 | #define __rsnd_mod_shift_init 1 | 285 | #define __rsnd_mod_shift_init 4 |
275 | #define __rsnd_mod_shift_quit 1 | 286 | #define __rsnd_mod_shift_quit 4 |
276 | #define __rsnd_mod_shift_start 2 | 287 | #define __rsnd_mod_shift_start 8 |
277 | #define __rsnd_mod_shift_stop 2 | 288 | #define __rsnd_mod_shift_stop 8 |
278 | #define __rsnd_mod_shift_pcm_new 3 | 289 | #define __rsnd_mod_shift_pcm_new 28 /* always called */ |
279 | #define __rsnd_mod_shift_fallback 4 | 290 | #define __rsnd_mod_shift_fallback 28 /* always called */ |
280 | #define __rsnd_mod_shift_hw_params 31 /* always called */ | 291 | #define __rsnd_mod_shift_hw_params 28 /* always called */ |
292 | |||
293 | #define __rsnd_mod_add_probe 1 | ||
294 | #define __rsnd_mod_add_remove -1 | ||
295 | #define __rsnd_mod_add_init 1 | ||
296 | #define __rsnd_mod_add_quit -1 | ||
297 | #define __rsnd_mod_add_start 1 | ||
298 | #define __rsnd_mod_add_stop -1 | ||
299 | #define __rsnd_mod_add_pcm_new 0 | ||
300 | #define __rsnd_mod_add_fallback 0 | ||
301 | #define __rsnd_mod_add_hw_params 0 | ||
281 | 302 | ||
282 | #define __rsnd_mod_call_probe 0 | 303 | #define __rsnd_mod_call_probe 0 |
283 | #define __rsnd_mod_call_remove 1 | 304 | #define __rsnd_mod_call_remove 1 |
@@ -289,21 +310,25 @@ struct rsnd_mod { | |||
289 | #define __rsnd_mod_call_fallback 0 | 310 | #define __rsnd_mod_call_fallback 0 |
290 | #define __rsnd_mod_call_hw_params 0 | 311 | #define __rsnd_mod_call_hw_params 0 |
291 | 312 | ||
292 | #define rsnd_mod_to_priv(mod) (rsnd_io_to_priv(rsnd_mod_to_io(mod))) | 313 | #define rsnd_mod_to_priv(mod) ((mod)->priv) |
293 | #define rsnd_mod_to_dma(mod) (&(mod)->dma) | 314 | #define rsnd_mod_to_dma(mod) (&(mod)->dma) |
294 | #define rsnd_mod_to_io(mod) ((mod)->io) | ||
295 | #define rsnd_mod_id(mod) ((mod)->id) | 315 | #define rsnd_mod_id(mod) ((mod)->id) |
296 | #define rsnd_mod_hw_start(mod) clk_enable((mod)->clk) | 316 | #define rsnd_mod_hw_start(mod) clk_enable((mod)->clk) |
297 | #define rsnd_mod_hw_stop(mod) clk_disable((mod)->clk) | 317 | #define rsnd_mod_hw_stop(mod) clk_disable((mod)->clk) |
298 | 318 | ||
299 | int rsnd_mod_init(struct rsnd_mod *mod, | 319 | int rsnd_mod_init(struct rsnd_priv *priv, |
320 | struct rsnd_mod *mod, | ||
300 | struct rsnd_mod_ops *ops, | 321 | struct rsnd_mod_ops *ops, |
301 | struct clk *clk, | 322 | struct clk *clk, |
302 | enum rsnd_mod_type type, | 323 | enum rsnd_mod_type type, |
303 | int id); | 324 | int id); |
304 | void rsnd_mod_quit(struct rsnd_mod *mod); | 325 | void rsnd_mod_quit(struct rsnd_mod *mod); |
305 | char *rsnd_mod_name(struct rsnd_mod *mod); | 326 | char *rsnd_mod_name(struct rsnd_mod *mod); |
306 | struct dma_chan *rsnd_mod_dma_req(struct rsnd_mod *mod); | 327 | struct dma_chan *rsnd_mod_dma_req(struct rsnd_dai_stream *io, |
328 | struct rsnd_mod *mod); | ||
329 | void rsnd_mod_interrupt(struct rsnd_mod *mod, | ||
330 | void (*callback)(struct rsnd_mod *mod, | ||
331 | struct rsnd_dai_stream *io)); | ||
307 | 332 | ||
308 | /* | 333 | /* |
309 | * R-Car sound DAI | 334 | * R-Car sound DAI |
@@ -328,7 +353,7 @@ struct rsnd_dai_stream { | |||
328 | #define rsnd_io_is_play(io) (&rsnd_io_to_rdai(io)->playback == io) | 353 | #define rsnd_io_is_play(io) (&rsnd_io_to_rdai(io)->playback == io) |
329 | #define rsnd_io_to_runtime(io) ((io)->substream ? \ | 354 | #define rsnd_io_to_runtime(io) ((io)->substream ? \ |
330 | (io)->substream->runtime : NULL) | 355 | (io)->substream->runtime : NULL) |
331 | 356 | int rsnd_io_is_working(struct rsnd_dai_stream *io); | |
332 | 357 | ||
333 | struct rsnd_dai { | 358 | struct rsnd_dai { |
334 | char name[RSND_DAI_NAME_SIZE]; | 359 | char name[RSND_DAI_NAME_SIZE]; |
@@ -354,7 +379,8 @@ struct rsnd_dai { | |||
354 | 379 | ||
355 | struct rsnd_dai *rsnd_rdai_get(struct rsnd_priv *priv, int id); | 380 | struct rsnd_dai *rsnd_rdai_get(struct rsnd_priv *priv, int id); |
356 | 381 | ||
357 | void rsnd_dai_pointer_update(struct rsnd_dai_stream *io, int cnt); | 382 | bool rsnd_dai_pointer_update(struct rsnd_dai_stream *io, int cnt); |
383 | void rsnd_dai_period_elapsed(struct rsnd_dai_stream *io); | ||
358 | int rsnd_dai_pointer_offset(struct rsnd_dai_stream *io, int additional); | 384 | int rsnd_dai_pointer_offset(struct rsnd_dai_stream *io, int additional); |
359 | 385 | ||
360 | /* | 386 | /* |
@@ -449,8 +475,6 @@ struct rsnd_priv { | |||
449 | #define rsnd_priv_to_pdev(priv) ((priv)->pdev) | 475 | #define rsnd_priv_to_pdev(priv) ((priv)->pdev) |
450 | #define rsnd_priv_to_dev(priv) (&(rsnd_priv_to_pdev(priv)->dev)) | 476 | #define rsnd_priv_to_dev(priv) (&(rsnd_priv_to_pdev(priv)->dev)) |
451 | #define rsnd_priv_to_info(priv) ((priv)->info) | 477 | #define rsnd_priv_to_info(priv) ((priv)->info) |
452 | #define rsnd_lock(priv, flags) spin_lock_irqsave(&priv->lock, flags) | ||
453 | #define rsnd_unlock(priv, flags) spin_unlock_irqrestore(&priv->lock, flags) | ||
454 | 478 | ||
455 | /* | 479 | /* |
456 | * rsnd_kctrl | 480 | * rsnd_kctrl |
@@ -460,7 +484,8 @@ struct rsnd_kctrl_cfg { | |||
460 | unsigned int size; | 484 | unsigned int size; |
461 | u32 *val; | 485 | u32 *val; |
462 | const char * const *texts; | 486 | const char * const *texts; |
463 | void (*update)(struct rsnd_mod *mod); | 487 | void (*update)(struct rsnd_dai_stream *io, struct rsnd_mod *mod); |
488 | struct rsnd_dai_stream *io; | ||
464 | struct snd_card *card; | 489 | struct snd_card *card; |
465 | struct snd_kcontrol *kctrl; | 490 | struct snd_kcontrol *kctrl; |
466 | }; | 491 | }; |
@@ -480,22 +505,28 @@ void _rsnd_kctrl_remove(struct rsnd_kctrl_cfg *cfg); | |||
480 | #define rsnd_kctrl_remove(_cfg) _rsnd_kctrl_remove(&((_cfg).cfg)) | 505 | #define rsnd_kctrl_remove(_cfg) _rsnd_kctrl_remove(&((_cfg).cfg)) |
481 | 506 | ||
482 | int rsnd_kctrl_new_m(struct rsnd_mod *mod, | 507 | int rsnd_kctrl_new_m(struct rsnd_mod *mod, |
508 | struct rsnd_dai_stream *io, | ||
483 | struct snd_soc_pcm_runtime *rtd, | 509 | struct snd_soc_pcm_runtime *rtd, |
484 | const unsigned char *name, | 510 | const unsigned char *name, |
485 | void (*update)(struct rsnd_mod *mod), | 511 | void (*update)(struct rsnd_dai_stream *io, |
512 | struct rsnd_mod *mod), | ||
486 | struct rsnd_kctrl_cfg_m *_cfg, | 513 | struct rsnd_kctrl_cfg_m *_cfg, |
487 | u32 max); | 514 | u32 max); |
488 | int rsnd_kctrl_new_s(struct rsnd_mod *mod, | 515 | int rsnd_kctrl_new_s(struct rsnd_mod *mod, |
516 | struct rsnd_dai_stream *io, | ||
489 | struct snd_soc_pcm_runtime *rtd, | 517 | struct snd_soc_pcm_runtime *rtd, |
490 | const unsigned char *name, | 518 | const unsigned char *name, |
491 | void (*update)(struct rsnd_mod *mod), | 519 | void (*update)(struct rsnd_dai_stream *io, |
520 | struct rsnd_mod *mod), | ||
492 | struct rsnd_kctrl_cfg_s *_cfg, | 521 | struct rsnd_kctrl_cfg_s *_cfg, |
493 | u32 max); | 522 | u32 max); |
494 | int rsnd_kctrl_new_e(struct rsnd_mod *mod, | 523 | int rsnd_kctrl_new_e(struct rsnd_mod *mod, |
524 | struct rsnd_dai_stream *io, | ||
495 | struct snd_soc_pcm_runtime *rtd, | 525 | struct snd_soc_pcm_runtime *rtd, |
496 | const unsigned char *name, | 526 | const unsigned char *name, |
497 | struct rsnd_kctrl_cfg_s *_cfg, | 527 | struct rsnd_kctrl_cfg_s *_cfg, |
498 | void (*update)(struct rsnd_mod *mod), | 528 | void (*update)(struct rsnd_dai_stream *io, |
529 | struct rsnd_mod *mod), | ||
499 | const char * const *texts, | 530 | const char * const *texts, |
500 | u32 max); | 531 | u32 max); |
501 | 532 | ||
@@ -512,8 +543,10 @@ unsigned int rsnd_src_get_ssi_rate(struct rsnd_priv *priv, | |||
512 | struct rsnd_dai_stream *io, | 543 | struct rsnd_dai_stream *io, |
513 | struct snd_pcm_runtime *runtime); | 544 | struct snd_pcm_runtime *runtime); |
514 | int rsnd_src_ssiu_start(struct rsnd_mod *ssi_mod, | 545 | int rsnd_src_ssiu_start(struct rsnd_mod *ssi_mod, |
546 | struct rsnd_dai_stream *io, | ||
515 | int use_busif); | 547 | int use_busif); |
516 | int rsnd_src_ssiu_stop(struct rsnd_mod *ssi_mod); | 548 | int rsnd_src_ssiu_stop(struct rsnd_mod *ssi_mod, |
549 | struct rsnd_dai_stream *io); | ||
517 | int rsnd_src_ssi_irq_enable(struct rsnd_mod *ssi_mod); | 550 | int rsnd_src_ssi_irq_enable(struct rsnd_mod *ssi_mod); |
518 | int rsnd_src_ssi_irq_disable(struct rsnd_mod *ssi_mod); | 551 | int rsnd_src_ssi_irq_disable(struct rsnd_mod *ssi_mod); |
519 | 552 | ||
@@ -530,7 +563,7 @@ void rsnd_ssi_remove(struct platform_device *pdev, | |||
530 | struct rsnd_mod *rsnd_ssi_mod_get(struct rsnd_priv *priv, int id); | 563 | struct rsnd_mod *rsnd_ssi_mod_get(struct rsnd_priv *priv, int id); |
531 | int rsnd_ssi_is_pin_sharing(struct rsnd_mod *mod); | 564 | int rsnd_ssi_is_pin_sharing(struct rsnd_mod *mod); |
532 | int rsnd_ssi_is_dma_mode(struct rsnd_mod *mod); | 565 | int rsnd_ssi_is_dma_mode(struct rsnd_mod *mod); |
533 | int rsnd_ssi_use_busif(struct rsnd_mod *mod); | 566 | int rsnd_ssi_use_busif(struct rsnd_dai_stream *io, struct rsnd_mod *mod); |
534 | 567 | ||
535 | /* | 568 | /* |
536 | * R-Car DVC | 569 | * R-Car DVC |
diff --git a/sound/soc/sh/rcar/rsrc-card.c b/sound/soc/sh/rcar/rsrc-card.c index a68517afe615..8caca2e180c3 100644 --- a/sound/soc/sh/rcar/rsrc-card.c +++ b/sound/soc/sh/rcar/rsrc-card.c | |||
@@ -45,61 +45,50 @@ static const struct of_device_id rsrc_card_of_match[] = { | |||
45 | }; | 45 | }; |
46 | MODULE_DEVICE_TABLE(of, rsrc_card_of_match); | 46 | MODULE_DEVICE_TABLE(of, rsrc_card_of_match); |
47 | 47 | ||
48 | #define DAI_NAME_NUM 32 | ||
48 | struct rsrc_card_dai { | 49 | struct rsrc_card_dai { |
49 | const char *name; | ||
50 | unsigned int fmt; | 50 | unsigned int fmt; |
51 | unsigned int sysclk; | 51 | unsigned int sysclk; |
52 | struct clk *clk; | 52 | struct clk *clk; |
53 | char dai_name[DAI_NAME_NUM]; | ||
53 | }; | 54 | }; |
54 | 55 | ||
55 | #define RSRC_FB_NUM 2 /* FE/BE */ | ||
56 | #define IDX_CPU 0 | 56 | #define IDX_CPU 0 |
57 | #define IDX_CODEC 1 | 57 | #define IDX_CODEC 1 |
58 | struct rsrc_card_priv { | 58 | struct rsrc_card_priv { |
59 | struct snd_soc_card snd_card; | 59 | struct snd_soc_card snd_card; |
60 | struct rsrc_card_dai_props { | ||
61 | struct rsrc_card_dai cpu_dai; | ||
62 | struct rsrc_card_dai codec_dai; | ||
63 | } dai_props[RSRC_FB_NUM]; | ||
64 | struct snd_soc_codec_conf codec_conf; | 60 | struct snd_soc_codec_conf codec_conf; |
65 | struct snd_soc_dai_link dai_link[RSRC_FB_NUM]; | 61 | struct rsrc_card_dai *dai_props; |
62 | struct snd_soc_dai_link *dai_link; | ||
63 | int dai_num; | ||
66 | u32 convert_rate; | 64 | u32 convert_rate; |
67 | }; | 65 | }; |
68 | 66 | ||
69 | #define rsrc_priv_to_dev(priv) ((priv)->snd_card.dev) | 67 | #define rsrc_priv_to_dev(priv) ((priv)->snd_card.dev) |
70 | #define rsrc_priv_to_link(priv, i) ((priv)->snd_card.dai_link + i) | 68 | #define rsrc_priv_to_link(priv, i) ((priv)->snd_card.dai_link + (i)) |
71 | #define rsrc_priv_to_props(priv, i) ((priv)->dai_props + i) | 69 | #define rsrc_priv_to_props(priv, i) ((priv)->dai_props + (i)) |
72 | #define rsrc_dev_to_of_data(dev) (of_match_device(rsrc_card_of_match, (dev))->data) | 70 | #define rsrc_dev_to_of_data(dev) (of_match_device(rsrc_card_of_match, (dev))->data) |
73 | 71 | ||
74 | static int rsrc_card_startup(struct snd_pcm_substream *substream) | 72 | static int rsrc_card_startup(struct snd_pcm_substream *substream) |
75 | { | 73 | { |
76 | struct snd_soc_pcm_runtime *rtd = substream->private_data; | 74 | struct snd_soc_pcm_runtime *rtd = substream->private_data; |
77 | struct rsrc_card_priv *priv = snd_soc_card_get_drvdata(rtd->card); | 75 | struct rsrc_card_priv *priv = snd_soc_card_get_drvdata(rtd->card); |
78 | struct rsrc_card_dai_props *dai_props = | 76 | struct rsrc_card_dai *dai_props = |
79 | &priv->dai_props[rtd - rtd->card->rtd]; | 77 | rsrc_priv_to_props(priv, rtd - rtd->card->rtd); |
80 | int ret; | 78 | int ret; |
81 | 79 | ||
82 | ret = clk_prepare_enable(dai_props->cpu_dai.clk); | ||
83 | if (ret) | ||
84 | return ret; | ||
85 | |||
86 | ret = clk_prepare_enable(dai_props->codec_dai.clk); | ||
87 | if (ret) | ||
88 | clk_disable_unprepare(dai_props->cpu_dai.clk); | ||
89 | 80 | ||
90 | return ret; | 81 | return clk_prepare_enable(dai_props->clk); |
91 | } | 82 | } |
92 | 83 | ||
93 | static void rsrc_card_shutdown(struct snd_pcm_substream *substream) | 84 | static void rsrc_card_shutdown(struct snd_pcm_substream *substream) |
94 | { | 85 | { |
95 | struct snd_soc_pcm_runtime *rtd = substream->private_data; | 86 | struct snd_soc_pcm_runtime *rtd = substream->private_data; |
96 | struct rsrc_card_priv *priv = snd_soc_card_get_drvdata(rtd->card); | 87 | struct rsrc_card_priv *priv = snd_soc_card_get_drvdata(rtd->card); |
97 | struct rsrc_card_dai_props *dai_props = | 88 | struct rsrc_card_dai *dai_props = |
98 | &priv->dai_props[rtd - rtd->card->rtd]; | 89 | rsrc_priv_to_props(priv, rtd - rtd->card->rtd); |
99 | |||
100 | clk_disable_unprepare(dai_props->cpu_dai.clk); | ||
101 | 90 | ||
102 | clk_disable_unprepare(dai_props->codec_dai.clk); | 91 | clk_disable_unprepare(dai_props->clk); |
103 | } | 92 | } |
104 | 93 | ||
105 | static struct snd_soc_ops rsrc_card_ops = { | 94 | static struct snd_soc_ops rsrc_card_ops = { |
@@ -107,21 +96,31 @@ static struct snd_soc_ops rsrc_card_ops = { | |||
107 | .shutdown = rsrc_card_shutdown, | 96 | .shutdown = rsrc_card_shutdown, |
108 | }; | 97 | }; |
109 | 98 | ||
110 | static int __rsrc_card_dai_init(struct snd_soc_dai *dai, | 99 | static int rsrc_card_dai_init(struct snd_soc_pcm_runtime *rtd) |
111 | struct rsrc_card_dai *set) | ||
112 | { | 100 | { |
101 | struct rsrc_card_priv *priv = snd_soc_card_get_drvdata(rtd->card); | ||
102 | struct snd_soc_dai *dai; | ||
103 | struct snd_soc_dai_link *dai_link; | ||
104 | struct rsrc_card_dai *dai_props; | ||
105 | int num = rtd - rtd->card->rtd; | ||
113 | int ret; | 106 | int ret; |
114 | 107 | ||
115 | if (set->fmt) { | 108 | dai_link = rsrc_priv_to_link(priv, num); |
116 | ret = snd_soc_dai_set_fmt(dai, set->fmt); | 109 | dai_props = rsrc_priv_to_props(priv, num); |
110 | dai = dai_link->dynamic ? | ||
111 | rtd->cpu_dai : | ||
112 | rtd->codec_dai; | ||
113 | |||
114 | if (dai_props->fmt) { | ||
115 | ret = snd_soc_dai_set_fmt(dai, dai_props->fmt); | ||
117 | if (ret && ret != -ENOTSUPP) { | 116 | if (ret && ret != -ENOTSUPP) { |
118 | dev_err(dai->dev, "set_fmt error\n"); | 117 | dev_err(dai->dev, "set_fmt error\n"); |
119 | goto err; | 118 | goto err; |
120 | } | 119 | } |
121 | } | 120 | } |
122 | 121 | ||
123 | if (set->sysclk) { | 122 | if (dai_props->sysclk) { |
124 | ret = snd_soc_dai_set_sysclk(dai, 0, set->sysclk, 0); | 123 | ret = snd_soc_dai_set_sysclk(dai, 0, dai_props->sysclk, 0); |
125 | if (ret && ret != -ENOTSUPP) { | 124 | if (ret && ret != -ENOTSUPP) { |
126 | dev_err(dai->dev, "set_sysclk error\n"); | 125 | dev_err(dai->dev, "set_sysclk error\n"); |
127 | goto err; | 126 | goto err; |
@@ -134,27 +133,6 @@ err: | |||
134 | return ret; | 133 | return ret; |
135 | } | 134 | } |
136 | 135 | ||
137 | static int rsrc_card_dai_init(struct snd_soc_pcm_runtime *rtd) | ||
138 | { | ||
139 | struct rsrc_card_priv *priv = snd_soc_card_get_drvdata(rtd->card); | ||
140 | struct snd_soc_dai *codec = rtd->codec_dai; | ||
141 | struct snd_soc_dai *cpu = rtd->cpu_dai; | ||
142 | struct rsrc_card_dai_props *dai_props; | ||
143 | int num, ret; | ||
144 | |||
145 | num = rtd - rtd->card->rtd; | ||
146 | dai_props = &priv->dai_props[num]; | ||
147 | ret = __rsrc_card_dai_init(codec, &dai_props->codec_dai); | ||
148 | if (ret < 0) | ||
149 | return ret; | ||
150 | |||
151 | ret = __rsrc_card_dai_init(cpu, &dai_props->cpu_dai); | ||
152 | if (ret < 0) | ||
153 | return ret; | ||
154 | |||
155 | return 0; | ||
156 | } | ||
157 | |||
158 | static int rsrc_card_be_hw_params_fixup(struct snd_soc_pcm_runtime *rtd, | 136 | static int rsrc_card_be_hw_params_fixup(struct snd_soc_pcm_runtime *rtd, |
159 | struct snd_pcm_hw_params *params) | 137 | struct snd_pcm_hw_params *params) |
160 | { | 138 | { |
@@ -170,40 +148,47 @@ static int rsrc_card_be_hw_params_fixup(struct snd_soc_pcm_runtime *rtd, | |||
170 | return 0; | 148 | return 0; |
171 | } | 149 | } |
172 | 150 | ||
173 | static int | 151 | static int rsrc_card_parse_daifmt(struct device_node *node, |
174 | rsrc_card_sub_parse_of(struct rsrc_card_priv *priv, | 152 | struct device_node *np, |
175 | struct device_node *np, | 153 | struct rsrc_card_priv *priv, |
176 | struct rsrc_card_dai *dai, | 154 | int idx, bool is_fe) |
177 | struct snd_soc_dai_link *dai_link, | ||
178 | int *args_count) | ||
179 | { | 155 | { |
180 | struct device *dev = rsrc_priv_to_dev(priv); | 156 | struct rsrc_card_dai *dai_props = rsrc_priv_to_props(priv, idx); |
181 | const struct rsrc_card_of_data *of_data = rsrc_dev_to_of_data(dev); | 157 | struct device_node *bitclkmaster = NULL; |
182 | struct of_phandle_args args; | 158 | struct device_node *framemaster = NULL; |
183 | struct device_node **p_node; | 159 | struct device_node *codec = is_fe ? NULL : np; |
184 | struct clk *clk; | 160 | unsigned int daifmt; |
185 | const char **dai_name; | ||
186 | const char **name; | ||
187 | u32 val; | ||
188 | int ret; | ||
189 | 161 | ||
190 | if (args_count) { | 162 | daifmt = snd_soc_of_parse_daifmt(node, NULL, |
191 | p_node = &dai_link->cpu_of_node; | 163 | &bitclkmaster, &framemaster); |
192 | dai_name = &dai_link->cpu_dai_name; | 164 | daifmt &= ~SND_SOC_DAIFMT_MASTER_MASK; |
193 | name = &dai_link->cpu_name; | ||
194 | } else { | ||
195 | p_node = &dai_link->codec_of_node; | ||
196 | dai_name = &dai_link->codec_dai_name; | ||
197 | name = &dai_link->codec_name; | ||
198 | } | ||
199 | 165 | ||
200 | if (!np) { | 166 | if (!bitclkmaster && !framemaster) |
201 | /* use snd-soc-dummy */ | 167 | return -EINVAL; |
202 | *p_node = NULL; | 168 | |
203 | *dai_name = "snd-soc-dummy-dai"; | 169 | if (codec == bitclkmaster) |
204 | *name = "snd-soc-dummy"; | 170 | daifmt |= (codec == framemaster) ? |
205 | return 0; | 171 | SND_SOC_DAIFMT_CBM_CFM : SND_SOC_DAIFMT_CBM_CFS; |
206 | } | 172 | else |
173 | daifmt |= (codec == framemaster) ? | ||
174 | SND_SOC_DAIFMT_CBS_CFM : SND_SOC_DAIFMT_CBS_CFS; | ||
175 | |||
176 | dai_props->fmt = daifmt; | ||
177 | |||
178 | of_node_put(bitclkmaster); | ||
179 | of_node_put(framemaster); | ||
180 | |||
181 | return 0; | ||
182 | } | ||
183 | |||
184 | static int rsrc_card_parse_links(struct device_node *np, | ||
185 | struct rsrc_card_priv *priv, | ||
186 | int idx, bool is_fe) | ||
187 | { | ||
188 | struct snd_soc_dai_link *dai_link = rsrc_priv_to_link(priv, idx); | ||
189 | struct rsrc_card_dai *dai_props = rsrc_priv_to_props(priv, idx); | ||
190 | struct of_phandle_args args; | ||
191 | int ret; | ||
207 | 192 | ||
208 | /* | 193 | /* |
209 | * Get node via "sound-dai = <&phandle port>" | 194 | * Get node via "sound-dai = <&phandle port>" |
@@ -214,30 +199,82 @@ rsrc_card_sub_parse_of(struct rsrc_card_priv *priv, | |||
214 | if (ret) | 199 | if (ret) |
215 | return ret; | 200 | return ret; |
216 | 201 | ||
217 | *p_node = args.np; | 202 | if (is_fe) { |
203 | /* BE is dummy */ | ||
204 | dai_link->codec_of_node = NULL; | ||
205 | dai_link->codec_dai_name = "snd-soc-dummy-dai"; | ||
206 | dai_link->codec_name = "snd-soc-dummy"; | ||
207 | |||
208 | /* FE settings */ | ||
209 | dai_link->dynamic = 1; | ||
210 | dai_link->dpcm_merged_format = 1; | ||
211 | dai_link->cpu_of_node = args.np; | ||
212 | snd_soc_of_get_dai_name(np, &dai_link->cpu_dai_name); | ||
213 | |||
214 | /* set dai_name */ | ||
215 | snprintf(dai_props->dai_name, DAI_NAME_NUM, "fe.%s", | ||
216 | dai_link->cpu_dai_name); | ||
217 | |||
218 | /* | ||
219 | * In soc_bind_dai_link() will check cpu name after | ||
220 | * of_node matching if dai_link has cpu_dai_name. | ||
221 | * but, it will never match if name was created by | ||
222 | * fmt_single_name() remove cpu_dai_name if cpu_args | ||
223 | * was 0. See: | ||
224 | * fmt_single_name() | ||
225 | * fmt_multiple_name() | ||
226 | */ | ||
227 | if (!args.args_count) | ||
228 | dai_link->cpu_dai_name = NULL; | ||
229 | } else { | ||
230 | struct device *dev = rsrc_priv_to_dev(priv); | ||
231 | const struct rsrc_card_of_data *of_data; | ||
218 | 232 | ||
219 | /* Get dai->name */ | 233 | of_data = rsrc_dev_to_of_data(dev); |
220 | ret = snd_soc_of_get_dai_name(np, dai_name); | ||
221 | if (ret < 0) | ||
222 | return ret; | ||
223 | 234 | ||
224 | /* | 235 | /* FE is dummy */ |
225 | * FIXME | 236 | dai_link->cpu_of_node = NULL; |
226 | * | 237 | dai_link->cpu_dai_name = "snd-soc-dummy-dai"; |
227 | * rsrc assumes DPCM playback/capture | 238 | dai_link->cpu_name = "snd-soc-dummy"; |
228 | */ | ||
229 | dai_link->dpcm_playback = 1; | ||
230 | dai_link->dpcm_capture = 1; | ||
231 | 239 | ||
232 | if (args_count) { | 240 | /* BE settings */ |
233 | *args_count = args.args_count; | 241 | dai_link->no_pcm = 1; |
234 | dai_link->dynamic = 1; | 242 | dai_link->be_hw_params_fixup = rsrc_card_be_hw_params_fixup; |
235 | } else { | 243 | dai_link->codec_of_node = args.np; |
236 | dai_link->no_pcm = 1; | 244 | snd_soc_of_get_dai_name(np, &dai_link->codec_dai_name); |
237 | priv->codec_conf.of_node = (*p_node); | 245 | |
238 | priv->codec_conf.name_prefix = of_data->prefix; | 246 | /* additional name prefix */ |
247 | priv->codec_conf.of_node = dai_link->codec_of_node; | ||
248 | priv->codec_conf.name_prefix = of_data->prefix; | ||
249 | |||
250 | /* set dai_name */ | ||
251 | snprintf(dai_props->dai_name, DAI_NAME_NUM, "be.%s", | ||
252 | dai_link->codec_dai_name); | ||
239 | } | 253 | } |
240 | 254 | ||
255 | /* Simple Card assumes platform == cpu */ | ||
256 | dai_link->platform_of_node = dai_link->cpu_of_node; | ||
257 | dai_link->dpcm_playback = 1; | ||
258 | dai_link->dpcm_capture = 1; | ||
259 | dai_link->name = dai_props->dai_name; | ||
260 | dai_link->stream_name = dai_props->dai_name; | ||
261 | dai_link->ops = &rsrc_card_ops; | ||
262 | dai_link->init = rsrc_card_dai_init; | ||
263 | |||
264 | return 0; | ||
265 | } | ||
266 | |||
267 | static int rsrc_card_parse_clk(struct device_node *np, | ||
268 | struct rsrc_card_priv *priv, | ||
269 | int idx, bool is_fe) | ||
270 | { | ||
271 | struct snd_soc_dai_link *dai_link = rsrc_priv_to_link(priv, idx); | ||
272 | struct rsrc_card_dai *dai_props = rsrc_priv_to_props(priv, idx); | ||
273 | struct clk *clk; | ||
274 | struct device_node *of_np = is_fe ? dai_link->cpu_of_node : | ||
275 | dai_link->codec_of_node; | ||
276 | u32 val; | ||
277 | |||
241 | /* | 278 | /* |
242 | * Parse dai->sysclk come from "clocks = <&xxx>" | 279 | * Parse dai->sysclk come from "clocks = <&xxx>" |
243 | * (if system has common clock) | 280 | * (if system has common clock) |
@@ -246,173 +283,92 @@ rsrc_card_sub_parse_of(struct rsrc_card_priv *priv, | |||
246 | */ | 283 | */ |
247 | if (of_property_read_bool(np, "clocks")) { | 284 | if (of_property_read_bool(np, "clocks")) { |
248 | clk = of_clk_get(np, 0); | 285 | clk = of_clk_get(np, 0); |
249 | if (IS_ERR(clk)) { | 286 | if (IS_ERR(clk)) |
250 | ret = PTR_ERR(clk); | 287 | return PTR_ERR(clk); |
251 | return ret; | ||
252 | } | ||
253 | 288 | ||
254 | dai->sysclk = clk_get_rate(clk); | 289 | dai_props->sysclk = clk_get_rate(clk); |
255 | dai->clk = clk; | 290 | dai_props->clk = clk; |
256 | } else if (!of_property_read_u32(np, "system-clock-frequency", &val)) { | 291 | } else if (!of_property_read_u32(np, "system-clock-frequency", &val)) { |
257 | dai->sysclk = val; | 292 | dai_props->sysclk = val; |
258 | } else { | 293 | } else { |
259 | clk = of_clk_get(args.np, 0); | 294 | clk = of_clk_get(of_np, 0); |
260 | if (!IS_ERR(clk)) | 295 | if (!IS_ERR(clk)) |
261 | dai->sysclk = clk_get_rate(clk); | 296 | dai_props->sysclk = clk_get_rate(clk); |
262 | } | 297 | } |
263 | 298 | ||
264 | return 0; | 299 | return 0; |
265 | } | 300 | } |
266 | 301 | ||
267 | static int rsrc_card_parse_daifmt(struct device_node *node, | ||
268 | struct rsrc_card_priv *priv, | ||
269 | struct device_node *codec, | ||
270 | int idx) | ||
271 | { | ||
272 | struct device_node *bitclkmaster = NULL; | ||
273 | struct device_node *framemaster = NULL; | ||
274 | struct rsrc_card_dai_props *dai_props = rsrc_priv_to_props(priv, idx); | ||
275 | struct rsrc_card_dai *cpu_dai = &dai_props->cpu_dai; | ||
276 | struct rsrc_card_dai *codec_dai = &dai_props->codec_dai; | ||
277 | unsigned int daifmt; | ||
278 | |||
279 | daifmt = snd_soc_of_parse_daifmt(node, NULL, | ||
280 | &bitclkmaster, &framemaster); | ||
281 | daifmt &= ~SND_SOC_DAIFMT_MASTER_MASK; | ||
282 | |||
283 | if (!bitclkmaster && !framemaster) | ||
284 | return -EINVAL; | ||
285 | |||
286 | if (codec == bitclkmaster) | ||
287 | daifmt |= (codec == framemaster) ? | ||
288 | SND_SOC_DAIFMT_CBM_CFM : SND_SOC_DAIFMT_CBM_CFS; | ||
289 | else | ||
290 | daifmt |= (codec == framemaster) ? | ||
291 | SND_SOC_DAIFMT_CBS_CFM : SND_SOC_DAIFMT_CBS_CFS; | ||
292 | |||
293 | cpu_dai->fmt = daifmt; | ||
294 | codec_dai->fmt = daifmt; | ||
295 | |||
296 | of_node_put(bitclkmaster); | ||
297 | of_node_put(framemaster); | ||
298 | |||
299 | return 0; | ||
300 | } | ||
301 | |||
302 | static int rsrc_card_dai_link_of(struct device_node *node, | 302 | static int rsrc_card_dai_link_of(struct device_node *node, |
303 | struct device_node *np, | ||
303 | struct rsrc_card_priv *priv, | 304 | struct rsrc_card_priv *priv, |
304 | int idx) | 305 | int idx) |
305 | { | 306 | { |
306 | struct device *dev = rsrc_priv_to_dev(priv); | 307 | struct device *dev = rsrc_priv_to_dev(priv); |
307 | struct snd_soc_dai_link *dai_link = rsrc_priv_to_link(priv, idx); | 308 | struct rsrc_card_dai *dai_props = rsrc_priv_to_props(priv, idx); |
308 | struct rsrc_card_dai_props *dai_props = rsrc_priv_to_props(priv, idx); | 309 | bool is_fe = false; |
309 | struct device_node *cpu = NULL; | 310 | int ret; |
310 | struct device_node *codec = NULL; | ||
311 | char *name; | ||
312 | char prop[128]; | ||
313 | int ret, cpu_args; | ||
314 | |||
315 | cpu = of_get_child_by_name(node, "cpu"); | ||
316 | codec = of_get_child_by_name(node, "codec"); | ||
317 | |||
318 | if (!cpu || !codec) { | ||
319 | ret = -EINVAL; | ||
320 | dev_err(dev, "%s: Can't find %s DT node\n", __func__, prop); | ||
321 | goto dai_link_of_err; | ||
322 | } | ||
323 | 311 | ||
324 | ret = rsrc_card_parse_daifmt(node, priv, codec, idx); | 312 | if (0 == strcmp(np->name, "cpu")) |
325 | if (ret < 0) | 313 | is_fe = true; |
326 | goto dai_link_of_err; | ||
327 | 314 | ||
328 | ret = rsrc_card_sub_parse_of(priv, (idx == IDX_CPU) ? cpu : NULL, | 315 | ret = rsrc_card_parse_daifmt(node, np, priv, idx, is_fe); |
329 | &dai_props->cpu_dai, | ||
330 | dai_link, | ||
331 | &cpu_args); | ||
332 | if (ret < 0) | 316 | if (ret < 0) |
333 | goto dai_link_of_err; | 317 | return ret; |
334 | 318 | ||
335 | ret = rsrc_card_sub_parse_of(priv, (idx == IDX_CODEC) ? codec : NULL, | 319 | ret = rsrc_card_parse_links(np, priv, idx, is_fe); |
336 | &dai_props->codec_dai, | ||
337 | dai_link, | ||
338 | NULL); | ||
339 | if (ret < 0) | 320 | if (ret < 0) |
340 | goto dai_link_of_err; | 321 | return ret; |
341 | |||
342 | if (!dai_link->cpu_dai_name || !dai_link->codec_dai_name) { | ||
343 | ret = -EINVAL; | ||
344 | goto dai_link_of_err; | ||
345 | } | ||
346 | |||
347 | /* Simple Card assumes platform == cpu */ | ||
348 | dai_link->platform_of_node = dai_link->cpu_of_node; | ||
349 | |||
350 | /* DAI link name is created from CPU/CODEC dai name */ | ||
351 | name = devm_kzalloc(dev, | ||
352 | strlen(dai_link->cpu_dai_name) + | ||
353 | strlen(dai_link->codec_dai_name) + 2, | ||
354 | GFP_KERNEL); | ||
355 | if (!name) { | ||
356 | ret = -ENOMEM; | ||
357 | goto dai_link_of_err; | ||
358 | } | ||
359 | |||
360 | sprintf(name, "%s-%s", dai_link->cpu_dai_name, | ||
361 | dai_link->codec_dai_name); | ||
362 | dai_link->name = dai_link->stream_name = name; | ||
363 | dai_link->ops = &rsrc_card_ops; | ||
364 | dai_link->init = rsrc_card_dai_init; | ||
365 | |||
366 | if (idx == IDX_CODEC) | ||
367 | dai_link->be_hw_params_fixup = rsrc_card_be_hw_params_fixup; | ||
368 | |||
369 | dev_dbg(dev, "\tname : %s\n", dai_link->stream_name); | ||
370 | dev_dbg(dev, "\tcpu : %s / %04x / %d\n", | ||
371 | dai_link->cpu_dai_name, | ||
372 | dai_props->cpu_dai.fmt, | ||
373 | dai_props->cpu_dai.sysclk); | ||
374 | dev_dbg(dev, "\tcodec : %s / %04x / %d\n", | ||
375 | dai_link->codec_dai_name, | ||
376 | dai_props->codec_dai.fmt, | ||
377 | dai_props->codec_dai.sysclk); | ||
378 | 322 | ||
379 | /* | 323 | ret = rsrc_card_parse_clk(np, priv, idx, is_fe); |
380 | * In soc_bind_dai_link() will check cpu name after | 324 | if (ret < 0) |
381 | * of_node matching if dai_link has cpu_dai_name. | 325 | return ret; |
382 | * but, it will never match if name was created by | ||
383 | * fmt_single_name() remove cpu_dai_name if cpu_args | ||
384 | * was 0. See: | ||
385 | * fmt_single_name() | ||
386 | * fmt_multiple_name() | ||
387 | */ | ||
388 | if (!cpu_args) | ||
389 | dai_link->cpu_dai_name = NULL; | ||
390 | 326 | ||
391 | dai_link_of_err: | 327 | dev_dbg(dev, "\t%s / %04x / %d\n", |
392 | of_node_put(cpu); | 328 | dai_props->dai_name, |
393 | of_node_put(codec); | 329 | dai_props->fmt, |
330 | dai_props->sysclk); | ||
394 | 331 | ||
395 | return ret; | 332 | return ret; |
396 | } | 333 | } |
397 | 334 | ||
398 | static int rsrc_card_parse_of(struct device_node *node, | 335 | static int rsrc_card_parse_of(struct device_node *node, |
399 | struct rsrc_card_priv *priv) | 336 | struct rsrc_card_priv *priv, |
337 | struct device *dev) | ||
400 | { | 338 | { |
401 | struct device *dev = rsrc_priv_to_dev(priv); | ||
402 | const struct rsrc_card_of_data *of_data = rsrc_dev_to_of_data(dev); | 339 | const struct rsrc_card_of_data *of_data = rsrc_dev_to_of_data(dev); |
340 | struct rsrc_card_dai *props; | ||
341 | struct snd_soc_dai_link *links; | ||
342 | struct device_node *np; | ||
403 | int ret; | 343 | int ret; |
404 | int i; | 344 | int i, num; |
405 | 345 | ||
406 | if (!node) | 346 | if (!node) |
407 | return -EINVAL; | 347 | return -EINVAL; |
408 | 348 | ||
409 | /* Parse the card name from DT */ | 349 | num = of_get_child_count(node); |
410 | snd_soc_of_parse_card_name(&priv->snd_card, "card-name"); | 350 | props = devm_kzalloc(dev, sizeof(*props) * num, GFP_KERNEL); |
351 | links = devm_kzalloc(dev, sizeof(*links) * num, GFP_KERNEL); | ||
352 | if (!props || !links) | ||
353 | return -ENOMEM; | ||
354 | |||
355 | priv->dai_props = props; | ||
356 | priv->dai_link = links; | ||
357 | priv->dai_num = num; | ||
411 | 358 | ||
412 | /* DAPM routes */ | 359 | /* Init snd_soc_card */ |
360 | priv->snd_card.owner = THIS_MODULE; | ||
361 | priv->snd_card.dev = dev; | ||
362 | priv->snd_card.dai_link = priv->dai_link; | ||
363 | priv->snd_card.num_links = num; | ||
364 | priv->snd_card.codec_conf = &priv->codec_conf; | ||
365 | priv->snd_card.num_configs = 1; | ||
413 | priv->snd_card.of_dapm_routes = of_data->routes; | 366 | priv->snd_card.of_dapm_routes = of_data->routes; |
414 | priv->snd_card.num_of_dapm_routes = of_data->num_routes; | 367 | priv->snd_card.num_of_dapm_routes = of_data->num_routes; |
415 | 368 | ||
369 | /* Parse the card name from DT */ | ||
370 | snd_soc_of_parse_card_name(&priv->snd_card, "card-name"); | ||
371 | |||
416 | /* sampling rate convert */ | 372 | /* sampling rate convert */ |
417 | of_property_read_u32(node, "convert-rate", &priv->convert_rate); | 373 | of_property_read_u32(node, "convert-rate", &priv->convert_rate); |
418 | 374 | ||
@@ -420,11 +376,12 @@ static int rsrc_card_parse_of(struct device_node *node, | |||
420 | priv->snd_card.name ? priv->snd_card.name : "", | 376 | priv->snd_card.name ? priv->snd_card.name : "", |
421 | priv->convert_rate); | 377 | priv->convert_rate); |
422 | 378 | ||
423 | /* FE/BE */ | 379 | i = 0; |
424 | for (i = 0; i < RSRC_FB_NUM; i++) { | 380 | for_each_child_of_node(node, np) { |
425 | ret = rsrc_card_dai_link_of(node, priv, i); | 381 | ret = rsrc_card_dai_link_of(node, np, priv, i); |
426 | if (ret < 0) | 382 | if (ret < 0) |
427 | return ret; | 383 | return ret; |
384 | i++; | ||
428 | } | 385 | } |
429 | 386 | ||
430 | if (!priv->snd_card.name) | 387 | if (!priv->snd_card.name) |
@@ -451,7 +408,6 @@ static int rsrc_card_unref(struct snd_soc_card *card) | |||
451 | static int rsrc_card_probe(struct platform_device *pdev) | 408 | static int rsrc_card_probe(struct platform_device *pdev) |
452 | { | 409 | { |
453 | struct rsrc_card_priv *priv; | 410 | struct rsrc_card_priv *priv; |
454 | struct snd_soc_dai_link *dai_link; | ||
455 | struct device_node *np = pdev->dev.of_node; | 411 | struct device_node *np = pdev->dev.of_node; |
456 | struct device *dev = &pdev->dev; | 412 | struct device *dev = &pdev->dev; |
457 | int ret; | 413 | int ret; |
@@ -461,16 +417,7 @@ static int rsrc_card_probe(struct platform_device *pdev) | |||
461 | if (!priv) | 417 | if (!priv) |
462 | return -ENOMEM; | 418 | return -ENOMEM; |
463 | 419 | ||
464 | /* Init snd_soc_card */ | 420 | ret = rsrc_card_parse_of(np, priv, dev); |
465 | priv->snd_card.owner = THIS_MODULE; | ||
466 | priv->snd_card.dev = dev; | ||
467 | dai_link = priv->dai_link; | ||
468 | priv->snd_card.dai_link = dai_link; | ||
469 | priv->snd_card.num_links = RSRC_FB_NUM; | ||
470 | priv->snd_card.codec_conf = &priv->codec_conf; | ||
471 | priv->snd_card.num_configs = 1; | ||
472 | |||
473 | ret = rsrc_card_parse_of(np, priv); | ||
474 | if (ret < 0) { | 421 | if (ret < 0) { |
475 | if (ret != -EPROBE_DEFER) | 422 | if (ret != -EPROBE_DEFER) |
476 | dev_err(dev, "parse error %d\n", ret); | 423 | dev_err(dev, "parse error %d\n", ret); |
diff --git a/sound/soc/sh/rcar/src.c b/sound/soc/sh/rcar/src.c index 3beb32eb412a..c61c17180142 100644 --- a/sound/soc/sh/rcar/src.c +++ b/sound/soc/sh/rcar/src.c | |||
@@ -117,10 +117,10 @@ struct rsnd_src { | |||
117 | /* | 117 | /* |
118 | * Gen1/Gen2 common functions | 118 | * Gen1/Gen2 common functions |
119 | */ | 119 | */ |
120 | static struct dma_chan *rsnd_src_dma_req(struct rsnd_mod *mod) | 120 | static struct dma_chan *rsnd_src_dma_req(struct rsnd_dai_stream *io, |
121 | struct rsnd_mod *mod) | ||
121 | { | 122 | { |
122 | struct rsnd_priv *priv = rsnd_mod_to_priv(mod); | 123 | struct rsnd_priv *priv = rsnd_mod_to_priv(mod); |
123 | struct rsnd_dai_stream *io = rsnd_mod_to_io(mod); | ||
124 | int is_play = rsnd_io_is_play(io); | 124 | int is_play = rsnd_io_is_play(io); |
125 | 125 | ||
126 | return rsnd_dma_request_channel(rsnd_src_of_node(priv), | 126 | return rsnd_dma_request_channel(rsnd_src_of_node(priv), |
@@ -129,9 +129,9 @@ static struct dma_chan *rsnd_src_dma_req(struct rsnd_mod *mod) | |||
129 | } | 129 | } |
130 | 130 | ||
131 | int rsnd_src_ssiu_start(struct rsnd_mod *ssi_mod, | 131 | int rsnd_src_ssiu_start(struct rsnd_mod *ssi_mod, |
132 | struct rsnd_dai_stream *io, | ||
132 | int use_busif) | 133 | int use_busif) |
133 | { | 134 | { |
134 | struct rsnd_dai_stream *io = rsnd_mod_to_io(ssi_mod); | ||
135 | struct rsnd_dai *rdai = rsnd_io_to_rdai(io); | 135 | struct rsnd_dai *rdai = rsnd_io_to_rdai(io); |
136 | struct snd_pcm_runtime *runtime = rsnd_io_to_runtime(io); | 136 | struct snd_pcm_runtime *runtime = rsnd_io_to_runtime(io); |
137 | int ssi_id = rsnd_mod_id(ssi_mod); | 137 | int ssi_id = rsnd_mod_id(ssi_mod); |
@@ -174,7 +174,7 @@ int rsnd_src_ssiu_start(struct rsnd_mod *ssi_mod, | |||
174 | u32 mask = ~0; | 174 | u32 mask = ~0; |
175 | 175 | ||
176 | rsnd_mod_write(ssi_mod, SSI_BUSIF_ADINR, | 176 | rsnd_mod_write(ssi_mod, SSI_BUSIF_ADINR, |
177 | rsnd_get_adinr(ssi_mod)); | 177 | rsnd_get_adinr(ssi_mod, io)); |
178 | rsnd_mod_write(ssi_mod, SSI_BUSIF_MODE, 1); | 178 | rsnd_mod_write(ssi_mod, SSI_BUSIF_MODE, 1); |
179 | rsnd_mod_write(ssi_mod, SSI_CTRL, 0x1); | 179 | rsnd_mod_write(ssi_mod, SSI_CTRL, 0x1); |
180 | 180 | ||
@@ -196,7 +196,8 @@ int rsnd_src_ssiu_start(struct rsnd_mod *ssi_mod, | |||
196 | return 0; | 196 | return 0; |
197 | } | 197 | } |
198 | 198 | ||
199 | int rsnd_src_ssiu_stop(struct rsnd_mod *ssi_mod) | 199 | int rsnd_src_ssiu_stop(struct rsnd_mod *ssi_mod, |
200 | struct rsnd_dai_stream *io) | ||
200 | { | 201 | { |
201 | /* | 202 | /* |
202 | * DMA settings for SSIU | 203 | * DMA settings for SSIU |
@@ -235,10 +236,9 @@ int rsnd_src_ssi_irq_disable(struct rsnd_mod *ssi_mod) | |||
235 | return 0; | 236 | return 0; |
236 | } | 237 | } |
237 | 238 | ||
238 | static u32 rsnd_src_convert_rate(struct rsnd_src *src) | 239 | static u32 rsnd_src_convert_rate(struct rsnd_dai_stream *io, |
240 | struct rsnd_src *src) | ||
239 | { | 241 | { |
240 | struct rsnd_mod *mod = &src->mod; | ||
241 | struct rsnd_dai_stream *io = rsnd_mod_to_io(mod); | ||
242 | struct snd_pcm_runtime *runtime = rsnd_io_to_runtime(io); | 242 | struct snd_pcm_runtime *runtime = rsnd_io_to_runtime(io); |
243 | u32 convert_rate; | 243 | u32 convert_rate; |
244 | 244 | ||
@@ -274,7 +274,7 @@ unsigned int rsnd_src_get_ssi_rate(struct rsnd_priv *priv, | |||
274 | * return convert rate if SRC is used, | 274 | * return convert rate if SRC is used, |
275 | * otherwise, return runtime->rate as usual | 275 | * otherwise, return runtime->rate as usual |
276 | */ | 276 | */ |
277 | rate = rsnd_src_convert_rate(src); | 277 | rate = rsnd_src_convert_rate(io, src); |
278 | } | 278 | } |
279 | 279 | ||
280 | if (!rate) | 280 | if (!rate) |
@@ -283,12 +283,12 @@ unsigned int rsnd_src_get_ssi_rate(struct rsnd_priv *priv, | |||
283 | return rate; | 283 | return rate; |
284 | } | 284 | } |
285 | 285 | ||
286 | static int rsnd_src_set_convert_rate(struct rsnd_mod *mod) | 286 | static int rsnd_src_set_convert_rate(struct rsnd_mod *mod, |
287 | struct rsnd_dai_stream *io) | ||
287 | { | 288 | { |
288 | struct rsnd_dai_stream *io = rsnd_mod_to_io(mod); | ||
289 | struct snd_pcm_runtime *runtime = rsnd_io_to_runtime(io); | 289 | struct snd_pcm_runtime *runtime = rsnd_io_to_runtime(io); |
290 | struct rsnd_src *src = rsnd_mod_to_src(mod); | 290 | struct rsnd_src *src = rsnd_mod_to_src(mod); |
291 | u32 convert_rate = rsnd_src_convert_rate(src); | 291 | u32 convert_rate = rsnd_src_convert_rate(io, src); |
292 | u32 fsrate = 0; | 292 | u32 fsrate = 0; |
293 | 293 | ||
294 | if (convert_rate) | 294 | if (convert_rate) |
@@ -299,7 +299,7 @@ static int rsnd_src_set_convert_rate(struct rsnd_mod *mod) | |||
299 | rsnd_mod_write(mod, SRC_SWRSR, 1); | 299 | rsnd_mod_write(mod, SRC_SWRSR, 1); |
300 | 300 | ||
301 | /* Set channel number and output bit length */ | 301 | /* Set channel number and output bit length */ |
302 | rsnd_mod_write(mod, SRC_ADINR, rsnd_get_adinr(mod)); | 302 | rsnd_mod_write(mod, SRC_ADINR, rsnd_get_adinr(mod, io)); |
303 | 303 | ||
304 | /* Enable the initial value of IFS */ | 304 | /* Enable the initial value of IFS */ |
305 | if (fsrate) { | 305 | if (fsrate) { |
@@ -316,6 +316,7 @@ static int rsnd_src_set_convert_rate(struct rsnd_mod *mod) | |||
316 | } | 316 | } |
317 | 317 | ||
318 | static int rsnd_src_hw_params(struct rsnd_mod *mod, | 318 | static int rsnd_src_hw_params(struct rsnd_mod *mod, |
319 | struct rsnd_dai_stream *io, | ||
319 | struct snd_pcm_substream *substream, | 320 | struct snd_pcm_substream *substream, |
320 | struct snd_pcm_hw_params *fe_params) | 321 | struct snd_pcm_hw_params *fe_params) |
321 | { | 322 | { |
@@ -372,6 +373,7 @@ static int rsnd_src_init(struct rsnd_mod *mod, | |||
372 | } | 373 | } |
373 | 374 | ||
374 | static int rsnd_src_quit(struct rsnd_mod *mod, | 375 | static int rsnd_src_quit(struct rsnd_mod *mod, |
376 | struct rsnd_dai_stream *io, | ||
375 | struct rsnd_priv *priv) | 377 | struct rsnd_priv *priv) |
376 | { | 378 | { |
377 | struct rsnd_src *src = rsnd_mod_to_src(mod); | 379 | struct rsnd_src *src = rsnd_mod_to_src(mod); |
@@ -411,9 +413,9 @@ static int rsnd_src_stop(struct rsnd_mod *mod) | |||
411 | /* | 413 | /* |
412 | * Gen1 functions | 414 | * Gen1 functions |
413 | */ | 415 | */ |
414 | static int rsnd_src_set_route_gen1(struct rsnd_mod *mod) | 416 | static int rsnd_src_set_route_gen1(struct rsnd_dai_stream *io, |
417 | struct rsnd_mod *mod) | ||
415 | { | 418 | { |
416 | struct rsnd_dai_stream *io = rsnd_mod_to_io(mod); | ||
417 | struct src_route_config { | 419 | struct src_route_config { |
418 | u32 mask; | 420 | u32 mask; |
419 | int shift; | 421 | int shift; |
@@ -448,13 +450,13 @@ static int rsnd_src_set_route_gen1(struct rsnd_mod *mod) | |||
448 | return 0; | 450 | return 0; |
449 | } | 451 | } |
450 | 452 | ||
451 | static int rsnd_src_set_convert_timing_gen1(struct rsnd_mod *mod) | 453 | static int rsnd_src_set_convert_timing_gen1(struct rsnd_dai_stream *io, |
454 | struct rsnd_mod *mod) | ||
452 | { | 455 | { |
453 | struct rsnd_dai_stream *io = rsnd_mod_to_io(mod); | ||
454 | struct rsnd_priv *priv = rsnd_mod_to_priv(mod); | 456 | struct rsnd_priv *priv = rsnd_mod_to_priv(mod); |
455 | struct rsnd_src *src = rsnd_mod_to_src(mod); | 457 | struct rsnd_src *src = rsnd_mod_to_src(mod); |
456 | struct snd_pcm_runtime *runtime = rsnd_io_to_runtime(io); | 458 | struct snd_pcm_runtime *runtime = rsnd_io_to_runtime(io); |
457 | u32 convert_rate = rsnd_src_convert_rate(src); | 459 | u32 convert_rate = rsnd_src_convert_rate(io, src); |
458 | u32 mask; | 460 | u32 mask; |
459 | u32 val; | 461 | u32 val; |
460 | int shift; | 462 | int shift; |
@@ -506,12 +508,13 @@ static int rsnd_src_set_convert_timing_gen1(struct rsnd_mod *mod) | |||
506 | return 0; | 508 | return 0; |
507 | } | 509 | } |
508 | 510 | ||
509 | static int rsnd_src_set_convert_rate_gen1(struct rsnd_mod *mod) | 511 | static int rsnd_src_set_convert_rate_gen1(struct rsnd_mod *mod, |
512 | struct rsnd_dai_stream *io) | ||
510 | { | 513 | { |
511 | struct rsnd_src *src = rsnd_mod_to_src(mod); | 514 | struct rsnd_src *src = rsnd_mod_to_src(mod); |
512 | int ret; | 515 | int ret; |
513 | 516 | ||
514 | ret = rsnd_src_set_convert_rate(mod); | 517 | ret = rsnd_src_set_convert_rate(mod, io); |
515 | if (ret < 0) | 518 | if (ret < 0) |
516 | return ret; | 519 | return ret; |
517 | 520 | ||
@@ -523,7 +526,7 @@ static int rsnd_src_set_convert_rate_gen1(struct rsnd_mod *mod) | |||
523 | rsnd_mod_read(mod, SRC_IFSVR) / 100 * 98); | 526 | rsnd_mod_read(mod, SRC_IFSVR) / 100 * 98); |
524 | 527 | ||
525 | /* Gen1/Gen2 are not compatible */ | 528 | /* Gen1/Gen2 are not compatible */ |
526 | if (rsnd_src_convert_rate(src)) | 529 | if (rsnd_src_convert_rate(io, src)) |
527 | rsnd_mod_write(mod, SRC_ROUTE_MODE0, 1); | 530 | rsnd_mod_write(mod, SRC_ROUTE_MODE0, 1); |
528 | 531 | ||
529 | /* no SRC_BFSSR settings, since SRC_SRCCR::BUFMD is 0 */ | 532 | /* no SRC_BFSSR settings, since SRC_SRCCR::BUFMD is 0 */ |
@@ -532,6 +535,7 @@ static int rsnd_src_set_convert_rate_gen1(struct rsnd_mod *mod) | |||
532 | } | 535 | } |
533 | 536 | ||
534 | static int rsnd_src_init_gen1(struct rsnd_mod *mod, | 537 | static int rsnd_src_init_gen1(struct rsnd_mod *mod, |
538 | struct rsnd_dai_stream *io, | ||
535 | struct rsnd_priv *priv) | 539 | struct rsnd_priv *priv) |
536 | { | 540 | { |
537 | int ret; | 541 | int ret; |
@@ -540,15 +544,15 @@ static int rsnd_src_init_gen1(struct rsnd_mod *mod, | |||
540 | if (ret < 0) | 544 | if (ret < 0) |
541 | return ret; | 545 | return ret; |
542 | 546 | ||
543 | ret = rsnd_src_set_route_gen1(mod); | 547 | ret = rsnd_src_set_route_gen1(io, mod); |
544 | if (ret < 0) | 548 | if (ret < 0) |
545 | return ret; | 549 | return ret; |
546 | 550 | ||
547 | ret = rsnd_src_set_convert_rate_gen1(mod); | 551 | ret = rsnd_src_set_convert_rate_gen1(mod, io); |
548 | if (ret < 0) | 552 | if (ret < 0) |
549 | return ret; | 553 | return ret; |
550 | 554 | ||
551 | ret = rsnd_src_set_convert_timing_gen1(mod); | 555 | ret = rsnd_src_set_convert_timing_gen1(io, mod); |
552 | if (ret < 0) | 556 | if (ret < 0) |
553 | return ret; | 557 | return ret; |
554 | 558 | ||
@@ -556,6 +560,7 @@ static int rsnd_src_init_gen1(struct rsnd_mod *mod, | |||
556 | } | 560 | } |
557 | 561 | ||
558 | static int rsnd_src_start_gen1(struct rsnd_mod *mod, | 562 | static int rsnd_src_start_gen1(struct rsnd_mod *mod, |
563 | struct rsnd_dai_stream *io, | ||
559 | struct rsnd_priv *priv) | 564 | struct rsnd_priv *priv) |
560 | { | 565 | { |
561 | int id = rsnd_mod_id(mod); | 566 | int id = rsnd_mod_id(mod); |
@@ -566,6 +571,7 @@ static int rsnd_src_start_gen1(struct rsnd_mod *mod, | |||
566 | } | 571 | } |
567 | 572 | ||
568 | static int rsnd_src_stop_gen1(struct rsnd_mod *mod, | 573 | static int rsnd_src_stop_gen1(struct rsnd_mod *mod, |
574 | struct rsnd_dai_stream *io, | ||
569 | struct rsnd_priv *priv) | 575 | struct rsnd_priv *priv) |
570 | { | 576 | { |
571 | int id = rsnd_mod_id(mod); | 577 | int id = rsnd_mod_id(mod); |
@@ -643,9 +649,9 @@ static bool rsnd_src_error_record_gen2(struct rsnd_mod *mod) | |||
643 | return ret; | 649 | return ret; |
644 | } | 650 | } |
645 | 651 | ||
646 | static int _rsnd_src_start_gen2(struct rsnd_mod *mod) | 652 | static int _rsnd_src_start_gen2(struct rsnd_mod *mod, |
653 | struct rsnd_dai_stream *io) | ||
647 | { | 654 | { |
648 | struct rsnd_dai_stream *io = rsnd_mod_to_io(mod); | ||
649 | u32 val = rsnd_io_to_mod_dvc(io) ? 0x01 : 0x11; | 655 | u32 val = rsnd_io_to_mod_dvc(io) ? 0x01 : 0x11; |
650 | 656 | ||
651 | rsnd_mod_write(mod, SRC_CTRL, val); | 657 | rsnd_mod_write(mod, SRC_CTRL, val); |
@@ -670,13 +676,16 @@ static int _rsnd_src_stop_gen2(struct rsnd_mod *mod) | |||
670 | return rsnd_src_stop(mod); | 676 | return rsnd_src_stop(mod); |
671 | } | 677 | } |
672 | 678 | ||
673 | static irqreturn_t rsnd_src_interrupt_gen2(int irq, void *data) | 679 | static void __rsnd_src_interrupt_gen2(struct rsnd_mod *mod, |
680 | struct rsnd_dai_stream *io) | ||
674 | { | 681 | { |
675 | struct rsnd_mod *mod = data; | 682 | struct rsnd_priv *priv = rsnd_mod_to_priv(mod); |
676 | struct rsnd_dai_stream *io = rsnd_mod_to_io(mod); | ||
677 | 683 | ||
678 | if (!io) | 684 | spin_lock(&priv->lock); |
679 | return IRQ_NONE; | 685 | |
686 | /* ignore all cases if not working */ | ||
687 | if (!rsnd_io_is_working(io)) | ||
688 | goto rsnd_src_interrupt_gen2_out; | ||
680 | 689 | ||
681 | if (rsnd_src_error_record_gen2(mod)) { | 690 | if (rsnd_src_error_record_gen2(mod)) { |
682 | struct rsnd_priv *priv = rsnd_mod_to_priv(mod); | 691 | struct rsnd_priv *priv = rsnd_mod_to_priv(mod); |
@@ -688,22 +697,32 @@ static irqreturn_t rsnd_src_interrupt_gen2(int irq, void *data) | |||
688 | 697 | ||
689 | _rsnd_src_stop_gen2(mod); | 698 | _rsnd_src_stop_gen2(mod); |
690 | if (src->err < 1024) | 699 | if (src->err < 1024) |
691 | _rsnd_src_start_gen2(mod); | 700 | _rsnd_src_start_gen2(mod, io); |
692 | else | 701 | else |
693 | dev_warn(dev, "no more SRC restart\n"); | 702 | dev_warn(dev, "no more SRC restart\n"); |
694 | } | 703 | } |
695 | 704 | ||
705 | rsnd_src_interrupt_gen2_out: | ||
706 | spin_unlock(&priv->lock); | ||
707 | } | ||
708 | |||
709 | static irqreturn_t rsnd_src_interrupt_gen2(int irq, void *data) | ||
710 | { | ||
711 | struct rsnd_mod *mod = data; | ||
712 | |||
713 | rsnd_mod_interrupt(mod, __rsnd_src_interrupt_gen2); | ||
714 | |||
696 | return IRQ_HANDLED; | 715 | return IRQ_HANDLED; |
697 | } | 716 | } |
698 | 717 | ||
699 | static int rsnd_src_set_convert_rate_gen2(struct rsnd_mod *mod) | 718 | static int rsnd_src_set_convert_rate_gen2(struct rsnd_mod *mod, |
719 | struct rsnd_dai_stream *io) | ||
700 | { | 720 | { |
701 | struct rsnd_priv *priv = rsnd_mod_to_priv(mod); | 721 | struct rsnd_priv *priv = rsnd_mod_to_priv(mod); |
702 | struct device *dev = rsnd_priv_to_dev(priv); | 722 | struct device *dev = rsnd_priv_to_dev(priv); |
703 | struct rsnd_dai_stream *io = rsnd_mod_to_io(mod); | ||
704 | struct snd_pcm_runtime *runtime = rsnd_io_to_runtime(io); | 723 | struct snd_pcm_runtime *runtime = rsnd_io_to_runtime(io); |
705 | struct rsnd_src *src = rsnd_mod_to_src(mod); | 724 | struct rsnd_src *src = rsnd_mod_to_src(mod); |
706 | u32 convert_rate = rsnd_src_convert_rate(src); | 725 | u32 convert_rate = rsnd_src_convert_rate(io, src); |
707 | u32 cr, route; | 726 | u32 cr, route; |
708 | uint ratio; | 727 | uint ratio; |
709 | int ret; | 728 | int ret; |
@@ -721,7 +740,7 @@ static int rsnd_src_set_convert_rate_gen2(struct rsnd_mod *mod) | |||
721 | return -EINVAL; | 740 | return -EINVAL; |
722 | } | 741 | } |
723 | 742 | ||
724 | ret = rsnd_src_set_convert_rate(mod); | 743 | ret = rsnd_src_set_convert_rate(mod, io); |
725 | if (ret < 0) | 744 | if (ret < 0) |
726 | return ret; | 745 | return ret; |
727 | 746 | ||
@@ -757,12 +776,12 @@ static int rsnd_src_set_convert_rate_gen2(struct rsnd_mod *mod) | |||
757 | return 0; | 776 | return 0; |
758 | } | 777 | } |
759 | 778 | ||
760 | static int rsnd_src_set_convert_timing_gen2(struct rsnd_mod *mod) | 779 | static int rsnd_src_set_convert_timing_gen2(struct rsnd_dai_stream *io, |
780 | struct rsnd_mod *mod) | ||
761 | { | 781 | { |
762 | struct rsnd_dai_stream *io = rsnd_mod_to_io(mod); | ||
763 | struct snd_pcm_runtime *runtime = rsnd_io_to_runtime(io); | 782 | struct snd_pcm_runtime *runtime = rsnd_io_to_runtime(io); |
764 | struct rsnd_src *src = rsnd_mod_to_src(mod); | 783 | struct rsnd_src *src = rsnd_mod_to_src(mod); |
765 | u32 convert_rate = rsnd_src_convert_rate(src); | 784 | u32 convert_rate = rsnd_src_convert_rate(io, src); |
766 | int ret; | 785 | int ret; |
767 | 786 | ||
768 | if (convert_rate) | 787 | if (convert_rate) |
@@ -776,6 +795,7 @@ static int rsnd_src_set_convert_timing_gen2(struct rsnd_mod *mod) | |||
776 | } | 795 | } |
777 | 796 | ||
778 | static int rsnd_src_probe_gen2(struct rsnd_mod *mod, | 797 | static int rsnd_src_probe_gen2(struct rsnd_mod *mod, |
798 | struct rsnd_dai_stream *io, | ||
779 | struct rsnd_priv *priv) | 799 | struct rsnd_priv *priv) |
780 | { | 800 | { |
781 | struct rsnd_src *src = rsnd_mod_to_src(mod); | 801 | struct rsnd_src *src = rsnd_mod_to_src(mod); |
@@ -797,7 +817,7 @@ static int rsnd_src_probe_gen2(struct rsnd_mod *mod, | |||
797 | return ret; | 817 | return ret; |
798 | } | 818 | } |
799 | 819 | ||
800 | ret = rsnd_dma_init(priv, | 820 | ret = rsnd_dma_init(io, |
801 | rsnd_mod_to_dma(mod), | 821 | rsnd_mod_to_dma(mod), |
802 | src->info->dma_id); | 822 | src->info->dma_id); |
803 | 823 | ||
@@ -805,14 +825,16 @@ static int rsnd_src_probe_gen2(struct rsnd_mod *mod, | |||
805 | } | 825 | } |
806 | 826 | ||
807 | static int rsnd_src_remove_gen2(struct rsnd_mod *mod, | 827 | static int rsnd_src_remove_gen2(struct rsnd_mod *mod, |
828 | struct rsnd_dai_stream *io, | ||
808 | struct rsnd_priv *priv) | 829 | struct rsnd_priv *priv) |
809 | { | 830 | { |
810 | rsnd_dma_quit(rsnd_mod_to_dma(mod)); | 831 | rsnd_dma_quit(io, rsnd_mod_to_dma(mod)); |
811 | 832 | ||
812 | return 0; | 833 | return 0; |
813 | } | 834 | } |
814 | 835 | ||
815 | static int rsnd_src_init_gen2(struct rsnd_mod *mod, | 836 | static int rsnd_src_init_gen2(struct rsnd_mod *mod, |
837 | struct rsnd_dai_stream *io, | ||
816 | struct rsnd_priv *priv) | 838 | struct rsnd_priv *priv) |
817 | { | 839 | { |
818 | int ret; | 840 | int ret; |
@@ -821,11 +843,11 @@ static int rsnd_src_init_gen2(struct rsnd_mod *mod, | |||
821 | if (ret < 0) | 843 | if (ret < 0) |
822 | return ret; | 844 | return ret; |
823 | 845 | ||
824 | ret = rsnd_src_set_convert_rate_gen2(mod); | 846 | ret = rsnd_src_set_convert_rate_gen2(mod, io); |
825 | if (ret < 0) | 847 | if (ret < 0) |
826 | return ret; | 848 | return ret; |
827 | 849 | ||
828 | ret = rsnd_src_set_convert_timing_gen2(mod); | 850 | ret = rsnd_src_set_convert_timing_gen2(io, mod); |
829 | if (ret < 0) | 851 | if (ret < 0) |
830 | return ret; | 852 | return ret; |
831 | 853 | ||
@@ -833,31 +855,33 @@ static int rsnd_src_init_gen2(struct rsnd_mod *mod, | |||
833 | } | 855 | } |
834 | 856 | ||
835 | static int rsnd_src_start_gen2(struct rsnd_mod *mod, | 857 | static int rsnd_src_start_gen2(struct rsnd_mod *mod, |
858 | struct rsnd_dai_stream *io, | ||
836 | struct rsnd_priv *priv) | 859 | struct rsnd_priv *priv) |
837 | { | 860 | { |
838 | rsnd_dma_start(rsnd_mod_to_dma(mod)); | 861 | rsnd_dma_start(io, rsnd_mod_to_dma(mod)); |
839 | 862 | ||
840 | return _rsnd_src_start_gen2(mod); | 863 | return _rsnd_src_start_gen2(mod, io); |
841 | } | 864 | } |
842 | 865 | ||
843 | static int rsnd_src_stop_gen2(struct rsnd_mod *mod, | 866 | static int rsnd_src_stop_gen2(struct rsnd_mod *mod, |
867 | struct rsnd_dai_stream *io, | ||
844 | struct rsnd_priv *priv) | 868 | struct rsnd_priv *priv) |
845 | { | 869 | { |
846 | int ret; | 870 | int ret; |
847 | 871 | ||
848 | ret = _rsnd_src_stop_gen2(mod); | 872 | ret = _rsnd_src_stop_gen2(mod); |
849 | 873 | ||
850 | rsnd_dma_stop(rsnd_mod_to_dma(mod)); | 874 | rsnd_dma_stop(io, rsnd_mod_to_dma(mod)); |
851 | 875 | ||
852 | return ret; | 876 | return ret; |
853 | } | 877 | } |
854 | 878 | ||
855 | static void rsnd_src_reconvert_update(struct rsnd_mod *mod) | 879 | static void rsnd_src_reconvert_update(struct rsnd_dai_stream *io, |
880 | struct rsnd_mod *mod) | ||
856 | { | 881 | { |
857 | struct rsnd_dai_stream *io = rsnd_mod_to_io(mod); | ||
858 | struct snd_pcm_runtime *runtime = rsnd_io_to_runtime(io); | 882 | struct snd_pcm_runtime *runtime = rsnd_io_to_runtime(io); |
859 | struct rsnd_src *src = rsnd_mod_to_src(mod); | 883 | struct rsnd_src *src = rsnd_mod_to_src(mod); |
860 | u32 convert_rate = rsnd_src_convert_rate(src); | 884 | u32 convert_rate = rsnd_src_convert_rate(io, src); |
861 | u32 fsrate; | 885 | u32 fsrate; |
862 | 886 | ||
863 | if (!runtime) | 887 | if (!runtime) |
@@ -873,10 +897,10 @@ static void rsnd_src_reconvert_update(struct rsnd_mod *mod) | |||
873 | } | 897 | } |
874 | 898 | ||
875 | static int rsnd_src_pcm_new(struct rsnd_mod *mod, | 899 | static int rsnd_src_pcm_new(struct rsnd_mod *mod, |
900 | struct rsnd_dai_stream *io, | ||
876 | struct snd_soc_pcm_runtime *rtd) | 901 | struct snd_soc_pcm_runtime *rtd) |
877 | { | 902 | { |
878 | struct rsnd_priv *priv = rsnd_mod_to_priv(mod); | 903 | struct rsnd_priv *priv = rsnd_mod_to_priv(mod); |
879 | struct rsnd_dai_stream *io = rsnd_mod_to_io(mod); | ||
880 | struct rsnd_dai *rdai = rsnd_io_to_rdai(io); | 904 | struct rsnd_dai *rdai = rsnd_io_to_rdai(io); |
881 | struct rsnd_src *src = rsnd_mod_to_src(mod); | 905 | struct rsnd_src *src = rsnd_mod_to_src(mod); |
882 | int ret; | 906 | int ret; |
@@ -907,7 +931,7 @@ static int rsnd_src_pcm_new(struct rsnd_mod *mod, | |||
907 | /* | 931 | /* |
908 | * enable sync convert | 932 | * enable sync convert |
909 | */ | 933 | */ |
910 | ret = rsnd_kctrl_new_s(mod, rtd, | 934 | ret = rsnd_kctrl_new_s(mod, io, rtd, |
911 | rsnd_io_is_play(io) ? | 935 | rsnd_io_is_play(io) ? |
912 | "SRC Out Rate Switch" : | 936 | "SRC Out Rate Switch" : |
913 | "SRC In Rate Switch", | 937 | "SRC In Rate Switch", |
@@ -916,7 +940,7 @@ static int rsnd_src_pcm_new(struct rsnd_mod *mod, | |||
916 | if (ret < 0) | 940 | if (ret < 0) |
917 | return ret; | 941 | return ret; |
918 | 942 | ||
919 | ret = rsnd_kctrl_new_s(mod, rtd, | 943 | ret = rsnd_kctrl_new_s(mod, io, rtd, |
920 | rsnd_io_is_play(io) ? | 944 | rsnd_io_is_play(io) ? |
921 | "SRC Out Rate" : | 945 | "SRC Out Rate" : |
922 | "SRC In Rate", | 946 | "SRC In Rate", |
@@ -1041,7 +1065,7 @@ int rsnd_src_probe(struct platform_device *pdev, | |||
1041 | 1065 | ||
1042 | src->info = &info->src_info[i]; | 1066 | src->info = &info->src_info[i]; |
1043 | 1067 | ||
1044 | ret = rsnd_mod_init(&src->mod, ops, clk, RSND_MOD_SRC, i); | 1068 | ret = rsnd_mod_init(priv, &src->mod, ops, clk, RSND_MOD_SRC, i); |
1045 | if (ret) | 1069 | if (ret) |
1046 | return ret; | 1070 | return ret; |
1047 | } | 1071 | } |
diff --git a/sound/soc/sh/rcar/ssi.c b/sound/soc/sh/rcar/ssi.c index 7bb9c087f3dc..2fbe59f7f9b5 100644 --- a/sound/soc/sh/rcar/ssi.c +++ b/sound/soc/sh/rcar/ssi.c | |||
@@ -66,6 +66,7 @@ struct rsnd_ssi { | |||
66 | 66 | ||
67 | u32 cr_own; | 67 | u32 cr_own; |
68 | u32 cr_clk; | 68 | u32 cr_clk; |
69 | int chan; | ||
69 | int err; | 70 | int err; |
70 | unsigned int usrcnt; | 71 | unsigned int usrcnt; |
71 | }; | 72 | }; |
@@ -80,16 +81,15 @@ struct rsnd_ssi { | |||
80 | #define rsnd_mod_to_ssi(_mod) container_of((_mod), struct rsnd_ssi, mod) | 81 | #define rsnd_mod_to_ssi(_mod) container_of((_mod), struct rsnd_ssi, mod) |
81 | #define rsnd_dma_to_ssi(dma) rsnd_mod_to_ssi(rsnd_dma_to_mod(dma)) | 82 | #define rsnd_dma_to_ssi(dma) rsnd_mod_to_ssi(rsnd_dma_to_mod(dma)) |
82 | #define rsnd_ssi_pio_available(ssi) ((ssi)->info->irq > 0) | 83 | #define rsnd_ssi_pio_available(ssi) ((ssi)->info->irq > 0) |
83 | #define rsnd_ssi_clk_from_parent(ssi) ((ssi)->parent) | 84 | #define rsnd_ssi_parent(ssi) ((ssi)->parent) |
84 | #define rsnd_ssi_mode_flags(p) ((p)->info->flags) | 85 | #define rsnd_ssi_mode_flags(p) ((p)->info->flags) |
85 | #define rsnd_ssi_dai_id(ssi) ((ssi)->info->dai_id) | 86 | #define rsnd_ssi_dai_id(ssi) ((ssi)->info->dai_id) |
86 | #define rsnd_ssi_of_node(priv) \ | 87 | #define rsnd_ssi_of_node(priv) \ |
87 | of_get_child_by_name(rsnd_priv_to_dev(priv)->of_node, "rcar_sound,ssi") | 88 | of_get_child_by_name(rsnd_priv_to_dev(priv)->of_node, "rcar_sound,ssi") |
88 | 89 | ||
89 | int rsnd_ssi_use_busif(struct rsnd_mod *mod) | 90 | int rsnd_ssi_use_busif(struct rsnd_dai_stream *io, struct rsnd_mod *mod) |
90 | { | 91 | { |
91 | struct rsnd_ssi *ssi = rsnd_mod_to_ssi(mod); | 92 | struct rsnd_ssi *ssi = rsnd_mod_to_ssi(mod); |
92 | struct rsnd_dai_stream *io = rsnd_mod_to_io(mod); | ||
93 | int use_busif = 0; | 93 | int use_busif = 0; |
94 | 94 | ||
95 | if (!rsnd_ssi_is_dma_mode(mod)) | 95 | if (!rsnd_ssi_is_dma_mode(mod)) |
@@ -189,22 +189,26 @@ static void rsnd_ssi_hw_start(struct rsnd_ssi *ssi, | |||
189 | rsnd_mod_hw_start(&ssi->mod); | 189 | rsnd_mod_hw_start(&ssi->mod); |
190 | 190 | ||
191 | if (rsnd_rdai_is_clk_master(rdai)) { | 191 | if (rsnd_rdai_is_clk_master(rdai)) { |
192 | if (rsnd_ssi_clk_from_parent(ssi)) | 192 | struct rsnd_ssi *ssi_parent = rsnd_ssi_parent(ssi); |
193 | rsnd_ssi_hw_start(ssi->parent, io); | 193 | |
194 | if (ssi_parent) | ||
195 | rsnd_ssi_hw_start(ssi_parent, io); | ||
194 | else | 196 | else |
195 | rsnd_ssi_master_clk_start(ssi, io); | 197 | rsnd_ssi_master_clk_start(ssi, io); |
196 | } | 198 | } |
197 | } | 199 | } |
198 | 200 | ||
199 | cr_mode = rsnd_ssi_is_dma_mode(&ssi->mod) ? | 201 | if (rsnd_ssi_is_dma_mode(&ssi->mod)) { |
200 | DMEN : /* DMA : enable DMA */ | 202 | cr_mode = UIEN | OIEN | /* over/under run */ |
201 | DIEN; /* PIO : enable Data interrupt */ | 203 | DMEN; /* DMA : enable DMA */ |
202 | 204 | } else { | |
205 | cr_mode = DIEN; /* PIO : enable Data interrupt */ | ||
206 | } | ||
203 | 207 | ||
204 | cr = ssi->cr_own | | 208 | cr = ssi->cr_own | |
205 | ssi->cr_clk | | 209 | ssi->cr_clk | |
206 | cr_mode | | 210 | cr_mode | |
207 | UIEN | OIEN | EN; | 211 | EN; |
208 | 212 | ||
209 | rsnd_mod_write(&ssi->mod, SSICR, cr); | 213 | rsnd_mod_write(&ssi->mod, SSICR, cr); |
210 | 214 | ||
@@ -221,16 +225,17 @@ static void rsnd_ssi_hw_start(struct rsnd_ssi *ssi, | |||
221 | rsnd_mod_name(&ssi->mod), rsnd_mod_id(&ssi->mod)); | 225 | rsnd_mod_name(&ssi->mod), rsnd_mod_id(&ssi->mod)); |
222 | } | 226 | } |
223 | 227 | ||
224 | static void rsnd_ssi_hw_stop(struct rsnd_ssi *ssi) | 228 | static void rsnd_ssi_hw_stop(struct rsnd_dai_stream *io, struct rsnd_ssi *ssi) |
225 | { | 229 | { |
226 | struct rsnd_priv *priv = rsnd_mod_to_priv(&ssi->mod); | 230 | struct rsnd_priv *priv = rsnd_mod_to_priv(&ssi->mod); |
227 | struct rsnd_dai_stream *io = rsnd_mod_to_io(&ssi->mod); | ||
228 | struct rsnd_dai *rdai = rsnd_io_to_rdai(io); | 231 | struct rsnd_dai *rdai = rsnd_io_to_rdai(io); |
229 | struct device *dev = rsnd_priv_to_dev(priv); | 232 | struct device *dev = rsnd_priv_to_dev(priv); |
230 | u32 cr; | 233 | u32 cr; |
231 | 234 | ||
232 | if (0 == ssi->usrcnt) /* stop might be called without start */ | 235 | if (0 == ssi->usrcnt) { |
236 | dev_err(dev, "%s called without starting\n", __func__); | ||
233 | return; | 237 | return; |
238 | } | ||
234 | 239 | ||
235 | ssi->usrcnt--; | 240 | ssi->usrcnt--; |
236 | 241 | ||
@@ -253,13 +258,17 @@ static void rsnd_ssi_hw_stop(struct rsnd_ssi *ssi) | |||
253 | rsnd_ssi_status_check(&ssi->mod, IIRQ); | 258 | rsnd_ssi_status_check(&ssi->mod, IIRQ); |
254 | 259 | ||
255 | if (rsnd_rdai_is_clk_master(rdai)) { | 260 | if (rsnd_rdai_is_clk_master(rdai)) { |
256 | if (rsnd_ssi_clk_from_parent(ssi)) | 261 | struct rsnd_ssi *ssi_parent = rsnd_ssi_parent(ssi); |
257 | rsnd_ssi_hw_stop(ssi->parent); | 262 | |
263 | if (ssi_parent) | ||
264 | rsnd_ssi_hw_stop(io, ssi_parent); | ||
258 | else | 265 | else |
259 | rsnd_ssi_master_clk_stop(ssi); | 266 | rsnd_ssi_master_clk_stop(ssi); |
260 | } | 267 | } |
261 | 268 | ||
262 | rsnd_mod_hw_stop(&ssi->mod); | 269 | rsnd_mod_hw_stop(&ssi->mod); |
270 | |||
271 | ssi->chan = 0; | ||
263 | } | 272 | } |
264 | 273 | ||
265 | dev_dbg(dev, "%s[%d] hw stopped\n", | 274 | dev_dbg(dev, "%s[%d] hw stopped\n", |
@@ -270,10 +279,10 @@ static void rsnd_ssi_hw_stop(struct rsnd_ssi *ssi) | |||
270 | * SSI mod common functions | 279 | * SSI mod common functions |
271 | */ | 280 | */ |
272 | static int rsnd_ssi_init(struct rsnd_mod *mod, | 281 | static int rsnd_ssi_init(struct rsnd_mod *mod, |
282 | struct rsnd_dai_stream *io, | ||
273 | struct rsnd_priv *priv) | 283 | struct rsnd_priv *priv) |
274 | { | 284 | { |
275 | struct rsnd_ssi *ssi = rsnd_mod_to_ssi(mod); | 285 | struct rsnd_ssi *ssi = rsnd_mod_to_ssi(mod); |
276 | struct rsnd_dai_stream *io = rsnd_mod_to_io(mod); | ||
277 | struct rsnd_dai *rdai = rsnd_io_to_rdai(io); | 286 | struct rsnd_dai *rdai = rsnd_io_to_rdai(io); |
278 | struct snd_pcm_runtime *runtime = rsnd_io_to_runtime(io); | 287 | struct snd_pcm_runtime *runtime = rsnd_io_to_runtime(io); |
279 | u32 cr; | 288 | u32 cr; |
@@ -321,6 +330,7 @@ static int rsnd_ssi_init(struct rsnd_mod *mod, | |||
321 | } | 330 | } |
322 | 331 | ||
323 | static int rsnd_ssi_quit(struct rsnd_mod *mod, | 332 | static int rsnd_ssi_quit(struct rsnd_mod *mod, |
333 | struct rsnd_dai_stream *io, | ||
324 | struct rsnd_priv *priv) | 334 | struct rsnd_priv *priv) |
325 | { | 335 | { |
326 | struct rsnd_ssi *ssi = rsnd_mod_to_ssi(mod); | 336 | struct rsnd_ssi *ssi = rsnd_mod_to_ssi(mod); |
@@ -336,6 +346,37 @@ static int rsnd_ssi_quit(struct rsnd_mod *mod, | |||
336 | return 0; | 346 | return 0; |
337 | } | 347 | } |
338 | 348 | ||
349 | static int rsnd_ssi_hw_params(struct rsnd_mod *mod, | ||
350 | struct rsnd_dai_stream *io, | ||
351 | struct snd_pcm_substream *substream, | ||
352 | struct snd_pcm_hw_params *params) | ||
353 | { | ||
354 | struct rsnd_ssi *ssi = rsnd_mod_to_ssi(mod); | ||
355 | struct rsnd_ssi *ssi_parent = rsnd_ssi_parent(ssi); | ||
356 | int chan = params_channels(params); | ||
357 | |||
358 | /* | ||
359 | * Already working. | ||
360 | * It will happen if SSI has parent/child connection. | ||
361 | */ | ||
362 | if (ssi->usrcnt) { | ||
363 | /* | ||
364 | * it is error if child <-> parent SSI uses | ||
365 | * different channels. | ||
366 | */ | ||
367 | if (ssi->chan != chan) | ||
368 | return -EIO; | ||
369 | } | ||
370 | |||
371 | /* It will be removed on rsnd_ssi_hw_stop */ | ||
372 | ssi->chan = chan; | ||
373 | if (ssi_parent) | ||
374 | return rsnd_ssi_hw_params(&ssi_parent->mod, io, | ||
375 | substream, params); | ||
376 | |||
377 | return 0; | ||
378 | } | ||
379 | |||
339 | static void rsnd_ssi_record_error(struct rsnd_ssi *ssi, u32 status) | 380 | static void rsnd_ssi_record_error(struct rsnd_ssi *ssi, u32 status) |
340 | { | 381 | { |
341 | /* under/over flow error */ | 382 | /* under/over flow error */ |
@@ -348,12 +389,12 @@ static void rsnd_ssi_record_error(struct rsnd_ssi *ssi, u32 status) | |||
348 | } | 389 | } |
349 | 390 | ||
350 | static int rsnd_ssi_start(struct rsnd_mod *mod, | 391 | static int rsnd_ssi_start(struct rsnd_mod *mod, |
392 | struct rsnd_dai_stream *io, | ||
351 | struct rsnd_priv *priv) | 393 | struct rsnd_priv *priv) |
352 | { | 394 | { |
353 | struct rsnd_ssi *ssi = rsnd_mod_to_ssi(mod); | 395 | struct rsnd_ssi *ssi = rsnd_mod_to_ssi(mod); |
354 | struct rsnd_dai_stream *io = rsnd_mod_to_io(mod); | ||
355 | 396 | ||
356 | rsnd_src_ssiu_start(mod, rsnd_ssi_use_busif(mod)); | 397 | rsnd_src_ssiu_start(mod, io, rsnd_ssi_use_busif(io, mod)); |
357 | 398 | ||
358 | rsnd_ssi_hw_start(ssi, io); | 399 | rsnd_ssi_hw_start(ssi, io); |
359 | 400 | ||
@@ -363,6 +404,7 @@ static int rsnd_ssi_start(struct rsnd_mod *mod, | |||
363 | } | 404 | } |
364 | 405 | ||
365 | static int rsnd_ssi_stop(struct rsnd_mod *mod, | 406 | static int rsnd_ssi_stop(struct rsnd_mod *mod, |
407 | struct rsnd_dai_stream *io, | ||
366 | struct rsnd_priv *priv) | 408 | struct rsnd_priv *priv) |
367 | { | 409 | { |
368 | struct rsnd_ssi *ssi = rsnd_mod_to_ssi(mod); | 410 | struct rsnd_ssi *ssi = rsnd_mod_to_ssi(mod); |
@@ -371,24 +413,29 @@ static int rsnd_ssi_stop(struct rsnd_mod *mod, | |||
371 | 413 | ||
372 | rsnd_ssi_record_error(ssi, rsnd_mod_read(mod, SSISR)); | 414 | rsnd_ssi_record_error(ssi, rsnd_mod_read(mod, SSISR)); |
373 | 415 | ||
374 | rsnd_ssi_hw_stop(ssi); | 416 | rsnd_ssi_hw_stop(io, ssi); |
375 | 417 | ||
376 | rsnd_src_ssiu_stop(mod); | 418 | rsnd_src_ssiu_stop(mod, io); |
377 | 419 | ||
378 | return 0; | 420 | return 0; |
379 | } | 421 | } |
380 | 422 | ||
381 | static irqreturn_t rsnd_ssi_interrupt(int irq, void *data) | 423 | static void __rsnd_ssi_interrupt(struct rsnd_mod *mod, |
424 | struct rsnd_dai_stream *io) | ||
382 | { | 425 | { |
383 | struct rsnd_ssi *ssi = data; | 426 | struct rsnd_ssi *ssi = rsnd_mod_to_ssi(mod); |
384 | struct rsnd_mod *mod = &ssi->mod; | ||
385 | struct rsnd_priv *priv = rsnd_mod_to_priv(mod); | 427 | struct rsnd_priv *priv = rsnd_mod_to_priv(mod); |
386 | struct rsnd_dai_stream *io = rsnd_mod_to_io(mod); | ||
387 | int is_dma = rsnd_ssi_is_dma_mode(mod); | 428 | int is_dma = rsnd_ssi_is_dma_mode(mod); |
388 | u32 status = rsnd_mod_read(mod, SSISR); | 429 | u32 status; |
430 | bool elapsed = false; | ||
431 | |||
432 | spin_lock(&priv->lock); | ||
433 | |||
434 | /* ignore all cases if not working */ | ||
435 | if (!rsnd_io_is_working(io)) | ||
436 | goto rsnd_ssi_interrupt_out; | ||
389 | 437 | ||
390 | if (!io) | 438 | status = rsnd_mod_read(mod, SSISR); |
391 | return IRQ_NONE; | ||
392 | 439 | ||
393 | /* PIO only */ | 440 | /* PIO only */ |
394 | if (!is_dma && (status & DIRQ)) { | 441 | if (!is_dma && (status & DIRQ)) { |
@@ -406,11 +453,11 @@ static irqreturn_t rsnd_ssi_interrupt(int irq, void *data) | |||
406 | else | 453 | else |
407 | *buf = rsnd_mod_read(mod, SSIRDR); | 454 | *buf = rsnd_mod_read(mod, SSIRDR); |
408 | 455 | ||
409 | rsnd_dai_pointer_update(io, sizeof(*buf)); | 456 | elapsed = rsnd_dai_pointer_update(io, sizeof(*buf)); |
410 | } | 457 | } |
411 | 458 | ||
412 | /* PIO / DMA */ | 459 | /* DMA only */ |
413 | if (status & (UIRQ | OIRQ)) { | 460 | if (is_dma && (status & (UIRQ | OIRQ))) { |
414 | struct device *dev = rsnd_priv_to_dev(priv); | 461 | struct device *dev = rsnd_priv_to_dev(priv); |
415 | 462 | ||
416 | /* | 463 | /* |
@@ -419,15 +466,28 @@ static irqreturn_t rsnd_ssi_interrupt(int irq, void *data) | |||
419 | dev_dbg(dev, "%s[%d] restart\n", | 466 | dev_dbg(dev, "%s[%d] restart\n", |
420 | rsnd_mod_name(mod), rsnd_mod_id(mod)); | 467 | rsnd_mod_name(mod), rsnd_mod_id(mod)); |
421 | 468 | ||
422 | rsnd_ssi_stop(mod, priv); | 469 | rsnd_ssi_stop(mod, io, priv); |
423 | if (ssi->err < 1024) | 470 | if (ssi->err < 1024) |
424 | rsnd_ssi_start(mod, priv); | 471 | rsnd_ssi_start(mod, io, priv); |
425 | else | 472 | else |
426 | dev_warn(dev, "no more SSI restart\n"); | 473 | dev_warn(dev, "no more SSI restart\n"); |
427 | } | 474 | } |
428 | 475 | ||
429 | rsnd_ssi_record_error(ssi, status); | 476 | rsnd_ssi_record_error(ssi, status); |
430 | 477 | ||
478 | rsnd_ssi_interrupt_out: | ||
479 | spin_unlock(&priv->lock); | ||
480 | |||
481 | if (elapsed) | ||
482 | rsnd_dai_period_elapsed(io); | ||
483 | } | ||
484 | |||
485 | static irqreturn_t rsnd_ssi_interrupt(int irq, void *data) | ||
486 | { | ||
487 | struct rsnd_mod *mod = data; | ||
488 | |||
489 | rsnd_mod_interrupt(mod, __rsnd_ssi_interrupt); | ||
490 | |||
431 | return IRQ_HANDLED; | 491 | return IRQ_HANDLED; |
432 | } | 492 | } |
433 | 493 | ||
@@ -435,6 +495,7 @@ static irqreturn_t rsnd_ssi_interrupt(int irq, void *data) | |||
435 | * SSI PIO | 495 | * SSI PIO |
436 | */ | 496 | */ |
437 | static int rsnd_ssi_pio_probe(struct rsnd_mod *mod, | 497 | static int rsnd_ssi_pio_probe(struct rsnd_mod *mod, |
498 | struct rsnd_dai_stream *io, | ||
438 | struct rsnd_priv *priv) | 499 | struct rsnd_priv *priv) |
439 | { | 500 | { |
440 | struct device *dev = rsnd_priv_to_dev(priv); | 501 | struct device *dev = rsnd_priv_to_dev(priv); |
@@ -444,7 +505,7 @@ static int rsnd_ssi_pio_probe(struct rsnd_mod *mod, | |||
444 | ret = devm_request_irq(dev, ssi->info->irq, | 505 | ret = devm_request_irq(dev, ssi->info->irq, |
445 | rsnd_ssi_interrupt, | 506 | rsnd_ssi_interrupt, |
446 | IRQF_SHARED, | 507 | IRQF_SHARED, |
447 | dev_name(dev), ssi); | 508 | dev_name(dev), mod); |
448 | 509 | ||
449 | return ret; | 510 | return ret; |
450 | } | 511 | } |
@@ -456,9 +517,11 @@ static struct rsnd_mod_ops rsnd_ssi_pio_ops = { | |||
456 | .quit = rsnd_ssi_quit, | 517 | .quit = rsnd_ssi_quit, |
457 | .start = rsnd_ssi_start, | 518 | .start = rsnd_ssi_start, |
458 | .stop = rsnd_ssi_stop, | 519 | .stop = rsnd_ssi_stop, |
520 | .hw_params = rsnd_ssi_hw_params, | ||
459 | }; | 521 | }; |
460 | 522 | ||
461 | static int rsnd_ssi_dma_probe(struct rsnd_mod *mod, | 523 | static int rsnd_ssi_dma_probe(struct rsnd_mod *mod, |
524 | struct rsnd_dai_stream *io, | ||
462 | struct rsnd_priv *priv) | 525 | struct rsnd_priv *priv) |
463 | { | 526 | { |
464 | struct rsnd_ssi *ssi = rsnd_mod_to_ssi(mod); | 527 | struct rsnd_ssi *ssi = rsnd_mod_to_ssi(mod); |
@@ -469,25 +532,26 @@ static int rsnd_ssi_dma_probe(struct rsnd_mod *mod, | |||
469 | ret = devm_request_irq(dev, ssi->info->irq, | 532 | ret = devm_request_irq(dev, ssi->info->irq, |
470 | rsnd_ssi_interrupt, | 533 | rsnd_ssi_interrupt, |
471 | IRQF_SHARED, | 534 | IRQF_SHARED, |
472 | dev_name(dev), ssi); | 535 | dev_name(dev), mod); |
473 | if (ret) | 536 | if (ret) |
474 | return ret; | 537 | return ret; |
475 | 538 | ||
476 | ret = rsnd_dma_init( | 539 | ret = rsnd_dma_init( |
477 | priv, rsnd_mod_to_dma(mod), | 540 | io, rsnd_mod_to_dma(mod), |
478 | dma_id); | 541 | dma_id); |
479 | 542 | ||
480 | return ret; | 543 | return ret; |
481 | } | 544 | } |
482 | 545 | ||
483 | static int rsnd_ssi_dma_remove(struct rsnd_mod *mod, | 546 | static int rsnd_ssi_dma_remove(struct rsnd_mod *mod, |
547 | struct rsnd_dai_stream *io, | ||
484 | struct rsnd_priv *priv) | 548 | struct rsnd_priv *priv) |
485 | { | 549 | { |
486 | struct rsnd_ssi *ssi = rsnd_mod_to_ssi(mod); | 550 | struct rsnd_ssi *ssi = rsnd_mod_to_ssi(mod); |
487 | struct device *dev = rsnd_priv_to_dev(priv); | 551 | struct device *dev = rsnd_priv_to_dev(priv); |
488 | int irq = ssi->info->irq; | 552 | int irq = ssi->info->irq; |
489 | 553 | ||
490 | rsnd_dma_quit(rsnd_mod_to_dma(mod)); | 554 | rsnd_dma_quit(io, rsnd_mod_to_dma(mod)); |
491 | 555 | ||
492 | /* PIO will request IRQ again */ | 556 | /* PIO will request IRQ again */ |
493 | devm_free_irq(dev, irq, ssi); | 557 | devm_free_irq(dev, irq, ssi); |
@@ -496,6 +560,7 @@ static int rsnd_ssi_dma_remove(struct rsnd_mod *mod, | |||
496 | } | 560 | } |
497 | 561 | ||
498 | static int rsnd_ssi_fallback(struct rsnd_mod *mod, | 562 | static int rsnd_ssi_fallback(struct rsnd_mod *mod, |
563 | struct rsnd_dai_stream *io, | ||
499 | struct rsnd_priv *priv) | 564 | struct rsnd_priv *priv) |
500 | { | 565 | { |
501 | struct device *dev = rsnd_priv_to_dev(priv); | 566 | struct device *dev = rsnd_priv_to_dev(priv); |
@@ -516,37 +581,39 @@ static int rsnd_ssi_fallback(struct rsnd_mod *mod, | |||
516 | } | 581 | } |
517 | 582 | ||
518 | static int rsnd_ssi_dma_start(struct rsnd_mod *mod, | 583 | static int rsnd_ssi_dma_start(struct rsnd_mod *mod, |
584 | struct rsnd_dai_stream *io, | ||
519 | struct rsnd_priv *priv) | 585 | struct rsnd_priv *priv) |
520 | { | 586 | { |
521 | struct rsnd_dma *dma = rsnd_mod_to_dma(mod); | 587 | struct rsnd_dma *dma = rsnd_mod_to_dma(mod); |
522 | 588 | ||
523 | rsnd_dma_start(dma); | 589 | rsnd_dma_start(io, dma); |
524 | 590 | ||
525 | rsnd_ssi_start(mod, priv); | 591 | rsnd_ssi_start(mod, io, priv); |
526 | 592 | ||
527 | return 0; | 593 | return 0; |
528 | } | 594 | } |
529 | 595 | ||
530 | static int rsnd_ssi_dma_stop(struct rsnd_mod *mod, | 596 | static int rsnd_ssi_dma_stop(struct rsnd_mod *mod, |
597 | struct rsnd_dai_stream *io, | ||
531 | struct rsnd_priv *priv) | 598 | struct rsnd_priv *priv) |
532 | { | 599 | { |
533 | struct rsnd_dma *dma = rsnd_mod_to_dma(mod); | 600 | struct rsnd_dma *dma = rsnd_mod_to_dma(mod); |
534 | 601 | ||
535 | rsnd_ssi_stop(mod, priv); | 602 | rsnd_ssi_stop(mod, io, priv); |
536 | 603 | ||
537 | rsnd_dma_stop(dma); | 604 | rsnd_dma_stop(io, dma); |
538 | 605 | ||
539 | return 0; | 606 | return 0; |
540 | } | 607 | } |
541 | 608 | ||
542 | static struct dma_chan *rsnd_ssi_dma_req(struct rsnd_mod *mod) | 609 | static struct dma_chan *rsnd_ssi_dma_req(struct rsnd_dai_stream *io, |
610 | struct rsnd_mod *mod) | ||
543 | { | 611 | { |
544 | struct rsnd_priv *priv = rsnd_mod_to_priv(mod); | 612 | struct rsnd_priv *priv = rsnd_mod_to_priv(mod); |
545 | struct rsnd_dai_stream *io = rsnd_mod_to_io(mod); | ||
546 | int is_play = rsnd_io_is_play(io); | 613 | int is_play = rsnd_io_is_play(io); |
547 | char *name; | 614 | char *name; |
548 | 615 | ||
549 | if (rsnd_ssi_use_busif(mod)) | 616 | if (rsnd_ssi_use_busif(io, mod)) |
550 | name = is_play ? "rxu" : "txu"; | 617 | name = is_play ? "rxu" : "txu"; |
551 | else | 618 | else |
552 | name = is_play ? "rx" : "tx"; | 619 | name = is_play ? "rx" : "tx"; |
@@ -565,6 +632,7 @@ static struct rsnd_mod_ops rsnd_ssi_dma_ops = { | |||
565 | .start = rsnd_ssi_dma_start, | 632 | .start = rsnd_ssi_dma_start, |
566 | .stop = rsnd_ssi_dma_stop, | 633 | .stop = rsnd_ssi_dma_stop, |
567 | .fallback = rsnd_ssi_fallback, | 634 | .fallback = rsnd_ssi_fallback, |
635 | .hw_params = rsnd_ssi_hw_params, | ||
568 | }; | 636 | }; |
569 | 637 | ||
570 | int rsnd_ssi_is_dma_mode(struct rsnd_mod *mod) | 638 | int rsnd_ssi_is_dma_mode(struct rsnd_mod *mod) |
@@ -598,7 +666,7 @@ int rsnd_ssi_is_pin_sharing(struct rsnd_mod *mod) | |||
598 | return !!(rsnd_ssi_mode_flags(ssi) & RSND_SSI_CLK_PIN_SHARE); | 666 | return !!(rsnd_ssi_mode_flags(ssi) & RSND_SSI_CLK_PIN_SHARE); |
599 | } | 667 | } |
600 | 668 | ||
601 | static void rsnd_ssi_parent_clk_setup(struct rsnd_priv *priv, struct rsnd_ssi *ssi) | 669 | static void rsnd_ssi_parent_setup(struct rsnd_priv *priv, struct rsnd_ssi *ssi) |
602 | { | 670 | { |
603 | if (!rsnd_ssi_is_pin_sharing(&ssi->mod)) | 671 | if (!rsnd_ssi_is_pin_sharing(&ssi->mod)) |
604 | return; | 672 | return; |
@@ -728,11 +796,11 @@ int rsnd_ssi_probe(struct platform_device *pdev, | |||
728 | else if (rsnd_ssi_pio_available(ssi)) | 796 | else if (rsnd_ssi_pio_available(ssi)) |
729 | ops = &rsnd_ssi_pio_ops; | 797 | ops = &rsnd_ssi_pio_ops; |
730 | 798 | ||
731 | ret = rsnd_mod_init(&ssi->mod, ops, clk, RSND_MOD_SSI, i); | 799 | ret = rsnd_mod_init(priv, &ssi->mod, ops, clk, RSND_MOD_SSI, i); |
732 | if (ret) | 800 | if (ret) |
733 | return ret; | 801 | return ret; |
734 | 802 | ||
735 | rsnd_ssi_parent_clk_setup(priv, ssi); | 803 | rsnd_ssi_parent_setup(priv, ssi); |
736 | } | 804 | } |
737 | 805 | ||
738 | return 0; | 806 | return 0; |
diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c index 23732523f87c..3a4a5c0e3f97 100644 --- a/sound/soc/soc-core.c +++ b/sound/soc/soc-core.c | |||
@@ -40,6 +40,7 @@ | |||
40 | #include <sound/pcm_params.h> | 40 | #include <sound/pcm_params.h> |
41 | #include <sound/soc.h> | 41 | #include <sound/soc.h> |
42 | #include <sound/soc-dpcm.h> | 42 | #include <sound/soc-dpcm.h> |
43 | #include <sound/soc-topology.h> | ||
43 | #include <sound/initval.h> | 44 | #include <sound/initval.h> |
44 | 45 | ||
45 | #define CREATE_TRACE_POINTS | 46 | #define CREATE_TRACE_POINTS |
@@ -92,30 +93,21 @@ static int format_register_str(struct snd_soc_codec *codec, | |||
92 | int wordsize = min_bytes_needed(codec->driver->reg_cache_size) * 2; | 93 | int wordsize = min_bytes_needed(codec->driver->reg_cache_size) * 2; |
93 | int regsize = codec->driver->reg_word_size * 2; | 94 | int regsize = codec->driver->reg_word_size * 2; |
94 | int ret; | 95 | int ret; |
95 | char tmpbuf[len + 1]; | ||
96 | char regbuf[regsize + 1]; | ||
97 | |||
98 | /* since tmpbuf is allocated on the stack, warn the callers if they | ||
99 | * try to abuse this function */ | ||
100 | WARN_ON(len > 63); | ||
101 | 96 | ||
102 | /* +2 for ': ' and + 1 for '\n' */ | 97 | /* +2 for ': ' and + 1 for '\n' */ |
103 | if (wordsize + regsize + 2 + 1 != len) | 98 | if (wordsize + regsize + 2 + 1 != len) |
104 | return -EINVAL; | 99 | return -EINVAL; |
105 | 100 | ||
106 | ret = snd_soc_read(codec, reg); | 101 | sprintf(buf, "%.*x: ", wordsize, reg); |
107 | if (ret < 0) { | 102 | buf += wordsize + 2; |
108 | memset(regbuf, 'X', regsize); | ||
109 | regbuf[regsize] = '\0'; | ||
110 | } else { | ||
111 | snprintf(regbuf, regsize + 1, "%.*x", regsize, ret); | ||
112 | } | ||
113 | |||
114 | /* prepare the buffer */ | ||
115 | snprintf(tmpbuf, len + 1, "%.*x: %s\n", wordsize, reg, regbuf); | ||
116 | /* copy it back to the caller without the '\0' */ | ||
117 | memcpy(buf, tmpbuf, len); | ||
118 | 103 | ||
104 | ret = snd_soc_read(codec, reg); | ||
105 | if (ret < 0) | ||
106 | memset(buf, 'X', regsize); | ||
107 | else | ||
108 | sprintf(buf, "%.*x", regsize, ret); | ||
109 | buf[regsize] = '\n'; | ||
110 | /* no NUL-termination needed */ | ||
119 | return 0; | 111 | return 0; |
120 | } | 112 | } |
121 | 113 | ||
@@ -750,23 +742,10 @@ static void soc_resume_deferred(struct work_struct *work) | |||
750 | } | 742 | } |
751 | 743 | ||
752 | list_for_each_entry(codec, &card->codec_dev_list, card_list) { | 744 | list_for_each_entry(codec, &card->codec_dev_list, card_list) { |
753 | /* If the CODEC was idle over suspend then it will have been | ||
754 | * left with bias OFF or STANDBY and suspended so we must now | ||
755 | * resume. Otherwise the suspend was suppressed. | ||
756 | */ | ||
757 | if (codec->suspended) { | 745 | if (codec->suspended) { |
758 | switch (codec->dapm.bias_level) { | 746 | if (codec->driver->resume) |
759 | case SND_SOC_BIAS_STANDBY: | 747 | codec->driver->resume(codec); |
760 | case SND_SOC_BIAS_OFF: | 748 | codec->suspended = 0; |
761 | if (codec->driver->resume) | ||
762 | codec->driver->resume(codec); | ||
763 | codec->suspended = 0; | ||
764 | break; | ||
765 | default: | ||
766 | dev_dbg(codec->dev, | ||
767 | "ASoC: CODEC was on over suspend\n"); | ||
768 | break; | ||
769 | } | ||
770 | } | 749 | } |
771 | } | 750 | } |
772 | 751 | ||
@@ -904,12 +883,17 @@ static struct snd_soc_dai *snd_soc_find_dai( | |||
904 | { | 883 | { |
905 | struct snd_soc_component *component; | 884 | struct snd_soc_component *component; |
906 | struct snd_soc_dai *dai; | 885 | struct snd_soc_dai *dai; |
886 | struct device_node *component_of_node; | ||
907 | 887 | ||
908 | lockdep_assert_held(&client_mutex); | 888 | lockdep_assert_held(&client_mutex); |
909 | 889 | ||
910 | /* Find CPU DAI from registered DAIs*/ | 890 | /* Find CPU DAI from registered DAIs*/ |
911 | list_for_each_entry(component, &component_list, list) { | 891 | list_for_each_entry(component, &component_list, list) { |
912 | if (dlc->of_node && component->dev->of_node != dlc->of_node) | 892 | component_of_node = component->dev->of_node; |
893 | if (!component_of_node && component->dev->parent) | ||
894 | component_of_node = component->dev->parent->of_node; | ||
895 | |||
896 | if (dlc->of_node && component_of_node != dlc->of_node) | ||
913 | continue; | 897 | continue; |
914 | if (dlc->name && strcmp(component->name, dlc->name)) | 898 | if (dlc->name && strcmp(component->name, dlc->name)) |
915 | continue; | 899 | continue; |
@@ -2435,6 +2419,7 @@ int snd_soc_register_card(struct snd_soc_card *card) | |||
2435 | card->rtd_aux[i].card = card; | 2419 | card->rtd_aux[i].card = card; |
2436 | 2420 | ||
2437 | INIT_LIST_HEAD(&card->dapm_dirty); | 2421 | INIT_LIST_HEAD(&card->dapm_dirty); |
2422 | INIT_LIST_HEAD(&card->dobj_list); | ||
2438 | card->instantiated = 0; | 2423 | card->instantiated = 0; |
2439 | mutex_init(&card->mutex); | 2424 | mutex_init(&card->mutex); |
2440 | mutex_init(&card->dapm_mutex); | 2425 | mutex_init(&card->dapm_mutex); |
@@ -2599,7 +2584,8 @@ static int snd_soc_register_dais(struct snd_soc_component *component, | |||
2599 | * the same naming style even though those DAIs are not | 2584 | * the same naming style even though those DAIs are not |
2600 | * component-less anymore. | 2585 | * component-less anymore. |
2601 | */ | 2586 | */ |
2602 | if (count == 1 && legacy_dai_naming) { | 2587 | if (count == 1 && legacy_dai_naming && |
2588 | (dai_drv[i].id == 0 || dai_drv[i].name == NULL)) { | ||
2603 | dai->name = fmt_single_name(dev, &dai->id); | 2589 | dai->name = fmt_single_name(dev, &dai->id); |
2604 | } else { | 2590 | } else { |
2605 | dai->name = fmt_multiple_name(dev, &dai_drv[i]); | 2591 | dai->name = fmt_multiple_name(dev, &dai_drv[i]); |
@@ -2749,6 +2735,7 @@ static void snd_soc_component_add_unlocked(struct snd_soc_component *component) | |||
2749 | } | 2735 | } |
2750 | 2736 | ||
2751 | list_add(&component->list, &component_list); | 2737 | list_add(&component->list, &component_list); |
2738 | INIT_LIST_HEAD(&component->dobj_list); | ||
2752 | } | 2739 | } |
2753 | 2740 | ||
2754 | static void snd_soc_component_add(struct snd_soc_component *component) | 2741 | static void snd_soc_component_add(struct snd_soc_component *component) |
@@ -2825,6 +2812,7 @@ void snd_soc_unregister_component(struct device *dev) | |||
2825 | return; | 2812 | return; |
2826 | 2813 | ||
2827 | found: | 2814 | found: |
2815 | snd_soc_tplg_component_remove(cmpnt, SND_SOC_TPLG_INDEX_ALL); | ||
2828 | snd_soc_component_del_unlocked(cmpnt); | 2816 | snd_soc_component_del_unlocked(cmpnt); |
2829 | mutex_unlock(&client_mutex); | 2817 | mutex_unlock(&client_mutex); |
2830 | snd_soc_component_cleanup(cmpnt); | 2818 | snd_soc_component_cleanup(cmpnt); |
@@ -3488,11 +3476,16 @@ static int snd_soc_get_dai_name(struct of_phandle_args *args, | |||
3488 | const char **dai_name) | 3476 | const char **dai_name) |
3489 | { | 3477 | { |
3490 | struct snd_soc_component *pos; | 3478 | struct snd_soc_component *pos; |
3479 | struct device_node *component_of_node; | ||
3491 | int ret = -EPROBE_DEFER; | 3480 | int ret = -EPROBE_DEFER; |
3492 | 3481 | ||
3493 | mutex_lock(&client_mutex); | 3482 | mutex_lock(&client_mutex); |
3494 | list_for_each_entry(pos, &component_list, list) { | 3483 | list_for_each_entry(pos, &component_list, list) { |
3495 | if (pos->dev->of_node != args->np) | 3484 | component_of_node = pos->dev->of_node; |
3485 | if (!component_of_node && pos->dev->parent) | ||
3486 | component_of_node = pos->dev->parent->of_node; | ||
3487 | |||
3488 | if (component_of_node != args->np) | ||
3496 | continue; | 3489 | continue; |
3497 | 3490 | ||
3498 | if (pos->driver->of_xlate_dai_name) { | 3491 | if (pos->driver->of_xlate_dai_name) { |
diff --git a/sound/soc/soc-dapm.c b/sound/soc/soc-dapm.c index defe0f0082b5..aa327c92480c 100644 --- a/sound/soc/soc-dapm.c +++ b/sound/soc/soc-dapm.c | |||
@@ -52,10 +52,15 @@ static int snd_soc_dapm_add_path(struct snd_soc_dapm_context *dapm, | |||
52 | const char *control, | 52 | const char *control, |
53 | int (*connected)(struct snd_soc_dapm_widget *source, | 53 | int (*connected)(struct snd_soc_dapm_widget *source, |
54 | struct snd_soc_dapm_widget *sink)); | 54 | struct snd_soc_dapm_widget *sink)); |
55 | static struct snd_soc_dapm_widget * | 55 | |
56 | struct snd_soc_dapm_widget * | ||
56 | snd_soc_dapm_new_control(struct snd_soc_dapm_context *dapm, | 57 | snd_soc_dapm_new_control(struct snd_soc_dapm_context *dapm, |
57 | const struct snd_soc_dapm_widget *widget); | 58 | const struct snd_soc_dapm_widget *widget); |
58 | 59 | ||
60 | struct snd_soc_dapm_widget * | ||
61 | snd_soc_dapm_new_control_unlocked(struct snd_soc_dapm_context *dapm, | ||
62 | const struct snd_soc_dapm_widget *widget); | ||
63 | |||
59 | /* dapm power sequences - make this per codec in the future */ | 64 | /* dapm power sequences - make this per codec in the future */ |
60 | static int dapm_up_seq[] = { | 65 | static int dapm_up_seq[] = { |
61 | [snd_soc_dapm_pre] = 0, | 66 | [snd_soc_dapm_pre] = 0, |
@@ -70,6 +75,7 @@ static int dapm_up_seq[] = { | |||
70 | [snd_soc_dapm_aif_out] = 4, | 75 | [snd_soc_dapm_aif_out] = 4, |
71 | [snd_soc_dapm_mic] = 5, | 76 | [snd_soc_dapm_mic] = 5, |
72 | [snd_soc_dapm_mux] = 6, | 77 | [snd_soc_dapm_mux] = 6, |
78 | [snd_soc_dapm_demux] = 6, | ||
73 | [snd_soc_dapm_dac] = 7, | 79 | [snd_soc_dapm_dac] = 7, |
74 | [snd_soc_dapm_switch] = 8, | 80 | [snd_soc_dapm_switch] = 8, |
75 | [snd_soc_dapm_mixer] = 8, | 81 | [snd_soc_dapm_mixer] = 8, |
@@ -100,6 +106,7 @@ static int dapm_down_seq[] = { | |||
100 | [snd_soc_dapm_mic] = 7, | 106 | [snd_soc_dapm_mic] = 7, |
101 | [snd_soc_dapm_micbias] = 8, | 107 | [snd_soc_dapm_micbias] = 8, |
102 | [snd_soc_dapm_mux] = 9, | 108 | [snd_soc_dapm_mux] = 9, |
109 | [snd_soc_dapm_demux] = 9, | ||
103 | [snd_soc_dapm_aif_in] = 10, | 110 | [snd_soc_dapm_aif_in] = 10, |
104 | [snd_soc_dapm_aif_out] = 10, | 111 | [snd_soc_dapm_aif_out] = 10, |
105 | [snd_soc_dapm_dai_in] = 10, | 112 | [snd_soc_dapm_dai_in] = 10, |
@@ -308,14 +315,13 @@ static int dapm_kcontrol_data_alloc(struct snd_soc_dapm_widget *widget, | |||
308 | { | 315 | { |
309 | struct dapm_kcontrol_data *data; | 316 | struct dapm_kcontrol_data *data; |
310 | struct soc_mixer_control *mc; | 317 | struct soc_mixer_control *mc; |
318 | struct soc_enum *e; | ||
319 | const char *name; | ||
320 | int ret; | ||
311 | 321 | ||
312 | data = kzalloc(sizeof(*data), GFP_KERNEL); | 322 | data = kzalloc(sizeof(*data), GFP_KERNEL); |
313 | if (!data) { | 323 | if (!data) |
314 | dev_err(widget->dapm->dev, | ||
315 | "ASoC: can't allocate kcontrol data for %s\n", | ||
316 | widget->name); | ||
317 | return -ENOMEM; | 324 | return -ENOMEM; |
318 | } | ||
319 | 325 | ||
320 | INIT_LIST_HEAD(&data->paths); | 326 | INIT_LIST_HEAD(&data->paths); |
321 | 327 | ||
@@ -328,6 +334,13 @@ static int dapm_kcontrol_data_alloc(struct snd_soc_dapm_widget *widget, | |||
328 | if (mc->autodisable) { | 334 | if (mc->autodisable) { |
329 | struct snd_soc_dapm_widget template; | 335 | struct snd_soc_dapm_widget template; |
330 | 336 | ||
337 | name = kasprintf(GFP_KERNEL, "%s %s", kcontrol->id.name, | ||
338 | "Autodisable"); | ||
339 | if (!name) { | ||
340 | ret = -ENOMEM; | ||
341 | goto err_data; | ||
342 | } | ||
343 | |||
331 | memset(&template, 0, sizeof(template)); | 344 | memset(&template, 0, sizeof(template)); |
332 | template.reg = mc->reg; | 345 | template.reg = mc->reg; |
333 | template.mask = (1 << fls(mc->max)) - 1; | 346 | template.mask = (1 << fls(mc->max)) - 1; |
@@ -338,18 +351,55 @@ static int dapm_kcontrol_data_alloc(struct snd_soc_dapm_widget *widget, | |||
338 | template.off_val = 0; | 351 | template.off_val = 0; |
339 | template.on_val = template.off_val; | 352 | template.on_val = template.off_val; |
340 | template.id = snd_soc_dapm_kcontrol; | 353 | template.id = snd_soc_dapm_kcontrol; |
341 | template.name = kcontrol->id.name; | 354 | template.name = name; |
342 | 355 | ||
343 | data->value = template.on_val; | 356 | data->value = template.on_val; |
344 | 357 | ||
345 | data->widget = snd_soc_dapm_new_control(widget->dapm, | 358 | data->widget = |
359 | snd_soc_dapm_new_control_unlocked(widget->dapm, | ||
346 | &template); | 360 | &template); |
347 | if (!data->widget) { | 361 | if (!data->widget) { |
348 | kfree(data); | 362 | ret = -ENOMEM; |
349 | return -ENOMEM; | 363 | goto err_name; |
350 | } | 364 | } |
351 | } | 365 | } |
352 | break; | 366 | break; |
367 | case snd_soc_dapm_demux: | ||
368 | case snd_soc_dapm_mux: | ||
369 | e = (struct soc_enum *)kcontrol->private_value; | ||
370 | |||
371 | if (e->autodisable) { | ||
372 | struct snd_soc_dapm_widget template; | ||
373 | |||
374 | name = kasprintf(GFP_KERNEL, "%s %s", kcontrol->id.name, | ||
375 | "Autodisable"); | ||
376 | if (!name) { | ||
377 | ret = -ENOMEM; | ||
378 | goto err_data; | ||
379 | } | ||
380 | |||
381 | memset(&template, 0, sizeof(template)); | ||
382 | template.reg = e->reg; | ||
383 | template.mask = e->mask << e->shift_l; | ||
384 | template.shift = e->shift_l; | ||
385 | template.off_val = snd_soc_enum_item_to_val(e, 0); | ||
386 | template.on_val = template.off_val; | ||
387 | template.id = snd_soc_dapm_kcontrol; | ||
388 | template.name = name; | ||
389 | |||
390 | data->value = template.on_val; | ||
391 | |||
392 | data->widget = snd_soc_dapm_new_control(widget->dapm, | ||
393 | &template); | ||
394 | if (!data->widget) { | ||
395 | ret = -ENOMEM; | ||
396 | goto err_name; | ||
397 | } | ||
398 | |||
399 | snd_soc_dapm_add_path(widget->dapm, data->widget, | ||
400 | widget, NULL, NULL); | ||
401 | } | ||
402 | break; | ||
353 | default: | 403 | default: |
354 | break; | 404 | break; |
355 | } | 405 | } |
@@ -357,11 +407,19 @@ static int dapm_kcontrol_data_alloc(struct snd_soc_dapm_widget *widget, | |||
357 | kcontrol->private_data = data; | 407 | kcontrol->private_data = data; |
358 | 408 | ||
359 | return 0; | 409 | return 0; |
410 | |||
411 | err_name: | ||
412 | kfree(name); | ||
413 | err_data: | ||
414 | kfree(data); | ||
415 | return ret; | ||
360 | } | 416 | } |
361 | 417 | ||
362 | static void dapm_kcontrol_free(struct snd_kcontrol *kctl) | 418 | static void dapm_kcontrol_free(struct snd_kcontrol *kctl) |
363 | { | 419 | { |
364 | struct dapm_kcontrol_data *data = snd_kcontrol_chip(kctl); | 420 | struct dapm_kcontrol_data *data = snd_kcontrol_chip(kctl); |
421 | if (data->widget) | ||
422 | kfree(data->widget->name); | ||
365 | kfree(data->wlist); | 423 | kfree(data->wlist); |
366 | kfree(data); | 424 | kfree(data); |
367 | } | 425 | } |
@@ -405,11 +463,6 @@ static void dapm_kcontrol_add_path(const struct snd_kcontrol *kcontrol, | |||
405 | struct dapm_kcontrol_data *data = snd_kcontrol_chip(kcontrol); | 463 | struct dapm_kcontrol_data *data = snd_kcontrol_chip(kcontrol); |
406 | 464 | ||
407 | list_add_tail(&path->list_kcontrol, &data->paths); | 465 | list_add_tail(&path->list_kcontrol, &data->paths); |
408 | |||
409 | if (data->widget) { | ||
410 | snd_soc_dapm_add_path(data->widget->dapm, data->widget, | ||
411 | path->source, NULL, NULL); | ||
412 | } | ||
413 | } | 466 | } |
414 | 467 | ||
415 | static bool dapm_kcontrol_is_powered(const struct snd_kcontrol *kcontrol) | 468 | static bool dapm_kcontrol_is_powered(const struct snd_kcontrol *kcontrol) |
@@ -525,6 +578,67 @@ static void soc_dapm_async_complete(struct snd_soc_dapm_context *dapm) | |||
525 | snd_soc_component_async_complete(dapm->component); | 578 | snd_soc_component_async_complete(dapm->component); |
526 | } | 579 | } |
527 | 580 | ||
581 | static struct snd_soc_dapm_widget * | ||
582 | dapm_wcache_lookup(struct snd_soc_dapm_wcache *wcache, const char *name) | ||
583 | { | ||
584 | struct snd_soc_dapm_widget *w = wcache->widget; | ||
585 | struct list_head *wlist; | ||
586 | const int depth = 2; | ||
587 | int i = 0; | ||
588 | |||
589 | if (w) { | ||
590 | wlist = &w->dapm->card->widgets; | ||
591 | |||
592 | list_for_each_entry_from(w, wlist, list) { | ||
593 | if (!strcmp(name, w->name)) | ||
594 | return w; | ||
595 | |||
596 | if (++i == depth) | ||
597 | break; | ||
598 | } | ||
599 | } | ||
600 | |||
601 | return NULL; | ||
602 | } | ||
603 | |||
604 | static inline void dapm_wcache_update(struct snd_soc_dapm_wcache *wcache, | ||
605 | struct snd_soc_dapm_widget *w) | ||
606 | { | ||
607 | wcache->widget = w; | ||
608 | } | ||
609 | |||
610 | /** | ||
611 | * snd_soc_dapm_force_bias_level() - Sets the DAPM bias level | ||
612 | * @dapm: The DAPM context for which to set the level | ||
613 | * @level: The level to set | ||
614 | * | ||
615 | * Forces the DAPM bias level to a specific state. It will call the bias level | ||
616 | * callback of DAPM context with the specified level. This will even happen if | ||
617 | * the context is already at the same level. Furthermore it will not go through | ||
618 | * the normal bias level sequencing, meaning any intermediate states between the | ||
619 | * current and the target state will not be entered. | ||
620 | * | ||
621 | * Note that the change in bias level is only temporary and the next time | ||
622 | * snd_soc_dapm_sync() is called the state will be set to the level as | ||
623 | * determined by the DAPM core. The function is mainly intended to be used to | ||
624 | * used during probe or resume from suspend to power up the device so | ||
625 | * initialization can be done, before the DAPM core takes over. | ||
626 | */ | ||
627 | int snd_soc_dapm_force_bias_level(struct snd_soc_dapm_context *dapm, | ||
628 | enum snd_soc_bias_level level) | ||
629 | { | ||
630 | int ret = 0; | ||
631 | |||
632 | if (dapm->set_bias_level) | ||
633 | ret = dapm->set_bias_level(dapm, level); | ||
634 | |||
635 | if (ret == 0) | ||
636 | dapm->bias_level = level; | ||
637 | |||
638 | return ret; | ||
639 | } | ||
640 | EXPORT_SYMBOL_GPL(snd_soc_dapm_force_bias_level); | ||
641 | |||
528 | /** | 642 | /** |
529 | * snd_soc_dapm_set_bias_level - set the bias level for the system | 643 | * snd_soc_dapm_set_bias_level - set the bias level for the system |
530 | * @dapm: DAPM context | 644 | * @dapm: DAPM context |
@@ -547,10 +661,8 @@ static int snd_soc_dapm_set_bias_level(struct snd_soc_dapm_context *dapm, | |||
547 | if (ret != 0) | 661 | if (ret != 0) |
548 | goto out; | 662 | goto out; |
549 | 663 | ||
550 | if (dapm->set_bias_level) | 664 | if (!card || dapm != &card->dapm) |
551 | ret = dapm->set_bias_level(dapm, level); | 665 | ret = snd_soc_dapm_force_bias_level(dapm, level); |
552 | else if (!card || dapm != &card->dapm) | ||
553 | dapm->bias_level = level; | ||
554 | 666 | ||
555 | if (ret != 0) | 667 | if (ret != 0) |
556 | goto out; | 668 | goto out; |
@@ -565,9 +677,10 @@ out: | |||
565 | 677 | ||
566 | /* connect mux widget to its interconnecting audio paths */ | 678 | /* connect mux widget to its interconnecting audio paths */ |
567 | static int dapm_connect_mux(struct snd_soc_dapm_context *dapm, | 679 | static int dapm_connect_mux(struct snd_soc_dapm_context *dapm, |
568 | struct snd_soc_dapm_path *path, const char *control_name) | 680 | struct snd_soc_dapm_path *path, const char *control_name, |
681 | struct snd_soc_dapm_widget *w) | ||
569 | { | 682 | { |
570 | const struct snd_kcontrol_new *kcontrol = &path->sink->kcontrol_news[0]; | 683 | const struct snd_kcontrol_new *kcontrol = &w->kcontrol_news[0]; |
571 | struct soc_enum *e = (struct soc_enum *)kcontrol->private_value; | 684 | struct soc_enum *e = (struct soc_enum *)kcontrol->private_value; |
572 | unsigned int val, item; | 685 | unsigned int val, item; |
573 | int i; | 686 | int i; |
@@ -707,6 +820,7 @@ static int dapm_create_or_share_mixmux_kcontrol(struct snd_soc_dapm_widget *w, | |||
707 | wname_in_long_name = false; | 820 | wname_in_long_name = false; |
708 | kcname_in_long_name = true; | 821 | kcname_in_long_name = true; |
709 | break; | 822 | break; |
823 | case snd_soc_dapm_demux: | ||
710 | case snd_soc_dapm_mux: | 824 | case snd_soc_dapm_mux: |
711 | wname_in_long_name = true; | 825 | wname_in_long_name = true; |
712 | kcname_in_long_name = false; | 826 | kcname_in_long_name = false; |
@@ -777,6 +891,7 @@ static int dapm_new_mixer(struct snd_soc_dapm_widget *w) | |||
777 | { | 891 | { |
778 | int i, ret; | 892 | int i, ret; |
779 | struct snd_soc_dapm_path *path; | 893 | struct snd_soc_dapm_path *path; |
894 | struct dapm_kcontrol_data *data; | ||
780 | 895 | ||
781 | /* add kcontrol */ | 896 | /* add kcontrol */ |
782 | for (i = 0; i < w->num_kcontrols; i++) { | 897 | for (i = 0; i < w->num_kcontrols; i++) { |
@@ -786,16 +901,20 @@ static int dapm_new_mixer(struct snd_soc_dapm_widget *w) | |||
786 | if (path->name != (char *)w->kcontrol_news[i].name) | 901 | if (path->name != (char *)w->kcontrol_news[i].name) |
787 | continue; | 902 | continue; |
788 | 903 | ||
789 | if (w->kcontrols[i]) { | 904 | if (!w->kcontrols[i]) { |
790 | dapm_kcontrol_add_path(w->kcontrols[i], path); | 905 | ret = dapm_create_or_share_mixmux_kcontrol(w, i); |
791 | continue; | 906 | if (ret < 0) |
907 | return ret; | ||
792 | } | 908 | } |
793 | 909 | ||
794 | ret = dapm_create_or_share_mixmux_kcontrol(w, i); | ||
795 | if (ret < 0) | ||
796 | return ret; | ||
797 | |||
798 | dapm_kcontrol_add_path(w->kcontrols[i], path); | 910 | dapm_kcontrol_add_path(w->kcontrols[i], path); |
911 | |||
912 | data = snd_kcontrol_chip(w->kcontrols[i]); | ||
913 | if (data->widget) | ||
914 | snd_soc_dapm_add_path(data->widget->dapm, | ||
915 | data->widget, | ||
916 | path->source, | ||
917 | NULL, NULL); | ||
799 | } | 918 | } |
800 | } | 919 | } |
801 | 920 | ||
@@ -807,17 +926,32 @@ static int dapm_new_mux(struct snd_soc_dapm_widget *w) | |||
807 | { | 926 | { |
808 | struct snd_soc_dapm_context *dapm = w->dapm; | 927 | struct snd_soc_dapm_context *dapm = w->dapm; |
809 | struct snd_soc_dapm_path *path; | 928 | struct snd_soc_dapm_path *path; |
929 | struct list_head *paths; | ||
930 | const char *type; | ||
810 | int ret; | 931 | int ret; |
811 | 932 | ||
933 | switch (w->id) { | ||
934 | case snd_soc_dapm_mux: | ||
935 | paths = &w->sources; | ||
936 | type = "mux"; | ||
937 | break; | ||
938 | case snd_soc_dapm_demux: | ||
939 | paths = &w->sinks; | ||
940 | type = "demux"; | ||
941 | break; | ||
942 | default: | ||
943 | return -EINVAL; | ||
944 | } | ||
945 | |||
812 | if (w->num_kcontrols != 1) { | 946 | if (w->num_kcontrols != 1) { |
813 | dev_err(dapm->dev, | 947 | dev_err(dapm->dev, |
814 | "ASoC: mux %s has incorrect number of controls\n", | 948 | "ASoC: %s %s has incorrect number of controls\n", type, |
815 | w->name); | 949 | w->name); |
816 | return -EINVAL; | 950 | return -EINVAL; |
817 | } | 951 | } |
818 | 952 | ||
819 | if (list_empty(&w->sources)) { | 953 | if (list_empty(paths)) { |
820 | dev_err(dapm->dev, "ASoC: mux %s has no paths\n", w->name); | 954 | dev_err(dapm->dev, "ASoC: %s %s has no paths\n", type, w->name); |
821 | return -EINVAL; | 955 | return -EINVAL; |
822 | } | 956 | } |
823 | 957 | ||
@@ -825,9 +959,16 @@ static int dapm_new_mux(struct snd_soc_dapm_widget *w) | |||
825 | if (ret < 0) | 959 | if (ret < 0) |
826 | return ret; | 960 | return ret; |
827 | 961 | ||
828 | list_for_each_entry(path, &w->sources, list_sink) { | 962 | if (w->id == snd_soc_dapm_mux) { |
829 | if (path->name) | 963 | list_for_each_entry(path, &w->sources, list_sink) { |
830 | dapm_kcontrol_add_path(w->kcontrols[0], path); | 964 | if (path->name) |
965 | dapm_kcontrol_add_path(w->kcontrols[0], path); | ||
966 | } | ||
967 | } else { | ||
968 | list_for_each_entry(path, &w->sinks, list_source) { | ||
969 | if (path->name) | ||
970 | dapm_kcontrol_add_path(w->kcontrols[0], path); | ||
971 | } | ||
831 | } | 972 | } |
832 | 973 | ||
833 | return 0; | 974 | return 0; |
@@ -2335,6 +2476,50 @@ static void dapm_update_widget_flags(struct snd_soc_dapm_widget *w) | |||
2335 | } | 2476 | } |
2336 | } | 2477 | } |
2337 | 2478 | ||
2479 | static int snd_soc_dapm_check_dynamic_path(struct snd_soc_dapm_context *dapm, | ||
2480 | struct snd_soc_dapm_widget *source, struct snd_soc_dapm_widget *sink, | ||
2481 | const char *control) | ||
2482 | { | ||
2483 | bool dynamic_source = false; | ||
2484 | bool dynamic_sink = false; | ||
2485 | |||
2486 | if (!control) | ||
2487 | return 0; | ||
2488 | |||
2489 | switch (source->id) { | ||
2490 | case snd_soc_dapm_demux: | ||
2491 | dynamic_source = true; | ||
2492 | break; | ||
2493 | default: | ||
2494 | break; | ||
2495 | } | ||
2496 | |||
2497 | switch (sink->id) { | ||
2498 | case snd_soc_dapm_mux: | ||
2499 | case snd_soc_dapm_switch: | ||
2500 | case snd_soc_dapm_mixer: | ||
2501 | case snd_soc_dapm_mixer_named_ctl: | ||
2502 | dynamic_sink = true; | ||
2503 | break; | ||
2504 | default: | ||
2505 | break; | ||
2506 | } | ||
2507 | |||
2508 | if (dynamic_source && dynamic_sink) { | ||
2509 | dev_err(dapm->dev, | ||
2510 | "Direct connection between demux and mixer/mux not supported for path %s -> [%s] -> %s\n", | ||
2511 | source->name, control, sink->name); | ||
2512 | return -EINVAL; | ||
2513 | } else if (!dynamic_source && !dynamic_sink) { | ||
2514 | dev_err(dapm->dev, | ||
2515 | "Control not supported for path %s -> [%s] -> %s\n", | ||
2516 | source->name, control, sink->name); | ||
2517 | return -EINVAL; | ||
2518 | } | ||
2519 | |||
2520 | return 0; | ||
2521 | } | ||
2522 | |||
2338 | static int snd_soc_dapm_add_path(struct snd_soc_dapm_context *dapm, | 2523 | static int snd_soc_dapm_add_path(struct snd_soc_dapm_context *dapm, |
2339 | struct snd_soc_dapm_widget *wsource, struct snd_soc_dapm_widget *wsink, | 2524 | struct snd_soc_dapm_widget *wsource, struct snd_soc_dapm_widget *wsink, |
2340 | const char *control, | 2525 | const char *control, |
@@ -2365,6 +2550,10 @@ static int snd_soc_dapm_add_path(struct snd_soc_dapm_context *dapm, | |||
2365 | return -EINVAL; | 2550 | return -EINVAL; |
2366 | } | 2551 | } |
2367 | 2552 | ||
2553 | ret = snd_soc_dapm_check_dynamic_path(dapm, wsource, wsink, control); | ||
2554 | if (ret) | ||
2555 | return ret; | ||
2556 | |||
2368 | path = kzalloc(sizeof(struct snd_soc_dapm_path), GFP_KERNEL); | 2557 | path = kzalloc(sizeof(struct snd_soc_dapm_path), GFP_KERNEL); |
2369 | if (!path) | 2558 | if (!path) |
2370 | return -ENOMEM; | 2559 | return -ENOMEM; |
@@ -2384,10 +2573,19 @@ static int snd_soc_dapm_add_path(struct snd_soc_dapm_context *dapm, | |||
2384 | if (control == NULL) { | 2573 | if (control == NULL) { |
2385 | path->connect = 1; | 2574 | path->connect = 1; |
2386 | } else { | 2575 | } else { |
2387 | /* connect dynamic paths */ | 2576 | switch (wsource->id) { |
2577 | case snd_soc_dapm_demux: | ||
2578 | ret = dapm_connect_mux(dapm, path, control, wsource); | ||
2579 | if (ret) | ||
2580 | goto err; | ||
2581 | break; | ||
2582 | default: | ||
2583 | break; | ||
2584 | } | ||
2585 | |||
2388 | switch (wsink->id) { | 2586 | switch (wsink->id) { |
2389 | case snd_soc_dapm_mux: | 2587 | case snd_soc_dapm_mux: |
2390 | ret = dapm_connect_mux(dapm, path, control); | 2588 | ret = dapm_connect_mux(dapm, path, control, wsink); |
2391 | if (ret != 0) | 2589 | if (ret != 0) |
2392 | goto err; | 2590 | goto err; |
2393 | break; | 2591 | break; |
@@ -2399,11 +2597,7 @@ static int snd_soc_dapm_add_path(struct snd_soc_dapm_context *dapm, | |||
2399 | goto err; | 2597 | goto err; |
2400 | break; | 2598 | break; |
2401 | default: | 2599 | default: |
2402 | dev_err(dapm->dev, | 2600 | break; |
2403 | "Control not supported for path %s -> [%s] -> %s\n", | ||
2404 | wsource->name, control, wsink->name); | ||
2405 | ret = -EINVAL; | ||
2406 | goto err; | ||
2407 | } | 2601 | } |
2408 | } | 2602 | } |
2409 | 2603 | ||
@@ -2451,6 +2645,12 @@ static int snd_soc_dapm_add_route(struct snd_soc_dapm_context *dapm, | |||
2451 | source = route->source; | 2645 | source = route->source; |
2452 | } | 2646 | } |
2453 | 2647 | ||
2648 | wsource = dapm_wcache_lookup(&dapm->path_source_cache, source); | ||
2649 | wsink = dapm_wcache_lookup(&dapm->path_sink_cache, sink); | ||
2650 | |||
2651 | if (wsink && wsource) | ||
2652 | goto skip_search; | ||
2653 | |||
2454 | /* | 2654 | /* |
2455 | * find src and dest widgets over all widgets but favor a widget from | 2655 | * find src and dest widgets over all widgets but favor a widget from |
2456 | * current DAPM context | 2656 | * current DAPM context |
@@ -2458,14 +2658,20 @@ static int snd_soc_dapm_add_route(struct snd_soc_dapm_context *dapm, | |||
2458 | list_for_each_entry(w, &dapm->card->widgets, list) { | 2658 | list_for_each_entry(w, &dapm->card->widgets, list) { |
2459 | if (!wsink && !(strcmp(w->name, sink))) { | 2659 | if (!wsink && !(strcmp(w->name, sink))) { |
2460 | wtsink = w; | 2660 | wtsink = w; |
2461 | if (w->dapm == dapm) | 2661 | if (w->dapm == dapm) { |
2462 | wsink = w; | 2662 | wsink = w; |
2663 | if (wsource) | ||
2664 | break; | ||
2665 | } | ||
2463 | continue; | 2666 | continue; |
2464 | } | 2667 | } |
2465 | if (!wsource && !(strcmp(w->name, source))) { | 2668 | if (!wsource && !(strcmp(w->name, source))) { |
2466 | wtsource = w; | 2669 | wtsource = w; |
2467 | if (w->dapm == dapm) | 2670 | if (w->dapm == dapm) { |
2468 | wsource = w; | 2671 | wsource = w; |
2672 | if (wsink) | ||
2673 | break; | ||
2674 | } | ||
2469 | } | 2675 | } |
2470 | } | 2676 | } |
2471 | /* use widget from another DAPM context if not found from this */ | 2677 | /* use widget from another DAPM context if not found from this */ |
@@ -2485,6 +2691,10 @@ static int snd_soc_dapm_add_route(struct snd_soc_dapm_context *dapm, | |||
2485 | return -ENODEV; | 2691 | return -ENODEV; |
2486 | } | 2692 | } |
2487 | 2693 | ||
2694 | skip_search: | ||
2695 | dapm_wcache_update(&dapm->path_sink_cache, wsink); | ||
2696 | dapm_wcache_update(&dapm->path_source_cache, wsource); | ||
2697 | |||
2488 | ret = snd_soc_dapm_add_path(dapm, wsource, wsink, route->control, | 2698 | ret = snd_soc_dapm_add_path(dapm, wsource, wsink, route->control, |
2489 | route->connected); | 2699 | route->connected); |
2490 | if (ret) | 2700 | if (ret) |
@@ -2736,6 +2946,7 @@ int snd_soc_dapm_new_widgets(struct snd_soc_card *card) | |||
2736 | dapm_new_mixer(w); | 2946 | dapm_new_mixer(w); |
2737 | break; | 2947 | break; |
2738 | case snd_soc_dapm_mux: | 2948 | case snd_soc_dapm_mux: |
2949 | case snd_soc_dapm_demux: | ||
2739 | dapm_new_mux(w); | 2950 | dapm_new_mux(w); |
2740 | break; | 2951 | break; |
2741 | case snd_soc_dapm_pga: | 2952 | case snd_soc_dapm_pga: |
@@ -2902,16 +3113,21 @@ int snd_soc_dapm_get_enum_double(struct snd_kcontrol *kcontrol, | |||
2902 | struct snd_ctl_elem_value *ucontrol) | 3113 | struct snd_ctl_elem_value *ucontrol) |
2903 | { | 3114 | { |
2904 | struct snd_soc_dapm_context *dapm = snd_soc_dapm_kcontrol_dapm(kcontrol); | 3115 | struct snd_soc_dapm_context *dapm = snd_soc_dapm_kcontrol_dapm(kcontrol); |
3116 | struct snd_soc_card *card = dapm->card; | ||
2905 | struct soc_enum *e = (struct soc_enum *)kcontrol->private_value; | 3117 | struct soc_enum *e = (struct soc_enum *)kcontrol->private_value; |
2906 | unsigned int reg_val, val; | 3118 | unsigned int reg_val, val; |
2907 | 3119 | ||
2908 | if (e->reg != SND_SOC_NOPM) { | 3120 | mutex_lock_nested(&card->dapm_mutex, SND_SOC_DAPM_CLASS_RUNTIME); |
3121 | if (e->reg != SND_SOC_NOPM && dapm_kcontrol_is_powered(kcontrol)) { | ||
2909 | int ret = soc_dapm_read(dapm, e->reg, ®_val); | 3122 | int ret = soc_dapm_read(dapm, e->reg, ®_val); |
2910 | if (ret) | 3123 | if (ret) { |
3124 | mutex_unlock(&card->dapm_mutex); | ||
2911 | return ret; | 3125 | return ret; |
3126 | } | ||
2912 | } else { | 3127 | } else { |
2913 | reg_val = dapm_kcontrol_get_value(kcontrol); | 3128 | reg_val = dapm_kcontrol_get_value(kcontrol); |
2914 | } | 3129 | } |
3130 | mutex_unlock(&card->dapm_mutex); | ||
2915 | 3131 | ||
2916 | val = (reg_val >> e->shift_l) & e->mask; | 3132 | val = (reg_val >> e->shift_l) & e->mask; |
2917 | ucontrol->value.enumerated.item[0] = snd_soc_enum_val_to_item(e, val); | 3133 | ucontrol->value.enumerated.item[0] = snd_soc_enum_val_to_item(e, val); |
@@ -2941,7 +3157,7 @@ int snd_soc_dapm_put_enum_double(struct snd_kcontrol *kcontrol, | |||
2941 | struct snd_soc_card *card = dapm->card; | 3157 | struct snd_soc_card *card = dapm->card; |
2942 | struct soc_enum *e = (struct soc_enum *)kcontrol->private_value; | 3158 | struct soc_enum *e = (struct soc_enum *)kcontrol->private_value; |
2943 | unsigned int *item = ucontrol->value.enumerated.item; | 3159 | unsigned int *item = ucontrol->value.enumerated.item; |
2944 | unsigned int val, change; | 3160 | unsigned int val, change, reg_change = 0; |
2945 | unsigned int mask; | 3161 | unsigned int mask; |
2946 | struct snd_soc_dapm_update update; | 3162 | struct snd_soc_dapm_update update; |
2947 | int ret = 0; | 3163 | int ret = 0; |
@@ -2960,19 +3176,20 @@ int snd_soc_dapm_put_enum_double(struct snd_kcontrol *kcontrol, | |||
2960 | 3176 | ||
2961 | mutex_lock_nested(&card->dapm_mutex, SND_SOC_DAPM_CLASS_RUNTIME); | 3177 | mutex_lock_nested(&card->dapm_mutex, SND_SOC_DAPM_CLASS_RUNTIME); |
2962 | 3178 | ||
3179 | change = dapm_kcontrol_set_value(kcontrol, val); | ||
3180 | |||
2963 | if (e->reg != SND_SOC_NOPM) | 3181 | if (e->reg != SND_SOC_NOPM) |
2964 | change = soc_dapm_test_bits(dapm, e->reg, mask, val); | 3182 | reg_change = soc_dapm_test_bits(dapm, e->reg, mask, val); |
2965 | else | ||
2966 | change = dapm_kcontrol_set_value(kcontrol, val); | ||
2967 | 3183 | ||
2968 | if (change) { | 3184 | if (change || reg_change) { |
2969 | if (e->reg != SND_SOC_NOPM) { | 3185 | if (reg_change) { |
2970 | update.kcontrol = kcontrol; | 3186 | update.kcontrol = kcontrol; |
2971 | update.reg = e->reg; | 3187 | update.reg = e->reg; |
2972 | update.mask = mask; | 3188 | update.mask = mask; |
2973 | update.val = val; | 3189 | update.val = val; |
2974 | card->update = &update; | 3190 | card->update = &update; |
2975 | } | 3191 | } |
3192 | change |= reg_change; | ||
2976 | 3193 | ||
2977 | ret = soc_dapm_mux_update_power(card, kcontrol, item[0], e); | 3194 | ret = soc_dapm_mux_update_power(card, kcontrol, item[0], e); |
2978 | 3195 | ||
@@ -3053,8 +3270,25 @@ int snd_soc_dapm_put_pin_switch(struct snd_kcontrol *kcontrol, | |||
3053 | } | 3270 | } |
3054 | EXPORT_SYMBOL_GPL(snd_soc_dapm_put_pin_switch); | 3271 | EXPORT_SYMBOL_GPL(snd_soc_dapm_put_pin_switch); |
3055 | 3272 | ||
3056 | static struct snd_soc_dapm_widget * | 3273 | struct snd_soc_dapm_widget * |
3057 | snd_soc_dapm_new_control(struct snd_soc_dapm_context *dapm, | 3274 | snd_soc_dapm_new_control(struct snd_soc_dapm_context *dapm, |
3275 | const struct snd_soc_dapm_widget *widget) | ||
3276 | { | ||
3277 | struct snd_soc_dapm_widget *w; | ||
3278 | |||
3279 | mutex_lock_nested(&dapm->card->dapm_mutex, SND_SOC_DAPM_CLASS_RUNTIME); | ||
3280 | w = snd_soc_dapm_new_control_unlocked(dapm, widget); | ||
3281 | if (!w) | ||
3282 | dev_err(dapm->dev, | ||
3283 | "ASoC: Failed to create DAPM control %s\n", | ||
3284 | widget->name); | ||
3285 | |||
3286 | mutex_unlock(&dapm->card->dapm_mutex); | ||
3287 | return w; | ||
3288 | } | ||
3289 | |||
3290 | struct snd_soc_dapm_widget * | ||
3291 | snd_soc_dapm_new_control_unlocked(struct snd_soc_dapm_context *dapm, | ||
3058 | const struct snd_soc_dapm_widget *widget) | 3292 | const struct snd_soc_dapm_widget *widget) |
3059 | { | 3293 | { |
3060 | struct snd_soc_dapm_widget *w; | 3294 | struct snd_soc_dapm_widget *w; |
@@ -3100,11 +3334,16 @@ snd_soc_dapm_new_control(struct snd_soc_dapm_context *dapm, | |||
3100 | } | 3334 | } |
3101 | 3335 | ||
3102 | prefix = soc_dapm_prefix(dapm); | 3336 | prefix = soc_dapm_prefix(dapm); |
3103 | if (prefix) | 3337 | if (prefix) { |
3104 | w->name = kasprintf(GFP_KERNEL, "%s %s", prefix, widget->name); | 3338 | w->name = kasprintf(GFP_KERNEL, "%s %s", prefix, widget->name); |
3105 | else | 3339 | if (widget->sname) |
3340 | w->sname = kasprintf(GFP_KERNEL, "%s %s", prefix, | ||
3341 | widget->sname); | ||
3342 | } else { | ||
3106 | w->name = kasprintf(GFP_KERNEL, "%s", widget->name); | 3343 | w->name = kasprintf(GFP_KERNEL, "%s", widget->name); |
3107 | 3344 | if (widget->sname) | |
3345 | w->sname = kasprintf(GFP_KERNEL, "%s", widget->sname); | ||
3346 | } | ||
3108 | if (w->name == NULL) { | 3347 | if (w->name == NULL) { |
3109 | kfree(w); | 3348 | kfree(w); |
3110 | return NULL; | 3349 | return NULL; |
@@ -3136,6 +3375,7 @@ snd_soc_dapm_new_control(struct snd_soc_dapm_context *dapm, | |||
3136 | w->power_check = dapm_always_on_check_power; | 3375 | w->power_check = dapm_always_on_check_power; |
3137 | break; | 3376 | break; |
3138 | case snd_soc_dapm_mux: | 3377 | case snd_soc_dapm_mux: |
3378 | case snd_soc_dapm_demux: | ||
3139 | case snd_soc_dapm_switch: | 3379 | case snd_soc_dapm_switch: |
3140 | case snd_soc_dapm_mixer: | 3380 | case snd_soc_dapm_mixer: |
3141 | case snd_soc_dapm_mixer_named_ctl: | 3381 | case snd_soc_dapm_mixer_named_ctl: |
@@ -3169,7 +3409,7 @@ snd_soc_dapm_new_control(struct snd_soc_dapm_context *dapm, | |||
3169 | INIT_LIST_HEAD(&w->sinks); | 3409 | INIT_LIST_HEAD(&w->sinks); |
3170 | INIT_LIST_HEAD(&w->list); | 3410 | INIT_LIST_HEAD(&w->list); |
3171 | INIT_LIST_HEAD(&w->dirty); | 3411 | INIT_LIST_HEAD(&w->dirty); |
3172 | list_add(&w->list, &dapm->card->widgets); | 3412 | list_add_tail(&w->list, &dapm->card->widgets); |
3173 | 3413 | ||
3174 | w->inputs = -1; | 3414 | w->inputs = -1; |
3175 | w->outputs = -1; | 3415 | w->outputs = -1; |
@@ -3199,7 +3439,7 @@ int snd_soc_dapm_new_controls(struct snd_soc_dapm_context *dapm, | |||
3199 | 3439 | ||
3200 | mutex_lock_nested(&dapm->card->dapm_mutex, SND_SOC_DAPM_CLASS_INIT); | 3440 | mutex_lock_nested(&dapm->card->dapm_mutex, SND_SOC_DAPM_CLASS_INIT); |
3201 | for (i = 0; i < num; i++) { | 3441 | for (i = 0; i < num; i++) { |
3202 | w = snd_soc_dapm_new_control(dapm, widget); | 3442 | w = snd_soc_dapm_new_control_unlocked(dapm, widget); |
3203 | if (!w) { | 3443 | if (!w) { |
3204 | dev_err(dapm->dev, | 3444 | dev_err(dapm->dev, |
3205 | "ASoC: Failed to create DAPM control %s\n", | 3445 | "ASoC: Failed to create DAPM control %s\n", |
@@ -3437,7 +3677,7 @@ int snd_soc_dapm_new_pcm(struct snd_soc_card *card, | |||
3437 | 3677 | ||
3438 | dev_dbg(card->dev, "ASoC: adding %s widget\n", link_name); | 3678 | dev_dbg(card->dev, "ASoC: adding %s widget\n", link_name); |
3439 | 3679 | ||
3440 | w = snd_soc_dapm_new_control(&card->dapm, &template); | 3680 | w = snd_soc_dapm_new_control_unlocked(&card->dapm, &template); |
3441 | if (!w) { | 3681 | if (!w) { |
3442 | dev_err(card->dev, "ASoC: Failed to create %s widget\n", | 3682 | dev_err(card->dev, "ASoC: Failed to create %s widget\n", |
3443 | link_name); | 3683 | link_name); |
@@ -3488,7 +3728,7 @@ int snd_soc_dapm_new_dai_widgets(struct snd_soc_dapm_context *dapm, | |||
3488 | dev_dbg(dai->dev, "ASoC: adding %s widget\n", | 3728 | dev_dbg(dai->dev, "ASoC: adding %s widget\n", |
3489 | template.name); | 3729 | template.name); |
3490 | 3730 | ||
3491 | w = snd_soc_dapm_new_control(dapm, &template); | 3731 | w = snd_soc_dapm_new_control_unlocked(dapm, &template); |
3492 | if (!w) { | 3732 | if (!w) { |
3493 | dev_err(dapm->dev, "ASoC: Failed to create %s widget\n", | 3733 | dev_err(dapm->dev, "ASoC: Failed to create %s widget\n", |
3494 | dai->driver->playback.stream_name); | 3734 | dai->driver->playback.stream_name); |
@@ -3507,7 +3747,7 @@ int snd_soc_dapm_new_dai_widgets(struct snd_soc_dapm_context *dapm, | |||
3507 | dev_dbg(dai->dev, "ASoC: adding %s widget\n", | 3747 | dev_dbg(dai->dev, "ASoC: adding %s widget\n", |
3508 | template.name); | 3748 | template.name); |
3509 | 3749 | ||
3510 | w = snd_soc_dapm_new_control(dapm, &template); | 3750 | w = snd_soc_dapm_new_control_unlocked(dapm, &template); |
3511 | if (!w) { | 3751 | if (!w) { |
3512 | dev_err(dapm->dev, "ASoC: Failed to create %s widget\n", | 3752 | dev_err(dapm->dev, "ASoC: Failed to create %s widget\n", |
3513 | dai->driver->capture.stream_name); | 3753 | dai->driver->capture.stream_name); |
diff --git a/sound/soc/soc-generic-dmaengine-pcm.c b/sound/soc/soc-generic-dmaengine-pcm.c index c9917ca5de1a..6fd1906af387 100644 --- a/sound/soc/soc-generic-dmaengine-pcm.c +++ b/sound/soc/soc-generic-dmaengine-pcm.c | |||
@@ -24,6 +24,12 @@ | |||
24 | 24 | ||
25 | #include <sound/dmaengine_pcm.h> | 25 | #include <sound/dmaengine_pcm.h> |
26 | 26 | ||
27 | /* | ||
28 | * The platforms dmaengine driver does not support reporting the amount of | ||
29 | * bytes that are still left to transfer. | ||
30 | */ | ||
31 | #define SND_DMAENGINE_PCM_FLAG_NO_RESIDUE BIT(31) | ||
32 | |||
27 | struct dmaengine_pcm { | 33 | struct dmaengine_pcm { |
28 | struct dma_chan *chan[SNDRV_PCM_STREAM_LAST + 1]; | 34 | struct dma_chan *chan[SNDRV_PCM_STREAM_LAST + 1]; |
29 | const struct snd_dmaengine_pcm_config *config; | 35 | const struct snd_dmaengine_pcm_config *config; |
@@ -222,14 +228,18 @@ static struct dma_chan *dmaengine_pcm_compat_request_channel( | |||
222 | return snd_dmaengine_pcm_request_channel(fn, dma_data->filter_data); | 228 | return snd_dmaengine_pcm_request_channel(fn, dma_data->filter_data); |
223 | } | 229 | } |
224 | 230 | ||
225 | static bool dmaengine_pcm_can_report_residue(struct dma_chan *chan) | 231 | static bool dmaengine_pcm_can_report_residue(struct device *dev, |
232 | struct dma_chan *chan) | ||
226 | { | 233 | { |
227 | struct dma_slave_caps dma_caps; | 234 | struct dma_slave_caps dma_caps; |
228 | int ret; | 235 | int ret; |
229 | 236 | ||
230 | ret = dma_get_slave_caps(chan, &dma_caps); | 237 | ret = dma_get_slave_caps(chan, &dma_caps); |
231 | if (ret != 0) | 238 | if (ret != 0) { |
232 | return true; | 239 | dev_warn(dev, "Failed to get DMA channel capabilities, falling back to period counting: %d\n", |
240 | ret); | ||
241 | return false; | ||
242 | } | ||
233 | 243 | ||
234 | if (dma_caps.residue_granularity == DMA_RESIDUE_GRANULARITY_DESCRIPTOR) | 244 | if (dma_caps.residue_granularity == DMA_RESIDUE_GRANULARITY_DESCRIPTOR) |
235 | return false; | 245 | return false; |
@@ -289,14 +299,7 @@ static int dmaengine_pcm_new(struct snd_soc_pcm_runtime *rtd) | |||
289 | if (ret) | 299 | if (ret) |
290 | return ret; | 300 | return ret; |
291 | 301 | ||
292 | /* | 302 | if (!dmaengine_pcm_can_report_residue(dev, pcm->chan[i])) |
293 | * This will only return false if we know for sure that at least | ||
294 | * one channel does not support residue reporting. If the DMA | ||
295 | * driver does not implement the slave_caps API we rely having | ||
296 | * the NO_RESIDUE flag set manually in case residue reporting is | ||
297 | * not supported. | ||
298 | */ | ||
299 | if (!dmaengine_pcm_can_report_residue(pcm->chan[i])) | ||
300 | pcm->flags |= SND_DMAENGINE_PCM_FLAG_NO_RESIDUE; | 303 | pcm->flags |= SND_DMAENGINE_PCM_FLAG_NO_RESIDUE; |
301 | } | 304 | } |
302 | 305 | ||
diff --git a/sound/soc/soc-jack.c b/sound/soc/soc-jack.c index 9f60c25c4568..171c4291ea21 100644 --- a/sound/soc/soc-jack.c +++ b/sound/soc/soc-jack.c | |||
@@ -315,8 +315,11 @@ int snd_soc_jack_add_gpios(struct snd_soc_jack *jack, int count, | |||
315 | goto undo; | 315 | goto undo; |
316 | } | 316 | } |
317 | 317 | ||
318 | if (gpios[i].gpiod_dev) { | 318 | if (gpios[i].desc) { |
319 | /* GPIO descriptor */ | 319 | /* Already have a GPIO descriptor. */ |
320 | goto got_gpio; | ||
321 | } else if (gpios[i].gpiod_dev) { | ||
322 | /* Get a GPIO descriptor */ | ||
320 | gpios[i].desc = gpiod_get_index(gpios[i].gpiod_dev, | 323 | gpios[i].desc = gpiod_get_index(gpios[i].gpiod_dev, |
321 | gpios[i].name, | 324 | gpios[i].name, |
322 | gpios[i].idx, GPIOD_IN); | 325 | gpios[i].idx, GPIOD_IN); |
@@ -344,7 +347,7 @@ int snd_soc_jack_add_gpios(struct snd_soc_jack *jack, int count, | |||
344 | 347 | ||
345 | gpios[i].desc = gpio_to_desc(gpios[i].gpio); | 348 | gpios[i].desc = gpio_to_desc(gpios[i].gpio); |
346 | } | 349 | } |
347 | 350 | got_gpio: | |
348 | INIT_DELAYED_WORK(&gpios[i].work, gpio_work); | 351 | INIT_DELAYED_WORK(&gpios[i].work, gpio_work); |
349 | gpios[i].jack = jack; | 352 | gpios[i].jack = jack; |
350 | 353 | ||
diff --git a/sound/soc/soc-pcm.c b/sound/soc/soc-pcm.c index 35fe58f4fa86..256b9c91aa94 100644 --- a/sound/soc/soc-pcm.c +++ b/sound/soc/soc-pcm.c | |||
@@ -1485,30 +1485,67 @@ unwind: | |||
1485 | } | 1485 | } |
1486 | 1486 | ||
1487 | static void dpcm_init_runtime_hw(struct snd_pcm_runtime *runtime, | 1487 | static void dpcm_init_runtime_hw(struct snd_pcm_runtime *runtime, |
1488 | struct snd_soc_pcm_stream *stream) | 1488 | struct snd_soc_pcm_stream *stream, |
1489 | u64 formats) | ||
1489 | { | 1490 | { |
1490 | runtime->hw.rate_min = stream->rate_min; | 1491 | runtime->hw.rate_min = stream->rate_min; |
1491 | runtime->hw.rate_max = stream->rate_max; | 1492 | runtime->hw.rate_max = stream->rate_max; |
1492 | runtime->hw.channels_min = stream->channels_min; | 1493 | runtime->hw.channels_min = stream->channels_min; |
1493 | runtime->hw.channels_max = stream->channels_max; | 1494 | runtime->hw.channels_max = stream->channels_max; |
1494 | if (runtime->hw.formats) | 1495 | if (runtime->hw.formats) |
1495 | runtime->hw.formats &= stream->formats; | 1496 | runtime->hw.formats &= formats & stream->formats; |
1496 | else | 1497 | else |
1497 | runtime->hw.formats = stream->formats; | 1498 | runtime->hw.formats = formats & stream->formats; |
1498 | runtime->hw.rates = stream->rates; | 1499 | runtime->hw.rates = stream->rates; |
1499 | } | 1500 | } |
1500 | 1501 | ||
1502 | static u64 dpcm_runtime_base_format(struct snd_pcm_substream *substream) | ||
1503 | { | ||
1504 | struct snd_soc_pcm_runtime *fe = substream->private_data; | ||
1505 | struct snd_soc_dpcm *dpcm; | ||
1506 | u64 formats = ULLONG_MAX; | ||
1507 | int stream = substream->stream; | ||
1508 | |||
1509 | if (!fe->dai_link->dpcm_merged_format) | ||
1510 | return formats; | ||
1511 | |||
1512 | /* | ||
1513 | * It returns merged BE codec format | ||
1514 | * if FE want to use it (= dpcm_merged_format) | ||
1515 | */ | ||
1516 | |||
1517 | list_for_each_entry(dpcm, &fe->dpcm[stream].be_clients, list_be) { | ||
1518 | struct snd_soc_pcm_runtime *be = dpcm->be; | ||
1519 | struct snd_soc_dai_driver *codec_dai_drv; | ||
1520 | struct snd_soc_pcm_stream *codec_stream; | ||
1521 | int i; | ||
1522 | |||
1523 | for (i = 0; i < be->num_codecs; i++) { | ||
1524 | codec_dai_drv = be->codec_dais[i]->driver; | ||
1525 | if (stream == SNDRV_PCM_STREAM_PLAYBACK) | ||
1526 | codec_stream = &codec_dai_drv->playback; | ||
1527 | else | ||
1528 | codec_stream = &codec_dai_drv->capture; | ||
1529 | |||
1530 | formats &= codec_stream->formats; | ||
1531 | } | ||
1532 | } | ||
1533 | |||
1534 | return formats; | ||
1535 | } | ||
1536 | |||
1501 | static void dpcm_set_fe_runtime(struct snd_pcm_substream *substream) | 1537 | static void dpcm_set_fe_runtime(struct snd_pcm_substream *substream) |
1502 | { | 1538 | { |
1503 | struct snd_pcm_runtime *runtime = substream->runtime; | 1539 | struct snd_pcm_runtime *runtime = substream->runtime; |
1504 | struct snd_soc_pcm_runtime *rtd = substream->private_data; | 1540 | struct snd_soc_pcm_runtime *rtd = substream->private_data; |
1505 | struct snd_soc_dai *cpu_dai = rtd->cpu_dai; | 1541 | struct snd_soc_dai *cpu_dai = rtd->cpu_dai; |
1506 | struct snd_soc_dai_driver *cpu_dai_drv = cpu_dai->driver; | 1542 | struct snd_soc_dai_driver *cpu_dai_drv = cpu_dai->driver; |
1543 | u64 format = dpcm_runtime_base_format(substream); | ||
1507 | 1544 | ||
1508 | if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) | 1545 | if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) |
1509 | dpcm_init_runtime_hw(runtime, &cpu_dai_drv->playback); | 1546 | dpcm_init_runtime_hw(runtime, &cpu_dai_drv->playback, format); |
1510 | else | 1547 | else |
1511 | dpcm_init_runtime_hw(runtime, &cpu_dai_drv->capture); | 1548 | dpcm_init_runtime_hw(runtime, &cpu_dai_drv->capture, format); |
1512 | } | 1549 | } |
1513 | 1550 | ||
1514 | static int dpcm_fe_dai_do_trigger(struct snd_pcm_substream *substream, int cmd); | 1551 | static int dpcm_fe_dai_do_trigger(struct snd_pcm_substream *substream, int cmd); |
diff --git a/sound/soc/soc-topology.c b/sound/soc/soc-topology.c new file mode 100644 index 000000000000..d0960683c409 --- /dev/null +++ b/sound/soc/soc-topology.c | |||
@@ -0,0 +1,1826 @@ | |||
1 | /* | ||
2 | * soc-topology.c -- ALSA SoC Topology | ||
3 | * | ||
4 | * Copyright (C) 2012 Texas Instruments Inc. | ||
5 | * Copyright (C) 2015 Intel Corporation. | ||
6 | * | ||
7 | * Authors: Liam Girdwood <liam.r.girdwood@linux.intel.com> | ||
8 | * K, Mythri P <mythri.p.k@intel.com> | ||
9 | * Prusty, Subhransu S <subhransu.s.prusty@intel.com> | ||
10 | * B, Jayachandran <jayachandran.b@intel.com> | ||
11 | * Abdullah, Omair M <omair.m.abdullah@intel.com> | ||
12 | * Jin, Yao <yao.jin@intel.com> | ||
13 | * Lin, Mengdong <mengdong.lin@intel.com> | ||
14 | * | ||
15 | * This program is free software; you can redistribute it and/or modify it | ||
16 | * under the terms of the GNU General Public License as published by the | ||
17 | * Free Software Foundation; either version 2 of the License, or (at your | ||
18 | * option) any later version. | ||
19 | * | ||
20 | * Add support to read audio firmware topology alongside firmware text. The | ||
21 | * topology data can contain kcontrols, DAPM graphs, widgets, DAIs, DAI links, | ||
22 | * equalizers, firmware, coefficients etc. | ||
23 | * | ||
24 | * This file only manages the core ALSA and ASoC components, all other bespoke | ||
25 | * firmware topology data is passed to component drivers for bespoke handling. | ||
26 | */ | ||
27 | |||
28 | #include <linux/kernel.h> | ||
29 | #include <linux/export.h> | ||
30 | #include <linux/list.h> | ||
31 | #include <linux/firmware.h> | ||
32 | #include <linux/slab.h> | ||
33 | #include <sound/soc.h> | ||
34 | #include <sound/soc-dapm.h> | ||
35 | #include <sound/soc-topology.h> | ||
36 | |||
37 | /* | ||
38 | * We make several passes over the data (since it wont necessarily be ordered) | ||
39 | * and process objects in the following order. This guarantees the component | ||
40 | * drivers will be ready with any vendor data before the mixers and DAPM objects | ||
41 | * are loaded (that may make use of the vendor data). | ||
42 | */ | ||
43 | #define SOC_TPLG_PASS_MANIFEST 0 | ||
44 | #define SOC_TPLG_PASS_VENDOR 1 | ||
45 | #define SOC_TPLG_PASS_MIXER 2 | ||
46 | #define SOC_TPLG_PASS_WIDGET 3 | ||
47 | #define SOC_TPLG_PASS_GRAPH 4 | ||
48 | #define SOC_TPLG_PASS_PINS 5 | ||
49 | #define SOC_TPLG_PASS_PCM_DAI 6 | ||
50 | |||
51 | #define SOC_TPLG_PASS_START SOC_TPLG_PASS_MANIFEST | ||
52 | #define SOC_TPLG_PASS_END SOC_TPLG_PASS_PCM_DAI | ||
53 | |||
54 | struct soc_tplg { | ||
55 | const struct firmware *fw; | ||
56 | |||
57 | /* runtime FW parsing */ | ||
58 | const u8 *pos; /* read postion */ | ||
59 | const u8 *hdr_pos; /* header position */ | ||
60 | unsigned int pass; /* pass number */ | ||
61 | |||
62 | /* component caller */ | ||
63 | struct device *dev; | ||
64 | struct snd_soc_component *comp; | ||
65 | u32 index; /* current block index */ | ||
66 | u32 req_index; /* required index, only loaded/free matching blocks */ | ||
67 | |||
68 | /* kcontrol operations */ | ||
69 | const struct snd_soc_tplg_kcontrol_ops *io_ops; | ||
70 | int io_ops_count; | ||
71 | |||
72 | /* optional fw loading callbacks to component drivers */ | ||
73 | struct snd_soc_tplg_ops *ops; | ||
74 | }; | ||
75 | |||
76 | static int soc_tplg_process_headers(struct soc_tplg *tplg); | ||
77 | static void soc_tplg_complete(struct soc_tplg *tplg); | ||
78 | struct snd_soc_dapm_widget * | ||
79 | snd_soc_dapm_new_control_unlocked(struct snd_soc_dapm_context *dapm, | ||
80 | const struct snd_soc_dapm_widget *widget); | ||
81 | struct snd_soc_dapm_widget * | ||
82 | snd_soc_dapm_new_control(struct snd_soc_dapm_context *dapm, | ||
83 | const struct snd_soc_dapm_widget *widget); | ||
84 | |||
85 | /* check we dont overflow the data for this control chunk */ | ||
86 | static int soc_tplg_check_elem_count(struct soc_tplg *tplg, size_t elem_size, | ||
87 | unsigned int count, size_t bytes, const char *elem_type) | ||
88 | { | ||
89 | const u8 *end = tplg->pos + elem_size * count; | ||
90 | |||
91 | if (end > tplg->fw->data + tplg->fw->size) { | ||
92 | dev_err(tplg->dev, "ASoC: %s overflow end of data\n", | ||
93 | elem_type); | ||
94 | return -EINVAL; | ||
95 | } | ||
96 | |||
97 | /* check there is enough room in chunk for control. | ||
98 | extra bytes at the end of control are for vendor data here */ | ||
99 | if (elem_size * count > bytes) { | ||
100 | dev_err(tplg->dev, | ||
101 | "ASoC: %s count %d of size %zu is bigger than chunk %zu\n", | ||
102 | elem_type, count, elem_size, bytes); | ||
103 | return -EINVAL; | ||
104 | } | ||
105 | |||
106 | return 0; | ||
107 | } | ||
108 | |||
109 | static inline int soc_tplg_is_eof(struct soc_tplg *tplg) | ||
110 | { | ||
111 | const u8 *end = tplg->hdr_pos; | ||
112 | |||
113 | if (end >= tplg->fw->data + tplg->fw->size) | ||
114 | return 1; | ||
115 | return 0; | ||
116 | } | ||
117 | |||
118 | static inline unsigned long soc_tplg_get_hdr_offset(struct soc_tplg *tplg) | ||
119 | { | ||
120 | return (unsigned long)(tplg->hdr_pos - tplg->fw->data); | ||
121 | } | ||
122 | |||
123 | static inline unsigned long soc_tplg_get_offset(struct soc_tplg *tplg) | ||
124 | { | ||
125 | return (unsigned long)(tplg->pos - tplg->fw->data); | ||
126 | } | ||
127 | |||
128 | /* mapping of Kcontrol types and associated operations. */ | ||
129 | static const struct snd_soc_tplg_kcontrol_ops io_ops[] = { | ||
130 | {SND_SOC_TPLG_CTL_VOLSW, snd_soc_get_volsw, | ||
131 | snd_soc_put_volsw, snd_soc_info_volsw}, | ||
132 | {SND_SOC_TPLG_CTL_VOLSW_SX, snd_soc_get_volsw_sx, | ||
133 | snd_soc_put_volsw_sx, NULL}, | ||
134 | {SND_SOC_TPLG_CTL_ENUM, snd_soc_get_enum_double, | ||
135 | snd_soc_put_enum_double, snd_soc_info_enum_double}, | ||
136 | {SND_SOC_TPLG_CTL_ENUM_VALUE, snd_soc_get_enum_double, | ||
137 | snd_soc_put_enum_double, NULL}, | ||
138 | {SND_SOC_TPLG_CTL_BYTES, snd_soc_bytes_get, | ||
139 | snd_soc_bytes_put, snd_soc_bytes_info}, | ||
140 | {SND_SOC_TPLG_CTL_RANGE, snd_soc_get_volsw_range, | ||
141 | snd_soc_put_volsw_range, snd_soc_info_volsw_range}, | ||
142 | {SND_SOC_TPLG_CTL_VOLSW_XR_SX, snd_soc_get_xr_sx, | ||
143 | snd_soc_put_xr_sx, snd_soc_info_xr_sx}, | ||
144 | {SND_SOC_TPLG_CTL_STROBE, snd_soc_get_strobe, | ||
145 | snd_soc_put_strobe, NULL}, | ||
146 | {SND_SOC_TPLG_DAPM_CTL_VOLSW, snd_soc_dapm_get_volsw, | ||
147 | snd_soc_dapm_put_volsw, NULL}, | ||
148 | {SND_SOC_TPLG_DAPM_CTL_ENUM_DOUBLE, snd_soc_dapm_get_enum_double, | ||
149 | snd_soc_dapm_put_enum_double, snd_soc_info_enum_double}, | ||
150 | {SND_SOC_TPLG_DAPM_CTL_ENUM_VIRT, snd_soc_dapm_get_enum_double, | ||
151 | snd_soc_dapm_put_enum_double, NULL}, | ||
152 | {SND_SOC_TPLG_DAPM_CTL_ENUM_VALUE, snd_soc_dapm_get_enum_double, | ||
153 | snd_soc_dapm_put_enum_double, NULL}, | ||
154 | {SND_SOC_TPLG_DAPM_CTL_PIN, snd_soc_dapm_get_pin_switch, | ||
155 | snd_soc_dapm_put_pin_switch, snd_soc_dapm_info_pin_switch}, | ||
156 | }; | ||
157 | |||
158 | struct soc_tplg_map { | ||
159 | int uid; | ||
160 | int kid; | ||
161 | }; | ||
162 | |||
163 | /* mapping of widget types from UAPI IDs to kernel IDs */ | ||
164 | static const struct soc_tplg_map dapm_map[] = { | ||
165 | {SND_SOC_TPLG_DAPM_INPUT, snd_soc_dapm_input}, | ||
166 | {SND_SOC_TPLG_DAPM_OUTPUT, snd_soc_dapm_output}, | ||
167 | {SND_SOC_TPLG_DAPM_MUX, snd_soc_dapm_mux}, | ||
168 | {SND_SOC_TPLG_DAPM_MIXER, snd_soc_dapm_mixer}, | ||
169 | {SND_SOC_TPLG_DAPM_PGA, snd_soc_dapm_pga}, | ||
170 | {SND_SOC_TPLG_DAPM_OUT_DRV, snd_soc_dapm_out_drv}, | ||
171 | {SND_SOC_TPLG_DAPM_ADC, snd_soc_dapm_adc}, | ||
172 | {SND_SOC_TPLG_DAPM_DAC, snd_soc_dapm_dac}, | ||
173 | {SND_SOC_TPLG_DAPM_SWITCH, snd_soc_dapm_switch}, | ||
174 | {SND_SOC_TPLG_DAPM_PRE, snd_soc_dapm_pre}, | ||
175 | {SND_SOC_TPLG_DAPM_POST, snd_soc_dapm_post}, | ||
176 | {SND_SOC_TPLG_DAPM_AIF_IN, snd_soc_dapm_aif_in}, | ||
177 | {SND_SOC_TPLG_DAPM_AIF_OUT, snd_soc_dapm_aif_out}, | ||
178 | {SND_SOC_TPLG_DAPM_DAI_IN, snd_soc_dapm_dai_in}, | ||
179 | {SND_SOC_TPLG_DAPM_DAI_OUT, snd_soc_dapm_dai_out}, | ||
180 | {SND_SOC_TPLG_DAPM_DAI_LINK, snd_soc_dapm_dai_link}, | ||
181 | }; | ||
182 | |||
183 | static int tplc_chan_get_reg(struct soc_tplg *tplg, | ||
184 | struct snd_soc_tplg_channel *chan, int map) | ||
185 | { | ||
186 | int i; | ||
187 | |||
188 | for (i = 0; i < SND_SOC_TPLG_MAX_CHAN; i++) { | ||
189 | if (chan[i].id == map) | ||
190 | return chan[i].reg; | ||
191 | } | ||
192 | |||
193 | return -EINVAL; | ||
194 | } | ||
195 | |||
196 | static int tplc_chan_get_shift(struct soc_tplg *tplg, | ||
197 | struct snd_soc_tplg_channel *chan, int map) | ||
198 | { | ||
199 | int i; | ||
200 | |||
201 | for (i = 0; i < SND_SOC_TPLG_MAX_CHAN; i++) { | ||
202 | if (chan[i].id == map) | ||
203 | return chan[i].shift; | ||
204 | } | ||
205 | |||
206 | return -EINVAL; | ||
207 | } | ||
208 | |||
209 | static int get_widget_id(int tplg_type) | ||
210 | { | ||
211 | int i; | ||
212 | |||
213 | for (i = 0; i < ARRAY_SIZE(dapm_map); i++) { | ||
214 | if (tplg_type == dapm_map[i].uid) | ||
215 | return dapm_map[i].kid; | ||
216 | } | ||
217 | |||
218 | return -EINVAL; | ||
219 | } | ||
220 | |||
221 | static enum snd_soc_dobj_type get_dobj_mixer_type( | ||
222 | struct snd_soc_tplg_ctl_hdr *control_hdr) | ||
223 | { | ||
224 | if (control_hdr == NULL) | ||
225 | return SND_SOC_DOBJ_NONE; | ||
226 | |||
227 | switch (control_hdr->ops.info) { | ||
228 | case SND_SOC_TPLG_CTL_VOLSW: | ||
229 | case SND_SOC_TPLG_CTL_VOLSW_SX: | ||
230 | case SND_SOC_TPLG_CTL_VOLSW_XR_SX: | ||
231 | case SND_SOC_TPLG_CTL_RANGE: | ||
232 | case SND_SOC_TPLG_CTL_STROBE: | ||
233 | return SND_SOC_DOBJ_MIXER; | ||
234 | case SND_SOC_TPLG_CTL_ENUM: | ||
235 | case SND_SOC_TPLG_CTL_ENUM_VALUE: | ||
236 | return SND_SOC_DOBJ_ENUM; | ||
237 | case SND_SOC_TPLG_CTL_BYTES: | ||
238 | return SND_SOC_DOBJ_BYTES; | ||
239 | default: | ||
240 | return SND_SOC_DOBJ_NONE; | ||
241 | } | ||
242 | } | ||
243 | |||
244 | static enum snd_soc_dobj_type get_dobj_type(struct snd_soc_tplg_hdr *hdr, | ||
245 | struct snd_soc_tplg_ctl_hdr *control_hdr) | ||
246 | { | ||
247 | switch (hdr->type) { | ||
248 | case SND_SOC_TPLG_TYPE_MIXER: | ||
249 | return get_dobj_mixer_type(control_hdr); | ||
250 | case SND_SOC_TPLG_TYPE_DAPM_GRAPH: | ||
251 | case SND_SOC_TPLG_TYPE_MANIFEST: | ||
252 | return SND_SOC_DOBJ_NONE; | ||
253 | case SND_SOC_TPLG_TYPE_DAPM_WIDGET: | ||
254 | return SND_SOC_DOBJ_WIDGET; | ||
255 | case SND_SOC_TPLG_TYPE_DAI_LINK: | ||
256 | return SND_SOC_DOBJ_DAI_LINK; | ||
257 | case SND_SOC_TPLG_TYPE_PCM: | ||
258 | return SND_SOC_DOBJ_PCM; | ||
259 | case SND_SOC_TPLG_TYPE_CODEC_LINK: | ||
260 | return SND_SOC_DOBJ_CODEC_LINK; | ||
261 | default: | ||
262 | return SND_SOC_DOBJ_NONE; | ||
263 | } | ||
264 | } | ||
265 | |||
266 | static inline void soc_bind_err(struct soc_tplg *tplg, | ||
267 | struct snd_soc_tplg_ctl_hdr *hdr, int index) | ||
268 | { | ||
269 | dev_err(tplg->dev, | ||
270 | "ASoC: invalid control type (g,p,i) %d:%d:%d index %d at 0x%lx\n", | ||
271 | hdr->ops.get, hdr->ops.put, hdr->ops.info, index, | ||
272 | soc_tplg_get_offset(tplg)); | ||
273 | } | ||
274 | |||
275 | static inline void soc_control_err(struct soc_tplg *tplg, | ||
276 | struct snd_soc_tplg_ctl_hdr *hdr, const char *name) | ||
277 | { | ||
278 | dev_err(tplg->dev, | ||
279 | "ASoC: no complete mixer IO handler for %s type (g,p,i) %d:%d:%d at 0x%lx\n", | ||
280 | name, hdr->ops.get, hdr->ops.put, hdr->ops.info, | ||
281 | soc_tplg_get_offset(tplg)); | ||
282 | } | ||
283 | |||
284 | /* pass vendor data to component driver for processing */ | ||
285 | static int soc_tplg_vendor_load_(struct soc_tplg *tplg, | ||
286 | struct snd_soc_tplg_hdr *hdr) | ||
287 | { | ||
288 | int ret = 0; | ||
289 | |||
290 | if (tplg->comp && tplg->ops && tplg->ops->vendor_load) | ||
291 | ret = tplg->ops->vendor_load(tplg->comp, hdr); | ||
292 | else { | ||
293 | dev_err(tplg->dev, "ASoC: no vendor load callback for ID %d\n", | ||
294 | hdr->vendor_type); | ||
295 | return -EINVAL; | ||
296 | } | ||
297 | |||
298 | if (ret < 0) | ||
299 | dev_err(tplg->dev, | ||
300 | "ASoC: vendor load failed at hdr offset %ld/0x%lx for type %d:%d\n", | ||
301 | soc_tplg_get_hdr_offset(tplg), | ||
302 | soc_tplg_get_hdr_offset(tplg), | ||
303 | hdr->type, hdr->vendor_type); | ||
304 | return ret; | ||
305 | } | ||
306 | |||
307 | /* pass vendor data to component driver for processing */ | ||
308 | static int soc_tplg_vendor_load(struct soc_tplg *tplg, | ||
309 | struct snd_soc_tplg_hdr *hdr) | ||
310 | { | ||
311 | if (tplg->pass != SOC_TPLG_PASS_VENDOR) | ||
312 | return 0; | ||
313 | |||
314 | return soc_tplg_vendor_load_(tplg, hdr); | ||
315 | } | ||
316 | |||
317 | /* optionally pass new dynamic widget to component driver. This is mainly for | ||
318 | * external widgets where we can assign private data/ops */ | ||
319 | static int soc_tplg_widget_load(struct soc_tplg *tplg, | ||
320 | struct snd_soc_dapm_widget *w, struct snd_soc_tplg_dapm_widget *tplg_w) | ||
321 | { | ||
322 | if (tplg->comp && tplg->ops && tplg->ops->widget_load) | ||
323 | return tplg->ops->widget_load(tplg->comp, w, tplg_w); | ||
324 | |||
325 | return 0; | ||
326 | } | ||
327 | |||
328 | /* pass dynamic FEs configurations to component driver */ | ||
329 | static int soc_tplg_pcm_dai_load(struct soc_tplg *tplg, | ||
330 | struct snd_soc_tplg_pcm_dai *pcm_dai, int num_pcm_dai) | ||
331 | { | ||
332 | if (tplg->comp && tplg->ops && tplg->ops->pcm_dai_load) | ||
333 | return tplg->ops->pcm_dai_load(tplg->comp, pcm_dai, num_pcm_dai); | ||
334 | |||
335 | return 0; | ||
336 | } | ||
337 | |||
338 | /* tell the component driver that all firmware has been loaded in this request */ | ||
339 | static void soc_tplg_complete(struct soc_tplg *tplg) | ||
340 | { | ||
341 | if (tplg->comp && tplg->ops && tplg->ops->complete) | ||
342 | tplg->ops->complete(tplg->comp); | ||
343 | } | ||
344 | |||
345 | /* add a dynamic kcontrol */ | ||
346 | static int soc_tplg_add_dcontrol(struct snd_card *card, struct device *dev, | ||
347 | const struct snd_kcontrol_new *control_new, const char *prefix, | ||
348 | void *data, struct snd_kcontrol **kcontrol) | ||
349 | { | ||
350 | int err; | ||
351 | |||
352 | *kcontrol = snd_soc_cnew(control_new, data, control_new->name, prefix); | ||
353 | if (*kcontrol == NULL) { | ||
354 | dev_err(dev, "ASoC: Failed to create new kcontrol %s\n", | ||
355 | control_new->name); | ||
356 | return -ENOMEM; | ||
357 | } | ||
358 | |||
359 | err = snd_ctl_add(card, *kcontrol); | ||
360 | if (err < 0) { | ||
361 | dev_err(dev, "ASoC: Failed to add %s: %d\n", | ||
362 | control_new->name, err); | ||
363 | return err; | ||
364 | } | ||
365 | |||
366 | return 0; | ||
367 | } | ||
368 | |||
369 | /* add a dynamic kcontrol for component driver */ | ||
370 | static int soc_tplg_add_kcontrol(struct soc_tplg *tplg, | ||
371 | struct snd_kcontrol_new *k, struct snd_kcontrol **kcontrol) | ||
372 | { | ||
373 | struct snd_soc_component *comp = tplg->comp; | ||
374 | |||
375 | return soc_tplg_add_dcontrol(comp->card->snd_card, | ||
376 | comp->dev, k, NULL, comp, kcontrol); | ||
377 | } | ||
378 | |||
379 | /* remove a mixer kcontrol */ | ||
380 | static void remove_mixer(struct snd_soc_component *comp, | ||
381 | struct snd_soc_dobj *dobj, int pass) | ||
382 | { | ||
383 | struct snd_card *card = comp->card->snd_card; | ||
384 | struct soc_mixer_control *sm = | ||
385 | container_of(dobj, struct soc_mixer_control, dobj); | ||
386 | const unsigned int *p = NULL; | ||
387 | |||
388 | if (pass != SOC_TPLG_PASS_MIXER) | ||
389 | return; | ||
390 | |||
391 | if (dobj->ops && dobj->ops->control_unload) | ||
392 | dobj->ops->control_unload(comp, dobj); | ||
393 | |||
394 | if (sm->dobj.control.kcontrol->tlv.p) | ||
395 | p = sm->dobj.control.kcontrol->tlv.p; | ||
396 | snd_ctl_remove(card, sm->dobj.control.kcontrol); | ||
397 | list_del(&sm->dobj.list); | ||
398 | kfree(sm); | ||
399 | kfree(p); | ||
400 | } | ||
401 | |||
402 | /* remove an enum kcontrol */ | ||
403 | static void remove_enum(struct snd_soc_component *comp, | ||
404 | struct snd_soc_dobj *dobj, int pass) | ||
405 | { | ||
406 | struct snd_card *card = comp->card->snd_card; | ||
407 | struct soc_enum *se = container_of(dobj, struct soc_enum, dobj); | ||
408 | int i; | ||
409 | |||
410 | if (pass != SOC_TPLG_PASS_MIXER) | ||
411 | return; | ||
412 | |||
413 | if (dobj->ops && dobj->ops->control_unload) | ||
414 | dobj->ops->control_unload(comp, dobj); | ||
415 | |||
416 | snd_ctl_remove(card, se->dobj.control.kcontrol); | ||
417 | list_del(&se->dobj.list); | ||
418 | |||
419 | kfree(se->dobj.control.dvalues); | ||
420 | for (i = 0; i < se->items; i++) | ||
421 | kfree(se->dobj.control.dtexts[i]); | ||
422 | kfree(se); | ||
423 | } | ||
424 | |||
425 | /* remove a byte kcontrol */ | ||
426 | static void remove_bytes(struct snd_soc_component *comp, | ||
427 | struct snd_soc_dobj *dobj, int pass) | ||
428 | { | ||
429 | struct snd_card *card = comp->card->snd_card; | ||
430 | struct soc_bytes_ext *sb = | ||
431 | container_of(dobj, struct soc_bytes_ext, dobj); | ||
432 | |||
433 | if (pass != SOC_TPLG_PASS_MIXER) | ||
434 | return; | ||
435 | |||
436 | if (dobj->ops && dobj->ops->control_unload) | ||
437 | dobj->ops->control_unload(comp, dobj); | ||
438 | |||
439 | snd_ctl_remove(card, sb->dobj.control.kcontrol); | ||
440 | list_del(&sb->dobj.list); | ||
441 | kfree(sb); | ||
442 | } | ||
443 | |||
444 | /* remove a widget and it's kcontrols - routes must be removed first */ | ||
445 | static void remove_widget(struct snd_soc_component *comp, | ||
446 | struct snd_soc_dobj *dobj, int pass) | ||
447 | { | ||
448 | struct snd_card *card = comp->card->snd_card; | ||
449 | struct snd_soc_dapm_widget *w = | ||
450 | container_of(dobj, struct snd_soc_dapm_widget, dobj); | ||
451 | int i; | ||
452 | |||
453 | if (pass != SOC_TPLG_PASS_WIDGET) | ||
454 | return; | ||
455 | |||
456 | if (dobj->ops && dobj->ops->widget_unload) | ||
457 | dobj->ops->widget_unload(comp, dobj); | ||
458 | |||
459 | /* | ||
460 | * Dynamic Widgets either have 1 enum kcontrol or 1..N mixers. | ||
461 | * The enum may either have an array of values or strings. | ||
462 | */ | ||
463 | if (dobj->widget.kcontrol_enum) { | ||
464 | /* enumerated widget mixer */ | ||
465 | struct soc_enum *se = | ||
466 | (struct soc_enum *)w->kcontrols[0]->private_value; | ||
467 | |||
468 | snd_ctl_remove(card, w->kcontrols[0]); | ||
469 | |||
470 | kfree(se->dobj.control.dvalues); | ||
471 | for (i = 0; i < se->items; i++) | ||
472 | kfree(se->dobj.control.dtexts[i]); | ||
473 | |||
474 | kfree(se); | ||
475 | kfree(w->kcontrol_news); | ||
476 | } else { | ||
477 | /* non enumerated widget mixer */ | ||
478 | for (i = 0; i < w->num_kcontrols; i++) { | ||
479 | struct snd_kcontrol *kcontrol = w->kcontrols[i]; | ||
480 | struct soc_mixer_control *sm = | ||
481 | (struct soc_mixer_control *) kcontrol->private_value; | ||
482 | |||
483 | kfree(w->kcontrols[i]->tlv.p); | ||
484 | |||
485 | snd_ctl_remove(card, w->kcontrols[i]); | ||
486 | kfree(sm); | ||
487 | } | ||
488 | kfree(w->kcontrol_news); | ||
489 | } | ||
490 | /* widget w is freed by soc-dapm.c */ | ||
491 | } | ||
492 | |||
493 | /* remove PCM DAI configurations */ | ||
494 | static void remove_pcm_dai(struct snd_soc_component *comp, | ||
495 | struct snd_soc_dobj *dobj, int pass) | ||
496 | { | ||
497 | if (pass != SOC_TPLG_PASS_PCM_DAI) | ||
498 | return; | ||
499 | |||
500 | if (dobj->ops && dobj->ops->pcm_dai_unload) | ||
501 | dobj->ops->pcm_dai_unload(comp, dobj); | ||
502 | |||
503 | list_del(&dobj->list); | ||
504 | kfree(dobj); | ||
505 | } | ||
506 | |||
507 | /* bind a kcontrol to it's IO handlers */ | ||
508 | static int soc_tplg_kcontrol_bind_io(struct snd_soc_tplg_ctl_hdr *hdr, | ||
509 | struct snd_kcontrol_new *k, | ||
510 | const struct snd_soc_tplg_kcontrol_ops *ops, int num_ops, | ||
511 | const struct snd_soc_tplg_kcontrol_ops *bops, int num_bops) | ||
512 | { | ||
513 | int i; | ||
514 | |||
515 | /* try and map standard kcontrols handler first */ | ||
516 | for (i = 0; i < num_ops; i++) { | ||
517 | |||
518 | if (ops[i].id == hdr->ops.put) | ||
519 | k->put = ops[i].put; | ||
520 | if (ops[i].id == hdr->ops.get) | ||
521 | k->get = ops[i].get; | ||
522 | if (ops[i].id == hdr->ops.info) | ||
523 | k->info = ops[i].info; | ||
524 | } | ||
525 | |||
526 | /* standard handlers found ? */ | ||
527 | if (k->put && k->get && k->info) | ||
528 | return 0; | ||
529 | |||
530 | /* none found so try bespoke handlers */ | ||
531 | for (i = 0; i < num_bops; i++) { | ||
532 | |||
533 | if (k->put == NULL && bops[i].id == hdr->ops.put) | ||
534 | k->put = bops[i].put; | ||
535 | if (k->get == NULL && bops[i].id == hdr->ops.get) | ||
536 | k->get = bops[i].get; | ||
537 | if (k->info == NULL && ops[i].id == hdr->ops.info) | ||
538 | k->info = bops[i].info; | ||
539 | } | ||
540 | |||
541 | /* bespoke handlers found ? */ | ||
542 | if (k->put && k->get && k->info) | ||
543 | return 0; | ||
544 | |||
545 | /* nothing to bind */ | ||
546 | return -EINVAL; | ||
547 | } | ||
548 | |||
549 | /* bind a widgets to it's evnt handlers */ | ||
550 | int snd_soc_tplg_widget_bind_event(struct snd_soc_dapm_widget *w, | ||
551 | const struct snd_soc_tplg_widget_events *events, | ||
552 | int num_events, u16 event_type) | ||
553 | { | ||
554 | int i; | ||
555 | |||
556 | w->event = NULL; | ||
557 | |||
558 | for (i = 0; i < num_events; i++) { | ||
559 | if (event_type == events[i].type) { | ||
560 | |||
561 | /* found - so assign event */ | ||
562 | w->event = events[i].event_handler; | ||
563 | return 0; | ||
564 | } | ||
565 | } | ||
566 | |||
567 | /* not found */ | ||
568 | return -EINVAL; | ||
569 | } | ||
570 | EXPORT_SYMBOL_GPL(snd_soc_tplg_widget_bind_event); | ||
571 | |||
572 | /* optionally pass new dynamic kcontrol to component driver. */ | ||
573 | static int soc_tplg_init_kcontrol(struct soc_tplg *tplg, | ||
574 | struct snd_kcontrol_new *k, struct snd_soc_tplg_ctl_hdr *hdr) | ||
575 | { | ||
576 | if (tplg->comp && tplg->ops && tplg->ops->control_load) | ||
577 | return tplg->ops->control_load(tplg->comp, k, hdr); | ||
578 | |||
579 | return 0; | ||
580 | } | ||
581 | |||
582 | static int soc_tplg_create_tlv(struct soc_tplg *tplg, | ||
583 | struct snd_kcontrol_new *kc, u32 tlv_size) | ||
584 | { | ||
585 | struct snd_soc_tplg_ctl_tlv *tplg_tlv; | ||
586 | struct snd_ctl_tlv *tlv; | ||
587 | |||
588 | if (tlv_size == 0) | ||
589 | return 0; | ||
590 | |||
591 | tplg_tlv = (struct snd_soc_tplg_ctl_tlv *) tplg->pos; | ||
592 | tplg->pos += tlv_size; | ||
593 | |||
594 | tlv = kzalloc(sizeof(*tlv) + tlv_size, GFP_KERNEL); | ||
595 | if (tlv == NULL) | ||
596 | return -ENOMEM; | ||
597 | |||
598 | dev_dbg(tplg->dev, " created TLV type %d size %d bytes\n", | ||
599 | tplg_tlv->numid, tplg_tlv->size); | ||
600 | |||
601 | tlv->numid = tplg_tlv->numid; | ||
602 | tlv->length = tplg_tlv->size; | ||
603 | memcpy(tlv->tlv, tplg_tlv + 1, tplg_tlv->size); | ||
604 | kc->tlv.p = (void *)tlv; | ||
605 | |||
606 | return 0; | ||
607 | } | ||
608 | |||
609 | static inline void soc_tplg_free_tlv(struct soc_tplg *tplg, | ||
610 | struct snd_kcontrol_new *kc) | ||
611 | { | ||
612 | kfree(kc->tlv.p); | ||
613 | } | ||
614 | |||
615 | static int soc_tplg_dbytes_create(struct soc_tplg *tplg, unsigned int count, | ||
616 | size_t size) | ||
617 | { | ||
618 | struct snd_soc_tplg_bytes_control *be; | ||
619 | struct soc_bytes_ext *sbe; | ||
620 | struct snd_kcontrol_new kc; | ||
621 | int i, err; | ||
622 | |||
623 | if (soc_tplg_check_elem_count(tplg, | ||
624 | sizeof(struct snd_soc_tplg_bytes_control), count, | ||
625 | size, "mixer bytes")) { | ||
626 | dev_err(tplg->dev, "ASoC: Invalid count %d for byte control\n", | ||
627 | count); | ||
628 | return -EINVAL; | ||
629 | } | ||
630 | |||
631 | for (i = 0; i < count; i++) { | ||
632 | be = (struct snd_soc_tplg_bytes_control *)tplg->pos; | ||
633 | |||
634 | /* validate kcontrol */ | ||
635 | if (strnlen(be->hdr.name, SNDRV_CTL_ELEM_ID_NAME_MAXLEN) == | ||
636 | SNDRV_CTL_ELEM_ID_NAME_MAXLEN) | ||
637 | return -EINVAL; | ||
638 | |||
639 | sbe = kzalloc(sizeof(*sbe), GFP_KERNEL); | ||
640 | if (sbe == NULL) | ||
641 | return -ENOMEM; | ||
642 | |||
643 | tplg->pos += (sizeof(struct snd_soc_tplg_bytes_control) + | ||
644 | be->priv.size); | ||
645 | |||
646 | dev_dbg(tplg->dev, | ||
647 | "ASoC: adding bytes kcontrol %s with access 0x%x\n", | ||
648 | be->hdr.name, be->hdr.access); | ||
649 | |||
650 | memset(&kc, 0, sizeof(kc)); | ||
651 | kc.name = be->hdr.name; | ||
652 | kc.private_value = (long)sbe; | ||
653 | kc.iface = SNDRV_CTL_ELEM_IFACE_MIXER; | ||
654 | kc.access = be->hdr.access; | ||
655 | |||
656 | sbe->max = be->max; | ||
657 | sbe->dobj.type = SND_SOC_DOBJ_BYTES; | ||
658 | sbe->dobj.ops = tplg->ops; | ||
659 | INIT_LIST_HEAD(&sbe->dobj.list); | ||
660 | |||
661 | /* map io handlers */ | ||
662 | err = soc_tplg_kcontrol_bind_io(&be->hdr, &kc, io_ops, | ||
663 | ARRAY_SIZE(io_ops), tplg->io_ops, tplg->io_ops_count); | ||
664 | if (err) { | ||
665 | soc_control_err(tplg, &be->hdr, be->hdr.name); | ||
666 | kfree(sbe); | ||
667 | continue; | ||
668 | } | ||
669 | |||
670 | /* pass control to driver for optional further init */ | ||
671 | err = soc_tplg_init_kcontrol(tplg, &kc, | ||
672 | (struct snd_soc_tplg_ctl_hdr *)be); | ||
673 | if (err < 0) { | ||
674 | dev_err(tplg->dev, "ASoC: failed to init %s\n", | ||
675 | be->hdr.name); | ||
676 | kfree(sbe); | ||
677 | continue; | ||
678 | } | ||
679 | |||
680 | /* register control here */ | ||
681 | err = soc_tplg_add_kcontrol(tplg, &kc, | ||
682 | &sbe->dobj.control.kcontrol); | ||
683 | if (err < 0) { | ||
684 | dev_err(tplg->dev, "ASoC: failed to add %s\n", | ||
685 | be->hdr.name); | ||
686 | kfree(sbe); | ||
687 | continue; | ||
688 | } | ||
689 | |||
690 | list_add(&sbe->dobj.list, &tplg->comp->dobj_list); | ||
691 | } | ||
692 | return 0; | ||
693 | |||
694 | } | ||
695 | |||
696 | static int soc_tplg_dmixer_create(struct soc_tplg *tplg, unsigned int count, | ||
697 | size_t size) | ||
698 | { | ||
699 | struct snd_soc_tplg_mixer_control *mc; | ||
700 | struct soc_mixer_control *sm; | ||
701 | struct snd_kcontrol_new kc; | ||
702 | int i, err; | ||
703 | |||
704 | if (soc_tplg_check_elem_count(tplg, | ||
705 | sizeof(struct snd_soc_tplg_mixer_control), | ||
706 | count, size, "mixers")) { | ||
707 | |||
708 | dev_err(tplg->dev, "ASoC: invalid count %d for controls\n", | ||
709 | count); | ||
710 | return -EINVAL; | ||
711 | } | ||
712 | |||
713 | for (i = 0; i < count; i++) { | ||
714 | mc = (struct snd_soc_tplg_mixer_control *)tplg->pos; | ||
715 | |||
716 | /* validate kcontrol */ | ||
717 | if (strnlen(mc->hdr.name, SNDRV_CTL_ELEM_ID_NAME_MAXLEN) == | ||
718 | SNDRV_CTL_ELEM_ID_NAME_MAXLEN) | ||
719 | return -EINVAL; | ||
720 | |||
721 | sm = kzalloc(sizeof(*sm), GFP_KERNEL); | ||
722 | if (sm == NULL) | ||
723 | return -ENOMEM; | ||
724 | tplg->pos += (sizeof(struct snd_soc_tplg_mixer_control) + | ||
725 | mc->priv.size); | ||
726 | |||
727 | dev_dbg(tplg->dev, | ||
728 | "ASoC: adding mixer kcontrol %s with access 0x%x\n", | ||
729 | mc->hdr.name, mc->hdr.access); | ||
730 | |||
731 | memset(&kc, 0, sizeof(kc)); | ||
732 | kc.name = mc->hdr.name; | ||
733 | kc.private_value = (long)sm; | ||
734 | kc.iface = SNDRV_CTL_ELEM_IFACE_MIXER; | ||
735 | kc.access = mc->hdr.access; | ||
736 | |||
737 | /* we only support FL/FR channel mapping atm */ | ||
738 | sm->reg = tplc_chan_get_reg(tplg, mc->channel, | ||
739 | SNDRV_CHMAP_FL); | ||
740 | sm->rreg = tplc_chan_get_reg(tplg, mc->channel, | ||
741 | SNDRV_CHMAP_FR); | ||
742 | sm->shift = tplc_chan_get_shift(tplg, mc->channel, | ||
743 | SNDRV_CHMAP_FL); | ||
744 | sm->rshift = tplc_chan_get_shift(tplg, mc->channel, | ||
745 | SNDRV_CHMAP_FR); | ||
746 | |||
747 | sm->max = mc->max; | ||
748 | sm->min = mc->min; | ||
749 | sm->invert = mc->invert; | ||
750 | sm->platform_max = mc->platform_max; | ||
751 | sm->dobj.index = tplg->index; | ||
752 | sm->dobj.ops = tplg->ops; | ||
753 | sm->dobj.type = SND_SOC_DOBJ_MIXER; | ||
754 | INIT_LIST_HEAD(&sm->dobj.list); | ||
755 | |||
756 | /* map io handlers */ | ||
757 | err = soc_tplg_kcontrol_bind_io(&mc->hdr, &kc, io_ops, | ||
758 | ARRAY_SIZE(io_ops), tplg->io_ops, tplg->io_ops_count); | ||
759 | if (err) { | ||
760 | soc_control_err(tplg, &mc->hdr, mc->hdr.name); | ||
761 | kfree(sm); | ||
762 | continue; | ||
763 | } | ||
764 | |||
765 | /* pass control to driver for optional further init */ | ||
766 | err = soc_tplg_init_kcontrol(tplg, &kc, | ||
767 | (struct snd_soc_tplg_ctl_hdr *) mc); | ||
768 | if (err < 0) { | ||
769 | dev_err(tplg->dev, "ASoC: failed to init %s\n", | ||
770 | mc->hdr.name); | ||
771 | kfree(sm); | ||
772 | continue; | ||
773 | } | ||
774 | |||
775 | /* create any TLV data */ | ||
776 | soc_tplg_create_tlv(tplg, &kc, mc->hdr.tlv_size); | ||
777 | |||
778 | /* register control here */ | ||
779 | err = soc_tplg_add_kcontrol(tplg, &kc, | ||
780 | &sm->dobj.control.kcontrol); | ||
781 | if (err < 0) { | ||
782 | dev_err(tplg->dev, "ASoC: failed to add %s\n", | ||
783 | mc->hdr.name); | ||
784 | soc_tplg_free_tlv(tplg, &kc); | ||
785 | kfree(sm); | ||
786 | continue; | ||
787 | } | ||
788 | |||
789 | list_add(&sm->dobj.list, &tplg->comp->dobj_list); | ||
790 | } | ||
791 | |||
792 | return 0; | ||
793 | } | ||
794 | |||
795 | static int soc_tplg_denum_create_texts(struct soc_enum *se, | ||
796 | struct snd_soc_tplg_enum_control *ec) | ||
797 | { | ||
798 | int i, ret; | ||
799 | |||
800 | se->dobj.control.dtexts = | ||
801 | kzalloc(sizeof(char *) * ec->items, GFP_KERNEL); | ||
802 | if (se->dobj.control.dtexts == NULL) | ||
803 | return -ENOMEM; | ||
804 | |||
805 | for (i = 0; i < ec->items; i++) { | ||
806 | |||
807 | if (strnlen(ec->texts[i], SNDRV_CTL_ELEM_ID_NAME_MAXLEN) == | ||
808 | SNDRV_CTL_ELEM_ID_NAME_MAXLEN) { | ||
809 | ret = -EINVAL; | ||
810 | goto err; | ||
811 | } | ||
812 | |||
813 | se->dobj.control.dtexts[i] = kstrdup(ec->texts[i], GFP_KERNEL); | ||
814 | if (!se->dobj.control.dtexts[i]) { | ||
815 | ret = -ENOMEM; | ||
816 | goto err; | ||
817 | } | ||
818 | } | ||
819 | |||
820 | return 0; | ||
821 | |||
822 | err: | ||
823 | for (--i; i >= 0; i--) | ||
824 | kfree(se->dobj.control.dtexts[i]); | ||
825 | kfree(se->dobj.control.dtexts); | ||
826 | return ret; | ||
827 | } | ||
828 | |||
829 | static int soc_tplg_denum_create_values(struct soc_enum *se, | ||
830 | struct snd_soc_tplg_enum_control *ec) | ||
831 | { | ||
832 | if (ec->items > sizeof(*ec->values)) | ||
833 | return -EINVAL; | ||
834 | |||
835 | se->dobj.control.dvalues = | ||
836 | kmalloc(ec->items * sizeof(u32), GFP_KERNEL); | ||
837 | if (!se->dobj.control.dvalues) | ||
838 | return -ENOMEM; | ||
839 | |||
840 | memcpy(se->dobj.control.dvalues, ec->values, ec->items * sizeof(u32)); | ||
841 | return 0; | ||
842 | } | ||
843 | |||
844 | static int soc_tplg_denum_create(struct soc_tplg *tplg, unsigned int count, | ||
845 | size_t size) | ||
846 | { | ||
847 | struct snd_soc_tplg_enum_control *ec; | ||
848 | struct soc_enum *se; | ||
849 | struct snd_kcontrol_new kc; | ||
850 | int i, ret, err; | ||
851 | |||
852 | if (soc_tplg_check_elem_count(tplg, | ||
853 | sizeof(struct snd_soc_tplg_enum_control), | ||
854 | count, size, "enums")) { | ||
855 | |||
856 | dev_err(tplg->dev, "ASoC: invalid count %d for enum controls\n", | ||
857 | count); | ||
858 | return -EINVAL; | ||
859 | } | ||
860 | |||
861 | for (i = 0; i < count; i++) { | ||
862 | ec = (struct snd_soc_tplg_enum_control *)tplg->pos; | ||
863 | tplg->pos += (sizeof(struct snd_soc_tplg_enum_control) + | ||
864 | ec->priv.size); | ||
865 | |||
866 | /* validate kcontrol */ | ||
867 | if (strnlen(ec->hdr.name, SNDRV_CTL_ELEM_ID_NAME_MAXLEN) == | ||
868 | SNDRV_CTL_ELEM_ID_NAME_MAXLEN) | ||
869 | return -EINVAL; | ||
870 | |||
871 | se = kzalloc((sizeof(*se)), GFP_KERNEL); | ||
872 | if (se == NULL) | ||
873 | return -ENOMEM; | ||
874 | |||
875 | dev_dbg(tplg->dev, "ASoC: adding enum kcontrol %s size %d\n", | ||
876 | ec->hdr.name, ec->items); | ||
877 | |||
878 | memset(&kc, 0, sizeof(kc)); | ||
879 | kc.name = ec->hdr.name; | ||
880 | kc.private_value = (long)se; | ||
881 | kc.iface = SNDRV_CTL_ELEM_IFACE_MIXER; | ||
882 | kc.access = ec->hdr.access; | ||
883 | |||
884 | se->reg = tplc_chan_get_reg(tplg, ec->channel, SNDRV_CHMAP_FL); | ||
885 | se->shift_l = tplc_chan_get_shift(tplg, ec->channel, | ||
886 | SNDRV_CHMAP_FL); | ||
887 | se->shift_r = tplc_chan_get_shift(tplg, ec->channel, | ||
888 | SNDRV_CHMAP_FL); | ||
889 | |||
890 | se->items = ec->items; | ||
891 | se->mask = ec->mask; | ||
892 | se->dobj.index = tplg->index; | ||
893 | se->dobj.type = SND_SOC_DOBJ_ENUM; | ||
894 | se->dobj.ops = tplg->ops; | ||
895 | INIT_LIST_HEAD(&se->dobj.list); | ||
896 | |||
897 | switch (ec->hdr.ops.info) { | ||
898 | case SND_SOC_TPLG_DAPM_CTL_ENUM_VALUE: | ||
899 | case SND_SOC_TPLG_CTL_ENUM_VALUE: | ||
900 | err = soc_tplg_denum_create_values(se, ec); | ||
901 | if (err < 0) { | ||
902 | dev_err(tplg->dev, | ||
903 | "ASoC: could not create values for %s\n", | ||
904 | ec->hdr.name); | ||
905 | kfree(se); | ||
906 | continue; | ||
907 | } | ||
908 | /* fall through and create texts */ | ||
909 | case SND_SOC_TPLG_CTL_ENUM: | ||
910 | case SND_SOC_TPLG_DAPM_CTL_ENUM_DOUBLE: | ||
911 | case SND_SOC_TPLG_DAPM_CTL_ENUM_VIRT: | ||
912 | err = soc_tplg_denum_create_texts(se, ec); | ||
913 | if (err < 0) { | ||
914 | dev_err(tplg->dev, | ||
915 | "ASoC: could not create texts for %s\n", | ||
916 | ec->hdr.name); | ||
917 | kfree(se); | ||
918 | continue; | ||
919 | } | ||
920 | break; | ||
921 | default: | ||
922 | dev_err(tplg->dev, | ||
923 | "ASoC: invalid enum control type %d for %s\n", | ||
924 | ec->hdr.ops.info, ec->hdr.name); | ||
925 | kfree(se); | ||
926 | continue; | ||
927 | } | ||
928 | |||
929 | /* map io handlers */ | ||
930 | err = soc_tplg_kcontrol_bind_io(&ec->hdr, &kc, io_ops, | ||
931 | ARRAY_SIZE(io_ops), tplg->io_ops, tplg->io_ops_count); | ||
932 | if (err) { | ||
933 | soc_control_err(tplg, &ec->hdr, ec->hdr.name); | ||
934 | kfree(se); | ||
935 | continue; | ||
936 | } | ||
937 | |||
938 | /* pass control to driver for optional further init */ | ||
939 | err = soc_tplg_init_kcontrol(tplg, &kc, | ||
940 | (struct snd_soc_tplg_ctl_hdr *) ec); | ||
941 | if (err < 0) { | ||
942 | dev_err(tplg->dev, "ASoC: failed to init %s\n", | ||
943 | ec->hdr.name); | ||
944 | kfree(se); | ||
945 | continue; | ||
946 | } | ||
947 | |||
948 | /* register control here */ | ||
949 | ret = soc_tplg_add_kcontrol(tplg, | ||
950 | &kc, &se->dobj.control.kcontrol); | ||
951 | if (ret < 0) { | ||
952 | dev_err(tplg->dev, "ASoC: could not add kcontrol %s\n", | ||
953 | ec->hdr.name); | ||
954 | kfree(se); | ||
955 | continue; | ||
956 | } | ||
957 | |||
958 | list_add(&se->dobj.list, &tplg->comp->dobj_list); | ||
959 | } | ||
960 | |||
961 | return 0; | ||
962 | } | ||
963 | |||
964 | static int soc_tplg_kcontrol_elems_load(struct soc_tplg *tplg, | ||
965 | struct snd_soc_tplg_hdr *hdr) | ||
966 | { | ||
967 | struct snd_soc_tplg_ctl_hdr *control_hdr; | ||
968 | int i; | ||
969 | |||
970 | if (tplg->pass != SOC_TPLG_PASS_MIXER) { | ||
971 | tplg->pos += hdr->size + hdr->payload_size; | ||
972 | return 0; | ||
973 | } | ||
974 | |||
975 | dev_dbg(tplg->dev, "ASoC: adding %d kcontrols at 0x%lx\n", hdr->count, | ||
976 | soc_tplg_get_offset(tplg)); | ||
977 | |||
978 | for (i = 0; i < hdr->count; i++) { | ||
979 | |||
980 | control_hdr = (struct snd_soc_tplg_ctl_hdr *)tplg->pos; | ||
981 | |||
982 | switch (control_hdr->ops.info) { | ||
983 | case SND_SOC_TPLG_CTL_VOLSW: | ||
984 | case SND_SOC_TPLG_CTL_STROBE: | ||
985 | case SND_SOC_TPLG_CTL_VOLSW_SX: | ||
986 | case SND_SOC_TPLG_CTL_VOLSW_XR_SX: | ||
987 | case SND_SOC_TPLG_CTL_RANGE: | ||
988 | case SND_SOC_TPLG_DAPM_CTL_VOLSW: | ||
989 | case SND_SOC_TPLG_DAPM_CTL_PIN: | ||
990 | soc_tplg_dmixer_create(tplg, 1, hdr->payload_size); | ||
991 | break; | ||
992 | case SND_SOC_TPLG_CTL_ENUM: | ||
993 | case SND_SOC_TPLG_CTL_ENUM_VALUE: | ||
994 | case SND_SOC_TPLG_DAPM_CTL_ENUM_DOUBLE: | ||
995 | case SND_SOC_TPLG_DAPM_CTL_ENUM_VIRT: | ||
996 | case SND_SOC_TPLG_DAPM_CTL_ENUM_VALUE: | ||
997 | soc_tplg_denum_create(tplg, 1, hdr->payload_size); | ||
998 | break; | ||
999 | case SND_SOC_TPLG_CTL_BYTES: | ||
1000 | soc_tplg_dbytes_create(tplg, 1, hdr->payload_size); | ||
1001 | break; | ||
1002 | default: | ||
1003 | soc_bind_err(tplg, control_hdr, i); | ||
1004 | return -EINVAL; | ||
1005 | } | ||
1006 | } | ||
1007 | |||
1008 | return 0; | ||
1009 | } | ||
1010 | |||
1011 | static int soc_tplg_dapm_graph_elems_load(struct soc_tplg *tplg, | ||
1012 | struct snd_soc_tplg_hdr *hdr) | ||
1013 | { | ||
1014 | struct snd_soc_dapm_context *dapm = &tplg->comp->dapm; | ||
1015 | struct snd_soc_dapm_route route; | ||
1016 | struct snd_soc_tplg_dapm_graph_elem *elem; | ||
1017 | int count = hdr->count, i; | ||
1018 | |||
1019 | if (tplg->pass != SOC_TPLG_PASS_GRAPH) { | ||
1020 | tplg->pos += hdr->size + hdr->payload_size; | ||
1021 | return 0; | ||
1022 | } | ||
1023 | |||
1024 | if (soc_tplg_check_elem_count(tplg, | ||
1025 | sizeof(struct snd_soc_tplg_dapm_graph_elem), | ||
1026 | count, hdr->payload_size, "graph")) { | ||
1027 | |||
1028 | dev_err(tplg->dev, "ASoC: invalid count %d for DAPM routes\n", | ||
1029 | count); | ||
1030 | return -EINVAL; | ||
1031 | } | ||
1032 | |||
1033 | dev_dbg(tplg->dev, "ASoC: adding %d DAPM routes\n", count); | ||
1034 | |||
1035 | for (i = 0; i < count; i++) { | ||
1036 | elem = (struct snd_soc_tplg_dapm_graph_elem *)tplg->pos; | ||
1037 | tplg->pos += sizeof(struct snd_soc_tplg_dapm_graph_elem); | ||
1038 | |||
1039 | /* validate routes */ | ||
1040 | if (strnlen(elem->source, SNDRV_CTL_ELEM_ID_NAME_MAXLEN) == | ||
1041 | SNDRV_CTL_ELEM_ID_NAME_MAXLEN) | ||
1042 | return -EINVAL; | ||
1043 | if (strnlen(elem->sink, SNDRV_CTL_ELEM_ID_NAME_MAXLEN) == | ||
1044 | SNDRV_CTL_ELEM_ID_NAME_MAXLEN) | ||
1045 | return -EINVAL; | ||
1046 | if (strnlen(elem->control, SNDRV_CTL_ELEM_ID_NAME_MAXLEN) == | ||
1047 | SNDRV_CTL_ELEM_ID_NAME_MAXLEN) | ||
1048 | return -EINVAL; | ||
1049 | |||
1050 | route.source = elem->source; | ||
1051 | route.sink = elem->sink; | ||
1052 | route.connected = NULL; /* set to NULL atm for tplg users */ | ||
1053 | if (strnlen(elem->control, SNDRV_CTL_ELEM_ID_NAME_MAXLEN) == 0) | ||
1054 | route.control = NULL; | ||
1055 | else | ||
1056 | route.control = elem->control; | ||
1057 | |||
1058 | /* add route, but keep going if some fail */ | ||
1059 | snd_soc_dapm_add_routes(dapm, &route, 1); | ||
1060 | } | ||
1061 | |||
1062 | return 0; | ||
1063 | } | ||
1064 | |||
1065 | static struct snd_kcontrol_new *soc_tplg_dapm_widget_dmixer_create( | ||
1066 | struct soc_tplg *tplg, int num_kcontrols) | ||
1067 | { | ||
1068 | struct snd_kcontrol_new *kc; | ||
1069 | struct soc_mixer_control *sm; | ||
1070 | struct snd_soc_tplg_mixer_control *mc; | ||
1071 | int i, err; | ||
1072 | |||
1073 | kc = kzalloc(sizeof(*kc) * num_kcontrols, GFP_KERNEL); | ||
1074 | if (kc == NULL) | ||
1075 | return NULL; | ||
1076 | |||
1077 | for (i = 0; i < num_kcontrols; i++) { | ||
1078 | mc = (struct snd_soc_tplg_mixer_control *)tplg->pos; | ||
1079 | sm = kzalloc(sizeof(*sm), GFP_KERNEL); | ||
1080 | if (sm == NULL) | ||
1081 | goto err; | ||
1082 | |||
1083 | tplg->pos += (sizeof(struct snd_soc_tplg_mixer_control) + | ||
1084 | mc->priv.size); | ||
1085 | |||
1086 | /* validate kcontrol */ | ||
1087 | if (strnlen(mc->hdr.name, SNDRV_CTL_ELEM_ID_NAME_MAXLEN) == | ||
1088 | SNDRV_CTL_ELEM_ID_NAME_MAXLEN) | ||
1089 | goto err_str; | ||
1090 | |||
1091 | dev_dbg(tplg->dev, " adding DAPM widget mixer control %s at %d\n", | ||
1092 | mc->hdr.name, i); | ||
1093 | |||
1094 | kc[i].name = mc->hdr.name; | ||
1095 | kc[i].private_value = (long)sm; | ||
1096 | kc[i].iface = SNDRV_CTL_ELEM_IFACE_MIXER; | ||
1097 | kc[i].access = mc->hdr.access; | ||
1098 | |||
1099 | /* we only support FL/FR channel mapping atm */ | ||
1100 | sm->reg = tplc_chan_get_reg(tplg, mc->channel, | ||
1101 | SNDRV_CHMAP_FL); | ||
1102 | sm->rreg = tplc_chan_get_reg(tplg, mc->channel, | ||
1103 | SNDRV_CHMAP_FR); | ||
1104 | sm->shift = tplc_chan_get_shift(tplg, mc->channel, | ||
1105 | SNDRV_CHMAP_FL); | ||
1106 | sm->rshift = tplc_chan_get_shift(tplg, mc->channel, | ||
1107 | SNDRV_CHMAP_FR); | ||
1108 | |||
1109 | sm->max = mc->max; | ||
1110 | sm->min = mc->min; | ||
1111 | sm->invert = mc->invert; | ||
1112 | sm->platform_max = mc->platform_max; | ||
1113 | sm->dobj.index = tplg->index; | ||
1114 | INIT_LIST_HEAD(&sm->dobj.list); | ||
1115 | |||
1116 | /* map io handlers */ | ||
1117 | err = soc_tplg_kcontrol_bind_io(&mc->hdr, &kc[i], io_ops, | ||
1118 | ARRAY_SIZE(io_ops), tplg->io_ops, tplg->io_ops_count); | ||
1119 | if (err) { | ||
1120 | soc_control_err(tplg, &mc->hdr, mc->hdr.name); | ||
1121 | kfree(sm); | ||
1122 | continue; | ||
1123 | } | ||
1124 | |||
1125 | /* pass control to driver for optional further init */ | ||
1126 | err = soc_tplg_init_kcontrol(tplg, &kc[i], | ||
1127 | (struct snd_soc_tplg_ctl_hdr *)mc); | ||
1128 | if (err < 0) { | ||
1129 | dev_err(tplg->dev, "ASoC: failed to init %s\n", | ||
1130 | mc->hdr.name); | ||
1131 | kfree(sm); | ||
1132 | continue; | ||
1133 | } | ||
1134 | } | ||
1135 | return kc; | ||
1136 | |||
1137 | err_str: | ||
1138 | kfree(sm); | ||
1139 | err: | ||
1140 | for (--i; i >= 0; i--) | ||
1141 | kfree((void *)kc[i].private_value); | ||
1142 | kfree(kc); | ||
1143 | return NULL; | ||
1144 | } | ||
1145 | |||
1146 | static struct snd_kcontrol_new *soc_tplg_dapm_widget_denum_create( | ||
1147 | struct soc_tplg *tplg) | ||
1148 | { | ||
1149 | struct snd_kcontrol_new *kc; | ||
1150 | struct snd_soc_tplg_enum_control *ec; | ||
1151 | struct soc_enum *se; | ||
1152 | int i, err; | ||
1153 | |||
1154 | ec = (struct snd_soc_tplg_enum_control *)tplg->pos; | ||
1155 | tplg->pos += (sizeof(struct snd_soc_tplg_enum_control) + | ||
1156 | ec->priv.size); | ||
1157 | |||
1158 | /* validate kcontrol */ | ||
1159 | if (strnlen(ec->hdr.name, SNDRV_CTL_ELEM_ID_NAME_MAXLEN) == | ||
1160 | SNDRV_CTL_ELEM_ID_NAME_MAXLEN) | ||
1161 | return NULL; | ||
1162 | |||
1163 | kc = kzalloc(sizeof(*kc), GFP_KERNEL); | ||
1164 | if (kc == NULL) | ||
1165 | return NULL; | ||
1166 | |||
1167 | se = kzalloc(sizeof(*se), GFP_KERNEL); | ||
1168 | if (se == NULL) | ||
1169 | goto err; | ||
1170 | |||
1171 | dev_dbg(tplg->dev, " adding DAPM widget enum control %s\n", | ||
1172 | ec->hdr.name); | ||
1173 | |||
1174 | kc->name = ec->hdr.name; | ||
1175 | kc->private_value = (long)se; | ||
1176 | kc->iface = SNDRV_CTL_ELEM_IFACE_MIXER; | ||
1177 | kc->access = ec->hdr.access; | ||
1178 | |||
1179 | /* we only support FL/FR channel mapping atm */ | ||
1180 | se->reg = tplc_chan_get_reg(tplg, ec->channel, SNDRV_CHMAP_FL); | ||
1181 | se->shift_l = tplc_chan_get_shift(tplg, ec->channel, SNDRV_CHMAP_FL); | ||
1182 | se->shift_r = tplc_chan_get_shift(tplg, ec->channel, SNDRV_CHMAP_FR); | ||
1183 | |||
1184 | se->items = ec->items; | ||
1185 | se->mask = ec->mask; | ||
1186 | se->dobj.index = tplg->index; | ||
1187 | |||
1188 | switch (ec->hdr.ops.info) { | ||
1189 | case SND_SOC_TPLG_CTL_ENUM_VALUE: | ||
1190 | case SND_SOC_TPLG_DAPM_CTL_ENUM_VALUE: | ||
1191 | err = soc_tplg_denum_create_values(se, ec); | ||
1192 | if (err < 0) { | ||
1193 | dev_err(tplg->dev, "ASoC: could not create values for %s\n", | ||
1194 | ec->hdr.name); | ||
1195 | goto err_se; | ||
1196 | } | ||
1197 | /* fall through to create texts */ | ||
1198 | case SND_SOC_TPLG_CTL_ENUM: | ||
1199 | case SND_SOC_TPLG_DAPM_CTL_ENUM_DOUBLE: | ||
1200 | case SND_SOC_TPLG_DAPM_CTL_ENUM_VIRT: | ||
1201 | err = soc_tplg_denum_create_texts(se, ec); | ||
1202 | if (err < 0) { | ||
1203 | dev_err(tplg->dev, "ASoC: could not create texts for %s\n", | ||
1204 | ec->hdr.name); | ||
1205 | goto err_se; | ||
1206 | } | ||
1207 | break; | ||
1208 | default: | ||
1209 | dev_err(tplg->dev, "ASoC: invalid enum control type %d for %s\n", | ||
1210 | ec->hdr.ops.info, ec->hdr.name); | ||
1211 | goto err_se; | ||
1212 | } | ||
1213 | |||
1214 | /* map io handlers */ | ||
1215 | err = soc_tplg_kcontrol_bind_io(&ec->hdr, kc, io_ops, | ||
1216 | ARRAY_SIZE(io_ops), tplg->io_ops, tplg->io_ops_count); | ||
1217 | if (err) { | ||
1218 | soc_control_err(tplg, &ec->hdr, ec->hdr.name); | ||
1219 | goto err_se; | ||
1220 | } | ||
1221 | |||
1222 | /* pass control to driver for optional further init */ | ||
1223 | err = soc_tplg_init_kcontrol(tplg, kc, | ||
1224 | (struct snd_soc_tplg_ctl_hdr *)ec); | ||
1225 | if (err < 0) { | ||
1226 | dev_err(tplg->dev, "ASoC: failed to init %s\n", | ||
1227 | ec->hdr.name); | ||
1228 | goto err_se; | ||
1229 | } | ||
1230 | |||
1231 | return kc; | ||
1232 | |||
1233 | err_se: | ||
1234 | /* free values and texts */ | ||
1235 | kfree(se->dobj.control.dvalues); | ||
1236 | for (i = 0; i < ec->items; i++) | ||
1237 | kfree(se->dobj.control.dtexts[i]); | ||
1238 | |||
1239 | kfree(se); | ||
1240 | err: | ||
1241 | kfree(kc); | ||
1242 | |||
1243 | return NULL; | ||
1244 | } | ||
1245 | |||
1246 | static struct snd_kcontrol_new *soc_tplg_dapm_widget_dbytes_create( | ||
1247 | struct soc_tplg *tplg, int count) | ||
1248 | { | ||
1249 | struct snd_soc_tplg_bytes_control *be; | ||
1250 | struct soc_bytes_ext *sbe; | ||
1251 | struct snd_kcontrol_new *kc; | ||
1252 | int i, err; | ||
1253 | |||
1254 | kc = kzalloc(sizeof(*kc) * count, GFP_KERNEL); | ||
1255 | if (!kc) | ||
1256 | return NULL; | ||
1257 | |||
1258 | for (i = 0; i < count; i++) { | ||
1259 | be = (struct snd_soc_tplg_bytes_control *)tplg->pos; | ||
1260 | |||
1261 | /* validate kcontrol */ | ||
1262 | if (strnlen(be->hdr.name, SNDRV_CTL_ELEM_ID_NAME_MAXLEN) == | ||
1263 | SNDRV_CTL_ELEM_ID_NAME_MAXLEN) | ||
1264 | goto err; | ||
1265 | |||
1266 | sbe = kzalloc(sizeof(*sbe), GFP_KERNEL); | ||
1267 | if (sbe == NULL) | ||
1268 | goto err; | ||
1269 | |||
1270 | tplg->pos += (sizeof(struct snd_soc_tplg_bytes_control) + | ||
1271 | be->priv.size); | ||
1272 | |||
1273 | dev_dbg(tplg->dev, | ||
1274 | "ASoC: adding bytes kcontrol %s with access 0x%x\n", | ||
1275 | be->hdr.name, be->hdr.access); | ||
1276 | |||
1277 | memset(kc, 0, sizeof(*kc)); | ||
1278 | kc[i].name = be->hdr.name; | ||
1279 | kc[i].private_value = (long)sbe; | ||
1280 | kc[i].iface = SNDRV_CTL_ELEM_IFACE_MIXER; | ||
1281 | kc[i].access = be->hdr.access; | ||
1282 | |||
1283 | sbe->max = be->max; | ||
1284 | INIT_LIST_HEAD(&sbe->dobj.list); | ||
1285 | |||
1286 | /* map standard io handlers and check for external handlers */ | ||
1287 | err = soc_tplg_kcontrol_bind_io(&be->hdr, &kc[i], io_ops, | ||
1288 | ARRAY_SIZE(io_ops), tplg->io_ops, | ||
1289 | tplg->io_ops_count); | ||
1290 | if (err) { | ||
1291 | soc_control_err(tplg, &be->hdr, be->hdr.name); | ||
1292 | kfree(sbe); | ||
1293 | continue; | ||
1294 | } | ||
1295 | |||
1296 | /* pass control to driver for optional further init */ | ||
1297 | err = soc_tplg_init_kcontrol(tplg, &kc[i], | ||
1298 | (struct snd_soc_tplg_ctl_hdr *)be); | ||
1299 | if (err < 0) { | ||
1300 | dev_err(tplg->dev, "ASoC: failed to init %s\n", | ||
1301 | be->hdr.name); | ||
1302 | kfree(sbe); | ||
1303 | continue; | ||
1304 | } | ||
1305 | } | ||
1306 | |||
1307 | return kc; | ||
1308 | |||
1309 | err: | ||
1310 | for (--i; i >= 0; i--) | ||
1311 | kfree((void *)kc[i].private_value); | ||
1312 | |||
1313 | kfree(kc); | ||
1314 | return NULL; | ||
1315 | } | ||
1316 | |||
1317 | static int soc_tplg_dapm_widget_create(struct soc_tplg *tplg, | ||
1318 | struct snd_soc_tplg_dapm_widget *w) | ||
1319 | { | ||
1320 | struct snd_soc_dapm_context *dapm = &tplg->comp->dapm; | ||
1321 | struct snd_soc_dapm_widget template, *widget; | ||
1322 | struct snd_soc_tplg_ctl_hdr *control_hdr; | ||
1323 | struct snd_soc_card *card = tplg->comp->card; | ||
1324 | int ret = 0; | ||
1325 | |||
1326 | if (strnlen(w->name, SNDRV_CTL_ELEM_ID_NAME_MAXLEN) == | ||
1327 | SNDRV_CTL_ELEM_ID_NAME_MAXLEN) | ||
1328 | return -EINVAL; | ||
1329 | if (strnlen(w->sname, SNDRV_CTL_ELEM_ID_NAME_MAXLEN) == | ||
1330 | SNDRV_CTL_ELEM_ID_NAME_MAXLEN) | ||
1331 | return -EINVAL; | ||
1332 | |||
1333 | dev_dbg(tplg->dev, "ASoC: creating DAPM widget %s id %d\n", | ||
1334 | w->name, w->id); | ||
1335 | |||
1336 | memset(&template, 0, sizeof(template)); | ||
1337 | |||
1338 | /* map user to kernel widget ID */ | ||
1339 | template.id = get_widget_id(w->id); | ||
1340 | if (template.id < 0) | ||
1341 | return template.id; | ||
1342 | |||
1343 | template.name = kstrdup(w->name, GFP_KERNEL); | ||
1344 | if (!template.name) | ||
1345 | return -ENOMEM; | ||
1346 | template.sname = kstrdup(w->sname, GFP_KERNEL); | ||
1347 | if (!template.sname) { | ||
1348 | ret = -ENOMEM; | ||
1349 | goto err; | ||
1350 | } | ||
1351 | template.reg = w->reg; | ||
1352 | template.shift = w->shift; | ||
1353 | template.mask = w->mask; | ||
1354 | template.on_val = w->invert ? 0 : 1; | ||
1355 | template.off_val = w->invert ? 1 : 0; | ||
1356 | template.ignore_suspend = w->ignore_suspend; | ||
1357 | template.event_flags = w->event_flags; | ||
1358 | template.dobj.index = tplg->index; | ||
1359 | |||
1360 | tplg->pos += | ||
1361 | (sizeof(struct snd_soc_tplg_dapm_widget) + w->priv.size); | ||
1362 | if (w->num_kcontrols == 0) { | ||
1363 | template.num_kcontrols = 0; | ||
1364 | goto widget; | ||
1365 | } | ||
1366 | |||
1367 | control_hdr = (struct snd_soc_tplg_ctl_hdr *)tplg->pos; | ||
1368 | dev_dbg(tplg->dev, "ASoC: template %s has %d controls of type %x\n", | ||
1369 | w->name, w->num_kcontrols, control_hdr->type); | ||
1370 | |||
1371 | switch (control_hdr->ops.info) { | ||
1372 | case SND_SOC_TPLG_CTL_VOLSW: | ||
1373 | case SND_SOC_TPLG_CTL_STROBE: | ||
1374 | case SND_SOC_TPLG_CTL_VOLSW_SX: | ||
1375 | case SND_SOC_TPLG_CTL_VOLSW_XR_SX: | ||
1376 | case SND_SOC_TPLG_CTL_RANGE: | ||
1377 | case SND_SOC_TPLG_DAPM_CTL_VOLSW: | ||
1378 | template.num_kcontrols = w->num_kcontrols; | ||
1379 | template.kcontrol_news = | ||
1380 | soc_tplg_dapm_widget_dmixer_create(tplg, | ||
1381 | template.num_kcontrols); | ||
1382 | if (!template.kcontrol_news) { | ||
1383 | ret = -ENOMEM; | ||
1384 | goto hdr_err; | ||
1385 | } | ||
1386 | break; | ||
1387 | case SND_SOC_TPLG_CTL_ENUM: | ||
1388 | case SND_SOC_TPLG_CTL_ENUM_VALUE: | ||
1389 | case SND_SOC_TPLG_DAPM_CTL_ENUM_DOUBLE: | ||
1390 | case SND_SOC_TPLG_DAPM_CTL_ENUM_VIRT: | ||
1391 | case SND_SOC_TPLG_DAPM_CTL_ENUM_VALUE: | ||
1392 | template.dobj.widget.kcontrol_enum = 1; | ||
1393 | template.num_kcontrols = 1; | ||
1394 | template.kcontrol_news = | ||
1395 | soc_tplg_dapm_widget_denum_create(tplg); | ||
1396 | if (!template.kcontrol_news) { | ||
1397 | ret = -ENOMEM; | ||
1398 | goto hdr_err; | ||
1399 | } | ||
1400 | break; | ||
1401 | case SND_SOC_TPLG_CTL_BYTES: | ||
1402 | template.num_kcontrols = w->num_kcontrols; | ||
1403 | template.kcontrol_news = | ||
1404 | soc_tplg_dapm_widget_dbytes_create(tplg, | ||
1405 | template.num_kcontrols); | ||
1406 | if (!template.kcontrol_news) { | ||
1407 | ret = -ENOMEM; | ||
1408 | goto hdr_err; | ||
1409 | } | ||
1410 | break; | ||
1411 | default: | ||
1412 | dev_err(tplg->dev, "ASoC: invalid widget control type %d:%d:%d\n", | ||
1413 | control_hdr->ops.get, control_hdr->ops.put, | ||
1414 | control_hdr->ops.info); | ||
1415 | ret = -EINVAL; | ||
1416 | goto hdr_err; | ||
1417 | } | ||
1418 | |||
1419 | widget: | ||
1420 | ret = soc_tplg_widget_load(tplg, &template, w); | ||
1421 | if (ret < 0) | ||
1422 | goto hdr_err; | ||
1423 | |||
1424 | /* card dapm mutex is held by the core if we are loading topology | ||
1425 | * data during sound card init. */ | ||
1426 | if (card->instantiated) | ||
1427 | widget = snd_soc_dapm_new_control(dapm, &template); | ||
1428 | else | ||
1429 | widget = snd_soc_dapm_new_control_unlocked(dapm, &template); | ||
1430 | if (widget == NULL) { | ||
1431 | dev_err(tplg->dev, "ASoC: failed to create widget %s controls\n", | ||
1432 | w->name); | ||
1433 | goto hdr_err; | ||
1434 | } | ||
1435 | |||
1436 | widget->dobj.type = SND_SOC_DOBJ_WIDGET; | ||
1437 | widget->dobj.ops = tplg->ops; | ||
1438 | widget->dobj.index = tplg->index; | ||
1439 | list_add(&widget->dobj.list, &tplg->comp->dobj_list); | ||
1440 | return 0; | ||
1441 | |||
1442 | hdr_err: | ||
1443 | kfree(template.sname); | ||
1444 | err: | ||
1445 | kfree(template.name); | ||
1446 | return ret; | ||
1447 | } | ||
1448 | |||
1449 | static int soc_tplg_dapm_widget_elems_load(struct soc_tplg *tplg, | ||
1450 | struct snd_soc_tplg_hdr *hdr) | ||
1451 | { | ||
1452 | struct snd_soc_tplg_dapm_widget *widget; | ||
1453 | int ret, count = hdr->count, i; | ||
1454 | |||
1455 | if (tplg->pass != SOC_TPLG_PASS_WIDGET) | ||
1456 | return 0; | ||
1457 | |||
1458 | dev_dbg(tplg->dev, "ASoC: adding %d DAPM widgets\n", count); | ||
1459 | |||
1460 | for (i = 0; i < count; i++) { | ||
1461 | widget = (struct snd_soc_tplg_dapm_widget *) tplg->pos; | ||
1462 | ret = soc_tplg_dapm_widget_create(tplg, widget); | ||
1463 | if (ret < 0) | ||
1464 | dev_err(tplg->dev, "ASoC: failed to load widget %s\n", | ||
1465 | widget->name); | ||
1466 | } | ||
1467 | |||
1468 | return 0; | ||
1469 | } | ||
1470 | |||
1471 | static int soc_tplg_dapm_complete(struct soc_tplg *tplg) | ||
1472 | { | ||
1473 | struct snd_soc_card *card = tplg->comp->card; | ||
1474 | int ret; | ||
1475 | |||
1476 | /* Card might not have been registered at this point. | ||
1477 | * If so, just return success. | ||
1478 | */ | ||
1479 | if (!card || !card->instantiated) { | ||
1480 | dev_warn(tplg->dev, "ASoC: Parent card not yet available," | ||
1481 | "Do not add new widgets now\n"); | ||
1482 | return 0; | ||
1483 | } | ||
1484 | |||
1485 | ret = snd_soc_dapm_new_widgets(card); | ||
1486 | if (ret < 0) | ||
1487 | dev_err(tplg->dev, "ASoC: failed to create new widgets %d\n", | ||
1488 | ret); | ||
1489 | |||
1490 | return 0; | ||
1491 | } | ||
1492 | |||
1493 | static int soc_tplg_pcm_dai_elems_load(struct soc_tplg *tplg, | ||
1494 | struct snd_soc_tplg_hdr *hdr) | ||
1495 | { | ||
1496 | struct snd_soc_tplg_pcm_dai *pcm_dai; | ||
1497 | struct snd_soc_dobj *dobj; | ||
1498 | int count = hdr->count; | ||
1499 | int ret; | ||
1500 | |||
1501 | if (tplg->pass != SOC_TPLG_PASS_PCM_DAI) | ||
1502 | return 0; | ||
1503 | |||
1504 | pcm_dai = (struct snd_soc_tplg_pcm_dai *)tplg->pos; | ||
1505 | |||
1506 | if (soc_tplg_check_elem_count(tplg, | ||
1507 | sizeof(struct snd_soc_tplg_pcm_dai), count, | ||
1508 | hdr->payload_size, "PCM DAI")) { | ||
1509 | dev_err(tplg->dev, "ASoC: invalid count %d for PCM DAI elems\n", | ||
1510 | count); | ||
1511 | return -EINVAL; | ||
1512 | } | ||
1513 | |||
1514 | dev_dbg(tplg->dev, "ASoC: adding %d PCM DAIs\n", count); | ||
1515 | tplg->pos += sizeof(struct snd_soc_tplg_pcm_dai) * count; | ||
1516 | |||
1517 | dobj = kzalloc(sizeof(struct snd_soc_dobj), GFP_KERNEL); | ||
1518 | if (dobj == NULL) | ||
1519 | return -ENOMEM; | ||
1520 | |||
1521 | /* Call the platform driver call back to register the dais */ | ||
1522 | ret = soc_tplg_pcm_dai_load(tplg, pcm_dai, count); | ||
1523 | if (ret < 0) { | ||
1524 | dev_err(tplg->comp->dev, "ASoC: PCM DAI loading failed\n"); | ||
1525 | goto err; | ||
1526 | } | ||
1527 | |||
1528 | dobj->type = get_dobj_type(hdr, NULL); | ||
1529 | dobj->pcm_dai.count = count; | ||
1530 | dobj->pcm_dai.pd = pcm_dai; | ||
1531 | dobj->ops = tplg->ops; | ||
1532 | dobj->index = tplg->index; | ||
1533 | list_add(&dobj->list, &tplg->comp->dobj_list); | ||
1534 | return 0; | ||
1535 | |||
1536 | err: | ||
1537 | kfree(dobj); | ||
1538 | return ret; | ||
1539 | } | ||
1540 | |||
1541 | static int soc_tplg_manifest_load(struct soc_tplg *tplg, | ||
1542 | struct snd_soc_tplg_hdr *hdr) | ||
1543 | { | ||
1544 | struct snd_soc_tplg_manifest *manifest; | ||
1545 | |||
1546 | if (tplg->pass != SOC_TPLG_PASS_MANIFEST) | ||
1547 | return 0; | ||
1548 | |||
1549 | manifest = (struct snd_soc_tplg_manifest *)tplg->pos; | ||
1550 | tplg->pos += sizeof(struct snd_soc_tplg_manifest); | ||
1551 | |||
1552 | if (tplg->comp && tplg->ops && tplg->ops->manifest) | ||
1553 | return tplg->ops->manifest(tplg->comp, manifest); | ||
1554 | |||
1555 | dev_err(tplg->dev, "ASoC: Firmware manifest not supported\n"); | ||
1556 | return 0; | ||
1557 | } | ||
1558 | |||
1559 | /* validate header magic, size and type */ | ||
1560 | static int soc_valid_header(struct soc_tplg *tplg, | ||
1561 | struct snd_soc_tplg_hdr *hdr) | ||
1562 | { | ||
1563 | if (soc_tplg_get_hdr_offset(tplg) >= tplg->fw->size) | ||
1564 | return 0; | ||
1565 | |||
1566 | /* big endian firmware objects not supported atm */ | ||
1567 | if (hdr->magic == cpu_to_be32(SND_SOC_TPLG_MAGIC)) { | ||
1568 | dev_err(tplg->dev, | ||
1569 | "ASoC: pass %d big endian not supported header got %x at offset 0x%lx size 0x%zx.\n", | ||
1570 | tplg->pass, hdr->magic, | ||
1571 | soc_tplg_get_hdr_offset(tplg), tplg->fw->size); | ||
1572 | return -EINVAL; | ||
1573 | } | ||
1574 | |||
1575 | if (hdr->magic != SND_SOC_TPLG_MAGIC) { | ||
1576 | dev_err(tplg->dev, | ||
1577 | "ASoC: pass %d does not have a valid header got %x at offset 0x%lx size 0x%zx.\n", | ||
1578 | tplg->pass, hdr->magic, | ||
1579 | soc_tplg_get_hdr_offset(tplg), tplg->fw->size); | ||
1580 | return -EINVAL; | ||
1581 | } | ||
1582 | |||
1583 | if (hdr->abi != SND_SOC_TPLG_ABI_VERSION) { | ||
1584 | dev_err(tplg->dev, | ||
1585 | "ASoC: pass %d invalid ABI version got 0x%x need 0x%x at offset 0x%lx size 0x%zx.\n", | ||
1586 | tplg->pass, hdr->abi, | ||
1587 | SND_SOC_TPLG_ABI_VERSION, soc_tplg_get_hdr_offset(tplg), | ||
1588 | tplg->fw->size); | ||
1589 | return -EINVAL; | ||
1590 | } | ||
1591 | |||
1592 | if (hdr->payload_size == 0) { | ||
1593 | dev_err(tplg->dev, "ASoC: header has 0 size at offset 0x%lx.\n", | ||
1594 | soc_tplg_get_hdr_offset(tplg)); | ||
1595 | return -EINVAL; | ||
1596 | } | ||
1597 | |||
1598 | if (tplg->pass == hdr->type) | ||
1599 | dev_dbg(tplg->dev, | ||
1600 | "ASoC: Got 0x%x bytes of type %d version %d vendor %d at pass %d\n", | ||
1601 | hdr->payload_size, hdr->type, hdr->version, | ||
1602 | hdr->vendor_type, tplg->pass); | ||
1603 | |||
1604 | return 1; | ||
1605 | } | ||
1606 | |||
1607 | /* check header type and call appropriate handler */ | ||
1608 | static int soc_tplg_load_header(struct soc_tplg *tplg, | ||
1609 | struct snd_soc_tplg_hdr *hdr) | ||
1610 | { | ||
1611 | tplg->pos = tplg->hdr_pos + sizeof(struct snd_soc_tplg_hdr); | ||
1612 | |||
1613 | /* check for matching ID */ | ||
1614 | if (hdr->index != tplg->req_index && | ||
1615 | hdr->index != SND_SOC_TPLG_INDEX_ALL) | ||
1616 | return 0; | ||
1617 | |||
1618 | tplg->index = hdr->index; | ||
1619 | |||
1620 | switch (hdr->type) { | ||
1621 | case SND_SOC_TPLG_TYPE_MIXER: | ||
1622 | case SND_SOC_TPLG_TYPE_ENUM: | ||
1623 | case SND_SOC_TPLG_TYPE_BYTES: | ||
1624 | return soc_tplg_kcontrol_elems_load(tplg, hdr); | ||
1625 | case SND_SOC_TPLG_TYPE_DAPM_GRAPH: | ||
1626 | return soc_tplg_dapm_graph_elems_load(tplg, hdr); | ||
1627 | case SND_SOC_TPLG_TYPE_DAPM_WIDGET: | ||
1628 | return soc_tplg_dapm_widget_elems_load(tplg, hdr); | ||
1629 | case SND_SOC_TPLG_TYPE_PCM: | ||
1630 | case SND_SOC_TPLG_TYPE_DAI_LINK: | ||
1631 | case SND_SOC_TPLG_TYPE_CODEC_LINK: | ||
1632 | return soc_tplg_pcm_dai_elems_load(tplg, hdr); | ||
1633 | case SND_SOC_TPLG_TYPE_MANIFEST: | ||
1634 | return soc_tplg_manifest_load(tplg, hdr); | ||
1635 | default: | ||
1636 | /* bespoke vendor data object */ | ||
1637 | return soc_tplg_vendor_load(tplg, hdr); | ||
1638 | } | ||
1639 | |||
1640 | return 0; | ||
1641 | } | ||
1642 | |||
1643 | /* process the topology file headers */ | ||
1644 | static int soc_tplg_process_headers(struct soc_tplg *tplg) | ||
1645 | { | ||
1646 | struct snd_soc_tplg_hdr *hdr; | ||
1647 | int ret; | ||
1648 | |||
1649 | tplg->pass = SOC_TPLG_PASS_START; | ||
1650 | |||
1651 | /* process the header types from start to end */ | ||
1652 | while (tplg->pass <= SOC_TPLG_PASS_END) { | ||
1653 | |||
1654 | tplg->hdr_pos = tplg->fw->data; | ||
1655 | hdr = (struct snd_soc_tplg_hdr *)tplg->hdr_pos; | ||
1656 | |||
1657 | while (!soc_tplg_is_eof(tplg)) { | ||
1658 | |||
1659 | /* make sure header is valid before loading */ | ||
1660 | ret = soc_valid_header(tplg, hdr); | ||
1661 | if (ret < 0) | ||
1662 | return ret; | ||
1663 | else if (ret == 0) | ||
1664 | break; | ||
1665 | |||
1666 | /* load the header object */ | ||
1667 | ret = soc_tplg_load_header(tplg, hdr); | ||
1668 | if (ret < 0) | ||
1669 | return ret; | ||
1670 | |||
1671 | /* goto next header */ | ||
1672 | tplg->hdr_pos += hdr->payload_size + | ||
1673 | sizeof(struct snd_soc_tplg_hdr); | ||
1674 | hdr = (struct snd_soc_tplg_hdr *)tplg->hdr_pos; | ||
1675 | } | ||
1676 | |||
1677 | /* next data type pass */ | ||
1678 | tplg->pass++; | ||
1679 | } | ||
1680 | |||
1681 | /* signal DAPM we are complete */ | ||
1682 | ret = soc_tplg_dapm_complete(tplg); | ||
1683 | if (ret < 0) | ||
1684 | dev_err(tplg->dev, | ||
1685 | "ASoC: failed to initialise DAPM from Firmware\n"); | ||
1686 | |||
1687 | return ret; | ||
1688 | } | ||
1689 | |||
1690 | static int soc_tplg_load(struct soc_tplg *tplg) | ||
1691 | { | ||
1692 | int ret; | ||
1693 | |||
1694 | ret = soc_tplg_process_headers(tplg); | ||
1695 | if (ret == 0) | ||
1696 | soc_tplg_complete(tplg); | ||
1697 | |||
1698 | return ret; | ||
1699 | } | ||
1700 | |||
1701 | /* load audio component topology from "firmware" file */ | ||
1702 | int snd_soc_tplg_component_load(struct snd_soc_component *comp, | ||
1703 | struct snd_soc_tplg_ops *ops, const struct firmware *fw, u32 id) | ||
1704 | { | ||
1705 | struct soc_tplg tplg; | ||
1706 | |||
1707 | /* setup parsing context */ | ||
1708 | memset(&tplg, 0, sizeof(tplg)); | ||
1709 | tplg.fw = fw; | ||
1710 | tplg.dev = comp->dev; | ||
1711 | tplg.comp = comp; | ||
1712 | tplg.ops = ops; | ||
1713 | tplg.req_index = id; | ||
1714 | tplg.io_ops = ops->io_ops; | ||
1715 | tplg.io_ops_count = ops->io_ops_count; | ||
1716 | |||
1717 | return soc_tplg_load(&tplg); | ||
1718 | } | ||
1719 | EXPORT_SYMBOL_GPL(snd_soc_tplg_component_load); | ||
1720 | |||
1721 | /* remove this dynamic widget */ | ||
1722 | void snd_soc_tplg_widget_remove(struct snd_soc_dapm_widget *w) | ||
1723 | { | ||
1724 | /* make sure we are a widget */ | ||
1725 | if (w->dobj.type != SND_SOC_DOBJ_WIDGET) | ||
1726 | return; | ||
1727 | |||
1728 | remove_widget(w->dapm->component, &w->dobj, SOC_TPLG_PASS_WIDGET); | ||
1729 | } | ||
1730 | EXPORT_SYMBOL_GPL(snd_soc_tplg_widget_remove); | ||
1731 | |||
1732 | /* remove all dynamic widgets from this DAPM context */ | ||
1733 | void snd_soc_tplg_widget_remove_all(struct snd_soc_dapm_context *dapm, | ||
1734 | u32 index) | ||
1735 | { | ||
1736 | struct snd_soc_dapm_widget *w, *next_w; | ||
1737 | struct snd_soc_dapm_path *p, *next_p; | ||
1738 | |||
1739 | list_for_each_entry_safe(w, next_w, &dapm->card->widgets, list) { | ||
1740 | |||
1741 | /* make sure we are a widget with correct context */ | ||
1742 | if (w->dobj.type != SND_SOC_DOBJ_WIDGET || w->dapm != dapm) | ||
1743 | continue; | ||
1744 | |||
1745 | /* match ID */ | ||
1746 | if (w->dobj.index != index && | ||
1747 | w->dobj.index != SND_SOC_TPLG_INDEX_ALL) | ||
1748 | continue; | ||
1749 | |||
1750 | list_del(&w->list); | ||
1751 | |||
1752 | /* | ||
1753 | * remove source and sink paths associated to this widget. | ||
1754 | * While removing the path, remove reference to it from both | ||
1755 | * source and sink widgets so that path is removed only once. | ||
1756 | */ | ||
1757 | list_for_each_entry_safe(p, next_p, &w->sources, list_sink) { | ||
1758 | list_del(&p->list_sink); | ||
1759 | list_del(&p->list_source); | ||
1760 | list_del(&p->list); | ||
1761 | kfree(p); | ||
1762 | } | ||
1763 | list_for_each_entry_safe(p, next_p, &w->sinks, list_source) { | ||
1764 | list_del(&p->list_sink); | ||
1765 | list_del(&p->list_source); | ||
1766 | list_del(&p->list); | ||
1767 | kfree(p); | ||
1768 | } | ||
1769 | /* check and free and dynamic widget kcontrols */ | ||
1770 | snd_soc_tplg_widget_remove(w); | ||
1771 | kfree(w->kcontrols); | ||
1772 | kfree(w->name); | ||
1773 | kfree(w); | ||
1774 | } | ||
1775 | } | ||
1776 | EXPORT_SYMBOL_GPL(snd_soc_tplg_widget_remove_all); | ||
1777 | |||
1778 | /* remove dynamic controls from the component driver */ | ||
1779 | int snd_soc_tplg_component_remove(struct snd_soc_component *comp, u32 index) | ||
1780 | { | ||
1781 | struct snd_soc_dobj *dobj, *next_dobj; | ||
1782 | int pass = SOC_TPLG_PASS_END; | ||
1783 | |||
1784 | /* process the header types from end to start */ | ||
1785 | while (pass >= SOC_TPLG_PASS_START) { | ||
1786 | |||
1787 | /* remove mixer controls */ | ||
1788 | list_for_each_entry_safe(dobj, next_dobj, &comp->dobj_list, | ||
1789 | list) { | ||
1790 | |||
1791 | /* match index */ | ||
1792 | if (dobj->index != index && | ||
1793 | dobj->index != SND_SOC_TPLG_INDEX_ALL) | ||
1794 | continue; | ||
1795 | |||
1796 | switch (dobj->type) { | ||
1797 | case SND_SOC_DOBJ_MIXER: | ||
1798 | remove_mixer(comp, dobj, pass); | ||
1799 | break; | ||
1800 | case SND_SOC_DOBJ_ENUM: | ||
1801 | remove_enum(comp, dobj, pass); | ||
1802 | break; | ||
1803 | case SND_SOC_DOBJ_BYTES: | ||
1804 | remove_bytes(comp, dobj, pass); | ||
1805 | break; | ||
1806 | case SND_SOC_DOBJ_WIDGET: | ||
1807 | remove_widget(comp, dobj, pass); | ||
1808 | break; | ||
1809 | case SND_SOC_DOBJ_PCM: | ||
1810 | case SND_SOC_DOBJ_DAI_LINK: | ||
1811 | case SND_SOC_DOBJ_CODEC_LINK: | ||
1812 | remove_pcm_dai(comp, dobj, pass); | ||
1813 | break; | ||
1814 | default: | ||
1815 | dev_err(comp->dev, "ASoC: invalid component type %d for removal\n", | ||
1816 | dobj->type); | ||
1817 | break; | ||
1818 | } | ||
1819 | } | ||
1820 | pass--; | ||
1821 | } | ||
1822 | |||
1823 | /* let caller know if FW can be freed when no objects are left */ | ||
1824 | return !list_empty(&comp->dobj_list); | ||
1825 | } | ||
1826 | EXPORT_SYMBOL_GPL(snd_soc_tplg_component_remove); | ||
diff --git a/sound/soc/ux500/mop500_ab8500.c b/sound/soc/ux500/mop500_ab8500.c index b81a7a4c938b..85d810d7667c 100644 --- a/sound/soc/ux500/mop500_ab8500.c +++ b/sound/soc/ux500/mop500_ab8500.c | |||
@@ -372,6 +372,10 @@ int mop500_ab8500_machine_init(struct snd_soc_pcm_runtime *rtd) | |||
372 | /* Create driver private-data struct */ | 372 | /* Create driver private-data struct */ |
373 | drvdata = devm_kzalloc(dev, sizeof(struct mop500_ab8500_drvdata), | 373 | drvdata = devm_kzalloc(dev, sizeof(struct mop500_ab8500_drvdata), |
374 | GFP_KERNEL); | 374 | GFP_KERNEL); |
375 | |||
376 | if (!drvdata) | ||
377 | return -ENOMEM; | ||
378 | |||
375 | snd_soc_card_set_drvdata(rtd->card, drvdata); | 379 | snd_soc_card_set_drvdata(rtd->card, drvdata); |
376 | 380 | ||
377 | /* Setup clocks */ | 381 | /* Setup clocks */ |
diff --git a/sound/soc/ux500/ux500_pcm.c b/sound/soc/ux500/ux500_pcm.c index 51a66a87305a..f12c01dddc8d 100644 --- a/sound/soc/ux500/ux500_pcm.c +++ b/sound/soc/ux500/ux500_pcm.c | |||
@@ -147,7 +147,6 @@ int ux500_pcm_register_platform(struct platform_device *pdev) | |||
147 | pcm_config = &ux500_dmaengine_pcm_config; | 147 | pcm_config = &ux500_dmaengine_pcm_config; |
148 | 148 | ||
149 | ret = snd_dmaengine_pcm_register(&pdev->dev, pcm_config, | 149 | ret = snd_dmaengine_pcm_register(&pdev->dev, pcm_config, |
150 | SND_DMAENGINE_PCM_FLAG_NO_RESIDUE | | ||
151 | SND_DMAENGINE_PCM_FLAG_COMPAT); | 150 | SND_DMAENGINE_PCM_FLAG_COMPAT); |
152 | if (ret < 0) { | 151 | if (ret < 0) { |
153 | dev_err(&pdev->dev, | 152 | dev_err(&pdev->dev, |
diff --git a/sound/soc/zte/Kconfig b/sound/soc/zte/Kconfig new file mode 100644 index 000000000000..c47eb25e441f --- /dev/null +++ b/sound/soc/zte/Kconfig | |||
@@ -0,0 +1,17 @@ | |||
1 | config ZX296702_SPDIF | ||
2 | tristate "ZX296702 spdif" | ||
3 | depends on SOC_ZX296702 || COMPILE_TEST | ||
4 | depends on COMMON_CLK | ||
5 | select SND_SOC_GENERIC_DMAENGINE_PCM | ||
6 | help | ||
7 | Say Y or M if you want to add support for codecs attached to the | ||
8 | zx296702 spdif interface | ||
9 | |||
10 | config ZX296702_I2S | ||
11 | tristate "ZX296702 i2s" | ||
12 | depends on SOC_ZX296702 || COMPILE_TEST | ||
13 | depends on COMMON_CLK | ||
14 | select SND_SOC_GENERIC_DMAENGINE_PCM | ||
15 | help | ||
16 | Say Y or M if you want to add support for codecs attached to the | ||
17 | zx296702 i2s interface | ||
diff --git a/sound/soc/zte/Makefile b/sound/soc/zte/Makefile new file mode 100644 index 000000000000..254ed2c8c1a0 --- /dev/null +++ b/sound/soc/zte/Makefile | |||
@@ -0,0 +1,2 @@ | |||
1 | obj-$(CONFIG_ZX296702_SPDIF) += zx296702-spdif.o | ||
2 | obj-$(CONFIG_ZX296702_I2S) += zx296702-i2s.o | ||
diff --git a/sound/soc/zte/zx296702-i2s.c b/sound/soc/zte/zx296702-i2s.c new file mode 100644 index 000000000000..98d96e1b17e0 --- /dev/null +++ b/sound/soc/zte/zx296702-i2s.c | |||
@@ -0,0 +1,436 @@ | |||
1 | /* | ||
2 | * Copyright (C) 2015 Linaro | ||
3 | * | ||
4 | * Author: Jun Nie <jun.nie@linaro.org> | ||
5 | * | ||
6 | * License terms: GNU General Public License (GPL) version 2 | ||
7 | */ | ||
8 | |||
9 | #include <linux/clk.h> | ||
10 | #include <linux/device.h> | ||
11 | #include <linux/init.h> | ||
12 | #include <linux/io.h> | ||
13 | #include <linux/kernel.h> | ||
14 | #include <linux/module.h> | ||
15 | #include <sound/pcm.h> | ||
16 | #include <sound/pcm_params.h> | ||
17 | #include <sound/soc.h> | ||
18 | #include <sound/soc-dai.h> | ||
19 | |||
20 | #include <sound/core.h> | ||
21 | #include <sound/dmaengine_pcm.h> | ||
22 | #include <sound/initval.h> | ||
23 | #include <sound/pcm.h> | ||
24 | #include <sound/pcm_params.h> | ||
25 | #include <sound/soc.h> | ||
26 | |||
27 | #define ZX_I2S_PROCESS_CTRL 0x04 | ||
28 | #define ZX_I2S_TIMING_CTRL 0x08 | ||
29 | #define ZX_I2S_FIFO_CTRL 0x0C | ||
30 | #define ZX_I2S_FIFO_STATUS 0x10 | ||
31 | #define ZX_I2S_INT_EN 0x14 | ||
32 | #define ZX_I2S_INT_STATUS 0x18 | ||
33 | #define ZX_I2S_DATA 0x1C | ||
34 | #define ZX_I2S_FRAME_CNTR 0x20 | ||
35 | |||
36 | #define I2S_DEAGULT_FIFO_THRES (0x10) | ||
37 | #define I2S_MAX_FIFO_THRES (0x20) | ||
38 | |||
39 | #define ZX_I2S_PROCESS_TX_EN (1 << 0) | ||
40 | #define ZX_I2S_PROCESS_TX_DIS (0 << 0) | ||
41 | #define ZX_I2S_PROCESS_RX_EN (1 << 1) | ||
42 | #define ZX_I2S_PROCESS_RX_DIS (0 << 1) | ||
43 | #define ZX_I2S_PROCESS_I2S_EN (1 << 2) | ||
44 | #define ZX_I2S_PROCESS_I2S_DIS (0 << 2) | ||
45 | |||
46 | #define ZX_I2S_TIMING_MAST (1 << 0) | ||
47 | #define ZX_I2S_TIMING_SLAVE (0 << 0) | ||
48 | #define ZX_I2S_TIMING_MS_MASK (1 << 0) | ||
49 | #define ZX_I2S_TIMING_LOOP (1 << 1) | ||
50 | #define ZX_I2S_TIMING_NOR (0 << 1) | ||
51 | #define ZX_I2S_TIMING_LOOP_MASK (1 << 1) | ||
52 | #define ZX_I2S_TIMING_PTNR (1 << 2) | ||
53 | #define ZX_I2S_TIMING_NTPR (0 << 2) | ||
54 | #define ZX_I2S_TIMING_PHASE_MASK (1 << 2) | ||
55 | #define ZX_I2S_TIMING_TDM (1 << 3) | ||
56 | #define ZX_I2S_TIMING_I2S (0 << 3) | ||
57 | #define ZX_I2S_TIMING_TIMING_MASK (1 << 3) | ||
58 | #define ZX_I2S_TIMING_LONG_SYNC (1 << 4) | ||
59 | #define ZX_I2S_TIMING_SHORT_SYNC (0 << 4) | ||
60 | #define ZX_I2S_TIMING_SYNC_MASK (1 << 4) | ||
61 | #define ZX_I2S_TIMING_TEAK_EN (1 << 5) | ||
62 | #define ZX_I2S_TIMING_TEAK_DIS (0 << 5) | ||
63 | #define ZX_I2S_TIMING_TEAK_MASK (1 << 5) | ||
64 | #define ZX_I2S_TIMING_STD_I2S (0 << 6) | ||
65 | #define ZX_I2S_TIMING_MSB_JUSTIF (1 << 6) | ||
66 | #define ZX_I2S_TIMING_LSB_JUSTIF (2 << 6) | ||
67 | #define ZX_I2S_TIMING_ALIGN_MASK (3 << 6) | ||
68 | #define ZX_I2S_TIMING_CHN_MASK (7 << 8) | ||
69 | #define ZX_I2S_TIMING_CHN(x) ((x - 1) << 8) | ||
70 | #define ZX_I2S_TIMING_LANE_MASK (3 << 11) | ||
71 | #define ZX_I2S_TIMING_LANE(x) ((x - 1) << 11) | ||
72 | #define ZX_I2S_TIMING_TSCFG_MASK (7 << 13) | ||
73 | #define ZX_I2S_TIMING_TSCFG(x) (x << 13) | ||
74 | #define ZX_I2S_TIMING_TS_WIDTH_MASK (0x1f << 16) | ||
75 | #define ZX_I2S_TIMING_TS_WIDTH(x) ((x - 1) << 16) | ||
76 | #define ZX_I2S_TIMING_DATA_SIZE_MASK (0x1f << 21) | ||
77 | #define ZX_I2S_TIMING_DATA_SIZE(x) ((x - 1) << 21) | ||
78 | #define ZX_I2S_TIMING_CFG_ERR_MASK (1 << 31) | ||
79 | |||
80 | #define ZX_I2S_FIFO_CTRL_TX_RST (1 << 0) | ||
81 | #define ZX_I2S_FIFO_CTRL_TX_RST_MASK (1 << 0) | ||
82 | #define ZX_I2S_FIFO_CTRL_RX_RST (1 << 1) | ||
83 | #define ZX_I2S_FIFO_CTRL_RX_RST_MASK (1 << 1) | ||
84 | #define ZX_I2S_FIFO_CTRL_TX_DMA_EN (1 << 4) | ||
85 | #define ZX_I2S_FIFO_CTRL_TX_DMA_DIS (0 << 4) | ||
86 | #define ZX_I2S_FIFO_CTRL_TX_DMA_MASK (1 << 4) | ||
87 | #define ZX_I2S_FIFO_CTRL_RX_DMA_EN (1 << 5) | ||
88 | #define ZX_I2S_FIFO_CTRL_RX_DMA_DIS (0 << 5) | ||
89 | #define ZX_I2S_FIFO_CTRL_RX_DMA_MASK (1 << 5) | ||
90 | #define ZX_I2S_FIFO_CTRL_TX_THRES_MASK (0x1F << 8) | ||
91 | #define ZX_I2S_FIFO_CTRL_RX_THRES_MASK (0x1F << 16) | ||
92 | |||
93 | #define CLK_RAT (32 * 4) | ||
94 | |||
95 | struct zx_i2s_info { | ||
96 | struct snd_dmaengine_dai_dma_data dma_playback; | ||
97 | struct snd_dmaengine_dai_dma_data dma_capture; | ||
98 | struct clk *dai_clk; | ||
99 | void __iomem *reg_base; | ||
100 | int master; | ||
101 | resource_size_t mapbase; | ||
102 | }; | ||
103 | |||
104 | static void zx_i2s_tx_en(void __iomem *base, bool on) | ||
105 | { | ||
106 | unsigned long val; | ||
107 | |||
108 | val = readl_relaxed(base + ZX_I2S_PROCESS_CTRL); | ||
109 | if (on) | ||
110 | val |= ZX_I2S_PROCESS_TX_EN | ZX_I2S_PROCESS_I2S_EN; | ||
111 | else | ||
112 | val &= ~(ZX_I2S_PROCESS_TX_EN | ZX_I2S_PROCESS_I2S_EN); | ||
113 | writel_relaxed(val, base + ZX_I2S_PROCESS_CTRL); | ||
114 | } | ||
115 | |||
116 | static void zx_i2s_rx_en(void __iomem *base, bool on) | ||
117 | { | ||
118 | unsigned long val; | ||
119 | |||
120 | val = readl_relaxed(base + ZX_I2S_PROCESS_CTRL); | ||
121 | if (on) | ||
122 | val |= ZX_I2S_PROCESS_RX_EN | ZX_I2S_PROCESS_I2S_EN; | ||
123 | else | ||
124 | val &= ~(ZX_I2S_PROCESS_RX_EN | ZX_I2S_PROCESS_I2S_EN); | ||
125 | writel_relaxed(val, base + ZX_I2S_PROCESS_CTRL); | ||
126 | } | ||
127 | |||
128 | static void zx_i2s_tx_dma_en(void __iomem *base, bool on) | ||
129 | { | ||
130 | unsigned long val; | ||
131 | |||
132 | val = readl_relaxed(base + ZX_I2S_FIFO_CTRL); | ||
133 | val |= ZX_I2S_FIFO_CTRL_TX_RST | (I2S_DEAGULT_FIFO_THRES << 8); | ||
134 | if (on) | ||
135 | val |= ZX_I2S_FIFO_CTRL_TX_DMA_EN; | ||
136 | else | ||
137 | val &= ~ZX_I2S_FIFO_CTRL_TX_DMA_EN; | ||
138 | writel_relaxed(val, base + ZX_I2S_FIFO_CTRL); | ||
139 | } | ||
140 | |||
141 | static void zx_i2s_rx_dma_en(void __iomem *base, bool on) | ||
142 | { | ||
143 | unsigned long val; | ||
144 | |||
145 | val = readl_relaxed(base + ZX_I2S_FIFO_CTRL); | ||
146 | val |= ZX_I2S_FIFO_CTRL_RX_RST | (I2S_DEAGULT_FIFO_THRES << 16); | ||
147 | if (on) | ||
148 | val |= ZX_I2S_FIFO_CTRL_RX_DMA_EN; | ||
149 | else | ||
150 | val &= ~ZX_I2S_FIFO_CTRL_RX_DMA_EN; | ||
151 | writel_relaxed(val, base + ZX_I2S_FIFO_CTRL); | ||
152 | } | ||
153 | |||
154 | #define ZX_I2S_RATES \ | ||
155 | (SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_11025 | SNDRV_PCM_RATE_16000 | \ | ||
156 | SNDRV_PCM_RATE_22050 | SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_44100 | \ | ||
157 | SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_88200 | SNDRV_PCM_RATE_96000| \ | ||
158 | SNDRV_PCM_RATE_176400 | SNDRV_PCM_RATE_192000) | ||
159 | |||
160 | #define ZX_I2S_FMTBIT \ | ||
161 | (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S24_LE | \ | ||
162 | SNDRV_PCM_FMTBIT_S32_LE) | ||
163 | |||
164 | static int zx_i2s_dai_probe(struct snd_soc_dai *dai) | ||
165 | { | ||
166 | struct zx_i2s_info *zx_i2s = dev_get_drvdata(dai->dev); | ||
167 | |||
168 | snd_soc_dai_set_drvdata(dai, zx_i2s); | ||
169 | zx_i2s->dma_playback.addr = zx_i2s->mapbase + ZX_I2S_DATA; | ||
170 | zx_i2s->dma_playback.maxburst = 16; | ||
171 | zx_i2s->dma_capture.addr = zx_i2s->mapbase + ZX_I2S_DATA; | ||
172 | zx_i2s->dma_capture.maxburst = 16; | ||
173 | snd_soc_dai_init_dma_data(dai, &zx_i2s->dma_playback, | ||
174 | &zx_i2s->dma_capture); | ||
175 | return 0; | ||
176 | } | ||
177 | |||
178 | static int zx_i2s_set_fmt(struct snd_soc_dai *cpu_dai, unsigned int fmt) | ||
179 | { | ||
180 | struct zx_i2s_info *i2s = snd_soc_dai_get_drvdata(cpu_dai); | ||
181 | unsigned long val; | ||
182 | |||
183 | val = readl_relaxed(i2s->reg_base + ZX_I2S_TIMING_CTRL); | ||
184 | val &= ~(ZX_I2S_TIMING_TIMING_MASK | ZX_I2S_TIMING_ALIGN_MASK | | ||
185 | ZX_I2S_TIMING_TEAK_MASK | ZX_I2S_TIMING_SYNC_MASK | | ||
186 | ZX_I2S_TIMING_MS_MASK); | ||
187 | |||
188 | switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) { | ||
189 | case SND_SOC_DAIFMT_I2S: | ||
190 | val |= (ZX_I2S_TIMING_I2S | ZX_I2S_TIMING_STD_I2S); | ||
191 | break; | ||
192 | case SND_SOC_DAIFMT_LEFT_J: | ||
193 | val |= (ZX_I2S_TIMING_I2S | ZX_I2S_TIMING_MSB_JUSTIF); | ||
194 | break; | ||
195 | case SND_SOC_DAIFMT_RIGHT_J: | ||
196 | val |= (ZX_I2S_TIMING_I2S | ZX_I2S_TIMING_LSB_JUSTIF); | ||
197 | break; | ||
198 | default: | ||
199 | dev_err(cpu_dai->dev, "Unknown i2s timeing\n"); | ||
200 | return -EINVAL; | ||
201 | } | ||
202 | |||
203 | switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { | ||
204 | case SND_SOC_DAIFMT_CBM_CFM: | ||
205 | i2s->master = 1; | ||
206 | val |= ZX_I2S_TIMING_MAST; | ||
207 | break; | ||
208 | case SND_SOC_DAIFMT_CBS_CFS: | ||
209 | i2s->master = 0; | ||
210 | val |= ZX_I2S_TIMING_SLAVE; | ||
211 | break; | ||
212 | default: | ||
213 | dev_err(cpu_dai->dev, "Unknown master/slave format\n"); | ||
214 | return -EINVAL; | ||
215 | } | ||
216 | |||
217 | writel_relaxed(val, i2s->reg_base + ZX_I2S_TIMING_CTRL); | ||
218 | return 0; | ||
219 | } | ||
220 | |||
221 | static int zx_i2s_hw_params(struct snd_pcm_substream *substream, | ||
222 | struct snd_pcm_hw_params *params, | ||
223 | struct snd_soc_dai *socdai) | ||
224 | { | ||
225 | struct zx_i2s_info *i2s = snd_soc_dai_get_drvdata(socdai); | ||
226 | struct snd_dmaengine_dai_dma_data *dma_data; | ||
227 | unsigned int lane, ch_num, len, ret = 0; | ||
228 | unsigned long val, format; | ||
229 | unsigned long chn_cfg; | ||
230 | |||
231 | dma_data = snd_soc_dai_get_dma_data(socdai, substream); | ||
232 | dma_data->addr_width = params_width(params) >> 3; | ||
233 | |||
234 | val = readl_relaxed(i2s->reg_base + ZX_I2S_TIMING_CTRL); | ||
235 | val &= ~(ZX_I2S_TIMING_TS_WIDTH_MASK | ZX_I2S_TIMING_DATA_SIZE_MASK | | ||
236 | ZX_I2S_TIMING_LANE_MASK | ZX_I2S_TIMING_CHN_MASK | | ||
237 | ZX_I2S_TIMING_TSCFG_MASK); | ||
238 | |||
239 | switch (params_format(params)) { | ||
240 | case SNDRV_PCM_FORMAT_S16_LE: | ||
241 | format = 0; | ||
242 | len = 16; | ||
243 | break; | ||
244 | case SNDRV_PCM_FORMAT_S24_LE: | ||
245 | format = 1; | ||
246 | len = 24; | ||
247 | break; | ||
248 | case SNDRV_PCM_FORMAT_S32_LE: | ||
249 | format = 2; | ||
250 | len = 32; | ||
251 | break; | ||
252 | default: | ||
253 | dev_err(socdai->dev, "Unknown data format\n"); | ||
254 | return -EINVAL; | ||
255 | } | ||
256 | val |= ZX_I2S_TIMING_TS_WIDTH(len) | ZX_I2S_TIMING_DATA_SIZE(len); | ||
257 | |||
258 | ch_num = params_channels(params); | ||
259 | switch (ch_num) { | ||
260 | case 1: | ||
261 | lane = 1; | ||
262 | chn_cfg = 2; | ||
263 | break; | ||
264 | case 2: | ||
265 | case 4: | ||
266 | case 6: | ||
267 | case 8: | ||
268 | lane = ch_num / 2; | ||
269 | chn_cfg = 3; | ||
270 | break; | ||
271 | default: | ||
272 | dev_err(socdai->dev, "Not support channel num %d\n", ch_num); | ||
273 | return -EINVAL; | ||
274 | } | ||
275 | val |= ZX_I2S_TIMING_LANE(lane); | ||
276 | val |= ZX_I2S_TIMING_TSCFG(chn_cfg); | ||
277 | val |= ZX_I2S_TIMING_CHN(ch_num); | ||
278 | writel_relaxed(val, i2s->reg_base + ZX_I2S_TIMING_CTRL); | ||
279 | |||
280 | if (i2s->master) | ||
281 | ret = clk_set_rate(i2s->dai_clk, | ||
282 | params_rate(params) * ch_num * CLK_RAT); | ||
283 | return ret; | ||
284 | } | ||
285 | |||
286 | static int zx_i2s_trigger(struct snd_pcm_substream *substream, int cmd, | ||
287 | struct snd_soc_dai *dai) | ||
288 | { | ||
289 | struct zx_i2s_info *zx_i2s = dev_get_drvdata(dai->dev); | ||
290 | int capture = (substream->stream == SNDRV_PCM_STREAM_CAPTURE); | ||
291 | int ret = 0; | ||
292 | |||
293 | switch (cmd) { | ||
294 | case SNDRV_PCM_TRIGGER_START: | ||
295 | if (capture) | ||
296 | zx_i2s_rx_dma_en(zx_i2s->reg_base, true); | ||
297 | else | ||
298 | zx_i2s_tx_dma_en(zx_i2s->reg_base, true); | ||
299 | /* fall thru */ | ||
300 | case SNDRV_PCM_TRIGGER_RESUME: | ||
301 | case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: | ||
302 | if (capture) | ||
303 | zx_i2s_rx_en(zx_i2s->reg_base, true); | ||
304 | else | ||
305 | zx_i2s_tx_en(zx_i2s->reg_base, true); | ||
306 | break; | ||
307 | |||
308 | case SNDRV_PCM_TRIGGER_STOP: | ||
309 | if (capture) | ||
310 | zx_i2s_rx_dma_en(zx_i2s->reg_base, false); | ||
311 | else | ||
312 | zx_i2s_tx_dma_en(zx_i2s->reg_base, false); | ||
313 | /* fall thru */ | ||
314 | case SNDRV_PCM_TRIGGER_SUSPEND: | ||
315 | case SNDRV_PCM_TRIGGER_PAUSE_PUSH: | ||
316 | if (capture) | ||
317 | zx_i2s_rx_en(zx_i2s->reg_base, false); | ||
318 | else | ||
319 | zx_i2s_tx_en(zx_i2s->reg_base, false); | ||
320 | break; | ||
321 | |||
322 | default: | ||
323 | ret = -EINVAL; | ||
324 | break; | ||
325 | } | ||
326 | |||
327 | return ret; | ||
328 | } | ||
329 | |||
330 | static int zx_i2s_startup(struct snd_pcm_substream *substream, | ||
331 | struct snd_soc_dai *dai) | ||
332 | { | ||
333 | struct zx_i2s_info *zx_i2s = dev_get_drvdata(dai->dev); | ||
334 | |||
335 | return clk_prepare_enable(zx_i2s->dai_clk); | ||
336 | } | ||
337 | |||
338 | static void zx_i2s_shutdown(struct snd_pcm_substream *substream, | ||
339 | struct snd_soc_dai *dai) | ||
340 | { | ||
341 | struct zx_i2s_info *zx_i2s = dev_get_drvdata(dai->dev); | ||
342 | |||
343 | clk_disable_unprepare(zx_i2s->dai_clk); | ||
344 | } | ||
345 | |||
346 | static struct snd_soc_dai_ops zx_i2s_dai_ops = { | ||
347 | .trigger = zx_i2s_trigger, | ||
348 | .hw_params = zx_i2s_hw_params, | ||
349 | .set_fmt = zx_i2s_set_fmt, | ||
350 | .startup = zx_i2s_startup, | ||
351 | .shutdown = zx_i2s_shutdown, | ||
352 | }; | ||
353 | |||
354 | static const struct snd_soc_component_driver zx_i2s_component = { | ||
355 | .name = "zx-i2s", | ||
356 | }; | ||
357 | |||
358 | static struct snd_soc_dai_driver zx_i2s_dai = { | ||
359 | .name = "zx-i2s-dai", | ||
360 | .id = 0, | ||
361 | .probe = zx_i2s_dai_probe, | ||
362 | .playback = { | ||
363 | .channels_min = 1, | ||
364 | .channels_max = 8, | ||
365 | .rates = ZX_I2S_RATES, | ||
366 | .formats = ZX_I2S_FMTBIT, | ||
367 | }, | ||
368 | .capture = { | ||
369 | .channels_min = 1, | ||
370 | .channels_max = 2, | ||
371 | .rates = ZX_I2S_RATES, | ||
372 | .formats = ZX_I2S_FMTBIT, | ||
373 | }, | ||
374 | .ops = &zx_i2s_dai_ops, | ||
375 | }; | ||
376 | |||
377 | static int zx_i2s_probe(struct platform_device *pdev) | ||
378 | { | ||
379 | struct resource *res; | ||
380 | struct zx_i2s_info *zx_i2s; | ||
381 | int ret; | ||
382 | |||
383 | zx_i2s = kzalloc(sizeof(*zx_i2s), GFP_KERNEL); | ||
384 | if (!zx_i2s) | ||
385 | return -ENOMEM; | ||
386 | |||
387 | zx_i2s->dai_clk = devm_clk_get(&pdev->dev, "tx"); | ||
388 | if (IS_ERR(zx_i2s->dai_clk)) { | ||
389 | dev_err(&pdev->dev, "Fail to get clk\n"); | ||
390 | return PTR_ERR(zx_i2s->dai_clk); | ||
391 | } | ||
392 | |||
393 | res = platform_get_resource(pdev, IORESOURCE_MEM, 0); | ||
394 | zx_i2s->mapbase = res->start; | ||
395 | zx_i2s->reg_base = devm_ioremap_resource(&pdev->dev, res); | ||
396 | if (!zx_i2s->reg_base) { | ||
397 | dev_err(&pdev->dev, "ioremap failed!\n"); | ||
398 | return -EIO; | ||
399 | } | ||
400 | |||
401 | writel_relaxed(0, zx_i2s->reg_base + ZX_I2S_FIFO_CTRL); | ||
402 | platform_set_drvdata(pdev, zx_i2s); | ||
403 | |||
404 | ret = snd_soc_register_component(&pdev->dev, &zx_i2s_component, | ||
405 | &zx_i2s_dai, 1); | ||
406 | if (ret) { | ||
407 | dev_err(&pdev->dev, "Register DAI failed: %d\n", ret); | ||
408 | return ret; | ||
409 | } | ||
410 | |||
411 | ret = devm_snd_dmaengine_pcm_register(&pdev->dev, NULL, 0); | ||
412 | if (ret) | ||
413 | dev_err(&pdev->dev, "Register platform PCM failed: %d\n", ret); | ||
414 | |||
415 | return ret; | ||
416 | } | ||
417 | |||
418 | static const struct of_device_id zx_i2s_dt_ids[] = { | ||
419 | { .compatible = "zte,zx296702-i2s", }, | ||
420 | {} | ||
421 | }; | ||
422 | MODULE_DEVICE_TABLE(of, zx_i2s_dt_ids); | ||
423 | |||
424 | static struct platform_driver i2s_driver = { | ||
425 | .probe = zx_i2s_probe, | ||
426 | .driver = { | ||
427 | .name = "zx-i2s", | ||
428 | .of_match_table = zx_i2s_dt_ids, | ||
429 | }, | ||
430 | }; | ||
431 | |||
432 | module_platform_driver(i2s_driver); | ||
433 | |||
434 | MODULE_AUTHOR("Jun Nie <jun.nie@linaro.org>"); | ||
435 | MODULE_DESCRIPTION("ZTE I2S SoC DAI"); | ||
436 | MODULE_LICENSE("GPL"); | ||
diff --git a/sound/soc/zte/zx296702-spdif.c b/sound/soc/zte/zx296702-spdif.c new file mode 100644 index 000000000000..11a0e46a1156 --- /dev/null +++ b/sound/soc/zte/zx296702-spdif.c | |||
@@ -0,0 +1,365 @@ | |||
1 | /* | ||
2 | * Copyright (C) 2015 Linaro | ||
3 | * | ||
4 | * Author: Jun Nie <jun.nie@linaro.org> | ||
5 | * | ||
6 | * License terms: GNU General Public License (GPL) version 2 | ||
7 | */ | ||
8 | |||
9 | #include <linux/clk.h> | ||
10 | #include <linux/device.h> | ||
11 | #include <linux/dmaengine.h> | ||
12 | #include <linux/init.h> | ||
13 | #include <linux/io.h> | ||
14 | #include <linux/kernel.h> | ||
15 | #include <linux/module.h> | ||
16 | #include <linux/of_address.h> | ||
17 | #include <sound/asoundef.h> | ||
18 | #include <sound/core.h> | ||
19 | #include <sound/dmaengine_pcm.h> | ||
20 | #include <sound/initval.h> | ||
21 | #include <sound/pcm.h> | ||
22 | #include <sound/pcm_params.h> | ||
23 | #include <sound/soc.h> | ||
24 | #include <sound/soc-dai.h> | ||
25 | |||
26 | #define ZX_CTRL 0x04 | ||
27 | #define ZX_FIFOCTRL 0x08 | ||
28 | #define ZX_INT_STATUS 0x10 | ||
29 | #define ZX_INT_MASK 0x14 | ||
30 | #define ZX_DATA 0x18 | ||
31 | #define ZX_VALID_BIT 0x1c | ||
32 | #define ZX_CH_STA_1 0x20 | ||
33 | #define ZX_CH_STA_2 0x24 | ||
34 | #define ZX_CH_STA_3 0x28 | ||
35 | #define ZX_CH_STA_4 0x2c | ||
36 | #define ZX_CH_STA_5 0x30 | ||
37 | #define ZX_CH_STA_6 0x34 | ||
38 | |||
39 | #define ZX_CTRL_MODA_16 (0 << 6) | ||
40 | #define ZX_CTRL_MODA_18 BIT(6) | ||
41 | #define ZX_CTRL_MODA_20 (2 << 6) | ||
42 | #define ZX_CTRL_MODA_24 (3 << 6) | ||
43 | #define ZX_CTRL_MODA_MASK (3 << 6) | ||
44 | |||
45 | #define ZX_CTRL_ENB BIT(4) | ||
46 | #define ZX_CTRL_DNB (0 << 4) | ||
47 | #define ZX_CTRL_ENB_MASK BIT(4) | ||
48 | |||
49 | #define ZX_CTRL_TX_OPEN BIT(0) | ||
50 | #define ZX_CTRL_TX_CLOSE (0 << 0) | ||
51 | #define ZX_CTRL_TX_MASK BIT(0) | ||
52 | |||
53 | #define ZX_CTRL_OPEN (ZX_CTRL_TX_OPEN | ZX_CTRL_ENB) | ||
54 | #define ZX_CTRL_CLOSE (ZX_CTRL_TX_CLOSE | ZX_CTRL_DNB) | ||
55 | |||
56 | #define ZX_CTRL_DOUBLE_TRACK (0 << 8) | ||
57 | #define ZX_CTRL_LEFT_TRACK BIT(8) | ||
58 | #define ZX_CTRL_RIGHT_TRACK (2 << 8) | ||
59 | #define ZX_CTRL_TRACK_MASK (3 << 8) | ||
60 | |||
61 | #define ZX_FIFOCTRL_TXTH_MASK (0x1f << 8) | ||
62 | #define ZX_FIFOCTRL_TXTH(x) (x << 8) | ||
63 | #define ZX_FIFOCTRL_TX_DMA_EN BIT(2) | ||
64 | #define ZX_FIFOCTRL_TX_DMA_DIS (0 << 2) | ||
65 | #define ZX_FIFOCTRL_TX_DMA_EN_MASK BIT(2) | ||
66 | #define ZX_FIFOCTRL_TX_FIFO_RST BIT(0) | ||
67 | #define ZX_FIFOCTRL_TX_FIFO_RST_MASK BIT(0) | ||
68 | |||
69 | #define ZX_VALID_DOUBLE_TRACK (0 << 0) | ||
70 | #define ZX_VALID_LEFT_TRACK BIT(1) | ||
71 | #define ZX_VALID_RIGHT_TRACK (2 << 0) | ||
72 | #define ZX_VALID_TRACK_MASK (3 << 0) | ||
73 | |||
74 | #define ZX_SPDIF_CLK_RAT (4 * 32) | ||
75 | |||
76 | struct zx_spdif_info { | ||
77 | struct snd_dmaengine_dai_dma_data dma_data; | ||
78 | struct clk *dai_clk; | ||
79 | void __iomem *reg_base; | ||
80 | resource_size_t mapbase; | ||
81 | }; | ||
82 | |||
83 | static int zx_spdif_dai_probe(struct snd_soc_dai *dai) | ||
84 | { | ||
85 | struct zx_spdif_info *zx_spdif = dev_get_drvdata(dai->dev); | ||
86 | |||
87 | snd_soc_dai_set_drvdata(dai, zx_spdif); | ||
88 | zx_spdif->dma_data.addr = zx_spdif->mapbase + ZX_DATA; | ||
89 | zx_spdif->dma_data.maxburst = 8; | ||
90 | snd_soc_dai_init_dma_data(dai, &zx_spdif->dma_data, NULL); | ||
91 | return 0; | ||
92 | } | ||
93 | |||
94 | static int zx_spdif_chanstats(void __iomem *base, unsigned int rate) | ||
95 | { | ||
96 | u32 cstas1; | ||
97 | |||
98 | switch (rate) { | ||
99 | case 22050: | ||
100 | cstas1 = IEC958_AES3_CON_FS_22050; | ||
101 | break; | ||
102 | case 24000: | ||
103 | cstas1 = IEC958_AES3_CON_FS_24000; | ||
104 | break; | ||
105 | case 32000: | ||
106 | cstas1 = IEC958_AES3_CON_FS_32000; | ||
107 | break; | ||
108 | case 44100: | ||
109 | cstas1 = IEC958_AES3_CON_FS_44100; | ||
110 | break; | ||
111 | case 48000: | ||
112 | cstas1 = IEC958_AES3_CON_FS_48000; | ||
113 | break; | ||
114 | case 88200: | ||
115 | cstas1 = IEC958_AES3_CON_FS_88200; | ||
116 | break; | ||
117 | case 96000: | ||
118 | cstas1 = IEC958_AES3_CON_FS_96000; | ||
119 | break; | ||
120 | case 176400: | ||
121 | cstas1 = IEC958_AES3_CON_FS_176400; | ||
122 | break; | ||
123 | case 192000: | ||
124 | cstas1 = IEC958_AES3_CON_FS_192000; | ||
125 | break; | ||
126 | default: | ||
127 | return -EINVAL; | ||
128 | } | ||
129 | cstas1 = cstas1 << 24; | ||
130 | cstas1 |= IEC958_AES0_CON_NOT_COPYRIGHT; | ||
131 | |||
132 | writel_relaxed(cstas1, base + ZX_CH_STA_1); | ||
133 | return 0; | ||
134 | } | ||
135 | |||
136 | static int zx_spdif_hw_params(struct snd_pcm_substream *substream, | ||
137 | struct snd_pcm_hw_params *params, | ||
138 | struct snd_soc_dai *socdai) | ||
139 | { | ||
140 | struct zx_spdif_info *zx_spdif = dev_get_drvdata(socdai->dev); | ||
141 | struct zx_spdif_info *spdif = snd_soc_dai_get_drvdata(socdai); | ||
142 | struct snd_dmaengine_dai_dma_data *dma_data = &zx_spdif->dma_data; | ||
143 | u32 val, ch_num, rate; | ||
144 | int ret; | ||
145 | |||
146 | dma_data = snd_soc_dai_get_dma_data(socdai, substream); | ||
147 | dma_data->addr_width = params_width(params) >> 3; | ||
148 | |||
149 | val = readl_relaxed(zx_spdif->reg_base + ZX_CTRL); | ||
150 | val &= ~ZX_CTRL_MODA_MASK; | ||
151 | switch (params_format(params)) { | ||
152 | case SNDRV_PCM_FORMAT_S16_LE: | ||
153 | val |= ZX_CTRL_MODA_16; | ||
154 | break; | ||
155 | |||
156 | case SNDRV_PCM_FORMAT_S18_3LE: | ||
157 | val |= ZX_CTRL_MODA_18; | ||
158 | break; | ||
159 | |||
160 | case SNDRV_PCM_FORMAT_S20_3LE: | ||
161 | val |= ZX_CTRL_MODA_20; | ||
162 | break; | ||
163 | |||
164 | case SNDRV_PCM_FORMAT_S24_LE: | ||
165 | val |= ZX_CTRL_MODA_24; | ||
166 | break; | ||
167 | default: | ||
168 | dev_err(socdai->dev, "Format not support!\n"); | ||
169 | return -EINVAL; | ||
170 | } | ||
171 | |||
172 | ch_num = params_channels(params); | ||
173 | if (ch_num == 2) | ||
174 | val |= ZX_CTRL_DOUBLE_TRACK; | ||
175 | else | ||
176 | val |= ZX_CTRL_LEFT_TRACK; | ||
177 | writel_relaxed(val, zx_spdif->reg_base + ZX_CTRL); | ||
178 | |||
179 | val = readl_relaxed(zx_spdif->reg_base + ZX_VALID_BIT); | ||
180 | val &= ~ZX_VALID_TRACK_MASK; | ||
181 | if (ch_num == 2) | ||
182 | val |= ZX_VALID_DOUBLE_TRACK; | ||
183 | else | ||
184 | val |= ZX_VALID_RIGHT_TRACK; | ||
185 | writel_relaxed(val, zx_spdif->reg_base + ZX_VALID_BIT); | ||
186 | |||
187 | rate = params_rate(params); | ||
188 | ret = zx_spdif_chanstats(zx_spdif->reg_base, rate); | ||
189 | if (ret) | ||
190 | return ret; | ||
191 | return clk_set_rate(spdif->dai_clk, rate * ch_num * ZX_SPDIF_CLK_RAT); | ||
192 | } | ||
193 | |||
194 | static void zx_spdif_cfg_tx(void __iomem *base, int on) | ||
195 | { | ||
196 | u32 val; | ||
197 | |||
198 | val = readl_relaxed(base + ZX_CTRL); | ||
199 | val &= ~(ZX_CTRL_ENB_MASK | ZX_CTRL_TX_MASK); | ||
200 | val |= on ? ZX_CTRL_OPEN : ZX_CTRL_CLOSE; | ||
201 | writel_relaxed(val, base + ZX_CTRL); | ||
202 | |||
203 | val = readl_relaxed(base + ZX_FIFOCTRL); | ||
204 | val &= ~ZX_FIFOCTRL_TX_DMA_EN_MASK; | ||
205 | if (on) | ||
206 | val |= ZX_FIFOCTRL_TX_DMA_EN; | ||
207 | writel_relaxed(val, base + ZX_FIFOCTRL); | ||
208 | } | ||
209 | |||
210 | static int zx_spdif_trigger(struct snd_pcm_substream *substream, int cmd, | ||
211 | struct snd_soc_dai *dai) | ||
212 | { | ||
213 | u32 val; | ||
214 | struct zx_spdif_info *zx_spdif = dev_get_drvdata(dai->dev); | ||
215 | int ret = 0; | ||
216 | |||
217 | switch (cmd) { | ||
218 | case SNDRV_PCM_TRIGGER_START: | ||
219 | val = readl_relaxed(zx_spdif->reg_base + ZX_FIFOCTRL); | ||
220 | val |= ZX_FIFOCTRL_TX_FIFO_RST; | ||
221 | writel_relaxed(val, zx_spdif->reg_base + ZX_FIFOCTRL); | ||
222 | /* fall thru */ | ||
223 | case SNDRV_PCM_TRIGGER_RESUME: | ||
224 | case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: | ||
225 | zx_spdif_cfg_tx(zx_spdif->reg_base, true); | ||
226 | break; | ||
227 | |||
228 | case SNDRV_PCM_TRIGGER_STOP: | ||
229 | case SNDRV_PCM_TRIGGER_SUSPEND: | ||
230 | case SNDRV_PCM_TRIGGER_PAUSE_PUSH: | ||
231 | zx_spdif_cfg_tx(zx_spdif->reg_base, false); | ||
232 | break; | ||
233 | |||
234 | default: | ||
235 | ret = -EINVAL; | ||
236 | break; | ||
237 | } | ||
238 | |||
239 | return ret; | ||
240 | } | ||
241 | |||
242 | static int zx_spdif_startup(struct snd_pcm_substream *substream, | ||
243 | struct snd_soc_dai *dai) | ||
244 | { | ||
245 | struct zx_spdif_info *zx_spdif = dev_get_drvdata(dai->dev); | ||
246 | |||
247 | return clk_prepare_enable(zx_spdif->dai_clk); | ||
248 | } | ||
249 | |||
250 | static void zx_spdif_shutdown(struct snd_pcm_substream *substream, | ||
251 | struct snd_soc_dai *dai) | ||
252 | { | ||
253 | struct zx_spdif_info *zx_spdif = dev_get_drvdata(dai->dev); | ||
254 | |||
255 | clk_disable_unprepare(zx_spdif->dai_clk); | ||
256 | } | ||
257 | |||
258 | #define ZX_RATES \ | ||
259 | (SNDRV_PCM_RATE_22050 | SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_44100 | \ | ||
260 | SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_88200 | SNDRV_PCM_RATE_96000 |\ | ||
261 | SNDRV_PCM_RATE_176400 | SNDRV_PCM_RATE_192000) | ||
262 | |||
263 | #define ZX_FORMAT \ | ||
264 | (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S18_3LE \ | ||
265 | | SNDRV_PCM_FMTBIT_S20_3LE | SNDRV_PCM_FMTBIT_S24_LE) | ||
266 | |||
267 | static struct snd_soc_dai_ops zx_spdif_dai_ops = { | ||
268 | .trigger = zx_spdif_trigger, | ||
269 | .startup = zx_spdif_startup, | ||
270 | .shutdown = zx_spdif_shutdown, | ||
271 | .hw_params = zx_spdif_hw_params, | ||
272 | }; | ||
273 | |||
274 | static struct snd_soc_dai_driver zx_spdif_dai = { | ||
275 | .name = "spdif", | ||
276 | .id = 0, | ||
277 | .probe = zx_spdif_dai_probe, | ||
278 | .playback = { | ||
279 | .channels_min = 1, | ||
280 | .channels_max = 2, | ||
281 | .rates = ZX_RATES, | ||
282 | .formats = ZX_FORMAT, | ||
283 | }, | ||
284 | .ops = &zx_spdif_dai_ops, | ||
285 | }; | ||
286 | |||
287 | static const struct snd_soc_component_driver zx_spdif_component = { | ||
288 | .name = "spdif", | ||
289 | }; | ||
290 | |||
291 | static void zx_spdif_dev_init(void __iomem *base) | ||
292 | { | ||
293 | u32 val; | ||
294 | |||
295 | writel_relaxed(0, base + ZX_CTRL); | ||
296 | writel_relaxed(0, base + ZX_INT_MASK); | ||
297 | writel_relaxed(0xf, base + ZX_INT_STATUS); | ||
298 | writel_relaxed(0x1, base + ZX_FIFOCTRL); | ||
299 | |||
300 | val = readl_relaxed(base + ZX_FIFOCTRL); | ||
301 | val &= ~(ZX_FIFOCTRL_TXTH_MASK | ZX_FIFOCTRL_TX_FIFO_RST_MASK); | ||
302 | val |= ZX_FIFOCTRL_TXTH(8); | ||
303 | writel_relaxed(val, base + ZX_FIFOCTRL); | ||
304 | } | ||
305 | |||
306 | static int zx_spdif_probe(struct platform_device *pdev) | ||
307 | { | ||
308 | struct resource *res; | ||
309 | struct zx_spdif_info *zx_spdif; | ||
310 | int ret; | ||
311 | |||
312 | zx_spdif = devm_kzalloc(&pdev->dev, sizeof(*zx_spdif), GFP_KERNEL); | ||
313 | if (!zx_spdif) | ||
314 | return -ENOMEM; | ||
315 | |||
316 | zx_spdif->dai_clk = devm_clk_get(&pdev->dev, "tx"); | ||
317 | if (IS_ERR(zx_spdif->dai_clk)) { | ||
318 | dev_err(&pdev->dev, "Fail to get clk\n"); | ||
319 | return PTR_ERR(zx_spdif->dai_clk); | ||
320 | } | ||
321 | |||
322 | res = platform_get_resource(pdev, IORESOURCE_MEM, 0); | ||
323 | zx_spdif->mapbase = res->start; | ||
324 | zx_spdif->reg_base = devm_ioremap_resource(&pdev->dev, res); | ||
325 | if (!zx_spdif->reg_base) { | ||
326 | dev_err(&pdev->dev, "ioremap failed!\n"); | ||
327 | return -EIO; | ||
328 | } | ||
329 | |||
330 | zx_spdif_dev_init(zx_spdif->reg_base); | ||
331 | platform_set_drvdata(pdev, zx_spdif); | ||
332 | |||
333 | ret = devm_snd_soc_register_component(&pdev->dev, &zx_spdif_component, | ||
334 | &zx_spdif_dai, 1); | ||
335 | if (ret) { | ||
336 | dev_err(&pdev->dev, "Register DAI failed: %d\n", ret); | ||
337 | return ret; | ||
338 | } | ||
339 | |||
340 | ret = devm_snd_dmaengine_pcm_register(&pdev->dev, NULL, 0); | ||
341 | if (ret) | ||
342 | dev_err(&pdev->dev, "Register platform PCM failed: %d\n", ret); | ||
343 | |||
344 | return ret; | ||
345 | } | ||
346 | |||
347 | static const struct of_device_id zx_spdif_dt_ids[] = { | ||
348 | { .compatible = "zte,zx296702-spdif", }, | ||
349 | {} | ||
350 | }; | ||
351 | MODULE_DEVICE_TABLE(of, zx_spdif_dt_ids); | ||
352 | |||
353 | static struct platform_driver spdif_driver = { | ||
354 | .probe = zx_spdif_probe, | ||
355 | .driver = { | ||
356 | .name = "zx-spdif", | ||
357 | .of_match_table = zx_spdif_dt_ids, | ||
358 | }, | ||
359 | }; | ||
360 | |||
361 | module_platform_driver(spdif_driver); | ||
362 | |||
363 | MODULE_AUTHOR("Jun Nie <jun.nie@linaro.org>"); | ||
364 | MODULE_DESCRIPTION("ZTE SPDIF SoC DAI"); | ||
365 | MODULE_LICENSE("GPL"); | ||
diff --git a/sound/synth/emux/emux_oss.c b/sound/synth/emux/emux_oss.c index ab37add269ae..82e350e9501c 100644 --- a/sound/synth/emux/emux_oss.c +++ b/sound/synth/emux/emux_oss.c | |||
@@ -118,12 +118,8 @@ snd_emux_open_seq_oss(struct snd_seq_oss_arg *arg, void *closure) | |||
118 | if (snd_BUG_ON(!arg || !emu)) | 118 | if (snd_BUG_ON(!arg || !emu)) |
119 | return -ENXIO; | 119 | return -ENXIO; |
120 | 120 | ||
121 | mutex_lock(&emu->register_mutex); | 121 | if (!snd_emux_inc_count(emu)) |
122 | |||
123 | if (!snd_emux_inc_count(emu)) { | ||
124 | mutex_unlock(&emu->register_mutex); | ||
125 | return -EFAULT; | 122 | return -EFAULT; |
126 | } | ||
127 | 123 | ||
128 | memset(&callback, 0, sizeof(callback)); | 124 | memset(&callback, 0, sizeof(callback)); |
129 | callback.owner = THIS_MODULE; | 125 | callback.owner = THIS_MODULE; |
@@ -135,7 +131,6 @@ snd_emux_open_seq_oss(struct snd_seq_oss_arg *arg, void *closure) | |||
135 | if (p == NULL) { | 131 | if (p == NULL) { |
136 | snd_printk(KERN_ERR "can't create port\n"); | 132 | snd_printk(KERN_ERR "can't create port\n"); |
137 | snd_emux_dec_count(emu); | 133 | snd_emux_dec_count(emu); |
138 | mutex_unlock(&emu->register_mutex); | ||
139 | return -ENOMEM; | 134 | return -ENOMEM; |
140 | } | 135 | } |
141 | 136 | ||
@@ -148,8 +143,6 @@ snd_emux_open_seq_oss(struct snd_seq_oss_arg *arg, void *closure) | |||
148 | reset_port_mode(p, arg->seq_mode); | 143 | reset_port_mode(p, arg->seq_mode); |
149 | 144 | ||
150 | snd_emux_reset_port(p); | 145 | snd_emux_reset_port(p); |
151 | |||
152 | mutex_unlock(&emu->register_mutex); | ||
153 | return 0; | 146 | return 0; |
154 | } | 147 | } |
155 | 148 | ||
@@ -195,13 +188,11 @@ snd_emux_close_seq_oss(struct snd_seq_oss_arg *arg) | |||
195 | if (snd_BUG_ON(!emu)) | 188 | if (snd_BUG_ON(!emu)) |
196 | return -ENXIO; | 189 | return -ENXIO; |
197 | 190 | ||
198 | mutex_lock(&emu->register_mutex); | ||
199 | snd_emux_sounds_off_all(p); | 191 | snd_emux_sounds_off_all(p); |
200 | snd_soundfont_close_check(emu->sflist, SF_CLIENT_NO(p->chset.port)); | 192 | snd_soundfont_close_check(emu->sflist, SF_CLIENT_NO(p->chset.port)); |
201 | snd_seq_event_port_detach(p->chset.client, p->chset.port); | 193 | snd_seq_event_port_detach(p->chset.client, p->chset.port); |
202 | snd_emux_dec_count(emu); | 194 | snd_emux_dec_count(emu); |
203 | 195 | ||
204 | mutex_unlock(&emu->register_mutex); | ||
205 | return 0; | 196 | return 0; |
206 | } | 197 | } |
207 | 198 | ||
diff --git a/sound/synth/emux/emux_seq.c b/sound/synth/emux/emux_seq.c index 7778b8e19782..a0209204ae48 100644 --- a/sound/synth/emux/emux_seq.c +++ b/sound/synth/emux/emux_seq.c | |||
@@ -124,12 +124,10 @@ snd_emux_detach_seq(struct snd_emux *emu) | |||
124 | if (emu->voices) | 124 | if (emu->voices) |
125 | snd_emux_terminate_all(emu); | 125 | snd_emux_terminate_all(emu); |
126 | 126 | ||
127 | mutex_lock(&emu->register_mutex); | ||
128 | if (emu->client >= 0) { | 127 | if (emu->client >= 0) { |
129 | snd_seq_delete_kernel_client(emu->client); | 128 | snd_seq_delete_kernel_client(emu->client); |
130 | emu->client = -1; | 129 | emu->client = -1; |
131 | } | 130 | } |
132 | mutex_unlock(&emu->register_mutex); | ||
133 | } | 131 | } |
134 | 132 | ||
135 | 133 | ||
@@ -269,8 +267,8 @@ snd_emux_event_input(struct snd_seq_event *ev, int direct, void *private_data, | |||
269 | /* | 267 | /* |
270 | * increment usage count | 268 | * increment usage count |
271 | */ | 269 | */ |
272 | int | 270 | static int |
273 | snd_emux_inc_count(struct snd_emux *emu) | 271 | __snd_emux_inc_count(struct snd_emux *emu) |
274 | { | 272 | { |
275 | emu->used++; | 273 | emu->used++; |
276 | if (!try_module_get(emu->ops.owner)) | 274 | if (!try_module_get(emu->ops.owner)) |
@@ -284,12 +282,21 @@ snd_emux_inc_count(struct snd_emux *emu) | |||
284 | return 1; | 282 | return 1; |
285 | } | 283 | } |
286 | 284 | ||
285 | int snd_emux_inc_count(struct snd_emux *emu) | ||
286 | { | ||
287 | int ret; | ||
288 | |||
289 | mutex_lock(&emu->register_mutex); | ||
290 | ret = __snd_emux_inc_count(emu); | ||
291 | mutex_unlock(&emu->register_mutex); | ||
292 | return ret; | ||
293 | } | ||
287 | 294 | ||
288 | /* | 295 | /* |
289 | * decrease usage count | 296 | * decrease usage count |
290 | */ | 297 | */ |
291 | void | 298 | static void |
292 | snd_emux_dec_count(struct snd_emux *emu) | 299 | __snd_emux_dec_count(struct snd_emux *emu) |
293 | { | 300 | { |
294 | module_put(emu->card->module); | 301 | module_put(emu->card->module); |
295 | emu->used--; | 302 | emu->used--; |
@@ -298,6 +305,12 @@ snd_emux_dec_count(struct snd_emux *emu) | |||
298 | module_put(emu->ops.owner); | 305 | module_put(emu->ops.owner); |
299 | } | 306 | } |
300 | 307 | ||
308 | void snd_emux_dec_count(struct snd_emux *emu) | ||
309 | { | ||
310 | mutex_lock(&emu->register_mutex); | ||
311 | __snd_emux_dec_count(emu); | ||
312 | mutex_unlock(&emu->register_mutex); | ||
313 | } | ||
301 | 314 | ||
302 | /* | 315 | /* |
303 | * Routine that is called upon a first use of a particular port | 316 | * Routine that is called upon a first use of a particular port |
@@ -317,7 +330,7 @@ snd_emux_use(void *private_data, struct snd_seq_port_subscribe *info) | |||
317 | 330 | ||
318 | mutex_lock(&emu->register_mutex); | 331 | mutex_lock(&emu->register_mutex); |
319 | snd_emux_init_port(p); | 332 | snd_emux_init_port(p); |
320 | snd_emux_inc_count(emu); | 333 | __snd_emux_inc_count(emu); |
321 | mutex_unlock(&emu->register_mutex); | 334 | mutex_unlock(&emu->register_mutex); |
322 | return 0; | 335 | return 0; |
323 | } | 336 | } |
@@ -340,7 +353,7 @@ snd_emux_unuse(void *private_data, struct snd_seq_port_subscribe *info) | |||
340 | 353 | ||
341 | mutex_lock(&emu->register_mutex); | 354 | mutex_lock(&emu->register_mutex); |
342 | snd_emux_sounds_off_all(p); | 355 | snd_emux_sounds_off_all(p); |
343 | snd_emux_dec_count(emu); | 356 | __snd_emux_dec_count(emu); |
344 | mutex_unlock(&emu->register_mutex); | 357 | mutex_unlock(&emu->register_mutex); |
345 | return 0; | 358 | return 0; |
346 | } | 359 | } |
diff --git a/sound/usb/mixer.c b/sound/usb/mixer.c index 3e2ef61c627b..8b7e391dd0b8 100644 --- a/sound/usb/mixer.c +++ b/sound/usb/mixer.c | |||
@@ -918,6 +918,7 @@ static void volume_control_quirks(struct usb_mixer_elem_info *cval, | |||
918 | case USB_ID(0x046d, 0x081d): /* HD Webcam c510 */ | 918 | case USB_ID(0x046d, 0x081d): /* HD Webcam c510 */ |
919 | case USB_ID(0x046d, 0x0825): /* HD Webcam c270 */ | 919 | case USB_ID(0x046d, 0x0825): /* HD Webcam c270 */ |
920 | case USB_ID(0x046d, 0x0826): /* HD Webcam c525 */ | 920 | case USB_ID(0x046d, 0x0826): /* HD Webcam c525 */ |
921 | case USB_ID(0x046d, 0x08ca): /* Logitech Quickcam Fusion */ | ||
921 | case USB_ID(0x046d, 0x0991): | 922 | case USB_ID(0x046d, 0x0991): |
922 | /* Most audio usb devices lie about volume resolution. | 923 | /* Most audio usb devices lie about volume resolution. |
923 | * Most Logitech webcams have res = 384. | 924 | * Most Logitech webcams have res = 384. |
@@ -1582,12 +1583,6 @@ static int parse_audio_mixer_unit(struct mixer_build *state, int unitid, | |||
1582 | unitid); | 1583 | unitid); |
1583 | return -EINVAL; | 1584 | return -EINVAL; |
1584 | } | 1585 | } |
1585 | /* no bmControls field (e.g. Maya44) -> ignore */ | ||
1586 | if (desc->bLength <= 10 + input_pins) { | ||
1587 | usb_audio_dbg(state->chip, "MU %d has no bmControls field\n", | ||
1588 | unitid); | ||
1589 | return 0; | ||
1590 | } | ||
1591 | 1586 | ||
1592 | num_ins = 0; | 1587 | num_ins = 0; |
1593 | ich = 0; | 1588 | ich = 0; |
@@ -1595,6 +1590,9 @@ static int parse_audio_mixer_unit(struct mixer_build *state, int unitid, | |||
1595 | err = parse_audio_unit(state, desc->baSourceID[pin]); | 1590 | err = parse_audio_unit(state, desc->baSourceID[pin]); |
1596 | if (err < 0) | 1591 | if (err < 0) |
1597 | continue; | 1592 | continue; |
1593 | /* no bmControls field (e.g. Maya44) -> ignore */ | ||
1594 | if (desc->bLength <= 10 + input_pins) | ||
1595 | continue; | ||
1598 | err = check_input_term(state, desc->baSourceID[pin], &iterm); | 1596 | err = check_input_term(state, desc->baSourceID[pin], &iterm); |
1599 | if (err < 0) | 1597 | if (err < 0) |
1600 | return err; | 1598 | return err; |
diff --git a/sound/usb/mixer_maps.c b/sound/usb/mixer_maps.c index b703cb3cda19..e5000da9e9d7 100644 --- a/sound/usb/mixer_maps.c +++ b/sound/usb/mixer_maps.c | |||
@@ -437,6 +437,11 @@ static struct usbmix_ctl_map usbmix_ctl_maps[] = { | |||
437 | .map = ebox44_map, | 437 | .map = ebox44_map, |
438 | }, | 438 | }, |
439 | { | 439 | { |
440 | /* MAYA44 USB+ */ | ||
441 | .id = USB_ID(0x2573, 0x0008), | ||
442 | .map = maya44_map, | ||
443 | }, | ||
444 | { | ||
440 | /* KEF X300A */ | 445 | /* KEF X300A */ |
441 | .id = USB_ID(0x27ac, 0x1000), | 446 | .id = USB_ID(0x27ac, 0x1000), |
442 | .map = scms_usb3318_map, | 447 | .map = scms_usb3318_map, |
diff --git a/sound/usb/quirks.c b/sound/usb/quirks.c index 7c5a70139278..754e689596a2 100644 --- a/sound/usb/quirks.c +++ b/sound/usb/quirks.c | |||
@@ -1117,7 +1117,10 @@ bool snd_usb_get_sample_rate_quirk(struct snd_usb_audio *chip) | |||
1117 | switch (chip->usb_id) { | 1117 | switch (chip->usb_id) { |
1118 | case USB_ID(0x045E, 0x075D): /* MS Lifecam Cinema */ | 1118 | case USB_ID(0x045E, 0x075D): /* MS Lifecam Cinema */ |
1119 | case USB_ID(0x045E, 0x076D): /* MS Lifecam HD-5000 */ | 1119 | case USB_ID(0x045E, 0x076D): /* MS Lifecam HD-5000 */ |
1120 | case USB_ID(0x045E, 0x0772): /* MS Lifecam Studio */ | ||
1121 | case USB_ID(0x045E, 0x0779): /* MS Lifecam HD-3000 */ | ||
1120 | case USB_ID(0x04D8, 0xFEEA): /* Benchmark DAC1 Pre */ | 1122 | case USB_ID(0x04D8, 0xFEEA): /* Benchmark DAC1 Pre */ |
1123 | case USB_ID(0x074D, 0x3553): /* Outlaw RR2150 (Micronas UAC3553B) */ | ||
1121 | return true; | 1124 | return true; |
1122 | } | 1125 | } |
1123 | return false; | 1126 | return false; |
@@ -1264,8 +1267,9 @@ u64 snd_usb_interface_dsd_format_quirks(struct snd_usb_audio *chip, | |||
1264 | if (fp->altsetting == 2) | 1267 | if (fp->altsetting == 2) |
1265 | return SNDRV_PCM_FMTBIT_DSD_U32_BE; | 1268 | return SNDRV_PCM_FMTBIT_DSD_U32_BE; |
1266 | break; | 1269 | break; |
1267 | /* DIYINHK DSD DXD 384kHz USB to I2S/DSD */ | 1270 | |
1268 | case USB_ID(0x20b1, 0x2009): | 1271 | case USB_ID(0x20b1, 0x2009): /* DIYINHK DSD DXD 384kHz USB to I2S/DSD */ |
1272 | case USB_ID(0x20b1, 0x2023): /* JLsounds I2SoverUSB */ | ||
1269 | if (fp->altsetting == 3) | 1273 | if (fp->altsetting == 3) |
1270 | return SNDRV_PCM_FMTBIT_DSD_U32_BE; | 1274 | return SNDRV_PCM_FMTBIT_DSD_U32_BE; |
1271 | break; | 1275 | break; |