~ubuntu-branches/ubuntu/precise/linux-lowlatency/precise

« back to all changes in this revision

Viewing changes to sound/soc/codecs/ssm2602.c

  • Committer: Package Import Robot
  • Author(s): Alessio Igor Bogani
  • Date: 2011-10-26 11:13:05 UTC
  • Revision ID: package-import@ubuntu.com-20111026111305-tz023xykf0i6eosh
Tags: upstream-3.2.0
ImportĀ upstreamĀ versionĀ 3.2.0

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
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/spi/spi.h>
 
36
#include <linux/platform_device.h>
 
37
#include <linux/slab.h>
 
38
#include <sound/core.h>
 
39
#include <sound/pcm.h>
 
40
#include <sound/pcm_params.h>
 
41
#include <sound/soc.h>
 
42
#include <sound/initval.h>
 
43
#include <sound/tlv.h>
 
44
 
 
45
#include "ssm2602.h"
 
46
 
 
47
#define SSM2602_VERSION "0.1"
 
48
 
 
49
enum ssm2602_type {
 
50
        SSM2602,
 
51
        SSM2604,
 
52
};
 
53
 
 
54
/* codec private data */
 
55
struct ssm2602_priv {
 
56
        unsigned int sysclk;
 
57
        enum snd_soc_control_type control_type;
 
58
        struct snd_pcm_substream *master_substream;
 
59
        struct snd_pcm_substream *slave_substream;
 
60
 
 
61
        enum ssm2602_type type;
 
62
        unsigned int clk_out_pwr;
 
63
};
 
64
 
 
65
/*
 
66
 * ssm2602 register cache
 
67
 * We can't read the ssm2602 register space when we are
 
68
 * using 2 wire for device control, so we cache them instead.
 
69
 * There is no point in caching the reset register
 
70
 */
 
71
static const u16 ssm2602_reg[SSM2602_CACHEREGNUM] = {
 
72
        0x0097, 0x0097, 0x0079, 0x0079,
 
73
        0x000a, 0x0008, 0x009f, 0x000a,
 
74
        0x0000, 0x0000
 
75
};
 
76
 
 
77
#define ssm2602_reset(c)        snd_soc_write(c, SSM2602_RESET, 0)
 
78
 
 
79
/*Appending several "None"s just for OSS mixer use*/
 
80
static const char *ssm2602_input_select[] = {
 
81
        "Line", "Mic", "None", "None", "None",
 
82
        "None", "None", "None",
 
83
};
 
84
 
 
85
static const char *ssm2602_deemph[] = {"None", "32Khz", "44.1Khz", "48Khz"};
 
86
 
 
87
static const struct soc_enum ssm2602_enum[] = {
 
88
        SOC_ENUM_SINGLE(SSM2602_APANA, 2, 2, ssm2602_input_select),
 
89
        SOC_ENUM_SINGLE(SSM2602_APDIGI, 1, 4, ssm2602_deemph),
 
90
};
 
91
 
 
92
static const unsigned int ssm260x_outmix_tlv[] = {
 
93
        TLV_DB_RANGE_HEAD(2),
 
94
        0, 47, TLV_DB_SCALE_ITEM(TLV_DB_GAIN_MUTE, 0, 0),
 
95
        48, 127, TLV_DB_SCALE_ITEM(-7400, 100, 0),
 
96
};
 
97
 
 
98
static const DECLARE_TLV_DB_SCALE(ssm260x_inpga_tlv, -3450, 150, 0);
 
99
static const DECLARE_TLV_DB_SCALE(ssm260x_sidetone_tlv, -1500, 300, 0);
 
100
 
 
101
static const struct snd_kcontrol_new ssm260x_snd_controls[] = {
 
102
SOC_DOUBLE_R_TLV("Capture Volume", SSM2602_LINVOL, SSM2602_RINVOL, 0, 45, 0,
 
103
        ssm260x_inpga_tlv),
 
104
SOC_DOUBLE_R("Capture Switch", SSM2602_LINVOL, SSM2602_RINVOL, 7, 1, 1),
 
105
 
 
106
SOC_SINGLE("ADC High Pass Filter Switch", SSM2602_APDIGI, 0, 1, 1),
 
107
SOC_SINGLE("Store DC Offset Switch", SSM2602_APDIGI, 4, 1, 0),
 
108
 
 
109
SOC_ENUM("Playback De-emphasis", ssm2602_enum[1]),
 
110
};
 
