123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200 |
- /* Copyright (c) 2016-2017, The Linux Foundation. All rights reserved.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 and
- * only version 2 as published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- */
- #include <linux/slimbus/slimbus.h>
- #include "btfm_slim.h"
- #include "btfm_slim_wcn3990.h"
- /* WCN3990 Port assignment */
- struct btfmslim_ch wcn3990_rxport[] = {
- {.id = BTFM_BT_SCO_A2DP_SLIM_RX, .name = "SCO_A2P_Rx",
- .port = CHRK_SB_PGD_PORT_RX_SCO},
- {.id = BTFM_BT_SPLIT_A2DP_SLIM_RX, .name = "A2P_Rx",
- .port = CHRK_SB_PGD_PORT_RX_A2P},
- {.id = BTFM_SLIM_NUM_CODEC_DAIS, .name = "",
- .port = BTFM_SLIM_PGD_PORT_LAST},
- };
- struct btfmslim_ch wcn3990_txport[] = {
- {.id = BTFM_FM_SLIM_TX, .name = "FM_Tx1",
- .port = CHRK_SB_PGD_PORT_TX1_FM},
- {.id = BTFM_FM_SLIM_TX, .name = "FM_Tx2",
- .port = CHRK_SB_PGD_PORT_TX2_FM},
- {.id = BTFM_BT_SCO_SLIM_TX, .name = "SCO_Tx",
- .port = CHRK_SB_PGD_PORT_TX_SCO},
- {.id = BTFM_SLIM_NUM_CODEC_DAIS, .name = "",
- .port = BTFM_SLIM_PGD_PORT_LAST},
- };
- /* Function description */
- int btfm_slim_chrk_hw_init(struct btfmslim *btfmslim)
- {
- int ret = 0;
- uint8_t reg_val;
- uint16_t reg;
- BTFMSLIM_DBG("");
- if (!btfmslim)
- return -EINVAL;
- /* Get SB_SLAVE_HW_REV_MSB value*/
- reg = CHRK_SB_SLAVE_HW_REV_MSB;
- ret = btfm_slim_read(btfmslim, reg, 1, ®_val, IFD);
- if (ret) {
- BTFMSLIM_ERR("failed to read (%d) reg 0x%x", ret, reg);
- goto error;
- }
- BTFMSLIM_DBG("Major Rev: 0x%x, Minor Rev: 0x%x",
- (reg_val & 0xF0) >> 4, (reg_val & 0x0F));
- /* Get SB_SLAVE_HW_REV_LSB value*/
- reg = CHRK_SB_SLAVE_HW_REV_LSB;
- ret = btfm_slim_read(btfmslim, reg, 1, ®_val, IFD);
- if (ret) {
- BTFMSLIM_ERR("failed to read (%d) reg 0x%x", ret, reg);
- goto error;
- }
- BTFMSLIM_DBG("Step Rev: 0x%x", reg_val);
- error:
- return ret;
- }
- static inline int is_fm_port(uint8_t port_num)
- {
- if (port_num == CHRK_SB_PGD_PORT_TX1_FM ||
- port_num == CHRK_SB_PGD_PORT_TX2_FM)
- return 1;
- else
- return 0;
- }
- int btfm_slim_chrk_enable_port(struct btfmslim *btfmslim, uint8_t port_num,
- uint8_t rxport, uint8_t enable)
- {
- int ret = 0;
- uint8_t reg_val = 0, en;
- uint8_t rxport_num = 0;
- uint16_t reg;
- uint8_t prev_reg_val = 0;
- BTFMSLIM_DBG("port(%d) enable(%d)", port_num, enable);
- if (rxport) {
- BTFMSLIM_DBG("sample rate is %d", btfmslim->sample_rate);
- if (enable) {
- /* For SCO Rx, A2DP Rx other than 44.1 and 88.2Khz */
- if (port_num < 24) {
- rxport_num = port_num - 16;
- reg_val = 0x01 << rxport_num;
- reg = CHRK_SB_PGD_RX_PORTn_MULTI_CHNL_0(
- rxport_num);
- } else {
- rxport_num = port_num - 24;
- reg_val = 0x01 << rxport_num;
- reg = CHRK_SB_PGD_RX_PORTn_MULTI_CHNL_1(
- rxport_num);
- }
- if (btfmslim->sample_rate == 44100 ||
- btfmslim->sample_rate == 88200) {
- BTFMSLIM_DBG("unsetting multichannel bit");
- ret = btfm_slim_read(btfmslim, reg, 1,
- &prev_reg_val, IFD);
- if (ret < 0) {
- BTFMSLIM_ERR("error %d reading", ret);
- prev_reg_val = 0;
- }
- BTFMSLIM_DBG("prev_reg_val (%d) from reg(%x)",
- prev_reg_val, reg);
- reg_val = prev_reg_val & ~reg_val;
- } else
- BTFMSLIM_DBG("setting multichannel bit");
- BTFMSLIM_DBG("writing reg_val (%d) to reg(%x)",
- reg_val, reg);
- ret = btfm_slim_write(btfmslim, reg, 1, ®_val, IFD);
- if (ret) {
- BTFMSLIM_ERR("failed to write (%d) reg 0x%x",
- ret, reg);
- goto error;
- }
- }
- /* Port enable */
- reg = CHRK_SB_PGD_PORT_RX_CFGN(port_num - 0x10);
- goto enable_disable_rxport;
- }
- if (!enable)
- goto enable_disable_txport;
- /* txport */
- /* Multiple Channel Setting */
- if (is_fm_port(port_num)) {
- reg_val = (0x1 << CHRK_SB_PGD_PORT_TX1_FM) |
- (0x1 << CHRK_SB_PGD_PORT_TX2_FM);
- reg = CHRK_SB_PGD_TX_PORTn_MULTI_CHNL_0(port_num);
- ret = btfm_slim_write(btfmslim, reg, 1, ®_val, IFD);
- if (ret) {
- BTFMSLIM_ERR("failed to write (%d) reg 0x%x", ret, reg);
- goto error;
- }
- } else if (port_num == CHRK_SB_PGD_PORT_TX_SCO) {
- /* SCO Tx */
- reg_val = 0x1 << CHRK_SB_PGD_PORT_TX_SCO;
- reg = CHRK_SB_PGD_TX_PORTn_MULTI_CHNL_0(port_num);
- BTFMSLIM_DBG("writing reg_val (%d) to reg(%x)",
- reg_val, reg);
- ret = btfm_slim_write(btfmslim, reg, 1, ®_val, IFD);
- if (ret) {
- BTFMSLIM_ERR("failed to write (%d) reg 0x%x",
- ret, reg);
- goto error;
- }
- }
- /* Enable Tx port hw auto recovery for underrun or overrun error */
- reg_val = (CHRK_ENABLE_OVERRUN_AUTO_RECOVERY |
- CHRK_ENABLE_UNDERRUN_AUTO_RECOVERY);
- reg = CHRK_SB_PGD_PORT_TX_OR_UR_CFGN(port_num);
- ret = btfm_slim_write(btfmslim, reg, 1, ®_val, IFD);
- if (ret) {
- BTFMSLIM_ERR("failed to write (%d) reg 0x%x", ret, reg);
- goto error;
- }
- enable_disable_txport:
- /* Port enable */
- reg = CHRK_SB_PGD_PORT_TX_CFGN(port_num);
- enable_disable_rxport:
- if (enable)
- en = CHRK_SB_PGD_PORT_ENABLE;
- else
- en = CHRK_SB_PGD_PORT_DISABLE;
- if (is_fm_port(port_num))
- reg_val = en | CHRK_SB_PGD_PORT_WM_L8;
- else if (port_num == CHRK_SB_PGD_PORT_TX_SCO)
- reg_val = enable ? en | CHRK_SB_PGD_PORT_WM_L1 : en;
- else
- reg_val = enable ? en | CHRK_SB_PGD_PORT_WM_LB : en;
- if (enable && port_num == CHRK_SB_PGD_PORT_TX_SCO)
- BTFMSLIM_INFO("programming SCO Tx with reg_val %d to reg 0x%x",
- reg_val, reg);
- ret = btfm_slim_write(btfmslim, reg, 1, ®_val, IFD);
- if (ret)
- BTFMSLIM_ERR("failed to write (%d) reg 0x%x", ret, reg);
- error:
- return ret;
- }
|