diff options
| author | Stephen Warren <swarren@nvidia.com> | 2012-04-13 14:14:07 -0400 |
|---|---|---|
| committer | Mark Brown <broonie@opensource.wolfsonmicro.com> | 2012-04-13 14:16:53 -0400 |
| commit | 5939ae74753ceda976732899bef71f99ffea6ea5 (patch) | |
| tree | 8226f5a9a601ae1fd86a37be1f6f720974e92e53 /sound/soc/tegra | |
| parent | c1607416aa59b8bc78445f8ac3de559ed68864a2 (diff) | |
ASoC: convert Tegra20 SPDIF driver to regmap
Signed-off-by: Stephen Warren <swarren@nvidia.com>
Signed-off-by: Mark Brown <broonie@opensource.wolfsonmicro.com>
Diffstat (limited to 'sound/soc/tegra')
| -rw-r--r-- | sound/soc/tegra/tegra20_spdif.c | 173 | ||||
| -rw-r--r-- | sound/soc/tegra/tegra20_spdif.h | 3 |
2 files changed, 92 insertions, 84 deletions
diff --git a/sound/soc/tegra/tegra20_spdif.c b/sound/soc/tegra/tegra20_spdif.c index 9efd71e13a0a..f9b57418bd08 100644 --- a/sound/soc/tegra/tegra20_spdif.c +++ b/sound/soc/tegra/tegra20_spdif.c | |||
| @@ -21,13 +21,12 @@ | |||
| 21 | */ | 21 | */ |
| 22 | 22 | ||
| 23 | #include <linux/clk.h> | 23 | #include <linux/clk.h> |
| 24 | #include <linux/debugfs.h> | ||
| 25 | #include <linux/device.h> | 24 | #include <linux/device.h> |
| 26 | #include <linux/io.h> | 25 | #include <linux/io.h> |
| 27 | #include <linux/module.h> | 26 | #include <linux/module.h> |
| 28 | #include <linux/platform_device.h> | 27 | #include <linux/platform_device.h> |
| 29 | #include <linux/pm_runtime.h> | 28 | #include <linux/pm_runtime.h> |
| 30 | #include <linux/seq_file.h> | 29 | #include <linux/regmap.h> |
| 31 | #include <linux/slab.h> | 30 | #include <linux/slab.h> |
| 32 | #include <sound/core.h> | 31 | #include <sound/core.h> |
| 33 | #include <sound/pcm.h> | 32 | #include <sound/pcm.h> |
| @@ -41,12 +40,14 @@ | |||
| 41 | static inline void tegra20_spdif_write(struct tegra20_spdif *spdif, u32 reg, | 40 | static inline void tegra20_spdif_write(struct tegra20_spdif *spdif, u32 reg, |
| 42 | u32 val) | 41 | u32 val) |
| 43 | { | 42 | { |
| 44 | __raw_writel(val, spdif->regs + reg); | 43 | regmap_write(spdif->regmap, reg, val); |
| 45 | } | 44 | } |
| 46 | 45 | ||
| 47 | static inline u32 tegra20_spdif_read(struct tegra20_spdif *spdif, u32 reg) | 46 | static inline u32 tegra20_spdif_read(struct tegra20_spdif *spdif, u32 reg) |
| 48 | { | 47 | { |
| 49 | return __raw_readl(spdif->regs + reg); | 48 | u32 val; |
| 49 | regmap_read(spdif->regmap, reg, &val); | ||
| 50 | return val; | ||
| 50 | } | 51 | } |
| 51 | 52 | ||
| 52 | static int tegra20_spdif_runtime_suspend(struct device *dev) | 53 | static int tegra20_spdif_runtime_suspend(struct device *dev) |
| @@ -72,78 +73,6 @@ static int tegra20_spdif_runtime_resume(struct device *dev) | |||
| 72 | return 0; | 73 | return 0; |
| 73 | } | 74 | } |
| 74 | 75 | ||
| 75 | #ifdef CONFIG_DEBUG_FS | ||
| 76 | static int tegra20_spdif_show(struct seq_file *s, void *unused) | ||
| 77 | { | ||
| 78 | #define REG(r) { r, #r } | ||
| 79 | static const struct { | ||
| 80 | int offset; | ||
| 81 | const char *name; | ||
| 82 | } regs[] = { | ||
| 83 | REG(TEGRA20_SPDIF_CTRL), | ||
| 84 | REG(TEGRA20_SPDIF_STATUS), | ||
| 85 | REG(TEGRA20_SPDIF_STROBE_CTRL), | ||
| 86 | REG(TEGRA20_SPDIF_DATA_FIFO_CSR), | ||
| 87 | REG(TEGRA20_SPDIF_CH_STA_RX_A), | ||
| 88 | REG(TEGRA20_SPDIF_CH_STA_RX_B), | ||
| 89 | REG(TEGRA20_SPDIF_CH_STA_RX_C), | ||
| 90 | REG(TEGRA20_SPDIF_CH_STA_RX_D), | ||
| 91 | REG(TEGRA20_SPDIF_CH_STA_RX_E), | ||
| 92 | REG(TEGRA20_SPDIF_CH_STA_RX_F), | ||
| 93 | REG(TEGRA20_SPDIF_CH_STA_TX_A), | ||
| 94 | REG(TEGRA20_SPDIF_CH_STA_TX_B), | ||
| 95 | REG(TEGRA20_SPDIF_CH_STA_TX_C), | ||
| 96 | REG(TEGRA20_SPDIF_CH_STA_TX_D), | ||
| 97 | REG(TEGRA20_SPDIF_CH_STA_TX_E), | ||
| 98 | REG(TEGRA20_SPDIF_CH_STA_TX_F), | ||
| 99 | }; | ||
| 100 | #undef REG | ||
| 101 | |||
| 102 | struct tegra20_spdif *spdif = s->private; | ||
| 103 | int i; | ||
| 104 | |||
| 105 | for (i = 0; i < ARRAY_SIZE(regs); i++) { | ||
| 106 | u32 val = tegra20_spdif_read(spdif, regs[i].offset); | ||
| 107 | seq_printf(s, "%s = %08x\n", regs[i].name, val); | ||
| 108 | } | ||
| 109 | |||
| 110 | return 0; | ||
| 111 | } | ||
| 112 | |||
| 113 | static int tegra20_spdif_debug_open(struct inode *inode, struct file *file) | ||
| 114 | { | ||
| 115 | return single_open(file, tegra20_spdif_show, inode->i_private); | ||
| 116 | } | ||
| 117 | |||
| 118 | static const struct file_operations tegra20_spdif_debug_fops = { | ||
| 119 | .open = tegra20_spdif_debug_open, | ||
| 120 | .read = seq_read, | ||
| 121 | .llseek = seq_lseek, | ||
| 122 | .release = single_release, | ||
| 123 | }; | ||
| 124 | |||
| 125 | static void tegra20_spdif_debug_add(struct tegra20_spdif *spdif) | ||
| 126 | { | ||
| 127 | spdif->debug = debugfs_create_file(DRV_NAME, S_IRUGO, | ||
| 128 | snd_soc_debugfs_root, spdif, | ||
| 129 | &tegra20_spdif_debug_fops); | ||
| 130 | } | ||
| 131 | |||
| 132 | static void tegra20_spdif_debug_remove(struct tegra20_spdif *spdif) | ||
| 133 | { | ||
| 134 | if (spdif->debug) | ||
| 135 | debugfs_remove(spdif->debug); | ||
| 136 | } | ||
| 137 | #else | ||
| 138 | static inline void tegra20_spdif_debug_add(struct tegra20_spdif *spdif) | ||
| 139 | { | ||
| 140 | } | ||
| 141 | |||
| 142 | static inline void tegra20_spdif_debug_remove(struct tegra20_spdif *spdif) | ||
| 143 | { | ||
| 144 | } | ||
| 145 | #endif | ||
| 146 | |||
| 147 | static int tegra20_spdif_hw_params(struct snd_pcm_substream *substream, | 76 | static int tegra20_spdif_hw_params(struct snd_pcm_substream *substream, |
| 148 | struct snd_pcm_hw_params *params, | 77 | struct snd_pcm_hw_params *params, |
| 149 | struct snd_soc_dai *dai) | 78 | struct snd_soc_dai *dai) |
| @@ -261,10 +190,86 @@ static struct snd_soc_dai_driver tegra20_spdif_dai = { | |||
| 261 | .ops = &tegra20_spdif_dai_ops, | 190 | .ops = &tegra20_spdif_dai_ops, |
| 262 | }; | 191 | }; |
| 263 | 192 | ||
| 193 | static bool tegra20_spdif_wr_rd_reg(struct device *dev, unsigned int reg) | ||
| 194 | { | ||
| 195 | switch (reg) { | ||
| 196 | case TEGRA20_SPDIF_CTRL: | ||
| 197 | case TEGRA20_SPDIF_STATUS: | ||
| 198 | case TEGRA20_SPDIF_STROBE_CTRL: | ||
| 199 | case TEGRA20_SPDIF_DATA_FIFO_CSR: | ||
| 200 | case TEGRA20_SPDIF_DATA_OUT: | ||
| 201 | case TEGRA20_SPDIF_DATA_IN: | ||
| 202 | case TEGRA20_SPDIF_CH_STA_RX_A: | ||
| 203 | case TEGRA20_SPDIF_CH_STA_RX_B: | ||
| 204 | case TEGRA20_SPDIF_CH_STA_RX_C: | ||
| 205 | case TEGRA20_SPDIF_CH_STA_RX_D: | ||
| 206 | case TEGRA20_SPDIF_CH_STA_RX_E: | ||
| 207 | case TEGRA20_SPDIF_CH_STA_RX_F: | ||
| 208 | case TEGRA20_SPDIF_CH_STA_TX_A: | ||
| 209 | case TEGRA20_SPDIF_CH_STA_TX_B: | ||
| 210 | case TEGRA20_SPDIF_CH_STA_TX_C: | ||
| 211 | case TEGRA20_SPDIF_CH_STA_TX_D: | ||
| 212 | case TEGRA20_SPDIF_CH_STA_TX_E: | ||
| 213 | case TEGRA20_SPDIF_CH_STA_TX_F: | ||
| 214 | case TEGRA20_SPDIF_USR_STA_RX_A: | ||
| 215 | case TEGRA20_SPDIF_USR_DAT_TX_A: | ||
| 216 | return true; | ||
| 217 | default: | ||
| 218 | return false; | ||
| 219 | }; | ||
| 220 | } | ||
| 221 | |||
| 222 | static bool tegra20_spdif_volatile_reg(struct device *dev, unsigned int reg) | ||
| 223 | { | ||
| 224 | switch (reg) { | ||
| 225 | case TEGRA20_SPDIF_STATUS: | ||
| 226 | case TEGRA20_SPDIF_DATA_FIFO_CSR: | ||
| 227 | case TEGRA20_SPDIF_DATA_OUT: | ||
| 228 | case TEGRA20_SPDIF_DATA_IN: | ||
| 229 | case TEGRA20_SPDIF_CH_STA_RX_A: | ||
| 230 | case TEGRA20_SPDIF_CH_STA_RX_B: | ||
| 231 | case TEGRA20_SPDIF_CH_STA_RX_C: | ||
| 232 | case TEGRA20_SPDIF_CH_STA_RX_D: | ||
| 233 | case TEGRA20_SPDIF_CH_STA_RX_E: | ||
| 234 | case TEGRA20_SPDIF_CH_STA_RX_F: | ||
| 235 | case TEGRA20_SPDIF_USR_STA_RX_A: | ||
| 236 | case TEGRA20_SPDIF_USR_DAT_TX_A: | ||
| 237 | return true; | ||
| 238 | default: | ||
| 239 | return false; | ||
| 240 | }; | ||
| 241 | } | ||
| 242 | |||
| 243 | static bool tegra20_spdif_precious_reg(struct device *dev, unsigned int reg) | ||
| 244 | { | ||
| 245 | switch (reg) { | ||
| 246 | case TEGRA20_SPDIF_DATA_OUT: | ||
| 247 | case TEGRA20_SPDIF_DATA_IN: | ||
| 248 | case TEGRA20_SPDIF_USR_STA_RX_A: | ||
| 249 | case TEGRA20_SPDIF_USR_DAT_TX_A: | ||
| 250 | return true; | ||
| 251 | default: | ||
| 252 | return false; | ||
| 253 | }; | ||
| 254 | } | ||
| 255 | |||
| 256 | static const struct regmap_config tegra20_spdif_regmap_config = { | ||
| 257 | .reg_bits = 32, | ||
| 258 | .reg_stride = 4, | ||
| 259 | .val_bits = 32, | ||
| 260 | .max_register = TEGRA20_SPDIF_USR_DAT_TX_A, | ||
| 261 | .writeable_reg = tegra20_spdif_wr_rd_reg, | ||
| 262 | .readable_reg = tegra20_spdif_wr_rd_reg, | ||
| 263 | .volatile_reg = tegra20_spdif_volatile_reg, | ||
| 264 | .precious_reg = tegra20_spdif_precious_reg, | ||
| 265 | .cache_type = REGCACHE_RBTREE, | ||
| 266 | }; | ||
| 267 | |||
| 264 | static __devinit int tegra20_spdif_platform_probe(struct platform_device *pdev) | 268 | static __devinit int tegra20_spdif_platform_probe(struct platform_device *pdev) |
| 265 | { | 269 | { |
| 266 | struct tegra20_spdif *spdif; | 270 | struct tegra20_spdif *spdif; |
| 267 | struct resource *mem, *memregion, *dmareq; | 271 | struct resource *mem, *memregion, *dmareq; |
| 272 | void __iomem *regs; | ||
| 268 | int ret; | 273 | int ret; |
| 269 | 274 | ||
| 270 | spdif = devm_kzalloc(&pdev->dev, sizeof(struct tegra20_spdif), | 275 | spdif = devm_kzalloc(&pdev->dev, sizeof(struct tegra20_spdif), |
| @@ -305,13 +310,21 @@ static __devinit int tegra20_spdif_platform_probe(struct platform_device *pdev) | |||
| 305 | goto err_clk_put; | 310 | goto err_clk_put; |
| 306 | } | 311 | } |
| 307 | 312 | ||
| 308 | spdif->regs = devm_ioremap(&pdev->dev, mem->start, resource_size(mem)); | 313 | regs = devm_ioremap(&pdev->dev, mem->start, resource_size(mem)); |
| 309 | if (!spdif->regs) { | 314 | if (!regs) { |
| 310 | dev_err(&pdev->dev, "ioremap failed\n"); | 315 | dev_err(&pdev->dev, "ioremap failed\n"); |
| 311 | ret = -ENOMEM; | 316 | ret = -ENOMEM; |
| 312 | goto err_clk_put; | 317 | goto err_clk_put; |
| 313 | } | 318 | } |
| 314 | 319 | ||
| 320 | spdif->regmap = devm_regmap_init_mmio(&pdev->dev, regs, | ||
| 321 | &tegra20_spdif_regmap_config); | ||
| 322 | if (IS_ERR(spdif->regmap)) { | ||
| 323 | dev_err(&pdev->dev, "regmap init failed\n"); | ||
| 324 | ret = PTR_ERR(spdif->regmap); | ||
| 325 | goto err_clk_put; | ||
| 326 | } | ||
| 327 | |||
| 315 | spdif->playback_dma_data.addr = mem->start + TEGRA20_SPDIF_DATA_OUT; | 328 | spdif->playback_dma_data.addr = mem->start + TEGRA20_SPDIF_DATA_OUT; |
| 316 | spdif->playback_dma_data.wrap = 4; | 329 | spdif->playback_dma_data.wrap = 4; |
| 317 | spdif->playback_dma_data.width = 32; | 330 | spdif->playback_dma_data.width = 32; |
| @@ -337,8 +350,6 @@ static __devinit int tegra20_spdif_platform_probe(struct platform_device *pdev) | |||
| 337 | goto err_unregister_dai; | 350 | goto err_unregister_dai; |
| 338 | } | 351 | } |
| 339 | 352 | ||
| 340 | tegra20_spdif_debug_add(spdif); | ||
| 341 | |||
| 342 | return 0; | 353 | return 0; |
| 343 | 354 | ||
| 344 | err_unregister_dai: | 355 | err_unregister_dai: |
| @@ -365,8 +376,6 @@ static int __devexit tegra20_spdif_platform_remove(struct platform_device *pdev) | |||
| 365 | tegra_pcm_platform_unregister(&pdev->dev); | 376 | tegra_pcm_platform_unregister(&pdev->dev); |
| 366 | snd_soc_unregister_dai(&pdev->dev); | 377 | snd_soc_unregister_dai(&pdev->dev); |
| 367 | 378 | ||
| 368 | tegra20_spdif_debug_remove(spdif); | ||
| 369 | |||
| 370 | clk_put(spdif->clk_spdif_out); | 379 | clk_put(spdif->clk_spdif_out); |
| 371 | 380 | ||
| 372 | return 0; | 381 | return 0; |
diff --git a/sound/soc/tegra/tegra20_spdif.h b/sound/soc/tegra/tegra20_spdif.h index 823af4c6bb7c..ed756527efea 100644 --- a/sound/soc/tegra/tegra20_spdif.h +++ b/sound/soc/tegra/tegra20_spdif.h | |||
| @@ -464,8 +464,7 @@ struct tegra20_spdif { | |||
| 464 | struct clk *clk_spdif_out; | 464 | struct clk *clk_spdif_out; |
| 465 | struct tegra_pcm_dma_params capture_dma_data; | 465 | struct tegra_pcm_dma_params capture_dma_data; |
| 466 | struct tegra_pcm_dma_params playback_dma_data; | 466 | struct tegra_pcm_dma_params playback_dma_data; |
| 467 | void __iomem *regs; | 467 | struct regmap *regmap; |
| 468 | struct dentry *debug; | ||
| 469 | u32 reg_ctrl; | 468 | u32 reg_ctrl; |
| 470 | }; | 469 | }; |
| 471 | 470 | ||
