xref: /openbmc/linux/sound/soc/tegra/tegra30_ahub.c (revision 4419617e)
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, *res1;
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 	res1 = platform_get_resource(pdev, IORESOURCE_MEM, 1);
591 	regs_ahub = devm_ioremap_resource(&pdev->dev, res1);
592 	if (IS_ERR(regs_ahub))
593 		return PTR_ERR(regs_ahub);
594 
595 	ahub->regmap_ahub = devm_regmap_init_mmio(&pdev->dev, regs_ahub,
596 					&tegra30_ahub_ahub_regmap_config);
597 	if (IS_ERR(ahub->regmap_ahub)) {
598 		dev_err(&pdev->dev, "ahub regmap init failed\n");
599 		ret = PTR_ERR(ahub->regmap_ahub);
600 		return ret;
601 	}
602 	regcache_cache_only(ahub->regmap_ahub, true);
603 
604 	pm_runtime_enable(&pdev->dev);
605 	if (!pm_runtime_enabled(&pdev->dev)) {
606 		ret = tegra30_ahub_runtime_resume(&pdev->dev);
607 		if (ret)
608 			goto err_pm_disable;
609 	}
610 
611 	of_platform_populate(pdev->dev.of_node, NULL, NULL, &pdev->dev);
612 
613 	return 0;
614 
615 err_pm_disable:
616 	pm_runtime_disable(&pdev->dev);
617 
618 	return ret;
619 }
620 
621 static int tegra30_ahub_remove(struct platform_device *pdev)
622 {
623 	if (!ahub)
624 		return -ENODEV;
625 
626 	pm_runtime_disable(&pdev->dev);
627 	if (!pm_runtime_status_suspended(&pdev->dev))
628 		tegra30_ahub_runtime_suspend(&pdev->dev);
629 
630 	return 0;
631 }
632 
633 #ifdef CONFIG_PM_SLEEP
634 static int tegra30_ahub_suspend(struct device *dev)
635 {
636 	regcache_mark_dirty(ahub->regmap_ahub);
637 	regcache_mark_dirty(ahub->regmap_apbif);
638 
639 	return 0;
640 }
641 
642 static int tegra30_ahub_resume(struct device *dev)
643 {
644 	int ret;
645 
646 	ret = pm_runtime_get_sync(dev);
647 	if (ret < 0)
648 		return ret;
649 	ret = regcache_sync(ahub->regmap_ahub);
650 	ret |= regcache_sync(ahub->regmap_apbif);
651 	pm_runtime_put(dev);
652 
653 	return ret;
654 }
655 #endif
656 
657 static const struct dev_pm_ops tegra30_ahub_pm_ops = {
658 	SET_RUNTIME_PM_OPS(tegra30_ahub_runtime_suspend,
659 			   tegra30_ahub_runtime_resume, NULL)
660 	SET_SYSTEM_SLEEP_PM_OPS(tegra30_ahub_suspend, tegra30_ahub_resume)
661 };
662 
663 static struct platform_driver tegra30_ahub_driver = {
664 	.probe = tegra30_ahub_probe,
665 	.remove = tegra30_ahub_remove,
666 	.driver = {
667 		.name = DRV_NAME,
668 		.of_match_table = tegra30_ahub_of_match,
669 		.pm = &tegra30_ahub_pm_ops,
670 	},
671 };
672 module_platform_driver(tegra30_ahub_driver);
673 
674 void tegra30_ahub_set_cif(struct regmap *regmap, unsigned int reg,
675 			  struct tegra30_ahub_cif_conf *conf)
676 {
677 	unsigned int value;
678 
679 	value = (conf->threshold <<
680 			TEGRA30_AUDIOCIF_CTRL_FIFO_THRESHOLD_SHIFT) |
681 		((conf->audio_channels - 1) <<
682 			TEGRA30_AUDIOCIF_CTRL_AUDIO_CHANNELS_SHIFT) |
683 		((conf->client_channels - 1) <<
684 			TEGRA30_AUDIOCIF_CTRL_CLIENT_CHANNELS_SHIFT) |
685 		(conf->audio_bits <<
686 			TEGRA30_AUDIOCIF_CTRL_AUDIO_BITS_SHIFT) |
687 		(conf->client_bits <<
688 			TEGRA30_AUDIOCIF_CTRL_CLIENT_BITS_SHIFT) |
689 		(conf->expand <<
690 			TEGRA30_AUDIOCIF_CTRL_EXPAND_SHIFT) |
691 		(conf->stereo_conv <<
692 			TEGRA30_AUDIOCIF_CTRL_STEREO_CONV_SHIFT) |
693 		(conf->replicate <<
694 			TEGRA30_AUDIOCIF_CTRL_REPLICATE_SHIFT) |
695 		(conf->direction <<
696 			TEGRA30_AUDIOCIF_CTRL_DIRECTION_SHIFT) |
697 		(conf->truncate <<
698 			TEGRA30_AUDIOCIF_CTRL_TRUNCATE_SHIFT) |
699 		(conf->mono_conv <<
700 			TEGRA30_AUDIOCIF_CTRL_MONO_CONV_SHIFT);
701 
702 	regmap_write(regmap, reg, value);
703 }
704 EXPORT_SYMBOL_GPL(tegra30_ahub_set_cif);
705 
706 void tegra124_ahub_set_cif(struct regmap *regmap, unsigned int reg,
707 			   struct tegra30_ahub_cif_conf *conf)
708 {
709 	unsigned int value;
710 
711 	value = (conf->threshold <<
712 			TEGRA124_AUDIOCIF_CTRL_FIFO_THRESHOLD_SHIFT) |
713 		((conf->audio_channels - 1) <<
714 			TEGRA124_AUDIOCIF_CTRL_AUDIO_CHANNELS_SHIFT) |
715 		((conf->client_channels - 1) <<
716 			TEGRA124_AUDIOCIF_CTRL_CLIENT_CHANNELS_SHIFT) |
717 		(conf->audio_bits <<
718 			TEGRA30_AUDIOCIF_CTRL_AUDIO_BITS_SHIFT) |
719 		(conf->client_bits <<
720 			TEGRA30_AUDIOCIF_CTRL_CLIENT_BITS_SHIFT) |
721 		(conf->expand <<
722 			TEGRA30_AUDIOCIF_CTRL_EXPAND_SHIFT) |
723 		(conf->stereo_conv <<
724 			TEGRA30_AUDIOCIF_CTRL_STEREO_CONV_SHIFT) |
725 		(conf->replicate <<
726 			TEGRA30_AUDIOCIF_CTRL_REPLICATE_SHIFT) |
727 		(conf->direction <<
728 			TEGRA30_AUDIOCIF_CTRL_DIRECTION_SHIFT) |
729 		(conf->truncate <<
730 			TEGRA30_AUDIOCIF_CTRL_TRUNCATE_SHIFT) |
731 		(conf->mono_conv <<
732 			TEGRA30_AUDIOCIF_CTRL_MONO_CONV_SHIFT);
733 
734 	regmap_write(regmap, reg, value);
735 }
736 EXPORT_SYMBOL_GPL(tegra124_ahub_set_cif);
737 
738 MODULE_AUTHOR("Stephen Warren <swarren@nvidia.com>");
739 MODULE_DESCRIPTION("Tegra30 AHUB driver");
740 MODULE_LICENSE("GPL v2");
741 MODULE_ALIAS("platform:" DRV_NAME);
742 MODULE_DEVICE_TABLE(of, tegra30_ahub_of_match);
743