pcm.c 31 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195
  1. // SPDX-License-Identifier: GPL-2.0-only
  2. //
  3. // Copyright(c) 2020 Intel Corporation. All rights reserved.
  4. //
  5. // Author: Cezary Rojewski <[email protected]>
  6. //
  7. #include <linux/pm_runtime.h>
  8. #include <sound/soc.h>
  9. #include <sound/pcm_params.h>
  10. #include <uapi/sound/tlv.h>
  11. #include "core.h"
  12. #include "messages.h"
  13. struct catpt_stream_template {
  14. enum catpt_path_id path_id;
  15. enum catpt_stream_type type;
  16. u32 persistent_size;
  17. u8 num_entries;
  18. struct catpt_module_entry entries[];
  19. };
  20. static struct catpt_stream_template system_pb = {
  21. .path_id = CATPT_PATH_SSP0_OUT,
  22. .type = CATPT_STRM_TYPE_SYSTEM,
  23. .num_entries = 1,
  24. .entries = {{ CATPT_MODID_PCM_SYSTEM, 0 }},
  25. };
  26. static struct catpt_stream_template system_cp = {
  27. .path_id = CATPT_PATH_SSP0_IN,
  28. .type = CATPT_STRM_TYPE_CAPTURE,
  29. .num_entries = 1,
  30. .entries = {{ CATPT_MODID_PCM_CAPTURE, 0 }},
  31. };
  32. static struct catpt_stream_template offload_pb = {
  33. .path_id = CATPT_PATH_SSP0_OUT,
  34. .type = CATPT_STRM_TYPE_RENDER,
  35. .num_entries = 1,
  36. .entries = {{ CATPT_MODID_PCM, 0 }},
  37. };
  38. static struct catpt_stream_template loopback_cp = {
  39. .path_id = CATPT_PATH_SSP0_OUT,
  40. .type = CATPT_STRM_TYPE_LOOPBACK,
  41. .num_entries = 1,
  42. .entries = {{ CATPT_MODID_PCM_REFERENCE, 0 }},
  43. };
  44. static struct catpt_stream_template bluetooth_pb = {
  45. .path_id = CATPT_PATH_SSP1_OUT,
  46. .type = CATPT_STRM_TYPE_BLUETOOTH_RENDER,
  47. .num_entries = 1,
  48. .entries = {{ CATPT_MODID_BLUETOOTH_RENDER, 0 }},
  49. };
  50. static struct catpt_stream_template bluetooth_cp = {
  51. .path_id = CATPT_PATH_SSP1_IN,
  52. .type = CATPT_STRM_TYPE_BLUETOOTH_CAPTURE,
  53. .num_entries = 1,
  54. .entries = {{ CATPT_MODID_BLUETOOTH_CAPTURE, 0 }},
  55. };
  56. static struct catpt_stream_template *catpt_topology[] = {
  57. [CATPT_STRM_TYPE_RENDER] = &offload_pb,
  58. [CATPT_STRM_TYPE_SYSTEM] = &system_pb,
  59. [CATPT_STRM_TYPE_CAPTURE] = &system_cp,
  60. [CATPT_STRM_TYPE_LOOPBACK] = &loopback_cp,
  61. [CATPT_STRM_TYPE_BLUETOOTH_RENDER] = &bluetooth_pb,
  62. [CATPT_STRM_TYPE_BLUETOOTH_CAPTURE] = &bluetooth_cp,
  63. };
  64. static struct catpt_stream_template *
  65. catpt_get_stream_template(struct snd_pcm_substream *substream)
  66. {
  67. struct snd_soc_pcm_runtime *rtm = asoc_substream_to_rtd(substream);
  68. struct snd_soc_dai *cpu_dai = asoc_rtd_to_cpu(rtm, 0);
  69. enum catpt_stream_type type;
  70. type = cpu_dai->driver->id;
  71. /* account for capture in bidirectional dais */
  72. switch (type) {
  73. case CATPT_STRM_TYPE_SYSTEM:
  74. if (substream->stream == SNDRV_PCM_STREAM_CAPTURE)
  75. type = CATPT_STRM_TYPE_CAPTURE;
  76. break;
  77. case CATPT_STRM_TYPE_BLUETOOTH_RENDER:
  78. if (substream->stream == SNDRV_PCM_STREAM_CAPTURE)
  79. type = CATPT_STRM_TYPE_BLUETOOTH_CAPTURE;
  80. break;
  81. default:
  82. break;
  83. }
  84. return catpt_topology[type];
  85. }
  86. struct catpt_stream_runtime *
  87. catpt_stream_find(struct catpt_dev *cdev, u8 stream_hw_id)
  88. {
  89. struct catpt_stream_runtime *pos, *result = NULL;
  90. spin_lock(&cdev->list_lock);
  91. list_for_each_entry(pos, &cdev->stream_list, node) {
  92. if (pos->info.stream_hw_id == stream_hw_id) {
  93. result = pos;
  94. break;
  95. }
  96. }
  97. spin_unlock(&cdev->list_lock);
  98. return result;
  99. }
  100. static u32 catpt_stream_read_position(struct catpt_dev *cdev,
  101. struct catpt_stream_runtime *stream)
  102. {
  103. u32 pos;
  104. memcpy_fromio(&pos, cdev->lpe_ba + stream->info.read_pos_regaddr,
  105. sizeof(pos));
  106. return pos;
  107. }
  108. static u32 catpt_stream_volume(struct catpt_dev *cdev,
  109. struct catpt_stream_runtime *stream, u32 channel)
  110. {
  111. u32 volume, offset;
  112. if (channel >= CATPT_CHANNELS_MAX)
  113. channel = 0;
  114. offset = stream->info.volume_regaddr[channel];
  115. memcpy_fromio(&volume, cdev->lpe_ba + offset, sizeof(volume));
  116. return volume;
  117. }
  118. static u32 catpt_mixer_volume(struct catpt_dev *cdev,
  119. struct catpt_mixer_stream_info *info, u32 channel)
  120. {
  121. u32 volume, offset;
  122. if (channel >= CATPT_CHANNELS_MAX)
  123. channel = 0;
  124. offset = info->volume_regaddr[channel];
  125. memcpy_fromio(&volume, cdev->lpe_ba + offset, sizeof(volume));
  126. return volume;
  127. }
  128. static void catpt_arrange_page_table(struct snd_pcm_substream *substream,
  129. struct snd_dma_buffer *pgtbl)
  130. {
  131. struct snd_pcm_runtime *rtm = substream->runtime;
  132. struct snd_dma_buffer *databuf = snd_pcm_get_dma_buf(substream);
  133. int i, pages;
  134. pages = snd_sgbuf_aligned_pages(rtm->dma_bytes);
  135. for (i = 0; i < pages; i++) {
  136. u32 pfn, offset;
  137. u32 *page_table;
  138. pfn = PFN_DOWN(snd_sgbuf_get_addr(databuf, i * PAGE_SIZE));
  139. /* incrementing by 2 on even and 3 on odd */
  140. offset = ((i << 2) + i) >> 1;
  141. page_table = (u32 *)(pgtbl->area + offset);
  142. if (i & 1)
  143. *page_table |= (pfn << 4);
  144. else
  145. *page_table |= pfn;
  146. }
  147. }
  148. static u32 catpt_get_channel_map(enum catpt_channel_config config)
  149. {
  150. switch (config) {
  151. case CATPT_CHANNEL_CONFIG_MONO:
  152. return GENMASK(31, 4) | CATPT_CHANNEL_CENTER;
  153. case CATPT_CHANNEL_CONFIG_STEREO:
  154. return GENMASK(31, 8) | CATPT_CHANNEL_LEFT
  155. | (CATPT_CHANNEL_RIGHT << 4);
  156. case CATPT_CHANNEL_CONFIG_2_POINT_1:
  157. return GENMASK(31, 12) | CATPT_CHANNEL_LEFT
  158. | (CATPT_CHANNEL_RIGHT << 4)
  159. | (CATPT_CHANNEL_LFE << 8);
  160. case CATPT_CHANNEL_CONFIG_3_POINT_0:
  161. return GENMASK(31, 12) | CATPT_CHANNEL_LEFT
  162. | (CATPT_CHANNEL_CENTER << 4)
  163. | (CATPT_CHANNEL_RIGHT << 8);
  164. case CATPT_CHANNEL_CONFIG_3_POINT_1:
  165. return GENMASK(31, 16) | CATPT_CHANNEL_LEFT
  166. | (CATPT_CHANNEL_CENTER << 4)
  167. | (CATPT_CHANNEL_RIGHT << 8)
  168. | (CATPT_CHANNEL_LFE << 12);
  169. case CATPT_CHANNEL_CONFIG_QUATRO:
  170. return GENMASK(31, 16) | CATPT_CHANNEL_LEFT
  171. | (CATPT_CHANNEL_RIGHT << 4)
  172. | (CATPT_CHANNEL_LEFT_SURROUND << 8)
  173. | (CATPT_CHANNEL_RIGHT_SURROUND << 12);
  174. case CATPT_CHANNEL_CONFIG_4_POINT_0:
  175. return GENMASK(31, 16) | CATPT_CHANNEL_LEFT
  176. | (CATPT_CHANNEL_CENTER << 4)
  177. | (CATPT_CHANNEL_RIGHT << 8)
  178. | (CATPT_CHANNEL_CENTER_SURROUND << 12);
  179. case CATPT_CHANNEL_CONFIG_5_POINT_0:
  180. return GENMASK(31, 20) | CATPT_CHANNEL_LEFT
  181. | (CATPT_CHANNEL_CENTER << 4)
  182. | (CATPT_CHANNEL_RIGHT << 8)
  183. | (CATPT_CHANNEL_LEFT_SURROUND << 12)
  184. | (CATPT_CHANNEL_RIGHT_SURROUND << 16);
  185. case CATPT_CHANNEL_CONFIG_5_POINT_1:
  186. return GENMASK(31, 24) | CATPT_CHANNEL_CENTER
  187. | (CATPT_CHANNEL_LEFT << 4)
  188. | (CATPT_CHANNEL_RIGHT << 8)
  189. | (CATPT_CHANNEL_LEFT_SURROUND << 12)
  190. | (CATPT_CHANNEL_RIGHT_SURROUND << 16)
  191. | (CATPT_CHANNEL_LFE << 20);
  192. case CATPT_CHANNEL_CONFIG_DUAL_MONO:
  193. return GENMASK(31, 8) | CATPT_CHANNEL_LEFT
  194. | (CATPT_CHANNEL_LEFT << 4);
  195. default:
  196. return U32_MAX;
  197. }
  198. }
  199. static enum catpt_channel_config catpt_get_channel_config(u32 num_channels)
  200. {
  201. switch (num_channels) {
  202. case 6:
  203. return CATPT_CHANNEL_CONFIG_5_POINT_1;
  204. case 5:
  205. return CATPT_CHANNEL_CONFIG_5_POINT_0;
  206. case 4:
  207. return CATPT_CHANNEL_CONFIG_QUATRO;
  208. case 3:
  209. return CATPT_CHANNEL_CONFIG_2_POINT_1;
  210. case 1:
  211. return CATPT_CHANNEL_CONFIG_MONO;
  212. case 2:
  213. default:
  214. return CATPT_CHANNEL_CONFIG_STEREO;
  215. }
  216. }
  217. static int catpt_dai_startup(struct snd_pcm_substream *substream,
  218. struct snd_soc_dai *dai)
  219. {
  220. struct catpt_stream_template *template;
  221. struct catpt_stream_runtime *stream;
  222. struct catpt_dev *cdev = dev_get_drvdata(dai->dev);
  223. struct resource *res;
  224. int ret;
  225. template = catpt_get_stream_template(substream);
  226. stream = kzalloc(sizeof(*stream), GFP_KERNEL);
  227. if (!stream)
  228. return -ENOMEM;
  229. ret = snd_dma_alloc_pages(SNDRV_DMA_TYPE_DEV, cdev->dev, PAGE_SIZE,
  230. &stream->pgtbl);
  231. if (ret)
  232. goto err_pgtbl;
  233. res = catpt_request_region(&cdev->dram, template->persistent_size);
  234. if (!res) {
  235. ret = -EBUSY;
  236. goto err_request;
  237. }
  238. catpt_dsp_update_srampge(cdev, &cdev->dram, cdev->spec->dram_mask);
  239. stream->template = template;
  240. stream->persistent = res;
  241. stream->substream = substream;
  242. INIT_LIST_HEAD(&stream->node);
  243. snd_soc_dai_set_dma_data(dai, substream, stream);
  244. spin_lock(&cdev->list_lock);
  245. list_add_tail(&stream->node, &cdev->stream_list);
  246. spin_unlock(&cdev->list_lock);
  247. return 0;
  248. err_request:
  249. snd_dma_free_pages(&stream->pgtbl);
  250. err_pgtbl:
  251. kfree(stream);
  252. return ret;
  253. }
  254. static void catpt_dai_shutdown(struct snd_pcm_substream *substream,
  255. struct snd_soc_dai *dai)
  256. {
  257. struct catpt_stream_runtime *stream;
  258. struct catpt_dev *cdev = dev_get_drvdata(dai->dev);
  259. stream = snd_soc_dai_get_dma_data(dai, substream);
  260. spin_lock(&cdev->list_lock);
  261. list_del(&stream->node);
  262. spin_unlock(&cdev->list_lock);
  263. release_resource(stream->persistent);
  264. kfree(stream->persistent);
  265. catpt_dsp_update_srampge(cdev, &cdev->dram, cdev->spec->dram_mask);
  266. snd_dma_free_pages(&stream->pgtbl);
  267. kfree(stream);
  268. snd_soc_dai_set_dma_data(dai, substream, NULL);
  269. }
  270. static int catpt_set_dspvol(struct catpt_dev *cdev, u8 stream_id, long *ctlvol);
  271. static int catpt_dai_apply_usettings(struct snd_soc_dai *dai,
  272. struct catpt_stream_runtime *stream)
  273. {
  274. struct snd_soc_component *component = dai->component;
  275. struct snd_kcontrol *pos;
  276. struct catpt_dev *cdev = dev_get_drvdata(dai->dev);
  277. const char *name;
  278. int ret;
  279. u32 id = stream->info.stream_hw_id;
  280. /* only selected streams have individual controls */
  281. switch (id) {
  282. case CATPT_PIN_ID_OFFLOAD1:
  283. name = "Media0 Playback Volume";
  284. break;
  285. case CATPT_PIN_ID_OFFLOAD2:
  286. name = "Media1 Playback Volume";
  287. break;
  288. case CATPT_PIN_ID_CAPTURE1:
  289. name = "Mic Capture Volume";
  290. break;
  291. case CATPT_PIN_ID_REFERENCE:
  292. name = "Loopback Mute";
  293. break;
  294. default:
  295. return 0;
  296. }
  297. list_for_each_entry(pos, &component->card->snd_card->controls, list) {
  298. if (pos->private_data == component &&
  299. !strncmp(name, pos->id.name, sizeof(pos->id.name)))
  300. break;
  301. }
  302. if (list_entry_is_head(pos, &component->card->snd_card->controls, list))
  303. return -ENOENT;
  304. if (stream->template->type != CATPT_STRM_TYPE_LOOPBACK)
  305. return catpt_set_dspvol(cdev, id, (long *)pos->private_value);
  306. ret = catpt_ipc_mute_loopback(cdev, id, *(bool *)pos->private_value);
  307. if (ret)
  308. return CATPT_IPC_ERROR(ret);
  309. return 0;
  310. }
  311. static int catpt_dai_hw_params(struct snd_pcm_substream *substream,
  312. struct snd_pcm_hw_params *params,
  313. struct snd_soc_dai *dai)
  314. {
  315. struct snd_pcm_runtime *rtm = substream->runtime;
  316. struct snd_dma_buffer *dmab;
  317. struct catpt_stream_runtime *stream;
  318. struct catpt_audio_format afmt;
  319. struct catpt_ring_info rinfo;
  320. struct catpt_dev *cdev = dev_get_drvdata(dai->dev);
  321. int ret;
  322. stream = snd_soc_dai_get_dma_data(dai, substream);
  323. if (stream->allocated)
  324. return 0;
  325. memset(&afmt, 0, sizeof(afmt));
  326. afmt.sample_rate = params_rate(params);
  327. afmt.bit_depth = params_physical_width(params);
  328. afmt.valid_bit_depth = params_width(params);
  329. afmt.num_channels = params_channels(params);
  330. afmt.channel_config = catpt_get_channel_config(afmt.num_channels);
  331. afmt.channel_map = catpt_get_channel_map(afmt.channel_config);
  332. afmt.interleaving = CATPT_INTERLEAVING_PER_CHANNEL;
  333. dmab = snd_pcm_get_dma_buf(substream);
  334. catpt_arrange_page_table(substream, &stream->pgtbl);
  335. memset(&rinfo, 0, sizeof(rinfo));
  336. rinfo.page_table_addr = stream->pgtbl.addr;
  337. rinfo.num_pages = DIV_ROUND_UP(rtm->dma_bytes, PAGE_SIZE);
  338. rinfo.size = rtm->dma_bytes;
  339. rinfo.offset = 0;
  340. rinfo.ring_first_page_pfn = PFN_DOWN(snd_sgbuf_get_addr(dmab, 0));
  341. ret = catpt_ipc_alloc_stream(cdev, stream->template->path_id,
  342. stream->template->type,
  343. &afmt, &rinfo,
  344. stream->template->num_entries,
  345. stream->template->entries,
  346. stream->persistent,
  347. cdev->scratch,
  348. &stream->info);
  349. if (ret)
  350. return CATPT_IPC_ERROR(ret);
  351. ret = catpt_dai_apply_usettings(dai, stream);
  352. if (ret)
  353. return ret;
  354. stream->allocated = true;
  355. return 0;
  356. }
  357. static int catpt_dai_hw_free(struct snd_pcm_substream *substream,
  358. struct snd_soc_dai *dai)
  359. {
  360. struct catpt_stream_runtime *stream;
  361. struct catpt_dev *cdev = dev_get_drvdata(dai->dev);
  362. stream = snd_soc_dai_get_dma_data(dai, substream);
  363. if (!stream->allocated)
  364. return 0;
  365. catpt_ipc_reset_stream(cdev, stream->info.stream_hw_id);
  366. catpt_ipc_free_stream(cdev, stream->info.stream_hw_id);
  367. stream->allocated = false;
  368. return 0;
  369. }
  370. static int catpt_dai_prepare(struct snd_pcm_substream *substream,
  371. struct snd_soc_dai *dai)
  372. {
  373. struct catpt_stream_runtime *stream;
  374. struct catpt_dev *cdev = dev_get_drvdata(dai->dev);
  375. int ret;
  376. stream = snd_soc_dai_get_dma_data(dai, substream);
  377. if (stream->prepared)
  378. return 0;
  379. ret = catpt_ipc_reset_stream(cdev, stream->info.stream_hw_id);
  380. if (ret)
  381. return CATPT_IPC_ERROR(ret);
  382. ret = catpt_ipc_pause_stream(cdev, stream->info.stream_hw_id);
  383. if (ret)
  384. return CATPT_IPC_ERROR(ret);
  385. stream->prepared = true;
  386. return 0;
  387. }
  388. static int catpt_dai_trigger(struct snd_pcm_substream *substream, int cmd,
  389. struct snd_soc_dai *dai)
  390. {
  391. struct snd_pcm_runtime *runtime = substream->runtime;
  392. struct catpt_stream_runtime *stream;
  393. struct catpt_dev *cdev = dev_get_drvdata(dai->dev);
  394. snd_pcm_uframes_t pos;
  395. int ret;
  396. stream = snd_soc_dai_get_dma_data(dai, substream);
  397. switch (cmd) {
  398. case SNDRV_PCM_TRIGGER_START:
  399. /* only offload is set_write_pos driven */
  400. if (stream->template->type != CATPT_STRM_TYPE_RENDER)
  401. goto resume_stream;
  402. pos = frames_to_bytes(runtime, runtime->start_threshold);
  403. /*
  404. * Dsp operates on buffer halves, thus max 2x set_write_pos
  405. * (entire buffer filled) prior to stream start.
  406. */
  407. ret = catpt_ipc_set_write_pos(cdev, stream->info.stream_hw_id,
  408. pos, false, false);
  409. if (ret)
  410. return CATPT_IPC_ERROR(ret);
  411. fallthrough;
  412. case SNDRV_PCM_TRIGGER_RESUME:
  413. case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
  414. resume_stream:
  415. catpt_dsp_update_lpclock(cdev);
  416. ret = catpt_ipc_resume_stream(cdev, stream->info.stream_hw_id);
  417. if (ret)
  418. return CATPT_IPC_ERROR(ret);
  419. break;
  420. case SNDRV_PCM_TRIGGER_STOP:
  421. stream->prepared = false;
  422. fallthrough;
  423. case SNDRV_PCM_TRIGGER_SUSPEND:
  424. case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
  425. ret = catpt_ipc_pause_stream(cdev, stream->info.stream_hw_id);
  426. catpt_dsp_update_lpclock(cdev);
  427. if (ret)
  428. return CATPT_IPC_ERROR(ret);
  429. break;
  430. default:
  431. break;
  432. }
  433. return 0;
  434. }
  435. void catpt_stream_update_position(struct catpt_dev *cdev,
  436. struct catpt_stream_runtime *stream,
  437. struct catpt_notify_position *pos)
  438. {
  439. struct snd_pcm_substream *substream = stream->substream;
  440. struct snd_pcm_runtime *r = substream->runtime;
  441. snd_pcm_uframes_t dsppos, newpos;
  442. int ret;
  443. dsppos = bytes_to_frames(r, pos->stream_position);
  444. if (!stream->prepared)
  445. goto exit;
  446. /* only offload is set_write_pos driven */
  447. if (stream->template->type != CATPT_STRM_TYPE_RENDER)
  448. goto exit;
  449. if (dsppos >= r->buffer_size / 2)
  450. newpos = r->buffer_size / 2;
  451. else
  452. newpos = 0;
  453. /*
  454. * Dsp operates on buffer halves, thus on every notify position
  455. * (buffer half consumed) update wp to allow stream progression.
  456. */
  457. ret = catpt_ipc_set_write_pos(cdev, stream->info.stream_hw_id,
  458. frames_to_bytes(r, newpos),
  459. false, false);
  460. if (ret) {
  461. dev_err(cdev->dev, "update position for stream %d failed: %d\n",
  462. stream->info.stream_hw_id, ret);
  463. return;
  464. }
  465. exit:
  466. snd_pcm_period_elapsed(substream);
  467. }
  468. /* 200 ms for 2 32-bit channels at 48kHz (native format) */
  469. #define CATPT_BUFFER_MAX_SIZE 76800
  470. #define CATPT_PCM_PERIODS_MAX 4
  471. #define CATPT_PCM_PERIODS_MIN 2
  472. static const struct snd_pcm_hardware catpt_pcm_hardware = {
  473. .info = SNDRV_PCM_INFO_MMAP |
  474. SNDRV_PCM_INFO_MMAP_VALID |
  475. SNDRV_PCM_INFO_INTERLEAVED |
  476. SNDRV_PCM_INFO_PAUSE |
  477. SNDRV_PCM_INFO_RESUME |
  478. SNDRV_PCM_INFO_NO_PERIOD_WAKEUP,
  479. .formats = SNDRV_PCM_FMTBIT_S16_LE |
  480. SNDRV_PCM_FMTBIT_S24_LE |
  481. SNDRV_PCM_FMTBIT_S32_LE,
  482. .period_bytes_min = PAGE_SIZE,
  483. .period_bytes_max = CATPT_BUFFER_MAX_SIZE / CATPT_PCM_PERIODS_MIN,
  484. .periods_min = CATPT_PCM_PERIODS_MIN,
  485. .periods_max = CATPT_PCM_PERIODS_MAX,
  486. .buffer_bytes_max = CATPT_BUFFER_MAX_SIZE,
  487. };
  488. static int catpt_component_pcm_construct(struct snd_soc_component *component,
  489. struct snd_soc_pcm_runtime *rtm)
  490. {
  491. struct catpt_dev *cdev = dev_get_drvdata(component->dev);
  492. snd_pcm_set_managed_buffer_all(rtm->pcm, SNDRV_DMA_TYPE_DEV_SG,
  493. cdev->dev,
  494. catpt_pcm_hardware.buffer_bytes_max,
  495. catpt_pcm_hardware.buffer_bytes_max);
  496. return 0;
  497. }
  498. static int catpt_component_open(struct snd_soc_component *component,
  499. struct snd_pcm_substream *substream)
  500. {
  501. struct snd_soc_pcm_runtime *rtm = asoc_substream_to_rtd(substream);
  502. if (!rtm->dai_link->no_pcm)
  503. snd_soc_set_runtime_hwparams(substream, &catpt_pcm_hardware);
  504. return 0;
  505. }
  506. static snd_pcm_uframes_t
  507. catpt_component_pointer(struct snd_soc_component *component,
  508. struct snd_pcm_substream *substream)
  509. {
  510. struct snd_soc_pcm_runtime *rtm = asoc_substream_to_rtd(substream);
  511. struct snd_soc_dai *cpu_dai = asoc_rtd_to_cpu(rtm, 0);
  512. struct catpt_stream_runtime *stream;
  513. struct catpt_dev *cdev = dev_get_drvdata(component->dev);
  514. u32 pos;
  515. if (rtm->dai_link->no_pcm)
  516. return 0;
  517. stream = snd_soc_dai_get_dma_data(cpu_dai, substream);
  518. pos = catpt_stream_read_position(cdev, stream);
  519. return bytes_to_frames(substream->runtime, pos);
  520. }
  521. static const struct snd_soc_dai_ops catpt_fe_dai_ops = {
  522. .startup = catpt_dai_startup,
  523. .shutdown = catpt_dai_shutdown,
  524. .hw_params = catpt_dai_hw_params,
  525. .hw_free = catpt_dai_hw_free,
  526. .prepare = catpt_dai_prepare,
  527. .trigger = catpt_dai_trigger,
  528. };
  529. static int catpt_dai_pcm_new(struct snd_soc_pcm_runtime *rtm,
  530. struct snd_soc_dai *dai)
  531. {
  532. struct snd_soc_dai *codec_dai = asoc_rtd_to_codec(rtm, 0);
  533. struct catpt_ssp_device_format devfmt;
  534. struct catpt_dev *cdev = dev_get_drvdata(dai->dev);
  535. int ret;
  536. devfmt.iface = dai->driver->id;
  537. devfmt.channels = codec_dai->driver->capture.channels_max;
  538. switch (devfmt.iface) {
  539. case CATPT_SSP_IFACE_0:
  540. devfmt.mclk = CATPT_MCLK_FREQ_24_MHZ;
  541. switch (devfmt.channels) {
  542. case 4:
  543. devfmt.mode = CATPT_SSP_MODE_TDM_PROVIDER;
  544. devfmt.clock_divider = 4;
  545. break;
  546. case 2:
  547. default:
  548. devfmt.mode = CATPT_SSP_MODE_I2S_PROVIDER;
  549. devfmt.clock_divider = 9;
  550. break;
  551. }
  552. break;
  553. case CATPT_SSP_IFACE_1:
  554. devfmt.mclk = CATPT_MCLK_OFF;
  555. devfmt.mode = CATPT_SSP_MODE_I2S_CONSUMER;
  556. devfmt.clock_divider = 0;
  557. break;
  558. }
  559. /* see if this is a new configuration */
  560. if (!memcmp(&cdev->devfmt[devfmt.iface], &devfmt, sizeof(devfmt)))
  561. return 0;
  562. ret = pm_runtime_resume_and_get(cdev->dev);
  563. if (ret < 0 && ret != -EACCES)
  564. return ret;
  565. ret = catpt_ipc_set_device_format(cdev, &devfmt);
  566. pm_runtime_mark_last_busy(cdev->dev);
  567. pm_runtime_put_autosuspend(cdev->dev);
  568. if (ret)
  569. return CATPT_IPC_ERROR(ret);
  570. /* store device format set for given SSP */
  571. memcpy(&cdev->devfmt[devfmt.iface], &devfmt, sizeof(devfmt));
  572. return 0;
  573. }
  574. static struct snd_soc_dai_driver dai_drivers[] = {
  575. /* FE DAIs */
  576. {
  577. .name = "System Pin",
  578. .id = CATPT_STRM_TYPE_SYSTEM,
  579. .ops = &catpt_fe_dai_ops,
  580. .playback = {
  581. .stream_name = "System Playback",
  582. .channels_min = 2,
  583. .channels_max = 2,
  584. .rates = SNDRV_PCM_RATE_48000,
  585. .formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S24_LE,
  586. },
  587. .capture = {
  588. .stream_name = "Analog Capture",
  589. .channels_min = 2,
  590. .channels_max = 4,
  591. .rates = SNDRV_PCM_RATE_48000,
  592. .formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S24_LE,
  593. },
  594. },
  595. {
  596. .name = "Offload0 Pin",
  597. .id = CATPT_STRM_TYPE_RENDER,
  598. .ops = &catpt_fe_dai_ops,
  599. .playback = {
  600. .stream_name = "Offload0 Playback",
  601. .channels_min = 2,
  602. .channels_max = 2,
  603. .rates = SNDRV_PCM_RATE_8000_192000,
  604. .formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S24_LE,
  605. },
  606. },
  607. {
  608. .name = "Offload1 Pin",
  609. .id = CATPT_STRM_TYPE_RENDER,
  610. .ops = &catpt_fe_dai_ops,
  611. .playback = {
  612. .stream_name = "Offload1 Playback",
  613. .channels_min = 2,
  614. .channels_max = 2,
  615. .rates = SNDRV_PCM_RATE_8000_192000,
  616. .formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S24_LE,
  617. },
  618. },
  619. {
  620. .name = "Loopback Pin",
  621. .id = CATPT_STRM_TYPE_LOOPBACK,
  622. .ops = &catpt_fe_dai_ops,
  623. .capture = {
  624. .stream_name = "Loopback Capture",
  625. .channels_min = 2,
  626. .channels_max = 2,
  627. .rates = SNDRV_PCM_RATE_48000,
  628. .formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S24_LE,
  629. },
  630. },
  631. {
  632. .name = "Bluetooth Pin",
  633. .id = CATPT_STRM_TYPE_BLUETOOTH_RENDER,
  634. .ops = &catpt_fe_dai_ops,
  635. .playback = {
  636. .stream_name = "Bluetooth Playback",
  637. .channels_min = 1,
  638. .channels_max = 1,
  639. .rates = SNDRV_PCM_RATE_8000,
  640. .formats = SNDRV_PCM_FMTBIT_S16_LE,
  641. },
  642. .capture = {
  643. .stream_name = "Bluetooth Capture",
  644. .channels_min = 1,
  645. .channels_max = 1,
  646. .rates = SNDRV_PCM_RATE_8000,
  647. .formats = SNDRV_PCM_FMTBIT_S16_LE,
  648. },
  649. },
  650. /* BE DAIs */
  651. {
  652. .name = "ssp0-port",
  653. .id = CATPT_SSP_IFACE_0,
  654. .pcm_new = catpt_dai_pcm_new,
  655. .playback = {
  656. .channels_min = 1,
  657. .channels_max = 8,
  658. },
  659. .capture = {
  660. .channels_min = 1,
  661. .channels_max = 8,
  662. },
  663. },
  664. {
  665. .name = "ssp1-port",
  666. .id = CATPT_SSP_IFACE_1,
  667. .pcm_new = catpt_dai_pcm_new,
  668. .playback = {
  669. .channels_min = 1,
  670. .channels_max = 8,
  671. },
  672. .capture = {
  673. .channels_min = 1,
  674. .channels_max = 8,
  675. },
  676. },
  677. };
  678. #define DSP_VOLUME_MAX S32_MAX /* 0db */
  679. #define DSP_VOLUME_STEP_MAX 30
  680. static u32 ctlvol_to_dspvol(u32 value)
  681. {
  682. if (value > DSP_VOLUME_STEP_MAX)
  683. value = 0;
  684. return DSP_VOLUME_MAX >> (DSP_VOLUME_STEP_MAX - value);
  685. }
  686. static u32 dspvol_to_ctlvol(u32 volume)
  687. {
  688. if (volume > DSP_VOLUME_MAX)
  689. return DSP_VOLUME_STEP_MAX;
  690. return volume ? __fls(volume) : 0;
  691. }
  692. static int catpt_set_dspvol(struct catpt_dev *cdev, u8 stream_id, long *ctlvol)
  693. {
  694. u32 dspvol;
  695. int ret, i;
  696. for (i = 1; i < CATPT_CHANNELS_MAX; i++)
  697. if (ctlvol[i] != ctlvol[0])
  698. break;
  699. if (i == CATPT_CHANNELS_MAX) {
  700. dspvol = ctlvol_to_dspvol(ctlvol[0]);
  701. ret = catpt_ipc_set_volume(cdev, stream_id,
  702. CATPT_ALL_CHANNELS_MASK, dspvol,
  703. 0, CATPT_AUDIO_CURVE_NONE);
  704. } else {
  705. for (i = 0; i < CATPT_CHANNELS_MAX; i++) {
  706. dspvol = ctlvol_to_dspvol(ctlvol[i]);
  707. ret = catpt_ipc_set_volume(cdev, stream_id,
  708. i, dspvol,
  709. 0, CATPT_AUDIO_CURVE_NONE);
  710. if (ret)
  711. break;
  712. }
  713. }
  714. if (ret)
  715. return CATPT_IPC_ERROR(ret);
  716. return 0;
  717. }
  718. static int catpt_volume_info(struct snd_kcontrol *kcontrol,
  719. struct snd_ctl_elem_info *uinfo)
  720. {
  721. uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
  722. uinfo->count = CATPT_CHANNELS_MAX;
  723. uinfo->value.integer.min = 0;
  724. uinfo->value.integer.max = DSP_VOLUME_STEP_MAX;
  725. return 0;
  726. }
  727. static int catpt_mixer_volume_get(struct snd_kcontrol *kcontrol,
  728. struct snd_ctl_elem_value *ucontrol)
  729. {
  730. struct snd_soc_component *component =
  731. snd_soc_kcontrol_component(kcontrol);
  732. struct catpt_dev *cdev = dev_get_drvdata(component->dev);
  733. u32 dspvol;
  734. int ret;
  735. int i;
  736. ret = pm_runtime_resume_and_get(cdev->dev);
  737. if (ret < 0 && ret != -EACCES)
  738. return ret;
  739. for (i = 0; i < CATPT_CHANNELS_MAX; i++) {
  740. dspvol = catpt_mixer_volume(cdev, &cdev->mixer, i);
  741. ucontrol->value.integer.value[i] = dspvol_to_ctlvol(dspvol);
  742. }
  743. pm_runtime_mark_last_busy(cdev->dev);
  744. pm_runtime_put_autosuspend(cdev->dev);
  745. return 0;
  746. }
  747. static int catpt_mixer_volume_put(struct snd_kcontrol *kcontrol,
  748. struct snd_ctl_elem_value *ucontrol)
  749. {
  750. struct snd_soc_component *component =
  751. snd_soc_kcontrol_component(kcontrol);
  752. struct catpt_dev *cdev = dev_get_drvdata(component->dev);
  753. int ret;
  754. ret = pm_runtime_resume_and_get(cdev->dev);
  755. if (ret < 0 && ret != -EACCES)
  756. return ret;
  757. ret = catpt_set_dspvol(cdev, cdev->mixer.mixer_hw_id,
  758. ucontrol->value.integer.value);
  759. pm_runtime_mark_last_busy(cdev->dev);
  760. pm_runtime_put_autosuspend(cdev->dev);
  761. return ret;
  762. }
  763. static int catpt_stream_volume_get(struct snd_kcontrol *kcontrol,
  764. struct snd_ctl_elem_value *ucontrol,
  765. enum catpt_pin_id pin_id)
  766. {
  767. struct snd_soc_component *component =
  768. snd_soc_kcontrol_component(kcontrol);
  769. struct catpt_stream_runtime *stream;
  770. struct catpt_dev *cdev = dev_get_drvdata(component->dev);
  771. long *ctlvol = (long *)kcontrol->private_value;
  772. u32 dspvol;
  773. int ret;
  774. int i;
  775. stream = catpt_stream_find(cdev, pin_id);
  776. if (!stream) {
  777. for (i = 0; i < CATPT_CHANNELS_MAX; i++)
  778. ucontrol->value.integer.value[i] = ctlvol[i];
  779. return 0;
  780. }
  781. ret = pm_runtime_resume_and_get(cdev->dev);
  782. if (ret < 0 && ret != -EACCES)
  783. return ret;
  784. for (i = 0; i < CATPT_CHANNELS_MAX; i++) {
  785. dspvol = catpt_stream_volume(cdev, stream, i);
  786. ucontrol->value.integer.value[i] = dspvol_to_ctlvol(dspvol);
  787. }
  788. pm_runtime_mark_last_busy(cdev->dev);
  789. pm_runtime_put_autosuspend(cdev->dev);
  790. return 0;
  791. }
  792. static int catpt_stream_volume_put(struct snd_kcontrol *kcontrol,
  793. struct snd_ctl_elem_value *ucontrol,
  794. enum catpt_pin_id pin_id)
  795. {
  796. struct snd_soc_component *component =
  797. snd_soc_kcontrol_component(kcontrol);
  798. struct catpt_stream_runtime *stream;
  799. struct catpt_dev *cdev = dev_get_drvdata(component->dev);
  800. long *ctlvol = (long *)kcontrol->private_value;
  801. int ret, i;
  802. stream = catpt_stream_find(cdev, pin_id);
  803. if (!stream) {
  804. for (i = 0; i < CATPT_CHANNELS_MAX; i++)
  805. ctlvol[i] = ucontrol->value.integer.value[i];
  806. return 0;
  807. }
  808. ret = pm_runtime_resume_and_get(cdev->dev);
  809. if (ret < 0 && ret != -EACCES)
  810. return ret;
  811. ret = catpt_set_dspvol(cdev, stream->info.stream_hw_id,
  812. ucontrol->value.integer.value);
  813. pm_runtime_mark_last_busy(cdev->dev);
  814. pm_runtime_put_autosuspend(cdev->dev);
  815. if (ret)
  816. return ret;
  817. for (i = 0; i < CATPT_CHANNELS_MAX; i++)
  818. ctlvol[i] = ucontrol->value.integer.value[i];
  819. return 0;
  820. }
  821. static int catpt_offload1_volume_get(struct snd_kcontrol *kctl,
  822. struct snd_ctl_elem_value *uctl)
  823. {
  824. return catpt_stream_volume_get(kctl, uctl, CATPT_PIN_ID_OFFLOAD1);
  825. }
  826. static int catpt_offload1_volume_put(struct snd_kcontrol *kctl,
  827. struct snd_ctl_elem_value *uctl)
  828. {
  829. return catpt_stream_volume_put(kctl, uctl, CATPT_PIN_ID_OFFLOAD1);
  830. }
  831. static int catpt_offload2_volume_get(struct snd_kcontrol *kctl,
  832. struct snd_ctl_elem_value *uctl)
  833. {
  834. return catpt_stream_volume_get(kctl, uctl, CATPT_PIN_ID_OFFLOAD2);
  835. }
  836. static int catpt_offload2_volume_put(struct snd_kcontrol *kctl,
  837. struct snd_ctl_elem_value *uctl)
  838. {
  839. return catpt_stream_volume_put(kctl, uctl, CATPT_PIN_ID_OFFLOAD2);
  840. }
  841. static int catpt_capture_volume_get(struct snd_kcontrol *kctl,
  842. struct snd_ctl_elem_value *uctl)
  843. {
  844. return catpt_stream_volume_get(kctl, uctl, CATPT_PIN_ID_CAPTURE1);
  845. }
  846. static int catpt_capture_volume_put(struct snd_kcontrol *kctl,
  847. struct snd_ctl_elem_value *uctl)
  848. {
  849. return catpt_stream_volume_put(kctl, uctl, CATPT_PIN_ID_CAPTURE1);
  850. }
  851. static int catpt_loopback_switch_get(struct snd_kcontrol *kcontrol,
  852. struct snd_ctl_elem_value *ucontrol)
  853. {
  854. ucontrol->value.integer.value[0] = *(bool *)kcontrol->private_value;
  855. return 0;
  856. }
  857. static int catpt_loopback_switch_put(struct snd_kcontrol *kcontrol,
  858. struct snd_ctl_elem_value *ucontrol)
  859. {
  860. struct snd_soc_component *component =
  861. snd_soc_kcontrol_component(kcontrol);
  862. struct catpt_stream_runtime *stream;
  863. struct catpt_dev *cdev = dev_get_drvdata(component->dev);
  864. bool mute;
  865. int ret;
  866. mute = (bool)ucontrol->value.integer.value[0];
  867. stream = catpt_stream_find(cdev, CATPT_PIN_ID_REFERENCE);
  868. if (!stream) {
  869. *(bool *)kcontrol->private_value = mute;
  870. return 0;
  871. }
  872. ret = pm_runtime_resume_and_get(cdev->dev);
  873. if (ret < 0 && ret != -EACCES)
  874. return ret;
  875. ret = catpt_ipc_mute_loopback(cdev, stream->info.stream_hw_id, mute);
  876. pm_runtime_mark_last_busy(cdev->dev);
  877. pm_runtime_put_autosuspend(cdev->dev);
  878. if (ret)
  879. return CATPT_IPC_ERROR(ret);
  880. *(bool *)kcontrol->private_value = mute;
  881. return 0;
  882. }
  883. static int catpt_waves_switch_get(struct snd_kcontrol *kcontrol,
  884. struct snd_ctl_elem_value *ucontrol)
  885. {
  886. return 0;
  887. }
  888. static int catpt_waves_switch_put(struct snd_kcontrol *kcontrol,
  889. struct snd_ctl_elem_value *ucontrol)
  890. {
  891. return 0;
  892. }
  893. static int catpt_waves_param_get(struct snd_kcontrol *kcontrol,
  894. unsigned int __user *bytes,
  895. unsigned int size)
  896. {
  897. return 0;
  898. }
  899. static int catpt_waves_param_put(struct snd_kcontrol *kcontrol,
  900. const unsigned int __user *bytes,
  901. unsigned int size)
  902. {
  903. return 0;
  904. }
  905. static const SNDRV_CTL_TLVD_DECLARE_DB_SCALE(catpt_volume_tlv, -9000, 300, 1);
  906. #define CATPT_VOLUME_CTL(kname, sname) \
  907. { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
  908. .name = (kname), \
  909. .access = SNDRV_CTL_ELEM_ACCESS_TLV_READ | \
  910. SNDRV_CTL_ELEM_ACCESS_READWRITE, \
  911. .info = catpt_volume_info, \
  912. .get = catpt_##sname##_volume_get, \
  913. .put = catpt_##sname##_volume_put, \
  914. .tlv.p = catpt_volume_tlv, \
  915. .private_value = (unsigned long) \
  916. &(long[CATPT_CHANNELS_MAX]) {0} }
  917. static const struct snd_kcontrol_new component_kcontrols[] = {
  918. /* Master volume (mixer stream) */
  919. CATPT_VOLUME_CTL("Master Playback Volume", mixer),
  920. /* Individual volume controls for offload and capture */
  921. CATPT_VOLUME_CTL("Media0 Playback Volume", offload1),
  922. CATPT_VOLUME_CTL("Media1 Playback Volume", offload2),
  923. CATPT_VOLUME_CTL("Mic Capture Volume", capture),
  924. SOC_SINGLE_BOOL_EXT("Loopback Mute", (unsigned long)&(bool[1]) {0},
  925. catpt_loopback_switch_get, catpt_loopback_switch_put),
  926. /* Enable or disable WAVES module */
  927. SOC_SINGLE_BOOL_EXT("Waves Switch", 0,
  928. catpt_waves_switch_get, catpt_waves_switch_put),
  929. /* WAVES module parameter control */
  930. SND_SOC_BYTES_TLV("Waves Set Param", 128,
  931. catpt_waves_param_get, catpt_waves_param_put),
  932. };
  933. static const struct snd_soc_dapm_widget component_widgets[] = {
  934. SND_SOC_DAPM_AIF_IN("SSP0 CODEC IN", NULL, 0, SND_SOC_NOPM, 0, 0),
  935. SND_SOC_DAPM_AIF_OUT("SSP0 CODEC OUT", NULL, 0, SND_SOC_NOPM, 0, 0),
  936. SND_SOC_DAPM_AIF_IN("SSP1 BT IN", NULL, 0, SND_SOC_NOPM, 0, 0),
  937. SND_SOC_DAPM_AIF_OUT("SSP1 BT OUT", NULL, 0, SND_SOC_NOPM, 0, 0),
  938. SND_SOC_DAPM_MIXER("Playback VMixer", SND_SOC_NOPM, 0, 0, NULL, 0),
  939. };
  940. static const struct snd_soc_dapm_route component_routes[] = {
  941. {"Playback VMixer", NULL, "System Playback"},
  942. {"Playback VMixer", NULL, "Offload0 Playback"},
  943. {"Playback VMixer", NULL, "Offload1 Playback"},
  944. {"SSP0 CODEC OUT", NULL, "Playback VMixer"},
  945. {"Analog Capture", NULL, "SSP0 CODEC IN"},
  946. {"Loopback Capture", NULL, "SSP0 CODEC IN"},
  947. {"SSP1 BT OUT", NULL, "Bluetooth Playback"},
  948. {"Bluetooth Capture", NULL, "SSP1 BT IN"},
  949. };
  950. static const struct snd_soc_component_driver catpt_comp_driver = {
  951. .name = "catpt-platform",
  952. .pcm_construct = catpt_component_pcm_construct,
  953. .open = catpt_component_open,
  954. .pointer = catpt_component_pointer,
  955. .controls = component_kcontrols,
  956. .num_controls = ARRAY_SIZE(component_kcontrols),
  957. .dapm_widgets = component_widgets,
  958. .num_dapm_widgets = ARRAY_SIZE(component_widgets),
  959. .dapm_routes = component_routes,
  960. .num_dapm_routes = ARRAY_SIZE(component_routes),
  961. };
  962. int catpt_arm_stream_templates(struct catpt_dev *cdev)
  963. {
  964. struct resource *res;
  965. u32 scratch_size = 0;
  966. int i, j;
  967. for (i = 0; i < ARRAY_SIZE(catpt_topology); i++) {
  968. struct catpt_stream_template *template;
  969. struct catpt_module_entry *entry;
  970. struct catpt_module_type *type;
  971. template = catpt_topology[i];
  972. template->persistent_size = 0;
  973. for (j = 0; j < template->num_entries; j++) {
  974. entry = &template->entries[j];
  975. type = &cdev->modules[entry->module_id];
  976. if (!type->loaded)
  977. return -ENOENT;
  978. entry->entry_point = type->entry_point;
  979. template->persistent_size += type->persistent_size;
  980. if (type->scratch_size > scratch_size)
  981. scratch_size = type->scratch_size;
  982. }
  983. }
  984. if (scratch_size) {
  985. /* allocate single scratch area for all modules */
  986. res = catpt_request_region(&cdev->dram, scratch_size);
  987. if (!res)
  988. return -EBUSY;
  989. cdev->scratch = res;
  990. }
  991. return 0;
  992. }
  993. int catpt_register_plat_component(struct catpt_dev *cdev)
  994. {
  995. struct snd_soc_component *component;
  996. int ret;
  997. component = devm_kzalloc(cdev->dev, sizeof(*component), GFP_KERNEL);
  998. if (!component)
  999. return -ENOMEM;
  1000. ret = snd_soc_component_initialize(component, &catpt_comp_driver,
  1001. cdev->dev);
  1002. if (ret)
  1003. return ret;
  1004. component->name = catpt_comp_driver.name;
  1005. return snd_soc_add_component(component, dai_drivers,
  1006. ARRAY_SIZE(dai_drivers));
  1007. }