Commit 4cb1a880 authored by Greg Kroah-Hartman's avatar Greg Kroah-Hartman

Merge tag 'soundwire-5.10-rc1' of...

Merge tag 'soundwire-5.10-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/vkoul/soundwire into char-misc-next

Vinod writes:

soundwire updates for 5.10-rc1

This round of update includes:
 - Generic bandwidth allocation algorithm from Intel folks
 - PM support for Intel chipsets
 - Updates to Intel drivers which makes sdw usable on latest laptops
 - Support for MMIO SDW controllers found in QC chipsets
 - Update to subsystem to use helpers in bitfield.h to manage register
   bits

* tag 'soundwire-5.10-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/vkoul/soundwire: (66 commits)
  soundwire: sysfs: add slave status and device number before probe
  soundwire: bus: add enumerated Slave device to device list
  soundwire: remove an unnecessary NULL check
  soundwire: cadence: add data port test fail interrupt
  soundwire: intel: enable test modes
  soundwire: enable Data Port test modes
  soundwire: intel: use {u32|u16}p_replace_bits
  soundwire: cadence: use u32p_replace_bits
  soundwire: qcom: get max rows and cols info from compatible
  soundwire: qcom: add support to block packing mode
  soundwire: qcom: clear BIT FIELDs before value set.
  soundwire: Add generic bandwidth allocation algorithm
  soundwire: cadence: add parity error injection through debugfs
  soundwire: bus: export broadcast read/write capability for tests
  ASoC: codecs: realtek-soundwire: ignore initial PARITY errors
  soundwire: bus: use quirk to filter out invalid parity errors
  soundwire: slave: add first_interrupt_done status
  soundwire: bus: filter-out unwanted interrupt reports
  ASoC/soundwire: bus: use property to set interrupt masks
  soundwire: qcom: fix SLIBMUS/SLIMBUS typo
  ...
