18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later
28c2ecf20Sopenharmony_ci/*
38c2ecf20Sopenharmony_ci */
48c2ecf20Sopenharmony_ci
58c2ecf20Sopenharmony_ci/*
68c2ecf20Sopenharmony_ci * 2002-07 Benny Sjostrand benny@hostmobility.com
78c2ecf20Sopenharmony_ci */
88c2ecf20Sopenharmony_ci
98c2ecf20Sopenharmony_ci
108c2ecf20Sopenharmony_ci#include <linux/io.h>
118c2ecf20Sopenharmony_ci#include <linux/delay.h>
128c2ecf20Sopenharmony_ci#include <linux/pm.h>
138c2ecf20Sopenharmony_ci#include <linux/init.h>
148c2ecf20Sopenharmony_ci#include <linux/slab.h>
158c2ecf20Sopenharmony_ci#include <linux/mutex.h>
168c2ecf20Sopenharmony_ci
178c2ecf20Sopenharmony_ci#include <sound/core.h>
188c2ecf20Sopenharmony_ci#include <sound/control.h>
198c2ecf20Sopenharmony_ci#include <sound/info.h>
208c2ecf20Sopenharmony_ci#include "cs46xx.h"
218c2ecf20Sopenharmony_ci
228c2ecf20Sopenharmony_ci#include "cs46xx_lib.h"
238c2ecf20Sopenharmony_ci#include "dsp_spos.h"
248c2ecf20Sopenharmony_ci
258c2ecf20Sopenharmony_cistruct proc_scb_info {
268c2ecf20Sopenharmony_ci	struct dsp_scb_descriptor * scb_desc;
278c2ecf20Sopenharmony_ci	struct snd_cs46xx *chip;
288c2ecf20Sopenharmony_ci};
298c2ecf20Sopenharmony_ci
308c2ecf20Sopenharmony_cistatic void remove_symbol (struct snd_cs46xx * chip, struct dsp_symbol_entry * symbol)
318c2ecf20Sopenharmony_ci{
328c2ecf20Sopenharmony_ci	struct dsp_spos_instance * ins = chip->dsp_spos_instance;
338c2ecf20Sopenharmony_ci	int symbol_index = (int)(symbol - ins->symbol_table.symbols);
348c2ecf20Sopenharmony_ci
358c2ecf20Sopenharmony_ci	if (snd_BUG_ON(ins->symbol_table.nsymbols <= 0))
368c2ecf20Sopenharmony_ci		return;
378c2ecf20Sopenharmony_ci	if (snd_BUG_ON(symbol_index < 0 ||
388c2ecf20Sopenharmony_ci		       symbol_index >= ins->symbol_table.nsymbols))
398c2ecf20Sopenharmony_ci		return;
408c2ecf20Sopenharmony_ci
418c2ecf20Sopenharmony_ci	ins->symbol_table.symbols[symbol_index].deleted = 1;
428c2ecf20Sopenharmony_ci
438c2ecf20Sopenharmony_ci	if (symbol_index < ins->symbol_table.highest_frag_index) {
448c2ecf20Sopenharmony_ci		ins->symbol_table.highest_frag_index = symbol_index;
458c2ecf20Sopenharmony_ci	}
468c2ecf20Sopenharmony_ci
478c2ecf20Sopenharmony_ci	if (symbol_index == ins->symbol_table.nsymbols - 1)
488c2ecf20Sopenharmony_ci		ins->symbol_table.nsymbols --;
498c2ecf20Sopenharmony_ci
508c2ecf20Sopenharmony_ci	if (ins->symbol_table.highest_frag_index > ins->symbol_table.nsymbols) {
518c2ecf20Sopenharmony_ci		ins->symbol_table.highest_frag_index = ins->symbol_table.nsymbols;
528c2ecf20Sopenharmony_ci	}
538c2ecf20Sopenharmony_ci
548c2ecf20Sopenharmony_ci}
558c2ecf20Sopenharmony_ci
568c2ecf20Sopenharmony_ci#ifdef CONFIG_SND_PROC_FS
578c2ecf20Sopenharmony_cistatic void cs46xx_dsp_proc_scb_info_read (struct snd_info_entry *entry,
588c2ecf20Sopenharmony_ci					   struct snd_info_buffer *buffer)
598c2ecf20Sopenharmony_ci{
608c2ecf20Sopenharmony_ci	struct proc_scb_info * scb_info  = entry->private_data;
618c2ecf20Sopenharmony_ci	struct dsp_scb_descriptor * scb = scb_info->scb_desc;
628c2ecf20Sopenharmony_ci	struct snd_cs46xx *chip = scb_info->chip;
638c2ecf20Sopenharmony_ci	int j,col;
648c2ecf20Sopenharmony_ci	void __iomem *dst = chip->region.idx[1].remap_addr + DSP_PARAMETER_BYTE_OFFSET;
658c2ecf20Sopenharmony_ci
668c2ecf20Sopenharmony_ci	mutex_lock(&chip->spos_mutex);
678c2ecf20Sopenharmony_ci	snd_iprintf(buffer,"%04x %s:\n",scb->address,scb->scb_name);
688c2ecf20Sopenharmony_ci
698c2ecf20Sopenharmony_ci	for (col = 0,j = 0;j < 0x10; j++,col++) {
708c2ecf20Sopenharmony_ci		if (col == 4) {
718c2ecf20Sopenharmony_ci			snd_iprintf(buffer,"\n");
728c2ecf20Sopenharmony_ci			col = 0;
738c2ecf20Sopenharmony_ci		}
748c2ecf20Sopenharmony_ci		snd_iprintf(buffer,"%08x ",readl(dst + (scb->address + j) * sizeof(u32)));
758c2ecf20Sopenharmony_ci	}
768c2ecf20Sopenharmony_ci
778c2ecf20Sopenharmony_ci	snd_iprintf(buffer,"\n");
788c2ecf20Sopenharmony_ci
798c2ecf20Sopenharmony_ci	if (scb->parent_scb_ptr != NULL) {
808c2ecf20Sopenharmony_ci		snd_iprintf(buffer,"parent [%s:%04x] ",
818c2ecf20Sopenharmony_ci			    scb->parent_scb_ptr->scb_name,
828c2ecf20Sopenharmony_ci			    scb->parent_scb_ptr->address);
838c2ecf20Sopenharmony_ci	} else snd_iprintf(buffer,"parent [none] ");
848c2ecf20Sopenharmony_ci
858c2ecf20Sopenharmony_ci	snd_iprintf(buffer,"sub_list_ptr [%s:%04x]\nnext_scb_ptr [%s:%04x]  task_entry [%s:%04x]\n",
868c2ecf20Sopenharmony_ci		    scb->sub_list_ptr->scb_name,
878c2ecf20Sopenharmony_ci		    scb->sub_list_ptr->address,
888c2ecf20Sopenharmony_ci		    scb->next_scb_ptr->scb_name,
898c2ecf20Sopenharmony_ci		    scb->next_scb_ptr->address,
908c2ecf20Sopenharmony_ci		    scb->task_entry->symbol_name,
918c2ecf20Sopenharmony_ci		    scb->task_entry->address);
928c2ecf20Sopenharmony_ci
938c2ecf20Sopenharmony_ci	snd_iprintf(buffer,"index [%d] ref_count [%d]\n",scb->index,scb->ref_count);
948c2ecf20Sopenharmony_ci	mutex_unlock(&chip->spos_mutex);
958c2ecf20Sopenharmony_ci}
968c2ecf20Sopenharmony_ci#endif
978c2ecf20Sopenharmony_ci
988c2ecf20Sopenharmony_cistatic void _dsp_unlink_scb (struct snd_cs46xx *chip, struct dsp_scb_descriptor * scb)
998c2ecf20Sopenharmony_ci{
1008c2ecf20Sopenharmony_ci	struct dsp_spos_instance * ins = chip->dsp_spos_instance;
1018c2ecf20Sopenharmony_ci
1028c2ecf20Sopenharmony_ci	if ( scb->parent_scb_ptr ) {
1038c2ecf20Sopenharmony_ci		/* unlink parent SCB */
1048c2ecf20Sopenharmony_ci		if (snd_BUG_ON(scb->parent_scb_ptr->sub_list_ptr != scb &&
1058c2ecf20Sopenharmony_ci			       scb->parent_scb_ptr->next_scb_ptr != scb))
1068c2ecf20Sopenharmony_ci			return;
1078c2ecf20Sopenharmony_ci
1088c2ecf20Sopenharmony_ci		if (scb->parent_scb_ptr->sub_list_ptr == scb) {
1098c2ecf20Sopenharmony_ci
1108c2ecf20Sopenharmony_ci			if (scb->next_scb_ptr == ins->the_null_scb) {
1118c2ecf20Sopenharmony_ci				/* last and only node in parent sublist */
1128c2ecf20Sopenharmony_ci				scb->parent_scb_ptr->sub_list_ptr = scb->sub_list_ptr;
1138c2ecf20Sopenharmony_ci
1148c2ecf20Sopenharmony_ci				if (scb->sub_list_ptr != ins->the_null_scb) {
1158c2ecf20Sopenharmony_ci					scb->sub_list_ptr->parent_scb_ptr = scb->parent_scb_ptr;
1168c2ecf20Sopenharmony_ci				}
1178c2ecf20Sopenharmony_ci				scb->sub_list_ptr = ins->the_null_scb;
1188c2ecf20Sopenharmony_ci			} else {
1198c2ecf20Sopenharmony_ci				/* first node in parent sublist */
1208c2ecf20Sopenharmony_ci				scb->parent_scb_ptr->sub_list_ptr = scb->next_scb_ptr;
1218c2ecf20Sopenharmony_ci
1228c2ecf20Sopenharmony_ci				if (scb->next_scb_ptr != ins->the_null_scb) {
1238c2ecf20Sopenharmony_ci					/* update next node parent ptr. */
1248c2ecf20Sopenharmony_ci					scb->next_scb_ptr->parent_scb_ptr = scb->parent_scb_ptr;
1258c2ecf20Sopenharmony_ci				}
1268c2ecf20Sopenharmony_ci				scb->next_scb_ptr = ins->the_null_scb;
1278c2ecf20Sopenharmony_ci			}
1288c2ecf20Sopenharmony_ci		} else {
1298c2ecf20Sopenharmony_ci			scb->parent_scb_ptr->next_scb_ptr = scb->next_scb_ptr;
1308c2ecf20Sopenharmony_ci
1318c2ecf20Sopenharmony_ci			if (scb->next_scb_ptr != ins->the_null_scb) {
1328c2ecf20Sopenharmony_ci				/* update next node parent ptr. */
1338c2ecf20Sopenharmony_ci				scb->next_scb_ptr->parent_scb_ptr = scb->parent_scb_ptr;
1348c2ecf20Sopenharmony_ci			}
1358c2ecf20Sopenharmony_ci			scb->next_scb_ptr = ins->the_null_scb;
1368c2ecf20Sopenharmony_ci		}
1378c2ecf20Sopenharmony_ci
1388c2ecf20Sopenharmony_ci		/* update parent first entry in DSP RAM */
1398c2ecf20Sopenharmony_ci		cs46xx_dsp_spos_update_scb(chip,scb->parent_scb_ptr);
1408c2ecf20Sopenharmony_ci
1418c2ecf20Sopenharmony_ci		/* then update entry in DSP RAM */
1428c2ecf20Sopenharmony_ci		cs46xx_dsp_spos_update_scb(chip,scb);
1438c2ecf20Sopenharmony_ci
1448c2ecf20Sopenharmony_ci		scb->parent_scb_ptr = NULL;
1458c2ecf20Sopenharmony_ci	}
1468c2ecf20Sopenharmony_ci}
1478c2ecf20Sopenharmony_ci
1488c2ecf20Sopenharmony_cistatic void _dsp_clear_sample_buffer (struct snd_cs46xx *chip, u32 sample_buffer_addr,
1498c2ecf20Sopenharmony_ci				      int dword_count)
1508c2ecf20Sopenharmony_ci{
1518c2ecf20Sopenharmony_ci	void __iomem *dst = chip->region.idx[2].remap_addr + sample_buffer_addr;
1528c2ecf20Sopenharmony_ci	int i;
1538c2ecf20Sopenharmony_ci
1548c2ecf20Sopenharmony_ci	for (i = 0; i < dword_count ; ++i ) {
1558c2ecf20Sopenharmony_ci		writel(0, dst);
1568c2ecf20Sopenharmony_ci		dst += 4;
1578c2ecf20Sopenharmony_ci	}
1588c2ecf20Sopenharmony_ci}
1598c2ecf20Sopenharmony_ci
1608c2ecf20Sopenharmony_civoid cs46xx_dsp_remove_scb (struct snd_cs46xx *chip, struct dsp_scb_descriptor * scb)
1618c2ecf20Sopenharmony_ci{
1628c2ecf20Sopenharmony_ci	struct dsp_spos_instance * ins = chip->dsp_spos_instance;
1638c2ecf20Sopenharmony_ci	unsigned long flags;
1648c2ecf20Sopenharmony_ci
1658c2ecf20Sopenharmony_ci	/* check integrety */
1668c2ecf20Sopenharmony_ci	if (snd_BUG_ON(scb->index < 0 ||
1678c2ecf20Sopenharmony_ci		       scb->index >= ins->nscb ||
1688c2ecf20Sopenharmony_ci		       (ins->scbs + scb->index) != scb))
1698c2ecf20Sopenharmony_ci		return;
1708c2ecf20Sopenharmony_ci
1718c2ecf20Sopenharmony_ci#if 0
1728c2ecf20Sopenharmony_ci	/* can't remove a SCB with childs before
1738c2ecf20Sopenharmony_ci	   removing childs first  */
1748c2ecf20Sopenharmony_ci	if (snd_BUG_ON(scb->sub_list_ptr != ins->the_null_scb ||
1758c2ecf20Sopenharmony_ci		       scb->next_scb_ptr != ins->the_null_scb))
1768c2ecf20Sopenharmony_ci		goto _end;
1778c2ecf20Sopenharmony_ci#endif
1788c2ecf20Sopenharmony_ci
1798c2ecf20Sopenharmony_ci	spin_lock_irqsave(&chip->reg_lock, flags);
1808c2ecf20Sopenharmony_ci	_dsp_unlink_scb (chip,scb);
1818c2ecf20Sopenharmony_ci	spin_unlock_irqrestore(&chip->reg_lock, flags);
1828c2ecf20Sopenharmony_ci
1838c2ecf20Sopenharmony_ci	cs46xx_dsp_proc_free_scb_desc(scb);
1848c2ecf20Sopenharmony_ci	if (snd_BUG_ON(!scb->scb_symbol))
1858c2ecf20Sopenharmony_ci		return;
1868c2ecf20Sopenharmony_ci	remove_symbol (chip,scb->scb_symbol);
1878c2ecf20Sopenharmony_ci
1888c2ecf20Sopenharmony_ci	ins->scbs[scb->index].deleted = 1;
1898c2ecf20Sopenharmony_ci#ifdef CONFIG_PM_SLEEP
1908c2ecf20Sopenharmony_ci	kfree(ins->scbs[scb->index].data);
1918c2ecf20Sopenharmony_ci	ins->scbs[scb->index].data = NULL;
1928c2ecf20Sopenharmony_ci#endif
1938c2ecf20Sopenharmony_ci
1948c2ecf20Sopenharmony_ci	if (scb->index < ins->scb_highest_frag_index)
1958c2ecf20Sopenharmony_ci		ins->scb_highest_frag_index = scb->index;
1968c2ecf20Sopenharmony_ci
1978c2ecf20Sopenharmony_ci	if (scb->index == ins->nscb - 1) {
1988c2ecf20Sopenharmony_ci		ins->nscb --;
1998c2ecf20Sopenharmony_ci	}
2008c2ecf20Sopenharmony_ci
2018c2ecf20Sopenharmony_ci	if (ins->scb_highest_frag_index > ins->nscb) {
2028c2ecf20Sopenharmony_ci		ins->scb_highest_frag_index = ins->nscb;
2038c2ecf20Sopenharmony_ci	}
2048c2ecf20Sopenharmony_ci
2058c2ecf20Sopenharmony_ci#if 0
2068c2ecf20Sopenharmony_ci	/* !!!! THIS IS A PIECE OF SHIT MADE BY ME !!! */
2078c2ecf20Sopenharmony_ci	for(i = scb->index + 1;i < ins->nscb; ++i) {
2088c2ecf20Sopenharmony_ci		ins->scbs[i - 1].index = i - 1;
2098c2ecf20Sopenharmony_ci	}
2108c2ecf20Sopenharmony_ci#endif
2118c2ecf20Sopenharmony_ci}
2128c2ecf20Sopenharmony_ci
2138c2ecf20Sopenharmony_ci
2148c2ecf20Sopenharmony_ci#ifdef CONFIG_SND_PROC_FS
2158c2ecf20Sopenharmony_civoid cs46xx_dsp_proc_free_scb_desc (struct dsp_scb_descriptor * scb)
2168c2ecf20Sopenharmony_ci{
2178c2ecf20Sopenharmony_ci	if (scb->proc_info) {
2188c2ecf20Sopenharmony_ci		struct proc_scb_info * scb_info = scb->proc_info->private_data;
2198c2ecf20Sopenharmony_ci		struct snd_cs46xx *chip = scb_info->chip;
2208c2ecf20Sopenharmony_ci
2218c2ecf20Sopenharmony_ci		dev_dbg(chip->card->dev,
2228c2ecf20Sopenharmony_ci			"cs46xx_dsp_proc_free_scb_desc: freeing %s\n",
2238c2ecf20Sopenharmony_ci			scb->scb_name);
2248c2ecf20Sopenharmony_ci
2258c2ecf20Sopenharmony_ci		snd_info_free_entry(scb->proc_info);
2268c2ecf20Sopenharmony_ci		scb->proc_info = NULL;
2278c2ecf20Sopenharmony_ci
2288c2ecf20Sopenharmony_ci		kfree (scb_info);
2298c2ecf20Sopenharmony_ci	}
2308c2ecf20Sopenharmony_ci}
2318c2ecf20Sopenharmony_ci
2328c2ecf20Sopenharmony_civoid cs46xx_dsp_proc_register_scb_desc (struct snd_cs46xx *chip,
2338c2ecf20Sopenharmony_ci					struct dsp_scb_descriptor * scb)
2348c2ecf20Sopenharmony_ci{
2358c2ecf20Sopenharmony_ci	struct dsp_spos_instance * ins = chip->dsp_spos_instance;
2368c2ecf20Sopenharmony_ci	struct snd_info_entry * entry;
2378c2ecf20Sopenharmony_ci	struct proc_scb_info * scb_info;
2388c2ecf20Sopenharmony_ci
2398c2ecf20Sopenharmony_ci	/* register to proc */
2408c2ecf20Sopenharmony_ci	if (ins->snd_card != NULL && ins->proc_dsp_dir != NULL &&
2418c2ecf20Sopenharmony_ci	    scb->proc_info == NULL) {
2428c2ecf20Sopenharmony_ci
2438c2ecf20Sopenharmony_ci		entry = snd_info_create_card_entry(ins->snd_card, scb->scb_name,
2448c2ecf20Sopenharmony_ci						   ins->proc_dsp_dir);
2458c2ecf20Sopenharmony_ci		if (entry) {
2468c2ecf20Sopenharmony_ci			scb_info = kmalloc(sizeof(struct proc_scb_info), GFP_KERNEL);
2478c2ecf20Sopenharmony_ci			if (!scb_info) {
2488c2ecf20Sopenharmony_ci				snd_info_free_entry(entry);
2498c2ecf20Sopenharmony_ci				entry = NULL;
2508c2ecf20Sopenharmony_ci				goto out;
2518c2ecf20Sopenharmony_ci			}
2528c2ecf20Sopenharmony_ci
2538c2ecf20Sopenharmony_ci			scb_info->chip = chip;
2548c2ecf20Sopenharmony_ci			scb_info->scb_desc = scb;
2558c2ecf20Sopenharmony_ci			snd_info_set_text_ops(entry, scb_info,
2568c2ecf20Sopenharmony_ci					      cs46xx_dsp_proc_scb_info_read);
2578c2ecf20Sopenharmony_ci		}
2588c2ecf20Sopenharmony_ciout:
2598c2ecf20Sopenharmony_ci		scb->proc_info = entry;
2608c2ecf20Sopenharmony_ci	}
2618c2ecf20Sopenharmony_ci}
2628c2ecf20Sopenharmony_ci#endif /* CONFIG_SND_PROC_FS */
2638c2ecf20Sopenharmony_ci
2648c2ecf20Sopenharmony_cistatic struct dsp_scb_descriptor *
2658c2ecf20Sopenharmony_ci_dsp_create_generic_scb (struct snd_cs46xx *chip, char * name, u32 * scb_data, u32 dest,
2668c2ecf20Sopenharmony_ci                         struct dsp_symbol_entry * task_entry,
2678c2ecf20Sopenharmony_ci                         struct dsp_scb_descriptor * parent_scb,
2688c2ecf20Sopenharmony_ci                         int scb_child_type)
2698c2ecf20Sopenharmony_ci{
2708c2ecf20Sopenharmony_ci	struct dsp_spos_instance * ins = chip->dsp_spos_instance;
2718c2ecf20Sopenharmony_ci	struct dsp_scb_descriptor * scb;
2728c2ecf20Sopenharmony_ci
2738c2ecf20Sopenharmony_ci	unsigned long flags;
2748c2ecf20Sopenharmony_ci
2758c2ecf20Sopenharmony_ci	if (snd_BUG_ON(!ins->the_null_scb))
2768c2ecf20Sopenharmony_ci		return NULL;
2778c2ecf20Sopenharmony_ci
2788c2ecf20Sopenharmony_ci	/* fill the data that will be wroten to DSP */
2798c2ecf20Sopenharmony_ci	scb_data[SCBsubListPtr] =
2808c2ecf20Sopenharmony_ci		(ins->the_null_scb->address << 0x10) | ins->the_null_scb->address;
2818c2ecf20Sopenharmony_ci
2828c2ecf20Sopenharmony_ci	scb_data[SCBfuncEntryPtr] &= 0xFFFF0000;
2838c2ecf20Sopenharmony_ci	scb_data[SCBfuncEntryPtr] |= task_entry->address;
2848c2ecf20Sopenharmony_ci
2858c2ecf20Sopenharmony_ci	dev_dbg(chip->card->dev, "dsp_spos: creating SCB <%s>\n", name);
2868c2ecf20Sopenharmony_ci
2878c2ecf20Sopenharmony_ci	scb = cs46xx_dsp_create_scb(chip,name,scb_data,dest);
2888c2ecf20Sopenharmony_ci
2898c2ecf20Sopenharmony_ci
2908c2ecf20Sopenharmony_ci	scb->sub_list_ptr = ins->the_null_scb;
2918c2ecf20Sopenharmony_ci	scb->next_scb_ptr = ins->the_null_scb;
2928c2ecf20Sopenharmony_ci
2938c2ecf20Sopenharmony_ci	scb->parent_scb_ptr = parent_scb;
2948c2ecf20Sopenharmony_ci	scb->task_entry = task_entry;
2958c2ecf20Sopenharmony_ci
2968c2ecf20Sopenharmony_ci
2978c2ecf20Sopenharmony_ci	/* update parent SCB */
2988c2ecf20Sopenharmony_ci	if (scb->parent_scb_ptr) {
2998c2ecf20Sopenharmony_ci#if 0
3008c2ecf20Sopenharmony_ci		dev_dbg(chip->card->dev,
3018c2ecf20Sopenharmony_ci			"scb->parent_scb_ptr = %s\n",
3028c2ecf20Sopenharmony_ci			scb->parent_scb_ptr->scb_name);
3038c2ecf20Sopenharmony_ci		dev_dbg(chip->card->dev,
3048c2ecf20Sopenharmony_ci			"scb->parent_scb_ptr->next_scb_ptr = %s\n",
3058c2ecf20Sopenharmony_ci			scb->parent_scb_ptr->next_scb_ptr->scb_name);
3068c2ecf20Sopenharmony_ci		dev_dbg(chip->card->dev,
3078c2ecf20Sopenharmony_ci			"scb->parent_scb_ptr->sub_list_ptr = %s\n",
3088c2ecf20Sopenharmony_ci			scb->parent_scb_ptr->sub_list_ptr->scb_name);
3098c2ecf20Sopenharmony_ci#endif
3108c2ecf20Sopenharmony_ci		/* link to  parent SCB */
3118c2ecf20Sopenharmony_ci		if (scb_child_type == SCB_ON_PARENT_NEXT_SCB) {
3128c2ecf20Sopenharmony_ci			if (snd_BUG_ON(scb->parent_scb_ptr->next_scb_ptr !=
3138c2ecf20Sopenharmony_ci				       ins->the_null_scb))
3148c2ecf20Sopenharmony_ci				return NULL;
3158c2ecf20Sopenharmony_ci
3168c2ecf20Sopenharmony_ci			scb->parent_scb_ptr->next_scb_ptr = scb;
3178c2ecf20Sopenharmony_ci
3188c2ecf20Sopenharmony_ci		} else if (scb_child_type == SCB_ON_PARENT_SUBLIST_SCB) {
3198c2ecf20Sopenharmony_ci			if (snd_BUG_ON(scb->parent_scb_ptr->sub_list_ptr !=
3208c2ecf20Sopenharmony_ci				       ins->the_null_scb))
3218c2ecf20Sopenharmony_ci				return NULL;
3228c2ecf20Sopenharmony_ci
3238c2ecf20Sopenharmony_ci			scb->parent_scb_ptr->sub_list_ptr = scb;
3248c2ecf20Sopenharmony_ci		} else {
3258c2ecf20Sopenharmony_ci			snd_BUG();
3268c2ecf20Sopenharmony_ci		}
3278c2ecf20Sopenharmony_ci
3288c2ecf20Sopenharmony_ci		spin_lock_irqsave(&chip->reg_lock, flags);
3298c2ecf20Sopenharmony_ci
3308c2ecf20Sopenharmony_ci		/* update entry in DSP RAM */
3318c2ecf20Sopenharmony_ci		cs46xx_dsp_spos_update_scb(chip,scb->parent_scb_ptr);
3328c2ecf20Sopenharmony_ci
3338c2ecf20Sopenharmony_ci		spin_unlock_irqrestore(&chip->reg_lock, flags);
3348c2ecf20Sopenharmony_ci	}
3358c2ecf20Sopenharmony_ci
3368c2ecf20Sopenharmony_ci
3378c2ecf20Sopenharmony_ci	cs46xx_dsp_proc_register_scb_desc (chip,scb);
3388c2ecf20Sopenharmony_ci
3398c2ecf20Sopenharmony_ci	return scb;
3408c2ecf20Sopenharmony_ci}
3418c2ecf20Sopenharmony_ci
3428c2ecf20Sopenharmony_cistatic struct dsp_scb_descriptor *
3438c2ecf20Sopenharmony_cics46xx_dsp_create_generic_scb (struct snd_cs46xx *chip, char * name, u32 * scb_data,
3448c2ecf20Sopenharmony_ci			       u32 dest, char * task_entry_name,
3458c2ecf20Sopenharmony_ci                               struct dsp_scb_descriptor * parent_scb,
3468c2ecf20Sopenharmony_ci                               int scb_child_type)
3478c2ecf20Sopenharmony_ci{
3488c2ecf20Sopenharmony_ci	struct dsp_symbol_entry * task_entry;
3498c2ecf20Sopenharmony_ci
3508c2ecf20Sopenharmony_ci	task_entry = cs46xx_dsp_lookup_symbol (chip,task_entry_name,
3518c2ecf20Sopenharmony_ci					       SYMBOL_CODE);
3528c2ecf20Sopenharmony_ci
3538c2ecf20Sopenharmony_ci	if (task_entry == NULL) {
3548c2ecf20Sopenharmony_ci		dev_err(chip->card->dev,
3558c2ecf20Sopenharmony_ci			"dsp_spos: symbol %s not found\n", task_entry_name);
3568c2ecf20Sopenharmony_ci		return NULL;
3578c2ecf20Sopenharmony_ci	}
3588c2ecf20Sopenharmony_ci
3598c2ecf20Sopenharmony_ci	return _dsp_create_generic_scb (chip,name,scb_data,dest,task_entry,
3608c2ecf20Sopenharmony_ci					parent_scb,scb_child_type);
3618c2ecf20Sopenharmony_ci}
3628c2ecf20Sopenharmony_ci
3638c2ecf20Sopenharmony_cistruct dsp_scb_descriptor *
3648c2ecf20Sopenharmony_cics46xx_dsp_create_timing_master_scb (struct snd_cs46xx *chip)
3658c2ecf20Sopenharmony_ci{
3668c2ecf20Sopenharmony_ci	struct dsp_scb_descriptor * scb;
3678c2ecf20Sopenharmony_ci
3688c2ecf20Sopenharmony_ci	struct dsp_timing_master_scb timing_master_scb = {
3698c2ecf20Sopenharmony_ci		{ 0,
3708c2ecf20Sopenharmony_ci		  0,
3718c2ecf20Sopenharmony_ci		  0,
3728c2ecf20Sopenharmony_ci		  0
3738c2ecf20Sopenharmony_ci		},
3748c2ecf20Sopenharmony_ci		{ 0,
3758c2ecf20Sopenharmony_ci		  0,
3768c2ecf20Sopenharmony_ci		  0,
3778c2ecf20Sopenharmony_ci		  0,
3788c2ecf20Sopenharmony_ci		  0
3798c2ecf20Sopenharmony_ci		},
3808c2ecf20Sopenharmony_ci		0,0,
3818c2ecf20Sopenharmony_ci		0,NULL_SCB_ADDR,
3828c2ecf20Sopenharmony_ci		0,0,             /* extraSampleAccum:TMreserved */
3838c2ecf20Sopenharmony_ci		0,0,             /* codecFIFOptr:codecFIFOsyncd */
3848c2ecf20Sopenharmony_ci		0x0001,0x8000,   /* fracSampAccumQm1:TMfrmsLeftInGroup */
3858c2ecf20Sopenharmony_ci		0x0001,0x0000,   /* fracSampCorrectionQm1:TMfrmGroupLength */
3868c2ecf20Sopenharmony_ci		0x00060000       /* nSampPerFrmQ15 */
3878c2ecf20Sopenharmony_ci	};
3888c2ecf20Sopenharmony_ci
3898c2ecf20Sopenharmony_ci	scb = cs46xx_dsp_create_generic_scb(chip,"TimingMasterSCBInst",(u32 *)&timing_master_scb,
3908c2ecf20Sopenharmony_ci					    TIMINGMASTER_SCB_ADDR,
3918c2ecf20Sopenharmony_ci					    "TIMINGMASTER",NULL,SCB_NO_PARENT);
3928c2ecf20Sopenharmony_ci
3938c2ecf20Sopenharmony_ci	return scb;
3948c2ecf20Sopenharmony_ci}
3958c2ecf20Sopenharmony_ci
3968c2ecf20Sopenharmony_ci
3978c2ecf20Sopenharmony_cistruct dsp_scb_descriptor *
3988c2ecf20Sopenharmony_cics46xx_dsp_create_codec_out_scb(struct snd_cs46xx * chip, char * codec_name,
3998c2ecf20Sopenharmony_ci                                u16 channel_disp, u16 fifo_addr, u16 child_scb_addr,
4008c2ecf20Sopenharmony_ci                                u32 dest, struct dsp_scb_descriptor * parent_scb,
4018c2ecf20Sopenharmony_ci                                int scb_child_type)
4028c2ecf20Sopenharmony_ci{
4038c2ecf20Sopenharmony_ci	struct dsp_scb_descriptor * scb;
4048c2ecf20Sopenharmony_ci
4058c2ecf20Sopenharmony_ci	struct dsp_codec_output_scb codec_out_scb = {
4068c2ecf20Sopenharmony_ci		{ 0,
4078c2ecf20Sopenharmony_ci		  0,
4088c2ecf20Sopenharmony_ci		  0,
4098c2ecf20Sopenharmony_ci		  0
4108c2ecf20Sopenharmony_ci		},
4118c2ecf20Sopenharmony_ci		{
4128c2ecf20Sopenharmony_ci			0,
4138c2ecf20Sopenharmony_ci			0,
4148c2ecf20Sopenharmony_ci			0,
4158c2ecf20Sopenharmony_ci			0,
4168c2ecf20Sopenharmony_ci			0
4178c2ecf20Sopenharmony_ci		},
4188c2ecf20Sopenharmony_ci		0,0,
4198c2ecf20Sopenharmony_ci		0,NULL_SCB_ADDR,
4208c2ecf20Sopenharmony_ci		0,                      /* COstrmRsConfig */
4218c2ecf20Sopenharmony_ci		0,                      /* COstrmBufPtr */
4228c2ecf20Sopenharmony_ci		channel_disp,fifo_addr, /* leftChanBaseIOaddr:rightChanIOdisp */
4238c2ecf20Sopenharmony_ci		0x0000,0x0080,          /* (!AC97!) COexpVolChangeRate:COscaleShiftCount */
4248c2ecf20Sopenharmony_ci		0,child_scb_addr        /* COreserved - need child scb to work with rom code */
4258c2ecf20Sopenharmony_ci	};
4268c2ecf20Sopenharmony_ci
4278c2ecf20Sopenharmony_ci
4288c2ecf20Sopenharmony_ci	scb = cs46xx_dsp_create_generic_scb(chip,codec_name,(u32 *)&codec_out_scb,
4298c2ecf20Sopenharmony_ci					    dest,"S16_CODECOUTPUTTASK",parent_scb,
4308c2ecf20Sopenharmony_ci					    scb_child_type);
4318c2ecf20Sopenharmony_ci
4328c2ecf20Sopenharmony_ci	return scb;
4338c2ecf20Sopenharmony_ci}
4348c2ecf20Sopenharmony_ci
4358c2ecf20Sopenharmony_cistruct dsp_scb_descriptor *
4368c2ecf20Sopenharmony_cics46xx_dsp_create_codec_in_scb(struct snd_cs46xx * chip, char * codec_name,
4378c2ecf20Sopenharmony_ci			       u16 channel_disp, u16 fifo_addr, u16 sample_buffer_addr,
4388c2ecf20Sopenharmony_ci			       u32 dest, struct dsp_scb_descriptor * parent_scb,
4398c2ecf20Sopenharmony_ci			       int scb_child_type)
4408c2ecf20Sopenharmony_ci{
4418c2ecf20Sopenharmony_ci
4428c2ecf20Sopenharmony_ci	struct dsp_scb_descriptor * scb;
4438c2ecf20Sopenharmony_ci	struct dsp_codec_input_scb codec_input_scb = {
4448c2ecf20Sopenharmony_ci		{ 0,
4458c2ecf20Sopenharmony_ci		  0,
4468c2ecf20Sopenharmony_ci		  0,
4478c2ecf20Sopenharmony_ci		  0
4488c2ecf20Sopenharmony_ci		},
4498c2ecf20Sopenharmony_ci		{
4508c2ecf20Sopenharmony_ci			0,
4518c2ecf20Sopenharmony_ci			0,
4528c2ecf20Sopenharmony_ci			0,
4538c2ecf20Sopenharmony_ci			0,
4548c2ecf20Sopenharmony_ci			0
4558c2ecf20Sopenharmony_ci		},
4568c2ecf20Sopenharmony_ci
4578c2ecf20Sopenharmony_ci#if 0  /* cs4620 */
4588c2ecf20Sopenharmony_ci		SyncIOSCB,NULL_SCB_ADDR
4598c2ecf20Sopenharmony_ci#else
4608c2ecf20Sopenharmony_ci		0 , 0,
4618c2ecf20Sopenharmony_ci#endif
4628c2ecf20Sopenharmony_ci		0,0,
4638c2ecf20Sopenharmony_ci
4648c2ecf20Sopenharmony_ci		RSCONFIG_SAMPLE_16STEREO + RSCONFIG_MODULO_64,  /* strmRsConfig */
4658c2ecf20Sopenharmony_ci		sample_buffer_addr << 0x10,       /* strmBufPtr; defined as a dword ptr, used as a byte ptr */
4668c2ecf20Sopenharmony_ci		channel_disp,fifo_addr,           /* (!AC97!) leftChanBaseINaddr=AC97primary
4678c2ecf20Sopenharmony_ci						     link input slot 3 :rightChanINdisp=""slot 4 */
4688c2ecf20Sopenharmony_ci		0x0000,0x0000,                    /* (!AC97!) ????:scaleShiftCount; no shift needed
4698c2ecf20Sopenharmony_ci						     because AC97 is already 20 bits */
4708c2ecf20Sopenharmony_ci		0x80008000                        /* ??clw cwcgame.scb has 0 */
4718c2ecf20Sopenharmony_ci	};
4728c2ecf20Sopenharmony_ci
4738c2ecf20Sopenharmony_ci	scb = cs46xx_dsp_create_generic_scb(chip,codec_name,(u32 *)&codec_input_scb,
4748c2ecf20Sopenharmony_ci					    dest,"S16_CODECINPUTTASK",parent_scb,
4758c2ecf20Sopenharmony_ci					    scb_child_type);
4768c2ecf20Sopenharmony_ci	return scb;
4778c2ecf20Sopenharmony_ci}
4788c2ecf20Sopenharmony_ci
4798c2ecf20Sopenharmony_ci
4808c2ecf20Sopenharmony_cistatic struct dsp_scb_descriptor *
4818c2ecf20Sopenharmony_cics46xx_dsp_create_pcm_reader_scb(struct snd_cs46xx * chip, char * scb_name,
4828c2ecf20Sopenharmony_ci                                 u16 sample_buffer_addr, u32 dest,
4838c2ecf20Sopenharmony_ci                                 int virtual_channel, u32 playback_hw_addr,
4848c2ecf20Sopenharmony_ci                                 struct dsp_scb_descriptor * parent_scb,
4858c2ecf20Sopenharmony_ci                                 int scb_child_type)
4868c2ecf20Sopenharmony_ci{
4878c2ecf20Sopenharmony_ci	struct dsp_spos_instance * ins = chip->dsp_spos_instance;
4888c2ecf20Sopenharmony_ci	struct dsp_scb_descriptor * scb;
4898c2ecf20Sopenharmony_ci
4908c2ecf20Sopenharmony_ci	struct dsp_generic_scb pcm_reader_scb = {
4918c2ecf20Sopenharmony_ci
4928c2ecf20Sopenharmony_ci		/*
4938c2ecf20Sopenharmony_ci		  Play DMA Task xfers data from host buffer to SP buffer
4948c2ecf20Sopenharmony_ci		  init/runtime variables:
4958c2ecf20Sopenharmony_ci		  PlayAC: Play Audio Data Conversion - SCB loc: 2nd dword, mask: 0x0000F000L
4968c2ecf20Sopenharmony_ci		  DATA_FMT_16BIT_ST_LTLEND(0x00000000L)   from 16-bit stereo, little-endian
4978c2ecf20Sopenharmony_ci		  DATA_FMT_8_BIT_ST_SIGNED(0x00001000L)   from 8-bit stereo, signed
4988c2ecf20Sopenharmony_ci		  DATA_FMT_16BIT_MN_LTLEND(0x00002000L)   from 16-bit mono, little-endian
4998c2ecf20Sopenharmony_ci		  DATA_FMT_8_BIT_MN_SIGNED(0x00003000L)   from 8-bit mono, signed
5008c2ecf20Sopenharmony_ci		  DATA_FMT_16BIT_ST_BIGEND(0x00004000L)   from 16-bit stereo, big-endian
5018c2ecf20Sopenharmony_ci		  DATA_FMT_16BIT_MN_BIGEND(0x00006000L)   from 16-bit mono, big-endian
5028c2ecf20Sopenharmony_ci		  DATA_FMT_8_BIT_ST_UNSIGNED(0x00009000L) from 8-bit stereo, unsigned
5038c2ecf20Sopenharmony_ci		  DATA_FMT_8_BIT_MN_UNSIGNED(0x0000b000L) from 8-bit mono, unsigned
5048c2ecf20Sopenharmony_ci		  ? Other combinations possible from:
5058c2ecf20Sopenharmony_ci		  DMA_RQ_C2_AUDIO_CONVERT_MASK    0x0000F000L
5068c2ecf20Sopenharmony_ci		  DMA_RQ_C2_AC_NONE               0x00000000L
5078c2ecf20Sopenharmony_ci		  DMA_RQ_C2_AC_8_TO_16_BIT        0x00001000L
5088c2ecf20Sopenharmony_ci		  DMA_RQ_C2_AC_MONO_TO_STEREO     0x00002000L
5098c2ecf20Sopenharmony_ci		  DMA_RQ_C2_AC_ENDIAN_CONVERT     0x00004000L
5108c2ecf20Sopenharmony_ci		  DMA_RQ_C2_AC_SIGNED_CONVERT     0x00008000L
5118c2ecf20Sopenharmony_ci
5128c2ecf20Sopenharmony_ci		  HostBuffAddr: Host Buffer Physical Byte Address - SCB loc:3rd dword, Mask: 0xFFFFFFFFL
5138c2ecf20Sopenharmony_ci		  aligned to dword boundary
5148c2ecf20Sopenharmony_ci		*/
5158c2ecf20Sopenharmony_ci		/* Basic (non scatter/gather) DMA requestor (4 ints) */
5168c2ecf20Sopenharmony_ci		{ DMA_RQ_C1_SOURCE_ON_HOST +        /* source buffer is on the host */
5178c2ecf20Sopenharmony_ci		  DMA_RQ_C1_SOURCE_MOD1024 +        /* source buffer is 1024 dwords (4096 bytes) */
5188c2ecf20Sopenharmony_ci		  DMA_RQ_C1_DEST_MOD32 +            /* dest buffer(PCMreaderBuf) is 32 dwords*/
5198c2ecf20Sopenharmony_ci		  DMA_RQ_C1_WRITEBACK_SRC_FLAG +    /* ?? */
5208c2ecf20Sopenharmony_ci		  DMA_RQ_C1_WRITEBACK_DEST_FLAG +   /* ?? */
5218c2ecf20Sopenharmony_ci		  15,                             /* DwordCount-1: picked 16 for DwordCount because Jim */
5228c2ecf20Sopenharmony_ci		  /*        Barnette said that is what we should use since */
5238c2ecf20Sopenharmony_ci		  /*        we are not running in optimized mode? */
5248c2ecf20Sopenharmony_ci		  DMA_RQ_C2_AC_NONE +
5258c2ecf20Sopenharmony_ci		  DMA_RQ_C2_SIGNAL_SOURCE_PINGPONG + /* set play interrupt (bit0) in HISR when source */
5268c2ecf20Sopenharmony_ci		  /*   buffer (on host) crosses half-way point */
5278c2ecf20Sopenharmony_ci		  virtual_channel,                   /* Play DMA channel arbitrarily set to 0 */
5288c2ecf20Sopenharmony_ci		  playback_hw_addr,                  /* HostBuffAddr (source) */
5298c2ecf20Sopenharmony_ci		  DMA_RQ_SD_SP_SAMPLE_ADDR +         /* destination buffer is in SP Sample Memory */
5308c2ecf20Sopenharmony_ci		  sample_buffer_addr                 /* SP Buffer Address (destination) */
5318c2ecf20Sopenharmony_ci		},
5328c2ecf20Sopenharmony_ci		/* Scatter/gather DMA requestor extension   (5 ints) */
5338c2ecf20Sopenharmony_ci		{
5348c2ecf20Sopenharmony_ci			0,
5358c2ecf20Sopenharmony_ci			0,
5368c2ecf20Sopenharmony_ci			0,
5378c2ecf20Sopenharmony_ci			0,
5388c2ecf20Sopenharmony_ci			0
5398c2ecf20Sopenharmony_ci		},
5408c2ecf20Sopenharmony_ci		/* Sublist pointer & next stream control block (SCB) link. */
5418c2ecf20Sopenharmony_ci		NULL_SCB_ADDR,NULL_SCB_ADDR,
5428c2ecf20Sopenharmony_ci		/* Pointer to this tasks parameter block & stream function pointer */
5438c2ecf20Sopenharmony_ci		0,NULL_SCB_ADDR,
5448c2ecf20Sopenharmony_ci		/* rsConfig register for stream buffer (rsDMA reg. is loaded from basicReq.daw */
5458c2ecf20Sopenharmony_ci		/*   for incoming streams, or basicReq.saw, for outgoing streams) */
5468c2ecf20Sopenharmony_ci		RSCONFIG_DMA_ENABLE +                 /* enable DMA */
5478c2ecf20Sopenharmony_ci		(19 << RSCONFIG_MAX_DMA_SIZE_SHIFT) + /* MAX_DMA_SIZE picked to be 19 since SPUD  */
5488c2ecf20Sopenharmony_ci		/*  uses it for some reason */
5498c2ecf20Sopenharmony_ci		((dest >> 4) << RSCONFIG_STREAM_NUM_SHIFT) + /* stream number = SCBaddr/16 */
5508c2ecf20Sopenharmony_ci		RSCONFIG_SAMPLE_16STEREO +
5518c2ecf20Sopenharmony_ci		RSCONFIG_MODULO_32,             /* dest buffer(PCMreaderBuf) is 32 dwords (256 bytes) */
5528c2ecf20Sopenharmony_ci		/* Stream sample pointer & MAC-unit mode for this stream */
5538c2ecf20Sopenharmony_ci		(sample_buffer_addr << 0x10),
5548c2ecf20Sopenharmony_ci		/* Fractional increment per output sample in the input sample buffer */
5558c2ecf20Sopenharmony_ci		0,
5568c2ecf20Sopenharmony_ci		{
5578c2ecf20Sopenharmony_ci			/* Standard stereo volume control
5588c2ecf20Sopenharmony_ci			   default muted */
5598c2ecf20Sopenharmony_ci			0xffff,0xffff,
5608c2ecf20Sopenharmony_ci			0xffff,0xffff
5618c2ecf20Sopenharmony_ci		}
5628c2ecf20Sopenharmony_ci	};
5638c2ecf20Sopenharmony_ci
5648c2ecf20Sopenharmony_ci	if (ins->null_algorithm == NULL) {
5658c2ecf20Sopenharmony_ci		ins->null_algorithm =  cs46xx_dsp_lookup_symbol (chip,"NULLALGORITHM",
5668c2ecf20Sopenharmony_ci								 SYMBOL_CODE);
5678c2ecf20Sopenharmony_ci
5688c2ecf20Sopenharmony_ci		if (ins->null_algorithm == NULL) {
5698c2ecf20Sopenharmony_ci			dev_err(chip->card->dev,
5708c2ecf20Sopenharmony_ci				"dsp_spos: symbol NULLALGORITHM not found\n");
5718c2ecf20Sopenharmony_ci			return NULL;
5728c2ecf20Sopenharmony_ci		}
5738c2ecf20Sopenharmony_ci	}
5748c2ecf20Sopenharmony_ci
5758c2ecf20Sopenharmony_ci	scb = _dsp_create_generic_scb(chip,scb_name,(u32 *)&pcm_reader_scb,
5768c2ecf20Sopenharmony_ci				      dest,ins->null_algorithm,parent_scb,
5778c2ecf20Sopenharmony_ci				      scb_child_type);
5788c2ecf20Sopenharmony_ci
5798c2ecf20Sopenharmony_ci	return scb;
5808c2ecf20Sopenharmony_ci}
5818c2ecf20Sopenharmony_ci
5828c2ecf20Sopenharmony_ci#define GOF_PER_SEC 200
5838c2ecf20Sopenharmony_ci
5848c2ecf20Sopenharmony_cistruct dsp_scb_descriptor *
5858c2ecf20Sopenharmony_cics46xx_dsp_create_src_task_scb(struct snd_cs46xx * chip, char * scb_name,
5868c2ecf20Sopenharmony_ci			       int rate,
5878c2ecf20Sopenharmony_ci                               u16 src_buffer_addr,
5888c2ecf20Sopenharmony_ci                               u16 src_delay_buffer_addr, u32 dest,
5898c2ecf20Sopenharmony_ci                               struct dsp_scb_descriptor * parent_scb,
5908c2ecf20Sopenharmony_ci                               int scb_child_type,
5918c2ecf20Sopenharmony_ci	                       int pass_through)
5928c2ecf20Sopenharmony_ci{
5938c2ecf20Sopenharmony_ci
5948c2ecf20Sopenharmony_ci	struct dsp_spos_instance * ins = chip->dsp_spos_instance;
5958c2ecf20Sopenharmony_ci	struct dsp_scb_descriptor * scb;
5968c2ecf20Sopenharmony_ci	unsigned int tmp1, tmp2;
5978c2ecf20Sopenharmony_ci	unsigned int phiIncr;
5988c2ecf20Sopenharmony_ci	unsigned int correctionPerGOF, correctionPerSec;
5998c2ecf20Sopenharmony_ci
6008c2ecf20Sopenharmony_ci	dev_dbg(chip->card->dev, "dsp_spos: setting %s rate to %u\n",
6018c2ecf20Sopenharmony_ci		scb_name, rate);
6028c2ecf20Sopenharmony_ci
6038c2ecf20Sopenharmony_ci	/*
6048c2ecf20Sopenharmony_ci	 *  Compute the values used to drive the actual sample rate conversion.
6058c2ecf20Sopenharmony_ci	 *  The following formulas are being computed, using inline assembly
6068c2ecf20Sopenharmony_ci	 *  since we need to use 64 bit arithmetic to compute the values:
6078c2ecf20Sopenharmony_ci	 *
6088c2ecf20Sopenharmony_ci	 *  phiIncr = floor((Fs,in * 2^26) / Fs,out)
6098c2ecf20Sopenharmony_ci	 *  correctionPerGOF = floor((Fs,in * 2^26 - Fs,out * phiIncr) /
6108c2ecf20Sopenharmony_ci	 *                                   GOF_PER_SEC)
6118c2ecf20Sopenharmony_ci	 *  ulCorrectionPerSec = Fs,in * 2^26 - Fs,out * phiIncr -M
6128c2ecf20Sopenharmony_ci	 *                       GOF_PER_SEC * correctionPerGOF
6138c2ecf20Sopenharmony_ci	 *
6148c2ecf20Sopenharmony_ci	 *  i.e.
6158c2ecf20Sopenharmony_ci	 *
6168c2ecf20Sopenharmony_ci	 *  phiIncr:other = dividend:remainder((Fs,in * 2^26) / Fs,out)
6178c2ecf20Sopenharmony_ci	 *  correctionPerGOF:correctionPerSec =
6188c2ecf20Sopenharmony_ci	 *      dividend:remainder(ulOther / GOF_PER_SEC)
6198c2ecf20Sopenharmony_ci	 */
6208c2ecf20Sopenharmony_ci	tmp1 = rate << 16;
6218c2ecf20Sopenharmony_ci	phiIncr = tmp1 / 48000;
6228c2ecf20Sopenharmony_ci	tmp1 -= phiIncr * 48000;
6238c2ecf20Sopenharmony_ci	tmp1 <<= 10;
6248c2ecf20Sopenharmony_ci	phiIncr <<= 10;
6258c2ecf20Sopenharmony_ci	tmp2 = tmp1 / 48000;
6268c2ecf20Sopenharmony_ci	phiIncr += tmp2;
6278c2ecf20Sopenharmony_ci	tmp1 -= tmp2 * 48000;
6288c2ecf20Sopenharmony_ci	correctionPerGOF = tmp1 / GOF_PER_SEC;
6298c2ecf20Sopenharmony_ci	tmp1 -= correctionPerGOF * GOF_PER_SEC;
6308c2ecf20Sopenharmony_ci	correctionPerSec = tmp1;
6318c2ecf20Sopenharmony_ci
6328c2ecf20Sopenharmony_ci	{
6338c2ecf20Sopenharmony_ci		struct dsp_src_task_scb src_task_scb = {
6348c2ecf20Sopenharmony_ci			0x0028,0x00c8,
6358c2ecf20Sopenharmony_ci			0x5555,0x0000,
6368c2ecf20Sopenharmony_ci			0x0000,0x0000,
6378c2ecf20Sopenharmony_ci			src_buffer_addr,1,
6388c2ecf20Sopenharmony_ci			correctionPerGOF,correctionPerSec,
6398c2ecf20Sopenharmony_ci			RSCONFIG_SAMPLE_16STEREO + RSCONFIG_MODULO_32,
6408c2ecf20Sopenharmony_ci			0x0000,src_delay_buffer_addr,
6418c2ecf20Sopenharmony_ci			0x0,
6428c2ecf20Sopenharmony_ci			0x080,(src_delay_buffer_addr + (24 * 4)),
6438c2ecf20Sopenharmony_ci			0,0, /* next_scb, sub_list_ptr */
6448c2ecf20Sopenharmony_ci			0,0, /* entry, this_spb */
6458c2ecf20Sopenharmony_ci			RSCONFIG_SAMPLE_16STEREO + RSCONFIG_MODULO_8,
6468c2ecf20Sopenharmony_ci			src_buffer_addr << 0x10,
6478c2ecf20Sopenharmony_ci			phiIncr,
6488c2ecf20Sopenharmony_ci			{
6498c2ecf20Sopenharmony_ci				0xffff - ins->dac_volume_right,0xffff - ins->dac_volume_left,
6508c2ecf20Sopenharmony_ci				0xffff - ins->dac_volume_right,0xffff - ins->dac_volume_left
6518c2ecf20Sopenharmony_ci			}
6528c2ecf20Sopenharmony_ci		};
6538c2ecf20Sopenharmony_ci
6548c2ecf20Sopenharmony_ci		if (ins->s16_up == NULL) {
6558c2ecf20Sopenharmony_ci			ins->s16_up =  cs46xx_dsp_lookup_symbol (chip,"S16_UPSRC",
6568c2ecf20Sopenharmony_ci								 SYMBOL_CODE);
6578c2ecf20Sopenharmony_ci
6588c2ecf20Sopenharmony_ci			if (ins->s16_up == NULL) {
6598c2ecf20Sopenharmony_ci				dev_err(chip->card->dev,
6608c2ecf20Sopenharmony_ci					"dsp_spos: symbol S16_UPSRC not found\n");
6618c2ecf20Sopenharmony_ci				return NULL;
6628c2ecf20Sopenharmony_ci			}
6638c2ecf20Sopenharmony_ci		}
6648c2ecf20Sopenharmony_ci
6658c2ecf20Sopenharmony_ci		/* clear buffers */
6668c2ecf20Sopenharmony_ci		_dsp_clear_sample_buffer (chip,src_buffer_addr,8);
6678c2ecf20Sopenharmony_ci		_dsp_clear_sample_buffer (chip,src_delay_buffer_addr,32);
6688c2ecf20Sopenharmony_ci
6698c2ecf20Sopenharmony_ci		if (pass_through) {
6708c2ecf20Sopenharmony_ci			/* wont work with any other rate than
6718c2ecf20Sopenharmony_ci			   the native DSP rate */
6728c2ecf20Sopenharmony_ci			snd_BUG_ON(rate != 48000);
6738c2ecf20Sopenharmony_ci
6748c2ecf20Sopenharmony_ci			scb = cs46xx_dsp_create_generic_scb(chip,scb_name,(u32 *)&src_task_scb,
6758c2ecf20Sopenharmony_ci							    dest,"DMAREADER",parent_scb,
6768c2ecf20Sopenharmony_ci							    scb_child_type);
6778c2ecf20Sopenharmony_ci		} else {
6788c2ecf20Sopenharmony_ci			scb = _dsp_create_generic_scb(chip,scb_name,(u32 *)&src_task_scb,
6798c2ecf20Sopenharmony_ci						      dest,ins->s16_up,parent_scb,
6808c2ecf20Sopenharmony_ci						      scb_child_type);
6818c2ecf20Sopenharmony_ci		}
6828c2ecf20Sopenharmony_ci
6838c2ecf20Sopenharmony_ci
6848c2ecf20Sopenharmony_ci	}
6858c2ecf20Sopenharmony_ci
6868c2ecf20Sopenharmony_ci	return scb;
6878c2ecf20Sopenharmony_ci}
6888c2ecf20Sopenharmony_ci
6898c2ecf20Sopenharmony_ci#if 0 /* not used */
6908c2ecf20Sopenharmony_cistruct dsp_scb_descriptor *
6918c2ecf20Sopenharmony_cics46xx_dsp_create_filter_scb(struct snd_cs46xx * chip, char * scb_name,
6928c2ecf20Sopenharmony_ci			     u16 buffer_addr, u32 dest,
6938c2ecf20Sopenharmony_ci			     struct dsp_scb_descriptor * parent_scb,
6948c2ecf20Sopenharmony_ci			     int scb_child_type) {
6958c2ecf20Sopenharmony_ci	struct dsp_scb_descriptor * scb;
6968c2ecf20Sopenharmony_ci
6978c2ecf20Sopenharmony_ci	struct dsp_filter_scb filter_scb = {
6988c2ecf20Sopenharmony_ci		.a0_right            = 0x41a9,
6998c2ecf20Sopenharmony_ci		.a0_left             = 0x41a9,
7008c2ecf20Sopenharmony_ci		.a1_right            = 0xb8e4,
7018c2ecf20Sopenharmony_ci		.a1_left             = 0xb8e4,
7028c2ecf20Sopenharmony_ci		.a2_right            = 0x3e55,
7038c2ecf20Sopenharmony_ci		.a2_left             = 0x3e55,
7048c2ecf20Sopenharmony_ci
7058c2ecf20Sopenharmony_ci		.filter_unused3      = 0x0000,
7068c2ecf20Sopenharmony_ci		.filter_unused2      = 0x0000,
7078c2ecf20Sopenharmony_ci
7088c2ecf20Sopenharmony_ci		.output_buf_ptr      = buffer_addr,
7098c2ecf20Sopenharmony_ci		.init                = 0x000,
7108c2ecf20Sopenharmony_ci
7118c2ecf20Sopenharmony_ci		.prev_sample_output1 = 0x00000000,
7128c2ecf20Sopenharmony_ci		.prev_sample_output2 = 0x00000000,
7138c2ecf20Sopenharmony_ci
7148c2ecf20Sopenharmony_ci		.prev_sample_input1  = 0x00000000,
7158c2ecf20Sopenharmony_ci		.prev_sample_input2  = 0x00000000,
7168c2ecf20Sopenharmony_ci
7178c2ecf20Sopenharmony_ci		.next_scb_ptr        = 0x0000,
7188c2ecf20Sopenharmony_ci		.sub_list_ptr        = 0x0000,
7198c2ecf20Sopenharmony_ci
7208c2ecf20Sopenharmony_ci		.entry_point         = 0x0000,
7218c2ecf20Sopenharmony_ci		.spb_ptr             = 0x0000,
7228c2ecf20Sopenharmony_ci
7238c2ecf20Sopenharmony_ci		.b0_right            = 0x0e38,
7248c2ecf20Sopenharmony_ci		.b0_left             = 0x0e38,
7258c2ecf20Sopenharmony_ci		.b1_right            = 0x1c71,
7268c2ecf20Sopenharmony_ci		.b1_left             = 0x1c71,
7278c2ecf20Sopenharmony_ci		.b2_right            = 0x0e38,
7288c2ecf20Sopenharmony_ci		.b2_left             = 0x0e38,
7298c2ecf20Sopenharmony_ci	};
7308c2ecf20Sopenharmony_ci
7318c2ecf20Sopenharmony_ci
7328c2ecf20Sopenharmony_ci	scb = cs46xx_dsp_create_generic_scb(chip,scb_name,(u32 *)&filter_scb,
7338c2ecf20Sopenharmony_ci					    dest,"FILTERTASK",parent_scb,
7348c2ecf20Sopenharmony_ci					    scb_child_type);
7358c2ecf20Sopenharmony_ci
7368c2ecf20Sopenharmony_ci 	return scb;
7378c2ecf20Sopenharmony_ci}
7388c2ecf20Sopenharmony_ci#endif /* not used */
7398c2ecf20Sopenharmony_ci
7408c2ecf20Sopenharmony_cistruct dsp_scb_descriptor *
7418c2ecf20Sopenharmony_cics46xx_dsp_create_mix_only_scb(struct snd_cs46xx * chip, char * scb_name,
7428c2ecf20Sopenharmony_ci                               u16 mix_buffer_addr, u32 dest,
7438c2ecf20Sopenharmony_ci                               struct dsp_scb_descriptor * parent_scb,
7448c2ecf20Sopenharmony_ci                               int scb_child_type)
7458c2ecf20Sopenharmony_ci{
7468c2ecf20Sopenharmony_ci	struct dsp_scb_descriptor * scb;
7478c2ecf20Sopenharmony_ci
7488c2ecf20Sopenharmony_ci	struct dsp_mix_only_scb master_mix_scb = {
7498c2ecf20Sopenharmony_ci		/* 0 */ { 0,
7508c2ecf20Sopenharmony_ci			  /* 1 */   0,
7518c2ecf20Sopenharmony_ci			  /* 2 */  mix_buffer_addr,
7528c2ecf20Sopenharmony_ci			  /* 3 */  0
7538c2ecf20Sopenharmony_ci			  /*   */ },
7548c2ecf20Sopenharmony_ci		{
7558c2ecf20Sopenharmony_ci			/* 4 */  0,
7568c2ecf20Sopenharmony_ci			/* 5 */  0,
7578c2ecf20Sopenharmony_ci			/* 6 */  0,
7588c2ecf20Sopenharmony_ci			/* 7 */  0,
7598c2ecf20Sopenharmony_ci			/* 8 */  0x00000080
7608c2ecf20Sopenharmony_ci		},
7618c2ecf20Sopenharmony_ci		/* 9 */ 0,0,
7628c2ecf20Sopenharmony_ci		/* A */ 0,0,
7638c2ecf20Sopenharmony_ci		/* B */ RSCONFIG_SAMPLE_16STEREO + RSCONFIG_MODULO_32,
7648c2ecf20Sopenharmony_ci		/* C */ (mix_buffer_addr  + (16 * 4)) << 0x10,
7658c2ecf20Sopenharmony_ci		/* D */ 0,
7668c2ecf20Sopenharmony_ci		{
7678c2ecf20Sopenharmony_ci			/* E */ 0x8000,0x8000,
7688c2ecf20Sopenharmony_ci			/* F */ 0x8000,0x8000
7698c2ecf20Sopenharmony_ci		}
7708c2ecf20Sopenharmony_ci	};
7718c2ecf20Sopenharmony_ci
7728c2ecf20Sopenharmony_ci
7738c2ecf20Sopenharmony_ci	scb = cs46xx_dsp_create_generic_scb(chip,scb_name,(u32 *)&master_mix_scb,
7748c2ecf20Sopenharmony_ci					    dest,"S16_MIX",parent_scb,
7758c2ecf20Sopenharmony_ci					    scb_child_type);
7768c2ecf20Sopenharmony_ci	return scb;
7778c2ecf20Sopenharmony_ci}
7788c2ecf20Sopenharmony_ci
7798c2ecf20Sopenharmony_ci
7808c2ecf20Sopenharmony_cistruct dsp_scb_descriptor *
7818c2ecf20Sopenharmony_cics46xx_dsp_create_mix_to_ostream_scb(struct snd_cs46xx * chip, char * scb_name,
7828c2ecf20Sopenharmony_ci                                     u16 mix_buffer_addr, u16 writeback_spb, u32 dest,
7838c2ecf20Sopenharmony_ci                                     struct dsp_scb_descriptor * parent_scb,
7848c2ecf20Sopenharmony_ci                                     int scb_child_type)
7858c2ecf20Sopenharmony_ci{
7868c2ecf20Sopenharmony_ci	struct dsp_scb_descriptor * scb;
7878c2ecf20Sopenharmony_ci
7888c2ecf20Sopenharmony_ci	struct dsp_mix2_ostream_scb mix2_ostream_scb = {
7898c2ecf20Sopenharmony_ci		/* Basic (non scatter/gather) DMA requestor (4 ints) */
7908c2ecf20Sopenharmony_ci		{
7918c2ecf20Sopenharmony_ci			DMA_RQ_C1_SOURCE_MOD64 +
7928c2ecf20Sopenharmony_ci			DMA_RQ_C1_DEST_ON_HOST +
7938c2ecf20Sopenharmony_ci			DMA_RQ_C1_DEST_MOD1024 +
7948c2ecf20Sopenharmony_ci			DMA_RQ_C1_WRITEBACK_SRC_FLAG +
7958c2ecf20Sopenharmony_ci			DMA_RQ_C1_WRITEBACK_DEST_FLAG +
7968c2ecf20Sopenharmony_ci			15,
7978c2ecf20Sopenharmony_ci
7988c2ecf20Sopenharmony_ci			DMA_RQ_C2_AC_NONE +
7998c2ecf20Sopenharmony_ci			DMA_RQ_C2_SIGNAL_DEST_PINGPONG +
8008c2ecf20Sopenharmony_ci
8018c2ecf20Sopenharmony_ci			CS46XX_DSP_CAPTURE_CHANNEL,
8028c2ecf20Sopenharmony_ci			DMA_RQ_SD_SP_SAMPLE_ADDR +
8038c2ecf20Sopenharmony_ci			mix_buffer_addr,
8048c2ecf20Sopenharmony_ci			0x0
8058c2ecf20Sopenharmony_ci		},
8068c2ecf20Sopenharmony_ci
8078c2ecf20Sopenharmony_ci		{ 0, 0, 0, 0, 0, },
8088c2ecf20Sopenharmony_ci		0,0,
8098c2ecf20Sopenharmony_ci		0,writeback_spb,
8108c2ecf20Sopenharmony_ci
8118c2ecf20Sopenharmony_ci		RSCONFIG_DMA_ENABLE +
8128c2ecf20Sopenharmony_ci		(19 << RSCONFIG_MAX_DMA_SIZE_SHIFT) +
8138c2ecf20Sopenharmony_ci
8148c2ecf20Sopenharmony_ci		((dest >> 4) << RSCONFIG_STREAM_NUM_SHIFT) +
8158c2ecf20Sopenharmony_ci		RSCONFIG_DMA_TO_HOST +
8168c2ecf20Sopenharmony_ci		RSCONFIG_SAMPLE_16STEREO +
8178c2ecf20Sopenharmony_ci		RSCONFIG_MODULO_64,
8188c2ecf20Sopenharmony_ci		(mix_buffer_addr + (32 * 4)) << 0x10,
8198c2ecf20Sopenharmony_ci		1,0,
8208c2ecf20Sopenharmony_ci		0x0001,0x0080,
8218c2ecf20Sopenharmony_ci		0xFFFF,0
8228c2ecf20Sopenharmony_ci	};
8238c2ecf20Sopenharmony_ci
8248c2ecf20Sopenharmony_ci
8258c2ecf20Sopenharmony_ci	scb = cs46xx_dsp_create_generic_scb(chip,scb_name,(u32 *)&mix2_ostream_scb,
8268c2ecf20Sopenharmony_ci
8278c2ecf20Sopenharmony_ci	    dest,"S16_MIX_TO_OSTREAM",parent_scb,
8288c2ecf20Sopenharmony_ci					    scb_child_type);
8298c2ecf20Sopenharmony_ci
8308c2ecf20Sopenharmony_ci	return scb;
8318c2ecf20Sopenharmony_ci}
8328c2ecf20Sopenharmony_ci
8338c2ecf20Sopenharmony_ci
8348c2ecf20Sopenharmony_cistruct dsp_scb_descriptor *
8358c2ecf20Sopenharmony_cics46xx_dsp_create_vari_decimate_scb(struct snd_cs46xx * chip,char * scb_name,
8368c2ecf20Sopenharmony_ci                                    u16 vari_buffer_addr0,
8378c2ecf20Sopenharmony_ci                                    u16 vari_buffer_addr1,
8388c2ecf20Sopenharmony_ci                                    u32 dest,
8398c2ecf20Sopenharmony_ci                                    struct dsp_scb_descriptor * parent_scb,
8408c2ecf20Sopenharmony_ci                                    int scb_child_type)
8418c2ecf20Sopenharmony_ci{
8428c2ecf20Sopenharmony_ci
8438c2ecf20Sopenharmony_ci	struct dsp_scb_descriptor * scb;
8448c2ecf20Sopenharmony_ci
8458c2ecf20Sopenharmony_ci	struct dsp_vari_decimate_scb vari_decimate_scb = {
8468c2ecf20Sopenharmony_ci		0x0028,0x00c8,
8478c2ecf20Sopenharmony_ci		0x5555,0x0000,
8488c2ecf20Sopenharmony_ci		0x0000,0x0000,
8498c2ecf20Sopenharmony_ci		vari_buffer_addr0,vari_buffer_addr1,
8508c2ecf20Sopenharmony_ci
8518c2ecf20Sopenharmony_ci		0x0028,0x00c8,
8528c2ecf20Sopenharmony_ci		RSCONFIG_SAMPLE_16STEREO + RSCONFIG_MODULO_256,
8538c2ecf20Sopenharmony_ci
8548c2ecf20Sopenharmony_ci		0xFF800000,
8558c2ecf20Sopenharmony_ci		0,
8568c2ecf20Sopenharmony_ci		0x0080,vari_buffer_addr1 + (25 * 4),
8578c2ecf20Sopenharmony_ci
8588c2ecf20Sopenharmony_ci		0,0,
8598c2ecf20Sopenharmony_ci		0,0,
8608c2ecf20Sopenharmony_ci
8618c2ecf20Sopenharmony_ci		RSCONFIG_SAMPLE_16STEREO + RSCONFIG_MODULO_8,
8628c2ecf20Sopenharmony_ci		vari_buffer_addr0 << 0x10,
8638c2ecf20Sopenharmony_ci		0x04000000,
8648c2ecf20Sopenharmony_ci		{
8658c2ecf20Sopenharmony_ci			0x8000,0x8000,
8668c2ecf20Sopenharmony_ci			0xFFFF,0xFFFF
8678c2ecf20Sopenharmony_ci		}
8688c2ecf20Sopenharmony_ci	};
8698c2ecf20Sopenharmony_ci
8708c2ecf20Sopenharmony_ci	scb = cs46xx_dsp_create_generic_scb(chip,scb_name,(u32 *)&vari_decimate_scb,
8718c2ecf20Sopenharmony_ci					    dest,"VARIDECIMATE",parent_scb,
8728c2ecf20Sopenharmony_ci					    scb_child_type);
8738c2ecf20Sopenharmony_ci
8748c2ecf20Sopenharmony_ci	return scb;
8758c2ecf20Sopenharmony_ci}
8768c2ecf20Sopenharmony_ci
8778c2ecf20Sopenharmony_ci
8788c2ecf20Sopenharmony_cistatic struct dsp_scb_descriptor *
8798c2ecf20Sopenharmony_cics46xx_dsp_create_pcm_serial_input_scb(struct snd_cs46xx * chip, char * scb_name, u32 dest,
8808c2ecf20Sopenharmony_ci                                       struct dsp_scb_descriptor * input_scb,
8818c2ecf20Sopenharmony_ci                                       struct dsp_scb_descriptor * parent_scb,
8828c2ecf20Sopenharmony_ci                                       int scb_child_type)
8838c2ecf20Sopenharmony_ci{
8848c2ecf20Sopenharmony_ci
8858c2ecf20Sopenharmony_ci	struct dsp_scb_descriptor * scb;
8868c2ecf20Sopenharmony_ci
8878c2ecf20Sopenharmony_ci
8888c2ecf20Sopenharmony_ci	struct dsp_pcm_serial_input_scb pcm_serial_input_scb = {
8898c2ecf20Sopenharmony_ci		{ 0,
8908c2ecf20Sopenharmony_ci		  0,
8918c2ecf20Sopenharmony_ci		  0,
8928c2ecf20Sopenharmony_ci		  0
8938c2ecf20Sopenharmony_ci		},
8948c2ecf20Sopenharmony_ci		{
8958c2ecf20Sopenharmony_ci			0,
8968c2ecf20Sopenharmony_ci			0,
8978c2ecf20Sopenharmony_ci			0,
8988c2ecf20Sopenharmony_ci			0,
8998c2ecf20Sopenharmony_ci			0
9008c2ecf20Sopenharmony_ci		},
9018c2ecf20Sopenharmony_ci
9028c2ecf20Sopenharmony_ci		0,0,
9038c2ecf20Sopenharmony_ci		0,0,
9048c2ecf20Sopenharmony_ci
9058c2ecf20Sopenharmony_ci		RSCONFIG_SAMPLE_16STEREO + RSCONFIG_MODULO_16,
9068c2ecf20Sopenharmony_ci		0,
9078c2ecf20Sopenharmony_ci      /* 0xD */ 0,input_scb->address,
9088c2ecf20Sopenharmony_ci		{
9098c2ecf20Sopenharmony_ci      /* 0xE */   0x8000,0x8000,
9108c2ecf20Sopenharmony_ci      /* 0xF */	  0x8000,0x8000
9118c2ecf20Sopenharmony_ci		}
9128c2ecf20Sopenharmony_ci	};
9138c2ecf20Sopenharmony_ci
9148c2ecf20Sopenharmony_ci	scb = cs46xx_dsp_create_generic_scb(chip,scb_name,(u32 *)&pcm_serial_input_scb,
9158c2ecf20Sopenharmony_ci					    dest,"PCMSERIALINPUTTASK",parent_scb,
9168c2ecf20Sopenharmony_ci					    scb_child_type);
9178c2ecf20Sopenharmony_ci	return scb;
9188c2ecf20Sopenharmony_ci}
9198c2ecf20Sopenharmony_ci
9208c2ecf20Sopenharmony_ci
9218c2ecf20Sopenharmony_cistatic struct dsp_scb_descriptor *
9228c2ecf20Sopenharmony_cics46xx_dsp_create_asynch_fg_tx_scb(struct snd_cs46xx * chip, char * scb_name, u32 dest,
9238c2ecf20Sopenharmony_ci                                   u16 hfg_scb_address,
9248c2ecf20Sopenharmony_ci                                   u16 asynch_buffer_address,
9258c2ecf20Sopenharmony_ci                                   struct dsp_scb_descriptor * parent_scb,
9268c2ecf20Sopenharmony_ci                                   int scb_child_type)
9278c2ecf20Sopenharmony_ci{
9288c2ecf20Sopenharmony_ci
9298c2ecf20Sopenharmony_ci	struct dsp_scb_descriptor * scb;
9308c2ecf20Sopenharmony_ci
9318c2ecf20Sopenharmony_ci	struct dsp_asynch_fg_tx_scb asynch_fg_tx_scb = {
9328c2ecf20Sopenharmony_ci		0xfc00,0x03ff,      /*  Prototype sample buffer size of 256 dwords */
9338c2ecf20Sopenharmony_ci		0x0058,0x0028,      /* Min Delta 7 dwords == 28 bytes */
9348c2ecf20Sopenharmony_ci		/* : Max delta 25 dwords == 100 bytes */
9358c2ecf20Sopenharmony_ci		0,hfg_scb_address,  /* Point to HFG task SCB */
9368c2ecf20Sopenharmony_ci		0,0,		    /* Initialize current Delta and Consumer ptr adjustment count */
9378c2ecf20Sopenharmony_ci		0,                  /* Initialize accumulated Phi to 0 */
9388c2ecf20Sopenharmony_ci		0,0x2aab,           /* Const 1/3 */
9398c2ecf20Sopenharmony_ci
9408c2ecf20Sopenharmony_ci		{
9418c2ecf20Sopenharmony_ci			0,         /* Define the unused elements */
9428c2ecf20Sopenharmony_ci			0,
9438c2ecf20Sopenharmony_ci			0
9448c2ecf20Sopenharmony_ci		},
9458c2ecf20Sopenharmony_ci
9468c2ecf20Sopenharmony_ci		0,0,
9478c2ecf20Sopenharmony_ci		0,dest + AFGTxAccumPhi,
9488c2ecf20Sopenharmony_ci
9498c2ecf20Sopenharmony_ci		RSCONFIG_SAMPLE_16STEREO + RSCONFIG_MODULO_256, /* Stereo, 256 dword */
9508c2ecf20Sopenharmony_ci		(asynch_buffer_address) << 0x10,  /* This should be automagically synchronized
9518c2ecf20Sopenharmony_ci                                                     to the producer pointer */
9528c2ecf20Sopenharmony_ci
9538c2ecf20Sopenharmony_ci		/* There is no correct initial value, it will depend upon the detected
9548c2ecf20Sopenharmony_ci		   rate etc  */
9558c2ecf20Sopenharmony_ci		0x18000000,                     /* Phi increment for approx 32k operation */
9568c2ecf20Sopenharmony_ci		0x8000,0x8000,                  /* Volume controls are unused at this time */
9578c2ecf20Sopenharmony_ci		0x8000,0x8000
9588c2ecf20Sopenharmony_ci	};
9598c2ecf20Sopenharmony_ci
9608c2ecf20Sopenharmony_ci	scb = cs46xx_dsp_create_generic_scb(chip,scb_name,(u32 *)&asynch_fg_tx_scb,
9618c2ecf20Sopenharmony_ci					    dest,"ASYNCHFGTXCODE",parent_scb,
9628c2ecf20Sopenharmony_ci					    scb_child_type);
9638c2ecf20Sopenharmony_ci
9648c2ecf20Sopenharmony_ci	return scb;
9658c2ecf20Sopenharmony_ci}
9668c2ecf20Sopenharmony_ci
9678c2ecf20Sopenharmony_ci
9688c2ecf20Sopenharmony_cistruct dsp_scb_descriptor *
9698c2ecf20Sopenharmony_cics46xx_dsp_create_asynch_fg_rx_scb(struct snd_cs46xx * chip, char * scb_name, u32 dest,
9708c2ecf20Sopenharmony_ci                                   u16 hfg_scb_address,
9718c2ecf20Sopenharmony_ci                                   u16 asynch_buffer_address,
9728c2ecf20Sopenharmony_ci                                   struct dsp_scb_descriptor * parent_scb,
9738c2ecf20Sopenharmony_ci                                   int scb_child_type)
9748c2ecf20Sopenharmony_ci{
9758c2ecf20Sopenharmony_ci	struct dsp_spos_instance * ins = chip->dsp_spos_instance;
9768c2ecf20Sopenharmony_ci	struct dsp_scb_descriptor * scb;
9778c2ecf20Sopenharmony_ci
9788c2ecf20Sopenharmony_ci	struct dsp_asynch_fg_rx_scb asynch_fg_rx_scb = {
9798c2ecf20Sopenharmony_ci		0xfe00,0x01ff,      /*  Prototype sample buffer size of 128 dwords */
9808c2ecf20Sopenharmony_ci		0x0064,0x001c,      /* Min Delta 7 dwords == 28 bytes */
9818c2ecf20Sopenharmony_ci		                    /* : Max delta 25 dwords == 100 bytes */
9828c2ecf20Sopenharmony_ci		0,hfg_scb_address,  /* Point to HFG task SCB */
9838c2ecf20Sopenharmony_ci		0,0,				/* Initialize current Delta and Consumer ptr adjustment count */
9848c2ecf20Sopenharmony_ci		{
9858c2ecf20Sopenharmony_ci			0,                /* Define the unused elements */
9868c2ecf20Sopenharmony_ci			0,
9878c2ecf20Sopenharmony_ci			0,
9888c2ecf20Sopenharmony_ci			0,
9898c2ecf20Sopenharmony_ci			0
9908c2ecf20Sopenharmony_ci		},
9918c2ecf20Sopenharmony_ci
9928c2ecf20Sopenharmony_ci		0,0,
9938c2ecf20Sopenharmony_ci		0,dest,
9948c2ecf20Sopenharmony_ci
9958c2ecf20Sopenharmony_ci		RSCONFIG_MODULO_128 |
9968c2ecf20Sopenharmony_ci        RSCONFIG_SAMPLE_16STEREO,                         /* Stereo, 128 dword */
9978c2ecf20Sopenharmony_ci		( (asynch_buffer_address + (16 * 4))  << 0x10),   /* This should be automagically
9988c2ecf20Sopenharmony_ci							                                  synchrinized to the producer pointer */
9998c2ecf20Sopenharmony_ci
10008c2ecf20Sopenharmony_ci		/* There is no correct initial value, it will depend upon the detected
10018c2ecf20Sopenharmony_ci		   rate etc  */
10028c2ecf20Sopenharmony_ci		0x18000000,
10038c2ecf20Sopenharmony_ci
10048c2ecf20Sopenharmony_ci		/* Set IEC958 input volume */
10058c2ecf20Sopenharmony_ci		0xffff - ins->spdif_input_volume_right,0xffff - ins->spdif_input_volume_left,
10068c2ecf20Sopenharmony_ci		0xffff - ins->spdif_input_volume_right,0xffff - ins->spdif_input_volume_left,
10078c2ecf20Sopenharmony_ci	};
10088c2ecf20Sopenharmony_ci
10098c2ecf20Sopenharmony_ci	scb = cs46xx_dsp_create_generic_scb(chip,scb_name,(u32 *)&asynch_fg_rx_scb,
10108c2ecf20Sopenharmony_ci					    dest,"ASYNCHFGRXCODE",parent_scb,
10118c2ecf20Sopenharmony_ci					    scb_child_type);
10128c2ecf20Sopenharmony_ci
10138c2ecf20Sopenharmony_ci	return scb;
10148c2ecf20Sopenharmony_ci}
10158c2ecf20Sopenharmony_ci
10168c2ecf20Sopenharmony_ci
10178c2ecf20Sopenharmony_ci#if 0 /* not used */
10188c2ecf20Sopenharmony_cistruct dsp_scb_descriptor *
10198c2ecf20Sopenharmony_cics46xx_dsp_create_output_snoop_scb(struct snd_cs46xx * chip, char * scb_name, u32 dest,
10208c2ecf20Sopenharmony_ci                                   u16 snoop_buffer_address,
10218c2ecf20Sopenharmony_ci                                   struct dsp_scb_descriptor * snoop_scb,
10228c2ecf20Sopenharmony_ci                                   struct dsp_scb_descriptor * parent_scb,
10238c2ecf20Sopenharmony_ci                                   int scb_child_type)
10248c2ecf20Sopenharmony_ci{
10258c2ecf20Sopenharmony_ci
10268c2ecf20Sopenharmony_ci	struct dsp_scb_descriptor * scb;
10278c2ecf20Sopenharmony_ci
10288c2ecf20Sopenharmony_ci	struct dsp_output_snoop_scb output_snoop_scb = {
10298c2ecf20Sopenharmony_ci		{ 0,	/*  not used.  Zero */
10308c2ecf20Sopenharmony_ci		  0,
10318c2ecf20Sopenharmony_ci		  0,
10328c2ecf20Sopenharmony_ci		  0,
10338c2ecf20Sopenharmony_ci		},
10348c2ecf20Sopenharmony_ci		{
10358c2ecf20Sopenharmony_ci			0, /* not used.  Zero */
10368c2ecf20Sopenharmony_ci			0,
10378c2ecf20Sopenharmony_ci			0,
10388c2ecf20Sopenharmony_ci			0,
10398c2ecf20Sopenharmony_ci			0
10408c2ecf20Sopenharmony_ci		},
10418c2ecf20Sopenharmony_ci
10428c2ecf20Sopenharmony_ci		0,0,
10438c2ecf20Sopenharmony_ci		0,0,
10448c2ecf20Sopenharmony_ci
10458c2ecf20Sopenharmony_ci		RSCONFIG_SAMPLE_16STEREO + RSCONFIG_MODULO_64,
10468c2ecf20Sopenharmony_ci		snoop_buffer_address << 0x10,
10478c2ecf20Sopenharmony_ci		0,0,
10488c2ecf20Sopenharmony_ci		0,
10498c2ecf20Sopenharmony_ci		0,snoop_scb->address
10508c2ecf20Sopenharmony_ci	};
10518c2ecf20Sopenharmony_ci
10528c2ecf20Sopenharmony_ci	scb = cs46xx_dsp_create_generic_scb(chip,scb_name,(u32 *)&output_snoop_scb,
10538c2ecf20Sopenharmony_ci					    dest,"OUTPUTSNOOP",parent_scb,
10548c2ecf20Sopenharmony_ci					    scb_child_type);
10558c2ecf20Sopenharmony_ci	return scb;
10568c2ecf20Sopenharmony_ci}
10578c2ecf20Sopenharmony_ci#endif /* not used */
10588c2ecf20Sopenharmony_ci
10598c2ecf20Sopenharmony_ci
10608c2ecf20Sopenharmony_cistruct dsp_scb_descriptor *
10618c2ecf20Sopenharmony_cics46xx_dsp_create_spio_write_scb(struct snd_cs46xx * chip, char * scb_name, u32 dest,
10628c2ecf20Sopenharmony_ci                                 struct dsp_scb_descriptor * parent_scb,
10638c2ecf20Sopenharmony_ci                                 int scb_child_type)
10648c2ecf20Sopenharmony_ci{
10658c2ecf20Sopenharmony_ci	struct dsp_scb_descriptor * scb;
10668c2ecf20Sopenharmony_ci
10678c2ecf20Sopenharmony_ci	struct dsp_spio_write_scb spio_write_scb = {
10688c2ecf20Sopenharmony_ci		0,0,         /*   SPIOWAddress2:SPIOWAddress1; */
10698c2ecf20Sopenharmony_ci		0,           /*   SPIOWData1; */
10708c2ecf20Sopenharmony_ci		0,           /*   SPIOWData2; */
10718c2ecf20Sopenharmony_ci		0,0,         /*   SPIOWAddress4:SPIOWAddress3; */
10728c2ecf20Sopenharmony_ci		0,           /*   SPIOWData3; */
10738c2ecf20Sopenharmony_ci		0,           /*   SPIOWData4; */
10748c2ecf20Sopenharmony_ci		0,0,         /*   SPIOWDataPtr:Unused1; */
10758c2ecf20Sopenharmony_ci		{ 0,0 },     /*   Unused2[2]; */
10768c2ecf20Sopenharmony_ci
10778c2ecf20Sopenharmony_ci		0,0,	     /*   SPIOWChildPtr:SPIOWSiblingPtr; */
10788c2ecf20Sopenharmony_ci		0,0,         /*   SPIOWThisPtr:SPIOWEntryPoint; */
10798c2ecf20Sopenharmony_ci
10808c2ecf20Sopenharmony_ci		{
10818c2ecf20Sopenharmony_ci			0,
10828c2ecf20Sopenharmony_ci			0,
10838c2ecf20Sopenharmony_ci			0,
10848c2ecf20Sopenharmony_ci			0,
10858c2ecf20Sopenharmony_ci			0          /*   Unused3[5];  */
10868c2ecf20Sopenharmony_ci		}
10878c2ecf20Sopenharmony_ci	};
10888c2ecf20Sopenharmony_ci
10898c2ecf20Sopenharmony_ci	scb = cs46xx_dsp_create_generic_scb(chip,scb_name,(u32 *)&spio_write_scb,
10908c2ecf20Sopenharmony_ci					    dest,"SPIOWRITE",parent_scb,
10918c2ecf20Sopenharmony_ci					    scb_child_type);
10928c2ecf20Sopenharmony_ci
10938c2ecf20Sopenharmony_ci	return scb;
10948c2ecf20Sopenharmony_ci}
10958c2ecf20Sopenharmony_ci
10968c2ecf20Sopenharmony_cistruct dsp_scb_descriptor *
10978c2ecf20Sopenharmony_cics46xx_dsp_create_magic_snoop_scb(struct snd_cs46xx * chip, char * scb_name, u32 dest,
10988c2ecf20Sopenharmony_ci				  u16 snoop_buffer_address,
10998c2ecf20Sopenharmony_ci				  struct dsp_scb_descriptor * snoop_scb,
11008c2ecf20Sopenharmony_ci				  struct dsp_scb_descriptor * parent_scb,
11018c2ecf20Sopenharmony_ci				  int scb_child_type)
11028c2ecf20Sopenharmony_ci{
11038c2ecf20Sopenharmony_ci	struct dsp_scb_descriptor * scb;
11048c2ecf20Sopenharmony_ci
11058c2ecf20Sopenharmony_ci	struct dsp_magic_snoop_task magic_snoop_scb = {
11068c2ecf20Sopenharmony_ci		/* 0 */ 0, /* i0 */
11078c2ecf20Sopenharmony_ci		/* 1 */ 0, /* i1 */
11088c2ecf20Sopenharmony_ci		/* 2 */ snoop_buffer_address << 0x10,
11098c2ecf20Sopenharmony_ci		/* 3 */ 0,snoop_scb->address,
11108c2ecf20Sopenharmony_ci		/* 4 */ 0, /* i3 */
11118c2ecf20Sopenharmony_ci		/* 5 */ 0, /* i4 */
11128c2ecf20Sopenharmony_ci		/* 6 */ 0, /* i5 */
11138c2ecf20Sopenharmony_ci		/* 7 */ 0, /* i6 */
11148c2ecf20Sopenharmony_ci		/* 8 */ 0, /* i7 */
11158c2ecf20Sopenharmony_ci		/* 9 */ 0,0, /* next_scb, sub_list_ptr */
11168c2ecf20Sopenharmony_ci		/* A */ 0,0, /* entry_point, this_ptr */
11178c2ecf20Sopenharmony_ci		/* B */ RSCONFIG_SAMPLE_16STEREO + RSCONFIG_MODULO_64,
11188c2ecf20Sopenharmony_ci		/* C */ snoop_buffer_address  << 0x10,
11198c2ecf20Sopenharmony_ci		/* D */ 0,
11208c2ecf20Sopenharmony_ci		/* E */ { 0x8000,0x8000,
11218c2ecf20Sopenharmony_ci	        /* F */   0xffff,0xffff
11228c2ecf20Sopenharmony_ci		}
11238c2ecf20Sopenharmony_ci	};
11248c2ecf20Sopenharmony_ci
11258c2ecf20Sopenharmony_ci	scb = cs46xx_dsp_create_generic_scb(chip,scb_name,(u32 *)&magic_snoop_scb,
11268c2ecf20Sopenharmony_ci					    dest,"MAGICSNOOPTASK",parent_scb,
11278c2ecf20Sopenharmony_ci					    scb_child_type);
11288c2ecf20Sopenharmony_ci
11298c2ecf20Sopenharmony_ci	return scb;
11308c2ecf20Sopenharmony_ci}
11318c2ecf20Sopenharmony_ci
11328c2ecf20Sopenharmony_cistatic struct dsp_scb_descriptor *
11338c2ecf20Sopenharmony_cifind_next_free_scb (struct snd_cs46xx * chip, struct dsp_scb_descriptor * from)
11348c2ecf20Sopenharmony_ci{
11358c2ecf20Sopenharmony_ci	struct dsp_spos_instance * ins = chip->dsp_spos_instance;
11368c2ecf20Sopenharmony_ci	struct dsp_scb_descriptor * scb = from;
11378c2ecf20Sopenharmony_ci
11388c2ecf20Sopenharmony_ci	while (scb->next_scb_ptr != ins->the_null_scb) {
11398c2ecf20Sopenharmony_ci		if (snd_BUG_ON(!scb->next_scb_ptr))
11408c2ecf20Sopenharmony_ci			return NULL;
11418c2ecf20Sopenharmony_ci
11428c2ecf20Sopenharmony_ci		scb = scb->next_scb_ptr;
11438c2ecf20Sopenharmony_ci	}
11448c2ecf20Sopenharmony_ci
11458c2ecf20Sopenharmony_ci	return scb;
11468c2ecf20Sopenharmony_ci}
11478c2ecf20Sopenharmony_ci
11488c2ecf20Sopenharmony_cistatic const u32 pcm_reader_buffer_addr[DSP_MAX_PCM_CHANNELS] = {
11498c2ecf20Sopenharmony_ci	0x0600, /* 1 */
11508c2ecf20Sopenharmony_ci	0x1500, /* 2 */
11518c2ecf20Sopenharmony_ci	0x1580, /* 3 */
11528c2ecf20Sopenharmony_ci	0x1600, /* 4 */
11538c2ecf20Sopenharmony_ci	0x1680, /* 5 */
11548c2ecf20Sopenharmony_ci	0x1700, /* 6 */
11558c2ecf20Sopenharmony_ci	0x1780, /* 7 */
11568c2ecf20Sopenharmony_ci	0x1800, /* 8 */
11578c2ecf20Sopenharmony_ci	0x1880, /* 9 */
11588c2ecf20Sopenharmony_ci	0x1900, /* 10 */
11598c2ecf20Sopenharmony_ci	0x1980, /* 11 */
11608c2ecf20Sopenharmony_ci	0x1A00, /* 12 */
11618c2ecf20Sopenharmony_ci	0x1A80, /* 13 */
11628c2ecf20Sopenharmony_ci	0x1B00, /* 14 */
11638c2ecf20Sopenharmony_ci	0x1B80, /* 15 */
11648c2ecf20Sopenharmony_ci	0x1C00, /* 16 */
11658c2ecf20Sopenharmony_ci	0x1C80, /* 17 */
11668c2ecf20Sopenharmony_ci	0x1D00, /* 18 */
11678c2ecf20Sopenharmony_ci	0x1D80, /* 19 */
11688c2ecf20Sopenharmony_ci	0x1E00, /* 20 */
11698c2ecf20Sopenharmony_ci	0x1E80, /* 21 */
11708c2ecf20Sopenharmony_ci	0x1F00, /* 22 */
11718c2ecf20Sopenharmony_ci	0x1F80, /* 23 */
11728c2ecf20Sopenharmony_ci	0x2000, /* 24 */
11738c2ecf20Sopenharmony_ci	0x2080, /* 25 */
11748c2ecf20Sopenharmony_ci	0x2100, /* 26 */
11758c2ecf20Sopenharmony_ci	0x2180, /* 27 */
11768c2ecf20Sopenharmony_ci	0x2200, /* 28 */
11778c2ecf20Sopenharmony_ci	0x2280, /* 29 */
11788c2ecf20Sopenharmony_ci	0x2300, /* 30 */
11798c2ecf20Sopenharmony_ci	0x2380, /* 31 */
11808c2ecf20Sopenharmony_ci	0x2400, /* 32 */
11818c2ecf20Sopenharmony_ci};
11828c2ecf20Sopenharmony_ci
11838c2ecf20Sopenharmony_cistatic const u32 src_output_buffer_addr[DSP_MAX_SRC_NR] = {
11848c2ecf20Sopenharmony_ci	0x2B80,
11858c2ecf20Sopenharmony_ci	0x2BA0,
11868c2ecf20Sopenharmony_ci	0x2BC0,
11878c2ecf20Sopenharmony_ci	0x2BE0,
11888c2ecf20Sopenharmony_ci	0x2D00,
11898c2ecf20Sopenharmony_ci	0x2D20,
11908c2ecf20Sopenharmony_ci	0x2D40,
11918c2ecf20Sopenharmony_ci	0x2D60,
11928c2ecf20Sopenharmony_ci	0x2D80,
11938c2ecf20Sopenharmony_ci	0x2DA0,
11948c2ecf20Sopenharmony_ci	0x2DC0,
11958c2ecf20Sopenharmony_ci	0x2DE0,
11968c2ecf20Sopenharmony_ci	0x2E00,
11978c2ecf20Sopenharmony_ci	0x2E20
11988c2ecf20Sopenharmony_ci};
11998c2ecf20Sopenharmony_ci
12008c2ecf20Sopenharmony_cistatic const u32 src_delay_buffer_addr[DSP_MAX_SRC_NR] = {
12018c2ecf20Sopenharmony_ci	0x2480,
12028c2ecf20Sopenharmony_ci	0x2500,
12038c2ecf20Sopenharmony_ci	0x2580,
12048c2ecf20Sopenharmony_ci	0x2600,
12058c2ecf20Sopenharmony_ci	0x2680,
12068c2ecf20Sopenharmony_ci	0x2700,
12078c2ecf20Sopenharmony_ci	0x2780,
12088c2ecf20Sopenharmony_ci	0x2800,
12098c2ecf20Sopenharmony_ci	0x2880,
12108c2ecf20Sopenharmony_ci	0x2900,
12118c2ecf20Sopenharmony_ci	0x2980,
12128c2ecf20Sopenharmony_ci	0x2A00,
12138c2ecf20Sopenharmony_ci	0x2A80,
12148c2ecf20Sopenharmony_ci	0x2B00
12158c2ecf20Sopenharmony_ci};
12168c2ecf20Sopenharmony_ci
12178c2ecf20Sopenharmony_cistruct dsp_pcm_channel_descriptor *
12188c2ecf20Sopenharmony_cics46xx_dsp_create_pcm_channel (struct snd_cs46xx * chip,
12198c2ecf20Sopenharmony_ci			       u32 sample_rate, void * private_data,
12208c2ecf20Sopenharmony_ci			       u32 hw_dma_addr,
12218c2ecf20Sopenharmony_ci			       int pcm_channel_id)
12228c2ecf20Sopenharmony_ci{
12238c2ecf20Sopenharmony_ci	struct dsp_spos_instance * ins = chip->dsp_spos_instance;
12248c2ecf20Sopenharmony_ci	struct dsp_scb_descriptor * src_scb = NULL, * pcm_scb, * mixer_scb = NULL;
12258c2ecf20Sopenharmony_ci	struct dsp_scb_descriptor * src_parent_scb = NULL;
12268c2ecf20Sopenharmony_ci
12278c2ecf20Sopenharmony_ci	/* struct dsp_scb_descriptor * pcm_parent_scb; */
12288c2ecf20Sopenharmony_ci	char scb_name[DSP_MAX_SCB_NAME];
12298c2ecf20Sopenharmony_ci	int i, pcm_index = -1, insert_point, src_index = -1, pass_through = 0;
12308c2ecf20Sopenharmony_ci	unsigned long flags;
12318c2ecf20Sopenharmony_ci
12328c2ecf20Sopenharmony_ci	switch (pcm_channel_id) {
12338c2ecf20Sopenharmony_ci	case DSP_PCM_MAIN_CHANNEL:
12348c2ecf20Sopenharmony_ci		mixer_scb = ins->master_mix_scb;
12358c2ecf20Sopenharmony_ci		break;
12368c2ecf20Sopenharmony_ci	case DSP_PCM_REAR_CHANNEL:
12378c2ecf20Sopenharmony_ci		mixer_scb = ins->rear_mix_scb;
12388c2ecf20Sopenharmony_ci		break;
12398c2ecf20Sopenharmony_ci	case DSP_PCM_CENTER_LFE_CHANNEL:
12408c2ecf20Sopenharmony_ci		mixer_scb = ins->center_lfe_mix_scb;
12418c2ecf20Sopenharmony_ci		break;
12428c2ecf20Sopenharmony_ci	case DSP_PCM_S71_CHANNEL:
12438c2ecf20Sopenharmony_ci		/* TODO */
12448c2ecf20Sopenharmony_ci		snd_BUG();
12458c2ecf20Sopenharmony_ci		break;
12468c2ecf20Sopenharmony_ci	case DSP_IEC958_CHANNEL:
12478c2ecf20Sopenharmony_ci		if (snd_BUG_ON(!ins->asynch_tx_scb))
12488c2ecf20Sopenharmony_ci			return NULL;
12498c2ecf20Sopenharmony_ci		mixer_scb = ins->asynch_tx_scb;
12508c2ecf20Sopenharmony_ci
12518c2ecf20Sopenharmony_ci		/* if sample rate is set to 48khz we pass
12528c2ecf20Sopenharmony_ci		   the Sample Rate Converted (which could
12538c2ecf20Sopenharmony_ci		   alter the raw data stream ...) */
12548c2ecf20Sopenharmony_ci		if (sample_rate == 48000) {
12558c2ecf20Sopenharmony_ci			dev_dbg(chip->card->dev, "IEC958 pass through\n");
12568c2ecf20Sopenharmony_ci			/* Hack to bypass creating a new SRC */
12578c2ecf20Sopenharmony_ci			pass_through = 1;
12588c2ecf20Sopenharmony_ci		}
12598c2ecf20Sopenharmony_ci		break;
12608c2ecf20Sopenharmony_ci	default:
12618c2ecf20Sopenharmony_ci		snd_BUG();
12628c2ecf20Sopenharmony_ci		return NULL;
12638c2ecf20Sopenharmony_ci	}
12648c2ecf20Sopenharmony_ci	/* default sample rate is 44100 */
12658c2ecf20Sopenharmony_ci	if (!sample_rate) sample_rate = 44100;
12668c2ecf20Sopenharmony_ci
12678c2ecf20Sopenharmony_ci	/* search for a already created SRC SCB with the same sample rate */
12688c2ecf20Sopenharmony_ci	for (i = 0; i < DSP_MAX_PCM_CHANNELS &&
12698c2ecf20Sopenharmony_ci		     (pcm_index == -1 || src_scb == NULL); ++i) {
12708c2ecf20Sopenharmony_ci
12718c2ecf20Sopenharmony_ci		/* virtual channel reserved
12728c2ecf20Sopenharmony_ci		   for capture */
12738c2ecf20Sopenharmony_ci		if (i == CS46XX_DSP_CAPTURE_CHANNEL) continue;
12748c2ecf20Sopenharmony_ci
12758c2ecf20Sopenharmony_ci		if (ins->pcm_channels[i].active) {
12768c2ecf20Sopenharmony_ci			if (!src_scb &&
12778c2ecf20Sopenharmony_ci			    ins->pcm_channels[i].sample_rate == sample_rate &&
12788c2ecf20Sopenharmony_ci			    ins->pcm_channels[i].mixer_scb == mixer_scb) {
12798c2ecf20Sopenharmony_ci				src_scb = ins->pcm_channels[i].src_scb;
12808c2ecf20Sopenharmony_ci				ins->pcm_channels[i].src_scb->ref_count ++;
12818c2ecf20Sopenharmony_ci				src_index = ins->pcm_channels[i].src_slot;
12828c2ecf20Sopenharmony_ci			}
12838c2ecf20Sopenharmony_ci		} else if (pcm_index == -1) {
12848c2ecf20Sopenharmony_ci			pcm_index = i;
12858c2ecf20Sopenharmony_ci		}
12868c2ecf20Sopenharmony_ci	}
12878c2ecf20Sopenharmony_ci
12888c2ecf20Sopenharmony_ci	if (pcm_index == -1) {
12898c2ecf20Sopenharmony_ci		dev_err(chip->card->dev, "dsp_spos: no free PCM channel\n");
12908c2ecf20Sopenharmony_ci		return NULL;
12918c2ecf20Sopenharmony_ci	}
12928c2ecf20Sopenharmony_ci
12938c2ecf20Sopenharmony_ci	if (src_scb == NULL) {
12948c2ecf20Sopenharmony_ci		if (ins->nsrc_scb >= DSP_MAX_SRC_NR) {
12958c2ecf20Sopenharmony_ci			dev_err(chip->card->dev,
12968c2ecf20Sopenharmony_ci				"dsp_spos: too many SRC instances\n!");
12978c2ecf20Sopenharmony_ci			return NULL;
12988c2ecf20Sopenharmony_ci		}
12998c2ecf20Sopenharmony_ci
13008c2ecf20Sopenharmony_ci		/* find a free slot */
13018c2ecf20Sopenharmony_ci		for (i = 0; i < DSP_MAX_SRC_NR; ++i) {
13028c2ecf20Sopenharmony_ci			if (ins->src_scb_slots[i] == 0) {
13038c2ecf20Sopenharmony_ci				src_index = i;
13048c2ecf20Sopenharmony_ci				ins->src_scb_slots[i] = 1;
13058c2ecf20Sopenharmony_ci				break;
13068c2ecf20Sopenharmony_ci			}
13078c2ecf20Sopenharmony_ci		}
13088c2ecf20Sopenharmony_ci		if (snd_BUG_ON(src_index == -1))
13098c2ecf20Sopenharmony_ci			return NULL;
13108c2ecf20Sopenharmony_ci
13118c2ecf20Sopenharmony_ci		/* we need to create a new SRC SCB */
13128c2ecf20Sopenharmony_ci		if (mixer_scb->sub_list_ptr == ins->the_null_scb) {
13138c2ecf20Sopenharmony_ci			src_parent_scb = mixer_scb;
13148c2ecf20Sopenharmony_ci			insert_point = SCB_ON_PARENT_SUBLIST_SCB;
13158c2ecf20Sopenharmony_ci		} else {
13168c2ecf20Sopenharmony_ci			src_parent_scb = find_next_free_scb(chip,mixer_scb->sub_list_ptr);
13178c2ecf20Sopenharmony_ci			insert_point = SCB_ON_PARENT_NEXT_SCB;
13188c2ecf20Sopenharmony_ci		}
13198c2ecf20Sopenharmony_ci
13208c2ecf20Sopenharmony_ci		snprintf (scb_name,DSP_MAX_SCB_NAME,"SrcTask_SCB%d",src_index);
13218c2ecf20Sopenharmony_ci
13228c2ecf20Sopenharmony_ci		dev_dbg(chip->card->dev,
13238c2ecf20Sopenharmony_ci			"dsp_spos: creating SRC \"%s\"\n", scb_name);
13248c2ecf20Sopenharmony_ci		src_scb = cs46xx_dsp_create_src_task_scb(chip,scb_name,
13258c2ecf20Sopenharmony_ci							 sample_rate,
13268c2ecf20Sopenharmony_ci							 src_output_buffer_addr[src_index],
13278c2ecf20Sopenharmony_ci							 src_delay_buffer_addr[src_index],
13288c2ecf20Sopenharmony_ci							 /* 0x400 - 0x600 source SCBs */
13298c2ecf20Sopenharmony_ci							 0x400 + (src_index * 0x10) ,
13308c2ecf20Sopenharmony_ci							 src_parent_scb,
13318c2ecf20Sopenharmony_ci							 insert_point,
13328c2ecf20Sopenharmony_ci							 pass_through);
13338c2ecf20Sopenharmony_ci
13348c2ecf20Sopenharmony_ci		if (!src_scb) {
13358c2ecf20Sopenharmony_ci			dev_err(chip->card->dev,
13368c2ecf20Sopenharmony_ci				"dsp_spos: failed to create SRCtaskSCB\n");
13378c2ecf20Sopenharmony_ci			return NULL;
13388c2ecf20Sopenharmony_ci		}
13398c2ecf20Sopenharmony_ci
13408c2ecf20Sopenharmony_ci		/* cs46xx_dsp_set_src_sample_rate(chip,src_scb,sample_rate); */
13418c2ecf20Sopenharmony_ci
13428c2ecf20Sopenharmony_ci		ins->nsrc_scb ++;
13438c2ecf20Sopenharmony_ci	}
13448c2ecf20Sopenharmony_ci
13458c2ecf20Sopenharmony_ci
13468c2ecf20Sopenharmony_ci	snprintf (scb_name,DSP_MAX_SCB_NAME,"PCMReader_SCB%d",pcm_index);
13478c2ecf20Sopenharmony_ci
13488c2ecf20Sopenharmony_ci	dev_dbg(chip->card->dev, "dsp_spos: creating PCM \"%s\" (%d)\n",
13498c2ecf20Sopenharmony_ci		scb_name, pcm_channel_id);
13508c2ecf20Sopenharmony_ci
13518c2ecf20Sopenharmony_ci	pcm_scb = cs46xx_dsp_create_pcm_reader_scb(chip,scb_name,
13528c2ecf20Sopenharmony_ci						   pcm_reader_buffer_addr[pcm_index],
13538c2ecf20Sopenharmony_ci						   /* 0x200 - 400 PCMreader SCBs */
13548c2ecf20Sopenharmony_ci						   (pcm_index * 0x10) + 0x200,
13558c2ecf20Sopenharmony_ci						   pcm_index,    /* virtual channel 0-31 */
13568c2ecf20Sopenharmony_ci						   hw_dma_addr,  /* pcm hw addr */
13578c2ecf20Sopenharmony_ci                           NULL,         /* parent SCB ptr */
13588c2ecf20Sopenharmony_ci                           0             /* insert point */
13598c2ecf20Sopenharmony_ci                           );
13608c2ecf20Sopenharmony_ci
13618c2ecf20Sopenharmony_ci	if (!pcm_scb) {
13628c2ecf20Sopenharmony_ci		dev_err(chip->card->dev,
13638c2ecf20Sopenharmony_ci			"dsp_spos: failed to create PCMreaderSCB\n");
13648c2ecf20Sopenharmony_ci		return NULL;
13658c2ecf20Sopenharmony_ci	}
13668c2ecf20Sopenharmony_ci
13678c2ecf20Sopenharmony_ci	spin_lock_irqsave(&chip->reg_lock, flags);
13688c2ecf20Sopenharmony_ci	ins->pcm_channels[pcm_index].sample_rate = sample_rate;
13698c2ecf20Sopenharmony_ci	ins->pcm_channels[pcm_index].pcm_reader_scb = pcm_scb;
13708c2ecf20Sopenharmony_ci	ins->pcm_channels[pcm_index].src_scb = src_scb;
13718c2ecf20Sopenharmony_ci	ins->pcm_channels[pcm_index].unlinked = 1;
13728c2ecf20Sopenharmony_ci	ins->pcm_channels[pcm_index].private_data = private_data;
13738c2ecf20Sopenharmony_ci	ins->pcm_channels[pcm_index].src_slot = src_index;
13748c2ecf20Sopenharmony_ci	ins->pcm_channels[pcm_index].active = 1;
13758c2ecf20Sopenharmony_ci	ins->pcm_channels[pcm_index].pcm_slot = pcm_index;
13768c2ecf20Sopenharmony_ci	ins->pcm_channels[pcm_index].mixer_scb = mixer_scb;
13778c2ecf20Sopenharmony_ci	ins->npcm_channels ++;
13788c2ecf20Sopenharmony_ci	spin_unlock_irqrestore(&chip->reg_lock, flags);
13798c2ecf20Sopenharmony_ci
13808c2ecf20Sopenharmony_ci	return (ins->pcm_channels + pcm_index);
13818c2ecf20Sopenharmony_ci}
13828c2ecf20Sopenharmony_ci
13838c2ecf20Sopenharmony_ciint cs46xx_dsp_pcm_channel_set_period (struct snd_cs46xx * chip,
13848c2ecf20Sopenharmony_ci				       struct dsp_pcm_channel_descriptor * pcm_channel,
13858c2ecf20Sopenharmony_ci				       int period_size)
13868c2ecf20Sopenharmony_ci{
13878c2ecf20Sopenharmony_ci	u32 temp = snd_cs46xx_peek (chip,pcm_channel->pcm_reader_scb->address << 2);
13888c2ecf20Sopenharmony_ci	temp &= ~DMA_RQ_C1_SOURCE_SIZE_MASK;
13898c2ecf20Sopenharmony_ci
13908c2ecf20Sopenharmony_ci	switch (period_size) {
13918c2ecf20Sopenharmony_ci	case 2048:
13928c2ecf20Sopenharmony_ci		temp |= DMA_RQ_C1_SOURCE_MOD1024;
13938c2ecf20Sopenharmony_ci		break;
13948c2ecf20Sopenharmony_ci	case 1024:
13958c2ecf20Sopenharmony_ci		temp |= DMA_RQ_C1_SOURCE_MOD512;
13968c2ecf20Sopenharmony_ci		break;
13978c2ecf20Sopenharmony_ci	case 512:
13988c2ecf20Sopenharmony_ci		temp |= DMA_RQ_C1_SOURCE_MOD256;
13998c2ecf20Sopenharmony_ci		break;
14008c2ecf20Sopenharmony_ci	case 256:
14018c2ecf20Sopenharmony_ci		temp |= DMA_RQ_C1_SOURCE_MOD128;
14028c2ecf20Sopenharmony_ci		break;
14038c2ecf20Sopenharmony_ci	case 128:
14048c2ecf20Sopenharmony_ci		temp |= DMA_RQ_C1_SOURCE_MOD64;
14058c2ecf20Sopenharmony_ci		break;
14068c2ecf20Sopenharmony_ci	case 64:
14078c2ecf20Sopenharmony_ci		temp |= DMA_RQ_C1_SOURCE_MOD32;
14088c2ecf20Sopenharmony_ci		break;
14098c2ecf20Sopenharmony_ci	case 32:
14108c2ecf20Sopenharmony_ci		temp |= DMA_RQ_C1_SOURCE_MOD16;
14118c2ecf20Sopenharmony_ci		break;
14128c2ecf20Sopenharmony_ci	default:
14138c2ecf20Sopenharmony_ci		dev_dbg(chip->card->dev,
14148c2ecf20Sopenharmony_ci			"period size (%d) not supported by HW\n", period_size);
14158c2ecf20Sopenharmony_ci		return -EINVAL;
14168c2ecf20Sopenharmony_ci	}
14178c2ecf20Sopenharmony_ci
14188c2ecf20Sopenharmony_ci	snd_cs46xx_poke (chip,pcm_channel->pcm_reader_scb->address << 2,temp);
14198c2ecf20Sopenharmony_ci
14208c2ecf20Sopenharmony_ci	return 0;
14218c2ecf20Sopenharmony_ci}
14228c2ecf20Sopenharmony_ci
14238c2ecf20Sopenharmony_ciint cs46xx_dsp_pcm_ostream_set_period (struct snd_cs46xx * chip,
14248c2ecf20Sopenharmony_ci				       int period_size)
14258c2ecf20Sopenharmony_ci{
14268c2ecf20Sopenharmony_ci	u32 temp = snd_cs46xx_peek (chip,WRITEBACK_SCB_ADDR << 2);
14278c2ecf20Sopenharmony_ci	temp &= ~DMA_RQ_C1_DEST_SIZE_MASK;
14288c2ecf20Sopenharmony_ci
14298c2ecf20Sopenharmony_ci	switch (period_size) {
14308c2ecf20Sopenharmony_ci	case 2048:
14318c2ecf20Sopenharmony_ci		temp |= DMA_RQ_C1_DEST_MOD1024;
14328c2ecf20Sopenharmony_ci		break;
14338c2ecf20Sopenharmony_ci	case 1024:
14348c2ecf20Sopenharmony_ci		temp |= DMA_RQ_C1_DEST_MOD512;
14358c2ecf20Sopenharmony_ci		break;
14368c2ecf20Sopenharmony_ci	case 512:
14378c2ecf20Sopenharmony_ci		temp |= DMA_RQ_C1_DEST_MOD256;
14388c2ecf20Sopenharmony_ci		break;
14398c2ecf20Sopenharmony_ci	case 256:
14408c2ecf20Sopenharmony_ci		temp |= DMA_RQ_C1_DEST_MOD128;
14418c2ecf20Sopenharmony_ci		break;
14428c2ecf20Sopenharmony_ci	case 128:
14438c2ecf20Sopenharmony_ci		temp |= DMA_RQ_C1_DEST_MOD64;
14448c2ecf20Sopenharmony_ci		break;
14458c2ecf20Sopenharmony_ci	case 64:
14468c2ecf20Sopenharmony_ci		temp |= DMA_RQ_C1_DEST_MOD32;
14478c2ecf20Sopenharmony_ci		break;
14488c2ecf20Sopenharmony_ci	case 32:
14498c2ecf20Sopenharmony_ci		temp |= DMA_RQ_C1_DEST_MOD16;
14508c2ecf20Sopenharmony_ci		break;
14518c2ecf20Sopenharmony_ci	default:
14528c2ecf20Sopenharmony_ci		dev_dbg(chip->card->dev,
14538c2ecf20Sopenharmony_ci			"period size (%d) not supported by HW\n", period_size);
14548c2ecf20Sopenharmony_ci		return -EINVAL;
14558c2ecf20Sopenharmony_ci	}
14568c2ecf20Sopenharmony_ci
14578c2ecf20Sopenharmony_ci	snd_cs46xx_poke (chip,WRITEBACK_SCB_ADDR << 2,temp);
14588c2ecf20Sopenharmony_ci
14598c2ecf20Sopenharmony_ci	return 0;
14608c2ecf20Sopenharmony_ci}
14618c2ecf20Sopenharmony_ci
14628c2ecf20Sopenharmony_civoid cs46xx_dsp_destroy_pcm_channel (struct snd_cs46xx * chip,
14638c2ecf20Sopenharmony_ci				     struct dsp_pcm_channel_descriptor * pcm_channel)
14648c2ecf20Sopenharmony_ci{
14658c2ecf20Sopenharmony_ci	struct dsp_spos_instance * ins = chip->dsp_spos_instance;
14668c2ecf20Sopenharmony_ci	unsigned long flags;
14678c2ecf20Sopenharmony_ci
14688c2ecf20Sopenharmony_ci	if (snd_BUG_ON(!pcm_channel->active ||
14698c2ecf20Sopenharmony_ci		       ins->npcm_channels <= 0 ||
14708c2ecf20Sopenharmony_ci		       pcm_channel->src_scb->ref_count <= 0))
14718c2ecf20Sopenharmony_ci		return;
14728c2ecf20Sopenharmony_ci
14738c2ecf20Sopenharmony_ci	spin_lock_irqsave(&chip->reg_lock, flags);
14748c2ecf20Sopenharmony_ci	pcm_channel->unlinked = 1;
14758c2ecf20Sopenharmony_ci	pcm_channel->active = 0;
14768c2ecf20Sopenharmony_ci	pcm_channel->private_data = NULL;
14778c2ecf20Sopenharmony_ci	pcm_channel->src_scb->ref_count --;
14788c2ecf20Sopenharmony_ci	ins->npcm_channels --;
14798c2ecf20Sopenharmony_ci	spin_unlock_irqrestore(&chip->reg_lock, flags);
14808c2ecf20Sopenharmony_ci
14818c2ecf20Sopenharmony_ci	cs46xx_dsp_remove_scb(chip,pcm_channel->pcm_reader_scb);
14828c2ecf20Sopenharmony_ci
14838c2ecf20Sopenharmony_ci	if (!pcm_channel->src_scb->ref_count) {
14848c2ecf20Sopenharmony_ci		cs46xx_dsp_remove_scb(chip,pcm_channel->src_scb);
14858c2ecf20Sopenharmony_ci
14868c2ecf20Sopenharmony_ci		if (snd_BUG_ON(pcm_channel->src_slot < 0 ||
14878c2ecf20Sopenharmony_ci			       pcm_channel->src_slot >= DSP_MAX_SRC_NR))
14888c2ecf20Sopenharmony_ci			return;
14898c2ecf20Sopenharmony_ci
14908c2ecf20Sopenharmony_ci		ins->src_scb_slots[pcm_channel->src_slot] = 0;
14918c2ecf20Sopenharmony_ci		ins->nsrc_scb --;
14928c2ecf20Sopenharmony_ci	}
14938c2ecf20Sopenharmony_ci}
14948c2ecf20Sopenharmony_ci
14958c2ecf20Sopenharmony_ciint cs46xx_dsp_pcm_unlink (struct snd_cs46xx * chip,
14968c2ecf20Sopenharmony_ci			   struct dsp_pcm_channel_descriptor * pcm_channel)
14978c2ecf20Sopenharmony_ci{
14988c2ecf20Sopenharmony_ci	unsigned long flags;
14998c2ecf20Sopenharmony_ci
15008c2ecf20Sopenharmony_ci	if (snd_BUG_ON(!pcm_channel->active ||
15018c2ecf20Sopenharmony_ci		       chip->dsp_spos_instance->npcm_channels <= 0))
15028c2ecf20Sopenharmony_ci		return -EIO;
15038c2ecf20Sopenharmony_ci
15048c2ecf20Sopenharmony_ci	spin_lock_irqsave(&chip->reg_lock, flags);
15058c2ecf20Sopenharmony_ci	if (pcm_channel->unlinked) {
15068c2ecf20Sopenharmony_ci		spin_unlock_irqrestore(&chip->reg_lock, flags);
15078c2ecf20Sopenharmony_ci		return -EIO;
15088c2ecf20Sopenharmony_ci	}
15098c2ecf20Sopenharmony_ci
15108c2ecf20Sopenharmony_ci	pcm_channel->unlinked = 1;
15118c2ecf20Sopenharmony_ci
15128c2ecf20Sopenharmony_ci	_dsp_unlink_scb (chip,pcm_channel->pcm_reader_scb);
15138c2ecf20Sopenharmony_ci	spin_unlock_irqrestore(&chip->reg_lock, flags);
15148c2ecf20Sopenharmony_ci
15158c2ecf20Sopenharmony_ci	return 0;
15168c2ecf20Sopenharmony_ci}
15178c2ecf20Sopenharmony_ci
15188c2ecf20Sopenharmony_ciint cs46xx_dsp_pcm_link (struct snd_cs46xx * chip,
15198c2ecf20Sopenharmony_ci			 struct dsp_pcm_channel_descriptor * pcm_channel)
15208c2ecf20Sopenharmony_ci{
15218c2ecf20Sopenharmony_ci	struct dsp_spos_instance * ins = chip->dsp_spos_instance;
15228c2ecf20Sopenharmony_ci	struct dsp_scb_descriptor * parent_scb;
15238c2ecf20Sopenharmony_ci	struct dsp_scb_descriptor * src_scb = pcm_channel->src_scb;
15248c2ecf20Sopenharmony_ci	unsigned long flags;
15258c2ecf20Sopenharmony_ci
15268c2ecf20Sopenharmony_ci	spin_lock_irqsave(&chip->reg_lock, flags);
15278c2ecf20Sopenharmony_ci
15288c2ecf20Sopenharmony_ci	if (pcm_channel->unlinked == 0) {
15298c2ecf20Sopenharmony_ci		spin_unlock_irqrestore(&chip->reg_lock, flags);
15308c2ecf20Sopenharmony_ci		return -EIO;
15318c2ecf20Sopenharmony_ci	}
15328c2ecf20Sopenharmony_ci
15338c2ecf20Sopenharmony_ci	parent_scb = src_scb;
15348c2ecf20Sopenharmony_ci
15358c2ecf20Sopenharmony_ci	if (src_scb->sub_list_ptr != ins->the_null_scb) {
15368c2ecf20Sopenharmony_ci		src_scb->sub_list_ptr->parent_scb_ptr = pcm_channel->pcm_reader_scb;
15378c2ecf20Sopenharmony_ci		pcm_channel->pcm_reader_scb->next_scb_ptr = src_scb->sub_list_ptr;
15388c2ecf20Sopenharmony_ci	}
15398c2ecf20Sopenharmony_ci
15408c2ecf20Sopenharmony_ci	src_scb->sub_list_ptr = pcm_channel->pcm_reader_scb;
15418c2ecf20Sopenharmony_ci
15428c2ecf20Sopenharmony_ci	snd_BUG_ON(pcm_channel->pcm_reader_scb->parent_scb_ptr);
15438c2ecf20Sopenharmony_ci	pcm_channel->pcm_reader_scb->parent_scb_ptr = parent_scb;
15448c2ecf20Sopenharmony_ci
15458c2ecf20Sopenharmony_ci	/* update SCB entry in DSP RAM */
15468c2ecf20Sopenharmony_ci	cs46xx_dsp_spos_update_scb(chip,pcm_channel->pcm_reader_scb);
15478c2ecf20Sopenharmony_ci
15488c2ecf20Sopenharmony_ci	/* update parent SCB entry */
15498c2ecf20Sopenharmony_ci	cs46xx_dsp_spos_update_scb(chip,parent_scb);
15508c2ecf20Sopenharmony_ci
15518c2ecf20Sopenharmony_ci	pcm_channel->unlinked = 0;
15528c2ecf20Sopenharmony_ci	spin_unlock_irqrestore(&chip->reg_lock, flags);
15538c2ecf20Sopenharmony_ci	return 0;
15548c2ecf20Sopenharmony_ci}
15558c2ecf20Sopenharmony_ci
15568c2ecf20Sopenharmony_cistruct dsp_scb_descriptor *
15578c2ecf20Sopenharmony_cics46xx_add_record_source (struct snd_cs46xx *chip, struct dsp_scb_descriptor * source,
15588c2ecf20Sopenharmony_ci			  u16 addr, char * scb_name)
15598c2ecf20Sopenharmony_ci{
15608c2ecf20Sopenharmony_ci  	struct dsp_spos_instance * ins = chip->dsp_spos_instance;
15618c2ecf20Sopenharmony_ci	struct dsp_scb_descriptor * parent;
15628c2ecf20Sopenharmony_ci	struct dsp_scb_descriptor * pcm_input;
15638c2ecf20Sopenharmony_ci	int insert_point;
15648c2ecf20Sopenharmony_ci
15658c2ecf20Sopenharmony_ci	if (snd_BUG_ON(!ins->record_mixer_scb))
15668c2ecf20Sopenharmony_ci		return NULL;
15678c2ecf20Sopenharmony_ci
15688c2ecf20Sopenharmony_ci	if (ins->record_mixer_scb->sub_list_ptr != ins->the_null_scb) {
15698c2ecf20Sopenharmony_ci		parent = find_next_free_scb (chip,ins->record_mixer_scb->sub_list_ptr);
15708c2ecf20Sopenharmony_ci		insert_point = SCB_ON_PARENT_NEXT_SCB;
15718c2ecf20Sopenharmony_ci	} else {
15728c2ecf20Sopenharmony_ci		parent = ins->record_mixer_scb;
15738c2ecf20Sopenharmony_ci		insert_point = SCB_ON_PARENT_SUBLIST_SCB;
15748c2ecf20Sopenharmony_ci	}
15758c2ecf20Sopenharmony_ci
15768c2ecf20Sopenharmony_ci	pcm_input = cs46xx_dsp_create_pcm_serial_input_scb(chip,scb_name,addr,
15778c2ecf20Sopenharmony_ci							   source, parent,
15788c2ecf20Sopenharmony_ci							   insert_point);
15798c2ecf20Sopenharmony_ci
15808c2ecf20Sopenharmony_ci	return pcm_input;
15818c2ecf20Sopenharmony_ci}
15828c2ecf20Sopenharmony_ci
15838c2ecf20Sopenharmony_ciint cs46xx_src_unlink(struct snd_cs46xx *chip, struct dsp_scb_descriptor * src)
15848c2ecf20Sopenharmony_ci{
15858c2ecf20Sopenharmony_ci	unsigned long flags;
15868c2ecf20Sopenharmony_ci
15878c2ecf20Sopenharmony_ci	if (snd_BUG_ON(!src->parent_scb_ptr))
15888c2ecf20Sopenharmony_ci		return -EINVAL;
15898c2ecf20Sopenharmony_ci
15908c2ecf20Sopenharmony_ci	/* mute SCB */
15918c2ecf20Sopenharmony_ci	cs46xx_dsp_scb_set_volume (chip,src,0,0);
15928c2ecf20Sopenharmony_ci
15938c2ecf20Sopenharmony_ci	spin_lock_irqsave(&chip->reg_lock, flags);
15948c2ecf20Sopenharmony_ci	_dsp_unlink_scb (chip,src);
15958c2ecf20Sopenharmony_ci	spin_unlock_irqrestore(&chip->reg_lock, flags);
15968c2ecf20Sopenharmony_ci
15978c2ecf20Sopenharmony_ci	return 0;
15988c2ecf20Sopenharmony_ci}
15998c2ecf20Sopenharmony_ci
16008c2ecf20Sopenharmony_ciint cs46xx_src_link(struct snd_cs46xx *chip, struct dsp_scb_descriptor * src)
16018c2ecf20Sopenharmony_ci{
16028c2ecf20Sopenharmony_ci	struct dsp_spos_instance * ins = chip->dsp_spos_instance;
16038c2ecf20Sopenharmony_ci	struct dsp_scb_descriptor * parent_scb;
16048c2ecf20Sopenharmony_ci
16058c2ecf20Sopenharmony_ci	if (snd_BUG_ON(src->parent_scb_ptr))
16068c2ecf20Sopenharmony_ci		return -EINVAL;
16078c2ecf20Sopenharmony_ci	if (snd_BUG_ON(!ins->master_mix_scb))
16088c2ecf20Sopenharmony_ci		return -EINVAL;
16098c2ecf20Sopenharmony_ci
16108c2ecf20Sopenharmony_ci	if (ins->master_mix_scb->sub_list_ptr != ins->the_null_scb) {
16118c2ecf20Sopenharmony_ci		parent_scb = find_next_free_scb (chip,ins->master_mix_scb->sub_list_ptr);
16128c2ecf20Sopenharmony_ci		parent_scb->next_scb_ptr = src;
16138c2ecf20Sopenharmony_ci	} else {
16148c2ecf20Sopenharmony_ci		parent_scb = ins->master_mix_scb;
16158c2ecf20Sopenharmony_ci		parent_scb->sub_list_ptr = src;
16168c2ecf20Sopenharmony_ci	}
16178c2ecf20Sopenharmony_ci
16188c2ecf20Sopenharmony_ci	src->parent_scb_ptr = parent_scb;
16198c2ecf20Sopenharmony_ci
16208c2ecf20Sopenharmony_ci	/* update entry in DSP RAM */
16218c2ecf20Sopenharmony_ci	cs46xx_dsp_spos_update_scb(chip,parent_scb);
16228c2ecf20Sopenharmony_ci
16238c2ecf20Sopenharmony_ci	return 0;
16248c2ecf20Sopenharmony_ci}
16258c2ecf20Sopenharmony_ci
16268c2ecf20Sopenharmony_ciint cs46xx_dsp_enable_spdif_out (struct snd_cs46xx *chip)
16278c2ecf20Sopenharmony_ci{
16288c2ecf20Sopenharmony_ci	struct dsp_spos_instance * ins = chip->dsp_spos_instance;
16298c2ecf20Sopenharmony_ci
16308c2ecf20Sopenharmony_ci	if ( ! (ins->spdif_status_out & DSP_SPDIF_STATUS_HW_ENABLED) ) {
16318c2ecf20Sopenharmony_ci		cs46xx_dsp_enable_spdif_hw (chip);
16328c2ecf20Sopenharmony_ci	}
16338c2ecf20Sopenharmony_ci
16348c2ecf20Sopenharmony_ci	/* dont touch anything if SPDIF is open */
16358c2ecf20Sopenharmony_ci	if ( ins->spdif_status_out & DSP_SPDIF_STATUS_PLAYBACK_OPEN) {
16368c2ecf20Sopenharmony_ci		/* when cs46xx_iec958_post_close(...) is called it
16378c2ecf20Sopenharmony_ci		   will call this function if necessary depending on
16388c2ecf20Sopenharmony_ci		   this bit */
16398c2ecf20Sopenharmony_ci		ins->spdif_status_out |= DSP_SPDIF_STATUS_OUTPUT_ENABLED;
16408c2ecf20Sopenharmony_ci
16418c2ecf20Sopenharmony_ci		return -EBUSY;
16428c2ecf20Sopenharmony_ci	}
16438c2ecf20Sopenharmony_ci
16448c2ecf20Sopenharmony_ci	if (snd_BUG_ON(ins->asynch_tx_scb))
16458c2ecf20Sopenharmony_ci		return -EINVAL;
16468c2ecf20Sopenharmony_ci	if (snd_BUG_ON(ins->master_mix_scb->next_scb_ptr !=
16478c2ecf20Sopenharmony_ci		       ins->the_null_scb))
16488c2ecf20Sopenharmony_ci		return -EINVAL;
16498c2ecf20Sopenharmony_ci
16508c2ecf20Sopenharmony_ci	/* reset output snooper sample buffer pointer */
16518c2ecf20Sopenharmony_ci	snd_cs46xx_poke (chip, (ins->ref_snoop_scb->address + 2) << 2,
16528c2ecf20Sopenharmony_ci			 (OUTPUT_SNOOP_BUFFER + 0x10) << 0x10 );
16538c2ecf20Sopenharmony_ci
16548c2ecf20Sopenharmony_ci	/* The asynch. transfer task */
16558c2ecf20Sopenharmony_ci	ins->asynch_tx_scb = cs46xx_dsp_create_asynch_fg_tx_scb(chip,"AsynchFGTxSCB",ASYNCTX_SCB_ADDR,
16568c2ecf20Sopenharmony_ci								SPDIFO_SCB_INST,
16578c2ecf20Sopenharmony_ci								SPDIFO_IP_OUTPUT_BUFFER1,
16588c2ecf20Sopenharmony_ci								ins->master_mix_scb,
16598c2ecf20Sopenharmony_ci								SCB_ON_PARENT_NEXT_SCB);
16608c2ecf20Sopenharmony_ci	if (!ins->asynch_tx_scb) return -ENOMEM;
16618c2ecf20Sopenharmony_ci
16628c2ecf20Sopenharmony_ci	ins->spdif_pcm_input_scb = cs46xx_dsp_create_pcm_serial_input_scb(chip,"PCMSerialInput_II",
16638c2ecf20Sopenharmony_ci									  PCMSERIALINII_SCB_ADDR,
16648c2ecf20Sopenharmony_ci									  ins->ref_snoop_scb,
16658c2ecf20Sopenharmony_ci									  ins->asynch_tx_scb,
16668c2ecf20Sopenharmony_ci									  SCB_ON_PARENT_SUBLIST_SCB);
16678c2ecf20Sopenharmony_ci
16688c2ecf20Sopenharmony_ci
16698c2ecf20Sopenharmony_ci	if (!ins->spdif_pcm_input_scb) return -ENOMEM;
16708c2ecf20Sopenharmony_ci
16718c2ecf20Sopenharmony_ci	/* monitor state */
16728c2ecf20Sopenharmony_ci	ins->spdif_status_out |= DSP_SPDIF_STATUS_OUTPUT_ENABLED;
16738c2ecf20Sopenharmony_ci
16748c2ecf20Sopenharmony_ci	return 0;
16758c2ecf20Sopenharmony_ci}
16768c2ecf20Sopenharmony_ci
16778c2ecf20Sopenharmony_ciint  cs46xx_dsp_disable_spdif_out (struct snd_cs46xx *chip)
16788c2ecf20Sopenharmony_ci{
16798c2ecf20Sopenharmony_ci	struct dsp_spos_instance * ins = chip->dsp_spos_instance;
16808c2ecf20Sopenharmony_ci
16818c2ecf20Sopenharmony_ci	/* dont touch anything if SPDIF is open */
16828c2ecf20Sopenharmony_ci	if ( ins->spdif_status_out & DSP_SPDIF_STATUS_PLAYBACK_OPEN) {
16838c2ecf20Sopenharmony_ci		ins->spdif_status_out &= ~DSP_SPDIF_STATUS_OUTPUT_ENABLED;
16848c2ecf20Sopenharmony_ci		return -EBUSY;
16858c2ecf20Sopenharmony_ci	}
16868c2ecf20Sopenharmony_ci
16878c2ecf20Sopenharmony_ci	/* check integrety */
16888c2ecf20Sopenharmony_ci	if (snd_BUG_ON(!ins->asynch_tx_scb))
16898c2ecf20Sopenharmony_ci		return -EINVAL;
16908c2ecf20Sopenharmony_ci	if (snd_BUG_ON(!ins->spdif_pcm_input_scb))
16918c2ecf20Sopenharmony_ci		return -EINVAL;
16928c2ecf20Sopenharmony_ci	if (snd_BUG_ON(ins->master_mix_scb->next_scb_ptr != ins->asynch_tx_scb))
16938c2ecf20Sopenharmony_ci		return -EINVAL;
16948c2ecf20Sopenharmony_ci	if (snd_BUG_ON(ins->asynch_tx_scb->parent_scb_ptr !=
16958c2ecf20Sopenharmony_ci		       ins->master_mix_scb))
16968c2ecf20Sopenharmony_ci		return -EINVAL;
16978c2ecf20Sopenharmony_ci
16988c2ecf20Sopenharmony_ci	cs46xx_dsp_remove_scb (chip,ins->spdif_pcm_input_scb);
16998c2ecf20Sopenharmony_ci	cs46xx_dsp_remove_scb (chip,ins->asynch_tx_scb);
17008c2ecf20Sopenharmony_ci
17018c2ecf20Sopenharmony_ci	ins->spdif_pcm_input_scb = NULL;
17028c2ecf20Sopenharmony_ci	ins->asynch_tx_scb = NULL;
17038c2ecf20Sopenharmony_ci
17048c2ecf20Sopenharmony_ci	/* clear buffer to prevent any undesired noise */
17058c2ecf20Sopenharmony_ci	_dsp_clear_sample_buffer(chip,SPDIFO_IP_OUTPUT_BUFFER1,256);
17068c2ecf20Sopenharmony_ci
17078c2ecf20Sopenharmony_ci	/* monitor state */
17088c2ecf20Sopenharmony_ci	ins->spdif_status_out  &= ~DSP_SPDIF_STATUS_OUTPUT_ENABLED;
17098c2ecf20Sopenharmony_ci
17108c2ecf20Sopenharmony_ci
17118c2ecf20Sopenharmony_ci	return 0;
17128c2ecf20Sopenharmony_ci}
17138c2ecf20Sopenharmony_ci
17148c2ecf20Sopenharmony_ciint cs46xx_iec958_pre_open (struct snd_cs46xx *chip)
17158c2ecf20Sopenharmony_ci{
17168c2ecf20Sopenharmony_ci	struct dsp_spos_instance * ins = chip->dsp_spos_instance;
17178c2ecf20Sopenharmony_ci
17188c2ecf20Sopenharmony_ci	if ( ins->spdif_status_out & DSP_SPDIF_STATUS_OUTPUT_ENABLED ) {
17198c2ecf20Sopenharmony_ci		/* remove AsynchFGTxSCB and PCMSerialInput_II */
17208c2ecf20Sopenharmony_ci		cs46xx_dsp_disable_spdif_out (chip);
17218c2ecf20Sopenharmony_ci
17228c2ecf20Sopenharmony_ci		/* save state */
17238c2ecf20Sopenharmony_ci		ins->spdif_status_out |= DSP_SPDIF_STATUS_OUTPUT_ENABLED;
17248c2ecf20Sopenharmony_ci	}
17258c2ecf20Sopenharmony_ci
17268c2ecf20Sopenharmony_ci	/* if not enabled already */
17278c2ecf20Sopenharmony_ci	if ( !(ins->spdif_status_out & DSP_SPDIF_STATUS_HW_ENABLED) ) {
17288c2ecf20Sopenharmony_ci		cs46xx_dsp_enable_spdif_hw (chip);
17298c2ecf20Sopenharmony_ci	}
17308c2ecf20Sopenharmony_ci
17318c2ecf20Sopenharmony_ci	/* Create the asynch. transfer task  for playback */
17328c2ecf20Sopenharmony_ci	ins->asynch_tx_scb = cs46xx_dsp_create_asynch_fg_tx_scb(chip,"AsynchFGTxSCB",ASYNCTX_SCB_ADDR,
17338c2ecf20Sopenharmony_ci								SPDIFO_SCB_INST,
17348c2ecf20Sopenharmony_ci								SPDIFO_IP_OUTPUT_BUFFER1,
17358c2ecf20Sopenharmony_ci								ins->master_mix_scb,
17368c2ecf20Sopenharmony_ci								SCB_ON_PARENT_NEXT_SCB);
17378c2ecf20Sopenharmony_ci
17388c2ecf20Sopenharmony_ci
17398c2ecf20Sopenharmony_ci	/* set spdif channel status value for streaming */
17408c2ecf20Sopenharmony_ci	cs46xx_poke_via_dsp (chip,SP_SPDOUT_CSUV, ins->spdif_csuv_stream);
17418c2ecf20Sopenharmony_ci
17428c2ecf20Sopenharmony_ci	ins->spdif_status_out  |= DSP_SPDIF_STATUS_PLAYBACK_OPEN;
17438c2ecf20Sopenharmony_ci
17448c2ecf20Sopenharmony_ci	return 0;
17458c2ecf20Sopenharmony_ci}
17468c2ecf20Sopenharmony_ci
17478c2ecf20Sopenharmony_ciint cs46xx_iec958_post_close (struct snd_cs46xx *chip)
17488c2ecf20Sopenharmony_ci{
17498c2ecf20Sopenharmony_ci	struct dsp_spos_instance * ins = chip->dsp_spos_instance;
17508c2ecf20Sopenharmony_ci
17518c2ecf20Sopenharmony_ci	if (snd_BUG_ON(!ins->asynch_tx_scb))
17528c2ecf20Sopenharmony_ci		return -EINVAL;
17538c2ecf20Sopenharmony_ci
17548c2ecf20Sopenharmony_ci	ins->spdif_status_out  &= ~DSP_SPDIF_STATUS_PLAYBACK_OPEN;
17558c2ecf20Sopenharmony_ci
17568c2ecf20Sopenharmony_ci	/* restore settings */
17578c2ecf20Sopenharmony_ci	cs46xx_poke_via_dsp (chip,SP_SPDOUT_CSUV, ins->spdif_csuv_default);
17588c2ecf20Sopenharmony_ci
17598c2ecf20Sopenharmony_ci	/* deallocate stuff */
17608c2ecf20Sopenharmony_ci	if (ins->spdif_pcm_input_scb != NULL) {
17618c2ecf20Sopenharmony_ci		cs46xx_dsp_remove_scb (chip,ins->spdif_pcm_input_scb);
17628c2ecf20Sopenharmony_ci		ins->spdif_pcm_input_scb = NULL;
17638c2ecf20Sopenharmony_ci	}
17648c2ecf20Sopenharmony_ci
17658c2ecf20Sopenharmony_ci	cs46xx_dsp_remove_scb (chip,ins->asynch_tx_scb);
17668c2ecf20Sopenharmony_ci	ins->asynch_tx_scb = NULL;
17678c2ecf20Sopenharmony_ci
17688c2ecf20Sopenharmony_ci	/* clear buffer to prevent any undesired noise */
17698c2ecf20Sopenharmony_ci	_dsp_clear_sample_buffer(chip,SPDIFO_IP_OUTPUT_BUFFER1,256);
17708c2ecf20Sopenharmony_ci
17718c2ecf20Sopenharmony_ci	/* restore state */
17728c2ecf20Sopenharmony_ci	if ( ins->spdif_status_out & DSP_SPDIF_STATUS_OUTPUT_ENABLED ) {
17738c2ecf20Sopenharmony_ci		cs46xx_dsp_enable_spdif_out (chip);
17748c2ecf20Sopenharmony_ci	}
17758c2ecf20Sopenharmony_ci
17768c2ecf20Sopenharmony_ci	return 0;
17778c2ecf20Sopenharmony_ci}
1778