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
23static struct tegra30_ahub *ahub;
24
25static inline void tegra30_apbif_write(u32 reg, u32 val)
26{
27	regmap_write(ahub->regmap_apbif, reg, val);
28}
29
30static 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
38static inline void tegra30_audio_write(u32 reg, u32 val)
39{
40	regmap_write(ahub->regmap_ahub, reg, val);
41}
42
43static 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 */
65static 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
87int 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}
139EXPORT_SYMBOL_GPL(tegra30_ahub_allocate_rx_fifo);
140
141int 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}
158EXPORT_SYMBOL_GPL(tegra30_ahub_enable_rx_fifo);
159
160int 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}
177EXPORT_SYMBOL_GPL(tegra30_ahub_disable_rx_fifo);
178
179int 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}
187EXPORT_SYMBOL_GPL(tegra30_ahub_free_rx_fifo);
188
189int 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}
241EXPORT_SYMBOL_GPL(tegra30_ahub_allocate_tx_fifo);
242
243int 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}
260EXPORT_SYMBOL_GPL(tegra30_ahub_enable_tx_fifo);
261
262int 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}
279EXPORT_SYMBOL_GPL(tegra30_ahub_disable_tx_fifo);
280
281int 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}
289EXPORT_SYMBOL_GPL(tegra30_ahub_free_tx_fifo);
290
291int 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}
307EXPORT_SYMBOL_GPL(tegra30_ahub_set_rx_cif_source);
308
309int 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}
324EXPORT_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
336static 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
370static 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
412static 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
444static 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
454static 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
467static 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
475static 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
486static 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
491static 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
496static 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
501static 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
508static 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
614err_pm_disable:
615	pm_runtime_disable(&pdev->dev);
616
617	return ret;
618}
619
620static 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
633static 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
641static 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
658static 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
664static 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};
673module_platform_driver(tegra30_ahub_driver);
674
675void 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}
705EXPORT_SYMBOL_GPL(tegra30_ahub_set_cif);
706
707void 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}
737EXPORT_SYMBOL_GPL(tegra124_ahub_set_cif);
738
739MODULE_AUTHOR("Stephen Warren <swarren@nvidia.com>");
740MODULE_DESCRIPTION("Tegra30 AHUB driver");
741MODULE_LICENSE("GPL v2");
742MODULE_ALIAS("platform:" DRV_NAME);
743MODULE_DEVICE_TABLE(of, tegra30_ahub_of_match);
744