111
 
 
112
static const struct snd_kcontrol_new ssm2602_snd_controls[] = {
 
113
SOC_DOUBLE_R_TLV("Master Playback Volume", SSM2602_LOUT1V, SSM2602_ROUT1V,
 
114
        0, 127, 0, ssm260x_outmix_tlv),
 
115
SOC_DOUBLE_R("Master Playback ZC Switch", SSM2602_LOUT1V, SSM2602_ROUT1V,
 
116
        7, 1, 0),
 
117
SOC_SINGLE_TLV("Sidetone Playback Volume", SSM2602_APANA, 6, 3, 1,
 
118
        ssm260x_sidetone_tlv),
 
119
 
 
120
SOC_SINGLE("Mic Boost (+20dB)", SSM2602_APANA, 0, 1, 0),
 
121
SOC_SINGLE("Mic Boost2 (+20dB)", SSM2602_APANA, 8, 1, 0),
 
122
SOC_SINGLE("Mic Switch", SSM2602_APANA, 1, 1, 1),
 
123
};
 
124
 
 
125
/* Output Mixer */
 
126
static const struct snd_kcontrol_new ssm260x_output_mixer_controls[] = {
 
127
SOC_DAPM_SINGLE("Line Bypass Switch", SSM2602_APANA, 3, 1, 0),
 
128
SOC_DAPM_SINGLE("HiFi Playback Switch", SSM2602_APANA, 4, 1, 0),
 
129
SOC_DAPM_SINGLE("Mic Sidetone Switch", SSM2602_APANA, 5, 1, 0),
 
130
};
 
131
 
 
132
/* Input mux */
 
133
static const struct snd_kcontrol_new ssm2602_input_mux_controls =
 
134
SOC_DAPM_ENUM("Input Select", ssm2602_enum[0]);
 
135
 
 
136
static const struct snd_soc_dapm_widget ssm260x_dapm_widgets[] = {
 
137
SND_SOC_DAPM_DAC("DAC", "HiFi Playback", SSM2602_PWR, 3, 1),
 
138
SND_SOC_DAPM_ADC("ADC", "HiFi Capture", SSM2602_PWR, 2, 1),
 
139
SND_SOC_DAPM_PGA("Line Input", SSM2602_PWR, 0, 1, NULL, 0),
 
140
 
 
141
SND_SOC_DAPM_SUPPLY("Digital Core Power", SSM2602_ACTIVE, 0, 0, NULL, 0),
 
142
 
 
143
SND_SOC_DAPM_OUTPUT("LOUT"),
 
144
SND_SOC_DAPM_OUTPUT("ROUT"),
 
145
SND_SOC_DAPM_INPUT("RLINEIN"),
 
146
SND_SOC_DAPM_INPUT("LLINEIN"),
 
147
};
 
148
 
 
149
static const struct snd_soc_dapm_widget ssm2602_dapm_widgets[] = {
 
150
SND_SOC_DAPM_MIXER("Output Mixer", SSM2602_PWR, 4, 1,
 
151
        ssm260x_output_mixer_controls,
 
152
        ARRAY_SIZE(ssm260x_output_mixer_controls)),
 
153
 
 
154
SND_SOC_DAPM_MUX("Input Mux", SND_SOC_NOPM, 0, 0, &ssm2602_input_mux_controls),
 
155
SND_SOC_DAPM_MICBIAS("Mic Bias", SSM2602_PWR, 1, 1),
 
156
 
 
157
SND_SOC_DAPM_OUTPUT("LHPOUT"),
 
158
SND_SOC_DAPM_OUTPUT("RHPOUT"),
 
159
SND_SOC_DAPM_INPUT("MICIN"),
 
160
};
 
161
 
 
162
static const struct snd_soc_dapm_widget ssm2604_dapm_widgets[] = {
 
163
SND_SOC_DAPM_MIXER("Output Mixer", SND_SOC_NOPM, 0, 0,
 
164
        ssm260x_output_mixer_controls,
 
165
        ARRAY_SIZE(ssm260x_output_mixer_controls) - 1), /* Last element is the mic */
 
166
};
 
167
 
 
168
static const struct snd_soc_dapm_route ssm260x_routes[] = {
 
169
        {"DAC", NULL, "Digital Core Power"},
 
170
        {"ADC", NULL, "Digital Core Power"},
 
171
 
 
172
        {"Output Mixer", "Line Bypass Switch", "Line Input"},
 
173
        {"Output Mixer", "HiFi Playback Switch", "DAC"},
 
174
 
 
175
        {"ROUT", NULL, "Output Mixer"},
 
176
        {"LOUT", NULL, "Output Mixer"},
 
177
 
 
178
        {"Line Input", NULL, "LLINEIN"},
 
179
        {"Line Input", NULL, "RLINEIN"},
 
180
};
 
