Skip to content

Commit

Permalink
Merge tag 'soundwire-5.9-rc1' of git://git.kernel.org/pub/scm/linux/k…
Browse files Browse the repository at this point in the history
…ernel/git/vkoul/soundwire into char-misc-next

Vinod writes:

soundwire updates for 5.9-rc1

This contains few core changes and bunch of Intel driver updates:

 - Adds definitions for 1.2 spec
 - Sanyog left as a MAINTAINER and Bard took his place while Sanyog
   is a reviewer now.
 - Intel: Lots of updates to stream/dai handling, wake support and link
   synchronization.

* tag 'soundwire-5.9-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/vkoul/soundwire: (31 commits)
  Soundwire: intel_init: save Slave(s) _ADR info in sdw_intel_ctx
  soundwire: intel: add wake interrupt support
  soundwire: intel/cadence: merge Soundwire interrupt handlers/threads
  soundwire: intel_init: use EXPORT_SYMBOL_NS
  soundwire: intel_init: add implementation of sdw_intel_enable_irq()
  soundwire: intel: introduce helper for link synchronization
  soundwire: intel: introduce a helper to arm link synchronization
  soundwire: intel: revisit SHIM programming sequences.
  soundwire: intel: reuse code for wait loops to set/clear bits
  soundwire: fix the kernel-doc comment
  soundwire: sdw.h: fix indentation
  soundwire: sdw.h: fix PRBS/Static_1 swapped definitions
  soundwire: intel: don't free dma_data in DAI shutdown
  soundwire: cadence: allocate/free dma_data in set_sdw_stream
  soundwire: intel: remove stream allocation/free
  soundwire: stream: add helper to startup/shutdown streams
  soundwire: intel: implement get_sdw_stream() operations
  MAINTAINERS: change SoundWire maintainer
  soundwire: bus: initialize bus clock base and scale registers
  soundwire: extend SDW_SLAVE_ENTRY
  ...
  • Loading branch information
Greg Kroah-Hartman committed Jul 23, 2020
2 parents 7a4462a + a818440 commit 575ec5e
Show file tree
Hide file tree
Showing 18 changed files with 1,136 additions and 302 deletions.
11 changes: 10 additions & 1 deletion Documentation/driver-api/soundwire/stream.rst
Original file line number Diff line number Diff line change
Expand Up @@ -293,6 +293,10 @@ per stream. From ASoC DPCM framework, this stream state maybe linked to
int sdw_alloc_stream(char * stream_name);
The SoundWire core provides a sdw_startup_stream() helper function,
typically called during a dailink .startup() callback, which performs
stream allocation and sets the stream pointer for all DAIs
connected to a stream.

SDW_STREAM_CONFIGURED
~~~~~~~~~~~~~~~~~~~~~
Expand Down Expand Up @@ -509,7 +513,12 @@ In .shutdown() the data structure maintaining stream state are freed up.
void sdw_release_stream(struct sdw_stream_runtime * stream);
Not Supported
The SoundWire core provides a sdw_shutdown_stream() helper function,
typically called during a dailink .shutdown() callback, which clears
the stream pointer for all DAIS connected to a stream and releases the
memory allocated for the stream.

Not Supported
=============

1. A single port with multiple channels supported cannot be used between two
Expand Down
3 changes: 2 additions & 1 deletion MAINTAINERS
Original file line number Diff line number Diff line change
Expand Up @@ -16014,8 +16014,9 @@ F: sound/soc/sof/

SOUNDWIRE SUBSYSTEM
M: Vinod Koul <vkoul@kernel.org>
M: Sanyog Kale <sanyog.r.kale@intel.com>
M: Bard Liao <yung-chuan.liao@linux.intel.com>
R: Pierre-Louis Bossart <pierre-louis.bossart@linux.intel.com>
R: Sanyog Kale <sanyog.r.kale@intel.com>
L: alsa-devel@alsa-project.org (moderated for non-subscribers)
S: Supported
F: Documentation/driver-api/soundwire/
Expand Down
10 changes: 5 additions & 5 deletions drivers/soundwire/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -4,22 +4,22 @@
#

#Bus Objs
soundwire-bus-objs := bus_type.o bus.o master.o slave.o mipi_disco.o stream.o \
soundwire-bus-y := bus_type.o bus.o master.o slave.o mipi_disco.o stream.o \
sysfs_slave.o sysfs_slave_dpn.o
obj-$(CONFIG_SOUNDWIRE) += soundwire-bus.o

