btfm_slim_wcn3990.c 5.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200
  1. /* Copyright (c) 2016-2017, The Linux Foundation. All rights reserved.
  2. *
  3. * This program is free software; you can redistribute it and/or modify
  4. * it under the terms of the GNU General Public License version 2 and
  5. * only version 2 as published by the Free Software Foundation.
  6. *
  7. * This program is distributed in the hope that it will be useful,
  8. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  9. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  10. * GNU General Public License for more details.
  11. */
  12. #include <linux/slimbus/slimbus.h>
  13. #include "btfm_slim.h"
  14. #include "btfm_slim_wcn3990.h"
  15. /* WCN3990 Port assignment */
  16. struct btfmslim_ch wcn3990_rxport[] = {
  17. {.id = BTFM_BT_SCO_A2DP_SLIM_RX, .name = "SCO_A2P_Rx",
  18. .port = CHRK_SB_PGD_PORT_RX_SCO},
  19. {.id = BTFM_BT_SPLIT_A2DP_SLIM_RX, .name = "A2P_Rx",
  20. .port = CHRK_SB_PGD_PORT_RX_A2P},
  21. {.id = BTFM_SLIM_NUM_CODEC_DAIS, .name = "",
  22. .port = BTFM_SLIM_PGD_PORT_LAST},
  23. };
  24. struct btfmslim_ch wcn3990_txport[] = {
  25. {.id = BTFM_FM_SLIM_TX, .name = "FM_Tx1",
  26. .port = CHRK_SB_PGD_PORT_TX1_FM},
  27. {.id = BTFM_FM_SLIM_TX, .name = "FM_Tx2",
  28. .port = CHRK_SB_PGD_PORT_TX2_FM},
  29. {.id = BTFM_BT_SCO_SLIM_TX, .name = "SCO_Tx",
  30. .port = CHRK_SB_PGD_PORT_TX_SCO},
  31. {.id = BTFM_SLIM_NUM_CODEC_DAIS, .name = "",
  32. .port = BTFM_SLIM_PGD_PORT_LAST},
  33. };
  34. /* Function description */
  35. int btfm_slim_chrk_hw_init(struct btfmslim *btfmslim)
  36. {
  37. int ret = 0;
  38. uint8_t reg_val;
  39. uint16_t reg;
  40. BTFMSLIM_DBG("");
  41. if (!btfmslim)
  42. return -EINVAL;
  43. /* Get SB_SLAVE_HW_REV_MSB value*/
  44. reg = CHRK_SB_SLAVE_HW_REV_MSB;
  45. ret = btfm_slim_read(btfmslim, reg, 1, &reg_val, IFD);
  46. if (ret) {
  47. BTFMSLIM_ERR("failed to read (%d) reg 0x%x", ret, reg);
  48. goto error;
  49. }
  50. BTFMSLIM_DBG("Major Rev: 0x%x, Minor Rev: 0x%x",
  51. (reg_val & 0xF0) >> 4, (reg_val & 0x0F));
  52. /* Get SB_SLAVE_HW_REV_LSB value*/
  53. reg = CHRK_SB_SLAVE_HW_REV_LSB;
  54. ret = btfm_slim_read(btfmslim, reg, 1, &reg_val, IFD);
  55. if (ret) {
  56. BTFMSLIM_ERR("failed to read (%d) reg 0x%x", ret, reg);
  57. goto error;
  58. }
  59. BTFMSLIM_DBG("Step Rev: 0x%x", reg_val);
  60. error:
  61. return ret;
  62. }
  63. static inline int is_fm_port(uint8_t port_num)
  64. {
  65. if (port_num == CHRK_SB_PGD_PORT_TX1_FM ||
  66. port_num == CHRK_SB_PGD_PORT_TX2_FM)
  67. return 1;
  68. else
  69. return 0;
  70. }
  71. int btfm_slim_chrk_enable_port(struct btfmslim *btfmslim, uint8_t port_num,
  72. uint8_t rxport, uint8_t enable)
  73. {
  74. int ret = 0;
  75. uint8_t reg_val = 0, en;
  76. uint8_t rxport_num = 0;
  77. uint16_t reg;
  78. uint8_t prev_reg_val = 0;
  79. BTFMSLIM_DBG("port(%d) enable(%d)", port_num, enable);
  80. if (rxport) {
  81. BTFMSLIM_DBG("sample rate is %d", btfmslim->sample_rate);
  82. if (enable) {
  83. /* For SCO Rx, A2DP Rx other than 44.1 and 88.2Khz */
  84. if (port_num < 24) {
  85. rxport_num = port_num - 16;
  86. reg_val = 0x01 << rxport_num;
  87. reg = CHRK_SB_PGD_RX_PORTn_MULTI_CHNL_0(
  88. rxport_num);
  89. } else {
  90. rxport_num = port_num - 24;
  91. reg_val = 0x01 << rxport_num;
  92. reg = CHRK_SB_PGD_RX_PORTn_MULTI_CHNL_1(
  93. rxport_num);
  94. }
  95. if (btfmslim->sample_rate == 44100 ||
  96. btfmslim->sample_rate == 88200) {
  97. BTFMSLIM_DBG("unsetting multichannel bit");
  98. ret = btfm_slim_read(btfmslim, reg, 1,
  99. &prev_reg_val, IFD);
  100. if (ret < 0) {
  101. BTFMSLIM_ERR("error %d reading", ret);
  102. prev_reg_val = 0;
  103. }
  104. BTFMSLIM_DBG("prev_reg_val (%d) from reg(%x)",
  105. prev_reg_val, reg);
  106. reg_val = prev_reg_val & ~reg_val;
  107. } else
  108. BTFMSLIM_DBG("setting multichannel bit");
  109. BTFMSLIM_DBG("writing reg_val (%d) to reg(%x)",
  110. reg_val, reg);
  111. ret = btfm_slim_write(btfmslim, reg, 1, &reg_val, IFD);
  112. if (ret) {
  113. BTFMSLIM_ERR("failed to write (%d) reg 0x%x",
  114. ret, reg);
  115. goto error;
  116. }
  117. }
  118. /* Port enable */
  119. reg = CHRK_SB_PGD_PORT_RX_CFGN(port_num - 0x10);
  120. goto enable_disable_rxport;
  121. }
  122. if (!enable)
  123. goto enable_disable_txport;
  124. /* txport */
  125. /* Multiple Channel Setting */
  126. if (is_fm_port(port_num)) {
  127. reg_val = (0x1 << CHRK_SB_PGD_PORT_TX1_FM) |
  128. (0x1 << CHRK_SB_PGD_PORT_TX2_FM);
  129. reg = CHRK_SB_PGD_TX_PORTn_MULTI_CHNL_0(port_num);
  130. ret = btfm_slim_write(btfmslim, reg, 1, &reg_val, IFD);
  131. if (ret) {
  132. BTFMSLIM_ERR("failed to write (%d) reg 0x%x", ret, reg);
  133. goto error;
  134. }
  135. } else if (port_num == CHRK_SB_PGD_PORT_TX_SCO) {
  136. /* SCO Tx */
  137. reg_val = 0x1 << CHRK_SB_PGD_PORT_TX_SCO;
  138. reg = CHRK_SB_PGD_TX_PORTn_MULTI_CHNL_0(port_num);
  139. BTFMSLIM_DBG("writing reg_val (%d) to reg(%x)",
  140. reg_val, reg);
  141. ret = btfm_slim_write(btfmslim, reg, 1, &reg_val, IFD);
  142. if (ret) {
  143. BTFMSLIM_ERR("failed to write (%d) reg 0x%x",
  144. ret, reg);
  145. goto error;
  146. }
  147. }
  148. /* Enable Tx port hw auto recovery for underrun or overrun error */
  149. reg_val = (CHRK_ENABLE_OVERRUN_AUTO_RECOVERY |
  150. CHRK_ENABLE_UNDERRUN_AUTO_RECOVERY);
  151. reg = CHRK_SB_PGD_PORT_TX_OR_UR_CFGN(port_num);
  152. ret = btfm_slim_write(btfmslim, reg, 1, &reg_val, IFD);
  153. if (ret) {
  154. BTFMSLIM_ERR("failed to write (%d) reg 0x%x", ret, reg);
  155. goto error;
  156. }
  157. enable_disable_txport:
  158. /* Port enable */
  159. reg = CHRK_SB_PGD_PORT_TX_CFGN(port_num);
  160. enable_disable_rxport:
  161. if (enable)
  162. en = CHRK_SB_PGD_PORT_ENABLE;
  163. else
  164. en = CHRK_SB_PGD_PORT_DISABLE;
  165. if (is_fm_port(port_num))
  166. reg_val = en | CHRK_SB_PGD_PORT_WM_L8;
  167. else if (port_num == CHRK_SB_PGD_PORT_TX_SCO)
  168. reg_val = enable ? en | CHRK_SB_PGD_PORT_WM_L1 : en;
  169. else
  170. reg_val = enable ? en | CHRK_SB_PGD_PORT_WM_LB : en;
  171. if (enable && port_num == CHRK_SB_PGD_PORT_TX_SCO)
  172. BTFMSLIM_INFO("programming SCO Tx with reg_val %d to reg 0x%x",
  173. reg_val, reg);
  174. ret = btfm_slim_write(btfmslim, reg, 1, &reg_val, IFD);
  175. if (ret)
  176. BTFMSLIM_ERR("failed to write (%d) reg 0x%x", ret, reg);
  177. error:
  178. return ret;
  179. }