|  | // SPDX-License-Identifier: GPL-2.0+ | 
|  | // | 
|  | // soc-io.c  --  ASoC register I/O helpers | 
|  | // | 
|  | // Copyright 2009-2011 Wolfson Microelectronics PLC. | 
|  | // | 
|  | // Author: Mark Brown <broonie@opensource.wolfsonmicro.com> | 
|  |  | 
|  | #include <linux/i2c.h> | 
|  | #include <linux/spi/spi.h> | 
|  | #include <linux/regmap.h> | 
|  | #include <linux/export.h> | 
|  | #include <sound/soc.h> | 
|  |  | 
|  | /** | 
|  | * 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); |