tegra30_ahub.c 18 KB

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