for (i = 0; i < val_size; i += sizeof(u32)) { /* Poll for bus bridge idle */
ret = cs35l56_sdw_poll_mem_status(peripheral,
CS35L56_SDW_CMD_IN_PROGRESS,
0); if (ret < 0) {
dev_err(&peripheral->dev, "!CMD_IN_PROGRESS fail: %d\n", ret); return ret;
}
/* Reading LSByte triggers read of register to holding buffer */
sdw_read_no_pm(peripheral, reg + i);
/* Wait for data available */
ret = cs35l56_sdw_poll_mem_status(peripheral,
CS35L56_SDW_RDATA_RDY,
CS35L56_SDW_RDATA_RDY); if (ret < 0) {
dev_err(&peripheral->dev, "RDATA_RDY fail: %d\n", ret); return ret;
}
/* Read data from buffer */
ret = sdw_nread_no_pm(peripheral, CS35L56_SDW_MEM_READ_DATA, sizeof(u32), &buf[i]); if (ret) {
dev_err(&peripheral->dev, "Late read @%#x failed: %d\n", reg + i, ret); return ret;
}
if (val_size == 4) return cs35l56_sdw_write_one(peripheral, reg, src_be);
while (val_size) {
bytes = SDW_REG_NO_PAGE - (reg & SDW_REGADDR); /* to end of page */ if (bytes > val_size)
bytes = val_size; if (bytes > sizeof(val_le_buf))
bytes = sizeof(val_le_buf);
/* First word of val_buf contains the destination address */ return cs35l56_sdw_gather_write(context, &src_buf[0], 4, &src_buf[4], val_size - 4);
}
/* * Registers are big-endian on I2C and SPI but little-endian on SoundWire. * Exported firmware controls are big-endian on I2C/SPI but little-endian on * SoundWire. Firmware files are always big-endian and are opaque blobs. * Present a big-endian regmap and hide the endianness swap, so that the ALSA * byte controls always have the same byte order, and firmware file blobs * can be written verbatim.
*/ staticconststruct regmap_bus cs35l56_regmap_bus_sdw = {
.read = cs35l56_sdw_read,
.write = cs35l56_sdw_write,
.gather_write = cs35l56_sdw_gather_write,
.reg_format_endian_default = REGMAP_ENDIAN_LITTLE,
.val_format_endian_default = REGMAP_ENDIAN_BIG,
};
staticint cs35l56_sdw_get_unique_id(struct cs35l56_private *cs35l56)
{ int ret;
ret = sdw_read_no_pm(cs35l56->sdw_peripheral, SDW_SCP_DEVID_0); if (ret < 0) return ret;
ret = cs35l56_sdw_get_unique_id(cs35l56); if (ret) goto out;
/* SoundWire UniqueId is used to index the calibration array */ if (cs35l56->base.cal_index < 0)
cs35l56->base.cal_index = cs35l56->sdw_unique_id;
ret = cs35l56_init(cs35l56); if (ret < 0) {
regcache_cache_only(cs35l56->base.regmap, true); goto out;
}
/* * cs35l56_init can return with !init_done if it triggered * a soft reset.
*/ if (cs35l56->base.init_done) { /* Enable SoundWire interrupts */
sdw_write_no_pm(peripheral, CS35L56_SDW_GEN_INT_MASK_1,
CS35L56_SDW_INT_MASK_CODEC_IRQ);
}
if ((status->control_port & SDW_SCP_INT1_IMPL_DEF) == 0) return 0;
/* * Prevent bus manager suspending and possibly issuing a * bus-reset before the queued work has run.
*/
pm_runtime_get_noresume(cs35l56->base.dev);
/* * Mask and clear until it has been handled. The read of GEN_INT_STAT_1 * is required as per the SoundWire spec for interrupt status bits * to clear. GEN_INT_MASK_1 masks the _inputs_ to GEN_INT_STAT1. * None of the interrupts are time-critical so use the * power-efficient queue.
*/
sdw_write_no_pm(peripheral, CS35L56_SDW_GEN_INT_MASK_1, 0);
sdw_read_no_pm(peripheral, CS35L56_SDW_GEN_INT_STAT_1);
sdw_write_no_pm(peripheral, CS35L56_SDW_GEN_INT_STAT_1, 0xFF);
queue_work(system_power_efficient_wq, &cs35l56->sdw_irq_work);
if (peripheral->unattach_request) { /* Cannot access registers until bus is re-initialized. */
dev_dbg(cs35l56->base.dev, "Wait for initialization_complete\n"); if (!wait_for_completion_timeout(&peripheral->initialization_complete,
msecs_to_jiffies(5000))) {
dev_err(cs35l56->base.dev, "initialization_complete timed out\n"); return -ETIMEDOUT;
}
peripheral->unattach_request = 0;
/* * Don't call regcache_mark_dirty(), we can't be sure that the * Manager really did issue a Bus Reset.
*/
}
/* * Disable SoundWire interrupts. * Flush - don't cancel because that could leave an unbalanced pm_runtime_get.
*/
cs35l56->sdw_irq_no_unmask = true;
flush_work(&cs35l56->sdw_irq_work);
/* Mask interrupts and flush in case sdw_irq_work was queued again */
sdw_write_no_pm(cs35l56->sdw_peripheral, CS35L56_SDW_GEN_INT_MASK_1, 0);
sdw_read_no_pm(cs35l56->sdw_peripheral, CS35L56_SDW_GEN_INT_STAT_1);
sdw_write_no_pm(cs35l56->sdw_peripheral, CS35L56_SDW_GEN_INT_STAT_1, 0xFF);
flush_work(&cs35l56->sdw_irq_work);
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.