Say Y or M if you want to support any AC97 codec attached to
the PXA2xx AC97 interface.
-config SND_OMAP_AIC23
- tristate "OMAP AIC23 alsa driver (osk5912)"
- depends on ARCH_OMAP && SND
- select SND_PCM
- #select I2C
- #select I2C_OMAP if ARCH_OMAP
- select SENSORS_TLV320AIC23
- help
- Say Y here if you have a OSK platform board
- and want to use its AIC23 audio chip.
-
- To compile this driver as a module, choose M here: the module
- will be called snd-omap-aic23.
-
-config SND_OMAP_TSC2101
- tristate "OMAP TSC2101 alsa driver"
- depends on ARCH_OMAP && SND
- select SND_PCM
- select SPI_TSC2101
- help
- Say Y here if you have a OMAP platform board
- and want to use its TSC2101 audio chip. Driver has
- been tested with H2 and iPAQ h6300.
-
- 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
- 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
- select SND_PCM
- select SPI_TSC2102
- help
- Say Y here if you have an OMAP platform board
- and want to use its TSC2102 audio chip.
-
- To compile this driver as a module, choose M here: the module
- will be called snd-omap-tsc2102.
-
-config SND_OMAP24XX_EAC
- tristate "Audio driver for OMAP24xx EAC"
- depends on SND
- help
- Audio driver for Enhanced Audio Controller found in TI's OMAP24xx
- processors.
-
- Currently contains only low-level support functions for
- initializing EAC HW, creating ALSA sound card instance for it
- and registering mixer controls implemented by a codec driver.
- PCM stream is expected to be under DSP co-processor control.
-
- To compile this driver as a module, choose M here: the module
- will be called snd-omap24xx-eac.
-
endif # SND_ARM
+
obj-$(CONFIG_SND_PXA2XX_AC97) += snd-pxa2xx-ac97.o
snd-pxa2xx-ac97-objs := pxa2xx-ac97.o
-
-obj-$(CONFIG_SND) += omap/
+++ /dev/null
-#
-## Makefile for ALSA OMAP
-#
-#
-obj-$(CONFIG_SND_OMAP_AIC23) += snd-omap-alsa-aic23.o
-snd-omap-alsa-aic23-objs := omap-alsa.o omap-alsa-dma.o omap-alsa-aic23.o omap-alsa-aic23-mixer.o
-
-obj-$(CONFIG_SND_OMAP_TSC2101) += snd-omap-alsa-tsc2101.o
-snd-omap-alsa-tsc2101-objs := omap-alsa.o omap-alsa-dma.o omap-alsa-tsc2101.o omap-alsa-tsc2101-mixer.o
-
-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
-
-obj-$(CONFIG_SND_OMAP24XX_EAC) += snd-omap24xx-eac.o
-snd-omap24xx-eac-objs := eac.o
+++ /dev/null
-/*
- * linux/sound/arm/omap/omap-alsa-eac.c
- *
- * OMAP24xx Enhanced Audio Controller sound driver
- *
- * Copyright (C) 2006 Nokia Corporation
- *
- * Contact: Jarkko Nikula <jarkko.nikula@nokia.com>
- * Juha Yrjölä
- *
- * Definitions:
- * Copyright (C) 2004 Texas Instruments, Inc.
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * version 2 as published by the Free Software Foundation.
- *
- * 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., 51 Franklin St, Fifth Floor, Boston, MA
- * 02110-1301 USA
- *
- */
-
-#define DEBUG
-
-#include <linux/device.h>
-#include <linux/init.h>
-#include <linux/kernel.h>
-#include <linux/err.h>
-#include <linux/module.h>
-#include <linux/moduleparam.h>
-#include <linux/delay.h>
-#include <linux/platform_device.h>
-#include <linux/clk.h>
-
-#include <asm/io.h>
-#include <mach/eac.h>
-
-#include <sound/core.h>
-#include <sound/initval.h>
-
-
-#define EAC_CPCFR1 0x0000
-#define EAC_CPCFR2 0x0004
-#define EAC_CPCFR3 0x0008
-#define EAC_CPCFR4 0x000C
-#define EAC_CPTCTL 0x0010
-#define EAC_CPTTADR 0x0014
-#define EAC_CPTDATL 0x0018
-#define EAC_CPTDATH 0x001C
-#define EAC_CPTVSLL 0x0020
-#define EAC_CPTVSLH 0x0024
-#define EAC_MPCTR 0x0040
-#define EAC_MPMCCFR 0x0044
-#define EAC_BPCTR 0x0060
-#define EAC_BPMCCFR 0x0064
-#define EAC_AMSCFR 0x0080
-#define EAC_AMVCTR 0x0084
-#define EAC_AM1VCTR 0x0088
-#define EAC_AM2VCTR 0x008C
-#define EAC_AM3VCTR 0x0090
-#define EAC_ASTCTR 0x0094
-#define EAC_APD1LCR 0x0098
-#define EAC_APD1RCR 0x009C
-#define EAC_APD2LCR 0x00A0
-#define EAC_APD2RCR 0x00A4
-#define EAC_APD3LCR 0x00A8
-#define EAC_APD3RCR 0x00AC
-#define EAC_APD4R 0x00B0
-#define EAC_ADWR 0x00B4
-#define EAC_ADRDR 0x00B8
-#define EAC_AGCFR 0x00BC
-#define EAC_AGCTR 0x00C0
-#define EAC_AGCFR2 0x00C4
-#define EAC_AGCFR3 0x00C8
-#define EAC_MBPDMACTR 0x00CC
-#define EAC_MPDDMARR 0x00D0
-#define EAC_MPDDMAWR 0x00D4
-#define EAC_MPUDMARR 0x00D8
-#define EAC_MPUDMAWR 0x00E0
-#define EAC_BPDDMARR 0x00E4
-#define EAC_BPDDMAWR 0x00E8
-#define EAC_BPUDMARR 0x00EC
-#define EAC_BPUDMAWR 0x00F0
-#define EAC_VERSION 0x0100
-#define EAC_SYSCONFIG 0x0104
-#define EAC_SYSSTATUS 0x0108
-
-/* CPTCTL */
-#define CPTCTL_RXF (1 << 7) /* receive data register full */
-#define CPTCTL_RXIE (1 << 6) /* receive interrupt enable */
-#define CPTCTL_TXE (1 << 5) /* transmit register empty */
-#define CPTCTL_TXIE (1 << 4) /* transmit interrupt enable */
-#define CPTCTL_CPEN (1 << 3) /* codec port enable */
-#define CPTCTL_CRST (1 << 0) /* external codec reset */
-
-/* CPCFR1 */
-#define CPCFR1_MTSL(val) ((val & 0x1f) << 3) /* number of time slots per frame */
-#define CPCFR1_MTSL_BITS (0x1f << 3)
-#define CPCFR1_MODE(val) ((val & 0x7) << 0) /* codec port interface mode */
-#define CPCFR1_MODE_BITS (0x7 << 0)
-
-/* CPCFR2 */
-#define CPCFR2_TSLOL(val) ((val & 0x3) << 6) /* time slot 0 length in number of serial clock (CLK_BIT) cycles */
-#define CPCFR2_TSLOL_BITS (0x3 << 6)
-#define CPCFR2_BPTSL(val) ((val & 0x7) << 3) /* number of data bits per audio time slot */
-#define CPCFR2_BPTSL_BITS (0x7 << 3)
-#define CPCFR2_TSLL(val) ((val & 0x7) << 0) /* time slot lenght (except slot 0) in number of serial clock cycles */
-#define CPCFR2_TSLL_BITS (0x7 << 0)
-
-/* CPCFR3 */
-#define CPCFR3_DDLY (1 << 7) /* data delay: data bits start according to SYNC signal leading edge */
-#define CPCFR3_TRSEN (1 << 6) /* 3-state enable: data serial output state during nonvalid audio frames */
-#define CPCFR3_CLKBP (1 << 5) /* clock polarity */
-#define CPCFR3_CSYNCP (1 << 4) /* cp_sync(synchro) polarity */
-#define CPCFR3_CSYNCL (1 << 3) /* csync length */
-/* bit 2 reserved */
-#define CPCFR3_CSCLKD (1 << 1) /* cp_sclk port (serial clock) direction */
-#define CPCFR3_CSYNCD (1 << 0) /* cp_sync (synchro) direction */
-
-/* CPCFR4 */
-#define CPCFR4_ATSL(val) ((val & 0xf) << 4) /* audio time slots for secondary communication address and data values */
-#define CPCFR4_ATSL_BITS (0xf << 4)
-#define CPCFR4_CLKS (1 << 3) /* clock source */
-#define CPCFR4_DIVB(val) ((val & 0x7) << 0) /* cp_sclk driver value */
-#define CPCFR4_DIVB_BITS (0x7 << 0)
-
-/* AGCFR */
-#define AGCFR_MN_ST (1 << 10) /* mono/stereo audio file */
-#define AGCFR_B8_16 (1 << 9) /* 8 bits/16 bits audio file */
-#define AGCFR_LI_BI (1 << 8) /* audio file endianism */
-#define AGCFR_FSINT(val) ((val & 0x3) << 6) /* intermediate sample frequency for DMA read and write operations */
-#define AGCFR_FINST_BITS (0x3 << 6)
-
-#define AGCFR_FSINT_8000 (0) /* 8000 Hz */
-#define AGCFR_FSINT_11025 (1) /* 11025 Hz */
-#define AGCFR_FSINT_22050 (2) /* 22050 Hz */
-#define AGCFR_FSINT_44100 (3) /* 44100 Hz */
-
-#define AGCFR_AUD_CKSRC(val)((val & 0x3) << 4) /* audio processing clock source */
-#define AGCFR_AUD_CKSRC_BITS (0x3 << 4)
-#define AGCFR_M_CKSRC (1 << 3) /* modem interface clock source */
-#define AGCFR_MCLK_OUT (1 << 1)
-#define AGCFR_MCLK (1 << 0)
-
-
-/* AGCTR */
-#define AGCTR_AUDRD (1 << 15) /* audio ready */
-#define AGCTR_AUDRDI (1 << 14) /* audio ready interrupt status */
-#define AGCTR_AUDRDIEN (1 << 13) /* audio ready interrupt enable */
-#define AGCTR_DMAREN (1 << 12) /* audio files play operation */
-#define AGCTR_DMAWEN (1 << 11) /* audio file record operation */
-/* bits 10:4 reserved */
-#define AGCTR_MCLK_EN (1 << 3) /* internal MCLK enable */
-#define AGCTR_OSCMCLK_EN (1 << 2) /* OSCMCLK_EN output for MCLK oscillator control */
-#define AGCTR_AUDEN (1 << 1) /* audio processing enable/disable */
-#define AGCTR_EACPWD (1 << 0) /* EAC operation */
-
-/* AGCFR2 */
-#define AGCFR2_BT_MD_WIDEBAND (1 << 5) /* the BT device and modem AuSPIs wide-band mode */
-#define AGCFR2_MCLK_I2S_N11M_12M (1 << 4) /* MCLK freq indicator for audio operations */
-#define AGCFR2_I2S_N44K_48K (1 << 3) /* Frame sample frecuency of I2S codec port, does not generate value */
-#define AGCFR2_FSINT2(val) ((val & 0x7) << 0) /* intermediate sample frequency for DMA channel read and write operations */
-#define AGCFR2_FSINT2_BITS (0x7 << 0)
-
-#define AGCFR2_FSINT2_8000 (0) /* 8000 Hz */
-#define AGCFR2_FSINT2_11025 (1) /* 11025 Hz */
-#define AGCFR2_FSINT2_22050 (2) /* 22050 Hz */
-#define AGCFR2_FSINT2_44100 (3) /* 44100 Hz */
-#define AGCFR2_FSINT2_48000 (4) /* 48000 Hz */
-#define AGCFR2_FSINT2_FSINT (7) /* based on AGCFR/FSINT */
-
-
-/* AGCFR3 */
-#define AGCFR3_CP_TR_DMA (1 << 15) /* codec port transparent DMA (to audio DMAs) */
-#define AGCFR3_BT_TR_DMA (1 << 14) /* BT transparent DMA (to BT UL write & DL read DMAs */
-#define AGCFR3_MD_TR_DMA (1 << 13) /* modem transparent DMA (to modem UL write and DL read DMAs) */
-#define AGCFR3_FSINT(val) ((val & 0xf) << 9) /* FSINT */
-#define AGCFR3_FSINT_BITS (0xf << 9)
-
-#define AGCFR3_FSINT_8000 (0) /* 8000 Hz */
-#define AGCFR3_FSINT_11025 (1) /* 11025 Hz */
-#define AGCFR3_FSINT_16000 (2) /* 16000 Hz */
-#define AGCFR3_FSINT_22050 (3) /* 22050 Hz */
-#define AGCFR3_FSINT_24000 (4) /* 24000 Hz */
-#define AGCFR3_FSINT_32000 (5) /* 32000 Hz */
-#define AGCFR3_FSINT_44100 (6) /* 44100 Hz */
-#define AGCFR3_FSINT_48000 (7) /* 48000 Hz */
-#define AGCFR3_FSINT_FSINT (15) /* based on AGCFR2/AGCFR */
-
-
-#define AGCFR3_BT_CKSRC(val) ((val & 0x3) << 7) /* BT port clock selection */
-#define AGCFR3_BT_CKSRC_BITS (0x3 << 7)
-#define AGCFR3_MD_CKSRC(val) ((val & 0x3) << 5) /* modem port clock source */
-#define AGCFR3_MD_CKSRC_BITS (0x3 << 5)
-#define AGCFR3_AUD_CKSRC(val) ((val & 0x7) << 2) /* audio and codec port clock source */
-#define AGCFR3_AUD_CKSRC_BITS (0x7 << 2)
-#define AGCFR3_CLK12MINT_SEL (1 << 1) /* internal 12MHz clock source */
-#define AGCFR3_MCLKINT_SEL (1 << 0) /* internal codec master clock source */
-
-/* AMSCFR */
-#define AMSCFR_K12 (1 << 11) /* K12 switch open/close */
-#define AMSCFR_K11 (1 << 10)
-#define AMSCFR_K10 (1 << 9)
-#define AMSCFR_K9 (1 << 8)
-#define AMSCFR_K8 (1 << 7)
-#define AMSCFR_K7 (1 << 6)
-#define AMSCFR_K6 (1 << 5)
-#define AMSCFR_K5 (1 << 4)
-#define AMSCFR_K4 (1 << 3)
-#define AMSCFR_K3 (1 << 2)
-#define AMSCFR_K2 (1 << 1)
-#define AMSCFR_K1 (1 << 0)
-
-/* AMVCTR */
-#define AMVCTR_GWO_BITS (0xff << 8)
-#define AMVCTR_GWO(val) ((val & 0xff) << 8) /* Gain on write DMA operation */
-#define AMVCTR_GRO_BITS (0xff << 0)
-#define AMVCTR_GRO(val) ((val & 0xff) << 0) /* Gain on read DMA operation */
-
-/* AM1VCTR */
-#define AM1VCTR_MUTE (1 << 15) /* mute/no mute on mixer output */
-#define AM1VCTR_GINB(val) ((val & 0x7f) << 8) /* gain on input B */
-#define AM1VCTR_GINB_BITS (0x7f << 8)
-#define AM1VCTR_GINA(val) ((val & 0x7f) << 0) /* gain on input A */
-#define AM1VCTR_GINA_BITS (0x7f << 0)
-
-/* AM2VCTR */
-#define AM2VCTR_MUTE (1 << 15) /* mute/no mute on mixer output */
-#define AM2VCTR_GINB(val) ((val & 0x7f) << 8) /* gain on input B */
-#define AM2VCTR_GINB_BITS (0x7f << 8)
-#define AM2VCTR_GINA(val) ((val & 0x7f) << 0) /* gain on input A */
-#define AM2VCTR_GINA_BITS (0x7f << 0)
-
-/* AM3VCTR */
-#define AM3VCTR_MUTE (1 << 15) /* mute/no mute */
-#define AM3VCTR_GINB(val) ((val & 0x7f) << 8) /* gain on input B */
-#define AM3VCTR_GINB_BITS (0x7f << 8)
-#define AM3VCTR_GINA(val) ((val & 0x7f) << 0) /* gain on input A */
-#define AM3VCTR_GINA_BITS (0x7f << 0)
-
-/* ASTCTR */
-#define ASTCTR_ATT(val) ((val & 0x7f) << 1) /* Attenuation of side tone */
-#define ASTCTR_ATT_BITS (0x7f << 1)
-#define ASTCTR_ATTEN (1 << 0) /* side tone enabled/disabled */
-
-
-/* internal structure of the EAC driver */
-struct omap_eac {
- struct mutex mutex;
- void __iomem * base;
- struct platform_device * pdev;
- struct eac_platform_data * pdata;
- struct snd_card * card;
- struct clk * fck;
- struct clk * ick;
- struct eac_codec * codec;
-
- unsigned clocks_enabled:1;
-};
-
-static char *id = SNDRV_DEFAULT_STR1;
-module_param(id, charp, 0444);
-MODULE_PARM_DESC(id, "ID string for OMAP24xx EAC");
-
-
-#define MOD_REG_BIT(val, mask, set) do { \
- if (set) \
- val |= mask; \
- else \
- val &= ~mask; \
-} while(0)
-
-static inline void eac_write_reg(struct omap_eac *eac, int idx, u16 val)
-{
- __raw_writew(val, eac->base + idx);
-}
-
-static inline u16 eac_read_reg(struct omap_eac *eac, int idx)
-{
- return __raw_readw(eac->base + idx);
-}
-
-static int eac_get_clocks(struct omap_eac *eac)
-{
- eac->ick = clk_get(NULL, "eac_ick");
- if (IS_ERR(eac->ick)) {
- dev_err(&eac->pdev->dev, "Could not get eac_ick");
- return -ENODEV;
- }
-
- eac->fck = clk_get(NULL, "eac_fck");
- if (IS_ERR(eac->fck)) {
- dev_err(&eac->pdev->dev, "Could not get eac_fck");
- clk_put(eac->ick);
- return -ENODEV;
- }
-
- return 0;
-}
-
-static void eac_put_clocks(struct omap_eac *eac)
-{
- clk_put(eac->fck);
- clk_put(eac->ick);
-}
-
-static int eac_enable_clocks(struct omap_eac *eac)
-{
- int err = 0;
-
- if (eac->clocks_enabled)
- return 0;
-
- if (eac->pdata != NULL && eac->pdata->enable_ext_clocks != NULL) {
- if ((err = eac->pdata->enable_ext_clocks(&eac->pdev->dev)) != 0)
- return err;
- }
- clk_enable(eac->ick);
- clk_enable(eac->fck);
- eac->clocks_enabled = 1;
-
- return 0;
-}
-
-static void eac_disable_clocks(struct omap_eac *eac)
-{
- if (!eac->clocks_enabled)
- return;
- eac->clocks_enabled = 0;
-
- clk_disable(eac->fck);
- clk_disable(eac->ick);
- if (eac->pdata != NULL && eac->pdata->disable_ext_clocks != NULL)
- eac->pdata->disable_ext_clocks(&eac->pdev->dev);
-}
-
-static int eac_reset(struct omap_eac *eac)
-{
- int i;
-
- /* step 1 (see TRM) */
- /* first, let's reset the EAC */
- eac_write_reg(eac, EAC_SYSCONFIG, 0x2);
- /* step 2 (see TRM) */
- eac_write_reg(eac, EAC_AGCTR, AGCTR_MCLK_EN | AGCTR_AUDEN);
- /* step 3 (see TRM) */
- /* wait until reset done */
- i = 10000;
- while (!(eac_read_reg(eac, EAC_SYSSTATUS) & 1)) {
- if (--i == 0)
- return -ENODEV;
- udelay(1);
- }
-
- return 0;
-}
-
-static int eac_calc_agcfr3_fsint(int rate)
-{
- int fsint;
-
- if (rate >= 48000)
- fsint = AGCFR3_FSINT_48000;
- else if (rate >= 44100)
- fsint = AGCFR3_FSINT_44100;
- else if (rate >= 32000)
- fsint = AGCFR3_FSINT_32000;
- else if (rate >= 24000)
- fsint = AGCFR3_FSINT_24000;
- else if (rate >= 22050)
- fsint = AGCFR3_FSINT_22050;
- else if (rate >= 16000)
- fsint = AGCFR3_FSINT_16000;
- else if (rate >= 11025)
- fsint = AGCFR3_FSINT_11025;
- else
- fsint = AGCFR3_FSINT_8000;
-
- return fsint;
-}
-
-static int eac_configure_pcm(struct omap_eac *eac, struct eac_codec *conf)
-{
- dev_err(&eac->pdev->dev,
- "EAC codec port configuration for PCM not implemented\n");
-
- return -ENODEV;
-}
-
-static int eac_configure_ac97(struct omap_eac *eac, struct eac_codec *conf)
-{
- dev_err(&eac->pdev->dev,
- "EAC codec port configuration for AC97 not implemented\n");
-
- return -ENODEV;
-}
-
-static int eac_configure_i2s(struct omap_eac *eac, struct eac_codec *conf)
-{
- u16 cpcfr1, cpcfr2, cpcfr3, cpcfr4;
-
- cpcfr1 = eac_read_reg(eac, EAC_CPCFR1);
- cpcfr2 = eac_read_reg(eac, EAC_CPCFR2);
- cpcfr3 = eac_read_reg(eac, EAC_CPCFR3);
- cpcfr4 = eac_read_reg(eac, EAC_CPCFR4);
-
- cpcfr1 &= ~(CPCFR1_MODE_BITS | CPCFR1_MTSL_BITS);
- cpcfr1 |= CPCFR1_MTSL(1); /* 2 timeslots per frame (I2S default) */
-
- /* audio time slot configuration for I2S mode */
- cpcfr2 &= ~(CPCFR2_TSLL_BITS | CPCFR2_BPTSL_BITS | CPCFR2_TSLOL_BITS);
- cpcfr2 |= CPCFR2_TSLOL(0); /* time slot 0 length same as TSLL */
- cpcfr2 |= CPCFR2_BPTSL(1); /* 16 data bits per time slot */
- cpcfr2 |= CPCFR2_TSLL(1); /* time slot length 16 serial clock cycles */
-
- /* I2S link configuration */
- MOD_REG_BIT(cpcfr3, CPCFR3_DDLY,
- conf->codec_conf.i2s.sync_delay_enable); /* 0/1 clk delay */
- /* data serial output enabled during nonvalid audio frames, clock
- * polarity = falling edge, CSYNC lenght equal to time slot0 length */
- MOD_REG_BIT(cpcfr3, CPCFR3_TRSEN, 1);
- MOD_REG_BIT(cpcfr3, CPCFR3_CLKBP, 1);
- MOD_REG_BIT(cpcfr3, CPCFR3_CSYNCL, 1);
-
- cpcfr4 &= ~(CPCFR4_DIVB_BITS | CPCFR4_ATSL_BITS);
- cpcfr4 |= CPCFR4_DIVB(7); /* CP_SCLK = MCLK / 8 */
-
- /* configuration for normal I2S or polarity-changed I2S */
- if (!conf->codec_conf.i2s.polarity_changed_mode) {
- cpcfr1 |= CPCFR1_MODE(4); /* I2S mode */
- MOD_REG_BIT(cpcfr3, CPCFR3_CSYNCP, 0); /* CP_SYNC active low */
- /* audio time slots configuration for I2S */
- cpcfr4 |= CPCFR4_ATSL(0);
- } else {
- cpcfr1 |= CPCFR1_MODE(1); /* PCM mode/polarity-changed I2S */
- MOD_REG_BIT(cpcfr3, CPCFR3_CSYNCP, 1); /* CP_SYNC active
- high */
- /* audio time slots configuration for polarity-changed I2S */
- cpcfr4 |= CPCFR4_ATSL(0xf);
- };
-
- /* master/slave configuration */
- if (conf->codec_mode == EAC_CODEC_I2S_MASTER) {
- /* EAC is master. Set CP_SCLK and CP_SYNC as outputs */
- MOD_REG_BIT(cpcfr3, CPCFR3_CSCLKD, 0);
- MOD_REG_BIT(cpcfr3, CPCFR3_CSYNCD, 0);
- } else {
- /* EAC is slave. Set CP_SCLK and CP_SYNC as inputs */
- MOD_REG_BIT(cpcfr3, CPCFR3_CSCLKD, 1);
- MOD_REG_BIT(cpcfr3, CPCFR3_CSYNCD, 1);
- }
-
- eac_write_reg(eac, EAC_CPCFR1, cpcfr1);
- eac_write_reg(eac, EAC_CPCFR2, cpcfr2);
- eac_write_reg(eac, EAC_CPCFR3, cpcfr3);
- eac_write_reg(eac, EAC_CPCFR4, cpcfr4);
-
- return 0;
-}
-
-static int eac_codec_port_init(struct omap_eac *eac, struct eac_codec *conf)
-{
- u16 agcfr, agcfr2, agcfr3, agctr;
- u16 cpctl, reg;
- int err = 0, i;
-
- /* use internal MCLK gating before doing full configuration for it.
- * Partial or misconfigured MCLK will cause that access to some of the
- * EAC registers causes "external abort on linefetch". Same happens
- * also when using external clock as a MCLK source and if that clock is
- * either missing or not having a right rate (e.g. half of it) */
- agcfr3 = eac_read_reg(eac, EAC_AGCFR3);
- MOD_REG_BIT(agcfr3, AGCFR3_MCLKINT_SEL, 1); /* 96 Mhz / 8.5 */
- eac_write_reg(eac, EAC_AGCFR3, agcfr3);
-
- /* disable codec port, enable access to config registers */
- cpctl = eac_read_reg(eac, EAC_CPTCTL);
- MOD_REG_BIT(cpctl, CPTCTL_CPEN, 0);
- eac_write_reg(eac, EAC_CPTCTL, cpctl);
-
- agcfr = eac_read_reg(eac, EAC_AGCFR);
- agctr = eac_read_reg(eac, EAC_AGCTR);
- agcfr2 = eac_read_reg(eac, EAC_AGCFR2);
-
- /* MCLK source and frequency configuration */
- MOD_REG_BIT(agcfr, AGCFR_MCLK, 0);
- switch (conf->mclk_src) {
- case EAC_MCLK_EXT_2x11289600:
- MOD_REG_BIT(agcfr, AGCFR_MCLK, 1); /* div by 2 path */
- MOD_REG_BIT(agcfr, AGCFR_MCLK_OUT, 1); /* div by 2 */
- case EAC_MCLK_EXT_11289600:
- MOD_REG_BIT(agcfr, AGCFR_MCLK, 1);
- MOD_REG_BIT(agcfr2, AGCFR2_I2S_N44K_48K, 0); /* 44.1 kHz */
- MOD_REG_BIT(agcfr2, AGCFR2_MCLK_I2S_N11M_12M, 0); /* 11.2896 */
- MOD_REG_BIT(agcfr3, AGCFR3_MCLKINT_SEL, 0);
- break;
-
- case EAC_MCLK_EXT_2x12288000:
- MOD_REG_BIT(agcfr, AGCFR_MCLK, 1); /* div by 2 path */
- MOD_REG_BIT(agcfr, AGCFR_MCLK_OUT, 1); /* div by 2 */
- case EAC_MCLK_EXT_12288000:
- MOD_REG_BIT(agcfr2, AGCFR2_I2S_N44K_48K, 1); /* 48 kHz */
- MOD_REG_BIT(agcfr2, AGCFR2_MCLK_I2S_N11M_12M, 1); /* 12.288 */
- MOD_REG_BIT(agcfr3, AGCFR3_MCLKINT_SEL, 0);
- break;
-
- default:
- /* internal MCLK gating */
- break;
- }
- MOD_REG_BIT(agctr, AGCTR_MCLK_EN, 1);
- MOD_REG_BIT(agctr, AGCTR_OSCMCLK_EN, 1); /* oscillator enabled? */
- /* use MCLK just configured above as audio & codec port clock source */
- agcfr3 &= ~AGCFR3_AUD_CKSRC_BITS;
- agcfr3 |= AGCFR3_AUD_CKSRC(0);
-
- /* audio data format */
- MOD_REG_BIT(agcfr, AGCFR_MN_ST, 1); /* stereo file */
- MOD_REG_BIT(agcfr, AGCFR_B8_16, 1); /* 16 bit audio file */
- MOD_REG_BIT(agcfr, AGCFR_LI_BI, 0); /* little endian stream */
-
- /* there are FSINT configuration bits in AGCFR, AGCFR2 and AGCFR3
- * registers but it seems that it is just enough to set in AGCFR3
- * only */
- agcfr3 &= ~AGCFR3_FSINT_BITS;
- agcfr3 |= AGCFR3_FSINT(eac_calc_agcfr3_fsint(conf->default_rate));
-
- /* transparent DMA enable bits */
- MOD_REG_BIT(agcfr3, AGCFR3_MD_TR_DMA, 1); /* modem */
- MOD_REG_BIT(agcfr3, AGCFR3_BT_TR_DMA, 1); /* BT */
- if (conf->codec_mode != EAC_CODEC_I2S_SLAVE)
- MOD_REG_BIT(agcfr3, AGCFR3_CP_TR_DMA, 0);
- else
- MOD_REG_BIT(agcfr3, AGCFR3_CP_TR_DMA, 1);
-
- /* step 4 (see TRM) */
- eac_write_reg(eac, EAC_AGCFR3, agcfr3);
- /* pre-write AGCTR now (finally in step 10) in order to get MCLK
- * settings effective (especially when using external MCLK) */
- eac_write_reg(eac, EAC_AGCTR, agctr);
- eac_write_reg(eac, EAC_AGCFR2, agcfr2);
-
- /* step 5 (see TRM) */
- eac_write_reg(eac, EAC_AGCFR, agcfr);
-
- /* step 6 (see TRM) */
- /* wait until audio reset done */
- i = 10000;
- while (!(eac_read_reg(eac, EAC_SYSSTATUS) & (1 << 3))) {
- if (--i == 0)
- return -ETIMEDOUT;
- udelay(1);
- }
-
- /* step 7 (see TRM) */
- reg = eac_read_reg(eac, EAC_AMSCFR);
- MOD_REG_BIT(reg, AMSCFR_K1, 1); /* K1 switch closed */
- MOD_REG_BIT(reg, AMSCFR_K5, 1); /* K5 switch closed */
- MOD_REG_BIT(reg, AMSCFR_K2, 0); /* K2 switch open */
- MOD_REG_BIT(reg, AMSCFR_K6, 0); /* K6 switch open */
- eac_write_reg(eac, EAC_AMSCFR, reg);
-
- /* step 8 (see TRM) */
- switch (conf->codec_mode) {
- case EAC_CODEC_PCM:
- err = eac_configure_pcm(eac, conf);
- break;
- case EAC_CODEC_AC97:
- err = eac_configure_ac97(eac, conf);
- break;
- default:
- err = eac_configure_i2s(eac, conf);
- break;
- }
-
- /* step 9 (see TRM) */
- MOD_REG_BIT(cpctl, CPTCTL_CPEN, 1); /* codec port enable */
- MOD_REG_BIT(cpctl, CPTCTL_RXIE, 1); /* receive int enable */
- MOD_REG_BIT(cpctl, CPTCTL_TXIE, 1); /* transmit int enable */
- eac_write_reg(eac, EAC_CPTCTL, cpctl);
-
- /* step 10 (see TRM) */
- /* enable playing & recording */
- MOD_REG_BIT(agctr, AGCTR_DMAREN, 1); /* playing enabled (DMA R) */
- MOD_REG_BIT(agctr, AGCTR_DMAWEN, 1); /* recording enabled (DMA W) */
- MOD_REG_BIT(agctr, AGCTR_AUDEN, 1); /* audio processing enabled */
- eac_write_reg(eac, EAC_AGCTR, agctr);
-
- /* audio mixer1, no mute on mixer output, gain = 0 dB */
- reg = eac_read_reg(eac, EAC_AM1VCTR);
- MOD_REG_BIT(reg, AM1VCTR_MUTE, 0);
- reg = ((reg & ~AM1VCTR_GINB_BITS) | (AM1VCTR_GINB(0x67)));
- eac_write_reg(eac, EAC_AM1VCTR, reg);
-
- /* audio mixer3, no mute on mixer output, gain = 0 dB */
- reg = eac_read_reg(eac, EAC_AM3VCTR);
- MOD_REG_BIT(reg, AM3VCTR_MUTE, 0);
- reg = ((reg & ~AM3VCTR_GINB_BITS) | (AM3VCTR_GINB(0x67)));
- eac_write_reg(eac, EAC_AM3VCTR, reg);
-
- /* audio side tone disabled */
- eac_write_reg(eac, EAC_ASTCTR, 0x0);
-
- return 0;
-}
-
-int eac_set_mode(struct device *dev, int play, int rec)
-{
- struct omap_eac *eac = dev_get_drvdata(dev);
-
-#ifdef DEBUG
- printk(KERN_DEBUG "EAC mode: play %s, rec %s\n",
- play ? "enabled" : "disabled",
- rec ? "enabled" : "disabled");
-#endif
- BUG_ON(eac == NULL);
- mutex_lock(&eac->mutex);
- if (play || rec) {
- /* activate clocks */
- eac_enable_clocks(eac);
-
- /* power-up codec */
- if (eac->codec != NULL && eac->codec->set_power != NULL)
- eac->codec->set_power(eac->codec->private_data,
- play, rec);
- } else {
- /* shutdown codec */
- if (eac->codec != NULL && eac->codec->set_power != NULL)
- eac->codec->set_power(eac->codec->private_data, 0, 0);
-
- /* de-activate clocks */
- eac_disable_clocks(eac);
- }
- mutex_unlock(&eac->mutex);
-
- return 0;
-}
-
-int eac_register_codec(struct device *dev, struct eac_codec *codec)
-{
- struct omap_eac *eac = dev_get_drvdata(dev);
- struct snd_card *card = eac->card;
- int err;
-
- BUG_ON(eac->codec != NULL);
-
- mutex_lock(&eac->mutex);
- eac->codec = codec;
- eac_enable_clocks(eac);
- err = eac_codec_port_init(eac, codec);
- eac_disable_clocks(eac);
- mutex_unlock(&eac->mutex);
- if (err)
- return err;
-
- /* register mixer controls implemented by a codec driver */
- if (codec->register_controls != NULL) {
- err = codec->register_controls(codec->private_data, card);
- if (err)
- return err;
- }
-
- if (codec->short_name != NULL) {
- sprintf(card->longname, "%s with codec %s", card->shortname,
- codec->short_name);
- strcpy(card->mixername, codec->short_name);
- }
-
- err = snd_card_register(card);
- return err;
-}
-
-void eac_unregister_codec(struct device *dev)
-{
- struct omap_eac *eac = dev_get_drvdata(dev);
-
- BUG_ON(eac->codec == NULL);
- eac_set_mode(dev, 0, 0);
- snd_card_disconnect(eac->card);
- eac->codec = NULL;
-}
-
-static int __devinit eac_probe(struct platform_device *pdev)
-{
- struct eac_platform_data *pdata = pdev->dev.platform_data;
- struct snd_card *card;
- struct omap_eac *eac;
- struct resource *res;
- int err;
-
- eac = kzalloc(sizeof(*eac), GFP_KERNEL);
- if (!eac)
- return -ENOMEM;
-
- mutex_init(&eac->mutex);
- eac->pdev = pdev;
- platform_set_drvdata(pdev, eac);
- res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- if (res == NULL) {
- err = -ENODEV;
- goto err1;
- }
- eac->base = ioremap(res->start, res->end - res->start + 1);
- eac->pdata = pdata;
-
- /* pre-initialize EAC hw */
- err = eac_get_clocks(eac);
- if (err)
- goto err1;
- err = eac_enable_clocks(eac);
- if (err)
- goto err2;
-
- err = eac_reset(eac);
- if (err)
- goto err3;
-
- dev_info(&pdev->dev, "EAC version: %d.%d\n",
- eac_read_reg(eac, EAC_VERSION) >> 4,
- eac_read_reg(eac, EAC_VERSION) & 0x0f);
- eac_disable_clocks(eac);
-
- /* create soundcard instance */
- card = snd_card_new(-1, id, THIS_MODULE, 0);
- if (card == NULL) {
- err = -ENOMEM;
- goto err3;
- }
- eac->card = card;
- strcpy(card->driver, "EAC");
- strcpy(card->shortname, "OMAP24xx EAC");
-
- sprintf(card->longname, "%s", card->shortname);
- strcpy(card->mixername, "EAC Mixer");
-
- if (eac->pdata->init) {
- err = eac->pdata->init(&pdev->dev);
- if (err < 0) {
- printk("init %d\n", err);
- goto err4;
- }
- }
-
- return 0;
-
-err4:
- snd_card_free(card);
-err3:
- eac_disable_clocks(eac);
-err2:
- eac_put_clocks(eac);
-err1:
- kfree(eac);
- return err;
-}
-
-static int __devexit eac_remove(struct platform_device *pdev)
-{
- struct omap_eac *eac = platform_get_drvdata(pdev);
- struct snd_card *card = eac->card;
-
- snd_card_free(card);
-
- eac_disable_clocks(eac);
- eac_put_clocks(eac);
-
- iounmap(eac->base);
-
- platform_set_drvdata(pdev, NULL);
-
- return 0;
-}
-
-static struct platform_driver eac_driver = {
- .driver = {
- .name = "omap24xx-eac",
- .bus = &platform_bus_type,
- },
- .probe = eac_probe,
- .remove = eac_remove,
-};
-
-static int __init eac_init(void)
-{
- return platform_driver_register(&eac_driver);
-}
-
-static void __exit eac_exit(void)
-{
- platform_driver_unregister(&eac_driver);
-}
-
-module_init(eac_init);
-module_exit(eac_exit);
-MODULE_AUTHOR("Jarkko Nikula <jarkko.nikula@nokia.com>");
-MODULE_LICENSE("GPL");
+++ /dev/null
-/*
- * sound/arm/omap/omap-alsa-aic23-mixer.c
- *
- * Alsa Driver Mixer for generic codecs for omap boards
- *
- * Copyright (C) 2005 Instituto Nokia de Tecnologia - INdT - Manaus Brazil
- * Written by David Cohen, Daniel Petrini
- * {david.cohen, daniel.petrini}@indt.org.br
- *
- * Based on es1688_lib.c,
- * Copyright (c) by Jaroslav Kysela <perex@suse.cz>
- *
- * 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.
- *
- * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
- * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN
- * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
- * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
- * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
- * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
- * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
- * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- * 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.
- *
- * History:
- *
- * 2005-08-02 INdT Kernel Team - Alsa mixer driver for omap osk.
- * Creation of new file omap-alsa-mixer.c.
- * Initial version with aic23 codec for osk5912
- */
-
-#include <linux/kernel.h>
-
-#include <mach/aic23.h>
-
-#include <mach/omap-alsa.h>
-#include "omap-alsa-aic23.h"
-#include <sound/initval.h>
-#include <sound/control.h>
-
-MODULE_AUTHOR("David Cohen");
-MODULE_AUTHOR("Daniel Petrini");
-
-MODULE_LICENSE("GPL");
-MODULE_DESCRIPTION("OMAP Alsa mixer driver for ALSA");
-
-/*
- * Codec dependent region
- */
-
-/* Codec AIC23 */
-#if defined(CONFIG_SENSORS_TLV320AIC23) || \
- defined(CONFIG_SENSORS_TLV320AIC23_MODULE)
-
-#define MIXER_NAME "Mixer AIC23"
-#define SND_OMAP_WRITE(reg, val) audio_aic23_write(reg, val)
-
-#endif
-
-/* Callback Functions */
-#define OMAP_BOOL(xname, xindex, reg, reg_index, mask, invert) \
-{ \
- .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
- .name = xname, \
- .index = xindex, \
- .info = snd_omap_info_bool, \
- .get = snd_omap_get_bool, \
- .put = snd_omap_put_bool, \
- .private_value = reg | (reg_index << 8) | (invert << 10) | \
- (mask << 12) \
-}
-
-#define OMAP_MUX(xname, reg, reg_index, mask) \
-{ \
- .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
- .name = xname, \
- .info = snd_omap_info_mux, \
- .get = snd_omap_get_mux, \
- .put = snd_omap_put_mux, \
- .private_value = reg | (reg_index << 8) | (mask << 10) \
-}
-
-#define OMAP_SINGLE(xname, xindex, reg, reg_index, reg_val, mask) \
-{\
- .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
- .name = xname, \
- .index = xindex, \
- .info = snd_omap_info_single, \
- .get = snd_omap_get_single, \
- .put = snd_omap_put_single, \
- .private_value = reg | (reg_val << 8) | (reg_index << 16) |\
- (mask << 18) \
-}
-
-#define OMAP_DOUBLE(xname, xindex, left_reg, right_reg, reg_index, mask) \
-{\
- .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
- .name = xname, \
- .index = xindex, \
- .info = snd_omap_info_double, \
- .get = snd_omap_get_double, \
- .put = snd_omap_put_double, \
- .private_value = left_reg | (right_reg << 8) | (reg_index << 16) | \
- (mask << 18) \
-}
-
-/* Local Registers */
-enum snd_device_index {
- PCM_INDEX = 0,
- LINE_INDEX,
- AAC_INDEX, /* Analog Audio Control: reg = l_reg */
-};
-
-struct {
- u16 l_reg;
- u16 r_reg;
- u8 sw;
-} omap_regs[3];
-
-#ifdef CONFIG_PM
-struct {
- u16 l_reg;
- u16 r_reg;
- u8 sw;
-} omap_pm_regs[3];
-#endif
-
-u16 snd_sidetone[6] = {
- SIDETONE_18,
- SIDETONE_12,
- SIDETONE_9,
- SIDETONE_6,
- SIDETONE_0,
- 0
-};
-
-/* Begin Bool Functions */
-
-static int snd_omap_info_bool(struct snd_kcontrol *kcontrol,
- struct snd_ctl_elem_info *uinfo)
-{
- uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN;
- uinfo->count = 1;
- uinfo->value.integer.min = 0;
- uinfo->value.integer.max = 1;
-
- return 0;
-}
-
-static int snd_omap_get_bool(struct snd_kcontrol *kcontrol,
- struct snd_ctl_elem_value *ucontrol)
-{
- int mic_index = (kcontrol->private_value >> 8) & 0x03;
- u16 mask = (kcontrol->private_value >> 12) & 0xff;
- int invert = (kcontrol->private_value >> 10) & 0x03;
-
- if (invert)
- ucontrol->value.integer.value[0] =
- (omap_regs[mic_index].l_reg & mask) ? 0 : 1;
- else
- ucontrol->value.integer.value[0] =
- (omap_regs[mic_index].l_reg & mask) ? 1 : 0;
-
- return 0;
-}
-
-static int snd_omap_put_bool(struct snd_kcontrol *kcontrol,
- struct snd_ctl_elem_value *ucontrol)
-{
- int mic_index = (kcontrol->private_value >> 8) & 0x03;
- u16 mask = (kcontrol->private_value >> 12) & 0xff;
- u16 reg = kcontrol->private_value & 0xff;
- int invert = (kcontrol->private_value >> 10) & 0x03;
-
- int changed = 1;
-
- if (ucontrol->value.integer.value[0]) /* XOR */
- if (invert)
- omap_regs[mic_index].l_reg &= ~mask;
- else
- omap_regs[mic_index].l_reg |= mask;
- else
- if (invert)
- omap_regs[mic_index].l_reg |= mask;
- else
- omap_regs[mic_index].l_reg &= ~mask;
-
- SND_OMAP_WRITE(reg, omap_regs[mic_index].l_reg);
-
- return changed;
-}
-
-/* End Bool Functions */
-
-/* Begin Mux Functions */
-
-static int snd_omap_info_mux(struct snd_kcontrol *kcontrol,
- struct snd_ctl_elem_info *uinfo)
-{
- /* Mic = 0
- * Line = 1 */
- static char *texts[2] = { "Mic", "Line" };
-
- uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
- uinfo->count = 1;
- uinfo->value.enumerated.items = 2;
-
- if (uinfo->value.enumerated.item > 1)
- uinfo->value.enumerated.item = 1;
-
- strcpy(uinfo->value.enumerated.name,
- texts[uinfo->value.enumerated.item]);
-
- return 0;
-}
-
-static int snd_omap_get_mux(struct snd_kcontrol *kcontrol,
- struct snd_ctl_elem_value *ucontrol)
-{
- u16 mask = (kcontrol->private_value >> 10) & 0xff;
- int mux_idx = (kcontrol->private_value >> 8) & 0x03;
-
- ucontrol->value.enumerated.item[0] =
- (omap_regs[mux_idx].l_reg & mask) ? 0 /* Mic */ : 1 /* Line */;
-
- return 0;
-}
-
-static int snd_omap_put_mux(struct snd_kcontrol *kcontrol,
- struct snd_ctl_elem_value *ucontrol)
-{
- u16 reg = kcontrol->private_value & 0xff;
- u16 mask = (kcontrol->private_value >> 10) & 0xff;
- int mux_index = (kcontrol->private_value >> 8) & 0x03;
-
- int changed = 1;
-
- if (!ucontrol->value.integer.value[0])
- omap_regs[mux_index].l_reg |= mask; /* AIC23: Mic */
- else
- omap_regs[mux_index].l_reg &= ~mask; /* AIC23: Line */
-
- SND_OMAP_WRITE(reg, omap_regs[mux_index].l_reg);
-
- return changed;
-}
-
-/* End Mux Functions */
-
-/* Begin Single Functions */
-
-static int snd_omap_info_single(struct snd_kcontrol *kcontrol,
- struct snd_ctl_elem_info *uinfo)
-{
- int mask = (kcontrol->private_value >> 18) & 0xff;
- int reg_val = (kcontrol->private_value >> 8) & 0xff;
-
- uinfo->type = mask ? SNDRV_CTL_ELEM_TYPE_INTEGER :
- SNDRV_CTL_ELEM_TYPE_BOOLEAN;
- uinfo->count = 1;
- uinfo->value.integer.min = 0;
- uinfo->value.integer.max = reg_val-1;
-
- return 0;
-}
-
-static int snd_omap_get_single(struct snd_kcontrol *kcontrol,
- struct snd_ctl_elem_value *ucontrol)
-{
- u16 reg_val = (kcontrol->private_value >> 8) & 0xff;
-
- ucontrol->value.integer.value[0] = snd_sidetone[reg_val];
-
- return 0;
-}
-
-static int snd_omap_put_single(struct snd_kcontrol *kcontrol,
- struct snd_ctl_elem_value *ucontrol)
-{
- u16 reg_index = (kcontrol->private_value >> 16) & 0x03;
- u16 mask = (kcontrol->private_value >> 18) & 0x1ff;
- u16 reg = kcontrol->private_value & 0xff;
- u16 reg_val = (kcontrol->private_value >> 8) & 0xff;
-
- int changed = 0;
-
- /* Volume */
- if ((omap_regs[reg_index].l_reg !=
- (ucontrol->value.integer.value[0] & mask))) {
- changed = 1;
-
- omap_regs[reg_index].l_reg &= ~mask;
- omap_regs[reg_index].l_reg |=
- snd_sidetone[ucontrol->value.integer.value[0]];
-
- snd_sidetone[reg_val] = ucontrol->value.integer.value[0];
- SND_OMAP_WRITE(reg, omap_regs[reg_index].l_reg);
- } else {
- changed = 0;
- }
-
- return changed;
-}
-
-/* End Single Functions */
-
-/* Begin Double Functions */
-
-static int snd_omap_info_double(struct snd_kcontrol *kcontrol,
- struct snd_ctl_elem_info *uinfo)
-{
- /*
- * mask == 0 : Switch
- * mask != 0 : Volume
- */
- int mask = (kcontrol->private_value >> 18) & 0xff;
-
- uinfo->type = mask ? SNDRV_CTL_ELEM_TYPE_INTEGER :
- SNDRV_CTL_ELEM_TYPE_BOOLEAN;
- uinfo->count = mask ? 2 : 1;
- uinfo->value.integer.min = 0;
- uinfo->value.integer.max = mask ? mask : 1;
-
- return 0;
-}
-
-static int snd_omap_get_double(struct snd_kcontrol *kcontrol,
- struct snd_ctl_elem_value *ucontrol)
-{
- /*
- * mask == 0 : Switch
- * mask != 0 : Volume
- */
- int mask = (kcontrol->private_value >> 18) & 0xff;
- int vol_index = (kcontrol->private_value >> 16) & 0x03;
-
- if (!mask) {
- /* Switch */
- ucontrol->value.integer.value[0] = omap_regs[vol_index].sw;
- } else {
- /* Volume */
- ucontrol->value.integer.value[0] = omap_regs[vol_index].l_reg;
- ucontrol->value.integer.value[1] = omap_regs[vol_index].r_reg;
- }
-
- return 0;
-}
-
-static int snd_omap_put_double(struct snd_kcontrol *kcontrol,
- struct snd_ctl_elem_value *ucontrol)
-{
- /* mask == 0 : Switch
- * mask != 0 : Volume */
- int vol_index = (kcontrol->private_value >> 16) & 0x03;
- int mask = (kcontrol->private_value >> 18) & 0xff;
- int left_reg = kcontrol->private_value & 0xff;
- int right_reg = (kcontrol->private_value >> 8) & 0xff;
-
- int changed = 0;
-
- if (!mask) {
- /* Switch */
- if (!ucontrol->value.integer.value[0]) {
- SND_OMAP_WRITE(left_reg, 0x00);
- SND_OMAP_WRITE(right_reg, 0x00);
- } else {
- SND_OMAP_WRITE(left_reg, omap_regs[vol_index].l_reg);
- SND_OMAP_WRITE(right_reg, omap_regs[vol_index].r_reg);
- }
- changed = 1;
- omap_regs[vol_index].sw = ucontrol->value.integer.value[0];
- } else {
- /* Volume */
- if ((omap_regs[vol_index].l_reg !=
- (ucontrol->value.integer.value[0] & mask)) ||
- (omap_regs[vol_index].r_reg !=
- (ucontrol->value.integer.value[1] & mask))) {
- changed = 1;
-
- omap_regs[vol_index].l_reg &= ~mask;
- omap_regs[vol_index].r_reg &= ~mask;
- omap_regs[vol_index].l_reg |=
- (ucontrol->value.integer.value[0] & mask);
- omap_regs[vol_index].r_reg |=
- (ucontrol->value.integer.value[1] & mask);
- if (omap_regs[vol_index].sw) {
- /* write to registers only if sw is actived */
- SND_OMAP_WRITE(left_reg,
- omap_regs[vol_index].l_reg);
- SND_OMAP_WRITE(right_reg,
- omap_regs[vol_index].r_reg);
- }
- } else {
- changed = 0;
- }
- }
-
- return changed;
-}
-
-/* End Double Functions */
-
-static struct snd_kcontrol_new snd_omap_controls[] = {
- OMAP_DOUBLE("PCM Playback Switch", 0, LEFT_CHANNEL_VOLUME_ADDR,
- RIGHT_CHANNEL_VOLUME_ADDR, PCM_INDEX, 0x00),
- OMAP_DOUBLE("PCM Playback Volume", 0, LEFT_CHANNEL_VOLUME_ADDR,
- RIGHT_CHANNEL_VOLUME_ADDR, PCM_INDEX,
- OUTPUT_VOLUME_MASK),
- OMAP_BOOL("Line Playback Switch", 0, ANALOG_AUDIO_CONTROL_ADDR,
- AAC_INDEX, BYPASS_ON, 0),
- OMAP_DOUBLE("Line Capture Switch", 0, LEFT_LINE_VOLUME_ADDR,
- RIGHT_LINE_VOLUME_ADDR, LINE_INDEX, 0x00),
- OMAP_DOUBLE("Line Capture Volume", 0, LEFT_LINE_VOLUME_ADDR,
- RIGHT_LINE_VOLUME_ADDR, LINE_INDEX, INPUT_VOLUME_MASK),
- OMAP_BOOL("Mic Playback Switch", 0, ANALOG_AUDIO_CONTROL_ADDR,
- AAC_INDEX, STE_ENABLED, 0),
- OMAP_SINGLE("Mic Playback Volume", 0, ANALOG_AUDIO_CONTROL_ADDR,
- AAC_INDEX, 5, SIDETONE_MASK),
- OMAP_BOOL("Mic Capture Switch", 0, ANALOG_AUDIO_CONTROL_ADDR,
- AAC_INDEX, MICM_MUTED, 1),
- OMAP_BOOL("Mic Booster Playback Switch", 0, ANALOG_AUDIO_CONTROL_ADDR,
- AAC_INDEX, MICB_20DB, 0),
- OMAP_MUX("Capture Source", ANALOG_AUDIO_CONTROL_ADDR, AAC_INDEX,
- INSEL_MIC),
-};
-
-#ifdef CONFIG_PM
-
-void snd_omap_suspend_mixer(void)
-{
- /* Saves current values to wake-up correctly */
- omap_pm_regs[LINE_INDEX].l_reg = omap_regs[LINE_INDEX].l_reg;
- omap_pm_regs[LINE_INDEX].r_reg = omap_regs[LINE_INDEX].l_reg;
- omap_pm_regs[LINE_INDEX].sw = omap_regs[LINE_INDEX].sw;
-
- omap_pm_regs[AAC_INDEX].l_reg = omap_regs[AAC_INDEX].l_reg;
-
- omap_pm_regs[PCM_INDEX].l_reg = omap_regs[PCM_INDEX].l_reg;
- omap_pm_regs[PCM_INDEX].r_reg = omap_regs[PCM_INDEX].r_reg;
- omap_pm_regs[PCM_INDEX].sw = omap_regs[PCM_INDEX].sw;
-}
-
-void snd_omap_resume_mixer(void)
-{
- /* Line's saved values */
- omap_regs[LINE_INDEX].l_reg = omap_pm_regs[LINE_INDEX].l_reg;
- omap_regs[LINE_INDEX].r_reg = omap_pm_regs[LINE_INDEX].l_reg;
- omap_regs[LINE_INDEX].sw = omap_pm_regs[LINE_INDEX].sw;
- SND_OMAP_WRITE(LEFT_LINE_VOLUME_ADDR, omap_pm_regs[LINE_INDEX].l_reg);
- SND_OMAP_WRITE(RIGHT_LINE_VOLUME_ADDR, omap_pm_regs[LINE_INDEX].l_reg);
-
- /* Analog Audio Control's saved values */
- omap_regs[AAC_INDEX].l_reg = omap_pm_regs[AAC_INDEX].l_reg;
- SND_OMAP_WRITE(ANALOG_AUDIO_CONTROL_ADDR, omap_regs[AAC_INDEX].l_reg);
-
- /* Headphone's saved values */
- omap_regs[PCM_INDEX].l_reg = omap_pm_regs[PCM_INDEX].l_reg;
- omap_regs[PCM_INDEX].r_reg = omap_pm_regs[PCM_INDEX].r_reg;
- omap_regs[PCM_INDEX].sw = omap_pm_regs[PCM_INDEX].sw;
- SND_OMAP_WRITE(LEFT_CHANNEL_VOLUME_ADDR,
- omap_pm_regs[PCM_INDEX].l_reg);
- SND_OMAP_WRITE(RIGHT_CHANNEL_VOLUME_ADDR,
- omap_pm_regs[PCM_INDEX].r_reg);
-}
-#endif
-
-void snd_omap_init_mixer(void)
-{
- u16 vol_reg;
-
- /* Line's default values */
- omap_regs[LINE_INDEX].l_reg = DEFAULT_INPUT_VOLUME & INPUT_VOLUME_MASK;
- omap_regs[LINE_INDEX].r_reg = DEFAULT_INPUT_VOLUME & INPUT_VOLUME_MASK;
- omap_regs[LINE_INDEX].sw = 0;
- SND_OMAP_WRITE(LEFT_LINE_VOLUME_ADDR,
- DEFAULT_INPUT_VOLUME & INPUT_VOLUME_MASK);
- SND_OMAP_WRITE(RIGHT_LINE_VOLUME_ADDR,
- DEFAULT_INPUT_VOLUME & INPUT_VOLUME_MASK);
-
- /* Analog Audio Control's default values */
- omap_regs[AAC_INDEX].l_reg = DEFAULT_ANALOG_AUDIO_CONTROL;
-
- /* Headphone's default values */
- vol_reg = LZC_ON;
- vol_reg &= ~OUTPUT_VOLUME_MASK;
- vol_reg |= DEFAULT_OUTPUT_VOLUME;
- omap_regs[PCM_INDEX].l_reg = DEFAULT_OUTPUT_VOLUME;
- omap_regs[PCM_INDEX].r_reg = DEFAULT_OUTPUT_VOLUME;
- omap_regs[PCM_INDEX].sw = 1;
- SND_OMAP_WRITE(LEFT_CHANNEL_VOLUME_ADDR, vol_reg);
- SND_OMAP_WRITE(RIGHT_CHANNEL_VOLUME_ADDR, vol_reg);
-}
-
-int snd_omap_mixer(struct snd_card_omap_codec *chip)
-{
- struct snd_card *card;
- unsigned int idx;
- int err;
-
- snd_assert(chip != NULL && chip->card != NULL, return -EINVAL);
-
- card = chip->card;
-
- strcpy(card->mixername, MIXER_NAME);
-
- /* Registering alsa mixer controls */
- for (idx = 0; idx < ARRAY_SIZE(snd_omap_controls); idx++) {
- err = snd_ctl_add(card,
- snd_ctl_new1(&snd_omap_controls[idx], chip));
- if (err < 0)
- return err;
- }
-
- return 0;
-}
+++ /dev/null
-/*
- * arch/arm/mach-omap1/omap-alsa-aic23.c
- *
- * Alsa codec Driver for AIC23 chip on OSK5912 platform board
- *
- * Copyright (C) 2005 Instituto Nokia de Tecnologia - INdT - Manaus Brazil
- * Written by Daniel Petrini, David Cohen, Anderson Briglia
- * {daniel.petrini, david.cohen, anderson.briglia}@indt.org.br
- *
- * Copyright (C) 2006 Mika Laitio <lamikr@cc.jyu.fi>
- *
- * Based in former alsa driver for osk and oss driver
- *
- * 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 <sound/core.h>
-#include <sound/pcm.h>
-#include <sound/initval.h>
-#include <sound/control.h>
-#include <linux/clk.h>
-#include <mach/clock.h>
-#include <mach/aic23.h>
-
-#include <mach/omap-alsa.h>
-#include "omap-alsa-aic23.h"
-
-static struct clk *aic23_mclk;
-
-/* aic23 related */
-static const struct aic23_samplerate_reg_info
- rate_reg_info[NUMBER_SAMPLE_RATES_SUPPORTED] = {
- {4000, 0x06, 1}, /* 4000 */
- {8000, 0x06, 0}, /* 8000 */
- {16000, 0x0C, 1}, /* 16000 */
- {22050, 0x11, 1}, /* 22050 */
- {24000, 0x00, 1}, /* 24000 */
- {32000, 0x0C, 0}, /* 32000 */
- {44100, 0x11, 0}, /* 44100 */
- {48000, 0x00, 0}, /* 48000 */
- {88200, 0x1F, 0}, /* 88200 */
- {96000, 0x0E, 0}, /* 96000 */
-};
-
-/*
- * 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[] = {
- 4000, 8000, 16000, 22050,
- 24000, 32000, 44100,
- 48000, 88200, 96000,
-};
-
-static struct snd_pcm_hw_constraint_list aic23_hw_constraints_rates = {
- .count = ARRAY_SIZE(rates),
- .list = rates,
- .mask = 0,
-};
-
-static struct snd_pcm_hardware aic23_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_16000 |
- SNDRV_PCM_RATE_22050 | SNDRV_PCM_RATE_32000 |
- SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000 |
- SNDRV_PCM_RATE_88200 | SNDRV_PCM_RATE_96000 |
- SNDRV_PCM_RATE_KNOT),
- .rate_min = 8000,
- .rate_max = 96000,
- .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 struct snd_pcm_hardware aic23_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_16000 |
- SNDRV_PCM_RATE_22050 | SNDRV_PCM_RATE_32000 |
- SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000 |
- SNDRV_PCM_RATE_88200 | SNDRV_PCM_RATE_96000 |
- SNDRV_PCM_RATE_KNOT),
- .rate_min = 8000,
- .rate_max = 96000,
- .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,
-};
-
-/*
- * Codec/mcbsp init and configuration section
- * codec dependent code.
- */
-
-/* TLV320AIC23 is a write only device */
-void audio_aic23_write(u8 address, u16 data)
-{
- aic23_write_value(address, data);
-}
-EXPORT_SYMBOL_GPL(audio_aic23_write);
-
-/*
- * Sample rate changing
- */
-void aic23_set_samplerate(long rate)
-{
- u8 count = 0;
- u16 data = 0;
-
- /* Fix the rate if it has a wrong value */
- if (rate >= 96000)
- rate = 96000;
- else if (rate >= 88200)
- rate = 88200;
- else if (rate >= 48000)
- rate = 48000;
- else if (rate >= 44100)
- rate = 44100;
- else if (rate >= 32000)
- rate = 32000;
- else if (rate >= 24000)
- rate = 24000;
- else if (rate >= 22050)
- rate = 22050;
- else if (rate >= 16000)
- rate = 16000;
- else if (rate >= 8000)
- rate = 8000;
- else
- rate = 4000;
-
- /* Search for the right sample rate */
- /* Verify what happens if the rate is not supported
- * now it goes to 96Khz */
- while ((rate_reg_info[count].sample_rate != rate) &&
- (count < (NUMBER_SAMPLE_RATES_SUPPORTED - 1))) {
- count++;
- }
-
- data = (rate_reg_info[count].divider << CLKIN_SHIFT) |
- (rate_reg_info[count].control << BOSR_SHIFT) | USB_CLK_ON;
-
- audio_aic23_write(SAMPLE_RATE_CONTROL_ADDR, data);
-}
-
-inline void aic23_configure(void)
-{
- /* Reset codec */
- audio_aic23_write(RESET_CONTROL_ADDR, 0);
-
- /* Initialize the AIC23 internal state */
-
- /*
- * Analog audio path control, DAC selected,
- * delete INSEL_MIC for line-in
- */
- audio_aic23_write(ANALOG_AUDIO_CONTROL_ADDR,
- DEFAULT_ANALOG_AUDIO_CONTROL);
-
- /* Digital audio path control, de-emphasis control 44.1kHz */
- audio_aic23_write(DIGITAL_AUDIO_CONTROL_ADDR, DEEMP_44K);
-
- /* Digital audio interface, master/slave mode, I2S, 16 bit */
-#ifdef AIC23_MASTER
- audio_aic23_write(DIGITAL_AUDIO_FORMAT_ADDR,
- MS_MASTER | IWL_16 | FOR_DSP);
-#else
- audio_aic23_write(DIGITAL_AUDIO_FORMAT_ADDR, IWL_16 | FOR_DSP);
-#endif
-
- /* Enable digital interface */
- audio_aic23_write(DIGITAL_INTERFACE_ACT_ADDR, ACT_ON);
-}
-
-/*
- * OMAP MCBSP clock configuration and Power Management
- *
- * Here we have some functions that allow 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
- */
-void aic23_clock_setup(void)
-{
- aic23_mclk = clk_get(0, "mclk");
-}
-
-/*
- * Do some sanity check, set clock rate, starts it and
- * turn codec audio on
- */
-int aic23_clock_on(void)
-{
- uint curRate;
-
- if (clk_get_usecount(aic23_mclk) > 0) {
- /* MCLK is already in use */
- printk(KERN_WARNING
- "MCLK in use at %d Hz. We change it to %d Hz\n",
- (uint) clk_get_rate(aic23_mclk),
- CODEC_CLOCK);
- }
- curRate = (uint)clk_get_rate(aic23_mclk);
- if (curRate != CODEC_CLOCK) {
- if (clk_set_rate(aic23_mclk, CODEC_CLOCK)) {
- printk(KERN_ERR
- "Cannot set MCLK for AIC23 CODEC\n");
- return -ECANCELED;
- }
- }
- clk_enable(aic23_mclk);
-
- printk(KERN_DEBUG
- "MCLK = %d [%d], usecount = %d\n",
- (uint) clk_get_rate(aic23_mclk), CODEC_CLOCK,
- clk_get_usecount(aic23_mclk));
-
- /* Now turn the audio on */
- audio_aic23_write(POWER_DOWN_CONTROL_ADDR,
- ~DEVICE_POWER_OFF & ~OUT_OFF & ~DAC_OFF &
- ~ADC_OFF & ~MIC_OFF & ~LINE_OFF);
- return 0;
-}
-
-/*
- * Do some sanity check, turn clock off and then turn
- * codec audio off
- */
-int aic23_clock_off(void)
-{
- if (clk_get_usecount(aic23_mclk) > 0) {
- if (clk_get_rate(aic23_mclk) != CODEC_CLOCK) {
- printk(KERN_WARNING
- "MCLK for audio should be %d Hz. But is %d Hz\n",
- (uint) clk_get_rate(aic23_mclk),
- CODEC_CLOCK);
- }
-
- clk_disable(aic23_mclk);
- }
-
- audio_aic23_write(POWER_DOWN_CONTROL_ADDR,
- DEVICE_POWER_OFF | OUT_OFF | DAC_OFF |
- ADC_OFF | MIC_OFF | LINE_OFF);
- return 0;
-}
-
-int aic23_get_default_samplerate(void)
-{
- return DEFAULT_SAMPLE_RATE;
-}
-
-static int __devinit snd_omap_alsa_aic23_probe(struct platform_device *pdev)
-{
- int ret;
- struct omap_alsa_codec_config *codec_cfg;
-
- codec_cfg = pdev->dev.platform_data;
- if (codec_cfg != NULL) {
- codec_cfg->hw_constraints_rates = &aic23_hw_constraints_rates;
- codec_cfg->snd_omap_alsa_playback =
- &aic23_snd_omap_alsa_playback;
- codec_cfg->snd_omap_alsa_capture = &aic23_snd_omap_alsa_capture;
- codec_cfg->codec_configure_dev = aic23_configure;
- codec_cfg->codec_set_samplerate = aic23_set_samplerate;
- codec_cfg->codec_clock_setup = aic23_clock_setup;
- codec_cfg->codec_clock_on = aic23_clock_on;
- codec_cfg->codec_clock_off = aic23_clock_off;
- codec_cfg->get_default_samplerate =
- aic23_get_default_samplerate;
- ret = snd_omap_alsa_post_probe(pdev, codec_cfg);
- } else
- ret = -ENODEV;
- return ret;
-}
-
-static struct platform_driver omap_alsa_driver = {
- .probe = snd_omap_alsa_aic23_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_aic23_init(void)
-{
- int err;
-
- ADEBUG();
- err = platform_driver_register(&omap_alsa_driver);
-
- return err;
-}
-
-static void __exit omap_alsa_aic23_exit(void)
-{
- ADEBUG();
-
- platform_driver_unregister(&omap_alsa_driver);
-}
-
-module_init(omap_alsa_aic23_init);
-module_exit(omap_alsa_aic23_exit);
+++ /dev/null
-/*
- * sound/arm/omap-alsa-aic23.h
- *
- * Alsa Driver for AIC23 codec on OSK5912 platform board
- *
- * Copyright (C) 2005 Instituto Nokia de Tecnologia - INdT - Manaus Brazil
- * Written by Daniel Petrini, David Cohen, Anderson Briglia
- * {daniel.petrini, david.cohen, anderson.briglia}@indt.org.br
- *
- * Copyright (C) 2006 Mika Laitio <lamikr@cc.jyu.fi>
- *
- * 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_AIC23_H
-#define __OMAP_ALSA_AIC23_H
-
-#include <mach/dma.h>
-#include <sound/core.h>
-#include <sound/pcm.h>
-#include <mach/mcbsp.h>
-
-/* Define to set the AIC23 as the master w.r.t McBSP */
-#define AIC23_MASTER
-
-#define NUMBER_SAMPLE_RATES_SUPPORTED 10
-
-/*
- * AUDIO related MACROS
- */
-#ifndef DEFAULT_BITPERSAMPLE
-#define DEFAULT_BITPERSAMPLE 16
-#endif
-
-#define DEFAULT_SAMPLE_RATE 44100
-#define CODEC_CLOCK 12000000
-#define AUDIO_MCBSP OMAP_MCBSP1
-
-#define DEFAULT_OUTPUT_VOLUME 0x60
-#define DEFAULT_INPUT_VOLUME 0x00 /* 0 ==> mute line in */
-
-#define OUTPUT_VOLUME_MIN LHV_MIN
-#define OUTPUT_VOLUME_MAX LHV_MAX
-#define OUTPUT_VOLUME_RANGE (OUTPUT_VOLUME_MAX - OUTPUT_VOLUME_MIN)
-#define OUTPUT_VOLUME_MASK OUTPUT_VOLUME_MAX
-
-#define INPUT_VOLUME_MIN LIV_MIN
-#define INPUT_VOLUME_MAX LIV_MAX
-#define INPUT_VOLUME_RANGE (INPUT_VOLUME_MAX - INPUT_VOLUME_MIN)
-#define INPUT_VOLUME_MASK INPUT_VOLUME_MAX
-
-#define SIDETONE_MASK 0x1c0
-#define SIDETONE_0 0x100
-#define SIDETONE_6 0x000
-#define SIDETONE_9 0x040
-#define SIDETONE_12 0x080
-#define SIDETONE_18 0x0c0
-
-#define DEFAULT_ANALOG_AUDIO_CONTROL (DAC_SELECTED | STE_ENABLED | \
- BYPASS_ON | INSEL_MIC | MICB_20DB)
-
-struct aic23_samplerate_reg_info {
- u32 sample_rate;
- u8 control; /* SR3, SR2, SR1, SR0 and BOSR */
- u8 divider; /* if 0 CLKIN = MCLK, if 1 CLKIN = MCLK/2 */
-};
-
-extern int aic23_write_value(u8 reg, u16 value);
-
-/*
- * Defines codec specific function pointers that can be used from the
- * common omap-alsa base driver for all omap codecs. (tsc2101 and aic23)
- */
-void audio_aic23_write(u8 address, u16 data);
-void define_codec_functions(struct omap_alsa_codec_config *codec_config);
-inline void aic23_configure(void);
-void aic23_set_samplerate(long rate);
-void aic23_clock_setup(void);
-int aic23_clock_on(void);
-int aic23_clock_off(void);
-int aic23_get_default_samplerate(void);
-
-#endif
+++ /dev/null
-/*
- * sound/arm/omap/omap-alsa-dma.c
- *
- * Common audio DMA handling for the OMAP processors
- *
- * Copyright (C) 2006 Mika Laitio <lamikr@cc.jyu.fi>
- *
- * Copyright (C) 2005 Instituto Nokia de Tecnologia - INdT - Manaus Brazil
- *
- * Copyright (C) 2004 Texas Instruments, Inc.
- *
- * Copyright (C) 2000, 2001 Nicolas Pitre <nico@cam.org>
- *
- * This package is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * THIS PACKAGE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
- * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
- * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
- *
- * History:
- *
- * 2004-06-07 Sriram Kannan - Created new file from omap_audio_dma_intfc.c.
- * This file will contain only the DMA interface
- * and buffer handling of OMAP audio driver.
- *
- * 2004-06-22 Sriram Kannan - removed legacy code (auto-init). Self-linking
- * of DMA logical channel.
- *
- * 2004-08-12 Nishanth Menon - Modified to integrate Audio requirements on
- * 1610, 1710 platforms
- *
- * 2004-11-01 Nishanth Menon - 16xx platform code base modified to support
- * multi channel chaining.
- *
- * 2004-12-15 Nishanth Menon - Improved 16xx platform channel logic
- * introduced - tasklets, queue handling updated
- *
- * 2005-07-19 INdT Kernel Team - Alsa port. Creation of new file
- * omap-alsa-dma.c based in omap-audio-dma-intfc.c
- * oss file. Support for aic23 codec. Removal of
- * buffer handling (Alsa does that), modifications
- * in dma handling and port to alsa structures.
- *
- * 2005-12-18 Dirk Behme - Added L/R Channel Interchange fix as proposed
- * by Ajaya Babu
- */
-
-#include <linux/module.h>
-#include <linux/init.h>
-#include <linux/types.h>
-#include <linux/fs.h>
-#include <linux/mm.h>
-#include <linux/slab.h>
-#include <linux/sched.h>
-#include <linux/poll.h>
-#include <linux/pm.h>
-#include <linux/errno.h>
-#include <linux/sound.h>
-#include <linux/soundcard.h>
-#include <linux/sysrq.h>
-#include <linux/interrupt.h>
-#include <linux/dma-mapping.h>
-#include <linux/io.h>
-#include <linux/uaccess.h>
-#include <linux/semaphore.h>
-
-#include <mach/hardware.h>
-#include <mach/dma.h>
-#include <mach/mcbsp.h>
-#include <mach/omap-alsa.h>
-
-#include "omap-alsa-dma.h"
-
-#undef DEBUG
-
-/*
- * Channel Queue Handling macros
- * tail always points to the current free entry
- * Head always points to the current entry being used
- * end is either head or tail
- */
-
-#define AUDIO_QUEUE_INIT(s) s->dma_q_head = s->dma_q_tail = s->dma_q_count = 0;
-#define AUDIO_QUEUE_FULL(s) (nr_linked_channels == s->dma_q_count)
-#define AUDIO_QUEUE_LAST(s) (1 == s->dma_q_count)
-#define AUDIO_QUEUE_EMPTY(s) (0 == s->dma_q_count)
-#define __AUDIO_INCREMENT_QUEUE(end) ((end) = ((end)+1) % nr_linked_channels)
-#define AUDIO_INCREMENT_HEAD(s) \
- do { \
- __AUDIO_INCREMENT_QUEUE(s->dma_q_head); \
- s->dma_q_count--; \
- } while (0)
-#define AUDIO_INCREMENT_TAIL(s) \
- do { \
- __AUDIO_INCREMENT_QUEUE(s->dma_q_tail); \
- s->dma_q_count++; \
- } while (0)
-
-/* DMA buffer fragmentation sizes */
-#define MAX_DMA_SIZE 0x1000000 /* todo: sync with alsa */
-/* #define CUT_DMA_SIZE 0x1000 */
-/* TODO: To be moved to more appropriate location */
-#define DCSR_ERROR 0x3
-#define DCSR_END_BLOCK (1 << 5)
-#define DCSR_SYNC_SET (1 << 6)
-
-#define DCCR_FS (1 << 5)
-#define DCCR_PRIO (1 << 6)
-#define DCCR_AI (1 << 8)
-#define DCCR_REPEAT (1 << 9)
-/* if 0 the channel works in 3.1 compatible mode */
-#define DCCR_N31COMP (1 << 10)
-#define DCCR_EP (1 << 11)
-#define DCCR_SRC_AMODE_BIT 12
-#define DCCR_SRC_AMODE_MASK (0x3<<12)
-#define DCCR_DST_AMODE_BIT 14
-#define DCCR_DST_AMODE_MASK (0x3<<14)
-#define AMODE_CONST 0x0
-#define AMODE_POST_INC 0x1
-#define AMODE_SINGLE_INDEX 0x2
-#define AMODE_DOUBLE_INDEX 0x3
-
-/* Data structures */
-DEFINE_SPINLOCK(dma_list_lock);
-static char nr_linked_channels = 1;
-
-/* Module specific functions */
-
-static void sound_dma_irq_handler(int lch, u16 ch_status, void *data);
-static int audio_set_dma_params_play(int channel, dma_addr_t dma_ptr,
- u_int dma_size);
-static int audio_set_dma_params_capture(int channel, dma_addr_t dma_ptr,
- u_int dma_size);
-static int audio_start_dma_chain(struct audio_stream *s);
-
-/*
- * DMA channel requests
- */
-static void omap_sound_dma_link_lch(void *data)
-{
-
- struct audio_stream *s = (struct audio_stream *) data;
- int *chan = s->lch;
- int i;
-
- FN_IN;
- if (s->linked) {
- FN_OUT(1);
- return;
- }
- for (i = 0; i < nr_linked_channels; i++) {
- int cur_chan = chan[i];
- int nex_chan =
- ((nr_linked_channels - 1 ==
- i) ? chan[0] : chan[i + 1]);
- omap_dma_link_lch(cur_chan, nex_chan);
- }
- s->linked = 1;
- FN_OUT(0);
-}
-
-int omap_request_alsa_sound_dma(int device_id, const char *device_name,
- void *data, int **channels)
-{
- int i, err = 0;
- int *chan = NULL;
- FN_IN;
- if (unlikely((NULL == channels) || (NULL == device_name))) {
- BUG();
- return -EPERM;
- }
- /* Try allocate memory for the num channels */
- *channels = kmalloc(sizeof(int) * nr_linked_channels, GFP_KERNEL);
- chan = *channels;
- if (NULL == chan) {
- ERR("No Memory for channel allocs!\n");
- FN_OUT(-ENOMEM);
- return -ENOMEM;
- }
- spin_lock(&dma_list_lock);
- for (i = 0; i < nr_linked_channels; i++) {
- err = omap_request_dma(device_id,
- device_name,
- sound_dma_irq_handler,
- data,
- &chan[i]);
-
- /* Handle Failure condition here */
- if (err < 0) {
- int j;
-
- for (j = 0; j < i; j++)
- omap_free_dma(chan[j]);
-
- spin_unlock(&dma_list_lock);
- kfree(chan);
- *channels = NULL;
- ERR("Error in requesting channel %d=0x%x\n", i,
- err);
- FN_OUT(err);
- return err;
- }
- }
-
- /* Chain the channels together */
- if (!cpu_is_omap15xx())
- omap_sound_dma_link_lch(data);
-
- spin_unlock(&dma_list_lock);
- FN_OUT(0);
- return 0;
-}
-EXPORT_SYMBOL(omap_request_alsa_sound_dma);
-
-/*
- * DMA channel requests Freeing
- */
-static void omap_sound_dma_unlink_lch(void *data)
-{
- struct audio_stream *s = (struct audio_stream *)data;
- int *chan = s->lch;
- int i;
-
- FN_IN;
- if (!s->linked) {
- FN_OUT(1);
- return;
- }
- for (i = 0; i < nr_linked_channels; i++) {
- int cur_chan = chan[i];
- int nex_chan =
- ((nr_linked_channels - 1 ==
- i) ? chan[0] : chan[i + 1]);
- omap_dma_unlink_lch(cur_chan, nex_chan);
- }
- s->linked = 0;
- FN_OUT(0);
-}
-
-int omap_free_alsa_sound_dma(void *data, int **channels)
-{
- int i;
- int *chan = NULL;
-
- FN_IN;
- if (unlikely(NULL == channels)) {
- BUG();
- return -EPERM;
- }
- if (unlikely(NULL == *channels)) {
- BUG();
- return -EPERM;
- }
- chan = (*channels);
-
- if (!cpu_is_omap15xx())
- omap_sound_dma_unlink_lch(data);
- for (i = 0; i < nr_linked_channels; i++) {
- int cur_chan = chan[i];
- omap_stop_dma(cur_chan);
- omap_free_dma(cur_chan);
- }
- kfree(*channels);
- *channels = NULL;
- FN_OUT(0);
- return 0;
-}
-EXPORT_SYMBOL(omap_free_alsa_sound_dma);
-
-/*
- * Stop all the DMA channels of the stream
- */
-void omap_stop_alsa_sound_dma(struct audio_stream *s)
-{
- int *chan = s->lch;
- int i;
-
- FN_IN;
- if (unlikely(NULL == chan)) {
- BUG();
- return;
- }
- for (i = 0; i < nr_linked_channels; i++) {
- int cur_chan = chan[i];
- omap_stop_dma(cur_chan);
- }
- s->started = 0;
- FN_OUT(0);
- return;
-}
-EXPORT_SYMBOL(omap_stop_alsa_sound_dma);
-
-/*
- * Clear any pending transfers
- */
-void omap_clear_alsa_sound_dma(struct audio_stream *s)
-{
- FN_IN;
- omap_clear_dma(s->lch[s->dma_q_head]);
- FN_OUT(0);
- return;
-}
-EXPORT_SYMBOL(omap_clear_alsa_sound_dma);
-
-/*
- * DMA related functions
- */
-static int audio_set_dma_params_play(int channel, dma_addr_t dma_ptr,
- u_int dma_size)
-{
- int dt = 0x1; /* data type 16 */
- int cen = 32; /* Stereo */
- int cfn = dma_size / (2 * cen);
-
- FN_IN;
- omap_set_dma_dest_params(channel, 0x05, 0x00,
- (OMAP1510_MCBSP1_BASE + 0x06),
- 0, 0);
- omap_set_dma_src_params(channel, 0x00, 0x01, dma_ptr,
- 0, 0);
- omap_set_dma_transfer_params(channel, dt, cen, cfn, 0x00, 0, 0);
- FN_OUT(0);
- return 0;
-}
-
-static int audio_set_dma_params_capture(int channel, dma_addr_t dma_ptr,
- u_int dma_size)
-{
- int dt = 0x1; /* data type 16 */
- int cen = 32; /* stereo */
- int cfn = dma_size / (2 * cen);
-
- FN_IN;
- omap_set_dma_src_params(channel, 0x05, 0x00,
- (OMAP1510_MCBSP1_BASE + 0x02),
- 0, 0);
- omap_set_dma_dest_params(channel, 0x00, 0x01, dma_ptr, 0, 0);
- omap_set_dma_transfer_params(channel, dt, cen, cfn, 0x00, 0, 0);
- FN_OUT(0);
- return 0;
-}
-
-static int audio_start_dma_chain(struct audio_stream *s)
-{
- int channel = s->lch[s->dma_q_head];
- FN_IN;
- if (!s->started) {
- s->hw_stop(); /* stops McBSP Interface */
- omap_start_dma(channel);
- s->started = 1;
- s->hw_start(); /* start McBSP interface */
- } else if (cpu_is_omap310())
- omap_start_dma(channel);
- /* else the dma itself will progress forward with out our help */
- FN_OUT(0);
- return 0;
-}
-
-/*
- * Start DMA -
- * Do the initial set of work to initialize all the channels as required.
- * We shall then initate a transfer
- */
-int omap_start_alsa_sound_dma(struct audio_stream *s,
- dma_addr_t dma_ptr,
- u_int dma_size)
-{
- int ret = -EPERM;
-
- FN_IN;
-
- if (unlikely(dma_size > MAX_DMA_SIZE)) {
- ERR("DmaSoundDma: Start: overflowed %d-%d\n", dma_size,
- MAX_DMA_SIZE);
- return -EOVERFLOW;
- }
-
- if (s->stream_id == SNDRV_PCM_STREAM_PLAYBACK) {
- /* playback */
- ret =
- audio_set_dma_params_play(s->lch[s->dma_q_tail],
- dma_ptr, dma_size);
- } else {
- ret =
- audio_set_dma_params_capture(s->lch[s->dma_q_tail],
- dma_ptr, dma_size);
- }
- if (ret != 0) {
- ret = -3; /* indicate queue full */
- goto sound_out;
- }
- AUDIO_INCREMENT_TAIL(s);
- ret = audio_start_dma_chain(s);
- if (ret)
- ERR("dma start failed");
-
-sound_out:
- FN_OUT(ret);
- return ret;
-
-}
-EXPORT_SYMBOL(omap_start_alsa_sound_dma);
-
-/*
- * ISRs have to be short and smart..
- * Here we call alsa handling, after some error checking
- */
-static void sound_dma_irq_handler(int sound_curr_lch, u16 ch_status,
- void *data)
-{
- int dma_status = ch_status;
- struct audio_stream *s = (struct audio_stream *) data;
- FN_IN;
-
- /* some register checking */
- DPRINTK("lch=%d,status=0x%x, dma_status=%d, data=%p\n",
- sound_curr_lch, ch_status, dma_status, data);
-
- if (dma_status & (DCSR_ERROR)) {
- omap_stop_dma(sound_curr_lch);
- ERR("DCSR_ERROR!\n");
- FN_OUT(-1);
- return;
- }
-
- if (ch_status & DCSR_END_BLOCK)
- callback_omap_alsa_sound_dma(s);
- FN_OUT(0);
- return;
-}
-
-MODULE_AUTHOR("Texas Instruments");
-MODULE_DESCRIPTION("Common DMA handling for Audio driver on OMAP processors");
-MODULE_LICENSE("GPL");
-
+++ /dev/null
-/*
- * linux/sound/arm/omap/omap-alsa-dma.h
- *
- * Common audio DMA handling for the OMAP processors
- *
- * Copyright (C) 2006 Mika Laitio <lamikr@cc.jyu.fi>
- *
- * Copyright (C) 2005 Instituto Nokia de Tecnologia - INdT - Manaus Brazil
- *
- * Copyright (C) 2004 Texas Instruments, Inc.
- *
- * Copyright (C) 2000, 2001 Nicolas Pitre <nico@cam.org>
- *
- * This package is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * THIS PACKAGE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
- * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
- * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
- *
- * History:
- *
- *
- * 2004/08/12 Nishanth Menon - Modified to integrate Audio requirements on
- * 1610, 1710 platforms
- *
- * 2005/07/25 INdT Kernel Team - Renamed to omap-alsa-dma.h. Ported to Alsa.
- */
-
-#ifndef __OMAP_AUDIO_ALSA_DMA_H
-#define __OMAP_AUDIO_ALSA_DMA_H
-
-#include <mach/omap-alsa.h>
-
-/* Global data structures */
-
-typedef void (*dma_callback_t) (int lch, u16 ch_status, void *data);
-
-/* arch specific functions */
-
-void omap_clear_alsa_sound_dma(struct audio_stream *s);
-
-int omap_request_alsa_sound_dma(int device_id, const char *device_name,
- void *data, int **channels);
-int omap_free_alsa_sound_dma(void *data, int **channels);
-
-int omap_start_alsa_sound_dma(struct audio_stream *s, dma_addr_t dma_ptr,
- u_int dma_size);
-
-void omap_stop_alsa_sound_dma(struct audio_stream *s);
-
-#endif
+++ /dev/null
-/*
- * sound/arm/omap/omap-alsa-sx1-mixer.c
- *
- * 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.
- *
- */
-
-#include "omap-alsa-sx1.h"
-#include "omap-alsa-sx1-mixer.h"
-
-#include <linux/types.h>
-#include <sound/initval.h>
-#include <sound/control.h>
-
-static int current_playback_target = PLAYBACK_TARGET_LOUDSPEAKER;
-static int current_rec_src = REC_SRC_SINGLE_ENDED_MICIN_HED;
-static int current_volume; /* current volume, we cant read it */
-static int current_fm_volume; /* current FM radio volume, we cant read it */
-
-/*
- * Select SX1 recording source.
- */
-static void set_record_source(int val)
-{
- /* TODO Recording is done on McBSP2 and Mic only */
- current_rec_src = val;
-}
-
-static int set_mixer_volume(int mixer_vol)
-{
- int ret, i;
- if ((mixer_vol < 0) || (mixer_vol > 9)) {
- printk(KERN_ERR "Trying a bad mixer volume (%d)!\n", mixer_vol);
- return -EPERM;
- }
- ret = (current_volume != mixer_vol);
- current_volume = mixer_vol; /* set current volume, we cant read it */
-
- i = cn_sx1snd_send(DAC_VOLUME_UPDATE, mixer_vol, 0);
- if (i)
- return i;
- return ret;
-}
-
-static void set_loudspeaker_to_playback_target(void)
-{
- /* TODO */
- cn_sx1snd_send(DAC_SETAUDIODEVICE, SX1_DEVICE_SPEAKER, 0);
-
- current_playback_target = PLAYBACK_TARGET_LOUDSPEAKER;
-}
-
-static void set_headphone_to_playback_target(void)
-{
- /* TODO */
- cn_sx1snd_send(DAC_SETAUDIODEVICE, SX1_DEVICE_HEADPHONE, 0);
-
- current_playback_target = PLAYBACK_TARGET_HEADPHONE;
-}
-
-static void set_telephone_to_playback_target(void)
-{
- /* TODO */
- cn_sx1snd_send(DAC_SETAUDIODEVICE, SX1_DEVICE_PHONE, 0);
-
- current_playback_target = PLAYBACK_TARGET_CELLPHONE;
-}
-
-static void set_telephone_to_record_source(void)
-{
- cn_sx1snd_send(DAC_SETAUDIODEVICE, SX1_DEVICE_PHONE, 0);
-}
-
-static void init_playback_targets(void)
-{
- set_loudspeaker_to_playback_target();
- set_mixer_volume(DEFAULT_OUTPUT_VOLUME);
-}
-
-/*
- * Initializes SX1 record source (to mic) and playback target (to loudspeaker)
- */
-void snd_omap_init_mixer(void)
-{
- /* Select headset to record source */
- set_record_source(REC_SRC_SINGLE_ENDED_MICIN_HED);
- /* Init loudspeaker as a default playback target*/
- init_playback_targets();
-}
-
-/* ---------------------------------------------------------------------- */
-static int pcm_playback_target_info(struct snd_kcontrol *kcontrol,
- struct snd_ctl_elem_info *uinfo)
-{
- static char *texts[PLAYBACK_TARGET_COUNT] = {
- "Loudspeaker", "Headphone", "Cellphone"
- };
-
- uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
- uinfo->count = 1;
- uinfo->value.enumerated.items = PLAYBACK_TARGET_COUNT;
- if (uinfo->value.enumerated.item > PLAYBACK_TARGET_COUNT - 1)
- uinfo->value.enumerated.item = PLAYBACK_TARGET_COUNT - 1;
-
- strcpy(uinfo->value.enumerated.name,
- texts[uinfo->value.enumerated.item]);
- return 0;
-}
-
-static int pcm_playback_target_get(struct snd_kcontrol *kcontrol,
- struct snd_ctl_elem_value *ucontrol)
-{
- ucontrol->value.integer.value[0] = current_playback_target;
- return 0;
-}
-
-static int pcm_playback_target_put(struct snd_kcontrol *kcontrol,
- struct snd_ctl_elem_value *ucontrol)
-{
- int ret_val = 0;
- int cur_val = ucontrol->value.integer.value[0];
-
- if ((cur_val >= 0) &&
- (cur_val < PLAYBACK_TARGET_COUNT) &&
- (cur_val != current_playback_target)) {
- if (cur_val == PLAYBACK_TARGET_LOUDSPEAKER) {
- set_record_source(REC_SRC_SINGLE_ENDED_MICIN_HED);
- set_loudspeaker_to_playback_target();
- } else if (cur_val == PLAYBACK_TARGET_HEADPHONE) {
- set_record_source(REC_SRC_SINGLE_ENDED_MICIN_HND);
- set_headphone_to_playback_target();
- } else if (cur_val == PLAYBACK_TARGET_CELLPHONE) {
- set_telephone_to_record_source();
- set_telephone_to_playback_target();
- }
- ret_val = 1;
- }
- return ret_val;
-}
-
-/*-----------------------------------------------------------*/
-static int pcm_playback_volume_info(struct snd_kcontrol *kcontrol,
- struct snd_ctl_elem_info *uinfo)
-{
- uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
- uinfo->count = 1;
- uinfo->value.integer.min = 0;
- uinfo->value.integer.max = 9;
- return 0;
-}
-
-static int pcm_playback_volume_get(struct snd_kcontrol *kcontrol,
- struct snd_ctl_elem_value *ucontrol)
-{
- ucontrol->value.integer.value[0] = current_volume;
- return 0;
-}
-
-static int pcm_playback_volume_put(struct snd_kcontrol *kcontrol,
- struct snd_ctl_elem_value *ucontrol)
-{
- return set_mixer_volume(ucontrol->value.integer.value[0]);
-}
-
-static int pcm_playback_switch_info(struct snd_kcontrol *kcontrol,
- struct snd_ctl_elem_info *uinfo)
-{
- uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN;
- uinfo->count = 1;
- uinfo->value.integer.min = 0;
- uinfo->value.integer.max = 1;
- return 0;
-}
-
-static int pcm_playback_switch_get(struct snd_kcontrol *kcontrol,
- struct snd_ctl_elem_value *ucontrol)
-{
- ucontrol->value.integer.value[0] = 1;
- return 0;
-}
-
-static int pcm_playback_switch_put(struct snd_kcontrol *kcontrol,
- struct snd_ctl_elem_value *ucontrol)
-{
- return 0;
-}
-
-/* ----------------------------------------------------------- */
-
-static int headset_playback_volume_info(struct snd_kcontrol *kcontrol,
- struct snd_ctl_elem_info *uinfo)
-{
- uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
- uinfo->count = 1;
- uinfo->value.integer.min = 0;
- uinfo->value.integer.max = 9;
- return 0;
-}
-
-static int headset_playback_volume_get(struct snd_kcontrol *kcontrol,
- struct snd_ctl_elem_value *ucontrol)
-{
- ucontrol->value.integer.value[0] = current_volume;
- return 0;
-}
-
-static int headset_playback_volume_put(struct snd_kcontrol *kcontrol,
- struct snd_ctl_elem_value *ucontrol)
-{
- return set_mixer_volume(ucontrol->value.integer.value[0]);
-}
-
-static int headset_playback_switch_info(struct snd_kcontrol *kcontrol,
- struct snd_ctl_elem_info *uinfo)
-{
- uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN;
- uinfo->count = 1;
- uinfo->value.integer.min = 0;
- uinfo->value.integer.max = 1;
- return 0;
-}
-
-static int headset_playback_switch_get(struct snd_kcontrol *kcontrol,
- struct snd_ctl_elem_value *ucontrol)
-{
- ucontrol->value.integer.value[0] = 1;
- return 0;
-}
-
-static int headset_playback_switch_put(struct snd_kcontrol *kcontrol,
- struct snd_ctl_elem_value *ucontrol)
-{
- /* mute/unmute headset */
-#if 0
- return adc_pga_unmute_control(ucontrol->value.integer.value[0],
- TSC2101_HEADSET_GAIN_CTRL,
- 15);
-#endif
- return 0;
-}
-/* ----------------------------------------------------------- */
-static int fmradio_playback_volume_info(struct snd_kcontrol *kcontrol,
- struct snd_ctl_elem_info *uinfo)
-{
- uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
- uinfo->count = 1;
- uinfo->value.integer.min = 0;
- uinfo->value.integer.max = 9;
- return 0;
-}
-
-static int fmradio_playback_volume_get(struct snd_kcontrol *kcontrol,
- struct snd_ctl_elem_value *ucontrol)
-{
- ucontrol->value.integer.value[0] = current_fm_volume;
- return 0;
-}
-
-static int fmradio_playback_volume_put(struct snd_kcontrol *kcontrol,
- struct snd_ctl_elem_value *ucontrol)
-{
- int ret = current_fm_volume != ucontrol->value.integer.value[0];
- int i;
- current_fm_volume = ucontrol->value.integer.value[0];
- i = cn_sx1snd_send(DAC_FMRADIO_OPEN, current_fm_volume, 0);
- if (i)
- return i;
- return ret;
-}
-
-static int fmradio_playback_switch_info(struct snd_kcontrol *kcontrol,
- struct snd_ctl_elem_info *uinfo)
-{
- uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN;
- uinfo->count = 1;
- uinfo->value.integer.min = 0;
- uinfo->value.integer.max = 1;
- return 0;
-}
-
-static int fmradio_playback_switch_get(struct snd_kcontrol *kcontrol,
- struct snd_ctl_elem_value *ucontrol)
-{
- ucontrol->value.integer.value[0] = 1;
- return 0;
-}
-
-static int fmradio_playback_switch_put(struct snd_kcontrol *kcontrol,
- struct snd_ctl_elem_value *ucontrol)
-{
- /* mute/unmute FM radio */
- if (ucontrol->value.integer.value[0])
- cn_sx1snd_send(DAC_FMRADIO_OPEN, current_fm_volume, 0);
- else
- cn_sx1snd_send(DAC_FMRADIO_CLOSE, 0, 0);
-
- return 0;
-}
-/* ----------------------------------------------------------- */
-static int cellphone_input_switch_info(struct snd_kcontrol *kcontrol,
- struct snd_ctl_elem_info *uinfo)
-{
- uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN;
- uinfo->count = 1;
- uinfo->value.integer.min = 0;
- uinfo->value.integer.max = 1;
- return 0;
-}
-
-static int cellphone_input_switch_get(struct snd_kcontrol *kcontrol,
- struct snd_ctl_elem_value *ucontrol)
-{
- ucontrol->value.integer.value[0] = 1;
- return 0;
-}
-
-static int cellphone_input_switch_put(struct snd_kcontrol *kcontrol,
- struct snd_ctl_elem_value *ucontrol)
-{
-#if 0
- return adc_pga_unmute_control(ucontrol->value.integer.value[0],
- TSC2101_BUZZER_GAIN_CTRL, 15);
-#endif
- return 0;
-}
-/* ----------------------------------------------------------- */
-
-static int buzzer_input_switch_info(struct snd_kcontrol *kcontrol,
- struct snd_ctl_elem_info *uinfo)
-{
- uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN;
- uinfo->count = 1;
- uinfo->value.integer.min = 0;
- uinfo->value.integer.max = 1;
- return 0;
-}
-
-static int buzzer_input_switch_get(struct snd_kcontrol *kcontrol,
- struct snd_ctl_elem_value *ucontrol)
-{
- ucontrol->value.integer.value[0] = 1;
- return 0;
-}
-
-static int buzzer_input_switch_put(struct snd_kcontrol *kcontrol,
- struct snd_ctl_elem_value *ucontrol)
-{
-#if 0
- return adc_pga_unmute_control(ucontrol->value.integer.value[0],
- TSC2101_BUZZER_GAIN_CTRL, 6);
-#endif
- return 0;
-}
-/*-----------------------------------------------------------*/
-
-static struct snd_kcontrol_new egold_control[] __devinitdata = {
- {
- .name = "Playback Playback Route",
- .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
- .index = 0,
- .access = SNDRV_CTL_ELEM_ACCESS_READWRITE,
- .info = pcm_playback_target_info,
- .get = pcm_playback_target_get,
- .put = pcm_playback_target_put,
- }, {
- .name = "Master Playback Volume",
- .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
- .index = 0,
- .access = SNDRV_CTL_ELEM_ACCESS_READWRITE,
- .info = pcm_playback_volume_info,
- .get = pcm_playback_volume_get,
- .put = pcm_playback_volume_put,
- }, {
- .name = "Master Playback Switch",
- .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
- .index = 0,
- .access = SNDRV_CTL_ELEM_ACCESS_READWRITE,
- .info = pcm_playback_switch_info,
- .get = pcm_playback_switch_get,
- .put = pcm_playback_switch_put,
- }, {
- .name = "Headset Playback Volume",
- .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
- .index = 1,
- .access = SNDRV_CTL_ELEM_ACCESS_READWRITE,
- .info = headset_playback_volume_info,
- .get = headset_playback_volume_get,
- .put = headset_playback_volume_put,
- }, {
- .name = "Headset Playback Switch",
- .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
- .index = 1,
- .access = SNDRV_CTL_ELEM_ACCESS_READWRITE,
- .info = headset_playback_switch_info,
- .get = headset_playback_switch_get,
- .put = headset_playback_switch_put,
- }, {
- .name = "FM Playback Volume",
- .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
- .index = 2,
- .access = SNDRV_CTL_ELEM_ACCESS_READWRITE,
- .info = fmradio_playback_volume_info,
- .get = fmradio_playback_volume_get,
- .put = fmradio_playback_volume_put,
- }, {
- .name = "FM Playback Switch",
- .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
- .index = 2,
- .access = SNDRV_CTL_ELEM_ACCESS_READWRITE,
- .info = fmradio_playback_switch_info,
- .get = fmradio_playback_switch_get,
- .put = fmradio_playback_switch_put,
- }, {
- .name = "Cellphone Input Switch",
- .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
- .index = 0,
- .access = SNDRV_CTL_ELEM_ACCESS_READWRITE,
- .info = cellphone_input_switch_info,
- .get = cellphone_input_switch_get,
- .put = cellphone_input_switch_put,
- }, {
- .name = "Buzzer Input Switch",
- .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
- .index = 0,
- .access = SNDRV_CTL_ELEM_ACCESS_READWRITE,
- .info = buzzer_input_switch_info,
- .get = buzzer_input_switch_get,
- .put = buzzer_input_switch_put,
- }
-};
-
-#ifdef CONFIG_PM
-void snd_omap_suspend_mixer(void)
-{
-}
-
-void snd_omap_resume_mixer(void)
-{
- snd_omap_init_mixer();
-}
-#endif
-
-int snd_omap_mixer(struct snd_card_omap_codec *egold)
-{
- int i = 0;
- int err = 0;
-
- if (!egold)
- return -EINVAL;
-
- for (i = 0; i < ARRAY_SIZE(egold_control); i++) {
- err = snd_ctl_add(egold->card,
- snd_ctl_new1(&egold_control[i], egold->card));
- if (err < 0)
- return err;
- }
- return 0;
-}
+++ /dev/null
-/*
- * 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 OMAPALSASX1MIXER_H_
-#define OMAPALSASX1MIXER_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
-/* OSS code referred to MIXER_LINE */
-#define REC_SRC_SINGLE_ENDED_MICIN_HED 0x00
-/* OSS code referred to MIXER_MIC */
-#define REC_SRC_SINGLE_ENDED_MICIN_HND 0x01
-#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
+++ /dev/null
-/*
- * 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 <linux/io.h>
-#include <linux/connector.h>
-#include <linux/slab.h>
-#include <linux/pm.h>
-
-#include <mach/dma.h>
-#include <mach/clock.h>
-#include <mach/gpio.h>
-#include <mach/mcbsp.h>
-#include <mach/omap-alsa.h>
-
-#include "omap-alsa-sx1.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(KERN_INFO
- "%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 struct snd_pcm_hw_constraint_list egold_hw_constraints_rates = {
- .count = ARRAY_SIZE(rates),
- .list = rates,
- .mask = 0,
-};
-
-static struct snd_pcm_hardware 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 struct snd_pcm_hardware 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);
+++ /dev/null
-/*
- * 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
+++ /dev/null
-/*
- * sound/arm/omap/omap-alsa-tsc2101-mixer.c
- *
- * Alsa Driver for TSC2101 codec for OMAP platform boards.
- *
- * Copyright (C) 2005 Mika Laitio <lamikr@cc.jyu.fi> and
- * Everett Coleman II <gcc80x86@fuzzyneural.net>
- *
- * Board initialization code is based on the code in TSC2101 OSS driver.
- * Copyright (C) 2004 Texas Instruments, Inc.
- * Written by Nishanth Menon and Sriram Kannan
- *
- * 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.
- *
- * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
- * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN
- * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
- * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
- * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
- * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
- * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
- * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- * 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.
- *
- * History:
- *
- * 2006-03-01 Mika Laitio - Mixer for the tsc2101 driver used in omap boards.
- * Can switch between headset and loudspeaker playback,
- * mute and unmute dgc, set dgc volume. Record source switch,
- * keyclick, buzzer and headset volume and handset volume control
- * are still missing.
- *
- */
-
-#include "omap-alsa-tsc2101.h"
-#include "omap-alsa-tsc2101-mixer.h"
-
-#include <linux/spi/tsc2101.h>
-#include <linux/types.h>
-#include <sound/initval.h>
-#include <sound/control.h>
-
-#ifdef DEBUG
-#define M_DPRINTK(ARGS...) \
- do { \
- printk(KERN_INFO "<%s>: ", __func__); \
- printk(ARGS); \
- } while (0)
-#else
-#define M_DPRINTK(ARGS...) /* nop */
-#endif
-
-#define CHECK_BIT(INDX, ARG) (((ARG) & TSC2101_BIT(INDX)) >> INDX)
-#define IS_UNMUTED(INDX, ARG) (((CHECK_BIT(INDX, ARG)) == 0))
-
-#define DGC_DALVL_EXTRACT(ARG) ((ARG & 0x7f00) >> 8)
-#define DGC_DARVL_EXTRACT(ARG) ((ARG & 0x007f))
-
-#define HGC_ADPGA_HED_EXTRACT(ARG) ((ARG & 0x7f00) >> 8)
-#define HNGC_ADPGA_HND_EXTRACT(ARG) ((ARG & 0x7f00) >> 8)
-#define BGC_ADPGA_BGC_EXTRACT(ARG) ((ARG & 0x7f00) >> 8)
-
-static int current_playback_target = PLAYBACK_TARGET_LOUDSPEAKER;
-static int current_rec_src = REC_SRC_SINGLE_ENDED_MICIN_HED;
-
-/*
- * Simplified write for the tsc2101 audio registers.
- */
-inline void omap_tsc2101_audio_write(u8 address, u16 data)
-{
- tsc2101_write_sync(mcbsp_dev.tsc2101_dev, PAGE2_AUDIO_CODEC_REGISTERS,
- address, data);
-}
-
-/*
- * Simplified read for the tsc2101 audio registers.
- */
-inline u16 omap_tsc2101_audio_read(u8 address)
-{
- return (tsc2101_read_sync(mcbsp_dev.tsc2101_dev,
- PAGE2_AUDIO_CODEC_REGISTERS, address));
-}
-
-/*
- * For selecting tsc2101 recourd source.
- */
-static void set_record_source(int val)
-{
- u16 data;
-
- /*
- * Mute Analog Sidetone
- * Analog sidetone gain db?
- * Input selected by MICSEL connected to ADC
- */
- data = MPC_ASTMU | MPC_ASTG(0x45);
- data &= ~MPC_MICSEL(7); /* clear all MICSEL bits */
- data |= MPC_MICSEL(val);
- data |= MPC_MICADC;
- omap_tsc2101_audio_write(TSC2101_MIXER_PGA_CTRL, data);
-
- current_rec_src = val;
-}
-
-/*
- * Converts the Alsa mixer volume (0 - 100) to real
- * Digital Gain Control (DGC) value that can be written
- * or read from the TSC2101 registry.
- *
- * Note that the number "OUTPUT_VOLUME_MAX" is smaller than OUTPUT_VOLUME_MIN
- * because DGC works as a volume decreaser. (The more bigger value is put
- * to DGC, the more the volume of controlled channel is decreased)
- *
- * In addition the TCS2101 chip would allow the maximum
- * volume reduction be 63.5 DB
- * but according to some tests user can not hear anything with this chip
- * when the volume is set to be less than 25 db.
- * Therefore this function will return a value
- * that means 38.5 db (63.5 db - 25 db)
- * reduction in the channel volume, when mixer is set to 0.
- * For mixer value 100, this will return a value that means
- * 0 db volume reduction.
- * ([mute_left_bit]0000000[mute_right_bit]0000000)
- */
-int get_mixer_volume_as_dac_gain_control_volume(int vol)
-{
- u16 retVal;
-
- /* Convert 0 -> 100 volume to 0x7F(min) -> y(max) volume range */
- retVal = ((vol * OUTPUT_VOLUME_RANGE) / 100) + OUTPUT_VOLUME_MAX;
- /* invert the value for getting the proper range 0 min and 100 max */
- retVal = OUTPUT_VOLUME_MIN - retVal;
-
- return retVal;
-}
-
-/*
- * Converts the Alsa mixer volume (0 - 100) to TSC2101
- * Digital Gain Control (DGC) volume. Alsa mixer volume 0
- * is converted to value meaning the volume reduction of -38.5 db
- * and Alsa mixer volume 100 is converted to value meaning the
- * reduction of 0 db.
- */
-int set_mixer_volume_as_dac_gain_control_volume(int mixerVolL, int mixerVolR)
-{
- u16 val;
- int retVal;
- int volL;
- int volR;
-
- if ((mixerVolL < 0) ||
- (mixerVolL > 100) ||
- (mixerVolR < 0) ||
- (mixerVolR > 100)) {
- printk(KERN_ERR "Trying a bad mixer volume as dac gain control"
- " volume value, left (%d), right (%d)!\n", mixerVolL,
- mixerVolR);
- return -EPERM;
- }
- M_DPRINTK("mixer volume left = %d, right = %d\n", mixerVolL, mixerVolR);
- volL = get_mixer_volume_as_dac_gain_control_volume(mixerVolL);
- volR = get_mixer_volume_as_dac_gain_control_volume(mixerVolR);
-
- val = omap_tsc2101_audio_read(TSC2101_DAC_GAIN_CTRL);
- /* keep the old mute bit settings */
- val &= ~(DGC_DALVL(OUTPUT_VOLUME_MIN) |
- DGC_DARVL(OUTPUT_VOLUME_MIN));
- val |= DGC_DALVL(volL) | DGC_DARVL(volR);
- retVal = 2;
- if (retVal)
- omap_tsc2101_audio_write(TSC2101_DAC_GAIN_CTRL, val);
-
- M_DPRINTK("to registry: left = %d, right = %d, total = %d\n",
- DGC_DALVL_EXTRACT(val), DGC_DARVL_EXTRACT(val), val);
- return retVal;
-}
-
-/*
- * If unmuteLeft/unmuteRight == 0 --> mute
- * If unmuteLeft/unmuteRight == 1 --> unmute
- */
-int dac_gain_control_unmute(int unmuteLeft, int unmuteRight)
-{
- u16 val;
- int count;
-
- count = 0;
- val = omap_tsc2101_audio_read(TSC2101_DAC_GAIN_CTRL);
- /*
- * in alsa mixer 1 --> on, 0 == off. In tsc2101 registry 1 --> off,
- * 0 --> on so if values are same, it's time to change the registry
- * value.
- */
- if (unmuteLeft != IS_UNMUTED(15, val)) {
- if (unmuteLeft == 0) {
- /* mute --> turn bit on */
- val = val | DGC_DALMU;
- } else {
- /* unmute --> turn bit off */
- val = val & ~DGC_DALMU;
- }
- count++;
- } /* L */
- if (unmuteRight != IS_UNMUTED(7, val)) {
- if (unmuteRight == 0) {
- /* mute --> turn bit on */
- val = val | DGC_DARMU;
- } else {
- /* unmute --> turn bit off */
- val = val & ~DGC_DARMU;
- }
- count++;
- } /* R */
- if (count) {
- omap_tsc2101_audio_write(TSC2101_DAC_GAIN_CTRL, val);
- M_DPRINTK("changed value, is_unmuted left = %d, right = %d\n",
- IS_UNMUTED(15, val),
- IS_UNMUTED(7, val));
- }
- return count;
-}
-
-/*
- * unmute: 0 --> mute, 1 --> unmute
- * page2RegIndx: Registry index in tsc2101 page2.
- * muteBitIndx: Index number for the bit in registry that indicates whether
- * muted or unmuted.
- */
-int adc_pga_unmute_control(int unmute, int page2regIndx, int muteBitIndx)
-{
- int count;
- u16 val;
-
- count = 0;
- val = omap_tsc2101_audio_read(page2regIndx);
- /*
- * in alsa mixer 1 --> on, 0 == off. In tsc2101 registry 1 --> off,
- * 0 --> on so if the values are same, it's time to change the
- * registry value...
- */
- if (unmute != IS_UNMUTED(muteBitIndx, val)) {
- if (unmute == 0) {
- /* mute --> turn bit on */
- val = val | TSC2101_BIT(muteBitIndx);
- } else {
- /* unmute --> turn bit off */
- val = val & ~TSC2101_BIT(muteBitIndx);
- }
- M_DPRINTK("changed value, is_unmuted = %d\n",
- IS_UNMUTED(muteBitIndx, val));
- count++;
- }
- if (count)
- omap_tsc2101_audio_write(page2regIndx, val);
-
- return count;
-}
-
-/*
- * Converts the DGC registry value read from the TSC2101 registry to
- * Alsa mixer volume format (0 - 100).
- */
-int get_dac_gain_control_volume_as_mixer_volume(u16 vol)
-{
- u16 retVal;
-
- retVal = OUTPUT_VOLUME_MIN - vol;
- retVal = ((retVal - OUTPUT_VOLUME_MAX) * 100) / OUTPUT_VOLUME_RANGE;
- /* fix scaling error */
- if ((retVal > 0) && (retVal < 100))
- retVal++;
-
- return retVal;
-}
-
-/*
- * Converts the headset gain control volume (0 - 63.5 db)
- * to Alsa mixer volume (0 - 100)
- */
-int get_headset_gain_control_volume_as_mixer_volume(u16 registerVal)
-{
- u16 retVal;
-
- retVal = ((registerVal * 100) / INPUT_VOLUME_RANGE);
- return retVal;
-}
-
-/*
- * Converts the handset gain control volume (0 - 63.5 db)
- * to Alsa mixer volume (0 - 100)
- */
-int get_handset_gain_control_volume_as_mixer_volume(u16 registerVal)
-{
- return get_headset_gain_control_volume_as_mixer_volume(registerVal);
-}
-
-/*
- * Converts the Alsa mixer volume (0 - 100) to
- * headset gain control volume (0 - 63.5 db)
- */
-int get_mixer_volume_as_headset_gain_control_volume(u16 mixerVal)
-{
- u16 retVal;
-
- retVal = ((mixerVal * INPUT_VOLUME_RANGE) / 100) + INPUT_VOLUME_MIN;
- return retVal;
-}
-
-/*
- * Writes Alsa mixer volume (0 - 100) to TSC2101 headset volume registry in
- * a TSC2101 format. (0 - 63.5 db)
- * In TSC2101 OSS driver this functionality was controlled with "SET_LINE"
- * parameter.
- */
-int set_mixer_volume_as_headset_gain_control_volume(int mixerVol)
-{
- int volume;
- int retVal;
- u16 val;
-
- if (mixerVol < 0 || mixerVol > 100) {
- M_DPRINTK("Trying a bad headset mixer volume value(%d)!\n",
- mixerVol);
- return -EPERM;
- }
- M_DPRINTK("mixer volume = %d\n", mixerVol);
- /*
- * Convert 0 -> 100 volume to 0x0(min) -> 0x7D(max) volume range
- * NOTE: 0 is minimum volume and not mute
- */
- volume = get_mixer_volume_as_headset_gain_control_volume(mixerVol);
- val = omap_tsc2101_audio_read(TSC2101_HEADSET_GAIN_CTRL);
- /* preserve the old mute settings */
- val &= ~(HGC_ADPGA_HED(INPUT_VOLUME_MAX));
- val |= HGC_ADPGA_HED(volume);
- omap_tsc2101_audio_write(TSC2101_HEADSET_GAIN_CTRL, val);
- retVal = 1;
-
- M_DPRINTK("to registry = %d\n", val);
- return retVal;
-}
-
-/*
- * Writes Alsa mixer volume (0 - 100) to TSC2101 handset volume registry in
- * a TSC2101 format. (0 - 63.5 db)
- * In TSC2101 OSS driver this functionality was controlled with
- * "SET_MIC" parameter.
- */
-int set_mixer_volume_as_handset_gain_control_volume(int mixerVol)
-{
- int volume;
- int retVal;
- u16 val;
-
- if (mixerVol < 0 || mixerVol > 100) {
- M_DPRINTK("Trying a bad mic mixer volume value(%d)!\n",
- mixerVol);
- return -EPERM;
- }
- M_DPRINTK("mixer volume = %d\n", mixerVol);
- /*
- * Convert 0 -> 100 volume to 0x0(min) -> 0x7D(max) volume range
- * NOTE: 0 is minimum volume and not mute
- */
- volume = get_mixer_volume_as_headset_gain_control_volume(mixerVol);
- val = omap_tsc2101_audio_read(TSC2101_HANDSET_GAIN_CTRL);
- /* preserve the old mute settigns */
- val &= ~(HNGC_ADPGA_HND(INPUT_VOLUME_MAX));
- val |= HNGC_ADPGA_HND(volume);
- omap_tsc2101_audio_write(TSC2101_HANDSET_GAIN_CTRL, val);
- retVal = 1;
-
- M_DPRINTK("to registry = %d\n", val);
- return retVal;
-}
-
-void set_loudspeaker_to_playback_target(void)
-{
- /* power down SPK1, SPK2 and loudspeaker */
- omap_tsc2101_audio_write(TSC2101_CODEC_POWER_CTRL,
- CPC_SP1PWDN | CPC_SP2PWDN | CPC_LDAPWDF);
- /*
- * ADC, DAC, Analog Sidetone, cellphone, buzzer softstepping enabled
- * 1dB AGC hysteresis
- * MICes bias 2V
- */
- omap_tsc2101_audio_write(TSC2101_AUDIO_CTRL_4, AC4_MB_HED(0));
-
- /*
- * DAC left and right routed to SPK1/SPK2
- * SPK1/SPK2 unmuted
- * Keyclicks routed to SPK1/SPK2 */
- omap_tsc2101_audio_write(TSC2101_AUDIO_CTRL_5,
- AC5_DIFFIN |
- AC5_DAC2SPK1(3) | AC5_AST2SPK1 | AC5_KCL2SPK1 |
- AC5_DAC2SPK2(3) | AC5_AST2SPK2 | AC5_KCL2SPK2);
-
- /*
- * routing selected to SPK1 goes also to OUT8P/OUT8N. (loudspeaker)
- * analog sidetone routed to loudspeaker
- * buzzer pga routed to loudspeaker
- * keyclick routing to loudspeaker
- * cellphone input routed to loudspeaker
- * mic selection (control register 04h/page2) routed to cell phone
- * output (CP_OUT)
- * routing selected for SPK1 goes also to cellphone output (CP_OUT)
- * OUT8P/OUT8N (loudspeakers) unmuted (0 = unmuted)
- * Cellphone output is not muted (0 = unmuted)
- * Enable loudspeaker short protection control (0 = enable protection)
- * VGND short protection control (0 = enable protection)
- */
- omap_tsc2101_audio_write(TSC2101_AUDIO_CTRL_6,
- AC6_SPL2LSK | AC6_AST2LSK | AC6_BUZ2LSK | AC6_KCL2LSK |
- AC6_CPI2LSK | AC6_MIC2CPO | AC6_SPL2CPO);
- current_playback_target = PLAYBACK_TARGET_LOUDSPEAKER;
-}
-
-void set_headphone_to_playback_target(void)
-{
- /* power down SPK1, SPK2 and loudspeaker */
- omap_tsc2101_audio_write(TSC2101_CODEC_POWER_CTRL,
- CPC_SP1PWDN | CPC_SP2PWDN | CPC_LDAPWDF);
- /*
- * ADC, DAC, Analog Sidetone, cellphone, buzzer softstepping enabled
- * 1dB AGC hysteresis
- * MICes bias 2V
- */
- omap_tsc2101_audio_write(TSC2101_AUDIO_CTRL_4, AC4_MB_HED(0));
-
- /*
- * DAC left and right routed to SPK1/SPK2
- * SPK1/SPK2 unmuted
- * Keyclicks routed to SPK1/SPK2
- */
- omap_tsc2101_audio_write(TSC2101_AUDIO_CTRL_5,
- AC5_DAC2SPK1(3) | AC5_AST2SPK1 | AC5_KCL2SPK1 |
- AC5_DAC2SPK2(3) | AC5_AST2SPK2 | AC5_KCL2SPK2 |
- AC5_HDSCPTC);
-
- /* OUT8P/OUT8N muted, CPOUT muted */
- omap_tsc2101_audio_write(TSC2101_AUDIO_CTRL_6,
- AC6_MUTLSPK | AC6_MUTSPK2 | AC6_LDSCPTC |
- AC6_VGNDSCPTC);
- current_playback_target = PLAYBACK_TARGET_HEADPHONE;
-}
-
-void set_telephone_to_playback_target(void)
-{
- /*
- * 0110 1101 0101 1100
- * power down MICBIAS_HED, Analog sidetone, SPK2, DAC,
- * Driver virtual ground, loudspeaker. Values D2-d5 are flags.
- */
- omap_tsc2101_audio_write(TSC2101_CODEC_POWER_CTRL,
- CPC_MBIAS_HED | CPC_ASTPWD | CPC_SP2PWDN | CPC_DAPWDN |
- CPC_VGPWDN | CPC_LSPWDN);
-
- /*
- * 0010 1010 0100 0000
- * ADC, DAC, Analog Sidetone, cellphone, buzzer softstepping enabled
- * 1dB AGC hysteresis
- * MICes bias 2V
- */
- omap_tsc2101_audio_write(TSC2101_AUDIO_CTRL_4,
- AC4_MB_HND | AC4_MB_HED(0) | AC4_AGCHYS(1) |
- AC4_BISTPD | AC4_ASSTPD | AC4_DASTPD);
- printk(KERN_INFO "set_telephone_to_playback_target(), "
- "TSC2101_AUDIO_CTRL_4 = %d\n",
- omap_tsc2101_audio_read(TSC2101_AUDIO_CTRL_4));
-
- /*
- * 1110 0010 0000 0010
- * DAC left and right routed to SPK1/SPK2
- * SPK1/SPK2 unmuted
- * keyclicks routed to SPK1/SPK2
- */
- omap_tsc2101_audio_write(TSC2101_AUDIO_CTRL_5,
- AC5_DIFFIN | AC5_DAC2SPK1(3) |
- AC5_CPI2SPK1 | AC5_MUTSPK2);
-
- omap_tsc2101_audio_write(TSC2101_AUDIO_CTRL_6,
- AC6_MIC2CPO | AC6_MUTLSPK |
- AC6_LDSCPTC | AC6_VGNDSCPTC | AC6_CAPINTF);
- current_playback_target = PLAYBACK_TARGET_CELLPHONE;
-}
-
-/*
- * 1100 0101 1101 0000
- *
- * #define MPC_ASTMU TSC2101_BIT(15)
- * #define MPC_ASTG(ARG) (((ARG) & 0x7F) << 8)
- * #define MPC_MICSEL(ARG) (((ARG) & 0x07) << 5)
- * #define MPC_MICADC TSC2101_BIT(4)
- * #define MPC_CPADC TSC2101_BIT(3)
- * #define MPC_ASTGF (0x01)
- */
-static void set_telephone_to_record_source(void)
-{
- u16 val;
-
- /*
- * D0 = 0:
- * --> AGC is off for handset input.
- * --> ADC PGA is controlled by the ADMUT_HDN + ADPGA_HND
- * (D15, D14-D8)
- * D4 - D1 = 0000
- * --> AGC time constant for handset input,
- * attack time = 8 mc, decay time = 100 ms
- * D7 - D5 = 000
- * --> AGC Target gain for handset input = -5.5 db
- * D14 - D8 = 011 1100
- * --> ADC handset PGA settings = 60 = 30 db
- * D15 = 0
- * --> Handset input ON (unmuted)
- */
- val = 0x3c00; /* 0011 1100 0000 0000 = 60 = 30 */
- omap_tsc2101_audio_write(TSC2101_HANDSET_GAIN_CTRL, val);
-
- /*
- * D0 = 0
- * --> AGC is off for headset/Aux input
- * --> ADC headset/Aux PGA is contoller by
- * ADMUT_HED + ADPGA_HED
- * (D15, D14-D8)
- * D4 - D1 = 0000
- * --> Agc constant for headset/Aux input,
- * attack time = 8 mc, decay time = 100 ms
- * D7 - D5 = 000
- * --> AGC target gain for headset input = -5.5 db
- * D14 - D8 = 000 0000
- * --> Adc headset/AUX pga settings = 0 db
- * D15 = 1
- * --> Headset/AUX input muted
- *
- * Mute headset aux input
- */
- val = 0x8000; /* 1000 0000 0000 0000 */
- omap_tsc2101_audio_write(TSC2101_HEADSET_GAIN_CTRL, val);
- set_record_source(REC_SRC_MICIN_HND_AND_AUX1);
-
- /*
- * hacks start
- * D0 = flag, Headset/Aux or handset PGA flag
- * --> & with 1 (= 1 -->gain applied == pga
- * register settings)
- * D1 = 0, DAC channel PGA soft stepping control
- * --> 0.5 db change every WCLK
- * D2 = flag, DAC right channel PGA flag
- * --> & with 1
- * D3 = flag, DAC left channel PGA flag
- * -- > & with 1
- * D7 - D4 = 0001, keyclick length
- * --> 4 periods key clicks
- * D10 - D8 = 100, keyclick frequency
- * --> 1 kHz,
- * D11 = 0, Headset/Aux or handset soft stepping control
- * --> 0,5 db change every WCLK or ADWS
- * D14 -D12 = 100, Keyclick applitude control
- * --> Medium amplitude
- * D15 = 0, keyclick disabled
- */
- val = omap_tsc2101_audio_read(TSC2101_AUDIO_CTRL_2);
- val = val & 0x441d;
- val = val | 0x4410; /* D14, D10, D4 bits == 1 */
- omap_tsc2101_audio_write(TSC2101_AUDIO_CTRL_2, val);
-
- /*
- * D0 = 0 (reserved, write always 0)
- * D1 = flag,
- * --> & with 1
- * D2 - D5 = 0000 (reserved, write always 0000)
- * D6 = 1
- * --> MICBIAS_HND = 2.0 v
- * D8 - D7 = 00
- * --> MICBIAS_HED = 3.3 v
- * D10 - D9 = 01,
- * --> Mic AGC hysteric selection = 2 db
- * D11 = 1,
- * --> Disable buzzer PGA soft stepping
- * D12 = 0,
- * --> Enable CELL phone PGA soft stepping control
- * D13 = 1
- * --> Disable analog sidetone soft
- * stepping control
- * D14 = 0
- * --> Enable DAC PGA soft stepping control
- * D15 = 0,
- * --> Enable headset/Aux or Handset soft
- * stepping control
- */
- val = omap_tsc2101_audio_read(TSC2101_AUDIO_CTRL_4);
- val = val & 0x2a42; /* 0010 1010 0100 0010 */
- val = val | 0x2a40; /* bits D13, D11, D9, D6 == 1 */
- omap_tsc2101_audio_write(TSC2101_AUDIO_CTRL_4, val);
- printk(KERN_INFO "set_telephone_to_record_source(), "
- "TSC2101_AUDIO_CTRL_4 = %d\n",
- omap_tsc2101_audio_read(TSC2101_AUDIO_CTRL_4));
- /*
- * D0 = 0
- * --> reserved, write always = 0
- * D1 = flag, read only
- * --> & with 1
- * D5 - D2 = 1111, Buzzer input PGA settings
- * --> 0 db
- * D6 = 1,
- * --> power down buzzer input pga
- * D7 = flag, read only
- * --> & with 1
- * D14 - D8 = 101 1101
- * --> 12 DB
- * D15 = 0
- * --> power up cell phone input PGA
- */
- val = omap_tsc2101_audio_read(TSC2101_BUZZER_GAIN_CTRL);
- val = val & 0x5dfe;
- /* bits, D14, D12, D11, D10, D8, D6, D5,D4,D3,D2 */
- val = val | 0x5dfe;
- omap_tsc2101_audio_write(TSC2101_BUZZER_GAIN_CTRL, val);
-
- /*
- * D6 - D0 = 000 1001
- * --> -4.5 db for DAC right channel volume control
- * D7 = 1
- * --> DAC right channel muted
- * D14 - D8 = 000 1001
- * --> -4.5 db for DAC left channel volume control
- * D15 = 1
- * --> DAC left channel muted
- */
- /* val = omap_tsc2101_audio_read(TSC2101_DAC_GAIN_CTRL); */
- val = 0x8989;
- omap_tsc2101_audio_write(TSC2101_DAC_GAIN_CTRL, val);
-
- /*
- * 0000 0000 0100 0000
- *
- * D1 - D0 = 0
- * --> GPIO 1 pin output is three stated
- * D2 = 0
- * --> Disaple GPIO2 for CLKOUT mode
- * D3 = 0
- * --> Disable GPUI1 for interrupt detection
- * D4 = 0
- * --> Disable GPIO2 for headset detection interrupt
- * D5 = reserved, always 0
- * D7 - D6 = 01
- * --> 8 ms clitch detection
- * D8 = reserved, write only 0
- * D10 -D9 = 00
- * --> 16 ms de-bouncing
- * for glitch detection during headset detection
- * D11 = flag for button press
- * D12 = flag for headset detection
- * D14-D13 = 00
- * --> type of headset detected = 00 == no stereo
- * headset deected
- * D15 = 0
- * --> Disable headset detection
- */
- val = 0x40;
- omap_tsc2101_audio_write(TSC2101_AUDIO_CTRL_7, val);
-}
-
-/*
- * Checks whether the headset is detected.
- * If headset is detected, the type is returned. Type can be
- * 0x01 = stereo headset detected
- * 0x02 = cellurar headset detected
- * 0x03 = stereo + cellurar headset detected
- * If headset is not detected 0 is returned.
- */
-u16 get_headset_detected(void)
-{
- u16 curDetected;
- u16 curType;
- u16 curVal;
-
- curType = 0; /* not detected */
- curVal = omap_tsc2101_audio_read(TSC2101_AUDIO_CTRL_7);
- curDetected = curVal & AC7_HDDETFL;
- if (curDetected) {
- printk(KERN_INFO "headset detected, checking type from %d \n",
- curVal);
- curType = ((curVal & 0x6000) >> 13);
- printk(KERN_INFO "headset type detected = %d \n", curType);
- } else {
- printk(KERN_INFO "headset not detected\n");
- }
- return curType;
-}
-
-void init_playback_targets(void)
-{
- u16 val;
-
- set_loudspeaker_to_playback_target();
- /*
- * Left line input volume control
- * = SET_LINE in the OSS driver
- */
- set_mixer_volume_as_headset_gain_control_volume(DEFAULT_INPUT_VOLUME);
-
- /*
- * Set headset to be controllable by handset mixer
- * AGC enable for handset input
- * Handset input not muted
- */
- val = omap_tsc2101_audio_read(TSC2101_HANDSET_GAIN_CTRL);
- val = val | HNGC_AGCEN_HND;
- val = val & ~HNGC_ADMUT_HND;
- omap_tsc2101_audio_write(TSC2101_HANDSET_GAIN_CTRL, val);
-
- /*
- * mic input volume control
- * SET_MIC in the OSS driver
- */
- set_mixer_volume_as_handset_gain_control_volume(DEFAULT_INPUT_VOLUME);
-
- /*
- * Left/Right headphone channel volume control
- * Zero-cross detect on
- */
- set_mixer_volume_as_dac_gain_control_volume(DEFAULT_OUTPUT_VOLUME,
- DEFAULT_OUTPUT_VOLUME);
- /* unmute */
- dac_gain_control_unmute(1, 1);
-}
-
-/*
- * Initializes tsc2101 recourd source (to line) and playback target
- * (to loudspeaker)
- */
-void snd_omap_init_mixer(void)
-{
- FN_IN;
-
- /* Headset/Hook switch detect enabled */
- omap_tsc2101_audio_write(TSC2101_AUDIO_CTRL_7, AC7_DETECT);
-
- /* Select headset to record source (MIC_INHED)*/
- set_record_source(REC_SRC_SINGLE_ENDED_MICIN_HED);
- /* Init loudspeaker as a default playback target*/
- init_playback_targets();
-
- FN_OUT(0);
-}
-
-static int __pcm_playback_target_info(struct snd_kcontrol *kcontrol,
- struct snd_ctl_elem_info *uinfo)
-{
- static char *texts[PLAYBACK_TARGET_COUNT] = {
- "Loudspeaker", "Headphone", "Cellphone"
- };
-
- uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
- uinfo->count = 1;
- uinfo->value.enumerated.items = PLAYBACK_TARGET_COUNT;
- if (uinfo->value.enumerated.item > PLAYBACK_TARGET_COUNT - 1)
- uinfo->value.enumerated.item = PLAYBACK_TARGET_COUNT - 1;
-
- strcpy(uinfo->value.enumerated.name,
- texts[uinfo->value.enumerated.item]);
- return 0;
-}
-
-static int __pcm_playback_target_get(struct snd_kcontrol *kcontrol,
- struct snd_ctl_elem_value *ucontrol)
-{
- ucontrol->value.integer.value[0] = current_playback_target;
- return 0;
-}
-
-static int __pcm_playback_target_put(struct snd_kcontrol *kcontrol,
- struct snd_ctl_elem_value *ucontrol)
-{
- int retVal;
- int curVal;
-
- retVal = 0;
- curVal = ucontrol->value.integer.value[0];
- if ((curVal >= 0) &&
- (curVal < PLAYBACK_TARGET_COUNT) &&
- (curVal != current_playback_target)) {
- if (curVal == PLAYBACK_TARGET_LOUDSPEAKER) {
- set_record_source(REC_SRC_SINGLE_ENDED_MICIN_HED);
- set_loudspeaker_to_playback_target();
- } else if (curVal == PLAYBACK_TARGET_HEADPHONE) {
- set_record_source(REC_SRC_SINGLE_ENDED_MICIN_HND);
- set_headphone_to_playback_target();
- } else if (curVal == PLAYBACK_TARGET_CELLPHONE) {
- set_telephone_to_record_source();
- set_telephone_to_playback_target();
- }
- retVal = 1;
- }
- return retVal;
-}
-
-static int __pcm_playback_volume_info(struct snd_kcontrol *kcontrol,
- struct snd_ctl_elem_info *uinfo)
-{
- uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
- uinfo->count = 2;
- uinfo->value.integer.min = 0;
- uinfo->value.integer.max = 100;
- return 0;
-}
-
-/*
- * Alsa mixer interface function for getting the volume read from the DGC in a
- * 0 -100 alsa mixer format.
- */
-static int __pcm_playback_volume_get(struct snd_kcontrol *kcontrol,
- struct snd_ctl_elem_value *ucontrol)
-{
- u16 volL;
- u16 volR;
- u16 val;
-
- val = omap_tsc2101_audio_read(TSC2101_DAC_GAIN_CTRL);
- M_DPRINTK("registry value = %d!\n", val);
- volL = DGC_DALVL_EXTRACT(val);
- volR = DGC_DARVL_EXTRACT(val);
- /* make sure that other bits are not on */
- volL = volL & ~DGC_DALMU;
- volR = volR & ~DGC_DARMU;
-
- volL = get_dac_gain_control_volume_as_mixer_volume(volL);
- volR = get_dac_gain_control_volume_as_mixer_volume(volR);
-
- ucontrol->value.integer.value[0] = volL; /* L */
- ucontrol->value.integer.value[1] = volR; /* R */
-
- M_DPRINTK("mixer volume left = %ld, right = %ld\n",
- ucontrol->value.integer.value[0],
- ucontrol->value.integer.value[1]);
- return 0;
-}
-
-static int __pcm_playback_volume_put(struct snd_kcontrol *kcontrol,
- struct snd_ctl_elem_value *ucontrol)
-{
- return set_mixer_volume_as_dac_gain_control_volume(
- ucontrol->value.integer.value[0],
- ucontrol->value.integer.value[1]);
-}
-
-static int __pcm_playback_switch_info(struct snd_kcontrol *kcontrol,
- struct snd_ctl_elem_info *uinfo)
-{
- uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN;
- uinfo->count = 2;
- uinfo->value.integer.min = 0;
- uinfo->value.integer.max = 1;
- return 0;
-}
-
-/*
- * When DGC_DALMU (bit 15) is 1, the left channel is muted.
- * When DGC_DALMU is 0, left channel is not muted.
- * Same logic apply also for the right channel.
- */
-static int __pcm_playback_switch_get(struct snd_kcontrol *kcontrol,
- struct snd_ctl_elem_value *ucontrol)
-{
- u16 val = omap_tsc2101_audio_read(TSC2101_DAC_GAIN_CTRL);
-
- ucontrol->value.integer.value[0] = IS_UNMUTED(15, val); /* left */
- ucontrol->value.integer.value[1] = IS_UNMUTED(7, val); /* right */
- return 0;
-}
-
-static int __pcm_playback_switch_put(struct snd_kcontrol *kcontrol,
- struct snd_ctl_elem_value *ucontrol)
-{
- return dac_gain_control_unmute(ucontrol->value.integer.value[0],
- ucontrol->value.integer.value[1]);
-}
-
-static int __headset_playback_volume_info(struct snd_kcontrol *kcontrol,
- struct snd_ctl_elem_info *uinfo)
-{
- uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
- uinfo->count = 1;
- uinfo->value.integer.min = 0;
- uinfo->value.integer.max = 100;
- return 0;
-}
-
-static int __headset_playback_volume_get(struct snd_kcontrol *kcontrol,
- struct snd_ctl_elem_value *ucontrol)
-{
- u16 val;
- u16 vol;
-
- val = omap_tsc2101_audio_read(TSC2101_HEADSET_GAIN_CTRL);
- M_DPRINTK("registry value = %d\n", val);
- vol = HGC_ADPGA_HED_EXTRACT(val);
- vol = vol & ~HGC_ADMUT_HED;
-
- vol = get_headset_gain_control_volume_as_mixer_volume(vol);
- ucontrol->value.integer.value[0] = vol;
-
- M_DPRINTK("mixer volume returned = %ld\n",
- ucontrol->value.integer.value[0]);
- return 0;
-}
-
-static int __headset_playback_volume_put(struct snd_kcontrol *kcontrol,
- struct snd_ctl_elem_value *ucontrol)
-{
- return set_mixer_volume_as_headset_gain_control_volume(
- ucontrol->value.integer.value[0]);
-}
-
-static int __headset_playback_switch_info(struct snd_kcontrol *kcontrol,
- struct snd_ctl_elem_info *uinfo)
-{
- uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN;
- uinfo->count = 1;
- uinfo->value.integer.min = 0;
- uinfo->value.integer.max = 1;
- return 0;
-}
-
-/*
- * When HGC_ADMUT_HED (bit 15) is 1, the headset is muted.
- * When HGC_ADMUT_HED is 0, headset is not muted.
- */
-static int __headset_playback_switch_get(struct snd_kcontrol *kcontrol,
- struct snd_ctl_elem_value *ucontrol)
-{
- u16 val = omap_tsc2101_audio_read(TSC2101_HEADSET_GAIN_CTRL);
- ucontrol->value.integer.value[0] = IS_UNMUTED(15, val);
- return 0;
-}
-
-static int __headset_playback_switch_put(struct snd_kcontrol *kcontrol,
- struct snd_ctl_elem_value *ucontrol)
-{
- /* mute/unmute headset */
- return adc_pga_unmute_control(ucontrol->value.integer.value[0],
- TSC2101_HEADSET_GAIN_CTRL,
- 15);
-}
-
-static int __handset_playback_volume_info(struct snd_kcontrol *kcontrol,
- struct snd_ctl_elem_info *uinfo)
-{
- uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
- uinfo->count = 1;
- uinfo->value.integer.min = 0;
- uinfo->value.integer.max = 100;
- return 0;
-}
-
-static int __handset_playback_volume_get(struct snd_kcontrol *kcontrol,
- struct snd_ctl_elem_value *ucontrol)
-{
- u16 val;
- u16 vol;
-
- val = omap_tsc2101_audio_read(TSC2101_HANDSET_GAIN_CTRL);
- M_DPRINTK("registry value = %d\n", val);
- vol = HNGC_ADPGA_HND_EXTRACT(val);
- vol = vol & ~HNGC_ADMUT_HND;
- vol = get_handset_gain_control_volume_as_mixer_volume(vol);
- ucontrol->value.integer.value[0] = vol;
-
- M_DPRINTK("mixer volume returned = %ld\n",
- ucontrol->value.integer.value[0]);
- return 0;
-}
-
-static int __handset_playback_volume_put(struct snd_kcontrol *kcontrol,
- struct snd_ctl_elem_value *ucontrol)
-{
- return set_mixer_volume_as_handset_gain_control_volume(
- ucontrol->value.integer.value[0]);
-}
-
-static int __handset_playback_switch_info(struct snd_kcontrol *kcontrol,
- struct snd_ctl_elem_info *uinfo)
-{
- uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN;
- uinfo->count = 1;
- uinfo->value.integer.min = 0;
- uinfo->value.integer.max = 1;
- return 0;
-}
-
-/*
- * When HNGC_ADMUT_HND (bit 15) is 1, the handset is muted.
- * When HNGC_ADMUT_HND is 0, handset is not muted.
- */
-static int __handset_playback_switch_get(struct snd_kcontrol *kcontrol,
- struct snd_ctl_elem_value *ucontrol)
-{
- u16 val = omap_tsc2101_audio_read(TSC2101_HANDSET_GAIN_CTRL);
- ucontrol->value.integer.value[0] = IS_UNMUTED(15, val);
- return 0;
-}
-
-static int __handset_playback_switch_put(struct snd_kcontrol *kcontrol,
- struct snd_ctl_elem_value *ucontrol)
-{
- /* handset mute/unmute */
- return adc_pga_unmute_control(ucontrol->value.integer.value[0],
- TSC2101_HANDSET_GAIN_CTRL,
- 15);
-}
-
-static int __cellphone_input_switch_info(struct snd_kcontrol *kcontrol,
- struct snd_ctl_elem_info *uinfo)
-{
- uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN;
- uinfo->count = 1;
- uinfo->value.integer.min = 0;
- uinfo->value.integer.max = 1;
- return 0;
-}
-
-/*
- * When BGC_MUT_CP (bit 15) = 1, power down cellphone input pga.
- * When BGC_MUT_CP = 0, power up cellphone input pga.
- */
-static int __cellphone_input_switch_get(struct snd_kcontrol *kcontrol,
- struct snd_ctl_elem_value *ucontrol)
-{
- u16 val = omap_tsc2101_audio_read(TSC2101_BUZZER_GAIN_CTRL);
- ucontrol->value.integer.value[0] = IS_UNMUTED(15, val);
- return 0;
-}
-
-static int __cellphone_input_switch_put(struct snd_kcontrol *kcontrol,
- struct snd_ctl_elem_value *ucontrol)
-{
- return adc_pga_unmute_control(ucontrol->value.integer.value[0],
- TSC2101_BUZZER_GAIN_CTRL,
- 15);
-}
-
-static int __buzzer_input_switch_info(struct snd_kcontrol *kcontrol,
- struct snd_ctl_elem_info *uinfo)
-{
- uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN;
- uinfo->count = 1;
- uinfo->value.integer.min = 0;
- uinfo->value.integer.max = 1;
- return 0;
-}
-
-/*
- * When BGC_MUT_BU (bit 6) = 1, power down cellphone input pga.
- * When BGC_MUT_BU = 0, power up cellphone input pga.
- */
-static int __buzzer_input_switch_get(struct snd_kcontrol *kcontrol,
- struct snd_ctl_elem_value *ucontrol)
-{
- u16 val = omap_tsc2101_audio_read(TSC2101_BUZZER_GAIN_CTRL);
- ucontrol->value.integer.value[0] = IS_UNMUTED(6, val);
- return 0;
-}
-
-static int __buzzer_input_switch_put(struct snd_kcontrol *kcontrol,
- struct snd_ctl_elem_value *ucontrol)
-{
- return adc_pga_unmute_control(ucontrol->value.integer.value[0],
- TSC2101_BUZZER_GAIN_CTRL,
- 6);
-}
-
-static struct snd_kcontrol_new tsc2101_control[] __devinitdata = {
- {
- .name = "Target Playback Route",
- .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
- .index = 0,
- .access = SNDRV_CTL_ELEM_ACCESS_READWRITE,
- .info = __pcm_playback_target_info,
- .get = __pcm_playback_target_get,
- .put = __pcm_playback_target_put,
- }, {
- .name = "Master Playback Volume",
- .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
- .index = 0,
- .access = SNDRV_CTL_ELEM_ACCESS_READWRITE,
- .info = __pcm_playback_volume_info,
- .get = __pcm_playback_volume_get,
- .put = __pcm_playback_volume_put,
- }, {
- .name = "Master Playback Switch",
- .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
- .index = 0,
- .access = SNDRV_CTL_ELEM_ACCESS_READWRITE,
- .info = __pcm_playback_switch_info,
- .get = __pcm_playback_switch_get,
- .put = __pcm_playback_switch_put,
- }, {
- .name = "Headset Playback Volume",
- .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
- .index = 0,
- .access = SNDRV_CTL_ELEM_ACCESS_READWRITE,
- .info = __headset_playback_volume_info,
- .get = __headset_playback_volume_get,
- .put = __headset_playback_volume_put,
- }, {
- .name = "Headset Playback Switch",
- .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
- .index = 0,
- .access = SNDRV_CTL_ELEM_ACCESS_READWRITE,
- .info = __headset_playback_switch_info,
- .get = __headset_playback_switch_get,
- .put = __headset_playback_switch_put,
- }, {
- .name = "Handset Playback Volume",
- .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
- .index = 0,
- .access = SNDRV_CTL_ELEM_ACCESS_READWRITE,
- .info = __handset_playback_volume_info,
- .get = __handset_playback_volume_get,
- .put = __handset_playback_volume_put,
- }, {
- .name = "Handset Playback Switch",
- .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
- .index = 0,
- .access = SNDRV_CTL_ELEM_ACCESS_READWRITE,
- .info = __handset_playback_switch_info,
- .get = __handset_playback_switch_get,
- .put = __handset_playback_switch_put,
- }, {
- .name = "Cellphone Input Switch",
- .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
- .index = 0,
- .access = SNDRV_CTL_ELEM_ACCESS_READWRITE,
- .info = __cellphone_input_switch_info,
- .get = __cellphone_input_switch_get,
- .put = __cellphone_input_switch_put,
- }, {
- .name = "Buzzer Input Switch",
- .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
- .index = 0,
- .access = SNDRV_CTL_ELEM_ACCESS_READWRITE,
- .info = __buzzer_input_switch_info,
- .get = __buzzer_input_switch_get,
- .put = __buzzer_input_switch_put,
- }
-};
-
-#ifdef CONFIG_PM
-
-void snd_omap_suspend_mixer(void)
-{
-}
-
-void snd_omap_resume_mixer(void)
-{
- snd_omap_init_mixer();
-}
-#endif
-
-int snd_omap_mixer(struct snd_card_omap_codec *tsc2101)
-{
- int i = 0;
- int err = 0;
-
- if (!tsc2101)
- return -EINVAL;
-
- for (i = 0; i < ARRAY_SIZE(tsc2101_control); i++) {
- err = snd_ctl_add(tsc2101->card,
- snd_ctl_new1(&tsc2101_control[i],
- tsc2101->card));
- if (err < 0)
- return err;
- }
- return 0;
-}
+++ /dev/null
-/*
- * sound/arm/omap/omap-alsa-tsc2101-mixer.h
- *
- * Alsa Driver for TSC2101 codec for OMAP platform boards.
- *
- * Copyright (C) 2005 Mika Laitio <lamikr@cc.jyu.fi> and
- * Everett Coleman II <gcc80x86@fuzzyneural.net>
- *
- * Based on the ideas in omap-aic23.c and sa11xx-uda1341.c
- * Copyright (C) 2005 Instituto Nokia de Tecnologia - INdT - Manaus Brazil
- * Copyright (C) 2002 Tomas Kasparek <tomas.kasparek@seznam.cz>
- *
- * 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.
- *
- * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
- * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN
- * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
- * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
- * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
- * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
- * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
- * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- * 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.
- *
- * History:
- *
- * 2006-03-01 Mika Laitio - Mixer for the tsc2101 driver used in omap boards.
- * Can switch between headset and loudspeaker playback,
- * mute and unmute dgc, set dgc volume. Record source switch,
- * keyclick, buzzer and headset volume and handset volume control
- * are still missing.
- */
-
-#ifndef OMAPALSATSC2101MIXER_H_
-#define OMAPALSATSC2101MIXER_H_
-
-#include <asm/hardware/tsc2101.h>
-#include "omap-alsa-dma.h"
-
-/* tsc2101 DAC gain control volume specific */
-#define OUTPUT_VOLUME_MIN 0x7F /* 1111111 = -63.5 DB */
-#define OUTPUT_VOLUME_MAX 0x32 /* 110010 */
-#define OUTPUT_VOLUME_RANGE (OUTPUT_VOLUME_MIN - OUTPUT_VOLUME_MAX)
-
-/* use input vol of 75 for 0dB gain */
-#define INPUT_VOLUME_MIN 0x0
-#define INPUT_VOLUME_MAX 0x7D
-#define INPUT_VOLUME_RANGE (INPUT_VOLUME_MAX - INPUT_VOLUME_MIN)
-
-#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
-/* oss code referred to MIXER_LINE */
-#define REC_SRC_SINGLE_ENDED_MICIN_HED 0x00
-/* oss code referred to MIXER_MIC */
-#define REC_SRC_SINGLE_ENDED_MICIN_HND 0x01
-#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
-
-/* default output volume to dac dgc */
-#define DEFAULT_OUTPUT_VOLUME 90
-/* default record volume */
-#define DEFAULT_INPUT_VOLUME 20
-
-#define TSC2101_AUDIO_CODEC_REGISTERS_PAGE2 (2)
-
-extern struct mcbsp_dev_info mcbsp_dev;
-
-#endif /*OMAPALSATSC2101MIXER_H_*/
+++ /dev/null
-/*
- * sound/arm/omap/omap-alsa-tsc2101.c
- *
- * Alsa codec Driver for TSC2101 chip for OMAP platform boards.
- * Code obtained from oss omap drivers
- *
- * Copyright (C) 2004 Texas Instruments, Inc.
- * Written by Nishanth Menon and Sriram Kannan
- *
- * Copyright (C) 2006 Instituto Nokia de Tecnologia - INdT - Manaus Brazil
- * Alsa modularization by Daniel Petrini (d.pensator@gmail.com)
- *
- * Copyright (C) 2006 Mika Laitio <lamikr@cc.jyu.fi>
- *
- * 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 <linux/spi/tsc2101.h>
-#include <linux/io.h>
-#include <linux/slab.h>
-#ifdef CONFIG_PM
-#include <linux/pm.h>
-#endif
-
-#include <asm/mach-types.h>
-#include <mach/dma.h>
-#include <mach/clock.h>
-#include <mach/mcbsp.h>
-#include <asm/hardware/tsc2101.h>
-#include <mach/omap-alsa.h>
-
-#include "omap-alsa-tsc2101.h"
-
-struct mcbsp_dev_info mcbsp_dev;
-
-static struct clk *tsc2101_mclk;
-
-/* #define DUMP_TSC2101_AUDIO_REGISTERS */
-#undef DUMP_TSC2101_AUDIO_REGISTERS
-
-/*
- * 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[] = {
- 7350, 8000, 8018, 8727,
- 8820, 9600, 11025, 12000,
- 14700, 16000, 22050, 24000,
- 29400, 32000, 44100, 48000,
-};
-
-static struct snd_pcm_hw_constraint_list tsc2101_hw_constraints_rates = {
- .count = ARRAY_SIZE(rates),
- .list = rates,
- .mask = 0,
-};
-
-static const struct tsc2101_samplerate_reg_info
- rate_reg_info[NUMBER_SAMPLE_RATES_SUPPORTED] = {
- /* Div 6 */
- {7350, 7, 1},
- {8000, 7, 0},
- /* Div 5.5 */
- {8018, 6, 1},
- {8727, 6, 0},
- /* Div 5 */
- {8820, 5, 1},
- {9600, 5, 0},
- /* Div 4 */
- {11025, 4, 1},
- {12000, 4, 0},
- /* Div 3 */
- {14700, 3, 1},
- {16000, 3, 0},
- /* Div 2 */
- {22050, 2, 1},
- {24000, 2, 0},
- /* Div 1.5 */
- {29400, 1, 1},
- {32000, 1, 0},
- /* Div 1 */
- {44100, 0, 1},
- {48000, 0, 0},
-};
-
-static struct snd_pcm_hardware tsc2101_snd_omap_alsa_playback = {
- .info = SNDRV_PCM_INFO_INTERLEAVED | SNDRV_PCM_INFO_BLOCK_TRANSFER |
- SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_MMAP_VALID,
-#ifdef CONFIG_MACH_OMAP_H6300
- .formats = SNDRV_PCM_FMTBIT_S8,
-#else
- .formats = SNDRV_PCM_FMTBIT_S16_LE,
-#endif
- .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 = 7350,
- .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 struct snd_pcm_hardware tsc2101_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 = 7350,
- .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,
-};
-
-/*
- * Simplified write for tsc2101 audio registers.
- */
-inline void tsc2101_audio_write(u8 address, u16 data)
-{
- tsc2101_write_sync(mcbsp_dev.tsc2101_dev, PAGE2_AUDIO_CODEC_REGISTERS,
- address, data);
-}
-
-/*
- * Simplified read for tsc2101 audio registers.
- */
-inline u16 tsc2101_audio_read(u8 address)
-{
- return (tsc2101_read_sync(mcbsp_dev.tsc2101_dev,
- PAGE2_AUDIO_CODEC_REGISTERS, address));
-}
-
-#ifdef DUMP_TSC2101_AUDIO_REGISTERS
-void dump_tsc2101_audio_reg(void)
-{
- dev_dbg(&mcbsp_dev.mcbsp_dev->dev,
- "TSC2101_AUDIO_CTRL_1 = 0x%04x\n",
- tsc2101_audio_read(TSC2101_AUDIO_CTRL_1));
- dev_dbg(&mcbsp_dev.mcbsp_dev->dev,
- "TSC2101_HEADSET_GAIN_CTRL = 0x%04x\n",
- tsc2101_audio_read(TSC2101_HEADSET_GAIN_CTRL));
- dev_dbg(&mcbsp_dev.mcbsp_dev->dev,
- "TSC2101_DAC_GAIN_CTRL = 0x%04x\n",
- tsc2101_audio_read(TSC2101_DAC_GAIN_CTRL));
- dev_dbg(&mcbsp_dev.mcbsp_dev->dev,
- "TSC2101_MIXER_PGA_CTRL = 0x%04x\n",
- tsc2101_audio_read(TSC2101_MIXER_PGA_CTRL));
- dev_dbg(&mcbsp_dev.mcbsp_dev->dev,
- "TSC2101_AUDIO_CTRL_2 = 0x%04x\n",
- tsc2101_audio_read(TSC2101_AUDIO_CTRL_2));
- dev_dbg(&mcbsp_dev.mcbsp_dev->dev,
- "TSC2101_CODEC_POWER_CTRL = 0x%04x\n",
- tsc2101_audio_read(TSC2101_CODEC_POWER_CTRL));
- dev_dbg(&mcbsp_dev.mcbsp_dev->dev,
- "TSC2101_AUDIO_CTRL_3 = 0x%04x\n",
- tsc2101_audio_read(TSC2101_AUDIO_CTRL_3));
- dev_dbg(&mcbsp_dev.mcbsp_dev->dev,
- "TSC2101_LCH_BASS_BOOST_N0 = 0x%04x\n",
- tsc2101_audio_read(TSC2101_LCH_BASS_BOOST_N0));
- dev_dbg(&mcbsp_dev.mcbsp_dev->dev,
- "TSC2101_LCH_BASS_BOOST_N1 = 0x%04x\n",
- tsc2101_audio_read(TSC2101_LCH_BASS_BOOST_N1));
- dev_dbg(&mcbsp_dev.mcbsp_dev->dev,
- "TSC2101_LCH_BASS_BOOST_N2 = 0x%04x\n",
- tsc2101_audio_read(TSC2101_LCH_BASS_BOOST_N2));
- dev_dbg(&mcbsp_dev.mcbsp_dev->dev,
- "TSC2101_LCH_BASS_BOOST_N3 = 0x%04x\n",
- tsc2101_audio_read(TSC2101_LCH_BASS_BOOST_N3));
- dev_dbg(&mcbsp_dev.mcbsp_dev->dev,
- "TSC2101_LCH_BASS_BOOST_N4 = 0x%04x\n",
- tsc2101_audio_read(TSC2101_LCH_BASS_BOOST_N4));
- dev_dbg(&mcbsp_dev.mcbsp_dev->dev,
- "TSC2101_LCH_BASS_BOOST_N5 = 0x%04x\n",
- tsc2101_audio_read(TSC2101_LCH_BASS_BOOST_N5));
- dev_dbg(&mcbsp_dev.mcbsp_dev->dev,
- "TSC2101_LCH_BASS_BOOST_D1 = 0x%04x\n",
- tsc2101_audio_read(TSC2101_LCH_BASS_BOOST_D1));
- dev_dbg(&mcbsp_dev.mcbsp_dev->dev,
- "TSC2101_LCH_BASS_BOOST_D2 = 0x%04x\n",
- tsc2101_audio_read(TSC2101_LCH_BASS_BOOST_D2));
- dev_dbg(&mcbsp_dev.mcbsp_dev->dev,
- "TSC2101_LCH_BASS_BOOST_D4 = 0x%04x\n",
- tsc2101_audio_read(TSC2101_LCH_BASS_BOOST_D4));
- dev_dbg(&mcbsp_dev.mcbsp_dev->dev,
- "TSC2101_LCH_BASS_BOOST_D5 = 0x%04x\n",
- tsc2101_audio_read(TSC2101_LCH_BASS_BOOST_D5));
-
- dev_dbg(&mcbsp_dev.mcbsp_dev->dev,
- "TSC2101_RCH_BASS_BOOST_N0 = 0x%04x\n",
- tsc2101_audio_read(TSC2101_RCH_BASS_BOOST_N0));
- dev_dbg(&mcbsp_dev.mcbsp_dev->dev,
- "TSC2101_RCH_BASS_BOOST_N1 = 0x%04x\n",
- tsc2101_audio_read(TSC2101_RCH_BASS_BOOST_N1));
- dev_dbg(&mcbsp_dev.mcbsp_dev->dev,
- "TSC2101_RCH_BASS_BOOST_N2 = 0x%04x\n",
- tsc2101_audio_read(TSC2101_RCH_BASS_BOOST_N2));
- dev_dbg(&mcbsp_dev.mcbsp_dev->dev,
- "TSC2101_RCH_BASS_BOOST_N3 = 0x%04x\n",
- tsc2101_audio_read(TSC2101_RCH_BASS_BOOST_N3));
- dev_dbg(&mcbsp_dev.mcbsp_dev->dev,
- "TSC2101_RCH_BASS_BOOST_N4 = 0x%04x\n",
- tsc2101_audio_read(TSC2101_RCH_BASS_BOOST_N4));
- dev_dbg(&mcbsp_dev.mcbsp_dev->dev,
- "TSC2101_RCH_BASS_BOOST_N5 = 0x%04x\n",
- tsc2101_audio_read(TSC2101_RCH_BASS_BOOST_N5));
- dev_dbg(&mcbsp_dev.mcbsp_dev->dev,
- "TSC2101_RCH_BASS_BOOST_D1 = 0x%04x\n",
- tsc2101_audio_read(TSC2101_RCH_BASS_BOOST_D1));
- dev_dbg(&mcbsp_dev.mcbsp_dev->dev,
- "TSC2101_RCH_BASS_BOOST_D2 = 0x%04x\n",
- tsc2101_audio_read(TSC2101_RCH_BASS_BOOST_D2));
- dev_dbg(&mcbsp_dev.mcbsp_dev->dev,
- "TSC2101_RCH_BASS_BOOST_D4 = 0x%04x\n",
- tsc2101_audio_read(TSC2101_RCH_BASS_BOOST_D4));
- dev_dbg(&mcbsp_dev.mcbsp_dev->dev,
- "TSC2101_RCH_BASS_BOOST_D5 = 0x%04x\n",
- tsc2101_audio_read(TSC2101_RCH_BASS_BOOST_D5));
-
- dev_dbg(&mcbsp_dev.mcbsp_dev->dev,
- "TSC2101_PLL_PROG_1 = 0x%04x\n",
- tsc2101_audio_read(TSC2101_PLL_PROG_1));
- dev_dbg(&mcbsp_dev.mcbsp_dev->dev,
- "TSC2101_PLL_PROG_1 = 0x%04x\n",
- tsc2101_audio_read(TSC2101_PLL_PROG_2));
- dev_dbg(&mcbsp_dev.mcbsp_dev->dev,
- "TSC2101_AUDIO_CTRL_4 = 0x%04x\n",
- tsc2101_audio_read(TSC2101_AUDIO_CTRL_4));
- dev_dbg(&mcbsp_dev.mcbsp_dev->dev,
- "TSC2101_HANDSET_GAIN_CTRL = 0x%04x\n",
- tsc2101_audio_read(TSC2101_HANDSET_GAIN_CTRL));
- dev_dbg(&mcbsp_dev.mcbsp_dev->dev,
- "TSC2101_BUZZER_GAIN_CTRL = 0x%04x\n",
- tsc2101_audio_read(TSC2101_BUZZER_GAIN_CTRL));
- dev_dbg(&mcbsp_dev.mcbsp_dev->dev,
- "TSC2101_AUDIO_CTRL_5 = 0x%04x\n",
- tsc2101_audio_read(TSC2101_AUDIO_CTRL_5));
- dev_dbg(&mcbsp_dev.mcbsp_dev->dev,
- "TSC2101_AUDIO_CTRL_6 = 0x%04x\n",
- tsc2101_audio_read(TSC2101_AUDIO_CTRL_6));
- dev_dbg(&mcbsp_dev.mcbsp_dev->dev,
- "TSC2101_AUDIO_CTRL_7 = 0x%04x\n",
- tsc2101_audio_read(TSC2101_AUDIO_CTRL_7));
- dev_dbg(&mcbsp_dev.mcbsp_dev->dev,
- "TSC2101_GPIO_CTRL = 0x%04x\n",
- tsc2101_audio_read(TSC2101_GPIO_CTRL));
- dev_dbg(&mcbsp_dev.mcbsp_dev->dev,
- "TSC2101_AGC_CTRL = 0x%04x\n",
- tsc2101_audio_read(TSC2101_AGC_CTRL));
- dev_dbg(&mcbsp_dev.mcbsp_dev->dev,
- "TSC2101_POWERDOWN_STS = 0x%04x\n",
- tsc2101_audio_read(TSC2101_POWERDOWN_STS));
- dev_dbg(&mcbsp_dev.mcbsp_dev->dev,
- "TSC2101_MIC_AGC_CONTROL = 0x%04x\n",
- tsc2101_audio_read(TSC2101_MIC_AGC_CONTROL));
- dev_dbg(&mcbsp_dev.mcbsp_dev->dev,
- "TSC2101_CELL_AGC_CONTROL = 0x%04x\n",
- tsc2101_audio_read(TSC2101_CELL_AGC_CONTROL));
-}
-#endif
-
-/*
- * ALSA operations according to board file
- */
-
-/*
- * Sample rate changing
- */
-void tsc2101_set_samplerate(long sample_rate)
-{
- u8 count = 0;
- u16 data = 0;
- int clkgdv = 0;
-
- u16 srgr1, srgr2;
- /* wait for any frame to complete */
- udelay(125);
- ADEBUG();
-
- sample_rate = sample_rate;
- /* Search for the right sample rate */
- while ((rate_reg_info[count].sample_rate != sample_rate) &&
- (count < NUMBER_SAMPLE_RATES_SUPPORTED)) {
- count++;
- }
- if (count == NUMBER_SAMPLE_RATES_SUPPORTED) {
- printk(KERN_ERR "Invalid Sample Rate %d requested\n",
- (int) sample_rate);
- return;
- }
-
- /* Set AC1 */
- data = tsc2101_audio_read(TSC2101_AUDIO_CTRL_1);
- /* Clear prev settings */
- data &= ~(AC1_DACFS(0x07) | AC1_ADCFS(0x07));
- data |= AC1_DACFS(rate_reg_info[count].divisor) |
- AC1_ADCFS(rate_reg_info[count].divisor);
- tsc2101_audio_write(TSC2101_AUDIO_CTRL_1, data);
-
- /* Set the AC3 */
- data = tsc2101_audio_read(TSC2101_AUDIO_CTRL_3);
- /*Clear prev settings */
- data &= ~(AC3_REFFS | AC3_SLVMS);
- data |= (rate_reg_info[count].fs_44kHz) ? AC3_REFFS : 0;
-#ifdef TSC_MASTER
- data |= AC3_SLVMS;
-#endif /* #ifdef TSC_MASTER */
- tsc2101_audio_write(TSC2101_AUDIO_CTRL_3, data);
-
- /*
- * Program the PLLs. This code assumes that the 12 Mhz MCLK is in use.
- * If MCLK rate is something else, these values must be changed.
- * See the tsc2101 specification for the details.
- */
- if (rate_reg_info[count].fs_44kHz) {
- /* samplerate = (44.1kHZ / x), where x is int. */
- tsc2101_audio_write(TSC2101_PLL_PROG_1, PLL1_PLLSEL |
- /* PVAL 1; I_VAL 7 */
- PLL1_PVAL(1) | PLL1_I_VAL(7));
- /* D_VAL 5264 */
- tsc2101_audio_write(TSC2101_PLL_PROG_2, PLL2_D_VAL(0x1490));
- } else {
- /* samplerate = (48.kHZ / x), where x is int. */
- tsc2101_audio_write(TSC2101_PLL_PROG_1, PLL1_PLLSEL |
- /* PVAL 1; I_VAL 8 */
- PLL1_PVAL(1) | PLL1_I_VAL(8));
- /* D_VAL 1920 */
- tsc2101_audio_write(TSC2101_PLL_PROG_2, PLL2_D_VAL(0x780));
- }
-
- /* Set the sample rate */
-#ifndef TSC_MASTER
- clkgdv = CODEC_CLOCK / (sample_rate * (DEFAULT_BITPERSAMPLE * 2 - 1));
- if (clkgdv)
- srgr1 = (FWID(DEFAULT_BITPERSAMPLE - 1) | CLKGDV(clkgdv));
- else
- return (1);
-
- /* Stereo Mode */
- srgr2 = (CLKSM | FSGM | FPER(DEFAULT_BITPERSAMPLE * 2 - 1));
-#else
- srgr1 = (FWID(DEFAULT_BITPERSAMPLE - 1) | CLKGDV(clkgdv));
- srgr2 = ((GSYNC | CLKSP | FSGM | FPER(DEFAULT_BITPERSAMPLE * 2 - 1)));
-
-#endif /* end of #ifdef TSC_MASTER */
- OMAP_MCBSP_WRITE(OMAP1610_MCBSP1_BASE, SRGR2, srgr2);
- OMAP_MCBSP_WRITE(OMAP1610_MCBSP1_BASE, SRGR1, srgr1);
-}
-
-void tsc2101_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
- */
-void tsc2101_clock_setup(void)
-{
- tsc2101_mclk = clk_get(0, "mclk");
-}
-
-/*
- * Do some sanity check, set clock rate, starts it and turn codec audio on
- */
-int tsc2101_clock_on(void)
-{
- int curUseCount;
- uint curRate;
- int err;
-
- curUseCount = clk_get_usecount(tsc2101_mclk);
- DPRINTK("clock use count = %d\n", curUseCount);
- if (curUseCount > 0) {
- /* MCLK is already in use */
- printk(KERN_WARNING
- "MCLK already in use at %d Hz. We change it to %d Hz\n",
- (uint) clk_get_rate(tsc2101_mclk),
- CODEC_CLOCK);
- }
- curRate = (uint)clk_get_rate(tsc2101_mclk);
- if (curRate != CODEC_CLOCK) {
- err = clk_set_rate(tsc2101_mclk, CODEC_CLOCK);
- if (err) {
- printk(KERN_WARNING "Cannot set MCLK clock rate for "
- "TSC2101 CODEC, error code = %d\n", err);
- return -ECANCELED;
- }
- }
- err = clk_enable(tsc2101_mclk);
- curRate = (uint)clk_get_rate(tsc2101_mclk);
- curUseCount = clk_get_usecount(tsc2101_mclk);
- DPRINTK("MCLK = %d [%d], usecount = %d, clk_enable retval = %d\n",
- curRate,
- CODEC_CLOCK,
- curUseCount,
- err);
-
- /* Now turn the audio on */
- tsc2101_write_sync(mcbsp_dev.tsc2101_dev, PAGE2_AUDIO_CODEC_REGISTERS,
- TSC2101_CODEC_POWER_CTRL,
- 0x0000);
- return 0;
-}
-
-/*
- * Do some sanity check, turn clock off and then turn codec audio off
- */
-int tsc2101_clock_off(void)
-{
- int curUseCount;
- int curRate;
-
- curUseCount = clk_get_usecount(tsc2101_mclk);
- DPRINTK("clock use count = %d\n", curUseCount);
- if (curUseCount > 0) {
- curRate = clk_get_rate(tsc2101_mclk);
- DPRINTK("clock rate = %d\n", curRate);
- if (curRate != CODEC_CLOCK) {
- printk(KERN_WARNING
- "MCLK for audio should be %d Hz. But is %d Hz\n",
- (uint) clk_get_rate(tsc2101_mclk),
- CODEC_CLOCK);
- }
- clk_disable(tsc2101_mclk);
- DPRINTK("clock disabled\n");
- }
- tsc2101_audio_write(TSC2101_CODEC_POWER_CTRL,
- ~(CPC_SP1PWDN | CPC_SP2PWDN | CPC_BASSBC));
- DPRINTK("audio codec off\n");
- return 0;
-}
-
-int tsc2101_get_default_samplerate(void)
-{
- return DEFAULT_SAMPLE_RATE;
-}
-
-static int __devinit snd_omap_alsa_tsc2101_probe(struct platform_device *pdev)
-{
- struct spi_device *tsc2101;
- int ret;
- struct omap_alsa_codec_config *codec_cfg;
-
- tsc2101 = dev_get_drvdata(&pdev->dev);
- if (tsc2101 == NULL) {
- dev_err(&pdev->dev, "no platform data\n");
- return -ENODEV;
- }
- if (strncmp(tsc2101->modalias, "tsc2101", 8) != 0) {
- dev_err(&pdev->dev, "tsc2101 not found\n");
- return -EINVAL;
- }
- mcbsp_dev.mcbsp_dev = pdev;
- mcbsp_dev.tsc2101_dev = tsc2101;
-
- codec_cfg = pdev->dev.platform_data;
- if (codec_cfg != NULL) {
- codec_cfg->hw_constraints_rates =
- &tsc2101_hw_constraints_rates;
- codec_cfg->snd_omap_alsa_playback =
- &tsc2101_snd_omap_alsa_playback;
- codec_cfg->snd_omap_alsa_capture =
- &tsc2101_snd_omap_alsa_capture;
- codec_cfg->codec_configure_dev = tsc2101_configure;
- codec_cfg->codec_set_samplerate = tsc2101_set_samplerate;
- codec_cfg->codec_clock_setup = tsc2101_clock_setup;
- codec_cfg->codec_clock_on = tsc2101_clock_on;
- codec_cfg->codec_clock_off = tsc2101_clock_off;
- codec_cfg->get_default_samplerate =
- tsc2101_get_default_samplerate;
- ret = snd_omap_alsa_post_probe(pdev, codec_cfg);
- } else
- ret = -ENODEV;
- return ret;
-}
-
-static struct platform_driver omap_alsa_driver = {
- .probe = snd_omap_alsa_tsc2101_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_tsc2101_init(void)
-{
- ADEBUG();
-#ifdef DUMP_TSC2101_AUDIO_REGISTERS
- printk(KERN_INFO "omap_alsa_tsc2101_init()\n");
- dump_tsc2101_audio_reg();
-#endif
- return platform_driver_register(&omap_alsa_driver);
-}
-
-static void __exit omap_alsa_tsc2101_exit(void)
-{
- ADEBUG();
-#ifdef DUMP_TSC2101_AUDIO_REGISTERS
- printk(KERN_INFO "omap_alsa_tsc2101_exit()\n");
- dump_tsc2101_audio_reg();
-#endif
- platform_driver_unregister(&omap_alsa_driver);
-}
-
-module_init(omap_alsa_tsc2101_init);
-module_exit(omap_alsa_tsc2101_exit);
+++ /dev/null
-/*
- * sound/arm/omap/omap-alsa-tsc2101.h
- *
- * Alsa Driver for TSC2101 codec for OMAP platform boards.
- *
- * Based on former omap-aic23.h and tsc2101 OSS drivers.
- * Copyright (C) 2004 Texas Instruments, Inc.
- * Written by Nishanth Menon and Sriram Kannan
- *
- * Copyright (C) 2006 Instituto Nokia de Tecnologia - INdT - Manaus Brazil
- * Alsa modularization by Daniel Petrini (d.pensator@gmail.com)
- *
- * Copyright (C) 2006 Mika Laitio <lamikr@cc.jyu.fi>
- *
- * 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_TSC2101_H_
-#define OMAP_ALSA_TSC2101_H_
-
-#include <linux/types.h>
-
-/* Define to set the tsc as the master w.r.t McBSP or EAC */
-#define TSC_MASTER
-
-#define NUMBER_SAMPLE_RATES_SUPPORTED 16
-
-/*
- * AUDIO related MACROS
- */
-#ifndef DEFAULT_BITPERSAMPLE
-#define DEFAULT_BITPERSAMPLE 16
-#endif
-
-#define DEFAULT_SAMPLE_RATE 44100
-
-/* FIXME codec clock rate is board-specific */
-#define CODEC_CLOCK 12000000
-
-#define PAGE2_AUDIO_CODEC_REGISTERS (2)
-
-struct mcbsp_dev_info {
- struct platform_device *mcbsp_dev;
- struct spi_device *tsc2101_dev;
-};
-
-struct tsc2101_samplerate_reg_info {
- u16 sample_rate;
- u8 divisor;
- u8 fs_44kHz; /* if 0 48 khz, if 1 44.1 khz fsref */
-};
-
-/*
- * Defines codec specific function pointers that can be used from the
- * common omap-alse base driver for all omap codecs. (tsc2101 and aic23)
- */
-inline void tsc2101_configure(void);
-void tsc2101_set_samplerate(long rate);
-void tsc2101_clock_setup(void);
-int tsc2101_clock_on(void);
-int tsc2101_clock_off(void);
-int tsc2101_get_default_samplerate(void);
-
-#endif /*OMAP_ALSA_TSC2101_H_*/
+++ /dev/null
-/*
- * sound/arm/omap/omap-alsa-tsc2102-mixer.c
- *
- * Alsa mixer driver for TSC2102 chip for OMAP platforms.
- *
- * Copyright (c) 2006 Andrzej Zaborowski <balrog@zabor.org>
- * Code based on the TSC2101 ALSA driver.
- *
- * 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.
- *
- * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
- * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN
- * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
- * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
- * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
- * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
- * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
- * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- * 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.
- */
-
-#include <linux/types.h>
-#include <linux/spi/tsc2102.h>
-
-#include <mach/omap-alsa.h>
-
-#include <sound/initval.h>
-#include <sound/control.h>
-
-#include "omap-alsa-tsc2102.h"
-#include "omap-alsa-dma.h"
-
-static int vol[2], mute[2], filter[2];
-
-/*
- * Converts the Alsa mixer volume (0 - 100) to actual Digital
- * Gain Control (DGC) value that can be written or read from the
- * TSC2102 registers.
- *
- * Note that the number "OUTPUT_VOLUME_MAX" is smaller than
- * OUTPUT_VOLUME_MIN because DGC works as a volume decreaser. (The
- * higher the value sent to DAC, the more the volume of controlled
- * channel is decreased)
- */
-static void set_dac_gain_stereo(int left_ch, int right_ch)
-{
- int lch, rch;
-
- if (left_ch > 100)
- vol[0] = 100;
- else if (left_ch < 0)
- vol[0] = 0;
- else
- vol[0] = left_ch;
- lch = OUTPUT_VOLUME_MIN - vol[0] *
- (OUTPUT_VOLUME_MIN - OUTPUT_VOLUME_MAX) / 100;
-
- if (right_ch > 100)
- vol[1] = 100;
- else if (right_ch < 0)
- vol[1] = 0;
- else
- vol[1] = right_ch;
- rch = OUTPUT_VOLUME_MIN - vol[1] *
- (OUTPUT_VOLUME_MIN - OUTPUT_VOLUME_MAX) / 100;
-
- tsc2102_set_volume(lch, rch);
-}
-
-void init_playback_targets(void)
-{
- set_dac_gain_stereo(DEFAULT_OUTPUT_VOLUME, DEFAULT_OUTPUT_VOLUME);
-
- /* Unmute */
- tsc2102_set_mute(0, 0);
-
- mute[0] = 0;
- mute[1] = 0;
- filter[0] = 0;
- filter[1] = 0;
-}
-
-/*
- * Initializes TSC 2102 and playback target.
- */
-void snd_omap_init_mixer(void)
-{
- FN_IN;
-
- init_playback_targets();
-
- FN_OUT(0);
-}
-
-static int __pcm_playback_volume_info(struct snd_kcontrol *kcontrol,
- struct snd_ctl_elem_info *uinfo)
-{
- uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
- uinfo->count = 2;
- uinfo->value.integer.min = 0;
- uinfo->value.integer.max = 100;
- return 0;
-}
-
-static int __pcm_playback_volume_get(struct snd_kcontrol *kcontrol,
- struct snd_ctl_elem_value *ucontrol)
-{
- ucontrol->value.integer.value[0] = vol[0]; /* L */
- ucontrol->value.integer.value[1] = vol[1]; /* R */
-
- return 0;
-}
-
-static int __pcm_playback_volume_put(struct snd_kcontrol *kcontrol,
- struct snd_ctl_elem_value *ucontrol)
-{
- set_dac_gain_stereo(
- ucontrol->value.integer.value[0], /* L */
- ucontrol->value.integer.value[1]); /* R */
- return 1;
-}
-
-static int __pcm_playback_switch_info(struct snd_kcontrol *kcontrol,
- struct snd_ctl_elem_info *uinfo)
-{
- uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN;
- uinfo->count = 2;
- uinfo->value.integer.min = 0;
- uinfo->value.integer.max = 1;
- return 0;
-}
-
-static int __pcm_playback_switch_get(struct snd_kcontrol *kcontrol,
- struct snd_ctl_elem_value *ucontrol)
-{
- ucontrol->value.integer.value[0] = !mute[0]; /* L */
- ucontrol->value.integer.value[1] = !mute[1]; /* R */
-
- return 0;
-}
-
-static int __pcm_playback_switch_put(struct snd_kcontrol *kcontrol,
- struct snd_ctl_elem_value *ucontrol)
-{
- mute[0] = (ucontrol->value.integer.value[0] == 0); /* L */
- mute[1] = (ucontrol->value.integer.value[1] == 0); /* R */
-
- tsc2102_set_mute(mute[0], mute[1]);
- return 1;
-}
-
-static int __pcm_playback_deemphasis_info(struct snd_kcontrol *kcontrol,
- struct snd_ctl_elem_info *uinfo)
-{
- uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN;
- uinfo->count = 1;
- uinfo->value.integer.min = 0;
- uinfo->value.integer.max = 1;
- return 0;
-}
-
-static int __pcm_playback_deemphasis_get(struct snd_kcontrol *kcontrol,
- struct snd_ctl_elem_value *ucontrol)
-{
- ucontrol->value.integer.value[0] = filter[0];
- return 0;
-}
-
-static int __pcm_playback_deemphasis_put(struct snd_kcontrol *kcontrol,
- struct snd_ctl_elem_value *ucontrol)
-{
- filter[0] = (ucontrol->value.integer.value[0] > 0);
-
- tsc2102_set_deemphasis(filter[0]);
- return 1;
-}
-
-static int __pcm_playback_bassboost_info(struct snd_kcontrol *kcontrol,
- struct snd_ctl_elem_info *uinfo)
-{
- uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN;
- uinfo->count = 1;
- uinfo->value.integer.min = 0;
- uinfo->value.integer.max = 1;
- return 0;
-}
-
-static int __pcm_playback_bassboost_get(struct snd_kcontrol *kcontrol,
- struct snd_ctl_elem_value *ucontrol)
-{
- ucontrol->value.integer.value[0] = filter[1];
- return 0;
-}
-
-static int __pcm_playback_bassboost_put(struct snd_kcontrol *kcontrol,
- struct snd_ctl_elem_value *ucontrol)
-{
- filter[1] = (ucontrol->value.integer.value[0] > 0);
-
- tsc2102_set_bassboost(filter[1]);
- return 1;
-}
-
-static struct snd_kcontrol_new tsc2102_controls[] __devinitdata = {
- {
- .name = "Master Playback Volume",
- .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
- .index = 0,
- .access = SNDRV_CTL_ELEM_ACCESS_READWRITE,
- .info = __pcm_playback_volume_info,
- .get = __pcm_playback_volume_get,
- .put = __pcm_playback_volume_put,
- },
- {
- .name = "Master Playback Switch",
- .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
- .index = 0,
- .access = SNDRV_CTL_ELEM_ACCESS_READWRITE,
- .info = __pcm_playback_switch_info,
- .get = __pcm_playback_switch_get,
- .put = __pcm_playback_switch_put,
- },
- {
- .name = "De-emphasis Filter Switch",
- .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
- .index = 0,
- .access = SNDRV_CTL_ELEM_ACCESS_READWRITE,
- .info = __pcm_playback_deemphasis_info,
- .get = __pcm_playback_deemphasis_get,
- .put = __pcm_playback_deemphasis_put,
- },
- {
- .name = "Bass-boost Filter Switch",
- .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
- .index = 0,
- .access = SNDRV_CTL_ELEM_ACCESS_READWRITE,
- .info = __pcm_playback_bassboost_info,
- .get = __pcm_playback_bassboost_get,
- .put = __pcm_playback_bassboost_put,
- },
-};
-
-#ifdef CONFIG_PM
-void snd_omap_suspend_mixer(void)
-{
- /* Nothing to do */
-}
-
-void snd_omap_resume_mixer(void)
-{
- /* The chip was reset, restore the last used values */
- set_dac_gain_stereo(vol[0], vol[1]);
-
- tsc2102_set_mute(mute[0], mute[1]);
- tsc2102_set_deemphasis(filter[0]);
- tsc2102_set_bassboost(filter[1]);
-}
-#endif
-
-int snd_omap_mixer(struct snd_card_omap_codec *tsc2102)
-{
- int i, err;
-
- if (!tsc2102)
- return -EINVAL;
-
- for (i = 0; i < ARRAY_SIZE(tsc2102_controls); i++) {
- err = snd_ctl_add(tsc2102->card,
- snd_ctl_new1(&tsc2102_controls[i],
- tsc2102->card));
-
- if (err < 0)
- return err;
- }
- return 0;
-}
+++ /dev/null
-/*
- * sound/arm/omap/omap-alsa-tsc2102.c
- *
- * Alsa codec driver for TSC2102 chip for OMAP platforms.
- *
- * Copyright (c) 2006 Andrzej Zaborowski <balrog@zabor.org>
- * Code based on the TSC2101 ALSA driver.
- *
- * 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 <linux/module.h>
-#include <linux/io.h>
-#include <linux/spi/tsc2102.h>
-
-#include <mach/dma.h>
-#include <mach/clock.h>
-#include <mach/omap-alsa.h>
-
-#include "omap-alsa-tsc2102.h"
-
-static struct clk *tsc2102_bclk;
-
-/*
- * Hardware capabilities
- */
-
-/* DAC sampling rates (BCLK = 12 MHz) */
-static unsigned int rates[] = {
- 7350, 8000, 8820, 9600, 11025, 12000, 14700,
- 16000, 22050, 24000, 29400, 32000, 44100, 48000,
-};
-
-static struct snd_pcm_hw_constraint_list tsc2102_hw_constraints_rates = {
- .count = ARRAY_SIZE(rates),
- .list = rates,
- .mask = 0,
-};
-
-static struct snd_pcm_hardware tsc2102_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 = 7350,
- .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,
-};
-
-#ifdef DUMP_TSC2102_AUDIO_REGISTERS
-static void dump_tsc2102_audio_regs(void)
-{
- printk(KERN_INFO "TSC2102_AUDIO1_CTRL = 0x%04x\n",
- tsc2102_read_sync(TSC2102_AUDIO1_CTRL));
- printk(KERN_INFO "TSC2102_DAC_GAIN_CTRL = 0x%04x\n",
- tsc2102_read_sync(TSC2102_DAC_GAIN_CTRL));
- printk(KERN_INFO "TSC2102_AUDIO2_CTRL = 0x%04x\n",
- tsc2102_read_sync(TSC2102_AUDIO2_CTRL));
- printk(KERN_INFO "TSC2102_DAC_POWER_CTRL = 0x%04x\n",
- tsc2102_read_sync(TSC2102_DAC_POWER_CTRL));
- printk(KERN_INFO "TSC2102_AUDIO3_CTRL = 0x%04x\n",
- tsc2102_read_sync(TSC2102_AUDIO_CTRL_3));
- printk(KERN_INFO "TSC2102_LCH_BASS_BOOST_N0 = 0x%04x\n",
- tsc2102_read_sync(TSC2102_LCH_BASS_BOOST_N0));
- printk(KERN_INFO "TSC2102_LCH_BASS_BOOST_N1 = 0x%04x\n",
- tsc2102_read_sync(TSC2102_LCH_BASS_BOOST_N1));
- printk(KERN_INFO "TSC2102_LCH_BASS_BOOST_N2 = 0x%04x\n",
- tsc2102_read_sync(TSC2102_LCH_BASS_BOOST_N2));
- printk(KERN_INFO "TSC2102_LCH_BASS_BOOST_N3 = 0x%04x\n",
- tsc2102_read_sync(TSC2102_LCH_BASS_BOOST_N3));
- printk(KERN_INFO "TSC2102_LCH_BASS_BOOST_N4 = 0x%04x\n",
- tsc2102_read_sync(TSC2102_LCH_BASS_BOOST_N4));
- printk(KERN_INFO "TSC2102_LCH_BASS_BOOST_N5 = 0x%04x\n",
- tsc2102_read_sync(TSC2102_LCH_BASS_BOOST_N5));
- printk(KERN_INFO "TSC2102_LCH_BASS_BOOST_D1 = 0x%04x\n",
- tsc2102_read_sync(TSC2102_LCH_BASS_BOOST_D1));
- printk(KERN_INFO "TSC2102_LCH_BASS_BOOST_D2 = 0x%04x\n",
- tsc2102_read_sync(TSC2102_LCH_BASS_BOOST_D2));
- printk(KERN_INFO "TSC2102_LCH_BASS_BOOST_D4 = 0x%04x\n",
- tsc2102_read_sync(TSC2102_LCH_BASS_BOOST_D4));
- printk(KERN_INFO "TSC2102_LCH_BASS_BOOST_D5 = 0x%04x\n",
- tsc2102_read_sync(TSC2102_LCH_BASS_BOOST_D5));
- printk(KERN_INFO "TSC2102_RCH_BASS_BOOST_N0 = 0x%04x\n",
- tsc2102_read_sync(TSC2102_RCH_BASS_BOOST_N0));
- printk(KERN_INFO "TSC2102_RCH_BASS_BOOST_N1 = 0x%04x\n",
- tsc2102_read_sync(TSC2102_RCH_BASS_BOOST_N1));
- printk(KERN_INFO "TSC2102_RCH_BASS_BOOST_N2 = 0x%04x\n",
- tsc2102_read_sync(TSC2102_RCH_BASS_BOOST_N2));
- printk(KERN_INFO "TSC2102_RCH_BASS_BOOST_N3 = 0x%04x\n",
- tsc2102_read_sync(TSC2102_RCH_BASS_BOOST_N3));
- printk(KERN_INFO "TSC2102_RCH_BASS_BOOST_N4 = 0x%04x\n",
- tsc2102_read_sync(TSC2102_RCH_BASS_BOOST_N4));
- printk(KERN_INFO "TSC2102_RCH_BASS_BOOST_N5 = 0x%04x\n",
- tsc2102_read_sync(TSC2102_RCH_BASS_BOOST_N5));
- printk(KERN_INFO "TSC2102_RCH_BASS_BOOST_D1 = 0x%04x\n",
- tsc2102_read_sync(TSC2102_RCH_BASS_BOOST_D1));
- printk(KERN_INFO "TSC2102_RCH_BASS_BOOST_D2 = 0x%04x\n",
- tsc2102_read_sync(TSC2102_RCH_BASS_BOOST_D2));
- printk(KERN_INFO "TSC2102_RCH_BASS_BOOST_D4 = 0x%04x\n",
- tsc2102_read_sync(TSC2102_RCH_BASS_BOOST_D4));
- printk(KERN_INFO "TSC2102_RCH_BASS_BOOST_D5 = 0x%04x\n",
- tsc2102_read_sync(TSC2102_RCH_BASS_BOOST_D5));
- printk(KERN_INFO "TSC2102_PLL1_CTRL = 0x%04x\n",
- tsc2102_read_sync(TSC2102_PLL1_CTRL));
- printk(KERN_INFO "TSC2102_PLL2_CTRL = 0x%04x\n",
- tsc2102_read_sync(TSC2102_PLL2_CTRL));
- printk(KERN_INFO "TSC2102_AUDIO4_CTRL = 0x%04x\n",
- tsc2102_read_sync(TSC2102_AUDIO4_CTRL));
-}
-#endif
-
-/*
- * ALSA operations according to board file
- */
-
-static long current_rate;
-
-/*
- * Sample rate changing
- */
-static void tsc2102_set_samplerate(long sample_rate)
-{
- int clkgdv = 0;
- u16 srgr1, srgr2;
-
- if (sample_rate == current_rate)
- return;
- current_rate = 0;
-
- if (tsc2102_set_rate(sample_rate))
- return;
-
- /* Set the sample rate */
-#ifndef TSC_MASTER
- clkgdv = CODEC_CLOCK / (sample_rate * (DEFAULT_BITPERSAMPLE * 2 - 1));
- if (clkgdv)
- srgr1 = (FWID(DEFAULT_BITPERSAMPLE - 1) | CLKGDV(clkgdv));
- else
- return;
-
- /* Stereo Mode */
- srgr2 = CLKSM | FSGM | FPER(DEFAULT_BITPERSAMPLE * 2 - 1);
-#else
- srgr1 = FWID(DEFAULT_BITPERSAMPLE - 1) | CLKGDV(clkgdv);
- srgr2 = GSYNC | CLKSP | FSGM | FPER(DEFAULT_BITPERSAMPLE * 2 - 1);
-#endif
- OMAP_MCBSP_WRITE(OMAP1510_MCBSP1_BASE, SRGR2, srgr2);
- OMAP_MCBSP_WRITE(OMAP1510_MCBSP1_BASE, SRGR1, srgr1);
- current_rate = sample_rate;
-}
-
-static void tsc2102_configure(void)
-{
- tsc2102_dac_power(1);
-
-#ifdef TSC_MASTER
- tsc2102_set_i2s_master(1);
-#else
- tsc2102_set_i2s_master(0);
-#endif
-}
-
-/*
- * Omap McBSP clock and Power Management configuration
- *
- * Here we have some functions that allow clock to be enabled and
- * disabled only when needed. Besides doing clock configuration
- * they allow turn audio on and off when necessary.
- */
-
-/*
- * Do clock framework bclk search
- */
-static void tsc2102_clock_setup(void)
-{
- tsc2102_bclk = clk_get(0, "bclk");
-}
-
-/*
- * Do some sanity checks, set clock rate, start it.
- */
-static int tsc2102_clock_on(void)
-{
- int err;
-
- if (clk_get_usecount(tsc2102_bclk) > 0 &&
- clk_get_rate(tsc2102_bclk) != CODEC_CLOCK) {
- /* BCLK is already in use */
- printk(KERN_WARNING
- "BCLK already in use at %d Hz. We change it to %d Hz\n",
- (uint) clk_get_rate(tsc2102_bclk), CODEC_CLOCK);
-
- err = clk_set_rate(tsc2102_bclk, CODEC_CLOCK);
- if (err)
- printk(KERN_WARNING "Cannot set BCLK clock rate "
- "for TSC2102 codec, error code = %d\n", err);
- }
-
- clk_enable(tsc2102_bclk);
- return 0;
-}
-
-/*
- * Turn off the audio codec and then stop the clock.
- */
-static int tsc2102_clock_off(void)
-{
- DPRINTK("clock use count = %d\n", clk_get_usecount(tsc2102_bclk));
-
- clk_disable(tsc2102_bclk);
- return 0;
-}
-
-static int tsc2102_get_default_samplerate(void)
-{
- return DEFAULT_SAMPLE_RATE;
-}
-
-static int snd_omap_alsa_tsc2102_suspend(
- struct platform_device *pdev, pm_message_t state)
-{
- tsc2102_dac_power(0);
- current_rate = 0;
-
- return snd_omap_alsa_suspend(pdev, state);
-}
-
-static int snd_omap_alsa_tsc2102_resume(struct platform_device *pdev)
-{
- tsc2102_dac_power(1);
-
-#ifdef TSC_MASTER
- tsc2102_set_i2s_master(1);
-#else
- tsc2102_set_i2s_master(0);
-#endif
-
- return snd_omap_alsa_resume(pdev);
-}
-
-static int __init snd_omap_alsa_tsc2102_probe(struct platform_device *pdev)
-{
- int ret;
- struct omap_alsa_codec_config *codec_cfg = pdev->dev.platform_data;
-
- if (codec_cfg) {
- codec_cfg->hw_constraints_rates =
- &tsc2102_hw_constraints_rates;
- codec_cfg->snd_omap_alsa_playback =
- &tsc2102_snd_omap_alsa_playback;
- codec_cfg->codec_configure_dev = tsc2102_configure;
- codec_cfg->codec_set_samplerate = tsc2102_set_samplerate;
- codec_cfg->codec_clock_setup = tsc2102_clock_setup;
- codec_cfg->codec_clock_on = tsc2102_clock_on;
- codec_cfg->codec_clock_off = tsc2102_clock_off;
- codec_cfg->get_default_samplerate =
- tsc2102_get_default_samplerate;
- ret = snd_omap_alsa_post_probe(pdev, codec_cfg);
- } else
- ret = -ENODEV;
-
- return ret;
-}
-
-static int snd_omap_alsa_tsc2102_remove(struct platform_device *pdev)
-{
- tsc2102_dac_power(0);
-
- return snd_omap_alsa_remove(pdev);
-}
-
-static struct platform_driver omap_alsa_driver = {
- .probe = snd_omap_alsa_tsc2102_probe,
- .remove = snd_omap_alsa_tsc2102_remove,
- .suspend = snd_omap_alsa_tsc2102_suspend,
- .resume = snd_omap_alsa_tsc2102_resume,
- .driver = {
- .name = "tsc2102-alsa",
- .owner = THIS_MODULE,
- },
-};
-
-static int __init omap_alsa_tsc2102_init(void)
-{
- int err;
-
- ADEBUG();
- err = platform_driver_register(&omap_alsa_driver);
-
- return err;
-}
-
-static void __exit omap_alsa_tsc2102_exit(void)
-{
- ADEBUG();
- platform_driver_unregister(&omap_alsa_driver);
-}
-
-module_init(omap_alsa_tsc2102_init);
-module_exit(omap_alsa_tsc2102_exit);
+++ /dev/null
-/*
- * sound/arm/omap/omap-alsa-tsc2102.h
- *
- * Alsa codec driver for TSC2102 chip for OMAP platforms.
- *
- * Copyright (c) 2006 Andrzej Zaborowski <balrog@zabor.org>
- * Code based on the TSC2101 ALSA driver.
- *
- * 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_TSC2102_H_
-#define OMAP_ALSA_TSC2102_H_
-
-/* Define to set the tsc as the master w.r.t McBSP */
-#define TSC_MASTER
-
-/*
- * Audio related macros
- */
-#ifndef DEFAULT_BITPERSAMPLE
-#define DEFAULT_BITPERSAMPLE 16
-#endif
-
-#define DEFAULT_SAMPLE_RATE 44100
-
-/* FIXME codec clock rate is board-specific */
-#define CODEC_CLOCK 12000000
-
-/*
- * ALSA mixer related macros
- */
-#define OUTPUT_VOLUME_MIN 0x7f /* 1111111 = -63.5 dB */
-#define OUTPUT_VOLUME_MAX 0x00 /* 0000000 */
-#define OUTPUT_VOLUME_RANGE (OUTPUT_VOLUME_MIN - OUTPUT_VOLUME_MAX)
-
-#define DEFAULT_OUTPUT_VOLUME 90 /* Default output volume */
-
-#endif /* OMAP_ALSA_TSC2102_H_ */
+++ /dev/null
-/*
- * sound/arm/omap-alsa.c
- *
- * Alsa Driver for OMAP
- *
- * Copyright (C) 2005 Instituto Nokia de Tecnologia - INdT - Manaus Brazil
- * Written by Daniel Petrini, David Cohen, Anderson Briglia
- * {daniel.petrini, david.cohen, anderson.briglia}@indt.org.br
- *
- * Copyright (C) 2006 Mika Laitio <lamikr@cc.jyu.fi>
- *
- * Based on sa11xx-uda1341.c,
- * Copyright (C) 2002 Tomas Kasparek <tomas.kasparek@seznam.cz>
- *
- * 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.
- *
- * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
- * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN
- * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
- * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
- * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
- * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
- * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
- * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- * 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.
- *
- * History:
- *
- * 2005-07-29 INdT Kernel Team - Alsa driver for omap osk. Creation of new
- * file omap-aic23.c
- *
- * 2005-12-18 Dirk Behme - Added L/R Channel Interchange fix as proposed
- * by Ajaya Babu
- *
- */
-
-#include <linux/platform_device.h>
-#ifdef CONFIG_PM
-#include <linux/pm.h>
-#endif
-#include <sound/core.h>
-#include <sound/pcm.h>
-
-#include <mach/omap-alsa.h>
-#include "omap-alsa-dma.h"
-
-MODULE_AUTHOR("Mika Laitio");
-MODULE_AUTHOR("Daniel Petrini");
-MODULE_AUTHOR("David Cohen");
-MODULE_AUTHOR("Anderson Briglia");
-
-MODULE_LICENSE("GPL");
-MODULE_DESCRIPTION("OMAP driver for ALSA");
-MODULE_ALIAS("omap_alsa_mcbsp.1");
-
-static char *id;
-static struct snd_card_omap_codec *alsa_codec;
-static struct omap_alsa_codec_config *alsa_codec_config;
-
-/* FIXME: Please change to use omap asoc framework instead, this can be racy */
-static dma_addr_t dma_start_pos;
-
-/*
- * HW interface start and stop helper functions
- */
-static int audio_ifc_start(void)
-{
- omap_mcbsp_start(AUDIO_MCBSP);
- return 0;
-}
-
-static int audio_ifc_stop(void)
-{
- omap_mcbsp_stop(AUDIO_MCBSP);
- return 0;
-}
-
-static void omap_alsa_audio_init(struct snd_card_omap_codec *omap_alsa)
-{
- /* Setup DMA stuff */
- omap_alsa->s[SNDRV_PCM_STREAM_PLAYBACK].id = "Alsa omap out";
- omap_alsa->s[SNDRV_PCM_STREAM_PLAYBACK].stream_id =
- SNDRV_PCM_STREAM_PLAYBACK;
- omap_alsa->s[SNDRV_PCM_STREAM_PLAYBACK].dma_dev =
- OMAP_DMA_MCBSP1_TX;
- omap_alsa->s[SNDRV_PCM_STREAM_PLAYBACK].hw_start =
- audio_ifc_start;
- omap_alsa->s[SNDRV_PCM_STREAM_PLAYBACK].hw_stop =
- audio_ifc_stop;
-
- omap_alsa->s[SNDRV_PCM_STREAM_CAPTURE].id = "Alsa omap in";
- omap_alsa->s[SNDRV_PCM_STREAM_CAPTURE].stream_id =
- SNDRV_PCM_STREAM_CAPTURE;
- omap_alsa->s[SNDRV_PCM_STREAM_CAPTURE].dma_dev =
- OMAP_DMA_MCBSP1_RX;
- omap_alsa->s[SNDRV_PCM_STREAM_CAPTURE].hw_start =
- audio_ifc_start;
- omap_alsa->s[SNDRV_PCM_STREAM_CAPTURE].hw_stop =
- audio_ifc_stop;
-}
-
-/*
- * DMA functions
- * Depends on omap-alsa-dma.c functions and (omap) dma.c
- */
-static int audio_dma_request(struct audio_stream *s,
- void (*callback) (void *))
-{
- int err;
- ADEBUG();
-
- err = omap_request_alsa_sound_dma(s->dma_dev, s->id, s, &s->lch);
- if (err < 0)
- printk(KERN_ERR "Unable to grab audio dma 0x%x\n", s->dma_dev);
- return err;
-}
-
-static int audio_dma_free(struct audio_stream *s)
-{
- int err = 0;
- ADEBUG();
-
- err = omap_free_alsa_sound_dma(s, &s->lch);
- if (err < 0)
- printk(KERN_ERR "Unable to free audio dma channels!\n");
- return err;
-}
-
-/*
- * This function should calculate the current position of the dma in the
- * buffer. It will help alsa middle layer to continue update the buffer.
- * Its correctness is crucial for good functioning.
- */
-static u_int audio_get_dma_pos(struct audio_stream *s)
-{
- struct snd_pcm_substream *substream = s->stream;
- struct snd_pcm_runtime *runtime = substream->runtime;
- unsigned int offset;
- unsigned long flags;
- dma_addr_t count;
- ADEBUG();
-
- /* this must be called w/ interrupts locked as requested in dma.c */
- spin_lock_irqsave(&s->dma_lock, flags);
-
- /* For the current period let's see where we are */
- count = omap_get_dma_src_pos(s->lch[s->dma_q_head]) - dma_start_pos;
-
- spin_unlock_irqrestore(&s->dma_lock, flags);
-
- /* Now, the position related to the end of that period */
- offset = bytes_to_frames(runtime, s->offset) -
- bytes_to_frames(runtime, count);
-
- if (offset >= runtime->buffer_size)
- offset = 0;
-
- return offset;
-}
-
-/*
- * this stops the dma and clears the dma ptrs
- */
-static void audio_stop_dma(struct audio_stream *s)
-{
- unsigned long flags;
- ADEBUG();
-
- spin_lock_irqsave(&s->dma_lock, flags);
- s->active = 0;
- s->period = 0;
- s->periods = 0;
-
- /* this stops the dma channel and clears the buffer ptrs */
- omap_stop_alsa_sound_dma(s);
-
- omap_clear_alsa_sound_dma(s);
-
- spin_unlock_irqrestore(&s->dma_lock, flags);
-}
-
-/*
- * Main dma routine, requests dma according where you are in main alsa buffer
- */
-static void audio_process_dma(struct audio_stream *s)
-{
- struct snd_pcm_substream *substream = s->stream;
- struct snd_pcm_runtime *runtime;
- unsigned int dma_size;
- unsigned int offset;
- int ret;
-
- ADEBUG();
- runtime = substream->runtime;
- if (s->active) {
- dma_size = frames_to_bytes(runtime, runtime->period_size);
- offset = dma_size * s->period;
- snd_assert(dma_size <= DMA_BUF_SIZE, return);
- /*
- * On omap1510 based devices, we need to call the stop_dma
- * before calling the start_dma or we will not receive the
- * irq from DMA after the first transfered/played buffer.
- * (invocation of callback_omap_alsa_sound_dma() method).
- */
- if (cpu_is_omap1510())
- omap_stop_alsa_sound_dma(s);
-
- dma_start_pos = (dma_addr_t)runtime->dma_area + offset;
- ret = omap_start_alsa_sound_dma(s, dma_start_pos, dma_size);
- if (ret) {
- printk(KERN_ERR "audio_process_dma: cannot"
- " queue DMA buffer (%i)\n", ret);
- return;
- }
-
- s->period++;
- s->period %= runtime->periods;
- s->periods++;
- s->offset = offset;
- }
-}
-
-/*
- * This is called when dma IRQ occurs at the end of each transmited block
- */
-void callback_omap_alsa_sound_dma(void *data)
-{
- struct audio_stream *s = data;
-
- ADEBUG();
- /*
- * If we are getting a callback for an active stream then we inform
- * the PCM middle layer we've finished a period
- */
- if (s->active)
- snd_pcm_period_elapsed(s->stream);
-
- spin_lock(&s->dma_lock);
- if (s->periods > 0)
- s->periods--;
-
- audio_process_dma(s);
- spin_unlock(&s->dma_lock);
-}
-
-/*
- * Alsa section
- * PCM settings and callbacks
- */
-static int snd_omap_alsa_trigger(struct snd_pcm_substream *substream, int cmd)
-{
- struct snd_card_omap_codec *chip =
- snd_pcm_substream_chip(substream);
- int stream_id = substream->pstr->stream;
- struct audio_stream *s = &chip->s[stream_id];
- int err = 0;
-
- ADEBUG();
- /* note local interrupts are already disabled in the midlevel code */
- spin_lock(&s->dma_lock);
- switch (cmd) {
- case SNDRV_PCM_TRIGGER_START:
- /* requested stream startup */
- s->active = 1;
- audio_process_dma(s);
- break;
- case SNDRV_PCM_TRIGGER_STOP:
- /* requested stream shutdown */
- audio_stop_dma(s);
- break;
- default:
- err = -EINVAL;
- break;
- }
- spin_unlock(&s->dma_lock);
-
- return err;
-}
-
-static int snd_omap_alsa_prepare(struct snd_pcm_substream *substream)
-{
- struct snd_card_omap_codec *chip = snd_pcm_substream_chip(substream);
- struct snd_pcm_runtime *runtime = substream->runtime;
- struct audio_stream *s = &chip->s[substream->pstr->stream];
-
- ADEBUG();
- /* set requested samplerate */
- alsa_codec_config->codec_set_samplerate(runtime->rate);
- chip->samplerate = runtime->rate;
-
- s->period = 0;
- s->periods = 0;
-
- return 0;
-}
-
-static snd_pcm_uframes_t
-snd_omap_alsa_pointer(struct snd_pcm_substream *substream)
-{
- struct snd_card_omap_codec *chip = snd_pcm_substream_chip(substream);
-
- ADEBUG();
- return audio_get_dma_pos(&chip->s[substream->pstr->stream]);
-}
-
-static int snd_card_omap_alsa_open(struct snd_pcm_substream *substream)
-{
- struct snd_card_omap_codec *chip =
- snd_pcm_substream_chip(substream);
- struct snd_pcm_runtime *runtime = substream->runtime;
- int stream_id = substream->pstr->stream;
- int err;
-
- ADEBUG();
- chip->s[stream_id].stream = substream;
- alsa_codec_config->codec_clock_on();
- if (stream_id == SNDRV_PCM_STREAM_PLAYBACK)
- runtime->hw = *(alsa_codec_config->snd_omap_alsa_playback);
- else
- runtime->hw = *(alsa_codec_config->snd_omap_alsa_capture);
-
- err = snd_pcm_hw_constraint_integer(runtime,
- SNDRV_PCM_HW_PARAM_PERIODS);
- if (err < 0)
- return err;
-
- err = snd_pcm_hw_constraint_list(runtime, 0, SNDRV_PCM_HW_PARAM_RATE,
- alsa_codec_config->hw_constraints_rates);
- if (err < 0)
- return err;
-
- return 0;
-}
-
-static int snd_card_omap_alsa_close(struct snd_pcm_substream *substream)
-{
- struct snd_card_omap_codec *chip = snd_pcm_substream_chip(substream);
-
- ADEBUG();
- alsa_codec_config->codec_clock_off();
- chip->s[substream->pstr->stream].stream = NULL;
-
- return 0;
-}
-
-/* HW params & free */
-static int snd_omap_alsa_hw_params(struct snd_pcm_substream *substream,
- struct snd_pcm_hw_params *hw_params)
-{
- return snd_pcm_lib_malloc_pages(substream,
- params_buffer_bytes(hw_params));
-}
-
-static int snd_omap_alsa_hw_free(struct snd_pcm_substream *substream)
-{
- return snd_pcm_lib_free_pages(substream);
-}
-
-/* pcm operations */
-static struct snd_pcm_ops snd_card_omap_alsa_playback_ops = {
- .open = snd_card_omap_alsa_open,
- .close = snd_card_omap_alsa_close,
- .ioctl = snd_pcm_lib_ioctl,
- .hw_params = snd_omap_alsa_hw_params,
- .hw_free = snd_omap_alsa_hw_free,
- .prepare = snd_omap_alsa_prepare,
- .trigger = snd_omap_alsa_trigger,
- .pointer = snd_omap_alsa_pointer,
-};
-
-static struct snd_pcm_ops snd_card_omap_alsa_capture_ops = {
- .open = snd_card_omap_alsa_open,
- .close = snd_card_omap_alsa_close,
- .ioctl = snd_pcm_lib_ioctl,
- .hw_params = snd_omap_alsa_hw_params,
- .hw_free = snd_omap_alsa_hw_free,
- .prepare = snd_omap_alsa_prepare,
- .trigger = snd_omap_alsa_trigger,
- .pointer = snd_omap_alsa_pointer,
-};
-
-/*
- * Alsa init and exit section
- * Inits pcm alsa structures, allocate the alsa buffer, suspend, resume
- */
-static int __init snd_card_omap_alsa_pcm(struct snd_card_omap_codec *omap_alsa,
- int device)
-{
- struct snd_pcm *pcm;
- int err;
-
- ADEBUG();
- err = snd_pcm_new(omap_alsa->card, "OMAP PCM", device, 1, 1, &pcm);
- if (err < 0)
- return err;
-
- /* sets up initial buffer with continuous allocation */
- snd_pcm_lib_preallocate_pages_for_all(pcm,
- SNDRV_DMA_TYPE_CONTINUOUS,
- snd_dma_continuous_data
- (GFP_KERNEL),
- 128 * 1024, 128 * 1024);
-
- snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK,
- &snd_card_omap_alsa_playback_ops);
- snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE,
- &snd_card_omap_alsa_capture_ops);
- pcm->private_data = omap_alsa;
- pcm->info_flags = 0;
- strcpy(pcm->name, "omap alsa pcm");
-
- omap_alsa_audio_init(omap_alsa);
-
- /* setup DMA controller */
- audio_dma_request(&omap_alsa->s[SNDRV_PCM_STREAM_PLAYBACK],
- callback_omap_alsa_sound_dma);
- audio_dma_request(&omap_alsa->s[SNDRV_PCM_STREAM_CAPTURE],
- callback_omap_alsa_sound_dma);
-
- omap_alsa->pcm = pcm;
-
- return 0;
-}
-
-
-#ifdef CONFIG_PM
-/*
- * Driver suspend/resume - calls alsa functions. Some hints from aaci.c
- */
-int snd_omap_alsa_suspend(struct platform_device *pdev, pm_message_t state)
-{
- struct snd_card_omap_codec *chip;
- struct snd_card *card = platform_get_drvdata(pdev);
-
- if (card->power_state != SNDRV_CTL_POWER_D3hot) {
- chip = card->private_data;
- if (chip->card->power_state != SNDRV_CTL_POWER_D3hot) {
- snd_power_change_state(chip->card,
- SNDRV_CTL_POWER_D3hot);
- snd_pcm_suspend_all(chip->pcm);
- /* Mutes and turn clock off */
- alsa_codec_config->codec_clock_off();
- snd_omap_suspend_mixer();
- }
- }
- return 0;
-}
-
-int snd_omap_alsa_resume(struct platform_device *pdev)
-{
- struct snd_card_omap_codec *chip;
- struct snd_card *card = platform_get_drvdata(pdev);
-
- if (card->power_state != SNDRV_CTL_POWER_D0) {
- chip = card->private_data;
- if (chip->card->power_state != SNDRV_CTL_POWER_D0) {
- snd_power_change_state(chip->card, SNDRV_CTL_POWER_D0);
- alsa_codec_config->codec_clock_on();
- snd_omap_resume_mixer();
- }
- }
- return 0;
-}
-
-#endif /* CONFIG_PM */
-
-void snd_omap_alsa_free(struct snd_card *card)
-{
- struct snd_card_omap_codec *chip = card->private_data;
- ADEBUG();
-
- /*
- * Turn off codec after it is done.
- * Can't do it immediately, since it may still have
- * buffered data.
- */
- schedule_timeout_interruptible(2);
-
- omap_mcbsp_stop(AUDIO_MCBSP);
- omap_mcbsp_free(AUDIO_MCBSP);
-
- audio_dma_free(&chip->s[SNDRV_PCM_STREAM_PLAYBACK]);
- audio_dma_free(&chip->s[SNDRV_PCM_STREAM_CAPTURE]);
-}
-
-/* module init & exit */
-
-/*
- * Inits alsa soudcard structure.
- * Called by the probe method in codec after function pointers has been set.
- */
-int snd_omap_alsa_post_probe(struct platform_device *pdev,
- struct omap_alsa_codec_config *config)
-{
- int err = 0;
- int def_rate;
- struct snd_card *card;
-
- ADEBUG();
- alsa_codec_config = config;
-
- alsa_codec_config->codec_clock_setup();
- alsa_codec_config->codec_clock_on();
-
- omap_mcbsp_request(AUDIO_MCBSP);
- omap_mcbsp_stop(AUDIO_MCBSP);
- omap_mcbsp_config(AUDIO_MCBSP, alsa_codec_config->mcbsp_regs_alsa);
- omap_mcbsp_start(AUDIO_MCBSP);
-
- if (alsa_codec_config && alsa_codec_config->codec_configure_dev)
- alsa_codec_config->codec_configure_dev();
-
- alsa_codec_config->codec_clock_off();
-
- /* register the soundcard */
- card = snd_card_new(-1, id, THIS_MODULE, sizeof(alsa_codec));
- if (card == NULL)
- goto nodev1;
-
- alsa_codec = kcalloc(1, sizeof(*alsa_codec), GFP_KERNEL);
- if (alsa_codec == NULL)
- goto nodev2;
-
- card->private_data = (void *)alsa_codec;
- card->private_free = snd_omap_alsa_free;
-
- alsa_codec->card = card;
- def_rate = alsa_codec_config->get_default_samplerate();
- alsa_codec->samplerate = def_rate;
-
- spin_lock_init(&alsa_codec->s[0].dma_lock);
- spin_lock_init(&alsa_codec->s[1].dma_lock);
-
- /* mixer */
- err = snd_omap_mixer(alsa_codec);
- if (err < 0)
- goto nodev3;
-
- /* PCM */
- err = snd_card_omap_alsa_pcm(alsa_codec, 0);
- if (err < 0)
- goto nodev3;
-
- strcpy(card->driver, "OMAP_ALSA");
- strcpy(card->shortname, alsa_codec_config->name);
- sprintf(card->longname, alsa_codec_config->name);
-
- snd_omap_init_mixer();
- snd_card_set_dev(card, &pdev->dev);
-
- err = snd_card_register(card);
- if (err == 0) {
- printk(KERN_INFO "audio support initialized\n");
- platform_set_drvdata(pdev, card);
- return 0;
- }
-
-nodev3:
- kfree(alsa_codec);
-nodev2:
- snd_card_free(card);
-nodev1:
- omap_mcbsp_stop(AUDIO_MCBSP);
- omap_mcbsp_free(AUDIO_MCBSP);
-
- return err;
-}
-
-int snd_omap_alsa_remove(struct platform_device *pdev)
-{
- struct snd_card *card = platform_get_drvdata(pdev);
- struct snd_card_omap_codec *chip = card->private_data;
-
- snd_card_free(card);
-
- alsa_codec = NULL;
- card->private_data = NULL;
- kfree(chip);
-
- platform_set_drvdata(pdev, NULL);
-
- return 0;
-}
obj-$(CONFIG_SOUND_OSS) += sound.o
-obj-$(CONFIG_SOUND_OMAP) += omap-audio-dma-intfc.o omap-audio.o
-obj-$(CONFIG_SOUND_OMAP_TSC2101)+= omap-audio-tsc2101.o
-obj-$(CONFIG_SOUND_OMAP_AIC23) += omap-audio-aic23.o
-
# Please leave it as is, cause the link order is significant !
obj-$(CONFIG_SOUND_SH_DAC_AUDIO) += sh_dac_audio.o
+++ /dev/null
-/*
- * linux/sound/oss/omap-audio-aic23.c
- *
- * Glue audio driver for TI TLV320AIC23 codec
- *
- * Copyright (c) 2000 Nicolas Pitre <nico@cam.org>
- * Copyright (C) 2001, Steve Johnson <stevej@ridgerun.com>
- * Copyright (C) 2004 Texas Instruments, Inc.
- * Copyright (C) 2005 Dirk Behme <dirk.behme@de.bosch.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.
- *
- * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
- * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN
- * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
- * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
- * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
- * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
- * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
- * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- * 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.
- */
-
-#include <linux/module.h>
-#include <linux/init.h>
-#include <linux/types.h>
-#include <linux/delay.h>
-#include <linux/pm.h>
-#include <linux/errno.h>
-#include <linux/sound.h>
-#include <linux/soundcard.h>
-#include <linux/clk.h>
-#include <linux/mutex.h>
-
-#include <asm/uaccess.h>
-#include <mach/hardware.h>
-#include <asm/io.h>
-#include <asm/mach-types.h>
-
-#include <mach/mcbsp.h>
-#include <mach/fpga.h>
-#include <mach/aic23.h>
-#include <mach/clock.h>
-
-#include "omap-audio.h"
-#include "omap-audio-dma-intfc.h"
-
-#ifdef CONFIG_PROC_FS
-#include <linux/proc_fs.h>
-#define PROC_START_FILE "driver/aic23-audio-start"
-#define PROC_STOP_FILE "driver/aic23-audio-stop"
-#endif
-
-//#define DEBUG
-
-#ifdef DEBUG
-#define DPRINTK(ARGS...) printk("<%s>: ",__FUNCTION__);printk(ARGS)
-#else
-#define DPRINTK( x... )
-#endif
-
-#define CODEC_NAME "AIC23"
-
-#if CONFIG_MACH_OMAP_OSK
-#define PLATFORM_NAME "OMAP OSK"
-#elif CONFIG_MACH_OMAP_INNOVATOR
-#define PLATFORM_NAME "OMAP INNOVATOR"
-#else
-#error "Unsupported plattform"
-#endif
-
-/* Define to set the AIC23 as the master w.r.t McBSP */
-#define AIC23_MASTER
-
-#define CODEC_CLOCK 12000000
-
-/*
- * AUDIO related MACROS
- */
-#define DEFAULT_BITPERSAMPLE 16
-#define AUDIO_RATE_DEFAULT 44100
-
-/* Select the McBSP For Audio */
-#define AUDIO_MCBSP OMAP_MCBSP1
-
-#define REC_MASK (SOUND_MASK_LINE | SOUND_MASK_MIC)
-#define DEV_MASK (REC_MASK | SOUND_MASK_VOLUME)
-
-#define SET_VOLUME 1
-#define SET_LINE 2
-
-#define DEFAULT_OUTPUT_VOLUME 93
-#define DEFAULT_INPUT_VOLUME 0 /* 0 ==> mute line in */
-
-#define OUTPUT_VOLUME_MIN LHV_MIN
-#define OUTPUT_VOLUME_MAX LHV_MAX
-#define OUTPUT_VOLUME_RANGE (OUTPUT_VOLUME_MAX - OUTPUT_VOLUME_MIN)
-#define OUTPUT_VOLUME_MASK OUTPUT_VOLUME_MAX
-
-#define INPUT_VOLUME_MIN LIV_MIN
-#define INPUT_VOLUME_MAX LIV_MAX
-#define INPUT_VOLUME_RANGE (INPUT_VOLUME_MAX - INPUT_VOLUME_MIN)
-#define INPUT_VOLUME_MASK INPUT_VOLUME_MAX
-
-#define NUMBER_SAMPLE_RATES_SUPPORTED 9
-
-/*
- * HW interface start and stop helper functions
- */
-static int audio_ifc_start(void)
-{
- omap_mcbsp_start(AUDIO_MCBSP);
- return 0;
-}
-
-static int audio_ifc_stop(void)
-{
- omap_mcbsp_stop(AUDIO_MCBSP);
- return 0;
-}
-
-static audio_stream_t output_stream = {
- .id = "AIC23 out",
- .dma_dev = OMAP_DMA_MCBSP1_TX,
- .input_or_output = FMODE_WRITE,
- .hw_start = audio_ifc_start,
- .hw_stop = audio_ifc_stop
-};
-
-static audio_stream_t input_stream = {
- .id = "AIC23 in",
- .dma_dev = OMAP_DMA_MCBSP1_RX,
- .input_or_output = FMODE_READ,
- .hw_start = audio_ifc_start,
- .hw_stop = audio_ifc_stop
-};
-
-static struct clk *aic23_mclk = 0;
-
-static int audio_dev_id, mixer_dev_id;
-
-static struct aic23_local_info {
- u8 volume;
- u16 volume_reg;
- u8 line;
- u8 mic;
- u16 input_volume_reg;
- int mod_cnt;
-} aic23_local;
-
-struct sample_rate_reg_info {
- u32 sample_rate;
- u8 control; /* SR3, SR2, SR1, SR0 and BOSR */
- u8 divider; /* if 0 CLKIN = MCLK, if 1 CLKIN = MCLK/2 */
-};
-
-/* To Store the default sample rate */
-static long audio_samplerate = AUDIO_RATE_DEFAULT;
-
-/* DAC USB-mode sampling rates (MCLK = 12 MHz) */
-static const struct sample_rate_reg_info
-reg_info[NUMBER_SAMPLE_RATES_SUPPORTED] = {
- {96000, 0x0E, 0},
- {88200, 0x1F, 0},
- {48000, 0x00, 0},
- {44100, 0x11, 0},
- {32000, 0x0C, 0},
- {24000, 0x00, 1},
- {16000, 0x0C, 1},
- { 8000, 0x06, 0},
- { 4000, 0x06, 1},
-};
-
-static struct omap_mcbsp_reg_cfg initial_config = {
- .spcr2 = FREE | FRST | GRST | XRST | XINTM(3),
- .spcr1 = RINTM(3) | RRST,
- .rcr2 = RPHASE | RFRLEN2(OMAP_MCBSP_WORD_8) |
- RWDLEN2(OMAP_MCBSP_WORD_16) | RDATDLY(0),
- .rcr1 = RFRLEN1(OMAP_MCBSP_WORD_8) | RWDLEN1(OMAP_MCBSP_WORD_16),
- .xcr2 = XPHASE | XFRLEN2(OMAP_MCBSP_WORD_8) |
- XWDLEN2(OMAP_MCBSP_WORD_16) | XDATDLY(0) | XFIG,
- .xcr1 = XFRLEN1(OMAP_MCBSP_WORD_8) | XWDLEN1(OMAP_MCBSP_WORD_16),
- .srgr1 = FWID(DEFAULT_BITPERSAMPLE - 1),
- .srgr2 = GSYNC | CLKSP | FSGM | FPER(DEFAULT_BITPERSAMPLE * 2 - 1),
-#ifndef AIC23_MASTER
- /* configure McBSP to be the I2S master */
- .pcr0 = FSXM | FSRM | CLKXM | CLKRM | CLKXP | CLKRP,
-#else
- /* configure McBSP to be the I2S slave */
- .pcr0 = CLKXP | CLKRP,
-#endif /* AIC23_MASTER */
-};
-
-static void omap_aic23_initialize(void *dummy);
-static void omap_aic23_shutdown(void *dummy);
-static int omap_aic23_ioctl(struct inode *inode, struct file *file,
- uint cmd, ulong arg);
-static int omap_aic23_probe(void);
-#ifdef MODULE
-static void omap_aic23_remove(void);
-#endif
-static int omap_aic23_suspend(void);
-static int omap_aic23_resume(void);
-static inline void aic23_configure(void);
-static int mixer_open(struct inode *inode, struct file *file);
-static int mixer_release(struct inode *inode, struct file *file);
-static int mixer_ioctl(struct inode *inode, struct file *file, uint cmd,
- ulong arg);
-
-#ifdef CONFIG_PROC_FS
-static int codec_start(char *buf, char **start, off_t offset, int count,
- int *eof, void *data);
-static int codec_stop(char *buf, char **start, off_t offset, int count,
- int *eof, void *data);
-#endif
-
-
-/* File Op structure for mixer */
-static struct file_operations omap_mixer_fops = {
- .open = mixer_open,
- .release = mixer_release,
- .ioctl = mixer_ioctl,
- .owner = THIS_MODULE
-};
-
-/* To store characteristic info regarding the codec for the audio driver */
-static audio_state_t aic23_state = {
- .output_stream = &output_stream,
- .input_stream = &input_stream,
-/* .need_tx_for_rx = 1, //Once the Full Duplex works */
- .need_tx_for_rx = 0,
- .hw_init = omap_aic23_initialize,
- .hw_shutdown = omap_aic23_shutdown,
- .client_ioctl = omap_aic23_ioctl,
- .hw_probe = omap_aic23_probe,
- .hw_remove = __exit_p(omap_aic23_remove),
- .hw_suspend = omap_aic23_suspend,
- .hw_resume = omap_aic23_resume,
-};
-
-/* This will be defined in the audio.h */
-static struct file_operations *omap_audio_fops;
-
-extern int aic23_write_value(u8 reg, u16 value);
-
-/* TLV320AIC23 is a write only device */
-static __inline__ void audio_aic23_write(u8 address, u16 data)
-{
- aic23_write_value(address, data);
-}
-
-static int aic23_update(int flag, int val)
-{
- u16 volume;
-
- /* Ignore separate left/right channel for now,
- even the codec does support it. */
- val &= 0xff;
-
- if (val < 0 || val > 100) {
- printk(KERN_ERR "Trying a bad volume value(%d)!\n",val);
- return -EPERM;
- }
-
- switch (flag) {
- case SET_VOLUME:
- // Convert 0 -> 100 volume to 0x00 (LHV_MIN) -> 0x7f (LHV_MAX)
- // volume range
- volume = ((val * OUTPUT_VOLUME_RANGE) / 100) + OUTPUT_VOLUME_MIN;
-
- // R/LHV[6:0] 1111111 (+6dB) to 0000000 (-73dB) in 1db steps,
- // default 1111001 (0dB)
- aic23_local.volume_reg &= ~OUTPUT_VOLUME_MASK;
- aic23_local.volume_reg |= volume;
- audio_aic23_write(LEFT_CHANNEL_VOLUME_ADDR, aic23_local.volume_reg);
- audio_aic23_write(RIGHT_CHANNEL_VOLUME_ADDR, aic23_local.volume_reg);
- break;
-
- case SET_LINE:
- // Convert 0 -> 100 volume to 0x0 (LIV_MIN) -> 0x1f (LIV_MAX)
- // volume range
- volume = ((val * INPUT_VOLUME_RANGE) / 100) + INPUT_VOLUME_MIN;
-
- // R/LIV[4:0] 11111 (+12dB) to 00000 (-34.5dB) in 1.5dB steps,
- // default 10111 (0dB)
- aic23_local.input_volume_reg &= ~INPUT_VOLUME_MASK;
- aic23_local.input_volume_reg |= volume;
- audio_aic23_write(LEFT_LINE_VOLUME_ADDR, aic23_local.input_volume_reg);
- audio_aic23_write(RIGHT_LINE_VOLUME_ADDR, aic23_local.input_volume_reg);
- break;
- }
- return 0;
-}
-
-static int mixer_open(struct inode *inode, struct file *file)
-{
- /* Any mixer specific initialization */
-
- return 0;
-}
-
-static int mixer_release(struct inode *inode, struct file *file)
-{
- /* Any mixer specific Un-initialization */
-
- return 0;
-}
-
-static int
-mixer_ioctl(struct inode *inode, struct file *file, uint cmd, ulong arg)
-{
- int val;
- int ret = 0;
- int nr = _IOC_NR(cmd);
-
- /*
- * We only accept mixer (type 'M') ioctls.
- */
- if (_IOC_TYPE(cmd) != 'M')
- return -EINVAL;
-
- DPRINTK(" 0x%08x\n", cmd);
-
- if (cmd == SOUND_MIXER_INFO) {
- struct mixer_info mi;
-
- strncpy(mi.id, "AIC23", sizeof(mi.id));
- strncpy(mi.name, "TI AIC23", sizeof(mi.name));
- mi.modify_counter = aic23_local.mod_cnt;
- return copy_to_user((void *)arg, &mi, sizeof(mi));
- }
-
- if (_IOC_DIR(cmd) & _IOC_WRITE) {
- ret = get_user(val, (int *)arg);
- if (ret)
- goto out;
-
-
- switch (nr) {
- case SOUND_MIXER_VOLUME:
- aic23_local.volume = val;
- aic23_local.mod_cnt++;
- ret = aic23_update(SET_VOLUME, val);
- break;
-
- case SOUND_MIXER_LINE:
- aic23_local.line = val;
- aic23_local.mod_cnt++;
- ret = aic23_update(SET_LINE, val);
- break;
-
- case SOUND_MIXER_MIC:
- aic23_local.mic = val;
- aic23_local.mod_cnt++;
- ret = aic23_update(SET_LINE, val);
- break;
-
- case SOUND_MIXER_RECSRC:
- break;
-
- default:
- ret = -EINVAL;
- }
- }
-
- if (ret == 0 && _IOC_DIR(cmd) & _IOC_READ) {
- ret = 0;
-
- switch (nr) {
- case SOUND_MIXER_VOLUME:
- val = aic23_local.volume;
- break;
- case SOUND_MIXER_LINE:
- val = aic23_local.line;
- break;
- case SOUND_MIXER_MIC:
- val = aic23_local.mic;
- break;
- case SOUND_MIXER_RECSRC:
- val = REC_MASK;
- break;
- case SOUND_MIXER_RECMASK:
- val = REC_MASK;
- break;
- case SOUND_MIXER_DEVMASK:
- val = DEV_MASK;
- break;
- case SOUND_MIXER_CAPS:
- val = 0;
- break;
- case SOUND_MIXER_STEREODEVS:
- val = 0;
- break;
- default:
- val = 0;
- ret = -EINVAL;
- break;
- }
-
- if (ret == 0)
- ret = put_user(val, (int *)arg);
- }
-out:
- return ret;
-
-}
-
-int omap_set_samplerate(long sample_rate)
-{
- u8 count = 0;
- u16 data = 0;
- /* wait for any frame to complete */
- udelay(125);
-
- /* Search for the right sample rate */
- while ((reg_info[count].sample_rate != sample_rate) &&
- (count < NUMBER_SAMPLE_RATES_SUPPORTED)) {
- count++;
- }
- if (count == NUMBER_SAMPLE_RATES_SUPPORTED) {
- printk(KERN_ERR "Invalid Sample Rate %d requested\n",
- (int)sample_rate);
- return -EPERM;
- }
-
- if (machine_is_omap_innovator()) {
- /* set the CODEC clock input source to 12.000MHz */
- fpga_write(fpga_read(OMAP1510_FPGA_POWER) & ~0x01,
- OMAP1510_FPGA_POWER);
- }
-
- data = (reg_info[count].divider << CLKIN_SHIFT) |
- (reg_info[count].control << BOSR_SHIFT) | USB_CLK_ON;
-
- audio_aic23_write(SAMPLE_RATE_CONTROL_ADDR, data);
-
- audio_samplerate = sample_rate;
-
-#ifndef AIC23_MASTER
- {
- int clkgdv = 0;
- /*
- Set Sample Rate at McBSP
-
- Formula :
- Codec System Clock = CODEC_CLOCK, or half if clock_divider = 1;
- clkgdv = ((Codec System Clock / (SampleRate * BitsPerSample * 2)) - 1);
-
- FWID = BitsPerSample - 1;
- FPER = (BitsPerSample * 2) - 1;
- */
- if (reg_info[count].divider)
- clkgdv = CODEC_CLOCK / 2;
- else
- clkgdv = CODEC_CLOCK;
-
- clkgdv = (clkgdv / (sample_rate * DEFAULT_BITPERSAMPLE * 2)) - 1;
-
- initial_config.srgr1 = (FWID(DEFAULT_BITPERSAMPLE - 1) | CLKGDV(clkgdv));
-
- initial_config.srgr2 =
- (CLKSM | FSGM | FPER(DEFAULT_BITPERSAMPLE * 2 - 1));
-
- omap_mcbsp_config(AUDIO_MCBSP, &initial_config);
- }
-#endif /* AIC23_MASTER */
-
- return 0;
-}
-
-static void omap_aic23_initialize(void *dummy)
-{
- DPRINTK("entry\n");
-
- /* initialize with default sample rate */
- audio_samplerate = AUDIO_RATE_DEFAULT;
-
- omap_mcbsp_request(AUDIO_MCBSP);
-
- /* if configured, then stop mcbsp */
- omap_mcbsp_stop(AUDIO_MCBSP);
-
- omap_mcbsp_config(AUDIO_MCBSP, &initial_config);
- omap_mcbsp_start(AUDIO_MCBSP);
- aic23_configure();
-
- DPRINTK("exit\n");
-}
-
-static void omap_aic23_shutdown(void *dummy)
-{
- /*
- Turn off codec after it is done.
- Can't do it immediately, since it may still have
- buffered data.
-
- Wait 20ms (arbitrary value) and then turn it off.
- */
-
- set_current_state(TASK_INTERRUPTIBLE);
- schedule_timeout(2);
-
- omap_mcbsp_stop(AUDIO_MCBSP);
- omap_mcbsp_free(AUDIO_MCBSP);
-
- audio_aic23_write(RESET_CONTROL_ADDR, 0);
- audio_aic23_write(POWER_DOWN_CONTROL_ADDR, 0xff);
-}
-
-static inline void aic23_configure()
-{
- /* Reset codec */
- audio_aic23_write(RESET_CONTROL_ADDR, 0);
-
- /* Initialize the AIC23 internal state */
-
- /* Left/Right line input volume control */
- aic23_local.line = DEFAULT_INPUT_VOLUME;
- aic23_local.mic = DEFAULT_INPUT_VOLUME;
- aic23_update(SET_LINE, DEFAULT_INPUT_VOLUME);
-
- /* Left/Right headphone channel volume control */
- /* Zero-cross detect on */
- aic23_local.volume_reg = LZC_ON;
- aic23_update(SET_VOLUME, aic23_local.volume);
-
- /* Analog audio path control, DAC selected, delete INSEL_MIC for line in */
- audio_aic23_write(ANALOG_AUDIO_CONTROL_ADDR, DAC_SELECTED | INSEL_MIC);
-
- /* Digital audio path control, de-emphasis control 44.1kHz */
- audio_aic23_write(DIGITAL_AUDIO_CONTROL_ADDR, DEEMP_44K);
-
- /* Power control, everything is on */
- audio_aic23_write(POWER_DOWN_CONTROL_ADDR, 0);
-
- /* Digital audio interface, master/slave mode, I2S, 16 bit */
-#ifdef AIC23_MASTER
- audio_aic23_write(DIGITAL_AUDIO_FORMAT_ADDR, MS_MASTER | IWL_16 | FOR_DSP);
-#else
- audio_aic23_write(DIGITAL_AUDIO_FORMAT_ADDR, IWL_16 | FOR_DSP);
-#endif /* AIC23_MASTER */
-
- /* Enable digital interface */
- audio_aic23_write(DIGITAL_INTERFACE_ACT_ADDR, ACT_ON);
-
- /* clock configuration */
- omap_set_samplerate(audio_samplerate);
-}
-
-static int
-omap_aic23_ioctl(struct inode *inode, struct file *file, uint cmd, ulong arg)
-{
- long val;
- int ret = 0;
-
- DPRINTK(" 0x%08x\n", cmd);
-
- /*
- * These are platform dependent ioctls which are not handled by the
- * generic omap-audio module.
- */
- switch (cmd) {
- case SNDCTL_DSP_STEREO:
- ret = get_user(val, (int *)arg);
- if (ret)
- return ret;
- /* the AIC23 is stereo only */
- ret = (val == 0) ? -EINVAL : 1;
- return put_user(ret, (int *)arg);
-
- case SNDCTL_DSP_CHANNELS:
- case SOUND_PCM_READ_CHANNELS:
- /* the AIC23 is stereo only */
- return put_user(2, (long *)arg);
-
- case SNDCTL_DSP_SPEED:
- ret = get_user(val, (long *)arg);
- if (ret)
- break;
- ret = omap_set_samplerate(val);
- if (ret)
- break;
- /* fall through */
-
- case SOUND_PCM_READ_RATE:
- return put_user(audio_samplerate, (long *)arg);
-
- case SOUND_PCM_READ_BITS:
- case SNDCTL_DSP_SETFMT:
- case SNDCTL_DSP_GETFMTS:
- /* we can do 16-bit only */
- return put_user(AFMT_S16_LE, (long *)arg);
-
- default:
- /* Maybe this is meant for the mixer (As per OSS Docs) */
- return mixer_ioctl(inode, file, cmd, arg);
- }
-
- return ret;
-}
-
-static int omap_aic23_probe(void)
-{
- /* Get the fops from audio oss driver */
- if (!(omap_audio_fops = audio_get_fops())) {
- printk(KERN_ERR "Unable to get the file operations for AIC23 OSS driver\n");
- audio_unregister_codec(&aic23_state);
- return -EPERM;
- }
-
- aic23_local.volume = DEFAULT_OUTPUT_VOLUME;
-
- /* register devices */
- audio_dev_id = register_sound_dsp(omap_audio_fops, -1);
- mixer_dev_id = register_sound_mixer(&omap_mixer_fops, -1);
-
-#ifdef CONFIG_PROC_FS
- create_proc_read_entry(PROC_START_FILE, 0 /* default mode */ ,
- NULL /* parent dir */ ,
- codec_start, NULL /* client data */ );
-
- create_proc_read_entry(PROC_STOP_FILE, 0 /* default mode */ ,
- NULL /* parent dir */ ,
- codec_stop, NULL /* client data */ );
-#endif
-
- /* Announcement Time */
- printk(KERN_INFO PLATFORM_NAME " " CODEC_NAME
- " audio support initialized\n");
- return 0;
-}
-
-#ifdef MODULE
-static void __exit omap_aic23_remove(void)
-{
- /* Un-Register the codec with the audio driver */
- unregister_sound_dsp(audio_dev_id);
- unregister_sound_mixer(mixer_dev_id);
-
-#ifdef CONFIG_PROC_FS
- remove_proc_entry(PROC_START_FILE, NULL);
- remove_proc_entry(PROC_STOP_FILE, NULL);
-#endif
-}
-#endif /* MODULE */
-
-static int omap_aic23_suspend(void)
-{
- /* Empty for the moment */
- return 0;
-}
-
-static int omap_aic23_resume(void)
-{
- /* Empty for the moment */
- return 0;
-}
-
-static int __init audio_aic23_init(void)
-{
-
- int err = 0;
-
- if (machine_is_omap_h2() || machine_is_omap_h3())
- return -ENODEV;
-
- mutex_init(&aic23_state.mutex);
-
- if (machine_is_omap_osk()) {
- /* Set MCLK to be clock input for AIC23 */
- aic23_mclk = clk_get(0, "mclk");
-
- if(clk_get_rate( aic23_mclk) != CODEC_CLOCK){
- /* MCLK ist not at CODEC_CLOCK */
- if( clk_get_usecount(aic23_mclk) > 0 ){
- /* MCLK is already in use */
- printk(KERN_WARNING "MCLK in use at %d Hz. We change it to %d Hz\n",
- (uint)clk_get_rate( aic23_mclk), CODEC_CLOCK);
- }
- if( clk_set_rate( aic23_mclk, CODEC_CLOCK ) ){
- printk(KERN_ERR "Cannot set MCLK for AIC23 CODEC\n");
- return -ECANCELED;
- }
- }
-
- clk_enable( aic23_mclk );
-
- DPRINTK("MCLK = %d [%d], usecount = %d\n",(uint)clk_get_rate( aic23_mclk ),
- CODEC_CLOCK, clk_get_usecount( aic23_mclk));
- }
-
- if (machine_is_omap_innovator()) {
- u8 fpga;
- /*
- Turn on chip select for CODEC (shared with touchscreen).
- Don't turn it back off, in case touch screen needs it.
- */
- fpga = fpga_read(OMAP1510_FPGA_TOUCHSCREEN);
- fpga |= 0x4;
- fpga_write(fpga, OMAP1510_FPGA_TOUCHSCREEN);
- }
-
- /* register the codec with the audio driver */
- if ((err = audio_register_codec(&aic23_state))) {
- printk(KERN_ERR
- "Failed to register AIC23 driver with Audio OSS Driver\n");
- }
-
- return err;
-}
-
-static void __exit audio_aic23_exit(void)
-{
- (void)audio_unregister_codec(&aic23_state);
- return;
-}
-
-#ifdef CONFIG_PROC_FS
-static int codec_start(char *buf, char **start, off_t offset, int count,
- int *eof, void *data)
-{
- void *foo = NULL;
-
- omap_aic23_initialize(foo);
-
- printk("AIC23 codec initialization done.\n");
- return 0;
-}
-static int codec_stop(char *buf, char **start, off_t offset, int count,
- int *eof, void *data)
-{
- void *foo = NULL;
-
- omap_aic23_shutdown(foo);
-
- printk("AIC23 codec shutdown.\n");
- return 0;
-}
-#endif /* CONFIG_PROC_FS */
-
-module_init(audio_aic23_init);
-module_exit(audio_aic23_exit);
-
-MODULE_AUTHOR("Dirk Behme <dirk.behme@de.bosch.com>");
-MODULE_DESCRIPTION("Glue audio driver for the TI AIC23 codec.");
-MODULE_LICENSE("GPL");
+++ /dev/null
-/*
- * linux/sound/oss/omap-audio-dma-intfc.c
- *
- * Common audio DMA handling for the OMAP processors
- *
- * Copyright (C) 2004 Texas Instruments, Inc.
- *
- * Copyright (C) 2000, 2001 Nicolas Pitre <nico@cam.org>
- *
- * This package is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * THIS PACKAGE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
- * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
- * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
- *
- * History:
- *
- * 2004-06-07 Sriram Kannan - Created new file from omap_audio_dma_intfc.c. This file
- * will contain only the DMA interface and buffer handling of OMAP
- * audio driver.
- *
- * 2004-06-22 Sriram Kannan - removed legacy code (auto-init). Self-linking of DMA logical channel.
- *
- * 2004-08-12 Nishanth Menon - Modified to integrate Audio requirements on 1610,1710 platforms
- *
- * 2004-11-01 Nishanth Menon - 16xx platform code base modified to support multi channel chaining.
- *
- * 2004-12-15 Nishanth Menon - Improved 16xx platform channel logic introduced - tasklets, queue handling updated
- *
- * 2005-12-10 Dirk Behme - Added L/R Channel Interchange fix as proposed by Ajaya Babu
- */
-
-#include <linux/module.h>
-#include <linux/init.h>
-#include <linux/types.h>
-#include <linux/fs.h>
-#include <linux/mm.h>
-#include <linux/slab.h>
-#include <linux/sched.h>
-#include <linux/poll.h>
-#include <linux/pm.h>
-#include <linux/errno.h>
-#include <linux/sound.h>
-#include <linux/soundcard.h>
-#include <linux/sysrq.h>
-#include <linux/interrupt.h>
-#include <linux/dma-mapping.h>
-#include <linux/completion.h>
-
-#include <asm/uaccess.h>
-#include <asm/io.h>
-#include <mach/hardware.h>
-#include <asm/semaphore.h>
-
-#include <mach/dma.h>
-#include "omap-audio-dma-intfc.h"
-
-#include <mach/mcbsp.h>
-
-#include "omap-audio.h"
-
-#undef DEBUG
-//#define DEBUG
-#ifdef DEBUG
-#define DPRINTK(ARGS...) printk(KERN_INFO "<%s>: ",__FUNCTION__);printk(ARGS)
-#define FN_IN printk(KERN_INFO "[%s]: start\n", __FUNCTION__)
-#define FN_OUT(n) printk(KERN_INFO "[%s]: end(%u)\n",__FUNCTION__, n)
-#else
-
-#define DPRINTK( x... )
-#define FN_IN
-#define FN_OUT(x)
-#endif
-
-#define ERR(ARGS...) printk(KERN_ERR "{%s}-ERROR: ", __FUNCTION__);printk(ARGS);
-
-#define AUDIO_NAME "omap-audio"
-#define AUDIO_NBFRAGS_DEFAULT 8
-#define AUDIO_FRAGSIZE_DEFAULT 8192
-
-#define AUDIO_ACTIVE(state) ((state)->rd_ref || (state)->wr_ref)
-
-#define SPIN_ADDR (dma_addr_t)0
-#define SPIN_SIZE 2048
-
-/* Channel Queue Handling macros
- * tail always points to the current free entry
- * Head always points to the current entry being used
- * end is either head or tail
- */
-
-#define AUDIO_QUEUE_INIT(s) s->dma_q_head = s->dma_q_tail = s->dma_q_count = 0;
-#define AUDIO_QUEUE_FULL(s) (nr_linked_channels == s->dma_q_count)
-#define AUDIO_QUEUE_LAST(s) (1 == s->dma_q_count)
-#define AUDIO_QUEUE_EMPTY(s) (0 == s->dma_q_count)
-#define __AUDIO_INCREMENT_QUEUE(end) ((end)=((end)+1) % nr_linked_channels)
-#define AUDIO_INCREMENT_HEAD(s) __AUDIO_INCREMENT_QUEUE(s->dma_q_head); s->dma_q_count--;
-#define AUDIO_INCREMENT_TAIL(s) __AUDIO_INCREMENT_QUEUE(s->dma_q_tail); s->dma_q_count++;
-
-/* DMA buffer fragmentation sizes */
-#define MAX_DMA_SIZE 0x1000000
-#define CUT_DMA_SIZE 0x1000
-/* TODO: To be moved to more appropriate location */
-#define DCSR_ERROR 0x3
-#define DCSR_SYNC_SET (1 << 6)
-
-#define DCCR_FS (1 << 5)
-#define DCCR_PRIO (1 << 6)
-#define DCCR_AI (1 << 8)
-#define DCCR_REPEAT (1 << 9)
-/* if 0 the channel works in 3.1 compatible mode*/
-#define DCCR_N31COMP (1 << 10)
-#define DCCR_EP (1 << 11)
-#define DCCR_SRC_AMODE_BIT 12
-#define DCCR_SRC_AMODE_MASK (0x3<<12)
-#define DCCR_DST_AMODE_BIT 14
-#define DCCR_DST_AMODE_MASK (0x3<<14)
-#define AMODE_CONST 0x0
-#define AMODE_POST_INC 0x1
-#define AMODE_SINGLE_INDEX 0x2
-#define AMODE_DOUBLE_INDEX 0x3
-
-/**************************** DATA STRUCTURES *****************************************/
-
-static spinlock_t dma_list_lock = SPIN_LOCK_UNLOCKED;
-
-struct audio_isr_work_item {
- int current_lch;
- u16 ch_status;
- audio_stream_t *s;
-};
-
-static char work_item_running = 0;
-static char nr_linked_channels = 1;
-static struct audio_isr_work_item work1, work2;
-
-
-/*********************************** MODULE SPECIFIC FUNCTIONS PROTOTYPES *************/
-
-static void audio_dsr_handler(unsigned long);
-static DECLARE_TASKLET(audio_isr_work1, audio_dsr_handler,
- (unsigned long)&work1);
-static DECLARE_TASKLET(audio_isr_work2, audio_dsr_handler,
- (unsigned long)&work2);
-
-static void sound_dma_irq_handler(int lch, u16 ch_status, void *data);
-static void audio_dma_callback(int lch, u16 ch_status, void *data);
-static int omap_start_sound_dma(audio_stream_t * s, dma_addr_t dma_ptr,
- u_int size);
-static int audio_set_dma_params_play(int channel, dma_addr_t dma_ptr,
- u_int dma_size);
-static int audio_set_dma_params_capture(int channel, dma_addr_t dma_ptr,
- u_int dma_size);
-static int audio_start_dma_chain(audio_stream_t * s);
-
-/*********************************** GLOBAL FUNCTIONS DEFINTIONS ***********************/
-
-/***************************************************************************************
- *
- * Buffer creation/destruction
- *
- **************************************************************************************/
-int audio_setup_buf(audio_stream_t * s)
-{
- int frag;
- int dmasize = 0;
- char *dmabuf = NULL;
- dma_addr_t dmaphys = 0;
- FN_IN;
- if (s->buffers) {
- FN_OUT(1);
- return -EBUSY;
- }
- s->buffers = kmalloc(sizeof(audio_buf_t) * s->nbfrags, GFP_KERNEL);
- if (!s->buffers)
- goto err;
- memset(s->buffers, 0, sizeof(audio_buf_t) * s->nbfrags);
- for (frag = 0; frag < s->nbfrags; frag++) {
- audio_buf_t *b = &s->buffers[frag];
- /*
- * Let's allocate non-cached memory for DMA buffers.
- * We try to allocate all memory at once.
- * If this fails (a common reason is memory fragmentation),
- * then we allocate more smaller buffers.
- */
- if (!dmasize) {
- dmasize = (s->nbfrags - frag) * s->fragsize;
- do {
- dmabuf =
- dma_alloc_coherent(NULL, dmasize, &dmaphys,
- 0);
- if (!dmabuf)
- dmasize -= s->fragsize;
- }
- while (!dmabuf && dmasize);
- if (!dmabuf)
- goto err;
- b->master = dmasize;
- memzero(dmabuf, dmasize);
- }
- b->data = dmabuf;
- b->dma_addr = dmaphys;
- dmabuf += s->fragsize;
- dmaphys += s->fragsize;
- dmasize -= s->fragsize;
- }
- s->usr_head = s->dma_head = s->dma_tail = 0;
- AUDIO_QUEUE_INIT(s);
- s->started = 0;
- s->bytecount = 0;
- s->fragcount = 0;
- init_completion(&s->wfc);
- s->wfc.done = s->nbfrags;
- FN_OUT(0);
- return 0;
- err:
- audio_discard_buf(s);
- FN_OUT(1);
- return -ENOMEM;
-}
-
-void audio_discard_buf(audio_stream_t * s)
-{
- FN_IN;
- /* ensure DMA isn't using those buffers */
- audio_reset(s);
- if (s->buffers) {
- int frag;
- for (frag = 0; frag < s->nbfrags; frag++) {
- if (!s->buffers[frag].master)
- continue;
- dma_free_coherent(NULL,
- s->buffers[frag].master,
- s->buffers[frag].data,
- s->buffers[frag].dma_addr);
- }
- kfree(s->buffers);
- s->buffers = NULL;
- }
- FN_OUT(0);
-}
-
-/***************************************************************************************
- *
- * DMA channel requests
- *
- **************************************************************************************/
-static void omap_sound_dma_link_lch(void *data)
-{
- audio_stream_t *s = (audio_stream_t *) data;
- int *chan = s->lch;
- int i;
-
- FN_IN;
- if (s->linked) {
- FN_OUT(1);
- return;
- }
- for (i = 0; i < nr_linked_channels; i++) {
- int cur_chan = chan[i];
- int nex_chan =
- ((nr_linked_channels - 1 ==
- i) ? chan[0] : chan[i + 1]);
- omap_dma_link_lch(cur_chan, nex_chan);
- }
- s->linked = 1;
- FN_OUT(0);
-}
-
-int
-omap_request_sound_dma(int device_id, const char *device_name, void *data,
- int **channels)
-{
- int i, err = 0;
- int *chan = NULL;
- FN_IN;
- if (unlikely((NULL == channels) || (NULL == device_name))) {
- BUG();
- return -EPERM;
- }
- /* Try allocate memory for the num channels */
- *channels =
- (int *)kmalloc(sizeof(int) * nr_linked_channels,
- GFP_KERNEL);
- chan = *channels;
- if (NULL == chan) {
- ERR("No Memory for channel allocs!\n");
- FN_OUT(-ENOMEM);
- return -ENOMEM;
- }
- spin_lock(&dma_list_lock);
- for (i = 0; i < nr_linked_channels; i++) {
- err =
- omap_request_dma(device_id, device_name,
- sound_dma_irq_handler, data, &chan[i]);
- /* Handle Failure condition here */
- if (err < 0) {
- int j;
- for (j = 0; j < i; j++) {
- omap_free_dma(chan[j]);
- }
- spin_unlock(&dma_list_lock);
- kfree(chan);
- *channels = NULL;
- ERR("Error in requesting channel %d=0x%x\n", i, err);
- FN_OUT(err);
- return err;
- }
- }
-
- /* Chain the channels together */
- if (!cpu_is_omap15xx())
- omap_sound_dma_link_lch(data);
-
- spin_unlock(&dma_list_lock);
- FN_OUT(0);
- return 0;
-}
-
-/***************************************************************************************
- *
- * DMA channel requests Freeing
- *
- **************************************************************************************/
-static void omap_sound_dma_unlink_lch(void *data)
-{
- audio_stream_t *s = (audio_stream_t *) data;
- int *chan = s->lch;
- int i;
-
- FN_IN;
- if (!s->linked) {
- FN_OUT(1);
- return;
- }
- for (i = 0; i < nr_linked_channels; i++) {
- int cur_chan = chan[i];
- int nex_chan =
- ((nr_linked_channels - 1 ==
- i) ? chan[0] : chan[i + 1]);
- omap_dma_unlink_lch(cur_chan, nex_chan);
- }
- s->linked = 0;
- FN_OUT(0);
-}
-
-int omap_free_sound_dma(void *data, int **channels)
-{
- int i;
- int *chan = NULL;
- FN_IN;
- if (unlikely(NULL == channels)) {
- BUG();
- return -EPERM;
- }
- if (unlikely(NULL == *channels)) {
- BUG();
- return -EPERM;
- }
- chan = (*channels);
-
- if (!cpu_is_omap15xx())
- omap_sound_dma_unlink_lch(data);
- for (i = 0; i < nr_linked_channels; i++) {
- int cur_chan = chan[i];
- omap_stop_dma(cur_chan);
- omap_free_dma(cur_chan);
- }
- kfree(*channels);
- *channels = NULL;
- FN_OUT(0);
- return 0;
-}
-
-/***************************************************************************************
- *
- * Process DMA requests - This will end up starting the transfer. Proper fragments of
- * Transfers will be initiated.
- *
- **************************************************************************************/
-int audio_process_dma(audio_stream_t * s)
-{
- int ret = 0;
- unsigned long flags;
- FN_IN;
-
- /* Dont let the ISR over ride touching the in_use flag */
- local_irq_save(flags);
- if (1 == s->in_use) {
- local_irq_restore(flags);
- ERR("Called again while In Use\n");
- return 0;
- }
- s->in_use = 1;
- local_irq_restore(flags);
-
- if (s->stopped)
- goto spin;
-
- if (s->dma_spinref > 0 && s->pending_frags) {
- s->dma_spinref = 0;
- DMA_CLEAR(s);
- }
- while (s->pending_frags) {
- audio_buf_t *b = &s->buffers[s->dma_head];
- u_int dma_size = s->fragsize - b->offset;
- if (dma_size > MAX_DMA_SIZE)
- dma_size = CUT_DMA_SIZE;
- ret =
- omap_start_sound_dma(s, b->dma_addr + b->offset, dma_size);
- if (ret) {
- goto process_out;
- }
- b->dma_ref++;
- b->offset += dma_size;
- if (b->offset >= s->fragsize) {
- s->pending_frags--;
- if (++s->dma_head >= s->nbfrags)
- s->dma_head = 0;
- }
- }
- spin:
- if (s->spin_idle) {
- int spincnt = 0;
- ERR("we are spinning\n");
- while (omap_start_sound_dma(s, SPIN_ADDR, SPIN_SIZE) == 0)
- spincnt++;
- /*
- * Note: if there is still a data buffer being
- * processed then the ref count is negative. This
- * allows for the DMA termination to be accounted in
- * the proper order. Of course dma_spinref can't be
- * greater than 0 if dma_ref is not 0 since we kill
- * the spinning above as soon as there is real data to process.
- */
- if (s->buffers && s->buffers[s->dma_tail].dma_ref)
- spincnt = -spincnt;
- s->dma_spinref += spincnt;
- }
-
- process_out:
- s->in_use = 0;
-
- FN_OUT(ret);
- return ret;
-}
-
-/***************************************************************************************
- *
- * Prime Rx - Since the recieve buffer has no time limit as to when it would arrive,
- * we need to prime it
- *
- **************************************************************************************/
-void audio_prime_rx(audio_state_t * state)
-{
- audio_stream_t *is = state->input_stream;
-
- FN_IN;
- if (state->need_tx_for_rx) {
- /*
- * With some codecs like the Philips UDA1341 we must ensure
- * there is an output stream at any time while recording since
- * this is how the UDA1341 gets its clock from the SA1100.
- * So while there is no playback data to send, the output DMA
- * will spin with all zeroes. We use the cache flush special
- * area for that.
- */
- state->output_stream->spin_idle = 1;
- audio_process_dma(state->output_stream);
- }
- is->pending_frags = is->nbfrags;
- init_completion(&is->wfc);
- is->wfc.done = 0;
-
- is->active = 1;
- audio_process_dma(is);
-
- FN_OUT(0);
- return;
-}
-
-/***************************************************************************************
- *
- * set the fragment size
- *
- **************************************************************************************/
-int audio_set_fragments(audio_stream_t * s, int val)
-{
- FN_IN;
- if (s->active)
- return -EBUSY;
- if (s->buffers)
- audio_discard_buf(s);
- s->nbfrags = (val >> 16) & 0x7FFF;
- val &= 0xFFFF;
- if (val < 4)
- val = 4;
- if (val > 15)
- val = 15;
- s->fragsize = 1 << val;
- if (s->nbfrags < 2)
- s->nbfrags = 2;
- if (s->nbfrags * s->fragsize > 128 * 1024)
- s->nbfrags = 128 * 1024 / s->fragsize;
- FN_OUT(0);
- if (audio_setup_buf(s))
- return -ENOMEM;
- return val | (s->nbfrags << 16);
-
-}
-
-/***************************************************************************************
- *
- * Sync up the buffers before we shutdown, else under-run errors will happen
- *
- **************************************************************************************/
-int audio_sync(struct file *file)
-{
- audio_state_t *state = file->private_data;
- audio_stream_t *s = state->output_stream;
- audio_buf_t *b;
- u_int shiftval = 0;
- unsigned long flags;
-
- DECLARE_WAITQUEUE(wait, current);
-
- FN_IN;
-
- if (!(file->f_mode & FMODE_WRITE) || !s->buffers || s->mapped) {
- FN_OUT(1);
- return 0;
- }
-
- /*
- * Send current buffer if it contains data. Be sure to send
- * a full sample count.
- */
- b = &s->buffers[s->usr_head];
- if (b->offset &= ~3) {
- /* Wait for a buffer to become free */
- if (wait_for_completion_interruptible(&s->wfc))
- return 0;
- /*
- * HACK ALERT !
- * To avoid increased complexity in the rest of the code
- * where full fragment sizes are assumed, we cheat a little
- * with the start pointer here and don't forget to restore
- * it later.
- */
-
- /* As this is a last frag we need only one dma channel
- * to complete. So it's need to unlink dma channels
- * to avoid empty dma work.
- */
- if (!cpu_is_omap15xx() && AUDIO_QUEUE_EMPTY(s))
- omap_sound_dma_unlink_lch(s);
-
- shiftval = s->fragsize - b->offset;
- b->offset = shiftval;
- b->dma_addr -= shiftval;
- b->data -= shiftval;
- local_irq_save(flags);
- s->bytecount -= shiftval;
- if (++s->usr_head >= s->nbfrags)
- s->usr_head = 0;
-
- s->pending_frags++;
- audio_process_dma(s);
- local_irq_restore(flags);
- }
-
- /* Let's wait for all buffers to complete */
- set_current_state(TASK_INTERRUPTIBLE);
- add_wait_queue(&s->wq, &wait);
- while ((s->pending_frags || (s->wfc.done < s->nbfrags))
- && !signal_pending(current)) {
- schedule();
- set_current_state(TASK_INTERRUPTIBLE);
- }
- set_current_state(TASK_RUNNING);
- remove_wait_queue(&s->wq, &wait);
-
- /* undo the pointer hack above */
- if (shiftval) {
- local_irq_save(flags);
- b->dma_addr += shiftval;
- b->data += shiftval;
- /* ensure sane DMA code behavior if not yet processed */
- if (b->offset != 0)
- b->offset = s->fragsize;
- local_irq_restore(flags);
- }
-
- FN_OUT(0);
- return 0;
-}
-
-/***************************************************************************************
- *
- * Stop all the DMA channels of the stream
- *
- **************************************************************************************/
-void audio_stop_dma(audio_stream_t * s)
-{
- int *chan = s->lch;
- int i;
- FN_IN;
- if (unlikely(NULL == chan)) {
- BUG();
- return;
- }
- for (i = 0; i < nr_linked_channels; i++) {
- int cur_chan = chan[i];
- omap_stop_dma(cur_chan);
- }
- s->started = 0;
- FN_OUT(0);
- return;
-}
-
-/***************************************************************************************
- *
- * Get the dma posn
- *
- **************************************************************************************/
-u_int audio_get_dma_pos(audio_stream_t * s)
-{
- audio_buf_t *b = &s->buffers[s->dma_tail];
- u_int offset;
-
- FN_IN;
- if (b->dma_ref) {
- offset = omap_get_dma_src_pos(s->lch[s->dma_q_head]) - b->dma_addr;
- if (offset >= s->fragsize)
- offset = s->fragsize - 4;
- } else if (s->pending_frags) {
- offset = b->offset;
- } else {
- offset = 0;
- }
- FN_OUT(offset);
- return offset;
-}
-
-/***************************************************************************************
- *
- * Reset the audio buffers
- *
- **************************************************************************************/
-void audio_reset(audio_stream_t * s)
-{
- FN_IN;
- if (s->buffers) {
- audio_stop_dma(s);
- s->buffers[s->dma_head].offset = 0;
- s->buffers[s->usr_head].offset = 0;
- s->usr_head = s->dma_head;
- s->pending_frags = 0;
- init_completion(&s->wfc);
- s->wfc.done = s->nbfrags;
- }
- s->active = 0;
- s->stopped = 0;
- s->started = 0;
- FN_OUT(0);
- return;
-}
-
-/***************************************************************************************
- *
- * Clear any pending transfers
- *
- **************************************************************************************/
-void omap_clear_sound_dma(audio_stream_t * s)
-{
- FN_IN;
- omap_clear_dma(s->lch[s->dma_q_head]);
- FN_OUT(0);
- return;
-}
-
-/***************************************************************************************
- *
- * DMA related functions
- *
- **************************************************************************************/
-static int audio_set_dma_params_play(int channel, dma_addr_t dma_ptr,
- u_int dma_size)
-{
- int dt = 0x1; /* data type 16 */
- int cen = 32; /* Stereo */
- int cfn = dma_size / (2 * cen);
- unsigned long dest_start;
- int dest_port = 0;
- int sync_dev = 0;
-
- FN_IN;
-
- if (cpu_is_omap15xx() || cpu_is_omap16xx()) {
- dest_start = AUDIO_MCBSP_DATAWRITE;
- dest_port = OMAP_DMA_PORT_MPUI;
- }
- if (cpu_is_omap24xx()) {
- dest_start = AUDIO_MCBSP_DATAWRITE;
- sync_dev = AUDIO_DMA_TX;
- }
-
- omap_set_dma_dest_params(channel, dest_port, OMAP_DMA_AMODE_CONSTANT, dest_start, 0, 0);
- omap_set_dma_src_params(channel, 0, OMAP_DMA_AMODE_POST_INC, dma_ptr, 0, 0);
- omap_set_dma_transfer_params(channel, dt, cen, cfn, OMAP_DMA_SYNC_ELEMENT, sync_dev, 0);
-
- FN_OUT(0);
- return 0;
-}
-
-static int audio_set_dma_params_capture(int channel, dma_addr_t dma_ptr,
- u_int dma_size)
-{
- int dt = 0x1; /* data type 16 */
- int cen = 16; /* mono */
- int cfn = dma_size / (2 * cen);
- unsigned long src_start;
- int src_port = 0;
- int sync_dev = 0;
- int src_sync = 0;
-
- FN_IN;
-
- if (cpu_is_omap15xx() || cpu_is_omap16xx()) {
- src_start = AUDIO_MCBSP_DATAREAD;
- src_port = OMAP_DMA_PORT_MPUI;
- }
- if (cpu_is_omap24xx()) {
- src_start = AUDIO_MCBSP_DATAREAD;
- sync_dev = AUDIO_DMA_RX;
- src_sync = 1;
- }
-
- omap_set_dma_src_params(channel, src_port, OMAP_DMA_AMODE_CONSTANT, src_start, 0, 0);
- omap_set_dma_dest_params(channel, 0, OMAP_DMA_AMODE_POST_INC, dma_ptr, 0, 0);
- omap_set_dma_transfer_params(channel, dt, cen, cfn, OMAP_DMA_SYNC_ELEMENT, sync_dev, src_sync);
-
- FN_OUT(0);
- return 0;
-}
-
-static int audio_start_dma_chain(audio_stream_t * s)
-{
- int channel = s->lch[s->dma_q_head];
- FN_IN;
- if (!s->started) {
- s->hw_stop(); /* stops McBSP Interface */
- omap_start_dma(channel);
- s->started = 1;
- s->hw_start(); /* start McBSP interface */
- }
- /* else the dma itself will progress forward with out our help */
- FN_OUT(0);
- return 0;
-}
-
-/* Start DMA -
- * Do the initial set of work to initialize all the channels as required.
- * We shall then initate a transfer
- */
-static int omap_start_sound_dma(audio_stream_t * s, dma_addr_t dma_ptr,
- u_int dma_size)
-{
- int ret = -EPERM;
-
- FN_IN;
- if (unlikely(dma_size > MAX_DMA_SIZE)) {
- ERR("DmaSoundDma: Start: overflowed %d-%d\n", dma_size,
- MAX_DMA_SIZE);
- return -EOVERFLOW;
- }
-
- if (AUDIO_QUEUE_FULL(s)) {
- ret = -2;
- goto sound_out;
- }
-
- if (s->input_or_output == FMODE_WRITE)
- /*playback */
- {
- ret =
- audio_set_dma_params_play(s->lch[s->dma_q_tail], dma_ptr,
- dma_size);
- } else {
- ret =
- audio_set_dma_params_capture(s->lch[s->dma_q_tail], dma_ptr,
- dma_size);
- }
- if (ret != 0) {
- ret = -2; /* indicate queue full */
- goto sound_out;
- }
- AUDIO_INCREMENT_TAIL(s);
- ret = audio_start_dma_chain(s);
- if (ret) {
- ERR("dma start failed");
- }
- sound_out:
- FN_OUT(ret);
- return ret;
-
-}
-
-/***************************************************************************************
- *
- * ISR related functions
- *
- **************************************************************************************/
-/* The work item handler */
-static void audio_dsr_handler(unsigned long inData)
-{
- void *data = (void *)inData;
- struct audio_isr_work_item *work = data;
- audio_stream_t *s = (work->s);
- int sound_curr_lch = work->current_lch;
- u16 ch_status = work->ch_status;
-
- FN_IN;
- DPRINTK("lch=%d,status=0x%x, data=%p as=%p\n", sound_curr_lch,
- ch_status, data, s);
- if (AUDIO_QUEUE_EMPTY(s)) {
- ERR("Interrupt(%d) for empty queue(h=%d, T=%d)???\n",
- sound_curr_lch, s->dma_q_head, s->dma_q_tail);
- ERR("nbfrag=%d,pendfrags=%d,USR-H=%d, QH-%d QT-%d\n",
- s->nbfrags, s->pending_frags, s->usr_head, s->dma_head,
- s->dma_tail);
- FN_OUT(-1);
- return;
- }
-
- AUDIO_INCREMENT_HEAD(s); /* Empty the queue */
-
- /* Try to fill again */
- audio_dma_callback(sound_curr_lch, ch_status, s);
- FN_OUT(0);
-
-}
-
-/* Macro to trace the IRQ calls - checks for multi-channel irqs */
-//#define IRQ_TRACE
-#ifdef IRQ_TRACE
-#define MAX_UP 10
-static char xyz[MAX_UP] = { 0 };
-static int h = 0;
-#endif
-
-/* ISRs have to be short and smart.. So we transfer every heavy duty stuff to the
- * work item
- */
-static void sound_dma_irq_handler(int sound_curr_lch, u16 ch_status, void *data)
-{
- int dma_status = ch_status;
- audio_stream_t *s = (audio_stream_t *) data;
- FN_IN;
-#ifdef IRQ_TRACE
- xyz[h++] = '0' + sound_curr_lch;
- if (h == MAX_UP - 1) {
- printk("%s-", xyz);
- h = 0;
- }
-#endif
- DPRINTK("lch=%d,status=0x%x, dma_status=%d, data=%p\n", sound_curr_lch,
- ch_status, dma_status, data);
-
- if (dma_status & (DCSR_ERROR)) {
- if (cpu_is_omap15xx() || cpu_is_omap16xx())
- omap_stop_dma(sound_curr_lch);
- ERR("DCSR_ERROR!\n");
- FN_OUT(-1);
- return;
- }
-
- if (AUDIO_QUEUE_LAST(s))
- audio_stop_dma(s);
-
- /* Start the work item - we ping pong the work items */
- if (!work_item_running) {
- work1.current_lch = sound_curr_lch;
- work1.ch_status = ch_status;
- work1.s = s;
- /* schedule tasklet 1 */
- tasklet_schedule(&audio_isr_work1);
- work_item_running = 1;
- } else {
- work2.current_lch = sound_curr_lch;
- work2.ch_status = ch_status;
- work2.s = s;
- /* schedule tasklet 2 */
- tasklet_schedule(&audio_isr_work2);
- work_item_running = 0;
- }
- FN_OUT(0);
- return;
-}
-
-/* The call back that handles buffer stuff */
-static void audio_dma_callback(int lch, u16 ch_status, void *data)
-{
- audio_stream_t *s = data;
- audio_buf_t *b = &s->buffers[s->dma_tail];
- FN_IN;
-
- if (s->dma_spinref > 0) {
- s->dma_spinref--;
- } else if (!s->buffers) {
- printk(KERN_CRIT
- "omap_audio: received DMA IRQ for non existent buffers!\n");
- return;
- } else if (b->dma_ref && --b->dma_ref == 0 && b->offset >= s->fragsize) {
- /* This fragment is done */
- b->offset = 0;
- s->bytecount += s->fragsize;
- s->fragcount++;
- s->dma_spinref = -s->dma_spinref;
-
- if (++s->dma_tail >= s->nbfrags)
- s->dma_tail = 0;
-
- if (!s->mapped)
- complete(&s->wfc);
- else
- s->pending_frags++;
-
- wake_up(&s->wq);
- }
-
- audio_process_dma(s);
-
- FN_OUT(0);
- return;
-}
-
-/*********************************************************************************
- *
- * audio_get_dma_callback(): return the dma interface call back function
- *
- *********************************************************************************/
-dma_callback_t audio_get_dma_callback(void)
-{
- FN_IN;
- FN_OUT(0);
- return audio_dma_callback;
-}
-
-static int __init audio_dma_init(void)
-{
- if (!cpu_is_omap15xx())
- nr_linked_channels = 2;
-
- return 0;
-}
-
-static void __exit audio_dma_exit(void)
-{
- /* Nothing */
-}
-
-module_init(audio_dma_init);
-module_exit(audio_dma_exit);
-
-MODULE_AUTHOR("Texas Instruments");
-MODULE_DESCRIPTION("Common DMA handling for Audio driver on OMAP processors");
-MODULE_LICENSE("GPL");
-
-EXPORT_SYMBOL(omap_clear_sound_dma);
-EXPORT_SYMBOL(omap_request_sound_dma);
-EXPORT_SYMBOL(omap_free_sound_dma);
-
-EXPORT_SYMBOL(audio_get_dma_callback);
-EXPORT_SYMBOL(audio_setup_buf);
-EXPORT_SYMBOL(audio_process_dma);
-EXPORT_SYMBOL(audio_prime_rx);
-EXPORT_SYMBOL(audio_set_fragments);
-EXPORT_SYMBOL(audio_sync);
-EXPORT_SYMBOL(audio_stop_dma);
-EXPORT_SYMBOL(audio_get_dma_pos);
-EXPORT_SYMBOL(audio_reset);
-EXPORT_SYMBOL(audio_discard_buf);
+++ /dev/null
-/*
- * linux/sound/oss/omap-audio-dma-intfc.h
- *
- * Common audio DMA handling for the OMAP processors
- *
- * Copyright (C) 2004 Texas Instruments, Inc.
- *
- * Copyright (C) 2000, 2001 Nicolas Pitre <nico@cam.org>
- *
- * This package is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * THIS PACKAGE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
- * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
- * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
- *
- * History:
- *
- * 2004/08/12 Nishanth Menon - Modified to integrate Audio requirements on 1610,1710 platforms
- */
-
-#ifndef __OMAP_AUDIO_DMA_INTFC_H
-#define __OMAP_AUDIO_DMA_INTFC_H
-
-/************************** INCLUDES *************************************/
-
-/* Requires omap-audio.h */
-#include "omap-audio.h"
-
-/************************** GLOBAL MACROS *************************************/
-
-/* Provide the Macro interfaces common across platforms */
-#define DMA_REQUEST(e,s, cb) {e=omap_request_sound_dma(s->dma_dev, s->id, s, &s->lch);}
-#define DMA_FREE(s) omap_free_sound_dma(s, &s->lch)
-#define DMA_CLEAR(s) omap_clear_sound_dma(s)
-
-/************************** GLOBAL DATA STRUCTURES *********************************/
-
-typedef void (*dma_callback_t) (int lch, u16 ch_status, void *data);
-
-/************************** GLOBAL FUNCTIONS ***************************************/
-
-dma_callback_t audio_get_dma_callback(void);
-int audio_setup_buf(audio_stream_t * s);
-int audio_process_dma(audio_stream_t * s);
-void audio_prime_rx(audio_state_t * state);
-int audio_set_fragments(audio_stream_t * s, int val);
-int audio_sync(struct file *file);
-void audio_stop_dma(audio_stream_t * s);
-u_int audio_get_dma_pos(audio_stream_t * s);
-void audio_reset(audio_stream_t * s);
-void audio_discard_buf(audio_stream_t * s);
-
-/**************** ARCH SPECIFIC FUNCIONS *******************************************/
-
-void omap_clear_sound_dma(audio_stream_t * s);
-
-int omap_request_sound_dma(int device_id, const char *device_name, void *data,
- int **channels);
-int omap_free_sound_dma(void *data, int **channels);
-
-#endif /* #ifndef __OMAP_AUDIO_DMA_INTFC_H */
+++ /dev/null
-/*
- * linux/sound/oss/omap-audio-tsc2101.c
- *
- * Glue driver for TSC2101 for OMAP processors
- *
- * Copyright (C) 2004 Texas Instruments, Inc.
- *
- * This package is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * THIS PACKAGE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
- * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
- * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
- *
- * History:
- * -------
- * 2004-08-12 Nishanth Menon - Modified to integrate Audio requirements on 1610,1710 platforms.
- * 2004-09-14 Sriram Kannan - Added /proc support for asynchronous starting/stopping the codec
- * (without affecting the normal driver flow).
- * 2004-11-04 Nishanth Menon - Support for power management
- * 2004-11-07 Nishanth Menon - Support for Common TSC access b/w Touchscreen and audio drivers
- */
-
-/***************************** INCLUDES ************************************/
-
-#include <linux/module.h>
-#include <linux/init.h>
-#include <linux/types.h>
-#include <linux/fs.h>
-#include <linux/delay.h>
-#include <linux/pm.h>
-#include <linux/errno.h>
-#include <linux/sound.h>
-#include <linux/soundcard.h>
-#include <linux/mutex.h>
-
-#include <asm/uaccess.h>
-#include <mach/hardware.h>
-#include <mach/dma.h>
-#include <asm/io.h>
-
-#include <mach/mux.h>
-#include <mach/io.h>
-#include <asm/mach-types.h>
-
-#include "omap-audio.h"
-#include "omap-audio-dma-intfc.h"
-#include <mach/mcbsp.h>
-#ifdef CONFIG_ARCH_OMAP16XX
-#include <../drivers/ssi/omap-uwire.h>
-#include <mach/dsp_common.h>
-#elif defined(CONFIG_ARCH_OMAP24XX)
-#else
-#error "Unsupported configuration"
-#endif
-
-#include <asm/hardware/tsc2101.h>
-#include <../drivers/ssi/omap-tsc2101.h>
-
-/***************************** MACROS ************************************/
-
-#define PROC_SUPPORT
-
-#ifdef PROC_SUPPORT
-#include <linux/proc_fs.h>
-#define PROC_START_FILE "driver/tsc2101-audio-start"
-#define PROC_STOP_FILE "driver/tsc2101-audio-stop"
-#endif
-
-#define CODEC_NAME "TSC2101"
-
-#ifdef CONFIG_ARCH_OMAP16XX
-#define PLATFORM_NAME "OMAP16XX"
-#elif defined(CONFIG_ARCH_OMAP24XX)
-#define PLATFORM_NAME "OMAP2"
-#endif
-
-/* Define to set the tsc as the master w.r.t McBSP */
-#define TSC_MASTER
-
-/*
- * AUDIO related MACROS
- */
-#define DEFAULT_BITPERSAMPLE 16
-#define AUDIO_RATE_DEFAULT 44100
-#define PAGE2_AUDIO_CODEC_REGISTERS (2)
-#define LEAVE_CS 0x80
-
-/* Select the McBSP For Audio */
-/* 16XX is MCBSP1 and 24XX is MCBSP2*/
-/* see include/asm-arm/arch-omap/mcbsp.h */
-#ifndef AUDIO_MCBSP
-#error "UnSupported Configuration"
-#endif
-
-#define REC_MASK (SOUND_MASK_LINE | SOUND_MASK_MIC)
-#define DEV_MASK (REC_MASK | SOUND_MASK_VOLUME)
-
-#define SET_VOLUME 1
-#define SET_LINE 2
-#define SET_MIC 3
-#define SET_RECSRC 4
-
-#define DEFAULT_VOLUME 93
-#define DEFAULT_INPUT_VOLUME 20 /* An minimal volume */
-
-/* Tsc Audio Specific */
-#define NUMBER_SAMPLE_RATES_SUPPORTED 16
-#define OUTPUT_VOLUME_MIN 0x7F
-#define OUTPUT_VOLUME_MAX 0x32
-#define OUTPUT_VOLUME_RANGE (OUTPUT_VOLUME_MIN - OUTPUT_VOLUME_MAX)
-#define OUTPUT_VOLUME_MASK OUTPUT_VOLUME_MIN
-#define DEFAULT_VOLUME_LEVEL OUTPUT_VOLUME_MAX
-
-/* use input vol of 75 for 0dB gain */
-#define INPUT_VOLUME_MIN 0x0
-#define INPUT_VOLUME_MAX 0x7D
-#define INPUT_VOLUME_RANGE (INPUT_VOLUME_MAX - INPUT_VOLUME_MIN)
-#define INPUT_VOLUME_MASK INPUT_VOLUME_MAX
-
-/*********** Debug Macros ********/
-/* To Generate a rather shrill tone -test the entire path */
-//#define TONE_GEN
-/* To Generate a tone for each keyclick - test the tsc,spi paths*/
-//#define TEST_KEYCLICK
-/* To dump the tsc registers for debug */
-//#define TSC_DUMP_REGISTERS
-
-#ifdef DPRINTK
-#undef DPRINTK
-#endif
-#undef DEBUG
-
-//#define DEBUG
-#ifdef DEBUG
-#define DPRINTK(ARGS...) printk(KERN_INFO "<%s>: ",__FUNCTION__);printk(ARGS)
-#define FN_IN printk(KERN_INFO "[%s]: start\n", __FUNCTION__)
-#define FN_OUT(n) printk(KERN_INFO "[%s]: end(%u)\n",__FUNCTION__, n)
-#else
-#define DPRINTK( x... )
-#define FN_IN
-#define FN_OUT(n)
-#endif
-
-/***************************** Data Structures **********************************/
-
-static int audio_ifc_start(void)
-{
- omap_mcbsp_start(AUDIO_MCBSP);
- return 0;
-}
-
-static int audio_ifc_stop(void)
-{
- omap_mcbsp_stop(AUDIO_MCBSP);
- return 0;
-}
-
-static audio_stream_t output_stream = {
- .id = "TSC2101 out",
- .dma_dev = AUDIO_DMA_TX,
- .input_or_output = FMODE_WRITE,
- .hw_start = audio_ifc_start,
- .hw_stop = audio_ifc_stop,
-};
-
-static audio_stream_t input_stream = {
- .id = "TSC2101 in",
- .dma_dev = AUDIO_DMA_RX,
- .input_or_output = FMODE_READ,
- .hw_start = audio_ifc_start,
- .hw_stop = audio_ifc_stop,
-};
-
-static int audio_dev_id, mixer_dev_id;
-
-typedef struct {
- u8 volume;
- u8 line;
- u8 mic;
- int recsrc;
- int mod_cnt;
-} tsc2101_local_info;
-
-static tsc2101_local_info tsc2101_local = {
- volume: DEFAULT_VOLUME,
- line: DEFAULT_INPUT_VOLUME,
- mic: DEFAULT_INPUT_VOLUME,
- recsrc: SOUND_MASK_LINE,
- mod_cnt: 0
-};
-
-struct sample_rate_reg_info {
- u16 sample_rate;
- u8 divisor;
- u8 fs_44kHz; /* if 0 48 khz, if 1 44.1 khz fsref */
-};
-
-/* To Store the default sample rate */
-static long audio_samplerate = AUDIO_RATE_DEFAULT;
-
-static const struct sample_rate_reg_info
- reg_info[NUMBER_SAMPLE_RATES_SUPPORTED] = {
- /* Div 1 */
- {48000, 0, 0},
- {44100, 0, 1},
- /* Div 1.5 */
- {32000, 1, 0},
- {29400, 1, 1},
- /* Div 2 */
- {24000, 2, 0},
- {22050, 2, 1},
- /* Div 3 */
- {16000, 3, 0},
- {14700, 3, 1},
- /* Div 4 */
- {12000, 4, 0},
- {11025, 4, 1},
- /* Div 5 */
- {9600, 5, 0},
- {8820, 5, 1},
- /* Div 5.5 */
- {8727, 6, 0},
- {8018, 6, 1},
- /* Div 6 */
- {8000, 7, 0},
- {7350, 7, 1},
-};
-
-static struct omap_mcbsp_reg_cfg initial_config = {
- .spcr2 = FREE | FRST | GRST | XRST | XINTM(3),
- .spcr1 = RINTM(3) | RRST,
- .rcr2 = RPHASE | RFRLEN2(OMAP_MCBSP_WORD_8) |
- RWDLEN2(OMAP_MCBSP_WORD_16) | RDATDLY(1),
- .rcr1 = RFRLEN1(OMAP_MCBSP_WORD_8) | RWDLEN1(OMAP_MCBSP_WORD_16),
- .xcr2 = XPHASE | XFRLEN2(OMAP_MCBSP_WORD_8) |
- XWDLEN2(OMAP_MCBSP_WORD_16) | XDATDLY(1) | XFIG,
- .xcr1 = XFRLEN1(OMAP_MCBSP_WORD_8) | XWDLEN1(OMAP_MCBSP_WORD_16),
- .srgr1 = FWID(15),
- .srgr2 = GSYNC | CLKSP | FSGM | FPER(31),
-
- /* platform specific initialization */
-#ifdef CONFIG_MACH_OMAP_H2
- .pcr0 = CLKXM | CLKRM | FSXP | FSRP | CLKXP | CLKRP,
-#elif defined(CONFIG_MACH_OMAP_H3) || defined(CONFIG_MACH_OMAP_H4) || defined(CONFIG_MACH_OMAP_APOLLON)
-
-#ifndef TSC_MASTER
- .pcr0 = FSXM | FSRM | CLKXM | CLKRM | CLKXP | CLKRP,
-#else
- .pcr0 = CLKRM | SCLKME | FSXP | FSRP | CLKXP | CLKRP,
-#endif /* tsc Master defs */
-
-#endif /* platform specific inits */
-};
-
-/***************************** MODULES SPECIFIC FUNCTION PROTOTYPES ********************/
-
-static void omap_tsc2101_initialize(void *dummy);
-
-static void omap_tsc2101_shutdown(void *dummy);
-
-static int omap_tsc2101_ioctl(struct inode *inode, struct file *file,
- uint cmd, ulong arg);
-
-static int omap_tsc2101_probe(void);
-
-static void omap_tsc2101_remove(void);
-
-static int omap_tsc2101_suspend(void);
-
-static int omap_tsc2101_resume(void);
-
-static void tsc2101_configure(void);
-
-static int mixer_open(struct inode *inode, struct file *file);
-
-static int mixer_release(struct inode *inode, struct file *file);
-
-static int mixer_ioctl(struct inode *inode, struct file *file, uint cmd,
- ulong arg);
-
-#ifdef TEST_KEYCLICK
-void tsc2101_testkeyclick(void);
-#endif
-
-#ifdef TONE_GEN
-void toneGen(void);
-#endif
-
-#ifdef TSC_DUMP_REGISTERS
-static void tsc2101_dumpRegisters(void);
-#endif
-
-#ifdef PROC_SUPPORT
-static int codec_start(char *buf, char **start, off_t offset, int count,
- int *eof, void *data);
-
-static int codec_stop(char *buf, char **start, off_t offset, int count,
- int *eof, void *data);
-
-static void tsc2101_start(void);
-#endif
-
-/******************** DATA STRUCTURES USING FUNCTION POINTERS **************************/
-
-/* File Op structure for mixer */
-static struct file_operations omap_mixer_fops = {
- .open = mixer_open,
- .release = mixer_release,
- .ioctl = mixer_ioctl,
- .owner = THIS_MODULE
-};
-
-/* To store characteristic info regarding the codec for the audio driver */
-static audio_state_t tsc2101_state = {
- .output_stream = &output_stream,
- .input_stream = &input_stream,
-/* .need_tx_for_rx = 1, //Once the Full Duplex works */
- .need_tx_for_rx = 0,
- .hw_init = omap_tsc2101_initialize,
- .hw_shutdown = omap_tsc2101_shutdown,
- .client_ioctl = omap_tsc2101_ioctl,
- .hw_probe = omap_tsc2101_probe,
- .hw_remove = omap_tsc2101_remove,
- .hw_suspend = omap_tsc2101_suspend,
- .hw_resume = omap_tsc2101_resume,
-};
-
-/* This will be defined in the Audio.h */
-static struct file_operations *omap_audio_fops;
-
-/***************************** MODULES SPECIFIC FUNCTIONs *******************************/
-
-/*********************************************************************************
- *
- * Simplified write for tsc Audio
- *
- *********************************************************************************/
-static __inline__ void audio_tsc2101_write(u8 address, u16 data)
-{
- omap_tsc2101_write(PAGE2_AUDIO_CODEC_REGISTERS, address, data);
-}
-
-/*********************************************************************************
- *
- * Simplified read for tsc Audio
- *
- *********************************************************************************/
-static __inline__ u16 audio_tsc2101_read(u8 address)
-{
- return (omap_tsc2101_read(PAGE2_AUDIO_CODEC_REGISTERS, address));
-}
-
-/*********************************************************************************
- *
- * tsc2101_update()
- * Volume Adj etc
- *
- ********************************************************************************/
-static int tsc2101_update(int flag, int val)
-{
- u16 volume;
- u16 data;
-
- FN_IN;
- switch (flag) {
- case SET_VOLUME:
- if (val < 0 || val > 100) {
- printk(KERN_ERR "Trying a bad volume value(%d)!\n", val);
- return -EPERM;
- }
- /* Convert 0 -> 100 volume to 0x7F(min) -> y(max) volume range */
- volume =
- ((val * OUTPUT_VOLUME_RANGE) / 100) + OUTPUT_VOLUME_MAX;
- /* invert the value for getting the proper range 0 min and 100 max */
- volume = OUTPUT_VOLUME_MIN - volume;
- data = audio_tsc2101_read(TSC2101_DAC_GAIN_CTRL);
- data &=
- ~(DGC_DALVL(OUTPUT_VOLUME_MIN) |
- DGC_DARVL(OUTPUT_VOLUME_MIN));
- data |= DGC_DALVL(volume) | DGC_DARVL(volume);
- audio_tsc2101_write(TSC2101_DAC_GAIN_CTRL, data);
- data = audio_tsc2101_read(TSC2101_DAC_GAIN_CTRL);
-
- break;
-
- case SET_LINE:
- if (val < 0 || val > 100) {
- printk(KERN_ERR "Trying a bad volume value(%d)!\n", val);
- return -EPERM;
- }
- /* Convert 0 -> 100 volume to 0x0(min) -> 0x7D(max) volume range */
- /* NOTE: 0 is minimum volume and not mute */
- volume = ((val * INPUT_VOLUME_RANGE) / 100) + INPUT_VOLUME_MIN;
- /* Handset Input not muted, AGC for Handset In off */
- audio_tsc2101_write(TSC2101_HEADSET_GAIN_CTRL,
- HGC_ADPGA_HED(volume));
- break;
-
- case SET_MIC:
- if (val < 0 || val > 100) {
- printk(KERN_ERR "Trying a bad volume value(%d)!\n", val);
- return -EPERM;
- }
- /* Convert 0 -> 100 volume to 0x0(min) -> 0x7D(max) volume range */
- /* NOTE: 0 is minimum volume and not mute */
- volume = ((val * INPUT_VOLUME_RANGE) / 100) + INPUT_VOLUME_MIN;
- /* Handset Input not muted, AGC for Handset In off */
- audio_tsc2101_write(TSC2101_HANDSET_GAIN_CTRL,
- HNGC_ADPGA_HND(volume));
- break;
-
- case SET_RECSRC:
- /*
- * If more than one recording device selected,
- * disable the device that is currently in use.
- */
- if (hweight32(val) > 1)
- val &= ~tsc2101_local.recsrc;
-
- data = audio_tsc2101_read(TSC2101_MIXER_PGA_CTRL);
- data &= ~MPC_MICSEL(7); /* clear all MICSEL bits */
-
- if (val == SOUND_MASK_MIC) {
- data |= MPC_MICSEL(1);
- audio_tsc2101_write(TSC2101_MIXER_PGA_CTRL, data);
- }
- else if (val == SOUND_MASK_LINE) {
- data |= MPC_MICSEL(0);
- audio_tsc2101_write(TSC2101_MIXER_PGA_CTRL, data);
- }
- else {
- printk(KERN_WARNING "omap1610-tsc2101: Wrong RECSRC"
- " value specified\n");
- return -EINVAL;
- }
- tsc2101_local.recsrc = val;
- break;
- default:
- printk(KERN_WARNING "omap1610-tsc2101: Wrong tsc2101_update "
- "flag specified\n");
- break;
- }
-
- FN_OUT(0);
- return 0;
-}
-
-/*********************************************************************************
- *
- * mixer_open()
- *
- ********************************************************************************/
-static int mixer_open(struct inode *inode, struct file *file)
-{
- /* Any mixer specific initialization */
-
- /* Initalize the tsc2101 */
- omap_tsc2101_enable();
-
- return 0;
-}
-
-/*********************************************************************************
- *
- * mixer_release()
- *
- ********************************************************************************/
-static int mixer_release(struct inode *inode, struct file *file)
-{
- /* Any mixer specific Un-initialization */
- omap_tsc2101_disable();
-
- return 0;
-}
-
-/*********************************************************************************
- *
- * mixer_ioctl()
- *
- ********************************************************************************/
-static int
-mixer_ioctl(struct inode *inode, struct file *file, uint cmd, ulong arg)
-{
- int val;
- int gain;
- int ret = 0;
- int nr = _IOC_NR(cmd);
-
- /*
- * We only accept mixer (type 'M') ioctls.
- */
- FN_IN;
- if (_IOC_TYPE(cmd) != 'M')
- return -EINVAL;
-
- DPRINTK(" 0x%08x\n", cmd);
-
- if (cmd == SOUND_MIXER_INFO) {
- struct mixer_info mi;
-
- strncpy(mi.id, "TSC2101", sizeof(mi.id));
- strncpy(mi.name, "TI TSC2101", sizeof(mi.name));
- mi.modify_counter = tsc2101_local.mod_cnt;
- FN_OUT(1);
- return copy_to_user((void __user *)arg, &mi, sizeof(mi));
- }
-
- if (_IOC_DIR(cmd) & _IOC_WRITE) {
- ret = get_user(val, (int __user *)arg);
- if (ret)
- goto out;
-
- /* Ignore separate left/right channel for now,
- * even the codec does support it.
- */
- gain = val & 255;
-
- switch (nr) {
- case SOUND_MIXER_VOLUME:
- tsc2101_local.volume = val;
- tsc2101_local.mod_cnt++;
- ret = tsc2101_update(SET_VOLUME, gain);
- break;
-
- case SOUND_MIXER_LINE:
- tsc2101_local.line = val;
- tsc2101_local.mod_cnt++;
- ret = tsc2101_update(SET_LINE, gain);
- break;
-
- case SOUND_MIXER_MIC:
- tsc2101_local.mic = val;
- tsc2101_local.mod_cnt++;
- ret = tsc2101_update(SET_MIC, gain);
- break;
-
- case SOUND_MIXER_RECSRC:
- if ((val & SOUND_MASK_LINE) ||
- (val & SOUND_MASK_MIC)) {
- if (tsc2101_local.recsrc != val) {
- tsc2101_local.mod_cnt++;
- tsc2101_update(SET_RECSRC, val);
- }
- }
- else {
- ret = -EINVAL;
- }
- break;
-
- default:
- ret = -EINVAL;
- }
- }
-
- if (ret == 0 && _IOC_DIR(cmd) & _IOC_READ) {
- ret = 0;
-
- switch (nr) {
- case SOUND_MIXER_VOLUME:
- val = tsc2101_local.volume;
- val = (tsc2101_local.volume << 8) |
- tsc2101_local.volume;
- break;
- case SOUND_MIXER_LINE:
- val = (tsc2101_local.line << 8) |
- tsc2101_local.line;
- break;
- case SOUND_MIXER_MIC:
- val = (tsc2101_local.mic << 8) |
- tsc2101_local.mic;
- break;
- case SOUND_MIXER_RECSRC:
- val = tsc2101_local.recsrc;
- break;
- case SOUND_MIXER_RECMASK:
- val = REC_MASK;
- break;
- case SOUND_MIXER_DEVMASK:
- val = DEV_MASK;
- break;
- case SOUND_MIXER_CAPS:
- val = 0;
- break;
- case SOUND_MIXER_STEREODEVS:
- val = SOUND_MASK_VOLUME;
- break;
- default:
- val = 0;
- printk(KERN_WARNING "omap1610-tsc2101: unknown mixer "
- "read ioctl flag specified\n");
- ret = -EINVAL;
- break;
- }
-
- if (ret == 0)
- ret = put_user(val, (int __user *)arg);
- }
- out:
- FN_OUT(0);
- return ret;
-
-}
-
-/*********************************************************************************
- *
- * omap_set_samplerate()
- *
- ********************************************************************************/
-static int omap_set_samplerate(long sample_rate)
-{
- u8 count = 0;
- u16 data = 0;
- int clkgdv = 0;
- /* wait for any frame to complete */
- udelay(125);
-
- /* Search for the right sample rate */
- while ((reg_info[count].sample_rate != sample_rate) &&
- (count < NUMBER_SAMPLE_RATES_SUPPORTED)) {
- count++;
- }
- if (count == NUMBER_SAMPLE_RATES_SUPPORTED) {
- printk(KERN_ERR "Invalid Sample Rate %d requested\n",
- (int)sample_rate);
- return -EPERM;
- }
-
- /* Set AC1 */
- data = audio_tsc2101_read(TSC2101_AUDIO_CTRL_1);
- /*Clear prev settings */
- data &= ~(AC1_DACFS(0x07) | AC1_ADCFS(0x07));
- data |=
- AC1_DACFS(reg_info[count].divisor) | AC1_ADCFS(reg_info[count].
- divisor);
- audio_tsc2101_write(TSC2101_AUDIO_CTRL_1, data);
-
- /* Set the AC3 */
- data = audio_tsc2101_read(TSC2101_AUDIO_CTRL_3);
- /*Clear prev settings */
- data &= ~(AC3_REFFS | AC3_SLVMS);
- data |= (reg_info[count].fs_44kHz) ? AC3_REFFS : 0;
-#ifdef TSC_MASTER
- data |= AC3_SLVMS;
-#endif /* #ifdef TSC_MASTER */
- audio_tsc2101_write(TSC2101_AUDIO_CTRL_3, data);
-
- /* program the PLLs */
- if (reg_info[count].fs_44kHz) {
- /* 44.1 khz - 12 MHz Mclk */
- audio_tsc2101_write(TSC2101_PLL_PROG_1, PLL1_PLLSEL | PLL1_PVAL(1) | PLL1_I_VAL(7)); /* PVAL 1; I_VAL 7 */
- audio_tsc2101_write(TSC2101_PLL_PROG_2, PLL2_D_VAL(0x1490)); /* D_VAL 5264 */
- } else {
- /* 48 khz - 12 Mhz Mclk */
- audio_tsc2101_write(TSC2101_PLL_PROG_1, PLL1_PLLSEL | PLL1_PVAL(1) | PLL1_I_VAL(8)); /* PVAL 1; I_VAL 8 */
- audio_tsc2101_write(TSC2101_PLL_PROG_2, PLL2_D_VAL(0x780)); /* D_VAL 1920 */
- }
-
- audio_samplerate = sample_rate;
-
- /* Set the sample rate */
-#ifndef TSC_MASTER
- clkgdv =
- DEFAULT_MCBSP_CLOCK / (sample_rate *
- (DEFAULT_BITPERSAMPLE * 2 - 1));
- if (clkgdv)
- initial_config.srgr1 =
- (FWID(DEFAULT_BITPERSAMPLE - 1) | CLKGDV(clkgdv));
- else
- return (1);
-
- /* Stereo Mode */
- initial_config.srgr2 =
- (CLKSM | FSGM | FPER(DEFAULT_BITPERSAMPLE * 2 - 1));
-#else
- initial_config.srgr1 =
- (FWID(DEFAULT_BITPERSAMPLE - 1) | CLKGDV(clkgdv));
- initial_config.srgr2 =
- ((GSYNC | CLKSP | FSGM | FPER(DEFAULT_BITPERSAMPLE * 2 - 1)));
-
-#endif /* end of #ifdef TSC_MASTER */
- omap_mcbsp_config(AUDIO_MCBSP, &initial_config);
-
- return 0;
-}
-
-/*********************************************************************************
- *
- * omap_tsc2101_initialize() [hw_init() ]
- *
- ********************************************************************************/
-static void omap_tsc2101_initialize(void *dummy)
-{
-
- DPRINTK("omap_tsc2101_initialize entry\n");
-
- /* initialize with default sample rate */
- audio_samplerate = AUDIO_RATE_DEFAULT;
-
- omap_mcbsp_request(AUDIO_MCBSP);
-
- /* if configured, then stop mcbsp */
- omap_mcbsp_stop(AUDIO_MCBSP);
-
- omap_tsc2101_enable();
-
- omap_mcbsp_config(AUDIO_MCBSP, &initial_config);
- omap_mcbsp_start(AUDIO_MCBSP);
- tsc2101_configure();
-
-#ifdef TEST_KEYCLICK
- tsc2101_testkeyclick();
-#endif
-
-#ifdef TONE_GEN
- toneGen();
-#endif
-
- DPRINTK("omap_tsc2101_initialize exit\n");
-}
-
-/*********************************************************************************
- *
- * omap_tsc2101_shutdown() [hw_shutdown() ]
- *
- ********************************************************************************/
-static void omap_tsc2101_shutdown(void *dummy)
-{
- /*
- Turn off codec after it is done.
- Can't do it immediately, since it may still have
- buffered data.
-
- Wait 20ms (arbitrary value) and then turn it off.
- */
-
- FN_IN;
- set_current_state(TASK_INTERRUPTIBLE);
- schedule_timeout(2);
-
- omap_mcbsp_stop(AUDIO_MCBSP);
- omap_mcbsp_free(AUDIO_MCBSP);
-
- audio_tsc2101_write(TSC2101_CODEC_POWER_CTRL,
- ~(CPC_SP1PWDN | CPC_SP2PWDN | CPC_BASSBC));
-
- omap_tsc2101_disable();
-
- FN_OUT(0);
-}
-
-/*********************************************************************************
- *
- * tsc2101_configure
- *
- ********************************************************************************/
-static void tsc2101_configure(void)
-{
- FN_IN;
-
- audio_tsc2101_write(TSC2101_CODEC_POWER_CTRL, 0x0000);
-
- /*Mute Analog Sidetone */
- /*Select MIC_INHED input for headset */
- /*Cell Phone In not connected */
- audio_tsc2101_write(TSC2101_MIXER_PGA_CTRL,
- MPC_ASTMU | MPC_ASTG(0x40) | MPC_MICADC);
-
- /* Set record source */
- tsc2101_update(SET_RECSRC, tsc2101_local.recsrc);
-
- /* ADC, DAC, Analog Sidetone, cellphone, buzzer softstepping enabled */
- /* 1dB AGC hysteresis */
- /* MICes bias 2V */
- audio_tsc2101_write(TSC2101_AUDIO_CTRL_4, AC4_MB_HED(0));
-
- /* Set codec output volume */
- audio_tsc2101_write(TSC2101_DAC_GAIN_CTRL, 0x0000);
-
- /* DAC left and right routed to SPK2 */
- /* SPK1/2 unmuted */
- audio_tsc2101_write(TSC2101_AUDIO_CTRL_5,
- AC5_DAC2SPK1(3) | AC5_AST2SPK1 | AC5_KCL2SPK1 |
- AC5_DAC2SPK2(3) | AC5_AST2SPK2 | AC5_KCL2SPK2 |
- AC5_HDSCPTC);
-
- /* OUT8P/N muted, CPOUT muted */
-
- audio_tsc2101_write(TSC2101_AUDIO_CTRL_6,
- AC6_MUTLSPK | AC6_MUTSPK2 | AC6_LDSCPTC |
- AC6_VGNDSCPTC);
-
- /* Headset/Hook switch detect disabled */
- audio_tsc2101_write(TSC2101_AUDIO_CTRL_7, 0x0000);
-
- /* Left line input volume control */
- tsc2101_update(SET_LINE, tsc2101_local.line);
-
- /* mic input volume control */
- tsc2101_update(SET_MIC, tsc2101_local.mic);
-
- /* Left/Right headphone channel volume control */
- /* Zero-cross detect on */
- tsc2101_update(SET_VOLUME, tsc2101_local.volume);
-
- /* clock configuration */
- omap_set_samplerate(audio_samplerate);
-
-#ifdef TSC_DUMP_REGISTERS
- tsc2101_dumpRegisters();
-#endif
-
- FN_OUT(0);
-}
-
-#ifdef PROC_SUPPORT
-static void tsc2101_start(void)
-{
- FN_IN;
-
- audio_tsc2101_write(TSC2101_CODEC_POWER_CTRL, 0x0000);
-
- /*Mute Analog Sidetone */
- /*Select MIC_INHED input for headset */
- /*Cell Phone In not connected */
- audio_tsc2101_write(TSC2101_MIXER_PGA_CTRL,
- MPC_ASTMU | MPC_ASTG(0x40) | MPC_MICADC);
-
- /* Set record source */
- tsc2101_update(SET_RECSRC, tsc2101_local.recsrc);
-
- /* ADC, DAC, Analog Sidetone, cellphone, buzzer softstepping enabled */
- /* 1dB AGC hysteresis */
- /* MICes bias 2V */
- audio_tsc2101_write(TSC2101_AUDIO_CTRL_4, AC4_MB_HED(0));
-
- /* Set codec output volume */
- audio_tsc2101_write(TSC2101_DAC_GAIN_CTRL, 0x0000);
-
- /* DAC left and right routed to SPK2 */
- /* SPK1/2 unmuted */
- audio_tsc2101_write(TSC2101_AUDIO_CTRL_5,
- AC5_DAC2SPK1(3) | AC5_AST2SPK1 | AC5_KCL2SPK1 |
- AC5_DAC2SPK2(3) | AC5_AST2SPK2 | AC5_KCL2SPK2 |
- AC5_HDSCPTC);
-
- /* OUT8P/N muted, CPOUT muted */
-
- audio_tsc2101_write(TSC2101_AUDIO_CTRL_6,
- AC6_MUTLSPK | AC6_MUTSPK2 | AC6_LDSCPTC |
- AC6_VGNDSCPTC);
-
- /* Headset/Hook switch detect disabled */
- audio_tsc2101_write(TSC2101_AUDIO_CTRL_7, 0x0000);
-
- /* Left line input volume control */
- tsc2101_update(SET_LINE, tsc2101_local.line);
-
- /* mic input volume control */
- tsc2101_update(SET_MIC, tsc2101_local.mic);
-
- /* Left/Right headphone channel volume control */
- /* Zero-cross detect on */
- tsc2101_update(SET_VOLUME, tsc2101_local.volume);
-
- FN_OUT(0);
-
-}
-#endif
-
-/******************************************************************************************
- *
- * All generic ioctl's are handled by audio_ioctl() [File: omap-audio.c]. This
- * routine handles some platform specific ioctl's
- *
- ******************************************************************************************/
-static int
-omap_tsc2101_ioctl(struct inode *inode, struct file *file, uint cmd, ulong arg)
-{
- long val;
- int ret = 0;
-
- DPRINTK(" 0x%08x\n", cmd);
-
- /*
- * These are platform dependent ioctls which are not handled by the
- * generic omap-audio module.
- */
- switch (cmd) {
- case SNDCTL_DSP_STEREO:
- ret = get_user(val, (int __user *)arg);
- if (ret)
- return ret;
- /* the AIC23 is stereo only */
- ret = (val == 0) ? -EINVAL : 1;
- FN_OUT(1);
- return put_user(ret, (int __user *)arg);
-
- case SNDCTL_DSP_CHANNELS:
- case SOUND_PCM_READ_CHANNELS:
- /* the AIC23 is stereo only */
- FN_OUT(2);
- return put_user(2, (long __user *)arg);
-
- case SNDCTL_DSP_SPEED:
- ret = get_user(val, (long __user *)arg);
- if (ret)
- break;
- ret = omap_set_samplerate(val);
- if (ret)
- break;
- /* fall through */
-
- case SOUND_PCM_READ_RATE:
- FN_OUT(3);
- return put_user(audio_samplerate, (long __user *)arg);
-
- case SOUND_PCM_READ_BITS:
- case SNDCTL_DSP_SETFMT:
- case SNDCTL_DSP_GETFMTS:
- /* we can do 16-bit only */
- FN_OUT(4);
- return put_user(AFMT_S16_LE, (long __user *)arg);
-
- default:
- /* Maybe this is meant for the mixer (As per OSS Docs) */
- FN_OUT(5);
- return mixer_ioctl(inode, file, cmd, arg);
- }
-
- FN_OUT(0);
- return ret;
-}
-
-/*********************************************************************************
- *
- * module_probe for TSC2101
- *
- ********************************************************************************/
-static int omap_tsc2101_probe(void)
-{
- FN_IN;
-
- /* Get the fops from audio oss driver */
- if (!(omap_audio_fops = audio_get_fops())) {
- printk(KERN_ERR "Unable to Get the FOPs of Audio OSS driver\n");
- audio_unregister_codec(&tsc2101_state);
- return -EPERM;
- }
-
- /* register devices */
- audio_dev_id = register_sound_dsp(omap_audio_fops, -1);
- mixer_dev_id = register_sound_mixer(&omap_mixer_fops, -1);
-
-#ifdef PROC_SUPPORT
- create_proc_read_entry(PROC_START_FILE, 0 /* default mode */ ,
- NULL /* parent dir */ ,
- codec_start, NULL /* client data */ );
-
- create_proc_read_entry(PROC_STOP_FILE, 0 /* default mode */ ,
- NULL /* parent dir */ ,
- codec_stop, NULL /* client data */ );
-#endif
-
- /* Announcement Time */
- printk(KERN_INFO PLATFORM_NAME " " CODEC_NAME
- " Audio support initialized\n");
-
- FN_OUT(0);
- return 0;
-}
-
-/*********************************************************************************
- *
- * Module Remove for TSC2101
- *
- ********************************************************************************/
-static void omap_tsc2101_remove(void)
-{
- FN_IN;
- /* Un-Register the codec with the audio driver */
- unregister_sound_dsp(audio_dev_id);
- unregister_sound_mixer(mixer_dev_id);
-
-#ifdef PROC_SUPPORT
- remove_proc_entry(PROC_START_FILE, NULL);
- remove_proc_entry(PROC_STOP_FILE, NULL);
-#endif
- FN_OUT(0);
-
-}
-
-/*********************************************************************************
- *
- * Module Suspend for TSC2101
- *
- ********************************************************************************/
-static int omap_tsc2101_suspend(void)
-{
-
- FN_OUT(0);
- return 0;
-}
-
-/*********************************************************************************
- *
- * Module Resume for TSC2101
- *
- ********************************************************************************/
-static int omap_tsc2101_resume(void)
-{
-
- FN_OUT(0);
- return 0;
-}
-
-/*********************************************************************************
- *
- * module_init for TSC2101
- *
- ********************************************************************************/
-static int __init audio_tsc2101_init(void)
-{
-
- int err = 0;
- FN_IN;
-
- if (machine_is_omap_osk() || machine_is_omap_innovator())
- return -ENODEV;
-
- mutex_init(&tsc2101_state.mutex);
-
- /* register the codec with the audio driver */
- if ((err = audio_register_codec(&tsc2101_state))) {
- printk(KERN_ERR
- "Failed to register TSC driver with Audio OSS Driver\n");
- }
- FN_OUT(err);
- return err;
-}
-
-/*********************************************************************************
- *
- * module_exit for TSC2101
- *
- ********************************************************************************/
-static void __exit audio_tsc2101_exit(void)
-{
-
- FN_IN;
- (void)audio_unregister_codec(&tsc2101_state);
- FN_OUT(0);
- return;
-}
-
-/**************************** DEBUG FUNCTIONS ***********************************/
-
-/*********************************************************************************
- * TEST_KEYCLICK:
- * This is a test to generate various keyclick sound on tsc.
- * verifies if the tsc and the spi interfaces are operational.
- *
- ********************************************************************************/
-#ifdef TEST_KEYCLICK
-void tsc2101_testkeyclick(void)
-{
- u8 freq = 0;
- u16 old_reg_val, reg_val;
- u32 uDummyVal = 0;
- u32 uTryVal = 0;
-
- old_reg_val = audio_tsc2101_read(TSC2101_AUDIO_CTRL_2);
-
- /* Keyclick active, max amplitude and longest key click len(32 period) */
- printk(KERN_INFO " TESTING KEYCLICK\n Listen carefully NOW....\n");
- printk(KERN_INFO " OLD REG VAL=0x%x\n", old_reg_val);
- /* try all frequencies */
- for (; freq < 8; freq++) {
- /* Keyclick active, max amplitude and longest key click len(32 period) */
- reg_val = old_reg_val | AC2_KCLAC(0x7) | AC2_KCLLN(0xF);
- uDummyVal = 0;
- uTryVal = 0;
- printk(KERN_INFO "\n\nTrying frequency %d reg val= 0x%x\n",
- freq, reg_val | AC2_KCLFRQ(freq) | AC2_KCLEN);
- audio_tsc2101_write(TSC2101_AUDIO_CTRL_2,
- reg_val | AC2_KCLFRQ(freq) | AC2_KCLEN);
- printk("DONE. Wait 10 ms ...\n");
- /* wait till the kclk bit is auto cleared! time out also to be considered. */
- while (audio_tsc2101_read(TSC2101_AUDIO_CTRL_2) & AC2_KCLEN) {
- udelay(3);
- uTryVal++;
- if (uTryVal > 2000) {
- printk(KERN_ERR
- "KEYCLICK TIMED OUT! freq val=%d, POSSIBLE ERROR!\n",
- freq);
- printk(KERN_INFO
- "uTryVal == %d: Read back new reg val= 0x%x\n",
- uTryVal,
- audio_tsc2101_read
- (TSC2101_AUDIO_CTRL_2));
- /* clear */
- audio_tsc2101_write(TSC2101_AUDIO_CTRL_2, 0x00);
- break;
- }
- }
- }
- /* put the old value back */
- audio_tsc2101_write(TSC2101_AUDIO_CTRL_2, old_reg_val);
- printk(KERN_INFO " KEYCLICK TEST COMPLETE\n");
-
-} /* End of tsc2101_testkeyclick */
-
-#endif /* TEST_KEYCLICK */
-
-/*********************************************************************************
- * TONEGEN:
- * This is a test to generate a rather unpleasant sound..
- * verifies if the mcbsp is active (requires MCBSP_DIRECT_RW to be active on McBSP)
- *
- ********************************************************************************/
-#ifdef TONE_GEN
-/* Generates a shrill tone */
-u16 tone[] = {
- 0x0ce4, 0x0ce4, 0x1985, 0x1985, 0x25A1, 0x25A1, 0x30FD, 0x30FE,
- 0x3B56, 0x3B55, 0x447A, 0x447A, 0x4C3B, 0x4C3C, 0x526D, 0x526C,
- 0x56F1, 0x56F1, 0x59B1, 0x59B1, 0x5A9E, 0x5A9D, 0x59B1, 0x59B2,
- 0x56F3, 0x56F2, 0x526D, 0x526D, 0x4C3B, 0x4C3B, 0x447C, 0x447C,
- 0x3B5A, 0x3B59, 0x30FE, 0x30FE, 0x25A5, 0x25A6, 0x1989, 0x198A,
- 0x0CE5, 0x0CE3, 0x0000, 0x0000, 0xF31C, 0xF31C, 0xE677, 0xE676,
- 0xDA5B, 0xDA5B, 0xCF03, 0xCF03, 0xC4AA, 0xC4AA, 0xBB83, 0xBB83,
- 0xB3C5, 0xB3C5, 0xAD94, 0xAD94, 0xA90D, 0xA90E, 0xA64F, 0xA64E,
- 0xA562, 0xA563, 0xA64F, 0xA64F, 0xA910, 0xA90F, 0xAD93, 0xAD94,
- 0xB3C4, 0xB3C4, 0xBB87, 0xBB86, 0xC4AB, 0xC4AB, 0xCF03, 0xCF03,
- 0xDA5B, 0xDA5A, 0xE67B, 0xE67B, 0xF31B, 0xF3AC, 0x0000, 0x0000,
- 0x0CE4, 0x0CE4, 0x1985, 0x1985, 0x25A1, 0x25A1, 0x30FD, 0x30FE,
- 0x3B56, 0x3B55, 0x447A, 0x447A, 0x4C3B, 0x4C3C, 0x526D, 0x526C,
- 0x56F1, 0x56F1, 0x59B1, 0x59B1, 0x5A9E, 0x5A9D, 0x59B1, 0x59B2,
- 0x56F3, 0x56F2, 0x526D, 0x526D, 0x4C3B, 0x4C3B, 0x447C, 0x447C,
- 0x3B5A, 0x3B59, 0x30FE, 0x30FE, 0x25A5, 0x25A6, 0x1989, 0x198A,
- 0x0CE5, 0x0CE3, 0x0000, 0x0000, 0xF31C, 0xF31C, 0xE677, 0xE676,
- 0xDA5B, 0xDA5B, 0xCF03, 0xCF03, 0xC4AA, 0xC4AA, 0xBB83, 0xBB83,
- 0xB3C5, 0xB3C5, 0xAD94, 0xAD94, 0xA90D, 0xA90E, 0xA64F, 0xA64E,
- 0xA562, 0xA563, 0xA64F, 0xA64F, 0xA910, 0xA90F, 0xAD93, 0xAD94,
- 0xB3C4, 0xB3C4, 0xBB87, 0xBB86, 0xC4AB, 0xC4AB, 0xCF03, 0xCF03,
- 0xDA5B, 0xDA5A, 0xE67B, 0xE67B, 0xF31B, 0xF3AC, 0x0000, 0x0000,
- 0x0CE4, 0x0CE4, 0x1985, 0x1985, 0x25A1, 0x25A1, 0x30FD, 0x30FE,
- 0x3B56, 0x3B55, 0x447A, 0x447A, 0x4C3B, 0x4C3C, 0x526D, 0x526C,
- 0x56F1, 0x56F1, 0x59B1, 0x59B1, 0x5A9E, 0x5A9D, 0x59B1, 0x59B2,
- 0x56F3, 0x56F2, 0x526D, 0x526D, 0x4C3B, 0x4C3B, 0x447C, 0x447C,
- 0x3B5A, 0x3B59, 0x30FE, 0x30FE, 0x25A5, 0x25A6, 0x1989, 0x198A,
- 0x0CE5, 0x0CE3, 0x0000, 0x0000, 0xF31C, 0xF31C, 0xE677, 0xE676,
- 0xDA5B, 0xDA5B, 0xCF03, 0xCF03, 0xC4AA, 0xC4AA, 0xBB83, 0xBB83,
- 0xB3C5, 0xB3C5, 0xAD94, 0xAD94, 0xA90D, 0xA90E, 0xA64F, 0xA64E,
- 0xA562, 0xA563, 0xA64F, 0xA64F, 0xA910, 0xA90F, 0xAD93, 0xAD94,
- 0xB3C4, 0xB3C4, 0xBB87, 0xBB86, 0xC4AB, 0xC4AB, 0xCF03, 0xCF03,
- 0xDA5B, 0xDA5A, 0xE67B, 0xE67B, 0xF31B, 0xF3AC, 0x0000, 0x0000
-};
-
-void toneGen(void)
-{
- int count = 0;
- int ret = 0;
- printk(KERN_INFO "TONE GEN TEST :");
-
- for (count = 0; count < 5000; count++) {
- int bytes;
- for (bytes = 0; bytes < sizeof(tone) / 2; bytes++) {
- ret = omap_mcbsp_pollwrite(AUDIO_MCBSP, tone[bytes]);
- if (ret == -1) {
- /* retry */
- bytes--;
- } else if (ret == -2) {
- printk(KERN_INFO "ERROR:bytes=%d\n", bytes);
- return;
- }
- }
- }
- printk(KERN_INFO "SUCCESS\n");
-}
-
-#endif /* End of TONE_GEN */
-
-/*********************************************************************************
- *
- * TSC_DUMP_REGISTERS:
- * This will dump the entire register set of Page 2 tsc2101.
- * Useful for major goof ups
- *
- ********************************************************************************/
-#ifdef TSC_DUMP_REGISTERS
-static void tsc2101_dumpRegisters(void)
-{
- int i = 0;
- u16 data = 0;
- printk("TSC 2101 Register dump for Page 2 \n");
- for (i = 0; i < 0x27; i++) {
- data = audio_tsc2101_read(i);
- printk(KERN_INFO "Register[%x]=0x%04x\n", i, data);
-
- }
-}
-#endif /* End of #ifdef TSC_DUMP_REGISTERS */
-
-#ifdef PROC_SUPPORT
-static int codec_start(char *buf, char **start, off_t offset, int count,
- int *eof, void *data)
-{
- omap_tsc2101_enable();
- tsc2101_start();
- printk("Codec initialization done.\n");
- return 0;
-}
-static int codec_stop(char *buf, char **start, off_t offset, int count,
- int *eof, void *data)
-{
-
- omap_tsc2101_disable();
- audio_tsc2101_write(TSC2101_CODEC_POWER_CTRL,
- ~(CPC_SP1PWDN | CPC_SP2PWDN | CPC_BASSBC));
- printk("Codec shutdown.\n");
- return 0;
-}
-#endif
-
-/*********************************************************************************
- *
- * Other misc management, registration etc
- *
- ********************************************************************************/
-module_init(audio_tsc2101_init);
-module_exit(audio_tsc2101_exit);
-
-MODULE_AUTHOR("Texas Instruments");
-MODULE_DESCRIPTION
- ("Glue audio driver for the TI OMAP1610/OMAP1710 TSC2101 codec.");
-MODULE_LICENSE("GPL");
+++ /dev/null
-/*
- * linux/sound/oss/omap-audio.c
- *
- * Common audio handling for the OMAP processors
- *
- * Copyright (C) 2004 Texas Instruments, Inc.
- *
- * Copyright (C) 2000, 2001 Nicolas Pitre <nico@cam.org>
- *
- * This package is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * THIS PACKAGE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
- * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
- * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
- *
- * History:
- *
- * 2004/08/12 Nishanth Menon - Modified to integrate Audio requirements on 1610,1710 platforms
- *
- * 2004-11-01 Nishanth Menon - modified to support 16xx and 17xx
- * platform multi channel chaining.
- *
- * 2004-11-04 Nishanth Menon - Added support for power management
- *
- * 2004-12-17 Nishanth Menon - Provided proper module handling support
- */
-
-/***************************** INCLUDES ************************************/
-
-#include <linux/module.h>
-#include <linux/init.h>
-#include <linux/types.h>
-#include <linux/fs.h>
-#include <linux/mm.h>
-#include <linux/slab.h>
-#include <linux/sched.h>
-#include <linux/poll.h>
-#include <linux/pm.h>
-#include <linux/errno.h>
-#include <linux/sound.h>
-#include <linux/soundcard.h>
-#include <linux/sysrq.h>
-#include <linux/delay.h>
-#include <linux/platform_device.h>
-#include <linux/completion.h>
-#include <linux/mutex.h>
-
-#include <asm/uaccess.h>
-#include <asm/io.h>
-#include <mach/hardware.h>
-
-#include "omap-audio-dma-intfc.h"
-#include "omap-audio.h"
-
-/***************************** MACROS ************************************/
-
-#undef DEBUG
-//#define DEBUG
-#ifdef DEBUG
-#define DPRINTK printk
-#define FN_IN printk("[omap_audio.c:[%s] start\n", __FUNCTION__)
-#define FN_OUT(n) printk("[omap_audio.c:[%s] end(%d)\n", __FUNCTION__ , n)
-#else
-#define DPRINTK( x... )
-#define FN_IN
-#define FN_OUT(x)
-#endif
-
-#define OMAP_AUDIO_NAME "omap-audio"
-#define AUDIO_NBFRAGS_DEFAULT 8
-#define AUDIO_FRAGSIZE_DEFAULT 8192
-
-/* HACK ALERT!: These values will bave to be tuned as this is a trade off b/w
- * Sampling Rate vs buffer size and delay we are prepared to do before giving up
- */
-#define MAX_QUEUE_FULL_RETRIES 1000000
-#define QUEUE_WAIT_TIME 10
-
-#define AUDIO_ACTIVE(state) ((state)->rd_ref || (state)->wr_ref)
-
-#define SPIN_ADDR (dma_addr_t)0
-#define SPIN_SIZE 2048
-
-/***************************** MODULES SPECIFIC FUNCTION PROTOTYPES ********************/
-
-static int audio_write(struct file *file, const char __user *buffer,
- size_t count, loff_t * ppos);
-
-static int audio_read(struct file *file, char __user *buffer, size_t count,
- loff_t * ppos);
-
-static int audio_mmap(struct file *file, struct vm_area_struct *vma);
-
-static unsigned int audio_poll(struct file *file,
- struct poll_table_struct *wait);
-
-static loff_t audio_llseek(struct file *file, loff_t offset, int origin);
-
-static int audio_ioctl(struct inode *inode, struct file *file, uint cmd,
- ulong arg);
-
-static int audio_open(struct inode *inode, struct file *file);
-
-static int audio_release(struct inode *inode, struct file *file);
-
-static int audio_probe(struct platform_device *pdev);
-
-static int audio_remove(struct platform_device *pdev);
-
-static void audio_shutdown(struct platform_device *pdev);
-
-static int audio_suspend(struct platform_device *pdev, pm_message_t mesg);
-
-static int audio_resume(struct platform_device *pdev);
-
-static void audio_free(struct device *dev);
-
-/***************************** Data Structures **********************************/
-
-/*
- * The function pointer set to be registered by the codec.
- */
-static audio_state_t audio_state = { NULL };
-
-/* DMA Call back function */
-static dma_callback_t audio_dma_callback = NULL;
-
-/* File Ops structure */
-static struct file_operations omap_audio_fops = {
- .open = audio_open,
- .release = audio_release,
- .write = audio_write,
- .read = audio_read,
- .mmap = audio_mmap,
- .poll = audio_poll,
- .ioctl = audio_ioctl,
- .llseek = audio_llseek,
- .owner = THIS_MODULE
-};
-
-/* Driver information */
-static struct platform_driver omap_audio_driver = {
- .probe = audio_probe,
- .remove = audio_remove,
- .suspend = audio_suspend,
- .shutdown = audio_shutdown,
- .resume = audio_resume,
- .driver = {
- .name = OMAP_AUDIO_NAME,
- },
-};
-
-/* Device Information */
-static struct platform_device omap_audio_device = {
- .name = OMAP_AUDIO_NAME,
- .dev = {
- .driver_data = &audio_state,
- .release = audio_free,
- },
- .id = 0,
-};
-
-/***************************** GLOBAL FUNCTIONs **********************************/
-
-/* Power Management Functions for Linux Device Model */
-/* DEBUG PUPOSES ONLY! */
-#ifdef CONFIG_PM
-//#undef CONFIG_PM
-#endif
-
-#ifdef CONFIG_PM
-/*********************************************************************************
- *
- * audio_ldm_suspend(): Suspend operation
- *
- *********************************************************************************/
-static int audio_ldm_suspend(void *data)
-{
- audio_state_t *state = data;
-
- FN_IN;
-
- /*
- * Reject the suspend request if we are already actively transmitting data
- * Rationale: We dont want to be suspended while in the middle of a call!
- */
- if (AUDIO_ACTIVE(state) && state->hw_init) {
- printk(KERN_ERR "Audio device Active, Cannot Suspend");
- return -EPERM;
-#if 0
- /* NOTE:
- * This Piece of code is commented out in hope
- * That one day we would need to suspend the device while
- * audio operations are in progress and resume the operations
- * once the resume is done.
- * This is just a sample implementation of how it could be done.
- * Currently NOT SUPPORTED
- */
- audio_stream_t *is = state->input_stream;
- audio_stream_t *os = state->output_stream;
- int stopstate;
- if (is && is->buffers) {
- printk("IS Suspend\n");
- stopstate = is->stopped;
- audio_stop_dma(is);
- DMA_CLEAR(is);
- is->dma_spinref = 0;
- is->stopped = stopstate;
- }
- if (os && os->buffers) {
- printk("OS Suspend\n");
- stopstate = os->stopped;
- audio_stop_dma(os);
- DMA_CLEAR(os);
- os->dma_spinref = 0;
- os->stopped = stopstate;
- }
-#endif
- }
-
- FN_OUT(0);
- return 0;
-}
-
-/*********************************************************************************
- *
- * audio_ldm_resume(): Resume Operations
- *
- *********************************************************************************/
-static int audio_ldm_resume(void *data)
-{
- audio_state_t *state = data;
-
- FN_IN;
- if (AUDIO_ACTIVE(state) && state->hw_init) {
- /* Should never occur - since we never suspend with active state */
- BUG();
- return -EPERM;
-#if 0
- /* NOTE:
- * This Piece of code is commented out in hope
- * That one day we would need to suspend the device while
- * audio operations are in progress and resume the operations
- * once the resume is done.
- * This is just a sample implementation of how it could be done.
- * Currently NOT SUPPORTED
- */
- audio_stream_t *is = state->input_stream;
- audio_stream_t *os = state->output_stream;
- if (os && os->buffers) {
- printk("OS Resume\n");
- audio_reset(os);
- audio_process_dma(os);
- }
- if (is && is->buffers) {
- printk("IS Resume\n");
- audio_reset(is);
- audio_process_dma(is);
- }
-#endif
- }
- FN_OUT(0);
- return 0;
-}
-#endif /* End of #ifdef CONFIG_PM */
-
-/*********************************************************************************
- *
- * audio_free(): The Audio driver release function
- * This is a dummy function required by the platform driver
- *
- *********************************************************************************/
-static void audio_free(struct device *dev)
-{
- /* Nothing to Release! */
-}
-
-/*********************************************************************************
- *
- * audio_probe(): The Audio driver probe function
- * WARNING!!!! : It is expected that the codec would have registered with us by now
- *
- *********************************************************************************/
-static int audio_probe(struct platform_device *pdev)
-{
- int ret;
- FN_IN;
- if (!audio_state.hw_probe) {
- printk(KERN_ERR "Probe Function Not Registered\n");
- return -ENODEV;
- }
- ret = audio_state.hw_probe();
- FN_OUT(ret);
- return ret;
-}
-
-/*********************************************************************************
- *
- * audio_remove() Function to handle removal operations
- *
- *********************************************************************************/
-static int audio_remove(struct platform_device *pdev)
-{
- FN_IN;
- if (audio_state.hw_remove) {
- audio_state.hw_remove();
- }
- FN_OUT(0);
- return 0;
-}
-
-/*********************************************************************************
- *
- * audio_shutdown(): Function to handle shutdown operations
- *
- *********************************************************************************/
-static void audio_shutdown(struct platform_device *pdev)
-{
- FN_IN;
- if (audio_state.hw_cleanup) {
- audio_state.hw_cleanup();
- }
- FN_OUT(0);
- return;
-}
-
-/*********************************************************************************
- *
- * audio_suspend(): Function to handle suspend operations
- *
- *********************************************************************************/
-static int audio_suspend(struct platform_device *pdev, pm_message_t mesg)
-{
- int ret = 0;
-
-#ifdef CONFIG_PM
- void *data = pdev->dev.driver_data;
- FN_IN;
- if (audio_state.hw_suspend) {
- ret = audio_ldm_suspend(data);
- if (ret == 0)
- ret = audio_state.hw_suspend();
- }
- if (ret) {
- printk(KERN_INFO "Audio Suspend Failed \n");
- } else {
- printk(KERN_INFO "Audio Suspend Success \n");
- }
-#endif /* CONFIG_PM */
-
- FN_OUT(ret);
- return ret;
-}
-
-/*********************************************************************************
- *
- * audio_resume(): Function to handle resume operations
- *
- *********************************************************************************/
-static int audio_resume(struct platform_device *pdev)
-{
- int ret = 0;
-
-#ifdef CONFIG_PM
- void *data = pdev->dev.driver_data;
- FN_IN;
- if (audio_state.hw_resume) {
- ret = audio_ldm_resume(data);
- if (ret == 0)
- ret = audio_state.hw_resume();
- }
- if (ret) {
- printk(KERN_INFO " Audio Resume Failed \n");
- } else {
- printk(KERN_INFO " Audio Resume Success \n");
- }
-#endif /* CONFIG_PM */
-
- FN_OUT(ret);
- return ret;
-}
-
-/*********************************************************************************
- *
- * audio_get_fops(): Return the fops required to get the function pointers of
- * OMAP Audio Driver
- *
- *********************************************************************************/
-struct file_operations *audio_get_fops(void)
-{
- FN_IN;
- FN_OUT(0);
- return &omap_audio_fops;
-}
-
-/*********************************************************************************
- *
- * audio_register_codec(): Register a Codec fn points using this function
- * WARNING!!!!! : Codecs should ensure that they do so! no sanity checks
- * during runtime is done due to obvious performance
- * penalties.
- *
- *********************************************************************************/
-int audio_register_codec(audio_state_t * codec_state)
-{
- int ret;
- FN_IN;
-
- /* We dont handle multiple codecs now */
- if (audio_state.hw_init) {
- printk(KERN_ERR " Codec Already registered\n");
- return -EPERM;
- }
-
- /* Grab the dma Callback */
- audio_dma_callback = audio_get_dma_callback();
- if (!audio_dma_callback) {
- printk(KERN_ERR "Unable to get call back function\n");
- return -EPERM;
- }
-
- /* Sanity checks */
- if (!codec_state) {
- printk(KERN_ERR "NULL ARGUMENT!\n");
- return -EPERM;
- }
-
- if (!codec_state->hw_probe || !codec_state->hw_init
- || !codec_state->hw_shutdown || !codec_state->client_ioctl) {
- printk(KERN_ERR
- "Required Fn Entry point Missing probe=%p init=%p,down=%p,ioctl=%p!\n",
- codec_state->hw_probe, codec_state->hw_init,
- codec_state->hw_shutdown, codec_state->client_ioctl);
- return -EPERM;
- }
-
- memcpy(&audio_state, codec_state, sizeof(audio_state_t));
- mutex_init(&audio_state.mutex);
-
- ret = platform_device_register(&omap_audio_device);
- if (ret != 0) {
- printk(KERN_ERR "Platform dev_register failed =%d\n", ret);
- ret = -ENODEV;
- goto register_out;
- }
-
- ret = platform_driver_register(&omap_audio_driver);
- if (ret != 0) {
- printk(KERN_ERR "Device Register failed =%d\n", ret);
- ret = -ENODEV;
- platform_device_unregister(&omap_audio_device);
- goto register_out;
- }
-
- register_out:
-
- FN_OUT(ret);
- return ret;
-}
-
-/*********************************************************************************
- *
- * audio_unregister_codec(): Un-Register a Codec using this function
- *
- *********************************************************************************/
-int audio_unregister_codec(audio_state_t * codec_state)
-{
- FN_IN;
-
- /* We dont handle multiple codecs now */
- if (!audio_state.hw_init) {
- printk(KERN_ERR " No Codec registered\n");
- return -EPERM;
- }
- /* Security check */
- if (audio_state.hw_init != codec_state->hw_init) {
- printk(KERN_ERR
- " Attempt to unregister codec which was not registered with us\n");
- return -EPERM;
- }
-
- platform_driver_unregister(&omap_audio_driver);
- platform_device_unregister(&omap_audio_device);
-
- memset(&audio_state, 0, sizeof(audio_state_t));
-
- FN_OUT(0);
- return 0;
-}
-
-/***************************** MODULES SPECIFIC FUNCTION *************************/
-
-/*********************************************************************************
- *
- * audio_write(): Exposed to write() call
- *
- *********************************************************************************/
-static int
-audio_write(struct file *file, const char __user *buffer,
- size_t count, loff_t * ppos)
-{
- const char __user *buffer0 = buffer;
- audio_state_t *state = file->private_data;
- audio_stream_t *s = state->output_stream;
- int chunksize, ret = 0;
-
- DPRINTK("audio_write: count=%d\n", count);
- if (*ppos != file->f_pos) {
- printk("FPOS not ppos ppos=0x%x fpos =0x%x\n", (u32) * ppos,
- (u32) file->f_pos);
- return -ESPIPE;
- }
- if (s->mapped) {
- printk("s already mapped\n");
- return -ENXIO;
- }
- if (!s->buffers && audio_setup_buf(s)) {
- printk("NO MEMORY\n");
- return -ENOMEM;
- }
-
- while (count > 0) {
- audio_buf_t *b = &s->buffers[s->usr_head];
-
- /* Wait for a buffer to become free */
- if (file->f_flags & O_NONBLOCK) {
- ret = -EAGAIN;
- if (!s->wfc.done)
- break;
- }
- ret = -ERESTARTSYS;
- if (wait_for_completion_interruptible(&s->wfc))
- break;
-
- /* Feed the current buffer */
- chunksize = s->fragsize - b->offset;
- if (chunksize > count)
- chunksize = count;
- DPRINTK("write %d to %d\n", chunksize, s->usr_head);
- if (copy_from_user(b->data + b->offset, buffer, chunksize)) {
- printk(KERN_ERR "Audio: CopyFrom User failed \n");
- complete(&s->wfc);
- return -EFAULT;
- }
-
- buffer += chunksize;
- count -= chunksize;
- b->offset += chunksize;
-
- if (b->offset < s->fragsize) {
- complete(&s->wfc);
- break;
- }
-
- /* Update pointers and send current fragment to DMA */
- b->offset = 0;
- if (++s->usr_head >= s->nbfrags)
- s->usr_head = 0;
- /* Add the num of frags pending */
- s->pending_frags++;
- s->active = 1;
-
- audio_process_dma(s);
-
- }
-
- if ((buffer - buffer0))
- ret = buffer - buffer0;
- DPRINTK("audio_write: return=%d\n", ret);
- return ret;
-}
-
-/*********************************************************************************
- *
- * audio_read(): Exposed as read() function
- *
- *********************************************************************************/
-static int
-audio_read(struct file *file, char __user *buffer, size_t count, loff_t * ppos)
-{
- char __user *buffer0 = buffer;
- audio_state_t *state = file->private_data;
- audio_stream_t *s = state->input_stream;
- int chunksize, ret = 0;
- unsigned long flags;
-
- DPRINTK("audio_read: count=%d\n", count);
-
- if (*ppos != file->f_pos) {
- printk("AudioRead - FPOS not ppos ppos=0x%x fpos =0x%x\n",
- (u32) * ppos, (u32) file->f_pos);
- return -ESPIPE;
- }
- if (s->mapped) {
- printk("AudioRead - s already mapped\n");
- return -ENXIO;
- }
-
- if (!s->active) {
- if (!s->buffers && audio_setup_buf(s)) {
- printk("AudioRead - No Memory\n");
- return -ENOMEM;
- }
- audio_prime_rx(state);
- }
-
- while (count > 0) {
- audio_buf_t *b = &s->buffers[s->usr_head];
-
- /* Wait for a buffer to become full */
- if (file->f_flags & O_NONBLOCK) {
- ret = -EAGAIN;
- if (!s->wfc.done)
- break;
- }
- ret = -ERESTARTSYS;
- if (wait_for_completion_interruptible(&s->wfc))
- break;
-
- /* Grab data from the current buffer */
- chunksize = s->fragsize - b->offset;
- if (chunksize > count)
- chunksize = count;
- DPRINTK("read %d from %d\n", chunksize, s->usr_head);
- if (copy_to_user(buffer, b->data + b->offset, chunksize)) {
- complete(&s->wfc);
- return -EFAULT;
- }
- buffer += chunksize;
- count -= chunksize;
- b->offset += chunksize;
- if (b->offset < s->fragsize) {
- complete(&s->wfc);
- break;
- }
-
- /* Update pointers and return current fragment to DMA */
- local_irq_save(flags);
- b->offset = 0;
- if (++s->usr_head >= s->nbfrags)
- s->usr_head = 0;
-
- s->pending_frags++;
- local_irq_restore(flags);
- audio_process_dma(s);
-
- }
-
- if ((buffer - buffer0))
- ret = buffer - buffer0;
- DPRINTK("audio_read: return=%d\n", ret);
- return ret;
-}
-
-/*********************************************************************************
- *
- * audio_mmap(): Exposed as mmap Function
- * !!WARNING: Still under development
- *
- *********************************************************************************/
-static int audio_mmap(struct file *file, struct vm_area_struct *vma)
-{
- audio_state_t *state = file->private_data;
- audio_stream_t *s;
- unsigned long size, vma_addr;
- int i, ret;
-
- FN_IN;
- if (vma->vm_pgoff != 0)
- return -EINVAL;
-
- if (vma->vm_flags & VM_WRITE) {
- if (!state->wr_ref)
- return -EINVAL;;
- s = state->output_stream;
- } else if (vma->vm_flags & VM_READ) {
- if (!state->rd_ref)
- return -EINVAL;
- s = state->input_stream;
- } else
- return -EINVAL;
-
- if (s->mapped)
- return -EINVAL;
- size = vma->vm_end - vma->vm_start;
- if (size != s->fragsize * s->nbfrags)
- return -EINVAL;
- if (!s->buffers && audio_setup_buf(s))
- return -ENOMEM;
- vma_addr = vma->vm_start;
- for (i = 0; i < s->nbfrags; i++) {
- audio_buf_t *buf = &s->buffers[i];
- if (!buf->master)
- continue;
- ret =
- remap_pfn_range(vma, vma_addr, buf->dma_addr >> PAGE_SHIFT,
- buf->master, vma->vm_page_prot);
- if (ret)
- return ret;
- vma_addr += buf->master;
- }
- s->mapped = 1;
-
- FN_OUT(0);
- return 0;
-}
-
-/*********************************************************************************
- *
- * audio_poll(): Exposed as poll function
- *
- *********************************************************************************/
-static unsigned int
-audio_poll(struct file *file, struct poll_table_struct *wait)
-{
- audio_state_t *state = file->private_data;
- audio_stream_t *is = state->input_stream;
- audio_stream_t *os = state->output_stream;
- unsigned int mask = 0;
-
- DPRINTK("audio_poll(): mode=%s%s\n",
- (file->f_mode & FMODE_READ) ? "r" : "",
- (file->f_mode & FMODE_WRITE) ? "w" : "");
-
- if (file->f_mode & FMODE_READ) {
- /* Start audio input if not already active */
- if (!is->active) {
- if (!is->buffers && audio_setup_buf(is))
- return -ENOMEM;
- audio_prime_rx(state);
- }
- poll_wait(file, &is->wq, wait);
- }
-
- if (file->f_mode & FMODE_WRITE) {
- if (!os->buffers && audio_setup_buf(os))
- return -ENOMEM;
- poll_wait(file, &os->wq, wait);
- }
-
- if (file->f_mode & FMODE_READ)
- if ((is->mapped && is->bytecount > 0) ||
- (!is->mapped && is->wfc.done > 0))
- mask |= POLLIN | POLLRDNORM;
-
- if (file->f_mode & FMODE_WRITE)
- if ((os->mapped && os->bytecount > 0) ||
- (!os->mapped && os->wfc.done > 0))
- mask |= POLLOUT | POLLWRNORM;
-
- DPRINTK("audio_poll() returned mask of %s%s\n",
- (mask & POLLIN) ? "r" : "", (mask & POLLOUT) ? "w" : "");
-
- FN_OUT(mask);
- return mask;
-}
-
-/*********************************************************************************
- *
- * audio_llseek(): Exposed as lseek() function.
- *
- *********************************************************************************/
-static loff_t audio_llseek(struct file *file, loff_t offset, int origin)
-{
- FN_IN;
- FN_OUT(0);
- return -ESPIPE;
-}
-
-/*********************************************************************************
- *
- * audio_ioctl(): Handles generic ioctls. If there is a request for something this
- * fn cannot handle, its then given to client specific ioctl routine, that will take
- * up platform specific requests
- *
- *********************************************************************************/
-static int
-audio_ioctl(struct inode *inode, struct file *file, uint cmd, ulong arg)
-{
- audio_state_t *state = file->private_data;
- audio_stream_t *os = state->output_stream;
- audio_stream_t *is = state->input_stream;
- long val;
-
- DPRINTK(__FILE__ " audio_ioctl 0x%08x\n", cmd);
-
- /* dispatch based on command */
- switch (cmd) {
- case OSS_GETVERSION:
- return put_user(SOUND_VERSION, (int __user *)arg);
-
- case SNDCTL_DSP_GETBLKSIZE:
- if (file->f_mode & FMODE_WRITE)
- return put_user(os->fragsize, (int __user *)arg);
- else
- return put_user(is->fragsize, (int __user *)arg);
-
- case SNDCTL_DSP_GETCAPS:
- val = DSP_CAP_REALTIME | DSP_CAP_TRIGGER | DSP_CAP_MMAP;
- if (is && os)
- val |= DSP_CAP_DUPLEX;
- FN_OUT(1);
- return put_user(val, (int __user *)arg);
-
- case SNDCTL_DSP_SETFRAGMENT:
- if (get_user(val, (long __user *)arg)) {
- FN_OUT(2);
- return -EFAULT;
- }
- if (file->f_mode & FMODE_READ) {
- int ret = audio_set_fragments(is, val);
- if (ret < 0) {
- FN_OUT(3);
- return ret;
- }
- ret = put_user(ret, (int __user *)arg);
- if (ret) {
- FN_OUT(4);
- return ret;
- }
- }
- if (file->f_mode & FMODE_WRITE) {
- int ret = audio_set_fragments(os, val);
- if (ret < 0) {
- FN_OUT(5);
- return ret;
- }
- ret = put_user(ret, (int __user *)arg);
- if (ret) {
- FN_OUT(6);
- return ret;
- }
- }
- FN_OUT(7);
- return 0;
-
- case SNDCTL_DSP_SYNC:
- FN_OUT(8);
- return audio_sync(file);
-
- case SNDCTL_DSP_SETDUPLEX:
- FN_OUT(9);
- return 0;
-
- case SNDCTL_DSP_POST:
- FN_OUT(10);
- return 0;
-
- case SNDCTL_DSP_GETTRIGGER:
- val = 0;
- if (file->f_mode & FMODE_READ && is->active && !is->stopped)
- val |= PCM_ENABLE_INPUT;
- if (file->f_mode & FMODE_WRITE && os->active && !os->stopped)
- val |= PCM_ENABLE_OUTPUT;
- FN_OUT(11);
- return put_user(val, (int __user *)arg);
-
- case SNDCTL_DSP_SETTRIGGER:
- if (get_user(val, (int __user *)arg)) {
- FN_OUT(12);
- return -EFAULT;
- }
- if (file->f_mode & FMODE_READ) {
- if (val & PCM_ENABLE_INPUT) {
- unsigned long flags;
- if (!is->active) {
- if (!is->buffers && audio_setup_buf(is)) {
- FN_OUT(13);
- return -ENOMEM;
- }
- audio_prime_rx(state);
- }
- local_irq_save(flags);
- is->stopped = 0;
- local_irq_restore(flags);
- audio_process_dma(is);
-
- } else {
- audio_stop_dma(is);
- }
- }
- if (file->f_mode & FMODE_WRITE) {
- if (val & PCM_ENABLE_OUTPUT) {
- unsigned long flags;
- if (!os->buffers && audio_setup_buf(os)) {
- FN_OUT(14);
- return -ENOMEM;
- }
- local_irq_save(flags);
- if (os->mapped && !os->pending_frags) {
- os->pending_frags = os->nbfrags;
- init_completion(&os->wfc);
- os->wfc.done = 0;
- os->active = 1;
- }
- os->stopped = 0;
- local_irq_restore(flags);
- audio_process_dma(os);
-
- } else {
- audio_stop_dma(os);
- }
- }
- FN_OUT(15);
- return 0;
-
- case SNDCTL_DSP_GETOPTR:
- case SNDCTL_DSP_GETIPTR:
- {
- count_info inf = { 0, };
- audio_stream_t *s =
- (cmd == SNDCTL_DSP_GETOPTR) ? os : is;
- int bytecount, offset;
- unsigned long flags;
-
- if ((s == is && !(file->f_mode & FMODE_READ)) ||
- (s == os && !(file->f_mode & FMODE_WRITE))) {
- FN_OUT(16);
- return -EINVAL;
- }
- if (s->active) {
- local_irq_save(flags);
- offset = audio_get_dma_pos(s);
- inf.ptr = s->dma_tail * s->fragsize + offset;
- bytecount = s->bytecount + offset;
- s->bytecount = -offset;
- inf.blocks = s->fragcount;
- s->fragcount = 0;
- local_irq_restore(flags);
- if (bytecount < 0)
- bytecount = 0;
- inf.bytes = bytecount;
- }
- FN_OUT(17);
- return copy_to_user((void __user *)arg, &inf, sizeof(inf));
- }
-
- case SNDCTL_DSP_GETOSPACE:
- case SNDCTL_DSP_GETISPACE:
- {
- audio_buf_info inf = { 0, };
- audio_stream_t *s =
- (cmd == SNDCTL_DSP_GETOSPACE) ? os : is;
-
- if ((s == is && !(file->f_mode & FMODE_READ)) ||
- (s == os && !(file->f_mode & FMODE_WRITE))) {
- FN_OUT(18);
- return -EINVAL;
- }
- if (!s->buffers && audio_setup_buf(s)) {
- FN_OUT(19);
- return -ENOMEM;
- }
- inf.bytes = s->wfc.done * s->fragsize;
-
- inf.fragments = inf.bytes / s->fragsize;
- inf.fragsize = s->fragsize;
- inf.fragstotal = s->nbfrags;
- FN_OUT(20);
- return copy_to_user((void __user *)arg, &inf, sizeof(inf));
- }
-
- case SNDCTL_DSP_NONBLOCK:
- file->f_flags |= O_NONBLOCK;
- FN_OUT(21);
- return 0;
-
- case SNDCTL_DSP_RESET:
- if (file->f_mode & FMODE_READ) {
- audio_reset(is);
- if (state->need_tx_for_rx) {
- unsigned long flags;
- local_irq_save(flags);
- os->spin_idle = 0;
- local_irq_restore(flags);
- }
- }
- if (file->f_mode & FMODE_WRITE) {
- audio_reset(os);
- }
- FN_OUT(22);
- return 0;
-
- default:
- /*
- * Let the client of this module handle the
- * non generic ioctls
- */
- FN_OUT(23);
- return state->client_ioctl(inode, file, cmd, arg);
- }
-
- FN_OUT(0);
- return 0;
-}
-
-/*********************************************************************************
- *
- * audio_open(): Exposed as open() function
- *
- *********************************************************************************/
-static int audio_open(struct inode *inode, struct file *file)
-{
- audio_state_t *state = (&audio_state);
- audio_stream_t *os = state->output_stream;
- audio_stream_t *is = state->input_stream;
- int err, need_tx_dma;
- static unsigned char tsc2101_init_flag = 0;
-
- FN_IN;
-
- /* Lock the module */
- if (!try_module_get(THIS_MODULE)) {
- printk(KERN_CRIT "Failed to get module\n");
- return -ESTALE;
- }
- /* Lock the codec module */
- if (!try_module_get(state->owner)) {
- printk(KERN_CRIT "Failed to get codec module\n");
- module_put(THIS_MODULE);
- return -ESTALE;
- }
-
- mutex_lock(&state->mutex);
-
- /* access control */
- err = -ENODEV;
- if ((file->f_mode & FMODE_WRITE) && !os)
- goto out;
- if ((file->f_mode & FMODE_READ) && !is)
- goto out;
- err = -EBUSY;
- if ((file->f_mode & FMODE_WRITE) && state->wr_ref)
- goto out;
- if ((file->f_mode & FMODE_READ) && state->rd_ref)
- goto out;
- err = -EINVAL;
- if ((file->f_mode & FMODE_READ) && state->need_tx_for_rx && !os)
- goto out;
-
- /* request DMA channels */
- need_tx_dma = ((file->f_mode & FMODE_WRITE) ||
- ((file->f_mode & FMODE_READ) && state->need_tx_for_rx));
- if (state->wr_ref || (state->rd_ref && state->need_tx_for_rx))
- need_tx_dma = 0;
- if (need_tx_dma) {
- DMA_REQUEST(err, os, audio_dma_callback);
- if (err < 0)
- goto out;
- }
- if (file->f_mode & FMODE_READ) {
- DMA_REQUEST(err, is, audio_dma_callback);
- if (err < 0) {
- if (need_tx_dma)
- DMA_FREE(os);
- goto out;
- }
- }
-
- /* now complete initialisation */
- if (!AUDIO_ACTIVE(state)) {
- if (state->hw_init && !tsc2101_init_flag) {
- state->hw_init(state->data);
- tsc2101_init_flag = 0;
-
- }
-
- }
-
- if ((file->f_mode & FMODE_WRITE)) {
- state->wr_ref = 1;
- audio_reset(os);
- os->fragsize = AUDIO_FRAGSIZE_DEFAULT;
- os->nbfrags = AUDIO_NBFRAGS_DEFAULT;
- os->mapped = 0;
- init_waitqueue_head(&os->wq);
- }
-
- if (file->f_mode & FMODE_READ) {
- state->rd_ref = 1;
- audio_reset(is);
- is->fragsize = AUDIO_FRAGSIZE_DEFAULT;
- is->nbfrags = AUDIO_NBFRAGS_DEFAULT;
- is->mapped = 0;
- init_waitqueue_head(&is->wq);
- }
-
- file->private_data = state;
- err = 0;
-
- out:
- mutex_unlock(&state->mutex);
- if (err) {
- module_put(state->owner);
- module_put(THIS_MODULE);
- }
- FN_OUT(err);
- return err;
-}
-
-/*********************************************************************************
- *
- * audio_release(): Exposed as release function()
- *
- *********************************************************************************/
-static int audio_release(struct inode *inode, struct file *file)
-{
- audio_state_t *state = file->private_data;
- audio_stream_t *os = state->output_stream;
- audio_stream_t *is = state->input_stream;
-
- FN_IN;
-
- mutex_lock(&state->mutex);
-
- if (file->f_mode & FMODE_READ) {
- audio_discard_buf(is);
- DMA_FREE(is);
- is->dma_spinref = 0;
- if (state->need_tx_for_rx) {
- os->spin_idle = 0;
- if (!state->wr_ref) {
- DMA_FREE(os);
- os->dma_spinref = 0;
- }
- }
- state->rd_ref = 0;
- }
-
- if (file->f_mode & FMODE_WRITE) {
- audio_sync(file);
- audio_discard_buf(os);
- if (!state->need_tx_for_rx || !state->rd_ref) {
- DMA_FREE(os);
- os->dma_spinref = 0;
- }
- state->wr_ref = 0;
- }
-
- if (!AUDIO_ACTIVE(state)) {
- if (state->hw_shutdown)
- state->hw_shutdown(state->data);
- }
-
- mutex_unlock(&state->mutex);
-
- module_put(state->owner);
- module_put(THIS_MODULE);
-
- FN_OUT(0);
- return 0;
-}
-
-EXPORT_SYMBOL(audio_register_codec);
-EXPORT_SYMBOL(audio_unregister_codec);
-EXPORT_SYMBOL(audio_get_fops);
-
-MODULE_AUTHOR("Texas Instruments");
-MODULE_DESCRIPTION("Common audio handling for OMAP processors");
-MODULE_LICENSE("GPL");
+++ /dev/null
-/*
- * linux/sound/oss/omap-audio.h
- *
- * Common audio handling for the OMAP processors
- *
- * Copyright (C) 2004 Texas Instruments, Inc.
- *
- * Copyright (C) 2000, 2001 Nicolas Pitre <nico@cam.org>
- *
- * This package is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * THIS PACKAGE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
- * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
- * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
- *
- * History
- * -------
- * 2004/08/12 Nishanth Menon - Modified to integrate Audio requirements on 1610,1710 platforms
- *
- * 2004/04/04 Nishanth menon - Added hooks for power management
- *
- * 2005/12/10 Dirk Behme - Added L/R Channel Interchange fix as proposed by Ajaya Babu
- */
-
-#ifndef __OMAP_AUDIO_H
-#define __OMAP_AUDIO_H
-
-/* Requires dma.h */
-#include <mach/dma.h>
-
-/*
- * Buffer Management
- */
-typedef struct {
- int offset; /* current offset */
- char *data; /* points to actual buffer */
- dma_addr_t dma_addr; /* physical buffer address */
- int dma_ref; /* DMA refcount */
- int master; /* owner for buffer allocation, contain size when true */
-} audio_buf_t;
-
-/*
- * Structure describing the data stream related information
- */
-typedef struct {
- char *id; /* identification string */
- audio_buf_t *buffers; /* pointer to audio buffer structures */
- u_int usr_head; /* user fragment index */
- u_int dma_head; /* DMA fragment index to go */
- u_int dma_tail; /* DMA fragment index to complete */
- u_int fragsize; /* fragment i.e. buffer size */
- u_int nbfrags; /* nbr of fragments i.e. buffers */
- u_int pending_frags; /* Fragments sent to DMA */
- int dma_dev; /* device identifier for DMA */
-
-#ifdef OMAP_DMA_CHAINING_SUPPORT
- lch_chain *dma_chain;
- dma_regs_t *dma_regs; /* points to our DMA registers */
-#else
- char started; /* to store if the chain was started or not */
- int dma_q_head; /* DMA Channel Q Head */
- int dma_q_tail; /* DMA Channel Q Tail */
- char dma_q_count; /* DMA Channel Q Count */
- char in_use; /* Is this is use? */
- int *lch; /* Chain of channels this stream is linked to */
-#endif
- int input_or_output; /* Direction of this data stream */
- int bytecount; /* nbr of processed bytes */
- int fragcount; /* nbr of fragment transitions */
- struct completion wfc; /* wait for "nbfrags" fragment completion */
- wait_queue_head_t wq; /* for poll */
- int dma_spinref; /* DMA is spinning */
- unsigned mapped:1; /* mmap()'ed buffers */
- unsigned active:1; /* actually in progress */
- unsigned stopped:1; /* might be active but stopped */
- unsigned spin_idle:1; /* have DMA spin on zeros when idle */
- unsigned linked:1; /* dma channels linked */
- int (*hw_start)(void); /* interface to start HW interface, e.g. McBSP */
- int (*hw_stop)(void); /* interface to stop HW interface, e.g. McBSP */
-} audio_stream_t;
-
-/*
- * State structure for one instance
- */
-typedef struct {
- struct module *owner; /* Codec module ID */
- audio_stream_t *output_stream;
- audio_stream_t *input_stream;
- unsigned rd_ref:1; /* open reference for recording */
- unsigned wr_ref:1; /* open reference for playback */
- unsigned need_tx_for_rx:1; /* if data must be sent while receiving */
- void *data;
- void (*hw_init) (void *);
- void (*hw_shutdown) (void *);
- int (*client_ioctl) (struct inode *, struct file *, uint, ulong);
- int (*hw_probe) (void);
- void (*hw_remove) (void);
- void (*hw_cleanup) (void);
- int (*hw_suspend) (void);
- int (*hw_resume) (void);
- struct pm_dev *pm_dev;
- struct mutex mutex; /* to protect against races in attach() */
-} audio_state_t;
-
-#ifdef AUDIO_PM
-void audio_ldm_suspend(void *data);
-
-void audio_ldm_resume(void *data);
-
-#endif
-
-/* Register a Codec using this function */
-extern int audio_register_codec(audio_state_t * codec_state);
-/* Un-Register a Codec using this function */
-extern int audio_unregister_codec(audio_state_t * codec_state);
-/* Function to provide fops of omap audio driver */
-extern struct file_operations *audio_get_fops(void);
-/* Function to initialize the device info for audio driver */
-extern int audio_dev_init(void);
-/* Function to un-initialize the device info for audio driver */
-void audio_dev_uninit(void);
-
-#endif /* End of #ifndef __OMAP_AUDIO_H */