| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381 |
- // SPDX-License-Identifier: GPL-2.0
- // Copyright (C) 2025 Cirrus Logic, Inc. and
- // Cirrus Logic International Semiconductor Ltd.
- /*
- * The MIPI SDCA specification is available for public downloads at
- * https://www.mipi.org/mipi-sdca-v1-0-download
- */
- #include <linux/bitops.h>
- #include <linux/minmax.h>
- #include <linux/module.h>
- #include <linux/regmap.h>
- #include <linux/soundwire/sdw_registers.h>
- #include <linux/types.h>
- #include <sound/sdca.h>
- #include <sound/sdca_function.h>
- #include <sound/sdca_regmap.h>
- static struct sdca_entity *
- function_find_entity(struct sdca_function_data *function, unsigned int reg)
- {
- int i;
- for (i = 0; i < function->num_entities; i++)
- if (SDW_SDCA_CTL_ENT(reg) == function->entities[i].id)
- return &function->entities[i];
- return NULL;
- }
- static struct sdca_control *
- entity_find_control(struct sdca_entity *entity, unsigned int reg)
- {
- int i;
- for (i = 0; i < entity->num_controls; i++) {
- if (SDW_SDCA_CTL_CSEL(reg) == entity->controls[i].sel)
- return &entity->controls[i];
- }
- return NULL;
- }
- static struct sdca_control *
- function_find_control(struct sdca_function_data *function, unsigned int reg)
- {
- struct sdca_entity *entity;
- entity = function_find_entity(function, reg);
- if (!entity)
- return NULL;
- return entity_find_control(entity, reg);
- }
- /**
- * sdca_regmap_readable - return if a given SDCA Control is readable
- * @function: Pointer to the Function information.
- * @reg: Register address/Control to be processed.
- *
- * Return: Returns true if the register is readable.
- */
- bool sdca_regmap_readable(struct sdca_function_data *function, unsigned int reg)
- {
- struct sdca_control *control;
- if (!SDW_SDCA_VALID_CTL(reg))
- return false;
- control = function_find_control(function, reg);
- if (!control)
- return false;
- if (!(BIT(SDW_SDCA_CTL_CNUM(reg)) & control->cn_list))
- return false;
- switch (control->mode) {
- case SDCA_ACCESS_MODE_RW:
- case SDCA_ACCESS_MODE_RO:
- case SDCA_ACCESS_MODE_RW1S:
- case SDCA_ACCESS_MODE_RW1C:
- if (SDW_SDCA_NEXT_CTL(0) & reg)
- return false;
- fallthrough;
- case SDCA_ACCESS_MODE_DUAL:
- /* No access to registers marked solely for device use */
- return control->layers & ~SDCA_ACCESS_LAYER_DEVICE;
- default:
- return false;
- }
- }
- EXPORT_SYMBOL_NS(sdca_regmap_readable, "SND_SOC_SDCA");
- /**
- * sdca_regmap_writeable - return if a given SDCA Control is writeable
- * @function: Pointer to the Function information.
- * @reg: Register address/Control to be processed.
- *
- * Return: Returns true if the register is writeable.
- */
- bool sdca_regmap_writeable(struct sdca_function_data *function, unsigned int reg)
- {
- struct sdca_control *control;
- if (!SDW_SDCA_VALID_CTL(reg))
- return false;
- control = function_find_control(function, reg);
- if (!control)
- return false;
- if (!(BIT(SDW_SDCA_CTL_CNUM(reg)) & control->cn_list))
- return false;
- switch (control->mode) {
- case SDCA_ACCESS_MODE_RW:
- case SDCA_ACCESS_MODE_RW1S:
- case SDCA_ACCESS_MODE_RW1C:
- if (SDW_SDCA_NEXT_CTL(0) & reg)
- return false;
- fallthrough;
- case SDCA_ACCESS_MODE_DUAL:
- /* No access to registers marked solely for device use */
- return control->layers & ~SDCA_ACCESS_LAYER_DEVICE;
- default:
- return false;
- }
- }
- EXPORT_SYMBOL_NS(sdca_regmap_writeable, "SND_SOC_SDCA");
- /**
- * sdca_regmap_volatile - return if a given SDCA Control is volatile
- * @function: Pointer to the Function information.
- * @reg: Register address/Control to be processed.
- *
- * Return: Returns true if the register is volatile.
- */
- bool sdca_regmap_volatile(struct sdca_function_data *function, unsigned int reg)
- {
- struct sdca_control *control;
- if (!SDW_SDCA_VALID_CTL(reg))
- return false;
- control = function_find_control(function, reg);
- if (!control)
- return false;
- return control->is_volatile;
- }
- EXPORT_SYMBOL_NS(sdca_regmap_volatile, "SND_SOC_SDCA");
- /**
- * sdca_regmap_deferrable - return if a given SDCA Control is deferrable
- * @function: Pointer to the Function information.
- * @reg: Register address/Control to be processed.
- *
- * Return: Returns true if the register is deferrable.
- */
- bool sdca_regmap_deferrable(struct sdca_function_data *function, unsigned int reg)
- {
- struct sdca_control *control;
- if (!SDW_SDCA_VALID_CTL(reg))
- return false;
- control = function_find_control(function, reg);
- if (!control)
- return false;
- return control->deferrable;
- }
- EXPORT_SYMBOL_NS(sdca_regmap_deferrable, "SND_SOC_SDCA");
- /**
- * sdca_regmap_mbq_size - return size in bytes of a given SDCA Control
- * @function: Pointer to the Function information.
- * @reg: Register address/Control to be processed.
- *
- * Return: Returns the size in bytes of the Control.
- */
- int sdca_regmap_mbq_size(struct sdca_function_data *function, unsigned int reg)
- {
- struct sdca_control *control;
- if (!SDW_SDCA_VALID_CTL(reg))
- return -EINVAL;
- control = function_find_control(function, reg);
- if (!control)
- return -EINVAL;
- return clamp_val(control->nbits / BITS_PER_BYTE, sizeof(u8), sizeof(u32));
- }
- EXPORT_SYMBOL_NS(sdca_regmap_mbq_size, "SND_SOC_SDCA");
- /**
- * sdca_regmap_count_constants - count the number of DisCo constant Controls
- * @dev: Pointer to the device.
- * @function: Pointer to the Function information, to be parsed.
- *
- * This function returns the number of DisCo constant Controls present
- * in a function. Typically this information will be used to populate
- * the regmap defaults array, allowing drivers to access the values of
- * DisCo constants as any other physical register.
- *
- * Return: Returns number of DisCo constant controls, or a negative error
- * code on failure.
- */
- int sdca_regmap_count_constants(struct device *dev,
- struct sdca_function_data *function)
- {
- int nconsts = 0;
- int i, j;
- for (i = 0; i < function->num_entities; i++) {
- struct sdca_entity *entity = &function->entities[i];
- for (j = 0; j < entity->num_controls; j++) {
- if (entity->controls[j].mode == SDCA_ACCESS_MODE_DC ||
- entity->controls[j].has_reset)
- nconsts += hweight64(entity->controls[j].cn_list);
- }
- }
- return nconsts;
- }
- EXPORT_SYMBOL_NS(sdca_regmap_count_constants, "SND_SOC_SDCA");
- /**
- * sdca_regmap_populate_constants - fill an array with DisCo constant values
- * @dev: Pointer to the device.
- * @function: Pointer to the Function information, to be parsed.
- * @consts: Pointer to the array which should be filled with the DisCo
- * constant values.
- *
- * This function will populate a regmap struct reg_default array with
- * the values of the DisCo constants for a given Function. This
- * allows to access the values of DisCo constants the same as any
- * other physical register.
- *
- * Return: Returns the number of constants populated on success, a negative
- * error code on failure.
- */
- int sdca_regmap_populate_constants(struct device *dev,
- struct sdca_function_data *function,
- struct reg_default *consts)
- {
- int i, j, k, l;
- for (i = 0, k = 0; i < function->num_entities; i++) {
- struct sdca_entity *entity = &function->entities[i];
- for (j = 0; j < entity->num_controls; j++) {
- struct sdca_control *control = &entity->controls[j];
- int cn;
- if (control->mode != SDCA_ACCESS_MODE_DC &&
- !control->has_reset)
- continue;
- l = 0;
- for_each_set_bit(cn, (unsigned long *)&control->cn_list,
- BITS_PER_TYPE(control->cn_list)) {
- consts[k].reg = SDW_SDCA_CTL(function->desc->adr,
- entity->id,
- control->sel, cn);
- if (control->mode == SDCA_ACCESS_MODE_DC)
- consts[k].def = control->values[l];
- else
- consts[k].def = control->reset;
- k++;
- l++;
- }
- }
- }
- return k;
- }
- EXPORT_SYMBOL_NS(sdca_regmap_populate_constants, "SND_SOC_SDCA");
- static int populate_control_defaults(struct device *dev, struct regmap *regmap,
- struct sdca_function_data *function,
- struct sdca_entity *entity,
- struct sdca_control *control)
- {
- int i, ret;
- int cn;
- if (control->mode == SDCA_ACCESS_MODE_DC)
- return 0;
- if (control->layers & SDCA_ACCESS_LAYER_DEVICE)
- return 0;
- i = 0;
- for_each_set_bit(cn, (unsigned long *)&control->cn_list,
- BITS_PER_TYPE(control->cn_list)) {
- unsigned int reg, val;
- reg = SDW_SDCA_CTL(function->desc->adr, entity->id, control->sel, cn);
- if (control->has_default || control->has_fixed) {
- ret = regmap_write(regmap, reg, control->values[i]);
- if (ret) {
- dev_err(dev, "Failed to write default %#x: %d\n",
- reg, ret);
- return ret;
- }
- i++;
- } else if (!control->is_volatile) {
- if (control->has_reset)
- regcache_drop_region(regmap, reg, reg);
- ret = regmap_read(regmap, reg, &val);
- if (ret) {
- dev_err(dev, "Failed to read initial %#x: %d\n",
- reg, ret);
- return ret;
- }
- }
- }
- return 0;
- }
- /**
- * sdca_regmap_write_defaults - write out DisCo defaults to device
- * @dev: Pointer to the device.
- * @regmap: Pointer to the Function register map.
- * @function: Pointer to the Function information, to be parsed.
- *
- * This function will write out to the hardware all the DisCo default and
- * fixed value controls. This will cause them to be populated into the cache,
- * and subsequent handling can be done through a cache sync. It will also
- * read any non-volatile registers that don't have defaults/fixed values to
- * populate those into the cache, this ensures they are available for reads
- * even when the device is runtime suspended.
- *
- * Return: Returns zero on success, and a negative error code on failure.
- */
- int sdca_regmap_write_defaults(struct device *dev, struct regmap *regmap,
- struct sdca_function_data *function)
- {
- int i, j;
- int ret;
- for (i = 0; i < function->num_entities; i++) {
- struct sdca_entity *entity = &function->entities[i];
- for (j = 0; j < entity->num_controls; j++) {
- struct sdca_control *control = &entity->controls[j];
- ret = populate_control_defaults(dev, regmap, function,
- entity, control);
- if (ret)
- return ret;
- }
- }
- return 0;
- }
- EXPORT_SYMBOL_NS(sdca_regmap_write_defaults, "SND_SOC_SDCA");
- int sdca_regmap_write_init(struct device *dev, struct regmap *regmap,
- struct sdca_function_data *function)
- {
- struct sdca_init_write *init = function->init_table;
- int ret, i;
- for (i = 0; i < function->num_init_table; i++) {
- ret = regmap_write(regmap, init[i].addr, init[i].val);
- if (ret)
- return ret;
- }
- return 0;
- }
- EXPORT_SYMBOL_NS(sdca_regmap_write_init, "SND_SOC_SDCA");
|