adg.c 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655
  1. // SPDX-License-Identifier: GPL-2.0
  2. //
  3. // Helper routines for R-Car sound ADG.
  4. //
  5. // Copyright (C) 2013 Kuninori Morimoto <kuninori.morimoto.gx@renesas.com>
  6. #include <linux/clk-provider.h>
  7. #include "rsnd.h"
  8. #define CLKA 0
  9. #define CLKB 1
  10. #define CLKC 2
  11. #define CLKI 3
  12. #define CLKMAX 4
  13. #define CLKOUT 0
  14. #define CLKOUT1 1
  15. #define CLKOUT2 2
  16. #define CLKOUT3 3
  17. #define CLKOUTMAX 4
  18. #define BRRx_MASK(x) (0x3FF & x)
  19. static struct rsnd_mod_ops adg_ops = {
  20. .name = "adg",
  21. };
  22. struct rsnd_adg {
  23. struct clk *clk[CLKMAX];
  24. struct clk *clkout[CLKOUTMAX];
  25. struct clk_onecell_data onecell;
  26. struct rsnd_mod mod;
  27. int clk_rate[CLKMAX];
  28. u32 flags;
  29. u32 ckr;
  30. u32 rbga;
  31. u32 rbgb;
  32. int rbga_rate_for_441khz; /* RBGA */
  33. int rbgb_rate_for_48khz; /* RBGB */
  34. };
  35. #define LRCLK_ASYNC (1 << 0)
  36. #define AUDIO_OUT_48 (1 << 1)
  37. #define for_each_rsnd_clk(pos, adg, i) \
  38. for (i = 0; \
  39. (i < CLKMAX) && \
  40. ((pos) = adg->clk[i]); \
  41. i++)
  42. #define for_each_rsnd_clkout(pos, adg, i) \
  43. for (i = 0; \
  44. (i < CLKOUTMAX) && \
  45. ((pos) = adg->clkout[i]); \
  46. i++)
  47. #define rsnd_priv_to_adg(priv) ((struct rsnd_adg *)(priv)->adg)
  48. static const char * const clk_name[] = {
  49. [CLKA] = "clk_a",
  50. [CLKB] = "clk_b",
  51. [CLKC] = "clk_c",
  52. [CLKI] = "clk_i",
  53. };
  54. static u32 rsnd_adg_calculate_rbgx(unsigned long div)
  55. {
  56. int i, ratio;
  57. if (!div)
  58. return 0;
  59. for (i = 3; i >= 0; i--) {
  60. ratio = 2 << (i * 2);
  61. if (0 == (div % ratio))
  62. return (u32)((i << 8) | ((div / ratio) - 1));
  63. }
  64. return ~0;
  65. }
  66. static u32 rsnd_adg_ssi_ws_timing_gen2(struct rsnd_dai_stream *io)
  67. {
  68. struct rsnd_mod *ssi_mod = rsnd_io_to_mod_ssi(io);
  69. int id = rsnd_mod_id(ssi_mod);
  70. int ws = id;
  71. if (rsnd_ssi_is_pin_sharing(io)) {
  72. switch (id) {
  73. case 1:
  74. case 2:
  75. ws = 0;
  76. break;
  77. case 4:
  78. ws = 3;
  79. break;
  80. case 8:
  81. ws = 7;
  82. break;
  83. }
  84. }
  85. return (0x6 + ws) << 8;
  86. }
  87. static void __rsnd_adg_get_timesel_ratio(struct rsnd_priv *priv,
  88. struct rsnd_dai_stream *io,
  89. unsigned int target_rate,
  90. unsigned int *target_val,
  91. unsigned int *target_en)
  92. {
  93. struct rsnd_adg *adg = rsnd_priv_to_adg(priv);
  94. struct device *dev = rsnd_priv_to_dev(priv);
  95. int idx, sel, div, step;
  96. unsigned int val, en;
  97. unsigned int min, diff;
  98. unsigned int sel_rate[] = {
  99. adg->clk_rate[CLKA], /* 0000: CLKA */
  100. adg->clk_rate[CLKB], /* 0001: CLKB */
  101. adg->clk_rate[CLKC], /* 0010: CLKC */
  102. adg->rbga_rate_for_441khz, /* 0011: RBGA */
  103. adg->rbgb_rate_for_48khz, /* 0100: RBGB */
  104. };
  105. min = ~0;
  106. val = 0;
  107. en = 0;
  108. for (sel = 0; sel < ARRAY_SIZE(sel_rate); sel++) {
  109. idx = 0;
  110. step = 2;
  111. if (!sel_rate[sel])
  112. continue;
  113. for (div = 2; div <= 98304; div += step) {
  114. diff = abs(target_rate - sel_rate[sel] / div);
  115. if (min > diff) {
  116. val = (sel << 8) | idx;
  117. min = diff;
  118. en = 1 << (sel + 1); /* fixme */
  119. }
  120. /*
  121. * step of 0_0000 / 0_0001 / 0_1101
  122. * are out of order
  123. */
  124. if ((idx > 2) && (idx % 2))
  125. step *= 2;
  126. if (idx == 0x1c) {
  127. div += step;
  128. step *= 2;
  129. }
  130. idx++;
  131. }
  132. }
  133. if (min == ~0) {
  134. dev_err(dev, "no Input clock\n");
  135. return;
  136. }
  137. *target_val = val;
  138. if (target_en)
  139. *target_en = en;
  140. }
  141. static void rsnd_adg_get_timesel_ratio(struct rsnd_priv *priv,
  142. struct rsnd_dai_stream *io,
  143. unsigned int in_rate,
  144. unsigned int out_rate,
  145. u32 *in, u32 *out, u32 *en)
  146. {
  147. struct snd_pcm_runtime *runtime = rsnd_io_to_runtime(io);
  148. unsigned int target_rate;
  149. u32 *target_val;
  150. u32 _in;
  151. u32 _out;
  152. u32 _en;
  153. /* default = SSI WS */
  154. _in =
  155. _out = rsnd_adg_ssi_ws_timing_gen2(io);
  156. target_rate = 0;
  157. target_val = NULL;
  158. _en = 0;
  159. if (runtime->rate != in_rate) {
  160. target_rate = out_rate;
  161. target_val = &_out;
  162. } else if (runtime->rate != out_rate) {
  163. target_rate = in_rate;
  164. target_val = &_in;
  165. }
  166. if (target_rate)
  167. __rsnd_adg_get_timesel_ratio(priv, io,
  168. target_rate,
  169. target_val, &_en);
  170. if (in)
  171. *in = _in;
  172. if (out)
  173. *out = _out;
  174. if (en)
  175. *en = _en;
  176. }
  177. int rsnd_adg_set_cmd_timsel_gen2(struct rsnd_mod *cmd_mod,
  178. struct rsnd_dai_stream *io)
  179. {
  180. struct rsnd_priv *priv = rsnd_mod_to_priv(cmd_mod);
  181. struct rsnd_adg *adg = rsnd_priv_to_adg(priv);
  182. struct rsnd_mod *adg_mod = rsnd_mod_get(adg);
  183. int id = rsnd_mod_id(cmd_mod);
  184. int shift = (id % 2) ? 16 : 0;
  185. u32 mask, val;
  186. rsnd_adg_get_timesel_ratio(priv, io,
  187. rsnd_src_get_in_rate(priv, io),
  188. rsnd_src_get_out_rate(priv, io),
  189. NULL, &val, NULL);
  190. val = val << shift;
  191. mask = 0x0f1f << shift;
  192. rsnd_mod_bset(adg_mod, CMDOUT_TIMSEL, mask, val);
  193. return 0;
  194. }
  195. int rsnd_adg_set_src_timesel_gen2(struct rsnd_mod *src_mod,
  196. struct rsnd_dai_stream *io,
  197. unsigned int in_rate,
  198. unsigned int out_rate)
  199. {
  200. struct rsnd_priv *priv = rsnd_mod_to_priv(src_mod);
  201. struct rsnd_adg *adg = rsnd_priv_to_adg(priv);
  202. struct rsnd_mod *adg_mod = rsnd_mod_get(adg);
  203. u32 in, out;
  204. u32 mask, en;
  205. int id = rsnd_mod_id(src_mod);
  206. int shift = (id % 2) ? 16 : 0;
  207. rsnd_mod_confirm_src(src_mod);
  208. rsnd_adg_get_timesel_ratio(priv, io,
  209. in_rate, out_rate,
  210. &in, &out, &en);
  211. in = in << shift;
  212. out = out << shift;
  213. mask = 0x0f1f << shift;
  214. switch (id / 2) {
  215. case 0:
  216. rsnd_mod_bset(adg_mod, SRCIN_TIMSEL0, mask, in);
  217. rsnd_mod_bset(adg_mod, SRCOUT_TIMSEL0, mask, out);
  218. break;
  219. case 1:
  220. rsnd_mod_bset(adg_mod, SRCIN_TIMSEL1, mask, in);
  221. rsnd_mod_bset(adg_mod, SRCOUT_TIMSEL1, mask, out);
  222. break;
  223. case 2:
  224. rsnd_mod_bset(adg_mod, SRCIN_TIMSEL2, mask, in);
  225. rsnd_mod_bset(adg_mod, SRCOUT_TIMSEL2, mask, out);
  226. break;
  227. case 3:
  228. rsnd_mod_bset(adg_mod, SRCIN_TIMSEL3, mask, in);
  229. rsnd_mod_bset(adg_mod, SRCOUT_TIMSEL3, mask, out);
  230. break;
  231. case 4:
  232. rsnd_mod_bset(adg_mod, SRCIN_TIMSEL4, mask, in);
  233. rsnd_mod_bset(adg_mod, SRCOUT_TIMSEL4, mask, out);
  234. break;
  235. }
  236. if (en)
  237. rsnd_mod_bset(adg_mod, DIV_EN, en, en);
  238. return 0;
  239. }
  240. static void rsnd_adg_set_ssi_clk(struct rsnd_mod *ssi_mod, u32 val)
  241. {
  242. struct rsnd_priv *priv = rsnd_mod_to_priv(ssi_mod);
  243. struct rsnd_adg *adg = rsnd_priv_to_adg(priv);
  244. struct rsnd_mod *adg_mod = rsnd_mod_get(adg);
  245. struct device *dev = rsnd_priv_to_dev(priv);
  246. int id = rsnd_mod_id(ssi_mod);
  247. int shift = (id % 4) * 8;
  248. u32 mask = 0xFF << shift;
  249. rsnd_mod_confirm_ssi(ssi_mod);
  250. val = val << shift;
  251. /*
  252. * SSI 8 is not connected to ADG.
  253. * it works with SSI 7
  254. */
  255. if (id == 8)
  256. return;
  257. switch (id / 4) {
  258. case 0:
  259. rsnd_mod_bset(adg_mod, AUDIO_CLK_SEL0, mask, val);
  260. break;
  261. case 1:
  262. rsnd_mod_bset(adg_mod, AUDIO_CLK_SEL1, mask, val);
  263. break;
  264. case 2:
  265. rsnd_mod_bset(adg_mod, AUDIO_CLK_SEL2, mask, val);
  266. break;
  267. }
  268. dev_dbg(dev, "AUDIO_CLK_SEL is 0x%x\n", val);
  269. }
  270. int rsnd_adg_clk_query(struct rsnd_priv *priv, unsigned int rate)
  271. {
  272. struct rsnd_adg *adg = rsnd_priv_to_adg(priv);
  273. struct clk *clk;
  274. int i;
  275. int sel_table[] = {
  276. [CLKA] = 0x1,
  277. [CLKB] = 0x2,
  278. [CLKC] = 0x3,
  279. [CLKI] = 0x0,
  280. };
  281. /*
  282. * find suitable clock from
  283. * AUDIO_CLKA/AUDIO_CLKB/AUDIO_CLKC/AUDIO_CLKI.
  284. */
  285. for_each_rsnd_clk(clk, adg, i) {
  286. if (rate == adg->clk_rate[i])
  287. return sel_table[i];
  288. }
  289. /*
  290. * find divided clock from BRGA/BRGB
  291. */
  292. if (rate == adg->rbga_rate_for_441khz)
  293. return 0x10;
  294. if (rate == adg->rbgb_rate_for_48khz)
  295. return 0x20;
  296. return -EIO;
  297. }
  298. int rsnd_adg_ssi_clk_stop(struct rsnd_mod *ssi_mod)
  299. {
  300. rsnd_adg_set_ssi_clk(ssi_mod, 0);
  301. return 0;
  302. }
  303. int rsnd_adg_ssi_clk_try_start(struct rsnd_mod *ssi_mod, unsigned int rate)
  304. {
  305. struct rsnd_priv *priv = rsnd_mod_to_priv(ssi_mod);
  306. struct rsnd_adg *adg = rsnd_priv_to_adg(priv);
  307. struct device *dev = rsnd_priv_to_dev(priv);
  308. struct rsnd_mod *adg_mod = rsnd_mod_get(adg);
  309. int data;
  310. u32 ckr = 0;
  311. data = rsnd_adg_clk_query(priv, rate);
  312. if (data < 0)
  313. return data;
  314. rsnd_adg_set_ssi_clk(ssi_mod, data);
  315. if (rsnd_flags_has(adg, LRCLK_ASYNC)) {
  316. if (rsnd_flags_has(adg, AUDIO_OUT_48))
  317. ckr = 0x80000000;
  318. } else {
  319. if (0 == (rate % 8000))
  320. ckr = 0x80000000;
  321. }
  322. rsnd_mod_bset(adg_mod, BRGCKR, 0x80770000, adg->ckr | ckr);
  323. rsnd_mod_write(adg_mod, BRRA, adg->rbga);
  324. rsnd_mod_write(adg_mod, BRRB, adg->rbgb);
  325. dev_dbg(dev, "CLKOUT is based on BRG%c (= %dHz)\n",
  326. (ckr) ? 'B' : 'A',
  327. (ckr) ? adg->rbgb_rate_for_48khz :
  328. adg->rbga_rate_for_441khz);
  329. return 0;
  330. }
  331. void rsnd_adg_clk_control(struct rsnd_priv *priv, int enable)
  332. {
  333. struct rsnd_adg *adg = rsnd_priv_to_adg(priv);
  334. struct device *dev = rsnd_priv_to_dev(priv);
  335. struct clk *clk;
  336. int i, ret;
  337. for_each_rsnd_clk(clk, adg, i) {
  338. ret = 0;
  339. if (enable) {
  340. ret = clk_prepare_enable(clk);
  341. /*
  342. * We shouldn't use clk_get_rate() under
  343. * atomic context. Let's keep it when
  344. * rsnd_adg_clk_enable() was called
  345. */
  346. adg->clk_rate[i] = clk_get_rate(adg->clk[i]);
  347. } else {
  348. clk_disable_unprepare(clk);
  349. }
  350. if (ret < 0)
  351. dev_warn(dev, "can't use clk %d\n", i);
  352. }
  353. }
  354. static void rsnd_adg_get_clkin(struct rsnd_priv *priv,
  355. struct rsnd_adg *adg)
  356. {
  357. struct device *dev = rsnd_priv_to_dev(priv);
  358. struct clk *clk;
  359. int i;
  360. for (i = 0; i < CLKMAX; i++) {
  361. clk = devm_clk_get(dev, clk_name[i]);
  362. adg->clk[i] = IS_ERR(clk) ? NULL : clk;
  363. }
  364. }
  365. static void rsnd_adg_get_clkout(struct rsnd_priv *priv,
  366. struct rsnd_adg *adg)
  367. {
  368. struct clk *clk;
  369. struct device *dev = rsnd_priv_to_dev(priv);
  370. struct device_node *np = dev->of_node;
  371. struct property *prop;
  372. u32 ckr, rbgx, rbga, rbgb;
  373. u32 rate, div;
  374. #define REQ_SIZE 2
  375. u32 req_rate[REQ_SIZE] = {};
  376. uint32_t count = 0;
  377. unsigned long req_48kHz_rate, req_441kHz_rate;
  378. int i, req_size;
  379. const char *parent_clk_name = NULL;
  380. static const char * const clkout_name[] = {
  381. [CLKOUT] = "audio_clkout",
  382. [CLKOUT1] = "audio_clkout1",
  383. [CLKOUT2] = "audio_clkout2",
  384. [CLKOUT3] = "audio_clkout3",
  385. };
  386. int brg_table[] = {
  387. [CLKA] = 0x0,
  388. [CLKB] = 0x1,
  389. [CLKC] = 0x4,
  390. [CLKI] = 0x2,
  391. };
  392. ckr = 0;
  393. rbga = 2; /* default 1/6 */
  394. rbgb = 2; /* default 1/6 */
  395. /*
  396. * ADG supports BRRA/BRRB output only
  397. * this means all clkout0/1/2/3 will be same rate
  398. */
  399. prop = of_find_property(np, "clock-frequency", NULL);
  400. if (!prop)
  401. goto rsnd_adg_get_clkout_end;
  402. req_size = prop->length / sizeof(u32);
  403. if (req_size > REQ_SIZE) {
  404. dev_err(dev,
  405. "too many clock-frequency, use top %d\n", REQ_SIZE);
  406. req_size = REQ_SIZE;
  407. }
  408. of_property_read_u32_array(np, "clock-frequency", req_rate, req_size);
  409. req_48kHz_rate = 0;
  410. req_441kHz_rate = 0;
  411. for (i = 0; i < req_size; i++) {
  412. if (0 == (req_rate[i] % 44100))
  413. req_441kHz_rate = req_rate[i];
  414. if (0 == (req_rate[i] % 48000))
  415. req_48kHz_rate = req_rate[i];
  416. }
  417. if (req_rate[0] % 48000 == 0)
  418. rsnd_flags_set(adg, AUDIO_OUT_48);
  419. if (of_get_property(np, "clkout-lr-asynchronous", NULL))
  420. rsnd_flags_set(adg, LRCLK_ASYNC);
  421. /*
  422. * This driver is assuming that AUDIO_CLKA/AUDIO_CLKB/AUDIO_CLKC
  423. * have 44.1kHz or 48kHz base clocks for now.
  424. *
  425. * SSI itself can divide parent clock by 1/1 - 1/16
  426. * see
  427. * rsnd_adg_ssi_clk_try_start()
  428. * rsnd_ssi_master_clk_start()
  429. */
  430. adg->rbga_rate_for_441khz = 0;
  431. adg->rbgb_rate_for_48khz = 0;
  432. for_each_rsnd_clk(clk, adg, i) {
  433. rate = clk_get_rate(clk);
  434. if (0 == rate) /* not used */
  435. continue;
  436. /* RBGA */
  437. if (!adg->rbga_rate_for_441khz && (0 == rate % 44100)) {
  438. div = 6;
  439. if (req_441kHz_rate)
  440. div = rate / req_441kHz_rate;
  441. rbgx = rsnd_adg_calculate_rbgx(div);
  442. if (BRRx_MASK(rbgx) == rbgx) {
  443. rbga = rbgx;
  444. adg->rbga_rate_for_441khz = rate / div;
  445. ckr |= brg_table[i] << 20;
  446. if (req_441kHz_rate &&
  447. !rsnd_flags_has(adg, AUDIO_OUT_48))
  448. parent_clk_name = __clk_get_name(clk);
  449. }
  450. }
  451. /* RBGB */
  452. if (!adg->rbgb_rate_for_48khz && (0 == rate % 48000)) {
  453. div = 6;
  454. if (req_48kHz_rate)
  455. div = rate / req_48kHz_rate;
  456. rbgx = rsnd_adg_calculate_rbgx(div);
  457. if (BRRx_MASK(rbgx) == rbgx) {
  458. rbgb = rbgx;
  459. adg->rbgb_rate_for_48khz = rate / div;
  460. ckr |= brg_table[i] << 16;
  461. if (req_48kHz_rate &&
  462. rsnd_flags_has(adg, AUDIO_OUT_48))
  463. parent_clk_name = __clk_get_name(clk);
  464. }
  465. }
  466. }
  467. /*
  468. * ADG supports BRRA/BRRB output only.
  469. * this means all clkout0/1/2/3 will be * same rate
  470. */
  471. of_property_read_u32(np, "#clock-cells", &count);
  472. /*
  473. * for clkout
  474. */
  475. if (!count) {
  476. clk = clk_register_fixed_rate(dev, clkout_name[CLKOUT],
  477. parent_clk_name, 0, req_rate[0]);
  478. if (!IS_ERR(clk)) {
  479. adg->clkout[CLKOUT] = clk;
  480. of_clk_add_provider(np, of_clk_src_simple_get, clk);
  481. }
  482. }
  483. /*
  484. * for clkout0/1/2/3
  485. */
  486. else {
  487. for (i = 0; i < CLKOUTMAX; i++) {
  488. clk = clk_register_fixed_rate(dev, clkout_name[i],
  489. parent_clk_name, 0,
  490. req_rate[0]);
  491. if (!IS_ERR(clk))
  492. adg->clkout[i] = clk;
  493. }
  494. adg->onecell.clks = adg->clkout;
  495. adg->onecell.clk_num = CLKOUTMAX;
  496. of_clk_add_provider(np, of_clk_src_onecell_get,
  497. &adg->onecell);
  498. }
  499. rsnd_adg_get_clkout_end:
  500. adg->ckr = ckr;
  501. adg->rbga = rbga;
  502. adg->rbgb = rbgb;
  503. }
  504. #ifdef DEBUG
  505. static void rsnd_adg_clk_dbg_info(struct rsnd_priv *priv, struct rsnd_adg *adg)
  506. {
  507. struct device *dev = rsnd_priv_to_dev(priv);
  508. struct clk *clk;
  509. int i;
  510. for_each_rsnd_clk(clk, adg, i)
  511. dev_dbg(dev, "%s : %p : %ld\n",
  512. clk_name[i], clk, clk_get_rate(clk));
  513. dev_dbg(dev, "BRGCKR = 0x%08x, BRRA/BRRB = 0x%x/0x%x\n",
  514. adg->ckr, adg->rbga, adg->rbgb);
  515. dev_dbg(dev, "BRGA (for 44100 base) = %d\n", adg->rbga_rate_for_441khz);
  516. dev_dbg(dev, "BRGB (for 48000 base) = %d\n", adg->rbgb_rate_for_48khz);
  517. /*
  518. * Actual CLKOUT will be exchanged in rsnd_adg_ssi_clk_try_start()
  519. * by BRGCKR::BRGCKR_31
  520. */
  521. for_each_rsnd_clkout(clk, adg, i)
  522. dev_dbg(dev, "clkout %d : %p : %ld\n", i,
  523. clk, clk_get_rate(clk));
  524. }
  525. #else
  526. #define rsnd_adg_clk_dbg_info(priv, adg)
  527. #endif
  528. int rsnd_adg_probe(struct rsnd_priv *priv)
  529. {
  530. struct rsnd_adg *adg;
  531. struct device *dev = rsnd_priv_to_dev(priv);
  532. int ret;
  533. adg = devm_kzalloc(dev, sizeof(*adg), GFP_KERNEL);
  534. if (!adg)
  535. return -ENOMEM;
  536. ret = rsnd_mod_init(priv, &adg->mod, &adg_ops,
  537. NULL, NULL, 0, 0);
  538. if (ret)
  539. return ret;
  540. rsnd_adg_get_clkin(priv, adg);
  541. rsnd_adg_get_clkout(priv, adg);
  542. rsnd_adg_clk_dbg_info(priv, adg);
  543. priv->adg = adg;
  544. rsnd_adg_clk_enable(priv);
  545. return 0;
  546. }
  547. void rsnd_adg_remove(struct rsnd_priv *priv)
  548. {
  549. struct device *dev = rsnd_priv_to_dev(priv);
  550. struct device_node *np = dev->of_node;
  551. struct rsnd_adg *adg = priv->adg;
  552. struct clk *clk;
  553. int i;
  554. for_each_rsnd_clkout(clk, adg, i)
  555. if (adg->clkout[i])
  556. clk_unregister_fixed_rate(adg->clkout[i]);
  557. of_clk_del_provider(np);
  558. rsnd_adg_clk_disable(priv);
  559. }