Merge tag 'docs-5.15' of git://git.lwn.net/linux
[linux-2.6-microblaze.git] / sound / soc / tegra / tegra30_ahub.c
1 // SPDX-License-Identifier: GPL-2.0-only
2 /*
3  * tegra30_ahub.c - Tegra30 AHUB driver
4  *
5  * Copyright (c) 2011,2012, NVIDIA CORPORATION.  All rights reserved.
6  */
7
8 #include <linux/clk.h>
9 #include <linux/device.h>
10 #include <linux/io.h>
11 #include <linux/module.h>
12 #include <linux/of_platform.h>
13 #include <linux/platform_device.h>
14 #include <linux/pm_runtime.h>
15 #include <linux/regmap.h>
16 #include <linux/reset.h>
17 #include <linux/slab.h>
18 #include <sound/soc.h>
19 #include "tegra30_ahub.h"
20
21 #define DRV_NAME "tegra30-ahub"
22
23 static struct tegra30_ahub *ahub;
24
25 static inline void tegra30_apbif_write(u32 reg, u32 val)
26 {
27         regmap_write(ahub->regmap_apbif, reg, val);
28 }
29
30 static inline u32 tegra30_apbif_read(u32 reg)
31 {
32         u32 val;
33
34         regmap_read(ahub->regmap_apbif, reg, &val);
35         return val;
36 }
37
38 static inline void tegra30_audio_write(u32 reg, u32 val)
39 {
40         regmap_write(ahub->regmap_ahub, reg, val);
41 }
42
43 static __maybe_unused int tegra30_ahub_runtime_suspend(struct device *dev)
44 {
45         regcache_cache_only(ahub->regmap_apbif, true);
46         regcache_cache_only(ahub->regmap_ahub, true);
47
48         clk_bulk_disable_unprepare(ahub->nclocks, ahub->clocks);
49
50         return 0;
51 }
52
53 /*
54  * clk_apbif isn't required for an I2S<->I2S configuration where no PCM data
55  * is read from or sent to memory. However, that's not something the rest of
56  * the driver supports right now, so we'll just treat the two clocks as one
57  * for now.
58  *
59  * These functions should not be a plain ref-count. Instead, each active stream
60  * contributes some requirement to the minimum clock rate, so starting or
61  * stopping streams should dynamically adjust the clock as required.  However,
62  * this is not yet implemented.
63  */
64 static __maybe_unused int tegra30_ahub_runtime_resume(struct device *dev)
65 {
66         int ret;
67
68         ret = reset_control_bulk_assert(ahub->nresets, ahub->resets);
69         if (ret)
70                 return ret;
71
72         ret = clk_bulk_prepare_enable(ahub->nclocks, ahub->clocks);
73         if (ret)
74                 return ret;
75
76         usleep_range(10, 100);
77
78         ret = reset_control_bulk_deassert(ahub->nresets, ahub->resets);
79         if (ret)
80                 goto disable_clocks;
81
82         regcache_cache_only(ahub->regmap_apbif, false);
83         regcache_cache_only(ahub->regmap_ahub, false);
84         regcache_mark_dirty(ahub->regmap_apbif);
85         regcache_mark_dirty(ahub->regmap_ahub);
86
87         ret = regcache_sync(ahub->regmap_apbif);
88         if (ret)
89                 goto disable_clocks;
90
91         ret = regcache_sync(ahub->regmap_ahub);
92         if (ret)
93                 goto disable_clocks;
94
95         return 0;
96
97 disable_clocks:
98         clk_bulk_disable_unprepare(ahub->nclocks, ahub->clocks);
99
100         return ret;
101 }
102
103 int tegra30_ahub_allocate_rx_fifo(enum tegra30_ahub_rxcif *rxcif,
104                                   char *dmachan, int dmachan_len,
105                                   dma_addr_t *fiforeg)
106 {
107         int channel;
108         u32 reg, val;
109         struct tegra30_ahub_cif_conf cif_conf;
110
111         channel = find_first_zero_bit(ahub->rx_usage,
112                                       TEGRA30_AHUB_CHANNEL_CTRL_COUNT);
113         if (channel >= TEGRA30_AHUB_CHANNEL_CTRL_COUNT)
114                 return -EBUSY;
115
116         __set_bit(channel, ahub->rx_usage);
117
118         *rxcif = TEGRA30_AHUB_RXCIF_APBIF_RX0 + channel;
119         snprintf(dmachan, dmachan_len, "rx%d", channel);
120         *fiforeg = ahub->apbif_addr + TEGRA30_AHUB_CHANNEL_RXFIFO +
121                    (channel * TEGRA30_AHUB_CHANNEL_RXFIFO_STRIDE);
122
123         pm_runtime_get_sync(ahub->dev);
124
125         reg = TEGRA30_AHUB_CHANNEL_CTRL +
126               (channel * TEGRA30_AHUB_CHANNEL_CTRL_STRIDE);
127         val = tegra30_apbif_read(reg);
128         val &= ~(TEGRA30_AHUB_CHANNEL_CTRL_RX_THRESHOLD_MASK |
129                  TEGRA30_AHUB_CHANNEL_CTRL_RX_PACK_MASK);
130         val |= (7 << TEGRA30_AHUB_CHANNEL_CTRL_RX_THRESHOLD_SHIFT) |
131                TEGRA30_AHUB_CHANNEL_CTRL_RX_PACK_EN |
132                TEGRA30_AHUB_CHANNEL_CTRL_RX_PACK_16;
133         tegra30_apbif_write(reg, val);
134
135         cif_conf.threshold = 0;
136         cif_conf.audio_channels = 2;
137         cif_conf.client_channels = 2;
138         cif_conf.audio_bits = TEGRA30_AUDIOCIF_BITS_16;
139         cif_conf.client_bits = TEGRA30_AUDIOCIF_BITS_16;
140         cif_conf.expand = 0;
141         cif_conf.stereo_conv = 0;
142         cif_conf.replicate = 0;
143         cif_conf.direction = TEGRA30_AUDIOCIF_DIRECTION_RX;
144         cif_conf.truncate = 0;
145         cif_conf.mono_conv = 0;
146
147         reg = TEGRA30_AHUB_CIF_RX_CTRL +
148               (channel * TEGRA30_AHUB_CIF_RX_CTRL_STRIDE);
149         ahub->soc_data->set_audio_cif(ahub->regmap_apbif, reg, &cif_conf);
150
151         pm_runtime_put(ahub->dev);
152
153         return 0;
154 }
155 EXPORT_SYMBOL_GPL(tegra30_ahub_allocate_rx_fifo);
156
157 int tegra30_ahub_enable_rx_fifo(enum tegra30_ahub_rxcif rxcif)
158 {
159         int channel = rxcif - TEGRA30_AHUB_RXCIF_APBIF_RX0;
160         int reg, val;
161
162         pm_runtime_get_sync(ahub->dev);
163
164         reg = TEGRA30_AHUB_CHANNEL_CTRL +
165               (channel * TEGRA30_AHUB_CHANNEL_CTRL_STRIDE);
166         val = tegra30_apbif_read(reg);
167         val |= TEGRA30_AHUB_CHANNEL_CTRL_RX_EN;
168         tegra30_apbif_write(reg, val);
169
170         pm_runtime_put(ahub->dev);
171
172         return 0;
173 }
174 EXPORT_SYMBOL_GPL(tegra30_ahub_enable_rx_fifo);
175
176 int tegra30_ahub_disable_rx_fifo(enum tegra30_ahub_rxcif rxcif)
177 {
178         int channel = rxcif - TEGRA30_AHUB_RXCIF_APBIF_RX0;
179         int reg, val;
180
181         pm_runtime_get_sync(ahub->dev);
182
183         reg = TEGRA30_AHUB_CHANNEL_CTRL +
184               (channel * TEGRA30_AHUB_CHANNEL_CTRL_STRIDE);
185         val = tegra30_apbif_read(reg);
186         val &= ~TEGRA30_AHUB_CHANNEL_CTRL_RX_EN;
187         tegra30_apbif_write(reg, val);
188
189         pm_runtime_put(ahub->dev);
190
191         return 0;
192 }
193 EXPORT_SYMBOL_GPL(tegra30_ahub_disable_rx_fifo);
194
195 int tegra30_ahub_free_rx_fifo(enum tegra30_ahub_rxcif rxcif)
196 {
197         int channel = rxcif - TEGRA30_AHUB_RXCIF_APBIF_RX0;
198
199         __clear_bit(channel, ahub->rx_usage);
200
201         return 0;
202 }
203 EXPORT_SYMBOL_GPL(tegra30_ahub_free_rx_fifo);
204
205 int tegra30_ahub_allocate_tx_fifo(enum tegra30_ahub_txcif *txcif,
206                                   char *dmachan, int dmachan_len,
207                                   dma_addr_t *fiforeg)
208 {
209         int channel;
210         u32 reg, val;
211         struct tegra30_ahub_cif_conf cif_conf;
212
213         channel = find_first_zero_bit(ahub->tx_usage,
214                                       TEGRA30_AHUB_CHANNEL_CTRL_COUNT);
215         if (channel >= TEGRA30_AHUB_CHANNEL_CTRL_COUNT)
216                 return -EBUSY;
217
218         __set_bit(channel, ahub->tx_usage);
219
220         *txcif = TEGRA30_AHUB_TXCIF_APBIF_TX0 + channel;
221         snprintf(dmachan, dmachan_len, "tx%d", channel);
222         *fiforeg = ahub->apbif_addr + TEGRA30_AHUB_CHANNEL_TXFIFO +
223                    (channel * TEGRA30_AHUB_CHANNEL_TXFIFO_STRIDE);
224
225         pm_runtime_get_sync(ahub->dev);
226
227         reg = TEGRA30_AHUB_CHANNEL_CTRL +
228               (channel * TEGRA30_AHUB_CHANNEL_CTRL_STRIDE);
229         val = tegra30_apbif_read(reg);
230         val &= ~(TEGRA30_AHUB_CHANNEL_CTRL_TX_THRESHOLD_MASK |
231                  TEGRA30_AHUB_CHANNEL_CTRL_TX_PACK_MASK);
232         val |= (7 << TEGRA30_AHUB_CHANNEL_CTRL_TX_THRESHOLD_SHIFT) |
233                TEGRA30_AHUB_CHANNEL_CTRL_TX_PACK_EN |
234                TEGRA30_AHUB_CHANNEL_CTRL_TX_PACK_16;
235         tegra30_apbif_write(reg, val);
236
237         cif_conf.threshold = 0;
238         cif_conf.audio_channels = 2;
239         cif_conf.client_channels = 2;
240         cif_conf.audio_bits = TEGRA30_AUDIOCIF_BITS_16;
241         cif_conf.client_bits = TEGRA30_AUDIOCIF_BITS_16;
242         cif_conf.expand = 0;
243         cif_conf.stereo_conv = 0;
244         cif_conf.replicate = 0;
245         cif_conf.direction = TEGRA30_AUDIOCIF_DIRECTION_TX;
246         cif_conf.truncate = 0;
247         cif_conf.mono_conv = 0;
248
249         reg = TEGRA30_AHUB_CIF_TX_CTRL +
250               (channel * TEGRA30_AHUB_CIF_TX_CTRL_STRIDE);
251         ahub->soc_data->set_audio_cif(ahub->regmap_apbif, reg, &cif_conf);
252
253         pm_runtime_put(ahub->dev);
254
255         return 0;
256 }
257 EXPORT_SYMBOL_GPL(tegra30_ahub_allocate_tx_fifo);
258
259 int tegra30_ahub_enable_tx_fifo(enum tegra30_ahub_txcif txcif)
260 {
261         int channel = txcif - TEGRA30_AHUB_TXCIF_APBIF_TX0;
262         int reg, val;
263
264         pm_runtime_get_sync(ahub->dev);
265
266         reg = TEGRA30_AHUB_CHANNEL_CTRL +
267               (channel * TEGRA30_AHUB_CHANNEL_CTRL_STRIDE);
268         val = tegra30_apbif_read(reg);
269         val |= TEGRA30_AHUB_CHANNEL_CTRL_TX_EN;
270         tegra30_apbif_write(reg, val);
271
272         pm_runtime_put(ahub->dev);
273
274         return 0;
275 }
276 EXPORT_SYMBOL_GPL(tegra30_ahub_enable_tx_fifo);
277
278 int tegra30_ahub_disable_tx_fifo(enum tegra30_ahub_txcif txcif)
279 {
280         int channel = txcif - TEGRA30_AHUB_TXCIF_APBIF_TX0;
281         int reg, val;
282
283         pm_runtime_get_sync(ahub->dev);
284
285         reg = TEGRA30_AHUB_CHANNEL_CTRL +
286               (channel * TEGRA30_AHUB_CHANNEL_CTRL_STRIDE);
287         val = tegra30_apbif_read(reg);
288         val &= ~TEGRA30_AHUB_CHANNEL_CTRL_TX_EN;
289         tegra30_apbif_write(reg, val);
290
291         pm_runtime_put(ahub->dev);
292
293         return 0;
294 }
295 EXPORT_SYMBOL_GPL(tegra30_ahub_disable_tx_fifo);
296
297 int tegra30_ahub_free_tx_fifo(enum tegra30_ahub_txcif txcif)
298 {
299         int channel = txcif - TEGRA30_AHUB_TXCIF_APBIF_TX0;
300
301         __clear_bit(channel, ahub->tx_usage);
302
303         return 0;
304 }
305 EXPORT_SYMBOL_GPL(tegra30_ahub_free_tx_fifo);
306
307 int tegra30_ahub_set_rx_cif_source(enum tegra30_ahub_rxcif rxcif,
308                                    enum tegra30_ahub_txcif txcif)
309 {
310         int channel = rxcif - TEGRA30_AHUB_RXCIF_APBIF_RX0;
311         int reg;
312
313         pm_runtime_get_sync(ahub->dev);
314
315         reg = TEGRA30_AHUB_AUDIO_RX +
316               (channel * TEGRA30_AHUB_AUDIO_RX_STRIDE);
317         tegra30_audio_write(reg, 1 << txcif);
318
319         pm_runtime_put(ahub->dev);
320
321         return 0;
322 }
323 EXPORT_SYMBOL_GPL(tegra30_ahub_set_rx_cif_source);
324
325 int tegra30_ahub_unset_rx_cif_source(enum tegra30_ahub_rxcif rxcif)
326 {
327         int channel = rxcif - TEGRA30_AHUB_RXCIF_APBIF_RX0;
328         int reg;
329
330         pm_runtime_get_sync(ahub->dev);
331
332         reg = TEGRA30_AHUB_AUDIO_RX +
333               (channel * TEGRA30_AHUB_AUDIO_RX_STRIDE);
334         tegra30_audio_write(reg, 0);
335
336         pm_runtime_put(ahub->dev);
337
338         return 0;
339 }
340 EXPORT_SYMBOL_GPL(tegra30_ahub_unset_rx_cif_source);
341
342 static const struct reset_control_bulk_data tegra30_ahub_resets_data[] = {
343         { "d_audio" },
344         { "apbif" },
345         { "i2s0" },
346         { "i2s1" },
347         { "i2s2" },
348         { "i2s3" },
349         { "i2s4" },
350         { "dam0" },
351         { "dam1" },
352         { "dam2" },
353         { "spdif" },
354         { "amx" }, /* Tegra114+ */
355         { "adx" }, /* Tegra114+ */
356         { "amx1" }, /* Tegra124 */
357         { "adx1" }, /* Tegra124 */
358         { "afc0" }, /* Tegra124 */
359         { "afc1" }, /* Tegra124 */
360         { "afc2" }, /* Tegra124 */
361         { "afc3" }, /* Tegra124 */
362         { "afc4" }, /* Tegra124 */
363         { "afc5" }, /* Tegra124 */
364 };
365
366 #define LAST_REG(name) \
367         (TEGRA30_AHUB_##name + \
368          (TEGRA30_AHUB_##name##_STRIDE * TEGRA30_AHUB_##name##_COUNT) - 4)
369
370 #define REG_IN_ARRAY(reg, name) \
371         ((reg >= TEGRA30_AHUB_##name) && \
372          (reg <= LAST_REG(name) && \
373          (!((reg - TEGRA30_AHUB_##name) % TEGRA30_AHUB_##name##_STRIDE))))
374
375 static bool tegra30_ahub_apbif_wr_rd_reg(struct device *dev, unsigned int reg)
376 {
377         switch (reg) {
378         case TEGRA30_AHUB_CONFIG_LINK_CTRL:
379         case TEGRA30_AHUB_MISC_CTRL:
380         case TEGRA30_AHUB_APBDMA_LIVE_STATUS:
381         case TEGRA30_AHUB_I2S_LIVE_STATUS:
382         case TEGRA30_AHUB_SPDIF_LIVE_STATUS:
383         case TEGRA30_AHUB_I2S_INT_MASK:
384         case TEGRA30_AHUB_DAM_INT_MASK:
385         case TEGRA30_AHUB_SPDIF_INT_MASK:
386         case TEGRA30_AHUB_APBIF_INT_MASK:
387         case TEGRA30_AHUB_I2S_INT_STATUS:
388         case TEGRA30_AHUB_DAM_INT_STATUS:
389         case TEGRA30_AHUB_SPDIF_INT_STATUS:
390         case TEGRA30_AHUB_APBIF_INT_STATUS:
391         case TEGRA30_AHUB_I2S_INT_SOURCE:
392         case TEGRA30_AHUB_DAM_INT_SOURCE:
393         case TEGRA30_AHUB_SPDIF_INT_SOURCE:
394         case TEGRA30_AHUB_APBIF_INT_SOURCE:
395         case TEGRA30_AHUB_I2S_INT_SET:
396         case TEGRA30_AHUB_DAM_INT_SET:
397         case TEGRA30_AHUB_SPDIF_INT_SET:
398         case TEGRA30_AHUB_APBIF_INT_SET:
399                 return true;
400         default:
401                 break;
402         }
403
404         if (REG_IN_ARRAY(reg, CHANNEL_CTRL) ||
405             REG_IN_ARRAY(reg, CHANNEL_CLEAR) ||
406             REG_IN_ARRAY(reg, CHANNEL_STATUS) ||
407             REG_IN_ARRAY(reg, CHANNEL_TXFIFO) ||
408             REG_IN_ARRAY(reg, CHANNEL_RXFIFO) ||
409             REG_IN_ARRAY(reg, CIF_TX_CTRL) ||
410             REG_IN_ARRAY(reg, CIF_RX_CTRL) ||
411             REG_IN_ARRAY(reg, DAM_LIVE_STATUS))
412                 return true;
413
414         return false;
415 }
416
417 static bool tegra30_ahub_apbif_volatile_reg(struct device *dev,
418                                             unsigned int reg)
419 {
420         switch (reg) {
421         case TEGRA30_AHUB_CONFIG_LINK_CTRL:
422         case TEGRA30_AHUB_MISC_CTRL:
423         case TEGRA30_AHUB_APBDMA_LIVE_STATUS:
424         case TEGRA30_AHUB_I2S_LIVE_STATUS:
425         case TEGRA30_AHUB_SPDIF_LIVE_STATUS:
426         case TEGRA30_AHUB_I2S_INT_STATUS:
427         case TEGRA30_AHUB_DAM_INT_STATUS:
428         case TEGRA30_AHUB_SPDIF_INT_STATUS:
429         case TEGRA30_AHUB_APBIF_INT_STATUS:
430         case TEGRA30_AHUB_I2S_INT_SET:
431         case TEGRA30_AHUB_DAM_INT_SET:
432         case TEGRA30_AHUB_SPDIF_INT_SET:
433         case TEGRA30_AHUB_APBIF_INT_SET:
434                 return true;
435         default:
436                 break;
437         }
438
439         if (REG_IN_ARRAY(reg, CHANNEL_CLEAR) ||
440             REG_IN_ARRAY(reg, CHANNEL_STATUS) ||
441             REG_IN_ARRAY(reg, CHANNEL_TXFIFO) ||
442             REG_IN_ARRAY(reg, CHANNEL_RXFIFO) ||
443             REG_IN_ARRAY(reg, DAM_LIVE_STATUS))
444                 return true;
445
446         return false;
447 }
448
449 static bool tegra30_ahub_apbif_precious_reg(struct device *dev,
450                                             unsigned int reg)
451 {
452         if (REG_IN_ARRAY(reg, CHANNEL_TXFIFO) ||
453             REG_IN_ARRAY(reg, CHANNEL_RXFIFO))
454                 return true;
455
456         return false;
457 }
458
459 static const struct regmap_config tegra30_ahub_apbif_regmap_config = {
460         .name = "apbif",
461         .reg_bits = 32,
462         .val_bits = 32,
463         .reg_stride = 4,
464         .max_register = TEGRA30_AHUB_APBIF_INT_SET,
465         .writeable_reg = tegra30_ahub_apbif_wr_rd_reg,
466         .readable_reg = tegra30_ahub_apbif_wr_rd_reg,
467         .volatile_reg = tegra30_ahub_apbif_volatile_reg,
468         .precious_reg = tegra30_ahub_apbif_precious_reg,
469         .cache_type = REGCACHE_FLAT,
470 };
471
472 static bool tegra30_ahub_ahub_wr_rd_reg(struct device *dev, unsigned int reg)
473 {
474         if (REG_IN_ARRAY(reg, AUDIO_RX))
475                 return true;
476
477         return false;
478 }
479
480 static const struct regmap_config tegra30_ahub_ahub_regmap_config = {
481         .name = "ahub",
482         .reg_bits = 32,
483         .val_bits = 32,
484         .reg_stride = 4,
485         .max_register = LAST_REG(AUDIO_RX),
486         .writeable_reg = tegra30_ahub_ahub_wr_rd_reg,
487         .readable_reg = tegra30_ahub_ahub_wr_rd_reg,
488         .cache_type = REGCACHE_FLAT,
489 };
490
491 static struct tegra30_ahub_soc_data soc_data_tegra30 = {
492         .num_resets = 11,
493         .set_audio_cif = tegra30_ahub_set_cif,
494 };
495
496 static struct tegra30_ahub_soc_data soc_data_tegra114 = {
497         .num_resets = 13,
498         .set_audio_cif = tegra30_ahub_set_cif,
499 };
500
501 static struct tegra30_ahub_soc_data soc_data_tegra124 = {
502         .num_resets = 21,
503         .set_audio_cif = tegra124_ahub_set_cif,
504 };
505
506 static const struct of_device_id tegra30_ahub_of_match[] = {
507         { .compatible = "nvidia,tegra124-ahub", .data = &soc_data_tegra124 },
508         { .compatible = "nvidia,tegra114-ahub", .data = &soc_data_tegra114 },
509         { .compatible = "nvidia,tegra30-ahub",  .data = &soc_data_tegra30 },
510         {},
511 };
512
513 static int tegra30_ahub_probe(struct platform_device *pdev)
514 {
515         const struct tegra30_ahub_soc_data *soc_data;
516         struct resource *res0;
517         void __iomem *regs_apbif, *regs_ahub;
518         int ret = 0;
519
520         soc_data = of_device_get_match_data(&pdev->dev);
521         if (!soc_data)
522                 return -EINVAL;
523
524         ahub = devm_kzalloc(&pdev->dev, sizeof(struct tegra30_ahub),
525                             GFP_KERNEL);
526         if (!ahub)
527                 return -ENOMEM;
528         dev_set_drvdata(&pdev->dev, ahub);
529
530         BUILD_BUG_ON(sizeof(ahub->resets) != sizeof(tegra30_ahub_resets_data));
531         memcpy(ahub->resets, tegra30_ahub_resets_data, sizeof(ahub->resets));
532
533         ahub->nresets = soc_data->num_resets;
534         ahub->soc_data = soc_data;
535         ahub->dev = &pdev->dev;
536
537         ahub->clocks[ahub->nclocks++].id = "apbif";
538         ahub->clocks[ahub->nclocks++].id = "d_audio";
539
540         ret = devm_clk_bulk_get(&pdev->dev, ahub->nclocks, ahub->clocks);
541         if (ret)
542                 goto err_unset_ahub;
543
544         ret = devm_reset_control_bulk_get_exclusive(&pdev->dev, ahub->nresets,
545                                                     ahub->resets);
546         if (ret) {
547                 dev_err(&pdev->dev, "Can't get resets: %d\n", ret);
548                 goto err_unset_ahub;
549         }
550
551         regs_apbif = devm_platform_get_and_ioremap_resource(pdev, 0, &res0);
552         if (IS_ERR(regs_apbif)) {
553                 ret = PTR_ERR(regs_apbif);
554                 goto err_unset_ahub;
555         }
556
557         ahub->apbif_addr = res0->start;
558
559         ahub->regmap_apbif = devm_regmap_init_mmio(&pdev->dev, regs_apbif,
560                                         &tegra30_ahub_apbif_regmap_config);
561         if (IS_ERR(ahub->regmap_apbif)) {
562                 dev_err(&pdev->dev, "apbif regmap init failed\n");
563                 ret = PTR_ERR(ahub->regmap_apbif);
564                 goto err_unset_ahub;
565         }
566         regcache_cache_only(ahub->regmap_apbif, true);
567
568         regs_ahub = devm_platform_ioremap_resource(pdev, 1);
569         if (IS_ERR(regs_ahub)) {
570                 ret = PTR_ERR(regs_ahub);
571                 goto err_unset_ahub;
572         }
573
574         ahub->regmap_ahub = devm_regmap_init_mmio(&pdev->dev, regs_ahub,
575                                         &tegra30_ahub_ahub_regmap_config);
576         if (IS_ERR(ahub->regmap_ahub)) {
577                 dev_err(&pdev->dev, "ahub regmap init failed\n");
578                 ret = PTR_ERR(ahub->regmap_ahub);
579                 goto err_unset_ahub;
580         }
581         regcache_cache_only(ahub->regmap_ahub, true);
582
583         pm_runtime_enable(&pdev->dev);
584
585         of_platform_populate(pdev->dev.of_node, NULL, NULL, &pdev->dev);
586
587         return 0;
588
589 err_unset_ahub:
590         ahub = NULL;
591
592         return ret;
593 }
594
595 static int tegra30_ahub_remove(struct platform_device *pdev)
596 {
597         pm_runtime_disable(&pdev->dev);
598
599         ahub = NULL;
600
601         return 0;
602 }
603
604 static const struct dev_pm_ops tegra30_ahub_pm_ops = {
605         SET_RUNTIME_PM_OPS(tegra30_ahub_runtime_suspend,
606                            tegra30_ahub_runtime_resume, NULL)
607         SET_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend,
608                                 pm_runtime_force_resume)
609 };
610
611 static struct platform_driver tegra30_ahub_driver = {
612         .probe = tegra30_ahub_probe,
613         .remove = tegra30_ahub_remove,
614         .driver = {
615                 .name = DRV_NAME,
616                 .of_match_table = tegra30_ahub_of_match,
617                 .pm = &tegra30_ahub_pm_ops,
618         },
619 };
620 module_platform_driver(tegra30_ahub_driver);
621
622 void tegra30_ahub_set_cif(struct regmap *regmap, unsigned int reg,
623                           struct tegra30_ahub_cif_conf *conf)
624 {
625         unsigned int value;
626
627         value = (conf->threshold <<
628                         TEGRA30_AUDIOCIF_CTRL_FIFO_THRESHOLD_SHIFT) |
629                 ((conf->audio_channels - 1) <<
630                         TEGRA30_AUDIOCIF_CTRL_AUDIO_CHANNELS_SHIFT) |
631                 ((conf->client_channels - 1) <<
632                         TEGRA30_AUDIOCIF_CTRL_CLIENT_CHANNELS_SHIFT) |
633                 (conf->audio_bits <<
634                         TEGRA30_AUDIOCIF_CTRL_AUDIO_BITS_SHIFT) |
635                 (conf->client_bits <<
636                         TEGRA30_AUDIOCIF_CTRL_CLIENT_BITS_SHIFT) |
637                 (conf->expand <<
638                         TEGRA30_AUDIOCIF_CTRL_EXPAND_SHIFT) |
639                 (conf->stereo_conv <<
640                         TEGRA30_AUDIOCIF_CTRL_STEREO_CONV_SHIFT) |
641                 (conf->replicate <<
642                         TEGRA30_AUDIOCIF_CTRL_REPLICATE_SHIFT) |
643                 (conf->direction <<
644                         TEGRA30_AUDIOCIF_CTRL_DIRECTION_SHIFT) |
645                 (conf->truncate <<
646                         TEGRA30_AUDIOCIF_CTRL_TRUNCATE_SHIFT) |
647                 (conf->mono_conv <<
648                         TEGRA30_AUDIOCIF_CTRL_MONO_CONV_SHIFT);
649
650         regmap_write(regmap, reg, value);
651 }
652 EXPORT_SYMBOL_GPL(tegra30_ahub_set_cif);
653
654 void tegra124_ahub_set_cif(struct regmap *regmap, unsigned int reg,
655                            struct tegra30_ahub_cif_conf *conf)
656 {
657         unsigned int value;
658
659         value = (conf->threshold <<
660                         TEGRA124_AUDIOCIF_CTRL_FIFO_THRESHOLD_SHIFT) |
661                 ((conf->audio_channels - 1) <<
662                         TEGRA124_AUDIOCIF_CTRL_AUDIO_CHANNELS_SHIFT) |
663                 ((conf->client_channels - 1) <<
664                         TEGRA124_AUDIOCIF_CTRL_CLIENT_CHANNELS_SHIFT) |
665                 (conf->audio_bits <<
666                         TEGRA30_AUDIOCIF_CTRL_AUDIO_BITS_SHIFT) |
667                 (conf->client_bits <<
668                         TEGRA30_AUDIOCIF_CTRL_CLIENT_BITS_SHIFT) |
669                 (conf->expand <<
670                         TEGRA30_AUDIOCIF_CTRL_EXPAND_SHIFT) |
671                 (conf->stereo_conv <<
672                         TEGRA30_AUDIOCIF_CTRL_STEREO_CONV_SHIFT) |
673                 (conf->replicate <<
674                         TEGRA30_AUDIOCIF_CTRL_REPLICATE_SHIFT) |
675                 (conf->direction <<
676                         TEGRA30_AUDIOCIF_CTRL_DIRECTION_SHIFT) |
677                 (conf->truncate <<
678                         TEGRA30_AUDIOCIF_CTRL_TRUNCATE_SHIFT) |
679                 (conf->mono_conv <<
680                         TEGRA30_AUDIOCIF_CTRL_MONO_CONV_SHIFT);
681
682         regmap_write(regmap, reg, value);
683 }
684 EXPORT_SYMBOL_GPL(tegra124_ahub_set_cif);
685
686 MODULE_AUTHOR("Stephen Warren <swarren@nvidia.com>");
687 MODULE_DESCRIPTION("Tegra30 AHUB driver");
688 MODULE_LICENSE("GPL v2");
689 MODULE_ALIAS("platform:" DRV_NAME);
690 MODULE_DEVICE_TABLE(of, tegra30_ahub_of_match);