181
 
 
182
static const struct snd_soc_dapm_route ssm2602_routes[] = {
 
183
        {"Output Mixer", "Mic Sidetone Switch", "Mic Bias"},
 
184
 
 
185
        {"RHPOUT", NULL, "Output Mixer"},
 
186
        {"LHPOUT", NULL, "Output Mixer"},
 
187
 
 
188
        {"Input Mux", "Line", "Line Input"},
 
189
        {"Input Mux", "Mic", "Mic Bias"},
 
190
        {"ADC", NULL, "Input Mux"},
 
191
 
 
192
        {"Mic Bias", NULL, "MICIN"},
 
193
};
 
194
 
 
195
static const struct snd_soc_dapm_route ssm2604_routes[] = {
 
196
        {"ADC", NULL, "Line Input"},
 
197
};
 
198
 
 
199
struct ssm2602_coeff {
 
200
        u32 mclk;
 
201
        u32 rate;
 
202
        u8 srate;
 
203
};
 
204
 
 
205
#define SSM2602_COEFF_SRATE(sr, bosr, usb) (((sr) << 2) | ((bosr) << 1) | (usb))
 
206
 
 
207
/* codec mclk clock coefficients */
 
208
static const struct ssm2602_coeff ssm2602_coeff_table[] = {
 
209
        /* 48k */
 
210
        {12288000, 48000, SSM2602_COEFF_SRATE(0x0, 0x0, 0x0)},
 
211
        {18432000, 48000, SSM2602_COEFF_SRATE(0x0, 0x1, 0x0)},
 
212
        {12000000, 48000, SSM2602_COEFF_SRATE(0x0, 0x0, 0x1)},
 
213
 
 
214
        /* 32k */
 
215
        {12288000, 32000, SSM2602_COEFF_SRATE(0x6, 0x0, 0x0)},
 
216
        {18432000, 32000, SSM2602_COEFF_SRATE(0x6, 0x1, 0x0)},
 
217
        {12000000, 32000, SSM2602_COEFF_SRATE(0x6, 0x0, 0x1)},
 
218
 
 
219
        /* 8k */
 
220
        {12288000, 8000, SSM2602_COEFF_SRATE(0x3, 0x0, 0x0)},
 
221
        {18432000, 8000, SSM2602_COEFF_SRATE(0x3, 0x1, 0x0)},
 
222
        {11289600, 8000, SSM2602_COEFF_SRATE(0xb, 0x0, 0x0)},
 
223
        {16934400, 8000, SSM2602_COEFF_SRATE(0xb, 0x1, 0x0)},
 
224
        {12000000, 8000, SSM2602_COEFF_SRATE(0x3, 0x0, 0x1)},
 
225
 
 
226
        /* 96k */
 
227
        {12288000, 96000, SSM2602_COEFF_SRATE(0x7, 0x0, 0x0)},
 
228
        {18432000, 96000, SSM2602_COEFF_SRATE(0x7, 0x1, 0x0)},
 
229
        {12000000, 96000, SSM2602_COEFF_SRATE(0x7, 0x0, 0x1)},
 
230
 
 
231
        /* 44.1k */
 
232
        {11289600, 44100, SSM2602_COEFF_SRATE(0x8, 0x0, 0x0)},
 
233
        {16934400, 44100, SSM2602_COEFF_SRATE(0x8, 0x1, 0x0)},
 
234
        {12000000, 44100, SSM2602_COEFF_SRATE(0x8, 0x1, 0x1)},
 
235
 
 
236
        /* 88.2k */
 
237
        {11289600, 88200, SSM2602_COEFF_SRATE(0xf, 0x0, 0x0)},
 
238
        {16934400, 88200, SSM2602_COEFF_SRATE(0xf, 0x1, 0x0)},
 
239
        {12000000, 88200, SSM2602_COEFF_SRATE(0xf, 0x1, 0x1)},
 
240
};
 
241
 
 
242
static inline int ssm2602_get_coeff(int mclk, int rate)
 
243
{
 
244
        int i;
 
245
 
 
246
        for (i = 0; i < ARRAY_SIZE(ssm2602_coeff_table); i++) {
 
247
                if (ssm2602_coeff_table[i].rate == rate &&
 
248
                        ssm2602_coeff_table[i].mclk == mclk)
 
249
                        return ssm2602_coeff_table[i].srate;
 
250
        }
 
251
        return -EINVAL;
 
252
}
 
253
 
 
254
static int ssm2602_hw_params(struct snd_pcm_substream *substream,
 
255
        struct snd_pcm_hw_params *params,
 
256
        struct snd_soc_dai *dai)
 
