Skip to content

Commit

Permalink
sof: fix and enable compilation of SPI, add DT support
Browse files Browse the repository at this point in the history
This patch extends the SOF SPI implementation with some rather basic
DT support, adds SPI IO functions, fixes compilation issues and
enables compilation in Kconfig files.

Signed-off-by: Guennadi Liakhovetski <guennadi.liakhovetski@intel.com>
  • Loading branch information
lyakh authored and lgirdwood committed Sep 6, 2018
1 parent e04cc9c commit b647da2
Show file tree
Hide file tree
Showing 4 changed files with 194 additions and 71 deletions.
3 changes: 3 additions & 0 deletions sound/soc/sof/Kconfig
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,9 @@ config SND_SOC_SOF_PCI
config SND_SOC_SOF_ACPI
tristate

config SND_SOC_SOF_SPI
tristate

config SND_SOC_SOF
tristate "Sound Open Firmware Support"
select SND_SOC_TOPOLOGY
Expand Down
134 changes: 92 additions & 42 deletions sound/soc/sof/hw-spi.c
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,8 @@
* Hardware interface for audio DSPs via SPI
*/

#include <linux/kernel.h>
#include <linux/irq.h>
#include <linux/delay.h>
#include <linux/fs.h>
#include <linux/slab.h>
Expand All @@ -29,22 +31,69 @@

#include "sof-priv.h"
#include "ops.h"
#include "intel.h"

/*
* Memory copy.
*/

static void spi_block_write(struct snd_sof_dev *sdev, u32 offset, void *src,
size_t size)
static void spi_block_read(struct snd_sof_dev *sdev, u32 offset, void *dest,
size_t size)
{
// use spi_write() to copy data to DSP
u8 *buf;
int ret;

if (offset) {
buf = kmalloc(size + offset, GFP_KERNEL);
if (!buf) {
dev_err(sdev->dev, "Buffer allocation failed\n");
return;
}
} else {
buf = dest;
}

ret = spi_read(to_spi_device(sdev->dev), buf, size + offset);
if (ret < 0)
dev_err(sdev->dev, "SPI read failed: %d\n", ret);

if (offset) {
memcpy(dest, buf + offset, size);
kfree(buf);
}
}

static void spi_block_read(struct snd_sof_dev *sdev, u32 offset, void *dest,
size_t size)
static void spi_block_write(struct snd_sof_dev *sdev, u32 offset, void *src,
size_t size)
{
// use spi_read() to copy data from DSP
int ret;
u8 *buf;

if (offset) {
buf = kmalloc(size + offset, GFP_KERNEL);
if (!buf) {
dev_err(sdev->dev, "Buffer allocation failed\n");
return;
}

/* Use Read-Modify-Wwrite */
ret = spi_read(to_spi_device(sdev->dev), buf, size + offset);
if (ret < 0) {
dev_err(sdev->dev, "SPI read failed: %d\n", ret);
goto free;
}

memcpy(buf + offset, src, size);
} else {
buf = src;
}

ret = spi_write(to_spi_device(sdev->dev), buf, size + offset);
if (ret < 0)
dev_err(sdev->dev, "SPI write failed: %d\n", ret);

free:
if (offset)
kfree(buf);
}

/*
Expand All @@ -59,7 +108,7 @@ static int spi_fw_ready(struct snd_sof_dev *sdev, u32 msg_id)

// read local buffer with SPI data

dev_info(sdev->dev, " Firmware info: version %d:%d-%s build %d on %s:%s\n",
dev_info(sdev->dev, "Firmware info: version %d:%d-%s build %d on %s:%s\n",
v->major, v->minor, v->tag, v->build, v->date, v->time);

return 0;
Expand All @@ -69,26 +118,25 @@ static int spi_fw_ready(struct snd_sof_dev *sdev, u32 msg_id)
* IPC Mailbox IO
*/

static void spi_mailbox_write(struct snd_sof_dev *sdev, u32 offset,
void *message, size_t bytes)
static void spi_mailbox_write(struct snd_sof_dev *sdev __maybe_unused,
u32 offset __maybe_unused,
void *message __maybe_unused,
size_t bytes __maybe_unused)
{
void __iomem *dest = sdev->bar[sdev->mailbox_bar] + offset;

//memcpy_toio(dest, message, bytes);
/*
* this will copy to a local memory buffer that will be sent to DSP via
* SPI at next IPC
*/
}

