Skip to content

Commit b8cc917

Browse files
committed
Merge tag 'regmap-v6.2' of git://git.kernel.org/pub/scm/linux/kernel/git/broonie/regmap
Pull regmap updates from Mark Brown: "A few new APIs here, support for the FSI bus (which is used in some PowerPC systems) plus a couple of new APIs, one allowing abstractions built on top of regmap to tell if the regmap can be used in an atomic context and one providing a callback for an in flight device which can't do interrupt masking very well. There's also a fix that I never got round to sending because it really should be fixed better but that's not happened yet and it does avoid the problem, the fix was in -next for a long time" * tag 'regmap-v6.2' of git://git.kernel.org/pub/scm/linux/kernel/git/broonie/regmap: regmap-irq: Add handle_mask_sync() callback regmap: Add FSI bus support regmap: add regmap_might_sleep() regmap-irq: Use the new num_config_regs property in regmap_add_irq_chip_fwnode
2 parents 1e4fa02 + 22250db commit b8cc917

File tree

6 files changed

+341
-18
lines changed

6 files changed

+341
-18
lines changed

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_SOUNDWIRE_MBQ || REGMAP_SCCB || REGMAP_I3C || REGMAP_SPI_AVMM || REGMAP_MDIO)
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 || REGMAP_SPI_AVMM || REGMAP_MDIO || REGMAP_FSI)
88
select IRQ_DOMAIN if REGMAP_IRQ
99
select MDIO_BUS if REGMAP_MDIO
1010
bool
@@ -65,3 +65,7 @@ config REGMAP_I3C
6565
config REGMAP_SPI_AVMM
6666
tristate
6767
depends on SPI
68+
69+
config REGMAP_FSI
70+
tristate
71+
depends on FSI

drivers/base/regmap/Makefile

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,3 +20,4 @@ obj-$(CONFIG_REGMAP_SCCB) += regmap-sccb.o
2020
obj-$(CONFIG_REGMAP_I3C) += regmap-i3c.o
2121
obj-$(CONFIG_REGMAP_SPI_AVMM) += regmap-spi-avmm.o
2222
obj-$(CONFIG_REGMAP_MDIO) += regmap-mdio.o
23+
obj-$(CONFIG_REGMAP_FSI) += regmap-fsi.o

drivers/base/regmap/regmap-fsi.c