ifdef CONFIG_DEBUG_FS
soundwire-bus-objs += debugfs.o
soundwire-bus-y += debugfs.o
endif

#Cadence Objs
soundwire-cadence-objs := cadence_master.o
soundwire-cadence-y := cadence_master.o
obj-$(CONFIG_SOUNDWIRE_CADENCE) += soundwire-cadence.o

#Intel driver
soundwire-intel-objs := intel.o intel_init.o
soundwire-intel-y := intel.o intel_init.o
obj-$(CONFIG_SOUNDWIRE_INTEL) += soundwire-intel.o

#Qualcomm driver
soundwire-qcom-objs := qcom.o
soundwire-qcom-y := qcom.o
obj-$(CONFIG_SOUNDWIRE_QCOM) += soundwire-qcom.o
130 changes: 124 additions & 6 deletions drivers/soundwire/bus.c
Original file line number Diff line number Diff line change
Expand Up @@ -863,13 +863,13 @@ int sdw_bus_prep_clk_stop(struct sdw_bus *bus)
if (!slave->dev_num)
continue;

/* Identify if Slave(s) are available on Bus */
is_slave = true;

if (slave->status != SDW_SLAVE_ATTACHED &&
slave->status != SDW_SLAVE_ALERT)
continue;

/* Identify if Slave(s) are available on Bus */
is_slave = true;

slave_mode = sdw_get_clk_stop_mode(slave);
slave->curr_clk_stop_mode = slave_mode;

Expand Down Expand Up @@ -900,6 +900,10 @@ int sdw_bus_prep_clk_stop(struct sdw_bus *bus)
return ret;
}

/* Don't need to inform slaves if there is no slave attached */
if (!is_slave)
return ret;

