Commit 7116747a authored by Linus Torvalds's avatar Linus Torvalds

Merge tag 'soundwire-6.12-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/vkoul/soundwire

Pull soundwire updates from Vinod Koul:

 - bus cleanup for warnings and probe deferral errors suppression

 - cadence recheck for status with a delayed work

 - intel interrupt rework on reset exit

* tag 'soundwire-6.12-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/vkoul/soundwire:
  soundwire: intel_bus_common: enable interrupts before exiting reset
  soundwire: cadence: re-check Peripheral status with delayed_work
  soundwire: bus: clean up probe warnings
  soundwire: bus: drop unused driver name field
  soundwire: bus: suppress probe deferral errors
parents f34c5125 5aedb8d8
...@@ -83,7 +83,6 @@ static int sdw_drv_probe(struct device *dev) ...@@ -83,7 +83,6 @@ static int sdw_drv_probe(struct device *dev)
struct sdw_slave *slave = dev_to_sdw_dev(dev); struct sdw_slave *slave = dev_to_sdw_dev(dev);
struct sdw_driver *drv = drv_to_sdw_driver(dev->driver); struct sdw_driver *drv = drv_to_sdw_driver(dev->driver);
const struct sdw_device_id *id; const struct sdw_device_id *id;
const char *name;
int ret; int ret;
/* /*
...@@ -108,11 +107,6 @@ static int sdw_drv_probe(struct device *dev) ...@@ -108,11 +107,6 @@ static int sdw_drv_probe(struct device *dev)
ret = drv->probe(slave, id); ret = drv->probe(slave, id);
if (ret) { if (ret) {
name = drv->name;
if (!name)
name = drv->driver.name;
dev_err(dev, "Probe of %s failed: %d\n", name, ret);
dev_pm_domain_detach(dev, false); dev_pm_domain_detach(dev, false);
return ret; return ret;
} }
...@@ -129,7 +123,7 @@ static int sdw_drv_probe(struct device *dev) ...@@ -129,7 +123,7 @@ static int sdw_drv_probe(struct device *dev)
/* init the dynamic sysfs attributes we need */ /* init the dynamic sysfs attributes we need */
ret = sdw_slave_sysfs_dpn_init(slave); ret = sdw_slave_sysfs_dpn_init(slave);
if (ret < 0) if (ret < 0)
dev_warn(dev, "Slave sysfs init failed:%d\n", ret); dev_warn(dev, "failed to initialise sysfs: %d\n", ret);
/* /*
* Check for valid clk_stop_timeout, use DisCo worst case value of * Check for valid clk_stop_timeout, use DisCo worst case value of
...@@ -153,7 +147,7 @@ static int sdw_drv_probe(struct device *dev) ...@@ -153,7 +147,7 @@ static int sdw_drv_probe(struct device *dev)
if (drv->ops && drv->ops->update_status) { if (drv->ops && drv->ops->update_status) {
ret = drv->ops->update_status(slave, slave->status); ret = drv->ops->update_status(slave, slave->status);
if (ret < 0) if (ret < 0)
dev_warn(dev, "%s: update_status failed with status %d\n", __func__, ret); dev_warn(dev, "failed to update status at probe: %d\n", ret);
} }
mutex_unlock(&slave->sdw_dev_lock); mutex_unlock(&slave->sdw_dev_lock);
...@@ -204,16 +198,11 @@ static void sdw_drv_shutdown(struct device *dev) ...@@ -204,16 +198,11 @@ static void sdw_drv_shutdown(struct device *dev)
*/ */
int __sdw_register_driver(struct sdw_driver *drv, struct module *owner) int __sdw_register_driver(struct sdw_driver *drv, struct module *owner)
{ {
const char *name;
drv->driver.bus = &sdw_bus_type; drv->driver.bus = &sdw_bus_type;
if (!drv->probe) { if (!drv->probe) {
name = drv->name; pr_err("driver %s didn't provide SDW probe routine\n",
if (!name) drv->driver.name);
name = drv->driver.name;
pr_err("driver %s didn't provide SDW probe routine\n", name);
return -EINVAL; return -EINVAL;
} }
......
...@@ -890,8 +890,14 @@ static int cdns_update_slave_status(struct sdw_cdns *cdns, ...@@ -890,8 +890,14 @@ static int cdns_update_slave_status(struct sdw_cdns *cdns,
} }
} }
if (is_slave) if (is_slave) {
return sdw_handle_slave_status(&cdns->bus, status); int ret;
mutex_lock(&cdns->status_update_lock);
ret = sdw_handle_slave_status(&cdns->bus, status);
mutex_unlock(&cdns->status_update_lock);
return ret;
}
return 0; return 0;
} }
...@@ -988,6 +994,31 @@ irqreturn_t sdw_cdns_irq(int irq, void *dev_id) ...@@ -988,6 +994,31 @@ irqreturn_t sdw_cdns_irq(int irq, void *dev_id)
} }
EXPORT_SYMBOL(sdw_cdns_irq); EXPORT_SYMBOL(sdw_cdns_irq);
static void cdns_check_attached_status_dwork(struct work_struct *work)
{
struct sdw_cdns *cdns =
container_of(work, struct sdw_cdns, attach_dwork.work);
enum sdw_slave_status status[SDW_MAX_DEVICES + 1];
u32 val;
int ret;
int i;
val = cdns_readl(cdns, CDNS_MCP_SLAVE_STAT);
for (i = 0; i <= SDW_MAX_DEVICES; i++) {
status[i] = val & 0x3;
if (status[i])
dev_dbg(cdns->dev, "Peripheral %d status: %d\n", i, status[i]);
val >>= 2;
}
mutex_lock(&cdns->status_update_lock);
ret = sdw_handle_slave_status(&cdns->bus, status);
mutex_unlock(&cdns->status_update_lock);
if (ret < 0)
dev_err(cdns->dev, "%s: sdw_handle_slave_status failed: %d\n", __func__, ret);
}
/** /**
* cdns_update_slave_status_work - update slave status in a work since we will need to handle * cdns_update_slave_status_work - update slave status in a work since we will need to handle
* other interrupts eg. CDNS_MCP_INT_RX_WL during the update slave * other interrupts eg. CDNS_MCP_INT_RX_WL during the update slave
...@@ -1740,7 +1771,11 @@ int sdw_cdns_probe(struct sdw_cdns *cdns) ...@@ -1740,7 +1771,11 @@ int sdw_cdns_probe(struct sdw_cdns *cdns)
init_completion(&cdns->tx_complete); init_completion(&cdns->tx_complete);
cdns->bus.port_ops = &cdns_port_ops; cdns->bus.port_ops = &cdns_port_ops;
mutex_init(&cdns->status_update_lock);
INIT_WORK(&cdns->work, cdns_update_slave_status_work); INIT_WORK(&cdns->work, cdns_update_slave_status_work);
INIT_DELAYED_WORK(&cdns->attach_dwork, cdns_check_attached_status_dwork);
return 0; return 0;
} }
EXPORT_SYMBOL(sdw_cdns_probe); EXPORT_SYMBOL(sdw_cdns_probe);
......
...@@ -117,6 +117,8 @@ struct sdw_cdns_dai_runtime { ...@@ -117,6 +117,8 @@ struct sdw_cdns_dai_runtime {
* @link_up: Link status * @link_up: Link status
* @msg_count: Messages sent on bus * @msg_count: Messages sent on bus
* @dai_runtime_array: runtime context for each allocated DAI. * @dai_runtime_array: runtime context for each allocated DAI.
* @status_update_lock: protect concurrency between interrupt-based and delayed work
* status update
*/ */
struct sdw_cdns { struct sdw_cdns {
struct device *dev; struct device *dev;
...@@ -148,10 +150,13 @@ struct sdw_cdns { ...@@ -148,10 +150,13 @@ struct sdw_cdns {
bool interrupt_enabled; bool interrupt_enabled;
struct work_struct work; struct work_struct work;
struct delayed_work attach_dwork;
struct list_head list; struct list_head list;
struct sdw_cdns_dai_runtime **dai_runtime_array; struct sdw_cdns_dai_runtime **dai_runtime_array;
struct mutex status_update_lock; /* add mutual exclusion to sdw_handle_slave_status() */
}; };
#define bus_to_cdns(_bus) container_of(_bus, struct sdw_cdns, bus) #define bus_to_cdns(_bus) container_of(_bus, struct sdw_cdns, bus)
......
...@@ -103,6 +103,8 @@ static inline void intel_writew(void __iomem *base, int offset, u16 value) ...@@ -103,6 +103,8 @@ static inline void intel_writew(void __iomem *base, int offset, u16 value)
#define INTEL_MASTER_RESET_ITERATIONS 10 #define INTEL_MASTER_RESET_ITERATIONS 10
#define SDW_INTEL_DELAYED_ENUMERATION_MS 100
#define SDW_INTEL_CHECK_OPS(sdw, cb) ((sdw) && (sdw)->link_res && (sdw)->link_res->hw_ops && \ #define SDW_INTEL_CHECK_OPS(sdw, cb) ((sdw) && (sdw)->link_res && (sdw)->link_res->hw_ops && \
(sdw)->link_res->hw_ops->cb) (sdw)->link_res->hw_ops->cb)
#define SDW_INTEL_OPS(sdw, cb) ((sdw)->link_res->hw_ops->cb) #define SDW_INTEL_OPS(sdw, cb) ((sdw)->link_res->hw_ops->cb)
......
...@@ -489,6 +489,7 @@ static void intel_link_remove(struct auxiliary_device *auxdev) ...@@ -489,6 +489,7 @@ static void intel_link_remove(struct auxiliary_device *auxdev)
*/ */
if (!bus->prop.hw_disabled) { if (!bus->prop.hw_disabled) {
sdw_intel_debugfs_exit(sdw); sdw_intel_debugfs_exit(sdw);
cancel_delayed_work_sync(&cdns->attach_dwork);
sdw_cdns_enable_interrupt(cdns, false); sdw_cdns_enable_interrupt(cdns, false);
} }
sdw_bus_master_delete(bus); sdw_bus_master_delete(bus);
......
...@@ -45,21 +45,24 @@ int intel_start_bus(struct sdw_intel *sdw) ...@@ -45,21 +45,24 @@ int intel_start_bus(struct sdw_intel *sdw)
return ret; return ret;
} }
ret = sdw_cdns_exit_reset(cdns); ret = sdw_cdns_enable_interrupt(cdns, true);
if (ret < 0) { if (ret < 0) {
dev_err(dev, "%s: unable to exit bus reset sequence: %d\n", __func__, ret); dev_err(dev, "%s: cannot enable interrupts: %d\n", __func__, ret);
return ret; return ret;
} }
ret = sdw_cdns_enable_interrupt(cdns, true); ret = sdw_cdns_exit_reset(cdns);
if (ret < 0) { if (ret < 0) {
dev_err(dev, "%s: cannot enable interrupts: %d\n", __func__, ret); dev_err(dev, "%s: unable to exit bus reset sequence: %d\n", __func__, ret);
return ret; return ret;
} }
sdw_cdns_check_self_clearing_bits(cdns, __func__, sdw_cdns_check_self_clearing_bits(cdns, __func__,
true, INTEL_MASTER_RESET_ITERATIONS); true, INTEL_MASTER_RESET_ITERATIONS);
schedule_delayed_work(&cdns->attach_dwork,
msecs_to_jiffies(SDW_INTEL_DELAYED_ENUMERATION_MS));
return 0; return 0;
} }
...@@ -136,21 +139,24 @@ int intel_start_bus_after_reset(struct sdw_intel *sdw) ...@@ -136,21 +139,24 @@ int intel_start_bus_after_reset(struct sdw_intel *sdw)
return ret; return ret;
} }
ret = sdw_cdns_exit_reset(cdns); ret = sdw_cdns_enable_interrupt(cdns, true);
if (ret < 0) { if (ret < 0) {
dev_err(dev, "unable to exit bus reset sequence during resume\n"); dev_err(dev, "cannot enable interrupts during resume\n");
return ret; return ret;
} }
ret = sdw_cdns_enable_interrupt(cdns, true); ret = sdw_cdns_exit_reset(cdns);
if (ret < 0) { if (ret < 0) {
dev_err(dev, "cannot enable interrupts during resume\n"); dev_err(dev, "unable to exit bus reset sequence during resume\n");
return ret; return ret;
} }
} }
sdw_cdns_check_self_clearing_bits(cdns, __func__, true, INTEL_MASTER_RESET_ITERATIONS); sdw_cdns_check_self_clearing_bits(cdns, __func__, true, INTEL_MASTER_RESET_ITERATIONS);
schedule_delayed_work(&cdns->attach_dwork,
msecs_to_jiffies(SDW_INTEL_DELAYED_ENUMERATION_MS));
return 0; return 0;
} }
...@@ -184,6 +190,9 @@ int intel_start_bus_after_clock_stop(struct sdw_intel *sdw) ...@@ -184,6 +190,9 @@ int intel_start_bus_after_clock_stop(struct sdw_intel *sdw)
sdw_cdns_check_self_clearing_bits(cdns, __func__, true, INTEL_MASTER_RESET_ITERATIONS); sdw_cdns_check_self_clearing_bits(cdns, __func__, true, INTEL_MASTER_RESET_ITERATIONS);
schedule_delayed_work(&cdns->attach_dwork,
msecs_to_jiffies(SDW_INTEL_DELAYED_ENUMERATION_MS));
return 0; return 0;
} }
...@@ -194,6 +203,8 @@ int intel_stop_bus(struct sdw_intel *sdw, bool clock_stop) ...@@ -194,6 +203,8 @@ int intel_stop_bus(struct sdw_intel *sdw, bool clock_stop)
bool wake_enable = false; bool wake_enable = false;
int ret; int ret;
cancel_delayed_work_sync(&cdns->attach_dwork);
if (clock_stop) { if (clock_stop) {
ret = sdw_cdns_clock_stop(cdns, true); ret = sdw_cdns_clock_stop(cdns, true);
if (ret < 0) if (ret < 0)
......
...@@ -704,8 +704,6 @@ struct sdw_master_device { ...@@ -704,8 +704,6 @@ struct sdw_master_device {
container_of(d, struct sdw_master_device, dev) container_of(d, struct sdw_master_device, dev)
struct sdw_driver { struct sdw_driver {
const char *name;
int (*probe)(struct sdw_slave *sdw, int (*probe)(struct sdw_slave *sdw,
const struct sdw_device_id *id); const struct sdw_device_id *id);
int (*remove)(struct sdw_slave *sdw); int (*remove)(struct sdw_slave *sdw);
......
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