257
{
 
258
        struct snd_soc_pcm_runtime *rtd = substream->private_data;
 
259
        struct snd_soc_codec *codec = rtd->codec;
 
260
        struct ssm2602_priv *ssm2602 = snd_soc_codec_get_drvdata(codec);
 
261
        u16 iface = snd_soc_read(codec, SSM2602_IFACE) & 0xfff3;
 
262
        int srate = ssm2602_get_coeff(ssm2602->sysclk, params_rate(params));
 
263
 
 
264
        if (substream == ssm2602->slave_substream) {
 
265
                dev_dbg(codec->dev, "Ignoring hw_params for slave substream\n");
 
266
                return 0;
 
267
        }
 
268
 
 
269
        if (srate < 0)
 
270
                return srate;
 
271
 
 
272
        snd_soc_write(codec, SSM2602_SRATE, srate);
 
273
 
 
274
        /* bit size */
 
275
        switch (params_format(params)) {
 
276
        case SNDRV_PCM_FORMAT_S16_LE:
 
277
                break;
 
278
        case SNDRV_PCM_FORMAT_S20_3LE:
 
279
                iface |= 0x0004;
 
280
                break;
 
281
        case SNDRV_PCM_FORMAT_S24_LE:
 
282
                iface |= 0x0008;
 
283
                break;
 
284
        case SNDRV_PCM_FORMAT_S32_LE:
 
285
                iface |= 0x000c;
 
286
                break;
 
287
        }
 
288
        snd_soc_write(codec, SSM2602_IFACE, iface);
 
289
        return 0;
 
290
}
 
291
 
 
292
static int ssm2602_startup(struct snd_pcm_substream *substream,
 
293
                           struct snd_soc_dai *dai)
 
294
{
 
295
        struct snd_soc_pcm_runtime *rtd = substream->private_data;
 
296
        struct snd_soc_codec *codec = rtd->codec;
 
297
        struct ssm2602_priv *ssm2602 = snd_soc_codec_get_drvdata(codec);
 
298
        struct snd_pcm_runtime *master_runtime;
 
299
 
 
300
        /* The DAI has shared clocks so if we already have a playback or
 
301
         * capture going then constrain this substream to match it.
 
302
         * TODO: the ssm2602 allows pairs of non-matching PB/REC rates
 
303
         */
 
304
        if (ssm2602->master_substream) {
 
305
                master_runtime = ssm2602->master_substream->runtime;
 
306
                dev_dbg(codec->dev, "Constraining to %d bits at %dHz\n",
 
307
                        master_runtime->sample_bits,
 
308
                        master_runtime->rate);
 
309
 
 
310
                if (master_runtime->rate != 0)
 
311
                        snd_pcm_hw_constraint_minmax(substream->runtime,
 
312
                                                     SNDRV_PCM_HW_PARAM_RATE,
 
313
                                                     master_runtime->rate,
 
314
                                                     master_runtime->rate);
 
315
 
 
316
                if (master_runtime->sample_bits != 0)
 
317
                        snd_pcm_hw_constraint_minmax(substream->runtime,
 
318
                                                     SNDRV_PCM_HW_PARAM_SAMPLE_BITS,
 
319
                                                     master_runtime->sample_bits,
 
320
                                                     master_runtime->sample_bits);
 
321
 
 
322
                ssm2602->slave_substream = substream;
 
323
        } else
 
324
                ssm2602->master_substream = substream;
 
325
 
 
326
        return 0;
 
327
}
 
328
 
 
329
static void ssm2602_shutdown(struct snd_pcm_substream *substream,
 
330
                             struct snd_soc_dai *dai)
 
331
{
 
332
        struct snd_soc_pcm_runtime *rtd = substream->private_data;
 
333
        struct snd_soc_codec *codec = rtd->codec;
 
334
        struct ssm2602_priv *ssm2602 = snd_soc_codec_get_drvdata(codec);
 
335
 
 
336
        if (ssm2602->master_substream == substream)
 
337
                ssm2602->master_substream = ssm2602->slave_substream;
 
338
 
 
339
        ssm2602->slave_substream = NULL;
 
340
}
 
341
 
 
342
 
 
343
static int ssm2602_mute(struct snd_soc_dai *dai, int mute)
 
344
{
 
345
        struct snd_soc_codec *codec = dai->codec;
 
346
 
 
347
        if (mute)
 
348
                snd_soc_update_bits(codec, SSM2602_APDIGI,
 
349
                                    APDIGI_ENABLE_DAC_MUTE,
 
350
                                    APDIGI_ENABLE_DAC_MUTE);
 
351
        else
 
352
                snd_soc_update_bits(codec, SSM2602_APDIGI,
 
353
                                    APDIGI_ENABLE_DAC_MUTE, 0);
 
354
        return 0;
 
355
}
 
