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