parents c471bf4b 0173f525
What: /sys/bus/soundwire/devices/sdw:.../status
/sys/bus/soundwire/devices/sdw:.../device_number
Date: September 2020
Contact: Pierre-Louis Bossart <pierre-louis.bossart@linux.intel.com>
Bard Liao <yung-chuan.liao@linux.intel.com>
Vinod Koul <vkoul@kernel.org>
Description: SoundWire Slave status
These properties report the Slave status, e.g. if it
is UNATTACHED or not, and in the latter case show the
device_number. This status information is useful to
detect devices exposed by platform firmware but not
physically present on the bus, and conversely devices
not exposed in platform firmware but enumerated.
What: /sys/bus/soundwire/devices/sdw:.../dev-properties/mipi_revision
/sys/bus/soundwire/devices/sdw:.../dev-properties/wake_capable
/sys/bus/soundwire/devices/sdw:.../dev-properties/test_mode_capable
......
......@@ -11,6 +11,7 @@ board specific bus parameters.
Example:
"qcom,soundwire-v1.3.0"
"qcom,soundwire-v1.5.0"
"qcom,soundwire-v1.5.1"
"qcom,soundwire-v1.6.0"
- reg:
Usage: required
......
......@@ -24,6 +24,7 @@ config SOUNDWIRE_CADENCE
config SOUNDWIRE_INTEL
tristate "Intel SoundWire Master driver"
select SOUNDWIRE_CADENCE
select SOUNDWIRE_GENERIC_ALLOCATION
depends on ACPI && SND_SOC
help
SoundWire Intel Master driver.
......@@ -33,11 +34,15 @@ config SOUNDWIRE_INTEL
config SOUNDWIRE_QCOM
tristate "Qualcomm SoundWire Master driver"
depends on SLIMBUS
imply SLIMBUS
depends on SND_SOC
help
SoundWire Qualcomm Master driver.
If you have an Qualcomm platform which has a SoundWire Master then
enable this config option to get the SoundWire support for that
device
config SOUNDWIRE_GENERIC_ALLOCATION
tristate
endif
......@@ -8,6 +8,9 @@ soundwire-bus-y := bus_type.o bus.o master.o slave.o mipi_disco.o stream.o \
sysfs_slave.o sysfs_slave_dpn.o
obj-$(CONFIG_SOUNDWIRE) += soundwire-bus.o
soundwire-generic-allocation-objs := generic_bandwidth_allocation.o
obj-$(CONFIG_SOUNDWIRE_GENERIC_ALLOCATION) += soundwire-generic-allocation.o
ifdef CONFIG_DEBUG_FS
soundwire-bus-y += debugfs.o
endif
......
......@@ -61,6 +61,12 @@ int sdw_bus_master_add(struct sdw_bus *bus, struct device *parent,
return -EINVAL;
}
if (!bus->compute_params) {
dev_err(bus->dev,
"Bandwidth allocation not configured, compute_params no set\n");
return -EINVAL;
}
mutex_init(&bus->msg_lock);
mutex_init(&bus->bus_lock);
INIT_LIST_HEAD(&bus->slaves);
......@@ -255,6 +261,21 @@ static int sdw_reset_page(struct sdw_bus *bus, u16 dev_num)
return ret;
}
static int sdw_transfer_unlocked(struct sdw_bus *bus, struct sdw_msg *msg)
{
int ret;
ret = do_transfer(bus, msg);
if (ret != 0 && ret != -ENODATA)
dev_err(bus->dev, "trf on Slave %d failed:%d\n",
msg->dev_num, ret);
if (msg->page)
sdw_reset_page(bus, msg->dev_num);
return ret;
}
/**
* sdw_transfer() - Synchronous transfer message to a SDW Slave device
* @bus: SDW bus
......@@ -266,13 +287,7 @@ int sdw_transfer(struct sdw_bus *bus, struct sdw_msg *msg)
mutex_lock(&bus->msg_lock);
ret = do_transfer(bus, msg);
if (ret != 0 && ret != -ENODATA)
dev_err(bus->dev, "trf on Slave %d failed:%d\n",
msg->dev_num, ret);
if (msg->page)
sdw_reset_page(bus, msg->dev_num);
ret = sdw_transfer_unlocked(bus, msg);
mutex_unlock(&bus->msg_lock);
......@@ -347,8 +362,8 @@ int sdw_fill_msg(struct sdw_msg *msg, struct sdw_slave *slave,
return -EINVAL;
}
msg->addr_page1 = (addr >> SDW_REG_SHIFT(SDW_SCP_ADDRPAGE1_MASK));
msg->addr_page2 = (addr >> SDW_REG_SHIFT(SDW_SCP_ADDRPAGE2_MASK));
msg->addr_page1 = FIELD_GET(SDW_SCP_ADDRPAGE1_MASK, addr);
msg->addr_page2 = FIELD_GET(SDW_SCP_ADDRPAGE2_MASK, addr);
msg->addr |= BIT(15);
msg->page = true;
......@@ -428,6 +443,39 @@ sdw_bwrite_no_pm(struct sdw_bus *bus, u16 dev_num, u32 addr, u8 value)
return sdw_transfer(bus, &msg);
}
int sdw_bread_no_pm_unlocked(struct sdw_bus *bus, u16 dev_num, u32 addr)
{
struct sdw_msg msg;
u8 buf;
int ret;
ret = sdw_fill_msg(&msg, NULL, addr, 1, dev_num,
SDW_MSG_FLAG_READ, &buf);
if (ret)
return ret;
ret = sdw_transfer_unlocked(bus, &msg);
if (ret < 0)
return ret;
return buf;
}
EXPORT_SYMBOL(sdw_bread_no_pm_unlocked);
int sdw_bwrite_no_pm_unlocked(struct sdw_bus *bus, u16 dev_num, u32 addr, u8 value)
{
struct sdw_msg msg;
int ret;
ret = sdw_fill_msg(&msg, NULL, addr, 1, dev_num,
SDW_MSG_FLAG_WRITE, &value);
if (ret)
return ret;
return sdw_transfer_unlocked(bus, &msg);
}
EXPORT_SYMBOL(sdw_bwrite_no_pm_unlocked);
static int
sdw_read_no_pm(struct sdw_slave *slave, u32 addr)
{
......@@ -699,6 +747,15 @@ static int sdw_program_device_num(struct sdw_bus *bus)
if (!found) {
/* TODO: Park this device in Group 13 */
/*
* add Slave device even if there is no platform
* firmware description. There will be no driver probe
* but the user/integration will be able to see the
* device, enumeration status and device number in sysfs
*/
sdw_slave_add(bus, &id, NULL);
dev_err(bus->dev, "Slave Entry not found\n");
}
......@@ -1051,6 +1108,12 @@ int sdw_configure_dpn_intr(struct sdw_slave *slave,
int ret;
u8 val = 0;
if (slave->bus->params.s_data_mode != SDW_PORT_DATA_MODE_NORMAL) {
dev_dbg(&slave->dev, "TEST FAIL interrupt %s\n",
enable ? "on" : "off");
mask |= SDW_DPN_INT_TEST_FAIL;
}
addr = SDW_DPN_INTMASK(port);
/* Set/Clear port ready interrupt mask */
......@@ -1184,13 +1247,13 @@ static int sdw_initialize_slave(struct sdw_slave *slave)
return ret;
/*
* Set bus clash, parity and SCP implementation
* defined interrupt mask
* TODO: Read implementation defined interrupt mask
* from Slave property
* Set SCP_INT1_MASK register, typically bus clash and
* implementation-defined interrupt mask. The Parity detection
* may not always be correct on startup so its use is
* device-dependent, it might e.g. only be enabled in
* steady-state after a couple of frames.
*/
val = SDW_SCP_INT1_IMPL_DEF | SDW_SCP_INT1_BUS_CLASH |
SDW_SCP_INT1_PARITY;
val = slave->prop.scp_int1_mask;
/* Enable SCP interrupts */
ret = sdw_update(slave, SDW_SCP_INTMASK1, val, val);
......@@ -1362,6 +1425,8 @@ static int sdw_handle_slave_alerts(struct sdw_slave *slave)
unsigned long port;
bool slave_notify = false;
u8 buf, buf2[2], _buf, _buf2[2];
bool parity_check;
bool parity_quirk;
sdw_modify_slave_status(slave, SDW_SLAVE_ALERT);
......@@ -1394,12 +1459,18 @@ static int sdw_handle_slave_alerts(struct sdw_slave *slave)
* interrupt
*/
if (buf & SDW_SCP_INT1_PARITY) {
dev_err(&slave->dev, "Parity error detected\n");
parity_check = slave->prop.scp_int1_mask & SDW_SCP_INT1_PARITY;
parity_quirk = !slave->first_interrupt_done &&
(slave->prop.quirks & SDW_SLAVE_QUIRKS_INVALID_INITIAL_PARITY);
if (parity_check && !parity_quirk)
dev_err(&slave->dev, "Parity error detected\n");
clear |= SDW_SCP_INT1_PARITY;
}
if (buf & SDW_SCP_INT1_BUS_CLASH) {
dev_err(&slave->dev, "Bus clash error detected\n");
if (slave->prop.scp_int1_mask & SDW_SCP_INT1_BUS_CLASH)
dev_err(&slave->dev, "Bus clash detected\n");
clear |= SDW_SCP_INT1_BUS_CLASH;
}
......@@ -1411,16 +1482,18 @@ static int sdw_handle_slave_alerts(struct sdw_slave *slave)
*/
if (buf & SDW_SCP_INT1_IMPL_DEF) {
dev_dbg(&slave->dev, "Slave impl defined interrupt\n");
if (slave->prop.scp_int1_mask & SDW_SCP_INT1_IMPL_DEF) {
dev_dbg(&slave->dev, "Slave impl defined interrupt\n");
slave_notify = true;
}
clear |= SDW_SCP_INT1_IMPL_DEF;
slave_notify = true;
}
/* Check port 0 - 3 interrupts */
port = buf & SDW_SCP_INT1_PORT0_3;
/* To get port number corresponding to bits, shift it */
port = port >> SDW_REG_SHIFT(SDW_SCP_INT1_PORT0_3);
port = FIELD_GET(SDW_SCP_INT1_PORT0_3, port);
for_each_set_bit(bit, &port, 8) {
sdw_handle_port_interrupt(slave, bit,
&port_status[bit]);
......@@ -1468,6 +1541,9 @@ static int sdw_handle_slave_alerts(struct sdw_slave *slave)
goto io_err;
}
/* at this point all initial interrupt sources were handled */
slave->first_interrupt_done = true;
/*
* Read status again to ensure no new interrupts arrived
* while servicing interrupts.
......@@ -1670,8 +1746,10 @@ void sdw_clear_slave_status(struct sdw_bus *bus, u32 request)
if (!slave)
continue;
if (slave->status != SDW_SLAVE_UNATTACHED)
if (slave->status != SDW_SLAVE_UNATTACHED) {
sdw_modify_slave_status(slave, SDW_SLAVE_UNATTACHED);
slave->first_interrupt_done = false;
}
/* keep track of request, used in pm_runtime resume */
slave->unattach_request = request;
......
......@@ -19,6 +19,8 @@ static inline int sdw_acpi_find_slaves(struct sdw_bus *bus)
int sdw_of_find_slaves(struct sdw_bus *bus);
void sdw_extract_slave_id(struct sdw_bus *bus,
u64 addr, struct sdw_slave_id *id);
int sdw_slave_add(struct sdw_bus *bus, struct sdw_slave_id *id,
struct fwnode_handle *fwnode);
int sdw_master_device_add(struct sdw_bus *bus, struct device *parent,
struct fwnode_handle *fwnode);
int sdw_master_device_del(struct sdw_bus *bus);
......@@ -69,6 +71,7 @@ struct sdw_msg {
};
#define SDW_DOUBLE_RATE_FACTOR 2
#define SDW_STRM_RATE_GROUPING 1
extern int sdw_rows[SDW_FRAME_ROWS];
extern int sdw_cols[SDW_FRAME_COLS];
......@@ -154,9 +157,50 @@ int sdw_transfer_defer(struct sdw_bus *bus, struct sdw_msg *msg,
int sdw_fill_msg(struct sdw_msg *msg, struct sdw_slave *slave,
u32 addr, size_t count, u16 dev_num, u8 flags, u8 *buf);
/* Retrieve and return channel count from channel mask */
static inline int sdw_ch_mask_to_ch(int ch_mask)
{
int c = 0;
for (c = 0; ch_mask; ch_mask >>= 1)
c += ch_mask & 1;
return c;
}
/* Fill transport parameter data structure */
static inline void sdw_fill_xport_params(struct sdw_transport_params *params,
int port_num, bool grp_ctrl_valid,
int grp_ctrl, int sample_int,
int off1, int off2,
int hstart, int hstop,
int pack_mode, int lane_ctrl)
{
params->port_num = port_num;
params->blk_grp_ctrl_valid = grp_ctrl_valid;
params->blk_grp_ctrl = grp_ctrl;
params->sample_interval = sample_int;
params->offset1 = off1;
params->offset2 = off2;
params->hstart = hstart;
params->hstop = hstop;
params->blk_pkg_mode = pack_mode;
params->lane_ctrl = lane_ctrl;
}
/* Fill port parameter data structure */
static inline void sdw_fill_port_params(struct sdw_port_params *params,
int port_num, int bps,
int flow_mode, int data_mode)
{
params->num = port_num;
params->bps = bps;
params->flow_mode = flow_mode;
params->data_mode = data_mode;
}
/* Read-Modify-Write Slave register */
static inline int
sdw_update(struct sdw_slave *slave, u32 addr, u8 mask, u8 val)
static inline int sdw_update(struct sdw_slave *slave, u32 addr, u8 mask, u8 val)
{
int tmp;
......@@ -168,6 +212,10 @@ sdw_update(struct sdw_slave *slave, u32 addr, u8 mask, u8 val)
return sdw_write(slave, addr, tmp);
}
/* broadcast read/write for tests */
int sdw_bread_no_pm_unlocked(struct sdw_bus *bus, u16 dev_num, u32 addr);
int sdw_bwrite_no_pm_unlocked(struct sdw_bus *bus, u16 dev_num, u32 addr, u8 value);
/*
* At the moment we only track Master-initiated hw_reset.
* Additional fields can be added as needed
......
......@@ -84,6 +84,15 @@ static int sdw_drv_probe(struct device *dev)
const struct sdw_device_id *id;
int ret;
/*
* fw description is mandatory to bind
*/
if (!dev->fwnode)
return -ENODEV;
if (!IS_ENABLED(CONFIG_ACPI) && !dev->of_node)
return -ENODEV;
id = sdw_get_device_id(slave, drv);
if (!id)
return -ENODEV;
......
This diff is collapsed.
......@@ -84,6 +84,8 @@ struct sdw_cdns_stream_config {
* @bus: Bus handle
* @stream_type: Stream type
* @link_id: Master link id
* @hw_params: hw_params to be applied in .prepare step
* @suspended: status set when suspended, to be used in .prepare
*/
struct sdw_cdns_dma_data {
char *name;
......@@ -92,6 +94,8 @@ struct sdw_cdns_dma_data {
struct sdw_bus *bus;
enum sdw_stream_type stream_type;
int link_id;
struct snd_pcm_hw_params *hw_params;
bool suspended;
};
/**
......@@ -129,6 +133,7 @@ struct sdw_cdns {
bool link_up;
unsigned int msg_count;
bool interrupt_enabled;
struct work_struct work;
......
// SPDX-License-Identifier: (GPL-2.0-only OR BSD-3-Clause)
// Copyright(c) 2015-2020 Intel Corporation.
/*
* Bandwidth management algorithm based on 2^n gears
*
*/
#include <linux/device.h>
#include <linux/module.h>
#include <linux/mod_devicetable.h>
#include <linux/slab.h>
#include <linux/soundwire/sdw.h>
#include "bus.h"
#define SDW_STRM_RATE_GROUPING 1
struct sdw_group_params {
unsigned int rate;
int full_bw;
int payload_bw;
int hwidth;
};
struct sdw_group {
unsigned int count;
unsigned int max_size;
unsigned int *rates;
};
struct sdw_transport_data {
int hstart;
int hstop;
int block_offset;
int sub_block_offset;
};
static void sdw_compute_slave_ports(struct sdw_master_runtime *m_rt,
struct sdw_transport_data *t_data)
{
struct sdw_slave_runtime *s_rt = NULL;
struct sdw_port_runtime *p_rt;
int port_bo, sample_int;
unsigned int rate, bps, ch = 0;
unsigned int slave_total_ch;
struct sdw_bus_params *b_params = &m_rt->bus->params;
port_bo = t_data->block_offset;
list_for_each_entry(s_rt, &m_rt->slave_rt_list, m_rt_node) {
rate = m_rt->stream->params.rate;
bps = m_rt->stream->params.bps;
sample_int = (m_rt->bus->params.curr_dr_freq / rate);
slave_total_ch = 0;
list_for_each_entry(p_rt, &s_rt->port_list, port_node) {
ch = sdw_ch_mask_to_ch(p_rt->ch_mask);
sdw_fill_xport_params(&p_rt->transport_params,
p_rt->num, false,
SDW_BLK_GRP_CNT_1,
sample_int, port_bo, port_bo >> 8,
t_data->hstart,
t_data->hstop,
(SDW_BLK_GRP_CNT_1 * ch), 0x0);
sdw_fill_port_params(&p_rt->port_params,
p_rt->num, bps,
SDW_PORT_FLOW_MODE_ISOCH,
b_params->s_data_mode);
port_bo += bps * ch;
slave_total_ch += ch;
}
if (m_rt->direction == SDW_DATA_DIR_TX &&
m_rt->ch_count == slave_total_ch) {
/*
* Slave devices were configured to access all channels
* of the stream, which indicates that they operate in
* 'mirror mode'. Make sure we reset the port offset for
* the next device in the list
*/
port_bo = t_data->block_offset;
}
}
}
static void sdw_compute_master_ports(struct sdw_master_runtime *m_rt,
struct sdw_group_params *params,
int port_bo, int hstop)
{
struct sdw_transport_data t_data = {0};
struct sdw_port_runtime *p_rt;
struct sdw_bus *bus = m_rt->bus;
struct sdw_bus_params *b_params = &bus->params;
int sample_int, hstart = 0;
unsigned int rate, bps, ch, no_ch;
rate = m_rt->stream->params.rate;
bps = m_rt->stream->params.bps;
ch = m_rt->ch_count;
sample_int = (bus->params.curr_dr_freq / rate);
if (rate != params->rate)
return;
t_data.hstop = hstop;
hstart = hstop - params->hwidth + 1;
t_data.hstart = hstart;
list_for_each_entry(p_rt, &m_rt->port_list, port_node) {
no_ch = sdw_ch_mask_to_ch(p_rt->ch_mask);
sdw_fill_xport_params(&p_rt->transport_params, p_rt->num,
false, SDW_BLK_GRP_CNT_1, sample_int,
port_bo, port_bo >> 8, hstart, hstop,
(SDW_BLK_GRP_CNT_1 * no_ch), 0x0);
sdw_fill_port_params(&p_rt->port_params,
p_rt->num, bps,
SDW_PORT_FLOW_MODE_ISOCH,
b_params->m_data_mode);
/* Check for first entry */
if (!(p_rt == list_first_entry(&m_rt->port_list,
struct sdw_port_runtime,
port_node))) {
port_bo += bps * ch;
continue;
}
t_data.hstart = hstart;
t_data.hstop = hstop;
t_data.block_offset = port_bo;
t_data.sub_block_offset = 0;
port_bo += bps * ch;
}
sdw_compute_slave_ports(m_rt, &t_data);
}
static void _sdw_compute_port_params(struct sdw_bus *bus,
struct sdw_group_params *params, int count)
{
struct sdw_master_runtime *m_rt = NULL;
int hstop = bus->params.col - 1;
int block_offset, port_bo, i;
/* Run loop for all groups to compute transport parameters */
for (i = 0; i < count; i++) {
port_bo = 1;
block_offset = 1;
list_for_each_entry(m_rt, &bus->m_rt_list, bus_node) {
sdw_compute_master_ports(m_rt, &params[i],
port_bo, hstop);
block_offset += m_rt->ch_count *
m_rt->stream->params.bps;
port_bo = block_offset;
}
hstop = hstop - params[i].hwidth;
}
}
static int sdw_compute_group_params(struct sdw_bus *bus,
struct sdw_group_params *params,
int *rates, int count)
{
struct sdw_master_runtime *m_rt = NULL;
int sel_col = bus->params.col;
unsigned int rate, bps, ch;
int i, column_needed = 0;
/* Calculate bandwidth per group */
for (i = 0; i < count; i++) {
params[i].rate = rates[i];
params[i].full_bw = bus->params.curr_dr_freq / params[i].rate;
}
list_for_each_entry(m_rt, &bus->m_rt_list, bus_node) {
rate = m_rt->stream->params.rate;
bps = m_rt->stream->params.bps;
ch = m_rt->ch_count;
for (i = 0; i < count; i++) {
if (rate == params[i].rate)
params[i].payload_bw += bps * ch;
}
}
for (i = 0; i < count; i++) {
params[i].hwidth = (sel_col *
params[i].payload_bw + params[i].full_bw - 1) /
params[i].full_bw;
column_needed += params[i].hwidth;
}
if (column_needed > sel_col - 1)
return -EINVAL;
return 0;
}
static int sdw_add_element_group_count(struct sdw_group *group,
unsigned int rate)
{
int num = group->count;
int i;
for (i = 0; i <= num; i++) {
if (rate == group->rates[i])
break;
if (i != num)
continue;
if (group->count >= group->max_size) {
unsigned int *rates;
group->max_size += 1;
rates = krealloc(group->rates,
(sizeof(int) * group->max_size),
GFP_KERNEL);
if (!rates)
return -ENOMEM;
group->rates = rates;
}
group->rates[group->count++] = rate;
}
return 0;
}
static int sdw_get_group_count(struct sdw_bus *bus,
struct sdw_group *group)
{
struct sdw_master_runtime *m_rt;
unsigned int rate;
int ret = 0;
group->count = 0;
group->max_size = SDW_STRM_RATE_GROUPING;
group->rates = kcalloc(group->max_size, sizeof(int), GFP_KERNEL);
if (!group->rates)
return -ENOMEM;
list_for_each_entry(m_rt, &bus->m_rt_list, bus_node) {
rate = m_rt->stream->params.rate;
if (m_rt == list_first_entry(&bus->m_rt_list,
struct sdw_master_runtime,
bus_node)) {
group->rates[group->count++] = rate;
} else {
ret = sdw_add_element_group_count(group, rate);
if (ret < 0) {
kfree(group->rates);
return ret;
}
}
}
return ret;
}
/**
* sdw_compute_port_params: Compute transport and port parameters
*
* @bus: SDW Bus instance
*/
static int sdw_compute_port_params(struct sdw_bus *bus)
{
struct sdw_group_params *params = NULL;
struct sdw_group group;
int ret;
ret = sdw_get_group_count(bus, &group);
if (ret < 0)
return ret;
if (group.count == 0)
goto out;
params = kcalloc(group.count, sizeof(*params), GFP_KERNEL);
if (!params) {
ret = -ENOMEM;
goto out;
}
/* Compute transport parameters for grouped streams */
ret = sdw_compute_group_params(bus, params,
&group.rates[0], group.count);
if (ret < 0)
goto free_params;
_sdw_compute_port_params(bus, params, group.count);
free_params:
kfree(params);
out:
kfree(group.rates);
return ret;
}
static int sdw_select_row_col(struct sdw_bus *bus, int clk_freq)
{
struct sdw_master_prop *prop = &bus->prop;
int frame_int, frame_freq;
int r, c;
for (c = 0; c < SDW_FRAME_COLS; c++) {
for (r = 0; r < SDW_FRAME_ROWS; r++) {
if (sdw_rows[r] != prop->default_row ||
sdw_cols[c] != prop->default_col)
continue;
frame_int = sdw_rows[r] * sdw_cols[c];
frame_freq = clk_freq / frame_int;
if ((clk_freq - (frame_freq * SDW_FRAME_CTRL_BITS)) <
bus->params.bandwidth)
continue;
bus->params.row = sdw_rows[r];
bus->params.col = sdw_cols[c];
return 0;
}
}
return -EINVAL;
}
/**
* sdw_compute_bus_params: Compute bus parameters
*
* @bus: SDW Bus instance
*/
static int sdw_compute_bus_params(struct sdw_bus *bus)
{
unsigned int max_dr_freq, curr_dr_freq = 0;
struct sdw_master_prop *mstr_prop = &bus->prop;
int i, clk_values, ret;
bool is_gear = false;
u32 *clk_buf;
if (mstr_prop->num_clk_gears) {
clk_values = mstr_prop->num_clk_gears;
clk_buf = mstr_prop->clk_gears;
is_gear = true;
} else if (mstr_prop->num_clk_freq) {
clk_values = mstr_prop->num_clk_freq;
clk_buf = mstr_prop->clk_freq;
} else {
clk_values = 1;
clk_buf = NULL;
}
max_dr_freq = mstr_prop->max_clk_freq * SDW_DOUBLE_RATE_FACTOR;
for (i = 0; i < clk_values; i++) {
if (!clk_buf)
curr_dr_freq = max_dr_freq;
else
curr_dr_freq = (is_gear) ?
(max_dr_freq >> clk_buf[i]) :
clk_buf[i] * SDW_DOUBLE_RATE_FACTOR;
if (curr_dr_freq <= bus->params.bandwidth)
continue;
break;
/*
* TODO: Check all the Slave(s) port(s) audio modes and find
* whether given clock rate is supported with glitchless
* transition.
*/
}
if (i == clk_values)
return -EINVAL;
ret = sdw_select_row_col(bus, curr_dr_freq);
if (ret < 0)
return -EINVAL;
bus->params.curr_dr_freq = curr_dr_freq;
return 0;
}
/**
* sdw_compute_params: Compute bus, transport and port parameters
*
* @bus: SDW Bus instance
*/
int sdw_compute_params(struct sdw_bus *bus)
{
int ret;
/* Computes clock frequency, frame shape and frame frequency */
ret = sdw_compute_bus_params(bus);
if (ret < 0) {
dev_err(bus->dev, "Compute bus params failed: %d", ret);
return ret;
}
/* Compute transport and port params */
ret = sdw_compute_port_params(bus);
if (ret < 0) {
dev_err(bus->dev, "Compute transport params failed: %d", ret);
return ret;
}
return 0;
}
EXPORT_SYMBOL(sdw_compute_params);
MODULE_LICENSE("Dual BSD/GPL");
MODULE_DESCRIPTION("SoundWire Generic Bandwidth Allocation");
This diff is collapsed.
......@@ -17,6 +17,8 @@
* @dev: device implementing hw_params and free callbacks
* @shim_lock: mutex to handle access to shared SHIM registers
* @shim_mask: global pointer to check SHIM register initialization
* @clock_stop_quirks: mask defining requested behavior on pm_suspend
* @link_mask: global mask needed for power-up/down sequences
* @cdns: Cadence master descriptor
* @list: used to walk-through all masters exposed by the same controller
*/
......@@ -31,6 +33,8 @@ struct sdw_intel_link_res {
struct device *dev;
struct mutex *shim_lock; /* protect shared registers */
u32 *shim_mask;
u32 clock_stop_quirks;
u32 link_mask;
struct sdw_cdns *cdns;
struct list_head list;
};
......
......@@ -13,6 +13,7 @@
#include <linux/io.h>
#include <linux/module.h>
#include <linux/platform_device.h>
#include <linux/pm_runtime.h>
#include <linux/soundwire/sdw_intel.h>
#include "cadence_master.h"
#include "intel.h"
......@@ -68,8 +69,13 @@ static int sdw_intel_cleanup(struct sdw_intel_ctx *ctx)
if (!(link_mask & BIT(i)))
continue;
if (link->pdev)
if (link->pdev) {
pm_runtime_disable(&link->pdev->dev);
platform_device_unregister(link->pdev);
}
if (!link->clock_stop_quirks)
pm_runtime_put_noidle(link->dev);
}
return 0;
......@@ -246,8 +252,10 @@ static struct sdw_intel_ctx
link->ops = res->ops;
link->dev = res->dev;
link->clock_stop_quirks = res->clock_stop_quirks;
link->shim_lock = &ctx->shim_lock;
link->shim_mask = &ctx->shim_mask;
link->link_mask = link_mask;
memset(&pdevinfo, 0, sizeof(pdevinfo));
......@@ -334,6 +342,16 @@ sdw_intel_startup_controller(struct sdw_intel_ctx *ctx)
continue;
intel_master_startup(link->pdev);
if (!link->clock_stop_quirks) {
/*
* we need to prevent the parent PCI device
* from entering pm_runtime suspend, so that
* power rails to the SoundWire IP are not
* turned off.
*/
pm_runtime_get_noresume(link->dev);
}
}
return 0;
......@@ -365,7 +383,7 @@ static acpi_status sdw_intel_acpi_cb(acpi_handle handle, u32 level,
* Name(_ADR, 0x40000000), with bits 31..28 representing the
* SoundWire link so filter accordingly
*/
if ((adr & GENMASK(31, 28)) >> 28 != SDW_LINK_TYPE)
if (FIELD_GET(GENMASK(31, 28), adr) != SDW_LINK_TYPE)
return AE_OK; /* keep going */
/* device found, stop namespace walk */
......
......@@ -154,6 +154,7 @@ int sdw_master_device_add(struct sdw_bus *bus, struct device *parent,
bus->dev = &md->dev;
bus->md = md;
pm_runtime_enable(&bus->md->dev);
device_register_err:
return ret;
}
......@@ -166,6 +167,7 @@ int sdw_master_device_add(struct sdw_bus *bus, struct device *parent,
*/
int sdw_master_device_del(struct sdw_bus *bus)
{
pm_runtime_disable(&bus->md->dev);
device_unregister(bus->dev);
return 0;
......
......@@ -289,7 +289,7 @@ int sdw_slave_read_prop(struct sdw_slave *slave)
struct sdw_slave_prop *prop = &slave->prop;
struct device *dev = &slave->dev;
struct fwnode_handle *port;
int num_of_ports, nval, i, dp0 = 0;
int nval;
device_property_read_u32(dev, "mipi-sdw-sw-interface-revision",
&prop->mipi_revision);
......@@ -352,7 +352,6 @@ int sdw_slave_read_prop(struct sdw_slave *slave)
return -ENOMEM;
sdw_slave_read_dp0(slave, port, prop->dp0_prop);
dp0 = 1;
}
/*
......@@ -383,21 +382,6 @@ int sdw_slave_read_prop(struct sdw_slave *slave)
sdw_slave_read_dpn(slave, prop->sink_dpn_prop, nval,
prop->sink_ports, "sink");
/* some ports are bidirectional so check total ports by ORing */
nval = prop->source_ports | prop->sink_ports;
num_of_ports = hweight32(nval) + dp0; /* add DP0 */
/* Allocate port_ready based on num_of_ports */
slave->port_ready = devm_kcalloc(&slave->dev, num_of_ports,
sizeof(*slave->port_ready),
GFP_KERNEL);
if (!slave->port_ready)
return -ENOMEM;
/* Initialize completion */
for (i = 0; i < num_of_ports; i++)
init_completion(&slave->port_ready[i]);
return 0;
}
EXPORT_SYMBOL(sdw_slave_read_prop);
This diff is collapsed.
......@@ -6,6 +6,7 @@
#include <linux/soundwire/sdw.h>
#include <linux/soundwire/sdw_type.h>
#include "bus.h"
#include "sysfs_local.h"
static void sdw_slave_release(struct device *dev)
{
......@@ -20,11 +21,12 @@ struct device_type sdw_slave_type = {
.uevent = sdw_slave_uevent,
};
static int sdw_slave_add(struct sdw_bus *bus,
struct sdw_slave_id *id, struct fwnode_handle *fwnode)
int sdw_slave_add(struct sdw_bus *bus,
struct sdw_slave_id *id, struct fwnode_handle *fwnode)
{
struct sdw_slave *slave;
int ret;
int i;
slave = kzalloc(sizeof(*slave), GFP_KERNEL);
if (!slave)
......@@ -50,6 +52,7 @@ static int sdw_slave_add(struct sdw_bus *bus,
slave->dev.bus = &sdw_bus_type;
slave->dev.of_node = of_node_get(to_of_node(fwnode));
slave->dev.type = &sdw_slave_type;
slave->dev.groups = sdw_slave_status_attr_groups;
slave->bus = bus;
slave->status = SDW_SLAVE_UNATTACHED;
init_completion(&slave->enumeration_complete);
......@@ -57,6 +60,10 @@ static int sdw_slave_add(struct sdw_bus *bus,
slave->dev_num = 0;
init_completion(&slave->probe_complete);
slave->probed = false;
slave->first_interrupt_done = false;
for (i = 0; i < SDW_MAX_PORTS; i++)
init_completion(&slave->port_ready[i]);
mutex_lock(&bus->bus_lock);
list_add_tail(&slave->node, &bus->slaves);
......@@ -102,7 +109,7 @@ static bool find_slave(struct sdw_bus *bus,
}
/* Extract link id from ADR, Bit 51 to 48 (included) */
link_id = (addr >> 48) & GENMASK(3, 0);
link_id = SDW_DISCO_LINK_ID(addr);
/* Check for link_id match */
if (link_id != bus->link_id)
......
......@@ -25,8 +25,10 @@
int sdw_rows[SDW_FRAME_ROWS] = {48, 50, 60, 64, 75, 80, 125, 147,
96, 100, 120, 128, 150, 160, 250, 0,
192, 200, 240, 256, 72, 144, 90, 180};
EXPORT_SYMBOL(sdw_rows);
int sdw_cols[SDW_FRAME_COLS] = {2, 4, 6, 8, 10, 12, 14, 16};
EXPORT_SYMBOL(sdw_cols);
int sdw_find_col_index(int col)
{
......@@ -100,9 +102,7 @@ static int _sdw_program_slave_port_params(struct sdw_bus *bus,
return ret;
/* Program DPN_SampleCtrl2 register */
wbuf = (t_params->sample_interval - 1);
wbuf &= SDW_DPN_SAMPLECTRL_HIGH;
wbuf >>= SDW_REG_SHIFT(SDW_DPN_SAMPLECTRL_HIGH);
wbuf = FIELD_GET(SDW_DPN_SAMPLECTRL_HIGH, t_params->sample_interval - 1);
ret = sdw_write(slave, addr3, wbuf);
if (ret < 0) {
......@@ -111,9 +111,8 @@ static int _sdw_program_slave_port_params(struct sdw_bus *bus,
}
/* Program DPN_HCtrl register */
wbuf = t_params->hstart;
wbuf <<= SDW_REG_SHIFT(SDW_DPN_HCTRL_HSTART);
wbuf |= t_params->hstop;
wbuf = FIELD_PREP(SDW_DPN_HCTRL_HSTART, t_params->hstart);
wbuf |= FIELD_PREP(SDW_DPN_HCTRL_HSTOP, t_params->hstop);
ret = sdw_write(slave, addr4, wbuf);
if (ret < 0)
......@@ -157,8 +156,8 @@ static int sdw_program_slave_port_params(struct sdw_bus *bus,
}
/* Program DPN_PortCtrl register */
wbuf = p_params->data_mode << SDW_REG_SHIFT(SDW_DPN_PORTCTRL_DATAMODE);
wbuf |= p_params->flow_mode;
wbuf = FIELD_PREP(SDW_DPN_PORTCTRL_DATAMODE, p_params->data_mode);
wbuf |= FIELD_PREP(SDW_DPN_PORTCTRL_FLOWMODE, p_params->flow_mode);
ret = sdw_update(s_rt->slave, addr1, 0xF, wbuf);
if (ret < 0) {
......@@ -444,7 +443,8 @@ static int sdw_prep_deprep_slave_ports(struct sdw_bus *bus,
prep_ch.bank = bus->params.next_bank;
if (dpn_prop->imp_def_interrupts || !dpn_prop->simple_ch_prep_sm)
if (dpn_prop->imp_def_interrupts || !dpn_prop->simple_ch_prep_sm ||
bus->params.s_data_mode != SDW_PORT_DATA_MODE_NORMAL)
intr = true;
/*
......@@ -689,9 +689,9 @@ static int sdw_bank_switch(struct sdw_bus *bus, int m_rt_count)
/*
* Set the multi_link flag only when both the hardware supports
* and there is a stream handled by multiple masters
* and hardware-based sync is required
*/
multi_link = bus->multi_link && (m_rt_count > 1);
multi_link = bus->multi_link && (m_rt_count >= bus->hw_sync_min_links);
if (multi_link)
ret = sdw_transfer_defer(bus, wr_msg, &bus->defer_msg);
......@@ -761,13 +761,16 @@ static int do_bank_switch(struct sdw_stream_runtime *stream)
const struct sdw_master_ops *ops;
struct sdw_bus *bus;
bool multi_link = false;
int m_rt_count;
int ret = 0;
m_rt_count = stream->m_rt_count;
list_for_each_entry(m_rt, &stream->master_list, stream_node) {
bus = m_rt->bus;
ops = bus->ops;
if (bus->multi_link) {
if (bus->multi_link && m_rt_count >= bus->hw_sync_min_links) {
multi_link = true;
mutex_lock(&bus->msg_lock);
}
......@@ -788,7 +791,7 @@ static int do_bank_switch(struct sdw_stream_runtime *stream)
* synchronized across all Masters and happens later as a
* part of post_bank_switch ops.
*/
ret = sdw_bank_switch(bus, stream->m_rt_count);
ret = sdw_bank_switch(bus, m_rt_count);
if (ret < 0) {
dev_err(bus->dev, "Bank switch failed: %d\n", ret);
goto error;
......@@ -814,7 +817,7 @@ static int do_bank_switch(struct sdw_stream_runtime *stream)
ret);
goto error;
}
} else if (bus->multi_link && stream->m_rt_count > 1) {
} else if (multi_link) {
dev_err(bus->dev,
"Post bank switch ops not implemented\n");
goto error;
......@@ -832,7 +835,7 @@ static int do_bank_switch(struct sdw_stream_runtime *stream)
goto error;
}
if (bus->multi_link)
if (multi_link)
mutex_unlock(&bus->msg_lock);
}
......@@ -1784,6 +1787,16 @@ static int _sdw_deprepare_stream(struct sdw_stream_runtime *stream)
bus->params.bandwidth -= m_rt->stream->params.rate *
m_rt->ch_count * m_rt->stream->params.bps;
/* Compute params */
if (bus->compute_params) {
ret = bus->compute_params(bus);
if (ret < 0) {
dev_err(bus->dev, "Compute params failed: %d",
ret);
return ret;
}
}
/* Program params */
ret = sdw_program_params(bus, false);
if (ret < 0) {
......@@ -1913,7 +1926,7 @@ void sdw_shutdown_stream(void *sdw_substream)
sdw_stream = snd_soc_dai_get_sdw_stream(dai, substream->stream);
if (!sdw_stream) {
if (IS_ERR(sdw_stream)) {
dev_err(rtd->dev, "no stream found for DAI %s", dai->name);
return;
}
......
......@@ -8,6 +8,10 @@
* SDW sysfs APIs -
*/
/* basic attributes to report status of Slave (attachment, dev_num) */
extern const struct attribute_group *sdw_slave_status_attr_groups[];
/* additional device-managed properties reported after driver probe */
int sdw_slave_sysfs_init(struct sdw_slave *slave);
int sdw_slave_sysfs_dpn_init(struct sdw_slave *slave);
......
......@@ -16,9 +16,13 @@
/*
* The sysfs for Slave reflects the MIPI description as given
* in the MIPI DisCo spec
* in the MIPI DisCo spec.
* status and device_number come directly from the MIPI SoundWire
* 1.x specification.
*
* Base file is device
* |---- status
* |---- device_number
* |---- modalias
* |---- dev-properties
* |---- mipi_revision
......@@ -212,3 +216,55 @@ int sdw_slave_sysfs_init(struct sdw_slave *slave)
return 0;
}
/*
* the status is shown in capital letters for UNATTACHED and RESERVED
* on purpose, to highligh users to the fact that these status values
* are not expected.
*/
static const char *const slave_status[] = {
[SDW_SLAVE_UNATTACHED] = "UNATTACHED",
[SDW_SLAVE_ATTACHED] = "Attached",
[SDW_SLAVE_ALERT] = "Alert",
[SDW_SLAVE_RESERVED] = "RESERVED",
};
static ssize_t status_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
struct sdw_slave *slave = dev_to_sdw_dev(dev);
return sprintf(buf, "%s\n", slave_status[slave->status]);
}
static DEVICE_ATTR_RO(status);
static ssize_t device_number_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
struct sdw_slave *slave = dev_to_sdw_dev(dev);
if (slave->status == SDW_SLAVE_UNATTACHED)
return sprintf(buf, "%s", "N/A");
else
return sprintf(buf, "%d", slave->dev_num);
}
static DEVICE_ATTR_RO(device_number);
static struct attribute *slave_status_attrs[] = {
&dev_attr_status.attr,
&dev_attr_device_number.attr,
NULL,
};
/*
* we don't use ATTRIBUTES_GROUP here since the group is used in a
* separate file and can't be handled as a static.
*/
static const struct attribute_group sdw_slave_status_attr_group = {
.attrs = slave_status_attrs,
};
const struct attribute_group *sdw_slave_status_attr_groups[] = {
&sdw_slave_status_attr_group,
NULL
};
......@@ -5,6 +5,7 @@
#define __SOUNDWIRE_H
#include <linux/mod_devicetable.h>
#include <linux/bitfield.h>
struct sdw_bus;
struct sdw_slave;
......@@ -38,7 +39,8 @@ struct sdw_slave;
#define SDW_FRAME_CTRL_BITS 48
#define SDW_MAX_DEVICES 11
#define SDW_VALID_PORT_RANGE(n) ((n) <= 14 && (n) >= 1)
#define SDW_MAX_PORTS 15
#define SDW_VALID_PORT_RANGE(n) ((n) < SDW_MAX_PORTS && (n) >= 1)
enum {
SDW_PORT_DIRN_SINK = 0,
......@@ -355,6 +357,8 @@ struct sdw_dpn_prop {
* @dp0_prop: Data Port 0 properties
* @src_dpn_prop: Source Data Port N properties
* @sink_dpn_prop: Sink Data Port N properties
* @scp_int1_mask: SCP_INT1_MASK desired settings
* @quirks: bitmask identifying deltas from the MIPI specification
*/
struct sdw_slave_prop {
u32 mipi_revision;
......@@ -376,8 +380,12 @@ struct sdw_slave_prop {
struct sdw_dp0_prop *dp0_prop;
struct sdw_dpn_prop *src_dpn_prop;
struct sdw_dpn_prop *sink_dpn_prop;
u8 scp_int1_mask;
u32 quirks;
};
#define SDW_SLAVE_QUIRKS_INVALID_INITIAL_PARITY BIT(0)
/**
* struct sdw_master_prop - Master properties
* @revision: MIPI spec version of the implementation
......@@ -455,13 +463,19 @@ struct sdw_slave_id {
*
* The MIPI DisCo for SoundWire defines in addition the link_id as bits 51:48
*/
#define SDW_DISCO_LINK_ID_MASK GENMASK_ULL(51, 48)
#define SDW_VERSION_MASK GENMASK_ULL(47, 44)
#define SDW_UNIQUE_ID_MASK GENMASK_ULL(43, 40)
#define SDW_MFG_ID_MASK GENMASK_ULL(39, 24)
#define SDW_PART_ID_MASK GENMASK_ULL(23, 8)
#define SDW_CLASS_ID_MASK GENMASK_ULL(7, 0)
#define SDW_DISCO_LINK_ID(adr) (((adr) >> 48) & GENMASK(3, 0))
#define SDW_VERSION(adr) (((adr) >> 44) & GENMASK(3, 0))
#define SDW_UNIQUE_ID(adr) (((adr) >> 40) & GENMASK(3, 0))
#define SDW_MFG_ID(adr) (((adr) >> 24) & GENMASK(15, 0))
#define SDW_PART_ID(adr) (((adr) >> 8) & GENMASK(15, 0))
#define SDW_CLASS_ID(adr) ((adr) & GENMASK(7, 0))
#define SDW_DISCO_LINK_ID(addr) FIELD_GET(SDW_DISCO_LINK_ID_MASK, addr)
#define SDW_VERSION(addr) FIELD_GET(SDW_VERSION_MASK, addr)
#define SDW_UNIQUE_ID(addr) FIELD_GET(SDW_UNIQUE_ID_MASK, addr)
#define SDW_MFG_ID(addr) FIELD_GET(SDW_MFG_ID_MASK, addr)
#define SDW_PART_ID(addr) FIELD_GET(SDW_PART_ID_MASK, addr)
#define SDW_CLASS_ID(addr) FIELD_GET(SDW_CLASS_ID_MASK, addr)
/**
* struct sdw_slave_intr_status - Slave interrupt status
......@@ -540,6 +554,10 @@ enum sdw_port_prep_ops {
* @bandwidth: Current bandwidth
* @col: Active columns
* @row: Active rows
* @s_data_mode: NORMAL, STATIC or PRBS mode for all Slave ports
* @m_data_mode: NORMAL, STATIC or PRBS mode for all Master ports. The value
* should be the same to detect transmission issues, but can be different to
* test the interrupt reports
*/
struct sdw_bus_params {
enum sdw_reg_bank curr_bank;
......@@ -549,6 +567,8 @@ struct sdw_bus_params {
unsigned int bandwidth;
unsigned int col;
unsigned int row;
int s_data_mode;
int m_data_mode;
};
/**
......@@ -606,6 +626,8 @@ struct sdw_slave_ops {
* between the Master suspending and the codec resuming, and make sure that
* when the Master triggered a reset the Slave is properly enumerated and
* initialized
* @first_interrupt_done: status flag tracking if the interrupt handling
* for a Slave happens for the first time after enumeration
*/
struct sdw_slave {
struct sdw_slave_id id;
......@@ -618,7 +640,7 @@ struct sdw_slave {
struct dentry *debugfs;
#endif
struct list_head node;
struct completion *port_ready;
struct completion port_ready[SDW_MAX_PORTS];
enum sdw_clk_stop_mode curr_clk_stop_mode;
u16 dev_num;
u16 dev_num_sticky;
......@@ -627,6 +649,7 @@ struct sdw_slave {
struct completion enumeration_complete;
struct completion initialization_complete;
u32 unattach_request;
bool first_interrupt_done;
};
#define dev_to_sdw_dev(_dev) container_of(_dev, struct sdw_slave, dev)
......@@ -827,6 +850,11 @@ struct sdw_master_ops {
* @multi_link: Store bus property that indicates if multi links
* are supported. This flag is populated by drivers after reading
* appropriate firmware (ACPI/DT).
* @hw_sync_min_links: Number of links used by a stream above which
* hardware-based synchronization is required. This value is only
* meaningful if multi_link is set. If set to 1, hardware-based
* synchronization will be used even if a stream only uses a single
* SoundWire segment.
*/
struct sdw_bus {
struct device *dev;
......@@ -850,6 +878,7 @@ struct sdw_bus {
unsigned int clk_stop_timeout;
u32 bank_switch_timeout;
bool multi_link;
int hw_sync_min_links;
};
int sdw_bus_master_add(struct sdw_bus *bus, struct device *parent,
......@@ -941,6 +970,9 @@ struct sdw_stream_runtime {
struct sdw_stream_runtime *sdw_alloc_stream(const char *stream_name);
void sdw_release_stream(struct sdw_stream_runtime *stream);
int sdw_compute_params(struct sdw_bus *bus);
int sdw_stream_add_master(struct sdw_bus *bus,
struct sdw_stream_config *stream_config,
struct sdw_port_config *port_config,
......
......@@ -4,13 +4,6 @@
#ifndef __SDW_REGISTERS_H
#define __SDW_REGISTERS_H
/*
* typically we define register and shifts but if one observes carefully,
* the shift can be generated from MASKS using few bit primitaives like ffs
* etc, so we use that and avoid defining shifts
*/
#define SDW_REG_SHIFT(n) (ffs(n) - 1)
/*
* SDW registers as defined by MIPI 1.2 Spec
*/
......
......@@ -15,6 +15,7 @@
#include <linux/of.h>
#include <linux/soundwire/sdw.h>
#include <linux/soundwire/sdw_type.h>
#include <linux/soundwire/sdw_registers.h>
#include "max98373.h"
#include "max98373-sdw.h"
......@@ -282,11 +283,13 @@ static const struct dev_pm_ops max98373_pm = {
static int max98373_read_prop(struct sdw_slave *slave)
{
struct sdw_slave_prop *prop = &slave->prop;
int nval, i, num_of_ports;
int nval, i;
u32 bit;
unsigned long addr;
struct sdw_dpn_prop *dpn;
prop->scp_int1_mask = SDW_SCP_INT1_BUS_CLASH | SDW_SCP_INT1_PARITY;
/* BITMAP: 00001000 Dataport 3 is active */
prop->source_ports = BIT(3);
/* BITMAP: 00000010 Dataport 1 is active */
......@@ -295,7 +298,6 @@ static int max98373_read_prop(struct sdw_slave *slave)
prop->clk_stop_timeout = 20;
nval = hweight32(prop->source_ports);
num_of_ports = nval;
prop->src_dpn_prop = devm_kcalloc(&slave->dev, nval,
sizeof(*prop->src_dpn_prop),
GFP_KERNEL);
......@@ -315,7 +317,6 @@ static int max98373_read_prop(struct sdw_slave *slave)
/* do this again for sink now */
nval = hweight32(prop->sink_ports);
num_of_ports += nval;
prop->sink_dpn_prop = devm_kcalloc(&slave->dev, nval,
sizeof(*prop->sink_dpn_prop),
GFP_KERNEL);
......@@ -333,17 +334,6 @@ static int max98373_read_prop(struct sdw_slave *slave)
i++;
}
/* Allocate port_ready based on num_of_ports */
slave->port_ready = devm_kcalloc(&slave->dev, num_of_ports,
sizeof(*slave->port_ready),
GFP_KERNEL);
if (!slave->port_ready)
return -ENOMEM;
/* Initialize completion */
for (i = 0; i < num_of_ports; i++)
init_completion(&slave->port_ready[i]);
/* set the timeout values */
prop->clk_stop_timeout = 20;
......
......@@ -118,11 +118,14 @@ static int rt1308_clock_config(struct device *dev)
static int rt1308_read_prop(struct sdw_slave *slave)
{
struct sdw_slave_prop *prop = &slave->prop;
int nval, i, num_of_ports = 1;
int nval, i;
u32 bit;
unsigned long addr;
struct sdw_dpn_prop *dpn;
prop->scp_int1_mask = SDW_SCP_INT1_BUS_CLASH | SDW_SCP_INT1_PARITY;
prop->quirks = SDW_SLAVE_QUIRKS_INVALID_INITIAL_PARITY;
prop->paging_support = true;
/* first we need to allocate memory for set bits in port lists */
......@@ -131,7 +134,6 @@ static int rt1308_read_prop(struct sdw_slave *slave)
/* for sink */
nval = hweight32(prop->sink_ports);
num_of_ports += nval;
prop->sink_dpn_prop = devm_kcalloc(&slave->dev, nval,
sizeof(*prop->sink_dpn_prop),
GFP_KERNEL);
......@@ -149,17 +151,6 @@ static int rt1308_read_prop(struct sdw_slave *slave)
i++;
}
/* Allocate port_ready based on num_of_ports */
slave->port_ready = devm_kcalloc(&slave->dev, num_of_ports,
sizeof(*slave->port_ready),
GFP_KERNEL);
if (!slave->port_ready)
return -ENOMEM;
/* Initialize completion */
for (i = 0; i < num_of_ports; i++)
init_completion(&slave->port_ready[i]);
/* set the timeout values */
prop->clk_stop_timeout = 20;
......
......@@ -19,6 +19,7 @@
#include <linux/mutex.h>
#include <linux/soundwire/sdw.h>
#include <linux/soundwire/sdw_type.h>
#include <linux/soundwire/sdw_registers.h>
#include <sound/core.h>
#include <sound/pcm.h>
#include <sound/pcm_params.h>
......@@ -537,11 +538,15 @@ static int rt5682_update_status(struct sdw_slave *slave,
static int rt5682_read_prop(struct sdw_slave *slave)
{
struct sdw_slave_prop *prop = &slave->prop;
int nval, i, num_of_ports = 1;
int nval, i;
u32 bit;
unsigned long addr;
struct sdw_dpn_prop *dpn;
prop->scp_int1_mask = SDW_SCP_INT1_IMPL_DEF | SDW_SCP_INT1_BUS_CLASH |
SDW_SCP_INT1_PARITY;
prop->quirks = SDW_SLAVE_QUIRKS_INVALID_INITIAL_PARITY;
prop->paging_support = false;
/* first we need to allocate memory for set bits in port lists */
......@@ -549,7 +554,6 @@ static int rt5682_read_prop(struct sdw_slave *slave)
prop->sink_ports = 0x2; /* BITMAP: 00000010 */
nval = hweight32(prop->source_ports);
num_of_ports += nval;
prop->src_dpn_prop = devm_kcalloc(&slave->dev, nval,
sizeof(*prop->src_dpn_prop),
GFP_KERNEL);
......@@ -569,7 +573,6 @@ static int rt5682_read_prop(struct sdw_slave *slave)
/* do this again for sink now */
nval = hweight32(prop->sink_ports);
num_of_ports += nval;
prop->sink_dpn_prop = devm_kcalloc(&slave->dev, nval,
sizeof(*prop->sink_dpn_prop),
GFP_KERNEL);
......@@ -587,17 +590,6 @@ static int rt5682_read_prop(struct sdw_slave *slave)
i++;
}
/* Allocate port_ready based on num_of_ports */
slave->port_ready = devm_kcalloc(&slave->dev, num_of_ports,
sizeof(*slave->port_ready),
GFP_KERNEL);
if (!slave->port_ready)
return -ENOMEM;
/* Initialize completion */
for (i = 0; i < num_of_ports; i++)
init_completion(&slave->port_ready[i]);
/* set the timeout values */
prop->clk_stop_timeout = 20;
......
......@@ -11,6 +11,7 @@
#include <linux/mod_devicetable.h>
#include <linux/soundwire/sdw.h>
#include <linux/soundwire/sdw_type.h>
#include <linux/soundwire/sdw_registers.h>
#include <linux/module.h>
#include <linux/regmap.h>
#include <sound/soc.h>
......@@ -333,11 +334,15 @@ static int rt700_update_status(struct sdw_slave *slave,
static int rt700_read_prop(struct sdw_slave *slave)
{
struct sdw_slave_prop *prop = &slave->prop;
int nval, i, num_of_ports = 1;
int nval, i;
u32 bit;
unsigned long addr;
struct sdw_dpn_prop *dpn;
prop->scp_int1_mask = SDW_SCP_INT1_IMPL_DEF | SDW_SCP_INT1_BUS_CLASH |
SDW_SCP_INT1_PARITY;
prop->quirks = SDW_SLAVE_QUIRKS_INVALID_INITIAL_PARITY;
prop->paging_support = false;
/* first we need to allocate memory for set bits in port lists */
......@@ -345,7 +350,6 @@ static int rt700_read_prop(struct sdw_slave *slave)
prop->sink_ports = 0xA; /* BITMAP: 00001010 */
nval = hweight32(prop->source_ports);
num_of_ports += nval;
prop->src_dpn_prop = devm_kcalloc(&slave->dev, nval,
sizeof(*prop->src_dpn_prop),
GFP_KERNEL);
......@@ -365,7 +369,6 @@ static int rt700_read_prop(struct sdw_slave *slave)
/* do this again for sink now */
nval = hweight32(prop->sink_ports);
num_of_ports += nval;
prop->sink_dpn_prop = devm_kcalloc(&slave->dev, nval,
sizeof(*prop->sink_dpn_prop),
GFP_KERNEL);
......@@ -383,17 +386,6 @@ static int rt700_read_prop(struct sdw_slave *slave)
i++;
}
/* Allocate port_ready based on num_of_ports */
slave->port_ready = devm_kcalloc(&slave->dev, num_of_ports,
sizeof(*slave->port_ready),
GFP_KERNEL);
if (!slave->port_ready)
return -ENOMEM;
/* Initialize completion */
for (i = 0; i < num_of_ports; i++)
init_completion(&slave->port_ready[i]);
/* set the timeout values */
prop->clk_stop_timeout = 20;
......
......@@ -11,6 +11,7 @@
#include <linux/mod_devicetable.h>
#include <linux/soundwire/sdw.h>
#include <linux/soundwire/sdw_type.h>
#include <linux/soundwire/sdw_registers.h>
#include <linux/module.h>
#include <linux/regmap.h>
#include <sound/soc.h>
......@@ -337,11 +338,15 @@ static int rt711_update_status(struct sdw_slave *slave,
static int rt711_read_prop(struct sdw_slave *slave)
{
struct sdw_slave_prop *prop = &slave->prop;
int nval, i, num_of_ports = 1;
int nval, i;
u32 bit;
unsigned long addr;
struct sdw_dpn_prop *dpn;
prop->scp_int1_mask = SDW_SCP_INT1_IMPL_DEF | SDW_SCP_INT1_BUS_CLASH |
SDW_SCP_INT1_PARITY;
prop->quirks = SDW_SLAVE_QUIRKS_INVALID_INITIAL_PARITY;
prop->paging_support = false;
/* first we need to allocate memory for set bits in port lists */
......@@ -349,7 +354,6 @@ static int rt711_read_prop(struct sdw_slave *slave)
prop->sink_ports = 0x8; /* BITMAP: 00001000 */
nval = hweight32(prop->source_ports);
num_of_ports += nval;
prop->src_dpn_prop = devm_kcalloc(&slave->dev, nval,
sizeof(*prop->src_dpn_prop),
GFP_KERNEL);
......@@ -369,7 +373,6 @@ static int rt711_read_prop(struct sdw_slave *slave)
/* do this again for sink now */
nval = hweight32(prop->sink_ports);
num_of_ports += nval;
prop->sink_dpn_prop = devm_kcalloc(&slave->dev, nval,
sizeof(*prop->sink_dpn_prop),
GFP_KERNEL);
......@@ -387,17 +390,6 @@ static int rt711_read_prop(struct sdw_slave *slave)
i++;
}
/* Allocate port_ready based on num_of_ports */
slave->port_ready = devm_kcalloc(&slave->dev, num_of_ports,
sizeof(*slave->port_ready),
GFP_KERNEL);
if (!slave->port_ready)
return -ENOMEM;
/* Initialize completion */
for (i = 0; i < num_of_ports; i++)
init_completion(&slave->port_ready[i]);
/* set the timeout values */
prop->clk_stop_timeout = 20;
......
......@@ -12,6 +12,7 @@
#include <linux/mod_devicetable.h>
#include <linux/soundwire/sdw.h>
#include <linux/soundwire/sdw_type.h>
#include <linux/soundwire/sdw_registers.h>
#include <linux/module.h>
#include <linux/of.h>
#include <linux/regmap.h>
......@@ -431,11 +432,15 @@ static int rt715_update_status(struct sdw_slave *slave,
static int rt715_read_prop(struct sdw_slave *slave)
{
struct sdw_slave_prop *prop = &slave->prop;
int nval, i, num_of_ports = 1;
int nval, i;
u32 bit;
unsigned long addr;
struct sdw_dpn_prop *dpn;
prop->scp_int1_mask = SDW_SCP_INT1_IMPL_DEF | SDW_SCP_INT1_BUS_CLASH |
SDW_SCP_INT1_PARITY;
prop->quirks = SDW_SLAVE_QUIRKS_INVALID_INITIAL_PARITY;
prop->paging_support = false;
/* first we need to allocate memory for set bits in port lists */
......@@ -443,7 +448,6 @@ static int rt715_read_prop(struct sdw_slave *slave)
prop->sink_ports = 0x0; /* BITMAP: 00000000 */
nval = hweight32(prop->source_ports);
num_of_ports += nval;
prop->src_dpn_prop = devm_kcalloc(&slave->dev, nval,
sizeof(*prop->src_dpn_prop),
GFP_KERNEL);
......@@ -460,36 +464,6 @@ static int rt715_read_prop(struct sdw_slave *slave)
i++;
}
/* do this again for sink now */
nval = hweight32(prop->sink_ports);
num_of_ports += nval;
prop->sink_dpn_prop = devm_kcalloc(&slave->dev, nval,
sizeof(*prop->sink_dpn_prop),
GFP_KERNEL);
if (!prop->sink_dpn_prop)
return -ENOMEM;
dpn = prop->sink_dpn_prop;
i = 0;
addr = prop->sink_ports;
for_each_set_bit(bit, &addr, 32) {
dpn[i].num = bit;
dpn[i].simple_ch_prep_sm = true;
dpn[i].ch_prep_timeout = 10;
i++;
}
/* Allocate port_ready based on num_of_ports */
slave->port_ready = devm_kcalloc(&slave->dev, num_of_ports,
sizeof(*slave->port_ready),
GFP_KERNEL);
if (!slave->port_ready)
return -ENOMEM;
/* Initialize completion */
for (i = 0; i < num_of_ports; i++)
init_completion(&slave->port_ready[i]);
/* set the timeout values */
prop->clk_stop_timeout = 20;
......
......@@ -1112,6 +1112,7 @@ static int wsa881x_probe(struct sdw_slave *pdev,
wsa881x->sconfig.type = SDW_STREAM_PDM;
pdev->prop.sink_ports = GENMASK(WSA881X_MAX_SWR_PORTS, 0);
pdev->prop.sink_dpn_prop = wsa_sink_dpn_prop;
pdev->prop.scp_int1_mask = SDW_SCP_INT1_BUS_CLASH | SDW_SCP_INT1_PARITY;
gpiod_direction_output(wsa881x->sd_n, 1);
wsa881x->regmap = devm_regmap_init_sdw(pdev, &wsa881x_regmap_config);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment