linux/sound/soc/codecs/ssm2602.c
<<
>>
Prefs
   1/*
   2 * File:         sound/soc/codecs/ssm2602.c
   3 * Author:       Cliff Cai <Cliff.Cai@analog.com>
   4 *
   5 * Created:      Tue June 06 2008
   6 * Description:  Driver for ssm2602 sound chip
   7 *
   8 * Modified:
   9 *               Copyright 2008 Analog Devices Inc.
  10 *
  11 * Bugs:         Enter bugs at http://blackfin.uclinux.org/
  12 *
  13 * This program is free software; you can redistribute it and/or modify
  14 * it under the terms of the GNU General Public License as published by
  15 * the Free Software Foundation; either version 2 of the License, or
  16 * (at your option) any later version.
  17 *
  18 * This program is distributed in the hope that it will be useful,
  19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
  20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  21 * GNU General Public License for more details.
  22 *
  23 * You should have received a copy of the GNU General Public License
  24 * along with this program; if not, see the file COPYING, or write
  25 * to the Free Software Foundation, Inc.,
  26 * 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
  27 */
  28
  29#include <linux/module.h>
  30#include <linux/moduleparam.h>
  31#include <linux/init.h>
  32#include <linux/delay.h>
  33#include <linux/pm.h>
  34#include <linux/i2c.h>
  35#include <linux/platform_device.h>
  36#include <sound/core.h>
  37#include <sound/pcm.h>
  38#include <sound/pcm_params.h>
  39#include <sound/soc.h>
  40#include <sound/soc-dapm.h>
  41#include <sound/initval.h>
  42
  43#include "ssm2602.h"
  44
  45#define SSM2602_VERSION "0.1"
  46
  47struct snd_soc_codec_device soc_codec_dev_ssm2602;
  48
  49/* codec private data */
  50struct ssm2602_priv {
  51        unsigned int sysclk;
  52        struct snd_pcm_substream *master_substream;
  53        struct snd_pcm_substream *slave_substream;
  54};
  55
  56/*
  57 * ssm2602 register cache
  58 * We can't read the ssm2602 register space when we are
  59 * using 2 wire for device control, so we cache them instead.
  60 * There is no point in caching the reset register
  61 */
  62static const u16 ssm2602_reg[SSM2602_CACHEREGNUM] = {
  63        0x0017, 0x0017, 0x0079, 0x0079,
  64        0x0000, 0x0000, 0x0000, 0x000a,
  65        0x0000, 0x0000
  66};
  67
  68/*
  69 * read ssm2602 register cache
  70 */
  71static inline unsigned int ssm2602_read_reg_cache(struct snd_soc_codec *codec,
  72        unsigned int reg)
  73{
  74        u16 *cache = codec->reg_cache;
  75        if (reg == SSM2602_RESET)
  76                return 0;
  77        if (reg >= SSM2602_CACHEREGNUM)
  78                return -1;
  79        return cache[reg];
  80}
  81
  82/*
  83 * write ssm2602 register cache
  84 */
  85static inline void ssm2602_write_reg_cache(struct snd_soc_codec *codec,
  86        u16 reg, unsigned int value)
  87{
  88        u16 *cache = codec->reg_cache;
  89        if (reg >= SSM2602_CACHEREGNUM)
  90                return;
  91        cache[reg] = value;
  92}
  93
  94/*
  95 * write to the ssm2602 register space
  96 */
  97static int ssm2602_write(struct snd_soc_codec *codec, unsigned int reg,
  98        unsigned int value)
  99{
 100        u8 data[2];
 101
 102        /* data is
 103         *   D15..D9 ssm2602 register offset
 104         *   D8...D0 register data
 105         */
 106        data[0] = (reg << 1) | ((value >> 8) & 0x0001);
 107        data[1] = value & 0x00ff;
 108
 109        ssm2602_write_reg_cache(codec, reg, value);
 110        if (codec->hw_write(codec->control_data, data, 2) == 2)
 111                return 0;
 112        else
 113                return -EIO;
 114}
 115
 116#define ssm2602_reset(c)        ssm2602_write(c, SSM2602_RESET, 0)
 117
 118/*Appending several "None"s just for OSS mixer use*/
 119static const char *ssm2602_input_select[] = {
 120        "Line", "Mic", "None", "None", "None",
 121        "None", "None", "None",
 122};
 123
 124static const char *ssm2602_deemph[] = {"None", "32Khz", "44.1Khz", "48Khz"};
 125
 126static const struct soc_enum ssm2602_enum[] = {
 127        SOC_ENUM_SINGLE(SSM2602_APANA, 2, 2, ssm2602_input_select),
 128        SOC_ENUM_SINGLE(SSM2602_APDIGI, 1, 4, ssm2602_deemph),
 129};
 130
 131static const struct snd_kcontrol_new ssm2602_snd_controls[] = {
 132
 133SOC_DOUBLE_R("Master Playback Volume", SSM2602_LOUT1V, SSM2602_ROUT1V,
 134        0, 127, 0),
 135SOC_DOUBLE_R("Master Playback ZC Switch", SSM2602_LOUT1V, SSM2602_ROUT1V,
 136        7, 1, 0),
 137
 138SOC_DOUBLE_R("Capture Volume", SSM2602_LINVOL, SSM2602_RINVOL, 0, 31, 0),
 139SOC_DOUBLE_R("Capture Switch", SSM2602_LINVOL, SSM2602_RINVOL, 7, 1, 1),
 140
 141SOC_SINGLE("Mic Boost (+20dB)", SSM2602_APANA, 0, 1, 0),
 142SOC_SINGLE("Mic Switch", SSM2602_APANA, 1, 1, 1),
 143
 144SOC_SINGLE("Sidetone Playback Volume", SSM2602_APANA, 6, 3, 1),
 145
 146SOC_SINGLE("ADC High Pass Filter Switch", SSM2602_APDIGI, 0, 1, 1),
 147SOC_SINGLE("Store DC Offset Switch", SSM2602_APDIGI, 4, 1, 0),
 148
 149SOC_ENUM("Capture Source", ssm2602_enum[0]),
 150
 151SOC_ENUM("Playback De-emphasis", ssm2602_enum[1]),
 152};
 153
 154/* add non dapm controls */
 155static int ssm2602_add_controls(struct snd_soc_codec *codec)
 156{
 157        int err, i;
 158
 159        for (i = 0; i < ARRAY_SIZE(ssm2602_snd_controls); i++) {
 160                err = snd_ctl_add(codec->card,
 161                        snd_soc_cnew(&ssm2602_snd_controls[i], codec, NULL));
 162                if (err < 0)
 163                        return err;
 164        }
 165
 166        return 0;
 167}
 168
 169/* Output Mixer */
 170static const struct snd_kcontrol_new ssm2602_output_mixer_controls[] = {
 171SOC_DAPM_SINGLE("Line Bypass Switch", SSM2602_APANA, 3, 1, 0),
 172SOC_DAPM_SINGLE("Mic Sidetone Switch", SSM2602_APANA, 5, 1, 0),
 173SOC_DAPM_SINGLE("HiFi Playback Switch", SSM2602_APANA, 4, 1, 0),
 174};
 175
 176/* Input mux */
 177static const struct snd_kcontrol_new ssm2602_input_mux_controls =
 178SOC_DAPM_ENUM("Input Select", ssm2602_enum[0]);
 179
 180static const struct snd_soc_dapm_widget ssm2602_dapm_widgets[] = {
 181SND_SOC_DAPM_MIXER("Output Mixer", SSM2602_PWR, 4, 1,
 182        &ssm2602_output_mixer_controls[0],
 183        ARRAY_SIZE(ssm2602_output_mixer_controls)),
 184SND_SOC_DAPM_DAC("DAC", "HiFi Playback", SSM2602_PWR, 3, 1),
 185SND_SOC_DAPM_OUTPUT("LOUT"),
 186SND_SOC_DAPM_OUTPUT("LHPOUT"),
 187SND_SOC_DAPM_OUTPUT("ROUT"),
 188SND_SOC_DAPM_OUTPUT("RHPOUT"),
 189SND_SOC_DAPM_ADC("ADC", "HiFi Capture", SSM2602_PWR, 2, 1),
 190SND_SOC_DAPM_MUX("Input Mux", SND_SOC_NOPM, 0, 0, &ssm2602_input_mux_controls),
 191SND_SOC_DAPM_PGA("Line Input", SSM2602_PWR, 0, 1, NULL, 0),
 192SND_SOC_DAPM_MICBIAS("Mic Bias", SSM2602_PWR, 1, 1),
 193SND_SOC_DAPM_INPUT("MICIN"),
 194SND_SOC_DAPM_INPUT("RLINEIN"),
 195SND_SOC_DAPM_INPUT("LLINEIN"),
 196};
 197
 198static const struct snd_soc_dapm_route audio_conn[] = {
 199        /* output mixer */
 200        {"Output Mixer", "Line Bypass Switch", "Line Input"},
 201        {"Output Mixer", "HiFi Playback Switch", "DAC"},
 202        {"Output Mixer", "Mic Sidetone Switch", "Mic Bias"},
 203
 204        /* outputs */
 205        {"RHPOUT", NULL, "Output Mixer"},
 206        {"ROUT", NULL, "Output Mixer"},
 207        {"LHPOUT", NULL, "Output Mixer"},
 208        {"LOUT", NULL, "Output Mixer"},
 209
 210        /* input mux */
 211        {"Input Mux", "Line", "Line Input"},
 212        {"Input Mux", "Mic", "Mic Bias"},
 213        {"ADC", NULL, "Input Mux"},
 214
 215        /* inputs */
 216        {"Line Input", NULL, "LLINEIN"},
 217        {"Line Input", NULL, "RLINEIN"},
 218        {"Mic Bias", NULL, "MICIN"},
 219};
 220
 221static int ssm2602_add_widgets(struct snd_soc_codec *codec)
 222{
 223        snd_soc_dapm_new_controls(codec, ssm2602_dapm_widgets,
 224                                  ARRAY_SIZE(ssm2602_dapm_widgets));
 225
 226        snd_soc_dapm_add_routes(codec, audio_conn, ARRAY_SIZE(audio_conn));
 227
 228        snd_soc_dapm_new_widgets(codec);
 229        return 0;
 230}
 231
 232struct _coeff_div {
 233        u32 mclk;
 234        u32 rate;
 235        u16 fs;
 236        u8 sr:4;
 237        u8 bosr:1;
 238        u8 usb:1;
 239};
 240
 241/* codec mclk clock divider coefficients */
 242static const struct _coeff_div coeff_div[] = {
 243        /* 48k */
 244        {12288000, 48000, 256, 0x0, 0x0, 0x0},
 245        {18432000, 48000, 384, 0x0, 0x1, 0x0},
 246        {12000000, 48000, 250, 0x0, 0x0, 0x1},
 247
 248        /* 32k */
 249        {12288000, 32000, 384, 0x6, 0x0, 0x0},
 250        {18432000, 32000, 576, 0x6, 0x1, 0x0},
 251        {12000000, 32000, 375, 0x6, 0x0, 0x1},
 252
 253        /* 8k */
 254        {12288000, 8000, 1536, 0x3, 0x0, 0x0},
 255        {18432000, 8000, 2304, 0x3, 0x1, 0x0},
 256        {11289600, 8000, 1408, 0xb, 0x0, 0x0},
 257        {16934400, 8000, 2112, 0xb, 0x1, 0x0},
 258        {12000000, 8000, 1500, 0x3, 0x0, 0x1},
 259
 260        /* 96k */
 261        {12288000, 96000, 128, 0x7, 0x0, 0x0},
 262        {18432000, 96000, 192, 0x7, 0x1, 0x0},
 263        {12000000, 96000, 125, 0x7, 0x0, 0x1},
 264
 265        /* 44.1k */
 266        {11289600, 44100, 256, 0x8, 0x0, 0x0},
 267        {16934400, 44100, 384, 0x8, 0x1, 0x0},
 268        {12000000, 44100, 272, 0x8, 0x1, 0x1},
 269
 270        /* 88.2k */
 271        {11289600, 88200, 128, 0xf, 0x0, 0x0},
 272        {16934400, 88200, 192, 0xf, 0x1, 0x0},
 273        {12000000, 88200, 136, 0xf, 0x1, 0x1},
 274};
 275
 276static inline int get_coeff(int mclk, int rate)
 277{
 278        int i;
 279
 280        for (i = 0; i < ARRAY_SIZE(coeff_div); i++) {
 281                if (coeff_div[i].rate == rate && coeff_div[i].mclk == mclk)
 282                        return i;
 283        }
 284        return i;
 285}
 286
 287static int ssm2602_hw_params(struct snd_pcm_substream *substream,
 288        struct snd_pcm_hw_params *params)
 289{
 290        u16 srate;
 291        struct snd_soc_pcm_runtime *rtd = substream->private_data;
 292        struct snd_soc_device *socdev = rtd->socdev;
 293        struct snd_soc_codec *codec = socdev->codec;
 294        struct ssm2602_priv *ssm2602 = codec->private_data;
 295        u16 iface = ssm2602_read_reg_cache(codec, SSM2602_IFACE) & 0xfff3;
 296        int i = get_coeff(ssm2602->sysclk, params_rate(params));
 297
 298        /*no match is found*/
 299        if (i == ARRAY_SIZE(coeff_div))
 300                return -EINVAL;
 301
 302        srate = (coeff_div[i].sr << 2) |
 303                (coeff_div[i].bosr << 1) | coeff_div[i].usb;
 304
 305        ssm2602_write(codec, SSM2602_ACTIVE, 0);
 306        ssm2602_write(codec, SSM2602_SRATE, srate);
 307
 308        /* bit size */
 309        switch (params_format(params)) {
 310        case SNDRV_PCM_FORMAT_S16_LE:
 311                break;
 312        case SNDRV_PCM_FORMAT_S20_3LE:
 313                iface |= 0x0004;
 314                break;
 315        case SNDRV_PCM_FORMAT_S24_LE:
 316                iface |= 0x0008;
 317                break;
 318        case SNDRV_PCM_FORMAT_S32_LE:
 319                iface |= 0x000c;
 320                break;
 321        }
 322        ssm2602_write(codec, SSM2602_IFACE, iface);
 323        ssm2602_write(codec, SSM2602_ACTIVE, ACTIVE_ACTIVATE_CODEC);
 324        return 0;
 325}
 326
 327static int ssm2602_startup(struct snd_pcm_substream *substream)
 328{
 329        struct snd_soc_pcm_runtime *rtd = substream->private_data;
 330        struct snd_soc_device *socdev = rtd->socdev;
 331        struct snd_soc_codec *codec = socdev->codec;
 332        struct ssm2602_priv *ssm2602 = codec->private_data;
 333        struct snd_pcm_runtime *master_runtime;
 334
 335        /* The DAI has shared clocks so if we already have a playback or
 336         * capture going then constrain this substream to match it.
 337         */
 338        if (ssm2602->master_substream) {
 339                master_runtime = ssm2602->master_substream->runtime;
 340                snd_pcm_hw_constraint_minmax(substream->runtime,
 341                                             SNDRV_PCM_HW_PARAM_RATE,
 342                                             master_runtime->rate,
 343                                             master_runtime->rate);
 344
 345                snd_pcm_hw_constraint_minmax(substream->runtime,
 346                                             SNDRV_PCM_HW_PARAM_SAMPLE_BITS,
 347                                             master_runtime->sample_bits,
 348                                             master_runtime->sample_bits);
 349
 350                ssm2602->slave_substream = substream;
 351        } else
 352                ssm2602->master_substream = substream;
 353
 354        return 0;
 355}
 356
 357static int ssm2602_pcm_prepare(struct snd_pcm_substream *substream)
 358{
 359        struct snd_soc_pcm_runtime *rtd = substream->private_data;
 360        struct snd_soc_device *socdev = rtd->socdev;
 361        struct snd_soc_codec *codec = socdev->codec;
 362        /* set active */
 363        ssm2602_write(codec, SSM2602_ACTIVE, ACTIVE_ACTIVATE_CODEC);
 364
 365        return 0;
 366}
 367
 368static void ssm2602_shutdown(struct snd_pcm_substream *substream)
 369{
 370        struct snd_soc_pcm_runtime *rtd = substream->private_data;
 371        struct snd_soc_device *socdev = rtd->socdev;
 372        struct snd_soc_codec *codec = socdev->codec;
 373        /* deactivate */
 374        if (!codec->active)
 375                ssm2602_write(codec, SSM2602_ACTIVE, 0);
 376}
 377
 378static int ssm2602_mute(struct snd_soc_dai *dai, int mute)
 379{
 380        struct snd_soc_codec *codec = dai->codec;
 381        u16 mute_reg = ssm2602_read_reg_cache(codec, SSM2602_APDIGI) & ~APDIGI_ENABLE_DAC_MUTE;
 382        if (mute)
 383                ssm2602_write(codec, SSM2602_APDIGI,
 384                                mute_reg | APDIGI_ENABLE_DAC_MUTE);
 385        else
 386                ssm2602_write(codec, SSM2602_APDIGI, mute_reg);
 387        return 0;
 388}
 389
 390static int ssm2602_set_dai_sysclk(struct snd_soc_dai *codec_dai,
 391                int clk_id, unsigned int freq, int dir)
 392{
 393        struct snd_soc_codec *codec = codec_dai->codec;
 394        struct ssm2602_priv *ssm2602 = codec->private_data;
 395        switch (freq) {
 396        case 11289600:
 397        case 12000000:
 398        case 12288000:
 399        case 16934400:
 400        case 18432000:
 401                ssm2602->sysclk = freq;
 402                return 0;
 403        }
 404        return -EINVAL;
 405}
 406
 407static int ssm2602_set_dai_fmt(struct snd_soc_dai *codec_dai,
 408                unsigned int fmt)
 409{
 410        struct snd_soc_codec *codec = codec_dai->codec;
 411        u16 iface = 0;
 412
 413        /* set master/slave audio interface */
 414        switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
 415        case SND_SOC_DAIFMT_CBM_CFM:
 416                iface |= 0x0040;
 417                break;
 418        case SND_SOC_DAIFMT_CBS_CFS:
 419                break;
 420        default:
 421                return -EINVAL;
 422        }
 423
 424        /* interface format */
 425        switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
 426        case SND_SOC_DAIFMT_I2S:
 427                iface |= 0x0002;
 428                break;
 429        case SND_SOC_DAIFMT_RIGHT_J:
 430                break;
 431        case SND_SOC_DAIFMT_LEFT_J:
 432                iface |= 0x0001;
 433                break;
 434        case SND_SOC_DAIFMT_DSP_A:
 435                iface |= 0x0003;
 436                break;
 437        case SND_SOC_DAIFMT_DSP_B:
 438                iface |= 0x0013;
 439                break;
 440        default:
 441                return -EINVAL;
 442        }
 443
 444        /* clock inversion */
 445        switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
 446        case SND_SOC_DAIFMT_NB_NF:
 447                break;
 448        case SND_SOC_DAIFMT_IB_IF:
 449                iface |= 0x0090;
 450                break;
 451        case SND_SOC_DAIFMT_IB_NF:
 452                iface |= 0x0080;
 453                break;
 454        case SND_SOC_DAIFMT_NB_IF:
 455                iface |= 0x0010;
 456                break;
 457        default:
 458                return -EINVAL;
 459        }
 460
 461        /* set iface */
 462        ssm2602_write(codec, SSM2602_IFACE, iface);
 463        return 0;
 464}
 465
 466static int ssm2602_set_bias_level(struct snd_soc_codec *codec,
 467                                 enum snd_soc_bias_level level)
 468{
 469        u16 reg = ssm2602_read_reg_cache(codec, SSM2602_PWR) & 0xff7f;
 470
 471        switch (level) {
 472        case SND_SOC_BIAS_ON:
 473                /* vref/mid, osc on, dac unmute */
 474                ssm2602_write(codec, SSM2602_PWR, reg);
 475                break;
 476        case SND_SOC_BIAS_PREPARE:
 477                break;
 478        case SND_SOC_BIAS_STANDBY:
 479                /* everything off except vref/vmid, */
 480                ssm2602_write(codec, SSM2602_PWR, reg | PWR_CLK_OUT_PDN);
 481                break;
 482        case SND_SOC_BIAS_OFF:
 483                /* everything off, dac mute, inactive */
 484                ssm2602_write(codec, SSM2602_ACTIVE, 0);
 485                ssm2602_write(codec, SSM2602_PWR, 0xffff);
 486                break;
 487
 488        }
 489        codec->bias_level = level;
 490        return 0;
 491}
 492
 493#define SSM2602_RATES (SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_11025 |\
 494                SNDRV_PCM_RATE_16000 | SNDRV_PCM_RATE_22050 |\
 495                SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_44100 |\
 496                SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_88200 |\
 497                SNDRV_PCM_RATE_96000)
 498
 499struct snd_soc_dai ssm2602_dai = {
 500        .name = "SSM2602",
 501        .playback = {
 502                .stream_name = "Playback",
 503                .channels_min = 2,
 504                .channels_max = 2,
 505                .rates = SSM2602_RATES,
 506                .formats = SNDRV_PCM_FMTBIT_S32_LE,},
 507        .capture = {
 508                .stream_name = "Capture",
 509                .channels_min = 2,
 510                .channels_max = 2,
 511                .rates = SSM2602_RATES,
 512                .formats = SNDRV_PCM_FMTBIT_S32_LE,},
 513        .ops = {
 514                .startup = ssm2602_startup,
 515                .prepare = ssm2602_pcm_prepare,
 516                .hw_params = ssm2602_hw_params,
 517                .shutdown = ssm2602_shutdown,
 518        },
 519        .dai_ops = {
 520                .digital_mute = ssm2602_mute,
 521                .set_sysclk = ssm2602_set_dai_sysclk,
 522                .set_fmt = ssm2602_set_dai_fmt,
 523        }
 524};
 525EXPORT_SYMBOL_GPL(ssm2602_dai);
 526
 527static int ssm2602_suspend(struct platform_device *pdev, pm_message_t state)
 528{
 529        struct snd_soc_device *socdev = platform_get_drvdata(pdev);
 530        struct snd_soc_codec *codec = socdev->codec;
 531
 532        ssm2602_set_bias_level(codec, SND_SOC_BIAS_OFF);
 533        return 0;
 534}
 535
 536static int ssm2602_resume(struct platform_device *pdev)
 537{
 538        struct snd_soc_device *socdev = platform_get_drvdata(pdev);
 539        struct snd_soc_codec *codec = socdev->codec;
 540        int i;
 541        u8 data[2];
 542        u16 *cache = codec->reg_cache;
 543
 544        /* Sync reg_cache with the hardware */
 545        for (i = 0; i < ARRAY_SIZE(ssm2602_reg); i++) {
 546                data[0] = (i << 1) | ((cache[i] >> 8) & 0x0001);
 547                data[1] = cache[i] & 0x00ff;
 548                codec->hw_write(codec->control_data, data, 2);
 549        }
 550        ssm2602_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
 551        ssm2602_set_bias_level(codec, codec->suspend_bias_level);
 552        return 0;
 553}
 554
 555/*
 556 * initialise the ssm2602 driver
 557 * register the mixer and dsp interfaces with the kernel
 558 */
 559static int ssm2602_init(struct snd_soc_device *socdev)
 560{
 561        struct snd_soc_codec *codec = socdev->codec;
 562        int reg, ret = 0;
 563
 564        codec->name = "SSM2602";
 565        codec->owner = THIS_MODULE;
 566        codec->read = ssm2602_read_reg_cache;
 567        codec->write = ssm2602_write;
 568        codec->set_bias_level = ssm2602_set_bias_level;
 569        codec->dai = &ssm2602_dai;
 570        codec->num_dai = 1;
 571        codec->reg_cache_size = sizeof(ssm2602_reg);
 572        codec->reg_cache = kmemdup(ssm2602_reg, sizeof(ssm2602_reg),
 573                                        GFP_KERNEL);
 574        if (codec->reg_cache == NULL)
 575                return -ENOMEM;
 576
 577        ssm2602_reset(codec);
 578
 579        /* register pcms */
 580        ret = snd_soc_new_pcms(socdev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1);
 581        if (ret < 0) {
 582                pr_err("ssm2602: failed to create pcms\n");
 583                goto pcm_err;
 584        }
 585        /*power on device*/
 586        ssm2602_write(codec, SSM2602_ACTIVE, 0);
 587        /* set the update bits */
 588        reg = ssm2602_read_reg_cache(codec, SSM2602_LINVOL);
 589        ssm2602_write(codec, SSM2602_LINVOL, reg | LINVOL_LRIN_BOTH);
 590        reg = ssm2602_read_reg_cache(codec, SSM2602_RINVOL);
 591        ssm2602_write(codec, SSM2602_RINVOL, reg | RINVOL_RLIN_BOTH);
 592        reg = ssm2602_read_reg_cache(codec, SSM2602_LOUT1V);
 593        ssm2602_write(codec, SSM2602_LOUT1V, reg | LOUT1V_LRHP_BOTH);
 594        reg = ssm2602_read_reg_cache(codec, SSM2602_ROUT1V);
 595        ssm2602_write(codec, SSM2602_ROUT1V, reg | ROUT1V_RLHP_BOTH);
 596        /*select Line in as default input*/
 597        ssm2602_write(codec, SSM2602_APANA,
 598                        APANA_ENABLE_MIC_BOOST2 | APANA_SELECT_DAC |
 599                        APANA_ENABLE_MIC_BOOST);
 600        ssm2602_write(codec, SSM2602_PWR, 0);
 601
 602        ssm2602_add_controls(codec);
 603        ssm2602_add_widgets(codec);
 604        ret = snd_soc_register_card(socdev);
 605        if (ret < 0) {
 606                pr_err("ssm2602: failed to register card\n");
 607                goto card_err;
 608        }
 609
 610        return ret;
 611
 612card_err:
 613        snd_soc_free_pcms(socdev);
 614        snd_soc_dapm_free(socdev);
 615pcm_err:
 616        kfree(codec->reg_cache);
 617        return ret;
 618}
 619
 620static struct snd_soc_device *ssm2602_socdev;
 621
 622#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
 623/*
 624 * ssm2602 2 wire address is determined by GPIO5
 625 * state during powerup.
 626 *    low  = 0x1a
 627 *    high = 0x1b
 628 */
 629static int ssm2602_i2c_probe(struct i2c_client *i2c,
 630                             const struct i2c_device_id *id)
 631{
 632        struct snd_soc_device *socdev = ssm2602_socdev;
 633        struct snd_soc_codec *codec = socdev->codec;
 634        int ret;
 635
 636        i2c_set_clientdata(i2c, codec);
 637        codec->control_data = i2c;
 638
 639        ret = ssm2602_init(socdev);
 640        if (ret < 0)
 641                pr_err("failed to initialise SSM2602\n");
 642
 643        return ret;
 644}
 645
 646static int ssm2602_i2c_remove(struct i2c_client *client)
 647{
 648        struct snd_soc_codec *codec = i2c_get_clientdata(client);
 649        kfree(codec->reg_cache);
 650        return 0;
 651}
 652
 653static const struct i2c_device_id ssm2602_i2c_id[] = {
 654        { "ssm2602", 0 },
 655        { }
 656};
 657MODULE_DEVICE_TABLE(i2c, ssm2602_i2c_id);
 658/* corgi i2c codec control layer */
 659static struct i2c_driver ssm2602_i2c_driver = {
 660        .driver = {
 661                .name = "SSM2602 I2C Codec",
 662                .owner = THIS_MODULE,
 663        },
 664        .probe = ssm2602_i2c_probe,
 665        .remove = ssm2602_i2c_remove,
 666        .id_table = ssm2602_i2c_id,
 667};
 668
 669static int ssm2602_add_i2c_device(struct platform_device *pdev,
 670                                  const struct ssm2602_setup_data *setup)
 671{
 672        struct i2c_board_info info;
 673        struct i2c_adapter *adapter;
 674        struct i2c_client *client;
 675        int ret;
 676
 677        ret = i2c_add_driver(&ssm2602_i2c_driver);
 678        if (ret != 0) {
 679                dev_err(&pdev->dev, "can't add i2c driver\n");
 680                return ret;
 681        }
 682        memset(&info, 0, sizeof(struct i2c_board_info));
 683        info.addr = setup->i2c_address;
 684        strlcpy(info.type, "ssm2602", I2C_NAME_SIZE);
 685        adapter = i2c_get_adapter(setup->i2c_bus);
 686        if (!adapter) {
 687                dev_err(&pdev->dev, "can't get i2c adapter %d\n",
 688                setup->i2c_bus);
 689                goto err_driver;
 690        }
 691        client = i2c_new_device(adapter, &info);
 692        i2c_put_adapter(adapter);
 693        if (!client) {
 694                dev_err(&pdev->dev, "can't add i2c device at 0x%x\n",
 695                (unsigned int)info.addr);
 696                goto err_driver;
 697        }
 698        return 0;
 699err_driver:
 700        i2c_del_driver(&ssm2602_i2c_driver);
 701        return -ENODEV;
 702}
 703#endif
 704
 705static int ssm2602_probe(struct platform_device *pdev)
 706{
 707        struct snd_soc_device *socdev = platform_get_drvdata(pdev);
 708        struct ssm2602_setup_data *setup;
 709        struct snd_soc_codec *codec;
 710        struct ssm2602_priv *ssm2602;
 711        int ret = 0;
 712
 713        pr_info("ssm2602 Audio Codec %s", SSM2602_VERSION);
 714
 715        setup = socdev->codec_data;
 716        codec = kzalloc(sizeof(struct snd_soc_codec), GFP_KERNEL);
 717        if (codec == NULL)
 718                return -ENOMEM;
 719
 720        ssm2602 = kzalloc(sizeof(struct ssm2602_priv), GFP_KERNEL);
 721        if (ssm2602 == NULL) {
 722                kfree(codec);
 723                return -ENOMEM;
 724        }
 725
 726        codec->private_data = ssm2602;
 727        socdev->codec = codec;
 728        mutex_init(&codec->mutex);
 729        INIT_LIST_HEAD(&codec->dapm_widgets);
 730        INIT_LIST_HEAD(&codec->dapm_paths);
 731
 732        ssm2602_socdev = socdev;
 733#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
 734        if (setup->i2c_address) {
 735                codec->hw_write = (hw_write_t)i2c_master_send;
 736                ret = ssm2602_add_i2c_device(pdev, setup);
 737        }
 738#else
 739        /* other interfaces */
 740#endif
 741        return ret;
 742}
 743
 744/* remove everything here */
 745static int ssm2602_remove(struct platform_device *pdev)
 746{
 747        struct snd_soc_device *socdev = platform_get_drvdata(pdev);
 748        struct snd_soc_codec *codec = socdev->codec;
 749
 750        if (codec->control_data)
 751                ssm2602_set_bias_level(codec, SND_SOC_BIAS_OFF);
 752
 753        snd_soc_free_pcms(socdev);
 754        snd_soc_dapm_free(socdev);
 755#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
 756        i2c_unregister_device(codec->control_data);
 757        i2c_del_driver(&ssm2602_i2c_driver);
 758#endif
 759        kfree(codec->private_data);
 760        kfree(codec);
 761
 762        return 0;
 763}
 764
 765struct snd_soc_codec_device soc_codec_dev_ssm2602 = {
 766        .probe =        ssm2602_probe,
 767        .remove =       ssm2602_remove,
 768        .suspend =      ssm2602_suspend,
 769        .resume =       ssm2602_resume,
 770};
 771EXPORT_SYMBOL_GPL(soc_codec_dev_ssm2602);
 772
 773MODULE_DESCRIPTION("ASoC ssm2602 driver");
 774MODULE_AUTHOR("Cliff Cai");
 775MODULE_LICENSE("GPL");
 776
lxr.linux.no kindly hosted by Redpill Linpro AS, provider of Linux consulting and operations services since 1995.