linux/sound/soc/codecs/sta529.c
<<
>>
Prefs
   1/*
   2 * ASoC codec driver for spear platform
   3 *
   4 * sound/soc/codecs/sta529.c -- spear ALSA Soc codec driver
   5 *
   6 * Copyright (C) 2012 ST Microelectronics
   7 * Rajeev Kumar <rajeevkumar.linux@gmail.com>
   8 *
   9 * This file is licensed under the terms of the GNU General Public
  10 * License version 2. This program is licensed "as is" without any
  11 * warranty of any kind, whether express or implied.
  12 */
  13
  14#include <linux/clk.h>
  15#include <linux/init.h>
  16#include <linux/i2c.h>
  17#include <linux/io.h>
  18#include <linux/module.h>
  19#include <linux/moduleparam.h>
  20#include <linux/pm.h>
  21#include <linux/regmap.h>
  22#include <linux/slab.h>
  23
  24#include <sound/core.h>
  25#include <sound/initval.h>
  26#include <sound/pcm.h>
  27#include <sound/pcm_params.h>
  28#include <sound/soc.h>
  29#include <sound/soc-dapm.h>
  30#include <sound/tlv.h>
  31
  32/* STA529 Register offsets */
  33#define  STA529_FFXCFG0         0x00
  34#define  STA529_FFXCFG1         0x01
  35#define  STA529_MVOL            0x02
  36#define  STA529_LVOL            0x03
  37#define  STA529_RVOL            0x04
  38#define  STA529_TTF0            0x05
  39#define  STA529_TTF1            0x06
  40#define  STA529_TTP0            0x07
  41#define  STA529_TTP1            0x08
  42#define  STA529_S2PCFG0         0x0A
  43#define  STA529_S2PCFG1         0x0B
  44#define  STA529_P2SCFG0         0x0C
  45#define  STA529_P2SCFG1         0x0D
  46#define  STA529_PLLCFG0         0x14
  47#define  STA529_PLLCFG1         0x15
  48#define  STA529_PLLCFG2         0x16
  49#define  STA529_PLLCFG3         0x17
  50#define  STA529_PLLPFE          0x18
  51#define  STA529_PLLST           0x19
  52#define  STA529_ADCCFG          0x1E /*mic_select*/
  53#define  STA529_CKOCFG          0x1F
  54#define  STA529_MISC            0x20
  55#define  STA529_PADST0          0x21
  56#define  STA529_PADST1          0x22
  57#define  STA529_FFXST           0x23
  58#define  STA529_PWMIN1          0x2D
  59#define  STA529_PWMIN2          0x2E
  60#define  STA529_POWST           0x32
  61
  62#define STA529_MAX_REGISTER     0x32
  63
  64#define STA529_RATES            (SNDRV_PCM_RATE_8000 | \
  65                                SNDRV_PCM_RATE_11025 | \
  66                                SNDRV_PCM_RATE_16000 | \
  67                                SNDRV_PCM_RATE_22050 | \
  68                                SNDRV_PCM_RATE_32000 | \
  69                                SNDRV_PCM_RATE_44100 | \
  70                                SNDRV_PCM_RATE_48000)
  71
  72#define STA529_FORMAT           (SNDRV_PCM_FMTBIT_S16_LE | \
  73                                SNDRV_PCM_FMTBIT_S24_LE | \
  74                                SNDRV_PCM_FMTBIT_S32_LE)
  75#define S2PC_VALUE              0x98
  76#define CLOCK_OUT               0x60
  77#define DATA_FORMAT_MSK         0x0E
  78#define LEFT_J_DATA_FORMAT      0x00
  79#define I2S_DATA_FORMAT         0x02
  80#define RIGHT_J_DATA_FORMAT     0x04
  81#define CODEC_MUTE_VAL          0x80
  82
  83#define POWER_CNTLMSAK          0x40
  84#define POWER_STDBY             0x40
  85#define FFX_MASK                0x80
  86#define FFX_OFF                 0x80
  87#define POWER_UP                0x00
  88#define FFX_CLK_ENB             0x01
  89#define FFX_CLK_DIS             0x00
  90#define FFX_CLK_MSK             0x01
  91#define PLAY_FREQ_RANGE_MSK     0x70
  92#define CAP_FREQ_RANGE_MSK      0x0C
  93#define PDATA_LEN_MSK           0xC0
  94#define BCLK_TO_FS_MSK          0x30
  95#define AUDIO_MUTE_MSK          0x80
  96
  97static const struct reg_default sta529_reg_defaults[] = {
  98        { 0,  0x35 },     /* R0   - FFX Configuration reg 0 */
  99        { 1,  0xc8 },     /* R1   - FFX Configuration reg 1 */
 100        { 2,  0x50 },     /* R2   - Master Volume */
 101        { 3,  0x00 },     /* R3   - Left Volume */
 102        { 4,  0x00 },     /* R4  -  Right Volume */
 103        { 10, 0xb2 },     /* R10  - S2P Config Reg 0 */
 104        { 11, 0x41 },     /* R11  - S2P Config Reg 1 */
 105        { 12, 0x92 },     /* R12  - P2S Config Reg 0 */
 106        { 13, 0x41 },     /* R13  - P2S Config Reg 1 */
 107        { 30, 0xd2 },     /* R30  - ADC Config Reg */
 108        { 31, 0x40 },     /* R31  - clock Out Reg */
 109        { 32, 0x21 },     /* R32  - Misc Register */
 110};
 111
 112struct sta529 {
 113        struct regmap *regmap;
 114};
 115
 116static bool sta529_readable(struct device *dev, unsigned int reg)
 117{
 118        switch (reg) {
 119
 120        case STA529_FFXCFG0:
 121        case STA529_FFXCFG1:
 122        case STA529_MVOL:
 123        case STA529_LVOL:
 124        case STA529_RVOL:
 125        case STA529_S2PCFG0:
 126        case STA529_S2PCFG1:
 127        case STA529_P2SCFG0:
 128        case STA529_P2SCFG1:
 129        case STA529_ADCCFG:
 130        case STA529_CKOCFG:
 131        case STA529_MISC:
 132                return true;
 133        default:
 134                return false;
 135        }
 136}
 137
 138
 139static const char *pwm_mode_text[] = { "Binary", "Headphone", "Ternary",
 140        "Phase-shift"};
 141
 142static const DECLARE_TLV_DB_SCALE(out_gain_tlv, -9150, 50, 0);
 143static const DECLARE_TLV_DB_SCALE(master_vol_tlv, -12750, 50, 0);
 144static SOC_ENUM_SINGLE_DECL(pwm_src, STA529_FFXCFG1, 4, pwm_mode_text);
 145
 146static const struct snd_kcontrol_new sta529_snd_controls[] = {
 147        SOC_DOUBLE_R_TLV("Digital Playback Volume", STA529_LVOL, STA529_RVOL, 0,
 148                        127, 0, out_gain_tlv),
 149        SOC_SINGLE_TLV("Master Playback Volume", STA529_MVOL, 0, 127, 1,
 150                        master_vol_tlv),
 151        SOC_ENUM("PWM Select", pwm_src),
 152};
 153
 154static int sta529_set_bias_level(struct snd_soc_component *component, enum
 155                snd_soc_bias_level level)
 156{
 157        struct sta529 *sta529 = snd_soc_component_get_drvdata(component);
 158
 159        switch (level) {
 160        case SND_SOC_BIAS_ON:
 161        case SND_SOC_BIAS_PREPARE:
 162                snd_soc_component_update_bits(component, STA529_FFXCFG0, POWER_CNTLMSAK,
 163                                POWER_UP);
 164                snd_soc_component_update_bits(component, STA529_MISC,   FFX_CLK_MSK,
 165                                FFX_CLK_ENB);
 166                break;
 167        case SND_SOC_BIAS_STANDBY:
 168                if (snd_soc_component_get_bias_level(component) == SND_SOC_BIAS_OFF)
 169                        regcache_sync(sta529->regmap);
 170                snd_soc_component_update_bits(component, STA529_FFXCFG0,
 171                                        POWER_CNTLMSAK, POWER_STDBY);
 172                /* Making FFX output to zero */
 173                snd_soc_component_update_bits(component, STA529_FFXCFG0, FFX_MASK,
 174                                FFX_OFF);
 175                snd_soc_component_update_bits(component, STA529_MISC, FFX_CLK_MSK,
 176                                FFX_CLK_DIS);
 177                break;
 178        case SND_SOC_BIAS_OFF:
 179                break;
 180        }
 181
 182        return 0;
 183
 184}
 185
 186static int sta529_hw_params(struct snd_pcm_substream *substream,
 187                struct snd_pcm_hw_params *params,
 188                struct snd_soc_dai *dai)
 189{
 190        struct snd_soc_component *component = dai->component;
 191        int pdata, play_freq_val, record_freq_val;
 192        int bclk_to_fs_ratio;
 193
 194        switch (params_width(params)) {
 195        case 16:
 196                pdata = 1;
 197                bclk_to_fs_ratio = 0;
 198                break;
 199        case 24:
 200                pdata = 2;
 201                bclk_to_fs_ratio = 1;
 202                break;
 203        case 32:
 204                pdata = 3;
 205                bclk_to_fs_ratio = 2;
 206                break;
 207        default:
 208                dev_err(component->dev, "Unsupported format\n");
 209                return -EINVAL;
 210        }
 211
 212        switch (params_rate(params)) {
 213        case 8000:
 214        case 11025:
 215                play_freq_val = 0;
 216                record_freq_val = 2;
 217                break;
 218        case 16000:
 219        case 22050:
 220                play_freq_val = 1;
 221                record_freq_val = 0;
 222                break;
 223
 224        case 32000:
 225        case 44100:
 226        case 48000:
 227                play_freq_val = 2;
 228                record_freq_val = 0;
 229                break;
 230        default:
 231                dev_err(component->dev, "Unsupported rate\n");
 232                return -EINVAL;
 233        }
 234
 235        if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
 236                snd_soc_component_update_bits(component, STA529_S2PCFG1, PDATA_LEN_MSK,
 237                                pdata << 6);
 238                snd_soc_component_update_bits(component, STA529_S2PCFG1, BCLK_TO_FS_MSK,
 239                                bclk_to_fs_ratio << 4);
 240                snd_soc_component_update_bits(component, STA529_MISC, PLAY_FREQ_RANGE_MSK,
 241                                play_freq_val << 4);
 242        } else {
 243                snd_soc_component_update_bits(component, STA529_P2SCFG1, PDATA_LEN_MSK,
 244                                pdata << 6);
 245                snd_soc_component_update_bits(component, STA529_P2SCFG1, BCLK_TO_FS_MSK,
 246                                bclk_to_fs_ratio << 4);
 247                snd_soc_component_update_bits(component, STA529_MISC, CAP_FREQ_RANGE_MSK,
 248                                record_freq_val << 2);
 249        }
 250
 251        return 0;
 252}
 253
 254static int sta529_mute(struct snd_soc_dai *dai, int mute, int direction)
 255{
 256        u8 val = 0;
 257
 258        if (mute)
 259                val |= CODEC_MUTE_VAL;
 260
 261        snd_soc_component_update_bits(dai->component, STA529_FFXCFG0, AUDIO_MUTE_MSK, val);
 262
 263        return 0;
 264}
 265
 266static int sta529_set_dai_fmt(struct snd_soc_dai *codec_dai, u32 fmt)
 267{
 268        struct snd_soc_component *component = codec_dai->component;
 269        u8 mode = 0;
 270
 271        /* interface format */
 272        switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
 273        case SND_SOC_DAIFMT_LEFT_J:
 274                mode = LEFT_J_DATA_FORMAT;
 275                break;
 276        case SND_SOC_DAIFMT_I2S:
 277                mode = I2S_DATA_FORMAT;
 278                break;
 279        case SND_SOC_DAIFMT_RIGHT_J:
 280                mode = RIGHT_J_DATA_FORMAT;
 281                break;
 282        default:
 283                return -EINVAL;
 284        }
 285
 286        snd_soc_component_update_bits(component, STA529_S2PCFG0, DATA_FORMAT_MSK, mode);
 287
 288        return 0;
 289}
 290
 291static const struct snd_soc_dai_ops sta529_dai_ops = {
 292        .hw_params      =       sta529_hw_params,
 293        .set_fmt        =       sta529_set_dai_fmt,
 294        .mute_stream    =       sta529_mute,
 295        .no_capture_mute = 1,
 296};
 297
 298static struct snd_soc_dai_driver sta529_dai = {
 299        .name = "sta529-audio",
 300        .playback = {
 301                .stream_name = "Playback",
 302                .channels_min = 2,
 303                .channels_max = 2,
 304                .rates = STA529_RATES,
 305                .formats = STA529_FORMAT,
 306        },
 307        .capture = {
 308                .stream_name = "Capture",
 309                .channels_min = 2,
 310                .channels_max = 2,
 311                .rates = STA529_RATES,
 312                .formats = STA529_FORMAT,
 313        },
 314        .ops    = &sta529_dai_ops,
 315};
 316
 317static const struct snd_soc_component_driver sta529_component_driver = {
 318        .set_bias_level         = sta529_set_bias_level,
 319        .controls               = sta529_snd_controls,
 320        .num_controls           = ARRAY_SIZE(sta529_snd_controls),
 321        .suspend_bias_off       = 1,
 322        .idle_bias_on           = 1,
 323        .use_pmdown_time        = 1,
 324        .endianness             = 1,
 325        .non_legacy_dai_naming  = 1,
 326};
 327
 328static const struct regmap_config sta529_regmap = {
 329        .reg_bits = 8,
 330        .val_bits = 8,
 331
 332        .max_register = STA529_MAX_REGISTER,
 333        .readable_reg = sta529_readable,
 334
 335        .cache_type = REGCACHE_RBTREE,
 336        .reg_defaults = sta529_reg_defaults,
 337        .num_reg_defaults = ARRAY_SIZE(sta529_reg_defaults),
 338};
 339
 340static int sta529_i2c_probe(struct i2c_client *i2c,
 341                            const struct i2c_device_id *id)
 342{
 343        struct sta529 *sta529;
 344        int ret;
 345
 346        sta529 = devm_kzalloc(&i2c->dev, sizeof(struct sta529), GFP_KERNEL);
 347        if (!sta529)
 348                return -ENOMEM;
 349
 350        sta529->regmap = devm_regmap_init_i2c(i2c, &sta529_regmap);
 351        if (IS_ERR(sta529->regmap)) {
 352                ret = PTR_ERR(sta529->regmap);
 353                dev_err(&i2c->dev, "Failed to allocate regmap: %d\n", ret);
 354                return ret;
 355        }
 356
 357        i2c_set_clientdata(i2c, sta529);
 358
 359        ret = devm_snd_soc_register_component(&i2c->dev,
 360                        &sta529_component_driver, &sta529_dai, 1);
 361        if (ret != 0)
 362                dev_err(&i2c->dev, "Failed to register CODEC: %d\n", ret);
 363
 364        return ret;
 365}
 366
 367static const struct i2c_device_id sta529_i2c_id[] = {
 368        { "sta529", 0 },
 369        { }
 370};
 371MODULE_DEVICE_TABLE(i2c, sta529_i2c_id);
 372
 373static const struct of_device_id sta529_of_match[] = {
 374        { .compatible = "st,sta529", },
 375        { }
 376};
 377MODULE_DEVICE_TABLE(of, sta529_of_match);
 378
 379static struct i2c_driver sta529_i2c_driver = {
 380        .driver = {
 381                .name = "sta529",
 382                .of_match_table = sta529_of_match,
 383        },
 384        .probe          = sta529_i2c_probe,
 385        .id_table       = sta529_i2c_id,
 386};
 387
 388module_i2c_driver(sta529_i2c_driver);
 389
 390MODULE_DESCRIPTION("ASoC STA529 codec driver");
 391MODULE_AUTHOR("Rajeev Kumar <rajeevkumar.linux@gmail.com>");
 392MODULE_LICENSE("GPL");
 393