xref: /linux/drivers/base/regmap/regmap-sdw-mbq.c (revision c31f4aa8fed048fa70e742c4bb49bb48dc489ab3)
1 // SPDX-License-Identifier: GPL-2.0
2 // Copyright(c) 2020 Intel Corporation.
3 
4 #include <linux/bits.h>
5 #include <linux/delay.h>
6 #include <linux/device.h>
7 #include <linux/errno.h>
8 #include <linux/iopoll.h>
9 #include <linux/module.h>
10 #include <linux/regmap.h>
11 #include <linux/soundwire/sdw.h>
12 #include <linux/soundwire/sdw_registers.h>
13 #include <sound/sdca_function.h>
14 #include "internal.h"
15 
16 struct regmap_mbq_context {
17 	struct device *dev;
18 	struct sdw_slave *sdw;
19 
20 	bool (*readable_reg)(struct device *dev, unsigned int reg);
21 
22 	struct regmap_sdw_mbq_cfg cfg;
23 
24 	int val_size;
25 };
26 
27 static int regmap_sdw_mbq_size(struct regmap_mbq_context *ctx, unsigned int reg)
28 {
29 	int size = ctx->val_size;
30 
31 	if (ctx->cfg.mbq_size) {
32 		size = ctx->cfg.mbq_size(ctx->dev, reg);
33 		if (!size || size > ctx->val_size)
34 			return -EINVAL;
35 	}
36 
37 	return size;
38 }
39 
40 static bool regmap_sdw_mbq_deferrable(struct regmap_mbq_context *ctx, unsigned int reg)
41 {
42 	if (ctx->cfg.deferrable)
43 		return ctx->cfg.deferrable(ctx->dev, reg);
44 
45 	return false;
46 }
47 
48 static int regmap_sdw_mbq_poll_busy(struct sdw_slave *slave, unsigned int reg,
49 				    struct regmap_mbq_context *ctx)
50 {
51 	struct device *dev = ctx->dev;
52 	int val, ret = 0;
53 
54 	dev_dbg(dev, "Deferring transaction for 0x%x\n", reg);
55 
56 	reg = SDW_SDCA_CTL(SDW_SDCA_CTL_FUNC(reg), 0,
57 			   SDCA_CTL_ENTITY_0_FUNCTION_STATUS, 0);
58 
59 	if (ctx->readable_reg(dev, reg)) {
60 		ret = read_poll_timeout(sdw_read_no_pm, val,
61 					val < 0 || !(val & SDCA_CTL_ENTITY_0_FUNCTION_BUSY),
62 					ctx->cfg.timeout_us, ctx->cfg.retry_us,
63 					false, slave, reg);
64 		if (val < 0)
65 			return val;
66 		if (ret)
67 			dev_err(dev, "Function busy timed out 0x%x: %d\n", reg, val);
68 	} else {
69 		fsleep(ctx->cfg.timeout_us);
70 	}
71 
72 	return ret;
73 }
74 
75 static int regmap_sdw_mbq_write_impl(struct sdw_slave *slave,
76 				     unsigned int reg, unsigned int val,
77 				     int mbq_size, bool deferrable)
78 {
79 	int shift = mbq_size * BITS_PER_BYTE;
80 	int ret;
81 
82 	while (--mbq_size > 0) {
83 		shift -= BITS_PER_BYTE;
84 
85 		ret = sdw_write_no_pm(slave, SDW_SDCA_MBQ_CTL(reg),
86 				      (val >> shift) & 0xff);
87 		if (ret < 0)
88 			return ret;
89 	}
90 
91 	ret = sdw_write_no_pm(slave, reg, val & 0xff);
92 	if (deferrable && ret == -ENODATA)
93 		return -EAGAIN;
94 
95 	return ret;
96 }
97 
98 static int regmap_sdw_mbq_write(void *context, unsigned int reg, unsigned int val)
99 {
100 	struct regmap_mbq_context *ctx = context;
101 	struct sdw_slave *slave = ctx->sdw;
102 	bool deferrable = regmap_sdw_mbq_deferrable(ctx, reg);
103 	int mbq_size = regmap_sdw_mbq_size(ctx, reg);
104 	int ret;
105 
106 	if (mbq_size < 0)
107 		return mbq_size;
108 
109 	/*
110 	 * Technically the spec does allow a device to set itself to busy for
111 	 * internal reasons, but since it doesn't provide any information on
112 	 * how to handle timeouts in that case, for now the code will only
113 	 * process a single wait/timeout on function busy and a single retry
114 	 * of the transaction.
115 	 */
116 	ret = regmap_sdw_mbq_write_impl(slave, reg, val, mbq_size, deferrable);
117 	if (ret == -EAGAIN) {
118 		ret = regmap_sdw_mbq_poll_busy(slave, reg, ctx);
119 		if (ret)
120 			return ret;
121 
122 		ret = regmap_sdw_mbq_write_impl(slave, reg, val, mbq_size, false);
123 	}
124 
125 	return ret;
126 }
127 
128 static int regmap_sdw_mbq_read_impl(struct sdw_slave *slave,
129 				    unsigned int reg, unsigned int *val,
130 				    int mbq_size, bool deferrable)
131 {
132 	int shift = BITS_PER_BYTE;
133 	int read;
134 
135 	read = sdw_read_no_pm(slave, reg);
136 	if (read < 0) {
137 		if (deferrable && read == -ENODATA)
138 			return -EAGAIN;
139 
140 		return read;
141 	}
142 
143 	*val = read;
144 
145 	while (--mbq_size > 0) {
146 		read = sdw_read_no_pm(slave, SDW_SDCA_MBQ_CTL(reg));
147 		if (read < 0)
148 			return read;
149 
150 		*val |= read << shift;
151 		shift += BITS_PER_BYTE;
152 	}
153 
154 	return 0;
155 }
156 
157 static int regmap_sdw_mbq_read(void *context, unsigned int reg, unsigned int *val)
158 {
159 	struct regmap_mbq_context *ctx = context;
160 	struct sdw_slave *slave = ctx->sdw;
161 	bool deferrable = regmap_sdw_mbq_deferrable(ctx, reg);
162 	int mbq_size = regmap_sdw_mbq_size(ctx, reg);
163 	int ret;
164 
165 	if (mbq_size < 0)
166 		return mbq_size;
167 
168 	/*
169 	 * Technically the spec does allow a device to set itself to busy for
170 	 * internal reasons, but since it doesn't provide any information on
171 	 * how to handle timeouts in that case, for now the code will only
172 	 * process a single wait/timeout on function busy and a single retry
173 	 * of the transaction.
174 	 */
175 	ret = regmap_sdw_mbq_read_impl(slave, reg, val, mbq_size, deferrable);
176 	if (ret == -EAGAIN) {
177 		ret = regmap_sdw_mbq_poll_busy(slave, reg, ctx);
178 		if (ret)
179 			return ret;
180 
181 		ret = regmap_sdw_mbq_read_impl(slave, reg, val, mbq_size, false);
182 	}
183 
184 	return ret;
185 }
186 
187 static const struct regmap_bus regmap_sdw_mbq = {
188 	.reg_read = regmap_sdw_mbq_read,
189 	.reg_write = regmap_sdw_mbq_write,
190 	.reg_format_endian_default = REGMAP_ENDIAN_LITTLE,
191 	.val_format_endian_default = REGMAP_ENDIAN_LITTLE,
192 };
193 
194 static int regmap_sdw_mbq_config_check(const struct regmap_config *config)
195 {
196 	if (config->val_bits > (sizeof(unsigned int) * BITS_PER_BYTE))
197 		return -ENOTSUPP;
198 
199 	/* Registers are 32 bits wide */
200 	if (config->reg_bits != 32)
201 		return -ENOTSUPP;
202 
203 	if (config->pad_bits != 0)
204 		return -ENOTSUPP;
205 
206 	return 0;
207 }
208 
209 static struct regmap_mbq_context *
210 regmap_sdw_mbq_gen_context(struct device *dev,
211 			   struct sdw_slave *sdw,
212 			   const struct regmap_config *config,
213 			   const struct regmap_sdw_mbq_cfg *mbq_config)
214 {
215 	struct regmap_mbq_context *ctx;
216 
217 	ctx = devm_kzalloc(dev, sizeof(*ctx), GFP_KERNEL);
218 	if (!ctx)
219 		return ERR_PTR(-ENOMEM);
220 
221 	ctx->dev = dev;
222 	ctx->sdw = sdw;
223 
224 	if (mbq_config)
225 		ctx->cfg = *mbq_config;
226 
227 	ctx->val_size = config->val_bits / BITS_PER_BYTE;
228 	ctx->readable_reg = config->readable_reg;
229 
230 	return ctx;
231 }
232 
233 struct regmap *__regmap_init_sdw_mbq(struct device *dev, struct sdw_slave *sdw,
234 				     const struct regmap_config *config,
235 				     const struct regmap_sdw_mbq_cfg *mbq_config,
236 				     struct lock_class_key *lock_key,
237 				     const char *lock_name)
238 {
239 	struct regmap_mbq_context *ctx;
240 	int ret;
241 
242 	ret = regmap_sdw_mbq_config_check(config);
243 	if (ret)
244 		return ERR_PTR(ret);
245 
246 	ctx = regmap_sdw_mbq_gen_context(dev, sdw, config, mbq_config);
247 	if (IS_ERR(ctx))
248 		return ERR_CAST(ctx);
249 
250 	return __regmap_init(dev, &regmap_sdw_mbq, ctx,
251 			     config, lock_key, lock_name);
252 }
253 EXPORT_SYMBOL_GPL(__regmap_init_sdw_mbq);
254 
255 struct regmap *__devm_regmap_init_sdw_mbq(struct device *dev, struct sdw_slave *sdw,
256 					  const struct regmap_config *config,
257 					  const struct regmap_sdw_mbq_cfg *mbq_config,
258 					  struct lock_class_key *lock_key,
259 					  const char *lock_name)
260 {
261 	struct regmap_mbq_context *ctx;
262 	int ret;
263 
264 	ret = regmap_sdw_mbq_config_check(config);
265 	if (ret)
266 		return ERR_PTR(ret);
267 
268 	ctx = regmap_sdw_mbq_gen_context(dev, sdw, config, mbq_config);
269 	if (IS_ERR(ctx))
270 		return ERR_CAST(ctx);
271 
272 	return __devm_regmap_init(dev, &regmap_sdw_mbq, ctx,
273 				  config, lock_key, lock_name);
274 }
275 EXPORT_SYMBOL_GPL(__devm_regmap_init_sdw_mbq);
276 
277 MODULE_DESCRIPTION("regmap SoundWire MBQ Module");
278 MODULE_LICENSE("GPL");
279