Lines changed: 231 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,231 @@
1+
// SPDX-License-Identifier: GPL-2.0
2+
//
3+
// Register map access API - FSI support
4+
//
5+
// Copyright 2022 IBM Corp
6+
//
7+
// Author: Eddie James <[email protected]>
8+
9+
#include <linux/fsi.h>
10+
#include <linux/module.h>
11+
#include <linux/regmap.h>
12+
13+
#include "internal.h"
14+
15+
static int regmap_fsi32_reg_read(void *context, unsigned int reg, unsigned int *val)
16+
{
17+
u32 v;
18+
int ret;
19+
20+
ret = fsi_slave_read(context, reg, &v, sizeof(v));
21+
if (ret)
22+
return ret;
23+
24+
*val = v;
25+
return 0;
26+
}
27+
28+
static int regmap_fsi32_reg_write(void *context, unsigned int reg, unsigned int val)
29+
{
30+
u32 v = val;
31+
32+
return fsi_slave_write(context, reg, &v, sizeof(v));
33+
}
34+
35+
static const struct regmap_bus regmap_fsi32 = {
36+
.reg_write = regmap_fsi32_reg_write,
37+
.reg_read = regmap_fsi32_reg_read,
38+
};
39+
40+
static int regmap_fsi32le_reg_read(void *context, unsigned int reg, unsigned int *val)
41+
{
42+
__be32 v;
43+
int ret;
44+
45+
ret = fsi_slave_read(context, reg, &v, sizeof(v));
46+
if (ret)
47+
return ret;
48+
49+
*val = be32_to_cpu(v);
50+
return 0;
51+
}
52+
53+
static int regmap_fsi32le_reg_write(void *context, unsigned int reg, unsigned int val)
54+
{
55+
__be32 v = cpu_to_be32(val);
56+
57+
return fsi_slave_write(context, reg, &v, sizeof(v));
58+
}
59+
60+
static const struct regmap_bus regmap_fsi32le = {
61+
.reg_write = regmap_fsi32le_reg_write,
62+
.reg_read = regmap_fsi32le_reg_read,
63+
};
64+
65+
static int regmap_fsi16_reg_read(void *context, unsigned int reg, unsigned int *val)
66+
{
67+
u16 v;
68+
int ret;
69+
70+
ret = fsi_slave_read(context, reg, &v, sizeof(v));
71+
if (ret)
72+
return ret;
73+
74+
*val = v;
75+
return 0;
76+
}
77+
78+
static int regmap_fsi16_reg_write(void *context, unsigned int reg, unsigned int val)
79+
{
80+
u16 v;
81+
82+
if (val > 0xffff)
83+
return -EINVAL;
84+
85+
v = val;
86+
return fsi_slave_write(context, reg, &v, sizeof(v));
87+
}
88+
89+
static const struct regmap_bus regmap_fsi16 = {
90+
.reg_write = regmap_fsi16_reg_write,
91+
.reg_read = regmap_fsi16_reg_read,
92+
};
93+
94+
static int regmap_fsi16le_reg_read(void *context, unsigned int reg, unsigned int *val)
95+
{
96+
__be16 v;
97+
int ret;
98+
99+
ret = fsi_slave_read(context, reg, &v, sizeof(v));
100+
if (ret)
101+
return ret;
102+
103+
*val = be16_to_cpu(v);
104+
return 0;
105+
}
106+
107+
static int regmap_fsi16le_reg_write(void *context, unsigned int reg, unsigned int val)
108+
{
109+
__be16 v;
110+
111+
if (val > 0xffff)
112+
return -EINVAL;
113+
114+
v = cpu_to_be16(val);
115+
return fsi_slave_write(context, reg, &v, sizeof(v));
116+
}
117+
118+
static const struct regmap_bus regmap_fsi16le = {
119+
.reg_write = regmap_fsi16le_reg_write,
120+
.reg_read = regmap_fsi16le_reg_read,
121+
};
122+
123+
static int regmap_fsi8_reg_read(void *context, unsigned int reg, unsigned int *val)
124+
{
125+
u8 v;
126+
int ret;
127+
128+
ret = fsi_slave_read(context, reg, &v, sizeof(v));
129+
if (ret)
130+
return ret;
131+
132+
*val = v;
133+
return 0;
134+
}
135+
136+
static int regmap_fsi8_reg_write(void *context, unsigned int reg, unsigned int val)
137+
{
138+
u8 v;
139+
140+
if (val > 0xff)
141+
return -EINVAL;
142+
143+
v = val;
144+
return fsi_slave_write(context, reg, &v, sizeof(v));
145+
}
146+
147+
static const struct regmap_bus regmap_fsi8 = {
148+
.reg_write = regmap_fsi8_reg_write,
149+
.reg_read = regmap_fsi8_reg_read,
150+
};
151+
152+
static const struct regmap_bus *regmap_get_fsi_bus(struct fsi_device *fsi_dev,
153+
const struct regmap_config *config)
154+
{
155+
const struct regmap_bus *bus = NULL;
156+
157+
if (config->reg_bits == 8 || config->reg_bits == 16 || config->reg_bits == 32) {
158+
switch (config->val_bits) {
159+
case 8:
160+
bus = &regmap_fsi8;
161+
break;
162+
case 16:
163+
switch (regmap_get_val_endian(&fsi_dev->dev, NULL, config)) {
164+
case REGMAP_ENDIAN_LITTLE:
165+
#ifdef __LITTLE_ENDIAN
166+
case REGMAP_ENDIAN_NATIVE:
167+
#endif
168+
bus = &regmap_fsi16le;
169+
break;
170+
case REGMAP_ENDIAN_DEFAULT:
171+
case REGMAP_ENDIAN_BIG:
172+
#ifdef __BIG_ENDIAN
173+
case REGMAP_ENDIAN_NATIVE:
174+
#endif
175+
bus = &regmap_fsi16;
176+
break;
177+
default:
178+
break;
179+
}
180+
break;
181+
case 32:
182+
switch (regmap_get_val_endian(&fsi_dev->dev, NULL, config)) {
183+
case REGMAP_ENDIAN_LITTLE:
184+
#ifdef __LITTLE_ENDIAN
185+
case REGMAP_ENDIAN_NATIVE:
186+
#endif
187+
bus = &regmap_fsi32le;
188+
break;
189+
case REGMAP_ENDIAN_DEFAULT:
190+
case REGMAP_ENDIAN_BIG:
191+
#ifdef __BIG_ENDIAN
192+
case REGMAP_ENDIAN_NATIVE:
193+
#endif
194+
bus = &regmap_fsi32;
195+
break;
196+
default:
197+
break;
198+
}
199+
break;
200+
}
201+
}
202+
203+
return bus ?: ERR_PTR(-EOPNOTSUPP);
204+
}
205+
206+
struct regmap *__regmap_init_fsi(struct fsi_device *fsi_dev, const struct regmap_config *config,
207+
struct lock_class_key *lock_key, const char *lock_name)
208+
{
209+
const struct regmap_bus *bus = regmap_get_fsi_bus(fsi_dev, config);
210+
211+
if (IS_ERR(bus))
212+
return ERR_CAST(bus);
213+
214+
return __regmap_init(&fsi_dev->dev, bus, fsi_dev->slave, config, lock_key, lock_name);
215+
}
216+
EXPORT_SYMBOL_GPL(__regmap_init_fsi);
217+
218+
struct regmap *__devm_regmap_init_fsi(struct fsi_device *fsi_dev,
219+
const struct regmap_config *config,
220+
struct lock_class_key *lock_key, const char *lock_name)
221+
{
222+
const struct regmap_bus *bus = regmap_get_fsi_bus(fsi_dev, config);
223+
224+
if (IS_ERR(bus))
225+
return ERR_CAST(bus);
226+
227+
return __devm_regmap_init(&fsi_dev->dev, bus, fsi_dev->slave, config, lock_key, lock_name);
228+
}
229+
EXPORT_SYMBOL_GPL(__devm_regmap_init_fsi);
230+
231+
MODULE_LICENSE("GPL");

