diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2011-07-23 10:59:37 -0700 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2011-07-23 10:59:37 -0700 |
commit | e4980371059ca4a81ccdcb4381c41af8869ca711 (patch) | |
tree | 29758f7e8d66b5866d9d3897eff12f122000b4d7 /sound/soc/sh/fsi.c | |
parent | 9d1c02135516866cbbb2f80e20cfb65c63a3ce40 (diff) | |
parent | 76531d4166fb620375ff3c1ac24753265216d579 (diff) | |
download | linux-e4980371059ca4a81ccdcb4381c41af8869ca711.tar.bz2 |
Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tiwai/sound-2.6
* 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tiwai/sound-2.6: (297 commits)
ALSA: asihpi - Replace with snd_ctl_boolean_mono_info()
ALSA: asihpi - HPI version 4.08
ALSA: asihpi - Add volume mute controls
ALSA: asihpi - Control name updates
ALSA: asihpi - Use size_t for sizeof result
ALSA: asihpi - Explicitly include mutex.h
ALSA: asihpi - Add new node and message defines
ALSA: asihpi - Make local function static
ALSA: asihpi - Fix minor typos and spelling
ALSA: asihpi - Remove unused structures, macros and functions
ALSA: asihpi - Remove spurious adapter index check
ALSA: asihpi - Revise snd_pcm_debug_name, get rid of DEBUG_NAME macro
ALSA: asihpi - DSP code loader API now independent of OS
ALSA: asihpi - Remove controlex structs and associated special data transfer code
ALSA: asihpi - Increase request and response buffer sizes
ALSA: asihpi - Give more meaningful name to hpi request message type
ALSA: usb-audio - Add quirk for Roland / BOSS BR-800
ALSA: hda - Remove a superfluous argument of via_auto_init_output()
ALSA: hda - Fix indep-HP path (de-)activation for VT1708* codecs
ALSA: hda - Add documentation for codec-specific mixer controls
...
Diffstat (limited to 'sound/soc/sh/fsi.c')
-rw-r--r-- | sound/soc/sh/fsi.c | 582 |
1 files changed, 299 insertions, 283 deletions
diff --git a/sound/soc/sh/fsi.c b/sound/soc/sh/fsi.c index 4a9da6b5f4e1..8e112ccffb13 100644 --- a/sound/soc/sh/fsi.c +++ b/sound/soc/sh/fsi.c @@ -118,10 +118,38 @@ typedef int (*set_rate_func)(struct device *dev, int is_porta, int rate, int ena /* * 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 + * xxx_pos : position of data + * xxx_capa : capacity of data + */ + +/* + * period/frame/sample image + * + * ex) PCM (2ch) + * + * period pos period pos + * [n] [n + 1] + * |<-------------------- period--------------------->| + * ==|============================================ ... =|== + * | | + * ||<----- frame ----->|<------ frame ----->| ... | + * |+--------------------+--------------------+- ... | + * ||[ sample ][ sample ]|[ sample ][ sample ]| ... | + * |+--------------------+--------------------+- ... | + * ==|============================================ ... =|== + */ + +/* + * FSI FIFO image + * + * | | + * | | + * | [ sample ] | + * | [ sample ] | + * | [ sample ] | + * | [ sample ] | + * --> go to codecs */ /* @@ -131,12 +159,11 @@ typedef int (*set_rate_func)(struct device *dev, int is_porta, int rate, int ena struct fsi_stream { struct snd_pcm_substream *substream; - int fifo_max_num; - - int buff_offset; - int buff_len; - int period_len; - int period_num; + int fifo_sample_capa; /* sample capacity of FSI FIFO */ + int buff_sample_capa; /* sample capacity of ALSA buffer */ + int buff_sample_pos; /* sample position of ALSA buffer */ + int period_samples; /* sample number / 1 period */ + int period_pos; /* current period position */ int uerr_num; int oerr_num; @@ -149,17 +176,14 @@ struct fsi_priv { struct fsi_stream playback; struct fsi_stream capture; + u32 do_fmt; + u32 di_fmt; + int chan_num:16; int clk_master:1; + int spdif:1; long rate; - - /* for suspend/resume */ - u32 saved_do_fmt; - u32 saved_di_fmt; - u32 saved_ckg1; - u32 saved_ckg2; - u32 saved_out_sel; }; struct fsi_core { @@ -180,14 +204,6 @@ struct fsi_master { struct fsi_core *core; struct sh_fsi_platform_info *info; spinlock_t lock; - - /* for suspend/resume */ - u32 saved_a_mclk; - u32 saved_b_mclk; - u32 saved_iemsk; - u32 saved_imsk; - u32 saved_clk_rst; - u32 saved_soft_rst; }; /* @@ -271,6 +287,11 @@ static int fsi_is_port_a(struct fsi_priv *fsi) return fsi->master->base == fsi->base; } +static int fsi_is_spdif(struct fsi_priv *fsi) +{ + return fsi->spdif; +} + static struct snd_soc_dai *fsi_get_dai(struct snd_pcm_substream *substream) { struct snd_soc_pcm_runtime *rtd = substream->private_data; @@ -342,28 +363,59 @@ static u32 fsi_get_port_shift(struct fsi_priv *fsi, int is_play) return shift; } +static int fsi_frame2sample(struct fsi_priv *fsi, int frames) +{ + return frames * fsi->chan_num; +} + +static int fsi_sample2frame(struct fsi_priv *fsi, int samples) +{ + return samples / fsi->chan_num; +} + +static int fsi_stream_is_working(struct fsi_priv *fsi, + int is_play) +{ + struct fsi_stream *io = fsi_get_stream(fsi, is_play); + struct fsi_master *master = fsi_get_master(fsi); + unsigned long flags; + int ret; + + spin_lock_irqsave(&master->lock, flags); + ret = !!io->substream; + spin_unlock_irqrestore(&master->lock, flags); + + return ret; +} + static void fsi_stream_push(struct fsi_priv *fsi, int is_play, - struct snd_pcm_substream *substream, - u32 buffer_len, - u32 period_len) + struct snd_pcm_substream *substream) { struct fsi_stream *io = fsi_get_stream(fsi, is_play); + struct snd_pcm_runtime *runtime = substream->runtime; + struct fsi_master *master = fsi_get_master(fsi); + unsigned long flags; + spin_lock_irqsave(&master->lock, flags); io->substream = substream; - io->buff_len = buffer_len; - io->buff_offset = 0; - io->period_len = period_len; - io->period_num = 0; + io->buff_sample_capa = fsi_frame2sample(fsi, runtime->buffer_size); + io->buff_sample_pos = 0; + io->period_samples = fsi_frame2sample(fsi, runtime->period_size); + io->period_pos = 0; io->oerr_num = -1; /* ignore 1st err */ io->uerr_num = -1; /* ignore 1st err */ + spin_unlock_irqrestore(&master->lock, flags); } static void fsi_stream_pop(struct fsi_priv *fsi, int is_play) { struct fsi_stream *io = fsi_get_stream(fsi, is_play); struct snd_soc_dai *dai = fsi_get_dai(io->substream); + struct fsi_master *master = fsi_get_master(fsi); + unsigned long flags; + spin_lock_irqsave(&master->lock, flags); if (io->oerr_num > 0) dev_err(dai->dev, "over_run = %d\n", io->oerr_num); @@ -372,47 +424,27 @@ static void fsi_stream_pop(struct fsi_priv *fsi, int is_play) dev_err(dai->dev, "under_run = %d\n", io->uerr_num); io->substream = NULL; - io->buff_len = 0; - io->buff_offset = 0; - io->period_len = 0; - io->period_num = 0; + io->buff_sample_capa = 0; + io->buff_sample_pos = 0; + io->period_samples = 0; + io->period_pos = 0; io->oerr_num = 0; io->uerr_num = 0; + spin_unlock_irqrestore(&master->lock, flags); } -static int fsi_get_fifo_data_num(struct fsi_priv *fsi, int is_play) +static int fsi_get_current_fifo_samples(struct fsi_priv *fsi, int is_play) { u32 status; - int data_num; + int frames; status = is_play ? fsi_reg_read(fsi, DOFF_ST) : fsi_reg_read(fsi, DIFF_ST); - data_num = 0x1ff & (status >> 8); - data_num *= fsi->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; + frames = 0x1ff & (status >> 8); - return frames_to_bytes(runtime, 1) / fsi->chan_num; + return fsi_frame2sample(fsi, frames); } static void fsi_count_fifo_err(struct fsi_priv *fsi) @@ -444,8 +476,10 @@ 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); + struct snd_pcm_runtime *runtime = io->substream->runtime; - return io->substream->runtime->dma_area + io->buff_offset; + return runtime->dma_area + + samples_to_bytes(runtime, io->buff_sample_pos); } static void fsi_dma_soft_push16(struct fsi_priv *fsi, int num) @@ -559,37 +593,94 @@ static void fsi_spdif_clk_ctrl(struct fsi_priv *fsi, int enable) /* * clock function */ -#define fsi_module_init(m, d) __fsi_module_clk_ctrl(m, d, 1) -#define fsi_module_kill(m, d) __fsi_module_clk_ctrl(m, d, 0) -static void __fsi_module_clk_ctrl(struct fsi_master *master, - struct device *dev, - int enable) +static int fsi_set_master_clk(struct device *dev, struct fsi_priv *fsi, + long rate, int enable) { - pm_runtime_get_sync(dev); + struct fsi_master *master = fsi_get_master(fsi); + set_rate_func set_rate = fsi_get_info_set_rate(master); + int fsi_ver = master->core->ver; + int ret; - if (enable) { - /* enable only SR */ - fsi_master_mask_set(master, SOFT_RST, FSISR, FSISR); - fsi_master_mask_set(master, SOFT_RST, PASR | PBSR, 0); - } else { - /* clear all registers */ - fsi_master_mask_set(master, SOFT_RST, FSISR, 0); + ret = set_rate(dev, fsi_is_port_a(fsi), rate, enable); + if (ret < 0) /* error */ + return ret; + + if (!enable) + return 0; + + if (ret > 0) { + u32 data = 0; + + switch (ret & SH_FSI_ACKMD_MASK) { + default: + /* FALL THROUGH */ + case SH_FSI_ACKMD_512: + data |= (0x0 << 12); + break; + case SH_FSI_ACKMD_256: + data |= (0x1 << 12); + break; + case SH_FSI_ACKMD_128: + data |= (0x2 << 12); + break; + case SH_FSI_ACKMD_64: + data |= (0x3 << 12); + break; + case SH_FSI_ACKMD_32: + if (fsi_ver < 2) + dev_err(dev, "unsupported ACKMD\n"); + else + data |= (0x4 << 12); + break; + } + + switch (ret & SH_FSI_BPFMD_MASK) { + default: + /* FALL THROUGH */ + case SH_FSI_BPFMD_32: + data |= (0x0 << 8); + break; + case SH_FSI_BPFMD_64: + data |= (0x1 << 8); + break; + case SH_FSI_BPFMD_128: + data |= (0x2 << 8); + break; + case SH_FSI_BPFMD_256: + data |= (0x3 << 8); + break; + case SH_FSI_BPFMD_512: + data |= (0x4 << 8); + break; + case SH_FSI_BPFMD_16: + if (fsi_ver < 2) + dev_err(dev, "unsupported ACKMD\n"); + else + data |= (0x7 << 8); + break; + } + + fsi_reg_mask_set(fsi, CKG1, (ACKMD_MASK | BPFMD_MASK) , data); + udelay(10); + ret = 0; } - pm_runtime_put_sync(dev); + return ret; } -#define fsi_port_start(f) __fsi_port_clk_ctrl(f, 1) -#define fsi_port_stop(f) __fsi_port_clk_ctrl(f, 0) -static void __fsi_port_clk_ctrl(struct fsi_priv *fsi, int enable) +#define fsi_port_start(f, i) __fsi_port_clk_ctrl(f, i, 1) +#define fsi_port_stop(f, i) __fsi_port_clk_ctrl(f, i, 0) +static void __fsi_port_clk_ctrl(struct fsi_priv *fsi, int is_play, int enable) { struct fsi_master *master = fsi_get_master(fsi); - u32 soft = fsi_is_port_a(fsi) ? PASR : PBSR; u32 clk = fsi_is_port_a(fsi) ? CRA : CRB; - int is_master = fsi_is_clk_master(fsi); - fsi_master_mask_set(master, SOFT_RST, soft, (enable) ? soft : 0); - if (is_master) + if (enable) + fsi_irq_enable(fsi, is_play); + else + fsi_irq_disable(fsi, is_play); + + if (fsi_is_clk_master(fsi)) fsi_master_mask_set(master, CLK_RST, clk, (enable) ? clk : 0); } @@ -598,18 +689,19 @@ static void __fsi_port_clk_ctrl(struct fsi_priv *fsi, int enable) */ static void fsi_fifo_init(struct fsi_priv *fsi, int is_play, - struct snd_soc_dai *dai) + struct device *dev) { struct fsi_master *master = fsi_get_master(fsi); struct fsi_stream *io = fsi_get_stream(fsi, is_play); u32 shift, i; + int frame_capa; /* get on-chip RAM capacity */ shift = fsi_master_read(master, FIFO_SZ); 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); + frame_capa = 256 << shift; + dev_dbg(dev, "fifo = %d words\n", frame_capa); /* * The maximum number of sample data varies depending @@ -631,9 +723,11 @@ static void fsi_fifo_init(struct fsi_priv *fsi, * 8 channels: 32 ( 32 x 8 = 256) */ for (i = 1; i < fsi->chan_num; i <<= 1) - io->fifo_max_num >>= 1; - dev_dbg(dai->dev, "%d channel %d store\n", - fsi->chan_num, io->fifo_max_num); + frame_capa >>= 1; + dev_dbg(dev, "%d channel %d store\n", + fsi->chan_num, frame_capa); + + io->fifo_sample_capa = fsi_frame2sample(fsi, frame_capa); /* * set interrupt generation factor @@ -654,10 +748,10 @@ static int fsi_fifo_data_ctrl(struct fsi_priv *fsi, int stream) struct snd_pcm_substream *substream = NULL; int is_play = fsi_stream_is_play(stream); struct fsi_stream *io = fsi_get_stream(fsi, is_play); - int data_residue_num; - int data_num; - int data_num_max; - int ch_width; + int sample_residues; + int sample_width; + int samples; + int samples_max; int over_period; void (*fn)(struct fsi_priv *fsi, int size); @@ -673,36 +767,35 @@ static int fsi_fifo_data_ctrl(struct fsi_priv *fsi, int stream) /* FSI FIFO has limit. * So, this driver can not send periods data at a time */ - if (io->buff_offset >= - fsi_num2offset(io->period_num + 1, io->period_len)) { + if (io->buff_sample_pos >= + io->period_samples * (io->period_pos + 1)) { over_period = 1; - io->period_num = (io->period_num + 1) % runtime->periods; + io->period_pos = (io->period_pos + 1) % runtime->periods; - if (0 == io->period_num) - io->buff_offset = 0; + if (0 == io->period_pos) + io->buff_sample_pos = 0; } - /* get 1 channel data width */ - ch_width = fsi_get_frame_width(fsi, is_play); + /* get 1 sample data width */ + sample_width = samples_to_bytes(runtime, 1); - /* get residue data number of alsa */ - data_residue_num = fsi_len2num(io->buff_len - io->buff_offset, - ch_width); + /* get number of residue samples */ + sample_residues = io->buff_sample_capa - io->buff_sample_pos; if (is_play) { /* * for play-back * - * data_num_max : number of FSI fifo free space - * data_num : number of ALSA residue data + * samples_max : number of FSI fifo free samples space + * samples : number of ALSA residue samples */ - data_num_max = io->fifo_max_num * fsi->chan_num; - data_num_max -= fsi_get_fifo_data_num(fsi, is_play); + samples_max = io->fifo_sample_capa; + samples_max -= fsi_get_current_fifo_samples(fsi, is_play); - data_num = data_residue_num; + samples = sample_residues; - switch (ch_width) { + switch (sample_width) { case 2: fn = fsi_dma_soft_push16; break; @@ -716,13 +809,13 @@ static int fsi_fifo_data_ctrl(struct fsi_priv *fsi, int stream) /* * for capture * - * data_num_max : number of ALSA free space - * data_num : number of data in FSI fifo + * samples_max : number of ALSA free samples space + * samples : number of samples in FSI fifo */ - data_num_max = data_residue_num; - data_num = fsi_get_fifo_data_num(fsi, is_play); + samples_max = sample_residues; + samples = fsi_get_current_fifo_samples(fsi, is_play); - switch (ch_width) { + switch (sample_width) { case 2: fn = fsi_dma_soft_pop16; break; @@ -734,12 +827,12 @@ static int fsi_fifo_data_ctrl(struct fsi_priv *fsi, int stream) } } - data_num = min(data_num, data_num_max); + samples = min(samples, samples_max); - fn(fsi, data_num); + fn(fsi, samples); - /* update buff_offset */ - io->buff_offset += fsi_num2offset(data_num, ch_width); + /* update buff_sample_pos */ + io->buff_sample_pos += samples; if (over_period) snd_pcm_period_elapsed(substream); @@ -788,16 +881,20 @@ static irqreturn_t fsi_interrupt(int irq, void *data) * dai ops */ -static int fsi_dai_startup(struct snd_pcm_substream *substream, - struct snd_soc_dai *dai) +static int fsi_hw_startup(struct fsi_priv *fsi, + int is_play, + struct device *dev) { - struct fsi_priv *fsi = fsi_get_priv(substream); u32 flags = fsi_get_info_flags(fsi); - u32 data; - int is_play = fsi_is_play(substream); + u32 data = 0; - pm_runtime_get_sync(dai->dev); + pm_runtime_get_sync(dev); + /* clock setting */ + if (fsi_is_clk_master(fsi)) + data = DIMD | DOMD; + + fsi_reg_mask_set(fsi, CKG1, (DIMD | DOMD), data); /* clock inversion (CKG2) */ data = 0; @@ -812,54 +909,70 @@ static int fsi_dai_startup(struct snd_pcm_substream *substream, 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); + fsi_reg_mask_set(fsi, OUT_SEL, DMMD, DMMD); + } + /* irq clear */ fsi_irq_disable(fsi, is_play); fsi_irq_clear_status(fsi); /* fifo init */ - fsi_fifo_init(fsi, is_play, dai); + fsi_fifo_init(fsi, is_play, dev); return 0; } -static void fsi_dai_shutdown(struct snd_pcm_substream *substream, - struct snd_soc_dai *dai) +static void fsi_hw_shutdown(struct fsi_priv *fsi, + int is_play, + struct device *dev) +{ + if (fsi_is_clk_master(fsi)) + fsi_set_master_clk(dev, fsi, fsi->rate, 0); + + pm_runtime_put_sync(dev); +} + +static int fsi_dai_startup(struct snd_pcm_substream *substream, + struct snd_soc_dai *dai) { struct fsi_priv *fsi = fsi_get_priv(substream); int is_play = fsi_is_play(substream); - struct fsi_master *master = fsi_get_master(fsi); - set_rate_func set_rate = fsi_get_info_set_rate(master); - fsi_irq_disable(fsi, is_play); + return fsi_hw_startup(fsi, is_play, dai->dev); +} - if (fsi_is_clk_master(fsi)) - set_rate(dai->dev, fsi_is_port_a(fsi), fsi->rate, 0); +static void fsi_dai_shutdown(struct snd_pcm_substream *substream, + struct snd_soc_dai *dai) +{ + struct fsi_priv *fsi = fsi_get_priv(substream); + int is_play = fsi_is_play(substream); + fsi_hw_shutdown(fsi, is_play, dai->dev); fsi->rate = 0; - - pm_runtime_put_sync(dai->dev); } static int fsi_dai_trigger(struct snd_pcm_substream *substream, int cmd, struct snd_soc_dai *dai) { struct fsi_priv *fsi = fsi_get_priv(substream); - struct snd_pcm_runtime *runtime = substream->runtime; int is_play = fsi_is_play(substream); int ret = 0; switch (cmd) { case SNDRV_PCM_TRIGGER_START: - fsi_stream_push(fsi, is_play, substream, - frames_to_bytes(runtime, runtime->buffer_size), - frames_to_bytes(runtime, runtime->period_size)); + fsi_stream_push(fsi, is_play, substream); ret = is_play ? fsi_data_push(fsi) : fsi_data_pop(fsi); - fsi_irq_enable(fsi, is_play); - fsi_port_start(fsi); + fsi_port_start(fsi, is_play); break; case SNDRV_PCM_TRIGGER_STOP: - fsi_port_stop(fsi); - fsi_irq_disable(fsi, is_play); + fsi_port_stop(fsi, is_play); fsi_stream_pop(fsi, is_play); break; } @@ -884,8 +997,8 @@ static int fsi_set_fmt_dai(struct fsi_priv *fsi, unsigned int fmt) return -EINVAL; } - fsi_reg_write(fsi, DO_FMT, data); - fsi_reg_write(fsi, DI_FMT, data); + fsi->do_fmt = data; + fsi->di_fmt = data; return 0; } @@ -900,11 +1013,10 @@ static int fsi_set_fmt_spdif(struct fsi_priv *fsi) data = CR_BWS_16 | CR_DTMD_SPDIF_PCM | CR_PCM; fsi->chan_num = 2; - fsi_spdif_clk_ctrl(fsi, 1); - fsi_reg_mask_set(fsi, OUT_SEL, DMMD, DMMD); + fsi->spdif = 1; - fsi_reg_write(fsi, DO_FMT, data); - fsi_reg_write(fsi, DI_FMT, data); + fsi->do_fmt = data; + fsi->di_fmt = data; return 0; } @@ -915,32 +1027,24 @@ static int fsi_dai_set_fmt(struct snd_soc_dai *dai, unsigned int fmt) struct fsi_master *master = fsi_get_master(fsi); set_rate_func set_rate = fsi_get_info_set_rate(master); u32 flags = fsi_get_info_flags(fsi); - u32 data = 0; int ret; - pm_runtime_get_sync(dai->dev); - /* set master/slave audio interface */ switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { case SND_SOC_DAIFMT_CBM_CFM: - data = DIMD | DOMD; fsi->clk_master = 1; break; case SND_SOC_DAIFMT_CBS_CFS: break; default: - ret = -EINVAL; - goto set_fmt_exit; + return -EINVAL; } if (fsi_is_clk_master(fsi) && !set_rate) { dev_err(dai->dev, "platform doesn't have set_rate\n"); - ret = -EINVAL; - goto set_fmt_exit; + return -EINVAL; } - fsi_reg_mask_set(fsi, CKG1, (DIMD | DOMD), data); - /* set format */ switch (flags & SH_FSI_FMT_MASK) { case SH_FSI_FMT_DAI: @@ -953,9 +1057,6 @@ static int fsi_dai_set_fmt(struct snd_soc_dai *dai, unsigned int fmt) ret = -EINVAL; } -set_fmt_exit: - pm_runtime_put_sync(dai->dev); - return ret; } @@ -964,79 +1065,19 @@ static int fsi_dai_hw_params(struct snd_pcm_substream *substream, struct snd_soc_dai *dai) { struct fsi_priv *fsi = fsi_get_priv(substream); - struct fsi_master *master = fsi_get_master(fsi); - set_rate_func set_rate = fsi_get_info_set_rate(master); - int fsi_ver = master->core->ver; long rate = params_rate(params); int ret; if (!fsi_is_clk_master(fsi)) return 0; - ret = set_rate(dai->dev, fsi_is_port_a(fsi), rate, 1); - if (ret < 0) /* error */ + ret = fsi_set_master_clk(dai->dev, fsi, rate, 1); + if (ret < 0) return ret; fsi->rate = rate; - if (ret > 0) { - u32 data = 0; - - switch (ret & SH_FSI_ACKMD_MASK) { - default: - /* FALL THROUGH */ - case SH_FSI_ACKMD_512: - data |= (0x0 << 12); - break; - case SH_FSI_ACKMD_256: - data |= (0x1 << 12); - break; - case SH_FSI_ACKMD_128: - data |= (0x2 << 12); - break; - case SH_FSI_ACKMD_64: - data |= (0x3 << 12); - break; - case SH_FSI_ACKMD_32: - if (fsi_ver < 2) - dev_err(dai->dev, "unsupported ACKMD\n"); - else - data |= (0x4 << 12); - break; - } - - switch (ret & SH_FSI_BPFMD_MASK) { - default: - /* FALL THROUGH */ - case SH_FSI_BPFMD_32: - data |= (0x0 << 8); - break; - case SH_FSI_BPFMD_64: - data |= (0x1 << 8); - break; - case SH_FSI_BPFMD_128: - data |= (0x2 << 8); - break; - case SH_FSI_BPFMD_256: - data |= (0x3 << 8); - break; - case SH_FSI_BPFMD_512: - data |= (0x4 << 8); - break; - case SH_FSI_BPFMD_16: - if (fsi_ver < 2) - dev_err(dai->dev, "unsupported ACKMD\n"); - else - data |= (0x7 << 8); - break; - } - - fsi_reg_mask_set(fsi, CKG1, (ACKMD_MASK | BPFMD_MASK) , data); - udelay(10); - ret = 0; - } return ret; - } static struct snd_soc_dai_ops fsi_dai_ops = { @@ -1097,16 +1138,14 @@ static int fsi_hw_free(struct snd_pcm_substream *substream) static snd_pcm_uframes_t fsi_pointer(struct snd_pcm_substream *substream) { - struct snd_pcm_runtime *runtime = substream->runtime; struct fsi_priv *fsi = fsi_get_priv(substream); struct fsi_stream *io = fsi_get_stream(fsi, fsi_is_play(substream)); - long location; + int samples_pos = io->buff_sample_pos - 1; - location = (io->buff_offset - 1); - if (location < 0) - location = 0; + if (samples_pos < 0) + samples_pos = 0; - return bytes_to_frames(runtime, location); + return fsi_sample2frame(fsi, samples_pos); } static struct snd_pcm_ops fsi_pcm_ops = { @@ -1129,10 +1168,10 @@ static void fsi_pcm_free(struct snd_pcm *pcm) snd_pcm_lib_preallocate_free_for_all(pcm); } -static int fsi_pcm_new(struct snd_card *card, - struct snd_soc_dai *dai, - struct snd_pcm *pcm) +static int fsi_pcm_new(struct snd_soc_pcm_runtime *rtd) { + struct snd_pcm *pcm = rtd->pcm; + /* * dont use SNDRV_DMA_TYPE_DEV, since it will oops the SH kernel * in MMAP mode (i.e. aplay -M) @@ -1246,8 +1285,6 @@ static int fsi_probe(struct platform_device *pdev) pm_runtime_enable(&pdev->dev); dev_set_drvdata(&pdev->dev, master); - fsi_module_init(master, &pdev->dev); - ret = request_irq(irq, &fsi_interrupt, IRQF_DISABLED, id_entry->name, master); if (ret) { @@ -1290,8 +1327,6 @@ static int fsi_remove(struct platform_device *pdev) master = dev_get_drvdata(&pdev->dev); - fsi_module_kill(master, &pdev->dev); - free_irq(master->irq, master); pm_runtime_disable(&pdev->dev); @@ -1305,53 +1340,43 @@ static int fsi_remove(struct platform_device *pdev) } static void __fsi_suspend(struct fsi_priv *fsi, - struct device *dev, - set_rate_func set_rate) + int is_play, + struct device *dev) { - fsi->saved_do_fmt = fsi_reg_read(fsi, DO_FMT); - fsi->saved_di_fmt = fsi_reg_read(fsi, DI_FMT); - fsi->saved_ckg1 = fsi_reg_read(fsi, CKG1); - fsi->saved_ckg2 = fsi_reg_read(fsi, CKG2); - fsi->saved_out_sel = fsi_reg_read(fsi, OUT_SEL); + if (!fsi_stream_is_working(fsi, is_play)) + return; - if (fsi_is_clk_master(fsi)) - set_rate(dev, fsi_is_port_a(fsi), fsi->rate, 0); + fsi_port_stop(fsi, is_play); + fsi_hw_shutdown(fsi, is_play, dev); } static void __fsi_resume(struct fsi_priv *fsi, - struct device *dev, - set_rate_func set_rate) + int is_play, + struct device *dev) { - fsi_reg_write(fsi, DO_FMT, fsi->saved_do_fmt); - fsi_reg_write(fsi, DI_FMT, fsi->saved_di_fmt); - fsi_reg_write(fsi, CKG1, fsi->saved_ckg1); - fsi_reg_write(fsi, CKG2, fsi->saved_ckg2); - fsi_reg_write(fsi, OUT_SEL, fsi->saved_out_sel); + if (!fsi_stream_is_working(fsi, is_play)) + return; + + fsi_hw_startup(fsi, is_play, dev); + + if (fsi_is_clk_master(fsi) && fsi->rate) + fsi_set_master_clk(dev, fsi, fsi->rate, 1); + + fsi_port_start(fsi, is_play); - if (fsi_is_clk_master(fsi)) - set_rate(dev, fsi_is_port_a(fsi), fsi->rate, 1); } static int fsi_suspend(struct device *dev) { struct fsi_master *master = dev_get_drvdata(dev); - set_rate_func set_rate = fsi_get_info_set_rate(master); - - pm_runtime_get_sync(dev); - - __fsi_suspend(&master->fsia, dev, set_rate); - __fsi_suspend(&master->fsib, dev, set_rate); + struct fsi_priv *fsia = &master->fsia; + struct fsi_priv *fsib = &master->fsib; - master->saved_a_mclk = fsi_core_read(master, a_mclk); - master->saved_b_mclk = fsi_core_read(master, b_mclk); - master->saved_iemsk = fsi_core_read(master, iemsk); - master->saved_imsk = fsi_core_read(master, imsk); - master->saved_clk_rst = fsi_master_read(master, CLK_RST); - master->saved_soft_rst = fsi_master_read(master, SOFT_RST); + __fsi_suspend(fsia, 1, dev); + __fsi_suspend(fsia, 0, dev); - fsi_module_kill(master, dev); - - pm_runtime_put_sync(dev); + __fsi_suspend(fsib, 1, dev); + __fsi_suspend(fsib, 0, dev); return 0; } @@ -1359,23 +1384,14 @@ static int fsi_suspend(struct device *dev) static int fsi_resume(struct device *dev) { struct fsi_master *master = dev_get_drvdata(dev); - set_rate_func set_rate = fsi_get_info_set_rate(master); - - pm_runtime_get_sync(dev); - - fsi_module_init(master, dev); + struct fsi_priv *fsia = &master->fsia; + struct fsi_priv *fsib = &master->fsib; - fsi_master_mask_set(master, SOFT_RST, 0xffff, master->saved_soft_rst); - fsi_master_mask_set(master, CLK_RST, 0xffff, master->saved_clk_rst); - fsi_core_mask_set(master, a_mclk, 0xffff, master->saved_a_mclk); - fsi_core_mask_set(master, b_mclk, 0xffff, master->saved_b_mclk); - fsi_core_mask_set(master, iemsk, 0xffff, master->saved_iemsk); - fsi_core_mask_set(master, imsk, 0xffff, master->saved_imsk); + __fsi_resume(fsia, 1, dev); + __fsi_resume(fsia, 0, dev); - __fsi_resume(&master->fsia, dev, set_rate); - __fsi_resume(&master->fsib, dev, set_rate); - - pm_runtime_put_sync(dev); + __fsi_resume(fsib, 1, dev); + __fsi_resume(fsib, 0, dev); return 0; } |