summaryrefslogtreecommitdiffstats
path: root/sound/soc/intel/common
diff options
context:
space:
mode:
Diffstat (limited to 'sound/soc/intel/common')
-rw-r--r--sound/soc/intel/common/sst-acpi.h17
-rw-r--r--sound/soc/intel/common/sst-ipc.c85
-rw-r--r--sound/soc/intel/common/sst-ipc.h8
-rw-r--r--sound/soc/intel/common/sst-match-acpi.c57
4 files changed, 124 insertions, 43 deletions
diff --git a/sound/soc/intel/common/sst-acpi.h b/sound/soc/intel/common/sst-acpi.h
index 0127422..214e000 100644
--- a/sound/soc/intel/common/sst-acpi.h
+++ b/sound/soc/intel/common/sst-acpi.h
@@ -15,14 +15,29 @@
#include <linux/stddef.h>
#include <linux/acpi.h>
-/* translation fron HID to I2C name, needed for DAI codec_name */
+struct sst_acpi_package_context {
+ char *name; /* package name */
+ int length; /* number of elements */
+ struct acpi_buffer *format;
+ struct acpi_buffer *state;
+ bool data_valid;
+};
+
#if IS_ENABLED(CONFIG_ACPI)
+/* translation fron HID to I2C name, needed for DAI codec_name */
const char *sst_acpi_find_name_from_hid(const u8 hid[ACPI_ID_LEN]);
+bool sst_acpi_find_package_from_hid(const u8 hid[ACPI_ID_LEN],
+ struct sst_acpi_package_context *ctx);
#else
static inline const char *sst_acpi_find_name_from_hid(const u8 hid[ACPI_ID_LEN])
{
return NULL;
}
+static inline bool sst_acpi_find_package_from_hid(const u8 hid[ACPI_ID_LEN],
+ struct sst_acpi_package_context *ctx)
+{
+ return false;
+}
#endif
/* acpi match */
diff --git a/sound/soc/intel/common/sst-ipc.c b/sound/soc/intel/common/sst-ipc.c
index 6c672ac..62f3a8e 100644
--- a/sound/soc/intel/common/sst-ipc.c
+++ b/sound/soc/intel/common/sst-ipc.c
@@ -26,7 +26,6 @@
#include <linux/sched.h>
#include <linux/delay.h>
#include <linux/platform_device.h>
-#include <linux/kthread.h>
#include <sound/asound.h>
#include "sst-dsp.h"
@@ -109,10 +108,9 @@ static int ipc_tx_message(struct sst_generic_ipc *ipc, u64 header,
ipc->ops.tx_data_copy(msg, tx_data, tx_bytes);
list_add_tail(&msg->list, &ipc->tx_list);
+ schedule_work(&ipc->kwork);
spin_unlock_irqrestore(&ipc->dsp->spinlock, flags);
- kthread_queue_work(&ipc->kworker, &ipc->kwork);
-
if (wait)
return tx_wait_done(ipc, msg, rx_data);
else
@@ -156,42 +154,56 @@ free_mem:
return -ENOMEM;
}
-static void ipc_tx_msgs(struct kthread_work *work)
+static void ipc_tx_msgs(struct work_struct *work)
{
struct sst_generic_ipc *ipc =
container_of(work, struct sst_generic_ipc, kwork);
struct ipc_message *msg;
- unsigned long flags;
- spin_lock_irqsave(&ipc->dsp->spinlock, flags);
+ spin_lock_irq(&ipc->dsp->spinlock);
- if (list_empty(&ipc->tx_list) || ipc->pending) {
- spin_unlock_irqrestore(&ipc->dsp->spinlock, flags);
- return;
- }
-
- /* if the DSP is busy, we will TX messages after IRQ.
- * also postpone if we are in the middle of procesing completion irq*/
- if (ipc->ops.is_dsp_busy && ipc->ops.is_dsp_busy(ipc->dsp)) {
- dev_dbg(ipc->dev, "ipc_tx_msgs dsp busy\n");
- spin_unlock_irqrestore(&ipc->dsp->spinlock, flags);
- return;
- }
+ while (!list_empty(&ipc->tx_list) && !ipc->pending) {
+ /* if the DSP is busy, we will TX messages after IRQ.
+ * also postpone if we are in the middle of processing
+ * completion irq
+ */
+ if (ipc->ops.is_dsp_busy && ipc->ops.is_dsp_busy(ipc->dsp)) {
+ dev_dbg(ipc->dev, "ipc_tx_msgs dsp busy\n");
+ break;
+ }
- msg = list_first_entry(&ipc->tx_list, struct ipc_message, list);
- list_move(&msg->list, &ipc->rx_list);
+ msg = list_first_entry(&ipc->tx_list, struct ipc_message, list);
+ list_move(&msg->list, &ipc->rx_list);
- if (ipc->ops.tx_msg != NULL)
- ipc->ops.tx_msg(ipc, msg);
+ if (ipc->ops.tx_msg != NULL)
+ ipc->ops.tx_msg(ipc, msg);
+ }
- spin_unlock_irqrestore(&ipc->dsp->spinlock, flags);
+ spin_unlock_irq(&ipc->dsp->spinlock);
}
int sst_ipc_tx_message_wait(struct sst_generic_ipc *ipc, u64 header,
void *tx_data, size_t tx_bytes, void *rx_data, size_t rx_bytes)
{
- return ipc_tx_message(ipc, header, tx_data, tx_bytes,
+ int ret;
+
+ /*
+ * DSP maybe in lower power active state, so
+ * check if the DSP supports DSP lp On method
+ * if so invoke that before sending IPC
+ */
+ if (ipc->ops.check_dsp_lp_on)
+ if (ipc->ops.check_dsp_lp_on(ipc->dsp, true))
+ return -EIO;
+
+ ret = ipc_tx_message(ipc, header, tx_data, tx_bytes,
rx_data, rx_bytes, 1);
+
+ if (ipc->ops.check_dsp_lp_on)
+ if (ipc->ops.check_dsp_lp_on(ipc->dsp, false))
+ return -EIO;
+
+ return ret;
}
EXPORT_SYMBOL_GPL(sst_ipc_tx_message_wait);
@@ -203,6 +215,14 @@ int sst_ipc_tx_message_nowait(struct sst_generic_ipc *ipc, u64 header,
}
EXPORT_SYMBOL_GPL(sst_ipc_tx_message_nowait);
+int sst_ipc_tx_message_nopm(struct sst_generic_ipc *ipc, u64 header,
+ void *tx_data, size_t tx_bytes, void *rx_data, size_t rx_bytes)
+{
+ return ipc_tx_message(ipc, header, tx_data, tx_bytes,
+ rx_data, rx_bytes, 1);
+}
+EXPORT_SYMBOL_GPL(sst_ipc_tx_message_nopm);
+
struct ipc_message *sst_ipc_reply_find_msg(struct sst_generic_ipc *ipc,
u64 header)
{
@@ -280,19 +300,7 @@ int sst_ipc_init(struct sst_generic_ipc *ipc)
if (ret < 0)
return -ENOMEM;
- /* start the IPC message thread */
- kthread_init_worker(&ipc->kworker);
- ipc->tx_thread = kthread_run(kthread_worker_fn,
- &ipc->kworker, "%s",
- dev_name(ipc->dev));
- if (IS_ERR(ipc->tx_thread)) {
- dev_err(ipc->dev, "error: failed to create message TX task\n");
- ret = PTR_ERR(ipc->tx_thread);
- kfree(ipc->msg);
- return ret;
- }
-
- kthread_init_work(&ipc->kwork, ipc_tx_msgs);
+ INIT_WORK(&ipc->kwork, ipc_tx_msgs);
return 0;
}
EXPORT_SYMBOL_GPL(sst_ipc_init);
@@ -301,8 +309,7 @@ void sst_ipc_fini(struct sst_generic_ipc *ipc)
{
int i;
- if (ipc->tx_thread)
- kthread_stop(ipc->tx_thread);
+ cancel_work_sync(&ipc->kwork);
if (ipc->msg) {
for (i = 0; i < IPC_EMPTY_LIST_SIZE; i++) {
diff --git a/sound/soc/intel/common/sst-ipc.h b/sound/soc/intel/common/sst-ipc.h
index ceb7e46..7ed42a6 100644
--- a/sound/soc/intel/common/sst-ipc.h
+++ b/sound/soc/intel/common/sst-ipc.h
@@ -23,7 +23,6 @@
#include <linux/list.h>
#include <linux/workqueue.h>
#include <linux/sched.h>
-#include <linux/kthread.h>
#define IPC_MAX_MAILBOX_BYTES 256
@@ -52,6 +51,7 @@ struct sst_plat_ipc_ops {
void (*tx_data_copy)(struct ipc_message *, char *, size_t);
u64 (*reply_msg_match)(u64 header, u64 *mask);
bool (*is_dsp_busy)(struct sst_dsp *dsp);
+ int (*check_dsp_lp_on)(struct sst_dsp *dsp, bool state);
};
/* SST generic IPC data */
@@ -65,8 +65,7 @@ struct sst_generic_ipc {
struct list_head empty_list;
wait_queue_head_t wait_txq;
struct task_struct *tx_thread;
- struct kthread_worker kworker;
- struct kthread_work kwork;
+ struct work_struct kwork;
bool pending;
struct ipc_message *msg;
int tx_data_max_size;
@@ -81,6 +80,9 @@ int sst_ipc_tx_message_wait(struct sst_generic_ipc *ipc, u64 header,
int sst_ipc_tx_message_nowait(struct sst_generic_ipc *ipc, u64 header,
void *tx_data, size_t tx_bytes);
+int sst_ipc_tx_message_nopm(struct sst_generic_ipc *ipc, u64 header,
+ void *tx_data, size_t tx_bytes, void *rx_data, size_t rx_bytes);
+
struct ipc_message *sst_ipc_reply_find_msg(struct sst_generic_ipc *ipc,
u64 header);
diff --git a/sound/soc/intel/common/sst-match-acpi.c b/sound/soc/intel/common/sst-match-acpi.c
index 7898433..1070f3a 100644
--- a/sound/soc/intel/common/sst-match-acpi.c
+++ b/sound/soc/intel/common/sst-match-acpi.c
@@ -77,5 +77,62 @@ struct sst_acpi_mach *sst_acpi_find_machine(struct sst_acpi_mach *machines)
}
EXPORT_SYMBOL_GPL(sst_acpi_find_machine);
+static acpi_status sst_acpi_find_package(acpi_handle handle, u32 level,
+ void *context, void **ret)
+{
+ struct acpi_device *adev;
+ acpi_status status = AE_OK;
+ struct sst_acpi_package_context *pkg_ctx = context;
+
+ pkg_ctx->data_valid = false;
+
+ if (acpi_bus_get_device(handle, &adev))
+ return AE_OK;
+
+ if (adev->status.present && adev->status.functional) {
+ struct acpi_buffer buffer = {ACPI_ALLOCATE_BUFFER, NULL};
+ union acpi_object *myobj = NULL;
+
+ status = acpi_evaluate_object_typed(handle, pkg_ctx->name,
+ NULL, &buffer,
+ ACPI_TYPE_PACKAGE);
+ if (ACPI_FAILURE(status))
+ return AE_OK;
+
+ myobj = buffer.pointer;
+ if (!myobj || myobj->package.count != pkg_ctx->length) {
+ kfree(buffer.pointer);
+ return AE_OK;
+ }
+
+ status = acpi_extract_package(myobj,
+ pkg_ctx->format, pkg_ctx->state);
+ if (ACPI_FAILURE(status)) {
+ kfree(buffer.pointer);
+ return AE_OK;
+ }
+
+ kfree(buffer.pointer);
+ pkg_ctx->data_valid = true;
+ return AE_CTRL_TERMINATE;
+ }
+
+ return AE_OK;
+}
+
+bool sst_acpi_find_package_from_hid(const u8 hid[ACPI_ID_LEN],
+ struct sst_acpi_package_context *ctx)
+{
+ acpi_status status;
+
+ status = acpi_get_devices(hid, sst_acpi_find_package, ctx, NULL);
+
+ if (ACPI_FAILURE(status) || !ctx->data_valid)
+ return false;
+
+ return true;
+}
+EXPORT_SYMBOL_GPL(sst_acpi_find_package_from_hid);
+
MODULE_LICENSE("GPL v2");
MODULE_DESCRIPTION("Intel Common ACPI Match module");
OpenPOWER on IntegriCloud