diff options
Diffstat (limited to 'sound/soc/sh')
-rw-r--r-- | sound/soc/sh/Kconfig | 11 | ||||
-rw-r--r-- | sound/soc/sh/Makefile | 2 | ||||
-rw-r--r-- | sound/soc/sh/dma-sh7760.c | 53 | ||||
-rw-r--r-- | sound/soc/sh/fsi-ak4642.c | 31 | ||||
-rw-r--r-- | sound/soc/sh/fsi-da7210.c | 24 | ||||
-rw-r--r-- | sound/soc/sh/fsi-hdmi.c | 60 | ||||
-rw-r--r-- | sound/soc/sh/fsi.c | 606 | ||||
-rw-r--r-- | sound/soc/sh/hac.c | 46 | ||||
-rw-r--r-- | sound/soc/sh/migor.c | 29 | ||||
-rw-r--r-- | sound/soc/sh/sh7760-ac97.c | 25 | ||||
-rw-r--r-- | sound/soc/sh/siu.h | 6 | ||||
-rw-r--r-- | sound/soc/sh/siu_dai.c | 97 | ||||
-rw-r--r-- | sound/soc/sh/siu_pcm.c | 32 | ||||
-rw-r--r-- | sound/soc/sh/ssi.c | 55 |
14 files changed, 619 insertions, 458 deletions
diff --git a/sound/soc/sh/Kconfig b/sound/soc/sh/Kconfig index 52d7e8ed9c1f..7f0a496e07ce 100644 --- a/sound/soc/sh/Kconfig +++ b/sound/soc/sh/Kconfig @@ -47,7 +47,7 @@ config SND_SH7760_AC97 AC97 unit of the SH7760. config SND_FSI_AK4642 - bool "FSI-AK4642 sound support" + tristate "FSI-AK4642 sound support" depends on SND_SOC_SH4_FSI && I2C_SH_MOBILE select SND_SOC_AK4642 help @@ -55,13 +55,20 @@ config SND_FSI_AK4642 FSI - AK4642 unit config SND_FSI_DA7210 - bool "FSI-DA7210 sound support" + tristate "FSI-DA7210 sound support" depends on SND_SOC_SH4_FSI && I2C_SH_MOBILE select SND_SOC_DA7210 help This option enables generic sound support for the FSI - DA7210 unit +config SND_FSI_HDMI + tristate "FSI-HDMI sound support" + depends on SND_SOC_SH4_FSI && FB_SH_MOBILE_HDMI + help + This option enables generic sound support for the + FSI - HDMI unit + config SND_SIU_MIGOR tristate "SIU sound support on Migo-R" depends on SH_MIGOR diff --git a/sound/soc/sh/Makefile b/sound/soc/sh/Makefile index 8a5a19293bda..94476d4c0fd5 100644 --- a/sound/soc/sh/Makefile +++ b/sound/soc/sh/Makefile @@ -16,9 +16,11 @@ obj-$(CONFIG_SND_SOC_SH4_SIU) += snd-soc-siu.o snd-soc-sh7760-ac97-objs := sh7760-ac97.o snd-soc-fsi-ak4642-objs := fsi-ak4642.o snd-soc-fsi-da7210-objs := fsi-da7210.o +snd-soc-fsi-hdmi-objs := fsi-hdmi.o snd-soc-migor-objs := migor.o obj-$(CONFIG_SND_SH7760_AC97) += snd-soc-sh7760-ac97.o obj-$(CONFIG_SND_FSI_AK4642) += snd-soc-fsi-ak4642.o obj-$(CONFIG_SND_FSI_DA7210) += snd-soc-fsi-da7210.o +obj-$(CONFIG_SND_FSI_HDMI) += snd-soc-fsi-hdmi.o obj-$(CONFIG_SND_SIU_MIGOR) += snd-soc-migor.o diff --git a/sound/soc/sh/dma-sh7760.c b/sound/soc/sh/dma-sh7760.c index 0d8bdf07729c..c326d29992fe 100644 --- a/sound/soc/sh/dma-sh7760.c +++ b/sound/soc/sh/dma-sh7760.c @@ -137,7 +137,7 @@ static void camelot_rxdma(void *data) static int camelot_pcm_open(struct snd_pcm_substream *substream) { struct snd_soc_pcm_runtime *rtd = substream->private_data; - struct camelot_pcm *cam = &cam_pcm_data[rtd->dai->cpu_dai->id]; + struct camelot_pcm *cam = &cam_pcm_data[rtd->cpu_dai->id]; int recv = substream->stream == SNDRV_PCM_STREAM_PLAYBACK ? 0:1; int ret, dmairq; @@ -150,7 +150,7 @@ static int camelot_pcm_open(struct snd_pcm_substream *substream) ret = dmabrg_request_irq(dmairq, camelot_rxdma, cam); if (unlikely(ret)) { pr_debug("audio unit %d irqs already taken!\n", - rtd->dai->cpu_dai->id); + rtd->cpu_dai->id); return -EBUSY; } (void)dmabrg_request_irq(dmairq + 1,camelot_rxdma, cam); @@ -159,7 +159,7 @@ static int camelot_pcm_open(struct snd_pcm_substream *substream) ret = dmabrg_request_irq(dmairq, camelot_txdma, cam); if (unlikely(ret)) { pr_debug("audio unit %d irqs already taken!\n", - rtd->dai->cpu_dai->id); + rtd->cpu_dai->id); return -EBUSY; } (void)dmabrg_request_irq(dmairq + 1, camelot_txdma, cam); @@ -170,7 +170,7 @@ static int camelot_pcm_open(struct snd_pcm_substream *substream) static int camelot_pcm_close(struct snd_pcm_substream *substream) { struct snd_soc_pcm_runtime *rtd = substream->private_data; - struct camelot_pcm *cam = &cam_pcm_data[rtd->dai->cpu_dai->id]; + struct camelot_pcm *cam = &cam_pcm_data[rtd->cpu_dai->id]; int recv = substream->stream == SNDRV_PCM_STREAM_PLAYBACK ? 0:1; int dmairq; @@ -191,7 +191,7 @@ static int camelot_hw_params(struct snd_pcm_substream *substream, struct snd_pcm_hw_params *hw_params) { struct snd_soc_pcm_runtime *rtd = substream->private_data; - struct camelot_pcm *cam = &cam_pcm_data[rtd->dai->cpu_dai->id]; + struct camelot_pcm *cam = &cam_pcm_data[rtd->cpu_dai->id]; int recv = substream->stream == SNDRV_PCM_STREAM_PLAYBACK ? 0:1; int ret; @@ -219,7 +219,7 @@ static int camelot_prepare(struct snd_pcm_substream *substream) { struct snd_pcm_runtime *runtime = substream->runtime; struct snd_soc_pcm_runtime *rtd = substream->private_data; - struct camelot_pcm *cam = &cam_pcm_data[rtd->dai->cpu_dai->id]; + struct camelot_pcm *cam = &cam_pcm_data[rtd->cpu_dai->id]; pr_debug("PCM data: addr 0x%08ulx len %d\n", (u32)runtime->dma_addr, runtime->dma_bytes); @@ -266,7 +266,7 @@ static inline void dmabrg_rec_dma_stop(struct camelot_pcm *cam) static int camelot_trigger(struct snd_pcm_substream *substream, int cmd) { struct snd_soc_pcm_runtime *rtd = substream->private_data; - struct camelot_pcm *cam = &cam_pcm_data[rtd->dai->cpu_dai->id]; + struct camelot_pcm *cam = &cam_pcm_data[rtd->cpu_dai->id]; int recv = substream->stream == SNDRV_PCM_STREAM_PLAYBACK ? 0:1; switch (cmd) { @@ -293,7 +293,7 @@ static snd_pcm_uframes_t camelot_pos(struct snd_pcm_substream *substream) { struct snd_pcm_runtime *runtime = substream->runtime; struct snd_soc_pcm_runtime *rtd = substream->private_data; - struct camelot_pcm *cam = &cam_pcm_data[rtd->dai->cpu_dai->id]; + struct camelot_pcm *cam = &cam_pcm_data[rtd->cpu_dai->id]; int recv = substream->stream == SNDRV_PCM_STREAM_PLAYBACK ? 0:1; unsigned long pos; @@ -342,25 +342,44 @@ static int camelot_pcm_new(struct snd_card *card, return 0; } -struct snd_soc_platform sh7760_soc_platform = { - .name = "sh7760-pcm", +static struct snd_soc_platform sh7760_soc_platform = { .pcm_ops = &camelot_pcm_ops, .pcm_new = camelot_pcm_new, .pcm_free = camelot_pcm_free, }; -EXPORT_SYMBOL_GPL(sh7760_soc_platform); -static int __init sh7760_soc_platform_init(void) +static int __devinit sh7760_soc_platform_probe(struct platform_device *pdev) { - return snd_soc_register_platform(&sh7760_soc_platform); + return snd_soc_register_platform(&pdev->dev, &sh7760_soc_platform); } -module_init(sh7760_soc_platform_init); -static void __exit sh7760_soc_platform_exit(void) +static int __devexit sh7760_soc_platform_remove(struct platform_device *pdev) { - snd_soc_unregister_platform(&sh7760_soc_platform); + snd_soc_unregister_platform(&pdev->dev); + return 0; +} + +static struct platform_driver sh7760_pcm_driver = { + .driver = { + .name = "sh7760-pcm-audio", + .owner = THIS_MODULE, + }, + + .probe = sh7760_soc_platform_probe, + .remove = __devexit_p(sh7760_soc_platform_remove), +}; + +static int __init snd_sh7760_pcm_init(void) +{ + return platform_driver_register(&sh7760_pcm_driver); +} +module_init(snd_sh7760_pcm_init); + +static void __exit snd_sh7760_pcm_exit(void) +{ + platform_driver_unregister(&sh7760_pcm_driver); } -module_exit(sh7760_soc_platform_exit); +module_exit(snd_sh7760_pcm_exit); MODULE_LICENSE("GPL"); MODULE_DESCRIPTION("SH7760 Audio DMA (DMABRG) driver"); diff --git a/sound/soc/sh/fsi-ak4642.c b/sound/soc/sh/fsi-ak4642.c index dad575a22622..d96602de71de 100644 --- a/sound/soc/sh/fsi-ak4642.c +++ b/sound/soc/sh/fsi-ak4642.c @@ -11,17 +11,17 @@ #include <linux/platform_device.h> #include <sound/sh_fsi.h> -#include <../sound/soc/codecs/ak4642.h> -static int fsi_ak4642_dai_init(struct snd_soc_codec *codec) +static int fsi_ak4642_dai_init(struct snd_soc_pcm_runtime *rtd) { + struct snd_soc_dai *dai = rtd->codec_dai; int ret; - ret = snd_soc_dai_set_fmt(&ak4642_dai, SND_SOC_DAIFMT_CBM_CFM); + ret = snd_soc_dai_set_fmt(dai, SND_SOC_DAIFMT_CBM_CFM); if (ret < 0) return ret; - ret = snd_soc_dai_set_sysclk(&ak4642_dai, 0, 11289600, 0); + ret = snd_soc_dai_set_sysclk(dai, 0, 11289600, 0); return ret; } @@ -29,24 +29,25 @@ static int fsi_ak4642_dai_init(struct snd_soc_codec *codec) static struct snd_soc_dai_link fsi_dai_link = { .name = "AK4642", .stream_name = "AK4642", - .cpu_dai = &fsi_soc_dai[FSI_PORT_A], - .codec_dai = &ak4642_dai, + .cpu_dai_name = "fsia-dai", /* fsi A */ + .codec_dai_name = "ak4642-hifi", +#ifdef CONFIG_MACH_AP4EVB + .platform_name = "sh_fsi2", + .codec_name = "ak4642-codec.0-0013", +#else + .platform_name = "sh_fsi.0", + .codec_name = "ak4642-codec.0-0012", +#endif .init = fsi_ak4642_dai_init, .ops = NULL, }; static struct snd_soc_card fsi_soc_card = { - .name = "FSI", - .platform = &fsi_soc_platform, + .name = "FSI (AK4642)", .dai_link = &fsi_dai_link, .num_links = 1, }; -static struct snd_soc_device fsi_snd_devdata = { - .card = &fsi_soc_card, - .codec_dev = &soc_codec_dev_ak4642, -}; - static struct platform_device *fsi_snd_device; static int __init fsi_ak4642_init(void) @@ -57,9 +58,7 @@ static int __init fsi_ak4642_init(void) if (!fsi_snd_device) goto out; - platform_set_drvdata(fsi_snd_device, - &fsi_snd_devdata); - fsi_snd_devdata.dev = &fsi_snd_device->dev; + platform_set_drvdata(fsi_snd_device, &fsi_soc_card); ret = platform_device_add(fsi_snd_device); if (ret) diff --git a/sound/soc/sh/fsi-da7210.c b/sound/soc/sh/fsi-da7210.c index 121bbb07bb03..a6adb6e43250 100644 --- a/sound/soc/sh/fsi-da7210.c +++ b/sound/soc/sh/fsi-da7210.c @@ -12,11 +12,12 @@ #include <linux/platform_device.h> #include <sound/sh_fsi.h> -#include "../codecs/da7210.h" -static int fsi_da7210_init(struct snd_soc_codec *codec) +static int fsi_da7210_init(struct snd_soc_pcm_runtime *rtd) { - return snd_soc_dai_set_fmt(&da7210_dai, + struct snd_soc_dai *dai = rtd->codec_dai; + + return snd_soc_dai_set_fmt(dai, SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBM_CFM); } @@ -24,23 +25,19 @@ static int fsi_da7210_init(struct snd_soc_codec *codec) static struct snd_soc_dai_link fsi_da7210_dai = { .name = "DA7210", .stream_name = "DA7210", - .cpu_dai = &fsi_soc_dai[FSI_PORT_B], - .codec_dai = &da7210_dai, + .cpu_dai_name = "fsib-dai", /* FSI B */ + .codec_dai_name = "da7210-hifi", + .platform_name = "sh_fsi.0", + .codec_name = "da7210-codec.0-001a", .init = fsi_da7210_init, }; static struct snd_soc_card fsi_soc_card = { - .name = "FSI", - .platform = &fsi_soc_platform, + .name = "FSI (DA7210)", .dai_link = &fsi_da7210_dai, .num_links = 1, }; -static struct snd_soc_device fsi_da7210_snd_devdata = { - .card = &fsi_soc_card, - .codec_dev = &soc_codec_dev_da7210, -}; - static struct platform_device *fsi_da7210_snd_device; static int __init fsi_da7210_sound_init(void) @@ -51,8 +48,7 @@ static int __init fsi_da7210_sound_init(void) if (!fsi_da7210_snd_device) return -ENOMEM; - platform_set_drvdata(fsi_da7210_snd_device, &fsi_da7210_snd_devdata); - fsi_da7210_snd_devdata.dev = &fsi_da7210_snd_device->dev; + platform_set_drvdata(fsi_da7210_snd_device, &fsi_soc_card); ret = platform_device_add(fsi_da7210_snd_device); if (ret) platform_device_put(fsi_da7210_snd_device); diff --git a/sound/soc/sh/fsi-hdmi.c b/sound/soc/sh/fsi-hdmi.c new file mode 100644 index 000000000000..a52dd8ec71d3 --- /dev/null +++ b/sound/soc/sh/fsi-hdmi.c @@ -0,0 +1,60 @@ +/* + * FSI - HDMI sound support + * + * Copyright (C) 2010 Renesas Solutions Corp. + * Kuninori Morimoto <kuninori.morimoto.gx@renesas.com> + * + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file "COPYING" in the main directory of this archive + * for more details. + */ + +#include <linux/platform_device.h> +#include <sound/sh_fsi.h> + +static struct snd_soc_dai_link fsi_dai_link = { + .name = "HDMI", + .stream_name = "HDMI", + .cpu_dai_name = "fsib-dai", /* fsi B */ + .codec_dai_name = "sh_mobile_hdmi-hifi", + .platform_name = "sh_fsi2", + .codec_name = "sh-mobile-hdmi", +}; + +static struct snd_soc_card fsi_soc_card = { + .name = "FSI (SH MOBILE HDMI)", + .dai_link = &fsi_dai_link, + .num_links = 1, +}; + +static struct platform_device *fsi_snd_device; + +static int __init fsi_hdmi_init(void) +{ + int ret = -ENOMEM; + + fsi_snd_device = platform_device_alloc("soc-audio", FSI_PORT_B); + if (!fsi_snd_device) + goto out; + + platform_set_drvdata(fsi_snd_device, &fsi_soc_card); + ret = platform_device_add(fsi_snd_device); + + if (ret) + platform_device_put(fsi_snd_device); + +out: + return ret; +} + +static void __exit fsi_hdmi_exit(void) +{ + platform_device_unregister(fsi_snd_device); +} + +module_init(fsi_hdmi_init); +module_exit(fsi_hdmi_exit); + +MODULE_LICENSE("GPL"); +MODULE_DESCRIPTION("Generic SH4 FSI-HDMI sound card"); +MODULE_AUTHOR("Kuninori Morimoto <kuninori.morimoto.gx@renesas.com>"); diff --git a/sound/soc/sh/fsi.c b/sound/soc/sh/fsi.c index 58c6bec642de..507e709f2807 100644 --- a/sound/soc/sh/fsi.c +++ b/sound/soc/sh/fsi.c @@ -80,11 +80,12 @@ #define B_CLK 0x00000010 #define A_CLK 0x00000001 -/* INT_ST */ -#define INT_B_IN (1 << 12) -#define INT_B_OUT (1 << 8) -#define INT_A_IN (1 << 4) -#define INT_A_OUT (1 << 0) +/* IO SHIFT / MACRO */ +#define BI_SHIFT 12 +#define BO_SHIFT 8 +#define AI_SHIFT 4 +#define AO_SHIFT 0 +#define AB_IO(param, shift) (param << shift) /* SOFT_RST */ #define PBSR (1 << 12) /* Port B Software Reset */ @@ -93,33 +94,43 @@ #define FSISR (1 << 0) /* Software Reset */ /* FIFO_SZ */ -#define OUT_SZ_MASK 0x7 -#define BO_SZ_SHIFT 8 -#define AO_SZ_SHIFT 0 +#define FIFO_SZ_MASK 0x7 #define FSI_RATES SNDRV_PCM_RATE_8000_96000 #define FSI_FMTS (SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S16_LE) -/************************************************************************ +/* + * FSI driver use below type name for variable + * + * xxx_len : data length + * xxx_width : data width + * xxx_offset : data offset + * xxx_num : number of data + */ + +/* + * struct + */ +struct fsi_stream { + struct snd_pcm_substream *substream; - struct + int fifo_max_num; + int chan_num; + int buff_offset; + int buff_len; + int period_len; + int period_num; +}; -************************************************************************/ struct fsi_priv { void __iomem *base; - struct snd_pcm_substream *substream; struct fsi_master *master; - int fifo_max; - int chan; - - int byte_offset; - int period_len; - int buffer_len; - int periods; + struct fsi_stream playback; + struct fsi_stream capture; u32 mst_ctrl; }; @@ -142,13 +153,10 @@ struct fsi_master { spinlock_t lock; }; -/************************************************************************ - - - basic read write function - +/* + * basic read write function + */ -************************************************************************/ static void __fsi_reg_write(u32 reg, u32 data) { /* valid data area is 24bit */ @@ -251,13 +259,10 @@ static void fsi_master_mask_set(struct fsi_master *master, spin_unlock_irqrestore(&master->lock, flags); } -/************************************************************************ - - - basic function - +/* + * basic function + */ -************************************************************************/ static struct fsi_master *fsi_get_master(struct fsi_priv *fsi) { return fsi->master; @@ -271,16 +276,19 @@ static int fsi_is_port_a(struct fsi_priv *fsi) static struct snd_soc_dai *fsi_get_dai(struct snd_pcm_substream *substream) { struct snd_soc_pcm_runtime *rtd = substream->private_data; - struct snd_soc_dai_link *machine = rtd->dai; - return machine->cpu_dai; + return rtd->cpu_dai; } static struct fsi_priv *fsi_get_priv(struct snd_pcm_substream *substream) { struct snd_soc_dai *dai = fsi_get_dai(substream); + struct fsi_master *master = snd_soc_dai_get_drvdata(dai); - return dai->private_data; + if (dai->id == 0) + return &master->fsia; + else + return &master->fsib; } static u32 fsi_get_info_flags(struct fsi_priv *fsi) @@ -292,6 +300,22 @@ static u32 fsi_get_info_flags(struct fsi_priv *fsi) master->info->portb_flags; } +static inline int fsi_stream_is_play(int stream) +{ + return stream == SNDRV_PCM_STREAM_PLAYBACK; +} + +static inline int fsi_is_play(struct snd_pcm_substream *substream) +{ + return fsi_stream_is_play(substream->stream); +} + +static inline struct fsi_stream *fsi_get_stream(struct fsi_priv *fsi, + int is_play) +{ + return is_play ? &fsi->playback : &fsi->capture; +} + static int fsi_is_master_mode(struct fsi_priv *fsi, int is_play) { u32 mode; @@ -307,63 +331,144 @@ static int fsi_is_master_mode(struct fsi_priv *fsi, int is_play) return (mode & flags) != mode; } -static u32 fsi_port_ab_io_bit(struct fsi_priv *fsi, int is_play) +static u32 fsi_get_port_shift(struct fsi_priv *fsi, int is_play) { int is_porta = fsi_is_port_a(fsi); - u32 data; + u32 shift; if (is_porta) - data = is_play ? (1 << 0) : (1 << 4); + shift = is_play ? AO_SHIFT : AI_SHIFT; else - data = is_play ? (1 << 8) : (1 << 12); + shift = is_play ? BO_SHIFT : BI_SHIFT; - return data; + return shift; } static void fsi_stream_push(struct fsi_priv *fsi, + int is_play, struct snd_pcm_substream *substream, u32 buffer_len, u32 period_len) { - fsi->substream = substream; - fsi->buffer_len = buffer_len; - fsi->period_len = period_len; - fsi->byte_offset = 0; - fsi->periods = 0; + struct fsi_stream *io = fsi_get_stream(fsi, is_play); + + io->substream = substream; + io->buff_len = buffer_len; + io->buff_offset = 0; + io->period_len = period_len; + io->period_num = 0; } -static void fsi_stream_pop(struct fsi_priv *fsi) +static void fsi_stream_pop(struct fsi_priv *fsi, int is_play) { - fsi->substream = NULL; - fsi->buffer_len = 0; - fsi->period_len = 0; - fsi->byte_offset = 0; - fsi->periods = 0; + struct fsi_stream *io = fsi_get_stream(fsi, is_play); + + io->substream = NULL; + io->buff_len = 0; + io->buff_offset = 0; + io->period_len = 0; + io->period_num = 0; } -static int fsi_get_fifo_residue(struct fsi_priv *fsi, int is_play) +static int fsi_get_fifo_data_num(struct fsi_priv *fsi, int is_play) { u32 status; u32 reg = is_play ? DOFF_ST : DIFF_ST; - int residue; + struct fsi_stream *io = fsi_get_stream(fsi, is_play); + int data_num; status = fsi_reg_read(fsi, reg); - residue = 0x1ff & (status >> 8); - residue *= fsi->chan; + data_num = 0x1ff & (status >> 8); + data_num *= io->chan_num; + + return data_num; +} + +static int fsi_len2num(int len, int width) +{ + return len / width; +} + +#define fsi_num2offset(a, b) fsi_num2len(a, b) +static int fsi_num2len(int num, int width) +{ + return num * width; +} + +static int fsi_get_frame_width(struct fsi_priv *fsi, int is_play) +{ + struct fsi_stream *io = fsi_get_stream(fsi, is_play); + struct snd_pcm_substream *substream = io->substream; + struct snd_pcm_runtime *runtime = substream->runtime; + + return frames_to_bytes(runtime, 1) / io->chan_num; +} + +/* + * dma function + */ + +static u8 *fsi_dma_get_area(struct fsi_priv *fsi, int stream) +{ + int is_play = fsi_stream_is_play(stream); + struct fsi_stream *io = fsi_get_stream(fsi, is_play); + + return io->substream->runtime->dma_area + io->buff_offset; +} + +static void fsi_dma_soft_push16(struct fsi_priv *fsi, int num) +{ + u16 *start; + int i; + + start = (u16 *)fsi_dma_get_area(fsi, SNDRV_PCM_STREAM_PLAYBACK); + + for (i = 0; i < num; i++) + fsi_reg_write(fsi, DODT, ((u32)*(start + i) << 8)); +} + +static void fsi_dma_soft_pop16(struct fsi_priv *fsi, int num) +{ + u16 *start; + int i; - return residue; + start = (u16 *)fsi_dma_get_area(fsi, SNDRV_PCM_STREAM_CAPTURE); + + + for (i = 0; i < num; i++) + *(start + i) = (u16)(fsi_reg_read(fsi, DIDT) >> 8); } -/************************************************************************ +static void fsi_dma_soft_push32(struct fsi_priv *fsi, int num) +{ + u32 *start; + int i; + + start = (u32 *)fsi_dma_get_area(fsi, SNDRV_PCM_STREAM_PLAYBACK); + + + for (i = 0; i < num; i++) + fsi_reg_write(fsi, DODT, *(start + i)); +} +static void fsi_dma_soft_pop32(struct fsi_priv *fsi, int num) +{ + u32 *start; + int i; - irq function + start = (u32 *)fsi_dma_get_area(fsi, SNDRV_PCM_STREAM_CAPTURE); + for (i = 0; i < num; i++) + *(start + i) = fsi_reg_read(fsi, DIDT); +} + +/* + * irq function + */ -************************************************************************/ static void fsi_irq_enable(struct fsi_priv *fsi, int is_play) { - u32 data = fsi_port_ab_io_bit(fsi, is_play); + u32 data = AB_IO(1, fsi_get_port_shift(fsi, is_play)); struct fsi_master *master = fsi_get_master(fsi); fsi_master_mask_set(master, master->core->imsk, data, data); @@ -372,7 +477,7 @@ static void fsi_irq_enable(struct fsi_priv *fsi, int is_play) static void fsi_irq_disable(struct fsi_priv *fsi, int is_play) { - u32 data = fsi_port_ab_io_bit(fsi, is_play); + u32 data = AB_IO(1, fsi_get_port_shift(fsi, is_play)); struct fsi_master *master = fsi_get_master(fsi); fsi_master_mask_set(master, master->core->imsk, data, 0); @@ -394,20 +499,18 @@ static void fsi_irq_clear_status(struct fsi_priv *fsi) u32 data = 0; struct fsi_master *master = fsi_get_master(fsi); - data |= fsi_port_ab_io_bit(fsi, 0); - data |= fsi_port_ab_io_bit(fsi, 1); + data |= AB_IO(1, fsi_get_port_shift(fsi, 0)); + data |= AB_IO(1, fsi_get_port_shift(fsi, 1)); /* clear interrupt factor */ fsi_master_mask_set(master, master->core->int_st, data, 0); } -/************************************************************************ - - - SPDIF master clock function - -These functions are used later FSI2 -************************************************************************/ +/* + * SPDIF master clock function + * + * These functions are used later FSI2 + */ static void fsi_spdif_clk_ctrl(struct fsi_priv *fsi, int enable) { struct fsi_master *master = fsi_get_master(fsi); @@ -424,13 +527,10 @@ static void fsi_spdif_clk_ctrl(struct fsi_priv *fsi, int enable) fsi_master_mask_set(master, fsi->mst_ctrl, val, 0); } -/************************************************************************ - - - ctrl function - +/* + * ctrl function + */ -************************************************************************/ static void fsi_clk_ctrl(struct fsi_priv *fsi, int enable) { u32 val = fsi_is_port_a(fsi) ? (1 << 0) : (1 << 4); @@ -447,14 +547,15 @@ static void fsi_fifo_init(struct fsi_priv *fsi, struct snd_soc_dai *dai) { struct fsi_master *master = fsi_get_master(fsi); + struct fsi_stream *io = fsi_get_stream(fsi, is_play); u32 ctrl, shift, i; /* get on-chip RAM capacity */ shift = fsi_master_read(master, FIFO_SZ); - shift >>= fsi_is_port_a(fsi) ? AO_SZ_SHIFT : BO_SZ_SHIFT; - shift &= OUT_SZ_MASK; - fsi->fifo_max = 256 << shift; - dev_dbg(dai->dev, "fifo = %d words\n", fsi->fifo_max); + shift >>= fsi_get_port_shift(fsi, is_play); + shift &= FIFO_SZ_MASK; + io->fifo_max_num = 256 << shift; + dev_dbg(dai->dev, "fifo = %d words\n", io->fifo_max_num); /* * The maximum number of sample data varies depending @@ -475,9 +576,10 @@ static void fsi_fifo_init(struct fsi_priv *fsi, * 7 channels: 32 ( 32 x 7 = 224) * 8 channels: 32 ( 32 x 8 = 256) */ - for (i = 1; i < fsi->chan; i <<= 1) - fsi->fifo_max >>= 1; - dev_dbg(dai->dev, "%d channel %d store\n", fsi->chan, fsi->fifo_max); + for (i = 1; i < io->chan_num; i <<= 1) + io->fifo_max_num >>= 1; + dev_dbg(dai->dev, "%d channel %d store\n", + io->chan_num, io->fifo_max_num); ctrl = is_play ? DOFF_CTL : DIFF_CTL; @@ -500,84 +602,114 @@ static void fsi_soft_all_reset(struct fsi_master *master) mdelay(10); } -/* playback interrupt */ -static int fsi_data_push(struct fsi_priv *fsi, int startup) +static int fsi_fifo_data_ctrl(struct fsi_priv *fsi, int startup, int stream) { struct snd_pcm_runtime *runtime; struct snd_pcm_substream *substream = NULL; - u32 status; - int send; - int fifo_free; - int width; - u8 *start; - int i, over_period; + int is_play = fsi_stream_is_play(stream); + struct fsi_stream *io = fsi_get_stream(fsi, is_play); + u32 status_reg = is_play ? DOFF_ST : DIFF_ST; + int data_residue_num; + int data_num; + int data_num_max; + int ch_width; + int over_period; + void (*fn)(struct fsi_priv *fsi, int size); if (!fsi || - !fsi->substream || - !fsi->substream->runtime) + !io->substream || + !io->substream->runtime) return -EINVAL; over_period = 0; - substream = fsi->substream; + substream = io->substream; runtime = substream->runtime; /* FSI FIFO has limit. * So, this driver can not send periods data at a time */ - if (fsi->byte_offset >= - fsi->period_len * (fsi->periods + 1)) { + if (io->buff_offset >= + fsi_num2offset(io->period_num + 1, io->period_len)) { over_period = 1; - fsi->periods = (fsi->periods + 1) % runtime->periods; + io->period_num = (io->period_num + 1) % runtime->periods; - if (0 == fsi->periods) - fsi->byte_offset = 0; + if (0 == io->period_num) + io->buff_offset = 0; } /* get 1 channel data width */ - width = frames_to_bytes(runtime, 1) / fsi->chan; - - /* get send size for alsa */ - send = (fsi->buffer_len - fsi->byte_offset) / width; - - /* get FIFO free size */ - fifo_free = (fsi->fifo_max * fsi->chan) - fsi_get_fifo_residue(fsi, 1); - - /* size check */ - if (fifo_free < send) - send = fifo_free; + ch_width = fsi_get_frame_width(fsi, is_play); + + /* get residue data number of alsa */ + data_residue_num = fsi_len2num(io->buff_len - io->buff_offset, + ch_width); + + if (is_play) { + /* + * for play-back + * + * data_num_max : number of FSI fifo free space + * data_num : number of ALSA residue data + */ + data_num_max = io->fifo_max_num * io->chan_num; + data_num_max -= fsi_get_fifo_data_num(fsi, is_play); + + data_num = data_residue_num; + + switch (ch_width) { + case 2: + fn = fsi_dma_soft_push16; + break; + case 4: + fn = fsi_dma_soft_push32; + break; + default: + return -EINVAL; + } + } else { + /* + * for capture + * + * data_num_max : number of ALSA free space + * data_num : number of data in FSI fifo + */ + data_num_max = data_residue_num; + data_num = fsi_get_fifo_data_num(fsi, is_play); + + switch (ch_width) { + case 2: + fn = fsi_dma_soft_pop16; + break; + case 4: + fn = fsi_dma_soft_pop32; + break; + default: + return -EINVAL; + } + } - start = runtime->dma_area; - start += fsi->byte_offset; + data_num = min(data_num, data_num_max); - switch (width) { - case 2: - for (i = 0; i < send; i++) - fsi_reg_write(fsi, DODT, - ((u32)*((u16 *)start + i) << 8)); - break; - case 4: - for (i = 0; i < send; i++) - fsi_reg_write(fsi, DODT, *((u32 *)start + i)); - break; - default: - return -EINVAL; - } + fn(fsi, data_num); - fsi->byte_offset += send * width; + /* update buff_offset */ + io->buff_offset += fsi_num2offset(data_num, ch_width); - status = fsi_reg_read(fsi, DOFF_ST); + /* check fifo status */ if (!startup) { struct snd_soc_dai *dai = fsi_get_dai(substream); + u32 status = fsi_reg_read(fsi, status_reg); if (status & ERR_OVER) dev_err(dai->dev, "over run\n"); if (status & ERR_UNDER) dev_err(dai->dev, "under run\n"); } - fsi_reg_write(fsi, DOFF_ST, 0); + fsi_reg_write(fsi, status_reg, 0); - fsi_irq_enable(fsi, 1); + /* re-enable irq */ + fsi_irq_enable(fsi, is_play); if (over_period) snd_pcm_period_elapsed(substream); @@ -587,85 +719,12 @@ static int fsi_data_push(struct fsi_priv *fsi, int startup) static int fsi_data_pop(struct fsi_priv *fsi, int startup) { - struct snd_pcm_runtime *runtime; - struct snd_pcm_substream *substream = NULL; - u32 status; - int free; - int fifo_fill; - int width; - u8 *start; - int i, over_period; - - if (!fsi || - !fsi->substream || - !fsi->substream->runtime) - return -EINVAL; - - over_period = 0; - substream = fsi->substream; - runtime = substream->runtime; - - /* FSI FIFO has limit. - * So, this driver can not send periods data at a time - */ - if (fsi->byte_offset >= - fsi->period_len * (fsi->periods + 1)) { - - over_period = 1; - fsi->periods = (fsi->periods + 1) % runtime->periods; - - if (0 == fsi->periods) - fsi->byte_offset = 0; - } - - /* get 1 channel data width */ - width = frames_to_bytes(runtime, 1) / fsi->chan; - - /* get free space for alsa */ - free = (fsi->buffer_len - fsi->byte_offset) / width; - - /* get recv size */ - fifo_fill = fsi_get_fifo_residue(fsi, 0); - - if (free < fifo_fill) - fifo_fill = free; - - start = runtime->dma_area; - start += fsi->byte_offset; - - switch (width) { - case 2: - for (i = 0; i < fifo_fill; i++) - *((u16 *)start + i) = - (u16)(fsi_reg_read(fsi, DIDT) >> 8); - break; - case 4: - for (i = 0; i < fifo_fill; i++) - *((u32 *)start + i) = fsi_reg_read(fsi, DIDT); - break; - default: - return -EINVAL; - } - - fsi->byte_offset += fifo_fill * width; - - status = fsi_reg_read(fsi, DIFF_ST); - if (!startup) { - struct snd_soc_dai *dai = fsi_get_dai(substream); - - if (status & ERR_OVER) - dev_err(dai->dev, "over run\n"); - if (status & ERR_UNDER) - dev_err(dai->dev, "under run\n"); - } - fsi_reg_write(fsi, DIFF_ST, 0); - - fsi_irq_enable(fsi, 0); - - if (over_period) - snd_pcm_period_elapsed(substream); + return fsi_fifo_data_ctrl(fsi, startup, SNDRV_PCM_STREAM_CAPTURE); +} - return 0; +static int fsi_data_push(struct fsi_priv *fsi, int startup) +{ + return fsi_fifo_data_ctrl(fsi, startup, SNDRV_PCM_STREAM_PLAYBACK); } |