ASoC: ad193x: Setup regmap read and write flag masks for SPI

Currently register read-back for the ad193x is broken, because it expects bit 0
of the upper byte to be set to indicate a read operation, while the regmap
default for SPI is to use bit 7.

This patch also addresses another oddity of the device. There are SPI and I2C
versions of this codec. In both cases the registers are 8-bit wide and numbered
from 0x0 to 0x10, but in the SPI case there is also a so called
'global address' which is prefixed in-front of the register address. The global
address mimics I2C behaviour and includes a static device address the and the
read/write flag. This basically extends the register address to an 16-bit value
numbered from 0x800 to 0x810. These are the register numbers which are
currently used by the driver. This works, because I2C will ignore the upper
8 bits of the register, but it is still a bit confusing, as there are no such
register numbers in the I2C case.

The approach taken by this patch is to number the registers from 0x00 to 0x10
and encode the global address for SPI mode into the read and write flag masks.

Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
Acked-by: Liam Girdwood <lrg@ti.com>
Signed-off-by: Mark Brown <broonie@opensource.wolfsonmicro.com>
diff --git a/sound/soc/codecs/ad193x.c b/sound/soc/codecs/ad193x.c
index eedb6f5..f934670 100644
--- a/sound/soc/codecs/ad193x.c
+++ b/sound/soc/codecs/ad193x.c
@@ -23,7 +23,7 @@
 
 /* codec private data */
 struct ad193x_priv {
-	enum snd_soc_control_type control_type;
+	struct regmap *regmap;
 	int sysclk;
 };
 
@@ -349,10 +349,8 @@
 	struct snd_soc_dapm_context *dapm = &codec->dapm;
 	int ret;
 
-	if (ad193x->control_type == SND_SOC_I2C)
-		ret = snd_soc_codec_set_cache_io(codec, 8, 8, ad193x->control_type);
-	else
-		ret = snd_soc_codec_set_cache_io(codec, 16, 8, ad193x->control_type);
+	codec->control_data = ad193x->regmap;
+	ret = snd_soc_codec_set_cache_io(codec, 0, 0, SND_SOC_REGMAP);
 	if (ret < 0) {
 		dev_err(codec->dev, "failed to set cache I/O: %d\n", ret);
 		return ret;
@@ -388,6 +386,14 @@
 };
 
 #if defined(CONFIG_SPI_MASTER)
+
+static const struct regmap_config ad193x_spi_regmap_config = {
+	.val_bits = 8,
+	.reg_bits = 16,
+	.read_flag_mask = 0x09,
+	.write_flag_mask = 0x08,
+};
+
 static int __devinit ad193x_spi_probe(struct spi_device *spi)
 {
 	struct ad193x_priv *ad193x;
@@ -397,20 +403,36 @@
 	if (ad193x == NULL)
 		return -ENOMEM;
 
+	ad193x->regmap = regmap_init_spi(spi, &ad193x_spi_regmap_config);
+	if (IS_ERR(ad193x->regmap)) {
+		ret = PTR_ERR(ad193x->regmap);
+		goto err_free;
+	}
+
 	spi_set_drvdata(spi, ad193x);
-	ad193x->control_type = SND_SOC_SPI;
 
 	ret = snd_soc_register_codec(&spi->dev,
 			&soc_codec_dev_ad193x, &ad193x_dai, 1);
 	if (ret < 0)
-		kfree(ad193x);
+		goto err_regmap_exit;
+
+	return 0;
+
+err_regmap_exit:
+	regmap_exit(ad193x->regmap);
+err_free:
+	kfree(ad193x);
+
 	return ret;
 }
 
 static int __devexit ad193x_spi_remove(struct spi_device *spi)
 {
+	struct ad193x_priv *ad193x = spi_get_drvdata(spi);
+
 	snd_soc_unregister_codec(&spi->dev);
-	kfree(spi_get_drvdata(spi));
+	regmap_exit(ad193x->regmap);
+	kfree(ad193x);
 	return 0;
 }
 
@@ -425,6 +447,12 @@
 #endif
 
 #if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
+
+static const struct regmap_config ad193x_i2c_regmap_config = {
+	.val_bits = 8,
+	.reg_bits = 8,
+};
+
 static const struct i2c_device_id ad193x_id[] = {
 	{ "ad1936", 0 },
 	{ "ad1937", 0 },
@@ -442,20 +470,35 @@
 	if (ad193x == NULL)
 		return -ENOMEM;
 
+	ad193x->regmap = regmap_init_i2c(client, &ad193x_i2c_regmap_config);
+	if (IS_ERR(ad193x->regmap)) {
+		ret = PTR_ERR(ad193x->regmap);
+		goto err_free;
+	}
+
 	i2c_set_clientdata(client, ad193x);
-	ad193x->control_type = SND_SOC_I2C;
 
 	ret =  snd_soc_register_codec(&client->dev,
 			&soc_codec_dev_ad193x, &ad193x_dai, 1);
 	if (ret < 0)
-		kfree(ad193x);
+		goto err_regmap_exit;
+
+	return 0;
+
+err_regmap_exit:
+	regmap_exit(ad193x->regmap);
+err_free:
+	kfree(ad193x);
 	return ret;
 }
 
 static int __devexit ad193x_i2c_remove(struct i2c_client *client)
 {
+	struct ad193x_priv *ad193x = i2c_get_clientdata(client);
+
 	snd_soc_unregister_codec(&client->dev);
-	kfree(i2c_get_clientdata(client));
+	regmap_exit(ad193x->regmap);
+	kfree(ad193x);
 	return 0;
 }