Skip to content

Commit 6e32dfc

Browse files
committed
Merge tag 'soundwire-6.6-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/vkoul/soundwire
Pull soundwire updates from Vinod Koul: "Device numbering and intel driver changes are main features: - Core support for soundwire device number allocation - intel driver updates for adding hw_params for DAI ops, hybrid number allocation and power managemnt callback updates - DT header include changes for subsystem" * tag 'soundwire-6.6-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/vkoul/soundwire: soundwire: intel_ace2x: add DAI hw_params/prepare/hw_free callbacks soundwire: intel_auxdevice: add hybrid IDA-based device_number allocation soundwire: bus: add callbacks for device_number allocation soundwire: extend parameters of new_peripheral_assigned() callback soundWire: intel_auxdevice: resume 'sdw-master' on startup and system resume soundwire: intel_auxdevice: enable pm_runtime earlier on startup soundwire: Explicitly include correct DT includes
2 parents bac8a20 + 8c4c9a9 commit 6e32dfc

File tree

6 files changed

+401
-32
lines changed

6 files changed

+401
-32
lines changed

drivers/soundwire/bus.c

Lines changed: 8 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,6 @@
1313
#include "sysfs_local.h"
1414

1515
static DEFINE_IDA(sdw_bus_ida);
16-
static DEFINE_IDA(sdw_peripheral_ida);
1716

