175 lines
5.3 KiB
C
175 lines
5.3 KiB
C
/*
|
|
* 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
|
|
*/
|
|
|
|
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
|
|
|
|
#include <linux/io.h>
|
|
#include <asm/intel_scu_ipc.h>
|
|
#include <sound/core.h>
|
|
#include <sound/control.h>
|
|
#include <sound/pcm.h>
|
|
#include "jack.h"
|
|
#include "intel_sst.h"
|
|
#include "intel_sst_ioctl.h"
|
|
#include "intelmid_snd_control.h"
|
|
#include "intelmid.h"
|
|
|
|
|
|
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;
|
|
|
|
if (stream->stream_status != RUNNING)
|
|
return;
|
|
pr_debug("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;
|
|
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.num_chan = (u8) substream->runtime->channels;
|
|
param.uc.pcm_params.pcm_wd_sz = substream->runtime->sample_bits;
|
|
param.uc.pcm_params.reserved = 0;
|
|
param.uc.pcm_params.sfreq = substream->runtime->rate;
|
|
param.uc.pcm_params.ring_buffer_size =
|
|
snd_pcm_lib_buffer_bytes(substream);
|
|
param.uc.pcm_params.period_count = substream->runtime->period_size;
|
|
param.uc.pcm_params.ring_buffer_addr =
|
|
virt_to_phys(substream->runtime->dma_area);
|
|
pr_debug("period_cnt = %d\n", param.uc.pcm_params.period_count);
|
|
pr_debug("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;
|
|
pr_debug("Playbck stream,Device %d\n", stream->device);
|
|
} else {
|
|
str_params.ops = STREAM_OPS_CAPTURE;
|
|
stream->device = SND_SST_DEVICE_CAPTURE;
|
|
pr_debug("Capture stream,Device %d\n", stream->device);
|
|
}
|
|
str_params.device_type = stream->device;
|
|
ret_val = intelmaddata->sstdrv_ops->pcm_control->open(&str_params);
|
|
pr_debug("sst: 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;
|
|
pr_debug("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;
|
|
|
|
pr_debug("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->pcm_control->device_control(
|
|
SST_SND_STREAM_INIT, &stream->stream_info);
|
|
if (ret_val)
|
|
pr_err("control_set ret error %d\n", ret_val);
|
|
return ret_val;
|
|
|
|
}
|
|
|
|
|
|
/**
|
|
* sst_sc_reg_access - IPC read/write wrapper
|
|
*
|
|
* @sc_access: array of data, addresses and mask
|
|
* @type: operation type
|
|
* @num_val: number of reg to opertae on
|
|
*
|
|
* Reads/writes/read-modify operations on registers accessed through SCU (sound
|
|
* card and few SST DSP regsisters 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;
|
|
if (type == PMIC_WRITE) {
|
|
for (i = 0; i < num_val; i++) {
|
|
retval = intel_scu_ipc_iowrite8(sc_access[i].reg_addr,
|
|
sc_access[i].value);
|
|
if (retval)
|
|
goto err;
|
|
}
|
|
} else if (type == PMIC_READ) {
|
|
for (i = 0; i < num_val; i++) {
|
|
retval = intel_scu_ipc_ioread8(sc_access[i].reg_addr,
|
|
&(sc_access[i].value));
|
|
if (retval)
|
|
goto err;
|
|
}
|
|
} else {
|
|
for (i = 0; i < num_val; i++) {
|
|
retval = intel_scu_ipc_update_register(
|
|
sc_access[i].reg_addr, sc_access[i].value,
|
|
sc_access[i].mask);
|
|
if (retval)
|
|
goto err;
|
|
}
|
|
}
|
|
return 0;
|
|
err:
|
|
pr_err("IPC failed for cmd %d, %d\n", retval, type);
|
|
pr_err("reg:0x%2x addr:0x%2x\n",
|
|
sc_access[i].reg_addr, sc_access[i].value);
|
|
return retval;
|
|
}
|