~ubuntu-branches/debian/wheezy/linux-2.6/wheezy

« back to all changes in this revision

Viewing changes to sound/soc/sh/migor.c

  • Committer: Bazaar Package Importer
  • Author(s): Ben Hutchings, Ben Hutchings, Aurelien Jarno, Martin Michlmayr
  • Date: 2011-04-06 13:53:30 UTC
  • mfrom: (43.1.5 sid)
  • Revision ID: james.westby@ubuntu.com-20110406135330-wjufxhd0tvn3zx4z
Tags: 2.6.38-3
[ Ben Hutchings ]
* [ppc64] Add to linux-tools package architectures (Closes: #620124)
* [amd64] Save cr4 to mmu_cr4_features at boot time (Closes: #620284)
* appletalk: Fix bugs introduced when removing use of BKL
* ALSA: Fix yet another race in disconnection
* cciss: Fix lost command issue
* ath9k: Fix kernel panic in AR2427
* ses: Avoid kernel panic when lun 0 is not mapped
* PCI/ACPI: Report ASPM support to BIOS if not disabled from command line

[ Aurelien Jarno ]
* rtlwifi: fix build when PCI is not enabled.

[ Martin Michlmayr ]
* rtlwifi: Eliminate udelay calls with too large values (Closes: #620204)

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
 * ALSA SoC driver for Migo-R
 
3
 *
 
4
 * Copyright (C) 2009-2010 Guennadi Liakhovetski <g.liakhovetski@gmx.de>
 
5
 *
 
6
 * This program is free software; you can redistribute it and/or modify
 
7
 * it under the terms of the GNU General Public License version 2 as
 
8
 * published by the Free Software Foundation.
 
9
 */
 
10
 
 
11
#include <linux/clkdev.h>
 
12
#include <linux/device.h>
 
13
#include <linux/firmware.h>
 
14
#include <linux/module.h>
 
15
 
 
16
#include <asm/clock.h>
 
17
 
 
18
#include <cpu/sh7722.h>
 
19
 
 
20
#include <sound/core.h>
 
21
#include <sound/pcm.h>
 
22
#include <sound/soc.h>
 
23
 
 
24
#include "../codecs/wm8978.h"
 
25
#include "siu.h"
 
26
 
 
27
/* Default 8000Hz sampling frequency */
 
28
static unsigned long codec_freq = 8000 * 512;
 
29
 
 
30
static unsigned int use_count;
 
31
 
 
32
/* External clock, sourced from the codec at the SIUMCKB pin */
 
33
static unsigned long siumckb_recalc(struct clk *clk)
 
34
{
 
35
        return codec_freq;
 
36
}
 
37
 
 
38
static struct clk_ops siumckb_clk_ops = {
 
39
        .recalc = siumckb_recalc,
 
40
};
 
41
 
 
42
static struct clk siumckb_clk = {
 
43
        .ops            = &siumckb_clk_ops,
 
44
        .rate           = 0, /* initialised at run-time */
 
45
};
 
46
 
 
47
static struct clk_lookup *siumckb_lookup;
 
48
 
 
49
static int migor_hw_params(struct snd_pcm_substream *substream,
 
50
                           struct snd_pcm_hw_params *params)
 
51
{
 
52
        struct snd_soc_pcm_runtime *rtd = substream->private_data;
 
53
        struct snd_soc_dai *codec_dai = rtd->codec_dai;
 
54
        int ret;
 
55
        unsigned int rate = params_rate(params);
 
56
 
 
57
        ret = snd_soc_dai_set_sysclk(codec_dai, WM8978_PLL, 13000000,
 
58
                                     SND_SOC_CLOCK_IN);
 
59
        if (ret < 0)
 
60
                return ret;
 
61
 
 
62
        ret = snd_soc_dai_set_clkdiv(codec_dai, WM8978_OPCLKRATE, rate * 512);
 
63
        if (ret < 0)
 
64
                return ret;
 
65
 
 
66
        ret = snd_soc_dai_set_fmt(codec_dai, SND_SOC_DAIFMT_NB_IF |
 
67
                                  SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_CBS_CFS);
 
68
        if (ret < 0)
 
69
                return ret;
 
70
 
 
71
        ret = snd_soc_dai_set_fmt(rtd->cpu_dai, SND_SOC_DAIFMT_NB_IF |
 
72
                                  SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_CBS_CFS);
 
73
        if (ret < 0)
 
74
                return ret;
 
75
 
 
76
        codec_freq = rate * 512;
 
77
        /*
 
78
         * This propagates the parent frequency change to children and
 
79
         * recalculates the frequency table
 
80
         */
 
81
        clk_set_rate(&siumckb_clk, codec_freq);
 
82
        dev_dbg(codec_dai->dev, "%s: configure %luHz\n", __func__, codec_freq);
 
83
 
 
84
        ret = snd_soc_dai_set_sysclk(rtd->cpu_dai, SIU_CLKB_EXT,
 
85
                                     codec_freq / 2, SND_SOC_CLOCK_IN);
 
86
 
 
87
        if (!ret)
 
88
                use_count++;
 
89
 
 
90
        return ret;
 
91
}
 
92
 
 
93
static int migor_hw_free(struct snd_pcm_substream *substream)
 
94
{
 
95
        struct snd_soc_pcm_runtime *rtd = substream->private_data;
 
96
        struct snd_soc_dai *codec_dai = rtd->codec_dai;
 
97
 
 
98
        if (use_count) {
 
99
                use_count--;
 
100
 
 
101
                if (!use_count)
 
102
                        snd_soc_dai_set_sysclk(codec_dai, WM8978_PLL, 0,
 
103
                                               SND_SOC_CLOCK_IN);
 
104
        } else {
 
105
                dev_dbg(codec_dai->dev, "Unbalanced hw_free!\n");
 
106
        }
 
107
 
 
108
        return 0;
 
109
}
 
110
 
 
111
static struct snd_soc_ops migor_dai_ops = {
 
112
        .hw_params = migor_hw_params,
 
113
        .hw_free = migor_hw_free,
 
114
};
 
115
 
 
116
static const struct snd_soc_dapm_widget migor_dapm_widgets[] = {
 
117
        SND_SOC_DAPM_HP("Headphone", NULL),
 
118
        SND_SOC_DAPM_MIC("Onboard Microphone", NULL),
 
119
        SND_SOC_DAPM_MIC("External Microphone", NULL),
 
120
};
 
121
 
 
122
static const struct snd_soc_dapm_route audio_map[] = {
 
123
        /* Headphone output connected to LHP/RHP, enable OUT4 for VMID */
 
124
        { "Headphone", NULL,  "OUT4 VMID" },
 
125
        { "OUT4 VMID", NULL,  "LHP" },
 
126
        { "OUT4 VMID", NULL,  "RHP" },
 
127
 
 
128
        /* On-board microphone */
 
129
        { "RMICN", NULL, "Mic Bias" },
 
130
        { "RMICP", NULL, "Mic Bias" },
 
131
        { "Mic Bias", NULL, "Onboard Microphone" },
 
132
 
 
133
        /* External microphone */
 
134
        { "LMICN", NULL, "Mic Bias" },
 
135
        { "LMICP", NULL, "Mic Bias" },
 
136
        { "Mic Bias", NULL, "External Microphone" },
 
137
};
 
138
 
 
139
static int migor_dai_init(struct snd_soc_pcm_runtime *rtd)
 
140
{
 
141
        struct snd_soc_codec *codec = rtd->codec;
 
142
        struct snd_soc_dapm_context *dapm = &codec->dapm;
 
143
 
 
144
        snd_soc_dapm_new_controls(dapm, migor_dapm_widgets,
 
145
                                  ARRAY_SIZE(migor_dapm_widgets));
 
146
 
 
147
        snd_soc_dapm_add_routes(dapm, audio_map, ARRAY_SIZE(audio_map));
 
148
 
 
149
        return 0;
 
150
}
 
151
 
 
152
/* migor digital audio interface glue - connects codec <--> CPU */
 
153
static struct snd_soc_dai_link migor_dai = {
 
154
        .name = "wm8978",
 
155
        .stream_name = "WM8978",
 
156
        .cpu_dai_name = "siu-i2s-dai",
 
157
        .codec_dai_name = "wm8978-hifi",
 
158
        .platform_name = "siu-pcm-audio",
 
159
        .codec_name = "wm8978.0-001a",
 
160
        .ops = &migor_dai_ops,
 
161
        .init = migor_dai_init,
 
162
};
 
163
 
 
164
/* migor audio machine driver */
 
165
static struct snd_soc_card snd_soc_migor = {
 
166
        .name = "Migo-R",
 
167
        .dai_link = &migor_dai,
 
168
        .num_links = 1,
 
169
};
 
170
 
 
171
static struct platform_device *migor_snd_device;
 
172
 
 
173
static int __init migor_init(void)
 
174
{
 
175
        int ret;
 
176
 
 
177
        ret = clk_register(&siumckb_clk);
 
178
        if (ret < 0)
 
179
                return ret;
 
180
 
 
181
        siumckb_lookup = clkdev_alloc(&siumckb_clk, "siumckb_clk", NULL);
 
182
        if (!siumckb_lookup) {
 
183
                ret = -ENOMEM;
 
184
                goto eclkdevalloc;
 
185
        }
 
186
        clkdev_add(siumckb_lookup);
 
187
 
 
188
        /* Port number used on this machine: port B */
 
189
        migor_snd_device = platform_device_alloc("soc-audio", 1);
 
190
        if (!migor_snd_device) {
 
191
                ret = -ENOMEM;
 
192
                goto epdevalloc;
 
193
        }
 
194
 
 
195
        platform_set_drvdata(migor_snd_device, &snd_soc_migor);
 
196
 
 
197
        ret = platform_device_add(migor_snd_device);
 
198
        if (ret)
 
199
                goto epdevadd;
 
200
 
 
201
        return 0;
 
202
 
 
203
epdevadd:
 
204
        platform_device_put(migor_snd_device);
 
205
epdevalloc:
 
206
        clkdev_drop(siumckb_lookup);
 
207
eclkdevalloc:
 
208
        clk_unregister(&siumckb_clk);
 
209
        return ret;
 
210
}
 
211
 
 
212
static void __exit migor_exit(void)
 
213
{
 
214
        clkdev_drop(siumckb_lookup);
 
215
        clk_unregister(&siumckb_clk);
 
216
        platform_device_unregister(migor_snd_device);
 
217
}
 
218
 
 
219
module_init(migor_init);
 
220
module_exit(migor_exit);
 
221
 
 
222
MODULE_AUTHOR("Guennadi Liakhovetski <g.liakhovetski@gmx.de>");
 
223
MODULE_DESCRIPTION("ALSA SoC Migor");
 
224
MODULE_LICENSE("GPL v2");