diff options
author | Vinod G <vinodg@nvidia.com> | 2011-04-13 14:33:49 -0700 |
---|---|---|
committer | Dan Willemsen <dwillemsen@nvidia.com> | 2011-04-26 15:55:51 -0700 |
commit | eee725de1119955fa792c8542b63a0d619745744 (patch) | |
tree | 579dc1656eb2a8aa69ce4070c89981b24e49917d | |
parent | 409af048b6e333588b022338cce6acdeb7c25f68 (diff) |
arm: tegra: suspend/resume calls to audioswitch
added suspend/resume calls to audioswitch and i2s code
is using those calls.
Original-Change-Id: I475f43b67feeab61f1a3fd84f446ba5c4e126f87
Reviewed-on: http://git-master/r/27697
Reviewed-by: Vinod Gopalakrishnakurup <vinodg@nvidia.com>
Tested-by: Vinod Gopalakrishnakurup <vinodg@nvidia.com>
Reviewed-by: Scott Peterson <speterson@nvidia.com>
Change-Id: Ie01d6d20c24902a42461bcdb42d9bef57c7cc63b
-rw-r--r-- | arch/arm/mach-tegra/audio_switch.c | 177 | ||||
-rw-r--r-- | arch/arm/mach-tegra/include/mach/audio_switch.h | 6 | ||||
-rw-r--r-- | arch/arm/mach-tegra/tegra3_i2s.c | 11 |
3 files changed, 159 insertions, 35 deletions
diff --git a/arch/arm/mach-tegra/audio_switch.c b/arch/arm/mach-tegra/audio_switch.c index b7ea079f86f9..07343be0f09e 100644 --- a/arch/arm/mach-tegra/audio_switch.c +++ b/arch/arm/mach-tegra/audio_switch.c @@ -150,6 +150,8 @@ #define APBIF_SPDIF_INT_SET_0 0x100 #define APBIF_APBIF_INT_SET_0 0x104 +#define APBIF_CHANNEL_MAXINDEX \ + ((APBIF_CHANNEL1_CTRL_0 - APBIF_CHANNEL0_CTRL_0) >> 2) /* * APBIF Channel Control * Generic for all 4 apbif channels @@ -222,6 +224,7 @@ struct apbif_channel_info { bool fifo_inuse[AUDIO_FIFO_CNT]; int fifo_req[AUDIO_FIFO_CNT]; int fifo_refcnt[AUDIO_FIFO_CNT]; + int reg_cache[APBIF_CHANNEL_MAXINDEX]; }; /* audio switch controller */ @@ -229,14 +232,21 @@ struct tegra_audiocont_info { struct clk *apbif_clk; struct clk *audiohub_clk; int refcnt; + int clk_refcnt; }; static struct tegra_audiocont_info *acinfo = NULL; -static int enable_audioswitch = 0; +static bool enable_audioswitch = false; static struct apbif_channel_info apbif_channels[NR_APBIF_CHANNELS]; -static void *ahub_reg_base[ahubrx_maxnum]; +struct tegra_ahub_info { + u32 regbase; + int regcache; +}; + +struct tegra_ahub_info ahub_reginfo[ahubrx_maxnum]; + static inline void audio_switch_writel(u32 reg, u32 val) { @@ -254,16 +264,15 @@ static inline u32 audio_switch_readl(u32 reg) void audio_switch_dump_registers(int ifc) { int i = 0; - check_apbif_ifc(ifc); pr_info("%s: \n",__func__); for (i = 0; i < ahubrx_maxnum; i++) - audio_switch_readl((u32)ahub_reg_base[i]); + audio_switch_readl(ahub_reginfo[i].regbase); } void audio_switch_set_rx_port(int rxport, int txport) { /*Get audioswitch base address*/ - audio_switch_writel((u32)ahub_reg_base[rxport], (1 << txport)); + audio_switch_writel(ahub_reginfo[rxport].regbase, (1 << txport)); } int audio_switch_get_rx_port(int rxport) @@ -272,6 +281,24 @@ int audio_switch_get_rx_port(int rxport) return audio_switch_readl(rxport); } +void ahub_save_registers(void) +{ + int i = 0; + + for (i = 0; i < ahubrx_maxnum; i++) + ahub_reginfo[i].regcache = audio_switch_readl( + ahub_reginfo[i].regbase); +} + +void ahub_restore_registers(void) +{ + int i = 0; + + for (i = 0; i < ahubrx_maxnum; i++) + audio_switch_writel(ahub_reginfo[i].regbase, + ahub_reginfo[i].regcache); +} + /* audiocif control */ void audio_switch_set_acif(int addr, struct audio_cif *cifInfo) { @@ -373,6 +400,24 @@ void apbif_dump_registers(int ifc) apbif_readl(0, APBIF_APBIF_INT_SET_0); } +void apbif_save_registers(int ifc) +{ + int i = 0; + struct apbif_channel_info *ch = &apbif_channels[ifc]; + + for(i = 0; i < APBIF_CHANNEL_MAXINDEX; i++) + ch->reg_cache[i] = apbif_readl(ifc, (i << 2)); +} + +void apbif_restore_registers(int ifc) +{ + int i = 0; + struct apbif_channel_info *ch = &apbif_channels[ifc]; + + for(i = 0; i < APBIF_CHANNEL_MAXINDEX; i++) + apbif_writel(ifc, ch->reg_cache[i], (i << 2)); +} + int audio_apbif_free_channel(int ifc, int fifo_mode) { struct apbif_channel_info *ch = 0; @@ -637,19 +682,38 @@ int apbif_get_channel(int regindex, int fifo_mode) return get_apbif_channel(regindex, fifo_mode); } -static void apbif_disable_clock(void) +void audio_switch_disable_clock(void) { if (!acinfo) return; - if (acinfo->audiohub_clk) - clk_disable(acinfo->audiohub_clk); + if (acinfo->clk_refcnt > 0) { + acinfo->clk_refcnt--; - if (acinfo->apbif_clk) - clk_disable(acinfo->apbif_clk); + if (acinfo->clk_refcnt == 0) { + if (acinfo->audiohub_clk) + clk_disable(acinfo->audiohub_clk); + if (acinfo->apbif_clk) + clk_disable(acinfo->apbif_clk); + } + } + AHUB_DEBUG_PRINT(" %s clk cnt %d \n",__func__, acinfo->clk_refcnt); } -static int apbif_enable_clock(void) + +int audio_switch_set_clock_rate(int rate) +{ + /* FIXME: to complete */ + return 0; +} + +int audio_switch_set_clock_parent(int parent) +{ + /* FIXME: to complete */ + return 0; +} + +int audio_switch_enable_clock(void) { int err = 0; @@ -657,23 +721,27 @@ static int apbif_enable_clock(void) if (!acinfo) return -EIO; - /*apbif clocks */ - if (clk_enable(acinfo->apbif_clk)) { - err = PTR_ERR(acinfo->apbif_clk); - goto fail_audio_clock; - } + if (!acinfo->clk_refcnt) { + /*apbif clocks */ + if (clk_enable(acinfo->apbif_clk)) { + err = PTR_ERR(acinfo->apbif_clk); + goto fail_audio_clock; + } - /* audio hub */ - if (clk_enable(acinfo->audiohub_clk)) { - err = PTR_ERR(acinfo->audiohub_clk); - goto fail_audio_clock; + /* audio hub */ + if (clk_enable(acinfo->audiohub_clk)) { + err = PTR_ERR(acinfo->audiohub_clk); + goto fail_audio_clock; + } } + acinfo->clk_refcnt++; + AHUB_DEBUG_PRINT(" %s clk cnt %d \n",__func__, acinfo->clk_refcnt); return err; fail_audio_clock: - apbif_disable_clock(); + audio_switch_disable_clock(); return err; } @@ -699,8 +767,43 @@ int audio_apbif_set_acif(int ifc, int fifo_mode, struct audio_cif *cifInfo) return 0; } -int apbif_initialize(int ifc, struct audio_cif *cifInfo) +int audio_switch_suspend(void) +{ + int i = 0; + struct apbif_channel_info *ch; + + ahub_save_registers(); + + for (i = 0; i < NR_APBIF_CHANNELS; i++) { + ch = &apbif_channels[i]; + + if ((ch->fifo_inuse[AUDIO_TX_MODE] == true) || + (ch->fifo_inuse[AUDIO_RX_MODE] == true)) { + apbif_save_registers(i); + } + } + + audio_switch_disable_clock(); + return 0; +} + +int audio_switch_resume(void) { + int i = 0; + struct apbif_channel_info *ch; + + audio_switch_enable_clock(); + ahub_restore_registers(); + + for (i = 0; i < NR_APBIF_CHANNELS; i++) { + ch = &apbif_channels[i]; + + if ((ch->fifo_inuse[AUDIO_TX_MODE] == true) || + (ch->fifo_inuse[AUDIO_RX_MODE] == true)) { + apbif_restore_registers(i); + } + } + return 0; } @@ -711,7 +814,7 @@ int audio_switch_open(void) AHUB_DEBUG_PRINT(" audio_switch_open acinfo 0x%x enable %d ++ \n", (unsigned int)acinfo, enable_audioswitch); - if (!acinfo && !enable_audioswitch) { + if (!acinfo && (enable_audioswitch == false)) { struct apbif_channel_info *ch; acinfo = @@ -747,19 +850,22 @@ int audio_switch_open(void) /*FIXME: add interface to set the audiohub rate and parent */ for (i = 0; i < ahubrx_maxnum; i++) { - ahub_reg_base[i] = IO_ADDRESS(TEGRA_AHUB_BASE) + + ahub_reginfo[i].regbase = + (u32)IO_ADDRESS(TEGRA_AHUB_BASE) + (i * AUDIO_APBIF_RX_OFFSET); } - err = apbif_enable_clock(); + /* FIXME: remove the clock enable, once the spdif stuff + is merged */ + err = audio_switch_enable_clock(); if (err) goto fail_audio_open; - enable_audioswitch = 1; + enable_audioswitch = true; } - acinfo->refcnt += 1; + acinfo->refcnt++; AHUB_DEBUG_PRINT(" audio_switch_open -- acinfo 0x%x refcnt %d \n", (unsigned int)acinfo, acinfo->refcnt); @@ -768,7 +874,7 @@ int audio_switch_open(void) fail_audio_open: if (acinfo) { - apbif_disable_clock(); + audio_switch_disable_clock(); kfree(acinfo); } @@ -777,13 +883,20 @@ fail_audio_open: int audio_switch_close(void) { - if (acinfo && enable_audioswitch) { - acinfo->refcnt -= 1; + if (acinfo && (enable_audioswitch == true)) { + acinfo->refcnt--; if (!acinfo->refcnt) { - apbif_disable_clock(); + audio_switch_disable_clock(); + + if (acinfo->apbif_clk) + clk_put(acinfo->apbif_clk); + + if (acinfo->audiohub_clk) + clk_put(acinfo->audiohub_clk); + kfree(acinfo); - enable_audioswitch = 0; + enable_audioswitch = false; } } return 0; diff --git a/arch/arm/mach-tegra/include/mach/audio_switch.h b/arch/arm/mach-tegra/include/mach/audio_switch.h index fc8a82268f87..b86ffb55c4ea 100644 --- a/arch/arm/mach-tegra/include/mach/audio_switch.h +++ b/arch/arm/mach-tegra/include/mach/audio_switch.h @@ -107,7 +107,7 @@ void apbif_set_pack_mode(int ifc, int tx, int pack_mode); void apbif_channel_set_loopback(int ifc, int on); void apbif_channel_enable(int ifc, int tx, int enable); int apbif_get_channel(int regindex, int fifo_mode); -int apbif_initialize(int ifc, struct audio_cif *cifInfo); + void apbif_soft_reset(int ifc, int fifo_mode, int enable); void apbif_fifo_write(int ifc, int fifo_mode, u32 data); u32 apbif_fifo_read(int ifc, int fifo_mode); @@ -119,6 +119,10 @@ int audio_switch_close(void); int audio_switch_open(void); int audio_apbif_free_channel(int ifc, int fifo_mode); int audio_apbif_set_acif(int ifc, int fifo_mode, struct audio_cif *cifInfo); +int audio_switch_suspend(void); +int audio_switch_resume(void); +int audio_switch_enable_clock(void); +void audio_switch_disable_clock(void); #endif /* __ARCH_ARM_MACH_AUDIO_SWITCH_H */ diff --git a/arch/arm/mach-tegra/tegra3_i2s.c b/arch/arm/mach-tegra/tegra3_i2s.c index ad8f22565587..807164782303 100644 --- a/arch/arm/mach-tegra/tegra3_i2s.c +++ b/arch/arm/mach-tegra/tegra3_i2s.c @@ -150,10 +150,12 @@ void i2s_suspend(int ifc) { i2s_save_registers(ifc); i2s_clock_disable(ifc); + audio_switch_suspend(); } void i2s_resume(int ifc) { + audio_switch_resume(); i2s_clock_enable(ifc); i2s_restore_registers(ifc); } @@ -862,6 +864,10 @@ int i2s_clock_enable(int ifc) int err = 0; struct i2s_controller_info *info = &i2s_cont_info[ifc]; + err = audio_switch_enable_clock(); + if (err) + return err; + if (info->i2sprop.i2s_clk && (info->i2sprop.master_mode == true)) { clk_set_rate(info->i2sprop.i2s_clk, info->i2sprop.clk_rate); @@ -878,7 +884,7 @@ int i2s_clock_enable(int ifc) info->clk_refs++; } - I2S_DEBUG_PRINT(" enable clock count 0x%x \n", info->clk_refs); + I2S_DEBUG_PRINT(" i2s enable clock count 0x%x \n", info->clk_refs); return err; } @@ -919,7 +925,8 @@ int i2s_clock_disable(int ifc) } } - I2S_DEBUG_PRINT(" disable clock count 0x%x \n", info->clk_refs); + audio_switch_disable_clock(); + I2S_DEBUG_PRINT(" i2s disable clock count 0x%x \n", info->clk_refs); return 0; } |