Skip to content

Commit fdd9ef3

Browse files
charleskeepaxbroonie
authored andcommitted
regmap: sdw-mbq: Add support for further MBQ register sizes
SoundWire MBQ register maps typically contain a variety of register sizes, which doesn't map ideally to the regmap abstraction which expects register maps to have a consistent size. Currently the MBQ register map only allows 16-bit registers to be defined, however this leads to complex CODEC driver implementations with an 8-bit register map and a 16-bit MBQ, every control will then have a custom get and put handler that allows them to access different register maps. Further more 32-bit MBQ quantities are not currently supported. Add support for additional MBQ sizes and to avoid the complexity of multiple register maps treat the val_size as a maximum size for the register map. Within the regmap use an ancillary callback to determine how many bytes to actually read/write to the hardware for a specific register. In the case that no callback is defined the behaviour defaults back to the existing behaviour of a fixed size register map. Signed-off-by: Charles Keepax <ckeepax@opensource.cirrus.com> Link: https://patch.msgid.link/20250107154408.814455-4-ckeepax@opensource.cirrus.com Reviewed-by: Pierre-Louis Bossart <pierre-louis.bossart@linux.dev> Signed-off-by: Mark Brown <broonie@kernel.org>
1 parent b21468e commit fdd9ef3

File tree

2 files changed

+139
-22
lines changed

2 files changed

+139
-22
lines changed

drivers/base/regmap/regmap-sdw-mbq.c

Lines changed: 94 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
// SPDX-License-Identifier: GPL-2.0
22
// Copyright(c) 2020 Intel Corporation.
33

4+
#include <linux/bits.h>
45
#include <linux/device.h>
56
#include <linux/errno.h>
67
#include <linux/module.h>
@@ -9,35 +10,77 @@
910
#include <linux/soundwire/sdw_registers.h>
1011
#include "internal.h"
1112

13+
struct regmap_mbq_context {
14+
struct device *dev;
15+
16+
struct regmap_sdw_mbq_cfg cfg;
17+
18+
int val_size;
19+
};
20+
21+
static int regmap_sdw_mbq_size(struct regmap_mbq_context *ctx, unsigned int reg)
22+
{
23+
int size = ctx->val_size;
24+
25+
if (ctx->cfg.mbq_size) {
26+
size = ctx->cfg.mbq_size(ctx->dev, reg);
27+
if (!size || size > ctx->val_size)
28+
return -EINVAL;
29+
}
30+
31+
return size;
32+
}
33+
1234
static int regmap_sdw_mbq_write(void *context, unsigned int reg, unsigned int val)
1335
{
14-
struct device *dev = context;
36+
struct regmap_mbq_context *ctx = context;
37+
struct device *dev = ctx->dev;
1538
struct sdw_slave *slave = dev_to_sdw_dev(dev);
39+
int mbq_size = regmap_sdw_mbq_size(ctx, reg);
40+
int shift = mbq_size * BITS_PER_BYTE;
1641
int ret;
1742

18-
ret = sdw_write_no_pm(slave, SDW_SDCA_MBQ_CTL(reg), (val >> 8) & 0xff);
19-
if (ret < 0)
20-
return ret;
43+
if (mbq_size < 0)
44+
return mbq_size;
45+
46+
while (--mbq_size > 0) {
47+
shift -= BITS_PER_BYTE;
48+
49+
ret = sdw_write_no_pm(slave, SDW_SDCA_MBQ_CTL(reg),
50+
(val >> shift) & 0xff);
51+
if (ret < 0)
52+
return ret;
53+
}
2154

2255
return sdw_write_no_pm(slave, reg, val & 0xff);
2356
}
2457

