mirror of
https://github.com/torvalds/linux.git
synced 2024-11-28 23:21:31 +00:00
fb5103f9d6
The SoundWire 1.1 specification only allowed for reads and writes of bytes. The SoundWire 1.2 specification adds a new capability to transfer "Multi-Byte Quantities" (MBQ) across the bus. The transfers still happens one-byte-at-a-time, but the update is atomic. For example when writing a 16-bit volume, the first byte transferred is only taken into account when the second byte is successfully transferred. The mechanism is symmetrical for read and writes: - On a read, the address of the last byte to be read is modified by setting the MBQ bit - On a write, the address of all but the last byte to be written are modified by setting the MBQ bit. The address for the last byte relies on the MBQ bit being cleared. The current definitions for MBQ-based controls in the SDCA draft standard are limited to 16 bits for volumes, so for now this is the only supported format. An update will be provided if and when support for 24-bit and 32-bit values is specified by the SDCA standard. One possible objection is that this code could have been handled with regmap-sdw.c. However this is a new spec addition not handled by every SoundWire 1.1 and non-SDCA device, so there's no reason to load code that will never be used. Also in practice it's extremely unlikely that CONFIG_REGMAP would not be selected with CONFIG_REGMAP_MBQ selected. However there's no functional dependency between the two modules so they can be selected separately. Reviewed-by: Rander Wang <rander.wang@linux.intel.com> Reviewed-by: Guennadi Liakhovetski <guennadi.liakhovetski@linux.intel.com> Reviewed-by: Kai Vehmanen <kai.vehmanen@linux.intel.com> Signed-off-by: Pierre-Louis Bossart <pierre-louis.bossart@linux.intel.com> Signed-off-by: Bard Liao <yung-chuan.liao@linux.intel.com> Reviewed-by: Vinod Koul <vkoul@kernel.org> Link: https://lore.kernel.org/r/20201103172226.4278-3-yung-chuan.liao@linux.intel.com Signed-off-by: Mark Brown <broonie@kernel.org>
102 lines
2.4 KiB
C
102 lines
2.4 KiB
C
// SPDX-License-Identifier: GPL-2.0
|
|
// Copyright(c) 2020 Intel Corporation.
|
|
|
|
#include <linux/device.h>
|
|
#include <linux/errno.h>
|
|
#include <linux/module.h>
|
|
#include <linux/regmap.h>
|
|
#include <linux/soundwire/sdw.h>
|
|
#include <linux/soundwire/sdw_registers.h>
|
|
#include "internal.h"
|
|
|
|
static int regmap_sdw_mbq_write(void *context, unsigned int reg, unsigned int val)
|
|
{
|
|
struct device *dev = context;
|
|
struct sdw_slave *slave = dev_to_sdw_dev(dev);
|
|
int ret;
|
|
|
|
ret = sdw_write(slave, SDW_SDCA_MBQ_CTL(reg), (val >> 8) & 0xff);
|
|
if (ret < 0)
|
|
return ret;
|
|
|
|
return sdw_write(slave, reg, val & 0xff);
|
|
}
|
|
|
|
static int regmap_sdw_mbq_read(void *context, unsigned int reg, unsigned int *val)
|
|
{
|
|
struct device *dev = context;
|
|
struct sdw_slave *slave = dev_to_sdw_dev(dev);
|
|
int read0;
|
|
int read1;
|
|
|
|
read0 = sdw_read(slave, reg);
|
|
if (read0 < 0)
|
|
return read0;
|
|
|
|
read1 = sdw_read(slave, SDW_SDCA_MBQ_CTL(reg));
|
|
if (read1 < 0)
|
|
return read1;
|
|
|
|
*val = (read1 << 8) | read0;
|
|
|
|
return 0;
|
|
}
|
|
|
|
static struct regmap_bus regmap_sdw_mbq = {
|
|
.reg_read = regmap_sdw_mbq_read,
|
|
.reg_write = regmap_sdw_mbq_write,
|
|
.reg_format_endian_default = REGMAP_ENDIAN_LITTLE,
|
|
.val_format_endian_default = REGMAP_ENDIAN_LITTLE,
|
|
};
|
|
|
|
static int regmap_sdw_mbq_config_check(const struct regmap_config *config)
|
|
{
|
|
/* MBQ-based controls are only 16-bits for now */
|
|
if (config->val_bits != 16)
|
|
return -ENOTSUPP;
|
|
|
|
/* Registers are 32 bits wide */
|
|
if (config->reg_bits != 32)
|
|
return -ENOTSUPP;
|
|
|
|
if (config->pad_bits != 0)
|
|
return -ENOTSUPP;
|
|
|
|
return 0;
|
|
}
|
|
|
|
struct regmap *__regmap_init_sdw_mbq(struct sdw_slave *sdw,
|
|
const struct regmap_config *config,
|
|
struct lock_class_key *lock_key,
|
|
const char *lock_name)
|
|
{
|
|
int ret;
|
|
|
|
ret = regmap_sdw_mbq_config_check(config);
|
|
if (ret)
|
|
return ERR_PTR(ret);
|
|
|
|
return __regmap_init(&sdw->dev, ®map_sdw_mbq,
|
|
&sdw->dev, config, lock_key, lock_name);
|
|
}
|
|
EXPORT_SYMBOL_GPL(__regmap_init_sdw_mbq);
|
|
|
|
struct regmap *__devm_regmap_init_sdw_mbq(struct sdw_slave *sdw,
|
|
const struct regmap_config *config,
|
|
struct lock_class_key *lock_key,
|
|
const char *lock_name)
|
|
{
|
|
int ret;
|
|
|
|
ret = regmap_sdw_mbq_config_check(config);
|
|
if (ret)
|
|
return ERR_PTR(ret);
|
|
|
|
return __devm_regmap_init(&sdw->dev, ®map_sdw_mbq,
|
|
&sdw->dev, config, lock_key, lock_name);
|
|
}
|
|
EXPORT_SYMBOL_GPL(__devm_regmap_init_sdw_mbq);
|
|
|
|
MODULE_DESCRIPTION("Regmap SoundWire MBQ Module");
|
|
MODULE_LICENSE("GPL v2");
|