356
 
 
357
static int ssm2602_set_dai_sysclk(struct snd_soc_dai *codec_dai,
 
358
                int clk_id, unsigned int freq, int dir)
 
359
{
 
360
        struct snd_soc_codec *codec = codec_dai->codec;
 
361
        struct ssm2602_priv *ssm2602 = snd_soc_codec_get_drvdata(codec);
 
362
 
 
363
        if (dir == SND_SOC_CLOCK_IN) {
 
364
                if (clk_id != SSM2602_SYSCLK)
 
365
                        return -EINVAL;
 
366
 
 
367
                switch (freq) {
 
368
                case 11289600:
 
369
                case 12000000:
 
370
                case 12288000:
 
371
                case 16934400:
 
372
                case 18432000:
 
373
                        ssm2602->sysclk = freq;
 
374
                        break;
 
375
                default:
 
376
                        return -EINVAL;
 
377
                }
 
378
        } else {
 
379
                unsigned int mask;
 
380
 
 
381
                switch (clk_id) {
 
382
                case SSM2602_CLK_CLKOUT:
 
383
                        mask = PWR_CLK_OUT_PDN;
 
384
                        break;
 
385
                case SSM2602_CLK_XTO:
 
386
                        mask = PWR_OSC_PDN;
 
387
                        break;
 
388
                default:
 
389
                        return -EINVAL;
 
390
                }
 
391
 
 
392
                if (freq == 0)
 
393
                        ssm2602->clk_out_pwr |= mask;
 
394
                else
 
395
                        ssm2602->clk_out_pwr &= ~mask;
 
396
 
 
397
                snd_soc_update_bits(codec, SSM2602_PWR,
 
398
                        PWR_CLK_OUT_PDN | PWR_OSC_PDN, ssm2602->clk_out_pwr);
 
399
        }
 
400
 
 
401
        return 0;
 
402
}
 
403
 
 
404
static int ssm2602_set_dai_fmt(struct snd_soc_dai *codec_dai,
 
405
                unsigned int fmt)
 
406
{
 
407
        struct snd_soc_codec *codec = codec_dai->codec;
 
408
        u16 iface = 0;
 
409
 
 
410
        /* set master/slave audio interface */
 
411
        switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
 
412
        case SND_SOC_DAIFMT_CBM_CFM:
 
413
                iface |= 0x0040;
 
414
                break;
 
415
        case SND_SOC_DAIFMT_CBS_CFS:
 
416
                break;
 
417
        default:
 
418
                return -EINVAL;
 
419
        }
 
420
 
 
421
        /* interface format */
 
422
        switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
 
423
        case SND_SOC_DAIFMT_I2S:
 
424
                iface |= 0x0002;
 
425
                break;
 
426
        case SND_SOC_DAIFMT_RIGHT_J:
 
427
                break;
 
428
        case SND_SOC_DAIFMT_LEFT_J:
 
429
                iface |= 0x0001;
 
430
                break;
 
431
        case SND_SOC_DAIFMT_DSP_A:
 
432
                iface |= 0x0013;
 
433
                break;
 
434
        case SND_SOC_DAIFMT_DSP_B:
 
435
                iface |= 0x0003;
 
436
                break;
 
437
        default:
 
438
                return -EINVAL;
 
439
        }
 
440
 
 
441
        /* clock inversion */
 
442
        switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
 
443
        case SND_SOC_DAIFMT_NB_NF:
 
444
                break;
 
445
        case SND_SOC_DAIFMT_IB_IF:
 
446
                iface |= 0x0090;
 
447
                break;
 
448
        case SND_SOC_DAIFMT_IB_NF:
 
449
                iface |= 0x0080;
 
450
                break;
 
451
        case SND_SOC_DAIFMT_NB_IF:
 
452
                iface |= 0x0010;
 
453
                break;
 
454
        default:
 
455
                return -EINVAL;
 
456
        }
 
457
 
 
458
        /* set iface */
 
459
        snd_soc_write(codec, SSM2602_IFACE, iface);
 
460
        return 0;
 
461
}
 
462
 
 
463
static int ssm2602_set_bias_level(struct snd_soc_codec *codec,
 
464
                                 enum snd_soc_bias_level level)
 
