189e59053SSanyog Kale // SPDX-License-Identifier: (GPL-2.0 OR BSD-3-Clause) 289e59053SSanyog Kale // Copyright(c) 2015-18 Intel Corporation. 389e59053SSanyog Kale 489e59053SSanyog Kale /* 589e59053SSanyog Kale * stream.c - SoundWire Bus stream operations. 689e59053SSanyog Kale */ 789e59053SSanyog Kale 889e59053SSanyog Kale #include <linux/delay.h> 989e59053SSanyog Kale #include <linux/device.h> 1089e59053SSanyog Kale #include <linux/init.h> 1189e59053SSanyog Kale #include <linux/module.h> 1289e59053SSanyog Kale #include <linux/mod_devicetable.h> 1389e59053SSanyog Kale #include <linux/slab.h> 14f8101c74SSanyog Kale #include <linux/soundwire/sdw_registers.h> 1589e59053SSanyog Kale #include <linux/soundwire/sdw.h> 1689e59053SSanyog Kale #include "bus.h" 1789e59053SSanyog Kale 1899b8a5d6SSanyog Kale /* 1999b8a5d6SSanyog Kale * Array of supported rows and columns as per MIPI SoundWire Specification 1.1 2099b8a5d6SSanyog Kale * 2199b8a5d6SSanyog Kale * The rows are arranged as per the array index value programmed 2299b8a5d6SSanyog Kale * in register. The index 15 has dummy value 0 in order to fill hole. 2399b8a5d6SSanyog Kale */ 2499b8a5d6SSanyog Kale int rows[SDW_FRAME_ROWS] = {48, 50, 60, 64, 75, 80, 125, 147, 2599b8a5d6SSanyog Kale 96, 100, 120, 128, 150, 160, 250, 0, 2699b8a5d6SSanyog Kale 192, 200, 240, 256, 72, 144, 90, 180}; 2799b8a5d6SSanyog Kale 2899b8a5d6SSanyog Kale int cols[SDW_FRAME_COLS] = {2, 4, 6, 8, 10, 12, 14, 16}; 2999b8a5d6SSanyog Kale 3099b8a5d6SSanyog Kale static int sdw_find_col_index(int col) 3199b8a5d6SSanyog Kale { 3299b8a5d6SSanyog Kale int i; 3399b8a5d6SSanyog Kale 3499b8a5d6SSanyog Kale for (i = 0; i < SDW_FRAME_COLS; i++) { 3599b8a5d6SSanyog Kale if (cols[i] == col) 3699b8a5d6SSanyog Kale return i; 3799b8a5d6SSanyog Kale } 3899b8a5d6SSanyog Kale 3999b8a5d6SSanyog Kale pr_warn("Requested column not found, selecting lowest column no: 2\n"); 4099b8a5d6SSanyog Kale return 0; 4199b8a5d6SSanyog Kale } 4299b8a5d6SSanyog Kale 4399b8a5d6SSanyog Kale static int sdw_find_row_index(int row) 4499b8a5d6SSanyog Kale { 4599b8a5d6SSanyog Kale int i; 4699b8a5d6SSanyog Kale 4799b8a5d6SSanyog Kale for (i = 0; i < SDW_FRAME_ROWS; i++) { 4899b8a5d6SSanyog Kale if (rows[i] == row) 4999b8a5d6SSanyog Kale return i; 5099b8a5d6SSanyog Kale } 5199b8a5d6SSanyog Kale 5299b8a5d6SSanyog Kale pr_warn("Requested row not found, selecting lowest row no: 48\n"); 5399b8a5d6SSanyog Kale return 0; 5499b8a5d6SSanyog Kale } 55f8101c74SSanyog Kale static int _sdw_program_slave_port_params(struct sdw_bus *bus, 56f8101c74SSanyog Kale struct sdw_slave *slave, 57f8101c74SSanyog Kale struct sdw_transport_params *t_params, 58f8101c74SSanyog Kale enum sdw_dpn_type type) 59f8101c74SSanyog Kale { 60f8101c74SSanyog Kale u32 addr1, addr2, addr3, addr4; 61f8101c74SSanyog Kale int ret; 62f8101c74SSanyog Kale u16 wbuf; 63f8101c74SSanyog Kale 64f8101c74SSanyog Kale if (bus->params.next_bank) { 65f8101c74SSanyog Kale addr1 = SDW_DPN_OFFSETCTRL2_B1(t_params->port_num); 66f8101c74SSanyog Kale addr2 = SDW_DPN_BLOCKCTRL3_B1(t_params->port_num); 67f8101c74SSanyog Kale addr3 = SDW_DPN_SAMPLECTRL2_B1(t_params->port_num); 68f8101c74SSanyog Kale addr4 = SDW_DPN_HCTRL_B1(t_params->port_num); 69f8101c74SSanyog Kale } else { 70f8101c74SSanyog Kale addr1 = SDW_DPN_OFFSETCTRL2_B0(t_params->port_num); 71f8101c74SSanyog Kale addr2 = SDW_DPN_BLOCKCTRL3_B0(t_params->port_num); 72f8101c74SSanyog Kale addr3 = SDW_DPN_SAMPLECTRL2_B0(t_params->port_num); 73f8101c74SSanyog Kale addr4 = SDW_DPN_HCTRL_B0(t_params->port_num); 74f8101c74SSanyog Kale } 75f8101c74SSanyog Kale 76f8101c74SSanyog Kale /* Program DPN_OffsetCtrl2 registers */ 77f8101c74SSanyog Kale ret = sdw_write(slave, addr1, t_params->offset2); 78f8101c74SSanyog Kale if (ret < 0) { 79f8101c74SSanyog Kale dev_err(bus->dev, "DPN_OffsetCtrl2 register write failed"); 80f8101c74SSanyog Kale return ret; 81f8101c74SSanyog Kale } 82f8101c74SSanyog Kale 83f8101c74SSanyog Kale /* Program DPN_BlockCtrl3 register */ 84f8101c74SSanyog Kale ret = sdw_write(slave, addr2, t_params->blk_pkg_mode); 85f8101c74SSanyog Kale if (ret < 0) { 86f8101c74SSanyog Kale dev_err(bus->dev, "DPN_BlockCtrl3 register write failed"); 87f8101c74SSanyog Kale return ret; 88f8101c74SSanyog Kale } 89f8101c74SSanyog Kale 90f8101c74SSanyog Kale /* 91f8101c74SSanyog Kale * Data ports are FULL, SIMPLE and REDUCED. This function handles 92f8101c74SSanyog Kale * FULL and REDUCED only and and beyond this point only FULL is 93f8101c74SSanyog Kale * handled, so bail out if we are not FULL data port type 94f8101c74SSanyog Kale */ 95f8101c74SSanyog Kale if (type != SDW_DPN_FULL) 96f8101c74SSanyog Kale return ret; 97f8101c74SSanyog Kale 98f8101c74SSanyog Kale /* Program DPN_SampleCtrl2 register */ 99f8101c74SSanyog Kale wbuf = (t_params->sample_interval - 1); 100f8101c74SSanyog Kale wbuf &= SDW_DPN_SAMPLECTRL_HIGH; 101f8101c74SSanyog Kale wbuf >>= SDW_REG_SHIFT(SDW_DPN_SAMPLECTRL_HIGH); 102f8101c74SSanyog Kale 103f8101c74SSanyog Kale ret = sdw_write(slave, addr3, wbuf); 104f8101c74SSanyog Kale if (ret < 0) { 105f8101c74SSanyog Kale dev_err(bus->dev, "DPN_SampleCtrl2 register write failed"); 106f8101c74SSanyog Kale return ret; 107f8101c74SSanyog Kale } 108f8101c74SSanyog Kale 109f8101c74SSanyog Kale /* Program DPN_HCtrl register */ 110f8101c74SSanyog Kale wbuf = t_params->hstart; 111f8101c74SSanyog Kale wbuf <<= SDW_REG_SHIFT(SDW_DPN_HCTRL_HSTART); 112f8101c74SSanyog Kale wbuf |= t_params->hstop; 113f8101c74SSanyog Kale 114f8101c74SSanyog Kale ret = sdw_write(slave, addr4, wbuf); 115f8101c74SSanyog Kale if (ret < 0) 116f8101c74SSanyog Kale dev_err(bus->dev, "DPN_HCtrl register write failed"); 117f8101c74SSanyog Kale 118f8101c74SSanyog Kale return ret; 119f8101c74SSanyog Kale } 120f8101c74SSanyog Kale 121f8101c74SSanyog Kale static int sdw_program_slave_port_params(struct sdw_bus *bus, 122f8101c74SSanyog Kale struct sdw_slave_runtime *s_rt, 123f8101c74SSanyog Kale struct sdw_port_runtime *p_rt) 124f8101c74SSanyog Kale { 125f8101c74SSanyog Kale struct sdw_transport_params *t_params = &p_rt->transport_params; 126f8101c74SSanyog Kale struct sdw_port_params *p_params = &p_rt->port_params; 127f8101c74SSanyog Kale struct sdw_slave_prop *slave_prop = &s_rt->slave->prop; 128f8101c74SSanyog Kale u32 addr1, addr2, addr3, addr4, addr5, addr6; 129f8101c74SSanyog Kale struct sdw_dpn_prop *dpn_prop; 130f8101c74SSanyog Kale int ret; 131f8101c74SSanyog Kale u8 wbuf; 132f8101c74SSanyog Kale 133f8101c74SSanyog Kale dpn_prop = sdw_get_slave_dpn_prop(s_rt->slave, 134f8101c74SSanyog Kale s_rt->direction, 135f8101c74SSanyog Kale t_params->port_num); 136f8101c74SSanyog Kale if (!dpn_prop) 137f8101c74SSanyog Kale return -EINVAL; 138f8101c74SSanyog Kale 139f8101c74SSanyog Kale addr1 = SDW_DPN_PORTCTRL(t_params->port_num); 140f8101c74SSanyog Kale addr2 = SDW_DPN_BLOCKCTRL1(t_params->port_num); 141f8101c74SSanyog Kale 142f8101c74SSanyog Kale if (bus->params.next_bank) { 143f8101c74SSanyog Kale addr3 = SDW_DPN_SAMPLECTRL1_B1(t_params->port_num); 144f8101c74SSanyog Kale addr4 = SDW_DPN_OFFSETCTRL1_B1(t_params->port_num); 145f8101c74SSanyog Kale addr5 = SDW_DPN_BLOCKCTRL2_B1(t_params->port_num); 146f8101c74SSanyog Kale addr6 = SDW_DPN_LANECTRL_B1(t_params->port_num); 147f8101c74SSanyog Kale 148f8101c74SSanyog Kale } else { 149f8101c74SSanyog Kale addr3 = SDW_DPN_SAMPLECTRL1_B0(t_params->port_num); 150f8101c74SSanyog Kale addr4 = SDW_DPN_OFFSETCTRL1_B0(t_params->port_num); 151f8101c74SSanyog Kale addr5 = SDW_DPN_BLOCKCTRL2_B0(t_params->port_num); 152f8101c74SSanyog Kale addr6 = SDW_DPN_LANECTRL_B0(t_params->port_num); 153f8101c74SSanyog Kale } 154f8101c74SSanyog Kale 155f8101c74SSanyog Kale /* Program DPN_PortCtrl register */ 156f8101c74SSanyog Kale wbuf = p_params->data_mode << SDW_REG_SHIFT(SDW_DPN_PORTCTRL_DATAMODE); 157f8101c74SSanyog Kale wbuf |= p_params->flow_mode; 158f8101c74SSanyog Kale 159f8101c74SSanyog Kale ret = sdw_update(s_rt->slave, addr1, 0xF, wbuf); 160f8101c74SSanyog Kale if (ret < 0) { 161f8101c74SSanyog Kale dev_err(&s_rt->slave->dev, 162f8101c74SSanyog Kale "DPN_PortCtrl register write failed for port %d", 163f8101c74SSanyog Kale t_params->port_num); 164f8101c74SSanyog Kale return ret; 165f8101c74SSanyog Kale } 166f8101c74SSanyog Kale 167f8101c74SSanyog Kale /* Program DPN_BlockCtrl1 register */ 168f8101c74SSanyog Kale ret = sdw_write(s_rt->slave, addr2, (p_params->bps - 1)); 169f8101c74SSanyog Kale if (ret < 0) { 170f8101c74SSanyog Kale dev_err(&s_rt->slave->dev, 171f8101c74SSanyog Kale "DPN_BlockCtrl1 register write failed for port %d", 172f8101c74SSanyog Kale t_params->port_num); 173f8101c74SSanyog Kale return ret; 174f8101c74SSanyog Kale } 175f8101c74SSanyog Kale 176f8101c74SSanyog Kale /* Program DPN_SampleCtrl1 register */ 177f8101c74SSanyog Kale wbuf = (t_params->sample_interval - 1) & SDW_DPN_SAMPLECTRL_LOW; 178f8101c74SSanyog Kale ret = sdw_write(s_rt->slave, addr3, wbuf); 179f8101c74SSanyog Kale if (ret < 0) { 180f8101c74SSanyog Kale dev_err(&s_rt->slave->dev, 181f8101c74SSanyog Kale "DPN_SampleCtrl1 register write failed for port %d", 182f8101c74SSanyog Kale t_params->port_num); 183f8101c74SSanyog Kale return ret; 184f8101c74SSanyog Kale } 185f8101c74SSanyog Kale 186f8101c74SSanyog Kale /* Program DPN_OffsetCtrl1 registers */ 187f8101c74SSanyog Kale ret = sdw_write(s_rt->slave, addr4, t_params->offset1); 188f8101c74SSanyog Kale if (ret < 0) { 189f8101c74SSanyog Kale dev_err(&s_rt->slave->dev, 190f8101c74SSanyog Kale "DPN_OffsetCtrl1 register write failed for port %d", 191f8101c74SSanyog Kale t_params->port_num); 192f8101c74SSanyog Kale return ret; 193f8101c74SSanyog Kale } 194f8101c74SSanyog Kale 195f8101c74SSanyog Kale /* Program DPN_BlockCtrl2 register*/ 196f8101c74SSanyog Kale if (t_params->blk_grp_ctrl_valid) { 197f8101c74SSanyog Kale ret = sdw_write(s_rt->slave, addr5, t_params->blk_grp_ctrl); 198f8101c74SSanyog Kale if (ret < 0) { 199f8101c74SSanyog Kale dev_err(&s_rt->slave->dev, 200f8101c74SSanyog Kale "DPN_BlockCtrl2 reg write failed for port %d", 201f8101c74SSanyog Kale t_params->port_num); 202f8101c74SSanyog Kale return ret; 203f8101c74SSanyog Kale } 204f8101c74SSanyog Kale } 205f8101c74SSanyog Kale 206f8101c74SSanyog Kale /* program DPN_LaneCtrl register */ 207f8101c74SSanyog Kale if (slave_prop->lane_control_support) { 208f8101c74SSanyog Kale ret = sdw_write(s_rt->slave, addr6, t_params->lane_ctrl); 209f8101c74SSanyog Kale if (ret < 0) { 210f8101c74SSanyog Kale dev_err(&s_rt->slave->dev, 211f8101c74SSanyog Kale "DPN_LaneCtrl register write failed for port %d", 212f8101c74SSanyog Kale t_params->port_num); 213f8101c74SSanyog Kale return ret; 214f8101c74SSanyog Kale } 215f8101c74SSanyog Kale } 216f8101c74SSanyog Kale 217f8101c74SSanyog Kale if (dpn_prop->type != SDW_DPN_SIMPLE) { 218f8101c74SSanyog Kale ret = _sdw_program_slave_port_params(bus, s_rt->slave, 219f8101c74SSanyog Kale t_params, dpn_prop->type); 220f8101c74SSanyog Kale if (ret < 0) 221f8101c74SSanyog Kale dev_err(&s_rt->slave->dev, 222f8101c74SSanyog Kale "Transport reg write failed for port: %d", 223f8101c74SSanyog Kale t_params->port_num); 224f8101c74SSanyog Kale } 225f8101c74SSanyog Kale 226f8101c74SSanyog Kale return ret; 227f8101c74SSanyog Kale } 228f8101c74SSanyog Kale 229f8101c74SSanyog Kale static int sdw_program_master_port_params(struct sdw_bus *bus, 230f8101c74SSanyog Kale struct sdw_port_runtime *p_rt) 231f8101c74SSanyog Kale { 232f8101c74SSanyog Kale int ret; 233f8101c74SSanyog Kale 234f8101c74SSanyog Kale /* 235f8101c74SSanyog Kale * we need to set transport and port parameters for the port. 236f8101c74SSanyog Kale * Transport parameters refers to the smaple interval, offsets and 237f8101c74SSanyog Kale * hstart/stop etc of the data. Port parameters refers to word 238f8101c74SSanyog Kale * length, flow mode etc of the port 239f8101c74SSanyog Kale */ 240f8101c74SSanyog Kale ret = bus->port_ops->dpn_set_port_transport_params(bus, 241f8101c74SSanyog Kale &p_rt->transport_params, 242f8101c74SSanyog Kale bus->params.next_bank); 243f8101c74SSanyog Kale if (ret < 0) 244f8101c74SSanyog Kale return ret; 245f8101c74SSanyog Kale 246f8101c74SSanyog Kale return bus->port_ops->dpn_set_port_params(bus, 247f8101c74SSanyog Kale &p_rt->port_params, 248f8101c74SSanyog Kale bus->params.next_bank); 249f8101c74SSanyog Kale } 250f8101c74SSanyog Kale 251f8101c74SSanyog Kale /** 252f8101c74SSanyog Kale * sdw_program_port_params() - Programs transport parameters of Master(s) 253f8101c74SSanyog Kale * and Slave(s) 254f8101c74SSanyog Kale * 255f8101c74SSanyog Kale * @m_rt: Master stream runtime 256f8101c74SSanyog Kale */ 257f8101c74SSanyog Kale static int sdw_program_port_params(struct sdw_master_runtime *m_rt) 258f8101c74SSanyog Kale { 259f8101c74SSanyog Kale struct sdw_slave_runtime *s_rt = NULL; 260f8101c74SSanyog Kale struct sdw_bus *bus = m_rt->bus; 261f8101c74SSanyog Kale struct sdw_port_runtime *p_rt; 262f8101c74SSanyog Kale int ret = 0; 263f8101c74SSanyog Kale 264f8101c74SSanyog Kale /* Program transport & port parameters for Slave(s) */ 265f8101c74SSanyog Kale list_for_each_entry(s_rt, &m_rt->slave_rt_list, m_rt_node) { 266f8101c74SSanyog Kale list_for_each_entry(p_rt, &s_rt->port_list, port_node) { 267f8101c74SSanyog Kale ret = sdw_program_slave_port_params(bus, s_rt, p_rt); 268f8101c74SSanyog Kale if (ret < 0) 269f8101c74SSanyog Kale return ret; 270f8101c74SSanyog Kale } 271f8101c74SSanyog Kale } 272f8101c74SSanyog Kale 273f8101c74SSanyog Kale /* Program transport & port parameters for Master(s) */ 274f8101c74SSanyog Kale list_for_each_entry(p_rt, &m_rt->port_list, port_node) { 275f8101c74SSanyog Kale ret = sdw_program_master_port_params(bus, p_rt); 276f8101c74SSanyog Kale if (ret < 0) 277f8101c74SSanyog Kale return ret; 278f8101c74SSanyog Kale } 279f8101c74SSanyog Kale 280f8101c74SSanyog Kale return 0; 281f8101c74SSanyog Kale } 282f8101c74SSanyog Kale 28389e59053SSanyog Kale /** 28479df15b7SSanyog Kale * sdw_enable_disable_slave_ports: Enable/disable slave data port 28579df15b7SSanyog Kale * 28679df15b7SSanyog Kale * @bus: bus instance 28779df15b7SSanyog Kale * @s_rt: slave runtime 28879df15b7SSanyog Kale * @p_rt: port runtime 28979df15b7SSanyog Kale * @en: enable or disable operation 29079df15b7SSanyog Kale * 29179df15b7SSanyog Kale * This function only sets the enable/disable bits in the relevant bank, the 29279df15b7SSanyog Kale * actual enable/disable is done with a bank switch 29379df15b7SSanyog Kale */ 29479df15b7SSanyog Kale static int sdw_enable_disable_slave_ports(struct sdw_bus *bus, 29579df15b7SSanyog Kale struct sdw_slave_runtime *s_rt, 29679df15b7SSanyog Kale struct sdw_port_runtime *p_rt, bool en) 29779df15b7SSanyog Kale { 29879df15b7SSanyog Kale struct sdw_transport_params *t_params = &p_rt->transport_params; 29979df15b7SSanyog Kale u32 addr; 30079df15b7SSanyog Kale int ret; 30179df15b7SSanyog Kale 30279df15b7SSanyog Kale if (bus->params.next_bank) 30379df15b7SSanyog Kale addr = SDW_DPN_CHANNELEN_B1(p_rt->num); 30479df15b7SSanyog Kale else 30579df15b7SSanyog Kale addr = SDW_DPN_CHANNELEN_B0(p_rt->num); 30679df15b7SSanyog Kale 30779df15b7SSanyog Kale /* 30879df15b7SSanyog Kale * Since bus doesn't support sharing a port across two streams, 30979df15b7SSanyog Kale * it is safe to reset this register 31079df15b7SSanyog Kale */ 31179df15b7SSanyog Kale if (en) 31279df15b7SSanyog Kale ret = sdw_update(s_rt->slave, addr, 0xFF, p_rt->ch_mask); 31379df15b7SSanyog Kale else 31479df15b7SSanyog Kale ret = sdw_update(s_rt->slave, addr, 0xFF, 0x0); 31579df15b7SSanyog Kale 31679df15b7SSanyog Kale if (ret < 0) 31779df15b7SSanyog Kale dev_err(&s_rt->slave->dev, 31879df15b7SSanyog Kale "Slave chn_en reg write failed:%d port:%d", 31979df15b7SSanyog Kale ret, t_params->port_num); 32079df15b7SSanyog Kale 32179df15b7SSanyog Kale return ret; 32279df15b7SSanyog Kale } 32379df15b7SSanyog Kale 32479df15b7SSanyog Kale static int sdw_enable_disable_master_ports(struct sdw_master_runtime *m_rt, 32579df15b7SSanyog Kale struct sdw_port_runtime *p_rt, bool en) 32679df15b7SSanyog Kale { 32779df15b7SSanyog Kale struct sdw_transport_params *t_params = &p_rt->transport_params; 32879df15b7SSanyog Kale struct sdw_bus *bus = m_rt->bus; 32979df15b7SSanyog Kale struct sdw_enable_ch enable_ch; 33079df15b7SSanyog Kale int ret = 0; 33179df15b7SSanyog Kale 33279df15b7SSanyog Kale enable_ch.port_num = p_rt->num; 33379df15b7SSanyog Kale enable_ch.ch_mask = p_rt->ch_mask; 33479df15b7SSanyog Kale enable_ch.enable = en; 33579df15b7SSanyog Kale 33679df15b7SSanyog Kale /* Perform Master port channel(s) enable/disable */ 33779df15b7SSanyog Kale if (bus->port_ops->dpn_port_enable_ch) { 33879df15b7SSanyog Kale ret = bus->port_ops->dpn_port_enable_ch(bus, 33979df15b7SSanyog Kale &enable_ch, bus->params.next_bank); 34079df15b7SSanyog Kale if (ret < 0) { 34179df15b7SSanyog Kale dev_err(bus->dev, 34279df15b7SSanyog Kale "Master chn_en write failed:%d port:%d", 34379df15b7SSanyog Kale ret, t_params->port_num); 34479df15b7SSanyog Kale return ret; 34579df15b7SSanyog Kale } 34679df15b7SSanyog Kale } else { 34779df15b7SSanyog Kale dev_err(bus->dev, 34879df15b7SSanyog Kale "dpn_port_enable_ch not supported, %s failed\n", 34979df15b7SSanyog Kale en ? "enable" : "disable"); 35079df15b7SSanyog Kale return -EINVAL; 35179df15b7SSanyog Kale } 35279df15b7SSanyog Kale 35379df15b7SSanyog Kale return 0; 35479df15b7SSanyog Kale } 35579df15b7SSanyog Kale 35679df15b7SSanyog Kale /** 35779df15b7SSanyog Kale * sdw_enable_disable_ports() - Enable/disable port(s) for Master and 35879df15b7SSanyog Kale * Slave(s) 35979df15b7SSanyog Kale * 36079df15b7SSanyog Kale * @m_rt: Master stream runtime 36179df15b7SSanyog Kale * @en: mode (enable/disable) 36279df15b7SSanyog Kale */ 36379df15b7SSanyog Kale static int sdw_enable_disable_ports(struct sdw_master_runtime *m_rt, bool en) 36479df15b7SSanyog Kale { 36579df15b7SSanyog Kale struct sdw_port_runtime *s_port, *m_port; 36679df15b7SSanyog Kale struct sdw_slave_runtime *s_rt = NULL; 36779df15b7SSanyog Kale int ret = 0; 36879df15b7SSanyog Kale 36979df15b7SSanyog Kale /* Enable/Disable Slave port(s) */ 37079df15b7SSanyog Kale list_for_each_entry(s_rt, &m_rt->slave_rt_list, m_rt_node) { 37179df15b7SSanyog Kale list_for_each_entry(s_port, &s_rt->port_list, port_node) { 37279df15b7SSanyog Kale ret = sdw_enable_disable_slave_ports(m_rt->bus, s_rt, 37379df15b7SSanyog Kale s_port, en); 37479df15b7SSanyog Kale if (ret < 0) 37579df15b7SSanyog Kale return ret; 37679df15b7SSanyog Kale } 37779df15b7SSanyog Kale } 37879df15b7SSanyog Kale 37979df15b7SSanyog Kale /* Enable/Disable Master port(s) */ 38079df15b7SSanyog Kale list_for_each_entry(m_port, &m_rt->port_list, port_node) { 38179df15b7SSanyog Kale ret = sdw_enable_disable_master_ports(m_rt, m_port, en); 38279df15b7SSanyog Kale if (ret < 0) 38379df15b7SSanyog Kale return ret; 38479df15b7SSanyog Kale } 38579df15b7SSanyog Kale 38679df15b7SSanyog Kale return 0; 38779df15b7SSanyog Kale } 38879df15b7SSanyog Kale 38979df15b7SSanyog Kale static int sdw_do_port_prep(struct sdw_slave_runtime *s_rt, 39079df15b7SSanyog Kale struct sdw_prepare_ch prep_ch, enum sdw_port_prep_ops cmd) 39179df15b7SSanyog Kale { 39279df15b7SSanyog Kale const struct sdw_slave_ops *ops = s_rt->slave->ops; 39379df15b7SSanyog Kale int ret; 39479df15b7SSanyog Kale 39579df15b7SSanyog Kale if (ops->port_prep) { 39679df15b7SSanyog Kale ret = ops->port_prep(s_rt->slave, &prep_ch, cmd); 39779df15b7SSanyog Kale if (ret < 0) { 39879df15b7SSanyog Kale dev_err(&s_rt->slave->dev, 39979df15b7SSanyog Kale "Slave Port Prep cmd %d failed: %d", cmd, ret); 40079df15b7SSanyog Kale return ret; 40179df15b7SSanyog Kale } 40279df15b7SSanyog Kale } 40379df15b7SSanyog Kale 40479df15b7SSanyog Kale return 0; 40579df15b7SSanyog Kale } 40679df15b7SSanyog Kale 40779df15b7SSanyog Kale static int sdw_prep_deprep_slave_ports(struct sdw_bus *bus, 40879df15b7SSanyog Kale struct sdw_slave_runtime *s_rt, 40979df15b7SSanyog Kale struct sdw_port_runtime *p_rt, bool prep) 41079df15b7SSanyog Kale { 41179df15b7SSanyog Kale struct completion *port_ready = NULL; 41279df15b7SSanyog Kale struct sdw_dpn_prop *dpn_prop; 41379df15b7SSanyog Kale struct sdw_prepare_ch prep_ch; 41479df15b7SSanyog Kale unsigned int time_left; 41579df15b7SSanyog Kale bool intr = false; 41679df15b7SSanyog Kale int ret = 0, val; 41779df15b7SSanyog Kale u32 addr; 41879df15b7SSanyog Kale 41979df15b7SSanyog Kale prep_ch.num = p_rt->num; 42079df15b7SSanyog Kale prep_ch.ch_mask = p_rt->ch_mask; 42179df15b7SSanyog Kale 42279df15b7SSanyog Kale dpn_prop = sdw_get_slave_dpn_prop(s_rt->slave, 42379df15b7SSanyog Kale s_rt->direction, 42479df15b7SSanyog Kale prep_ch.num); 42579df15b7SSanyog Kale if (!dpn_prop) { 42679df15b7SSanyog Kale dev_err(bus->dev, 42779df15b7SSanyog Kale "Slave Port:%d properties not found", prep_ch.num); 42879df15b7SSanyog Kale return -EINVAL; 42979df15b7SSanyog Kale } 43079df15b7SSanyog Kale 43179df15b7SSanyog Kale prep_ch.prepare = prep; 43279df15b7SSanyog Kale 43379df15b7SSanyog Kale prep_ch.bank = bus->params.next_bank; 43479df15b7SSanyog Kale 43579df15b7SSanyog Kale if (dpn_prop->device_interrupts || !dpn_prop->simple_ch_prep_sm) 43679df15b7SSanyog Kale intr = true; 43779df15b7SSanyog Kale 43879df15b7SSanyog Kale /* 43979df15b7SSanyog Kale * Enable interrupt before Port prepare. 44079df15b7SSanyog Kale * For Port de-prepare, it is assumed that port 44179df15b7SSanyog Kale * was prepared earlier 44279df15b7SSanyog Kale */ 44379df15b7SSanyog Kale if (prep && intr) { 44479df15b7SSanyog Kale ret = sdw_configure_dpn_intr(s_rt->slave, p_rt->num, prep, 44579df15b7SSanyog Kale dpn_prop->device_interrupts); 44679df15b7SSanyog Kale if (ret < 0) 44779df15b7SSanyog Kale return ret; 44879df15b7SSanyog Kale } 44979df15b7SSanyog Kale 45079df15b7SSanyog Kale /* Inform slave about the impending port prepare */ 45179df15b7SSanyog Kale sdw_do_port_prep(s_rt, prep_ch, SDW_OPS_PORT_PRE_PREP); 45279df15b7SSanyog Kale 45379df15b7SSanyog Kale /* Prepare Slave port implementing CP_SM */ 45479df15b7SSanyog Kale if (!dpn_prop->simple_ch_prep_sm) { 45579df15b7SSanyog Kale addr = SDW_DPN_PREPARECTRL(p_rt->num); 45679df15b7SSanyog Kale 45779df15b7SSanyog Kale if (prep) 45879df15b7SSanyog Kale ret = sdw_update(s_rt->slave, addr, 45979df15b7SSanyog Kale 0xFF, p_rt->ch_mask); 46079df15b7SSanyog Kale else 46179df15b7SSanyog Kale ret = sdw_update(s_rt->slave, addr, 0xFF, 0x0); 46279df15b7SSanyog Kale 46379df15b7SSanyog Kale if (ret < 0) { 46479df15b7SSanyog Kale dev_err(&s_rt->slave->dev, 46579df15b7SSanyog Kale "Slave prep_ctrl reg write failed"); 46679df15b7SSanyog Kale return ret; 46779df15b7SSanyog Kale } 46879df15b7SSanyog Kale 46979df15b7SSanyog Kale /* Wait for completion on port ready */ 47079df15b7SSanyog Kale port_ready = &s_rt->slave->port_ready[prep_ch.num]; 47179df15b7SSanyog Kale time_left = wait_for_completion_timeout(port_ready, 47279df15b7SSanyog Kale msecs_to_jiffies(dpn_prop->ch_prep_timeout)); 47379df15b7SSanyog Kale 47479df15b7SSanyog Kale val = sdw_read(s_rt->slave, SDW_DPN_PREPARESTATUS(p_rt->num)); 47579df15b7SSanyog Kale val &= p_rt->ch_mask; 47679df15b7SSanyog Kale if (!time_left || val) { 47779df15b7SSanyog Kale dev_err(&s_rt->slave->dev, 47879df15b7SSanyog Kale "Chn prep failed for port:%d", prep_ch.num); 47979df15b7SSanyog Kale return -ETIMEDOUT; 48079df15b7SSanyog Kale } 48179df15b7SSanyog Kale } 48279df15b7SSanyog Kale 48379df15b7SSanyog Kale /* Inform slaves about ports prepared */ 48479df15b7SSanyog Kale sdw_do_port_prep(s_rt, prep_ch, SDW_OPS_PORT_POST_PREP); 48579df15b7SSanyog Kale 48679df15b7SSanyog Kale /* Disable interrupt after Port de-prepare */ 48779df15b7SSanyog Kale if (!prep && intr) 48879df15b7SSanyog Kale ret = sdw_configure_dpn_intr(s_rt->slave, p_rt->num, prep, 48979df15b7SSanyog Kale dpn_prop->device_interrupts); 49079df15b7SSanyog Kale 49179df15b7SSanyog Kale return ret; 49279df15b7SSanyog Kale } 49379df15b7SSanyog Kale 49479df15b7SSanyog Kale static int sdw_prep_deprep_master_ports(struct sdw_master_runtime *m_rt, 49579df15b7SSanyog Kale struct sdw_port_runtime *p_rt, bool prep) 49679df15b7SSanyog Kale { 49779df15b7SSanyog Kale struct sdw_transport_params *t_params = &p_rt->transport_params; 49879df15b7SSanyog Kale struct sdw_bus *bus = m_rt->bus; 49979df15b7SSanyog Kale const struct sdw_master_port_ops *ops = bus->port_ops; 50079df15b7SSanyog Kale struct sdw_prepare_ch prep_ch; 50179df15b7SSanyog Kale int ret = 0; 50279df15b7SSanyog Kale 50379df15b7SSanyog Kale prep_ch.num = p_rt->num; 50479df15b7SSanyog Kale prep_ch.ch_mask = p_rt->ch_mask; 50579df15b7SSanyog Kale prep_ch.prepare = prep; /* Prepare/De-prepare */ 50679df15b7SSanyog Kale prep_ch.bank = bus->params.next_bank; 50779df15b7SSanyog Kale 50879df15b7SSanyog Kale /* Pre-prepare/Pre-deprepare port(s) */ 50979df15b7SSanyog Kale if (ops->dpn_port_prep) { 51079df15b7SSanyog Kale ret = ops->dpn_port_prep(bus, &prep_ch); 51179df15b7SSanyog Kale if (ret < 0) { 51279df15b7SSanyog Kale dev_err(bus->dev, "Port prepare failed for port:%d", 51379df15b7SSanyog Kale t_params->port_num); 51479df15b7SSanyog Kale return ret; 51579df15b7SSanyog Kale } 51679df15b7SSanyog Kale } 51779df15b7SSanyog Kale 51879df15b7SSanyog Kale return ret; 51979df15b7SSanyog Kale } 52079df15b7SSanyog Kale 52179df15b7SSanyog Kale /** 52279df15b7SSanyog Kale * sdw_prep_deprep_ports() - Prepare/De-prepare port(s) for Master(s) and 52379df15b7SSanyog Kale * Slave(s) 52479df15b7SSanyog Kale * 52579df15b7SSanyog Kale * @m_rt: Master runtime handle 52679df15b7SSanyog Kale * @prep: Prepare or De-prepare 52779df15b7SSanyog Kale */ 52879df15b7SSanyog Kale static int sdw_prep_deprep_ports(struct sdw_master_runtime *m_rt, bool prep) 52979df15b7SSanyog Kale { 53079df15b7SSanyog Kale struct sdw_slave_runtime *s_rt = NULL; 53179df15b7SSanyog Kale struct sdw_port_runtime *p_rt; 53279df15b7SSanyog Kale int ret = 0; 53379df15b7SSanyog Kale 53479df15b7SSanyog Kale /* Prepare/De-prepare Slave port(s) */ 53579df15b7SSanyog Kale list_for_each_entry(s_rt, &m_rt->slave_rt_list, m_rt_node) { 53679df15b7SSanyog Kale list_for_each_entry(p_rt, &s_rt->port_list, port_node) { 53779df15b7SSanyog Kale ret = sdw_prep_deprep_slave_ports(m_rt->bus, s_rt, 53879df15b7SSanyog Kale p_rt, prep); 53979df15b7SSanyog Kale if (ret < 0) 54079df15b7SSanyog Kale return ret; 54179df15b7SSanyog Kale } 54279df15b7SSanyog Kale } 54379df15b7SSanyog Kale 54479df15b7SSanyog Kale /* Prepare/De-prepare Master port(s) */ 54579df15b7SSanyog Kale list_for_each_entry(p_rt, &m_rt->port_list, port_node) { 54679df15b7SSanyog Kale ret = sdw_prep_deprep_master_ports(m_rt, p_rt, prep); 54779df15b7SSanyog Kale if (ret < 0) 54879df15b7SSanyog Kale return ret; 54979df15b7SSanyog Kale } 55079df15b7SSanyog Kale 55179df15b7SSanyog Kale return ret; 55279df15b7SSanyog Kale } 55379df15b7SSanyog Kale 55479df15b7SSanyog Kale /** 55599b8a5d6SSanyog Kale * sdw_notify_config() - Notify bus configuration 55699b8a5d6SSanyog Kale * 55799b8a5d6SSanyog Kale * @m_rt: Master runtime handle 55899b8a5d6SSanyog Kale * 55999b8a5d6SSanyog Kale * This function notifies the Master(s) and Slave(s) of the 56099b8a5d6SSanyog Kale * new bus configuration. 56199b8a5d6SSanyog Kale */ 56299b8a5d6SSanyog Kale static int sdw_notify_config(struct sdw_master_runtime *m_rt) 56399b8a5d6SSanyog Kale { 56499b8a5d6SSanyog Kale struct sdw_slave_runtime *s_rt; 56599b8a5d6SSanyog Kale struct sdw_bus *bus = m_rt->bus; 56699b8a5d6SSanyog Kale struct sdw_slave *slave; 56799b8a5d6SSanyog Kale int ret = 0; 56899b8a5d6SSanyog Kale 56999b8a5d6SSanyog Kale if (bus->ops->set_bus_conf) { 57099b8a5d6SSanyog Kale ret = bus->ops->set_bus_conf(bus, &bus->params); 57199b8a5d6SSanyog Kale if (ret < 0) 57299b8a5d6SSanyog Kale return ret; 57399b8a5d6SSanyog Kale } 57499b8a5d6SSanyog Kale 57599b8a5d6SSanyog Kale list_for_each_entry(s_rt, &m_rt->slave_rt_list, m_rt_node) { 57699b8a5d6SSanyog Kale slave = s_rt->slave; 57799b8a5d6SSanyog Kale 57899b8a5d6SSanyog Kale if (slave->ops->bus_config) { 57999b8a5d6SSanyog Kale ret = slave->ops->bus_config(slave, &bus->params); 58099b8a5d6SSanyog Kale if (ret < 0) 58199b8a5d6SSanyog Kale dev_err(bus->dev, "Notify Slave: %d failed", 58299b8a5d6SSanyog Kale slave->dev_num); 58399b8a5d6SSanyog Kale return ret; 58499b8a5d6SSanyog Kale } 58599b8a5d6SSanyog Kale } 58699b8a5d6SSanyog Kale 58799b8a5d6SSanyog Kale return ret; 58899b8a5d6SSanyog Kale } 58999b8a5d6SSanyog Kale 59099b8a5d6SSanyog Kale /** 59199b8a5d6SSanyog Kale * sdw_program_params() - Program transport and port parameters for Master(s) 59299b8a5d6SSanyog Kale * and Slave(s) 59399b8a5d6SSanyog Kale * 59499b8a5d6SSanyog Kale * @bus: SDW bus instance 59599b8a5d6SSanyog Kale */ 59699b8a5d6SSanyog Kale static int sdw_program_params(struct sdw_bus *bus) 59799b8a5d6SSanyog Kale { 59899b8a5d6SSanyog Kale struct sdw_master_runtime *m_rt = NULL; 59999b8a5d6SSanyog Kale int ret = 0; 60099b8a5d6SSanyog Kale 60199b8a5d6SSanyog Kale list_for_each_entry(m_rt, &bus->m_rt_list, bus_node) { 60299b8a5d6SSanyog Kale ret = sdw_program_port_params(m_rt); 60399b8a5d6SSanyog Kale if (ret < 0) { 60499b8a5d6SSanyog Kale dev_err(bus->dev, 60599b8a5d6SSanyog Kale "Program transport params failed: %d", ret); 60699b8a5d6SSanyog Kale return ret; 60799b8a5d6SSanyog Kale } 60899b8a5d6SSanyog Kale 60999b8a5d6SSanyog Kale ret = sdw_notify_config(m_rt); 61099b8a5d6SSanyog Kale if (ret < 0) { 61199b8a5d6SSanyog Kale dev_err(bus->dev, "Notify bus config failed: %d", ret); 61299b8a5d6SSanyog Kale return ret; 61399b8a5d6SSanyog Kale } 61499b8a5d6SSanyog Kale 61599b8a5d6SSanyog Kale /* Enable port(s) on alternate bank for all active streams */ 61699b8a5d6SSanyog Kale if (m_rt->stream->state != SDW_STREAM_ENABLED) 61799b8a5d6SSanyog Kale continue; 61899b8a5d6SSanyog Kale 61999b8a5d6SSanyog Kale ret = sdw_enable_disable_ports(m_rt, true); 62099b8a5d6SSanyog Kale if (ret < 0) { 62199b8a5d6SSanyog Kale dev_err(bus->dev, "Enable channel failed: %d", ret); 62299b8a5d6SSanyog Kale return ret; 62399b8a5d6SSanyog Kale } 62499b8a5d6SSanyog Kale } 62599b8a5d6SSanyog Kale 62699b8a5d6SSanyog Kale return ret; 62799b8a5d6SSanyog Kale } 62899b8a5d6SSanyog Kale 62999b8a5d6SSanyog Kale static int sdw_bank_switch(struct sdw_bus *bus) 63099b8a5d6SSanyog Kale { 63199b8a5d6SSanyog Kale int col_index, row_index; 63299b8a5d6SSanyog Kale struct sdw_msg *wr_msg; 63399b8a5d6SSanyog Kale u8 *wbuf = NULL; 63499b8a5d6SSanyog Kale int ret = 0; 63599b8a5d6SSanyog Kale u16 addr; 63699b8a5d6SSanyog Kale 63799b8a5d6SSanyog Kale wr_msg = kzalloc(sizeof(*wr_msg), GFP_KERNEL); 63899b8a5d6SSanyog Kale if (!wr_msg) 63999b8a5d6SSanyog Kale return -ENOMEM; 64099b8a5d6SSanyog Kale 64199b8a5d6SSanyog Kale wbuf = kzalloc(sizeof(*wbuf), GFP_KERNEL); 64299b8a5d6SSanyog Kale if (!wbuf) { 64399b8a5d6SSanyog Kale ret = -ENOMEM; 64499b8a5d6SSanyog Kale goto error_1; 64599b8a5d6SSanyog Kale } 64699b8a5d6SSanyog Kale 64799b8a5d6SSanyog Kale /* Get row and column index to program register */ 64899b8a5d6SSanyog Kale col_index = sdw_find_col_index(bus->params.col); 64999b8a5d6SSanyog Kale row_index = sdw_find_row_index(bus->params.row); 65099b8a5d6SSanyog Kale wbuf[0] = col_index | (row_index << 3); 65199b8a5d6SSanyog Kale 65299b8a5d6SSanyog Kale if (bus->params.next_bank) 65399b8a5d6SSanyog Kale addr = SDW_SCP_FRAMECTRL_B1; 65499b8a5d6SSanyog Kale else 65599b8a5d6SSanyog Kale addr = SDW_SCP_FRAMECTRL_B0; 65699b8a5d6SSanyog Kale 65799b8a5d6SSanyog Kale sdw_fill_msg(wr_msg, NULL, addr, 1, SDW_BROADCAST_DEV_NUM, 65899b8a5d6SSanyog Kale SDW_MSG_FLAG_WRITE, wbuf); 65999b8a5d6SSanyog Kale wr_msg->ssp_sync = true; 66099b8a5d6SSanyog Kale 66199b8a5d6SSanyog Kale ret = sdw_transfer(bus, wr_msg); 66299b8a5d6SSanyog Kale if (ret < 0) { 66399b8a5d6SSanyog Kale dev_err(bus->dev, "Slave frame_ctrl reg write failed"); 66499b8a5d6SSanyog Kale goto error; 66599b8a5d6SSanyog Kale } 66699b8a5d6SSanyog Kale 66799b8a5d6SSanyog Kale kfree(wr_msg); 66899b8a5d6SSanyog Kale kfree(wbuf); 66999b8a5d6SSanyog Kale bus->defer_msg.msg = NULL; 67099b8a5d6SSanyog Kale bus->params.curr_bank = !bus->params.curr_bank; 67199b8a5d6SSanyog Kale bus->params.next_bank = !bus->params.next_bank; 67299b8a5d6SSanyog Kale 67399b8a5d6SSanyog Kale return 0; 67499b8a5d6SSanyog Kale 67599b8a5d6SSanyog Kale error: 67699b8a5d6SSanyog Kale kfree(wbuf); 67799b8a5d6SSanyog Kale error_1: 67899b8a5d6SSanyog Kale kfree(wr_msg); 67999b8a5d6SSanyog Kale return ret; 68099b8a5d6SSanyog Kale } 68199b8a5d6SSanyog Kale 68299b8a5d6SSanyog Kale static int do_bank_switch(struct sdw_stream_runtime *stream) 68399b8a5d6SSanyog Kale { 68499b8a5d6SSanyog Kale struct sdw_master_runtime *m_rt = stream->m_rt; 68599b8a5d6SSanyog Kale const struct sdw_master_ops *ops; 68699b8a5d6SSanyog Kale struct sdw_bus *bus = m_rt->bus; 68799b8a5d6SSanyog Kale int ret = 0; 68899b8a5d6SSanyog Kale 68999b8a5d6SSanyog Kale ops = bus->ops; 69099b8a5d6SSanyog Kale 69199b8a5d6SSanyog Kale /* Pre-bank switch */ 69299b8a5d6SSanyog Kale if (ops->pre_bank_switch) { 69399b8a5d6SSanyog Kale ret = ops->pre_bank_switch(bus); 69499b8a5d6SSanyog Kale if (ret < 0) { 69599b8a5d6SSanyog Kale dev_err(bus->dev, "Pre bank switch op failed: %d", ret); 69699b8a5d6SSanyog Kale return ret; 69799b8a5d6SSanyog Kale } 69899b8a5d6SSanyog Kale } 69999b8a5d6SSanyog Kale 70099b8a5d6SSanyog Kale /* Bank switch */ 70199b8a5d6SSanyog Kale ret = sdw_bank_switch(bus); 70299b8a5d6SSanyog Kale if (ret < 0) { 70399b8a5d6SSanyog Kale dev_err(bus->dev, "Bank switch failed: %d", ret); 70499b8a5d6SSanyog Kale return ret; 70599b8a5d6SSanyog Kale } 70699b8a5d6SSanyog Kale 70799b8a5d6SSanyog Kale /* Post-bank switch */ 70899b8a5d6SSanyog Kale if (ops->post_bank_switch) { 70999b8a5d6SSanyog Kale ret = ops->post_bank_switch(bus); 71099b8a5d6SSanyog Kale if (ret < 0) { 71199b8a5d6SSanyog Kale dev_err(bus->dev, 71299b8a5d6SSanyog Kale "Post bank switch op failed: %d", ret); 71399b8a5d6SSanyog Kale } 71499b8a5d6SSanyog Kale } 71599b8a5d6SSanyog Kale 71699b8a5d6SSanyog Kale return ret; 71799b8a5d6SSanyog Kale } 71899b8a5d6SSanyog Kale 71999b8a5d6SSanyog Kale /** 72089e59053SSanyog Kale * sdw_release_stream() - Free the assigned stream runtime 72189e59053SSanyog Kale * 72289e59053SSanyog Kale * @stream: SoundWire stream runtime 72389e59053SSanyog Kale * 72489e59053SSanyog Kale * sdw_release_stream should be called only once per stream 72589e59053SSanyog Kale */ 72689e59053SSanyog Kale void sdw_release_stream(struct sdw_stream_runtime *stream) 72789e59053SSanyog Kale { 72889e59053SSanyog Kale kfree(stream); 72989e59053SSanyog Kale } 73089e59053SSanyog Kale EXPORT_SYMBOL(sdw_release_stream); 73189e59053SSanyog Kale 73289e59053SSanyog Kale /** 73389e59053SSanyog Kale * sdw_alloc_stream() - Allocate and return stream runtime 73489e59053SSanyog Kale * 73589e59053SSanyog Kale * @stream_name: SoundWire stream name 73689e59053SSanyog Kale * 73789e59053SSanyog Kale * Allocates a SoundWire stream runtime instance. 73889e59053SSanyog Kale * sdw_alloc_stream should be called only once per stream. Typically 73989e59053SSanyog Kale * invoked from ALSA/ASoC machine/platform driver. 74089e59053SSanyog Kale */ 74189e59053SSanyog Kale struct sdw_stream_runtime *sdw_alloc_stream(char *stream_name) 74289e59053SSanyog Kale { 74389e59053SSanyog Kale struct sdw_stream_runtime *stream; 74489e59053SSanyog Kale 74589e59053SSanyog Kale stream = kzalloc(sizeof(*stream), GFP_KERNEL); 74689e59053SSanyog Kale if (!stream) 74789e59053SSanyog Kale return NULL; 74889e59053SSanyog Kale 74989e59053SSanyog Kale stream->name = stream_name; 75089e59053SSanyog Kale stream->state = SDW_STREAM_ALLOCATED; 75189e59053SSanyog Kale 75289e59053SSanyog Kale return stream; 75389e59053SSanyog Kale } 75489e59053SSanyog Kale EXPORT_SYMBOL(sdw_alloc_stream); 75589e59053SSanyog Kale 75689e59053SSanyog Kale /** 75789e59053SSanyog Kale * sdw_alloc_master_rt() - Allocates and initialize Master runtime handle 75889e59053SSanyog Kale * 75989e59053SSanyog Kale * @bus: SDW bus instance 76089e59053SSanyog Kale * @stream_config: Stream configuration 76189e59053SSanyog Kale * @stream: Stream runtime handle. 76289e59053SSanyog Kale * 76389e59053SSanyog Kale * This function is to be called with bus_lock held. 76489e59053SSanyog Kale */ 76589e59053SSanyog Kale static struct sdw_master_runtime 76689e59053SSanyog Kale *sdw_alloc_master_rt(struct sdw_bus *bus, 76789e59053SSanyog Kale struct sdw_stream_config *stream_config, 76889e59053SSanyog Kale struct sdw_stream_runtime *stream) 76989e59053SSanyog Kale { 77089e59053SSanyog Kale struct sdw_master_runtime *m_rt; 77189e59053SSanyog Kale 77289e59053SSanyog Kale m_rt = stream->m_rt; 77389e59053SSanyog Kale 77489e59053SSanyog Kale /* 77589e59053SSanyog Kale * check if Master is already allocated (as a result of Slave adding 77689e59053SSanyog Kale * it first), if so skip allocation and go to configure 77789e59053SSanyog Kale */ 77889e59053SSanyog Kale if (m_rt) 77989e59053SSanyog Kale goto stream_config; 78089e59053SSanyog Kale 78189e59053SSanyog Kale m_rt = kzalloc(sizeof(*m_rt), GFP_KERNEL); 78289e59053SSanyog Kale if (!m_rt) 78389e59053SSanyog Kale return NULL; 78489e59053SSanyog Kale 78589e59053SSanyog Kale /* Initialization of Master runtime handle */ 786bbe7379dSSanyog Kale INIT_LIST_HEAD(&m_rt->port_list); 78789e59053SSanyog Kale INIT_LIST_HEAD(&m_rt->slave_rt_list); 78889e59053SSanyog Kale stream->m_rt = m_rt; 78989e59053SSanyog Kale 79089e59053SSanyog Kale list_add_tail(&m_rt->bus_node, &bus->m_rt_list); 79189e59053SSanyog Kale 79289e59053SSanyog Kale stream_config: 79389e59053SSanyog Kale m_rt->ch_count = stream_config->ch_count; 79489e59053SSanyog Kale m_rt->bus = bus; 79589e59053SSanyog Kale m_rt->stream = stream; 79689e59053SSanyog Kale m_rt->direction = stream_config->direction; 79789e59053SSanyog Kale 79889e59053SSanyog Kale return m_rt; 79989e59053SSanyog Kale } 80089e59053SSanyog Kale 80189e59053SSanyog Kale /** 80289e59053SSanyog Kale * sdw_alloc_slave_rt() - Allocate and initialize Slave runtime handle. 80389e59053SSanyog Kale * 80489e59053SSanyog Kale * @slave: Slave handle 80589e59053SSanyog Kale * @stream_config: Stream configuration 80689e59053SSanyog Kale * @stream: Stream runtime handle 80789e59053SSanyog Kale * 80889e59053SSanyog Kale * This function is to be called with bus_lock held. 80989e59053SSanyog Kale */ 81089e59053SSanyog Kale static struct sdw_slave_runtime 81189e59053SSanyog Kale *sdw_alloc_slave_rt(struct sdw_slave *slave, 81289e59053SSanyog Kale struct sdw_stream_config *stream_config, 81389e59053SSanyog Kale struct sdw_stream_runtime *stream) 81489e59053SSanyog Kale { 81589e59053SSanyog Kale struct sdw_slave_runtime *s_rt = NULL; 81689e59053SSanyog Kale 81789e59053SSanyog Kale s_rt = kzalloc(sizeof(*s_rt), GFP_KERNEL); 81889e59053SSanyog Kale if (!s_rt) 81989e59053SSanyog Kale return NULL; 82089e59053SSanyog Kale 821bbe7379dSSanyog Kale INIT_LIST_HEAD(&s_rt->port_list); 82289e59053SSanyog Kale s_rt->ch_count = stream_config->ch_count; 82389e59053SSanyog Kale s_rt->direction = stream_config->direction; 82489e59053SSanyog Kale s_rt->slave = slave; 82589e59053SSanyog Kale 82689e59053SSanyog Kale return s_rt; 82789e59053SSanyog Kale } 82889e59053SSanyog Kale 829bbe7379dSSanyog Kale static void sdw_master_port_release(struct sdw_bus *bus, 830bbe7379dSSanyog Kale struct sdw_master_runtime *m_rt) 831bbe7379dSSanyog Kale { 832bbe7379dSSanyog Kale struct sdw_port_runtime *p_rt, *_p_rt; 833bbe7379dSSanyog Kale 834bbe7379dSSanyog Kale list_for_each_entry_safe(p_rt, _p_rt, 835bbe7379dSSanyog Kale &m_rt->port_list, port_node) { 836bbe7379dSSanyog Kale list_del(&p_rt->port_node); 837bbe7379dSSanyog Kale kfree(p_rt); 838bbe7379dSSanyog Kale } 839bbe7379dSSanyog Kale } 840bbe7379dSSanyog Kale 841bbe7379dSSanyog Kale static void sdw_slave_port_release(struct sdw_bus *bus, 842bbe7379dSSanyog Kale struct sdw_slave *slave, 843bbe7379dSSanyog Kale struct sdw_stream_runtime *stream) 844bbe7379dSSanyog Kale { 845bbe7379dSSanyog Kale struct sdw_port_runtime *p_rt, *_p_rt; 846bbe7379dSSanyog Kale struct sdw_master_runtime *m_rt = stream->m_rt; 847bbe7379dSSanyog Kale struct sdw_slave_runtime *s_rt; 848bbe7379dSSanyog Kale 849bbe7379dSSanyog Kale list_for_each_entry(s_rt, &m_rt->slave_rt_list, m_rt_node) { 850bbe7379dSSanyog Kale if (s_rt->slave != slave) 851bbe7379dSSanyog Kale continue; 852bbe7379dSSanyog Kale 853bbe7379dSSanyog Kale list_for_each_entry_safe(p_rt, _p_rt, 854bbe7379dSSanyog Kale &s_rt->port_list, port_node) { 855bbe7379dSSanyog Kale list_del(&p_rt->port_node); 856bbe7379dSSanyog Kale kfree(p_rt); 857bbe7379dSSanyog Kale } 858bbe7379dSSanyog Kale } 859bbe7379dSSanyog Kale } 860bbe7379dSSanyog Kale 86189e59053SSanyog Kale /** 86289e59053SSanyog Kale * sdw_release_slave_stream() - Free Slave(s) runtime handle 86389e59053SSanyog Kale * 86489e59053SSanyog Kale * @slave: Slave handle. 86589e59053SSanyog Kale * @stream: Stream runtime handle. 86689e59053SSanyog Kale * 86789e59053SSanyog Kale * This function is to be called with bus_lock held. 86889e59053SSanyog Kale */ 86989e59053SSanyog Kale static void sdw_release_slave_stream(struct sdw_slave *slave, 87089e59053SSanyog Kale struct sdw_stream_runtime *stream) 87189e59053SSanyog Kale { 87289e59053SSanyog Kale struct sdw_slave_runtime *s_rt, *_s_rt; 87389e59053SSanyog Kale struct sdw_master_runtime *m_rt = stream->m_rt; 87489e59053SSanyog Kale 87589e59053SSanyog Kale /* Retrieve Slave runtime handle */ 87689e59053SSanyog Kale list_for_each_entry_safe(s_rt, _s_rt, 87789e59053SSanyog Kale &m_rt->slave_rt_list, m_rt_node) { 87889e59053SSanyog Kale 87989e59053SSanyog Kale if (s_rt->slave == slave) { 88089e59053SSanyog Kale list_del(&s_rt->m_rt_node); 88189e59053SSanyog Kale kfree(s_rt); 88289e59053SSanyog Kale return; 88389e59053SSanyog Kale } 88489e59053SSanyog Kale } 88589e59053SSanyog Kale } 88689e59053SSanyog Kale 88789e59053SSanyog Kale /** 88889e59053SSanyog Kale * sdw_release_master_stream() - Free Master runtime handle 88989e59053SSanyog Kale * 89089e59053SSanyog Kale * @stream: Stream runtime handle. 89189e59053SSanyog Kale * 89289e59053SSanyog Kale * This function is to be called with bus_lock held 89389e59053SSanyog Kale * It frees the Master runtime handle and associated Slave(s) runtime 89489e59053SSanyog Kale * handle. If this is called first then sdw_release_slave_stream() will have 89589e59053SSanyog Kale * no effect as Slave(s) runtime handle would already be freed up. 89689e59053SSanyog Kale */ 89789e59053SSanyog Kale static void sdw_release_master_stream(struct sdw_stream_runtime *stream) 89889e59053SSanyog Kale { 89989e59053SSanyog Kale struct sdw_master_runtime *m_rt = stream->m_rt; 90089e59053SSanyog Kale struct sdw_slave_runtime *s_rt, *_s_rt; 90189e59053SSanyog Kale 90289e59053SSanyog Kale list_for_each_entry_safe(s_rt, _s_rt, 90389e59053SSanyog Kale &m_rt->slave_rt_list, m_rt_node) 90489e59053SSanyog Kale sdw_stream_remove_slave(s_rt->slave, stream); 90589e59053SSanyog Kale 90689e59053SSanyog Kale list_del(&m_rt->bus_node); 90789e59053SSanyog Kale } 90889e59053SSanyog Kale 90989e59053SSanyog Kale /** 91089e59053SSanyog Kale * sdw_stream_remove_master() - Remove master from sdw_stream 91189e59053SSanyog Kale * 91289e59053SSanyog Kale * @bus: SDW Bus instance 91389e59053SSanyog Kale * @stream: SoundWire stream 91489e59053SSanyog Kale * 915bbe7379dSSanyog Kale * This removes and frees port_rt and master_rt from a stream 91689e59053SSanyog Kale */ 91789e59053SSanyog Kale int sdw_stream_remove_master(struct sdw_bus *bus, 91889e59053SSanyog Kale struct sdw_stream_runtime *stream) 91989e59053SSanyog Kale { 92089e59053SSanyog Kale mutex_lock(&bus->bus_lock); 92189e59053SSanyog Kale 92289e59053SSanyog Kale sdw_release_master_stream(stream); 923bbe7379dSSanyog Kale sdw_master_port_release(bus, stream->m_rt); 92489e59053SSanyog Kale stream->state = SDW_STREAM_RELEASED; 92589e59053SSanyog Kale kfree(stream->m_rt); 92689e59053SSanyog Kale stream->m_rt = NULL; 92789e59053SSanyog Kale 92889e59053SSanyog Kale mutex_unlock(&bus->bus_lock); 92989e59053SSanyog Kale 93089e59053SSanyog Kale return 0; 93189e59053SSanyog Kale } 93289e59053SSanyog Kale EXPORT_SYMBOL(sdw_stream_remove_master); 93389e59053SSanyog Kale 93489e59053SSanyog Kale /** 93589e59053SSanyog Kale * sdw_stream_remove_slave() - Remove slave from sdw_stream 93689e59053SSanyog Kale * 93789e59053SSanyog Kale * @slave: SDW Slave instance 93889e59053SSanyog Kale * @stream: SoundWire stream 93989e59053SSanyog Kale * 940bbe7379dSSanyog Kale * This removes and frees port_rt and slave_rt from a stream 94189e59053SSanyog Kale */ 94289e59053SSanyog Kale int sdw_stream_remove_slave(struct sdw_slave *slave, 94389e59053SSanyog Kale struct sdw_stream_runtime *stream) 94489e59053SSanyog Kale { 94589e59053SSanyog Kale mutex_lock(&slave->bus->bus_lock); 94689e59053SSanyog Kale 947bbe7379dSSanyog Kale sdw_slave_port_release(slave->bus, slave, stream); 94889e59053SSanyog Kale sdw_release_slave_stream(slave, stream); 94989e59053SSanyog Kale 95089e59053SSanyog Kale mutex_unlock(&slave->bus->bus_lock); 95189e59053SSanyog Kale 95289e59053SSanyog Kale return 0; 95389e59053SSanyog Kale } 95489e59053SSanyog Kale EXPORT_SYMBOL(sdw_stream_remove_slave); 95589e59053SSanyog Kale 95689e59053SSanyog Kale /** 95789e59053SSanyog Kale * sdw_config_stream() - Configure the allocated stream 95889e59053SSanyog Kale * 95989e59053SSanyog Kale * @dev: SDW device 96089e59053SSanyog Kale * @stream: SoundWire stream 96189e59053SSanyog Kale * @stream_config: Stream configuration for audio stream 96289e59053SSanyog Kale * @is_slave: is API called from Slave or Master 96389e59053SSanyog Kale * 96489e59053SSanyog Kale * This function is to be called with bus_lock held. 96589e59053SSanyog Kale */ 96689e59053SSanyog Kale static int sdw_config_stream(struct device *dev, 96789e59053SSanyog Kale struct sdw_stream_runtime *stream, 96889e59053SSanyog Kale struct sdw_stream_config *stream_config, bool is_slave) 96989e59053SSanyog Kale { 97089e59053SSanyog Kale /* 97189e59053SSanyog Kale * Update the stream rate, channel and bps based on data 97289e59053SSanyog Kale * source. For more than one data source (multilink), 97389e59053SSanyog Kale * match the rate, bps, stream type and increment number of channels. 97489e59053SSanyog Kale * 97589e59053SSanyog Kale * If rate/bps is zero, it means the values are not set, so skip 97689e59053SSanyog Kale * comparison and allow the value to be set and stored in stream 97789e59053SSanyog Kale */ 97889e59053SSanyog Kale if (stream->params.rate && 97989e59053SSanyog Kale stream->params.rate != stream_config->frame_rate) { 98089e59053SSanyog Kale dev_err(dev, "rate not matching, stream:%s", stream->name); 98189e59053SSanyog Kale return -EINVAL; 98289e59053SSanyog Kale } 98389e59053SSanyog Kale 98489e59053SSanyog Kale if (stream->params.bps && 98589e59053SSanyog Kale stream->params.bps != stream_config->bps) { 98689e59053SSanyog Kale dev_err(dev, "bps not matching, stream:%s", stream->name); 98789e59053SSanyog Kale return -EINVAL; 98889e59053SSanyog Kale } 98989e59053SSanyog Kale 99089e59053SSanyog Kale stream->type = stream_config->type; 99189e59053SSanyog Kale stream->params.rate = stream_config->frame_rate; 99289e59053SSanyog Kale stream->params.bps = stream_config->bps; 99389e59053SSanyog Kale 99489e59053SSanyog Kale /* TODO: Update this check during Device-device support */ 99589e59053SSanyog Kale if (is_slave) 99689e59053SSanyog Kale stream->params.ch_count += stream_config->ch_count; 99789e59053SSanyog Kale 99889e59053SSanyog Kale return 0; 99989e59053SSanyog Kale } 100089e59053SSanyog Kale 1001bbe7379dSSanyog Kale static int sdw_is_valid_port_range(struct device *dev, 1002bbe7379dSSanyog Kale struct sdw_port_runtime *p_rt) 1003bbe7379dSSanyog Kale { 1004bbe7379dSSanyog Kale if (!SDW_VALID_PORT_RANGE(p_rt->num)) { 1005bbe7379dSSanyog Kale dev_err(dev, 1006bbe7379dSSanyog Kale "SoundWire: Invalid port number :%d", p_rt->num); 1007bbe7379dSSanyog Kale return -EINVAL; 1008bbe7379dSSanyog Kale } 1009bbe7379dSSanyog Kale 1010bbe7379dSSanyog Kale return 0; 1011bbe7379dSSanyog Kale } 1012bbe7379dSSanyog Kale 1013bbe7379dSSanyog Kale static struct sdw_port_runtime *sdw_port_alloc(struct device *dev, 1014bbe7379dSSanyog Kale struct sdw_port_config *port_config, 1015bbe7379dSSanyog Kale int port_index) 1016bbe7379dSSanyog Kale { 1017bbe7379dSSanyog Kale struct sdw_port_runtime *p_rt; 1018bbe7379dSSanyog Kale 1019bbe7379dSSanyog Kale p_rt = kzalloc(sizeof(*p_rt), GFP_KERNEL); 1020bbe7379dSSanyog Kale if (!p_rt) 1021bbe7379dSSanyog Kale return NULL; 1022bbe7379dSSanyog Kale 1023bbe7379dSSanyog Kale p_rt->ch_mask = port_config[port_index].ch_mask; 1024bbe7379dSSanyog Kale p_rt->num = port_config[port_index].num; 1025bbe7379dSSanyog Kale 1026bbe7379dSSanyog Kale return p_rt; 1027bbe7379dSSanyog Kale } 1028bbe7379dSSanyog Kale 1029bbe7379dSSanyog Kale static int sdw_master_port_config(struct sdw_bus *bus, 1030bbe7379dSSanyog Kale struct sdw_master_runtime *m_rt, 1031bbe7379dSSanyog Kale struct sdw_port_config *port_config, 1032bbe7379dSSanyog Kale unsigned int num_ports) 1033bbe7379dSSanyog Kale { 1034bbe7379dSSanyog Kale struct sdw_port_runtime *p_rt; 1035bbe7379dSSanyog Kale int i; 1036bbe7379dSSanyog Kale 1037bbe7379dSSanyog Kale /* Iterate for number of ports to perform initialization */ 1038bbe7379dSSanyog Kale for (i = 0; i < num_ports; i++) { 1039bbe7379dSSanyog Kale p_rt = sdw_port_alloc(bus->dev, port_config, i); 1040bbe7379dSSanyog Kale if (!p_rt) 1041bbe7379dSSanyog Kale return -ENOMEM; 1042bbe7379dSSanyog Kale 1043bbe7379dSSanyog Kale /* 1044bbe7379dSSanyog Kale * TODO: Check port capabilities for requested 1045bbe7379dSSanyog Kale * configuration (audio mode support) 1046bbe7379dSSanyog Kale */ 1047bbe7379dSSanyog Kale 1048bbe7379dSSanyog Kale list_add_tail(&p_rt->port_node, &m_rt->port_list); 1049bbe7379dSSanyog Kale } 1050bbe7379dSSanyog Kale 1051bbe7379dSSanyog Kale return 0; 1052bbe7379dSSanyog Kale } 1053bbe7379dSSanyog Kale 1054bbe7379dSSanyog Kale static int sdw_slave_port_config(struct sdw_slave *slave, 1055bbe7379dSSanyog Kale struct sdw_slave_runtime *s_rt, 1056bbe7379dSSanyog Kale struct sdw_port_config *port_config, 1057bbe7379dSSanyog Kale unsigned int num_config) 1058bbe7379dSSanyog Kale { 1059bbe7379dSSanyog Kale struct sdw_port_runtime *p_rt; 1060bbe7379dSSanyog Kale int i, ret; 1061bbe7379dSSanyog Kale 1062bbe7379dSSanyog Kale /* Iterate for number of ports to perform initialization */ 1063bbe7379dSSanyog Kale for (i = 0; i < num_config; i++) { 1064bbe7379dSSanyog Kale p_rt = sdw_port_alloc(&slave->dev, port_config, i); 1065bbe7379dSSanyog Kale if (!p_rt) 1066bbe7379dSSanyog Kale return -ENOMEM; 1067bbe7379dSSanyog Kale 1068bbe7379dSSanyog Kale /* 1069bbe7379dSSanyog Kale * TODO: Check valid port range as defined by DisCo/ 1070bbe7379dSSanyog Kale * slave 1071bbe7379dSSanyog Kale */ 1072bbe7379dSSanyog Kale ret = sdw_is_valid_port_range(&slave->dev, p_rt); 1073bbe7379dSSanyog Kale if (ret < 0) { 1074bbe7379dSSanyog Kale kfree(p_rt); 1075bbe7379dSSanyog Kale return ret; 1076bbe7379dSSanyog Kale } 1077bbe7379dSSanyog Kale 1078bbe7379dSSanyog Kale /* 1079bbe7379dSSanyog Kale * TODO: Check port capabilities for requested 1080bbe7379dSSanyog Kale * configuration (audio mode support) 1081bbe7379dSSanyog Kale */ 1082bbe7379dSSanyog Kale 1083bbe7379dSSanyog Kale list_add_tail(&p_rt->port_node, &s_rt->port_list); 1084bbe7379dSSanyog Kale } 1085bbe7379dSSanyog Kale 1086bbe7379dSSanyog Kale return 0; 1087bbe7379dSSanyog Kale } 1088bbe7379dSSanyog Kale 108989e59053SSanyog Kale /** 109089e59053SSanyog Kale * sdw_stream_add_master() - Allocate and add master runtime to a stream 109189e59053SSanyog Kale * 109289e59053SSanyog Kale * @bus: SDW Bus instance 109389e59053SSanyog Kale * @stream_config: Stream configuration for audio stream 1094bbe7379dSSanyog Kale * @port_config: Port configuration for audio stream 1095bbe7379dSSanyog Kale * @num_ports: Number of ports 109689e59053SSanyog Kale * @stream: SoundWire stream 109789e59053SSanyog Kale */ 109889e59053SSanyog Kale int sdw_stream_add_master(struct sdw_bus *bus, 109989e59053SSanyog Kale struct sdw_stream_config *stream_config, 1100bbe7379dSSanyog Kale struct sdw_port_config *port_config, 1101bbe7379dSSanyog Kale unsigned int num_ports, 110289e59053SSanyog Kale struct sdw_stream_runtime *stream) 110389e59053SSanyog Kale { 110489e59053SSanyog Kale struct sdw_master_runtime *m_rt = NULL; 110589e59053SSanyog Kale int ret; 110689e59053SSanyog Kale 110789e59053SSanyog Kale mutex_lock(&bus->bus_lock); 110889e59053SSanyog Kale 110989e59053SSanyog Kale m_rt = sdw_alloc_master_rt(bus, stream_config, stream); 111089e59053SSanyog Kale if (!m_rt) { 111189e59053SSanyog Kale dev_err(bus->dev, 111289e59053SSanyog Kale "Master runtime config failed for stream:%s", 111389e59053SSanyog Kale stream->name); 111489e59053SSanyog Kale ret = -ENOMEM; 111589e59053SSanyog Kale goto error; 111689e59053SSanyog Kale } 111789e59053SSanyog Kale 111889e59053SSanyog Kale ret = sdw_config_stream(bus->dev, stream, stream_config, false); 111989e59053SSanyog Kale if (ret) 112089e59053SSanyog Kale goto stream_error; 112189e59053SSanyog Kale 1122bbe7379dSSanyog Kale ret = sdw_master_port_config(bus, m_rt, port_config, num_ports); 1123bbe7379dSSanyog Kale if (ret) 1124bbe7379dSSanyog Kale goto stream_error; 1125bbe7379dSSanyog Kale 112689e59053SSanyog Kale stream_error: 112789e59053SSanyog Kale sdw_release_master_stream(stream); 112889e59053SSanyog Kale error: 112989e59053SSanyog Kale mutex_unlock(&bus->bus_lock); 113089e59053SSanyog Kale return ret; 113189e59053SSanyog Kale } 113289e59053SSanyog Kale EXPORT_SYMBOL(sdw_stream_add_master); 113389e59053SSanyog Kale 113489e59053SSanyog Kale /** 113589e59053SSanyog Kale * sdw_stream_add_slave() - Allocate and add master/slave runtime to a stream 113689e59053SSanyog Kale * 113789e59053SSanyog Kale * @slave: SDW Slave instance 113889e59053SSanyog Kale * @stream_config: Stream configuration for audio stream 113989e59053SSanyog Kale * @stream: SoundWire stream 1140bbe7379dSSanyog Kale * @port_config: Port configuration for audio stream 1141bbe7379dSSanyog Kale * @num_ports: Number of ports 11420aebe40bSShreyas NC * 11430aebe40bSShreyas NC * It is expected that Slave is added before adding Master 11440aebe40bSShreyas NC * to the Stream. 11450aebe40bSShreyas NC * 114689e59053SSanyog Kale */ 114789e59053SSanyog Kale int sdw_stream_add_slave(struct sdw_slave *slave, 114889e59053SSanyog Kale struct sdw_stream_config *stream_config, 1149bbe7379dSSanyog Kale struct sdw_port_config *port_config, 1150bbe7379dSSanyog Kale unsigned int num_ports, 115189e59053SSanyog Kale struct sdw_stream_runtime *stream) 115289e59053SSanyog Kale { 115389e59053SSanyog Kale struct sdw_slave_runtime *s_rt; 115489e59053SSanyog Kale struct sdw_master_runtime *m_rt; 115589e59053SSanyog Kale int ret; 115689e59053SSanyog Kale 115789e59053SSanyog Kale mutex_lock(&slave->bus->bus_lock); 115889e59053SSanyog Kale 115989e59053SSanyog Kale /* 116089e59053SSanyog Kale * If this API is invoked by Slave first then m_rt is not valid. 116189e59053SSanyog Kale * So, allocate m_rt and add Slave to it. 116289e59053SSanyog Kale */ 116389e59053SSanyog Kale m_rt = sdw_alloc_master_rt(slave->bus, stream_config, stream); 116489e59053SSanyog Kale if (!m_rt) { 116589e59053SSanyog Kale dev_err(&slave->dev, 116689e59053SSanyog Kale "alloc master runtime failed for stream:%s", 116789e59053SSanyog Kale stream->name); 116889e59053SSanyog Kale ret = -ENOMEM; 116989e59053SSanyog Kale goto error; 117089e59053SSanyog Kale } 117189e59053SSanyog Kale 117289e59053SSanyog Kale s_rt = sdw_alloc_slave_rt(slave, stream_config, stream); 117389e59053SSanyog Kale if (!s_rt) { 117489e59053SSanyog Kale dev_err(&slave->dev, 117589e59053SSanyog Kale "Slave runtime config failed for stream:%s", 117689e59053SSanyog Kale stream->name); 117789e59053SSanyog Kale ret = -ENOMEM; 117889e59053SSanyog Kale goto stream_error; 117989e59053SSanyog Kale } 118089e59053SSanyog Kale 118189e59053SSanyog Kale ret = sdw_config_stream(&slave->dev, stream, stream_config, true); 118289e59053SSanyog Kale if (ret) 118389e59053SSanyog Kale goto stream_error; 118489e59053SSanyog Kale 118589e59053SSanyog Kale list_add_tail(&s_rt->m_rt_node, &m_rt->slave_rt_list); 118689e59053SSanyog Kale 1187bbe7379dSSanyog Kale ret = sdw_slave_port_config(slave, s_rt, port_config, num_ports); 1188bbe7379dSSanyog Kale if (ret) 1189bbe7379dSSanyog Kale goto stream_error; 1190bbe7379dSSanyog Kale 11910aebe40bSShreyas NC /* 11920aebe40bSShreyas NC * Change stream state to CONFIGURED on first Slave add. 11930aebe40bSShreyas NC * Bus is not aware of number of Slave(s) in a stream at this 11940aebe40bSShreyas NC * point so cannot depend on all Slave(s) to be added in order to 11950aebe40bSShreyas NC * change stream state to CONFIGURED. 11960aebe40bSShreyas NC */ 119789e59053SSanyog Kale stream->state = SDW_STREAM_CONFIGURED; 119889e59053SSanyog Kale goto error; 119989e59053SSanyog Kale 120089e59053SSanyog Kale stream_error: 120189e59053SSanyog Kale /* 120289e59053SSanyog Kale * we hit error so cleanup the stream, release all Slave(s) and 120389e59053SSanyog Kale * Master runtime 120489e59053SSanyog Kale */ 120589e59053SSanyog Kale sdw_release_master_stream(stream); 120689e59053SSanyog Kale error: 120789e59053SSanyog Kale mutex_unlock(&slave->bus->bus_lock); 120889e59053SSanyog Kale return ret; 120989e59053SSanyog Kale } 121089e59053SSanyog Kale EXPORT_SYMBOL(sdw_stream_add_slave); 1211f8101c74SSanyog Kale 1212f8101c74SSanyog Kale /** 1213f8101c74SSanyog Kale * sdw_get_slave_dpn_prop() - Get Slave port capabilities 1214f8101c74SSanyog Kale * 1215f8101c74SSanyog Kale * @slave: Slave handle 1216f8101c74SSanyog Kale * @direction: Data direction. 1217f8101c74SSanyog Kale * @port_num: Port number 1218f8101c74SSanyog Kale */ 1219f8101c74SSanyog Kale struct sdw_dpn_prop *sdw_get_slave_dpn_prop(struct sdw_slave *slave, 1220f8101c74SSanyog Kale enum sdw_data_direction direction, 1221f8101c74SSanyog Kale unsigned int port_num) 1222f8101c74SSanyog Kale { 1223f8101c74SSanyog Kale struct sdw_dpn_prop *dpn_prop; 1224f8101c74SSanyog Kale u8 num_ports; 1225f8101c74SSanyog Kale int i; 1226f8101c74SSanyog Kale 1227f8101c74SSanyog Kale if (direction == SDW_DATA_DIR_TX) { 1228f8101c74SSanyog Kale num_ports = hweight32(slave->prop.source_ports); 1229f8101c74SSanyog Kale dpn_prop = slave->prop.src_dpn_prop; 1230f8101c74SSanyog Kale } else { 1231f8101c74SSanyog Kale num_ports = hweight32(slave->prop.sink_ports); 1232f8101c74SSanyog Kale dpn_prop = slave->prop.sink_dpn_prop; 1233f8101c74SSanyog Kale } 1234f8101c74SSanyog Kale 1235f8101c74SSanyog Kale for (i = 0; i < num_ports; i++) { 1236f8101c74SSanyog Kale dpn_prop = &dpn_prop[i]; 1237f8101c74SSanyog Kale 1238f8101c74SSanyog Kale if (dpn_prop->num == port_num) 1239f8101c74SSanyog Kale return &dpn_prop[i]; 1240f8101c74SSanyog Kale } 1241f8101c74SSanyog Kale 1242f8101c74SSanyog Kale return NULL; 1243f8101c74SSanyog Kale } 12445c3eb9f7SSanyog Kale 12455c3eb9f7SSanyog Kale static int _sdw_prepare_stream(struct sdw_stream_runtime *stream) 12465c3eb9f7SSanyog Kale { 12475c3eb9f7SSanyog Kale struct sdw_master_runtime *m_rt = stream->m_rt; 12485c3eb9f7SSanyog Kale struct sdw_bus *bus = m_rt->bus; 12495c3eb9f7SSanyog Kale struct sdw_master_prop *prop = NULL; 12505c3eb9f7SSanyog Kale struct sdw_bus_params params; 12515c3eb9f7SSanyog Kale int ret; 12525c3eb9f7SSanyog Kale 12535c3eb9f7SSanyog Kale prop = &bus->prop; 12545c3eb9f7SSanyog Kale memcpy(¶ms, &bus->params, sizeof(params)); 12555c3eb9f7SSanyog Kale 12565c3eb9f7SSanyog Kale /* TODO: Support Asynchronous mode */ 12575c3eb9f7SSanyog Kale if ((prop->max_freq % stream->params.rate) != 0) { 12585c3eb9f7SSanyog Kale dev_err(bus->dev, "Async mode not supported"); 12595c3eb9f7SSanyog Kale return -EINVAL; 12605c3eb9f7SSanyog Kale } 12615c3eb9f7SSanyog Kale 12625c3eb9f7SSanyog Kale /* Increment cumulative bus bandwidth */ 12635c3eb9f7SSanyog Kale /* TODO: Update this during Device-Device support */ 12645c3eb9f7SSanyog Kale bus->params.bandwidth += m_rt->stream->params.rate * 12655c3eb9f7SSanyog Kale m_rt->ch_count * m_rt->stream->params.bps; 12665c3eb9f7SSanyog Kale 12675c3eb9f7SSanyog Kale /* Program params */ 12685c3eb9f7SSanyog Kale ret = sdw_program_params(bus); 12695c3eb9f7SSanyog Kale if (ret < 0) { 12705c3eb9f7SSanyog Kale dev_err(bus->dev, "Program params failed: %d", ret); 12715c3eb9f7SSanyog Kale goto restore_params; 12725c3eb9f7SSanyog Kale } 12735c3eb9f7SSanyog Kale 12745c3eb9f7SSanyog Kale ret = do_bank_switch(stream); 12755c3eb9f7SSanyog Kale if (ret < 0) { 12765c3eb9f7SSanyog Kale dev_err(bus->dev, "Bank switch failed: %d", ret); 12775c3eb9f7SSanyog Kale goto restore_params; 12785c3eb9f7SSanyog Kale } 12795c3eb9f7SSanyog Kale 12805c3eb9f7SSanyog Kale /* Prepare port(s) on the new clock configuration */ 12815c3eb9f7SSanyog Kale ret = sdw_prep_deprep_ports(m_rt, true); 12825c3eb9f7SSanyog Kale if (ret < 0) { 12835c3eb9f7SSanyog Kale dev_err(bus->dev, "Prepare port(s) failed ret = %d", 12845c3eb9f7SSanyog Kale ret); 12855c3eb9f7SSanyog Kale return ret; 12865c3eb9f7SSanyog Kale } 12875c3eb9f7SSanyog Kale 12885c3eb9f7SSanyog Kale stream->state = SDW_STREAM_PREPARED; 12895c3eb9f7SSanyog Kale 12905c3eb9f7SSanyog Kale return ret; 12915c3eb9f7SSanyog Kale 12925c3eb9f7SSanyog Kale restore_params: 12935c3eb9f7SSanyog Kale memcpy(&bus->params, ¶ms, sizeof(params)); 12945c3eb9f7SSanyog Kale return ret; 12955c3eb9f7SSanyog Kale } 12965c3eb9f7SSanyog Kale 12975c3eb9f7SSanyog Kale /** 12985c3eb9f7SSanyog Kale * sdw_prepare_stream() - Prepare SoundWire stream 12995c3eb9f7SSanyog Kale * 13005c3eb9f7SSanyog Kale * @stream: Soundwire stream 13015c3eb9f7SSanyog Kale * 130234962fb8SMauro Carvalho Chehab * Documentation/driver-api/soundwire/stream.rst explains this API in detail 13035c3eb9f7SSanyog Kale */ 13045c3eb9f7SSanyog Kale int sdw_prepare_stream(struct sdw_stream_runtime *stream) 13055c3eb9f7SSanyog Kale { 13065c3eb9f7SSanyog Kale int ret = 0; 13075c3eb9f7SSanyog Kale 13085c3eb9f7SSanyog Kale if (!stream) { 13095c3eb9f7SSanyog Kale pr_err("SoundWire: Handle not found for stream"); 13105c3eb9f7SSanyog Kale return -EINVAL; 13115c3eb9f7SSanyog Kale } 13125c3eb9f7SSanyog Kale 13135c3eb9f7SSanyog Kale mutex_lock(&stream->m_rt->bus->bus_lock); 13145c3eb9f7SSanyog Kale 13155c3eb9f7SSanyog Kale ret = _sdw_prepare_stream(stream); 13165c3eb9f7SSanyog Kale if (ret < 0) 13175c3eb9f7SSanyog Kale pr_err("Prepare for stream:%s failed: %d", stream->name, ret); 13185c3eb9f7SSanyog Kale 13195c3eb9f7SSanyog Kale mutex_unlock(&stream->m_rt->bus->bus_lock); 13205c3eb9f7SSanyog Kale return ret; 13215c3eb9f7SSanyog Kale } 13225c3eb9f7SSanyog Kale EXPORT_SYMBOL(sdw_prepare_stream); 13235c3eb9f7SSanyog Kale 13245c3eb9f7SSanyog Kale static int _sdw_enable_stream(struct sdw_stream_runtime *stream) 13255c3eb9f7SSanyog Kale { 13265c3eb9f7SSanyog Kale struct sdw_master_runtime *m_rt = stream->m_rt; 13275c3eb9f7SSanyog Kale struct sdw_bus *bus = m_rt->bus; 13285c3eb9f7SSanyog Kale int ret; 13295c3eb9f7SSanyog Kale 13305c3eb9f7SSanyog Kale /* Program params */ 13315c3eb9f7SSanyog Kale ret = sdw_program_params(bus); 13325c3eb9f7SSanyog Kale if (ret < 0) { 13335c3eb9f7SSanyog Kale dev_err(bus->dev, "Program params failed: %d", ret); 13345c3eb9f7SSanyog Kale return ret; 13355c3eb9f7SSanyog Kale } 13365c3eb9f7SSanyog Kale 13375c3eb9f7SSanyog Kale /* Enable port(s) */ 13385c3eb9f7SSanyog Kale ret = sdw_enable_disable_ports(m_rt, true); 13395c3eb9f7SSanyog Kale if (ret < 0) { 13405c3eb9f7SSanyog Kale dev_err(bus->dev, "Enable port(s) failed ret: %d", ret); 13415c3eb9f7SSanyog Kale return ret; 13425c3eb9f7SSanyog Kale } 13435c3eb9f7SSanyog Kale 13445c3eb9f7SSanyog Kale ret = do_bank_switch(stream); 13455c3eb9f7SSanyog Kale if (ret < 0) { 13465c3eb9f7SSanyog Kale dev_err(bus->dev, "Bank switch failed: %d", ret); 13475c3eb9f7SSanyog Kale return ret; 13485c3eb9f7SSanyog Kale } 13495c3eb9f7SSanyog Kale 13505c3eb9f7SSanyog Kale stream->state = SDW_STREAM_ENABLED; 13515c3eb9f7SSanyog Kale return 0; 13525c3eb9f7SSanyog Kale } 13535c3eb9f7SSanyog Kale 13545c3eb9f7SSanyog Kale /** 13555c3eb9f7SSanyog Kale * sdw_enable_stream() - Enable SoundWire stream 13565c3eb9f7SSanyog Kale * 13575c3eb9f7SSanyog Kale * @stream: Soundwire stream 13585c3eb9f7SSanyog Kale * 135934962fb8SMauro Carvalho Chehab * Documentation/driver-api/soundwire/stream.rst explains this API in detail 13605c3eb9f7SSanyog Kale */ 13615c3eb9f7SSanyog Kale int sdw_enable_stream(struct sdw_stream_runtime *stream) 13625c3eb9f7SSanyog Kale { 13635c3eb9f7SSanyog Kale int ret = 0; 13645c3eb9f7SSanyog Kale 13655c3eb9f7SSanyog Kale if (!stream) { 13665c3eb9f7SSanyog Kale pr_err("SoundWire: Handle not found for stream"); 13675c3eb9f7SSanyog Kale return -EINVAL; 13685c3eb9f7SSanyog Kale } 13695c3eb9f7SSanyog Kale 13705c3eb9f7SSanyog Kale mutex_lock(&stream->m_rt->bus->bus_lock); 13715c3eb9f7SSanyog Kale 13725c3eb9f7SSanyog Kale ret = _sdw_enable_stream(stream); 13735c3eb9f7SSanyog Kale if (ret < 0) 13745c3eb9f7SSanyog Kale pr_err("Enable for stream:%s failed: %d", stream->name, ret); 13755c3eb9f7SSanyog Kale 13765c3eb9f7SSanyog Kale mutex_unlock(&stream->m_rt->bus->bus_lock); 13775c3eb9f7SSanyog Kale return ret; 13785c3eb9f7SSanyog Kale } 13795c3eb9f7SSanyog Kale EXPORT_SYMBOL(sdw_enable_stream); 13805c3eb9f7SSanyog Kale 13815c3eb9f7SSanyog Kale static int _sdw_disable_stream(struct sdw_stream_runtime *stream) 13825c3eb9f7SSanyog Kale { 13835c3eb9f7SSanyog Kale struct sdw_master_runtime *m_rt = stream->m_rt; 13845c3eb9f7SSanyog Kale struct sdw_bus *bus = m_rt->bus; 13855c3eb9f7SSanyog Kale int ret; 13865c3eb9f7SSanyog Kale 13875c3eb9f7SSanyog Kale /* Disable port(s) */ 13885c3eb9f7SSanyog Kale ret = sdw_enable_disable_ports(m_rt, false); 13895c3eb9f7SSanyog Kale if (ret < 0) { 13905c3eb9f7SSanyog Kale dev_err(bus->dev, "Disable port(s) failed: %d", ret); 13915c3eb9f7SSanyog Kale return ret; 13925c3eb9f7SSanyog Kale } 13935c3eb9f7SSanyog Kale 13945c3eb9f7SSanyog Kale stream->state = SDW_STREAM_DISABLED; 13955c3eb9f7SSanyog Kale 13965c3eb9f7SSanyog Kale /* Program params */ 13975c3eb9f7SSanyog Kale ret = sdw_program_params(bus); 13985c3eb9f7SSanyog Kale if (ret < 0) { 13995c3eb9f7SSanyog Kale dev_err(bus->dev, "Program params failed: %d", ret); 14005c3eb9f7SSanyog Kale return ret; 14015c3eb9f7SSanyog Kale } 14025c3eb9f7SSanyog Kale 14035c3eb9f7SSanyog Kale return do_bank_switch(stream); 14045c3eb9f7SSanyog Kale } 14055c3eb9f7SSanyog Kale 14065c3eb9f7SSanyog Kale /** 14075c3eb9f7SSanyog Kale * sdw_disable_stream() - Disable SoundWire stream 14085c3eb9f7SSanyog Kale * 14095c3eb9f7SSanyog Kale * @stream: Soundwire stream 14105c3eb9f7SSanyog Kale * 141134962fb8SMauro Carvalho Chehab * Documentation/driver-api/soundwire/stream.rst explains this API in detail 14125c3eb9f7SSanyog Kale */ 14135c3eb9f7SSanyog Kale int sdw_disable_stream(struct sdw_stream_runtime *stream) 14145c3eb9f7SSanyog Kale { 14155c3eb9f7SSanyog Kale int ret = 0; 14165c3eb9f7SSanyog Kale 14175c3eb9f7SSanyog Kale if (!stream) { 14185c3eb9f7SSanyog Kale pr_err("SoundWire: Handle not found for stream"); 14195c3eb9f7SSanyog Kale return -EINVAL; 14205c3eb9f7SSanyog Kale } 14215c3eb9f7SSanyog Kale 14225c3eb9f7SSanyog Kale mutex_lock(&stream->m_rt->bus->bus_lock); 14235c3eb9f7SSanyog Kale 14245c3eb9f7SSanyog Kale ret = _sdw_disable_stream(stream); 14255c3eb9f7SSanyog Kale if (ret < 0) 14265c3eb9f7SSanyog Kale pr_err("Disable for stream:%s failed: %d", stream->name, ret); 14275c3eb9f7SSanyog Kale 14285c3eb9f7SSanyog Kale mutex_unlock(&stream->m_rt->bus->bus_lock); 14295c3eb9f7SSanyog Kale return ret; 14305c3eb9f7SSanyog Kale } 14315c3eb9f7SSanyog Kale EXPORT_SYMBOL(sdw_disable_stream); 14325c3eb9f7SSanyog Kale 14335c3eb9f7SSanyog Kale static int _sdw_deprepare_stream(struct sdw_stream_runtime *stream) 14345c3eb9f7SSanyog Kale { 14355c3eb9f7SSanyog Kale struct sdw_master_runtime *m_rt = stream->m_rt; 14365c3eb9f7SSanyog Kale struct sdw_bus *bus = m_rt->bus; 14375c3eb9f7SSanyog Kale int ret = 0; 14385c3eb9f7SSanyog Kale 14395c3eb9f7SSanyog Kale /* De-prepare port(s) */ 14405c3eb9f7SSanyog Kale ret = sdw_prep_deprep_ports(m_rt, false); 14415c3eb9f7SSanyog Kale if (ret < 0) { 14425c3eb9f7SSanyog Kale dev_err(bus->dev, "De-prepare port(s) failed: %d", ret); 14435c3eb9f7SSanyog Kale return ret; 14445c3eb9f7SSanyog Kale } 14455c3eb9f7SSanyog Kale 14465c3eb9f7SSanyog Kale stream->state = SDW_STREAM_DEPREPARED; 14475c3eb9f7SSanyog Kale 14485c3eb9f7SSanyog Kale /* TODO: Update this during Device-Device support */ 14495c3eb9f7SSanyog Kale bus->params.bandwidth -= m_rt->stream->params.rate * 14505c3eb9f7SSanyog Kale m_rt->ch_count * m_rt->stream->params.bps; 14515c3eb9f7SSanyog Kale 14525c3eb9f7SSanyog Kale /* Program params */ 14535c3eb9f7SSanyog Kale ret = sdw_program_params(bus); 14545c3eb9f7SSanyog Kale if (ret < 0) { 14555c3eb9f7SSanyog Kale dev_err(bus->dev, "Program params failed: %d", ret); 14565c3eb9f7SSanyog Kale return ret; 14575c3eb9f7SSanyog Kale } 14585c3eb9f7SSanyog Kale 14595c3eb9f7SSanyog Kale return do_bank_switch(stream); 14605c3eb9f7SSanyog Kale } 14615c3eb9f7SSanyog Kale 14625c3eb9f7SSanyog Kale /** 14635c3eb9f7SSanyog Kale * sdw_deprepare_stream() - Deprepare SoundWire stream 14645c3eb9f7SSanyog Kale * 14655c3eb9f7SSanyog Kale * @stream: Soundwire stream 14665c3eb9f7SSanyog Kale * 146734962fb8SMauro Carvalho Chehab * Documentation/driver-api/soundwire/stream.rst explains this API in detail 14685c3eb9f7SSanyog Kale */ 14695c3eb9f7SSanyog Kale int sdw_deprepare_stream(struct sdw_stream_runtime *stream) 14705c3eb9f7SSanyog Kale { 14715c3eb9f7SSanyog Kale int ret = 0; 14725c3eb9f7SSanyog Kale 14735c3eb9f7SSanyog Kale if (!stream) { 14745c3eb9f7SSanyog Kale pr_err("SoundWire: Handle not found for stream"); 14755c3eb9f7SSanyog Kale return -EINVAL; 14765c3eb9f7SSanyog Kale } 14775c3eb9f7SSanyog Kale 14785c3eb9f7SSanyog Kale mutex_lock(&stream->m_rt->bus->bus_lock); 14795c3eb9f7SSanyog Kale 14805c3eb9f7SSanyog Kale ret = _sdw_deprepare_stream(stream); 14815c3eb9f7SSanyog Kale if (ret < 0) 14825c3eb9f7SSanyog Kale pr_err("De-prepare for stream:%d failed: %d", ret, ret); 14835c3eb9f7SSanyog Kale 14845c3eb9f7SSanyog Kale mutex_unlock(&stream->m_rt->bus->bus_lock); 14855c3eb9f7SSanyog Kale return ret; 14865c3eb9f7SSanyog Kale } 14875c3eb9f7SSanyog Kale EXPORT_SYMBOL(sdw_deprepare_stream); 1488