Skip to content

Commit 4e6466e

Browse files
committed
regmap: sdw: add support for SoundWire 1.2 MBQ
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 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. Signed-off-by: Pierre-Louis Bossart <pierre-louis.bossart@linux.intel.com>
1 parent 60b56f7 commit 4e6466e

4 files changed

Lines changed: 128 additions & 1 deletion

File tree

drivers/base/regmap/Kconfig

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
# subsystems should select the appropriate symbols.
55

66
config REGMAP
7-
default y if (REGMAP_I2C || REGMAP_SPI || REGMAP_SPMI || REGMAP_W1 || REGMAP_AC97 || REGMAP_MMIO || REGMAP_IRQ || REGMAP_SOUNDWIRE || REGMAP_SCCB || REGMAP_I3C)
7+
default y if (REGMAP_I2C || REGMAP_SPI || REGMAP_SPMI || REGMAP_W1 || REGMAP_AC97 || REGMAP_MMIO || REGMAP_IRQ || REGMAP_SOUNDWIRE || REGMAP_SOUNDWIRE_MBQ || REGMAP_SCCB || REGMAP_I3C)
88
select IRQ_DOMAIN if REGMAP_IRQ
99
bool
1010

@@ -46,6 +46,10 @@ config REGMAP_SOUNDWIRE
4646
tristate
4747
depends on SOUNDWIRE
4848

49+
config REGMAP_SOUNDWIRE_MBQ
50+
tristate
51+
depends on SOUNDWIRE
52+
4953
config REGMAP_SCCB
5054
tristate
5155
depends on I2C

drivers/base/regmap/Makefile

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,5 +15,6 @@ obj-$(CONFIG_REGMAP_MMIO) += regmap-mmio.o
1515
obj-$(CONFIG_REGMAP_IRQ) += regmap-irq.o
1616
obj-$(CONFIG_REGMAP_W1) += regmap-w1.o
1717
obj-$(CONFIG_REGMAP_SOUNDWIRE) += regmap-sdw.o
18+
obj-$(CONFIG_REGMAP_SOUNDWIRE_MBQ) += regmap-sdw-mbq.o
1819
obj-$(CONFIG_REGMAP_SCCB) += regmap-sccb.o
1920
obj-$(CONFIG_REGMAP_I3C) += regmap-i3c.o
Lines changed: 102 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,102 @@
1+
// SPDX-License-Identifier: GPL-2.0
2+
// Copyright(c) 2020 Intel Corporation.
3+
4+
#include <linux/device.h>
5+
#include <linux/errno.h>
6+
#include <linux/mod_devicetable.h>
7+
#include <linux/module.h>
8+
#include <linux/regmap.h>
9+
#include <linux/soundwire/sdw.h>
10+
#include <linux/soundwire/sdw_registers.h>
11+
#include "internal.h"
12+
13+
static int regmap_sdw_mbq_write(void *context, unsigned int reg, unsigned int val)
14+
{
15+
struct device *dev = context;
16+
struct sdw_slave *slave = dev_to_sdw_dev(dev);
17+
int ret;
18+
19+
ret = sdw_write(slave, SDW_SDCA_MBQ_CTL(reg), (val >> 8) & 0xff);
20+
if (ret < 0)
21+
return ret;
22+
23+
return sdw_write(slave, reg, val & 0xff);
24+
}
25+
26+
static int regmap_sdw_mbq_read(void *context, unsigned int reg, unsigned int *val)
27+
{
28+
struct device *dev = context;
29+
struct sdw_slave *slave = dev_to_sdw_dev(dev);
30+
int read0;
31+
int read1;
32+
33+
read0 = sdw_read(slave, reg);
34+
if (read0 < 0)
35+
return read0;
36+
37+
read1 = sdw_read(slave, SDW_SDCA_MBQ_CTL(reg));
38+
if (read1 < 0)
39+
return read1;
40+
41+
*val = (read1 << 8) | read0;
42+
43+
return 0;
44+
}
45+
46+
static struct regmap_bus regmap_sdw_mbq = {
47+
.reg_read = regmap_sdw_mbq_read,
48+
.reg_write = regmap_sdw_mbq_write,
49+
.reg_format_endian_default = REGMAP_ENDIAN_LITTLE,
50+
.val_format_endian_default = REGMAP_ENDIAN_LITTLE,
51+
};
52+
53+
static int regmap_sdw_mbq_config_check(const struct regmap_config *config)
54+
{
55+
/* MBQ-based controls are only 16-bits for now */
56+
if (config->val_bits != 16)
57+
return -EOPNOTSUPP;
58+
59+
/* Registers are 32 bits wide */
60+
if (config->reg_bits != 32)
61+
return -EOPNOTSUPP;
62+
63+
if (config->pad_bits != 0)
64+
return -EOPNOTSUPP;
65+
66+
return 0;
67+
}
68+
69+
struct regmap *__regmap_init_sdw_mbq(struct sdw_slave *sdw,
70+
const struct regmap_config *config,
71+
struct lock_class_key *lock_key,
72+
const char *lock_name)
73+
{
74+
int ret;
75+
76+
ret = regmap_sdw_mbq_config_check(config);
77+
if (ret)
78+
return ERR_PTR(ret);
79+
80+
return __regmap_init(&sdw->dev, &regmap_sdw_mbq,
81+
&sdw->dev, config, lock_key, lock_name);
82+
}
83+
EXPORT_SYMBOL_GPL(__regmap_init_sdw_mbq);
84+
85+
struct regmap *__devm_regmap_init_sdw_mbq(struct sdw_slave *sdw,
86+
const struct regmap_config *config,
87+
struct lock_class_key *lock_key,
88+
const char *lock_name)
89+
{
90+
int ret;
91+
92+
ret = regmap_sdw_mbq_config_check(config);
93+
if (ret)
94+
return ERR_PTR(ret);
95+
96+
return __devm_regmap_init(&sdw->dev, &regmap_sdw_mbq,
97+
&sdw->dev, config, lock_key, lock_name);
98+
}
99+
EXPORT_SYMBOL_GPL(__devm_regmap_init_sdw_mbq);
100+
101+
MODULE_DESCRIPTION("Regmap SoundWire Module");
102+
MODULE_LICENSE("GPL v2");