465
{
 
466
        struct ssm2602_priv *ssm2602 = snd_soc_codec_get_drvdata(codec);
 
467
 
 
468
        switch (level) {
 
469
        case SND_SOC_BIAS_ON:
 
470
                /* vref/mid on, osc and clkout on if enabled */
 
471
                snd_soc_update_bits(codec, SSM2602_PWR,
 
472
                        PWR_POWER_OFF | PWR_CLK_OUT_PDN | PWR_OSC_PDN,
 
473
                        ssm2602->clk_out_pwr);
 
474
                break;
 
475
        case SND_SOC_BIAS_PREPARE:
 
476
                break;
 
477
        case SND_SOC_BIAS_STANDBY:
 
478
                /* everything off except vref/vmid, */
 
479
                snd_soc_update_bits(codec, SSM2602_PWR,
 
480
                        PWR_POWER_OFF | PWR_CLK_OUT_PDN | PWR_OSC_PDN,
 
481
                        PWR_CLK_OUT_PDN | PWR_OSC_PDN);
 
482
                break;
 
483
        case SND_SOC_BIAS_OFF:
 
484
                /* everything off */
 
485
                snd_soc_update_bits(codec, SSM2602_PWR,
 
486
                        PWR_POWER_OFF, PWR_POWER_OFF);
 
487
                break;
 
488
 
 
489
        }
 
490
        codec->dapm.bias_level = level;
 
491
        return 0;
 
492
}
 
493
 
 
494
#define SSM2602_RATES (SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_32000 |\
 
495
                SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000 |\
 
496
                SNDRV_PCM_RATE_88200 | SNDRV_PCM_RATE_96000)
 
497
 
 
498
#define SSM2602_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE |\
 
499
                SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S32_LE)
 
500
 
 
501
static struct snd_soc_dai_ops ssm2602_dai_ops = {
 
502
        .startup        = ssm2602_startup,
 
503
        .hw_params      = ssm2602_hw_params,
 
504
        .shutdown       = ssm2602_shutdown,
 
505
        .digital_mute   = ssm2602_mute,
 
506
        .set_sysclk     = ssm2602_set_dai_sysclk,
 
507
        .set_fmt        = ssm2602_set_dai_fmt,
 
508
};
 
509
 
 
510
static struct snd_soc_dai_driver ssm2602_dai = {
 
511
        .name = "ssm2602-hifi",
 
512
        .playback = {
 
513
                .stream_name = "Playback",
 
514
                .channels_min = 2,
 
515
                .channels_max = 2,
 
516
                .rates = SSM2602_RATES,
 
517
                .formats = SSM2602_FORMATS,},
 
518
        .capture = {
 
519
                .stream_name = "Capture",
 
520
                .channels_min = 2,
 
521
                .channels_max = 2,
 
522
                .rates = SSM2602_RATES,
 
523
                .formats = SSM2602_FORMATS,},
 
524
        .ops = &ssm2602_dai_ops,
 
525
};
 
526
 
 
527
static int ssm2602_suspend(struct snd_soc_codec *codec, pm_message_t state)
 
528
{
 
529
        ssm2602_set_bias_level(codec, SND_SOC_BIAS_OFF);
 
530
        return 0;
 
531
}
 
532
 
 
533
static int ssm2602_resume(struct snd_soc_codec *codec)
 
534
{
 
535
        snd_soc_cache_sync(codec);
 
536
 
 
537
        ssm2602_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
 
538
 
 
539
        return 0;
 
540
}
 
541
 
 
542
static int ssm2602_probe(struct snd_soc_codec *codec)
 
543
{
 
544
        struct snd_soc_dapm_context *dapm = &codec->dapm;
 
545
        int ret;
 
546
 
 
547
        snd_soc_update_bits(codec, SSM2602_LOUT1V,
 
548
                            LOUT1V_LRHP_BOTH, LOUT1V_LRHP_BOTH);
 
549
        snd_soc_update_bits(codec, SSM2602_ROUT1V,
 
550
                            ROUT1V_RLHP_BOTH, ROUT1V_RLHP_BOTH);
 
551
 
 
552
        ret = snd_soc_add_controls(codec, ssm2602_snd_controls,
 
553
                        ARRAY_SIZE(ssm2602_snd_controls));
 
554
        if (ret)
 
555
                return ret;
 
556
 
 
557
        ret = snd_soc_dapm_new_controls(dapm, ssm2602_dapm_widgets,
 
558
                        ARRAY_SIZE(ssm2602_dapm_widgets));
 
559
        if (ret)
 
560
                return ret;
 
561
 
 
562
        return snd_soc_dapm_add_routes(dapm, ssm2602_routes,
 
563
                        ARRAY_SIZE(ssm2602_routes));
 
564
}
 
