Merge "ASoC: wcd934x-dsp-cntl: add support for subsystem restart"
This commit is contained in:
commit
a0e79f8e03
3 changed files with 170 additions and 22 deletions
|
@ -639,12 +639,10 @@ static int wcd_spi_init(struct spi_device *spi)
|
|||
WCD_SPI_SLAVE_TRNS_LEN,
|
||||
0xFFFF0000,
|
||||
(WCD_SPI_RW_MULTI_MAX_LEN / 4) << 16);
|
||||
done:
|
||||
return ret;
|
||||
|
||||
err_wr_en:
|
||||
wcd_spi_clk_ctrl(spi, WCD_SPI_CLK_DISABLE,
|
||||
WCD_SPI_CLK_FLAG_IMMEDIATE);
|
||||
done:
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
@ -845,6 +843,7 @@ static int wdsp_spi_event_handler(struct device *dev, void *priv_data,
|
|||
__func__, event);
|
||||
|
||||
switch (event) {
|
||||
case WDSP_EVENT_PRE_DLOAD_CODE:
|
||||
case WDSP_EVENT_PRE_DLOAD_DATA:
|
||||
ret = wcd_spi_clk_ctrl(spi, WCD_SPI_CLK_ENABLE,
|
||||
WCD_SPI_CLK_FLAG_IMMEDIATE);
|
||||
|
|
|
@ -28,20 +28,21 @@
|
|||
#define WCD_MEM_ENABLE_MAX_RETRIES 20
|
||||
#define WCD_DSP_BOOT_TIMEOUT_MS 3000
|
||||
#define WCD_SYSFS_ENTRY_MAX_LEN 8
|
||||
#define WCD_PROCFS_ENTRY_MAX_LEN 16
|
||||
#define WCD_934X_RAMDUMP_START_ADDR 0x20100000
|
||||
#define WCD_934X_RAMDUMP_SIZE ((1024 * 1024) - 128)
|
||||
|
||||
#define WCD_CNTL_MUTEX_LOCK(codec, lock) \
|
||||
{ \
|
||||
dev_dbg(codec->dev, "mutex_lock(%s)\n", \
|
||||
__func__); \
|
||||
dev_dbg(codec->dev, "%s: mutex_lock(%s)\n", \
|
||||
__func__, __stringify_1(lock)); \
|
||||
mutex_lock(&lock); \
|
||||
}
|
||||
|
||||
#define WCD_CNTL_MUTEX_UNLOCK(codec, lock) \
|
||||
{ \
|
||||
dev_dbg(codec->dev, "mutex_unlock(%s)\n",\
|
||||
__func__); \
|
||||
dev_dbg(codec->dev, "%s: mutex_unlock(%s)\n", \
|
||||
__func__, __stringify_1(lock)); \
|
||||
mutex_unlock(&lock); \
|
||||
}
|
||||
|
||||
|
@ -149,6 +150,97 @@ static struct kobj_type wcd_cntl_ktype = {
|
|||
.sysfs_ops = &wcd_cntl_sysfs_ops,
|
||||
};
|
||||
|
||||
static void wcd_cntl_change_online_state(struct wcd_dsp_cntl *cntl,
|
||||
u8 online)
|
||||
{
|
||||
struct wdsp_ssr_entry *ssr_entry = &cntl->ssr_entry;
|
||||
unsigned long ret;
|
||||
|
||||
WCD_CNTL_MUTEX_LOCK(cntl->codec, cntl->ssr_mutex);
|
||||
ssr_entry->offline = !online;
|
||||
/* Make sure the write is complete */
|
||||
wmb();
|
||||
ret = xchg(&ssr_entry->offline_change, 1);
|
||||
wake_up_interruptible(&ssr_entry->offline_poll_wait);
|
||||
dev_dbg(cntl->codec->dev,
|
||||
"%s: requested %u, offline %u offline_change %u, ret = %ldn",
|
||||
__func__, online, ssr_entry->offline,
|
||||
ssr_entry->offline_change, ret);
|
||||
WCD_CNTL_MUTEX_UNLOCK(cntl->codec, cntl->ssr_mutex);
|
||||
}
|
||||
|
||||
static ssize_t wdsp_ssr_entry_read(struct snd_info_entry *entry,
|
||||
void *file_priv_data, struct file *file,
|
||||
char __user *buf, size_t count, loff_t pos)
|
||||
{
|
||||
int len = 0;
|
||||
char buffer[WCD_PROCFS_ENTRY_MAX_LEN];
|
||||
struct wcd_dsp_cntl *cntl;
|
||||
struct wdsp_ssr_entry *ssr_entry;
|
||||
ssize_t ret;
|
||||
u8 offline;
|
||||
|
||||
cntl = (struct wcd_dsp_cntl *) entry->private_data;
|
||||
if (!cntl) {
|
||||
pr_err("%s: Invalid private data for SSR procfs entry\n",
|
||||
__func__);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
ssr_entry = &cntl->ssr_entry;
|
||||
|
||||
WCD_CNTL_MUTEX_LOCK(cntl->codec, cntl->ssr_mutex);
|
||||
offline = ssr_entry->offline;
|
||||
/* Make sure the read is complete */
|
||||
rmb();
|
||||
dev_dbg(cntl->codec->dev, "%s: offline = %s\n", __func__,
|
||||
offline ? "true" : "false");
|
||||
len = snprintf(buffer, sizeof(buffer), "%s\n",
|
||||
offline ? "OFFLINE" : "ONLINE");
|
||||
ret = simple_read_from_buffer(buf, count, &pos, buffer, len);
|
||||
WCD_CNTL_MUTEX_UNLOCK(cntl->codec, cntl->ssr_mutex);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static unsigned int wdsp_ssr_entry_poll(struct snd_info_entry *entry,
|
||||
void *private_data, struct file *file,
|
||||
poll_table *wait)
|
||||
{
|
||||
struct wcd_dsp_cntl *cntl;
|
||||
struct wdsp_ssr_entry *ssr_entry;
|
||||
unsigned int ret = 0;
|
||||
|
||||
if (!entry || !entry->private_data) {
|
||||
pr_err("%s: %s is NULL\n", __func__,
|
||||
(!entry) ? "entry" : "private_data");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
cntl = (struct wcd_dsp_cntl *) entry->private_data;
|
||||
ssr_entry = &cntl->ssr_entry;
|
||||
|
||||
dev_dbg(cntl->codec->dev, "%s: Poll wait, offline = %u\n",
|
||||
__func__, ssr_entry->offline);
|
||||
poll_wait(file, &ssr_entry->offline_poll_wait, wait);
|
||||
dev_dbg(cntl->codec->dev, "%s: Woken up Poll wait, offline = %u\n",
|
||||
__func__, ssr_entry->offline);
|
||||
|
||||
WCD_CNTL_MUTEX_LOCK(cntl->codec, cntl->ssr_mutex);
|
||||
if (xchg(&ssr_entry->offline_change, 0))
|
||||
ret = POLLIN | POLLPRI | POLLRDNORM;
|
||||
dev_dbg(cntl->codec->dev, "%s: ret (%d) from poll_wait\n",
|
||||
__func__, ret);
|
||||
WCD_CNTL_MUTEX_UNLOCK(cntl->codec, cntl->ssr_mutex);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static struct snd_info_entry_ops wdsp_ssr_entry_ops = {
|
||||
.read = wdsp_ssr_entry_read,
|
||||
.poll = wdsp_ssr_entry_poll,
|
||||
};
|
||||
|
||||
static int wcd_cntl_cpe_fll_calibrate(struct wcd_dsp_cntl *cntl)
|
||||
{
|
||||
struct snd_soc_codec *codec = cntl->codec;
|
||||
|
@ -596,6 +688,7 @@ static irqreturn_t wcd_cntl_err_irq(int irq, void *data)
|
|||
dev_err(cntl->codec->dev,
|
||||
"%s: Failed to handle fatal irq 0x%x\n",
|
||||
__func__, status & cntl->irqs.fatal_irqs);
|
||||
wcd_cntl_change_online_state(cntl, 0);
|
||||
} else {
|
||||
dev_err(cntl->codec->dev, "%s: Invalid intr_handler\n",
|
||||
__func__);
|
||||
|
@ -612,10 +705,15 @@ static int wcd_control_handler(struct device *dev, void *priv_data,
|
|||
int ret = 0;
|
||||
|
||||
switch (event) {
|
||||
case WDSP_EVENT_POST_INIT:
|
||||
case WDSP_EVENT_POST_DLOAD_CODE:
|
||||
case WDSP_EVENT_DLOAD_FAILED:
|
||||
case WDSP_EVENT_POST_SHUTDOWN:
|
||||
|
||||
if (event == WDSP_EVENT_POST_DLOAD_CODE)
|
||||
/* Mark DSP online since code download is complete */
|
||||
wcd_cntl_change_online_state(cntl, 1);
|
||||
|
||||
/* Disable CPAR */
|
||||
wcd_cntl_cpar_ctrl(cntl, false);
|
||||
/* Disable all the clocks */
|
||||
|
@ -626,12 +724,8 @@ static int wcd_control_handler(struct device *dev, void *priv_data,
|
|||
__func__, ret);
|
||||
break;
|
||||
|
||||
case WDSP_EVENT_PRE_DLOAD_CODE:
|
||||
|
||||
wcd_cntl_enable_memory(cntl);
|
||||
break;
|
||||
|
||||
case WDSP_EVENT_PRE_DLOAD_DATA:
|
||||
case WDSP_EVENT_PRE_DLOAD_CODE:
|
||||
|
||||
/* Enable all the clocks */
|
||||
ret = wcd_cntl_clocks_enable(cntl);
|
||||
|
@ -644,6 +738,9 @@ static int wcd_control_handler(struct device *dev, void *priv_data,
|
|||
|
||||
/* Enable CPAR */
|
||||
wcd_cntl_cpar_ctrl(cntl, true);
|
||||
|
||||
if (event == WDSP_EVENT_PRE_DLOAD_CODE)
|
||||
wcd_cntl_enable_memory(cntl);
|
||||
break;
|
||||
|
||||
case WDSP_EVENT_DO_BOOT:
|
||||
|
@ -850,6 +947,10 @@ static int wcd_ctrl_component_bind(struct device *dev,
|
|||
void *data)
|
||||
{
|
||||
struct wcd_dsp_cntl *cntl;
|
||||
struct snd_soc_codec *codec;
|
||||
struct snd_card *card;
|
||||
struct snd_info_entry *entry;
|
||||
char proc_name[WCD_PROCFS_ENTRY_MAX_LEN];
|
||||
int ret = 0;
|
||||
|
||||
if (!dev || !master || !data) {
|
||||
|
@ -867,13 +968,47 @@ static int wcd_ctrl_component_bind(struct device *dev,
|
|||
cntl->m_dev = master;
|
||||
cntl->m_ops = data;
|
||||
|
||||
if (cntl->m_ops->register_cmpnt_ops)
|
||||
ret = cntl->m_ops->register_cmpnt_ops(master, dev, cntl,
|
||||
&control_ops);
|
||||
if (!cntl->m_ops->register_cmpnt_ops) {
|
||||
dev_err(dev, "%s: invalid master callback register_cmpnt_ops\n",
|
||||
__func__);
|
||||
ret = -EINVAL;
|
||||
goto done;
|
||||
}
|
||||
|
||||
if (ret)
|
||||
ret = cntl->m_ops->register_cmpnt_ops(master, dev, cntl, &control_ops);
|
||||
if (ret) {
|
||||
dev_err(dev, "%s: register_cmpnt_ops failed, err = %d\n",
|
||||
__func__, ret);
|
||||
goto done;
|
||||
}
|
||||
|
||||
codec = cntl->codec;
|
||||
card = codec->component.card->snd_card;
|
||||
snprintf(proc_name, WCD_PROCFS_ENTRY_MAX_LEN, "%s%d%s", "cpe",
|
||||
cntl->dsp_instance, "_state");
|
||||
entry = snd_info_create_card_entry(card, proc_name, card->proc_root);
|
||||
if (!entry) {
|
||||
/* Do not treat this as Fatal error */
|
||||
dev_err(dev, "%s: Failed to create procfs entry %s\n",
|
||||
__func__, proc_name);
|
||||
goto done;
|
||||
}
|
||||
|
||||
cntl->ssr_entry.entry = entry;
|
||||
cntl->ssr_entry.offline = 1;
|
||||
entry->size = WCD_PROCFS_ENTRY_MAX_LEN;
|
||||
entry->content = SNDRV_INFO_CONTENT_DATA;
|
||||
entry->c.ops = &wdsp_ssr_entry_ops;
|
||||
entry->private_data = cntl;
|
||||
ret = snd_info_register(entry);
|
||||
if (IS_ERR_VALUE(ret)) {
|
||||
dev_err(dev, "%s: Failed to register entry %s, err = %d\n",
|
||||
__func__, proc_name, ret);
|
||||
snd_info_free_entry(entry);
|
||||
/* Let bind still happen even if creating the entry failed */
|
||||
ret = 0;
|
||||
}
|
||||
done:
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
@ -952,6 +1087,8 @@ void wcd_dsp_cntl_init(struct snd_soc_codec *codec,
|
|||
memcpy(&control->irqs, ¶ms->irqs, sizeof(control->irqs));
|
||||
init_completion(&control->boot_complete);
|
||||
mutex_init(&control->clk_mutex);
|
||||
mutex_init(&control->ssr_mutex);
|
||||
init_waitqueue_head(&control->ssr_entry.offline_poll_wait);
|
||||
|
||||
/*
|
||||
* The default state of WDSP is in SVS mode.
|
||||
|
@ -1004,6 +1141,7 @@ void wcd_dsp_cntl_deinit(struct wcd_dsp_cntl **cntl)
|
|||
component_del(codec->dev, &wcd_ctrl_component_ops);
|
||||
|
||||
mutex_destroy(&control->clk_mutex);
|
||||
mutex_destroy(&control->ssr_mutex);
|
||||
kfree(*cntl);
|
||||
*cntl = NULL;
|
||||
}
|
||||
|
|
|
@ -54,6 +54,13 @@ struct wcd_dsp_params {
|
|||
u32 dsp_instance;
|
||||
};
|
||||
|
||||
struct wdsp_ssr_entry {
|
||||
u8 offline;
|
||||
u8 offline_change;
|
||||
wait_queue_head_t offline_poll_wait;
|
||||
struct snd_info_entry *entry;
|
||||
};
|
||||
|
||||
struct wcd_dsp_cntl {
|
||||
/* Handle to codec */
|
||||
struct snd_soc_codec *codec;
|
||||
|
@ -89,6 +96,10 @@ struct wcd_dsp_cntl {
|
|||
|
||||
/* Keep track of WDSP boot status */
|
||||
bool is_wdsp_booted;
|
||||
|
||||
/* SSR related */
|
||||
struct wdsp_ssr_entry ssr_entry;
|
||||
struct mutex ssr_mutex;
|
||||
};
|
||||
|
||||
void wcd_dsp_cntl_init(struct snd_soc_codec *codec,
|
||||
|
|
Loading…
Add table
Reference in a new issue