mirror of
https://github.com/torvalds/linux.git
synced 2024-11-21 19:46:16 +00:00
soundwire updates for 6.12
- bus cleanup for warnings and probe deferral errors suppression - cadence recheck for status with a delayed work - intel interrupt rework on reset exit -----BEGIN PGP SIGNATURE----- iQIzBAABCgAdFiEE+vs47OPLdNbVcHzyfBQHDyUjg0cFAmbv9W8ACgkQfBQHDyUj g0cZqxAAjsXmwjky3zGs8vuC8hFfTJ4nI9NGW0pPKcYlTLDCGfN49/caL0X+BYvE 12x+tHyKa3H29as5CDkS/NkmtBGI27V3wcdOTQEv9OXvv1G/Kc8sfB5wJZS2deec 41EvSu/If1qqQaNXoooI3s63S23SE22vxE6RtN7UNRKlgXs/5qjIVPhdYSUcXiCl gl7wG/NgyfMwH17LCY2W1l2/BSP7XKRBny+cT8dzNR1muaZn8Noi3RiIzI+eEWVv ldHHkc5yTrCYVsi/xW9oDmUJJ4IKZU1TBGAbtOe/EtaJuMyjOCVClfTG96WQrpFl 0gDS7qlGjD0tf8RVn4QLVV68ZVXI6EYPUrv2+Z9f8swf21RLKEjx5aflxktzEwPY SDPvRhpXa5FjmHt7yhVMLXV1u4CyNWepeEcbmZgsll8zrAXwIcltH8NDicURdzqK UHzQFG3LPHrlnC5zBsFpRXFoC8VDa//1kr6vEsXvnY1ehMRUa6+Hvy+1+7q5Syyj ffmhzlw1dJcjnQC1l5xYejPzXi0kw/eAsr0eQ+aumVjDm/2BV/UJbnQ4Pj+l4lAU b9+K6R+ZxC+XZYE4CZtlT/Jtx2Q8Ncp41XA3ErZSUpEJgFzpWCd+C1u/gYzghoUx X0JaX4XzrUtlCvBw8px/NirG8jy36NqvKnoNLkFS/PUMQ74dcmg= =Xwb2 -----END PGP SIGNATURE----- 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
This commit is contained in:
commit
7116747a68
@ -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)
|
|||||||
|
|
||||||
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)
|
|||||||
/* 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)
|
|||||||
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)
|
|||||||
*/
|
*/
|
||||||
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,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
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)
|
|||||||
}
|
}
|
||||||
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)
|
|||||||
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 {
|
|||||||
* @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 {
|
|||||||
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)
|
|||||||
|
|
||||||
#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)
|
|||||||
*/
|
*/
|
||||||
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)
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
ret = sdw_cdns_exit_reset(cdns);
|
|
||||||
if (ret < 0) {
|
|
||||||
dev_err(dev, "%s: unable to exit bus reset sequence: %d\n", __func__, ret);
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
ret = sdw_cdns_enable_interrupt(cdns, true);
|
ret = sdw_cdns_enable_interrupt(cdns, true);
|
||||||
if (ret < 0) {
|
if (ret < 0) {
|
||||||
dev_err(dev, "%s: cannot enable interrupts: %d\n", __func__, ret);
|
dev_err(dev, "%s: cannot enable interrupts: %d\n", __func__, ret);
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ret = sdw_cdns_exit_reset(cdns);
|
||||||
|
if (ret < 0) {
|
||||||
|
dev_err(dev, "%s: unable to exit bus reset sequence: %d\n", __func__, 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)
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
ret = sdw_cdns_exit_reset(cdns);
|
|
||||||
if (ret < 0) {
|
|
||||||
dev_err(dev, "unable to exit bus reset sequence during resume\n");
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
ret = sdw_cdns_enable_interrupt(cdns, true);
|
ret = sdw_cdns_enable_interrupt(cdns, true);
|
||||||
if (ret < 0) {
|
if (ret < 0) {
|
||||||
dev_err(dev, "cannot enable interrupts during resume\n");
|
dev_err(dev, "cannot enable interrupts during resume\n");
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ret = sdw_cdns_exit_reset(cdns);
|
||||||
|
if (ret < 0) {
|
||||||
|
dev_err(dev, "unable to exit bus reset sequence during resume\n");
|
||||||
|
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)
|
|||||||
|
|
||||||
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)
|
|||||||
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 {
|
|||||||
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);
|
||||||
|
Loading…
Reference in New Issue
Block a user