| From bb1acd92639a1c3dae57bbc1d457fba98f084a6d Mon Sep 17 00:00:00 2001 |
| From: Kuninori Morimoto <kuninori.morimoto.gx@renesas.com> |
| Date: Fri, 3 Feb 2012 00:55:55 -0800 |
| Subject: ASoC: fsi: add fsi_stream_handler and PIO handler |
| |
| This patch adds struct fsi_stream_handler and defined fsi_pio_push/pop_handler. |
| these are controled by fsi_steam_xxx() function. |
| |
| Signed-off-by: Kuninori Morimoto <kuninori.morimoto.gx@renesas.com> |
| Signed-off-by: Mark Brown <broonie@opensource.wolfsonmicro.com> |
| (cherry picked from commit 5e97313ac483f03a9af661aada356980fe310e0d) |
| |
| Signed-off-by: Simon Horman <horms@verge.net.au> |
| --- |
| sound/soc/sh/fsi.c | 133 +++++++++++++++++++++++++++++++++++++++++++++++------ |
| 1 file changed, 118 insertions(+), 15 deletions(-) |
| |
| diff --git a/sound/soc/sh/fsi.c b/sound/soc/sh/fsi.c |
| index 24dbe16..b02886a 100644 |
| --- a/sound/soc/sh/fsi.c |
| +++ b/sound/soc/sh/fsi.c |
| @@ -159,18 +159,27 @@ typedef int (*set_rate_func)(struct device *dev, int is_porta, int rate, int ena |
| * struct |
| */ |
| |
| +struct fsi_stream_handler; |
| struct fsi_stream { |
| - struct snd_pcm_substream *substream; |
| |
| + /* |
| + * these are initialized by fsi_stream_init() |
| + */ |
| + struct snd_pcm_substream *substream; |
| 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 sample_width; /* sample width */ |
| - |
| int uerr_num; |
| int oerr_num; |
| + |
| + /* |
| + * thse are initialized by fsi_handler_init() |
| + */ |
| + struct fsi_stream_handler *handler; |
| + struct fsi_priv *priv; |
| }; |
| |
| struct fsi_priv { |
| @@ -190,6 +199,16 @@ struct fsi_priv { |
| long rate; |
| }; |
| |
| +struct fsi_stream_handler { |
| + int (*probe)(struct fsi_priv *fsi, struct fsi_stream *io); |
| + int (*transfer)(struct fsi_priv *fsi, struct fsi_stream *io); |
| + int (*remove)(struct fsi_priv *fsi, struct fsi_stream *io); |
| +}; |
| +#define fsi_stream_handler_call(io, func, args...) \ |
| + (!(io) ? -ENODEV : \ |
| + !((io)->handler->func) ? 0 : \ |
| + (io)->handler->func(args)) |
| + |
| struct fsi_core { |
| int ver; |
| |
| @@ -435,6 +454,11 @@ static int fsi_stream_is_working(struct fsi_priv *fsi, |
| return ret; |
| } |
| |
| +static struct fsi_priv *fsi_stream_to_priv(struct fsi_stream *io) |
| +{ |
| + return io->priv; |
| +} |
| + |
| static void fsi_stream_init(struct fsi_priv *fsi, |
| int is_play, |
| struct snd_pcm_substream *substream) |
| @@ -482,6 +506,53 @@ static void fsi_stream_quit(struct fsi_priv *fsi, int is_play) |
| spin_unlock_irqrestore(&master->lock, flags); |
| } |
| |
| +static int fsi_stream_transfer(struct fsi_stream *io) |
| +{ |
| + struct fsi_priv *fsi = fsi_stream_to_priv(io); |
| + if (!fsi) |
| + return -EIO; |
| + |
| + return fsi_stream_handler_call(io, transfer, fsi, io); |
| +} |
| + |
| +static int fsi_stream_probe(struct fsi_priv *fsi) |
| +{ |
| + struct fsi_stream *io; |
| + int ret1, ret2; |
| + |
| + io = &fsi->playback; |
| + ret1 = fsi_stream_handler_call(io, probe, fsi, io); |
| + |
| + io = &fsi->capture; |
| + ret2 = fsi_stream_handler_call(io, probe, fsi, io); |
| + |
| + if (ret1 < 0) |
| + return ret1; |
| + if (ret2 < 0) |
| + return ret2; |
| + |
| + return 0; |
| +} |
| + |
| +static int fsi_stream_remove(struct fsi_priv *fsi) |
| +{ |
| + struct fsi_stream *io; |
| + int ret1, ret2; |
| + |
| + io = &fsi->playback; |
| + ret1 = fsi_stream_handler_call(io, remove, fsi, io); |
| + |
| + io = &fsi->capture; |
| + ret2 = fsi_stream_handler_call(io, remove, fsi, io); |
| + |
| + if (ret1 < 0) |
| + return ret1; |
| + if (ret2 < 0) |
| + return ret2; |
| + |
| + return 0; |
| +} |
| + |
| /* |
| * pio function |
| */ |
| @@ -743,13 +814,11 @@ static int fsi_fifo_data_ctrl(struct fsi_priv *fsi, struct fsi_stream *io, |
| return 0; |
| } |
| |
| -static int fsi_data_pop(struct fsi_priv *fsi) |
| +static int fsi_pio_pop(struct fsi_priv *fsi, struct fsi_stream *io) |
| { |
| - int is_play = 0; |
| int sample_residues; /* samples in FSI fifo */ |
| int sample_space; /* ALSA free samples space */ |
| int samples; |
| - struct fsi_stream *io = fsi_stream_get(fsi, is_play); |
| |
| sample_residues = fsi_get_current_fifo_samples(fsi, io); |
| sample_space = io->buff_sample_capa - io->buff_sample_pos; |
| @@ -762,13 +831,11 @@ static int fsi_data_pop(struct fsi_priv *fsi) |
| samples); |
| } |
| |
| -static int fsi_data_push(struct fsi_priv *fsi) |
| +static int fsi_pio_push(struct fsi_priv *fsi, struct fsi_stream *io) |
| { |
| - int is_play = 1; |
| int sample_residues; /* ALSA residue samples */ |
| int sample_space; /* FSI fifo free samples space */ |
| int samples; |
| - struct fsi_stream *io = fsi_stream_get(fsi, is_play); |
| |
| sample_residues = io->buff_sample_capa - io->buff_sample_pos; |
| sample_space = io->fifo_sample_capa - |
| @@ -782,6 +849,14 @@ static int fsi_data_push(struct fsi_priv *fsi) |
| samples); |
| } |
| |
| +static struct fsi_stream_handler fsi_pio_push_handler = { |
| + .transfer = fsi_pio_push, |
| +}; |
| + |
| +static struct fsi_stream_handler fsi_pio_pop_handler = { |
| + .transfer = fsi_pio_pop, |
| +}; |
| + |
| static irqreturn_t fsi_interrupt(int irq, void *data) |
| { |
| struct fsi_master *master = data; |
| @@ -792,13 +867,13 @@ static irqreturn_t fsi_interrupt(int irq, void *data) |
| fsi_master_mask_set(master, SOFT_RST, IR, IR); |
| |
| if (int_st & AB_IO(1, AO_SHIFT)) |
| - fsi_data_push(&master->fsia); |
| + fsi_stream_transfer(&master->fsia.playback); |
| if (int_st & AB_IO(1, BO_SHIFT)) |
| - fsi_data_push(&master->fsib); |
| + fsi_stream_transfer(&master->fsib.playback); |
| if (int_st & AB_IO(1, AI_SHIFT)) |
| - fsi_data_pop(&master->fsia); |
| + fsi_stream_transfer(&master->fsia.capture); |
| if (int_st & AB_IO(1, BI_SHIFT)) |
| - fsi_data_pop(&master->fsib); |
| + fsi_stream_transfer(&master->fsib.capture); |
| |
| fsi_count_fifo_err(&master->fsia); |
| fsi_count_fifo_err(&master->fsib); |
| @@ -955,14 +1030,16 @@ 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 fsi_stream *io = fsi_stream_get(fsi, fsi_is_play(substream)); |
| int is_play = fsi_is_play(substream); |
| int ret = 0; |
| |
| switch (cmd) { |
| case SNDRV_PCM_TRIGGER_START: |
| fsi_stream_init(fsi, is_play, substream); |
| - ret = is_play ? fsi_data_push(fsi) : fsi_data_pop(fsi); |
| - fsi_port_start(fsi, is_play); |
| + ret = fsi_stream_transfer(io); |
| + if (0 == ret) |
| + fsi_port_start(fsi, is_play); |
| break; |
| case SNDRV_PCM_TRIGGER_STOP: |
| fsi_port_stop(fsi, is_play); |
| @@ -1224,6 +1301,13 @@ static struct snd_soc_platform_driver fsi_soc_platform = { |
| /* |
| * platform function |
| */ |
| +static void fsi_handler_init(struct fsi_priv *fsi) |
| +{ |
| + fsi->playback.handler = &fsi_pio_push_handler; /* default PIO */ |
| + fsi->playback.priv = fsi; |
| + fsi->capture.handler = &fsi_pio_pop_handler; /* default PIO */ |
| + fsi->capture.priv = fsi; |
| +} |
| |
| static int fsi_probe(struct platform_device *pdev) |
| { |
| @@ -1270,10 +1354,22 @@ static int fsi_probe(struct platform_device *pdev) |
| /* FSI A setting */ |
| master->fsia.base = master->base; |
| master->fsia.master = master; |
| + fsi_handler_init(&master->fsia); |
| + ret = fsi_stream_probe(&master->fsia); |
| + if (ret < 0) { |
| + dev_err(&pdev->dev, "FSIA stream probe failed\n"); |
| + goto exit_iounmap; |
| + } |
| |
| /* FSI B setting */ |
| master->fsib.base = master->base + 0x40; |
| master->fsib.master = master; |
| + fsi_handler_init(&master->fsib); |
| + ret = fsi_stream_probe(&master->fsib); |
| + if (ret < 0) { |
| + dev_err(&pdev->dev, "FSIB stream probe failed\n"); |
| + goto exit_fsia; |
| + } |
| |
| pm_runtime_enable(&pdev->dev); |
| dev_set_drvdata(&pdev->dev, master); |
| @@ -1282,7 +1378,7 @@ static int fsi_probe(struct platform_device *pdev) |
| id_entry->name, master); |
| if (ret) { |
| dev_err(&pdev->dev, "irq request err\n"); |
| - goto exit_iounmap; |
| + goto exit_fsib; |
| } |
| |
| ret = snd_soc_register_platform(&pdev->dev, &fsi_soc_platform); |
| @@ -1304,6 +1400,10 @@ exit_snd_soc: |
| snd_soc_unregister_platform(&pdev->dev); |
| exit_free_irq: |
| free_irq(irq, master); |
| +exit_fsib: |
| + fsi_stream_remove(&master->fsib); |
| +exit_fsia: |
| + fsi_stream_remove(&master->fsia); |
| exit_iounmap: |
| iounmap(master->base); |
| pm_runtime_disable(&pdev->dev); |
| @@ -1326,6 +1426,9 @@ static int fsi_remove(struct platform_device *pdev) |
| snd_soc_unregister_dais(&pdev->dev, ARRAY_SIZE(fsi_soc_dai)); |
| snd_soc_unregister_platform(&pdev->dev); |
| |
| + fsi_stream_remove(&master->fsia); |
| + fsi_stream_remove(&master->fsib); |
| + |
| iounmap(master->base); |
| kfree(master); |
| |
| -- |
| 1.7.10.2.565.gbd578b5 |
| |