1 // SPDX-License-Identifier: GPL-2.0
2 // Copyright (C) 2025 Cirrus Logic, Inc. and
3 // Cirrus Logic International Semiconductor Ltd.
4
5 /*
6 * The MIPI SDCA specification is available for public downloads at
7 * https://www.mipi.org/mipi-sdca-v1-0-download
8 */
9
10 #include <linux/bitops.h>
11 #include <linux/minmax.h>
12 #include <linux/module.h>
13 #include <linux/regmap.h>
14 #include <linux/soundwire/sdw_registers.h>
15 #include <linux/types.h>
16 #include <sound/sdca.h>
17 #include <sound/sdca_function.h>
18 #include <sound/sdca_regmap.h>
19
20 static struct sdca_entity *
function_find_entity(struct sdca_function_data * function,unsigned int reg)21 function_find_entity(struct sdca_function_data *function, unsigned int reg)
22 {
23 int i;
24
25 for (i = 0; i < function->num_entities; i++)
26 if (SDW_SDCA_CTL_ENT(reg) == function->entities[i].id)
27 return &function->entities[i];
28
29 return NULL;
30 }
31
32 static struct sdca_control *
entity_find_control(struct sdca_entity * entity,unsigned int reg)33 entity_find_control(struct sdca_entity *entity, unsigned int reg)
34 {
35 int i;
36
37 for (i = 0; i < entity->num_controls; i++) {
38 if (SDW_SDCA_CTL_CSEL(reg) == entity->controls[i].sel)
39 return &entity->controls[i];
40 }
41
42 return NULL;
43 }
44
45 static struct sdca_control *
function_find_control(struct sdca_function_data * function,unsigned int reg)46 function_find_control(struct sdca_function_data *function, unsigned int reg)
47 {
48 struct sdca_entity *entity;
49
50 entity = function_find_entity(function, reg);
51 if (!entity)
52 return NULL;
53
54 return entity_find_control(entity, reg);
55 }
56
57 /**
58 * sdca_regmap_readable - return if a given SDCA Control is readable
59 * @function: Pointer to the Function information.
60 * @reg: Register address/Control to be processed.
61 *
62 * Return: Returns true if the register is readable.
63 */
sdca_regmap_readable(struct sdca_function_data * function,unsigned int reg)64 bool sdca_regmap_readable(struct sdca_function_data *function, unsigned int reg)
65 {
66 struct sdca_control *control;
67
68 if (!SDW_SDCA_VALID_CTL(reg))
69 return false;
70
71 control = function_find_control(function, reg);
72 if (!control)
73 return false;
74
75 switch (control->mode) {
76 case SDCA_ACCESS_MODE_RW:
77 case SDCA_ACCESS_MODE_RO:
78 case SDCA_ACCESS_MODE_DUAL:
79 case SDCA_ACCESS_MODE_RW1S:
80 case SDCA_ACCESS_MODE_RW1C:
81 /* No access to registers marked solely for device use */
82 return control->layers & ~SDCA_ACCESS_LAYER_DEVICE;
83 default:
84 return false;
85 }
86 }
87 EXPORT_SYMBOL_NS(sdca_regmap_readable, "SND_SOC_SDCA");
88
89 /**
90 * sdca_regmap_writeable - return if a given SDCA Control is writeable
91 * @function: Pointer to the Function information.
92 * @reg: Register address/Control to be processed.
93 *
94 * Return: Returns true if the register is writeable.
95 */
sdca_regmap_writeable(struct sdca_function_data * function,unsigned int reg)96 bool sdca_regmap_writeable(struct sdca_function_data *function, unsigned int reg)
97 {
98 struct sdca_control *control;
99
100 if (!SDW_SDCA_VALID_CTL(reg))
101 return false;
102
103 control = function_find_control(function, reg);
104 if (!control)
105 return false;
106
107 switch (control->mode) {
108 case SDCA_ACCESS_MODE_RW:
109 case SDCA_ACCESS_MODE_DUAL:
110 case SDCA_ACCESS_MODE_RW1S:
111 case SDCA_ACCESS_MODE_RW1C:
112 /* No access to registers marked solely for device use */
113 return control->layers & ~SDCA_ACCESS_LAYER_DEVICE;
114 default:
115 return false;
116 }
117 }
118 EXPORT_SYMBOL_NS(sdca_regmap_writeable, "SND_SOC_SDCA");
119
120 /**
121 * sdca_regmap_volatile - return if a given SDCA Control is volatile
122 * @function: Pointer to the Function information.
123 * @reg: Register address/Control to be processed.
124 *
125 * Return: Returns true if the register is volatile.
126 */
sdca_regmap_volatile(struct sdca_function_data * function,unsigned int reg)127 bool sdca_regmap_volatile(struct sdca_function_data *function, unsigned int reg)
128 {
129 struct sdca_control *control;
130
131 if (!SDW_SDCA_VALID_CTL(reg))
132 return false;
133
134 control = function_find_control(function, reg);
135 if (!control)
136 return false;
137
138 switch (control->mode) {
139 case SDCA_ACCESS_MODE_RO:
140 case SDCA_ACCESS_MODE_RW1S:
141 case SDCA_ACCESS_MODE_RW1C:
142 return true;
143 default:
144 return false;
145 }
146 }
147 EXPORT_SYMBOL_NS(sdca_regmap_volatile, "SND_SOC_SDCA");
148
149 /**
150 * sdca_regmap_deferrable - return if a given SDCA Control is deferrable
151 * @function: Pointer to the Function information.
152 * @reg: Register address/Control to be processed.
153 *
154 * Return: Returns true if the register is deferrable.
155 */
sdca_regmap_deferrable(struct sdca_function_data * function,unsigned int reg)156 bool sdca_regmap_deferrable(struct sdca_function_data *function, unsigned int reg)
157 {
158 struct sdca_control *control;
159
160 if (!SDW_SDCA_VALID_CTL(reg))
161 return false;
162
163 control = function_find_control(function, reg);
164 if (!control)
165 return false;
166
167 return control->deferrable;
168 }
169 EXPORT_SYMBOL_NS(sdca_regmap_deferrable, "SND_SOC_SDCA");
170
171 /**
172 * sdca_regmap_mbq_size - return size in bytes of a given SDCA Control
173 * @function: Pointer to the Function information.
174 * @reg: Register address/Control to be processed.
175 *
176 * Return: Returns the size in bytes of the Control.
177 */
sdca_regmap_mbq_size(struct sdca_function_data * function,unsigned int reg)178 int sdca_regmap_mbq_size(struct sdca_function_data *function, unsigned int reg)
179 {
180 struct sdca_control *control;
181
182 if (!SDW_SDCA_VALID_CTL(reg))
183 return -EINVAL;
184
185 control = function_find_control(function, reg);
186 if (!control)
187 return false;
188
189 return clamp_val(control->nbits / BITS_PER_BYTE, sizeof(u8), sizeof(u32));
190 }
191 EXPORT_SYMBOL_NS(sdca_regmap_mbq_size, "SND_SOC_SDCA");
192
193 /**
194 * sdca_regmap_count_constants - count the number of DisCo constant Controls
195 * @dev: Pointer to the device.
196 * @function: Pointer to the Function information, to be parsed.
197 *
198 * This function returns the number of DisCo constant Controls present
199 * in a function. Typically this information will be used to populate
200 * the regmap defaults array, allowing drivers to access the values of
201 * DisCo constants as any other physical register.
202 *
203 * Return: Returns number of DisCo constant controls, or a negative error
204 * code on failure.
205 */
sdca_regmap_count_constants(struct device * dev,struct sdca_function_data * function)206 int sdca_regmap_count_constants(struct device *dev,
207 struct sdca_function_data *function)
208 {
209 int nconsts = 0;
210 int i, j;
211
212 for (i = 0; i < function->num_entities; i++) {
213 struct sdca_entity *entity = &function->entities[i];
214
215 for (j = 0; j < entity->num_controls; j++) {
216 if (entity->controls[j].mode == SDCA_ACCESS_MODE_DC)
217 nconsts += hweight64(entity->controls[j].cn_list);
218 }
219 }
220
221 return nconsts;
222 }
223 EXPORT_SYMBOL_NS(sdca_regmap_count_constants, "SND_SOC_SDCA");
224
225 /**
226 * sdca_regmap_populate_constants - fill an array with DisCo constant values
227 * @dev: Pointer to the device.
228 * @function: Pointer to the Function information, to be parsed.
229 * @consts: Pointer to the array which should be filled with the DisCo
230 * constant values.
231 *
232 * This function will populate a regmap struct reg_default array with
233 * the values of the DisCo constants for a given Function. This
234 * allows to access the values of DisCo constants the same as any
235 * other physical register.
236 *
237 * Return: Returns the number of constants populated on success, a negative
238 * error code on failure.
239 */
sdca_regmap_populate_constants(struct device * dev,struct sdca_function_data * function,struct reg_default * consts)240 int sdca_regmap_populate_constants(struct device *dev,
241 struct sdca_function_data *function,
242 struct reg_default *consts)
243 {
244 int i, j, k;
245
246 for (i = 0, k = 0; i < function->num_entities; i++) {
247 struct sdca_entity *entity = &function->entities[i];
248
249 for (j = 0; j < entity->num_controls; j++) {
250 struct sdca_control *control = &entity->controls[j];
251 int cn;
252
253 if (control->mode != SDCA_ACCESS_MODE_DC)
254 continue;
255
256 for_each_set_bit(cn, (unsigned long *)&control->cn_list,
257 BITS_PER_TYPE(control->cn_list)) {
258 consts[k].reg = SDW_SDCA_CTL(function->desc->adr,
259 entity->id,
260 control->sel, cn);
261 consts[k].def = control->value;
262 k++;
263 }
264 }
265 }
266
267 return k;
268 }
269 EXPORT_SYMBOL_NS(sdca_regmap_populate_constants, "SND_SOC_SDCA");
270
271 /**
272 * sdca_regmap_write_defaults - write out DisCo defaults to device
273 * @dev: Pointer to the device.
274 * @regmap: Pointer to the Function register map.
275 * @function: Pointer to the Function information, to be parsed.
276 *
277 * This function will write out to the hardware all the DisCo default and
278 * fixed value controls. This will cause them to be populated into the cache,
279 * and subsequent handling can be done through a cache sync.
280 *
281 * Return: Returns zero on success, and a negative error code on failure.
282 */
sdca_regmap_write_defaults(struct device * dev,struct regmap * regmap,struct sdca_function_data * function)283 int sdca_regmap_write_defaults(struct device *dev, struct regmap *regmap,
284 struct sdca_function_data *function)
285 {
286 int i, j;
287 int ret;
288
289 for (i = 0; i < function->num_entities; i++) {
290 struct sdca_entity *entity = &function->entities[i];
291
292 for (j = 0; j < entity->num_controls; j++) {
293 struct sdca_control *control = &entity->controls[j];
294 int cn;
295
296 if (control->mode == SDCA_ACCESS_MODE_DC)
297 continue;
298
299 if (!control->has_default && !control->has_fixed)
300 continue;
301
302 for_each_set_bit(cn, (unsigned long *)&control->cn_list,
303 BITS_PER_TYPE(control->cn_list)) {
304 unsigned int reg;
305
306 reg = SDW_SDCA_CTL(function->desc->adr, entity->id,
307 control->sel, cn);
308
309 ret = regmap_write(regmap, reg, control->value);
310 if (ret)
311 return ret;
312 }
313 }
314 }
315
316 return 0;
317 }
318 EXPORT_SYMBOL_NS(sdca_regmap_write_defaults, "SND_SOC_SDCA");
319