diff options
Diffstat (limited to 'drivers/soundwire/bus.c')
| -rw-r--r-- | drivers/soundwire/bus.c | 600 |
1 files changed, 412 insertions, 188 deletions
diff --git a/drivers/soundwire/bus.c b/drivers/soundwire/bus.c index 67369e941d0d..55c1db816534 100644 --- a/drivers/soundwire/bus.c +++ b/drivers/soundwire/bus.c @@ -7,19 +7,26 @@ #include <linux/pm_runtime.h> #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_ida); +static DEFINE_IDA(sdw_bus_ida); static int sdw_get_id(struct sdw_bus *bus) { - int rc = ida_alloc(&sdw_ida, GFP_KERNEL); + int rc = ida_alloc(&sdw_bus_ida, GFP_KERNEL); if (rc < 0) return rc; bus->id = rc; + + if (bus->controller_id == -1) + bus->controller_id = rc; + return 0; } @@ -49,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", @@ -67,14 +76,22 @@ 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); /* * Initialize multi_link flag - * TODO: populate this flag by reading property from FW node */ bus->multi_link = false; if (bus->ops->read_prop) { @@ -98,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); @@ -107,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. @@ -123,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; } @@ -156,9 +178,11 @@ static int sdw_delete_slave(struct device *dev, void *data) mutex_lock(&bus->bus_lock); - if (slave->dev_num) /* clear dev_num if assigned */ + if (slave->dev_num) { /* clear dev_num if assigned */ clear_bit(slave->dev_num, bus->assigned); - + 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); @@ -175,10 +199,15 @@ 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); - ida_free(&sdw_ida, bus->id); + 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); @@ -222,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; @@ -234,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) @@ -269,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; } @@ -297,29 +306,56 @@ int sdw_transfer(struct sdw_bus *bus, struct sdw_msg *msg) } /** + * sdw_show_ping_status() - Direct report of PING status, to be used by Peripheral drivers + * @bus: SDW bus + * @sync_delay: Delay before reading status + */ +void sdw_show_ping_status(struct sdw_bus *bus, bool sync_delay) +{ + u32 status; + + if (!bus->ops->read_ping_status) + return; + + /* + * wait for peripheral to sync if desired. 10-15ms should be more than + * enough in most cases. + */ + if (sync_delay) + usleep_range(10000, 15000); + + mutex_lock(&bus->msg_lock); + + status = bus->ops->read_ping_status(bus); + + mutex_unlock(&bus->msg_lock); + + if (!status) + dev_warn(bus->dev, "%s: no peripherals attached\n", __func__); + else + dev_dbg(bus->dev, "PING status: %#x\n", status); +} +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; } @@ -374,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); @@ -485,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; @@ -531,6 +600,11 @@ 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) { @@ -557,6 +631,11 @@ 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) { @@ -581,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) { @@ -600,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) { @@ -640,19 +725,26 @@ 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; - bit = find_first_zero_bit(slave->bus->assigned, SDW_MAX_DEVICES); - if (bit == SDW_MAX_DEVICES) { - bit = -ENODEV; - goto err; + 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(bus->assigned, SDW_MAX_DEVICES); + if (bit == SDW_MAX_DEVICES) { + bit = -ENODEV; + goto err; + } } /* * 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; @@ -661,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; } @@ -722,7 +812,17 @@ void sdw_extract_slave_id(struct sdw_bus *bus, } EXPORT_SYMBOL(sdw_extract_slave_id); -static int sdw_program_device_num(struct sdw_bus *bus) +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}; struct sdw_slave *slave, *_s; @@ -732,6 +832,8 @@ static int sdw_program_device_num(struct sdw_bus *bus) int count = 0, ret; u64 addr; + *programmed = false; + /* No Slave, so use raw xfer api */ ret = sdw_fill_msg(&msg, NULL, SDW_SCP_DEVID_0, SDW_NUM_DEV_ID_REGISTERS, 0, SDW_MSG_FLAG_READ, buf); @@ -767,6 +869,16 @@ static int sdw_program_device_num(struct sdw_bus *bus) found = true; /* + * To prevent skipping state-machine stages don't + * program a device until we've seen it UNATTACH. + * Must return here because no other device on #0 + * can be detected until this one has been + * assigned a device ID. + */ + if (slave->status != SDW_SLAVE_UNATTACHED) + return 0; + + /* * Assign a new dev_num to this Slave and * not mark it present. It will be marked * present after it reports ATTACHED on new @@ -780,6 +892,8 @@ static int sdw_program_device_num(struct sdw_bus *bus) return ret; } + *programmed = true; + break; } } @@ -819,24 +933,24 @@ static void sdw_modify_slave_status(struct sdw_slave *slave, mutex_lock(&bus->bus_lock); dev_vdbg(bus->dev, - "%s: changing status slave %d status %d new status %d\n", - __func__, slave->dev_num, slave->status, status); + "changing status slave %d status %d new status %d\n", + slave->dev_num, slave->status, status); if (status == SDW_SLAVE_UNATTACHED) { dev_dbg(&slave->dev, - "%s: initializing enumeration and init completion for Slave %d\n", - __func__, slave->dev_num); + "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)) { dev_dbg(&slave->dev, - "%s: signaling enumeration completion for Slave %d\n", - __func__, slave->dev_num); + "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); @@ -846,15 +960,21 @@ static int sdw_slave_clk_stop_callback(struct sdw_slave *slave, enum sdw_clk_stop_mode mode, enum sdw_clk_stop_type type) { - int ret; + int ret = 0; - if (slave->ops && slave->ops->clk_stop) { - ret = slave->ops->clk_stop(slave, mode, type); - if (ret < 0) - return ret; + mutex_lock(&slave->sdw_dev_lock); + + if (slave->probed) { + struct device *dev = &slave->dev; + struct sdw_driver *drv = drv_to_sdw_driver(dev->driver); + + if (drv->ops && drv->ops->clk_stop) + ret = drv->ops->clk_stop(slave, mode, type); } - return 0; + mutex_unlock(&slave->sdw_dev_lock); + + return ret; } static int sdw_slave_clk_stop_prepare(struct sdw_slave *slave, @@ -894,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; @@ -908,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; } @@ -917,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; @@ -988,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 @@ -1108,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); } @@ -1140,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; } @@ -1155,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); @@ -1163,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, @@ -1197,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", @@ -1240,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, @@ -1259,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; } @@ -1296,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) { @@ -1322,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); @@ -1333,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 */ @@ -1360,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"); @@ -1500,7 +1648,7 @@ 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; @@ -1529,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, @@ -1596,7 +1744,7 @@ static int sdw_handle_slave_alerts(struct sdw_slave *slave) port = buf2[0] & SDW_SCP_INTSTAT2_PORT4_10; for_each_set_bit(bit, &port, 8) { /* scp2 ports start from 4 */ - port_num = bit + 3; + port_num = bit + 4; sdw_handle_port_interrupt(slave, port_num, &port_status[port_num]); @@ -1608,7 +1756,7 @@ static int sdw_handle_slave_alerts(struct sdw_slave *slave) port = buf2[1] & SDW_SCP_INTSTAT3_PORT11_14; for_each_set_bit(bit, &port, 8) { /* scp3 ports start from 11 */ - port_num = bit + 10; + port_num = bit + 11; sdw_handle_port_interrupt(slave, port_num, &port_status[port_num]); @@ -1616,14 +1764,27 @@ static int sdw_handle_slave_alerts(struct sdw_slave *slave) } /* Update the Slave driver */ - if (slave_notify && slave->ops && - slave->ops->interrupt_callback) { - slave_intr.sdca_cascade = sdca_cascade; - slave_intr.control_port = clear; - memcpy(slave_intr.port, &port_status, - sizeof(slave_intr.port)); - - slave->ops->interrupt_callback(slave, &slave_intr); + 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) { + struct device *dev = &slave->dev; + struct sdw_driver *drv = drv_to_sdw_driver(dev->driver); + + if (drv->ops && drv->ops->interrupt_callback) { + slave_intr.sdca_cascade = sdca_cascade; + slave_intr.control_port = clear; + memcpy(slave_intr.port, &port_status, + sizeof(slave_intr.port)); + + drv->ops->interrupt_callback(slave, &slave_intr); + } + } + + mutex_unlock(&slave->sdw_dev_lock); } /* Ack interrupt */ @@ -1647,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, @@ -1667,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; /* @@ -1697,29 +1854,21 @@ io_err: static int sdw_update_slave_status(struct sdw_slave *slave, enum sdw_slave_status status) { - unsigned long time; + int ret = 0; - if (!slave->probed) { - /* - * the slave status update is typically handled in an - * interrupt thread, which can race with the driver - * probe, e.g. when a module needs to be loaded. - * - * make sure the probe is complete before updating - * status. - */ - time = wait_for_completion_timeout(&slave->probe_complete, - msecs_to_jiffies(DEFAULT_PROBE_TIMEOUT)); - if (!time) { - dev_err(&slave->dev, "Probe not complete, timed out\n"); - return -ETIMEDOUT; - } + mutex_lock(&slave->sdw_dev_lock); + + if (slave->probed) { + struct device *dev = &slave->dev; + struct sdw_driver *drv = drv_to_sdw_driver(dev->driver); + + if (drv->ops && drv->ops->update_status) + ret = drv->ops->update_status(slave, status); } - if (!slave->ops || !slave->ops->update_status) - return 0; + mutex_unlock(&slave->sdw_dev_lock); - return slave->ops->update_status(slave, status); + return ret; } /** @@ -1732,7 +1881,7 @@ int sdw_handle_slave_status(struct sdw_bus *bus, { enum sdw_slave_status prev_status; struct sdw_slave *slave; - bool attached_initializing; + bool attached_initializing, id_programmed; int i, ret = 0; /* first check if any Slaves fell off the bus */ @@ -1749,20 +1898,37 @@ int sdw_handle_slave_status(struct sdw_bus *bus, continue; if (status[i] == SDW_SLAVE_UNATTACHED && - slave->status != SDW_SLAVE_UNATTACHED) + slave->status != SDW_SLAVE_UNATTACHED) { + dev_warn(&slave->dev, "Slave %d state check1: UNATTACHED, status was %d\n", + i, slave->status); sdw_modify_slave_status(slave, SDW_SLAVE_UNATTACHED); + + /* Ensure driver knows that peripheral unattached */ + ret = sdw_update_slave_status(slave, status[i]); + if (ret < 0) + dev_warn(&slave->dev, "Update Slave status failed:%d\n", ret); + } } if (status[0] == SDW_SLAVE_ATTACHED) { dev_dbg(bus->dev, "Slave attached, programming device number\n"); - ret = sdw_program_device_num(bus); - if (ret < 0) - dev_err(bus->dev, "Slave attach failed: %d\n", ret); + /* - * programming a device number will have side effects, - * so we deal with other devices at a later time + * Programming a device number will have side effects, + * so we deal with other devices at a later time. + * This relies on those devices reporting ATTACHED, which will + * trigger another call to this function. This will only + * happen if at least one device ID was programmed. + * Error returns from sdw_program_device_num() are currently + * ignored because there's no useful recovery that can be done. + * Returning the error here could result in the current status + * of other devices not being handled, because if no device IDs + * were programmed there's nothing to guarantee a status change + * to trigger another call to this function. */ - return ret; + sdw_program_device_num(bus, &id_programmed); + if (id_programmed) + return 0; } /* Continue to check other slave statuses */ @@ -1785,6 +1951,9 @@ int sdw_handle_slave_status(struct sdw_bus *bus, if (slave->status == SDW_SLAVE_UNATTACHED) break; + dev_warn(&slave->dev, "Slave %d state check2: UNATTACHED, status was %d\n", + i, slave->status); + sdw_modify_slave_status(slave, SDW_SLAVE_UNATTACHED); break; @@ -1828,10 +1997,22 @@ int sdw_handle_slave_status(struct sdw_bus *bus, "Update Slave status failed:%d\n", ret); if (attached_initializing) { dev_dbg(&slave->dev, - "%s: signaling initialization completion for Slave %d\n", - __func__, slave->dev_num); + "signaling initialization completion for Slave %d\n", + slave->dev_num); + + complete_all(&slave->initialization_complete); - complete(&slave->initialization_complete); + /* + * If the manager became pm_runtime active, the peripherals will be + * restarted and attach, but their pm_runtime status may remain + * suspended. If the 'update_slave_status' callback initiates + * any sort of deferred processing, this processing would not be + * cancelled on pm_runtime suspend. + * To avoid such zombie states, we queue a request to resume. + * This would be a no-op in case the peripheral was being resumed + * by e.g. the ALSA/ASoC framework. + */ + pm_request_resume(&slave->dev); } } @@ -1868,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); |
