// SPDX-License-Identifier: GPL-2.0+ // // soc-io.c -- ASoC register I/O helpers // // Copyright 2009-2011 Wolfson Microelectronics PLC. // // Author: Mark Brown #include #include #include #include #include /** * snd_soc_component_read() - Read register value * @component: Component to read from * @reg: Register to read * @val: Pointer to where the read value is stored * * Return: 0 on success, a negative error code otherwise. */ int snd_soc_component_read(struct snd_soc_component *component, unsigned int reg, unsigned int *val) { int ret; if (component->regmap) ret = regmap_read(component->regmap, reg, val); else if (component->driver->read) { *val = component->driver->read(component, reg); ret = 0; } else ret = -EIO; return ret; } EXPORT_SYMBOL_GPL(snd_soc_component_read); unsigned int snd_soc_component_read32(struct snd_soc_component *component, unsigned int reg) { unsigned int val; int ret; ret = snd_soc_component_read(component, reg, &val); if (ret < 0) return -1; return val; } EXPORT_SYMBOL_GPL(snd_soc_component_read32); /** * snd_soc_component_write() - Write register value * @component: Component to write to * @reg: Register to write * @val: Value to write to the register * * Return: 0 on success, a negative error code otherwise. */ int snd_soc_component_write(struct snd_soc_component *component, unsigned int reg, unsigned int val) { if (component->regmap) return regmap_write(component->regmap, reg, val); else if (component->driver->write) return component->driver->write(component, reg, val); else return -EIO; } EXPORT_SYMBOL_GPL(snd_soc_component_write); static int snd_soc_component_update_bits_legacy( struct snd_soc_component *component, unsigned int reg, unsigned int mask, unsigned int val, bool *change) { unsigned int old, new; int ret; mutex_lock(&component->io_mutex); ret = snd_soc_component_read(component, reg, &old); if (ret < 0) goto out_unlock; new = (old & ~mask) | (val & mask); *change = old != new; if (*change) ret = snd_soc_component_write(component, reg, new); out_unlock: mutex_unlock(&component->io_mutex); return ret; } /** * snd_soc_component_update_bits() - Perform read/modify/write cycle * @component: Component to update * @reg: Register to update * @mask: Mask that specifies which bits to update * @val: New value for the bits specified by mask * * Return: 1 if the operation was successful and the value of the register * changed, 0 if the operation was successful, but the value did not change. * Returns a negative error code otherwise. */ int snd_soc_component_update_bits(struct snd_soc_component *component, unsigned int reg, unsigned int mask, unsigned int val) { bool change; int ret; if (component->regmap) ret = regmap_update_bits_check(component->regmap, reg, mask, val, &change); else ret = snd_soc_component_update_bits_legacy(component, reg, mask, val, &change); if (ret < 0) return ret; return change; } EXPORT_SYMBOL_GPL(snd_soc_component_update_bits); /** * snd_soc_component_update_bits_async() - Perform asynchronous * read/modify/write cycle * @component: Component to update * @reg: Register to update * @mask: Mask that specifies which bits to update * @val: New value for the bits specified by mask * * This function is similar to snd_soc_component_update_bits(), but the update * operation is scheduled asynchronously. This means it may not be completed * when the function returns. To make sure that all scheduled updates have been * completed snd_soc_component_async_complete() must be called. * * Return: 1 if the operation was successful and the value of the register * changed, 0 if the operation was successful, but the value did not change. * Returns a negative error code otherwise. */ int snd_soc_component_update_bits_async(struct snd_soc_component *component, unsigned int reg, unsigned int mask, unsigned int val) { bool change; int ret; if (component->regmap) ret = regmap_update_bits_check_async(component->regmap, reg, mask, val, &change); else ret = snd_soc_component_update_bits_legacy(component, reg, mask, val, &change); if (ret < 0) return ret; return change; } EXPORT_SYMBOL_GPL(snd_soc_component_update_bits_async); /** * snd_soc_component_async_complete() - Ensure asynchronous I/O has completed * @component: Component for which to wait * * This function blocks until all asynchronous I/O which has previously been * scheduled using snd_soc_component_update_bits_async() has completed. */ void snd_soc_component_async_complete(struct snd_soc_component *component) { if (component->regmap) regmap_async_complete(component->regmap); } EXPORT_SYMBOL_GPL(snd_soc_component_async_complete); /** * snd_soc_component_test_bits - Test register for change * @component: component * @reg: Register to test * @mask: Mask that specifies which bits to test * @value: Value to test against * * Tests a register with a new value and checks if the new value is * different from the old value. * * Return: 1 for change, otherwise 0. */ int snd_soc_component_test_bits(struct snd_soc_component *component, unsigned int reg, unsigned int mask, unsigned int value) { unsigned int old, new; int ret; ret = snd_soc_component_read(component, reg, &old); if (ret < 0) return ret; new = (old & ~mask) | value; return old != new; } EXPORT_SYMBOL_GPL(snd_soc_component_test_bits);