diff options
author | Daniel Mack <zonque@gmail.com> | 2013-06-24 10:25:29 -0400 |
---|---|---|
committer | Mark Brown <broonie@linaro.org> | 2013-06-25 05:26:47 -0400 |
commit | 6b36d370ad66aa73328a0cd8763f6028e7b28f6c (patch) | |
tree | e32c4937997c12caa09f609a56abf17b3ee51519 /sound | |
parent | 9e895ace5d82df8929b16f58e9f515f6d54ab82d (diff) |
ASoC: tas5086: open-code I2C transfer routines
In order to support registers of unequal sizes, the I2C I/O has to be
open-coded.
Signed-off-by: Daniel Mack <zonque@gmail.com>
Signed-off-by: Mark Brown <broonie@linaro.org>
Diffstat (limited to 'sound')
-rw-r--r-- | sound/soc/codecs/tas5086.c | 85 |
1 files changed, 84 insertions, 1 deletions
diff --git a/sound/soc/codecs/tas5086.c b/sound/soc/codecs/tas5086.c index d447c4aa1d5e..57c9de02b14f 100644 --- a/sound/soc/codecs/tas5086.c +++ b/sound/soc/codecs/tas5086.c | |||
@@ -119,6 +119,17 @@ static const struct reg_default tas5086_reg_defaults[] = { | |||
119 | { 0x1c, 0x05 }, | 119 | { 0x1c, 0x05 }, |
120 | }; | 120 | }; |
121 | 121 | ||
122 | static int tas5086_register_size(struct device *dev, unsigned int reg) | ||
123 | { | ||
124 | switch (reg) { | ||
125 | case TAS5086_DEV_ID ... TAS5086_BKNDERR: | ||
126 | return 1; | ||
127 | } | ||
128 | |||
129 | dev_err(dev, "Unsupported register address: %d\n", reg); | ||
130 | return 0; | ||
131 | } | ||
132 | |||
122 | static bool tas5086_accessible_reg(struct device *dev, unsigned int reg) | 133 | static bool tas5086_accessible_reg(struct device *dev, unsigned int reg) |
123 | { | 134 | { |
124 | return !((reg == 0x0f) || (reg >= 0x11 && reg <= 0x17)); | 135 | return !((reg == 0x0f) || (reg >= 0x11 && reg <= 0x17)); |
@@ -140,6 +151,76 @@ static bool tas5086_writeable_reg(struct device *dev, unsigned int reg) | |||
140 | return tas5086_accessible_reg(dev, reg) && (reg != TAS5086_DEV_ID); | 151 | return tas5086_accessible_reg(dev, reg) && (reg != TAS5086_DEV_ID); |
141 | } | 152 | } |
142 | 153 | ||
154 | static int tas5086_reg_write(void *context, unsigned int reg, | ||
155 | unsigned int value) | ||
156 | { | ||
157 | struct i2c_client *client = context; | ||
158 | unsigned int i, size; | ||
159 | uint8_t buf[5]; | ||
160 | int ret; | ||
161 | |||
162 | size = tas5086_register_size(&client->dev, reg); | ||
163 | if (size == 0) | ||
164 | return -EINVAL; | ||
165 | |||
166 | buf[0] = reg; | ||
167 | |||
168 | for (i = size; i >= 1; --i) { | ||
169 | buf[i] = value; | ||
170 | value >>= 8; | ||
171 | } | ||
172 | |||
173 | ret = i2c_master_send(client, buf, size + 1); | ||
174 | if (ret == size + 1) | ||
175 | return 0; | ||
176 | else if (ret < 0) | ||
177 | return ret; | ||
178 | else | ||
179 | return -EIO; | ||
180 | } | ||
181 | |||
182 | static int tas5086_reg_read(void *context, unsigned int reg, | ||
183 | unsigned int *value) | ||
184 | { | ||
185 | struct i2c_client *client = context; | ||
186 | uint8_t send_buf, recv_buf[4]; | ||
187 | struct i2c_msg msgs[2]; | ||
188 | unsigned int size; | ||
189 | unsigned int i; | ||
190 | int ret; | ||
191 | |||
192 | size = tas5086_register_size(&client->dev, reg); | ||
193 | if (size == 0) | ||
194 | return -EINVAL; | ||
195 | |||
196 | send_buf = reg; | ||
197 | |||
198 | msgs[0].addr = client->addr; | ||
199 | msgs[0].len = sizeof(send_buf); | ||
200 | msgs[0].buf = &send_buf; | ||
201 | msgs[0].flags = 0; | ||
202 | |||
203 | msgs[1].addr = client->addr; | ||
204 | msgs[1].len = size; | ||
205 | msgs[1].buf = recv_buf; | ||
206 | msgs[1].flags = I2C_M_RD; | ||
207 | |||
208 | ret = i2c_transfer(client->adapter, msgs, ARRAY_SIZE(msgs)); | ||
209 | if (ret < 0) | ||
210 | return ret; | ||
211 | else if (ret != ARRAY_SIZE(msgs)) | ||
212 | return -EIO; | ||
213 | |||
214 | *value = 0; | ||
215 | |||
216 | for (i = 0; i < size; i++) { | ||
217 | *value <<= 8; | ||
218 | *value |= recv_buf[i]; | ||
219 | } | ||
220 | |||
221 | return 0; | ||
222 | } | ||
223 | |||
143 | struct tas5086_private { | 224 | struct tas5086_private { |
144 | struct regmap *regmap; | 225 | struct regmap *regmap; |
145 | unsigned int mclk, sclk; | 226 | unsigned int mclk, sclk; |
@@ -508,6 +589,8 @@ static const struct regmap_config tas5086_regmap = { | |||
508 | .volatile_reg = tas5086_volatile_reg, | 589 | .volatile_reg = tas5086_volatile_reg, |
509 | .writeable_reg = tas5086_writeable_reg, | 590 | .writeable_reg = tas5086_writeable_reg, |
510 | .readable_reg = tas5086_accessible_reg, | 591 | .readable_reg = tas5086_accessible_reg, |
592 | .reg_read = tas5086_reg_read, | ||
593 | .reg_write = tas5086_reg_write, | ||
511 | }; | 594 | }; |
512 | 595 | ||
513 | static int tas5086_i2c_probe(struct i2c_client *i2c, | 596 | static int tas5086_i2c_probe(struct i2c_client *i2c, |
@@ -522,7 +605,7 @@ static int tas5086_i2c_probe(struct i2c_client *i2c, | |||
522 | if (!priv) | 605 | if (!priv) |
523 | return -ENOMEM; | 606 | return -ENOMEM; |
524 | 607 | ||
525 | priv->regmap = devm_regmap_init_i2c(i2c, &tas5086_regmap); | 608 | priv->regmap = devm_regmap_init(dev, NULL, i2c, &tas5086_regmap); |
526 | if (IS_ERR(priv->regmap)) { | 609 | if (IS_ERR(priv->regmap)) { |
527 | ret = PTR_ERR(priv->regmap); | 610 | ret = PTR_ERR(priv->regmap); |
528 | dev_err(&i2c->dev, "Failed to create regmap: %d\n", ret); | 611 | dev_err(&i2c->dev, "Failed to create regmap: %d\n", ret); |