mirror of https://gitee.com/openkylin/linux.git
ASoC: remove blackfin drivers
The blackfin architecture is getting removed, so the ASoC drivers are all obsolete as well. Signed-off-by: Arnd Bergmann <arnd@arndb.de> Signed-off-by: Mark Brown <broonie@kernel.org>
This commit is contained in:
parent
03a0ddeda7
commit
6ca1118551
|
@ -841,13 +841,6 @@ F: sound/soc/codecs/ad7*
|
|||
F: sound/soc/codecs/ssm*
|
||||
F: sound/soc/codecs/sigmadsp.*
|
||||
|
||||
ANALOG DEVICES INC ASOC DRIVERS
|
||||
L: adi-buildroot-devel@lists.sourceforge.net (moderated for non-subscribers)
|
||||
L: alsa-devel@alsa-project.org (moderated for non-subscribers)
|
||||
W: http://blackfin.uclinux.org/
|
||||
S: Supported
|
||||
F: sound/soc/blackfin/*
|
||||
|
||||
ANALOG DEVICES INC DMA DRIVERS
|
||||
M: Lars-Peter Clausen <lars@metafoo.de>
|
||||
W: http://ez.analog.com/community/linux-device-drivers
|
||||
|
|
|
@ -45,7 +45,6 @@ source "sound/soc/amd/Kconfig"
|
|||
source "sound/soc/atmel/Kconfig"
|
||||
source "sound/soc/au1x/Kconfig"
|
||||
source "sound/soc/bcm/Kconfig"
|
||||
source "sound/soc/blackfin/Kconfig"
|
||||
source "sound/soc/cirrus/Kconfig"
|
||||
source "sound/soc/davinci/Kconfig"
|
||||
source "sound/soc/dwc/Kconfig"
|
||||
|
|
|
@ -29,7 +29,6 @@ obj-$(CONFIG_SND_SOC) += amd/
|
|||
obj-$(CONFIG_SND_SOC) += atmel/
|
||||
obj-$(CONFIG_SND_SOC) += au1x/
|
||||
obj-$(CONFIG_SND_SOC) += bcm/
|
||||
obj-$(CONFIG_SND_SOC) += blackfin/
|
||||
obj-$(CONFIG_SND_SOC) += cirrus/
|
||||
obj-$(CONFIG_SND_SOC) += davinci/
|
||||
obj-$(CONFIG_SND_SOC) += dwc/
|
||||
|
|
|
@ -1,205 +0,0 @@
|
|||
config SND_BF5XX_I2S
|
||||
tristate "SoC I2S Audio for the ADI Blackfin chip"
|
||||
depends on BLACKFIN
|
||||
select SND_BF5XX_SOC_SPORT if !BF60x
|
||||
select SND_BF6XX_SOC_SPORT if BF60x
|
||||
help
|
||||
Say Y or M if you want to add support for codecs attached to
|
||||
the Blackfin SPORT (synchronous serial ports) interface in I2S
|
||||
mode (supports single stereo In/Out).
|
||||
You will also need to select the audio interfaces to support below.
|
||||
|
||||
config SND_BF5XX_SOC_SSM2602
|
||||
tristate "SoC SSM2602 Audio Codec Add-On Card support"
|
||||
depends on SND_BF5XX_I2S && SND_SOC_I2C_AND_SPI
|
||||
select SND_BF5XX_SOC_I2S if !BF60x
|
||||
select SND_BF6XX_SOC_I2S if BF60x
|
||||
select SND_SOC_SSM2602_SPI if SPI_MASTER
|
||||
select SND_SOC_SSM2602_I2C if I2C
|
||||
help
|
||||
Say Y if you want to add support for the Analog Devices
|
||||
SSM2602 Audio Codec Add-On Card.
|
||||
|
||||
config SND_SOC_BFIN_EVAL_ADAU1701
|
||||
tristate "Support for the EVAL-ADAU1701MINIZ board on Blackfin eval boards"
|
||||
depends on SND_BF5XX_I2S && I2C
|
||||
select SND_BF5XX_SOC_I2S
|
||||
select SND_SOC_ADAU1701
|
||||
help
|
||||
Say Y if you want to add support for the Analog Devices EVAL-ADAU1701MINIZ
|
||||
board connected to one of the Blackfin evaluation boards like the
|
||||
BF5XX-STAMP or BF5XX-EZKIT.
|
||||
|
||||
config SND_SOC_BFIN_EVAL_ADAU1373
|
||||
tristate "Support for the EVAL-ADAU1373 board on Blackfin eval boards"
|
||||
depends on SND_BF5XX_I2S && I2C
|
||||
select SND_BF5XX_SOC_I2S
|
||||
select SND_SOC_ADAU1373
|
||||
help
|
||||
Say Y if you want to add support for the Analog Devices EVAL-ADAU1373
|
||||
board connected to one of the Blackfin evaluation boards like the
|
||||
BF5XX-STAMP or BF5XX-EZKIT.
|
||||
|
||||
Note: This driver assumes that first ADAU1373 DAI is connected to the
|
||||
first SPORT port on the BF5XX board.
|
||||
|
||||
config SND_SOC_BFIN_EVAL_ADAU1X61
|
||||
tristate "Support for the EVAL-ADAU1X61 board on Blackfin eval boards"
|
||||
depends on SND_BF5XX_I2S && I2C
|
||||
select SND_BF5XX_SOC_I2S
|
||||
select SND_SOC_ADAU1761_I2C
|
||||
help
|
||||
Say Y if you want to add support for the Analog Devices EVAL-ADAU1X61
|
||||
board connected to one of the Blackfin evaluation boards like the
|
||||
BF5XX-STAMP or BF5XX-EZKIT.
|
||||
|
||||
Note: This driver assumes that the ADAU1X61 is connected to the
|
||||
first SPORT port on the BF5XX board.
|
||||
|
||||
config SND_SOC_BFIN_EVAL_ADAU1X81
|
||||
tristate "Support for the EVAL-ADAU1X81 boards on Blackfin eval boards"
|
||||
depends on SND_BF5XX_I2S && I2C
|
||||
select SND_BF5XX_SOC_I2S
|
||||
select SND_SOC_ADAU1781_I2C
|
||||
help
|
||||
Say Y if you want to add support for the Analog Devices EVAL-ADAU1X81
|
||||
board connected to one of the Blackfin evaluation boards like the
|
||||
BF5XX-STAMP or BF5XX-EZKIT.
|
||||
|
||||
Note: This driver assumes that the ADAU1X81 is connected to the
|
||||
first SPORT port on the BF5XX board.
|
||||
|
||||
config SND_SOC_BFIN_EVAL_ADAV80X
|
||||
tristate "Support for the EVAL-ADAV80X boards on Blackfin eval boards"
|
||||
depends on SND_BF5XX_I2S && SND_SOC_I2C_AND_SPI
|
||||
select SND_BF5XX_SOC_I2S
|
||||
select SND_SOC_ADAV801 if SPI_MASTER
|
||||
select SND_SOC_ADAV803 if I2C
|
||||
help
|
||||
Say Y if you want to add support for the Analog Devices EVAL-ADAV801 or
|
||||
EVAL-ADAV803 board connected to one of the Blackfin evaluation boards
|
||||
like the BF5XX-STAMP or BF5XX-EZKIT.
|
||||
|
||||
Note: This driver assumes that the ADAV80X digital record and playback
|
||||
interfaces are connected to the first SPORT port on the BF5XX board.
|
||||
|
||||
config SND_BF5XX_SOC_AD1836
|
||||
tristate "SoC AD1836 Audio support for BF5xx"
|
||||
depends on SND_BF5XX_I2S && SPI_MASTER
|
||||
select SND_BF5XX_SOC_I2S
|
||||
select SND_SOC_AD1836
|
||||
help
|
||||
Say Y if you want to add support for SoC audio on BF5xx STAMP/EZKIT.
|
||||
|
||||
config SND_BF5XX_SOC_AD193X
|
||||
tristate "SoC AD193X Audio support for Blackfin"
|
||||
depends on SND_BF5XX_I2S && SND_SOC_I2C_AND_SPI
|
||||
select SND_BF5XX_SOC_I2S
|
||||
select SND_SOC_AD193X_I2C if I2C
|
||||
select SND_SOC_AD193X_SPI if SPI_MASTER
|
||||
help
|
||||
Say Y if you want to add support for AD193X codec on Blackfin.
|
||||
This driver supports AD1936, AD1937, AD1938 and AD1939.
|
||||
|
||||
config SND_BF5XX_SOC_AD73311
|
||||
tristate "SoC AD73311 Audio support for Blackfin"
|
||||
depends on SND_BF5XX_I2S
|
||||
select SND_BF5XX_SOC_I2S
|
||||
select SND_SOC_AD73311
|
||||
help
|
||||
Say Y if you want to add support for AD73311 codec on Blackfin.
|
||||
|
||||
config SND_BFIN_AD73311_SE
|
||||
int "PF pin for AD73311L Chip Select"
|
||||
depends on SND_BF5XX_SOC_AD73311
|
||||
default 4
|
||||
help
|
||||
Enter the GPIO used to control AD73311's SE pin. Acceptable
|
||||
values are 0 to 7
|
||||
|
||||
config SND_BF5XX_AC97
|
||||
tristate "SoC AC97 Audio for the ADI BF5xx chip"
|
||||
depends on BLACKFIN
|
||||
select AC97_BUS
|
||||
select SND_SOC_AC97_BUS
|
||||
select SND_BF5XX_SOC_SPORT
|
||||
select SND_BF5XX_SOC_AC97
|
||||
help
|
||||
Say Y or M if you want to add support for codecs attached to
|
||||
the Blackfin SPORT (synchronous serial ports) interface in slot 16
|
||||
mode (pseudo AC97 interface).
|
||||
You will also need to select the audio interfaces to support below.
|
||||
|
||||
Note:
|
||||
AC97 codecs which do not implement the slot-16 mode will not function
|
||||
properly with this driver. This driver is known to work with the
|
||||
Analog Devices line of AC97 codecs.
|
||||
|
||||
config SND_BF5XX_MMAP_SUPPORT
|
||||
bool "Enable MMAP Support"
|
||||
depends on SND_BF5XX_AC97
|
||||
default y
|
||||
help
|
||||
Say y if you want AC97 driver to support mmap mode.
|
||||
We introduce an intermediate buffer to simulate mmap.
|
||||
|
||||
config SND_BF5XX_MULTICHAN_SUPPORT
|
||||
bool "Enable Multichannel Support"
|
||||
depends on SND_BF5XX_AC97
|
||||
default n
|
||||
help
|
||||
Say y if you want AC97 driver to support up to 5.1 channel audio.
|
||||
this mode will consume much more memory for DMA.
|
||||
|
||||
config SND_BF5XX_HAVE_COLD_RESET
|
||||
bool "BOARD has COLD Reset GPIO"
|
||||
depends on SND_BF5XX_AC97
|
||||
default y if BFIN548_EZKIT
|
||||
default n if !BFIN548_EZKIT
|
||||
|
||||
config SND_BF5XX_RESET_GPIO_NUM
|
||||
int "Set a GPIO for cold reset"
|
||||
depends on SND_BF5XX_HAVE_COLD_RESET
|
||||
range 0 159
|
||||
default 19 if BFIN548_EZKIT
|
||||
default 5 if BFIN537_STAMP
|
||||
default 0
|
||||
help
|
||||
Set the correct GPIO for RESET the sound chip.
|
||||
|
||||
config SND_BF5XX_SOC_AD1980
|
||||
tristate "SoC AD1980/1 Audio support for BF5xx (Obsolete)"
|
||||
depends on SND_BF5XX_AC97
|
||||
select SND_BF5XX_SOC_AC97
|
||||
select SND_SOC_AD1980
|
||||
help
|
||||
Say Y if you want to add support for SoC audio on BF5xx STAMP/EZKIT.
|
||||
|
||||
Warning:
|
||||
Because Analog Devices Inc. discontinued the ad1980 sound chip since
|
||||
Sep. 2009, this ad1980 driver is not maintained, tested and supported
|
||||
by ADI now.
|
||||
|
||||
config SND_BF5XX_SOC_SPORT
|
||||
tristate
|
||||
|
||||
config SND_BF6XX_SOC_SPORT
|
||||
tristate
|
||||
|
||||
config SND_BF5XX_SOC_I2S
|
||||
tristate
|
||||
|
||||
config SND_BF6XX_SOC_I2S
|
||||
tristate
|
||||
|
||||
config SND_BF5XX_SOC_AC97
|
||||
tristate
|
||||
|
||||
config SND_BF5XX_SPORT_NUM
|
||||
int "Set a SPORT for Sound chip"
|
||||
depends on (SND_BF5XX_SOC_SPORT || SND_BF6XX_SOC_SPORT)
|
||||
range 0 3 if BF54x
|
||||
range 0 1 if !BF54x
|
||||
default 0
|
||||
help
|
||||
Set the correct SPORT for sound chip.
|
|
@ -1,40 +0,0 @@
|
|||
# SPDX-License-Identifier: GPL-2.0
|
||||
# Blackfin Platform Support
|
||||
snd-bf5xx-ac97-objs := bf5xx-ac97-pcm.o
|
||||
snd-bf5xx-i2s-objs := bf5xx-i2s-pcm.o
|
||||
snd-soc-bf5xx-sport-objs := bf5xx-sport.o
|
||||
snd-soc-bf6xx-sport-objs := bf6xx-sport.o
|
||||
snd-soc-bf5xx-ac97-objs := bf5xx-ac97.o
|
||||
snd-soc-bf5xx-i2s-objs := bf5xx-i2s.o
|
||||
snd-soc-bf6xx-i2s-objs := bf6xx-i2s.o
|
||||
|
||||
obj-$(CONFIG_SND_BF5XX_AC97) += snd-bf5xx-ac97.o
|
||||
obj-$(CONFIG_SND_BF5XX_I2S) += snd-bf5xx-i2s.o
|
||||
obj-$(CONFIG_SND_BF5XX_SOC_SPORT) += snd-soc-bf5xx-sport.o
|
||||
obj-$(CONFIG_SND_BF6XX_SOC_SPORT) += snd-soc-bf6xx-sport.o
|
||||
obj-$(CONFIG_SND_BF5XX_SOC_AC97) += snd-soc-bf5xx-ac97.o
|
||||
obj-$(CONFIG_SND_BF5XX_SOC_I2S) += snd-soc-bf5xx-i2s.o
|
||||
obj-$(CONFIG_SND_BF6XX_SOC_I2S) += snd-soc-bf6xx-i2s.o
|
||||
|
||||
# Blackfin Machine Support
|
||||
snd-ad1836-objs := bf5xx-ad1836.o
|
||||
snd-ad1980-objs := bf5xx-ad1980.o
|
||||
snd-ssm2602-objs := bf5xx-ssm2602.o
|
||||
snd-ad73311-objs := bf5xx-ad73311.o
|
||||
snd-ad193x-objs := bf5xx-ad193x.o
|
||||
snd-soc-bfin-eval-adau1373-objs := bfin-eval-adau1373.o
|
||||
snd-soc-bfin-eval-adau1x61-objs := bfin-eval-adau1x61.o
|
||||
snd-soc-bfin-eval-adau1x81-objs := bfin-eval-adau1x81.o
|
||||
snd-soc-bfin-eval-adau1701-objs := bfin-eval-adau1701.o
|
||||
snd-soc-bfin-eval-adav80x-objs := bfin-eval-adav80x.o
|
||||
|
||||
obj-$(CONFIG_SND_BF5XX_SOC_AD1836) += snd-ad1836.o
|
||||
obj-$(CONFIG_SND_BF5XX_SOC_AD1980) += snd-ad1980.o
|
||||
obj-$(CONFIG_SND_BF5XX_SOC_SSM2602) += snd-ssm2602.o
|
||||
obj-$(CONFIG_SND_BF5XX_SOC_AD73311) += snd-ad73311.o
|
||||
obj-$(CONFIG_SND_BF5XX_SOC_AD193X) += snd-ad193x.o
|
||||
obj-$(CONFIG_SND_SOC_BFIN_EVAL_ADAU1373) += snd-soc-bfin-eval-adau1373.o
|
||||
obj-$(CONFIG_SND_SOC_BFIN_EVAL_ADAU1X61) += snd-soc-bfin-eval-adau1x61.o
|
||||
obj-$(CONFIG_SND_SOC_BFIN_EVAL_ADAU1X81) += snd-soc-bfin-eval-adau1x81.o
|
||||
obj-$(CONFIG_SND_SOC_BFIN_EVAL_ADAU1701) += snd-soc-bfin-eval-adau1701.o
|
||||
obj-$(CONFIG_SND_SOC_BFIN_EVAL_ADAV80X) += snd-soc-bfin-eval-adav80x.o
|
|
@ -1,480 +0,0 @@
|
|||
/*
|
||||
* File: sound/soc/blackfin/bf5xx-ac97-pcm.c
|
||||
* Author: Cliff Cai <Cliff.Cai@analog.com>
|
||||
*
|
||||
* Created: Tue June 06 2008
|
||||
* Description: DMA Driver for AC97 sound chip
|
||||
*
|
||||
* Modified:
|
||||
* Copyright 2008 Analog Devices Inc.
|
||||
*
|
||||
* Bugs: Enter bugs at http://blackfin.uclinux.org/
|
||||
*
|
||||
* 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 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, see the file COPYING, or write
|
||||
* to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#include <linux/module.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/dma-mapping.h>
|
||||
#include <linux/gfp.h>
|
||||
|
||||
#include <sound/core.h>
|
||||
#include <sound/pcm.h>
|
||||
#include <sound/pcm_params.h>
|
||||
#include <sound/soc.h>
|
||||
|
||||
#include <asm/dma.h>
|
||||
|
||||
#include "bf5xx-ac97.h"
|
||||
#include "bf5xx-sport.h"
|
||||
|
||||
static unsigned int ac97_chan_mask[] = {
|
||||
SP_FL, /* Mono */
|
||||
SP_STEREO, /* Stereo */
|
||||
SP_2DOT1, /* 2.1*/
|
||||
SP_QUAD,/*Quadraquic*/
|
||||
SP_FL | SP_FR | SP_FC | SP_SL | SP_SR,/*5 channels */
|
||||
SP_5DOT1, /* 5.1 */
|
||||
};
|
||||
|
||||
#if defined(CONFIG_SND_BF5XX_MMAP_SUPPORT)
|
||||
static void bf5xx_mmap_copy(struct snd_pcm_substream *substream,
|
||||
snd_pcm_uframes_t count)
|
||||
{
|
||||
struct snd_pcm_runtime *runtime = substream->runtime;
|
||||
struct sport_device *sport = runtime->private_data;
|
||||
unsigned int chan_mask = ac97_chan_mask[runtime->channels - 1];
|
||||
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
|
||||
bf5xx_pcm_to_ac97((struct ac97_frame *)sport->tx_dma_buf +
|
||||
sport->tx_pos, (__u16 *)runtime->dma_area + sport->tx_pos *
|
||||
runtime->channels, count, chan_mask);
|
||||
sport->tx_pos += runtime->period_size;
|
||||
if (sport->tx_pos >= runtime->buffer_size)
|
||||
sport->tx_pos %= runtime->buffer_size;
|
||||
sport->tx_delay_pos = sport->tx_pos;
|
||||
} else {
|
||||
bf5xx_ac97_to_pcm((struct ac97_frame *)sport->rx_dma_buf +
|
||||
sport->rx_pos, (__u16 *)runtime->dma_area + sport->rx_pos *
|
||||
runtime->channels, count);
|
||||
sport->rx_pos += runtime->period_size;
|
||||
if (sport->rx_pos >= runtime->buffer_size)
|
||||
sport->rx_pos %= runtime->buffer_size;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
static void bf5xx_dma_irq(void *data)
|
||||
{
|
||||
struct snd_pcm_substream *pcm = data;
|
||||
#if defined(CONFIG_SND_BF5XX_MMAP_SUPPORT)
|
||||
struct snd_pcm_runtime *runtime = pcm->runtime;
|
||||
struct sport_device *sport = runtime->private_data;
|
||||
bf5xx_mmap_copy(pcm, runtime->period_size);
|
||||
if (pcm->stream == SNDRV_PCM_STREAM_PLAYBACK) {
|
||||
if (sport->once == 0) {
|
||||
snd_pcm_period_elapsed(pcm);
|
||||
bf5xx_mmap_copy(pcm, runtime->period_size);
|
||||
sport->once = 1;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
snd_pcm_period_elapsed(pcm);
|
||||
}
|
||||
|
||||
/* The memory size for pure pcm data is 128*1024 = 0x20000 bytes.
|
||||
* The total rx/tx buffer is for ac97 frame to hold all pcm data
|
||||
* is 0x20000 * sizeof(struct ac97_frame) / 4.
|
||||
*/
|
||||
static const struct snd_pcm_hardware bf5xx_pcm_hardware = {
|
||||
.info = SNDRV_PCM_INFO_INTERLEAVED |
|
||||
#if defined(CONFIG_SND_BF5XX_MMAP_SUPPORT)
|
||||
SNDRV_PCM_INFO_MMAP |
|
||||
SNDRV_PCM_INFO_MMAP_VALID |
|
||||
#endif
|
||||
SNDRV_PCM_INFO_BLOCK_TRANSFER,
|
||||
|
||||
.period_bytes_min = 32,
|
||||
.period_bytes_max = 0x10000,
|
||||
.periods_min = 1,
|
||||
.periods_max = PAGE_SIZE/32,
|
||||
.buffer_bytes_max = 0x20000, /* 128 kbytes */
|
||||
.fifo_size = 16,
|
||||
};
|
||||
|
||||
static int bf5xx_pcm_hw_params(struct snd_pcm_substream *substream,
|
||||
struct snd_pcm_hw_params *params)
|
||||
{
|
||||
size_t size = bf5xx_pcm_hardware.buffer_bytes_max
|
||||
* sizeof(struct ac97_frame) / 4;
|
||||
|
||||
snd_pcm_lib_malloc_pages(substream, size);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int bf5xx_pcm_hw_free(struct snd_pcm_substream *substream)
|
||||
{
|
||||
#if defined(CONFIG_SND_BF5XX_MMAP_SUPPORT)
|
||||
struct snd_pcm_runtime *runtime = substream->runtime;
|
||||
struct sport_device *sport = runtime->private_data;
|
||||
|
||||
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
|
||||
sport->once = 0;
|
||||
if (runtime->dma_area)
|
||||
memset(runtime->dma_area, 0, runtime->buffer_size);
|
||||
memset(sport->tx_dma_buf, 0, runtime->buffer_size *
|
||||
sizeof(struct ac97_frame));
|
||||
} else
|
||||
memset(sport->rx_dma_buf, 0, runtime->buffer_size *
|
||||
sizeof(struct ac97_frame));
|
||||
#endif
|
||||
snd_pcm_lib_free_pages(substream);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int bf5xx_pcm_prepare(struct snd_pcm_substream *substream)
|
||||
{
|
||||
struct snd_pcm_runtime *runtime = substream->runtime;
|
||||
struct sport_device *sport = runtime->private_data;
|
||||
|
||||
/* An intermediate buffer is introduced for implementing mmap for
|
||||
* SPORT working in TMD mode(include AC97).
|
||||
*/
|
||||
#if defined(CONFIG_SND_BF5XX_MMAP_SUPPORT)
|
||||
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
|
||||
sport_set_tx_callback(sport, bf5xx_dma_irq, substream);
|
||||
sport_config_tx_dma(sport, sport->tx_dma_buf, runtime->periods,
|
||||
runtime->period_size * sizeof(struct ac97_frame));
|
||||
} else {
|
||||
sport_set_rx_callback(sport, bf5xx_dma_irq, substream);
|
||||
sport_config_rx_dma(sport, sport->rx_dma_buf, runtime->periods,
|
||||
runtime->period_size * sizeof(struct ac97_frame));
|
||||
}
|
||||
#else
|
||||
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
|
||||
sport_set_tx_callback(sport, bf5xx_dma_irq, substream);
|
||||
sport_config_tx_dma(sport, runtime->dma_area, runtime->periods,
|
||||
runtime->period_size * sizeof(struct ac97_frame));
|
||||
} else {
|
||||
sport_set_rx_callback(sport, bf5xx_dma_irq, substream);
|
||||
sport_config_rx_dma(sport, runtime->dma_area, runtime->periods,
|
||||
runtime->period_size * sizeof(struct ac97_frame));
|
||||
}
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int bf5xx_pcm_trigger(struct snd_pcm_substream *substream, int cmd)
|
||||
{
|
||||
struct snd_pcm_runtime *runtime = substream->runtime;
|
||||
struct sport_device *sport = runtime->private_data;
|
||||
int ret = 0;
|
||||
|
||||
pr_debug("%s enter\n", __func__);
|
||||
switch (cmd) {
|
||||
case SNDRV_PCM_TRIGGER_START:
|
||||
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
|
||||
#if defined(CONFIG_SND_BF5XX_MMAP_SUPPORT)
|
||||
bf5xx_mmap_copy(substream, runtime->period_size);
|
||||
sport->tx_delay_pos = 0;
|
||||
#endif
|
||||
sport_tx_start(sport);
|
||||
} else
|
||||
sport_rx_start(sport);
|
||||
break;
|
||||
case SNDRV_PCM_TRIGGER_STOP:
|
||||
case SNDRV_PCM_TRIGGER_SUSPEND:
|
||||
case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
|
||||
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
|
||||
#if defined(CONFIG_SND_BF5XX_MMAP_SUPPORT)
|
||||
sport->tx_pos = 0;
|
||||
#endif
|
||||
sport_tx_stop(sport);
|
||||
} else {
|
||||
#if defined(CONFIG_SND_BF5XX_MMAP_SUPPORT)
|
||||
sport->rx_pos = 0;
|
||||
#endif
|
||||
sport_rx_stop(sport);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
ret = -EINVAL;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
static snd_pcm_uframes_t bf5xx_pcm_pointer(struct snd_pcm_substream *substream)
|
||||
{
|
||||
struct snd_pcm_runtime *runtime = substream->runtime;
|
||||
struct sport_device *sport = runtime->private_data;
|
||||
unsigned int curr;
|
||||
|
||||
#if defined(CONFIG_SND_BF5XX_MMAP_SUPPORT)
|
||||
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
|
||||
curr = sport->tx_delay_pos;
|
||||
else
|
||||
curr = sport->rx_pos;
|
||||
#else
|
||||
|
||||
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
|
||||
curr = sport_curr_offset_tx(sport) / sizeof(struct ac97_frame);
|
||||
else
|
||||
curr = sport_curr_offset_rx(sport) / sizeof(struct ac97_frame);
|
||||
|
||||
#endif
|
||||
return curr;
|
||||
}
|
||||
|
||||
static int bf5xx_pcm_open(struct snd_pcm_substream *substream)
|
||||
{
|
||||
struct snd_soc_pcm_runtime *rtd = substream->private_data;
|
||||
struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
|
||||
struct sport_device *sport_handle = snd_soc_dai_get_drvdata(cpu_dai);
|
||||
struct snd_pcm_runtime *runtime = substream->runtime;
|
||||
int ret;
|
||||
|
||||
pr_debug("%s enter\n", __func__);
|
||||
snd_soc_set_runtime_hwparams(substream, &bf5xx_pcm_hardware);
|
||||
|
||||
ret = snd_pcm_hw_constraint_integer(runtime,
|
||||
SNDRV_PCM_HW_PARAM_PERIODS);
|
||||
if (ret < 0)
|
||||
goto out;
|
||||
|
||||
if (sport_handle != NULL)
|
||||
runtime->private_data = sport_handle;
|
||||
else {
|
||||
pr_err("sport_handle is NULL\n");
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
|
||||
out:
|
||||
return ret;
|
||||
}
|
||||
|
||||
#if defined(CONFIG_SND_BF5XX_MMAP_SUPPORT)
|
||||
static int bf5xx_pcm_mmap(struct snd_pcm_substream *substream,
|
||||
struct vm_area_struct *vma)
|
||||
{
|
||||
struct snd_pcm_runtime *runtime = substream->runtime;
|
||||
size_t size = vma->vm_end - vma->vm_start;
|
||||
vma->vm_start = (unsigned long)runtime->dma_area;
|
||||
vma->vm_end = vma->vm_start + size;
|
||||
vma->vm_flags |= VM_SHARED;
|
||||
return 0 ;
|
||||
}
|
||||
#else
|
||||
static int bf5xx_pcm_copy(struct snd_pcm_substream *substream,
|
||||
int channel, unsigned long pos,
|
||||
void *buf, unsigned long count)
|
||||
{
|
||||
struct snd_pcm_runtime *runtime = substream->runtime;
|
||||
unsigned int chan_mask = ac97_chan_mask[runtime->channels - 1];
|
||||
struct ac97_frame *dst;
|
||||
|
||||
pr_debug("%s copy pos:0x%lx count:0x%lx\n",
|
||||
substream->stream ? "Capture" : "Playback", pos, count);
|
||||
dst = (struct ac97_frame *)runtime->dma_area +
|
||||
bytes_to_frames(runtime, pos);
|
||||
count = bytes_to_frames(runtime, count);
|
||||
|
||||
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
|
||||
bf5xx_pcm_to_ac97(dst, buf, count, chan_mask);
|
||||
else
|
||||
bf5xx_ac97_to_pcm(dst, buf, count);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int bf5xx_pcm_copy_user(struct snd_pcm_substream *substream,
|
||||
int channel, unsigned long pos,
|
||||
void __user *buf, unsigned long count)
|
||||
{
|
||||
return bf5xx_pcm_copy(substream, channel, pos, (void *)buf, count);
|
||||
}
|
||||
#endif
|
||||
|
||||
static const struct snd_pcm_ops bf5xx_pcm_ac97_ops = {
|
||||
.open = bf5xx_pcm_open,
|
||||
.ioctl = snd_pcm_lib_ioctl,
|
||||
.hw_params = bf5xx_pcm_hw_params,
|
||||
.hw_free = bf5xx_pcm_hw_free,
|
||||
.prepare = bf5xx_pcm_prepare,
|
||||
.trigger = bf5xx_pcm_trigger,
|
||||
.pointer = bf5xx_pcm_pointer,
|
||||
#if defined(CONFIG_SND_BF5XX_MMAP_SUPPORT)
|
||||
.mmap = bf5xx_pcm_mmap,
|
||||
#else
|
||||
.copy_user = bf5xx_pcm_copy_user,
|
||||
.copy_kernel = bf5xx_pcm_copy,
|
||||
#endif
|
||||
};
|
||||
|
||||
static int bf5xx_pcm_preallocate_dma_buffer(struct snd_pcm *pcm, int stream)
|
||||
{
|
||||
struct snd_soc_pcm_runtime *rtd = pcm->private_data;
|
||||
struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
|
||||
struct sport_device *sport_handle = snd_soc_dai_get_drvdata(cpu_dai);
|
||||
struct snd_pcm_substream *substream = pcm->streams[stream].substream;
|
||||
struct snd_dma_buffer *buf = &substream->dma_buffer;
|
||||
size_t size = bf5xx_pcm_hardware.buffer_bytes_max
|
||||
* sizeof(struct ac97_frame) / 4;
|
||||
|
||||
buf->dev.type = SNDRV_DMA_TYPE_DEV;
|
||||
buf->dev.dev = pcm->card->dev;
|
||||
buf->private_data = NULL;
|
||||
buf->area = dma_alloc_coherent(pcm->card->dev, size,
|
||||
&buf->addr, GFP_KERNEL);
|
||||
if (!buf->area) {
|
||||
pr_err("Failed to allocate dma memory\n");
|
||||
pr_err("Please increase uncached DMA memory region\n");
|
||||
return -ENOMEM;
|
||||
}
|
||||
buf->bytes = size;
|
||||
|
||||
pr_debug("%s, area:%p, size:0x%08lx\n", __func__,
|
||||
buf->area, buf->bytes);
|
||||
|
||||
if (stream == SNDRV_PCM_STREAM_PLAYBACK)
|
||||
sport_handle->tx_buf = buf->area;
|
||||
else
|
||||
sport_handle->rx_buf = buf->area;
|
||||
|
||||
/*
|
||||
* Need to allocate local buffer when enable
|
||||
* MMAP for SPORT working in TMD mode (include AC97).
|
||||
*/
|
||||
#if defined(CONFIG_SND_BF5XX_MMAP_SUPPORT)
|
||||
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
|
||||
if (!sport_handle->tx_dma_buf) {
|
||||
sport_handle->tx_dma_buf = dma_alloc_coherent(NULL, \
|
||||
size, &sport_handle->tx_dma_phy, GFP_KERNEL);
|
||||
if (!sport_handle->tx_dma_buf) {
|
||||
pr_err("Failed to allocate memory for tx dma buf - Please increase uncached DMA memory region\n");
|
||||
return -ENOMEM;
|
||||
} else
|
||||
memset(sport_handle->tx_dma_buf, 0, size);
|
||||
} else
|
||||
memset(sport_handle->tx_dma_buf, 0, size);
|
||||
} else {
|
||||
if (!sport_handle->rx_dma_buf) {
|
||||
sport_handle->rx_dma_buf = dma_alloc_coherent(NULL, \
|
||||
size, &sport_handle->rx_dma_phy, GFP_KERNEL);
|
||||
if (!sport_handle->rx_dma_buf) {
|
||||
pr_err("Failed to allocate memory for rx dma buf - Please increase uncached DMA memory region\n");
|
||||
return -ENOMEM;
|
||||
} else
|
||||
memset(sport_handle->rx_dma_buf, 0, size);
|
||||
} else
|
||||
memset(sport_handle->rx_dma_buf, 0, size);
|
||||
}
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void bf5xx_pcm_free_dma_buffers(struct snd_pcm *pcm)
|
||||
{
|
||||
struct snd_pcm_substream *substream;
|
||||
struct snd_dma_buffer *buf;
|
||||
int stream;
|
||||
#if defined(CONFIG_SND_BF5XX_MMAP_SUPPORT)
|
||||
struct snd_soc_pcm_runtime *rtd = pcm->private_data;
|
||||
struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
|
||||
struct sport_device *sport_handle = snd_soc_dai_get_drvdata(cpu_dai);
|
||||
size_t size = bf5xx_pcm_hardware.buffer_bytes_max *
|
||||
sizeof(struct ac97_frame) / 4;
|
||||
#endif
|
||||
for (stream = 0; stream < 2; stream++) {
|
||||
substream = pcm->streams[stream].substream;
|
||||
if (!substream)
|
||||
continue;
|
||||
|
||||
buf = &substream->dma_buffer;
|
||||
if (!buf->area)
|
||||
continue;
|
||||
dma_free_coherent(NULL, buf->bytes, buf->area, 0);
|
||||
buf->area = NULL;
|
||||
#if defined(CONFIG_SND_BF5XX_MMAP_SUPPORT)
|
||||
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
|
||||
if (sport_handle->tx_dma_buf)
|
||||
dma_free_coherent(NULL, size, \
|
||||
sport_handle->tx_dma_buf, 0);
|
||||
sport_handle->tx_dma_buf = NULL;
|
||||
} else {
|
||||
|
||||
if (sport_handle->rx_dma_buf)
|
||||
dma_free_coherent(NULL, size, \
|
||||
sport_handle->rx_dma_buf, 0);
|
||||
sport_handle->rx_dma_buf = NULL;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
static int bf5xx_pcm_ac97_new(struct snd_soc_pcm_runtime *rtd)
|
||||
{
|
||||
struct snd_card *card = rtd->card->snd_card;
|
||||
struct snd_pcm *pcm = rtd->pcm;
|
||||
int ret;
|
||||
|
||||
pr_debug("%s enter\n", __func__);
|
||||
ret = dma_coerce_mask_and_coherent(card->dev, DMA_BIT_MASK(32));
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
if (pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream) {
|
||||
ret = bf5xx_pcm_preallocate_dma_buffer(pcm,
|
||||
SNDRV_PCM_STREAM_PLAYBACK);
|
||||
if (ret)
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (pcm->streams[SNDRV_PCM_STREAM_CAPTURE].substream) {
|
||||
ret = bf5xx_pcm_preallocate_dma_buffer(pcm,
|
||||
SNDRV_PCM_STREAM_CAPTURE);
|
||||
if (ret)
|
||||
goto out;
|
||||
}
|
||||
out:
|
||||
return ret;
|
||||
}
|
||||
|
||||
static struct snd_soc_component_driver bf5xx_ac97_soc_component = {
|
||||
.ops = &bf5xx_pcm_ac97_ops,
|
||||
.pcm_new = bf5xx_pcm_ac97_new,
|
||||
.pcm_free = bf5xx_pcm_free_dma_buffers,
|
||||
};
|
||||
|
||||
static int bf5xx_soc_platform_probe(struct platform_device *pdev)
|
||||
{
|
||||
return devm_snd_soc_register_component(&pdev->dev,
|
||||
&bf5xx_ac97_soc_component, NULL, 0);
|
||||
}
|
||||
|
||||
static struct platform_driver bf5xx_pcm_driver = {
|
||||
.driver = {
|
||||
.name = "bfin-ac97-pcm-audio",
|
||||
},
|
||||
|
||||
.probe = bf5xx_soc_platform_probe,
|
||||
};
|
||||
|
||||
module_platform_driver(bf5xx_pcm_driver);
|
||||
|
||||
MODULE_AUTHOR("Cliff Cai");
|
||||
MODULE_DESCRIPTION("ADI Blackfin AC97 PCM DMA module");
|
||||
MODULE_LICENSE("GPL");
|
|
@ -1,388 +0,0 @@
|
|||
/*
|
||||
* bf5xx-ac97.c -- AC97 support for the ADI blackfin chip.
|
||||
*
|
||||
* Author: Roy Huang
|
||||
* Created: 11th. June 2007
|
||||
* Copyright: Analog Device 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.
|
||||
*/
|
||||
|
||||
#include <linux/init.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/wait.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/slab.h>
|
||||
|
||||
#include <sound/core.h>
|
||||
#include <sound/pcm.h>
|
||||
#include <sound/ac97_codec.h>
|
||||
#include <sound/initval.h>
|
||||
#include <sound/soc.h>
|
||||
|
||||
#include <asm/irq.h>
|
||||
#include <asm/portmux.h>
|
||||
#include <linux/mutex.h>
|
||||
#include <linux/gpio.h>
|
||||
|
||||
#include "bf5xx-sport.h"
|
||||
#include "bf5xx-ac97.h"
|
||||
|
||||
/* Anomaly notes:
|
||||
* 05000250 - AD1980 is running in TDM mode and RFS/TFS are generated by SPORT
|
||||
* contrtoller. But, RFSDIV and TFSDIV are always set to 16*16-1,
|
||||
* while the max AC97 data size is 13*16. The DIV is always larger
|
||||
* than data size. AD73311 and ad2602 are not running in TDM mode.
|
||||
* AD1836 and AD73322 depend on external RFS/TFS only. So, this
|
||||
* anomaly does not affect blackfin sound drivers.
|
||||
*/
|
||||
|
||||
static struct sport_device *ac97_sport_handle;
|
||||
|
||||
void bf5xx_pcm_to_ac97(struct ac97_frame *dst, const __u16 *src,
|
||||
size_t count, unsigned int chan_mask)
|
||||
{
|
||||
while (count--) {
|
||||
dst->ac97_tag = TAG_VALID;
|
||||
if (chan_mask & SP_FL) {
|
||||
dst->ac97_pcm_r = *src++;
|
||||
dst->ac97_tag |= TAG_PCM_RIGHT;
|
||||
}
|
||||
if (chan_mask & SP_FR) {
|
||||
dst->ac97_pcm_l = *src++;
|
||||
dst->ac97_tag |= TAG_PCM_LEFT;
|
||||
|
||||
}
|
||||
#if defined(CONFIG_SND_BF5XX_MULTICHAN_SUPPORT)
|
||||
if (chan_mask & SP_SR) {
|
||||
dst->ac97_sl = *src++;
|
||||
dst->ac97_tag |= TAG_PCM_SL;
|
||||
}
|
||||
if (chan_mask & SP_SL) {
|
||||
dst->ac97_sr = *src++;
|
||||
dst->ac97_tag |= TAG_PCM_SR;
|
||||
}
|
||||
if (chan_mask & SP_LFE) {
|
||||
dst->ac97_lfe = *src++;
|
||||
dst->ac97_tag |= TAG_PCM_LFE;
|
||||
}
|
||||
if (chan_mask & SP_FC) {
|
||||
dst->ac97_center = *src++;
|
||||
dst->ac97_tag |= TAG_PCM_CENTER;
|
||||
}
|
||||
#endif
|
||||
dst++;
|
||||
}
|
||||
}
|
||||
EXPORT_SYMBOL(bf5xx_pcm_to_ac97);
|
||||
|
||||
void bf5xx_ac97_to_pcm(const struct ac97_frame *src, __u16 *dst,
|
||||
size_t count)
|
||||
{
|
||||
while (count--) {
|
||||
*(dst++) = src->ac97_pcm_l;
|
||||
*(dst++) = src->ac97_pcm_r;
|
||||
src++;
|
||||
}
|
||||
}
|
||||
EXPORT_SYMBOL(bf5xx_ac97_to_pcm);
|
||||
|
||||
static unsigned int sport_tx_curr_frag(struct sport_device *sport)
|
||||
{
|
||||
return sport->tx_curr_frag = sport_curr_offset_tx(sport) /
|
||||
sport->tx_fragsize;
|
||||
}
|
||||
|
||||
static void enqueue_cmd(struct snd_ac97 *ac97, __u16 addr, __u16 data)
|
||||
{
|
||||
struct sport_device *sport = ac97_sport_handle;
|
||||
int *cmd_count = sport->private_data;
|
||||
int nextfrag = sport_tx_curr_frag(sport);
|
||||
struct ac97_frame *nextwrite;
|
||||
|
||||
sport_incfrag(sport, &nextfrag, 1);
|
||||
|
||||
nextwrite = (struct ac97_frame *)(sport->tx_buf +
|
||||
nextfrag * sport->tx_fragsize);
|
||||
pr_debug("sport->tx_buf:%p, nextfrag:0x%x nextwrite:%p, cmd_count:%d\n",
|
||||
sport->tx_buf, nextfrag, nextwrite, cmd_count[nextfrag]);
|
||||
nextwrite[cmd_count[nextfrag]].ac97_tag |= TAG_CMD;
|
||||
nextwrite[cmd_count[nextfrag]].ac97_addr = addr;
|
||||
nextwrite[cmd_count[nextfrag]].ac97_data = data;
|
||||
++cmd_count[nextfrag];
|
||||
pr_debug("ac97_sport: Inserting %02x/%04x into fragment %d\n",
|
||||
addr >> 8, data, nextfrag);
|
||||
}
|
||||
|
||||
static unsigned short bf5xx_ac97_read(struct snd_ac97 *ac97,
|
||||
unsigned short reg)
|
||||
{
|
||||
struct sport_device *sport_handle = ac97_sport_handle;
|
||||
struct ac97_frame out_frame[2], in_frame[2];
|
||||
|
||||
pr_debug("%s enter 0x%x\n", __func__, reg);
|
||||
|
||||
/* When dma descriptor is enabled, the register should not be read */
|
||||
if (sport_handle->tx_run || sport_handle->rx_run) {
|
||||
pr_err("Could you send a mail to cliff.cai@analog.com "
|
||||
"to report this?\n");
|
||||
return -EFAULT;
|
||||
}
|
||||
|
||||
memset(&out_frame, 0, 2 * sizeof(struct ac97_frame));
|
||||
memset(&in_frame, 0, 2 * sizeof(struct ac97_frame));
|
||||
out_frame[0].ac97_tag = TAG_VALID | TAG_CMD;
|
||||
out_frame[0].ac97_addr = ((reg << 8) | 0x8000);
|
||||
sport_send_and_recv(sport_handle, (unsigned char *)&out_frame,
|
||||
(unsigned char *)&in_frame,
|
||||
2 * sizeof(struct ac97_frame));
|
||||
return in_frame[1].ac97_data;
|
||||
}
|
||||
|
||||
void bf5xx_ac97_write(struct snd_ac97 *ac97, unsigned short reg,
|
||||
unsigned short val)
|
||||
{
|
||||
struct sport_device *sport_handle = ac97_sport_handle;
|
||||
|
||||
pr_debug("%s enter 0x%x:0x%04x\n", __func__, reg, val);
|
||||
|
||||
if (sport_handle->tx_run) {
|
||||
enqueue_cmd(ac97, (reg << 8), val); /* write */
|
||||
enqueue_cmd(ac97, (reg << 8) | 0x8000, 0); /* read back */
|
||||
} else {
|
||||
struct ac97_frame frame;
|
||||
memset(&frame, 0, sizeof(struct ac97_frame));
|
||||
frame.ac97_tag = TAG_VALID | TAG_CMD;
|
||||
frame.ac97_addr = (reg << 8);
|
||||
frame.ac97_data = val;
|
||||
sport_send_and_recv(sport_handle, (unsigned char *)&frame, \
|
||||
NULL, sizeof(struct ac97_frame));
|
||||
}
|
||||
}
|
||||
|
||||
static void bf5xx_ac97_warm_reset(struct snd_ac97 *ac97)
|
||||
{
|
||||
struct sport_device *sport_handle = ac97_sport_handle;
|
||||
u16 gpio = P_IDENT(sport_handle->pin_req[3]);
|
||||
|
||||
pr_debug("%s enter\n", __func__);
|
||||
|
||||
peripheral_free_list(sport_handle->pin_req);
|
||||
gpio_request(gpio, "bf5xx-ac97");
|
||||
gpio_direction_output(gpio, 1);
|
||||
udelay(2);
|
||||
gpio_set_value(gpio, 0);
|
||||
udelay(1);
|
||||
gpio_free(gpio);
|
||||
peripheral_request_list(sport_handle->pin_req, "soc-audio");
|
||||
}
|
||||
|
||||
static void bf5xx_ac97_cold_reset(struct snd_ac97 *ac97)
|
||||
{
|
||||
#ifdef CONFIG_SND_BF5XX_HAVE_COLD_RESET
|
||||
pr_debug("%s enter\n", __func__);
|
||||
|
||||
/* It is specified for bf548-ezkit */
|
||||
gpio_set_value(CONFIG_SND_BF5XX_RESET_GPIO_NUM, 0);
|
||||
/* Keep reset pin low for 1 ms */
|
||||
mdelay(1);
|
||||
gpio_set_value(CONFIG_SND_BF5XX_RESET_GPIO_NUM, 1);
|
||||
/* Wait for bit clock recover */
|
||||
mdelay(1);
|
||||
#else
|
||||
pr_info("%s: Not implemented\n", __func__);
|
||||
#endif
|
||||
}
|
||||
|
||||
static struct snd_ac97_bus_ops bf5xx_ac97_ops = {
|
||||
.read = bf5xx_ac97_read,
|
||||
.write = bf5xx_ac97_write,
|
||||
.warm_reset = bf5xx_ac97_warm_reset,
|
||||
.reset = bf5xx_ac97_cold_reset,
|
||||
};
|
||||
|
||||
#ifdef CONFIG_PM
|
||||
static int bf5xx_ac97_suspend(struct snd_soc_dai *dai)
|
||||
{
|
||||
struct sport_device *sport = snd_soc_dai_get_drvdata(dai);
|
||||
|
||||
pr_debug("%s : sport %d\n", __func__, dai->id);
|
||||
if (!dai->active)
|
||||
return 0;
|
||||
if (dai->capture_active)
|
||||
sport_rx_stop(sport);
|
||||
if (dai->playback_active)
|
||||
sport_tx_stop(sport);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int bf5xx_ac97_resume(struct snd_soc_dai *dai)
|
||||
{
|
||||
int ret;
|
||||
struct sport_device *sport = snd_soc_dai_get_drvdata(dai);
|
||||
|
||||
pr_debug("%s : sport %d\n", __func__, dai->id);
|
||||
if (!dai->active)
|
||||
return 0;
|
||||
|
||||
#if defined(CONFIG_SND_BF5XX_MULTICHAN_SUPPORT)
|
||||
ret = sport_set_multichannel(sport, 16, 0x3FF, 0x3FF, 1);
|
||||
#else
|
||||
ret = sport_set_multichannel(sport, 16, 0x1F, 0x1F, 1);
|
||||
#endif
|
||||
if (ret) {
|
||||
pr_err("SPORT is busy!\n");
|
||||
return -EBUSY;
|
||||
}
|
||||
|
||||
ret = sport_config_rx(sport, IRFS, 0xF, 0, (16*16-1));
|
||||
if (ret) {
|
||||
pr_err("SPORT is busy!\n");
|
||||
return -EBUSY;
|
||||
}
|
||||
|
||||
ret = sport_config_tx(sport, ITFS, 0xF, 0, (16*16-1));
|
||||
if (ret) {
|
||||
pr_err("SPORT is busy!\n");
|
||||
return -EBUSY;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#else
|
||||
#define bf5xx_ac97_suspend NULL
|
||||
#define bf5xx_ac97_resume NULL
|
||||
#endif
|
||||
|
||||
static struct snd_soc_dai_driver bfin_ac97_dai = {
|
||||
.bus_control = true,
|
||||
.suspend = bf5xx_ac97_suspend,
|
||||
.resume = bf5xx_ac97_resume,
|
||||
.playback = {
|
||||
.stream_name = "AC97 Playback",
|
||||
.channels_min = 2,
|
||||
#if defined(CONFIG_SND_BF5XX_MULTICHAN_SUPPORT)
|
||||
.channels_max = 6,
|
||||
#else
|
||||
.channels_max = 2,
|
||||
#endif
|
||||
.rates = SNDRV_PCM_RATE_48000,
|
||||
.formats = SNDRV_PCM_FMTBIT_S16_LE, },
|
||||
.capture = {
|
||||
.stream_name = "AC97 Capture",
|
||||
.channels_min = 2,
|
||||
.channels_max = 2,
|
||||
.rates = SNDRV_PCM_RATE_48000,
|
||||
.formats = SNDRV_PCM_FMTBIT_S16_LE, },
|
||||
};
|
||||
|
||||
static const struct snd_soc_component_driver bfin_ac97_component = {
|
||||
.name = "bfin-ac97",
|
||||
};
|
||||
|
||||
static int asoc_bfin_ac97_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct sport_device *sport_handle;
|
||||
int ret;
|
||||
|
||||
#ifdef CONFIG_SND_BF5XX_HAVE_COLD_RESET
|
||||
/* Request PB3 as reset pin */
|
||||
ret = devm_gpio_request_one(&pdev->dev,
|
||||
CONFIG_SND_BF5XX_RESET_GPIO_NUM,
|
||||
GPIOF_OUT_INIT_HIGH, "SND_AD198x RESET");
|
||||
if (ret) {
|
||||
dev_err(&pdev->dev,
|
||||
"Failed to request GPIO_%d for reset: %d\n",
|
||||
CONFIG_SND_BF5XX_RESET_GPIO_NUM, ret);
|
||||
return ret;
|
||||
}
|
||||
#endif
|
||||
|
||||
sport_handle = sport_init(pdev, 2, sizeof(struct ac97_frame),
|
||||
PAGE_SIZE);
|
||||
if (!sport_handle) {
|
||||
ret = -ENODEV;
|
||||
goto sport_err;
|
||||
}
|
||||
|
||||
/*SPORT works in TDM mode to simulate AC97 transfers*/
|
||||
#if defined(CONFIG_SND_BF5XX_MULTICHAN_SUPPORT)
|
||||
ret = sport_set_multichannel(sport_handle, 16, 0x3FF, 0x3FF, 1);
|
||||
#else
|
||||
ret = sport_set_multichannel(sport_handle, 16, 0x1F, 0x1F, 1);
|
||||
#endif
|
||||
if (ret) {
|
||||
pr_err("SPORT is busy!\n");
|
||||
ret = -EBUSY;
|
||||
goto sport_config_err;
|
||||
}
|
||||
|
||||
ret = sport_config_rx(sport_handle, IRFS, 0xF, 0, (16*16-1));
|
||||
if (ret) {
|
||||
pr_err("SPORT is busy!\n");
|
||||
ret = -EBUSY;
|
||||
goto sport_config_err;
|
||||
}
|
||||
|
||||
ret = sport_config_tx(sport_handle, ITFS, 0xF, 0, (16*16-1));
|
||||
if (ret) {
|
||||
pr_err("SPORT is busy!\n");
|
||||
ret = -EBUSY;
|
||||
goto sport_config_err;
|
||||
}
|
||||
|
||||
ret = snd_soc_set_ac97_ops(&bf5xx_ac97_ops);
|
||||
if (ret != 0) {
|
||||
dev_err(&pdev->dev, "Failed to set AC'97 ops: %d\n", ret);
|
||||
goto sport_config_err;
|
||||
}
|
||||
|
||||
ret = snd_soc_register_component(&pdev->dev, &bfin_ac97_component,
|
||||
&bfin_ac97_dai, 1);
|
||||
if (ret) {
|
||||
pr_err("Failed to register DAI: %d\n", ret);
|
||||
goto sport_config_err;
|
||||
}
|
||||
|
||||
ac97_sport_handle = sport_handle;
|
||||
|
||||
return 0;
|
||||
|
||||
sport_config_err:
|
||||
sport_done(sport_handle);
|
||||
sport_err:
|
||||
snd_soc_set_ac97_ops(NULL);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int asoc_bfin_ac97_remove(struct platform_device *pdev)
|
||||
{
|
||||
struct sport_device *sport_handle = platform_get_drvdata(pdev);
|
||||
|
||||
snd_soc_unregister_component(&pdev->dev);
|
||||
sport_done(sport_handle);
|
||||
snd_soc_set_ac97_ops(NULL);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct platform_driver asoc_bfin_ac97_driver = {
|
||||
.driver = {
|
||||
.name = "bfin-ac97",
|
||||
},
|
||||
|
||||
.probe = asoc_bfin_ac97_probe,
|
||||
.remove = asoc_bfin_ac97_remove,
|
||||
};
|
||||
|
||||
module_platform_driver(asoc_bfin_ac97_driver);
|
||||
|
||||
MODULE_AUTHOR("Roy Huang");
|
||||
MODULE_DESCRIPTION("AC97 driver for ADI Blackfin");
|
||||
MODULE_LICENSE("GPL");
|
|
@ -1,57 +0,0 @@
|
|||
/*
|
||||
* sound/soc/blackfin/bf5xx-ac97.h
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#ifndef _BF5XX_AC97_H
|
||||
#define _BF5XX_AC97_H
|
||||
|
||||
/* Frame format in memory, only support stereo currently */
|
||||
struct ac97_frame {
|
||||
u16 ac97_tag; /* slot 0 */
|
||||
u16 ac97_addr; /* slot 1 */
|
||||
u16 ac97_data; /* slot 2 */
|
||||
u16 ac97_pcm_l; /*slot 3:front left*/
|
||||
u16 ac97_pcm_r; /*slot 4:front left*/
|
||||
#if defined(CONFIG_SND_BF5XX_MULTICHAN_SUPPORT)
|
||||
u16 ac97_mdm_l1;
|
||||
u16 ac97_center; /*slot 6:center*/
|
||||
u16 ac97_sl; /*slot 7:surround left*/
|
||||
u16 ac97_sr; /*slot 8:surround right*/
|
||||
u16 ac97_lfe; /*slot 9:lfe*/
|
||||
#endif
|
||||
} __attribute__ ((packed));
|
||||
|
||||
/* Speaker location */
|
||||
#define SP_FL 0x0001
|
||||
#define SP_FR 0x0010
|
||||
#define SP_FC 0x0002
|
||||
#define SP_LFE 0x0020
|
||||
#define SP_SL 0x0004
|
||||
#define SP_SR 0x0040
|
||||
|
||||
#define SP_STEREO (SP_FL | SP_FR)
|
||||
#define SP_2DOT1 (SP_FL | SP_FR | SP_LFE)
|
||||
#define SP_QUAD (SP_FL | SP_FR | SP_SL | SP_SR)
|
||||
#define SP_5DOT1 (SP_FL | SP_FR | SP_FC | SP_LFE | SP_SL | SP_SR)
|
||||
|
||||
#define TAG_VALID 0x8000
|
||||
#define TAG_CMD 0x6000
|
||||
#define TAG_PCM_LEFT 0x1000
|
||||
#define TAG_PCM_RIGHT 0x0800
|
||||
#define TAG_PCM_MDM_L1 0x0400
|
||||
#define TAG_PCM_CENTER 0x0200
|
||||
#define TAG_PCM_SL 0x0100
|
||||
#define TAG_PCM_SR 0x0080
|
||||
#define TAG_PCM_LFE 0x0040
|
||||
|
||||
void bf5xx_pcm_to_ac97(struct ac97_frame *dst, const __u16 *src, \
|
||||
size_t count, unsigned int chan_mask);
|
||||
|
||||
void bf5xx_ac97_to_pcm(const struct ac97_frame *src, __u16 *dst, \
|
||||
size_t count);
|
||||
|
||||
#endif
|
|
@ -1,109 +0,0 @@
|
|||
/*
|
||||
* File: sound/soc/blackfin/bf5xx-ad1836.c
|
||||
* Author: Barry Song <Barry.Song@analog.com>
|
||||
*
|
||||
* Created: Aug 4 2009
|
||||
* Description: Board driver for ad1836 sound chip
|
||||
*
|
||||
* Bugs: Enter bugs at http://blackfin.uclinux.org/
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
*/
|
||||
|
||||
#include <linux/module.h>
|
||||
#include <linux/moduleparam.h>
|
||||
#include <linux/device.h>
|
||||
#include <sound/core.h>
|
||||
#include <sound/pcm.h>
|
||||
#include <sound/soc.h>
|
||||
#include <sound/pcm_params.h>
|
||||
|
||||
#include <asm/blackfin.h>
|
||||
#include <asm/cacheflush.h>
|
||||
#include <asm/irq.h>
|
||||
#include <asm/dma.h>
|
||||
#include <asm/portmux.h>
|
||||
|
||||
#include "../codecs/ad1836.h"
|
||||
|
||||
static struct snd_soc_card bf5xx_ad1836;
|
||||
|
||||
static int bf5xx_ad1836_init(struct snd_soc_pcm_runtime *rtd)
|
||||
{
|
||||
struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
|
||||
unsigned int channel_map[] = {0, 4, 1, 5, 2, 6, 3, 7};
|
||||
int ret = 0;
|
||||
|
||||
/* set cpu DAI channel mapping */
|
||||
ret = snd_soc_dai_set_channel_map(cpu_dai, ARRAY_SIZE(channel_map),
|
||||
channel_map, ARRAY_SIZE(channel_map), channel_map);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
ret = snd_soc_dai_set_tdm_slot(cpu_dai, 0xFF, 0xFF, 8, 32);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#define BF5XX_AD1836_DAIFMT (SND_SOC_DAIFMT_DSP_A | SND_SOC_DAIFMT_IB_IF | \
|
||||
SND_SOC_DAIFMT_CBM_CFM)
|
||||
|
||||
static struct snd_soc_dai_link bf5xx_ad1836_dai = {
|
||||
.name = "ad1836",
|
||||
.stream_name = "AD1836",
|
||||
.codec_dai_name = "ad1836-hifi",
|
||||
.platform_name = "bfin-i2s-pcm-audio",
|
||||
.dai_fmt = BF5XX_AD1836_DAIFMT,
|
||||
.init = bf5xx_ad1836_init,
|
||||
};
|
||||
|
||||
static struct snd_soc_card bf5xx_ad1836 = {
|
||||
.name = "bfin-ad1836",
|
||||
.owner = THIS_MODULE,
|
||||
.dai_link = &bf5xx_ad1836_dai,
|
||||
.num_links = 1,
|
||||
};
|
||||
|
||||
static int bf5xx_ad1836_driver_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct snd_soc_card *card = &bf5xx_ad1836;
|
||||
const char **link_name;
|
||||
int ret;
|
||||
|
||||
link_name = pdev->dev.platform_data;
|
||||
if (!link_name) {
|
||||
dev_err(&pdev->dev, "No platform data supplied\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
bf5xx_ad1836_dai.cpu_dai_name = link_name[0];
|
||||
bf5xx_ad1836_dai.codec_name = link_name[1];
|
||||
|
||||
card->dev = &pdev->dev;
|
||||
platform_set_drvdata(pdev, card);
|
||||
|
||||
ret = devm_snd_soc_register_card(&pdev->dev, card);
|
||||
if (ret)
|
||||
dev_err(&pdev->dev, "Failed to register card\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
static struct platform_driver bf5xx_ad1836_driver = {
|
||||
.driver = {
|
||||
.name = "bfin-snd-ad1836",
|
||||
.pm = &snd_soc_pm_ops,
|
||||
},
|
||||
.probe = bf5xx_ad1836_driver_probe,
|
||||
};
|
||||
module_platform_driver(bf5xx_ad1836_driver);
|
||||
|
||||
/* Module information */
|
||||
MODULE_AUTHOR("Barry Song");
|
||||
MODULE_DESCRIPTION("ALSA SoC AD1836 board driver");
|
||||
MODULE_LICENSE("GPL");
|
||||
|
|
@ -1,131 +0,0 @@
|
|||
/*
|
||||
* File: sound/soc/blackfin/bf5xx-ad193x.c
|
||||
* Author: Barry Song <Barry.Song@analog.com>
|
||||
*
|
||||
* Created: Thur June 4 2009
|
||||
* Description: Board driver for ad193x sound chip
|
||||
*
|
||||
* Bugs: Enter bugs at http://blackfin.uclinux.org/
|
||||
*
|
||||
* 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 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, see the file COPYING, or write
|
||||
* to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#include <linux/module.h>
|
||||
#include <linux/moduleparam.h>
|
||||
#include <linux/device.h>
|
||||
#include <sound/core.h>
|
||||
#include <sound/pcm.h>
|
||||
#include <sound/soc.h>
|
||||
#include <sound/pcm_params.h>
|
||||
|
||||
#include <asm/blackfin.h>
|
||||
#include <asm/cacheflush.h>
|
||||
#include <asm/irq.h>
|
||||
#include <asm/dma.h>
|
||||
#include <asm/portmux.h>
|
||||
|
||||
#include "../codecs/ad193x.h"
|
||||
|
||||
static struct snd_soc_card bf5xx_ad193x;
|
||||
|
||||
static int bf5xx_ad193x_link_init(struct snd_soc_pcm_runtime *rtd)
|
||||
{
|
||||
struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
|
||||
struct snd_soc_dai *codec_dai = rtd->codec_dai;
|
||||
int ret;
|
||||
|
||||
/* set the codec system clock for DAC and ADC */
|
||||
ret = snd_soc_dai_set_sysclk(codec_dai, 0, 24576000, SND_SOC_CLOCK_IN);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
/* set codec DAI slots, 8 channels, all channels are enabled */
|
||||
ret = snd_soc_dai_set_tdm_slot(codec_dai, 0xFF, 0xFF, 8, 32);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
ret = snd_soc_dai_set_tdm_slot(cpu_dai, 0xFF, 0xFF, 8, 32);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#define BF5XX_AD193X_DAIFMT (SND_SOC_DAIFMT_DSP_A | SND_SOC_DAIFMT_IB_IF | \
|
||||
SND_SOC_DAIFMT_CBM_CFM)
|
||||
|
||||
static struct snd_soc_dai_link bf5xx_ad193x_dai[] = {
|
||||
{
|
||||
.name = "ad193x",
|
||||
.stream_name = "AD193X",
|
||||
.cpu_dai_name = "bfin-i2s.0",
|
||||
.codec_dai_name ="ad193x-hifi",
|
||||
.platform_name = "bfin-i2s-pcm-audio",
|
||||
.codec_name = "spi0.5",
|
||||
.dai_fmt = BF5XX_AD193X_DAIFMT,
|
||||
.init = bf5xx_ad193x_link_init,
|
||||
},
|
||||
{
|
||||
.name = "ad193x",
|
||||
.stream_name = "AD193X",
|
||||
.cpu_dai_name = "bfin-i2s.1",
|
||||
.codec_dai_name ="ad193x-hifi",
|
||||
.platform_name = "bfin-i2s-pcm-audio",
|
||||
.codec_name = "spi0.5",
|
||||
.dai_fmt = BF5XX_AD193X_DAIFMT,
|
||||
.init = bf5xx_ad193x_link_init,
|
||||
},
|
||||
};
|
||||
|
||||
static struct snd_soc_card bf5xx_ad193x = {
|
||||
.name = "bfin-ad193x",
|
||||
.owner = THIS_MODULE,
|
||||
.dai_link = &bf5xx_ad193x_dai[CONFIG_SND_BF5XX_SPORT_NUM],
|
||||
.num_links = 1,
|
||||
};
|
||||
|
||||
static struct platform_device *bfxx_ad193x_snd_device;
|
||||
|
||||
static int __init bf5xx_ad193x_init(void)
|
||||
{
|
||||
int ret;
|
||||
|
||||
bfxx_ad193x_snd_device = platform_device_alloc("soc-audio", -1);
|
||||
if (!bfxx_ad193x_snd_device)
|
||||
return -ENOMEM;
|
||||
|
||||
platform_set_drvdata(bfxx_ad193x_snd_device, &bf5xx_ad193x);
|
||||
ret = platform_device_add(bfxx_ad193x_snd_device);
|
||||
|
||||
if (ret)
|
||||
platform_device_put(bfxx_ad193x_snd_device);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void __exit bf5xx_ad193x_exit(void)
|
||||
{
|
||||
platform_device_unregister(bfxx_ad193x_snd_device);
|
||||
}
|
||||
|
||||
module_init(bf5xx_ad193x_init);
|
||||
module_exit(bf5xx_ad193x_exit);
|
||||
|
||||
/* Module information */
|
||||
MODULE_AUTHOR("Barry Song");
|
||||
MODULE_DESCRIPTION("ALSA SoC AD193X board driver");
|
||||
MODULE_LICENSE("GPL");
|
||||
|
|
@ -1,109 +0,0 @@
|
|||
/*
|
||||
* File: sound/soc/blackfin/bf5xx-ad1980.c
|
||||
* Author: Cliff Cai <Cliff.Cai@analog.com>
|
||||
*
|
||||
* Created: Tue June 06 2008
|
||||
* Description: Board driver for AD1980/1 audio codec
|
||||
*
|
||||
* Modified:
|
||||
* Copyright 2008 Analog Devices Inc.
|
||||
*
|
||||
* Bugs: Enter bugs at http://blackfin.uclinux.org/
|
||||
*
|
||||
* 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 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, see the file COPYING, or write
|
||||
* to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
/*
|
||||
* WARNING:
|
||||
*
|
||||
* Because Analog Devices Inc. discontinued the ad1980 sound chip since
|
||||
* Sep. 2009, this ad1980 driver is not maintained, tested and supported
|
||||
* by ADI now.
|
||||
*/
|
||||
|
||||
#include <linux/module.h>
|
||||
#include <linux/moduleparam.h>
|
||||
#include <linux/device.h>
|
||||
#include <asm/dma.h>
|
||||
|
||||
#include <sound/core.h>
|
||||
#include <sound/pcm.h>
|
||||
#include <sound/soc.h>
|
||||
|
||||
#include <linux/gpio.h>
|
||||
#include <asm/portmux.h>
|
||||
|
||||
#include "bf5xx-ac97.h"
|
||||
|
||||
static struct snd_soc_card bf5xx_board;
|
||||
|
||||
static struct snd_soc_dai_link bf5xx_board_dai[] = {
|
||||
{
|
||||
.name = "AC97",
|
||||
.stream_name = "AC97 HiFi",
|
||||
.cpu_dai_name = "bfin-ac97.0",
|
||||
.codec_dai_name = "ad1980-hifi",
|
||||
.platform_name = "bfin-ac97-pcm-audio",
|
||||
.codec_name = "ad1980",
|
||||
},
|
||||
{
|
||||
.name = "AC97",
|
||||
.stream_name = "AC97 HiFi",
|
||||
.cpu_dai_name = "bfin-ac97.1",
|
||||
.codec_dai_name = "ad1980-hifi",
|
||||
.platform_name = "bfin-ac97-pcm-audio",
|
||||
.codec_name = "ad1980",
|
||||
},
|
||||
};
|
||||
|
||||
static struct snd_soc_card bf5xx_board = {
|
||||
.name = "bfin-ad1980",
|
||||
.owner = THIS_MODULE,
|
||||
.dai_link = &bf5xx_board_dai[CONFIG_SND_BF5XX_SPORT_NUM],
|
||||
.num_links = 1,
|
||||
};
|
||||
|
||||
static struct platform_device *bf5xx_board_snd_device;
|
||||
|
||||
static int __init bf5xx_board_init(void)
|
||||
{
|
||||
int ret;
|
||||
|
||||
bf5xx_board_snd_device = platform_device_alloc("soc-audio", -1);
|
||||
if (!bf5xx_board_snd_device)
|
||||
return -ENOMEM;
|
||||
|
||||
platform_set_drvdata(bf5xx_board_snd_device, &bf5xx_board);
|
||||
ret = platform_device_add(bf5xx_board_snd_device);
|
||||
|
||||
if (ret)
|
||||
platform_device_put(bf5xx_board_snd_device);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void __exit bf5xx_board_exit(void)
|
||||
{
|
||||
platform_device_unregister(bf5xx_board_snd_device);
|
||||
}
|
||||
|
||||
module_init(bf5xx_board_init);
|
||||
module_exit(bf5xx_board_exit);
|
||||
|
||||
/* Module information */
|
||||
MODULE_AUTHOR("Cliff Cai");
|
||||
MODULE_DESCRIPTION("ALSA SoC AD1980/1 BF5xx board (Obsolete)");
|
||||
MODULE_LICENSE("GPL");
|
|
@ -1,212 +0,0 @@
|
|||
/*
|
||||
* File: sound/soc/blackfin/bf5xx-ad73311.c
|
||||
* Author: Cliff Cai <Cliff.Cai@analog.com>
|
||||
*
|
||||
* Created: Thur Sep 25 2008
|
||||
* Description: Board driver for ad73311 sound chip
|
||||
*
|
||||
* Modified:
|
||||
* Copyright 2008 Analog Devices Inc.
|
||||
*
|
||||
* Bugs: Enter bugs at http://blackfin.uclinux.org/
|
||||
*
|
||||
* 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 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, see the file COPYING, or write
|
||||
* to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#include <linux/module.h>
|
||||
#include <linux/moduleparam.h>
|
||||
#include <linux/device.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/gpio.h>
|
||||
|
||||
#include <sound/core.h>
|
||||
#include <sound/pcm.h>
|
||||
#include <sound/soc.h>
|
||||
#include <sound/pcm_params.h>
|
||||
|
||||
#include <asm/blackfin.h>
|
||||
#include <asm/cacheflush.h>
|
||||
#include <asm/irq.h>
|
||||
#include <asm/dma.h>
|
||||
#include <asm/portmux.h>
|
||||
|
||||
#include "../codecs/ad73311.h"
|
||||
#include "bf5xx-sport.h"
|
||||
|
||||
#if CONFIG_SND_BF5XX_SPORT_NUM == 0
|
||||
#define bfin_write_SPORT_TCR1 bfin_write_SPORT0_TCR1
|
||||
#define bfin_read_SPORT_TCR1 bfin_read_SPORT0_TCR1
|
||||
#define bfin_write_SPORT_TCR2 bfin_write_SPORT0_TCR2
|
||||
#define bfin_write_SPORT_TX16 bfin_write_SPORT0_TX16
|
||||
#define bfin_read_SPORT_STAT bfin_read_SPORT0_STAT
|
||||
#else
|
||||
#define bfin_write_SPORT_TCR1 bfin_write_SPORT1_TCR1
|
||||
#define bfin_read_SPORT_TCR1 bfin_read_SPORT1_TCR1
|
||||
#define bfin_write_SPORT_TCR2 bfin_write_SPORT1_TCR2
|
||||
#define bfin_write_SPORT_TX16 bfin_write_SPORT1_TX16
|
||||
#define bfin_read_SPORT_STAT bfin_read_SPORT1_STAT
|
||||
#endif
|
||||
|
||||
#define GPIO_SE CONFIG_SND_BFIN_AD73311_SE
|
||||
|
||||
static struct snd_soc_card bf5xx_ad73311;
|
||||
|
||||
static int snd_ad73311_startup(void)
|
||||
{
|
||||
pr_debug("%s enter\n", __func__);
|
||||
|
||||
/* Pull up SE pin on AD73311L */
|
||||
gpio_set_value(GPIO_SE, 1);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int snd_ad73311_configure(void)
|
||||
{
|
||||
unsigned short ctrl_regs[6];
|
||||
unsigned short status = 0;
|
||||
int count = 0;
|
||||
|
||||
/* DMCLK = MCLK = 16.384 MHz
|
||||
* SCLK = DMCLK/8 = 2.048 MHz
|
||||
* Sample Rate = DMCLK/2048 = 8 KHz
|
||||
*/
|
||||
ctrl_regs[0] = AD_CONTROL | AD_WRITE | CTRL_REG_B | REGB_MCDIV(0) | \
|
||||
REGB_SCDIV(0) | REGB_DIRATE(0);
|
||||
ctrl_regs[1] = AD_CONTROL | AD_WRITE | CTRL_REG_C | REGC_PUDEV | \
|
||||
REGC_PUADC | REGC_PUDAC | REGC_PUREF | REGC_REFUSE ;
|
||||
ctrl_regs[2] = AD_CONTROL | AD_WRITE | CTRL_REG_D | REGD_OGS(2) | \
|
||||
REGD_IGS(2);
|
||||
ctrl_regs[3] = AD_CONTROL | AD_WRITE | CTRL_REG_E | REGE_DA(0x1f);
|
||||
ctrl_regs[4] = AD_CONTROL | AD_WRITE | CTRL_REG_F | REGF_SEEN ;
|
||||
ctrl_regs[5] = AD_CONTROL | AD_WRITE | CTRL_REG_A | REGA_MODE_DATA;
|
||||
|
||||
local_irq_disable();
|
||||
snd_ad73311_startup();
|
||||
udelay(1);
|
||||
|
||||
bfin_write_SPORT_TCR1(TFSR);
|
||||
bfin_write_SPORT_TCR2(0xF);
|
||||
SSYNC();
|
||||
|
||||
/* SPORT Tx Register is a 8 x 16 FIFO, all the data can be put to
|
||||
* FIFO before enable SPORT to transfer the data
|
||||
*/
|
||||
for (count = 0; count < 6; count++)
|
||||
bfin_write_SPORT_TX16(ctrl_regs[count]);
|
||||
SSYNC();
|
||||
bfin_write_SPORT_TCR1(bfin_read_SPORT_TCR1() | TSPEN);
|
||||
SSYNC();
|
||||
|
||||
/* When TUVF is set, the data is already send out */
|
||||
while (!(status & TUVF) && ++count < 10000) {
|
||||
udelay(1);
|
||||
status = bfin_read_SPORT_STAT();
|
||||
SSYNC();
|
||||
}
|
||||
bfin_write_SPORT_TCR1(bfin_read_SPORT_TCR1() & ~TSPEN);
|
||||
SSYNC();
|
||||
local_irq_enable();
|
||||
|
||||
if (count >= 10000) {
|
||||
printk(KERN_ERR "ad73311: failed to configure codec\n");
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int bf5xx_probe(struct snd_soc_card *card)
|
||||
{
|
||||
int err;
|
||||
if (gpio_request(GPIO_SE, "AD73311_SE")) {
|
||||
printk(KERN_ERR "%s: Failed ro request GPIO_%d\n", __func__, GPIO_SE);
|
||||
return -EBUSY;
|
||||
}
|
||||
|
||||
gpio_direction_output(GPIO_SE, 0);
|
||||
|
||||
err = snd_ad73311_configure();
|
||||
if (err < 0)
|
||||
return -EFAULT;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#define BF5XX_AD7311_DAI_FMT (SND_SOC_DAIFMT_DSP_A | SND_SOC_DAIFMT_NB_NF | \
|
||||
SND_SOC_DAIFMT_CBM_CFM)
|
||||
|
||||
static struct snd_soc_dai_link bf5xx_ad73311_dai[] = {
|
||||
{
|
||||
.name = "ad73311",
|
||||
.stream_name = "AD73311",
|
||||
.cpu_dai_name = "bfin-i2s.0",
|
||||
.codec_dai_name = "ad73311-hifi",
|
||||
.platform_name = "bfin-i2s-pcm-audio",
|
||||
.codec_name = "ad73311",
|
||||
.dai_fmt = BF5XX_AD7311_DAI_FMT,
|
||||
},
|
||||
{
|
||||
.name = "ad73311",
|
||||
.stream_name = "AD73311",
|
||||
.cpu_dai_name = "bfin-i2s.1",
|
||||
.codec_dai_name = "ad73311-hifi",
|
||||
.platform_name = "bfin-i2s-pcm-audio",
|
||||
.codec_name = "ad73311",
|
||||
.dai_fmt = BF5XX_AD7311_DAI_FMT,
|
||||
},
|
||||
};
|
||||
|
||||
static struct snd_soc_card bf5xx_ad73311 = {
|
||||
.name = "bfin-ad73311",
|
||||
.owner = THIS_MODULE,
|
||||
.probe = bf5xx_probe,
|
||||
.dai_link = &bf5xx_ad73311_dai[CONFIG_SND_BF5XX_SPORT_NUM],
|
||||
.num_links = 1,
|
||||
};
|
||||
|
||||
static struct platform_device *bf5xx_ad73311_snd_device;
|
||||
|
||||
static int __init bf5xx_ad73311_init(void)
|
||||
{
|
||||
int ret;
|
||||
|
||||
pr_debug("%s enter\n", __func__);
|
||||
bf5xx_ad73311_snd_device = platform_device_alloc("soc-audio", -1);
|
||||
if (!bf5xx_ad73311_snd_device)
|
||||
return -ENOMEM;
|
||||
|
||||
platform_set_drvdata(bf5xx_ad73311_snd_device, &bf5xx_ad73311);
|
||||
ret = platform_device_add(bf5xx_ad73311_snd_device);
|
||||
|
||||
if (ret)
|
||||
platform_device_put(bf5xx_ad73311_snd_device);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void __exit bf5xx_ad73311_exit(void)
|
||||
{
|
||||
pr_debug("%s enter\n", __func__);
|
||||
platform_device_unregister(bf5xx_ad73311_snd_device);
|
||||
}
|
||||
|
||||
module_init(bf5xx_ad73311_init);
|
||||
module_exit(bf5xx_ad73311_exit);
|
||||
|
||||
/* Module information */
|
||||
MODULE_AUTHOR("Cliff Cai");
|
||||
MODULE_DESCRIPTION("ALSA SoC AD73311 Blackfin");
|
||||
MODULE_LICENSE("GPL");
|
||||
|
|
@ -1,373 +0,0 @@
|
|||
/*
|
||||
* File: sound/soc/blackfin/bf5xx-i2s-pcm.c
|
||||
* Author: Cliff Cai <Cliff.Cai@analog.com>
|
||||
*
|
||||
* Created: Tue June 06 2008
|
||||
* Description: DMA driver for i2s codec
|
||||
*
|
||||
* Modified:
|
||||
* Copyright 2008 Analog Devices Inc.
|
||||
*
|
||||
* Bugs: Enter bugs at http://blackfin.uclinux.org/
|
||||
*
|
||||
* 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 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, see the file COPYING, or write
|
||||
* to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#include <linux/module.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/dma-mapping.h>
|
||||
#include <linux/gfp.h>
|
||||
|
||||
#include <sound/core.h>
|
||||
#include <sound/pcm.h>
|
||||
#include <sound/pcm_params.h>
|
||||
#include <sound/soc.h>
|
||||
|
||||
#include <asm/dma.h>
|
||||
|
||||
#include "bf5xx-sport.h"
|
||||
#include "bf5xx-i2s-pcm.h"
|
||||
|
||||
static void bf5xx_dma_irq(void *data)
|
||||
{
|
||||
struct snd_pcm_substream *pcm = data;
|
||||
snd_pcm_period_elapsed(pcm);
|
||||
}
|
||||
|
||||
static const struct snd_pcm_hardware bf5xx_pcm_hardware = {
|
||||
.info = SNDRV_PCM_INFO_INTERLEAVED |
|
||||
SNDRV_PCM_INFO_MMAP_VALID |
|
||||
SNDRV_PCM_INFO_BLOCK_TRANSFER,
|
||||
.period_bytes_min = 32,
|
||||
.period_bytes_max = 0x10000,
|
||||
.periods_min = 1,
|
||||
.periods_max = PAGE_SIZE/32,
|
||||
.buffer_bytes_max = 0x20000, /* 128 kbytes */
|
||||
.fifo_size = 16,
|
||||
};
|
||||
|
||||
static int bf5xx_pcm_hw_params(struct snd_pcm_substream *substream,
|
||||
struct snd_pcm_hw_params *params)
|
||||
{
|
||||
struct snd_soc_pcm_runtime *rtd = substream->private_data;
|
||||
unsigned int buffer_size = params_buffer_bytes(params);
|
||||
struct bf5xx_i2s_pcm_data *dma_data;
|
||||
|
||||
dma_data = snd_soc_dai_get_dma_data(rtd->cpu_dai, substream);
|
||||
|
||||
if (dma_data->tdm_mode)
|
||||
buffer_size = buffer_size / params_channels(params) * 8;
|
||||
|
||||
return snd_pcm_lib_malloc_pages(substream, buffer_size);
|
||||
}
|
||||
|
||||
static int bf5xx_pcm_hw_free(struct snd_pcm_substream *substream)
|
||||
{
|
||||
snd_pcm_lib_free_pages(substream);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int bf5xx_pcm_prepare(struct snd_pcm_substream *substream)
|
||||
{
|
||||
struct snd_soc_pcm_runtime *rtd = substream->private_data;
|
||||
struct snd_pcm_runtime *runtime = substream->runtime;
|
||||
struct sport_device *sport = runtime->private_data;
|
||||
int period_bytes = frames_to_bytes(runtime, runtime->period_size);
|
||||
struct bf5xx_i2s_pcm_data *dma_data;
|
||||
|
||||
dma_data = snd_soc_dai_get_dma_data(rtd->cpu_dai, substream);
|
||||
|
||||
if (dma_data->tdm_mode)
|
||||
period_bytes = period_bytes / runtime->channels * 8;
|
||||
|
||||
pr_debug("%s enter\n", __func__);
|
||||
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
|
||||
sport_set_tx_callback(sport, bf5xx_dma_irq, substream);
|
||||
sport_config_tx_dma(sport, runtime->dma_area,
|
||||
runtime->periods, period_bytes);
|
||||
} else {
|
||||
sport_set_rx_callback(sport, bf5xx_dma_irq, substream);
|
||||
sport_config_rx_dma(sport, runtime->dma_area,
|
||||
runtime->periods, period_bytes);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int bf5xx_pcm_trigger(struct snd_pcm_substream *substream, int cmd)
|
||||
{
|
||||
struct snd_pcm_runtime *runtime = substream->runtime;
|
||||
struct sport_device *sport = runtime->private_data;
|
||||
int ret = 0;
|
||||
|
||||
pr_debug("%s enter\n", __func__);
|
||||
switch (cmd) {
|
||||
case SNDRV_PCM_TRIGGER_START:
|
||||
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
|
||||
sport_tx_start(sport);
|
||||
else
|
||||
sport_rx_start(sport);
|
||||
break;
|
||||
case SNDRV_PCM_TRIGGER_STOP:
|
||||
case SNDRV_PCM_TRIGGER_SUSPEND:
|
||||
case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
|
||||
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
|
||||
sport_tx_stop(sport);
|
||||
else
|
||||
sport_rx_stop(sport);
|
||||
break;
|
||||
default:
|
||||
ret = -EINVAL;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static snd_pcm_uframes_t bf5xx_pcm_pointer(struct snd_pcm_substream *substream)
|
||||
{
|
||||
struct snd_soc_pcm_runtime *rtd = substream->private_data;
|
||||
struct snd_pcm_runtime *runtime = substream->runtime;
|
||||
struct sport_device *sport = runtime->private_data;
|
||||
unsigned int diff;
|
||||
snd_pcm_uframes_t frames;
|
||||
struct bf5xx_i2s_pcm_data *dma_data;
|
||||
|
||||
dma_data = snd_soc_dai_get_dma_data(rtd->cpu_dai, substream);
|
||||
|
||||
pr_debug("%s enter\n", __func__);
|
||||
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
|
||||
diff = sport_curr_offset_tx(sport);
|
||||
} else {
|
||||
diff = sport_curr_offset_rx(sport);
|
||||
}
|
||||
|
||||
/*
|
||||
* TX at least can report one frame beyond the end of the
|
||||
* buffer if we hit the wraparound case - clamp to within the
|
||||
* buffer as the ALSA APIs require.
|
||||
*/
|
||||
if (diff == snd_pcm_lib_buffer_bytes(substream))
|
||||
diff = 0;
|
||||
|
||||
frames = bytes_to_frames(substream->runtime, diff);
|
||||
if (dma_data->tdm_mode)
|
||||
frames = frames * runtime->channels / 8;
|
||||
|
||||
return frames;
|
||||
}
|
||||
|
||||
static int bf5xx_pcm_open(struct snd_pcm_substream *substream)
|
||||
{
|
||||
struct snd_soc_pcm_runtime *rtd = substream->private_data;
|
||||
struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
|
||||
struct sport_device *sport_handle = snd_soc_dai_get_drvdata(cpu_dai);
|
||||
struct snd_pcm_runtime *runtime = substream->runtime;
|
||||
struct snd_dma_buffer *buf = &substream->dma_buffer;
|
||||
struct bf5xx_i2s_pcm_data *dma_data;
|
||||
int ret;
|
||||
|
||||
dma_data = snd_soc_dai_get_dma_data(rtd->cpu_dai, substream);
|
||||
|
||||
pr_debug("%s enter\n", __func__);
|
||||
|
||||
snd_soc_set_runtime_hwparams(substream, &bf5xx_pcm_hardware);
|
||||
if (dma_data->tdm_mode)
|
||||
runtime->hw.buffer_bytes_max /= 4;
|
||||
else
|
||||
runtime->hw.info |= SNDRV_PCM_INFO_MMAP;
|
||||
|
||||
ret = snd_pcm_hw_constraint_integer(runtime,
|
||||
SNDRV_PCM_HW_PARAM_PERIODS);
|
||||
if (ret < 0)
|
||||
goto out;
|
||||
|
||||
if (sport_handle != NULL) {
|
||||
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
|
||||
sport_handle->tx_buf = buf->area;
|
||||
else
|
||||
sport_handle->rx_buf = buf->area;
|
||||
|
||||
runtime->private_data = sport_handle;
|
||||
} else {
|
||||
pr_err("sport_handle is NULL\n");
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
|
||||
out:
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int bf5xx_pcm_mmap(struct snd_pcm_substream *substream,
|
||||
struct vm_area_struct *vma)
|
||||
{
|
||||
struct snd_pcm_runtime *runtime = substream->runtime;
|
||||
size_t size = vma->vm_end - vma->vm_start;
|
||||
vma->vm_start = (unsigned long)runtime->dma_area;
|
||||
vma->vm_end = vma->vm_start + size;
|
||||
vma->vm_flags |= VM_SHARED;
|
||||
|
||||
return 0 ;
|
||||
}
|
||||
|
||||
static int bf5xx_pcm_copy(struct snd_pcm_substream *substream,
|
||||
int channel, unsigned long pos,
|
||||
void *buf, unsigned long count)
|
||||
{
|
||||
struct snd_soc_pcm_runtime *rtd = substream->private_data;
|
||||
struct snd_pcm_runtime *runtime = substream->runtime;
|
||||
unsigned int sample_size = runtime->sample_bits / 8;
|
||||
struct bf5xx_i2s_pcm_data *dma_data;
|
||||
unsigned int i;
|
||||
void *src, *dst;
|
||||
|
||||
dma_data = snd_soc_dai_get_dma_data(rtd->cpu_dai, substream);
|
||||
|
||||
if (dma_data->tdm_mode) {
|
||||
pos = bytes_to_frames(runtime, pos);
|
||||
count = bytes_to_frames(runtime, count);
|
||||
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
|
||||
src = buf;
|
||||
dst = runtime->dma_area;
|
||||
dst += pos * sample_size * 8;
|
||||
|
||||
while (count--) {
|
||||
for (i = 0; i < runtime->channels; i++) {
|
||||
memcpy(dst + dma_data->map[i] *
|
||||
sample_size, src, sample_size);
|
||||
src += sample_size;
|
||||
}
|
||||
dst += 8 * sample_size;
|
||||
}
|
||||
} else {
|
||||
src = runtime->dma_area;
|
||||
src += pos * sample_size * 8;
|
||||
dst = buf;
|
||||
|
||||
while (count--) {
|
||||
for (i = 0; i < runtime->channels; i++) {
|
||||
memcpy(dst, src + dma_data->map[i] *
|
||||
sample_size, sample_size);
|
||||
dst += sample_size;
|
||||
}
|
||||
src += 8 * sample_size;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
|
||||
src = buf;
|
||||
dst = runtime->dma_area;
|
||||
dst += pos;
|
||||
} else {
|
||||
src = runtime->dma_area;
|
||||
src += pos;
|
||||
dst = buf;
|
||||
}
|
||||
|
||||
memcpy(dst, src, count);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int bf5xx_pcm_copy_user(struct snd_pcm_substream *substream,
|
||||
int channel, unsigned long pos,
|
||||
void __user *buf, unsigned long count)
|
||||
{
|
||||
return bf5xx_pcm_copy(substream, channel, pos, (void *)buf, count);
|
||||
}
|
||||
|
||||
static int bf5xx_pcm_silence(struct snd_pcm_substream *substream,
|
||||
int channel, unsigned long pos,
|
||||
unsigned long count)
|
||||
{
|
||||
struct snd_soc_pcm_runtime *rtd = substream->private_data;
|
||||
struct snd_pcm_runtime *runtime = substream->runtime;
|
||||
unsigned int sample_size = runtime->sample_bits / 8;
|
||||
void *buf = runtime->dma_area;
|
||||
struct bf5xx_i2s_pcm_data *dma_data;
|
||||
unsigned int offset, samples;
|
||||
|
||||
dma_data = snd_soc_dai_get_dma_data(rtd->cpu_dai, substream);
|
||||
|
||||
if (dma_data->tdm_mode) {
|
||||
offset = bytes_to_frames(runtime, pos) * 8 * sample_size;
|
||||
samples = bytes_to_frames(runtime, count) * 8;
|
||||
} else {
|
||||
offset = pos;
|
||||
samples = bytes_to_samples(runtime, count);
|
||||
}
|
||||
|
||||
snd_pcm_format_set_silence(runtime->format, buf + offset, samples);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct snd_pcm_ops bf5xx_pcm_i2s_ops = {
|
||||
.open = bf5xx_pcm_open,
|
||||
.ioctl = snd_pcm_lib_ioctl,
|
||||
.hw_params = bf5xx_pcm_hw_params,
|
||||
.hw_free = bf5xx_pcm_hw_free,
|
||||
.prepare = bf5xx_pcm_prepare,
|
||||
.trigger = bf5xx_pcm_trigger,
|
||||
.pointer = bf5xx_pcm_pointer,
|
||||
.mmap = bf5xx_pcm_mmap,
|
||||
.copy_user = bf5xx_pcm_copy_user,
|
||||
.copy_kernel = bf5xx_pcm_copy,
|
||||
.fill_silence = bf5xx_pcm_silence,
|
||||
};
|
||||
|
||||
static int bf5xx_pcm_i2s_new(struct snd_soc_pcm_runtime *rtd)
|
||||
{
|
||||
struct snd_card *card = rtd->card->snd_card;
|
||||
size_t size = bf5xx_pcm_hardware.buffer_bytes_max;
|
||||
int ret;
|
||||
|
||||
pr_debug("%s enter\n", __func__);
|
||||
ret = dma_coerce_mask_and_coherent(card->dev, DMA_BIT_MASK(32));
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
return snd_pcm_lib_preallocate_pages_for_all(rtd->pcm,
|
||||
SNDRV_DMA_TYPE_DEV, card->dev, size, size);
|
||||
}
|
||||
|
||||
static struct snd_soc_component_driver bf5xx_i2s_soc_component = {
|
||||
.ops = &bf5xx_pcm_i2s_ops,
|
||||
.pcm_new = bf5xx_pcm_i2s_new,
|
||||
};
|
||||
|
||||
static int bfin_i2s_soc_platform_probe(struct platform_device *pdev)
|
||||
{
|
||||
return devm_snd_soc_register_component(&pdev->dev,
|
||||
&bf5xx_i2s_soc_component, NULL, 0);
|
||||
}
|
||||
|
||||
static struct platform_driver bfin_i2s_pcm_driver = {
|
||||
.driver = {
|
||||
.name = "bfin-i2s-pcm-audio",
|
||||
},
|
||||
|
||||
.probe = bfin_i2s_soc_platform_probe,
|
||||
};
|
||||
|
||||
module_platform_driver(bfin_i2s_pcm_driver);
|
||||
|
||||
MODULE_AUTHOR("Cliff Cai");
|
||||
MODULE_DESCRIPTION("ADI Blackfin I2S PCM DMA module");
|
||||
MODULE_LICENSE("GPL");
|
|
@ -1,17 +0,0 @@
|
|||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#ifndef _BF5XX_TDM_PCM_H
|
||||
#define _BF5XX_TDM_PCM_H
|
||||
|
||||
#define BFIN_TDM_DAI_MAX_SLOTS 8
|
||||
|
||||
struct bf5xx_i2s_pcm_data {
|
||||
unsigned int map[BFIN_TDM_DAI_MAX_SLOTS];
|
||||
bool tdm_mode;
|
||||
};
|
||||
|
||||
#endif
|
|
@ -1,391 +0,0 @@
|
|||
/*
|
||||
* File: sound/soc/blackfin/bf5xx-i2s.c
|
||||
* Author: Cliff Cai <Cliff.Cai@analog.com>
|
||||
*
|
||||
* Created: Tue June 06 2008
|
||||
* Description: Blackfin I2S CPU DAI driver
|
||||
*
|
||||
* Modified:
|
||||
* Copyright 2008 Analog Devices Inc.
|
||||
*
|
||||
* Bugs: Enter bugs at http://blackfin.uclinux.org/
|
||||
*
|
||||
* 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 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, see the file COPYING, or write
|
||||
* to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#include <linux/init.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/device.h>
|
||||
#include <linux/delay.h>
|
||||
#include <sound/core.h>
|
||||
#include <sound/pcm.h>
|
||||
#include <sound/pcm_params.h>
|
||||
#include <sound/initval.h>
|
||||
#include <sound/soc.h>
|
||||
|
||||
#include <asm/irq.h>
|
||||
#include <asm/portmux.h>
|
||||
#include <linux/mutex.h>
|
||||
#include <linux/gpio.h>
|
||||
|
||||
#include "bf5xx-sport.h"
|
||||
#include "bf5xx-i2s-pcm.h"
|
||||
|
||||
struct bf5xx_i2s_port {
|
||||
u16 tcr1;
|
||||
u16 rcr1;
|
||||
u16 tcr2;
|
||||
u16 rcr2;
|
||||
int configured;
|
||||
|
||||
unsigned int slots;
|
||||
unsigned int tx_mask;
|
||||
unsigned int rx_mask;
|
||||
|
||||
struct bf5xx_i2s_pcm_data tx_dma_data;
|
||||
struct bf5xx_i2s_pcm_data rx_dma_data;
|
||||
};
|
||||
|
||||
static int bf5xx_i2s_set_dai_fmt(struct snd_soc_dai *cpu_dai,
|
||||
unsigned int fmt)
|
||||
{
|
||||
struct sport_device *sport_handle = snd_soc_dai_get_drvdata(cpu_dai);
|
||||
struct bf5xx_i2s_port *bf5xx_i2s = sport_handle->private_data;
|
||||
int ret = 0;
|
||||
|
||||
/* interface format:support I2S,slave mode */
|
||||
switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
|
||||
case SND_SOC_DAIFMT_I2S:
|
||||
bf5xx_i2s->tcr1 |= TFSR | TCKFE;
|
||||
bf5xx_i2s->rcr1 |= RFSR | RCKFE;
|
||||
bf5xx_i2s->tcr2 |= TSFSE;
|
||||
bf5xx_i2s->rcr2 |= RSFSE;
|
||||
break;
|
||||
case SND_SOC_DAIFMT_DSP_A:
|
||||
bf5xx_i2s->tcr1 |= TFSR;
|
||||
bf5xx_i2s->rcr1 |= RFSR;
|
||||
break;
|
||||
case SND_SOC_DAIFMT_LEFT_J:
|
||||
ret = -EINVAL;
|
||||
break;
|
||||
default:
|
||||
dev_err(cpu_dai->dev, "%s: Unknown DAI format type\n",
|
||||
__func__);
|
||||
ret = -EINVAL;
|
||||
break;
|
||||
}
|
||||
|
||||
switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
|
||||
case SND_SOC_DAIFMT_CBM_CFM:
|
||||
break;
|
||||
case SND_SOC_DAIFMT_CBS_CFS:
|
||||
case SND_SOC_DAIFMT_CBM_CFS:
|
||||
case SND_SOC_DAIFMT_CBS_CFM:
|
||||
ret = -EINVAL;
|
||||
break;
|
||||
default:
|
||||
dev_err(cpu_dai->dev, "%s: Unknown DAI master type\n",
|
||||
__func__);
|
||||
ret = -EINVAL;
|
||||
break;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int bf5xx_i2s_hw_params(struct snd_pcm_substream *substream,
|
||||
struct snd_pcm_hw_params *params,
|
||||
struct snd_soc_dai *dai)
|
||||
{
|
||||
struct sport_device *sport_handle = snd_soc_dai_get_drvdata(dai);
|
||||
struct bf5xx_i2s_port *bf5xx_i2s = sport_handle->private_data;
|
||||
int ret = 0;
|
||||
|
||||
bf5xx_i2s->tcr2 &= ~0x1f;
|
||||
bf5xx_i2s->rcr2 &= ~0x1f;
|
||||
switch (params_format(params)) {
|
||||
case SNDRV_PCM_FORMAT_S8:
|
||||
bf5xx_i2s->tcr2 |= 7;
|
||||
bf5xx_i2s->rcr2 |= 7;
|
||||
sport_handle->wdsize = 1;
|
||||
break;
|
||||
case SNDRV_PCM_FORMAT_S16_LE:
|
||||
bf5xx_i2s->tcr2 |= 15;
|
||||
bf5xx_i2s->rcr2 |= 15;
|
||||
sport_handle->wdsize = 2;
|
||||
break;
|
||||
case SNDRV_PCM_FORMAT_S24_LE:
|
||||
bf5xx_i2s->tcr2 |= 23;
|
||||
bf5xx_i2s->rcr2 |= 23;
|
||||
sport_handle->wdsize = 3;
|
||||
break;
|
||||
case SNDRV_PCM_FORMAT_S32_LE:
|
||||
bf5xx_i2s->tcr2 |= 31;
|
||||
bf5xx_i2s->rcr2 |= 31;
|
||||
sport_handle->wdsize = 4;
|
||||
break;
|
||||
}
|
||||
|
||||
if (!bf5xx_i2s->configured) {
|
||||
/*
|
||||
* TX and RX are not independent,they are enabled at the
|
||||
* same time, even if only one side is running. So, we
|
||||
* need to configure both of them at the time when the first
|
||||
* stream is opened.
|
||||
*
|
||||
* CPU DAI:slave mode.
|
||||
*/
|
||||
bf5xx_i2s->configured = 1;
|
||||
ret = sport_config_rx(sport_handle, bf5xx_i2s->rcr1,
|
||||
bf5xx_i2s->rcr2, 0, 0);
|
||||
if (ret) {
|
||||
dev_err(dai->dev, "SPORT is busy!\n");
|
||||
return -EBUSY;
|
||||
}
|
||||
|
||||
ret = sport_config_tx(sport_handle, bf5xx_i2s->tcr1,
|
||||
bf5xx_i2s->tcr2, 0, 0);
|
||||
if (ret) {
|
||||
dev_err(dai->dev, "SPORT is busy!\n");
|
||||
return -EBUSY;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void bf5xx_i2s_shutdown(struct snd_pcm_substream *substream,
|
||||
struct snd_soc_dai *dai)
|
||||
{
|
||||
struct sport_device *sport_handle = snd_soc_dai_get_drvdata(dai);
|
||||
struct bf5xx_i2s_port *bf5xx_i2s = sport_handle->private_data;
|
||||
|
||||
dev_dbg(dai->dev, "%s enter\n", __func__);
|
||||
/* No active stream, SPORT is allowed to be configured again. */
|
||||
if (!dai->active)
|
||||
bf5xx_i2s->configured = 0;
|
||||
}
|
||||
|
||||
static int bf5xx_i2s_set_channel_map(struct snd_soc_dai *dai,
|
||||
unsigned int tx_num, unsigned int *tx_slot,
|
||||
unsigned int rx_num, unsigned int *rx_slot)
|
||||
{
|
||||
struct sport_device *sport_handle = snd_soc_dai_get_drvdata(dai);
|
||||
struct bf5xx_i2s_port *bf5xx_i2s = sport_handle->private_data;
|
||||
unsigned int tx_mapped = 0, rx_mapped = 0;
|
||||
unsigned int slot;
|
||||
int i;
|
||||
|
||||
if ((tx_num > BFIN_TDM_DAI_MAX_SLOTS) ||
|
||||
(rx_num > BFIN_TDM_DAI_MAX_SLOTS))
|
||||
return -EINVAL;
|
||||
|
||||
for (i = 0; i < tx_num; i++) {
|
||||
slot = tx_slot[i];
|
||||
if ((slot < BFIN_TDM_DAI_MAX_SLOTS) &&
|
||||
(!(tx_mapped & (1 << slot)))) {
|
||||
bf5xx_i2s->tx_dma_data.map[i] = slot;
|
||||
tx_mapped |= 1 << slot;
|
||||
} else
|
||||
return -EINVAL;
|
||||
}
|
||||
for (i = 0; i < rx_num; i++) {
|
||||
slot = rx_slot[i];
|
||||
if ((slot < BFIN_TDM_DAI_MAX_SLOTS) &&
|
||||
(!(rx_mapped & (1 << slot)))) {
|
||||
bf5xx_i2s->rx_dma_data.map[i] = slot;
|
||||
rx_mapped |= 1 << slot;
|
||||
} else
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int bf5xx_i2s_set_tdm_slot(struct snd_soc_dai *dai, unsigned int tx_mask,
|
||||
unsigned int rx_mask, int slots, int width)
|
||||
{
|
||||
struct sport_device *sport_handle = snd_soc_dai_get_drvdata(dai);
|
||||
struct bf5xx_i2s_port *bf5xx_i2s = sport_handle->private_data;
|
||||
|
||||
if (slots % 8 != 0 || slots > 8)
|
||||
return -EINVAL;
|
||||
|
||||
if (width != 32)
|
||||
return -EINVAL;
|
||||
|
||||
bf5xx_i2s->slots = slots;
|
||||
bf5xx_i2s->tx_mask = tx_mask;
|
||||
bf5xx_i2s->rx_mask = rx_mask;
|
||||
|
||||
bf5xx_i2s->tx_dma_data.tdm_mode = slots != 0;
|
||||
bf5xx_i2s->rx_dma_data.tdm_mode = slots != 0;
|
||||
|
||||
return sport_set_multichannel(sport_handle, slots, tx_mask, rx_mask, 0);
|
||||
}
|
||||
|
||||
#ifdef CONFIG_PM
|
||||
static int bf5xx_i2s_suspend(struct snd_soc_dai *dai)
|
||||
{
|
||||
struct sport_device *sport_handle = snd_soc_dai_get_drvdata(dai);
|
||||
|
||||
dev_dbg(dai->dev, "%s : sport %d\n", __func__, dai->id);
|
||||
|
||||
if (dai->capture_active)
|
||||
sport_rx_stop(sport_handle);
|
||||
if (dai->playback_active)
|
||||
sport_tx_stop(sport_handle);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int bf5xx_i2s_resume(struct snd_soc_dai *dai)
|
||||
{
|
||||
struct sport_device *sport_handle = snd_soc_dai_get_drvdata(dai);
|
||||
struct bf5xx_i2s_port *bf5xx_i2s = sport_handle->private_data;
|
||||
int ret;
|
||||
|
||||
dev_dbg(dai->dev, "%s : sport %d\n", __func__, dai->id);
|
||||
|
||||
ret = sport_config_rx(sport_handle, bf5xx_i2s->rcr1,
|
||||
bf5xx_i2s->rcr2, 0, 0);
|
||||
if (ret) {
|
||||
dev_err(dai->dev, "SPORT is busy!\n");
|
||||
return -EBUSY;
|
||||
}
|
||||
|
||||
ret = sport_config_tx(sport_handle, bf5xx_i2s->tcr1,
|
||||
bf5xx_i2s->tcr2, 0, 0);
|
||||
if (ret) {
|
||||
dev_err(dai->dev, "SPORT is busy!\n");
|
||||
return -EBUSY;
|
||||
}
|
||||
|
||||
return sport_set_multichannel(sport_handle, bf5xx_i2s->slots,
|
||||
bf5xx_i2s->tx_mask, bf5xx_i2s->rx_mask, 0);
|
||||
}
|
||||
|
||||
#else
|
||||
#define bf5xx_i2s_suspend NULL
|
||||
#define bf5xx_i2s_resume NULL
|
||||
#endif
|
||||
|
||||
static int bf5xx_i2s_dai_probe(struct snd_soc_dai *dai)
|
||||
{
|
||||
struct sport_device *sport_handle = snd_soc_dai_get_drvdata(dai);
|
||||
struct bf5xx_i2s_port *bf5xx_i2s = sport_handle->private_data;
|
||||
unsigned int i;
|
||||
|
||||
for (i = 0; i < BFIN_TDM_DAI_MAX_SLOTS; i++) {
|
||||
bf5xx_i2s->tx_dma_data.map[i] = i;
|
||||
bf5xx_i2s->rx_dma_data.map[i] = i;
|
||||
}
|
||||
|
||||
dai->playback_dma_data = &bf5xx_i2s->tx_dma_data;
|
||||
dai->capture_dma_data = &bf5xx_i2s->rx_dma_data;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#define BF5XX_I2S_RATES (SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_11025 |\
|
||||
SNDRV_PCM_RATE_16000 | SNDRV_PCM_RATE_22050 | \
|
||||
SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000 | \
|
||||
SNDRV_PCM_RATE_96000)
|
||||
|
||||
#define BF5XX_I2S_FORMATS \
|
||||
(SNDRV_PCM_FMTBIT_S8 | \
|
||||
SNDRV_PCM_FMTBIT_S16_LE | \
|
||||
SNDRV_PCM_FMTBIT_S24_LE | \
|
||||
SNDRV_PCM_FMTBIT_S32_LE)
|
||||
|
||||
static const struct snd_soc_dai_ops bf5xx_i2s_dai_ops = {
|
||||
.shutdown = bf5xx_i2s_shutdown,
|
||||
.hw_params = bf5xx_i2s_hw_params,
|
||||
.set_fmt = bf5xx_i2s_set_dai_fmt,
|
||||
.set_tdm_slot = bf5xx_i2s_set_tdm_slot,
|
||||
.set_channel_map = bf5xx_i2s_set_channel_map,
|
||||
};
|
||||
|
||||
static struct snd_soc_dai_driver bf5xx_i2s_dai = {
|
||||
.probe = bf5xx_i2s_dai_probe,
|
||||
.suspend = bf5xx_i2s_suspend,
|
||||
.resume = bf5xx_i2s_resume,
|
||||
.playback = {
|
||||
.channels_min = 2,
|
||||
.channels_max = 8,
|
||||
.rates = BF5XX_I2S_RATES,
|
||||
.formats = BF5XX_I2S_FORMATS,},
|
||||
.capture = {
|
||||
.channels_min = 2,
|
||||
.channels_max = 8,
|
||||
.rates = BF5XX_I2S_RATES,
|
||||
.formats = BF5XX_I2S_FORMATS,},
|
||||
.ops = &bf5xx_i2s_dai_ops,
|
||||
};
|
||||
|
||||
static const struct snd_soc_component_driver bf5xx_i2s_component = {
|
||||
.name = "bf5xx-i2s",
|
||||
};
|
||||
|
||||
static int bf5xx_i2s_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct sport_device *sport_handle;
|
||||
int ret;
|
||||
|
||||
/* configure SPORT for I2S */
|
||||
sport_handle = sport_init(pdev, 4, 8 * sizeof(u32),
|
||||
sizeof(struct bf5xx_i2s_port));
|
||||
if (!sport_handle)
|
||||
return -ENODEV;
|
||||
|
||||
/* register with the ASoC layers */
|
||||
ret = snd_soc_register_component(&pdev->dev, &bf5xx_i2s_component,
|
||||
&bf5xx_i2s_dai, 1);
|
||||
if (ret) {
|
||||
dev_err(&pdev->dev, "Failed to register DAI: %d\n", ret);
|
||||
sport_done(sport_handle);
|
||||
return ret;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int bf5xx_i2s_remove(struct platform_device *pdev)
|
||||
{
|
||||
struct sport_device *sport_handle = platform_get_drvdata(pdev);
|
||||
|
||||
dev_dbg(&pdev->dev, "%s enter\n", __func__);
|
||||
|
||||
snd_soc_unregister_component(&pdev->dev);
|
||||
sport_done(sport_handle);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct platform_driver bfin_i2s_driver = {
|
||||
.probe = bf5xx_i2s_probe,
|
||||
.remove = bf5xx_i2s_remove,
|
||||
.driver = {
|
||||
.name = "bfin-i2s",
|
||||
},
|
||||
};
|
||||
|
||||
module_platform_driver(bfin_i2s_driver);
|
||||
|
||||
/* Module information */
|
||||
MODULE_AUTHOR("Cliff Cai");
|
||||
MODULE_DESCRIPTION("I2S driver for ADI Blackfin");
|
||||
MODULE_LICENSE("GPL");
|
||||
|
File diff suppressed because it is too large
Load Diff
|
@ -1,174 +0,0 @@
|
|||
/*
|
||||
* File: bf5xx_sport.h
|
||||
* Based on:
|
||||
* Author: Roy Huang <roy.huang@analog.com>
|
||||
*
|
||||
* Created:
|
||||
* Description:
|
||||
*
|
||||
* Copyright 2004-2007 Analog Devices Inc.
|
||||
*
|
||||
* Bugs: Enter bugs at http://blackfin.uclinux.org/
|
||||
*
|
||||
* 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 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, see the file COPYING, or write
|
||||
* to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
|
||||
#ifndef __BF5XX_SPORT_H__
|
||||
#define __BF5XX_SPORT_H__
|
||||
|
||||
#include <linux/types.h>
|
||||
#include <linux/wait.h>
|
||||
#include <linux/workqueue.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <asm/dma.h>
|
||||
#include <asm/bfin_sport.h>
|
||||
|
||||
#define DESC_ELEMENT_COUNT 9
|
||||
|
||||
struct sport_device {
|
||||
int num;
|
||||
int dma_rx_chan;
|
||||
int dma_tx_chan;
|
||||
int err_irq;
|
||||
const unsigned short *pin_req;
|
||||
struct sport_register *regs;
|
||||
|
||||
unsigned char *rx_buf;
|
||||
unsigned char *tx_buf;
|
||||
unsigned int rx_fragsize;
|
||||
unsigned int tx_fragsize;
|
||||
unsigned int rx_frags;
|
||||
unsigned int tx_frags;
|
||||
unsigned int wdsize;
|
||||
|
||||
/* for dummy dma transfer */
|
||||
void *dummy_buf;
|
||||
unsigned int dummy_count;
|
||||
|
||||
/* DMA descriptor ring head of current audio stream*/
|
||||
struct dmasg *dma_rx_desc;
|
||||
struct dmasg *dma_tx_desc;
|
||||
unsigned int rx_desc_bytes;
|
||||
unsigned int tx_desc_bytes;
|
||||
|
||||
unsigned int rx_run:1; /* rx is running */
|
||||
unsigned int tx_run:1; /* tx is running */
|
||||
|
||||
struct dmasg *dummy_rx_desc;
|
||||
struct dmasg *dummy_tx_desc;
|
||||
|
||||
struct dmasg *curr_rx_desc;
|
||||
struct dmasg *curr_tx_desc;
|
||||
|
||||
int rx_curr_frag;
|
||||
int tx_curr_frag;
|
||||
|
||||
unsigned int rcr1;
|
||||
unsigned int rcr2;
|
||||
int rx_tdm_count;
|
||||
|
||||
unsigned int tcr1;
|
||||
unsigned int tcr2;
|
||||
int tx_tdm_count;
|
||||
|
||||
void (*rx_callback)(void *data);
|
||||
void *rx_data;
|
||||
void (*tx_callback)(void *data);
|
||||
void *tx_data;
|
||||
void (*err_callback)(void *data);
|
||||
void *err_data;
|
||||
unsigned char *tx_dma_buf;
|
||||
unsigned char *rx_dma_buf;
|
||||
#ifdef CONFIG_SND_BF5XX_MMAP_SUPPORT
|
||||
dma_addr_t tx_dma_phy;
|
||||
dma_addr_t rx_dma_phy;
|
||||
int tx_pos;/*pcm sample count*/
|
||||
int rx_pos;
|
||||
unsigned int tx_buffer_size;
|
||||
unsigned int rx_buffer_size;
|
||||
int tx_delay_pos;
|
||||
int once;
|
||||
#endif
|
||||
void *private_data;
|
||||
};
|
||||
|
||||
struct sport_param {
|
||||
int num;
|
||||
int dma_rx_chan;
|
||||
int dma_tx_chan;
|
||||
int err_irq;
|
||||
const unsigned short *pin_req;
|
||||
struct sport_register *regs;
|
||||
unsigned int wdsize;
|
||||
unsigned int dummy_count;
|
||||
void *private_data;
|
||||
};
|
||||
|
||||
struct sport_device *sport_init(struct platform_device *pdev,
|
||||
unsigned int wdsize, unsigned int dummy_count, size_t priv_size);
|
||||
|
||||
void sport_done(struct sport_device *sport);
|
||||
|
||||
/* first use these ...*/
|
||||
|
||||
/* note: multichannel is in units of 8 channels, tdm_count is number of channels
|
||||
* NOT / 8 ! all channels are enabled by default */
|
||||
int sport_set_multichannel(struct sport_device *sport, int tdm_count,
|
||||
u32 tx_mask, u32 rx_mask, int packed);
|
||||
|
||||
int sport_config_rx(struct sport_device *sport,
|
||||
unsigned int rcr1, unsigned int rcr2,
|
||||
unsigned int clkdiv, unsigned int fsdiv);
|
||||
|
||||
int sport_config_tx(struct sport_device *sport,
|
||||
unsigned int tcr1, unsigned int tcr2,
|
||||
unsigned int clkdiv, unsigned int fsdiv);
|
||||
|
||||
/* ... then these: */
|
||||
|
||||
/* buffer size (in bytes) == fragcount * fragsize_bytes */
|
||||
|
||||
/* this is not a very general api, it sets the dma to 2d autobuffer mode */
|
||||
|
||||
int sport_config_rx_dma(struct sport_device *sport, void *buf,
|
||||
int fragcount, size_t fragsize_bytes);
|
||||
|
||||
int sport_config_tx_dma(struct sport_device *sport, void *buf,
|
||||
int fragcount, size_t fragsize_bytes);
|
||||
|
||||
int sport_tx_start(struct sport_device *sport);
|
||||
int sport_tx_stop(struct sport_device *sport);
|
||||
int sport_rx_start(struct sport_device *sport);
|
||||
int sport_rx_stop(struct sport_device *sport);
|
||||
|
||||
/* for use in interrupt handler */
|
||||
unsigned long sport_curr_offset_rx(struct sport_device *sport);
|
||||
unsigned long sport_curr_offset_tx(struct sport_device *sport);
|
||||
|
||||
void sport_incfrag(struct sport_device *sport, int *frag, int tx);
|
||||
void sport_decfrag(struct sport_device *sport, int *frag, int tx);
|
||||
|
||||
int sport_set_rx_callback(struct sport_device *sport,
|
||||
void (*rx_callback)(void *), void *rx_data);
|
||||
int sport_set_tx_callback(struct sport_device *sport,
|
||||
void (*tx_callback)(void *), void *tx_data);
|
||||
int sport_set_err_callback(struct sport_device *sport,
|
||||
void (*err_callback)(void *), void *err_data);
|
||||
|
||||
int sport_send_and_recv(struct sport_device *sport, u8 *out_data, \
|
||||
u8 *in_data, int len);
|
||||
#endif /* BF53X_SPORT_H */
|
|
@ -1,126 +0,0 @@
|
|||
/*
|
||||
* File: sound/soc/blackfin/bf5xx-ssm2602.c
|
||||
* Author: Cliff Cai <Cliff.Cai@analog.com>
|
||||
*
|
||||
* Created: Tue June 06 2008
|
||||
* Description: board driver for SSM2602 sound chip
|
||||
*
|
||||
* Modified:
|
||||
* Copyright 2008 Analog Devices Inc.
|
||||
*
|
||||
* Bugs: Enter bugs at http://blackfin.uclinux.org/
|
||||
*
|
||||
* 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 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, see the file COPYING, or write
|
||||
* to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#include <linux/module.h>
|
||||
#include <linux/moduleparam.h>
|
||||
#include <linux/device.h>
|
||||
|
||||
#include <sound/core.h>
|
||||
#include <sound/pcm.h>
|
||||
#include <sound/soc.h>
|
||||
#include <sound/pcm_params.h>
|
||||
|
||||
#include <asm/dma.h>
|
||||
#include <asm/portmux.h>
|
||||
#include <linux/gpio.h>
|
||||
#include "../codecs/ssm2602.h"
|
||||
#include "bf5xx-sport.h"
|
||||
|
||||
static struct snd_soc_card bf5xx_ssm2602;
|
||||
|
||||
static int bf5xx_ssm2602_dai_init(struct snd_soc_pcm_runtime *rtd)
|
||||
{
|
||||
/*
|
||||
* If you are using a crystal source which frequency is not 12MHz
|
||||
* then modify the below case statement with frequency of the crystal.
|
||||
*
|
||||
* If you are using the SPORT to generate clocking then this is
|
||||
* where to do it.
|
||||
*/
|
||||
return snd_soc_dai_set_sysclk(rtd->codec_dai, SSM2602_SYSCLK, 12000000,
|
||||
SND_SOC_CLOCK_IN);
|
||||
}
|
||||
|
||||
/* CODEC is master for BCLK and LRC in this configuration. */
|
||||
#define BF5XX_SSM2602_DAIFMT (SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF | \
|
||||
SND_SOC_DAIFMT_CBM_CFM)
|
||||
|
||||
static struct snd_soc_dai_link bf5xx_ssm2602_dai[] = {
|
||||
{
|
||||
.name = "ssm2602",
|
||||
.stream_name = "SSM2602",
|
||||
.cpu_dai_name = "bfin-i2s.0",
|
||||
.codec_dai_name = "ssm2602-hifi",
|
||||
.platform_name = "bfin-i2s-pcm-audio",
|
||||
.codec_name = "ssm2602.0-001b",
|
||||
.init = bf5xx_ssm2602_dai_init,
|
||||
.dai_fmt = BF5XX_SSM2602_DAIFMT,
|
||||
},
|
||||
{
|
||||
.name = "ssm2602",
|
||||
.stream_name = "SSM2602",
|
||||
.cpu_dai_name = "bfin-i2s.1",
|
||||
.codec_dai_name = "ssm2602-hifi",
|
||||
.platform_name = "bfin-i2s-pcm-audio",
|
||||
.codec_name = "ssm2602.0-001b",
|
||||
.init = bf5xx_ssm2602_dai_init,
|
||||
.dai_fmt = BF5XX_SSM2602_DAIFMT,
|
||||
},
|
||||
};
|
||||
|
||||
static struct snd_soc_card bf5xx_ssm2602 = {
|
||||
.name = "bfin-ssm2602",
|
||||
.owner = THIS_MODULE,
|
||||
.dai_link = &bf5xx_ssm2602_dai[CONFIG_SND_BF5XX_SPORT_NUM],
|
||||
.num_links = 1,
|
||||
};
|
||||
|
||||
static struct platform_device *bf5xx_ssm2602_snd_device;
|
||||
|
||||
static int __init bf5xx_ssm2602_init(void)
|
||||
{
|
||||
int ret;
|
||||
|
||||
pr_debug("%s enter\n", __func__);
|
||||
bf5xx_ssm2602_snd_device = platform_device_alloc("soc-audio", -1);
|
||||
if (!bf5xx_ssm2602_snd_device)
|
||||
return -ENOMEM;
|
||||
|
||||
platform_set_drvdata(bf5xx_ssm2602_snd_device, &bf5xx_ssm2602);
|
||||
ret = platform_device_add(bf5xx_ssm2602_snd_device);
|
||||
|
||||
if (ret)
|
||||
platform_device_put(bf5xx_ssm2602_snd_device);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void __exit bf5xx_ssm2602_exit(void)
|
||||
{
|
||||
pr_debug("%s enter\n", __func__);
|
||||
platform_device_unregister(bf5xx_ssm2602_snd_device);
|
||||
}
|
||||
|
||||
module_init(bf5xx_ssm2602_init);
|
||||
module_exit(bf5xx_ssm2602_exit);
|
||||
|
||||
/* Module information */
|
||||
MODULE_AUTHOR("Cliff Cai");
|
||||
MODULE_DESCRIPTION("ALSA SoC SSM2602 BF527-EZKIT");
|
||||
MODULE_LICENSE("GPL");
|
||||
|
|
@ -1,239 +0,0 @@
|
|||
/*
|
||||
* bf6xx-i2s.c - Analog Devices BF6XX i2s interface driver
|
||||
*
|
||||
* Copyright (c) 2012 Analog Devices 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., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*/
|
||||
|
||||
#include <linux/device.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <sound/pcm.h>
|
||||
#include <sound/pcm_params.h>
|
||||
#include <sound/soc.h>
|
||||
#include <sound/soc-dai.h>
|
||||
|
||||
#include "bf6xx-sport.h"
|
||||
|
||||
struct sport_params param;
|
||||
|
||||
static int bfin_i2s_set_dai_fmt(struct snd_soc_dai *cpu_dai,
|
||||
unsigned int fmt)
|
||||
{
|
||||
struct sport_device *sport = snd_soc_dai_get_drvdata(cpu_dai);
|
||||
struct device *dev = &sport->pdev->dev;
|
||||
int ret = 0;
|
||||
|
||||
param.spctl &= ~(SPORT_CTL_OPMODE | SPORT_CTL_CKRE | SPORT_CTL_FSR
|
||||
| SPORT_CTL_LFS | SPORT_CTL_LAFS);
|
||||
switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
|
||||
case SND_SOC_DAIFMT_I2S:
|
||||
param.spctl |= SPORT_CTL_OPMODE | SPORT_CTL_CKRE
|
||||
| SPORT_CTL_LFS;
|
||||
break;
|
||||
case SND_SOC_DAIFMT_DSP_A:
|
||||
param.spctl |= SPORT_CTL_FSR;
|
||||
break;
|
||||
case SND_SOC_DAIFMT_LEFT_J:
|
||||
param.spctl |= SPORT_CTL_OPMODE | SPORT_CTL_LFS
|
||||
| SPORT_CTL_LAFS;
|
||||
break;
|
||||
default:
|
||||
dev_err(dev, "%s: Unknown DAI format type\n", __func__);
|
||||
ret = -EINVAL;
|
||||
break;
|
||||
}
|
||||
|
||||
param.spctl &= ~(SPORT_CTL_ICLK | SPORT_CTL_IFS);
|
||||
switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
|
||||
case SND_SOC_DAIFMT_CBM_CFM:
|
||||
break;
|
||||
case SND_SOC_DAIFMT_CBS_CFS:
|
||||
case SND_SOC_DAIFMT_CBM_CFS:
|
||||
case SND_SOC_DAIFMT_CBS_CFM:
|
||||
ret = -EINVAL;
|
||||
break;
|
||||
default:
|
||||
dev_err(dev, "%s: Unknown DAI master type\n", __func__);
|
||||
ret = -EINVAL;
|
||||
break;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int bfin_i2s_hw_params(struct snd_pcm_substream *substream,
|
||||
struct snd_pcm_hw_params *params,
|
||||
struct snd_soc_dai *dai)
|
||||
{
|
||||
struct sport_device *sport = snd_soc_dai_get_drvdata(dai);
|
||||
struct device *dev = &sport->pdev->dev;
|
||||
int ret = 0;
|
||||
|
||||
param.spctl &= ~SPORT_CTL_SLEN;
|
||||
switch (params_format(params)) {
|
||||
case SNDRV_PCM_FORMAT_S8:
|
||||
param.spctl |= 0x70;
|
||||
sport->wdsize = 1;
|
||||
break;
|
||||
case SNDRV_PCM_FORMAT_S16_LE:
|
||||
param.spctl |= 0xf0;
|
||||
sport->wdsize = 2;
|
||||
break;
|
||||
case SNDRV_PCM_FORMAT_S24_LE:
|
||||
param.spctl |= 0x170;
|
||||
sport->wdsize = 3;
|
||||
break;
|
||||
case SNDRV_PCM_FORMAT_S32_LE:
|
||||
param.spctl |= 0x1f0;
|
||||
sport->wdsize = 4;
|
||||
break;
|
||||
}
|
||||
|
||||
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
|
||||
ret = sport_set_tx_params(sport, ¶m);
|
||||
if (ret) {
|
||||
dev_err(dev, "SPORT tx is busy!\n");
|
||||
return ret;
|
||||
}
|
||||
} else {
|
||||
ret = sport_set_rx_params(sport, ¶m);
|
||||
if (ret) {
|
||||
dev_err(dev, "SPORT rx is busy!\n");
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_PM
|
||||
static int bfin_i2s_suspend(struct snd_soc_dai *dai)
|
||||
{
|
||||
struct sport_device *sport = snd_soc_dai_get_drvdata(dai);
|
||||
|
||||
if (dai->capture_active)
|
||||
sport_rx_stop(sport);
|
||||
if (dai->playback_active)
|
||||
sport_tx_stop(sport);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int bfin_i2s_resume(struct snd_soc_dai *dai)
|
||||
{
|
||||
struct sport_device *sport = snd_soc_dai_get_drvdata(dai);
|
||||
struct device *dev = &sport->pdev->dev;
|
||||
int ret;
|
||||
|
||||
ret = sport_set_tx_params(sport, ¶m);
|
||||
if (ret) {
|
||||
dev_err(dev, "SPORT tx is busy!\n");
|
||||
return ret;
|
||||
}
|
||||
ret = sport_set_rx_params(sport, ¶m);
|
||||
if (ret) {
|
||||
dev_err(dev, "SPORT rx is busy!\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#else
|
||||
#define bfin_i2s_suspend NULL
|
||||
#define bfin_i2s_resume NULL
|
||||
#endif
|
||||
|
||||
#define BFIN_I2S_RATES (SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_11025 |\
|
||||
SNDRV_PCM_RATE_16000 | SNDRV_PCM_RATE_22050 | \
|
||||
SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000 | \
|
||||
SNDRV_PCM_RATE_96000)
|
||||
|
||||
#define BFIN_I2S_FORMATS (SNDRV_PCM_FMTBIT_S8 | SNDRV_PCM_FMTBIT_S16_LE | \
|
||||
SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S32_LE)
|
||||
|
||||
static const struct snd_soc_dai_ops bfin_i2s_dai_ops = {
|
||||
.hw_params = bfin_i2s_hw_params,
|
||||
.set_fmt = bfin_i2s_set_dai_fmt,
|
||||
};
|
||||
|
||||
static struct snd_soc_dai_driver bfin_i2s_dai = {
|
||||
.suspend = bfin_i2s_suspend,
|
||||
.resume = bfin_i2s_resume,
|
||||
.playback = {
|
||||
.channels_min = 1,
|
||||
.channels_max = 2,
|
||||
.rates = BFIN_I2S_RATES,
|
||||
.formats = BFIN_I2S_FORMATS,
|
||||
},
|
||||
.capture = {
|
||||
.channels_min = 1,
|
||||
.channels_max = 2,
|
||||
.rates = BFIN_I2S_RATES,
|
||||
.formats = BFIN_I2S_FORMATS,
|
||||
},
|
||||
.ops = &bfin_i2s_dai_ops,
|
||||
};
|
||||
|
||||
static const struct snd_soc_component_driver bfin_i2s_component = {
|
||||
.name = "bfin-i2s",
|
||||
};
|
||||
|
||||
static int bfin_i2s_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct sport_device *sport;
|
||||
struct device *dev = &pdev->dev;
|
||||
int ret;
|
||||
|
||||
sport = sport_create(pdev);
|
||||
if (!sport)
|
||||
return -ENODEV;
|
||||
|
||||
/* register with the ASoC layers */
|
||||
ret = snd_soc_register_component(dev, &bfin_i2s_component,
|
||||
&bfin_i2s_dai, 1);
|
||||
if (ret) {
|
||||
dev_err(dev, "Failed to register DAI: %d\n", ret);
|
||||
sport_delete(sport);
|
||||
return ret;
|
||||
}
|
||||
platform_set_drvdata(pdev, sport);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int bfin_i2s_remove(struct platform_device *pdev)
|
||||
{
|
||||
struct sport_device *sport = platform_get_drvdata(pdev);
|
||||
|
||||
snd_soc_unregister_component(&pdev->dev);
|
||||
sport_delete(sport);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct platform_driver bfin_i2s_driver = {
|
||||
.probe = bfin_i2s_probe,
|
||||
.remove = bfin_i2s_remove,
|
||||
.driver = {
|
||||
.name = "bfin-i2s",
|
||||
},
|
||||
};
|
||||
|
||||
module_platform_driver(bfin_i2s_driver);
|
||||
|
||||
MODULE_DESCRIPTION("Analog Devices BF6XX i2s interface driver");
|
||||
MODULE_AUTHOR("Scott Jiang <Scott.Jiang.Linux@gmail.com>");
|
||||
MODULE_LICENSE("GPL v2");
|
|
@ -1,425 +0,0 @@
|
|||
/*
|
||||
* bf6xx_sport.c Analog Devices BF6XX SPORT driver
|
||||
*
|
||||
* Copyright (c) 2012 Analog Devices 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., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*/
|
||||
|
||||
#include <linux/device.h>
|
||||
#include <linux/dma-mapping.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/slab.h>
|
||||
|
||||
#include <asm/blackfin.h>
|
||||
#include <asm/dma.h>
|
||||
#include <asm/portmux.h>
|
||||
|
||||
#include "bf6xx-sport.h"
|
||||
|
||||
int sport_set_tx_params(struct sport_device *sport,
|
||||
struct sport_params *params)
|
||||
{
|
||||
if (sport->tx_regs->spctl & SPORT_CTL_SPENPRI)
|
||||
return -EBUSY;
|
||||
sport->tx_regs->spctl = params->spctl | SPORT_CTL_SPTRAN;
|
||||
sport->tx_regs->div = params->div;
|
||||
SSYNC();
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL(sport_set_tx_params);
|
||||
|
||||
int sport_set_rx_params(struct sport_device *sport,
|
||||
struct sport_params *params)
|
||||
{
|
||||
if (sport->rx_regs->spctl & SPORT_CTL_SPENPRI)
|
||||
return -EBUSY;
|
||||
sport->rx_regs->spctl = params->spctl & ~SPORT_CTL_SPTRAN;
|
||||
sport->rx_regs->div = params->div;
|
||||
SSYNC();
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL(sport_set_rx_params);
|
||||
|
||||
static int compute_wdsize(size_t wdsize)
|
||||
{
|
||||
switch (wdsize) {
|
||||
case 1:
|
||||
return WDSIZE_8 | PSIZE_8;
|
||||
case 2:
|
||||
return WDSIZE_16 | PSIZE_16;
|
||||
default:
|
||||
return WDSIZE_32 | PSIZE_32;
|
||||
}
|
||||
}
|
||||
|
||||
void sport_tx_start(struct sport_device *sport)
|
||||
{
|
||||
set_dma_next_desc_addr(sport->tx_dma_chan, sport->tx_desc);
|
||||
set_dma_config(sport->tx_dma_chan, DMAFLOW_LIST | DI_EN
|
||||
| compute_wdsize(sport->wdsize) | NDSIZE_6);
|
||||
enable_dma(sport->tx_dma_chan);
|
||||
sport->tx_regs->spctl |= SPORT_CTL_SPENPRI;
|
||||
SSYNC();
|
||||
}
|
||||
EXPORT_SYMBOL(sport_tx_start);
|
||||
|
||||
void sport_rx_start(struct sport_device *sport)
|
||||
{
|
||||
set_dma_next_desc_addr(sport->rx_dma_chan, sport->rx_desc);
|
||||
set_dma_config(sport->rx_dma_chan, DMAFLOW_LIST | DI_EN | WNR
|
||||
| compute_wdsize(sport->wdsize) | NDSIZE_6);
|
||||
enable_dma(sport->rx_dma_chan);
|
||||
sport->rx_regs->spctl |= SPORT_CTL_SPENPRI;
|
||||
SSYNC();
|
||||
}
|
||||
EXPORT_SYMBOL(sport_rx_start);
|
||||
|
||||
void sport_tx_stop(struct sport_device *sport)
|
||||
{
|
||||
sport->tx_regs->spctl &= ~SPORT_CTL_SPENPRI;
|
||||
SSYNC();
|
||||
disable_dma(sport->tx_dma_chan);
|
||||
}
|
||||
EXPORT_SYMBOL(sport_tx_stop);
|
||||
|
||||
void sport_rx_stop(struct sport_device *sport)
|
||||
{
|
||||
sport->rx_regs->spctl &= ~SPORT_CTL_SPENPRI;
|
||||
SSYNC();
|
||||
disable_dma(sport->rx_dma_chan);
|
||||
}
|
||||
EXPORT_SYMBOL(sport_rx_stop);
|
||||
|
||||
void sport_set_tx_callback(struct sport_device *sport,
|
||||
void (*tx_callback)(void *), void *tx_data)
|
||||
{
|
||||
sport->tx_callback = tx_callback;
|
||||
sport->tx_data = tx_data;
|
||||
}
|
||||
EXPORT_SYMBOL(sport_set_tx_callback);
|
||||
|
||||
void sport_set_rx_callback(struct sport_device *sport,
|
||||
void (*rx_callback)(void *), void *rx_data)
|
||||
{
|
||||
sport->rx_callback = rx_callback;
|
||||
sport->rx_data = rx_data;
|
||||
}
|
||||
EXPORT_SYMBOL(sport_set_rx_callback);
|
||||
|
||||
static void setup_desc(struct dmasg *desc, void *buf, int fragcount,
|
||||
size_t fragsize, unsigned int cfg,
|
||||
unsigned int count, size_t wdsize)
|
||||
{
|
||||
|
||||
int i;
|
||||
|
||||
for (i = 0; i < fragcount; ++i) {
|
||||
desc[i].next_desc_addr = &(desc[i + 1]);
|
||||
desc[i].start_addr = (unsigned long)buf + i * fragsize;
|
||||
desc[i].cfg = cfg;
|
||||
desc[i].x_count = count;
|
||||
desc[i].x_modify = wdsize;
|
||||
desc[i].y_count = 0;
|
||||
desc[i].y_modify = 0;
|
||||
}
|
||||
|
||||
/* make circular */
|
||||
desc[fragcount - 1].next_desc_addr = desc;
|
||||
}
|
||||
|
||||
int sport_config_tx_dma(struct sport_device *sport, void *buf,
|
||||
int fragcount, size_t fragsize)
|
||||
{
|
||||
unsigned int count;
|
||||
unsigned int cfg;
|
||||
dma_addr_t addr;
|
||||
|
||||
count = fragsize / sport->wdsize;
|
||||
|
||||
if (sport->tx_desc)
|
||||
dma_free_coherent(NULL, sport->tx_desc_size,
|
||||
sport->tx_desc, 0);
|
||||
|
||||
sport->tx_desc = dma_alloc_coherent(NULL,
|
||||
fragcount * sizeof(struct dmasg), &addr, 0);
|
||||
sport->tx_desc_size = fragcount * sizeof(struct dmasg);
|
||||
if (!sport->tx_desc)
|
||||
return -ENOMEM;
|
||||
|
||||
sport->tx_buf = buf;
|
||||
sport->tx_fragsize = fragsize;
|
||||
sport->tx_frags = fragcount;
|
||||
cfg = DMAFLOW_LIST | DI_EN | compute_wdsize(sport->wdsize) | NDSIZE_6;
|
||||
|
||||
setup_desc(sport->tx_desc, buf, fragcount, fragsize,
|
||||
cfg | DMAEN, count, sport->wdsize);
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL(sport_config_tx_dma);
|
||||
|
||||
int sport_config_rx_dma(struct sport_device *sport, void *buf,
|
||||
int fragcount, size_t fragsize)
|
||||
{
|
||||
unsigned int count;
|
||||
unsigned int cfg;
|
||||
dma_addr_t addr;
|
||||
|
||||
count = fragsize / sport->wdsize;
|
||||
|
||||
if (sport->rx_desc)
|
||||
dma_free_coherent(NULL, sport->rx_desc_size,
|
||||
sport->rx_desc, 0);
|
||||
|
||||
sport->rx_desc = dma_alloc_coherent(NULL,
|
||||
fragcount * sizeof(struct dmasg), &addr, 0);
|
||||
sport->rx_desc_size = fragcount * sizeof(struct dmasg);
|
||||
if (!sport->rx_desc)
|
||||
return -ENOMEM;
|
||||
|
||||
sport->rx_buf = buf;
|
||||
sport->rx_fragsize = fragsize;
|
||||
sport->rx_frags = fragcount;
|
||||
cfg = DMAFLOW_LIST | DI_EN | compute_wdsize(sport->wdsize)
|
||||
| WNR | NDSIZE_6;
|
||||
|
||||
setup_desc(sport->rx_desc, buf, fragcount, fragsize,
|
||||
cfg | DMAEN, count, sport->wdsize);
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL(sport_config_rx_dma);
|
||||
|
||||
unsigned long sport_curr_offset_tx(struct sport_device *sport)
|
||||
{
|
||||
unsigned long curr = get_dma_curr_addr(sport->tx_dma_chan);
|
||||
|
||||
return (unsigned char *)curr - sport->tx_buf;
|
||||
}
|
||||
EXPORT_SYMBOL(sport_curr_offset_tx);
|
||||
|
||||
unsigned long sport_curr_offset_rx(struct sport_device *sport)
|
||||
{
|
||||
unsigned long curr = get_dma_curr_addr(sport->rx_dma_chan);
|
||||
|
||||
return (unsigned char *)curr - sport->rx_buf;
|
||||
}
|
||||
EXPORT_SYMBOL(sport_curr_offset_rx);
|
||||
|
||||
static irqreturn_t sport_tx_irq(int irq, void *dev_id)
|
||||
{
|
||||
struct sport_device *sport = dev_id;
|
||||
static unsigned long status;
|
||||
|
||||
status = get_dma_curr_irqstat(sport->tx_dma_chan);
|
||||
if (status & (DMA_DONE | DMA_ERR)) {
|
||||
clear_dma_irqstat(sport->tx_dma_chan);
|
||||
SSYNC();
|
||||
}
|
||||
if (sport->tx_callback)
|
||||
sport->tx_callback(sport->tx_data);
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
static irqreturn_t sport_rx_irq(int irq, void *dev_id)
|
||||
{
|
||||
struct sport_device *sport = dev_id;
|
||||
unsigned long status;
|
||||
|
||||
status = get_dma_curr_irqstat(sport->rx_dma_chan);
|
||||
if (status & (DMA_DONE | DMA_ERR)) {
|
||||
clear_dma_irqstat(sport->rx_dma_chan);
|
||||
SSYNC();
|
||||
}
|
||||
if (sport->rx_callback)
|
||||
sport->rx_callback(sport->rx_data);
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
static irqreturn_t sport_err_irq(int irq, void *dev_id)
|
||||
{
|
||||
struct sport_device *sport = dev_id;
|
||||
struct device *dev = &sport->pdev->dev;
|
||||
|
||||
if (sport->tx_regs->spctl & SPORT_CTL_DERRPRI)
|
||||
dev_err(dev, "sport error: TUVF\n");
|
||||
if (sport->rx_regs->spctl & SPORT_CTL_DERRPRI)
|
||||
dev_err(dev, "sport error: ROVF\n");
|
||||
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
static int sport_get_resource(struct sport_device *sport)
|
||||
{
|
||||
struct platform_device *pdev = sport->pdev;
|
||||
struct device *dev = &pdev->dev;
|
||||
struct bfin_snd_platform_data *pdata = dev->platform_data;
|
||||
struct resource *res;
|
||||
|
||||
if (!pdata) {
|
||||
dev_err(dev, "No platform data\n");
|
||||
return -ENODEV;
|
||||
}
|
||||
sport->pin_req = pdata->pin_req;
|
||||
|
||||
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
||||
if (!res) {
|
||||
dev_err(dev, "No tx MEM resource\n");
|
||||
return -ENODEV;
|
||||
}
|
||||
sport->tx_regs = (struct sport_register *)res->start;
|
||||
|
||||
res = platform_get_resource(pdev, IORESOURCE_MEM, 1);
|
||||
if (!res) {
|
||||
dev_err(dev, "No rx MEM resource\n");
|
||||
return -ENODEV;
|
||||
}
|
||||
sport->rx_regs = (struct sport_register *)res->start;
|
||||
|
||||
res = platform_get_resource(pdev, IORESOURCE_DMA, 0);
|
||||
if (!res) {
|
||||
dev_err(dev, "No tx DMA resource\n");
|
||||
return -ENODEV;
|
||||
}
|
||||
sport->tx_dma_chan = res->start;
|
||||
|
||||
res = platform_get_resource(pdev, IORESOURCE_DMA, 1);
|
||||
if (!res) {
|
||||
dev_err(dev, "No rx DMA resource\n");
|
||||
return -ENODEV;
|
||||
}
|
||||
sport->rx_dma_chan = res->start;
|
||||
|
||||
res = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
|
||||
if (!res) {
|
||||
dev_err(dev, "No tx error irq resource\n");
|
||||
return -ENODEV;
|
||||
}
|
||||
sport->tx_err_irq = res->start;
|
||||
|
||||
res = platform_get_resource(pdev, IORESOURCE_IRQ, 1);
|
||||
if (!res) {
|
||||
dev_err(dev, "No rx error irq resource\n");
|
||||
return -ENODEV;
|
||||
}
|
||||
sport->rx_err_irq = res->start;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int sport_request_resource(struct sport_device *sport)
|
||||
{
|
||||
struct device *dev = &sport->pdev->dev;
|
||||
int ret;
|
||||
|
||||
ret = peripheral_request_list(sport->pin_req, "soc-audio");
|
||||
if (ret) {
|
||||
dev_err(dev, "Unable to request sport pin\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = request_dma(sport->tx_dma_chan, "SPORT TX Data");
|
||||
if (ret) {
|
||||
dev_err(dev, "Unable to allocate DMA channel for sport tx\n");
|
||||
goto err_tx_dma;
|
||||
}
|
||||
set_dma_callback(sport->tx_dma_chan, sport_tx_irq, sport);
|
||||
|
||||
ret = request_dma(sport->rx_dma_chan, "SPORT RX Data");
|
||||
if (ret) {
|
||||
dev_err(dev, "Unable to allocate DMA channel for sport rx\n");
|
||||
goto err_rx_dma;
|
||||
}
|
||||
set_dma_callback(sport->rx_dma_chan, sport_rx_irq, sport);
|
||||
|
||||
ret = request_irq(sport->tx_err_irq, sport_err_irq,
|
||||
0, "SPORT TX ERROR", sport);
|
||||
if (ret) {
|
||||
dev_err(dev, "Unable to allocate tx error IRQ for sport\n");
|
||||
goto err_tx_irq;
|
||||
}
|
||||
|
||||
ret = request_irq(sport->rx_err_irq, sport_err_irq,
|
||||
0, "SPORT RX ERROR", sport);
|
||||
if (ret) {
|
||||
dev_err(dev, "Unable to allocate rx error IRQ for sport\n");
|
||||
goto err_rx_irq;
|
||||
}
|
||||
|
||||
return 0;
|
||||
err_rx_irq:
|
||||
free_irq(sport->tx_err_irq, sport);
|
||||
err_tx_irq:
|
||||
free_dma(sport->rx_dma_chan);
|
||||
err_rx_dma:
|
||||
free_dma(sport->tx_dma_chan);
|
||||
err_tx_dma:
|
||||
peripheral_free_list(sport->pin_req);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void sport_free_resource(struct sport_device *sport)
|
||||
{
|
||||
free_irq(sport->rx_err_irq, sport);
|
||||
free_irq(sport->tx_err_irq, sport);
|
||||
free_dma(sport->rx_dma_chan);
|
||||
free_dma(sport->tx_dma_chan);
|
||||
peripheral_free_list(sport->pin_req);
|
||||
}
|
||||
|
||||
struct sport_device *sport_create(struct platform_device *pdev)
|
||||
{
|
||||
struct device *dev = &pdev->dev;
|
||||
struct sport_device *sport;
|
||||
int ret;
|
||||
|
||||
sport = kzalloc(sizeof(*sport), GFP_KERNEL);
|
||||
if (!sport)
|
||||
return NULL;
|
||||
|
||||
sport->pdev = pdev;
|
||||
|
||||
ret = sport_get_resource(sport);
|
||||
if (ret)
|
||||
goto free_data;
|
||||
|
||||
ret = sport_request_resource(sport);
|
||||
if (ret)
|
||||
goto free_data;
|
||||
|
||||
dev_dbg(dev, "SPORT create success\n");
|
||||
return sport;
|
||||
free_data:
|
||||
kfree(sport);
|
||||
return NULL;
|
||||
}
|
||||
EXPORT_SYMBOL(sport_create);
|
||||
|
||||
void sport_delete(struct sport_device *sport)
|
||||
{
|
||||
if (sport->tx_desc)
|
||||
dma_free_coherent(NULL, sport->tx_desc_size,
|
||||
sport->tx_desc, 0);
|
||||
if (sport->rx_desc)
|
||||
dma_free_coherent(NULL, sport->rx_desc_size,
|
||||
sport->rx_desc, 0);
|
||||
sport_free_resource(sport);
|
||||
kfree(sport);
|
||||
}
|
||||
EXPORT_SYMBOL(sport_delete);
|
||||
|
||||
MODULE_DESCRIPTION("Analog Devices BF6XX SPORT driver");
|
||||
MODULE_AUTHOR("Scott Jiang <Scott.Jiang.Linux@gmail.com>");
|
||||
MODULE_LICENSE("GPL v2");
|
|
@ -1,82 +0,0 @@
|
|||
/*
|
||||
* bf6xx_sport - Analog Devices BF6XX SPORT driver
|
||||
*
|
||||
* Copyright (c) 2012 Analog Devices 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., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*/
|
||||
|
||||
#ifndef _BF6XX_SPORT_H_
|
||||
#define _BF6XX_SPORT_H_
|
||||
|
||||
#include <linux/platform_device.h>
|
||||
#include <asm/bfin_sport3.h>
|
||||
|
||||
struct sport_device {
|
||||
struct platform_device *pdev;
|
||||
const unsigned short *pin_req;
|
||||
struct sport_register *tx_regs;
|
||||
struct sport_register *rx_regs;
|
||||
int tx_dma_chan;
|
||||
int rx_dma_chan;
|
||||
int tx_err_irq;
|
||||
int rx_err_irq;
|
||||
|
||||
void (*tx_callback)(void *data);
|
||||
void *tx_data;
|
||||
void (*rx_callback)(void *data);
|
||||
void *rx_data;
|
||||
|
||||
struct dmasg *tx_desc;
|
||||
struct dmasg *rx_desc;
|
||||
unsigned int tx_desc_size;
|
||||
unsigned int rx_desc_size;
|
||||
unsigned char *tx_buf;
|
||||
unsigned char *rx_buf;
|
||||
unsigned int tx_fragsize;
|
||||
unsigned int rx_fragsize;
|
||||
unsigned int tx_frags;
|
||||
unsigned int rx_frags;
|
||||
unsigned int wdsize;
|
||||
};
|
||||
|
||||
struct sport_params {
|
||||
u32 spctl;
|
||||
u32 div;
|
||||
};
|
||||
|
||||
struct sport_device *sport_create(struct platform_device *pdev);
|
||||
void sport_delete(struct sport_device *sport);
|
||||
int sport_set_tx_params(struct sport_device *sport,
|
||||
struct sport_params *params);
|
||||
int sport_set_rx_params(struct sport_device *sport,
|
||||
struct sport_params *params);
|
||||
void sport_tx_start(struct sport_device *sport);
|
||||
void sport_rx_start(struct sport_device *sport);
|
||||
void sport_tx_stop(struct sport_device *sport);
|
||||
void sport_rx_stop(struct sport_device *sport);
|
||||
void sport_set_tx_callback(struct sport_device *sport,
|
||||
void (*tx_callback)(void *), void *tx_data);
|
||||
void sport_set_rx_callback(struct sport_device *sport,
|
||||
void (*rx_callback)(void *), void *rx_data);
|
||||
int sport_config_tx_dma(struct sport_device *sport, void *buf,
|
||||
int fragcount, size_t fragsize);
|
||||
int sport_config_rx_dma(struct sport_device *sport, void *buf,
|
||||
int fragcount, size_t fragsize);
|
||||
unsigned long sport_curr_offset_tx(struct sport_device *sport);
|
||||
unsigned long sport_curr_offset_rx(struct sport_device *sport);
|
||||
|
||||
|
||||
|
||||
#endif
|
|
@ -1,173 +0,0 @@
|
|||
/*
|
||||
* Machine driver for EVAL-ADAU1373 on Analog Devices bfin
|
||||
* evaluation boards.
|
||||
*
|
||||
* Copyright 2011 Analog Devices Inc.
|
||||
* Author: Lars-Peter Clausen <lars@metafoo.de>
|
||||
*
|
||||
* Licensed under the GPL-2 or later.
|
||||
*/
|
||||
|
||||
#include <linux/module.h>
|
||||
#include <linux/device.h>
|
||||
#include <sound/core.h>
|
||||
#include <sound/pcm.h>
|
||||
#include <sound/soc.h>
|
||||
#include <sound/pcm_params.h>
|
||||
|
||||
#include "../codecs/adau1373.h"
|
||||
|
||||
static const struct snd_soc_dapm_widget bfin_eval_adau1373_dapm_widgets[] = {
|
||||
SND_SOC_DAPM_LINE("Line In1", NULL),
|
||||
SND_SOC_DAPM_LINE("Line In2", NULL),
|
||||
SND_SOC_DAPM_LINE("Line In3", NULL),
|
||||
SND_SOC_DAPM_LINE("Line In4", NULL),
|
||||
|
||||
SND_SOC_DAPM_LINE("Line Out1", NULL),
|
||||
SND_SOC_DAPM_LINE("Line Out2", NULL),
|
||||
SND_SOC_DAPM_LINE("Stereo Out", NULL),
|
||||
SND_SOC_DAPM_HP("Headphone", NULL),
|
||||
SND_SOC_DAPM_HP("Earpiece", NULL),
|
||||
SND_SOC_DAPM_SPK("Speaker", NULL),
|
||||
};
|
||||
|
||||
static const struct snd_soc_dapm_route bfin_eval_adau1373_dapm_routes[] = {
|
||||
{ "AIN1L", NULL, "Line In1" },
|
||||
{ "AIN1R", NULL, "Line In1" },
|
||||
{ "AIN2L", NULL, "Line In2" },
|
||||
{ "AIN2R", NULL, "Line In2" },
|
||||
{ "AIN3L", NULL, "Line In3" },
|
||||
{ "AIN3R", NULL, "Line In3" },
|
||||
{ "AIN4L", NULL, "Line In4" },
|
||||
{ "AIN4R", NULL, "Line In4" },
|
||||
|
||||
/* MICBIAS can be connected via a jumper to the line-in jack, since w
|
||||
don't know which one is going to be used, just power both. */
|
||||
{ "Line In1", NULL, "MICBIAS1" },
|
||||
{ "Line In2", NULL, "MICBIAS1" },
|
||||
{ "Line In3", NULL, "MICBIAS1" },
|
||||
{ "Line In4", NULL, "MICBIAS1" },
|
||||
{ "Line In1", NULL, "MICBIAS2" },
|
||||
{ "Line In2", NULL, "MICBIAS2" },
|
||||
{ "Line In3", NULL, "MICBIAS2" },
|
||||
{ "Line In4", NULL, "MICBIAS2" },
|
||||
|
||||
{ "Line Out1", NULL, "LOUT1L" },
|
||||
{ "Line Out1", NULL, "LOUT1R" },
|
||||
{ "Line Out2", NULL, "LOUT2L" },
|
||||
{ "Line Out2", NULL, "LOUT2R" },
|
||||
{ "Headphone", NULL, "HPL" },
|
||||
{ "Headphone", NULL, "HPR" },
|
||||
{ "Earpiece", NULL, "EP" },
|
||||
{ "Speaker", NULL, "SPKL" },
|
||||
{ "Stereo Out", NULL, "SPKR" },
|
||||
};
|
||||
|
||||
static int bfin_eval_adau1373_hw_params(struct snd_pcm_substream *substream,
|
||||
struct snd_pcm_hw_params *params)
|
||||
{
|
||||
struct snd_soc_pcm_runtime *rtd = substream->private_data;
|
||||
struct snd_soc_dai *codec_dai = rtd->codec_dai;
|
||||
int ret;
|
||||
int pll_rate;
|
||||
|
||||
switch (params_rate(params)) {
|
||||
case 48000:
|
||||
case 8000:
|
||||
case 12000:
|
||||
case 16000:
|
||||
case 24000:
|
||||
case 32000:
|
||||
pll_rate = 48000 * 1024;
|
||||
break;
|
||||
case 44100:
|
||||
case 7350:
|
||||
case 11025:
|
||||
case 14700:
|
||||
case 22050:
|
||||
case 29400:
|
||||
pll_rate = 44100 * 1024;
|
||||
break;
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
ret = snd_soc_dai_set_pll(codec_dai, ADAU1373_PLL1,
|
||||
ADAU1373_PLL_SRC_MCLK1, 12288000, pll_rate);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = snd_soc_dai_set_sysclk(codec_dai, ADAU1373_CLK_SRC_PLL1, pll_rate,
|
||||
SND_SOC_CLOCK_IN);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int bfin_eval_adau1373_codec_init(struct snd_soc_pcm_runtime *rtd)
|
||||
{
|
||||
struct snd_soc_dai *codec_dai = rtd->codec_dai;
|
||||
unsigned int pll_rate = 48000 * 1024;
|
||||
int ret;
|
||||
|
||||
ret = snd_soc_dai_set_pll(codec_dai, ADAU1373_PLL1,
|
||||
ADAU1373_PLL_SRC_MCLK1, 12288000, pll_rate);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = snd_soc_dai_set_sysclk(codec_dai, ADAU1373_CLK_SRC_PLL1, pll_rate,
|
||||
SND_SOC_CLOCK_IN);
|
||||
|
||||
return ret;
|
||||
}
|
||||
static const struct snd_soc_ops bfin_eval_adau1373_ops = {
|
||||
.hw_params = bfin_eval_adau1373_hw_params,
|
||||
};
|
||||
|
||||
static struct snd_soc_dai_link bfin_eval_adau1373_dai = {
|
||||
.name = "adau1373",
|
||||
.stream_name = "adau1373",
|
||||
.cpu_dai_name = "bfin-i2s.0",
|
||||
.codec_dai_name = "adau1373-aif1",
|
||||
.platform_name = "bfin-i2s-pcm-audio",
|
||||
.codec_name = "adau1373.0-001a",
|
||||
.ops = &bfin_eval_adau1373_ops,
|
||||
.init = bfin_eval_adau1373_codec_init,
|
||||
.dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF |
|
||||
SND_SOC_DAIFMT_CBM_CFM,
|
||||
};
|
||||
|
||||
static struct snd_soc_card bfin_eval_adau1373 = {
|
||||
.name = "bfin-eval-adau1373",
|
||||
.owner = THIS_MODULE,
|
||||
.dai_link = &bfin_eval_adau1373_dai,
|
||||
.num_links = 1,
|
||||
|
||||
.dapm_widgets = bfin_eval_adau1373_dapm_widgets,
|
||||
.num_dapm_widgets = ARRAY_SIZE(bfin_eval_adau1373_dapm_widgets),
|
||||
.dapm_routes = bfin_eval_adau1373_dapm_routes,
|
||||
.num_dapm_routes = ARRAY_SIZE(bfin_eval_adau1373_dapm_routes),
|
||||
};
|
||||
|
||||
static int bfin_eval_adau1373_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct snd_soc_card *card = &bfin_eval_adau1373;
|
||||
|
||||
card->dev = &pdev->dev;
|
||||
|
||||
return devm_snd_soc_register_card(&pdev->dev, &bfin_eval_adau1373);
|
||||
}
|
||||
|
||||
static struct platform_driver bfin_eval_adau1373_driver = {
|
||||
.driver = {
|
||||
.name = "bfin-eval-adau1373",
|
||||
.pm = &snd_soc_pm_ops,
|
||||
},
|
||||
.probe = bfin_eval_adau1373_probe,
|
||||
};
|
||||
|
||||
module_platform_driver(bfin_eval_adau1373_driver);
|
||||
|
||||
MODULE_AUTHOR("Lars-Peter Clausen <lars@metafoo.de>");
|
||||
MODULE_DESCRIPTION("ALSA SoC bfin adau1373 driver");
|
||||
MODULE_LICENSE("GPL");
|
||||
MODULE_ALIAS("platform:bfin-eval-adau1373");
|
|
@ -1,113 +0,0 @@
|
|||
/*
|
||||
* Machine driver for EVAL-ADAU1701MINIZ on Analog Devices bfin
|
||||
* evaluation boards.
|
||||
*
|
||||
* Copyright 2011 Analog Devices Inc.
|
||||
* Author: Lars-Peter Clausen <lars@metafoo.de>
|
||||
*
|
||||
* Licensed under the GPL-2 or later.
|
||||
*/
|
||||
|
||||
#include <linux/module.h>
|
||||
#include <linux/device.h>
|
||||
#include <sound/core.h>
|
||||
#include <sound/pcm.h>
|
||||
#include <sound/soc.h>
|
||||
#include <sound/pcm_params.h>
|
||||
|
||||
#include "../codecs/adau1701.h"
|
||||
|
||||
static const struct snd_soc_dapm_widget bfin_eval_adau1701_dapm_widgets[] = {
|
||||
SND_SOC_DAPM_SPK("Speaker", NULL),
|
||||
SND_SOC_DAPM_LINE("Line Out", NULL),
|
||||
SND_SOC_DAPM_LINE("Line In", NULL),
|
||||
};
|
||||
|
||||
static const struct snd_soc_dapm_route bfin_eval_adau1701_dapm_routes[] = {
|
||||
{ "Speaker", NULL, "OUT0" },
|
||||
{ "Speaker", NULL, "OUT1" },
|
||||
{ "Line Out", NULL, "OUT2" },
|
||||
{ "Line Out", NULL, "OUT3" },
|
||||
|
||||
{ "IN0", NULL, "Line In" },
|
||||
{ "IN1", NULL, "Line In" },
|
||||
};
|
||||
|
||||
static int bfin_eval_adau1701_hw_params(struct snd_pcm_substream *substream,
|
||||
struct snd_pcm_hw_params *params)
|
||||
{
|
||||
struct snd_soc_pcm_runtime *rtd = substream->private_data;
|
||||
struct snd_soc_dai *codec_dai = rtd->codec_dai;
|
||||
int ret;
|
||||
|
||||
ret = snd_soc_dai_set_sysclk(codec_dai, ADAU1701_CLK_SRC_OSC, 12288000,
|
||||
SND_SOC_CLOCK_IN);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static struct snd_soc_ops bfin_eval_adau1701_ops = {
|
||||
.hw_params = bfin_eval_adau1701_hw_params,
|
||||
};
|
||||
|
||||
#define BFIN_EVAL_ADAU1701_DAI_FMT (SND_SOC_DAIFMT_I2S | \
|
||||
SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBM_CFM)
|
||||
|
||||
static struct snd_soc_dai_link bfin_eval_adau1701_dai[] = {
|
||||
{
|
||||
.name = "adau1701",
|
||||
.stream_name = "adau1701",
|
||||
.cpu_dai_name = "bfin-i2s.0",
|
||||
.codec_dai_name = "adau1701",
|
||||
.platform_name = "bfin-i2s-pcm-audio",
|
||||
.codec_name = "adau1701.0-0034",
|
||||
.ops = &bfin_eval_adau1701_ops,
|
||||
.dai_fmt = BFIN_EVAL_ADAU1701_DAI_FMT,
|
||||
},
|
||||
{
|
||||
.name = "adau1701",
|
||||
.stream_name = "adau1701",
|
||||
.cpu_dai_name = "bfin-i2s.1",
|
||||
.codec_dai_name = "adau1701",
|
||||
.platform_name = "bfin-i2s-pcm-audio",
|
||||
.codec_name = "adau1701.0-0034",
|
||||
.ops = &bfin_eval_adau1701_ops,
|
||||
.dai_fmt = BFIN_EVAL_ADAU1701_DAI_FMT,
|
||||
},
|
||||
};
|
||||
|
||||
static struct snd_soc_card bfin_eval_adau1701 = {
|
||||
.name = "bfin-eval-adau1701",
|
||||
.owner = THIS_MODULE,
|
||||
.dai_link = &bfin_eval_adau1701_dai[CONFIG_SND_BF5XX_SPORT_NUM],
|
||||
.num_links = 1,
|
||||
|
||||
.dapm_widgets = bfin_eval_adau1701_dapm_widgets,
|
||||
.num_dapm_widgets = ARRAY_SIZE(bfin_eval_adau1701_dapm_widgets),
|
||||
.dapm_routes = bfin_eval_adau1701_dapm_routes,
|
||||
.num_dapm_routes = ARRAY_SIZE(bfin_eval_adau1701_dapm_routes),
|
||||
};
|
||||
|
||||
static int bfin_eval_adau1701_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct snd_soc_card *card = &bfin_eval_adau1701;
|
||||
|
||||
card->dev = &pdev->dev;
|
||||
|
||||
return devm_snd_soc_register_card(&pdev->dev, &bfin_eval_adau1701);
|
||||
}
|
||||
|
||||
static struct platform_driver bfin_eval_adau1701_driver = {
|
||||
.driver = {
|
||||
.name = "bfin-eval-adau1701",
|
||||
.pm = &snd_soc_pm_ops,
|
||||
},
|
||||
.probe = bfin_eval_adau1701_probe,
|
||||
};
|
||||
|
||||
module_platform_driver(bfin_eval_adau1701_driver);
|
||||
|
||||
MODULE_AUTHOR("Lars-Peter Clausen <lars@metafoo.de>");
|
||||
MODULE_DESCRIPTION("ALSA SoC bfin ADAU1701 driver");
|
||||
MODULE_LICENSE("GPL");
|
||||
MODULE_ALIAS("platform:bfin-eval-adau1701");
|
|
@ -1,142 +0,0 @@
|
|||
/*
|
||||
* Machine driver for EVAL-ADAU1x61MINIZ on Analog Devices bfin
|
||||
* evaluation boards.
|
||||
*
|
||||
* Copyright 2011-2014 Analog Devices Inc.
|
||||
* Author: Lars-Peter Clausen <lars@metafoo.de>
|
||||
*
|
||||
* Licensed under the GPL-2 or later.
|
||||
*/
|
||||
|
||||
#include <linux/module.h>
|
||||
#include <linux/device.h>
|
||||
#include <linux/slab.h>
|
||||
#include <sound/core.h>
|
||||
#include <sound/pcm.h>
|
||||
#include <sound/soc.h>
|
||||
#include <sound/pcm_params.h>
|
||||
|
||||
#include "../codecs/adau17x1.h"
|
||||
|
||||
static const struct snd_soc_dapm_widget bfin_eval_adau1x61_dapm_widgets[] = {
|
||||
SND_SOC_DAPM_LINE("In 1", NULL),
|
||||
SND_SOC_DAPM_LINE("In 2", NULL),
|
||||
SND_SOC_DAPM_LINE("In 3-4", NULL),
|
||||
|
||||
SND_SOC_DAPM_LINE("Diff Out L", NULL),
|
||||
SND_SOC_DAPM_LINE("Diff Out R", NULL),
|
||||
SND_SOC_DAPM_LINE("Stereo Out", NULL),
|
||||
SND_SOC_DAPM_HP("Capless HP Out", NULL),
|
||||
};
|
||||
|
||||
static const struct snd_soc_dapm_route bfin_eval_adau1x61_dapm_routes[] = {
|
||||
{ "LAUX", NULL, "In 3-4" },
|
||||
{ "RAUX", NULL, "In 3-4" },
|
||||
{ "LINP", NULL, "In 1" },
|
||||
{ "LINN", NULL, "In 1"},
|
||||
{ "RINP", NULL, "In 2" },
|
||||
{ "RINN", NULL, "In 2" },
|
||||
|
||||
{ "In 1", NULL, "MICBIAS" },
|
||||
{ "In 2", NULL, "MICBIAS" },
|
||||
|
||||
{ "Capless HP Out", NULL, "LHP" },
|
||||
{ "Capless HP Out", NULL, "RHP" },
|
||||
{ "Diff Out L", NULL, "LOUT" },
|
||||
{ "Diff Out R", NULL, "ROUT" },
|
||||
{ "Stereo Out", NULL, "LOUT" },
|
||||
{ "Stereo Out", NULL, "ROUT" },
|
||||
};
|
||||
|
||||
static int bfin_eval_adau1x61_hw_params(struct snd_pcm_substream *substream,
|
||||
struct snd_pcm_hw_params *params)
|
||||
{
|
||||
struct snd_soc_pcm_runtime *rtd = substream->private_data;
|
||||
struct snd_soc_dai *codec_dai = rtd->codec_dai;
|
||||
int pll_rate;
|
||||
int ret;
|
||||
|
||||
switch (params_rate(params)) {
|
||||
case 48000:
|
||||
case 8000:
|
||||
case 12000:
|
||||
case 16000:
|
||||
case 24000:
|
||||
case 32000:
|
||||
case 96000:
|
||||
pll_rate = 48000 * 1024;
|
||||
break;
|
||||
case 44100:
|
||||
case 7350:
|
||||
case 11025:
|
||||
case 14700:
|
||||
case 22050:
|
||||
case 29400:
|
||||
case 88200:
|
||||
pll_rate = 44100 * 1024;
|
||||
break;
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
ret = snd_soc_dai_set_pll(codec_dai, ADAU17X1_PLL,
|
||||
ADAU17X1_PLL_SRC_MCLK, 12288000, pll_rate);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = snd_soc_dai_set_sysclk(codec_dai, ADAU17X1_CLK_SRC_PLL, pll_rate,
|
||||
SND_SOC_CLOCK_IN);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static const struct snd_soc_ops bfin_eval_adau1x61_ops = {
|
||||
.hw_params = bfin_eval_adau1x61_hw_params,
|
||||
};
|
||||
|
||||
static struct snd_soc_dai_link bfin_eval_adau1x61_dai = {
|
||||
.name = "adau1x61",
|
||||
.stream_name = "adau1x61",
|
||||
.cpu_dai_name = "bfin-i2s.0",
|
||||
.codec_dai_name = "adau-hifi",
|
||||
.platform_name = "bfin-i2s-pcm-audio",
|
||||
.codec_name = "adau1761.0-0038",
|
||||
.ops = &bfin_eval_adau1x61_ops,
|
||||
.dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF |
|
||||
SND_SOC_DAIFMT_CBM_CFM,
|
||||
};
|
||||
|
||||
static struct snd_soc_card bfin_eval_adau1x61 = {
|
||||
.name = "bfin-eval-adau1x61",
|
||||
.owner = THIS_MODULE,
|
||||
.driver_name = "eval-adau1x61",
|
||||
.dai_link = &bfin_eval_adau1x61_dai,
|
||||
.num_links = 1,
|
||||
|
||||
.dapm_widgets = bfin_eval_adau1x61_dapm_widgets,
|
||||
.num_dapm_widgets = ARRAY_SIZE(bfin_eval_adau1x61_dapm_widgets),
|
||||
.dapm_routes = bfin_eval_adau1x61_dapm_routes,
|
||||
.num_dapm_routes = ARRAY_SIZE(bfin_eval_adau1x61_dapm_routes),
|
||||
.fully_routed = true,
|
||||
};
|
||||
|
||||
static int bfin_eval_adau1x61_probe(struct platform_device *pdev)
|
||||
{
|
||||
bfin_eval_adau1x61.dev = &pdev->dev;
|
||||
|
||||
return devm_snd_soc_register_card(&pdev->dev, &bfin_eval_adau1x61);
|
||||
}
|
||||
|
||||
static struct platform_driver bfin_eval_adau1x61_driver = {
|
||||
.driver = {
|
||||
.name = "bfin-eval-adau1x61",
|
||||
.pm = &snd_soc_pm_ops,
|
||||
},
|
||||
.probe = bfin_eval_adau1x61_probe,
|
||||
};
|
||||
module_platform_driver(bfin_eval_adau1x61_driver);
|
||||
|
||||
MODULE_AUTHOR("Lars-Peter Clausen <lars@metafoo.de>");
|
||||
MODULE_DESCRIPTION("ALSA SoC bfin adau1x61 driver");
|
||||
MODULE_LICENSE("GPL");
|
||||
MODULE_ALIAS("platform:bfin-eval-adau1x61");
|
|
@ -1,129 +0,0 @@
|
|||
/*
|
||||
* Machine driver for EVAL-ADAU1x81 on Analog Devices bfin
|
||||
* evaluation boards.
|
||||
*
|
||||
* Copyright 2011-2014 Analog Devices Inc.
|
||||
* Author: Lars-Peter Clausen <lars@metafoo.de>
|
||||
*
|
||||
* Licensed under the GPL-2 or later.
|
||||
*/
|
||||
|
||||
#include <linux/module.h>
|
||||
#include <linux/device.h>
|
||||
#include <linux/slab.h>
|
||||
#include <sound/core.h>
|
||||
#include <sound/pcm.h>
|
||||
#include <sound/soc.h>
|
||||
#include <sound/pcm_params.h>
|
||||
|
||||
#include "../codecs/adau17x1.h"
|
||||
|
||||
static const struct snd_soc_dapm_widget bfin_eval_adau1x81_dapm_widgets[] = {
|
||||
SND_SOC_DAPM_LINE("Stereo In", NULL),
|
||||
SND_SOC_DAPM_LINE("Beep", NULL),
|
||||
|
||||
SND_SOC_DAPM_SPK("Speaker", NULL),
|
||||
SND_SOC_DAPM_HP("Headphone", NULL),
|
||||
};
|
||||
|
||||
static const struct snd_soc_dapm_route bfin_eval_adau1x81_dapm_routes[] = {
|
||||
{ "BEEP", NULL, "Beep" },
|
||||
{ "LMIC", NULL, "Stereo In" },
|
||||
{ "LMIC", NULL, "Stereo In" },
|
||||
|
||||
{ "Headphone", NULL, "AOUTL" },
|
||||
{ "Headphone", NULL, "AOUTR" },
|
||||
{ "Speaker", NULL, "SP" },
|
||||
};
|
||||
|
||||
static int bfin_eval_adau1x81_hw_params(struct snd_pcm_substream *substream,
|
||||
struct snd_pcm_hw_params *params)
|
||||
{
|
||||
struct snd_soc_pcm_runtime *rtd = substream->private_data;
|
||||
struct snd_soc_dai *codec_dai = rtd->codec_dai;
|
||||
int pll_rate;
|
||||
int ret;
|
||||
|
||||
switch (params_rate(params)) {
|
||||
case 48000:
|
||||
case 8000:
|
||||
case 12000:
|
||||
case 16000:
|
||||
case 24000:
|
||||
case 32000:
|
||||
case 96000:
|
||||
pll_rate = 48000 * 1024;
|
||||
break;
|
||||
case 44100:
|
||||
case 7350:
|
||||
case 11025:
|
||||
case 14700:
|
||||
case 22050:
|
||||
case 29400:
|
||||
case 88200:
|
||||
pll_rate = 44100 * 1024;
|
||||
break;
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
ret = snd_soc_dai_set_pll(codec_dai, ADAU17X1_PLL,
|
||||
ADAU17X1_PLL_SRC_MCLK, 12288000, pll_rate);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = snd_soc_dai_set_sysclk(codec_dai, ADAU17X1_CLK_SRC_PLL, pll_rate,
|
||||
SND_SOC_CLOCK_IN);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static const struct snd_soc_ops bfin_eval_adau1x81_ops = {
|
||||
.hw_params = bfin_eval_adau1x81_hw_params,
|
||||
};
|
||||
|
||||
static struct snd_soc_dai_link bfin_eval_adau1x81_dai = {
|
||||
.name = "adau1x81",
|
||||
.stream_name = "adau1x81",
|
||||
.cpu_dai_name = "bfin-i2s.0",
|
||||
.codec_dai_name = "adau-hifi",
|
||||
.platform_name = "bfin-i2s-pcm-audio",
|
||||
.codec_name = "adau1781.0-0038",
|
||||
.ops = &bfin_eval_adau1x81_ops,
|
||||
.dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF |
|
||||
SND_SOC_DAIFMT_CBM_CFM,
|
||||
};
|
||||
|
||||
static struct snd_soc_card bfin_eval_adau1x81 = {
|
||||
.name = "bfin-eval-adau1x81",
|
||||
.driver_name = "eval-adau1x81",
|
||||
.dai_link = &bfin_eval_adau1x81_dai,
|
||||
.num_links = 1,
|
||||
|
||||
.dapm_widgets = bfin_eval_adau1x81_dapm_widgets,
|
||||
.num_dapm_widgets = ARRAY_SIZE(bfin_eval_adau1x81_dapm_widgets),
|
||||
.dapm_routes = bfin_eval_adau1x81_dapm_routes,
|
||||
.num_dapm_routes = ARRAY_SIZE(bfin_eval_adau1x81_dapm_routes),
|
||||
.fully_routed = true,
|
||||
};
|
||||
|
||||
static int bfin_eval_adau1x81_probe(struct platform_device *pdev)
|
||||
{
|
||||
bfin_eval_adau1x81.dev = &pdev->dev;
|
||||
|
||||
return devm_snd_soc_register_card(&pdev->dev, &bfin_eval_adau1x81);
|
||||
}
|
||||
|
||||
static struct platform_driver bfin_eval_adau1x81_driver = {
|
||||
.driver = {
|
||||
.name = "bfin-eval-adau1x81",
|
||||
.pm = &snd_soc_pm_ops,
|
||||
},
|
||||
.probe = bfin_eval_adau1x81_probe,
|
||||
};
|
||||
module_platform_driver(bfin_eval_adau1x81_driver);
|
||||
|
||||
MODULE_AUTHOR("Lars-Peter Clausen <lars@metafoo.de>");
|
||||
MODULE_DESCRIPTION("ALSA SoC bfin adau1x81 driver");
|
||||
MODULE_LICENSE("GPL");
|
||||
MODULE_ALIAS("platform:bfin-eval-adau1x81");
|
|
@ -1,145 +0,0 @@
|
|||
/*
|
||||
* Machine driver for EVAL-ADAV801 and EVAL-ADAV803 on Analog Devices bfin
|
||||
* evaluation boards.
|
||||
*
|
||||
* Copyright 2011 Analog Devices Inc.
|
||||
* Author: Lars-Peter Clausen <lars@metafoo.de>
|
||||
*
|
||||
* Licensed under the GPL-2 or later.
|
||||
*/
|
||||
|
||||
#include <linux/init.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/module.h>
|
||||
#include <sound/core.h>
|
||||
#include <sound/pcm.h>
|
||||
#include <sound/soc.h>
|
||||
|
||||
#include "../codecs/adav80x.h"
|
||||
|
||||
static const struct snd_soc_dapm_widget bfin_eval_adav80x_dapm_widgets[] = {
|
||||
SND_SOC_DAPM_LINE("Line Out", NULL),
|
||||
SND_SOC_DAPM_LINE("Line In", NULL),
|
||||
};
|
||||
|
||||
static const struct snd_soc_dapm_route bfin_eval_adav80x_dapm_routes[] = {
|
||||
{ "Line Out", NULL, "VOUTL" },
|
||||
{ "Line Out", NULL, "VOUTR" },
|
||||
|
||||
{ "VINL", NULL, "Line In" },
|
||||
{ "VINR", NULL, "Line In" },
|
||||
};
|
||||
|
||||
static int bfin_eval_adav80x_hw_params(struct snd_pcm_substream *substream,
|
||||
struct snd_pcm_hw_params *params)
|
||||
{
|
||||
struct snd_soc_pcm_runtime *rtd = substream->private_data;
|
||||
struct snd_soc_dai *codec_dai = rtd->codec_dai;
|
||||
int ret;
|
||||
|
||||
ret = snd_soc_dai_set_pll(codec_dai, ADAV80X_PLL1, ADAV80X_PLL_SRC_XTAL,
|
||||
27000000, params_rate(params) * 256);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = snd_soc_dai_set_sysclk(codec_dai, ADAV80X_CLK_PLL1,
|
||||
params_rate(params) * 256, SND_SOC_CLOCK_IN);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int bfin_eval_adav80x_codec_init(struct snd_soc_pcm_runtime *rtd)
|
||||
{
|
||||
struct snd_soc_dai *codec_dai = rtd->codec_dai;
|
||||
|
||||
snd_soc_dai_set_sysclk(codec_dai, ADAV80X_CLK_SYSCLK1, 0,
|
||||
SND_SOC_CLOCK_OUT);
|
||||
snd_soc_dai_set_sysclk(codec_dai, ADAV80X_CLK_SYSCLK2, 0,
|
||||
SND_SOC_CLOCK_OUT);
|
||||
snd_soc_dai_set_sysclk(codec_dai, ADAV80X_CLK_SYSCLK3, 0,
|
||||
SND_SOC_CLOCK_OUT);
|
||||
|
||||
snd_soc_dai_set_sysclk(codec_dai, ADAV80X_CLK_XTAL, 2700000, 0);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct snd_soc_ops bfin_eval_adav80x_ops = {
|
||||
.hw_params = bfin_eval_adav80x_hw_params,
|
||||
};
|
||||
|
||||
static struct snd_soc_dai_link bfin_eval_adav80x_dais[] = {
|
||||
{
|
||||
.name = "adav80x",
|
||||
.stream_name = "ADAV80x HiFi",
|
||||
.cpu_dai_name = "bfin-i2s.0",
|
||||
.codec_dai_name = "adav80x-hifi",
|
||||
.platform_name = "bfin-i2s-pcm-audio",
|
||||
.init = bfin_eval_adav80x_codec_init,
|
||||
.ops = &bfin_eval_adav80x_ops,
|
||||
.dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF |
|
||||
SND_SOC_DAIFMT_CBM_CFM,
|
||||
},
|
||||
};
|
||||
|
||||
static struct snd_soc_card bfin_eval_adav80x = {
|
||||
.name = "bfin-eval-adav80x",
|
||||
.owner = THIS_MODULE,
|
||||
.dai_link = bfin_eval_adav80x_dais,
|
||||
.num_links = ARRAY_SIZE(bfin_eval_adav80x_dais),
|
||||
|
||||
.dapm_widgets = bfin_eval_adav80x_dapm_widgets,
|
||||
.num_dapm_widgets = ARRAY_SIZE(bfin_eval_adav80x_dapm_widgets),
|
||||
.dapm_routes = bfin_eval_adav80x_dapm_routes,
|
||||
.num_dapm_routes = ARRAY_SIZE(bfin_eval_adav80x_dapm_routes),
|
||||
};
|
||||
|
||||
enum bfin_eval_adav80x_type {
|
||||
BFIN_EVAL_ADAV801,
|
||||
BFIN_EVAL_ADAV803,
|
||||
};
|
||||
|
||||
static int bfin_eval_adav80x_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct snd_soc_card *card = &bfin_eval_adav80x;
|
||||
const char *codec_name;
|
||||
|
||||
switch (platform_get_device_id(pdev)->driver_data) {
|
||||
case BFIN_EVAL_ADAV801:
|
||||
codec_name = "spi0.1";
|
||||
break;
|
||||
case BFIN_EVAL_ADAV803:
|
||||
codec_name = "adav803.0-0034";
|
||||
break;
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
bfin_eval_adav80x_dais[0].codec_name = codec_name;
|
||||
|
||||
card->dev = &pdev->dev;
|
||||
|
||||
return devm_snd_soc_register_card(&pdev->dev, &bfin_eval_adav80x);
|
||||
}
|
||||
|
||||
static const struct platform_device_id bfin_eval_adav80x_ids[] = {
|
||||
{ "bfin-eval-adav801", BFIN_EVAL_ADAV801 },
|
||||
{ "bfin-eval-adav803", BFIN_EVAL_ADAV803 },
|
||||
{ },
|
||||
};
|
||||
MODULE_DEVICE_TABLE(platform, bfin_eval_adav80x_ids);
|
||||
|
||||
static struct platform_driver bfin_eval_adav80x_driver = {
|
||||
.driver = {
|
||||
.name = "bfin-eval-adav80x",
|
||||
.pm = &snd_soc_pm_ops,
|
||||
},
|
||||
.probe = bfin_eval_adav80x_probe,
|
||||
.id_table = bfin_eval_adav80x_ids,
|
||||
};
|
||||
|
||||
module_platform_driver(bfin_eval_adav80x_driver);
|
||||
|
||||
MODULE_AUTHOR("Lars-Peter Clausen <lars@metafoo.de>");
|
||||
MODULE_DESCRIPTION("ALSA SoC bfin adav80x driver");
|
||||
MODULE_LICENSE("GPL");
|
Loading…
Reference in New Issue