blob: cbe09f2bde39dc7403c0758b53440a21ec4869ef [file] [log] [blame]
Vinod Koulfffa1cc2010-10-05 16:25:17 +01001/*
2 * intelmid.c - Intel Sound card driver for MID
3 *
4 * Copyright (C) 2008-10 Intel Corp
5 * Authors: Harsha Priya <priya.harsha@intel.com>
6 * Vinod Koul <vinod.koul@intel.com>
7 * Dharageswari R <dharageswari.r@intel.com>
8 * KP Jeeja <jeeja.kp@intel.com>
9 * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
10 *
11 * This program is free software; you can redistribute it and/or modify
12 * it under the terms of the GNU General Public License as published by
13 * the Free Software Foundation; version 2 of the License.
14 *
15 * This program is distributed in the hope that it will be useful, but
16 * WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
18 * General Public License for more details.
19 *
20 * You should have received a copy of the GNU General Public License along
21 * with this program; if not, write to the Free Software Foundation, Inc.,
22 * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
23 *
24 * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
25 * ALSA driver for Intel MID sound card chipset
26 */
Joe Perchesd0f40c52010-10-20 18:51:06 -070027
28#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
29
Vinod Koulfffa1cc2010-10-05 16:25:17 +010030#include <linux/slab.h>
31#include <linux/io.h>
32#include <linux/platform_device.h>
33#include <linux/interrupt.h>
34#include <linux/sched.h>
Lu Guanqun6c550052011-04-08 08:41:38 +080035#include <linux/firmware.h>
Ramesh Babu K V8a251ff2011-05-03 17:33:13 +010036#include <linux/input.h>
Vinod Koulfffa1cc2010-10-05 16:25:17 +010037#include <sound/control.h>
38#include <asm/mrst.h>
39#include <sound/pcm.h>
Ramesh Babu K V8a251ff2011-05-03 17:33:13 +010040#include <sound/jack.h>
Vinod Koulfffa1cc2010-10-05 16:25:17 +010041#include <sound/pcm_params.h>
42#include <sound/initval.h>
43#include "intel_sst.h"
44#include "intel_sst_ioctl.h"
Lu Guanqun6c550052011-04-08 08:41:38 +080045#include "intel_sst_fw_ipc.h"
46#include "intel_sst_common.h"
Vinod Koulfffa1cc2010-10-05 16:25:17 +010047#include "intelmid_snd_control.h"
Ramesh Babu K V8a251ff2011-05-03 17:33:13 +010048#include "intelmid_adc_control.h"
Vinod Koulfffa1cc2010-10-05 16:25:17 +010049#include "intelmid.h"
50
51MODULE_AUTHOR("Vinod Koul <vinod.koul@intel.com>");
52MODULE_AUTHOR("Harsha Priya <priya.harsha@intel.com>");
53MODULE_AUTHOR("Dharageswari R <dharageswari.r@intel.com>");
54MODULE_AUTHOR("KP Jeeja <jeeja.kp@intel.com>");
55MODULE_DESCRIPTION("Intel MAD Sound card driver");
56MODULE_LICENSE("GPL v2");
57MODULE_SUPPORTED_DEVICE("{Intel,Intel_MAD}");
58
59
60static int card_index = SNDRV_DEFAULT_IDX1;/* Index 0-MAX */
61static char *card_id = SNDRV_DEFAULT_STR1; /* ID for this card */
62
63module_param(card_index, int, 0444);
64MODULE_PARM_DESC(card_index, "Index value for INTELMAD soundcard.");
65module_param(card_id, charp, 0444);
66MODULE_PARM_DESC(card_id, "ID string for INTELMAD soundcard.");
67
68int sst_card_vendor_id;
69int intelmid_audio_interrupt_enable;/*checkpatch fix*/
Ramesh Babu K V8a251ff2011-05-03 17:33:13 +010070struct snd_intelmad *intelmad_drv;
Vinod Koulfffa1cc2010-10-05 16:25:17 +010071
Ramesh Babu K V8a251ff2011-05-03 17:33:13 +010072#define INFO(_cpu_id, _irq_cache, _size) \
73 ((kernel_ulong_t)&(struct snd_intelmad_probe_info) { \
74 .cpu_id = (_cpu_id), \
75 .irq_cache = (_irq_cache), \
76 .size = (_size), \
77 })
Vinod Koulfffa1cc2010-10-05 16:25:17 +010078/* Data path functionalities */
79static struct snd_pcm_hardware snd_intelmad_stream = {
80 .info = (SNDRV_PCM_INFO_INTERLEAVED |
81 SNDRV_PCM_INFO_DOUBLE |
82 SNDRV_PCM_INFO_PAUSE |
83 SNDRV_PCM_INFO_RESUME |
84 SNDRV_PCM_INFO_MMAP|
85 SNDRV_PCM_INFO_MMAP_VALID |
86 SNDRV_PCM_INFO_BLOCK_TRANSFER |
87 SNDRV_PCM_INFO_SYNC_START),
88 .formats = (SNDRV_PCM_FMTBIT_S16 | SNDRV_PCM_FMTBIT_U16 |
89 SNDRV_PCM_FMTBIT_S24 | SNDRV_PCM_FMTBIT_U24 |
90 SNDRV_PCM_FMTBIT_S32 | SNDRV_PCM_FMTBIT_U32),
91 .rates = (SNDRV_PCM_RATE_8000|
92 SNDRV_PCM_RATE_44100 |
93 SNDRV_PCM_RATE_48000),
94 .rate_min = MIN_RATE,
95
96 .rate_max = MAX_RATE,
97 .channels_min = MIN_CHANNEL,
98 .channels_max = MAX_CHANNEL_AMIC,
99 .buffer_bytes_max = MAX_BUFFER,
100 .period_bytes_min = MIN_PERIOD_BYTES,
101 .period_bytes_max = MAX_PERIOD_BYTES,
102 .periods_min = MIN_PERIODS,
103 .periods_max = MAX_PERIODS,
104 .fifo_size = FIFO_SIZE,
105};
106
107
108/**
109 * snd_intelmad_pcm_trigger - stream activities are handled here
110 *
111 * @substream:substream for which the stream function is called
112 * @cmd:the stream commamd that requested from upper layer
113 *
114 * This function is called whenever an a stream activity is invoked
115 */
116static int snd_intelmad_pcm_trigger(struct snd_pcm_substream *substream,
117 int cmd)
118{
Vinod Koul6f6ffec2010-11-19 15:06:31 +0000119 int ret_val = 0, str_id;
Vinod Koulfffa1cc2010-10-05 16:25:17 +0100120 struct snd_intelmad *intelmaddata;
121 struct mad_stream_pvt *stream;
Vinod Koul6f6ffec2010-11-19 15:06:31 +0000122 struct intel_sst_pcm_control *sst_ops;
Vinod Koulfffa1cc2010-10-05 16:25:17 +0100123
124 WARN_ON(!substream);
125
126 intelmaddata = snd_pcm_substream_chip(substream);
127 stream = substream->runtime->private_data;
128
129 WARN_ON(!intelmaddata->sstdrv_ops);
130 WARN_ON(!intelmaddata->sstdrv_ops->scard_ops);
Vinod Koul6f6ffec2010-11-19 15:06:31 +0000131 sst_ops = intelmaddata->sstdrv_ops->pcm_control;
132 str_id = stream->stream_info.str_id;
Vinod Koulfffa1cc2010-10-05 16:25:17 +0100133
134 switch (cmd) {
135 case SNDRV_PCM_TRIGGER_START:
Joe Perchesd0f40c52010-10-20 18:51:06 -0700136 pr_debug("Trigger Start\n");
Vinod Koul6f6ffec2010-11-19 15:06:31 +0000137 ret_val = sst_ops->device_control(SST_SND_START, &str_id);
Vinod Koulfffa1cc2010-10-05 16:25:17 +0100138 if (ret_val)
139 return ret_val;
140 stream->stream_status = RUNNING;
141 stream->substream = substream;
Vinod Koulfffa1cc2010-10-05 16:25:17 +0100142 break;
143 case SNDRV_PCM_TRIGGER_STOP:
Joe Perchesd0f40c52010-10-20 18:51:06 -0700144 pr_debug("in stop\n");
Vinod Koul6f6ffec2010-11-19 15:06:31 +0000145 ret_val = sst_ops->device_control(SST_SND_DROP, &str_id);
Vinod Koulfffa1cc2010-10-05 16:25:17 +0100146 if (ret_val)
147 return ret_val;
148 stream->stream_status = DROPPED;
149 break;
150 case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
Joe Perchesd0f40c52010-10-20 18:51:06 -0700151 pr_debug("in pause\n");
Vinod Koul6f6ffec2010-11-19 15:06:31 +0000152 ret_val = sst_ops->device_control(SST_SND_PAUSE, &str_id);
Vinod Koulfffa1cc2010-10-05 16:25:17 +0100153 if (ret_val)
154 return ret_val;
155 stream->stream_status = PAUSED;
156 break;
157 case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
Joe Perchesd0f40c52010-10-20 18:51:06 -0700158 pr_debug("in pause release\n");
Vinod Koul6f6ffec2010-11-19 15:06:31 +0000159 ret_val = sst_ops->device_control(SST_SND_RESUME, &str_id);
Vinod Koulfffa1cc2010-10-05 16:25:17 +0100160 if (ret_val)
161 return ret_val;
162 stream->stream_status = RUNNING;
163 break;
164 default:
165 return -EINVAL;
166 }
167 return ret_val;
168}
169
170/**
171* snd_intelmad_pcm_prepare- internal preparation before starting a stream
172*
173* @substream: substream for which the function is called
174*
175* This function is called when a stream is started for internal preparation.
176*/
177static int snd_intelmad_pcm_prepare(struct snd_pcm_substream *substream)
178{
179 struct mad_stream_pvt *stream;
180 int ret_val = 0;
181 struct snd_intelmad *intelmaddata;
182
Joe Perchesd0f40c52010-10-20 18:51:06 -0700183 pr_debug("pcm_prepare called\n");
Vinod Koulfffa1cc2010-10-05 16:25:17 +0100184
185 WARN_ON(!substream);
186 stream = substream->runtime->private_data;
187 intelmaddata = snd_pcm_substream_chip(substream);
Joe Perchesd0f40c52010-10-20 18:51:06 -0700188 pr_debug("pb cnt = %d cap cnt = %d\n",\
Vinod Koulfffa1cc2010-10-05 16:25:17 +0100189 intelmaddata->playback_cnt,
190 intelmaddata->capture_cnt);
191
192 if (stream->stream_info.str_id) {
Joe Perchesd0f40c52010-10-20 18:51:06 -0700193 pr_debug("Prepare called for already set stream\n");
Vinod Koul6f6ffec2010-11-19 15:06:31 +0000194 ret_val = intelmaddata->sstdrv_ops->pcm_control->device_control(
195 SST_SND_DROP, &stream->stream_info.str_id);
Vinod Koulfffa1cc2010-10-05 16:25:17 +0100196 return ret_val;
197 }
198
Dharageswari R5572a442011-05-03 17:32:38 +0100199 ret_val = snd_intelmad_alloc_stream(substream);
Vinod Koulfffa1cc2010-10-05 16:25:17 +0100200 if (ret_val < 0)
201 return ret_val;
202 stream->dbg_cum_bytes = 0;
203 if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
204 intelmaddata->playback_cnt++;
205 else
206 intelmaddata->capture_cnt++;
207 /* return back the stream id */
208 snprintf(substream->pcm->id, sizeof(substream->pcm->id),
209 "%d", stream->stream_info.str_id);
Joe Perchesd0f40c52010-10-20 18:51:06 -0700210 pr_debug("stream id to user = %s\n",
Vinod Koulfffa1cc2010-10-05 16:25:17 +0100211 substream->pcm->id);
212
213 ret_val = snd_intelmad_init_stream(substream);
214 if (ret_val)
215 return ret_val;
216 substream->runtime->hw.info = SNDRV_PCM_INFO_BLOCK_TRANSFER;
217 return ret_val;
218}
219
220static int snd_intelmad_hw_params(struct snd_pcm_substream *substream,
221 struct snd_pcm_hw_params *hw_params)
222{
223 int ret_val;
224
Joe Perchesd0f40c52010-10-20 18:51:06 -0700225 pr_debug("snd_intelmad_hw_params called\n");
Vinod Koulfffa1cc2010-10-05 16:25:17 +0100226 ret_val = snd_pcm_lib_malloc_pages(substream,
227 params_buffer_bytes(hw_params));
228 memset(substream->runtime->dma_area, 0,
229 params_buffer_bytes(hw_params));
230
231 return ret_val;
232}
233
234static int snd_intelmad_hw_free(struct snd_pcm_substream *substream)
235{
Joe Perchesd0f40c52010-10-20 18:51:06 -0700236 pr_debug("snd_intelmad_hw_free called\n");
Vinod Koulfffa1cc2010-10-05 16:25:17 +0100237 return snd_pcm_lib_free_pages(substream);
238}
239
240/**
241 * snd_intelmad_pcm_pointer- to send the current buffer pointer processed by hw
242 *
243 * @substream: substream for which the function is called
244 *
245 * This function is called by ALSA framework to get the current hw buffer ptr
246 * when a period is elapsed
247 */
248static snd_pcm_uframes_t snd_intelmad_pcm_pointer
249 (struct snd_pcm_substream *substream)
250{
251 /* struct snd_pcm_runtime *runtime = substream->runtime; */
252 struct mad_stream_pvt *stream;
253 struct snd_intelmad *intelmaddata;
254 int ret_val;
255
256 WARN_ON(!substream);
257
258 intelmaddata = snd_pcm_substream_chip(substream);
259 stream = substream->runtime->private_data;
260 if (stream->stream_status == INIT)
261 return 0;
262
Vinod Koul6f6ffec2010-11-19 15:06:31 +0000263 ret_val = intelmaddata->sstdrv_ops->pcm_control->device_control(
264 SST_SND_BUFFER_POINTER, &stream->stream_info);
Vinod Koulfffa1cc2010-10-05 16:25:17 +0100265 if (ret_val) {
Joe Perchesd0f40c52010-10-20 18:51:06 -0700266 pr_err("error code = 0x%x\n", ret_val);
Vinod Koulfffa1cc2010-10-05 16:25:17 +0100267 return ret_val;
268 }
Joe Perchesd0f40c52010-10-20 18:51:06 -0700269 pr_debug("samples reported out 0x%llx\n",
Vinod Koulfffa1cc2010-10-05 16:25:17 +0100270 stream->stream_info.buffer_ptr);
Joe Perchesd0f40c52010-10-20 18:51:06 -0700271 pr_debug("Frame bits:: %d period_count :: %d\n",
Vinod Koulfffa1cc2010-10-05 16:25:17 +0100272 (int)substream->runtime->frame_bits,
273 (int)substream->runtime->period_size);
274
275 return stream->stream_info.buffer_ptr;
276
277}
278
279/**
280 * snd_intelmad_close- to free parameteres when stream is stopped
281 *
282 * @substream: substream for which the function is called
283 *
284 * This function is called by ALSA framework when stream is stopped
285 */
286static int snd_intelmad_close(struct snd_pcm_substream *substream)
287{
288 struct snd_intelmad *intelmaddata;
289 struct mad_stream_pvt *stream;
Vinod Koul6f6ffec2010-11-19 15:06:31 +0000290 int ret_val = 0, str_id;
Vinod Koulfffa1cc2010-10-05 16:25:17 +0100291
292 WARN_ON(!substream);
293
294 stream = substream->runtime->private_data;
Vinod Koul6f6ffec2010-11-19 15:06:31 +0000295 str_id = stream->stream_info.str_id;
Vinod Koulfffa1cc2010-10-05 16:25:17 +0100296
Vinod Koul6f6ffec2010-11-19 15:06:31 +0000297 pr_debug("sst: snd_intelmad_close called for %d\n", str_id);
Vinod Koulfffa1cc2010-10-05 16:25:17 +0100298 intelmaddata = snd_pcm_substream_chip(substream);
299
Joe Perchesd0f40c52010-10-20 18:51:06 -0700300 pr_debug("str id = %d\n", stream->stream_info.str_id);
Vinod Koulfffa1cc2010-10-05 16:25:17 +0100301 if (stream->stream_info.str_id) {
302 /* SST API to actually stop/free the stream */
Vinod Koul6f6ffec2010-11-19 15:06:31 +0000303 ret_val = intelmaddata->sstdrv_ops->pcm_control->close(str_id);
Vinod Koulfffa1cc2010-10-05 16:25:17 +0100304 if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
305 intelmaddata->playback_cnt--;
306 else
307 intelmaddata->capture_cnt--;
308 }
Joe Perchesd0f40c52010-10-20 18:51:06 -0700309 pr_debug("snd_intelmad_close : pb cnt = %d cap cnt = %d\n",
Vinod Koulfffa1cc2010-10-05 16:25:17 +0100310 intelmaddata->playback_cnt, intelmaddata->capture_cnt);
311 kfree(substream->runtime->private_data);
312 return ret_val;
313}
314
315/**
316 * snd_intelmad_open- to set runtime parameters during stream start
317 *
318 * @substream: substream for which the function is called
319 * @type: audio device type
320 *
321 * This function is called by ALSA framework when stream is started
322 */
323static int snd_intelmad_open(struct snd_pcm_substream *substream,
324 enum snd_sst_audio_device_type type)
325{
326 struct snd_intelmad *intelmaddata;
327 struct snd_pcm_runtime *runtime;
328 struct mad_stream_pvt *stream;
329
330 WARN_ON(!substream);
331
Joe Perchesd0f40c52010-10-20 18:51:06 -0700332 pr_debug("snd_intelmad_open called\n");
Vinod Koulfffa1cc2010-10-05 16:25:17 +0100333
334 intelmaddata = snd_pcm_substream_chip(substream);
335 runtime = substream->runtime;
336 /* set the runtime hw parameter with local snd_pcm_hardware struct */
337 runtime->hw = snd_intelmad_stream;
Wu Fengguang3ca13bd2011-05-03 17:35:19 +0100338 if (intelmaddata->cpu_id == CPU_CHIP_LINCROFT) {
339 /*
340 * MRST firmware currently denies stereo recording requests.
341 */
Wu Fengguanga4820502011-05-03 17:35:31 +0100342 if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) {
343 runtime->hw.formats = (SNDRV_PCM_FMTBIT_S16 |
344 SNDRV_PCM_FMTBIT_U16);
Wu Fengguang3ca13bd2011-05-03 17:35:19 +0100345 runtime->hw.channels_max = 1;
Wu Fengguanga4820502011-05-03 17:35:31 +0100346 }
Wu Fengguang3ca13bd2011-05-03 17:35:19 +0100347 }
Vinod Koulfffa1cc2010-10-05 16:25:17 +0100348 if (intelmaddata->cpu_id == CPU_CHIP_PENWELL) {
349 runtime->hw = snd_intelmad_stream;
350 runtime->hw.rates = SNDRV_PCM_RATE_48000;
351 runtime->hw.rate_min = MAX_RATE;
352 runtime->hw.formats = (SNDRV_PCM_FMTBIT_S24 |
353 SNDRV_PCM_FMTBIT_U24);
354 if (intelmaddata->sstdrv_ops->scard_ops->input_dev_id == AMIC)
355 runtime->hw.channels_max = MAX_CHANNEL_AMIC;
356 else
357 runtime->hw.channels_max = MAX_CHANNEL_DMIC;
358
359 }
360 /* setup the internal datastruture stream pointers based on it being
361 playback or capture stream */
362 stream = kzalloc(sizeof(*stream), GFP_KERNEL);
363 if (!stream)
364 return -ENOMEM;
365 stream->stream_info.str_id = 0;
366 stream->device = type;
367 stream->stream_status = INIT;
368 runtime->private_data = stream;
369 return snd_pcm_hw_constraint_integer(runtime,
370 SNDRV_PCM_HW_PARAM_PERIODS);
371}
372
373static int snd_intelmad_headset_open(struct snd_pcm_substream *substream)
374{
375 return snd_intelmad_open(substream, SND_SST_DEVICE_HEADSET);
376}
377
378static int snd_intelmad_ihf_open(struct snd_pcm_substream *substream)
379{
380 return snd_intelmad_open(substream, SND_SST_DEVICE_IHF);
381}
382
383static int snd_intelmad_vibra_open(struct snd_pcm_substream *substream)
384{
385 return snd_intelmad_open(substream, SND_SST_DEVICE_VIBRA);
386}
387
388static int snd_intelmad_haptic_open(struct snd_pcm_substream *substream)
389{
390 return snd_intelmad_open(substream, SND_SST_DEVICE_HAPTIC);
391}
392
393static struct snd_pcm_ops snd_intelmad_headset_ops = {
394 .open = snd_intelmad_headset_open,
395 .close = snd_intelmad_close,
396 .ioctl = snd_pcm_lib_ioctl,
397 .hw_params = snd_intelmad_hw_params,
398 .hw_free = snd_intelmad_hw_free,
399 .prepare = snd_intelmad_pcm_prepare,
400 .trigger = snd_intelmad_pcm_trigger,
401 .pointer = snd_intelmad_pcm_pointer,
402};
403
404static struct snd_pcm_ops snd_intelmad_ihf_ops = {
405 .open = snd_intelmad_ihf_open,
406 .close = snd_intelmad_close,
407 .ioctl = snd_pcm_lib_ioctl,
408 .hw_params = snd_intelmad_hw_params,
409 .hw_free = snd_intelmad_hw_free,
410 .prepare = snd_intelmad_pcm_prepare,
411 .trigger = snd_intelmad_pcm_trigger,
412 .pointer = snd_intelmad_pcm_pointer,
413};
414
415static struct snd_pcm_ops snd_intelmad_vibra_ops = {
416 .open = snd_intelmad_vibra_open,
417 .close = snd_intelmad_close,
418 .ioctl = snd_pcm_lib_ioctl,
419 .hw_params = snd_intelmad_hw_params,
420 .hw_free = snd_intelmad_hw_free,
421 .prepare = snd_intelmad_pcm_prepare,
422 .trigger = snd_intelmad_pcm_trigger,
423 .pointer = snd_intelmad_pcm_pointer,
424};
425
426static struct snd_pcm_ops snd_intelmad_haptic_ops = {
427 .open = snd_intelmad_haptic_open,
428 .close = snd_intelmad_close,
429 .ioctl = snd_pcm_lib_ioctl,
430 .hw_params = snd_intelmad_hw_params,
431 .hw_free = snd_intelmad_hw_free,
432 .prepare = snd_intelmad_pcm_prepare,
433 .trigger = snd_intelmad_pcm_trigger,
434 .pointer = snd_intelmad_pcm_pointer,
435};
436
437static struct snd_pcm_ops snd_intelmad_capture_ops = {
438 .open = snd_intelmad_headset_open,
439 .close = snd_intelmad_close,
440 .ioctl = snd_pcm_lib_ioctl,
441 .hw_params = snd_intelmad_hw_params,
442 .hw_free = snd_intelmad_hw_free,
443 .prepare = snd_intelmad_pcm_prepare,
444 .trigger = snd_intelmad_pcm_trigger,
445 .pointer = snd_intelmad_pcm_pointer,
446};
447
Ramesh Babu K V8a251ff2011-05-03 17:33:13 +0100448int intelmad_get_mic_bias(void)
449{
450 struct snd_pmic_ops *pmic_ops;
Vinod Koulfffa1cc2010-10-05 16:25:17 +0100451
Ramesh Babu K V8a251ff2011-05-03 17:33:13 +0100452 if (!intelmad_drv || !intelmad_drv->sstdrv_ops)
453 return -ENODEV;
454 pmic_ops = intelmad_drv->sstdrv_ops->scard_ops;
455 if (pmic_ops && pmic_ops->pmic_get_mic_bias)
456 return pmic_ops->pmic_get_mic_bias(intelmad_drv);
457 else
458 return -ENODEV;
459}
460EXPORT_SYMBOL_GPL(intelmad_get_mic_bias);
461
462int intelmad_set_headset_state(int state)
463{
464 struct snd_pmic_ops *pmic_ops;
465
466 if (!intelmad_drv || !intelmad_drv->sstdrv_ops)
467 return -ENODEV;
468 pmic_ops = intelmad_drv->sstdrv_ops->scard_ops;
469 if (pmic_ops && pmic_ops->pmic_set_headset_state)
470 return pmic_ops->pmic_set_headset_state(state);
471 else
472 return -ENODEV;
473}
474EXPORT_SYMBOL_GPL(intelmad_set_headset_state);
475
476void sst_process_mad_jack_detection(struct work_struct *work)
477{
478 u8 interrupt_status;
479 struct mad_jack_msg_wq *mad_jack_detect =
480 container_of(work, struct mad_jack_msg_wq, wq);
481
482 struct snd_intelmad *intelmaddata =
483 mad_jack_detect->intelmaddata;
484
485 if (!intelmaddata)
486 return;
487
488 interrupt_status = mad_jack_detect->intsts;
489 if (intelmaddata->sstdrv_ops && intelmaddata->sstdrv_ops->scard_ops
490 && intelmaddata->sstdrv_ops->scard_ops->pmic_irq_cb) {
491 intelmaddata->sstdrv_ops->scard_ops->pmic_irq_cb(
492 (void *)intelmaddata, interrupt_status);
493 intelmaddata->sstdrv_ops->scard_ops->pmic_jack_enable();
494 }
495 kfree(mad_jack_detect);
496}
Vinod Koulfffa1cc2010-10-05 16:25:17 +0100497/**
498 * snd_intelmad_intr_handler- interrupt handler
499 *
500 * @irq : irq number of the interrupt received
501 * @dev: device context
502 *
503 * This function is called when an interrupt is raised at the sound card
504 */
505static irqreturn_t snd_intelmad_intr_handler(int irq, void *dev)
506{
507 struct snd_intelmad *intelmaddata =
508 (struct snd_intelmad *)dev;
Ramesh Babu K V8a251ff2011-05-03 17:33:13 +0100509 u8 interrupt_status;
510 struct mad_jack_msg_wq *mad_jack_msg;
511 memcpy_fromio(&interrupt_status,
Vinod Koulfffa1cc2010-10-05 16:25:17 +0100512 ((void *)(intelmaddata->int_base)),
513 sizeof(u8));
Vinod Koulfffa1cc2010-10-05 16:25:17 +0100514
Ramesh Babu K V8a251ff2011-05-03 17:33:13 +0100515 mad_jack_msg = kzalloc(sizeof(*mad_jack_msg), GFP_ATOMIC);
516 mad_jack_msg->intsts = interrupt_status;
517 mad_jack_msg->intelmaddata = intelmaddata;
518 INIT_WORK(&mad_jack_msg->wq, sst_process_mad_jack_detection);
519 queue_work(intelmaddata->mad_jack_wq, &mad_jack_msg->wq);
Vinod Koulfffa1cc2010-10-05 16:25:17 +0100520
521 return IRQ_HANDLED;
522}
523
524void sst_mad_send_jack_report(struct snd_jack *jack,
525 int buttonpressevent , int status)
526{
527
528 if (!jack) {
Joe Perchesd0f40c52010-10-20 18:51:06 -0700529 pr_debug("MAD error jack empty\n");
Vinod Koulfffa1cc2010-10-05 16:25:17 +0100530
531 } else {
Vinod Koulfffa1cc2010-10-05 16:25:17 +0100532 snd_jack_report(jack, status);
Ramesh Babu K V8a251ff2011-05-03 17:33:13 +0100533 /* button pressed and released */
Vinod Koulfffa1cc2010-10-05 16:25:17 +0100534 if (buttonpressevent)
535 snd_jack_report(jack, 0);
Joe Perchesd0f40c52010-10-20 18:51:06 -0700536 pr_debug("MAD sending jack report Done !!!\n");
Vinod Koulfffa1cc2010-10-05 16:25:17 +0100537 }
Vinod Koulfffa1cc2010-10-05 16:25:17 +0100538}
539
Vinod Koulfffa1cc2010-10-05 16:25:17 +0100540static int __devinit snd_intelmad_register_irq(
Ramesh Babu K V8a251ff2011-05-03 17:33:13 +0100541 struct snd_intelmad *intelmaddata, unsigned int regbase,
542 unsigned int regsize)
Vinod Koulfffa1cc2010-10-05 16:25:17 +0100543{
544 int ret_val;
Vinod Koulfffa1cc2010-10-05 16:25:17 +0100545 char *drv_name;
546
Ramesh Babu K V8a251ff2011-05-03 17:33:13 +0100547 pr_debug("irq reg regbase 0x%x, regsize 0x%x\n",
Vinod Koulfffa1cc2010-10-05 16:25:17 +0100548 regbase, regsize);
549 intelmaddata->int_base = ioremap_nocache(regbase, regsize);
550 if (!intelmaddata->int_base)
Joe Perchesd0f40c52010-10-20 18:51:06 -0700551 pr_err("Mapping of cache failed\n");
552 pr_debug("irq = 0x%x\n", intelmaddata->irq);
Vinod Koulfffa1cc2010-10-05 16:25:17 +0100553 if (intelmaddata->cpu_id == CPU_CHIP_PENWELL)
554 drv_name = DRIVER_NAME_MFLD;
555 else
556 drv_name = DRIVER_NAME_MRST;
557 ret_val = request_irq(intelmaddata->irq,
558 snd_intelmad_intr_handler,
559 IRQF_SHARED, drv_name,
560 intelmaddata);
561 if (ret_val)
Joe Perchesd0f40c52010-10-20 18:51:06 -0700562 pr_err("cannot register IRQ\n");
Vinod Koulfffa1cc2010-10-05 16:25:17 +0100563 return ret_val;
564}
565
566static int __devinit snd_intelmad_sst_register(
567 struct snd_intelmad *intelmaddata)
568{
569 int ret_val = 0;
570 struct snd_pmic_ops *intelmad_vendor_ops[MAX_VENDORS] = {
571 &snd_pmic_ops_fs,
572 &snd_pmic_ops_mx,
573 &snd_pmic_ops_nc,
574 &snd_msic_ops
575 };
576
577 struct sc_reg_access vendor_addr = {0x00, 0x00, 0x00};
578
579 if (intelmaddata->cpu_id == CPU_CHIP_LINCROFT) {
580 ret_val = sst_sc_reg_access(&vendor_addr, PMIC_READ, 1);
581 if (ret_val)
582 return ret_val;
583 sst_card_vendor_id = (vendor_addr.value & (MASK2|MASK1|MASK0));
Lucas De Marchi25985ed2011-03-30 22:57:33 -0300584 pr_debug("original n extrated vendor id = 0x%x %d\n",
Vinod Koulfffa1cc2010-10-05 16:25:17 +0100585 vendor_addr.value, sst_card_vendor_id);
586 if (sst_card_vendor_id < 0 || sst_card_vendor_id > 2) {
Joe Perchesd0f40c52010-10-20 18:51:06 -0700587 pr_err("vendor card not supported!!\n");
Vinod Koulfffa1cc2010-10-05 16:25:17 +0100588 return -EIO;
589 }
590 } else
591 sst_card_vendor_id = 0x3;
592
593 intelmaddata->sstdrv_ops->module_name = SST_CARD_NAMES;
594 intelmaddata->sstdrv_ops->vendor_id = sst_card_vendor_id;
595 BUG_ON(!intelmad_vendor_ops[sst_card_vendor_id]);
596 intelmaddata->sstdrv_ops->scard_ops =
597 intelmad_vendor_ops[sst_card_vendor_id];
598
599 if (intelmaddata->cpu_id == CPU_CHIP_PENWELL) {
600 intelmaddata->sstdrv_ops->scard_ops->pb_on = 0;
601 intelmaddata->sstdrv_ops->scard_ops->cap_on = 0;
602 intelmaddata->sstdrv_ops->scard_ops->input_dev_id = DMIC;
603 intelmaddata->sstdrv_ops->scard_ops->output_dev_id =
604 STEREO_HEADPHONE;
Dharageswari R5572a442011-05-03 17:32:38 +0100605 intelmaddata->sstdrv_ops->scard_ops->lineout_dev_id = NONE;
Vinod Koulfffa1cc2010-10-05 16:25:17 +0100606 }
607
608 /* registering with SST driver to get access to SST APIs to use */
609 ret_val = register_sst_card(intelmaddata->sstdrv_ops);
610 if (ret_val) {
Joe Perchesd0f40c52010-10-20 18:51:06 -0700611 pr_err("sst card registration failed\n");
Vinod Koulfffa1cc2010-10-05 16:25:17 +0100612 return ret_val;
613 }
Vinod Koulfffa1cc2010-10-05 16:25:17 +0100614 sst_card_vendor_id = intelmaddata->sstdrv_ops->vendor_id;
615 intelmaddata->pmic_status = PMIC_UNINIT;
616 return ret_val;
617}
618
Ramesh Babu K V8a251ff2011-05-03 17:33:13 +0100619static void snd_intelmad_page_free(struct snd_pcm *pcm)
620{
621 snd_pcm_lib_preallocate_free_for_all(pcm);
622}
Vinod Koulfffa1cc2010-10-05 16:25:17 +0100623/* Driver Init/exit functionalities */
624/**
625 * snd_intelmad_pcm_new - to setup pcm for the card
626 *
627 * @card: pointer to the sound card structure
628 * @intelmaddata: pointer to internal context
629 * @pb: playback count for this card
630 * @cap: capture count for this card
631 * @index: device index
632 *
633 * This function is called from probe function to set up pcm params
634 * and functions
635 */
636static int __devinit snd_intelmad_pcm_new(struct snd_card *card,
637 struct snd_intelmad *intelmaddata,
638 unsigned int pb, unsigned int cap, unsigned int index)
639{
640 int ret_val = 0;
641 struct snd_pcm *pcm;
642 char name[32] = INTEL_MAD;
643 struct snd_pcm_ops *pb_ops = NULL, *cap_ops = NULL;
644
Joe Perchesd0f40c52010-10-20 18:51:06 -0700645 pr_debug("called for pb %d, cp %d, idx %d\n", pb, cap, index);
Vinod Koulfffa1cc2010-10-05 16:25:17 +0100646 ret_val = snd_pcm_new(card, name, index, pb, cap, &pcm);
647 if (ret_val)
648 return ret_val;
649 /* setup the ops for playback and capture streams */
650 switch (index) {
651 case 0:
652 pb_ops = &snd_intelmad_headset_ops;
653 cap_ops = &snd_intelmad_capture_ops;
654 break;
655 case 1:
656 pb_ops = &snd_intelmad_ihf_ops;
657 cap_ops = &snd_intelmad_capture_ops;
658 break;
659 case 2:
660 pb_ops = &snd_intelmad_vibra_ops;
661 cap_ops = &snd_intelmad_capture_ops;
662 break;
663 case 3:
664 pb_ops = &snd_intelmad_haptic_ops;
665 cap_ops = &snd_intelmad_capture_ops;
666 break;
667 }
668 if (pb)
669 snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, pb_ops);
670 if (cap)
671 snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, cap_ops);
672 /* setup private data which can be retrieved when required */
673 pcm->private_data = intelmaddata;
Ramesh Babu K V8a251ff2011-05-03 17:33:13 +0100674 pcm->private_free = snd_intelmad_page_free;
Vinod Koulfffa1cc2010-10-05 16:25:17 +0100675 pcm->info_flags = 0;
676 strncpy(pcm->name, card->shortname, strlen(card->shortname));
677 /* allocate dma pages for ALSA stream operations */
678 snd_pcm_lib_preallocate_pages_for_all(pcm,
679 SNDRV_DMA_TYPE_CONTINUOUS,
680 snd_dma_continuous_data(GFP_KERNEL),
681 MIN_BUFFER, MAX_BUFFER);
682 return ret_val;
683}
684
685static int __devinit snd_intelmad_pcm(struct snd_card *card,
686 struct snd_intelmad *intelmaddata)
687{
688 int ret_val = 0;
689
690 WARN_ON(!card);
691 WARN_ON(!intelmaddata);
Joe Perchesd0f40c52010-10-20 18:51:06 -0700692 pr_debug("snd_intelmad_pcm called\n");
Vinod Koulfffa1cc2010-10-05 16:25:17 +0100693 ret_val = snd_intelmad_pcm_new(card, intelmaddata, 1, 1, 0);
694 if (intelmaddata->cpu_id == CPU_CHIP_LINCROFT)
695 return ret_val;
696 ret_val = snd_intelmad_pcm_new(card, intelmaddata, 1, 0, 1);
697 if (ret_val)
698 return ret_val;
699 ret_val = snd_intelmad_pcm_new(card, intelmaddata, 1, 0, 2);
700 if (ret_val)
701 return ret_val;
702 return snd_intelmad_pcm_new(card, intelmaddata, 1, 0, 3);
703}
704
705/**
706 * snd_intelmad_jack- to setup jack settings of the card
707 *
708 * @intelmaddata: pointer to internal context
709 *
710 * This function is called send jack events
711 */
712static int snd_intelmad_jack(struct snd_intelmad *intelmaddata)
713{
714 struct snd_jack *jack;
715 int retval;
716
Joe Perchesd0f40c52010-10-20 18:51:06 -0700717 pr_debug("snd_intelmad_jack called\n");
Vinod Koulfffa1cc2010-10-05 16:25:17 +0100718 jack = &intelmaddata->jack[0].jack;
Ramesh Babu K V8a251ff2011-05-03 17:33:13 +0100719 snd_jack_set_key(jack, SND_JACK_BTN_0, KEY_PHONE);
720 retval = snd_jack_new(intelmaddata->card, "Intel(R) MID Audio Jack",
721 SND_JACK_HEADPHONE | SND_JACK_HEADSET |
722 SW_JACK_PHYSICAL_INSERT | SND_JACK_BTN_0
723 | SND_JACK_BTN_1, &jack);
724 pr_debug("snd_intelmad_jack called\n");
Vinod Koulfffa1cc2010-10-05 16:25:17 +0100725 if (retval < 0)
726 return retval;
727 snd_jack_report(jack, 0);
728
729 jack->private_data = jack;
730 intelmaddata->jack[0].jack = *jack;
731
Vinod Koulfffa1cc2010-10-05 16:25:17 +0100732 return retval;
733}
734
735/**
736 * snd_intelmad_mixer- to setup mixer settings of the card
737 *
738 * @intelmaddata: pointer to internal context
739 *
740 * This function is called from probe function to set up mixer controls
741 */
742static int __devinit snd_intelmad_mixer(struct snd_intelmad *intelmaddata)
743{
744 struct snd_card *card;
745 unsigned int idx;
746 int ret_val = 0, max_controls = 0;
747 char *mixername = "IntelMAD Controls";
748 struct snd_kcontrol_new *controls;
749
750 WARN_ON(!intelmaddata);
751
752 card = intelmaddata->card;
753 strncpy(card->mixername, mixername, sizeof(card->mixername)-1);
754 /* add all widget controls and expose the same */
755 if (intelmaddata->cpu_id == CPU_CHIP_PENWELL) {
756 max_controls = MAX_CTRL_MFLD;
757 controls = snd_intelmad_controls_mfld;
758 } else {
759 max_controls = MAX_CTRL_MRST;
760 controls = snd_intelmad_controls_mrst;
761 }
762 for (idx = 0; idx < max_controls; idx++) {
763 ret_val = snd_ctl_add(card,
764 snd_ctl_new1(&controls[idx],
765 intelmaddata));
Joe Perchesd0f40c52010-10-20 18:51:06 -0700766 pr_debug("mixer[idx]=%d added\n", idx);
Vinod Koulfffa1cc2010-10-05 16:25:17 +0100767 if (ret_val) {
Joe Perchesd0f40c52010-10-20 18:51:06 -0700768 pr_err("in adding of control index = %d\n", idx);
Vinod Koulfffa1cc2010-10-05 16:25:17 +0100769 break;
770 }
771 }
772 return ret_val;
773}
774
775static int snd_intelmad_dev_free(struct snd_device *device)
776{
777 struct snd_intelmad *intelmaddata;
778
779 WARN_ON(!device);
780
781 intelmaddata = device->device_data;
782
Joe Perchesd0f40c52010-10-20 18:51:06 -0700783 pr_debug("snd_intelmad_dev_free called\n");
Vinod Koulfffa1cc2010-10-05 16:25:17 +0100784 unregister_sst_card(intelmaddata->sstdrv_ops);
785
786 /* free allocated memory for internal context */
787 destroy_workqueue(intelmaddata->mad_jack_wq);
Ramesh Babu K V8a251ff2011-05-03 17:33:13 +0100788 device->device_data = NULL;
Vinod Koulfffa1cc2010-10-05 16:25:17 +0100789 kfree(intelmaddata->sstdrv_ops);
790 kfree(intelmaddata);
Ramesh Babu K V8a251ff2011-05-03 17:33:13 +0100791
Vinod Koulfffa1cc2010-10-05 16:25:17 +0100792 return 0;
793}
794
795static int __devinit snd_intelmad_create(
796 struct snd_intelmad *intelmaddata,
797 struct snd_card *card)
798{
799 int ret_val;
800 static struct snd_device_ops ops = {
801 .dev_free = snd_intelmad_dev_free,
802 };
803
804 WARN_ON(!intelmaddata);
805 WARN_ON(!card);
806 /* ALSA api to register for the device */
807 ret_val = snd_device_new(card, SNDRV_DEV_LOWLEVEL, intelmaddata, &ops);
808 return ret_val;
809}
810
811/**
812* snd_intelmad_probe- function registred for init
813* @pdev : pointer to the device struture
814* This function is called when the device is initialized
815*/
816int __devinit snd_intelmad_probe(struct platform_device *pdev)
817{
818 struct snd_card *card;
819 int ret_val;
820 struct snd_intelmad *intelmaddata;
821 const struct platform_device_id *id = platform_get_device_id(pdev);
Ramesh Babu K V8a251ff2011-05-03 17:33:13 +0100822 struct snd_intelmad_probe_info *info = (void *)id->driver_data;
Vinod Koulfffa1cc2010-10-05 16:25:17 +0100823
Ramesh Babu K V8a251ff2011-05-03 17:33:13 +0100824 pr_debug("probe for %s cpu_id %d\n", pdev->name, info->cpu_id);
825 pr_debug("rq_chache %x of size %x\n", info->irq_cache, info->size);
Vinod Koulfffa1cc2010-10-05 16:25:17 +0100826 if (!strcmp(pdev->name, DRIVER_NAME_MRST))
Joe Perchesd0f40c52010-10-20 18:51:06 -0700827 pr_debug("detected MRST\n");
Vinod Koulfffa1cc2010-10-05 16:25:17 +0100828 else if (!strcmp(pdev->name, DRIVER_NAME_MFLD))
Joe Perchesd0f40c52010-10-20 18:51:06 -0700829 pr_debug("detected MFLD\n");
Vinod Koulfffa1cc2010-10-05 16:25:17 +0100830 else {
Joe Perchesd0f40c52010-10-20 18:51:06 -0700831 pr_err("detected unknown device abort!!\n");
Vinod Koulfffa1cc2010-10-05 16:25:17 +0100832 return -EIO;
833 }
Ramesh Babu K V8a251ff2011-05-03 17:33:13 +0100834 if ((info->cpu_id < CPU_CHIP_LINCROFT) ||
835 (info->cpu_id > CPU_CHIP_PENWELL)) {
Joe Perchesd0f40c52010-10-20 18:51:06 -0700836 pr_err("detected unknown cpu_id abort!!\n");
Vinod Koulfffa1cc2010-10-05 16:25:17 +0100837 return -EIO;
838 }
839 /* allocate memory for saving internal context and working */
840 intelmaddata = kzalloc(sizeof(*intelmaddata), GFP_KERNEL);
841 if (!intelmaddata) {
Joe Perchesd0f40c52010-10-20 18:51:06 -0700842 pr_debug("mem alloctn fail\n");
Vinod Koulfffa1cc2010-10-05 16:25:17 +0100843 return -ENOMEM;
844 }
Ramesh Babu K V8a251ff2011-05-03 17:33:13 +0100845 intelmad_drv = intelmaddata;
Vinod Koulfffa1cc2010-10-05 16:25:17 +0100846
847 /* allocate memory for LPE API set */
848 intelmaddata->sstdrv_ops = kzalloc(sizeof(struct intel_sst_card_ops),
849 GFP_KERNEL);
850 if (!intelmaddata->sstdrv_ops) {
Joe Perchesd0f40c52010-10-20 18:51:06 -0700851 pr_err("mem allocation for ops fail\n");
Vinod Koulfffa1cc2010-10-05 16:25:17 +0100852 kfree(intelmaddata);
853 return -ENOMEM;
854 }
855
Ramesh Babu K V8a251ff2011-05-03 17:33:13 +0100856 intelmaddata->cpu_id = info->cpu_id;
Vinod Koulfffa1cc2010-10-05 16:25:17 +0100857 /* create a card instance with ALSA framework */
858 ret_val = snd_card_create(card_index, card_id, THIS_MODULE, 0, &card);
859 if (ret_val) {
Joe Perchesd0f40c52010-10-20 18:51:06 -0700860 pr_err("snd_card_create fail\n");
Vinod Koulfffa1cc2010-10-05 16:25:17 +0100861 goto free_allocs;
862 }
863
864 intelmaddata->pdev = pdev;
865 intelmaddata->irq = platform_get_irq(pdev, 0);
866 platform_set_drvdata(pdev, intelmaddata);
867 intelmaddata->card = card;
868 intelmaddata->card_id = card_id;
869 intelmaddata->card_index = card_index;
870 intelmaddata->master_mute = UNMUTE;
871 intelmaddata->playback_cnt = intelmaddata->capture_cnt = 0;
872 strncpy(card->driver, INTEL_MAD, strlen(INTEL_MAD));
873 strncpy(card->shortname, INTEL_MAD, strlen(INTEL_MAD));
874
875 intelmaddata->sstdrv_ops->module_name = SST_CARD_NAMES;
876 /* registering with LPE driver to get access to SST APIs to use */
877 ret_val = snd_intelmad_sst_register(intelmaddata);
878 if (ret_val) {
Joe Perchesd0f40c52010-10-20 18:51:06 -0700879 pr_err("snd_intelmad_sst_register failed\n");
Ramesh Babu K V8a251ff2011-05-03 17:33:13 +0100880 goto set_null_data;
Vinod Koulfffa1cc2010-10-05 16:25:17 +0100881 }
882
883 intelmaddata->pmic_status = PMIC_INIT;
884
885 ret_val = snd_intelmad_pcm(card, intelmaddata);
886 if (ret_val) {
Joe Perchesd0f40c52010-10-20 18:51:06 -0700887 pr_err("snd_intelmad_pcm failed\n");
Ramesh Babu K V8a251ff2011-05-03 17:33:13 +0100888 goto free_sst;
Vinod Koulfffa1cc2010-10-05 16:25:17 +0100889 }
890
891 ret_val = snd_intelmad_mixer(intelmaddata);
892 if (ret_val) {
Joe Perchesd0f40c52010-10-20 18:51:06 -0700893 pr_err("snd_intelmad_mixer failed\n");
Ramesh Babu K V8a251ff2011-05-03 17:33:13 +0100894 goto free_card;
Vinod Koulfffa1cc2010-10-05 16:25:17 +0100895 }
896
897 ret_val = snd_intelmad_jack(intelmaddata);
898 if (ret_val) {
Joe Perchesd0f40c52010-10-20 18:51:06 -0700899 pr_err("snd_intelmad_jack failed\n");
Ramesh Babu K V8a251ff2011-05-03 17:33:13 +0100900 goto free_card;
Vinod Koulfffa1cc2010-10-05 16:25:17 +0100901 }
Ramesh Babu K V8a251ff2011-05-03 17:33:13 +0100902 intelmaddata->adc_address = mid_initialize_adc();
Vinod Koulfffa1cc2010-10-05 16:25:17 +0100903
904 /*create work queue for jack interrupt*/
905 INIT_WORK(&intelmaddata->mad_jack_msg.wq,
906 sst_process_mad_jack_detection);
907
908 intelmaddata->mad_jack_wq = create_workqueue("sst_mad_jack_wq");
909 if (!intelmaddata->mad_jack_wq)
Ramesh Babu K V8a251ff2011-05-03 17:33:13 +0100910 goto free_card;
Vinod Koulfffa1cc2010-10-05 16:25:17 +0100911
Ramesh Babu K V8a251ff2011-05-03 17:33:13 +0100912 ret_val = snd_intelmad_register_irq(intelmaddata,
913 info->irq_cache, info->size);
Vinod Koulfffa1cc2010-10-05 16:25:17 +0100914 if (ret_val) {
Joe Perchesd0f40c52010-10-20 18:51:06 -0700915 pr_err("snd_intelmad_register_irq fail\n");
Ramesh Babu K V8a251ff2011-05-03 17:33:13 +0100916 goto free_mad_jack_wq;
Vinod Koulfffa1cc2010-10-05 16:25:17 +0100917 }
918
919 /* internal function call to register device with ALSA */
920 ret_val = snd_intelmad_create(intelmaddata, card);
921 if (ret_val) {
Joe Perchesd0f40c52010-10-20 18:51:06 -0700922 pr_err("snd_intelmad_create failed\n");
Ramesh Babu K V8a251ff2011-05-03 17:33:13 +0100923 goto set_pvt_data;;
Vinod Koulfffa1cc2010-10-05 16:25:17 +0100924 }
925 card->private_data = &intelmaddata;
926 snd_card_set_dev(card, &pdev->dev);
927 ret_val = snd_card_register(card);
928 if (ret_val) {
Joe Perchesd0f40c52010-10-20 18:51:06 -0700929 pr_err("snd_card_register failed\n");
Ramesh Babu K V8a251ff2011-05-03 17:33:13 +0100930 goto set_pvt_data;;
Vinod Koulfffa1cc2010-10-05 16:25:17 +0100931 }
932
Joe Perchesd0f40c52010-10-20 18:51:06 -0700933 pr_debug("snd_intelmad_probe complete\n");
Vinod Koulfffa1cc2010-10-05 16:25:17 +0100934 return ret_val;
935
Ramesh Babu K V8a251ff2011-05-03 17:33:13 +0100936set_pvt_data:
937 card->private_data = NULL;
Vinod Koulfffa1cc2010-10-05 16:25:17 +0100938free_mad_jack_wq:
939 destroy_workqueue(intelmaddata->mad_jack_wq);
Ramesh Babu K V8a251ff2011-05-03 17:33:13 +0100940free_card:
941 snd_card_free(intelmaddata->card);
942free_sst:
943 unregister_sst_card(intelmaddata->sstdrv_ops);
944set_null_data:
945 platform_set_drvdata(pdev, NULL);
Vinod Koulfffa1cc2010-10-05 16:25:17 +0100946free_allocs:
Joe Perchesd0f40c52010-10-20 18:51:06 -0700947 pr_err("probe failed\n");
Vinod Koulfffa1cc2010-10-05 16:25:17 +0100948 snd_card_free(card);
949 kfree(intelmaddata->sstdrv_ops);
950 kfree(intelmaddata);
951 return ret_val;
952}
953
954
955static int snd_intelmad_remove(struct platform_device *pdev)
956{
957 struct snd_intelmad *intelmaddata = platform_get_drvdata(pdev);
958
959 if (intelmaddata) {
Ramesh Babu K V8a251ff2011-05-03 17:33:13 +0100960 free_irq(intelmaddata->irq, intelmaddata);
Vinod Koulfffa1cc2010-10-05 16:25:17 +0100961 snd_card_free(intelmaddata->card);
Vinod Koulfffa1cc2010-10-05 16:25:17 +0100962 }
Ramesh Babu K V8a251ff2011-05-03 17:33:13 +0100963 intelmad_drv = NULL;
964 platform_set_drvdata(pdev, NULL);
Vinod Koulfffa1cc2010-10-05 16:25:17 +0100965 return 0;
966}
967
968/*********************************************************************
969 * Driver initialization and exit
970 *********************************************************************/
971static const struct platform_device_id snd_intelmad_ids[] = {
Ramesh Babu K V8a251ff2011-05-03 17:33:13 +0100972 {DRIVER_NAME_MRST, INFO(CPU_CHIP_LINCROFT, AUDINT_BASE, 1)},
973 {DRIVER_NAME_MFLD, INFO(CPU_CHIP_PENWELL, 0xFFFF7FCD, 1)},
Vinod Koulfffa1cc2010-10-05 16:25:17 +0100974 {"", 0},
975
976};
977
978static struct platform_driver snd_intelmad_driver = {
979 .driver = {
980 .owner = THIS_MODULE,
981 .name = "intel_mid_sound_card",
982 },
983 .id_table = snd_intelmad_ids,
984 .probe = snd_intelmad_probe,
985 .remove = __devexit_p(snd_intelmad_remove),
986};
987
988/*
989 * alsa_card_intelmad_init- driver init function
990 *
991 * This function is called when driver module is inserted
992 */
993static int __init alsa_card_intelmad_init(void)
994{
Joe Perchesd0f40c52010-10-20 18:51:06 -0700995 pr_debug("mad_init called\n");
Vinod Koulfffa1cc2010-10-05 16:25:17 +0100996 return platform_driver_register(&snd_intelmad_driver);
997}
998
999/**
1000 * alsa_card_intelmad_exit- driver exit function
1001 *
1002 * This function is called when driver module is removed
1003 */
1004static void __exit alsa_card_intelmad_exit(void)
1005{
Joe Perchesd0f40c52010-10-20 18:51:06 -07001006 pr_debug("mad_exit called\n");
Vinod Koulfffa1cc2010-10-05 16:25:17 +01001007 return platform_driver_unregister(&snd_intelmad_driver);
1008}
1009
1010module_init(alsa_card_intelmad_init)
1011module_exit(alsa_card_intelmad_exit)
1012