drivers/base/regmap/regmap-irq.c

Lines changed: 42 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -115,12 +115,20 @@ static void regmap_irq_sync_unlock(struct irq_data *data)
115115
*/
116116
for (i = 0; i < d->chip->num_regs; i++) {
117117
if (d->mask_base) {
118-
reg = d->get_irq_reg(d, d->mask_base, i);
119-
ret = regmap_update_bits(d->map, reg,
120-
d->mask_buf_def[i], d->mask_buf[i]);
121-
if (ret)
122-
dev_err(d->map->dev, "Failed to sync masks in %x\n",
123-
reg);
118+
if (d->chip->handle_mask_sync)
119+
d->chip->handle_mask_sync(d->map, i,
120+
d->mask_buf_def[i],
121+
d->mask_buf[i],
122+
d->chip->irq_drv_data);
123+
else {
124+
reg = d->get_irq_reg(d, d->mask_base, i);
125+
ret = regmap_update_bits(d->map, reg,
126+
d->mask_buf_def[i],
127+
d->mask_buf[i]);
128+
if (ret)
129+
dev_err(d->map->dev, "Failed to sync masks in %x\n",
130+
reg);
131+
}
124132
}
125133

126134
if (d->unmask_base) {
@@ -722,6 +730,7 @@ int regmap_add_irq_chip_fwnode(struct fwnode_handle *fwnode,
722730
int i;
723731
int ret = -ENOMEM;
724732
int num_type_reg;
733+
int num_regs;
725734
u32 reg;
726735

727736
if (chip->num_regs <= 0)
@@ -796,14 +805,20 @@ int regmap_add_irq_chip_fwnode(struct fwnode_handle *fwnode,
796805
goto err_alloc;
797806
}
798807

799-
num_type_reg = chip->type_in_mask ? chip->num_regs : chip->num_type_reg;
800-
if (num_type_reg) {
801-
d->type_buf_def = kcalloc(num_type_reg,
808+
/*
809+
* Use num_config_regs if defined, otherwise fall back to num_type_reg
810+
* to maintain backward compatibility.
811+
*/
812+
num_type_reg = chip->num_config_regs ? chip->num_config_regs
813+
: chip->num_type_reg;
814+
num_regs = chip->type_in_mask ? chip->num_regs : num_type_reg;
815+
if (num_regs) {
816+
d->type_buf_def = kcalloc(num_regs,
802817
sizeof(*d->type_buf_def), GFP_KERNEL);
803818
if (!d->type_buf_def)
804819
goto err_alloc;
805820

806-
d->type_buf = kcalloc(num_type_reg, sizeof(*d->type_buf),
821+
d->type_buf = kcalloc(num_regs, sizeof(*d->type_buf),
807822
GFP_KERNEL);
808823
if (!d->type_buf)
809824
goto err_alloc;
@@ -917,13 +932,23 @@ int regmap_add_irq_chip_fwnode(struct fwnode_handle *fwnode,
917932
d->mask_buf[i] = d->mask_buf_def[i];
918933

919934
if (d->mask_base) {
920-
reg = d->get_irq_reg(d, d->mask_base, i);
921-
ret = regmap_update_bits(d->map, reg,
922-
d->mask_buf_def[i], d->mask_buf[i]);
923-
if (ret) {
924-
dev_err(map->dev, "Failed to set masks in 0x%x: %d\n",
925-
reg, ret);
926-
goto err_alloc;
935+
if (chip->handle_mask_sync) {
936+
ret = chip->handle_mask_sync(d->map, i,
937+
d->mask_buf_def[i],
938+
d->mask_buf[i],
939+
chip->irq_drv_data);
940+
if (ret)
941+
goto err_alloc;
942+
} else {
943+
reg = d->get_irq_reg(d, d->mask_base, i);
944+
ret = regmap_update_bits(d->map, reg,
945+
d->mask_buf_def[i],
946+
d->mask_buf[i]);
947+
if (ret) {
948+
dev_err(map->dev, "Failed to set masks in 0x%x: %d\n",
949+
reg, ret);
950+
goto err_alloc;
951+
}
927952
}
928953
}
929954

drivers/base/regmap/regmap.c

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3486,6 +3486,19 @@ int regmap_get_reg_stride(struct regmap *map)
34863486
}
34873487
EXPORT_SYMBOL_GPL(regmap_get_reg_stride);
34883488

3489+
/**
3490+
* regmap_might_sleep() - Returns whether a regmap access might sleep.
3491+
*
3492+
* @map: Register map to operate on.
3493+
*
3494+
* Returns true if an access to the register might sleep, else false.
3495+
*/
3496+
bool regmap_might_sleep(struct regmap *map)
3497+
{
3498+
return map->can_sleep;
3499+
}
3500+
EXPORT_SYMBOL_GPL(regmap_might_sleep);
3501+
34893502
int regmap_parse_val(struct regmap *map, const void *buf,
34903503
unsigned int *val)
34913504
{

0 commit comments

Comments
 (0)