summaryrefslogtreecommitdiff
path: root/drivers/soundwire/intel.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/soundwire/intel.c')
-rw-r--r--drivers/soundwire/intel.c201
1 files changed, 64 insertions, 137 deletions
diff --git a/drivers/soundwire/intel.c b/drivers/soundwire/intel.c
index 13c54eac0cc3..99dc61021211 100644
--- a/drivers/soundwire/intel.c
+++ b/drivers/soundwire/intel.c
@@ -10,6 +10,7 @@
#include <linux/delay.h>
#include <linux/module.h>
#include <linux/interrupt.h>
+#include <linux/io.h>
#include <linux/platform_device.h>
#include <sound/pcm_params.h>
#include <sound/soc.h>
@@ -479,7 +480,10 @@ intel_pdi_shim_configure(struct sdw_intel *sdw, struct sdw_cdns_pdi *pdi)
unsigned int link_id = sdw->instance;
int pdi_conf = 0;
- pdi->intel_alh_id = (link_id * 16) + pdi->num + 5;
+ /* the Bulk and PCM streams are not contiguous */
+ pdi->intel_alh_id = (link_id * 16) + pdi->num + 3;
+ if (pdi->num >= 2)
+ pdi->intel_alh_id += 2;
/*
* Program stream parameters to stream SHIM register
@@ -508,7 +512,10 @@ intel_pdi_alh_configure(struct sdw_intel *sdw, struct sdw_cdns_pdi *pdi)
unsigned int link_id = sdw->instance;
unsigned int conf;
- pdi->intel_alh_id = (link_id * 16) + pdi->num + 5;
+ /* the Bulk and PCM streams are not contiguous */
+ pdi->intel_alh_id = (link_id * 16) + pdi->num + 3;
+ if (pdi->num >= 2)
+ pdi->intel_alh_id += 2;
/* Program Stream config ALH register */
conf = intel_readl(alh, SDW_ALH_STRMZCFG(pdi->intel_alh_id));
@@ -603,66 +610,6 @@ static int intel_post_bank_switch(struct sdw_bus *bus)
* DAI routines
*/
-static struct sdw_cdns_port *intel_alloc_port(struct sdw_intel *sdw,
- u32 ch, u32 dir, bool pcm)
-{
- struct sdw_cdns *cdns = &sdw->cdns;
- struct sdw_cdns_port *port = NULL;
- int i, ret = 0;
-
- for (i = 0; i < cdns->num_ports; i++) {
- if (cdns->ports[i].assigned)
- continue;
-
- port = &cdns->ports[i];
- port->assigned = true;
- port->direction = dir;
- port->ch = ch;
- break;
- }
-
- if (!port) {
- dev_err(cdns->dev, "Unable to find a free port\n");
- return NULL;
- }
-
- if (pcm) {
- ret = sdw_cdns_alloc_stream(cdns, &cdns->pcm, port, ch, dir);
- if (ret)
- goto out;
-
- intel_pdi_shim_configure(sdw, port->pdi);
- sdw_cdns_config_stream(cdns, port, ch, dir, port->pdi);
-
- intel_pdi_alh_configure(sdw, port->pdi);
-
- } else {
- ret = sdw_cdns_alloc_stream(cdns, &cdns->pdm, port, ch, dir);
- }
-
-out:
- if (ret) {
- port->assigned = false;
- port = NULL;
- }
-
- return port;
-}
-
-static void intel_port_cleanup(struct sdw_cdns_dma_data *dma)
-{
- int i;
-
- for (i = 0; i < dma->nr_ports; i++) {
- if (dma->port[i]) {
- dma->port[i]->pdi->assigned = false;
- dma->port[i]->pdi = NULL;
- dma->port[i]->assigned = false;
- dma->port[i] = NULL;
- }
- }
-}
-
static int intel_hw_params(struct snd_pcm_substream *substream,
struct snd_pcm_hw_params *params,
struct snd_soc_dai *dai)
@@ -670,9 +617,11 @@ static int intel_hw_params(struct snd_pcm_substream *substream,
struct sdw_cdns *cdns = snd_soc_dai_get_drvdata(dai);
struct sdw_intel *sdw = cdns_to_intel(cdns);
struct sdw_cdns_dma_data *dma;
+ struct sdw_cdns_pdi *pdi;
struct sdw_stream_config sconfig;
struct sdw_port_config *pconfig;
- int ret, i, ch, dir;
+ int ch, dir;
+ int ret;
bool pcm = true;
dma = snd_soc_dai_get_dma_data(dai, substream);
@@ -685,38 +634,30 @@ static int intel_hw_params(struct snd_pcm_substream *substream,
else
dir = SDW_DATA_DIR_TX;
- if (dma->stream_type == SDW_STREAM_PDM) {
- /* TODO: Check whether PDM decimator is already in use */
- dma->nr_ports = sdw_cdns_get_stream(cdns, &cdns->pdm, ch, dir);
+ if (dma->stream_type == SDW_STREAM_PDM)
pcm = false;
- } else {
- dma->nr_ports = sdw_cdns_get_stream(cdns, &cdns->pcm, ch, dir);
- }
- if (!dma->nr_ports) {
- dev_err(dai->dev, "ports/resources not available\n");
- return -EINVAL;
+ if (pcm)
+ pdi = sdw_cdns_alloc_pdi(cdns, &cdns->pcm, ch, dir, dai->id);
+ else
+ pdi = sdw_cdns_alloc_pdi(cdns, &cdns->pdm, ch, dir, dai->id);
+
+ if (!pdi) {
+ ret = -EINVAL;
+ goto error;
}
- dma->port = kcalloc(dma->nr_ports, sizeof(*dma->port), GFP_KERNEL);
- if (!dma->port)
- return -ENOMEM;
+ /* do run-time configurations for SHIM, ALH and PDI/PORT */
+ intel_pdi_shim_configure(sdw, pdi);
+ intel_pdi_alh_configure(sdw, pdi);
+ sdw_cdns_config_stream(cdns, ch, dir, pdi);
- for (i = 0; i < dma->nr_ports; i++) {
- dma->port[i] = intel_alloc_port(sdw, ch, dir, pcm);
- if (!dma->port[i]) {
- ret = -EINVAL;
- goto port_error;
- }
- }
/* Inform DSP about PDI stream number */
- for (i = 0; i < dma->nr_ports; i++) {
- ret = intel_config_stream(sdw, substream, dai, params,
- dma->port[i]->pdi->intel_alh_id);
- if (ret)
- goto port_error;
- }
+ ret = intel_config_stream(sdw, substream, dai, params,
+ pdi->intel_alh_id);
+ if (ret)
+ goto error;
sconfig.direction = dir;
sconfig.ch_count = ch;
@@ -731,32 +672,22 @@ static int intel_hw_params(struct snd_pcm_substream *substream,
}
/* Port configuration */
- pconfig = kcalloc(dma->nr_ports, sizeof(*pconfig), GFP_KERNEL);
+ pconfig = kcalloc(1, sizeof(*pconfig), GFP_KERNEL);
if (!pconfig) {
ret = -ENOMEM;
- goto port_error;
+ goto error;
}
- for (i = 0; i < dma->nr_ports; i++) {
- pconfig[i].num = dma->port[i]->num;
- pconfig[i].ch_mask = (1 << ch) - 1;
- }
+ pconfig->num = pdi->num;
+ pconfig->ch_mask = (1 << ch) - 1;
ret = sdw_stream_add_master(&cdns->bus, &sconfig,
- pconfig, dma->nr_ports, dma->stream);
- if (ret) {
+ pconfig, 1, dma->stream);
+ if (ret)
dev_err(cdns->dev, "add master to stream failed:%d\n", ret);
- goto stream_error;
- }
kfree(pconfig);
- return ret;
-
-stream_error:
- kfree(pconfig);
-port_error:
- intel_port_cleanup(dma);
- kfree(dma->port);
+error:
return ret;
}
@@ -776,8 +707,6 @@ intel_hw_free(struct snd_pcm_substream *substream, struct snd_soc_dai *dai)
dev_err(dai->dev, "remove master from stream %s failed: %d\n",
dma->stream->name, ret);
- intel_port_cleanup(dma);
- kfree(dma->port);
return ret;
}
@@ -842,14 +771,6 @@ static int intel_create_dai(struct sdw_cdns *cdns,
return -ENOMEM;
if (type == INTEL_PDI_BD || type == INTEL_PDI_OUT) {
- dais[i].playback.stream_name =
- kasprintf(GFP_KERNEL, "SDW%d Tx%d",
- cdns->instance, i);
- if (!dais[i].playback.stream_name) {
- kfree(dais[i].name);
- return -ENOMEM;
- }
-
dais[i].playback.channels_min = 1;
dais[i].playback.channels_max = max_ch;
dais[i].playback.rates = SNDRV_PCM_RATE_48000;
@@ -857,23 +778,12 @@ static int intel_create_dai(struct sdw_cdns *cdns,
}
if (type == INTEL_PDI_BD || type == INTEL_PDI_IN) {
- dais[i].capture.stream_name =
- kasprintf(GFP_KERNEL, "SDW%d Rx%d",
- cdns->instance, i);
- if (!dais[i].capture.stream_name) {
- kfree(dais[i].name);
- kfree(dais[i].playback.stream_name);
- return -ENOMEM;
- }
-
dais[i].capture.channels_min = 1;
dais[i].capture.channels_max = max_ch;
dais[i].capture.rates = SNDRV_PCM_RATE_48000;
dais[i].capture.formats = SNDRV_PCM_FMTBIT_S16_LE;
}
- dais[i].id = SDW_DAI_ID_RANGE_START + i;
-
if (pcm)
dais[i].ops = &intel_pcm_dai_ops;
else
@@ -993,6 +903,15 @@ static struct sdw_master_ops sdw_intel_ops = {
.post_bank_switch = intel_post_bank_switch,
};
+static int intel_init(struct sdw_intel *sdw)
+{
+ /* Initialize shim and controller */
+ intel_link_power_up(sdw);
+ intel_shim_init(sdw);
+
+ return sdw_cdns_init(&sdw->cdns, false);
+}
+
/*
* probe and init
*/
@@ -1026,7 +945,7 @@ static int intel_probe(struct platform_device *pdev)
ret = sdw_add_bus_master(&sdw->cdns.bus);
if (ret) {
dev_err(&pdev->dev, "sdw_add_bus_master fail: %d\n", ret);
- goto err_master_reg;
+ return ret;
}
if (sdw->cdns.bus.prop.hw_disabled) {
@@ -1035,16 +954,11 @@ static int intel_probe(struct platform_device *pdev)
return 0;
}
- /* Initialize shim and controller */
- intel_link_power_up(sdw);
- intel_shim_init(sdw);
-
- ret = sdw_cdns_init(&sdw->cdns);
+ /* Initialize shim, controller and Cadence IP */
+ ret = intel_init(sdw);
if (ret)
goto err_init;
- ret = sdw_cdns_enable_interrupt(&sdw->cdns);
-
/* Read the PDI config and initialize cadence PDI */
intel_pdi_init(sdw, &config);
ret = sdw_cdns_pdi_init(&sdw->cdns, config);
@@ -1062,23 +976,35 @@ static int intel_probe(struct platform_device *pdev)
goto err_init;
}
+ ret = sdw_cdns_enable_interrupt(&sdw->cdns, true);
+ if (ret < 0) {
+ dev_err(sdw->cdns.dev, "cannot enable interrupts\n");
+ goto err_init;
+ }
+
+ ret = sdw_cdns_exit_reset(&sdw->cdns);
+ if (ret < 0) {
+ dev_err(sdw->cdns.dev, "unable to exit bus reset sequence\n");
+ goto err_interrupt;
+ }
+
/* Register DAIs */
ret = intel_register_dai(sdw);
if (ret) {
dev_err(sdw->cdns.dev, "DAI registration failed: %d\n", ret);
snd_soc_unregister_component(sdw->cdns.dev);
- goto err_dai;
+ goto err_interrupt;
}
intel_debugfs_init(sdw);
return 0;
-err_dai:
+err_interrupt:
+ sdw_cdns_enable_interrupt(&sdw->cdns, false);
free_irq(sdw->res->irq, sdw);
err_init:
sdw_delete_bus_master(&sdw->cdns.bus);
-err_master_reg:
return ret;
}
@@ -1090,6 +1016,7 @@ static int intel_remove(struct platform_device *pdev)
if (!sdw->cdns.bus.prop.hw_disabled) {
intel_debugfs_exit(sdw);
+ sdw_cdns_enable_interrupt(&sdw->cdns, false);
free_irq(sdw->res->irq, sdw);
snd_soc_unregister_component(sdw->cdns.dev);
}