diff --git a/drivers/bluetooth/hci_qca.c b/drivers/bluetooth/hci_qca.c index 9b2cf6429c855..f595a0f0aee2a 100644 --- a/drivers/bluetooth/hci_qca.c +++ b/drivers/bluetooth/hci_qca.c @@ -2226,8 +2226,8 @@ static void qca_power_off(struct hci_uart *hu) bool sw_ctrl_state; struct qca_power *power; - /* From this point we go into power off state. But serial port is - * still open, stop queueing the IBS data and flush all the buffered + /* From this point we go into power off state. But serial port may + * still be open, stop queueing the IBS data and flush all the buffered * data in skb's. */ spin_lock_irqsave(&qca->hci_ibs_lock, flags); @@ -2249,8 +2249,14 @@ static void qca_power_off(struct hci_uart *hu) case QCA_WCN3990: case QCA_WCN3991: case QCA_WCN3998: - host_set_baudrate(hu, 2400); - qca_send_power_pulse(hu, false); + /* Both of these write to the serial port which may have + * already been closed by hci_uart_close(), which closes + * the port if HCI_QUIRK_NON_PERSISTENT_SETUP is set. + */ + if (test_bit(HCI_UART_PROTO_READY, &hu->flags)) { + host_set_baudrate(hu, 2400); + qca_send_power_pulse(hu, false); + } break; default: break; diff --git a/drivers/gpu/drm/bridge/analogix/anx7625.c b/drivers/gpu/drm/bridge/analogix/anx7625.c index 54b02242d6db4..0aa03f33811f8 100644 --- a/drivers/gpu/drm/bridge/analogix/anx7625.c +++ b/drivers/gpu/drm/bridge/analogix/anx7625.c @@ -606,6 +606,16 @@ static int anx7625_api_dsi_config(struct anx7625_data *ctx) return ret; } + for (int i = 0; i < 5; i++) { + /* Set MIPI RX termination to 75ohm */ + ret = anx7625_reg_write(ctx, ctx->i2c.rx_p1_client, + MIPI_ANALOG_CTRL_0 + i, 0xf8); + if (ret < 0) { + DRM_DEV_ERROR(dev, "IO error : set lane %d termination fail.\n", i); + return ret; + } + } + /* DSI clock settings */ val = (0 << MIPI_HS_PWD_CLK) | (0 << MIPI_HS_RT_CLK) | @@ -1326,6 +1336,39 @@ static int anx7625_read_hpd_gpio_config_status(struct anx7625_data *ctx) return anx7625_reg_read(ctx, ctx->i2c.rx_p0_client, GPIO_CTRL_2); } +static ssize_t mipi_check_sum_err_hs_show(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct anx7625_data *ctx = dev_get_drvdata(dev); + int ret; + + ret = pm_runtime_resume_and_get(dev); + if (ret < 0) + return ret; + + mutex_lock(&ctx->lock); + ret = anx7625_reg_read(ctx, ctx->i2c.rx_p1_client, 0x19); + mutex_unlock(&ctx->lock); + + pm_runtime_put_autosuspend(dev); + + if (ret < 0) + return ret; + + return sysfs_emit(buf, "%u\n", !!(ret & BIT(5))); +} +static DEVICE_ATTR_RO(mipi_check_sum_err_hs); + +static struct attribute *anx7625_attrs[] = { + &dev_attr_mipi_check_sum_err_hs.attr, + NULL, +}; + +static const struct attribute_group anx7625_attr_group = { + .attrs = anx7625_attrs, +}; + static void anx7625_disable_pd_protocol(struct anx7625_data *ctx) { struct device *dev = ctx->dev; @@ -1796,6 +1839,9 @@ static void anx7625_work_func(struct work_struct *work) struct anx7625_data *ctx = container_of(work, struct anx7625_data, work); + if (!ctx->display) + return; + mutex_lock(&ctx->lock); if (pm_runtime_suspended(ctx->dev)) { @@ -2044,6 +2090,7 @@ static int anx7625_audio_hw_params(struct device *dev, void *data, wl = AUDIO_W_LEN_20_20MAX; break; case 24: + case 32: wl = AUDIO_W_LEN_24_24MAX; break; default: @@ -2083,6 +2130,11 @@ static int anx7625_audio_hw_params(struct device *dev, void *data, ret |= anx7625_write_and(ctx, ctx->i2c.tx_p2_client, AUDIO_CHANNEL_STATUS_6, ~AUDIO_LAYOUT); + + /* Right justified for Qualcomm DSP limitations */ + ret |= anx7625_write_or(ctx, ctx->i2c.tx_p2_client, + AUDIO_CONTROL_REGISTER, 1); + /* FS */ switch (params->sample_rate) { case 32000: @@ -2867,6 +2919,7 @@ static int anx7625_i2c_probe(struct i2c_client *client) } } + platform->display = true; platform->aux.name = "anx7625-aux"; platform->aux.dev = dev; platform->aux.transfer = anx7625_aux_transfer; @@ -2874,13 +2927,16 @@ static int anx7625_i2c_probe(struct i2c_client *client) drm_dp_aux_init(&platform->aux); ret = anx7625_parse_dt(dev, pdata); - if (ret) { + if (ret == -ENODEV) { + /* Not using the display function, but we want USB-C function */ + platform->display = false; + } else if (ret) { if (ret != -EPROBE_DEFER) DRM_DEV_ERROR(dev, "fail to parse DT : %d\n", ret); goto free_wq; } - if (!platform->pdata.is_dpi) { + if (platform->display && !platform->pdata.is_dpi) { ret = anx7625_setup_dsi_device(platform); if (ret < 0) goto free_wq; @@ -2904,12 +2960,17 @@ static int anx7625_i2c_probe(struct i2c_client *client) if (ret) goto free_wq; + ret = devm_device_add_group(dev, &anx7625_attr_group); + if (ret) + goto free_wq; + /* * Populating the aux bus will retrigger deferred probe, so it needs to * be done after calls that might return EPROBE_DEFER, otherwise we can * get an infinite loop. */ - ret = devm_of_dp_aux_populate_bus(&platform->aux, anx7625_link_bridge); + if (platform->display) + ret = devm_of_dp_aux_populate_bus(&platform->aux, anx7625_link_bridge); if (ret) { if (ret != -ENODEV) { DRM_DEV_ERROR(dev, "failed to populate aux bus : %d\n", ret); @@ -2974,7 +3035,8 @@ static void anx7625_i2c_remove(struct i2c_client *client) anx7625_typec_unregister(platform); - drm_bridge_remove(&platform->bridge); + if (platform->display) + drm_bridge_remove(&platform->bridge); if (platform->pdata.intp_irq) destroy_workqueue(platform->workqueue); diff --git a/drivers/gpu/drm/bridge/analogix/anx7625.h b/drivers/gpu/drm/bridge/analogix/anx7625.h index 957d234ec07c8..72f16eacc0e68 100644 --- a/drivers/gpu/drm/bridge/analogix/anx7625.h +++ b/drivers/gpu/drm/bridge/analogix/anx7625.h @@ -293,6 +293,8 @@ #define MIPI_LANE_CTRL_0 0x05 #define MIPI_TIME_HS_PRPR 0x08 +#define MIPI_ANALOG_CTRL_0 0x10 + /* * After MIPI RX protocol layer received video frames, * Protocol layer starts to reconstruct video stream from PHY @@ -509,6 +511,7 @@ struct anx7625_data { struct mipi_dsi_device *dsi; struct drm_dp_aux aux; struct fw_msg send_msg; + bool display; }; #endif /* __ANX7625_H__ */ diff --git a/drivers/tty/serdev/serdev-ttyport.c b/drivers/tty/serdev/serdev-ttyport.c index bab1b143b8a68..b6638f9f40d2d 100644 --- a/drivers/tty/serdev/serdev-ttyport.c +++ b/drivers/tty/serdev/serdev-ttyport.c @@ -137,6 +137,7 @@ static int ttyport_open(struct serdev_controller *ctrl) err_unlock: tty_unlock(tty); tty_release_struct(tty, serport->tty_idx); + serport->tty = NULL; return ret; } @@ -154,6 +155,7 @@ static void ttyport_close(struct serdev_controller *ctrl) tty_unlock(tty); tty_release_struct(tty, serport->tty_idx); + serport->tty = NULL; } static unsigned int ttyport_set_baudrate(struct serdev_controller *ctrl, unsigned int speed) diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c index 28d7929dc5937..b47b9d9400381 100644 --- a/net/bluetooth/hci_core.c +++ b/net/bluetooth/hci_core.c @@ -4074,7 +4074,7 @@ static int hci_send_cmd_sync(struct hci_dev *hdev, struct sk_buff *skb) if (!hdev->sent_cmd) { skb_queue_head(&hdev->cmd_q, skb); queue_work(hdev->workqueue, &hdev->cmd_work); - return -EINVAL; + return -ENOMEM; } if (hci_skb_opcode(skb) != HCI_OP_NOP) { diff --git a/net/bluetooth/hci_sync.c b/net/bluetooth/hci_sync.c index 89075a36b27a7..88f86c241690a 100644 --- a/net/bluetooth/hci_sync.c +++ b/net/bluetooth/hci_sync.c @@ -5283,6 +5283,7 @@ int hci_dev_open_sync(struct hci_dev *hdev) if (hdev->req_skb) { kfree_skb(hdev->req_skb); hdev->req_skb = NULL; + hci_dev_clear_flag(hdev, HCI_CMD_PENDING); } clear_bit(HCI_RUNNING, &hdev->flags); @@ -5467,6 +5468,7 @@ int hci_dev_close_sync(struct hci_dev *hdev) if (hdev->req_skb) { kfree_skb(hdev->req_skb); hdev->req_skb = NULL; + hci_dev_clear_flag(hdev, HCI_CMD_PENDING); } clear_bit(HCI_RUNNING, &hdev->flags); diff --git a/sound/soc/codecs/pm4125.c b/sound/soc/codecs/pm4125.c index 1f0a3f5389f1b..6de37a358e02e 100644 --- a/sound/soc/codecs/pm4125.c +++ b/sound/soc/codecs/pm4125.c @@ -842,13 +842,32 @@ static int pm4125_codec_enable_micbias_pullup(struct snd_soc_dapm_widget *w, static int pm4125_connect_port(struct pm4125_sdw_priv *sdw_priv, u8 port_idx, u8 ch_id, bool enable) { - struct sdw_port_config *port_config = &sdw_priv->port_config[port_idx - 1]; - const struct wcd_sdw_ch_info *ch_info = &sdw_priv->ch_info[ch_id]; + struct sdw_port_config *port_config; + const struct wcd_sdw_ch_info *ch_info; struct sdw_slave *sdev = sdw_priv->sdev; - u8 port_num = ch_info->port_num; - u8 ch_mask = ch_info->ch_mask; + u8 port_num, ch_mask; u8 mstr_port_num, mstr_ch_mask; + if (!port_idx) /* Invalid port index */ + return -EINVAL; + + if (sdw_priv->is_tx) { + if (ch_id > PM4125_ADC2) + return -EINVAL; + } else { + if (ch_id > PM4125_COMP_R) + return -EINVAL; + } + + ch_info = &sdw_priv->ch_info[ch_id]; + port_num = ch_info->port_num; + ch_mask = ch_info->ch_mask; + + if (!port_num || port_num > PM4125_MAX_SWR_PORTS) + return -EINVAL; + + port_config = &sdw_priv->port_config[port_idx - 1]; + port_config->num = port_num; mstr_port_num = sdev->m_port_map[port_num]; @@ -888,10 +907,18 @@ static int pm4125_set_compander(struct snd_kcontrol *kcontrol, struct snd_ctl_el struct soc_mixer_control *mc; int portidx; bool hphr; + int ch_idx; mc = (struct soc_mixer_control *)(kcontrol->private_value); + ch_idx = mc->reg; hphr = mc->shift; + if (!sdw_priv) + return -EINVAL; + + if (ch_idx < 0 || ch_idx > PM4125_COMP_R) + return -EINVAL; + if (hphr) { if (value == pm4125->comp2_enable) return 0; @@ -904,9 +931,11 @@ static int pm4125_set_compander(struct snd_kcontrol *kcontrol, struct snd_ctl_el pm4125->comp1_enable = value; } - portidx = sdw_priv->ch_info[mc->reg].port_num; + portidx = sdw_priv->ch_info[ch_idx].port_num; + if (!portidx) + return 0; - pm4125_connect_port(sdw_priv, portidx, mc->reg, value ? true : false); + pm4125_connect_port(sdw_priv, portidx, ch_idx, value ? true : false); return 1; } @@ -921,8 +950,24 @@ static int pm4125_get_swr_port(struct snd_kcontrol *kcontrol, struct snd_ctl_ele int ch_idx = mixer->reg; int portidx; + if (dai_id < 0 || dai_id >= NUM_CODEC_DAIS) + return -EINVAL; + sdw_priv = pm4125->sdw_priv[dai_id]; + if (!sdw_priv) + return -EINVAL; + + if (sdw_priv->is_tx) { + if (ch_idx < 0 || ch_idx > PM4125_ADC2) + return -EINVAL; + } else { + if (ch_idx < 0 || ch_idx > PM4125_HPH_R) + return -EINVAL; + } + portidx = sdw_priv->ch_info[ch_idx].port_num; + if (!portidx) /* Invalid port index */ + return 0; ucontrol->value.integer.value[0] = sdw_priv->port_enable[portidx]; @@ -940,9 +985,24 @@ static int pm4125_set_swr_port(struct snd_kcontrol *kcontrol, struct snd_ctl_ele int portidx; bool enable; + if (dai_id < 0 || dai_id >= NUM_CODEC_DAIS) + return -EINVAL; + sdw_priv = pm4125->sdw_priv[dai_id]; + if (!sdw_priv) + return -EINVAL; + + if (sdw_priv->is_tx) { + if (ch_idx < 0 || ch_idx > PM4125_ADC2) + return -EINVAL; + } else { + if (ch_idx < 0 || ch_idx > PM4125_HPH_R) + return -EINVAL; + } portidx = sdw_priv->ch_info[ch_idx].port_num; + if (!portidx) /* Invalid port index */ + return 0; enable = ucontrol->value.integer.value[0]; @@ -1411,8 +1471,16 @@ static int pm4125_codec_free(struct snd_pcm_substream *substream, struct snd_soc { struct pm4125_priv *pm4125 = dev_get_drvdata(dai->dev); struct pm4125_sdw_priv *sdw_priv = pm4125->sdw_priv[dai->id]; + int ret; + + /* hw_free() can be invoked again on a DAPM-driven route change; avoid a stale stream UAF */ + if (!sdw_priv->sruntime) + return 0; - return sdw_stream_remove_slave(sdw_priv->sdev, sdw_priv->sruntime); + ret = sdw_stream_remove_slave(sdw_priv->sdev, sdw_priv->sruntime); + sdw_priv->sruntime = NULL; + + return ret; } static int pm4125_codec_set_sdw_stream(struct snd_soc_dai *dai, void *stream, int direction) diff --git a/sound/soc/qcom/common.c b/sound/soc/qcom/common.c index cf1f3a767ceef..4f0c421359a47 100644 --- a/sound/soc/qcom/common.c +++ b/sound/soc/qcom/common.c @@ -23,16 +23,110 @@ static const struct snd_soc_dapm_widget qcom_jack_snd_widgets[] = { SND_SOC_DAPM_SPK("DP7 Jack", NULL), }; -int qcom_snd_parse_of(struct snd_soc_card *card) +static int qcom_snd_setup_dai_links(struct snd_soc_card *card, struct snd_soc_dai_link *link, + struct device_node *np) { - struct device_node *np; struct device_node *codec = NULL; struct device_node *platform = NULL; struct device_node *cpu = NULL; struct device *dev = card->dev; - struct snd_soc_dai_link *link; struct of_phandle_args args; struct snd_soc_dai_link_component *dlc; + int ret; + + dlc = devm_kcalloc(dev, 2, sizeof(*dlc), GFP_KERNEL); + if (!dlc) { + ret = -ENOMEM; + goto err_put_np; + } + link->cpus = &dlc[0]; + link->platforms = &dlc[1]; + + link->num_cpus = 1; + link->num_platforms = 1; + + ret = of_property_read_string(np, "link-name", &link->name); + if (ret) { + dev_err(card->dev, "error getting codec dai_link name\n"); + goto err_put_np; + } + + cpu = of_get_child_by_name(np, "cpu"); + platform = of_get_child_by_name(np, "platform"); + codec = of_get_child_by_name(np, "codec"); + + if (!cpu) { + dev_err(dev, "%s: Can't find cpu DT node\n", link->name); + ret = -EINVAL; + goto err; + } + + ret = snd_soc_of_get_dlc(cpu, &args, link->cpus, 0); + if (ret) { + dev_err_probe(card->dev, ret, + "%s: error getting cpu dai name\n", link->name); + goto err; + } + + link->id = args.args[0]; + + if (platform) { + link->platforms->of_node = of_parse_phandle(platform, + "sound-dai", + 0); + if (!link->platforms->of_node) { + dev_err(card->dev, "%s: platform dai not found\n", link->name); + ret = -EINVAL; + goto err; + } + } else { + link->platforms->of_node = link->cpus->of_node; + } + + if (codec) { + ret = snd_soc_of_get_dai_link_codecs(dev, codec, link); + if (ret < 0) { + dev_err_probe(card->dev, ret, + "%s: codec dai not found\n", link->name); + goto err; + } + + if (platform) { + /* DPCM backend */ + link->no_pcm = 1; + link->ignore_pmdown_time = 1; + } + } else { + /* DPCM frontend */ + link->codecs = &snd_soc_dummy_dlc; + link->num_codecs = 1; + link->dynamic = 1; + } + + if (platform || !codec) { + /* DPCM */ + link->ignore_suspend = 1; + link->nonatomic = 1; + } + link->stream_name = link->name; + + ret = 0; +err: + of_node_put(cpu); + of_node_put(codec); + of_node_put(platform); +err_put_np: + of_node_put(np); + + return ret; +} + +int qcom_snd_parse_of(struct snd_soc_card *card) +{ + struct device_node *np; + struct device_node *codec = NULL; + struct device *dev = card->dev; + struct snd_soc_dai_link *link; int ret, num_links; ret = snd_soc_of_parse_card_name(card, "model"); @@ -82,95 +176,33 @@ int qcom_snd_parse_of(struct snd_soc_card *card) card->num_links = num_links; link = card->dai_link; + /* setup pcm dais first */ for_each_available_child_of_node(dev->of_node, np) { - dlc = devm_kcalloc(dev, 2, sizeof(*dlc), GFP_KERNEL); - if (!dlc) { - ret = -ENOMEM; - goto err_put_np; - } - - link->cpus = &dlc[0]; - link->platforms = &dlc[1]; - - link->num_cpus = 1; - link->num_platforms = 1; - - ret = of_property_read_string(np, "link-name", &link->name); - if (ret) { - dev_err(card->dev, "error getting codec dai_link name\n"); - goto err_put_np; - } - - cpu = of_get_child_by_name(np, "cpu"); - platform = of_get_child_by_name(np, "platform"); codec = of_get_child_by_name(np, "codec"); - if (!cpu) { - dev_err(dev, "%s: Can't find cpu DT node\n", link->name); - ret = -EINVAL; - goto err; - } - - ret = snd_soc_of_get_dlc(cpu, &args, link->cpus, 0); - if (ret) { - dev_err_probe(card->dev, ret, - "%s: error getting cpu dai name\n", link->name); - goto err; - } - - link->id = args.args[0]; - - if (link->id >= LPASS_MAX_PORT) { - dev_err(dev, "%s: Invalid cpu dai id %d\n", link->name, link->id); - ret = -EINVAL; - goto err; + if (codec) { + of_node_put(codec); + continue; } - if (platform) { - link->platforms->of_node = of_parse_phandle(platform, - "sound-dai", - 0); - if (!link->platforms->of_node) { - dev_err(card->dev, "%s: platform dai not found\n", link->name); - ret = -EINVAL; - goto err; - } - } else { - link->platforms->of_node = link->cpus->of_node; - } + ret = qcom_snd_setup_dai_links(card, link, np); + if (ret) + return ret; - if (codec) { - ret = snd_soc_of_get_dai_link_codecs(dev, codec, link); - if (ret < 0) { - dev_err_probe(card->dev, ret, - "%s: codec dai not found\n", link->name); - goto err; - } + link++; + } - if (platform) { - /* DPCM backend */ - link->no_pcm = 1; - link->ignore_pmdown_time = 1; - } - } else { - /* DPCM frontend */ - link->codecs = &snd_soc_dummy_dlc; - link->num_codecs = 1; - link->dynamic = 1; - } + /* setup backend dais */ + for_each_available_child_of_node(dev->of_node, np) { + codec = of_get_child_by_name(np, "codec"); + if (!codec) + continue; - if (platform || !codec) { - /* DPCM */ - link->ignore_suspend = 1; - link->nonatomic = 1; - } + ret = qcom_snd_setup_dai_links(card, link, np); + if (ret) + return ret; - link->stream_name = link->name; link++; - - of_node_put(cpu); - of_node_put(codec); - of_node_put(platform); } if (!card->dapm_widgets) { @@ -178,13 +210,6 @@ int qcom_snd_parse_of(struct snd_soc_card *card) card->num_dapm_widgets = ARRAY_SIZE(qcom_jack_snd_widgets); } - return 0; -err: - of_node_put(cpu); - of_node_put(codec); - of_node_put(platform); -err_put_np: - of_node_put(np); return ret; } EXPORT_SYMBOL_GPL(qcom_snd_parse_of); diff --git a/sound/soc/qcom/qdsp6/q6asm-dai.c b/sound/soc/qcom/qdsp6/q6asm-dai.c index 4f09fdd409058..d6f2e80375da6 100644 --- a/sound/soc/qcom/qdsp6/q6asm-dai.c +++ b/sound/soc/qcom/qdsp6/q6asm-dai.c @@ -222,8 +222,12 @@ static int q6asm_dai_prepare(struct snd_soc_component *component, } prtd->pcm_count = snd_pcm_lib_period_bytes(substream); - /* rate and channels are sent to audio driver */ - if (prtd->state == Q6ASM_STREAM_RUNNING) { + /* + * Re-prepare can be called after STOP without closing the previous + * stream session. Ensure any non-idle session is torn down before + * issuing a new OPEN command. + */ + if (prtd->state != Q6ASM_STREAM_IDLE) { /* clear the previous setup if any */ ret = q6asm_cmd(prtd->audio_client, prtd->stream_id, CMD_CLOSE); if (ret < 0) { @@ -240,7 +244,7 @@ static int q6asm_dai_prepare(struct snd_soc_component *component, q6routing_stream_close(soc_prtd->dai_link->id, substream->stream); - prtd->state = Q6ASM_STREAM_STOPPED; + prtd->state = Q6ASM_STREAM_IDLE; } ret = q6asm_map_memory_regions(substream->stream, prtd->audio_client, @@ -265,7 +269,7 @@ static int q6asm_dai_prepare(struct snd_soc_component *component, } if (ret < 0) { - dev_err(dev, "%s: q6asm_open_write failed\n", __func__); + dev_err(dev, "%s: q6asm_open failed\n", __func__); goto open_err; } diff --git a/sound/soc/qcom/qdsp6/q6dsp-lpass-ports.c b/sound/soc/qcom/qdsp6/q6dsp-lpass-ports.c index e5cd82f77b552..507009dea60a8 100644 --- a/sound/soc/qcom/qdsp6/q6dsp-lpass-ports.c +++ b/sound/soc/qcom/qdsp6/q6dsp-lpass-ports.c @@ -389,7 +389,7 @@ static struct snd_soc_dai_driver q6dsp_audio_fe_dais[] = { .rates = SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000, .formats = SNDRV_PCM_FMTBIT_S16_LE | - SNDRV_PCM_FMTBIT_S24_LE, + SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S32_LE, .channels_min = 1, .channels_max = 8, .rate_min = 8000, @@ -416,7 +416,8 @@ static struct snd_soc_dai_driver q6dsp_audio_fe_dais[] = { .stream_name = "Secondary MI2S Playback", .rates = SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000, - .formats = SNDRV_PCM_FMTBIT_S16_LE, + .formats = SNDRV_PCM_FMTBIT_S16_LE | + SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S32_LE, .channels_min = 1, .channels_max = 8, .rate_min = 8000, @@ -443,7 +444,8 @@ static struct snd_soc_dai_driver q6dsp_audio_fe_dais[] = { .stream_name = "Tertiary MI2S Playback", .rates = SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000, - .formats = SNDRV_PCM_FMTBIT_S16_LE, + .formats = SNDRV_PCM_FMTBIT_S16_LE | + SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S32_LE, .channels_min = 1, .channels_max = 8, .rate_min = 8000, @@ -470,7 +472,8 @@ static struct snd_soc_dai_driver q6dsp_audio_fe_dais[] = { .stream_name = "Quaternary MI2S Playback", .rates = SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000, - .formats = SNDRV_PCM_FMTBIT_S16_LE, + .formats = SNDRV_PCM_FMTBIT_S16_LE | + SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S32_LE, .channels_min = 1, .channels_max = 8, .rate_min = 8000, @@ -498,7 +501,8 @@ static struct snd_soc_dai_driver q6dsp_audio_fe_dais[] = { .rates = SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000 | SNDRV_PCM_RATE_96000 | SNDRV_PCM_RATE_192000, - .formats = SNDRV_PCM_FMTBIT_S16_LE, + .formats = SNDRV_PCM_FMTBIT_S16_LE | + SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S32_LE, .channels_min = 1, .channels_max = 8, .rate_min = 8000, diff --git a/sound/soc/qcom/qdsp6/q6routing.c b/sound/soc/qcom/qdsp6/q6routing.c index 7386226046fae..bbaa47303456f 100644 --- a/sound/soc/qcom/qdsp6/q6routing.c +++ b/sound/soc/qcom/qdsp6/q6routing.c @@ -1083,6 +1083,9 @@ static int routing_hw_params(struct snd_soc_component *component, case SNDRV_PCM_FORMAT_S24_LE: session->bits_per_sample = 24; break; + case SNDRV_PCM_FORMAT_S32_LE: + session->bits_per_sample = 32; + break; default: break; } diff --git a/sound/soc/qcom/sm8250.c b/sound/soc/qcom/sm8250.c index f193d0ba63d00..8f6e1b03ad003 100644 --- a/sound/soc/qcom/sm8250.c +++ b/sound/soc/qcom/sm8250.c @@ -16,7 +16,7 @@ #include "usb_offload_utils.h" #include "sdw.h" -#define MI2S_BCLK_RATE 1536000 +#define MI2S_BCLK_RATE 3072000 struct sm8250_snd_data { bool stream_prepared[AFE_PORT_MAX]; @@ -58,6 +58,7 @@ static void sm8250_snd_exit(struct snd_soc_pcm_runtime *rtd) static int sm8250_be_hw_params_fixup(struct snd_soc_pcm_runtime *rtd, struct snd_pcm_hw_params *params) { + struct snd_soc_dai *cpu_dai = snd_soc_rtd_to_cpu(rtd, 0); struct snd_interval *rate = hw_param_interval(params, SNDRV_PCM_HW_PARAM_RATE); struct snd_interval *channels = hw_param_interval(params, @@ -68,6 +69,26 @@ static int sm8250_be_hw_params_fixup(struct snd_soc_pcm_runtime *rtd, channels->min = channels->max = 2; snd_mask_set_format(fmt, SNDRV_PCM_FORMAT_S16_LE); + switch (cpu_dai->id) { + case TX_CODEC_DMA_TX_0: + case TX_CODEC_DMA_TX_1: + case TX_CODEC_DMA_TX_2: + case TX_CODEC_DMA_TX_3: + channels->min = 1; + channels->min = channels->max = 1; + break; + case PRIMARY_MI2S_RX: + case SECONDARY_MI2S_RX: + case TERTIARY_MI2S_RX: + /* clean any param mask before setting new param */ + snd_mask_reset_range(hw_param_mask(params, SNDRV_PCM_HW_PARAM_FORMAT), + 0, (__force unsigned int)SNDRV_PCM_FORMAT_LAST); + params_set_format(params, SNDRV_PCM_FORMAT_S32_LE); + break; + default: + break; + } + return 0; }