SST_VMIC_CHANNEL_SELECT = 0x1011,
SST_SND_DEVICE_RESUME = 0x1012,
SST_SND_DEVICE_RESUME_SYNC = 0x1013,
- SST_MAX_CONTROLS = 0x1013,
+ SST_SET_RUNTIME_PARAMS = 0x1014,
+ SST_MAX_CONTROLS = 0x1014,
};
enum SND_CARDS {
struct intel_sst_pcm_control {
int (*open) (struct snd_sst_params *str_param);
int (*device_control) (int cmd, void *arg);
+ int (*set_generic_params) (enum sst_controls cmd, void *arg);
int (*close) (unsigned int str_id);
};
struct intel_sst_card_ops {
};
enum stream_param_type {
- SET_TIME_SLOT = 0,
- OTHERS = 1, /*reserved for other params that need to be set in future*/
+ SST_SET_TIME_SLOT = 0,
+ SST_SET_CHANNEL_INFO = 1,
+ OTHERS = 2, /*reserved for other params that need to be set in future*/
};
/* Target selection per device structure */
__u8 rsvd;
__u64 addr;
} __attribute__ ((packed));
+
+struct snd_sst_runtime_params {
+ __u8 type;
+ __u8 str_id;
+ __u8 size;
+ __u8 rsvd;
+ void *addr;
+} __attribute__ ((packed));
/*IOCTL defined here */
/*SST MMF IOCTLS only */
#define SNDRV_SST_STREAM_SET_PARAMS _IOWR('L', 0x00, \
kfree(sst_drv_ctx->mmap_mem);
} else
kfree(sst_drv_ctx->fw_cntx);
+ kfree(sst_drv_ctx->runtime_param.param.addr);
flush_scheduled_work();
destroy_workqueue(sst_drv_ctx->process_reply_wq);
destroy_workqueue(sst_drv_ctx->process_msg_wq);
struct pci_dev *dmac;
};
-
+struct sst_runtime_param {
+ struct snd_sst_runtime_params param;
+};
#define PCI_DMAC_MFLD_ID 0x0830
#define PCI_DMAC_CLV_ID 0x08F0
#define SST_MAX_DMA_LEN (4095*4)
struct list_head fw_list;
struct sst_dma dma;
void *fw_in_mem;
+ struct sst_runtime_param runtime_param;
};
extern struct intel_sst_drv *sst_drv_ctx;
return retval;
}
+/*
+ * sst_copy_runtime_param - copy runtime params from src to dst
+ * structure.
+ *
+ *@dst: destination runtime structure
+ *@src: source runtime structure
+ *
+ * This helper function is called to copy the runtime parameter
+ * structure.
+*/
+static int sst_copy_runtime_param(struct snd_sst_runtime_params *dst,
+ struct snd_sst_runtime_params *src)
+{
+ dst->type = src->type;
+ dst->str_id = src->str_id;
+ dst->size = src->size;
+ if (dst->addr) {
+ pr_err("mem allocated in prev setting, use the same memory\n");
+ return -EINVAL;
+ }
+ dst->addr = kzalloc(dst->size, GFP_KERNEL);
+ if (!dst->addr)
+ return -ENOMEM;
+ memcpy(dst->addr, src->addr, dst->size);
+ return 0;
+}
+/*
+ * sst_set_generic_params - Set generic params
+ *
+ * @cmd: control cmd to be set
+ * @arg: command argument
+ *
+ * This function is called by MID sound card driver to configure
+ * SST runtime params.
+ */
+static int sst_set_generic_params(enum sst_controls cmd, void *arg)
+{
+ int ret_val = 0;
+ pr_debug("Enter:%s, cmd:%d\n", __func__, cmd);
+
+ if (NULL == arg)
+ return -EINVAL;
+
+ switch (cmd) {
+ case SST_SET_RUNTIME_PARAMS: {
+ struct snd_sst_runtime_params *src;
+ struct snd_sst_runtime_params *dst;
+
+ src = (struct snd_sst_runtime_params *)arg;
+ dst = &(sst_drv_ctx->runtime_param.param);
+ ret_val = sst_copy_runtime_param(dst, src);
+ break;
+ }
+ default:
+ pr_err("Invalid cmd request:%d\n", cmd);
+ ret_val = -EINVAL;
+ }
+ return ret_val;
+}
static struct intel_sst_pcm_control pcm_ops = {
.open = sst_open_pcm_stream,
.device_control = sst_device_control,
+ .set_generic_params = sst_set_generic_params,
.close = sst_close_pcm_stream,
};
#include "intel_sst_fw_ipc.h"
#include "intel_sst_common.h"
+/**
+ * sst_send_ipc_msg_nowait - send ipc msg for algorithm parameters
+ * and returns immediately without waiting for reply
+ *
+ * @msg: post msg pointer
+ *
+ * This function is called to send ipc msg
+ */
+static int sst_send_ipc_msg_nowait(struct ipc_post **msg)
+{
+ spin_lock(&sst_drv_ctx->list_spin_lock);
+ list_add_tail(&(*msg)->node, &sst_drv_ctx->ipc_dispatch_list);
+ spin_unlock(&sst_drv_ctx->list_spin_lock);
+ sst_post_message(&sst_drv_ctx->ipc_post_msg_wq);
+ return 0;
+}
+
/*
* sst_send_sound_card_type - send sound card type
*
sst_post_message(&sst_drv_ctx->ipc_post_msg_wq);
}
+/*
+ * sst_send_runtime_param - send runtime param to SST
+ *
+ * this function sends the runtime parameter to sst dsp engine
+ */
+static int sst_send_runtime_param(struct snd_sst_runtime_params *params)
+{
+ struct ipc_post *msg = NULL;
+ int ret_val;
+
+ pr_debug("Enter:%s\n", __func__);
+ ret_val = sst_create_large_msg(&msg);
+ if (ret_val)
+ return ret_val;
+ sst_fill_header(&msg->header, IPC_IA_SET_RUNTIME_PARAMS, 1,
+ params->str_id);
+ msg->header.part.data = sizeof(u32) + sizeof(*params) + params->size;
+ memcpy(msg->mailbox_data, &msg->header.full, sizeof(u32));
+ memcpy(msg->mailbox_data + sizeof(u32), params, sizeof(*params));
+ /* driver doesn't need to send address, so overwrite addr with data */
+ memcpy(msg->mailbox_data + sizeof(u32) + sizeof(*params) - sizeof(params->addr),
+ params->addr, params->size);
+ return sst_send_ipc_msg_nowait(&msg);
+}
/**
* sst_post_message - Posts message to SST
*
}
if (sst_drv_ctx->pci_id == SST_MRST_PCI_ID)
sst_send_sound_card_type();
+ /* If there any runtime parameter to set, send it */
+ if (sst_drv_ctx->runtime_param.param.addr)
+ sst_send_runtime_param(&(sst_drv_ctx->runtime_param.param));
mutex_lock(&sst_drv_ctx->sst_lock);
sst_drv_ctx->lpe_stalled = 0;
mutex_unlock(&sst_drv_ctx->sst_lock);
config SND_SST_PLATFORM
tristate
+
+config SND_MFLD_MONO_SPEAKER_SUPPORT
+ tristate "Mono Speaker support for Medfield based devices"
+ default N
+ help
+ This adds support for Mono speaker support on Intel(R) MID Medfield based devices.
+ Say Y if you have device with mono speaker. If you say N support for stereo speakers
+ will be enabled.
+ If unsure select "N".
return ret_val;
}
+#ifdef CONFIG_SND_MFLD_MONO_SPEAKER_SUPPORT
+static int mfld_speaker_init(struct snd_soc_pcm_runtime *runtime)
+{
+ struct snd_soc_dai *cpu_dai = runtime->cpu_dai;
+ struct snd_soc_dapm_context *dapm = &runtime->codec->dapm;
+
+ snd_soc_dapm_disable_pin(dapm, "IHFOUTR");
+ snd_soc_dapm_sync(dapm);
+ return cpu_dai->driver->ops->set_tdm_slot(cpu_dai, 0, 0, 1, 0);
+}
+#endif
+
static struct snd_soc_dai_link mfld_msic_dailink[] = {
{
.name = "Medfield Headset",
.codec_dai_name = "SN95031 Speaker",
.codec_name = "sn95031",
.platform_name = "sst-platform",
+#ifdef CONFIG_SND_MFLD_MONO_SPEAKER_SUPPORT
+ .init = mfld_speaker_init,
+#else
.init = NULL,
+#endif
.ignore_suspend = 1,
},
/*
.fifo_size = SST_FIFO_SIZE,
};
+static int sst_platform_ihf_set_tdm_slot(struct snd_soc_dai *dai,
+ unsigned int tx_mask, unsigned int rx_mask,
+ int slots, int slot_width) {
+ struct intel_sst_card_ops *sstdrv_ops;
+ struct snd_sst_runtime_params params_data;
+ int channels = slots;
+ int ret_val;
+
+ /* allocate memory for SST API set */
+ sstdrv_ops = kzalloc(sizeof(*sstdrv_ops), GFP_KERNEL);
+ if (!sstdrv_ops)
+ return -ENOMEM;
+ /* registering with SST driver to get access to SST APIs to use */
+ ret_val = register_sst_card(sstdrv_ops);
+ if (ret_val) {
+ pr_err("sst: sst card registration failed\n");
+ return -EIO;
+ }
+ params_data.type = SST_SET_CHANNEL_INFO;
+ params_data.str_id = SND_SST_DEVICE_IHF;
+ params_data.size = sizeof(channels);
+ params_data.addr = &channels;
+ ret_val = sstdrv_ops->pcm_control->set_generic_params(SST_SET_RUNTIME_PARAMS,
+ (void *)¶ms_data);
+ kfree(sstdrv_ops);
+ return ret_val;
+}
+
+static const struct snd_soc_dai_ops sst_ihf_ops = {
+ .set_tdm_slot = sst_platform_ihf_set_tdm_slot,
+};
+
/* MFLD - MSIC */
static struct snd_soc_dai_driver sst_platform_dai[] = {
{
#endif
.formats = SNDRV_PCM_FMTBIT_S16_LE,
},
+ .ops = &sst_ihf_ops,
},
{
.name = "Vibra1-cpu-dai",