1e3f7caf7SCharles Keepax // SPDX-License-Identifier: GPL-2.0
2e3f7caf7SCharles Keepax // Copyright (C) 2025 Cirrus Logic, Inc. and
3e3f7caf7SCharles Keepax // Cirrus Logic International Semiconductor Ltd.
4e3f7caf7SCharles Keepax
5e3f7caf7SCharles Keepax /*
6e3f7caf7SCharles Keepax * The MIPI SDCA specification is available for public downloads at
7e3f7caf7SCharles Keepax * https://www.mipi.org/mipi-sdca-v1-0-download
8e3f7caf7SCharles Keepax */
9e3f7caf7SCharles Keepax
10e3f7caf7SCharles Keepax #include <linux/bitops.h>
11e3f7caf7SCharles Keepax #include <linux/minmax.h>
12e3f7caf7SCharles Keepax #include <linux/module.h>
1328c12866SCharles Keepax #include <linux/regmap.h>
14e3f7caf7SCharles Keepax #include <linux/soundwire/sdw_registers.h>
15e3f7caf7SCharles Keepax #include <linux/types.h>
1628c12866SCharles Keepax #include <sound/sdca.h>
17e3f7caf7SCharles Keepax #include <sound/sdca_function.h>
18e3f7caf7SCharles Keepax #include <sound/sdca_regmap.h>
19e3f7caf7SCharles Keepax
20e3f7caf7SCharles Keepax static struct sdca_entity *
function_find_entity(struct sdca_function_data * function,unsigned int reg)21e3f7caf7SCharles Keepax function_find_entity(struct sdca_function_data *function, unsigned int reg)
22e3f7caf7SCharles Keepax {
23e3f7caf7SCharles Keepax int i;
24e3f7caf7SCharles Keepax
25e3f7caf7SCharles Keepax for (i = 0; i < function->num_entities; i++)
26e3f7caf7SCharles Keepax if (SDW_SDCA_CTL_ENT(reg) == function->entities[i].id)
27e3f7caf7SCharles Keepax return &function->entities[i];
28e3f7caf7SCharles Keepax
29e3f7caf7SCharles Keepax return NULL;
30e3f7caf7SCharles Keepax }
31e3f7caf7SCharles Keepax
32e3f7caf7SCharles Keepax static struct sdca_control *
entity_find_control(struct sdca_entity * entity,unsigned int reg)33e3f7caf7SCharles Keepax entity_find_control(struct sdca_entity *entity, unsigned int reg)
34e3f7caf7SCharles Keepax {
35e3f7caf7SCharles Keepax int i;
36e3f7caf7SCharles Keepax
37e3f7caf7SCharles Keepax for (i = 0; i < entity->num_controls; i++) {
38e3f7caf7SCharles Keepax if (SDW_SDCA_CTL_CSEL(reg) == entity->controls[i].sel)
39e3f7caf7SCharles Keepax return &entity->controls[i];
40e3f7caf7SCharles Keepax }
41e3f7caf7SCharles Keepax
42e3f7caf7SCharles Keepax return NULL;
43e3f7caf7SCharles Keepax }
44e3f7caf7SCharles Keepax
45e3f7caf7SCharles Keepax static struct sdca_control *
function_find_control(struct sdca_function_data * function,unsigned int reg)46e3f7caf7SCharles Keepax function_find_control(struct sdca_function_data *function, unsigned int reg)
47e3f7caf7SCharles Keepax {
48e3f7caf7SCharles Keepax struct sdca_entity *entity;
49e3f7caf7SCharles Keepax
50e3f7caf7SCharles Keepax entity = function_find_entity(function, reg);
51e3f7caf7SCharles Keepax if (!entity)
52e3f7caf7SCharles Keepax return NULL;
53e3f7caf7SCharles Keepax
54e3f7caf7SCharles Keepax return entity_find_control(entity, reg);
55e3f7caf7SCharles Keepax }
56e3f7caf7SCharles Keepax
57e3f7caf7SCharles Keepax /**
58e3f7caf7SCharles Keepax * sdca_regmap_readable - return if a given SDCA Control is readable
59e3f7caf7SCharles Keepax * @function: Pointer to the Function information.
60e3f7caf7SCharles Keepax * @reg: Register address/Control to be processed.
61e3f7caf7SCharles Keepax *
62e3f7caf7SCharles Keepax * Return: Returns true if the register is readable.
63e3f7caf7SCharles Keepax */
sdca_regmap_readable(struct sdca_function_data * function,unsigned int reg)64e3f7caf7SCharles Keepax bool sdca_regmap_readable(struct sdca_function_data *function, unsigned int reg)
65e3f7caf7SCharles Keepax {
66e3f7caf7SCharles Keepax struct sdca_control *control;
67e3f7caf7SCharles Keepax
68e3f7caf7SCharles Keepax if (!SDW_SDCA_VALID_CTL(reg))
69e3f7caf7SCharles Keepax return false;
70e3f7caf7SCharles Keepax
71e3f7caf7SCharles Keepax control = function_find_control(function, reg);
72e3f7caf7SCharles Keepax if (!control)
73e3f7caf7SCharles Keepax return false;
74e3f7caf7SCharles Keepax
75e3f7caf7SCharles Keepax switch (control->mode) {
76e3f7caf7SCharles Keepax case SDCA_ACCESS_MODE_RW:
77e3f7caf7SCharles Keepax case SDCA_ACCESS_MODE_RO:
78e3f7caf7SCharles Keepax case SDCA_ACCESS_MODE_DUAL:
79e3f7caf7SCharles Keepax case SDCA_ACCESS_MODE_RW1S:
80e3f7caf7SCharles Keepax case SDCA_ACCESS_MODE_RW1C:
81e3f7caf7SCharles Keepax /* No access to registers marked solely for device use */
82e3f7caf7SCharles Keepax return control->layers & ~SDCA_ACCESS_LAYER_DEVICE;
83e3f7caf7SCharles Keepax default:
84e3f7caf7SCharles Keepax return false;
85e3f7caf7SCharles Keepax }
86e3f7caf7SCharles Keepax }
87e3f7caf7SCharles Keepax EXPORT_SYMBOL_NS(sdca_regmap_readable, "SND_SOC_SDCA");
88e3f7caf7SCharles Keepax
89e3f7caf7SCharles Keepax /**
90e3f7caf7SCharles Keepax * sdca_regmap_writeable - return if a given SDCA Control is writeable
91e3f7caf7SCharles Keepax * @function: Pointer to the Function information.
92e3f7caf7SCharles Keepax * @reg: Register address/Control to be processed.
93e3f7caf7SCharles Keepax *
94e3f7caf7SCharles Keepax * Return: Returns true if the register is writeable.
95e3f7caf7SCharles Keepax */
sdca_regmap_writeable(struct sdca_function_data * function,unsigned int reg)96e3f7caf7SCharles Keepax bool sdca_regmap_writeable(struct sdca_function_data *function, unsigned int reg)
97e3f7caf7SCharles Keepax {
98e3f7caf7SCharles Keepax struct sdca_control *control;
99e3f7caf7SCharles Keepax
100e3f7caf7SCharles Keepax if (!SDW_SDCA_VALID_CTL(reg))
101e3f7caf7SCharles Keepax return false;
102e3f7caf7SCharles Keepax
103e3f7caf7SCharles Keepax control = function_find_control(function, reg);
104e3f7caf7SCharles Keepax if (!control)
105e3f7caf7SCharles Keepax return false;
106e3f7caf7SCharles Keepax
107e3f7caf7SCharles Keepax switch (control->mode) {
108e3f7caf7SCharles Keepax case SDCA_ACCESS_MODE_RW:
109e3f7caf7SCharles Keepax case SDCA_ACCESS_MODE_DUAL:
110e3f7caf7SCharles Keepax case SDCA_ACCESS_MODE_RW1S:
111e3f7caf7SCharles Keepax case SDCA_ACCESS_MODE_RW1C:
112e3f7caf7SCharles Keepax /* No access to registers marked solely for device use */
113e3f7caf7SCharles Keepax return control->layers & ~SDCA_ACCESS_LAYER_DEVICE;
114e3f7caf7SCharles Keepax default:
115e3f7caf7SCharles Keepax return false;
116e3f7caf7SCharles Keepax }
117e3f7caf7SCharles Keepax }
118e3f7caf7SCharles Keepax EXPORT_SYMBOL_NS(sdca_regmap_writeable, "SND_SOC_SDCA");
119e3f7caf7SCharles Keepax
120e3f7caf7SCharles Keepax /**
121e3f7caf7SCharles Keepax * sdca_regmap_volatile - return if a given SDCA Control is volatile
122e3f7caf7SCharles Keepax * @function: Pointer to the Function information.
123e3f7caf7SCharles Keepax * @reg: Register address/Control to be processed.
124e3f7caf7SCharles Keepax *
125e3f7caf7SCharles Keepax * Return: Returns true if the register is volatile.
126e3f7caf7SCharles Keepax */
sdca_regmap_volatile(struct sdca_function_data * function,unsigned int reg)127e3f7caf7SCharles Keepax bool sdca_regmap_volatile(struct sdca_function_data *function, unsigned int reg)
128e3f7caf7SCharles Keepax {
129e3f7caf7SCharles Keepax struct sdca_control *control;
130e3f7caf7SCharles Keepax
131e3f7caf7SCharles Keepax if (!SDW_SDCA_VALID_CTL(reg))
132e3f7caf7SCharles Keepax return false;
133e3f7caf7SCharles Keepax
134e3f7caf7SCharles Keepax control = function_find_control(function, reg);
135e3f7caf7SCharles Keepax if (!control)
136e3f7caf7SCharles Keepax return false;
137e3f7caf7SCharles Keepax
138e3f7caf7SCharles Keepax switch (control->mode) {
139e3f7caf7SCharles Keepax case SDCA_ACCESS_MODE_RO:
140e3f7caf7SCharles Keepax case SDCA_ACCESS_MODE_RW1S:
141e3f7caf7SCharles Keepax case SDCA_ACCESS_MODE_RW1C:
142e3f7caf7SCharles Keepax return true;
143e3f7caf7SCharles Keepax default:
144e3f7caf7SCharles Keepax return false;
145e3f7caf7SCharles Keepax }
146e3f7caf7SCharles Keepax }
147e3f7caf7SCharles Keepax EXPORT_SYMBOL_NS(sdca_regmap_volatile, "SND_SOC_SDCA");
148e3f7caf7SCharles Keepax
149e3f7caf7SCharles Keepax /**
150e3f7caf7SCharles Keepax * sdca_regmap_deferrable - return if a given SDCA Control is deferrable
151e3f7caf7SCharles Keepax * @function: Pointer to the Function information.
152e3f7caf7SCharles Keepax * @reg: Register address/Control to be processed.
153e3f7caf7SCharles Keepax *
154e3f7caf7SCharles Keepax * Return: Returns true if the register is deferrable.
155e3f7caf7SCharles Keepax */
sdca_regmap_deferrable(struct sdca_function_data * function,unsigned int reg)156e3f7caf7SCharles Keepax bool sdca_regmap_deferrable(struct sdca_function_data *function, unsigned int reg)
157e3f7caf7SCharles Keepax {
158e3f7caf7SCharles Keepax struct sdca_control *control;
159e3f7caf7SCharles Keepax
160e3f7caf7SCharles Keepax if (!SDW_SDCA_VALID_CTL(reg))
161e3f7caf7SCharles Keepax return false;
162e3f7caf7SCharles Keepax
163e3f7caf7SCharles Keepax control = function_find_control(function, reg);
164e3f7caf7SCharles Keepax if (!control)
165e3f7caf7SCharles Keepax return false;
166e3f7caf7SCharles Keepax
167e3f7caf7SCharles Keepax return control->deferrable;
168e3f7caf7SCharles Keepax }
169e3f7caf7SCharles Keepax EXPORT_SYMBOL_NS(sdca_regmap_deferrable, "SND_SOC_SDCA");
170e3f7caf7SCharles Keepax
171e3f7caf7SCharles Keepax /**
172e3f7caf7SCharles Keepax * sdca_regmap_mbq_size - return size in bytes of a given SDCA Control
173e3f7caf7SCharles Keepax * @function: Pointer to the Function information.
174e3f7caf7SCharles Keepax * @reg: Register address/Control to be processed.
175e3f7caf7SCharles Keepax *
176e3f7caf7SCharles Keepax * Return: Returns the size in bytes of the Control.
177e3f7caf7SCharles Keepax */
sdca_regmap_mbq_size(struct sdca_function_data * function,unsigned int reg)178e3f7caf7SCharles Keepax int sdca_regmap_mbq_size(struct sdca_function_data *function, unsigned int reg)
179e3f7caf7SCharles Keepax {
180e3f7caf7SCharles Keepax struct sdca_control *control;
181e3f7caf7SCharles Keepax
182e3f7caf7SCharles Keepax if (!SDW_SDCA_VALID_CTL(reg))
183e3f7caf7SCharles Keepax return -EINVAL;
184e3f7caf7SCharles Keepax
185e3f7caf7SCharles Keepax control = function_find_control(function, reg);
186e3f7caf7SCharles Keepax if (!control)
187e3f7caf7SCharles Keepax return false;
188e3f7caf7SCharles Keepax
189e3f7caf7SCharles Keepax return clamp_val(control->nbits / BITS_PER_BYTE, sizeof(u8), sizeof(u32));
190e3f7caf7SCharles Keepax }
191e3f7caf7SCharles Keepax EXPORT_SYMBOL_NS(sdca_regmap_mbq_size, "SND_SOC_SDCA");
192e3f7caf7SCharles Keepax
19328c12866SCharles Keepax /**
19428c12866SCharles Keepax * sdca_regmap_count_constants - count the number of DisCo constant Controls
19528c12866SCharles Keepax * @dev: Pointer to the device.
19628c12866SCharles Keepax * @function: Pointer to the Function information, to be parsed.
19728c12866SCharles Keepax *
19828c12866SCharles Keepax * This function returns the number of DisCo constant Controls present
19928c12866SCharles Keepax * in a function. Typically this information will be used to populate
20028c12866SCharles Keepax * the regmap defaults array, allowing drivers to access the values of
20128c12866SCharles Keepax * DisCo constants as any other physical register.
20228c12866SCharles Keepax *
20328c12866SCharles Keepax * Return: Returns number of DisCo constant controls, or a negative error
20428c12866SCharles Keepax * code on failure.
20528c12866SCharles Keepax */
sdca_regmap_count_constants(struct device * dev,struct sdca_function_data * function)20628c12866SCharles Keepax int sdca_regmap_count_constants(struct device *dev,
20728c12866SCharles Keepax struct sdca_function_data *function)
20828c12866SCharles Keepax {
20928c12866SCharles Keepax int nconsts = 0;
21028c12866SCharles Keepax int i, j;
21128c12866SCharles Keepax
21228c12866SCharles Keepax for (i = 0; i < function->num_entities; i++) {
21328c12866SCharles Keepax struct sdca_entity *entity = &function->entities[i];
21428c12866SCharles Keepax
21528c12866SCharles Keepax for (j = 0; j < entity->num_controls; j++) {
21628c12866SCharles Keepax if (entity->controls[j].mode == SDCA_ACCESS_MODE_DC)
21728c12866SCharles Keepax nconsts += hweight64(entity->controls[j].cn_list);
21828c12866SCharles Keepax }
21928c12866SCharles Keepax }
22028c12866SCharles Keepax
22128c12866SCharles Keepax return nconsts;
22228c12866SCharles Keepax }
22328c12866SCharles Keepax EXPORT_SYMBOL_NS(sdca_regmap_count_constants, "SND_SOC_SDCA");
22428c12866SCharles Keepax
22528c12866SCharles Keepax /**
22628c12866SCharles Keepax * sdca_regmap_populate_constants - fill an array with DisCo constant values
22728c12866SCharles Keepax * @dev: Pointer to the device.
22828c12866SCharles Keepax * @function: Pointer to the Function information, to be parsed.
22928c12866SCharles Keepax * @consts: Pointer to the array which should be filled with the DisCo
23028c12866SCharles Keepax * constant values.
23128c12866SCharles Keepax *
23228c12866SCharles Keepax * This function will populate a regmap struct reg_default array with
23328c12866SCharles Keepax * the values of the DisCo constants for a given Function. This
23428c12866SCharles Keepax * allows to access the values of DisCo constants the same as any
23528c12866SCharles Keepax * other physical register.
23628c12866SCharles Keepax *
23728c12866SCharles Keepax * Return: Returns the number of constants populated on success, a negative
23828c12866SCharles Keepax * error code on failure.
23928c12866SCharles Keepax */
sdca_regmap_populate_constants(struct device * dev,struct sdca_function_data * function,struct reg_default * consts)24028c12866SCharles Keepax int sdca_regmap_populate_constants(struct device *dev,
24128c12866SCharles Keepax struct sdca_function_data *function,
24228c12866SCharles Keepax struct reg_default *consts)
24328c12866SCharles Keepax {
24428c12866SCharles Keepax int i, j, k;
24528c12866SCharles Keepax
24628c12866SCharles Keepax for (i = 0, k = 0; i < function->num_entities; i++) {
24728c12866SCharles Keepax struct sdca_entity *entity = &function->entities[i];
24828c12866SCharles Keepax
24928c12866SCharles Keepax for (j = 0; j < entity->num_controls; j++) {
25028c12866SCharles Keepax struct sdca_control *control = &entity->controls[j];
25128c12866SCharles Keepax int cn;
25228c12866SCharles Keepax
25328c12866SCharles Keepax if (control->mode != SDCA_ACCESS_MODE_DC)
25428c12866SCharles Keepax continue;
25528c12866SCharles Keepax
25628c12866SCharles Keepax for_each_set_bit(cn, (unsigned long *)&control->cn_list,
25728c12866SCharles Keepax BITS_PER_TYPE(control->cn_list)) {
25828c12866SCharles Keepax consts[k].reg = SDW_SDCA_CTL(function->desc->adr,
25928c12866SCharles Keepax entity->id,
26028c12866SCharles Keepax control->sel, cn);
26128c12866SCharles Keepax consts[k].def = control->value;
26228c12866SCharles Keepax k++;
26328c12866SCharles Keepax }
26428c12866SCharles Keepax }
26528c12866SCharles Keepax }
26628c12866SCharles Keepax
26728c12866SCharles Keepax return k;
26828c12866SCharles Keepax }
26928c12866SCharles Keepax EXPORT_SYMBOL_NS(sdca_regmap_populate_constants, "SND_SOC_SDCA");
27028c12866SCharles Keepax
271*c143755dSCharles Keepax /**
272*c143755dSCharles Keepax * sdca_regmap_write_defaults - write out DisCo defaults to device
273*c143755dSCharles Keepax * @dev: Pointer to the device.
274*c143755dSCharles Keepax * @regmap: Pointer to the Function register map.
275*c143755dSCharles Keepax * @function: Pointer to the Function information, to be parsed.
276*c143755dSCharles Keepax *
277*c143755dSCharles Keepax * This function will write out to the hardware all the DisCo default and
278*c143755dSCharles Keepax * fixed value controls. This will cause them to be populated into the cache,
279*c143755dSCharles Keepax * and subsequent handling can be done through a cache sync.
280*c143755dSCharles Keepax *
281*c143755dSCharles Keepax * Return: Returns zero on success, and a negative error code on failure.
282*c143755dSCharles Keepax */
sdca_regmap_write_defaults(struct device * dev,struct regmap * regmap,struct sdca_function_data * function)283*c143755dSCharles Keepax int sdca_regmap_write_defaults(struct device *dev, struct regmap *regmap,
284*c143755dSCharles Keepax struct sdca_function_data *function)
285*c143755dSCharles Keepax {
286*c143755dSCharles Keepax int i, j;
287*c143755dSCharles Keepax int ret;
288*c143755dSCharles Keepax
289*c143755dSCharles Keepax for (i = 0; i < function->num_entities; i++) {
290*c143755dSCharles Keepax struct sdca_entity *entity = &function->entities[i];
291*c143755dSCharles Keepax
292*c143755dSCharles Keepax for (j = 0; j < entity->num_controls; j++) {
293*c143755dSCharles Keepax struct sdca_control *control = &entity->controls[j];
294*c143755dSCharles Keepax int cn;
295*c143755dSCharles Keepax
296*c143755dSCharles Keepax if (control->mode == SDCA_ACCESS_MODE_DC)
297*c143755dSCharles Keepax continue;
298*c143755dSCharles Keepax
299*c143755dSCharles Keepax if (!control->has_default && !control->has_fixed)
300*c143755dSCharles Keepax continue;
301*c143755dSCharles Keepax
302*c143755dSCharles Keepax for_each_set_bit(cn, (unsigned long *)&control->cn_list,
303*c143755dSCharles Keepax BITS_PER_TYPE(control->cn_list)) {
304*c143755dSCharles Keepax unsigned int reg;
305*c143755dSCharles Keepax
306*c143755dSCharles Keepax reg = SDW_SDCA_CTL(function->desc->adr, entity->id,
307*c143755dSCharles Keepax control->sel, cn);
308*c143755dSCharles Keepax
309*c143755dSCharles Keepax ret = regmap_write(regmap, reg, control->value);
310*c143755dSCharles Keepax if (ret)
311*c143755dSCharles Keepax return ret;
312*c143755dSCharles Keepax }
313*c143755dSCharles Keepax }
314*c143755dSCharles Keepax }
315*c143755dSCharles Keepax
316*c143755dSCharles Keepax return 0;
317*c143755dSCharles Keepax }
318*c143755dSCharles Keepax EXPORT_SYMBOL_NS(sdca_regmap_write_defaults, "SND_SOC_SDCA");
319