static void spi_mailbox_read(struct snd_sof_dev *sdev, u32 offset,
static void spi_mailbox_read(struct snd_sof_dev *sdev __maybe_unused,
u32 offset __maybe_unused,
void *message, size_t bytes)
{
void __iomem *src = sdev->bar[sdev->mailbox_bar] + offset;
memset(message, 0, bytes);

//memcpy_fromio(message, src, bytes);
/*
* this will copy from a local memory buffer that will be received from
* this will copy from a local memory buffer that was received from
* DSP via SPI at last IPC
*/
}
Expand All @@ -97,9 +145,8 @@ static void spi_mailbox_read(struct snd_sof_dev *sdev, u32 offset,
* IPC Doorbell IRQ handler and thread.
*/

static irqreturn_t spi_irq_handler(int irq, void *context)
static irqreturn_t spi_irq_handler(int irq __maybe_unused, void *context __maybe_unused)
{
struct snd_sof_dev *sdev = (struct snd_sof_dev *)context;
int ret = IRQ_NONE;

// on SPI based devices this will likely come via a SoC GPIO IRQ
Expand All @@ -109,25 +156,21 @@ static irqreturn_t spi_irq_handler(int irq, void *context)
return ret;
}

static irqreturn_t spi_irq_thread(int irq, void *context)
static irqreturn_t spi_irq_thread(int irq __maybe_unused, void *context __maybe_unused)
{
struct snd_sof_dev *sdev = (struct snd_sof_dev *)context;

// read SPI data into local buffer and determine IPC cmd or reply

/*
* if reply. Handle Immediate reply from DSP Core and set DSP
* state to ready
*/
//snd_sof_ipc_reply(sdev, ipcx);

/* if cmd, Handle messages from DSP Core */
//snd_sof_ipc_msgs_rx(sdev);

return IRQ_HANDLED;
}

static int spi_is_ready(struct snd_sof_dev *sdev)
static int spi_is_ready(struct snd_sof_dev *sdev __maybe_unused)
{
// use local variable to store DSP command state. either DSP is ready
// for new cmd or still processing current cmd.
Expand All @@ -137,8 +180,6 @@ static int spi_is_ready(struct snd_sof_dev *sdev)

static int spi_send_msg(struct snd_sof_dev *sdev, struct snd_sof_ipc_msg *msg)
{
u64 cmd = msg->header;

/* send the message */
spi_mailbox_write(sdev, sdev->host_box.offset, msg->msg_data,
msg->msg_size);
Expand All @@ -160,7 +201,7 @@ static int spi_get_reply(struct snd_sof_dev *sdev, struct snd_sof_ipc_msg *msg)
} else {
/* reply correct size ? */
if (reply.hdr.size != msg->reply_size) {
dev_err(sdev->dev, "error: reply expected 0x%lx got 0x%x bytes\n",
dev_err(sdev->dev, "error: reply expected 0x%zu got 0x%x bytes\n",
msg->reply_size, reply.hdr.size);
size = msg->reply_size;
ret = -EINVAL;
Expand All @@ -183,22 +224,26 @@ static int spi_get_reply(struct snd_sof_dev *sdev, struct snd_sof_ipc_msg *msg)

static int spi_sof_probe(struct snd_sof_dev *sdev)
{
struct snd_sof_pdata *pdata = sdev->pdata;
const struct sof_dev_desc *desc = pdata->desc;
struct platform_device *pdev =
container_of(sdev->parent, struct platform_device, dev);
int ret = 0;

/* get IRQ from Device tree or ACPI - register our IRQ */
struct irq_data *irqd;
struct spi_device *spi = to_spi_device(pdev->dev.parent);
int ret;

sdev->ipc_irq = spi->irq;
dev_dbg(sdev->dev, "using IRQ %d\n", sdev->ipc_irq);
ret = request_threaded_irq(sdev->ipc_irq, spi_irq_handler,
spi_irq_thread, IRQF_SHARED, "AudioDSP",
sdev);
if (ret < 0) {
irqd = irq_get_irq_data(sdev->ipc_irq);
if (!irqd)
return -EINVAL;

ret = devm_request_threaded_irq(sdev->dev, sdev->ipc_irq,
spi_irq_handler, spi_irq_thread,
irqd_get_trigger_type(irqd) | IRQF_ONESHOT,
"AudioDSP", sdev);
if (ret < 0)
dev_err(sdev->dev, "error: failed to register IRQ %d\n",
sdev->ipc_irq);
goto irq_err;
}

return ret;
}
Expand All @@ -209,7 +254,12 @@ static int spi_sof_remove(struct snd_sof_dev *sdev)
return 0;
}

/* baytrail ops */
static int spi_cmd_done(struct snd_sof_dev *sof_dev __maybe_unused, int dir __maybe_unused)
{
return 0;
}

/* SPI SOF ops */
struct snd_sof_dsp_ops snd_sof_spi_ops = {
/* device init */
.probe = spi_sof_probe,
Expand All @@ -235,9 +285,9 @@ struct snd_sof_dsp_ops snd_sof_spi_ops = {
.cmd_done = spi_cmd_done,

/* debug */
.debug_map = spi_debugfs,
.debug_map_count = ARRAY_SIZE(spi_debugfs),
.dbg_dump = spi_dump,
.debug_map = NULL/*spi_debugfs*/,
.debug_map_count = 0/*ARRAY_SIZE(spi_debugfs)*/,
.dbg_dump = NULL/*spi_dump*/,

/* module loading */
.load_module = snd_sof_parse_module_memcpy,
Expand Down
11 changes: 11 additions & 0 deletions sound/soc/sof/intel/Kconfig
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,17 @@ config SND_SOC_SOF_INTEL
Say Y if you have such a device.
If unsure select "N".

config SND_SOC_SOF_SPIDSP
tristate "SOF support over the SPI bus"
depends on SND_SOC_SOF
depends on SPI
select SND_SOC_SOF_SPI
help
This adds support for Sound Open Firmware over SPI for Device
Tree based systems.
Say Y if you have such a device.
If unsure select "N".

if SND_SOC_SOF_INTEL

config SND_SOC_SOF_BAYTRAIL
Expand Down
Loading

0 comments on commit b647da2

Please sign in to comment.