Commit 66e46386 authored by Pavel Machek's avatar Pavel Machek Committed by Tony Lindgren

ALSA: sx1 mixer support

From: Vladimir Ananiev <vovan888@gmail.com>

Support mixer on Siemens SX1. Supporting mixer is quite important,
because it allows doing voice calls, and SX1 is a telephone after all.
Signed-off-by: default avatarPavel Machek <pavel@suse.cz>
Signed-off-by: default avatarTony Lindgren <tony@atomide.com>
parent c608ff06
......@@ -63,6 +63,17 @@ config SND_OMAP_TSC2101
To compile this driver as a module, choose M here: the module
will be called snd-omap-tsc2101.
config SND_SX1
tristate "Siemens SX1 Egold alsa driver"
depends on ARCH_OMAP && SND
select SND_PCM
select OMAP_MCBSP
help
Say Y here if you have a OMAP310 based Siemens SX1.
To compile this driver as a module, choose M here: the module
will be called snd-omap-sx1.
config SND_OMAP_TSC2102
tristate "OMAP TSC2102 alsa driver"
depends on ARCH_OMAP && SND
......
......@@ -10,3 +10,6 @@ snd-omap-alsa-tsc2101-objs := omap-alsa.o omap-alsa-dma.o omap-alsa-tsc2101.o om
obj-$(CONFIG_SND_OMAP_TSC2102) += snd-omap-alsa-tsc2102.o
snd-omap-alsa-tsc2102-objs := omap-alsa.o omap-alsa-dma.o omap-alsa-tsc2102.o omap-alsa-tsc2102-mixer.o
obj-$(CONFIG_SND_SX1) += snd-omap-alsa-sx1.o
snd-omap-alsa-sx1-objs := omap-alsa.o omap-alsa-dma.o omap-alsa-sx1.o omap-alsa-sx1-mixer.o
This diff is collapsed.
/*
* sound/arm/omap/omap-alsa-sx1-mixer.h
*
* Alsa codec Driver for Siemens SX1 board.
* based on omap-alsa-tsc2101-mixer.c
*
* Copyright (C) 2006 Vladimir Ananiev (vovan888 at gmail 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; either version 2 of the License, or (at your
* option) any later version.
*
* 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.,
* 675 Mass Ave, Cambridge, MA 02139, USA.
*
*/
#ifndef OMAPALSATSC2101MIXER_H_
#define OMAPALSATSC2101MIXER_H_
#include "omap-alsa-dma.h"
#define PLAYBACK_TARGET_COUNT 0x03
#define PLAYBACK_TARGET_LOUDSPEAKER 0x00
#define PLAYBACK_TARGET_HEADPHONE 0x01
#define PLAYBACK_TARGET_CELLPHONE 0x02
/* following are used for register 03h Mixer PGA control bits D7-D5 for selecting record source */
#define REC_SRC_TARGET_COUNT 0x08
#define REC_SRC_SINGLE_ENDED_MICIN_HED 0x00 /* oss code referred to MIXER_LINE */
#define REC_SRC_SINGLE_ENDED_MICIN_HND 0x01 /* oss code referred to MIXER_MIC */
#define REC_SRC_SINGLE_ENDED_AUX1 0x02
#define REC_SRC_SINGLE_ENDED_AUX2 0x03
#define REC_SRC_MICIN_HED_AND_AUX1 0x04
#define REC_SRC_MICIN_HED_AND_AUX2 0x05
#define REC_SRC_MICIN_HND_AND_AUX1 0x06
#define REC_SRC_MICIN_HND_AND_AUX2 0x07
#define DEFAULT_OUTPUT_VOLUME 5 /* default output volume to dac dgc */
#define DEFAULT_INPUT_VOLUME 2 /* default record volume */
#endif
/*
* arch/arm/mach-omap1/omap-alsa-sx1.c
*
* Alsa codec Driver for Siemens SX1 board.
* based on omap-alsa-tsc2101.c and cn_test.c example by Evgeniy Polyakov
*
* Copyright (C) 2006 Vladimir Ananiev (vovan888 at gmail 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; either version 2 of the License, or (at your
* option) any later version.
*/
#include <linux/delay.h>
#include <linux/soundcard.h>
#include <linux/platform_device.h>
#include <linux/clk.h>
#include <asm/io.h>
#include <asm/arch/mcbsp.h>
#include <linux/slab.h>
#include <linux/pm.h>
#include <asm/mach-types.h>
#include <asm/arch/dma.h>
#include <asm/arch/clock.h>
#include <asm/arch/gpio.h>
#include <asm/arch/omap-alsa.h>
#include "omap-alsa-sx1.h"
#include <linux/connector.h>
/* Connector implementation */
static struct cb_id cn_sx1snd_id = { CN_IDX_SX1SND, CN_VAL_SX1SND };
static char cn_sx1snd_name[] = "cn_sx1snd";
static void cn_sx1snd_callback(void *data)
{
struct cn_msg *msg = (struct cn_msg *)data;
printk("%s: %lu: idx=%x, val=%x, seq=%u, ack=%u, len=%d: %s.\n",
__func__, jiffies, msg->id.idx, msg->id.val,
msg->seq, msg->ack, msg->len, (char *)msg->data);
}
/* Send IPC message to sound server */
int cn_sx1snd_send(unsigned int cmd, unsigned int arg1, unsigned int arg2)
{
struct cn_msg *m;
unsigned short data[3];
int err;
m = kzalloc(sizeof(*m) + sizeof(data), gfp_any());
if (!m)
return -1;
memcpy(&m->id, &cn_sx1snd_id, sizeof(m->id));
m->seq = 1;
m->len = sizeof(data);
data[0] = (unsigned short)cmd;
data[1] = (unsigned short)arg1;
data[2] = (unsigned short)arg2;
memcpy(m + 1, data, m->len);
err = cn_netlink_send(m, CN_IDX_SX1SND, gfp_any());
snd_printd("sent= %02X %02X %02X, err=%d\n", cmd,arg1,arg2,err);
kfree(m);
if (err == -ESRCH)
return -1; /* there are no listeners on socket */
return 0;
}
/* Hardware capabilities
*
* DAC USB-mode sampling rates (MCLK = 12 MHz)
* The rates and rate_reg_into MUST be in the same order
*/
static unsigned int rates[] = {
8000, 11025, 12000,
16000, 22050, 24000,
32000, 44100, 48000,
};
static snd_pcm_hw_constraint_list_t egold_hw_constraints_rates = {
.count = ARRAY_SIZE(rates),
.list = rates,
.mask = 0,
};
static snd_pcm_hardware_t egold_snd_omap_alsa_playback = {
.info = (SNDRV_PCM_INFO_INTERLEAVED | SNDRV_PCM_INFO_BLOCK_TRANSFER |
SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_MMAP_VALID),
.formats = (SNDRV_PCM_FMTBIT_S16_LE),
.rates = (SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_11025 |
SNDRV_PCM_RATE_16000 |
SNDRV_PCM_RATE_22050 | SNDRV_PCM_RATE_32000 |
SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000 |
SNDRV_PCM_RATE_KNOT),
.rate_min = 8000,
.rate_max = 48000,
.channels_min = 2,
.channels_max = 2,
.buffer_bytes_max = 128 * 1024,
.period_bytes_min = 32,
.period_bytes_max = 8 * 1024,
.periods_min = 16,
.periods_max = 255,
.fifo_size = 0,
};
static snd_pcm_hardware_t egold_snd_omap_alsa_capture = {
.info = (SNDRV_PCM_INFO_INTERLEAVED | SNDRV_PCM_INFO_BLOCK_TRANSFER |
SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_MMAP_VALID),
.formats = (SNDRV_PCM_FMTBIT_S16_LE),
.rates = (SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_11025 |
SNDRV_PCM_RATE_16000 |
SNDRV_PCM_RATE_22050 | SNDRV_PCM_RATE_32000 |
SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000 |
SNDRV_PCM_RATE_KNOT),
.rate_min = 8000,
.rate_max = 48000,
.channels_min = 2,
.channels_max = 2,
.buffer_bytes_max = 128 * 1024,
.period_bytes_min = 32,
.period_bytes_max = 8 * 1024,
.periods_min = 16,
.periods_max = 255,
.fifo_size = 0,
};
static long current_rate = -1; /* current rate in egold format 0..8 */
/*
* ALSA operations according to board file
*/
/*
* Sample rate changing
*/
static void egold_set_samplerate(long sample_rate)
{
int egold_rate = 0;
int clkgdv = 0;
u16 srgr1, srgr2;
/* Set the sample rate */
#if 0
/* fw15: 5005E490 - divs are different !!! */
clkgdv = CODEC_CLOCK / (sample_rate * (DEFAULT_BITPERSAMPLE * 2 - 1));
#endif
switch (sample_rate) {
case 8000: clkgdv = 71; egold_rate = FRQ_8000; break;
case 11025: clkgdv = 51; egold_rate = FRQ_11025; break;
case 12000: clkgdv = 47; egold_rate = FRQ_12000; break;
case 16000: clkgdv = 35; egold_rate = FRQ_16000; break;
case 22050: clkgdv = 25; egold_rate = FRQ_22050; break;
case 24000: clkgdv = 23; egold_rate = FRQ_24000; break;
case 32000: clkgdv = 17; egold_rate = FRQ_32000; break;
case 44100: clkgdv = 12; egold_rate = FRQ_44100; break;
case 48000: clkgdv = 11; egold_rate = FRQ_48000; break;
}
srgr1 = (FWID(DEFAULT_BITPERSAMPLE - 1) | CLKGDV(clkgdv));
srgr2 = ((FSGM | FPER(DEFAULT_BITPERSAMPLE * 2 - 1)));
OMAP_MCBSP_WRITE(OMAP1510_MCBSP1_BASE, SRGR2, srgr2);
OMAP_MCBSP_WRITE(OMAP1510_MCBSP1_BASE, SRGR1, srgr1);
current_rate = egold_rate;
snd_printd("set samplerate=%ld\n", sample_rate);
}
static void egold_configure(void)
{
}
/*
* Omap MCBSP clock and Power Management configuration
*
* Here we have some functions that allows clock to be enabled and
* disabled only when needed. Besides doing clock configuration
* it allows turn on/turn off audio when necessary.
*/
/*
* Do clock framework mclk search
*/
static void egold_clock_setup(void)
{
omap_request_gpio(OSC_EN);
omap_set_gpio_direction(OSC_EN, 0); /* output */
snd_printd("\n");
}
/*
* Do some sanity check, set clock rate, starts it and turn codec audio on
*/
static int egold_clock_on(void)
{
omap_set_gpio_dataout(OSC_EN, 1);
egold_set_samplerate(44100); /* TODO */
cn_sx1snd_send(DAC_SETAUDIODEVICE, SX1_DEVICE_SPEAKER, 0);
cn_sx1snd_send(DAC_OPEN_DEFAULT, current_rate , 4);
snd_printd("\n");
return 0;
}
/*
* Do some sanity check, turn clock off and then turn codec audio off
*/
static int egold_clock_off(void)
{
cn_sx1snd_send(DAC_CLOSE, 0 , 0);
cn_sx1snd_send(DAC_SETAUDIODEVICE, SX1_DEVICE_PHONE, 0);
omap_set_gpio_dataout(OSC_EN, 0);
snd_printd("\n");
return 0;
}
static int egold_get_default_samplerate(void)
{
snd_printd("\n");
return DEFAULT_SAMPLE_RATE;
}
static int __init snd_omap_alsa_egold_probe(struct platform_device *pdev)
{
int ret;
struct omap_alsa_codec_config *codec_cfg;
codec_cfg = pdev->dev.platform_data;
if (!codec_cfg)
return -ENODEV;
codec_cfg->hw_constraints_rates = &egold_hw_constraints_rates;
codec_cfg->snd_omap_alsa_playback= &egold_snd_omap_alsa_playback;
codec_cfg->snd_omap_alsa_capture = &egold_snd_omap_alsa_capture;
codec_cfg->codec_configure_dev = egold_configure;
codec_cfg->codec_set_samplerate = egold_set_samplerate;
codec_cfg->codec_clock_setup = egold_clock_setup;
codec_cfg->codec_clock_on = egold_clock_on;
codec_cfg->codec_clock_off = egold_clock_off;
codec_cfg->get_default_samplerate = egold_get_default_samplerate;
ret = snd_omap_alsa_post_probe(pdev, codec_cfg);
snd_printd("\n");
return ret;
}
static struct platform_driver omap_alsa_driver = {
.probe = snd_omap_alsa_egold_probe,
.remove = snd_omap_alsa_remove,
.suspend = snd_omap_alsa_suspend,
.resume = snd_omap_alsa_resume,
.driver = {
.name = "omap_alsa_mcbsp",
},
};
static int __init omap_alsa_egold_init(void)
{
int retval;
retval = cn_add_callback(&cn_sx1snd_id, cn_sx1snd_name, cn_sx1snd_callback);
if (retval)
printk(KERN_WARNING "cn_sx1snd failed to register\n");
return platform_driver_register(&omap_alsa_driver);
}
static void __exit omap_alsa_egold_exit(void)
{
cn_del_callback(&cn_sx1snd_id);
platform_driver_unregister(&omap_alsa_driver);
}
module_init(omap_alsa_egold_init);
module_exit(omap_alsa_egold_exit);
/*
* arch/arc/mach-omap1/omap-alsa-sx1.h
*
* based on omap-alsa-tsc2101.h
*
* Alsa Driver for Siemens SX1.
* Copyright (C) 2006 Vladimir Ananiev (vovan888 at gmail 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; either version 2 of the License, or (at your
* option) any later version.
*/
#ifndef OMAP_ALSA_SX1_H_
#define OMAP_ALSA_SX1_H_
#include <linux/types.h>
#define NUMBER_SAMPLE_RATES_SUPPORTED 9
/*
* AUDIO related MACROS
*/
#ifndef DEFAULT_BITPERSAMPLE
#define DEFAULT_BITPERSAMPLE 16
#endif
#define DEFAULT_SAMPLE_RATE 44100
/* fw15: 18356000 */
#define CODEC_CLOCK 18359000
/* McBSP for playing music */
#define AUDIO_MCBSP OMAP_MCBSP1
/* McBSP for record/play audio from phone and mic */
#define AUDIO_MCBSP_PCM OMAP_MCBSP2
/* gpio pin for enable/disable clock */
#define OSC_EN 2
/* Send IPC message to sound server */
extern int cn_sx1snd_send(unsigned int cmd, unsigned int arg1, unsigned int arg2);
/* cmd for IPC_GROUP_DAC */
#define DAC_VOLUME_UPDATE 0
#define DAC_SETAUDIODEVICE 1
#define DAC_OPEN_RING 2
#define DAC_OPEN_DEFAULT 3
#define DAC_CLOSE 4
#define DAC_FMRADIO_OPEN 5
#define DAC_FMRADIO_CLOSE 6
#define DAC_PLAYTONE 7
/* cmd for IPC_GROUP_PCM */
#define PCM_PLAY (0+8)
#define PCM_RECORD (1+8)
#define PCM_CLOSE (2+8)
/* for DAC_SETAUDIODEVICE */
#define SX1_DEVICE_SPEAKER 0
#define SX1_DEVICE_HEADPHONE 4
#define SX1_DEVICE_PHONE 3
/* frequencies for MdaDacOpenDefaultL, MdaDacOpenRingL */
#define FRQ_8000 0
#define FRQ_11025 1
#define FRQ_12000 2
#define FRQ_16000 3
#define FRQ_22050 4
#define FRQ_24000 5
#define FRQ_32000 6
#define FRQ_44100 7
#define FRQ_48000 8
#endif
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment