From: Tony Lindgren Date: Mon, 27 Oct 2008 20:25:17 +0000 (-0700) Subject: REMOVE OMAP LEGACY CODE: Delete all old omap specific sound drivers X-Git-Tag: v2.6.28-omap1~217 X-Git-Url: http://pilppa.com/gitweb/?a=commitdiff_plain;h=9fa298dc5f0b3e343337848b63c850e1a89d2d59;p=linux-2.6-omap-h63xx.git REMOVE OMAP LEGACY CODE: Delete all old omap specific sound drivers All omap boards should be using sound/soc. Any development must be done on the alsa mailing list with linux-omap list cc'd. Signed-off-by: Tony Lindgren --- diff --git a/sound/arm/Kconfig b/sound/arm/Kconfig index 3e4b26349f4..f8e6de48d81 100644 --- a/sound/arm/Kconfig +++ b/sound/arm/Kconfig @@ -50,68 +50,5 @@ config SND_PXA2XX_AC97 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 + diff --git a/sound/arm/Makefile b/sound/arm/Makefile index b55e17bd221..2054de11de8 100644 --- a/sound/arm/Makefile +++ b/sound/arm/Makefile @@ -17,5 +17,3 @@ snd-pxa2xx-lib-$(CONFIG_SND_PXA2XX_LIB_AC97) += pxa2xx-ac97-lib.o obj-$(CONFIG_SND_PXA2XX_AC97) += snd-pxa2xx-ac97.o snd-pxa2xx-ac97-objs := pxa2xx-ac97.o - -obj-$(CONFIG_SND) += omap/ diff --git a/sound/arm/omap/Makefile b/sound/arm/omap/Makefile deleted file mode 100644 index 2f004d7102e..00000000000 --- a/sound/arm/omap/Makefile +++ /dev/null @@ -1,18 +0,0 @@ -# -## 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 diff --git a/sound/arm/omap/eac.c b/sound/arm/omap/eac.c deleted file mode 100644 index 667051e6bc9..00000000000 --- a/sound/arm/omap/eac.c +++ /dev/null @@ -1,803 +0,0 @@ -/* - * linux/sound/arm/omap/omap-alsa-eac.c - * - * OMAP24xx Enhanced Audio Controller sound driver - * - * Copyright (C) 2006 Nokia Corporation - * - * Contact: Jarkko Nikula - * 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 -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include - -#include -#include - - -#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 "); -MODULE_LICENSE("GPL"); diff --git a/sound/arm/omap/omap-alsa-aic23-mixer.c b/sound/arm/omap/omap-alsa-aic23-mixer.c deleted file mode 100644 index da2a875f417..00000000000 --- a/sound/arm/omap/omap-alsa-aic23-mixer.c +++ /dev/null @@ -1,523 +0,0 @@ -/* - * 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 - * - * 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 - -#include - -#include -#include "omap-alsa-aic23.h" -#include -#include - -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; -} diff --git a/sound/arm/omap/omap-alsa-aic23.c b/sound/arm/omap/omap-alsa-aic23.c deleted file mode 100644 index 9820e51c2e9..00000000000 --- a/sound/arm/omap/omap-alsa-aic23.c +++ /dev/null @@ -1,327 +0,0 @@ -/* - * 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 - * - * 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 -#include -#include -#include -#include -#include -#include - -#include -#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); diff --git a/sound/arm/omap/omap-alsa-aic23.h b/sound/arm/omap/omap-alsa-aic23.h deleted file mode 100644 index 5431b022699..00000000000 --- a/sound/arm/omap/omap-alsa-aic23.h +++ /dev/null @@ -1,86 +0,0 @@ -/* - * 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 - * - * 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 -#include -#include -#include - -/* 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 diff --git a/sound/arm/omap/omap-alsa-dma.c b/sound/arm/omap/omap-alsa-dma.c deleted file mode 100644 index b2623cbb53f..00000000000 --- a/sound/arm/omap/omap-alsa-dma.c +++ /dev/null @@ -1,437 +0,0 @@ -/* - * sound/arm/omap/omap-alsa-dma.c - * - * Common audio DMA handling for the OMAP processors - * - * Copyright (C) 2006 Mika Laitio - * - * Copyright (C) 2005 Instituto Nokia de Tecnologia - INdT - Manaus Brazil - * - * Copyright (C) 2004 Texas Instruments, Inc. - * - * Copyright (C) 2000, 2001 Nicolas Pitre - * - * 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 -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include - -#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"); - diff --git a/sound/arm/omap/omap-alsa-dma.h b/sound/arm/omap/omap-alsa-dma.h deleted file mode 100644 index 0dcd3791418..00000000000 --- a/sound/arm/omap/omap-alsa-dma.h +++ /dev/null @@ -1,53 +0,0 @@ -/* - * linux/sound/arm/omap/omap-alsa-dma.h - * - * Common audio DMA handling for the OMAP processors - * - * Copyright (C) 2006 Mika Laitio - * - * Copyright (C) 2005 Instituto Nokia de Tecnologia - INdT - Manaus Brazil - * - * Copyright (C) 2004 Texas Instruments, Inc. - * - * Copyright (C) 2000, 2001 Nicolas Pitre - * - * 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 - -/* 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 diff --git a/sound/arm/omap/omap-alsa-sx1-mixer.c b/sound/arm/omap/omap-alsa-sx1-mixer.c deleted file mode 100644 index d0c3322378f..00000000000 --- a/sound/arm/omap/omap-alsa-sx1-mixer.c +++ /dev/null @@ -1,470 +0,0 @@ -/* - * 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 -#include -#include - -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; -} diff --git a/sound/arm/omap/omap-alsa-sx1-mixer.h b/sound/arm/omap/omap-alsa-sx1-mixer.h deleted file mode 100644 index 7d5538865af..00000000000 --- a/sound/arm/omap/omap-alsa-sx1-mixer.h +++ /dev/null @@ -1,48 +0,0 @@ -/* - * 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 diff --git a/sound/arm/omap/omap-alsa-sx1.c b/sound/arm/omap/omap-alsa-sx1.c deleted file mode 100644 index 62530430fd9..00000000000 --- a/sound/arm/omap/omap-alsa-sx1.c +++ /dev/null @@ -1,306 +0,0 @@ -/* - * 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 -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include - -#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); diff --git a/sound/arm/omap/omap-alsa-sx1.h b/sound/arm/omap/omap-alsa-sx1.h deleted file mode 100644 index 9e11e0abfa2..00000000000 --- a/sound/arm/omap/omap-alsa-sx1.h +++ /dev/null @@ -1,69 +0,0 @@ -/* - * 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 - -#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 diff --git a/sound/arm/omap/omap-alsa-tsc2101-mixer.c b/sound/arm/omap/omap-alsa-tsc2101-mixer.c deleted file mode 100644 index d443342260a..00000000000 --- a/sound/arm/omap/omap-alsa-tsc2101-mixer.c +++ /dev/null @@ -1,1185 +0,0 @@ -/* - * sound/arm/omap/omap-alsa-tsc2101-mixer.c - * - * Alsa Driver for TSC2101 codec for OMAP platform boards. - * - * Copyright (C) 2005 Mika Laitio and - * Everett Coleman II - * - * 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 -#include -#include -#include - -#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; -} diff --git a/sound/arm/omap/omap-alsa-tsc2101-mixer.h b/sound/arm/omap/omap-alsa-tsc2101-mixer.h deleted file mode 100644 index c0d9b235da0..00000000000 --- a/sound/arm/omap/omap-alsa-tsc2101-mixer.h +++ /dev/null @@ -1,88 +0,0 @@ -/* - * sound/arm/omap/omap-alsa-tsc2101-mixer.h - * - * Alsa Driver for TSC2101 codec for OMAP platform boards. - * - * Copyright (C) 2005 Mika Laitio and - * Everett Coleman II - * - * 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 - * - * 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 -#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_*/ diff --git a/sound/arm/omap/omap-alsa-tsc2101.c b/sound/arm/omap/omap-alsa-tsc2101.c deleted file mode 100644 index 6b0e1063346..00000000000 --- a/sound/arm/omap/omap-alsa-tsc2101.c +++ /dev/null @@ -1,543 +0,0 @@ -/* - * 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 - * - * 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 -#include -#include -#include -#include -#include -#include -#ifdef CONFIG_PM -#include -#endif - -#include -#include -#include -#include -#include -#include - -#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); diff --git a/sound/arm/omap/omap-alsa-tsc2101.h b/sound/arm/omap/omap-alsa-tsc2101.h deleted file mode 100644 index fb038015971..00000000000 --- a/sound/arm/omap/omap-alsa-tsc2101.h +++ /dev/null @@ -1,67 +0,0 @@ -/* - * 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 - * - * 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 - -/* 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_*/ diff --git a/sound/arm/omap/omap-alsa-tsc2102-mixer.c b/sound/arm/omap/omap-alsa-tsc2102-mixer.c deleted file mode 100644 index 74c1fd6de0b..00000000000 --- a/sound/arm/omap/omap-alsa-tsc2102-mixer.c +++ /dev/null @@ -1,284 +0,0 @@ -/* - * sound/arm/omap/omap-alsa-tsc2102-mixer.c - * - * Alsa mixer driver for TSC2102 chip for OMAP platforms. - * - * Copyright (c) 2006 Andrzej Zaborowski - * 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 -#include - -#include - -#include -#include - -#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; -} diff --git a/sound/arm/omap/omap-alsa-tsc2102.c b/sound/arm/omap/omap-alsa-tsc2102.c deleted file mode 100644 index 4c34f7cf312..00000000000 --- a/sound/arm/omap/omap-alsa-tsc2102.c +++ /dev/null @@ -1,318 +0,0 @@ -/* - * sound/arm/omap/omap-alsa-tsc2102.c - * - * Alsa codec driver for TSC2102 chip for OMAP platforms. - * - * Copyright (c) 2006 Andrzej Zaborowski - * 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 -#include -#include -#include -#include -#include -#include - -#include -#include -#include - -#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); diff --git a/sound/arm/omap/omap-alsa-tsc2102.h b/sound/arm/omap/omap-alsa-tsc2102.h deleted file mode 100644 index 0e0c097dfcd..00000000000 --- a/sound/arm/omap/omap-alsa-tsc2102.h +++ /dev/null @@ -1,42 +0,0 @@ -/* - * sound/arm/omap/omap-alsa-tsc2102.h - * - * Alsa codec driver for TSC2102 chip for OMAP platforms. - * - * Copyright (c) 2006 Andrzej Zaborowski - * 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_ */ diff --git a/sound/arm/omap/omap-alsa.c b/sound/arm/omap/omap-alsa.c deleted file mode 100644 index 45c46e2dfb1..00000000000 --- a/sound/arm/omap/omap-alsa.c +++ /dev/null @@ -1,591 +0,0 @@ -/* - * 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 - * - * Based on sa11xx-uda1341.c, - * Copyright (C) 2002 Tomas Kasparek - * - * 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 -#ifdef CONFIG_PM -#include -#endif -#include -#include - -#include -#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; -} diff --git a/sound/oss/Makefile b/sound/oss/Makefile index bd8fd056f7f..e0ae4d4d6a5 100644 --- a/sound/oss/Makefile +++ b/sound/oss/Makefile @@ -7,10 +7,6 @@ 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 diff --git a/sound/oss/omap-audio-aic23.c b/sound/oss/omap-audio-aic23.c deleted file mode 100644 index c603aaa18d5..00000000000 --- a/sound/oss/omap-audio-aic23.c +++ /dev/null @@ -1,754 +0,0 @@ -/* - * linux/sound/oss/omap-audio-aic23.c - * - * Glue audio driver for TI TLV320AIC23 codec - * - * Copyright (c) 2000 Nicolas Pitre - * Copyright (C) 2001, Steve Johnson - * Copyright (C) 2004 Texas Instruments, Inc. - * Copyright (C) 2005 Dirk Behme - * - * 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 -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include - -#include -#include -#include -#include - -#include "omap-audio.h" -#include "omap-audio-dma-intfc.h" - -#ifdef CONFIG_PROC_FS -#include -#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 "); -MODULE_DESCRIPTION("Glue audio driver for the TI AIC23 codec."); -MODULE_LICENSE("GPL"); diff --git a/sound/oss/omap-audio-dma-intfc.c b/sound/oss/omap-audio-dma-intfc.c deleted file mode 100644 index c6a61369eab..00000000000 --- a/sound/oss/omap-audio-dma-intfc.c +++ /dev/null @@ -1,985 +0,0 @@ -/* - * 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 - * - * 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 -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include - -#include -#include "omap-audio-dma-intfc.h" - -#include - -#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); diff --git a/sound/oss/omap-audio-dma-intfc.h b/sound/oss/omap-audio-dma-intfc.h deleted file mode 100644 index 65aa528f21c..00000000000 --- a/sound/oss/omap-audio-dma-intfc.h +++ /dev/null @@ -1,63 +0,0 @@ -/* - * 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 - * - * 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 */ diff --git a/sound/oss/omap-audio-tsc2101.c b/sound/oss/omap-audio-tsc2101.c deleted file mode 100644 index 4931ecf93dc..00000000000 --- a/sound/oss/omap-audio-tsc2101.c +++ /dev/null @@ -1,1237 +0,0 @@ -/* - * 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 -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include - -#include -#include -#include - -#include "omap-audio.h" -#include "omap-audio-dma-intfc.h" -#include -#ifdef CONFIG_ARCH_OMAP16XX -#include <../drivers/ssi/omap-uwire.h> -#include -#elif defined(CONFIG_ARCH_OMAP24XX) -#else -#error "Unsupported configuration" -#endif - -#include -#include <../drivers/ssi/omap-tsc2101.h> - -/***************************** MACROS ************************************/ - -#define PROC_SUPPORT - -#ifdef PROC_SUPPORT -#include -#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"); diff --git a/sound/oss/omap-audio.c b/sound/oss/omap-audio.c deleted file mode 100644 index 95b5eef1184..00000000000 --- a/sound/oss/omap-audio.c +++ /dev/null @@ -1,1162 +0,0 @@ -/* - * 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 - * - * 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 -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include - -#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"); diff --git a/sound/oss/omap-audio.h b/sound/oss/omap-audio.h deleted file mode 100644 index 895d8031d7c..00000000000 --- a/sound/oss/omap-audio.h +++ /dev/null @@ -1,125 +0,0 @@ -/* - * 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 - * - * 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 - -/* - * 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 */