/* Inform slaves that prep is done */
list_for_each_entry(slave, &bus->slaves, node) {
if (!slave->dev_num)
Expand Down Expand Up @@ -985,13 +989,13 @@ int sdw_bus_exit_clk_stop(struct sdw_bus *bus)
if (!slave->dev_num)
continue;

/* Identify if Slave(s) are available on Bus */
is_slave = true;

if (slave->status != SDW_SLAVE_ATTACHED &&
slave->status != SDW_SLAVE_ALERT)
continue;

/* Identify if Slave(s) are available on Bus */
is_slave = true;

mode = slave->curr_clk_stop_mode;

if (mode == SDW_CLK_STOP_MODE1) {
Expand All @@ -1016,6 +1020,13 @@ int sdw_bus_exit_clk_stop(struct sdw_bus *bus)
if (is_slave && !simple_clk_stop)
sdw_bus_wait_for_clk_prep_deprep(bus, SDW_BROADCAST_DEV_NUM);

/*
* Don't need to call slave callback function if there is no slave
* attached
*/
if (!is_slave)
return 0;

list_for_each_entry(slave, &bus->slaves, node) {
if (!slave->dev_num)
continue;
Expand Down Expand Up @@ -1059,12 +1070,119 @@ int sdw_configure_dpn_intr(struct sdw_slave *slave,
return ret;
}

static int sdw_slave_set_frequency(struct sdw_slave *slave)
{
u32 mclk_freq = slave->bus->prop.mclk_freq;
u32 curr_freq = slave->bus->params.curr_dr_freq >> 1;
unsigned int scale;
u8 scale_index;
u8 base;
int ret;

/*
* frequency base and scale registers are required for SDCA
* devices. They may also be used for 1.2+/non-SDCA devices,
* but we will need a DisCo property to cover this case
*/
if (!slave->id.class_id)
return 0;

if (!mclk_freq) {
dev_err(&slave->dev,
"no bus MCLK, cannot set SDW_SCP_BUS_CLOCK_BASE\n");
return -EINVAL;
}

/*
* map base frequency using Table 89 of SoundWire 1.2 spec.
* The order of the tests just follows the specification, this
* is not a selection between possible values or a search for
* the best value but just a mapping. Only one case per platform
* is relevant.
* Some BIOS have inconsistent values for mclk_freq but a
* correct root so we force the mclk_freq to avoid variations.
*/
if (!(19200000 % mclk_freq)) {
mclk_freq = 19200000;
base = SDW_SCP_BASE_CLOCK_19200000_HZ;
} else if (!(24000000 % mclk_freq)) {
mclk_freq = 24000000;
base = SDW_SCP_BASE_CLOCK_24000000_HZ;
} else if (!(24576000 % mclk_freq)) {
mclk_freq = 24576000;
base = SDW_SCP_BASE_CLOCK_24576000_HZ;
} else if (!(22579200 % mclk_freq)) {
mclk_freq = 22579200;
base = SDW_SCP_BASE_CLOCK_22579200_HZ;
} else if (!(32000000 % mclk_freq)) {
mclk_freq = 32000000;
base = SDW_SCP_BASE_CLOCK_32000000_HZ;
} else {
dev_err(&slave->dev,
"Unsupported clock base, mclk %d\n",
mclk_freq);
return -EINVAL;
}

if (mclk_freq % curr_freq) {
dev_err(&slave->dev,
"mclk %d is not multiple of bus curr_freq %d\n",
mclk_freq, curr_freq);
return -EINVAL;
}

scale = mclk_freq / curr_freq;

/*
* map scale to Table 90 of SoundWire 1.2 spec - and check
* that the scale is a power of two and maximum 64
*/
scale_index = ilog2(scale);

if (BIT(scale_index) != scale || scale_index > 6) {
dev_err(&slave->dev,
"No match found for scale %d, bus mclk %d curr_freq %d\n",
scale, mclk_freq, curr_freq);
return -EINVAL;
}
scale_index++;

ret = sdw_write(slave, SDW_SCP_BUS_CLOCK_BASE, base);
if (ret < 0) {
dev_err(&slave->dev,
"SDW_SCP_BUS_CLOCK_BASE write failed:%d\n", ret);
return ret;
}

/* initialize scale for both banks */
ret = sdw_write(slave, SDW_SCP_BUSCLOCK_SCALE_B0, scale_index);
if (ret < 0) {
dev_err(&slave->dev,
"SDW_SCP_BUSCLOCK_SCALE_B0 write failed:%d\n", ret);
return ret;
}
ret = sdw_write(slave, SDW_SCP_BUSCLOCK_SCALE_B1, scale_index);
if (ret < 0)
dev_err(&slave->dev,
"SDW_SCP_BUSCLOCK_SCALE_B1 write failed:%d\n", ret);

dev_dbg(&slave->dev,
"Configured bus base %d, scale %d, mclk %d, curr_freq %d\n",
base, scale_index, mclk_freq, curr_freq);

return ret;
}

static int sdw_initialize_slave(struct sdw_slave *slave)
{
struct sdw_slave_prop *prop = &slave->prop;
int ret;
u8 val;

ret = sdw_slave_set_frequency(slave);
if (ret < 0)
return ret;

/*
* Set bus clash, parity and SCP implementation
* defined interrupt mask
Expand Down
19 changes: 11 additions & 8 deletions drivers/soundwire/bus_type.c
Original file line number Diff line number Diff line change
Expand Up @@ -20,14 +20,16 @@
static const struct sdw_device_id *
sdw_get_device_id(struct sdw_slave *slave, struct sdw_driver *drv)
{
const struct sdw_device_id *id = drv->id_table;
const struct sdw_device_id *id;

while (id && id->mfg_id) {
for (id = drv->id_table; id && id->mfg_id; id++)
if (slave->id.mfg_id == id->mfg_id &&
slave->id.part_id == id->part_id)
slave->id.part_id == id->part_id &&
(!id->sdw_version ||
slave->id.sdw_version == id->sdw_version) &&
(!id->class_id ||
slave->id.class_id == id->class_id))
return id;
id++;
}

return NULL;
}
Expand All @@ -49,10 +51,11 @@ static int sdw_bus_match(struct device *dev, struct device_driver *ddrv)

int sdw_slave_modalias(const struct sdw_slave *slave, char *buf, size_t size)
{
/* modalias is sdw:m<mfg_id>p<part_id> */
/* modalias is sdw:m<mfg_id>p<part_id>v<version>c<class_id> */

return snprintf(buf, size, "sdw:m%04Xp%04X\n",
slave->id.mfg_id, slave->id.part_id);
return snprintf(buf, size, "sdw:m%04Xp%04Xv%02Xc%02X\n",
slave->id.mfg_id, slave->id.part_id,
slave->id.sdw_version, slave->id.class_id);
}

int sdw_slave_uevent(struct device *dev, struct kobj_uevent_env *env)
Expand Down
70 changes: 48 additions & 22 deletions drivers/soundwire/cadence_master.c
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
#include <linux/soundwire/sdw.h>
#include <sound/pcm_params.h>
#include <sound/soc.h>
#include <linux/workqueue.h>
#include "bus.h"
#include "cadence_master.h"

Expand Down Expand Up @@ -790,7 +791,7 @@ irqreturn_t sdw_cdns_irq(int irq, void *dev_id)
CDNS_MCP_INT_SLAVE_MASK, 0);

int_status &= ~CDNS_MCP_INT_SLAVE_MASK;
ret = IRQ_WAKE_THREAD;
schedule_work(&cdns->work);
}

cdns_writel(cdns, CDNS_MCP_INTSTAT, int_status);
Expand All @@ -799,13 +800,15 @@ irqreturn_t sdw_cdns_irq(int irq, void *dev_id)
EXPORT_SYMBOL(sdw_cdns_irq);

/**
* sdw_cdns_thread() - Cadence irq thread handler
* @irq: irq number
* @dev_id: irq context
* To update slave status in a work since we will need to handle
* other interrupts eg. CDNS_MCP_INT_RX_WL during the update slave
* process.
* @work: cdns worker thread
*/
irqreturn_t sdw_cdns_thread(int irq, void *dev_id)
static void cdns_update_slave_status_work(struct work_struct *work)
{
struct sdw_cdns *cdns = dev_id;
struct sdw_cdns *cdns =
container_of(work, struct sdw_cdns, work);
u32 slave0, slave1;

dev_dbg_ratelimited(cdns->dev, "Slave status change\n");
Expand All @@ -822,9 +825,7 @@ irqreturn_t sdw_cdns_thread(int irq, void *dev_id)
cdns_updatel(cdns, CDNS_MCP_INTMASK,
CDNS_MCP_INT_SLAVE_MASK, CDNS_MCP_INT_SLAVE_MASK);

return IRQ_HANDLED;
}
EXPORT_SYMBOL(sdw_cdns_thread);

/*
* init routines
Expand Down Expand Up @@ -1427,6 +1428,7 @@ int sdw_cdns_probe(struct sdw_cdns *cdns)
init_completion(&cdns->tx_complete);
cdns->bus.port_ops = &cdns_port_ops;

INIT_WORK(&cdns->work, cdns_update_slave_status_work);
return 0;
}
EXPORT_SYMBOL(sdw_cdns_probe);
Expand All @@ -1437,25 +1439,49 @@ int cdns_set_sdw_stream(struct snd_soc_dai *dai,
struct sdw_cdns *cdns = snd_soc_dai_get_drvdata(dai);
struct sdw_cdns_dma_data *dma;

dma = kzalloc(sizeof(*dma), GFP_KERNEL);
if (!dma)
return -ENOMEM;
if (stream) {
/* first paranoia check */
if (direction == SNDRV_PCM_STREAM_PLAYBACK)
dma = dai->playback_dma_data;
else
dma = dai->capture_dma_data;

if (dma) {
dev_err(dai->dev,
"dma_data already allocated for dai %s\n",
dai->name);
return -EINVAL;
}

if (pcm)
dma->stream_type = SDW_STREAM_PCM;
else
dma->stream_type = SDW_STREAM_PDM;
/* allocate and set dma info */
dma = kzalloc(sizeof(*dma), GFP_KERNEL);
if (!dma)
return -ENOMEM;

dma->bus = &cdns->bus;
dma->link_id = cdns->instance;
if (pcm)
dma->stream_type = SDW_STREAM_PCM;
else
dma->stream_type = SDW_STREAM_PDM;

dma->stream = stream;
dma->bus = &cdns->bus;
dma->link_id = cdns->instance;

if (direction == SNDRV_PCM_STREAM_PLAYBACK)
dai->playback_dma_data = dma;
else
dai->capture_dma_data = dma;
dma->stream = stream;

if (direction == SNDRV_PCM_STREAM_PLAYBACK)
dai->playback_dma_data = dma;
else
dai->capture_dma_data = dma;
} else {
/* for NULL stream we release allocated dma_data */
if (direction == SNDRV_PCM_STREAM_PLAYBACK) {
kfree(dai->playback_dma_data);
dai->playback_dma_data = NULL;
} else {
kfree(dai->capture_dma_data);
dai->capture_dma_data = NULL;
}
}
return 0;
}
EXPORT_SYMBOL(cdns_set_sdw_stream);
Expand Down
Loading

0 comments on commit 575ec5e

Please sign in to comment.