diff options
Diffstat (limited to 'sound/soc')
-rw-r--r-- | sound/soc/codecs/max98090.c | 115 | ||||
-rw-r--r-- | sound/soc/codecs/max98090.h | 3 | ||||
-rw-r--r-- | sound/soc/intel/Makefile | 3 | ||||
-rw-r--r-- | sound/soc/intel/byt-max98090.c | 1 | ||||
-rw-r--r-- | sound/soc/intel/byt-rt5640.c | 54 | ||||
-rw-r--r-- | sound/soc/intel/sst-atom-controls.c | 218 | ||||
-rw-r--r-- | sound/soc/intel/sst-atom-controls.h | 416 | ||||
-rw-r--r-- | sound/soc/intel/sst-haswell-pcm.c | 56 | ||||
-rw-r--r-- | sound/soc/intel/sst-mfld-platform-compress.c | 38 | ||||
-rw-r--r-- | sound/soc/intel/sst-mfld-platform-pcm.c | 106 | ||||
-rw-r--r-- | sound/soc/intel/sst-mfld-platform.h | 58 | ||||
-rw-r--r-- | sound/soc/samsung/speyside.c | 6 | ||||
-rw-r--r-- | sound/soc/soc-core.c | 669 | ||||
-rw-r--r-- | sound/soc/soc-generic-dmaengine-pcm.c | 4 | ||||
-rw-r--r-- | sound/soc/soc-io.c | 28 |
15 files changed, 1265 insertions, 510 deletions
diff --git a/sound/soc/codecs/max98090.c b/sound/soc/codecs/max98090.c index 4a063fa88526..7e111865946a 100644 --- a/sound/soc/codecs/max98090.c +++ b/sound/soc/codecs/max98090.c @@ -1311,8 +1311,6 @@ static const struct snd_soc_dapm_route max98090_dapm_routes[] = { {"MIC1 Input", NULL, "MIC1"}, {"MIC2 Input", NULL, "MIC2"}, - {"DMICL", NULL, "DMICL_ENA"}, - {"DMICR", NULL, "DMICR_ENA"}, {"DMICL", NULL, "AHPF"}, {"DMICR", NULL, "AHPF"}, @@ -1370,6 +1368,8 @@ static const struct snd_soc_dapm_route max98090_dapm_routes[] = { {"DMIC Mux", "ADC", "ADCR"}, {"DMIC Mux", "DMIC", "DMICL"}, {"DMIC Mux", "DMIC", "DMICR"}, + {"DMIC Mux", "DMIC", "DMICL_ENA"}, + {"DMIC Mux", "DMIC", "DMICR_ENA"}, {"LBENL Mux", "Normal", "DMIC Mux"}, {"LBENL Mux", "Loopback", "LTENL Mux"}, @@ -1972,6 +1972,102 @@ static int max98090_dai_digital_mute(struct snd_soc_dai *codec_dai, int mute) return 0; } +static int max98090_dai_trigger(struct snd_pcm_substream *substream, int cmd, + struct snd_soc_dai *dai) +{ + struct snd_soc_codec *codec = dai->codec; + struct max98090_priv *max98090 = snd_soc_codec_get_drvdata(codec); + + switch (cmd) { + case SNDRV_PCM_TRIGGER_START: + case SNDRV_PCM_TRIGGER_RESUME: + case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: + if (!max98090->master && dai->active == 1) + queue_delayed_work(system_power_efficient_wq, + &max98090->pll_det_enable_work, + msecs_to_jiffies(10)); + break; + case SNDRV_PCM_TRIGGER_STOP: + case SNDRV_PCM_TRIGGER_SUSPEND: + case SNDRV_PCM_TRIGGER_PAUSE_PUSH: + if (!max98090->master && dai->active == 1) + schedule_work(&max98090->pll_det_disable_work); + break; + default: + break; + } + + return 0; +} + +static void max98090_pll_det_enable_work(struct work_struct *work) +{ + struct max98090_priv *max98090 = + container_of(work, struct max98090_priv, + pll_det_enable_work.work); + struct snd_soc_codec *codec = max98090->codec; + unsigned int status, mask; + + /* + * Clear status register in order to clear possibly already occurred + * PLL unlock. If PLL hasn't still locked, the status will be set + * again and PLL unlock interrupt will occur. + * Note this will clear all status bits + */ + regmap_read(max98090->regmap, M98090_REG_DEVICE_STATUS, &status); + + /* + * Queue jack work in case jack state has just changed but handler + * hasn't run yet + */ + regmap_read(max98090->regmap, M98090_REG_INTERRUPT_S, &mask); + status &= mask; + if (status & M98090_JDET_MASK) + queue_delayed_work(system_power_efficient_wq, + &max98090->jack_work, + msecs_to_jiffies(100)); + + /* Enable PLL unlock interrupt */ + snd_soc_update_bits(codec, M98090_REG_INTERRUPT_S, + M98090_IULK_MASK, + 1 << M98090_IULK_SHIFT); +} + +static void max98090_pll_det_disable_work(struct work_struct *work) +{ + struct max98090_priv *max98090 = + container_of(work, struct max98090_priv, pll_det_disable_work); + struct snd_soc_codec *codec = max98090->codec; + + cancel_delayed_work_sync(&max98090->pll_det_enable_work); + + /* Disable PLL unlock interrupt */ + snd_soc_update_bits(codec, M98090_REG_INTERRUPT_S, + M98090_IULK_MASK, 0); +} + +static void max98090_pll_work(struct work_struct *work) +{ + struct max98090_priv *max98090 = + container_of(work, struct max98090_priv, pll_work); + struct snd_soc_codec *codec = max98090->codec; + + if (!snd_soc_codec_is_active(codec)) + return; + + dev_info(codec->dev, "PLL unlocked\n"); + + /* Toggle shutdown OFF then ON */ + snd_soc_update_bits(codec, M98090_REG_DEVICE_SHUTDOWN, + M98090_SHDNN_MASK, 0); + msleep(10); + snd_soc_update_bits(codec, M98090_REG_DEVICE_SHUTDOWN, + M98090_SHDNN_MASK, M98090_SHDNN_MASK); + + /* Give PLL time to lock */ + msleep(10); +} + static void max98090_jack_work(struct work_struct *work) { struct max98090_priv *max98090 = container_of(work, @@ -2103,8 +2199,10 @@ static irqreturn_t max98090_interrupt(int irq, void *data) if (active & M98090_SLD_MASK) dev_dbg(codec->dev, "M98090_SLD_MASK\n"); - if (active & M98090_ULK_MASK) - dev_err(codec->dev, "M98090_ULK_MASK\n"); + if (active & M98090_ULK_MASK) { + dev_dbg(codec->dev, "M98090_ULK_MASK\n"); + schedule_work(&max98090->pll_work); + } if (active & M98090_JDET_MASK) { dev_dbg(codec->dev, "M98090_JDET_MASK\n"); @@ -2177,6 +2275,7 @@ static struct snd_soc_dai_ops max98090_dai_ops = { .set_tdm_slot = max98090_set_tdm_slot, .hw_params = max98090_dai_hw_params, .digital_mute = max98090_dai_digital_mute, + .trigger = max98090_dai_trigger, }; static struct snd_soc_dai_driver max98090_dai[] = { @@ -2258,6 +2357,11 @@ static int max98090_probe(struct snd_soc_codec *codec) max98090->jack_state = M98090_JACK_STATE_NO_HEADSET; INIT_DELAYED_WORK(&max98090->jack_work, max98090_jack_work); + INIT_DELAYED_WORK(&max98090->pll_det_enable_work, + max98090_pll_det_enable_work); + INIT_WORK(&max98090->pll_det_disable_work, + max98090_pll_det_disable_work); + INIT_WORK(&max98090->pll_work, max98090_pll_work); /* Enable jack detection */ snd_soc_write(codec, M98090_REG_JACK_DETECT, @@ -2310,6 +2414,9 @@ static int max98090_remove(struct snd_soc_codec *codec) struct max98090_priv *max98090 = snd_soc_codec_get_drvdata(codec); cancel_delayed_work_sync(&max98090->jack_work); + cancel_delayed_work_sync(&max98090->pll_det_enable_work); + cancel_work_sync(&max98090->pll_det_disable_work); + cancel_work_sync(&max98090->pll_work); return 0; } diff --git a/sound/soc/codecs/max98090.h b/sound/soc/codecs/max98090.h index cf1b6062ba8c..14427a566f41 100644 --- a/sound/soc/codecs/max98090.h +++ b/sound/soc/codecs/max98090.h @@ -1532,6 +1532,9 @@ struct max98090_priv { int irq; int jack_state; struct delayed_work jack_work; + struct delayed_work pll_det_enable_work; + struct work_struct pll_det_disable_work; + struct work_struct pll_work; struct snd_soc_jack *jack; unsigned int dai_fmt; int tdm_slots; diff --git a/sound/soc/intel/Makefile b/sound/soc/intel/Makefile index 7acbfc43a0c6..f841786dad15 100644 --- a/sound/soc/intel/Makefile +++ b/sound/soc/intel/Makefile @@ -2,7 +2,8 @@ snd-soc-sst-dsp-objs := sst-dsp.o sst-firmware.o snd-soc-sst-acpi-objs := sst-acpi.o -snd-soc-sst-mfld-platform-objs := sst-mfld-platform-pcm.o sst-mfld-platform-compress.o +snd-soc-sst-mfld-platform-objs := sst-mfld-platform-pcm.o \ + sst-mfld-platform-compress.o sst-atom-controls.o snd-soc-mfld-machine-objs := mfld_machine.o obj-$(CONFIG_SND_SST_MFLD_PLATFORM) += snd-soc-sst-mfld-platform.o diff --git a/sound/soc/intel/byt-max98090.c b/sound/soc/intel/byt-max98090.c index b8b8af571ef1..d52681e7225e 100644 --- a/sound/soc/intel/byt-max98090.c +++ b/sound/soc/intel/byt-max98090.c @@ -139,6 +139,7 @@ static struct snd_soc_card byt_max98090_card = { .num_dapm_routes = ARRAY_SIZE(byt_max98090_audio_map), .controls = byt_max98090_controls, .num_controls = ARRAY_SIZE(byt_max98090_controls), + .fully_routed = true, }; static int byt_max98090_probe(struct platform_device *pdev) diff --git a/sound/soc/intel/byt-rt5640.c b/sound/soc/intel/byt-rt5640.c index 234a58de3c53..c323a101214e 100644 --- a/sound/soc/intel/byt-rt5640.c +++ b/sound/soc/intel/byt-rt5640.c @@ -17,6 +17,7 @@ #include <linux/platform_device.h> #include <linux/acpi.h> #include <linux/device.h> +#include <linux/dmi.h> #include <linux/slab.h> #include <sound/pcm.h> #include <sound/pcm_params.h> @@ -36,8 +37,6 @@ static const struct snd_soc_dapm_widget byt_rt5640_widgets[] = { static const struct snd_soc_dapm_route byt_rt5640_audio_map[] = { {"Headset Mic", NULL, "MICBIAS1"}, {"IN2P", NULL, "Headset Mic"}, - {"IN2N", NULL, "Headset Mic"}, - {"DMIC1", NULL, "Internal Mic"}, {"Headphone", NULL, "HPOL"}, {"Headphone", NULL, "HPOR"}, {"Speaker", NULL, "SPOLP"}, @@ -46,6 +45,22 @@ static const struct snd_soc_dapm_route byt_rt5640_audio_map[] = { {"Speaker", NULL, "SPORN"}, }; +static const struct snd_soc_dapm_route byt_rt5640_intmic_dmic1_map[] = { + {"DMIC1", NULL, "Internal Mic"}, +}; + +static const struct snd_soc_dapm_route byt_rt5640_intmic_in1_map[] = { + {"Internal Mic", NULL, "MICBIAS1"}, + {"IN1P", NULL, "Internal Mic"}, +}; + +enum { + BYT_RT5640_DMIC1_MAP, + BYT_RT5640_IN1_MAP, +}; + +static unsigned long byt_rt5640_custom_map = BYT_RT5640_DMIC1_MAP; + static const struct snd_kcontrol_new byt_rt5640_controls[] = { SOC_DAPM_PIN_SWITCH("Headphone"), SOC_DAPM_PIN_SWITCH("Headset Mic"), @@ -77,12 +92,32 @@ static int byt_rt5640_hw_params(struct snd_pcm_substream *substream, return 0; } +static int byt_rt5640_quirk_cb(const struct dmi_system_id *id) +{ + byt_rt5640_custom_map = (unsigned long)id->driver_data; + return 1; +} + +static const struct dmi_system_id byt_rt5640_quirk_table[] = { + { + .callback = byt_rt5640_quirk_cb, + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."), + DMI_MATCH(DMI_PRODUCT_NAME, "T100TA"), + }, + .driver_data = (unsigned long *)BYT_RT5640_IN1_MAP, + }, + {} +}; + static int byt_rt5640_init(struct snd_soc_pcm_runtime *runtime) { int ret; struct snd_soc_codec *codec = runtime->codec; struct snd_soc_dapm_context *dapm = &codec->dapm; struct snd_soc_card *card = runtime->card; + const struct snd_soc_dapm_route *custom_map; + int num_routes; card->dapm.idle_bias_off = true; @@ -93,6 +128,21 @@ static int byt_rt5640_init(struct snd_soc_pcm_runtime *runtime) return ret; } + dmi_check_system(byt_rt5640_quirk_table); + switch (byt_rt5640_custom_map) { + case BYT_RT5640_IN1_MAP: + custom_map = byt_rt5640_intmic_in1_map; + num_routes = ARRAY_SIZE(byt_rt5640_intmic_in1_map); + break; + default: + custom_map = byt_rt5640_intmic_dmic1_map; + num_routes = ARRAY_SIZE(byt_rt5640_intmic_dmic1_map); + }; + + ret = snd_soc_dapm_add_routes(dapm, custom_map, num_routes); + if (ret) + return ret; + snd_soc_dapm_ignore_suspend(dapm, "HPOL"); snd_soc_dapm_ignore_suspend(dapm, "HPOR"); diff --git a/sound/soc/intel/sst-atom-controls.c b/sound/soc/intel/sst-atom-controls.c new file mode 100644 index 000000000000..7104a34181a9 --- /dev/null +++ b/sound/soc/intel/sst-atom-controls.c @@ -0,0 +1,218 @@ +/* + * sst-atom-controls.c - Intel MID Platform driver DPCM ALSA controls for Mrfld + * + * Copyright (C) 2013-14 Intel Corp + * Author: Omair Mohammed Abdullah <omair.m.abdullah@intel.com> + * Vinod Koul <vinod.koul@intel.com> + * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + */ +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + +#include <linux/slab.h> +#include <sound/soc.h> +#include <sound/tlv.h> +#include "sst-mfld-platform.h" +#include "sst-atom-controls.h" + +static int sst_fill_byte_control(struct sst_data *drv, + u8 ipc_msg, u8 block, + u8 task_id, u8 pipe_id, + u16 len, void *cmd_data) +{ + struct snd_sst_bytes_v2 *byte_data = drv->byte_stream; + + byte_data->type = SST_CMD_BYTES_SET; + byte_data->ipc_msg = ipc_msg; + byte_data->block = block; + byte_data->task_id = task_id; + byte_data->pipe_id = pipe_id; + + if (len > SST_MAX_BIN_BYTES - sizeof(*byte_data)) { + dev_err(&drv->pdev->dev, "command length too big (%u)", len); + return -EINVAL; + } + byte_data->len = len; + memcpy(byte_data->bytes, cmd_data, len); + print_hex_dump_bytes("writing to lpe: ", DUMP_PREFIX_OFFSET, + byte_data, len + sizeof(*byte_data)); + return 0; +} + +static int sst_fill_and_send_cmd_unlocked(struct sst_data *drv, + u8 ipc_msg, u8 block, u8 task_id, u8 pipe_id, + void *cmd_data, u16 len) +{ + int ret = 0; + + ret = sst_fill_byte_control(drv, ipc_msg, + block, task_id, pipe_id, len, cmd_data); + if (ret < 0) + return ret; + return sst->ops->send_byte_stream(sst->dev, drv->byte_stream); +} + +/** + * sst_fill_and_send_cmd - generate the IPC message and send it to the FW + * @ipc_msg: type of IPC (CMD, SET_PARAMS, GET_PARAMS) + * @cmd_data: the IPC payload + */ +static int sst_fill_and_send_cmd(struct sst_data *drv, + u8 ipc_msg, u8 block, u8 task_id, u8 pipe_id, + void *cmd_data, u16 len) +{ + int ret; + + mutex_lock(&drv->lock); + ret = sst_fill_and_send_cmd_unlocked(drv, ipc_msg, block, + task_id, pipe_id, cmd_data, len); + mutex_unlock(&drv->lock); + + return ret; +} + +static int sst_send_algo_cmd(struct sst_data *drv, + struct sst_algo_control *bc) +{ + int len, ret = 0; + struct sst_cmd_set_params *cmd; + + /*bc->max includes sizeof algos + length field*/ + len = sizeof(cmd->dst) + sizeof(cmd->command_id) + bc->max; + + cmd = kzalloc(len, GFP_KERNEL); + if (cmd == NULL) + return -ENOMEM; + + SST_FILL_DESTINATION(2, cmd->dst, bc->pipe_id, bc->module_id); + cmd->command_id = bc->cmd_id; + memcpy(cmd->params, bc->params, bc->max); + + ret = sst_fill_and_send_cmd_unlocked(drv, SST_IPC_IA_SET_PARAMS, + SST_FLAG_BLOCKED, bc->task_id, 0, cmd, len); + kfree(cmd); + return ret; +} + +static int sst_algo_bytes_ctl_info(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_info *uinfo) +{ + struct sst_algo_control *bc = (void *)kcontrol->private_value; + + uinfo->type = SNDRV_CTL_ELEM_TYPE_BYTES; + uinfo->count = bc->max; + + return 0; +} + +static int sst_algo_control_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct sst_algo_control *bc = (void *)kcontrol->private_value; + struct snd_soc_component *component = snd_kcontrol_chip(kcontrol); + + switch (bc->type) { + case SST_ALGO_PARAMS: + memcpy(ucontrol->value.bytes.data, bc->params, bc->max); + break; + default: + dev_err(component->dev, "Invalid Input- algo type:%d\n", + bc->type); + return -EINVAL; + + } + return 0; +} + +static int sst_algo_control_set(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + int ret = 0; + struct snd_soc_component *cmpnt = snd_soc_kcontrol_component(kcontrol); + struct sst_data *drv = snd_soc_component_get_drvdata(cmpnt); + struct sst_algo_control *bc = (void *)kcontrol->private_value; + + dev_dbg(cmpnt->dev, "control_name=%s\n", kcontrol->id.name); + mutex_lock(&drv->lock); + switch (bc->type) { + case SST_ALGO_PARAMS: + memcpy(bc->params, ucontrol->value.bytes.data, bc->max); + break; + default: + mutex_unlock(&drv->lock); + dev_err(cmpnt->dev, "Invalid Input- algo type:%d\n", + bc->type); + return -EINVAL; + } + /*if pipe is enabled, need to send the algo params from here*/ + if (bc->w && bc->w->power) + ret = sst_send_algo_cmd(drv, bc); + mutex_unlock(&drv->lock); + + return ret; +} + +static const struct snd_kcontrol_new sst_algo_controls[] = { + SST_ALGO_KCONTROL_BYTES("media_loop1_out", "fir", 272, SST_MODULE_ID_FIR_24, + SST_PATH_INDEX_MEDIA_LOOP1_OUT, 0, SST_TASK_SBA, SBA_VB_SET_FIR), + SST_ALGO_KCONTROL_BYTES("media_loop1_out", "iir", 300, SST_MODULE_ID_IIR_24, + SST_PATH_INDEX_MEDIA_LOOP1_OUT, 0, SST_TASK_SBA, SBA_VB_SET_IIR), + SST_ALGO_KCONTROL_BYTES("media_loop1_out", "mdrp", 286, SST_MODULE_ID_MDRP, + SST_PATH_INDEX_MEDIA_LOOP1_OUT, 0, SST_TASK_SBA, SBA_SET_MDRP), + SST_ALGO_KCONTROL_BYTES("media_loop2_out", "fir", 272, SST_MODULE_ID_FIR_24, + SST_PATH_INDEX_MEDIA_LOOP2_OUT, 0, SST_TASK_SBA, SBA_VB_SET_FIR), + SST_ALGO_KCONTROL_BYTES("media_loop2_out", "iir", 300, SST_MODULE_ID_IIR_24, + SST_PATH_INDEX_MEDIA_LOOP2_OUT, 0, SST_TASK_SBA, SBA_VB_SET_IIR), + SST_ALGO_KCONTROL_BYTES("media_loop2_out", "mdrp", 286, SST_MODULE_ID_MDRP, + SST_PATH_INDEX_MEDIA_LOOP2_OUT, 0, SST_TASK_SBA, SBA_SET_MDRP), + SST_ALGO_KCONTROL_BYTES("sprot_loop_out", "lpro", 192, SST_MODULE_ID_SPROT, + SST_PATH_INDEX_SPROT_LOOP_OUT, 0, SST_TASK_SBA, SBA_VB_LPRO), + SST_ALGO_KCONTROL_BYTES("codec_in0", "dcr", 52, SST_MODULE_ID_FILT_DCR, + SST_PATH_INDEX_CODEC_IN0, 0, SST_TASK_SBA, SBA_VB_SET_IIR), + SST_ALGO_KCONTROL_BYTES("codec_in1", "dcr", 52, SST_MODULE_ID_FILT_DCR, + SST_PATH_INDEX_CODEC_IN1, 0, SST_TASK_SBA, SBA_VB_SET_IIR), + +}; + +static int sst_algo_control_init(struct device *dev) +{ + int i = 0; + struct sst_algo_control *bc; + /*allocate space to cache the algo parameters in the driver*/ + for (i = 0; i < ARRAY_SIZE(sst_algo_controls); i++) { + bc = (struct sst_algo_control *)sst_algo_controls[i].private_value; + bc->params = devm_kzalloc(dev, bc->max, GFP_KERNEL); + if (bc->params == NULL) + return -ENOMEM; + } + return 0; +} + +int sst_dsp_init_v2_dpcm(struct snd_soc_platform *platform) +{ + int ret = 0; + struct sst_data *drv = snd_soc_platform_get_drvdata(platform); + + drv->byte_stream = devm_kzalloc(platform->dev, + SST_MAX_BIN_BYTES, GFP_KERNEL); + if (!drv->byte_stream) + return -ENOMEM; + + /*Initialize algo control params*/ + ret = sst_algo_control_init(platform->dev); + if (ret) + return ret; + ret = snd_soc_add_platform_controls(platform, sst_algo_controls, + ARRAY_SIZE(sst_algo_controls)); + return ret; +} diff --git a/sound/soc/intel/sst-atom-controls.h b/sound/soc/intel/sst-atom-controls.h index 14063ab8c7c5..a73e894b175c 100644 --- a/sound/soc/intel/sst-atom-controls.h +++ b/sound/soc/intel/sst-atom-controls.h @@ -1,4 +1,6 @@ /* + * sst-atom-controls.h - Intel MID Platform driver header file + * * Copyright (C) 2013-14 Intel Corp * Author: Ramesh Babu <ramesh.babu.koul@intel.com> * Omair M Abdullah <omair.m.abdullah@intel.com> @@ -18,13 +20,423 @@ * */ -#ifndef __SST_CONTROLS_V2_H__ -#define __SST_CONTROLS_V2_H__ +#ifndef __SST_ATOM_CONTROLS_H__ +#define __SST_ATOM_CONTROLS_H__ enum { MERR_DPCM_AUDIO = 0, MERR_DPCM_COMPR, }; +/* define a bit for each mixer input */ +#define SST_MIX_IP(x) (x) + +#define SST_IP_CODEC0 SST_MIX_IP(2) +#define SST_IP_CODEC1 SST_MIX_IP(3) +#define SST_IP_LOOP0 SST_MIX_IP(4) +#define SST_IP_LOOP1 SST_MIX_IP(5) +#define SST_IP_LOOP2 SST_MIX_IP(6) +#define SST_IP_PROBE SST_MIX_IP(7) +#define SST_IP_VOIP SST_MIX_IP(12) +#define SST_IP_PCM0 SST_MIX_IP(13) +#define SST_IP_PCM1 SST_MIX_IP(14) +#define SST_IP_MEDIA0 SST_MIX_IP(17) +#define SST_IP_MEDIA1 SST_MIX_IP(18) +#define SST_IP_MEDIA2 SST_MIX_IP(19) +#define SST_IP_MEDIA3 SST_MIX_IP(20) + +#define SST_IP_LAST SST_IP_MEDIA3 + +#define SST_SWM_INPUT_COUNT (SST_IP_LAST + 1) +#define SST_CMD_SWM_MAX_INPUTS 6 + +#define SST_PATH_ID_SHIFT 8 +#define SST_DEFAULT_LOCATION_ID 0xFFFF +#define SST_DEFAULT_CELL_NBR 0xFF +#define SST_DEFAULT_MODULE_ID 0xFFFF + +/* + * Audio DSP Path Ids. Specified by the audio DSP FW + */ +enum sst_path_index { + SST_PATH_INDEX_CODEC_OUT0 = (0x02 << SST_PATH_ID_SHIFT), + SST_PATH_INDEX_CODEC_OUT1 = (0x03 << SST_PATH_ID_SHIFT), + + SST_PATH_INDEX_SPROT_LOOP_OUT = (0x04 << SST_PATH_ID_SHIFT), + SST_PATH_INDEX_MEDIA_LOOP1_OUT = (0x05 << SST_PATH_ID_SHIFT), + SST_PATH_INDEX_MEDIA_LOOP2_OUT = (0x06 << SST_PATH_ID_SHIFT), + + SST_PATH_INDEX_VOIP_OUT = (0x0C << SST_PATH_ID_SHIFT), + SST_PATH_INDEX_PCM0_OUT = (0x0D << SST_PATH_ID_SHIFT), + SST_PATH_INDEX_PCM1_OUT = (0x0E << SST_PATH_ID_SHIFT), + SST_PATH_INDEX_PCM2_OUT = (0x0F << SST_PATH_ID_SHIFT), + + SST_PATH_INDEX_MEDIA0_OUT = (0x12 << SST_PATH_ID_SHIFT), + SST_PATH_INDEX_MEDIA1_OUT = (0x13 << SST_PATH_ID_SHIFT), + + + /* Start of input paths */ + SST_PATH_INDEX_CODEC_IN0 = (0x82 << SST_PATH_ID_SHIFT), + SST_PATH_INDEX_CODEC_IN1 = (0x83 << SST_PATH_ID_SHIFT), + + SST_PATH_INDEX_SPROT_LOOP_IN = (0x84 << SST_PATH_ID_SHIFT), + SST_PATH_INDEX_MEDIA_LOOP1_IN = (0x85 << SST_PATH_ID_SHIFT), + SST_PATH_INDEX_MEDIA_LOOP2_IN = (0x86 << SST_PATH_ID_SHIFT), + + SST_PATH_INDEX_VOIP_IN = (0x8C << SST_PATH_ID_SHIFT), + + SST_PATH_INDEX_PCM0_IN = (0x8D << SST_PATH_ID_SHIFT), + SST_PATH_INDEX_PCM1_IN = (0x8E << SST_PATH_ID_SHIFT), + + SST_PATH_INDEX_MEDIA0_IN = (0x8F << SST_PATH_ID_SHIFT), + SST_PATH_INDEX_MEDIA1_IN = (0x90 << SST_PATH_ID_SHIFT), + SST_PATH_INDEX_MEDIA2_IN = (0x91 << SST_PATH_ID_SHIFT), + + SST_PATH_INDEX_MEDIA3_IN = (0x9C << SST_PATH_ID_SHIFT), + + SST_PATH_INDEX_RESERVED = (0xFF << SST_PATH_ID_SHIFT), +}; + +/* + * path IDs + */ +enum sst_swm_inputs { + SST_SWM_IN_CODEC0 = (SST_PATH_INDEX_CODEC_IN0 | SST_DEFAULT_CELL_NBR), + SST_SWM_IN_CODEC1 = (SST_PATH_INDEX_CODEC_IN1 | SST_DEFAULT_CELL_NBR), + SST_SWM_IN_SPROT_LOOP = (SST_PATH_INDEX_SPROT_LOOP_IN | SST_DEFAULT_CELL_NBR), + SST_SWM_IN_MEDIA_LOOP1 = (SST_PATH_INDEX_MEDIA_LOOP1_IN | SST_DEFAULT_CELL_NBR), + SST_SWM_IN_MEDIA_LOOP2 = (SST_PATH_INDEX_MEDIA_LOOP2_IN | SST_DEFAULT_CELL_NBR), + SST_SWM_IN_VOIP = (SST_PATH_INDEX_VOIP_IN | SST_DEFAULT_CELL_NBR), + SST_SWM_IN_PCM0 = (SST_PATH_INDEX_PCM0_IN | SST_DEFAULT_CELL_NBR), + SST_SWM_IN_PCM1 = (SST_PATH_INDEX_PCM1_IN | SST_DEFAULT_CELL_NBR), + SST_SWM_IN_MEDIA0 = (SST_PATH_INDEX_MEDIA0_IN | SST_DEFAULT_CELL_NBR), /* Part of Media Mixer */ + SST_SWM_IN_MEDIA1 = (SST_PATH_INDEX_MEDIA1_IN | SST_DEFAULT_CELL_NBR), /* Part of Media Mixer */ + SST_SWM_IN_MEDIA2 = (SST_PATH_INDEX_MEDIA2_IN | SST_DEFAULT_CELL_NBR), /* Part of Media Mixer */ + SST_SWM_IN_MEDIA3 = (SST_PATH_INDEX_MEDIA3_IN | SST_DEFAULT_CELL_NBR), /* Part of Media Mixer */ + SST_SWM_IN_END = (SST_PATH_INDEX_RESERVED | SST_DEFAULT_CELL_NBR) +}; + +/* + * path IDs + */ +enum sst_swm_outputs { + SST_SWM_OUT_CODEC0 = (SST_PATH_INDEX_CODEC_OUT0 | SST_DEFAULT_CELL_NBR), + SST_SWM_OUT_CODEC1 = (SST_PATH_INDEX_CODEC_OUT1 | SST_DEFAULT_CELL_NBR), + SST_SWM_OUT_SPROT_LOOP = (SST_PATH_INDEX_SPROT_LOOP_OUT | SST_DEFAULT_CELL_NBR), + SST_SWM_OUT_MEDIA_LOOP1 = (SST_PATH_INDEX_MEDIA_LOOP1_OUT | SST_DEFAULT_CELL_NBR), + SST_SWM_OUT_MEDIA_LOOP2 = (SST_PATH_INDEX_MEDIA_LOOP2_OUT | SST_DEFAULT_CELL_NBR), + SST_SWM_OUT_VOIP = (SST_PATH_INDEX_VOIP_OUT | SST_DEFAULT_CELL_NBR), + SST_SWM_OUT_PCM0 = (SST_PATH_INDEX_PCM0_OUT | SST_DEFAULT_CELL_NBR), + SST_SWM_OUT_PCM1 = (SST_PATH_INDEX_PCM1_OUT | SST_DEFAULT_CELL_NBR), + SST_SWM_OUT_PCM2 = (SST_PATH_INDEX_PCM2_OUT | SST_DEFAULT_CELL_NBR), + SST_SWM_OUT_MEDIA0 = (SST_PATH_INDEX_MEDIA0_OUT | SST_DEFAULT_CELL_NBR), /* Part of Media Mixer */ + SST_SWM_OUT_MEDIA1 = (SST_PATH_INDEX_MEDIA1_OUT | SST_DEFAULT_CELL_NBR), /* Part of Media Mixer */ + SST_SWM_OUT_END = (SST_PATH_INDEX_RESERVED | SST_DEFAULT_CELL_NBR), +}; + +enum sst_ipc_msg { + SST_IPC_IA_CMD = 1, + SST_IPC_IA_SET_PARAMS, + SST_IPC_IA_GET_PARAMS, +}; + +enum sst_cmd_type { + SST_CMD_BYTES_SET = 1, + SST_CMD_BYTES_GET = 2, +}; + +enum sst_task { + SST_TASK_SBA = 1, + SST_TASK_MMX, +}; + +enum sst_type { + SST_TYPE_CMD = 1, + SST_TYPE_PARAMS, +}; + +enum sst_flag { + SST_FLAG_BLOCKED = 1, + SST_FLAG_NONBLOCK, +}; + +/* + * Enumeration for indexing the gain cells in VB_SET_GAIN DSP command + */ +enum sst_gain_index { + /* GAIN IDs for SB task start here */ + SST_GAIN_INDEX_CODEC_OUT0, + SST_GAIN_INDEX_CODEC_OUT1, + SST_GAIN_INDEX_CODEC_IN0, + SST_GAIN_INDEX_CODEC_IN1, + + SST_GAIN_INDEX_SPROT_LOOP_OUT, + SST_GAIN_INDEX_MEDIA_LOOP1_OUT, + SST_GAIN_INDEX_MEDIA_LOOP2_OUT, + + SST_GAIN_INDEX_PCM0_IN_LEFT, + SST_GAIN_INDEX_PCM0_IN_RIGHT, + + SST_GAIN_INDEX_PCM1_OUT_LEFT, + SST_GAIN_INDEX_PCM1_OUT_RIGHT, + SST_GAIN_INDEX_PCM1_IN_LEFT, + SST_GAIN_INDEX_PCM1_IN_RIGHT, + SST_GAIN_INDEX_PCM2_OUT_LEFT, + + SST_GAIN_INDEX_PCM2_OUT_RIGHT, + SST_GAIN_INDEX_VOIP_OUT, + SST_GAIN_INDEX_VOIP_IN, + + /* Gain IDs for MMX task start here */ + SST_GAIN_INDEX_MEDIA0_IN_LEFT, + SST_GAIN_INDEX_MEDIA0_IN_RIGHT, + SST_GAIN_INDEX_MEDIA1_IN_LEFT, + SST_GAIN_INDEX_MEDIA1_IN_RIGHT, + + SST_GAIN_INDEX_MEDIA2_IN_LEFT, + SST_GAIN_INDEX_MEDIA2_IN_RIGHT, + + SST_GAIN_INDEX_GAIN_END +}; + +/* + * Audio DSP module IDs specified by FW spec + * TODO: Update with all modules + */ +enum sst_module_id { + SST_MODULE_ID_PCM = 0x0001, + SST_MODULE_ID_MP3 = 0x0002, + SST_MODULE_ID_MP24 = 0x0003, + SST_MODULE_ID_AAC = 0x0004, + SST_MODULE_ID_AACP = 0x0005, + SST_MODULE_ID_EAACP = 0x0006, + SST_MODULE_ID_WMA9 = 0x0007, + SST_MODULE_ID_WMA10 = 0x0008, + SST_MODULE_ID_WMA10P = 0x0009, + SST_MODULE_ID_RA = 0x000A, + SST_MODULE_ID_DDAC3 = 0x000B, + SST_MODULE_ID_TRUE_HD = 0x000C, + SST_MODULE_ID_HD_PLUS = 0x000D, + + SST_MODULE_ID_SRC = 0x0064, + SST_MODULE_ID_DOWNMIX = 0x0066, + SST_MODULE_ID_GAIN_CELL = 0x0067, + SST_MODULE_ID_SPROT = 0x006D, + SST_MODULE_ID_BASS_BOOST = 0x006E, + SST_MODULE_ID_STEREO_WDNG = 0x006F, + SST_MODULE_ID_AV_REMOVAL = 0x0070, + SST_MODULE_ID_MIC_EQ = 0x0071, + SST_MODULE_ID_SPL = 0x0072, + SST_MODULE_ID_ALGO_VTSV = 0x0073, + SST_MODULE_ID_NR = 0x0076, + SST_MODULE_ID_BWX = 0x0077, + SST_MODULE_ID_DRP = 0x0078, + SST_MODULE_ID_MDRP = 0x0079, + + SST_MODULE_ID_ANA = 0x007A, + SST_MODULE_ID_AEC = 0x007B, + SST_MODULE_ID_NR_SNS = 0x007C, + SST_MODULE_ID_SER = 0x007D, + SST_MODULE_ID_AGC = 0x007E, + + SST_MODULE_ID_CNI = 0x007F, + SST_MODULE_ID_CONTEXT_ALGO_AWARE = 0x0080, + SST_MODULE_ID_FIR_24 = 0x0081, + SST_MODULE_ID_IIR_24 = 0x0082, + + SST_MODULE_ID_ASRC = 0x0083, + SST_MODULE_ID_TONE_GEN = 0x0084, + SST_MODULE_ID_BMF = 0x0086, + SST_MODULE_ID_EDL = 0x0087, + SST_MODULE_ID_GLC = 0x0088, + + SST_MODULE_ID_FIR_16 = 0x0089, + SST_MODULE_ID_IIR_16 = 0x008A, + SST_MODULE_ID_DNR = 0x008B, + + SST_MODULE_ID_VIRTUALIZER = 0x008C, + SST_MODULE_ID_VISUALIZATION = 0x008D, + SST_MODULE_ID_LOUDNESS_OPTIMIZER = 0x008E, + SST_MODULE_ID_REVERBERATION = 0x008F, + + SST_MODULE_ID_CNI_TX = 0x0090, + SST_MODULE_ID_REF_LINE = 0x0091, + SST_MODULE_ID_VOLUME = 0x0092, + SST_MODULE_ID_FILT_DCR = 0x0094, + SST_MODULE_ID_SLV = 0x009A, + SST_MODULE_ID_NLF = 0x009B, + SST_MODULE_ID_TNR = 0x009C, + SST_MODULE_ID_WNR = 0x009D, + + SST_MODULE_ID_LOG = 0xFF00, + + SST_MODULE_ID_TASK = 0xFFFF, +}; + +enum sst_cmd { + SBA_IDLE = 14, + SBA_VB_SET_SPEECH_PATH = 26, + MMX_SET_GAIN = 33, + SBA_VB_SET_GAIN = 33, + FBA_VB_RX_CNI = 35, + MMX_SET_GAIN_TIMECONST = 36, + SBA_VB_SET_TIMECONST = 36, + SBA_VB_START = 85, + SBA_SET_SWM = 114, + SBA_SET_MDRP = 116, + SBA_HW_SET_SSP = 117, + SBA_SET_MEDIA_LOOP_MAP = 118, + SBA_SET_MEDIA_PATH = 119, + MMX_SET_MEDIA_PATH = 119, + SBA_VB_LPRO = 126, + SBA_VB_SET_FIR = 128, + SBA_VB_SET_IIR = 129, + SBA_SET_SSP_SLOT_MAP = 130, +}; + +enum sst_dsp_switch { + SST_SWITCH_OFF = 0, + SST_SWITCH_ON = 3, +}; + +enum sst_path_switch { + SST_PATH_OFF = 0, + SST_PATH_ON = 1, +}; + +enum sst_swm_state { + SST_SWM_OFF = 0, + SST_SWM_ON = 3, +}; + +#define SST_FILL_LOCATION_IDS(dst, cell_idx, pipe_id) do { \ + dst.location_id.p.cell_nbr_idx = (cell_idx); \ + dst.location_id.p.path_id = (pipe_id); \ + } while (0) +#define SST_FILL_LOCATION_ID(dst, loc_id) (\ + dst.location_id.f = (loc_id)) +#define SST_FILL_MODULE_ID(dst, mod_id) (\ + dst.module_id = (mod_id)) + +#define SST_FILL_DESTINATION1(dst, id) do { \ + SST_FILL_LOCATION_ID(dst, (id) & 0xFFFF); \ + SST_FILL_MODULE_ID(dst, ((id) & 0xFFFF0000) >> 16); \ + } while (0) +#define SST_FILL_DESTINATION2(dst, loc_id, mod_id) do { \ + SST_FILL_LOCATION_ID(dst, loc_id); \ + SST_FILL_MODULE_ID(dst, mod_id); \ + } while (0) +#define SST_FILL_DESTINATION3(dst, cell_idx, path_id, mod_id) do { \ + SST_FILL_LOCATION_IDS(dst, cell_idx, path_id); \ + SST_FILL_MODULE_ID(dst, mod_id); \ + } while (0) + +#define SST_FILL_DESTINATION(level, dst, ...) \ + SST_FILL_DESTINATION##level(dst, __VA_ARGS__) +#define SST_FILL_DEFAULT_DESTINATION(dst) \ + SST_FILL_DESTINATION(2, dst, SST_DEFAULT_LOCATION_ID, SST_DEFAULT_MODULE_ID) + +struct sst_destination_id { + union sst_location_id { + struct { + u8 cell_nbr_idx; /* module index */ + u8 path_id; /* pipe_id */ + } __packed p; /* part */ + u16 f; /* full */ + } __packed location_id; + u16 module_id; +} __packed; +struct sst_dsp_header { + struct sst_destination_id dst; + u16 command_id; + u16 length; +} __packed; + +/* + * + * Common Commands + * + */ +struct sst_cmd_generic { + struct sst_dsp_header header; +} __packed; +struct sst_cmd_set_params { + struct sst_destination_id dst; + u16 command_id; + char params[0]; +} __packed; +#define SST_CONTROL_NAME(xpname, xmname, xinstance, xtype) \ + xpname " " xmname " " #xinstance " " xtype + +#define SST_COMBO_CONTROL_NAME(xpname, xmname, xinstance, xtype, xsubmodule) \ + xpname " " xmname " " #xinstance " " xtype " " xsubmodule +enum sst_algo_kcontrol_type { + SST_ALGO_PARAMS, + SST_ALGO_BYPASS, +}; + +struct sst_algo_control { + enum sst_algo_kcontrol_type type; + int max; + u16 module_id; + u16 pipe_id; + u16 task_id; + u16 cmd_id; + bool bypass; + unsigned char *params; + struct snd_soc_dapm_widget *w; +}; + +/* size of the control = size of params + size of length field */ +#define SST_ALGO_CTL_VALUE(xcount, xtype, xpipe, xmod, xtask, xcmd) \ + (struct sst_algo_control){ \ + .max = xcount + sizeof(u16), .type = xtype, .module_id = xmod, \ + .pipe_id = xpipe, .task_id = xtask, .cmd_id = xcmd, \ + } + +#define SST_ALGO_KCONTROL(xname, xcount, xmod, xpipe, \ + xtask, xcmd, xtype, xinfo, xget, xput) \ +{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \ + .name = xname, \ + .info = xinfo, .get = xget, .put = xput, \ + .private_value = (unsigned long)& \ + SST_ALGO_CTL_VALUE(xcount, xtype, xpipe, \ + xmod, xtask, xcmd), \ +} + +#define SST_ALGO_KCONTROL_BYTES(xpname, xmname, xcount, xmod, \ + xpipe, xinstance, xtask, xcmd) \ + SST_ALGO_KCONTROL(SST_CONTROL_NAME(xpname, xmname, xinstance, "params"), \ + xcount, xmod, xpipe, xtask, xcmd, SST_ALGO_PARAMS, \ + sst_algo_bytes_ctl_info, \ + sst_algo_control_get, sst_algo_control_set) + +#define SST_ALGO_KCONTROL_BOOL(xpname, xmname, xmod, xpipe, xinstance, xtask) \ + SST_ALGO_KCONTROL(SST_CONTROL_NAME(xpname, xmname, xinstance, "bypass"), \ + 0, xmod, xpipe, xtask, 0, SST_ALGO_BYPASS, \ + snd_soc_info_bool_ext, \ + sst_algo_control_get, sst_algo_control_set) + +#define SST_ALGO_BYPASS_PARAMS(xpname, xmname, xcount, xmod, xpipe, \ + xinstance, xtask, xcmd) \ + SST_ALGO_KCONTROL_BOOL(xpname, xmname, xmod, xpipe, xinstance, xtask), \ + SST_ALGO_KCONTROL_BYTES(xpname, xmname, xcount, xmod, xpipe, xinstance, xtask, xcmd) + +#define SST_COMBO_ALGO_KCONTROL_BYTES(xpname, xmname, xsubmod, xcount, xmod, \ + xpipe, xinstance, xtask, xcmd) \ + SST_ALGO_KCONTROL(SST_COMBO_CONTROL_NAME(xpname, xmname, xinstance, "params", \ + xsubmod), \ + xcount, xmod, xpipe, xtask, xcmd, SST_ALGO_PARAMS, \ + sst_algo_bytes_ctl_info, \ + sst_algo_control_get, sst_algo_control_set) + + +struct sst_enum { + bool tx; + unsigned short reg; + unsigned int max; + const char * const *texts; + struct snd_soc_dapm_widget *w; +}; #endif diff --git a/sound/soc/intel/sst-haswell-pcm.c b/sound/soc/intel/sst-haswell-pcm.c index 61bf6da4bb02..33fc5c3abf55 100644 --- a/sound/soc/intel/sst-haswell-pcm.c +++ b/sound/soc/intel/sst-haswell-pcm.c @@ -138,11 +138,10 @@ static inline unsigned int hsw_ipc_to_mixer(u32 value) static int hsw_stream_volume_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { - struct snd_soc_platform *platform = snd_soc_kcontrol_platform(kcontrol); + struct snd_soc_component *cmpnt = snd_soc_kcontrol_component(kcontrol); + struct hsw_priv_data *pdata = snd_soc_component_get_drvdata(cmpnt); struct soc_mixer_control *mc = (struct soc_mixer_control *)kcontrol->private_value; - struct hsw_priv_data *pdata = - snd_soc_platform_get_drvdata(platform); struct hsw_pcm_data *pcm_data = &pdata->pcm[mc->reg]; struct sst_hsw *hsw = pdata->hsw; u32 volume; @@ -176,11 +175,10 @@ static int hsw_stream_volume_put(struct snd_kcontrol *kcontrol, static int hsw_stream_volume_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { - struct snd_soc_platform *platform = snd_soc_kcontrol_platform(kcontrol); + struct snd_soc_component *cmpnt = snd_soc_kcontrol_component(kcontrol); + struct hsw_priv_data *pdata = snd_soc_component_get_drvdata(cmpnt); struct soc_mixer_control *mc = (struct soc_mixer_control *)kcontrol->private_value; - struct hsw_priv_data *pdata = - snd_soc_platform_get_drvdata(platform); struct hsw_pcm_data *pcm_data = &pdata->pcm[mc->reg]; struct sst_hsw *hsw = pdata->hsw; u32 volume; @@ -208,8 +206,8 @@ static int hsw_stream_volume_get(struct snd_kcontrol *kcontrol, static int hsw_volume_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { - struct snd_soc_platform *platform = snd_soc_kcontrol_platform(kcontrol); - struct hsw_priv_data *pdata = snd_soc_platform_get_drvdata(platform); + struct snd_soc_component *cmpnt = snd_soc_kcontrol_component(kcontrol); + struct hsw_priv_data *pdata = snd_soc_component_get_drvdata(cmpnt); struct sst_hsw *hsw = pdata->hsw; u32 volume; @@ -233,8 +231,8 @@ static int hsw_volume_put(struct snd_kcontrol *kcontrol, static int hsw_volume_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { - struct snd_soc_platform *platform = snd_soc_kcontrol_platform(kcontrol); - struct hsw_priv_data *pdata = snd_soc_platform_get_drvdata(platform); + struct snd_soc_component *cmpnt = snd_soc_kcontrol_component(kcontrol); + struct hsw_priv_data *pdata = snd_soc_component_get_drvdata(cmpnt); struct sst_hsw *hsw = pdata->hsw; unsigned int volume = 0; @@ -778,20 +776,11 @@ static const struct snd_soc_dapm_route graph[] = { static int hsw_pcm_probe(struct snd_soc_platform *platform) { + struct hsw_priv_data *priv_data = snd_soc_platform_get_drvdata(platform); struct sst_pdata *pdata = dev_get_platdata(platform->dev); - struct hsw_priv_data *priv_data; - struct device *dma_dev; + struct device *dma_dev = pdata->dma_dev; int i, ret = 0; - if (!pdata) - return -ENODEV; - - dma_dev = pdata->dma_dev; - - priv_data = devm_kzalloc(platform->dev, sizeof(*priv_data), GFP_KERNEL); - priv_data->hsw = pdata->dsp; - snd_soc_platform_set_drvdata(platform, priv_data); - /* allocate DSP buffer page tables */ for (i = 0; i < ARRAY_SIZE(hsw_dais); i++) { @@ -848,27 +837,38 @@ static struct snd_soc_platform_driver hsw_soc_platform = { .ops = &hsw_pcm_ops, .pcm_new = hsw_pcm_new, .pcm_free = hsw_pcm_free, - .controls = hsw_volume_controls, - .num_controls = ARRAY_SIZE(hsw_volume_controls), - .dapm_widgets = widgets, - .num_dapm_widgets = ARRAY_SIZE(widgets), - .dapm_routes = graph, - .num_dapm_routes = ARRAY_SIZE(graph), }; static const struct snd_soc_component_driver hsw_dai_component = { - .name = "haswell-dai", + .name = "haswell-dai", + .controls = hsw_volume_controls, + .num_controls = ARRAY_SIZE(hsw_volume_controls), + .dapm_widgets = widgets, + .num_dapm_widgets = ARRAY_SIZE(widgets), + .dapm_routes = graph, + .num_dapm_routes = ARRAY_SIZE(graph), }; static int hsw_pcm_dev_probe(struct platform_device *pdev) { struct sst_pdata *sst_pdata = dev_get_platdata(&pdev->dev); + struct hsw_priv_data *priv_data; int ret; + if (!sst_pdata) + return -EINVAL; + + priv_data = devm_kzalloc(&pdev->dev, sizeof(*priv_data), GFP_KERNEL); + if (!priv_data) + return -ENOMEM; + ret = sst_hsw_dsp_init(&pdev->dev, sst_pdata); if (ret < 0) return -ENODEV; + priv_data->hsw = sst_pdata->dsp; + platform_set_drvdata(pdev, priv_data); + ret = snd_soc_register_platform(&pdev->dev, &hsw_soc_platform); if (ret < 0) goto err_plat; diff --git a/sound/soc/intel/sst-mfld-platform-compress.c b/sound/soc/intel/sst-mfld-platform-compress.c index 29c059ca19e8..59467775c9b8 100644 --- a/sound/soc/intel/sst-mfld-platform-compress.c +++ b/sound/soc/intel/sst-mfld-platform-compress.c @@ -86,7 +86,7 @@ static int sst_platform_compr_free(struct snd_compr_stream *cstream) /*need to check*/ str_id = stream->id; if (str_id) - ret_val = stream->compr_ops->close(str_id); + ret_val = stream->compr_ops->close(sst->dev, str_id); module_put(sst->dev->driver->owner); kfree(stream); pr_debug("%s: %d\n", __func__, ret_val); @@ -158,7 +158,7 @@ static int sst_platform_compr_set_params(struct snd_compr_stream *cstream, cb.drain_cb_param = cstream; cb.drain_notify = sst_drain_notify; - retval = stream->compr_ops->open(&str_params, &cb); + retval = stream->compr_ops->open(sst->dev, &str_params, &cb); if (retval < 0) { pr_err("stream allocation failed %d\n", retval); return retval; @@ -170,10 +170,30 @@ static int sst_platform_compr_set_params(struct snd_compr_stream *cstream, static int sst_platform_compr_trigger(struct snd_compr_stream *cstream, int cmd) { - struct sst_runtime_stream *stream = - cstream->runtime->private_data; - - return stream->compr_ops->control(cmd, stream->id); + struct sst_runtime_stream *stream = cstream->runtime->private_data; + + switch (cmd) { + case SNDRV_PCM_TRIGGER_START: + if (stream->compr_ops->stream_start) + return stream->compr_ops->stream_start(sst->dev, stream->id); + case SNDRV_PCM_TRIGGER_STOP: + if (stream->compr_ops->stream_drop) + return stream->compr_ops->stream_drop(sst->dev, stream->id); + case SND_COMPR_TRIGGER_DRAIN: + if (stream->compr_ops->stream_drain) + return stream->compr_ops->stream_drain(sst->dev, stream->id); + case SND_COMPR_TRIGGER_PARTIAL_DRAIN: + if (stream->compr_ops->stream_partial_drain) + return stream->compr_ops->stream_partial_drain(sst->dev, stream->id); + case SNDRV_PCM_TRIGGER_PAUSE_PUSH: + if (stream->compr_ops->stream_pause) + return stream->compr_ops->stream_pause(sst->dev, stream->id); + case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: + if (stream->compr_ops->stream_pause_release) + return stream->compr_ops->stream_pause_release(sst->dev, stream->id); + default: + return -EINVAL; + } } static int sst_platform_compr_pointer(struct snd_compr_stream *cstream, @@ -182,7 +202,7 @@ static int sst_platform_compr_pointer(struct snd_compr_stream *cstream, struct sst_runtime_stream *stream; stream = cstream->runtime->private_data; - stream->compr_ops->tstamp(stream->id, tstamp); + stream->compr_ops->tstamp(sst->dev, stream->id, tstamp); tstamp->byte_offset = tstamp->copied_total % (u32)cstream->runtime->buffer_size; pr_debug("calc bytes offset/copied bytes as %d\n", tstamp->byte_offset); @@ -195,7 +215,7 @@ static int sst_platform_compr_ack(struct snd_compr_stream *cstream, struct sst_runtime_stream *stream; stream = cstream->runtime->private_data; - stream->compr_ops->ack(stream->id, (unsigned long)bytes); + stream->compr_ops->ack(sst->dev, stream->id, (unsigned long)bytes); stream->bytes_written += bytes; return 0; @@ -225,7 +245,7 @@ static int sst_platform_compr_set_metadata(struct snd_compr_stream *cstream, struct sst_runtime_stream *stream = cstream->runtime->private_data; - return stream->compr_ops->set_metadata(stream->id, metadata); + return stream->compr_ops->set_metadata(sst->dev, stream->id, metadata); } struct snd_compr_ops sst_platform_compr_ops = { diff --git a/sound/soc/intel/sst-mfld-platform-pcm.c b/sound/soc/intel/sst-mfld-platform-pcm.c index 706212a6a68c..aa9b600dfc9b 100644 --- a/sound/soc/intel/sst-mfld-platform-pcm.c +++ b/sound/soc/intel/sst-mfld-platform-pcm.c @@ -43,12 +43,12 @@ int sst_register_dsp(struct sst_device *dev) return -ENODEV; mutex_lock(&sst_lock); if (sst) { - pr_err("we already have a device %s\n", sst->name); + dev_err(dev->dev, "we already have a device %s\n", sst->name); module_put(dev->dev->driver->owner); mutex_unlock(&sst_lock); return -EEXIST; } - pr_debug("registering device %s\n", dev->name); + dev_dbg(dev->dev, "registering device %s\n", dev->name); sst = dev; mutex_unlock(&sst_lock); return 0; @@ -70,7 +70,7 @@ int sst_unregister_dsp(struct sst_device *dev) } module_put(sst->dev->driver->owner); - pr_debug("unreg %s\n", sst->name); + dev_dbg(dev->dev, "unreg %s\n", sst->name); sst = NULL; mutex_unlock(&sst_lock); return 0; @@ -252,7 +252,7 @@ int sst_fill_stream_params(void *substream, } static int sst_platform_alloc_stream(struct snd_pcm_substream *substream, - struct snd_soc_platform *platform) + struct snd_soc_dai *dai) { struct sst_runtime_stream *stream = substream->runtime->private_data; @@ -260,7 +260,7 @@ static int sst_platform_alloc_stream(struct snd_pcm_substream *substream, struct snd_sst_params str_params = {0}; struct snd_sst_alloc_params_ext alloc_params = {0}; int ret_val = 0; - struct sst_data *ctx = snd_soc_platform_get_drvdata(platform); + struct sst_data *ctx = snd_soc_dai_get_drvdata(dai); /* set codec params and inform SST driver the same */ sst_fill_pcm_params(substream, ¶m); @@ -277,7 +277,7 @@ static int sst_platform_alloc_stream(struct snd_pcm_substream *substream, stream->stream_info.str_id = str_params.stream_id; - ret_val = stream->ops->open(&str_params); + ret_val = stream->ops->open(sst->dev, &str_params); if (ret_val <= 0) return ret_val; @@ -306,22 +306,31 @@ static int sst_platform_init_stream(struct snd_pcm_substream *substream) { struct sst_runtime_stream *stream = substream->runtime->private_data; + struct snd_soc_pcm_runtime *rtd = substream->private_data; int ret_val; - pr_debug("setting buffer ptr param\n"); + dev_dbg(rtd->dev, "setting buffer ptr param\n"); sst_set_stream_status(stream, SST_PLATFORM_INIT); stream->stream_info.period_elapsed = sst_period_elapsed; stream->stream_info.arg = substream; stream->stream_info.buffer_ptr = 0; stream->stream_info.sfreq = substream->runtime->rate; - ret_val = stream->ops->device_control( - SST_SND_STREAM_INIT, &stream->stream_info); + ret_val = stream->ops->stream_init(sst->dev, &stream->stream_info); if (ret_val) - pr_err("control_set ret error %d\n", ret_val); + dev_err(rtd->dev, "control_set ret error %d\n", ret_val); return ret_val; } -/* end -- helper functions */ + +static int power_up_sst(struct sst_runtime_stream *stream) +{ + return stream->ops->power(sst->dev, true); +} + +static void power_down_sst(struct sst_runtime_stream *stream) +{ + stream->ops->power(sst->dev, false); +} static int sst_media_open(struct snd_pcm_substream *substream, struct snd_soc_dai *dai) @@ -339,7 +348,7 @@ static int sst_media_open(struct snd_pcm_substream *substream, mutex_lock(&sst_lock); if (!sst || !try_module_get(sst->dev->driver->owner)) { - pr_err("no device available to run\n"); + dev_err(dai->dev, "no device available to run\n"); ret_val = -ENODEV; goto out_ops; } @@ -352,6 +361,10 @@ static int sst_media_open(struct snd_pcm_substream *substream, /* allocate memory for SST API set */ runtime->private_data = stream; + ret_val = power_up_sst(stream); + if (ret_val < 0) + return ret_val; + /* Make sure, that the period size is always even */ snd_pcm_hw_constraint_step(substream->runtime, 0, SNDRV_PCM_HW_PARAM_PERIODS, 2); @@ -371,26 +384,29 @@ static void sst_media_close(struct snd_pcm_substream *substream, int ret_val = 0, str_id; stream = substream->runtime->private_data; + power_down_sst(stream); + str_id = stream->stream_info.str_id; if (str_id) - ret_val = stream->ops->close(str_id); + ret_val = stream->ops->close(sst->dev, str_id); module_put(sst->dev->driver->owner); kfree(stream); } -static inline unsigned int get_current_pipe_id(struct snd_soc_platform *platform, +static inline unsigned int get_current_pipe_id(struct snd_soc_dai *dai, struct snd_pcm_substream *substream) { - struct sst_data *sst = snd_soc_platform_get_drvdata(platform); + struct sst_data *sst = snd_soc_dai_get_drvdata(dai); struct sst_dev_stream_map *map = sst->pdata->pdev_strm_map; struct sst_runtime_stream *stream = substream->runtime->private_data; u32 str_id = stream->stream_info.str_id; unsigned int pipe_id; + pipe_id = map[str_id].device_id; - pr_debug("%s: got pipe_id = %#x for str_id = %d\n", - __func__, pipe_id, str_id); + dev_dbg(dai->dev, "got pipe_id = %#x for str_id = %d\n", + pipe_id, str_id); return pipe_id; } @@ -403,12 +419,11 @@ static int sst_media_prepare(struct snd_pcm_substream *substream, stream = substream->runtime->private_data; str_id = stream->stream_info.str_id; if (stream->stream_info.str_id) { - ret_val = stream->ops->device_control( - SST_SND_DROP, &str_id); + ret_val = stream->ops->stream_drop(sst->dev, str_id); return ret_val; } - ret_val = sst_platform_alloc_stream(substream, dai->platform); + ret_val = sst_platform_alloc_stream(substream, dai); if (ret_val <= 0) return ret_val; snprintf(substream->pcm->id, sizeof(substream->pcm->id), @@ -461,37 +476,40 @@ static int sst_platform_pcm_trigger(struct snd_pcm_substream *substream, { int ret_val = 0, str_id; struct sst_runtime_stream *stream; - int str_cmd, status; + int status; + struct snd_soc_pcm_runtime *rtd = substream->private_data; - pr_debug("sst_platform_pcm_trigger called\n"); + dev_dbg(rtd->dev, "sst_platform_pcm_trigger called\n"); + if (substream->pcm->internal) + return 0; stream = substream->runtime->private_data; str_id = stream->stream_info.str_id; switch (cmd) { case SNDRV_PCM_TRIGGER_START: - pr_debug("sst: Trigger Start\n"); - str_cmd = SST_SND_START; + dev_dbg(rtd->dev, "sst: Trigger Start\n"); status = SST_PLATFORM_RUNNING; stream->stream_info.arg = substream; + ret_val = stream->ops->stream_start(sst->dev, str_id); break; case SNDRV_PCM_TRIGGER_STOP: - pr_debug("sst: in stop\n"); - str_cmd = SST_SND_DROP; + dev_dbg(rtd->dev, "sst: in stop\n"); status = SST_PLATFORM_DROPPED; + ret_val = stream->ops->stream_drop(sst->dev, str_id); break; case SNDRV_PCM_TRIGGER_PAUSE_PUSH: - pr_debug("sst: in pause\n"); - str_cmd = SST_SND_PAUSE; + dev_dbg(rtd->dev, "sst: in pause\n"); status = SST_PLATFORM_PAUSED; + ret_val = stream->ops->stream_pause(sst->dev, str_id); break; case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: - pr_debug("sst: in pause release\n"); - str_cmd = SST_SND_RESUME; + dev_dbg(rtd->dev, "sst: in pause release\n"); status = SST_PLATFORM_RUNNING; + ret_val = stream->ops->stream_pause_release(sst->dev, str_id); break; default: return -EINVAL; } - ret_val = stream->ops->device_control(str_cmd, &str_id); + if (!ret_val) sst_set_stream_status(stream, status); @@ -505,16 +523,16 @@ static snd_pcm_uframes_t sst_platform_pcm_pointer struct sst_runtime_stream *stream; int ret_val, status; struct pcm_stream_info *str_info; + struct snd_soc_pcm_runtime *rtd = substream->private_data; stream = substream->runtime->private_data; status = sst_get_stream_status(stream); if (status == SST_PLATFORM_INIT) return 0; str_info = &stream->stream_info; - ret_val = stream->ops->device_control( - SST_SND_BUFFER_POINTER, str_info); + ret_val = stream->ops->stream_read_tstamp(sst->dev, str_info); if (ret_val) { - pr_err("sst: error code = %d\n", ret_val); + dev_err(rtd->dev, "sst: error code = %d\n", ret_val); return ret_val; } substream->runtime->delay = str_info->pcm_delay; @@ -530,7 +548,7 @@ static struct snd_pcm_ops sst_platform_ops = { static void sst_pcm_free(struct snd_pcm *pcm) { - pr_debug("sst_pcm_free called\n"); + dev_dbg(pcm->dev, "sst_pcm_free called\n"); snd_pcm_lib_preallocate_free_for_all(pcm); } @@ -547,14 +565,20 @@ static int sst_pcm_new(struct snd_soc_pcm_runtime *rtd) snd_dma_continuous_data(GFP_DMA), SST_MIN_BUFFER, SST_MAX_BUFFER); if (retval) { - pr_err("dma buffer allocationf fail\n"); + dev_err(rtd->dev, "dma buffer allocationf fail\n"); return retval; } } return retval; } -static struct snd_soc_platform_driver sst_soc_platform_drv = { +static int sst_soc_probe(struct snd_soc_platform *platform) +{ + return sst_dsp_init_v2_dpcm(platform); +} + +static struct snd_soc_platform_driver sst_soc_platform_drv = { + .probe = sst_soc_probe, .ops = &sst_platform_ops, .compr_ops = &sst_platform_compr_ops, .pcm_new = sst_pcm_new, @@ -574,13 +598,11 @@ static int sst_platform_probe(struct platform_device *pdev) drv = devm_kzalloc(&pdev->dev, sizeof(*drv), GFP_KERNEL); if (drv == NULL) { - pr_err("kzalloc failed\n"); return -ENOMEM; } pdata = devm_kzalloc(&pdev->dev, sizeof(*pdata), GFP_KERNEL); if (pdata == NULL) { - pr_err("kzalloc failed for pdata\n"); return -ENOMEM; } @@ -592,14 +614,14 @@ static int sst_platform_probe(struct platform_device *pdev) ret = snd_soc_register_platform(&pdev->dev, &sst_soc_platform_drv); if (ret) { - pr_err("registering soc platform failed\n"); + dev_err(&pdev->dev, "registering soc platform failed\n"); return ret; } ret = snd_soc_register_component(&pdev->dev, &sst_component, sst_platform_dai, ARRAY_SIZE(sst_platform_dai)); if (ret) { - pr_err("registering cpu dais failed\n"); + dev_err(&pdev->dev, "registering cpu dais failed\n"); snd_soc_unregister_platform(&pdev->dev); } return ret; @@ -610,7 +632,7 @@ static int sst_platform_remove(struct platform_device *pdev) snd_soc_unregister_component(&pdev->dev); snd_soc_unregister_platform(&pdev->dev); - pr_debug("sst_platform_remove success\n"); + dev_dbg(&pdev->dev, "sst_platform_remove success\n"); return 0; } diff --git a/sound/soc/intel/sst-mfld-platform.h b/sound/soc/intel/sst-mfld-platform.h index 6c6a42c08e24..19f83ec51613 100644 --- a/sound/soc/intel/sst-mfld-platform.h +++ b/sound/soc/intel/sst-mfld-platform.h @@ -54,20 +54,6 @@ enum sst_drv_status { SST_PLATFORM_DROPPED, }; -enum sst_controls { - SST_SND_ALLOC = 0x00, - SST_SND_PAUSE = 0x01, - SST_SND_RESUME = 0x02, - SST_SND_DROP = 0x03, - SST_SND_FREE = 0x04, - SST_SND_BUFFER_POINTER = 0x05, - SST_SND_STREAM_INIT = 0x06, - SST_SND_START = 0x07, - SST_SET_BYTE_STREAM = 0x100A, - SST_GET_BYTE_STREAM = 0x100B, - SST_MAX_CONTROLS = SST_GET_BYTE_STREAM, -}; - enum sst_stream_ops { STREAM_OPS_PLAYBACK = 0, STREAM_OPS_CAPTURE, @@ -113,24 +99,37 @@ struct sst_compress_cb { struct compress_sst_ops { const char *name; - int (*open) (struct snd_sst_params *str_params, - struct sst_compress_cb *cb); - int (*control) (unsigned int cmd, unsigned int str_id); - int (*tstamp) (unsigned int str_id, struct snd_compr_tstamp *tstamp); - int (*ack) (unsigned int str_id, unsigned long bytes); - int (*close) (unsigned int str_id); - int (*get_caps) (struct snd_compr_caps *caps); - int (*get_codec_caps) (struct snd_compr_codec_caps *codec); - int (*set_metadata) (unsigned int str_id, + int (*open)(struct device *dev, + struct snd_sst_params *str_params, struct sst_compress_cb *cb); + int (*stream_start)(struct device *dev, unsigned int str_id); + int (*stream_drop)(struct device *dev, unsigned int str_id); + int (*stream_drain)(struct device *dev, unsigned int str_id); + int (*stream_partial_drain)(struct device *dev, unsigned int str_id); + int (*stream_pause)(struct device *dev, unsigned int str_id); + int (*stream_pause_release)(struct device *dev, unsigned int str_id); + + int (*tstamp)(struct device *dev, unsigned int str_id, + struct snd_compr_tstamp *tstamp); + int (*ack)(struct device *dev, unsigned int str_id, + unsigned long bytes); + int (*close)(struct device *dev, unsigned int str_id); + int (*get_caps)(struct snd_compr_caps *caps); + int (*get_codec_caps)(struct snd_compr_codec_caps *codec); + int (*set_metadata)(struct device *dev, unsigned int str_id, struct snd_compr_metadata *mdata); - }; struct sst_ops { - 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); + int (*open)(struct device *dev, struct snd_sst_params *str_param); + int (*stream_init)(struct device *dev, struct pcm_stream_info *str_info); + int (*stream_start)(struct device *dev, int str_id); + int (*stream_drop)(struct device *dev, int str_id); + int (*stream_pause)(struct device *dev, int str_id); + int (*stream_pause_release)(struct device *dev, int str_id); + int (*stream_read_tstamp)(struct device *dev, struct pcm_stream_info *str_info); + int (*send_byte_stream)(struct device *dev, struct snd_sst_bytes_v2 *bytes); + int (*close)(struct device *dev, unsigned int str_id); + int (*power)(struct device *dev, bool state); }; struct sst_runtime_stream { @@ -152,6 +151,8 @@ struct sst_device { }; struct sst_data; + +int sst_dsp_init_v2_dpcm(struct snd_soc_platform *platform); void sst_set_stream_status(struct sst_runtime_stream *stream, int state); int sst_fill_stream_params(void *substream, const struct sst_data *ctx, struct snd_sst_params *str_params, bool is_compress); @@ -166,6 +167,7 @@ struct sst_algo_int_control_v2 { struct sst_data { struct platform_device *pdev; struct sst_platform_data *pdata; + struct snd_sst_bytes_v2 *byte_stream; struct mutex lock; }; int sst_register_dsp(struct sst_device *sst); diff --git a/sound/soc/samsung/speyside.c b/sound/soc/samsung/speyside.c index 9902efcb8ea1..a05482651aae 100644 --- a/sound/soc/samsung/speyside.c +++ b/sound/soc/samsung/speyside.c @@ -228,10 +228,12 @@ static struct snd_soc_dai_link speyside_dai[] = { }, }; -static int speyside_wm9081_init(struct snd_soc_dapm_context *dapm) +static int speyside_wm9081_init(struct snd_soc_component *component) { + struct snd_soc_codec *codec = snd_soc_component_to_codec(component); + /* At any time the WM9081 is active it will have this clock */ - return snd_soc_codec_set_sysclk(dapm->codec, WM9081_SYSCLK_MCLK, 0, + return snd_soc_codec_set_sysclk(codec, WM9081_SYSCLK_MCLK, 0, MCLK_AUDIO_RATE, 0); } diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c index d4bfd4a9076f..1b422c5c36c8 100644 --- a/sound/soc/soc-core.c +++ b/sound/soc/soc-core.c @@ -270,79 +270,54 @@ static const struct file_operations codec_reg_fops = { .llseek = default_llseek, }; -static struct dentry *soc_debugfs_create_dir(struct dentry *parent, - const char *fmt, ...) +static void soc_init_component_debugfs(struct snd_soc_component *component) { - struct dentry *de; - va_list ap; - char *s; + if (component->debugfs_prefix) { + char *name; - va_start(ap, fmt); - s = kvasprintf(GFP_KERNEL, fmt, ap); - va_end(ap); + name = kasprintf(GFP_KERNEL, "%s:%s", + component->debugfs_prefix, component->name); + if (name) { + component->debugfs_root = debugfs_create_dir(name, + component->card->debugfs_card_root); + kfree(name); + } + } else { + component->debugfs_root = debugfs_create_dir(component->name, + component->card->debugfs_card_root); + } - if (!s) - return NULL; + if (!component->debugfs_root) { + dev_warn(component->dev, + "ASoC: Failed to create component debugfs directory\n"); + return; + } - de = debugfs_create_dir(s, parent); - kfree(s); + snd_soc_dapm_debugfs_init(snd_soc_component_get_dapm(component), + component->debugfs_root); - return de; + if (component->init_debugfs) + component->init_debugfs(component); } -static void soc_init_codec_debugfs(struct snd_soc_codec *codec) +static void soc_cleanup_component_debugfs(struct snd_soc_component *component) { - struct dentry *debugfs_card_root = codec->component.card->debugfs_card_root; + debugfs_remove_recursive(component->debugfs_root); +} - codec->debugfs_codec_root = soc_debugfs_create_dir(debugfs_card_root, - "codec:%s", - codec->component.name); - if (!codec->debugfs_codec_root) { - dev_warn(codec->dev, - "ASoC: Failed to create codec debugfs directory\n"); - return; - } +static void soc_init_codec_debugfs(struct snd_soc_component *component) +{ + struct snd_soc_codec *codec = snd_soc_component_to_codec(component); - debugfs_create_bool("cache_sync", 0444, codec->debugfs_codec_root, + debugfs_create_bool("cache_sync", 0444, codec->component.debugfs_root, &codec->cache_sync); - debugfs_create_bool("cache_only", 0444, codec->debugfs_codec_root, - &codec->cache_only); codec->debugfs_reg = debugfs_create_file("codec_reg", 0644, - codec->debugfs_codec_root, + codec->component.debugfs_root, codec, &codec_reg_fops); if (!codec->debugfs_reg) dev_warn(codec->dev, "ASoC: Failed to create codec register debugfs file\n"); - - snd_soc_dapm_debugfs_init(&codec->dapm, codec->debugfs_codec_root); -} - -static void soc_cleanup_codec_debugfs(struct snd_soc_codec *codec) -{ - debugfs_remove_recursive(codec->debugfs_codec_root); -} - -static void soc_init_platform_debugfs(struct snd_soc_platform *platform) -{ - struct dentry *debugfs_card_root = platform->component.card->debugfs_card_root; - - platform->debugfs_platform_root = soc_debugfs_create_dir(debugfs_card_root, - "platform:%s", - platform->component.name); - if (!platform->debugfs_platform_root) { - dev_warn(platform->dev, - "ASoC: Failed to create platform debugfs directory\n"); - return; - } - - snd_soc_dapm_debugfs_init(&platform->component.dapm, - platform->debugfs_platform_root); -} - -static void soc_cleanup_platform_debugfs(struct snd_soc_platform *platform) -{ - debugfs_remove_recursive(platform->debugfs_platform_root); } static ssize_t codec_list_read_file(struct file *file, char __user *user_buf, @@ -474,19 +449,15 @@ static void soc_cleanup_card_debugfs(struct snd_soc_card *card) #else -static inline void soc_init_codec_debugfs(struct snd_soc_codec *codec) -{ -} +#define soc_init_codec_debugfs NULL -static inline void soc_cleanup_codec_debugfs(struct snd_soc_codec *codec) +static inline void soc_init_component_debugfs( + struct snd_soc_component *component) { } -static inline void soc_init_platform_debugfs(struct snd_soc_platform *platform) -{ -} - -static inline void soc_cleanup_platform_debugfs(struct snd_soc_platform *platform) +static inline void soc_cleanup_component_debugfs( + struct snd_soc_component *component) { } @@ -579,10 +550,8 @@ int snd_soc_suspend(struct device *dev) struct snd_soc_codec *codec; int i, j; - /* If the initialization of this soc device failed, there is no codec - * associated with it. Just bail out in this case. - */ - if (list_empty(&card->codec_dev_list)) + /* If the card is not initialized yet there is nothing to do */ + if (!card->instantiated) return 0; /* Due to the resume being scheduled into a workqueue we could @@ -835,10 +804,8 @@ int snd_soc_resume(struct device *dev) struct snd_soc_card *card = dev_get_drvdata(dev); int i, ac97_control = 0; - /* If the initialization of this soc device failed, there is no codec - * associated with it. Just bail out in this case. - */ - if (list_empty(&card->codec_dev_list)) + /* If the card is not initialized yet there is nothing to do */ + if (!card->instantiated) return 0; /* activate pins from sleep state */ @@ -887,35 +854,40 @@ EXPORT_SYMBOL_GPL(snd_soc_resume); static const struct snd_soc_dai_ops null_dai_ops = { }; -static struct snd_soc_codec *soc_find_codec( - const struct device_node *codec_of_node, - const char *codec_name) +static struct snd_soc_component *soc_find_component( + const struct device_node *of_node, const char *name) { - struct snd_soc_codec *codec; + struct snd_soc_component *component; - list_for_each_entry(codec, &codec_list, list) { - if (codec_of_node) { - if (codec->dev->of_node != codec_of_node) - continue; - } else { - if (strcmp(codec->component.name, codec_name)) - continue; + list_for_each_entry(component, &component_list, list) { + if (of_node) { + if (component->dev->of_node == of_node) + return component; + } else if (strcmp(component->name, name) == 0) { + return component; } - - return codec; } return NULL; } -static struct snd_soc_dai *soc_find_codec_dai(struct snd_soc_codec *codec, - const char *codec_dai_name) +static struct snd_soc_dai *snd_soc_find_dai( + const struct snd_soc_dai_link_component *dlc) { - struct snd_soc_dai *codec_dai; + struct snd_soc_component *component; + struct snd_soc_dai *dai; - list_for_each_entry(codec_dai, &codec->component.dai_list, list) { - if (!strcmp(codec_dai->name, codec_dai_name)) { - return codec_dai; + /* Find CPU DAI from registered DAIs*/ + list_for_each_entry(component, &component_list, list) { + if (dlc->of_node && component->dev->of_node != dlc->of_node) + continue; + if (dlc->name && strcmp(dev_name(component->dev), dlc->name)) + continue; + list_for_each_entry(dai, &component->dai_list, list) { + if (dlc->dai_name && strcmp(dai->name, dlc->dai_name)) + continue; + + return dai; } } @@ -926,33 +898,19 @@ static int soc_bind_dai_link(struct snd_soc_card *card, int num) { struct snd_soc_dai_link *dai_link = &card->dai_link[num]; struct snd_soc_pcm_runtime *rtd = &card->rtd[num]; - struct snd_soc_component *component; struct snd_soc_dai_link_component *codecs = dai_link->codecs; + struct snd_soc_dai_link_component cpu_dai_component; struct snd_soc_dai **codec_dais = rtd->codec_dais; struct snd_soc_platform *platform; - struct snd_soc_dai *cpu_dai; const char *platform_name; int i; dev_dbg(card->dev, "ASoC: binding %s at idx %d\n", dai_link->name, num); - /* Find CPU DAI from registered DAIs*/ - list_for_each_entry(component, &component_list, list) { - if (dai_link->cpu_of_node && - component->dev->of_node != dai_link->cpu_of_node) - continue; - if (dai_link->cpu_name && - strcmp(dev_name(component->dev), dai_link->cpu_name)) - continue; - list_for_each_entry(cpu_dai, &component->dai_list, list) { - if (dai_link->cpu_dai_name && - strcmp(cpu_dai->name, dai_link->cpu_dai_name)) - continue; - - rtd->cpu_dai = cpu_dai; - } - } - + cpu_dai_component.name = dai_link->cpu_name; + cpu_dai_component.of_node = dai_link->cpu_of_node; + cpu_dai_component.dai_name = dai_link->cpu_dai_name; + rtd->cpu_dai = snd_soc_find_dai(&cpu_dai_component); if (!rtd->cpu_dai) { dev_err(card->dev, "ASoC: CPU DAI %s not registered\n", dai_link->cpu_dai_name); @@ -963,15 +921,7 @@ static int soc_bind_dai_link(struct snd_soc_card *card, int num) /* Find CODEC from registered CODECs */ for (i = 0; i < rtd->num_codecs; i++) { - struct snd_soc_codec *codec; - codec = soc_find_codec(codecs[i].of_node, codecs[i].name); - if (!codec) { - dev_err(card->dev, "ASoC: CODEC %s not registered\n", - codecs[i].name); - return -EPROBE_DEFER; - } - - codec_dais[i] = soc_find_codec_dai(codec, codecs[i].dai_name); + codec_dais[i] = snd_soc_find_dai(&codecs[i]); if (!codec_dais[i]) { dev_err(card->dev, "ASoC: CODEC DAI %s not registered\n", codecs[i].dai_name); @@ -1012,68 +962,46 @@ static int soc_bind_dai_link(struct snd_soc_card *card, int num) return 0; } -static int soc_remove_platform(struct snd_soc_platform *platform) +static void soc_remove_component(struct snd_soc_component *component) { - int ret; - - if (platform->driver->remove) { - ret = platform->driver->remove(platform); - if (ret < 0) - dev_err(platform->dev, "ASoC: failed to remove %d\n", - ret); - } - - /* Make sure all DAPM widgets are freed */ - snd_soc_dapm_free(&platform->component.dapm); - - soc_cleanup_platform_debugfs(platform); - platform->probed = 0; - module_put(platform->dev->driver->owner); - - return 0; -} + if (!component->probed) + return; -static void soc_remove_codec(struct snd_soc_codec *codec) -{ - int err; + /* This is a HACK and will be removed soon */ + if (component->codec) + list_del(&component->codec->card_list); - if (codec->driver->remove) { - err = codec->driver->remove(codec); - if (err < 0) - dev_err(codec->dev, "ASoC: failed to remove %d\n", err); - } + if (component->remove) + component->remove(component); - /* Make sure all DAPM widgets are freed */ - snd_soc_dapm_free(&codec->dapm); + snd_soc_dapm_free(snd_soc_component_get_dapm(component)); - soc_cleanup_codec_debugfs(codec); - codec->probed = 0; - list_del(&codec->card_list); - module_put(codec->dev->driver->owner); + soc_cleanup_component_debugfs(component); + component->probed = 0; + module_put(component->dev->driver->owner); } -static void soc_remove_codec_dai(struct snd_soc_dai *codec_dai, int order) +static void soc_remove_dai(struct snd_soc_dai *dai, int order) { int err; - if (codec_dai && codec_dai->probed && - codec_dai->driver->remove_order == order) { - if (codec_dai->driver->remove) { - err = codec_dai->driver->remove(codec_dai); + if (dai && dai->probed && + dai->driver->remove_order == order) { + if (dai->driver->remove) { + err = dai->driver->remove(dai); if (err < 0) - dev_err(codec_dai->dev, + dev_err(dai->dev, "ASoC: failed to remove %s: %d\n", - codec_dai->name, err); + dai->name, err); } - codec_dai->probed = 0; + dai->probed = 0; } } static void soc_remove_link_dais(struct snd_soc_card *card, int num, int order) { struct snd_soc_pcm_runtime *rtd = &card->rtd[num]; - struct snd_soc_dai *cpu_dai = rtd->cpu_dai; - int i, err; + int i; /* unregister the rtd device */ if (rtd->dev_registered) { @@ -1085,22 +1013,9 @@ static void soc_remove_link_dais(struct snd_soc_card *card, int num, int order) /* remove the CODEC DAI */ for (i = 0; i < rtd->num_codecs; i++) - soc_remove_codec_dai(rtd->codec_dais[i], order); + soc_remove_dai(rtd->codec_dais[i], order); - /* remove the cpu_dai */ - if (cpu_dai && cpu_dai->probed && - cpu_dai->driver->remove_order == order) { - if (cpu_dai->driver->remove) { - err = cpu_dai->driver->remove(cpu_dai); - if (err < 0) - dev_err(cpu_dai->dev, - "ASoC: failed to remove %s: %d\n", - cpu_dai->name, err); - } - cpu_dai->probed = 0; - if (!cpu_dai->codec) - module_put(cpu_dai->dev->driver->owner); - } + soc_remove_dai(rtd->cpu_dai, order); } static void soc_remove_link_components(struct snd_soc_card *card, int num, @@ -1109,29 +1024,24 @@ static void soc_remove_link_components(struct snd_soc_card *card, int num, struct snd_soc_pcm_runtime *rtd = &card->rtd[num]; struct snd_soc_dai *cpu_dai = rtd->cpu_dai; struct snd_soc_platform *platform = rtd->platform; - struct snd_soc_codec *codec; + struct snd_soc_component *component; int i; /* remove the platform */ - if (platform && platform->probed && - platform->driver->remove_order == order) { - soc_remove_platform(platform); - } + if (platform && platform->component.driver->remove_order == order) + soc_remove_component(&platform->component); /* remove the CODEC-side CODEC */ for (i = 0; i < rtd->num_codecs; i++) { - codec = rtd->codec_dais[i]->codec; - if (codec && codec->probed && - codec->driver->remove_order == order) - soc_remove_codec(codec); + component = rtd->codec_dais[i]->component; + if (component->driver->remove_order == order) + soc_remove_component(component); } /* remove any CPU-side CODEC */ if (cpu_dai) { - codec = cpu_dai->codec; - if (codec && codec->probed && - codec->driver->remove_order == order) - soc_remove_codec(codec); + if (cpu_dai->component->driver->remove_order == order) + soc_remove_component(cpu_dai->component); } } @@ -1173,137 +1083,111 @@ static void soc_set_name_prefix(struct snd_soc_card *card, } } -static int soc_probe_codec(struct snd_soc_card *card, - struct snd_soc_codec *codec) +static int soc_probe_component(struct snd_soc_card *card, + struct snd_soc_component *component) { - int ret = 0; - const struct snd_soc_codec_driver *driver = codec->driver; + struct snd_soc_dapm_context *dapm = snd_soc_component_get_dapm(component); + struct snd_soc_component *dai_component, *component2; struct snd_soc_dai *dai; + int ret; + + if (component->probed) + return 0; - codec->component.card = card; - codec->dapm.card = card; - soc_set_name_prefix(card, &codec->component); + component->card = card; + dapm->card = card; + soc_set_name_prefix(card, component); - if (!try_module_get(codec->dev->driver->owner)) + if (!try_module_get(component->dev->driver->owner)) return -ENODEV; - soc_init_codec_debugfs(codec); + soc_init_component_debugfs(component); - if (driver->dapm_widgets) { - ret = snd_soc_dapm_new_controls(&codec->dapm, - driver->dapm_widgets, - driver->num_dapm_widgets); + if (component->dapm_widgets) { + ret = snd_soc_dapm_new_controls(dapm, component->dapm_widgets, + component->num_dapm_widgets); if (ret != 0) { - dev_err(codec->dev, + dev_err(component->dev, "Failed to create new controls %d\n", ret); goto err_probe; } } - /* Create DAPM widgets for each DAI stream */ - list_for_each_entry(dai, &codec->component.dai_list, list) { - ret = snd_soc_dapm_new_dai_widgets(&codec->dapm, dai); + /* + * This is rather ugly, but certain platforms expect that the DAPM + * widgets for the DAIs for components with the same parent device are + * created in the platforms DAPM context. Until that is fixed we need to + * keep this. + */ + if (component->steal_sibling_dai_widgets) { + dai_component = NULL; + list_for_each_entry(component2, &component_list, list) { + if (component == component2) + continue; - if (ret != 0) { - dev_err(codec->dev, - "Failed to create DAI widgets %d\n", ret); - goto err_probe; + if (component2->dev == component->dev && + !list_empty(&component2->dai_list)) { + dai_component = component2; + break; + } } - } - - codec->dapm.idle_bias_off = driver->idle_bias_off; - - if (driver->probe) { - ret = driver->probe(codec); - if (ret < 0) { - dev_err(codec->dev, - "ASoC: failed to probe CODEC %d\n", ret); - goto err_probe; + } else { + dai_component = component; + list_for_each_entry(component2, &component_list, list) { + if (component2->dev == component->dev && + component2->steal_sibling_dai_widgets) { + dai_component = NULL; + break; + } } - WARN(codec->dapm.idle_bias_off && - codec->dapm.bias_level != SND_SOC_BIAS_OFF, - "codec %s can not start from non-off bias with idle_bias_off==1\n", - codec->component.name); } - if (driver->controls) - snd_soc_add_codec_controls(codec, driver->controls, - driver->num_controls); - if (driver->dapm_routes) - snd_soc_dapm_add_routes(&codec->dapm, driver->dapm_routes, - driver->num_dapm_routes); - - /* mark codec as probed and add to card codec list */ - codec->probed = 1; - list_add(&codec->card_list, &card->codec_dev_list); - list_add(&codec->dapm.list, &card->dapm_list); - - return 0; - -err_probe: - soc_cleanup_codec_debugfs(codec); - module_put(codec->dev->driver->owner); - - return ret; -} - -static int soc_probe_platform(struct snd_soc_card *card, - struct snd_soc_platform *platform) -{ - int ret = 0; - const struct snd_soc_platform_driver *driver = platform->driver; - struct snd_soc_component *component; - struct snd_soc_dai *dai; - - platform->component.card = card; - platform->component.dapm.card = card; - - if (!try_module_get(platform->dev->driver->owner)) - return -ENODEV; - - soc_init_platform_debugfs(platform); - - if (driver->dapm_widgets) - snd_soc_dapm_new_controls(&platform->component.dapm, - driver->dapm_widgets, driver->num_dapm_widgets); - - /* Create DAPM widgets for each DAI stream */ - list_for_each_entry(component, &component_list, list) { - if (component->dev != platform->dev) - continue; - list_for_each_entry(dai, &component->dai_list, list) - snd_soc_dapm_new_dai_widgets(&platform->component.dapm, - dai); + if (dai_component) { + list_for_each_entry(dai, &dai_component->dai_list, list) { + snd_soc_dapm_new_dai_widgets(dapm, dai); + if (ret != 0) { + dev_err(component->dev, + "Failed to create DAI widgets %d\n", + ret); + goto err_probe; + } + } } - platform->component.dapm.idle_bias_off = 1; - - if (driver->probe) { - ret = driver->probe(platform); + if (component->probe) { + ret = component->probe(component); if (ret < 0) { - dev_err(platform->dev, - "ASoC: failed to probe platform %d\n", ret); + dev_err(component->dev, + "ASoC: failed to probe component %d\n", ret); goto err_probe; } + + WARN(dapm->idle_bias_off && + dapm->bias_level != SND_SOC_BIAS_OFF, + "codec %s can not start from non-off bias with idle_bias_off==1\n", + component->name); } - if (driver->controls) - snd_soc_add_platform_controls(platform, driver->controls, - driver->num_controls); - if (driver->dapm_routes) - snd_soc_dapm_add_routes(&platform->component.dapm, - driver->dapm_routes, driver->num_dapm_routes); + if (component->controls) + snd_soc_add_component_controls(component, component->controls, + component->num_controls); + if (component->dapm_routes) + snd_soc_dapm_add_routes(dapm, component->dapm_routes, + component->num_dapm_routes); - /* mark platform as probed and add to card platform list */ - platform->probed = 1; - list_add(&platform->component.dapm.list, &card->dapm_list); + component->probed = 1; + list_add(&dapm->list, &card->dapm_list); + + /* This is a HACK and will be removed soon */ + if (component->codec) + list_add(&component->codec->card_list, &card->codec_dev_list); return 0; err_probe: - soc_cleanup_platform_debugfs(platform); - module_put(platform->dev->driver->owner); + soc_cleanup_component_debugfs(component); + module_put(component->dev->driver->owner); return ret; } @@ -1342,17 +1226,21 @@ static int soc_post_component_init(struct snd_soc_pcm_runtime *rtd, } rtd->dev_registered = 1; - /* add DAPM sysfs entries for this codec */ - ret = snd_soc_dapm_sys_add(rtd->dev); - if (ret < 0) - dev_err(rtd->dev, - "ASoC: failed to add codec dapm sysfs entries: %d\n", ret); + if (rtd->codec) { + /* add DAPM sysfs entries for this codec */ + ret = snd_soc_dapm_sys_add(rtd->dev); + if (ret < 0) + dev_err(rtd->dev, + "ASoC: failed to add codec dapm sysfs entries: %d\n", + ret); - /* add codec sysfs entries */ - ret = device_create_file(rtd->dev, &dev_attr_codec_reg); - if (ret < 0) - dev_err(rtd->dev, - "ASoC: failed to add codec sysfs files: %d\n", ret); + /* add codec sysfs entries */ + ret = device_create_file(rtd->dev, &dev_attr_codec_reg); + if (ret < 0) + dev_err(rtd->dev, + "ASoC: failed to add codec sysfs files: %d\n", + ret); + } return 0; } @@ -1361,33 +1249,31 @@ static int soc_probe_link_components(struct snd_soc_card *card, int num, int order) { struct snd_soc_pcm_runtime *rtd = &card->rtd[num]; - struct snd_soc_dai *cpu_dai = rtd->cpu_dai; struct snd_soc_platform *platform = rtd->platform; + struct snd_soc_component *component; int i, ret; /* probe the CPU-side component, if it is a CODEC */ - if (cpu_dai->codec && - !cpu_dai->codec->probed && - cpu_dai->codec->driver->probe_order == order) { - ret = soc_probe_codec(card, cpu_dai->codec); + component = rtd->cpu_dai->component; + if (component->driver->probe_order == order) { + ret = soc_probe_component(card, component); if (ret < 0) return ret; } /* probe the CODEC-side components */ for (i = 0; i < rtd->num_codecs; i++) { - if (!rtd->codec_dais[i]->codec->probed && - rtd->codec_dais[i]->codec->driver->probe_order == order) { - ret = soc_probe_codec(card, rtd->codec_dais[i]->codec); + component = rtd->codec_dais[i]->component; + if (component->driver->probe_order == order) { + ret = soc_probe_component(card, component); if (ret < 0) return ret; } } /* probe the platform */ - if (!platform->probed && - platform->driver->probe_order == order) { - ret = soc_probe_platform(card, platform); + if (platform->component.driver->probe_order == order) { + ret = soc_probe_component(card, &platform->component); if (ret < 0) return ret; } @@ -1482,18 +1368,12 @@ static int soc_probe_link_dais(struct snd_soc_card *card, int num, int order) /* probe the cpu_dai */ if (!cpu_dai->probed && cpu_dai->driver->probe_order == order) { - if (!cpu_dai->codec) { - if (!try_module_get(cpu_dai->dev->driver->owner)) - return -ENODEV; - } - if (cpu_dai->driver->probe) { ret = cpu_dai->driver->probe(cpu_dai); if (ret < 0) { dev_err(cpu_dai->dev, "ASoC: failed to probe CPU DAI %s: %d\n", cpu_dai->name, ret); - module_put(cpu_dai->dev->driver->owner); return ret; } } @@ -1654,17 +1534,24 @@ static int soc_bind_aux_dev(struct snd_soc_card *card, int num) { struct snd_soc_pcm_runtime *rtd = &card->rtd_aux[num]; struct snd_soc_aux_dev *aux_dev = &card->aux_dev[num]; - const char *codecname = aux_dev->codec_name; + const char *name = aux_dev->codec_name; - rtd->codec = soc_find_codec(aux_dev->codec_of_node, codecname); - if (!rtd->codec) { + rtd->component = soc_find_component(aux_dev->codec_of_node, name); + if (!rtd->component) { if (aux_dev->codec_of_node) - codecname = of_node_full_name(aux_dev->codec_of_node); + name = of_node_full_name(aux_dev->codec_of_node); - dev_err(card->dev, "ASoC: %s not registered\n", codecname); + dev_err(card->dev, "ASoC: %s not registered\n", name); return -EPROBE_DEFER; } + /* + * Some places still reference rtd->codec, so we have to keep that + * initialized if the component is a CODEC. Once all those references + * have been removed, this code can be removed as well. + */ + rtd->codec = rtd->component->codec; + return 0; } @@ -1674,18 +1561,13 @@ static int soc_probe_aux_dev(struct snd_soc_card *card, int num) struct snd_soc_aux_dev *aux_dev = &card->aux_dev[num]; int ret; - if (rtd->codec->probed) { - dev_err(rtd->codec->dev, "ASoC: codec already probed\n"); - return -EBUSY; - } - - ret = soc_probe_codec(card, rtd->codec); + ret = soc_probe_component(card, rtd->component); if (ret < 0) return ret; /* do machine specific initialization */ if (aux_dev->init) { - ret = aux_dev->init(&rtd->codec->dapm); + ret = aux_dev->init(rtd->component); if (ret < 0) { dev_err(card->dev, "ASoC: failed to init %s: %d\n", aux_dev->name, ret); @@ -1699,7 +1581,7 @@ static int soc_probe_aux_dev(struct snd_soc_card *card, int num) static void soc_remove_aux_dev(struct snd_soc_card *card, int num) { struct snd_soc_pcm_runtime *rtd = &card->rtd_aux[num]; - struct snd_soc_codec *codec = rtd->codec; + struct snd_soc_component *component = rtd->component; /* unregister the rtd device */ if (rtd->dev_registered) { @@ -1708,8 +1590,8 @@ static void soc_remove_aux_dev(struct snd_soc_card *card, int num) rtd->dev_registered = 0; } - if (codec && codec->probed) - soc_remove_codec(codec); + if (component && component->probed) + soc_remove_component(component); } static int snd_soc_init_codec_cache(struct snd_soc_codec *codec) @@ -4116,6 +3998,8 @@ static int snd_soc_component_initialize(struct snd_soc_component *component, component->dev = dev; component->driver = driver; + component->probe = component->driver->probe; + component->remove = component->driver->remove; if (!component->dapm_ptr) component->dapm_ptr = &component->dapm; @@ -4124,19 +4008,42 @@ static int snd_soc_component_initialize(struct snd_soc_component *component, dapm->dev = dev; dapm->component = component; dapm->bias_level = SND_SOC_BIAS_OFF; + dapm->idle_bias_off = true; if (driver->seq_notifier) dapm->seq_notifier = snd_soc_component_seq_notifier; if (driver->stream_event) dapm->stream_event = snd_soc_component_stream_event; + component->controls = driver->controls; + component->num_controls = driver->num_controls; + component->dapm_widgets = driver->dapm_widgets; + component->num_dapm_widgets = driver->num_dapm_widgets; + component->dapm_routes = driver->dapm_routes; + component->num_dapm_routes = driver->num_dapm_routes; + INIT_LIST_HEAD(&component->dai_list); mutex_init(&component->io_mutex); return 0; } +static void snd_soc_component_init_regmap(struct snd_soc_component *component) +{ + if (!component->regmap) + component->regmap = dev_get_regmap(component->dev, NULL); + if (component->regmap) { + int val_bytes = regmap_get_val_bytes(component->regmap); + /* Errors are legitimate for non-integer byte multiples */ + if (val_bytes > 0) + component->val_bytes = val_bytes; + } +} + static void snd_soc_component_add_unlocked(struct snd_soc_component *component) { + if (!component->write && !component->read) + snd_soc_component_init_regmap(component); + list_add(&component->list, &component_list); } @@ -4225,22 +4132,18 @@ found: } EXPORT_SYMBOL_GPL(snd_soc_unregister_component); -static int snd_soc_platform_drv_write(struct snd_soc_component *component, - unsigned int reg, unsigned int val) +static int snd_soc_platform_drv_probe(struct snd_soc_component *component) { struct snd_soc_platform *platform = snd_soc_component_to_platform(component); - return platform->driver->write(platform, reg, val); + return platform->driver->probe(platform); } -static int snd_soc_platform_drv_read(struct snd_soc_component *component, - unsigned int reg, unsigned int *val) +static void snd_soc_platform_drv_remove(struct snd_soc_component *component) { struct snd_soc_platform *platform = snd_soc_component_to_platform(component); - *val = platform->driver->read(platform, reg); - - return 0; + platform->driver->remove(platform); } /** @@ -4261,10 +4164,28 @@ int snd_soc_add_platform(struct device *dev, struct snd_soc_platform *platform, platform->dev = dev; platform->driver = platform_drv; - if (platform_drv->write) - platform->component.write = snd_soc_platform_drv_write; - if (platform_drv->read) - platform->component.read = snd_soc_platform_drv_read; + if (platform_drv->controls) { + platform->component.controls = platform_drv->controls; + platform->component.num_controls = platform_drv->num_controls; + } + if (platform_drv->dapm_widgets) { + platform->component.dapm_widgets = platform_drv->dapm_widgets; + platform->component.num_dapm_widgets = platform_drv->num_dapm_widgets; + platform->component.steal_sibling_dai_widgets = true; + } + if (platform_drv->dapm_routes) { + platform->component.dapm_routes = platform_drv->dapm_routes; + platform->component.num_dapm_routes = platform_drv->num_dapm_routes; + } + + if (platform_drv->probe) + platform->component.probe = snd_soc_platform_drv_probe; + if (platform_drv->remove) + platform->component.remove = snd_soc_platform_drv_remove; + +#ifdef CONFIG_DEBUG_FS + platform->component.debugfs_prefix = "platform"; +#endif mutex_lock(&client_mutex); snd_soc_component_add_unlocked(&platform->component); @@ -4386,6 +4307,20 @@ static void fixup_codec_formats(struct snd_soc_pcm_stream *stream) stream->formats |= codec_format_map[i]; } +static int snd_soc_codec_drv_probe(struct snd_soc_component *component) +{ + struct snd_soc_codec *codec = snd_soc_component_to_codec(component); + + return codec->driver->probe(codec); +} + +static void snd_soc_codec_drv_remove(struct snd_soc_component *component) +{ + struct snd_soc_codec *codec = snd_soc_component_to_codec(component); + + codec->driver->remove(codec); +} + static int snd_soc_codec_drv_write(struct snd_soc_component *component, unsigned int reg, unsigned int val) { @@ -4424,7 +4359,6 @@ int snd_soc_register_codec(struct device *dev, { struct snd_soc_codec *codec; struct snd_soc_dai *dai; - struct regmap *regmap; int ret, i; dev_dbg(dev, "codec register %s\n", dev_name(dev)); @@ -4434,18 +4368,37 @@ int snd_soc_register_codec(struct device *dev, return -ENOMEM; codec->component.dapm_ptr = &codec->dapm; + codec->component.codec = codec; ret = snd_soc_component_initialize(&codec->component, &codec_drv->component_driver, dev); if (ret) goto err_free; + if (codec_drv->controls) { + codec->component.controls = codec_drv->controls; + codec->component.num_controls = codec_drv->num_controls; + } + if (codec_drv->dapm_widgets) { + codec->component.dapm_widgets = codec_drv->dapm_widgets; + codec->component.num_dapm_widgets = codec_drv->num_dapm_widgets; + } + if (codec_drv->dapm_routes) { + codec->component.dapm_routes = codec_drv->dapm_routes; + codec->component.num_dapm_routes = codec_drv->num_dapm_routes; + } + + if (codec_drv->probe) + codec->component.probe = snd_soc_codec_drv_probe; + if (codec_drv->remove) + codec->component.remove = snd_soc_codec_drv_remove; if (codec_drv->write) codec->component.write = snd_soc_codec_drv_write; if (codec_drv->read) codec->component.read = snd_soc_codec_drv_read; codec->component.ignore_pmdown_time = codec_drv->ignore_pmdown_time; codec->dapm.codec = codec; + codec->dapm.idle_bias_off = codec_drv->idle_bias_off; if (codec_drv->seq_notifier) codec->dapm.seq_notifier = codec_drv->seq_notifier; if (codec_drv->set_bias_level) @@ -4455,23 +4408,13 @@ int snd_soc_register_codec(struct device *dev, codec->component.val_bytes = codec_drv->reg_word_size; mutex_init(&codec->mutex); - if (!codec->component.write) { - if (codec_drv->get_regmap) - regmap = codec_drv->get_regmap(dev); - else - regmap = dev_get_regmap(dev, NULL); - - if (regmap) { - ret = snd_soc_component_init_io(&codec->component, - regmap); - if (ret) { - dev_err(codec->dev, - "Failed to set cache I/O:%d\n", - ret); - goto err_cleanup; - } - } - } +#ifdef CONFIG_DEBUG_FS + codec->component.init_debugfs = soc_init_codec_debugfs; + codec->component.debugfs_prefix = "codec"; +#endif + + if (codec_drv->get_regmap) + codec->component.regmap = codec_drv->get_regmap(dev); for (i = 0; i < num_dai; i++) { fixup_codec_formats(&dai_drv[i].playback); diff --git a/sound/soc/soc-generic-dmaengine-pcm.c b/sound/soc/soc-generic-dmaengine-pcm.c index 6307f85e871b..b329b84bc5af 100644 --- a/sound/soc/soc-generic-dmaengine-pcm.c +++ b/sound/soc/soc-generic-dmaengine-pcm.c @@ -336,10 +336,12 @@ static const struct snd_pcm_ops dmaengine_pcm_ops = { }; static const struct snd_soc_platform_driver dmaengine_pcm_platform = { + .component_driver = { + .probe_order = SND_SOC_COMP_ORDER_LATE, + }, .ops = &dmaengine_pcm_ops, .pcm_new = dmaengine_pcm_new, .pcm_free = dmaengine_pcm_free, - .probe_order = SND_SOC_COMP_ORDER_LATE, }; static const char * const dmaengine_pcm_dma_channel_names[] = { diff --git a/sound/soc/soc-io.c b/sound/soc/soc-io.c index 7767fbd73eb7..9b3939049cef 100644 --- a/sound/soc/soc-io.c +++ b/sound/soc/soc-io.c @@ -271,31 +271,3 @@ int snd_soc_platform_write(struct snd_soc_platform *platform, return snd_soc_component_write(&platform->component, reg, val); } EXPORT_SYMBOL_GPL(snd_soc_platform_write); - -/** - * snd_soc_component_init_io() - Initialize regmap IO - * - * @component: component to initialize - * @regmap: regmap instance to use for IO operations - * - * Return: 0 on success, a negative error code otherwise - */ -int snd_soc_component_init_io(struct snd_soc_component *component, - struct regmap *regmap) -{ - int ret; - - if (!regmap) - return -EINVAL; - - ret = regmap_get_val_bytes(regmap); - /* Errors are legitimate for non-integer byte - * multiples */ - if (ret > 0) - component->val_bytes = ret; - - component->regmap = regmap; - - return 0; -} -EXPORT_SYMBOL_GPL(snd_soc_component_init_io); |