diff options
Diffstat (limited to 'drivers/soundwire/qcom.c')
-rw-r--r-- | drivers/soundwire/qcom.c | 80 |
1 files changed, 58 insertions, 22 deletions
diff --git a/drivers/soundwire/qcom.c b/drivers/soundwire/qcom.c index 3c4d6debab1f..295a46dc2be7 100644 --- a/drivers/soundwire/qcom.c +++ b/drivers/soundwire/qcom.c @@ -156,6 +156,7 @@ struct qcom_swrm_port_config { u8 word_length; u8 blk_group_count; u8 lane_control; + u8 ch_mask; }; /* @@ -197,8 +198,7 @@ struct qcom_swrm_ctrl { int num_dout_ports; int cols_index; int rows_index; - unsigned long dout_port_mask; - unsigned long din_port_mask; + unsigned long port_mask; u32 intr_mask; u8 rcmd_id; u8 wcmd_id; @@ -905,6 +905,18 @@ static int qcom_swrm_init(struct qcom_swrm_ctrl *ctrl) return 0; } +static int qcom_swrm_read_prop(struct sdw_bus *bus) +{ + struct qcom_swrm_ctrl *ctrl = to_qcom_sdw(bus); + + if (ctrl->version >= SWRM_VERSION_2_0_0) { + bus->multi_link = true; + bus->hw_sync_min_links = 3; + } + + return 0; +} + static enum sdw_command_response qcom_swrm_xfer_msg(struct sdw_bus *bus, struct sdw_msg *msg) { @@ -1037,9 +1049,13 @@ static int qcom_swrm_port_enable(struct sdw_bus *bus, { u32 reg = SWRM_DP_PORT_CTRL_BANK(enable_ch->port_num, bank); struct qcom_swrm_ctrl *ctrl = to_qcom_sdw(bus); + struct qcom_swrm_port_config *pcfg; u32 val; + pcfg = &ctrl->pconfig[enable_ch->port_num]; ctrl->reg_read(ctrl, reg, &val); + if (pcfg->ch_mask != SWR_INVALID_PARAM && pcfg->ch_mask != 0) + enable_ch->ch_mask = pcfg->ch_mask; if (enable_ch->enable) val |= (enable_ch->ch_mask << SWRM_DP_PORT_CTRL_EN_CHAN_SHFT); @@ -1056,11 +1072,12 @@ static const struct sdw_master_port_ops qcom_swrm_port_ops = { }; static const struct sdw_master_ops qcom_swrm_ops = { + .read_prop = qcom_swrm_read_prop, .xfer_msg = qcom_swrm_xfer_msg, .pre_bank_switch = qcom_swrm_pre_bank_switch, }; -static int qcom_swrm_compute_params(struct sdw_bus *bus) +static int qcom_swrm_compute_params(struct sdw_bus *bus, struct sdw_stream_runtime *stream) { struct qcom_swrm_ctrl *ctrl = to_qcom_sdw(bus); struct sdw_master_runtime *m_rt; @@ -1133,11 +1150,7 @@ static void qcom_swrm_stream_free_ports(struct qcom_swrm_ctrl *ctrl, mutex_lock(&ctrl->port_lock); list_for_each_entry(m_rt, &stream->master_list, stream_node) { - if (m_rt->direction == SDW_DATA_DIR_RX) - port_mask = &ctrl->dout_port_mask; - else - port_mask = &ctrl->din_port_mask; - + port_mask = &ctrl->port_mask; list_for_each_entry(p_rt, &m_rt->port_list, port_node) clear_bit(p_rt->num, port_mask); } @@ -1165,7 +1178,7 @@ static int qcom_swrm_stream_alloc_ports(struct qcom_swrm_ctrl *ctrl, else sconfig.direction = SDW_DATA_DIR_RX; - /* hw parameters wil be ignored as we only support PDM */ + /* hw parameters will be ignored as we only support PDM */ sconfig.ch_count = 1; sconfig.frame_rate = params_rate(params); sconfig.type = stream->type; @@ -1173,13 +1186,18 @@ static int qcom_swrm_stream_alloc_ports(struct qcom_swrm_ctrl *ctrl, mutex_lock(&ctrl->port_lock); list_for_each_entry(m_rt, &stream->master_list, stream_node) { - if (m_rt->direction == SDW_DATA_DIR_RX) { - maxport = ctrl->num_dout_ports; - port_mask = &ctrl->dout_port_mask; - } else { - maxport = ctrl->num_din_ports; - port_mask = &ctrl->din_port_mask; - } + /* + * For streams with multiple masters: + * Allocate ports only for devices connected to this master. + * Such devices will have ports allocated by their own master + * and its qcom_swrm_stream_alloc_ports() call. + */ + if (ctrl->bus.id != m_rt->bus->id) + continue; + + port_mask = &ctrl->port_mask; + maxport = ctrl->num_dout_ports + ctrl->num_din_ports; + list_for_each_entry(s_rt, &m_rt->slave_rt_list, m_rt_node) { slave = s_rt->slave; @@ -1257,6 +1275,26 @@ static void *qcom_swrm_get_sdw_stream(struct snd_soc_dai *dai, int direction) return ctrl->sruntime[dai->id]; } +static int qcom_swrm_set_channel_map(struct snd_soc_dai *dai, + unsigned int tx_num, const unsigned int *tx_slot, + unsigned int rx_num, const unsigned int *rx_slot) +{ + struct qcom_swrm_ctrl *ctrl = dev_get_drvdata(dai->dev); + int i; + + if (tx_slot) { + for (i = 0; i < tx_num; i++) + ctrl->pconfig[i].ch_mask = tx_slot[i]; + } + + if (rx_slot) { + for (i = 0; i < rx_num; i++) + ctrl->pconfig[i].ch_mask = rx_slot[i]; + } + + return 0; +} + static int qcom_swrm_startup(struct snd_pcm_substream *substream, struct snd_soc_dai *dai) { @@ -1293,6 +1331,7 @@ static const struct snd_soc_dai_ops qcom_swrm_pdm_dai_ops = { .shutdown = qcom_swrm_shutdown, .set_stream = qcom_swrm_set_sdw_stream, .get_stream = qcom_swrm_get_sdw_stream, + .set_channel_map = qcom_swrm_set_channel_map, }; static const struct snd_soc_component_driver qcom_swrm_dai_component = { @@ -1379,8 +1418,7 @@ static int qcom_swrm_get_port_config(struct qcom_swrm_ctrl *ctrl) return -EINVAL; /* Valid port numbers are from 1-14, so mask out port 0 explicitly */ - set_bit(0, &ctrl->dout_port_mask); - set_bit(0, &ctrl->din_port_mask); + set_bit(0, &ctrl->port_mask); ret = of_property_read_u8_array(np, "qcom,ports-offset1", off1, nports); @@ -1636,14 +1674,12 @@ err_init: return ret; } -static int qcom_swrm_remove(struct platform_device *pdev) +static void qcom_swrm_remove(struct platform_device *pdev) { struct qcom_swrm_ctrl *ctrl = dev_get_drvdata(&pdev->dev); sdw_bus_master_delete(&ctrl->bus); clk_disable_unprepare(ctrl->hclk); - - return 0; } static int __maybe_unused swrm_runtime_resume(struct device *dev) @@ -1769,7 +1805,7 @@ MODULE_DEVICE_TABLE(of, qcom_swrm_of_match); static struct platform_driver qcom_swrm_driver = { .probe = &qcom_swrm_probe, - .remove = &qcom_swrm_remove, + .remove = qcom_swrm_remove, .driver = { .name = "qcom-soundwire", .of_match_table = qcom_swrm_of_match, |