Commit a61ead03 authored by Greg Kroah-Hartman's avatar Greg Kroah-Hartman

Merge tag 'soundwire-5.5-rc1' of...

Merge tag 'soundwire-5.5-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/vkoul/soundwire into char-misc-next

Vinod writes:

soundwire updates for v5.5-rc1

This round we have bunch of core and Intel driver updates spearheaded
by Pierre

Details
 - Update unique id checks in core and ACPI helpers
 - Improvements to to Intel driver and cadence lib

* tag 'soundwire-5.5-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/vkoul/soundwire:
  soundwire: ignore uniqueID when irrelevant
  soundwire: slave: add helper to extract slave ID
  soundwire: remove bitfield for unique_id, use u8
  soundwire: intel: fix PDI/stream mapping for Bulk
  soundwire: cadence_master: make clock stop exit configurable on init
  soundwire: intel/cadence: add flag for interrupt enable
  soundwire: intel: add helper for initialization
  soundwire: cadence_master: add hw_reset capability in debugfs
  soundwire: intel/cadence: fix startup sequence
  soundwire: intel: use correct header for io calls
  soundwire: cadence_master: improve PDI allocation
  soundwire: intel: don't filter out PDI0/1
  soundwire: cadence/intel: simplify PDI/port mapping
  soundwire: intel: remove playback/capture stream_name
  soundwire: remove DAI_ID_RANGE definitions
  soundwire: intel: remove X86 dependency
  soundwire: intel: add missing headers for cross-compilation
