Commit 85e184e4 authored by Takashi Iwai's avatar Takashi Iwai

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.
parents 382e6a85 766812e6
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 @@ ...@@ -21,10 +21,11 @@
/* /*
* flags format * flags format
* *
* 0x000000BA * 0x00000CBA
* *
* A: inversion * A: inversion
* B: format mode * B: format mode
* C: chip specific
*/ */
/* A: clock inversion */ /* A: clock inversion */
...@@ -39,6 +40,9 @@ ...@@ -39,6 +40,9 @@
#define SH_FSI_FMT_DAI (0 << 4) #define SH_FSI_FMT_DAI (0 << 4)
#define SH_FSI_FMT_SPDIF (1 << 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 * set_rate return value
......
...@@ -46,6 +46,7 @@ config SND_SOC_ALL_CODECS ...@@ -46,6 +46,7 @@ config SND_SOC_ALL_CODECS
select SND_SOC_MAX9877 if I2C select SND_SOC_MAX9877 if I2C
select SND_SOC_MC13783 if MFD_MC13XXX select SND_SOC_MC13783 if MFD_MC13XXX
select SND_SOC_ML26124 if I2C select SND_SOC_ML26124 if I2C
select SND_SOC_OMAP_HDMI_CODEC if OMAP4_DSS_HDMI
select SND_SOC_PCM3008 select SND_SOC_PCM3008
select SND_SOC_RT5631 if I2C select SND_SOC_RT5631 if I2C
select SND_SOC_SGTL5000 if I2C select SND_SOC_SGTL5000 if I2C
...@@ -236,6 +237,9 @@ config SND_SOC_MAX98095 ...@@ -236,6 +237,9 @@ config SND_SOC_MAX98095
config SND_SOC_MAX9850 config SND_SOC_MAX9850
tristate tristate
config SND_SOC_OMAP_HDMI_CODEC
tristate
config SND_SOC_PCM3008 config SND_SOC_PCM3008
tristate tristate
......
...@@ -33,6 +33,7 @@ snd-soc-max98095-objs := max98095.o ...@@ -33,6 +33,7 @@ snd-soc-max98095-objs := max98095.o
snd-soc-max9850-objs := max9850.o snd-soc-max9850-objs := max9850.o
snd-soc-mc13783-objs := mc13783.o snd-soc-mc13783-objs := mc13783.o
snd-soc-ml26124-objs := ml26124.o snd-soc-ml26124-objs := ml26124.o
snd-soc-omap-hdmi-codec-objs := omap-hdmi.o
snd-soc-pcm3008-objs := pcm3008.o snd-soc-pcm3008-objs := pcm3008.o
snd-soc-rt5631-objs := rt5631.o snd-soc-rt5631-objs := rt5631.o
snd-soc-sgtl5000-objs := sgtl5000.o snd-soc-sgtl5000-objs := sgtl5000.o
...@@ -143,6 +144,7 @@ obj-$(CONFIG_SND_SOC_MAX98095) += snd-soc-max98095.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_MAX9850) += snd-soc-max9850.o
obj-$(CONFIG_SND_SOC_MC13783) += snd-soc-mc13783.o obj-$(CONFIG_SND_SOC_MC13783) += snd-soc-mc13783.o
obj-$(CONFIG_SND_SOC_ML26124) += snd-soc-ml26124.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_PCM3008) += snd-soc-pcm3008.o
obj-$(CONFIG_SND_SOC_RT5631) += snd-soc-rt5631.o obj-$(CONFIG_SND_SOC_RT5631) += snd-soc-rt5631.o
obj-$(CONFIG_SND_SOC_SGTL5000) += snd-soc-sgtl5000.o obj-$(CONFIG_SND_SOC_SGTL5000) += snd-soc-sgtl5000.o
......
/*
* 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 ...@@ -113,6 +113,7 @@ config SND_OMAP_SOC_OMAP4_HDMI
tristate "SoC Audio support for Texas Instruments OMAP4 HDMI" tristate "SoC Audio support for Texas Instruments OMAP4 HDMI"
depends on SND_OMAP_SOC && OMAP4_DSS_HDMI && OMAP2_DSS && ARCH_OMAP4 depends on SND_OMAP_SOC && OMAP4_DSS_HDMI && OMAP2_DSS && ARCH_OMAP4
select SND_OMAP_SOC_HDMI select SND_OMAP_SOC_HDMI
select SND_SOC_OMAP_HDMI_CODEC
help help
Say Y if you want to add support for SoC HDMI audio on Texas Instruments Say Y if you want to add support for SoC HDMI audio on Texas Instruments
OMAP4 chips OMAP4 chips
......
...@@ -131,6 +131,25 @@ ...@@ -131,6 +131,25 @@
typedef int (*set_rate_func)(struct device *dev, int rate, int enable); 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 * FSI driver use below type name for variable
* *
...@@ -188,6 +207,11 @@ struct fsi_stream { ...@@ -188,6 +207,11 @@ struct fsi_stream {
int uerr_num; int uerr_num;
int oerr_num; int oerr_num;
/*
* bus options
*/
u32 bus_option;
/* /*
* thse are initialized by fsi_handler_init() * thse are initialized by fsi_handler_init()
*/ */
...@@ -211,8 +235,7 @@ struct fsi_priv { ...@@ -211,8 +235,7 @@ struct fsi_priv {
struct fsi_stream playback; struct fsi_stream playback;
struct fsi_stream capture; struct fsi_stream capture;
u32 do_fmt; u32 fmt;
u32 di_fmt;
int chan_num:16; int chan_num:16;
int clk_master:1; int clk_master:1;
...@@ -321,6 +344,10 @@ static void _fsi_master_mask_set(struct fsi_master *master, ...@@ -321,6 +344,10 @@ static void _fsi_master_mask_set(struct fsi_master *master,
/* /*
* basic function * 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) static struct fsi_master *fsi_get_master(struct fsi_priv *fsi)
{ {
...@@ -495,6 +522,7 @@ static void fsi_stream_init(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_samples = fsi_frame2sample(fsi, runtime->period_size);
io->period_pos = 0; io->period_pos = 0;
io->sample_width = samples_to_bytes(runtime, 1); io->sample_width = samples_to_bytes(runtime, 1);
io->bus_option = 0;
io->oerr_num = -1; /* ignore 1st err */ io->oerr_num = -1; /* ignore 1st err */
io->uerr_num = -1; /* ignore 1st err */ io->uerr_num = -1; /* ignore 1st err */
fsi_stream_handler_call(io, init, fsi, io); 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) ...@@ -522,6 +550,7 @@ static void fsi_stream_quit(struct fsi_priv *fsi, struct fsi_stream *io)
io->period_samples = 0; io->period_samples = 0;
io->period_pos = 0; io->period_pos = 0;
io->sample_width = 0; io->sample_width = 0;
io->bus_option = 0;
io->oerr_num = 0; io->oerr_num = 0;
io->uerr_num = 0; io->uerr_num = 0;
spin_unlock_irqrestore(&master->lock, flags); spin_unlock_irqrestore(&master->lock, flags);
...@@ -580,6 +609,53 @@ static int fsi_stream_remove(struct fsi_priv *fsi) ...@@ -580,6 +609,53 @@ static int fsi_stream_remove(struct fsi_priv *fsi)
return 0; 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 * irq function
*/ */
...@@ -629,11 +705,6 @@ static void fsi_spdif_clk_ctrl(struct fsi_priv *fsi, int enable) ...@@ -629,11 +705,6 @@ static void fsi_spdif_clk_ctrl(struct fsi_priv *fsi, int enable)
struct fsi_master *master = fsi_get_master(fsi); struct fsi_master *master = fsi_get_master(fsi);
u32 mask, val; u32 mask, val;
if (master->core->ver < 2) {
pr_err("fsi: register access err (%s)\n", __func__);
return;
}
mask = BP | SE; mask = BP | SE;
val = enable ? mask : 0; val = enable ? mask : 0;
...@@ -648,9 +719,7 @@ static void fsi_spdif_clk_ctrl(struct fsi_priv *fsi, int enable) ...@@ -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, static int fsi_set_master_clk(struct device *dev, struct fsi_priv *fsi,
long rate, int enable) long rate, int enable)
{ {
struct fsi_master *master = fsi_get_master(fsi);
set_rate_func set_rate = fsi_get_info_set_rate(fsi); set_rate_func set_rate = fsi_get_info_set_rate(fsi);
int fsi_ver = master->core->ver;
int ret; int ret;
if (!set_rate) if (!set_rate)
...@@ -682,10 +751,7 @@ static int fsi_set_master_clk(struct device *dev, struct fsi_priv *fsi, ...@@ -682,10 +751,7 @@ static int fsi_set_master_clk(struct device *dev, struct fsi_priv *fsi,
data |= (0x3 << 12); data |= (0x3 << 12);
break; break;
case SH_FSI_ACKMD_32: case SH_FSI_ACKMD_32:
if (fsi_ver < 2) data |= (0x4 << 12);
dev_err(dev, "unsupported ACKMD\n");
else
data |= (0x4 << 12);
break; break;
} }
...@@ -708,10 +774,7 @@ static int fsi_set_master_clk(struct device *dev, struct fsi_priv *fsi, ...@@ -708,10 +774,7 @@ static int fsi_set_master_clk(struct device *dev, struct fsi_priv *fsi,
data |= (0x4 << 8); data |= (0x4 << 8);
break; break;
case SH_FSI_BPFMD_16: case SH_FSI_BPFMD_16:
if (fsi_ver < 2) data |= (0x7 << 8);
dev_err(dev, "unsupported ACKMD\n");
else
data |= (0x7 << 8);
break; break;
} }
...@@ -728,11 +791,26 @@ static int fsi_set_master_clk(struct device *dev, struct fsi_priv *fsi, ...@@ -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) 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; int i;
for (i = 0; i < samples; i++) if (enable_stream) {
fsi_reg_write(fsi, DODT, ((u32)*(buf + i) << 8)); /*
* 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) 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, ...@@ -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); 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 = { static struct fsi_stream_handler fsi_pio_push_handler = {
.init = fsi_pio_push_init,
.transfer = fsi_pio_push, .transfer = fsi_pio_push,
.start_stop = fsi_pio_start_stop, .start_stop = fsi_pio_start_stop,
}; };
static struct fsi_stream_handler fsi_pio_pop_handler = { static struct fsi_stream_handler fsi_pio_pop_handler = {
.init = fsi_pio_pop_init,
.transfer = fsi_pio_pop, .transfer = fsi_pio_pop,
.start_stop = fsi_pio_start_stop, .start_stop = fsi_pio_start_stop,
}; };
...@@ -919,6 +1029,13 @@ static int fsi_dma_init(struct fsi_priv *fsi, struct fsi_stream *io) ...@@ -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) ? enum dma_data_direction dir = fsi_stream_is_play(fsi, io) ?
DMA_TO_DEVICE : DMA_FROM_DEVICE; 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, io->dma = dma_map_single(dai->dev, runtime->dma_area,
snd_pcm_lib_buffer_bytes(io->substream), dir); snd_pcm_lib_buffer_bytes(io->substream), dir);
return 0; return 0;
...@@ -1055,25 +1172,9 @@ static int fsi_dma_transfer(struct fsi_priv *fsi, struct fsi_stream *io) ...@@ -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, static void fsi_dma_push_start_stop(struct fsi_priv *fsi, struct fsi_stream *io,
int start) int start)
{ {
u32 bws; u32 enable = start ? DMA_ON : 0;
u32 dma;
switch (io->sample_width * start) { fsi_reg_mask_set(fsi, OUT_DMAC, DMA_ON, enable);
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);
} }
static int fsi_dma_probe(struct fsi_priv *fsi, struct fsi_stream *io) 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, ...@@ -1176,8 +1277,6 @@ static int fsi_hw_startup(struct fsi_priv *fsi,
struct fsi_stream *io, struct fsi_stream *io,
struct device *dev) 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 flags = fsi_get_info_flags(fsi);
u32 data = 0; u32 data = 0;
...@@ -1200,10 +1299,6 @@ static int fsi_hw_startup(struct fsi_priv *fsi, ...@@ -1200,10 +1299,6 @@ static int fsi_hw_startup(struct fsi_priv *fsi,
fsi_reg_write(fsi, CKG2, data); 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 ? */ /* spdif ? */
if (fsi_is_spdif(fsi)) { if (fsi_is_spdif(fsi)) {
fsi_spdif_clk_ctrl(fsi, 1); fsi_spdif_clk_ctrl(fsi, 1);
...@@ -1211,15 +1306,18 @@ static int fsi_hw_startup(struct fsi_priv *fsi, ...@@ -1211,15 +1306,18 @@ static int fsi_hw_startup(struct fsi_priv *fsi,
} }
/* /*
* FIXME * get bus settings
*
* FSI driver assumed that data package is in-back.
* FSI2 chip can select it.
*/ */
if (fsi_ver >= 2) { data = 0;
fsi_reg_write(fsi, OUT_DMAC, (1 << 4)); switch (io->sample_width) {
fsi_reg_write(fsi, IN_DMAC, (1 << 4)); 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 */ /* irq clear */
fsi_irq_disable(fsi, io); fsi_irq_disable(fsi, io);
...@@ -1243,7 +1341,9 @@ static int fsi_dai_startup(struct snd_pcm_substream *substream, ...@@ -1243,7 +1341,9 @@ static int fsi_dai_startup(struct snd_pcm_substream *substream,
{ {
struct fsi_priv *fsi = fsi_get_priv(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, static void fsi_dai_shutdown(struct snd_pcm_substream *substream,
...@@ -1251,7 +1351,6 @@ 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); struct fsi_priv *fsi = fsi_get_priv(substream);
fsi_hw_shutdown(fsi, dai->dev);
fsi->rate = 0; fsi->rate = 0;
} }
...@@ -1265,11 +1364,13 @@ static int fsi_dai_trigger(struct snd_pcm_substream *substream, int cmd, ...@@ -1265,11 +1364,13 @@ static int fsi_dai_trigger(struct snd_pcm_substream *substream, int cmd,
switch (cmd) { switch (cmd) {
case SNDRV_PCM_TRIGGER_START: case SNDRV_PCM_TRIGGER_START:
fsi_stream_init(fsi, io, substream); fsi_stream_init(fsi, io, substream);
fsi_hw_startup(fsi, io, dai->dev);
ret = fsi_stream_transfer(io); ret = fsi_stream_transfer(io);
if (0 == ret) if (0 == ret)
fsi_stream_start(fsi, io); fsi_stream_start(fsi, io);
break; break;
case SNDRV_PCM_TRIGGER_STOP: case SNDRV_PCM_TRIGGER_STOP:
fsi_hw_shutdown(fsi, dai->dev);
fsi_stream_stop(fsi, io); fsi_stream_stop(fsi, io);
fsi_stream_quit(fsi, io); fsi_stream_quit(fsi, io);
break; break;
...@@ -1280,42 +1381,33 @@ static int fsi_dai_trigger(struct snd_pcm_substream *substream, int cmd, ...@@ -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) static int fsi_set_fmt_dai(struct fsi_priv *fsi, unsigned int fmt)
{ {
u32 data = 0;
switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) { switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
case SND_SOC_DAIFMT_I2S: case SND_SOC_DAIFMT_I2S:
data = CR_I2S; fsi->fmt = CR_I2S;
fsi->chan_num = 2; fsi->chan_num = 2;
break; break;
case SND_SOC_DAIFMT_LEFT_J: case SND_SOC_DAIFMT_LEFT_J:
data = CR_PCM; fsi->fmt = CR_PCM;
fsi->chan_num = 2; fsi->chan_num = 2;
break; break;
default: default:
return -EINVAL; return -EINVAL;
} }
fsi->do_fmt = data;
fsi->di_fmt = data;
return 0; return 0;
} }
static int fsi_set_fmt_spdif(struct fsi_priv *fsi) static int fsi_set_fmt_spdif(struct fsi_priv *fsi)
{ {
struct fsi_master *master = fsi_get_master(fsi); struct fsi_master *master = fsi_get_master(fsi);
u32 data = 0;
if (master->core->ver < 2) if (fsi_version(master) < 2)
return -EINVAL; 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->chan_num = 2;
fsi->spdif = 1; fsi->spdif = 1;
fsi->do_fmt = data;
fsi->di_fmt = data;
return 0; return 0;
} }
......
...@@ -48,6 +48,16 @@ config SND_SOC_TEGRA30_I2S ...@@ -48,6 +48,16 @@ config SND_SOC_TEGRA30_I2S
Tegra30 I2S interface. You will also need to select the individual Tegra30 I2S interface. You will also need to select the individual
machine drivers to support below. 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 config MACH_HAS_SND_SOC_TEGRA_WM8903
bool bool
help help
......
...@@ -16,10 +16,12 @@ obj-$(CONFIG_SND_SOC_TEGRA30_AHUB) += snd-soc-tegra30-ahub.o ...@@ -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 obj-$(CONFIG_SND_SOC_TEGRA30_I2S) += snd-soc-tegra30-i2s.o
# Tegra machine Support # Tegra machine Support
snd-soc-tegra-wm8753-objs := tegra_wm8753.o
snd-soc-tegra-wm8903-objs := tegra_wm8903.o snd-soc-tegra-wm8903-objs := tegra_wm8903.o
snd-soc-tegra-trimslice-objs := trimslice.o snd-soc-tegra-trimslice-objs := trimslice.o
snd-soc-tegra-alc5632-objs := tegra_alc5632.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_WM8903) += snd-soc-tegra-wm8903.o
obj-$(CONFIG_SND_SOC_TEGRA_TRIMSLICE) += snd-soc-tegra-trimslice.o obj-$(CONFIG_SND_SOC_TEGRA_TRIMSLICE) += snd-soc-tegra-trimslice.o
obj-$(CONFIG_SND_SOC_TEGRA_ALC5632) += snd-soc-tegra-alc5632.o obj-$(CONFIG_SND_SOC_TEGRA_ALC5632) += snd-soc-tegra-alc5632.o
/*
* 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);
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment