Commit 27bcd37e authored by Linus Torvalds's avatar Linus Torvalds

Merge tag 'sound-4.9-rc5' of git://git.kernel.org/pub/scm/linux/kernel/git/tiwai/sound

Pull sound fixes from Takashi Iwai:
 "This became a largish pull-request, as we've got a bunch of pending
  ASoC fixes at this time. One noticeable change is the removal of error
  directive in uapi/sound/asoc.h. We found that the API has been already
  used on Chromebooks, so we need to support it even now.

  A slight big LOC is found in Qualcomm lpass driver, but the rest are
  all small and easy fixes for ASoC drivers (sti, sun4i, Realtek codecs,
  Intel, tas571x, etc) in addition to the patches to harden the ALSA
  core proc file accesses"

* tag 'sound-4.9-rc5' of git://git.kernel.org/pub/scm/linux/kernel/git/tiwai/sound: (26 commits)
  ALSA: info: Return error for invalid read/write
  ALSA: info: Limit the proc text input size
  ASoC: samsung: spdif: Fix DMA filter initialization
  ASoC: sun4i-codec: Enable bus clock after getting GPIO
  ASoC: lpass-cpu: add module licence and description
  ASoC: lpass-platform: Fix broken pcm data usage
  ASoC: sun4i-codec: return error code instead of NULL when create_card fails
  ASoC: hdmi-codec: Fix hdmi_of_xlate_dai_name when #sound-dai-cells = <0>
  ASoC: samsung: get access to DMA engine early to defer probe properly
  ASoC: da7219: Connect output enable register to DAIOUT
  ASoC: Intel: Skylake: Fix to turn off hdmi power on probe failure
  ASoC: sti-sas: enable fast io for regmap
  ASoC: sti: fix channel status update after playback start
  ASoC: PXA: Brownstone needs I2C
  ASoC: Intel: Skylake: Always acquire runtime pm ref on unload
  ASoC: Intel: Atom: add terminate entry for dmi_system_id tables
  ASoC: rt298: fix jack type detect error
  ASoC: rt5663: fix a debug statement
  ASoC: cs4270: fix DAPM stream name mismatch
  ASoC: Intel: haswell depends on sst-firmware
  ...