include/linux/regmap.h

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -596,6 +596,10 @@ struct regmap *__regmap_init_sdw(struct sdw_slave *sdw,
596596
const struct regmap_config *config,
597597
struct lock_class_key *lock_key,
598598
const char *lock_name);
599+
struct regmap *__regmap_init_sdw_mbq(struct sdw_slave *sdw,
600+
const struct regmap_config *config,
601+
struct lock_class_key *lock_key,
602+
const char *lock_name);
599603

600604
struct regmap *__devm_regmap_init(struct device *dev,
601605
const struct regmap_bus *bus,
@@ -641,6 +645,10 @@ struct regmap *__devm_regmap_init_sdw(struct sdw_slave *sdw,
641645
const struct regmap_config *config,
642646
struct lock_class_key *lock_key,
643647
const char *lock_name);
648+
struct regmap *__devm_regmap_init_sdw_mbq(struct sdw_slave *sdw,
649+
const struct regmap_config *config,
650+
struct lock_class_key *lock_key,
651+
const char *lock_name);
644652
struct regmap *__devm_regmap_init_slimbus(struct slim_device *slimbus,
645653
const struct regmap_config *config,
646654
struct lock_class_key *lock_key,
@@ -835,6 +843,18 @@ bool regmap_ac97_default_volatile(struct device *dev, unsigned int reg);
835843
__regmap_lockdep_wrapper(__regmap_init_sdw, #config, \
836844
sdw, config)
837845

846+
/**
847+
* regmap_init_sdw_mbq() - Initialise register map
848+
*
849+
* @sdw: Device that will be interacted with
850+
* @config: Configuration for register map
851+
*
852+
* The return value will be an ERR_PTR() on error or a valid pointer to
853+
* a struct regmap.
854+
*/
855+
#define regmap_init_sdw_mbq(sdw, config) \
856+
__regmap_lockdep_wrapper(__regmap_init_sdw_mbq, #config, \
857+
sdw, config)
838858

839859
/**
840860
* devm_regmap_init() - Initialise managed register map

0 commit comments

Comments
 (0)