diff options
| -rw-r--r-- | sound/soc/codecs/stac9766.c | 108 |
1 files changed, 59 insertions, 49 deletions
diff --git a/sound/soc/codecs/stac9766.c b/sound/soc/codecs/stac9766.c index f675d343b529..62cbeedf93b9 100644 --- a/sound/soc/codecs/stac9766.c +++ b/sound/soc/codecs/stac9766.c | |||
| @@ -18,6 +18,7 @@ | |||
| 18 | #include <linux/slab.h> | 18 | #include <linux/slab.h> |
| 19 | #include <linux/module.h> | 19 | #include <linux/module.h> |
| 20 | #include <linux/device.h> | 20 | #include <linux/device.h> |
| 21 | #include <linux/regmap.h> | ||
| 21 | #include <sound/core.h> | 22 | #include <sound/core.h> |
| 22 | #include <sound/pcm.h> | 23 | #include <sound/pcm.h> |
| 23 | #include <sound/ac97_codec.h> | 24 | #include <sound/ac97_codec.h> |
| @@ -33,26 +34,49 @@ | |||
| 33 | #define AC97_STAC_ANALOG_SPECIAL 0x6E | 34 | #define AC97_STAC_ANALOG_SPECIAL 0x6E |
| 34 | #define AC97_STAC_STEREO_MIC 0x78 | 35 | #define AC97_STAC_STEREO_MIC 0x78 |
| 35 | 36 | ||
| 36 | /* | 37 | static const struct reg_default stac9766_reg_defaults[] = { |
| 37 | * STAC9766 register cache | 38 | { 0x02, 0x8000 }, |
| 38 | */ | 39 | { 0x04, 0x8000 }, |
| 39 | static const u16 stac9766_reg[] = { | 40 | { 0x06, 0x8000 }, |
| 40 | 0x6A90, 0x8000, 0x8000, 0x8000, /* 6 */ | 41 | { 0x0a, 0x0000 }, |
| 41 | 0x0000, 0x0000, 0x8008, 0x8008, /* e */ | 42 | { 0x0c, 0x8008 }, |
| 42 | 0x8808, 0x8808, 0x8808, 0x8808, /* 16 */ | 43 | { 0x0e, 0x8008 }, |
| 43 | 0x8808, 0x0000, 0x8000, 0x0000, /* 1e */ | 44 | { 0x10, 0x8808 }, |
| 44 | 0x0000, 0x0000, 0x0000, 0x000f, /* 26 */ | 45 | { 0x12, 0x8808 }, |
| 45 | 0x0a05, 0x0400, 0xbb80, 0x0000, /* 2e */ | 46 | { 0x14, 0x8808 }, |
| 46 | 0x0000, 0xbb80, 0x0000, 0x0000, /* 36 */ | 47 | { 0x16, 0x8808 }, |
| 47 | 0x0000, 0x2000, 0x0000, 0x0100, /* 3e */ | 48 | { 0x18, 0x8808 }, |
| 48 | 0x0000, 0x0000, 0x0080, 0x0000, /* 46 */ | 49 | { 0x1a, 0x0000 }, |
| 49 | 0x0000, 0x0000, 0x0003, 0xffff, /* 4e */ | 50 | { 0x1c, 0x8000 }, |
| 50 | 0x0000, 0x0000, 0x0000, 0x0000, /* 56 */ | 51 | { 0x20, 0x0000 }, |
| 51 | 0x4000, 0x0000, 0x0000, 0x0000, /* 5e */ | 52 | { 0x22, 0x0000 }, |
| 52 | 0x1201, 0x0000, 0x0000, 0x0000, /* 66 */ | 53 | { 0x28, 0x0a05 }, |
| 53 | 0x0000, 0x0000, 0x0000, 0x1000, /* 6e */ | 54 | { 0x2c, 0xbb80 }, |
| 54 | 0x0000, 0x0000, 0x0000, 0x0006, /* 76 */ | 55 | { 0x32, 0xbb80 }, |
| 55 | 0x0000, 0x0000, 0x0000, 0x0000, /* 7e */ | 56 | { 0x3a, 0x2000 }, |
| 57 | { 0x3e, 0x0100 }, | ||
| 58 | { 0x4c, 0x0300 }, | ||
| 59 | { 0x4e, 0xffff }, | ||
| 60 | { 0x50, 0x0000 }, | ||
| 61 | { 0x52, 0x0000 }, | ||
| 62 | { 0x54, 0x0000 }, | ||
| 63 | { 0x6a, 0x0000 }, | ||
| 64 | { 0x6e, 0x1000 }, | ||
| 65 | { 0x72, 0x0000 }, | ||
| 66 | { 0x78, 0x0000 }, | ||
| 67 | }; | ||
| 68 | |||
| 69 | static const struct regmap_config stac9766_regmap_config = { | ||
| 70 | .reg_bits = 16, | ||
| 71 | .reg_stride = 2, | ||
| 72 | .val_bits = 16, | ||
| 73 | .max_register = 0x78, | ||
| 74 | .cache_type = REGCACHE_RBTREE, | ||
| 75 | |||
| 76 | .volatile_reg = regmap_ac97_default_volatile, | ||
| 77 | |||
| 78 | .reg_defaults = stac9766_reg_defaults, | ||
| 79 | .num_reg_defaults = ARRAY_SIZE(stac9766_reg_defaults), | ||
| 56 | }; | 80 | }; |
| 57 | 81 | ||
| 58 | static const char *stac9766_record_mux[] = {"Mic", "CD", "Video", "AUX", | 82 | static const char *stac9766_record_mux[] = {"Mic", "CD", "Video", "AUX", |
| @@ -144,34 +168,13 @@ static const struct snd_kcontrol_new stac9766_snd_ac97_controls[] = { | |||
| 144 | static int stac9766_ac97_write(struct snd_soc_codec *codec, unsigned int reg, | 168 | static int stac9766_ac97_write(struct snd_soc_codec *codec, unsigned int reg, |
| 145 | unsigned int val) | 169 | unsigned int val) |
| 146 | { | 170 | { |
| 147 | struct snd_ac97 *ac97 = snd_soc_codec_get_drvdata(codec); | 171 | return snd_soc_write(codec, reg, val); |
| 148 | u16 *cache = codec->reg_cache; | ||
| 149 | |||
| 150 | if (reg / 2 >= ARRAY_SIZE(stac9766_reg)) | ||
| 151 | return -EIO; | ||
| 152 | |||
| 153 | soc_ac97_ops->write(ac97, reg, val); | ||
| 154 | cache[reg / 2] = val; | ||
| 155 | return 0; | ||
| 156 | } | 172 | } |
| 157 | 173 | ||
| 158 | static unsigned int stac9766_ac97_read(struct snd_soc_codec *codec, | 174 | static unsigned int stac9766_ac97_read(struct snd_soc_codec *codec, |
| 159 | unsigned int reg) | 175 | unsigned int reg) |
| 160 | { | 176 | { |
| 161 | struct snd_ac97 *ac97 = snd_soc_codec_get_drvdata(codec); | 177 | return snd_soc_read(codec, reg); |
| 162 | u16 val = 0, *cache = codec->reg_cache; | ||
| 163 | |||
| 164 | if (reg / 2 >= ARRAY_SIZE(stac9766_reg)) | ||
| 165 | return -EIO; | ||
| 166 | |||
| 167 | if (reg == AC97_RESET || reg == AC97_GPIO_STATUS || | ||
| 168 | reg == AC97_INT_PAGING || reg == AC97_VENDOR_ID1 || | ||
| 169 | reg == AC97_VENDOR_ID2) { | ||
| 170 | |||
| 171 | val = soc_ac97_ops->read(ac97, reg); | ||
| 172 | return val; | ||
| 173 | } | ||
| 174 | return cache[reg / 2]; | ||
| 175 | } | 178 | } |
| 176 | 179 | ||
| 177 | static int ac97_analog_prepare(struct snd_pcm_substream *substream, | 180 | static int ac97_analog_prepare(struct snd_pcm_substream *substream, |
| @@ -290,21 +293,34 @@ static struct snd_soc_dai_driver stac9766_dai[] = { | |||
| 290 | static int stac9766_codec_probe(struct snd_soc_codec *codec) | 293 | static int stac9766_codec_probe(struct snd_soc_codec *codec) |
| 291 | { | 294 | { |
| 292 | struct snd_ac97 *ac97; | 295 | struct snd_ac97 *ac97; |
| 296 | struct regmap *regmap; | ||
| 297 | int ret; | ||
| 293 | 298 | ||
| 294 | ac97 = snd_soc_new_ac97_codec(codec, STAC9766_VENDOR_ID, | 299 | ac97 = snd_soc_new_ac97_codec(codec, STAC9766_VENDOR_ID, |
| 295 | STAC9766_VENDOR_ID_MASK); | 300 | STAC9766_VENDOR_ID_MASK); |
| 296 | if (IS_ERR(ac97)) | 301 | if (IS_ERR(ac97)) |
| 297 | return PTR_ERR(ac97); | 302 | return PTR_ERR(ac97); |
| 298 | 303 | ||
| 304 | regmap = regmap_init_ac97(ac97, &stac9766_regmap_config); | ||
| 305 | if (IS_ERR(regmap)) { | ||
| 306 | ret = PTR_ERR(regmap); | ||
| 307 | goto err_free_ac97; | ||
| 308 | } | ||
| 309 | |||
| 310 | snd_soc_codec_init_regmap(codec, regmap); | ||
| 299 | snd_soc_codec_set_drvdata(codec, ac97); | 311 | snd_soc_codec_set_drvdata(codec, ac97); |
| 300 | 312 | ||
| 301 | return 0; | 313 | return 0; |
| 314 | err_free_ac97: | ||
| 315 | snd_soc_free_ac97_codec(ac97); | ||
| 316 | return ret; | ||
| 302 | } | 317 | } |
| 303 | 318 | ||
| 304 | static int stac9766_codec_remove(struct snd_soc_codec *codec) | 319 | static int stac9766_codec_remove(struct snd_soc_codec *codec) |
| 305 | { | 320 | { |
| 306 | struct snd_ac97 *ac97 = snd_soc_codec_get_drvdata(codec); | 321 | struct snd_ac97 *ac97 = snd_soc_codec_get_drvdata(codec); |
| 307 | 322 | ||
| 323 | snd_soc_codec_exit_regmap(codec); | ||
| 308 | snd_soc_free_ac97_codec(ac97); | 324 | snd_soc_free_ac97_codec(ac97); |
| 309 | return 0; | 325 | return 0; |
| 310 | } | 326 | } |
| @@ -314,17 +330,11 @@ static struct snd_soc_codec_driver soc_codec_dev_stac9766 = { | |||
| 314 | .controls = stac9766_snd_ac97_controls, | 330 | .controls = stac9766_snd_ac97_controls, |
| 315 | .num_controls = ARRAY_SIZE(stac9766_snd_ac97_controls), | 331 | .num_controls = ARRAY_SIZE(stac9766_snd_ac97_controls), |
| 316 | }, | 332 | }, |
| 317 | .write = stac9766_ac97_write, | ||
| 318 | .read = stac9766_ac97_read, | ||
| 319 | .set_bias_level = stac9766_set_bias_level, | 333 | .set_bias_level = stac9766_set_bias_level, |
| 320 | .suspend_bias_off = true, | 334 | .suspend_bias_off = true, |
| 321 | .probe = stac9766_codec_probe, | 335 | .probe = stac9766_codec_probe, |
| 322 | .remove = stac9766_codec_remove, | 336 | .remove = stac9766_codec_remove, |
| 323 | .resume = stac9766_codec_resume, | 337 | .resume = stac9766_codec_resume, |
| 324 | .reg_cache_size = ARRAY_SIZE(stac9766_reg), | ||
| 325 | .reg_word_size = sizeof(u16), | ||
| 326 | .reg_cache_step = 2, | ||
| 327 | .reg_cache_default = stac9766_reg, | ||
| 328 | }; | 338 | }; |
| 329 | 339 | ||
| 330 | static int stac9766_probe(struct platform_device *pdev) | 340 | static int stac9766_probe(struct platform_device *pdev) |
