diff options
Diffstat (limited to 'meta-moblin/packages/linux/linux-moblin-2.6.33.2/linux-2.6.34-moorestown-audio-driver-6.0-7-8.patch')
-rw-r--r-- | meta-moblin/packages/linux/linux-moblin-2.6.33.2/linux-2.6.34-moorestown-audio-driver-6.0-7-8.patch | 2391 |
1 files changed, 0 insertions, 2391 deletions
diff --git a/meta-moblin/packages/linux/linux-moblin-2.6.33.2/linux-2.6.34-moorestown-audio-driver-6.0-7-8.patch b/meta-moblin/packages/linux/linux-moblin-2.6.33.2/linux-2.6.34-moorestown-audio-driver-6.0-7-8.patch deleted file mode 100644 index 557b67d93..000000000 --- a/meta-moblin/packages/linux/linux-moblin-2.6.33.2/linux-2.6.34-moorestown-audio-driver-6.0-7-8.patch +++ /dev/null @@ -1,2391 +0,0 @@ -From d88bb1ae711414e9bca4a23a7d6375cb4bad18f4 Mon Sep 17 00:00:00 2001 -From: R, Dharageswari <dharageswari.r@intel.com> -Date: Thu, 29 Apr 2010 20:28:59 +0530 -Subject: [PATCH] ADR-Post-Beta-0.05.002.03-7/8-Moorestown Audio Drivers: sound card ALSA driver - -This adds support for Moorestown ALSA Sound card driver. -This is an ALSA driver for supporting PCM playback/capture in -traditional ALSA way. Anyone who chooses not to use DSP for -decoding/encoding can use ALSA path to play/capture, but obvious loss will -be power. This driver registers the control interface and PCM interface with -the SST driver which finally sends it to the hardware. This driver allows any -subsystem in OS which wants to use the audio-subsystems to be routed -through the ALSA.The patch includes ALSA driver header file for handling -mixer controls for Intel MAD chipset.This patch also includes enum additions to -jack.h of ALSA Framework - -Signed-off-by: Vinod Koul <vinod.koul@intel.com> - - modified: include/sound/jack.h - new file: sound/pci/sst/intelmid.c - new file: sound/pci/sst/intelmid.h - new file: sound/pci/sst/intelmid_ctrl.c - new file: sound/pci/sst/intelmid_ctrl.h - new file: sound/pci/sst/intelmid_pvt.c -Patch-mainline: 2.6.35? ---- - include/sound/jack.h | 2 + - sound/pci/sst/intelmid.c | 1205 +++++++++++++++++++++++++++++++++++++++++ - sound/pci/sst/intelmid.h | 170 ++++++ - sound/pci/sst/intelmid_ctrl.c | 555 +++++++++++++++++++ - sound/pci/sst/intelmid_ctrl.h | 33 ++ - sound/pci/sst/intelmid_pvt.c | 343 ++++++++++++ - 6 files changed, 2308 insertions(+), 0 deletions(-) - create mode 100644 sound/pci/sst/intelmid.c - create mode 100644 sound/pci/sst/intelmid.h - create mode 100644 sound/pci/sst/intelmid_ctrl.c - create mode 100644 sound/pci/sst/intelmid_ctrl.h - create mode 100644 sound/pci/sst/intelmid_pvt.c - -diff --git a/include/sound/jack.h b/include/sound/jack.h -index f236e42..791c550 100644 ---- a/include/sound/jack.h -+++ b/include/sound/jack.h -@@ -42,6 +42,8 @@ enum snd_jack_types { - SND_JACK_MECHANICAL = 0x0008, /* If detected separately */ - SND_JACK_VIDEOOUT = 0x0010, - SND_JACK_AVOUT = SND_JACK_LINEOUT | SND_JACK_VIDEOOUT, -+ SND_JACK_HS_SHORT_PRESS = SND_JACK_HEADSET | 0x0020, -+ SND_JACK_HS_LONG_PRESS = SND_JACK_HEADSET | 0x0040, - }; - - struct snd_jack { -diff --git a/sound/pci/sst/intelmid.c b/sound/pci/sst/intelmid.c -new file mode 100644 -index 0000000..c5a3b36 ---- /dev/null -+++ b/sound/pci/sst/intelmid.c -@@ -0,0 +1,1205 @@ -+/* -+ * intelmid.c - Intel Sound card driver for MID -+ * -+ * Copyright (C) 2008-10 Intel Corp -+ * Authors: Harsha Priya <priya.harsha@intel.com> -+ * Vinod Koul <vinod.koul@intel.com> -+ * Dharageswari R <dharageswari.r@intel.com> -+ * KP Jeeja <jeeja.kp@intel.com> -+ * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License as published by -+ * the Free Software Foundation; version 2 of the License. -+ * -+ * This program is distributed in the hope that it will be useful, but -+ * WITHOUT ANY WARRANTY; without even the implied warranty of -+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -+ * General Public License for more details. -+ * -+ * You should have received a copy of the GNU General Public License along -+ * with this program; if not, write to the Free Software Foundation, Inc., -+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. -+ * -+ * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -+ * ALSA driver for Intel MID sound card chipset -+ */ -+#include <linux/spi/spi.h> -+#include <linux/io.h> -+#include <linux/delay.h> -+#include <linux/interrupt.h> -+#include <linux/init.h> -+#include <linux/slab.h> -+#include <linux/moduleparam.h> -+#include <linux/sched.h> -+#include <sound/core.h> -+#include <sound/control.h> -+#include <sound/pcm.h> -+#include <sound/jack.h> -+#include <sound/pcm_params.h> -+#include <sound/info.h> -+#include <sound/initval.h> -+ -+#include <sound/pcm-indirect.h> -+#include <sound/intel_lpe.h> -+#include <sound/intel_sst_ioctl.h> -+/* #include <net/netlink.h> -+#include <net/genetlink.h> */ -+ -+#include "intelmid_snd_control.h" -+#include "intelmid.h" -+#include "intelmid_ctrl.h" -+ -+MODULE_AUTHOR("Harsha Priya <priya.harsha@intel.com>"); -+MODULE_AUTHOR("Vinod Koul <vinod.koul@intel.com>"); -+MODULE_DESCRIPTION("Intel MAD Sound card driver"); -+MODULE_LICENSE("GPL v2"); -+MODULE_SUPPORTED_DEVICE("{Intel,Intel_MAD}"); -+ -+ -+static int card_index = SNDRV_DEFAULT_IDX1;/* Index 0-MAX */ -+static char *card_id = SNDRV_DEFAULT_STR1; /* ID for this card */ -+ -+module_param(card_index, int, 0444); -+MODULE_PARM_DESC(card_index, "Index value for INTELMAD soundcard."); -+module_param(card_id, charp, 0444); -+MODULE_PARM_DESC(card_id, "ID string for INTELMAD soundcard."); -+ -+int sst_card_vendor_id; -+int audio_interrupt_enable = 0; -+ -+/* Data path functionalities */ -+static struct snd_pcm_hardware snd_intelmad_stream = { -+ .info = (SNDRV_PCM_INFO_INTERLEAVED | -+ SNDRV_PCM_INFO_DOUBLE | -+ SNDRV_PCM_INFO_PAUSE | -+ SNDRV_PCM_INFO_RESUME | -+ SNDRV_PCM_INFO_MMAP| -+ SNDRV_PCM_INFO_MMAP_VALID | -+ /* SNDRV_PCM_INFO_BATCH | */ -+ SNDRV_PCM_INFO_BLOCK_TRANSFER | -+ SNDRV_PCM_INFO_SYNC_START), -+ .formats = (SNDRV_PCM_FMTBIT_S16 | SNDRV_PCM_FMTBIT_U16 | -+ /* SNDRV_PCM_FMTBIT_S8 | SNDRV_PCM_FMTBIT_U8 | */ -+ SNDRV_PCM_FMTBIT_S24 | SNDRV_PCM_FMTBIT_U24), -+ .rates = (SNDRV_PCM_RATE_8000| -+ SNDRV_PCM_RATE_44100 | -+ SNDRV_PCM_RATE_48000), -+ .rate_min = MIN_RATE, -+ -+ .rate_max = MAX_RATE, -+ .channels_min = MIN_CHANNEL, -+ .channels_max = MAX_CHANNEL, -+ .buffer_bytes_max = MAX_BUFFER, -+ .period_bytes_min = MIN_PERIOD_BYTES, -+ .period_bytes_max = MAX_PERIOD_BYTES, -+ .periods_min = MIN_PERIODS, -+ .periods_max = MAX_PERIODS, -+ .fifo_size = FIFO_SIZE, -+}; -+ -+static int snd_intelmad_pcm_ack(struct snd_pcm_substream *substream) -+{ -+ struct mad_stream_pvt *stream; -+ struct snd_pcm_indirect *rec; -+ -+ WARN_ON(!substream); -+ WARN_ON(!substream->runtime); -+ -+ stream = substream->runtime->private_data; -+ WARN_ON(!stream); -+ -+// printk(KERN_DEBUG "SST DBG:called %d\n", stream->stream_status); -+ if (stream->stream_status != INIT) { -+ -+ rec = &stream->pcm_indirect; -+ if (substream->stream == STREAM_OPS_PLAYBACK) { -+// printk(KERN_DEBUG "SST DBG:calling indirect playback transfer\n"); -+ snd_pcm_indirect_playback_transfer(substream, rec, -+ send_buffer_to_sst); -+ } else if (substream->stream == STREAM_OPS_CAPTURE) { -+// printk(KERN_DEBUG "SST DBG:calling indirect capture transfer\n"); -+ snd_pcm_indirect_capture_transfer(substream, rec, -+ send_buffer_to_sst); -+ } -+ -+ stream->stream_status = RUNNING; -+ } -+ return 0; -+} -+ -+/** -+* snd_intelmad_pcm_trigger - stream activities are handled here -+* @substream:substream for which the stream function is called -+*@cmd:the stream commamd thats requested from upper layer -+* This function is called whenever an a stream activity is invoked -+*/ -+static int snd_intelmad_pcm_trigger(struct snd_pcm_substream *substream, -+ int cmd) -+{ -+ int ret_val = 0; -+ struct snd_intelmad *intelmaddata; -+ struct mad_stream_pvt *stream; -+ struct stream_buffer buffer_to_sst; -+ -+// printk(KERN_DEBUG "SST DBG:called\n"); -+ -+ WARN_ON(!substream); -+ -+ intelmaddata = snd_pcm_substream_chip(substream); -+ stream = substream->runtime->private_data; -+ -+ WARN_ON(!intelmaddata->sstdrv_ops); -+ WARN_ON(!intelmaddata->sstdrv_ops->scard_ops); -+ -+ switch (cmd) { -+ case SNDRV_PCM_TRIGGER_START: -+ stream->substream = substream; -+/* -+ printk(KERN_DEBUG "SST DBG:pcm_size+\ -+ =%d\n", snd_pcm_lib_buffer_bytes(substream)); -+*/ -+ stream->stream_status = STARTED; -+ -+ if (substream->stream == STREAM_OPS_PLAYBACK) -+ snd_intelmad_pcm_ack(substream); -+ else if (substream->stream == STREAM_OPS_CAPTURE) { -+ buffer_to_sst.length = -+ frames_to_bytes(substream->runtime, -+ substream->runtime->buffer_size); -+ buffer_to_sst.addr = (unsigned long) -+ substream->runtime->dma_area; -+ ret_val = intelmaddata->sstdrv_ops->send_buffer( -+ stream->stream_info.str_id, -+ &buffer_to_sst); -+ stream->dbg_cum_bytes += -+ frames_to_bytes(substream->runtime, -+ substream->runtime->buffer_size); -+ stream->stream_status = RUNNING; -+ } -+ break; -+ case SNDRV_PCM_TRIGGER_STOP: -+// printk(KERN_DEBUG "SST DBG:in stop\n"); -+ ret_val = intelmaddata->sstdrv_ops->control_set(SST_SND_DROP, -+ &stream->stream_info.str_id); -+ if (ret_val) -+ return ret_val; -+ stream->stream_status = DROPPED; -+ break; -+ case SNDRV_PCM_TRIGGER_PAUSE_PUSH: -+// printk(KERN_DEBUG "SST DBG:in pause\n"); -+ ret_val = intelmaddata->sstdrv_ops->control_set(SST_SND_PAUSE, -+ &stream->stream_info.str_id); -+ if (ret_val) -+ return ret_val; -+ stream->stream_status = PAUSED; -+ break; -+ case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: -+// printk(KERN_DEBUG "SST DBG:in pause release \n"); -+ ret_val = intelmaddata->sstdrv_ops->control_set(SST_SND_RESUME, -+ &stream->stream_info.str_id); -+ if (ret_val) -+ return ret_val; -+ stream->stream_status = RUNNING; -+ break; -+ default: -+ return -EINVAL; -+ } -+ return ret_val; -+} -+ -+/** -+* snd_intelmad_pcm_prepare- internal preparation before starting a stream -+* @substream: substream for which the function is called -+* This function is called when a stream is started for internal preparation. -+*/ -+static int snd_intelmad_pcm_prepare(struct snd_pcm_substream *substream) -+{ -+ struct mad_stream_pvt *stream; -+ int ret_val = 0; -+ struct snd_intelmad *intelmaddata; -+ -+ printk(KERN_DEBUG "SST DBG:called \n"); -+ -+ WARN_ON(!substream); -+ stream = substream->runtime->private_data; -+ intelmaddata = snd_pcm_substream_chip(substream); -+ printk(KERN_DEBUG "SST DBG:pb cnt = %d cap cnt = %d\n",\ -+ intelmaddata->playback_cnt, -+ intelmaddata->capture_cnt); -+ -+ if(stream->stream_info.str_id) { -+ printk(KERN_DEBUG "SST DBG:Prepare called for already set stream\n"); -+ ret_val = intelmaddata->sstdrv_ops->control_set(SST_SND_DROP, -+ &stream->stream_info.str_id); -+ -+ } else { -+ ret_val = snd_intelmad_alloc_stream(substream); -+ if (ret_val < 0) -+ return ret_val; -+ stream->dbg_cum_bytes = 0; -+ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) -+ intelmaddata->playback_cnt++; -+ else -+ intelmaddata->capture_cnt++; -+ printk(KERN_DEBUG "SST DBG:period size = %d \n", -+ (int)substream->runtime->period_size); -+ printk(KERN_DEBUG "SST DBG:buf size = %d \n", -+ (int)substream->runtime->buffer_size); -+ memset(&stream->pcm_indirect, 0, sizeof(stream->pcm_indirect)); -+ stream->pcm_indirect.hw_buffer_size = -+ snd_pcm_lib_buffer_bytes(substream); -+ stream->pcm_indirect.sw_buffer_size = -+ stream->pcm_indirect.hw_buffer_size; -+ /* return back the stream id */ -+ snprintf(substream->pcm->id, sizeof(substream->pcm->id), -+ "%d", stream->stream_info.str_id); -+ printk(KERN_DEBUG "SST DBG:stream id to user = %s\n", substream->pcm->id); -+ } -+ ret_val = snd_intelmad_init_stream(substream); -+ if (ret_val) -+ return ret_val; -+ -+ return ret_val; -+} -+ -+static int snd_intelmad_hw_params(struct snd_pcm_substream *substream, -+ struct snd_pcm_hw_params *hw_params) -+{ -+ int ret_val; -+ -+ printk(KERN_DEBUG "SST DBG:called\n"); -+ ret_val = snd_pcm_lib_malloc_pages(substream, -+ params_buffer_bytes(hw_params)); -+ memset(substream->runtime->dma_area, 0, -+ params_buffer_bytes(hw_params)); -+ return ret_val; -+} -+ -+static int snd_intelmad_hw_free(struct snd_pcm_substream *substream) -+{ -+ printk(KERN_DEBUG "SST DBG:called\n"); -+ return snd_pcm_lib_free_pages(substream); -+} -+ -+/** -+* snd_intelmad_pcm_pointer- to send the current buffer pointer processed by hw -+* @substream: substream for which the function is called -+* This function is called by ALSA framework to get the current hw buffer ptr -+* when a period is elapsed -+*/ -+static snd_pcm_uframes_t snd_intelmad_pcm_pointer -+ (struct snd_pcm_substream *substream) -+{ -+ /* struct snd_pcm_runtime *runtime = substream->runtime; */ -+ struct mad_stream_pvt *stream; -+ struct snd_intelmad *intelmaddata; -+ int ret_val; -+ unsigned long buf_size; -+ -+ WARN_ON(!substream); -+ -+ intelmaddata = snd_pcm_substream_chip(substream); -+ stream = substream->runtime->private_data; -+ if (stream->stream_status == INIT) -+ return 0; -+ -+ ret_val = intelmaddata->sstdrv_ops->control_set(SST_SND_BUFFER_POINTER, -+ &stream->stream_info); -+ if (ret_val) { -+ dev_err(&intelmaddata->spi->dev,\ -+ "SST ERR: error code = 0x%x \n", ret_val); -+ return ret_val; -+ } -+/* printk(KERN_DEBUG "SST DBG:samples reported out 0x%llx \n", -+ stream->stream_info.buffer_ptr); -+ printk(KERN_DEBUG "SST DBG:Frame bits:: %d period_count :: %d \n", -+ (int)substream->runtime->frame_bits, -+ (int)substream->runtime->period_size); -+*/ -+ if (substream->stream == STREAM_OPS_PLAYBACK) { -+ if(SNDRV_PCM_POS_XRUN == stream->stream_info.buffer_ptr) -+ return SNDRV_PCM_POS_XRUN; -+ } -+ -+ buf_size = frames_to_bytes(substream->runtime, -+ stream->stream_info.buffer_ptr); -+ -+// printk(KERN_DEBUG "SST DBG: bytes reported out = 0x%lx\n", buf_size); -+ if (buf_size > stream->dbg_cum_bytes) -+ dev_err(&intelmaddata->spi->dev, "SST ERR: excess reported \n"); -+ -+ if (substream->stream == STREAM_OPS_PLAYBACK) -+ return snd_pcm_indirect_playback_pointer( -+ substream, &stream->pcm_indirect, buf_size); -+ else -+ return snd_pcm_indirect_capture_pointer( -+ substream, &stream->pcm_indirect, buf_size); -+} -+ -+/** -+* snd_intelmad_close- to free parameteres when stream is stopped -+* @substream: substream for which the function is called -+* This function is called by ALSA framework when stream is stopped -+*/ -+static int snd_intelmad_close(struct snd_pcm_substream *substream) -+{ -+ struct snd_intelmad *intelmaddata; -+ struct mad_stream_pvt *stream; -+ int ret_val = 0; -+ -+ WARN_ON(!substream); -+ -+ stream = substream->runtime->private_data; -+ -+ printk(KERN_DEBUG "SST DBG:called \n"); -+ intelmaddata = snd_pcm_substream_chip(substream); -+ -+ printk(KERN_DEBUG "SST DBG:str id = %d\n", stream->stream_info.str_id); -+ if (stream->stream_info.str_id) { -+ /* SST API to actually stop/free the stream */ -+ ret_val = intelmaddata->sstdrv_ops->control_set(SST_SND_FREE, -+ &stream->stream_info.str_id); -+ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) -+ intelmaddata->playback_cnt--; -+ else -+ intelmaddata->capture_cnt--; -+ } -+ printk(KERN_DEBUG "SST DBG:pb cnt = %d cap cnt = %d\n", intelmaddata->playback_cnt, -+ intelmaddata->capture_cnt); -+ kfree(substream->runtime->private_data); -+ return ret_val; -+} -+ -+/** -+* snd_intelmad_open- to set runtime parameters during stream start -+* @substream: substream for which the function is called -+* This function is called by ALSA framework when stream is started -+*/ -+static int snd_intelmad_open(struct snd_pcm_substream *substream) -+{ -+ struct snd_intelmad *intelmaddata; -+ struct snd_pcm_runtime *runtime; -+ struct mad_stream_pvt *stream; -+ -+ WARN_ON(!substream); -+ -+ printk(KERN_DEBUG "SST DBG:called \n"); -+ -+ intelmaddata = snd_pcm_substream_chip(substream); -+ runtime = substream->runtime; -+ /* set the runtime hw parameter with local snd_pcm_hardware struct */ -+ runtime->hw = snd_intelmad_stream; -+ /* setup the internal datastruture stream pointers based on it being -+ playback or capture stream */ -+ stream = kzalloc(sizeof(*stream), GFP_KERNEL); -+ if (!stream) -+ return -ENOMEM; -+ stream->stream_info.str_id = 0; -+ stream->stream_status = INIT; -+ runtime->private_data = stream; -+ return snd_pcm_hw_constraint_integer(runtime, -+ SNDRV_PCM_HW_PARAM_PERIODS); -+} -+ -+static struct snd_pcm_ops snd_intelmad_playback_ops = { -+ .open = snd_intelmad_open, -+ .close = snd_intelmad_close, -+ .ioctl = snd_pcm_lib_ioctl, -+ .hw_params = snd_intelmad_hw_params, -+ .hw_free = snd_intelmad_hw_free, -+ .prepare = snd_intelmad_pcm_prepare, -+ .trigger = snd_intelmad_pcm_trigger, -+ .pointer = snd_intelmad_pcm_pointer, -+ .ack = snd_intelmad_pcm_ack, -+}; -+ -+static struct snd_pcm_ops snd_intelmad_capture_ops = { -+ .open = snd_intelmad_open, -+ .close = snd_intelmad_close, -+ .ioctl = snd_pcm_lib_ioctl, -+ .hw_params = snd_intelmad_hw_params, -+ .hw_free = snd_intelmad_hw_free, -+ .prepare = snd_intelmad_pcm_prepare, -+ .trigger = snd_intelmad_pcm_trigger, -+ .pointer = snd_intelmad_pcm_pointer, -+ .ack = snd_intelmad_pcm_ack, -+}; -+ -+ -+#ifdef REG_IRQ -+/** -+* snd_intelmad_intr_handler- interrupt handler -+*@irq : irq number of the interrupt received -+*@dev: device context -+* This function is called when an interrupt is raised at the sound card -+*/ -+static irqreturn_t snd_intelmad_intr_handler(int irq, void *dev) -+{ -+ struct snd_intelmad *intelmaddata = -+ (struct snd_intelmad *)dev; -+ u8 intsts; -+ -+ memcpy_fromio(&intsts, -+ ((void *)(intelmaddata->int_base)), -+ sizeof(u8)); -+ intelmaddata->mad_jack_msg.intsts = intsts; -+ intelmaddata->mad_jack_msg.intelmaddata = intelmaddata; -+ -+ queue_work(intelmaddata->mad_jack_wq, &intelmaddata->mad_jack_msg.wq); -+ -+ return IRQ_HANDLED; -+} -+ -+void sst_mad_send_jack_report(struct snd_jack *jack, int buttonpressevent , int status) -+{ -+ -+ if (!jack) { -+ printk(KERN_DEBUG "SST DBG:MAD error jack empty \n"); -+ -+ } else { -+ printk(KERN_DEBUG "SST DBG:MAD sending jack +\ -+ report for = %d!!!\n", status); -+ if (jack) -+ printk(KERN_DEBUG "SST DBG:MAD sending +\ -+ jack report for = %d !!!\n", jack->type); -+ -+ snd_jack_report(jack, status); -+ -+ /*button pressed and released */ -+ if (buttonpressevent) -+ snd_jack_report(jack, 0); -+ printk(KERN_DEBUG "SST DBG:MAD sending jack report Done !!!\n"); -+ } -+ -+ -+ -+} -+ -+void sst_mad_jackdetection_fs(u8 intsts , struct snd_intelmad *intelmaddata) -+{ -+ struct snd_jack *jack = NULL; -+ unsigned int present = 0, jack_event_flag = 0, buttonpressflag = 0; -+ struct sc_reg_access sc_access[] = { -+ {0x187, 0x00, MASK7}, -+ {0x188, 0x10, MASK4}, -+ {0x18b, 0x10, MASK4}, -+ }; -+ -+ struct sc_reg_access sc_access_write[] = { -+ {0x198, 0x00, 0x0}, -+ }; -+ -+ if (intsts & 0x4) { -+ -+ if (!(audio_interrupt_enable)) { -+ printk(KERN_DEBUG "SST DBG:Audio interrupt enable\n"); -+ sst_sc_reg_access(sc_access, PMIC_READ_MODIFY, 3); -+ -+ sst_sc_reg_access(sc_access_write, PMIC_WRITE, 1); -+ audio_interrupt_enable = 1; -+ intelmaddata->jack[0].jack_status = 0; -+ intelmaddata->jack[1].jack_status = 0; -+ -+ } -+ /* send headphone detect */ -+ printk(KERN_DEBUG "SST DBG:MAD headphone +\ -+ = %d!!!\n", intsts & 0x4); -+ jack = &intelmaddata->jack[0].jack; -+ present = !(intelmaddata->jack[0].jack_status); -+ intelmaddata->jack[0].jack_status = present; -+ jack_event_flag = 1; -+ -+ } -+ -+ if (intsts & 0x2) { -+ /* send short push */ -+ printk(KERN_DEBUG "SST DBG:MAD short push +\ -+ = %d!!!\n", intsts & 0x2); -+ jack = &intelmaddata->jack[2].jack; -+ present = 1; -+ jack_event_flag = 1; -+ buttonpressflag = 1; -+ } -+ if (intsts & 0x1) { -+ /* send long push */ -+ printk(KERN_DEBUG "SST DBG:MAD long push+\ -+ = %d!!!\n", intsts & 0x1); -+ jack = &intelmaddata->jack[3].jack; -+ present = 1; -+ jack_event_flag = 1; -+ buttonpressflag = 1; -+ } -+ if (intsts & 0x8) { -+ if (!(audio_interrupt_enable)) { -+ printk(KERN_DEBUG "SST DBG:Audio interrupt enable\n"); -+ sst_sc_reg_access(sc_access, PMIC_READ_MODIFY, 3); -+ -+ sst_sc_reg_access(sc_access_write, PMIC_WRITE, 1); -+ audio_interrupt_enable = 1; -+ intelmaddata->jack[0].jack_status = 0; -+ intelmaddata->jack[1].jack_status = 0; -+ } -+ /* send headset detect */ -+ printk(KERN_DEBUG "SST DBG:MAD headset +\ -+ = %d!!!\n", intsts & 0x8); -+ jack = &intelmaddata->jack[1].jack; -+ present = !(intelmaddata->jack[1].jack_status); -+ intelmaddata->jack[1].jack_status = present; -+ jack_event_flag = 1; -+ } -+ -+ -+ if (jack_event_flag) -+ sst_mad_send_jack_report( jack, buttonpressflag, present); -+} -+ -+ -+void sst_mad_jackdetection_mx(u8 intsts, struct snd_intelmad *intelmaddata) -+{ -+ u8 value = 0,jack_prev_state = 0; -+ struct snd_jack *jack = NULL; -+ unsigned int present = 0, jack_event_flag = 0, buttonpressflag = 0; -+ time_t timediff; -+ struct sc_reg_access sc_access_read = {0,}; -+ -+ -+ -+ printk(KERN_DEBUG "SST DBG:previos value: = 0x%x \n" ,intelmaddata->jack_prev_state); -+ -+ if (!(audio_interrupt_enable)) { -+ printk(KERN_DEBUG "SST DBG:Audio interrupt enable\n"); -+ intelmaddata->jack_prev_state = 0xC0; -+ audio_interrupt_enable = 1; -+ } -+ -+ if (intsts & 0x2) { -+ jack_prev_state = intelmaddata->jack_prev_state; -+ if(intelmaddata->pmic_status == PMIC_INIT) { -+ sc_access_read.reg_addr = 0x201; -+ sst_sc_reg_access(&sc_access_read, PMIC_READ, 1); -+ value = (sc_access_read.value); -+ printk(KERN_DEBUG "value returned = 0x%x\n", value); -+ } -+ -+ if ((jack_prev_state == 0xc0) && (value == 0x40) ) { -+ //headset detected. -+ printk(KERN_DEBUG "MAD headset inserted\n"); -+ jack = &intelmaddata->jack[1].jack; -+ present= 1; -+ jack_event_flag = 1; -+ intelmaddata->jack[1].jack_status = 1; -+ -+ } -+ -+ if ((jack_prev_state == 0xc0 ) && ( value == 0x00) ) { -+ //headphone detected. -+ printk(KERN_DEBUG "MAD headphone inserted\n"); -+ jack = &intelmaddata->jack[0].jack; -+ present= 1; -+ jack_event_flag = 1; -+ -+ } -+ -+ if ( (jack_prev_state == 0x40 ) && ( value == 0xc0) ) { -+ //headset removed -+ printk(KERN_DEBUG "Jack headset status %d\n",\ -+ intelmaddata->jack[1].jack_status); -+ printk(KERN_DEBUG "MAD headset removed \n"); -+ jack = &intelmaddata->jack[1].jack; -+ present= 0; -+ jack_event_flag = 1; -+ intelmaddata->jack[1].jack_status = 0; -+ } -+ -+ if ( (jack_prev_state == 0x00 ) && ( value == 0xc0) ) { -+ //headphone detected. -+ printk(KERN_DEBUG "Jack headphone status %d\n",\ -+ intelmaddata->jack[0].jack_status); -+ printk(KERN_DEBUG "MAD headphone removed\n"); -+ jack = &intelmaddata->jack[0].jack; -+ present= 0; -+ jack_event_flag = 1; -+ } -+ -+ if ( (jack_prev_state == 0x40 ) && (value == 0x00) ) { -+ //button pressed -+ do_gettimeofday(&intelmaddata->jack[1].buttonpressed); -+ printk(KERN_DEBUG "MAD button press detected n"); -+ } -+ -+ -+ if( (jack_prev_state == 0x00 ) && ( value == 0x40) ) { -+ if ( intelmaddata->jack[1].jack_status ) { -+ //button pressed -+ do_gettimeofday(&intelmaddata->jack[1].buttonreleased); -+ /*button pressed */ -+ printk(KERN_DEBUG "MAD Button Released detected time \n" ); -+ timediff = intelmaddata->jack[1].buttonreleased.tv_sec - -+ intelmaddata->jack[1].buttonpressed.tv_sec; -+ buttonpressflag = 1; -+ if(timediff > 1) { -+ printk(KERN_DEBUG "MAD long press detected time \n" ); -+ /* send headphone detect/undetect */ -+ jack = &intelmaddata->jack[3].jack; -+ present= 1; -+ jack_event_flag = 1; -+ } -+ else { -+ printk(KERN_DEBUG "MAD short press detected time \n" ); -+ /* send headphone detect/undetect */ -+ jack = &intelmaddata->jack[2].jack; -+ present= 1; -+ jack_event_flag = 1; -+ } -+ } -+ -+ } -+ intelmaddata->jack_prev_state = value ; -+ -+ } -+ -+ if (jack_event_flag) -+ sst_mad_send_jack_report( jack, buttonpressflag, present); -+} -+ -+ -+void sst_mad_jackdetection_nec(u8 intsts, struct snd_intelmad *intelmaddata) -+{ -+ u8 value = 0; -+ struct snd_jack *jack = NULL; -+ unsigned int present = 0, jack_event_flag = 0, buttonpressflag = 0; -+ -+ struct sc_reg_access sc_access_read = {0,}; -+ -+ if (intelmaddata->pmic_status == PMIC_INIT) { -+ sc_access_read.reg_addr = 0x132; -+ sst_sc_reg_access(&sc_access_read, PMIC_READ, 1); -+ value = (sc_access_read.value); -+ printk(KERN_DEBUG "SST DBG:value returned = 0x%x\n", value); -+ } -+ if (intsts & 0x1) { -+ printk(KERN_DEBUG "SST DBG:MAD headset detected\n"); -+ /* send headset detect/undetect */ -+ jack = &intelmaddata->jack[1].jack; -+ present = (value == 0x1) ? 1 : 0; -+ jack_event_flag = 1; -+ } -+ if (intsts & 0x2) { -+ printk(KERN_DEBUG "SST DBG:MAD headphone detected\n"); -+ /* send headphone detect/undetect */ -+ jack = &intelmaddata->jack[0].jack; -+ present = (value == 0x2) ? 1 : 0; -+ jack_event_flag = 1; -+ } -+ if (intsts & 0x4) { -+ printk(KERN_DEBUG "SST DBG:MAD short push detected\n"); -+ /* send short push */ -+ jack = &intelmaddata->jack[2].jack; -+ present = 1; -+ jack_event_flag = 1; -+ buttonpressflag = 1; -+ } -+ if (intsts & 0x8) { -+ printk(KERN_DEBUG "SST DBG:MAD long push detected\n"); -+ /* send long push */ -+ jack = &intelmaddata->jack[3].jack; -+ present = 1; -+ jack_event_flag = 1; -+ buttonpressflag = 1; -+ } -+ -+ if (jack_event_flag) -+ sst_mad_send_jack_report( jack, buttonpressflag, present); -+ -+ -+} -+ -+void sst_process_mad_jack_detection(struct work_struct *work) -+{ -+ u8 intsts; -+ struct mad_jack_msg_wq *mad_jack_detect = -+ container_of(work, struct mad_jack_msg_wq, wq); -+ -+ struct snd_intelmad *intelmaddata = -+ mad_jack_detect->intelmaddata; -+ -+ intsts = mad_jack_detect->intsts; -+ -+ switch (intelmaddata->sstdrv_ops->vendor_id) { -+ case SND_FS: -+ sst_mad_jackdetection_fs(intsts,intelmaddata); -+ break; -+ case SND_MX: -+ sst_mad_jackdetection_mx(intsts,intelmaddata); -+ break; -+ case SND_NC: -+ sst_mad_jackdetection_nec(intsts,intelmaddata); -+ break; -+ } -+} -+ -+ -+static int __devinit snd_intelmad_register_irq( -+ struct snd_intelmad *intelmaddata) -+{ -+ int ret_val; -+ u32 regbase = AUDINT_BASE, regsize = 8; -+ -+ printk(KERN_DEBUG "SST DBG:irq reg done, now mapping... regbase 0x%x, regsize 0x%x\n", -+ regbase, regsize); -+ intelmaddata->int_base = ioremap_nocache(regbase, regsize); -+ if (!intelmaddata->int_base) -+ dev_err(&intelmaddata->spi->dev, "SST ERR: +\ -+ Mapping of cache failed \n"); -+ -+ /* interpret irq field */ -+ printk(KERN_DEBUG "SST DBG:irq = 0x%x\n", intelmaddata->irq); -+ ret_val = request_irq(intelmaddata->irq, -+ snd_intelmad_intr_handler, -+ IRQF_SHARED, DRIVER_NAME, -+ intelmaddata); -+ if (ret_val) -+ dev_err(&intelmaddata->spi->dev, "SST ERR: cannot +\ -+ register IRQ \n"); -+ return ret_val; -+} -+ -+/*static int __devinit snd_intelmad_register_netlink(void) -+{ -+ int ret_val; -+ -+ ret_val = genl_register_family(&audio_event_genl_family); -+ if (ret_val) { -+ printk(KERN_DEBUG "SST DBG:netlink registration failed\n"); -+ return ret_val; -+ } -+ ret_val = genl_register_mc_group(&audio_event_genl_family, -+ &audio_event_mcgrp); -+ if (ret_val) { -+ printk(KERN_DEBUG "SST DBG:netlink +\ -+ group registration failed\n"); -+ genl_unregister_family(&audio_event_genl_family); -+ return ret_val; -+ } -+ return ret_val; -+}*/ -+#endif -+ -+static int __devinit snd_intelmad_sst_register( -+ struct snd_intelmad *intelmaddata) -+{ -+ int ret_val; -+ struct sc_reg_access pmic_reg = {0,}; -+ -+ pmic_reg.reg_addr = 0; -+ ret_val = sst_sc_reg_access(&pmic_reg, PMIC_READ, 1); -+ -+ if (ret_val) -+ return ret_val; -+ -+ sst_card_vendor_id = pmic_reg.value & (MASK2|MASK1|MASK0); -+ printk(KERN_DEBUG "SST DBG:orginal reg n extrated vendor id = 0x%x %d\n", -+ pmic_reg.value, sst_card_vendor_id); -+ if (sst_card_vendor_id < 0 || sst_card_vendor_id > 2) { -+ dev_err(&intelmaddata->spi->dev, \ -+ "SST ERR: vendor card not supported!! \n"); -+ return -EIO; -+ } -+ intelmaddata->sstdrv_ops->module_name = SST_CARD_NAMES; -+ intelmaddata->sstdrv_ops->vendor_id = sst_card_vendor_id; -+ intelmaddata->sstdrv_ops->scard_ops = -+ intelmad_vendor_ops[sst_card_vendor_id]; -+ -+ /* registering with SST driver to get access to SST APIs to use */ -+ ret_val = register_sst_card(intelmaddata->sstdrv_ops); -+ if (ret_val) { -+ dev_err(&intelmaddata->spi->dev, \ -+ "SST ERR: sst card registration failed \n"); -+ return ret_val; -+ } -+ -+ sst_card_vendor_id = intelmaddata->sstdrv_ops->vendor_id; -+ intelmaddata->pmic_status = PMIC_UNINIT; -+ return ret_val; -+} -+ -+/* Driver Init/exit functionalities */ -+/** -+* snd_intelmad_pcm- to setup pcm for the card -+* @card: pointer to the sound card structure -+*@intelmaddata: pointer to internal context -+* This function is called from probe function to set up pcm params and functions -+*/ -+static int __devinit snd_intelmad_pcm(struct snd_card *card, -+ struct snd_intelmad *intelmaddata) -+{ -+ struct snd_pcm *pcm; -+ int i, ret_val = 0; -+ char name[32] = INTEL_MAD; -+ -+ WARN_ON(!card); -+ WARN_ON(!intelmaddata); -+ -+ for (i = 0; i < MAX_DEVICES; i++) { -+ ret_val = snd_pcm_new(card, name, i, PLAYBACK_COUNT, -+ CAPTURE_COUNT, &pcm); -+ if (ret_val) -+ break; -+ /* setup the ops for playback and capture streams */ -+ snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, -+ &snd_intelmad_playback_ops); -+ snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, -+ &snd_intelmad_capture_ops); -+ /* setup private data which can be retrieved when required */ -+ pcm->private_data = intelmaddata; -+ pcm->info_flags = 0; -+ strncpy(pcm->name, card->shortname, strlen(card->shortname)); -+ /* allocate dma pages for ALSA stream operations */ -+ snd_pcm_lib_preallocate_pages_for_all(pcm, -+ SNDRV_DMA_TYPE_CONTINUOUS, -+ snd_dma_continuous_data(GFP_KERNEL), -+ MIN_BUFFER, MAX_BUFFER); -+ } -+ return ret_val; -+} -+ -+/** -+* snd_intelmad_jack- to setup jack settings of the card -+*@intelmaddata: pointer to internal context -+* This function is called from probe function to set up mixer controls -+*/ -+static int __devinit snd_intelmad_jack(struct snd_intelmad *intelmaddata) -+{ -+ struct snd_jack *jack; -+ int retval; -+ -+ printk(KERN_DEBUG "SST DBG:called\n"); -+ jack = &intelmaddata->jack[0].jack; -+ retval = snd_jack_new(intelmaddata->card, "Headphone", -+ SND_JACK_HEADPHONE, &jack); -+ if (retval < 0) -+ return retval; -+ snd_jack_report(jack, 0); -+ -+ jack->private_data = jack; -+ intelmaddata->jack[0].jack = *jack; -+ -+ -+ jack = &intelmaddata->jack[1].jack; -+ retval = snd_jack_new(intelmaddata->card, "Headset", -+ SND_JACK_HEADSET, &jack); -+ if (retval < 0) -+ return retval; -+ -+ -+ -+ jack->private_data = jack; -+ intelmaddata->jack[1].jack = *jack; -+ -+ -+ jack = &intelmaddata->jack[2].jack; -+ retval = snd_jack_new(intelmaddata->card, "Short Press", -+ SND_JACK_HS_SHORT_PRESS, &jack); -+ if (retval < 0) -+ return retval; -+ -+ -+ jack->private_data = jack; -+ intelmaddata->jack[2].jack = *jack; -+ -+ -+ jack = &intelmaddata->jack[3].jack; -+ retval = snd_jack_new(intelmaddata->card, "Long Press", -+ SND_JACK_HS_LONG_PRESS, &jack); -+ if (retval < 0) -+ return retval; -+ -+ -+ jack->private_data = jack; -+ intelmaddata->jack[3].jack = *jack; -+ -+ return retval; -+} -+ -+/** -+* snd_intelmad_mixer- to setup mixer settings of the card -+*@intelmaddata: pointer to internal context -+* This function is called from probe function to set up mixer controls -+*/ -+static int __devinit snd_intelmad_mixer(struct snd_intelmad *intelmaddata) -+{ -+ struct snd_card *card; -+ unsigned int idx; -+ int ret_val = 0; -+ char *mixername = "IntelMAD Controls"; -+ -+ WARN_ON(!intelmaddata); -+ -+ card = intelmaddata->card; -+ -+ strncpy(card->mixername, mixername, strlen(mixername)); -+ /* add all widget controls and expose the same */ -+ for (idx = 0; idx < MAX_CTRL; idx++) { -+ ret_val = snd_ctl_add(card, -+ snd_ctl_new1(&snd_intelmad_controls[idx], -+ intelmaddata)); -+ printk(KERN_DEBUG "SST DBG:mixer[idx]=%d added \n", idx); -+ if (ret_val) { -+ dev_err(&intelmaddata->spi->dev, \ -+ "SST ERR: adding of control +\ -+ failed index = %d \n", idx); -+ break; -+ } -+ } -+ return ret_val; -+} -+ -+/** -+* snd_intelmad_dev_free- to free device -+*@device: pointer to the device -+* This function is called when driver module is removed -+*/ -+static int snd_intelmad_dev_free(struct snd_device *device) -+{ -+ struct snd_intelmad *intelmaddata; -+ -+ WARN_ON(!device); -+ -+ intelmaddata = device->device_data; -+ -+ printk(KERN_DEBUG "SST DBG:called\n"); -+ snd_card_free(intelmaddata->card); -+ /*genl_unregister_family(&audio_event_genl_family);*/ -+ unregister_sst_card(intelmaddata->sstdrv_ops); -+ -+ /* free allocated memory for internal context */ -+ destroy_workqueue(intelmaddata->mad_jack_wq); -+ kfree(intelmaddata->sstdrv_ops); -+ kfree(intelmaddata); -+ return 0; -+} -+ -+/** -+* snd_intelmad_create- called from probe to create a snd device -+*@intelmaddata : pointer to the internal context -+*@card : pointer to the sound card -+* This function is called when driver module is started -+*/ -+static int __devinit snd_intelmad_create( -+ struct snd_intelmad *intelmaddata, -+ struct snd_card *card) -+{ -+ int ret_val; -+ static struct snd_device_ops ops = { -+ .dev_free = snd_intelmad_dev_free, -+ }; -+ -+ WARN_ON(!intelmaddata); -+ WARN_ON(!card); -+ /* ALSA api to register for the device */ -+ ret_val = snd_device_new(card, SNDRV_DEV_LOWLEVEL, intelmaddata, &ops); -+ return ret_val; -+} -+ -+/********************************************************************* -+ * SPI Functions -+ *********************************************************************/ -+ -+ -+/** -+* snd_intelmad_probe- function registred for init -+*@spi : pointer to the spi device context -+* This function is called when the device is initialized -+*/ -+int __devinit snd_intelmad_probe(struct spi_device *spi) -+{ -+ struct snd_card *card; -+ int ret_val; -+ struct snd_intelmad *intelmaddata; -+ -+ printk(KERN_DEBUG "SST DBG:called \n"); -+ -+ /* allocate memory for saving internal context and working */ -+ intelmaddata = kzalloc(sizeof(*intelmaddata), GFP_KERNEL); -+ if (!intelmaddata) -+ return -ENOMEM; -+ -+ /* allocate memory for LPE API set */ -+ intelmaddata->sstdrv_ops = kzalloc(sizeof(struct intel_sst_card_ops), -+ GFP_KERNEL); -+ if (!intelmaddata->sstdrv_ops) { -+ dev_err(&intelmaddata->spi->dev, "SST ERR: +\ -+ mem alloctn fail \n"); -+ kfree(intelmaddata); -+ return -ENOMEM; -+ } -+ -+ /* create a card instance with ALSA framework */ -+ ret_val = snd_card_create(card_index, card_id, THIS_MODULE, 0, &card); -+ if (ret_val) { -+ dev_err(&intelmaddata->spi->dev, "SST +\ -+ ERR: snd_card_create fail \n"); -+ goto free_allocs; -+ } -+ -+ intelmaddata->spi = spi; -+ intelmaddata->irq = spi->irq; -+ dev_set_drvdata(&spi->dev, intelmaddata); -+ intelmaddata->card = card; -+ intelmaddata->card_id = card_id; -+ intelmaddata->card_index = card_index; -+ intelmaddata->playback_cnt = intelmaddata->capture_cnt = 0; -+ strncpy(card->driver, INTEL_MAD, strlen(INTEL_MAD)); -+ strncpy(card->shortname, INTEL_MAD, strlen(INTEL_MAD)); -+ -+ -+ intelmaddata->sstdrv_ops->module_name = SST_CARD_NAMES; -+ /* registering with LPE driver to get access to SST APIs to use */ -+ ret_val = snd_intelmad_sst_register(intelmaddata); -+ if (ret_val) { -+ dev_err(&intelmaddata->spi->dev,\ -+ "SST ERR:+ snd_intelmad_sst_register failed \n"); -+ goto free_allocs; -+ } -+ -+ intelmaddata->pmic_status = PMIC_INIT; -+ -+ ret_val = snd_intelmad_pcm(card, intelmaddata); -+ if (ret_val) { -+ dev_err(&intelmaddata->spi->dev,\ -+ "SST ERR: snd_intelmad_pcm failed \n"); -+ goto free_allocs; -+ } -+ -+ ret_val = snd_intelmad_mixer(intelmaddata); -+ if (ret_val) { -+ dev_err(&intelmaddata->spi->dev,\ -+ "SST ERR: snd_intelmad_mixer failed \n"); -+ goto free_allocs; -+ } -+ -+ ret_val = snd_intelmad_jack(intelmaddata); -+ if (ret_val) { -+ dev_err(&intelmaddata->spi->dev,\ -+ "SST ERR: snd_intelmad_jack failed \n"); -+ goto free_allocs; -+ } -+ -+ /*create work queue for jack interrupt*/ -+ -+ INIT_WORK(&intelmaddata->mad_jack_msg.wq, \ -+ sst_process_mad_jack_detection); -+ -+ intelmaddata->mad_jack_wq = create_workqueue("sst_mad_jack_wq"); -+ if (!intelmaddata->mad_jack_wq) -+ goto free_mad_jack_wq; -+ -+#ifdef REG_IRQ -+ ret_val = snd_intelmad_register_irq(intelmaddata); -+ if (ret_val) { -+ dev_err(&intelmaddata->spi->dev,\ -+ "SST ERR: snd_intelmad_register_irq fail \n"); -+ goto free_allocs; -+ } -+ /*ret_val = snd_intelmad_register_netlink(); -+ if (ret_val) { -+ printk(KERN_DEBUG "SST DBG:...complete\n"); -+ return ret_val; -+ }*/ -+#endif -+ -+ /* internal function call to register device with ALSA */ -+ ret_val = snd_intelmad_create(intelmaddata, card); -+ if (ret_val) { -+ dev_err(&intelmaddata->spi->dev,\ -+ "SST ERR: snd_intelmad_create failed \n"); -+ goto free_allocs; -+ } -+ card->private_data = &intelmaddata; -+ snd_card_set_dev(card, &spi->dev); -+ ret_val = snd_card_register(card); -+ if (ret_val) { -+ dev_err(&intelmaddata->spi->dev,\ -+ "SST ERR: snd_card_register failed \n"); -+ goto free_allocs; -+ } -+ -+ printk(KERN_DEBUG "SST DBG:...complete\n"); -+ return ret_val; -+ -+free_mad_jack_wq: -+ destroy_workqueue(intelmaddata->mad_jack_wq); -+ -+free_allocs: -+ /* TODO: unregister IRQ */ -+ dev_err(&intelmaddata->spi->dev, "SST ERR: probe failed \n"); -+ /* snd_card_free(card); */ -+ kfree(intelmaddata->sstdrv_ops); -+ kfree(intelmaddata); -+ return ret_val; -+} -+ -+ -+/** -+* snd_intelmad_remove- function registred for exit -+*@spi : pointer to the spi device context -+* This function is called when the device is uninitialized -+*/ -+static int snd_intelmad_remove(struct spi_device *spi) -+{ -+ struct snd_intelmad *intelmaddata = -+ dev_get_drvdata(&spi->dev); -+ /* -+ * TODO:: de-register interrupt handler -+ */ -+ -+ if (intelmaddata) { -+ snd_card_free(intelmaddata->card); -+ /*genl_unregister_family(&audio_event_genl_family);*/ -+ unregister_sst_card(intelmaddata->sstdrv_ops); -+ /* free allocated memory for internal context */ -+ destroy_workqueue(intelmaddata->mad_jack_wq); -+ kfree(intelmaddata->sstdrv_ops); -+ kfree(intelmaddata); -+ } -+ return 0; -+} -+ -+/********************************************************************* -+ * Driver initialization and exit -+ *********************************************************************/ -+ -+static struct spi_driver snd_intelmad_driver = { -+ .driver = { -+ .name = DRIVER_NAME, -+ .bus = &spi_bus_type, -+ .owner = THIS_MODULE, -+ }, -+ .probe = snd_intelmad_probe, -+ .remove = __devexit_p(snd_intelmad_remove), -+}; -+ -+/* -+* alsa_card_intelmad_init- driver init function -+* This function is called when driver module is inserted -+*/ -+static int __init alsa_card_intelmad_init(void) -+{ -+ printk(KERN_DEBUG "SST DBG:called\n"); -+ return spi_register_driver(&snd_intelmad_driver); -+} -+ -+/** -+* alsa_card_intelmad_exit- driver exit function -+* This function is called when driver module is removed -+*/ -+static void __exit alsa_card_intelmad_exit(void) -+{ -+ printk(KERN_DEBUG "SST DBG:called\n"); -+ spi_unregister_driver(&snd_intelmad_driver); -+} -+ -+module_init(alsa_card_intelmad_init) -+module_exit(alsa_card_intelmad_exit) -+ -diff --git a/sound/pci/sst/intelmid.h b/sound/pci/sst/intelmid.h -new file mode 100644 -index 0000000..235115e ---- /dev/null -+++ b/sound/pci/sst/intelmid.h -@@ -0,0 +1,170 @@ -+/* -+ * intelmid.h - Intel Sound card driver for MID -+ * -+ * Copyright (C) 2008-10 Intel Corp -+ * Authors: Harsha Priya <priya.harsha@intel.com> -+ * Vinod Koul <vinod.koul@intel.com> -+ * KP Jeeja <jeeja.kp@intel.com> -+ * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License as published by -+ * the Free Software Foundation version 2 of the License. -+ * -+ * This program is distributed in the hope that it will be useful, but -+ * WITHOUT ANY WARRANTY; without even the implied warranty of -+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -+ * General Public License for more details. -+ * -+ * You should have received a copy of the GNU General Public License along -+ * with this program; if not, write to the Free Software Foundation, Inc., -+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. -+ * -+ * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -+ * ALSA driver header for Intel MAD chipset -+ */ -+#ifndef __INTELMID_H -+#define __INTELMID_H -+ -+#include <linux/time.h> -+ -+#define DRIVER_NAME "pmic_audio" -+#define PMIC_SOUND_IRQ_TYPE_MASK (1 << 15) -+#define AUDINT_BASE (0xFFFFEFF8 + (6 * sizeof(u8))) -+#define REG_IRQ -+/* values #defined */ -+/* will differ for different hw - to be taken from config */ -+#define MAX_DEVICES 1 -+#define MIN_RATE 8000 -+#define MAX_RATE 48000 -+#define MAX_BUFFER (128*1024) /* TBD for PCM */ -+#define MIN_BUFFER (128*1024) -+#define MAX_PERIODS (1024) -+#define MIN_PERIODS 2 -+#define MAX_PERIOD_BYTES MAX_BUFFER -+//#define MIN_PERIOD_BYTES 32 -+#define MIN_PERIOD_BYTES 160 -+#define MAX_MUTE 1 -+#define MIN_MUTE 0 -+#define MONO_CNTL 1 -+#define STEREO_CNTL 2 -+#define MIN_CHANNEL 1 -+#define MAX_CHANNEL 2 -+#define FIFO_SIZE 0 /* fifo not being used */ -+#define INTEL_MAD "Intel MAD" -+#define MAX_CTRL 7 -+#define MAX_VENDORS 3 -+/* TODO +6 db */ -+#define MAX_VOL 64 -+/* TODO -57 db */ -+#define MIN_VOL 0 -+#define PLAYBACK_COUNT 1 -+#define CAPTURE_COUNT 1 -+ -+extern int sst_card_vendor_id; -+ -+struct mad_jack { -+ struct snd_jack jack; -+ int jack_status; -+ struct timeval buttonpressed; -+ struct timeval buttonreleased; -+}; -+struct mad_jack_msg_wq { -+ u8 intsts; -+ struct snd_intelmad *intelmaddata; -+ struct work_struct wq; -+ -+}; -+struct snd_intelmad { -+ struct snd_card *card; /* ptr to the card details */ -+ int card_index;/* card index */ -+ char *card_id; /* card id */ -+ struct intel_sst_card_ops *sstdrv_ops;/* ptr to sst driver ops */ -+ struct spi_device *spi; -+ int irq; -+ int pmic_status; -+ void __iomem *int_base; -+ int output_sel; -+ int input_sel; -+ int master_mute; -+ struct mad_jack jack[4]; -+ int playback_cnt; -+ int capture_cnt; -+ struct mad_jack_msg_wq mad_jack_msg; -+ struct workqueue_struct *mad_jack_wq; -+ u8 jack_prev_state; -+}; -+ -+struct snd_control_val { -+ int playback_vol_max; -+ int playback_vol_min; -+ int capture_vol_max; -+ int capture_vol_min; -+}; -+ -+struct mad_stream_pvt { -+ int stream_status; -+ int stream_ops; -+ struct snd_pcm_substream *substream; -+ struct snd_pcm_indirect pcm_indirect; -+ struct pcm_stream_info stream_info; -+ ssize_t dbg_cum_bytes; -+}; -+ -+enum mad_drv_status { -+ INIT = 1, -+ STARTED, -+ RUNNING, -+ PAUSED, -+ DROPPED, -+}; -+ -+enum mad_pmic_status { -+ PMIC_UNINIT = 1, -+ PMIC_INIT, -+}; -+enum _widget_ctrl { -+ PLAYBACK_VOL = 1 , -+ PLAYBACK_MUTE, -+ CAPTURE_VOL, -+ CAPTURE_MUTE, -+ OUTPUT_SEL, -+ INPUT_SEL, -+ MASTER_MUTE -+}; -+ -+/*enum { -+ AUDIO_GENL_ATTR_UNSPEC = 0, -+ AUDIO_GENL_ATTR_EVENT, -+ AUDIO_GENL_ATTR_MAX, -+}; -+enum { -+ AUDIO_GENL_CMD_UNSPEC, -+ AUDIO_GENL_CMD_EVENT, -+ AUDIO_GENL_CMD_MAX, -+}; -+ -+enum eaudio_events { -+ AUDIO_EVENT_HP_DETECT, -+ AUDIO_EVENT_HS_DETECT, -+ AUDIO_EVENT_SHORT_PRESS, -+ AUDIO_EVENT_LONG_PRESS, -+ AUDIO_EVENT_COUNT, -+}; -+ -+struct audio_genl_event { -+ u32 orig; -+ enum eaudio_events event; -+};*/ -+ -+ -+void period_elapsed(void *mad_substream); -+int snd_intelmad_alloc_stream(struct snd_pcm_substream *substream); -+int snd_intelmad_init_stream(struct snd_pcm_substream *substream); -+void send_buffer_to_sst(struct snd_pcm_substream *substream, -+ struct snd_pcm_indirect *rec, size_t bytes); -+int sst_sc_reg_access(struct sc_reg_access *sc_access, -+ int type, int num_val); -+ -+ -+#endif /* __INTELMID_H */ -diff --git a/sound/pci/sst/intelmid_ctrl.c b/sound/pci/sst/intelmid_ctrl.c -new file mode 100644 -index 0000000..f778628 ---- /dev/null -+++ b/sound/pci/sst/intelmid_ctrl.c -@@ -0,0 +1,555 @@ -+/* -+ * intelmid_ctrl.c - Intel Sound card driver for MID -+ * -+ * Copyright (C) 2008-10 Intel Corp -+ * Authors: Harsha Priya <priya.harsha@intel.com> -+ * Vinod Koul <vinod.koul@intel.com> -+ * KP Jeeja <jeeja.kp@intel.com> -+ * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License as published by -+ * the Free Software Foundation version 2 of the License. -+ * -+ * This program is distributed in the hope that it will be useful, but -+ * WITHOUT ANY WARRANTY; without even the implied warranty of -+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -+ * General Public License for more details. -+ * -+ * You should have received a copy of the GNU General Public License along -+ * with this program; if not, write to the Free Software Foundation, Inc., -+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. -+ * -+ * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -+ * ALSA driver handling mixer controls for Intel MAD chipset -+ */ -+#include <linux/spi/spi.h> -+#include <linux/io.h> -+#include <linux/delay.h> -+#include <linux/interrupt.h> -+#include <linux/init.h> -+#include <linux/slab.h> -+#include <linux/moduleparam.h> -+#include <linux/sched.h> -+#include <sound/core.h> -+#include <sound/control.h> -+#include <sound/pcm.h> -+#include <sound/jack.h> -+#include <sound/pcm_params.h> -+#include <sound/info.h> -+#include <sound/initval.h> -+#include <sound/pcm-indirect.h> -+#include <sound/intel_lpe.h> -+#include <sound/intel_sst_ioctl.h> -+#include "intelmid_snd_control.h" -+#include "intelmid.h" -+ -+static char *out_names[] = {"Headphones", -+ "Internal speakers"}; -+static char *in_names[] = {"HS_MIC", -+ "AMIC", -+ "DMIC"}; -+ -+struct snd_pmic_ops *intelmad_vendor_ops[MAX_VENDORS] = { -+ &snd_pmic_ops_fs, -+ &snd_pmic_ops_mx, -+ &snd_pmic_ops_nc -+}; -+ -+struct snd_control_val intelmad_ctrl_val[MAX_VENDORS] = { -+ { -+ .playback_vol_max = 63, -+ .playback_vol_min = 0, -+ .capture_vol_max = 63, -+ .capture_vol_min = 0, -+ }, -+ { -+ .playback_vol_max = 0, -+ .playback_vol_min = -31, -+ .capture_vol_max = 0, -+ .capture_vol_min = -20, -+ }, -+ { -+ .playback_vol_max = 0, -+ .playback_vol_min = -126, -+ .capture_vol_max = 0, -+ .capture_vol_min = -31, -+ }, -+}; -+ -+/* control path functionalities */ -+ -+static inline int snd_intelmad_volume_info(struct snd_ctl_elem_info *uinfo, -+ int control_type, int max, int min) -+{ -+ WARN_ON(!uinfo); -+ -+ uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; -+ uinfo->count = control_type; -+ uinfo->value.integer.min = min; -+ uinfo->value.integer.max = max; -+ return 0; -+} -+ -+/** -+* snd_intelmad_mute_info - provides information about the mute controls -+* @kcontrol: pointer to the control -+* @uinfo: pointer to the structure where the control's info need -+* to be filled -+* This function is called when a mixer application requests for control's info -+*/ -+static int snd_intelmad_mute_info(struct snd_kcontrol *kcontrol, -+ struct snd_ctl_elem_info *uinfo) -+{ -+ WARN_ON(!uinfo); -+ WARN_ON(!kcontrol); -+ -+ /* set up the mute as a boolean mono control with min-max values */ -+ uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN; -+ uinfo->count = MONO_CNTL; -+ uinfo->value.integer.min = MIN_MUTE; -+ uinfo->value.integer.max = MAX_MUTE; -+ return 0; -+} -+ -+/** -+* snd_intelmad_capture_volume_info - provides info about the volume control -+* @kcontrol: pointer to the control -+* @uinfo: pointer to the structure where the control's info need -+* to be filled -+* This function is called when a mixer application requests for control's info -+*/ -+static int snd_intelmad_capture_volume_info(struct snd_kcontrol *kcontrol, -+ struct snd_ctl_elem_info *uinfo) -+{ -+ snd_intelmad_volume_info(uinfo, MONO_CNTL, -+ intelmad_ctrl_val[sst_card_vendor_id].capture_vol_max, -+ intelmad_ctrl_val[sst_card_vendor_id].capture_vol_min); -+ return 0; -+} -+ -+/** -+* snd_intelmad_playback_volume_info - provides info about the volume control -+* @kcontrol: pointer to the control -+* @uinfo: pointer to the structure where the control's info need -+* to be filled -+* This function is called when a mixer application requests for control's info -+*/ -+static int snd_intelmad_playback_volume_info(struct snd_kcontrol *kcontrol, -+ struct snd_ctl_elem_info *uinfo) -+{ -+ snd_intelmad_volume_info(uinfo, STEREO_CNTL, -+ intelmad_ctrl_val[sst_card_vendor_id].playback_vol_max, -+ intelmad_ctrl_val[sst_card_vendor_id].playback_vol_min); -+ return 0; -+} -+ -+/** -+* snd_intelmad_device_info - provides information about the devices available -+* @kcontrol: pointer to the control -+* @uinfo: pointer to the structure where the devices's info need -+* to be filled -+* This function is called when a mixer application requests for device's info -+*/ -+static int snd_intelmad_device_info(struct snd_kcontrol *kcontrol, -+ struct snd_ctl_elem_info *uinfo) -+{ -+ WARN_ON(!kcontrol); -+ WARN_ON(!uinfo); -+ /* setup device select as drop down controls with different values */ -+ if (kcontrol->id.numid == OUTPUT_SEL) -+ uinfo->value.enumerated.items = ARRAY_SIZE(out_names); -+ else -+ uinfo->value.enumerated.items = ARRAY_SIZE(in_names); -+ uinfo->count = MONO_CNTL; -+ uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; -+ -+ if (uinfo->value.enumerated.item >= uinfo->value.enumerated.items) -+ uinfo->value.enumerated.item = 1; -+ if (kcontrol->id.numid == OUTPUT_SEL) -+ strncpy(uinfo->value.enumerated.name, -+ out_names[uinfo->value.enumerated.item], -+ strlen(out_names[uinfo->value.enumerated.item])); -+ else -+ strncpy(uinfo->value.enumerated.name, -+ in_names[uinfo->value.enumerated.item], -+ strlen(in_names[uinfo->value.enumerated.item])); -+ return 0; -+} -+ -+/** -+* snd_intelmad_volume_get - gets the current volume for the control -+* @kcontrol: pointer to the control -+* @uval: pointer to the structure where the control's info need -+* to be filled -+* This function is called when .get function of a control is invoked from app -+*/ -+static int snd_intelmad_volume_get(struct snd_kcontrol *kcontrol, -+ struct snd_ctl_elem_value *uval) -+{ -+ int ret_val = 0, cntl_list[2] = {0,}; -+ u8 value = 0; -+ struct snd_intelmad *intelmaddata; -+ struct snd_pmic_ops *scard_ops; -+ -+ printk(KERN_DEBUG "SST DBG:called\n"); -+ -+ WARN_ON(!uval); -+ WARN_ON(!kcontrol); -+ -+ intelmaddata = kcontrol->private_data; -+ -+ WARN_ON(!intelmaddata->sstdrv_ops); -+ -+ scard_ops = intelmaddata->sstdrv_ops->scard_ops; -+ -+ WARN_ON(!scard_ops); -+ -+ switch (kcontrol->id.numid) { -+ case PLAYBACK_VOL: -+ cntl_list[0] = PMIC_SND_RIGHT_PB_VOL; -+ cntl_list[1] = PMIC_SND_LEFT_PB_VOL; -+ break; -+ -+ case CAPTURE_VOL: -+ cntl_list[0] = PMIC_SND_CAPTURE_VOL; -+ break; -+ default: -+ return -EINVAL; -+ } -+ -+ ret_val = scard_ops->get_vol(cntl_list[0], &value); -+ uval->value.integer.value[0] = value; -+ -+ if (ret_val) -+ return ret_val; -+ -+ if (kcontrol->id.numid == PLAYBACK_VOL) { -+ ret_val = scard_ops->get_vol(cntl_list[1], &value); -+ uval->value.integer.value[1] = value; -+ } -+ return ret_val; -+} -+ -+/** -+* snd_intelmad_mute_get - gets the current mute status for the control -+* @kcontrol: pointer to the control -+* @uval: pointer to the structure where the control's info need -+* to be filled -+* This function is called when .get function of a control is invoked from app -+*/ -+static int snd_intelmad_mute_get(struct snd_kcontrol *kcontrol, -+ struct snd_ctl_elem_value *uval) -+{ -+ -+ int cntl_list = 0, ret_val = 0; -+ u8 value = 0; -+ struct snd_intelmad *intelmaddata; -+ struct snd_pmic_ops *scard_ops; -+ -+ printk(KERN_DEBUG "SST DBG:called\n"); -+ -+ WARN_ON(!uval); -+ WARN_ON(!kcontrol); -+ -+ intelmaddata = kcontrol->private_data; -+ -+ WARN_ON(!intelmaddata->sstdrv_ops); -+ -+ scard_ops = intelmaddata->sstdrv_ops->scard_ops; -+ -+ WARN_ON(!scard_ops); -+ -+ switch (kcontrol->id.numid) { -+ case PLAYBACK_MUTE: -+ if (intelmaddata->output_sel == STEREO_HEADPHONE) -+ cntl_list = PMIC_SND_LEFT_HP_MUTE; -+ else if (intelmaddata->output_sel == INTERNAL_SPKR) -+ cntl_list = PMIC_SND_LEFT_SPEAKER_MUTE; -+ break; -+ -+ case CAPTURE_MUTE: -+ if (intelmaddata->input_sel == DMIC) -+ cntl_list = PMIC_SND_DMIC_MUTE; -+ else if (intelmaddata->input_sel == AMIC) -+ cntl_list = PMIC_SND_AMIC_MUTE; -+ else if (intelmaddata->input_sel == HS_MIC) -+ cntl_list = PMIC_SND_HP_MIC_MUTE; -+ break; -+ case MASTER_MUTE: -+ uval->value.integer.value[0] = intelmaddata->master_mute; -+ return 0; -+ default: -+ return -EINVAL; -+ } -+ -+ ret_val = scard_ops->get_mute(cntl_list, &value); -+ uval->value.integer.value[0] = value; -+ return ret_val; -+} -+ -+/** -+* snd_intelmad_volume_set - sets the volume control's info -+* @kcontrol: pointer to the control -+* @uval: pointer to the structure where the control's info is -+* available to be set -+* This function is called when .set function of a control is invoked from app -+*/ -+static int snd_intelmad_volume_set(struct snd_kcontrol *kcontrol, -+ struct snd_ctl_elem_value *uval) -+{ -+ -+ int ret_val, cntl_list[2] = {0,}; -+ struct snd_intelmad *intelmaddata; -+ struct snd_pmic_ops *scard_ops; -+ -+ printk(KERN_DEBUG "SST DBG:volume set called:%ld %ld \n", -+ uval->value.integer.value[0], -+ uval->value.integer.value[1]); -+ -+ WARN_ON(!uval); -+ WARN_ON(!kcontrol); -+ -+ intelmaddata = kcontrol->private_data; -+ -+ WARN_ON(!intelmaddata->sstdrv_ops); -+ -+ scard_ops = intelmaddata->sstdrv_ops->scard_ops; -+ -+ WARN_ON(!scard_ops); -+ -+ switch (kcontrol->id.numid) { -+ case PLAYBACK_VOL: -+ cntl_list[0] = PMIC_SND_LEFT_PB_VOL; -+ cntl_list[1] = PMIC_SND_RIGHT_PB_VOL; -+ break; -+ -+ case CAPTURE_VOL: -+ cntl_list[0] = PMIC_SND_CAPTURE_VOL; -+ break; -+ default: -+ return -EINVAL; -+ } -+ -+ ret_val = scard_ops->set_vol(cntl_list[0], -+ uval->value.integer.value[0]); -+ if (ret_val) -+ return ret_val; -+ -+ if (kcontrol->id.numid == PLAYBACK_VOL) -+ ret_val = scard_ops->set_vol(cntl_list[1], -+ uval->value.integer.value[1]); -+ return ret_val; -+} -+ -+/** -+* snd_intelmad_mute_set - sets the mute control's info -+* @kcontrol: pointer to the control -+* @uval: pointer to the structure where the control's info is -+* available to be set -+* This function is called when .set function of a control is invoked from app -+*/ -+static int snd_intelmad_mute_set(struct snd_kcontrol *kcontrol, -+ struct snd_ctl_elem_value *uval) -+{ -+ int cntl_list[2] = {0,}, ret_val; -+ struct snd_intelmad *intelmaddata; -+ struct snd_pmic_ops *scard_ops; -+ -+ printk(KERN_DEBUG "SST DBG:called\n"); -+ -+ WARN_ON(!uval); -+ WARN_ON(!kcontrol); -+ -+ intelmaddata = kcontrol->private_data; -+ -+ WARN_ON(!intelmaddata->sstdrv_ops); -+ -+ scard_ops = intelmaddata->sstdrv_ops->scard_ops; -+ -+ WARN_ON(!scard_ops); -+ -+ kcontrol->private_value = uval->value.integer.value[0]; -+ -+ switch (kcontrol->id.numid) { -+ case PLAYBACK_MUTE: -+ if (intelmaddata->output_sel == STEREO_HEADPHONE) { -+ cntl_list[0] = PMIC_SND_LEFT_HP_MUTE; -+ cntl_list[1] = PMIC_SND_RIGHT_HP_MUTE; -+ } else if (intelmaddata->output_sel == INTERNAL_SPKR) { -+ cntl_list[0] = PMIC_SND_LEFT_SPEAKER_MUTE; -+ cntl_list[1] = PMIC_SND_RIGHT_SPEAKER_MUTE; -+ } -+ break; -+ -+ case CAPTURE_MUTE:/*based on sel device mute the i/p dev*/ -+ if (intelmaddata->input_sel == DMIC) -+ cntl_list[0] = PMIC_SND_DMIC_MUTE; -+ else if (intelmaddata->input_sel == AMIC) -+ cntl_list[0] = PMIC_SND_AMIC_MUTE; -+ else if (intelmaddata->input_sel == HS_MIC) -+ cntl_list[0] = PMIC_SND_HP_MIC_MUTE; -+ break; -+ case MASTER_MUTE: -+ cntl_list[0] = PMIC_SND_MUTE_ALL; -+ intelmaddata->master_mute = uval->value.integer.value[0]; -+ break; -+ default: -+ return -EINVAL; -+ } -+ -+ ret_val = scard_ops->set_mute(cntl_list[0], -+ uval->value.integer.value[0]); -+ if (ret_val) -+ return ret_val; -+ -+ if (kcontrol->id.numid == PLAYBACK_MUTE) -+ ret_val = scard_ops->set_mute(cntl_list[1], -+ uval->value.integer.value[0]); -+ return ret_val; -+} -+ -+/** -+* snd_intelmad_device_get - get the device select control's info -+* @kcontrol: pointer to the control -+* @uval: pointer to the structure where the control's info is -+* to be filled -+* This function is called when .get function of a control is invoked from app -+*/ -+static int snd_intelmad_device_get(struct snd_kcontrol *kcontrol, -+ struct snd_ctl_elem_value *uval) -+{ -+ printk(KERN_DEBUG "SST DBG:called\n"); -+ -+ WARN_ON(!uval); -+ WARN_ON(!kcontrol); -+ -+ uval->value.enumerated.item[0] = kcontrol->private_value; -+ return 0; -+} -+ -+/** -+* snd_intelmad_device_set - set the device select control's info -+* @kcontrol: pointer to the control -+* @uval: pointer to the structure where the control's info is -+* available to be set -+* This function is called when .set function of a control is invoked from app -+*/ -+static int snd_intelmad_device_set(struct snd_kcontrol *kcontrol, -+ struct snd_ctl_elem_value *uval) -+{ -+ struct snd_intelmad *intelmaddata; -+ struct snd_pmic_ops *scard_ops; -+ int ret_val = 0, vendor, status; -+ -+ printk(KERN_DEBUG "SST DBG:called\n"); -+ -+ WARN_ON(!uval); -+ WARN_ON(!kcontrol); -+ status = -1; -+ -+ intelmaddata = kcontrol->private_data; -+ -+ WARN_ON(!intelmaddata->sstdrv_ops); -+ -+ scard_ops = intelmaddata->sstdrv_ops->scard_ops; -+ -+ WARN_ON(!scard_ops); -+ -+ /* store value with driver */ -+ kcontrol->private_value = uval->value.enumerated.item[0]; -+ -+ switch (kcontrol->id.numid) { -+ case OUTPUT_SEL: -+ ret_val = scard_ops->set_output_dev( -+ uval->value.enumerated.item[0]); -+ intelmaddata->output_sel = uval->value.enumerated.item[0]; -+ break; -+ case INPUT_SEL: -+ vendor = intelmaddata->sstdrv_ops->vendor_id; -+ if ((vendor == SND_MX) || (vendor == SND_FS )) { -+ if(uval->value.enumerated.item[0] == HS_MIC) { -+ status = 1; -+ intelmaddata->sstdrv_ops->control_set(SST_ENABLE_RX_TIME_SLOT, &status); -+ } -+ else { -+ status = 0; -+ intelmaddata->sstdrv_ops->control_set(SST_ENABLE_RX_TIME_SLOT, &status); -+ } -+ } -+ ret_val = scard_ops->set_input_dev( -+ uval->value.enumerated.item[0]); -+ intelmaddata->input_sel = uval->value.enumerated.item[0]; -+ break; -+ default: -+ return -EINVAL; -+ } -+ kcontrol->private_value = uval->value.enumerated.item[0]; -+ return ret_val; -+} -+ -+struct snd_kcontrol_new snd_intelmad_controls[MAX_CTRL] __devinitdata = { -+{ -+ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, -+ .name = "PCM Playback Volume", -+ .access = SNDRV_CTL_ELEM_ACCESS_READWRITE, -+ .info = snd_intelmad_playback_volume_info, -+ .get = snd_intelmad_volume_get, -+ .put = snd_intelmad_volume_set, -+ .private_value = 0, -+}, -+{ -+ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, -+ .name = "PCM Playback Switch", -+ .access = SNDRV_CTL_ELEM_ACCESS_READWRITE, -+ .info = snd_intelmad_mute_info, -+ .get = snd_intelmad_mute_get, -+ .put = snd_intelmad_mute_set, -+ .private_value = 0, -+}, -+{ -+ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, -+ .name = "PCM Capture Volume", -+ .access = SNDRV_CTL_ELEM_ACCESS_READWRITE, -+ .info = snd_intelmad_capture_volume_info, -+ .get = snd_intelmad_volume_get, -+ .put = snd_intelmad_volume_set, -+ .private_value = 0, -+}, -+{ -+ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, -+ .name = "PCM Capture Switch", -+ .access = SNDRV_CTL_ELEM_ACCESS_READWRITE, -+ .info = snd_intelmad_mute_info, -+ .get = snd_intelmad_mute_get, -+ .put = snd_intelmad_mute_set, -+ .private_value = 0, -+}, -+{ -+ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, -+ .name = "PCM Playback Source", -+ .access = SNDRV_CTL_ELEM_ACCESS_READWRITE, -+ .info = snd_intelmad_device_info, -+ .get = snd_intelmad_device_get, -+ .put = snd_intelmad_device_set, -+ .private_value = 0, -+}, -+{ -+ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, -+ .name = "PCM Capture Source", -+ .access = SNDRV_CTL_ELEM_ACCESS_READWRITE, -+ .info = snd_intelmad_device_info, -+ .get = snd_intelmad_device_get, -+ .put = snd_intelmad_device_set, -+ .private_value = 0, -+}, -+{ -+ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, -+ .name = "Master Playback Switch", -+ .access = SNDRV_CTL_ELEM_ACCESS_READWRITE, -+ .info = snd_intelmad_mute_info, -+ .get = snd_intelmad_mute_get, -+ .put = snd_intelmad_mute_set, -+ .private_value = 0, -+}, -+}; -diff --git a/sound/pci/sst/intelmid_ctrl.h b/sound/pci/sst/intelmid_ctrl.h -new file mode 100644 -index 0000000..fa5feaf ---- /dev/null -+++ b/sound/pci/sst/intelmid_ctrl.h -@@ -0,0 +1,33 @@ -+/* -+ * intelmid_ctrl.h - Intel Sound card driver for MID -+ * -+ * Copyright (C) 2008-10 Intel Corp -+ * Authors: Harsha Priya <priya.harsha@intel.com> -+ * Vinod Koul <vinod.koul@intel.com> -+ * KP Jeeja <jeeja.kp@intel.com> -+ * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License as published by -+ * the Free Software Foundation version 2 of the License. -+ * -+ * This program is distributed in the hope that it will be useful, but -+ * WITHOUT ANY WARRANTY; without even the implied warranty of -+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -+ * General Public License for more details. -+ * -+ * You should have received a copy of the GNU General Public License along -+ * with this program; if not, write to the Free Software Foundation, Inc., -+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. -+ * -+ * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -+ * ALSA driver header file for handling mixer controls for Intel MAD chipset -+ */ -+#ifndef __INTELMID_CTRL_H -+#define __INTELMID_CTRL_H -+ -+extern struct snd_control_val intelmad_ctrl_val[]; -+extern struct snd_kcontrol_new snd_intelmad_controls[]; -+extern struct snd_pmic_ops *intelmad_vendor_ops[]; -+ -+#endif /*__INTELMID_CTRL_H*/ -diff --git a/sound/pci/sst/intelmid_pvt.c b/sound/pci/sst/intelmid_pvt.c -new file mode 100644 -index 0000000..1dd00c3 ---- /dev/null -+++ b/sound/pci/sst/intelmid_pvt.c -@@ -0,0 +1,343 @@ -+/* -+ * intelmid_pvt.h - Intel Sound card driver for MID -+ * -+ * Copyright (C) 2008-10 Intel Corp -+ * Authors: Harsha Priya <priya.harsha@intel.com> -+ * Vinod Koul <vinod.koul@intel.com> -+ * KP Jeeja <jeeja.kp@intel.com> -+ * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License as published by -+ * the Free Software Foundation; version 2 of the License. -+ * -+ * This program is distributed in the hope that it will be useful, but -+ * WITHOUT ANY WARRANTY; without even the implied warranty of -+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -+ * General Public License for more details. -+ * -+ * You should have received a copy of the GNU General Public License along -+ * with this program; if not, write to the Free Software Foundation, Inc., -+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. -+ * -+ * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -+ * ALSA driver for Intel MID sound card chipset - holding private functions -+ */ -+#include <linux/spi/spi.h> -+#include <linux/io.h> -+#include <linux/delay.h> -+#include <linux/interrupt.h> -+#include <linux/init.h> -+#include <linux/slab.h> -+#include <linux/moduleparam.h> -+#include <linux/sched.h> -+#include <asm/ipc_defs.h> -+#include <sound/core.h> -+#include <sound/control.h> -+#include <sound/pcm.h> -+#include <sound/jack.h> -+#include <sound/pcm_params.h> -+#include <sound/info.h> -+#include <sound/initval.h> -+#include <sound/pcm-indirect.h> -+#include <sound/intel_lpe.h> -+#include <sound/intel_sst_ioctl.h> -+#include "intelmid_snd_control.h" -+#include "intelmid.h" -+ -+ -+/*static unsigned int audio_event_seqnum; -+static struct genl_family audio_event_genl_family = { -+ .id = GENL_ID_GENERATE, -+ .name = "audio events", -+ .version = 0x01, -+ .maxattr = 0, -+}; -+ -+static struct genl_multicast_group audio_event_mcgrp = { -+ .name = "audio_group", -+}; -+*/ -+ -+void period_elapsed(void *mad_substream) -+{ -+ struct snd_pcm_substream *substream = mad_substream; -+ struct mad_stream_pvt *stream; -+ -+ if (!substream || !substream->runtime) -+ return; -+ stream = substream->runtime->private_data; -+ if (!stream) -+ return; -+ -+// printk(KERN_DEBUG "SST DBG:called\n"); -+ if (stream->stream_status != RUNNING) -+ return; -+// printk(KERN_DEBUG "SST DBG:calling period elapsed\n"); -+ snd_pcm_period_elapsed(substream); -+ return; -+} -+ -+ -+int snd_intelmad_alloc_stream(struct snd_pcm_substream *substream) -+{ -+ struct snd_intelmad *intelmaddata = snd_pcm_substream_chip(substream); -+ struct mad_stream_pvt *stream = substream->runtime->private_data; -+ unsigned int bits_per_sec = (substream->runtime->sample_bits/8) -+ * (substream->runtime->channels) -+ * (substream->runtime->rate); -+ struct snd_sst_stream_params param = {{{0,},},}; -+ struct snd_sst_params str_params = {0}; -+ int ret_val; -+ -+ /* set codec params and inform SST driver the same */ -+ -+ param.uc.pcm_params.codec = SST_CODEC_TYPE_PCM; -+ param.uc.pcm_params.brate = bits_per_sec; -+ param.uc.pcm_params.num_chan = (u8) substream->runtime->channels; -+ param.uc.pcm_params.sfreq = substream->runtime->rate; -+ param.uc.pcm_params.pcm_wd_sz = substream->runtime->sample_bits; -+// param.uc.pcm_params.frame_size = 0; -+// param.uc.pcm_params.samples_per_frame = 250; /* FIXME */ -+ param.uc.pcm_params.buffer_size = substream->runtime->buffer_size; -+ param.uc.pcm_params.period_count = substream->runtime->period_size; -+ printk(KERN_DEBUG "SST DBG:period_count +\ -+ = %d\n", param.uc.pcm_params.period_count); -+ printk(KERN_DEBUG "SST DBG:sfreq= %d, wd_sz = %d\n", +\ -+ param.uc.pcm_params.sfreq, param.uc.pcm_params.pcm_wd_sz); -+ -+ str_params.sparams = param; -+ str_params.codec = SST_CODEC_TYPE_PCM; -+ -+ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) -+ str_params.ops = STREAM_OPS_PLAYBACK; -+ else -+ str_params.ops = STREAM_OPS_CAPTURE; -+ ret_val = intelmaddata->sstdrv_ops->control_set(SST_SND_ALLOC, -+ &str_params); -+ printk(KERN_DEBUG "SST DBG:SST_SND_PLAY/CAPTURE ret_val = %x\n", -+ ret_val); -+ if (ret_val < 0) -+ return ret_val; -+ -+ stream->stream_info.str_id = ret_val; -+ stream->stream_status = INIT; -+ stream->stream_info.buffer_ptr = 0; -+ printk(KERN_DEBUG "SST DBG:str id : %d\n", stream->stream_info.str_id); -+ -+ return ret_val; -+} -+ -+int snd_intelmad_init_stream(struct snd_pcm_substream *substream) -+{ -+ struct mad_stream_pvt *stream = substream->runtime->private_data; -+ struct snd_intelmad *intelmaddata = snd_pcm_substream_chip(substream); -+ int ret_val; -+ -+ printk(KERN_DEBUG "SST DBG:setting buffer ptr param\n"); -+ stream->stream_info.period_elapsed = period_elapsed; -+ stream->stream_info.mad_substream = substream; -+ stream->stream_info.buffer_ptr = 0; -+ stream->stream_info.sfreq = substream->runtime->rate; -+ ret_val = intelmaddata->sstdrv_ops->control_set(SST_SND_STREAM_INIT, -+ &stream->stream_info); -+ if (ret_val) -+ dev_err(&intelmaddata->spi->dev,\ -+ "SST ERR: error code = %d \n", ret_val); -+ return ret_val; -+ -+} -+ -+void send_buffer_to_sst(struct snd_pcm_substream *substream, -+ struct snd_pcm_indirect *rec, size_t bytes) -+{ -+ struct snd_intelmad *intelmaddata = snd_pcm_substream_chip(substream); -+ struct mad_stream_pvt *stream = substream->runtime->private_data; -+ struct stream_buffer buffer_to_sst = {0,}; -+ int ret_val; -+ -+ /* sends data to SST to be processed */ -+ stream->dbg_cum_bytes += bytes; -+ printk(KERN_DEBUG "SST DBG:bytes = %d \n", bytes); -+ printk(KERN_DEBUG "SST DBG:cum_bytes +\ -+ = 0x%x, \n", stream->dbg_cum_bytes); -+ buffer_to_sst.length = bytes; -+ buffer_to_sst.addr = (unsigned long) substream->runtime->dma_area + -+ rec->sw_data; -+ /* SST API to actually send the buffer to be played */ -+ ret_val = intelmaddata->sstdrv_ops->send_buffer( -+ stream->stream_info.str_id, -+ &buffer_to_sst); -+ printk(KERN_DEBUG "SST DBG:send_buffer +\ -+ ret_val = 0x%x \n", ret_val); -+ return; -+} -+ -+/*int snd_intelmad_generate_netlink(u32 orig, enum eaudio_events event) -+{ -+ struct sk_buff *skb = NULL; -+ struct nlattr *attr = NULL; -+ struct audio_genl_event *aud_event = NULL; -+ void *msg_header = NULL; -+ int size = 0, ret_val = 0; -+ -+ -+ size = nla_total_size(sizeof(struct audio_genl_event)) + \ -+ nla_total_size(0); -+ -+ skb = genlmsg_new(size, GFP_ATOMIC); -+ if (!skb) -+ return -ENOMEM; -+ -+ -+ msg_header = genlmsg_put(skb, 0, audio_event_seqnum++, -+ &audio_event_genl_family, 0, -+ AUDIO_GENL_CMD_EVENT); -+ if (!msg_header) { -+ nlmsg_free(skb); -+ return -ENOMEM; -+ } -+ -+ attr = nla_reserve(skb, AUDIO_GENL_ATTR_EVENT, \ -+ sizeof(struct audio_genl_event)); -+ -+ if (!attr) { -+ nlmsg_free(skb); -+ return -EINVAL; -+ } -+ -+ aud_event = nla_data(attr); -+ if (!aud_event) { -+ nlmsg_free(skb); -+ return -EINVAL; -+ } -+ -+ memset(aud_event, 0, sizeof(struct audio_genl_event)); -+ -+ aud_event->orig = orig; -+ aud_event->event = event; -+ -+ -+ ret_val = genlmsg_end(skb, msg_header); -+ if (ret_val < 0) { -+ nlmsg_free(skb); -+ return ret_val; -+ } -+ -+ ret_val = genlmsg_multicast(skb, 0, audio_event_mcgrp.id, GFP_ATOMIC); -+ -+ if (ret_val) -+ printk(KERN_INFO "Failed to send a Genetlink message!\n"); -+ return 0; -+}*/ -+ -+ -+/** -+* Reads/writes/read-modify operations on registers accessed through SCU (sound -+* card and few SST DSP regsiters that are not accissible to IA) -+*/ -+int sst_sc_reg_access(struct sc_reg_access *sc_access, -+ int type, int num_val) -+{ -+ int i, retval = 0, j = 0, k = 0, count = 0; -+ struct ipc_pmic_reg_data reg_data; -+ struct ipc_pmic_mod_reg_data pmic_mod_reg = {0}; -+ -+ reg_data.ioc = TRUE; -+ if (type == PMIC_WRITE) { -+ do { -+ int max_retries = 0; -+ -+ if (num_val <= 4) -+ count = num_val; -+ else -+ count = 4; -+retry_write: -+ for (i = 0; i < count; i++, j++) { -+ reg_data.pmic_reg_data[i]. -+ register_address = sc_access[j].reg_addr; -+ -+ reg_data.pmic_reg_data[i].value = -+ sc_access[j].value; -+ } -+ reg_data.num_entries = (u8) count; -+ retval = ipc_pmic_register_write(®_data, 0); -+ if (retval == E_NO_INTERRUPT_ON_IOC && -+ max_retries < 10) { -+ printk(KERN_ERR "SST ERR: write communcation needs retry \n"); -+ max_retries++; -+ goto retry_write; -+ } -+ if (0 != retval) { -+ printk(KERN_ERR "SST ERR: pmic write failed \n"); -+ return retval; -+ } -+ num_val -= count; -+ } while (num_val > 0); -+ } else if (type == PMIC_READ) { -+ do { -+ int max_retries = 0; -+ if (num_val <= 4) -+ count = num_val; -+ else -+ count = 4; -+retry_read: -+ for (i = 0; i < count; i++, j++) -+ reg_data.pmic_reg_data[i].register_address -+ = sc_access[j].reg_addr; -+ reg_data.num_entries = count; -+ retval = ipc_pmic_register_read(®_data); -+ if (retval == E_NO_INTERRUPT_ON_IOC && -+ max_retries < 10) { -+ printk(KERN_ERR "ERR: read communcation needs retry \n"); -+ max_retries++; -+ goto retry_read; -+ } -+ if (0 != retval) { -+ printk(KERN_ERR "ERR: pmic read failed \n"); -+ return retval; -+ } -+ -+ for (i = 0; i < count; i++, k++) -+ sc_access[k].value = -+ reg_data.pmic_reg_data[i].value; -+ num_val -= count; -+ } while (num_val > 0); -+ } else { -+ pmic_mod_reg.ioc = TRUE; -+ do { -+ int max_retries = 0; -+ if (num_val <= 4) -+ count = num_val; -+ else -+ count = 4; -+retry_readmod: -+ for (i = 0; i < count; i++, j++) { -+ pmic_mod_reg.pmic_mod_reg_data[i]. -+ register_address = sc_access[j].reg_addr; -+ pmic_mod_reg.pmic_mod_reg_data[i].value = -+ sc_access[j].value; -+ pmic_mod_reg.pmic_mod_reg_data[i].bit_map = -+ sc_access[j].mask; -+ } -+ pmic_mod_reg.num_entries = count; -+ printk(KERN_DEBUG "SST DBG:read_modify +\ -+ called for cnt = %d\n", count); -+ retval = ipc_pmic_register_read_modify(&pmic_mod_reg); -+ if (retval == E_NO_INTERRUPT_ON_IOC && -+ max_retries < 10) { -+ printk(KERN_ERR "SST ERR: read/modify retry \n"); -+ max_retries++; -+ goto retry_readmod; -+ } -+ if (0 != retval) { -+ /* pmic communication fails */ -+ printk(KERN_ERR "SST ERR: pmic read_modify failed \n"); -+ return retval; -+ } -+ num_val -= count; -+ } while (num_val > 0); -+ } -+ return retval; -+} -+ --- -1.6.2.2 - |