parents bce92136 2e8c4ad1
...@@ -23,7 +23,7 @@ config SOUNDWIRE_CADENCE ...@@ -23,7 +23,7 @@ config SOUNDWIRE_CADENCE
config SOUNDWIRE_INTEL config SOUNDWIRE_INTEL
tristate "Intel SoundWire Master driver" tristate "Intel SoundWire Master driver"
select SOUNDWIRE_CADENCE select SOUNDWIRE_CADENCE
depends on X86 && ACPI && SND_SOC depends on ACPI && SND_SOC
help help
SoundWire Intel Master driver. SoundWire Intel Master driver.
If you have an Intel platform which has a SoundWire Master then If you have an Intel platform which has a SoundWire Master then
......
...@@ -422,10 +422,11 @@ static struct sdw_slave *sdw_get_slave(struct sdw_bus *bus, int i) ...@@ -422,10 +422,11 @@ static struct sdw_slave *sdw_get_slave(struct sdw_bus *bus, int i)
static int sdw_compare_devid(struct sdw_slave *slave, struct sdw_slave_id id) static int sdw_compare_devid(struct sdw_slave *slave, struct sdw_slave_id id)
{ {
if (slave->id.unique_id != id.unique_id || if (slave->id.mfg_id != id.mfg_id ||
slave->id.mfg_id != id.mfg_id ||
slave->id.part_id != id.part_id || slave->id.part_id != id.part_id ||
slave->id.class_id != id.class_id) slave->id.class_id != id.class_id ||
(slave->id.unique_id != SDW_IGNORED_UNIQUE_ID &&
slave->id.unique_id != id.unique_id))
return -ENODEV; return -ENODEV;
return 0; return 0;
......
This diff is collapsed.
...@@ -8,7 +8,6 @@ ...@@ -8,7 +8,6 @@
/** /**
* struct sdw_cdns_pdi: PDI (Physical Data Interface) instance * struct sdw_cdns_pdi: PDI (Physical Data Interface) instance
* *
* @assigned: pdi assigned
* @num: pdi number * @num: pdi number
* @intel_alh_id: link identifier * @intel_alh_id: link identifier
* @l_ch_num: low channel for PDI * @l_ch_num: low channel for PDI
...@@ -18,7 +17,6 @@ ...@@ -18,7 +17,6 @@
* @type: stream type, PDM or PCM * @type: stream type, PDM or PCM
*/ */
struct sdw_cdns_pdi { struct sdw_cdns_pdi {
bool assigned;
int num; int num;
int intel_alh_id; int intel_alh_id;
int l_ch_num; int l_ch_num;
...@@ -28,23 +26,6 @@ struct sdw_cdns_pdi { ...@@ -28,23 +26,6 @@ struct sdw_cdns_pdi {
enum sdw_stream_type type; enum sdw_stream_type type;
}; };
/**
* struct sdw_cdns_port: Cadence port structure
*
* @num: port number
* @assigned: port assigned
* @ch: channel count
* @direction: data port direction
* @pdi: pdi for this port
*/
struct sdw_cdns_port {
unsigned int num;
bool assigned;
unsigned int ch;
enum sdw_data_direction direction;
struct sdw_cdns_pdi *pdi;
};
/** /**
* struct sdw_cdns_streams: Cadence stream data structure * struct sdw_cdns_streams: Cadence stream data structure
* *
...@@ -95,8 +76,8 @@ struct sdw_cdns_stream_config { ...@@ -95,8 +76,8 @@ struct sdw_cdns_stream_config {
* struct sdw_cdns_dma_data: Cadence DMA data * struct sdw_cdns_dma_data: Cadence DMA data
* *
* @name: SoundWire stream name * @name: SoundWire stream name
* @nr_ports: Number of ports * @stream: stream runtime
* @port: Ports * @pdi: PDI used for this dai
* @bus: Bus handle * @bus: Bus handle
* @stream_type: Stream type * @stream_type: Stream type
* @link_id: Master link id * @link_id: Master link id
...@@ -104,8 +85,7 @@ struct sdw_cdns_stream_config { ...@@ -104,8 +85,7 @@ struct sdw_cdns_stream_config {
struct sdw_cdns_dma_data { struct sdw_cdns_dma_data {
char *name; char *name;
struct sdw_stream_runtime *stream; struct sdw_stream_runtime *stream;
int nr_ports; struct sdw_cdns_pdi *pdi;
struct sdw_cdns_port **port;
struct sdw_bus *bus; struct sdw_bus *bus;
enum sdw_stream_type stream_type; enum sdw_stream_type stream_type;
int link_id; int link_id;
...@@ -158,10 +138,11 @@ extern struct sdw_master_ops sdw_cdns_master_ops; ...@@ -158,10 +138,11 @@ extern struct sdw_master_ops sdw_cdns_master_ops;
irqreturn_t sdw_cdns_irq(int irq, void *dev_id); irqreturn_t sdw_cdns_irq(int irq, void *dev_id);
irqreturn_t sdw_cdns_thread(int irq, void *dev_id); irqreturn_t sdw_cdns_thread(int irq, void *dev_id);
int sdw_cdns_init(struct sdw_cdns *cdns); int sdw_cdns_init(struct sdw_cdns *cdns, bool clock_stop_exit);
int sdw_cdns_pdi_init(struct sdw_cdns *cdns, int sdw_cdns_pdi_init(struct sdw_cdns *cdns,
struct sdw_cdns_stream_config config); struct sdw_cdns_stream_config config);
int sdw_cdns_enable_interrupt(struct sdw_cdns *cdns); int sdw_cdns_exit_reset(struct sdw_cdns *cdns);
int sdw_cdns_enable_interrupt(struct sdw_cdns *cdns, bool state);
#ifdef CONFIG_DEBUG_FS #ifdef CONFIG_DEBUG_FS
void sdw_cdns_debugfs_init(struct sdw_cdns *cdns, struct dentry *root); void sdw_cdns_debugfs_init(struct sdw_cdns *cdns, struct dentry *root);
...@@ -170,10 +151,10 @@ void sdw_cdns_debugfs_init(struct sdw_cdns *cdns, struct dentry *root); ...@@ -170,10 +151,10 @@ void sdw_cdns_debugfs_init(struct sdw_cdns *cdns, struct dentry *root);
int sdw_cdns_get_stream(struct sdw_cdns *cdns, int sdw_cdns_get_stream(struct sdw_cdns *cdns,
struct sdw_cdns_streams *stream, struct sdw_cdns_streams *stream,
u32 ch, u32 dir); u32 ch, u32 dir);
int sdw_cdns_alloc_stream(struct sdw_cdns *cdns, struct sdw_cdns_pdi *sdw_cdns_alloc_pdi(struct sdw_cdns *cdns,
struct sdw_cdns_streams *stream, struct sdw_cdns_streams *stream,
struct sdw_cdns_port *port, u32 ch, u32 dir); u32 ch, u32 dir, int dai_id);
void sdw_cdns_config_stream(struct sdw_cdns *cdns, struct sdw_cdns_port *port, void sdw_cdns_config_stream(struct sdw_cdns *cdns,
u32 ch, u32 dir, struct sdw_cdns_pdi *pdi); u32 ch, u32 dir, struct sdw_cdns_pdi *pdi);
int sdw_cdns_pcm_set_stream(struct snd_soc_dai *dai, int sdw_cdns_pcm_set_stream(struct snd_soc_dai *dai,
......
...@@ -10,6 +10,7 @@ ...@@ -10,6 +10,7 @@
#include <linux/delay.h> #include <linux/delay.h>
#include <linux/module.h> #include <linux/module.h>
#include <linux/interrupt.h> #include <linux/interrupt.h>
#include <linux/io.h>
#include <linux/platform_device.h> #include <linux/platform_device.h>
#include <sound/pcm_params.h> #include <sound/pcm_params.h>
#include <sound/soc.h> #include <sound/soc.h>
...@@ -479,7 +480,10 @@ intel_pdi_shim_configure(struct sdw_intel *sdw, struct sdw_cdns_pdi *pdi) ...@@ -479,7 +480,10 @@ intel_pdi_shim_configure(struct sdw_intel *sdw, struct sdw_cdns_pdi *pdi)
unsigned int link_id = sdw->instance; unsigned int link_id = sdw->instance;
int pdi_conf = 0; 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 * Program stream parameters to stream SHIM register
...@@ -508,7 +512,10 @@ intel_pdi_alh_configure(struct sdw_intel *sdw, struct sdw_cdns_pdi *pdi) ...@@ -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 link_id = sdw->instance;
unsigned int conf; 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 */ /* Program Stream config ALH register */
conf = intel_readl(alh, SDW_ALH_STRMZCFG(pdi->intel_alh_id)); 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) ...@@ -603,66 +610,6 @@ static int intel_post_bank_switch(struct sdw_bus *bus)
* DAI routines * 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, static int intel_hw_params(struct snd_pcm_substream *substream,
struct snd_pcm_hw_params *params, struct snd_pcm_hw_params *params,
struct snd_soc_dai *dai) struct snd_soc_dai *dai)
...@@ -670,9 +617,11 @@ static int intel_hw_params(struct snd_pcm_substream *substream, ...@@ -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_cdns *cdns = snd_soc_dai_get_drvdata(dai);
struct sdw_intel *sdw = cdns_to_intel(cdns); struct sdw_intel *sdw = cdns_to_intel(cdns);
struct sdw_cdns_dma_data *dma; struct sdw_cdns_dma_data *dma;
struct sdw_cdns_pdi *pdi;
struct sdw_stream_config sconfig; struct sdw_stream_config sconfig;
struct sdw_port_config *pconfig; struct sdw_port_config *pconfig;
int ret, i, ch, dir; int ch, dir;
int ret;
bool pcm = true; bool pcm = true;
dma = snd_soc_dai_get_dma_data(dai, substream); dma = snd_soc_dai_get_dma_data(dai, substream);
...@@ -685,38 +634,30 @@ static int intel_hw_params(struct snd_pcm_substream *substream, ...@@ -685,38 +634,30 @@ static int intel_hw_params(struct snd_pcm_substream *substream,
else else
dir = SDW_DATA_DIR_TX; dir = SDW_DATA_DIR_TX;
if (dma->stream_type == SDW_STREAM_PDM) { 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);
pcm = false; pcm = false;
} else {
dma->nr_ports = sdw_cdns_get_stream(cdns, &cdns->pcm, ch, dir);
}
if (!dma->nr_ports) { if (pcm)
dev_err(dai->dev, "ports/resources not available\n"); pdi = sdw_cdns_alloc_pdi(cdns, &cdns->pcm, ch, dir, dai->id);
return -EINVAL; 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); /* do run-time configurations for SHIM, ALH and PDI/PORT */
if (!dma->port) intel_pdi_shim_configure(sdw, pdi);
return -ENOMEM; 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 */ /* Inform DSP about PDI stream number */
for (i = 0; i < dma->nr_ports; i++) { ret = intel_config_stream(sdw, substream, dai, params,
ret = intel_config_stream(sdw, substream, dai, params, pdi->intel_alh_id);
dma->port[i]->pdi->intel_alh_id); if (ret)
if (ret) goto error;
goto port_error;
}
sconfig.direction = dir; sconfig.direction = dir;
sconfig.ch_count = ch; sconfig.ch_count = ch;
...@@ -731,32 +672,22 @@ static int intel_hw_params(struct snd_pcm_substream *substream, ...@@ -731,32 +672,22 @@ static int intel_hw_params(struct snd_pcm_substream *substream,
} }
/* Port configuration */ /* Port configuration */
pconfig = kcalloc(dma->nr_ports, sizeof(*pconfig), GFP_KERNEL); pconfig = kcalloc(1, sizeof(*pconfig), GFP_KERNEL);
if (!pconfig) { if (!pconfig) {
ret = -ENOMEM; ret = -ENOMEM;
goto port_error; goto error;
} }
for (i = 0; i < dma->nr_ports; i++) { pconfig->num = pdi->num;
pconfig[i].num = dma->port[i]->num; pconfig->ch_mask = (1 << ch) - 1;
pconfig[i].ch_mask = (1 << ch) - 1;
}
ret = sdw_stream_add_master(&cdns->bus, &sconfig, ret = sdw_stream_add_master(&cdns->bus, &sconfig,
pconfig, dma->nr_ports, dma->stream); pconfig, 1, dma->stream);
if (ret) { if (ret)
dev_err(cdns->dev, "add master to stream failed:%d\n", ret); dev_err(cdns->dev, "add master to stream failed:%d\n", ret);
goto stream_error;
}
kfree(pconfig); kfree(pconfig);
return ret; error:
stream_error:
kfree(pconfig);
port_error:
intel_port_cleanup(dma);
kfree(dma->port);
return ret; return ret;
} }
...@@ -776,8 +707,6 @@ intel_hw_free(struct snd_pcm_substream *substream, struct snd_soc_dai *dai) ...@@ -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", dev_err(dai->dev, "remove master from stream %s failed: %d\n",
dma->stream->name, ret); dma->stream->name, ret);
intel_port_cleanup(dma);
kfree(dma->port);
return ret; return ret;
} }
...@@ -842,14 +771,6 @@ static int intel_create_dai(struct sdw_cdns *cdns, ...@@ -842,14 +771,6 @@ static int intel_create_dai(struct sdw_cdns *cdns,
return -ENOMEM; return -ENOMEM;
if (type == INTEL_PDI_BD || type == INTEL_PDI_OUT) { 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_min = 1;
dais[i].playback.channels_max = max_ch; dais[i].playback.channels_max = max_ch;
dais[i].playback.rates = SNDRV_PCM_RATE_48000; dais[i].playback.rates = SNDRV_PCM_RATE_48000;
...@@ -857,23 +778,12 @@ static int intel_create_dai(struct sdw_cdns *cdns, ...@@ -857,23 +778,12 @@ static int intel_create_dai(struct sdw_cdns *cdns,
} }
if (type == INTEL_PDI_BD || type == INTEL_PDI_IN) { 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_min = 1;
dais[i].capture.channels_max = max_ch; dais[i].capture.channels_max = max_ch;
dais[i].capture.rates = SNDRV_PCM_RATE_48000; dais[i].capture.rates = SNDRV_PCM_RATE_48000;
dais[i].capture.formats = SNDRV_PCM_FMTBIT_S16_LE; dais[i].capture.formats = SNDRV_PCM_FMTBIT_S16_LE;
} }
dais[i].id = SDW_DAI_ID_RANGE_START + i;
if (pcm) if (pcm)
dais[i].ops = &intel_pcm_dai_ops; dais[i].ops = &intel_pcm_dai_ops;
else else
...@@ -993,6 +903,15 @@ static struct sdw_master_ops sdw_intel_ops = { ...@@ -993,6 +903,15 @@ static struct sdw_master_ops sdw_intel_ops = {
.post_bank_switch = intel_post_bank_switch, .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 * probe and init
*/ */
...@@ -1026,7 +945,7 @@ static int intel_probe(struct platform_device *pdev) ...@@ -1026,7 +945,7 @@ static int intel_probe(struct platform_device *pdev)
ret = sdw_add_bus_master(&sdw->cdns.bus); ret = sdw_add_bus_master(&sdw->cdns.bus);
if (ret) { if (ret) {
dev_err(&pdev->dev, "sdw_add_bus_master fail: %d\n", 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) { if (sdw->cdns.bus.prop.hw_disabled) {
...@@ -1035,16 +954,11 @@ static int intel_probe(struct platform_device *pdev) ...@@ -1035,16 +954,11 @@ static int intel_probe(struct platform_device *pdev)
return 0; return 0;
} }
/* Initialize shim and controller */ /* Initialize shim, controller and Cadence IP */
intel_link_power_up(sdw); ret = intel_init(sdw);
intel_shim_init(sdw);
ret = sdw_cdns_init(&sdw->cdns);
if (ret) if (ret)
goto err_init; goto err_init;
ret = sdw_cdns_enable_interrupt(&sdw->cdns);
/* Read the PDI config and initialize cadence PDI */ /* Read the PDI config and initialize cadence PDI */
intel_pdi_init(sdw, &config); intel_pdi_init(sdw, &config);
ret = sdw_cdns_pdi_init(&sdw->cdns, config); ret = sdw_cdns_pdi_init(&sdw->cdns, config);
...@@ -1062,23 +976,35 @@ static int intel_probe(struct platform_device *pdev) ...@@ -1062,23 +976,35 @@ static int intel_probe(struct platform_device *pdev)
goto err_init; 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 */ /* Register DAIs */
ret = intel_register_dai(sdw); ret = intel_register_dai(sdw);
if (ret) { if (ret) {
dev_err(sdw->cdns.dev, "DAI registration failed: %d\n", ret); dev_err(sdw->cdns.dev, "DAI registration failed: %d\n", ret);
snd_soc_unregister_component(sdw->cdns.dev); snd_soc_unregister_component(sdw->cdns.dev);
goto err_dai; goto err_interrupt;
} }
intel_debugfs_init(sdw); intel_debugfs_init(sdw);
return 0; return 0;
err_dai: err_interrupt:
sdw_cdns_enable_interrupt(&sdw->cdns, false);
free_irq(sdw->res->irq, sdw); free_irq(sdw->res->irq, sdw);
err_init: err_init:
sdw_delete_bus_master(&sdw->cdns.bus); sdw_delete_bus_master(&sdw->cdns.bus);
err_master_reg:
return ret; return ret;
} }
...@@ -1090,6 +1016,7 @@ static int intel_remove(struct platform_device *pdev) ...@@ -1090,6 +1016,7 @@ static int intel_remove(struct platform_device *pdev)
if (!sdw->cdns.bus.prop.hw_disabled) { if (!sdw->cdns.bus.prop.hw_disabled) {
intel_debugfs_exit(sdw); intel_debugfs_exit(sdw);
sdw_cdns_enable_interrupt(&sdw->cdns, false);
free_irq(sdw->res->irq, sdw); free_irq(sdw->res->irq, sdw);
snd_soc_unregister_component(sdw->cdns.dev); snd_soc_unregister_component(sdw->cdns.dev);
} }
......
...@@ -9,6 +9,7 @@ ...@@ -9,6 +9,7 @@
#include <linux/acpi.h> #include <linux/acpi.h>
#include <linux/export.h> #include <linux/export.h>
#include <linux/io.h>
#include <linux/module.h> #include <linux/module.h>
#include <linux/platform_device.h> #include <linux/platform_device.h>
#include <linux/soundwire/sdw_intel.h> #include <linux/soundwire/sdw_intel.h>
......
...@@ -29,10 +29,17 @@ static int sdw_slave_add(struct sdw_bus *bus, ...@@ -29,10 +29,17 @@ static int sdw_slave_add(struct sdw_bus *bus,
slave->dev.parent = bus->dev; slave->dev.parent = bus->dev;
slave->dev.fwnode = fwnode; slave->dev.fwnode = fwnode;
/* name shall be sdw:link:mfg:part:class:unique */ if (id->unique_id == SDW_IGNORED_UNIQUE_ID) {
dev_set_name(&slave->dev, "sdw:%x:%x:%x:%x:%x", /* name shall be sdw:link:mfg:part:class */
bus->link_id, id->mfg_id, id->part_id, dev_set_name(&slave->dev, "sdw:%x:%x:%x:%x",
id->class_id, id->unique_id); bus->link_id, id->mfg_id, id->part_id,
id->class_id);
} else {
/* name shall be sdw:link:mfg:part:class:unique */
dev_set_name(&slave->dev, "sdw:%x:%x:%x:%x:%x",
bus->link_id, id->mfg_id, id->part_id,
id->class_id, id->unique_id);
}
slave->dev.release = sdw_slave_release; slave->dev.release = sdw_slave_release;
slave->dev.bus = &sdw_bus_type; slave->dev.bus = &sdw_bus_type;
...@@ -64,6 +71,36 @@ static int sdw_slave_add(struct sdw_bus *bus, ...@@ -64,6 +71,36 @@ static int sdw_slave_add(struct sdw_bus *bus,
} }
#if IS_ENABLED(CONFIG_ACPI) #if IS_ENABLED(CONFIG_ACPI)
static bool find_slave(struct sdw_bus *bus,
struct acpi_device *adev,
struct sdw_slave_id *id)
{
unsigned long long addr;
unsigned int link_id;
acpi_status status;
status = acpi_evaluate_integer(adev->handle,
METHOD_NAME__ADR, NULL, &addr);
if (ACPI_FAILURE(status)) {
dev_err(bus->dev, "_ADR resolution failed: %x\n",
status);
return false;
}
/* Extract link id from ADR, Bit 51 to 48 (included) */
link_id = (addr >> 48) & GENMASK(3, 0);
/* Check for link_id match */
if (link_id != bus->link_id)
return false;
sdw_extract_slave_id(bus, addr, id);
return true;
}
/* /*
* sdw_acpi_find_slaves() - Find Slave devices in Master ACPI node * sdw_acpi_find_slaves() - Find Slave devices in Master ACPI node
* @bus: SDW bus instance * @bus: SDW bus instance
...@@ -73,6 +110,7 @@ static int sdw_slave_add(struct sdw_bus *bus, ...@@ -73,6 +110,7 @@ static int sdw_slave_add(struct sdw_bus *bus,
int sdw_acpi_find_slaves(struct sdw_bus *bus) int sdw_acpi_find_slaves(struct sdw_bus *bus)
{ {
struct acpi_device *adev, *parent; struct acpi_device *adev, *parent;
struct acpi_device *adev2, *parent2;
parent = ACPI_COMPANION(bus->dev); parent = ACPI_COMPANION(bus->dev);
if (!parent) { if (!parent) {
...@@ -81,28 +119,46 @@ int sdw_acpi_find_slaves(struct sdw_bus *bus) ...@@ -81,28 +119,46 @@ int sdw_acpi_find_slaves(struct sdw_bus *bus)
} }
list_for_each_entry(adev, &parent->children, node) { list_for_each_entry(adev, &parent->children, node) {
unsigned long long addr;
struct sdw_slave_id id; struct sdw_slave_id id;
unsigned int link_id; struct sdw_slave_id id2;
acpi_status status; bool ignore_unique_id = true;
status = acpi_evaluate_integer(adev->handle, if (!find_slave(bus, adev, &id))
METHOD_NAME__ADR, NULL, &addr); continue;
if (ACPI_FAILURE(status)) { /* brute-force O(N^2) search for duplicates */
dev_err(bus->dev, "_ADR resolution failed: %x\n", parent2 = parent;
status); list_for_each_entry(adev2, &parent2->children, node) {
return status;
if (adev == adev2)
continue;
if (!find_slave(bus, adev2, &id2))
continue;
if (id.sdw_version != id2.sdw_version ||
id.mfg_id != id2.mfg_id ||
id.part_id != id2.part_id ||
id.class_id != id2.class_id)
continue;
if (id.unique_id != id2.unique_id) {
dev_dbg(bus->dev,
"Valid unique IDs %x %x for Slave mfg %x part %d\n",
id.unique_id, id2.unique_id,
id.mfg_id, id.part_id);
ignore_unique_id = false;
} else {
dev_err(bus->dev,
"Invalid unique IDs %x %x for Slave mfg %x part %d\n",
id.unique_id, id2.unique_id,
id.mfg_id, id.part_id);
return -ENODEV;
}
} }
/* Extract link id from ADR, Bit 51 to 48 (included) */ if (ignore_unique_id)
link_id = (addr >> 48) & GENMASK(3, 0); id.unique_id = SDW_IGNORED_UNIQUE_ID;
/* Check for link_id match */
if (link_id != bus->link_id)
continue;
sdw_extract_slave_id(bus, addr, &id);
/* /*
* don't error check for sdw_slave_add as we want to continue * don't error check for sdw_slave_add as we want to continue
......
...@@ -40,9 +40,6 @@ struct sdw_slave; ...@@ -40,9 +40,6 @@ struct sdw_slave;
#define SDW_VALID_PORT_RANGE(n) ((n) <= 14 && (n) >= 1) #define SDW_VALID_PORT_RANGE(n) ((n) <= 14 && (n) >= 1)
#define SDW_DAI_ID_RANGE_START 100
#define SDW_DAI_ID_RANGE_END 200
enum { enum {
SDW_PORT_DIRN_SINK = 0, SDW_PORT_DIRN_SINK = 0,
SDW_PORT_DIRN_SOURCE, SDW_PORT_DIRN_SOURCE,
...@@ -406,6 +403,8 @@ int sdw_slave_read_prop(struct sdw_slave *slave); ...@@ -406,6 +403,8 @@ int sdw_slave_read_prop(struct sdw_slave *slave);
* SDW Slave Structures and APIs * SDW Slave Structures and APIs
*/ */
#define SDW_IGNORED_UNIQUE_ID 0xFF
/** /**
* struct sdw_slave_id - Slave ID * struct sdw_slave_id - Slave ID
* @mfg_id: MIPI Manufacturer ID * @mfg_id: MIPI Manufacturer ID
...@@ -421,7 +420,7 @@ struct sdw_slave_id { ...@@ -421,7 +420,7 @@ struct sdw_slave_id {
__u16 mfg_id; __u16 mfg_id;
__u16 part_id; __u16 part_id;
__u8 class_id; __u8 class_id;
__u8 unique_id:4; __u8 unique_id;
__u8 sdw_version:4; __u8 sdw_version:4;
}; };
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment