#include <linux/delay.h>
#include <linux/pm.h>
#include <linux/i2c.h>
+#include <linux/regmap.h>
#include <linux/regulator/consumer.h>
#include <linux/slab.h>
#include <linux/workqueue.h>
SNDRV_PCM_FMTBIT_S32_LE | SNDRV_PCM_FMTBIT_S32_BE)
/* Power-up register defaults */
-static const u8 sta32x_regs[STA32X_REGISTER_COUNT] = {
- 0x63, 0x80, 0xc2, 0x40, 0xc2, 0x5c, 0x10, 0xff, 0x60, 0x60,
- 0x60, 0x80, 0x00, 0x00, 0x00, 0x40, 0x80, 0x77, 0x6a, 0x69,
- 0x6a, 0x69, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x2d,
- 0xc0, 0xf3, 0x33, 0x00, 0x0c,
+static const struct reg_default sta32x_regs[] = {
+ { 0x0, 0x63 },
+ { 0x1, 0x80 },
+ { 0x2, 0xc2 },
+ { 0x3, 0x40 },
+ { 0x4, 0xc2 },
+ { 0x5, 0x5c },
+ { 0x6, 0x10 },
+ { 0x7, 0xff },
+ { 0x8, 0x60 },
+ { 0x9, 0x60 },
+ { 0xa, 0x60 },
+ { 0xb, 0x80 },
+ { 0xc, 0x00 },
+ { 0xd, 0x00 },
+ { 0xe, 0x00 },
+ { 0xf, 0x40 },
+ { 0x10, 0x80 },
+ { 0x11, 0x77 },
+ { 0x12, 0x6a },
+ { 0x13, 0x69 },
+ { 0x14, 0x6a },
+ { 0x15, 0x69 },
+ { 0x16, 0x00 },
+ { 0x17, 0x00 },
+ { 0x18, 0x00 },
+ { 0x19, 0x00 },
+ { 0x1a, 0x00 },
+ { 0x1b, 0x00 },
+ { 0x1c, 0x00 },
+ { 0x1d, 0x00 },
+ { 0x1e, 0x00 },
+ { 0x1f, 0x00 },
+ { 0x20, 0x00 },
+ { 0x21, 0x00 },
+ { 0x22, 0x00 },
+ { 0x23, 0x00 },
+ { 0x24, 0x00 },
+ { 0x25, 0x00 },
+ { 0x26, 0x00 },
+ { 0x27, 0x2d },
+ { 0x28, 0xc0 },
+ { 0x2b, 0x00 },
+ { 0x2c, 0x0c },
};
/* regulator power supply names */
/* codec private data */
struct sta32x_priv {
+ struct regmap *regmap;
struct regulator_bulk_data supplies[ARRAY_SIZE(sta32x_supply_names)];
struct snd_soc_codec *codec;
struct sta32x_platform_data *pdata;
static int sta32x_cache_sync(struct snd_soc_codec *codec)
{
+ struct sta32x_priv *sta32x = codec->control_data;
unsigned int mute;
int rc;
- if (!codec->cache_sync)
- return 0;
-
/* mute during register sync */
mute = snd_soc_read(codec, STA32X_MMUTE);
snd_soc_write(codec, STA32X_MMUTE, mute | STA32X_MMUTE_MMUTE);
sta32x_sync_coef_shadow(codec);
- rc = snd_soc_cache_sync(codec);
+ rc = regcache_sync(sta32x->regmap);
snd_soc_write(codec, STA32X_MMUTE, mute);
return rc;
}
/* check if sta32x has reset itself */
confa_cached = snd_soc_read(codec, STA32X_CONFA);
- codec->cache_bypass = 1;
+ regcache_cache_bypass(sta32x->regmap, true);
confa = snd_soc_read(codec, STA32X_CONFA);
- codec->cache_bypass = 0;
+ regcache_cache_bypass(sta32x->regmap, false);
if (confa != confa_cached) {
- codec->cache_sync = 1;
+ regcache_mark_dirty(sta32x->regmap);
sta32x_cache_sync(codec);
}
sta32x->codec = codec;
sta32x->pdata = dev_get_platdata(codec->dev);
- /* regulators */
- for (i = 0; i < ARRAY_SIZE(sta32x->supplies); i++)
- sta32x->supplies[i].supply = sta32x_supply_names[i];
-
- ret = regulator_bulk_get(codec->dev, ARRAY_SIZE(sta32x->supplies),
- sta32x->supplies);
- if (ret != 0) {
- dev_err(codec->dev, "Failed to request supplies: %d\n", ret);
- goto err;
- }
-
ret = regulator_bulk_enable(ARRAY_SIZE(sta32x->supplies),
sta32x->supplies);
if (ret != 0) {
dev_err(codec->dev, "Failed to enable supplies: %d\n", ret);
- goto err_get;
+ return ret;
}
/* Tell ASoC what kind of I/O to use to read the registers. ASoC will
* then do the I2C transactions itself.
*/
- ret = snd_soc_codec_set_cache_io(codec, 8, 8, SND_SOC_I2C);
+ codec->control_data = sta32x->regmap;
+ ret = snd_soc_codec_set_cache_io(codec, 8, 8, SND_SOC_REGMAP);
if (ret < 0) {
dev_err(codec->dev, "failed to set cache I/O (ret=%i)\n", ret);
- return ret;
+ goto err;
}
/* Chip documentation explicitly requires that the reset values
* so the write to the these registers are suppressed by the cache
* restore code when it skips writes of default registers.
*/
- snd_soc_cache_write(codec, STA32X_CONFC, 0xc2);
- snd_soc_cache_write(codec, STA32X_CONFE, 0xc2);
- snd_soc_cache_write(codec, STA32X_CONFF, 0x5c);
- snd_soc_cache_write(codec, STA32X_MMUTE, 0x10);
- snd_soc_cache_write(codec, STA32X_AUTO1, 0x60);
- snd_soc_cache_write(codec, STA32X_AUTO3, 0x00);
- snd_soc_cache_write(codec, STA32X_C3CFG, 0x40);
+ regcache_cache_only(sta32x->regmap, true);
+ snd_soc_write(codec, STA32X_CONFC, 0xc2);
+ snd_soc_write(codec, STA32X_CONFE, 0xc2);
+ snd_soc_write(codec, STA32X_CONFF, 0x5c);
+ snd_soc_write(codec, STA32X_MMUTE, 0x10);
+ snd_soc_write(codec, STA32X_AUTO1, 0x60);
+ snd_soc_write(codec, STA32X_AUTO3, 0x00);
+ snd_soc_write(codec, STA32X_C3CFG, 0x40);
+ regcache_cache_only(sta32x->regmap, false);
/* set thermal warning adjustment and recovery */
if (!(sta32x->pdata->thermal_conf & STA32X_THERMAL_ADJUSTMENT_ENABLE))
return 0;
-err_get:
- regulator_bulk_free(ARRAY_SIZE(sta32x->supplies), sta32x->supplies);
err:
+ regulator_bulk_disable(ARRAY_SIZE(sta32x->supplies), sta32x->supplies);
return ret;
}
sta32x_watchdog_stop(sta32x);
sta32x_set_bias_level(codec, SND_SOC_BIAS_OFF);
regulator_bulk_disable(ARRAY_SIZE(sta32x->supplies), sta32x->supplies);
- regulator_bulk_free(ARRAY_SIZE(sta32x->supplies), sta32x->supplies);
return 0;
}
-static int sta32x_reg_is_volatile(struct snd_soc_codec *codec,
- unsigned int reg)
+static bool sta32x_reg_is_volatile(struct device *dev, unsigned int reg)
{
switch (reg) {
case STA32X_CONFA ... STA32X_L2ATRT:
.remove = sta32x_remove,
.suspend = sta32x_suspend,
.resume = sta32x_resume,
- .reg_cache_size = STA32X_REGISTER_COUNT,
- .reg_word_size = sizeof(u8),
- .reg_cache_default = sta32x_regs,
- .volatile_register = sta32x_reg_is_volatile,
.set_bias_level = sta32x_set_bias_level,
.controls = sta32x_snd_controls,
.num_controls = ARRAY_SIZE(sta32x_snd_controls),
.num_dapm_routes = ARRAY_SIZE(sta32x_dapm_routes),
};
+static const struct regmap_config sta32x_regmap = {
+ .reg_bits = 8,
+ .val_bits = 8,
+ .max_register = STA32X_FDRC2,
+ .reg_defaults = sta32x_regs,
+ .num_reg_defaults = ARRAY_SIZE(sta32x_regs),
+ .cache_type = REGCACHE_RBTREE,
+ .volatile_reg = sta32x_reg_is_volatile,
+};
+
static __devinit int sta32x_i2c_probe(struct i2c_client *i2c,
const struct i2c_device_id *id)
{
struct sta32x_priv *sta32x;
- int ret;
+ int ret, i;
sta32x = devm_kzalloc(&i2c->dev, sizeof(struct sta32x_priv),
GFP_KERNEL);
if (!sta32x)
return -ENOMEM;
+ /* regulators */
+ for (i = 0; i < ARRAY_SIZE(sta32x->supplies); i++)
+ sta32x->supplies[i].supply = sta32x_supply_names[i];
+
+ ret = devm_regulator_bulk_get(&i2c->dev, ARRAY_SIZE(sta32x->supplies),
+ sta32x->supplies);
+ if (ret != 0) {
+ dev_err(&i2c->dev, "Failed to request supplies: %d\n", ret);
+ return ret;
+ }
+
+ sta32x->regmap = devm_regmap_init_i2c(i2c, &sta32x_regmap);
+ if (IS_ERR(sta32x->regmap)) {
+ ret = PTR_ERR(sta32x->regmap);
+ dev_err(&i2c->dev, "Failed to init regmap: %d\n", ret);
+ return ret;
+ }
+
i2c_set_clientdata(i2c, sta32x);
ret = snd_soc_register_codec(&i2c->dev, &sta32x_codec, &sta32x_dai, 1);
.id_table = sta32x_i2c_id,
};
-static int __init sta32x_init(void)
-{
- return i2c_add_driver(&sta32x_i2c_driver);
-}
-module_init(sta32x_init);
-
-static void __exit sta32x_exit(void)
-{
- i2c_del_driver(&sta32x_i2c_driver);
-}
-module_exit(sta32x_exit);
+module_i2c_driver(sta32x_i2c_driver);
MODULE_DESCRIPTION("ASoC STA32X driver");
MODULE_AUTHOR("Johannes Stezenbach <js@sig21.net>");