
On 4/5/18 11:48 AM, Vinod Koul wrote:
From: Sanyog Kale sanyog.r.kale@intel.com
Master and Slave port registers need to be programmed for each port used in a stream. Add the helpers for port register programming.
Signed-off-by: Sanyog Kale sanyog.r.kale@intel.com Signed-off-by: Vinod Koul vinod.koul@intel.com Signed-off-by: Shreyas NC shreyas.nc@intel.com
drivers/soundwire/bus.h | 4 + drivers/soundwire/stream.c | 262 ++++++++++++++++++++++++++++++++++++++++++ include/linux/soundwire/sdw.h | 47 +++++++- 3 files changed, 312 insertions(+), 1 deletion(-)
diff --git a/drivers/soundwire/bus.h b/drivers/soundwire/bus.h index 2e834a8038ed..33dc31c8f992 100644 --- a/drivers/soundwire/bus.h +++ b/drivers/soundwire/bus.h @@ -106,6 +106,10 @@ struct sdw_master_runtime { struct list_head bus_node; };
+struct sdw_dpn_prop *sdw_get_slave_dpn_prop(struct sdw_slave *slave,
enum sdw_data_direction direction,
unsigned int port_num);
- int sdw_transfer(struct sdw_bus *bus, struct sdw_msg *msg); int sdw_transfer_defer(struct sdw_bus *bus, struct sdw_msg *msg, struct sdw_defer *defer);
diff --git a/drivers/soundwire/stream.c b/drivers/soundwire/stream.c index 4b10f07b3e9e..61417a4decc5 100644 --- a/drivers/soundwire/stream.c +++ b/drivers/soundwire/stream.c @@ -11,9 +11,238 @@ #include <linux/module.h> #include <linux/mod_devicetable.h> #include <linux/slab.h> +#include <linux/soundwire/sdw_registers.h> #include <linux/soundwire/sdw.h> #include "bus.h"
+static int _sdw_program_slave_port_params(struct sdw_bus *bus,
struct sdw_slave *slave,
struct sdw_transport_params *t_params,
enum sdw_dpn_type type)
+{
- u32 addr1, addr2, addr3, addr4;
- int ret;
- u8 wbuf;
- if (bus->params.next_bank) {
addr1 = SDW_DPN_OFFSETCTRL2_B1(t_params->port_num);
addr2 = SDW_DPN_BLOCKCTRL3_B1(t_params->port_num);
addr3 = SDW_DPN_SAMPLECTRL2_B1(t_params->port_num);
addr4 = SDW_DPN_HCTRL_B1(t_params->port_num);
- } else {
addr1 = SDW_DPN_OFFSETCTRL2_B0(t_params->port_num);
addr2 = SDW_DPN_BLOCKCTRL3_B0(t_params->port_num);
addr3 = SDW_DPN_SAMPLECTRL2_B0(t_params->port_num);
addr4 = SDW_DPN_HCTRL_B0(t_params->port_num);
- }
- /* Program DPN_OffsetCtrl2 registers */
- ret = sdw_write(slave, addr1, t_params->offset2);
- if (ret < 0) {
dev_err(bus->dev, "DPN_OffsetCtrl2 register write failed");
return ret;
- }
- /* Program DPN_BlockCtrl3 register */
- ret = sdw_write(slave, addr2, t_params->blk_pkg_mode);
- if (ret < 0) {
dev_err(bus->dev, "DPN_BlockCtrl3 register write failed");
return ret;
- }
- /*
* Data ports are FULL, SIMPLE and REDUCED. This function handles
* FULL and REDUCED only and and beyond this point only FULL is
* handled, so bail out if we are not FULL data port type
*/
- if (type != SDW_DPN_FULL)
return ret;
- /* Program DPN_SampleCtrl2 register */
- wbuf = ((t_params->sample_interval - 1) &
SDW_DPN_SAMPLECTRL_HIGH) >>
SDW_REG_SHIFT(SDW_DPN_SAMPLECTRL_HIGH);
wbuf = t_params->sample_interval - 1; wbuf &= SDW_DPN_SAMPLECTRL_HIGH); wbuf >>= SDW_REG_SHIFT(SDW_DPN_SAMPLECTRL_HIGH);
same lines of code, simpler to read?
- ret = sdw_write(slave, addr3, wbuf);
- if (ret < 0) {
dev_err(bus->dev, "DPN_SampleCtrl2 register write failed");
return ret;
- }
- /* Program DPN_HCtrl register */
- wbuf = (t_params->hstop | (t_params->hstart <<
SDW_REG_SHIFT(SDW_DPN_HCTRL_HSTART)));
eyesore again.
- ret = sdw_write(slave, addr4, wbuf);
- if (ret < 0)
dev_err(bus->dev, "DPN_HCtrl register write failed");
- return ret;
+}
+static int sdw_program_slave_port_params(struct sdw_bus *bus,
struct sdw_slave_runtime *s_rt,
struct sdw_port_runtime *p_rt)
+{
- struct sdw_transport_params *t_params = &p_rt->transport_params;
- struct sdw_port_params *p_params = &p_rt->port_params;
- struct sdw_slave_prop *slave_prop = &s_rt->slave->prop;
- u32 addr1, addr2, addr3, addr4, addr5, addr6;
- struct sdw_dpn_prop *dpn_prop;
- int ret;
- u8 wbuf;
- dpn_prop = sdw_get_slave_dpn_prop(s_rt->slave,
s_rt->direction,
t_params->port_num);
- if (!dpn_prop)
return -EINVAL;
- addr1 = SDW_DPN_PORTCTRL(t_params->port_num);
- addr2 = SDW_DPN_BLOCKCTRL1(t_params->port_num);
- if (bus->params.next_bank) {
addr3 = SDW_DPN_SAMPLECTRL1_B1(t_params->port_num);
addr4 = SDW_DPN_OFFSETCTRL1_B1(t_params->port_num);
addr5 = SDW_DPN_BLOCKCTRL2_B1(t_params->port_num);
addr6 = SDW_DPN_LANECTRL_B1(t_params->port_num);
- } else {
addr3 = SDW_DPN_SAMPLECTRL1_B0(t_params->port_num);
addr4 = SDW_DPN_OFFSETCTRL1_B0(t_params->port_num);
addr5 = SDW_DPN_BLOCKCTRL2_B0(t_params->port_num);
addr6 = SDW_DPN_LANECTRL_B0(t_params->port_num);
- }
- /* Program DPN_PortCtrl register */
- wbuf = p_params->data_mode << SDW_REG_SHIFT(SDW_DPN_PORTCTRL_DATAMODE);
- wbuf |= p_params->flow_mode;
- ret = sdw_update(s_rt->slave, addr1, 0xF, wbuf);
- if (ret < 0) {
dev_err(&s_rt->slave->dev,
"DPN_PortCtrl register write failed for port %d",
t_params->port_num);
return ret;
- }
- /* Program DPN_BlockCtrl1 register */
- ret = sdw_write(s_rt->slave, addr2, (p_params->bps - 1));
- if (ret < 0) {
dev_err(&s_rt->slave->dev,
"DPN_BlockCtrl1 register write failed for port %d",
t_params->port_num);
return ret;
- }
- /* Program DPN_SampleCtrl1 register */
- wbuf = (t_params->sample_interval - 1) & SDW_DPN_SAMPLECTRL_LOW;
- ret = sdw_write(s_rt->slave, addr3, wbuf);
- if (ret < 0) {
dev_err(&s_rt->slave->dev,
"DPN_SampleCtrl1 register write failed for port %d",
t_params->port_num);
return ret;
- }
- /* Program DPN_OffsetCtrl1 registers */
- ret = sdw_write(s_rt->slave, addr4, t_params->offset1);
- if (ret < 0) {
dev_err(&s_rt->slave->dev,
"DPN_OffsetCtrl1 register write failed for port %d",
t_params->port_num);
return ret;
- }
- /* Program DPN_BlockCtrl2 register*/
- if (t_params->blk_grp_ctrl_valid) {
ret = sdw_write(s_rt->slave, addr5, t_params->blk_grp_ctrl);
if (ret < 0) {
dev_err(&s_rt->slave->dev,
"DPN_BlockCtrl2 reg write failed for port %d",
t_params->port_num);
return ret;
}
- }
- /* program DPN_LaneCtrl register */
- if (slave_prop->lane_control_support) {
ret = sdw_write(s_rt->slave, addr6, t_params->lane_ctrl);
if (ret < 0) {
dev_err(&s_rt->slave->dev,
"DPN_LaneCtrl register write failed for port %d",
t_params->port_num);
return ret;
}
- }
- if (dpn_prop->type != SDW_DPN_SIMPLE) {
ret = _sdw_program_slave_port_params(bus, s_rt->slave,
t_params, dpn_prop->type);
if (ret < 0)
dev_err(&s_rt->slave->dev,
"Transport reg write failed for port: %d",
t_params->port_num);
- }
- return ret;
+}
+static int sdw_program_master_port_params(struct sdw_bus *bus,
struct sdw_port_runtime *p_rt)
+{
- int ret;
- /*
* we need to set transport and port parameters for the port.
* Transport parameters refers to the smaple interval, offsets and
* hstart/stop etc of the data. Port parameters refers to word
* length, flow mode etc of the port
*/
- ret = bus->port_ops->dpn_set_port_transport_params(bus,
&p_rt->transport_params,
bus->params.next_bank);
- if (ret < 0)
return ret;
- return bus->port_ops->dpn_set_port_params(bus,
&p_rt->port_params,
bus->params.next_bank);
+}
+/**
- sdw_program_port_params: Programs transport parameters of Master(s)
- and Slave(s)
- @m_rt: Master stream runtime
- */
+static int sdw_program_port_params(struct sdw_master_runtime *m_rt) +{
- struct sdw_slave_runtime *s_rt = NULL;
- struct sdw_bus *bus = m_rt->bus;
- struct sdw_port_runtime *p_rt;
- int ret = 0;
- /* Program transport & port parameters for Slave(s) */
- list_for_each_entry(s_rt, &m_rt->slave_rt_list, m_rt_node) {
list_for_each_entry(p_rt, &s_rt->port_list, port_node) {
ret = sdw_program_slave_port_params(bus, s_rt, p_rt);
if (ret < 0)
return ret;
}
- }
- /* Program transport & port parameters for Master(s) */
- list_for_each_entry(p_rt, &m_rt->port_list, port_node) {
ret = sdw_program_master_port_params(bus, p_rt);
if (ret < 0)
return ret;
- }
- return 0;
+}
- /**
- sdw_release_stream: Free the assigned stream runtime
@@ -499,3 +728,36 @@ int sdw_stream_add_slave(struct sdw_slave *slave, return ret; } EXPORT_SYMBOL(sdw_stream_add_slave);
+/**
- sdw_get_slave_dpn_prop: Get Slave port capabilities
- @slave: Slave handle
- @direction: Data direction.
- @port_num: Port number
- */
+struct sdw_dpn_prop *sdw_get_slave_dpn_prop(struct sdw_slave *slave,
enum sdw_data_direction direction,
unsigned int port_num)
+{
- struct sdw_dpn_prop *dpn_prop;
- u8 num_ports;
- int i;
- if (direction == SDW_DATA_DIR_TX) {
num_ports = hweight32(slave->prop.source_ports);
dpn_prop = slave->prop.src_dpn_prop;
- } else {
num_ports = hweight32(slave->prop.sink_ports);
dpn_prop = slave->prop.sink_dpn_prop;
- }
- for (i = 0; i < num_ports; i++) {
dpn_prop = &dpn_prop[i];
if (dpn_prop->num == port_num)
return &dpn_prop[i];
- }
- return NULL;
+} diff --git a/include/linux/soundwire/sdw.h b/include/linux/soundwire/sdw.h index 228fdbf506fe..f2b952148e1a 100644 --- a/include/linux/soundwire/sdw.h +++ b/include/linux/soundwire/sdw.h @@ -367,7 +367,30 @@ struct sdw_slave_intr_status { };
/**
- struct sdw_slave_ops - Slave driver callback ops
- sdw_reg_bank - SoundWire register banks
- @SDW_BANK0: Soundwire register bank 0
- @SDW_BANK1: Soundwire register bank 1
- */
+enum sdw_reg_bank {
- SDW_BANK0,
- SDW_BANK1,
+};
+/**
- struct sdw_bus_params: Structure holding bus configuration
- @curr_bank: Current bank in use (BANK0/BANK1)
- @next_bank: Next bank to use (BANK0/BANK1). next_bank will always be
- set to !curr_bank
- */
+struct sdw_bus_params {
- enum sdw_reg_bank curr_bank;
- enum sdw_reg_bank next_bank;
+};
+/**
- struct sdw_slave_ops: Slave driver callback ops
- @read_prop: Read Slave properties
- @interrupt_callback: Device interrupt notification (invoked in thread
- context)
@@ -482,6 +505,24 @@ struct sdw_transport_params { unsigned int lane_ctrl; };
+/**
- struct sdw_master_port_ops: Callback functions from bus to Master
- driver to set Master Data ports.
- @dpn_set_port_params: Set the Port parameters for the Master Port.
- Mandatory callback
- @dpn_set_port_transport_params: Set transport parameters for the Master
- Port. Mandatory callback
- */
+struct sdw_master_port_ops {
- int (*dpn_set_port_params)(struct sdw_bus *bus,
struct sdw_port_params *port_params,
unsigned int bank);
- int (*dpn_set_port_transport_params)(struct sdw_bus *bus,
struct sdw_transport_params *transport_params,
enum sdw_reg_bank bank);
+};
struct sdw_msg;
/**
@@ -525,6 +566,8 @@ struct sdw_master_ops {
- @bus_lock: bus lock
- @msg_lock: message lock
- @ops: Master callback ops
- @port_ops: Master port callback ops
- @params: Current bus parameters
- @prop: Master properties
- @m_rt_list: List of Master instance of all stream(s) running on Bus. This
- is used to compute and program bus bandwidth, clock, frame shape,
@@ -540,6 +583,8 @@ struct sdw_bus { struct mutex bus_lock; struct mutex msg_lock; const struct sdw_master_ops *ops;
- const struct sdw_master_port_ops *port_ops;
- struct sdw_bus_params params; struct sdw_master_prop prop; struct list_head m_rt_list; struct sdw_defer defer_msg;