blob: b56e1c4bb9e6f9a6ca1510c53fde6fbb23a954a7 [file] [log] [blame]
Mark Brown5bef44f2011-06-13 17:49:55 +01001/*
2 * soc-io.c -- ASoC register I/O helpers
3 *
4 * Copyright 2009-2011 Wolfson Microelectronics PLC.
5 *
6 * Author: Mark Brown <broonie@opensource.wolfsonmicro.com>
7 *
8 * This program is free software; you can redistribute it and/or modify it
9 * under the terms of the GNU General Public License as published by the
10 * Free Software Foundation; either version 2 of the License, or (at your
11 * option) any later version.
12 */
13
14#include <linux/i2c.h>
15#include <linux/spi/spi.h>
Mark Brownbe3ea3b2011-06-13 19:35:29 +010016#include <linux/regmap.h>
Mark Brown5bef44f2011-06-13 17:49:55 +010017#include <sound/soc.h>
18
19#include <trace/events/asoc.h>
20
Mark Brownbe3ea3b2011-06-13 19:35:29 +010021static int hw_write(struct snd_soc_codec *codec, unsigned int reg,
22 unsigned int value)
Mark Brown5bef44f2011-06-13 17:49:55 +010023{
24 int ret;
25
26 if (!snd_soc_codec_volatile_register(codec, reg) &&
27 reg < codec->driver->reg_cache_size &&
28 !codec->cache_bypass) {
29 ret = snd_soc_cache_write(codec, reg, value);
30 if (ret < 0)
31 return -1;
32 }
33
34 if (codec->cache_only) {
35 codec->cache_sync = 1;
36 return 0;
37 }
38
Mark Brownbe3ea3b2011-06-13 19:35:29 +010039 return regmap_write(codec->control_data, reg, value);
Mark Brown5bef44f2011-06-13 17:49:55 +010040}
41
42static unsigned int hw_read(struct snd_soc_codec *codec, unsigned int reg)
43{
44 int ret;
45 unsigned int val;
46
47 if (reg >= codec->driver->reg_cache_size ||
48 snd_soc_codec_volatile_register(codec, reg) ||
49 codec->cache_bypass) {
50 if (codec->cache_only)
51 return -1;
52
Mark Brownbe3ea3b2011-06-13 19:35:29 +010053 ret = regmap_read(codec->control_data, reg, &val);
54 if (ret == 0)
55 return val;
56 else
57 return ret;
Mark Brown5bef44f2011-06-13 17:49:55 +010058 }
59
60 ret = snd_soc_cache_read(codec, reg, &val);
61 if (ret < 0)
62 return -1;
63 return val;
64}
65
Mark Brown5bef44f2011-06-13 17:49:55 +010066/* Primitive bulk write support for soc-cache. The data pointed to by
Mark Brownbe3ea3b2011-06-13 19:35:29 +010067 * `data' needs to already be in the form the hardware expects. Any
68 * data written through this function will not go through the cache as
69 * it only handles writing to volatile or out of bounds registers.
70 *
71 * This is currently only supported for devices using the regmap API
72 * wrappers.
Mark Brown5bef44f2011-06-13 17:49:55 +010073 */
Mark Brownbe3ea3b2011-06-13 19:35:29 +010074static int snd_soc_hw_bulk_write_raw(struct snd_soc_codec *codec,
75 unsigned int reg,
Mark Brown5bef44f2011-06-13 17:49:55 +010076 const void *data, size_t len)
77{
Mark Brown5bef44f2011-06-13 17:49:55 +010078 /* To ensure that we don't get out of sync with the cache, check
79 * whether the base register is volatile or if we've directly asked
80 * to bypass the cache. Out of bounds registers are considered
81 * volatile.
82 */
83 if (!codec->cache_bypass
84 && !snd_soc_codec_volatile_register(codec, reg)
85 && reg < codec->driver->reg_cache_size)
86 return -EINVAL;
87
Mark Brownbe3ea3b2011-06-13 19:35:29 +010088 return regmap_raw_write(codec->control_data, reg, data, len);
Mark Brown5bef44f2011-06-13 17:49:55 +010089}
90
Mark Brown5bef44f2011-06-13 17:49:55 +010091/**
92 * snd_soc_codec_set_cache_io: Set up standard I/O functions.
93 *
94 * @codec: CODEC to configure.
95 * @addr_bits: Number of bits of register address data.
96 * @data_bits: Number of bits of data per register.
97 * @control: Control bus used.
98 *
99 * Register formats are frequently shared between many I2C and SPI
100 * devices. In order to promote code reuse the ASoC core provides
101 * some standard implementations of CODEC read and write operations
102 * which can be set up using this function.
103 *
104 * The caller is responsible for allocating and initialising the
105 * actual cache.
106 *
107 * Note that at present this code cannot be used by CODECs with
108 * volatile registers.
109 */
110int snd_soc_codec_set_cache_io(struct snd_soc_codec *codec,
111 int addr_bits, int data_bits,
112 enum snd_soc_control_type control)
113{
Mark Brownbe3ea3b2011-06-13 19:35:29 +0100114 struct regmap_config config;
Mark Brown5bef44f2011-06-13 17:49:55 +0100115
Mark Brownbe3ea3b2011-06-13 19:35:29 +0100116 memset(&config, 0, sizeof(config));
117 codec->write = hw_write;
Mark Brown5bef44f2011-06-13 17:49:55 +0100118 codec->read = hw_read;
119 codec->bulk_write_raw = snd_soc_hw_bulk_write_raw;
120
Mark Brownbe3ea3b2011-06-13 19:35:29 +0100121 config.reg_bits = addr_bits;
122 config.val_bits = data_bits;
123
Mark Brown5bef44f2011-06-13 17:49:55 +0100124 switch (control) {
Mark Brown5bef44f2011-06-13 17:49:55 +0100125 case SND_SOC_I2C:
Mark Brownbe3ea3b2011-06-13 19:35:29 +0100126 codec->control_data = regmap_init_i2c(to_i2c_client(codec->dev),
127 &config);
Mark Brown5bef44f2011-06-13 17:49:55 +0100128 break;
129
130 case SND_SOC_SPI:
Mark Brownbe3ea3b2011-06-13 19:35:29 +0100131 codec->control_data = regmap_init_spi(to_spi_device(codec->dev),
132 &config);
Mark Brown5bef44f2011-06-13 17:49:55 +0100133 break;
Mark Brownbe3ea3b2011-06-13 19:35:29 +0100134
135 default:
136 return -EINVAL;
Mark Brown5bef44f2011-06-13 17:49:55 +0100137 }
138
Mark Brownbe3ea3b2011-06-13 19:35:29 +0100139 if (IS_ERR(codec->control_data))
140 return PTR_ERR(codec->control_data);
141
Mark Brown5bef44f2011-06-13 17:49:55 +0100142 return 0;
143}
144EXPORT_SYMBOL_GPL(snd_soc_codec_set_cache_io);
145