565
 
 
566
static int ssm2604_probe(struct snd_soc_codec *codec)
 
567
{
 
568
        struct snd_soc_dapm_context *dapm = &codec->dapm;
 
569
        int ret;
 
570
 
 
571
        ret = snd_soc_dapm_new_controls(dapm, ssm2604_dapm_widgets,
 
572
                        ARRAY_SIZE(ssm2604_dapm_widgets));
 
573
        if (ret)
 
574
                return ret;
 
575
 
 
576
        return snd_soc_dapm_add_routes(dapm, ssm2604_routes,
 
577
                        ARRAY_SIZE(ssm2604_routes));
 
578
}
 
579
 
 
580
static int ssm260x_probe(struct snd_soc_codec *codec)
 
581
{
 
582
        struct ssm2602_priv *ssm2602 = snd_soc_codec_get_drvdata(codec);
 
583
        int ret;
 
584
 
 
585
        pr_info("ssm2602 Audio Codec %s", SSM2602_VERSION);
 
586
 
 
587
        ret = snd_soc_codec_set_cache_io(codec, 7, 9, ssm2602->control_type);
 
588
        if (ret < 0) {
 
589
                dev_err(codec->dev, "Failed to set cache I/O: %d\n", ret);
 
590
                return ret;
 
591
        }
 
592
 
 
593
        ret = ssm2602_reset(codec);
 
594
        if (ret < 0) {
 
595
                dev_err(codec->dev, "Failed to issue reset: %d\n", ret);
 
596
                return ret;
 
597
        }
 
598
 
 
599
        /* set the update bits */
 
600
        snd_soc_update_bits(codec, SSM2602_LINVOL,
 
601
                            LINVOL_LRIN_BOTH, LINVOL_LRIN_BOTH);
 
602
        snd_soc_update_bits(codec, SSM2602_RINVOL,
 
603
                            RINVOL_RLIN_BOTH, RINVOL_RLIN_BOTH);
 
604
        /*select Line in as default input*/
 
605
        snd_soc_write(codec, SSM2602_APANA, APANA_SELECT_DAC |
 
606
                        APANA_ENABLE_MIC_BOOST);
 
607
 
 
608
        switch (ssm2602->type) {
 
609
        case SSM2602:
 
610
                ret = ssm2602_probe(codec);
 
611
                break;
 
612
        case SSM2604:
 
613
                ret = ssm2604_probe(codec);
 
614
                break;
 
615
        }
 
616
 
 
617
        if (ret)
 
618
                return ret;
 
619
 
 
620
        ssm2602_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
 
621
 
 
622
        return 0;
 
623
}
 
624
 
 
625
/* remove everything here */
 
626
static int ssm2602_remove(struct snd_soc_codec *codec)
 
627
{
 
628
        ssm2602_set_bias_level(codec, SND_SOC_BIAS_OFF);
 
629
        return 0;
 
630
}
 
631
 
 
632
static struct snd_soc_codec_driver soc_codec_dev_ssm2602 = {
 
633
        .probe =        ssm260x_probe,
 
634
        .remove =       ssm2602_remove,
 
635
        .suspend =      ssm2602_suspend,
 
636
        .resume =       ssm2602_resume,
 
637
        .set_bias_level = ssm2602_set_bias_level,
 
638
        .reg_cache_size = ARRAY_SIZE(ssm2602_reg),
 
639
        .reg_word_size = sizeof(u16),
 
640
        .reg_cache_default = ssm2602_reg,
 
641
 
 
642
        .controls = ssm260x_snd_controls,
 
643
        .num_controls = ARRAY_SIZE(ssm260x_snd_controls),
 
644
        .dapm_widgets = ssm260x_dapm_widgets,
 
645
        .num_dapm_widgets = ARRAY_SIZE(ssm260x_dapm_widgets),
 
646
        .dapm_routes = ssm260x_routes,
 
647
        .num_dapm_routes = ARRAY_SIZE(ssm260x_routes),
 
648
};
 
649
 
 
650
#if defined(CONFIG_SPI_MASTER)
 
651
static int __devinit ssm2602_spi_probe(struct spi_device *spi)
 
652
{
 
653
        struct ssm2602_priv *ssm2602;
 
654
        int ret;
 
655
 
 
656
        ssm2602 = kzalloc(sizeof(struct ssm2602_priv), GFP_KERNEL);
 
657
        if (ssm2602 == NULL)
 
658
                return -ENOMEM;
 
659
 
 
660
        spi_set_drvdata(spi, ssm2602);
 
661
        ssm2602->control_type = SND_SOC_SPI;
 
662
        ssm2602->type = SSM2602;
 
663
 
 
664
        ret = snd_soc_register_codec(&spi->dev,
 
665
                        &soc_codec_dev_ssm2602, &ssm2602_dai, 1);
 
666
        if (ret < 0)
 
667
                kfree(ssm2602);
 
668
        return ret;
 
669
}
 
