ASoC: Factor out I2C 8 bit address 16 bit data I/O
[safe/jmp/linux-2.6] / sound / soc / soc-cache.c
1 /*
2  * soc-cache.c  --  ASoC register cache helpers
3  *
4  * Copyright 2009 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 <sound/soc.h>
16
17 static unsigned int snd_soc_7_9_read(struct snd_soc_codec *codec,
18                                      unsigned int reg)
19 {
20         u16 *cache = codec->reg_cache;
21         if (reg >= codec->reg_cache_size)
22                 return -1;
23         return cache[reg];
24 }
25
26 static int snd_soc_7_9_write(struct snd_soc_codec *codec, unsigned int reg,
27                              unsigned int value)
28 {
29         u16 *cache = codec->reg_cache;
30         u8 data[2];
31         int ret;
32
33         BUG_ON(codec->volatile_register);
34
35         data[0] = (reg << 1) | ((value >> 8) & 0x0001);
36         data[1] = value & 0x00ff;
37
38         if (reg < codec->reg_cache_size)
39                 cache[reg] = value;
40         ret = codec->hw_write(codec->control_data, data, 2);
41         if (ret == 2)
42                 return 0;
43         if (ret < 0)
44                 return ret;
45         else
46                 return -EIO;
47 }
48
49 static int snd_soc_8_16_write(struct snd_soc_codec *codec, unsigned int reg,
50                               unsigned int value)
51 {
52         u16 *reg_cache = codec->reg_cache;
53         u8 data[3];
54
55         data[0] = reg;
56         data[1] = (value >> 8) & 0xff;
57         data[2] = value & 0xff;
58
59         if (!snd_soc_codec_volatile_register(codec, reg))
60                 reg_cache[reg] = value;
61
62         if (codec->hw_write(codec->control_data, data, 3) == 3)
63                 return 0;
64         else
65                 return -EIO;
66 }
67
68 static unsigned int snd_soc_8_16_read(struct snd_soc_codec *codec,
69                                       unsigned int reg)
70 {
71         u16 *cache = codec->reg_cache;
72
73         if (reg >= codec->reg_cache_size ||
74             snd_soc_codec_volatile_register(codec, reg))
75                 return codec->hw_read(codec, reg);
76         else
77                 return cache[reg];
78 }
79
80 #if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
81 static unsigned int snd_soc_8_16_read_i2c(struct snd_soc_codec *codec,
82                                           unsigned int r)
83 {
84         struct i2c_msg xfer[2];
85         u8 reg = r;
86         u16 data;
87         int ret;
88         struct i2c_client *client = codec->control_data;
89
90         /* Write register */
91         xfer[0].addr = client->addr;
92         xfer[0].flags = 0;
93         xfer[0].len = 1;
94         xfer[0].buf = &reg;
95
96         /* Read data */
97         xfer[1].addr = client->addr;
98         xfer[1].flags = I2C_M_RD;
99         xfer[1].len = 2;
100         xfer[1].buf = (u8 *)&data;
101
102         ret = i2c_transfer(client->adapter, xfer, 2);
103         if (ret != 2) {
104                 dev_err(&client->dev, "i2c_transfer() returned %d\n", ret);
105                 return 0;
106         }
107
108         return (data >> 8) | ((data & 0xff) << 8);
109 }
110 #else
111 #define snd_soc_8_16_read_i2c NULL
112 #endif
113
114 static struct {
115         int addr_bits;
116         int data_bits;
117         int (*write)(struct snd_soc_codec *codec, unsigned int, unsigned int);
118         unsigned int (*read)(struct snd_soc_codec *, unsigned int);
119         unsigned int (*i2c_read)(struct snd_soc_codec *, unsigned int);
120 } io_types[] = {
121         { 7, 9, snd_soc_7_9_write, snd_soc_7_9_read },
122         { 8, 16,
123           snd_soc_8_16_write, snd_soc_8_16_read,
124           snd_soc_8_16_read_i2c },
125 };
126
127 /**
128  * snd_soc_codec_set_cache_io: Set up standard I/O functions.
129  *
130  * @codec: CODEC to configure.
131  * @type: Type of cache.
132  * @addr_bits: Number of bits of register address data.
133  * @data_bits: Number of bits of data per register.
134  * @control: Control bus used.
135  *
136  * Register formats are frequently shared between many I2C and SPI
137  * devices.  In order to promote code reuse the ASoC core provides
138  * some standard implementations of CODEC read and write operations
139  * which can be set up using this function.
140  *
141  * The caller is responsible for allocating and initialising the
142  * actual cache.
143  *
144  * Note that at present this code cannot be used by CODECs with
145  * volatile registers.
146  */
147 int snd_soc_codec_set_cache_io(struct snd_soc_codec *codec,
148                                int addr_bits, int data_bits,
149                                enum snd_soc_control_type control)
150 {
151         int i;
152
153         for (i = 0; i < ARRAY_SIZE(io_types); i++)
154                 if (io_types[i].addr_bits == addr_bits &&
155                     io_types[i].data_bits == data_bits)
156                         break;
157         if (i == ARRAY_SIZE(io_types)) {
158                 printk(KERN_ERR
159                        "No I/O functions for %d bit address %d bit data\n",
160                        addr_bits, data_bits);
161                 return -EINVAL;
162         }
163
164         codec->write = io_types[i].write;
165         codec->read = io_types[i].read;
166
167         switch (control) {
168         case SND_SOC_CUSTOM:
169                 break;
170
171         case SND_SOC_I2C:
172 #if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
173                 codec->hw_write = (hw_write_t)i2c_master_send;
174 #endif
175                 if (io_types[i].i2c_read)
176                         codec->hw_read = io_types[i].i2c_read;
177                 break;
178
179         case SND_SOC_SPI:
180                 break;
181         }
182
183         return 0;
184 }
185 EXPORT_SYMBOL_GPL(snd_soc_codec_set_cache_io);