parents 3c6106da 6809cd68
...@@ -18,12 +18,6 @@ ...@@ -18,12 +18,6 @@
#include <linux/types.h> #include <linux/types.h>
#include <sound/asound.h> #include <sound/asound.h>
#ifndef __KERNEL__
#error This API is an early revision and not enabled in the current
#error kernel release, it will be enabled in a future kernel version
#error with incompatible changes to what is here.
#endif
/* /*
* Maximum number of channels topology kcontrol can represent. * Maximum number of channels topology kcontrol can represent.
*/ */
......
...@@ -325,10 +325,15 @@ static ssize_t snd_info_text_entry_write(struct file *file, ...@@ -325,10 +325,15 @@ static ssize_t snd_info_text_entry_write(struct file *file,
size_t next; size_t next;
int err = 0; int err = 0;
if (!entry->c.text.write)
return -EIO;
pos = *offset; pos = *offset;
if (!valid_pos(pos, count)) if (!valid_pos(pos, count))
return -EIO; return -EIO;
next = pos + count; next = pos + count;
/* don't handle too large text inputs */
if (next > 16 * 1024)
return -EIO;
mutex_lock(&entry->access); mutex_lock(&entry->access);
buf = data->wbuffer; buf = data->wbuffer;
if (!buf) { if (!buf) {
...@@ -366,7 +371,9 @@ static int snd_info_seq_show(struct seq_file *seq, void *p) ...@@ -366,7 +371,9 @@ static int snd_info_seq_show(struct seq_file *seq, void *p)
struct snd_info_private_data *data = seq->private; struct snd_info_private_data *data = seq->private;
struct snd_info_entry *entry = data->entry; struct snd_info_entry *entry = data->entry;
if (entry->c.text.read) { if (!entry->c.text.read) {
return -EIO;
} else {
data->rbuffer->buffer = (char *)seq; /* XXX hack! */ data->rbuffer->buffer = (char *)seq; /* XXX hack! */
entry->c.text.read(entry, data->rbuffer); entry->c.text.read(entry, data->rbuffer);
} }
......
...@@ -148,11 +148,11 @@ SND_SOC_DAPM_OUTPUT("AOUTR"), ...@@ -148,11 +148,11 @@ SND_SOC_DAPM_OUTPUT("AOUTR"),
}; };
static const struct snd_soc_dapm_route cs4270_dapm_routes[] = { static const struct snd_soc_dapm_route cs4270_dapm_routes[] = {
{ "Capture", NULL, "AINA" }, { "Capture", NULL, "AINL" },
{ "Capture", NULL, "AINB" }, { "Capture", NULL, "AINR" },
{ "AOUTA", NULL, "Playback" }, { "AOUTL", NULL, "Playback" },
{ "AOUTB", NULL, "Playback" }, { "AOUTR", NULL, "Playback" },
}; };
/** /**
......
...@@ -880,7 +880,8 @@ static const struct snd_soc_dapm_widget da7219_dapm_widgets[] = { ...@@ -880,7 +880,8 @@ static const struct snd_soc_dapm_widget da7219_dapm_widgets[] = {
SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
/* DAI */ /* DAI */
SND_SOC_DAPM_AIF_OUT("DAIOUT", "Capture", 0, SND_SOC_NOPM, 0, 0), SND_SOC_DAPM_AIF_OUT("DAIOUT", "Capture", 0, DA7219_DAI_TDM_CTRL,
DA7219_DAI_OE_SHIFT, DA7219_NO_INVERT),
SND_SOC_DAPM_AIF_IN("DAIIN", "Playback", 0, SND_SOC_NOPM, 0, 0), SND_SOC_DAPM_AIF_IN("DAIIN", "Playback", 0, SND_SOC_NOPM, 0, 0),
/* Output Muxes */ /* Output Muxes */
......
...@@ -364,7 +364,12 @@ static int hdmi_of_xlate_dai_name(struct snd_soc_component *component, ...@@ -364,7 +364,12 @@ static int hdmi_of_xlate_dai_name(struct snd_soc_component *component,
struct of_phandle_args *args, struct of_phandle_args *args,
const char **dai_name) const char **dai_name)
{ {
int id = args->args[0]; int id;
if (args->args_count)
id = args->args[0];
else
id = 0;
if (id < ARRAY_SIZE(hdmi_dai_name)) { if (id < ARRAY_SIZE(hdmi_dai_name)) {
*dai_name = hdmi_dai_name[id]; *dai_name = hdmi_dai_name[id];
......
...@@ -249,6 +249,11 @@ static int rt298_jack_detect(struct rt298_priv *rt298, bool *hp, bool *mic) ...@@ -249,6 +249,11 @@ static int rt298_jack_detect(struct rt298_priv *rt298, bool *hp, bool *mic)
snd_soc_dapm_force_enable_pin(dapm, "LDO1"); snd_soc_dapm_force_enable_pin(dapm, "LDO1");
snd_soc_dapm_sync(dapm); snd_soc_dapm_sync(dapm);
regmap_update_bits(rt298->regmap,
RT298_POWER_CTRL1, 0x1001, 0);
regmap_update_bits(rt298->regmap,
RT298_POWER_CTRL2, 0x4, 0x4);
regmap_write(rt298->regmap, RT298_SET_MIC1, 0x24); regmap_write(rt298->regmap, RT298_SET_MIC1, 0x24);
msleep(50); msleep(50);
......
...@@ -1547,11 +1547,11 @@ static int rt5663_jack_detect(struct snd_soc_codec *codec, int jack_insert) ...@@ -1547,11 +1547,11 @@ static int rt5663_jack_detect(struct snd_soc_codec *codec, int jack_insert)
msleep(sleep_time[i]); msleep(sleep_time[i]);
val = snd_soc_read(codec, RT5663_EM_JACK_TYPE_2) & val = snd_soc_read(codec, RT5663_EM_JACK_TYPE_2) &
0x0003; 0x0003;
dev_dbg(codec->dev, "%s: MX-00e7 val=%x sleep %d\n",
__func__, val, sleep_time[i]);
i++; i++;
if (val == 0x1 || val == 0x2 || val == 0x3) if (val == 0x1 || val == 0x2 || val == 0x3)
break; break;
dev_dbg(codec->dev, "%s: MX-00e7 val=%x sleep %d\n",
__func__, val, sleep_time[i]);
} }
dev_dbg(codec->dev, "%s val = %d\n", __func__, val); dev_dbg(codec->dev, "%s val = %d\n", __func__, val);
switch (val) { switch (val) {
......
...@@ -424,7 +424,7 @@ static const struct snd_soc_dai_ops stih407_dac_ops = { ...@@ -424,7 +424,7 @@ static const struct snd_soc_dai_ops stih407_dac_ops = {
static const struct regmap_config stih407_sas_regmap = { static const struct regmap_config stih407_sas_regmap = {
.reg_bits = 32, .reg_bits = 32,
.val_bits = 32, .val_bits = 32,
.fast_io = true,
.max_register = STIH407_AUDIO_DAC_CTRL, .max_register = STIH407_AUDIO_DAC_CTRL,
.reg_defaults = stih407_sas_reg_defaults, .reg_defaults = stih407_sas_reg_defaults,
.num_reg_defaults = ARRAY_SIZE(stih407_sas_reg_defaults), .num_reg_defaults = ARRAY_SIZE(stih407_sas_reg_defaults),
......
...@@ -341,20 +341,9 @@ static int tas571x_set_bias_level(struct snd_soc_codec *codec, ...@@ -341,20 +341,9 @@ static int tas571x_set_bias_level(struct snd_soc_codec *codec,
return ret; return ret;
} }
} }
gpiod_set_value(priv->pdn_gpio, 0);
usleep_range(5000, 6000);
regcache_cache_only(priv->regmap, false);
ret = regcache_sync(priv->regmap);
if (ret)
return ret;
} }
break; break;
case SND_SOC_BIAS_OFF: case SND_SOC_BIAS_OFF:
regcache_cache_only(priv->regmap, true);
gpiod_set_value(priv->pdn_gpio, 1);
if (!IS_ERR(priv->mclk)) if (!IS_ERR(priv->mclk))
clk_disable_unprepare(priv->mclk); clk_disable_unprepare(priv->mclk);
break; break;
...@@ -401,16 +390,6 @@ static const struct snd_kcontrol_new tas5711_controls[] = { ...@@ -401,16 +390,6 @@ static const struct snd_kcontrol_new tas5711_controls[] = {
TAS571X_SOFT_MUTE_REG, TAS571X_SOFT_MUTE_REG,
TAS571X_SOFT_MUTE_CH1_SHIFT, TAS571X_SOFT_MUTE_CH2_SHIFT, TAS571X_SOFT_MUTE_CH1_SHIFT, TAS571X_SOFT_MUTE_CH2_SHIFT,
1, 1), 1, 1),
SOC_DOUBLE_R_RANGE("CH1 Mixer Volume",
TAS5717_CH1_LEFT_CH_MIX_REG,
TAS5717_CH1_RIGHT_CH_MIX_REG,
16, 0, 0x80, 0),
SOC_DOUBLE_R_RANGE("CH2 Mixer Volume",
TAS5717_CH2_LEFT_CH_MIX_REG,
TAS5717_CH2_RIGHT_CH_MIX_REG,
16, 0, 0x80, 0),
}; };
static const struct regmap_range tas571x_readonly_regs_range[] = { static const struct regmap_range tas571x_readonly_regs_range[] = {
...@@ -488,6 +467,16 @@ static const struct snd_kcontrol_new tas5717_controls[] = { ...@@ -488,6 +467,16 @@ static const struct snd_kcontrol_new tas5717_controls[] = {
TAS571X_SOFT_MUTE_CH1_SHIFT, TAS571X_SOFT_MUTE_CH2_SHIFT, TAS571X_SOFT_MUTE_CH1_SHIFT, TAS571X_SOFT_MUTE_CH2_SHIFT,
1, 1), 1, 1),
SOC_DOUBLE_R_RANGE("CH1 Mixer Volume",
TAS5717_CH1_LEFT_CH_MIX_REG,
TAS5717_CH1_RIGHT_CH_MIX_REG,
16, 0, 0x80, 0),
SOC_DOUBLE_R_RANGE("CH2 Mixer Volume",
TAS5717_CH2_LEFT_CH_MIX_REG,
TAS5717_CH2_RIGHT_CH_MIX_REG,
16, 0, 0x80, 0),
/* /*
* The biquads are named according to the register names. * The biquads are named according to the register names.
* Please note that TI's TAS57xx Graphical Development Environment * Please note that TI's TAS57xx Graphical Development Environment
...@@ -747,13 +736,14 @@ static int tas571x_i2c_probe(struct i2c_client *client, ...@@ -747,13 +736,14 @@ static int tas571x_i2c_probe(struct i2c_client *client,
/* pulse the active low reset line for ~100us */ /* pulse the active low reset line for ~100us */
usleep_range(100, 200); usleep_range(100, 200);
gpiod_set_value(priv->reset_gpio, 0); gpiod_set_value(priv->reset_gpio, 0);
usleep_range(12000, 20000); usleep_range(13500, 20000);
} }
ret = regmap_write(priv->regmap, TAS571X_OSC_TRIM_REG, 0); ret = regmap_write(priv->regmap, TAS571X_OSC_TRIM_REG, 0);
if (ret) if (ret)
return ret; return ret;
usleep_range(50000, 60000);
memcpy(&priv->codec_driver, &tas571x_codec, sizeof(priv->codec_driver)); memcpy(&priv->codec_driver, &tas571x_codec, sizeof(priv->codec_driver));
priv->codec_driver.component_driver.controls = priv->chip->controls; priv->codec_driver.component_driver.controls = priv->chip->controls;
...@@ -770,9 +760,6 @@ static int tas571x_i2c_probe(struct i2c_client *client, ...@@ -770,9 +760,6 @@ static int tas571x_i2c_probe(struct i2c_client *client,
return ret; return ret;
} }
regcache_cache_only(priv->regmap, true);
gpiod_set_value(priv->pdn_gpio, 1);
return snd_soc_register_codec(&client->dev, &priv->codec_driver, return snd_soc_register_codec(&client->dev, &priv->codec_driver,
&tas571x_dai, 1); &tas571x_dai, 1);
} }
......
...@@ -47,6 +47,7 @@ config SND_SOC_INTEL_SST_MATCH ...@@ -47,6 +47,7 @@ config SND_SOC_INTEL_SST_MATCH
config SND_SOC_INTEL_HASWELL config SND_SOC_INTEL_HASWELL
tristate tristate
select SND_SOC_INTEL_SST_FIRMWARE
config SND_SOC_INTEL_BAYTRAIL config SND_SOC_INTEL_BAYTRAIL
tristate tristate
...@@ -56,7 +57,6 @@ config SND_SOC_INTEL_HASWELL_MACH ...@@ -56,7 +57,6 @@ config SND_SOC_INTEL_HASWELL_MACH
depends on X86_INTEL_LPSS && I2C && I2C_DESIGNWARE_PLATFORM depends on X86_INTEL_LPSS && I2C && I2C_DESIGNWARE_PLATFORM
depends on DW_DMAC_CORE depends on DW_DMAC_CORE
select SND_SOC_INTEL_SST select SND_SOC_INTEL_SST
select SND_SOC_INTEL_SST_FIRMWARE
select SND_SOC_INTEL_HASWELL select SND_SOC_INTEL_HASWELL
select SND_SOC_RT5640 select SND_SOC_RT5640
help help
...@@ -138,7 +138,6 @@ config SND_SOC_INTEL_BROADWELL_MACH ...@@ -138,7 +138,6 @@ config SND_SOC_INTEL_BROADWELL_MACH
I2C_DESIGNWARE_PLATFORM I2C_DESIGNWARE_PLATFORM
depends on DW_DMAC_CORE depends on DW_DMAC_CORE
select SND_SOC_INTEL_SST select SND_SOC_INTEL_SST
select SND_SOC_INTEL_SST_FIRMWARE
select SND_SOC_INTEL_HASWELL select SND_SOC_INTEL_HASWELL
select SND_SOC_RT286 select SND_SOC_RT286
help help
......
...@@ -416,6 +416,7 @@ static const struct dmi_system_id cht_table[] = { ...@@ -416,6 +416,7 @@ static const struct dmi_system_id cht_table[] = {
DMI_MATCH(DMI_PRODUCT_NAME, "Surface 3"), DMI_MATCH(DMI_PRODUCT_NAME, "Surface 3"),
}, },
}, },
{ }
}; };
......
...@@ -130,8 +130,8 @@ static int broxton_da7219_codec_init(struct snd_soc_pcm_runtime *rtd) ...@@ -130,8 +130,8 @@ static int broxton_da7219_codec_init(struct snd_soc_pcm_runtime *rtd)
*/ */
ret = snd_soc_card_jack_new(rtd->card, "Headset Jack", ret = snd_soc_card_jack_new(rtd->card, "Headset Jack",
SND_JACK_HEADSET | SND_JACK_BTN_0 | SND_JACK_BTN_1 | SND_JACK_HEADSET | SND_JACK_BTN_0 | SND_JACK_BTN_1 |
SND_JACK_BTN_2 | SND_JACK_BTN_3, &broxton_headset, SND_JACK_BTN_2 | SND_JACK_BTN_3 | SND_JACK_LINEOUT,
NULL, 0); &broxton_headset, NULL, 0);
if (ret) { if (ret) {
dev_err(rtd->dev, "Headset Jack creation failed: %d\n", ret); dev_err(rtd->dev, "Headset Jack creation failed: %d\n", ret);
return ret; return ret;
......
...@@ -674,7 +674,7 @@ static int skl_probe(struct pci_dev *pci, ...@@ -674,7 +674,7 @@ static int skl_probe(struct pci_dev *pci,
if (skl->nhlt == NULL) { if (skl->nhlt == NULL) {
err = -ENODEV; err = -ENODEV;
goto out_free; goto out_display_power_off;
} }
skl_nhlt_update_topology_bin(skl); skl_nhlt_update_topology_bin(skl);
...@@ -746,6 +746,9 @@ static int skl_probe(struct pci_dev *pci, ...@@ -746,6 +746,9 @@ static int skl_probe(struct pci_dev *pci,
skl_machine_device_unregister(skl); skl_machine_device_unregister(skl);
out_nhlt_free: out_nhlt_free:
skl_nhlt_free(skl->nhlt); skl_nhlt_free(skl->nhlt);
out_display_power_off:
if (IS_ENABLED(CONFIG_SND_SOC_HDAC_HDMI))
snd_hdac_display_power(bus, false);
out_free: out_free:
skl->init_failed = 1; skl->init_failed = 1;
skl_free(ebus); skl_free(ebus);
...@@ -785,8 +788,7 @@ static void skl_remove(struct pci_dev *pci) ...@@ -785,8 +788,7 @@ static void skl_remove(struct pci_dev *pci)
release_firmware(skl->tplg); release_firmware(skl->tplg);
if (pci_dev_run_wake(pci)) pm_runtime_get_noresume(&pci->dev);
pm_runtime_get_noresume(&pci->dev);
/* codec removal, invoke bus_device_remove */ /* codec removal, invoke bus_device_remove */
snd_hdac_ext_bus_device_remove(ebus); snd_hdac_ext_bus_device_remove(ebus);
......
...@@ -208,7 +208,7 @@ config SND_PXA2XX_SOC_IMOTE2 ...@@ -208,7 +208,7 @@ config SND_PXA2XX_SOC_IMOTE2
config SND_MMP_SOC_BROWNSTONE config SND_MMP_SOC_BROWNSTONE
tristate "SoC Audio support for Marvell Brownstone" tristate "SoC Audio support for Marvell Brownstone"
depends on SND_MMP_SOC && MACH_BROWNSTONE depends on SND_MMP_SOC && MACH_BROWNSTONE && I2C
select SND_MMP_SOC_SSPA select SND_MMP_SOC_SSPA
select MFD_WM8994 select MFD_WM8994
select SND_SOC_WM8994 select SND_SOC_WM8994
......
...@@ -586,3 +586,6 @@ int asoc_qcom_lpass_cpu_platform_remove(struct platform_device *pdev) ...@@ -586,3 +586,6 @@ int asoc_qcom_lpass_cpu_platform_remove(struct platform_device *pdev)
return 0; return 0;
} }
EXPORT_SYMBOL_GPL(asoc_qcom_lpass_cpu_platform_remove); EXPORT_SYMBOL_GPL(asoc_qcom_lpass_cpu_platform_remove);
MODULE_DESCRIPTION("QTi LPASS CPU Driver");
MODULE_LICENSE("GPL v2");
...@@ -61,7 +61,40 @@ static int lpass_platform_pcmops_open(struct snd_pcm_substream *substream) ...@@ -61,7 +61,40 @@ static int lpass_platform_pcmops_open(struct snd_pcm_substream *substream)
{ {
struct snd_pcm_runtime *runtime = substream->runtime; struct snd_pcm_runtime *runtime = substream->runtime;
struct snd_soc_pcm_runtime *soc_runtime = substream->private_data; struct snd_soc_pcm_runtime *soc_runtime = substream->private_data;
int ret; struct snd_soc_dai *cpu_dai = soc_runtime->cpu_dai;
struct lpass_data *drvdata =
snd_soc_platform_get_drvdata(soc_runtime->platform);
struct lpass_variant *v = drvdata->variant;
int ret, dma_ch, dir = substream->stream;
struct lpass_pcm_data *data;
data = devm_kzalloc(soc_runtime->dev, sizeof(*data), GFP_KERNEL);
if (!data)
return -ENOMEM;
data->i2s_port = cpu_dai->driver->id;
runtime->private_data = data;
if (v->alloc_dma_channel)
dma_ch = v->alloc_dma_channel(drvdata, dir);
if (dma_ch < 0)
return dma_ch;
drvdata->substream[dma_ch] = substream;
ret = regmap_write(drvdata->lpaif_map,
LPAIF_DMACTL_REG(v, dma_ch, dir), 0);
if (ret) {
dev_err(soc_runtime->dev,
"%s() error writing to rdmactl reg: %d\n",
__func__, ret);
return ret;
}
if (dir == SNDRV_PCM_STREAM_PLAYBACK)
data->rdma_ch = dma_ch;
else
data->wrdma_ch = dma_ch;
snd_soc_set_runtime_hwparams(substream, &lpass_platform_pcm_hardware); snd_soc_set_runtime_hwparams(substream, &lpass_platform_pcm_hardware);
...@@ -80,13 +113,40 @@ static int lpass_platform_pcmops_open(struct snd_pcm_substream *substream) ...@@ -80,13 +113,40 @@ static int lpass_platform_pcmops_open(struct snd_pcm_substream *substream)
return 0; return 0;
} }
static int lpass_platform_pcmops_close(struct snd_pcm_substream *substream)
{
struct snd_pcm_runtime *runtime = substream->runtime;
struct snd_soc_pcm_runtime *soc_runtime = substream->private_data;
struct lpass_data *drvdata =
snd_soc_platform_get_drvdata(soc_runtime->platform);
struct lpass_variant *v = drvdata->variant;
struct lpass_pcm_data *data;
int dma_ch, dir = substream->stream;
data = runtime->private_data;
v = drvdata->variant;
if (dir == SNDRV_PCM_STREAM_PLAYBACK)
dma_ch = data->rdma_ch;
else
dma_ch = data->wrdma_ch;
drvdata->substream[dma_ch] = NULL;
if (v->free_dma_channel)
v->free_dma_channel(drvdata, dma_ch);
return 0;
}
static int lpass_platform_pcmops_hw_params(struct snd_pcm_substream *substream, static int lpass_platform_pcmops_hw_params(struct snd_pcm_substream *substream,
struct snd_pcm_hw_params *params) struct snd_pcm_hw_params *params)
{ {
struct snd_soc_pcm_runtime *soc_runtime = substream->private_data; struct snd_soc_pcm_runtime *soc_runtime = substream->private_data;
struct lpass_data *drvdata = struct lpass_data *drvdata =
snd_soc_platform_get_drvdata(soc_runtime->platform); snd_soc_platform_get_drvdata(soc_runtime->platform);
struct lpass_pcm_data *pcm_data = drvdata->private_data; struct snd_pcm_runtime *rt = substream->runtime;
struct lpass_pcm_data *pcm_data = rt->private_data;
struct lpass_variant *v = drvdata->variant; struct lpass_variant *v = drvdata->variant;
snd_pcm_format_t format = params_format(params); snd_pcm_format_t format = params_format(params);
unsigned int channels = params_channels(params); unsigned int channels = params_channels(params);
...@@ -179,7 +239,8 @@ static int lpass_platform_pcmops_hw_free(struct snd_pcm_substream *substream) ...@@ -179,7 +239,8 @@ static int lpass_platform_pcmops_hw_free(struct snd_pcm_substream *substream)
struct snd_soc_pcm_runtime *soc_runtime = substream->private_data; struct snd_soc_pcm_runtime *soc_runtime = substream->private_data;
struct lpass_data *drvdata = struct lpass_data *drvdata =
snd_soc_platform_get_drvdata(soc_runtime->platform); snd_soc_platform_get_drvdata(soc_runtime->platform);
struct lpass_pcm_data *pcm_data = drvdata->private_data; struct snd_pcm_runtime *rt = substream->runtime;
struct lpass_pcm_data *pcm_data = rt->private_data;
struct lpass_variant *v = drvdata->variant; struct lpass_variant *v = drvdata->variant;
unsigned int reg; unsigned int reg;
int ret; int ret;
...@@ -203,7 +264,8 @@ static int lpass_platform_pcmops_prepare(struct snd_pcm_substream *substream) ...@@ -203,7 +264,8 @@ static int lpass_platform_pcmops_prepare(struct snd_pcm_substream *substream)
struct snd_soc_pcm_runtime *soc_runtime = substream->private_data; struct snd_soc_pcm_runtime *soc_runtime = substream->private_data;
struct lpass_data *drvdata = struct lpass_data *drvdata =
snd_soc_platform_get_drvdata(soc_runtime->platform); snd_soc_platform_get_drvdata(soc_runtime->platform);
struct lpass_pcm_data *pcm_data = drvdata->private_data; struct snd_pcm_runtime *rt = substream->runtime;
struct lpass_pcm_data *pcm_data = rt->private_data;
struct lpass_variant *v = drvdata->variant; struct lpass_variant *v = drvdata->variant;
int ret, ch, dir = substream->stream; int ret, ch, dir = substream->stream;
...@@ -257,7 +319,8 @@ static int lpass_platform_pcmops_trigger(struct snd_pcm_substream *substream, ...@@ -257,7 +319,8 @@ static int lpass_platform_pcmops_trigger(struct snd_pcm_substream *substream,
struct snd_soc_pcm_runtime *soc_runtime = substream->private_data; struct snd_soc_pcm_runtime *soc_runtime = substream->private_data;
struct lpass_data *drvdata = struct lpass_data *drvdata =
snd_soc_platform_get_drvdata(soc_runtime->platform); snd_soc_platform_get_drvdata(soc_runtime->platform);
struct lpass_pcm_data *pcm_data = drvdata->private_data; struct snd_pcm_runtime *rt = substream->runtime;
struct lpass_pcm_data *pcm_data = rt->private_data;
struct lpass_variant *v = drvdata->variant; struct lpass_variant *v = drvdata->variant;
int ret, ch, dir = substream->stream; int ret, ch, dir = substream->stream;
...@@ -333,7 +396,8 @@ static snd_pcm_uframes_t lpass_platform_pcmops_pointer( ...@@ -333,7 +396,8 @@ static snd_pcm_uframes_t lpass_platform_pcmops_pointer(
struct snd_soc_pcm_runtime *soc_runtime = substream->private_data; struct snd_soc_pcm_runtime *soc_runtime = substream->private_data;
struct lpass_data *drvdata = struct lpass_data *drvdata =
snd_soc_platform_get_drvdata(soc_runtime->platform); snd_soc_platform_get_drvdata(soc_runtime->platform);
struct lpass_pcm_data *pcm_data = drvdata->private_data; struct snd_pcm_runtime *rt = substream->runtime;
struct lpass_pcm_data *pcm_data = rt->private_data;
struct lpass_variant *v = drvdata->variant; struct lpass_variant *v = drvdata->variant;
unsigned int base_addr, curr_addr; unsigned int base_addr, curr_addr;
int ret, ch, dir = substream->stream; int ret, ch, dir = substream->stream;
...@@ -374,6 +438,7 @@ static int lpass_platform_pcmops_mmap(struct snd_pcm_substream *substream, ...@@ -374,6 +438,7 @@ static int lpass_platform_pcmops_mmap(struct snd_pcm_substream *substream,
static const struct snd_pcm_ops lpass_platform_pcm_ops = { static const struct snd_pcm_ops lpass_platform_pcm_ops = {
.open = lpass_platform_pcmops_open, .open = lpass_platform_pcmops_open,
.close = lpass_platform_pcmops_close,
.ioctl = snd_pcm_lib_ioctl, .ioctl = snd_pcm_lib_ioctl,
.hw_params = lpass_platform_pcmops_hw_params, .hw_params = lpass_platform_pcmops_hw_params,
.hw_free = lpass_platform_pcmops_hw_free, .hw_free = lpass_platform_pcmops_hw_free,
...@@ -470,117 +535,45 @@ static int lpass_platform_pcm_new(struct snd_soc_pcm_runtime *soc_runtime) ...@@ -470,117 +535,45 @@ static int lpass_platform_pcm_new(struct snd_soc_pcm_runtime *soc_runtime)
{ {
struct snd_pcm *pcm = soc_runtime->pcm; struct snd_pcm *pcm = soc_runtime->pcm;
struct snd_pcm_substream *psubstream, *csubstream; struct snd_pcm_substream *psubstream, *csubstream;
struct snd_soc_dai *cpu_dai = soc_runtime->cpu_dai;
struct lpass_data *drvdata =
snd_soc_platform_get_drvdata(soc_runtime->platform);
struct lpass_variant *v = drvdata->variant;
int ret = -EINVAL; int ret = -EINVAL;
struct lpass_pcm_data *data;
size_t size = lpass_platform_pcm_hardware.buffer_bytes_max; size_t size = lpass_platform_pcm_hardware.buffer_bytes_max;
data = devm_kzalloc(soc_runtime->dev, sizeof(*data), GFP_KERNEL);
if (!data)
return -ENOMEM;
data->i2s_port = cpu_dai->driver->id;
drvdata->private_data = data;
psubstream = pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream; psubstream = pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream;
if (psubstream) { if (psubstream) {
if (v->alloc_dma_channel)
data->rdma_ch = v->alloc_dma_channel(drvdata,
SNDRV_PCM_STREAM_PLAYBACK);
if (data->rdma_ch < 0)
return data->rdma_ch;
drvdata->substream[data->rdma_ch] = psubstream;
ret = snd_dma_alloc_pages(SNDRV_DMA_TYPE_DEV, ret = snd_dma_alloc_pages(SNDRV_DMA_TYPE_DEV,
soc_runtime->platform->dev, soc_runtime->platform->dev,
size, &psubstream->dma_buffer); size, &psubstream->dma_buffer);
if (ret)
goto playback_alloc_err;
ret = regmap_write(drvdata->lpaif_map,
LPAIF_RDMACTL_REG(v, data->rdma_ch), 0);
if (ret) { if (ret) {
dev_err(soc_runtime->dev, dev_err(soc_runtime->dev, "Cannot allocate buffer(s)\n");
"%s() error writing to rdmactl reg: %d\n", return ret;
__func__, ret);
goto capture_alloc_err;
} }
} }
csubstream = pcm->streams[SNDRV_PCM_STREAM_CAPTURE].substream; csubstream = pcm->streams[SNDRV_PCM_STREAM_CAPTURE].substream;
if (csubstream) { if (csubstream) {
if (v->alloc_dma_channel)
data->wrdma_ch = v->alloc_dma_channel(drvdata,
SNDRV_PCM_STREAM_CAPTURE);
if (data->wrdma_ch < 0) {
ret = data->wrdma_ch;
goto capture_alloc_err;
}
drvdata->substream[data->wrdma_ch] = csubstream;
ret = snd_dma_alloc_pages(SNDRV_DMA_TYPE_DEV, ret = snd_dma_alloc_pages(SNDRV_DMA_TYPE_DEV,
soc_runtime->platform->dev, soc_runtime->platform->dev,
size, &csubstream->dma_buffer); size, &csubstream->dma_buffer);
if (ret)
goto capture_alloc_err;
ret = regmap_write(drvdata->lpaif_map,
LPAIF_WRDMACTL_REG(v, data->wrdma_ch), 0);
if (ret) { if (ret) {
dev_err(soc_runtime->dev, dev_err(soc_runtime->dev, "Cannot allocate buffer(s)\n");
"%s() error writing to wrdmactl reg: %d\n", if (psubstream)
__func__, ret); snd_dma_free_pages(&psubstream->dma_buffer);
goto capture_reg_err; return ret;
} }
} }
return 0; return 0;
capture_reg_err:
if (csubstream)
snd_dma_free_pages(&csubstream->dma_buffer);
capture_alloc_err:
if (psubstream)
snd_dma_free_pages(&psubstream->dma_buffer);
playback_alloc_err:
dev_err(soc_runtime->dev, "Cannot allocate buffer(s)\n");
return ret;
} }
static void lpass_platform_pcm_free(struct snd_pcm *pcm) static void lpass_platform_pcm_free(struct snd_pcm *pcm)
{ {
struct snd_soc_pcm_runtime *rt;
struct lpass_data *drvdata;
struct lpass_pcm_data *data;
struct lpass_variant *v;
struct snd_pcm_substream *substream; struct snd_pcm_substream *substream;
int ch, i; int i;
for (i = 0; i < ARRAY_SIZE(pcm->streams); i++) { for (i = 0; i < ARRAY_SIZE(pcm->streams); i++) {
substream = pcm->streams[i].substream; substream = pcm->streams[i].substream;
if (substream) { if (substream) {
rt = substream->private_data;
drvdata = snd_soc_platform_get_drvdata(rt->platform);
data = drvdata->private_data;
ch = (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
? data->rdma_ch
: data->wrdma_ch;
v = drvdata->variant;
drvdata->substream[ch] = NULL;
if (v->free_dma_channel)
v->free_dma_channel(drvdata, ch);
snd_dma_free_pages(&substream->dma_buffer); snd_dma_free_pages(&substream->dma_buffer);
substream->dma_buffer.area = NULL; substream->dma_buffer.area = NULL;
substream->dma_buffer.addr = 0; substream->dma_buffer.addr = 0;
......
...@@ -59,7 +59,6 @@ struct lpass_data { ...@@ -59,7 +59,6 @@ struct lpass_data {
struct clk *pcnoc_mport_clk; struct clk *pcnoc_mport_clk;
struct clk *pcnoc_sway_clk; struct clk *pcnoc_sway_clk;
void *private_data;
}; };
/* Vairant data per each SOC */ /* Vairant data per each SOC */
......
...@@ -383,11 +383,6 @@ static int s3c_ac97_probe(struct platform_device *pdev) ...@@ -383,11 +383,6 @@ static int s3c_ac97_probe(struct platform_device *pdev)
goto err4; goto err4;
} }
ret = devm_snd_soc_register_component(&pdev->dev, &s3c_ac97_component,
s3c_ac97_dai, ARRAY_SIZE(s3c_ac97_dai));
if (ret)
goto err5;
ret = samsung_asoc_dma_platform_register(&pdev->dev, ret = samsung_asoc_dma_platform_register(&pdev->dev,
ac97_pdata->dma_filter, ac97_pdata->dma_filter,
NULL, NULL); NULL, NULL);
...@@ -396,6 +391,11 @@ static int s3c_ac97_probe(struct platform_device *pdev) ...@@ -396,6 +391,11 @@ static int s3c_ac97_probe(struct platform_device *pdev)
goto err5; goto err5;
} }
ret = devm_snd_soc_register_component(&pdev->dev, &s3c_ac97_component,
s3c_ac97_dai, ARRAY_SIZE(s3c_ac97_dai));
if (ret)
goto err5;
return 0; return 0;
err5: err5:
free_irq(irq_res->start, NULL); free_irq(irq_res->start, NULL);
......
...@@ -1237,14 +1237,14 @@ static int samsung_i2s_probe(struct platform_device *pdev) ...@@ -1237,14 +1237,14 @@ static int samsung_i2s_probe(struct platform_device *pdev)
dev_err(&pdev->dev, "Unable to get drvdata\n"); dev_err(&pdev->dev, "Unable to get drvdata\n");
return -EFAULT; return -EFAULT;
} }
ret = devm_snd_soc_register_component(&sec_dai->pdev->dev, ret = samsung_asoc_dma_platform_register(&pdev->dev,
&samsung_i2s_component, sec_dai->filter, "tx-sec", NULL);
&sec_dai->i2s_dai_drv, 1);
if (ret != 0) if (ret != 0)
return ret; return ret;
return samsung_asoc_dma_platform_register(&pdev->dev, return devm_snd_soc_register_component(&sec_dai->pdev->dev,
sec_dai->filter, "tx-sec", NULL); &samsung_i2s_component,
&sec_dai->i2s_dai_drv, 1);
} }
pri_dai = i2s_alloc_dai(pdev, false); pri_dai = i2s_alloc_dai(pdev, false);
...@@ -1314,6 +1314,11 @@ static int samsung_i2s_probe(struct platform_device *pdev) ...@@ -1314,6 +1314,11 @@ static int samsung_i2s_probe(struct platform_device *pdev)
if (quirks & QUIRK_PRI_6CHAN) if (quirks & QUIRK_PRI_6CHAN)
pri_dai->i2s_dai_drv.playback.channels_max = 6; pri_dai->i2s_dai_drv.playback.channels_max = 6;
ret = samsung_asoc_dma_platform_register(&pdev->dev, pri_dai->filter,
NULL, NULL);
if (ret < 0)
goto err_disable_clk;
if (quirks & QUIRK_SEC_DAI) { if (quirks & QUIRK_SEC_DAI) {
sec_dai = i2s_alloc_dai(pdev, true); sec_dai = i2s_alloc_dai(pdev, true);
if (!sec_dai) { if (!sec_dai) {
...@@ -1353,10 +1358,6 @@ static int samsung_i2s_probe(struct platform_device *pdev) ...@@ -1353,10 +1358,6 @@ static int samsung_i2s_probe(struct platform_device *pdev)
if (ret < 0) if (ret < 0)
goto err_free_dai; goto err_free_dai;
ret = samsung_asoc_dma_platform_register(&pdev->dev, pri_dai->filter,
NULL, NULL);
if (ret < 0)
goto err_free_dai;
pm_runtime_enable(&pdev->dev); pm_runtime_enable(&pdev->dev);
......
...@@ -565,24 +565,25 @@ static int s3c_pcm_dev_probe(struct platform_device *pdev) ...@@ -565,24 +565,25 @@ static int s3c_pcm_dev_probe(struct platform_device *pdev)
pcm->dma_capture = &s3c_pcm_stereo_in[pdev->id]; pcm->dma_capture = &s3c_pcm_stereo_in[pdev->id];
pcm->dma_playback = &s3c_pcm_stereo_out[pdev->id]; pcm->dma_playback = &s3c_pcm_stereo_out[pdev->id];
ret = samsung_asoc_dma_platform_register(&pdev->dev, filter,
NULL, NULL);
if (ret) {
dev_err(&pdev->dev, "failed to get register DMA: %d\n", ret);
goto err5;
}
pm_runtime_enable(&pdev->dev); pm_runtime_enable(&pdev->dev);
ret = devm_snd_soc_register_component(&pdev->dev, &s3c_pcm_component, ret = devm_snd_soc_register_component(&pdev->dev, &s3c_pcm_component,
&s3c_pcm_dai[pdev->id], 1); &s3c_pcm_dai[pdev->id], 1);
if (ret != 0) { if (ret != 0) {
dev_err(&pdev->dev, "failed to get register DAI: %d\n", ret); dev_err(&pdev->dev, "failed to get register DAI: %d\n", ret);
goto err5; goto err6;
}
ret = samsung_asoc_dma_platform_register(&pdev->dev, filter,
NULL, NULL);
if (ret) {
dev_err(&pdev->dev, "failed to get register DMA: %d\n", ret);
goto err5;
} }
return 0; return 0;
err6:
pm_runtime_disable(&pdev->dev);
err5: err5:
clk_disable_unprepare(pcm->pclk); clk_disable_unprepare(pcm->pclk);
err4: err4:
......
...@@ -168,19 +168,19 @@ static int s3c2412_iis_dev_probe(struct platform_device *pdev) ...@@ -168,19 +168,19 @@ static int s3c2412_iis_dev_probe(struct platform_device *pdev)
s3c2412_i2s_pcm_stereo_in.addr = res->start + S3C2412_IISRXD; s3c2412_i2s_pcm_stereo_in.addr = res->start + S3C2412_IISRXD;
s3c2412_i2s_pcm_stereo_in.filter_data = pdata->dma_capture; s3c2412_i2s_pcm_stereo_in.filter_data = pdata->dma_capture;
ret = s3c_i2sv2_register_component(&pdev->dev, -1, ret = samsung_asoc_dma_platform_register(&pdev->dev,
&s3c2412_i2s_component, pdata->dma_filter,
&s3c2412_i2s_dai); NULL, NULL);
if (ret) { if (ret) {
pr_err("failed to register the dai\n"); pr_err("failed to register the DMA: %d\n", ret);
return ret; return ret;
} }
ret = samsung_asoc_dma_platform_register(&pdev->dev, ret = s3c_i2sv2_register_component(&pdev->dev, -1,
pdata->dma_filter, &s3c2412_i2s_component,
NULL, NULL); &s3c2412_i2s_dai);
if (ret) if (ret)
pr_err("failed to register the DMA: %d\n", ret); pr_err("failed to register the dai\n");
return ret; return ret;
} }
......
...@@ -474,18 +474,18 @@ static int s3c24xx_iis_dev_probe(struct platform_device *pdev) ...@@ -474,18 +474,18 @@ static int s3c24xx_iis_dev_probe(struct platform_device *pdev)
s3c24xx_i2s_pcm_stereo_in.addr = res->start + S3C2410_IISFIFO; s3c24xx_i2s_pcm_stereo_in.addr = res->start + S3C2410_IISFIFO;
s3c24xx_i2s_pcm_stereo_in.filter_data = pdata->dma_capture; s3c24xx_i2s_pcm_stereo_in.filter_data = pdata->dma_capture;
ret = devm_snd_soc_register_component(&pdev->dev, ret = samsung_asoc_dma_platform_register(&pdev->dev,
&s3c24xx_i2s_component, &s3c24xx_i2s_dai, 1); pdata->dma_filter,
NULL, NULL);
if (ret) { if (ret) {
pr_err("failed to register the dai\n"); pr_err("failed to register the dma: %d\n", ret);
return ret; return ret;
} }
ret = samsung_asoc_dma_platform_register(&pdev->dev, ret = devm_snd_soc_register_component(&pdev->dev,
pdata->dma_filter, &s3c24xx_i2s_component, &s3c24xx_i2s_dai, 1);
NULL, NULL);
if (ret) if (ret)
pr_err("failed to register the dma: %d\n", ret); pr_err("failed to register the dai\n");
return ret; return ret;
} }
......
...@@ -416,15 +416,6 @@ static int spdif_probe(struct platform_device *pdev) ...@@ -416,15 +416,6 @@ static int spdif_probe(struct platform_device *pdev)
goto err3; goto err3;
} }
dev_set_drvdata(&pdev->dev, spdif);
ret = devm_snd_soc_register_component(&pdev->dev,
&samsung_spdif_component, &samsung_spdif_dai, 1);
if (ret != 0) {
dev_err(&pdev->dev, "fail to register dai\n");
goto err4;
}
spdif_stereo_out.addr_width = 2; spdif_stereo_out.addr_width = 2;
spdif_stereo_out.addr = mem_res->start + DATA_OUTBUF; spdif_stereo_out.addr = mem_res->start + DATA_OUTBUF;
filter = NULL; filter = NULL;
...@@ -432,7 +423,6 @@ static int spdif_probe(struct platform_device *pdev) ...@@ -432,7 +423,6 @@ static int spdif_probe(struct platform_device *pdev)
spdif_stereo_out.filter_data = spdif_pdata->dma_playback; spdif_stereo_out.filter_data = spdif_pdata->dma_playback;
filter = spdif_pdata->dma_filter; filter = spdif_pdata->dma_filter;
} }
spdif->dma_playback = &spdif_stereo_out; spdif->dma_playback = &spdif_stereo_out;
ret = samsung_asoc_dma_platform_register(&pdev->dev, filter, ret = samsung_asoc_dma_platform_register(&pdev->dev, filter,
...@@ -442,6 +432,15 @@ static int spdif_probe(struct platform_device *pdev) ...@@ -442,6 +432,15 @@ static int spdif_probe(struct platform_device *pdev)
goto err4; goto err4;
} }
dev_set_drvdata(&pdev->dev, spdif);
ret = devm_snd_soc_register_component(&pdev->dev,
&samsung_spdif_component, &samsung_spdif_dai, 1);
if (ret != 0) {
dev_err(&pdev->dev, "fail to register dai\n");
goto err4;
}
return 0; return 0;
err4: err4:
iounmap(spdif->regs); iounmap(spdif->regs);
......
...@@ -614,7 +614,11 @@ static int uni_player_ctl_iec958_put(struct snd_kcontrol *kcontrol, ...@@ -614,7 +614,11 @@ static int uni_player_ctl_iec958_put(struct snd_kcontrol *kcontrol,
iec958->status[3] = ucontrol->value.iec958.status[3]; iec958->status[3] = ucontrol->value.iec958.status[3];
mutex_unlock(&player->ctrl_lock); mutex_unlock(&player->ctrl_lock);
uni_player_set_channel_status(player, NULL); if (player->substream && player->substream->runtime)
uni_player_set_channel_status(player,
player->substream->runtime);
else
uni_player_set_channel_status(player, NULL);
return 0; return 0;
} }
......
...@@ -765,11 +765,11 @@ static struct snd_soc_card *sun4i_codec_create_card(struct device *dev) ...@@ -765,11 +765,11 @@ static struct snd_soc_card *sun4i_codec_create_card(struct device *dev)
card = devm_kzalloc(dev, sizeof(*card), GFP_KERNEL); card = devm_kzalloc(dev, sizeof(*card), GFP_KERNEL);
if (!card) if (!card)
return NULL; return ERR_PTR(-ENOMEM);
card->dai_link = sun4i_codec_create_link(dev, &card->num_links); card->dai_link = sun4i_codec_create_link(dev, &card->num_links);
if (!card->dai_link) if (!card->dai_link)
return NULL; return ERR_PTR(-ENOMEM);
card->dev = dev; card->dev = dev;
card->name = "sun4i-codec"; card->name = "sun4i-codec";
...@@ -829,12 +829,6 @@ static int sun4i_codec_probe(struct platform_device *pdev) ...@@ -829,12 +829,6 @@ static int sun4i_codec_probe(struct platform_device *pdev)
return PTR_ERR(scodec->clk_module); return PTR_ERR(scodec->clk_module);
} }
/* Enable the bus clock */
if (clk_prepare_enable(scodec->clk_apb)) {
dev_err(&pdev->dev, "Failed to enable the APB clock\n");
return -EINVAL;
}
scodec->gpio_pa = devm_gpiod_get_optional(&pdev->dev, "allwinner,pa", scodec->gpio_pa = devm_gpiod_get_optional(&pdev->dev, "allwinner,pa",
GPIOD_OUT_LOW); GPIOD_OUT_LOW);
if (IS_ERR(scodec->gpio_pa)) { if (IS_ERR(scodec->gpio_pa)) {
...@@ -844,6 +838,12 @@ static int sun4i_codec_probe(struct platform_device *pdev) ...@@ -844,6 +838,12 @@ static int sun4i_codec_probe(struct platform_device *pdev)
return ret; return ret;
} }
/* Enable the bus clock */
if (clk_prepare_enable(scodec->clk_apb)) {
dev_err(&pdev->dev, "Failed to enable the APB clock\n");
return -EINVAL;
}
/* DMA configuration for TX FIFO */ /* DMA configuration for TX FIFO */
scodec->playback_dma_data.addr = res->start + SUN4I_CODEC_DAC_TXDATA; scodec->playback_dma_data.addr = res->start + SUN4I_CODEC_DAC_TXDATA;
scodec->playback_dma_data.maxburst = 4; scodec->playback_dma_data.maxburst = 4;
...@@ -876,7 +876,8 @@ static int sun4i_codec_probe(struct platform_device *pdev) ...@@ -876,7 +876,8 @@ static int sun4i_codec_probe(struct platform_device *pdev)
} }
card = sun4i_codec_create_card(&pdev->dev); card = sun4i_codec_create_card(&pdev->dev);
if (!card) { if (IS_ERR(card)) {
ret = PTR_ERR(card);
dev_err(&pdev->dev, "Failed to create our card\n"); dev_err(&pdev->dev, "Failed to create our card\n");
goto err_unregister_codec; goto err_unregister_codec;
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment