diff options
Diffstat (limited to 'drivers/soundwire/bus.c')
-rw-r--r-- | drivers/soundwire/bus.c | 100 |
1 files changed, 75 insertions, 25 deletions
diff --git a/drivers/soundwire/bus.c b/drivers/soundwire/bus.c index 46885429928a..a9e0aa72654d 100644 --- a/drivers/soundwire/bus.c +++ b/drivers/soundwire/bus.c @@ -44,13 +44,13 @@ int sdw_bus_master_add(struct sdw_bus *bus, struct device *parent, } ret = sdw_get_id(bus); - if (ret) { + if (ret < 0) { dev_err(parent, "Failed to get bus id\n"); return ret; } ret = sdw_master_device_add(bus, parent, fwnode); - if (ret) { + if (ret < 0) { dev_err(parent, "Failed to add master device at link %d\n", bus->link_id); return ret; @@ -121,7 +121,7 @@ int sdw_bus_master_add(struct sdw_bus *bus, struct device *parent, else ret = -ENOTSUPP; /* No ACPI/DT so error out */ - if (ret) { + if (ret < 0) { dev_err(bus->dev, "Finding slaves failed:%d\n", ret); return ret; } @@ -422,7 +422,7 @@ sdw_bread_no_pm(struct sdw_bus *bus, u16 dev_num, u32 addr) ret = sdw_fill_msg(&msg, NULL, addr, 1, dev_num, SDW_MSG_FLAG_READ, &buf); - if (ret) + if (ret < 0) return ret; ret = sdw_transfer(bus, &msg); @@ -440,7 +440,7 @@ sdw_bwrite_no_pm(struct sdw_bus *bus, u16 dev_num, u32 addr, u8 value) ret = sdw_fill_msg(&msg, NULL, addr, 1, dev_num, SDW_MSG_FLAG_WRITE, &value); - if (ret) + if (ret < 0) return ret; return sdw_transfer(bus, &msg); @@ -454,7 +454,7 @@ int sdw_bread_no_pm_unlocked(struct sdw_bus *bus, u16 dev_num, u32 addr) ret = sdw_fill_msg(&msg, NULL, addr, 1, dev_num, SDW_MSG_FLAG_READ, &buf); - if (ret) + if (ret < 0) return ret; ret = sdw_transfer_unlocked(bus, &msg); @@ -472,7 +472,7 @@ int sdw_bwrite_no_pm_unlocked(struct sdw_bus *bus, u16 dev_num, u32 addr, u8 val ret = sdw_fill_msg(&msg, NULL, addr, 1, dev_num, SDW_MSG_FLAG_WRITE, &value); - if (ret) + if (ret < 0) return ret; return sdw_transfer_unlocked(bus, &msg); @@ -593,7 +593,7 @@ EXPORT_SYMBOL(sdw_write); /* called with bus_lock held */ static struct sdw_slave *sdw_get_slave(struct sdw_bus *bus, int i) { - struct sdw_slave *slave = NULL; + struct sdw_slave *slave; list_for_each_entry(slave, &bus->slaves, node) { if (slave->dev_num == i) @@ -603,7 +603,7 @@ static struct sdw_slave *sdw_get_slave(struct sdw_bus *bus, int i) return NULL; } -static int sdw_compare_devid(struct sdw_slave *slave, struct sdw_slave_id id) +int sdw_compare_devid(struct sdw_slave *slave, struct sdw_slave_id id) { if (slave->id.mfg_id != id.mfg_id || slave->id.part_id != id.part_id || @@ -614,6 +614,7 @@ static int sdw_compare_devid(struct sdw_slave *slave, struct sdw_slave_id id) return 0; } +EXPORT_SYMBOL(sdw_compare_devid); /* called with bus_lock held */ static int sdw_get_device_num(struct sdw_slave *slave) @@ -698,6 +699,7 @@ void sdw_extract_slave_id(struct sdw_bus *bus, "SDW Slave class_id 0x%02x, mfg_id 0x%04x, part_id 0x%04x, unique_id 0x%x, version 0x%x\n", id->class_id, id->mfg_id, id->part_id, id->unique_id, id->sdw_version); } +EXPORT_SYMBOL(sdw_extract_slave_id); static int sdw_program_device_num(struct sdw_bus *bus) { @@ -705,7 +707,7 @@ static int sdw_program_device_num(struct sdw_bus *bus) struct sdw_slave *slave, *_s; struct sdw_slave_id id; struct sdw_msg msg; - bool found = false; + bool found; int count = 0, ret; u64 addr; @@ -737,6 +739,7 @@ static int sdw_program_device_num(struct sdw_bus *bus) sdw_extract_slave_id(bus, addr, &id); + found = false; /* Now compare with entries */ list_for_each_entry_safe(slave, _s, &bus->slaves, node) { if (sdw_compare_devid(slave, id) == 0) { @@ -749,7 +752,7 @@ static int sdw_program_device_num(struct sdw_bus *bus) * dev_num */ ret = sdw_assign_device_num(slave); - if (ret) { + if (ret < 0) { dev_err(bus->dev, "Assign dev_num failed:%d\n", ret); @@ -875,14 +878,18 @@ static int sdw_slave_clk_stop_prepare(struct sdw_slave *slave, if (wake_en) val |= SDW_SCP_SYSTEMCTRL_WAKE_UP_EN; } else { - val = sdw_read_no_pm(slave, SDW_SCP_SYSTEMCTRL); - + ret = sdw_read_no_pm(slave, SDW_SCP_SYSTEMCTRL); + if (ret < 0) { + dev_err(&slave->dev, "SDW_SCP_SYSTEMCTRL read failed:%d\n", ret); + return ret; + } + val = ret; val &= ~(SDW_SCP_SYSTEMCTRL_CLK_STP_PREP); } ret = sdw_write_no_pm(slave, SDW_SCP_SYSTEMCTRL, val); - if (ret != 0) + if (ret < 0) dev_err(&slave->dev, "Clock Stop prepare failed for slave: %d", ret); @@ -895,11 +902,15 @@ static int sdw_bus_wait_for_clk_prep_deprep(struct sdw_bus *bus, u16 dev_num) int val; do { - val = sdw_bread_no_pm(bus, dev_num, SDW_SCP_STAT) & - SDW_SCP_STAT_CLK_STP_NF; + val = sdw_bread_no_pm(bus, dev_num, SDW_SCP_STAT); + if (val < 0) { + dev_err(bus->dev, "SDW_SCP_STAT bread failed:%d\n", val); + return val; + } + val &= SDW_SCP_STAT_CLK_STP_NF; if (!val) { - dev_info(bus->dev, "clock stop prep/de-prep done slave:%d", - dev_num); + dev_dbg(bus->dev, "clock stop prep/de-prep done slave:%d", + dev_num); return 0; } @@ -1253,6 +1264,7 @@ static int sdw_slave_set_frequency(struct sdw_slave *slave) static int sdw_initialize_slave(struct sdw_slave *slave) { struct sdw_slave_prop *prop = &slave->prop; + int status; int ret; u8 val; @@ -1260,6 +1272,44 @@ static int sdw_initialize_slave(struct sdw_slave *slave) if (ret < 0) return ret; + if (slave->bus->prop.quirks & SDW_MASTER_QUIRKS_CLEAR_INITIAL_CLASH) { + /* Clear bus clash interrupt before enabling interrupt mask */ + status = sdw_read_no_pm(slave, SDW_SCP_INT1); + if (status < 0) { + dev_err(&slave->dev, + "SDW_SCP_INT1 (BUS_CLASH) read failed:%d\n", status); + return status; + } + if (status & SDW_SCP_INT1_BUS_CLASH) { + dev_warn(&slave->dev, "Bus clash detected before INT mask is enabled\n"); + ret = sdw_write_no_pm(slave, SDW_SCP_INT1, SDW_SCP_INT1_BUS_CLASH); + if (ret < 0) { + dev_err(&slave->dev, + "SDW_SCP_INT1 (BUS_CLASH) write failed:%d\n", ret); + return ret; + } + } + } + if ((slave->bus->prop.quirks & SDW_MASTER_QUIRKS_CLEAR_INITIAL_PARITY) && + !(slave->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) { + dev_err(&slave->dev, + "SDW_SCP_INT1 (PARITY) read failed:%d\n", status); + return status; + } + if (status & SDW_SCP_INT1_PARITY) { + dev_warn(&slave->dev, "PARITY error detected before INT mask is enabled\n"); + ret = sdw_write_no_pm(slave, SDW_SCP_INT1, SDW_SCP_INT1_PARITY); + if (ret < 0) { + dev_err(&slave->dev, + "SDW_SCP_INT1 (PARITY) write failed:%d\n", ret); + return ret; + } + } + } + /* * Set SCP_INT1_MASK register, typically bus clash and * implementation-defined interrupt mask. The Parity detection @@ -1589,7 +1639,7 @@ static int sdw_handle_slave_alerts(struct sdw_slave *slave) ret = sdw_read_no_pm(slave, SDW_SCP_INT1); if (ret < 0) { dev_err(&slave->dev, - "SDW_SCP_INT1 read failed:%d\n", ret); + "SDW_SCP_INT1 recheck read failed:%d\n", ret); goto io_err; } _buf = ret; @@ -1597,7 +1647,7 @@ static int sdw_handle_slave_alerts(struct sdw_slave *slave) ret = sdw_nread_no_pm(slave, SDW_SCP_INTSTAT2, 2, _buf2); if (ret < 0) { dev_err(&slave->dev, - "SDW_SCP_INT2/3 read failed:%d\n", ret); + "SDW_SCP_INT2/3 recheck read failed:%d\n", ret); goto io_err; } @@ -1605,7 +1655,7 @@ static int sdw_handle_slave_alerts(struct sdw_slave *slave) ret = sdw_read_no_pm(slave, SDW_DP0_INT); if (ret < 0) { dev_err(&slave->dev, - "SDW_DP0_INT read failed:%d\n", ret); + "SDW_DP0_INT recheck read failed:%d\n", ret); goto io_err; } sdca_cascade = ret & SDW_DP0_SDCA_CASCADE; @@ -1701,7 +1751,7 @@ int sdw_handle_slave_status(struct sdw_bus *bus, if (status[0] == SDW_SLAVE_ATTACHED) { dev_dbg(bus->dev, "Slave attached, programming device number\n"); ret = sdw_program_device_num(bus); - if (ret) + if (ret < 0) dev_err(bus->dev, "Slave attach failed: %d\n", ret); /* * programming a device number will have side effects, @@ -1735,7 +1785,7 @@ int sdw_handle_slave_status(struct sdw_bus *bus, case SDW_SLAVE_ALERT: ret = sdw_handle_slave_alerts(slave); - if (ret) + if (ret < 0) dev_err(&slave->dev, "Slave %d alert handling failed: %d\n", i, ret); @@ -1754,7 +1804,7 @@ int sdw_handle_slave_status(struct sdw_bus *bus, attached_initializing = true; ret = sdw_initialize_slave(slave); - if (ret) + if (ret < 0) dev_err(&slave->dev, "Slave %d initialization failed: %d\n", i, ret); @@ -1768,7 +1818,7 @@ int sdw_handle_slave_status(struct sdw_bus *bus, } ret = sdw_update_slave_status(slave, status[i]); - if (ret) + if (ret < 0) dev_err(&slave->dev, "Update Slave status failed:%d\n", ret); if (attached_initializing) { |