linux/sound/soc/soc-io.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0+
   2//
   3// soc-io.c  --  ASoC register I/O helpers
   4//
   5// Copyright 2009-2011 Wolfson Microelectronics PLC.
   6//
   7// Author: Mark Brown <broonie@opensource.wolfsonmicro.com>
   8
   9#include <linux/i2c.h>
  10#include <linux/spi/spi.h>
  11#include <linux/regmap.h>
  12#include <linux/export.h>
  13#include <sound/soc.h>
  14
  15/**
  16 * snd_soc_component_read() - Read register value
  17 * @component: Component to read from
  18 * @reg: Register to read
  19 * @val: Pointer to where the read value is stored
  20 *
  21 * Return: 0 on success, a negative error code otherwise.
  22 */
  23int snd_soc_component_read(struct snd_soc_component *component,
  24        unsigned int reg, unsigned int *val)
  25{
  26        int ret;
  27
  28        if (component->regmap)
  29                ret = regmap_read(component->regmap, reg, val);
  30        else if (component->driver->read) {
  31                *val = component->driver->read(component, reg);
  32                ret = 0;
  33        }
  34        else
  35                ret = -EIO;
  36
  37        return ret;
  38}
  39EXPORT_SYMBOL_GPL(snd_soc_component_read);
  40
  41unsigned int snd_soc_component_read32(struct snd_soc_component *component,
  42                                      unsigned int reg)
  43{
  44        unsigned int val;
  45        int ret;
  46
  47        ret = snd_soc_component_read(component, reg, &val);
  48        if (ret < 0)
  49                return -1;
  50
  51        return val;
  52}
  53EXPORT_SYMBOL_GPL(snd_soc_component_read32);
  54
  55/**
  56 * snd_soc_component_write() - Write register value
  57 * @component: Component to write to
  58 * @reg: Register to write
  59 * @val: Value to write to the register
  60 *
  61 * Return: 0 on success, a negative error code otherwise.
  62 */
  63int snd_soc_component_write(struct snd_soc_component *component,
  64        unsigned int reg, unsigned int val)
  65{
  66        if (component->regmap)
  67                return regmap_write(component->regmap, reg, val);
  68        else if (component->driver->write)
  69                return component->driver->write(component, reg, val);
  70        else
  71                return -EIO;
  72}
  73EXPORT_SYMBOL_GPL(snd_soc_component_write);
  74
  75static int snd_soc_component_update_bits_legacy(
  76        struct snd_soc_component *component, unsigned int reg,
  77        unsigned int mask, unsigned int val, bool *change)
  78{
  79        unsigned int old, new;
  80        int ret;
  81
  82        mutex_lock(&component->io_mutex);
  83
  84        ret = snd_soc_component_read(component, reg, &old);
  85        if (ret < 0)
  86                goto out_unlock;
  87
  88        new = (old & ~mask) | (val & mask);
  89        *change = old != new;
  90        if (*change)
  91                ret = snd_soc_component_write(component, reg, new);
  92out_unlock:
  93        mutex_unlock(&component->io_mutex);
  94
  95        return ret;
  96}
  97
  98/**
  99 * snd_soc_component_update_bits() - Perform read/modify/write cycle
 100 * @component: Component to update
 101 * @reg: Register to update
 102 * @mask: Mask that specifies which bits to update
 103 * @val: New value for the bits specified by mask
 104 *
 105 * Return: 1 if the operation was successful and the value of the register
 106 * changed, 0 if the operation was successful, but the value did not change.
 107 * Returns a negative error code otherwise.
 108 */
 109int snd_soc_component_update_bits(struct snd_soc_component *component,
 110        unsigned int reg, unsigned int mask, unsigned int val)
 111{
 112        bool change;
 113        int ret;
 114
 115        if (component->regmap)
 116                ret = regmap_update_bits_check(component->regmap, reg, mask,
 117                        val, &change);
 118        else
 119                ret = snd_soc_component_update_bits_legacy(component, reg,
 120                        mask, val, &change);
 121
 122        if (ret < 0)
 123                return ret;
 124        return change;
 125}
 126EXPORT_SYMBOL_GPL(snd_soc_component_update_bits);
 127
 128/**
 129 * snd_soc_component_update_bits_async() - Perform asynchronous
 130 *  read/modify/write cycle
 131 * @component: Component to update
 132 * @reg: Register to update
 133 * @mask: Mask that specifies which bits to update
 134 * @val: New value for the bits specified by mask
 135 *
 136 * This function is similar to snd_soc_component_update_bits(), but the update
 137 * operation is scheduled asynchronously. This means it may not be completed
 138 * when the function returns. To make sure that all scheduled updates have been
 139 * completed snd_soc_component_async_complete() must be called.
 140 *
 141 * Return: 1 if the operation was successful and the value of the register
 142 * changed, 0 if the operation was successful, but the value did not change.
 143 * Returns a negative error code otherwise.
 144 */
 145int snd_soc_component_update_bits_async(struct snd_soc_component *component,
 146        unsigned int reg, unsigned int mask, unsigned int val)
 147{
 148        bool change;
 149        int ret;
 150
 151        if (component->regmap)
 152                ret = regmap_update_bits_check_async(component->regmap, reg,
 153                        mask, val, &change);
 154        else
 155                ret = snd_soc_component_update_bits_legacy(component, reg,
 156                        mask, val, &change);
 157
 158        if (ret < 0)
 159                return ret;
 160        return change;
 161}
 162EXPORT_SYMBOL_GPL(snd_soc_component_update_bits_async);
 163
 164/**
 165 * snd_soc_component_async_complete() - Ensure asynchronous I/O has completed
 166 * @component: Component for which to wait
 167 *
 168 * This function blocks until all asynchronous I/O which has previously been
 169 * scheduled using snd_soc_component_update_bits_async() has completed.
 170 */
 171void snd_soc_component_async_complete(struct snd_soc_component *component)
 172{
 173        if (component->regmap)
 174                regmap_async_complete(component->regmap);
 175}
 176EXPORT_SYMBOL_GPL(snd_soc_component_async_complete);
 177
 178/**
 179 * snd_soc_component_test_bits - Test register for change
 180 * @component: component
 181 * @reg: Register to test
 182 * @mask: Mask that specifies which bits to test
 183 * @value: Value to test against
 184 *
 185 * Tests a register with a new value and checks if the new value is
 186 * different from the old value.
 187 *
 188 * Return: 1 for change, otherwise 0.
 189 */
 190int snd_soc_component_test_bits(struct snd_soc_component *component,
 191        unsigned int reg, unsigned int mask, unsigned int value)
 192{
 193        unsigned int old, new;
 194        int ret;
 195
 196        ret = snd_soc_component_read(component, reg, &old);
 197        if (ret < 0)
 198                return ret;
 199        new = (old & ~mask) | value;
 200        return old != new;
 201}
 202EXPORT_SYMBOL_GPL(snd_soc_component_test_bits);
 203