2558
static int regmap_sdw_mbq_read(void *context, unsigned int reg, unsigned int *val)
2659
{
27-
struct device *dev = context;
60+
struct regmap_mbq_context *ctx = context;
61+
struct device *dev = ctx->dev;
2862
struct sdw_slave *slave = dev_to_sdw_dev(dev);
29-
int read0;
30-
int read1;
63+
int mbq_size = regmap_sdw_mbq_size(ctx, reg);
64+
int shift = BITS_PER_BYTE;
65+
int read;
3166

32-
read0 = sdw_read_no_pm(slave, reg);
33-
if (read0 < 0)
34-
return read0;
67+
if (mbq_size < 0)
68+
return mbq_size;
3569

36-
read1 = sdw_read_no_pm(slave, SDW_SDCA_MBQ_CTL(reg));
37-
if (read1 < 0)
38-
return read1;
70+
read = sdw_read_no_pm(slave, reg);
71+
if (read < 0)
72+
return read;
3973

40-
*val = (read1 << 8) | read0;
74+
*val = read;
75+
76+
while (--mbq_size > 0) {
77+
read = sdw_read_no_pm(slave, SDW_SDCA_MBQ_CTL(reg));
78+
if (read < 0)
79+
return read;
80+
81+
*val |= read << shift;
82+
shift += BITS_PER_BYTE;
83+
}
4184

4285
return 0;
4386
}
@@ -51,8 +94,7 @@ static const struct regmap_bus regmap_sdw_mbq = {
5194

5295
static int regmap_sdw_mbq_config_check(const struct regmap_config *config)
5396
{
54-
/* MBQ-based controls are only 16-bits for now */
55-
if (config->val_bits != 16)
97+
if (config->val_bits > (sizeof(unsigned int) * BITS_PER_BYTE))
5698
return -ENOTSUPP;
5799

58100
/* Registers are 32 bits wide */
@@ -65,35 +107,67 @@ static int regmap_sdw_mbq_config_check(const struct regmap_config *config)
65107
return 0;
66108
}
67109

110+
static struct regmap_mbq_context *
111+
regmap_sdw_mbq_gen_context(struct device *dev,
112+
const struct regmap_config *config,
113+
const struct regmap_sdw_mbq_cfg *mbq_config)
114+
{
115+
struct regmap_mbq_context *ctx;
116+
117+
ctx = devm_kzalloc(dev, sizeof(*ctx), GFP_KERNEL);
118+
if (!ctx)
119+
return ERR_PTR(-ENOMEM);
120+
121+
ctx->dev = dev;
122+
ctx->val_size = config->val_bits / BITS_PER_BYTE;
123+
124+
if (mbq_config)
125+
ctx->cfg = *mbq_config;
126+
127+
return ctx;
128+
}
129+
68130
struct regmap *__regmap_init_sdw_mbq(struct sdw_slave *sdw,
69131
const struct regmap_config *config,
132+
const struct regmap_sdw_mbq_cfg *mbq_config,
70133
struct lock_class_key *lock_key,
71134
const char *lock_name)
72135
{
136+
struct regmap_mbq_context *ctx;
73137
int ret;
74138

75139
ret = regmap_sdw_mbq_config_check(config);
76140
if (ret)
77141
return ERR_PTR(ret);
78142

79-
return __regmap_init(&sdw->dev, &regmap_sdw_mbq,
80-
&sdw->dev, config, lock_key, lock_name);
143+
ctx = regmap_sdw_mbq_gen_context(&sdw->dev, config, mbq_config);
144+
if (IS_ERR(ctx))
145+
return ERR_CAST(ctx);
146+
147+
return __regmap_init(&sdw->dev, &regmap_sdw_mbq, ctx,
148+
config, lock_key, lock_name);
81149
}
82150
EXPORT_SYMBOL_GPL(__regmap_init_sdw_mbq);
83151

84152
struct regmap *__devm_regmap_init_sdw_mbq(struct sdw_slave *sdw,
85153
const struct regmap_config *config,
154+
const struct regmap_sdw_mbq_cfg *mbq_config,
86155
struct lock_class_key *lock_key,
87156
const char *lock_name)
88157
{
158+
struct regmap_mbq_context *ctx;
89159
int ret;
90160

91161
ret = regmap_sdw_mbq_config_check(config);
92162
if (ret)
93163
return ERR_PTR(ret);
94164

95-
return __devm_regmap_init(&sdw->dev, &regmap_sdw_mbq,
96-
&sdw->dev, config, lock_key, lock_name);
165+
ctx = regmap_sdw_mbq_gen_context(&sdw->dev, config, mbq_config);
166+
if (IS_ERR(ctx))
167+
return ERR_CAST(ctx);
168+
169+
return __devm_regmap_init(&sdw->dev, &regmap_sdw_mbq, ctx,
170+
config, lock_key, lock_name);
97171
}
98172
EXPORT_SYMBOL_GPL(__devm_regmap_init_sdw_mbq);
99173

include/linux/regmap.h

Lines changed: 45 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -506,6 +506,17 @@ struct regmap_range_cfg {
506506
unsigned int window_len;
507507
};
508508

509+
/**
510+
* struct regmap_sdw_mbq_cfg - Configuration for Multi-Byte Quantities
511+
*
512+
* @mbq_size: Callback returning the actual size of the given register.
513+
*
514+
* Provides additional configuration required for SoundWire MBQ register maps.
515+
*/
516+
struct regmap_sdw_mbq_cfg {
517+
int (*mbq_size)(struct device *dev, unsigned int reg);
518+
};
519+
509520
struct regmap_async;
510521

511522
typedef int (*regmap_hw_write)(void *context, const void *data,
@@ -652,6 +663,7 @@ struct regmap *__regmap_init_sdw(struct sdw_slave *sdw,
652663
const char *lock_name);
653664
struct regmap *__regmap_init_sdw_mbq(struct sdw_slave *sdw,
654665
const struct regmap_config *config,
666+
const struct regmap_sdw_mbq_cfg *mbq_config,
655667
struct lock_class_key *lock_key,
656668
const char *lock_name);
657669
struct regmap *__regmap_init_spi_avmm(struct spi_device *spi,
@@ -713,6 +725,7 @@ struct regmap *__devm_regmap_init_sdw(struct sdw_slave *sdw,
713725
const char *lock_name);
714726
struct regmap *__devm_regmap_init_sdw_mbq(struct sdw_slave *sdw,
715727
const struct regmap_config *config,
728+
const struct regmap_sdw_mbq_cfg *mbq_config,
716729
struct lock_class_key *lock_key,
717730
const char *lock_name);
718731
struct regmap *__devm_regmap_init_slimbus(struct slim_device *slimbus,
@@ -942,7 +955,22 @@ bool regmap_ac97_default_volatile(struct device *dev, unsigned int reg);
942955
*/
943956
#define regmap_init_sdw_mbq(sdw, config) \
944957
__regmap_lockdep_wrapper(__regmap_init_sdw_mbq, #config, \
945-
sdw, config)
958+
sdw, config, NULL)
959+
960+
/**
961+
* regmap_init_sdw_mbq_cfg() - Initialise MBQ SDW register map with config
962+
*
963+
* @sdw: Device that will be interacted with
964+
* @config: Configuration for register map
965+
* @mbq_config: Properties for the MBQ registers
966+
*
967+
* The return value will be an ERR_PTR() on error or a valid pointer
968+
* to a struct regmap. The regmap will be automatically freed by the
969+
* device management code.
970+
*/
971+
#define regmap_init_sdw_mbq_cfg(sdw, config, mbq_config) \
972+
__regmap_lockdep_wrapper(__regmap_init_sdw_mbq, #config, \
973+
sdw, config, mbq_config)
946974

947975
/**
948976
* regmap_init_spi_avmm() - Initialize register map for Intel SPI Slave
@@ -1155,7 +1183,22 @@ bool regmap_ac97_default_volatile(struct device *dev, unsigned int reg);
11551183
*/
11561184
#define devm_regmap_init_sdw_mbq(sdw, config) \
11571185
__regmap_lockdep_wrapper(__devm_regmap_init_sdw_mbq, #config, \
1158-
sdw, config)
1186+
sdw, config, NULL)
1187+
1188+
/**
1189+
* devm_regmap_init_sdw_mbq_cfg() - Initialise managed MBQ SDW register map with config
1190+
*
1191+
* @sdw: Device that will be interacted with
1192+
* @config: Configuration for register map
1193+
* @mbq_config: Properties for the MBQ registers
1194+
*
1195+
* The return value will be an ERR_PTR() on error or a valid pointer
1196+
* to a struct regmap. The regmap will be automatically freed by the
1197+
* device management code.
1198+
*/
1199+
#define devm_regmap_init_sdw_mbq_cfg(sdw, config, mbq_config) \
1200+
__regmap_lockdep_wrapper(__devm_regmap_init_sdw_mbq, \
1201+
#config, sdw, config, mbq_config)
11591202

11601203
/**
11611204
* devm_regmap_init_slimbus() - Initialise managed register map

0 commit comments

Comments
 (0)