ASoC: Last minute updates
These are all new code, they've been in -next already so should be OK for merge this time round. I'd been planning to send a pull request today after they'd had a bit of exposure there to make sure breakage didn't propagate into your tree. -----BEGIN PGP SIGNATURE----- Version: GnuPG v1.4.12 (GNU/Linux) iQIcBAABAgAGBQJPuldTAAoJEBus8iNuMP3d+AgP/jqsjHm4DRXw48OMO3gX45yN Y9JsvMQRYtiUY/zmfHKm8J2BoH3N1SdQjFXzp7qpAJ1RIz5aEKQu41ji/xDOSiu7 X/SxPxeMumZp50HjQS3VHyrwtkd+bwprbG0/Hk2TPnZ2aY6WQ6pfC3smHQYKQ75m saXrpmTv7s4zgAN2KXw35m304WvifuQ/KvUs/PU5LFVdy38YXacA0SMusTV6H2VG DN5ENxT2e9NYU5zTCTEVmK7vwoApsX7PmnDor6KygGUceGijHHmDtDqRWBxelVJv MS+LQsM3xdqRkX4gETtzg4EN7taRLRJQAFFImM32+M3u4g2Q2fYSpIEPYrf5SatP GxpcZogDtjs6e+SqtWQb8vFmVCEq/6icMpOzmUQZhoKjF4D5QO7gGN8LLPiahons Cc1C3L2JQO1tZ9vryt6aEub2vUNm7KO22ODqYo6xVYBaYYl8vv9WXvLv7TgTSocF YwsxaRfFTy8jlP1OFVsywQa5k1yPb/twD9HFNpwTUtMrMP4QPdp7wvJaDJrBBXxi U8uD/JSub/0CDjlYgvB/f6LRTZdjeVeirR9AyAyiLKnj9YxdrmY0v6n40voDFwMg wLGECAdksuDSfnnN7+k+LM7bRDycQhO/QMV7t6ZdtMl5KdQZ69KoK4qdyoLq4BUi c3LRJaPlV6tmI54YrhRN =5L34 -----END PGP SIGNATURE----- Merge tag 'asoc-3.5' of git://git.kernel.org/pub/scm/linux/kernel/git/broonie/sound into for-linus ASoC: Last minute updates These are all new code, they've been in -next already so should be OK for merge this time round. I'd been planning to send a pull request today after they'd had a bit of exposure there to make sure breakage didn't propagate into your tree.
This commit is contained in:
commit
85e184e4c3
|
@ -0,0 +1,54 @@
|
|||
NVIDIA Tegra audio complex
|
||||
|
||||
Required properties:
|
||||
- compatible : "nvidia,tegra-audio-wm8753"
|
||||
- nvidia,model : The user-visible name of this sound complex.
|
||||
- nvidia,audio-routing : A list of the connections between audio components.
|
||||
Each entry is a pair of strings, the first being the connection's sink,
|
||||
the second being the connection's source. Valid names for sources and
|
||||
sinks are the WM8753's pins, and the jacks on the board:
|
||||
|
||||
WM8753 pins:
|
||||
|
||||
* LOUT1
|
||||
* LOUT2
|
||||
* ROUT1
|
||||
* ROUT2
|
||||
* MONO1
|
||||
* MONO2
|
||||
* OUT3
|
||||
* OUT4
|
||||
* LINE1
|
||||
* LINE2
|
||||
* RXP
|
||||
* RXN
|
||||
* ACIN
|
||||
* ACOP
|
||||
* MIC1N
|
||||
* MIC1
|
||||
* MIC2N
|
||||
* MIC2
|
||||
* Mic Bias
|
||||
|
||||
Board connectors:
|
||||
|
||||
* Headphone Jack
|
||||
* Mic Jack
|
||||
|
||||
- nvidia,i2s-controller : The phandle of the Tegra I2S1 controller
|
||||
- nvidia,audio-codec : The phandle of the WM8753 audio codec
|
||||
Example:
|
||||
|
||||
sound {
|
||||
compatible = "nvidia,tegra-audio-wm8753-whistler",
|
||||
"nvidia,tegra-audio-wm8753"
|
||||
nvidia,model = "tegra-wm8753-harmony";
|
||||
|
||||
nvidia,audio-routing =
|
||||
"Headphone Jack", "LOUT1",
|
||||
"Headphone Jack", "ROUT1";
|
||||
|
||||
nvidia,i2s-controller = <&i2s1>;
|
||||
nvidia,audio-codec = <&wm8753>;
|
||||
};
|
||||
|
|
@ -21,10 +21,11 @@
|
|||
/*
|
||||
* flags format
|
||||
*
|
||||
* 0x000000BA
|
||||
* 0x00000CBA
|
||||
*
|
||||
* A: inversion
|
||||
* B: format mode
|
||||
* C: chip specific
|
||||
*/
|
||||
|
||||
/* A: clock inversion */
|
||||
|
@ -39,6 +40,9 @@
|
|||
#define SH_FSI_FMT_DAI (0 << 4)
|
||||
#define SH_FSI_FMT_SPDIF (1 << 4)
|
||||
|
||||
/* C: chip specific */
|
||||
#define SH_FSI_OPTION_MASK 0x00000F00
|
||||
#define SH_FSI_ENABLE_STREAM_MODE (1 << 8) /* for 16bit data */
|
||||
|
||||
/*
|
||||
* set_rate return value
|
||||
|
|
|
@ -46,6 +46,7 @@ config SND_SOC_ALL_CODECS
|
|||
select SND_SOC_MAX9877 if I2C
|
||||
select SND_SOC_MC13783 if MFD_MC13XXX
|
||||
select SND_SOC_ML26124 if I2C
|
||||
select SND_SOC_OMAP_HDMI_CODEC if OMAP4_DSS_HDMI
|
||||
select SND_SOC_PCM3008
|
||||
select SND_SOC_RT5631 if I2C
|
||||
select SND_SOC_SGTL5000 if I2C
|
||||
|
@ -236,6 +237,9 @@ config SND_SOC_MAX98095
|
|||
config SND_SOC_MAX9850
|
||||
tristate
|
||||
|
||||
config SND_SOC_OMAP_HDMI_CODEC
|
||||
tristate
|
||||
|
||||
config SND_SOC_PCM3008
|
||||
tristate
|
||||
|
||||
|
|
|
@ -33,6 +33,7 @@ snd-soc-max98095-objs := max98095.o
|
|||
snd-soc-max9850-objs := max9850.o
|
||||
snd-soc-mc13783-objs := mc13783.o
|
||||
snd-soc-ml26124-objs := ml26124.o
|
||||
snd-soc-omap-hdmi-codec-objs := omap-hdmi.o
|
||||
snd-soc-pcm3008-objs := pcm3008.o
|
||||
snd-soc-rt5631-objs := rt5631.o
|
||||
snd-soc-sgtl5000-objs := sgtl5000.o
|
||||
|
@ -143,6 +144,7 @@ obj-$(CONFIG_SND_SOC_MAX98095) += snd-soc-max98095.o
|
|||
obj-$(CONFIG_SND_SOC_MAX9850) += snd-soc-max9850.o
|
||||
obj-$(CONFIG_SND_SOC_MC13783) += snd-soc-mc13783.o
|
||||
obj-$(CONFIG_SND_SOC_ML26124) += snd-soc-ml26124.o
|
||||
obj-$(CONFIG_SND_SOC_OMAP_HDMI_CODEC) += snd-soc-omap-hdmi-codec.o
|
||||
obj-$(CONFIG_SND_SOC_PCM3008) += snd-soc-pcm3008.o
|
||||
obj-$(CONFIG_SND_SOC_RT5631) += snd-soc-rt5631.o
|
||||
obj-$(CONFIG_SND_SOC_SGTL5000) += snd-soc-sgtl5000.o
|
||||
|
|
|
@ -0,0 +1,69 @@
|
|||
/*
|
||||
* ALSA SoC codec driver for HDMI audio on OMAP processors.
|
||||
* Copyright (C) 2012 Texas Instruments Incorporated - http://www.ti.com/
|
||||
* Author: Ricardo Neri <ricardo.neri@ti.com>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* version 2 as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
|
||||
* 02110-1301 USA
|
||||
*
|
||||
*/
|
||||
#include <linux/module.h>
|
||||
#include <sound/soc.h>
|
||||
|
||||
#define DRV_NAME "hdmi-audio-codec"
|
||||
|
||||
static struct snd_soc_codec_driver omap_hdmi_codec;
|
||||
|
||||
static struct snd_soc_dai_driver omap_hdmi_codec_dai = {
|
||||
.name = "omap-hdmi-hifi",
|
||||
.playback = {
|
||||
.channels_min = 2,
|
||||
.channels_max = 8,
|
||||
.rates = SNDRV_PCM_RATE_32000 |
|
||||
SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000 |
|
||||
SNDRV_PCM_RATE_88200 | SNDRV_PCM_RATE_96000 |
|
||||
SNDRV_PCM_RATE_176400 | SNDRV_PCM_RATE_192000,
|
||||
.formats = SNDRV_PCM_FMTBIT_S16_LE |
|
||||
SNDRV_PCM_FMTBIT_S24_LE,
|
||||
},
|
||||
};
|
||||
|
||||
static __devinit int omap_hdmi_codec_probe(struct platform_device *pdev)
|
||||
{
|
||||
return snd_soc_register_codec(&pdev->dev, &omap_hdmi_codec,
|
||||
&omap_hdmi_codec_dai, 1);
|
||||
}
|
||||
|
||||
static __devexit int omap_hdmi_codec_remove(struct platform_device *pdev)
|
||||
{
|
||||
snd_soc_unregister_codec(&pdev->dev);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct platform_driver omap_hdmi_codec_driver = {
|
||||
.driver = {
|
||||
.name = DRV_NAME,
|
||||
.owner = THIS_MODULE,
|
||||
},
|
||||
|
||||
.probe = omap_hdmi_codec_probe,
|
||||
.remove = __devexit_p(omap_hdmi_codec_remove),
|
||||
};
|
||||
|
||||
module_platform_driver(omap_hdmi_codec_driver);
|
||||
|
||||
MODULE_AUTHOR("Ricardo Neri <ricardo.neri@ti.com>");
|
||||
MODULE_DESCRIPTION("ASoC OMAP HDMI codec driver");
|
||||
MODULE_LICENSE("GPL");
|
||||
MODULE_ALIAS("platform:" DRV_NAME);
|
|
@ -113,6 +113,7 @@ config SND_OMAP_SOC_OMAP4_HDMI
|
|||
tristate "SoC Audio support for Texas Instruments OMAP4 HDMI"
|
||||
depends on SND_OMAP_SOC && OMAP4_DSS_HDMI && OMAP2_DSS && ARCH_OMAP4
|
||||
select SND_OMAP_SOC_HDMI
|
||||
select SND_SOC_OMAP_HDMI_CODEC
|
||||
help
|
||||
Say Y if you want to add support for SoC HDMI audio on Texas Instruments
|
||||
OMAP4 chips
|
||||
|
|
|
@ -131,6 +131,25 @@
|
|||
|
||||
typedef int (*set_rate_func)(struct device *dev, int rate, int enable);
|
||||
|
||||
/*
|
||||
* bus options
|
||||
*
|
||||
* 0x000000BA
|
||||
*
|
||||
* A : sample widtht 16bit setting
|
||||
* B : sample widtht 24bit setting
|
||||
*/
|
||||
|
||||
#define SHIFT_16DATA 0
|
||||
#define SHIFT_24DATA 4
|
||||
|
||||
#define PACKAGE_24BITBUS_BACK 0
|
||||
#define PACKAGE_24BITBUS_FRONT 1
|
||||
#define PACKAGE_16BITBUS_STREAM 2
|
||||
|
||||
#define BUSOP_SET(s, a) ((a) << SHIFT_ ## s ## DATA)
|
||||
#define BUSOP_GET(s, a) (((a) >> SHIFT_ ## s ## DATA) & 0xF)
|
||||
|
||||
/*
|
||||
* FSI driver use below type name for variable
|
||||
*
|
||||
|
@ -188,6 +207,11 @@ struct fsi_stream {
|
|||
int uerr_num;
|
||||
int oerr_num;
|
||||
|
||||
/*
|
||||
* bus options
|
||||
*/
|
||||
u32 bus_option;
|
||||
|
||||
/*
|
||||
* thse are initialized by fsi_handler_init()
|
||||
*/
|
||||
|
@ -211,8 +235,7 @@ struct fsi_priv {
|
|||
struct fsi_stream playback;
|
||||
struct fsi_stream capture;
|
||||
|
||||
u32 do_fmt;
|
||||
u32 di_fmt;
|
||||
u32 fmt;
|
||||
|
||||
int chan_num:16;
|
||||
int clk_master:1;
|
||||
|
@ -321,6 +344,10 @@ static void _fsi_master_mask_set(struct fsi_master *master,
|
|||
/*
|
||||
* basic function
|
||||
*/
|
||||
static int fsi_version(struct fsi_master *master)
|
||||
{
|
||||
return master->core->ver;
|
||||
}
|
||||
|
||||
static struct fsi_master *fsi_get_master(struct fsi_priv *fsi)
|
||||
{
|
||||
|
@ -495,6 +522,7 @@ static void fsi_stream_init(struct fsi_priv *fsi,
|
|||
io->period_samples = fsi_frame2sample(fsi, runtime->period_size);
|
||||
io->period_pos = 0;
|
||||
io->sample_width = samples_to_bytes(runtime, 1);
|
||||
io->bus_option = 0;
|
||||
io->oerr_num = -1; /* ignore 1st err */
|
||||
io->uerr_num = -1; /* ignore 1st err */
|
||||
fsi_stream_handler_call(io, init, fsi, io);
|
||||
|
@ -522,6 +550,7 @@ static void fsi_stream_quit(struct fsi_priv *fsi, struct fsi_stream *io)
|
|||
io->period_samples = 0;
|
||||
io->period_pos = 0;
|
||||
io->sample_width = 0;
|
||||
io->bus_option = 0;
|
||||
io->oerr_num = 0;
|
||||
io->uerr_num = 0;
|
||||
spin_unlock_irqrestore(&master->lock, flags);
|
||||
|
@ -580,6 +609,53 @@ static int fsi_stream_remove(struct fsi_priv *fsi)
|
|||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* format/bus/dma setting
|
||||
*/
|
||||
static void fsi_format_bus_setup(struct fsi_priv *fsi, struct fsi_stream *io,
|
||||
u32 bus, struct device *dev)
|
||||
{
|
||||
struct fsi_master *master = fsi_get_master(fsi);
|
||||
int is_play = fsi_stream_is_play(fsi, io);
|
||||
u32 fmt = fsi->fmt;
|
||||
|
||||
if (fsi_version(master) >= 2) {
|
||||
u32 dma = 0;
|
||||
|
||||
/*
|
||||
* FSI2 needs DMA/Bus setting
|
||||
*/
|
||||
switch (bus) {
|
||||
case PACKAGE_24BITBUS_FRONT:
|
||||
fmt |= CR_BWS_24;
|
||||
dma |= VDMD_FRONT;
|
||||
dev_dbg(dev, "24bit bus / package in front\n");
|
||||
break;
|
||||
case PACKAGE_16BITBUS_STREAM:
|
||||
fmt |= CR_BWS_16;
|
||||
dma |= VDMD_STREAM;
|
||||
dev_dbg(dev, "16bit bus / stream mode\n");
|
||||
break;
|
||||
case PACKAGE_24BITBUS_BACK:
|
||||
default:
|
||||
fmt |= CR_BWS_24;
|
||||
dma |= VDMD_BACK;
|
||||
dev_dbg(dev, "24bit bus / package in back\n");
|
||||
break;
|
||||
}
|
||||
|
||||
if (is_play)
|
||||
fsi_reg_write(fsi, OUT_DMAC, dma);
|
||||
else
|
||||
fsi_reg_write(fsi, IN_DMAC, dma);
|
||||
}
|
||||
|
||||
if (is_play)
|
||||
fsi_reg_write(fsi, DO_FMT, fmt);
|
||||
else
|
||||
fsi_reg_write(fsi, DI_FMT, fmt);
|
||||
}
|
||||
|
||||
/*
|
||||
* irq function
|
||||
*/
|
||||
|
@ -629,11 +705,6 @@ static void fsi_spdif_clk_ctrl(struct fsi_priv *fsi, int enable)
|
|||
struct fsi_master *master = fsi_get_master(fsi);
|
||||
u32 mask, val;
|
||||
|
||||
if (master->core->ver < 2) {
|
||||
pr_err("fsi: register access err (%s)\n", __func__);
|
||||
return;
|
||||
}
|
||||
|
||||
mask = BP | SE;
|
||||
val = enable ? mask : 0;
|
||||
|
||||
|
@ -648,9 +719,7 @@ static void fsi_spdif_clk_ctrl(struct fsi_priv *fsi, int enable)
|
|||
static int fsi_set_master_clk(struct device *dev, struct fsi_priv *fsi,
|
||||
long rate, int enable)
|
||||
{
|
||||
struct fsi_master *master = fsi_get_master(fsi);
|
||||
set_rate_func set_rate = fsi_get_info_set_rate(fsi);
|
||||
int fsi_ver = master->core->ver;
|
||||
int ret;
|
||||
|
||||
if (!set_rate)
|
||||
|
@ -682,10 +751,7 @@ static int fsi_set_master_clk(struct device *dev, struct fsi_priv *fsi,
|
|||
data |= (0x3 << 12);
|
||||
break;
|
||||
case SH_FSI_ACKMD_32:
|
||||
if (fsi_ver < 2)
|
||||
dev_err(dev, "unsupported ACKMD\n");
|
||||
else
|
||||
data |= (0x4 << 12);
|
||||
data |= (0x4 << 12);
|
||||
break;
|
||||
}
|
||||
|
||||
|
@ -708,10 +774,7 @@ static int fsi_set_master_clk(struct device *dev, struct fsi_priv *fsi,
|
|||
data |= (0x4 << 8);
|
||||
break;
|
||||
case SH_FSI_BPFMD_16:
|
||||
if (fsi_ver < 2)
|
||||
dev_err(dev, "unsupported ACKMD\n");
|
||||
else
|
||||
data |= (0x7 << 8);
|
||||
data |= (0x7 << 8);
|
||||
break;
|
||||
}
|
||||
|
||||
|
@ -728,11 +791,26 @@ static int fsi_set_master_clk(struct device *dev, struct fsi_priv *fsi,
|
|||
*/
|
||||
static void fsi_pio_push16(struct fsi_priv *fsi, u8 *_buf, int samples)
|
||||
{
|
||||
u16 *buf = (u16 *)_buf;
|
||||
u32 enable_stream = fsi_get_info_flags(fsi) & SH_FSI_ENABLE_STREAM_MODE;
|
||||
int i;
|
||||
|
||||
for (i = 0; i < samples; i++)
|
||||
fsi_reg_write(fsi, DODT, ((u32)*(buf + i) << 8));
|
||||
if (enable_stream) {
|
||||
/*
|
||||
* stream mode
|
||||
* see
|
||||
* fsi_pio_push_init()
|
||||
*/
|
||||
u32 *buf = (u32 *)_buf;
|
||||
|
||||
for (i = 0; i < samples / 2; i++)
|
||||
fsi_reg_write(fsi, DODT, buf[i]);
|
||||
} else {
|
||||
/* normal mode */
|
||||
u16 *buf = (u16 *)_buf;
|
||||
|
||||
for (i = 0; i < samples; i++)
|
||||
fsi_reg_write(fsi, DODT, ((u32)*(buf + i) << 8));
|
||||
}
|
||||
}
|
||||
|
||||
static void fsi_pio_pop16(struct fsi_priv *fsi, u8 *_buf, int samples)
|
||||
|
@ -872,12 +950,44 @@ static void fsi_pio_start_stop(struct fsi_priv *fsi, struct fsi_stream *io,
|
|||
fsi_master_mask_set(master, CLK_RST, clk, (enable) ? clk : 0);
|
||||
}
|
||||
|
||||
static int fsi_pio_push_init(struct fsi_priv *fsi, struct fsi_stream *io)
|
||||
{
|
||||
u32 enable_stream = fsi_get_info_flags(fsi) & SH_FSI_ENABLE_STREAM_MODE;
|
||||
|
||||
/*
|
||||
* we can use 16bit stream mode
|
||||
* when "playback" and "16bit data"
|
||||
* and platform allows "stream mode"
|
||||
* see
|
||||
* fsi_pio_push16()
|
||||
*/
|
||||
if (enable_stream)
|
||||
io->bus_option = BUSOP_SET(24, PACKAGE_24BITBUS_BACK) |
|
||||
BUSOP_SET(16, PACKAGE_16BITBUS_STREAM);
|
||||
else
|
||||
io->bus_option = BUSOP_SET(24, PACKAGE_24BITBUS_BACK) |
|
||||
BUSOP_SET(16, PACKAGE_24BITBUS_BACK);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int fsi_pio_pop_init(struct fsi_priv *fsi, struct fsi_stream *io)
|
||||
{
|
||||
/*
|
||||
* always 24bit bus, package back when "capture"
|
||||
*/
|
||||
io->bus_option = BUSOP_SET(24, PACKAGE_24BITBUS_BACK) |
|
||||
BUSOP_SET(16, PACKAGE_24BITBUS_BACK);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct fsi_stream_handler fsi_pio_push_handler = {
|
||||
.init = fsi_pio_push_init,
|
||||
.transfer = fsi_pio_push,
|
||||
.start_stop = fsi_pio_start_stop,
|
||||
};
|
||||
|
||||
static struct fsi_stream_handler fsi_pio_pop_handler = {
|
||||
.init = fsi_pio_pop_init,
|
||||
.transfer = fsi_pio_pop,
|
||||
.start_stop = fsi_pio_start_stop,
|
||||
};
|
||||
|
@ -919,6 +1029,13 @@ static int fsi_dma_init(struct fsi_priv *fsi, struct fsi_stream *io)
|
|||
enum dma_data_direction dir = fsi_stream_is_play(fsi, io) ?
|
||||
DMA_TO_DEVICE : DMA_FROM_DEVICE;
|
||||
|
||||
/*
|
||||
* 24bit data : 24bit bus / package in back
|
||||
* 16bit data : 16bit bus / stream mode
|
||||
*/
|
||||
io->bus_option = BUSOP_SET(24, PACKAGE_24BITBUS_BACK) |
|
||||
BUSOP_SET(16, PACKAGE_16BITBUS_STREAM);
|
||||
|
||||
io->dma = dma_map_single(dai->dev, runtime->dma_area,
|
||||
snd_pcm_lib_buffer_bytes(io->substream), dir);
|
||||
return 0;
|
||||
|
@ -1055,25 +1172,9 @@ static int fsi_dma_transfer(struct fsi_priv *fsi, struct fsi_stream *io)
|
|||
static void fsi_dma_push_start_stop(struct fsi_priv *fsi, struct fsi_stream *io,
|
||||
int start)
|
||||
{
|
||||
u32 bws;
|
||||
u32 dma;
|
||||
u32 enable = start ? DMA_ON : 0;
|
||||
|
||||
switch (io->sample_width * start) {
|
||||
case 2:
|
||||
bws = CR_BWS_16;
|
||||
dma = VDMD_STREAM | DMA_ON;
|
||||
break;
|
||||
case 4:
|
||||
bws = CR_BWS_24;
|
||||
dma = VDMD_BACK | DMA_ON;
|
||||
break;
|
||||
default:
|
||||
bws = 0;
|
||||
dma = 0;
|
||||
}
|
||||
|
||||
fsi_reg_mask_set(fsi, DO_FMT, CR_BWS_MASK, bws);
|
||||
fsi_reg_write(fsi, OUT_DMAC, dma);
|
||||
fsi_reg_mask_set(fsi, OUT_DMAC, DMA_ON, enable);
|
||||
}
|
||||
|
||||
static int fsi_dma_probe(struct fsi_priv *fsi, struct fsi_stream *io)
|
||||
|
@ -1176,8 +1277,6 @@ static int fsi_hw_startup(struct fsi_priv *fsi,
|
|||
struct fsi_stream *io,
|
||||
struct device *dev)
|
||||
{
|
||||
struct fsi_master *master = fsi_get_master(fsi);
|
||||
int fsi_ver = master->core->ver;
|
||||
u32 flags = fsi_get_info_flags(fsi);
|
||||
u32 data = 0;
|
||||
|
||||
|
@ -1200,10 +1299,6 @@ static int fsi_hw_startup(struct fsi_priv *fsi,
|
|||
|
||||
fsi_reg_write(fsi, CKG2, data);
|
||||
|
||||
/* set format */
|
||||
fsi_reg_write(fsi, DO_FMT, fsi->do_fmt);
|
||||
fsi_reg_write(fsi, DI_FMT, fsi->di_fmt);
|
||||
|
||||
/* spdif ? */
|
||||
if (fsi_is_spdif(fsi)) {
|
||||
fsi_spdif_clk_ctrl(fsi, 1);
|
||||
|
@ -1211,15 +1306,18 @@ static int fsi_hw_startup(struct fsi_priv *fsi,
|
|||
}
|
||||
|
||||
/*
|
||||
* FIXME
|
||||
*
|
||||
* FSI driver assumed that data package is in-back.
|
||||
* FSI2 chip can select it.
|
||||
* get bus settings
|
||||
*/
|
||||
if (fsi_ver >= 2) {
|
||||
fsi_reg_write(fsi, OUT_DMAC, (1 << 4));
|
||||
fsi_reg_write(fsi, IN_DMAC, (1 << 4));
|
||||
data = 0;
|
||||
switch (io->sample_width) {
|
||||
case 2:
|
||||
data = BUSOP_GET(16, io->bus_option);
|
||||
break;
|
||||
case 4:
|
||||
data = BUSOP_GET(24, io->bus_option);
|
||||
break;
|
||||
}
|
||||
fsi_format_bus_setup(fsi, io, data, dev);
|
||||
|
||||
/* irq clear */
|
||||
fsi_irq_disable(fsi, io);
|
||||
|
@ -1243,7 +1341,9 @@ static int fsi_dai_startup(struct snd_pcm_substream *substream,
|
|||
{
|
||||
struct fsi_priv *fsi = fsi_get_priv(substream);
|
||||
|
||||
return fsi_hw_startup(fsi, fsi_stream_get(fsi, substream), dai->dev);
|
||||
fsi->rate = 0;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void fsi_dai_shutdown(struct snd_pcm_substream *substream,
|
||||
|
@ -1251,7 +1351,6 @@ static void fsi_dai_shutdown(struct snd_pcm_substream *substream,
|
|||
{
|
||||
struct fsi_priv *fsi = fsi_get_priv(substream);
|
||||
|
||||
fsi_hw_shutdown(fsi, dai->dev);
|
||||
fsi->rate = 0;
|
||||
}
|
||||
|
||||
|
@ -1265,11 +1364,13 @@ static int fsi_dai_trigger(struct snd_pcm_substream *substream, int cmd,
|
|||
switch (cmd) {
|
||||
case SNDRV_PCM_TRIGGER_START:
|
||||
fsi_stream_init(fsi, io, substream);
|
||||
fsi_hw_startup(fsi, io, dai->dev);
|
||||
ret = fsi_stream_transfer(io);
|
||||
if (0 == ret)
|
||||
fsi_stream_start(fsi, io);
|
||||
break;
|
||||
case SNDRV_PCM_TRIGGER_STOP:
|
||||
fsi_hw_shutdown(fsi, dai->dev);
|
||||
fsi_stream_stop(fsi, io);
|
||||
fsi_stream_quit(fsi, io);
|
||||
break;
|
||||
|
@ -1280,42 +1381,33 @@ static int fsi_dai_trigger(struct snd_pcm_substream *substream, int cmd,
|
|||
|
||||
static int fsi_set_fmt_dai(struct fsi_priv *fsi, unsigned int fmt)
|
||||
{
|
||||
u32 data = 0;
|
||||
|
||||
switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
|
||||
case SND_SOC_DAIFMT_I2S:
|
||||
data = CR_I2S;
|
||||
fsi->fmt = CR_I2S;
|
||||
fsi->chan_num = 2;
|
||||
break;
|
||||
case SND_SOC_DAIFMT_LEFT_J:
|
||||
data = CR_PCM;
|
||||
fsi->fmt = CR_PCM;
|
||||
fsi->chan_num = 2;
|
||||
break;
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
fsi->do_fmt = data;
|
||||
fsi->di_fmt = data;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int fsi_set_fmt_spdif(struct fsi_priv *fsi)
|
||||
{
|
||||
struct fsi_master *master = fsi_get_master(fsi);
|
||||
u32 data = 0;
|
||||
|
||||
if (master->core->ver < 2)
|
||||
if (fsi_version(master) < 2)
|
||||
return -EINVAL;
|
||||
|
||||
data = CR_BWS_16 | CR_DTMD_SPDIF_PCM | CR_PCM;
|
||||
fsi->fmt = CR_DTMD_SPDIF_PCM | CR_PCM;
|
||||
fsi->chan_num = 2;
|
||||
fsi->spdif = 1;
|
||||
|
||||
fsi->do_fmt = data;
|
||||
fsi->di_fmt = data;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
|
@ -48,6 +48,16 @@ config SND_SOC_TEGRA30_I2S
|
|||
Tegra30 I2S interface. You will also need to select the individual
|
||||
machine drivers to support below.
|
||||
|
||||
config SND_SOC_TEGRA_WM8753
|
||||
tristate "SoC Audio support for Tegra boards using a WM8753 codec"
|
||||
depends on SND_SOC_TEGRA && I2C
|
||||
select SND_SOC_TEGRA20_I2S if ARCH_TEGRA_2x_SOC
|
||||
select SND_SOC_TEGRA30_I2S if ARCH_TEGRA_3x_SOC
|
||||
select SND_SOC_WM8753
|
||||
help
|
||||
Say Y or M here if you want to add support for SoC audio on Tegra
|
||||
boards using the WM8753 codec, such as Whistler.
|
||||
|
||||
config MACH_HAS_SND_SOC_TEGRA_WM8903
|
||||
bool
|
||||
help
|
||||
|
|
|
@ -16,10 +16,12 @@ obj-$(CONFIG_SND_SOC_TEGRA30_AHUB) += snd-soc-tegra30-ahub.o
|
|||
obj-$(CONFIG_SND_SOC_TEGRA30_I2S) += snd-soc-tegra30-i2s.o
|
||||
|
||||
# Tegra machine Support
|
||||
snd-soc-tegra-wm8753-objs := tegra_wm8753.o
|
||||
snd-soc-tegra-wm8903-objs := tegra_wm8903.o
|
||||
snd-soc-tegra-trimslice-objs := trimslice.o
|
||||
snd-soc-tegra-alc5632-objs := tegra_alc5632.o
|
||||
|
||||
obj-$(CONFIG_SND_SOC_TEGRA_WM8753) += snd-soc-tegra-wm8753.o
|
||||
obj-$(CONFIG_SND_SOC_TEGRA_WM8903) += snd-soc-tegra-wm8903.o
|
||||
obj-$(CONFIG_SND_SOC_TEGRA_TRIMSLICE) += snd-soc-tegra-trimslice.o
|
||||
obj-$(CONFIG_SND_SOC_TEGRA_ALC5632) += snd-soc-tegra-alc5632.o
|
||||
|
|
|
@ -0,0 +1,224 @@
|
|||
/*
|
||||
* tegra_wm8753.c - Tegra machine ASoC driver for boards using WM8753 codec.
|
||||
*
|
||||
* Author: Stephen Warren <swarren@nvidia.com>
|
||||
* Copyright (C) 2010-2012 - NVIDIA, Inc.
|
||||
*
|
||||
* Based on code copyright/by:
|
||||
*
|
||||
* (c) 2009, 2010 Nvidia Graphics Pvt. Ltd.
|
||||
*
|
||||
* Copyright 2007 Wolfson Microelectronics PLC.
|
||||
* Author: Graeme Gregory
|
||||
* graeme.gregory@wolfsonmicro.com or linux@wolfsonmicro.com
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* version 2 as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
|
||||
* 02110-1301 USA
|
||||
*
|
||||
*/
|
||||
|
||||
#include <asm/mach-types.h>
|
||||
|
||||
#include <linux/module.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/gpio.h>
|
||||
#include <linux/of_gpio.h>
|
||||
|
||||
#include <sound/core.h>
|
||||
#include <sound/jack.h>
|
||||
#include <sound/pcm.h>
|
||||
#include <sound/pcm_params.h>
|
||||
#include <sound/soc.h>
|
||||
|
||||
#include "../codecs/wm8753.h"
|
||||
|
||||
#include "tegra_asoc_utils.h"
|
||||
|
||||
#define DRV_NAME "tegra-snd-wm8753"
|
||||
|
||||
struct tegra_wm8753 {
|
||||
struct tegra_asoc_utils_data util_data;
|
||||
};
|
||||
|
||||
static int tegra_wm8753_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;
|
||||
struct snd_soc_codec *codec = rtd->codec;
|
||||
struct snd_soc_card *card = codec->card;
|
||||
struct tegra_wm8753 *machine = snd_soc_card_get_drvdata(card);
|
||||
int srate, mclk;
|
||||
int err;
|
||||
|
||||
srate = params_rate(params);
|
||||
switch (srate) {
|
||||
case 11025:
|
||||
case 22050:
|
||||
case 44100:
|
||||
case 88200:
|
||||
mclk = 11289600;
|
||||
break;
|
||||
default:
|
||||
mclk = 12288000;
|
||||
break;
|
||||
}
|
||||
|
||||
err = tegra_asoc_utils_set_rate(&machine->util_data, srate, mclk);
|
||||
if (err < 0) {
|
||||
dev_err(card->dev, "Can't configure clocks\n");
|
||||
return err;
|
||||
}
|
||||
|
||||
err = snd_soc_dai_set_sysclk(codec_dai, WM8753_MCLK, mclk,
|
||||
SND_SOC_CLOCK_IN);
|
||||
if (err < 0) {
|
||||
dev_err(card->dev, "codec_dai clock not set\n");
|
||||
return err;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct snd_soc_ops tegra_wm8753_ops = {
|
||||
.hw_params = tegra_wm8753_hw_params,
|
||||
};
|
||||
|
||||
static const struct snd_soc_dapm_widget tegra_wm8753_dapm_widgets[] = {
|
||||
SND_SOC_DAPM_HP("Headphone Jack", NULL),
|
||||
SND_SOC_DAPM_MIC("Mic Jack", NULL),
|
||||
};
|
||||
|
||||
static struct snd_soc_dai_link tegra_wm8753_dai = {
|
||||
.name = "WM8753",
|
||||
.stream_name = "WM8753 PCM",
|
||||
.codec_dai_name = "wm8753-hifi",
|
||||
.ops = &tegra_wm8753_ops,
|
||||
.dai_fmt = SND_SOC_DAIFMT_I2S |
|
||||
SND_SOC_DAIFMT_NB_NF |
|
||||
SND_SOC_DAIFMT_CBS_CFS,
|
||||
};
|
||||
|
||||
static struct snd_soc_card snd_soc_tegra_wm8753 = {
|
||||
.name = "tegra-wm8753",
|
||||
.owner = THIS_MODULE,
|
||||
.dai_link = &tegra_wm8753_dai,
|
||||
.num_links = 1,
|
||||
|
||||
.dapm_widgets = tegra_wm8753_dapm_widgets,
|
||||
.num_dapm_widgets = ARRAY_SIZE(tegra_wm8753_dapm_widgets),
|
||||
.fully_routed = true,
|
||||
};
|
||||
|
||||
static __devinit int tegra_wm8753_driver_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct snd_soc_card *card = &snd_soc_tegra_wm8753;
|
||||
struct tegra_wm8753 *machine;
|
||||
int ret;
|
||||
|
||||
machine = devm_kzalloc(&pdev->dev, sizeof(struct tegra_wm8753),
|
||||
GFP_KERNEL);
|
||||
if (!machine) {
|
||||
dev_err(&pdev->dev, "Can't allocate tegra_wm8753 struct\n");
|
||||
ret = -ENOMEM;
|
||||
goto err;
|
||||
}
|
||||
|
||||
card->dev = &pdev->dev;
|
||||
platform_set_drvdata(pdev, card);
|
||||
snd_soc_card_set_drvdata(card, machine);
|
||||
|
||||
ret = snd_soc_of_parse_card_name(card, "nvidia,model");
|
||||
if (ret)
|
||||
goto err;
|
||||
|
||||
ret = snd_soc_of_parse_audio_routing(card, "nvidia,audio-routing");
|
||||
if (ret)
|
||||
goto err;
|
||||
|
||||
tegra_wm8753_dai.codec_of_node = of_parse_phandle(
|
||||
pdev->dev.of_node, "nvidia,audio-codec", 0);
|
||||
if (!tegra_wm8753_dai.codec_of_node) {
|
||||
dev_err(&pdev->dev,
|
||||
"Property 'nvidia,audio-codec' missing or invalid\n");
|
||||
ret = -EINVAL;
|
||||
goto err;
|
||||
}
|
||||
|
||||
tegra_wm8753_dai.cpu_dai_of_node = of_parse_phandle(
|
||||
pdev->dev.of_node, "nvidia,i2s-controller", 0);
|
||||
if (!tegra_wm8753_dai.cpu_dai_of_node) {
|
||||
dev_err(&pdev->dev,
|
||||
"Property 'nvidia,i2s-controller' missing or invalid\n");
|
||||
ret = -EINVAL;
|
||||
goto err;
|
||||
}
|
||||
|
||||
tegra_wm8753_dai.platform_of_node =
|
||||
tegra_wm8753_dai.cpu_dai_of_node;
|
||||
|
||||
ret = tegra_asoc_utils_init(&machine->util_data, &pdev->dev);
|
||||
if (ret)
|
||||
goto err;
|
||||
|
||||
ret = snd_soc_register_card(card);
|
||||
if (ret) {
|
||||
dev_err(&pdev->dev, "snd_soc_register_card failed (%d)\n",
|
||||
ret);
|
||||
goto err_fini_utils;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
err_fini_utils:
|
||||
tegra_asoc_utils_fini(&machine->util_data);
|
||||
err:
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int __devexit tegra_wm8753_driver_remove(struct platform_device *pdev)
|
||||
{
|
||||
struct snd_soc_card *card = platform_get_drvdata(pdev);
|
||||
struct tegra_wm8753 *machine = snd_soc_card_get_drvdata(card);
|
||||
|
||||
snd_soc_unregister_card(card);
|
||||
|
||||
tegra_asoc_utils_fini(&machine->util_data);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct of_device_id tegra_wm8753_of_match[] __devinitconst = {
|
||||
{ .compatible = "nvidia,tegra-audio-wm8753", },
|
||||
{},
|
||||
};
|
||||
|
||||
static struct platform_driver tegra_wm8753_driver = {
|
||||
.driver = {
|
||||
.name = DRV_NAME,
|
||||
.owner = THIS_MODULE,
|
||||
.pm = &snd_soc_pm_ops,
|
||||
.of_match_table = tegra_wm8753_of_match,
|
||||
},
|
||||
.probe = tegra_wm8753_driver_probe,
|
||||
.remove = __devexit_p(tegra_wm8753_driver_remove),
|
||||
};
|
||||
module_platform_driver(tegra_wm8753_driver);
|
||||
|
||||
MODULE_AUTHOR("Stephen Warren <swarren@nvidia.com>");
|
||||
MODULE_DESCRIPTION("Tegra+WM8753 machine ASoC driver");
|
||||
MODULE_LICENSE("GPL");
|
||||
MODULE_ALIAS("platform:" DRV_NAME);
|
||||
MODULE_DEVICE_TABLE(of, tegra_wm8753_of_match);
|
Loading…
Reference in New Issue