670
 
 
671
static int __devexit ssm2602_spi_remove(struct spi_device *spi)
 
672
{
 
673
        snd_soc_unregister_codec(&spi->dev);
 
674
        kfree(spi_get_drvdata(spi));
 
675
        return 0;
 
676
}
 
677
 
 
678
static struct spi_driver ssm2602_spi_driver = {
 
679
        .driver = {
 
680
                .name   = "ssm2602",
 
681
                .owner  = THIS_MODULE,
 
682
        },
 
683
        .probe          = ssm2602_spi_probe,
 
684
        .remove         = __devexit_p(ssm2602_spi_remove),
 
685
};
 
686
#endif
 
687
 
 
688
#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
 
689
/*
 
690
 * ssm2602 2 wire address is determined by GPIO5
 
691
 * state during powerup.
 
692
 *    low  = 0x1a
 
693
 *    high = 0x1b
 
694
 */
 
695
static int __devinit ssm2602_i2c_probe(struct i2c_client *i2c,
 
696
                             const struct i2c_device_id *id)
 
697
{
 
698
        struct ssm2602_priv *ssm2602;
 
699
        int ret;
 
700
 
 
701
        ssm2602 = kzalloc(sizeof(struct ssm2602_priv), GFP_KERNEL);
 
702
        if (ssm2602 == NULL)
 
703
                return -ENOMEM;
 
704
 
 
705
        i2c_set_clientdata(i2c, ssm2602);
 
706
        ssm2602->control_type = SND_SOC_I2C;
 
707
        ssm2602->type = id->driver_data;
 
708
 
 
709
        ret = snd_soc_register_codec(&i2c->dev,
 
710
                        &soc_codec_dev_ssm2602, &ssm2602_dai, 1);
 
711
        if (ret < 0)
 
712
                kfree(ssm2602);
 
713
        return ret;
 
714
}
 
715
 
 
716
static int __devexit ssm2602_i2c_remove(struct i2c_client *client)
 
717
{
 
718
        snd_soc_unregister_codec(&client->dev);
 
719
        kfree(i2c_get_clientdata(client));
 
720
        return 0;
 
721
}
 
722
 
 
723
static const struct i2c_device_id ssm2602_i2c_id[] = {
 
724
        { "ssm2602", SSM2602 },
 
725
        { "ssm2603", SSM2602 },
 
726
        { "ssm2604", SSM2604 },
 
727
        { }
 
728
};
 
729
MODULE_DEVICE_TABLE(i2c, ssm2602_i2c_id);
 
730
 
 
731
/* corgi i2c codec control layer */
 
732
static struct i2c_driver ssm2602_i2c_driver = {
 
733
        .driver = {
 
734
                .name = "ssm2602",
 
735
                .owner = THIS_MODULE,
 
736
        },
 
737
        .probe = ssm2602_i2c_probe,
 
738
        .remove = __devexit_p(ssm2602_i2c_remove),
 
739
        .id_table = ssm2602_i2c_id,
 
740
};
 
741
#endif
 
742
 
 
743
 
 
744
static int __init ssm2602_modinit(void)
 
745
{
 
746
        int ret = 0;
 
747
 
 
748
#if defined(CONFIG_SPI_MASTER)
 
749
        ret = spi_register_driver(&ssm2602_spi_driver);
 
750
        if (ret)
 
751
                return ret;
 
752
#endif
 
753
 
 
754
#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
 
755
        ret = i2c_add_driver(&ssm2602_i2c_driver);
 
756
        if (ret)
 
757
                return ret;
 
758
#endif
 
759
 
 
760
        return ret;
 
761
}
 
762
module_init(ssm2602_modinit);
 
763
 
 
764
static void __exit ssm2602_exit(void)
 
765
{
 
766
#if defined(CONFIG_SPI_MASTER)
 
767
        spi_unregister_driver(&ssm2602_spi_driver);
 
768
#endif
 
769
 
 
770
#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
 
771
        i2c_del_driver(&ssm2602_i2c_driver);
 
772
#endif
 
773
}
 
774
module_exit(ssm2602_exit);
 
775
 
 
776
MODULE_DESCRIPTION("ASoC SSM2602/SSM2603/SSM2604 driver");
 
777
MODULE_AUTHOR("Cliff Cai");
 
778
MODULE_LICENSE("GPL");