1817
static int sdw_get_id(struct sdw_bus *bus)
1918
{
@@ -194,8 +193,8 @@ static int sdw_delete_slave(struct device *dev, void *data)
194193

195194
if (slave->dev_num) { /* clear dev_num if assigned */
196195
clear_bit(slave->dev_num, bus->assigned);
197-
if (bus->dev_num_ida_min)
198-
ida_free(&sdw_peripheral_ida, slave->dev_num);
196+
if (bus->ops && bus->ops->put_device_num)
197+
bus->ops->put_device_num(bus, slave);
199198
}
200199
list_del_init(&slave->node);
201200
mutex_unlock(&bus->bus_lock);
@@ -739,16 +738,15 @@ EXPORT_SYMBOL(sdw_compare_devid);
739738
/* called with bus_lock held */
740739
static int sdw_get_device_num(struct sdw_slave *slave)
741740
{
741+
struct sdw_bus *bus = slave->bus;
742742
int bit;
743743

744-
if (slave->bus->dev_num_ida_min) {
745-
bit = ida_alloc_range(&sdw_peripheral_ida,
746-
slave->bus->dev_num_ida_min, SDW_MAX_DEVICES,
747-
GFP_KERNEL);
744+
if (bus->ops && bus->ops->get_device_num) {
745+
bit = bus->ops->get_device_num(bus, slave);
748746
if (bit < 0)
749747
goto err;
750748
} else {
751-
bit = find_first_zero_bit(slave->bus->assigned, SDW_MAX_DEVICES);
749+
bit = find_first_zero_bit(bus->assigned, SDW_MAX_DEVICES);
752750
if (bit == SDW_MAX_DEVICES) {
753751
bit = -ENODEV;
754752
goto err;
@@ -759,7 +757,7 @@ static int sdw_get_device_num(struct sdw_slave *slave)
759757
* Do not update dev_num in Slave data structure here,
760758
* Update once program dev_num is successful
761759
*/
762-
set_bit(bit, slave->bus->assigned);
760+
set_bit(bit, bus->assigned);
763761

764762
err:
765763
return bit;
@@ -810,7 +808,7 @@ static int sdw_assign_device_num(struct sdw_slave *slave)
810808
slave->dev_num = slave->dev_num_sticky;
811809

812810
if (bus->ops && bus->ops->new_peripheral_assigned)
813-
bus->ops->new_peripheral_assigned(bus, dev_num);
811+
bus->ops->new_peripheral_assigned(bus, slave, dev_num);
814812

815813
return 0;
816814
}

drivers/soundwire/intel_ace2x.c

Lines changed: 283 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
#include <linux/soundwire/sdw_registers.h>
1111
#include <linux/soundwire/sdw.h>
1212
#include <linux/soundwire/sdw_intel.h>
13+
#include <sound/pcm_params.h>
1314
#include <sound/hda-mlink.h>
1415
#include "cadence_master.h"
1516
#include "bus.h"
@@ -191,10 +192,292 @@ static bool intel_check_cmdsync_unlocked(struct sdw_intel *sdw)
191192
return hdac_bus_eml_sdw_check_cmdsync_unlocked(sdw->link_res->hbus);
192193
}
193194

195+
/* DAI callbacks */
196+
static int intel_params_stream(struct sdw_intel *sdw,
197+
struct snd_pcm_substream *substream,
198+
struct snd_soc_dai *dai,
199+
struct snd_pcm_hw_params *hw_params,
200+
int link_id, int alh_stream_id)
201+
{
202+
struct sdw_intel_link_res *res = sdw->link_res;
203+
struct sdw_intel_stream_params_data params_data;
204+
205+
params_data.substream = substream;
206+
params_data.dai = dai;
207+
params_data.hw_params = hw_params;
208+
params_data.link_id = link_id;
209+
params_data.alh_stream_id = alh_stream_id;
210+
211+
if (res->ops && res->ops->params_stream && res->dev)
212+
return res->ops->params_stream(res->dev,
213+
&params_data);
214+
return -EIO;
215+
}
216+
217+
static int intel_free_stream(struct sdw_intel *sdw,
218+
struct snd_pcm_substream *substream,
219+
struct snd_soc_dai *dai,
220+
int link_id)
221+
222+
{
223+
struct sdw_intel_link_res *res = sdw->link_res;
224+
struct sdw_intel_stream_free_data free_data;
225+
226+
free_data.substream = substream;
227+
free_data.dai = dai;
228+
free_data.link_id = link_id;
229+
230+
if (res->ops && res->ops->free_stream && res->dev)
231+
return res->ops->free_stream(res->dev,
232+
&free_data);
233+
234+
return 0;
235+
}
236+
194237
/*
195238
* DAI operations
196239
*/
240+
static int intel_hw_params(struct snd_pcm_substream *substream,
241+
struct snd_pcm_hw_params *params,
242+
struct snd_soc_dai *dai)
243+
{
244+
struct sdw_cdns *cdns = snd_soc_dai_get_drvdata(dai);
245+
struct sdw_intel *sdw = cdns_to_intel(cdns);
246+
struct sdw_cdns_dai_runtime *dai_runtime;
247+
struct sdw_cdns_pdi *pdi;
248+
struct sdw_stream_config sconfig;
249+
struct sdw_port_config *pconfig;
250+
int ch, dir;
251+
int ret;
252+
253+
dai_runtime = cdns->dai_runtime_array[dai->id];
254+
if (!dai_runtime)
255+
return -EIO;
256+
257+
ch = params_channels(params);
258+
if (substream->stream == SNDRV_PCM_STREAM_CAPTURE)
259+
dir = SDW_DATA_DIR_RX;
260+
else
261+
dir = SDW_DATA_DIR_TX;
262+
263+
pdi = sdw_cdns_alloc_pdi(cdns, &cdns->pcm, ch, dir, dai->id);
264+
265+
if (!pdi) {
266+
ret = -EINVAL;
267+
goto error;
268+
}
269+
270+
/* the SHIM will be configured in the callback functions */
271+
272+
sdw_cdns_config_stream(cdns, ch, dir, pdi);
273+
274+
/* store pdi and state, may be needed in prepare step */
275+
dai_runtime->paused = false;
276+
dai_runtime->suspended = false;
277+
dai_runtime->pdi = pdi;
278+
279+
/* Inform DSP about PDI stream number */
280+
ret = intel_params_stream(sdw, substream, dai, params,
281+
sdw->instance,
282+
pdi->intel_alh_id);
283+
if (ret)
284+
goto error;
285+
286+
sconfig.direction = dir;
287+
sconfig.ch_count = ch;
288+
sconfig.frame_rate = params_rate(params);
289+
sconfig.type = dai_runtime->stream_type;
290+
291+
sconfig.bps = snd_pcm_format_width(params_format(params));
292+
293+
/* Port configuration */
294+
pconfig = kzalloc(sizeof(*pconfig), GFP_KERNEL);
295+
if (!pconfig) {
296+
ret = -ENOMEM;
297+
goto error;
298+
}
299+
300+
pconfig->num = pdi->num;
301+
pconfig->ch_mask = (1 << ch) - 1;
302+
303+
ret = sdw_stream_add_master(&cdns->bus, &sconfig,
304+
pconfig, 1, dai_runtime->stream);
305+
if (ret)
306+
dev_err(cdns->dev, "add master to stream failed:%d\n", ret);
307+
308+
kfree(pconfig);
309+
error:
310+
return ret;
311+
}
312+
313+
static int intel_prepare(struct snd_pcm_substream *substream,
314+
struct snd_soc_dai *dai)
315+
{
316+
struct sdw_cdns *cdns = snd_soc_dai_get_drvdata(dai);
317+
struct sdw_intel *sdw = cdns_to_intel(cdns);
318+
struct sdw_cdns_dai_runtime *dai_runtime;
319+
int ch, dir;
320+
int ret = 0;
321+
322+
dai_runtime = cdns->dai_runtime_array[dai->id];
323+
if (!dai_runtime) {
324+
dev_err(dai->dev, "failed to get dai runtime in %s\n",
325+
__func__);
326+
return -EIO;
327+
}
328+
329+
if (dai_runtime->suspended) {
330+
struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
331+
struct snd_pcm_hw_params *hw_params;
332+
333+
hw_params = &rtd->dpcm[substream->stream].hw_params;
334+
335+
dai_runtime->suspended = false;
336+
337+
/*
338+
* .prepare() is called after system resume, where we
339+
* need to reinitialize the SHIM/ALH/Cadence IP.
340+
* .prepare() is also called to deal with underflows,
341+
* but in those cases we cannot touch ALH/SHIM
342+
* registers
343+
*/
344+
345+
/* configure stream */
346+
ch = params_channels(hw_params);
347+
if (substream->stream == SNDRV_PCM_STREAM_CAPTURE)
348+
dir = SDW_DATA_DIR_RX;
349+
else
350+
dir = SDW_DATA_DIR_TX;
351+
352+
/* the SHIM will be configured in the callback functions */
353+
354+
sdw_cdns_config_stream(cdns, ch, dir, dai_runtime->pdi);
355+
356+
/* Inform DSP about PDI stream number */
357+
ret = intel_params_stream(sdw, substream, dai,
358+
hw_params,
359+
sdw->instance,
360+
dai_runtime->pdi->intel_alh_id);
361+
}
362+
363+
return ret;
364+
}
365+
366+
static int
367+
intel_hw_free(struct snd_pcm_substream *substream, struct snd_soc_dai *dai)
368+
{
369+
struct sdw_cdns *cdns = snd_soc_dai_get_drvdata(dai);
370+
struct sdw_intel *sdw = cdns_to_intel(cdns);
371+
struct sdw_cdns_dai_runtime *dai_runtime;
372+
int ret;
373+
374+
dai_runtime = cdns->dai_runtime_array[dai->id];
375+
if (!dai_runtime)
376+
return -EIO;
377+
378+
/*
379+
* The sdw stream state will transition to RELEASED when stream->
380+
* master_list is empty. So the stream state will transition to
381+
* DEPREPARED for the first cpu-dai and to RELEASED for the last
382+
* cpu-dai.
383+
*/
384+
ret = sdw_stream_remove_master(&cdns->bus, dai_runtime->stream);
385+
if (ret < 0) {
386+
dev_err(dai->dev, "remove master from stream %s failed: %d\n",
387+
dai_runtime->stream->name, ret);
388+
return ret;
389+
}
390+
391+
ret = intel_free_stream(sdw, substream, dai, sdw->instance);
392+
if (ret < 0) {
393+
dev_err(dai->dev, "intel_free_stream: failed %d\n", ret);
394+
return ret;
395+
}
396+
397+
dai_runtime->pdi = NULL;
398+
399+
return 0;
400+
}
401+
402+
static int intel_pcm_set_sdw_stream(struct snd_soc_dai *dai,
403+
void *stream, int direction)
404+
{
405+
return cdns_set_sdw_stream(dai, stream, direction);
406+
}
407+
408+
static void *intel_get_sdw_stream(struct snd_soc_dai *dai,
409+
int direction)
410+
{
411+
struct sdw_cdns *cdns = snd_soc_dai_get_drvdata(dai);
412+
struct sdw_cdns_dai_runtime *dai_runtime;
413+
414+
dai_runtime = cdns->dai_runtime_array[dai->id];
415+
if (!dai_runtime)
416+
return ERR_PTR(-EINVAL);
417+
418+
return dai_runtime->stream;
419+
}
420+
421+
static int intel_trigger(struct snd_pcm_substream *substream, int cmd, struct snd_soc_dai *dai)
422+
{
423+
struct sdw_cdns *cdns = snd_soc_dai_get_drvdata(dai);
424+
struct sdw_intel *sdw = cdns_to_intel(cdns);
425+
struct sdw_intel_link_res *res = sdw->link_res;
426+
struct sdw_cdns_dai_runtime *dai_runtime;
427+
int ret = 0;
428+
429+
/*
430+
* The .trigger callback is used to program HDaudio DMA and send required IPC to audio
431+
* firmware.
432+
*/
433+
if (res->ops && res->ops->trigger) {
434+
ret = res->ops->trigger(substream, cmd, dai);
435+
if (ret < 0)
436+
return ret;
437+
}
438+
439+
dai_runtime = cdns->dai_runtime_array[dai->id];
440+
if (!dai_runtime) {
441+
dev_err(dai->dev, "failed to get dai runtime in %s\n",
442+
__func__);
443+
return -EIO;
444+
}
445+
446+
switch (cmd) {
447+
case SNDRV_PCM_TRIGGER_SUSPEND:
448+
449+
/*
450+
* The .prepare callback is used to deal with xruns and resume operations.
451+
* In the case of xruns, the DMAs and SHIM registers cannot be touched,
452+
* but for resume operations the DMAs and SHIM registers need to be initialized.
453+
* the .trigger callback is used to track the suspend case only.
454+
*/
455+
456+
dai_runtime->suspended = true;
457+
458+
break;
459+
460+
case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
461+
dai_runtime->paused = true;
462+
break;
463+
case SNDRV_PCM_TRIGGER_STOP:
464+
case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
465+
dai_runtime->paused = false;
466+
break;
467+
default:
468+
break;
469+
}
470+
471+
return ret;
472+
}
473+
197474
static const struct snd_soc_dai_ops intel_pcm_dai_ops = {
475+
.hw_params = intel_hw_params,
476+
.prepare = intel_prepare,
477+
.hw_free = intel_hw_free,
478+
.trigger = intel_trigger,
479+
.set_stream = intel_pcm_set_sdw_stream,
480+
.get_stream = intel_get_sdw_stream,
198481
};
199482

200483
static const struct snd_soc_component_driver dai_component = {

0 commit comments

Comments
 (0)