summaryrefslogtreecommitdiff
path: root/drivers/soundwire/bus.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/soundwire/bus.c')
-rw-r--r--drivers/soundwire/bus.c410
1 files changed, 271 insertions, 139 deletions
diff --git a/drivers/soundwire/bus.c b/drivers/soundwire/bus.c
index 76515c33e639..55c1db816534 100644
--- a/drivers/soundwire/bus.c
+++ b/drivers/soundwire/bus.c
@@ -8,11 +8,12 @@
#include <linux/soundwire/sdw_registers.h>
#include <linux/soundwire/sdw.h>
#include <linux/soundwire/sdw_type.h>
+#include <linux/string_choices.h>
#include "bus.h"
+#include "irq.h"
#include "sysfs_local.h"
static DEFINE_IDA(sdw_bus_ida);
-static DEFINE_IDA(sdw_peripheral_ida);
static int sdw_get_id(struct sdw_bus *bus)
{
@@ -22,6 +23,10 @@ static int sdw_get_id(struct sdw_bus *bus)
return rc;
bus->id = rc;
+
+ if (bus->controller_id == -1)
+ bus->controller_id = rc;
+
return 0;
}
@@ -51,6 +56,8 @@ int sdw_bus_master_add(struct sdw_bus *bus, struct device *parent,
return ret;
}
+ ida_init(&bus->slave_ida);
+
ret = sdw_master_device_add(bus, parent, fwnode);
if (ret < 0) {
dev_err(parent, "Failed to add master device at link %d\n",
@@ -69,8 +76,17 @@ int sdw_bus_master_add(struct sdw_bus *bus, struct device *parent,
return -EINVAL;
}
- mutex_init(&bus->msg_lock);
- mutex_init(&bus->bus_lock);
+ /*
+ * Give each bus_lock and msg_lock a unique key so that lockdep won't
+ * trigger a deadlock warning when the locks of several buses are
+ * grabbed during configuration of a multi-bus stream.
+ */
+ lockdep_register_key(&bus->msg_lock_key);
+ __mutex_init(&bus->msg_lock, "msg_lock", &bus->msg_lock_key);
+
+ lockdep_register_key(&bus->bus_lock_key);
+ __mutex_init(&bus->bus_lock, "bus_lock", &bus->bus_lock_key);
+
INIT_LIST_HEAD(&bus->slaves);
INIT_LIST_HEAD(&bus->m_rt_list);
@@ -99,7 +115,7 @@ int sdw_bus_master_add(struct sdw_bus *bus, struct device *parent,
/* Set higher order bits */
*bus->assigned = ~GENMASK(SDW_BROADCAST_DEV_NUM, SDW_ENUM_DEV_NUM);
- /* Set enumuration device number and broadcast device number */
+ /* Set enumeration device number and broadcast device number */
set_bit(SDW_ENUM_DEV_NUM, bus->assigned);
set_bit(SDW_BROADCAST_DEV_NUM, bus->assigned);
@@ -108,6 +124,10 @@ int sdw_bus_master_add(struct sdw_bus *bus, struct device *parent,
set_bit(SDW_GROUP13_DEV_NUM, bus->assigned);
set_bit(SDW_MASTER_DEV_NUM, bus->assigned);
+ ret = sdw_irq_create(bus, fwnode);
+ if (ret)
+ return ret;
+
/*
* SDW is an enumerable bus, but devices can be powered off. So,
* they won't be able to report as present.
@@ -124,6 +144,7 @@ int sdw_bus_master_add(struct sdw_bus *bus, struct device *parent,
if (ret < 0) {
dev_err(bus->dev, "Finding slaves failed:%d\n", ret);
+ sdw_irq_delete(bus);
return ret;
}
@@ -159,8 +180,8 @@ static int sdw_delete_slave(struct device *dev, void *data)
if (slave->dev_num) { /* clear dev_num if assigned */
clear_bit(slave->dev_num, bus->assigned);
- if (bus->dev_num_ida_min)
- ida_free(&sdw_peripheral_ida, slave->dev_num);
+ if (bus->ops && bus->ops->put_device_num)
+ bus->ops->put_device_num(bus, slave);
}
list_del_init(&slave->node);
mutex_unlock(&bus->bus_lock);
@@ -178,9 +199,14 @@ static int sdw_delete_slave(struct device *dev, void *data)
void sdw_bus_master_delete(struct sdw_bus *bus)
{
device_for_each_child(bus->dev, NULL, sdw_delete_slave);
+
+ sdw_irq_delete(bus);
+
sdw_master_device_del(bus);
sdw_bus_debugfs_exit(bus);
+ lockdep_unregister_key(&bus->bus_lock_key);
+ lockdep_unregister_key(&bus->msg_lock_key);
ida_free(&sdw_bus_ida, bus->id);
}
EXPORT_SYMBOL(sdw_bus_master_delete);
@@ -225,9 +251,9 @@ static inline int do_transfer(struct sdw_bus *bus, struct sdw_msg *msg)
}
static inline int do_transfer_defer(struct sdw_bus *bus,
- struct sdw_msg *msg,
- struct sdw_defer *defer)
+ struct sdw_msg *msg)
{
+ struct sdw_defer *defer = &bus->defer_msg;
int retry = bus->prop.err_threshold;
enum sdw_command_response resp;
int ret = 0, i;
@@ -237,24 +263,7 @@ static inline int do_transfer_defer(struct sdw_bus *bus,
init_completion(&defer->complete);
for (i = 0; i <= retry; i++) {
- resp = bus->ops->xfer_msg_defer(bus, msg, defer);
- ret = find_response_code(resp);
- /* if cmd is ok or ignored return */
- if (ret == 0 || ret == -ENODATA)
- return ret;
- }
-
- return ret;
-}
-
-static int sdw_reset_page(struct sdw_bus *bus, u16 dev_num)
-{
- int retry = bus->prop.err_threshold;
- enum sdw_command_response resp;
- int ret = 0, i;
-
- for (i = 0; i <= retry; i++) {
- resp = bus->ops->reset_page_addr(bus, dev_num);
+ resp = bus->ops->xfer_msg_defer(bus);
ret = find_response_code(resp);
/* if cmd is ok or ignored return */
if (ret == 0 || ret == -ENODATA)
@@ -272,12 +281,9 @@ static int sdw_transfer_unlocked(struct sdw_bus *bus, struct sdw_msg *msg)
if (ret != 0 && ret != -ENODATA)
dev_err(bus->dev, "trf on Slave %d failed:%d %s addr %x count %d\n",
msg->dev_num, ret,
- (msg->flags & SDW_MSG_FLAG_WRITE) ? "write" : "read",
+ str_write_read(msg->flags & SDW_MSG_FLAG_WRITE),
msg->addr, msg->len);
- if (msg->page)
- sdw_reset_page(bus, msg->dev_num);
-
return ret;
}
@@ -335,26 +341,21 @@ EXPORT_SYMBOL(sdw_show_ping_status);
* sdw_transfer_defer() - Asynchronously transfer message to a SDW Slave device
* @bus: SDW bus
* @msg: SDW message to be xfered
- * @defer: Defer block for signal completion
*
* Caller needs to hold the msg_lock lock while calling this
*/
-int sdw_transfer_defer(struct sdw_bus *bus, struct sdw_msg *msg,
- struct sdw_defer *defer)
+int sdw_transfer_defer(struct sdw_bus *bus, struct sdw_msg *msg)
{
int ret;
if (!bus->ops->xfer_msg_defer)
return -ENOTSUPP;
- ret = do_transfer_defer(bus, msg, defer);
+ ret = do_transfer_defer(bus, msg);
if (ret != 0 && ret != -ENODATA)
dev_err(bus->dev, "Defer trf on Slave %d failed:%d\n",
msg->dev_num, ret);
- if (msg->page)
- sdw_reset_page(bus, msg->dev_num);
-
return ret;
}
@@ -409,45 +410,73 @@ int sdw_fill_msg(struct sdw_msg *msg, struct sdw_slave *slave,
/*
* Read/Write IO functions.
- * no_pm versions can only be called by the bus, e.g. while enumerating or
- * handling suspend-resume sequences.
- * all clients need to use the pm versions
*/
-static int
-sdw_nread_no_pm(struct sdw_slave *slave, u32 addr, size_t count, u8 *val)
+static int sdw_ntransfer_no_pm(struct sdw_slave *slave, u32 addr, u8 flags,
+ size_t count, u8 *val)
{
struct sdw_msg msg;
+ size_t size;
int ret;
- ret = sdw_fill_msg(&msg, slave, addr, count,
- slave->dev_num, SDW_MSG_FLAG_READ, val);
- if (ret < 0)
- return ret;
+ while (count) {
+ // Only handle bytes up to next page boundary
+ size = min_t(size_t, count, (SDW_REGADDR + 1) - (addr & SDW_REGADDR));
- ret = sdw_transfer(slave->bus, &msg);
- if (slave->is_mockup_device)
- ret = 0;
- return ret;
+ ret = sdw_fill_msg(&msg, slave, addr, size, slave->dev_num, flags, val);
+ if (ret < 0)
+ return ret;
+
+ ret = sdw_transfer(slave->bus, &msg);
+ if (ret < 0 && !slave->is_mockup_device)
+ return ret;
+
+ addr += size;
+ val += size;
+ count -= size;
+ }
+
+ return 0;
}
-static int
-sdw_nwrite_no_pm(struct sdw_slave *slave, u32 addr, size_t count, const u8 *val)
+/**
+ * sdw_nread_no_pm() - Read "n" contiguous SDW Slave registers with no PM
+ * @slave: SDW Slave
+ * @addr: Register address
+ * @count: length
+ * @val: Buffer for values to be read
+ *
+ * Note that if the message crosses a page boundary each page will be
+ * transferred under a separate invocation of the msg_lock.
+ */
+int sdw_nread_no_pm(struct sdw_slave *slave, u32 addr, size_t count, u8 *val)
{
- struct sdw_msg msg;
- int ret;
-
- ret = sdw_fill_msg(&msg, slave, addr, count,
- slave->dev_num, SDW_MSG_FLAG_WRITE, (u8 *)val);
- if (ret < 0)
- return ret;
+ return sdw_ntransfer_no_pm(slave, addr, SDW_MSG_FLAG_READ, count, val);
+}
+EXPORT_SYMBOL(sdw_nread_no_pm);
- ret = sdw_transfer(slave->bus, &msg);
- if (slave->is_mockup_device)
- ret = 0;
- return ret;
+/**
+ * sdw_nwrite_no_pm() - Write "n" contiguous SDW Slave registers with no PM
+ * @slave: SDW Slave
+ * @addr: Register address
+ * @count: length
+ * @val: Buffer for values to be written
+ *
+ * Note that if the message crosses a page boundary each page will be
+ * transferred under a separate invocation of the msg_lock.
+ */
+int sdw_nwrite_no_pm(struct sdw_slave *slave, u32 addr, size_t count, const u8 *val)
+{
+ return sdw_ntransfer_no_pm(slave, addr, SDW_MSG_FLAG_WRITE, count, (u8 *)val);
}
+EXPORT_SYMBOL(sdw_nwrite_no_pm);
+/**
+ * sdw_write_no_pm() - Write a SDW Slave register with no PM
+ * @slave: SDW Slave
+ * @addr: Register address
+ * @value: Register value
+ */
int sdw_write_no_pm(struct sdw_slave *slave, u32 addr, u8 value)
{
return sdw_nwrite_no_pm(slave, addr, 1, &value);
@@ -520,6 +549,11 @@ int sdw_bwrite_no_pm_unlocked(struct sdw_bus *bus, u16 dev_num, u32 addr, u8 val
}
EXPORT_SYMBOL(sdw_bwrite_no_pm_unlocked);
+/**
+ * sdw_read_no_pm() - Read a SDW Slave register with no PM
+ * @slave: SDW Slave
+ * @addr: Register address
+ */
int sdw_read_no_pm(struct sdw_slave *slave, u32 addr)
{
u8 buf;
@@ -566,14 +600,21 @@ EXPORT_SYMBOL(sdw_update);
* @addr: Register address
* @count: length
* @val: Buffer for values to be read
+ *
+ * This version of the function will take a PM reference to the slave
+ * device.
+ * Note that if the message crosses a page boundary each page will be
+ * transferred under a separate invocation of the msg_lock.
*/
int sdw_nread(struct sdw_slave *slave, u32 addr, size_t count, u8 *val)
{
int ret;
- ret = pm_runtime_resume_and_get(&slave->dev);
- if (ret < 0 && ret != -EACCES)
+ ret = pm_runtime_get_sync(&slave->dev);
+ if (ret < 0 && ret != -EACCES) {
+ pm_runtime_put_noidle(&slave->dev);
return ret;
+ }
ret = sdw_nread_no_pm(slave, addr, count, val);
@@ -590,14 +631,21 @@ EXPORT_SYMBOL(sdw_nread);
* @addr: Register address
* @count: length
* @val: Buffer for values to be written
+ *
+ * This version of the function will take a PM reference to the slave
+ * device.
+ * Note that if the message crosses a page boundary each page will be
+ * transferred under a separate invocation of the msg_lock.
*/
int sdw_nwrite(struct sdw_slave *slave, u32 addr, size_t count, const u8 *val)
{
int ret;
- ret = pm_runtime_resume_and_get(&slave->dev);
- if (ret < 0 && ret != -EACCES)
+ ret = pm_runtime_get_sync(&slave->dev);
+ if (ret < 0 && ret != -EACCES) {
+ pm_runtime_put_noidle(&slave->dev);
return ret;
+ }
ret = sdw_nwrite_no_pm(slave, addr, count, val);
@@ -612,6 +660,9 @@ EXPORT_SYMBOL(sdw_nwrite);
* sdw_read() - Read a SDW Slave register
* @slave: SDW Slave
* @addr: Register address
+ *
+ * This version of the function will take a PM reference to the slave
+ * device.
*/
int sdw_read(struct sdw_slave *slave, u32 addr)
{
@@ -631,6 +682,9 @@ EXPORT_SYMBOL(sdw_read);
* @slave: SDW Slave
* @addr: Register address
* @value: Register value
+ *
+ * This version of the function will take a PM reference to the slave
+ * device.
*/
int sdw_write(struct sdw_slave *slave, u32 addr, u8 value)
{
@@ -671,16 +725,15 @@ EXPORT_SYMBOL(sdw_compare_devid);
/* called with bus_lock held */
static int sdw_get_device_num(struct sdw_slave *slave)
{
+ struct sdw_bus *bus = slave->bus;
int bit;
- if (slave->bus->dev_num_ida_min) {
- bit = ida_alloc_range(&sdw_peripheral_ida,
- slave->bus->dev_num_ida_min, SDW_MAX_DEVICES,
- GFP_KERNEL);
+ if (bus->ops && bus->ops->get_device_num) {
+ bit = bus->ops->get_device_num(bus, slave);
if (bit < 0)
goto err;
} else {
- bit = find_first_zero_bit(slave->bus->assigned, SDW_MAX_DEVICES);
+ bit = find_first_zero_bit(bus->assigned, SDW_MAX_DEVICES);
if (bit == SDW_MAX_DEVICES) {
bit = -ENODEV;
goto err;
@@ -691,7 +744,7 @@ static int sdw_get_device_num(struct sdw_slave *slave)
* Do not update dev_num in Slave data structure here,
* Update once program dev_num is successful
*/
- set_bit(bit, slave->bus->assigned);
+ set_bit(bit, bus->assigned);
err:
return bit;
@@ -700,47 +753,45 @@ err:
static int sdw_assign_device_num(struct sdw_slave *slave)
{
struct sdw_bus *bus = slave->bus;
- int ret, dev_num;
- bool new_device = false;
+ struct device *dev = bus->dev;
+ int ret;
/* check first if device number is assigned, if so reuse that */
if (!slave->dev_num) {
if (!slave->dev_num_sticky) {
+ int dev_num;
+
mutex_lock(&slave->bus->bus_lock);
dev_num = sdw_get_device_num(slave);
mutex_unlock(&slave->bus->bus_lock);
if (dev_num < 0) {
- dev_err(bus->dev, "Get dev_num failed: %d\n",
- dev_num);
+ dev_err(dev, "Get dev_num failed: %d\n", dev_num);
return dev_num;
}
- slave->dev_num = dev_num;
+
slave->dev_num_sticky = dev_num;
- new_device = true;
} else {
- slave->dev_num = slave->dev_num_sticky;
+ dev_dbg(dev, "Slave already registered, reusing dev_num: %d\n",
+ slave->dev_num_sticky);
}
}
- if (!new_device)
- dev_dbg(bus->dev,
- "Slave already registered, reusing dev_num:%d\n",
- slave->dev_num);
-
/* Clear the slave->dev_num to transfer message on device 0 */
- dev_num = slave->dev_num;
slave->dev_num = 0;
- ret = sdw_write_no_pm(slave, SDW_SCP_DEVNUMBER, dev_num);
+ ret = sdw_write_no_pm(slave, SDW_SCP_DEVNUMBER, slave->dev_num_sticky);
if (ret < 0) {
- dev_err(bus->dev, "Program device_num %d failed: %d\n",
- dev_num, ret);
+ dev_err(dev, "Program device_num %d failed: %d\n",
+ slave->dev_num_sticky, ret);
return ret;
}
/* After xfer of msg, restore dev_num */
slave->dev_num = slave->dev_num_sticky;
+ if (bus->ops && bus->ops->new_peripheral_assigned)
+ bus->ops->new_peripheral_assigned(bus, slave, slave->dev_num);
+
return 0;
}
@@ -761,6 +812,16 @@ void sdw_extract_slave_id(struct sdw_bus *bus,
}
EXPORT_SYMBOL(sdw_extract_slave_id);
+bool is_clock_scaling_supported_by_slave(struct sdw_slave *slave)
+{
+ /*
+ * Dynamic scaling is a defined by SDCA. However, some devices expose the class ID but
+ * can't support dynamic scaling. We might need a quirk to handle such devices.
+ */
+ return slave->id.class_id;
+}
+EXPORT_SYMBOL(is_clock_scaling_supported_by_slave);
+
static int sdw_program_device_num(struct sdw_bus *bus, bool *programmed)
{
u8 buf[SDW_NUM_DEV_ID_REGISTERS] = {0};
@@ -880,8 +941,8 @@ static void sdw_modify_slave_status(struct sdw_slave *slave,
"initializing enumeration and init completion for Slave %d\n",
slave->dev_num);
- init_completion(&slave->enumeration_complete);
- init_completion(&slave->initialization_complete);
+ reinit_completion(&slave->enumeration_complete);
+ reinit_completion(&slave->initialization_complete);
} else if ((status == SDW_SLAVE_ATTACHED) &&
(slave->status == SDW_SLAVE_UNATTACHED)) {
@@ -889,7 +950,7 @@ static void sdw_modify_slave_status(struct sdw_slave *slave,
"signaling enumeration completion for Slave %d\n",
slave->dev_num);
- complete(&slave->enumeration_complete);
+ complete_all(&slave->enumeration_complete);
}
slave->status = status;
mutex_unlock(&bus->bus_lock);
@@ -953,7 +1014,7 @@ static int sdw_slave_clk_stop_prepare(struct sdw_slave *slave,
return ret;
}
-static int sdw_bus_wait_for_clk_prep_deprep(struct sdw_bus *bus, u16 dev_num)
+static int sdw_bus_wait_for_clk_prep_deprep(struct sdw_bus *bus, u16 dev_num, bool prepare)
{
int retry = bus->clk_stop_timeout;
int val;
@@ -967,7 +1028,8 @@ static int sdw_bus_wait_for_clk_prep_deprep(struct sdw_bus *bus, u16 dev_num)
}
val &= SDW_SCP_STAT_CLK_STP_NF;
if (!val) {
- dev_dbg(bus->dev, "clock stop prep/de-prep done slave:%d\n",
+ dev_dbg(bus->dev, "clock stop %s done slave:%d\n",
+ prepare ? "prepare" : "deprepare",
dev_num);
return 0;
}
@@ -976,7 +1038,8 @@ static int sdw_bus_wait_for_clk_prep_deprep(struct sdw_bus *bus, u16 dev_num)
retry--;
} while (retry);
- dev_err(bus->dev, "clock stop prep/de-prep failed slave:%d\n",
+ dev_dbg(bus->dev, "clock stop %s did not complete for slave:%d\n",
+ prepare ? "prepare" : "deprepare",
dev_num);
return -ETIMEDOUT;
@@ -1047,7 +1110,7 @@ int sdw_bus_prep_clk_stop(struct sdw_bus *bus)
*/
if (!simple_clk_stop) {
ret = sdw_bus_wait_for_clk_prep_deprep(bus,
- SDW_BROADCAST_DEV_NUM);
+ SDW_BROADCAST_DEV_NUM, true);
/*
* if there are no Slave devices present and the reply is
* Command_Ignored/-ENODATA, we don't need to continue with the
@@ -1167,7 +1230,7 @@ int sdw_bus_exit_clk_stop(struct sdw_bus *bus)
* state machine
*/
if (!simple_clk_stop) {
- ret = sdw_bus_wait_for_clk_prep_deprep(bus, SDW_BROADCAST_DEV_NUM);
+ ret = sdw_bus_wait_for_clk_prep_deprep(bus, SDW_BROADCAST_DEV_NUM, false);
if (ret < 0)
dev_warn(bus->dev, "clock stop deprepare wait failed:%d\n", ret);
}
@@ -1199,7 +1262,7 @@ int sdw_configure_dpn_intr(struct sdw_slave *slave,
if (slave->bus->params.s_data_mode != SDW_PORT_DATA_MODE_NORMAL) {
dev_dbg(&slave->dev, "TEST FAIL interrupt %s\n",
- enable ? "on" : "off");
+ str_on_off(enable));
mask |= SDW_DPN_INT_TEST_FAIL;
}
@@ -1214,7 +1277,7 @@ int sdw_configure_dpn_intr(struct sdw_slave *slave,
val &= ~SDW_DPN_INT_PORT_READY;
}
- ret = sdw_update(slave, addr, (mask | SDW_DPN_INT_PORT_READY), val);
+ ret = sdw_update_no_pm(slave, addr, (mask | SDW_DPN_INT_PORT_READY), val);
if (ret < 0)
dev_err(&slave->dev,
"SDW_DPN_INTMASK write failed:%d\n", val);
@@ -1222,22 +1285,12 @@ int sdw_configure_dpn_intr(struct sdw_slave *slave,
return ret;
}
-static int sdw_slave_set_frequency(struct sdw_slave *slave)
+int sdw_slave_get_scale_index(struct sdw_slave *slave, u8 *base)
{
u32 mclk_freq = slave->bus->prop.mclk_freq;
u32 curr_freq = slave->bus->params.curr_dr_freq >> 1;
unsigned int scale;
u8 scale_index;
- u8 base;
- int ret;
-
- /*
- * frequency base and scale registers are required for SDCA
- * devices. They may also be used for 1.2+/non-SDCA devices,
- * but we will need a DisCo property to cover this case
- */
- if (!slave->id.class_id)
- return 0;
if (!mclk_freq) {
dev_err(&slave->dev,
@@ -1256,19 +1309,19 @@ static int sdw_slave_set_frequency(struct sdw_slave *slave)
*/
if (!(19200000 % mclk_freq)) {
mclk_freq = 19200000;
- base = SDW_SCP_BASE_CLOCK_19200000_HZ;
- } else if (!(24000000 % mclk_freq)) {
- mclk_freq = 24000000;
- base = SDW_SCP_BASE_CLOCK_24000000_HZ;
- } else if (!(24576000 % mclk_freq)) {
- mclk_freq = 24576000;
- base = SDW_SCP_BASE_CLOCK_24576000_HZ;
+ *base = SDW_SCP_BASE_CLOCK_19200000_HZ;
} else if (!(22579200 % mclk_freq)) {
mclk_freq = 22579200;
- base = SDW_SCP_BASE_CLOCK_22579200_HZ;
+ *base = SDW_SCP_BASE_CLOCK_22579200_HZ;
+ } else if (!(24576000 % mclk_freq)) {
+ mclk_freq = 24576000;
+ *base = SDW_SCP_BASE_CLOCK_24576000_HZ;
} else if (!(32000000 % mclk_freq)) {
mclk_freq = 32000000;
- base = SDW_SCP_BASE_CLOCK_32000000_HZ;
+ *base = SDW_SCP_BASE_CLOCK_32000000_HZ;
+ } else if (!(96000000 % mclk_freq)) {
+ mclk_freq = 24000000;
+ *base = SDW_SCP_BASE_CLOCK_24000000_HZ;
} else {
dev_err(&slave->dev,
"Unsupported clock base, mclk %d\n",
@@ -1299,6 +1352,46 @@ static int sdw_slave_set_frequency(struct sdw_slave *slave)
}
scale_index++;
+ dev_dbg(&slave->dev,
+ "Configured bus base %d, scale %d, mclk %d, curr_freq %d\n",
+ *base, scale_index, mclk_freq, curr_freq);
+
+ return scale_index;
+}
+EXPORT_SYMBOL(sdw_slave_get_scale_index);
+
+int sdw_slave_get_current_bank(struct sdw_slave *slave)
+{
+ int tmp;
+
+ tmp = sdw_read(slave, SDW_SCP_CTRL);
+ if (tmp < 0)
+ return tmp;
+
+ return FIELD_GET(SDW_SCP_STAT_CURR_BANK, tmp);
+}
+EXPORT_SYMBOL_GPL(sdw_slave_get_current_bank);
+
+static int sdw_slave_set_frequency(struct sdw_slave *slave)
+{
+ int scale_index;
+ u8 base;
+ int ret;
+
+ /*
+ * frequency base and scale registers are required for SDCA
+ * devices. They may also be used for 1.2+/non-SDCA devices.
+ * Driver can set the property directly, for now there's no
+ * DisCo property to discover support for the scaling registers
+ * from platform firmware.
+ */
+ if (!slave->id.class_id && !slave->prop.clock_reg_supported)
+ return 0;
+
+ scale_index = sdw_slave_get_scale_index(slave, &base);
+ if (scale_index < 0)
+ return scale_index;
+
ret = sdw_write_no_pm(slave, SDW_SCP_BUS_CLOCK_BASE, base);
if (ret < 0) {
dev_err(&slave->dev,
@@ -1318,10 +1411,6 @@ static int sdw_slave_set_frequency(struct sdw_slave *slave)
dev_err(&slave->dev,
"SDW_SCP_BUSCLOCK_SCALE_B1 write failed:%d\n", ret);
- dev_dbg(&slave->dev,
- "Configured bus base %d, scale %d, mclk %d, curr_freq %d\n",
- base, scale_index, mclk_freq, curr_freq);
-
return ret;
}
@@ -1355,7 +1444,7 @@ static int sdw_initialize_slave(struct sdw_slave *slave)
}
}
if ((slave->bus->prop.quirks & SDW_MASTER_QUIRKS_CLEAR_INITIAL_PARITY) &&
- !(slave->prop.quirks & SDW_SLAVE_QUIRKS_INVALID_INITIAL_PARITY)) {
+ !(prop->quirks & SDW_SLAVE_QUIRKS_INVALID_INITIAL_PARITY)) {
/* Clear parity interrupt before enabling interrupt mask */
status = sdw_read_no_pm(slave, SDW_SCP_INT1);
if (status < 0) {
@@ -1381,7 +1470,7 @@ static int sdw_initialize_slave(struct sdw_slave *slave)
* device-dependent, it might e.g. only be enabled in
* steady-state after a couple of frames.
*/
- val = slave->prop.scp_int1_mask;
+ val = prop->scp_int1_mask;
/* Enable SCP interrupts */
ret = sdw_update_no_pm(slave, SDW_SCP_INTMASK1, val, val);
@@ -1392,7 +1481,7 @@ static int sdw_initialize_slave(struct sdw_slave *slave)
}
/* No need to continue if DP0 is not present */
- if (!slave->prop.dp0_prop)
+ if (!prop->dp0_prop)
return 0;
/* Enable DP0 interrupts */
@@ -1419,7 +1508,7 @@ static int sdw_handle_dp0_interrupt(struct sdw_slave *slave, u8 *slave_status)
}
do {
- clear = status & ~SDW_DP0_INTERRUPTS;
+ clear = status & ~(SDW_DP0_INTERRUPTS | SDW_DP0_SDCA_CASCADE);
if (status & SDW_DP0_INT_TEST_FAIL) {
dev_err(&slave->dev, "Test fail for port 0\n");
@@ -1559,15 +1648,16 @@ static int sdw_handle_slave_alerts(struct sdw_slave *slave)
unsigned long port;
bool slave_notify;
u8 sdca_cascade = 0;
- u8 buf, buf2[2], _buf, _buf2[2];
+ u8 buf, buf2[2];
bool parity_check;
bool parity_quirk;
sdw_modify_slave_status(slave, SDW_SLAVE_ALERT);
- ret = pm_runtime_resume_and_get(&slave->dev);
+ ret = pm_runtime_get_sync(&slave->dev);
if (ret < 0 && ret != -EACCES) {
dev_err(&slave->dev, "Failed to resume device: %d\n", ret);
+ pm_runtime_put_noidle(&slave->dev);
return ret;
}
@@ -1587,7 +1677,7 @@ static int sdw_handle_slave_alerts(struct sdw_slave *slave)
goto io_err;
}
- if (slave->prop.is_sdca) {
+ if (slave->id.class_id) {
ret = sdw_read_no_pm(slave, SDW_DP0_INT);
if (ret < 0) {
dev_err(&slave->dev,
@@ -1675,6 +1765,9 @@ static int sdw_handle_slave_alerts(struct sdw_slave *slave)
/* Update the Slave driver */
if (slave_notify) {
+ if (slave->prop.use_domain_irq && slave->irq)
+ handle_nested_irq(slave->irq);
+
mutex_lock(&slave->sdw_dev_lock);
if (slave->probed) {
@@ -1715,16 +1808,16 @@ static int sdw_handle_slave_alerts(struct sdw_slave *slave)
"SDW_SCP_INT1 recheck read failed:%d\n", ret);
goto io_err;
}
- _buf = ret;
+ buf = ret;
- ret = sdw_nread_no_pm(slave, SDW_SCP_INTSTAT2, 2, _buf2);
+ ret = sdw_nread_no_pm(slave, SDW_SCP_INTSTAT2, 2, buf2);
if (ret < 0) {
dev_err(&slave->dev,
"SDW_SCP_INT2/3 recheck read failed:%d\n", ret);
goto io_err;
}
- if (slave->prop.is_sdca) {
+ if (slave->id.class_id) {
ret = sdw_read_no_pm(slave, SDW_DP0_INT);
if (ret < 0) {
dev_err(&slave->dev,
@@ -1735,12 +1828,8 @@ static int sdw_handle_slave_alerts(struct sdw_slave *slave)
}
/*
- * Make sure no interrupts are pending, but filter to limit loop
- * to interrupts identified in the first status read
+ * Make sure no interrupts are pending
*/
- buf &= _buf;
- buf2[0] &= _buf2[0];
- buf2[1] &= _buf2[1];
stat = buf || buf2[0] || buf2[1] || sdca_cascade;
/*
@@ -1911,7 +2000,7 @@ int sdw_handle_slave_status(struct sdw_bus *bus,
"signaling initialization completion for Slave %d\n",
slave->dev_num);
- complete(&slave->initialization_complete);
+ complete_all(&slave->initialization_complete);
/*
* If the manager became pm_runtime active, the peripherals will be
@@ -1960,3 +2049,46 @@ void sdw_clear_slave_status(struct sdw_bus *bus, u32 request)
}
}
EXPORT_SYMBOL(sdw_clear_slave_status);
+
+int sdw_bpt_send_async(struct sdw_bus *bus, struct sdw_slave *slave, struct sdw_bpt_msg *msg)
+{
+ if (msg->len > SDW_BPT_MSG_MAX_BYTES) {
+ dev_err(bus->dev, "Invalid BPT message length %d\n", msg->len);
+ return -EINVAL;
+ }
+
+ /* check device is enumerated */
+ if (slave->dev_num == SDW_ENUM_DEV_NUM ||
+ slave->dev_num > SDW_MAX_DEVICES) {
+ dev_err(&slave->dev, "Invalid device number %d\n", slave->dev_num);
+ return -ENODEV;
+ }
+
+ /* make sure all callbacks are defined */
+ if (!bus->ops->bpt_send_async ||
+ !bus->ops->bpt_wait) {
+ dev_err(bus->dev, "BPT callbacks not defined\n");
+ return -EOPNOTSUPP;
+ }
+
+ return bus->ops->bpt_send_async(bus, slave, msg);
+}
+EXPORT_SYMBOL(sdw_bpt_send_async);
+
+int sdw_bpt_wait(struct sdw_bus *bus, struct sdw_slave *slave, struct sdw_bpt_msg *msg)
+{
+ return bus->ops->bpt_wait(bus, slave, msg);
+}
+EXPORT_SYMBOL(sdw_bpt_wait);
+
+int sdw_bpt_send_sync(struct sdw_bus *bus, struct sdw_slave *slave, struct sdw_bpt_msg *msg)
+{
+ int ret;
+
+ ret = sdw_bpt_send_async(bus, slave, msg);
+ if (ret < 0)
+ return ret;
+
+ return sdw_bpt_wait(bus, slave, msg);
+}
+EXPORT_SYMBOL(sdw_bpt_send_sync);