From eaa3717b1dda7bbae3ed6fc3df098c5a48e6376a Mon Sep 17 00:00:00 2001 From: Umesh Vats Date: Fri, 5 Nov 2021 13:04:05 -0700 Subject: [PATCH 002/154] bt-kernel: Bring initial files for BT family drivers Bring BT family drivers from msm-5.10 kernel to BT kernel project. drivers/bluetooth/btpower.c -> . drivers/bluetooth/btfm* -> . drivers/media/radio/rtc6226/* -> . include/net/bt* -> include/ Above shows how directories and header files are relocated. Change-Id: I6263eaa81dec344d7589f09ad3ec525ee7b04a8a --- Android.mk | 84 ++ Kbuild | 15 + Makefile | 16 + bt_kernel_product_board.mk | 5 + bt_kernel_vendor_board.mk | 10 + include/btpower.h | 88 ++ pwr/Kconfig | 13 + pwr/Makefile | 2 + pwr/btpower.c | 1251 +++++++++++++++++ rtc6226/Kconfig | 14 + rtc6226/Makefile | 3 + rtc6226/radio-rtc6226-common.c | 2374 ++++++++++++++++++++++++++++++++ rtc6226/radio-rtc6226-i2c.c | 1010 ++++++++++++++ rtc6226/radio-rtc6226.h | 700 ++++++++++ slimbus/Kconfig | 16 + slimbus/Makefile | 3 + slimbus/btfm_slim.c | 531 +++++++ slimbus/btfm_slim.h | 169 +++ slimbus/btfm_slim_codec.c | 458 ++++++ slimbus/btfm_slim_slave.c | 187 +++ slimbus/btfm_slim_slave.h | 180 +++ 21 files changed, 7129 insertions(+) create mode 100644 Android.mk create mode 100644 Kbuild create mode 100644 Makefile create mode 100644 bt_kernel_product_board.mk create mode 100644 bt_kernel_vendor_board.mk create mode 100644 include/btpower.h create mode 100644 pwr/Kconfig create mode 100644 pwr/Makefile create mode 100644 pwr/btpower.c create mode 100644 rtc6226/Kconfig create mode 100644 rtc6226/Makefile create mode 100644 rtc6226/radio-rtc6226-common.c create mode 100644 rtc6226/radio-rtc6226-i2c.c create mode 100644 rtc6226/radio-rtc6226.h create mode 100644 slimbus/Kconfig create mode 100644 slimbus/Makefile create mode 100644 slimbus/btfm_slim.c create mode 100644 slimbus/btfm_slim.h create mode 100644 slimbus/btfm_slim_codec.c create mode 100644 slimbus/btfm_slim_slave.c create mode 100644 slimbus/btfm_slim_slave.h diff --git a/Android.mk b/Android.mk new file mode 100644 index 0000000000..663d29dcf7 --- /dev/null +++ b/Android.mk @@ -0,0 +1,84 @@ +# Android makefile for BT kernel modules + +LOCAL_PATH := $(call my-dir) + +# Build/Package only in case of supported target +ifeq ($(call is-board-platform-in-list,taro kalama), true) + +BT_SELECT := CONFIG_MSM_BT_POWER=m +BT_SELECT += CONFIG_BTFM_SLIM=m +BT_SELECT += CONFIG_I2C_RTC6226_QCA=m + +LOCAL_PATH := $(call my-dir) + +# This makefile is only for DLKM +ifneq ($(findstring vendor,$(LOCAL_PATH)),) + +ifneq ($(findstring opensource,$(LOCAL_PATH)),) + BT_BLD_DIR := $(abspath .)/vendor/qcom/opensource/bt-kernel +endif # opensource + +DLKM_DIR := $(TOP)/device/qcom/common/dlkm + + +########################################################### +# This is set once per LOCAL_PATH, not per (kernel) module +KBUILD_OPTIONS := BT_KERNEL_ROOT=$(BT_BLD_DIR) +KBUILD_OPTIONS += $(foreach bt_select, \ + $(BT_SELECT), \ + $(bt_select)) + +BT_SRC_FILES := \ + $(wildcard $(LOCAL_PATH)/*) \ + $(wildcard $(LOCAL_PATH)/*/*) \ + +# Module.symvers needs to be generated as a intermediate module so that +# other modules which depend on BT platform modules can set local +# dependencies to it. + +########################### Module.symvers ############################ +include $(CLEAR_VARS) +LOCAL_SRC_FILES := $(BT_SRC_FILES) +LOCAL_MODULE := bt-kernel-module-symvers +LOCAL_MODULE_STEM := Module.symvers +LOCAL_MODULE_KBUILD_NAME := Module.symvers +LOCAL_MODULE_PATH := $(KERNEL_MODULES_OUT) +include $(DLKM_DIR)/Build_external_kernelmodule.mk + +# Below are for Android build system to recognize each module name, so +# they can be installed properly. Since Kbuild is used to compile these +# modules, invoking any of them will cause other modules to be compiled +# as well if corresponding flags are added in KBUILD_OPTIONS from upper +# level Makefiles. + +################################ pwr ################################ +include $(CLEAR_VARS) +LOCAL_SRC_FILES := $(BT_SRC_FILES) +LOCAL_MODULE := btpower.ko +LOCAL_MODULE_KBUILD_NAME := pwr/btpower.ko +LOCAL_MODULE_TAGS := optional +LOCAL_MODULE_DEBUG_ENABLE := true +LOCAL_MODULE_PATH := $(KERNEL_MODULES_OUT) +include $(DLKM_DIR)/Build_external_kernelmodule.mk +################################ slimbus ################################ +include $(CLEAR_VARS) +LOCAL_SRC_FILES := $(BT_SRC_FILES) +LOCAL_MODULE := bt_fm_slim.ko +LOCAL_MODULE_KBUILD_NAME := slimbus/bt_fm_slim.ko +LOCAL_MODULE_TAGS := optional +LOCAL_MODULE_DEBUG_ENABLE := true +LOCAL_MODULE_PATH := $(KERNEL_MODULES_OUT) +include $(DLKM_DIR)/Build_external_kernelmodule.mk +################################ rtc6226 ################################ +include $(CLEAR_VARS) +LOCAL_SRC_FILES := $(BT_SRC_FILES) +LOCAL_MODULE := radio-i2c-rtc6226-qca.ko +LOCAL_MODULE_KBUILD_NAME := rtc6226/radio-i2c-rtc6226-qca.ko +LOCAL_MODULE_TAGS := optional +LOCAL_MODULE_DEBUG_ENABLE := true +LOCAL_MODULE_PATH := $(KERNEL_MODULES_OUT) +include $(DLKM_DIR)/Build_external_kernelmodule.mk +########################################################### + +endif # DLKM check +endif # supported target check diff --git a/Kbuild b/Kbuild new file mode 100644 index 0000000000..5e11372e50 --- /dev/null +++ b/Kbuild @@ -0,0 +1,15 @@ +ifeq ($(CONFIG_MSM_BT_POWER),m) +KBUILD_CPPFLAGS += -DCONFIG_MSM_BT_POWER +endif + +ifeq ($(CONFIG_BTFM_SLIM),m) +KBUILD_CPPFLAGS += -DCONFIG_BTFM_SLIM +endif + +ifeq ($(CONFIG_I2C_RTC6226_QCA),m) +KBUILD_CPPFLAGS += -DCONFIG_I2C_RTC6226_QCA +endif + +obj-$(CONFIG_MSM_BT_POWER) += pwr/ +obj-$(CONFIG_BTFM_SLIM) += slimbus/ +obj-$(CONFIG_I2C_RTC6226_QCA) += rtc6226/ diff --git a/Makefile b/Makefile new file mode 100644 index 0000000000..de0aa3f278 --- /dev/null +++ b/Makefile @@ -0,0 +1,16 @@ +KERNEL_SRC ?= /lib/modules/$(shell uname -r)/build +M ?= $(shell pwd) + +M=$(PWD) +BT_ROOT=$(KERNEL_SRC)/$(M) + +KBUILD_OPTIONS+= BT_ROOT=$(BT_ROOT) + +all: + $(MAKE) -C $(KERNEL_SRC) M=$(M) modules $(KBUILD_OPTIONS) + +modules_install: + $(MAKE) INSTALL_MOD_STRIP=1 -C $(KERNEL_SRC) M=$(M) modules_install + +clean: + $(MAKE) -C $(KERNEL_SRC) M=$(M) clean diff --git a/bt_kernel_product_board.mk b/bt_kernel_product_board.mk new file mode 100644 index 0000000000..15d265662e --- /dev/null +++ b/bt_kernel_product_board.mk @@ -0,0 +1,5 @@ +# Build BT kernel drivers +PRODUCT_PACKAGES += $(KERNEL_MODULES_OUT)/btpower.ko\ + $(KERNEL_MODULES_OUT)/bt_fm_slim.ko \ + $(KERNEL_MODULES_OUT)/radio-i2c-rtc6226-qca.ko + diff --git a/bt_kernel_vendor_board.mk b/bt_kernel_vendor_board.mk new file mode 100644 index 0000000000..d1666d03d6 --- /dev/null +++ b/bt_kernel_vendor_board.mk @@ -0,0 +1,10 @@ +# Build audio kernel driver +ifneq ($(TARGET_USES_QMAA),true) +ifneq ($(TARGET_BOARD_AUTO),true) +ifeq ($(call is-board-platform-in-list,$(TARGET_BOARD_PLATFORM)),true) +BOARD_VENDOR_KERNEL_MODULES += $(KERNEL_MODULES_OUT)/btpower.ko\ + $(KERNEL_MODULES_OUT)/bt_fm_slim.ko \ + $(KERNEL_MODULES_OUT)/radio-i2c-rtc6226-qca.ko +endif +endif +endif diff --git a/include/btpower.h b/include/btpower.h new file mode 100644 index 0000000000..3141862402 --- /dev/null +++ b/include/btpower.h @@ -0,0 +1,88 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (c) 2016-2021, The Linux Foundation. All rights reserved. + * Copyright (c) 2021 Qualcomm Innovation Center, Inc. All rights reserved. + */ + +#ifndef __LINUX_BLUETOOTH_POWER_H +#define __LINUX_BLUETOOTH_POWER_H + +#include +#include +#include + +/* + * voltage regulator information required for configuring the + * bluetooth chipset + */ +enum bt_power_modes { + BT_POWER_DISABLE = 0, + BT_POWER_ENABLE, + BT_POWER_RETENTION +}; + +struct log_index { + int init; + int crash; +}; + +struct bt_power_vreg_data { + struct regulator *reg; /* voltage regulator handle */ + const char *name; /* regulator name */ + u32 min_vol; /* min voltage level */ + u32 max_vol; /* max voltage level */ + u32 load_curr; /* current */ + bool is_enabled; /* is this regulator enabled? */ + bool is_retention_supp; /* does this regulator support retention mode */ + struct log_index indx; /* Index for reg. w.r.t init & crash */ +}; + +struct bt_power { + char compatible[32]; + struct bt_power_vreg_data *vregs; + int num_vregs; +}; + +struct bt_power_clk_data { + struct clk *clk; /* clock regulator handle */ + const char *name; /* clock name */ + bool is_enabled; /* is this clock enabled? */ +}; + +/* + * Platform data for the bluetooth power driver. + */ +struct btpower_platform_data { + struct platform_device *pdev; + int bt_gpio_sys_rst; /* Bluetooth reset gpio */ + int wl_gpio_sys_rst; /* Wlan reset gpio */ + int bt_gpio_sw_ctrl; /* Bluetooth sw_ctrl gpio */ + int bt_gpio_debug; /* Bluetooth debug gpio */ + int xo_gpio_clk; /* XO clock gpio*/ + struct device *slim_dev; + struct bt_power_vreg_data *vreg_info; /* VDDIO voltage regulator */ + struct bt_power_clk_data *bt_chip_clk; /* bluetooth reference clock */ + int (*bt_power_setup)(int id); /* Bluetooth power setup function */ + char compatible[32]; /*Bluetooth SoC name */ + int num_vregs; + struct mbox_client mbox_client_data; + struct mbox_chan *mbox_chan; + const char *vreg_ipa; +}; + +int btpower_register_slimdev(struct device *dev); +int btpower_get_chipset_version(void); +int btpower_aop_mbox_init(struct btpower_platform_data *pdata); + +#define BT_CMD_SLIM_TEST 0xbfac +#define BT_CMD_PWR_CTRL 0xbfad +#define BT_CMD_CHIPSET_VERS 0xbfae +#define BT_CMD_GET_CHIPSET_ID 0xbfaf +#define BT_CMD_CHECK_SW_CTRL 0xbfb0 +#define BT_CMD_GETVAL_POWER_SRCS 0xbfb1 +#define BT_CMD_SET_IPA_TCS_INFO 0xbfc0 + +/* total number of power src */ +#define BT_POWER_SRC_SIZE 28 + +#endif /* __LINUX_BLUETOOTH_POWER_H */ diff --git a/pwr/Kconfig b/pwr/Kconfig new file mode 100644 index 0000000000..87cb3c3298 --- /dev/null +++ b/pwr/Kconfig @@ -0,0 +1,13 @@ +# SPDX-License-Identifier: GPL-2.0-only + +config MSM_BT_POWER + tristate "MSM Bluetooth Power Control" + depends on ARCH_QCOM + help + MSM Bluetooth Power control driver. + This provides a parameter to switch on/off power from PMIC + to Bluetooth device. This will control LDOs/Clock/GPIOs to + control Bluetooth Chipset based on power on/off sequence. + + Say Y here to compile support for Bluetooth Power driver + into the kernel or say M to compile as a module. diff --git a/pwr/Makefile b/pwr/Makefile new file mode 100644 index 0000000000..ac7e92aa5d --- /dev/null +++ b/pwr/Makefile @@ -0,0 +1,2 @@ +ccflags-y += -I$(BT_ROOT)/include +obj-$(CONFIG_MSM_BT_POWER) += btpower.o diff --git a/pwr/btpower.c b/pwr/btpower.c new file mode 100644 index 0000000000..199420a5db --- /dev/null +++ b/pwr/btpower.c @@ -0,0 +1,1251 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2016-2021, The Linux Foundation. All rights reserved. + * Copyright (c) 2021 Qualcomm Innovation Center, Inc. All rights reserved. + */ + +/* + * Bluetooth Power Switch Module + * controls power to external Bluetooth device + * with interface to power management device + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "btpower.h" + +#if defined CONFIG_BT_SLIM_QCA6390 || \ + defined CONFIG_BT_SLIM_QCA6490 || \ + defined CONFIG_BTFM_SLIM_WCN3990 +#include "btfm_slim.h" +#endif +#include + +#define PWR_SRC_NOT_AVAILABLE -2 +#define DEFAULT_INVALID_VALUE -1 +#define PWR_SRC_INIT_STATE_IDX 0 +#define BTPOWER_MBOX_MSG_MAX_LEN 64 +#define BTPOWER_MBOX_TIMEOUT_MS 1000 +#define XO_CLK_RETRY_COUNT_MAX 5 +/** + * enum btpower_vreg_param: Voltage regulator TCS param + * @BTPOWER_VREG_VOLTAGE: Provides voltage level to be configured in TCS + * @BTPOWER_VREG_MODE: Regulator mode + * @BTPOWER_VREG_TCS_ENABLE: Set Voltage regulator enable config in TCS + */ +enum btpower_vreg_param { + BTPOWER_VREG_VOLTAGE, + BTPOWER_VREG_MODE, + BTPOWER_VREG_ENABLE, +}; + +/** + * enum btpower_tcs_seq: TCS sequence ID for trigger + * BTPOWER_TCS_UP_SEQ: TCS Sequence based on up trigger / Wake TCS + * BTPOWER_TCS_DOWN_SEQ: TCS Sequence based on down trigger / Sleep TCS + * BTPOWER_TCS_ALL_SEQ: Update for both up and down triggers + */ +enum btpower_tcs_seq { + BTPOWER_TCS_UP_SEQ, + BTPOWER_TCS_DOWN_SEQ, + BTPOWER_TCS_ALL_SEQ, +}; + +enum power_src_pos { + BT_RESET_GPIO = PWR_SRC_INIT_STATE_IDX, + BT_SW_CTRL_GPIO, + BT_VDD_AON_LDO, + BT_VDD_DIG_LDO, + BT_VDD_RFA1_LDO, + BT_VDD_RFA2_LDO, + BT_VDD_ASD_LDO, + BT_VDD_XTAL_LDO, + BT_VDD_PA_LDO, + BT_VDD_CORE_LDO, + BT_VDD_IO_LDO, + BT_VDD_LDO, + BT_VDD_RFA_0p8, + BT_VDD_RFACMN, + // these indexes GPIOs/regs value are fetched during crash. + BT_RESET_GPIO_CURRENT, + BT_SW_CTRL_GPIO_CURRENT, + BT_VDD_AON_LDO_CURRENT, + BT_VDD_DIG_LDO_CURRENT, + BT_VDD_RFA1_LDO_CURRENT, + BT_VDD_RFA2_LDO_CURRENT, + BT_VDD_ASD_LDO_CURRENT, + BT_VDD_XTAL_LDO_CURRENT, + BT_VDD_PA_LDO_CURRENT, + BT_VDD_CORE_LDO_CURRENT, + BT_VDD_IO_LDO_CURRENT, + BT_VDD_LDO_CURRENT, + BT_VDD_RFA_0p8_CURRENT, + BT_VDD_RFACMN_CURRENT +}; + +// Regulator structure for QCA6390 and QCA6490 BT SoC series +static struct bt_power_vreg_data bt_vregs_info_qca6x9x[] = { + {NULL, "qcom,bt-vdd-io", 1800000, 1800000, 0, false, true, + {BT_VDD_IO_LDO, BT_VDD_IO_LDO_CURRENT}}, + {NULL, "qcom,bt-vdd-aon", 966000, 966000, 0, false, true, + {BT_VDD_AON_LDO, BT_VDD_AON_LDO_CURRENT}}, + {NULL, "qcom,bt-vdd-rfacmn", 950000, 950000, 0, false, true, + {BT_VDD_RFACMN, BT_VDD_RFACMN_CURRENT}}, + /* BT_CX_MX */ + {NULL, "qcom,bt-vdd-dig", 966000, 966000, 0, false, true, + {BT_VDD_DIG_LDO, BT_VDD_DIG_LDO_CURRENT}}, + {NULL, "qcom,bt-vdd-rfa-0p8", 950000, 952000, 0, false, true, + {BT_VDD_RFA_0p8, BT_VDD_RFA_0p8_CURRENT}}, + {NULL, "qcom,bt-vdd-rfa1", 1900000, 1900000, 0, false, true, + {BT_VDD_RFA1_LDO, BT_VDD_RFA1_LDO_CURRENT}}, + {NULL, "qcom,bt-vdd-rfa2", 1900000, 1900000, 0, false, true, + {BT_VDD_RFA2_LDO, BT_VDD_RFA2_LDO_CURRENT}}, + {NULL, "qcom,bt-vdd-asd", 2800000, 2800000, 0, false, true, + {BT_VDD_ASD_LDO, BT_VDD_ASD_LDO_CURRENT}}, +}; + +// Regulator structure for WCN399x BT SoC series +static struct bt_power bt_vreg_info_wcn399x = { + .compatible = "qcom,wcn3990", + .vregs = (struct bt_power_vreg_data []) { + {NULL, "qcom,bt-vdd-io", 1700000, 1900000, 0, false, false, + {BT_VDD_IO_LDO, BT_VDD_IO_LDO_CURRENT}}, + {NULL, "qcom,bt-vdd-core", 1304000, 1304000, 0, false, false, + {BT_VDD_CORE_LDO, BT_VDD_CORE_LDO_CURRENT}}, + {NULL, "qcom,bt-vdd-pa", 3000000, 3312000, 0, false, false, + {BT_VDD_PA_LDO, BT_VDD_PA_LDO_CURRENT}}, + {NULL, "qcom,bt-vdd-xtal", 1700000, 1900000, 0, false, false, + {BT_VDD_XTAL_LDO, BT_VDD_XTAL_LDO_CURRENT}}, + }, + .num_vregs = 4, +}; + +static struct bt_power bt_vreg_info_qca6390 = { + .compatible = "qcom,qca6390", + .vregs = bt_vregs_info_qca6x9x, + .num_vregs = ARRAY_SIZE(bt_vregs_info_qca6x9x), +}; + +static struct bt_power bt_vreg_info_qca6490 = { + .compatible = "qcom,qca6490", + .vregs = bt_vregs_info_qca6x9x, + .num_vregs = ARRAY_SIZE(bt_vregs_info_qca6x9x), +}; + +static const struct of_device_id bt_power_match_table[] = { + { .compatible = "qcom,qca6174" }, + { .compatible = "qcom,wcn3990", .data = &bt_vreg_info_wcn399x}, + { .compatible = "qcom,qca6390", .data = &bt_vreg_info_qca6390}, + { .compatible = "qcom,qca6490", .data = &bt_vreg_info_qca6490}, + {}, +}; + +static int bt_power_vreg_set(enum bt_power_modes mode); +static int btpower_enable_ipa_vreg(struct btpower_platform_data *pdata); + +static int bt_power_src_status[BT_POWER_SRC_SIZE]; +static struct btpower_platform_data *bt_power_pdata; +static bool previous; +static int pwr_state; +static struct class *bt_class; +static int bt_major; +static int soc_id; +static bool probe_finished; + +static int bt_vreg_enable(struct bt_power_vreg_data *vreg) +{ + int rc = 0; + + pr_debug("%s: vreg_en for : %s\n", __func__, vreg->name); + + if (!vreg->is_enabled) { + if ((vreg->min_vol != 0) && (vreg->max_vol != 0)) { + rc = regulator_set_voltage(vreg->reg, + vreg->min_vol, + vreg->max_vol); + if (rc < 0) { + pr_err("%s: regulator_set_voltage(%s) failed rc=%d\n", + __func__, vreg->name, rc); + goto out; + } + } + + if (vreg->load_curr >= 0) { + rc = regulator_set_load(vreg->reg, + vreg->load_curr); + if (rc < 0) { + pr_err("%s: regulator_set_load(%s) failed rc=%d\n", + __func__, vreg->name, rc); + goto out; + } + } + + rc = regulator_enable(vreg->reg); + if (rc < 0) { + pr_err("regulator_enable(%s) failed. rc=%d\n", + __func__, vreg->name, rc); + goto out; + } + vreg->is_enabled = true; + } +out: + return rc; +} + +static int bt_vreg_enable_retention(struct bt_power_vreg_data *vreg) +{ + int rc = 0; + + if (!vreg) + return rc; + + pr_debug("%s: enable_retention for : %s\n", __func__, vreg->name); + + if ((vreg->is_enabled) && (vreg->is_retention_supp)) { + if ((vreg->min_vol != 0) && (vreg->max_vol != 0)) { + /* Set the min voltage to 0 */ + rc = regulator_set_voltage(vreg->reg, 0, vreg->max_vol); + if (rc < 0) { + pr_err("%s: regulator_set_voltage(%s) failed rc=%d\n", + __func__, vreg->name, rc); + goto out; + } + } + if (vreg->load_curr >= 0) { + rc = regulator_set_load(vreg->reg, 0); + if (rc < 0) { + pr_err("%s: regulator_set_load(%s) failed rc=%d\n", + __func__, vreg->name, rc); + } + } + } +out: + return rc; +} + +static int bt_vreg_disable(struct bt_power_vreg_data *vreg) +{ + int rc = 0; + + if (!vreg) + return rc; + + pr_debug("%s for : %s\n", __func__, vreg->name); + + if (vreg->is_enabled) { + rc = regulator_disable(vreg->reg); + if (rc < 0) { + pr_err("%s, regulator_disable(%s) failed. rc=%d\n", + __func__, vreg->name, rc); + goto out; + } + vreg->is_enabled = false; + + if ((vreg->min_vol != 0) && (vreg->max_vol != 0)) { + /* Set the min voltage to 0 */ + rc = regulator_set_voltage(vreg->reg, 0, + vreg->max_vol); + if (rc < 0) { + pr_err("%s: regulator_set_voltage(%s) failed rc=%d\n", + __func__, vreg->name, rc); + goto out; + } + } + if (vreg->load_curr >= 0) { + rc = regulator_set_load(vreg->reg, 0); + if (rc < 0) { + pr_err("%s: regulator_set_load(%s) failed rc=%d\n", + __func__, vreg->name, rc); + } + } + } +out: + return rc; +} + +static int bt_clk_enable(struct bt_power_clk_data *clk) +{ + int rc = 0; + + pr_info("%s: %s\n", __func__, clk->name); + + /* Get the clock handle for vreg */ + if (!clk->clk || clk->is_enabled) { + pr_err("%s: error - node: %p, clk->is_enabled:%d\n", + __func__, clk->clk, clk->is_enabled); + return -EINVAL; + } + + rc = clk_prepare_enable(clk->clk); + if (rc) { + pr_err("%s: failed to enable %s, rc(%d)\n", + __func__, clk->name, rc); + return rc; + } + + clk->is_enabled = true; + return rc; +} + +static int bt_clk_disable(struct bt_power_clk_data *clk) +{ + int rc = 0; + + pr_debug("%s: %s\n", __func__, clk->name); + + /* Get the clock handle for vreg */ + if (!clk->clk || !clk->is_enabled) { + pr_err("%s: error - node: %p, clk->is_enabled:%d\n", + __func__, clk->clk, clk->is_enabled); + return -EINVAL; + } + clk_disable_unprepare(clk->clk); + + clk->is_enabled = false; + return rc; +} + +static void btpower_set_xo_clk_gpio_state(bool enable) +{ + int xo_clk_gpio = bt_power_pdata->xo_gpio_clk; + int retry = 0; + int rc = 0; + + if (xo_clk_gpio < 0) + return; + +retry_gpio_req: + rc = gpio_request(xo_clk_gpio, "bt_xo_clk_gpio"); + if (rc) { + if (retry++ < XO_CLK_RETRY_COUNT_MAX) { + /* wait for ~(10 - 20) ms */ + usleep_range(10000, 20000); + goto retry_gpio_req; + } + } + + if (rc) { + pr_err("%s: unable to request XO clk gpio %d (%d)\n", + __func__, xo_clk_gpio, rc); + return; + } + + if (enable) { + gpio_direction_output(xo_clk_gpio, 1); + /*XO CLK must be asserted for some time before BT_EN */ + usleep_range(100, 200); + } else { + /* Assert XO CLK ~(2-5)ms before off for valid latch in HW */ + usleep_range(4000, 6000); + gpio_direction_output(xo_clk_gpio, 0); + } + + pr_info("%s:gpio(%d) success\n", __func__, xo_clk_gpio); + + gpio_free(xo_clk_gpio); +} + +static int bt_configure_gpios(int on) +{ + int rc = 0; + int bt_reset_gpio = bt_power_pdata->bt_gpio_sys_rst; + int wl_reset_gpio = bt_power_pdata->wl_gpio_sys_rst; + int bt_sw_ctrl_gpio = bt_power_pdata->bt_gpio_sw_ctrl; + int bt_debug_gpio = bt_power_pdata->bt_gpio_debug; + int assert_dbg_gpio = 0; + + if (on) { + rc = gpio_request(bt_reset_gpio, "bt_sys_rst_n"); + if (rc) { + pr_err("%s: unable to request gpio %d (%d)\n", + __func__, bt_reset_gpio, rc); + return rc; + } + + rc = gpio_direction_output(bt_reset_gpio, 0); + if (rc) { + pr_err("%s: Unable to set direction\n", __func__); + return rc; + } + bt_power_src_status[BT_RESET_GPIO] = + gpio_get_value(bt_reset_gpio); + msleep(50); + pr_info("BTON:Turn Bt Off bt-reset-gpio(%d) value(%d)\n", + bt_reset_gpio, gpio_get_value(bt_reset_gpio)); + if (bt_sw_ctrl_gpio >= 0) { + pr_info("BTON:Turn Bt Off\n"); + bt_power_src_status[BT_SW_CTRL_GPIO] = + gpio_get_value(bt_sw_ctrl_gpio); + pr_info("bt-sw-ctrl-gpio(%d) value(%d)\n", + bt_sw_ctrl_gpio, + bt_power_src_status[BT_SW_CTRL_GPIO]); + } + if (wl_reset_gpio >= 0) + pr_info("BTON:Turn Bt On wl-reset-gpio(%d) value(%d)\n", + wl_reset_gpio, gpio_get_value(wl_reset_gpio)); + + if ((wl_reset_gpio < 0) || + ((wl_reset_gpio >= 0) && gpio_get_value(wl_reset_gpio))) { + + btpower_set_xo_clk_gpio_state(true); + pr_info("%s: BTON: Asserting BT_EN\n", __func__); + rc = gpio_direction_output(bt_reset_gpio, 1); + if (rc) { + pr_err("%s: Unable to set direction\n", __func__); + return rc; + } + bt_power_src_status[BT_RESET_GPIO] = + gpio_get_value(bt_reset_gpio); + btpower_set_xo_clk_gpio_state(false); + } + if ((wl_reset_gpio >= 0) && (gpio_get_value(wl_reset_gpio) == 0)) { + if (gpio_get_value(bt_reset_gpio)) { + pr_info("%s: Wlan Off and BT On too close\n", __func__); + pr_info("%s: reset BT_EN, enable it after delay\n", __func__); + rc = gpio_direction_output(bt_reset_gpio, 0); + if (rc) { + pr_err("%s: Unable to set direction\n", __func__); + return rc; + } + bt_power_src_status[BT_RESET_GPIO] = + gpio_get_value(bt_reset_gpio); + } + pr_info("%s:add 100ms delay for AON output to fully discharge\n", + __func__); + msleep(100); + btpower_set_xo_clk_gpio_state(true); + rc = gpio_direction_output(bt_reset_gpio, 1); + if (rc) { + pr_err("%s: Unable to set direction\n", __func__); + return rc; + } + bt_power_src_status[BT_RESET_GPIO] = + gpio_get_value(bt_reset_gpio); + btpower_set_xo_clk_gpio_state(false); + } + msleep(50); + /* Check if SW_CTRL is asserted */ + if (bt_sw_ctrl_gpio >= 0) { + rc = gpio_direction_input(bt_sw_ctrl_gpio); + if (rc) { + pr_err("%s:SWCTRL Dir Set Problem:%d\n", + __func__, rc); + } else if (!gpio_get_value(bt_sw_ctrl_gpio)) { + /* SW_CTRL not asserted, assert debug GPIO */ + if (bt_debug_gpio >= 0) + assert_dbg_gpio = 1; + } + } + if (assert_dbg_gpio) { + rc = gpio_request(bt_debug_gpio, "bt_debug_n"); + if (rc) { + pr_err("unable to request Debug Gpio\n"); + } else { + rc = gpio_direction_output(bt_debug_gpio, 1); + if (rc) + pr_err("%s:Prob Set Debug-Gpio\n", + __func__); + } + } + pr_info("BTON:Turn Bt On bt-reset-gpio(%d) value(%d)\n", + bt_reset_gpio, gpio_get_value(bt_reset_gpio)); + if (bt_sw_ctrl_gpio >= 0) { + pr_info("BTON:Turn Bt On\n"); + bt_power_src_status[BT_SW_CTRL_GPIO] = + gpio_get_value(bt_sw_ctrl_gpio); + pr_info("bt-sw-ctrl-gpio(%d) value(%d)\n", + bt_sw_ctrl_gpio, + bt_power_src_status[BT_SW_CTRL_GPIO]); + } + } else { + gpio_set_value(bt_reset_gpio, 0); + msleep(100); + pr_info("BT-OFF:bt-reset-gpio(%d) value(%d)\n", + bt_reset_gpio, gpio_get_value(bt_reset_gpio)); + if (bt_sw_ctrl_gpio >= 0) { + pr_info("BT-OFF:bt-sw-ctrl-gpio(%d) value(%d)\n", + bt_sw_ctrl_gpio, + gpio_get_value(bt_sw_ctrl_gpio)); + } + } + + pr_info("%s: bt_gpio= %d on: %d\n", __func__, bt_reset_gpio, on); + + return rc; +} + +static int bluetooth_power(int on) +{ + int rc = 0; + + pr_debug("%s: on: %d\n", __func__, on); + + if (on == 1) { + rc = bt_power_vreg_set(BT_POWER_ENABLE); + if (rc < 0) { + pr_err("%s: bt_power regulators config failed\n", + __func__); + goto regulator_fail; + } + /* Parse dt_info and check if a target requires clock voting. + * Enable BT clock when BT is on and disable it when BT is off + */ + if (bt_power_pdata->bt_chip_clk) { + rc = bt_clk_enable(bt_power_pdata->bt_chip_clk); + if (rc < 0) { + pr_err("%s: bt_power gpio config failed\n", + __func__); + goto clk_fail; + } + } + if (bt_power_pdata->bt_gpio_sys_rst > 0) { + bt_power_src_status[BT_RESET_GPIO] = + DEFAULT_INVALID_VALUE; + bt_power_src_status[BT_SW_CTRL_GPIO] = + DEFAULT_INVALID_VALUE; + rc = bt_configure_gpios(on); + if (rc < 0) { + pr_err("%s: bt_power gpio config failed\n", + __func__); + goto gpio_fail; + } + } + } else if (on == 0) { + // Power Off + if (bt_power_pdata->bt_gpio_sys_rst > 0) + bt_configure_gpios(on); +gpio_fail: + if (bt_power_pdata->bt_gpio_sys_rst > 0) + gpio_free(bt_power_pdata->bt_gpio_sys_rst); + if (bt_power_pdata->bt_gpio_debug > 0) + gpio_free(bt_power_pdata->bt_gpio_debug); + if (bt_power_pdata->bt_chip_clk) + bt_clk_disable(bt_power_pdata->bt_chip_clk); +clk_fail: +regulator_fail: + bt_power_vreg_set(BT_POWER_DISABLE); + } else if (on == 2) { + /* Retention mode */ + bt_power_vreg_set(BT_POWER_RETENTION); + } else { + pr_err("%s: Invalid power mode: %d\n", __func__, on); + rc = -1; + } + return rc; +} + +static int btpower_toggle_radio(void *data, bool blocked) +{ + int ret = 0; + int (*power_control)(int enable); + + power_control = + ((struct btpower_platform_data *)data)->bt_power_setup; + + if (previous != blocked) + ret = (*power_control)(!blocked); + if (!ret) + previous = blocked; + return ret; +} + +static const struct rfkill_ops btpower_rfkill_ops = { + .set_block = btpower_toggle_radio, +}; + +static ssize_t extldo_show(struct device *dev, struct device_attribute *attr, + char *buf) +{ + return scnprintf(buf, 6, "false\n"); +} + +static DEVICE_ATTR_RO(extldo); + +static int btpower_rfkill_probe(struct platform_device *pdev) +{ + struct rfkill *rfkill; + int ret; + + rfkill = rfkill_alloc("bt_power", &pdev->dev, RFKILL_TYPE_BLUETOOTH, + &btpower_rfkill_ops, + pdev->dev.platform_data); + + if (!rfkill) { + dev_err(&pdev->dev, "rfkill allocate failed\n"); + return -ENOMEM; + } + + /* add file into rfkill0 to handle LDO27 */ + ret = device_create_file(&pdev->dev, &dev_attr_extldo); + if (ret < 0) + pr_err("%s: device create file error\n", __func__); + + /* force Bluetooth off during init to allow for user control */ + rfkill_init_sw_state(rfkill, 1); + previous = true; + + ret = rfkill_register(rfkill); + if (ret) { + dev_err(&pdev->dev, "rfkill register failed=%d\n", ret); + rfkill_destroy(rfkill); + return ret; + } + + platform_set_drvdata(pdev, rfkill); + + return 0; +} + +static void btpower_rfkill_remove(struct platform_device *pdev) +{ + struct rfkill *rfkill; + + pr_debug("%s\n", __func__); + + rfkill = platform_get_drvdata(pdev); + if (rfkill) + rfkill_unregister(rfkill); + rfkill_destroy(rfkill); + platform_set_drvdata(pdev, NULL); +} + +#define MAX_PROP_SIZE 32 +static int bt_dt_parse_vreg_info(struct device *dev, + struct bt_power_vreg_data *vreg_data) +{ + int len, ret = 0; + const __be32 *prop; + char prop_name[MAX_PROP_SIZE]; + struct bt_power_vreg_data *vreg = vreg_data; + struct device_node *np = dev->of_node; + const char *vreg_name = vreg_data->name; + + pr_debug("%s: vreg dev tree parse for %s\n", __func__, vreg_name); + + snprintf(prop_name, sizeof(prop_name), "%s-supply", vreg_name); + if (of_parse_phandle(np, prop_name, 0)) { + vreg->reg = regulator_get(dev, vreg_name); + if (IS_ERR(vreg->reg)) { + ret = PTR_ERR(vreg->reg); + vreg->reg = NULL; + pr_warn("%s: failed to get: %s error:%d\n", __func__, + vreg_name, ret); + return ret; + } + + snprintf(prop_name, sizeof(prop_name), "%s-config", vreg->name); + prop = of_get_property(dev->of_node, prop_name, &len); + if (!prop || len != (4 * sizeof(__be32))) { + pr_debug("%s: Property %s %s, use default\n", + __func__, prop_name, + prop ? "invalid format" : "doesn't exist"); + } else { + vreg->min_vol = be32_to_cpup(&prop[0]); + vreg->max_vol = be32_to_cpup(&prop[1]); + vreg->load_curr = be32_to_cpup(&prop[2]); + vreg->is_retention_supp = be32_to_cpup(&prop[3]); + } + + pr_debug("%s: Got regulator: %s, min_vol: %u, max_vol: %u, load_curr: %u,is_retention_supp: %u\n", + __func__, vreg->name, vreg->min_vol, vreg->max_vol, + vreg->load_curr, vreg->is_retention_supp); + } else { + pr_info("%s: %s is not provided in device tree\n", __func__, + vreg_name); + } + + return ret; +} + +static int bt_dt_parse_clk_info(struct device *dev, + struct bt_power_clk_data **clk_data) +{ + int ret = -EINVAL; + struct bt_power_clk_data *clk = NULL; + struct device_node *np = dev->of_node; + + pr_debug("%s\n", __func__); + + *clk_data = NULL; + if (of_parse_phandle(np, "clocks", 0)) { + clk = devm_kzalloc(dev, sizeof(*clk), GFP_KERNEL); + if (!clk) { + ret = -ENOMEM; + goto err; + } + + /* Allocated 20 bytes size buffer for clock name string */ + clk->name = devm_kzalloc(dev, 20, GFP_KERNEL); + + /* Parse clock name from node */ + ret = of_property_read_string_index(np, "clock-names", 0, + &(clk->name)); + if (ret < 0) { + pr_err("%s: reading \"clock-names\" failed\n", + __func__); + return ret; + } + + clk->clk = devm_clk_get(dev, clk->name); + if (IS_ERR(clk->clk)) { + ret = PTR_ERR(clk->clk); + pr_err("%s: failed to get %s, ret (%d)\n", + __func__, clk->name, ret); + clk->clk = NULL; + return ret; + } + + *clk_data = clk; + } else { + pr_err("%s: clocks is not provided in device tree\n", __func__); + } + +err: + return ret; +} + +static int bt_power_vreg_get(struct platform_device *pdev) +{ + int num_vregs, i = 0, ret = 0; + const struct bt_power *data; + + data = of_device_get_match_data(&pdev->dev); + if (!data) { + pr_err("%s: failed to get dev node\n", __func__); + return -EINVAL; + } + + memcpy(&bt_power_pdata->compatible, &data->compatible, MAX_PROP_SIZE); + bt_power_pdata->vreg_info = data->vregs; + num_vregs = bt_power_pdata->num_vregs = data->num_vregs; + for (; i < num_vregs; i++) { + ret = bt_dt_parse_vreg_info(&(pdev->dev), + &bt_power_pdata->vreg_info[i]); + /* No point to go further if failed to get regulator handler */ + if (ret) + break; + } + + return ret; +} + +static int bt_power_vreg_set(enum bt_power_modes mode) +{ + int num_vregs, i = 0, ret = 0; + int log_indx; + struct bt_power_vreg_data *vreg_info = NULL; + + num_vregs = bt_power_pdata->num_vregs; + if (mode == BT_POWER_ENABLE) { + for (; i < num_vregs; i++) { + vreg_info = &bt_power_pdata->vreg_info[i]; + log_indx = vreg_info->indx.init; + if (vreg_info->reg) { + bt_power_src_status[log_indx] = + DEFAULT_INVALID_VALUE; + ret = bt_vreg_enable(vreg_info); + if (ret < 0) + goto out; + if (vreg_info->is_enabled) { + bt_power_src_status[log_indx] = + regulator_get_voltage( + vreg_info->reg); + } + } + } + } else if (mode == BT_POWER_DISABLE) { + for (; i < num_vregs; i++) { + vreg_info = &bt_power_pdata->vreg_info[i]; + ret = bt_vreg_disable(vreg_info); + } + } else if (mode == BT_POWER_RETENTION) { + for (; i < num_vregs; i++) { + vreg_info = &bt_power_pdata->vreg_info[i]; + ret = bt_vreg_enable_retention(vreg_info); + } + } else { + pr_err("%s: Invalid power mode: %d\n", __func__, mode); + ret = -1; + } + +out: + return ret; +} + +static void bt_power_vreg_put(void) +{ + int i = 0; + struct bt_power_vreg_data *vreg_info = NULL; + int num_vregs = bt_power_pdata->num_vregs; + + for (; i < num_vregs; i++) { + vreg_info = &bt_power_pdata->vreg_info[i]; + if (vreg_info->reg) + regulator_put(vreg_info->reg); + } +} + + +static int bt_power_populate_dt_pinfo(struct platform_device *pdev) +{ + int rc; + + pr_debug("%s\n", __func__); + + if (!bt_power_pdata) + return -ENOMEM; + + if (pdev->dev.of_node) { + rc = bt_power_vreg_get(pdev); + if (rc) + return rc; + + bt_power_pdata->bt_gpio_sys_rst = + of_get_named_gpio(pdev->dev.of_node, + "qcom,bt-reset-gpio", 0); + if (bt_power_pdata->bt_gpio_sys_rst < 0) + pr_warn("bt-reset-gpio not provided in devicetree\n"); + + bt_power_pdata->wl_gpio_sys_rst = + of_get_named_gpio(pdev->dev.of_node, + "qcom,wl-reset-gpio", 0); + if (bt_power_pdata->wl_gpio_sys_rst < 0) + pr_err("%s: wl-reset-gpio not provided in device tree\n", + __func__); + + + bt_power_pdata->bt_gpio_sw_ctrl = + of_get_named_gpio(pdev->dev.of_node, + "qcom,bt-sw-ctrl-gpio", 0); + if (bt_power_pdata->bt_gpio_sw_ctrl < 0) + pr_warn("bt-sw-ctrl-gpio not provided in devicetree\n"); + + bt_power_pdata->bt_gpio_debug = + of_get_named_gpio(pdev->dev.of_node, + "qcom,bt-debug-gpio", 0); + if (bt_power_pdata->bt_gpio_debug < 0) + pr_warn("bt-debug-gpio not provided in devicetree\n"); + + bt_power_pdata->xo_gpio_clk = + of_get_named_gpio(pdev->dev.of_node, + "qcom,xo-clk-gpio", 0); + if (bt_power_pdata->xo_gpio_clk < 0) + pr_warn("xo-clk-gpio not provided in devicetree\n"); + + rc = bt_dt_parse_clk_info(&pdev->dev, + &bt_power_pdata->bt_chip_clk); + if (rc < 0) + pr_warn("%s: clock not provided in device tree\n", + __func__); + } + + bt_power_pdata->bt_power_setup = bluetooth_power; + + return 0; +} + +static int bt_power_probe(struct platform_device *pdev) +{ + int ret = 0; + int itr; + + pr_debug("%s\n", __func__); + + /* Fill whole array with -2 i.e NOT_AVAILABLE state by default + * for any GPIO or Reg handle. + */ + for (itr = PWR_SRC_INIT_STATE_IDX; + itr < BT_POWER_SRC_SIZE; ++itr) + bt_power_src_status[itr] = PWR_SRC_NOT_AVAILABLE; + + bt_power_pdata = kzalloc(sizeof(*bt_power_pdata), GFP_KERNEL); + + if (!bt_power_pdata) + return -ENOMEM; + + bt_power_pdata->pdev = pdev; + if (pdev->dev.of_node) { + ret = bt_power_populate_dt_pinfo(pdev); + if (ret < 0) { + pr_err("%s, Failed to populate device tree info\n", + __func__); + goto free_pdata; + } + pdev->dev.platform_data = bt_power_pdata; + } else if (pdev->dev.platform_data) { + /* Optional data set to default if not provided */ + if (!((struct btpower_platform_data *) + (pdev->dev.platform_data))->bt_power_setup) + ((struct btpower_platform_data *) + (pdev->dev.platform_data))->bt_power_setup = + bluetooth_power; + + memcpy(bt_power_pdata, pdev->dev.platform_data, + sizeof(struct btpower_platform_data)); + pwr_state = 0; + } else { + pr_err("%s: Failed to get platform data\n", __func__); + goto free_pdata; + } + + if (btpower_rfkill_probe(pdev) < 0) + goto free_pdata; + + btpower_aop_mbox_init(bt_power_pdata); + + probe_finished = true; + return 0; + +free_pdata: + kfree(bt_power_pdata); + return ret; +} + +static int bt_power_remove(struct platform_device *pdev) +{ + dev_dbg(&pdev->dev, "%s\n", __func__); + + probe_finished = false; + btpower_rfkill_remove(pdev); + bt_power_vreg_put(); + + kfree(bt_power_pdata); + + return 0; +} + +int btpower_register_slimdev(struct device *dev) +{ + pr_debug("%s\n", __func__); + if (!bt_power_pdata || (dev == NULL)) { + pr_err("%s: Failed to allocate memory\n", __func__); + return -EINVAL; + } + bt_power_pdata->slim_dev = dev; + return 0; +} +EXPORT_SYMBOL(btpower_register_slimdev); + +int btpower_get_chipset_version(void) +{ + pr_debug("%s\n", __func__); + return soc_id; +} +EXPORT_SYMBOL(btpower_get_chipset_version); + +static void set_pwr_srcs_status(struct bt_power_vreg_data *handle) +{ + int ldo_index; + + if (handle) { + ldo_index = handle->indx.crash; + bt_power_src_status[ldo_index] = + DEFAULT_INVALID_VALUE; + if (handle->is_enabled && + (regulator_is_enabled(handle->reg))) { + bt_power_src_status[ldo_index] = + (int)regulator_get_voltage(handle->reg); + pr_err("%s(%d) value(%d)\n", handle->name, + handle, bt_power_src_status[ldo_index]); + } else { + pr_err("%s:%s is_enabled: %d\n", + __func__, handle->name, + handle->is_enabled); + } + } +} + +static void set_gpios_srcs_status(char *gpio_name, + int gpio_index, int handle) +{ + if (handle >= 0) { + bt_power_src_status[gpio_index] = + DEFAULT_INVALID_VALUE; + bt_power_src_status[gpio_index] = + gpio_get_value(handle); + pr_err("%s(%d) value(%d)\n", gpio_name, + handle, bt_power_src_status[gpio_index]); + } else { + pr_err("%s: %s not configured\n", + __func__, gpio_name); + } +} + +static long bt_ioctl(struct file *file, unsigned int cmd, unsigned long arg) +{ + int ret = 0, pwr_cntrl = 0; + int chipset_version = 0; + int itr, num_vregs; + struct bt_power_vreg_data *vreg_info = NULL; + + if (!bt_power_pdata || !probe_finished) { + pr_err("%s: BTPower Probing Pending.Try Again\n", __func__); + return -EAGAIN; + } + + switch (cmd) { + case BT_CMD_SLIM_TEST: +#if (defined CONFIG_BT_SLIM_QCA6390 || \ + defined CONFIG_BT_SLIM_QCA6490 || \ + defined CONFIG_BTFM_SLIM_WCN3990) + if (!bt_power_pdata->slim_dev) { + pr_err("%s: slim_dev is null\n", __func__); + return -EINVAL; + } + ret = btfm_slim_hw_init( + bt_power_pdata->slim_dev->platform_data + ); +#endif + break; + case BT_CMD_PWR_CTRL: + pwr_cntrl = (int)arg; + pr_warn("%s: BT_CMD_PWR_CTRL pwr_cntrl: %d\n", + __func__, pwr_cntrl); + if (pwr_state != pwr_cntrl) { + ret = bluetooth_power(pwr_cntrl); + if (!ret) + pwr_state = pwr_cntrl; + } else { + pr_err("%s: BT chip state is already: %d no change\n", + __func__, pwr_state); + ret = 0; + } + break; + case BT_CMD_CHIPSET_VERS: + chipset_version = (int)arg; + pr_warn("%s: unified Current SOC Version : %x\n", __func__, + chipset_version); + if (chipset_version) { + soc_id = chipset_version; + } else { + pr_err("%s: got invalid soc version\n", __func__); + soc_id = 0; + } + break; + case BT_CMD_GET_CHIPSET_ID: + if (copy_to_user((void __user *)arg, bt_power_pdata->compatible, + MAX_PROP_SIZE)) { + pr_err("%s: copy to user failed\n", __func__); + ret = -EFAULT; + } + break; + case BT_CMD_CHECK_SW_CTRL: + /* Check if SW_CTRL is asserted */ + pr_info("BT_CMD_CHECK_SW_CTRL\n"); + if (bt_power_pdata->bt_gpio_sw_ctrl > 0) { + bt_power_src_status[BT_SW_CTRL_GPIO] = + DEFAULT_INVALID_VALUE; + ret = gpio_direction_input( + bt_power_pdata->bt_gpio_sw_ctrl); + if (ret) { + pr_err("%s:gpio_direction_input api\n", + __func__); + pr_err("%s:failed for SW_CTRL:%d\n", + __func__, ret); + } else { + bt_power_src_status[BT_SW_CTRL_GPIO] = + gpio_get_value( + bt_power_pdata->bt_gpio_sw_ctrl); + pr_info("bt-sw-ctrl-gpio(%d) value(%d)\n", + bt_power_pdata->bt_gpio_sw_ctrl, + bt_power_src_status[BT_SW_CTRL_GPIO]); + } + } else { + pr_err("bt_gpio_sw_ctrl not configured\n"); + return -EINVAL; + } + break; + case BT_CMD_GETVAL_POWER_SRCS: + pr_err("BT_CMD_GETVAL_POWER_SRCS\n"); + set_gpios_srcs_status("BT_RESET_GPIO", BT_RESET_GPIO_CURRENT, + bt_power_pdata->bt_gpio_sys_rst); + set_gpios_srcs_status("SW_CTRL_GPIO", BT_SW_CTRL_GPIO_CURRENT, + bt_power_pdata->bt_gpio_sw_ctrl); + + num_vregs = bt_power_pdata->num_vregs; + for (itr = 0; itr < num_vregs; itr++) { + vreg_info = &bt_power_pdata->vreg_info[itr]; + set_pwr_srcs_status(vreg_info); + } + if (copy_to_user((void __user *)arg, + bt_power_src_status, sizeof(bt_power_src_status))) { + pr_err("%s: copy to user failed\n", __func__); + ret = -EFAULT; + } + break; + case BT_CMD_SET_IPA_TCS_INFO: + pr_err("%s: BT_CMD_SET_IPA_TCS_INFO\n", __func__); + btpower_enable_ipa_vreg(bt_power_pdata); + break; + default: + return -ENOIOCTLCMD; + } + return ret; +} + +static struct platform_driver bt_power_driver = { + .probe = bt_power_probe, + .remove = bt_power_remove, + .driver = { + .name = "bt_power", + .of_match_table = bt_power_match_table, + }, +}; + +static const struct file_operations bt_dev_fops = { + .unlocked_ioctl = bt_ioctl, + .compat_ioctl = bt_ioctl, +}; + +static int __init btpower_init(void) +{ + int ret = 0; + + probe_finished = false; + ret = platform_driver_register(&bt_power_driver); + if (ret) { + pr_err("%s: platform_driver_register error: %d\n", + __func__, ret); + goto driver_err; + } + + bt_major = register_chrdev(0, "bt", &bt_dev_fops); + if (bt_major < 0) { + pr_err("%s: failed to allocate char dev\n", __func__); + ret = -1; + goto chrdev_err; + } + + bt_class = class_create(THIS_MODULE, "bt-dev"); + if (IS_ERR(bt_class)) { + pr_err("%s: coudn't create class\n", __func__); + ret = -1; + goto class_err; + } + + + if (device_create(bt_class, NULL, MKDEV(bt_major, 0), + NULL, "btpower") == NULL) { + pr_err("%s: failed to allocate char dev\n", __func__); + goto device_err; + } + return 0; + +device_err: + class_destroy(bt_class); +class_err: + unregister_chrdev(bt_major, "bt"); +chrdev_err: + platform_driver_unregister(&bt_power_driver); +driver_err: + return ret; +} + +int btpower_aop_mbox_init(struct btpower_platform_data *pdata) +{ + struct mbox_client *mbox = &pdata->mbox_client_data; + struct mbox_chan *chan; + int ret = 0; + + mbox->dev = &pdata->pdev->dev; + mbox->tx_block = true; + mbox->tx_tout = BTPOWER_MBOX_TIMEOUT_MS; + mbox->knows_txdone = false; + + pdata->mbox_chan = NULL; + chan = mbox_request_channel(mbox, 0); + if (IS_ERR(chan)) { + pr_err("%s: failed to get mbox channel\n", __func__); + return PTR_ERR(chan); + } + pdata->mbox_chan = chan; + + ret = of_property_read_string(pdata->pdev->dev.of_node, + "qcom,vreg_ipa", + &pdata->vreg_ipa); + if (ret) + pr_info("%s: vreg for iPA not configured\n", __func__); + else + pr_info("%s: Mbox channel initialized\n", __func__); + + return 0; +} + +static int btpower_aop_set_vreg_param(struct btpower_platform_data *pdata, + const char *vreg_name, + enum btpower_vreg_param param, + enum btpower_tcs_seq seq, int val) +{ + struct qmp_pkt pkt; + char mbox_msg[BTPOWER_MBOX_MSG_MAX_LEN]; + static const char * const vreg_param_str[] = {"v", "m", "e"}; + static const char *const tcs_seq_str[] = {"upval", "dwnval", "enable"}; + int ret = 0; + + if (param > BTPOWER_VREG_ENABLE || seq > BTPOWER_TCS_ALL_SEQ || !vreg_name) + return -EINVAL; + + snprintf(mbox_msg, BTPOWER_MBOX_MSG_MAX_LEN, + "{class: wlan_pdc, res: %s.%s, %s: %d}", vreg_name, + vreg_param_str[param], tcs_seq_str[seq], val); + + pr_info("%s: sending AOP Mbox msg: %s\n", __func__, mbox_msg); + pkt.size = BTPOWER_MBOX_MSG_MAX_LEN; + pkt.data = mbox_msg; + + ret = mbox_send_message(pdata->mbox_chan, &pkt); + if (ret < 0) + pr_err("%s:Failed to send AOP mbox msg(%s), err(%d)\n", + __func__, mbox_msg, ret); + + return ret; +} + +static int btpower_enable_ipa_vreg(struct btpower_platform_data *pdata) +{ + int ret = 0; + static bool config_done; + + if (config_done) { + pr_info("%s: IPA Vreg already configured\n", __func__); + return 0; + } + + if (!pdata->vreg_ipa || !pdata->mbox_chan) { + pr_info("%s: mbox/iPA vreg not configured\n", __func__); + } else { + ret = btpower_aop_set_vreg_param(pdata, + pdata->vreg_ipa, + BTPOWER_VREG_ENABLE, + BTPOWER_TCS_UP_SEQ, 1); + if (ret >= 0) { + pr_info("%s:Enabled iPA\n", __func__); + config_done = true; + } + } + + return ret; +} + +static void __exit btpower_exit(void) +{ + platform_driver_unregister(&bt_power_driver); +} + +MODULE_LICENSE("GPL v2"); +MODULE_DESCRIPTION("MSM Bluetooth power control driver"); + +module_init(btpower_init); +module_exit(btpower_exit); diff --git a/rtc6226/Kconfig b/rtc6226/Kconfig new file mode 100644 index 0000000000..7bc68d747d --- /dev/null +++ b/rtc6226/Kconfig @@ -0,0 +1,14 @@ +# SPDX-License-Identifier: GPL-2.0-only + +config I2C_RTC6226_QCA + tristate "Richwave RTC6226 FM Radio Receiver support with I2C for QCA" + depends on I2C && VIDEO_V4L2 + help + This is a driver for I2C devices with the Richwave RTC6226 + chip. + + Say Y here if you want to connect this type of radio to your + computer's I2C port. + + To compile this driver as a module, choose M here: the + module will be called radio-i2c-RTC6226_QCA. diff --git a/rtc6226/Makefile b/rtc6226/Makefile new file mode 100644 index 0000000000..8eb15acfc9 --- /dev/null +++ b/rtc6226/Makefile @@ -0,0 +1,3 @@ +ccflags-y += -I$(BT_ROOT)/include +radio-i2c-rtc6226-qca-objs := radio-rtc6226-i2c.o radio-rtc6226-common.o +obj-$(CONFIG_I2C_RTC6226_QCA) += radio-i2c-rtc6226-qca.o diff --git a/rtc6226/radio-rtc6226-common.c b/rtc6226/radio-rtc6226-common.c new file mode 100644 index 0000000000..275a061b1b --- /dev/null +++ b/rtc6226/radio-rtc6226-common.c @@ -0,0 +1,2374 @@ +/* drivers/media/radio/rtc6226/radio-rtc6226-common.c + * + * Driver for Richwave RTC6226 FM Tuner + * + * Copyright (c) 2009 Tobias Lorenz + * Copyright (c) 2012 Hans de Goede + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * 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. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +/* + * 2008-01-12 Tobias Lorenz + * Version 1.0.0 + * - First working version + * 2008-01-13 Tobias Lorenz + * Version 1.0.1 + * - Improved error handling, every function now returns errno + * - Improved multi user access (start/mute/stop) + * - Channel doesn't get lost anymore after start/mute/stop + * - RDS support added (polling mode via interrupt EP 1) + * - marked default module parameters with *value* + * - switched from bit structs to bit masks + * - header file cleaned and integrated + * 2008-01-14 Tobias Lorenz + * Version 1.0.2 + * - hex values are now lower case + * - commented USB ID for ADS/Tech moved on todo list + * - blacklisted in hid-quirks.c + * - rds buffer handling functions integrated into *_work, *_read + * - rds_command exchanged against simple retval + * - check for firmware version 15 + * - code order and prototypes still remain the same + * - spacing and bottom of band codes remain the same + * 2008-01-16 Tobias Lorenz + * Version 1.0.3 + * - code reordered to avoid function prototypes + * - switch/case defaults are now more user-friendly + * - unified comment style + * - applied all checkpatch.pl v1.12 suggestions + * except the warning about the too long lines with bit comments + * - renamed FMRADIO to RADIO to cut line length (checkpatch.pl) + * 2008-01-22 Tobias Lorenz + * Version 1.0.4 + * - avoid poss. locking when doing copy_to_user which may sleep + * - RDS is automatically activated on read now + * - code cleaned of unnecessary rds_commands + * - USB Vendor/Product ID for ADS/Tech FM Radio Receiver verified + * (thanks to Guillaume RAMOUSSE) + * 2008-01-27 Tobias Lorenz + * Version 1.0.5 + * - number of seek_retries changed to tune_timeout + * - fixed problem with incomplete tune operations by own buffers + * - optimization of variables and printf types + * - improved error logging + * 2008-01-31 Tobias Lorenz + * Oliver Neukum + * Version 1.0.6 + * - fixed coverity checker warnings in *_usb_driver_disconnect + * - probe()/open() race by correct ordering in probe() + * - DMA coherency rules by separate allocation of all buffers + * - use of endianness macros + * - abuse of spinlock, replaced by mutex + * - racy handling of timer in disconnect, + * replaced by delayed_work + * - racy interruptible_sleep_on(), + * replaced with wait_event_interruptible() + * - handle signals in read() + * 2008-02-08 Tobias Lorenz + * Oliver Neukum + * Version 1.0.7 + * - usb autosuspend support + * - unplugging fixed + * 2008-05-07 Tobias Lorenz + * Version 1.0.8 + * - hardware frequency seek support + * - afc indication + * - more safety checks, get_freq return errno + * - vidioc behavior corrected according to v4l2 spec + * 2008-10-20 Alexey Klimov + * - add support for KWorld USB FM Radio FM700 + * - blacklisted KWorld radio in hid-core.c and hid-ids.h + * 2008-12-03 Mark Lord + * - add support for DealExtreme USB Radio + * 2009-01-31 Bob Ross + * - correction of stereo detection/setting + * - correction of signal strength indicator scaling + * 2009-01-31 Rick Bronson + * Tobias Lorenz + * - add LED status output + * - get HW/SW version from scratchpad + * 2009-06-16 Edouard Lafargue + * Version 1.0.10 + * - add support for interrupt mode for RDS endpoint, + * instead of polling. + * Improves RDS reception significantly + * 2018-02-01 LG Electronics, Inc. + * 2018-08-19 Richwave Technology Co.Ltd + * Copyright (c) 2021 Qualcomm Innovation Center, Inc. All rights reserved. + */ + +/* kernel includes */ +#include +#include +#include "radio-rtc6226.h" +/************************************************************************** + * Module Parameters + **************************************************************************/ + +/* Bottom of Band (MHz) */ +/* 0: 87.5 - 108 MHz (USA, Europe)*/ +/* 1: 76 - 108 MHz (Japan wide band) */ +/* 2: 76 - 90 MHz (Japan) */ + +/* De-emphasis */ +/* 0: 75 us (USA) */ +/* 1: 50 us (Europe, Australia, Japan) */ +static unsigned short de; + +wait_queue_head_t rtc6226_wq; +int rtc6226_wq_flag = NO_WAIT; +#ifdef New_VolumeControl +unsigned short global_volume; +#endif + +void rtc6226_q_event(struct rtc6226_device *radio, + enum rtc6226_evt_t event) +{ + + struct kfifo *data_b; + unsigned char evt = event; + + data_b = &radio->data_buf[RTC6226_FM_BUF_EVENTS]; + + FMDBG("%s updating event_q with event %x\n", __func__, event); + if (kfifo_in_locked(data_b, + &evt, + 1, + &radio->buf_lock[RTC6226_FM_BUF_EVENTS])) + wake_up_interruptible(&radio->event_queue); +} + +/* + * rtc6226_set_chan - set the channel + */ +static int rtc6226_set_chan(struct rtc6226_device *radio, unsigned short chan) +{ + int retval; + unsigned short current_chan = + radio->registers[CHANNEL] & CHANNEL_CSR0_CH; + + FMDBG("%s CHAN=%d chan=%d\n", __func__, radio->registers[CHANNEL], + chan); + + /* start tuning */ + radio->registers[CHANNEL] &= ~CHANNEL_CSR0_CH; + radio->registers[CHANNEL] |= CHANNEL_CSR0_TUNE | chan; + retval = rtc6226_set_register(radio, CHANNEL); + if (retval < 0) { + radio->registers[CHANNEL] = current_chan; + goto done; + } + +done: + FMDBG("%s exit %d\n", __func__, retval); + return retval; +} + +/* + * rtc6226_get_freq - get the frequency + */ +static int rtc6226_get_freq(struct rtc6226_device *radio, unsigned int *freq) +{ + unsigned short chan; + unsigned short rssi = 0; + int retval; + + FMDBG("%s enter\n", __func__); + + /* read channel */ + retval = rtc6226_get_register(radio, CHANNEL1); + if (retval < 0) { + FMDBG("%s fail to get register\n", __func__); + goto end; + } + chan = radio->registers[CHANNEL1] & STATUS_READCH; + retval = rtc6226_get_register(radio, RSSI); + rssi = radio->registers[RSSI] & RSSI_RSSI; + FMDBG("%s chan %d\n", __func__, chan); + *freq = chan * TUNE_STEP_SIZE; + FMDBG("FMRICHWAVE, freq= %d, rssi= %d dBuV\n", *freq, rssi); + + if (rssi < radio->rssi_th) + rtc6226_q_event(radio, RTC6226_EVT_BELOW_TH); + else + rtc6226_q_event(radio, RTC6226_EVT_ABOVE_TH); + +end: + return retval; +} + + +/* + * rtc6226_set_freq - set the frequency + */ +int rtc6226_set_freq(struct rtc6226_device *radio, unsigned int freq) +{ + unsigned int band_bottom; + unsigned short chan; + unsigned char i; + int retval = 0; + + FMDBG("%s enter freq:%d\n", __func__, freq); + + band_bottom = (radio->registers[RADIOSEEKCFG2] & + CHANNEL_CSR0_FREQ_BOT) * TUNE_STEP_SIZE; + + if (freq < band_bottom) + freq = band_bottom; + + /* Chan = Freq (Mhz) / 10 */ + chan = (u16)(freq / TUNE_STEP_SIZE); + + FMDBG("%s chan:%d freq:%d band_bottom:%d\n", __func__, + chan, freq, band_bottom); + retval = rtc6226_set_chan(radio, chan); + if (retval < 0) { + FMDBG("%s fail to set chan\n", __func__); + goto end; + } + + for (i = 0x12; i < RADIO_REGISTER_NUM; i++) { + retval = rtc6226_get_register(radio, i); + if (retval < 0) { + FMDBG("%s fail to get register\n", __func__); + goto end; + } + } + +end: + return retval; +} + + +/* + * rtc6226_set_seek - set seek + */ +static int rtc6226_set_seek(struct rtc6226_device *radio, + unsigned int seek_up, unsigned int seek_wrap) +{ + int retval = 0; + unsigned short seekcfg1_val = radio->registers[SEEKCFG1]; + + FMDBG("%s enter up:%d wrap:%d, th:%d\n", __func__, seek_up, seek_wrap, + seekcfg1_val); + if (seek_wrap) + radio->registers[SEEKCFG1] &= ~SEEKCFG1_CSR0_SKMODE; + else + radio->registers[SEEKCFG1] |= SEEKCFG1_CSR0_SKMODE; + + if (seek_up) + radio->registers[SEEKCFG1] |= SEEKCFG1_CSR0_SEEKUP; + else + radio->registers[SEEKCFG1] &= ~SEEKCFG1_CSR0_SEEKUP; + + radio->registers[SEEKCFG1] &= ~SEEKCFG1_CSR0_SEEK; + retval = rtc6226_set_register(radio, SEEKCFG1); + if (retval < 0) { + radio->registers[SEEKCFG1] = seekcfg1_val; + goto done; + } + + /* start seeking */ + radio->registers[SEEKCFG1] |= SEEKCFG1_CSR0_SEEK; + retval = rtc6226_set_register(radio, SEEKCFG1); + if (retval < 0) { + radio->registers[SEEKCFG1] = seekcfg1_val; + goto done; + } + +done: + FMDBG("%s exit %d\n", __func__, retval); + return retval; +} + +static void rtc6226_update_search_list(struct rtc6226_device *radio, int freq) +{ + int temp_freq = freq; + int index = radio->srch_list.num_stations_found; + + temp_freq = temp_freq - + (radio->recv_conf.band_low_limit * TUNE_STEP_SIZE); + temp_freq = temp_freq / 50; + radio->srch_list.rel_freq[index].rel_freq_lsb = GET_LSB(temp_freq); + radio->srch_list.rel_freq[index].rel_freq_msb = GET_MSB(temp_freq); + radio->srch_list.num_stations_found++; +} + +void rtc6226_scan(struct work_struct *work) +{ + struct rtc6226_device *radio; + int current_freq_khz = 0; + struct kfifo *data_b; + int len = 0; + u32 next_freq_khz; + int retval = 0; + int i, rssi; + + FMDBG("%s enter\n", __func__); + + radio = container_of(work, struct rtc6226_device, work_scan.work); + + retval = rtc6226_get_freq(radio, ¤t_freq_khz); + if (retval < 0) { + FMDERR("%s fail to get freq\n", __func__); + goto seek_tune_fail; + } + FMDBG("%s current freq %d\n", __func__, current_freq_khz); + /* tune to lowest freq of the band */ + radio->seek_tune_status = SCAN_PENDING; + retval = rtc6226_set_freq(radio, + radio->recv_conf.band_low_limit * TUNE_STEP_SIZE); + if (retval < 0) + goto seek_tune_fail; + /* wait for tune to complete. */ + if (!wait_for_completion_timeout(&radio->completion, + msecs_to_jiffies(TUNE_TIMEOUT_MSEC))) { + FMDERR("In %s, didn't receive STC for tune\n", __func__); + rtc6226_q_event(radio, RTC6226_EVT_ERROR); + return; + } + + while (1) { + if (radio->is_search_cancelled) { + FMDERR("%s: scan cancelled\n", __func__); + if (radio->g_search_mode == SCAN_FOR_STRONG) + goto seek_tune_fail; + else + goto seek_cancelled; + goto seek_cancelled; + } else if (radio->mode != FM_RECV) { + FMDERR("%s: FM is not in proper state\n", __func__); + rtc6226_q_event(radio, RTC6226_EVT_ERROR); + return; + } + + retval = rtc6226_set_seek(radio, SRCH_UP, WRAP_DISABLE); + if (retval < 0) { + FMDERR("%s seek fail %d\n", __func__, retval); + goto seek_tune_fail; + } + /* wait for seek to complete */ + if (!wait_for_completion_timeout(&radio->completion, + msecs_to_jiffies(SEEK_TIMEOUT_MSEC))) { + FMDERR("%s:timeout didn't receive STC for seek\n", + __func__); + rtc6226_get_all_registers(radio); + for (i = 0; i < 16; i++) + FMDBG("%s registers[%d]:%x\n", __func__, i, + radio->registers[i]); + /* FM is not correct state or scan is cancelled */ + rtc6226_q_event(radio, RTC6226_EVT_ERROR); + return; + } else + FMDERR("%s: received STC for seek\n", __func__); + + retval = rtc6226_get_freq(radio, &next_freq_khz); + if (retval < 0) { + FMDERR("%s fail to get freq\n", __func__); + goto seek_tune_fail; + } + FMDBG("%s next freq %d\n", __func__, next_freq_khz); + + retval = rtc6226_get_register(radio, RSSI); + if (retval < 0) { + FMDERR("%s read fail to RSSI\n", __func__); + goto seek_tune_fail; + } + rssi = radio->registers[RSSI] & RSSI_RSSI; + FMDBG("%s valid channel %d, rssi %d threshold rssi %d\n", + __func__, next_freq_khz, rssi, radio->rssi_th); + + if (radio->g_search_mode == SCAN && rssi >= radio->rssi_th) + rtc6226_q_event(radio, RTC6226_EVT_TUNE_SUCC); + /* + * If scan is cancelled or FM is not ON, break ASAP so that we + * don't need to sleep for dwell time. + */ + if (radio->is_search_cancelled) { + FMDERR("%s: scan cancelled\n", __func__); + if (radio->g_search_mode == SCAN_FOR_STRONG) + goto seek_tune_fail; + else + goto seek_cancelled; + goto seek_cancelled; + } else if (radio->mode != FM_RECV) { + FMDERR("%s: FM is not in proper state\n", __func__); + rtc6226_q_event(radio, RTC6226_EVT_ERROR); + return; + } + FMDBG("%s update search list %d\n", __func__, next_freq_khz); + if (radio->g_search_mode == SCAN && rssi >= radio->rssi_th) { + /* sleep for dwell period */ + msleep(radio->dwell_time_sec * 1000); + /* need to queue the event when the seek completes */ + FMDBG("%s frequency update list %d\n", __func__, + next_freq_khz); + rtc6226_q_event(radio, RTC6226_EVT_SCAN_NEXT); + } else if (radio->g_search_mode == SCAN_FOR_STRONG + && rssi >= radio->rssi_th) { + rtc6226_update_search_list(radio, next_freq_khz); + } + + FMDBG("%s : STATUS=0x%4.4hx\n", __func__, + radio->registers[STATUS]); + if (radio->registers[STATUS] & STATUS_SF || + (radio->recv_conf.band_high_limit * + TUNE_STEP_SIZE) == next_freq_khz) { + FMDERR("%s Seek one more time if lower freq is valid\n", + __func__); + retval = rtc6226_set_seek(radio, SRCH_UP, WRAP_ENABLE); + if (retval < 0) { + FMDERR("%s seek fail %d\n", __func__, retval); + goto seek_tune_fail; + } + if (!wait_for_completion_timeout(&radio->completion, + msecs_to_jiffies(SEEK_TIMEOUT_MSEC))) { + FMDERR("timeout didn't receive STC for seek\n"); + rtc6226_q_event(radio, RTC6226_EVT_ERROR); + return; + } else { + FMDERR("%s: received STC for seek\n", __func__); + retval = rtc6226_get_freq(radio, + &next_freq_khz); + if (retval < 0) { + FMDERR("%s getFreq failed\n", __func__); + goto seek_tune_fail; + } + retval = rtc6226_get_register(radio, RSSI); + if (retval < 0) { + FMDERR("%s read fail to RSSI\n", + __func__); + goto seek_tune_fail; + } + rssi = radio->registers[RSSI] & RSSI_RSSI; + FMDBG("%s freq %d, rssi %d rssi threshold %d\n", + __func__, next_freq_khz, rssi, radio->rssi_th); + if ((radio->recv_conf.band_low_limit * + TUNE_STEP_SIZE) == + next_freq_khz && + rssi >= radio->rssi_th) { + FMDERR("lower band freq is valid\n"); + rtc6226_q_event(radio, + RTC6226_EVT_TUNE_SUCC); + /* sleep for dwell period */ + msleep(radio->dwell_time_sec * 1000); + rtc6226_q_event(radio, + RTC6226_EVT_SCAN_NEXT); + } + } + break; + } + + } + +seek_tune_fail: + if (radio->g_search_mode == SCAN_FOR_STRONG) { + len = radio->srch_list.num_stations_found * 2 + + sizeof(radio->srch_list.num_stations_found); + data_b = &radio->data_buf[RTC6226_FM_BUF_SRCH_LIST]; + kfifo_in_locked(data_b, &radio->srch_list, len, + &radio->buf_lock[RTC6226_FM_BUF_SRCH_LIST]); + rtc6226_q_event(radio, RTC6226_EVT_NEW_SRCH_LIST); + } +seek_cancelled: + /* tune to original frequency */ + retval = rtc6226_set_freq(radio, current_freq_khz); + if (retval < 0) + FMDERR("%s: Tune to orig freq failed with error %d\n", + __func__, retval); + else { + if (!wait_for_completion_timeout(&radio->completion, + msecs_to_jiffies(TUNE_TIMEOUT_MSEC))) + FMDERR("%s: didn't receive STD for tune\n", __func__); + else + FMDERR("%s: received STD for tune\n", __func__); + } + /* Enable the RDS as it was disabled before scan */ + rtc6226_rds_on(radio); + rtc6226_q_event(radio, RTC6226_EVT_SEEK_COMPLETE); + rtc6226_q_event(radio, RTC6226_EVT_TUNE_SUCC); + radio->seek_tune_status = NO_SEEK_TUNE_PENDING; + FMDERR("%s seek cancelled %d\n", __func__, retval); + return; + +} + +int rtc6226_cancel_seek(struct rtc6226_device *radio) +{ + int retval = 0; + + FMDBG("%s enter\n", __func__); + mutex_lock(&radio->lock); + + /* stop seeking */ + radio->registers[SEEKCFG1] &= ~SEEKCFG1_CSR0_SEEK; + retval = rtc6226_set_register(radio, SEEKCFG1); + complete(&radio->completion); + + mutex_unlock(&radio->lock); + radio->is_search_cancelled = true; + if (radio->g_search_mode == SEEK) + rtc6226_q_event(radio, RTC6226_EVT_SEEK_COMPLETE); + + return retval; + +} + +void rtc6226_search(struct rtc6226_device *radio, bool on) +{ + int current_freq_khz; + + current_freq_khz = radio->tuned_freq_khz; + + if (on) { + FMDBG("%s: Queuing the work onto scan work q\n", __func__); + queue_delayed_work(radio->wqueue_scan, &radio->work_scan, + msecs_to_jiffies(10)); + } else { + rtc6226_cancel_seek(radio); + } +} + +/* + * rtc6226_start - switch on radio + */ +int rtc6226_start(struct rtc6226_device *radio) +{ + int retval; + u8 i2c_error; + u16 initbuf[] = {0x0000}; + + radio->registers[BANKCFG] = 0x0000; + i2c_error = 0; + /* Keep in case of any unpredicted control */ + /* Set 0x16AA */ + radio->registers[DEVICEID] = 0x16AA; + /* released the I2C from unexpected I2C start condition */ + retval = rtc6226_set_register(radio, DEVICEID); + /* recheck TH : 10 */ + while ((retval < 0) && (i2c_error < 10)) { + retval = rtc6226_set_register(radio, DEVICEID); + i2c_error++; + } + + if (retval < 0) { + FMDERR("%s set to fail retval = %d\n", __func__, retval); + /* goto done;*/ + } + msleep(30); + + /* Don't read all between writing 0x16AA and 0x96AA */ + i2c_error = 0; + radio->registers[DEVICEID] = 0x96AA; + retval = rtc6226_set_register(radio, DEVICEID); + /* recheck TH : 10 */ + while ((retval < 0) && (i2c_error < 10)) { + retval = rtc6226_set_register(radio, DEVICEID); + i2c_error++; + } + + if (retval < 0) + FMDERR("%s set to fail 0x96AA %d\n", __func__, retval); + msleep(30); + + /* get device and chip versions */ + rtc6226_get_register(radio, DEVICEID); + rtc6226_get_register(radio, CHIPID); + FMDBG("%s DeviceID=0x%x ChipID=0x%x Addr=0x%x\n", __func__, + radio->registers[DEVICEID], radio->registers[CHIPID], + radio->client->addr); + + /* Have to update shadow buf from all register */ + retval = rtc6226_get_all_registers(radio); + if (retval < 0) + goto done; + + FMDBG("%s rtc6226_power_up1: DeviceID=0x%4.4hx ChipID=0x%4.4hx\n", + __func__, + radio->registers[DEVICEID], radio->registers[CHIPID]); + FMDBG("%s rtc6226_power_up2: Reg2=0x%4.4hx Reg3=0x%4.4hx\n", __func__, + radio->registers[MPXCFG], radio->registers[CHANNEL]); + FMDBG("%s rtc6226_power_up3: Reg4=0x%4.4hx Reg5=0x%4.4hx\n", __func__, + radio->registers[SYSCFG], radio->registers[SEEKCFG1]); + FMDBG("%s rtc6226_power_up4: Reg6=0x%4.4hx Reg7=0x%4.4hx\n", __func__, + radio->registers[POWERCFG], radio->registers[PADCFG]); + FMDBG("%s rtc6226_power_up5: Reg8=0x%4.4hx Reg9=0x%4.4hx\n", __func__, + radio->registers[8], radio->registers[9]); + FMDBG("%s rtc6226_power_up6: regA=0x%4.4hx RegB=0x%4.4hx\n", __func__, + radio->registers[10], radio->registers[11]); + FMDBG("%s rtc6226_power_up7: regC=0x%4.4hx RegD=0x%4.4hx\n", __func__, + radio->registers[12], radio->registers[13]); + FMDBG("%s rtc6226_power_up8: regE=0x%4.4hx RegF=0x%4.4hx\n", __func__, + radio->registers[14], radio->registers[15]); + + + FMDBG("%s DeviceID=0x%x ChipID=0x%x Addr=0x%x\n", __func__, + radio->registers[DEVICEID], radio->registers[CHIPID], + radio->client->addr); + + /* initial patch 01 */ + initbuf[0] = 0x0038; + retval = rtc6226_set_serial_registers(radio, initbuf, 0x40); + if (retval < 0) + goto done; + + /* initial patch 02 */ + initbuf[0] = 0xC100; + retval = rtc6226_set_serial_registers(radio, initbuf, 0x8E); + if (retval < 0) + goto done; + +done: + return retval; +} + +/* + * rtc6226_stop - switch off radio + */ +int rtc6226_stop(struct rtc6226_device *radio) +{ + int retval; + + /* sysconfig */ + radio->registers[SYSCFG] &= ~SYSCFG_CSR0_RDS_EN; + radio->registers[SYSCFG] &= ~SYSCFG_CSR0_RDSIRQEN; + radio->registers[SYSCFG] &= ~SYSCFG_CSR0_STDIRQEN; + retval = rtc6226_set_register(radio, SYSCFG); + if (retval < 0) + goto done; + + /* powerconfig */ + radio->registers[MPXCFG] &= ~MPXCFG_CSR0_DIS_MUTE; + retval = rtc6226_set_register(radio, MPXCFG); + + /* POWERCFG_ENABLE has to automatically go low */ + radio->registers[POWERCFG] |= POWERCFG_CSR0_DISABLE; + radio->registers[POWERCFG] &= ~POWERCFG_CSR0_ENABLE; + retval = rtc6226_set_register(radio, POWERCFG); + + /* Set 0x16AA */ + radio->registers[DEVICEID] = 0x16AA; + retval = rtc6226_set_register(radio, DEVICEID); + +done: + return retval; +} + +static void rtc6226_get_rds(struct rtc6226_device *radio) +{ + int retval = 0; + + mutex_lock(&radio->lock); + retval = rtc6226_get_all_registers(radio); + + if (retval < 0) { + FMDERR("%s read fail%d\n", __func__, retval); + mutex_unlock(&radio->lock); + return; + } + radio->block[0] = radio->registers[BA_DATA]; + radio->block[1] = radio->registers[BB_DATA]; + radio->block[2] = radio->registers[BC_DATA]; + radio->block[3] = radio->registers[BD_DATA]; + + radio->bler[0] = (radio->registers[RSSI] & RSSI_RDS_BA_ERRS) >> 14; + radio->bler[1] = (radio->registers[RSSI] & RSSI_RDS_BB_ERRS) >> 12; + radio->bler[2] = (radio->registers[RSSI] & RSSI_RDS_BC_ERRS) >> 10; + radio->bler[3] = (radio->registers[RSSI] & RSSI_RDS_BD_ERRS) >> 8; + mutex_unlock(&radio->lock); +} + +static void rtc6226_pi_check(struct rtc6226_device *radio, u16 current_pi) +{ + if (radio->pi != current_pi) { + FMDBG("%s current_pi %x , radio->pi %x\n" + , __func__, current_pi, radio->pi); + radio->pi = current_pi; + } else { + FMDBG("%s Received same PI code\n", __func__); + } +} + +static void rtc6226_pty_check(struct rtc6226_device *radio, u8 current_pty) +{ + if (radio->pty != current_pty) { + FMDBG("%s PTY code of radio->block[1] = %x\n", + __func__, current_pty); + radio->pty = current_pty; + } else { + FMDBG("%s PTY repeated\n", __func__); + } +} + +static bool is_new_freq(struct rtc6226_device *radio, u32 freq) +{ + u8 i = 0; + + for (i = 0; i < radio->af_info2.size; i++) { + if (freq == radio->af_info2.af_list[i]) + return false; + } + + return true; +} + +static bool is_different_af_list(struct rtc6226_device *radio) +{ + u8 i = 0, j = 0; + u32 freq; + + if (radio->af_info1.orig_freq_khz != radio->af_info2.orig_freq_khz) + return true; + + /* freq is same, check if the AFs are same. */ + for (i = 0; i < radio->af_info1.size; i++) { + freq = radio->af_info1.af_list[i]; + for (j = 0; j < radio->af_info2.size; j++) { + if (freq == radio->af_info2.af_list[j]) + break; + } + + /* freq is not there in list2 i.e list1, list2 are different.*/ + if (j == radio->af_info2.size) + return true; + } + + return false; +} + +static bool is_valid_freq(struct rtc6226_device *radio, u32 freq) +{ + u32 band_low_limit; + u32 band_high_limit; + u8 spacing = 0; + + band_low_limit = radio->recv_conf.band_low_limit * TUNE_STEP_SIZE; + band_high_limit = radio->recv_conf.band_high_limit * TUNE_STEP_SIZE; + + if (radio->space == 0) + spacing = CH_SPACING_200; + else if (radio->space == 1) + spacing = CH_SPACING_100; + else if (radio->space == 2) + spacing = CH_SPACING_50; + else + return false; + + if ((freq >= band_low_limit) && + (freq <= band_high_limit) && + ((freq - band_low_limit) % spacing == 0)) + return true; + + return false; +} + +static void rtc6226_update_af_list(struct rtc6226_device *radio) +{ + + bool retval; + u8 i = 0; + u8 af_data = radio->block[2] >> 8; + u32 af_freq_khz; + u32 tuned_freq_khz; + struct kfifo *buff; + struct af_list_ev ev; + spinlock_t lock = radio->buf_lock[RTC6226_FM_BUF_AF_LIST]; + + rtc6226_get_freq(radio, &tuned_freq_khz); + + for (; i < NO_OF_AF_IN_GRP; i++, af_data = radio->block[2] & 0xFF) { + + if (af_data >= MIN_AF_CNT_CODE && af_data <= MAX_AF_CNT_CODE) { + + FMDBG("%s: resetting af info, freq %u, pi %u\n", + __func__, tuned_freq_khz, radio->pi); + radio->af_info2.inval_freq_cnt = 0; + radio->af_info2.cnt = 0; + radio->af_info2.orig_freq_khz = 0; + + /* AF count. */ + radio->af_info2.cnt = af_data - NO_AF_CNT_CODE; + radio->af_info2.orig_freq_khz = tuned_freq_khz; + radio->af_info2.pi = radio->pi; + + FMDBG("%s: current freq is %u, AF cnt is %u\n", + __func__, tuned_freq_khz, radio->af_info2.cnt); + } else if (af_data >= MIN_AF_FREQ_CODE && + af_data <= MAX_AF_FREQ_CODE && + radio->af_info2.orig_freq_khz != 0 && + radio->af_info2.size < MAX_NO_OF_AF) { + + af_freq_khz = SCALE_AF_CODE_TO_FREQ_KHZ(af_data); + retval = is_valid_freq(radio, af_freq_khz); + if (!retval) { + FMDBG("%s: Invalid AF\n", __func__); + radio->af_info2.inval_freq_cnt++; + continue; + } + + retval = is_new_freq(radio, af_freq_khz); + if (!retval) { + FMDBG("%s: Duplicate AF\n", __func__); + radio->af_info2.inval_freq_cnt++; + continue; + } + + /* update the AF list */ + radio->af_info2.af_list[radio->af_info2.size++] = + af_freq_khz; + FMDBG("%s: AF is %u\n", __func__, af_freq_khz); + if ((radio->af_info2.size + + radio->af_info2.inval_freq_cnt == + radio->af_info2.cnt) && + is_different_af_list(radio)) { + + /* Copy the list to af_info1. */ + radio->af_info1.cnt = radio->af_info2.cnt; + radio->af_info1.size = radio->af_info2.size; + radio->af_info1.pi = radio->af_info2.pi; + radio->af_info1.orig_freq_khz = + radio->af_info2.orig_freq_khz; + memset(radio->af_info1.af_list, 0, + sizeof(radio->af_info1.af_list)); + + memcpy(radio->af_info1.af_list, + radio->af_info2.af_list, + sizeof(radio->af_info2.af_list)); + + /* AF list changed, post it to user space */ + memset(&ev, 0, sizeof(struct af_list_ev)); + + ev.tune_freq_khz = + radio->af_info1.orig_freq_khz; + ev.pi_code = radio->pi; + ev.af_size = radio->af_info1.size; + + memcpy(&ev.af_list[0], + radio->af_info1.af_list, + GET_AF_LIST_LEN(ev.af_size)); + + buff = &radio->data_buf[RTC6226_FM_BUF_AF_LIST]; + kfifo_in_locked(buff, + (u8 *)&ev, + GET_AF_EVT_LEN(ev.af_size), + &lock); + + FMDBG("%s: posting AF list evt,currfreq %u\n", + __func__, ev.tune_freq_khz); + + rtc6226_q_event(radio, + RTC6226_EVT_NEW_AF_LIST); + } + } + } +} + +static void rtc6226_update_ps(struct rtc6226_device *radio, u8 addr, u8 ps) +{ + u8 i; + bool ps_txt_chg = false; + bool ps_cmplt = true; + u8 *data; + struct kfifo *data_b; + + FMDBG("%s enter addr:%x ps:%x\n", __func__, addr, ps); + + if (radio->ps_tmp0[addr] == ps) { + if (radio->ps_cnt[addr] < PS_VALIDATE_LIMIT) { + radio->ps_cnt[addr]++; + } else { + radio->ps_cnt[addr] = PS_VALIDATE_LIMIT; + radio->ps_tmp1[addr] = ps; + } + } else if (radio->ps_tmp1[addr] == ps) { + if (radio->ps_cnt[addr] >= PS_VALIDATE_LIMIT) { + ps_txt_chg = true; + radio->ps_cnt[addr] = PS_VALIDATE_LIMIT + 1; + } else { + radio->ps_cnt[addr] = PS_VALIDATE_LIMIT; + } + radio->ps_tmp1[addr] = radio->ps_tmp0[addr]; + radio->ps_tmp0[addr] = ps; + } else if (!radio->ps_cnt[addr]) { + radio->ps_tmp0[addr] = ps; + radio->ps_cnt[addr] = 1; + } else { + radio->ps_tmp1[addr] = ps; + } + + if (ps_txt_chg) { + for (i = 0; i < MAX_PS_LEN; i++) { + if (radio->ps_cnt[i] > 1) + radio->ps_cnt[i]--; + } + } + + for (i = 0; i < MAX_PS_LEN; i++) { + if (radio->ps_cnt[i] < PS_VALIDATE_LIMIT) { + FMDBG("%s ps_cnt[%d] %d\n", __func__, i, + radio->ps_cnt[i]); + ps_cmplt = false; + return; + } + } + + if (ps_cmplt) { + for (i = 0; (i < MAX_PS_LEN) && + (radio->ps_display[i] == radio->ps_tmp0[i]); i++) + ; + if (i == MAX_PS_LEN) { + FMDBG("%s Same PS string repeated\n", __func__); + return; + } + + for (i = 0; i < MAX_PS_LEN; i++) + radio->ps_display[i] = radio->ps_tmp0[i]; + + data = kmalloc(PS_EVT_DATA_LEN, GFP_ATOMIC); + if (data != NULL) { + data[0] = NO_OF_PS; + data[1] = radio->pty; + data[2] = (radio->pi >> 8) & 0xFF; + data[3] = (radio->pi & 0xFF); + data[4] = 0; + memcpy(data + OFFSET_OF_PS, + radio->ps_tmp0, MAX_PS_LEN); + data_b = &radio->data_buf[RTC6226_FM_BUF_PS_RDS]; + kfifo_in_locked(data_b, data, PS_EVT_DATA_LEN, + &radio->buf_lock[RTC6226_FM_BUF_PS_RDS]); + FMDBG("%s Q the PS event\n", __func__); + rtc6226_q_event(radio, RTC6226_EVT_NEW_PS_RDS); + kfree(data); + } else { + FMDERR("%s Memory allocation failed for PTY\n", + __func__); + } + } +} + +static void display_rt(struct rtc6226_device *radio) +{ + u8 len = 0, i = 0; + u8 *data; + struct kfifo *data_b; + bool rt_cmplt = true; + + FMDBG("%s enter\n", __func__); + + for (i = 0; i < MAX_RT_LEN; i++) { + if (radio->rt_cnt[i] < RT_VALIDATE_LIMIT) { + FMDBG("%s rt_cnt %d\n", __func__, radio->rt_cnt[i]); + rt_cmplt = false; + return; + } + if (radio->rt_tmp0[i] == END_OF_RT) + break; + } + if (rt_cmplt) { + while ((len < MAX_RT_LEN) && (radio->rt_tmp0[len] != END_OF_RT)) + len++; + + for (i = 0; (i < len) && + (radio->rt_display[i] == radio->rt_tmp0[i]); i++) + ; + if (i == len) { + FMDBG("%s Same RT string repeated\n", __func__); + return; + } + for (i = 0; i < len; i++) + radio->rt_display[i] = radio->rt_tmp0[i]; + data = kmalloc(len + OFFSET_OF_RT, GFP_ATOMIC); + if (data != NULL) { + data[0] = len; /* len of RT */ + data[1] = radio->pty; + data[2] = (radio->pi >> 8) & 0xFF; + data[3] = (radio->pi & 0xFF); + data[4] = radio->rt_flag; + memcpy(data + OFFSET_OF_RT, radio->rt_display, len); + data_b = &radio->data_buf[RTC6226_FM_BUF_RT_RDS]; + kfifo_in_locked(data_b, data, OFFSET_OF_RT + len, + &radio->buf_lock[RTC6226_FM_BUF_RT_RDS]); + FMDBG("%s Q the RT event\n", __func__); + rtc6226_q_event(radio, RTC6226_EVT_NEW_RT_RDS); + kfree(data); + } else { + FMDERR("%s Memory allocation failed for PTY\n", + __func__); + } + } +} + +static void rt_handler(struct rtc6226_device *radio, u8 ab_flg, + u8 cnt, u8 addr, u8 *rt) +{ + u8 i, errcnt, blermax; + bool rt_txt_chg = false; + + FMDBG("%s enter\n", __func__); + + if (ab_flg != radio->rt_flag && radio->valid_rt_flg) { + for (i = 0; i < sizeof(radio->rt_cnt); i++) { + if (!radio->rt_tmp0[i]) { + radio->rt_tmp0[i] = ' '; + radio->rt_cnt[i]++; + } + } + memset(radio->rt_cnt, 0, sizeof(radio->rt_cnt)); + memset(radio->rt_tmp0, 0, sizeof(radio->rt_tmp0)); + memset(radio->rt_tmp1, 0, sizeof(radio->rt_tmp1)); + } + + radio->rt_flag = ab_flg; + radio->valid_rt_flg = true; + + for (i = 0; i < cnt; i++) { + if ((i < 2) && (cnt > 2)) { + errcnt = radio->bler[2]; + blermax = CORRECTED_THREE_TO_FIVE; + } else { + errcnt = radio->bler[3]; + blermax = CORRECTED_THREE_TO_FIVE; + } + if (errcnt <= blermax) { + if (!rt[i]) + rt[i] = ' '; + if (radio->rt_tmp0[addr+i] == rt[i]) { + if (radio->rt_cnt[addr+i] < RT_VALIDATE_LIMIT) { + radio->rt_cnt[addr+i]++; + } else { + radio->rt_cnt[addr+i] = + RT_VALIDATE_LIMIT; + radio->rt_tmp1[addr+i] = rt[i]; + } + } else if (radio->rt_tmp1[addr+i] == rt[i]) { + if (radio->rt_cnt[addr+i] >= + RT_VALIDATE_LIMIT) { + rt_txt_chg = true; + radio->rt_cnt[addr+i] = + RT_VALIDATE_LIMIT + 1; + } else { + radio->rt_cnt[addr+i] = + RT_VALIDATE_LIMIT; + } + radio->rt_tmp1[addr+i] = radio->rt_tmp0[addr+i]; + radio->rt_tmp0[addr+i] = rt[i]; + } else if (!radio->rt_cnt[addr+i]) { + radio->rt_tmp0[addr+i] = rt[i]; + radio->rt_cnt[addr+i] = 1; + } else { + radio->rt_tmp1[addr+i] = rt[i]; + } + } + } + + if (rt_txt_chg) { + for (i = 0; i < MAX_RT_LEN; i++) { + if (radio->rt_cnt[i] > 1) + radio->rt_cnt[i]--; + } + } + display_rt(radio); +} + +static void rtc6226_raw_rds(struct rtc6226_device *radio) +{ + u16 aid, app_grp_typ; + + aid = radio->block[3]; + app_grp_typ = radio->block[1] & APP_GRP_typ_MASK; + FMDBG("%s app_grp_typ = %x\n", __func__, app_grp_typ); + FMDBG("%s AID = %x\n", __func__, aid); + + switch (aid) { + case ERT_AID: + radio->utf_8_flag = (radio->block[2] & 1); + radio->formatting_dir = EXTRACT_BIT(radio->block[2], + ERT_FORMAT_DIR_BIT); + if (radio->ert_carrier != app_grp_typ) { + rtc6226_q_event(radio, RTC6226_EVT_NEW_ODA); + radio->ert_carrier = app_grp_typ; + } + break; + case RT_PLUS_AID: + /*Extract 5th bit of MSB (b7b6b5b4b3b2b1b0)*/ + radio->rt_ert_flag = EXTRACT_BIT(radio->block[2], + RT_ERT_FLAG_BIT); + if (radio->rt_plus_carrier != app_grp_typ) { + rtc6226_q_event(radio, RTC6226_EVT_NEW_ODA); + radio->rt_plus_carrier = app_grp_typ; + } + break; + default: + FMDBG("%s Not handling the AID of %x\n", __func__, aid); + break; + } +} + +static void rtc6226_ev_ert(struct rtc6226_device *radio) +{ + u8 *data = NULL; + struct kfifo *data_b; + + if (radio->ert_len <= 0) + return; + + FMDBG("%s enter\n", __func__); + data = kmalloc((radio->ert_len + ERT_OFFSET), GFP_ATOMIC); + if (data != NULL) { + data[0] = radio->ert_len; + data[1] = radio->utf_8_flag; + data[2] = radio->formatting_dir; + memcpy((data + ERT_OFFSET), radio->ert_buf, radio->ert_len); + data_b = &radio->data_buf[RTC6226_FM_BUF_ERT]; + kfifo_in_locked(data_b, data, (radio->ert_len + ERT_OFFSET), + &radio->buf_lock[RTC6226_FM_BUF_ERT]); + rtc6226_q_event(radio, RTC6226_EVT_NEW_ERT); + kfree(data); + } +} + +static void rtc6226_buff_ert(struct rtc6226_device *radio) +{ + int i; + u16 info_byte = 0; + u8 byte_pair_index; + + byte_pair_index = radio->block[1] & APP_GRP_typ_MASK; + if (byte_pair_index == 0) { + radio->c_byt_pair_index = 0; + radio->ert_len = 0; + } + if (radio->c_byt_pair_index == byte_pair_index) { + for (i = 2; i <= 3; i++) { + info_byte = radio->block[i]; + FMDBG("%s info_byte = %x\n", __func__, info_byte); + FMDBG("%s ert_len = %x\n", __func__, radio->ert_len); + if (radio->ert_len > (MAX_ERT_LEN - 2)) + return; + radio->ert_buf[radio->ert_len] = radio->block[i] >> 8; + radio->ert_buf[radio->ert_len + 1] = + radio->block[i] & 0xFF; + radio->ert_len += ERT_CNT_PER_BLK; + FMDBG("%s utf_8_flag = %d\n", __func__, + radio->utf_8_flag); + if ((radio->utf_8_flag == 0) && + (info_byte == END_OF_RT)) { + radio->ert_len -= ERT_CNT_PER_BLK; + break; + } else if ((radio->utf_8_flag == 1) && + (radio->block[i] >> 8 == END_OF_RT)) { + info_byte = END_OF_RT; + radio->ert_len -= ERT_CNT_PER_BLK; + break; + } else if ((radio->utf_8_flag == 1) && + ((radio->block[i] & 0xFF) + == END_OF_RT)) { + info_byte = END_OF_RT; + radio->ert_len--; + break; + } + } + if ((byte_pair_index == MAX_ERT_SEGMENT) || + (info_byte == END_OF_RT)) { + rtc6226_ev_ert(radio); + radio->c_byt_pair_index = 0; + radio->ert_len = 0; + } + radio->c_byt_pair_index++; + } else { + radio->ert_len = 0; + radio->c_byt_pair_index = 0; + } +} + +static void rtc6226_rt_plus(struct rtc6226_device *radio) +{ + u8 tag_type1, tag_type2; + u8 *data = NULL; + int len = 0; + u16 grp_typ; + struct kfifo *data_b; + + grp_typ = radio->block[1] & APP_GRP_typ_MASK; + /* + *right most 3 bits of Lsb of block 2 + * and left most 3 bits of Msb of block 3 + */ + tag_type1 = (((grp_typ & TAG1_MSB_MASK) << TAG1_MSB_OFFSET) | + (radio->block[2] >> TAG1_LSB_OFFSET)); + /* + *right most 1 bit of lsb of 3rd block + * and left most 5 bits of Msb of 4th block + */ + tag_type2 = (((radio->block[2] & TAG2_MSB_MASK) + << TAG2_MSB_OFFSET) | + (radio->block[2] >> TAG2_LSB_OFFSET)); + + if (tag_type1 != DUMMY_CLASS) + len += RT_PLUS_LEN_1_TAG; + if (tag_type2 != DUMMY_CLASS) + len += RT_PLUS_LEN_1_TAG; + + if (len != 0) { + len += RT_PLUS_OFFSET; + data = kmalloc(len, GFP_ATOMIC); + } else { + FMDERR("%s:Len is zero\n", __func__); + return; + } + if (data != NULL) { + data[0] = len; + len = RT_ERT_FLAG_OFFSET; + data[len++] = radio->rt_ert_flag; + if (tag_type1 != DUMMY_CLASS) { + data[len++] = tag_type1; + /* + *start position of tag1 + *right most 5 bits of msb of 3rd block + *and left most bit of lsb of 3rd block + */ + data[len++] = (radio->block[2] >> TAG1_POS_LSB_OFFSET) + & TAG1_POS_MSB_MASK; + /* + *length of tag1 + *left most 6 bits of lsb of 3rd block + */ + data[len++] = (radio->block[2] >> TAG1_LEN_OFFSET) & + TAG1_LEN_MASK; + } + if (tag_type2 != DUMMY_CLASS) { + data[len++] = tag_type2; + /* + *start position of tag2 + *right most 3 bit of msb of 4th block + *and left most 3 bits of lsb of 4th block + */ + data[len++] = (radio->block[3] >> TAG2_POS_LSB_OFFSET) & + TAG2_POS_MSB_MASK; + /* + *length of tag2 + *right most 5 bits of lsb of 4th block + */ + data[len++] = radio->block[3] & TAG2_LEN_MASK; + } + data_b = &radio->data_buf[RTC6226_FM_BUF_RT_PLUS]; + kfifo_in_locked(data_b, data, len, + &radio->buf_lock[RTC6226_FM_BUF_RT_PLUS]); + rtc6226_q_event(radio, RTC6226_EVT_NEW_RT_PLUS); + kfree(data); + } else { + FMDERR("%s:memory allocation failed\n", __func__); + } +} + +void rtc6226_rds_handler(struct work_struct *worker) +{ + struct rtc6226_device *radio; + u8 rt_blks[NO_OF_RDS_BLKS]; + u8 grp_type, addr, ab_flg; + + radio = container_of(worker, struct rtc6226_device, rds_worker); + + if (!radio) { + FMDERR("%s:radio is null\n", __func__); + return; + } + + FMDBG("%s enter\n", __func__); + + rtc6226_get_rds(radio); + + if (radio->bler[0] < CORRECTED_THREE_TO_FIVE) + rtc6226_pi_check(radio, radio->block[0]); + + if (radio->bler[1] < CORRECTED_ONE_TO_TWO) { + grp_type = radio->block[1] >> OFFSET_OF_GRP_TYP; + FMDBG("%s grp_type = %d\n", __func__, grp_type); + } else { + /* invalid data case */ + return; + } + if (grp_type & 0x01) + rtc6226_pi_check(radio, radio->block[2]); + + rtc6226_pty_check(radio, (radio->block[1] >> OFFSET_OF_PTY) & PTY_MASK); + + switch (grp_type) { + case RDS_TYPE_0A: + if (radio->bler[2] <= CORRECTED_THREE_TO_FIVE) + rtc6226_update_af_list(radio); + /* fall through */ + case RDS_TYPE_0B: + addr = (radio->block[1] & PS_MASK) * NO_OF_CHARS_IN_EACH_ADD; + FMDBG("%s RDS is PS\n", __func__); + if (radio->bler[3] <= CORRECTED_THREE_TO_FIVE) { + rtc6226_update_ps(radio, addr+0, radio->block[3] >> 8); + rtc6226_update_ps(radio, addr+1, + radio->block[3] & 0xff); + } + break; + case RDS_TYPE_2A: + FMDBG("%s RDS is RT 2A group\n", __func__); + rt_blks[0] = (u8)(radio->block[2] >> 8); + rt_blks[1] = (u8)(radio->block[2] & 0xFF); + rt_blks[2] = (u8)(radio->block[3] >> 8); + rt_blks[3] = (u8)(radio->block[3] & 0xFF); + addr = (radio->block[1] & 0xf) * 4; + ab_flg = (radio->block[1] & 0x0010) >> 4; + rt_handler(radio, ab_flg, CNT_FOR_2A_GRP_RT, addr, rt_blks); + break; + case RDS_TYPE_2B: + FMDBG("%s RDS is RT 2B group\n", __func__); + rt_blks[0] = (u8)(radio->block[3] >> 8); + rt_blks[1] = (u8)(radio->block[3] & 0xFF); + rt_blks[2] = 0; + rt_blks[3] = 0; + addr = (radio->block[1] & 0xf) * 2; + ab_flg = (radio->block[1] & 0x0010) >> 4; + radio->rt_tmp0[MAX_LEN_2B_GRP_RT] = END_OF_RT; + radio->rt_tmp1[MAX_LEN_2B_GRP_RT] = END_OF_RT; + radio->rt_cnt[MAX_LEN_2B_GRP_RT] = RT_VALIDATE_LIMIT; + rt_handler(radio, ab_flg, CNT_FOR_2B_GRP_RT, addr, rt_blks); + break; + case RDS_TYPE_3A: + FMDBG("%s RDS is 3A group\n", __func__); + rtc6226_raw_rds(radio); + break; + default: + FMDERR("%s Not handling the group type %d\n", __func__, + grp_type); + break; + } + FMDBG("%s rt_plus_carrier = %x\n", __func__, radio->rt_plus_carrier); + FMDBG("%s ert_carrier = %x\n", __func__, radio->ert_carrier); + if (radio->rt_plus_carrier && (grp_type == radio->rt_plus_carrier)) + rtc6226_rt_plus(radio); + else if (radio->ert_carrier && (grp_type == radio->ert_carrier)) + rtc6226_buff_ert(radio); +} + +/* + * rtc6226_rds_on - switch on rds reception + */ +int rtc6226_rds_on(struct rtc6226_device *radio) +{ + int retval; + + FMDBG("%s enter\n", __func__); + /* sysconfig */ + radio->registers[SYSCFG] |= SYSCFG_CSR0_RDS_EN; + retval = rtc6226_set_register(radio, SYSCFG); + + if (retval < 0) + radio->registers[SYSCFG] &= ~SYSCFG_CSR0_RDS_EN; + + return retval; +} + +int rtc6226_reset_rds_data(struct rtc6226_device *radio) +{ + mutex_lock(&radio->lock); + radio->pi = 0; + /* reset PS bufferes */ + memset(radio->ps_display, 0, sizeof(radio->ps_display)); + memset(radio->ps_tmp0, 0, sizeof(radio->ps_tmp0)); + memset(radio->ps_tmp1, 0, sizeof(radio->ps_tmp1)); + memset(radio->ps_cnt, 0, sizeof(radio->ps_cnt)); + + memset(radio->rt_display, 0, sizeof(radio->rt_display)); + memset(radio->rt_tmp0, 0, sizeof(radio->rt_tmp0)); + memset(radio->rt_tmp1, 0, sizeof(radio->rt_tmp1)); + memset(radio->rt_cnt, 0, sizeof(radio->rt_cnt)); + radio->wr_index = 0; + radio->rd_index = 0; + memset(radio->buffer, 0, radio->buf_size); + mutex_unlock(&radio->lock); + + return 0; +} + +int rtc6226_set_rssi_threshold(struct rtc6226_device *radio, u16 rssi) +{ + int retval = 0; + + /*csr_rssi_low_th = RSSI_threshold/4*/ + rssi = rssi/4; + if ((rssi < MIN_RSSI) && (rssi > MAX_RSSI)) + return -EINVAL; + radio->registers[SEEKCFG1] &= ~SEEKCFG1_CSR0_RSSI_LOW_TH; + radio->registers[SEEKCFG1] |= rssi << 8; + retval = rtc6226_set_register(radio, SEEKCFG1); + radio->rssi_th = (u8)(rssi*4); + return retval; +} + +int rtc6226_power_down(struct rtc6226_device *radio) +{ + int retval = 0; + + FMDBG("%s enter\n", __func__); + + mutex_lock(&radio->lock); + /* stop radio */ + retval = rtc6226_stop(radio); + + //rtc6226_disable_irq(radio); + mutex_unlock(&radio->lock); + FMDBG("%s exit %d\n", __func__, retval); + + return retval; +} + +int rtc6226_power_up(struct rtc6226_device *radio) +{ + int retval = 0; + + mutex_lock(&radio->lock); + + FMDBG("%s enter\n", __func__); + + /* start radio */ + retval = rtc6226_start(radio); + if (retval < 0) + goto done; + FMDBG("%s : after initialization\n", __func__); + + /* mpxconfig */ + /* Disable Mute / De-emphasis / Volume 12 */ + radio->registers[MPXCFG] = 0x000c | + MPXCFG_CSR0_DIS_MUTE | + ((de << 12) & MPXCFG_CSR0_DEEM); + retval = rtc6226_set_register(radio, MPXCFG); + if (retval < 0) + goto done; + + /* enable RDS / STC interrupt */ + radio->registers[SYSCFG] |= SYSCFG_CSR0_RDSIRQEN; + radio->registers[SYSCFG] |= SYSCFG_CSR0_STDIRQEN; + /*radio->registers[SYSCFG] |= SYSCFG_CSR0_RDS_EN;*/ + retval = rtc6226_set_register(radio, SYSCFG); + if (retval < 0) + goto done; + + radio->registers[PADCFG] &= ~PADCFG_CSR0_GPIO; + radio->registers[PADCFG] |= 0x1 << 2; + retval = rtc6226_set_register(radio, PADCFG); + if (retval < 0) + goto done; + + /* I2S salve */ + radio->registers[I2SCFG] = 0x2480; + retval = rtc6226_set_register(radio, I2SCFG); + if (retval < 0) + goto done; + + /*set default rssi threshold*/ + retval = rtc6226_set_rssi_threshold(radio, DEFAULT_RSSI_TH); + if (retval < 0) + FMDERR("%s fail to set rssi threshold\n", __func__); + + /* powerconfig */ + /* Enable FM */ + radio->registers[POWERCFG] = POWERCFG_CSR0_ENABLE; + retval = rtc6226_set_register(radio, POWERCFG); + if (retval < 0) + goto done; + /*wait for radio enable to complete*/ + msleep(30); + retval = rtc6226_get_all_registers(radio); + if (retval < 0) + goto done; + + FMDBG("%s : DeviceID=0x%4.4hx ChipID=0x%4.4hx\n", __func__, + radio->registers[DEVICEID], radio->registers[CHIPID]); + FMDBG("%s : Reg2=0x%4.4hx Reg3=0x%4.4hx\n", __func__, + radio->registers[MPXCFG], radio->registers[CHANNEL]); + FMDBG("%s : Reg4=0x%4.4hx Reg5=0x%4.4hx\n", __func__, + radio->registers[SYSCFG], radio->registers[SEEKCFG1]); + FMDBG("%s : Reg6=0x%4.4hx Reg7=0x%4.4hx\n", __func__, + radio->registers[POWERCFG], radio->registers[PADCFG]); + FMDBG("%s : Reg8=0x%4.4hx Reg9=0x%4.4hx\n", __func__, + radio->registers[8], radio->registers[9]); + FMDBG("%s : regA=0x%4.4hx RegB=0x%4.4hx\n", __func__, + radio->registers[10], radio->registers[11]); + FMDBG("%s : regC=0x%4.4hx RegD=0x%4.4hx\n", __func__, + radio->registers[12], radio->registers[13]); + FMDBG("%s : regE=0x%4.4hx RegF=0x%4.4hx\n", __func__, + radio->registers[14], radio->registers[15]); + +done: + FMDBG("%s exit %d\n", __func__, retval); + mutex_unlock(&radio->lock); + return retval; +} + +/************************************************************************** + * File Operations Interface + **************************************************************************/ + +/* + * rtc6226_fops_read - read event data + */ +static ssize_t rtc6226_fops_read(struct file *file, char __user *buffer, + size_t count, loff_t *ppos) +{ + struct rtc6226_device *radio = video_get_drvdata(video_devdata(file)); + enum rtc6226_buf_t buf_type = -1; + u8 buf_fifo[STD_BUF_SIZE] = {0}; + struct kfifo *data_fifo = NULL; + int len = 0, retval = -1; + u32 bytesused = 0; + + if ((radio == NULL) || (buffer == NULL)) { + FMDERR("%s radio/buffer is NULL\n", __func__); + return -ENXIO; + } + + buf_type = count; + len = STD_BUF_SIZE; + FMDBG("%s: requesting buffer %d\n", __func__, buf_type); + + if ((buf_type < RTC6226_FM_BUF_MAX) && (buf_type >= 0)) { + data_fifo = &radio->data_buf[buf_type]; + if (buf_type == RTC6226_FM_BUF_EVENTS) { + if (wait_event_interruptible(radio->event_queue, + kfifo_len(data_fifo)) < 0) { + return -EINTR; + } + } + } else { + FMDERR("%s invalid buffer type\n", __func__); + return -EINVAL; + } + if (len <= STD_BUF_SIZE) { + bytesused = kfifo_out_locked(data_fifo, &buf_fifo[0], + len, &radio->buf_lock[buf_type]); + } else { + FMDERR("%s kfifo_out_locked can not use len more than 128\n", + __func__); + return -EINVAL; + } + retval = copy_to_user(buffer, &buf_fifo[0], bytesused); + if (retval > 0) { + FMDERR("%s Failed to copy %d bytes data\n", __func__, retval); + return -EAGAIN; + } + retval = bytesused; + return retval; +} + +/* + * rtc6226_fops_poll - poll RDS data + */ +static unsigned int rtc6226_fops_poll(struct file *file, + struct poll_table_struct *pts) +{ + struct rtc6226_device *radio = video_drvdata(file); + int retval = 0; + + /* switch on rds reception */ + mutex_lock(&radio->lock); + if ((radio->registers[SYSCFG] & SYSCFG_CSR0_RDS_EN) == 0) + rtc6226_rds_on(radio); + mutex_unlock(&radio->lock); + + poll_wait(file, &radio->read_queue, pts); + + if (radio->rd_index != radio->wr_index) + retval = POLLIN | POLLRDNORM; + + return retval; +} + +/* static */ +int rtc6226_vidioc_g_ctrl(struct file *file, void *priv, + struct v4l2_control *ctrl) +{ + struct rtc6226_device *radio = video_drvdata(file); + int retval = 0; + + FMDBG("%s enter, ctrl->id: %x, value:%d\n", __func__, + ctrl->id, ctrl->value); + + mutex_lock(&radio->lock); + + switch (ctrl->id) { + case V4L2_CID_PRIVATE_CSR0_ENABLE: + FMDBG("V4L2_CID_PRIVATE_CSR0_ENABLE val=%d\n", ctrl->value); + break; + case V4L2_CID_PRIVATE_CSR0_DISABLE: + FMDBG("V4L2_CID_PRIVATE_CSR0_DISABLE val=%d\n", ctrl->value); + break; + case V4L2_CID_PRIVATE_CSR0_VOLUME: + case V4L2_CID_AUDIO_VOLUME: + ctrl->value = radio->registers[MPXCFG] & MPXCFG_CSR0_VOLUME; + break; + case V4L2_CID_PRIVATE_CSR0_DIS_MUTE: + case V4L2_CID_AUDIO_MUTE: + ctrl->value = ((radio->registers[MPXCFG] & + MPXCFG_CSR0_DIS_MUTE) == 0) ? 1 : 0; + break; + case V4L2_CID_PRIVATE_CSR0_DIS_SMUTE: + ctrl->value = ((radio->registers[MPXCFG] & + MPXCFG_CSR0_DIS_SMUTE) == 0) ? 1 : 0; + break; + case V4L2_CID_PRIVATE_CSR0_BAND: + ctrl->value = radio->band; + break; + case V4L2_CID_PRIVATE_CSR0_SEEKRSSITH: + ctrl->value = radio->registers[SEEKCFG1] & + SEEKCFG1_CSR0_RSSI_LOW_TH; + break; + case V4L2_CID_PRIVATE_RSSI: + rtc6226_get_all_registers(radio); + ctrl->value = radio->registers[RSSI] & RSSI_RSSI; + FMDBG("Get V4L2_CONTROL V4L2_CID_PRIVATE_RSSI: RSSI = %d\n", + radio->registers[RSSI] & RSSI_RSSI); + break; + case V4L2_CID_PRIVATE_DEVICEID: + ctrl->value = radio->registers[DEVICEID] & DEVICE_ID; + FMDBG("Get V4L2_CID_PRIVATE_DEVICEID: DEVICEID=0x%4.4hx\n", + radio->registers[DEVICEID]); + break; + case V4L2_CID_PRIVATE_RTC6226_RDSGROUP_PROC: + break; + case V4L2_CID_PRIVATE_RTC6226_SIGNAL_TH: + /* intentional fallthrough */ + case V4L2_CID_PRIVATE_RTC6226_RSSI_TH: + ctrl->value = radio->rssi_th; + break; + default: + FMDBG("%s in default id:%d\n", __func__, ctrl->id); + retval = -EINVAL; + } + + mutex_unlock(&radio->lock); + return retval; +} + +static int rtc6226_vidioc_dqbuf(struct file *file, void *priv, + struct v4l2_buffer *buffer) +{ + + struct rtc6226_device *radio = video_get_drvdata(video_devdata(file)); + enum rtc6226_buf_t buf_type = -1; + u8 buf_fifo[STD_BUF_SIZE] = {0}; + struct kfifo *data_fifo = NULL; + u8 *buf = NULL; + int len = 0, retval = -1; + + if ((radio == NULL) || (buffer == NULL)) { + FMDERR("%s radio/buffer is NULL\n", __func__); + return -ENXIO; + } + + buf_type = buffer->index; + buf = (u8 *)buffer->m.userptr; + len = buffer->length; + FMDBG("%s: requesting buffer %d\n", __func__, buf_type); + + if ((buf_type < RTC6226_FM_BUF_MAX) && (buf_type >= 0)) { + data_fifo = &radio->data_buf[buf_type]; + if (buf_type == RTC6226_FM_BUF_EVENTS) { + if (wait_event_interruptible(radio->event_queue, + kfifo_len(data_fifo)) < 0) { + return -EINTR; + } + } + } else { + FMDERR("%s invalid buffer type\n", __func__); + return -EINVAL; + } + if (len <= STD_BUF_SIZE) { + buffer->bytesused = kfifo_out_locked(data_fifo, &buf_fifo[0], + len, &radio->buf_lock[buf_type]); + } else { + FMDERR("%s kfifo_out_locked can not use len more than 128\n", + __func__); + return -EINVAL; + } + retval = copy_to_user(buf, &buf_fifo[0], buffer->bytesused); + if (retval > 0) { + FMDERR("%s Failed to copy %d bytes data\n", __func__, retval); + return -EAGAIN; + } + + return retval; +} + +static bool check_mode(struct rtc6226_device *radio) +{ + bool retval = true; + + if (radio->mode == FM_OFF || radio->mode == FM_RECV) + retval = false; + + return retval; +} + + + +static int rtc6226_disable(struct rtc6226_device *radio) +{ + int retval = 0; + + /* disable RDS/STC interrupt */ + radio->registers[SYSCFG] &= ~SYSCFG_CSR0_RDS_EN; + radio->registers[SYSCFG] &= ~SYSCFG_CSR0_RDSIRQEN; + radio->registers[SYSCFG] &= ~SYSCFG_CSR0_STDIRQEN; + retval = rtc6226_set_register(radio, SYSCFG); + if (retval < 0) { + FMDERR("%s fail to disable RDS/SCT interrupt\n", __func__); + goto done; + } + retval = rtc6226_power_down(radio); + if (retval < 0) { + FMDERR("%s fail to turn off fmradio\n", __func__); + goto done; + } + + if (radio->mode == FM_TURNING_OFF || radio->mode == FM_RECV) { + FMDBG("%s: posting RTC6226_EVT_RADIO_DISABLED event\n", + __func__); + rtc6226_q_event(radio, RTC6226_EVT_RADIO_DISABLED); + radio->mode = FM_OFF; + } + /* flush_workqueue(radio->wqueue); */ + +done: + return retval; +} + +static int rtc6226_enable(struct rtc6226_device *radio) +{ + int retval = 0; + + rtc6226_get_register(radio, POWERCFG); + retval = rtc6226_power_up(radio); + if (retval < 0) + goto done; + + if ((radio->registers[SYSCFG] & SYSCFG_CSR0_STDIRQEN) == 0) { + radio->registers[SYSCFG] |= SYSCFG_CSR0_RDSIRQEN; + radio->registers[SYSCFG] |= SYSCFG_CSR0_STDIRQEN; + retval = rtc6226_set_register(radio, SYSCFG); + if (retval < 0) { + FMDERR("%s set register fail\n", __func__); + goto done; + } else { + rtc6226_q_event(radio, RTC6226_EVT_RADIO_READY); + radio->mode = FM_RECV; + } + } else { + rtc6226_q_event(radio, RTC6226_EVT_RADIO_READY); + radio->mode = FM_RECV; + } +done: + return retval; + +} + +bool rtc6226_is_valid_srch_mode(int srch_mode) +{ + if ((srch_mode >= RTC6226_MIN_SRCH_MODE) && + (srch_mode <= RTC6226_MAX_SRCH_MODE)) + return true; + else + return false; +} + +/* + * rtc6226_vidioc_s_ctrl - set the value of a control + */ +int rtc6226_vidioc_s_ctrl(struct file *file, void *priv, + struct v4l2_control *ctrl) +{ + struct rtc6226_device *radio = video_drvdata(file); + int retval = 0; + + FMDBG("%s enter, ctrl->id: %x, value:%d\n", __func__, + ctrl->id, ctrl->value); + + switch (ctrl->id) { + case V4L2_CID_PRIVATE_RTC6226_STATE: + if (ctrl->value == FM_RECV) { + if (check_mode(radio)) { + FMDERR("%s:fm is not in proper state\n", + __func__); + retval = -EINVAL; + goto end; + } + radio->mode = FM_RECV_TURNING_ON; + retval = rtc6226_enable(radio); + if (retval < 0) { + FMDERR( + "%s Error while enabling RECV FM %d\n", + __func__, retval); + radio->mode = FM_OFF; + goto end; + } + } else if (ctrl->value == FM_OFF) { + radio->mode = FM_TURNING_OFF; + retval = rtc6226_disable(radio); + if (retval < 0) { + FMDERR("Err on disable recv FM %d\n", retval); + radio->mode = FM_RECV; + goto end; + } + } + break; + case V4L2_CID_PRIVATE_RTC6226_SET_AUDIO_PATH: + case V4L2_CID_PRIVATE_RTC6226_SRCH_ALGORITHM: + case V4L2_CID_PRIVATE_RTC6226_REGION: + retval = 0; + break; + case V4L2_CID_PRIVATE_RTC6226_EMPHASIS: + if (ctrl->value == 1) + radio->registers[MPXCFG] |= MPXCFG_CSR0_DEEM; + else + radio->registers[MPXCFG] &= ~MPXCFG_CSR0_DEEM; + retval = rtc6226_set_register(radio, MPXCFG); + break; + case V4L2_CID_PRIVATE_RTC6226_RDS_STD: + /* enable RDS / STC interrupt */ + radio->registers[SYSCFG] |= SYSCFG_CSR0_RDSIRQEN; + radio->registers[SYSCFG] |= SYSCFG_CSR0_STDIRQEN; + /*radio->registers[SYSCFG] |= SYSCFG_CSR0_RDS_EN;*/ + retval = rtc6226_set_register(radio, SYSCFG); + break; + case V4L2_CID_PRIVATE_RTC6226_SRCHON: + rtc6226_search(radio, (bool)ctrl->value); + break; + case V4L2_CID_PRIVATE_RTC6226_LP_MODE: + if (ctrl->value) { + /* disable RDS interrupts */ + radio->registers[SYSCFG] &= ~SYSCFG_CSR0_RDSIRQEN; + retval = rtc6226_set_register(radio, SYSCFG); + } else { + /* enable RDS interrupts */ + radio->registers[SYSCFG] |= SYSCFG_CSR0_RDSIRQEN; + retval = rtc6226_set_register(radio, SYSCFG); + } + break; + case V4L2_CID_PRIVATE_RTC6226_ANTENNA: + case V4L2_CID_PRIVATE_RTC6226_AF_JUMP: + case V4L2_CID_PRIVATE_RTC6226_SRCH_CNT: + case V4L2_CID_PRIVATE_RTC6226_RXREPEATCOUNT: + case V4L2_CID_PRIVATE_RTC6226_SINR_THRESHOLD: + retval = 0; + break; + case V4L2_CID_PRIVATE_RTC6226_SIGNAL_TH: + retval = rtc6226_set_rssi_threshold(radio, ctrl->value); + if (retval < 0) + FMDERR("%s fail to set rssi threshold\n", __func__); + rtc6226_get_register(radio, SEEKCFG1); + FMDBG("FMRICHWAVE RSSI_TH: Dec = %d , Hexa = %x\n", + radio->registers[SEEKCFG1] & 0xFF, + radio->registers[SEEKCFG1] & 0xFF); + break; + /* case V4L2_CID_PRIVATE_RTC6226_OFS_THRESHOLD: */ + case V4L2_CID_PRIVATE_RTC6226_SPUR_FREQ_RMSSI: + break; + case V4L2_CID_PRIVATE_RTC6226_RDSD_BUF: + case V4L2_CID_PRIVATE_RTC6226_RDSGROUP_MASK: + case V4L2_CID_PRIVATE_RTC6226_RDSGROUP_PROC: + if ((radio->registers[SYSCFG] & SYSCFG_CSR0_RDS_EN) == 0) + rtc6226_rds_on(radio); + retval = 0; + break; + case V4L2_CID_PRIVATE_RTC6226_SRCHMODE: + if (rtc6226_is_valid_srch_mode(ctrl->value)) { + radio->g_search_mode = ctrl->value; + } else { + FMDERR("%s:srch mode is not valid\n", __func__); + retval = -EINVAL; + goto end; + } + break; + case V4L2_CID_PRIVATE_RTC6226_PSALL: + break; + case V4L2_CID_PRIVATE_RTC6226_SCANDWELL: + if ((ctrl->value >= MIN_DWELL_TIME) && + (ctrl->value <= MAX_DWELL_TIME)) { + radio->dwell_time_sec = ctrl->value; + } else { + FMDERR( + "%s:scandwell period is not valid\n", __func__); + retval = -EINVAL; + } + break; + case V4L2_CID_PRIVATE_CSR0_ENABLE: + FMDBG("V4L2_CID_PRIVATE_CSR0_ENABLE val=%d\n", + ctrl->value); + retval = rtc6226_power_up(radio); + /* must keep below line */ + ctrl->value = 0; + break; + case V4L2_CID_PRIVATE_CSR0_DISABLE: + FMDBG("V4L2_CID_PRIVATE_CSR0_DISABLE val=%d\n", + ctrl->value); + retval = rtc6226_power_down(radio); + /* must keep below line */ + ctrl->value = 0; + break; + case V4L2_CID_PRIVATE_DEVICEID: + FMDBG("V4L2_CID_PRIVATE_DEVICEID val=%d\n", ctrl->value); + break; + case V4L2_CID_PRIVATE_CSR0_VOLUME: + case V4L2_CID_AUDIO_VOLUME: + FMDBG("MPXCFG=0x%4.4hx POWERCFG=0x%4.4hx\n", + radio->registers[MPXCFG], radio->registers[POWERCFG]); + radio->registers[MPXCFG] &= ~MPXCFG_CSR0_VOLUME; + radio->registers[MPXCFG] |= + (ctrl->value > 15) ? 8 : ctrl->value; + FMDBG("MPXCFG=0x%4.4hx POWERCFG=0x%4.4hx\n", + radio->registers[MPXCFG], radio->registers[POWERCFG]); + retval = rtc6226_set_register(radio, MPXCFG); + break; + case V4L2_CID_PRIVATE_CSR0_DIS_MUTE: + case V4L2_CID_AUDIO_MUTE: + if (ctrl->value == 1) + radio->registers[MPXCFG] &= ~MPXCFG_CSR0_DIS_MUTE; + else + radio->registers[MPXCFG] |= MPXCFG_CSR0_DIS_MUTE; + retval = rtc6226_set_register(radio, MPXCFG); + break; + case V4L2_CID_PRIVATE_RTC6226_SOFT_MUTE: + FMDBG("V4L2_CID_PRIVATE_RTC6226_SOFT_MUTE\n"); + if (ctrl->value == 1) + radio->registers[MPXCFG] &= ~MPXCFG_CSR0_DIS_SMUTE; + else + radio->registers[MPXCFG] |= MPXCFG_CSR0_DIS_SMUTE; + retval = rtc6226_set_register(radio, MPXCFG); + break; + case V4L2_CID_PRIVATE_CSR0_DEEM: + FMDBG("V4L2_CID_PRIVATE_CSR0_DEEM\n"); + if (ctrl->value == 1) + radio->registers[MPXCFG] |= MPXCFG_CSR0_DEEM; + else + radio->registers[MPXCFG] &= ~MPXCFG_CSR0_DEEM; + retval = rtc6226_set_register(radio, MPXCFG); + break; + case V4L2_CID_PRIVATE_CSR0_BLNDADJUST: + FMDBG("V4L2_CID_PRIVATE_CSR0_BLNDADJUST val=%d\n", + ctrl->value); + break; + case V4L2_CID_PRIVATE_CSR0_BAND: + FMDBG( + "V4L2_CID_PRIVATE_CSR0_BAND : FREQ_TOP=%d FREQ_BOT=%d %d\n", + radio->registers[RADIOSEEKCFG1], + radio->registers[RADIOSEEKCFG2], ctrl->value); + switch (ctrl->value) { + case FMBAND_87_108_MHZ: + radio->registers[RADIOSEEKCFG1] = 10800; + radio->registers[RADIOSEEKCFG2] = 8750; + break; + case FMBAND_76_108_MHZ: + radio->registers[RADIOSEEKCFG1] = 10800; + radio->registers[RADIOSEEKCFG2] = 7600; + break; + case FMBAND_76_91_MHZ: + radio->registers[RADIOSEEKCFG1] = 9100; + radio->registers[RADIOSEEKCFG2] = 7600; + break; + case FMBAND_64_76_MHZ: + radio->registers[RADIOSEEKCFG1] = 7600; + radio->registers[RADIOSEEKCFG2] = 6400; + break; + default: + retval = -EINVAL; + break; + } + FMDBG( + "V4L2_CID_PRIVATE_CSR0_BAND : FREQ_TOP=%d FREQ_BOT=%d %d\n", + radio->registers[RADIOSEEKCFG1], + radio->registers[RADIOSEEKCFG2], ctrl->value); + radio->band = ctrl->value; + retval = rtc6226_set_register(radio, RADIOSEEKCFG1); + retval = rtc6226_set_register(radio, RADIOSEEKCFG2); + break; + case V4L2_CID_PRIVATE_RTC6226_SPACING: + case V4L2_CID_PRIVATE_CSR0_CHSPACE: + FMDBG("V4L2_CID_PRIVATE_CSR0_CHSPACE : FM_SPACE=%d %d\n", + radio->registers[RADIOCFG], ctrl->value); + radio->space = ctrl->value; + radio->registers[RADIOCFG] &= ~CHANNEL_CSR0_CHSPACE; + + switch (ctrl->value) { + case FMSPACE_200_KHZ: + radio->registers[RADIOCFG] |= 0x1400; + break; + case FMSPACE_100_KHZ: + radio->registers[RADIOCFG] |= 0x0A00; + break; + case FMSPACE_50_KHZ: + radio->registers[RADIOCFG] |= 0x0500; + break; + default: + retval = -EINVAL; + break; + } + radio->space = ctrl->value; + FMDBG("V4L2_CID_PRIVATE_CSR0_CHSPACE : FM_SPACE=%d %d\n", + radio->registers[RADIOCFG], ctrl->value); + retval = rtc6226_set_register(radio, RADIOCFG); + break; + case V4L2_CID_PRIVATE_CSR0_DIS_AGC: + FMDBG("V4L2_CID_PRIVATE_CSR0_DIS_AGC val=%d\n", + ctrl->value); + break; + case V4L2_CID_PRIVATE_RTC6226_RDSON: + FMDBG( + "V4L2_CSR0_RDS_EN:CHANNEL=0x%4.4hx SYSCFG=0x%4.4hx\n", + radio->registers[CHANNEL], + radio->registers[SYSCFG]); + rtc6226_reset_rds_data(radio); + radio->registers[SYSCFG] &= ~SYSCFG_CSR0_RDS_EN; + radio->registers[SYSCFG] &= ~SYSCFG_CSR0_RDSIRQEN; + radio->registers[SYSCFG] |= (ctrl->value << 15); + radio->registers[SYSCFG] |= (ctrl->value << 12); + FMDBG + ("V4L2_CSR0_RDS_EN : CHANNEL=0x%4.4hx SYSCFG=0x%4.4hx\n", + radio->registers[CHANNEL], + radio->registers[SYSCFG]); + retval = rtc6226_set_register(radio, SYSCFG); + break; + case V4L2_CID_PRIVATE_SEEK_CANCEL: + rtc6226_search(radio, (bool)ctrl->value); + break; + case V4L2_CID_PRIVATE_CSR0_SEEKRSSITH: + radio->registers[SEEKCFG1] &= ~SEEKCFG1_CSR0_RSSI_LOW_TH; + radio->registers[SEEKCFG1] |= ctrl->value; + retval = rtc6226_set_register(radio, SEEKCFG1); + break; + default: + FMDBG("%s id: %x in default\n", __func__, ctrl->id); + retval = -EINVAL; + break; + } + +end: + FMDBG("%s exit id: %x , ret: %d\n", __func__, ctrl->id, retval); + + return retval; +} + +/* + * rtc6226_vidioc_g_audio - get audio attributes + */ +static int rtc6226_vidioc_g_audio(struct file *file, void *priv, + struct v4l2_audio *audio) +{ + /* driver constants */ + audio->index = 0; + strlcpy(audio->name, "Radio", sizeof(audio->name)); + audio->capability = V4L2_AUDCAP_STEREO; + audio->mode = 0; + + return 0; +} + + +/* + * rtc6226_vidioc_g_tuner - get tuner attributes + */ +static int rtc6226_vidioc_g_tuner(struct file *file, void *priv, + struct v4l2_tuner *tuner) +{ + struct rtc6226_device *radio = video_drvdata(file); + int retval = 0; + + FMDBG("%s enter\n", __func__); + + if (tuner->index != 0) { + retval = -EINVAL; + goto done; + } + + retval = rtc6226_get_register(radio, RSSI); + if (retval < 0) + goto done; + + /* driver constants */ + strlcpy(tuner->name, "FM", sizeof(tuner->name)); + tuner->type = V4L2_TUNER_RADIO; + tuner->capability = V4L2_TUNER_CAP_LOW | V4L2_TUNER_CAP_STEREO | + V4L2_TUNER_CAP_RDS | V4L2_TUNER_CAP_RDS_BLOCK_IO; + + tuner->rangehigh = (radio->registers[RADIOSEEKCFG1] & + CHANNEL_CSR0_FREQ_TOP) * TUNE_STEP_SIZE * TUNE_PARAM; + tuner->rangelow = (radio->registers[RADIOSEEKCFG2] & + CHANNEL_CSR0_FREQ_BOT) * TUNE_STEP_SIZE * TUNE_PARAM; + + FMDBG("%s low:%d high:%d\n", __func__, + tuner->rangelow, tuner->rangehigh); + /* stereo indicator == stereo (instead of mono) */ + if ((radio->registers[STATUS] & STATUS_SI) == 0) + tuner->rxsubchans = V4L2_TUNER_SUB_MONO; + else + tuner->rxsubchans = V4L2_TUNER_SUB_MONO | V4L2_TUNER_SUB_STEREO; + /* If there is a reliable method of detecting an RDS channel, + * then this code should check for that before setting this + * RDS subchannel. + */ + tuner->rxsubchans |= V4L2_TUNER_SUB_RDS; + + /* mono/stereo selector */ + if ((radio->registers[MPXCFG] & MPXCFG_CSR0_MONO) == 0) { + tuner->audmode = V4L2_TUNER_MODE_STEREO; + rtc6226_q_event(radio, RTC6226_EVT_STEREO); + } else { + tuner->audmode = V4L2_TUNER_MODE_MONO; + rtc6226_q_event(radio, RTC6226_EVT_MONO); + } + + /* min is worst, max is best; rssi: 0..0xff */ + tuner->signal = (radio->registers[RSSI] & RSSI_RSSI); + +done: + FMDBG("%s exit %d\n", __func__, retval); + + return retval; +} + + +/* + * rtc6226_vidioc_s_tuner - set tuner attributes + */ +static int rtc6226_vidioc_s_tuner(struct file *file, void *priv, + const struct v4l2_tuner *tuner) +{ + struct rtc6226_device *radio = video_drvdata(file); + int retval = 0; + u16 bottom_freq; + u16 top_freq; + + FMDBG("%s entry\n", __func__); + + if (tuner->index != 0) { + FMDBG("%s index :%d\n", __func__, tuner->index); + goto done; + } + + /* mono/stereo selector */ + switch (tuner->audmode) { + case V4L2_TUNER_MODE_MONO: + radio->registers[MPXCFG] |= MPXCFG_CSR0_MONO; /* force mono */ + break; + case V4L2_TUNER_MODE_STEREO: + radio->registers[MPXCFG] &= ~MPXCFG_CSR0_MONO; /* try stereo */ + break; + default: + FMDBG("%s audmode is not set\n", __func__); + } + + retval = rtc6226_set_register(radio, MPXCFG); + + /* unit is 10kHz */ + top_freq = (u16)((tuner->rangehigh / TUNE_PARAM) / TUNE_STEP_SIZE); + bottom_freq = (u16)((tuner->rangelow / TUNE_PARAM) / TUNE_STEP_SIZE); + + FMDBG("%s low:%d high:%d\n", __func__, + bottom_freq, top_freq); + + radio->registers[RADIOSEEKCFG1] = top_freq; + radio->registers[RADIOSEEKCFG2] = bottom_freq; + + retval = rtc6226_set_register(radio, RADIOSEEKCFG1); + if (retval < 0) + FMDERR("In %s, error %d setting higher limit freq\n", + __func__, retval); + else + radio->recv_conf.band_high_limit = top_freq; + + retval = rtc6226_set_register(radio, RADIOSEEKCFG2); + if (retval < 0) + FMDERR("In %s, error %d setting lower limit freq\n", + __func__, retval); + else + radio->recv_conf.band_low_limit = bottom_freq; +done: + FMDBG("%s exit %d\n", __func__, retval); + return retval; +} + + +/* + * rtc6226_vidioc_g_frequency - get tuner or modulator radio frequency + */ +static int rtc6226_vidioc_g_frequency(struct file *file, void *priv, + struct v4l2_frequency *freq) +{ + struct rtc6226_device *radio = video_drvdata(file); + int retval = 0; + unsigned int frq; + + FMDBG("%s enter freq %d\n", __func__, freq->frequency); + + freq->type = V4L2_TUNER_RADIO; + retval = rtc6226_get_freq(radio, &frq); + freq->frequency = frq * TUNE_PARAM; + radio->tuned_freq_khz = frq * TUNE_STEP_SIZE; + FMDBG(" %s *freq=%d, ret %d\n", __func__, freq->frequency, retval); + + if (retval < 0) + FMDERR(" %s get frequency failed with %d\n", __func__, retval); + + return retval; +} + + +/* + * rtc6226_vidioc_s_frequency - set tuner or modulator radio frequency + */ +static int rtc6226_vidioc_s_frequency(struct file *file, void *priv, + const struct v4l2_frequency *freq) +{ + struct rtc6226_device *radio = video_drvdata(file); + int retval = 0; + u32 f = 0; + + FMDBG("%s enter freq = %d\n", __func__, freq->frequency); + if (unlikely(freq == NULL)) { + FMDERR("%s:freq is null\n", __func__); + return -EINVAL; + } + if (freq->type != V4L2_TUNER_RADIO) + return -EINVAL; + f = (freq->frequency)/TUNE_PARAM; + + radio->seek_tune_status = TUNE_PENDING; + retval = rtc6226_set_freq(radio, f); + if (retval < 0) + FMDERR("%s set frequency failed with %d\n", __func__, retval); + else + radio->tuned_freq_khz = f; + + return retval; +} + + +/* + * rtc6226_vidioc_s_hw_freq_seek - set hardware frequency seek + */ +static int rtc6226_vidioc_s_hw_freq_seek(struct file *file, void *priv, + const struct v4l2_hw_freq_seek *seek) +{ + struct rtc6226_device *radio = video_drvdata(file); + int retval = 0; + + FMDBG("%s enter\n", __func__); + + if (file->f_flags & O_NONBLOCK) + return -EWOULDBLOCK; + + radio->is_search_cancelled = false; + + /* Disable the rds before seek */ + radio->registers[SYSCFG] &= ~SYSCFG_CSR0_RDS_EN; + retval = rtc6226_set_register(radio, SYSCFG); + if (retval < 0) { + FMDERR("%s fail to disable RDS\n", __func__); + return retval; + } + + if (radio->g_search_mode == SEEK) { + /* seek */ + FMDBG("%s starting seek\n", __func__); + radio->seek_tune_status = SEEK_PENDING; + retval = rtc6226_set_seek(radio, seek->seek_upward, + WRAP_ENABLE); + } else if ((radio->g_search_mode == SCAN) || + (radio->g_search_mode == SCAN_FOR_STRONG)) { + /* scan */ + if (radio->g_search_mode == SCAN_FOR_STRONG) { + FMDBG("%s starting search list\n", __func__); + memset(&radio->srch_list, 0, + sizeof(struct rtc6226_srch_list_compl)); + } else { + FMDBG("%s starting scan\n", __func__); + } + rtc6226_search(radio, START_SCAN); + } else { + retval = -EINVAL; + FMDERR("In %s, invalid search mode %d\n", + __func__, radio->g_search_mode); + } + FMDBG("%s exit %d\n", __func__, retval); + return retval; +} + +static const struct v4l2_file_operations rtc6226_fops = { + .owner = THIS_MODULE, + .unlocked_ioctl = video_ioctl2, +#ifdef CONFIG_COMPAT + .compat_ioctl32 = v4l2_compat_ioctl32, +#endif + .read = rtc6226_fops_read, + .poll = rtc6226_fops_poll, + .open = rtc6226_fops_open, + .release = rtc6226_fops_release, +}; + +/* + * rtc6226_ioctl_ops - video device ioctl operations + */ +/* static */ +const struct v4l2_ioctl_ops rtc6226_ioctl_ops = { + .vidioc_querycap = rtc6226_vidioc_querycap, + .vidioc_g_audio = rtc6226_vidioc_g_audio, + .vidioc_g_tuner = rtc6226_vidioc_g_tuner, + .vidioc_s_tuner = rtc6226_vidioc_s_tuner, + .vidioc_g_ctrl = rtc6226_vidioc_g_ctrl, + .vidioc_s_ctrl = rtc6226_vidioc_s_ctrl, + .vidioc_g_frequency = rtc6226_vidioc_g_frequency, + .vidioc_s_frequency = rtc6226_vidioc_s_frequency, + .vidioc_s_hw_freq_seek = rtc6226_vidioc_s_hw_freq_seek, + .vidioc_dqbuf = rtc6226_vidioc_dqbuf, +}; + +/* + * rtc6226_viddev_template - video device interface + */ +struct video_device rtc6226_viddev_template = { + .fops = &rtc6226_fops, + .name = DRIVER_NAME, + .release = video_device_release_empty, + .ioctl_ops = &rtc6226_ioctl_ops, +}; + +/************************************************************************** + * Module Interface + **************************************************************************/ + +/* + * rtc6226_i2c_init - module init + */ +static __init int rtc6226_init(void) +{ + FMDBG(DRIVER_DESC ", Version " DRIVER_VERSION "\n"); + return rtc6226_i2c_init(); +} + +/* + * rtc6226_i2c_exit - module exit + */ +static void __exit rtc6226_exit(void) +{ + i2c_del_driver(&rtc6226_i2c_driver); +} + +module_init(rtc6226_init); +module_exit(rtc6226_exit); diff --git a/rtc6226/radio-rtc6226-i2c.c b/rtc6226/radio-rtc6226-i2c.c new file mode 100644 index 0000000000..0b5d0c72b7 --- /dev/null +++ b/rtc6226/radio-rtc6226-i2c.c @@ -0,0 +1,1010 @@ +/* drivers/media/radio/rtc6226/radio-rtc6226-i2c.c + * + * Driver for Richwave RTC6226 FM Tuner + * + * Copyright (c) 2009 Samsung Electronics Co.Ltd + * Author: Joonyoung Shim + * Copyright (c) 2009 Tobias Lorenz + * Copyright (c) 2012 Hans de Goede + * Copyright (c) 2018 LG Electronics, Inc. + * Copyright (c) 2018 Richwave Technology Co.Ltd + * Copyright (c) 2021 Qualcomm Innovation Center, Inc. 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 as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * 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. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +/* kernel includes */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "radio-rtc6226.h" +#include + +static const struct of_device_id rtc6226_i2c_dt_ids[] = { + {.compatible = "rtc6226"}, + {} +}; + +/* I2C Device ID List */ +static const struct i2c_device_id rtc6226_i2c_id[] = { + /* Generic Entry */ + { "rtc6226", 0 }, + /* Terminating entry */ + { } +}; +MODULE_DEVICE_TABLE(i2c, rtc6226_i2c_id); + + +/************************************************************************** + * Module Parameters + **************************************************************************/ + +/* Radio Nr */ +static int radio_nr = -1; +MODULE_PARM_DESC(radio_nr, "Radio Nr"); + +/* RDS buffer blocks */ +static unsigned int rds_buf = 100; +MODULE_PARM_DESC(rds_buf, "RDS buffer entries: *100*"); + +enum rtc6226_ctrl_id { + RTC6226_ID_CSR0_ENABLE, + RTC6226_ID_CSR0_DISABLE, + RTC6226_ID_DEVICEID, + RTC6226_ID_CSR0_DIS_SMUTE, + RTC6226_ID_CSR0_DIS_MUTE, + RTC6226_ID_CSR0_DEEM, + RTC6226_ID_CSR0_BLNDADJUST, + RTC6226_ID_CSR0_VOLUME, + RTC6226_ID_CSR0_BAND, + RTC6226_ID_CSR0_CHSPACE, + RTC6226_ID_CSR0_DIS_AGC, + RTC6226_ID_CSR0_RDS_EN, + RTC6226_ID_SEEK_CANCEL, + RTC6226_ID_CSR0_SEEKRSSITH, + RTC6226_ID_CSR0_OFSTH, + RTC6226_ID_CSR0_QLTTH, + RTC6226_ID_RSSI, + RTC6226_ID_RDS_RDY, + RTC6226_ID_STD, + RTC6226_ID_SF, + RTC6226_ID_RDS_SYNC, + RTC6226_ID_SI, +}; + + +/************************************************************************** + * I2C Definitions + **************************************************************************/ +/* Write starts with the upper byte of register 0x02 */ +#define WRITE_REG_NUM 3 +#define WRITE_INDEX(i) ((i + 0x02)%16) + +/* Read starts with the upper byte of register 0x0a */ +#define READ_REG_NUM 2 +#define READ_INDEX(i) ((i + RADIO_REGISTER_NUM - 0x0a) % READ_REG_NUM) + +/*static*/ +struct tasklet_struct my_tasklet; +/* + * rtc6226_get_register - read register + */ +int rtc6226_get_register(struct rtc6226_device *radio, int regnr) +{ + u8 reg[1]; + u8 buf[READ_REG_NUM]; + struct i2c_msg msgs[2] = { + { radio->client->addr, 0, 1, reg }, + { radio->client->addr, I2C_M_RD, sizeof(buf), buf }, + }; + + reg[0] = (u8)(regnr); + if (i2c_transfer(radio->client->adapter, msgs, 2) != 2) + return -EIO; + + radio->registers[regnr] = + (u16)(((buf[0] << 8) & 0xff00) | buf[1]); + + return 0; +} + +/* + * rtc6226_set_register - write register + */ +int rtc6226_set_register(struct rtc6226_device *radio, int regnr) +{ + u8 buf[WRITE_REG_NUM]; + struct i2c_msg msgs[1] = { + { radio->client->addr, 0, sizeof(u8) * WRITE_REG_NUM, + (void *)buf }, + }; + + buf[0] = (u8)(regnr); + buf[1] = (u8)((radio->registers[(u8)(regnr) & 0xFF] >> 8) & 0xFF); + buf[2] = (u8)(radio->registers[(u8)(regnr) & 0xFF] & 0xFF); + + if (i2c_transfer(radio->client->adapter, msgs, 1) != 1) + return -EIO; + + return 0; +} + +/* + * rtc6226_set_register - write register + */ +int rtc6226_set_serial_registers(struct rtc6226_device *radio, + u16 *data, int regnr) +{ + u8 buf[WRITE_REG_NUM]; + struct i2c_msg msgs[1] = { + { radio->client->addr, 0, sizeof(u8) * WRITE_REG_NUM, + (void *)buf }, + }; + + buf[0] = (u8)(regnr); + buf[1] = (u8)((data[0] >> 8) & 0xFF); + buf[2] = (u8)(data[0] & 0xFF); + + if (i2c_transfer(radio->client->adapter, msgs, 1) != 1) + return -EIO; + + return 0; +} + +/************************************************************************** + * General Driver Functions - ENTIRE REGISTERS + **************************************************************************/ +/* + * rtc6226_get_all_registers - read entire registers + */ +/* changed from static */ +int rtc6226_get_all_registers(struct rtc6226_device *radio) +{ + int i; + int err; + u8 reg[1] = {0x00}; + u8 buf[RADIO_REGISTER_NUM]; + struct i2c_msg msgs1[1] = { + { radio->client->addr, 0, 1, reg}, + }; + struct i2c_msg msgs[1] = { + { radio->client->addr, I2C_M_RD, sizeof(buf), buf }, + }; + + if (i2c_transfer(radio->client->adapter, msgs1, 1) != 1) + return -EIO; + + err = i2c_transfer(radio->client->adapter, msgs, 1); + + if (err < 0) + return -EIO; + + for (i = 0; i < 16; i++) + radio->registers[i] = + (u16)(((buf[i*2] << 8) & 0xff00) | buf[i*2+1]); + + return 0; +} + +/* + * rtc6226_vidioc_querycap - query device capabilities + */ +int rtc6226_vidioc_querycap(struct file *file, void *priv, + struct v4l2_capability *capability) +{ + FMDBG("%s enter\n", __func__); + strlcpy(capability->driver, DRIVER_NAME, sizeof(capability->driver)); + strlcpy(capability->card, DRIVER_CARD, sizeof(capability->card)); + capability->device_caps = V4L2_CAP_HW_FREQ_SEEK | V4L2_CAP_READWRITE | + V4L2_CAP_TUNER | V4L2_CAP_RADIO | V4L2_CAP_RDS_CAPTURE; + capability->capabilities = capability->device_caps | + V4L2_CAP_DEVICE_CAPS; + + return 0; +} + +/* + * rtc6226_i2c_interrupt - interrupt handler + */ +static void rtc6226_i2c_interrupt_handler(struct rtc6226_device *radio) +{ + unsigned char regnr; + int retval = 0; + unsigned short current_chan; + + FMDBG("%s enter\n", __func__); + + /* check Seek/Tune Complete */ + retval = rtc6226_get_register(radio, STATUS); + if (retval < 0) { + FMDERR("%s read fail to STATUS\n", __func__); + goto end; + } + + if (radio->registers[STATUS] & STATUS_STD) { + FMDBG("%s : STATUS=0x%4.4hx\n", __func__, + radio->registers[STATUS]); + + retval = rtc6226_get_register(radio, RSSI); + if (retval < 0) { + FMDERR("%s read fail to RSSI\n", __func__); + goto end; + } + FMDBG("%s : RSSI=0x%4.4hx\n", __func__, radio->registers[RSSI]); + /* stop seeking : clear STD*/ + radio->registers[SEEKCFG1] &= ~SEEKCFG1_CSR0_SEEK; + retval = rtc6226_set_register(radio, SEEKCFG1); + /*clear the status bit to allow another tune or seek*/ + current_chan = radio->registers[CHANNEL] & CHANNEL_CSR0_CH; + radio->registers[CHANNEL] &= ~CHANNEL_CSR0_TUNE; + retval = rtc6226_set_register(radio, CHANNEL); + if (retval < 0) + radio->registers[CHANNEL] = current_chan; + rtc6226_reset_rds_data(radio); + FMDBG("%s clear Seek/Tune bit\n", __func__); + if (radio->seek_tune_status == SEEK_PENDING) { + /* Enable the RDS as it was disabled before seek */ + rtc6226_rds_on(radio); + FMDBG("posting RTC6226_EVT_SEEK_COMPLETE event\n"); + rtc6226_q_event(radio, RTC6226_EVT_SEEK_COMPLETE); + /* post tune comp evt since seek results in a tune.*/ + FMDBG("posting RICHWAVE_EVT_TUNE_SUCC event\n"); + rtc6226_q_event(radio, RTC6226_EVT_TUNE_SUCC); + radio->seek_tune_status = NO_SEEK_TUNE_PENDING; + } else if (radio->seek_tune_status == TUNE_PENDING) { + FMDBG("posting RICHWAVE_EVT_TUNE_SUCC event\n"); + rtc6226_q_event(radio, RTC6226_EVT_TUNE_SUCC); + radio->seek_tune_status = NO_SEEK_TUNE_PENDING; + } else if (radio->seek_tune_status == SCAN_PENDING) { + /* when scan is pending and STC int is set, signal + * so that scan can proceed + */ + FMDBG("In %s, signalling scan thread\n", __func__); + complete(&radio->completion); + } + FMDBG("%s Seek/Tune done\n", __func__); + } else { + /* Check RDS data after tune/seek interrupt finished + * Update RDS registers + */ + for (regnr = 1; regnr < RDS_REGISTER_NUM; regnr++) { + retval = rtc6226_get_register(radio, STATUS + regnr); + if (retval < 0) + goto end; + } + /* get rds blocks */ + if ((radio->registers[STATUS] & STATUS_RDS_RDY) == 0) { + /* No RDS group ready, better luck next time */ + FMDERR("%s No RDS group ready\n", __func__); + goto end; + } else { + /* avoid RDS interrupt lock disable_irq*/ + if ((radio->registers[SYSCFG] & + SYSCFG_CSR0_RDS_EN) != 0) { + schedule_work(&radio->rds_worker); + } + } + } +end: + FMDBG("%s exit :%d\n", __func__, retval); +} + +static irqreturn_t rtc6226_isr(int irq, void *dev_id) +{ + struct rtc6226_device *radio = dev_id; + /* + * The call to queue_delayed_work ensures that a minimum delay + * (in jiffies) passes before the work is actually executed. The return + * value from the function is nonzero if the work_struct was actually + * added to queue (otherwise, it may have already been there and will + * not be added a second time). + */ + + queue_delayed_work(radio->wqueue, &radio->work, + msecs_to_jiffies(10)); + + return IRQ_HANDLED; +} + +static void rtc6226_handler(struct work_struct *work) +{ + struct rtc6226_device *radio; + + radio = container_of(work, struct rtc6226_device, work.work); + + rtc6226_i2c_interrupt_handler(radio); +} + +void rtc6226_disable_irq(struct rtc6226_device *radio) +{ + int irq; + + irq = radio->irq; + disable_irq_wake(irq); + free_irq(irq, radio); + + cancel_delayed_work_sync(&radio->work); + flush_workqueue(radio->wqueue); + + cancel_work_sync(&radio->rds_worker); + flush_workqueue(radio->wqueue_rds); + cancel_delayed_work_sync(&radio->work_scan); + flush_workqueue(radio->wqueue_scan); +} + +int rtc6226_enable_irq(struct rtc6226_device *radio) +{ + int retval; + int irq; + + retval = gpio_direction_input(radio->int_gpio); + if (retval) { + FMDERR("%s unable to set the gpio %d direction(%d)\n", + __func__, radio->int_gpio, retval); + return retval; + } + radio->irq = gpio_to_irq(radio->int_gpio); + irq = radio->irq; + + if (radio->irq < 0) { + FMDERR("%s: gpio_to_irq returned %d\n", __func__, radio->irq); + goto open_err_req_irq; + } + + FMDBG("%s irq number is = %d\n", __func__, radio->irq); + + retval = request_any_context_irq(radio->irq, rtc6226_isr, + IRQF_TRIGGER_FALLING, DRIVER_NAME, radio); + + if (retval < 0) { + FMDERR("%s Couldn't acquire FM gpio %d, retval:%d\n", + __func__, radio->irq, retval); + goto open_err_req_irq; + } else { + FMDBG("%s FM GPIO %d registered\n", __func__, radio->irq); + } + retval = enable_irq_wake(irq); + if (retval < 0) { + FMDERR("Could not wake FM interrupt\n"); + free_irq(irq, radio); + } + return retval; + +open_err_req_irq: + rtc6226_disable_irq(radio); + + return retval; +} + +static int rtc6226_fm_vio_reg_cfg(struct rtc6226_device *radio, bool on) +{ + int rc = 0; + struct fm_power_vreg_data *vreg; + + vreg = radio->vioreg; + if (!vreg) { + FMDERR("In %s, vio reg is NULL\n", __func__); + return rc; + } + if (on) { + FMDBG("vreg is : %s\n", vreg->name); + rc = regulator_set_voltage(vreg->reg, + vreg->low_vol_level, + vreg->high_vol_level); + if (rc < 0) { + FMDERR("set_vol(%s) fail %d\n", vreg->name, rc); + return rc; + } + rc = regulator_enable(vreg->reg); + if (rc < 0) { + FMDERR("reg enable(%s) failed.rc=%d\n", vreg->name, rc); + regulator_set_voltage(vreg->reg, + 0, + vreg->high_vol_level); + return rc; + } + vreg->is_enabled = true; + + } else { + rc = regulator_disable(vreg->reg); + if (rc < 0) { + FMDERR("reg disable(%s) fail rc=%d\n", vreg->name, rc); + return rc; + } + vreg->is_enabled = false; + + /* Set the min voltage to 0 */ + rc = regulator_set_voltage(vreg->reg, + 0, + vreg->high_vol_level); + if (rc < 0) { + FMDERR("set_vol(%s) fail %d\n", vreg->name, rc); + return rc; + } + } + return rc; +} + +static int rtc6226_fm_vdd_reg_cfg(struct rtc6226_device *radio, bool on) +{ + int rc = 0; + struct fm_power_vreg_data *vreg; + + vreg = radio->vddreg; + if (!vreg) { + FMDERR("In %s, vdd reg is NULL\n", __func__); + return rc; + } + + if (on) { + FMDBG("vreg is : %s\n", vreg->name); + rc = regulator_set_voltage(vreg->reg, + vreg->low_vol_level, + vreg->high_vol_level); + if (rc < 0) { + FMDERR("set_vol(%s) fail %d\n", vreg->name, rc); + return rc; + } + if (vreg->vdd_load) { + rc = regulator_set_load(vreg->reg, vreg->vdd_load); + if (rc < 0) { + FMDERR("%s Unable to set the load %d ,err=%d\n", + __func__, vreg->vdd_load, rc); + return rc; + } + } + + rc = regulator_enable(vreg->reg); + if (rc < 0) { + FMDERR("reg enable(%s) failed.rc=%d\n", vreg->name, rc); + regulator_set_voltage(vreg->reg, + 0, + vreg->high_vol_level); + return rc; + } + vreg->is_enabled = true; + } else { + rc = regulator_disable(vreg->reg); + if (rc < 0) { + FMDERR("reg disable(%s) fail. rc=%d\n", vreg->name, rc); + return rc; + } + vreg->is_enabled = false; + + /* Set the min voltage to 0 */ + rc = regulator_set_voltage(vreg->reg, + 0, + vreg->high_vol_level); + if (rc < 0) { + FMDERR("set_vol(%s) fail %d\n", vreg->name, rc); + return rc; + } + if (vreg->vdd_load) { + rc = regulator_set_load(vreg->reg, 0); + if (rc < 0) { + FMDERR("%s Unable to set the load 0 ,err=%d\n", + __func__, rc); + return rc; + } + } + } + return rc; +} + +static int rtc6226_fm_power_cfg(struct rtc6226_device *radio, bool powerflag) +{ + int rc = 0; + + if (powerflag) { + /* Turn ON sequence */ + rc = rtc6226_fm_vdd_reg_cfg(radio, powerflag); + if (rc < 0) { + FMDERR("In %s, vdd reg cfg failed %x\n", __func__, rc); + return rc; + } + rc = rtc6226_fm_vio_reg_cfg(radio, powerflag); + if (rc < 0) { + FMDERR("In %s, vio reg cfg failed %x\n", __func__, rc); + rtc6226_fm_vdd_reg_cfg(radio, false); + return rc; + } + } else { + /* Turn OFF sequence */ + rc = rtc6226_fm_vdd_reg_cfg(radio, powerflag); + if (rc < 0) + FMDERR("In %s, vdd reg cfg failed %x\n", __func__, rc); + rc = rtc6226_fm_vio_reg_cfg(radio, powerflag); + if (rc < 0) + FMDERR("In %s, vio reg cfg failed %x\n", __func__, rc); + } + return rc; +} +/* + * rtc6226_fops_open - file open + */ +int rtc6226_fops_open(struct file *file) +{ + struct rtc6226_device *radio = video_drvdata(file); + int retval; + + FMDBG("%s enter user num = %d\n", __func__, radio->users); + if (atomic_inc_return(&radio->users) != 1) { + FMDERR("Device already in use. Try again later\n"); + atomic_dec(&radio->users); + return -EBUSY; + } + + INIT_DELAYED_WORK(&radio->work, rtc6226_handler); + INIT_DELAYED_WORK(&radio->work_scan, rtc6226_scan); + INIT_WORK(&radio->rds_worker, rtc6226_rds_handler); + + /* Power up Supply voltage to VDD and VIO */ + retval = rtc6226_fm_power_cfg(radio, TURNING_ON); + if (retval) { + FMDERR("%s: failed to supply voltage\n", __func__); + goto open_err_setup; + } + + retval = rtc6226_enable_irq(radio); + /* Wait for the value to take effect on gpio. */ + msleep(100); + if (retval) { + FMDERR("%s:enable irq failed\n", __func__); + goto open_err_req_irq; + } + return retval; + +open_err_req_irq: + rtc6226_fm_power_cfg(radio, TURNING_OFF); +open_err_setup: + atomic_dec(&radio->users); + return retval; +} + +/* + * rtc6226_fops_release - file release + */ +int rtc6226_fops_release(struct file *file) +{ + struct rtc6226_device *radio = video_drvdata(file); + int retval = 0; + + FMDBG("%s : Exit\n", __func__); + if (radio->mode != FM_OFF) { + rtc6226_power_down(radio); + radio->mode = FM_OFF; + } + rtc6226_disable_irq(radio); + atomic_dec(&radio->users); + retval = rtc6226_fm_power_cfg(radio, TURNING_OFF); + if (retval < 0) + FMDERR("%s: failed to apply voltage\n", __func__); + return retval; +} + +static int rtc6226_parse_dt(struct device *dev, + struct rtc6226_device *radio) +{ + int rc = 0; + struct device_node *np = dev->of_node; + + radio->int_gpio = of_get_named_gpio(np, "fmint-gpio", 0); + if (radio->int_gpio < 0) { + FMDERR("%s int-gpio not provided in device tree\n", __func__); + rc = radio->int_gpio; + goto err_int_gpio; + } + + rc = gpio_request(radio->int_gpio, "fm_int"); + if (rc) { + FMDERR("%s unable to request gpio %d (%d)\n", __func__, + radio->int_gpio, rc); + goto err_int_gpio; + } + + rc = gpio_direction_output(radio->int_gpio, 0); + if (rc) { + FMDERR("%s unable to set the gpio %d direction(%d)\n", + __func__, radio->int_gpio, rc); + goto err_int_gpio; + } + /* Wait for the value to take effect on gpio. */ + msleep(100); + + return rc; + +err_int_gpio: + gpio_free(radio->int_gpio); + + return rc; +} + +static int rtc6226_pinctrl_init(struct rtc6226_device *radio) +{ + int retval = 0; + + radio->fm_pinctrl = devm_pinctrl_get(&radio->client->dev); + if (IS_ERR_OR_NULL(radio->fm_pinctrl)) { + FMDERR("%s: target does not use pinctrl\n", __func__); + retval = PTR_ERR(radio->fm_pinctrl); + return retval; + } + + radio->gpio_state_active = + pinctrl_lookup_state(radio->fm_pinctrl, + "pmx_fm_active"); + if (IS_ERR_OR_NULL(radio->gpio_state_active)) { + FMDERR("%s: cannot get FM active state\n", __func__); + retval = PTR_ERR(radio->gpio_state_active); + goto err_active_state; + } + + radio->gpio_state_suspend = + pinctrl_lookup_state(radio->fm_pinctrl, + "pmx_fm_suspend"); + if (IS_ERR_OR_NULL(radio->gpio_state_suspend)) { + FMDERR("%s: cannot get FM suspend state\n", __func__); + retval = PTR_ERR(radio->gpio_state_suspend); + goto err_suspend_state; + } + + return retval; + +err_suspend_state: + radio->gpio_state_suspend = 0; + +err_active_state: + radio->gpio_state_active = 0; + + return retval; +} + +static int rtc6226_dt_parse_vreg_info(struct device *dev, + struct fm_power_vreg_data *vreg, const char *vreg_name) +{ + int ret = 0; + u32 vol_suply[2]; + struct device_node *np = dev->of_node; + + ret = of_property_read_u32_array(np, vreg_name, vol_suply, 2); + if (ret < 0) { + FMDERR("Invalid property name\n"); + ret = -EINVAL; + } else { + vreg->low_vol_level = vol_suply[0]; + vreg->high_vol_level = vol_suply[1]; + } + return ret; +} + +/* + * rtc6226_i2c_probe - probe for the device + */ +static int rtc6226_i2c_probe(struct i2c_client *client, + const struct i2c_device_id *id) +{ + struct rtc6226_device *radio; + struct v4l2_device *v4l2_dev; + struct v4l2_ctrl_handler *hdl; + struct regulator *vddvreg = NULL; + struct regulator *viovreg = NULL; + int retval = 0; + int i = 0; + int kfifo_alloc_rc = 0; + + /* struct v4l2_ctrl *ctrl; */ + /* need to add description "irq-fm" in dts */ + + FMDBG("%s enter\n", __func__); + if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) { + retval = -ENODEV; + return retval; + } + + /* + * if voltage regulator is not ready yet, return the error + * if error is -EPROBE_DEFER to kernel then probe will be called at + * later point of time. + */ + viovreg = regulator_get(&client->dev, "vio"); + if (IS_ERR(viovreg)) { + retval = PTR_ERR(viovreg); + FMDERR("%s: regulator_get(vio) failed. retval=%d\n", + __func__, retval); + return retval; + } + + vddvreg = regulator_get(&client->dev, "vdd"); + if (IS_ERR(vddvreg)) { + retval = PTR_ERR(vddvreg); + FMDERR("%s: regulator_get(vdd) failed. retval=%d\n", + __func__, retval); + regulator_put(viovreg); + return retval; + } + + /* private data allocation and initialization */ + radio = kzalloc(sizeof(struct rtc6226_device), GFP_KERNEL); + if (!radio) { + retval = -ENOMEM; + regulator_put(viovreg); + regulator_put(vddvreg); + return retval; + } + + v4l2_dev = &radio->v4l2_dev; + retval = v4l2_device_register(&client->dev, v4l2_dev); + if (retval < 0) { + FMDERR("%s couldn't register v4l2_device\n", __func__); + goto err_vreg; + } + + FMDBG("v4l2_device_register successfully\n"); + hdl = &radio->ctrl_handler; + + /* initialize the device count */ + atomic_set(&radio->users, 0); + radio->client = client; + mutex_init(&radio->lock); + init_completion(&radio->completion); + + retval = rtc6226_parse_dt(&client->dev, radio); + if (retval) { + FMDERR("%s: Parsing DT failed(%d)\n", __func__, retval); + goto err_v4l2; + } + + radio->vddreg = devm_kzalloc(&client->dev, + sizeof(struct fm_power_vreg_data), + GFP_KERNEL); + if (!radio->vddreg) { + FMDERR("%s: allocating memory for vdd vreg failed\n", + __func__); + retval = -ENOMEM; + goto err_v4l2; + } + + radio->vddreg->reg = vddvreg; + radio->vddreg->name = "vdd"; + radio->vddreg->is_enabled = false; + of_property_read_u32(client->dev.of_node, + "rtc6226,vdd-load", &radio->vddreg->vdd_load); + FMDERR("%s: rtc6226,vdd-load val %d\n", + __func__, radio->vddreg->vdd_load); + retval = rtc6226_dt_parse_vreg_info(&client->dev, + radio->vddreg, "rtc6226,vdd-supply-voltage"); + if (retval < 0) { + FMDERR("%s: parsing vdd-supply failed\n", __func__); + goto err_v4l2; + } + + radio->vioreg = devm_kzalloc(&client->dev, + sizeof(struct fm_power_vreg_data), + GFP_KERNEL); + if (!radio->vioreg) { + FMDERR("%s: allocating memory for vio vreg failed\n", + __func__); + retval = -ENOMEM; + goto err_v4l2; + } + radio->vioreg->reg = viovreg; + radio->vioreg->name = "vio"; + radio->vioreg->is_enabled = false; + retval = rtc6226_dt_parse_vreg_info(&client->dev, + radio->vioreg, "rtc6226,vio-supply-voltage"); + if (retval < 0) { + FMDERR("%s: parsing vio-supply failed\n", __func__); + goto err_v4l2; + } + /* Initialize pin control*/ + retval = rtc6226_pinctrl_init(radio); + if (retval) { + FMDERR("%s: rtc6226_pinctrl_init returned %d\n", + __func__, retval); + /* if pinctrl is not supported, -EINVAL is returned*/ + if (retval == -EINVAL) + retval = 0; + } else { + FMDBG("%s rtc6226_pinctrl_init success\n", __func__); + } + + memcpy(&radio->videodev, &rtc6226_viddev_template, + sizeof(struct video_device)); + + radio->videodev.v4l2_dev = v4l2_dev; + radio->videodev.ioctl_ops = &rtc6226_ioctl_ops; + radio->videodev.device_caps = V4L2_CAP_HW_FREQ_SEEK | V4L2_CAP_READWRITE + | V4L2_CAP_TUNER | V4L2_CAP_RADIO | V4L2_CAP_RDS_CAPTURE; + video_set_drvdata(&radio->videodev, radio); + + /* rds buffer allocation */ + radio->buf_size = rds_buf * 3; + radio->buffer = kmalloc(radio->buf_size, GFP_KERNEL); + if (!radio->buffer) { + retval = -EIO; + goto err; + } + + for (i = 0; i < RTC6226_FM_BUF_MAX; i++) { + spin_lock_init(&radio->buf_lock[i]); + + kfifo_alloc_rc = kfifo_alloc(&radio->data_buf[i], + STD_BUF_SIZE, GFP_KERNEL); + + if (kfifo_alloc_rc != 0) { + FMDERR("%s: failed allocating buffers %d\n", + __func__, kfifo_alloc_rc); + retval = -ENOMEM; + goto err_rds; + } + } + radio->wqueue = NULL; + radio->wqueue_scan = NULL; + radio->wqueue_rds = NULL; + radio->band = -1; + + /* rds buffer configuration */ + radio->wr_index = 0; + radio->rd_index = 0; + init_waitqueue_head(&radio->event_queue); + init_waitqueue_head(&radio->read_queue); + init_waitqueue_head(&rtc6226_wq); + + radio->wqueue = create_singlethread_workqueue("fmradio"); + if (!radio->wqueue) { + retval = -ENOMEM; + goto err_rds; + } + + radio->wqueue_scan = create_singlethread_workqueue("fmradioscan"); + if (!radio->wqueue_scan) { + retval = -ENOMEM; + goto err_wqueue; + } + + radio->wqueue_rds = create_singlethread_workqueue("fmradiords"); + if (!radio->wqueue_rds) { + retval = -ENOMEM; + goto err_wqueue_scan; + } + + /* register video device */ + retval = video_register_device(&radio->videodev, VFL_TYPE_RADIO, + radio_nr); + if (retval) { + dev_info(&client->dev, "Could not register video device\n"); + goto err_all; + } + + i2c_set_clientdata(client, radio); /* move from below */ + FMDBG("%s exit\n", __func__); + return 0; + +err_all: + destroy_workqueue(radio->wqueue_rds); +err_wqueue_scan: + destroy_workqueue(radio->wqueue_scan); +err_wqueue: + destroy_workqueue(radio->wqueue); +err_rds: + kfree(radio->buffer); +err: + video_device_release_empty(&radio->videodev); +err_v4l2: + v4l2_device_unregister(v4l2_dev); +err_vreg: + if (radio && radio->vioreg && radio->vioreg->reg) { + regulator_put(radio->vioreg->reg); + devm_kfree(&client->dev, radio->vioreg); + } else { + regulator_put(viovreg); + } + if (radio && radio->vddreg && radio->vddreg->reg) { + regulator_put(radio->vddreg->reg); + devm_kfree(&client->dev, radio->vddreg); + } else { + regulator_put(vddvreg); + } + kfree(radio); + return retval; +} + +/* + * rtc6226_i2c_remove - remove the device + */ +static int rtc6226_i2c_remove(struct i2c_client *client) +{ + struct rtc6226_device *radio = i2c_get_clientdata(client); + + free_irq(client->irq, radio); + kfree(radio->buffer); + v4l2_ctrl_handler_free(&radio->ctrl_handler); + if (video_is_registered(&radio->videodev)) + video_unregister_device(&radio->videodev); + video_device_release_empty(&radio->videodev); + v4l2_device_unregister(&radio->v4l2_dev); + kfree(radio); + FMDBG("%s exit\n", __func__); + + return 0; +} + +#ifdef CONFIG_PM +/* + * rtc6226_i2c_suspend - suspend the device + */ +static int rtc6226_i2c_suspend(struct device *dev) +{ + struct i2c_client *client = to_i2c_client(dev); + struct rtc6226_device *radio = i2c_get_clientdata(client); + + FMDBG("%s %d\n", __func__, radio->client->addr); + + return 0; +} + + +/* + * rtc6226_i2c_resume - resume the device + */ +static int rtc6226_i2c_resume(struct device *dev) +{ + struct i2c_client *client = to_i2c_client(dev); + struct rtc6226_device *radio = i2c_get_clientdata(client); + + FMDBG("%s %d\n", __func__, radio->client->addr); + + return 0; +} + +static SIMPLE_DEV_PM_OPS(rtc6226_i2c_pm, rtc6226_i2c_suspend, + rtc6226_i2c_resume); +#endif + + +/* + * rtc6226_i2c_driver - i2c driver interface + */ +struct i2c_driver rtc6226_i2c_driver = { + .driver = { + .name = "rtc6226", + .owner = THIS_MODULE, + .of_match_table = of_match_ptr(rtc6226_i2c_dt_ids), +#ifdef CONFIG_PM + .pm = &rtc6226_i2c_pm, +#endif + }, + .probe = rtc6226_i2c_probe, + .remove = rtc6226_i2c_remove, + .id_table = rtc6226_i2c_id, +}; + +/* + * rtc6226_i2c_init + */ +int rtc6226_i2c_init(void) +{ + FMDBG(DRIVER_DESC ", Version " DRIVER_VERSION "\n"); + return i2c_add_driver(&rtc6226_i2c_driver); +} + +MODULE_LICENSE("GPL v2"); +MODULE_DESCRIPTION(DRIVER_DESC); +MODULE_VERSION(DRIVER_VERSION); diff --git a/rtc6226/radio-rtc6226.h b/rtc6226/radio-rtc6226.h new file mode 100644 index 0000000000..19d5cb48d4 --- /dev/null +++ b/rtc6226/radio-rtc6226.h @@ -0,0 +1,700 @@ +/* drivers/media/radio/rtc6226/radio-rtc6226.h + * + * Driver for Richwave RTC6226 FM Tuner + * + * Copyright (c) 2009 Tobias Lorenz + * Copyright (c) 2012 Hans de Goede + * Copyright (c) 2018 LG Electronics, Inc. + * Copyright (c) 2018 Richwave Technology Co.Ltd + * Copyright (c) 2021 Qualcomm Innovation Center, Inc. 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 as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * 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. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +/* driver definitions */ +/* #define _RDSDEBUG */ +#define DRIVER_NAME "rtc6226-fmtuner" + +/* kernel includes */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define RW_Kernel_ENG + +#define DEBUG +#undef FMDBG +#define FMDBG(fmt, args...) pr_debug("rtc6226: " fmt, ##args) + +#undef FMDERR +#define FMDERR(fmt, args...) pr_err("rtc6226: " fmt, ##args) + +/* driver definitions */ +#define DRIVER_KERNEL_VERSION KERNEL_VERSION(1, 0, 1) +#define DRIVER_CARD "Richwave rtc6226 FM Tuner" +#define DRIVER_DESC "I2C radio driver for rtc6226 FM Tuner" +#define DRIVER_VERSION "0.1.0" + +/************************************************************************** + * Register Definitions + **************************************************************************/ +#define RADIO_REGISTER_SIZE 2 /* 16 register bit width */ +#define RADIO_REGISTER_NUM 32 /* DEVICEID */ +#define RDS_REGISTER_NUM 6 /* STATUSRSSI */ + +#define DEVICEID 0 /* Device ID Code */ +#define DEVICE_ID 0xffff /* [15:00] Device ID */ +#define DEVICEID_PN 0xf000 /* [15:12] Part Number */ +#define DEVICEID_MFGID 0x0fff /* [11:00] Manufacturer ID */ + +#define CHIPID 1 /* Chip ID Code */ +#define CHIPID_REVISION_NO 0xfc00 /* [15:10] Chip Reversion */ + +#define MPXCFG 2 /* Power Configuration */ +#define MPXCFG_CSR0_DIS_SMUTE 0x8000 /* [15:15] Disable Softmute */ +#define MPXCFG_CSR0_DIS_MUTE 0x4000 /* [14:14] Disable Mute */ +#define MPXCFG_CSR0_MONO 0x2000 /* [13:13] Mono or Auto Detect */ +#define MPXCFG_CSR0_DEEM 0x1000 /* [12:12] DE-emphasis */ +#define MPXCFG_CSR0_VOLUME_EXT 0x0400 /* [10:10] Volume Extend */ +#define MPXCFG_CSR0_BLNDADJUST 0x0300 /* [09:08] Blending Adjust */ +#define MPXCFG_CSR0_SMUTERATE 0x00c0 /* [07:06] Softmute Rate */ +#define MPXCFG_CSR0_SMUTEATT 0x0030 /* [05:04] Softmute Attenuation */ +#define MPXCFG_CSR0_VOLUME 0x000f /* [03:00] Volume */ + +#define CHANNEL 3 /* Tuning Channel Setting */ +#define CHANNEL_CSR0_TUNE 0x8000 /* [15:15] Tune */ +#define CHANNEL_CSR0_CH 0x7fff /* [14:00] Tuning Channel */ + +#define SYSCFG 4 /* System Configuration 1 */ +#define SYSCFG_CSR0_RDSIRQEN 0x8000 /* [15:15] RDS Interrupt Enable */ +#define SYSCFG_CSR0_STDIRQEN 0x4000 /* [14:14] STD Interrupt Enable */ +#define SYSCFG_CSR0_DIS_AGC 0x2000 /* [13:13] Disable AGC */ +#define SYSCFG_CSR0_RDS_EN 0x1000 /* [12:12] RDS Enable */ +#define SYSCFG_CSR0_RBDS_M 0x0300 /* [09:08] MMBS setting */ + +#define SEEKCFG1 5 /* Seek Configuration 1 */ +#define SEEKCFG1_CSR0_SEEK 0x8000 /* [15:15] Enable Seek Function */ +#define SEEKCFG1_CSR0_SEEKUP 0x4000 /* [14:14] Seek Direction */ +#define SEEKCFG1_CSR0_SKMODE 0x2000 /* [13:13] Seek Mode */ +#define SEEKCFG1_CSR0_RSSI_LOW_TH 0x0f00 /* [11:08] RSSI Seek Threshold */ +#define SEEKCFG1_CSR0_RSSI_MONO_TH 0x000f /* [03:00] RSSI Seek Threshold */ + +#define POWERCFG 6 /* Power Configuration */ +#define POWERCFG_CSR0_ENABLE 0x8000 /* [15:15] Power-up Enable */ +#define POWERCFG_CSR0_DISABLE 0x4000 /* [14:14] Power-up Disable */ +#define POWERCFG_CSR0_BLNDOFS 0x0f00 /* [11:08] Blending Offset Value */ + +#define PADCFG 7 /* PAD Configuration */ +#define PADCFG_CSR0_GPIO 0x0004 /* [03:02] General purpose I/O */ + +#define BANKCFG 8 /* Bank Serlection */ + +#define SEEKCFG2 9 /* Seek Configuration 2 */ + +#define STATUS 10 /* Status and Work channel */ +#define STATUS_RDS_RDY 0x8000 /* [15:15] RDS Ready */ +#define STATUS_STD 0x4000 /* [14:14] Seek/Tune Done */ +#define STATUS_SF 0x2000 /* [13:13] Seek Fail */ +#define STATUS_RDS_SYNC 0x0800 /* [11:11] RDS synchronization */ +#define STATUS_SI 0x0400 /* [10:10] Stereo Indicator */ + +#define RSSI 11 /* RSSI and RDS error */ +#define RSSI_RDS_BA_ERRS 0xc000 /* [15:14] RDS Block A Errors */ +#define RSSI_RDS_BB_ERRS 0x3000 /* [15:14] RDS Block B Errors */ +#define RSSI_RDS_BC_ERRS 0x0c00 /* [13:12] RDS Block C Errors */ +#define RSSI_RDS_BD_ERRS 0x0300 /* [11:10] RDS Block D Errors */ +#define RSSI_RSSI 0x00ff /* [09:00] Read Channel */ + +#define BA_DATA 12 /* Block A data */ +#define RDSA_RDSA 0xffff /* [15:00] RDS Block A Data */ + +#define BB_DATA 13 /* Block B data */ +#define RDSB_RDSB 0xffff /* [15:00] RDS Block B Data */ + +#define BC_DATA 14 /* Block C data */ +#define RDSC_RDSC 0xffff /* [15:00] RDS Block C Data */ + +#define BD_DATA 15 /* Block D data */ +#define RDSD_RDSD 0xffff /* [15:00] RDS Block D Data */ + +#define AUDIOCFG 0x12 +#define AUDIOCFG_CSR0_VOL_AUTOFIX 0x0800 //[11:11] LSB Volume Bit Auto Fix(1) + +#define RADIOCFG 0x13 +#define CHANNEL_CSR0_CHSPACE 0x1f00 /* [12:08] Channel Sapcing */ + +#define RADIOSEEKCFG1 0x14 +/* [14:00] FM Seek Top CH, Unit 10KHz */ +#define CHANNEL_CSR0_FREQ_TOP 0x7fff + +#define RADIOSEEKCFG2 0x15 +/*[14:00] FM Seek Bottom CH, Unit 10KHz */ +#define CHANNEL_CSR0_FREQ_BOT 0x7fff + +#define I2SCFG 0x1c +/* [13:13] I2S DSP Mode(0:Normal, 1:Special) */ +#define I2S_DSP_SEL 0x2000 +/* [12:12] BCLK Polarity(0:Falling, 1:Rising) */ +#define I2S_BCLK_POL 0x1000 +/* [11:10] Word Bits Select(0:8b, 1:16b, 2:20b, 3:24b) */ +#define I2S_WD_SEL 0x0c00 +/* [09:08] Right CH Control(0:On, 1:Off, 1x:Auto) */ +#define I2S_RCH_SEL 0x0300 +/* [07:07] I2S Enable */ +#define I2S_EN 0x0080 /* [07:07] I2S Enable */ +#define I2S_MSEL 0x0040 /* [06:06] I2S Master */ +/* [05:04] I2S Output Mode(0:I2S, 1:LJ, 2:DSPA, 3:DSPB) */ +#define I2S_MODE 0x0030 +/* [03:02] I2S Sample Rate(0:32K, 1:44.1K, 2:48K) */ +#define I2S_FS_AUD_SEL 0x000c +/* [05:04] I2S BCLK Ratio(0:M32, 1:M64, 2:M128, 3:M256) */ +#define I2S_BCLK_AUD_SEL 0x0030 + +#define CHANNEL1 0x1e +#define STATUS_READCH 0x7fff /* [14:00] Read Channel */ + +#define TURN_ON 1 +#define TURN_OFF 0 +#define SRCH_UP 1 +#define SRCH_DOWN 0 + +#define WRAP_ENABLE 1 +#define WRAP_DISABLE 0 +#define DEFAULT_RSSI_TH 8 +/* Standard buffer size */ +#define STD_BUF_SIZE 256 + +/* to distinguish between seek, tune during STC int. */ +#define NO_SEEK_TUNE_PENDING 0 +#define TUNE_PENDING 1 +#define SEEK_PENDING 2 +#define SCAN_PENDING 3 +#define START_SCAN 1 +#define TUNE_TIMEOUT_MSEC 3000 +#define SEEK_TIMEOUT_MSEC 15000 + +#define RTC6226_MIN_SRCH_MODE 0x00 +#define RTC6226_MAX_SRCH_MODE 0x02 + +#define MIN_DWELL_TIME 0x00 +#define MAX_DWELL_TIME 0x0F + +#define TUNE_STEP_SIZE 10 +#define NO_OF_RDS_BLKS 4 + +#define GET_MSB(x)((x >> 8) & 0xFF) +#define GET_LSB(x)((x) & 0xFF) + +#define OFFSET_OF_GRP_TYP 11 +#define RDS_INT_BIT 0x01 +#define FIFO_CNT_16 0x10 +#define UNCORRECTABLE_RDS_EN 0xFF01 + +/* Write starts with the upper byte of register 0x02 */ +#define WRITE_REG_NUM 3 +#define WRITE_INDEX(i) ((i + 0x02)%16) + +/* Read starts with the upper byte of register 0x0a */ +#define READ_REG_NUM 2 +#define READ_INDEX(i) ((i + RADIO_REGISTER_NUM - 0x0a) % READ_REG_NUM) + +#define MSB_OF_BLK_0 4 +#define LSB_OF_BLK_0 5 +#define MSB_OF_BLK_1 6 +#define LSB_OF_BLK_1 7 +#define MSB_OF_BLK_2 8 +#define LSB_OF_BLK_2 9 +#define MSB_OF_BLK_3 10 +#define LSB_OF_BLK_3 11 +#define MAX_RT_LEN 64 +#define END_OF_RT 0x0d +#define MAX_PS_LEN 8 +#define OFFSET_OF_PS 5 +#define PS_VALIDATE_LIMIT 2 +#define RT_VALIDATE_LIMIT 2 +#define RDS_CMD_LEN 3 +#define RDS_RSP_LEN 13 +#define PS_EVT_DATA_LEN (MAX_PS_LEN + OFFSET_OF_PS) +#define NO_OF_PS 1 +#define OFFSET_OF_RT 5 +#define OFFSET_OF_PTY 5 +#define MAX_LEN_2B_GRP_RT 32 +#define CNT_FOR_2A_GRP_RT 4 +#define CNT_FOR_2B_GRP_RT 2 +#define PS_MASK 0x3 +#define PTY_MASK 0x1F +#define NO_OF_CHARS_IN_EACH_ADD 2 + +#define CORRECTED_NONE 0 +#define CORRECTED_ONE_TO_TWO 1 +#define CORRECTED_THREE_TO_FIVE 2 +#define ERRORS_CORRECTED(data, block) ((data>>block)&0x03) +/*Block Errors are reported in .5% increments*/ +#define BLER_SCALE_MAX 200 + +/* freqs are divided by 10. */ +#define SCALE_AF_CODE_TO_FREQ_KHZ(x) (87500 + (x*100)) + +#define RDS_TYPE_0A (0 * 2 + 0) +#define RDS_TYPE_0B (0 * 2 + 1) +#define RDS_TYPE_2A (2 * 2 + 0) +#define RDS_TYPE_2B (2 * 2 + 1) +#define RDS_TYPE_3A (3 * 2 + 0) +#define UNCORRECTABLE 3 + +#define APP_GRP_typ_MASK 0x1F +/*ERT*/ +#define ERT_AID 0x6552 +#define MAX_ERT_SEGMENT 31 +#define MAX_ERT_LEN 256 +#define ERT_OFFSET 3 +#define ERT_FORMAT_DIR_BIT 1 +#define ERT_CNT_PER_BLK 2 +/*RT PLUS*/ +#define DUMMY_CLASS 0 +#define RT_PLUS_LEN_1_TAG 3 +#define RT_ERT_FLAG_BIT 13 +#define RT_PLUS_AID 0x4bd7 +#define RT_ERT_FLAG_OFFSET 1 +#define RT_PLUS_OFFSET 2 +/*TAG1*/ +#define TAG1_MSB_OFFSET 3 +#define TAG1_MSB_MASK 7 +#define TAG1_LSB_OFFSET 13 +#define TAG1_POS_MSB_MASK 0x3F +#define TAG1_POS_MSB_OFFSET 1 +#define TAG1_POS_LSB_OFFSET 7 +#define TAG1_LEN_OFFSET 1 +#define TAG1_LEN_MASK 0x3F +/*TAG2*/ +#define TAG2_MSB_OFFSET 5 +#define TAG2_MSB_MASK 9 +#define TAG2_LSB_OFFSET 11 +#define TAG2_POS_MSB_MASK 0x3F +#define TAG2_POS_MSB_OFFSET 3 +#define TAG2_POS_LSB_OFFSET 5 +#define TAG2_LEN_MASK 0x1F + +#define DEFAULT_AF_RSSI_LOW_TH 25 +#define NO_OF_AF_IN_GRP 2 +#define MAX_NO_OF_AF 25 +#define MAX_AF_LIST_SIZE (MAX_NO_OF_AF * 4) /* 4 bytes per freq */ +#define GET_AF_EVT_LEN(x) (7 + x*4) +#define GET_AF_LIST_LEN(x) (x*4) +#define MIN_AF_FREQ_CODE 1 +#define MAX_AF_FREQ_CODE 204 +#define MIN_RSSI 0 +#define MAX_RSSI 15 + +/* 25 AFs supported for a freq. 224 means 1 AF. 225 means 2 AFs and so on */ +#define NO_AF_CNT_CODE 224 +#define MIN_AF_CNT_CODE 225 +#define MAX_AF_CNT_CODE 249 +#define AF_WAIT_SEC 10 +#define MAX_AF_WAIT_SEC 255 +#define AF_PI_WAIT_TIME 50 /* 50*100msec = 5sec */ + +#define CH_SPACING_200 200 +#define CH_SPACING_100 100 +#define CH_SPACING_50 50 +#define TURNING_ON 1 +#define TURNING_OFF 0 + +#define RW_PRIBASE (V4L2_CID_USER_BASE | 0xf000) + +/* freqs are divided by 10. */ +#define SCALE_AF_CODE_TO_FREQ_KHZ(x) (87500 + (x*100)) + +#define EXTRACT_BIT(data, bit_pos) ((data >> bit_pos) & 1) + +#define V4L2_CID_PRIVATE_CSR0_ENABLE (RW_PRIBASE + (DEVICEID<<4) + 1) +#define V4L2_CID_PRIVATE_CSR0_DISABLE (RW_PRIBASE + (DEVICEID<<4) + 2) +#define V4L2_CID_PRIVATE_DEVICEID (RW_PRIBASE + (DEVICEID<<4) + 3) + +#define V4L2_CID_PRIVATE_CSR0_DIS_SMUTE (RW_PRIBASE + (DEVICEID<<4) + 4) +#define V4L2_CID_PRIVATE_CSR0_DIS_MUTE (RW_PRIBASE + (DEVICEID<<4) + 5) +#define V4L2_CID_PRIVATE_CSR0_DEEM (RW_PRIBASE + (DEVICEID<<4) + 6) +#define V4L2_CID_PRIVATE_CSR0_BLNDADJUST (RW_PRIBASE + (DEVICEID<<4) + 7) +#define V4L2_CID_PRIVATE_CSR0_VOLUME (RW_PRIBASE + (DEVICEID<<4) + 8) + +#define V4L2_CID_PRIVATE_CSR0_BAND (RW_PRIBASE + (DEVICEID<<4) + 9) +#define V4L2_CID_PRIVATE_CSR0_CHSPACE (RW_PRIBASE + (DEVICEID<<4) + 10) + +#define V4L2_CID_PRIVATE_CSR0_DIS_AGC (RW_PRIBASE + (DEVICEID<<4) + 11) +#define V4L2_CID_PRIVATE_CSR0_RDS_EN (RW_PRIBASE + (DEVICEID<<4) + 12) + +#define V4L2_CID_PRIVATE_SEEK_CANCEL (RW_PRIBASE + (DEVICEID<<4) + 13) + +#define V4L2_CID_PRIVATE_CSR0_SEEKRSSITH (RW_PRIBASE + (DEVICEID<<4) + 14) +#define V4L2_CID_PRIVATE_RSSI (RW_PRIBASE + (CHIPID<<4) + 1) + +#define V4L2_CID_PRIVATE_RDS_RDY (RW_PRIBASE + (CHIPID<<4) + 2) +#define V4L2_CID_PRIVATE_STD (RW_PRIBASE + (CHIPID<<4) + 3) +#define V4L2_CID_PRIVATE_SF (RW_PRIBASE + (CHIPID<<4) + 4) +#define V4L2_CID_PRIVATE_RDS_SYNC (RW_PRIBASE + (CHIPID<<4) + 5) +#define V4L2_CID_PRIVATE_SI (RW_PRIBASE + (CHIPID<<4) + 6) + +#define NO_WAIT 2 +#define RDS_WAITING 5 +#define SEEK_CANCEL 6 +#define TUNE_PARAM 16 + +/************************************************************************** + * General Driver Definitions + **************************************************************************/ + +enum rtc6226_buf_t { + RTC6226_FM_BUF_SRCH_LIST, + RTC6226_FM_BUF_EVENTS, + RTC6226_FM_BUF_RT_RDS, + RTC6226_FM_BUF_PS_RDS, + RTC6226_FM_BUF_RAW_RDS, + RTC6226_FM_BUF_AF_LIST, + RTC6226_FM_BUF_RT_PLUS = 11, + RTC6226_FM_BUF_ERT, + RTC6226_FM_BUF_MAX +}; + +enum rtc6226_evt_t { + RTC6226_EVT_RADIO_READY, + RTC6226_EVT_TUNE_SUCC, + RTC6226_EVT_SEEK_COMPLETE, + RTC6226_EVT_SCAN_NEXT, + RTC6226_EVT_NEW_RAW_RDS, + RTC6226_EVT_NEW_RT_RDS, + RTC6226_EVT_NEW_PS_RDS, + RTC6226_EVT_ERROR, + RTC6226_EVT_BELOW_TH, + RTC6226_EVT_ABOVE_TH, + RTC6226_EVT_STEREO, + RTC6226_EVT_MONO, + RTC6226_EVT_RDS_AVAIL, + RTC6226_EVT_RDS_NOT_AVAIL, + RTC6226_EVT_NEW_SRCH_LIST, + RTC6226_EVT_NEW_AF_LIST, + RTC6226_EVT_TXRDSDAT, + RTC6226_EVT_TXRDSDONE, + RTC6226_EVT_RADIO_DISABLED, + RTC6226_EVT_NEW_ODA, + RTC6226_EVT_NEW_RT_PLUS, + RTC6226_EVT_NEW_ERT +}; + +struct rtc6226_recv_conf_req { + __u16 emphasis; + __u16 ch_spacing; + /* limits stored as actual freq / TUNE_STEP_SIZE */ + __u16 band_low_limit; + __u16 band_high_limit; +}; + +struct rtc6226_rel_freq { + __u8 rel_freq_msb; + __u8 rel_freq_lsb; +} __packed; + +struct rtc6226_srch_list_compl { + __u8 num_stations_found; + struct rtc6226_rel_freq rel_freq[20]; +} __packed; + +struct af_list_ev { + __le32 tune_freq_khz; + __le16 pi_code; + __u8 af_size; + __u8 af_list[MAX_AF_LIST_SIZE]; +} __packed; + +struct rtc6226_af_info { + /* no. of invalid AFs. */ + u8 inval_freq_cnt; + /* no. of AFs in the list. */ + u8 cnt; + /* actual size of the list */ + u8 size; + /* index of currently tuned station in the AF list. */ + u8 index; + /* PI of the frequency */ + u16 pi; + /* freq to which AF list belongs to. */ + u32 orig_freq_khz; + /* AF list */ + u32 af_list[MAX_NO_OF_AF]; +}; + +struct fm_power_vreg_data { + /* voltage regulator handle */ + struct regulator *reg; + /* regulator name */ + const char *name; + /* voltage levels to be set */ + unsigned int low_vol_level; + unsigned int high_vol_level; + int vdd_load; + /* is this regulator enabled? */ + bool is_enabled; +}; + +/* + * rtc6226_device - private data + */ +struct rtc6226_device { + int int_gpio; + int fm_sw_gpio; + int ext_ldo_gpio; + int reset_gpio; + struct regulator *vdd_reg; + struct v4l2_device v4l2_dev; + struct video_device videodev; + struct pinctrl *fm_pinctrl; + struct pinctrl_state *gpio_state_active; + struct pinctrl_state *gpio_state_suspend; + struct v4l2_ctrl_handler ctrl_handler; + struct fm_power_vreg_data *vddreg; + struct fm_power_vreg_data *vioreg; + int band; + int space; + atomic_t users; + unsigned int mode; + u8 seek_tune_status; + u8 rssi_th; + /* Richwave internal registers (0..15) */ + unsigned short registers[RADIO_REGISTER_NUM]; + + /* RDS receive buffer */ + wait_queue_head_t read_queue; + int irq; + int tuned_freq_khz; + int dwell_time_sec; + struct mutex lock; /* buffer locking */ + unsigned char *buffer; /* size is always multiple of three */ + bool is_search_cancelled; + u8 g_search_mode; + struct rtc6226_srch_list_compl srch_list; + /* buffer locks*/ + spinlock_t buf_lock[RTC6226_FM_BUF_MAX]; + struct rtc6226_recv_conf_req recv_conf; + struct workqueue_struct *wqueue; + struct workqueue_struct *wqueue_scan; + struct workqueue_struct *wqueue_rds; + struct work_struct rds_worker; + struct rtc6226_af_info af_info1; + struct rtc6226_af_info af_info2; + + struct delayed_work work; + struct delayed_work work_scan; + + wait_queue_head_t event_queue; + u8 write_buf[WRITE_REG_NUM]; + /* TO read events, data*/ + u8 read_buf[READ_REG_NUM]; + + u16 pi; /* PI of tuned channel */ + u8 pty; /* programe type of the tuned channel */ + + u16 block[NO_OF_RDS_BLKS]; + u8 rt_display[MAX_RT_LEN]; /* RT that will be displayed */ + u8 rt_tmp0[MAX_RT_LEN]; /* high probability RT */ + u8 rt_tmp1[MAX_RT_LEN]; /* low probability RT */ + u8 rt_cnt[MAX_RT_LEN]; /* high probability RT's hit count */ + u8 rt_flag; /* A/B flag of RT */ + bool valid_rt_flg; /* validity of A/B flag */ + u8 ps_display[MAX_PS_LEN]; /* PS that will be displayed */ + u8 ps_tmp0[MAX_PS_LEN]; /* high probability PS */ + u8 ps_tmp1[MAX_PS_LEN]; /* low probability PS */ + u8 ps_cnt[MAX_PS_LEN]; /* high probability PS's hit count */ + u8 bler[NO_OF_RDS_BLKS]; + u8 rt_plus_carrier; + u8 ert_carrier; + u8 ert_buf[MAX_ERT_LEN]; + u8 ert_len; + u8 c_byt_pair_index; + u8 utf_8_flag; + u8 rt_ert_flag; + u8 formatting_dir; + unsigned int buf_size; + unsigned int rd_index; + unsigned int wr_index; + + struct kfifo data_buf[RTC6226_FM_BUF_MAX]; + + struct completion completion; + bool stci_enabled; /* Seek/Tune Complete Interrupt */ + + struct i2c_client *client; + unsigned int tuner_state; + int lna_en; + int lna_gain; +}; + +enum radio_state_t { + FM_OFF, + FM_RECV, + FM_RESET, + FM_CALIB, + FM_TURNING_OFF, + FM_RECV_TURNING_ON, + FM_MAX_NO_STATES, +}; + +enum search_t { + SEEK, + SCAN, + SCAN_FOR_STRONG, +}; + +/************************************************************************** + * Frequency Multiplicator + **************************************************************************/ +#define FREQ_MUL 1000 +#define CONFIG_RDS + +enum v4l2_cid_private_rtc6226_t { + V4L2_CID_PRIVATE_RTC6226_SRCHMODE = (V4L2_CID_PRIVATE_BASE + 1), + V4L2_CID_PRIVATE_RTC6226_SCANDWELL, + V4L2_CID_PRIVATE_RTC6226_SRCHON, + V4L2_CID_PRIVATE_RTC6226_STATE, + V4L2_CID_PRIVATE_RTC6226_TRANSMIT_MODE, + V4L2_CID_PRIVATE_RTC6226_RDSGROUP_MASK, + V4L2_CID_PRIVATE_RTC6226_REGION, + V4L2_CID_PRIVATE_RTC6226_SIGNAL_TH, + V4L2_CID_PRIVATE_RTC6226_SRCH_PTY, + V4L2_CID_PRIVATE_RTC6226_SRCH_PI, + V4L2_CID_PRIVATE_RTC6226_SRCH_CNT, + V4L2_CID_PRIVATE_RTC6226_EMPHASIS, /* 800000c */ + V4L2_CID_PRIVATE_RTC6226_RDS_STD, + V4L2_CID_PRIVATE_RTC6226_SPACING, + V4L2_CID_PRIVATE_RTC6226_RDSON, + V4L2_CID_PRIVATE_RTC6226_RDSGROUP_PROC, + V4L2_CID_PRIVATE_RTC6226_LP_MODE, + V4L2_CID_PRIVATE_RTC6226_ANTENNA, + V4L2_CID_PRIVATE_RTC6226_RDSD_BUF, + V4L2_CID_PRIVATE_RTC6226_PSALL, + /*v4l2 Tx controls*/ + V4L2_CID_PRIVATE_RTC6226_TX_SETPSREPEATCOUNT, + V4L2_CID_PRIVATE_RTC6226_STOP_RDS_TX_PS_NAME, + V4L2_CID_PRIVATE_RTC6226_STOP_RDS_TX_RT, + V4L2_CID_PRIVATE_RTC6226_IOVERC, + V4L2_CID_PRIVATE_RTC6226_INTDET, + V4L2_CID_PRIVATE_RTC6226_MPX_DCC, + V4L2_CID_PRIVATE_RTC6226_AF_JUMP, + V4L2_CID_PRIVATE_RTC6226_RSSI_DELTA, + V4L2_CID_PRIVATE_RTC6226_HLSI, + + /* + * Here we have IOCTl's that are specific to IRIS + * (V4L2_CID_PRIVATE_BASE + 0x1E to V4L2_CID_PRIVATE_BASE + 0x28) + */ + V4L2_CID_PRIVATE_RTC6226_SOFT_MUTE,/* 0x800001E*/ + V4L2_CID_PRIVATE_RTC6226_RIVA_ACCS_ADDR, + V4L2_CID_PRIVATE_RTC6226_RIVA_ACCS_LEN, + V4L2_CID_PRIVATE_RTC6226_RIVA_PEEK, + V4L2_CID_PRIVATE_RTC6226_RIVA_POKE, + V4L2_CID_PRIVATE_RTC6226_SSBI_ACCS_ADDR, + V4L2_CID_PRIVATE_RTC6226_SSBI_PEEK, + V4L2_CID_PRIVATE_RTC6226_SSBI_POKE, + V4L2_CID_PRIVATE_RTC6226_TX_TONE, + V4L2_CID_PRIVATE_RTC6226_RDS_GRP_COUNTERS, + V4L2_CID_PRIVATE_RTC6226_SET_NOTCH_FILTER, /* 0x8000028 */ + + V4L2_CID_PRIVATE_RTC6226_SET_AUDIO_PATH, /* 0x8000029 */ + V4L2_CID_PRIVATE_RTC6226_DO_CALIBRATION, /* 0x800002A : IRIS */ + V4L2_CID_PRIVATE_RTC6226_SRCH_ALGORITHM, /* 0x800002B */ + V4L2_CID_PRIVATE_RTC6226_GET_SINR, /* 0x800002C : IRIS */ + V4L2_CID_PRIVATE_RTC6226_INTF_LOW_THRESHOLD, /* 0x800002D */ + V4L2_CID_PRIVATE_RTC6226_INTF_HIGH_THRESHOLD, /* 0x800002E */ + /* 0x800002F : IRIS, For Richwave Spike TH */ + V4L2_CID_PRIVATE_RTC6226_SINR_THRESHOLD, + /* V4L2_CID_PRIVATE_RTC6226_QLT_THRESHOLD, + */ /* 0x800002F : IRIS, For Richwave Spike TH + */ + V4L2_CID_PRIVATE_RTC6226_SINR_SAMPLES, /* 0x8000030 : IRIS */ + V4L2_CID_PRIVATE_RTC6226_SPUR_FREQ, + V4L2_CID_PRIVATE_RTC6226_SPUR_FREQ_RMSSI, /* For Richwave DC TH */ + /* V4L2_CID_PRIVATE_RTC6226_OFS_THRESHOLD, */ /* For Richwave DC TH */ + V4L2_CID_PRIVATE_RTC6226_SPUR_SELECTION, + V4L2_CID_PRIVATE_RTC6226_UPDATE_SPUR_TABLE, + V4L2_CID_PRIVATE_RTC6226_VALID_CHANNEL, + V4L2_CID_PRIVATE_RTC6226_AF_RMSSI_TH, + V4L2_CID_PRIVATE_RTC6226_AF_RMSSI_SAMPLES, + V4L2_CID_PRIVATE_RTC6226_GOOD_CH_RMSSI_TH, + V4L2_CID_PRIVATE_RTC6226_SRCHALGOTYPE, + V4L2_CID_PRIVATE_RTC6226_CF0TH12, + V4L2_CID_PRIVATE_RTC6226_SINRFIRSTSTAGE, + V4L2_CID_PRIVATE_RTC6226_RMSSIFIRSTSTAGE, + V4L2_CID_PRIVATE_RTC6226_RXREPEATCOUNT, + V4L2_CID_PRIVATE_RTC6226_RSSI_TH, /* 0x800003E */ + V4L2_CID_PRIVATE_RTC6226_AF_JUMP_RSSI_TH /* 0x800003F */ +}; + +enum FMBAND {FMBAND_87_108_MHZ, FMBAND_76_108_MHZ, FMBAND_76_91_MHZ, + FMBAND_64_76_MHZ}; +enum FMSPACE {FMSPACE_200_KHZ, FMSPACE_100_KHZ, FMSPACE_50_KHZ}; + + +/************************************************************************** + * Common Functions + **************************************************************************/ +extern struct i2c_driver rtc6226_i2c_driver; +extern struct video_device rtc6226_viddev_template; +extern const struct v4l2_ioctl_ops rtc6226_ioctl_ops; +extern const struct v4l2_ctrl_ops rtc6226_ctrl_ops; + +extern struct tasklet_struct my_tasklet; +extern int rtc6226_wq_flag; +extern wait_queue_head_t rtc6226_wq; +extern int rtc6226_get_all_registers(struct rtc6226_device *radio); +extern int rtc6226_get_register(struct rtc6226_device *radio, int regnr); +extern int rtc6226_set_register(struct rtc6226_device *radio, int regnr); +extern int rtc6226_set_serial_registers(struct rtc6226_device *radio, + u16 *data, int bytes); +int rtc6226_i2c_init(void); +int rtc6226_reset_rds_data(struct rtc6226_device *radio); +int rtc6226_set_freq(struct rtc6226_device *radio, unsigned int freq); +int rtc6226_start(struct rtc6226_device *radio); +int rtc6226_stop(struct rtc6226_device *radio); +int rtc6226_fops_open(struct file *file); +int rtc6226_power_up(struct rtc6226_device *radio); +int rtc6226_power_down(struct rtc6226_device *radio); +int rtc6226_fops_release(struct file *file); +int rtc6226_vidioc_querycap(struct file *file, void *priv, + struct v4l2_capability *capability); +int rtc6226_enable_irq(struct rtc6226_device *radio); +void rtc6226_disable_irq(struct rtc6226_device *radio); +void rtc6226_scan(struct work_struct *work); +void rtc6226_search(struct rtc6226_device *radio, bool on); +int rtc6226_cancel_seek(struct rtc6226_device *radio); +void rtc6226_rds_handler(struct work_struct *worker); +void rtc6226_q_event(struct rtc6226_device *radio, enum rtc6226_evt_t event); +int rtc6226_reset_rds_data(struct rtc6226_device *radio); +int rtc6226_rds_on(struct rtc6226_device *radio); diff --git a/slimbus/Kconfig b/slimbus/Kconfig new file mode 100644 index 0000000000..a465e3c4ce --- /dev/null +++ b/slimbus/Kconfig @@ -0,0 +1,16 @@ +# SPDX-License-Identifier: GPL-2.0-only + +config BTFM_SLIM + tristate "MSM Bluetooth/FM Slimbus Device" + depends on MSM_BT_POWER + select SLIMBUS + help + This enables BT/FM slimbus driver to get multiple audio channel. + This will make use of slimbus platform driver and slimbus + codec driver to communicate with slimbus machine driver and LPSS which + is Slimbus master.Slimbus slave initialization and configuration + will be done through this driver. + + Say Y here to compile support for Bluetooth slimbus driver + into the kernel or say M to compile as a module. + diff --git a/slimbus/Makefile b/slimbus/Makefile new file mode 100644 index 0000000000..bebebe22f7 --- /dev/null +++ b/slimbus/Makefile @@ -0,0 +1,3 @@ +ccflags-y += -I$(BT_ROOT)/include +bt_fm_slim-objs := btfm_slim.o btfm_slim_codec.o btfm_slim_slave.o +obj-$(CONFIG_BTFM_SLIM) += bt_fm_slim.o diff --git a/slimbus/btfm_slim.c b/slimbus/btfm_slim.c new file mode 100644 index 0000000000..d855f5f1db --- /dev/null +++ b/slimbus/btfm_slim.c @@ -0,0 +1,531 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2016-2021, The Linux Foundation. All rights reserved. + * Copyright (c) 2021 Qualcomm Innovation Center, Inc. All rights reserved. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "btpower.h" +#include "btfm_slim.h" +#include "btfm_slim_slave.h" +#define DELAY_FOR_PORT_OPEN_MS (200) +#define SLIM_MANF_ID_QCOM 0x217 +#define SLIM_PROD_CODE 0x221 + +#ifdef CONFIG_SLIMBUS +static bool btfm_is_port_opening_delayed = true; +#endif + +int btfm_slim_write(struct btfmslim *btfmslim, + uint16_t reg, uint8_t reg_val, uint8_t pgd) +{ + int ret = -1; +#ifdef CONFIG_SLIMBUS + uint32_t reg_addr; + int slim_write_tries = SLIM_SLAVE_RW_MAX_TRIES; + + BTFMSLIM_INFO("Write to %s", pgd?"PGD":"IFD"); + reg_addr = SLIM_SLAVE_REG_OFFSET + reg; + + for ( ; slim_write_tries != 0; slim_write_tries--) { + mutex_lock(&btfmslim->xfer_lock); + ret = slim_writeb(pgd ? btfmslim->slim_pgd : + &btfmslim->slim_ifd, reg_addr, reg_val); + mutex_unlock(&btfmslim->xfer_lock); + if (ret) { + BTFMSLIM_DBG("retrying to Write 0x%02x to reg 0x%x ret %d", + reg_val, reg_addr, ret); + } else { + BTFMSLIM_DBG("Written 0x%02x to reg 0x%x ret %d", reg_val, reg_addr, ret); + break; + } + + usleep_range(5000, 5100); + } + if (ret) { + BTFMSLIM_DBG("retrying to Write 0x%02x to reg 0x%x ret %d", + reg_val, reg_addr, ret); + } +#endif + return ret; +} + +int btfm_slim_read(struct btfmslim *btfmslim, uint32_t reg, uint8_t pgd) +{ + int ret = -1; +#ifdef CONFIG_SLIMBUS + int slim_read_tries = SLIM_SLAVE_RW_MAX_TRIES; + uint32_t reg_addr; + BTFMSLIM_DBG("Read from %s", pgd?"PGD":"IFD"); + reg_addr = SLIM_SLAVE_REG_OFFSET + reg; + + for ( ; slim_read_tries != 0; slim_read_tries--) { + mutex_lock(&btfmslim->xfer_lock); + + ret = slim_readb(pgd ? btfmslim->slim_pgd : + &btfmslim->slim_ifd, reg_addr); + BTFMSLIM_DBG("Read 0x%02x from reg 0x%x", ret, reg_addr); + mutex_unlock(&btfmslim->xfer_lock); + if (ret > 0) + break; + usleep_range(5000, 5100); + } +#endif + return ret; +} + +#ifdef CONFIG_SLIMBUS +static bool btfm_slim_is_sb_reset_needed(int chip_ver) +{ + switch (chip_ver) { + case QCA_APACHE_SOC_ID_0100: + case QCA_APACHE_SOC_ID_0110: + case QCA_APACHE_SOC_ID_0120: + case QCA_APACHE_SOC_ID_0121: + return true; + default: + return false; + } +} + +int btfm_slim_enable_ch(struct btfmslim *btfmslim, struct btfmslim_ch *ch, + uint8_t rxport, uint32_t rates, uint8_t nchan) +{ + int ret = -1; + int i = 0; + struct btfmslim_ch *chan = ch; + int chipset_ver; + + if (!btfmslim || !ch) + return -EINVAL; + + BTFMSLIM_DBG("port: %d ch: %d", ch->port, ch->ch); + + chan->dai.sruntime = slim_stream_allocate(btfmslim->slim_pgd, "BTFM_SLIM"); + if (chan->dai.sruntime == NULL) { + BTFMSLIM_ERR("slim_stream_allocate failed"); + return -EINVAL; + } + chan->dai.sconfig.bps = btfmslim->bps; + chan->dai.sconfig.direction = btfmslim->direction; + chan->dai.sconfig.rate = rates; + chan->dai.sconfig.ch_count = nchan; + chan->dai.sconfig.chs = kcalloc(nchan, sizeof(unsigned int), GFP_KERNEL); + if (!chan->dai.sconfig.chs) + return -ENOMEM; + + for (i = 0; i < nchan; i++, ch++) { + /* Enable port through registration setting */ + if (btfmslim->vendor_port_en) { + ret = btfmslim->vendor_port_en(btfmslim, ch->port, + rxport, 1); + if (ret < 0) { + BTFMSLIM_ERR("vendor_port_en failed ret[%d]", + ret); + goto error; + } + } + chan->dai.sconfig.chs[i] = chan->ch; + chan->dai.sconfig.port_mask |= BIT(chan->port); + } + + /* Activate the channel immediately */ + BTFMSLIM_INFO("port: %d, ch: %d", chan->port, chan->ch); + chipset_ver = btpower_get_chipset_version(); + BTFMSLIM_INFO("chipset soc version:%x", chipset_ver); + + /* Delay port opening for few chipsets if: + 1. for 8k, feedback channel + 2. 44.1k, 88.2k rxports + */ + if (((rates == 8000 && btfm_feedback_ch_setting && rxport == 0) || + (rxport == 1 && (rates == 44100 || rates == 88200))) && + btfm_slim_is_sb_reset_needed(chipset_ver)) { + + BTFMSLIM_INFO("btfm_is_port_opening_delayed %d", + btfm_is_port_opening_delayed); + if (!btfm_is_port_opening_delayed) { + BTFMSLIM_INFO("SB reset needed, sleeping"); + btfm_is_port_opening_delayed = true; + msleep(DELAY_FOR_PORT_OPEN_MS); + } + } + + /* for feedback channel, PCM bit should not be set */ + if (btfm_feedback_ch_setting) { + BTFMSLIM_DBG("port open for feedback ch, not setting PCM bit"); + //prop.dataf = SLIM_CH_DATAF_NOT_DEFINED; + /* reset so that next port open sets the data format properly */ + btfm_feedback_ch_setting = 0; + } + + ret = slim_stream_prepare(chan->dai.sruntime, &chan->dai.sconfig); + if (ret) { + BTFMSLIM_ERR("slim_stream_prepare failed = %d", ret); + goto error; + } + + ret = slim_stream_enable(chan->dai.sruntime); + if (ret) { + BTFMSLIM_ERR("slim_stream_enable failed = %d", ret); + goto error; + } +error: + kfree(chan->dai.sconfig.chs); + return ret; +} + +int btfm_slim_disable_ch(struct btfmslim *btfmslim, struct btfmslim_ch *ch, + uint8_t rxport, uint8_t nchan) +{ + int ret = -1; + int i = 0; + if (!btfmslim || !ch) + return -EINVAL; + + BTFMSLIM_INFO("port:%d ", ch->port); + if (ch->dai.sruntime == NULL) { + BTFMSLIM_ERR("Channel not enabled yet. returning"); + return -EINVAL; + } + + btfm_is_port_opening_delayed = false; + + ret = slim_stream_disable(ch->dai.sruntime); + if (ret != 0) + BTFMSLIM_ERR("slim_stream_disable failed returned val = %d", ret); + ret = slim_stream_unprepare(ch->dai.sruntime); + if (ret != 0) + BTFMSLIM_ERR("slim_stream_unprepare failed returned val = %d", ret); + + /* Disable port through registration setting */ + for (i = 0; i < nchan; i++, ch++) { + if (btfmslim->vendor_port_en) { + ret = btfmslim->vendor_port_en(btfmslim, ch->port, + rxport, 0); + if (ret < 0) { + BTFMSLIM_ERR("vendor_port_en failed [%d]", ret); + break; + } + } + } + ch->dai.sconfig.port_mask = 0; + kfree(ch->dai.sconfig.chs); + return ret; +} + +static int btfm_slim_alloc_port(struct btfmslim *btfmslim) +{ + int ret = -EINVAL, i; + int chipset_ver; + struct btfmslim_ch *rx_chs; + struct btfmslim_ch *tx_chs; + + if (!btfmslim) + return ret; + + chipset_ver = btpower_get_chipset_version(); + BTFMSLIM_INFO("chipset soc version:%x", chipset_ver); + + rx_chs = btfmslim->rx_chs; + tx_chs = btfmslim->tx_chs; + if ((chipset_ver >= QCA_CHEROKEE_SOC_ID_0310) && + (chipset_ver <= QCA_CHEROKEE_SOC_ID_0320_UMC)) { + for (i = 0; (tx_chs->port != BTFM_SLIM_PGD_PORT_LAST) && + (i < BTFM_SLIM_NUM_CODEC_DAIS); i++, tx_chs++) { + if (tx_chs->port == SLAVE_SB_PGD_PORT_TX1_FM) + tx_chs->port = CHRKVER3_SB_PGD_PORT_TX1_FM; + else if (tx_chs->port == SLAVE_SB_PGD_PORT_TX2_FM) + tx_chs->port = CHRKVER3_SB_PGD_PORT_TX2_FM; + BTFMSLIM_INFO("Tx port:%d", tx_chs->port); + } + tx_chs = btfmslim->tx_chs; + } + if (!rx_chs || !tx_chs) + return ret; + + return 0; +} + +static int btfm_slim_get_logical_addr(struct slim_device *slim) +{ + int ret = 0; + const unsigned long timeout = jiffies + + msecs_to_jiffies(SLIM_SLAVE_PRESENT_TIMEOUT); + BTFMSLIM_INFO(""); + + do { + + ret = slim_get_logical_addr(slim); + if (!ret) { + BTFMSLIM_DBG("Assigned l-addr: 0x%x", slim->laddr); + break; + } + /* Give SLIMBUS time to report present and be ready. */ + usleep_range(1000, 1100); + BTFMSLIM_DBG("retyring get logical addr"); + } while (time_before(jiffies, timeout)); + return ret; +} + +int btfm_slim_hw_init(struct btfmslim *btfmslim) +{ + int ret = -1; + int chipset_ver; + struct slim_device *slim; + struct slim_device *slim_ifd; + + BTFMSLIM_DBG(""); + if (!btfmslim) + return -EINVAL; + + if (btfmslim->enabled) { + BTFMSLIM_DBG("Already enabled"); + return 0; + } + + slim = btfmslim->slim_pgd; + slim_ifd = &btfmslim->slim_ifd; + + mutex_lock(&btfmslim->io_lock); + BTFMSLIM_INFO( + "PGD Enum Addr: mfr id:%.02x prod code:%.02x dev ind:%.02x ins:%.02x", + slim->e_addr.manf_id, slim->e_addr.prod_code, + slim->e_addr.dev_index, slim->e_addr.instance); + + + chipset_ver = btpower_get_chipset_version(); + BTFMSLIM_INFO("chipset soc version:%x", chipset_ver); + + if (chipset_ver == QCA_HSP_SOC_ID_0100 || + chipset_ver == QCA_HSP_SOC_ID_0110 || + chipset_ver == QCA_HSP_SOC_ID_0200 || + chipset_ver == QCA_HSP_SOC_ID_0210 || + chipset_ver == QCA_HSP_SOC_ID_1201 || + chipset_ver == QCA_HSP_SOC_ID_1211) { + BTFMSLIM_INFO("chipset is hastings prime, overwriting EA"); + slim->is_laddr_valid = false; + slim->e_addr.manf_id = SLIM_MANF_ID_QCOM; + slim->e_addr.prod_code = SLIM_PROD_CODE; + slim->e_addr.dev_index = 0x01; + slim->e_addr.instance = 0x0; + /* we are doing this to indicate that this is not a child node + * (doesn't have call back functions). Needed only for querying + * logical address. + */ + slim_ifd->dev.driver = NULL; + slim_ifd->ctrl = btfmslim->slim_pgd->ctrl; //slimbus controller structure. + slim_ifd->is_laddr_valid = false; + slim_ifd->e_addr.manf_id = SLIM_MANF_ID_QCOM; + slim_ifd->e_addr.prod_code = SLIM_PROD_CODE; + slim_ifd->e_addr.dev_index = 0x0; + slim_ifd->e_addr.instance = 0x0; + slim_ifd->laddr = 0x0; + } else if (chipset_ver == QCA_MOSELLE_SOC_ID_0100 || + chipset_ver == QCA_MOSELLE_SOC_ID_0110) { + BTFMSLIM_INFO("chipset is Moselle, overwriting EA"); + slim->is_laddr_valid = false; + slim->e_addr.manf_id = SLIM_MANF_ID_QCOM; + slim->e_addr.prod_code = 0x222; + slim->e_addr.dev_index = 0x01; + slim->e_addr.instance = 0x0; + /* we are doing this to indicate that this is not a child node + * (doesn't have call back functions). Needed only for querying + * logical address. + */ + slim_ifd->dev.driver = NULL; + slim_ifd->ctrl = btfmslim->slim_pgd->ctrl; //slimbus controller structure. + slim_ifd->is_laddr_valid = false; + slim_ifd->e_addr.manf_id = SLIM_MANF_ID_QCOM; + slim_ifd->e_addr.prod_code = 0x222; + slim_ifd->e_addr.dev_index = 0x0; + slim_ifd->e_addr.instance = 0x0; + slim_ifd->laddr = 0x0; + } + BTFMSLIM_INFO( + "PGD Enum Addr: manu id:%.02x prod code:%.02x dev idx:%.02x instance:%.02x", + slim->e_addr.manf_id, slim->e_addr.prod_code, + slim->e_addr.dev_index, slim->e_addr.instance); + + BTFMSLIM_INFO( + "IFD Enum Addr: manu id:%.02x prod code:%.02x dev idx:%.02x instance:%.02x", + slim_ifd->e_addr.manf_id, slim_ifd->e_addr.prod_code, + slim_ifd->e_addr.dev_index, slim_ifd->e_addr.instance); + + /* Assign Logical Address for PGD (Ported Generic Device) + * enumeration address + */ + ret = btfm_slim_get_logical_addr(btfmslim->slim_pgd); + if (ret) { + BTFMSLIM_ERR("failed to get slimbus logical address: %d", ret); + goto error; + } + + /* Assign Logical Address for Ported Generic Device + * enumeration address + */ + ret = btfm_slim_get_logical_addr(&btfmslim->slim_ifd); + if (ret) { + BTFMSLIM_ERR("failed to get slimbus logical address: %d", ret); + goto error; + } + + ret = btfm_slim_alloc_port(btfmslim); + if (ret != 0) + goto error; + /* Start vendor specific initialization and get port information */ + if (btfmslim->vendor_init) + ret = btfmslim->vendor_init(btfmslim); + + /* Only when all registers read/write successfully, it set to + * enabled status + */ + btfmslim->enabled = 1; +error: + mutex_unlock(&btfmslim->io_lock); + return ret; +} + + +int btfm_slim_hw_deinit(struct btfmslim *btfmslim) +{ + int ret = 0; + + BTFMSLIM_INFO(""); + if (!btfmslim) + return -EINVAL; + + if (!btfmslim->enabled) { + BTFMSLIM_DBG("Already disabled"); + return 0; + } + mutex_lock(&btfmslim->io_lock); + btfmslim->enabled = 0; + mutex_unlock(&btfmslim->io_lock); + return ret; +} +#endif + +static int btfm_slim_status(struct slim_device *sdev, + enum slim_device_status status) +{ + int ret = 0; +#ifdef CONFIG_SLIMBUS + struct device *dev = &sdev->dev; + struct btfmslim *btfm_slim; + btfm_slim = dev_get_drvdata(dev); + ret = btfm_slim_register_codec(btfm_slim); + if (ret) + BTFMSLIM_ERR("error, registering slimbus codec failed"); +#endif + return ret; +} + +static int btfm_slim_probe(struct slim_device *slim) +{ + int ret = 0; + struct btfmslim *btfm_slim; + + pr_info("%s: name = %s\n", __func__, dev_name(&slim->dev)); + /*this as true during the probe then slimbus won't check for logical address*/ + slim->is_laddr_valid = true; + dev_set_name(&slim->dev, "%s", "btfmslim_slave"); + pr_info("%s: name = %s\n", __func__, dev_name(&slim->dev)); + + BTFMSLIM_DBG(""); + BTFMSLIM_ERR("is_laddr_valid is true"); + if (!slim->ctrl) + return -EINVAL; + + /* Allocation btfmslim data pointer */ + btfm_slim = kzalloc(sizeof(struct btfmslim), GFP_KERNEL); + if (btfm_slim == NULL) { + BTFMSLIM_ERR("error, allocation failed"); + return -ENOMEM; + } + /* BTFM Slimbus driver control data configuration */ + btfm_slim->slim_pgd = slim; + /* Assign vendor specific function */ + btfm_slim->rx_chs = SLIM_SLAVE_RXPORT; + btfm_slim->tx_chs = SLIM_SLAVE_TXPORT; + btfm_slim->vendor_init = SLIM_SLAVE_INIT; + btfm_slim->vendor_port_en = SLIM_SLAVE_PORT_EN; + + /* Created Mutex for slimbus data transfer */ + mutex_init(&btfm_slim->io_lock); + mutex_init(&btfm_slim->xfer_lock); + dev_set_drvdata(&slim->dev, btfm_slim); + + /* Driver specific data allocation */ + btfm_slim->dev = &slim->dev; + ret = btpower_register_slimdev(&slim->dev); + if (ret < 0) { + btfm_slim_unregister_codec(&slim->dev); + ret = -EPROBE_DEFER; + goto dealloc; + } + return ret; +dealloc: + mutex_destroy(&btfm_slim->io_lock); + mutex_destroy(&btfm_slim->xfer_lock); + kfree(btfm_slim); + return ret; +} + +static void btfm_slim_remove(struct slim_device *slim) +{ + struct device *dev = &slim->dev; + struct btfmslim *btfm_slim = dev_get_drvdata(dev); + BTFMSLIM_DBG(""); + mutex_destroy(&btfm_slim->io_lock); + mutex_destroy(&btfm_slim->xfer_lock); + snd_soc_unregister_component(&slim->dev); + kfree(btfm_slim); +} + +static const struct slim_device_id btfm_slim_id[] = { + { + .manf_id = SLIM_MANF_ID_QCOM, + .prod_code = SLIM_PROD_CODE, + .dev_index = 0x1, + .instance = 0x0, + }, + { + .manf_id = SLIM_MANF_ID_QCOM, + .prod_code = 0x220, + .dev_index = 0x1, + .instance = 0x0, + } +}; + +MODULE_DEVICE_TABLE(slim, btfm_slim_id); + +static struct slim_driver btfm_slim_driver = { + .driver = { + .name = "btfmslim-driver", + .owner = THIS_MODULE, + }, + .probe = btfm_slim_probe, + .device_status = btfm_slim_status, + .remove = btfm_slim_remove, + .id_table = btfm_slim_id +}; + +#ifdef CONFIG_SLIMBUS +module_slim_driver(btfm_slim_driver); +#endif +MODULE_LICENSE("GPL v2"); +MODULE_DESCRIPTION("BTFM Slimbus Slave driver"); diff --git a/slimbus/btfm_slim.h b/slimbus/btfm_slim.h new file mode 100644 index 0000000000..d3e0377dca --- /dev/null +++ b/slimbus/btfm_slim.h @@ -0,0 +1,169 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (c) 2016-2020, The Linux Foundation. All rights reserved. + * Copyright (c) 2021 Qualcomm Innovation Center, Inc. All rights reserved. + */ + +#ifndef BTFM_SLIM_H +#define BTFM_SLIM_H +#include + +#define BTFMSLIM_DBG(fmt, arg...) pr_debug("%s: " fmt "\n", __func__, ## arg) +#define BTFMSLIM_INFO(fmt, arg...) pr_info("%s: " fmt "\n", __func__, ## arg) +#define BTFMSLIM_ERR(fmt, arg...) pr_err("%s: " fmt "\n", __func__, ## arg) + +/* Vendor specific defines + * This should redefines in slimbus slave specific header + */ +#define SLIM_SLAVE_COMPATIBLE_STR "btfmslim_slave" +#define SLIM_SLAVE_REG_OFFSET 0x0000 +#define SLIM_SLAVE_RXPORT NULL +#define SLIM_SLAVE_TXPORT NULL +#define SLIM_SLAVE_INIT NULL +#define SLIM_SLAVE_PORT_EN NULL + +/* Misc defines */ +#define SLIM_SLAVE_RW_MAX_TRIES 3 +#define SLIM_SLAVE_PRESENT_TIMEOUT 100 + +#define PGD 1 +#define IFD 0 + + + +/* Codec driver defines */ +enum { + BTFM_FM_SLIM_TX = 0, + BTFM_BT_SCO_SLIM_TX, + BTFM_BT_SCO_A2DP_SLIM_RX, + BTFM_BT_SPLIT_A2DP_SLIM_RX, + BTFM_SLIM_NUM_CODEC_DAIS +}; + +struct btfm_slim_codec_dai_data { + struct slim_stream_config sconfig; + struct slim_stream_runtime *sruntime; +}; + +struct btfmslim_ch { + int id; + char *name; + uint16_t port; /* slimbus port number */ + uint8_t ch; /* slimbus channel number */ + struct btfm_slim_codec_dai_data dai; +}; + +/* Slimbus Port defines - This should be redefined in specific device file */ +#define BTFM_SLIM_PGD_PORT_LAST 0xFF + +struct btfmslim { + struct device *dev; + struct slim_device *slim_pgd; //Physical address + struct slim_device slim_ifd; //Interface address + struct mutex io_lock; + struct mutex xfer_lock; + uint8_t enabled; + uint32_t num_rx_port; + uint32_t num_tx_port; + uint32_t sample_rate; + uint32_t bps; + uint16_t direction; + struct btfmslim_ch *rx_chs; + struct btfmslim_ch *tx_chs; + int (*vendor_init)(struct btfmslim *btfmslim); + int (*vendor_port_en)(struct btfmslim *btfmslim, uint8_t port_num, + uint8_t rxport, uint8_t enable); +}; + +extern int btfm_feedback_ch_setting; + +/** + * btfm_slim_hw_init: Initialize slimbus slave device + * Returns: + * 0: Success + * else: Fail + */ +int btfm_slim_hw_init(struct btfmslim *btfmslim); + +/** + * btfm_slim_hw_deinit: Deinitialize slimbus slave device + * Returns: + * 0: Success + * else: Fail + */ +int btfm_slim_hw_deinit(struct btfmslim *btfmslim); + +/** + * btfm_slim_write: write value to pgd or ifd device + * @btfmslim: slimbus slave device data pointer. + * @reg: slimbus slave register address + * @reg_val: value to write at register address + * @pgd: selection for device: either PGD or IFD + * Returns: + No of bytes written + -1 + */ +int btfm_slim_write(struct btfmslim *btfmslim, + uint16_t reg, uint8_t reg_val, uint8_t pgd); + + + +/** + * btfm_slim_read: read value from pgd or ifd device + * @btfmslim: slimbus slave device data pointer. + * @reg: slimbus slave register address + * @dest: data pointer to read + * @pgd: selection for device: either PGD or IFD + * Returns: + No of bytes read + -1 + */ +int btfm_slim_read(struct btfmslim *btfmslim, + uint32_t reg, uint8_t pgd); + + +/** + * btfm_slim_enable_ch: enable channel for slimbus slave port + * @btfmslim: slimbus slave device data pointer. + * @ch: slimbus slave channel pointer + * @rxport: rxport or txport + * Returns: + * -EINVAL + * -ETIMEDOUT + * -ENOMEM + */ +int btfm_slim_enable_ch(struct btfmslim *btfmslim, + struct btfmslim_ch *ch, uint8_t rxport, uint32_t rates, + uint8_t nchan); + +/** + * btfm_slim_disable_ch: disable channel for slimbus slave port + * @btfmslim: slimbus slave device data pointer. + * @ch: slimbus slave channel pointer + * @rxport: rxport or txport + * @nChan: number of chaneels. + * Returns: + * -EINVAL + * -ETIMEDOUT + * -ENOMEM + */ +int btfm_slim_disable_ch(struct btfmslim *btfmslim, + struct btfmslim_ch *ch, uint8_t rxport, uint8_t nchan); + +/** + * btfm_slim_register_codec: Register codec driver in slimbus device node + * @btfmslim: slimbus slave device data pointer. + * Returns: + * -ENOMEM + * 0 + */ +int btfm_slim_register_codec(struct btfmslim *btfmslim); + +/** + * btfm_slim_unregister_codec: Unregister codec driver in slimbus device node + * @dev: device node + * Returns: + * VOID + */ +void btfm_slim_unregister_codec(struct device *dev); +#endif /* BTFM_SLIM_H */ diff --git a/slimbus/btfm_slim_codec.c b/slimbus/btfm_slim_codec.c new file mode 100644 index 0000000000..fc529e3d0c --- /dev/null +++ b/slimbus/btfm_slim_codec.c @@ -0,0 +1,458 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2016-2021, The Linux Foundation. All rights reserved. + * Copyright (c) 2021 Qualcomm Innovation Center, Inc. All rights reserved. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "btfm_slim.h" + +static int bt_soc_enable_status; +int btfm_feedback_ch_setting; + +#ifdef CONFIG_SLIMBUS +static int btfm_slim_codec_write(struct snd_soc_component *codec, + unsigned int reg, unsigned int value) +{ + BTFMSLIM_DBG(""); + return 0; +} + +static unsigned int btfm_slim_codec_read(struct snd_soc_component *codec, + unsigned int reg) +{ + BTFMSLIM_DBG(""); + return 0; +} + +static int btfm_soc_status_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + BTFMSLIM_DBG(""); + ucontrol->value.integer.value[0] = bt_soc_enable_status; + return 1; +} + +static int btfm_soc_status_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + BTFMSLIM_DBG(""); + return 1; +} + +static int btfm_get_feedback_ch_setting(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + BTFMSLIM_DBG(""); + ucontrol->value.integer.value[0] = btfm_feedback_ch_setting; + return 1; +} + +static int btfm_put_feedback_ch_setting(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + BTFMSLIM_DBG(""); + btfm_feedback_ch_setting = ucontrol->value.integer.value[0]; + return 1; +} + +static const struct snd_kcontrol_new status_controls[] = { + SOC_SINGLE_EXT("BT SOC status", 0, 0, 1, 0, + btfm_soc_status_get, + btfm_soc_status_put), + SOC_SINGLE_EXT("BT set feedback channel", 0, 0, 1, 0, + btfm_get_feedback_ch_setting, + btfm_put_feedback_ch_setting) +}; + + +static int btfm_slim_codec_probe(struct snd_soc_component *codec) +{ + BTFMSLIM_DBG(""); + snd_soc_add_component_controls(codec, status_controls, + ARRAY_SIZE(status_controls)); + return 0; +} + +static void btfm_slim_codec_remove(struct snd_soc_component *codec) +{ + BTFMSLIM_DBG(""); +} + +static int btfm_slim_dai_startup(struct snd_pcm_substream *substream, + struct snd_soc_dai *dai) +{ + int ret = -1; + struct btfmslim *btfmslim = snd_soc_component_get_drvdata(dai->component); + + BTFMSLIM_DBG("substream = %s stream = %d dai->name = %s", + substream->name, substream->stream, dai->name); + ret = btfm_slim_hw_init(btfmslim); + return ret; +} + +static void btfm_slim_dai_shutdown(struct snd_pcm_substream *substream, + struct snd_soc_dai *dai) +{ + int i; + struct btfmslim *btfmslim = snd_soc_component_get_drvdata(dai->component); + struct btfmslim_ch *ch; + uint8_t rxport, nchan = 1; + + BTFMSLIM_DBG("dai->name: %s, dai->id: %d, dai->rate: %d", dai->name, + dai->id, dai->rate); + + switch (dai->id) { + case BTFM_FM_SLIM_TX: + nchan = 2; + ch = btfmslim->tx_chs; + rxport = 0; + break; + case BTFM_BT_SCO_SLIM_TX: + ch = btfmslim->tx_chs; + rxport = 0; + break; + case BTFM_BT_SCO_A2DP_SLIM_RX: + case BTFM_BT_SPLIT_A2DP_SLIM_RX: + ch = btfmslim->rx_chs; + rxport = 1; + break; + case BTFM_SLIM_NUM_CODEC_DAIS: + default: + BTFMSLIM_ERR("dai->id is invalid:%d", dai->id); + return; + } + /* Search for dai->id matched port handler */ + for (i = 0; (i < BTFM_SLIM_NUM_CODEC_DAIS) && + (ch->id != BTFM_SLIM_NUM_CODEC_DAIS) && + (ch->id != dai->id); ch++, i++) + ; + + if ((ch->port == BTFM_SLIM_PGD_PORT_LAST) || + (ch->id == BTFM_SLIM_NUM_CODEC_DAIS)) { + BTFMSLIM_ERR("ch is invalid!!"); + return; + } + + btfm_slim_disable_ch(btfmslim, ch, rxport, nchan); + btfm_slim_hw_deinit(btfmslim); +} + +static int btfm_slim_dai_hw_params(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params, + struct snd_soc_dai *dai) +{ + struct btfmslim *btfmslim; + + btfmslim = snd_soc_component_get_drvdata(dai->component); + btfmslim->bps = params_width(params); + btfmslim->direction = substream->stream; + BTFMSLIM_DBG("dai->name = %s DAI-ID %x rate %d bps %d num_ch %d", + dai->name, dai->id, params_rate(params), params_width(params), + params_channels(params)); + return 0; +} + +static int btfm_slim_dai_prepare(struct snd_pcm_substream *substream, + struct snd_soc_dai *dai) +{ + int ret = -EINVAL; + int i = 0; + struct btfmslim_ch *ch; + uint8_t rxport, nchan = 1; + struct btfmslim *btfmslim; + + btfmslim = snd_soc_component_get_drvdata(dai->component); + btfmslim->direction = substream->stream; + bt_soc_enable_status = 0; + BTFMSLIM_INFO("dai->name: %s, dai->id: %d, dai->rate: %d direction: %d", dai->name, + dai->id, dai->rate, btfmslim->direction); + + /* save sample rate */ + btfmslim->sample_rate = dai->rate; + + switch (dai->id) { + case BTFM_FM_SLIM_TX: + nchan = 2; + ch = btfmslim->tx_chs; + rxport = 0; + break; + case BTFM_BT_SCO_SLIM_TX: + ch = btfmslim->tx_chs; + rxport = 0; + break; + case BTFM_BT_SCO_A2DP_SLIM_RX: + case BTFM_BT_SPLIT_A2DP_SLIM_RX: + ch = btfmslim->rx_chs; + rxport = 1; + break; + case BTFM_SLIM_NUM_CODEC_DAIS: + default: + BTFMSLIM_ERR("dai->id is invalid:%d", dai->id); + return ret; + } + + /* Search for dai->id matched port handler */ + for (i = 0; (i < BTFM_SLIM_NUM_CODEC_DAIS) && + (ch->id != BTFM_SLIM_NUM_CODEC_DAIS) && + (ch->id != dai->id); ch++, i++) + ; + + if ((ch->port == BTFM_SLIM_PGD_PORT_LAST) || + (ch->id == BTFM_SLIM_NUM_CODEC_DAIS)) { + BTFMSLIM_ERR("ch is invalid!!"); + return ret; + } + + ret = btfm_slim_enable_ch(btfmslim, ch, rxport, dai->rate, nchan); + + /* save the enable channel status */ + if (ret == 0) + bt_soc_enable_status = 1; + return ret; +} + +/* This function will be called once during boot up */ +static int btfm_slim_dai_set_channel_map(struct snd_soc_dai *dai, + unsigned int tx_num, unsigned int *tx_slot, + unsigned int rx_num, unsigned int *rx_slot) +{ + int ret = 0, i; + struct btfmslim *btfmslim = snd_soc_component_get_drvdata(dai->component); + struct btfmslim_ch *rx_chs; + struct btfmslim_ch *tx_chs; + + BTFMSLIM_DBG(""); + + if (!btfmslim) + return -EINVAL; + + rx_chs = btfmslim->rx_chs; + tx_chs = btfmslim->tx_chs; + + if (!rx_chs || !tx_chs) + return ret; + + BTFMSLIM_DBG("Rx: id\tname\tport\tch"); + for (i = 0; (rx_chs->port != BTFM_SLIM_PGD_PORT_LAST) && (i < rx_num); + i++, rx_chs++) { + /* Set Rx Channel number from machine driver and + * get channel handler from slimbus driver + */ + rx_chs->ch = *(uint8_t *)(rx_slot + i); + BTFMSLIM_DBG(" %d\t%s\t%d\t%x\t%d\t%x", rx_chs->id, + rx_chs->name, rx_chs->port, rx_chs->ch); + } + + BTFMSLIM_DBG("Tx: id\tname\tport\tch"); + for (i = 0; (tx_chs->port != BTFM_SLIM_PGD_PORT_LAST) && (i < tx_num); + i++, tx_chs++) { + /* Set Tx Channel number from machine driver and + * get channel handler from slimbus driver + */ + tx_chs->ch = *(uint8_t *)(tx_slot + i); + BTFMSLIM_DBG(" %d\t%s\t%d\t%x\t%d\t%x", tx_chs->id, + tx_chs->name, tx_chs->port, tx_chs->ch); + } + + return ret; +} + +static int btfm_slim_dai_get_channel_map(struct snd_soc_dai *dai, + unsigned int *tx_num, unsigned int *tx_slot, + unsigned int *rx_num, unsigned int *rx_slot) +{ + int i, ret = -EINVAL, *slot = NULL, j = 0, num = 1; + struct btfmslim *btfmslim = snd_soc_component_get_drvdata(dai->component); + struct btfmslim_ch *ch = NULL; + + if (!btfmslim) + return ret; + + switch (dai->id) { + case BTFM_FM_SLIM_TX: + num = 2; + case BTFM_BT_SCO_SLIM_TX: + if (!tx_slot || !tx_num) { + BTFMSLIM_ERR("Invalid tx_slot %p or tx_num %p", + tx_slot, tx_num); + return -EINVAL; + } + ch = btfmslim->tx_chs; + if (!ch) + return -EINVAL; + slot = tx_slot; + *rx_slot = 0; + *tx_num = num; + *rx_num = 0; + break; + case BTFM_BT_SCO_A2DP_SLIM_RX: + case BTFM_BT_SPLIT_A2DP_SLIM_RX: + if (!rx_slot || !rx_num) { + BTFMSLIM_ERR("Invalid rx_slot %p or rx_num %p", + rx_slot, rx_num); + return -EINVAL; + } + ch = btfmslim->rx_chs; + if (!ch) + return -EINVAL; + slot = rx_slot; + *tx_slot = 0; + *tx_num = 0; + *rx_num = num; + break; + default: + BTFMSLIM_ERR("Unsupported DAI %d", dai->id); + return -EINVAL; + } + + do { + if (!ch) + return -EINVAL; + for (i = 0; (i < BTFM_SLIM_NUM_CODEC_DAIS) && (ch->id != + BTFM_SLIM_NUM_CODEC_DAIS) && (ch->id != dai->id); + ch++, i++) + ; + + if (ch->id == BTFM_SLIM_NUM_CODEC_DAIS || + i == BTFM_SLIM_NUM_CODEC_DAIS) { + BTFMSLIM_ERR( + "No channel has been allocated for dai (%d)", + dai->id); + return -EINVAL; + } + if (!slot) + return -EINVAL; + *(slot + j) = ch->ch; + BTFMSLIM_DBG("id:%d, port:%d, ch:%d, slot: %d", ch->id, + ch->port, ch->ch, *(slot + j)); + + /* In case it has mulitiple channels */ + if (++j < num) + ch++; + } while (j < num); + + return 0; +} + +static struct snd_soc_dai_ops btfmslim_dai_ops = { + .startup = btfm_slim_dai_startup, + .shutdown = btfm_slim_dai_shutdown, + .hw_params = btfm_slim_dai_hw_params, + .prepare = btfm_slim_dai_prepare, + .set_channel_map = btfm_slim_dai_set_channel_map, + .get_channel_map = btfm_slim_dai_get_channel_map, +}; + +static struct snd_soc_dai_driver btfmslim_dai[] = { + { /* FM Audio data multiple channel : FM -> qdsp */ + .name = "btfm_fm_slim_tx", + .id = BTFM_FM_SLIM_TX, + .capture = { + .stream_name = "FM TX Capture", + .rates = SNDRV_PCM_RATE_48000, /* 48 KHz */ + .formats = SNDRV_PCM_FMTBIT_S16_LE, /* 16 bits */ + .rate_max = 48000, + .rate_min = 48000, + .channels_min = 1, + .channels_max = 2, + }, + .ops = &btfmslim_dai_ops, + }, + { /* Bluetooth SCO voice uplink: bt -> modem */ + .name = "btfm_bt_sco_slim_tx", + .id = BTFM_BT_SCO_SLIM_TX, + .capture = { + .stream_name = "SCO TX Capture", + /* 8 KHz or 16 KHz */ + .rates = SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000 + | SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000 + | SNDRV_PCM_RATE_88200 | SNDRV_PCM_RATE_96000, + .formats = SNDRV_PCM_FMTBIT_S16_LE, /* 16 bits */ + .rate_max = 96000, + .rate_min = 8000, + .channels_min = 1, + .channels_max = 1, + }, + .ops = &btfmslim_dai_ops, + }, + { /* Bluetooth SCO voice downlink: modem -> bt or A2DP Playback */ + .name = "btfm_bt_sco_a2dp_slim_rx", + .id = BTFM_BT_SCO_A2DP_SLIM_RX, + .playback = { + .stream_name = "SCO A2DP RX Playback", + /* 8/16/44.1/48/88.2/96 Khz */ + .rates = SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000 + | SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000 + | SNDRV_PCM_RATE_88200 | SNDRV_PCM_RATE_96000, + .formats = SNDRV_PCM_FMTBIT_S16_LE, /* 16 bits */ + .rate_max = 96000, + .rate_min = 8000, + .channels_min = 1, + .channels_max = 1, + }, + .ops = &btfmslim_dai_ops, + }, + { /* Bluetooth Split A2DP data: qdsp -> bt */ + .name = "btfm_bt_split_a2dp_slim_rx", + .id = BTFM_BT_SPLIT_A2DP_SLIM_RX, + .playback = { + .stream_name = "SPLIT A2DP Playback", + .rates = SNDRV_PCM_RATE_48000, /* 48 KHz */ + .formats = SNDRV_PCM_FMTBIT_S16_LE, /* 16 bits */ + .rate_max = 48000, + .rate_min = 48000, + .channels_min = 1, + .channels_max = 1, + }, + .ops = &btfmslim_dai_ops, + }, +}; + +static const struct snd_soc_component_driver btfmslim_codec = { + .probe = btfm_slim_codec_probe, + .remove = btfm_slim_codec_remove, + .read = btfm_slim_codec_read, + .write = btfm_slim_codec_write, +}; + +int btfm_slim_register_codec(struct btfmslim *btfm_slim) +{ + int ret = 0; + struct device *dev = btfm_slim->dev; + + BTFMSLIM_DBG(""); + dev_err(dev, "\n"); + + /* Register Codec driver */ + ret = snd_soc_register_component(dev, &btfmslim_codec, + btfmslim_dai, ARRAY_SIZE(btfmslim_dai)); + if (ret) + BTFMSLIM_ERR("failed to register codec (%d)", ret); + return ret; +} + +void btfm_slim_unregister_codec(struct device *dev) +{ + BTFMSLIM_DBG(""); + /* Unregister Codec driver */ + snd_soc_unregister_component(dev); +} +#endif + +MODULE_DESCRIPTION("BTFM Slimbus Codec driver"); +MODULE_LICENSE("GPL v2"); diff --git a/slimbus/btfm_slim_slave.c b/slimbus/btfm_slim_slave.c new file mode 100644 index 0000000000..fb4493eff2 --- /dev/null +++ b/slimbus/btfm_slim_slave.c @@ -0,0 +1,187 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2016-2020, The Linux Foundation. All rights reserved. + * Copyright (c) 2021 Qualcomm Innovation Center, Inc. All rights reserved. + */ + +#include +#include "btfm_slim.h" +#include "btfm_slim_slave.h" + +/* SLAVE (WCN3990/QCA6390) Port assignment */ +struct btfmslim_ch slave_rxport[] = { + {.id = BTFM_BT_SCO_A2DP_SLIM_RX, .name = "SCO_A2P_Rx", + .port = SLAVE_SB_PGD_PORT_RX_SCO}, + {.id = BTFM_BT_SPLIT_A2DP_SLIM_RX, .name = "A2P_Rx", + .port = SLAVE_SB_PGD_PORT_RX_A2P}, + {.id = BTFM_SLIM_NUM_CODEC_DAIS, .name = "", + .port = BTFM_SLIM_PGD_PORT_LAST}, +}; + +struct btfmslim_ch slave_txport[] = { + {.id = BTFM_BT_SCO_SLIM_TX, .name = "SCO_Tx", + .port = SLAVE_SB_PGD_PORT_TX_SCO}, + {.id = BTFM_FM_SLIM_TX, .name = "FM_Tx1", + .port = SLAVE_SB_PGD_PORT_TX1_FM}, + {.id = BTFM_FM_SLIM_TX, .name = "FM_Tx2", + .port = SLAVE_SB_PGD_PORT_TX2_FM}, + {.id = BTFM_SLIM_NUM_CODEC_DAIS, .name = "", + .port = BTFM_SLIM_PGD_PORT_LAST}, +}; + +/* Function description */ +int btfm_slim_slave_hw_init(struct btfmslim *btfmslim) +{ + int ret = 0; + uint32_t reg; + + BTFMSLIM_DBG(""); + + if (!btfmslim) + return -EINVAL; + + /* Get SB_SLAVE_HW_REV_MSB value*/ + reg = SLAVE_SB_SLAVE_HW_REV_MSB; + ret = btfm_slim_read(btfmslim, reg, IFD); + if (ret < 0) + BTFMSLIM_ERR("failed to read (%d) reg 0x%x", ret, reg); + + BTFMSLIM_DBG("Major Rev: 0x%x, Minor Rev: 0x%x", + (ret & 0xF0) >> 4, (ret & 0x0F)); + + /* Get SB_SLAVE_HW_REV_LSB value*/ + reg = SLAVE_SB_SLAVE_HW_REV_LSB; + ret = btfm_slim_read(btfmslim, reg, IFD); + if (ret < 0) + BTFMSLIM_ERR("failed to read (%d) reg 0x%x", ret, reg); + else { + BTFMSLIM_INFO("read (%d) reg 0x%x", ret, reg); + ret = 0; + } + return ret; +} + +static inline int is_fm_port(uint8_t port_num) +{ + if (port_num == SLAVE_SB_PGD_PORT_TX1_FM || + port_num == CHRKVER3_SB_PGD_PORT_TX1_FM || + port_num == CHRKVER3_SB_PGD_PORT_TX2_FM || + port_num == SLAVE_SB_PGD_PORT_TX2_FM) + return 1; + else + return 0; +} + +int btfm_slim_slave_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; + + BTFMSLIM_DBG("port(%d) enable(%d)", port_num, enable); + if (rxport) { + BTFMSLIM_DBG("sample rate is %d", btfmslim->sample_rate); + if (enable && + btfmslim->sample_rate != 44100 && + btfmslim->sample_rate != 88200) { + BTFMSLIM_DBG("setting multichannel bit"); + /* 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 = SLAVE_SB_PGD_RX_PORTn_MULTI_CHNL_0( + rxport_num); + } else { + rxport_num = port_num - 24; + reg_val = 0x01 << rxport_num; + reg = SLAVE_SB_PGD_RX_PORTn_MULTI_CHNL_1( + rxport_num); + } + + BTFMSLIM_DBG("writing reg_val (%d) to reg(%x)", + reg_val, reg); + ret = btfm_slim_write(btfmslim, reg, reg_val, IFD); + if (ret < 0) { + BTFMSLIM_ERR("failed to write (%d) reg 0x%x", + ret, reg); + goto error; + } + } + /* Port enable */ + reg = SLAVE_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)) { + if (port_num == CHRKVER3_SB_PGD_PORT_TX1_FM) + reg_val = (0x1 << CHRKVER3_SB_PGD_PORT_TX1_FM); + else if (port_num == CHRKVER3_SB_PGD_PORT_TX2_FM) + reg_val = (0x1 << CHRKVER3_SB_PGD_PORT_TX2_FM); + else + reg_val = (0x1 << SLAVE_SB_PGD_PORT_TX1_FM) | + (0x1 << SLAVE_SB_PGD_PORT_TX2_FM); + reg = SLAVE_SB_PGD_TX_PORTn_MULTI_CHNL_0(port_num); + BTFMSLIM_INFO("writing reg_val (%d) to reg(%x)", reg_val, reg); + ret = btfm_slim_write(btfmslim, reg, reg_val, IFD); + if (ret < 0) { + BTFMSLIM_ERR("failed to write (%d) reg 0x%x", ret, reg); + goto error; + } + } else if (port_num == SLAVE_SB_PGD_PORT_TX_SCO) { + /* SCO Tx */ + reg_val = 0x1 << SLAVE_SB_PGD_PORT_TX_SCO; + reg = SLAVE_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, reg_val, IFD); + if (ret < 0) { + 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 = (SLAVE_ENABLE_OVERRUN_AUTO_RECOVERY | + SLAVE_ENABLE_UNDERRUN_AUTO_RECOVERY); + reg = SLAVE_SB_PGD_PORT_TX_OR_UR_CFGN(port_num); + ret = btfm_slim_write(btfmslim, reg, reg_val, IFD); + if (ret < 0) { + BTFMSLIM_ERR("failed to write (%d) reg 0x%x", ret, reg); + goto error; + } + +enable_disable_txport: + /* Port enable */ + reg = SLAVE_SB_PGD_PORT_TX_CFGN(port_num); + +enable_disable_rxport: + if (enable) + en = SLAVE_SB_PGD_PORT_ENABLE; + else + en = SLAVE_SB_PGD_PORT_DISABLE; + + if (is_fm_port(port_num)) + reg_val = en | SLAVE_SB_PGD_PORT_WM_L8; + else if (port_num == SLAVE_SB_PGD_PORT_TX_SCO) + reg_val = enable ? en | SLAVE_SB_PGD_PORT_WM_L1 : en; + else + reg_val = enable ? en | SLAVE_SB_PGD_PORT_WM_LB : en; + + if (enable && port_num == SLAVE_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, reg_val, IFD); + if (ret < 0) + BTFMSLIM_ERR("failed to write (%d) reg 0x%x", ret, reg); + +error: + return ret; +} diff --git a/slimbus/btfm_slim_slave.h b/slimbus/btfm_slim_slave.h new file mode 100644 index 0000000000..0c1d1ff07e --- /dev/null +++ b/slimbus/btfm_slim_slave.h @@ -0,0 +1,180 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (c) 2016-2021, The Linux Foundation. All rights reserved. + * Copyright (c) 2021 Qualcomm Innovation Center, Inc. All rights reserved. + */ + +#ifndef BTFM_SLIM_SLAVE_H +#define BTFM_SLIM_SLAVE_H +#include "btfm_slim.h" + +/* Registers Address */ +#define SLAVE_SB_COMP_TEST 0x00000000 +#define SLAVE_SB_SLAVE_HW_REV_MSB 0x00000001 +#define SLAVE_SB_SLAVE_HW_REV_LSB 0x00000002 +#define SLAVE_SB_DEBUG_FEATURES 0x00000005 +#define SLAVE_SB_INTF_INT_EN 0x00000010 +#define SLAVE_SB_INTF_INT_STATUS 0x00000011 +#define SLAVE_SB_INTF_INT_CLR 0x00000012 +#define SLAVE_SB_FRM_CFG 0x00000013 +#define SLAVE_SB_FRM_STATUS 0x00000014 +#define SLAVE_SB_FRM_INT_EN 0x00000015 +#define SLAVE_SB_FRM_INT_STATUS 0x00000016 +#define SLAVE_SB_FRM_INT_CLR 0x00000017 +#define SLAVE_SB_FRM_WAKEUP 0x00000018 +#define SLAVE_SB_FRM_CLKCTL_DONE 0x00000019 +#define SLAVE_SB_FRM_IE_STATUS 0x0000001A +#define SLAVE_SB_FRM_VE_STATUS 0x0000001B +#define SLAVE_SB_PGD_TX_CFG_STATUS 0x00000020 +#define SLAVE_SB_PGD_RX_CFG_STATUS 0x00000021 +#define SLAVE_SB_PGD_DEV_INT_EN 0x00000022 +#define SLAVE_SB_PGD_DEV_INT_STATUS 0x00000023 +#define SLAVE_SB_PGD_DEV_INT_CLR 0x00000024 +#define SLAVE_SB_PGD_PORT_INT_EN_RX_0 0x00000030 +#define SLAVE_SB_PGD_PORT_INT_EN_RX_1 0x00000031 +#define SLAVE_SB_PGD_PORT_INT_EN_TX_0 0x00000032 +#define SLAVE_SB_PGD_PORT_INT_EN_TX_1 0x00000033 +#define SLAVE_SB_PGD_PORT_INT_STATUS_RX_0 0x00000034 +#define SLAVE_SB_PGD_PORT_INT_STATUS_RX_1 0x00000035 +#define SLAVE_SB_PGD_PORT_INT_STATUS_TX_0 0x00000036 +#define SLAVE_SB_PGD_PORT_INT_STATUS_TX_1 0x00000037 +#define SLAVE_SB_PGD_PORT_INT_CLR_RX_0 0x00000038 +#define SLAVE_SB_PGD_PORT_INT_CLR_RX_1 0x00000039 +#define SLAVE_SB_PGD_PORT_INT_CLR_TX_0 0x0000003A +#define SLAVE_SB_PGD_PORT_INT_CLR_TX_1 0x0000003B +#define SLAVE_SB_PGD_PORT_RX_CFGN(n) (0x00000040 + n) +#define SLAVE_SB_PGD_PORT_TX_CFGN(n) (0x00000050 + n) +#define SLAVE_SB_PGD_PORT_INT_RX_SOURCEN(n) (0x00000060 + n) +#define SLAVE_SB_PGD_PORT_INT_TX_SOURCEN(n) (0x00000070 + n) +#define SLAVE_SB_PGD_PORT_RX_STATUSN(n) (0x00000080 + n) +#define SLAVE_SB_PGD_PORT_TX_STATUSN(n) (0x00000090 + n) +#define SLAVE_SB_PGD_TX_PORTn_MULTI_CHNL_0(n) (0x00000100 + 0x4*n) +#define SLAVE_SB_PGD_TX_PORTn_MULTI_CHNL_1(n) (0x00000101 + 0x4*n) +#define SLAVE_SB_PGD_RX_PORTn_MULTI_CHNL_0(n) (0x00000180 + 0x4*n) +#define SLAVE_SB_PGD_RX_PORTn_MULTI_CHNL_1(n) (0x00000181 + 0x4*n) +#define SLAVE_SB_PGD_PORT_TX_OR_UR_CFGN(n) (0x000001F0 + n) + +/* Register Bit Setting */ +#define SLAVE_ENABLE_OVERRUN_AUTO_RECOVERY (0x1 << 1) +#define SLAVE_ENABLE_UNDERRUN_AUTO_RECOVERY (0x1 << 0) +#define SLAVE_SB_PGD_PORT_ENABLE (0x1 << 0) +#define SLAVE_SB_PGD_PORT_DISABLE (0x0 << 0) +#define SLAVE_SB_PGD_PORT_WM_L1 (0x1 << 1) +#define SLAVE_SB_PGD_PORT_WM_L2 (0x2 << 1) +#define SLAVE_SB_PGD_PORT_WM_L3 (0x3 << 1) +#define SLAVE_SB_PGD_PORT_WM_L8 (0x8 << 1) +#define SLAVE_SB_PGD_PORT_WM_LB (0xB << 1) + +#define SLAVE_SB_PGD_PORT_RX_NUM 16 +#define SLAVE_SB_PGD_PORT_TX_NUM 16 + +/* PGD Port Map */ +#define SLAVE_SB_PGD_PORT_TX_SCO 0 +#define SLAVE_SB_PGD_PORT_TX1_FM 1 +#define SLAVE_SB_PGD_PORT_TX2_FM 2 +#define CHRKVER3_SB_PGD_PORT_TX1_FM 5 +#define CHRKVER3_SB_PGD_PORT_TX2_FM 4 +#define SLAVE_SB_PGD_PORT_RX_SCO 16 +#define SLAVE_SB_PGD_PORT_RX_A2P 17 + +enum { + QCA_CHEROKEE_SOC_ID_0200 = 0x40010200, + QCA_CHEROKEE_SOC_ID_0201 = 0x40010201, + QCA_CHEROKEE_SOC_ID_0210 = 0x40010214, + QCA_CHEROKEE_SOC_ID_0211 = 0x40010224, + QCA_CHEROKEE_SOC_ID_0310 = 0x40010310, + QCA_CHEROKEE_SOC_ID_0320 = 0x40010320, + QCA_CHEROKEE_SOC_ID_0320_UMC = 0x40014320, +}; + +enum { + QCA_APACHE_SOC_ID_0100 = 0x40020120, + QCA_APACHE_SOC_ID_0110 = 0x40020130, + QCA_APACHE_SOC_ID_0120 = 0x40020140, + QCA_APACHE_SOC_ID_0121 = 0x40020150, +}; + +enum { + QCA_COMANCHE_SOC_ID_0101 = 0x40070101, + QCA_COMANCHE_SOC_ID_0110 = 0x40070110, + QCA_COMANCHE_SOC_ID_0120 = 0x40070120, + QCA_COMANCHE_SOC_ID_0130 = 0x40070130, + QCA_COMANCHE_SOC_ID_4130 = 0x40074130, + QCA_COMANCHE_SOC_ID_5120 = 0x40075120, + QCA_COMANCHE_SOC_ID_5130 = 0x40075130, +}; + +enum { + QCA_HASTINGS_SOC_ID_0200 = 0x400A0200, +}; + +enum { + QCA_HSP_SOC_ID_0100 = 0x400C0100, + QCA_HSP_SOC_ID_0110 = 0x400C0110, + QCA_HSP_SOC_ID_0200 = 0x400C0200, + QCA_HSP_SOC_ID_0210 = 0x400C0210, + QCA_HSP_SOC_ID_1201 = 0x400C1201, + QCA_HSP_SOC_ID_1211 = 0x400C1211, +}; + +enum { + QCA_MOSELLE_SOC_ID_0100 = 0x40140100, + QCA_MOSELLE_SOC_ID_0110 = 0x40140110, +}; + +/* Function Prototype */ + +/* + * btfm_slim_slave_hw_init: Initialize slave specific slimbus slave device + * @btfmslim: slimbus slave device data pointer. + * Returns: + * 0: Success + * else: Fail + */ +int btfm_slim_slave_hw_init(struct btfmslim *btfmslim); + +/* + * btfm_slim_slave_enable_rxport: Enable slave Rx port by given port number + * @btfmslim: slimbus slave device data pointer. + * @portNum: slimbus slave port number to enable + * @rxport: rxport or txport + * @enable: enable port or disable port + * Returns: + * 0: Success + * else: Fail + */ +int btfm_slim_slave_enable_port(struct btfmslim *btfmslim, uint8_t portNum, + uint8_t rxport, uint8_t enable); + +/* Specific defines for slave slimbus device */ +#define SLAVE_SLIM_REG_OFFSET 0x0800 + +#ifdef SLIM_SLAVE_REG_OFFSET +#undef SLIM_SLAVE_REG_OFFSET +#define SLIM_SLAVE_REG_OFFSET SLAVE_SLIM_REG_OFFSET +#endif + +/* Assign vendor specific function */ +extern struct btfmslim_ch slave_txport[]; +extern struct btfmslim_ch slave_rxport[]; + +#ifdef SLIM_SLAVE_RXPORT +#undef SLIM_SLAVE_RXPORT +#define SLIM_SLAVE_RXPORT (&slave_rxport[0]) +#endif + +#ifdef SLIM_SLAVE_TXPORT +#undef SLIM_SLAVE_TXPORT +#define SLIM_SLAVE_TXPORT (&slave_txport[0]) +#endif + +#ifdef SLIM_SLAVE_INIT +#undef SLIM_SLAVE_INIT +#define SLIM_SLAVE_INIT btfm_slim_slave_hw_init +#endif + +#ifdef SLIM_SLAVE_PORT_EN +#undef SLIM_SLAVE_PORT_EN +#define SLIM_SLAVE_PORT_EN btfm_slim_slave_enable_port +#endif +#endif From cc92023f48768c7bfba04609a4e5580c85277db8 Mon Sep 17 00:00:00 2001 From: satish kumar sugasi Date: Thu, 2 Dec 2021 15:51:46 -0800 Subject: [PATCH 003/154] BT: Add support for kalama target Adds voltage regulators info needed for powering on BT chipset. Change-Id: I5f281c88b3f94a9899396ad38b81f2970e91a054 Signed-off-by: satish kumar sugasi --- pwr/btpower.c | 145 ++++++++++++++++++++++++++++++-------- slimbus/btfm_slim.c | 38 ++++++++++ slimbus/btfm_slim_codec.c | 6 ++ slimbus/btfm_slim_slave.h | 6 ++ 4 files changed, 164 insertions(+), 31 deletions(-) diff --git a/pwr/btpower.c b/pwr/btpower.c index 199420a5db..57947bf7b8 100644 --- a/pwr/btpower.c +++ b/pwr/btpower.c @@ -25,10 +25,7 @@ #include #include #include "btpower.h" - -#if defined CONFIG_BT_SLIM_QCA6390 || \ - defined CONFIG_BT_SLIM_QCA6490 || \ - defined CONFIG_BTFM_SLIM_WCN3990 +#if (defined CONFIG_BT_SLIM) #include "btfm_slim.h" #endif #include @@ -92,11 +89,32 @@ enum power_src_pos { BT_VDD_IO_LDO_CURRENT, BT_VDD_LDO_CURRENT, BT_VDD_RFA_0p8_CURRENT, - BT_VDD_RFACMN_CURRENT + BT_VDD_RFACMN_CURRENT, + BT_VDD_IPA_2p2, + BT_VDD_IPA_2p2_CURRENT, + /* The below bucks are voted for HW WAR on some platform which supports + * WNC39xx. + */ + BT_VDD_SMPS, + BT_VDD_SMPS_CURRENT, + /* New entries need to be added before PWR_SRC_SIZE. + * Its hold the max size of power sources states. + */ + BT_POWER_SRC_SIZE, }; -// Regulator structure for QCA6390 and QCA6490 BT SoC series -static struct bt_power_vreg_data bt_vregs_info_qca6x9x[] = { +// Regulator structure for QCA6174/QCA9377/QCA9379 BT SoC series +static struct bt_power_vreg_data bt_vregs_info_qca61x4_937x[] = { + {NULL, "qcom,bt-vdd-aon", 928000, 928000, 0, false, false, + {BT_VDD_AON_LDO, BT_VDD_AON_LDO_CURRENT}}, + {NULL, "qcom,bt-vdd-io", 1710000, 3460000, 0, false, false, + {BT_VDD_IO_LDO, BT_VDD_IO_LDO_CURRENT}}, + {NULL, "qcom,bt-vdd-core", 3135000, 3465000, 0, false, false, + {BT_VDD_CORE_LDO, BT_VDD_CORE_LDO_CURRENT}}, +}; + +// Regulator structure for QCA6390,QCA6490 and WCN6750 BT SoC series +static struct bt_power_vreg_data bt_vregs_info_qca6xx0[] = { {NULL, "qcom,bt-vdd-io", 1800000, 1800000, 0, false, true, {BT_VDD_IO_LDO, BT_VDD_IO_LDO_CURRENT}}, {NULL, "qcom,bt-vdd-aon", 966000, 966000, 0, false, true, @@ -114,12 +132,36 @@ static struct bt_power_vreg_data bt_vregs_info_qca6x9x[] = { {BT_VDD_RFA2_LDO, BT_VDD_RFA2_LDO_CURRENT}}, {NULL, "qcom,bt-vdd-asd", 2800000, 2800000, 0, false, true, {BT_VDD_ASD_LDO, BT_VDD_ASD_LDO_CURRENT}}, + {NULL, "qcom,bt-vdd-ipa-2p2", 2200000, 2210000, 0, false, true, + {BT_VDD_IPA_2p2, BT_VDD_IPA_2p2_CURRENT}}, +}; + + +// Regulator structure for kiwi BT SoC series +static struct bt_power_vreg_data bt_vregs_info_kiwi[] = { + {NULL, "qcom,bt-vdd-io", 1800000, 1800000, 0, false, true, + {BT_VDD_IO_LDO, BT_VDD_IO_LDO_CURRENT}}, + {NULL, "qcom,bt-vdd-aon", 950000, 950000, 0, false, true, + {BT_VDD_AON_LDO, BT_VDD_AON_LDO_CURRENT}}, + {NULL, "qcom,bt-vdd-rfacmn", 950000, 950000, 0, false, true, + {BT_VDD_RFACMN, BT_VDD_RFACMN_CURRENT}}, + /* BT_CX_MX */ + {NULL, "qcom,bt-vdd-dig", 950000, 950000, 0, false, true, + {BT_VDD_DIG_LDO, BT_VDD_DIG_LDO_CURRENT}}, + {NULL, "qcom,bt-vdd-rfa-0p8", 950000, 952000, 0, false, true, + {BT_VDD_RFA_0p8, BT_VDD_RFA_0p8_CURRENT}}, + {NULL, "qcom,bt-vdd-rfa1", 1350000, 1350000, 0, false, true, + {BT_VDD_RFA1_LDO, BT_VDD_RFA1_LDO_CURRENT}}, + {NULL, "qcom,bt-vdd-rfa2", 1900000, 1900000, 0, false, true, + {BT_VDD_RFA2_LDO, BT_VDD_RFA2_LDO_CURRENT}}, }; // Regulator structure for WCN399x BT SoC series static struct bt_power bt_vreg_info_wcn399x = { .compatible = "qcom,wcn3990", .vregs = (struct bt_power_vreg_data []) { + {NULL, "qcom,bt-vdd-smps", 984000, 984000, 0, false, false, + {BT_VDD_SMPS, BT_VDD_SMPS_CURRENT}}, {NULL, "qcom,bt-vdd-io", 1700000, 1900000, 0, false, false, {BT_VDD_IO_LDO, BT_VDD_IO_LDO_CURRENT}}, {NULL, "qcom,bt-vdd-core", 1304000, 1304000, 0, false, false, @@ -129,26 +171,47 @@ static struct bt_power bt_vreg_info_wcn399x = { {NULL, "qcom,bt-vdd-xtal", 1700000, 1900000, 0, false, false, {BT_VDD_XTAL_LDO, BT_VDD_XTAL_LDO_CURRENT}}, }, - .num_vregs = 4, + .num_vregs = 5, +}; + +static struct bt_power bt_vreg_info_qca6174 = { + .compatible = "qcom,qca6174", + .vregs = bt_vregs_info_qca61x4_937x, + .num_vregs = ARRAY_SIZE(bt_vregs_info_qca61x4_937x), + + +static struct bt_power bt_vreg_info_kiwi = { + .compatible = "qcom,kiwi", + .vregs = bt_vregs_info_kiwi, + .num_vregs = ARRAY_SIZE(bt_vregs_info_kiwi), }; static struct bt_power bt_vreg_info_qca6390 = { .compatible = "qcom,qca6390", - .vregs = bt_vregs_info_qca6x9x, - .num_vregs = ARRAY_SIZE(bt_vregs_info_qca6x9x), + .vregs = bt_vregs_info_qca6xx0, + .num_vregs = ARRAY_SIZE(bt_vregs_info_qca6xx0), }; static struct bt_power bt_vreg_info_qca6490 = { .compatible = "qcom,qca6490", - .vregs = bt_vregs_info_qca6x9x, - .num_vregs = ARRAY_SIZE(bt_vregs_info_qca6x9x), + .vregs = bt_vregs_info_qca6xx0, + .num_vregs = ARRAY_SIZE(bt_vregs_info_qca6xx0), +}; + + +static struct bt_power bt_vreg_info_wcn6750 = { + .compatible = "qcom,wcn6750-bt", + .vregs = bt_vregs_info_qca6xx0, + .num_vregs = ARRAY_SIZE(bt_vregs_info_qca6xx0), }; static const struct of_device_id bt_power_match_table[] = { - { .compatible = "qcom,qca6174" }, + { .compatible = "qcom,qca6174", .data = &bt_vreg_info_qca6174}, { .compatible = "qcom,wcn3990", .data = &bt_vreg_info_wcn399x}, { .compatible = "qcom,qca6390", .data = &bt_vreg_info_qca6390}, { .compatible = "qcom,qca6490", .data = &bt_vreg_info_qca6490}, + { .compatible = "qcom,kiwi", .data = &bt_vreg_info_kiwi}, + { .compatible = "qcom,wcn6750-bt", .data = &bt_vreg_info_wcn6750}, {}, }; @@ -194,7 +257,7 @@ static int bt_vreg_enable(struct bt_power_vreg_data *vreg) rc = regulator_enable(vreg->reg); if (rc < 0) { - pr_err("regulator_enable(%s) failed. rc=%d\n", + pr_err("%s: regulator_enable(%s) failed. rc=%d\n", __func__, vreg->name, rc); goto out; } @@ -374,6 +437,9 @@ static int bt_configure_gpios(int on) return rc; } + pr_info("BTON:Turn Bt OFF asserting BT_EN to low\n"); + pr_info("bt-reset-gpio(%d) value(%d)\n", bt_reset_gpio, + gpio_get_value(bt_reset_gpio)); rc = gpio_direction_output(bt_reset_gpio, 0); if (rc) { pr_err("%s: Unable to set direction\n", __func__); @@ -382,25 +448,26 @@ static int bt_configure_gpios(int on) bt_power_src_status[BT_RESET_GPIO] = gpio_get_value(bt_reset_gpio); msleep(50); - pr_info("BTON:Turn Bt Off bt-reset-gpio(%d) value(%d)\n", - bt_reset_gpio, gpio_get_value(bt_reset_gpio)); + pr_info("BTON:Turn Bt OFF post asserting BT_EN to low\n"); + pr_info("bt-reset-gpio(%d) value(%d)\n", bt_reset_gpio, + gpio_get_value(bt_reset_gpio)); + if (bt_sw_ctrl_gpio >= 0) { - pr_info("BTON:Turn Bt Off\n"); bt_power_src_status[BT_SW_CTRL_GPIO] = gpio_get_value(bt_sw_ctrl_gpio); - pr_info("bt-sw-ctrl-gpio(%d) value(%d)\n", + pr_info("BTON:Turn Bt OFF bt-sw-ctrl-gpio(%d) value(%d)\n", bt_sw_ctrl_gpio, bt_power_src_status[BT_SW_CTRL_GPIO]); } if (wl_reset_gpio >= 0) - pr_info("BTON:Turn Bt On wl-reset-gpio(%d) value(%d)\n", + pr_info("BTON:Turn Bt ON wl-reset-gpio(%d) value(%d)\n", wl_reset_gpio, gpio_get_value(wl_reset_gpio)); if ((wl_reset_gpio < 0) || ((wl_reset_gpio >= 0) && gpio_get_value(wl_reset_gpio))) { btpower_set_xo_clk_gpio_state(true); - pr_info("%s: BTON: Asserting BT_EN\n", __func__); + pr_info("BTON: WLAN ON Asserting BT_EN to high\n"); rc = gpio_direction_output(bt_reset_gpio, 1); if (rc) { pr_err("%s: Unable to set direction\n", __func__); @@ -412,19 +479,21 @@ static int bt_configure_gpios(int on) } if ((wl_reset_gpio >= 0) && (gpio_get_value(wl_reset_gpio) == 0)) { if (gpio_get_value(bt_reset_gpio)) { - pr_info("%s: Wlan Off and BT On too close\n", __func__); - pr_info("%s: reset BT_EN, enable it after delay\n", __func__); + pr_info("BTON: WLAN OFF and BT ON are too close\n"); + pr_info("reset BT_EN, enable it after delay\n"); rc = gpio_direction_output(bt_reset_gpio, 0); if (rc) { - pr_err("%s: Unable to set direction\n", __func__); + pr_err("%s: Unable to set direction\n", + __func__); return rc; } bt_power_src_status[BT_RESET_GPIO] = gpio_get_value(bt_reset_gpio); } - pr_info("%s:add 100ms delay for AON output to fully discharge\n", - __func__); + pr_info("BTON: WLAN OFF waiting for 100ms delay\n"); + pr_info("for AON output to fully discharge\n"); msleep(100); + pr_info("BTON: WLAN OFF Asserting BT_EN to high\n"); btpower_set_xo_clk_gpio_state(true); rc = gpio_direction_output(bt_reset_gpio, 1); if (rc) { @@ -435,6 +504,23 @@ static int bt_configure_gpios(int on) gpio_get_value(bt_reset_gpio); btpower_set_xo_clk_gpio_state(false); } + /* Below block of code executes if WL_EN is pulled high when + * BT_EN is about to pull high. so above two if conditions are + * not executed. + */ + if (!gpio_get_value(bt_reset_gpio)) { + btpower_set_xo_clk_gpio_state(true); + pr_info("BTON: WLAN ON and BT ON are too close\n"); + pr_info("Asserting BT_EN to high\n"); + rc = gpio_direction_output(bt_reset_gpio, 1); + if (rc) { + pr_err("%s: Unable to set direction\n", __func__); + return rc; + } + bt_power_src_status[BT_RESET_GPIO] = + gpio_get_value(bt_reset_gpio); + btpower_set_xo_clk_gpio_state(false); + } msleep(50); /* Check if SW_CTRL is asserted */ if (bt_sw_ctrl_gpio >= 0) { @@ -462,10 +548,9 @@ static int bt_configure_gpios(int on) pr_info("BTON:Turn Bt On bt-reset-gpio(%d) value(%d)\n", bt_reset_gpio, gpio_get_value(bt_reset_gpio)); if (bt_sw_ctrl_gpio >= 0) { - pr_info("BTON:Turn Bt On\n"); bt_power_src_status[BT_SW_CTRL_GPIO] = gpio_get_value(bt_sw_ctrl_gpio); - pr_info("bt-sw-ctrl-gpio(%d) value(%d)\n", + pr_info("BTON: Turn BT ON bt-sw-ctrl-gpio(%d) value(%d)\n", bt_sw_ctrl_gpio, bt_power_src_status[BT_SW_CTRL_GPIO]); } @@ -957,7 +1042,7 @@ static void set_pwr_srcs_status(struct bt_power_vreg_data *handle) (regulator_is_enabled(handle->reg))) { bt_power_src_status[ldo_index] = (int)regulator_get_voltage(handle->reg); - pr_err("%s(%d) value(%d)\n", handle->name, + pr_err("%s(%p) value(%d)\n", handle->name, handle, bt_power_src_status[ldo_index]); } else { pr_err("%s:%s is_enabled: %d\n", @@ -997,9 +1082,7 @@ static long bt_ioctl(struct file *file, unsigned int cmd, unsigned long arg) switch (cmd) { case BT_CMD_SLIM_TEST: -#if (defined CONFIG_BT_SLIM_QCA6390 || \ - defined CONFIG_BT_SLIM_QCA6490 || \ - defined CONFIG_BTFM_SLIM_WCN3990) +#if (defined CONFIG_BT_SLIM) if (!bt_power_pdata->slim_dev) { pr_err("%s: slim_dev is null\n", __func__); return -EINVAL; diff --git a/slimbus/btfm_slim.c b/slimbus/btfm_slim.c index d855f5f1db..c0dfd35411 100644 --- a/slimbus/btfm_slim.c +++ b/slimbus/btfm_slim.c @@ -27,6 +27,7 @@ #ifdef CONFIG_SLIMBUS static bool btfm_is_port_opening_delayed = true; +static int btfm_num_ports_open; #endif int btfm_slim_write(struct btfmslim *btfmslim, @@ -183,7 +184,11 @@ int btfm_slim_enable_ch(struct btfmslim *btfmslim, struct btfmslim_ch *ch, BTFMSLIM_ERR("slim_stream_enable failed = %d", ret); goto error; } + + if (ret == 0) + btfm_num_ports_open++; error: + BTFMSLIM_INFO("btfm_num_ports_open: %d", btfm_num_ports_open); kfree(chan->dai.sconfig.chs); return ret; } @@ -224,6 +229,10 @@ int btfm_slim_disable_ch(struct btfmslim *btfmslim, struct btfmslim_ch *ch, } ch->dai.sconfig.port_mask = 0; kfree(ch->dai.sconfig.chs); + + if (btfm_num_ports_open > 0) + btfm_num_ports_open--; + BTFMSLIM_INFO("btfm_num_ports_open: %d", btfm_num_ports_open); return ret; } @@ -354,6 +363,27 @@ int btfm_slim_hw_init(struct btfmslim *btfmslim) slim_ifd->e_addr.dev_index = 0x0; slim_ifd->e_addr.instance = 0x0; slim_ifd->laddr = 0x0; + } else if (chipset_ver == QCA_HAMILTON_SOC_ID_0100 || + chipset_ver == QCA_HAMILTON_SOC_ID_0101 || + chipset_ver == QCA_HAMILTON_SOC_ID_0200) { + BTFMSLIM_INFO("chipset is Hamliton, overwriting EA"); + slim->is_laddr_valid = false; + slim->e_addr.manf_id = SLIM_MANF_ID_QCOM; + slim->e_addr.prod_code = 0x220; + slim->e_addr.dev_index = 0x01; + slim->e_addr.instance = 0x0; + /* we are doing this to indicate that this is not a child node + * (doesn't have call back functions). Needed only for querying + * logical address. + */ + slim_ifd->dev.driver = NULL; + slim_ifd->ctrl = btfmslim->slim_pgd->ctrl; //slimbus controller structure. + slim_ifd->is_laddr_valid = false; + slim_ifd->e_addr.manf_id = SLIM_MANF_ID_QCOM; + slim_ifd->e_addr.prod_code = 0x220; + slim_ifd->e_addr.dev_index = 0x0; + slim_ifd->e_addr.instance = 0x0; + slim_ifd->laddr = 0x0; } BTFMSLIM_INFO( "PGD Enum Addr: manu id:%.02x prod code:%.02x dev idx:%.02x instance:%.02x", @@ -365,6 +395,14 @@ int btfm_slim_hw_init(struct btfmslim *btfmslim) slim_ifd->e_addr.manf_id, slim_ifd->e_addr.prod_code, slim_ifd->e_addr.dev_index, slim_ifd->e_addr.instance); + if (btfm_num_ports_open == 0 && (chipset_ver == QCA_HSP_SOC_ID_0200 || + chipset_ver == QCA_HSP_SOC_ID_0210 || + chipset_ver == QCA_HSP_SOC_ID_1201 || + chipset_ver == QCA_HSP_SOC_ID_1211)) { + BTFMSLIM_INFO("SB reset needed before getting LA, sleeping"); + msleep(DELAY_FOR_PORT_OPEN_MS); + } + /* Assign Logical Address for PGD (Ported Generic Device) * enumeration address */ diff --git a/slimbus/btfm_slim_codec.c b/slimbus/btfm_slim_codec.c index fc529e3d0c..bb1a10dd28 100644 --- a/slimbus/btfm_slim_codec.c +++ b/slimbus/btfm_slim_codec.c @@ -14,6 +14,7 @@ #include #include #include +#include #include #include #include @@ -223,6 +224,11 @@ static int btfm_slim_dai_prepare(struct snd_pcm_substream *substream, /* save the enable channel status */ if (ret == 0) bt_soc_enable_status = 1; + + if (ret == -EISCONN) { + BTFMSLIM_ERR("channel opened without closing, returning success"); + ret = 0; + } return ret; } diff --git a/slimbus/btfm_slim_slave.h b/slimbus/btfm_slim_slave.h index 0c1d1ff07e..b9e1e647be 100644 --- a/slimbus/btfm_slim_slave.h +++ b/slimbus/btfm_slim_slave.h @@ -122,6 +122,12 @@ enum { QCA_MOSELLE_SOC_ID_0110 = 0x40140110, }; +enum { + QCA_HAMILTON_SOC_ID_0100 = 0x40170100, + QCA_HAMILTON_SOC_ID_0101 = 0x40170101, + QCA_HAMILTON_SOC_ID_0200 = 0x40170200, +}; + /* Function Prototype */ /* From 1d6e351ae8d688e3f67f210d2442dcf4e5b9ed92 Mon Sep 17 00:00:00 2001 From: satish kumar sugasi Date: Tue, 18 Jan 2022 16:52:37 -0800 Subject: [PATCH 004/154] BT: Check slimbus configuration enabled or not Disable BTFM slimbus driver if core slimbus disabled. Change-Id: I6bcbe037181021d4449f345a81d257a2bc2deab6 --- Android.mk | 2 ++ include/btpower.h | 3 --- pwr/btpower.c | 12 ++++++------ slimbus/btfm_slim.c | 12 ------------ slimbus/btfm_slim_codec.c | 2 -- 5 files changed, 8 insertions(+), 23 deletions(-) diff --git a/Android.mk b/Android.mk index 663d29dcf7..e96f13d675 100644 --- a/Android.mk +++ b/Android.mk @@ -6,7 +6,9 @@ LOCAL_PATH := $(call my-dir) ifeq ($(call is-board-platform-in-list,taro kalama), true) BT_SELECT := CONFIG_MSM_BT_POWER=m +ifdef CONFIG_SLIMBUS BT_SELECT += CONFIG_BTFM_SLIM=m +endif BT_SELECT += CONFIG_I2C_RTC6226_QCA=m LOCAL_PATH := $(call my-dir) diff --git a/include/btpower.h b/include/btpower.h index 3141862402..2db3697007 100644 --- a/include/btpower.h +++ b/include/btpower.h @@ -82,7 +82,4 @@ int btpower_aop_mbox_init(struct btpower_platform_data *pdata); #define BT_CMD_GETVAL_POWER_SRCS 0xbfb1 #define BT_CMD_SET_IPA_TCS_INFO 0xbfc0 -/* total number of power src */ -#define BT_POWER_SRC_SIZE 28 - #endif /* __LINUX_BLUETOOTH_POWER_H */ diff --git a/pwr/btpower.c b/pwr/btpower.c index 57947bf7b8..ad29bc7014 100644 --- a/pwr/btpower.c +++ b/pwr/btpower.c @@ -178,12 +178,6 @@ static struct bt_power bt_vreg_info_qca6174 = { .compatible = "qcom,qca6174", .vregs = bt_vregs_info_qca61x4_937x, .num_vregs = ARRAY_SIZE(bt_vregs_info_qca61x4_937x), - - -static struct bt_power bt_vreg_info_kiwi = { - .compatible = "qcom,kiwi", - .vregs = bt_vregs_info_kiwi, - .num_vregs = ARRAY_SIZE(bt_vregs_info_kiwi), }; static struct bt_power bt_vreg_info_qca6390 = { @@ -198,6 +192,12 @@ static struct bt_power bt_vreg_info_qca6490 = { .num_vregs = ARRAY_SIZE(bt_vregs_info_qca6xx0), }; +static struct bt_power bt_vreg_info_kiwi = { + .compatible = "qcom,kiwi", + .vregs = bt_vregs_info_kiwi, + .num_vregs = ARRAY_SIZE(bt_vregs_info_kiwi), +}; + static struct bt_power bt_vreg_info_wcn6750 = { .compatible = "qcom,wcn6750-bt", diff --git a/slimbus/btfm_slim.c b/slimbus/btfm_slim.c index c0dfd35411..b0d8d825b8 100644 --- a/slimbus/btfm_slim.c +++ b/slimbus/btfm_slim.c @@ -25,16 +25,13 @@ #define SLIM_MANF_ID_QCOM 0x217 #define SLIM_PROD_CODE 0x221 -#ifdef CONFIG_SLIMBUS static bool btfm_is_port_opening_delayed = true; static int btfm_num_ports_open; -#endif int btfm_slim_write(struct btfmslim *btfmslim, uint16_t reg, uint8_t reg_val, uint8_t pgd) { int ret = -1; -#ifdef CONFIG_SLIMBUS uint32_t reg_addr; int slim_write_tries = SLIM_SLAVE_RW_MAX_TRIES; @@ -60,14 +57,12 @@ int btfm_slim_write(struct btfmslim *btfmslim, BTFMSLIM_DBG("retrying to Write 0x%02x to reg 0x%x ret %d", reg_val, reg_addr, ret); } -#endif return ret; } int btfm_slim_read(struct btfmslim *btfmslim, uint32_t reg, uint8_t pgd) { int ret = -1; -#ifdef CONFIG_SLIMBUS int slim_read_tries = SLIM_SLAVE_RW_MAX_TRIES; uint32_t reg_addr; BTFMSLIM_DBG("Read from %s", pgd?"PGD":"IFD"); @@ -84,11 +79,9 @@ int btfm_slim_read(struct btfmslim *btfmslim, uint32_t reg, uint8_t pgd) break; usleep_range(5000, 5100); } -#endif return ret; } -#ifdef CONFIG_SLIMBUS static bool btfm_slim_is_sb_reset_needed(int chip_ver) { switch (chip_ver) { @@ -455,20 +448,17 @@ int btfm_slim_hw_deinit(struct btfmslim *btfmslim) mutex_unlock(&btfmslim->io_lock); return ret; } -#endif static int btfm_slim_status(struct slim_device *sdev, enum slim_device_status status) { int ret = 0; -#ifdef CONFIG_SLIMBUS struct device *dev = &sdev->dev; struct btfmslim *btfm_slim; btfm_slim = dev_get_drvdata(dev); ret = btfm_slim_register_codec(btfm_slim); if (ret) BTFMSLIM_ERR("error, registering slimbus codec failed"); -#endif return ret; } @@ -562,8 +552,6 @@ static struct slim_driver btfm_slim_driver = { .id_table = btfm_slim_id }; -#ifdef CONFIG_SLIMBUS module_slim_driver(btfm_slim_driver); -#endif MODULE_LICENSE("GPL v2"); MODULE_DESCRIPTION("BTFM Slimbus Slave driver"); diff --git a/slimbus/btfm_slim_codec.c b/slimbus/btfm_slim_codec.c index bb1a10dd28..665d2b28b7 100644 --- a/slimbus/btfm_slim_codec.c +++ b/slimbus/btfm_slim_codec.c @@ -25,7 +25,6 @@ static int bt_soc_enable_status; int btfm_feedback_ch_setting; -#ifdef CONFIG_SLIMBUS static int btfm_slim_codec_write(struct snd_soc_component *codec, unsigned int reg, unsigned int value) { @@ -458,7 +457,6 @@ void btfm_slim_unregister_codec(struct device *dev) /* Unregister Codec driver */ snd_soc_unregister_component(dev); } -#endif MODULE_DESCRIPTION("BTFM Slimbus Codec driver"); MODULE_LICENSE("GPL v2"); From 2f0eff54eda3d25279fa56362a539298d18fb313 Mon Sep 17 00:00:00 2001 From: Balakrishna Godavarthi Date: Tue, 11 Jan 2022 20:26:10 +0530 Subject: [PATCH 005/154] Add out of band sleep support to bluetooth driver This change adds out of band sleep support to bluetooth power driver. This feature will be enabled when macro CONFIG_MSM_BT_OOBS is defined. Change-Id: I74b231956ad0884528b17720cbfa3639281af9a3 --- include/btpower.h | 15 ++++++ pwr/btpower.c | 121 ++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 136 insertions(+) diff --git a/include/btpower.h b/include/btpower.h index 2db3697007..f3befbd397 100644 --- a/include/btpower.h +++ b/include/btpower.h @@ -7,6 +7,7 @@ #ifndef __LINUX_BLUETOOTH_POWER_H #define __LINUX_BLUETOOTH_POWER_H +#include #include #include #include @@ -58,6 +59,11 @@ struct btpower_platform_data { int wl_gpio_sys_rst; /* Wlan reset gpio */ int bt_gpio_sw_ctrl; /* Bluetooth sw_ctrl gpio */ int bt_gpio_debug; /* Bluetooth debug gpio */ +#ifdef CONFIG_MSM_BT_OOBS + int bt_gpio_dev_wake; /* Bluetooth bt_wake */ + int bt_gpio_host_wake; /* Bluetooth bt_host_wake */ + int irq; /* Bluetooth host_wake IRQ */ +#endif int xo_gpio_clk; /* XO clock gpio*/ struct device *slim_dev; struct bt_power_vreg_data *vreg_info; /* VDDIO voltage regulator */ @@ -68,6 +74,10 @@ struct btpower_platform_data { struct mbox_client mbox_client_data; struct mbox_chan *mbox_chan; const char *vreg_ipa; +#ifdef CONFIG_MSM_BT_OOBS + struct file *reffilp_obs; + struct task_struct *reftask_obs; +#endif }; int btpower_register_slimdev(struct device *dev); @@ -82,4 +92,9 @@ int btpower_aop_mbox_init(struct btpower_platform_data *pdata); #define BT_CMD_GETVAL_POWER_SRCS 0xbfb1 #define BT_CMD_SET_IPA_TCS_INFO 0xbfc0 +#ifdef CONFIG_MSM_BT_OOBS +#define BT_CMD_OBS_SIGNAL_TASK 0xbfd0 +#define BT_CMD_OBS_VOTE_CLOCK 0xbfd1 +#endif + #endif /* __LINUX_BLUETOOTH_POWER_H */ diff --git a/pwr/btpower.c b/pwr/btpower.c index ad29bc7014..45bf9ddc3a 100644 --- a/pwr/btpower.c +++ b/pwr/btpower.c @@ -227,6 +227,42 @@ static int bt_major; static int soc_id; static bool probe_finished; +#ifdef CONFIG_MSM_BT_OOBS +static void btpower_uart_transport_locked(struct btpower_platform_data *drvdata, + bool locked) +{ + pr_debug("%s: %s\n", __func__, (locked ? "busy" : "idle")); +} + +static irqreturn_t btpower_host_wake_isr(int irq, void *data) +{ + struct btpower_platform_data *drvdata = data; + int host_waking = gpio_get_value(drvdata->bt_gpio_host_wake); + struct kernel_siginfo siginfo; + int rc = 0; + + pr_debug("%s: bt-hostwake-gpio(%d) IRQ(%d) value(%d)\n", __func__, + drvdata->bt_gpio_host_wake, drvdata->irq, host_waking); + + if (drvdata->reftask_obs == NULL) { + pr_info("%s: ignore BT-HOSTWAKE IRQ\n", __func__); + return IRQ_HANDLED; + } + + // Sending signal to HAL layer + memset(&siginfo, 0, sizeof(siginfo)); + siginfo.si_signo = SIGIO; + siginfo.si_code = SI_QUEUE; + siginfo.si_int = host_waking; + rc = send_sig_info(siginfo.si_signo, &siginfo, drvdata->reftask_obs); + if (rc < 0) { + pr_err("%s: failed (%d) to send SIG to HAL(%d)\n", __func__, + rc, drvdata->reftask_obs->pid); + } + return IRQ_HANDLED; +} +#endif + static int bt_vreg_enable(struct bt_power_vreg_data *vreg) { int rc = 0; @@ -420,6 +456,47 @@ retry_gpio_req: gpio_free(xo_clk_gpio); } +#ifdef CONFIG_MSM_BT_OOBS +void bt_configure_wakeup_gpios(int on) +{ + int bt_gpio_dev_wake = bt_power_pdata->bt_gpio_dev_wake; + int bt_host_wake_gpio = bt_power_pdata->bt_gpio_host_wake; + int rc; + + if (on) { + if (gpio_is_valid(bt_gpio_dev_wake)) { + gpio_set_value(bt_gpio_dev_wake, 1); + pr_debug("%s: BT-ON asserting BT_WAKE(%d)\n", __func__, + bt_gpio_dev_wake); + } + + if (gpio_is_valid(bt_host_wake_gpio)) { + bt_power_pdata->irq = gpio_to_irq(bt_host_wake_gpio); + pr_debug("%s: BT-ON bt-host_wake-gpio(%d) IRQ(%d)\n", + __func__, bt_host_wake_gpio, bt_power_pdata->irq); + rc = request_irq(bt_power_pdata->irq, + btpower_host_wake_isr, + IRQF_TRIGGER_FALLING | + IRQF_TRIGGER_RISING, + "btpower_hostwake_isr", bt_power_pdata); + if (rc) + pr_err("%s: unable to request IRQ %d (%d)\n", + __func__, bt_host_wake_gpio, rc); + } + } else { + if (gpio_is_valid(bt_host_wake_gpio)) { + pr_debug("%s: BT-OFF bt-hostwake-gpio(%d) IRQ(%d) value(%d)\n", + __func__, bt_host_wake_gpio, bt_power_pdata->irq, + gpio_get_value(bt_host_wake_gpio)); + free_irq(bt_power_pdata->irq, bt_power_pdata); + } + + if (gpio_is_valid(bt_gpio_dev_wake)) + gpio_set_value(bt_gpio_dev_wake, 0); + } +} +#endif + static int bt_configure_gpios(int on) { int rc = 0; @@ -522,6 +599,9 @@ static int bt_configure_gpios(int on) btpower_set_xo_clk_gpio_state(false); } msleep(50); +#ifdef CONFIG_MSM_BT_OOBS + bt_configure_wakeup_gpios(on); +#endif /* Check if SW_CTRL is asserted */ if (bt_sw_ctrl_gpio >= 0) { rc = gpio_direction_input(bt_sw_ctrl_gpio); @@ -555,6 +635,9 @@ static int bt_configure_gpios(int on) bt_power_src_status[BT_SW_CTRL_GPIO]); } } else { +#ifdef CONFIG_MSM_BT_OOBS + bt_configure_wakeup_gpios(on); +#endif gpio_set_value(bt_reset_gpio, 0); msleep(100); pr_info("BT-OFF:bt-reset-gpio(%d) value(%d)\n", @@ -934,6 +1017,22 @@ static int bt_power_populate_dt_pinfo(struct platform_device *pdev) if (rc < 0) pr_warn("%s: clock not provided in device tree\n", __func__); +#ifdef CONFIG_MSM_BT_OOBS + bt_power_pdata->bt_gpio_dev_wake = + of_get_named_gpio(pdev->dev.of_node, + "qcom,btwake_gpio", 0); + if (bt_power_pdata->bt_gpio_dev_wake < 0) + pr_warn("%s: btwake-gpio not provided in device tree\n", + __func__); + + + bt_power_pdata->bt_gpio_host_wake = + of_get_named_gpio(pdev->dev.of_node, + "qcom,bthostwake_gpio", 0); + if (bt_power_pdata->bt_gpio_host_wake < 0) + pr_warn("%s: bthostwake_gpio not provided in device tree\n", + __func__); +#endif } bt_power_pdata->bt_power_setup = bluetooth_power; @@ -1081,6 +1180,28 @@ static long bt_ioctl(struct file *file, unsigned int cmd, unsigned long arg) } switch (cmd) { +#ifdef CONFIG_MSM_BT_OOBS + case BT_CMD_OBS_SIGNAL_TASK: + bt_power_pdata->reffilp_obs = file; + bt_power_pdata->reftask_obs = get_current(); + pr_info("%s: BT_CMD_OBS_SIGNAL_TASK tid %d filp %pK\n", + __func__, bt_power_pdata->reftask_obs->pid, file); + break; + case BT_CMD_OBS_VOTE_CLOCK: + if (!gpio_is_valid(bt_power_pdata->bt_gpio_dev_wake)) { + pr_warn("%s: BT_CMD_OBS_VOTE_CLOCK bt_dev_wake_n(%d) not configured\n", + __func__, bt_power_pdata->bt_gpio_dev_wake); + return -EIO; + } + pwr_cntrl = (int)arg; + btpower_uart_transport_locked(bt_power_pdata, (pwr_cntrl == 1 ? true : + false)); + gpio_set_value(bt_power_pdata->bt_gpio_dev_wake, pwr_cntrl); + pr_debug("%s: BT_CMD_OBS_VOTE_CLOCK cntrl(%d) %s\n", __func__, + pwr_cntrl, gpio_get_value(bt_power_pdata->bt_gpio_dev_wake) ? + "Assert" : "Deassert"); + break; +#endif case BT_CMD_SLIM_TEST: #if (defined CONFIG_BT_SLIM) if (!bt_power_pdata->slim_dev) { From e30db52d581b1b737861159fe3575fce3b5ffb3a Mon Sep 17 00:00:00 2001 From: Satish Kumar Kodishala Date: Thu, 6 Jan 2022 13:51:13 +0530 Subject: [PATCH 006/154] Add support for 192KHz sample rate Add support for 192KHz sample rate for Aptx Adaptive R3 CRs-Fixed: 3105454 Change-Id: Idfc5fd79e4cc3c1dfd5dffa9f3808ee53b481706 Signed-off-by: Satish Kumar Kodishala --- slimbus/btfm_slim_codec.c | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/slimbus/btfm_slim_codec.c b/slimbus/btfm_slim_codec.c index 665d2b28b7..59a3c0a0c3 100644 --- a/slimbus/btfm_slim_codec.c +++ b/slimbus/btfm_slim_codec.c @@ -378,7 +378,7 @@ static struct snd_soc_dai_driver btfmslim_dai[] = { }, .ops = &btfmslim_dai_ops, }, - { /* Bluetooth SCO voice uplink: bt -> modem */ + { /* Bluetooth SCO voice uplink: bt -> lpass */ .name = "btfm_bt_sco_slim_tx", .id = BTFM_BT_SCO_SLIM_TX, .capture = { @@ -386,16 +386,17 @@ static struct snd_soc_dai_driver btfmslim_dai[] = { /* 8 KHz or 16 KHz */ .rates = SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000 | SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000 - | SNDRV_PCM_RATE_88200 | SNDRV_PCM_RATE_96000, + | SNDRV_PCM_RATE_88200 | SNDRV_PCM_RATE_96000 + | SNDRV_PCM_RATE_192000, .formats = SNDRV_PCM_FMTBIT_S16_LE, /* 16 bits */ - .rate_max = 96000, + .rate_max = 192000, .rate_min = 8000, .channels_min = 1, .channels_max = 1, }, .ops = &btfmslim_dai_ops, }, - { /* Bluetooth SCO voice downlink: modem -> bt or A2DP Playback */ + { /* Bluetooth SCO voice downlink: lpass -> bt or A2DP Playback */ .name = "btfm_bt_sco_a2dp_slim_rx", .id = BTFM_BT_SCO_A2DP_SLIM_RX, .playback = { @@ -403,9 +404,10 @@ static struct snd_soc_dai_driver btfmslim_dai[] = { /* 8/16/44.1/48/88.2/96 Khz */ .rates = SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000 | SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000 - | SNDRV_PCM_RATE_88200 | SNDRV_PCM_RATE_96000, + | SNDRV_PCM_RATE_88200 | SNDRV_PCM_RATE_96000 + | SNDRV_PCM_RATE_192000, .formats = SNDRV_PCM_FMTBIT_S16_LE, /* 16 bits */ - .rate_max = 96000, + .rate_max = 192000, .rate_min = 8000, .channels_min = 1, .channels_max = 1, From 633df0b2edf7d0b175fdf8ced4c4132f2c1b3093 Mon Sep 17 00:00:00 2001 From: Girish BN Date: Thu, 27 Jan 2022 17:14:31 +0530 Subject: [PATCH 007/154] OOBS enanchment changes for Bluetooth Driver - Handling GPIO and UART clock throw State machine. Change-Id: I9b10b15f2150c51823e5eb670954d5b6a97a606e --- include/btpower.h | 14 ++++++++++++++ pwr/btpower.c | 42 ++++++++++++++++++++++++++++++++---------- 2 files changed, 46 insertions(+), 10 deletions(-) diff --git a/include/btpower.h b/include/btpower.h index f3befbd397..03c8451c43 100644 --- a/include/btpower.h +++ b/include/btpower.h @@ -95,6 +95,20 @@ int btpower_aop_mbox_init(struct btpower_platform_data *pdata); #ifdef CONFIG_MSM_BT_OOBS #define BT_CMD_OBS_SIGNAL_TASK 0xbfd0 #define BT_CMD_OBS_VOTE_CLOCK 0xbfd1 + +/** + * enum btpower_obs_param: OOBS low power param + * @BTPOWER_OBS_CLK_OFF: Transport bus is no longer acquired + * @BTPOWER_OBS_CLK_ON: Acquire transport bus for either transmitting or receiving + * @BTPOWER_OBS_DEV_OFF: Bluetooth is released because of no more transmission + * @BTPOWER_OBS_DEV_ON: Wake up the Bluetooth controller for transmission + */ +enum btpower_obs_param { + BTPOWER_OBS_CLK_OFF = 0, + BTPOWER_OBS_CLK_ON, + BTPOWER_OBS_DEV_OFF, + BTPOWER_OBS_DEV_ON, +}; #endif #endif /* __LINUX_BLUETOOTH_POWER_H */ diff --git a/pwr/btpower.c b/pwr/btpower.c index 45bf9ddc3a..9ab5b3abdf 100644 --- a/pwr/btpower.c +++ b/pwr/btpower.c @@ -1173,7 +1173,9 @@ static long bt_ioctl(struct file *file, unsigned int cmd, unsigned long arg) int chipset_version = 0; int itr, num_vregs; struct bt_power_vreg_data *vreg_info = NULL; - +#ifdef CONFIG_MSM_BT_OOBS + enum btpower_obs_param clk_cntrl; +#endif if (!bt_power_pdata || !probe_finished) { pr_err("%s: BTPower Probing Pending.Try Again\n", __func__); return -EAGAIN; @@ -1184,22 +1186,42 @@ static long bt_ioctl(struct file *file, unsigned int cmd, unsigned long arg) case BT_CMD_OBS_SIGNAL_TASK: bt_power_pdata->reffilp_obs = file; bt_power_pdata->reftask_obs = get_current(); - pr_info("%s: BT_CMD_OBS_SIGNAL_TASK tid %d filp %pK\n", + pr_info("%s: BT_CMD_OBS_SIGNAL_TASK tid %d file %pK\n", __func__, bt_power_pdata->reftask_obs->pid, file); break; case BT_CMD_OBS_VOTE_CLOCK: if (!gpio_is_valid(bt_power_pdata->bt_gpio_dev_wake)) { - pr_warn("%s: BT_CMD_OBS_VOTE_CLOCK bt_dev_wake_n(%d) not configured\n", + pr_debug("%s: BT_CMD_OBS_VOTE_CLOCK bt_dev_wake_n(%d) not configured\n", __func__, bt_power_pdata->bt_gpio_dev_wake); return -EIO; } - pwr_cntrl = (int)arg; - btpower_uart_transport_locked(bt_power_pdata, (pwr_cntrl == 1 ? true : - false)); - gpio_set_value(bt_power_pdata->bt_gpio_dev_wake, pwr_cntrl); - pr_debug("%s: BT_CMD_OBS_VOTE_CLOCK cntrl(%d) %s\n", __func__, - pwr_cntrl, gpio_get_value(bt_power_pdata->bt_gpio_dev_wake) ? - "Assert" : "Deassert"); + clk_cntrl = (enum btpower_obs_param)arg; + switch (clk_cntrl) { + case BTPOWER_OBS_CLK_OFF: + btpower_uart_transport_locked(bt_power_pdata, false); + ret = 0; + break; + case BTPOWER_OBS_CLK_ON: + btpower_uart_transport_locked(bt_power_pdata, true); + ret = 0; + break; + case BTPOWER_OBS_DEV_OFF: + gpio_set_value(bt_power_pdata->bt_gpio_dev_wake, 0); + ret = 0; + break; + case BTPOWER_OBS_DEV_ON: + gpio_set_value(bt_power_pdata->bt_gpio_dev_wake, 1); + ret = 0; + break; + default: + pr_debug("%s: BT_CMD_OBS_VOTE_CLOCK clk_cntrl(%d)\n", + __func__, clk_cntrl); + return -EINVAL; + } + pr_debug("%s: BT_CMD_OBS_VOTE_CLOCK clk_cntrl(%d) %s\n", + __func__, clk_cntrl, + gpio_get_value(bt_power_pdata->bt_gpio_dev_wake) ? + "Assert" : "Deassert"); break; #endif case BT_CMD_SLIM_TEST: From 88a332ba60f48731c9ec9481810ddcc3c84be7e2 Mon Sep 17 00:00:00 2001 From: satish kumar sugasi Date: Mon, 7 Feb 2022 23:58:48 -0800 Subject: [PATCH 008/154] btfm slimbus configuration change to enable Enable btfm slimbus slave configuration default if BT power driver enabled. Change-Id: Iea4ee82cd366c9fa5a0824b9277b9bb49e15b128 --- Android.mk | 4 ++-- bt_kernel_vendor_board.mk | 21 +++++++++++++++------ pwr/btpower.c | 6 +++--- slimbus/Kconfig | 1 - 4 files changed, 20 insertions(+), 12 deletions(-) diff --git a/Android.mk b/Android.mk index e96f13d675..5311caee7d 100644 --- a/Android.mk +++ b/Android.mk @@ -6,9 +6,9 @@ LOCAL_PATH := $(call my-dir) ifeq ($(call is-board-platform-in-list,taro kalama), true) BT_SELECT := CONFIG_MSM_BT_POWER=m -ifdef CONFIG_SLIMBUS +#ifdef CONFIG_SLIMBUS BT_SELECT += CONFIG_BTFM_SLIM=m -endif +#endif BT_SELECT += CONFIG_I2C_RTC6226_QCA=m LOCAL_PATH := $(call my-dir) diff --git a/bt_kernel_vendor_board.mk b/bt_kernel_vendor_board.mk index d1666d03d6..72c5e5d865 100644 --- a/bt_kernel_vendor_board.mk +++ b/bt_kernel_vendor_board.mk @@ -1,10 +1,19 @@ # Build audio kernel driver -ifneq ($(TARGET_USES_QMAA),true) ifneq ($(TARGET_BOARD_AUTO),true) -ifeq ($(call is-board-platform-in-list,$(TARGET_BOARD_PLATFORM)),true) -BOARD_VENDOR_KERNEL_MODULES += $(KERNEL_MODULES_OUT)/btpower.ko\ - $(KERNEL_MODULES_OUT)/bt_fm_slim.ko \ - $(KERNEL_MODULES_OUT)/radio-i2c-rtc6226-qca.ko -endif +ifeq ($(TARGET_USES_QMAA),true) + ifeq ($(TARGET_USES_QMAA_OVERRIDE_BLUETOOTH), true) + ifeq ($(call is-board-platform-in-list,$(TARGET_BOARD_PLATFORM)),true) + BOARD_VENDOR_KERNEL_MODULES += $(KERNEL_MODULES_OUT)/btpower.ko\ + $(KERNEL_MODULES_OUT)/bt_fm_slim.ko \ + $(KERNEL_MODULES_OUT)/radio-i2c-rtc6226-qca.ko + endif + endif +else + ifeq ($(call is-board-platform-in-list,$(TARGET_BOARD_PLATFORM)),true) + BOARD_VENDOR_KERNEL_MODULES += $(KERNEL_MODULES_OUT)/btpower.ko\ + $(KERNEL_MODULES_OUT)/bt_fm_slim.ko \ + $(KERNEL_MODULES_OUT)/radio-i2c-rtc6226-qca.ko + + endif endif endif diff --git a/pwr/btpower.c b/pwr/btpower.c index 9ab5b3abdf..aed5507ed7 100644 --- a/pwr/btpower.c +++ b/pwr/btpower.c @@ -139,16 +139,16 @@ static struct bt_power_vreg_data bt_vregs_info_qca6xx0[] = { // Regulator structure for kiwi BT SoC series static struct bt_power_vreg_data bt_vregs_info_kiwi[] = { - {NULL, "qcom,bt-vdd-io", 1800000, 1800000, 0, false, true, + {NULL, "qcom,bt-vdd18-aon", 1800000, 1800000, 0, false, true, {BT_VDD_IO_LDO, BT_VDD_IO_LDO_CURRENT}}, {NULL, "qcom,bt-vdd-aon", 950000, 950000, 0, false, true, {BT_VDD_AON_LDO, BT_VDD_AON_LDO_CURRENT}}, - {NULL, "qcom,bt-vdd-rfacmn", 950000, 950000, 0, false, true, + {NULL, "qcom,bt-vdd-rfaOp8", 950000, 950000, 0, false, true, {BT_VDD_RFACMN, BT_VDD_RFACMN_CURRENT}}, /* BT_CX_MX */ {NULL, "qcom,bt-vdd-dig", 950000, 950000, 0, false, true, {BT_VDD_DIG_LDO, BT_VDD_DIG_LDO_CURRENT}}, - {NULL, "qcom,bt-vdd-rfa-0p8", 950000, 952000, 0, false, true, + {NULL, "qcom,bt-vdd-rfaOp8", 950000, 952000, 0, false, true, {BT_VDD_RFA_0p8, BT_VDD_RFA_0p8_CURRENT}}, {NULL, "qcom,bt-vdd-rfa1", 1350000, 1350000, 0, false, true, {BT_VDD_RFA1_LDO, BT_VDD_RFA1_LDO_CURRENT}}, diff --git a/slimbus/Kconfig b/slimbus/Kconfig index a465e3c4ce..e94dc56e18 100644 --- a/slimbus/Kconfig +++ b/slimbus/Kconfig @@ -3,7 +3,6 @@ config BTFM_SLIM tristate "MSM Bluetooth/FM Slimbus Device" depends on MSM_BT_POWER - select SLIMBUS help This enables BT/FM slimbus driver to get multiple audio channel. This will make use of slimbus platform driver and slimbus From d3174b47220932d627785702c5e379ac6b50efbd Mon Sep 17 00:00:00 2001 From: satish kumar sugasi Date: Wed, 16 Feb 2022 23:58:19 -0800 Subject: [PATCH 009/154] FM: Add ALT_SLEEP_CLK support for power on chip This enables/disable alt_sleep_clock during FM on/off Change-Id: I95fbe011e34c80c013f13875bf9472e50aa05742 --- rtc6226/radio-rtc6226-i2c.c | 68 +++++++++++++++++++++++++++++++++++++ rtc6226/radio-rtc6226.h | 1 + 2 files changed, 69 insertions(+) diff --git a/rtc6226/radio-rtc6226-i2c.c b/rtc6226/radio-rtc6226-i2c.c index 0b5d0c72b7..30d3bcf2ad 100644 --- a/rtc6226/radio-rtc6226-i2c.c +++ b/rtc6226/radio-rtc6226-i2c.c @@ -393,6 +393,35 @@ open_err_req_irq: return retval; } +static int rtc6226_fm_alt_sleep_clk_reg_cfg(struct rtc6226_device *radio, bool power) +{ + int rc =0; + struct fm_power_vreg_data *vreg; + + vreg = radio->alt_sleep_clkreg; + if (!vreg) { + FMDERR("In %s, vio reg is NULL\n", __func__); + return rc; + } + if (power) { + FMDBG("vreg is : %s\n", vreg->name); + rc = regulator_enable(vreg->reg); + if (rc < 0) { + FMDERR("reg enable(%s) failed.rc=%d\n", vreg->name, rc); + return rc; + } + vreg->is_enabled = true; + } else { + rc = regulator_disable(vreg->reg); + if (rc < 0) { + FMDERR("reg disable(%s) fail rc=%d\n", vreg->name, rc); + return rc; + } + vreg->is_enabled = false; + } + return rc; +} + static int rtc6226_fm_vio_reg_cfg(struct rtc6226_device *radio, bool on) { int rc = 0; @@ -525,6 +554,13 @@ static int rtc6226_fm_power_cfg(struct rtc6226_device *radio, bool powerflag) rtc6226_fm_vdd_reg_cfg(radio, false); return rc; } + rc = rtc6226_fm_alt_sleep_clk_reg_cfg(radio, powerflag); + if (rc < 0) { + FMDERR("In %s, vio reg cfg failed %x\n", __func__, rc); + rtc6226_fm_vdd_reg_cfg(radio, false); + rtc6226_fm_vio_reg_cfg(radio, false); + return rc; + } } else { /* Turn OFF sequence */ rc = rtc6226_fm_vdd_reg_cfg(radio, powerflag); @@ -533,6 +569,9 @@ static int rtc6226_fm_power_cfg(struct rtc6226_device *radio, bool powerflag) rc = rtc6226_fm_vio_reg_cfg(radio, powerflag); if (rc < 0) FMDERR("In %s, vio reg cfg failed %x\n", __func__, rc); + rc = rtc6226_fm_alt_sleep_clk_reg_cfg(radio, powerflag); + if (rc < 0) + FMDERR("In %s, alt_sleep_clk_ reg cfg failed %x\n", __func__, rc); } return rc; } @@ -705,6 +744,7 @@ static int rtc6226_i2c_probe(struct i2c_client *client, struct v4l2_ctrl_handler *hdl; struct regulator *vddvreg = NULL; struct regulator *viovreg = NULL; + struct regulator *alt_sleep_clk_vreg = NULL; int retval = 0; int i = 0; int kfifo_alloc_rc = 0; @@ -740,6 +780,15 @@ static int rtc6226_i2c_probe(struct i2c_client *client, return retval; } + alt_sleep_clk_vreg = regulator_get(&client->dev, "alt-sleep-clk"); + if (IS_ERR(alt_sleep_clk_vreg)) { + retval = PTR_ERR(alt_sleep_clk_vreg); + FMDERR("%s: regulator_get(alt_sleep_clk) failed. retval=%d\n", + __func__, retval); + regulator_put(vddvreg); + regulator_put(viovreg); + return retval; + } /* private data allocation and initialization */ radio = kzalloc(sizeof(struct rtc6226_device), GFP_KERNEL); if (!radio) { @@ -813,6 +862,19 @@ static int rtc6226_i2c_probe(struct i2c_client *client, FMDERR("%s: parsing vio-supply failed\n", __func__); goto err_v4l2; } + radio->alt_sleep_clkreg = devm_kzalloc(&client->dev, + sizeof(struct fm_power_vreg_data), + GFP_KERNEL); + if (!radio->alt_sleep_clkreg) { + FMDERR("%s: allocating memory for alt_sleep_clk vreg failed\n", + __func__); + retval = -ENOMEM; + goto err_v4l2; + } + radio->alt_sleep_clkreg->reg = alt_sleep_clk_vreg; + radio->alt_sleep_clkreg->name = "alt-sleep-clk"; + radio->alt_sleep_clkreg->is_enabled = false; + /* Initialize pin control*/ retval = rtc6226_pinctrl_init(radio); if (retval) { @@ -922,6 +984,12 @@ err_vreg: } else { regulator_put(vddvreg); } + if (radio && radio->alt_sleep_clkreg && radio->alt_sleep_clkreg->reg) { + regulator_put(radio->alt_sleep_clkreg->reg); + devm_kfree(&client->dev, radio->alt_sleep_clkreg); + } else { + regulator_put(alt_sleep_clk_vreg); + } kfree(radio); return retval; } diff --git a/rtc6226/radio-rtc6226.h b/rtc6226/radio-rtc6226.h index 19d5cb48d4..4e092d45bb 100644 --- a/rtc6226/radio-rtc6226.h +++ b/rtc6226/radio-rtc6226.h @@ -482,6 +482,7 @@ struct rtc6226_device { struct v4l2_ctrl_handler ctrl_handler; struct fm_power_vreg_data *vddreg; struct fm_power_vreg_data *vioreg; + struct fm_power_vreg_data *alt_sleep_clkreg; int band; int space; atomic_t users; From 21dce9f3afb83d4d4086f21e8db2d942d7ba8bc9 Mon Sep 17 00:00:00 2001 From: satish kumar sugasi Date: Mon, 28 Feb 2022 09:02:07 -0800 Subject: [PATCH 010/154] Revert "FM: Add ALT_SLEEP_CLK support for power on chip" This reverts commit d3174b47220932d627785702c5e379ac6b50efbd Change-Id: I592fc7a404b9dfe601a392fdb82b41c332af65da --- rtc6226/radio-rtc6226-i2c.c | 68 ------------------------------------- rtc6226/radio-rtc6226.h | 1 - 2 files changed, 69 deletions(-) diff --git a/rtc6226/radio-rtc6226-i2c.c b/rtc6226/radio-rtc6226-i2c.c index 30d3bcf2ad..0b5d0c72b7 100644 --- a/rtc6226/radio-rtc6226-i2c.c +++ b/rtc6226/radio-rtc6226-i2c.c @@ -393,35 +393,6 @@ open_err_req_irq: return retval; } -static int rtc6226_fm_alt_sleep_clk_reg_cfg(struct rtc6226_device *radio, bool power) -{ - int rc =0; - struct fm_power_vreg_data *vreg; - - vreg = radio->alt_sleep_clkreg; - if (!vreg) { - FMDERR("In %s, vio reg is NULL\n", __func__); - return rc; - } - if (power) { - FMDBG("vreg is : %s\n", vreg->name); - rc = regulator_enable(vreg->reg); - if (rc < 0) { - FMDERR("reg enable(%s) failed.rc=%d\n", vreg->name, rc); - return rc; - } - vreg->is_enabled = true; - } else { - rc = regulator_disable(vreg->reg); - if (rc < 0) { - FMDERR("reg disable(%s) fail rc=%d\n", vreg->name, rc); - return rc; - } - vreg->is_enabled = false; - } - return rc; -} - static int rtc6226_fm_vio_reg_cfg(struct rtc6226_device *radio, bool on) { int rc = 0; @@ -554,13 +525,6 @@ static int rtc6226_fm_power_cfg(struct rtc6226_device *radio, bool powerflag) rtc6226_fm_vdd_reg_cfg(radio, false); return rc; } - rc = rtc6226_fm_alt_sleep_clk_reg_cfg(radio, powerflag); - if (rc < 0) { - FMDERR("In %s, vio reg cfg failed %x\n", __func__, rc); - rtc6226_fm_vdd_reg_cfg(radio, false); - rtc6226_fm_vio_reg_cfg(radio, false); - return rc; - } } else { /* Turn OFF sequence */ rc = rtc6226_fm_vdd_reg_cfg(radio, powerflag); @@ -569,9 +533,6 @@ static int rtc6226_fm_power_cfg(struct rtc6226_device *radio, bool powerflag) rc = rtc6226_fm_vio_reg_cfg(radio, powerflag); if (rc < 0) FMDERR("In %s, vio reg cfg failed %x\n", __func__, rc); - rc = rtc6226_fm_alt_sleep_clk_reg_cfg(radio, powerflag); - if (rc < 0) - FMDERR("In %s, alt_sleep_clk_ reg cfg failed %x\n", __func__, rc); } return rc; } @@ -744,7 +705,6 @@ static int rtc6226_i2c_probe(struct i2c_client *client, struct v4l2_ctrl_handler *hdl; struct regulator *vddvreg = NULL; struct regulator *viovreg = NULL; - struct regulator *alt_sleep_clk_vreg = NULL; int retval = 0; int i = 0; int kfifo_alloc_rc = 0; @@ -780,15 +740,6 @@ static int rtc6226_i2c_probe(struct i2c_client *client, return retval; } - alt_sleep_clk_vreg = regulator_get(&client->dev, "alt-sleep-clk"); - if (IS_ERR(alt_sleep_clk_vreg)) { - retval = PTR_ERR(alt_sleep_clk_vreg); - FMDERR("%s: regulator_get(alt_sleep_clk) failed. retval=%d\n", - __func__, retval); - regulator_put(vddvreg); - regulator_put(viovreg); - return retval; - } /* private data allocation and initialization */ radio = kzalloc(sizeof(struct rtc6226_device), GFP_KERNEL); if (!radio) { @@ -862,19 +813,6 @@ static int rtc6226_i2c_probe(struct i2c_client *client, FMDERR("%s: parsing vio-supply failed\n", __func__); goto err_v4l2; } - radio->alt_sleep_clkreg = devm_kzalloc(&client->dev, - sizeof(struct fm_power_vreg_data), - GFP_KERNEL); - if (!radio->alt_sleep_clkreg) { - FMDERR("%s: allocating memory for alt_sleep_clk vreg failed\n", - __func__); - retval = -ENOMEM; - goto err_v4l2; - } - radio->alt_sleep_clkreg->reg = alt_sleep_clk_vreg; - radio->alt_sleep_clkreg->name = "alt-sleep-clk"; - radio->alt_sleep_clkreg->is_enabled = false; - /* Initialize pin control*/ retval = rtc6226_pinctrl_init(radio); if (retval) { @@ -984,12 +922,6 @@ err_vreg: } else { regulator_put(vddvreg); } - if (radio && radio->alt_sleep_clkreg && radio->alt_sleep_clkreg->reg) { - regulator_put(radio->alt_sleep_clkreg->reg); - devm_kfree(&client->dev, radio->alt_sleep_clkreg); - } else { - regulator_put(alt_sleep_clk_vreg); - } kfree(radio); return retval; } diff --git a/rtc6226/radio-rtc6226.h b/rtc6226/radio-rtc6226.h index 4e092d45bb..19d5cb48d4 100644 --- a/rtc6226/radio-rtc6226.h +++ b/rtc6226/radio-rtc6226.h @@ -482,7 +482,6 @@ struct rtc6226_device { struct v4l2_ctrl_handler ctrl_handler; struct fm_power_vreg_data *vddreg; struct fm_power_vreg_data *vioreg; - struct fm_power_vreg_data *alt_sleep_clkreg; int band; int space; atomic_t users; From 17f729b2ed5f25a93e517afe54b348e3bc0c9153 Mon Sep 17 00:00:00 2001 From: Satish Kumar Kodishala Date: Thu, 28 Apr 2022 23:23:45 +0530 Subject: [PATCH 011/154] BTFMSLIM: Free memory during error while port open Free memory only during error while opening a port. In success case, memory will be freed during port closure. CRs-Fixed: 3162291, 3113018 Change-Id: Ice2172c7865e5df5898b3ac927f842db1516fd96 --- slimbus/btfm_slim.c | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/slimbus/btfm_slim.c b/slimbus/btfm_slim.c index b0d8d825b8..ea36de1f83 100644 --- a/slimbus/btfm_slim.c +++ b/slimbus/btfm_slim.c @@ -180,9 +180,13 @@ int btfm_slim_enable_ch(struct btfmslim *btfmslim, struct btfmslim_ch *ch, if (ret == 0) btfm_num_ports_open++; -error: BTFMSLIM_INFO("btfm_num_ports_open: %d", btfm_num_ports_open); + return ret; +error: + BTFMSLIM_INFO("error %d while opening port, btfm_num_ports_open: %d", + ret, btfm_num_ports_open); kfree(chan->dai.sconfig.chs); + chan->dai.sconfig.chs = NULL; return ret; } @@ -221,10 +225,14 @@ int btfm_slim_disable_ch(struct btfmslim *btfmslim, struct btfmslim_ch *ch, } } ch->dai.sconfig.port_mask = 0; - kfree(ch->dai.sconfig.chs); + if (ch->dai.sconfig.chs != NULL) + kfree(ch->dai.sconfig.chs); if (btfm_num_ports_open > 0) btfm_num_ports_open--; + + ch->dai.sruntime = NULL; + BTFMSLIM_INFO("btfm_num_ports_open: %d", btfm_num_ports_open); return ret; } From b54bc3270defeb351e5c8a8ca62cbe4b54b40e27 Mon Sep 17 00:00:00 2001 From: satish kumar sugasi Date: Tue, 19 Apr 2022 17:50:52 -0700 Subject: [PATCH 012/154] BT: Add support for converged node for kalama -Adds new device node entry to support dual attach. -Chipset attached is detected using gpio value and corresponding device tree node is selected. Change-Id: Iad12577a23ae0dca691b24de4efd385695259f41 --- Android.mk | 3 +- Makefile | 3 ++ include/btpower.h | 15 ++++-- pwr/Kconfig | 1 + pwr/Makefile | 2 + pwr/btpower.c | 125 ++++++++++++++++++++++++++++++++++++++++++++-- 6 files changed, 139 insertions(+), 10 deletions(-) diff --git a/Android.mk b/Android.mk index 5311caee7d..d21c4160d1 100644 --- a/Android.mk +++ b/Android.mk @@ -29,7 +29,6 @@ KBUILD_OPTIONS := BT_KERNEL_ROOT=$(BT_BLD_DIR) KBUILD_OPTIONS += $(foreach bt_select, \ $(BT_SELECT), \ $(bt_select)) - BT_SRC_FILES := \ $(wildcard $(LOCAL_PATH)/*) \ $(wildcard $(LOCAL_PATH)/*/*) \ @@ -45,6 +44,8 @@ LOCAL_MODULE := bt-kernel-module-symvers LOCAL_MODULE_STEM := Module.symvers LOCAL_MODULE_KBUILD_NAME := Module.symvers LOCAL_MODULE_PATH := $(KERNEL_MODULES_OUT) +LOCAL_REQUIRED_MODULES := wlan-platform-module-symvers +LOCAL_ADDITIONAL_DEPENDENCIES += $(call intermediates-dir-for,DLKM,wlan-platform-module-symvers)/Module.symvers include $(DLKM_DIR)/Build_external_kernelmodule.mk # Below are for Android build system to recognize each module name, so diff --git a/Makefile b/Makefile index de0aa3f278..51cbbaea9b 100644 --- a/Makefile +++ b/Makefile @@ -5,6 +5,9 @@ M=$(PWD) BT_ROOT=$(KERNEL_SRC)/$(M) KBUILD_OPTIONS+= BT_ROOT=$(BT_ROOT) +KBUILD_EXTRA_SYMBOLS=$(call intermediates-dir-for,DLKM,wlan-platform-module-symvers)/Module.symvers +KBUILD_EXTRA_SYMBOLS=$(OUT_DIR)/vendor/qcom/wlan/platform/Module.symvers +ccflags-y += -I$(BT_ROOT)/../wlan/platform/inc all: $(MAKE) -C $(KERNEL_SRC) M=$(M) modules $(KBUILD_OPTIONS) diff --git a/include/btpower.h b/include/btpower.h index 03c8451c43..ef9c934d67 100644 --- a/include/btpower.h +++ b/include/btpower.h @@ -11,7 +11,6 @@ #include #include #include - /* * voltage regulator information required for configuring the * bluetooth chipset @@ -59,6 +58,7 @@ struct btpower_platform_data { int wl_gpio_sys_rst; /* Wlan reset gpio */ int bt_gpio_sw_ctrl; /* Bluetooth sw_ctrl gpio */ int bt_gpio_debug; /* Bluetooth debug gpio */ + unsigned int wlan_sw_ctrl_gpio; /* Wlan switch control gpio*/ #ifdef CONFIG_MSM_BT_OOBS int bt_gpio_dev_wake; /* Bluetooth bt_wake */ int bt_gpio_host_wake; /* Bluetooth bt_host_wake */ @@ -74,6 +74,10 @@ struct btpower_platform_data { struct mbox_client mbox_client_data; struct mbox_chan *mbox_chan; const char *vreg_ipa; + bool is_converged_dt; + int pdc_init_table_len; + const char **pdc_init_table; + int bt_device_type; #ifdef CONFIG_MSM_BT_OOBS struct file *reffilp_obs; struct task_struct *reftask_obs; @@ -83,10 +87,12 @@ struct btpower_platform_data { int btpower_register_slimdev(struct device *dev); int btpower_get_chipset_version(void); int btpower_aop_mbox_init(struct btpower_platform_data *pdata); +int bt_aop_pdc_reconfig(struct btpower_platform_data *pdata); -#define BT_CMD_SLIM_TEST 0xbfac -#define BT_CMD_PWR_CTRL 0xbfad -#define BT_CMD_CHIPSET_VERS 0xbfae +#define WLAN_SW_CTRL_GPIO "qcom,wlan-sw-ctrl-gpio" +#define BT_CMD_SLIM_TEST 0xbfac +#define BT_CMD_PWR_CTRL 0xbfad +#define BT_CMD_CHIPSET_VERS 0xbfae #define BT_CMD_GET_CHIPSET_ID 0xbfaf #define BT_CMD_CHECK_SW_CTRL 0xbfb0 #define BT_CMD_GETVAL_POWER_SRCS 0xbfb1 @@ -95,7 +101,6 @@ int btpower_aop_mbox_init(struct btpower_platform_data *pdata); #ifdef CONFIG_MSM_BT_OOBS #define BT_CMD_OBS_SIGNAL_TASK 0xbfd0 #define BT_CMD_OBS_VOTE_CLOCK 0xbfd1 - /** * enum btpower_obs_param: OOBS low power param * @BTPOWER_OBS_CLK_OFF: Transport bus is no longer acquired diff --git a/pwr/Kconfig b/pwr/Kconfig index 87cb3c3298..75be717c2e 100644 --- a/pwr/Kconfig +++ b/pwr/Kconfig @@ -3,6 +3,7 @@ config MSM_BT_POWER tristate "MSM Bluetooth Power Control" depends on ARCH_QCOM + select CNSS_UTILS help MSM Bluetooth Power control driver. This provides a parameter to switch on/off power from PMIC diff --git a/pwr/Makefile b/pwr/Makefile index ac7e92aa5d..31b1d01f7e 100644 --- a/pwr/Makefile +++ b/pwr/Makefile @@ -1,2 +1,4 @@ ccflags-y += -I$(BT_ROOT)/include +ccflags-y += -I$(BT_ROOT)/../wlan/platform/inc +ccflags-y += -I$(BT_ROOT)/../wlan/platform/cnss_utils obj-$(CONFIG_MSM_BT_POWER) += btpower.o diff --git a/pwr/btpower.c b/pwr/btpower.c index aed5507ed7..8d995c10a3 100644 --- a/pwr/btpower.c +++ b/pwr/btpower.c @@ -17,6 +17,7 @@ #include #include #include +#include #include #include #include @@ -29,6 +30,7 @@ #include "btfm_slim.h" #endif #include +#include "cnss_utils.h" #define PWR_SRC_NOT_AVAILABLE -2 #define DEFAULT_INVALID_VALUE -1 @@ -198,6 +200,11 @@ static struct bt_power bt_vreg_info_kiwi = { .num_vregs = ARRAY_SIZE(bt_vregs_info_kiwi), }; +static struct bt_power bt_vreg_info_converged = { + .compatible = "qcom,bt-qca-converged", + .vregs = bt_vregs_info_kiwi, + .num_vregs = ARRAY_SIZE(bt_vregs_info_kiwi), +}; static struct bt_power bt_vreg_info_wcn6750 = { .compatible = "qcom,wcn6750-bt", @@ -212,6 +219,7 @@ static const struct of_device_id bt_power_match_table[] = { { .compatible = "qcom,qca6490", .data = &bt_vreg_info_qca6490}, { .compatible = "qcom,kiwi", .data = &bt_vreg_info_kiwi}, { .compatible = "qcom,wcn6750-bt", .data = &bt_vreg_info_wcn6750}, + { .compatible = "qcom,bt-qca-converged", .data = &bt_vreg_info_converged}, {}, }; @@ -965,16 +973,30 @@ static void bt_power_vreg_put(void) } } - static int bt_power_populate_dt_pinfo(struct platform_device *pdev) { int rc; - + struct device_node *child; pr_debug("%s\n", __func__); if (!bt_power_pdata) return -ENOMEM; + if (bt_power_pdata->is_converged_dt) { + for_each_available_child_of_node(pdev->dev.of_node, child) { + if (bt_power_pdata->bt_device_type == CNSS_HSP_DEVICE_TYPE ) { + if (strcmp(child->name, "bt_qca6490")) + continue; + pr_info("%s: bt_qca6490 device node found", __func__); + } else if (bt_power_pdata->bt_device_type == CNSS_HMT_DEVICE_TYPE) { + if (strcmp(child->name, "bt_kiwi")) + continue; + pr_info("%s: bt_kiwi device node found", __func__); + } + pdev->dev.of_node = child; + break; + } + } if (pdev->dev.of_node) { rc = bt_power_vreg_get(pdev); if (rc) @@ -1040,9 +1062,35 @@ static int bt_power_populate_dt_pinfo(struct platform_device *pdev) return 0; } +static inline bool bt_is_converged_dt(struct platform_device *plat_dev) +{ + return of_property_read_bool(plat_dev->dev.of_node, "qcom,converged-dt"); +} + +static void bt_power_pdc_init_params (struct btpower_platform_data *pdata) +{ + int ret; + struct device *dev = &pdata->pdev->dev; + pdata->pdc_init_table_len = of_property_count_strings(dev->of_node, + "qcom,pdc_init_table"); + if (pdata->pdc_init_table_len > 0) { + pdata->pdc_init_table = kcalloc(pdata->pdc_init_table_len, + sizeof(char *), GFP_KERNEL); + ret = of_property_read_string_array(dev->of_node, "qcom,pdc_init_table", + pdata->pdc_init_table, pdata->pdc_init_table_len); + if (ret < 0) + pr_err("Failed to get PDC Init Table\n"); + else + pr_info("PDC Init table configured\n"); + } else { + pr_debug("PDC Init Table not configured\n"); + } +} + static int bt_power_probe(struct platform_device *pdev) { int ret = 0; + unsigned int gpio_value; int itr; pr_debug("%s\n", __func__); @@ -1060,6 +1108,27 @@ static int bt_power_probe(struct platform_device *pdev) return -ENOMEM; bt_power_pdata->pdev = pdev; + bt_power_pdata->is_converged_dt = bt_is_converged_dt(pdev); + if (bt_power_pdata->is_converged_dt) { + if (of_find_property(pdev->dev.of_node, WLAN_SW_CTRL_GPIO, NULL)) { + bt_power_pdata->wlan_sw_ctrl_gpio = + of_get_named_gpio(pdev->dev.of_node, WLAN_SW_CTRL_GPIO,0); + pr_debug("WLAN Switch control GPIO: %d\n", + bt_power_pdata->wlan_sw_ctrl_gpio); + } else { + bt_power_pdata->wlan_sw_ctrl_gpio = -EINVAL; + } + gpio_value = gpio_get_value(bt_power_pdata->wlan_sw_ctrl_gpio); + pr_info("%s:WLAN_SW_CNTRL_GPIO value= %d\n", __func__, gpio_value); + if(gpio_value) { + bt_power_pdata->bt_device_type = + cnss_utils_update_device_type(CNSS_HSP_DEVICE_TYPE); + } else { + bt_power_pdata->bt_device_type = + cnss_utils_update_device_type(CNSS_HMT_DEVICE_TYPE); + } + } + if (pdev->dev.of_node) { ret = bt_power_populate_dt_pinfo(pdev); if (ret < 0) { @@ -1083,10 +1152,9 @@ static int bt_power_probe(struct platform_device *pdev) pr_err("%s: Failed to get platform data\n", __func__); goto free_pdata; } - if (btpower_rfkill_probe(pdev) < 0) goto free_pdata; - + bt_power_pdc_init_params(bt_power_pdata); btpower_aop_mbox_init(bt_power_pdata); probe_finished = true; @@ -1379,6 +1447,51 @@ driver_err: return ret; } +/** + * bt_aop_send_msg: Sends json message to AOP using QMP + * @plat_priv: Pointer to cnss platform data + * @msg: String in json format + * + * AOP accepts JSON message to configure WLAN/BT resources. Format as follows: + * To send VReg config: {class: wlan_pdc, ss: , + * res: ., : } + * To send PDC Config: {class: wlan_pdc, ss: , res: pdc, + * enable: } + * QMP returns timeout error if format not correct or AOP operation fails. + * + * Return: 0 for success + */ + int bt_aop_send_msg(struct btpower_platform_data *plat_priv, char *mbox_msg) + { + struct qmp_pkt pkt; + int ret = 0; + pkt.size = BTPOWER_MBOX_MSG_MAX_LEN; + pkt.data = mbox_msg; + ret = mbox_send_message(plat_priv->mbox_chan, &pkt); + if (ret < 0) + pr_err("Failed to send AOP mbox msg: %s\n", mbox_msg); + else + ret =0; + return ret; + + } +int bt_aop_pdc_reconfig(struct btpower_platform_data *pdata) +{ + + unsigned int i; + int ret; + if (pdata->pdc_init_table_len <= 0 || !pdata->pdc_init_table) + return 0; + pr_debug("Setting PDC defaults"); + for (i = 0; i < pdata->pdc_init_table_len; i++) { + ret =bt_aop_send_msg(pdata,(char *)pdata->pdc_init_table[i]); + if (ret < 0) + break; + } + return ret; +} + + int btpower_aop_mbox_init(struct btpower_platform_data *pdata) { struct mbox_client *mbox = &pdata->mbox_client_data; @@ -1406,6 +1519,10 @@ int btpower_aop_mbox_init(struct btpower_platform_data *pdata) else pr_info("%s: Mbox channel initialized\n", __func__); + ret = bt_aop_pdc_reconfig(pdata); + if (ret) + pr_err("Failed to reconfig BT WLAN PDC, err = %d\n", ret); + return 0; } From 8d9d6954ea5e7bfd7c39ac7241a6f1671c811eb2 Mon Sep 17 00:00:00 2001 From: Satish Kumar Kodishala Date: Fri, 10 Jun 2022 13:03:34 +0530 Subject: [PATCH 013/154] Delay after all ports are closed for HMT Delay after all ports are closed for HMT to allow the slimbus hw to reset. Also, slimbus slave don't expect port to be disconnected while tearing down for sample rates other than 44.1/88.2k. Change added not to disconnect ports during tear down. CRs-Fixed: 3203895 Change-Id: Ib352a40582506fe9644e44572f56d2fb08fba075 --- slimbus/btfm_slim.c | 76 +++++++++++++++++++++++++++++++++++++++------ 1 file changed, 66 insertions(+), 10 deletions(-) diff --git a/slimbus/btfm_slim.c b/slimbus/btfm_slim.c index ea36de1f83..0e8a8b7631 100644 --- a/slimbus/btfm_slim.c +++ b/slimbus/btfm_slim.c @@ -195,6 +195,7 @@ int btfm_slim_disable_ch(struct btfmslim *btfmslim, struct btfmslim_ch *ch, { int ret = -1; int i = 0; + int chipset_ver = 0; if (!btfmslim || !ch) return -EINVAL; @@ -206,10 +207,30 @@ int btfm_slim_disable_ch(struct btfmslim *btfmslim, struct btfmslim_ch *ch, btfm_is_port_opening_delayed = false; + if (rxport && (btfmslim->sample_rate == 44100 || + btfmslim->sample_rate == 88200)) { + BTFMSLIM_INFO("disconnecting the ports, removing the channel"); + /* disconnect the ports of the stream */ + ret = slim_stream_unprepare_disconnect_port(ch->dai.sruntime, + true, false); + if (ret != 0) + BTFMSLIM_ERR("slim_stream_unprepare failed %d", ret); + } + ret = slim_stream_disable(ch->dai.sruntime); - if (ret != 0) + if (ret != 0) { BTFMSLIM_ERR("slim_stream_disable failed returned val = %d", ret); - ret = slim_stream_unprepare(ch->dai.sruntime); + if ((btfmslim->sample_rate != 44100) && (btfmslim->sample_rate != 88200)) { + /* disconnect the ports of the stream */ + ret = slim_stream_unprepare_disconnect_port(ch->dai.sruntime, + true, false); + if (ret != 0) + BTFMSLIM_ERR("slim_stream_unprepare failed %d", ret); + } + } + + /* free the ports allocated to the stream */ + ret = slim_stream_unprepare_disconnect_port(ch->dai.sruntime, false, true); if (ret != 0) BTFMSLIM_ERR("slim_stream_unprepare failed returned val = %d", ret); @@ -234,6 +255,20 @@ int btfm_slim_disable_ch(struct btfmslim *btfmslim, struct btfmslim_ch *ch, ch->dai.sruntime = NULL; BTFMSLIM_INFO("btfm_num_ports_open: %d", btfm_num_ports_open); + + chipset_ver = btpower_get_chipset_version(); + + if (btfm_num_ports_open == 0 && (chipset_ver == QCA_HSP_SOC_ID_0200 || + chipset_ver == QCA_HSP_SOC_ID_0210 || + chipset_ver == QCA_HSP_SOC_ID_1201 || + chipset_ver == QCA_HSP_SOC_ID_1211 || + chipset_ver == QCA_HAMILTON_SOC_ID_0100 || + chipset_ver == QCA_HAMILTON_SOC_ID_0101 || + chipset_ver == QCA_HAMILTON_SOC_ID_0200 )) { + BTFMSLIM_INFO("SB reset needed after all ports disabled, sleeping"); + msleep(DELAY_FOR_PORT_OPEN_MS); + } + return ret; } @@ -385,6 +420,35 @@ int btfm_slim_hw_init(struct btfmslim *btfmslim) slim_ifd->e_addr.dev_index = 0x0; slim_ifd->e_addr.instance = 0x0; slim_ifd->laddr = 0x0; + } else if (chipset_ver == QCA_CHEROKEE_SOC_ID_0200 || + chipset_ver == QCA_CHEROKEE_SOC_ID_0201 || + chipset_ver == QCA_CHEROKEE_SOC_ID_0210 || + chipset_ver == QCA_CHEROKEE_SOC_ID_0211 || + chipset_ver == QCA_CHEROKEE_SOC_ID_0310 || + chipset_ver == QCA_CHEROKEE_SOC_ID_0320 || + chipset_ver == QCA_CHEROKEE_SOC_ID_0320_UMC || + chipset_ver == QCA_APACHE_SOC_ID_0100 || + chipset_ver == QCA_APACHE_SOC_ID_0110 || + chipset_ver == QCA_APACHE_SOC_ID_0120 || + chipset_ver == QCA_APACHE_SOC_ID_0121) { + BTFMSLIM_INFO("chipset is Chk/Apache, overwriting EA"); + slim->is_laddr_valid = false; + slim->e_addr.manf_id = SLIM_MANF_ID_QCOM; + slim->e_addr.prod_code = 0x220; + slim->e_addr.dev_index = 0x01; + slim->e_addr.instance = 0x0; + /* we are doing this to indicate that this is not a child node + * (doesn't have call back functions). Needed only for querying + * logical address. + */ + slim_ifd->dev.driver = NULL; + slim_ifd->ctrl = btfmslim->slim_pgd->ctrl; //slimbus controller structure. + slim_ifd->is_laddr_valid = false; + slim_ifd->e_addr.manf_id = SLIM_MANF_ID_QCOM; + slim_ifd->e_addr.prod_code = 0x220; + slim_ifd->e_addr.dev_index = 0x0; + slim_ifd->e_addr.instance = 0x0; + slim_ifd->laddr = 0x0; } BTFMSLIM_INFO( "PGD Enum Addr: manu id:%.02x prod code:%.02x dev idx:%.02x instance:%.02x", @@ -396,14 +460,6 @@ int btfm_slim_hw_init(struct btfmslim *btfmslim) slim_ifd->e_addr.manf_id, slim_ifd->e_addr.prod_code, slim_ifd->e_addr.dev_index, slim_ifd->e_addr.instance); - if (btfm_num_ports_open == 0 && (chipset_ver == QCA_HSP_SOC_ID_0200 || - chipset_ver == QCA_HSP_SOC_ID_0210 || - chipset_ver == QCA_HSP_SOC_ID_1201 || - chipset_ver == QCA_HSP_SOC_ID_1211)) { - BTFMSLIM_INFO("SB reset needed before getting LA, sleeping"); - msleep(DELAY_FOR_PORT_OPEN_MS); - } - /* Assign Logical Address for PGD (Ported Generic Device) * enumeration address */ From 2b813f0aba47f6decf9e04daa90a2093c0299b8b Mon Sep 17 00:00:00 2001 From: Satish Kumar Kodishala Date: Tue, 21 Jun 2022 15:00:46 +0530 Subject: [PATCH 014/154] Fix FM slimbus channel and port configuration Fix FM slimbus channel and port configuration. CRs-Fixed: 3219117 Change-Id: I3f8f5536a2d8a6cae0e0764ef4e2d6e4fc17cf7d --- slimbus/btfm_slim.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/slimbus/btfm_slim.c b/slimbus/btfm_slim.c index 0e8a8b7631..e3458485f4 100644 --- a/slimbus/btfm_slim.c +++ b/slimbus/btfm_slim.c @@ -132,8 +132,8 @@ int btfm_slim_enable_ch(struct btfmslim *btfmslim, struct btfmslim_ch *ch, goto error; } } - chan->dai.sconfig.chs[i] = chan->ch; - chan->dai.sconfig.port_mask |= BIT(chan->port); + chan->dai.sconfig.chs[i] = ch->ch; + chan->dai.sconfig.port_mask |= BIT(ch->port); } /* Activate the channel immediately */ From 45014a6ec98a2eeb62a012fe9a6150f08e516ab9 Mon Sep 17 00:00:00 2001 From: Franklin Abreu Bueno Date: Thu, 20 Oct 2022 10:58:02 -0700 Subject: [PATCH 015/154] Add support for pineapple - Enables bt kernel driver for pineapple - Replace fallthrough comments with attribute - Disable WLAN dependencies Change-Id: I7843ecc47b656e22d9e558af6be8d3445d79918f --- Android.mk | 4 +-- Makefile | 3 --- include/btpower.h | 1 - pwr/Kconfig | 1 - pwr/Makefile | 2 -- pwr/btpower.c | 49 +++++----------------------------- rtc6226/radio-rtc6226-common.c | 3 ++- slimbus/btfm_slim_codec.c | 6 +++-- 8 files changed, 13 insertions(+), 56 deletions(-) diff --git a/Android.mk b/Android.mk index d21c4160d1..4d30a66464 100644 --- a/Android.mk +++ b/Android.mk @@ -3,7 +3,7 @@ LOCAL_PATH := $(call my-dir) # Build/Package only in case of supported target -ifeq ($(call is-board-platform-in-list,taro kalama), true) +ifeq ($(call is-board-platform-in-list,taro kalama pineapple), true) BT_SELECT := CONFIG_MSM_BT_POWER=m #ifdef CONFIG_SLIMBUS @@ -44,8 +44,6 @@ LOCAL_MODULE := bt-kernel-module-symvers LOCAL_MODULE_STEM := Module.symvers LOCAL_MODULE_KBUILD_NAME := Module.symvers LOCAL_MODULE_PATH := $(KERNEL_MODULES_OUT) -LOCAL_REQUIRED_MODULES := wlan-platform-module-symvers -LOCAL_ADDITIONAL_DEPENDENCIES += $(call intermediates-dir-for,DLKM,wlan-platform-module-symvers)/Module.symvers include $(DLKM_DIR)/Build_external_kernelmodule.mk # Below are for Android build system to recognize each module name, so diff --git a/Makefile b/Makefile index 51cbbaea9b..de0aa3f278 100644 --- a/Makefile +++ b/Makefile @@ -5,9 +5,6 @@ M=$(PWD) BT_ROOT=$(KERNEL_SRC)/$(M) KBUILD_OPTIONS+= BT_ROOT=$(BT_ROOT) -KBUILD_EXTRA_SYMBOLS=$(call intermediates-dir-for,DLKM,wlan-platform-module-symvers)/Module.symvers -KBUILD_EXTRA_SYMBOLS=$(OUT_DIR)/vendor/qcom/wlan/platform/Module.symvers -ccflags-y += -I$(BT_ROOT)/../wlan/platform/inc all: $(MAKE) -C $(KERNEL_SRC) M=$(M) modules $(KBUILD_OPTIONS) diff --git a/include/btpower.h b/include/btpower.h index ef9c934d67..cffe09f00a 100644 --- a/include/btpower.h +++ b/include/btpower.h @@ -74,7 +74,6 @@ struct btpower_platform_data { struct mbox_client mbox_client_data; struct mbox_chan *mbox_chan; const char *vreg_ipa; - bool is_converged_dt; int pdc_init_table_len; const char **pdc_init_table; int bt_device_type; diff --git a/pwr/Kconfig b/pwr/Kconfig index 75be717c2e..87cb3c3298 100644 --- a/pwr/Kconfig +++ b/pwr/Kconfig @@ -3,7 +3,6 @@ config MSM_BT_POWER tristate "MSM Bluetooth Power Control" depends on ARCH_QCOM - select CNSS_UTILS help MSM Bluetooth Power control driver. This provides a parameter to switch on/off power from PMIC diff --git a/pwr/Makefile b/pwr/Makefile index 31b1d01f7e..ac7e92aa5d 100644 --- a/pwr/Makefile +++ b/pwr/Makefile @@ -1,4 +1,2 @@ ccflags-y += -I$(BT_ROOT)/include -ccflags-y += -I$(BT_ROOT)/../wlan/platform/inc -ccflags-y += -I$(BT_ROOT)/../wlan/platform/cnss_utils obj-$(CONFIG_MSM_BT_POWER) += btpower.o diff --git a/pwr/btpower.c b/pwr/btpower.c index 8d995c10a3..47cb364e7e 100644 --- a/pwr/btpower.c +++ b/pwr/btpower.c @@ -30,7 +30,6 @@ #include "btfm_slim.h" #endif #include -#include "cnss_utils.h" #define PWR_SRC_NOT_AVAILABLE -2 #define DEFAULT_INVALID_VALUE -1 @@ -77,6 +76,7 @@ enum power_src_pos { BT_VDD_LDO, BT_VDD_RFA_0p8, BT_VDD_RFACMN, + BT_VDD_ANT_LDO, // these indexes GPIOs/regs value are fetched during crash. BT_RESET_GPIO_CURRENT, BT_SW_CTRL_GPIO_CURRENT, @@ -94,6 +94,7 @@ enum power_src_pos { BT_VDD_RFACMN_CURRENT, BT_VDD_IPA_2p2, BT_VDD_IPA_2p2_CURRENT, + BT_VDD_ANT_LDO_CURRENT, /* The below bucks are voted for HW WAR on some platform which supports * WNC39xx. */ @@ -142,6 +143,8 @@ static struct bt_power_vreg_data bt_vregs_info_qca6xx0[] = { // Regulator structure for kiwi BT SoC series static struct bt_power_vreg_data bt_vregs_info_kiwi[] = { {NULL, "qcom,bt-vdd18-aon", 1800000, 1800000, 0, false, true, + {BT_VDD_LDO, BT_VDD_LDO_CURRENT}}, + {NULL, "qcom,bt-vdd12-io", 1200000, 1200000, 0, false, true, {BT_VDD_IO_LDO, BT_VDD_IO_LDO_CURRENT}}, {NULL, "qcom,bt-vdd-aon", 950000, 950000, 0, false, true, {BT_VDD_AON_LDO, BT_VDD_AON_LDO_CURRENT}}, @@ -156,6 +159,8 @@ static struct bt_power_vreg_data bt_vregs_info_kiwi[] = { {BT_VDD_RFA1_LDO, BT_VDD_RFA1_LDO_CURRENT}}, {NULL, "qcom,bt-vdd-rfa2", 1900000, 1900000, 0, false, true, {BT_VDD_RFA2_LDO, BT_VDD_RFA2_LDO_CURRENT}}, + {NULL, "qcom,bt-ant-ldo", 1776000, 1776000, 0, false, true, + {BT_VDD_ANT_LDO, BT_VDD_ANT_LDO_CURRENT}}, }; // Regulator structure for WCN399x BT SoC series @@ -976,27 +981,11 @@ static void bt_power_vreg_put(void) static int bt_power_populate_dt_pinfo(struct platform_device *pdev) { int rc; - struct device_node *child; pr_debug("%s\n", __func__); if (!bt_power_pdata) return -ENOMEM; - if (bt_power_pdata->is_converged_dt) { - for_each_available_child_of_node(pdev->dev.of_node, child) { - if (bt_power_pdata->bt_device_type == CNSS_HSP_DEVICE_TYPE ) { - if (strcmp(child->name, "bt_qca6490")) - continue; - pr_info("%s: bt_qca6490 device node found", __func__); - } else if (bt_power_pdata->bt_device_type == CNSS_HMT_DEVICE_TYPE) { - if (strcmp(child->name, "bt_kiwi")) - continue; - pr_info("%s: bt_kiwi device node found", __func__); - } - pdev->dev.of_node = child; - break; - } - } if (pdev->dev.of_node) { rc = bt_power_vreg_get(pdev); if (rc) @@ -1062,11 +1051,6 @@ static int bt_power_populate_dt_pinfo(struct platform_device *pdev) return 0; } -static inline bool bt_is_converged_dt(struct platform_device *plat_dev) -{ - return of_property_read_bool(plat_dev->dev.of_node, "qcom,converged-dt"); -} - static void bt_power_pdc_init_params (struct btpower_platform_data *pdata) { int ret; @@ -1090,7 +1074,6 @@ static void bt_power_pdc_init_params (struct btpower_platform_data *pdata) static int bt_power_probe(struct platform_device *pdev) { int ret = 0; - unsigned int gpio_value; int itr; pr_debug("%s\n", __func__); @@ -1108,26 +1091,6 @@ static int bt_power_probe(struct platform_device *pdev) return -ENOMEM; bt_power_pdata->pdev = pdev; - bt_power_pdata->is_converged_dt = bt_is_converged_dt(pdev); - if (bt_power_pdata->is_converged_dt) { - if (of_find_property(pdev->dev.of_node, WLAN_SW_CTRL_GPIO, NULL)) { - bt_power_pdata->wlan_sw_ctrl_gpio = - of_get_named_gpio(pdev->dev.of_node, WLAN_SW_CTRL_GPIO,0); - pr_debug("WLAN Switch control GPIO: %d\n", - bt_power_pdata->wlan_sw_ctrl_gpio); - } else { - bt_power_pdata->wlan_sw_ctrl_gpio = -EINVAL; - } - gpio_value = gpio_get_value(bt_power_pdata->wlan_sw_ctrl_gpio); - pr_info("%s:WLAN_SW_CNTRL_GPIO value= %d\n", __func__, gpio_value); - if(gpio_value) { - bt_power_pdata->bt_device_type = - cnss_utils_update_device_type(CNSS_HSP_DEVICE_TYPE); - } else { - bt_power_pdata->bt_device_type = - cnss_utils_update_device_type(CNSS_HMT_DEVICE_TYPE); - } - } if (pdev->dev.of_node) { ret = bt_power_populate_dt_pinfo(pdev); diff --git a/rtc6226/radio-rtc6226-common.c b/rtc6226/radio-rtc6226-common.c index 275a061b1b..98cbfbfc0e 100644 --- a/rtc6226/radio-rtc6226-common.c +++ b/rtc6226/radio-rtc6226-common.c @@ -1309,7 +1309,8 @@ void rtc6226_rds_handler(struct work_struct *worker) case RDS_TYPE_0A: if (radio->bler[2] <= CORRECTED_THREE_TO_FIVE) rtc6226_update_af_list(radio); - /* fall through */ + /* fall through */ + fallthrough; case RDS_TYPE_0B: addr = (radio->block[1] & PS_MASK) * NO_OF_CHARS_IN_EACH_ADD; FMDBG("%s RDS is PS\n", __func__); diff --git a/slimbus/btfm_slim_codec.c b/slimbus/btfm_slim_codec.c index 59a3c0a0c3..c530ef652b 100644 --- a/slimbus/btfm_slim_codec.c +++ b/slimbus/btfm_slim_codec.c @@ -259,7 +259,7 @@ static int btfm_slim_dai_set_channel_map(struct snd_soc_dai *dai, * get channel handler from slimbus driver */ rx_chs->ch = *(uint8_t *)(rx_slot + i); - BTFMSLIM_DBG(" %d\t%s\t%d\t%x\t%d\t%x", rx_chs->id, + BTFMSLIM_DBG(" %d\t%s\t%d\t%d\t", rx_chs->id, rx_chs->name, rx_chs->port, rx_chs->ch); } @@ -270,7 +270,7 @@ static int btfm_slim_dai_set_channel_map(struct snd_soc_dai *dai, * get channel handler from slimbus driver */ tx_chs->ch = *(uint8_t *)(tx_slot + i); - BTFMSLIM_DBG(" %d\t%s\t%d\t%x\t%d\t%x", tx_chs->id, + BTFMSLIM_DBG(" %d\t%s\t%d\t%d\t", tx_chs->id, tx_chs->name, tx_chs->port, tx_chs->ch); } @@ -291,6 +291,8 @@ static int btfm_slim_dai_get_channel_map(struct snd_soc_dai *dai, switch (dai->id) { case BTFM_FM_SLIM_TX: num = 2; + /* fall through */ + fallthrough; case BTFM_BT_SCO_SLIM_TX: if (!tx_slot || !tx_num) { BTFMSLIM_ERR("Invalid tx_slot %p or tx_num %p", From 11cd6d25d572d3351e58d54338231480fe82d2b1 Mon Sep 17 00:00:00 2001 From: satish kumar sugasi Date: Wed, 23 Nov 2022 17:28:25 -0800 Subject: [PATCH 016/154] btfm: set sw_cntrl gpiois during poweron sequence. Change-Id: I641c4a480bccfdb282e17f3489ec7c4481d84256 --- include/btpower.h | 1 + pwr/btpower.c | 14 ++++++++++++++ 2 files changed, 15 insertions(+) diff --git a/include/btpower.h b/include/btpower.h index cffe09f00a..f059401bb4 100644 --- a/include/btpower.h +++ b/include/btpower.h @@ -64,6 +64,7 @@ struct btpower_platform_data { int bt_gpio_host_wake; /* Bluetooth bt_host_wake */ int irq; /* Bluetooth host_wake IRQ */ #endif + int sw_cntrl_gpio; int xo_gpio_clk; /* XO clock gpio*/ struct device *slim_dev; struct bt_power_vreg_data *vreg_info; /* VDDIO voltage regulator */ diff --git a/pwr/btpower.c b/pwr/btpower.c index 47cb364e7e..e89bb8a231 100644 --- a/pwr/btpower.c +++ b/pwr/btpower.c @@ -25,6 +25,7 @@ #include #include #include +#include #include "btpower.h" #if (defined CONFIG_BT_SLIM) #include "btfm_slim.h" @@ -545,6 +546,14 @@ static int bt_configure_gpios(int on) if (bt_sw_ctrl_gpio >= 0) { bt_power_src_status[BT_SW_CTRL_GPIO] = gpio_get_value(bt_sw_ctrl_gpio); + rc = msm_gpio_mpm_wake_set(bt_power_pdata->sw_cntrl_gpio, 1); + if (rc < 0) { + pr_err("Failed to set msm_gpio_mpm_wake_set for sw_cntrl gpio, ret: %d\n", + rc); + return rc; + } else { + pr_info("Set msm_gpio_mpm_wake_set for sw_cntrl gpio successful\n"); + } pr_info("BTON:Turn Bt OFF bt-sw-ctrl-gpio(%d) value(%d)\n", bt_sw_ctrl_gpio, bt_power_src_status[BT_SW_CTRL_GPIO]); @@ -1011,6 +1020,11 @@ static int bt_power_populate_dt_pinfo(struct platform_device *pdev) if (bt_power_pdata->bt_gpio_sw_ctrl < 0) pr_warn("bt-sw-ctrl-gpio not provided in devicetree\n"); + rc = of_property_read_u32(pdev->dev.of_node, + "mpm_wake_set_gpios",&bt_power_pdata->sw_cntrl_gpio); + if (rc) + pr_warn("sw_cntrl-gpio not provided in devicetree\n"); + bt_power_pdata->bt_gpio_debug = of_get_named_gpio(pdev->dev.of_node, "qcom,bt-debug-gpio", 0); From b4c65a7e1edc66cf3c4b80b8564a0bac000c4375 Mon Sep 17 00:00:00 2001 From: Franklin Abreu Bueno Date: Fri, 23 Sep 2022 16:48:53 -0700 Subject: [PATCH 017/154] Enable Kernel Panic through ioctl - Add new ioctl command (BT_CMD_KERNEL_PANIC), so that when it is called, the kernel panics. - Add unique message that gets printed when kernel panic. Change-Id: Ied82749020058fe8e091f7fd5f0f212edb9a7285 --- include/btpower.h | 15 ++++++++------- pwr/btpower.c | 8 ++++++-- 2 files changed, 14 insertions(+), 9 deletions(-) diff --git a/include/btpower.h b/include/btpower.h index f059401bb4..553e000a48 100644 --- a/include/btpower.h +++ b/include/btpower.h @@ -90,13 +90,14 @@ int btpower_aop_mbox_init(struct btpower_platform_data *pdata); int bt_aop_pdc_reconfig(struct btpower_platform_data *pdata); #define WLAN_SW_CTRL_GPIO "qcom,wlan-sw-ctrl-gpio" -#define BT_CMD_SLIM_TEST 0xbfac -#define BT_CMD_PWR_CTRL 0xbfad -#define BT_CMD_CHIPSET_VERS 0xbfae -#define BT_CMD_GET_CHIPSET_ID 0xbfaf -#define BT_CMD_CHECK_SW_CTRL 0xbfb0 -#define BT_CMD_GETVAL_POWER_SRCS 0xbfb1 -#define BT_CMD_SET_IPA_TCS_INFO 0xbfc0 +#define BT_CMD_SLIM_TEST 0xbfac +#define BT_CMD_PWR_CTRL 0xbfad +#define BT_CMD_CHIPSET_VERS 0xbfae +#define BT_CMD_GET_CHIPSET_ID 0xbfaf +#define BT_CMD_CHECK_SW_CTRL 0xbfb0 +#define BT_CMD_GETVAL_POWER_SRCS 0xbfb1 +#define BT_CMD_SET_IPA_TCS_INFO 0xbfc0 +#define BT_CMD_KERNEL_PANIC 0xbfc1 #ifdef CONFIG_MSM_BT_OOBS #define BT_CMD_OBS_SIGNAL_TASK 0xbfd0 diff --git a/pwr/btpower.c b/pwr/btpower.c index e89bb8a231..12d3d4406f 100644 --- a/pwr/btpower.c +++ b/pwr/btpower.c @@ -1339,7 +1339,7 @@ static long bt_ioctl(struct file *file, unsigned int cmd, unsigned long arg) } break; case BT_CMD_GETVAL_POWER_SRCS: - pr_err("BT_CMD_GETVAL_POWER_SRCS\n"); + pr_info("BT_CMD_GETVAL_POWER_SRCS\n"); set_gpios_srcs_status("BT_RESET_GPIO", BT_RESET_GPIO_CURRENT, bt_power_pdata->bt_gpio_sys_rst); set_gpios_srcs_status("SW_CTRL_GPIO", BT_SW_CTRL_GPIO_CURRENT, @@ -1357,9 +1357,13 @@ static long bt_ioctl(struct file *file, unsigned int cmd, unsigned long arg) } break; case BT_CMD_SET_IPA_TCS_INFO: - pr_err("%s: BT_CMD_SET_IPA_TCS_INFO\n", __func__); + pr_info("%s: BT_CMD_SET_IPA_TCS_INFO\n", __func__); btpower_enable_ipa_vreg(bt_power_pdata); break; + case BT_CMD_KERNEL_PANIC: + pr_info("%s: BT_CMD_KERNEL_PANIC\n", __func__); + panic("subsys-restart: Resetting the SoC - Bluetooth crashed\n"); + break; default: return -ENOIOCTLCMD; } From a4d571f1da2dd5f945794ecc8e9badd9b08216c6 Mon Sep 17 00:00:00 2001 From: jianzhou Date: Mon, 12 Dec 2022 02:24:01 -0800 Subject: [PATCH 018/154] rtc6226: Make remove callback return void The value returned by an i2c driver's remove function is mostly ignored, so the prototype of the remove function was changed to return no value. So change the related remove callback return void. Change-Id: Iba2d83fe7f11ddfaabc67171b3ed7ee6955680be --- rtc6226/radio-rtc6226-i2c.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/rtc6226/radio-rtc6226-i2c.c b/rtc6226/radio-rtc6226-i2c.c index 0b5d0c72b7..4e688bfa85 100644 --- a/rtc6226/radio-rtc6226-i2c.c +++ b/rtc6226/radio-rtc6226-i2c.c @@ -36,6 +36,7 @@ #include #include "radio-rtc6226.h" #include +#include static const struct of_device_id rtc6226_i2c_dt_ids[] = { {.compatible = "rtc6226"}, @@ -929,7 +930,11 @@ err_vreg: /* * rtc6226_i2c_remove - remove the device */ +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(6, 1, 0)) +static void rtc6226_i2c_remove(struct i2c_client *client) +#else static int rtc6226_i2c_remove(struct i2c_client *client) +#endif { struct rtc6226_device *radio = i2c_get_clientdata(client); @@ -942,8 +947,9 @@ static int rtc6226_i2c_remove(struct i2c_client *client) v4l2_device_unregister(&radio->v4l2_dev); kfree(radio); FMDBG("%s exit\n", __func__); - +#if (LINUX_VERSION_CODE < KERNEL_VERSION(6, 1, 0)) return 0; +#endif } #ifdef CONFIG_PM From d261d4757e45ce82d63a0426a9ef7d0c74e13178 Mon Sep 17 00:00:00 2001 From: Franklin Abreu Bueno Date: Fri, 11 Nov 2022 09:49:52 -0800 Subject: [PATCH 019/154] bt-kernel: Add support for Bazel build system - kernel modules can now be built using Bazel/kleaf for pineapple. - Added macro that makes it easy to register new modules Change-Id: If19f9663135342bc36f543b1598231d133c1748f --- BUILD.bazel | 5 +++++ bt_kernel.bzl | 61 ++++++++++++++++++++++++++++++++++++++++++++++++++ bt_modules.bzl | 59 ++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 125 insertions(+) create mode 100644 BUILD.bazel create mode 100644 bt_kernel.bzl create mode 100644 bt_modules.bzl diff --git a/BUILD.bazel b/BUILD.bazel new file mode 100644 index 0000000000..3e1939f5da --- /dev/null +++ b/BUILD.bazel @@ -0,0 +1,5 @@ +load(":bt_kernel.bzl", "define_bt_modules") + +targets = ["pineapple"] + +define_bt_modules(targets) diff --git a/bt_kernel.bzl b/bt_kernel.bzl new file mode 100644 index 0000000000..36b9642c6e --- /dev/null +++ b/bt_kernel.bzl @@ -0,0 +1,61 @@ +load("//msm-kernel:target_variants.bzl", "get_all_variants") +load("//build/kernel/kleaf:kernel.bzl", "ddk_module") + +load(":bt_modules.bzl", "bt_modules") + +def _get_module_srcs(module): + """ + Gets all the module sources, formats them with the path for that module + and then groups them together + It also includes all the headers within the `include` directory + `native.glob()` returns a new list with every file need for the current package + """ + return native.glob( + ["{}/{}".format(module.path, src) for src in module.srcs] + ["include/*.h"] + ) + +def _get_module_deps(module, formatter): + """ + Formats the dependent targets with the necessary prefix + Args: + module: kernel module + formatter: function that will replace the format string within `deps` + Example: + kernel build = "pineapple_gki" + dep = "%b_btpower" + The formatted string will look as follow + formatted_dep = formatter(dep) = "pineapple_gki_btpower" + """ + return [formatter(dep) for dep in module.deps] + +def define_target_variant_modules(target, variant, modules): + """ + Generates the ddk_module for each of our kernel modules + Args: + target: either `pineapple` or `kalama` + variant: either `gki` or `consolidate` + modules: bt_modules dict defined in `bt_modules.bzl` + """ + kernel_build = "{}_{}".format(target, variant) + modules = [modules.get(module_name) for module_name in modules] + formatter = lambda s : s.replace("%b", kernel_build) + + for module in modules: + rule_name = "{}_{}".format(kernel_build, module.name) + module_srcs = _get_module_srcs(module) + + ddk_module( + name = rule_name, + kernel_build = "//msm-kernel:{}".format(kernel_build), + srcs = module_srcs, + out = "{}.ko".format(module.name), + deps = ["//msm-kernel:all_headers"] + _get_module_deps(module, formatter), + includes = ["include"], + visibility = ["//visibility:public"], + ) + +def define_bt_modules(targets): + for target in targets: + for (t, v) in get_all_variants(): + if t == target: + define_target_variant_modules(t, v, bt_modules) diff --git a/bt_modules.bzl b/bt_modules.bzl new file mode 100644 index 0000000000..e9e2841ef9 --- /dev/null +++ b/bt_modules.bzl @@ -0,0 +1,59 @@ +PWR_PATH = "pwr" +SLIMBUS_PATH = "slimbus" +FMRTC_PATH = "rtc6226" + +# This dictionary holds all the BT modules included in the bt-kernel +bt_modules = {} + +def register_bt_modules(name, path = None, config_opt = None, srcs = {}, deps = []): + """ + Register modules + Args: + name: Name of the module (which will be used to generate the name of the .ko file) + path: Path in which the source files can be found + config_opt: Config name used in Kconfig (not needed currently) + srcs: source files and local headers + deps: a list of dependent targets + """ + module = struct( + name = name, + path = path, + srcs = srcs, + config_opt = config_opt, + deps = deps + ) + bt_modules[name] = module + +# --- BT Modules --- + +register_bt_modules( + name = "btpower", + path = PWR_PATH, + config_opt = "CONFIG_MSM_BT_PWR", + srcs = ["btpower.c"] +) + +register_bt_modules( + name = "bt_fm_slim", + path = SLIMBUS_PATH, + config_opt = "CONFIG_BTFM_SLIM", + srcs = [ + "btfm_slim.c", + "btfm_slim.h", + "btfm_slim_codec.c", + "btfm_slim_slave.c", + "btfm_slim_slave.h", + ], + deps = [":%b_btpower"] +) + +register_bt_modules( + name = "radio-i2c-rtc6226-qca", + path = FMRTC_PATH, + config_opt = "CONFIG_I2C_RTC6226_QCA", + srcs = [ + "radio-rtc6226-common.c", + "radio-rtc6226-i2c.c", + "radio-rtc6226.h", + ] +) From d22c6870770f6dd57846d385d36fb2feb7919509 Mon Sep 17 00:00:00 2001 From: Balakrishna Godavarthi Date: Wed, 20 Apr 2022 12:27:37 +0530 Subject: [PATCH 020/154] btfmcodec: Create btfmcodec driver This changes handles below. 1. Create btfm codec driver. 2. add support to enumerate char device. 3. create hardware endpoint abstract layers. 4. Register with ALSA driver CRs-Fixed: 3298745 Change-Id: Id75dad16de8414b3b6a24d265c8acb54eca4d5dc --- Kbuild | 7 + btfmcodec/Kconfig | 10 + btfmcodec/Makefile | 4 + btfmcodec/btfm_codec.c | 239 ++++++++++ btfmcodec/btfm_codec_hw_interface.c | 99 +++++ btfmcodec/btfm_codec_interface.c | 278 ++++++++++++ btfmcodec/include/btfm_codec.h | 58 +++ btfmcodec/include/btfm_codec_hw_interface.h | 77 ++++ btfmcodec/include/btfm_codec_interface.h | 12 + slimbus/Kconfig | 10 + slimbus/Makefile | 5 + slimbus/btfm_slim.c | 14 +- slimbus/btfm_slim_hw_interface.c | 457 ++++++++++++++++++++ slimbus/btfm_slim_hw_interface.h | 18 + 14 files changed, 1287 insertions(+), 1 deletion(-) create mode 100644 btfmcodec/Kconfig create mode 100644 btfmcodec/Makefile create mode 100644 btfmcodec/btfm_codec.c create mode 100644 btfmcodec/btfm_codec_hw_interface.c create mode 100644 btfmcodec/btfm_codec_interface.c create mode 100644 btfmcodec/include/btfm_codec.h create mode 100644 btfmcodec/include/btfm_codec_hw_interface.h create mode 100644 btfmcodec/include/btfm_codec_interface.h create mode 100644 slimbus/btfm_slim_hw_interface.c create mode 100644 slimbus/btfm_slim_hw_interface.h diff --git a/Kbuild b/Kbuild index 5e11372e50..e55b1cb8d2 100644 --- a/Kbuild +++ b/Kbuild @@ -10,6 +10,13 @@ ifeq ($(CONFIG_I2C_RTC6226_QCA),m) KBUILD_CPPFLAGS += -DCONFIG_I2C_RTC6226_QCA endif + +ifeq ($(CONFIG_SLIM_BTFM_CODEC), m) +KBUILD_CPPFLAGS += -DCONFIG_SLIM_BTFM_CODEC +endif + obj-$(CONFIG_MSM_BT_POWER) += pwr/ obj-$(CONFIG_BTFM_SLIM) += slimbus/ obj-$(CONFIG_I2C_RTC6226_QCA) += rtc6226/ +obj-$(CONFIG_BTFM_CODEC) += btfmcodec/ +obj-$(CONFIG_SLIM_BTFM_CODEC) += slimbus/ diff --git a/btfmcodec/Kconfig b/btfmcodec/Kconfig new file mode 100644 index 0000000000..0f47ce1d1a --- /dev/null +++ b/btfmcodec/Kconfig @@ -0,0 +1,10 @@ +# SPDX-License-Identifier: GPL-2.0-only +config BTFM_CODEC + tristate "MSM Bluetooth/FM CODEC Driver" + help + This will enables BT/FM Codec driver. Hardware endpoint + drivers will register to this driver to communicates with ALSA codec + driver. + + Say Y here to compile support for BT/FM Codec driver + into the kernel or say M to compile as a module. diff --git a/btfmcodec/Makefile b/btfmcodec/Makefile new file mode 100644 index 0000000000..966976f5b0 --- /dev/null +++ b/btfmcodec/Makefile @@ -0,0 +1,4 @@ +ccflags-y += -I$(BT_ROOT)/include +ccflags-y += -I$(BT_ROOT)/btfmcodec/include +btfmcodec-objs := btfm_codec.o btfm_codec_hw_interface.o btfm_codec_interface.o +obj-$(CONFIG_BTFM_CODEC) += btfmcodec.o diff --git a/btfmcodec/btfm_codec.c b/btfmcodec/btfm_codec.c new file mode 100644 index 0000000000..9d06bd281f --- /dev/null +++ b/btfmcodec/btfm_codec.c @@ -0,0 +1,239 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2023 Qualcomm Innovation Center, Inc. All rights reserved. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "btfm_codec.h" +//#include "btfm_codec_hw_interface.h" + +#define dev_to_btfmcodec(_dev) container_of(_dev, struct btfmcodec_data, dev) + +static DEFINE_IDR(dev_minor); +static struct class *dev_class; +static dev_t dev_major; +struct btfmcodec_data *btfmcodec; +struct device_driver driver = {.name = "btfmcodec-driver", .owner = THIS_MODULE}; +struct btfmcodec_char_device *btfmcodec_dev; + +char *coverttostring(enum btfmcodec_states state) { + switch (state) { + case IDLE: + return "IDLE"; + break; + case BT_Connected: + return "BT_CONNECTED"; + break; + case BT_Connecting: + return "BT_CONNECTING"; + break; + case BTADV_AUDIO_Connected: + return "BTADV_AUDIO_CONNECTED"; + break; + case BTADV_AUDIO_Connecting: + return "BTADV_AUDIO_CONNECTING"; + break; + default: + return "INVALID_STATE"; + break; + } +} + +static const struct file_operations btfmcodec_fops = { + .owner = THIS_MODULE, +/* .open = glink_pkt_open, + .release = glink_pkt_release, + .read = glink_pkt_read, + .write = glink_pkt_write, + .poll = glink_pkt_poll, + .unlocked_ioctl = glink_pkt_ioctl, + .compat_ioctl = glink_pkt_ioctl, +*/}; + +static ssize_t btfmcodec_attributes_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t n) +{ + struct btfmcodec_data *btfmcodec = dev_to_btfmcodec(dev); + struct btfmcodec_char_device *btfmcodec_dev = btfmcodec->btfmcodec_dev; + long tmp; + + mutex_lock(&btfmcodec_dev->lock); + if (kstrtol(buf, 0, &tmp)) { + mutex_unlock(&btfmcodec_dev->lock); +/* BTFMCODEC_ERR("unable to convert string to int for /dev/%s\n", + btfmcodec->dev->name); +*/ return -EINVAL; + } + mutex_unlock(&btfmcodec_dev->lock); + + return n; +} + +static ssize_t btfmcodec_attributes_show(struct device *dev, + struct device_attribute *attr, + char *buf) +{ +// struct btfmcodec_char_device *btfmcodec_dev = dev_to_btfmcodec(dev); + + return 0; +} + +struct btfmcodec_data* btfm_get_btfmcodec(void) +{ + return btfmcodec; +} +EXPORT_SYMBOL(btfm_get_btfmcodec); + +static DEVICE_ATTR_RW(btfmcodec_attributes); + +static int __init btfmcodec_init(void) +{ + struct btfmcodec_state_machine *states; + struct btfmcodec_char_device *btfmcodec_dev; + struct device *dev; + int ret; + + BTFMCODEC_INFO("starting up the module"); + btfmcodec = kzalloc(sizeof(struct btfmcodec_data), GFP_KERNEL); + if (!btfmcodec) { + BTFMCODEC_ERR("failed to allocate memory"); + return -ENOMEM; + } + + states = &btfmcodec->states; + states->current_state = IDLE; + states->next_state = IDLE; + + BTFMCODEC_INFO("creating device node"); + /* create device node for communication between userspace and kernel */ + btfmcodec_dev = kzalloc(sizeof(struct btfmcodec_char_device), GFP_KERNEL); + if (!btfmcodec_dev) { + BTFMCODEC_ERR("failed to allocate memory"); + ret = -ENOMEM; + goto info_cleanup; + } + + BTFMCODEC_INFO("trying to get major number\n"); + ret = alloc_chrdev_region(&dev_major, 0, 0, "btfmcodec"); + if (ret < 0) { + BTFMCODEC_ERR("failed to allocate character device region"); + goto dev_cleanup; + } + + BTFMCODEC_INFO("creating btfm codec class"); + dev_class = class_create(THIS_MODULE, "btfmcodec"); + if (IS_ERR(dev_class)) { + ret = PTR_ERR(dev_class); + BTFMCODEC_ERR("class_create failed ret:%d\n", ret); + goto deinit_chrdev; + } + + btfmcodec_dev->reuse_minor = idr_alloc(&dev_minor, btfmcodec, 1, 0, GFP_KERNEL); + if (ret < 0) { + BTFMCODEC_ERR("failed to allocated minor number"); + goto deinit_class; + } + + dev = &btfmcodec->dev; + dev->driver = &driver; + + // ToDo Rethink of having btfmcodec alone instead of btfmcodec + btfmcodec->btfmcodec_dev = btfmcodec_dev; + refcount_set(&btfmcodec_dev->active_clients, 1); + mutex_init(&btfmcodec_dev->lock); + strlcpy(btfmcodec_dev->dev_name, "btfmcodec_dev", DEVICE_NAME_MAX_LEN); + device_initialize(dev); + dev->class = dev_class; + dev->devt = MKDEV(MAJOR(dev_major), btfmcodec_dev->reuse_minor); + dev_set_drvdata(dev, btfmcodec); + + cdev_init(&btfmcodec_dev->cdev, &btfmcodec_fops); + btfmcodec_dev->cdev.owner = THIS_MODULE; + dev_set_name(dev, btfmcodec_dev->dev_name, btfmcodec_dev->reuse_minor); + ret = cdev_add(&btfmcodec_dev->cdev, dev->devt, 1); + if (ret) { + BTFMCODEC_ERR("cdev_add failed with error no %d", ret); + goto idr_cleanup; + } + + // ToDo to handler HIDL abrupt kill + dev->release = NULL; + ret = device_add(dev); + if (ret) { + BTFMCODEC_ERR("Failed to add device error no %d", ret); + goto free_device; + } + + BTFMCODEC_ERR("Creating a sysfs entry with name: %s", btfmcodec_dev->dev_name); + ret = device_create_file(dev, &dev_attr_btfmcodec_attributes); + if (ret) { + BTFMCODEC_ERR("Failed to create a devicd node: %s", btfmcodec_dev->dev_name); + goto free_device; + } + + BTFMCODEC_INFO("created a node at /dev/%s with %u:%u\n", + btfmcodec_dev->dev_name, dev_major, btfmcodec_dev->reuse_minor); + + return ret; + +free_device: + put_device(dev); +idr_cleanup: + idr_remove(&dev_minor, btfmcodec_dev->reuse_minor); +deinit_class: + class_destroy(dev_class); +deinit_chrdev: + unregister_chrdev_region(MAJOR(dev_major), 0); +dev_cleanup: + kfree(btfmcodec_dev); +info_cleanup: + kfree(btfmcodec); + + return ret; +} + +static void __exit btfmcodec_deinit(void) +{ + struct btfmcodec_char_device *btfmcodec_dev; + struct device *dev; + BTFMCODEC_INFO("cleaning up btfm codec driver", __func__); + if (!btfmcodec) { + BTFMCODEC_ERR("skiping driver cleanup", __func__); + goto info_cleanup; + } + + dev = &btfmcodec->dev; + + device_remove_file(dev, &dev_attr_btfmcodec_attributes); + put_device(dev); + + if (!btfmcodec->btfmcodec_dev) { + BTFMCODEC_ERR("skiping device node cleanup", __func__); + goto info_cleanup; + } + + btfmcodec_dev = btfmcodec->btfmcodec_dev; + idr_remove(&dev_minor, btfmcodec_dev->reuse_minor); + class_destroy(dev_class); + unregister_chrdev_region(MAJOR(dev_major), 0); + kfree(btfmcodec_dev); +info_cleanup: + kfree(btfmcodec); + BTFMCODEC_INFO("btfm codec driver cleanup completed", __func__); + return; +} + +MODULE_LICENSE("GPL v2"); +MODULE_DESCRIPTION("MSM Bluetooth FM CODEC driver"); + +module_init(btfmcodec_init); +module_exit(btfmcodec_deinit); diff --git a/btfmcodec/btfm_codec_hw_interface.c b/btfmcodec/btfm_codec_hw_interface.c new file mode 100644 index 0000000000..091fe190cd --- /dev/null +++ b/btfmcodec/btfm_codec_hw_interface.c @@ -0,0 +1,99 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2023 Qualcomm Innovation Center, Inc. All rights reserved. + */ +#include "btfm_codec.h" +#include "btfm_codec_hw_interface.h" +#include "btfm_codec_interface.h" + +struct mutex hwep_drv_lock; + +int btfmcodec_register_hw_ep (struct hwep_data *ep_info) +{ + struct btfmcodec_data *btfmcodec; + struct hwep_data *hwep_info; + int ret = 0; + + // ToDo Check wether we need mutex_init api + mutex_lock(&hwep_drv_lock); + btfmcodec = btfm_get_btfmcodec(); + if (!btfmcodec) { + BTFMCODEC_ERR("btfm codec driver it not initialized"); + ret = -EPERM; + goto end; + } + + if (ep_info->num_dai == 0) { + BTFMCODEC_ERR("no active information provided by hw ep interface"); + ret = -EPERM; + goto end; + + } + + hwep_info = btfmcodec->hwep_info; + if (hwep_info) { + BTFMCODEC_ERR("driver already holds hardware endpoint info"); + ret = -EPERM; + goto end; + } + + hwep_info = kzalloc(sizeof(struct hwep_data), GFP_KERNEL); + if (!hwep_info) { + BTFMCODEC_ERR("%s: failed to allocate memory\n", __func__); + ret = -ENOMEM; + goto end; + } + + btfmcodec->hwep_info = hwep_info; + memcpy(hwep_info, ep_info, sizeof(struct hwep_data)); + + BTFMCODEC_INFO("Below driver registered with btfm codec\n"); + BTFMCODEC_INFO("Driver name: %s\n", hwep_info->driver_name); + BTFMCODEC_INFO("Num of dai: %d supported", hwep_info->num_dai); + BTFMCODEC_INFO("Master config enabled: %u\n", test_bit(BTADV_AUDIO_MASTER_CONFIG, + &hwep_info->flags)); + ret = btfm_register_codec(hwep_info); +end: + mutex_unlock(&hwep_drv_lock); + return ret; +} + +int btfmcodec_unregister_hw_ep (char *driver_name) +{ + struct btfmcodec_data *btfmcodec; + struct hwep_data *hwep_info; + int ret; + + mutex_lock(&hwep_drv_lock); + btfmcodec = btfm_get_btfmcodec(); + if (!btfmcodec) { + BTFMCODEC_ERR("btfm codec driver it not initialized"); + ret = -EPERM; + goto end; + } + + hwep_info = btfmcodec->hwep_info; + if (!hwep_info) { + BTFMCODEC_ERR("%s: no active hardware endpoint registered\n", __func__); + ret = -EPERM; + goto end; + } + + if(!strncmp(hwep_info->driver_name, driver_name, DEVICE_NAME_MAX_LEN)) { + btfm_unregister_codec(); + kfree(hwep_info); + BTFMCODEC_INFO("%s: deleted %s hardware endpoint\n", __func__, driver_name); + ret = -1; + goto end; + } else { + BTFMCODEC_ERR("%s: No hardware endpoint registered with %s\n", __func__, driver_name); + ret = -1; + goto end; + } +end: + mutex_unlock(&hwep_drv_lock); + return ret; +} + +EXPORT_SYMBOL(btfmcodec_register_hw_ep); +EXPORT_SYMBOL(btfmcodec_unregister_hw_ep); diff --git a/btfmcodec/btfm_codec_interface.c b/btfmcodec/btfm_codec_interface.c new file mode 100644 index 0000000000..cfd15d4e41 --- /dev/null +++ b/btfmcodec/btfm_codec_interface.c @@ -0,0 +1,278 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2023 Qualcomm Innovation Center, Inc. All rights reserved. + */ + +#include +#include "btfm_codec.h" +#include "btfm_codec_interface.h" + +static struct snd_soc_dai_driver *btfmcodec_dai_info; + +static int btfmcodec_codec_probe(struct snd_soc_component *codec) +{ + struct btfmcodec_data *btfmcodec = snd_soc_component_get_drvdata(codec); + struct btfmcodec_state_machine states = btfmcodec->states; + struct hwep_data *hwep_info = btfmcodec->hwep_info; + BTFMCODEC_DBG(""); + + // ToDo: check weather probe has to allowed when state if different + if (states.current_state != IDLE) { + BTFMCODEC_WARN("Received probe when state is :%s", coverttostring(states.current_state)); + } else if (hwep_info->drv && hwep_info->drv->hwep_probe) { + return hwep_info->drv->hwep_probe(codec); + } + + // ToDo to add mixer control. + return 0; +} + +static void btfmcodec_codec_remove(struct snd_soc_component *codec) +{ + struct btfmcodec_data *btfmcodec = snd_soc_component_get_drvdata(codec); + struct btfmcodec_state_machine states = btfmcodec->states; + struct hwep_data *hwep_info = btfmcodec->hwep_info; + BTFMCODEC_DBG(""); + + // ToDo: check whether remove has to allowed when state if different + if (states.current_state != IDLE) { + BTFMCODEC_WARN("Received probe when state is :%s", coverttostring(states.current_state)); + } else if (hwep_info->drv && hwep_info->drv->hwep_remove) { + hwep_info->drv->hwep_remove(codec); + } +} + +static int btfmcodec_codec_write(struct snd_soc_component *codec, + unsigned int reg, unsigned int value) +{ + struct btfmcodec_data *btfmcodec = snd_soc_component_get_drvdata(codec); + struct btfmcodec_state_machine states = btfmcodec->states; + struct hwep_data *hwep_info = btfmcodec->hwep_info; + BTFMCODEC_DBG(""); + + // ToDo: check whether remove has to allowed when state if different + if (states.current_state != IDLE) { + BTFMCODEC_WARN("Received probe when state is :%s", coverttostring(states.current_state)); + } else if (hwep_info->drv && hwep_info->drv->hwep_remove) { + return hwep_info->drv->hwep_write(codec, reg, value); + } + + return 0; +} + +static unsigned int btfmcodec_codec_read(struct snd_soc_component *codec, + unsigned int reg) +{ + struct btfmcodec_data *btfmcodec = snd_soc_component_get_drvdata(codec); + struct btfmcodec_state_machine states = btfmcodec->states; + struct hwep_data *hwep_info = btfmcodec->hwep_info; + BTFMCODEC_DBG(""); + + // ToDo: check whether remove has to allowed when state if different + if (states.current_state != IDLE) { + BTFMCODEC_WARN("Received probe when state is :%s", coverttostring(states.current_state)); + } else if (hwep_info->drv && hwep_info->drv->hwep_read) { + return hwep_info->drv->hwep_read(codec, reg); + } + + return 0; +} + +static const struct snd_soc_component_driver btfmcodec_codec_component = { + .probe = btfmcodec_codec_probe, + .remove = btfmcodec_codec_remove, + .read = btfmcodec_codec_read, + .write = btfmcodec_codec_write, +}; + + +static inline void * btfmcodec_get_dai_drvdata(struct hwep_data *hwep_info) +{ + if (!hwep_info || !hwep_info->dai_drv) return NULL; + return hwep_info->dai_drv; +} + +static int btfmcodec_dai_startup(struct snd_pcm_substream *substream, + struct snd_soc_dai *dai) +{ + struct btfmcodec_data *btfmcodec = snd_soc_component_get_drvdata(dai->component); + struct btfmcodec_state_machine states = btfmcodec->states; + struct hwep_dai_driver *dai_drv = (struct hwep_dai_driver *)btfmcodec_get_dai_drvdata(btfmcodec->hwep_info); + + BTFMCODEC_DBG("substream = %s stream = %d dai->name = %s", + substream->name, substream->stream, dai->name); + + // ToDo: check whether statup has to allowed when state if different + if (states.current_state != IDLE) { + BTFMCODEC_WARN("Received probe when state is :%s", coverttostring(states.current_state)); + } else if (dai && dai_drv->dai_ops && dai_drv->dai_ops->hwep_startup) { + return dai_drv->dai_ops->hwep_startup((void *)btfmcodec->hwep_info); + } else { + return -1; + } + + return 0; +} + +static void btfmcodec_dai_shutdown(struct snd_pcm_substream *substream, + struct snd_soc_dai *dai) +{ + struct btfmcodec_data *btfmcodec = snd_soc_component_get_drvdata(dai->component); + struct btfmcodec_state_machine states = btfmcodec->states; + struct hwep_dai_driver *dai_drv = (struct hwep_dai_driver *)btfmcodec_get_dai_drvdata(btfmcodec->hwep_info); + + BTFMCODEC_DBG("dai->name: %s, dai->id: %d, dai->rate: %d", dai->name, + dai->id, dai->rate); + + // ToDo: check whether statup has to allowed when state if different + if (states.current_state != IDLE) { + BTFMCODEC_WARN("Received probe when state is :%s", coverttostring(states.current_state)); + } else if (dai && dai_drv->dai_ops && dai_drv->dai_ops->hwep_shutdown) { + dai_drv->dai_ops->hwep_shutdown((void *)btfmcodec->hwep_info, dai->id); + } +} + +static int btfmcodec_dai_hw_params(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params, + struct snd_soc_dai *dai) +{ + struct btfmcodec_data *btfmcodec = snd_soc_component_get_drvdata(dai->component); + struct btfmcodec_state_machine states = btfmcodec->states; + struct hwep_dai_driver *dai_drv = (struct hwep_dai_driver *)btfmcodec_get_dai_drvdata(btfmcodec->hwep_info); + uint32_t bps = params_width(params); + uint32_t direction = substream->stream; + + BTFMCODEC_DBG("dai->name = %s DAI-ID %x rate %d bps %d num_ch %d", + dai->name, dai->id, params_rate(params), params_width(params), + params_channels(params)); + // ToDo: check whether hw_params has to allowed when state if different + if (states.current_state != IDLE) { + BTFMCODEC_WARN("Received probe when state is :%s", coverttostring(states.current_state)); + } else if (dai_drv && dai_drv->dai_ops && dai_drv->dai_ops->hwep_hw_params) { + return dai_drv->dai_ops->hwep_hw_params((void *)btfmcodec->hwep_info, bps, direction); + } else { + return -1; + } + + return 0; +} + +static int btfmcodec_dai_prepare(struct snd_pcm_substream *substream, + struct snd_soc_dai *dai) +{ + struct btfmcodec_data *btfmcodec = snd_soc_component_get_drvdata(dai->component); + struct btfmcodec_state_machine states = btfmcodec->states; + struct hwep_dai_driver *dai_drv = (struct hwep_dai_driver *)btfmcodec_get_dai_drvdata(btfmcodec->hwep_info); + uint32_t sampling_rate = dai->rate; + uint32_t direction = substream->stream; + int id = dai->id; + + + BTFMCODEC_INFO("dai->name: %s, dai->id: %d, dai->rate: %d direction: %d", dai->name, + id, sampling_rate, direction); + // ToDo: check whether hw_params has to allowed when state if different + if (states.current_state != IDLE) { + BTFMCODEC_WARN("Received probe when state is :%s", coverttostring(states.current_state)); + } else if (dai_drv && dai_drv->dai_ops && dai_drv->dai_ops->hwep_prepare) { + return dai_drv->dai_ops->hwep_prepare((void *)btfmcodec->hwep_info, sampling_rate, + direction, id); + } else { + return -1; + } + + return 0; + return 0; +} + +static int btfmcodec_dai_set_channel_map(struct snd_soc_dai *dai, + unsigned int tx_num, unsigned int *tx_slot, + unsigned int rx_num, unsigned int *rx_slot) +{ + struct btfmcodec_data *btfmcodec = snd_soc_component_get_drvdata(dai->component); + struct btfmcodec_state_machine states = btfmcodec->states; + struct hwep_dai_driver *dai_drv = (struct hwep_dai_driver *)btfmcodec_get_dai_drvdata(btfmcodec->hwep_info); + + BTFMCODEC_DBG(""); + // ToDo: check whether hw_params has to allowed when state if different + if (states.current_state != IDLE) { + BTFMCODEC_WARN("Received probe when state is :%s", coverttostring(states.current_state)); + } else if (dai_drv && dai_drv->dai_ops && dai_drv->dai_ops->hwep_set_channel_map) { + return dai_drv->dai_ops->hwep_set_channel_map((void *)btfmcodec->hwep_info, tx_num, + tx_slot, rx_num, rx_slot); + } else { + return -1; + } + + return 0; +} + +static int btfmcodec_dai_get_channel_map(struct snd_soc_dai *dai, + unsigned int *tx_num, unsigned int *tx_slot, + unsigned int *rx_num, unsigned int *rx_slot) +{ + struct btfmcodec_data *btfmcodec = snd_soc_component_get_drvdata(dai->component); + struct btfmcodec_state_machine states = btfmcodec->states; + struct hwep_dai_driver *dai_drv = (struct hwep_dai_driver *)btfmcodec_get_dai_drvdata(btfmcodec->hwep_info); + + BTFMCODEC_DBG(""); + // ToDo: check whether hw_params has to allowed when state if different + if (states.current_state != IDLE) { + BTFMCODEC_WARN("Received probe when state is :%s", coverttostring(states.current_state)); + } else if (dai_drv && dai_drv->dai_ops && dai_drv->dai_ops->hwep_get_channel_map) { + return dai_drv->dai_ops->hwep_get_channel_map((void *)btfmcodec->hwep_info, tx_num, + tx_slot, rx_num, rx_slot, dai->id); + } else { + return -1; + } + + return 0; +} + +static struct snd_soc_dai_ops btfmcodec_dai_ops = { + .startup = btfmcodec_dai_startup, + .shutdown = btfmcodec_dai_shutdown, + .hw_params = btfmcodec_dai_hw_params, + .prepare = btfmcodec_dai_prepare, + .set_channel_map = btfmcodec_dai_set_channel_map, + .get_channel_map = btfmcodec_dai_get_channel_map, +}; + +int btfm_register_codec(struct hwep_data *hwep_info) +{ + struct btfmcodec_data *btfmcodec; + struct device *dev; + struct hwep_dai_driver *dai_drv; + int i, ret; + + btfmcodec = btfm_get_btfmcodec(); + dev = &btfmcodec->dev; + btfmcodec_dai_info = kzalloc((sizeof(struct snd_soc_dai_driver) * hwep_info->num_dai), GFP_KERNEL); + if (!btfmcodec_dai_info) { + BTFMCODEC_ERR("failed to allocate memory"); + return -ENOMEM; + } + + for (i = 0; i < hwep_info->num_dai; i++) { + dai_drv = &hwep_info->dai_drv[i]; + btfmcodec_dai_info[i].name = dai_drv->dai_name; + btfmcodec_dai_info[i].id = dai_drv->id; + btfmcodec_dai_info[i].capture = dai_drv->capture; + btfmcodec_dai_info[i].playback = dai_drv->playback; + btfmcodec_dai_info[i].ops = &btfmcodec_dai_ops; + } + + BTFMCODEC_INFO("Adding %d dai support to codec", hwep_info->num_dai); + BTFMCODEC_INFO("slim bus driver name:%s", dev->driver->name); + ret = snd_soc_register_component(dev, &btfmcodec_codec_component, + btfmcodec_dai_info, hwep_info->num_dai); + + return ret; +} + +void btfm_unregister_codec(void) +{ + struct btfmcodec_data *btfmcodec; + + btfmcodec = btfm_get_btfmcodec(); + snd_soc_unregister_component(&btfmcodec->dev); +} diff --git a/btfmcodec/include/btfm_codec.h b/btfmcodec/include/btfm_codec.h new file mode 100644 index 0000000000..68a91fb8b9 --- /dev/null +++ b/btfmcodec/include/btfm_codec.h @@ -0,0 +1,58 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2023 Qualcomm Innovation Center, Inc. All rights reserved. + */ + +#ifndef __LINUX_BTFM_CODEC_H +#define __LINUX_BTFM_CODEC_H + +#include +#include +#include +#include +#include "btfm_codec_hw_interface.h" + +#define BTFMCODEC_DBG(fmt, arg...) pr_err("%s: " fmt "\n", __func__, ## arg) +#define BTFMCODEC_INFO(fmt, arg...) pr_err("%s: " fmt "\n", __func__, ## arg) +#define BTFMCODEC_ERR(fmt, arg...) pr_err("%s: " fmt "\n", __func__, ## arg) +#define BTFMCODEC_WARN(fmt, arg...) pr_warn("%s: " fmt "\n", __func__, ## arg) + +#define DEVICE_NAME_MAX_LEN 64 + +enum btfmcodec_states { + /*Default state of btfm codec driver */ + IDLE = 0, + /* When BT is active transport */ + BT_Connected = 1, + /* Waiting for BT bearer indication after configuring HW ports */ + BT_Connecting = 2, + /* When BTADV_AUDIO is active transport */ + BTADV_AUDIO_Connected = 3, + /* Waiting for BTADV_AUDIO bearer switch indications */ + BTADV_AUDIO_Connecting = 4 +}; + +char *coverttostring(enum btfmcodec_states); +struct btfmcodec_state_machine { + enum btfmcodec_states prev_state; + enum btfmcodec_states current_state; + enum btfmcodec_states next_state; +}; + +struct btfmcodec_char_device { + struct cdev cdev; + refcount_t active_clients; + struct mutex lock; + int reuse_minor; + char dev_name[DEVICE_NAME_MAX_LEN]; +}; + +struct btfmcodec_data { + struct device dev; + struct btfmcodec_state_machine states; + struct btfmcodec_char_device *btfmcodec_dev; + struct hwep_data *hwep_info; +}; + +struct btfmcodec_data *btfm_get_btfmcodec(void); +#endif /*__LINUX_BTFM_CODEC_H */ diff --git a/btfmcodec/include/btfm_codec_hw_interface.h b/btfmcodec/include/btfm_codec_hw_interface.h new file mode 100644 index 0000000000..116b415da9 --- /dev/null +++ b/btfmcodec/include/btfm_codec_hw_interface.h @@ -0,0 +1,77 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2023 Qualcomm Innovation Center, Inc. All rights reserved. + */ + +#ifndef __LINUX_BTFM_CODEC_HW_INTERFACE_H +#define __LINUX_BTFM_CODEC_HW_INTERFACE_H + +#include +#include +#include +#include +#include +#include +#include + +/* This flag is set to indicate btfm codec driver is + * responsible to configure master. + */ +#define BTADV_AUDIO_MASTER_CONFIG 0 +#define DEVICE_NAME_MAX_LEN 64 + +struct hwep_comp_drv { + int (*hwep_probe) (struct snd_soc_component *component); + void (*hwep_remove) (struct snd_soc_component *component); + unsigned int (*hwep_read)(struct snd_soc_component *component, unsigned int reg); + int (*hwep_write)(struct snd_soc_component *componentm, unsigned int reg, unsigned int value); +}; + +struct hwep_dai_ops { + int (*hwep_startup)(void *); + void (*hwep_shutdown)(void *, int); + int (*hwep_hw_params)(void *, uint32_t, uint32_t); + int (*hwep_prepare)(void *, uint32_t, uint32_t, int); + int (*hwep_set_channel_map)(void *, unsigned int, unsigned int *, + unsigned int, unsigned int *); + int (*hwep_get_channel_map)(void *, unsigned int *, unsigned int *, + unsigned int *, unsigned int *, int); +}; + +struct hwep_dai_driver { + const char *dai_name; + unsigned int id; + struct snd_soc_pcm_stream capture; + struct snd_soc_pcm_stream playback; + struct hwep_dai_ops *dai_ops; +}; + +struct hwep_data { + struct device *dev; + char driver_name [DEVICE_NAME_MAX_LEN]; + struct hwep_comp_drv *drv; + struct hwep_dai_driver *dai_drv; + int num_dai; + unsigned long flags; +}; + +int btfmcodec_register_hw_ep(struct hwep_data *); +int btfmcodec_unregister_hw_ep(char *); +// ToDo below. +/* +#if IS_ENABLED(CONFIG_SLIM_BTFM_CODEC_DRV) +int btfmcodec_register_hw_ep(struct hwep_data *); +int btfmcodec_unregister_hw_ep(char *); +#else +static inline int btfmcodec_register_hw_ep(struct hwep_data *hwep_info) +{ + return -EOPNOTSUPP; +} + +static inline int btfmcodec_unregister_hw_ep(char *dev_name) +{ + return -EOPNOTSUPP; +} +#endif +*/ +#endif /*__LINUX_BTFM_CODEC_HW_INTERFACE_H */ diff --git a/btfmcodec/include/btfm_codec_interface.h b/btfmcodec/include/btfm_codec_interface.h new file mode 100644 index 0000000000..3d652df4b5 --- /dev/null +++ b/btfmcodec/include/btfm_codec_interface.h @@ -0,0 +1,12 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2023 Qualcomm Innovation Center, Inc. All rights reserved. + */ + +#ifndef __LINUX_BTFM_CODEC_INTERFACE +#define __LINUX_BTFM_CODEC_INTERFACE + +#include "btfm_codec_hw_interface.h" +int btfm_register_codec(struct hwep_data *hwep_info); +void btfm_unregister_codec(void); +#endif /*__LINUX_BTFM_CODEC_INTERFACE */ diff --git a/slimbus/Kconfig b/slimbus/Kconfig index e94dc56e18..45f2272ecb 100644 --- a/slimbus/Kconfig +++ b/slimbus/Kconfig @@ -13,3 +13,13 @@ config BTFM_SLIM Say Y here to compile support for Bluetooth slimbus driver into the kernel or say M to compile as a module. +config SLIM_BTFM_CODEC + tristate "MSM Bluetooth/FM Slimbus Device using BTFM codec driver" + depends on MSM_BT_POWER + depends on BTFM_CODEC + help + This enables BT/FM slimbus driver to use btfm codec driver as + interface to interacts with codec driver. + + Say Y here to compile support for Bluetooth slimbus driver + into the kernel or say M to compile as a module. diff --git a/slimbus/Makefile b/slimbus/Makefile index bebebe22f7..18aa0a3f45 100644 --- a/slimbus/Makefile +++ b/slimbus/Makefile @@ -1,3 +1,8 @@ ccflags-y += -I$(BT_ROOT)/include +ccflags-y += -I$(BT_ROOT)/btfmcodec/include +#Below src is for BTFM SLAVE CODEC Driver support on LE platform. bt_fm_slim-objs := btfm_slim.o btfm_slim_codec.o btfm_slim_slave.o obj-$(CONFIG_BTFM_SLIM) += bt_fm_slim.o +# Below src is for BTFM Driver support based on btfm codec +btfm_slim_codec-objs := btfm_slim.o btfm_slim_hw_interface.o btfm_slim_slave.o +obj-$(CONFIG_SLIM_BTFM_CODEC) += btfm_slim_codec.o \ No newline at end of file diff --git a/slimbus/btfm_slim.c b/slimbus/btfm_slim.c index e3458485f4..2178ca7a7e 100644 --- a/slimbus/btfm_slim.c +++ b/slimbus/btfm_slim.c @@ -21,6 +21,8 @@ #include "btpower.h" #include "btfm_slim.h" #include "btfm_slim_slave.h" +#include "btfm_slim_hw_interface.h" + #define DELAY_FOR_PORT_OPEN_MS (200) #define SLIM_MANF_ID_QCOM 0x217 #define SLIM_PROD_CODE 0x221 @@ -520,7 +522,12 @@ static int btfm_slim_status(struct slim_device *sdev, struct device *dev = &sdev->dev; struct btfmslim *btfm_slim; btfm_slim = dev_get_drvdata(dev); + +#if IS_ENABLED(CONFIG_BTFM_SLIM) ret = btfm_slim_register_codec(btfm_slim); +#else + ret = btfm_slim_register_hw_ep(btfm_slim); +#endif if (ret) BTFMSLIM_ERR("error, registering slimbus codec failed"); return ret; @@ -534,7 +541,8 @@ static int btfm_slim_probe(struct slim_device *slim) pr_info("%s: name = %s\n", __func__, dev_name(&slim->dev)); /*this as true during the probe then slimbus won't check for logical address*/ slim->is_laddr_valid = true; - dev_set_name(&slim->dev, "%s", "btfmslim_slave"); + + dev_set_name(&slim->dev, "%s", BTFMSLIM_DEV_NAME); pr_info("%s: name = %s\n", __func__, dev_name(&slim->dev)); BTFMSLIM_DBG(""); @@ -565,7 +573,11 @@ static int btfm_slim_probe(struct slim_device *slim) btfm_slim->dev = &slim->dev; ret = btpower_register_slimdev(&slim->dev); if (ret < 0) { +#if IS_ENABLED(CONFIG_BTFM_SLIM) btfm_slim_unregister_codec(&slim->dev); +#else + btfm_slim_unregister_hwep(); +#endif ret = -EPROBE_DEFER; goto dealloc; } diff --git a/slimbus/btfm_slim_hw_interface.c b/slimbus/btfm_slim_hw_interface.c new file mode 100644 index 0000000000..67ce3ba41d --- /dev/null +++ b/slimbus/btfm_slim_hw_interface.c @@ -0,0 +1,457 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2016-2021, The Linux Foundation. All rights reserved. + * Copyright (c) 2021, 2023 Qualcomm Innovation Center, Inc. All rights reserved. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "btfm_slim.h" +#include "btfm_slim_hw_interface.h" +#include "btfm_codec_hw_interface.h" + +static int bt_soc_enable_status; +int btfm_feedback_ch_setting; + +static int btfm_slim_codec_write(struct snd_soc_component *codec, + unsigned int reg, unsigned int value) +{ + BTFMSLIM_DBG(""); + return 0; +} + +static unsigned int btfm_slim_codec_read(struct snd_soc_component *codec, + unsigned int reg) +{ + BTFMSLIM_DBG(""); + return 0; +} + +static int btfm_soc_status_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + BTFMSLIM_DBG(""); + ucontrol->value.integer.value[0] = bt_soc_enable_status; + return 1; +} + +static int btfm_soc_status_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + BTFMSLIM_DBG(""); + return 1; +} + +static int btfm_get_feedback_ch_setting(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + BTFMSLIM_DBG(""); + ucontrol->value.integer.value[0] = btfm_feedback_ch_setting; + return 1; +} + +static int btfm_put_feedback_ch_setting(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + BTFMSLIM_DBG(""); + btfm_feedback_ch_setting = ucontrol->value.integer.value[0]; + return 1; +} + +static const struct snd_kcontrol_new status_controls[] = { + SOC_SINGLE_EXT("BT SOC status", 0, 0, 1, 0, + btfm_soc_status_get, + btfm_soc_status_put), + SOC_SINGLE_EXT("BT set feedback channel", 0, 0, 1, 0, + btfm_get_feedback_ch_setting, + btfm_put_feedback_ch_setting) +}; + + +static int btfm_slim_codec_probe(struct snd_soc_component *codec) +{ + BTFMSLIM_DBG(""); + snd_soc_add_component_controls(codec, status_controls, + ARRAY_SIZE(status_controls)); + return 0; +} + +static void btfm_slim_codec_remove(struct snd_soc_component *codec) +{ + BTFMSLIM_DBG(""); +} + +static int btfm_slim_dai_startup(void *dai) +{ + struct hwep_data *hwep_info = (struct hwep_data *)dai; + struct btfmslim *btfmslim = dev_get_drvdata(hwep_info->dev); + int ret = -1; + + BTFMSLIM_DBG(""); + ret = btfm_slim_hw_init(btfmslim); + return ret; +} + +static void btfm_slim_dai_shutdown(void *dai, int id) +{ + struct hwep_data *hwep_info = (struct hwep_data *)dai; + struct btfmslim *btfmslim = dev_get_drvdata(hwep_info->dev); + struct btfmslim_ch *ch; + int i; + uint8_t rxport, nchan = 1; + + BTFMSLIM_DBG(""); + switch (id) { + case BTFM_FM_SLIM_TX: + nchan = 2; + ch = btfmslim->tx_chs; + rxport = 0; + break; + case BTFM_BT_SCO_SLIM_TX: + ch = btfmslim->tx_chs; + rxport = 0; + break; + case BTFM_BT_SCO_A2DP_SLIM_RX: + case BTFM_BT_SPLIT_A2DP_SLIM_RX: + ch = btfmslim->rx_chs; + rxport = 1; + break; + case BTFM_SLIM_NUM_CODEC_DAIS: + default: + BTFMSLIM_ERR("id is invalid:%d", id); + return; + } + /* Search for dai->id matched port handler */ + for (i = 0; (i < BTFM_SLIM_NUM_CODEC_DAIS) && + (ch->id != BTFM_SLIM_NUM_CODEC_DAIS) && + (ch->id != id); ch++, i++) + ; + + if ((ch->port == BTFM_SLIM_PGD_PORT_LAST) || + (ch->id == BTFM_SLIM_NUM_CODEC_DAIS)) { + BTFMSLIM_ERR("ch is invalid!!"); + return; + } + + btfm_slim_disable_ch(btfmslim, ch, rxport, nchan); + btfm_slim_hw_deinit(btfmslim); +} + +static int btfm_slim_dai_hw_params(void *dai, uint32_t bps, + uint32_t direction) { + struct hwep_data *hwep_info = (struct hwep_data *)dai; + struct btfmslim *btfmslim = dev_get_drvdata(hwep_info->dev); + + BTFMSLIM_DBG(""); + btfmslim->bps = bps; + btfmslim->direction = direction; + + return 0; +} + +static int btfm_slim_dai_prepare(void *dai, uint32_t sampling_rate, uint32_t direction, int id) +{ + struct hwep_data *hwep_info = (struct hwep_data *)dai; + struct btfmslim *btfmslim = dev_get_drvdata(hwep_info->dev); + struct btfmslim_ch *ch; + int ret = -EINVAL; + int i = 0; + uint8_t rxport, nchan = 1; + + btfmslim->direction = direction; + bt_soc_enable_status = 0; + + /* save sample rate */ + btfmslim->sample_rate = sampling_rate; + + switch (id) { + case BTFM_FM_SLIM_TX: + nchan = 2; + ch = btfmslim->tx_chs; + rxport = 0; + break; + case BTFM_BT_SCO_SLIM_TX: + ch = btfmslim->tx_chs; + rxport = 0; + break; + case BTFM_BT_SCO_A2DP_SLIM_RX: + case BTFM_BT_SPLIT_A2DP_SLIM_RX: + ch = btfmslim->rx_chs; + rxport = 1; + break; + case BTFM_SLIM_NUM_CODEC_DAIS: + default: + BTFMSLIM_ERR("id is invalid:%d", id); + return ret; + } + + /* Search for dai->id matched port handler */ + for (i = 0; (i < BTFM_SLIM_NUM_CODEC_DAIS) && + (ch->id != BTFM_SLIM_NUM_CODEC_DAIS) && + (ch->id != id); ch++, i++) + ; + + if ((ch->port == BTFM_SLIM_PGD_PORT_LAST) || + (ch->id == BTFM_SLIM_NUM_CODEC_DAIS)) { + BTFMSLIM_ERR("ch is invalid!!"); + return ret; + } + + ret = btfm_slim_enable_ch(btfmslim, ch, rxport, sampling_rate, nchan); + + /* save the enable channel status */ + if (ret == 0) + bt_soc_enable_status = 1; + + if (ret == -EISCONN) { + BTFMSLIM_ERR("channel opened without closing, returning success"); + ret = 0; + } + return ret; +} + +/* This function will be called once during boot up */ +static int btfm_slim_dai_set_channel_map(void *dai, + unsigned int tx_num, unsigned int *tx_slot, + unsigned int rx_num, unsigned int *rx_slot) +{ + + struct hwep_data *hwep_info = (struct hwep_data *)dai; + struct btfmslim *btfmslim = dev_get_drvdata(hwep_info->dev); + struct btfmslim_ch *rx_chs; + struct btfmslim_ch *tx_chs; + int ret = 0, i; + + BTFMSLIM_DBG(""); + + if (!btfmslim) + return -EINVAL; + + rx_chs = btfmslim->rx_chs; + tx_chs = btfmslim->tx_chs; + + if (!rx_chs || !tx_chs) + return ret; + + BTFMSLIM_DBG("Rx: id\tname\tport\tch"); + for (i = 0; (rx_chs->port != BTFM_SLIM_PGD_PORT_LAST) && (i < rx_num); + i++, rx_chs++) { + /* Set Rx Channel number from machine driver and + * get channel handler from slimbus driver + */ + rx_chs->ch = *(uint8_t *)(rx_slot + i); + BTFMSLIM_DBG(" %d\t%s\t%d\t%x\t%d\t%x", rx_chs->id, + rx_chs->name, rx_chs->port, rx_chs->ch); + } + + BTFMSLIM_DBG("Tx: id\tname\tport\tch"); + for (i = 0; (tx_chs->port != BTFM_SLIM_PGD_PORT_LAST) && (i < tx_num); + i++, tx_chs++) { + /* Set Tx Channel number from machine driver and + * get channel handler from slimbus driver + */ + tx_chs->ch = *(uint8_t *)(tx_slot + i); + BTFMSLIM_DBG(" %d\t%s\t%d\t%x\t%d\t%x", tx_chs->id, + tx_chs->name, tx_chs->port, tx_chs->ch); + } + + return ret; +} + +static int btfm_slim_dai_get_channel_map(void *dai, + unsigned int *tx_num, unsigned int *tx_slot, + unsigned int *rx_num, unsigned int *rx_slot, int id) +{ + + struct hwep_data *hwep_info = (struct hwep_data *)dai; + struct btfmslim *btfmslim = dev_get_drvdata(hwep_info->dev); + int i, ret = -EINVAL, *slot = NULL, j = 0, num = 1; + struct btfmslim_ch *ch = NULL; + + BTFMSLIM_DBG(""); + if (!btfmslim) + return ret; + + switch (id) { + case BTFM_FM_SLIM_TX: + num = 2; + case BTFM_BT_SCO_SLIM_TX: + if (!tx_slot || !tx_num) { + BTFMSLIM_ERR("Invalid tx_slot %p or tx_num %p", + tx_slot, tx_num); + return -EINVAL; + } + ch = btfmslim->tx_chs; + if (!ch) + return -EINVAL; + slot = tx_slot; + *rx_slot = 0; + *tx_num = num; + *rx_num = 0; + break; + case BTFM_BT_SCO_A2DP_SLIM_RX: + case BTFM_BT_SPLIT_A2DP_SLIM_RX: + if (!rx_slot || !rx_num) { + BTFMSLIM_ERR("Invalid rx_slot %p or rx_num %p", + rx_slot, rx_num); + return -EINVAL; + } + ch = btfmslim->rx_chs; + if (!ch) + return -EINVAL; + slot = rx_slot; + *tx_slot = 0; + *tx_num = 0; + *rx_num = num; + break; + default: + BTFMSLIM_ERR("Unsupported DAI %d", id); + return -EINVAL; + } + + do { + if (!ch) + return -EINVAL; + for (i = 0; (i < BTFM_SLIM_NUM_CODEC_DAIS) && (ch->id != + BTFM_SLIM_NUM_CODEC_DAIS) && (ch->id != id); + ch++, i++) + ; + + if (ch->id == BTFM_SLIM_NUM_CODEC_DAIS || + i == BTFM_SLIM_NUM_CODEC_DAIS) { + BTFMSLIM_ERR( + "No channel has been allocated for dai (%d)", + id); + return -EINVAL; + } + if (!slot) + return -EINVAL; + *(slot + j) = ch->ch; + BTFMSLIM_DBG("id:%d, port:%d, ch:%d, slot: %d", ch->id, + ch->port, ch->ch, *(slot + j)); + + /* In case it has mulitiple channels */ + if (++j < num) + ch++; + } while (j < num); + + return 0; +} + +static struct hwep_dai_ops btfmslim_hw_dai_ops = { + .hwep_startup = btfm_slim_dai_startup, + .hwep_shutdown = btfm_slim_dai_shutdown, + .hwep_hw_params = btfm_slim_dai_hw_params, + .hwep_prepare = btfm_slim_dai_prepare, + .hwep_set_channel_map = btfm_slim_dai_set_channel_map, + .hwep_get_channel_map = btfm_slim_dai_get_channel_map, +}; + +static struct hwep_dai_driver btfmslim_dai_driver[] = { + { /* Bluetooth SCO voice uplink: bt -> lpass */ + .dai_name = "btfm_bt_sco_slim_tx", + .id = BTFM_BT_SCO_SLIM_TX, + .capture = { + .stream_name = "SCO TX Capture", + /* 8 KHz or 16 KHz */ + .rates = SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000 + | SNDRV_PCM_RATE_8000_192000 + | SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000 + | SNDRV_PCM_RATE_88200 | SNDRV_PCM_RATE_96000 + | SNDRV_PCM_RATE_192000, + .formats = SNDRV_PCM_FMTBIT_S16_LE, /* 16 bits */ + .rate_max = 192000, + .rate_min = 8000, + .channels_min = 1, + .channels_max = 1, + }, + .dai_ops = &btfmslim_hw_dai_ops, + }, + { /* Bluetooth SCO voice downlink: lpass -> bt or A2DP Playback */ + .dai_name = "btfm_bt_sco_a2dp_slim_rx", + .id = BTFM_BT_SCO_A2DP_SLIM_RX, + .playback = { + .stream_name = "SCO A2DP RX Playback", + /* 8/16/44.1/48/88.2/96 Khz */ + .rates = SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000 + | SNDRV_PCM_RATE_8000_192000 + | SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000 + | SNDRV_PCM_RATE_88200 | SNDRV_PCM_RATE_96000 + | SNDRV_PCM_RATE_192000, + .formats = SNDRV_PCM_FMTBIT_S16_LE, /* 16 bits */ + .rate_max = 192000, + .rate_min = 8000, + .channels_min = 1, + .channels_max = 1, + }, + .dai_ops = &btfmslim_hw_dai_ops, + }, +}; + +static struct hwep_comp_drv btfmslim_hw_driver = { + .hwep_probe = btfm_slim_codec_probe, + .hwep_remove = btfm_slim_codec_remove, + .hwep_read = btfm_slim_codec_read, + .hwep_write = btfm_slim_codec_write, +}; + +int btfm_slim_register_hw_ep(struct btfmslim *btfm_slim) +{ + struct device *dev = btfm_slim->dev; + struct hwep_data *hwep_info; + int ret = 0; + + BTFMSLIM_INFO("Registering with BTFMCODEC HWEP interface\n"); + hwep_info = kzalloc(sizeof(struct hwep_data), GFP_KERNEL); + + if (!hwep_info) { + BTFMSLIM_ERR("%s: failed to allocate memory\n", __func__); + ret = -ENOMEM; + goto end; + } + + /* Copy EP device parameters as intercations will be on the same device */ + hwep_info->dev = dev; + strlcpy(hwep_info->driver_name, BTFMSLIM_DEV_NAME, DEVICE_NAME_MAX_LEN); + hwep_info->drv = &btfmslim_hw_driver; + hwep_info->dai_drv = btfmslim_dai_driver; + hwep_info->num_dai = ARRAY_SIZE(btfmslim_dai_driver); + hwep_info->num_dai = 2; + set_bit(BTADV_AUDIO_MASTER_CONFIG, &hwep_info->flags); + /* Register to hardware endpoint */ + ret = btfmcodec_register_hw_ep(hwep_info); + if (ret) { + BTFMSLIM_ERR("failed to register with btfmcodec driver hw interface (%d)", ret); + goto end; + } + + BTFMSLIM_INFO("Registered succesfull with BTFMCODEC HWEP interface\n"); + return ret; +end: + return ret; +} + +void btfm_slim_unregister_hwep(void) +{ + BTFMSLIM_INFO("Unregistered with BTFMCODEC HWEP interface"); + /* Unregister with BTFMCODEC HWEP driver */ + btfmcodec_unregister_hw_ep(BTFMSLIM_DEV_NAME); + +} + +MODULE_DESCRIPTION("BTFM Slimbus driver"); +MODULE_LICENSE("GPL v2"); diff --git a/slimbus/btfm_slim_hw_interface.h b/slimbus/btfm_slim_hw_interface.h new file mode 100644 index 0000000000..38b480cf6b --- /dev/null +++ b/slimbus/btfm_slim_hw_interface.h @@ -0,0 +1,18 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2023 Qualcomm Innovation Center, Inc. All rights reserved. + */ + +#ifndef __LINUX_BTFM_SLIM_HW_INTERFACE_H +#define __LINUX_BTFM_SLIM_HW_INTERFACE_H + +#if IS_ENABLED(CONFIG_BTFM_SLIM) +#define BTFMSLIM_DEV_NAME "btfmslim_slave" +#else +#define BTFMSLIM_DEV_NAME "btfmslim" +#endif + +// Todo protect with flags +int btfm_slim_register_hw_ep(struct btfmslim *btfm_slim); +void btfm_slim_unregister_hwep(void); +#endif /*__LINUX_BTFM_SLIM_HW_INTERFACE_H*/ From 30209d05c3c1b7a3b9a49da8aa54f3462875a504 Mon Sep 17 00:00:00 2001 From: Balakrishna Godavarthi Date: Mon, 2 Jan 2023 10:11:03 +0530 Subject: [PATCH 021/154] btfmcodec: Add packetization and depacketizations This change adds support for packetization and depacketization of various packet received or sent from btfmcodec driver. CRs-Fixed: 3298745 Change-Id: I30c1a7897a1f50d5dcad83757900152f2c06255b --- btfmcodec/btfm_codec.c | 337 ++++++++++++++++++++++++++++- btfmcodec/btfm_codec_interface.c | 6 +- btfmcodec/include/btfm_codec.h | 8 + btfmcodec/include/btfm_codec_pkt.h | 49 +++++ 4 files changed, 389 insertions(+), 11 deletions(-) create mode 100644 btfmcodec/include/btfm_codec_pkt.h diff --git a/btfmcodec/btfm_codec.c b/btfmcodec/btfm_codec.c index 9d06bd281f..a6e789df23 100644 --- a/btfmcodec/btfm_codec.c +++ b/btfmcodec/btfm_codec.c @@ -13,7 +13,7 @@ #include #include #include "btfm_codec.h" -//#include "btfm_codec_hw_interface.h" +#include "btfm_codec_pkt.h" #define dev_to_btfmcodec(_dev) container_of(_dev, struct btfmcodec_data, dev) @@ -23,6 +23,8 @@ static dev_t dev_major; struct btfmcodec_data *btfmcodec; struct device_driver driver = {.name = "btfmcodec-driver", .owner = THIS_MODULE}; struct btfmcodec_char_device *btfmcodec_dev; +#define cdev_to_btfmchardev(_cdev) container_of(_cdev, struct btfmcodec_char_device, cdev) +#define MIN_PKT_LEN 0x3 char *coverttostring(enum btfmcodec_states state) { switch (state) { @@ -47,16 +49,323 @@ char *coverttostring(enum btfmcodec_states state) { } } +/* + * btfmcodec_dev_open() - open() syscall for the btfmcodec dev node + * inode: Pointer to the inode structure. + * file: Pointer to the file structure. + * + * This function is used to open the btfmcodec char device when + * userspace client do a open() system call. All input arguments are + * validated by the virtual file system before calling this function. + * Note: btfmcodec dev node works on nonblocking mode. + */ +static int btfmcodec_dev_open(struct inode *inode, struct file *file) +{ + struct btfmcodec_char_device *btfmcodec_dev = cdev_to_btfmchardev(inode->i_cdev); + struct btfmcodec_data *btfmcodec = (struct btfmcodec_data *)btfmcodec_dev->btfmcodec; + int active_clients = refcount_read(&btfmcodec_dev->active_clients); + + btfmcodec->states.current_state = IDLE; /* Just a temp*/ + BTFMCODEC_INFO("File mode :%u", file->f_mode); + BTFMCODEC_INFO("for %s by %s:%d active_clients[%d]\n", + btfmcodec_dev->dev_name, current->comm, + task_pid_nr(current), refcount_read(&btfmcodec_dev->active_clients)); + /* Don't allow a new client if already one is active. */ + if (active_clients > 0) { + BTFMCODEC_WARN("%s: Not honoring open as other client is active", __func__); + return EACCES; + } + /* for now have btfmcodec and later we can think of having it btfmcodec_dev */ + file->private_data = btfmcodec; + refcount_inc(&btfmcodec_dev->active_clients); + return 0; +} + +/* + * btfmcodec_pkt_release() - release operation on btfmcodec device + * inode: Pointer to the inode structure. + * file: Pointer to the file structure. + * + * This function is used to release the btfmcodec dev node when + * userspace client do a close() system call. All input arguments are + * validated by the virtual file system before calling this function. + */ +static int btfmcodec_dev_release(struct inode *inode, struct file *file) +{ + struct btfmcodec_char_device *btfmcodec_dev = cdev_to_btfmchardev(inode->i_cdev); + unsigned long flags; + + BTFMCODEC_INFO("for %s by %s:%d active_clients[%d]\n", + btfmcodec_dev->dev_name, current->comm, + task_pid_nr(current), refcount_read(&btfmcodec_dev->active_clients)); + + refcount_dec(&btfmcodec_dev->active_clients); + if (refcount_read(&btfmcodec_dev->active_clients) == 0) { + spin_lock_irqsave(&btfmcodec_dev->tx_queue_lock, flags); + skb_queue_purge(&btfmcodec_dev->txq); + /* Wakeup the device if waiting for the data */ + wake_up_interruptible(&btfmcodec_dev->readq); + spin_unlock_irqrestore(&btfmcodec_dev->tx_queue_lock, flags); + /* we need to have separte rx lock for below buff */ + skb_queue_purge(&btfmcodec_dev->rxq); + } + + return 0; +} + +btm_opcode get_opcode (struct sk_buff *skb) +{ + return ((skb->data[0]<< 8) | skb->data[1]); +} + +static void btfmcodec_dev_rxwork(struct work_struct *work) +{ + struct btfmcodec_char_device *btfmcodec_dev = container_of(work, struct btfmcodec_char_device, rx_work); + struct sk_buff *skb; + struct btm_req *req_pkt; + + BTFMCODEC_DBG("start"); + while ((skb = skb_dequeue(&btfmcodec_dev->rxq))) { + btm_opcode opcode = get_opcode(skb); +// skb_pull(skb, sizeof(btm_opcode)); + switch (opcode) { + case BTM_BTFMCODEC_PREPARE_AUDIO_BEARER_SWITCH_REQ: + req_pkt = (void *)skb->data; + req_pkt->opcode = opcode; + BTFMCODEC_DBG("BTM_BTFMCODEC_PREPARE_AUDIO_BEARER_SWITCH_REQ opcode %4x and len %d", req_pkt->opcode, req_pkt->len); + btfmcodec_dev_enqueue_pkt(btfmcodec_dev, skb->data, skb->len); + break; + case BTM_BTFMCODEC_MASTER_CONFIG_RSP: + BTFMCODEC_DBG("BTM_BTFMCODEC_MASTER_CONFIG_RSP"); + break; + case BTM_BTFMCODEC_CTRL_MASTER_SHUTDOWN_RSP: + BTFMCODEC_DBG("BTM_BTFMCODEC_CTRL_MASTER_SHUTDOWN_RSP"); + break; + case BTM_BTFMCODEC_BEARER_SWITCH_IND: + BTFMCODEC_DBG("BTM_BTFMCODEC_BEARER_SWITCH_IND"); + break; + default: + BTFMCODEC_ERR("wrong opcode:%04x", opcode); + } + kfree_skb(skb); + } + BTFMCODEC_DBG("end"); +} + +/* + * btfmcodec_pkt_write() - write() syscall for the btfmcodec_pkt device + * file: Pointer to the file structure. + * buf: Pointer to the userspace buffer. + * count: Number bytes to read from the file. + * ppos: Pointer to the position into the file. + * + * This function is used to write the data to btfmcodec dev node when + * userspace client do a write() system call. All input arguments are + * validated by the virtual file system before calling this function. + */ +static ssize_t btfmcodec_dev_write(struct file *file, + const char __user *buf, size_t count, loff_t *ppos) +{ + struct btfmcodec_data *btfmcodec = file->private_data; + struct btfmcodec_char_device *btfmcodec_dev= NULL; + struct sk_buff *skb; + void *kbuf; + int ret = 0; + + if (!btfmcodec || !btfmcodec->btfmcodec_dev || refcount_read(&btfmcodec->btfmcodec_dev->active_clients) == 0) { + BTFMCODEC_INFO("%s: %d\n", current->comm, task_pid_nr(current)); + return -EINVAL; + } else { + btfmcodec_dev = btfmcodec->btfmcodec_dev; + } + + if (mutex_lock_interruptible(&btfmcodec_dev->lock)) { + ret = -ERESTARTSYS; + goto free_kbuf; + } + + /* Hack for Now */ + if (count < MIN_PKT_LEN) { + BTFMCODEC_ERR("minimum packet len should be greater than 3 bytes"); + goto free_kbuf; + } + if (refcount_read(&btfmcodec->btfmcodec_dev->active_clients) == 0) { + BTFMCODEC_WARN("Client disconnected"); + ret = -ENETRESET; + goto free_kbuf; + } + + BTFMCODEC_DBG("begin to %s buffer_size %zu\n", btfmcodec_dev->dev_name, count); + kbuf = memdup_user(buf, count); + if (IS_ERR(kbuf)) { + ret = PTR_ERR(kbuf); + goto free_kbuf; + } + + /* Check whether we need a dedicated chunk of memory for this driver */ + skb = alloc_skb(count* sizeof(size_t), GFP_KERNEL); + if (!skb) { + BTFMCODEC_ERR("failed to allocate memory for recevied packet"); + ret = -ENOMEM; + goto free_kbuf; + } + + skb_put_data(skb, (uint8_t *)kbuf, count); + skb_queue_tail(&btfmcodec_dev->rxq, skb); + schedule_work(&btfmcodec_dev->rx_work); + + kfree(kbuf); + +free_kbuf: + mutex_unlock(&btfmcodec_dev->lock); + BTFMCODEC_DBG("finish to %s ret %d\n", btfmcodec_dev->dev_name, ret); + return ret; +} + +int btfmcodec_dev_enqueue_pkt(struct btfmcodec_char_device *btfmcodec_dev, uint8_t *buf, int len) +{ + struct sk_buff *skb; + unsigned long flags; + + BTFMCODEC_DBG("start"); + spin_lock_irqsave(&btfmcodec_dev->tx_queue_lock, flags); + skb = alloc_skb(len, GFP_ATOMIC); + if (!skb) { + BTFMCODEC_ERR("failed to allocate memory"); + spin_unlock_irqrestore(&btfmcodec_dev->tx_queue_lock, flags); + return -ENOMEM; + } + + skb_put_data(skb, buf, len); + skb_queue_tail(&btfmcodec_dev->txq, skb); + wake_up_interruptible(&btfmcodec_dev->readq); + spin_unlock_irqrestore(&btfmcodec_dev->tx_queue_lock, flags); + BTFMCODEC_DBG("end"); + return 0; +} + +/* + * btfmcodec_pkt_poll() - poll() syscall for the btfmcodec device + * file: Pointer to the file structure. + * wait: pointer to Poll table. + * + * This function is used to poll on the btfmcodec dev node when + * userspace client do a poll() system call. All input arguments are + * validated by the virtual file system before calling this function. + */ +static __poll_t btfmcodec_dev_poll(struct file *file, poll_table *wait) +{ + struct btfmcodec_data *btfmcodec = file->private_data; + struct btfmcodec_char_device *btfmcodec_dev= NULL; + __poll_t mask = 0; + unsigned long flags; + + BTFMCODEC_DBG("start"); + if (!btfmcodec || !btfmcodec->btfmcodec_dev || refcount_read(&btfmcodec->btfmcodec_dev->active_clients) == 0) { + BTFMCODEC_INFO("%s: %d\n", current->comm, task_pid_nr(current)); + return -EINVAL; + } else { + btfmcodec_dev = btfmcodec->btfmcodec_dev; + } + + /* Wait here for timeout or for a wakeup signal on readq */ + poll_wait(file, &btfmcodec_dev->readq, wait); + + mutex_lock(&btfmcodec_dev->lock); + /* recheck if the client has released by the driver */ + if (refcount_read(&btfmcodec_dev->active_clients) == 0) { + BTFMCODEC_WARN("port has been closed alreadt"); + mutex_unlock(&btfmcodec_dev->lock); + return POLLHUP; + } + + spin_lock_irqsave(&btfmcodec_dev->tx_queue_lock, flags); + /* Set flags if data is avilable to read */ + if (!skb_queue_empty(&btfmcodec_dev->txq)) + mask |= POLLIN | POLLRDNORM; + + spin_unlock_irqrestore(&btfmcodec_dev->tx_queue_lock, flags); + mutex_unlock(&btfmcodec_dev->lock); + + BTFMCODEC_DBG("end with reason %d", mask); + return mask; +} + +/* + * btfmcodec_dev_read() - read() syscall for the btfmcodec dev node + * file: Pointer to the file structure. + * buf: Pointer to the userspace buffer. + * count: Number bytes to read from the file. + * ppos: Pointer to the position into the file. + * + * This function is used to Read the data from btfmcodec pkt device when + * userspace client do a read() system call. All input arguments are + * validated by the virtual file system before calling this function. + */ +static ssize_t btfmcodec_dev_read(struct file *file, + char __user *buf, size_t count, loff_t *ppos) +{ + struct btfmcodec_data *btfmcodec = file->private_data; + struct btfmcodec_char_device *btfmcodec_dev= NULL; + unsigned long flags; + struct sk_buff *skb; + int use; + + BTFMCODEC_DBG("start"); + if (!btfmcodec || !btfmcodec->btfmcodec_dev || refcount_read(&btfmcodec->btfmcodec_dev->active_clients) == 0) { + BTFMCODEC_INFO("%s: %d\n", current->comm, task_pid_nr(current)); + return -EINVAL; + } else { + btfmcodec_dev = btfmcodec->btfmcodec_dev; + } + + spin_lock_irqsave(&btfmcodec_dev->tx_queue_lock, flags); + /* Wait for data in the queue */ + if (skb_queue_empty(&btfmcodec_dev->txq)) { + spin_unlock_irqrestore(&btfmcodec_dev->tx_queue_lock, flags); + + if (file->f_flags & O_NONBLOCK) + return -EAGAIN; + + /* Wait until we get data*/ + if (wait_event_interruptible(btfmcodec_dev->readq, + !skb_queue_empty(&btfmcodec_dev->txq))) + return -ERESTARTSYS; + + /* We lost the client while waiting */ + if (!refcount_read(&btfmcodec->btfmcodec_dev->active_clients)) + return -ENETRESET; + + spin_lock_irqsave(&btfmcodec_dev->tx_queue_lock, flags); + } + + skb = skb_dequeue(&btfmcodec_dev->txq); + spin_unlock_irqrestore(&btfmcodec_dev->tx_queue_lock, flags); + if (!skb) + return -EFAULT; + + use = min_t(size_t, count, skb->len); + if (copy_to_user(buf, skb->data, use)) + use = -EFAULT; + + kfree_skb(skb); + + BTFMCODEC_DBG("end for %s by %s:%d ret[%d]\n", btfmcodec_dev->dev_name, + current->comm, task_pid_nr(current), use); + + return use; +} static const struct file_operations btfmcodec_fops = { .owner = THIS_MODULE, -/* .open = glink_pkt_open, - .release = glink_pkt_release, - .read = glink_pkt_read, - .write = glink_pkt_write, - .poll = glink_pkt_poll, - .unlocked_ioctl = glink_pkt_ioctl, - .compat_ioctl = glink_pkt_ioctl, -*/}; + .open = btfmcodec_dev_open, + .release = btfmcodec_dev_release, + .write = btfmcodec_dev_write, + .poll = btfmcodec_dev_poll, + .read = btfmcodec_dev_read, + /* For Now add no hookups for below callbacks */ + .unlocked_ioctl = NULL, + .compat_ioctl = NULL, +}; static ssize_t btfmcodec_attributes_store(struct device *dev, struct device_attribute *attr, @@ -148,7 +457,7 @@ static int __init btfmcodec_init(void) // ToDo Rethink of having btfmcodec alone instead of btfmcodec btfmcodec->btfmcodec_dev = btfmcodec_dev; - refcount_set(&btfmcodec_dev->active_clients, 1); + refcount_set(&btfmcodec_dev->active_clients, 0); mutex_init(&btfmcodec_dev->lock); strlcpy(btfmcodec_dev->dev_name, "btfmcodec_dev", DEVICE_NAME_MAX_LEN); device_initialize(dev); @@ -158,6 +467,7 @@ static int __init btfmcodec_init(void) cdev_init(&btfmcodec_dev->cdev, &btfmcodec_fops); btfmcodec_dev->cdev.owner = THIS_MODULE; + btfmcodec_dev->btfmcodec = (struct btfmcodec_data *)btfmcodec; dev_set_name(dev, btfmcodec_dev->dev_name, btfmcodec_dev->reuse_minor); ret = cdev_add(&btfmcodec_dev->cdev, dev->devt, 1); if (ret) { @@ -183,6 +493,12 @@ static int __init btfmcodec_init(void) BTFMCODEC_INFO("created a node at /dev/%s with %u:%u\n", btfmcodec_dev->dev_name, dev_major, btfmcodec_dev->reuse_minor); + skb_queue_head_init(&btfmcodec_dev->rxq); + mutex_init(&btfmcodec_dev->lock); + INIT_WORK(&btfmcodec_dev->rx_work, btfmcodec_dev_rxwork); + init_waitqueue_head(&btfmcodec_dev->readq); + spin_lock_init(&btfmcodec_dev->tx_queue_lock); + skb_queue_head_init(&btfmcodec_dev->txq); return ret; free_device: @@ -222,6 +538,7 @@ static void __exit btfmcodec_deinit(void) } btfmcodec_dev = btfmcodec->btfmcodec_dev; + skb_queue_purge(&btfmcodec_dev->rxq); idr_remove(&dev_minor, btfmcodec_dev->reuse_minor); class_destroy(dev_class); unregister_chrdev_region(MAJOR(dev_major), 0); diff --git a/btfmcodec/btfm_codec_interface.c b/btfmcodec/btfm_codec_interface.c index cfd15d4e41..5a4aa30f07 100644 --- a/btfmcodec/btfm_codec_interface.c +++ b/btfmcodec/btfm_codec_interface.c @@ -166,6 +166,7 @@ static int btfmcodec_dai_prepare(struct snd_pcm_substream *substream, uint32_t sampling_rate = dai->rate; uint32_t direction = substream->stream; int id = dai->id; + int ret; BTFMCODEC_INFO("dai->name: %s, dai->id: %d, dai->rate: %d direction: %d", dai->name, @@ -174,8 +175,11 @@ static int btfmcodec_dai_prepare(struct snd_pcm_substream *substream, if (states.current_state != IDLE) { BTFMCODEC_WARN("Received probe when state is :%s", coverttostring(states.current_state)); } else if (dai_drv && dai_drv->dai_ops && dai_drv->dai_ops->hwep_prepare) { - return dai_drv->dai_ops->hwep_prepare((void *)btfmcodec->hwep_info, sampling_rate, + ret = dai_drv->dai_ops->hwep_prepare((void *)btfmcodec->hwep_info, sampling_rate, direction, id); + if (ret == 0 && test_bit(BTADV_AUDIO_MASTER_CONFIG, &btfmcodec->hwep_info->flags)) { + BTFMCODEC_DBG("configuring master now"); + } } else { return -1; } diff --git a/btfmcodec/include/btfm_codec.h b/btfmcodec/include/btfm_codec.h index 68a91fb8b9..46d4d86287 100644 --- a/btfmcodec/include/btfm_codec.h +++ b/btfmcodec/include/btfm_codec.h @@ -10,6 +10,7 @@ #include #include #include +#include #include "btfm_codec_hw_interface.h" #define BTFMCODEC_DBG(fmt, arg...) pr_err("%s: " fmt "\n", __func__, ## arg) @@ -45,6 +46,12 @@ struct btfmcodec_char_device { struct mutex lock; int reuse_minor; char dev_name[DEVICE_NAME_MAX_LEN]; + struct sk_buff_head rxq; + struct work_struct rx_work; + wait_queue_head_t readq; + spinlock_t tx_queue_lock; + struct sk_buff_head txq; + void *btfmcodec; }; struct btfmcodec_data { @@ -54,5 +61,6 @@ struct btfmcodec_data { struct hwep_data *hwep_info; }; +int btfmcodec_dev_enqueue_pkt(struct btfmcodec_char_device *, uint8_t *, int); struct btfmcodec_data *btfm_get_btfmcodec(void); #endif /*__LINUX_BTFM_CODEC_H */ diff --git a/btfmcodec/include/btfm_codec_pkt.h b/btfmcodec/include/btfm_codec_pkt.h new file mode 100644 index 0000000000..33432e22c7 --- /dev/null +++ b/btfmcodec/include/btfm_codec_pkt.h @@ -0,0 +1,49 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2023 Qualcomm Innovation Center, Inc. All rights reserved. + */ + +#ifndef __LINUX_BTFM_CODEC_PKT_H +#define __LINUX_BTFM_CODEC_PKT_H + +typedef uint16_t btm_opcode; + +struct btm_req { + btm_opcode opcode; + uint8_t len; + uint8_t *data; +}; + +struct btm_rsp { + btm_opcode opcode; + uint8_t status; +}; + +struct btm_ind { + btm_opcode opcode; + uint8_t len; + uint8_t *data; +}; + +#define BTM_BTFMCODEC_PREPARE_AUDIO_BEARER_SWITCH_REQ 0x5000 +#define BTM_BTFMCODEC_PREPARE_AUDIO_BEARER_SWITCH_RSP 0x5001 +#define BTM_BTFMCODEC_MASTER_CONFIG_REQ 0x5002 +#define BTM_BTFMCODEC_MASTER_CONFIG_RSP 0x5003 +#define BTM_BTFMCODEC_MASTER_SHUTDOWN_REQ 0x5004 +#define BTM_BTFMCODEC_CTRL_MASTER_SHUTDOWN_RSP 0x5005 +#define BTM_BTFMCODEC_BEARER_SWITCH_IND 0x50C8 +#define BTM_BTFMCODEC_TRANSPORT_SWITCH_FAILED_IND 0x50C9 + +struct btm_master_config_req { + btm_opcode opcode; + uint8_t len; + uint8_t stream_identifier; + uint32_t device_identifier; + uint32_t sampling_rate; + uint8_t bit_width; + uint8_t num_of_channels; + uint8_t channel_num; + uint8_t codec_id; +}; + +#endif /* __LINUX_BTFM_CODEC_PKT_H*/ From 4a2649332e9c7567d3ca6c9fb0a692e275dc7b4e Mon Sep 17 00:00:00 2001 From: Balakrishna Godavarthi Date: Mon, 2 Jan 2023 12:06:09 +0530 Subject: [PATCH 022/154] btfmcodec: Add btadv audio support This change adds below support for BT advance audio * Add support for codec type mixer control * Update slim driver to read master id, channel number. * Update slim driver to support HW EP. * Add support for transport switch based on the request CRs-Fixed: 3298745 Change-Id: Ica349cb6f3615f4dc51bbc3070c90d43eeba1cdd --- btfmcodec/Makefile | 2 +- btfmcodec/btfm_codec.c | 128 +++- btfmcodec/btfm_codec_btadv_interface.c | 314 +++++++++ btfmcodec/btfm_codec_interface.c | 596 ++++++++++++++++-- btfmcodec/include/btfm_codec.h | 44 +- .../include/btfm_codec_btadv_interface.h | 21 + btfmcodec/include/btfm_codec_hw_interface.h | 34 +- btfmcodec/include/btfm_codec_pkt.h | 87 ++- slimbus/Makefile | 2 +- slimbus/btfm_slim.c | 62 ++ slimbus/btfm_slim.h | 3 + slimbus/btfm_slim_hw_interface.c | 115 +++- slimbus/btfm_slim_hw_interface.h | 24 + 13 files changed, 1276 insertions(+), 156 deletions(-) create mode 100644 btfmcodec/btfm_codec_btadv_interface.c create mode 100644 btfmcodec/include/btfm_codec_btadv_interface.h diff --git a/btfmcodec/Makefile b/btfmcodec/Makefile index 966976f5b0..9b41a19b17 100644 --- a/btfmcodec/Makefile +++ b/btfmcodec/Makefile @@ -1,4 +1,4 @@ ccflags-y += -I$(BT_ROOT)/include ccflags-y += -I$(BT_ROOT)/btfmcodec/include -btfmcodec-objs := btfm_codec.o btfm_codec_hw_interface.o btfm_codec_interface.o +btfmcodec-objs := btfm_codec.o btfm_codec_hw_interface.o btfm_codec_interface.o btfm_codec_btadv_interface.o obj-$(CONFIG_BTFM_CODEC) += btfmcodec.o diff --git a/btfmcodec/btfm_codec.c b/btfmcodec/btfm_codec.c index a6e789df23..75da3097ca 100644 --- a/btfmcodec/btfm_codec.c +++ b/btfmcodec/btfm_codec.c @@ -24,7 +24,7 @@ struct btfmcodec_data *btfmcodec; struct device_driver driver = {.name = "btfmcodec-driver", .owner = THIS_MODULE}; struct btfmcodec_char_device *btfmcodec_dev; #define cdev_to_btfmchardev(_cdev) container_of(_cdev, struct btfmcodec_char_device, cdev) -#define MIN_PKT_LEN 0x3 +#define MIN_PKT_LEN 0x9 char *coverttostring(enum btfmcodec_states state) { switch (state) { @@ -63,15 +63,15 @@ static int btfmcodec_dev_open(struct inode *inode, struct file *file) { struct btfmcodec_char_device *btfmcodec_dev = cdev_to_btfmchardev(inode->i_cdev); struct btfmcodec_data *btfmcodec = (struct btfmcodec_data *)btfmcodec_dev->btfmcodec; - int active_clients = refcount_read(&btfmcodec_dev->active_clients); + unsigned int active_clients = refcount_read(&btfmcodec_dev->active_clients); btfmcodec->states.current_state = IDLE; /* Just a temp*/ - BTFMCODEC_INFO("File mode :%u", file->f_mode); + btfmcodec->states.next_state = IDLE; BTFMCODEC_INFO("for %s by %s:%d active_clients[%d]\n", btfmcodec_dev->dev_name, current->comm, task_pid_nr(current), refcount_read(&btfmcodec_dev->active_clients)); /* Don't allow a new client if already one is active. */ - if (active_clients > 0) { + if (active_clients > 1) { BTFMCODEC_WARN("%s: Not honoring open as other client is active", __func__); return EACCES; } @@ -95,12 +95,12 @@ static int btfmcodec_dev_release(struct inode *inode, struct file *file) struct btfmcodec_char_device *btfmcodec_dev = cdev_to_btfmchardev(inode->i_cdev); unsigned long flags; - BTFMCODEC_INFO("for %s by %s:%d active_clients[%d]\n", + BTFMCODEC_INFO("for %s by %s:%d active_clients[%u]\n", btfmcodec_dev->dev_name, current->comm, task_pid_nr(current), refcount_read(&btfmcodec_dev->active_clients)); refcount_dec(&btfmcodec_dev->active_clients); - if (refcount_read(&btfmcodec_dev->active_clients) == 0) { + if (refcount_read(&btfmcodec_dev->active_clients) == 1) { spin_lock_irqsave(&btfmcodec_dev->tx_queue_lock, flags); skb_queue_purge(&btfmcodec_dev->txq); /* Wakeup the device if waiting for the data */ @@ -110,42 +110,93 @@ static int btfmcodec_dev_release(struct inode *inode, struct file *file) skb_queue_purge(&btfmcodec_dev->rxq); } + btfmcodec->states.current_state = IDLE; + btfmcodec->states.next_state = IDLE; return 0; } -btm_opcode get_opcode (struct sk_buff *skb) +btm_opcode STREAM_TO_UINT32 (struct sk_buff *skb) { - return ((skb->data[0]<< 8) | skb->data[1]); + return (skb->data[0] | (skb->data[1] << 8) | + (skb->data[2] << 16) | (skb->data[3] << 24)); } static void btfmcodec_dev_rxwork(struct work_struct *work) { struct btfmcodec_char_device *btfmcodec_dev = container_of(work, struct btfmcodec_char_device, rx_work); struct sk_buff *skb; - struct btm_req *req_pkt; + uint32_t len; + uint8_t status; + int idx; BTFMCODEC_DBG("start"); while ((skb = skb_dequeue(&btfmcodec_dev->rxq))) { - btm_opcode opcode = get_opcode(skb); -// skb_pull(skb, sizeof(btm_opcode)); + btm_opcode opcode = STREAM_TO_UINT32(skb); + skb_pull(skb, sizeof(btm_opcode)); + len = STREAM_TO_UINT32(skb); + skb_pull(skb, sizeof(len)); switch (opcode) { case BTM_BTFMCODEC_PREPARE_AUDIO_BEARER_SWITCH_REQ: - req_pkt = (void *)skb->data; - req_pkt->opcode = opcode; - BTFMCODEC_DBG("BTM_BTFMCODEC_PREPARE_AUDIO_BEARER_SWITCH_REQ opcode %4x and len %d", req_pkt->opcode, req_pkt->len); - btfmcodec_dev_enqueue_pkt(btfmcodec_dev, skb->data, skb->len); + idx = BTM_PKT_TYPE_PREPARE_REQ; + BTFMCODEC_DBG("BTM_BTFMCODEC_PREPARE_AUDIO_BEARER_SWITCH_REQ"); + if (len == BTM_PREPARE_AUDIO_BEARER_SWITCH_REQ_LEN) { + btfmcodec_dev->status[idx] = skb->data[0]; + BTFMCODEC_INFO("prepare wq_prepare_bearer:%p", btfmcodec_dev->wq_prepare_bearer); + queue_work(btfmcodec_dev->workqueue, &btfmcodec_dev->wq_prepare_bearer); + } else { + BTFMCODEC_ERR("wrong packet format with len:%d", len); + } break; case BTM_BTFMCODEC_MASTER_CONFIG_RSP: - BTFMCODEC_DBG("BTM_BTFMCODEC_MASTER_CONFIG_RSP"); + idx = BTM_PKT_TYPE_MASTER_CONFIG_RSP; + if (len == BTM_MASTER_CONFIG_RSP_LEN) { + status = skb->data[1]; + if (status == MSG_SUCCESS) + btfmcodec_dev->status[idx] = BTM_RSP_RECV; + else + btfmcodec_dev->status[idx] = BTM_FAIL_RESP_RECV; + } else { + BTFMCODEC_ERR("wrong packet format with len:%d", len); + btfmcodec_dev->status[idx] = BTM_FAIL_RESP_RECV; + } + BTFMCODEC_INFO("Rx BTM_BTFMCODEC_MASTER_CONFIG_RSP status:%d", + status); + wake_up_interruptible(&btfmcodec_dev->rsp_wait_q[idx]); break; case BTM_BTFMCODEC_CTRL_MASTER_SHUTDOWN_RSP: - BTFMCODEC_DBG("BTM_BTFMCODEC_CTRL_MASTER_SHUTDOWN_RSP"); + idx = BTM_PKT_TYPE_MASTER_SHUTDOWN_RSP; + if (len == BTM_MASTER_CONFIG_RSP_LEN) { + status = skb->data[1]; + if (status == MSG_SUCCESS) + btfmcodec_dev->status[idx] = BTM_RSP_RECV; + else + btfmcodec_dev->status[idx] = BTM_FAIL_RESP_RECV; + } else { + BTFMCODEC_ERR("wrong packet format with len:%d", len); + btfmcodec_dev->status[idx] = BTM_FAIL_RESP_RECV; + } + BTFMCODEC_INFO("Rx BTM_BTFMCODEC_CTRL_MASTER_SHUTDOWN_RSP status:%d", + status); + wake_up_interruptible(&btfmcodec_dev->rsp_wait_q[idx]); break; case BTM_BTFMCODEC_BEARER_SWITCH_IND: - BTFMCODEC_DBG("BTM_BTFMCODEC_BEARER_SWITCH_IND"); + idx = BTM_PKT_TYPE_BEARER_SWITCH_IND; + if (len == BTM_BEARER_SWITCH_IND_LEN) { + status = skb->data[0]; + if (status == MSG_SUCCESS) + btfmcodec_dev->status[idx] = BTM_RSP_RECV; + else + btfmcodec_dev->status[idx] = BTM_FAIL_RESP_RECV; + } else { + BTFMCODEC_ERR("wrong packet format with len:%d", len); + btfmcodec_dev->status[idx] = BTM_FAIL_RESP_RECV; + } + BTFMCODEC_INFO("Rx BTM_BTFMCODEC_BEARER_SWITCH_IND status:%d", + status); + wake_up_interruptible(&btfmcodec_dev->rsp_wait_q[idx]); break; default: - BTFMCODEC_ERR("wrong opcode:%04x", opcode); + BTFMCODEC_ERR("wrong opcode:%08x", opcode); } kfree_skb(skb); } @@ -172,7 +223,7 @@ static ssize_t btfmcodec_dev_write(struct file *file, void *kbuf; int ret = 0; - if (!btfmcodec || !btfmcodec->btfmcodec_dev || refcount_read(&btfmcodec->btfmcodec_dev->active_clients) == 0) { + if (!btfmcodec || !btfmcodec->btfmcodec_dev || refcount_read(&btfmcodec->btfmcodec_dev->active_clients) == 1) { BTFMCODEC_INFO("%s: %d\n", current->comm, task_pid_nr(current)); return -EINVAL; } else { @@ -219,16 +270,22 @@ static ssize_t btfmcodec_dev_write(struct file *file, free_kbuf: mutex_unlock(&btfmcodec_dev->lock); BTFMCODEC_DBG("finish to %s ret %d\n", btfmcodec_dev->dev_name, ret); - return ret; + return ret < 0 ? ret : count; } -int btfmcodec_dev_enqueue_pkt(struct btfmcodec_char_device *btfmcodec_dev, uint8_t *buf, int len) +int btfmcodec_dev_enqueue_pkt(struct btfmcodec_char_device *btfmcodec_dev, void *buf, int len) { struct sk_buff *skb; unsigned long flags; + uint8_t *cmd = buf; BTFMCODEC_DBG("start"); spin_lock_irqsave(&btfmcodec_dev->tx_queue_lock, flags); + if (refcount_read(&btfmcodec_dev->active_clients) == 1) { + BTFMCODEC_WARN("no active clients discarding the packet"); + spin_unlock_irqrestore(&btfmcodec_dev->tx_queue_lock, flags); + return -EINVAL; + } skb = alloc_skb(len, GFP_ATOMIC); if (!skb) { BTFMCODEC_ERR("failed to allocate memory"); @@ -236,7 +293,7 @@ int btfmcodec_dev_enqueue_pkt(struct btfmcodec_char_device *btfmcodec_dev, uint8 return -ENOMEM; } - skb_put_data(skb, buf, len); + skb_put_data(skb, cmd, len); skb_queue_tail(&btfmcodec_dev->txq, skb); wake_up_interruptible(&btfmcodec_dev->readq); spin_unlock_irqrestore(&btfmcodec_dev->tx_queue_lock, flags); @@ -261,7 +318,7 @@ static __poll_t btfmcodec_dev_poll(struct file *file, poll_table *wait) unsigned long flags; BTFMCODEC_DBG("start"); - if (!btfmcodec || !btfmcodec->btfmcodec_dev || refcount_read(&btfmcodec->btfmcodec_dev->active_clients) == 0) { + if (!btfmcodec || !btfmcodec->btfmcodec_dev || refcount_read(&btfmcodec->btfmcodec_dev->active_clients) == 1) { BTFMCODEC_INFO("%s: %d\n", current->comm, task_pid_nr(current)); return -EINVAL; } else { @@ -273,7 +330,7 @@ static __poll_t btfmcodec_dev_poll(struct file *file, poll_table *wait) mutex_lock(&btfmcodec_dev->lock); /* recheck if the client has released by the driver */ - if (refcount_read(&btfmcodec_dev->active_clients) == 0) { + if (refcount_read(&btfmcodec_dev->active_clients) == 1) { BTFMCODEC_WARN("port has been closed alreadt"); mutex_unlock(&btfmcodec_dev->lock); return POLLHUP; @@ -312,7 +369,7 @@ static ssize_t btfmcodec_dev_read(struct file *file, int use; BTFMCODEC_DBG("start"); - if (!btfmcodec || !btfmcodec->btfmcodec_dev || refcount_read(&btfmcodec->btfmcodec_dev->active_clients) == 0) { + if (!btfmcodec || !btfmcodec->btfmcodec_dev || refcount_read(&btfmcodec->btfmcodec_dev->active_clients) == 1) { BTFMCODEC_INFO("%s: %d\n", current->comm, task_pid_nr(current)); return -EINVAL; } else { @@ -333,7 +390,7 @@ static ssize_t btfmcodec_dev_read(struct file *file, return -ERESTARTSYS; /* We lost the client while waiting */ - if (!refcount_read(&btfmcodec->btfmcodec_dev->active_clients)) + if (refcount_read(&btfmcodec->btfmcodec_dev->active_clients) == 1) return -ENETRESET; spin_lock_irqsave(&btfmcodec_dev->tx_queue_lock, flags); @@ -391,7 +448,7 @@ static ssize_t btfmcodec_attributes_show(struct device *dev, struct device_attribute *attr, char *buf) { -// struct btfmcodec_char_device *btfmcodec_dev = dev_to_btfmcodec(dev); +// struct btfmcodec_get_current_transport *btfmcodec_dev = dev_to_btfmcodec(dev); return 0; } @@ -409,7 +466,7 @@ static int __init btfmcodec_init(void) struct btfmcodec_state_machine *states; struct btfmcodec_char_device *btfmcodec_dev; struct device *dev; - int ret; + int ret, i; BTFMCODEC_INFO("starting up the module"); btfmcodec = kzalloc(sizeof(struct btfmcodec_data), GFP_KERNEL); @@ -457,7 +514,7 @@ static int __init btfmcodec_init(void) // ToDo Rethink of having btfmcodec alone instead of btfmcodec btfmcodec->btfmcodec_dev = btfmcodec_dev; - refcount_set(&btfmcodec_dev->active_clients, 0); + refcount_set(&btfmcodec_dev->active_clients, 1); mutex_init(&btfmcodec_dev->lock); strlcpy(btfmcodec_dev->dev_name, "btfmcodec_dev", DEVICE_NAME_MAX_LEN); device_initialize(dev); @@ -499,6 +556,17 @@ static int __init btfmcodec_init(void) init_waitqueue_head(&btfmcodec_dev->readq); spin_lock_init(&btfmcodec_dev->tx_queue_lock); skb_queue_head_init(&btfmcodec_dev->txq); + INIT_LIST_HEAD(&btfmcodec->config_head); + for (i = 0; i < BTM_PKT_TYPE_MAX; i++) { + init_waitqueue_head(&btfmcodec_dev->rsp_wait_q[i]); + } + mutex_init(&states->state_machine_lock); + btfmcodec_dev->workqueue = alloc_ordered_workqueue("btfmcodec_wq", 0); + if (!btfmcodec_dev->workqueue) { + BTFMCODEC_ERR("btfmcodec_dev Workqueue not initialized properly"); + ret = -ENOMEM; + goto free_device; + } return ret; free_device: diff --git a/btfmcodec/btfm_codec_btadv_interface.c b/btfmcodec/btfm_codec_btadv_interface.c new file mode 100644 index 0000000000..79f0488df6 --- /dev/null +++ b/btfmcodec/btfm_codec_btadv_interface.c @@ -0,0 +1,314 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 202333 Qualcomm Innovation Center, Inc. All rights reserved. + */ + +#include "btfm_codec.h" +#include "btfm_codec_pkt.h" +#include "btfm_codec_btadv_interface.h" + +void btfmcodec_initiate_hwep_shutdown(struct btfmcodec_char_device *btfmcodec_dev) +{ + wait_queue_head_t *rsp_wait_q = + &btfmcodec_dev->rsp_wait_q[BTM_PKT_TYPE_HWEP_SHUTDOWN]; + int ret; + uint8_t *status = &btfmcodec_dev->status[BTM_PKT_TYPE_HWEP_SHUTDOWN]; + + *status = BTM_WAITING_RSP; + BTFMCODEC_INFO("queuing work to shutdown"); + schedule_work(&btfmcodec_dev->wq_hwep_shutdown); + BTFMCODEC_INFO("waiting here for shutdown"); + ret = wait_event_interruptible_timeout(*rsp_wait_q, + *status != BTM_WAITING_RSP, + msecs_to_jiffies(BTM_MASTER_CONFIG_RSP_TIMEOUT)); + + /* Rethink of having a new packet to notify transport switch error */ + if (ret == 0) { + BTFMCODEC_ERR("failed to recevie to complete hwep_shutdown"); + flush_work(&btfmcodec_dev->wq_hwep_shutdown); + } else { + if (*status == BTM_RSP_RECV) { + BTFMCODEC_ERR("sucessfully closed hwep"); + return; + } else if (*status == BTM_FAIL_RESP_RECV) { + BTFMCODEC_ERR("Failed to close hwep"); + return; + } + } +} + +void btfmcodec_move_to_next_state(struct btfmcodec_state_machine *state) +{ + mutex_lock(&state->state_machine_lock); + if (state->current_state == BT_Connecting || + state->current_state == BTADV_AUDIO_Connecting) { + state->current_state += 1; + BTFMCODEC_INFO("moving from %s to %s", + coverttostring(state->current_state -1 ), + coverttostring(state->current_state)); + } else { + BTFMCODEC_ERR("State machine might have gone bad. reseting to default"); + state->current_state = IDLE; + } + + state->prev_state = IDLE; + mutex_unlock(&state->state_machine_lock); +} + +void btfmcodec_revert_current_state(struct btfmcodec_state_machine *state) +{ + mutex_lock(&state->state_machine_lock); + BTFMCODEC_INFO("reverting from %s to %s", coverttostring(state->current_state), + coverttostring(state->prev_state)); + state->current_state = state->prev_state; + state->prev_state = IDLE; + mutex_unlock(&state->state_machine_lock); +} + +void btfmcodec_set_current_state(struct btfmcodec_state_machine *state, + btfmcodec_state current_state) +{ + mutex_lock(&state->state_machine_lock); + BTFMCODEC_INFO("moving from %s to %s", coverttostring(state->current_state), + coverttostring(current_state)); + state->prev_state = state->current_state; + state->current_state = current_state; + mutex_unlock(&state->state_machine_lock); +} + +btfmcodec_state btfmcodec_get_current_transport(struct + btfmcodec_state_machine *state) +{ + btfmcodec_state current_state; + + mutex_lock(&state->state_machine_lock); + current_state = state->current_state; + mutex_unlock(&state->state_machine_lock); + return current_state; +} + +int btfmcodec_frame_transport_switch_ind_pkt(struct btfmcodec_char_device *btfmcodec_dev, + uint8_t active_transport, + uint8_t status) +{ + struct btm_ctrl_pkt rsp; + + rsp.opcode = BTM_BTFMCODEC_TRANSPORT_SWITCH_FAILED_IND; + rsp.len = BTM_PREPARE_AUDIO_BEARER_SWITCH_RSP_LEN; + rsp.active_transport = active_transport; + rsp.status = status; + return btfmcodec_dev_enqueue_pkt(btfmcodec_dev, &rsp, (rsp.len + + BTM_HEADER_LEN)); +} + +int btfmcodec_frame_prepare_bearer_rsp_pkt(struct btfmcodec_char_device *btfmcodec_dev, + uint8_t active_transport, + uint8_t status) +{ + struct btm_ctrl_pkt rsp; + + rsp.opcode = BTM_BTFMCODEC_PREPARE_AUDIO_BEARER_SWITCH_RSP; + rsp.len =BTM_PREPARE_AUDIO_BEARER_SWITCH_RSP_LEN; + rsp.active_transport = active_transport; + rsp.status = status; + return btfmcodec_dev_enqueue_pkt(btfmcodec_dev, &rsp, (rsp.len + + BTM_HEADER_LEN)); +} + +int btfmcodec_wait_for_bearer_ind(struct btfmcodec_char_device *btfmcodec_dev) +{ + wait_queue_head_t *rsp_wait_q = + &btfmcodec_dev->rsp_wait_q[BTM_PKT_TYPE_BEARER_SWITCH_IND]; + int ret; + uint8_t *status = &btfmcodec_dev->status[BTM_PKT_TYPE_BEARER_SWITCH_IND]; + + *status = BTM_WAITING_RSP; + ret = wait_event_interruptible_timeout(*rsp_wait_q, + *status != BTM_WAITING_RSP, + msecs_to_jiffies(BTM_MASTER_CONFIG_RSP_TIMEOUT)); + + if (ret == 0) { + BTFMCODEC_ERR("failed to recevie BTM_BEARER_SWITCH_IND"); + ret = -MSG_INTERNAL_TIMEOUT; + } else { + if (*status == BTM_RSP_RECV) { + ret = 0; + } else if (*status == BTM_FAIL_RESP_RECV) { + BTFMCODEC_ERR("Rx BTM_BEARER_SWITCH_IND with failure status"); + ret = -1; + } + } + + return ret; +} + +int btfmcodec_initiate_hwep_configuration(struct btfmcodec_char_device *btfmcodec_dev) +{ + wait_queue_head_t *rsp_wait_q = + &btfmcodec_dev->rsp_wait_q[BTM_PKT_TYPE_HWEP_CONFIG]; + uint8_t *status = &btfmcodec_dev->status[BTM_PKT_TYPE_HWEP_CONFIG]; + int ret; + + schedule_work(&btfmcodec_dev->wq_hwep_configure); + + ret = wait_event_interruptible_timeout(*rsp_wait_q, + *status != BTM_WAITING_RSP, + msecs_to_jiffies(BTM_MASTER_CONFIG_RSP_TIMEOUT)); + + if (ret == 0) { + BTFMCODEC_ERR("failed to recevie complete hwep configure"); + flush_work(&btfmcodec_dev->wq_hwep_configure); + ret = -1; + } else { + if (*status == BTM_RSP_RECV) { + ret = 0; + } else if (*status == BTM_FAIL_RESP_RECV) { + BTFMCODEC_ERR("Failed to close hwep moving back to previous state"); + ret = -1; + } + } + + return ret; +} + +void btfmcodec_configure_hwep(struct btfmcodec_char_device *btfmcodec_dev) +{ + struct btfmcodec_data *btfmcodec = (struct btfmcodec_data *)btfmcodec_dev->btfmcodec; + struct btfmcodec_state_machine *state = &btfmcodec->states; + int ret; + uint8_t status = MSG_SUCCESS; + + ret = btfmcodec_initiate_hwep_configuration(btfmcodec_dev); + if (ret < 0) { + status = MSG_FAILED_TO_CONFIGURE_HWEP; + /* Move back to BTADV_AUDIO_Connected from BT_Connecting */ + btfmcodec_revert_current_state(state); + } + + ret = btfmcodec_frame_transport_switch_ind_pkt(btfmcodec_dev, + btfmcodec_get_current_transport(state), status); + + if (status != MSG_SUCCESS) + return; + + if (ret < 0) { + ret = btfmcodec_wait_for_bearer_ind(btfmcodec_dev); + if (ret < 0) { + /* Move back to BTADV_AUDIO_Connected for failure cases*/ + BTFMCODEC_ERR("moving back to previous state"); + btfmcodec_revert_current_state(state); + /* close HWEP */ + btfmcodec_initiate_hwep_shutdown(btfmcodec_dev); + if (ret == -MSG_INTERNAL_TIMEOUT) { + btfmcodec_frame_transport_switch_ind_pkt(btfmcodec_dev, BT, + MSG_INTERNAL_TIMEOUT); + } + } else { + /* move from BT_Connecting to BT_Connected */ + btfmcodec_move_to_next_state(state); + } + } else { + /* add code to handle packet errors */ + } +} + +void btfmcodec_prepare_bearer(struct btfmcodec_char_device *btfmcodec_dev, + enum transport_type new_transport) +{ + struct btfmcodec_data *btfmcodec = (struct btfmcodec_data *)btfmcodec_dev->btfmcodec; + struct btfmcodec_state_machine *state = &btfmcodec->states; + btfmcodec_state current_state; + int ret = -1; + + if (new_transport > (ARRAY_SIZE(transport_type_text))) { + btfmcodec_frame_prepare_bearer_rsp_pkt(btfmcodec_dev, + (uint8_t) btfmcodec_get_current_transport(state), + MSG_WRONG_TRANSPORT_TYPE); + return; + } + + BTFMCODEC_INFO("Rx to switch from transport type %s to %s", + coverttostring(btfmcodec_get_current_transport(state)), + transport_type_text[new_transport - 1]); + + current_state = btfmcodec_get_current_transport(state); + if (new_transport == BT) { + /* If BT is already active. send +ve ack to BTADV Audio Manager */ + if (current_state == BT_Connected || + current_state == BT_Connecting) { + btfmcodec_frame_prepare_bearer_rsp_pkt(btfmcodec_dev, + (uint8_t)current_state, MSG_SUCCESS); + return; + } else if (current_state == BTADV_AUDIO_Connected || + current_state == BTADV_AUDIO_Connecting|| + current_state == IDLE) { + if (btfmcodec_is_valid_cache_avb(btfmcodec)) { + BTFMCODEC_INFO("detected BTADV audio Gaming usecase to BT usecase"); + btfmcodec_set_current_state(state, BT_Connecting); + btfmcodec_configure_hwep(btfmcodec_dev); + } else { + if (current_state != IDLE) + BTFMCODEC_INFO("detected BTADV Audio lossless to IDLE"); + BTFMCODEC_INFO("moving to IDLE as no config available"); + btfmcodec_set_current_state(state, IDLE); + btfmcodec_frame_prepare_bearer_rsp_pkt(btfmcodec_dev, + btfmcodec_get_current_transport(state), + MSG_SUCCESS); + /* No need wait for bearer switch indications as BTFMCODEC + * driver doesn't have configs to configure + */ + } + } + } else if(new_transport == BTADV) { + /* If BTADV audio is already active. send +ve ack to BTADV audio Manager */ + if (current_state == BTADV_AUDIO_Connecting || + current_state == BTADV_AUDIO_Connected) { + btfmcodec_frame_prepare_bearer_rsp_pkt(btfmcodec_dev, + (uint8_t)current_state, MSG_SUCCESS); + return; + } else { + btfmcodec_set_current_state(state, BTADV_AUDIO_Connecting); + if (btfmcodec_is_valid_cache_avb(btfmcodec)) { + BTFMCODEC_INFO("detected BT to BTADV audio Gaming usecase"); + } else { + BTFMCODEC_INFO("detected IDLE to BTADV audio lossless usecase"); + } + + ret = btfmcodec_frame_prepare_bearer_rsp_pkt(btfmcodec_dev, + BTADV_AUDIO_Connecting, MSG_SUCCESS); + if (ret < 0) + return; + + /* Wait here to get Bearer switch indication */ + ret = btfmcodec_wait_for_bearer_ind(btfmcodec_dev); + if (ret < 0) { + BTFMCODEC_ERR("moving back to previous state"); + btfmcodec_revert_current_state(state); + if (ret == -MSG_INTERNAL_TIMEOUT) { + btfmcodec_frame_transport_switch_ind_pkt( + btfmcodec_dev, BTADV, + MSG_INTERNAL_TIMEOUT); + } + } else { + btfmcodec_move_to_next_state(state); + } + if (ret < 0) + return; + + if (btfmcodec_is_valid_cache_avb(btfmcodec)) { + BTFMCODEC_INFO("Initiating BT port close..."); + btfmcodec_initiate_hwep_shutdown(btfmcodec_dev); + } + } + } +} + +void btfmcodec_wq_prepare_bearer(struct work_struct *work) +{ + struct btfmcodec_char_device *btfmcodec_dev = container_of(work, + struct btfmcodec_char_device, + wq_prepare_bearer); + int idx = BTM_PKT_TYPE_PREPARE_REQ; + BTFMCODEC_INFO(": with new transport:%d", btfmcodec_dev->status[idx]); + btfmcodec_prepare_bearer(btfmcodec_dev, btfmcodec_dev->status[idx]); +} diff --git a/btfmcodec/btfm_codec_interface.c b/btfmcodec/btfm_codec_interface.c index 5a4aa30f07..be360f34a9 100644 --- a/btfmcodec/btfm_codec_interface.c +++ b/btfmcodec/btfm_codec_interface.c @@ -6,23 +6,116 @@ #include #include "btfm_codec.h" #include "btfm_codec_interface.h" +#include "btfm_codec_pkt.h" +#include "btfm_codec_btadv_interface.h" static struct snd_soc_dai_driver *btfmcodec_dai_info; +uint32_t bits_per_second; + +static int btfm_codec_get_mixer_control(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_component *codec = kcontrol->private_data; + struct btfmcodec_data *btfmcodec = snd_soc_component_get_drvdata(codec); + struct hwep_data *hwepinfo = btfmcodec->hwep_info; + struct btfmcodec_state_machine states = btfmcodec->states; + struct snd_kcontrol_new *mixer_ctrl = hwepinfo->mixer_ctrl; + struct snd_ctl_elem_id id = kcontrol->id; + int num_mixer_ctrl = hwepinfo->num_mixer_ctrl; + int i = 0; + + BTFMCODEC_DBG(""); + if (states.current_state != IDLE) { + BTFMCODEC_WARN("Received probe when state is :%s", + coverttostring(states.current_state)); + } else { + for (; i < num_mixer_ctrl ; i++) { + BTFMCODEC_DBG("checking mixer_ctrl:%s and current mixer:%s", + id.name, mixer_ctrl[i].name); + if (!strncmp(id.name, mixer_ctrl[i].name, 64)) { + BTFMCODEC_DBG("Matched"); + mixer_ctrl[i].get(kcontrol, ucontrol); + break; + } + } + if (num_mixer_ctrl == i) + return 0; + } + return 1; +} + + +static int btfmcodec_put_mixer_control(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_component *codec = kcontrol->private_data; + struct btfmcodec_data *btfmcodec = snd_soc_component_get_drvdata(codec); + struct hwep_data *hwepinfo = btfmcodec->hwep_info; + struct btfmcodec_state_machine states = btfmcodec->states; + struct snd_kcontrol_new *mixer_ctrl = hwepinfo->mixer_ctrl; + struct snd_ctl_elem_id id = kcontrol->id; + int num_mixer_ctrl = hwepinfo->num_mixer_ctrl; + int i = 0; + + BTFMCODEC_DBG(""); + if (states.current_state != IDLE) { + BTFMCODEC_WARN("Received probe when state is :%s", + coverttostring(states.current_state)); + } else { + for (; i < num_mixer_ctrl ; i++) { + BTFMCODEC_DBG("checking mixer_ctrl:%s and current mixer:%s", + id.name, mixer_ctrl[i].name); + if (!strncmp(id.name, mixer_ctrl[i].name, 64)) { + BTFMCODEC_DBG("Matched"); + mixer_ctrl[i].put(kcontrol, ucontrol); + break; + } + } + if (num_mixer_ctrl == i) + return 0; + } + return 1; +} static int btfmcodec_codec_probe(struct snd_soc_component *codec) { struct btfmcodec_data *btfmcodec = snd_soc_component_get_drvdata(codec); - struct btfmcodec_state_machine states = btfmcodec->states; + struct btfmcodec_state_machine *state = &btfmcodec->states; struct hwep_data *hwep_info = btfmcodec->hwep_info; + int num_mixer_ctrl = hwep_info->num_mixer_ctrl; BTFMCODEC_DBG(""); // ToDo: check weather probe has to allowed when state if different - if (states.current_state != IDLE) { - BTFMCODEC_WARN("Received probe when state is :%s", coverttostring(states.current_state)); + if (btfmcodec_get_current_transport(state)!= IDLE) { + BTFMCODEC_WARN("Received probe when state is :%s", + coverttostring(btfmcodec_get_current_transport(state))); } else if (hwep_info->drv && hwep_info->drv->hwep_probe) { - return hwep_info->drv->hwep_probe(codec); + hwep_info->drv->hwep_probe(codec); + /* Register mixer control */ + if (hwep_info->mixer_ctrl && num_mixer_ctrl >= 1) { + struct snd_kcontrol_new *mixer_ctrl; + int i = 0; + mixer_ctrl = (struct snd_kcontrol_new *) + kzalloc(num_mixer_ctrl * + sizeof(struct snd_kcontrol_new), GFP_KERNEL); + if (!mixer_ctrl) { + BTFMCODEC_ERR("failed to register mixer controls"); + goto end; + } + + BTFMCODEC_INFO("Registering %d mixer controls", num_mixer_ctrl); + memcpy(mixer_ctrl, hwep_info->mixer_ctrl, num_mixer_ctrl * sizeof(struct snd_kcontrol_new)); + for (; i< num_mixer_ctrl; i++) { + BTFMCODEC_INFO("name of control:%s", mixer_ctrl[i].name); + mixer_ctrl[i].get = btfm_codec_get_mixer_control; + mixer_ctrl[i].put = btfmcodec_put_mixer_control; + } + snd_soc_add_component_controls(codec, mixer_ctrl, num_mixer_ctrl); + BTFMCODEC_INFO("CODEC address while registering mixer ctrl:%p", codec); + } } +end: // ToDo to add mixer control. return 0; } @@ -30,13 +123,14 @@ static int btfmcodec_codec_probe(struct snd_soc_component *codec) static void btfmcodec_codec_remove(struct snd_soc_component *codec) { struct btfmcodec_data *btfmcodec = snd_soc_component_get_drvdata(codec); - struct btfmcodec_state_machine states = btfmcodec->states; + struct btfmcodec_state_machine *state = &btfmcodec->states; struct hwep_data *hwep_info = btfmcodec->hwep_info; BTFMCODEC_DBG(""); // ToDo: check whether remove has to allowed when state if different - if (states.current_state != IDLE) { - BTFMCODEC_WARN("Received probe when state is :%s", coverttostring(states.current_state)); + if (btfmcodec_get_current_transport(state)!= IDLE) { + BTFMCODEC_WARN("Received probe when state is :%s", + coverttostring(btfmcodec_get_current_transport(state))); } else if (hwep_info->drv && hwep_info->drv->hwep_remove) { hwep_info->drv->hwep_remove(codec); } @@ -46,13 +140,14 @@ static int btfmcodec_codec_write(struct snd_soc_component *codec, unsigned int reg, unsigned int value) { struct btfmcodec_data *btfmcodec = snd_soc_component_get_drvdata(codec); - struct btfmcodec_state_machine states = btfmcodec->states; + struct btfmcodec_state_machine *state = &btfmcodec->states; struct hwep_data *hwep_info = btfmcodec->hwep_info; BTFMCODEC_DBG(""); - // ToDo: check whether remove has to allowed when state if different - if (states.current_state != IDLE) { - BTFMCODEC_WARN("Received probe when state is :%s", coverttostring(states.current_state)); + // ToDo: check whether write has to allowed when state if different + if (btfmcodec_get_current_transport(state)!= IDLE) { + BTFMCODEC_WARN("Received probe when state is :%s", + coverttostring(btfmcodec_get_current_transport(state))); } else if (hwep_info->drv && hwep_info->drv->hwep_remove) { return hwep_info->drv->hwep_write(codec, reg, value); } @@ -64,13 +159,14 @@ static unsigned int btfmcodec_codec_read(struct snd_soc_component *codec, unsigned int reg) { struct btfmcodec_data *btfmcodec = snd_soc_component_get_drvdata(codec); - struct btfmcodec_state_machine states = btfmcodec->states; + struct btfmcodec_state_machine *state = &btfmcodec->states; struct hwep_data *hwep_info = btfmcodec->hwep_info; BTFMCODEC_DBG(""); - // ToDo: check whether remove has to allowed when state if different - if (states.current_state != IDLE) { - BTFMCODEC_WARN("Received probe when state is :%s", coverttostring(states.current_state)); + // ToDo: check whether read has to allowed when state if different + if (btfmcodec_get_current_transport(state)!= IDLE) { + BTFMCODEC_WARN("Received probe when state is :%s", + coverttostring(btfmcodec_get_current_transport(state))); } else if (hwep_info->drv && hwep_info->drv->hwep_read) { return hwep_info->drv->hwep_read(codec, reg); } @@ -92,43 +188,178 @@ static inline void * btfmcodec_get_dai_drvdata(struct hwep_data *hwep_info) return hwep_info->dai_drv; } -static int btfmcodec_dai_startup(struct snd_pcm_substream *substream, - struct snd_soc_dai *dai) +int btfmcodec_hwep_startup(struct btfmcodec_data *btfmcodec) { - struct btfmcodec_data *btfmcodec = snd_soc_component_get_drvdata(dai->component); - struct btfmcodec_state_machine states = btfmcodec->states; - struct hwep_dai_driver *dai_drv = (struct hwep_dai_driver *)btfmcodec_get_dai_drvdata(btfmcodec->hwep_info); + struct hwep_data *hwep_info = btfmcodec->hwep_info; + struct hwep_dai_driver *dai_drv = (struct hwep_dai_driver *) + btfmcodec_get_dai_drvdata(hwep_info); - BTFMCODEC_DBG("substream = %s stream = %d dai->name = %s", - substream->name, substream->stream, dai->name); - - // ToDo: check whether statup has to allowed when state if different - if (states.current_state != IDLE) { - BTFMCODEC_WARN("Received probe when state is :%s", coverttostring(states.current_state)); - } else if (dai && dai_drv->dai_ops && dai_drv->dai_ops->hwep_startup) { + if (dai_drv && dai_drv->dai_ops && dai_drv->dai_ops->hwep_startup) { return dai_drv->dai_ops->hwep_startup((void *)btfmcodec->hwep_info); } else { return -1; } +} + +static int btfmcodec_dai_startup(struct snd_pcm_substream *substream, + struct snd_soc_dai *dai) +{ + struct btfmcodec_data *btfmcodec = snd_soc_component_get_drvdata(dai->component); + struct btfmcodec_state_machine *state = &btfmcodec->states; + + BTFMCODEC_DBG("substream = %s stream = %d dai->name = %s", + substream->name, substream->stream, dai->name); + + if (btfmcodec_get_current_transport(state) != IDLE && + btfmcodec_get_current_transport(state) != BT_Connected) { + BTFMCODEC_DBG("Not allowing as state is:%s", + coverttostring(btfmcodec_get_current_transport(state))); + } else { + return btfmcodec_hwep_startup(btfmcodec); + } return 0; } +int btfmcodec_hwep_shutdown(struct btfmcodec_data *btfmcodec, int id) +{ + struct hwep_data *hwep_info = btfmcodec->hwep_info; + struct btfmcodec_char_device *btfmcodec_dev = btfmcodec->btfmcodec_dev; + struct hwep_dai_driver *dai_drv = (struct hwep_dai_driver *) + btfmcodec_get_dai_drvdata(hwep_info); + struct btfmcodec_state_machine *state = &btfmcodec->states; + struct btm_master_shutdown_req shutdown_req; + wait_queue_head_t *rsp_wait_q = + &btfmcodec_dev->rsp_wait_q[BTM_PKT_TYPE_MASTER_SHUTDOWN_RSP]; + uint8_t *status = &btfmcodec_dev->status[BTM_PKT_TYPE_MASTER_SHUTDOWN_RSP]; + int ret = 0; + + /* for master configurations failure cases, we don't need to send + * shutdown request + */ + if (btfmcodec_get_current_transport(state) == BT_Connected) { + BTFMCODEC_DBG("sending master shutdown request.."); + shutdown_req.opcode = BTM_BTFMCODEC_MASTER_SHUTDOWN_REQ; + shutdown_req.len = BTM_MASTER_SHUTDOWN_REQ_LEN; + shutdown_req.stream_id = id; + /* See if we need to protect below with lock */ + *status = BTM_WAITING_RSP; + btfmcodec_dev_enqueue_pkt(btfmcodec_dev, &shutdown_req, (shutdown_req.len + + BTM_HEADER_LEN)); + + ret = wait_event_interruptible_timeout(*rsp_wait_q, + (*status) != BTM_WAITING_RSP, + msecs_to_jiffies(BTM_MASTER_CONFIG_RSP_TIMEOUT)); + if (ret == 0) { + BTFMCODEC_ERR("failed to recevie response from BTADV audio Manager"); + } else { + if (*status == BTM_RSP_RECV) + ret = 0; + else if (*status == BTM_FAIL_RESP_RECV) + ret = -1; + } + } else { + BTFMCODEC_WARN("Not sending master shutdown request as state is:%s", + coverttostring(btfmcodec_get_current_transport(state))); + } + + if (dai_drv && dai_drv->dai_ops && dai_drv->dai_ops->hwep_shutdown) { + dai_drv->dai_ops->hwep_shutdown((void *)btfmcodec->hwep_info, id); + } + + return ret; +} + +void btfmcodec_wq_hwep_shutdown(struct work_struct *work) +{ + struct btfmcodec_char_device *btfmcodec_dev = container_of(work, + struct btfmcodec_char_device, + wq_hwep_shutdown); + struct btfmcodec_data *btfmcodec = (struct btfmcodec_data *)btfmcodec_dev->btfmcodec; + struct list_head *head = &btfmcodec->config_head; + struct hwep_configurations *hwep_configs = NULL; + int ret = -1; + int idx = BTM_PKT_TYPE_HWEP_SHUTDOWN; + + BTFMCODEC_INFO(" starting shutdown"); + /* Just check if first Rx has to be closed first or + * any order should be ok. + */ + list_for_each_entry(hwep_configs, head, dai_list) { + BTFMCODEC_INFO("shuting down dai id:%d", hwep_configs->stream_id); + ret = btfmcodec_hwep_shutdown(btfmcodec, hwep_configs->stream_id); + if (ret < 0) { + BTFMCODEC_ERR("failed to shutdown master with id", hwep_configs->stream_id); + break; + } + } + + if (ret < 0) + btfmcodec_dev->status[idx] = BTM_FAIL_RESP_RECV; + else + btfmcodec_dev->status[idx] = BTM_RSP_RECV; + + wake_up_interruptible(&btfmcodec_dev->rsp_wait_q[idx]); +} + +static int btfmcodec_delete_configs(struct btfmcodec_data *btfmcodec, uint8_t id) +{ + struct list_head *head = &btfmcodec->config_head; + struct hwep_configurations *hwep_configs; + int ret = -1; + + list_for_each_entry(hwep_configs, head, dai_list) { + if (hwep_configs->stream_id == id) { + BTFMCODEC_INFO("deleting configs with id %d", id); + list_del(&hwep_configs->dai_list); + ret = 1; + break; + } + } + + return ret; +} + static void btfmcodec_dai_shutdown(struct snd_pcm_substream *substream, struct snd_soc_dai *dai) { struct btfmcodec_data *btfmcodec = snd_soc_component_get_drvdata(dai->component); - struct btfmcodec_state_machine states = btfmcodec->states; - struct hwep_dai_driver *dai_drv = (struct hwep_dai_driver *)btfmcodec_get_dai_drvdata(btfmcodec->hwep_info); + struct btfmcodec_state_machine *state = &btfmcodec->states; BTFMCODEC_DBG("dai->name: %s, dai->id: %d, dai->rate: %d", dai->name, dai->id, dai->rate); - // ToDo: check whether statup has to allowed when state if different - if (states.current_state != IDLE) { - BTFMCODEC_WARN("Received probe when state is :%s", coverttostring(states.current_state)); - } else if (dai && dai_drv->dai_ops && dai_drv->dai_ops->hwep_shutdown) { - dai_drv->dai_ops->hwep_shutdown((void *)btfmcodec->hwep_info, dai->id); + if (btfmcodec_get_current_transport(state) != IDLE && + btfmcodec_get_current_transport(state) != BT_Connected) { + BTFMCODEC_WARN("not allowing shutdown as state is:%s", + coverttostring(btfmcodec_get_current_transport(state))); + /* Delete stored configs */ + btfmcodec_delete_configs(btfmcodec, dai->id); + } else { + /* first master shutdown has to done */ + btfmcodec_hwep_shutdown(btfmcodec, dai->id); + btfmcodec_delete_configs(btfmcodec, dai->id); + if (!btfmcodec_is_valid_cache_avb(btfmcodec)) + btfmcodec_set_current_state(state, IDLE); + else { + BTFMCODEC_WARN("valid stream id is available not updating state\n"); + btfmcodec_set_current_state(state, BT_Connected); + } + } +} + +int btfmcodec_hwep_hw_params (struct btfmcodec_data *btfmcodec, uint32_t bps, + uint32_t direction) +{ + struct hwep_data *hwep_info = btfmcodec->hwep_info; + struct hwep_dai_driver *dai_drv = (struct hwep_dai_driver *) + btfmcodec_get_dai_drvdata(hwep_info); + + if (dai_drv && dai_drv->dai_ops && dai_drv->dai_ops->hwep_hw_params) { + return dai_drv->dai_ops->hwep_hw_params((void *)btfmcodec->hwep_info, + bps, direction); + } else { + return -1; } } @@ -137,55 +368,214 @@ static int btfmcodec_dai_hw_params(struct snd_pcm_substream *substream, struct snd_soc_dai *dai) { struct btfmcodec_data *btfmcodec = snd_soc_component_get_drvdata(dai->component); - struct btfmcodec_state_machine states = btfmcodec->states; - struct hwep_dai_driver *dai_drv = (struct hwep_dai_driver *)btfmcodec_get_dai_drvdata(btfmcodec->hwep_info); + struct btfmcodec_state_machine *state = &btfmcodec->states; uint32_t bps = params_width(params); uint32_t direction = substream->stream; BTFMCODEC_DBG("dai->name = %s DAI-ID %x rate %d bps %d num_ch %d", dai->name, dai->id, params_rate(params), params_width(params), params_channels(params)); - // ToDo: check whether hw_params has to allowed when state if different - if (states.current_state != IDLE) { - BTFMCODEC_WARN("Received probe when state is :%s", coverttostring(states.current_state)); - } else if (dai_drv && dai_drv->dai_ops && dai_drv->dai_ops->hwep_hw_params) { - return dai_drv->dai_ops->hwep_hw_params((void *)btfmcodec->hwep_info, bps, direction); + + if (btfmcodec_get_current_transport(state) != IDLE && + btfmcodec_get_current_transport(state) != BT_Connected) { + BTFMCODEC_WARN("caching bps as state is :%s", + coverttostring(btfmcodec_get_current_transport(state))); + bits_per_second = bps; + } else { + return btfmcodec_hwep_hw_params(btfmcodec, bps, direction); + } + + return 0; +} + +bool btfmcodec_is_valid_cache_avb(struct btfmcodec_data *btfmcodec) +{ + struct list_head *head = &btfmcodec->config_head; + struct hwep_configurations *hwep_configs; + bool cache_avb = false; + + list_for_each_entry(hwep_configs, head, dai_list) { + cache_avb = true; + break; + } + + return cache_avb; +} + +static int btfmcodec_check_and_cache_configs(struct btfmcodec_data *btfmcodec, + uint32_t sampling_rate, uint32_t direction, + int id, uint8_t codectype) +{ + struct list_head *head = &btfmcodec->config_head; + struct hwep_configurations *hwep_configs; + + list_for_each_entry(hwep_configs, head, dai_list) { + if (hwep_configs->stream_id == id) { + BTFMCODEC_WARN("previous entry for %d is already available", + id); + list_del(&hwep_configs->dai_list); + } + } + + hwep_configs = kzalloc(sizeof(struct hwep_configurations), + GFP_KERNEL); + if (!hwep_configs) { + BTFMCODEC_ERR("failed to allocate memory"); + return -ENOMEM; + } + + hwep_configs->stream_id = id; /* Stream identifier */ + hwep_configs->sample_rate = sampling_rate; + hwep_configs->bit_width = bits_per_second; + hwep_configs->codectype = codectype; + hwep_configs->direction = direction; + + list_add(&hwep_configs->dai_list, head); + BTFMCODEC_INFO("added dai id:%d to list with sampling_rate :%u, direction:%u", id, sampling_rate, direction); + return 1; +} + +static int btfmcodec_configure_master(struct btfmcodec_data *btfmcodec, uint8_t id) +{ + struct btfmcodec_char_device *btfmcodec_dev = btfmcodec->btfmcodec_dev; + struct hwep_data *hwep_info = btfmcodec->hwep_info; + struct master_hwep_configurations hwep_configs; + struct btm_master_config_req config_reg; + struct hwep_dai_driver *dai_drv = (struct hwep_dai_driver *) + btfmcodec_get_dai_drvdata(hwep_info); + wait_queue_head_t *rsp_wait_q = + &btfmcodec_dev->rsp_wait_q[BTM_PKT_TYPE_MASTER_CONFIG_RSP]; + uint8_t *status = &btfmcodec_dev->status[BTM_PKT_TYPE_MASTER_CONFIG_RSP]; + int ret = 0; + + if (dai_drv && dai_drv->dai_ops && dai_drv->dai_ops->hwep_get_configs) { + dai_drv->dai_ops->hwep_get_configs((void *)btfmcodec->hwep_info, + &hwep_configs, id); + } else { + BTFMCODEC_ERR("No hwep_get_configs is set by hw ep driver"); + return -1; + } + + BTFMCODEC_INFO("framing packet for %d", id); + config_reg.opcode = BTM_BTFMCODEC_MASTER_CONFIG_REQ; + config_reg.len = BTM_MASTER_CONFIG_REQ_LEN; + config_reg.stream_id = hwep_configs.stream_id; + config_reg.device_id = hwep_configs.device_id; + config_reg.sample_rate = hwep_configs.sample_rate; + config_reg.bit_width = hwep_configs.bit_width; + config_reg.num_channels = hwep_configs.num_channels; + config_reg.channel_num = hwep_configs.chan_num; + config_reg.codec_id = hwep_configs.codectype; + BTFMCODEC_DBG("================================================\n"); + BTFMCODEC_DBG("config_reg.len :%d", config_reg.len); + BTFMCODEC_DBG("config_reg.stream_id :%d", config_reg.stream_id); + BTFMCODEC_DBG("config_reg.device_id :%d", config_reg.device_id); + BTFMCODEC_DBG("config_reg.sample_rate :%d", config_reg.sample_rate); + BTFMCODEC_DBG("config_reg.bit_width :%d", config_reg.bit_width); + BTFMCODEC_DBG("config_reg.num_channels :%d", config_reg.num_channels); + BTFMCODEC_DBG("config_reg.channel_num :%d", config_reg.channel_num); + BTFMCODEC_DBG("config_reg.codec_id :%d", config_reg.codec_id); + BTFMCODEC_DBG("================================================\n"); + /* See if we need to protect below with lock */ + *status = BTM_WAITING_RSP; + btfmcodec_dev_enqueue_pkt(btfmcodec_dev, &config_reg, (config_reg.len + + BTM_HEADER_LEN)); + ret = wait_event_interruptible_timeout(*rsp_wait_q, + (*status) != BTM_WAITING_RSP, + msecs_to_jiffies(BTM_MASTER_CONFIG_RSP_TIMEOUT)); + if (ret == 0) { + BTFMCODEC_ERR("failed to recevie response from BTADV audio Manager"); + ret = -ETIMEDOUT; + } else { + if (*status == BTM_RSP_RECV) + return 0; + else if (*status == BTM_FAIL_RESP_RECV) + return -1; + } + + return ret; +} + +int btfmcodec_hwep_prepare(struct btfmcodec_data *btfmcodec, uint32_t sampling_rate, + uint32_t direction, int id) +{ + struct hwep_data *hwep_info = btfmcodec->hwep_info; + struct hwep_dai_driver *dai_drv = (struct hwep_dai_driver *) + btfmcodec_get_dai_drvdata(hwep_info); + struct btfmcodec_state_machine *state = &btfmcodec->states; + + int ret; + if (dai_drv && dai_drv->dai_ops && dai_drv->dai_ops->hwep_prepare) { + ret = dai_drv->dai_ops->hwep_prepare((void *)hwep_info, sampling_rate, + direction, id); + if (ret == 0 && test_bit(BTADV_AUDIO_MASTER_CONFIG, &hwep_info->flags)) { + ret = btfmcodec_configure_master(btfmcodec, (uint8_t)id); + if (ret < 0) { + BTFMCODEC_ERR("failed to configure master error %d", ret); + /* close slave port and reset the state*/ + btfmcodec_set_current_state(state, IDLE); + /* we don't need to do shutdown, ASOC is doing it */ +// btfmcodec_hwep_shutdown(btfmcodec, id); + } else { + btfmcodec_set_current_state(state, BT_Connected); + } + } } else { return -1; } - return 0; + return ret; } static int btfmcodec_dai_prepare(struct snd_pcm_substream *substream, struct snd_soc_dai *dai) { struct btfmcodec_data *btfmcodec = snd_soc_component_get_drvdata(dai->component); - struct btfmcodec_state_machine states = btfmcodec->states; - struct hwep_dai_driver *dai_drv = (struct hwep_dai_driver *)btfmcodec_get_dai_drvdata(btfmcodec->hwep_info); + struct btfmcodec_state_machine *state = &btfmcodec->states; + struct hwep_data *hwep_info = btfmcodec->hwep_info; + struct hwep_dai_driver *dai_drv = (struct hwep_dai_driver *) + btfmcodec_get_dai_drvdata(hwep_info); + uint8_t *codectype = dai_drv->dai_ops->hwep_codectype; uint32_t sampling_rate = dai->rate; uint32_t direction = substream->stream; int id = dai->id; int ret; + BTFMCODEC_INFO("dai->name: %s, dai->id: %d, dai->rate: %d direction: %d", + dai->name, id, sampling_rate, direction); - BTFMCODEC_INFO("dai->name: %s, dai->id: %d, dai->rate: %d direction: %d", dai->name, - id, sampling_rate, direction); - // ToDo: check whether hw_params has to allowed when state if different - if (states.current_state != IDLE) { - BTFMCODEC_WARN("Received probe when state is :%s", coverttostring(states.current_state)); - } else if (dai_drv && dai_drv->dai_ops && dai_drv->dai_ops->hwep_prepare) { - ret = dai_drv->dai_ops->hwep_prepare((void *)btfmcodec->hwep_info, sampling_rate, - direction, id); - if (ret == 0 && test_bit(BTADV_AUDIO_MASTER_CONFIG, &btfmcodec->hwep_info->flags)) { - BTFMCODEC_DBG("configuring master now"); + if (btfmcodec_get_current_transport(state) != IDLE && + btfmcodec_get_current_transport(state) != BT_Connected) { + BTFMCODEC_WARN("caching required info as state is:%s", + coverttostring(btfmcodec_get_current_transport(state))); + ret = btfmcodec_check_and_cache_configs(btfmcodec, sampling_rate, direction, + id, *codectype); + } else { + ret = btfmcodec_hwep_prepare(btfmcodec, sampling_rate, direction, id); + if (ret >= 0) { + btfmcodec_check_and_cache_configs(btfmcodec, sampling_rate, direction, + id, *codectype); } + } + + return ret; +} + +int btfmcodec_hwep_set_channel_map(void *hwep_info, unsigned int tx_num, + unsigned int *tx_slot, unsigned int rx_num, + unsigned int *rx_slot) +{ + struct hwep_dai_driver *dai_drv = (struct hwep_dai_driver *) + btfmcodec_get_dai_drvdata(hwep_info); + + if (dai_drv && dai_drv->dai_ops && dai_drv->dai_ops->hwep_set_channel_map) { + return dai_drv->dai_ops->hwep_set_channel_map(hwep_info, tx_num, + tx_slot, rx_num, + rx_slot); } else { return -1; } - return 0; - return 0; } static int btfmcodec_dai_set_channel_map(struct snd_soc_dai *dai, @@ -194,44 +584,95 @@ static int btfmcodec_dai_set_channel_map(struct snd_soc_dai *dai, { struct btfmcodec_data *btfmcodec = snd_soc_component_get_drvdata(dai->component); struct btfmcodec_state_machine states = btfmcodec->states; - struct hwep_dai_driver *dai_drv = (struct hwep_dai_driver *)btfmcodec_get_dai_drvdata(btfmcodec->hwep_info); BTFMCODEC_DBG(""); // ToDo: check whether hw_params has to allowed when state if different if (states.current_state != IDLE) { BTFMCODEC_WARN("Received probe when state is :%s", coverttostring(states.current_state)); - } else if (dai_drv && dai_drv->dai_ops && dai_drv->dai_ops->hwep_set_channel_map) { - return dai_drv->dai_ops->hwep_set_channel_map((void *)btfmcodec->hwep_info, tx_num, - tx_slot, rx_num, rx_slot); } else { - return -1; + return btfmcodec_hwep_set_channel_map((void *)btfmcodec->hwep_info, tx_num, + tx_slot, rx_num, rx_slot); } return 0; } + +int btfmcodec_hwep_get_channel_map(void *hwep_info, unsigned int *tx_num, + unsigned int *tx_slot, unsigned int *rx_num, + unsigned int *rx_slot, int id) +{ + struct hwep_dai_driver *dai_drv = (struct hwep_dai_driver *) + btfmcodec_get_dai_drvdata(hwep_info); + + if (dai_drv && dai_drv->dai_ops && dai_drv->dai_ops->hwep_get_channel_map) { + return dai_drv->dai_ops->hwep_get_channel_map(hwep_info, tx_num, + tx_slot, rx_num, + rx_slot, id); + } else { + return -1; + } +} + static int btfmcodec_dai_get_channel_map(struct snd_soc_dai *dai, unsigned int *tx_num, unsigned int *tx_slot, unsigned int *rx_num, unsigned int *rx_slot) { struct btfmcodec_data *btfmcodec = snd_soc_component_get_drvdata(dai->component); - struct btfmcodec_state_machine states = btfmcodec->states; - struct hwep_dai_driver *dai_drv = (struct hwep_dai_driver *)btfmcodec_get_dai_drvdata(btfmcodec->hwep_info); +// struct btfmcodec_state_machine states = btfmcodec->states; BTFMCODEC_DBG(""); - // ToDo: check whether hw_params has to allowed when state if different - if (states.current_state != IDLE) { + // ToDo: get_channel_map is not needed for new driver +/* if (states.current_state != IDLE) { BTFMCODEC_WARN("Received probe when state is :%s", coverttostring(states.current_state)); - } else if (dai_drv && dai_drv->dai_ops && dai_drv->dai_ops->hwep_get_channel_map) { - return dai_drv->dai_ops->hwep_get_channel_map((void *)btfmcodec->hwep_info, tx_num, - tx_slot, rx_num, rx_slot, dai->id); } else { - return -1; - } +*/ return btfmcodec_hwep_get_channel_map((void *)btfmcodec->hwep_info, + tx_num, tx_slot, rx_num, + rx_slot, dai->id); +// } return 0; } +void btfmcodec_wq_hwep_configure(struct work_struct *work) +{ + struct btfmcodec_char_device *btfmcodec_dev = container_of(work, + struct btfmcodec_char_device, + wq_hwep_configure); + struct btfmcodec_data *btfmcodec = (struct btfmcodec_data *)btfmcodec_dev->btfmcodec; + struct list_head *head = &btfmcodec->config_head; + struct hwep_configurations *hwep_configs = NULL; + int ret; + int idx = BTM_PKT_TYPE_HWEP_CONFIG; + uint32_t sample_rate, direction; + uint8_t id, bit_width, codectype; + + list_for_each_entry(hwep_configs, head, dai_list) { + id = hwep_configs->stream_id; + sample_rate = hwep_configs->sample_rate; + bit_width = hwep_configs->bit_width; + codectype = hwep_configs->codectype; + direction = hwep_configs->direction; + + BTFMCODEC_INFO("configuring dai id:%d with sampling rate:%d bit_width:%d", id, sample_rate, bit_width); + ret = btfmcodec_hwep_startup(btfmcodec); + if (ret >= 0) + ret = btfmcodec_hwep_hw_params(btfmcodec, bit_width, direction); + if (ret >= 0) + ret = btfmcodec_hwep_prepare(btfmcodec, sample_rate, direction, id); + if (ret < 0) { + BTFMCODEC_ERR("failed to configure hwep", hwep_configs->stream_id); + break; + } + } + + if (ret < 0) + btfmcodec_dev->status[idx] = BTM_FAIL_RESP_RECV; + else + btfmcodec_dev->status[idx] = BTM_RSP_RECV; + + wake_up_interruptible(&btfmcodec_dev->rsp_wait_q[idx]); +} static struct snd_soc_dai_ops btfmcodec_dai_ops = { .startup = btfmcodec_dai_startup, .shutdown = btfmcodec_dai_shutdown, @@ -244,11 +685,13 @@ static struct snd_soc_dai_ops btfmcodec_dai_ops = { int btfm_register_codec(struct hwep_data *hwep_info) { struct btfmcodec_data *btfmcodec; + struct btfmcodec_char_device *btfmcodec_dev; struct device *dev; struct hwep_dai_driver *dai_drv; int i, ret; btfmcodec = btfm_get_btfmcodec(); + btfmcodec_dev = btfmcodec->btfmcodec_dev; dev = &btfmcodec->dev; btfmcodec_dai_info = kzalloc((sizeof(struct snd_soc_dai_driver) * hwep_info->num_dai), GFP_KERNEL); if (!btfmcodec_dai_info) { @@ -269,6 +712,19 @@ int btfm_register_codec(struct hwep_data *hwep_info) BTFMCODEC_INFO("slim bus driver name:%s", dev->driver->name); ret = snd_soc_register_component(dev, &btfmcodec_codec_component, btfmcodec_dai_info, hwep_info->num_dai); + BTFMCODEC_INFO("Dev node address: %p", dev); + BTFMCODEC_INFO("btfmcodec address :%p, btfmcodec"); + BTFMCODEC_INFO("HWEPINFO address:%p", hwep_info); + BTFMCODEC_INFO("btfmcodec_dev INFO address:%p", btfmcodec->btfmcodec_dev); + BTFMCODEC_INFO("before wq_hwep_shutdown:%p", btfmcodec_dev->wq_hwep_shutdown); + BTFMCODEC_INFO("before wq_prepare_bearer:%p", btfmcodec_dev->wq_prepare_bearer); + INIT_WORK(&btfmcodec_dev->wq_hwep_shutdown, btfmcodec_wq_hwep_shutdown); + INIT_WORK(&btfmcodec_dev->wq_prepare_bearer, btfmcodec_wq_prepare_bearer); + INIT_WORK(&btfmcodec_dev->wq_hwep_configure, btfmcodec_wq_hwep_configure); + BTFMCODEC_INFO("after wq_hwep_shutdown:%p", btfmcodec_dev->wq_hwep_shutdown); + BTFMCODEC_INFO("after wq_prepare_bearer:%p", btfmcodec_dev->wq_prepare_bearer); + BTFMCODEC_INFO("btfmcodec_wq_prepare_bearer:%p", btfmcodec_wq_prepare_bearer); + BTFMCODEC_INFO("btfmcodec_wq_hwep_shutdown:%p", btfmcodec_wq_hwep_shutdown); return ret; } diff --git a/btfmcodec/include/btfm_codec.h b/btfmcodec/include/btfm_codec.h index 46d4d86287..4ed3ecea44 100644 --- a/btfmcodec/include/btfm_codec.h +++ b/btfmcodec/include/btfm_codec.h @@ -20,24 +20,36 @@ #define DEVICE_NAME_MAX_LEN 64 -enum btfmcodec_states { - /*Default state of btfm codec driver */ +typedef enum btfmcodec_states { + /*Default state of kernel proxy driver */ IDLE = 0, - /* When BT is active transport */ - BT_Connected = 1, /* Waiting for BT bearer indication after configuring HW ports */ - BT_Connecting = 2, - /* When BTADV_AUDIO is active transport */ - BTADV_AUDIO_Connected = 3, - /* Waiting for BTADV_AUDIO bearer switch indications */ - BTADV_AUDIO_Connecting = 4 + BT_Connecting = 1, + /* When BT is active transport */ + BT_Connected = 2, + /* Waiting for BTADV Audio bearer switch indications */ + BTADV_AUDIO_Connecting = 3, + /* When BTADV audio is active transport */ + BTADV_AUDIO_Connected = 4 +} btfmcodec_state; + +enum btfm_pkt_type { + BTM_PKT_TYPE_PREPARE_REQ = 0, + BTM_PKT_TYPE_MASTER_CONFIG_RSP, + BTM_PKT_TYPE_MASTER_SHUTDOWN_RSP, + BTM_PKT_TYPE_BEARER_SWITCH_IND, + BTM_PKT_TYPE_HWEP_SHUTDOWN, + BTM_PKT_TYPE_HWEP_CONFIG, + BTM_PKT_TYPE_MAX, }; + char *coverttostring(enum btfmcodec_states); struct btfmcodec_state_machine { - enum btfmcodec_states prev_state; - enum btfmcodec_states current_state; - enum btfmcodec_states next_state; + struct mutex state_machine_lock; + btfmcodec_state prev_state; + btfmcodec_state current_state; + btfmcodec_state next_state; }; struct btfmcodec_char_device { @@ -46,11 +58,17 @@ struct btfmcodec_char_device { struct mutex lock; int reuse_minor; char dev_name[DEVICE_NAME_MAX_LEN]; + struct workqueue_struct *workqueue; struct sk_buff_head rxq; struct work_struct rx_work; + struct work_struct wq_hwep_shutdown; + struct work_struct wq_prepare_bearer; + struct work_struct wq_hwep_configure; wait_queue_head_t readq; spinlock_t tx_queue_lock; struct sk_buff_head txq; + wait_queue_head_t rsp_wait_q[BTM_PKT_TYPE_MAX]; + uint8_t status[BTM_PKT_TYPE_MAX]; void *btfmcodec; }; @@ -59,8 +77,8 @@ struct btfmcodec_data { struct btfmcodec_state_machine states; struct btfmcodec_char_device *btfmcodec_dev; struct hwep_data *hwep_info; + struct list_head config_head; }; -int btfmcodec_dev_enqueue_pkt(struct btfmcodec_char_device *, uint8_t *, int); struct btfmcodec_data *btfm_get_btfmcodec(void); #endif /*__LINUX_BTFM_CODEC_H */ diff --git a/btfmcodec/include/btfm_codec_btadv_interface.h b/btfmcodec/include/btfm_codec_btadv_interface.h new file mode 100644 index 0000000000..b27d2a0503 --- /dev/null +++ b/btfmcodec/include/btfm_codec_btadv_interface.h @@ -0,0 +1,21 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved. + */ + +#ifndef __LINUX_BTFM_CODEC_BTADV_INTERFACE_H +#define __LINUX_BTFM_CODEC_BTADV_INTERFACE_H + +enum transport_type { + BT = 1, + BTADV, +}; + +static char *transport_type_text[] = {"BT", "BTADV"}; + +void btfmcodec_set_current_state(struct btfmcodec_state_machine *, btfmcodec_state); +void btfmcodec_wq_prepare_bearer(struct work_struct *); +void btfmcodec_wq_hwep_shutdown(struct work_struct *); +void btfmcodec_initiate_hwep_shutdown(struct btfmcodec_char_device *btfmcodec_dev); +btfmcodec_state btfmcodec_get_current_transport(struct btfmcodec_state_machine *state); +#endif /* __LINUX_BTFM_CODEC_BTADV_INTERFACE_H */ diff --git a/btfmcodec/include/btfm_codec_hw_interface.h b/btfmcodec/include/btfm_codec_hw_interface.h index 116b415da9..60163b95ab 100644 --- a/btfmcodec/include/btfm_codec_hw_interface.h +++ b/btfmcodec/include/btfm_codec_hw_interface.h @@ -20,11 +20,32 @@ #define BTADV_AUDIO_MASTER_CONFIG 0 #define DEVICE_NAME_MAX_LEN 64 +struct hwep_configurations { + void *btfmcodec; + uint8_t stream_id; + uint32_t sample_rate; + uint8_t bit_width; + uint8_t codectype; + uint32_t direction; + struct list_head dai_list; +}; + +struct master_hwep_configurations { + uint8_t stream_id; + uint32_t device_id; + uint32_t sample_rate; + uint8_t bit_width; + uint8_t num_channels; + uint8_t chan_num; + uint8_t codectype; + uint16_t direction; +}; struct hwep_comp_drv { - int (*hwep_probe) (struct snd_soc_component *component); - void (*hwep_remove) (struct snd_soc_component *component); - unsigned int (*hwep_read)(struct snd_soc_component *component, unsigned int reg); - int (*hwep_write)(struct snd_soc_component *componentm, unsigned int reg, unsigned int value); + int (*hwep_probe) (struct snd_soc_component *); + void (*hwep_remove) (struct snd_soc_component *); + unsigned int (*hwep_read)(struct snd_soc_component *, unsigned int ); + int (*hwep_write)(struct snd_soc_component *, unsigned int, + unsigned int); }; struct hwep_dai_ops { @@ -36,6 +57,9 @@ struct hwep_dai_ops { unsigned int, unsigned int *); int (*hwep_get_channel_map)(void *, unsigned int *, unsigned int *, unsigned int *, unsigned int *, int); + int (*hwep_get_configs)(void *, struct master_hwep_configurations *, + uint8_t); + uint8_t *hwep_codectype; }; struct hwep_dai_driver { @@ -51,7 +75,9 @@ struct hwep_data { char driver_name [DEVICE_NAME_MAX_LEN]; struct hwep_comp_drv *drv; struct hwep_dai_driver *dai_drv; + struct snd_kcontrol_new *mixer_ctrl; int num_dai; + int num_mixer_ctrl; unsigned long flags; }; diff --git a/btfmcodec/include/btfm_codec_pkt.h b/btfmcodec/include/btfm_codec_pkt.h index 33432e22c7..3084b88de5 100644 --- a/btfmcodec/include/btfm_codec_pkt.h +++ b/btfmcodec/include/btfm_codec_pkt.h @@ -6,44 +6,89 @@ #ifndef __LINUX_BTFM_CODEC_PKT_H #define __LINUX_BTFM_CODEC_PKT_H -typedef uint16_t btm_opcode; +typedef uint32_t btm_opcode; struct btm_req { btm_opcode opcode; - uint8_t len; + uint32_t len; uint8_t *data; -}; +}__attribute__((packed)); struct btm_rsp { btm_opcode opcode; uint8_t status; -}; +}__attribute__((packed)); struct btm_ind { btm_opcode opcode; - uint8_t len; + uint32_t len; uint8_t *data; +}__attribute__((packed)); + +struct btm_ctrl_pkt { + btm_opcode opcode; + uint32_t len; + uint8_t active_transport; + uint8_t status; +}__attribute__((packed)); + +#define BTM_BTFMCODEC_PREPARE_AUDIO_BEARER_SWITCH_REQ 0x50000000 +#define BTM_BTFMCODEC_PREPARE_AUDIO_BEARER_SWITCH_RSP 0x50000001 +#define BTM_BTFMCODEC_MASTER_CONFIG_REQ 0x50000002 +#define BTM_BTFMCODEC_MASTER_CONFIG_RSP 0x50000003 +#define BTM_BTFMCODEC_MASTER_SHUTDOWN_REQ 0x50000004 +#define BTM_BTFMCODEC_CTRL_MASTER_SHUTDOWN_RSP 0x50000005 +#define BTM_BTFMCODEC_BEARER_SWITCH_IND 0x58000001 +#define BTM_BTFMCODEC_TRANSPORT_SWITCH_FAILED_IND 0x58000002 + +#define BTM_MASTER_CONFIG_REQ_LEN 13 +#define BTM_MASTER_CONFIG_RSP_TIMEOUT 1000 +#define BTM_HEADER_LEN 8 +#define BTM_PREPARE_AUDIO_BEARER_SWITCH_RSP_LEN 2 +#define BTM_MASTER_CONFIG_RSP_LEN 2 +#define BTM_MASTER_SHUTDOWN_REQ_LEN 1 +#define BTM_PREPARE_AUDIO_BEARER_SWITCH_REQ_LEN 1 +#define BTM_BEARER_SWITCH_IND_LEN 1 + +enum rx_status { + /* Waiting for response */ + BTM_WAITING_RSP, + /* Response recevied */ + BTM_RSP_RECV, + /* Response recevied with failure status*/ + BTM_FAIL_RESP_RECV, +}; +enum btfm_kp_status { + /* KP processed message succesfully */ + MSG_SUCCESS = 0, + /* Error while processing the message */ + MSG_FAILED, + /* Wrong transport type selected by BTADV audio manager */ + MSG_WRONG_TRANSPORT_TYPE, + /* Timeout triggered to receive bearer switch indications*/ + MSG_INTERNAL_TIMEOUT, + MSG_FAILED_TO_CONFIGURE_HWEP, + MSG_FAILED_TO_SHUTDOWN_HWEP, + MSG_ERR_WHILE_SHUTING_DOWN_HWEP, }; - -#define BTM_BTFMCODEC_PREPARE_AUDIO_BEARER_SWITCH_REQ 0x5000 -#define BTM_BTFMCODEC_PREPARE_AUDIO_BEARER_SWITCH_RSP 0x5001 -#define BTM_BTFMCODEC_MASTER_CONFIG_REQ 0x5002 -#define BTM_BTFMCODEC_MASTER_CONFIG_RSP 0x5003 -#define BTM_BTFMCODEC_MASTER_SHUTDOWN_REQ 0x5004 -#define BTM_BTFMCODEC_CTRL_MASTER_SHUTDOWN_RSP 0x5005 -#define BTM_BTFMCODEC_BEARER_SWITCH_IND 0x50C8 -#define BTM_BTFMCODEC_TRANSPORT_SWITCH_FAILED_IND 0x50C9 - struct btm_master_config_req { btm_opcode opcode; - uint8_t len; - uint8_t stream_identifier; - uint32_t device_identifier; - uint32_t sampling_rate; + uint32_t len; + uint8_t stream_id; + uint32_t device_id; + uint32_t sample_rate; uint8_t bit_width; - uint8_t num_of_channels; + uint8_t num_channels; uint8_t channel_num; uint8_t codec_id; -}; +}__attribute__((packed)); + +struct btm_master_shutdown_req { + btm_opcode opcode; + uint32_t len; + uint8_t stream_id; +}__attribute__((packed)); +int btfmcodec_dev_enqueue_pkt(struct btfmcodec_char_device *, void *, int); +bool btfmcodec_is_valid_cache_avb(struct btfmcodec_data *); #endif /* __LINUX_BTFM_CODEC_PKT_H*/ diff --git a/slimbus/Makefile b/slimbus/Makefile index 18aa0a3f45..ae35b58e12 100644 --- a/slimbus/Makefile +++ b/slimbus/Makefile @@ -5,4 +5,4 @@ bt_fm_slim-objs := btfm_slim.o btfm_slim_codec.o btfm_slim_slave.o obj-$(CONFIG_BTFM_SLIM) += bt_fm_slim.o # Below src is for BTFM Driver support based on btfm codec btfm_slim_codec-objs := btfm_slim.o btfm_slim_hw_interface.o btfm_slim_slave.o -obj-$(CONFIG_SLIM_BTFM_CODEC) += btfm_slim_codec.o \ No newline at end of file +obj-$(CONFIG_SLIM_BTFM_CODEC) += btfm_slim_codec.o diff --git a/slimbus/btfm_slim.c b/slimbus/btfm_slim.c index 2178ca7a7e..dbab9dff2b 100644 --- a/slimbus/btfm_slim.c +++ b/slimbus/btfm_slim.c @@ -515,6 +515,67 @@ int btfm_slim_hw_deinit(struct btfmslim *btfmslim) return ret; } +#if IS_ENABLED (CONFIG_BTFM_SLIM) +void btfm_slim_get_hwep_details(struct slim_device *dev, struct btfmslim *btfm_slim) +{ +} +#else +void btfm_slim_get_hwep_details(struct slim_device *slim, struct btfmslim *btfm_slim) +{ + struct device_node *np = slim->dev.of_node; + const __be32 *prop; + struct btfmslim_ch *rx_chs = btfm_slim->rx_chs; + struct btfmslim_ch *tx_chs = btfm_slim->tx_chs; + int len; + + prop = of_get_property(np, "qcom,btslim-address", &len); + if (prop) { + btfm_slim->device_id = be32_to_cpup(&prop[0]); + BTFMSLIM_DBG("hwep slim address define in dt %08x", btfm_slim->device_id); + } else { + BTFMSLIM_ERR("btslim-address is not defined in dt using default address"); + btfm_slim->device_id = 0; + } + + if (!rx_chs || !tx_chs) { + BTFMSLIM_ERR("either rx/tx channels are configured to null"); + return; + } + + prop = of_get_property(np, "qcom,btslimrx-channels", &len); + if (prop) { + /* Check if we need any protection for index */ + rx_chs[0].ch = (uint8_t)be32_to_cpup(&prop[0]); + rx_chs[1].ch = (uint8_t)be32_to_cpup(&prop[1]); + BTFMSLIM_DBG("Rx: id\tname\tport\tch"); + BTFMSLIM_DBG(" %d\t%s\t%d\t%d", rx_chs[0].id, + rx_chs[0].name, rx_chs[0].port, + rx_chs[0].ch); + BTFMSLIM_DBG(" %d\t%s\t%d\t%d", rx_chs[1].id, + rx_chs[1].name, rx_chs[1].port, + rx_chs[1].ch); + } else { + BTFMSLIM_ERR("btslimrx channels are missing in dt using default values"); + } + + prop = of_get_property(np, "qcom,btslimtx-channels", &len); + if (prop) { + /* Check if we need any protection for index */ + tx_chs[0].ch = (uint8_t)be32_to_cpup(&prop[0]); + tx_chs[1].ch = (uint8_t)be32_to_cpup(&prop[1]); + BTFMSLIM_DBG("Tx: id\tname\tport\tch"); + BTFMSLIM_DBG(" %d\t%s\t%d\t%x", tx_chs[0].id, + tx_chs[0].name, tx_chs[0].port, + tx_chs[0].ch); + BTFMSLIM_DBG(" %d\t%s\t%d\t%x", tx_chs[1].id, + tx_chs[1].name, tx_chs[1].port, + tx_chs[1].ch); + } else { + BTFMSLIM_ERR("btslimtx channels are missing in dt using default values"); + } + +} +#endif static int btfm_slim_status(struct slim_device *sdev, enum slim_device_status status) { @@ -526,6 +587,7 @@ static int btfm_slim_status(struct slim_device *sdev, #if IS_ENABLED(CONFIG_BTFM_SLIM) ret = btfm_slim_register_codec(btfm_slim); #else + btfm_slim_get_hwep_details(sdev, btfm_slim); ret = btfm_slim_register_hw_ep(btfm_slim); #endif if (ret) diff --git a/slimbus/btfm_slim.h b/slimbus/btfm_slim.h index d3e0377dca..393b0ab82a 100644 --- a/slimbus/btfm_slim.h +++ b/slimbus/btfm_slim.h @@ -73,6 +73,9 @@ struct btfmslim { int (*vendor_init)(struct btfmslim *btfmslim); int (*vendor_port_en)(struct btfmslim *btfmslim, uint8_t port_num, uint8_t rxport, uint8_t enable); +#if IS_ENABLED(CONFIG_SLIM_BTFM_CODEC) + int device_id; +#endif }; extern int btfm_feedback_ch_setting; diff --git a/slimbus/btfm_slim_hw_interface.c b/slimbus/btfm_slim_hw_interface.c index 67ce3ba41d..bcc7477a56 100644 --- a/slimbus/btfm_slim_hw_interface.c +++ b/slimbus/btfm_slim_hw_interface.c @@ -26,15 +26,16 @@ static int bt_soc_enable_status; int btfm_feedback_ch_setting; +static uint8_t usecase_codec; -static int btfm_slim_codec_write(struct snd_soc_component *codec, +static int btfm_slim_hwep_write(struct snd_soc_component *codec, unsigned int reg, unsigned int value) { BTFMSLIM_DBG(""); return 0; } -static unsigned int btfm_slim_codec_read(struct snd_soc_component *codec, +static unsigned int btfm_slim_hwep_read(struct snd_soc_component *codec, unsigned int reg) { BTFMSLIM_DBG(""); @@ -72,25 +73,39 @@ static int btfm_put_feedback_ch_setting(struct snd_kcontrol *kcontrol, return 1; } -static const struct snd_kcontrol_new status_controls[] = { +static int btfm_get_codec_type(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + BTFMSLIM_DBG("current codec type:%s", codec_text[usecase_codec]); + ucontrol->value.integer.value[0] = usecase_codec; + return 1; +} + +static int btfm_put_codec_type(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + usecase_codec = ucontrol->value.integer.value[0]; + BTFMSLIM_DBG("codec type set to:%s", codec_text[usecase_codec]); + return 1; +} +static struct snd_kcontrol_new status_controls[] = { SOC_SINGLE_EXT("BT SOC status", 0, 0, 1, 0, - btfm_soc_status_get, - btfm_soc_status_put), + btfm_soc_status_get, btfm_soc_status_put), SOC_SINGLE_EXT("BT set feedback channel", 0, 0, 1, 0, btfm_get_feedback_ch_setting, - btfm_put_feedback_ch_setting) + btfm_put_feedback_ch_setting), + SOC_ENUM_EXT("BT codec type", codec_display, + btfm_get_codec_type, btfm_put_codec_type), }; -static int btfm_slim_codec_probe(struct snd_soc_component *codec) +static int btfm_slim_hwep_probe(struct snd_soc_component *codec) { BTFMSLIM_DBG(""); - snd_soc_add_component_controls(codec, status_controls, - ARRAY_SIZE(status_controls)); return 0; } -static void btfm_slim_codec_remove(struct snd_soc_component *codec) +static void btfm_slim_hwep_remove(struct snd_soc_component *codec) { BTFMSLIM_DBG(""); } @@ -163,6 +178,30 @@ static int btfm_slim_dai_hw_params(void *dai, uint32_t bps, return 0; } +void btfm_get_sampling_rate(uint32_t *sampling_rate) +{ + uint8_t codec_types_avb = ARRAY_SIZE(codec_text); + if (usecase_codec > (codec_types_avb - 1)) { + BTFMSLIM_ERR("falling back to use default sampling_rate: %u", + *sampling_rate); + return; + } + + if (*sampling_rate == 44100 || *sampling_rate == 48000) { + if (usecase_codec == LDAC || + usecase_codec == APTX_AD) + *sampling_rate = (*sampling_rate) *2; + } + + if (usecase_codec == LC3_VOICE || + usecase_codec == APTX_AD_SPEECH || + usecase_codec == LC3 || usecase_codec == APTX_AD_QLEA) { + *sampling_rate = 96000; + } + + BTFMSLIM_INFO("current usecase codec type %s and sampling rate:%u khz", + codec_text[usecase_codec], *sampling_rate); +} static int btfm_slim_dai_prepare(void *dai, uint32_t sampling_rate, uint32_t direction, int id) { struct hwep_data *hwep_info = (struct hwep_data *)dai; @@ -175,6 +214,7 @@ static int btfm_slim_dai_prepare(void *dai, uint32_t sampling_rate, uint32_t dir btfmslim->direction = direction; bt_soc_enable_status = 0; + btfm_get_sampling_rate(&sampling_rate); /* save sample rate */ btfmslim->sample_rate = sampling_rate; @@ -254,7 +294,7 @@ static int btfm_slim_dai_set_channel_map(void *dai, * get channel handler from slimbus driver */ rx_chs->ch = *(uint8_t *)(rx_slot + i); - BTFMSLIM_DBG(" %d\t%s\t%d\t%x\t%d\t%x", rx_chs->id, + BTFMSLIM_DBG(" %d\t%s\t%d\t%x", rx_chs->id, rx_chs->name, rx_chs->port, rx_chs->ch); } @@ -265,7 +305,7 @@ static int btfm_slim_dai_set_channel_map(void *dai, * get channel handler from slimbus driver */ tx_chs->ch = *(uint8_t *)(tx_slot + i); - BTFMSLIM_DBG(" %d\t%s\t%d\t%x\t%d\t%x", tx_chs->id, + BTFMSLIM_DBG(" %d\t%s\t%d\t%x", tx_chs->id, tx_chs->name, tx_chs->port, tx_chs->ch); } @@ -352,6 +392,45 @@ static int btfm_slim_dai_get_channel_map(void *dai, return 0; } +int btfm_slim_dai_get_configs (void * dai, + struct master_hwep_configurations *hwep_config, + uint8_t id) +{ + struct hwep_data *hwep_info = (struct hwep_data *)dai; + struct btfmslim *btfmslim = dev_get_drvdata(hwep_info->dev); + struct btfmslim_ch *ch = NULL; + int i = 0; + + BTFMSLIM_DBG(""); + hwep_config->stream_id = id; + hwep_config->device_id = btfmslim->device_id; + hwep_config->sample_rate = btfmslim->sample_rate; + hwep_config->bit_width = (uint8_t)btfmslim->bps; + hwep_config->codectype = usecase_codec; + hwep_config->direction = btfmslim->direction; + + switch (id) { + case BTFM_FM_SLIM_TX: + case BTFM_BT_SCO_SLIM_TX: + ch = btfmslim->tx_chs; + break; + case BTFM_BT_SCO_A2DP_SLIM_RX: + case BTFM_BT_SPLIT_A2DP_SLIM_RX: + ch = btfmslim->rx_chs; + break; + } + + for (; i < id ; i++) { + if (ch[i].id == id) { + BTFMSLIM_DBG("id matched"); + hwep_config->num_channels = 1; + hwep_config->chan_num = ch[i].ch; + break; + } + } + + return 1; +} static struct hwep_dai_ops btfmslim_hw_dai_ops = { .hwep_startup = btfm_slim_dai_startup, .hwep_shutdown = btfm_slim_dai_shutdown, @@ -359,6 +438,8 @@ static struct hwep_dai_ops btfmslim_hw_dai_ops = { .hwep_prepare = btfm_slim_dai_prepare, .hwep_set_channel_map = btfm_slim_dai_set_channel_map, .hwep_get_channel_map = btfm_slim_dai_get_channel_map, + .hwep_get_configs = btfm_slim_dai_get_configs, + .hwep_codectype = &usecase_codec, }; static struct hwep_dai_driver btfmslim_dai_driver[] = { @@ -403,10 +484,10 @@ static struct hwep_dai_driver btfmslim_dai_driver[] = { }; static struct hwep_comp_drv btfmslim_hw_driver = { - .hwep_probe = btfm_slim_codec_probe, - .hwep_remove = btfm_slim_codec_remove, - .hwep_read = btfm_slim_codec_read, - .hwep_write = btfm_slim_codec_write, + .hwep_probe = btfm_slim_hwep_probe, + .hwep_remove = btfm_slim_hwep_remove, + .hwep_read = btfm_slim_hwep_read, + .hwep_write = btfm_slim_hwep_write, }; int btfm_slim_register_hw_ep(struct btfmslim *btfm_slim) @@ -431,6 +512,8 @@ int btfm_slim_register_hw_ep(struct btfmslim *btfm_slim) hwep_info->dai_drv = btfmslim_dai_driver; hwep_info->num_dai = ARRAY_SIZE(btfmslim_dai_driver); hwep_info->num_dai = 2; + hwep_info->num_mixer_ctrl = ARRAY_SIZE(status_controls); + hwep_info->mixer_ctrl = status_controls; set_bit(BTADV_AUDIO_MASTER_CONFIG, &hwep_info->flags); /* Register to hardware endpoint */ ret = btfmcodec_register_hw_ep(hwep_info); diff --git a/slimbus/btfm_slim_hw_interface.h b/slimbus/btfm_slim_hw_interface.h index 38b480cf6b..f51d52b882 100644 --- a/slimbus/btfm_slim_hw_interface.h +++ b/slimbus/btfm_slim_hw_interface.h @@ -15,4 +15,28 @@ // Todo protect with flags int btfm_slim_register_hw_ep(struct btfmslim *btfm_slim); void btfm_slim_unregister_hwep(void); + +typedef enum Codec { + SBC = 0, + AAC, + LDAC, + APTX, + APTX_HD, + APTX_AD, + LC3, + APTX_AD_SPEECH, + LC3_VOICE, + APTX_AD_QLEA, + APTX_AD_R4, + NO_CODEC +} codectype; + +static char const *codec_text[] = {"CODEC_TYPE_SBC", "CODEC_TYPE_AAC", + "CODEC_TYPE_LDAC", "CODEC_TYPE_APTX", + "CODEC_TYPE_APTX_HD", "CODEC_TYPE_APTX_AD", + "CODEC_TYPE_LC3", "CODEC_TYPE_APTX_AD_SPEECH", + "CODEC_TYPE_LC3_VOICE", "CODEC_TYPE_APTX_AD_QLEA", + "CODEC_TYPE_APTX_AD_R4","CODEC_TYPE_INVALID"}; + +static SOC_ENUM_SINGLE_EXT_DECL(codec_display, codec_text); #endif /*__LINUX_BTFM_SLIM_HW_INTERFACE_H*/ From 594501303c8193e4a5c67683b78d402617a024c1 Mon Sep 17 00:00:00 2001 From: satish kumar sugasi Date: Tue, 1 Nov 2022 19:33:41 -0700 Subject: [PATCH 023/154] BT: Add secure mode check to avoid BT ON Adds secure peripheral check to ensure bluetooth is not powered on if secure state for Bluetooth is enabled Change-Id: I3ac13ec38ec30f03bf747d317fdacbe58f022cd0 --- Android.mk | 13 +++++++ Kbuild | 5 ++- include/btpower.h | 2 + pwr/Makefile | 1 + pwr/btpower.c | 99 ++++++++++++++++++++++++++++++++++++++++++++++- 5 files changed, 117 insertions(+), 3 deletions(-) diff --git a/Android.mk b/Android.mk index 4d30a66464..3331408b20 100644 --- a/Android.mk +++ b/Android.mk @@ -11,6 +11,12 @@ BT_SELECT += CONFIG_BTFM_SLIM=m #endif BT_SELECT += CONFIG_I2C_RTC6226_QCA=m +ifeq ($(TARGET_KERNEL_DLKM_SECURE_MSM_OVERRIDE), true) +ifeq ($(ENABLE_PERIPHERAL_STATE_UTILS), true) +BT_SELECT += CONFIG_BT_HW_SECURE_DISABLE=y +endif +endif + LOCAL_PATH := $(call my-dir) # This makefile is only for DLKM @@ -33,6 +39,13 @@ BT_SRC_FILES := \ $(wildcard $(LOCAL_PATH)/*) \ $(wildcard $(LOCAL_PATH)/*/*) \ +ifeq ($(TARGET_KERNEL_DLKM_SECURE_MSM_OVERRIDE), true) +ifeq ($(ENABLE_PERIPHERAL_STATE_UTILS), true) +KBUILD_REQUIRED_KOS := smcinvoke_dlkm.ko +endif +endif + + # Module.symvers needs to be generated as a intermediate module so that # other modules which depend on BT platform modules can set local # dependencies to it. diff --git a/Kbuild b/Kbuild index e55b1cb8d2..5415a289dc 100644 --- a/Kbuild +++ b/Kbuild @@ -10,11 +10,14 @@ ifeq ($(CONFIG_I2C_RTC6226_QCA),m) KBUILD_CPPFLAGS += -DCONFIG_I2C_RTC6226_QCA endif - ifeq ($(CONFIG_SLIM_BTFM_CODEC), m) KBUILD_CPPFLAGS += -DCONFIG_SLIM_BTFM_CODEC endif +ifeq ($(CONFIG_BT_HW_SECURE_DISABLE), y) +KBUILD_CPPFLAGS += -DCONFIG_BT_HW_SECURE_DISABLE +endif + obj-$(CONFIG_MSM_BT_POWER) += pwr/ obj-$(CONFIG_BTFM_SLIM) += slimbus/ obj-$(CONFIG_I2C_RTC6226_QCA) += rtc6226/ diff --git a/include/btpower.h b/include/btpower.h index 553e000a48..29b5887819 100644 --- a/include/btpower.h +++ b/include/btpower.h @@ -78,6 +78,8 @@ struct btpower_platform_data { int pdc_init_table_len; const char **pdc_init_table; int bt_device_type; + bool sec_peri_feature_disable; + int bt_sec_hw_disable; #ifdef CONFIG_MSM_BT_OOBS struct file *reffilp_obs; struct task_struct *reftask_obs; diff --git a/pwr/Makefile b/pwr/Makefile index ac7e92aa5d..000773c3ad 100644 --- a/pwr/Makefile +++ b/pwr/Makefile @@ -1,2 +1,3 @@ ccflags-y += -I$(BT_ROOT)/include + obj-$(CONFIG_MSM_BT_POWER) += btpower.o diff --git a/pwr/btpower.c b/pwr/btpower.c index 12d3d4406f..e4642ebad8 100644 --- a/pwr/btpower.c +++ b/pwr/btpower.c @@ -32,6 +32,18 @@ #endif #include +#ifdef CONFIG_BT_HW_SECURE_DISABLE +#include "linux/smcinvoke.h" +#include "linux/smcinvoke_object.h" +#include "linux/IClientEnv.h" + +#define PERISEC_HW_STATE_UID 0x108 +#define PERISEC_HW_OP_GET_STATE 1 +#define PERISEC_HW_BLUETOOTH_UID 0x502 +#define PERISEC_FEATURE_NOT_SUPPORTED 12 +#define PERISEC_PERIPHERAL_NOT_FOUND 10 +#endif + #define PWR_SRC_NOT_AVAILABLE -2 #define DEFAULT_INVALID_VALUE -1 #define PWR_SRC_INIT_STATE_IDX 0 @@ -241,6 +253,76 @@ static int bt_major; static int soc_id; static bool probe_finished; + +#ifdef CONFIG_BT_HW_SECURE_DISABLE +int perisec_cnss_bt_hw_disable_check(struct btpower_platform_data *plat_priv) +{ + struct Object client_env; + struct Object app_object; + int bt_uid = PERISEC_HW_BLUETOOTH_UID; + union ObjectArg obj_arg[2] = {{{0, 0}}}; + int ret; + u8 state = 0; + + /* Once this flag is set, secure peripheral feature + * will not be supported till next reboot + */ + if (plat_priv->sec_peri_feature_disable) + return 0; + + /* get rootObj */ + ret = get_client_env_object(&client_env); + if (ret) { + pr_debug("Failed to get client_env_object, ret: %d\n", ret); + goto end; + } + ret = IClientEnv_open(client_env, PERISEC_HW_STATE_UID, &app_object); + if (ret) { + pr_debug("Failed to get app_object, ret: %d\n", ret); + if (ret == PERISEC_FEATURE_NOT_SUPPORTED) { + ret = 0; /* Do not Assert */ + plat_priv->sec_peri_feature_disable = true; + pr_debug("Secure HW feature not supported\n"); + } + goto exit_release_clientenv; + } + + obj_arg[0].b = (struct ObjectBuf) {&bt_uid, sizeof(u32)}; + obj_arg[1].b = (struct ObjectBuf) {&state, sizeof(u8)}; + ret = Object_invoke(app_object, PERISEC_HW_OP_GET_STATE, obj_arg, + ObjectCounts_pack(1, 1, 0, 0)); + + pr_debug("SMC invoke ret: %d state: %d\n", ret, state); + if (ret) { + if (ret == PERISEC_PERIPHERAL_NOT_FOUND) { + ret = 0; /* Do not Assert */ + plat_priv->sec_peri_feature_disable = true; + pr_debug("Secure HW mode is not updated. Peripheral not found\n"); + } + Object_release(app_object); + } else { + if (state == 1) + plat_priv->bt_sec_hw_disable = 1; + else + plat_priv->bt_sec_hw_disable = 0; + } + +exit_release_clientenv: + Object_release(client_env); +end: + if (ret) { + pr_err("SecMode:Unable to get sec mode BT Hardware status\n"); + } + return ret; +} +#else +int perisec_cnss_bt_hw_disable_check(struct btpower_platform_data *plat_priv) +{ + return 0; +} +#endif + + #ifdef CONFIG_MSM_BT_OOBS static void btpower_uart_transport_locked(struct btpower_platform_data *drvdata, bool locked) @@ -682,7 +764,13 @@ static int bluetooth_power(int on) pr_debug("%s: on: %d\n", __func__, on); + rc = perisec_cnss_bt_hw_disable_check(bt_power_pdata); if (on == 1) { + if (bt_power_pdata->bt_sec_hw_disable) { + pr_err("%s:secure hw mode on,BT ON not allowed", + __func__); + return -EINVAL; + } rc = bt_power_vreg_set(BT_POWER_ENABLE); if (rc < 0) { pr_err("%s: bt_power regulators config failed\n", @@ -714,8 +802,14 @@ static int bluetooth_power(int on) } } else if (on == 0) { // Power Off - if (bt_power_pdata->bt_gpio_sys_rst > 0) - bt_configure_gpios(on); + if (bt_power_pdata->bt_gpio_sys_rst > 0) { + if (bt_power_pdata->bt_sec_hw_disable) { + pr_err("%s: secure hw mode on, not allowed to access gpio", + __func__); + }else { + bt_configure_gpios(on); + } + } gpio_fail: if (bt_power_pdata->bt_gpio_sys_rst > 0) gpio_free(bt_power_pdata->bt_gpio_sys_rst); @@ -1106,6 +1200,7 @@ static int bt_power_probe(struct platform_device *pdev) bt_power_pdata->pdev = pdev; + ret = perisec_cnss_bt_hw_disable_check(bt_power_pdata); if (pdev->dev.of_node) { ret = bt_power_populate_dt_pinfo(pdev); if (ret < 0) { From e7e85692a155d415ed2832c83ed140d572bc0b64 Mon Sep 17 00:00:00 2001 From: Balakrishna Godavarthi Date: Fri, 27 Jan 2023 10:52:49 +0530 Subject: [PATCH 024/154] btfmcodec: unblock waiting threads during usecase shutdown This change notifies waiting thread when usecase shutdown is triggered and also flush work queues. Change-Id: If523e806dc23fc256e82c4eac30f7aa79b119f55 --- btfmcodec/btfm_codec.c | 21 ++++++++++++++++++++- btfmcodec/btfm_codec_btadv_interface.c | 9 +++++++-- btfmcodec/btfm_codec_interface.c | 6 ++++-- btfmcodec/include/btfm_codec_pkt.h | 3 +++ 4 files changed, 34 insertions(+), 5 deletions(-) diff --git a/btfmcodec/btfm_codec.c b/btfmcodec/btfm_codec.c index 75da3097ca..6b62f91936 100644 --- a/btfmcodec/btfm_codec.c +++ b/btfmcodec/btfm_codec.c @@ -94,6 +94,7 @@ static int btfmcodec_dev_release(struct inode *inode, struct file *file) { struct btfmcodec_char_device *btfmcodec_dev = cdev_to_btfmchardev(inode->i_cdev); unsigned long flags; + int idx; BTFMCODEC_INFO("for %s by %s:%d active_clients[%u]\n", btfmcodec_dev->dev_name, current->comm, @@ -110,6 +111,16 @@ static int btfmcodec_dev_release(struct inode *inode, struct file *file) skb_queue_purge(&btfmcodec_dev->rxq); } + /* Notify waiting clients that client is closed or killed */ + for (idx = 0; idx < BTM_PKT_TYPE_MAX; idx++) { + btfmcodec_dev->status[idx] = BTM_RSP_NOT_RECV_CLIENT_KILLED; + wake_up_interruptible(&btfmcodec_dev->rsp_wait_q[idx]); + } + + cancel_work_sync(&btfmcodec_dev->wq_hwep_shutdown); + cancel_work_sync(&btfmcodec_dev->wq_hwep_configure); + cancel_work_sync(&btfmcodec_dev->wq_prepare_bearer); + btfmcodec->states.current_state = IDLE; btfmcodec->states.next_state = IDLE; return 0; @@ -140,8 +151,16 @@ static void btfmcodec_dev_rxwork(struct work_struct *work) idx = BTM_PKT_TYPE_PREPARE_REQ; BTFMCODEC_DBG("BTM_BTFMCODEC_PREPARE_AUDIO_BEARER_SWITCH_REQ"); if (len == BTM_PREPARE_AUDIO_BEARER_SWITCH_REQ_LEN) { + /* there are chances where bearer indication is not recevied, + * So inform waiting thread to unblock itself and move to + * previous state. + */ + if (btfmcodec_dev->status[BTM_PKT_TYPE_BEARER_SWITCH_IND] == BTM_WAITING_RSP) { + BTFMCODEC_DBG("Notifying waiting beare indications"); + btfmcodec_dev->status[BTM_PKT_TYPE_BEARER_SWITCH_IND] = BTM_FAIL_RESP_RECV; + wake_up_interruptible(&btfmcodec_dev->rsp_wait_q[BTM_PKT_TYPE_BEARER_SWITCH_IND]); + } btfmcodec_dev->status[idx] = skb->data[0]; - BTFMCODEC_INFO("prepare wq_prepare_bearer:%p", btfmcodec_dev->wq_prepare_bearer); queue_work(btfmcodec_dev->workqueue, &btfmcodec_dev->wq_prepare_bearer); } else { BTFMCODEC_ERR("wrong packet format with len:%d", len); diff --git a/btfmcodec/btfm_codec_btadv_interface.c b/btfmcodec/btfm_codec_btadv_interface.c index 79f0488df6..b85bcaa362 100644 --- a/btfmcodec/btfm_codec_btadv_interface.c +++ b/btfmcodec/btfm_codec_btadv_interface.c @@ -30,7 +30,8 @@ void btfmcodec_initiate_hwep_shutdown(struct btfmcodec_char_device *btfmcodec_de if (*status == BTM_RSP_RECV) { BTFMCODEC_ERR("sucessfully closed hwep"); return; - } else if (*status == BTM_FAIL_RESP_RECV) { + } else if (*status == BTM_FAIL_RESP_RECV || + *status == BTM_RSP_NOT_RECV_CLIENT_KILLED) { BTFMCODEC_ERR("Failed to close hwep"); return; } @@ -136,6 +137,9 @@ int btfmcodec_wait_for_bearer_ind(struct btfmcodec_char_device *btfmcodec_dev) } else if (*status == BTM_FAIL_RESP_RECV) { BTFMCODEC_ERR("Rx BTM_BEARER_SWITCH_IND with failure status"); ret = -1; + } else if (*status == BTM_RSP_NOT_RECV_CLIENT_KILLED) { + BTFMCODEC_ERR("client killed so moving further"); + ret = -1; } } @@ -162,7 +166,8 @@ int btfmcodec_initiate_hwep_configuration(struct btfmcodec_char_device *btfmcode } else { if (*status == BTM_RSP_RECV) { ret = 0; - } else if (*status == BTM_FAIL_RESP_RECV) { + } else if (*status == BTM_FAIL_RESP_RECV || + *status == BTM_RSP_NOT_RECV_CLIENT_KILLED) { BTFMCODEC_ERR("Failed to close hwep moving back to previous state"); ret = -1; } diff --git a/btfmcodec/btfm_codec_interface.c b/btfmcodec/btfm_codec_interface.c index be360f34a9..6672cd8e70 100644 --- a/btfmcodec/btfm_codec_interface.c +++ b/btfmcodec/btfm_codec_interface.c @@ -255,7 +255,8 @@ int btfmcodec_hwep_shutdown(struct btfmcodec_data *btfmcodec, int id) } else { if (*status == BTM_RSP_RECV) ret = 0; - else if (*status == BTM_FAIL_RESP_RECV) + else if (*status == BTM_FAIL_RESP_RECV || + *status == BTM_RSP_NOT_RECV_CLIENT_KILLED) ret = -1; } } else { @@ -489,7 +490,8 @@ static int btfmcodec_configure_master(struct btfmcodec_data *btfmcodec, uint8_t } else { if (*status == BTM_RSP_RECV) return 0; - else if (*status == BTM_FAIL_RESP_RECV) + else if (*status == BTM_FAIL_RESP_RECV || + *status == BTM_RSP_NOT_RECV_CLIENT_KILLED) return -1; } diff --git a/btfmcodec/include/btfm_codec_pkt.h b/btfmcodec/include/btfm_codec_pkt.h index 3084b88de5..3e48b7c839 100644 --- a/btfmcodec/include/btfm_codec_pkt.h +++ b/btfmcodec/include/btfm_codec_pkt.h @@ -57,7 +57,10 @@ enum rx_status { BTM_RSP_RECV, /* Response recevied with failure status*/ BTM_FAIL_RESP_RECV, + /* Response not recevied, but client killed */ + BTM_RSP_NOT_RECV_CLIENT_KILLED, }; + enum btfm_kp_status { /* KP processed message succesfully */ MSG_SUCCESS = 0, From 751f3c2b0f436f98049c9ba56e9fd26165f4943e Mon Sep 17 00:00:00 2001 From: Balakrishna Godavarthi Date: Mon, 30 Jan 2023 12:26:35 +0530 Subject: [PATCH 025/154] btfmcodec: Don't send master shutdown request This change will stop sending master shutdown request during legacy transport shutdown. Change-Id: I7d83eeb15fc686e55cbaa83262eec0386e31f495 --- btfmcodec/btfm_codec_interface.c | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/btfmcodec/btfm_codec_interface.c b/btfmcodec/btfm_codec_interface.c index 6672cd8e70..88a70f03d7 100644 --- a/btfmcodec/btfm_codec_interface.c +++ b/btfmcodec/btfm_codec_interface.c @@ -221,7 +221,8 @@ static int btfmcodec_dai_startup(struct snd_pcm_substream *substream, return 0; } -int btfmcodec_hwep_shutdown(struct btfmcodec_data *btfmcodec, int id) +int btfmcodec_hwep_shutdown(struct btfmcodec_data *btfmcodec, int id, + bool disable_master) { struct hwep_data *hwep_info = btfmcodec->hwep_info; struct btfmcodec_char_device *btfmcodec_dev = btfmcodec->btfmcodec_dev; @@ -237,7 +238,7 @@ int btfmcodec_hwep_shutdown(struct btfmcodec_data *btfmcodec, int id) /* for master configurations failure cases, we don't need to send * shutdown request */ - if (btfmcodec_get_current_transport(state) == BT_Connected) { + if (btfmcodec_get_current_transport(state) == BT_Connected && disable_master) { BTFMCODEC_DBG("sending master shutdown request.."); shutdown_req.opcode = BTM_BTFMCODEC_MASTER_SHUTDOWN_REQ; shutdown_req.len = BTM_MASTER_SHUTDOWN_REQ_LEN; @@ -260,6 +261,9 @@ int btfmcodec_hwep_shutdown(struct btfmcodec_data *btfmcodec, int id) ret = -1; } } else { + if (!disable_master) + BTFMCODEC_WARN("Not sending master shutdown request as graph might have closed"); + else BTFMCODEC_WARN("Not sending master shutdown request as state is:%s", coverttostring(btfmcodec_get_current_transport(state))); } @@ -288,7 +292,7 @@ void btfmcodec_wq_hwep_shutdown(struct work_struct *work) */ list_for_each_entry(hwep_configs, head, dai_list) { BTFMCODEC_INFO("shuting down dai id:%d", hwep_configs->stream_id); - ret = btfmcodec_hwep_shutdown(btfmcodec, hwep_configs->stream_id); + ret = btfmcodec_hwep_shutdown(btfmcodec, hwep_configs->stream_id, true); if (ret < 0) { BTFMCODEC_ERR("failed to shutdown master with id", hwep_configs->stream_id); break; @@ -338,7 +342,7 @@ static void btfmcodec_dai_shutdown(struct snd_pcm_substream *substream, btfmcodec_delete_configs(btfmcodec, dai->id); } else { /* first master shutdown has to done */ - btfmcodec_hwep_shutdown(btfmcodec, dai->id); + btfmcodec_hwep_shutdown(btfmcodec, dai->id, false); btfmcodec_delete_configs(btfmcodec, dai->id); if (!btfmcodec_is_valid_cache_avb(btfmcodec)) btfmcodec_set_current_state(state, IDLE); From f3db4b2cdca3be57b63dcd07008ad701dcfc770f Mon Sep 17 00:00:00 2001 From: Satish Kumar Kodishala Date: Fri, 18 Nov 2022 18:19:10 +0530 Subject: [PATCH 026/154] Remove delay while opening ports for Apache Remove delay while opening ports for Apache. CRs-Fixed: 3330157 Change-Id: I6b9141313524ae5c13759ba1058dbe8c9e07ccc3 Signed-off-by: Satish Kumar Kodishala --- slimbus/btfm_slim.c | 33 --------------------------------- 1 file changed, 33 deletions(-) diff --git a/slimbus/btfm_slim.c b/slimbus/btfm_slim.c index dbab9dff2b..44ba8faeb0 100644 --- a/slimbus/btfm_slim.c +++ b/slimbus/btfm_slim.c @@ -27,7 +27,6 @@ #define SLIM_MANF_ID_QCOM 0x217 #define SLIM_PROD_CODE 0x221 -static bool btfm_is_port_opening_delayed = true; static int btfm_num_ports_open; int btfm_slim_write(struct btfmslim *btfmslim, @@ -84,19 +83,6 @@ int btfm_slim_read(struct btfmslim *btfmslim, uint32_t reg, uint8_t pgd) return ret; } -static bool btfm_slim_is_sb_reset_needed(int chip_ver) -{ - switch (chip_ver) { - case QCA_APACHE_SOC_ID_0100: - case QCA_APACHE_SOC_ID_0110: - case QCA_APACHE_SOC_ID_0120: - case QCA_APACHE_SOC_ID_0121: - return true; - default: - return false; - } -} - int btfm_slim_enable_ch(struct btfmslim *btfmslim, struct btfmslim_ch *ch, uint8_t rxport, uint32_t rates, uint8_t nchan) { @@ -143,23 +129,6 @@ int btfm_slim_enable_ch(struct btfmslim *btfmslim, struct btfmslim_ch *ch, chipset_ver = btpower_get_chipset_version(); BTFMSLIM_INFO("chipset soc version:%x", chipset_ver); - /* Delay port opening for few chipsets if: - 1. for 8k, feedback channel - 2. 44.1k, 88.2k rxports - */ - if (((rates == 8000 && btfm_feedback_ch_setting && rxport == 0) || - (rxport == 1 && (rates == 44100 || rates == 88200))) && - btfm_slim_is_sb_reset_needed(chipset_ver)) { - - BTFMSLIM_INFO("btfm_is_port_opening_delayed %d", - btfm_is_port_opening_delayed); - if (!btfm_is_port_opening_delayed) { - BTFMSLIM_INFO("SB reset needed, sleeping"); - btfm_is_port_opening_delayed = true; - msleep(DELAY_FOR_PORT_OPEN_MS); - } - } - /* for feedback channel, PCM bit should not be set */ if (btfm_feedback_ch_setting) { BTFMSLIM_DBG("port open for feedback ch, not setting PCM bit"); @@ -207,8 +176,6 @@ int btfm_slim_disable_ch(struct btfmslim *btfmslim, struct btfmslim_ch *ch, return -EINVAL; } - btfm_is_port_opening_delayed = false; - if (rxport && (btfmslim->sample_rate == 44100 || btfmslim->sample_rate == 88200)) { BTFMSLIM_INFO("disconnecting the ports, removing the channel"); From df0dd43a7849c4407ec8f5af29f878dc71899265 Mon Sep 17 00:00:00 2001 From: Balakrishna Godavarthi Date: Wed, 8 Feb 2023 16:21:13 +0530 Subject: [PATCH 027/154] btfmcodec: Add new transport type This change adds new transport type, when it is recevied the state will be moved to IDLE. Change-Id: Ia728ec151afb78d75444361cba3b2788fc278876 --- btfmcodec/btfm_codec_btadv_interface.c | 7 +++++++ btfmcodec/include/btfm_codec_btadv_interface.h | 3 ++- 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/btfmcodec/btfm_codec_btadv_interface.c b/btfmcodec/btfm_codec_btadv_interface.c index b85bcaa362..3817285e90 100644 --- a/btfmcodec/btfm_codec_btadv_interface.c +++ b/btfmcodec/btfm_codec_btadv_interface.c @@ -305,6 +305,13 @@ void btfmcodec_prepare_bearer(struct btfmcodec_char_device *btfmcodec_dev, btfmcodec_initiate_hwep_shutdown(btfmcodec_dev); } } + } else if (new_transport == NONE) { + /* Let ALSA handles the transport close for BT */ + if (current_state != BT_Connecting && current_state != BT_Connected) + btfmcodec_set_current_state(state, IDLE); + btfmcodec_frame_prepare_bearer_rsp_pkt(btfmcodec_dev, (uint8_t)current_state, + MSG_SUCCESS); + return; } } diff --git a/btfmcodec/include/btfm_codec_btadv_interface.h b/btfmcodec/include/btfm_codec_btadv_interface.h index b27d2a0503..7f10b7bb93 100644 --- a/btfmcodec/include/btfm_codec_btadv_interface.h +++ b/btfmcodec/include/btfm_codec_btadv_interface.h @@ -9,9 +9,10 @@ enum transport_type { BT = 1, BTADV, + NONE, }; -static char *transport_type_text[] = {"BT", "BTADV"}; +static char *transport_type_text[] = {"BT", "BTADV", "NONE"}; void btfmcodec_set_current_state(struct btfmcodec_state_machine *, btfmcodec_state); void btfmcodec_wq_prepare_bearer(struct work_struct *); From 07a9ef55f54e52e1f64f9404a3bd2d8566647e90 Mon Sep 17 00:00:00 2001 From: Satish Kumar Kodishala Date: Mon, 29 Aug 2022 17:36:08 +0530 Subject: [PATCH 028/154] BTFM SLIM:Add support for pin connectivity test Add support for pin connectivity test for BT/FM slimbus CRs-Fixed: 3270916 Change-Id: Ia913bcb204f6cccc59790b9a4cef20cbd346f05c Signed-off-by: Satish Kumar Kodishala --- slimbus/btfm_slim.c | 54 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 54 insertions(+) diff --git a/slimbus/btfm_slim.c b/slimbus/btfm_slim.c index 44ba8faeb0..8c9bf2bed4 100644 --- a/slimbus/btfm_slim.c +++ b/slimbus/btfm_slim.c @@ -13,6 +13,7 @@ #include #include #include +#include #include #include #include @@ -26,6 +27,12 @@ #define DELAY_FOR_PORT_OPEN_MS (200) #define SLIM_MANF_ID_QCOM 0x217 #define SLIM_PROD_CODE 0x221 +#define BT_CMD_SLIM_TEST 0xbfac + +struct class *btfm_slim_class; +static int btfm_slim_major; + +struct btfmslim *btfm_slim_drv_data; static int btfm_num_ports_open; @@ -562,6 +569,24 @@ static int btfm_slim_status(struct slim_device *sdev, return ret; } +static long btfm_slim_ioctl(struct file *file, unsigned int cmd, unsigned long arg) +{ + int ret = 0; + + switch (cmd) { + case BT_CMD_SLIM_TEST: + BTFMSLIM_INFO("cmd BT_CMD_SLIM_TEST, call btfm_slim_hw_init"); + ret = btfm_slim_hw_init(btfm_slim_drv_data); + break; + } + return ret; +} + +static const struct file_operations bt_dev_fops = { + .unlocked_ioctl = btfm_slim_ioctl, + .compat_ioctl = btfm_slim_ioctl, +}; + static int btfm_slim_probe(struct slim_device *slim) { int ret = 0; @@ -610,7 +635,36 @@ static int btfm_slim_probe(struct slim_device *slim) ret = -EPROBE_DEFER; goto dealloc; } + + btfm_slim_drv_data = btfm_slim; + btfm_slim_major = register_chrdev(0, "btfm_slim", &bt_dev_fops); + if (btfm_slim_major < 0) { + BTFMSLIM_ERR("%s: failed to allocate char dev\n", __func__); + ret = -1; + goto register_err; + } + + btfm_slim_class = class_create(THIS_MODULE, "btfmslim-dev"); + if (IS_ERR(btfm_slim_class)) { + BTFMSLIM_ERR("%s: coudn't create class\n", __func__); + ret = -1; + goto class_err; + } + + if (device_create(btfm_slim_class, NULL, MKDEV(btfm_slim_major, 0), + NULL, "btfmslim") == NULL) { + BTFMSLIM_ERR("%s: failed to allocate char dev\n", __func__); + ret = -1; + goto device_err; + } return ret; + +device_err: + class_destroy(btfm_slim_class); +class_err: + unregister_chrdev(btfm_slim_major, "btfm_slim"); +register_err: + btfm_slim_unregister_codec(&slim->dev); dealloc: mutex_destroy(&btfm_slim->io_lock); mutex_destroy(&btfm_slim->xfer_lock); From fb51f095af9c7f183a7edf63c41e6eaf0f6b44a2 Mon Sep 17 00:00:00 2001 From: pramod kotreshappa Date: Mon, 20 Mar 2023 14:14:09 -0700 Subject: [PATCH 029/154] BTFM techpack make file changes Change-Id: I9521acfbcde5ab610ea529c0a0f0ac589bd71a77 --- bt_kernel_vendor_board.mk | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/bt_kernel_vendor_board.mk b/bt_kernel_vendor_board.mk index 72c5e5d865..1c8ce659ce 100644 --- a/bt_kernel_vendor_board.mk +++ b/bt_kernel_vendor_board.mk @@ -3,17 +3,18 @@ ifneq ($(TARGET_BOARD_AUTO),true) ifeq ($(TARGET_USES_QMAA),true) ifeq ($(TARGET_USES_QMAA_OVERRIDE_BLUETOOTH), true) ifeq ($(call is-board-platform-in-list,$(TARGET_BOARD_PLATFORM)),true) - BOARD_VENDOR_KERNEL_MODULES += $(KERNEL_MODULES_OUT)/btpower.ko\ + BT_KERNEL_DRIVER := $(KERNEL_MODULES_OUT)/btpower.ko\ $(KERNEL_MODULES_OUT)/bt_fm_slim.ko \ - $(KERNEL_MODULES_OUT)/radio-i2c-rtc6226-qca.ko + $(KERNEL_MODULES_OUT)/radio-i2c-rtc6226-qca.ko + BOARD_VENDOR_KERNEL_MODULES += $(BT_KERNEL_DRIVER) endif endif else ifeq ($(call is-board-platform-in-list,$(TARGET_BOARD_PLATFORM)),true) - BOARD_VENDOR_KERNEL_MODULES += $(KERNEL_MODULES_OUT)/btpower.ko\ + BT_KERNEL_DRIVER := $(KERNEL_MODULES_OUT)/btpower.ko\ $(KERNEL_MODULES_OUT)/bt_fm_slim.ko \ - $(KERNEL_MODULES_OUT)/radio-i2c-rtc6226-qca.ko - + $(KERNEL_MODULES_OUT)/radio-i2c-rtc6226-qca.ko + BOARD_VENDOR_KERNEL_MODULES += $(BT_KERNEL_DRIVER) endif endif endif From 176b51aefae451ff8e04990e09154e65cf8db14c Mon Sep 17 00:00:00 2001 From: Franklin Abreu Bueno Date: Mon, 6 Feb 2023 16:04:44 -0800 Subject: [PATCH 030/154] bt-kernel: Additional bazel configuration - add support to copy *.ko to out dir - enable conditional compilation with config flags - enable CONFIG_BT_HW_SECURE_DISABLE with dependency on securemsm-kernel - re-enable compilation of bt_fm_slim with new headers - add fallthrough attribute btfm_slim_hw_interface.c - move BTFMSLIM_DEV_NAME to btfm_slim.h - add target.bzl file to define specific targets Change-Id: I7f7920870d81125f95b020ef33df77df3f937682 Signed-off-by: Franklin Abreu Bueno --- BUILD.bazel | 14 +++++-- bt_kernel.bzl | 66 ++++++++++++++++++++++++-------- bt_modules.bzl | 60 +++++++++++++++++++++++++---- slimbus/btfm_slim.c | 2 + slimbus/btfm_slim.h | 6 ++- slimbus/btfm_slim_hw_interface.c | 1 + slimbus/btfm_slim_hw_interface.h | 6 --- target.bzl | 19 +++++++++ 8 files changed, 140 insertions(+), 34 deletions(-) create mode 100644 target.bzl diff --git a/BUILD.bazel b/BUILD.bazel index 3e1939f5da..556c6041a9 100644 --- a/BUILD.bazel +++ b/BUILD.bazel @@ -1,5 +1,13 @@ -load(":bt_kernel.bzl", "define_bt_modules") +load("//build/kernel/kleaf:kernel.bzl", "ddk_headers") -targets = ["pineapple"] +ddk_headers( + name = "btfmcodec_headers", + hdrs = glob([ + "btfmcodec/include/*.h" + ]), + includes = ["btfmcodec/include"] +) -define_bt_modules(targets) +load(":target.bzl", "define_pineapple") + +define_pineapple() diff --git a/bt_kernel.bzl b/bt_kernel.bzl index 36b9642c6e..d1905913e9 100644 --- a/bt_kernel.bzl +++ b/bt_kernel.bzl @@ -1,24 +1,34 @@ load("//msm-kernel:target_variants.bzl", "get_all_variants") load("//build/kernel/kleaf:kernel.bzl", "ddk_module") - +load("//build/bazel_common_rules/dist:dist.bzl", "copy_to_dist_dir") load(":bt_modules.bzl", "bt_modules") -def _get_module_srcs(module): +def _get_config_choices(config_srcs, options): + choices = [] + + for option in config_srcs: + choices.extend(config_srcs[option].get(option in options, [])) + + return choices + +def _get_module_srcs(module, options): """ Gets all the module sources, formats them with the path for that module and then groups them together It also includes all the headers within the `include` directory `native.glob()` returns a new list with every file need for the current package """ + srcs = module.srcs + _get_config_choices(module.config_srcs, options) return native.glob( - ["{}/{}".format(module.path, src) for src in module.srcs] + ["include/*.h"] + ["{}/{}".format(module.path, src) for src in srcs] + ["include/*.h"] ) -def _get_module_deps(module, formatter): +def _get_module_deps(module, options, formatter): """ Formats the dependent targets with the necessary prefix Args: module: kernel module + options: dependencies that rely on a config option formatter: function that will replace the format string within `deps` Example: kernel build = "pineapple_gki" @@ -26,36 +36,60 @@ def _get_module_deps(module, formatter): The formatted string will look as follow formatted_dep = formatter(dep) = "pineapple_gki_btpower" """ - return [formatter(dep) for dep in module.deps] + deps = module.deps + _get_config_choices(module.config_deps, options) + return [formatter(dep) for dep in deps] -def define_target_variant_modules(target, variant, modules): +def _get_build_options(modules, config_options): + all_options = {option: True for option in config_options} + all_options = all_options | {module.config_opt: True for module in modules if module.config_opt} + + return all_options + +def define_target_variant_modules(target, variant, modules, config_options = []): """ Generates the ddk_module for each of our kernel modules Args: target: either `pineapple` or `kalama` variant: either `gki` or `consolidate` - modules: bt_modules dict defined in `bt_modules.bzl` + modules: bt_modules dictionary defined in `bt_modules.bzl` + config_options: decides which kernel modules to build """ kernel_build = "{}_{}".format(target, variant) - modules = [modules.get(module_name) for module_name in modules] + kernel_build_label = "//msm-kernel:{}".format(kernel_build) + modules = [bt_modules.get(module_name) for module_name in modules] + options = _get_build_options(modules, config_options) formatter = lambda s : s.replace("%b", kernel_build) + all_modules = [] for module in modules: rule_name = "{}_{}".format(kernel_build, module.name) - module_srcs = _get_module_srcs(module) + module_srcs = _get_module_srcs(module, options) ddk_module( name = rule_name, - kernel_build = "//msm-kernel:{}".format(kernel_build), + kernel_build = kernel_build_label, srcs = module_srcs, out = "{}.ko".format(module.name), - deps = ["//msm-kernel:all_headers"] + _get_module_deps(module, formatter), + deps = ["//msm-kernel:all_headers"] + _get_module_deps(module, options, formatter), includes = ["include"], + local_defines = options.keys(), visibility = ["//visibility:public"], ) -def define_bt_modules(targets): - for target in targets: - for (t, v) in get_all_variants(): - if t == target: - define_target_variant_modules(t, v, bt_modules) + all_modules.append(rule_name) + + copy_to_dist_dir( + name = "{}_bt-kernel_dist".format(kernel_build), + data = all_modules, + dist_dir = "out/target/product/{}/dlkm/lib/modules".format(target), + flat = True, + wipe_dist_dir = False, + allow_duplicate_filenames = False, + mode_overrides = {"**/*": "644"}, + log = "info", + ) + +def define_bt_modules(target, modules, config_options = []): + for (t, v) in get_all_variants(): + if t == target: + define_target_variant_modules(t, v, modules, config_options) diff --git a/bt_modules.bzl b/bt_modules.bzl index e9e2841ef9..8918e024ee 100644 --- a/bt_modules.bzl +++ b/bt_modules.bzl @@ -5,7 +5,7 @@ FMRTC_PATH = "rtc6226" # This dictionary holds all the BT modules included in the bt-kernel bt_modules = {} -def register_bt_modules(name, path = None, config_opt = None, srcs = {}, deps = []): +def register_bt_modules(name, path = None, config_opt = None, srcs = [], config_srcs = {}, deps = [], config_deps = {}): """ Register modules Args: @@ -13,14 +13,37 @@ def register_bt_modules(name, path = None, config_opt = None, srcs = {}, deps = path: Path in which the source files can be found config_opt: Config name used in Kconfig (not needed currently) srcs: source files and local headers + config_srcs: source files and local headers that depend on a config define being enabled. deps: a list of dependent targets + config_deps: a list of dependent targets that depend on a config define being enabled. """ + processed_config_srcs = {} + processed_config_deps = {} + + for config_src_name in config_srcs: + config_src = config_srcs[config_src_name] + + if type(config_src) == "list": + processed_config_srcs[config_src_name] = {True: config_src} + else: + processed_config_srcs[config_src_name] = config_src + + for config_deps_name in config_deps: + config_dep = config_deps[config_deps_name] + + if type(config_dep) == "list": + processed_config_deps[config_deps_name] = {True: config_dep} + else: + processed_config_deps[config_deps_name] = config_dep + module = struct( name = name, path = path, srcs = srcs, + config_srcs = processed_config_srcs, config_opt = config_opt, - deps = deps + deps = deps, + config_deps = processed_config_deps, ) bt_modules[name] = module @@ -29,22 +52,43 @@ def register_bt_modules(name, path = None, config_opt = None, srcs = {}, deps = register_bt_modules( name = "btpower", path = PWR_PATH, - config_opt = "CONFIG_MSM_BT_PWR", - srcs = ["btpower.c"] + config_opt = "CONFIG_MSM_BT_POWER", + srcs = ["btpower.c"], + config_deps = { + "CONFIG_BT_HW_SECURE_DISABLE": [ + "//vendor/qcom/opensource/securemsm-kernel:%b_smcinvoke_dlkm", + ] + }, ) register_bt_modules( name = "bt_fm_slim", path = SLIMBUS_PATH, - config_opt = "CONFIG_BTFM_SLIM", + # config_opt = "CONFIG_BTFM_SLIM", srcs = [ "btfm_slim.c", "btfm_slim.h", - "btfm_slim_codec.c", "btfm_slim_slave.c", "btfm_slim_slave.h", + "btfm_slim_codec.c", ], - deps = [":%b_btpower"] + deps = [":%b_btpower"], +) + +# Not enabled/compiling until btfmcodec is enabled +register_bt_modules( + name = "btfm_slim_codec", + path = SLIMBUS_PATH, + # config_opt = "CONFIG_SLIM_BTFM_CODEC", + srcs = [ + "btfm_slim.c", + "btfm_slim.h", + "btfm_slim_slave.c", + "btfm_slim_slave.h", + "btfm_slim_hw_interface.c", + "btfm_slim_hw_interface.h", + ], + deps = [":%b_btpower", ":btfmcodec_headers"], ) register_bt_modules( @@ -55,5 +99,5 @@ register_bt_modules( "radio-rtc6226-common.c", "radio-rtc6226-i2c.c", "radio-rtc6226.h", - ] + ], ) diff --git a/slimbus/btfm_slim.c b/slimbus/btfm_slim.c index 8c9bf2bed4..03142d7057 100644 --- a/slimbus/btfm_slim.c +++ b/slimbus/btfm_slim.c @@ -22,7 +22,9 @@ #include "btpower.h" #include "btfm_slim.h" #include "btfm_slim_slave.h" +#if IS_ENABLED(CONFIG_SLIM_BTFM_CODEC) #include "btfm_slim_hw_interface.h" +#endif #define DELAY_FOR_PORT_OPEN_MS (200) #define SLIM_MANF_ID_QCOM 0x217 diff --git a/slimbus/btfm_slim.h b/slimbus/btfm_slim.h index 393b0ab82a..632710dcfd 100644 --- a/slimbus/btfm_slim.h +++ b/slimbus/btfm_slim.h @@ -29,7 +29,11 @@ #define PGD 1 #define IFD 0 - +#if IS_ENABLED(CONFIG_BTFM_SLIM) +#define BTFMSLIM_DEV_NAME "btfmslim_slave" +#else +#define BTFMSLIM_DEV_NAME "btfmslim" +#endif /* Codec driver defines */ enum { diff --git a/slimbus/btfm_slim_hw_interface.c b/slimbus/btfm_slim_hw_interface.c index bcc7477a56..7d33412a32 100644 --- a/slimbus/btfm_slim_hw_interface.c +++ b/slimbus/btfm_slim_hw_interface.c @@ -329,6 +329,7 @@ static int btfm_slim_dai_get_channel_map(void *dai, switch (id) { case BTFM_FM_SLIM_TX: num = 2; + fallthrough; case BTFM_BT_SCO_SLIM_TX: if (!tx_slot || !tx_num) { BTFMSLIM_ERR("Invalid tx_slot %p or tx_num %p", diff --git a/slimbus/btfm_slim_hw_interface.h b/slimbus/btfm_slim_hw_interface.h index f51d52b882..3da2b302bb 100644 --- a/slimbus/btfm_slim_hw_interface.h +++ b/slimbus/btfm_slim_hw_interface.h @@ -6,12 +6,6 @@ #ifndef __LINUX_BTFM_SLIM_HW_INTERFACE_H #define __LINUX_BTFM_SLIM_HW_INTERFACE_H -#if IS_ENABLED(CONFIG_BTFM_SLIM) -#define BTFMSLIM_DEV_NAME "btfmslim_slave" -#else -#define BTFMSLIM_DEV_NAME "btfmslim" -#endif - // Todo protect with flags int btfm_slim_register_hw_ep(struct btfmslim *btfm_slim); void btfm_slim_unregister_hwep(void); diff --git a/target.bzl b/target.bzl new file mode 100644 index 0000000000..26e53e95fc --- /dev/null +++ b/target.bzl @@ -0,0 +1,19 @@ +load(":bt_kernel.bzl", "define_bt_modules") + +def define_pineapple(): + define_bt_modules( + target = "pineapple", + modules = [ + "btpower", + "bt_fm_slim", + "radio-i2c-rtc6226-qca", + # "btfm_slim_codec", + ], + config_options = [ + "CONFIG_MSM_BT_POWER", + "CONFIG_BTFM_SLIM", + "CONFIG_I2C_RTC6226_QCA", + # "CONFIG_SLIM_BTFM_CODEC", + "CONFIG_BT_HW_SECURE_DISABLE", + ] + ) From 2d38897294fb08a7e35b8fb321d55a64f20d8f72 Mon Sep 17 00:00:00 2001 From: Satish Kumar Kodishala Date: Mon, 5 Sep 2022 19:24:57 +0530 Subject: [PATCH 031/154] Add support for Comanche Add support for Comanche while getting logical address. CRs-Fixed: 3464807 Change-Id: I479f5c4c631f9b2a0d65792b98ad0d9c7ead9e6f --- slimbus/btfm_slim.c | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/slimbus/btfm_slim.c b/slimbus/btfm_slim.c index 03142d7057..90f461fc27 100644 --- a/slimbus/btfm_slim.c +++ b/slimbus/btfm_slim.c @@ -408,8 +408,15 @@ int btfm_slim_hw_init(struct btfmslim *btfmslim) chipset_ver == QCA_APACHE_SOC_ID_0100 || chipset_ver == QCA_APACHE_SOC_ID_0110 || chipset_ver == QCA_APACHE_SOC_ID_0120 || - chipset_ver == QCA_APACHE_SOC_ID_0121) { - BTFMSLIM_INFO("chipset is Chk/Apache, overwriting EA"); + chipset_ver == QCA_APACHE_SOC_ID_0121 || + chipset_ver == QCA_COMANCHE_SOC_ID_0101 || + chipset_ver == QCA_COMANCHE_SOC_ID_0110 || + chipset_ver == QCA_COMANCHE_SOC_ID_0120 || + chipset_ver == QCA_COMANCHE_SOC_ID_0130 || + chipset_ver == QCA_COMANCHE_SOC_ID_4130 || + chipset_ver == QCA_COMANCHE_SOC_ID_5120 || + chipset_ver == QCA_COMANCHE_SOC_ID_5130 ) { + BTFMSLIM_INFO("chipset is Chk/Apache/CMC, overwriting EA"); slim->is_laddr_valid = false; slim->e_addr.manf_id = SLIM_MANF_ID_QCOM; slim->e_addr.prod_code = 0x220; From 6ec792453079724d2c845538fb3c269a3e059bba Mon Sep 17 00:00:00 2001 From: Satish Kumar Kodishala Date: Thu, 13 Apr 2023 10:10:32 +0530 Subject: [PATCH 032/154] Add support for Moselle 1.2 SOC Add support for Moselle 1.2 SOC CRs-Fixed: 3425712 Change-Id: Icc4ee04cbc948519b8f7b1d8c8911bd071cae7f2 Signed-off-by: Satish Kumar Kodishala --- slimbus/btfm_slim.c | 3 ++- slimbus/btfm_slim_slave.h | 1 + 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/slimbus/btfm_slim.c b/slimbus/btfm_slim.c index 90f461fc27..9020ffdde8 100644 --- a/slimbus/btfm_slim.c +++ b/slimbus/btfm_slim.c @@ -358,7 +358,8 @@ int btfm_slim_hw_init(struct btfmslim *btfmslim) slim_ifd->e_addr.instance = 0x0; slim_ifd->laddr = 0x0; } else if (chipset_ver == QCA_MOSELLE_SOC_ID_0100 || - chipset_ver == QCA_MOSELLE_SOC_ID_0110) { + chipset_ver == QCA_MOSELLE_SOC_ID_0110 || + chipset_ver == QCA_MOSELLE_SOC_ID_0120) { BTFMSLIM_INFO("chipset is Moselle, overwriting EA"); slim->is_laddr_valid = false; slim->e_addr.manf_id = SLIM_MANF_ID_QCOM; diff --git a/slimbus/btfm_slim_slave.h b/slimbus/btfm_slim_slave.h index b9e1e647be..3eb0ff8f9d 100644 --- a/slimbus/btfm_slim_slave.h +++ b/slimbus/btfm_slim_slave.h @@ -120,6 +120,7 @@ enum { enum { QCA_MOSELLE_SOC_ID_0100 = 0x40140100, QCA_MOSELLE_SOC_ID_0110 = 0x40140110, + QCA_MOSELLE_SOC_ID_0120 = 0x40140120, }; enum { From dad69c09093d01c46fadd243d6f5d35ab744696f Mon Sep 17 00:00:00 2001 From: Satish Kumar Kodishala Date: Thu, 13 Apr 2023 11:41:14 +0530 Subject: [PATCH 033/154] Delay after port closure when usecase ended Delay after port closure when usecase ended for Apache. This would give some time for SB to be in right state before next usecase starts and helps in quick SHO scenarios. CRs-Fixed: 3394790 Change-Id: I6706bdbda1de9cf7d2b208ef402d2185809b55fa Signed-off-by: Satish Kumar Kodishala --- slimbus/btfm_slim.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/slimbus/btfm_slim.c b/slimbus/btfm_slim.c index 9020ffdde8..7c0ce22021 100644 --- a/slimbus/btfm_slim.c +++ b/slimbus/btfm_slim.c @@ -242,7 +242,10 @@ int btfm_slim_disable_ch(struct btfmslim *btfmslim, struct btfmslim_ch *ch, chipset_ver == QCA_HSP_SOC_ID_1211 || chipset_ver == QCA_HAMILTON_SOC_ID_0100 || chipset_ver == QCA_HAMILTON_SOC_ID_0101 || - chipset_ver == QCA_HAMILTON_SOC_ID_0200 )) { + chipset_ver == QCA_HAMILTON_SOC_ID_0200 || + chipset_ver == QCA_APACHE_SOC_ID_0100 || + chipset_ver == QCA_APACHE_SOC_ID_0110 || + chipset_ver == QCA_APACHE_SOC_ID_0121)) { BTFMSLIM_INFO("SB reset needed after all ports disabled, sleeping"); msleep(DELAY_FOR_PORT_OPEN_MS); } From 99a9cefe3186a5c71fe885834329095a9be6b78c Mon Sep 17 00:00:00 2001 From: Satish Kumar Kodishala Date: Thu, 13 Apr 2023 11:45:00 +0530 Subject: [PATCH 034/154] Assign channel pointer to NULL after free Assign channel pointer to NULL after free CRs-Fixed: 3421429 Change-Id: I23cc90c8df7124cde577ad751db9b83b6f7eee91 Signed-off-by: Satish Kumar Kodishala --- slimbus/btfm_slim.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/slimbus/btfm_slim.c b/slimbus/btfm_slim.c index 7c0ce22021..08523ead88 100644 --- a/slimbus/btfm_slim.c +++ b/slimbus/btfm_slim.c @@ -224,8 +224,12 @@ int btfm_slim_disable_ch(struct btfmslim *btfmslim, struct btfmslim_ch *ch, } } ch->dai.sconfig.port_mask = 0; - if (ch->dai.sconfig.chs != NULL) + if (ch->dai.sconfig.chs != NULL) { kfree(ch->dai.sconfig.chs); + BTFMSLIM_INFO("setting ch->dai.sconfig.chs to NULL"); + ch->dai.sconfig.chs = NULL; + } else + BTFMSLIM_ERR("ch->dai.sconfig.chs is already NULL"); if (btfm_num_ports_open > 0) btfm_num_ports_open--; From 4e02031c9f404b7b58fe56dc361a61015e6d0f65 Mon Sep 17 00:00:00 2001 From: Franklin Abreu Bueno Date: Wed, 26 Apr 2023 12:56:44 -0700 Subject: [PATCH 035/154] bt-kernel: Enable Bazel Build Enable DDK Build in Android.mk Change-Id: Ie34b4cc785904cf8d58a5fa47bc87c1fb77abf4e Signed-off-by: Franklin Abreu Bueno --- Android.mk | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/Android.mk b/Android.mk index 3331408b20..fcffc5ec19 100644 --- a/Android.mk +++ b/Android.mk @@ -18,6 +18,11 @@ endif endif LOCAL_PATH := $(call my-dir) +LOCAL_MODULE_DDK_BUILD := true +LOCAL_MODULE_KO_DIRS := pwr/btpower.ko +LOCAL_MODULE_KO_DIRS += slimbus/bt_fm_slim.ko +LOCAL_MODULE_KO_DIRS += rtc6226/radio-i2c-rtc6226-qca.ko + # This makefile is only for DLKM ifneq ($(findstring vendor,$(LOCAL_PATH)),) From 55b61275af488427f852c16d2a9aa9e02f05505f Mon Sep 17 00:00:00 2001 From: Balakrishna Godavarthi Date: Mon, 1 May 2023 21:26:34 +0530 Subject: [PATCH 036/154] btfmslim: Update DAI names to have Uniformity This changes update below DAI names to have Uniformity across multiple transports. BTFM_BT_SCO_SLIM_TX -> BTAUDIO_TX BTFM_BT_SCO_A2DP_SLIM_RX -> BTAUDIO_RX Change-Id: Ie43cb8d19c3f8520f79abf9022c7b44dc644e70f --- slimbus/btfm_slim_hw_interface.c | 12 ++++++------ slimbus/btfm_slim_hw_interface.h | 7 +++++++ 2 files changed, 13 insertions(+), 6 deletions(-) diff --git a/slimbus/btfm_slim_hw_interface.c b/slimbus/btfm_slim_hw_interface.c index 7d33412a32..69604f3268 100644 --- a/slimbus/btfm_slim_hw_interface.c +++ b/slimbus/btfm_slim_hw_interface.c @@ -445,10 +445,10 @@ static struct hwep_dai_ops btfmslim_hw_dai_ops = { static struct hwep_dai_driver btfmslim_dai_driver[] = { { /* Bluetooth SCO voice uplink: bt -> lpass */ - .dai_name = "btfm_bt_sco_slim_tx", - .id = BTFM_BT_SCO_SLIM_TX, + .dai_name = "btaudio_tx", + .id = BTAUDIO_TX, .capture = { - .stream_name = "SCO TX Capture", + .stream_name = "BT Audio Slim Tx Capture", /* 8 KHz or 16 KHz */ .rates = SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000 | SNDRV_PCM_RATE_8000_192000 @@ -464,10 +464,10 @@ static struct hwep_dai_driver btfmslim_dai_driver[] = { .dai_ops = &btfmslim_hw_dai_ops, }, { /* Bluetooth SCO voice downlink: lpass -> bt or A2DP Playback */ - .dai_name = "btfm_bt_sco_a2dp_slim_rx", - .id = BTFM_BT_SCO_A2DP_SLIM_RX, + .dai_name = "btaudio_rx", + .id = BTAUDIO_RX, .playback = { - .stream_name = "SCO A2DP RX Playback", + .stream_name = "BT Audio Slim Rx Playback", /* 8/16/44.1/48/88.2/96 Khz */ .rates = SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000 | SNDRV_PCM_RATE_8000_192000 diff --git a/slimbus/btfm_slim_hw_interface.h b/slimbus/btfm_slim_hw_interface.h index 3da2b302bb..371bf890bc 100644 --- a/slimbus/btfm_slim_hw_interface.h +++ b/slimbus/btfm_slim_hw_interface.h @@ -10,6 +10,13 @@ int btfm_slim_register_hw_ep(struct btfmslim *btfm_slim); void btfm_slim_unregister_hwep(void); +/* Codec driver defines */ +enum { + BTAUDIO_TX = 1, + BTAUDIO_RX = 2, + BTAUDIO_NUM_CODEC_DAIS +}; + typedef enum Codec { SBC = 0, AAC, From 4ad148c189bee6c811e20c62ae560c8fd2884696 Mon Sep 17 00:00:00 2001 From: Balakrishna Godavarthi Date: Thu, 25 May 2023 15:09:34 +0530 Subject: [PATCH 037/154] btfmcodec: fix compilation issue This change will protect btfm_slim_unregister_codec under a compile time flag. With out which a compilation issue is observed when btfmcodec driver is selected. Change-Id: I7fd85904c39efefd9d9819c83591098c16fc793b --- slimbus/btfm_slim.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/slimbus/btfm_slim.c b/slimbus/btfm_slim.c index 08523ead88..8074c1739d 100644 --- a/slimbus/btfm_slim.c +++ b/slimbus/btfm_slim.c @@ -681,7 +681,11 @@ device_err: class_err: unregister_chrdev(btfm_slim_major, "btfm_slim"); register_err: +#if IS_ENABLED(CONFIG_BTFM_SLIM) btfm_slim_unregister_codec(&slim->dev); +#else + btfm_slim_unregister_hwep(); +#endif dealloc: mutex_destroy(&btfm_slim->io_lock); mutex_destroy(&btfm_slim->xfer_lock); From 37707f54de67c7df51530a158bbdda086873faa9 Mon Sep 17 00:00:00 2001 From: "P.N.Janani" Date: Thu, 25 May 2023 12:37:22 +0530 Subject: [PATCH 038/154] Adding BT support for blair target -Enable BT Kernel compilation support for blair CRs-Fixed: 3509655 Change-Id: I637909670819b470081d96e68a66155aab136be9 Signed-off-by: P.N JANANI --- Android.mk | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Android.mk b/Android.mk index fcffc5ec19..b55b9473a3 100644 --- a/Android.mk +++ b/Android.mk @@ -3,7 +3,7 @@ LOCAL_PATH := $(call my-dir) # Build/Package only in case of supported target -ifeq ($(call is-board-platform-in-list,taro kalama pineapple), true) +ifeq ($(call is-board-platform-in-list,taro kalama pineapple blair), true) BT_SELECT := CONFIG_MSM_BT_POWER=m #ifdef CONFIG_SLIMBUS From 8b49d4668d20a0ee494f0d46ed98349594f2d504 Mon Sep 17 00:00:00 2001 From: satish kumar sugasi Date: Thu, 1 Jun 2023 13:18:45 -0700 Subject: [PATCH 039/154] btpower: avoid gpio pinctrl if secure mode enabled This checks for secure mode enabled in driver probe and skips sending platform device data to device probe which will try to do write default setting for bt reset gpio pin. Change-Id: I10d83b26a4b32517a6b0ff95eb0132c0be9bab3c CRs-Fixed: 3406335 Signed-off-by: satish kumar sugasi --- pwr/btpower.c | 19 ++++++++++++------- 1 file changed, 12 insertions(+), 7 deletions(-) diff --git a/pwr/btpower.c b/pwr/btpower.c index e4642ebad8..8ee43a60cf 100644 --- a/pwr/btpower.c +++ b/pwr/btpower.c @@ -1,7 +1,7 @@ // SPDX-License-Identifier: GPL-2.0-only /* * Copyright (c) 2016-2021, The Linux Foundation. All rights reserved. - * Copyright (c) 2021 Qualcomm Innovation Center, Inc. All rights reserved. + * Copyright (c) 2021-2023 Qualcomm Innovation Center, Inc. All rights reserved. */ /* @@ -273,12 +273,12 @@ int perisec_cnss_bt_hw_disable_check(struct btpower_platform_data *plat_priv) /* get rootObj */ ret = get_client_env_object(&client_env); if (ret) { - pr_debug("Failed to get client_env_object, ret: %d\n", ret); + pr_err("Failed to get client_env_object, ret: %d\n", ret); goto end; } ret = IClientEnv_open(client_env, PERISEC_HW_STATE_UID, &app_object); if (ret) { - pr_debug("Failed to get app_object, ret: %d\n", ret); + pr_err("Failed to get app_object, ret: %d\n", ret); if (ret == PERISEC_FEATURE_NOT_SUPPORTED) { ret = 0; /* Do not Assert */ plat_priv->sec_peri_feature_disable = true; @@ -292,12 +292,12 @@ int perisec_cnss_bt_hw_disable_check(struct btpower_platform_data *plat_priv) ret = Object_invoke(app_object, PERISEC_HW_OP_GET_STATE, obj_arg, ObjectCounts_pack(1, 1, 0, 0)); - pr_debug("SMC invoke ret: %d state: %d\n", ret, state); + pr_info("SMC invoke ret: %d state: %d\n", ret, state); if (ret) { if (ret == PERISEC_PERIPHERAL_NOT_FOUND) { ret = 0; /* Do not Assert */ plat_priv->sec_peri_feature_disable = true; - pr_debug("Secure HW mode is not updated. Peripheral not found\n"); + pr_info("Secure HW mode is not updated. Peripheral not found\n"); } Object_release(app_object); } else { @@ -762,7 +762,7 @@ static int bluetooth_power(int on) { int rc = 0; - pr_debug("%s: on: %d\n", __func__, on); + pr_info("%s: on: %d\n", __func__, on); rc = perisec_cnss_bt_hw_disable_check(bt_power_pdata); if (on == 1) { @@ -1208,7 +1208,12 @@ static int bt_power_probe(struct platform_device *pdev) __func__); goto free_pdata; } - pdev->dev.platform_data = bt_power_pdata; + if (bt_power_pdata->bt_sec_hw_disable) { + pr_info("%s: bt is in secure mode\n", __func__); + } else { + pr_info(" %s:send platform data of btpower\n", __func__); + pdev->dev.platform_data = bt_power_pdata; + } } else if (pdev->dev.platform_data) { /* Optional data set to default if not provided */ if (!((struct btpower_platform_data *) From cbe962c9b19040e0ab8af627a238d45edc2d8f7d Mon Sep 17 00:00:00 2001 From: Balakrishna Godavarthi Date: Thu, 8 Jun 2023 14:08:02 +0530 Subject: [PATCH 040/154] btfmcodec: Update Sampling rate for R4 Codec This change updates sampling rate to 96khz for R4 codec. Change-Id: I93bc8c88921ed0fc170efea265e45a7f9790ca3e Signed-off-by: Balakrishna Godavarthi --- slimbus/btfm_slim_hw_interface.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/slimbus/btfm_slim_hw_interface.c b/slimbus/btfm_slim_hw_interface.c index 69604f3268..34567253b8 100644 --- a/slimbus/btfm_slim_hw_interface.c +++ b/slimbus/btfm_slim_hw_interface.c @@ -195,7 +195,8 @@ void btfm_get_sampling_rate(uint32_t *sampling_rate) if (usecase_codec == LC3_VOICE || usecase_codec == APTX_AD_SPEECH || - usecase_codec == LC3 || usecase_codec == APTX_AD_QLEA) { + usecase_codec == LC3 || usecase_codec == APTX_AD_QLEA || + usecase_codec == APTX_AD_R4) { *sampling_rate = 96000; } From c49fc215ed894176e55c23dc323f6487225fd67b Mon Sep 17 00:00:00 2001 From: Balakrishna Godavarthi Date: Mon, 12 Jun 2023 21:11:10 +0530 Subject: [PATCH 041/154] btfmcodec: Update bearer response instead of ind This change will send bearer response instead of transport failed indications. Update correct codeid and smaple rate for seamles transitions Change-Id: I4b91f5e158c02d4f2dc1852cc58cec959d028497 Signed-off-by: Balakrishna Godavarthi --- btfmcodec/btfm_codec_btadv_interface.c | 5 +-- btfmcodec/btfm_codec_interface.c | 48 ++++++++++---------------- btfmcodec/include/btfm_codec_pkt.h | 2 +- 3 files changed, 22 insertions(+), 33 deletions(-) diff --git a/btfmcodec/btfm_codec_btadv_interface.c b/btfmcodec/btfm_codec_btadv_interface.c index 3817285e90..0b1bab99df 100644 --- a/btfmcodec/btfm_codec_btadv_interface.c +++ b/btfmcodec/btfm_codec_btadv_interface.c @@ -155,6 +155,7 @@ int btfmcodec_initiate_hwep_configuration(struct btfmcodec_char_device *btfmcode schedule_work(&btfmcodec_dev->wq_hwep_configure); + *status = BTM_WAITING_RSP; ret = wait_event_interruptible_timeout(*rsp_wait_q, *status != BTM_WAITING_RSP, msecs_to_jiffies(BTM_MASTER_CONFIG_RSP_TIMEOUT)); @@ -190,8 +191,8 @@ void btfmcodec_configure_hwep(struct btfmcodec_char_device *btfmcodec_dev) btfmcodec_revert_current_state(state); } - ret = btfmcodec_frame_transport_switch_ind_pkt(btfmcodec_dev, - btfmcodec_get_current_transport(state), status); + ret = btfmcodec_frame_prepare_bearer_rsp_pkt(btfmcodec_dev, + btfmcodec_get_current_transport(state), status); if (status != MSG_SUCCESS) return; diff --git a/btfmcodec/btfm_codec_interface.c b/btfmcodec/btfm_codec_interface.c index 88a70f03d7..b23b624225 100644 --- a/btfmcodec/btfm_codec_interface.c +++ b/btfmcodec/btfm_codec_interface.c @@ -18,29 +18,23 @@ static int btfm_codec_get_mixer_control(struct snd_kcontrol *kcontrol, struct snd_soc_component *codec = kcontrol->private_data; struct btfmcodec_data *btfmcodec = snd_soc_component_get_drvdata(codec); struct hwep_data *hwepinfo = btfmcodec->hwep_info; - struct btfmcodec_state_machine states = btfmcodec->states; struct snd_kcontrol_new *mixer_ctrl = hwepinfo->mixer_ctrl; struct snd_ctl_elem_id id = kcontrol->id; int num_mixer_ctrl = hwepinfo->num_mixer_ctrl; int i = 0; BTFMCODEC_DBG(""); - if (states.current_state != IDLE) { - BTFMCODEC_WARN("Received probe when state is :%s", - coverttostring(states.current_state)); - } else { - for (; i < num_mixer_ctrl ; i++) { - BTFMCODEC_DBG("checking mixer_ctrl:%s and current mixer:%s", - id.name, mixer_ctrl[i].name); - if (!strncmp(id.name, mixer_ctrl[i].name, 64)) { - BTFMCODEC_DBG("Matched"); - mixer_ctrl[i].get(kcontrol, ucontrol); - break; - } + for (; i < num_mixer_ctrl ; i++) { + BTFMCODEC_DBG("checking mixer_ctrl:%s and current mixer:%s", + id.name, mixer_ctrl[i].name); + if (!strncmp(id.name, mixer_ctrl[i].name, 64)) { + BTFMCODEC_DBG("Matched"); + mixer_ctrl[i].get(kcontrol, ucontrol); + break; } - if (num_mixer_ctrl == i) - return 0; } + if (num_mixer_ctrl == i) + return 0; return 1; } @@ -51,29 +45,23 @@ static int btfmcodec_put_mixer_control(struct snd_kcontrol *kcontrol, struct snd_soc_component *codec = kcontrol->private_data; struct btfmcodec_data *btfmcodec = snd_soc_component_get_drvdata(codec); struct hwep_data *hwepinfo = btfmcodec->hwep_info; - struct btfmcodec_state_machine states = btfmcodec->states; struct snd_kcontrol_new *mixer_ctrl = hwepinfo->mixer_ctrl; struct snd_ctl_elem_id id = kcontrol->id; int num_mixer_ctrl = hwepinfo->num_mixer_ctrl; int i = 0; BTFMCODEC_DBG(""); - if (states.current_state != IDLE) { - BTFMCODEC_WARN("Received probe when state is :%s", - coverttostring(states.current_state)); - } else { - for (; i < num_mixer_ctrl ; i++) { - BTFMCODEC_DBG("checking mixer_ctrl:%s and current mixer:%s", - id.name, mixer_ctrl[i].name); - if (!strncmp(id.name, mixer_ctrl[i].name, 64)) { - BTFMCODEC_DBG("Matched"); - mixer_ctrl[i].put(kcontrol, ucontrol); - break; - } + for (; i < num_mixer_ctrl ; i++) { + BTFMCODEC_DBG("checking mixer_ctrl:%s and current mixer:%s", + id.name, mixer_ctrl[i].name); + if (!strncmp(id.name, mixer_ctrl[i].name, 64)) { + BTFMCODEC_DBG("Matched"); + mixer_ctrl[i].put(kcontrol, ucontrol); + break; } - if (num_mixer_ctrl == i) - return 0; } + if (num_mixer_ctrl == i) + return 0; return 1; } diff --git a/btfmcodec/include/btfm_codec_pkt.h b/btfmcodec/include/btfm_codec_pkt.h index 3e48b7c839..e8e83f7710 100644 --- a/btfmcodec/include/btfm_codec_pkt.h +++ b/btfmcodec/include/btfm_codec_pkt.h @@ -42,7 +42,7 @@ struct btm_ctrl_pkt { #define BTM_BTFMCODEC_TRANSPORT_SWITCH_FAILED_IND 0x58000002 #define BTM_MASTER_CONFIG_REQ_LEN 13 -#define BTM_MASTER_CONFIG_RSP_TIMEOUT 1000 +#define BTM_MASTER_CONFIG_RSP_TIMEOUT 5000 #define BTM_HEADER_LEN 8 #define BTM_PREPARE_AUDIO_BEARER_SWITCH_RSP_LEN 2 #define BTM_MASTER_CONFIG_RSP_LEN 2 From 89985878911e80cb5635d6ccd0882c20ada4b1e8 Mon Sep 17 00:00:00 2001 From: Balakrishna Godavarthi Date: Tue, 20 Jun 2023 20:46:07 +0530 Subject: [PATCH 042/154] btfmcodec: Enable Dynamic logging This change will enable dynamic logging based on below flags Below bit has to be set to enable respective logging. * Bit 0: Error message. * Bit 1: Warning message. * Bit 2: Debug message. * Bit 3: Info message. * 0x08 is similar to 0x0F. * 0x04 is similar to 0x07. * 0x02 is similar to 0x03. * 0x03 is default log level for BTFM Codec. Change-Id: Ia986a49f73d6144f2631936b8d02985d3ccf98d0 Signed-off-by: Balakrishna Godavarthi --- btfmcodec/btfm_codec.c | 11 +++++++++++ btfmcodec/include/btfm_codec.h | 18 ++++++++++++++++-- btfmcodec/include/btfm_codec_pkt.h | 18 ++++++++++-------- 3 files changed, 37 insertions(+), 10 deletions(-) diff --git a/btfmcodec/btfm_codec.c b/btfmcodec/btfm_codec.c index 6b62f91936..aeb1130491 100644 --- a/btfmcodec/btfm_codec.c +++ b/btfmcodec/btfm_codec.c @@ -23,6 +23,7 @@ static dev_t dev_major; struct btfmcodec_data *btfmcodec; struct device_driver driver = {.name = "btfmcodec-driver", .owner = THIS_MODULE}; struct btfmcodec_char_device *btfmcodec_dev; + #define cdev_to_btfmchardev(_cdev) container_of(_cdev, struct btfmcodec_char_device, cdev) #define MIN_PKT_LEN 0x9 @@ -214,6 +215,16 @@ static void btfmcodec_dev_rxwork(struct work_struct *work) status); wake_up_interruptible(&btfmcodec_dev->rsp_wait_q[idx]); break; + case BTM_BTFMCODEC_CTRL_LOG_LVL_IND: + if (len == BTM_LOG_LVL_IND_LEN) { + log_lvl = skb->data[0]; + } else { + BTFMCODEC_ERR("wrong packet format with len:%d", len); + } + BTFMCODEC_INFO("Rx BTM_BTFMCODEC_CTRL_LOG_LVL_IND status:%d", + log_lvl); + wake_up_interruptible(&btfmcodec_dev->rsp_wait_q[idx]); + break; default: BTFMCODEC_ERR("wrong opcode:%08x", opcode); } diff --git a/btfmcodec/include/btfm_codec.h b/btfmcodec/include/btfm_codec.h index 4ed3ecea44..2f05639a78 100644 --- a/btfmcodec/include/btfm_codec.h +++ b/btfmcodec/include/btfm_codec.h @@ -13,10 +13,24 @@ #include #include "btfm_codec_hw_interface.h" -#define BTFMCODEC_DBG(fmt, arg...) pr_err("%s: " fmt "\n", __func__, ## arg) -#define BTFMCODEC_INFO(fmt, arg...) pr_err("%s: " fmt "\n", __func__, ## arg) +#define BTM_BTFMCODEC_DEFAULT_LOG_LVL 0x03 +#define BTM_BTFMCODEC_DEBUG_LOG_LVL 0x04 +#define BTM_BTFMCODEC_INFO_LOG_LVL 0x08 + +static uint8_t log_lvl = BTM_BTFMCODEC_DEFAULT_LOG_LVL; + #define BTFMCODEC_ERR(fmt, arg...) pr_err("%s: " fmt "\n", __func__, ## arg) #define BTFMCODEC_WARN(fmt, arg...) pr_warn("%s: " fmt "\n", __func__, ## arg) +#define BTFMCODEC_DBG(fmt, arg...) { if(log_lvl >= BTM_BTFMCODEC_DEBUG_LOG_LVL) \ + pr_err("%s: " fmt "\n", __func__, ## arg); \ + else \ + pr_debug("%s: " fmt "\n", __func__, ## arg); \ + } +#define BTFMCODEC_INFO(fmt, arg...) { if(log_lvl >= BTM_BTFMCODEC_INFO_LOG_LVL) \ + pr_err("%s: " fmt "\n", __func__, ## arg);\ + else \ + pr_info("%s: " fmt "\n", __func__, ## arg);\ + } #define DEVICE_NAME_MAX_LEN 64 diff --git a/btfmcodec/include/btfm_codec_pkt.h b/btfmcodec/include/btfm_codec_pkt.h index e8e83f7710..12f604bc60 100644 --- a/btfmcodec/include/btfm_codec_pkt.h +++ b/btfmcodec/include/btfm_codec_pkt.h @@ -32,14 +32,15 @@ struct btm_ctrl_pkt { uint8_t status; }__attribute__((packed)); -#define BTM_BTFMCODEC_PREPARE_AUDIO_BEARER_SWITCH_REQ 0x50000000 -#define BTM_BTFMCODEC_PREPARE_AUDIO_BEARER_SWITCH_RSP 0x50000001 -#define BTM_BTFMCODEC_MASTER_CONFIG_REQ 0x50000002 -#define BTM_BTFMCODEC_MASTER_CONFIG_RSP 0x50000003 -#define BTM_BTFMCODEC_MASTER_SHUTDOWN_REQ 0x50000004 -#define BTM_BTFMCODEC_CTRL_MASTER_SHUTDOWN_RSP 0x50000005 -#define BTM_BTFMCODEC_BEARER_SWITCH_IND 0x58000001 -#define BTM_BTFMCODEC_TRANSPORT_SWITCH_FAILED_IND 0x58000002 +#define BTM_BTFMCODEC_PREPARE_AUDIO_BEARER_SWITCH_REQ 0x50000000 +#define BTM_BTFMCODEC_PREPARE_AUDIO_BEARER_SWITCH_RSP 0x50000001 +#define BTM_BTFMCODEC_MASTER_CONFIG_REQ 0x50000002 +#define BTM_BTFMCODEC_MASTER_CONFIG_RSP 0x50000003 +#define BTM_BTFMCODEC_MASTER_SHUTDOWN_REQ 0x50000004 +#define BTM_BTFMCODEC_CTRL_MASTER_SHUTDOWN_RSP 0x50000005 +#define BTM_BTFMCODEC_BEARER_SWITCH_IND 0x58000001 +#define BTM_BTFMCODEC_TRANSPORT_SWITCH_FAILED_IND 0x58000002 +#define BTM_BTFMCODEC_CTRL_LOG_LVL_IND 0x58000004 #define BTM_MASTER_CONFIG_REQ_LEN 13 #define BTM_MASTER_CONFIG_RSP_TIMEOUT 5000 @@ -49,6 +50,7 @@ struct btm_ctrl_pkt { #define BTM_MASTER_SHUTDOWN_REQ_LEN 1 #define BTM_PREPARE_AUDIO_BEARER_SWITCH_REQ_LEN 1 #define BTM_BEARER_SWITCH_IND_LEN 1 +#define BTM_LOG_LVL_IND_LEN 1 enum rx_status { /* Waiting for response */ From 818edfe5ace5f4dff75b2d7c01f77d1e8cc96142 Mon Sep 17 00:00:00 2001 From: satish kumar sugasi Date: Fri, 16 Jun 2023 15:34:40 -0700 Subject: [PATCH 043/154] btpower: release secure mode state object during bluetooth secure mode check process, once state of peripheral is invoked and read successfully, release state object to avoid leak. Change-Id: I826702d2a57cd92b57e6e50ca40a3dcafd82a8b7 Signed-off-by: satish kumar sugasi --- pwr/btpower.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pwr/btpower.c b/pwr/btpower.c index 8ee43a60cf..e01f3ac856 100644 --- a/pwr/btpower.c +++ b/pwr/btpower.c @@ -299,13 +299,13 @@ int perisec_cnss_bt_hw_disable_check(struct btpower_platform_data *plat_priv) plat_priv->sec_peri_feature_disable = true; pr_info("Secure HW mode is not updated. Peripheral not found\n"); } - Object_release(app_object); } else { if (state == 1) plat_priv->bt_sec_hw_disable = 1; else plat_priv->bt_sec_hw_disable = 0; } + Object_release(app_object); exit_release_clientenv: Object_release(client_env); From fd58910c2da3eee399e43f539ac1f8237950704c Mon Sep 17 00:00:00 2001 From: Balakrishna Godavarthi Date: Thu, 8 Jun 2023 14:17:21 +0530 Subject: [PATCH 044/154] btfmcodec: Notify ADSP SSR to host This change notifies ADSP SSR to host when it completely boots up. Change-Id: Icfa5a895a6f31e662ba4e7d2b818a7a75854f248 Signed-off-by: Balakrishna Godavarthi --- btfmcodec/btfm_codec_interface.c | 46 ++++++++++++++++++++++++++++++ btfmcodec/include/btfm_codec.h | 6 ++++ btfmcodec/include/btfm_codec_pkt.h | 9 ++++++ 3 files changed, 61 insertions(+) diff --git a/btfmcodec/btfm_codec_interface.c b/btfmcodec/btfm_codec_interface.c index b23b624225..e6d3d379ba 100644 --- a/btfmcodec/btfm_codec_interface.c +++ b/btfmcodec/btfm_codec_interface.c @@ -4,6 +4,8 @@ */ #include +#include +#include #include "btfm_codec.h" #include "btfm_codec_interface.h" #include "btfm_codec_pkt.h" @@ -676,6 +678,40 @@ static struct snd_soc_dai_ops btfmcodec_dai_ops = { .get_channel_map = btfmcodec_dai_get_channel_map, }; +static int btfmcodec_adsp_ssr_notify(struct notifier_block *nb, + unsigned long action, void *data) +{ + struct btfmcodec_data *btfmcodec = container_of(nb, + struct btfmcodec_data, notifier.nb); + struct btfmcodec_char_device *btfmcodec_dev = btfmcodec->btfmcodec_dev; + struct btm_adsp_state_ind state_ind; + + switch (action) { + case QCOM_SSR_BEFORE_SHUTDOWN: { + BTFMCODEC_WARN("LPASS SSR triggered"); + break; + } case QCOM_SSR_AFTER_SHUTDOWN: { + BTFMCODEC_WARN("LPASS SSR Completed"); + break; + } case QCOM_SSR_BEFORE_POWERUP: { + BTFMCODEC_WARN("LPASS booted up after SSR"); + break; + } case QCOM_SSR_AFTER_POWERUP: { + BTFMCODEC_WARN("LPASS booted up completely"); + state_ind.opcode = BTM_BTFMCODEC_ADSP_STATE_IND; + state_ind.len = BTM_ADSP_STATE_IND_LEN; + state_ind.action = (uint32_t)action; + btfmcodec_dev_enqueue_pkt(btfmcodec_dev, &state_ind, + (state_ind.len + + BTM_HEADER_LEN)); + break; + } default: + BTFMCODEC_WARN("unhandled action id %lu", action); + break; + } + return 0; +} + int btfm_register_codec(struct hwep_data *hwep_info) { struct btfmcodec_data *btfmcodec; @@ -687,6 +723,16 @@ int btfm_register_codec(struct hwep_data *hwep_info) btfmcodec = btfm_get_btfmcodec(); btfmcodec_dev = btfmcodec->btfmcodec_dev; dev = &btfmcodec->dev; + + btfmcodec->notifier.nb.notifier_call = btfmcodec_adsp_ssr_notify; + btfmcodec->notifier.notifier = qcom_register_ssr_notifier("lpass", + &btfmcodec->notifier.nb); + if (IS_ERR(btfmcodec->notifier.notifier)) { + ret = PTR_ERR(btfmcodec->notifier.notifier); + BTFMCODEC_ERR("Failed to register SSR notification: %d\n", ret); + return ret; + } + btfmcodec_dai_info = kzalloc((sizeof(struct snd_soc_dai_driver) * hwep_info->num_dai), GFP_KERNEL); if (!btfmcodec_dai_info) { BTFMCODEC_ERR("failed to allocate memory"); diff --git a/btfmcodec/include/btfm_codec.h b/btfmcodec/include/btfm_codec.h index 2f05639a78..88c7117997 100644 --- a/btfmcodec/include/btfm_codec.h +++ b/btfmcodec/include/btfm_codec.h @@ -86,12 +86,18 @@ struct btfmcodec_char_device { void *btfmcodec; }; +struct adsp_notifier { + void *notifier; + struct notifier_block nb; +}; + struct btfmcodec_data { struct device dev; struct btfmcodec_state_machine states; struct btfmcodec_char_device *btfmcodec_dev; struct hwep_data *hwep_info; struct list_head config_head; + struct adsp_notifier notifier; }; struct btfmcodec_data *btfm_get_btfmcodec(void); diff --git a/btfmcodec/include/btfm_codec_pkt.h b/btfmcodec/include/btfm_codec_pkt.h index 12f604bc60..cc75c2e357 100644 --- a/btfmcodec/include/btfm_codec_pkt.h +++ b/btfmcodec/include/btfm_codec_pkt.h @@ -40,6 +40,7 @@ struct btm_ctrl_pkt { #define BTM_BTFMCODEC_CTRL_MASTER_SHUTDOWN_RSP 0x50000005 #define BTM_BTFMCODEC_BEARER_SWITCH_IND 0x58000001 #define BTM_BTFMCODEC_TRANSPORT_SWITCH_FAILED_IND 0x58000002 +#define BTM_BTFMCODEC_ADSP_STATE_IND 0x58000003 #define BTM_BTFMCODEC_CTRL_LOG_LVL_IND 0x58000004 #define BTM_MASTER_CONFIG_REQ_LEN 13 @@ -51,6 +52,7 @@ struct btm_ctrl_pkt { #define BTM_PREPARE_AUDIO_BEARER_SWITCH_REQ_LEN 1 #define BTM_BEARER_SWITCH_IND_LEN 1 #define BTM_LOG_LVL_IND_LEN 1 +#define BTM_ADSP_STATE_IND_LEN 4 enum rx_status { /* Waiting for response */ @@ -94,6 +96,13 @@ struct btm_master_shutdown_req { uint32_t len; uint8_t stream_id; }__attribute__((packed)); + +struct btm_adsp_state_ind { + btm_opcode opcode; + uint32_t len; + uint32_t action; +} __attribute__((packed)); + int btfmcodec_dev_enqueue_pkt(struct btfmcodec_char_device *, void *, int); bool btfmcodec_is_valid_cache_avb(struct btfmcodec_data *); #endif /* __LINUX_BTFM_CODEC_PKT_H*/ From f6eccaaf19577aa39f7a46a127fa5e3cfa27efbb Mon Sep 17 00:00:00 2001 From: Balakrishna Godavarthi Date: Wed, 5 Jul 2023 19:34:18 +0530 Subject: [PATCH 045/154] btfmcodec: fix logging errors This change add format specifiers wherever required. Change-Id: I8bac382b0cc50e302ed780335510c0ba7df279fa Signed-off-by: Balakrishna Godavarthi --- btfmcodec/btfm_codec.c | 14 ++++++-------- btfmcodec/btfm_codec_btadv_interface.c | 2 +- btfmcodec/btfm_codec_interface.c | 8 ++++---- 3 files changed, 11 insertions(+), 13 deletions(-) diff --git a/btfmcodec/btfm_codec.c b/btfmcodec/btfm_codec.c index aeb1130491..a970e59793 100644 --- a/btfmcodec/btfm_codec.c +++ b/btfmcodec/btfm_codec.c @@ -361,7 +361,7 @@ static __poll_t btfmcodec_dev_poll(struct file *file, poll_table *wait) mutex_lock(&btfmcodec_dev->lock); /* recheck if the client has released by the driver */ if (refcount_read(&btfmcodec_dev->active_clients) == 1) { - BTFMCODEC_WARN("port has been closed alreadt"); + BTFMCODEC_WARN("port has been closed already"); mutex_unlock(&btfmcodec_dev->lock); return POLLHUP; } @@ -465,9 +465,7 @@ static ssize_t btfmcodec_attributes_store(struct device *dev, mutex_lock(&btfmcodec_dev->lock); if (kstrtol(buf, 0, &tmp)) { mutex_unlock(&btfmcodec_dev->lock); -/* BTFMCODEC_ERR("unable to convert string to int for /dev/%s\n", - btfmcodec->dev->name); -*/ return -EINVAL; + return -EINVAL; } mutex_unlock(&btfmcodec_dev->lock); @@ -619,9 +617,9 @@ static void __exit btfmcodec_deinit(void) { struct btfmcodec_char_device *btfmcodec_dev; struct device *dev; - BTFMCODEC_INFO("cleaning up btfm codec driver", __func__); + BTFMCODEC_INFO("%s: cleaning up btfm codec driver", __func__); if (!btfmcodec) { - BTFMCODEC_ERR("skiping driver cleanup", __func__); + BTFMCODEC_ERR("%s: skiping driver cleanup", __func__); goto info_cleanup; } @@ -631,7 +629,7 @@ static void __exit btfmcodec_deinit(void) put_device(dev); if (!btfmcodec->btfmcodec_dev) { - BTFMCODEC_ERR("skiping device node cleanup", __func__); + BTFMCODEC_ERR("%s: skiping device node cleanup", __func__); goto info_cleanup; } @@ -643,7 +641,7 @@ static void __exit btfmcodec_deinit(void) kfree(btfmcodec_dev); info_cleanup: kfree(btfmcodec); - BTFMCODEC_INFO("btfm codec driver cleanup completed", __func__); + BTFMCODEC_INFO("%s: btfm codec driver cleanup completed", __func__); return; } diff --git a/btfmcodec/btfm_codec_btadv_interface.c b/btfmcodec/btfm_codec_btadv_interface.c index 0b1bab99df..a73bc972ba 100644 --- a/btfmcodec/btfm_codec_btadv_interface.c +++ b/btfmcodec/btfm_codec_btadv_interface.c @@ -322,6 +322,6 @@ void btfmcodec_wq_prepare_bearer(struct work_struct *work) struct btfmcodec_char_device, wq_prepare_bearer); int idx = BTM_PKT_TYPE_PREPARE_REQ; - BTFMCODEC_INFO(": with new transport:%d", btfmcodec_dev->status[idx]); + BTFMCODEC_INFO("with new transport:%d", btfmcodec_dev->status[idx]); btfmcodec_prepare_bearer(btfmcodec_dev, btfmcodec_dev->status[idx]); } diff --git a/btfmcodec/btfm_codec_interface.c b/btfmcodec/btfm_codec_interface.c index e6d3d379ba..b3c563b76a 100644 --- a/btfmcodec/btfm_codec_interface.c +++ b/btfmcodec/btfm_codec_interface.c @@ -75,7 +75,7 @@ static int btfmcodec_codec_probe(struct snd_soc_component *codec) int num_mixer_ctrl = hwep_info->num_mixer_ctrl; BTFMCODEC_DBG(""); - // ToDo: check weather probe has to allowed when state if different + // ToDo: check Whether probe has to allowed when state if different if (btfmcodec_get_current_transport(state)!= IDLE) { BTFMCODEC_WARN("Received probe when state is :%s", coverttostring(btfmcodec_get_current_transport(state))); @@ -284,7 +284,7 @@ void btfmcodec_wq_hwep_shutdown(struct work_struct *work) BTFMCODEC_INFO("shuting down dai id:%d", hwep_configs->stream_id); ret = btfmcodec_hwep_shutdown(btfmcodec, hwep_configs->stream_id, true); if (ret < 0) { - BTFMCODEC_ERR("failed to shutdown master with id", hwep_configs->stream_id); + BTFMCODEC_ERR("failed to shutdown master with id %d", hwep_configs->stream_id); break; } } @@ -657,7 +657,7 @@ void btfmcodec_wq_hwep_configure(struct work_struct *work) if (ret >= 0) ret = btfmcodec_hwep_prepare(btfmcodec, sample_rate, direction, id); if (ret < 0) { - BTFMCODEC_ERR("failed to configure hwep", hwep_configs->stream_id); + BTFMCODEC_ERR("failed to configure hwep %d", hwep_configs->stream_id); break; } } @@ -753,7 +753,7 @@ int btfm_register_codec(struct hwep_data *hwep_info) ret = snd_soc_register_component(dev, &btfmcodec_codec_component, btfmcodec_dai_info, hwep_info->num_dai); BTFMCODEC_INFO("Dev node address: %p", dev); - BTFMCODEC_INFO("btfmcodec address :%p, btfmcodec"); + BTFMCODEC_INFO("btfmcodec address :%p", btfmcodec); BTFMCODEC_INFO("HWEPINFO address:%p", hwep_info); BTFMCODEC_INFO("btfmcodec_dev INFO address:%p", btfmcodec->btfmcodec_dev); BTFMCODEC_INFO("before wq_hwep_shutdown:%p", btfmcodec_dev->wq_hwep_shutdown); From 38173f406967e9559fe74c873d83e93f087ec392 Mon Sep 17 00:00:00 2001 From: Satish Kumar Kodishala Date: Thu, 11 May 2023 15:32:45 +0530 Subject: [PATCH 046/154] Request to suspend after all ports are closed Request core slimbus to suspend after all ports are closed. This is to early reset slimbus hw instead and avoid waiting till time out after ports closure. CRs-Fixed: 3536919 Change-Id: I1bf92b2651d9ee8716a06144ef75f9cb2779c415 Signed-off-by: Satish Kumar Kodishala --- slimbus/btfm_slim.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/slimbus/btfm_slim.c b/slimbus/btfm_slim.c index 8074c1739d..7e3372d647 100644 --- a/slimbus/btfm_slim.c +++ b/slimbus/btfm_slim.c @@ -1,7 +1,7 @@ // SPDX-License-Identifier: GPL-2.0-only /* * Copyright (c) 2016-2021, The Linux Foundation. All rights reserved. - * Copyright (c) 2021 Qualcomm Innovation Center, Inc. All rights reserved. + * Copyright (c) 2021-2023 Qualcomm Innovation Center, Inc. All rights reserved. */ #include @@ -26,7 +26,7 @@ #include "btfm_slim_hw_interface.h" #endif -#define DELAY_FOR_PORT_OPEN_MS (200) +#define DELAY_FOR_PORT_OPEN_MS (20) #define SLIM_MANF_ID_QCOM 0x217 #define SLIM_PROD_CODE 0x221 #define BT_CMD_SLIM_TEST 0xbfac @@ -250,7 +250,8 @@ int btfm_slim_disable_ch(struct btfmslim *btfmslim, struct btfmslim_ch *ch, chipset_ver == QCA_APACHE_SOC_ID_0100 || chipset_ver == QCA_APACHE_SOC_ID_0110 || chipset_ver == QCA_APACHE_SOC_ID_0121)) { - BTFMSLIM_INFO("SB reset needed after all ports disabled, sleeping"); + BTFMSLIM_INFO("SB reset needed after all ports disabled, send suspend and sleep"); + slim_vote_for_suspend(btfmslim->slim_pgd); msleep(DELAY_FOR_PORT_OPEN_MS); } From c0568d1c4d8728729f777f630028d0a904236dcc Mon Sep 17 00:00:00 2001 From: Satish Kumar Kodishala Date: Wed, 17 May 2023 15:19:33 +0530 Subject: [PATCH 047/154] Register only once with ALSA Register only once with ALSA. CRs-Fixed: 3543436 Change-Id: Ibc9bffd048921a7e3666c41771e9e08349af57d3 Signed-off-by: Satish Kumar Kodishala --- slimbus/btfm_slim.c | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/slimbus/btfm_slim.c b/slimbus/btfm_slim.c index 7e3372d647..70ac2d700e 100644 --- a/slimbus/btfm_slim.c +++ b/slimbus/btfm_slim.c @@ -38,6 +38,8 @@ struct btfmslim *btfm_slim_drv_data; static int btfm_num_ports_open; +static bool is_registered; + int btfm_slim_write(struct btfmslim *btfmslim, uint16_t reg, uint8_t reg_val, uint8_t pgd) { @@ -577,7 +579,11 @@ static int btfm_slim_status(struct slim_device *sdev, btfm_slim = dev_get_drvdata(dev); #if IS_ENABLED(CONFIG_BTFM_SLIM) - ret = btfm_slim_register_codec(btfm_slim); + if (!is_registered) { + ret = btfm_slim_register_codec(btfm_slim); + if (ret == 0) + is_registered = true; + } #else btfm_slim_get_hwep_details(sdev, btfm_slim); ret = btfm_slim_register_hw_ep(btfm_slim); @@ -613,6 +619,7 @@ static int btfm_slim_probe(struct slim_device *slim) pr_info("%s: name = %s\n", __func__, dev_name(&slim->dev)); /*this as true during the probe then slimbus won't check for logical address*/ slim->is_laddr_valid = true; + is_registered = false; dev_set_name(&slim->dev, "%s", BTFMSLIM_DEV_NAME); pr_info("%s: name = %s\n", __func__, dev_name(&slim->dev)); From 63d367af6b5b685ec9b45d3204180c14eb58a063 Mon Sep 17 00:00:00 2001 From: Balakrishna Godavarthi Date: Thu, 29 Jun 2023 12:18:57 +0530 Subject: [PATCH 048/154] btfmslim: Register only once with btfmcodec driver This change will register hardware endpoint with btfmcodec driver during initial boot. Based on the further changes to slimbus status will not take any effect with driver registrations. Change-Id: I1a3c20d111ed4288c26ab7e72168745e34b03bd5 Signed-off-by: Balakrishna Godavarthi --- slimbus/btfm_slim.c | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/slimbus/btfm_slim.c b/slimbus/btfm_slim.c index 70ac2d700e..0ad4a00361 100644 --- a/slimbus/btfm_slim.c +++ b/slimbus/btfm_slim.c @@ -581,15 +581,18 @@ static int btfm_slim_status(struct slim_device *sdev, #if IS_ENABLED(CONFIG_BTFM_SLIM) if (!is_registered) { ret = btfm_slim_register_codec(btfm_slim); - if (ret == 0) - is_registered = true; } #else - btfm_slim_get_hwep_details(sdev, btfm_slim); - ret = btfm_slim_register_hw_ep(btfm_slim); + if (!is_registered) { + btfm_slim_get_hwep_details(sdev, btfm_slim); + ret = btfm_slim_register_hw_ep(btfm_slim); + } #endif - if (ret) + if (!ret) + is_registered = true; + else BTFMSLIM_ERR("error, registering slimbus codec failed"); + return ret; } From 6b32d8743b9cf349fce2819b2e34d611b34a7feb Mon Sep 17 00:00:00 2001 From: Balakrishna Godavarthi Date: Fri, 7 Jul 2023 12:02:22 +0530 Subject: [PATCH 049/154] btfmcodec: Cache configs for all the transitions This change will cache configs for all the transitions Change-Id: If1201fd8cf045fcc2a6c4d83d50e3dd939ebc3a4 Signed-off-by: Balakrishna Godavarthi --- btfmcodec/btfm_codec_interface.c | 33 ++++++++++++--------- btfmcodec/include/btfm_codec_hw_interface.h | 3 +- slimbus/btfm_slim_hw_interface.c | 3 +- 3 files changed, 23 insertions(+), 16 deletions(-) diff --git a/btfmcodec/btfm_codec_interface.c b/btfmcodec/btfm_codec_interface.c index b3c563b76a..5fe7e3c905 100644 --- a/btfmcodec/btfm_codec_interface.c +++ b/btfmcodec/btfm_codec_interface.c @@ -13,6 +13,7 @@ static struct snd_soc_dai_driver *btfmcodec_dai_info; uint32_t bits_per_second; +uint8_t num_channels; static int btfm_codec_get_mixer_control(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) @@ -344,7 +345,7 @@ static void btfmcodec_dai_shutdown(struct snd_pcm_substream *substream, } int btfmcodec_hwep_hw_params (struct btfmcodec_data *btfmcodec, uint32_t bps, - uint32_t direction) + uint32_t direction, uint8_t num_channels) { struct hwep_data *hwep_info = btfmcodec->hwep_info; struct hwep_dai_driver *dai_drv = (struct hwep_dai_driver *) @@ -352,7 +353,8 @@ int btfmcodec_hwep_hw_params (struct btfmcodec_data *btfmcodec, uint32_t bps, if (dai_drv && dai_drv->dai_ops && dai_drv->dai_ops->hwep_hw_params) { return dai_drv->dai_ops->hwep_hw_params((void *)btfmcodec->hwep_info, - bps, direction); + bps, direction, + num_channels); } else { return -1; } @@ -364,20 +366,21 @@ static int btfmcodec_dai_hw_params(struct snd_pcm_substream *substream, { struct btfmcodec_data *btfmcodec = snd_soc_component_get_drvdata(dai->component); struct btfmcodec_state_machine *state = &btfmcodec->states; - uint32_t bps = params_width(params); uint32_t direction = substream->stream; BTFMCODEC_DBG("dai->name = %s DAI-ID %x rate %d bps %d num_ch %d", dai->name, dai->id, params_rate(params), params_width(params), params_channels(params)); + bits_per_second = params_width(params); + num_channels = params_channels(params); if (btfmcodec_get_current_transport(state) != IDLE && btfmcodec_get_current_transport(state) != BT_Connected) { - BTFMCODEC_WARN("caching bps as state is :%s", + BTFMCODEC_WARN("caching bps and num_channels as state is :%s", coverttostring(btfmcodec_get_current_transport(state))); - bits_per_second = bps; } else { - return btfmcodec_hwep_hw_params(btfmcodec, bps, direction); + return btfmcodec_hwep_hw_params(btfmcodec, bits_per_second, + direction, num_channels); } return 0; @@ -424,6 +427,7 @@ static int btfmcodec_check_and_cache_configs(struct btfmcodec_data *btfmcodec, hwep_configs->bit_width = bits_per_second; hwep_configs->codectype = codectype; hwep_configs->direction = direction; + hwep_configs->num_channels = num_channels; list_add(&hwep_configs->dai_list, head); BTFMCODEC_INFO("added dai id:%d to list with sampling_rate :%u, direction:%u", id, sampling_rate, direction); @@ -535,24 +539,24 @@ static int btfmcodec_dai_prepare(struct snd_pcm_substream *substream, uint32_t sampling_rate = dai->rate; uint32_t direction = substream->stream; int id = dai->id; - int ret; + int ret ; BTFMCODEC_INFO("dai->name: %s, dai->id: %d, dai->rate: %d direction: %d", dai->name, id, sampling_rate, direction); + ret = btfmcodec_check_and_cache_configs(btfmcodec, sampling_rate, + direction, id, *codectype); if (btfmcodec_get_current_transport(state) != IDLE && btfmcodec_get_current_transport(state) != BT_Connected) { - BTFMCODEC_WARN("caching required info as state is:%s", + BTFMCODEC_WARN("cached required info as state is:%s", coverttostring(btfmcodec_get_current_transport(state))); - ret = btfmcodec_check_and_cache_configs(btfmcodec, sampling_rate, direction, - id, *codectype); } else { ret = btfmcodec_hwep_prepare(btfmcodec, sampling_rate, direction, id); - if (ret >= 0) { +/* if (ret >= 0) { btfmcodec_check_and_cache_configs(btfmcodec, sampling_rate, direction, id, *codectype); } - } +*/ } return ret; } @@ -641,7 +645,7 @@ void btfmcodec_wq_hwep_configure(struct work_struct *work) int ret; int idx = BTM_PKT_TYPE_HWEP_CONFIG; uint32_t sample_rate, direction; - uint8_t id, bit_width, codectype; + uint8_t id, bit_width, codectype, num_channels; list_for_each_entry(hwep_configs, head, dai_list) { id = hwep_configs->stream_id; @@ -649,11 +653,12 @@ void btfmcodec_wq_hwep_configure(struct work_struct *work) bit_width = hwep_configs->bit_width; codectype = hwep_configs->codectype; direction = hwep_configs->direction; + num_channels = hwep_configs->num_channels; BTFMCODEC_INFO("configuring dai id:%d with sampling rate:%d bit_width:%d", id, sample_rate, bit_width); ret = btfmcodec_hwep_startup(btfmcodec); if (ret >= 0) - ret = btfmcodec_hwep_hw_params(btfmcodec, bit_width, direction); + ret = btfmcodec_hwep_hw_params(btfmcodec, bit_width, direction, num_channels); if (ret >= 0) ret = btfmcodec_hwep_prepare(btfmcodec, sample_rate, direction, id); if (ret < 0) { diff --git a/btfmcodec/include/btfm_codec_hw_interface.h b/btfmcodec/include/btfm_codec_hw_interface.h index 60163b95ab..bf8e2e6790 100644 --- a/btfmcodec/include/btfm_codec_hw_interface.h +++ b/btfmcodec/include/btfm_codec_hw_interface.h @@ -27,6 +27,7 @@ struct hwep_configurations { uint8_t bit_width; uint8_t codectype; uint32_t direction; + uint8_t num_channels; struct list_head dai_list; }; @@ -51,7 +52,7 @@ struct hwep_comp_drv { struct hwep_dai_ops { int (*hwep_startup)(void *); void (*hwep_shutdown)(void *, int); - int (*hwep_hw_params)(void *, uint32_t, uint32_t); + int (*hwep_hw_params)(void *, uint32_t, uint32_t, uint8_t); int (*hwep_prepare)(void *, uint32_t, uint32_t, int); int (*hwep_set_channel_map)(void *, unsigned int, unsigned int *, unsigned int, unsigned int *); diff --git a/slimbus/btfm_slim_hw_interface.c b/slimbus/btfm_slim_hw_interface.c index 34567253b8..9cc08cc9bd 100644 --- a/slimbus/btfm_slim_hw_interface.c +++ b/slimbus/btfm_slim_hw_interface.c @@ -167,7 +167,8 @@ static void btfm_slim_dai_shutdown(void *dai, int id) } static int btfm_slim_dai_hw_params(void *dai, uint32_t bps, - uint32_t direction) { + uint32_t direction, + uint8_t num_channels) { struct hwep_data *hwep_info = (struct hwep_data *)dai; struct btfmslim *btfmslim = dev_get_drvdata(hwep_info->dev); From 240ba24497c0dbe2a812e3eb65ff39c7927c7fa2 Mon Sep 17 00:00:00 2001 From: Reut Zysman Date: Wed, 5 Jul 2023 10:28:59 -0700 Subject: [PATCH 050/154] btpower: Remove unused dependency Remove dependency on smcinvoke.h. Change-Id: I82d80d3f901d761070b2900701b70ee054d89888 Signed-off-by: Reut Zysman --- pwr/btpower.c | 1 - 1 file changed, 1 deletion(-) diff --git a/pwr/btpower.c b/pwr/btpower.c index e01f3ac856..52f671383f 100644 --- a/pwr/btpower.c +++ b/pwr/btpower.c @@ -33,7 +33,6 @@ #include #ifdef CONFIG_BT_HW_SECURE_DISABLE -#include "linux/smcinvoke.h" #include "linux/smcinvoke_object.h" #include "linux/IClientEnv.h" From 360a8bd705c234b499a6cc301d34a2fb1a4ca563 Mon Sep 17 00:00:00 2001 From: Balakrishna Godavarthi Date: Wed, 9 Aug 2023 22:22:14 +0530 Subject: [PATCH 051/154] Update R3 codec sampling rate to 192k This change updates R3 codec sampling rate to 192k. CRs-Fixed: 3585575 Change-Id: I316b021a0c737050b98cd51bfe6f7bc3a0f511f3 Signed-off-by: Balakrishna Godavarthi --- slimbus/btfm_slim_hw_interface.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/slimbus/btfm_slim_hw_interface.c b/slimbus/btfm_slim_hw_interface.c index 9cc08cc9bd..0a2eeea973 100644 --- a/slimbus/btfm_slim_hw_interface.c +++ b/slimbus/btfm_slim_hw_interface.c @@ -196,11 +196,13 @@ void btfm_get_sampling_rate(uint32_t *sampling_rate) if (usecase_codec == LC3_VOICE || usecase_codec == APTX_AD_SPEECH || - usecase_codec == LC3 || usecase_codec == APTX_AD_QLEA || - usecase_codec == APTX_AD_R4) { + usecase_codec == LC3 || usecase_codec == APTX_AD_R4) { *sampling_rate = 96000; } + if (usecase_codec == APTX_AD_QLEA) + *sampling_rate = 192000; + BTFMSLIM_INFO("current usecase codec type %s and sampling rate:%u khz", codec_text[usecase_codec], *sampling_rate); } From 1408642d4f5ab4db2b474bedb06f03ffe879f537 Mon Sep 17 00:00:00 2001 From: Satish Kumar Kodishala Date: Thu, 17 Aug 2023 11:02:53 +0530 Subject: [PATCH 052/154] Revert "Request to suspend after all ports are closed" This reverts commit 38173f406967e9559fe74c873d83e93f087ec392. Change-Id: I9e85e9a558176124fb238410358537b741123d38 Signed-off-by: Satish Kumar Kodishala --- slimbus/btfm_slim.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/slimbus/btfm_slim.c b/slimbus/btfm_slim.c index 0ad4a00361..436008a93b 100644 --- a/slimbus/btfm_slim.c +++ b/slimbus/btfm_slim.c @@ -26,7 +26,7 @@ #include "btfm_slim_hw_interface.h" #endif -#define DELAY_FOR_PORT_OPEN_MS (20) +#define DELAY_FOR_PORT_OPEN_MS (200) #define SLIM_MANF_ID_QCOM 0x217 #define SLIM_PROD_CODE 0x221 #define BT_CMD_SLIM_TEST 0xbfac @@ -252,8 +252,7 @@ int btfm_slim_disable_ch(struct btfmslim *btfmslim, struct btfmslim_ch *ch, chipset_ver == QCA_APACHE_SOC_ID_0100 || chipset_ver == QCA_APACHE_SOC_ID_0110 || chipset_ver == QCA_APACHE_SOC_ID_0121)) { - BTFMSLIM_INFO("SB reset needed after all ports disabled, send suspend and sleep"); - slim_vote_for_suspend(btfmslim->slim_pgd); + BTFMSLIM_INFO("SB reset needed after all ports disabled, sleeping"); msleep(DELAY_FOR_PORT_OPEN_MS); } From d1e8e16be6580fa030bb966f8797459a12950b6d Mon Sep 17 00:00:00 2001 From: Balakrishna Godavarthi Date: Tue, 29 Aug 2023 15:31:19 +0530 Subject: [PATCH 053/154] btfmcodec: Update with list_for_each_entry_safe API This changes updates list_for_each_entry API with list_for_each_entry_safe API. Change-Id: Ifeb684ba1407123aef5b5b922e843a8089a6236f Signed-off-by: Balakrishna Godavarthi --- btfmcodec/btfm_codec_interface.c | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/btfmcodec/btfm_codec_interface.c b/btfmcodec/btfm_codec_interface.c index 5fe7e3c905..38c2660861 100644 --- a/btfmcodec/btfm_codec_interface.c +++ b/btfmcodec/btfm_codec_interface.c @@ -273,7 +273,7 @@ void btfmcodec_wq_hwep_shutdown(struct work_struct *work) wq_hwep_shutdown); struct btfmcodec_data *btfmcodec = (struct btfmcodec_data *)btfmcodec_dev->btfmcodec; struct list_head *head = &btfmcodec->config_head; - struct hwep_configurations *hwep_configs = NULL; + struct hwep_configurations *hwep_configs = NULL, *tmp; int ret = -1; int idx = BTM_PKT_TYPE_HWEP_SHUTDOWN; @@ -281,7 +281,7 @@ void btfmcodec_wq_hwep_shutdown(struct work_struct *work) /* Just check if first Rx has to be closed first or * any order should be ok. */ - list_for_each_entry(hwep_configs, head, dai_list) { + list_for_each_entry_safe(hwep_configs, tmp, head, dai_list) { BTFMCODEC_INFO("shuting down dai id:%d", hwep_configs->stream_id); ret = btfmcodec_hwep_shutdown(btfmcodec, hwep_configs->stream_id, true); if (ret < 0) { @@ -301,10 +301,10 @@ void btfmcodec_wq_hwep_shutdown(struct work_struct *work) static int btfmcodec_delete_configs(struct btfmcodec_data *btfmcodec, uint8_t id) { struct list_head *head = &btfmcodec->config_head; - struct hwep_configurations *hwep_configs; + struct hwep_configurations *hwep_configs, *tmp; int ret = -1; - list_for_each_entry(hwep_configs, head, dai_list) { + list_for_each_entry_safe(hwep_configs, tmp, head, dai_list) { if (hwep_configs->stream_id == id) { BTFMCODEC_INFO("deleting configs with id %d", id); list_del(&hwep_configs->dai_list); @@ -389,10 +389,10 @@ static int btfmcodec_dai_hw_params(struct snd_pcm_substream *substream, bool btfmcodec_is_valid_cache_avb(struct btfmcodec_data *btfmcodec) { struct list_head *head = &btfmcodec->config_head; - struct hwep_configurations *hwep_configs; + struct hwep_configurations *hwep_configs, *tmp; bool cache_avb = false; - list_for_each_entry(hwep_configs, head, dai_list) { + list_for_each_entry_safe(hwep_configs, tmp, head, dai_list) { cache_avb = true; break; } @@ -405,9 +405,9 @@ static int btfmcodec_check_and_cache_configs(struct btfmcodec_data *btfmcodec, int id, uint8_t codectype) { struct list_head *head = &btfmcodec->config_head; - struct hwep_configurations *hwep_configs; + struct hwep_configurations *hwep_configs, *tmp; - list_for_each_entry(hwep_configs, head, dai_list) { + list_for_each_entry_safe(hwep_configs, tmp, head, dai_list) { if (hwep_configs->stream_id == id) { BTFMCODEC_WARN("previous entry for %d is already available", id); @@ -641,13 +641,13 @@ void btfmcodec_wq_hwep_configure(struct work_struct *work) wq_hwep_configure); struct btfmcodec_data *btfmcodec = (struct btfmcodec_data *)btfmcodec_dev->btfmcodec; struct list_head *head = &btfmcodec->config_head; - struct hwep_configurations *hwep_configs = NULL; + struct hwep_configurations *hwep_configs = NULL, *tmp; int ret; int idx = BTM_PKT_TYPE_HWEP_CONFIG; uint32_t sample_rate, direction; uint8_t id, bit_width, codectype, num_channels; - list_for_each_entry(hwep_configs, head, dai_list) { + list_for_each_entry_safe(hwep_configs, tmp, head, dai_list) { id = hwep_configs->stream_id; sample_rate = hwep_configs->sample_rate; bit_width = hwep_configs->bit_width; From 245f899293a62de06caf509ff0740f278168191d Mon Sep 17 00:00:00 2001 From: zhiwyan Date: Tue, 5 Sep 2023 21:27:04 +0800 Subject: [PATCH 054/154] bt-kernel: add configuration for special bt kiwi add new compatible for special bt kiwi case as qcom,bt-ant-ldo can't be supported for HDK kiwi. CRs-Fixed: 3607042 Change-Id: I1e072be95481231a5f54b83a74205298038e058d Signed-off-by: zhiwyan --- pwr/btpower.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/pwr/btpower.c b/pwr/btpower.c index e01f3ac856..147ee80f8f 100644 --- a/pwr/btpower.c +++ b/pwr/btpower.c @@ -218,6 +218,12 @@ static struct bt_power bt_vreg_info_kiwi = { .num_vregs = ARRAY_SIZE(bt_vregs_info_kiwi), }; +static struct bt_power bt_vreg_info_kiwi_no_share_ant_power = { + .compatible = "qcom,kiwi-no-share-ant-power", + .vregs = bt_vregs_info_kiwi, + .num_vregs = ARRAY_SIZE(bt_vregs_info_kiwi), +}; + static struct bt_power bt_vreg_info_converged = { .compatible = "qcom,bt-qca-converged", .vregs = bt_vregs_info_kiwi, @@ -236,6 +242,8 @@ static const struct of_device_id bt_power_match_table[] = { { .compatible = "qcom,qca6390", .data = &bt_vreg_info_qca6390}, { .compatible = "qcom,qca6490", .data = &bt_vreg_info_qca6490}, { .compatible = "qcom,kiwi", .data = &bt_vreg_info_kiwi}, + { .compatible = "qcom,kiwi-no-share-ant-power", + .data = &bt_vreg_info_kiwi_no_share_ant_power}, { .compatible = "qcom,wcn6750-bt", .data = &bt_vreg_info_wcn6750}, { .compatible = "qcom,bt-qca-converged", .data = &bt_vreg_info_converged}, {}, From 2318d40d9fc843a737ef565ea6cdeca1dd1243ea Mon Sep 17 00:00:00 2001 From: pramod kotreshappa Date: Thu, 21 Sep 2023 13:03:44 -0700 Subject: [PATCH 055/154] Align to LTS6.3 changes - class_create takes one argument. - new i2c probe function with one argument. Change-Id: I3d0c91ba4d181d1d44ba69415824a0ec863ff60b --- btfmcodec/btfm_codec.c | 2 +- pwr/btpower.c | 2 +- rtc6226/radio-rtc6226-i2c.c | 6 +++--- slimbus/btfm_slim.c | 2 +- 4 files changed, 6 insertions(+), 6 deletions(-) diff --git a/btfmcodec/btfm_codec.c b/btfmcodec/btfm_codec.c index a970e59793..e6ee51ac77 100644 --- a/btfmcodec/btfm_codec.c +++ b/btfmcodec/btfm_codec.c @@ -524,7 +524,7 @@ static int __init btfmcodec_init(void) } BTFMCODEC_INFO("creating btfm codec class"); - dev_class = class_create(THIS_MODULE, "btfmcodec"); + dev_class = class_create("btfmcodec"); if (IS_ERR(dev_class)) { ret = PTR_ERR(dev_class); BTFMCODEC_ERR("class_create failed ret:%d\n", ret); diff --git a/pwr/btpower.c b/pwr/btpower.c index 147ee80f8f..8667b47e81 100644 --- a/pwr/btpower.c +++ b/pwr/btpower.c @@ -1511,7 +1511,7 @@ static int __init btpower_init(void) goto chrdev_err; } - bt_class = class_create(THIS_MODULE, "bt-dev"); + bt_class = class_create("bt-dev"); if (IS_ERR(bt_class)) { pr_err("%s: coudn't create class\n", __func__); ret = -1; diff --git a/rtc6226/radio-rtc6226-i2c.c b/rtc6226/radio-rtc6226-i2c.c index 4e688bfa85..4b9bb8b7b6 100644 --- a/rtc6226/radio-rtc6226-i2c.c +++ b/rtc6226/radio-rtc6226-i2c.c @@ -34,6 +34,7 @@ #include #include #include +#include #include "radio-rtc6226.h" #include #include @@ -545,7 +546,7 @@ int rtc6226_fops_open(struct file *file) struct rtc6226_device *radio = video_drvdata(file); int retval; - FMDBG("%s enter user num = %d\n", __func__, radio->users); + //FMDBG("%s enter user num = %d\n", __func__, radio->users); if (atomic_inc_return(&radio->users) != 1) { FMDERR("Device already in use. Try again later\n"); atomic_dec(&radio->users); @@ -698,8 +699,7 @@ static int rtc6226_dt_parse_vreg_info(struct device *dev, /* * rtc6226_i2c_probe - probe for the device */ -static int rtc6226_i2c_probe(struct i2c_client *client, - const struct i2c_device_id *id) +static int rtc6226_i2c_probe(struct i2c_client *client) { struct rtc6226_device *radio; struct v4l2_device *v4l2_dev; diff --git a/slimbus/btfm_slim.c b/slimbus/btfm_slim.c index 8074c1739d..ca7521ce1a 100644 --- a/slimbus/btfm_slim.c +++ b/slimbus/btfm_slim.c @@ -661,7 +661,7 @@ static int btfm_slim_probe(struct slim_device *slim) goto register_err; } - btfm_slim_class = class_create(THIS_MODULE, "btfmslim-dev"); + btfm_slim_class = class_create("btfmslim-dev"); if (IS_ERR(btfm_slim_class)) { BTFMSLIM_ERR("%s: coudn't create class\n", __func__); ret = -1; From cd581c70f757b855f094f0803ad0ec3193326bb8 Mon Sep 17 00:00:00 2001 From: pramod kotreshappa Date: Fri, 15 Sep 2023 14:01:45 -0700 Subject: [PATCH 056/154] Enable QMAA for bluetooth Change-Id: I3b48b37ff255cbfbe647e1d915fd14d8df8993eb --- Android.mk | 20 ++++++++++---------- bt_kernel_product_board.mk | 6 +++--- bt_kernel_vendor_board.mk | 12 ++++++------ target.bzl | 6 +++--- 4 files changed, 22 insertions(+), 22 deletions(-) diff --git a/Android.mk b/Android.mk index b55b9473a3..50d4f1a641 100644 --- a/Android.mk +++ b/Android.mk @@ -3,11 +3,11 @@ LOCAL_PATH := $(call my-dir) # Build/Package only in case of supported target -ifeq ($(call is-board-platform-in-list,taro kalama pineapple blair), true) +ifeq ($(call is-board-platform-in-list,taro kalama pineapple blair sun), true) BT_SELECT := CONFIG_MSM_BT_POWER=m #ifdef CONFIG_SLIMBUS -BT_SELECT += CONFIG_BTFM_SLIM=m +BT_SELECT += CONFIG_BTFM_SLIM=n #endif BT_SELECT += CONFIG_I2C_RTC6226_QCA=m @@ -80,14 +80,14 @@ LOCAL_MODULE_DEBUG_ENABLE := true LOCAL_MODULE_PATH := $(KERNEL_MODULES_OUT) include $(DLKM_DIR)/Build_external_kernelmodule.mk ################################ slimbus ################################ -include $(CLEAR_VARS) -LOCAL_SRC_FILES := $(BT_SRC_FILES) -LOCAL_MODULE := bt_fm_slim.ko -LOCAL_MODULE_KBUILD_NAME := slimbus/bt_fm_slim.ko -LOCAL_MODULE_TAGS := optional -LOCAL_MODULE_DEBUG_ENABLE := true -LOCAL_MODULE_PATH := $(KERNEL_MODULES_OUT) -include $(DLKM_DIR)/Build_external_kernelmodule.mk +#include $(CLEAR_VARS) +#LOCAL_SRC_FILES := $(BT_SRC_FILES) +#LOCAL_MODULE := bt_fm_slim.ko +#LOCAL_MODULE_KBUILD_NAME := slimbus/bt_fm_slim.ko +#LOCAL_MODULE_TAGS := optional +#LOCAL_MODULE_DEBUG_ENABLE := true +#LOCAL_MODULE_PATH := $(KERNEL_MODULES_OUT) +#include $(DLKM_DIR)/Build_external_kernelmodule.mk ################################ rtc6226 ################################ include $(CLEAR_VARS) LOCAL_SRC_FILES := $(BT_SRC_FILES) diff --git a/bt_kernel_product_board.mk b/bt_kernel_product_board.mk index 15d265662e..6d22eee61e 100644 --- a/bt_kernel_product_board.mk +++ b/bt_kernel_product_board.mk @@ -1,5 +1,5 @@ # Build BT kernel drivers -PRODUCT_PACKAGES += $(KERNEL_MODULES_OUT)/btpower.ko\ - $(KERNEL_MODULES_OUT)/bt_fm_slim.ko \ - $(KERNEL_MODULES_OUT)/radio-i2c-rtc6226-qca.ko +PRODUCT_PACKAGES += $(KERNEL_MODULES_OUT)/btpower.ko +#PRODUCT_PACKAGES += $(KERNEL_MODULES_OUT)/bt_fm_slim.ko +PRODUCT_PACKAGES += $(KERNEL_MODULES_OUT)/radio-i2c-rtc6226-qca.ko diff --git a/bt_kernel_vendor_board.mk b/bt_kernel_vendor_board.mk index 1c8ce659ce..fc86885a6d 100644 --- a/bt_kernel_vendor_board.mk +++ b/bt_kernel_vendor_board.mk @@ -3,17 +3,17 @@ ifneq ($(TARGET_BOARD_AUTO),true) ifeq ($(TARGET_USES_QMAA),true) ifeq ($(TARGET_USES_QMAA_OVERRIDE_BLUETOOTH), true) ifeq ($(call is-board-platform-in-list,$(TARGET_BOARD_PLATFORM)),true) - BT_KERNEL_DRIVER := $(KERNEL_MODULES_OUT)/btpower.ko\ - $(KERNEL_MODULES_OUT)/bt_fm_slim.ko \ - $(KERNEL_MODULES_OUT)/radio-i2c-rtc6226-qca.ko + BT_KERNEL_DRIVER := $(KERNEL_MODULES_OUT)/btpower.ko + #BT_KERNEL_DRIVER += $(KERNEL_MODULES_OUT)/bt_fm_slim.ko + BT_KERNEL_DRIVER += $(KERNEL_MODULES_OUT)/radio-i2c-rtc6226-qca.ko BOARD_VENDOR_KERNEL_MODULES += $(BT_KERNEL_DRIVER) endif endif else ifeq ($(call is-board-platform-in-list,$(TARGET_BOARD_PLATFORM)),true) - BT_KERNEL_DRIVER := $(KERNEL_MODULES_OUT)/btpower.ko\ - $(KERNEL_MODULES_OUT)/bt_fm_slim.ko \ - $(KERNEL_MODULES_OUT)/radio-i2c-rtc6226-qca.ko + BT_KERNEL_DRIVER := $(KERNEL_MODULES_OUT)/btpower.ko + #BT_KERNEL_DRIVER += $(KERNEL_MODULES_OUT)/bt_fm_slim.ko + BT_KERNEL_DRIVER += $(KERNEL_MODULES_OUT)/radio-i2c-rtc6226-qca.ko BOARD_VENDOR_KERNEL_MODULES += $(BT_KERNEL_DRIVER) endif endif diff --git a/target.bzl b/target.bzl index 26e53e95fc..d7a6d674cd 100644 --- a/target.bzl +++ b/target.bzl @@ -5,15 +5,15 @@ def define_pineapple(): target = "pineapple", modules = [ "btpower", - "bt_fm_slim", + #"bt_fm_slim", "radio-i2c-rtc6226-qca", # "btfm_slim_codec", ], config_options = [ "CONFIG_MSM_BT_POWER", - "CONFIG_BTFM_SLIM", + #"CONFIG_BTFM_SLIM", "CONFIG_I2C_RTC6226_QCA", # "CONFIG_SLIM_BTFM_CODEC", - "CONFIG_BT_HW_SECURE_DISABLE", + #"CONFIG_BT_HW_SECURE_DISABLE", ] ) From d638487f1065006e0505c237bf310557c5f8015e Mon Sep 17 00:00:00 2001 From: Satish Kumar Kodishala Date: Mon, 25 Sep 2023 12:24:01 +0530 Subject: [PATCH 057/154] Add support for BT/FM SoundWire slave driver Added support for BT/FM SoundWire slave driver. The driver registers as a codec driver with ALSA. Slave port configuration is sent to master driver. Master driver takes care of programming master and slave registers at once when BT audio usecase is started/stopped. Change-Id: I3a4de9872323c470f2ec73218601be94a768d726 Signed-off-by: Satish Kumar Kodishala --- soundwire/Kconfig | 12 ++ soundwire/Makefile | 3 + soundwire/btfm_swr.c | 288 +++++++++++++++++++++++++++++++ soundwire/btfm_swr.h | 103 +++++++++++ soundwire/btfm_swr_codec.c | 341 +++++++++++++++++++++++++++++++++++++ soundwire/btfm_swr_slave.c | 44 +++++ soundwire/btfm_swr_slave.h | 45 +++++ 7 files changed, 836 insertions(+) create mode 100644 soundwire/Kconfig create mode 100644 soundwire/Makefile create mode 100644 soundwire/btfm_swr.c create mode 100644 soundwire/btfm_swr.h create mode 100644 soundwire/btfm_swr_codec.c create mode 100644 soundwire/btfm_swr_slave.c create mode 100644 soundwire/btfm_swr_slave.h diff --git a/soundwire/Kconfig b/soundwire/Kconfig new file mode 100644 index 0000000000..f01fac6089 --- /dev/null +++ b/soundwire/Kconfig @@ -0,0 +1,12 @@ + +config BTFM_SWR + tristate "MSM Bluetooth/FM SoundWire Device" + depends on MSM_BT_POWER + help + This enables BT/FM soundwire driver to open/close ports. + This will make use of soundwire bus driver and soundwire + master driver to communicate with soundwire slave. + + Say Y here to compile support for Bluetooth/FM soundwire slave driver + into the kernel or say M to compile as a module. + diff --git a/soundwire/Makefile b/soundwire/Makefile new file mode 100644 index 0000000000..04eb9a25e3 --- /dev/null +++ b/soundwire/Makefile @@ -0,0 +1,3 @@ +ccflags-y += -I$(BT_ROOT)/include +bt_fm_swr-objs := btfm_swr.o btfm_swr_codec.o btfm_swr_slave.o +obj-$(CONFIG_BTFM_SWR) += bt_fm_swr.o diff --git a/soundwire/btfm_swr.c b/soundwire/btfm_swr.c new file mode 100644 index 0000000000..c40271d5de --- /dev/null +++ b/soundwire/btfm_swr.c @@ -0,0 +1,288 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2023 Qualcomm Innovation Center, Inc. All rights reserved. + */ + + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "btpower.h" +#include "btfm_swr.h" +#include "btfm_swr_slave.h" + +struct class *btfm_swr_class; +static int btfm_swr_major; +struct btfmswr *pbtfmswr; +static int btfm_num_ports_open; + +#define BT_CMD_SWR_TEST 0xbfac + +static int btfm_swr_probe(struct swr_device *pdev); + +int btfm_get_bt_soc_index(int chipset_ver) +{ + switch (chipset_ver) { + case QCA_GANGES_SOC_ID_0100: + case QCA_GANGES_SOC_ID_0200: + return GANGES; + case QCA_EVROS_SOC_ID_0100: + case QCA_EVROS_SOC_ID_0200: + return EVROS; + default: + BTFMSWR_ERR("no BT SOC id defined, returning EVROS"); + return EVROS; + } +} + +int btfm_swr_hw_init(void) +{ + uint8_t dev_num = 0; + int ret = 0; + int chipset_ver; + + BTFMSWR_DBG(""); + + if (pbtfmswr->initialized) + BTFMSWR_INFO("Already initialized"); + + // get BT chipset version + chipset_ver = btpower_get_chipset_version(); + + // get BT/FM SOC slave port details + pbtfmswr->soc_index = btfm_get_bt_soc_index(chipset_ver); + + BTFMSWR_INFO("chipset soc version:%x, soc index: %x", chipset_ver, + pbtfmswr->soc_index); + + pbtfmswr->p_dai_port = &slave_port[pbtfmswr->soc_index]; + + // get logical address + /* + * Add 5msec delay to provide sufficient time for + * soundwire auto enumeration of slave devices as + * per HW requirement. + */ + usleep_range(5000, 5010); + ret = swr_get_logical_dev_num(pbtfmswr->swr_slave, pbtfmswr->p_dai_port->ea, + &dev_num); + if (ret) { + BTFMSWR_ERR("error while getting logical device number"); + goto err; + } + + pbtfmswr->swr_slave->dev_num = dev_num; + pbtfmswr->initialized = true; + +err: + return ret; +} + +int btfm_swr_enable_port(u8 port_num, u8 ch_count, u32 sample_rate, u8 usecase) +{ + int ret = 0; + u8 port_id[MAX_BT_PORTS]; + u8 num_ch[MAX_BT_PORTS]; + u8 ch_mask[MAX_BT_PORTS]; + u32 ch_rate[MAX_BT_PORTS]; + u8 port_type[MAX_BT_PORTS]; + u8 num_port = 1; + + // master expects port num -1 to be sent + port_id[0] = port_num-1; + num_ch[0] = ch_count; + ch_mask[0] = ch_count == 2 ? TWO_CHANNEL_MASK : ONE_CHANNEL_MASK; + ch_rate[0] = sample_rate; + port_type[0] = usecase; + + BTFMSWR_INFO("enabling port : %d\n", port_num); + ret = swr_connect_port(pbtfmswr->swr_slave, &port_id[0], num_port, + &ch_mask[0], &ch_rate[0], &num_ch[0], + &port_type[0]); + + if (ret < 0) { + BTFMSWR_ERR("swr_connect_port failed, error %d", ret); + return ret; + } + + BTFMSWR_INFO("calling swr_slvdev_datapath_control\n"); + ret = swr_slvdev_datapath_control(pbtfmswr->swr_slave, + pbtfmswr->swr_slave->dev_num, + true); + if (ret < 0) + BTFMSWR_ERR("swr_slvdev_datapath_control failed"); + + if (ret == 0) + btfm_num_ports_open++; + + BTFMSWR_INFO("btfm_num_ports_open: %d", btfm_num_ports_open); + + return ret; +} + +int btfm_swr_disable_port(u8 port_num, u8 ch_count, u8 usecase) +{ + int ret = 0; + u8 port_id[MAX_BT_PORTS]; + u8 ch_mask[MAX_BT_PORTS]; + u8 port_type[MAX_BT_PORTS]; + u8 num_port = 1; + + // master expects port num -1 to be sent + port_id[0] = port_num-1; + ch_mask[0] = ch_count == 2 ? TWO_CHANNEL_MASK : ONE_CHANNEL_MASK; + port_type[0] = usecase; + + BTFMSWR_INFO("disabling port : %d\n", port_num); + ret = swr_disconnect_port(pbtfmswr->swr_slave, &port_id[0], num_port, + &ch_mask[0], &port_type[0]); + + if (ret < 0) + BTFMSWR_ERR("swr_disconnect_port port failed, error %d", ret); + + BTFMSWR_INFO("calling swr_slvdev_datapath_control\n"); + ret = swr_slvdev_datapath_control(pbtfmswr->swr_slave, + pbtfmswr->swr_slave->dev_num, + false); + if (ret < 0) + BTFMSWR_ERR("swr_slvdev_datapath_control failed"); + + if (btfm_num_ports_open > 0) + btfm_num_ports_open--; + + BTFMSWR_INFO("btfm_num_ports_open: %d", btfm_num_ports_open); + + return ret; +} + +static long btfm_swr_ioctl(struct file *file, unsigned int cmd, unsigned long arg) +{ + int ret = 0; + + BTFMSWR_INFO(""); + switch (cmd) { + case BT_CMD_SWR_TEST: + BTFMSWR_INFO("cmd BT_CMD_SLIM_TEST, call btfm_swr_hw_init"); + ret = btfm_swr_hw_init(); + break; + } + return ret; +} + +static const struct file_operations bt_dev_fops = { + .unlocked_ioctl = btfm_swr_ioctl, + .compat_ioctl = btfm_swr_ioctl, +}; + +static int btfm_swr_probe(struct swr_device *pdev) +{ + int ret = 0; + + BTFMSWR_INFO(""); + + pbtfmswr = devm_kzalloc(&pdev->dev, + sizeof(struct btfmswr), GFP_KERNEL); + if (!pbtfmswr) { + BTFMSWR_ERR("memory allocation to driver failed"); + return -ENOMEM; + } + + swr_set_dev_data(pdev, pbtfmswr); + pbtfmswr->swr_slave = pdev; + pbtfmswr->dev = &pdev->dev; + pbtfmswr->initialized = false; + + // register with ALSA + ret = btfm_swr_register_codec(pbtfmswr); + if (ret) { + BTFMSWR_ERR("registration with ALSA failed, returning"); + goto dealloc; + } + + btfm_swr_major = register_chrdev(0, "btfm_swr", &bt_dev_fops); + if (btfm_swr_major < 0) { + BTFMSWR_ERR("%s: failed to allocate char dev\n", __func__); + ret = -1; + goto register_err; + } + + btfm_swr_class = class_create(THIS_MODULE, "btfmswr-dev"); + if (IS_ERR(btfm_swr_class)) { + BTFMSWR_ERR("%s: coudn't create class\n", __func__); + ret = -1; + goto class_err; + } + + if (device_create(btfm_swr_class, NULL, MKDEV(btfm_swr_major, 0), + NULL, "btfmswr") == NULL) { + BTFMSWR_ERR("%s: failed to allocate char dev\n", __func__); + ret = -1; + goto device_err; + } + return ret; + +device_err: + class_destroy(btfm_swr_class); +class_err: + unregister_chrdev(btfm_swr_major, "btfm_swr"); + +register_err: + btfm_swr_unregister_codec(pbtfmswr->dev); + +dealloc: + kfree(pbtfmswr); + return ret; +} + +static const struct swr_device_id btfm_swr_id[] = { + {SWR_SLAVE_COMPATIBLE_STR, 0}, + {} +}; + +static const struct of_device_id btfm_swr_dt_match[] = { + { + .compatible = "qcom,btfmswr_slave", + }, + {} +}; + +static struct swr_driver btfm_swr_driver = { + .driver = { + .name = "btfmswr-driver", + .owner = THIS_MODULE, + .of_match_table = btfm_swr_dt_match, + }, + .probe = btfm_swr_probe, + .id_table = btfm_swr_id, +}; + +static int __init btfm_swr_init(void) +{ + BTFMSWR_INFO(""); + return swr_driver_register(&btfm_swr_driver); +} + +static void __exit btfm_swr_exit(void) +{ + BTFMSWR_INFO(""); + swr_driver_unregister(&btfm_swr_driver); +} + +module_init(btfm_swr_init); +module_exit(btfm_swr_exit); + +MODULE_LICENSE("GPL v2"); +MODULE_DESCRIPTION("BTFM SoundWire Slave driver"); + diff --git a/soundwire/btfm_swr.h b/soundwire/btfm_swr.h new file mode 100644 index 0000000000..a1e9b7ab86 --- /dev/null +++ b/soundwire/btfm_swr.h @@ -0,0 +1,103 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2023 Qualcomm Innovation Center, Inc. All rights reserved. + */ + + +#ifndef BTFM_SWR_H +#define BTFM_SWR_H + +#include +#include +#include +#include "soc/soundwire.h" + +#define SWR_SLAVE_COMPATIBLE_STR "btfmswr_slave" + + +#define BTFMSWR_DBG(fmt, arg...) pr_debug("%s: " fmt "\n", __func__, ## arg) +#define BTFMSWR_INFO(fmt, arg...) pr_info("%s: " fmt "\n", __func__, ## arg) +#define BTFMSWR_ERR(fmt, arg...) pr_err("%s: " fmt "\n", __func__, ## arg) + +extern struct btfmswr *pbtfmswr; + +// assumption is that we use adjacent channels +#define ONE_CHANNEL_MASK 1 +#define TWO_CHANNEL_MASK 3 + +#define MAX_BT_PORTS 1 + +/* Codec driver defines */ +enum { + FMAUDIO_TX = 0, + BTAUDIO_TX, + BTAUDIO_RX, + BTAUDIO_A2DP_SINK_TX, + BTFM_NUM_CODEC_DAIS +}; + +enum { + EVROS = 0, + GANGES = 1, + MAX_SOC_ID = 0xFF +}; + + +struct btfmswr_dai_port_info { + int dai_id; + char *dai_name; + uint8_t port; +}; + +struct soc_port_mapping { + // enumeration address of BT SOC + u64 ea; + struct btfmswr_dai_port_info port_info[BTFM_NUM_CODEC_DAIS]; +}; + + +struct btfmswr { + struct device *dev; + struct swr_device *swr_slave; + bool initialized; + uint32_t sample_rate; + uint32_t bps; + uint16_t direction; + uint8_t num_channels; + int soc_index; + struct soc_port_mapping *p_dai_port; +}; + +/** + * btfm_swr_hw_init: Initialize soundwire slave device + * Returns: + * 0: Success + * else: Fail + */ +int btfm_swr_hw_init(void); + +int btfm_get_bt_soc_index(int chipset_ver); + +int btfm_swr_enable_port(u8 port_num, u8 ch_count, u32 sample_rate, + u8 port_type); + + +int btfm_swr_disable_port(u8 port_num, u8 ch_count, u8 usecase); + +/** + * btfm_swr_register_codec: Register codec driver with ALSA + * @btfmswr: swr slave device data pointer. + * Returns: + * -ENOMEM + * 0 + */ +int btfm_swr_register_codec(struct btfmswr *btfmswr); + +/** + * btfm_swr_unregister_codec: Unregister codec driver with ALSA + * @dev: device node + * Returns: + * VOID + */ +void btfm_swr_unregister_codec(struct device *dev); +#endif /* BTFM_SWR_H */ diff --git a/soundwire/btfm_swr_codec.c b/soundwire/btfm_swr_codec.c new file mode 100644 index 0000000000..e0fcd363a1 --- /dev/null +++ b/soundwire/btfm_swr_codec.c @@ -0,0 +1,341 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2023 Qualcomm Innovation Center, Inc. All rights reserved. + */ + +#include +#include +#include +#include +#include +#include +#include "btfm_swr.h" + +static int bt_soc_enable_status; +int btfm_feedback_ch_setting; + +static int btfm_swr_codec_write(struct snd_soc_component *codec, + unsigned int reg, unsigned int value) +{ + BTFMSWR_DBG(""); + return 0; +} + +static unsigned int btfm_swr_codec_read(struct snd_soc_component *codec, + unsigned int reg) +{ + BTFMSWR_DBG(""); + return 0; +} + +static int btfm_soc_status_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + BTFMSWR_DBG(""); + ucontrol->value.integer.value[0] = bt_soc_enable_status; + return 1; +} + +static int btfm_soc_status_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + BTFMSWR_DBG(""); + return 1; +} + +static int btfm_get_feedback_ch_setting(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + BTFMSWR_DBG(""); + ucontrol->value.integer.value[0] = btfm_feedback_ch_setting; + return 1; +} + +static int btfm_put_feedback_ch_setting(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + BTFMSWR_DBG(""); + btfm_feedback_ch_setting = ucontrol->value.integer.value[0]; + return 1; +} + +static const struct snd_kcontrol_new status_controls[] = { + SOC_SINGLE_EXT("BT SOC status", 0, 0, 1, 0, + btfm_soc_status_get, + btfm_soc_status_put), + SOC_SINGLE_EXT("BT set feedback channel", 0, 0, 1, 0, + btfm_get_feedback_ch_setting, + btfm_put_feedback_ch_setting) +}; + + +static int btfm_swr_codec_probe(struct snd_soc_component *codec) +{ + BTFMSWR_DBG(""); + snd_soc_add_component_controls(codec, status_controls, + ARRAY_SIZE(status_controls)); + return 0; +} + +static void btfm_swr_codec_remove(struct snd_soc_component *codec) +{ + BTFMSWR_DBG(""); +} + +static int btfm_swr_dai_startup(struct snd_pcm_substream *substream, + struct snd_soc_dai *dai) +{ + int ret = -1; + + BTFMSWR_INFO("substream = %s stream = %d dai->name = %s", + substream->name, substream->stream, dai->name); + ret = btfm_swr_hw_init(); + return ret; +} + +static void btfm_swr_dai_shutdown(struct snd_pcm_substream *substream, + struct snd_soc_dai *dai) +{ + int ret = 0; + u8 port_type; + + BTFMSWR_INFO("dai->name: %s, dai->id: %d, dai->rate: %d", dai->name, + dai->id, dai->rate); + + switch (dai->id) { + case FMAUDIO_TX: + port_type = FM_AUDIO_TX1; + break; + case BTAUDIO_TX: + port_type = BT_AUDIO_TX1; + break; + case BTAUDIO_RX: + port_type = BT_AUDIO_RX1; + break; + case BTAUDIO_A2DP_SINK_TX: + port_type = BT_AUDIO_TX2; + break; + case BTFM_NUM_CODEC_DAIS: + default: + BTFMSWR_ERR("dai->id is invalid:%d", dai->id); + return; + } + + ret = btfm_swr_disable_port(pbtfmswr->p_dai_port->port_info[dai->id].port, + pbtfmswr->num_channels, port_type); + +} + +static int btfm_swr_dai_hw_params(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params, + struct snd_soc_dai *dai) +{ + pbtfmswr->bps = params_width(params); + pbtfmswr->direction = substream->stream; + pbtfmswr->num_channels = params_channels(params); + + BTFMSWR_INFO("dai->name = %s dai id %x rate %d bps %d num_ch %d", + dai->name, dai->id, params_rate(params), params_width(params), + params_channels(params)); + return 0; +} + +static int btfm_swr_dai_prepare(struct snd_pcm_substream *substream, + struct snd_soc_dai *dai) +{ + int ret = -EINVAL; + u8 port_type; + + bt_soc_enable_status = 0; + BTFMSWR_INFO("dai->name: %s, dai->id: %d, dai->rate: %d direction: %d", dai->name, + dai->id, dai->rate, pbtfmswr->direction); + + /* save sample rate */ + pbtfmswr->sample_rate = dai->rate; + + switch (dai->id) { + case FMAUDIO_TX: + port_type = FM_AUDIO_TX1; + break; + case BTAUDIO_TX: + port_type = BT_AUDIO_TX1; + break; + case BTAUDIO_RX: + port_type = BT_AUDIO_RX1; + break; + case BTAUDIO_A2DP_SINK_TX: + port_type = BT_AUDIO_TX2; + break; + case BTFM_NUM_CODEC_DAIS: + default: + BTFMSWR_ERR("dai->id is invalid:%d", dai->id); + return -EINVAL; + } + + ret = btfm_swr_enable_port(pbtfmswr->p_dai_port->port_info[dai->id].port, + pbtfmswr->num_channels, dai->rate, port_type); + + /* save the enable channel status */ + if (ret == 0) + bt_soc_enable_status = 1; + + if (ret == -EISCONN) { + BTFMSWR_ERR("channel opened without closing, returning success"); + ret = 0; + } + + return ret; +} + +/* This function will be called once during boot up */ +static int btfm_swr_dai_set_channel_map(struct snd_soc_dai *dai, + unsigned int tx_num, unsigned int *tx_slot, + unsigned int rx_num, unsigned int *rx_slot) +{ + BTFMSWR_DBG(""); + return 0; +} + +static int btfm_swr_dai_get_channel_map(struct snd_soc_dai *dai, + unsigned int *tx_num, unsigned int *tx_slot, + unsigned int *rx_num, unsigned int *rx_slot) +{ + *rx_slot = 0; + *tx_slot = 0; + *rx_num = 0; + *tx_num = 0; + + switch (dai->id) { + case FMAUDIO_TX: + case BTAUDIO_TX: + case BTAUDIO_A2DP_SINK_TX: + *tx_num = pbtfmswr->num_channels; + *tx_slot = pbtfmswr->num_channels == 2 ? TWO_CHANNEL_MASK : + ONE_CHANNEL_MASK; + break; + case BTAUDIO_RX: + *rx_num = pbtfmswr->num_channels; + *rx_slot = pbtfmswr->num_channels == 2 ? TWO_CHANNEL_MASK : + ONE_CHANNEL_MASK; + break; + + default: + BTFMSWR_ERR("Unsupported DAI %d", dai->id); + return -EINVAL; + } + + return 0; +} +static struct snd_soc_dai_ops btfmswr_dai_ops = { + .startup = btfm_swr_dai_startup, + .shutdown = btfm_swr_dai_shutdown, + .hw_params = btfm_swr_dai_hw_params, + .prepare = btfm_swr_dai_prepare, + .set_channel_map = btfm_swr_dai_set_channel_map, + .get_channel_map = btfm_swr_dai_get_channel_map, +}; + +static struct snd_soc_dai_driver btfmswr_dai[] = { + { /* FM Audio data multiple channel : FM -> lpass */ + .name = "btfm_fm_swr_tx", + .id = FMAUDIO_TX, + .capture = { + .stream_name = "FM TX Capture", + .rates = SNDRV_PCM_RATE_48000, /* 48 KHz */ + .formats = SNDRV_PCM_FMTBIT_S16_LE, /* 16 bits */ + .rate_max = 48000, + .rate_min = 48000, + .channels_min = 1, + .channels_max = 2, + }, + .ops = &btfmswr_dai_ops, + }, + { /* Bluetooth SCO voice uplink: bt -> lpass */ + .name = "btfm_bt_sco_swr_tx", + .id = BTAUDIO_TX, + .capture = { + .stream_name = "SCO TX Capture", + /* 8/16/44.1/48/88.2/96/192 Khz */ + .rates = SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000 + | SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000 + | SNDRV_PCM_RATE_88200 | SNDRV_PCM_RATE_96000 + | SNDRV_PCM_RATE_192000, + .formats = SNDRV_PCM_FMTBIT_S16_LE, /* 16 bits */ + .rate_max = 192000, + .rate_min = 8000, + .channels_min = 1, + .channels_max = 1, + }, + .ops = &btfmswr_dai_ops, + }, + { /* Bluetooth SCO voice downlink: lpass -> bt or A2DP Playback */ + .name = "btfm_bt_sco_a2dp_swr_rx", + .id = BTAUDIO_RX, + .playback = { + .stream_name = "SCO A2DP RX Playback", + /* 8/16/44.1/48/88.2/96/192 Khz */ + .rates = SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000 + | SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000 + | SNDRV_PCM_RATE_88200 | SNDRV_PCM_RATE_96000 + | SNDRV_PCM_RATE_192000, + .formats = SNDRV_PCM_FMTBIT_S16_LE, /* 16 bits */ + .rate_max = 192000, + .rate_min = 8000, + .channels_min = 1, + .channels_max = 1, + }, + .ops = &btfmswr_dai_ops, + }, + { /* Bluetooth A2DP sink: bt -> lpass */ + .name = "btfm_a2dp_sink_swr_tx", + .id = BTAUDIO_A2DP_SINK_TX, + .capture = { + .stream_name = "A2DP sink TX Capture", + /* 8/16/44.1/48/88.2/96/192 Khz */ + .rates = SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000 + | SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000 + | SNDRV_PCM_RATE_88200 | SNDRV_PCM_RATE_96000 + | SNDRV_PCM_RATE_192000, + .formats = SNDRV_PCM_FMTBIT_S16_LE, /* 16 bits */ + .rate_max = 192000, + .rate_min = 8000, + .channels_min = 1, + .channels_max = 1, + }, + .ops = &btfmswr_dai_ops, + }, +}; + +static const struct snd_soc_component_driver btfmswr_codec = { + .probe = btfm_swr_codec_probe, + .remove = btfm_swr_codec_remove, + .read = btfm_swr_codec_read, + .write = btfm_swr_codec_write, +}; + +int btfm_swr_register_codec(struct btfmswr *btfm_swr) +{ + int ret = 0; + struct device *dev = btfm_swr->dev; + + BTFMSWR_DBG(""); + dev_err(dev, "\n"); + + /* Register Codec driver */ + ret = snd_soc_register_component(dev, &btfmswr_codec, + btfmswr_dai, ARRAY_SIZE(btfmswr_dai)); + if (ret) + BTFMSWR_ERR("failed to register codec (%d)", ret); + return ret; +} + +void btfm_swr_unregister_codec(struct device *dev) +{ + BTFMSWR_DBG(""); + /* Unregister Codec driver */ + snd_soc_unregister_component(dev); +} + + +MODULE_DESCRIPTION("BTFM SoundWire Codec driver"); +MODULE_LICENSE("GPL v2"); diff --git a/soundwire/btfm_swr_slave.c b/soundwire/btfm_swr_slave.c new file mode 100644 index 0000000000..f5e99bf092 --- /dev/null +++ b/soundwire/btfm_swr_slave.c @@ -0,0 +1,44 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2023 Qualcomm Innovation Center, Inc. All rights reserved. + */ + + +#include "btfm_swr.h" +#include "btfm_swr_slave.h" + +struct soc_port_mapping slave_port[] = { + // Evros + { + .ea = EVROS_EA, + .port_info[0].dai_id = FMAUDIO_TX, + .port_info[0].port = 5, + + .port_info[1].dai_id = BTAUDIO_TX, + .port_info[1].port = 3, + + .port_info[2].dai_id = BTAUDIO_RX, + .port_info[2].port = 1, + + .port_info[3].dai_id = BTAUDIO_A2DP_SINK_TX, + .port_info[3].port = 4, + }, + + // Ganges + { + .ea = GANGES_EA, + // FM is not supported on Ganges. populate with invalid port number + .port_info[0].dai_id = FMAUDIO_TX, + .port_info[0].port = BTFM_INVALID_PORT, + + .port_info[1].dai_id = BTAUDIO_TX, + .port_info[1].port = 4, + + .port_info[2].dai_id = BTAUDIO_RX, + .port_info[2].port = 1, + + .port_info[3].dai_id = BTAUDIO_A2DP_SINK_TX, + .port_info[3].port = 5, + }, +}; + diff --git a/soundwire/btfm_swr_slave.h b/soundwire/btfm_swr_slave.h new file mode 100644 index 0000000000..ab07cdddd4 --- /dev/null +++ b/soundwire/btfm_swr_slave.h @@ -0,0 +1,45 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2023 Qualcomm Innovation Center, Inc. All rights reserved. + */ + + +#ifndef BTFM_SWR_SLAVE_H +#define BTFM_SWR_SLAVE_H + +#include "btfm_swr.h" + +/* Registers Address */ + +/* Register Bit Setting */ +#define SLAVE_ENABLE_OVERRUN_AUTO_RECOVERY (0x1 << 1) +#define SLAVE_ENABLE_UNDERRUN_AUTO_RECOVERY (0x1 << 0) +#define SLAVE_SB_PGD_PORT_ENABLE (0x1 << 0) +#define SLAVE_SB_PGD_PORT_DISABLE (0x0 << 0) + + +#define BTFM_INVALID_PORT 0xFF + +extern struct soc_port_mapping slave_port[]; + +enum { + QCA_GANGES_SOC_ID_0100 = 0x40210100, + QCA_GANGES_SOC_ID_0200 = 0x40210200, +}; + + +enum { + QCA_EVROS_SOC_ID_0100 = 0x40200100, + QCA_EVROS_SOC_ID_0200 = 0x40200200, +}; + + +enum { + EVROS_EA = 0x0108170220, + GANGES_EA = 0x0208170220, +}; + +/* Specific defines for slave slimbus device */ +#define SLAVE_SWR_REG_OFFSET 0x0800 + +#endif From 7bd1a061bbe78bf4177c10efcfdbe68b1a267d0f Mon Sep 17 00:00:00 2001 From: Balakrishna Godavarthi Date: Wed, 20 Sep 2023 20:31:25 +0530 Subject: [PATCH 058/154] btfmcodec: Update usecase start This change will notify client about usecase start if transport selected is bt advance audio. Change-Id: I5c85d32e0701cec4f36e0dda4110cc20338bf6a4 Signed-off-by: Balakrishna Godavarthi --- btfmcodec/btfm_codec_interface.c | 14 ++++++++++++++ btfmcodec/include/btfm_codec_pkt.h | 9 +++++++++ 2 files changed, 23 insertions(+) diff --git a/btfmcodec/btfm_codec_interface.c b/btfmcodec/btfm_codec_interface.c index 38c2660861..eea4cf04bd 100644 --- a/btfmcodec/btfm_codec_interface.c +++ b/btfmcodec/btfm_codec_interface.c @@ -527,6 +527,19 @@ int btfmcodec_hwep_prepare(struct btfmcodec_data *btfmcodec, uint32_t sampling_r return ret; } +static int btfmcodec_notify_usecase_start(struct btfmcodec_data *btfmcodec, + uint8_t transport) +{ + struct btfmcodec_char_device *btfmcodec_dev = btfmcodec->btfmcodec_dev; + struct btm_usecase_start_ind ind; + + ind.opcode = BTM_BTFMCODEC_USECASE_START_IND; + ind.len = BTM_USECASE_START_IND_LEN; + ind.transport = transport; + return btfmcodec_dev_enqueue_pkt(btfmcodec_dev, &ind, (ind.len + + BTM_HEADER_LEN)); +} + static int btfmcodec_dai_prepare(struct snd_pcm_substream *substream, struct snd_soc_dai *dai) { @@ -550,6 +563,7 @@ static int btfmcodec_dai_prepare(struct snd_pcm_substream *substream, btfmcodec_get_current_transport(state) != BT_Connected) { BTFMCODEC_WARN("cached required info as state is:%s", coverttostring(btfmcodec_get_current_transport(state))); + btfmcodec_notify_usecase_start(btfmcodec, BTADV); } else { ret = btfmcodec_hwep_prepare(btfmcodec, sampling_rate, direction, id); /* if (ret >= 0) { diff --git a/btfmcodec/include/btfm_codec_pkt.h b/btfmcodec/include/btfm_codec_pkt.h index cc75c2e357..e6b1f8c67b 100644 --- a/btfmcodec/include/btfm_codec_pkt.h +++ b/btfmcodec/include/btfm_codec_pkt.h @@ -54,6 +54,9 @@ struct btm_ctrl_pkt { #define BTM_LOG_LVL_IND_LEN 1 #define BTM_ADSP_STATE_IND_LEN 4 +#define BTM_BTFMCODEC_USECASE_START_IND 0x58000008 +#define BTM_USECASE_START_IND_LEN 1 + enum rx_status { /* Waiting for response */ BTM_WAITING_RSP, @@ -91,6 +94,12 @@ struct btm_master_config_req { }__attribute__((packed)); +struct btm_usecase_start_ind { + btm_opcode opcode; + uint32_t len; + uint8_t transport; +} __packed; + struct btm_master_shutdown_req { btm_opcode opcode; uint32_t len; From 897ecff7426b1837a9d3ea7e87fff5d870c0ce01 Mon Sep 17 00:00:00 2001 From: Balakrishna Godavarthi Date: Wed, 5 Jul 2023 11:55:04 +0530 Subject: [PATCH 059/154] soundwire: Update soundwire driver to support btfmcodec This change add supports in both btfmcodec and soundwire to support btfmcodec driver has interface. Change-Id: I2e77afaea44778147b362175aae33961dcc5042e Signed-off-by: Balakrishna Godavarthi --- bt_modules.bzl | 19 +- btfmcodec/btfm_codec.c | 72 +++- btfmcodec/btfm_codec_hw_interface.c | 11 +- btfmcodec/btfm_codec_interface.c | 128 +++++- btfmcodec/include/btfm_codec.h | 4 + btfmcodec/include/btfm_codec_hw_interface.h | 16 +- btfmcodec/include/btfm_codec_pkt.h | 19 + slimbus/btfm_slim_hw_interface.c | 9 +- soundwire/Makefile | 2 +- soundwire/btfm_swr.c | 6 +- soundwire/btfm_swr.h | 17 - soundwire/btfm_swr_codec.c | 341 --------------- soundwire/btfm_swr_hw_interface.c | 440 ++++++++++++++++++++ soundwire/btfm_swr_hw_interface.h | 35 ++ 14 files changed, 717 insertions(+), 402 deletions(-) delete mode 100644 soundwire/btfm_swr_codec.c create mode 100644 soundwire/btfm_swr_hw_interface.c create mode 100644 soundwire/btfm_swr_hw_interface.h diff --git a/bt_modules.bzl b/bt_modules.bzl index 8918e024ee..6759503284 100644 --- a/bt_modules.bzl +++ b/bt_modules.bzl @@ -1,6 +1,7 @@ PWR_PATH = "pwr" SLIMBUS_PATH = "slimbus" FMRTC_PATH = "rtc6226" +BTFMCODEC_PATH = "btfmcodec" # This dictionary holds all the BT modules included in the bt-kernel bt_modules = {} @@ -75,11 +76,10 @@ register_bt_modules( deps = [":%b_btpower"], ) -# Not enabled/compiling until btfmcodec is enabled register_bt_modules( name = "btfm_slim_codec", path = SLIMBUS_PATH, - # config_opt = "CONFIG_SLIM_BTFM_CODEC", + config_opt = "CONFIG_SLIM_BTFM_CODEC", srcs = [ "btfm_slim.c", "btfm_slim.h", @@ -88,7 +88,20 @@ register_bt_modules( "btfm_slim_hw_interface.c", "btfm_slim_hw_interface.h", ], - deps = [":%b_btpower", ":btfmcodec_headers"], + deps = [":%b_btpower", ":%b_btfmcodec", ":btfmcodec_headers"], +) + +register_bt_modules( + name = "btfmcodec", + path = BTFMCODEC_PATH, + config_opt = "CONFIG_BTFM_CODEC", + srcs = [ + "btfm_codec.c", + "btfm_codec_btadv_interface.c", + "btfm_codec_hw_interface.c", + "btfm_codec_interface.c", + ], + deps = [":btfmcodec_headers"], ) register_bt_modules( diff --git a/btfmcodec/btfm_codec.c b/btfmcodec/btfm_codec.c index a970e59793..7677b22f89 100644 --- a/btfmcodec/btfm_codec.c +++ b/btfmcodec/btfm_codec.c @@ -23,6 +23,7 @@ static dev_t dev_major; struct btfmcodec_data *btfmcodec; struct device_driver driver = {.name = "btfmcodec-driver", .owner = THIS_MODULE}; struct btfmcodec_char_device *btfmcodec_dev; +bool is_cp_supported = true; #define cdev_to_btfmchardev(_cdev) container_of(_cdev, struct btfmcodec_char_device, cdev) #define MIN_PKT_LEN 0x9 @@ -183,6 +184,22 @@ static void btfmcodec_dev_rxwork(struct work_struct *work) status); wake_up_interruptible(&btfmcodec_dev->rsp_wait_q[idx]); break; + case BTM_BTFMCODEC_CODEC_CONFIG_DMA_RSP: + idx = BTM_PKT_TYPE_DMA_CONFIG_RSP; + if (len == BTM_CODEC_CONFIG_DMA_RSP_LEN) { + status = skb->data[1]; + if (status == MSG_SUCCESS) + btfmcodec_dev->status[idx] = BTM_RSP_RECV; + else + btfmcodec_dev->status[idx] = BTM_FAIL_RESP_RECV; + } else { + BTFMCODEC_ERR("wrong packet format with len:%d", len); + btfmcodec_dev->status[idx] = BTM_FAIL_RESP_RECV; + } + BTFMCODEC_INFO("Rx BTM_BTFMCODEC_CODEC_CONFIG_DMA_RSP status:%d", + status); + wake_up_interruptible(&btfmcodec_dev->rsp_wait_q[idx]); + break; case BTM_BTFMCODEC_CTRL_MASTER_SHUTDOWN_RSP: idx = BTM_PKT_TYPE_MASTER_SHUTDOWN_RSP; if (len == BTM_MASTER_CONFIG_RSP_LEN) { @@ -442,6 +459,56 @@ static ssize_t btfmcodec_dev_read(struct file *file, return use; } + +bool isCpSupported(void) +{ + return is_cp_supported; +} + +static long btfmcodec_ioctl(struct file *file, unsigned int cmd, unsigned long arg) +{ + struct btfmcodec_data *btfmcodec = file->private_data; + struct hwep_data *hwep_info; + + BTFMCODEC_INFO("%s: command %04x", __func__, cmd); + + mutex_lock(&btfmcodec->hwep_drv_lock); + hwep_info = btfmcodec->hwep_info; + if (!hwep_info) { + BTFMCODEC_WARN("%s: HWEP is not registered with btfmcodec", __func__); + BTFMCODEC_WARN("%s: caching required info", __func__); + is_cp_supported = ((int)arg == 1) ? true : false; + mutex_unlock(&btfmcodec->hwep_drv_lock); + return 0; + } + + mutex_unlock(&btfmcodec->hwep_drv_lock); + switch (cmd) { + case BTM_CP_UPDATE: { + if ((int)arg == 1) { + if (!strcmp(hwep_info->driver_name, "btfmslim")) + set_bit(BTADV_AUDIO_MASTER_CONFIG, &hwep_info->flags); + else if (!strcmp(hwep_info->driver_name, "btfmswr_slave")) + set_bit(BTADV_CONFIGURE_DMA, &hwep_info->flags); + BTFMCODEC_INFO("%s: This target support CP hwep %s", + __func__, hwep_info->driver_name); + } else { + clear_bit(BTADV_AUDIO_MASTER_CONFIG, &hwep_info->flags); + clear_bit(BTADV_CONFIGURE_DMA, &hwep_info->flags); + BTFMCODEC_INFO("%s: This target support doesn't CP", __func__); + } + + BTFMCODEC_INFO("%s: mastr %d dma codec %d", __func__, + (int)test_bit(BTADV_AUDIO_MASTER_CONFIG, &hwep_info->flags), + (int)test_bit(BTADV_CONFIGURE_DMA, &hwep_info->flags)); + break; + } default: { + BTFMCODEC_ERR("%s unhandled cmd %04x", __func__, cmd); + } + } + + return 0; +} static const struct file_operations btfmcodec_fops = { .owner = THIS_MODULE, .open = btfmcodec_dev_open, @@ -450,8 +517,8 @@ static const struct file_operations btfmcodec_fops = { .poll = btfmcodec_dev_poll, .read = btfmcodec_dev_read, /* For Now add no hookups for below callbacks */ - .unlocked_ioctl = NULL, - .compat_ioctl = NULL, + .unlocked_ioctl = btfmcodec_ioctl, + .compat_ioctl = btfmcodec_ioctl, }; static ssize_t btfmcodec_attributes_store(struct device *dev, @@ -503,6 +570,7 @@ static int __init btfmcodec_init(void) return -ENOMEM; } + mutex_init(&btfmcodec->hwep_drv_lock); states = &btfmcodec->states; states->current_state = IDLE; states->next_state = IDLE; diff --git a/btfmcodec/btfm_codec_hw_interface.c b/btfmcodec/btfm_codec_hw_interface.c index 091fe190cd..97d4d7d4ca 100644 --- a/btfmcodec/btfm_codec_hw_interface.c +++ b/btfmcodec/btfm_codec_hw_interface.c @@ -6,17 +6,14 @@ #include "btfm_codec_hw_interface.h" #include "btfm_codec_interface.h" -struct mutex hwep_drv_lock; - int btfmcodec_register_hw_ep (struct hwep_data *ep_info) { struct btfmcodec_data *btfmcodec; struct hwep_data *hwep_info; int ret = 0; - // ToDo Check wether we need mutex_init api - mutex_lock(&hwep_drv_lock); btfmcodec = btfm_get_btfmcodec(); + mutex_lock(&btfmcodec->hwep_drv_lock); if (!btfmcodec) { BTFMCODEC_ERR("btfm codec driver it not initialized"); ret = -EPERM; @@ -54,7 +51,7 @@ int btfmcodec_register_hw_ep (struct hwep_data *ep_info) &hwep_info->flags)); ret = btfm_register_codec(hwep_info); end: - mutex_unlock(&hwep_drv_lock); + mutex_unlock(&btfmcodec->hwep_drv_lock); return ret; } @@ -64,8 +61,8 @@ int btfmcodec_unregister_hw_ep (char *driver_name) struct hwep_data *hwep_info; int ret; - mutex_lock(&hwep_drv_lock); btfmcodec = btfm_get_btfmcodec(); + mutex_lock(&btfmcodec->hwep_drv_lock); if (!btfmcodec) { BTFMCODEC_ERR("btfm codec driver it not initialized"); ret = -EPERM; @@ -91,7 +88,7 @@ int btfmcodec_unregister_hw_ep (char *driver_name) goto end; } end: - mutex_unlock(&hwep_drv_lock); + mutex_unlock(&btfmcodec->hwep_drv_lock); return ret; } diff --git a/btfmcodec/btfm_codec_interface.c b/btfmcodec/btfm_codec_interface.c index eea4cf04bd..d8139d482b 100644 --- a/btfmcodec/btfm_codec_interface.c +++ b/btfmcodec/btfm_codec_interface.c @@ -439,7 +439,7 @@ static int btfmcodec_configure_master(struct btfmcodec_data *btfmcodec, uint8_t struct btfmcodec_char_device *btfmcodec_dev = btfmcodec->btfmcodec_dev; struct hwep_data *hwep_info = btfmcodec->hwep_info; struct master_hwep_configurations hwep_configs; - struct btm_master_config_req config_reg; + struct btm_master_config_req config_req; struct hwep_dai_driver *dai_drv = (struct hwep_dai_driver *) btfmcodec_get_dai_drvdata(hwep_info); wait_queue_head_t *rsp_wait_q = @@ -456,28 +456,28 @@ static int btfmcodec_configure_master(struct btfmcodec_data *btfmcodec, uint8_t } BTFMCODEC_INFO("framing packet for %d", id); - config_reg.opcode = BTM_BTFMCODEC_MASTER_CONFIG_REQ; - config_reg.len = BTM_MASTER_CONFIG_REQ_LEN; - config_reg.stream_id = hwep_configs.stream_id; - config_reg.device_id = hwep_configs.device_id; - config_reg.sample_rate = hwep_configs.sample_rate; - config_reg.bit_width = hwep_configs.bit_width; - config_reg.num_channels = hwep_configs.num_channels; - config_reg.channel_num = hwep_configs.chan_num; - config_reg.codec_id = hwep_configs.codectype; + config_req.opcode = BTM_BTFMCODEC_MASTER_CONFIG_REQ; + config_req.len = BTM_MASTER_CONFIG_REQ_LEN; + config_req.stream_id = hwep_configs.stream_id; + config_req.device_id = hwep_configs.device_id; + config_req.sample_rate = hwep_configs.sample_rate; + config_req.bit_width = hwep_configs.bit_width; + config_req.num_channels = hwep_configs.num_channels; + config_req.channel_num = hwep_configs.chan_num; + config_req.codec_id = hwep_configs.codectype; BTFMCODEC_DBG("================================================\n"); - BTFMCODEC_DBG("config_reg.len :%d", config_reg.len); - BTFMCODEC_DBG("config_reg.stream_id :%d", config_reg.stream_id); - BTFMCODEC_DBG("config_reg.device_id :%d", config_reg.device_id); - BTFMCODEC_DBG("config_reg.sample_rate :%d", config_reg.sample_rate); - BTFMCODEC_DBG("config_reg.bit_width :%d", config_reg.bit_width); - BTFMCODEC_DBG("config_reg.num_channels :%d", config_reg.num_channels); - BTFMCODEC_DBG("config_reg.channel_num :%d", config_reg.channel_num); - BTFMCODEC_DBG("config_reg.codec_id :%d", config_reg.codec_id); + BTFMCODEC_DBG("dma_config_req.len :%d", config_req.len); + BTFMCODEC_DBG("dma_config_req.stream_id :%d", config_req.stream_id); + BTFMCODEC_DBG("dma_config_req.device_id :%d", config_req.device_id); + BTFMCODEC_DBG("dma_config_req.sample_rate :%d", config_req.sample_rate); + BTFMCODEC_DBG("dma_config_req.bit_width :%d", config_req.bit_width); + BTFMCODEC_DBG("dma_config_req.num_channels :%d", config_req.num_channels); + BTFMCODEC_DBG("dma_config_req.channel_num :%d", config_req.channel_num); + BTFMCODEC_DBG("dma_config_req.codec_id :%d", config_req.codec_id); BTFMCODEC_DBG("================================================\n"); /* See if we need to protect below with lock */ *status = BTM_WAITING_RSP; - btfmcodec_dev_enqueue_pkt(btfmcodec_dev, &config_reg, (config_reg.len + + btfmcodec_dev_enqueue_pkt(btfmcodec_dev, &config_req, (config_req.len + BTM_HEADER_LEN)); ret = wait_event_interruptible_timeout(*rsp_wait_q, (*status) != BTM_WAITING_RSP, @@ -496,6 +496,73 @@ static int btfmcodec_configure_master(struct btfmcodec_data *btfmcodec, uint8_t return ret; } +static int btfmcodec_configure_dma(struct btfmcodec_data *btfmcodec, uint8_t id) +{ + struct btfmcodec_char_device *btfmcodec_dev = btfmcodec->btfmcodec_dev; + struct hwep_data *hwep_info = btfmcodec->hwep_info; + struct hwep_dma_configurations dma_config; + struct btm_dma_config_req dma_config_req; + struct hwep_dai_driver *dai_drv = (struct hwep_dai_driver *) + btfmcodec_get_dai_drvdata(hwep_info); + wait_queue_head_t *rsp_wait_q = + &btfmcodec_dev->rsp_wait_q[BTM_PKT_TYPE_DMA_CONFIG_RSP]; + uint8_t *status = &btfmcodec_dev->status[BTM_PKT_TYPE_DMA_CONFIG_RSP]; + int ret = 0; + + if (dai_drv && dai_drv->dai_ops && dai_drv->dai_ops->hwep_get_configs) { + dai_drv->dai_ops->hwep_get_configs((void *)btfmcodec->hwep_info, + &dma_config, id); + } else { + BTFMCODEC_ERR("No hwep_get_configs is set by hw ep driver"); + return -1; + } + + BTFMCODEC_INFO("framing packet for %d", id); + dma_config_req.opcode = BTM_BTFMCODEC_CODEC_CONFIG_DMA_REQ; + dma_config_req.len = BTM_CODEC_CONFIG_DMA_REQ_LEN; + dma_config_req.stream_id = dma_config.stream_id; + dma_config_req.sample_rate = dma_config.sample_rate; + dma_config_req.bit_width = dma_config.bit_width; + dma_config_req.num_channels = dma_config.num_channels; + dma_config_req.codec_id = dma_config.codectype; + dma_config_req.lpaif = dma_config.lpaif; + dma_config_req.inf_index = dma_config.inf_index; + dma_config_req.active_channel_mask = dma_config.active_channel_mask; + + BTFMCODEC_DBG("================================================\n"); + BTFMCODEC_DBG("dma_config_req.len :%d", dma_config_req.len); + BTFMCODEC_DBG("dma_config_req.stream_id :%d", dma_config_req.stream_id); + BTFMCODEC_DBG("dma_config_req.sample_rate :%d", dma_config_req.sample_rate); + BTFMCODEC_DBG("dma_config_req.bit_width :%d", dma_config_req.bit_width); + BTFMCODEC_DBG("dma_config_req.num_channels :%d", dma_config_req.num_channels); + BTFMCODEC_DBG("dma_config_req.codec_id :%d", dma_config_req.codec_id); + BTFMCODEC_DBG("dma_config_req.lpaif :%d", dma_config_req.lpaif); + BTFMCODEC_DBG("dma_config_req.inf_index :%d", dma_config_req.inf_index); + BTFMCODEC_DBG("dma_config_req.active_channel_mask :%d", dma_config_req.active_channel_mask); + BTFMCODEC_DBG("================================================\n"); + + *status = BTM_WAITING_RSP; + btfmcodec_dev_enqueue_pkt(btfmcodec_dev, &dma_config_req, (dma_config_req.len + + BTM_HEADER_LEN)); + + ret = wait_event_interruptible_timeout(*rsp_wait_q, + (*status) != BTM_WAITING_RSP, + msecs_to_jiffies(BTM_MASTER_DMA_CONFIG_RSP_TIMEOUT)); + + if (ret == 0) { + BTFMCODEC_ERR("failed to recevie response from BTADV audio Manager"); + ret = -ETIMEDOUT; + } else { + if (*status == BTM_RSP_RECV) + return 0; + else if (*status == BTM_FAIL_RESP_RECV || + *status == BTM_RSP_NOT_RECV_CLIENT_KILLED) + return -1; + } + + return ret; +} + int btfmcodec_hwep_prepare(struct btfmcodec_data *btfmcodec, uint32_t sampling_rate, uint32_t direction, int id) { @@ -508,14 +575,20 @@ int btfmcodec_hwep_prepare(struct btfmcodec_data *btfmcodec, uint32_t sampling_r if (dai_drv && dai_drv->dai_ops && dai_drv->dai_ops->hwep_prepare) { ret = dai_drv->dai_ops->hwep_prepare((void *)hwep_info, sampling_rate, direction, id); + BTFMCODEC_ERR("%s: hwep info %d", __func__, hwep_info->flags); if (ret == 0 && test_bit(BTADV_AUDIO_MASTER_CONFIG, &hwep_info->flags)) { ret = btfmcodec_configure_master(btfmcodec, (uint8_t)id); if (ret < 0) { BTFMCODEC_ERR("failed to configure master error %d", ret); - /* close slave port and reset the state*/ btfmcodec_set_current_state(state, IDLE); - /* we don't need to do shutdown, ASOC is doing it */ -// btfmcodec_hwep_shutdown(btfmcodec, id); + } else { + btfmcodec_set_current_state(state, BT_Connected); + } + } else if (ret == 0 && test_bit(BTADV_CONFIGURE_DMA, &hwep_info->flags)) { + ret = btfmcodec_configure_dma(btfmcodec, (uint8_t)id); + if (ret < 0) { + BTFMCODEC_ERR("failed to configure Codec DMA %d", ret); + btfmcodec_set_current_state(state, IDLE); } else { btfmcodec_set_current_state(state, BT_Connected); } @@ -785,6 +858,17 @@ int btfm_register_codec(struct hwep_data *hwep_info) BTFMCODEC_INFO("btfmcodec_wq_prepare_bearer:%p", btfmcodec_wq_prepare_bearer); BTFMCODEC_INFO("btfmcodec_wq_hwep_shutdown:%p", btfmcodec_wq_hwep_shutdown); + if (isCpSupported()) { + if (!strcmp(hwep_info->driver_name, "btfmslim")) + set_bit(BTADV_AUDIO_MASTER_CONFIG, &hwep_info->flags); + else if (!strcmp(hwep_info->driver_name, "btfmswr_slave")) + set_bit(BTADV_CONFIGURE_DMA, &hwep_info->flags); + + BTFMCODEC_INFO("%s: master %d dma codec %d", __func__, + (int)test_bit(BTADV_AUDIO_MASTER_CONFIG, &hwep_info->flags), + (int)test_bit(BTADV_CONFIGURE_DMA, &hwep_info->flags)); + } + return ret; } diff --git a/btfmcodec/include/btfm_codec.h b/btfmcodec/include/btfm_codec.h index 88c7117997..563e557817 100644 --- a/btfmcodec/include/btfm_codec.h +++ b/btfmcodec/include/btfm_codec.h @@ -33,6 +33,7 @@ static uint8_t log_lvl = BTM_BTFMCODEC_DEFAULT_LOG_LVL; } #define DEVICE_NAME_MAX_LEN 64 +#define BTM_CP_UPDATE 0xbfaf typedef enum btfmcodec_states { /*Default state of kernel proxy driver */ @@ -54,6 +55,7 @@ enum btfm_pkt_type { BTM_PKT_TYPE_BEARER_SWITCH_IND, BTM_PKT_TYPE_HWEP_SHUTDOWN, BTM_PKT_TYPE_HWEP_CONFIG, + BTM_PKT_TYPE_DMA_CONFIG_RSP, BTM_PKT_TYPE_MAX, }; @@ -98,7 +100,9 @@ struct btfmcodec_data { struct hwep_data *hwep_info; struct list_head config_head; struct adsp_notifier notifier; + struct mutex hwep_drv_lock; }; struct btfmcodec_data *btfm_get_btfmcodec(void); +bool isCpSupported(void); #endif /*__LINUX_BTFM_CODEC_H */ diff --git a/btfmcodec/include/btfm_codec_hw_interface.h b/btfmcodec/include/btfm_codec_hw_interface.h index bf8e2e6790..3474a6495b 100644 --- a/btfmcodec/include/btfm_codec_hw_interface.h +++ b/btfmcodec/include/btfm_codec_hw_interface.h @@ -18,6 +18,7 @@ * responsible to configure master. */ #define BTADV_AUDIO_MASTER_CONFIG 0 +#define BTADV_CONFIGURE_DMA 1 #define DEVICE_NAME_MAX_LEN 64 struct hwep_configurations { @@ -41,6 +42,18 @@ struct master_hwep_configurations { uint8_t codectype; uint16_t direction; }; + +struct hwep_dma_configurations { + uint8_t stream_id; + uint32_t sample_rate; + uint8_t bit_width; + uint8_t num_channels; + uint8_t codectype; + uint8_t lpaif; // Low power audio interface + uint8_t inf_index; // interface index + uint8_t active_channel_mask; +}; + struct hwep_comp_drv { int (*hwep_probe) (struct snd_soc_component *); void (*hwep_remove) (struct snd_soc_component *); @@ -58,8 +71,7 @@ struct hwep_dai_ops { unsigned int, unsigned int *); int (*hwep_get_channel_map)(void *, unsigned int *, unsigned int *, unsigned int *, unsigned int *, int); - int (*hwep_get_configs)(void *, struct master_hwep_configurations *, - uint8_t); + int (*hwep_get_configs)(void *a, void *b, uint8_t c); uint8_t *hwep_codectype; }; diff --git a/btfmcodec/include/btfm_codec_pkt.h b/btfmcodec/include/btfm_codec_pkt.h index e6b1f8c67b..ccf7ef4ddb 100644 --- a/btfmcodec/include/btfm_codec_pkt.h +++ b/btfmcodec/include/btfm_codec_pkt.h @@ -38,6 +38,9 @@ struct btm_ctrl_pkt { #define BTM_BTFMCODEC_MASTER_CONFIG_RSP 0x50000003 #define BTM_BTFMCODEC_MASTER_SHUTDOWN_REQ 0x50000004 #define BTM_BTFMCODEC_CTRL_MASTER_SHUTDOWN_RSP 0x50000005 +#define BTM_BTFMCODEC_CODEC_CONFIG_DMA_REQ 0x58000006 +#define BTM_BTFMCODEC_CODEC_CONFIG_DMA_RSP 0x58000007 + #define BTM_BTFMCODEC_BEARER_SWITCH_IND 0x58000001 #define BTM_BTFMCODEC_TRANSPORT_SWITCH_FAILED_IND 0x58000002 #define BTM_BTFMCODEC_ADSP_STATE_IND 0x58000003 @@ -45,14 +48,17 @@ struct btm_ctrl_pkt { #define BTM_MASTER_CONFIG_REQ_LEN 13 #define BTM_MASTER_CONFIG_RSP_TIMEOUT 5000 +#define BTM_MASTER_DMA_CONFIG_RSP_TIMEOUT 5000 #define BTM_HEADER_LEN 8 #define BTM_PREPARE_AUDIO_BEARER_SWITCH_RSP_LEN 2 #define BTM_MASTER_CONFIG_RSP_LEN 2 +#define BTM_CODEC_CONFIG_DMA_RSP_LEN 2 #define BTM_MASTER_SHUTDOWN_REQ_LEN 1 #define BTM_PREPARE_AUDIO_BEARER_SWITCH_REQ_LEN 1 #define BTM_BEARER_SWITCH_IND_LEN 1 #define BTM_LOG_LVL_IND_LEN 1 #define BTM_ADSP_STATE_IND_LEN 4 +#define BTM_CODEC_CONFIG_DMA_REQ_LEN 11 #define BTM_BTFMCODEC_USECASE_START_IND 0x58000008 #define BTM_USECASE_START_IND_LEN 1 @@ -81,6 +87,7 @@ enum btfm_kp_status { MSG_FAILED_TO_SHUTDOWN_HWEP, MSG_ERR_WHILE_SHUTING_DOWN_HWEP, }; + struct btm_master_config_req { btm_opcode opcode; uint32_t len; @@ -93,6 +100,18 @@ struct btm_master_config_req { uint8_t codec_id; }__attribute__((packed)); +struct btm_dma_config_req { + btm_opcode opcode; + uint32_t len; + uint8_t stream_id; + uint32_t sample_rate; + uint8_t bit_width; + uint8_t num_channels; + uint8_t codec_id; + uint8_t lpaif; // Low power audio interface + uint8_t inf_index; // interface index + uint8_t active_channel_mask; +} __packed; struct btm_usecase_start_ind { btm_opcode opcode; diff --git a/slimbus/btfm_slim_hw_interface.c b/slimbus/btfm_slim_hw_interface.c index 0a2eeea973..9886307f2d 100644 --- a/slimbus/btfm_slim_hw_interface.c +++ b/slimbus/btfm_slim_hw_interface.c @@ -397,16 +397,17 @@ static int btfm_slim_dai_get_channel_map(void *dai, return 0; } -int btfm_slim_dai_get_configs (void * dai, - struct master_hwep_configurations *hwep_config, - uint8_t id) +int btfm_slim_dai_get_configs(void *dai, void *config, uint8_t id) { struct hwep_data *hwep_info = (struct hwep_data *)dai; struct btfmslim *btfmslim = dev_get_drvdata(hwep_info->dev); + struct master_hwep_configurations *hwep_config; struct btfmslim_ch *ch = NULL; int i = 0; BTFMSLIM_DBG(""); + + hwep_config = (struct master_hwep_configurations *) config; hwep_config->stream_id = id; hwep_config->device_id = btfmslim->device_id; hwep_config->sample_rate = btfmslim->sample_rate; @@ -436,6 +437,7 @@ int btfm_slim_dai_get_configs (void * dai, return 1; } + static struct hwep_dai_ops btfmslim_hw_dai_ops = { .hwep_startup = btfm_slim_dai_startup, .hwep_shutdown = btfm_slim_dai_shutdown, @@ -519,7 +521,6 @@ int btfm_slim_register_hw_ep(struct btfmslim *btfm_slim) hwep_info->num_dai = 2; hwep_info->num_mixer_ctrl = ARRAY_SIZE(status_controls); hwep_info->mixer_ctrl = status_controls; - set_bit(BTADV_AUDIO_MASTER_CONFIG, &hwep_info->flags); /* Register to hardware endpoint */ ret = btfmcodec_register_hw_ep(hwep_info); if (ret) { diff --git a/soundwire/Makefile b/soundwire/Makefile index 04eb9a25e3..db71d25bba 100644 --- a/soundwire/Makefile +++ b/soundwire/Makefile @@ -1,3 +1,3 @@ ccflags-y += -I$(BT_ROOT)/include -bt_fm_swr-objs := btfm_swr.o btfm_swr_codec.o btfm_swr_slave.o +bt_fm_swr-objs := btfm_swr.o btfm_swr_hw_interface.o btfm_swr_slave.o obj-$(CONFIG_BTFM_SWR) += bt_fm_swr.o diff --git a/soundwire/btfm_swr.c b/soundwire/btfm_swr.c index c40271d5de..3b4d049a16 100644 --- a/soundwire/btfm_swr.c +++ b/soundwire/btfm_swr.c @@ -21,6 +21,7 @@ #include #include "btpower.h" #include "btfm_swr.h" +#include "btfm_swr_hw_interface.h" #include "btfm_swr_slave.h" struct class *btfm_swr_class; @@ -205,7 +206,7 @@ static int btfm_swr_probe(struct swr_device *pdev) pbtfmswr->initialized = false; // register with ALSA - ret = btfm_swr_register_codec(pbtfmswr); + ret = btfm_swr_register_hw_ep(pbtfmswr); if (ret) { BTFMSWR_ERR("registration with ALSA failed, returning"); goto dealloc; @@ -239,8 +240,7 @@ class_err: unregister_chrdev(btfm_swr_major, "btfm_swr"); register_err: - btfm_swr_unregister_codec(pbtfmswr->dev); - + btfm_swr_unregister_hwep(); dealloc: kfree(pbtfmswr); return ret; diff --git a/soundwire/btfm_swr.h b/soundwire/btfm_swr.h index a1e9b7ab86..d28dab04c1 100644 --- a/soundwire/btfm_swr.h +++ b/soundwire/btfm_swr.h @@ -83,21 +83,4 @@ int btfm_swr_enable_port(u8 port_num, u8 ch_count, u32 sample_rate, int btfm_swr_disable_port(u8 port_num, u8 ch_count, u8 usecase); - -/** - * btfm_swr_register_codec: Register codec driver with ALSA - * @btfmswr: swr slave device data pointer. - * Returns: - * -ENOMEM - * 0 - */ -int btfm_swr_register_codec(struct btfmswr *btfmswr); - -/** - * btfm_swr_unregister_codec: Unregister codec driver with ALSA - * @dev: device node - * Returns: - * VOID - */ -void btfm_swr_unregister_codec(struct device *dev); #endif /* BTFM_SWR_H */ diff --git a/soundwire/btfm_swr_codec.c b/soundwire/btfm_swr_codec.c deleted file mode 100644 index e0fcd363a1..0000000000 --- a/soundwire/btfm_swr_codec.c +++ /dev/null @@ -1,341 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-only -/* - * Copyright (c) 2023 Qualcomm Innovation Center, Inc. All rights reserved. - */ - -#include -#include -#include -#include -#include -#include -#include "btfm_swr.h" - -static int bt_soc_enable_status; -int btfm_feedback_ch_setting; - -static int btfm_swr_codec_write(struct snd_soc_component *codec, - unsigned int reg, unsigned int value) -{ - BTFMSWR_DBG(""); - return 0; -} - -static unsigned int btfm_swr_codec_read(struct snd_soc_component *codec, - unsigned int reg) -{ - BTFMSWR_DBG(""); - return 0; -} - -static int btfm_soc_status_get(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) -{ - BTFMSWR_DBG(""); - ucontrol->value.integer.value[0] = bt_soc_enable_status; - return 1; -} - -static int btfm_soc_status_put(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) -{ - BTFMSWR_DBG(""); - return 1; -} - -static int btfm_get_feedback_ch_setting(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) -{ - BTFMSWR_DBG(""); - ucontrol->value.integer.value[0] = btfm_feedback_ch_setting; - return 1; -} - -static int btfm_put_feedback_ch_setting(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) -{ - BTFMSWR_DBG(""); - btfm_feedback_ch_setting = ucontrol->value.integer.value[0]; - return 1; -} - -static const struct snd_kcontrol_new status_controls[] = { - SOC_SINGLE_EXT("BT SOC status", 0, 0, 1, 0, - btfm_soc_status_get, - btfm_soc_status_put), - SOC_SINGLE_EXT("BT set feedback channel", 0, 0, 1, 0, - btfm_get_feedback_ch_setting, - btfm_put_feedback_ch_setting) -}; - - -static int btfm_swr_codec_probe(struct snd_soc_component *codec) -{ - BTFMSWR_DBG(""); - snd_soc_add_component_controls(codec, status_controls, - ARRAY_SIZE(status_controls)); - return 0; -} - -static void btfm_swr_codec_remove(struct snd_soc_component *codec) -{ - BTFMSWR_DBG(""); -} - -static int btfm_swr_dai_startup(struct snd_pcm_substream *substream, - struct snd_soc_dai *dai) -{ - int ret = -1; - - BTFMSWR_INFO("substream = %s stream = %d dai->name = %s", - substream->name, substream->stream, dai->name); - ret = btfm_swr_hw_init(); - return ret; -} - -static void btfm_swr_dai_shutdown(struct snd_pcm_substream *substream, - struct snd_soc_dai *dai) -{ - int ret = 0; - u8 port_type; - - BTFMSWR_INFO("dai->name: %s, dai->id: %d, dai->rate: %d", dai->name, - dai->id, dai->rate); - - switch (dai->id) { - case FMAUDIO_TX: - port_type = FM_AUDIO_TX1; - break; - case BTAUDIO_TX: - port_type = BT_AUDIO_TX1; - break; - case BTAUDIO_RX: - port_type = BT_AUDIO_RX1; - break; - case BTAUDIO_A2DP_SINK_TX: - port_type = BT_AUDIO_TX2; - break; - case BTFM_NUM_CODEC_DAIS: - default: - BTFMSWR_ERR("dai->id is invalid:%d", dai->id); - return; - } - - ret = btfm_swr_disable_port(pbtfmswr->p_dai_port->port_info[dai->id].port, - pbtfmswr->num_channels, port_type); - -} - -static int btfm_swr_dai_hw_params(struct snd_pcm_substream *substream, - struct snd_pcm_hw_params *params, - struct snd_soc_dai *dai) -{ - pbtfmswr->bps = params_width(params); - pbtfmswr->direction = substream->stream; - pbtfmswr->num_channels = params_channels(params); - - BTFMSWR_INFO("dai->name = %s dai id %x rate %d bps %d num_ch %d", - dai->name, dai->id, params_rate(params), params_width(params), - params_channels(params)); - return 0; -} - -static int btfm_swr_dai_prepare(struct snd_pcm_substream *substream, - struct snd_soc_dai *dai) -{ - int ret = -EINVAL; - u8 port_type; - - bt_soc_enable_status = 0; - BTFMSWR_INFO("dai->name: %s, dai->id: %d, dai->rate: %d direction: %d", dai->name, - dai->id, dai->rate, pbtfmswr->direction); - - /* save sample rate */ - pbtfmswr->sample_rate = dai->rate; - - switch (dai->id) { - case FMAUDIO_TX: - port_type = FM_AUDIO_TX1; - break; - case BTAUDIO_TX: - port_type = BT_AUDIO_TX1; - break; - case BTAUDIO_RX: - port_type = BT_AUDIO_RX1; - break; - case BTAUDIO_A2DP_SINK_TX: - port_type = BT_AUDIO_TX2; - break; - case BTFM_NUM_CODEC_DAIS: - default: - BTFMSWR_ERR("dai->id is invalid:%d", dai->id); - return -EINVAL; - } - - ret = btfm_swr_enable_port(pbtfmswr->p_dai_port->port_info[dai->id].port, - pbtfmswr->num_channels, dai->rate, port_type); - - /* save the enable channel status */ - if (ret == 0) - bt_soc_enable_status = 1; - - if (ret == -EISCONN) { - BTFMSWR_ERR("channel opened without closing, returning success"); - ret = 0; - } - - return ret; -} - -/* This function will be called once during boot up */ -static int btfm_swr_dai_set_channel_map(struct snd_soc_dai *dai, - unsigned int tx_num, unsigned int *tx_slot, - unsigned int rx_num, unsigned int *rx_slot) -{ - BTFMSWR_DBG(""); - return 0; -} - -static int btfm_swr_dai_get_channel_map(struct snd_soc_dai *dai, - unsigned int *tx_num, unsigned int *tx_slot, - unsigned int *rx_num, unsigned int *rx_slot) -{ - *rx_slot = 0; - *tx_slot = 0; - *rx_num = 0; - *tx_num = 0; - - switch (dai->id) { - case FMAUDIO_TX: - case BTAUDIO_TX: - case BTAUDIO_A2DP_SINK_TX: - *tx_num = pbtfmswr->num_channels; - *tx_slot = pbtfmswr->num_channels == 2 ? TWO_CHANNEL_MASK : - ONE_CHANNEL_MASK; - break; - case BTAUDIO_RX: - *rx_num = pbtfmswr->num_channels; - *rx_slot = pbtfmswr->num_channels == 2 ? TWO_CHANNEL_MASK : - ONE_CHANNEL_MASK; - break; - - default: - BTFMSWR_ERR("Unsupported DAI %d", dai->id); - return -EINVAL; - } - - return 0; -} -static struct snd_soc_dai_ops btfmswr_dai_ops = { - .startup = btfm_swr_dai_startup, - .shutdown = btfm_swr_dai_shutdown, - .hw_params = btfm_swr_dai_hw_params, - .prepare = btfm_swr_dai_prepare, - .set_channel_map = btfm_swr_dai_set_channel_map, - .get_channel_map = btfm_swr_dai_get_channel_map, -}; - -static struct snd_soc_dai_driver btfmswr_dai[] = { - { /* FM Audio data multiple channel : FM -> lpass */ - .name = "btfm_fm_swr_tx", - .id = FMAUDIO_TX, - .capture = { - .stream_name = "FM TX Capture", - .rates = SNDRV_PCM_RATE_48000, /* 48 KHz */ - .formats = SNDRV_PCM_FMTBIT_S16_LE, /* 16 bits */ - .rate_max = 48000, - .rate_min = 48000, - .channels_min = 1, - .channels_max = 2, - }, - .ops = &btfmswr_dai_ops, - }, - { /* Bluetooth SCO voice uplink: bt -> lpass */ - .name = "btfm_bt_sco_swr_tx", - .id = BTAUDIO_TX, - .capture = { - .stream_name = "SCO TX Capture", - /* 8/16/44.1/48/88.2/96/192 Khz */ - .rates = SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000 - | SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000 - | SNDRV_PCM_RATE_88200 | SNDRV_PCM_RATE_96000 - | SNDRV_PCM_RATE_192000, - .formats = SNDRV_PCM_FMTBIT_S16_LE, /* 16 bits */ - .rate_max = 192000, - .rate_min = 8000, - .channels_min = 1, - .channels_max = 1, - }, - .ops = &btfmswr_dai_ops, - }, - { /* Bluetooth SCO voice downlink: lpass -> bt or A2DP Playback */ - .name = "btfm_bt_sco_a2dp_swr_rx", - .id = BTAUDIO_RX, - .playback = { - .stream_name = "SCO A2DP RX Playback", - /* 8/16/44.1/48/88.2/96/192 Khz */ - .rates = SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000 - | SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000 - | SNDRV_PCM_RATE_88200 | SNDRV_PCM_RATE_96000 - | SNDRV_PCM_RATE_192000, - .formats = SNDRV_PCM_FMTBIT_S16_LE, /* 16 bits */ - .rate_max = 192000, - .rate_min = 8000, - .channels_min = 1, - .channels_max = 1, - }, - .ops = &btfmswr_dai_ops, - }, - { /* Bluetooth A2DP sink: bt -> lpass */ - .name = "btfm_a2dp_sink_swr_tx", - .id = BTAUDIO_A2DP_SINK_TX, - .capture = { - .stream_name = "A2DP sink TX Capture", - /* 8/16/44.1/48/88.2/96/192 Khz */ - .rates = SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000 - | SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000 - | SNDRV_PCM_RATE_88200 | SNDRV_PCM_RATE_96000 - | SNDRV_PCM_RATE_192000, - .formats = SNDRV_PCM_FMTBIT_S16_LE, /* 16 bits */ - .rate_max = 192000, - .rate_min = 8000, - .channels_min = 1, - .channels_max = 1, - }, - .ops = &btfmswr_dai_ops, - }, -}; - -static const struct snd_soc_component_driver btfmswr_codec = { - .probe = btfm_swr_codec_probe, - .remove = btfm_swr_codec_remove, - .read = btfm_swr_codec_read, - .write = btfm_swr_codec_write, -}; - -int btfm_swr_register_codec(struct btfmswr *btfm_swr) -{ - int ret = 0; - struct device *dev = btfm_swr->dev; - - BTFMSWR_DBG(""); - dev_err(dev, "\n"); - - /* Register Codec driver */ - ret = snd_soc_register_component(dev, &btfmswr_codec, - btfmswr_dai, ARRAY_SIZE(btfmswr_dai)); - if (ret) - BTFMSWR_ERR("failed to register codec (%d)", ret); - return ret; -} - -void btfm_swr_unregister_codec(struct device *dev) -{ - BTFMSWR_DBG(""); - /* Unregister Codec driver */ - snd_soc_unregister_component(dev); -} - - -MODULE_DESCRIPTION("BTFM SoundWire Codec driver"); -MODULE_LICENSE("GPL v2"); diff --git a/soundwire/btfm_swr_hw_interface.c b/soundwire/btfm_swr_hw_interface.c new file mode 100644 index 0000000000..200c4e7016 --- /dev/null +++ b/soundwire/btfm_swr_hw_interface.c @@ -0,0 +1,440 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2023 Qualcomm Innovation Center, Inc. All rights reserved. + */ + +#include +#include +#include +#include +#include +#include +#include "btfm_swr.h" +#include "btfm_swr_hw_interface.h" +#include "btfm_codec_hw_interface.h" + +#define LPAIF_AUD 0x05 + +static int bt_soc_enable_status; +int btfm_feedback_ch_setting; +static uint8_t usecase_codec; + +static int btfm_swr_hwep_write(struct snd_soc_component *codec, + unsigned int reg, unsigned int value) +{ + BTFMSWR_DBG(""); + return 0; +} + +static unsigned int btfm_swr_hwep_read(struct snd_soc_component *codec, + unsigned int reg) +{ + BTFMSWR_DBG(""); + return 0; +} + +static int btfm_soc_status_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + BTFMSWR_DBG(""); + ucontrol->value.integer.value[0] = bt_soc_enable_status; + return 1; +} + +static int btfm_soc_status_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + BTFMSWR_DBG(""); + return 1; +} + +static int btfm_get_feedback_ch_setting(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + BTFMSWR_DBG(""); + ucontrol->value.integer.value[0] = btfm_feedback_ch_setting; + return 1; +} + +static int btfm_put_feedback_ch_setting(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + BTFMSWR_DBG(""); + btfm_feedback_ch_setting = ucontrol->value.integer.value[0]; + return 1; +} + +static int btfm_get_codec_type(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + BTFMSWR_DBG("current codec type:%s", codec_text[usecase_codec]); + ucontrol->value.integer.value[0] = usecase_codec; + return 1; +} + +static int btfm_put_codec_type(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + usecase_codec = ucontrol->value.integer.value[0]; + BTFMSWR_DBG("codec type set to:%s", codec_text[usecase_codec]); + return 1; +} + +static struct snd_kcontrol_new status_controls[] = { + SOC_SINGLE_EXT("BT SOC status", 0, 0, 1, 0, + btfm_soc_status_get, btfm_soc_status_put), + SOC_SINGLE_EXT("BT set feedback channel", 0, 0, 1, 0, + btfm_get_feedback_ch_setting, + btfm_put_feedback_ch_setting), + SOC_ENUM_EXT("BT codec type", codec_display, + btfm_get_codec_type, btfm_put_codec_type), +}; + + +static int btfm_swr_hwep_probe(struct snd_soc_component *codec) +{ + BTFMSWR_DBG(""); + return 0; +} + +static void btfm_swr_hwep_remove(struct snd_soc_component *codec) +{ + BTFMSWR_DBG(""); +} + +static int btfm_swr_dai_startup(void *dai) +{ + //struct hwep_data *hwep_info = (struct hwep_data *)dai; + int ret = -1; + + BTFMSWR_DBG(""); + + ret = btfm_swr_hw_init(); + return ret; +} + +static void btfm_swr_dai_shutdown(void *dai, int id) +{ + struct hwep_data *hwep_info = (struct hwep_data *)dai; + struct btfmswr *btfmswr = dev_get_drvdata(hwep_info->dev); + int ret = 0; + u8 port_type; + + BTFMSWR_INFO(""); + + if (btfmswr == NULL) + BTFMSWR_INFO("btfmswr is NULL\n"); + + switch (id) { + case FMAUDIO_TX: + port_type = FM_AUDIO_TX1; + break; + case BTAUDIO_TX: + port_type = BT_AUDIO_TX1; + break; + case BTAUDIO_RX: + port_type = BT_AUDIO_RX1; + break; + case BTAUDIO_A2DP_SINK_TX: + port_type = BT_AUDIO_TX2; + break; + case BTFM_NUM_CODEC_DAIS: + default: + BTFMSWR_ERR("dai->id is invalid:%d", id); + return; + } + + ret = btfm_swr_disable_port(btfmswr->p_dai_port->port_info[id].port, + btfmswr->num_channels, port_type); +} + +static int btfm_swr_dai_hw_params(void *dai, uint32_t bps, + uint32_t direction, uint8_t num_channels) +{ + struct hwep_data *hwep_info = (struct hwep_data *)dai; + struct btfmswr *btfmswr = dev_get_drvdata(hwep_info->dev); + + BTFMSWR_DBG(""); + btfmswr->bps = bps; + btfmswr->direction = direction; + btfmswr->num_channels = num_channels; + + return 0; +} + +void btfm_get_sampling_rate(uint32_t *sampling_rate) +{ + uint8_t codec_types_avb = ARRAY_SIZE(codec_text); + + if (usecase_codec > (codec_types_avb - 1)) { + BTFMSWR_ERR("falling back to use default sampling_rate: %u", + *sampling_rate); + return; + } + + if (*sampling_rate == 44100 || *sampling_rate == 48000) { + if (usecase_codec == LDAC || + usecase_codec == APTX_AD) + *sampling_rate = (*sampling_rate) * 2; + } + + if (usecase_codec == LC3_VOICE || + usecase_codec == APTX_AD_SPEECH || + usecase_codec == LC3 || usecase_codec == APTX_AD_QLEA || + usecase_codec == APTX_AD_R4) { + *sampling_rate = 96000; + } + + BTFMSWR_INFO("current usecase codec type %s and sampling rate:%u khz", + codec_text[usecase_codec], *sampling_rate); +} + +static int btfm_swr_dai_prepare(void *dai, uint32_t sampling_rate, uint32_t direction, int id) +{ + struct hwep_data *hwep_info = (struct hwep_data *)dai; + struct btfmswr *btfmswr = dev_get_drvdata(hwep_info->dev); + int ret = -EINVAL; + u8 port_type; + + bt_soc_enable_status = 0; + BTFMSWR_INFO("dai->id: %d, dai->rate: %d direction: %d", id, sampling_rate, direction); + + btfm_get_sampling_rate(&sampling_rate); + btfmswr->sample_rate = sampling_rate; + + switch (id) { + case FMAUDIO_TX: + port_type = FM_AUDIO_TX1; + break; + case BTAUDIO_TX: + port_type = BT_AUDIO_TX1; + break; + case BTAUDIO_RX: + port_type = BT_AUDIO_RX1; + break; + case BTAUDIO_A2DP_SINK_TX: + port_type = BT_AUDIO_TX2; + break; + case BTFM_NUM_CODEC_DAIS: + default: + BTFMSWR_ERR("dai->id is invalid:%d", id); + return -EINVAL; + } + + ret = btfm_swr_enable_port(btfmswr->p_dai_port->port_info[id].port, + btfmswr->num_channels, sampling_rate, port_type); + + /* save the enable channel status */ + if (ret == 0) + bt_soc_enable_status = 1; + + if (ret == -EISCONN) { + BTFMSWR_ERR("channel opened without closing, returning success"); + ret = 0; + } + + return ret; +} + +/* This function will be called once during boot up */ +static int btfm_swr_dai_set_channel_map(void *dai, + unsigned int tx_num, unsigned int *tx_slot, + unsigned int rx_num, unsigned int *rx_slot) +{ + BTFMSWR_DBG(""); + return 0; +} + +static int btfm_swr_dai_get_channel_map(void *dai, + unsigned int *tx_num, unsigned int *tx_slot, + unsigned int *rx_num, unsigned int *rx_slot, int id) +{ + + struct hwep_data *hwep_info = (struct hwep_data *)dai; + struct btfmswr *btfmswr = dev_get_drvdata(hwep_info->dev); + + *rx_slot = 0; + *tx_slot = 0; + *rx_num = 0; + *tx_num = 0; + + switch (id) { + case FMAUDIO_TX: + case BTAUDIO_TX: + case BTAUDIO_A2DP_SINK_TX: + *tx_num = btfmswr->num_channels; + *tx_slot = btfmswr->num_channels == 2 ? TWO_CHANNEL_MASK : ONE_CHANNEL_MASK; + break; + case BTAUDIO_RX: + *rx_num = btfmswr->num_channels; + *rx_slot = btfmswr->num_channels == 2 ? TWO_CHANNEL_MASK : ONE_CHANNEL_MASK; + break; + + default: + BTFMSWR_ERR("Unsupported DAI %d", id); + return -EINVAL; + } + + return 0; +} + +int btfm_swr_dai_get_configs(void *dai, void *config, uint8_t id) +{ + struct hwep_data *hwep_info = (struct hwep_data *)dai; + struct btfmswr *btfmswr = dev_get_drvdata(hwep_info->dev); + struct hwep_dma_configurations *hwep_config; + + BTFMSWR_DBG(""); + hwep_config = (struct hwep_dma_configurations *)config; + + hwep_config->stream_id = id; + hwep_config->sample_rate = btfmswr->sample_rate; + hwep_config->bit_width = (uint8_t)btfmswr->bps; + hwep_config->codectype = usecase_codec; + + hwep_config->num_channels = btfmswr->num_channels; + hwep_config->active_channel_mask = (btfmswr->num_channels == 2 ? + TWO_CHANNEL_MASK : ONE_CHANNEL_MASK); + hwep_config->lpaif = LPAIF_AUD; + hwep_config->inf_index = 1; + return 1; +} + +static struct hwep_dai_ops btfmswr_hw_dai_ops = { + .hwep_startup = btfm_swr_dai_startup, + .hwep_shutdown = btfm_swr_dai_shutdown, + .hwep_hw_params = btfm_swr_dai_hw_params, + .hwep_prepare = btfm_swr_dai_prepare, + .hwep_set_channel_map = btfm_swr_dai_set_channel_map, + .hwep_get_channel_map = btfm_swr_dai_get_channel_map, + .hwep_get_configs = btfm_swr_dai_get_configs, + .hwep_codectype = &usecase_codec, +}; + +static struct hwep_dai_driver btfmswr_dai_driver[] = { + { /* FM Audio data multiple channel : FM -> lpass */ + .dai_name = "btaudio_fm_tx", + .id = FMAUDIO_TX, + .capture = { + .stream_name = "FM SWR TX Capture", + .rates = SNDRV_PCM_RATE_48000, /* 48 KHz */ + .formats = SNDRV_PCM_FMTBIT_S16_LE, /* 16 bits */ + .rate_max = 48000, + .rate_min = 48000, + .channels_min = 1, + .channels_max = 2, + }, + .dai_ops = &btfmswr_hw_dai_ops, + }, + { /* Bluetooth SCO voice uplink: bt -> lpass */ + .dai_name = "btaudio_tx", + .id = BTAUDIO_TX, + .capture = { + .stream_name = "BT Audio SWR Tx Capture", + /* 8 KHz or 16 KHz */ + .rates = SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000 + | SNDRV_PCM_RATE_8000_192000 + | SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000 + | SNDRV_PCM_RATE_88200 | SNDRV_PCM_RATE_96000 + | SNDRV_PCM_RATE_192000, + .formats = SNDRV_PCM_FMTBIT_S16_LE, /* 16 bits */ + .rate_max = 192000, + .rate_min = 8000, + .channels_min = 1, + .channels_max = 1, + }, + .dai_ops = &btfmswr_hw_dai_ops, + }, + { /* Bluetooth SCO voice downlink: lpass -> bt or A2DP Playback */ + .dai_name = "btaudio_rx", + .id = BTAUDIO_RX, + .playback = { + .stream_name = "BT Audio SWR Rx Playback", + /* 8/16/44.1/48/88.2/96 Khz */ + .rates = SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000 + | SNDRV_PCM_RATE_8000_192000 + | SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000 + | SNDRV_PCM_RATE_88200 | SNDRV_PCM_RATE_96000 + | SNDRV_PCM_RATE_192000, + .formats = SNDRV_PCM_FMTBIT_S16_LE, /* 16 bits */ + .rate_max = 192000, + .rate_min = 8000, + .channels_min = 1, + .channels_max = 1, + }, + .dai_ops = &btfmswr_hw_dai_ops, + }, + { /* Bluetooth A2DP sink: bt -> lpass */ + .dai_name = "btfm_a2dp_sink_swr_tx", + .id = BTAUDIO_A2DP_SINK_TX, + .capture = { + .stream_name = "A2DP sink TX Capture", + /* 8/16/44.1/48/88.2/96/192 Khz */ + .rates = SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000 + | SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000 + | SNDRV_PCM_RATE_88200 | SNDRV_PCM_RATE_96000 + | SNDRV_PCM_RATE_192000, + .formats = SNDRV_PCM_FMTBIT_S16_LE, /* 16 bits */ + .rate_max = 192000, + .rate_min = 8000, + .channels_min = 1, + .channels_max = 1, + }, + .dai_ops = &btfmswr_hw_dai_ops, + } +}; + +static struct hwep_comp_drv btfmswr_hw_driver = { + .hwep_probe = btfm_swr_hwep_probe, + .hwep_remove = btfm_swr_hwep_remove, + .hwep_read = btfm_swr_hwep_read, + .hwep_write = btfm_swr_hwep_write, +}; + +int btfm_swr_register_hw_ep(struct btfmswr *btfm_swr) +{ + struct device *dev = btfm_swr->dev; + struct hwep_data *hwep_info; + int ret = 0; + + BTFMSWR_INFO("Registering with BTFMCODEC HWEP interface\n"); + hwep_info = kzalloc(sizeof(struct hwep_data), GFP_KERNEL); + + if (!hwep_info) { + BTFMSWR_ERR("%s: failed to allocate memory\n", __func__); + ret = -ENOMEM; + goto end; + } + + /* Copy EP device parameters as intercations will be on the same device */ + hwep_info->dev = dev; + strscpy(hwep_info->driver_name, SWR_SLAVE_COMPATIBLE_STR, DEVICE_NAME_MAX_LEN); + hwep_info->drv = &btfmswr_hw_driver; + hwep_info->dai_drv = btfmswr_dai_driver; + hwep_info->num_dai = ARRAY_SIZE(btfmswr_dai_driver); + hwep_info->num_dai = 4; + hwep_info->num_mixer_ctrl = ARRAY_SIZE(status_controls); + hwep_info->mixer_ctrl = status_controls; + /* Register to hardware endpoint */ + ret = btfmcodec_register_hw_ep(hwep_info); + if (ret) { + BTFMSWR_ERR("failed to register with btfmcodec driver hw interface (%d)", ret); + goto end; + } + + BTFMSWR_INFO("Registered succesfull with BTFMCODEC HWEP interface\n"); + return ret; +end: + return ret; +} + +void btfm_swr_unregister_hwep(void) +{ + BTFMSWR_INFO("Unregistered with BTFMCODEC HWEP interface"); + /* Unregister with BTFMCODEC HWEP driver */ + btfmcodec_unregister_hw_ep(SWR_SLAVE_COMPATIBLE_STR); + +} + +MODULE_DESCRIPTION("BTFM SoundWire Codec driver"); +MODULE_LICENSE("GPL v2"); diff --git a/soundwire/btfm_swr_hw_interface.h b/soundwire/btfm_swr_hw_interface.h new file mode 100644 index 0000000000..60b2ff7557 --- /dev/null +++ b/soundwire/btfm_swr_hw_interface.h @@ -0,0 +1,35 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2023 Qualcomm Innovation Center, Inc. All rights reserved. + */ + +#ifndef __LINUX_BTFM_SWR_HW_INTERFACE_H +#define __LINUX_BTFM_SWR_HW_INTERFACE_H + +int btfm_swr_register_hw_ep(struct btfmswr *a); +void btfm_swr_unregister_hwep(void); + +enum Codec { + SBC = 0, + AAC, + LDAC, + APTX, + APTX_HD, + APTX_AD, + LC3, + APTX_AD_SPEECH, + LC3_VOICE, + APTX_AD_QLEA, + APTX_AD_R4, + NO_CODEC +}; + +static const char * const codec_text[] = {"CODEC_TYPE_SBC", "CODEC_TYPE_AAC", + "CODEC_TYPE_LDAC", "CODEC_TYPE_APTX", + "CODEC_TYPE_APTX_HD", "CODEC_TYPE_APTX_AD", + "CODEC_TYPE_LC3", "CODEC_TYPE_APTX_AD_SPEECH", + "CODEC_TYPE_LC3_VOICE", "CODEC_TYPE_APTX_AD_QLEA", + "CODEC_TYPE_APTX_AD_R4", "CODEC_TYPE_INVALID"}; + +static SOC_ENUM_SINGLE_EXT_DECL(codec_display, codec_text); +#endif /*__LINUX_BTFM_SWR_HW_INTERFACE_H*/ From d6a07449f0c9fcff916e6ea42bb3ce32594da4fb Mon Sep 17 00:00:00 2001 From: Balakrishna Godavarthi Date: Sun, 15 Oct 2023 21:15:51 +0530 Subject: [PATCH 060/154] Enable bt drivers in sun target This change will enable below. 1. BTFM Codec Driver. 2. Enable Bazel build Change-Id: Ifebf99929ef15644aaa87a51a4c542f8ec887a37 Signed-off-by: Balakrishna Godavarthi --- Android.mk | 30 +++++++++++++++++++++--------- bt_kernel_product_board.mk | 4 ++-- bt_kernel_vendor_board.mk | 6 ++++-- btfmcodec/btfm_codec_interface.c | 8 +------- target.bzl | 18 ++++++++++++++++++ 5 files changed, 46 insertions(+), 20 deletions(-) diff --git a/Android.mk b/Android.mk index 50d4f1a641..38da262508 100644 --- a/Android.mk +++ b/Android.mk @@ -3,12 +3,11 @@ LOCAL_PATH := $(call my-dir) # Build/Package only in case of supported target -ifeq ($(call is-board-platform-in-list,taro kalama pineapple blair sun), true) +ifeq ($(call is-board-platform-in-list, taro kalama pineapple blair sun), true) BT_SELECT := CONFIG_MSM_BT_POWER=m -#ifdef CONFIG_SLIMBUS -BT_SELECT += CONFIG_BTFM_SLIM=n -#endif +BT_SELECT += CONFIG_SLIM_BTFM_CODEC=n +BT_SELECT += CONFIG_BTFM_CODEC=m BT_SELECT += CONFIG_I2C_RTC6226_QCA=m ifeq ($(TARGET_KERNEL_DLKM_SECURE_MSM_OVERRIDE), true) @@ -20,9 +19,9 @@ endif LOCAL_PATH := $(call my-dir) LOCAL_MODULE_DDK_BUILD := true LOCAL_MODULE_KO_DIRS := pwr/btpower.ko -LOCAL_MODULE_KO_DIRS += slimbus/bt_fm_slim.ko LOCAL_MODULE_KO_DIRS += rtc6226/radio-i2c-rtc6226-qca.ko - +#LOCAL_MODULE_KO_DIRS += slimbus/btfm_slim_codec.ko +LOCAL_MODULE_KO_DIRS += btfmcodec/btfmcodec.ko # This makefile is only for DLKM ifneq ($(findstring vendor,$(LOCAL_PATH)),) @@ -79,15 +78,27 @@ LOCAL_MODULE_TAGS := optional LOCAL_MODULE_DEBUG_ENABLE := true LOCAL_MODULE_PATH := $(KERNEL_MODULES_OUT) include $(DLKM_DIR)/Build_external_kernelmodule.mk -################################ slimbus ################################ + +ifeq ($(call is-board-platform-in-list, sun), true) +################################ BTFM CODEC Driver ######################### +include $(CLEAR_VARS) +LOCAL_SRC_FILES := $(BT_SRC_FILES) +LOCAL_MODULE := btfmcodec.ko +LOCAL_MODULE_KBUILD_NAME := btfmcodec/btfmcodec.ko +LOCAL_MODULE_TAGS := optional +LOCAL_MODULE_DEBUG_ENABLE := true +LOCAL_MODULE_PATH := $(KERNEL_MODULES_OUT) +include $(DLKM_DIR)/Build_external_kernelmodule.mk +############################ slimbus with BTFM CODEC Driver ################# #include $(CLEAR_VARS) #LOCAL_SRC_FILES := $(BT_SRC_FILES) -#LOCAL_MODULE := bt_fm_slim.ko -#LOCAL_MODULE_KBUILD_NAME := slimbus/bt_fm_slim.ko +#LOCAL_MODULE := btfm_slim_codec.ko +#LOCAL_MODULE_KBUILD_NAME := slimbus/btfm_slim_codec.ko #LOCAL_MODULE_TAGS := optional #LOCAL_MODULE_DEBUG_ENABLE := true #LOCAL_MODULE_PATH := $(KERNEL_MODULES_OUT) #include $(DLKM_DIR)/Build_external_kernelmodule.mk +endif ################################ rtc6226 ################################ include $(CLEAR_VARS) LOCAL_SRC_FILES := $(BT_SRC_FILES) @@ -99,5 +110,6 @@ LOCAL_MODULE_PATH := $(KERNEL_MODULES_OUT) include $(DLKM_DIR)/Build_external_kernelmodule.mk ########################################################### + endif # DLKM check endif # supported target check diff --git a/bt_kernel_product_board.mk b/bt_kernel_product_board.mk index 6d22eee61e..a4d55dafa5 100644 --- a/bt_kernel_product_board.mk +++ b/bt_kernel_product_board.mk @@ -1,5 +1,5 @@ # Build BT kernel drivers PRODUCT_PACKAGES += $(KERNEL_MODULES_OUT)/btpower.ko -#PRODUCT_PACKAGES += $(KERNEL_MODULES_OUT)/bt_fm_slim.ko +#PRODUCT_PACKAGES += $(KERNEL_MODULES_OUT)/btfm_slim_codec.ko PRODUCT_PACKAGES += $(KERNEL_MODULES_OUT)/radio-i2c-rtc6226-qca.ko - +PRODUCT_PACKAGES += $(KERNEL_MODULES_OUT)/btfmcodec.ko diff --git a/bt_kernel_vendor_board.mk b/bt_kernel_vendor_board.mk index fc86885a6d..c8405e5b8a 100644 --- a/bt_kernel_vendor_board.mk +++ b/bt_kernel_vendor_board.mk @@ -4,16 +4,18 @@ ifeq ($(TARGET_USES_QMAA),true) ifeq ($(TARGET_USES_QMAA_OVERRIDE_BLUETOOTH), true) ifeq ($(call is-board-platform-in-list,$(TARGET_BOARD_PLATFORM)),true) BT_KERNEL_DRIVER := $(KERNEL_MODULES_OUT)/btpower.ko - #BT_KERNEL_DRIVER += $(KERNEL_MODULES_OUT)/bt_fm_slim.ko + #BT_KERNEL_DRIVER += $(KERNEL_MODULES_OUT)/btfm_slim_codec.ko BT_KERNEL_DRIVER += $(KERNEL_MODULES_OUT)/radio-i2c-rtc6226-qca.ko + BT_KERNEL_DRIVER += $(KERNEL_MODULES_OUT)/btfmcodec.ko BOARD_VENDOR_KERNEL_MODULES += $(BT_KERNEL_DRIVER) endif endif else ifeq ($(call is-board-platform-in-list,$(TARGET_BOARD_PLATFORM)),true) BT_KERNEL_DRIVER := $(KERNEL_MODULES_OUT)/btpower.ko - #BT_KERNEL_DRIVER += $(KERNEL_MODULES_OUT)/bt_fm_slim.ko + #BT_KERNEL_DRIVER += $(KERNEL_MODULES_OUT)/btfm_slim_codec.ko BT_KERNEL_DRIVER += $(KERNEL_MODULES_OUT)/radio-i2c-rtc6226-qca.ko + BT_KERNEL_DRIVER += $(KERNEL_MODULES_OUT)/btfmcodec.ko BOARD_VENDOR_KERNEL_MODULES += $(BT_KERNEL_DRIVER) endif endif diff --git a/btfmcodec/btfm_codec_interface.c b/btfmcodec/btfm_codec_interface.c index d8139d482b..fb99d4308c 100644 --- a/btfmcodec/btfm_codec_interface.c +++ b/btfmcodec/btfm_codec_interface.c @@ -575,7 +575,7 @@ int btfmcodec_hwep_prepare(struct btfmcodec_data *btfmcodec, uint32_t sampling_r if (dai_drv && dai_drv->dai_ops && dai_drv->dai_ops->hwep_prepare) { ret = dai_drv->dai_ops->hwep_prepare((void *)hwep_info, sampling_rate, direction, id); - BTFMCODEC_ERR("%s: hwep info %d", __func__, hwep_info->flags); + BTFMCODEC_ERR("%s: hwep info %ld", __func__, hwep_info->flags); if (ret == 0 && test_bit(BTADV_AUDIO_MASTER_CONFIG, &hwep_info->flags)) { ret = btfmcodec_configure_master(btfmcodec, (uint8_t)id); if (ret < 0) { @@ -848,15 +848,9 @@ int btfm_register_codec(struct hwep_data *hwep_info) BTFMCODEC_INFO("btfmcodec address :%p", btfmcodec); BTFMCODEC_INFO("HWEPINFO address:%p", hwep_info); BTFMCODEC_INFO("btfmcodec_dev INFO address:%p", btfmcodec->btfmcodec_dev); - BTFMCODEC_INFO("before wq_hwep_shutdown:%p", btfmcodec_dev->wq_hwep_shutdown); - BTFMCODEC_INFO("before wq_prepare_bearer:%p", btfmcodec_dev->wq_prepare_bearer); INIT_WORK(&btfmcodec_dev->wq_hwep_shutdown, btfmcodec_wq_hwep_shutdown); INIT_WORK(&btfmcodec_dev->wq_prepare_bearer, btfmcodec_wq_prepare_bearer); INIT_WORK(&btfmcodec_dev->wq_hwep_configure, btfmcodec_wq_hwep_configure); - BTFMCODEC_INFO("after wq_hwep_shutdown:%p", btfmcodec_dev->wq_hwep_shutdown); - BTFMCODEC_INFO("after wq_prepare_bearer:%p", btfmcodec_dev->wq_prepare_bearer); - BTFMCODEC_INFO("btfmcodec_wq_prepare_bearer:%p", btfmcodec_wq_prepare_bearer); - BTFMCODEC_INFO("btfmcodec_wq_hwep_shutdown:%p", btfmcodec_wq_hwep_shutdown); if (isCpSupported()) { if (!strcmp(hwep_info->driver_name, "btfmslim")) diff --git a/target.bzl b/target.bzl index d7a6d674cd..98f1efb97e 100644 --- a/target.bzl +++ b/target.bzl @@ -17,3 +17,21 @@ def define_pineapple(): #"CONFIG_BT_HW_SECURE_DISABLE", ] ) + +def define_sun(): + define_bt_modules( + target = "sun", + modules = [ + "btpower", + "radio-i2c-rtc6226-qca", + # "btfm_slim_codec", + "btfmcodec", + ], + config_options = [ + "CONFIG_MSM_BT_POWER", + "CONFIG_I2C_RTC6226_QCA", + # "CONFIG_SLIM_BTFM_CODEC", + "CONFIG_BTFM_CODEC", + # "CONFIG_BT_HW_SECURE_DISABLE", + ] + ) From f0f904a9ad9ba634a51c840c2547e77aef8cf82c Mon Sep 17 00:00:00 2001 From: Xhoendi Collaku Date: Fri, 13 Oct 2023 10:04:42 -0700 Subject: [PATCH 061/154] Add DLKM restriction for bt-kernel Change-Id: I2667bc2acfb3818578c847dcdcb9c2318bf6e08e Signed-off-by: Xhoendi Collaku --- Android.mk | 20 +++++++++++++++----- 1 file changed, 15 insertions(+), 5 deletions(-) diff --git a/Android.mk b/Android.mk index 50d4f1a641..489387506c 100644 --- a/Android.mk +++ b/Android.mk @@ -1,5 +1,14 @@ # Android makefile for BT kernel modules +BT_DLKM_ENABLE := true +ifeq ($(TARGET_KERNEL_DLKM_DISABLE), true) + ifeq ($(TARGET_KERNEL_DLKM_BT_OVERRIDE), false) + BT_DLKM_ENABLE := false + endif +endif + +ifeq ($(BT_DLKM_ENABLE), true) + LOCAL_PATH := $(call my-dir) # Build/Package only in case of supported target @@ -28,7 +37,7 @@ LOCAL_MODULE_KO_DIRS += rtc6226/radio-i2c-rtc6226-qca.ko ifneq ($(findstring vendor,$(LOCAL_PATH)),) ifneq ($(findstring opensource,$(LOCAL_PATH)),) - BT_BLD_DIR := $(abspath .)/vendor/qcom/opensource/bt-kernel +BT_BLD_DIR := $(abspath .)/vendor/qcom/opensource/bt-kernel endif # opensource DLKM_DIR := $(TOP)/device/qcom/common/dlkm @@ -38,11 +47,11 @@ DLKM_DIR := $(TOP)/device/qcom/common/dlkm # This is set once per LOCAL_PATH, not per (kernel) module KBUILD_OPTIONS := BT_KERNEL_ROOT=$(BT_BLD_DIR) KBUILD_OPTIONS += $(foreach bt_select, \ - $(BT_SELECT), \ - $(bt_select)) + $(BT_SELECT), \ + $(bt_select)) BT_SRC_FILES := \ - $(wildcard $(LOCAL_PATH)/*) \ - $(wildcard $(LOCAL_PATH)/*/*) \ + $(wildcard $(LOCAL_PATH)/*) \ + $(wildcard $(LOCAL_PATH)/*/*) \ ifeq ($(TARGET_KERNEL_DLKM_SECURE_MSM_OVERRIDE), true) ifeq ($(ENABLE_PERIPHERAL_STATE_UTILS), true) @@ -101,3 +110,4 @@ include $(DLKM_DIR)/Build_external_kernelmodule.mk endif # DLKM check endif # supported target check +endif # TARGET_KERNEL_DLKM_BT_OVERRIDE From 3186b236045182a1781092c25d541f607b941fbf Mon Sep 17 00:00:00 2001 From: pramod kotreshappa Date: Wed, 25 Oct 2023 00:54:16 -0700 Subject: [PATCH 062/154] Do not include btfmcodec for pineapple target. Change-Id: Ibfb380993e856f348263b82841abf0da1657ed60 Signed-off-by: pramod kotreshappa --- Android.mk | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/Android.mk b/Android.mk index 1af8524020..0200efd825 100644 --- a/Android.mk +++ b/Android.mk @@ -16,7 +16,6 @@ ifeq ($(call is-board-platform-in-list, taro kalama pineapple blair sun), true) BT_SELECT := CONFIG_MSM_BT_POWER=m BT_SELECT += CONFIG_SLIM_BTFM_CODEC=n -BT_SELECT += CONFIG_BTFM_CODEC=m BT_SELECT += CONFIG_I2C_RTC6226_QCA=m ifeq ($(TARGET_KERNEL_DLKM_SECURE_MSM_OVERRIDE), true) @@ -30,7 +29,11 @@ LOCAL_MODULE_DDK_BUILD := true LOCAL_MODULE_KO_DIRS := pwr/btpower.ko LOCAL_MODULE_KO_DIRS += rtc6226/radio-i2c-rtc6226-qca.ko #LOCAL_MODULE_KO_DIRS += slimbus/btfm_slim_codec.ko + +ifneq ($(TARGET_BOARD_PLATFORM), pineapple) +BT_SELECT += CONFIG_BTFM_CODEC=m LOCAL_MODULE_KO_DIRS += btfmcodec/btfmcodec.ko +endif # This makefile is only for DLKM ifneq ($(findstring vendor,$(LOCAL_PATH)),) From 61618d20e201ab02765f9c9641c4b5ca39b20312 Mon Sep 17 00:00:00 2001 From: pramod kotreshappa Date: Thu, 26 Oct 2023 17:38:46 -0700 Subject: [PATCH 063/154] Exclude btfmcodec.ko from techpack compilation for pineapple Change-Id: I0b1d739fc268662058787da521fa7def8c7afec3 --- bt_kernel_vendor_board.mk | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/bt_kernel_vendor_board.mk b/bt_kernel_vendor_board.mk index c8405e5b8a..f9af0921a5 100644 --- a/bt_kernel_vendor_board.mk +++ b/bt_kernel_vendor_board.mk @@ -6,7 +6,9 @@ ifeq ($(TARGET_USES_QMAA),true) BT_KERNEL_DRIVER := $(KERNEL_MODULES_OUT)/btpower.ko #BT_KERNEL_DRIVER += $(KERNEL_MODULES_OUT)/btfm_slim_codec.ko BT_KERNEL_DRIVER += $(KERNEL_MODULES_OUT)/radio-i2c-rtc6226-qca.ko + ifneq ($(TARGET_BOARD_PLATFORM), pineapple) BT_KERNEL_DRIVER += $(KERNEL_MODULES_OUT)/btfmcodec.ko + endif BOARD_VENDOR_KERNEL_MODULES += $(BT_KERNEL_DRIVER) endif endif @@ -15,7 +17,9 @@ else BT_KERNEL_DRIVER := $(KERNEL_MODULES_OUT)/btpower.ko #BT_KERNEL_DRIVER += $(KERNEL_MODULES_OUT)/btfm_slim_codec.ko BT_KERNEL_DRIVER += $(KERNEL_MODULES_OUT)/radio-i2c-rtc6226-qca.ko + ifneq ($(TARGET_BOARD_PLATFORM), pineapple) BT_KERNEL_DRIVER += $(KERNEL_MODULES_OUT)/btfmcodec.ko + endif BOARD_VENDOR_KERNEL_MODULES += $(BT_KERNEL_DRIVER) endif endif From 55b51d64b6ac254a12806241a2d032ff888e6579 Mon Sep 17 00:00:00 2001 From: Girish BN Date: Thu, 26 Oct 2023 22:07:23 +0530 Subject: [PATCH 064/154] Add Multi Client Support to Power Driver This change adds multi-client support for BT power driver Change-Id: Ibfa57bb476d145c66f963d8185500a8c24a3702f Signed-off-by: Girish BN --- include/btpower.h | 85 ++- pwr/btpower.c | 1296 ++++++++++++++++++++++++++++++++------------- 2 files changed, 998 insertions(+), 383 deletions(-) diff --git a/include/btpower.h b/include/btpower.h index 29b5887819..3ad80ecb9d 100644 --- a/include/btpower.h +++ b/include/btpower.h @@ -1,7 +1,7 @@ /* SPDX-License-Identifier: GPL-2.0-only */ /* * Copyright (c) 2016-2021, The Linux Foundation. All rights reserved. - * Copyright (c) 2021 Qualcomm Innovation Center, Inc. All rights reserved. + * Copyright (c) 2021-2023 Qualcomm Innovation Center, Inc. All rights reserved. */ #ifndef __LINUX_BLUETOOTH_POWER_H @@ -11,14 +11,45 @@ #include #include #include +#include + /* * voltage regulator information required for configuring the * bluetooth chipset */ -enum bt_power_modes { - BT_POWER_DISABLE = 0, - BT_POWER_ENABLE, - BT_POWER_RETENTION + +enum power_modes { + POWER_DISABLE = 0, + POWER_ENABLE, + POWER_RETENTION +}; + +enum SubSystem { + BLUETOOTH = 1, + UWB, +}; + +enum power_states { + IDLE = 0, + BT_ON, + UWB_ON, + ALL_CLIENTS_ON, +}; + +enum cores { + BT_CORE = 0, + UWB_CORE, + PLATFORM_CORE +}; + +enum ssr_states { + SUB_STATE_IDLE = 0, + SSR_ON_BT, + BT_SSR_COMPLETED, + SSR_ON_UWB, + UWB_SSR_COMPLETED, + REG_BT_PID, + REG_UWB_PID, }; struct log_index { @@ -26,7 +57,7 @@ struct log_index { int crash; }; -struct bt_power_vreg_data { +struct vreg_data { struct regulator *reg; /* voltage regulator handle */ const char *name; /* regulator name */ u32 min_vol; /* min voltage level */ @@ -37,10 +68,14 @@ struct bt_power_vreg_data { struct log_index indx; /* Index for reg. w.r.t init & crash */ }; -struct bt_power { +struct pwr_data { char compatible[32]; - struct bt_power_vreg_data *vregs; - int num_vregs; + struct vreg_data *bt_vregs; + int bt_num_vregs; + struct vreg_data *uwb_vregs; + int uwb_num_vregs; + struct vreg_data *platform_vregs; + int platform_num_vregs; }; struct bt_power_clk_data { @@ -52,7 +87,7 @@ struct bt_power_clk_data { /* * Platform data for the bluetooth power driver. */ -struct btpower_platform_data { +struct platform_pwr_data { struct platform_device *pdev; int bt_gpio_sys_rst; /* Bluetooth reset gpio */ int wl_gpio_sys_rst; /* Wlan reset gpio */ @@ -67,14 +102,19 @@ struct btpower_platform_data { int sw_cntrl_gpio; int xo_gpio_clk; /* XO clock gpio*/ struct device *slim_dev; - struct bt_power_vreg_data *vreg_info; /* VDDIO voltage regulator */ + struct vreg_data *bt_vregs; + struct vreg_data *uwb_vregs; + struct vreg_data *platform_vregs; struct bt_power_clk_data *bt_chip_clk; /* bluetooth reference clock */ - int (*bt_power_setup)(int id); /* Bluetooth power setup function */ + int (*power_setup)(int core, int id); /* Bluetooth power setup function */ char compatible[32]; /*Bluetooth SoC name */ - int num_vregs; + int bt_num_vregs; + int uwb_num_vregs; + int platform_num_vregs; struct mbox_client mbox_client_data; struct mbox_chan *mbox_chan; const char *vreg_ipa; + bool is_ganges_dt; int pdc_init_table_len; const char **pdc_init_table; int bt_device_type; @@ -84,12 +124,23 @@ struct btpower_platform_data { struct file *reffilp_obs; struct task_struct *reftask_obs; #endif + struct task_struct *reftask; + struct task_struct *reftask_bt; + struct task_struct *reftask_uwb; + enum power_states power_state; + enum ssr_states sub_state; + enum ssr_states wrkq_signal_state; + struct workqueue_struct *workq; + struct work_struct bt_wq; + struct work_struct uwb_wq; + struct device_node *bt_of_node; + struct device_node *uwb_of_node; }; int btpower_register_slimdev(struct device *dev); int btpower_get_chipset_version(void); -int btpower_aop_mbox_init(struct btpower_platform_data *pdata); -int bt_aop_pdc_reconfig(struct btpower_platform_data *pdata); +int btpower_aop_mbox_init(struct platform_pwr_data *pdata); +int bt_aop_pdc_reconfig(struct platform_pwr_data *pdata); #define WLAN_SW_CTRL_GPIO "qcom,wlan-sw-ctrl-gpio" #define BT_CMD_SLIM_TEST 0xbfac @@ -100,9 +151,11 @@ int bt_aop_pdc_reconfig(struct btpower_platform_data *pdata); #define BT_CMD_GETVAL_POWER_SRCS 0xbfb1 #define BT_CMD_SET_IPA_TCS_INFO 0xbfc0 #define BT_CMD_KERNEL_PANIC 0xbfc1 +#define UWB_CMD_PWR_CTRL 0xbfe1 +#define BT_CMD_REGISTRATION 0xbfe2 +#define UWB_CMD_REGISTRATION 0xbfe3 #ifdef CONFIG_MSM_BT_OOBS -#define BT_CMD_OBS_SIGNAL_TASK 0xbfd0 #define BT_CMD_OBS_VOTE_CLOCK 0xbfd1 /** * enum btpower_obs_param: OOBS low power param diff --git a/pwr/btpower.c b/pwr/btpower.c index 07c3f42bfa..fd6b248ccf 100644 --- a/pwr/btpower.c +++ b/pwr/btpower.c @@ -49,6 +49,15 @@ #define BTPOWER_MBOX_MSG_MAX_LEN 64 #define BTPOWER_MBOX_TIMEOUT_MS 1000 #define XO_CLK_RETRY_COUNT_MAX 5 +#define MAX_PROP_SIZE 32 + +#define SIGIO_OOBS_SINGAL 0x00010000 +#define SIGIO_NOTIFICATION_SIGNAL 0x00020000 +#define SIGIO_GPIO_HIGH 0x00000001 +#define SIGIO_GPIO_LOW 0x00000000 +#define SIGIO_SSR_ON_UWB 0x00000001 +#define SIGIO_UWB_SSR_COMPLETED 0x00000002 + /** * enum btpower_vreg_param: Voltage regulator TCS param * @BTPOWER_VREG_VOLTAGE: Provides voltage level to be configured in TCS @@ -119,7 +128,7 @@ enum power_src_pos { }; // Regulator structure for QCA6174/QCA9377/QCA9379 BT SoC series -static struct bt_power_vreg_data bt_vregs_info_qca61x4_937x[] = { +static struct vreg_data bt_vregs_info_qca61x4_937x[] = { {NULL, "qcom,bt-vdd-aon", 928000, 928000, 0, false, false, {BT_VDD_AON_LDO, BT_VDD_AON_LDO_CURRENT}}, {NULL, "qcom,bt-vdd-io", 1710000, 3460000, 0, false, false, @@ -129,7 +138,7 @@ static struct bt_power_vreg_data bt_vregs_info_qca61x4_937x[] = { }; // Regulator structure for QCA6390,QCA6490 and WCN6750 BT SoC series -static struct bt_power_vreg_data bt_vregs_info_qca6xx0[] = { +static struct vreg_data bt_vregs_info_qca6xx0[] = { {NULL, "qcom,bt-vdd-io", 1800000, 1800000, 0, false, true, {BT_VDD_IO_LDO, BT_VDD_IO_LDO_CURRENT}}, {NULL, "qcom,bt-vdd-aon", 966000, 966000, 0, false, true, @@ -151,15 +160,14 @@ static struct bt_power_vreg_data bt_vregs_info_qca6xx0[] = { {BT_VDD_IPA_2p2, BT_VDD_IPA_2p2_CURRENT}}, }; - // Regulator structure for kiwi BT SoC series -static struct bt_power_vreg_data bt_vregs_info_kiwi[] = { +static struct vreg_data bt_vregs_info_kiwi[] = { {NULL, "qcom,bt-vdd18-aon", 1800000, 1800000, 0, false, true, {BT_VDD_LDO, BT_VDD_LDO_CURRENT}}, {NULL, "qcom,bt-vdd12-io", 1200000, 1200000, 0, false, true, {BT_VDD_IO_LDO, BT_VDD_IO_LDO_CURRENT}}, {NULL, "qcom,bt-vdd-aon", 950000, 950000, 0, false, true, - {BT_VDD_AON_LDO, BT_VDD_AON_LDO_CURRENT}}, + {BT_VDD_AON_LDO, BT_VDD_AON_LDO_CURRENT}}, {NULL, "qcom,bt-vdd-rfaOp8", 950000, 950000, 0, false, true, {BT_VDD_RFACMN, BT_VDD_RFACMN_CURRENT}}, /* BT_CX_MX */ @@ -175,10 +183,30 @@ static struct bt_power_vreg_data bt_vregs_info_kiwi[] = { {BT_VDD_ANT_LDO, BT_VDD_ANT_LDO_CURRENT}}, }; +static struct vreg_data platform_vregs_info_peach[] = { + {NULL, "qcom,bt-vdd18-aon", 1800000, 1800000, 0, false, true, + {BT_VDD_LDO, BT_VDD_LDO_CURRENT}}, + {NULL, "qcom,bt-vdd12-io", 1200000, 1200000, 0, false, true, + {BT_VDD_IO_LDO, BT_VDD_IO_LDO_CURRENT}}, + {NULL, "qcom,bt-ant-ldo", 1776000, 1776000, 0, false, true, + {BT_VDD_ANT_LDO, BT_VDD_ANT_LDO_CURRENT}}, + {NULL, "qcom,bt-vdd-dig", 950000, 950000, 0, false, true, + {BT_VDD_DIG_LDO, BT_VDD_DIG_LDO_CURRENT}}, + {NULL, "qcom,bt-vdd-aon", 950000, 950000, 0, false, true, + {BT_VDD_AON_LDO, BT_VDD_AON_LDO_CURRENT}}, + {NULL, "qcom,bt-vdd-rfaOp8", 950000, 952000, 0, false, true, + {BT_VDD_RFA_0p8, BT_VDD_RFA_0p8_CURRENT}}, + /* BT_CX_MX */ + {NULL, "qcom,bt-vdd-rfa2", 1900000, 1900000, 0, false, true, + {BT_VDD_RFA2_LDO, BT_VDD_RFA2_LDO_CURRENT}}, + {NULL, "qcom,bt-vdd-rfa1", 1350000, 1350000, 0, false, true, + {BT_VDD_RFA1_LDO, BT_VDD_RFA1_LDO_CURRENT}}, +}; + // Regulator structure for WCN399x BT SoC series -static struct bt_power bt_vreg_info_wcn399x = { +static struct pwr_data vreg_info_wcn399x = { .compatible = "qcom,wcn3990", - .vregs = (struct bt_power_vreg_data []) { + .bt_vregs = (struct vreg_data []) { {NULL, "qcom,bt-vdd-smps", 984000, 984000, 0, false, false, {BT_VDD_SMPS, BT_VDD_SMPS_CURRENT}}, {NULL, "qcom,bt-vdd-io", 1700000, 1900000, 0, false, false, @@ -190,79 +218,101 @@ static struct bt_power bt_vreg_info_wcn399x = { {NULL, "qcom,bt-vdd-xtal", 1700000, 1900000, 0, false, false, {BT_VDD_XTAL_LDO, BT_VDD_XTAL_LDO_CURRENT}}, }, - .num_vregs = 5, + .bt_num_vregs = 5, }; -static struct bt_power bt_vreg_info_qca6174 = { +static struct pwr_data vreg_info_qca6174 = { .compatible = "qcom,qca6174", - .vregs = bt_vregs_info_qca61x4_937x, - .num_vregs = ARRAY_SIZE(bt_vregs_info_qca61x4_937x), + .bt_vregs = bt_vregs_info_qca61x4_937x, + .bt_num_vregs = ARRAY_SIZE(bt_vregs_info_qca61x4_937x), }; -static struct bt_power bt_vreg_info_qca6390 = { +static struct pwr_data vreg_info_qca6390 = { .compatible = "qcom,qca6390", - .vregs = bt_vregs_info_qca6xx0, - .num_vregs = ARRAY_SIZE(bt_vregs_info_qca6xx0), + .bt_vregs = bt_vregs_info_qca6xx0, + .bt_num_vregs = ARRAY_SIZE(bt_vregs_info_qca6xx0), }; -static struct bt_power bt_vreg_info_qca6490 = { +static struct pwr_data vreg_info_qca6490 = { .compatible = "qcom,qca6490", - .vregs = bt_vregs_info_qca6xx0, - .num_vregs = ARRAY_SIZE(bt_vregs_info_qca6xx0), + .bt_vregs = bt_vregs_info_qca6xx0, + .bt_num_vregs = ARRAY_SIZE(bt_vregs_info_qca6xx0), }; -static struct bt_power bt_vreg_info_kiwi = { +static struct pwr_data vreg_info_kiwi = { .compatible = "qcom,kiwi", - .vregs = bt_vregs_info_kiwi, - .num_vregs = ARRAY_SIZE(bt_vregs_info_kiwi), + .bt_vregs = bt_vregs_info_kiwi, + .bt_num_vregs = ARRAY_SIZE(bt_vregs_info_kiwi), }; -static struct bt_power bt_vreg_info_kiwi_no_share_ant_power = { +static struct pwr_data vreg_info_kiwi_no_share_ant_power = { .compatible = "qcom,kiwi-no-share-ant-power", - .vregs = bt_vregs_info_kiwi, - .num_vregs = ARRAY_SIZE(bt_vregs_info_kiwi), + .bt_vregs = bt_vregs_info_kiwi, + .bt_num_vregs = ARRAY_SIZE(bt_vregs_info_kiwi), }; -static struct bt_power bt_vreg_info_converged = { +static struct pwr_data vreg_info_converged = { .compatible = "qcom,bt-qca-converged", - .vregs = bt_vregs_info_kiwi, - .num_vregs = ARRAY_SIZE(bt_vregs_info_kiwi), + .bt_vregs = bt_vregs_info_kiwi, + .bt_num_vregs = ARRAY_SIZE(bt_vregs_info_kiwi), }; -static struct bt_power bt_vreg_info_wcn6750 = { +static struct pwr_data vreg_info_wcn6750 = { .compatible = "qcom,wcn6750-bt", - .vregs = bt_vregs_info_qca6xx0, - .num_vregs = ARRAY_SIZE(bt_vregs_info_qca6xx0), + .bt_vregs = bt_vregs_info_qca6xx0, + .bt_num_vregs = ARRAY_SIZE(bt_vregs_info_qca6xx0), +}; + +/* Kiwi supports both BT & UWB SS. For now it requires + * only platform regulators to be powered ON. + */ +static struct pwr_data vreg_info_peach = { + .compatible = "qcom,peach-bt", + .platform_vregs = platform_vregs_info_peach, + .platform_num_vregs = ARRAY_SIZE(platform_vregs_info_peach), }; static const struct of_device_id bt_power_match_table[] = { - { .compatible = "qcom,qca6174", .data = &bt_vreg_info_qca6174}, - { .compatible = "qcom,wcn3990", .data = &bt_vreg_info_wcn399x}, - { .compatible = "qcom,qca6390", .data = &bt_vreg_info_qca6390}, - { .compatible = "qcom,qca6490", .data = &bt_vreg_info_qca6490}, - { .compatible = "qcom,kiwi", .data = &bt_vreg_info_kiwi}, + { .compatible = "qcom,qca6174", .data = &vreg_info_qca6174}, + { .compatible = "qcom,wcn3990", .data = &vreg_info_wcn399x}, + { .compatible = "qcom,qca6390", .data = &vreg_info_qca6390}, + { .compatible = "qcom,qca6490", .data = &vreg_info_qca6490}, + { .compatible = "qcom,kiwi", .data = &vreg_info_kiwi}, { .compatible = "qcom,kiwi-no-share-ant-power", - .data = &bt_vreg_info_kiwi_no_share_ant_power}, - { .compatible = "qcom,wcn6750-bt", .data = &bt_vreg_info_wcn6750}, - { .compatible = "qcom,bt-qca-converged", .data = &bt_vreg_info_converged}, + .data = &vreg_info_kiwi_no_share_ant_power}, + { .compatible = "qcom,wcn6750-bt", .data = &vreg_info_wcn6750}, + { .compatible = "qcom,bt-qca-converged", .data = &vreg_info_converged}, + { .compatible = "qcom,peach-bt", .data = &vreg_info_peach}, {}, }; -static int bt_power_vreg_set(enum bt_power_modes mode); -static int btpower_enable_ipa_vreg(struct btpower_platform_data *pdata); - -static int bt_power_src_status[BT_POWER_SRC_SIZE]; -static struct btpower_platform_data *bt_power_pdata; +static int btpower_enable_ipa_vreg(struct platform_pwr_data *pdata); +static struct platform_pwr_data *pwr_data; static bool previous; static int pwr_state; static struct class *bt_class; static int bt_major; static int soc_id; static bool probe_finished; +const struct pwr_data *data; +char *bt_arg[20] = {"power off BT", "power on BT", "BT power retention"}; +char *uwb_arg[20] = {"power off UWB", "power on UWB", "UWB power retention"}; +char *pwr_states[40] = {"Both Sub-System powered OFF", "BT powered ON", + "UWB powered ON", "Both Sub-System powered ON"}; +char *ssr_state[40] = {"No SSR on Sub-Sytem", "SSR on BT", + "SSR Completed on BT", "SSR on UWB", + "SSR Completed on UWB"}; +char *reg_mode[25] = {"vote off", "vote on", "vote for retention"}; + +static struct { + int platform_state[BT_POWER_SRC_SIZE]; + int bt_state[BT_POWER_SRC_SIZE]; + int uwb_state[BT_POWER_SRC_SIZE]; +} power_src; #ifdef CONFIG_BT_HW_SECURE_DISABLE -int perisec_cnss_bt_hw_disable_check(struct btpower_platform_data *plat_priv) +int perisec_cnss_bt_hw_disable_check(struct platform_pwr_data *plat_priv) { struct Object client_env; struct Object app_object; @@ -323,7 +373,7 @@ end: return ret; } #else -int perisec_cnss_bt_hw_disable_check(struct btpower_platform_data *plat_priv) +int perisec_cnss_bt_hw_disable_check(struct platform_pwr_data *plat_priv) { return 0; } @@ -331,7 +381,7 @@ int perisec_cnss_bt_hw_disable_check(struct btpower_platform_data *plat_priv) #ifdef CONFIG_MSM_BT_OOBS -static void btpower_uart_transport_locked(struct btpower_platform_data *drvdata, +static void btpower_uart_transport_locked(struct platform_pwr_data *drvdata, bool locked) { pr_debug("%s: %s\n", __func__, (locked ? "busy" : "idle")); @@ -339,15 +389,16 @@ static void btpower_uart_transport_locked(struct btpower_platform_data *drvdata, static irqreturn_t btpower_host_wake_isr(int irq, void *data) { - struct btpower_platform_data *drvdata = data; - int host_waking = gpio_get_value(drvdata->bt_gpio_host_wake); + struct platform_pwr_data *drvdata = data; struct kernel_siginfo siginfo; + int host_waking = (SIGIO_OOBS_SINGAL | + gpio_get_value(drvdata->bt_gpio_host_wake)); int rc = 0; pr_debug("%s: bt-hostwake-gpio(%d) IRQ(%d) value(%d)\n", __func__, drvdata->bt_gpio_host_wake, drvdata->irq, host_waking); - if (drvdata->reftask_obs == NULL) { + if (drvdata->reftask_bt == NULL) { pr_info("%s: ignore BT-HOSTWAKE IRQ\n", __func__); return IRQ_HANDLED; } @@ -357,16 +408,16 @@ static irqreturn_t btpower_host_wake_isr(int irq, void *data) siginfo.si_signo = SIGIO; siginfo.si_code = SI_QUEUE; siginfo.si_int = host_waking; - rc = send_sig_info(siginfo.si_signo, &siginfo, drvdata->reftask_obs); + rc = send_sig_info(siginfo.si_signo, &siginfo, drvdata->reftask_bt); if (rc < 0) { pr_err("%s: failed (%d) to send SIG to HAL(%d)\n", __func__, - rc, drvdata->reftask_obs->pid); + rc, drvdata->reftask_bt->pid); } return IRQ_HANDLED; } #endif -static int bt_vreg_enable(struct bt_power_vreg_data *vreg) +static int vreg_enable(struct vreg_data *vreg) { int rc = 0; @@ -406,7 +457,7 @@ out: return rc; } -static int bt_vreg_enable_retention(struct bt_power_vreg_data *vreg) +static int vreg_enable_retention(struct vreg_data *vreg) { int rc = 0; @@ -437,7 +488,7 @@ out: return rc; } -static int bt_vreg_disable(struct bt_power_vreg_data *vreg) +static int vreg_disable(struct vreg_data *vreg) { int rc = 0; @@ -521,7 +572,7 @@ static int bt_clk_disable(struct bt_power_clk_data *clk) static void btpower_set_xo_clk_gpio_state(bool enable) { - int xo_clk_gpio = bt_power_pdata->xo_gpio_clk; + int xo_clk_gpio = pwr_data->xo_gpio_clk; int retry = 0; int rc = 0; @@ -562,8 +613,8 @@ retry_gpio_req: #ifdef CONFIG_MSM_BT_OOBS void bt_configure_wakeup_gpios(int on) { - int bt_gpio_dev_wake = bt_power_pdata->bt_gpio_dev_wake; - int bt_host_wake_gpio = bt_power_pdata->bt_gpio_host_wake; + int bt_gpio_dev_wake = pwr_data->bt_gpio_dev_wake; + int bt_host_wake_gpio = pwr_data->bt_gpio_host_wake; int rc; if (on) { @@ -574,14 +625,14 @@ void bt_configure_wakeup_gpios(int on) } if (gpio_is_valid(bt_host_wake_gpio)) { - bt_power_pdata->irq = gpio_to_irq(bt_host_wake_gpio); + pwr_data->irq = gpio_to_irq(bt_host_wake_gpio); pr_debug("%s: BT-ON bt-host_wake-gpio(%d) IRQ(%d)\n", - __func__, bt_host_wake_gpio, bt_power_pdata->irq); - rc = request_irq(bt_power_pdata->irq, + __func__, bt_host_wake_gpio, pwr_data->irq); + rc = request_irq(pwr_data->irq, btpower_host_wake_isr, IRQF_TRIGGER_FALLING | IRQF_TRIGGER_RISING, - "btpower_hostwake_isr", bt_power_pdata); + "btpower_hostwake_isr", pwr_data); if (rc) pr_err("%s: unable to request IRQ %d (%d)\n", __func__, bt_host_wake_gpio, rc); @@ -589,9 +640,9 @@ void bt_configure_wakeup_gpios(int on) } else { if (gpio_is_valid(bt_host_wake_gpio)) { pr_debug("%s: BT-OFF bt-hostwake-gpio(%d) IRQ(%d) value(%d)\n", - __func__, bt_host_wake_gpio, bt_power_pdata->irq, + __func__, bt_host_wake_gpio, pwr_data->irq, gpio_get_value(bt_host_wake_gpio)); - free_irq(bt_power_pdata->irq, bt_power_pdata); + free_irq(pwr_data->irq, pwr_data); } if (gpio_is_valid(bt_gpio_dev_wake)) @@ -603,10 +654,10 @@ void bt_configure_wakeup_gpios(int on) static int bt_configure_gpios(int on) { int rc = 0; - int bt_reset_gpio = bt_power_pdata->bt_gpio_sys_rst; - int wl_reset_gpio = bt_power_pdata->wl_gpio_sys_rst; - int bt_sw_ctrl_gpio = bt_power_pdata->bt_gpio_sw_ctrl; - int bt_debug_gpio = bt_power_pdata->bt_gpio_debug; + int bt_reset_gpio = pwr_data->bt_gpio_sys_rst; + int wl_reset_gpio = pwr_data->wl_gpio_sys_rst; + int bt_sw_ctrl_gpio = pwr_data->bt_gpio_sw_ctrl; + int bt_debug_gpio = pwr_data->bt_gpio_debug; int assert_dbg_gpio = 0; if (on) { @@ -625,7 +676,7 @@ static int bt_configure_gpios(int on) pr_err("%s: Unable to set direction\n", __func__); return rc; } - bt_power_src_status[BT_RESET_GPIO] = + power_src.platform_state[BT_RESET_GPIO] = gpio_get_value(bt_reset_gpio); msleep(50); pr_info("BTON:Turn Bt OFF post asserting BT_EN to low\n"); @@ -633,9 +684,9 @@ static int bt_configure_gpios(int on) gpio_get_value(bt_reset_gpio)); if (bt_sw_ctrl_gpio >= 0) { - bt_power_src_status[BT_SW_CTRL_GPIO] = + power_src.platform_state[BT_SW_CTRL_GPIO] = gpio_get_value(bt_sw_ctrl_gpio); - rc = msm_gpio_mpm_wake_set(bt_power_pdata->sw_cntrl_gpio, 1); + rc = msm_gpio_mpm_wake_set(pwr_data->sw_cntrl_gpio, 1); if (rc < 0) { pr_err("Failed to set msm_gpio_mpm_wake_set for sw_cntrl gpio, ret: %d\n", rc); @@ -645,7 +696,7 @@ static int bt_configure_gpios(int on) } pr_info("BTON:Turn Bt OFF bt-sw-ctrl-gpio(%d) value(%d)\n", bt_sw_ctrl_gpio, - bt_power_src_status[BT_SW_CTRL_GPIO]); + power_src.platform_state[BT_SW_CTRL_GPIO]); } if (wl_reset_gpio >= 0) pr_info("BTON:Turn Bt ON wl-reset-gpio(%d) value(%d)\n", @@ -661,7 +712,7 @@ static int bt_configure_gpios(int on) pr_err("%s: Unable to set direction\n", __func__); return rc; } - bt_power_src_status[BT_RESET_GPIO] = + power_src.platform_state[BT_RESET_GPIO] = gpio_get_value(bt_reset_gpio); btpower_set_xo_clk_gpio_state(false); } @@ -675,7 +726,7 @@ static int bt_configure_gpios(int on) __func__); return rc; } - bt_power_src_status[BT_RESET_GPIO] = + power_src.platform_state[BT_RESET_GPIO] = gpio_get_value(bt_reset_gpio); } pr_info("BTON: WLAN OFF waiting for 100ms delay\n"); @@ -683,12 +734,13 @@ static int bt_configure_gpios(int on) msleep(100); pr_info("BTON: WLAN OFF Asserting BT_EN to high\n"); btpower_set_xo_clk_gpio_state(true); + rc = gpio_direction_output(bt_reset_gpio, 1); if (rc) { pr_err("%s: Unable to set direction\n", __func__); return rc; } - bt_power_src_status[BT_RESET_GPIO] = + power_src.platform_state[BT_RESET_GPIO] = gpio_get_value(bt_reset_gpio); btpower_set_xo_clk_gpio_state(false); } @@ -705,7 +757,7 @@ static int bt_configure_gpios(int on) pr_err("%s: Unable to set direction\n", __func__); return rc; } - bt_power_src_status[BT_RESET_GPIO] = + power_src.platform_state[BT_RESET_GPIO] = gpio_get_value(bt_reset_gpio); btpower_set_xo_clk_gpio_state(false); } @@ -736,14 +788,14 @@ static int bt_configure_gpios(int on) __func__); } } - pr_info("BTON:Turn Bt On bt-reset-gpio(%d) value(%d)\n", + pr_info("BTON: Turn BT ON bt-reset-gpio(%d) value(%d)\n", bt_reset_gpio, gpio_get_value(bt_reset_gpio)); if (bt_sw_ctrl_gpio >= 0) { - bt_power_src_status[BT_SW_CTRL_GPIO] = + power_src.platform_state[BT_SW_CTRL_GPIO] = gpio_get_value(bt_sw_ctrl_gpio); pr_info("BTON: Turn BT ON bt-sw-ctrl-gpio(%d) value(%d)\n", bt_sw_ctrl_gpio, - bt_power_src_status[BT_SW_CTRL_GPIO]); + power_src.platform_state[BT_SW_CTRL_GPIO]); } } else { #ifdef CONFIG_MSM_BT_OOBS @@ -765,88 +817,276 @@ static int bt_configure_gpios(int on) return rc; } -static int bluetooth_power(int on) +static int bt_regulators_pwr(int pwr_state) { - int rc = 0; + int i, log_indx, bt_num_vregs, rc = 0; + struct vreg_data *bt_vregs = NULL; - pr_info("%s: on: %d\n", __func__, on); + rc = perisec_cnss_bt_hw_disable_check(pwr_data); - rc = perisec_cnss_bt_hw_disable_check(bt_power_pdata); - if (on == 1) { - if (bt_power_pdata->bt_sec_hw_disable) { + bt_num_vregs = pwr_data->bt_num_vregs; + + if (!bt_num_vregs) { + pr_warn("%s: not avilable to %s\n", + __func__, reg_mode[pwr_state]); + return 0; + } + + pr_info("%s: %s\n", __func__, reg_mode[pwr_state]); + + if (pwr_state == POWER_ENABLE) { + /* Power On */ + if (pwr_data->bt_sec_hw_disable) { pr_err("%s:secure hw mode on,BT ON not allowed", __func__); return -EINVAL; } - rc = bt_power_vreg_set(BT_POWER_ENABLE); - if (rc < 0) { - pr_err("%s: bt_power regulators config failed\n", - __func__); - goto regulator_fail; + + for (i = 0; i < bt_num_vregs; i++) { + bt_vregs = &pwr_data->bt_vregs[i]; + log_indx = bt_vregs->indx.init; + if (bt_vregs->reg) { + power_src.bt_state[log_indx] = DEFAULT_INVALID_VALUE; + rc = vreg_enable(bt_vregs); + if (rc < 0) { + pr_err("%s: bt_power regulators config failed\n", + __func__); + goto regulator_fail; + } + if (bt_vregs->is_enabled) + power_src.bt_state[log_indx] = + regulator_get_voltage(bt_vregs->reg); + } } + /* Parse dt_info and check if a target requires clock voting. * Enable BT clock when BT is on and disable it when BT is off */ - if (bt_power_pdata->bt_chip_clk) { - rc = bt_clk_enable(bt_power_pdata->bt_chip_clk); + if (pwr_data->bt_chip_clk) { + rc = bt_clk_enable(pwr_data->bt_chip_clk); if (rc < 0) { pr_err("%s: bt_power gpio config failed\n", __func__); goto clk_fail; } } - if (bt_power_pdata->bt_gpio_sys_rst > 0) { - bt_power_src_status[BT_RESET_GPIO] = - DEFAULT_INVALID_VALUE; - bt_power_src_status[BT_SW_CTRL_GPIO] = - DEFAULT_INVALID_VALUE; - rc = bt_configure_gpios(on); + if (pwr_data->bt_gpio_sys_rst > 0) { + power_src.bt_state[BT_RESET_GPIO] = DEFAULT_INVALID_VALUE; + power_src.bt_state[BT_SW_CTRL_GPIO] = DEFAULT_INVALID_VALUE; + rc = bt_configure_gpios(POWER_ENABLE); if (rc < 0) { pr_err("%s: bt_power gpio config failed\n", __func__); goto gpio_fail; } } - } else if (on == 0) { - // Power Off - if (bt_power_pdata->bt_gpio_sys_rst > 0) { - if (bt_power_pdata->bt_sec_hw_disable) { + } else if (pwr_state == POWER_DISABLE) { + /* Power Off */ + if (pwr_data->bt_gpio_sys_rst > 0) { + if (pwr_data->bt_sec_hw_disable) { pr_err("%s: secure hw mode on, not allowed to access gpio", __func__); }else { - bt_configure_gpios(on); + bt_configure_gpios(POWER_DISABLE); } } gpio_fail: - if (bt_power_pdata->bt_gpio_sys_rst > 0) - gpio_free(bt_power_pdata->bt_gpio_sys_rst); - if (bt_power_pdata->bt_gpio_debug > 0) - gpio_free(bt_power_pdata->bt_gpio_debug); - if (bt_power_pdata->bt_chip_clk) - bt_clk_disable(bt_power_pdata->bt_chip_clk); + if (pwr_data->bt_gpio_sys_rst > 0) + gpio_free(pwr_data->bt_gpio_sys_rst); + if (pwr_data->bt_gpio_debug > 0) + gpio_free(pwr_data->bt_gpio_debug); + if (pwr_data->bt_chip_clk) + bt_clk_disable(pwr_data->bt_chip_clk); clk_fail: regulator_fail: - bt_power_vreg_set(BT_POWER_DISABLE); - } else if (on == 2) { + for (i = 0; i < bt_num_vregs; i++) { + bt_vregs = &pwr_data->bt_vregs[i]; + rc = vreg_disable(bt_vregs); + } + } else if (pwr_state == POWER_RETENTION) { /* Retention mode */ - bt_power_vreg_set(BT_POWER_RETENTION); + for (i = 0; i < bt_num_vregs; i++) { + bt_vregs = &pwr_data->bt_vregs[i]; + rc = vreg_enable_retention(bt_vregs); + } } else { - pr_err("%s: Invalid power mode: %d\n", __func__, on); + pr_err("%s: Invalid power mode: %d\n", __func__, pwr_state); rc = -1; } return rc; } +static int uwb_regulators_pwr(int pwr_state) +{ + int i, log_indx, uwb_num_vregs, rc = 0; + struct vreg_data *uwb_vregs = NULL; + + rc = perisec_cnss_bt_hw_disable_check(pwr_data); + + uwb_num_vregs = pwr_data->uwb_num_vregs; + + if (!uwb_num_vregs) { + pr_warn("%s: not avilable to %s\n", + __func__, reg_mode[pwr_state]); + return 0; + } + + pr_info("%s: %s\n", __func__, reg_mode[pwr_state]); + + switch (pwr_state) { + case POWER_ENABLE: + for (i = 0; i < uwb_num_vregs; i++) { + uwb_vregs = &pwr_data->uwb_vregs[i]; + log_indx = uwb_vregs->indx.init; + if (uwb_vregs->reg) { + power_src.uwb_state[log_indx] = DEFAULT_INVALID_VALUE; + rc = vreg_enable(uwb_vregs); + if (rc < 0) { + pr_err("%s: UWB regulators config failed\n", + __func__); + goto regulator_failed; + } + if (uwb_vregs->is_enabled) { + power_src.uwb_state[log_indx] = + regulator_get_voltage(uwb_vregs->reg); + } + } + } + break; + case POWER_DISABLE: +regulator_failed: + for (i = 0; i < uwb_num_vregs; i++) { + uwb_vregs = &pwr_data->uwb_vregs[i]; + rc = vreg_disable(uwb_vregs); + } + break; + case POWER_RETENTION: + for (i = 0; i < uwb_num_vregs; i++) { + uwb_vregs = &pwr_data->uwb_vregs[i]; + rc = vreg_enable_retention(uwb_vregs); + } + break; + } + return rc; +} + +static int platform_regulators_pwr(int pwr_state) +{ + int i, log_indx, platform_num_vregs, rc = 0; + struct vreg_data *platform_vregs = NULL; + + rc = perisec_cnss_bt_hw_disable_check(pwr_data); + + platform_num_vregs = pwr_data->platform_num_vregs; + + if (!platform_num_vregs) { + pr_warn("%s: not available to %s\n", + __func__, reg_mode[pwr_state]); + return 0; + } + + pr_info("%s: %s\n", __func__, reg_mode[pwr_state]); + + switch (pwr_state) { + case POWER_ENABLE: + for (i = 0; i < platform_num_vregs; i++) { + platform_vregs = &pwr_data->platform_vregs[i]; + log_indx = platform_vregs->indx.init; + if (platform_vregs->reg) { + power_src.platform_state[log_indx] = DEFAULT_INVALID_VALUE; + rc = vreg_enable(platform_vregs); + if (rc < 0) { + pr_err("%s: Platform regulators config failed\n", + __func__); + goto regulator_failed; + } + if (platform_vregs->is_enabled) + power_src.platform_state[log_indx] = + regulator_get_voltage(platform_vregs->reg); + } + } + rc = bt_configure_gpios(POWER_ENABLE); + if (rc < 0) { + pr_err("%s: bt_power gpio config failed\n", + __func__); + goto gpio_failed; + } + break; + case POWER_DISABLE: + rc = bt_configure_gpios(POWER_DISABLE); + if (rc < 0) { + pr_err("%s: bt_power gpio config failed\n", + __func__); + } +gpio_failed: + if (pwr_data->bt_gpio_sys_rst > 0) + gpio_free(pwr_data->bt_gpio_sys_rst); + if (pwr_data->bt_gpio_debug > 0) + gpio_free(pwr_data->bt_gpio_debug); +regulator_failed: + for (i = 0; i < platform_num_vregs; i++) { + platform_vregs = &pwr_data->platform_vregs[i]; + rc = vreg_disable(platform_vregs); + } + break; + case POWER_RETENTION: + for (i = 0; i < platform_num_vregs; i++) { + platform_vregs = &pwr_data->platform_vregs[i]; + rc = vreg_enable_retention(platform_vregs); + } + break; + } + return rc; +} + +static int power_regulators(int core_type, int mode) +{ + int ret = 0; + + if ((mode != POWER_DISABLE) && (mode != POWER_ENABLE) && + (mode != POWER_RETENTION)) { + pr_err("%s: Received wrong Mode to do regulator operation\n", + __func__); + return -1; + } + + switch (core_type) { + case BT_CORE: + ret = bt_regulators_pwr(mode); + if (ret) + pr_err("%s: Failed to configure BT regulators to mode(%d)\n", + __func__, mode); + break; + case UWB_CORE: + ret = uwb_regulators_pwr(mode); + if (ret) + pr_err("%s: Failed to configure UWB regulators to mode(%d)\n", + __func__, mode); + break; + case PLATFORM_CORE: + ret = platform_regulators_pwr(mode); + if (ret) + pr_err("%s: Failed to configure platform regulators to mode(%d)\n", + __func__, mode); + break; + default: + pr_err("%s: Received wrong Core Type to do regulator operation\n", + __func__); + return -1; + } + return ret; +} + static int btpower_toggle_radio(void *data, bool blocked) { int ret = 0; - int (*power_control)(int enable); + int (*power_control)(int Core, int enable); power_control = - ((struct btpower_platform_data *)data)->bt_power_setup; + ((struct platform_pwr_data *)data)->power_setup; if (previous != blocked) - ret = (*power_control)(!blocked); + ret = (*power_control)(BT_CORE, !blocked); if (!ret) previous = blocked; return ret; @@ -912,18 +1152,18 @@ static void btpower_rfkill_remove(struct platform_device *pdev) platform_set_drvdata(pdev, NULL); } -#define MAX_PROP_SIZE 32 -static int bt_dt_parse_vreg_info(struct device *dev, - struct bt_power_vreg_data *vreg_data) +static int dt_parse_vreg_info(struct device *dev, struct device_node *child, + struct vreg_data *vreg_data) { int len, ret = 0; const __be32 *prop; char prop_name[MAX_PROP_SIZE]; - struct bt_power_vreg_data *vreg = vreg_data; - struct device_node *np = dev->of_node; + struct vreg_data *vreg = vreg_data; + struct device_node *np = child; const char *vreg_name = vreg_data->name; - pr_debug("%s: vreg dev tree parse for %s\n", __func__, vreg_name); + if (!child) + np = dev->of_node; snprintf(prop_name, sizeof(prop_name), "%s-supply", vreg_name); if (of_parse_phandle(np, prop_name, 0)) { @@ -937,7 +1177,7 @@ static int bt_dt_parse_vreg_info(struct device *dev, } snprintf(prop_name, sizeof(prop_name), "%s-config", vreg->name); - prop = of_get_property(dev->of_node, prop_name, &len); + prop = of_get_property(np, prop_name, &len); if (!prop || len != (4 * sizeof(__be32))) { pr_debug("%s: Property %s %s, use default\n", __func__, prop_name, @@ -956,7 +1196,6 @@ static int bt_dt_parse_vreg_info(struct device *dev, pr_info("%s: %s is not provided in device tree\n", __func__, vreg_name); } - return ret; } @@ -1007,166 +1246,170 @@ err: return ret; } -static int bt_power_vreg_get(struct platform_device *pdev) +static void bt_power_vreg_put(void) { - int num_vregs, i = 0, ret = 0; - const struct bt_power *data; + int i = 0; + struct vreg_data *bt_vregs = NULL; + int bt_num_vregs = pwr_data->bt_num_vregs; + + for (; i < bt_num_vregs; i++) { + bt_vregs = &pwr_data->bt_vregs[i]; + if (bt_vregs->reg) + regulator_put(bt_vregs->reg); + } +} + +static int get_gpio_dt_pinfo(struct platform_device *pdev) +{ + int ret; + struct device_node *child; + + child = pdev->dev.of_node; + + pwr_data->bt_gpio_sys_rst = + of_get_named_gpio(child, + "qcom,bt-reset-gpio", 0); + if (pwr_data->bt_gpio_sys_rst < 0) + pr_warn("bt-reset-gpio not provided in devicetree\n"); + + pwr_data->wl_gpio_sys_rst = + of_get_named_gpio(child, + "qcom,wl-reset-gpio", 0); + if (pwr_data->wl_gpio_sys_rst < 0) + pr_err("%s: wl-reset-gpio not provided in device tree\n", + __func__); + + pwr_data->bt_gpio_sw_ctrl = + of_get_named_gpio(child, + "qcom,bt-sw-ctrl-gpio", 0); + if (pwr_data->bt_gpio_sw_ctrl < 0) + pr_warn("bt-sw-ctrl-gpio not provided in devicetree\n"); + + + ret = of_property_read_u32(child, "mpm_wake_set_gpios", + &pwr_data->sw_cntrl_gpio); + if (ret) + pr_warn("sw_cntrl-gpio not provided in devicetree\n"); + + pwr_data->bt_gpio_debug = of_get_named_gpio(child, + "qcom,bt-debug-gpio", 0); + if (pwr_data->bt_gpio_debug < 0) + pr_warn("bt-debug-gpio not provided in devicetree\n"); + + pwr_data->xo_gpio_clk = + of_get_named_gpio(child, + "qcom,xo-clk-gpio", 0); + if (pwr_data->xo_gpio_clk < 0) + pr_warn("xo-clk-gpio not provided in devicetree\n"); + +#ifdef CONFIG_MSM_BT_OOBS + pwr_data->bt_gpio_dev_wake = + of_get_named_gpio(child, + "qcom,btwake_gpio", 0); + if (pwr_data->bt_gpio_dev_wake < 0) + pr_warn("%s: btwake-gpio not provided in device tree\n", + __func__); + + pwr_data->bt_gpio_host_wake = + of_get_named_gpio(child, + "qcom,bthostwake_gpio", 0); + if (pwr_data->bt_gpio_host_wake < 0) + pr_warn("%s: bthostwake_gpio not provided in device tree\n", + __func__); +#endif + return true; +} + +static int get_power_dt_pinfo(struct platform_device *pdev) +{ + int rc, i; data = of_device_get_match_data(&pdev->dev); + if (!data) { pr_err("%s: failed to get dev node\n", __func__); return -EINVAL; } - memcpy(&bt_power_pdata->compatible, &data->compatible, MAX_PROP_SIZE); - bt_power_pdata->vreg_info = data->vregs; - num_vregs = bt_power_pdata->num_vregs = data->num_vregs; - for (; i < num_vregs; i++) { - ret = bt_dt_parse_vreg_info(&(pdev->dev), - &bt_power_pdata->vreg_info[i]); - /* No point to go further if failed to get regulator handler */ - if (ret) - break; - } + memcpy(&pwr_data->compatible, &data->compatible, MAX_PROP_SIZE); + pwr_data->bt_vregs = data->bt_vregs; + pwr_data->bt_num_vregs = data->bt_num_vregs; - return ret; -} + if (pwr_data->is_ganges_dt) { + pwr_data->uwb_vregs = data->uwb_vregs; + pwr_data->platform_vregs = data->platform_vregs; + pwr_data->uwb_num_vregs = data->uwb_num_vregs; + pwr_data->platform_num_vregs = data->platform_num_vregs; -static int bt_power_vreg_set(enum bt_power_modes mode) -{ - int num_vregs, i = 0, ret = 0; - int log_indx; - struct bt_power_vreg_data *vreg_info = NULL; - - num_vregs = bt_power_pdata->num_vregs; - if (mode == BT_POWER_ENABLE) { - for (; i < num_vregs; i++) { - vreg_info = &bt_power_pdata->vreg_info[i]; - log_indx = vreg_info->indx.init; - if (vreg_info->reg) { - bt_power_src_status[log_indx] = - DEFAULT_INVALID_VALUE; - ret = bt_vreg_enable(vreg_info); - if (ret < 0) - goto out; - if (vreg_info->is_enabled) { - bt_power_src_status[log_indx] = - regulator_get_voltage( - vreg_info->reg); - } - } - } - } else if (mode == BT_POWER_DISABLE) { - for (; i < num_vregs; i++) { - vreg_info = &bt_power_pdata->vreg_info[i]; - ret = bt_vreg_disable(vreg_info); - } - } else if (mode == BT_POWER_RETENTION) { - for (; i < num_vregs; i++) { - vreg_info = &bt_power_pdata->vreg_info[i]; - ret = bt_vreg_enable_retention(vreg_info); - } + pr_info("%s: bt_num_vregs =%d uwb_num_vregs =%d platform_num_vregs=%d\n", + __func__, pwr_data->bt_num_vregs, pwr_data->uwb_num_vregs, + pwr_data->platform_num_vregs); } else { - pr_err("%s: Invalid power mode: %d\n", __func__, mode); - ret = -1; + pr_info("%s: bt_num_vregs =%d\n", __func__, pwr_data->bt_num_vregs); } -out: - return ret; -} - -static void bt_power_vreg_put(void) -{ - int i = 0; - struct bt_power_vreg_data *vreg_info = NULL; - int num_vregs = bt_power_pdata->num_vregs; - - for (; i < num_vregs; i++) { - vreg_info = &bt_power_pdata->vreg_info[i]; - if (vreg_info->reg) - regulator_put(vreg_info->reg); + for (i = 0; i < pwr_data->bt_num_vregs; i++) { + rc = dt_parse_vreg_info(&(pdev->dev), pwr_data->bt_of_node, + &pwr_data->bt_vregs[i]); + /* No point to go further if failed to get regulator handler */ + if (rc) + return rc; } + + if (pwr_data->is_ganges_dt) { + for (i = 0; i < pwr_data->platform_num_vregs; i++) { + rc = dt_parse_vreg_info(&(pdev->dev), NULL, + &pwr_data->platform_vregs[i]); + /* No point to go further if failed to get regulator handler */ + if (rc) + return rc; + } + + for (i = 0; i < pwr_data->uwb_num_vregs; i++) { + rc = dt_parse_vreg_info(&(pdev->dev), pwr_data->uwb_of_node, + &pwr_data->uwb_vregs[i]); + /* No point to go further if failed to get regulator handler */ + if (rc) + return rc; + } + } + return rc; } static int bt_power_populate_dt_pinfo(struct platform_device *pdev) { + struct device_node *of_node; int rc; - pr_debug("%s\n", __func__); - if (!bt_power_pdata) + if (!pwr_data) return -ENOMEM; - if (pdev->dev.of_node) { - rc = bt_power_vreg_get(pdev); - if (rc) - return rc; - - bt_power_pdata->bt_gpio_sys_rst = - of_get_named_gpio(pdev->dev.of_node, - "qcom,bt-reset-gpio", 0); - if (bt_power_pdata->bt_gpio_sys_rst < 0) - pr_warn("bt-reset-gpio not provided in devicetree\n"); - - bt_power_pdata->wl_gpio_sys_rst = - of_get_named_gpio(pdev->dev.of_node, - "qcom,wl-reset-gpio", 0); - if (bt_power_pdata->wl_gpio_sys_rst < 0) - pr_err("%s: wl-reset-gpio not provided in device tree\n", - __func__); - - - bt_power_pdata->bt_gpio_sw_ctrl = - of_get_named_gpio(pdev->dev.of_node, - "qcom,bt-sw-ctrl-gpio", 0); - if (bt_power_pdata->bt_gpio_sw_ctrl < 0) - pr_warn("bt-sw-ctrl-gpio not provided in devicetree\n"); - - rc = of_property_read_u32(pdev->dev.of_node, - "mpm_wake_set_gpios",&bt_power_pdata->sw_cntrl_gpio); - if (rc) - pr_warn("sw_cntrl-gpio not provided in devicetree\n"); - - bt_power_pdata->bt_gpio_debug = - of_get_named_gpio(pdev->dev.of_node, - "qcom,bt-debug-gpio", 0); - if (bt_power_pdata->bt_gpio_debug < 0) - pr_warn("bt-debug-gpio not provided in devicetree\n"); - - bt_power_pdata->xo_gpio_clk = - of_get_named_gpio(pdev->dev.of_node, - "qcom,xo-clk-gpio", 0); - if (bt_power_pdata->xo_gpio_clk < 0) - pr_warn("xo-clk-gpio not provided in devicetree\n"); - - rc = bt_dt_parse_clk_info(&pdev->dev, - &bt_power_pdata->bt_chip_clk); - if (rc < 0) - pr_warn("%s: clock not provided in device tree\n", - __func__); -#ifdef CONFIG_MSM_BT_OOBS - bt_power_pdata->bt_gpio_dev_wake = - of_get_named_gpio(pdev->dev.of_node, - "qcom,btwake_gpio", 0); - if (bt_power_pdata->bt_gpio_dev_wake < 0) - pr_warn("%s: btwake-gpio not provided in device tree\n", - __func__); - - - bt_power_pdata->bt_gpio_host_wake = - of_get_named_gpio(pdev->dev.of_node, - "qcom,bthostwake_gpio", 0); - if (bt_power_pdata->bt_gpio_host_wake < 0) - pr_warn("%s: bthostwake_gpio not provided in device tree\n", - __func__); -#endif + if (pwr_data->is_ganges_dt) { + for_each_available_child_of_node(pdev->dev.of_node, of_node) { + if (!strcmp(of_node->name, "bt_ganges")) { + pwr_data->bt_of_node = of_node; + pr_info("%s: %s device node found\n", __func__, + pwr_data->bt_of_node->name); + } else if (!strcmp(of_node->name, "uwb_ganges")) { + pwr_data->uwb_of_node = of_node; + pr_info("%s: %s device node found\n", __func__, + pwr_data->uwb_of_node->name); + } + } } - bt_power_pdata->bt_power_setup = bluetooth_power; + rc = get_power_dt_pinfo(pdev); + if (rc < 0) + return rc; + + get_gpio_dt_pinfo(pdev); + bt_dt_parse_clk_info(&pdev->dev, &pwr_data->bt_chip_clk); + pwr_data->power_setup = power_regulators; return 0; } -static void bt_power_pdc_init_params (struct btpower_platform_data *pdata) +static void bt_power_pdc_init_params(struct platform_pwr_data *pdata) { int ret; struct device *dev = &pdata->pdev->dev; @@ -1186,28 +1429,78 @@ static void bt_power_pdc_init_params (struct btpower_platform_data *pdata) } } +static void bt_signal_handler(struct work_struct *w_arg) +{ + struct kernel_siginfo siginfo; + int rc = 0; + + memset(&siginfo, 0, sizeof(siginfo)); + siginfo.si_signo = SIGIO; + siginfo.si_code = SI_QUEUE; + siginfo.si_int = pwr_data->wrkq_signal_state; + rc = send_sig_info(siginfo.si_signo, &siginfo, pwr_data->reftask_bt); + if (rc < 0) + pr_err("%s: failed (%d) to send SIG to HAL(%d)\n", __func__, + rc, pwr_data->reftask_bt->pid); + else + pr_err("%s: Signal to BT HAL (PID-%d) succesfull\n", __func__, + pwr_data->reftask_bt->pid); +} + +static void uwb_signal_handler(struct work_struct *w_arg) +{ + struct kernel_siginfo siginfo; + int rc = 0; + + memset(&siginfo, 0, sizeof(siginfo)); + siginfo.si_signo = SIGIO; + siginfo.si_code = SI_QUEUE; + siginfo.si_int = pwr_data->wrkq_signal_state; + rc = send_sig_info(siginfo.si_signo, &siginfo, pwr_data->reftask_uwb); + if (rc < 0) + pr_err("%s: failed (%d) to send SIG to HAL(%d)\n", __func__, + rc, pwr_data->reftask_uwb->pid); + else + pr_err("%s: Signal to UWB HAL (PID-%d) succesfull\n", __func__, + pwr_data->reftask_uwb->pid); +} + static int bt_power_probe(struct platform_device *pdev) { int ret = 0; int itr; - pr_debug("%s\n", __func__); - /* Fill whole array with -2 i.e NOT_AVAILABLE state by default * for any GPIO or Reg handle. */ - for (itr = PWR_SRC_INIT_STATE_IDX; - itr < BT_POWER_SRC_SIZE; ++itr) - bt_power_src_status[itr] = PWR_SRC_NOT_AVAILABLE; + for (itr = PWR_SRC_INIT_STATE_IDX; itr < BT_POWER_SRC_SIZE; ++itr) { + power_src.bt_state[itr] = PWR_SRC_NOT_AVAILABLE; + power_src.platform_state[itr] = PWR_SRC_NOT_AVAILABLE; + power_src.uwb_state[itr] = PWR_SRC_NOT_AVAILABLE; + } - bt_power_pdata = kzalloc(sizeof(*bt_power_pdata), GFP_KERNEL); + pwr_data = kzalloc(sizeof(*pwr_data), GFP_KERNEL); - if (!bt_power_pdata) + if (!pwr_data) return -ENOMEM; - bt_power_pdata->pdev = pdev; + pwr_data->pdev = pdev; + + pwr_data->is_ganges_dt = of_property_read_bool(pdev->dev.of_node, + "qcom,peach-bt"); + + if (pwr_data->is_ganges_dt) { + pwr_data->workq = alloc_workqueue("btpwrwq", WQ_HIGHPRI, WQ_DFL_ACTIVE); + if (!pwr_data->workq) { + pr_err("%s: Failed to create workqueue\n", __func__); + return -ENOMEM; + } + INIT_WORK(&pwr_data->uwb_wq, uwb_signal_handler); + INIT_WORK(&pwr_data->bt_wq, bt_signal_handler); + } + + perisec_cnss_bt_hw_disable_check(pwr_data); - ret = perisec_cnss_bt_hw_disable_check(bt_power_pdata); if (pdev->dev.of_node) { ret = bt_power_populate_dt_pinfo(pdev); if (ret < 0) { @@ -1215,37 +1508,39 @@ static int bt_power_probe(struct platform_device *pdev) __func__); goto free_pdata; } - if (bt_power_pdata->bt_sec_hw_disable) { + if (pwr_data->bt_sec_hw_disable) { pr_info("%s: bt is in secure mode\n", __func__); } else { pr_info(" %s:send platform data of btpower\n", __func__); - pdev->dev.platform_data = bt_power_pdata; + pdev->dev.platform_data = pwr_data; } } else if (pdev->dev.platform_data) { /* Optional data set to default if not provided */ - if (!((struct btpower_platform_data *) - (pdev->dev.platform_data))->bt_power_setup) - ((struct btpower_platform_data *) - (pdev->dev.platform_data))->bt_power_setup = - bluetooth_power; + if (!((struct platform_pwr_data *) + (pdev->dev.platform_data))->power_setup) + ((struct platform_pwr_data *) + (pdev->dev.platform_data))->power_setup = + power_regulators; - memcpy(bt_power_pdata, pdev->dev.platform_data, - sizeof(struct btpower_platform_data)); + memcpy(pwr_data, pdev->dev.platform_data, + sizeof(struct platform_pwr_data)); pwr_state = 0; } else { pr_err("%s: Failed to get platform data\n", __func__); goto free_pdata; } + if (btpower_rfkill_probe(pdev) < 0) goto free_pdata; - bt_power_pdc_init_params(bt_power_pdata); - btpower_aop_mbox_init(bt_power_pdata); + + bt_power_pdc_init_params(pwr_data); + btpower_aop_mbox_init(pwr_data); probe_finished = true; return 0; free_pdata: - kfree(bt_power_pdata); + kfree(pwr_data); return ret; } @@ -1256,20 +1551,20 @@ static int bt_power_remove(struct platform_device *pdev) probe_finished = false; btpower_rfkill_remove(pdev); bt_power_vreg_put(); - - kfree(bt_power_pdata); - + if (pwr_data->is_ganges_dt) + destroy_workqueue(pwr_data->workq); + kfree(pwr_data); return 0; } int btpower_register_slimdev(struct device *dev) { pr_debug("%s\n", __func__); - if (!bt_power_pdata || (dev == NULL)) { + if (!pwr_data || (dev == NULL)) { pr_err("%s: Failed to allocate memory\n", __func__); return -EINVAL; } - bt_power_pdata->slim_dev = dev; + pwr_data->slim_dev = dev; return 0; } EXPORT_SYMBOL(btpower_register_slimdev); @@ -1281,88 +1576,338 @@ int btpower_get_chipset_version(void) } EXPORT_SYMBOL(btpower_get_chipset_version); -static void set_pwr_srcs_status(struct bt_power_vreg_data *handle) +static void set_pwr_srcs_status(struct vreg_data *handle, + int core_type) { - int ldo_index; + int power_src_state; - if (handle) { - ldo_index = handle->indx.crash; - bt_power_src_status[ldo_index] = - DEFAULT_INVALID_VALUE; - if (handle->is_enabled && - (regulator_is_enabled(handle->reg))) { - bt_power_src_status[ldo_index] = - (int)regulator_get_voltage(handle->reg); - pr_err("%s(%p) value(%d)\n", handle->name, - handle, bt_power_src_status[ldo_index]); + if (!handle) + pr_err("%s: invalid handler received\n", __func__); + + if (handle->is_enabled) + power_src_state = (int)regulator_get_voltage(handle->reg); + else + power_src_state = DEFAULT_INVALID_VALUE; + + switch (core_type) { + case BT_CORE: + power_src.bt_state[handle->indx.crash] = power_src_state; + if (power_src_state != DEFAULT_INVALID_VALUE) { + pr_err("%s(%p) value(%d)\n", handle->name, handle, + power_src.bt_state[handle->indx.crash]); } else { - pr_err("%s:%s is_enabled: %d\n", - __func__, handle->name, + pr_err("%s:%s is_enabled: %d\n", __func__, handle->name, handle->is_enabled); } + break; + case UWB_CORE: + power_src.uwb_state[handle->indx.crash] = power_src_state; + if (power_src_state != DEFAULT_INVALID_VALUE) { + pr_err("%s(%p) value(%d)\n", handle->name, handle, + power_src.uwb_state[handle->indx.crash]); + } else { + pr_err("%s:%s is_enabled: %d\n", __func__, handle->name, + handle->is_enabled); + } + break; + case PLATFORM_CORE: + power_src.platform_state[handle->indx.crash] = power_src_state; + if (power_src_state != DEFAULT_INVALID_VALUE) { + pr_err("%s(%p) value(%d)\n", handle->name, handle, + power_src.platform_state[handle->indx.crash]); + } else { + pr_err("%s:%s is_enabled: %d\n", __func__, handle->name, + handle->is_enabled); + } + break; + default: + pr_err("%s: invalid core type received = %d\n", __func__, core_type); + break; } } static void set_gpios_srcs_status(char *gpio_name, - int gpio_index, int handle) -{ + int gpio_index, int handle, int core_type) { + if (handle >= 0) { - bt_power_src_status[gpio_index] = - DEFAULT_INVALID_VALUE; - bt_power_src_status[gpio_index] = - gpio_get_value(handle); - pr_err("%s(%d) value(%d)\n", gpio_name, - handle, bt_power_src_status[gpio_index]); - } else { - pr_err("%s: %s not configured\n", - __func__, gpio_name); + pr_err("%s: %s not configured\n", __func__, gpio_name); + return; } + + switch (core_type) { + case BT_CORE: + power_src.bt_state[gpio_index] = gpio_get_value(handle); + break; + case UWB_CORE: + power_src.uwb_state[gpio_index] = gpio_get_value(handle); + break; + case PLATFORM_CORE: + power_src.platform_state[gpio_index] = gpio_get_value(handle); + break; + default: + pr_err("%s: invalid core type received = %d\n", __func__, core_type); + break; + } + pr_err("%s(%d) value(%d)\n", gpio_name, handle, + power_src.bt_state[gpio_index]); +} + +static void update_pwr_state(int state) +{ + pwr_data->power_state = state; +} + +static int get_pwr_state(void) +{ + return pwr_data->power_state; +} + +static void update_sub_state(int state) +{ + pwr_data->sub_state = state; +} + +static int get_sub_state(void) +{ + return pwr_data->sub_state; +} + +void power_enable(int SubSystemType) +{ + switch (get_pwr_state()) { + case IDLE: + power_regulators(PLATFORM_CORE, POWER_ENABLE); + if (SubSystemType == BLUETOOTH) { + power_regulators(BT_CORE, POWER_ENABLE); + update_pwr_state(BT_ON); + } else { + power_regulators(UWB_CORE, POWER_ENABLE); + update_pwr_state(UWB_ON); + } + break; + case BT_ON: + if (SubSystemType == BLUETOOTH) { + pr_err("%s: BT Regulators already Voted-On\n", + __func__); + return; + } + power_regulators(UWB_CORE, POWER_ENABLE); + update_pwr_state(ALL_CLIENTS_ON); + break; + case UWB_ON: + if (SubSystemType == UWB) { + pr_err("%s: UWB Regulators already Voted-On\n", + __func__); + return; + } + power_regulators(BT_CORE, POWER_ENABLE); + update_pwr_state(ALL_CLIENTS_ON); + break; + case ALL_CLIENTS_ON: + pr_err("%s: Both BT and UWB Regulators already Voted-On\n", + __func__); + return; + } +} + +void send_signal_to_subsystem(int SubSystemType, int state) +{ + pwr_data->wrkq_signal_state = state; + if (SubSystemType == BLUETOOTH) + queue_work(pwr_data->workq, &pwr_data->bt_wq); + else + queue_work(pwr_data->workq, &pwr_data->uwb_wq); +} + +void power_disable(int SubSystemType) +{ + switch (get_pwr_state()) { + case IDLE: + pr_err("%s: both BT and UWB regulators already voted-Off\n", __func__); + return; + case ALL_CLIENTS_ON: + if (SubSystemType == BLUETOOTH) { + power_regulators(BT_CORE, POWER_DISABLE); + update_pwr_state(UWB_ON); + if (get_sub_state() == SSR_ON_BT) { + power_regulators(UWB_CORE, POWER_DISABLE); + power_regulators(PLATFORM_CORE, POWER_DISABLE); + update_pwr_state(IDLE); + update_sub_state(SUB_STATE_IDLE); + send_signal_to_subsystem(UWB, + BT_SSR_COMPLETED); + } + } else { + power_regulators(UWB_CORE, POWER_DISABLE); + update_pwr_state(BT_ON); + if (get_sub_state() == SSR_ON_UWB) { + power_regulators(BT_CORE, POWER_DISABLE); + power_regulators(PLATFORM_CORE, POWER_DISABLE); + update_pwr_state(IDLE); + update_sub_state(SUB_STATE_IDLE); + send_signal_to_subsystem(BLUETOOTH, + (SIGIO_NOTIFICATION_SIGNAL|SIGIO_UWB_SSR_COMPLETED)); + } + } + break; + case UWB_ON: + if (SubSystemType == BLUETOOTH) { + pr_err("%s: BT Regulator already Voted-Off\n", __func__); + return; + } + power_regulators(UWB_CORE, POWER_DISABLE); + power_regulators(PLATFORM_CORE, POWER_DISABLE); + update_pwr_state(IDLE); + update_sub_state(SUB_STATE_IDLE); + break; + case BT_ON: + if (SubSystemType == UWB) { + pr_err("%s: UWB Regulator already Voted-Off\n", __func__); + return; + } + power_regulators(BT_CORE, POWER_DISABLE); + power_regulators(PLATFORM_CORE, POWER_DISABLE); + update_pwr_state(IDLE); + update_sub_state(SUB_STATE_IDLE); + break; + } +} + +static int client_state_notified(int SubSystemType) +{ + if (get_sub_state() != SUB_STATE_IDLE) { + pr_err("%s: SSR is already running on other Sub-system\n", __func__); + return -1; + } + + if (SubSystemType == BLUETOOTH) { + update_sub_state(SSR_ON_BT); + if (get_pwr_state() == ALL_CLIENTS_ON) { + if (!pwr_data->reftask_uwb) { + pr_err("%s: UWB PID is not register to send signal\n", + __func__); + return -1; + } + send_signal_to_subsystem(UWB, SSR_ON_BT); + } + } else { + update_sub_state(SSR_ON_UWB); + if (get_pwr_state() == ALL_CLIENTS_ON) { + if (!pwr_data->reftask_bt) { + pr_err("%s: BT PID is not register to send signal\n", + __func__); + return -1; + } + send_signal_to_subsystem(BLUETOOTH, + (SIGIO_NOTIFICATION_SIGNAL|SIGIO_SSR_ON_UWB)); + } + } + return 0; +} + +void set_pwr_state(int core, int mode) +{ + pr_info("%s: Entry %s, %s\n", __func__, + pwr_states[(int)get_pwr_state()], + ssr_state[(int)get_sub_state()]); + + switch (mode) { + case POWER_DISABLE: + power_disable(core); + break; + case POWER_ENABLE: + power_enable(core); + break; + case POWER_RETENTION: + power_regulators(PLATFORM_CORE, POWER_RETENTION); + power_regulators((core == BLUETOOTH ? BT_CORE : UWB_CORE), + POWER_RETENTION); + pr_err("%s: BT Power Retention done\n", __func__); + break; + } + pr_info("%s: Done %s, %s\n", __func__, + pwr_states[(int)get_pwr_state()], + ssr_state[(int)get_sub_state()]); +} + +void client_notified(int client, int cmd) +{ + if (cmd == REG_BT_PID) { + pwr_data->reftask_bt = get_current(); + pr_info("%s: Registering BT Service(PID-%d) with Power driver\n", + __func__, pwr_data->reftask_bt->tgid); + return; + } else if (cmd == REG_UWB_PID) { + pwr_data->reftask_uwb = get_current(); + pr_info("%s: Registering UWB Service(PID-%d) with Power driver\n", + __func__, pwr_data->reftask_uwb->tgid); + return; + } + + if (client == BLUETOOTH) + client_state_notified(BLUETOOTH); + else + client_state_notified(UWB); +} + +void log_power_src_val(void) +{ + int itr = 0; + + pr_info("BT_CMD_GETVAL_POWER_SRCS\n"); + set_gpios_srcs_status("BT_RESET_GPIO", BT_RESET_GPIO_CURRENT, + pwr_data->bt_gpio_sys_rst, PLATFORM_CORE); + set_gpios_srcs_status("SW_CTRL_GPIO", BT_SW_CTRL_GPIO_CURRENT, + pwr_data->bt_gpio_sw_ctrl, PLATFORM_CORE); + + for (itr = 0; itr < pwr_data->bt_num_vregs; itr++) + set_pwr_srcs_status(&pwr_data->bt_vregs[itr], BT_CORE); + + for (itr = 0; itr < pwr_data->platform_num_vregs; itr++) + set_pwr_srcs_status(&pwr_data->platform_vregs[itr], PLATFORM_CORE); + + for (itr = 0; itr < pwr_data->uwb_num_vregs; itr++) + set_pwr_srcs_status(&pwr_data->uwb_vregs[itr], UWB_CORE); } static long bt_ioctl(struct file *file, unsigned int cmd, unsigned long arg) { - int ret = 0, pwr_cntrl = 0; + int ret = 0; int chipset_version = 0; - int itr, num_vregs; - struct bt_power_vreg_data *vreg_info = NULL; + #ifdef CONFIG_MSM_BT_OOBS enum btpower_obs_param clk_cntrl; #endif - if (!bt_power_pdata || !probe_finished) { + + if (!pwr_data || !probe_finished) { pr_err("%s: BTPower Probing Pending.Try Again\n", __func__); return -EAGAIN; } switch (cmd) { #ifdef CONFIG_MSM_BT_OOBS - case BT_CMD_OBS_SIGNAL_TASK: - bt_power_pdata->reffilp_obs = file; - bt_power_pdata->reftask_obs = get_current(); - pr_info("%s: BT_CMD_OBS_SIGNAL_TASK tid %d file %pK\n", - __func__, bt_power_pdata->reftask_obs->pid, file); - break; case BT_CMD_OBS_VOTE_CLOCK: - if (!gpio_is_valid(bt_power_pdata->bt_gpio_dev_wake)) { + if (!gpio_is_valid(pwr_data->bt_gpio_dev_wake)) { pr_debug("%s: BT_CMD_OBS_VOTE_CLOCK bt_dev_wake_n(%d) not configured\n", - __func__, bt_power_pdata->bt_gpio_dev_wake); + __func__, pwr_data->bt_gpio_dev_wake); return -EIO; } clk_cntrl = (enum btpower_obs_param)arg; switch (clk_cntrl) { case BTPOWER_OBS_CLK_OFF: - btpower_uart_transport_locked(bt_power_pdata, false); + btpower_uart_transport_locked(pwr_data, false); ret = 0; break; case BTPOWER_OBS_CLK_ON: - btpower_uart_transport_locked(bt_power_pdata, true); + btpower_uart_transport_locked(pwr_data, true); ret = 0; break; case BTPOWER_OBS_DEV_OFF: - gpio_set_value(bt_power_pdata->bt_gpio_dev_wake, 0); + gpio_set_value(pwr_data->bt_gpio_dev_wake, 0); ret = 0; break; case BTPOWER_OBS_DEV_ON: - gpio_set_value(bt_power_pdata->bt_gpio_dev_wake, 1); + gpio_set_value(pwr_data->bt_gpio_dev_wake, 1); ret = 0; break; default: @@ -1372,34 +1917,32 @@ static long bt_ioctl(struct file *file, unsigned int cmd, unsigned long arg) } pr_debug("%s: BT_CMD_OBS_VOTE_CLOCK clk_cntrl(%d) %s\n", __func__, clk_cntrl, - gpio_get_value(bt_power_pdata->bt_gpio_dev_wake) ? + gpio_get_value(pwr_data->bt_gpio_dev_wake) ? "Assert" : "Deassert"); break; #endif case BT_CMD_SLIM_TEST: #if (defined CONFIG_BT_SLIM) - if (!bt_power_pdata->slim_dev) { + if (!pwr_data->slim_dev) { pr_err("%s: slim_dev is null\n", __func__); return -EINVAL; } ret = btfm_slim_hw_init( - bt_power_pdata->slim_dev->platform_data + pwr_data->slim_dev->platform_data ); #endif break; case BT_CMD_PWR_CTRL: - pwr_cntrl = (int)arg; - pr_warn("%s: BT_CMD_PWR_CTRL pwr_cntrl: %d\n", - __func__, pwr_cntrl); - if (pwr_state != pwr_cntrl) { - ret = bluetooth_power(pwr_cntrl); - if (!ret) - pwr_state = pwr_cntrl; - } else { - pr_err("%s: BT chip state is already: %d no change\n", - __func__, pwr_state); - ret = 0; - } + set_pwr_state(BLUETOOTH, (int)arg); + break; + case UWB_CMD_PWR_CTRL: + set_pwr_state(UWB, (int)arg); + break; + case BT_CMD_REGISTRATION: + client_notified(BLUETOOTH, (int)arg); + break; + case UWB_CMD_REGISTRATION: + client_notified(UWB, (int)arg); break; case BT_CMD_CHIPSET_VERS: chipset_version = (int)arg; @@ -1413,7 +1956,9 @@ static long bt_ioctl(struct file *file, unsigned int cmd, unsigned long arg) } break; case BT_CMD_GET_CHIPSET_ID: - if (copy_to_user((void __user *)arg, bt_power_pdata->compatible, + pr_err("%s: BT_CMD_GET_CHIPSET_ID = %s\n", __func__, + pwr_data->compatible); + if (copy_to_user((void __user *)arg, pwr_data->compatible, MAX_PROP_SIZE)) { pr_err("%s: copy to user failed\n", __func__); ret = -EFAULT; @@ -1422,23 +1967,23 @@ static long bt_ioctl(struct file *file, unsigned int cmd, unsigned long arg) case BT_CMD_CHECK_SW_CTRL: /* Check if SW_CTRL is asserted */ pr_info("BT_CMD_CHECK_SW_CTRL\n"); - if (bt_power_pdata->bt_gpio_sw_ctrl > 0) { - bt_power_src_status[BT_SW_CTRL_GPIO] = + if (pwr_data->bt_gpio_sw_ctrl > 0) { + power_src.bt_state[BT_SW_CTRL_GPIO] = DEFAULT_INVALID_VALUE; ret = gpio_direction_input( - bt_power_pdata->bt_gpio_sw_ctrl); + pwr_data->bt_gpio_sw_ctrl); if (ret) { pr_err("%s:gpio_direction_input api\n", __func__); pr_err("%s:failed for SW_CTRL:%d\n", __func__, ret); } else { - bt_power_src_status[BT_SW_CTRL_GPIO] = + power_src.bt_state[BT_SW_CTRL_GPIO] = gpio_get_value( - bt_power_pdata->bt_gpio_sw_ctrl); + pwr_data->bt_gpio_sw_ctrl); pr_info("bt-sw-ctrl-gpio(%d) value(%d)\n", - bt_power_pdata->bt_gpio_sw_ctrl, - bt_power_src_status[BT_SW_CTRL_GPIO]); + pwr_data->bt_gpio_sw_ctrl, + power_src.bt_state[BT_SW_CTRL_GPIO]); } } else { pr_err("bt_gpio_sw_ctrl not configured\n"); @@ -1447,25 +1992,15 @@ static long bt_ioctl(struct file *file, unsigned int cmd, unsigned long arg) break; case BT_CMD_GETVAL_POWER_SRCS: pr_info("BT_CMD_GETVAL_POWER_SRCS\n"); - set_gpios_srcs_status("BT_RESET_GPIO", BT_RESET_GPIO_CURRENT, - bt_power_pdata->bt_gpio_sys_rst); - set_gpios_srcs_status("SW_CTRL_GPIO", BT_SW_CTRL_GPIO_CURRENT, - bt_power_pdata->bt_gpio_sw_ctrl); - - num_vregs = bt_power_pdata->num_vregs; - for (itr = 0; itr < num_vregs; itr++) { - vreg_info = &bt_power_pdata->vreg_info[itr]; - set_pwr_srcs_status(vreg_info); - } - if (copy_to_user((void __user *)arg, - bt_power_src_status, sizeof(bt_power_src_status))) { + log_power_src_val(); + if (copy_to_user((void __user *)arg, &power_src, sizeof(power_src))) { pr_err("%s: copy to user failed\n", __func__); ret = -EFAULT; } break; case BT_CMD_SET_IPA_TCS_INFO: pr_info("%s: BT_CMD_SET_IPA_TCS_INFO\n", __func__); - btpower_enable_ipa_vreg(bt_power_pdata); + btpower_enable_ipa_vreg(pwr_data); break; case BT_CMD_KERNEL_PANIC: pr_info("%s: BT_CMD_KERNEL_PANIC\n", __func__); @@ -1477,6 +2012,32 @@ static long bt_ioctl(struct file *file, unsigned int cmd, unsigned long arg) return ret; } +static int bt_power_release(struct inode *inode, struct file *file) +{ + if (!pwr_data || !probe_finished) { + pr_err("%s: BTPower Probing Pending.Try Again\n", __func__); + return -EAGAIN; + } + + pwr_data->reftask = get_current(); + if (pwr_data->reftask_bt != NULL) { + if (pwr_data->reftask->tgid == pwr_data->reftask_bt->tgid) { + pr_err("%s called by BT service(PID-%d)\n", + __func__, pwr_data->reftask->tgid); + pwr_data->reftask_bt = NULL; + power_disable(BLUETOOTH); + } + } else if (pwr_data->reftask_uwb != NULL) { + if (pwr_data->reftask->tgid == pwr_data->reftask_uwb->tgid) { + pr_err("%s called by uwb service(PID-%d)\n", + __func__, pwr_data->reftask->tgid); + pwr_data->reftask_uwb = NULL; + power_disable(UWB); + } + } + return 0; +} + static struct platform_driver bt_power_driver = { .probe = bt_power_probe, .remove = bt_power_remove, @@ -1489,6 +2050,7 @@ static struct platform_driver bt_power_driver = { static const struct file_operations bt_dev_fops = { .unlocked_ioctl = bt_ioctl, .compat_ioctl = bt_ioctl, + .release = bt_power_release, }; static int __init btpower_init(void) @@ -1549,12 +2111,13 @@ driver_err: * * Return: 0 for success */ - int bt_aop_send_msg(struct btpower_platform_data *plat_priv, char *mbox_msg) - { +int bt_aop_send_msg(struct platform_pwr_data *plat_priv, char *mbox_msg) +{ struct qmp_pkt pkt; int ret = 0; pkt.size = BTPOWER_MBOX_MSG_MAX_LEN; pkt.data = mbox_msg; + pr_err("%s: %s\n", __func__, mbox_msg); ret = mbox_send_message(plat_priv->mbox_chan, &pkt); if (ret < 0) pr_err("Failed to send AOP mbox msg: %s\n", mbox_msg); @@ -1562,15 +2125,15 @@ driver_err: ret =0; return ret; - } -int bt_aop_pdc_reconfig(struct btpower_platform_data *pdata) -{ +} +int bt_aop_pdc_reconfig(struct platform_pwr_data *pdata) +{ unsigned int i; int ret; if (pdata->pdc_init_table_len <= 0 || !pdata->pdc_init_table) return 0; - pr_debug("Setting PDC defaults"); + pr_debug("Setting PDC defaults\n"); for (i = 0; i < pdata->pdc_init_table_len; i++) { ret =bt_aop_send_msg(pdata,(char *)pdata->pdc_init_table[i]); if (ret < 0) @@ -1579,8 +2142,7 @@ int bt_aop_pdc_reconfig(struct btpower_platform_data *pdata) return ret; } - -int btpower_aop_mbox_init(struct btpower_platform_data *pdata) +int btpower_aop_mbox_init(struct platform_pwr_data *pdata) { struct mbox_client *mbox = &pdata->mbox_client_data; struct mbox_chan *chan; @@ -1614,7 +2176,7 @@ int btpower_aop_mbox_init(struct btpower_platform_data *pdata) return 0; } -static int btpower_aop_set_vreg_param(struct btpower_platform_data *pdata, +static int btpower_aop_set_vreg_param(struct platform_pwr_data *pdata, const char *vreg_name, enum btpower_vreg_param param, enum btpower_tcs_seq seq, int val) @@ -1644,7 +2206,7 @@ static int btpower_aop_set_vreg_param(struct btpower_platform_data *pdata, return ret; } -static int btpower_enable_ipa_vreg(struct btpower_platform_data *pdata) +static int btpower_enable_ipa_vreg(struct platform_pwr_data *pdata) { int ret = 0; static bool config_done; From 5b17bd9bc9657f7cee6dec7904ae1174450ddb4c Mon Sep 17 00:00:00 2001 From: Balakrishna Godavarthi Date: Mon, 6 Nov 2023 14:45:55 +0530 Subject: [PATCH 065/154] btpower: Align voltage sources name with BT SoC This change align voltage sources names with BT SoC. Change-Id: Ie1693fdcd4011a2c790608e7401e2d4b4bff498d Signed-off-by: Balakrishna Godavarthi --- pwr/btpower.c | 27 +++++++++++++++++---------- 1 file changed, 17 insertions(+), 10 deletions(-) diff --git a/pwr/btpower.c b/pwr/btpower.c index fd6b248ccf..df5fbd0911 100644 --- a/pwr/btpower.c +++ b/pwr/btpower.c @@ -184,22 +184,29 @@ static struct vreg_data bt_vregs_info_kiwi[] = { }; static struct vreg_data platform_vregs_info_peach[] = { - {NULL, "qcom,bt-vdd18-aon", 1800000, 1800000, 0, false, true, + /* VDD1P8_AON */ + {NULL, "qcom,bt-vdd18-aon", 1620000, 1980000, 0, false, true, {BT_VDD_LDO, BT_VDD_LDO_CURRENT}}, - {NULL, "qcom,bt-vdd12-io", 1200000, 1200000, 0, false, true, + /* VDD1P2_IOAV91C_VDD Extractor */ + {NULL, "qcom,bt-vdd12-io", 1080000, 1980000, 0, false, true, {BT_VDD_IO_LDO, BT_VDD_IO_LDO_CURRENT}}, + /* AV91C_VDD Extractor */ {NULL, "qcom,bt-ant-ldo", 1776000, 1776000, 0, false, true, {BT_VDD_ANT_LDO, BT_VDD_ANT_LDO_CURRENT}}, - {NULL, "qcom,bt-vdd-dig", 950000, 950000, 0, false, true, - {BT_VDD_DIG_LDO, BT_VDD_DIG_LDO_CURRENT}}, - {NULL, "qcom,bt-vdd-aon", 950000, 950000, 0, false, true, - {BT_VDD_AON_LDO, BT_VDD_AON_LDO_CURRENT}}, - {NULL, "qcom,bt-vdd-rfaOp8", 950000, 952000, 0, false, true, - {BT_VDD_RFA_0p8, BT_VDD_RFA_0p8_CURRENT}}, /* BT_CX_MX */ - {NULL, "qcom,bt-vdd-rfa2", 1900000, 1900000, 0, false, true, + {NULL, "qcom,bt-vdd-dig", 700000, 2100000, 0, false, true, + {BT_VDD_DIG_LDO, BT_VDD_DIG_LDO_CURRENT}}, + /* RFA_CMN/AON */ + {NULL, "qcom,bt-vdd-aon", 800000, 2100000, 0, false, true, + {BT_VDD_AON_LDO, BT_VDD_AON_LDO_CURRENT}}, + /* RFA_OP75 */ + {NULL, "qcom,bt-vdd-rfa0p75", 800000, 2100000, 0, false, true, + {BT_VDD_RFA_0p8, BT_VDD_RFA_0p8_CURRENT}}, + /* RFA_1P8 */ + {NULL, "qcom,bt-vdd-rfa1p8", 1850000, 2100000, 0, false, true, {BT_VDD_RFA2_LDO, BT_VDD_RFA2_LDO_CURRENT}}, - {NULL, "qcom,bt-vdd-rfa1", 1350000, 1350000, 0, false, true, + /* RFA_1P25 */ + {NULL, "qcom,bt-vdd-rfa1p25", 1300000, 2100000, 0, false, true, {BT_VDD_RFA1_LDO, BT_VDD_RFA1_LDO_CURRENT}}, }; From 0006b4a1625f600aed100efe24220a2368366c20 Mon Sep 17 00:00:00 2001 From: Bhakthavatsala Raghavendra Date: Fri, 15 Sep 2023 14:53:56 -0700 Subject: [PATCH 066/154] BT: use aosp QMP client Enable AOP client instead of mbox. Change-Id: Id0ce78eab34aea3c8b1b093d762c78d35a5eb15e Signed-off-by: Bhakthavatsala Raghavendra --- include/btpower.h | 5 ++--- pwr/btpower.c | 43 ++++++++++++++----------------------------- 2 files changed, 16 insertions(+), 32 deletions(-) diff --git a/include/btpower.h b/include/btpower.h index 3ad80ecb9d..060753339b 100644 --- a/include/btpower.h +++ b/include/btpower.h @@ -9,8 +9,7 @@ #include #include -#include -#include +#include #include /* @@ -111,7 +110,7 @@ struct platform_pwr_data { int bt_num_vregs; int uwb_num_vregs; int platform_num_vregs; - struct mbox_client mbox_client_data; + struct qmp *qmp; struct mbox_chan *mbox_chan; const char *vreg_ipa; bool is_ganges_dt; diff --git a/pwr/btpower.c b/pwr/btpower.c index df5fbd0911..a179571b66 100644 --- a/pwr/btpower.c +++ b/pwr/btpower.c @@ -26,6 +26,7 @@ #include #include #include +#include #include "btpower.h" #if (defined CONFIG_BT_SLIM) #include "btfm_slim.h" @@ -2120,14 +2121,10 @@ driver_err: */ int bt_aop_send_msg(struct platform_pwr_data *plat_priv, char *mbox_msg) { - struct qmp_pkt pkt; int ret = 0; - pkt.size = BTPOWER_MBOX_MSG_MAX_LEN; - pkt.data = mbox_msg; - pr_err("%s: %s\n", __func__, mbox_msg); - ret = mbox_send_message(plat_priv->mbox_chan, &pkt); + ret = qmp_send(plat_priv->qmp, mbox_msg, BTPOWER_MBOX_MSG_MAX_LEN); if (ret < 0) - pr_err("Failed to send AOP mbox msg: %s\n", mbox_msg); + pr_err("Failed to send AOP qmp xmsg: %s\n", mbox_msg); else ret =0; return ret; @@ -2142,7 +2139,7 @@ int bt_aop_pdc_reconfig(struct platform_pwr_data *pdata) return 0; pr_debug("Setting PDC defaults\n"); for (i = 0; i < pdata->pdc_init_table_len; i++) { - ret =bt_aop_send_msg(pdata,(char *)pdata->pdc_init_table[i]); + ret = bt_aop_send_msg(pdata, (char *)pdata->pdc_init_table[i]); if (ret < 0) break; } @@ -2151,30 +2148,20 @@ int bt_aop_pdc_reconfig(struct platform_pwr_data *pdata) int btpower_aop_mbox_init(struct platform_pwr_data *pdata) { - struct mbox_client *mbox = &pdata->mbox_client_data; - struct mbox_chan *chan; int ret = 0; - - mbox->dev = &pdata->pdev->dev; - mbox->tx_block = true; - mbox->tx_tout = BTPOWER_MBOX_TIMEOUT_MS; - mbox->knows_txdone = false; - - pdata->mbox_chan = NULL; - chan = mbox_request_channel(mbox, 0); - if (IS_ERR(chan)) { - pr_err("%s: failed to get mbox channel\n", __func__); - return PTR_ERR(chan); +// ret = of_find_property(pdata->pdev->dev.of_node, "qcom,qmp", NULL); + pdata->qmp = qmp_get(&pdata->pdev->dev); + if (IS_ERR(pdata->qmp)) { + pr_err("%s: failed to get qmp\n", __func__); + return PTR_ERR(pdata->qmp); } - pdata->mbox_chan = chan; - ret = of_property_read_string(pdata->pdev->dev.of_node, "qcom,vreg_ipa", &pdata->vreg_ipa); if (ret) pr_info("%s: vreg for iPA not configured\n", __func__); else - pr_info("%s: Mbox channel initialized\n", __func__); + pr_info("%s: qmp initialized\n", __func__); ret = bt_aop_pdc_reconfig(pdata); if (ret) @@ -2188,7 +2175,7 @@ static int btpower_aop_set_vreg_param(struct platform_pwr_data *pdata, enum btpower_vreg_param param, enum btpower_tcs_seq seq, int val) { - struct qmp_pkt pkt; + char mbox_msg[BTPOWER_MBOX_MSG_MAX_LEN]; static const char * const vreg_param_str[] = {"v", "m", "e"}; static const char *const tcs_seq_str[] = {"upval", "dwnval", "enable"}; @@ -2202,10 +2189,7 @@ static int btpower_aop_set_vreg_param(struct platform_pwr_data *pdata, vreg_param_str[param], tcs_seq_str[seq], val); pr_info("%s: sending AOP Mbox msg: %s\n", __func__, mbox_msg); - pkt.size = BTPOWER_MBOX_MSG_MAX_LEN; - pkt.data = mbox_msg; - - ret = mbox_send_message(pdata->mbox_chan, &pkt); + ret = qmp_send(pdata->qmp, mbox_msg, BTPOWER_MBOX_MSG_MAX_LEN); if (ret < 0) pr_err("%s:Failed to send AOP mbox msg(%s), err(%d)\n", __func__, mbox_msg, ret); @@ -2223,7 +2207,7 @@ static int btpower_enable_ipa_vreg(struct platform_pwr_data *pdata) return 0; } - if (!pdata->vreg_ipa || !pdata->mbox_chan) { + if (!pdata->vreg_ipa) { pr_info("%s: mbox/iPA vreg not configured\n", __func__); } else { ret = btpower_aop_set_vreg_param(pdata, @@ -2241,6 +2225,7 @@ static int btpower_enable_ipa_vreg(struct platform_pwr_data *pdata) static void __exit btpower_exit(void) { + qmp_put(pwr_data->qmp); platform_driver_unregister(&bt_power_driver); } From bc21d3695db2a3686d42eda853e9e579ca718de8 Mon Sep 17 00:00:00 2001 From: Balakrishna Godavarthi Date: Tue, 7 Nov 2023 14:31:56 +0530 Subject: [PATCH 067/154] btfmcodec: cancel workqueue This change will cancel workqueue when bearer indication is received. Change-Id: Ib16849e684d6c2fb2ded817baff7ab31b5cbd6db Signed-off-by: Balakrishna Godavarthi --- btfmcodec/btfm_codec.c | 8 ++++++++ btfmcodec/btfm_codec_btadv_interface.c | 3 +-- 2 files changed, 9 insertions(+), 2 deletions(-) diff --git a/btfmcodec/btfm_codec.c b/btfmcodec/btfm_codec.c index 22bd9844e4..f6b5b35e5a 100644 --- a/btfmcodec/btfm_codec.c +++ b/btfmcodec/btfm_codec.c @@ -141,6 +141,7 @@ static void btfmcodec_dev_rxwork(struct work_struct *work) uint32_t len; uint8_t status; int idx; + uint8_t *bearer_switch_ind; BTFMCODEC_DBG("start"); while ((skb = skb_dequeue(&btfmcodec_dev->rxq))) { @@ -163,6 +164,10 @@ static void btfmcodec_dev_rxwork(struct work_struct *work) wake_up_interruptible(&btfmcodec_dev->rsp_wait_q[BTM_PKT_TYPE_BEARER_SWITCH_IND]); } btfmcodec_dev->status[idx] = skb->data[0]; + /* Reset bearer switch ind flag */ + bearer_switch_ind = + &btfmcodec_dev->status[BTM_PKT_TYPE_BEARER_SWITCH_IND]; + *bearer_switch_ind = BTM_WAITING_RSP; queue_work(btfmcodec_dev->workqueue, &btfmcodec_dev->wq_prepare_bearer); } else { BTFMCODEC_ERR("wrong packet format with len:%d", len); @@ -215,6 +220,9 @@ static void btfmcodec_dev_rxwork(struct work_struct *work) BTFMCODEC_INFO("Rx BTM_BTFMCODEC_CTRL_MASTER_SHUTDOWN_RSP status:%d", status); wake_up_interruptible(&btfmcodec_dev->rsp_wait_q[idx]); + BTFMCODEC_INFO("%s: waiting to cancel prepare bearer wq", __func__); + cancel_work_sync(&btfmcodec_dev->wq_prepare_bearer); + BTFMCODEC_INFO("%s: prepare bearer wq canceled", __func__); break; case BTM_BTFMCODEC_BEARER_SWITCH_IND: idx = BTM_PKT_TYPE_BEARER_SWITCH_IND; diff --git a/btfmcodec/btfm_codec_btadv_interface.c b/btfmcodec/btfm_codec_btadv_interface.c index a73bc972ba..7804d0d395 100644 --- a/btfmcodec/btfm_codec_btadv_interface.c +++ b/btfmcodec/btfm_codec_btadv_interface.c @@ -1,6 +1,6 @@ // SPDX-License-Identifier: GPL-2.0-only /* - * Copyright (c) 202333 Qualcomm Innovation Center, Inc. All rights reserved. + * Copyright (c) 2023 Qualcomm Innovation Center, Inc. All rights reserved. */ #include "btfm_codec.h" @@ -123,7 +123,6 @@ int btfmcodec_wait_for_bearer_ind(struct btfmcodec_char_device *btfmcodec_dev) int ret; uint8_t *status = &btfmcodec_dev->status[BTM_PKT_TYPE_BEARER_SWITCH_IND]; - *status = BTM_WAITING_RSP; ret = wait_event_interruptible_timeout(*rsp_wait_q, *status != BTM_WAITING_RSP, msecs_to_jiffies(BTM_MASTER_CONFIG_RSP_TIMEOUT)); From e7e615c2c2eecb97ef4f6e6cadb31d473b152280 Mon Sep 17 00:00:00 2001 From: Franklin Abreu Bueno Date: Tue, 24 Oct 2023 13:50:24 -0700 Subject: [PATCH 068/154] UWB Kernel Panic Support Add UWB Kernel Panic ioctl command that prints unique message with crash reasons on kernel panic. Change-Id: Ifb8f7b901acc3d337107d091c7116732cce7dbf5 Signed-off-by: Franklin Abreu Bueno --- include/btpower.h | 1 + pwr/btpower.c | 12 ++++++++++++ 2 files changed, 13 insertions(+) diff --git a/include/btpower.h b/include/btpower.h index 060753339b..3762c56eda 100644 --- a/include/btpower.h +++ b/include/btpower.h @@ -150,6 +150,7 @@ int bt_aop_pdc_reconfig(struct platform_pwr_data *pdata); #define BT_CMD_GETVAL_POWER_SRCS 0xbfb1 #define BT_CMD_SET_IPA_TCS_INFO 0xbfc0 #define BT_CMD_KERNEL_PANIC 0xbfc1 +#define UWB_CMD_KERNEL_PANIC 0xbfc2 #define UWB_CMD_PWR_CTRL 0xbfe1 #define BT_CMD_REGISTRATION 0xbfe2 #define UWB_CMD_REGISTRATION 0xbfe3 diff --git a/pwr/btpower.c b/pwr/btpower.c index a179571b66..f2d4ec825b 100644 --- a/pwr/btpower.c +++ b/pwr/btpower.c @@ -1882,6 +1882,8 @@ static long bt_ioctl(struct file *file, unsigned int cmd, unsigned long arg) { int ret = 0; int chipset_version = 0; + unsigned int panic_reason = 0; + unsigned short primary_reason = 0, sec_reason = 0; #ifdef CONFIG_MSM_BT_OOBS enum btpower_obs_param clk_cntrl; @@ -2014,6 +2016,16 @@ static long bt_ioctl(struct file *file, unsigned int cmd, unsigned long arg) pr_info("%s: BT_CMD_KERNEL_PANIC\n", __func__); panic("subsys-restart: Resetting the SoC - Bluetooth crashed\n"); break; + case UWB_CMD_KERNEL_PANIC: + pr_err("%s: UWB_CMD_KERNEL_PANIC\n", __func__); + panic_reason = (unsigned int)arg; + primary_reason = panic_reason & 0xFFFF; + sec_reason = (panic_reason & 0xFFFF0000) >> 16; + pr_err("%s: UWB kernel panic primary reason [0x%04x] secondary reason [0x%04x]\n", + __func__, primary_reason, sec_reason); + panic("subsys-restart: Resetting the SoC - UWB crashed primary reason [0x%04x] secondary reason [0x%04x]\n", + primary_reason, sec_reason); + break; default: return -ENOIOCTLCMD; } From 370fa432f78dcb0f5d082b82c908bdb4105c6cc7 Mon Sep 17 00:00:00 2001 From: Balakrishna Godavarthi Date: Fri, 17 Nov 2023 18:17:42 +0530 Subject: [PATCH 069/154] btpower: Disable AOP and pdc This change disables AOP and PDC. Change-Id: I53dfad0b34bc89fa0a7286f41fe65e08f27e52cd Signed-off-by: Balakrishna Godavarthi --- pwr/btpower.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pwr/btpower.c b/pwr/btpower.c index a179571b66..b2e586d426 100644 --- a/pwr/btpower.c +++ b/pwr/btpower.c @@ -1540,10 +1540,10 @@ static int bt_power_probe(struct platform_device *pdev) if (btpower_rfkill_probe(pdev) < 0) goto free_pdata; - +/* bt_power_pdc_init_params(pwr_data); btpower_aop_mbox_init(pwr_data); - +*/ probe_finished = true; return 0; From 8ceb20aa802b9efb2026dd7f3e83ca28f554dc11 Mon Sep 17 00:00:00 2001 From: Balakrishna Godavarthi Date: Sat, 18 Nov 2023 00:20:16 +0530 Subject: [PATCH 070/154] btpower: Fix compilation issue This change fixes compilation issue. Change-Id: I0673ae5cef3fc6e2023503780f58ff92f94e2223 Signed-off-by: Balakrishna Godavarthi --- pwr/btpower.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pwr/btpower.c b/pwr/btpower.c index b2e586d426..cf0348c5fc 100644 --- a/pwr/btpower.c +++ b/pwr/btpower.c @@ -1416,7 +1416,7 @@ static int bt_power_populate_dt_pinfo(struct platform_device *pdev) pwr_data->power_setup = power_regulators; return 0; } - +/* static void bt_power_pdc_init_params(struct platform_pwr_data *pdata) { int ret; @@ -1436,7 +1436,7 @@ static void bt_power_pdc_init_params(struct platform_pwr_data *pdata) pr_debug("PDC Init Table not configured\n"); } } - +*/ static void bt_signal_handler(struct work_struct *w_arg) { struct kernel_siginfo siginfo; From c672e4105b5aa1a78f634464ccab5aa39c3274c7 Mon Sep 17 00:00:00 2001 From: Balakrishna Godavarthi Date: Mon, 20 Nov 2023 22:37:38 +0530 Subject: [PATCH 071/154] btpower: set pin control configurations This change sets pin control configurations to enable PDC. Change-Id: If87921252ce7d35d803b6bb2e85fc9ec1e7b6ddc Signed-off-by: Balakrishna Godavarthi --- pwr/btpower.c | 30 ++++++++++++++++++++++++++---- 1 file changed, 26 insertions(+), 4 deletions(-) diff --git a/pwr/btpower.c b/pwr/btpower.c index cf0348c5fc..a558fc2b51 100644 --- a/pwr/btpower.c +++ b/pwr/btpower.c @@ -27,6 +27,11 @@ #include #include #include +#include +#include +#include +#include + #include "btpower.h" #if (defined CONFIG_BT_SLIM) #include "btfm_slim.h" @@ -1271,9 +1276,12 @@ static int get_gpio_dt_pinfo(struct platform_device *pdev) { int ret; struct device_node *child; + struct pinctrl *pinctrl1; + struct pinctrl_state *sw_ctrl; child = pdev->dev.of_node; + pinctrl1 = devm_pinctrl_get(&pdev->dev); pwr_data->bt_gpio_sys_rst = of_get_named_gpio(child, "qcom,bt-reset-gpio", 0); @@ -1299,6 +1307,20 @@ static int get_gpio_dt_pinfo(struct platform_device *pdev) if (ret) pr_warn("sw_cntrl-gpio not provided in devicetree\n"); + if (pinctrl1) { + sw_ctrl = pinctrl_lookup_state(pinctrl1, "sw_ctrl"); + if (IS_ERR_OR_NULL(sw_ctrl)) { + ret = PTR_ERR(sw_ctrl); + pr_err("Failed to get sw_ctrl state, err = %d\n", ret); + } else { + ret = pinctrl_select_state(pinctrl1, sw_ctrl); + if (ret) + pr_err("Failed to select sw_ctrl state, err = %d\n", ret); + } + } else { + pr_err("%s: pinctrl is null", __func__); + } + pwr_data->bt_gpio_debug = of_get_named_gpio(child, "qcom,bt-debug-gpio", 0); if (pwr_data->bt_gpio_debug < 0) @@ -1416,7 +1438,7 @@ static int bt_power_populate_dt_pinfo(struct platform_device *pdev) pwr_data->power_setup = power_regulators; return 0; } -/* + static void bt_power_pdc_init_params(struct platform_pwr_data *pdata) { int ret; @@ -1436,7 +1458,7 @@ static void bt_power_pdc_init_params(struct platform_pwr_data *pdata) pr_debug("PDC Init Table not configured\n"); } } -*/ + static void bt_signal_handler(struct work_struct *w_arg) { struct kernel_siginfo siginfo; @@ -1540,10 +1562,10 @@ static int bt_power_probe(struct platform_device *pdev) if (btpower_rfkill_probe(pdev) < 0) goto free_pdata; -/* + bt_power_pdc_init_params(pwr_data); btpower_aop_mbox_init(pwr_data); -*/ + probe_finished = true; return 0; From 6f4ae8ae1c15a3784c5e1a30410c85d8b8768a12 Mon Sep 17 00:00:00 2001 From: Girish BN Date: Mon, 20 Nov 2023 18:54:57 +0530 Subject: [PATCH 072/154] Power driver update wrong GPIO state to BT Host Use case: - Whenever the BT host crashes, Requests to Power driver for GPIO values to log in state files Current Behavior: - Power driver updating the current GPIO value as -2 Expected Behavior: - Power driver should be update with proper GPIO values either 0 or 1 Fix: - Implemented the logic to update proper GPIO value either 0 or 1 Change-Id: I54689afb097fbabc24d181980074b59d7c1143d9 Signed-off-by: Girish BN --- pwr/btpower.c | 35 ++++------------------------------- 1 file changed, 4 insertions(+), 31 deletions(-) diff --git a/pwr/btpower.c b/pwr/btpower.c index cf0348c5fc..b2fd22cc4e 100644 --- a/pwr/btpower.c +++ b/pwr/btpower.c @@ -1634,32 +1634,6 @@ static void set_pwr_srcs_status(struct vreg_data *handle, } } -static void set_gpios_srcs_status(char *gpio_name, - int gpio_index, int handle, int core_type) { - - if (handle >= 0) { - pr_err("%s: %s not configured\n", __func__, gpio_name); - return; - } - - switch (core_type) { - case BT_CORE: - power_src.bt_state[gpio_index] = gpio_get_value(handle); - break; - case UWB_CORE: - power_src.uwb_state[gpio_index] = gpio_get_value(handle); - break; - case PLATFORM_CORE: - power_src.platform_state[gpio_index] = gpio_get_value(handle); - break; - default: - pr_err("%s: invalid core type received = %d\n", __func__, core_type); - break; - } - pr_err("%s(%d) value(%d)\n", gpio_name, handle, - power_src.bt_state[gpio_index]); -} - static void update_pwr_state(int state) { pwr_data->power_state = state; @@ -1862,11 +1836,10 @@ void log_power_src_val(void) { int itr = 0; - pr_info("BT_CMD_GETVAL_POWER_SRCS\n"); - set_gpios_srcs_status("BT_RESET_GPIO", BT_RESET_GPIO_CURRENT, - pwr_data->bt_gpio_sys_rst, PLATFORM_CORE); - set_gpios_srcs_status("SW_CTRL_GPIO", BT_SW_CTRL_GPIO_CURRENT, - pwr_data->bt_gpio_sw_ctrl, PLATFORM_CORE); + power_src.platform_state[BT_SW_CTRL_GPIO_CURRENT] = + gpio_get_value(pwr_data->bt_gpio_sw_ctrl); + power_src.platform_state[BT_RESET_GPIO_CURRENT] = + gpio_get_value(pwr_data->bt_gpio_sys_rst); for (itr = 0; itr < pwr_data->bt_num_vregs; itr++) set_pwr_srcs_status(&pwr_data->bt_vregs[itr], BT_CORE); From 91429be378edf43d58511fa4e81b8011e0fe69db Mon Sep 17 00:00:00 2001 From: Girish BN Date: Sat, 18 Nov 2023 21:24:31 +0530 Subject: [PATCH 073/154] Handling the NULL pointer dereference in BT Power driver MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Use case: - Power driver schedule the workq to signal other-subsystem, to update SSR_COMPLETE status. Before completing the vote off, other sub-system also voted to power driver for power off and got killed Observation: - Power driver release called, erase the Subsystem PID. Workq failing to access and seeing the NULL pointer dereference Exception: - NULL pointer dereference shouldn’t happened Fix: - In BT power driver release function not erasing registered PID Change-Id: I450103afa32469913129535c34981828c210ad85 Signed-off-by: Girish BN --- pwr/btpower.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/pwr/btpower.c b/pwr/btpower.c index fd6b248ccf..9319a49ee2 100644 --- a/pwr/btpower.c +++ b/pwr/btpower.c @@ -2024,14 +2024,12 @@ static int bt_power_release(struct inode *inode, struct file *file) if (pwr_data->reftask->tgid == pwr_data->reftask_bt->tgid) { pr_err("%s called by BT service(PID-%d)\n", __func__, pwr_data->reftask->tgid); - pwr_data->reftask_bt = NULL; power_disable(BLUETOOTH); } } else if (pwr_data->reftask_uwb != NULL) { if (pwr_data->reftask->tgid == pwr_data->reftask_uwb->tgid) { pr_err("%s called by uwb service(PID-%d)\n", __func__, pwr_data->reftask->tgid); - pwr_data->reftask_uwb = NULL; power_disable(UWB); } } From cd76da24d23e3dfe66c88324e25a7badcbcaf6c6 Mon Sep 17 00:00:00 2001 From: Anmolpreet Kaur Date: Mon, 30 Oct 2023 15:13:34 -0700 Subject: [PATCH 074/154] Add dependency on smcinvoke headers Add dependency on smcinvoke headers. Change-Id: I0e876e3dd93428dbd55f63da75a58faca4c3b1e5 Signed-off-by: Anmolpreet Kaur --- bt_modules.bzl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bt_modules.bzl b/bt_modules.bzl index 6759503284..9cc8596aaf 100644 --- a/bt_modules.bzl +++ b/bt_modules.bzl @@ -56,7 +56,7 @@ register_bt_modules( config_opt = "CONFIG_MSM_BT_POWER", srcs = ["btpower.c"], config_deps = { - "CONFIG_BT_HW_SECURE_DISABLE": [ + "CONFIG_BT_HW_SECURE_DISABLE": [ ":smcinvoke_kernel_headers", "//vendor/qcom/opensource/securemsm-kernel:%b_smcinvoke_dlkm", ] }, From ae82f62158ca68ff02cebe473240dbec4b193f73 Mon Sep 17 00:00:00 2001 From: Satish Kumar Kodishala Date: Wed, 6 Sep 2023 23:13:15 +0530 Subject: [PATCH 075/154] Enable compilation for BT/FM SoundWire slave driver Enable compilation for BT/FM SoundWire slave driver. CRs-Fixed: 3629038 Change-Id: I5d712db8346c20f8769f6e88c9b622688a8e78cc Signed-off-by: Satish Kumar Kodishala --- Android.mk | 16 ++++++++++++++++ BUILD.bazel | 2 ++ Kbuild | 5 +++++ bt_kernel_product_board.mk | 1 + bt_kernel_vendor_board.mk | 2 ++ bt_modules.bzl | 21 +++++++++++++++++++++ soundwire/btfm_swr.c | 3 ++- soundwire/btfm_swr.h | 2 +- target.bzl | 2 ++ 9 files changed, 52 insertions(+), 2 deletions(-) diff --git a/Android.mk b/Android.mk index 0200efd825..d9c4ddfe42 100644 --- a/Android.mk +++ b/Android.mk @@ -17,6 +17,7 @@ ifeq ($(call is-board-platform-in-list, taro kalama pineapple blair sun), true) BT_SELECT := CONFIG_MSM_BT_POWER=m BT_SELECT += CONFIG_SLIM_BTFM_CODEC=n BT_SELECT += CONFIG_I2C_RTC6226_QCA=m +BT_SELECT += CONFIG_BTFM_SWR=m ifeq ($(TARGET_KERNEL_DLKM_SECURE_MSM_OVERRIDE), true) ifeq ($(ENABLE_PERIPHERAL_STATE_UTILS), true) @@ -29,6 +30,7 @@ LOCAL_MODULE_DDK_BUILD := true LOCAL_MODULE_KO_DIRS := pwr/btpower.ko LOCAL_MODULE_KO_DIRS += rtc6226/radio-i2c-rtc6226-qca.ko #LOCAL_MODULE_KO_DIRS += slimbus/btfm_slim_codec.ko +LOCAL_MODULE_KO_DIRS += soundwire/bt_fm_swr.ko ifneq ($(TARGET_BOARD_PLATFORM), pineapple) BT_SELECT += CONFIG_BTFM_CODEC=m @@ -62,6 +64,8 @@ endif endif +KBUILD_REQUIRED_KOS += swr_dlkm.ko + # Module.symvers needs to be generated as a intermediate module so that # other modules which depend on BT platform modules can set local # dependencies to it. @@ -120,6 +124,18 @@ LOCAL_MODULE_TAGS := optional LOCAL_MODULE_DEBUG_ENABLE := true LOCAL_MODULE_PATH := $(KERNEL_MODULES_OUT) include $(DLKM_DIR)/Build_external_kernelmodule.mk +################################ slimbus ################################ +include $(CLEAR_VARS) +LOCAL_SRC_FILES := $(BT_SRC_FILES) +LOCAL_MODULE := bt_fm_swr.ko +LOCAL_MODULE_KBUILD_NAME := soundwire/bt_fm_swr.ko +LOCAL_MODULE_TAGS := optional +LOCAL_MODULE_DEBUG_ENABLE := true +#KBUILD_OPTIONS += KBUILD_EXTRA_SYMBOLS+=$(call intermediates-dir-for,DLKM,swr_dlkm)/Module.symvers +#LOCAL_REQUIRED_MODULES := swr_dlkm +#LOCAL_ADDITIONAL_DEPENDENCIES += $(call intermediates-dir-for,DLKM,swr_dlkm)/Module.symvers +LOCAL_MODULE_PATH := $(KERNEL_MODULES_OUT) +include $(DLKM_DIR)/Build_external_kernelmodule.mk ########################################################### diff --git a/BUILD.bazel b/BUILD.bazel index 556c6041a9..4e7e750f4c 100644 --- a/BUILD.bazel +++ b/BUILD.bazel @@ -9,5 +9,7 @@ ddk_headers( ) load(":target.bzl", "define_pineapple") +load(":target.bzl", "define_sun") define_pineapple() +define_sun() diff --git a/Kbuild b/Kbuild index 5415a289dc..4d7c576619 100644 --- a/Kbuild +++ b/Kbuild @@ -18,8 +18,13 @@ ifeq ($(CONFIG_BT_HW_SECURE_DISABLE), y) KBUILD_CPPFLAGS += -DCONFIG_BT_HW_SECURE_DISABLE endif +ifeq ($(CONFIG_BTFM_SWR),m) +KBUILD_CPPFLAGS += -DCONFIG_BTFM_SWR +endif + obj-$(CONFIG_MSM_BT_POWER) += pwr/ obj-$(CONFIG_BTFM_SLIM) += slimbus/ obj-$(CONFIG_I2C_RTC6226_QCA) += rtc6226/ obj-$(CONFIG_BTFM_CODEC) += btfmcodec/ obj-$(CONFIG_SLIM_BTFM_CODEC) += slimbus/ +obj-$(CONFIG_BTFM_SWR) += soundwire/ diff --git a/bt_kernel_product_board.mk b/bt_kernel_product_board.mk index a4d55dafa5..7fdba5f94b 100644 --- a/bt_kernel_product_board.mk +++ b/bt_kernel_product_board.mk @@ -3,3 +3,4 @@ PRODUCT_PACKAGES += $(KERNEL_MODULES_OUT)/btpower.ko #PRODUCT_PACKAGES += $(KERNEL_MODULES_OUT)/btfm_slim_codec.ko PRODUCT_PACKAGES += $(KERNEL_MODULES_OUT)/radio-i2c-rtc6226-qca.ko PRODUCT_PACKAGES += $(KERNEL_MODULES_OUT)/btfmcodec.ko +PRODUCT_PACKAGES += $(KERNEL_MODULES_OUT)/bt_fm_swr.ko diff --git a/bt_kernel_vendor_board.mk b/bt_kernel_vendor_board.mk index f9af0921a5..e384cfaf81 100644 --- a/bt_kernel_vendor_board.mk +++ b/bt_kernel_vendor_board.mk @@ -9,6 +9,7 @@ ifeq ($(TARGET_USES_QMAA),true) ifneq ($(TARGET_BOARD_PLATFORM), pineapple) BT_KERNEL_DRIVER += $(KERNEL_MODULES_OUT)/btfmcodec.ko endif + BT_KERNEL_DRIVER += $(KERNEL_MODULES_OUT)/bt_fm_swr.ko BOARD_VENDOR_KERNEL_MODULES += $(BT_KERNEL_DRIVER) endif endif @@ -20,6 +21,7 @@ else ifneq ($(TARGET_BOARD_PLATFORM), pineapple) BT_KERNEL_DRIVER += $(KERNEL_MODULES_OUT)/btfmcodec.ko endif + BT_KERNEL_DRIVER += $(KERNEL_MODULES_OUT)/bt_fm_swr.ko BOARD_VENDOR_KERNEL_MODULES += $(BT_KERNEL_DRIVER) endif endif diff --git a/bt_modules.bzl b/bt_modules.bzl index 6759503284..b9f10a4762 100644 --- a/bt_modules.bzl +++ b/bt_modules.bzl @@ -2,6 +2,7 @@ PWR_PATH = "pwr" SLIMBUS_PATH = "slimbus" FMRTC_PATH = "rtc6226" BTFMCODEC_PATH = "btfmcodec" +SWR_PATH = "soundwire" # This dictionary holds all the BT modules included in the bt-kernel bt_modules = {} @@ -114,3 +115,23 @@ register_bt_modules( "radio-rtc6226.h", ], ) + +register_bt_modules( + name = "bt_fm_swr", + path = SWR_PATH, + config_opt = "CONFIG_BTFM_SWR", + srcs = [ + "btfm_swr.c", + "btfm_swr.h", + "btfm_swr_slave.c", + "btfm_swr_slave.h", + "btfm_swr_hw_interface.c", + "btfm_swr_hw_interface.h", + ], + deps = [ + ":%b_btpower", ":%b_btfmcodec", ":btfmcodec_headers", + "//vendor/qcom/opensource/audio-kernel:%b_modules", + "//vendor/qcom/opensource/audio-kernel:audio_headers", + ], +) + diff --git a/soundwire/btfm_swr.c b/soundwire/btfm_swr.c index 3b4d049a16..4ba58d6a35 100644 --- a/soundwire/btfm_swr.c +++ b/soundwire/btfm_swr.c @@ -219,7 +219,8 @@ static int btfm_swr_probe(struct swr_device *pdev) goto register_err; } - btfm_swr_class = class_create(THIS_MODULE, "btfmswr-dev"); + //btfm_swr_class = class_create(THIS_MODULE, "btfmswr-dev"); + btfm_swr_class = class_create("btfmswr-dev"); if (IS_ERR(btfm_swr_class)) { BTFMSWR_ERR("%s: coudn't create class\n", __func__); ret = -1; diff --git a/soundwire/btfm_swr.h b/soundwire/btfm_swr.h index d28dab04c1..f1e643d37f 100644 --- a/soundwire/btfm_swr.h +++ b/soundwire/btfm_swr.h @@ -10,7 +10,7 @@ #include #include #include -#include "soc/soundwire.h" +#include #define SWR_SLAVE_COMPATIBLE_STR "btfmswr_slave" diff --git a/target.bzl b/target.bzl index 98f1efb97e..4ab18518c1 100644 --- a/target.bzl +++ b/target.bzl @@ -26,6 +26,7 @@ def define_sun(): "radio-i2c-rtc6226-qca", # "btfm_slim_codec", "btfmcodec", + "bt_fm_swr", ], config_options = [ "CONFIG_MSM_BT_POWER", @@ -33,5 +34,6 @@ def define_sun(): # "CONFIG_SLIM_BTFM_CODEC", "CONFIG_BTFM_CODEC", # "CONFIG_BT_HW_SECURE_DISABLE", + "CONFIG_BTFM_SWR", ] ) From 259db3a70ebf733f286d959b6585c5bca472a70d Mon Sep 17 00:00:00 2001 From: Satish Kumar Kodishala Date: Tue, 21 Nov 2023 15:38:31 +0530 Subject: [PATCH 076/154] Sun: Enable compilation of BT/FM slimbus slave driver Enable compilation of BT/FM slimbus slave driver for Sun. CRs-Fixed: 3672367 Change-Id: I506674f8bc208add5eb25334df6ff369c5c807f4 Signed-off-by: Satish Kumar Kodishala --- Android.mk | 20 ++++++++++---------- bt_kernel_product_board.mk | 2 +- bt_kernel_vendor_board.mk | 4 ++-- target.bzl | 4 ++-- 4 files changed, 15 insertions(+), 15 deletions(-) diff --git a/Android.mk b/Android.mk index d9c4ddfe42..107d71aaf7 100644 --- a/Android.mk +++ b/Android.mk @@ -15,7 +15,7 @@ LOCAL_PATH := $(call my-dir) ifeq ($(call is-board-platform-in-list, taro kalama pineapple blair sun), true) BT_SELECT := CONFIG_MSM_BT_POWER=m -BT_SELECT += CONFIG_SLIM_BTFM_CODEC=n +BT_SELECT += CONFIG_SLIM_BTFM_CODEC=m BT_SELECT += CONFIG_I2C_RTC6226_QCA=m BT_SELECT += CONFIG_BTFM_SWR=m @@ -29,7 +29,7 @@ LOCAL_PATH := $(call my-dir) LOCAL_MODULE_DDK_BUILD := true LOCAL_MODULE_KO_DIRS := pwr/btpower.ko LOCAL_MODULE_KO_DIRS += rtc6226/radio-i2c-rtc6226-qca.ko -#LOCAL_MODULE_KO_DIRS += slimbus/btfm_slim_codec.ko +LOCAL_MODULE_KO_DIRS += slimbus/btfm_slim_codec.ko LOCAL_MODULE_KO_DIRS += soundwire/bt_fm_swr.ko ifneq ($(TARGET_BOARD_PLATFORM), pineapple) @@ -106,14 +106,14 @@ LOCAL_MODULE_DEBUG_ENABLE := true LOCAL_MODULE_PATH := $(KERNEL_MODULES_OUT) include $(DLKM_DIR)/Build_external_kernelmodule.mk ############################ slimbus with BTFM CODEC Driver ################# -#include $(CLEAR_VARS) -#LOCAL_SRC_FILES := $(BT_SRC_FILES) -#LOCAL_MODULE := btfm_slim_codec.ko -#LOCAL_MODULE_KBUILD_NAME := slimbus/btfm_slim_codec.ko -#LOCAL_MODULE_TAGS := optional -#LOCAL_MODULE_DEBUG_ENABLE := true -#LOCAL_MODULE_PATH := $(KERNEL_MODULES_OUT) -#include $(DLKM_DIR)/Build_external_kernelmodule.mk +include $(CLEAR_VARS) +LOCAL_SRC_FILES := $(BT_SRC_FILES) +LOCAL_MODULE := btfm_slim_codec.ko +LOCAL_MODULE_KBUILD_NAME := slimbus/btfm_slim_codec.ko +LOCAL_MODULE_TAGS := optional +LOCAL_MODULE_DEBUG_ENABLE := true +LOCAL_MODULE_PATH := $(KERNEL_MODULES_OUT) +include $(DLKM_DIR)/Build_external_kernelmodule.mk endif ################################ rtc6226 ################################ include $(CLEAR_VARS) diff --git a/bt_kernel_product_board.mk b/bt_kernel_product_board.mk index 7fdba5f94b..54f52b8f3a 100644 --- a/bt_kernel_product_board.mk +++ b/bt_kernel_product_board.mk @@ -1,6 +1,6 @@ # Build BT kernel drivers PRODUCT_PACKAGES += $(KERNEL_MODULES_OUT)/btpower.ko -#PRODUCT_PACKAGES += $(KERNEL_MODULES_OUT)/btfm_slim_codec.ko +PRODUCT_PACKAGES += $(KERNEL_MODULES_OUT)/btfm_slim_codec.ko PRODUCT_PACKAGES += $(KERNEL_MODULES_OUT)/radio-i2c-rtc6226-qca.ko PRODUCT_PACKAGES += $(KERNEL_MODULES_OUT)/btfmcodec.ko PRODUCT_PACKAGES += $(KERNEL_MODULES_OUT)/bt_fm_swr.ko diff --git a/bt_kernel_vendor_board.mk b/bt_kernel_vendor_board.mk index e384cfaf81..24ae02b76a 100644 --- a/bt_kernel_vendor_board.mk +++ b/bt_kernel_vendor_board.mk @@ -4,7 +4,7 @@ ifeq ($(TARGET_USES_QMAA),true) ifeq ($(TARGET_USES_QMAA_OVERRIDE_BLUETOOTH), true) ifeq ($(call is-board-platform-in-list,$(TARGET_BOARD_PLATFORM)),true) BT_KERNEL_DRIVER := $(KERNEL_MODULES_OUT)/btpower.ko - #BT_KERNEL_DRIVER += $(KERNEL_MODULES_OUT)/btfm_slim_codec.ko + BT_KERNEL_DRIVER += $(KERNEL_MODULES_OUT)/btfm_slim_codec.ko BT_KERNEL_DRIVER += $(KERNEL_MODULES_OUT)/radio-i2c-rtc6226-qca.ko ifneq ($(TARGET_BOARD_PLATFORM), pineapple) BT_KERNEL_DRIVER += $(KERNEL_MODULES_OUT)/btfmcodec.ko @@ -16,7 +16,7 @@ ifeq ($(TARGET_USES_QMAA),true) else ifeq ($(call is-board-platform-in-list,$(TARGET_BOARD_PLATFORM)),true) BT_KERNEL_DRIVER := $(KERNEL_MODULES_OUT)/btpower.ko - #BT_KERNEL_DRIVER += $(KERNEL_MODULES_OUT)/btfm_slim_codec.ko + BT_KERNEL_DRIVER += $(KERNEL_MODULES_OUT)/btfm_slim_codec.ko BT_KERNEL_DRIVER += $(KERNEL_MODULES_OUT)/radio-i2c-rtc6226-qca.ko ifneq ($(TARGET_BOARD_PLATFORM), pineapple) BT_KERNEL_DRIVER += $(KERNEL_MODULES_OUT)/btfmcodec.ko diff --git a/target.bzl b/target.bzl index 4ab18518c1..1db1e13aca 100644 --- a/target.bzl +++ b/target.bzl @@ -24,14 +24,14 @@ def define_sun(): modules = [ "btpower", "radio-i2c-rtc6226-qca", - # "btfm_slim_codec", + "btfm_slim_codec", "btfmcodec", "bt_fm_swr", ], config_options = [ "CONFIG_MSM_BT_POWER", "CONFIG_I2C_RTC6226_QCA", - # "CONFIG_SLIM_BTFM_CODEC", + "CONFIG_SLIM_BTFM_CODEC", "CONFIG_BTFM_CODEC", # "CONFIG_BT_HW_SECURE_DISABLE", "CONFIG_BTFM_SWR", From 4124f443c73f959c9c428ef5079adc2d8605ed79 Mon Sep 17 00:00:00 2001 From: Girish BN Date: Wed, 22 Nov 2023 00:05:45 +0530 Subject: [PATCH 077/154] IOCTL synchronization issue Fix IOCTL synchronization issue between UWB and BT Client(s) CRs-Fixed: 3663940 Change-Id: I7fac93e54086aeab2058798992955b58a4399d40 Signed-off-by: Girish BN --- include/btpower.h | 31 ++++- pwr/btpower.c | 310 +++++++++++++++++++++++++++++++++++++++------- 2 files changed, 292 insertions(+), 49 deletions(-) diff --git a/include/btpower.h b/include/btpower.h index 060753339b..2994d86a9c 100644 --- a/include/btpower.h +++ b/include/btpower.h @@ -11,7 +11,9 @@ #include #include #include +#include +#define BTPWR_MAX_CLIENTS 6 /* * voltage regulator information required for configuring the * bluetooth chipset @@ -51,6 +53,22 @@ enum ssr_states { REG_UWB_PID, }; +enum plt_pwr_state { + POWER_ON_BT = 0, + POWER_OFF_BT, + POWER_ON_UWB, + POWER_OFF_UWB, + POWER_ON_BT_RETENION, + POWER_ON_UWB_RETENION, +}; + +enum { + PWR_WAITING_RSP, + PWR_RSP_RECV, + PWR_FAIL_RSP_RECV, + PWR_CLIENT_KILLED, +}; + struct log_index { int init; int crash; @@ -130,10 +148,15 @@ struct platform_pwr_data { enum ssr_states sub_state; enum ssr_states wrkq_signal_state; struct workqueue_struct *workq; - struct work_struct bt_wq; - struct work_struct uwb_wq; struct device_node *bt_of_node; struct device_node *uwb_of_node; + struct work_struct bt_wq; + struct work_struct uwb_wq; + wait_queue_head_t rsp_wait_q[BTPWR_MAX_CLIENTS]; + uint8_t wait_status[BTPWR_MAX_CLIENTS]; + struct work_struct wq_pwr_voting; + struct sk_buff_head rxq; + struct mutex pwr_mtx; }; int btpower_register_slimdev(struct device *dev); @@ -141,6 +164,10 @@ int btpower_get_chipset_version(void); int btpower_aop_mbox_init(struct platform_pwr_data *pdata); int bt_aop_pdc_reconfig(struct platform_pwr_data *pdata); +static char const *pwr_req[] = {"POWER_ON_BT", "POWER_OFF_BT", + "POWER_OFF_BT", "POWER_OFF_UWB", + "POWER_ON_BT_RETENION", "POWER_ON_UWB_RETENION"}; + #define WLAN_SW_CTRL_GPIO "qcom,wlan-sw-ctrl-gpio" #define BT_CMD_SLIM_TEST 0xbfac #define BT_CMD_PWR_CTRL 0xbfad diff --git a/pwr/btpower.c b/pwr/btpower.c index eb059ba94f..7d91b8df53 100644 --- a/pwr/btpower.c +++ b/pwr/btpower.c @@ -15,6 +15,7 @@ #include #include #include +#include #include #include #include @@ -25,6 +26,11 @@ #include #include #include +#include +#include +#include +#include +#include #include #include #include @@ -307,16 +313,18 @@ static struct class *bt_class; static int bt_major; static int soc_id; static bool probe_finished; +static struct workqueue_struct *workq = NULL; +struct device_node *bt_of_node, *uwb_of_node; const struct pwr_data *data; +u8 client_rsp_q[2]; +char bt_arg[ ][20] = {"power off BT", "power on BT", "BT power retention"}; +char uwb_arg[ ][20] = {"power off UWB", "power on UWB", "UWB power retention"}; +char pwr_states[ ][40] = {"Both Sub-System powered OFF", "BT powered ON", "UWB powered ON", "Both Sub-System powered ON"}; +char ssr_state[ ][40] = {"No SSR on Sub-Sytem", "SSR on BT", "SSR Completed on BT", "SSR on UWB", "SSR Completed on UWB"}; +char reg_mode[ ][25] = {"vote off", "vote on", "vote for retention"}; -char *bt_arg[20] = {"power off BT", "power on BT", "BT power retention"}; -char *uwb_arg[20] = {"power off UWB", "power on UWB", "UWB power retention"}; -char *pwr_states[40] = {"Both Sub-System powered OFF", "BT powered ON", - "UWB powered ON", "Both Sub-System powered ON"}; -char *ssr_state[40] = {"No SSR on Sub-Sytem", "SSR on BT", - "SSR Completed on BT", "SSR on UWB", - "SSR Completed on UWB"}; -char *reg_mode[25] = {"vote off", "vote on", "vote for retention"}; +#define TIMEOUT 5000 +static void bt_power_vote(struct work_struct *work); static struct { int platform_state[BT_POWER_SRC_SIZE]; @@ -1517,16 +1525,25 @@ static int bt_power_probe(struct platform_device *pdev) pwr_data->pdev = pdev; pwr_data->is_ganges_dt = of_property_read_bool(pdev->dev.of_node, - "qcom,peach-bt"); + "qcom,peach-bt"); + pr_info("%s is_ganges_dt %d\n", __func__, pwr_data->is_ganges_dt); if (pwr_data->is_ganges_dt) { - pwr_data->workq = alloc_workqueue("btpwrwq", WQ_HIGHPRI, WQ_DFL_ACTIVE); - if (!pwr_data->workq) { - pr_err("%s: Failed to create workqueue\n", __func__); + workq = alloc_workqueue("workq", WQ_HIGHPRI, WQ_DFL_ACTIVE); + if (!workq) { + pr_err("%s: Failed to creat the Work Queue (workq)\n", + __func__); return -ENOMEM; } + INIT_WORK(&pwr_data->uwb_wq, uwb_signal_handler); INIT_WORK(&pwr_data->bt_wq, bt_signal_handler); + INIT_WORK(&pwr_data->wq_pwr_voting, bt_power_vote); + for (itr = 0; itr < BTPWR_MAX_CLIENTS; itr++) { + init_waitqueue_head(&pwr_data->rsp_wait_q[itr]); + } + skb_queue_head_init(&pwr_data->rxq); + mutex_init(&pwr_data->pwr_mtx); } perisec_cnss_bt_hw_disable_check(pwr_data); @@ -1676,16 +1693,18 @@ static int get_sub_state(void) return pwr_data->sub_state; } -void power_enable(int SubSystemType) +int power_enable (enum SubSystem SubSystemType) { + int ret; + switch (get_pwr_state()) { case IDLE: - power_regulators(PLATFORM_CORE, POWER_ENABLE); + ret = power_regulators(PLATFORM_CORE, POWER_ENABLE); if (SubSystemType == BLUETOOTH) { - power_regulators(BT_CORE, POWER_ENABLE); + ret = power_regulators(BT_CORE, POWER_ENABLE); update_pwr_state(BT_ON); } else { - power_regulators(UWB_CORE, POWER_ENABLE); + ret = power_regulators(UWB_CORE, POWER_ENABLE); update_pwr_state(UWB_ON); } break; @@ -1693,25 +1712,26 @@ void power_enable(int SubSystemType) if (SubSystemType == BLUETOOTH) { pr_err("%s: BT Regulators already Voted-On\n", __func__); - return; + return 0; } - power_regulators(UWB_CORE, POWER_ENABLE); + ret = power_regulators(UWB_CORE, POWER_ENABLE); update_pwr_state(ALL_CLIENTS_ON); break; case UWB_ON: if (SubSystemType == UWB) { pr_err("%s: UWB Regulators already Voted-On\n", __func__); - return; + return 0; } - power_regulators(BT_CORE, POWER_ENABLE); + ret = power_regulators(BT_CORE, POWER_ENABLE); update_pwr_state(ALL_CLIENTS_ON); break; case ALL_CLIENTS_ON: pr_err("%s: Both BT and UWB Regulators already Voted-On\n", __func__); - return; + return 0; } + return ret; } void send_signal_to_subsystem(int SubSystemType, int state) @@ -1723,30 +1743,32 @@ void send_signal_to_subsystem(int SubSystemType, int state) queue_work(pwr_data->workq, &pwr_data->uwb_wq); } -void power_disable(int SubSystemType) +int power_disable (enum SubSystem SubSystemType) { + int ret = 0; + switch (get_pwr_state()) { case IDLE: pr_err("%s: both BT and UWB regulators already voted-Off\n", __func__); - return; + return 0; case ALL_CLIENTS_ON: if (SubSystemType == BLUETOOTH) { - power_regulators(BT_CORE, POWER_DISABLE); + ret = power_regulators(BT_CORE, POWER_DISABLE); update_pwr_state(UWB_ON); - if (get_sub_state() == SSR_ON_BT) { - power_regulators(UWB_CORE, POWER_DISABLE); - power_regulators(PLATFORM_CORE, POWER_DISABLE); + if(get_sub_state() == SSR_ON_BT) { + ret = power_regulators(UWB_CORE, POWER_DISABLE); + ret = power_regulators(PLATFORM_CORE, POWER_DISABLE); update_pwr_state(IDLE); update_sub_state(SUB_STATE_IDLE); send_signal_to_subsystem(UWB, BT_SSR_COMPLETED); } } else { - power_regulators(UWB_CORE, POWER_DISABLE); + ret = power_regulators(UWB_CORE, POWER_DISABLE); update_pwr_state(BT_ON); - if (get_sub_state() == SSR_ON_UWB) { - power_regulators(BT_CORE, POWER_DISABLE); - power_regulators(PLATFORM_CORE, POWER_DISABLE); + if(get_sub_state() == SSR_ON_UWB) { + ret = power_regulators(BT_CORE, POWER_DISABLE); + ret = power_regulators(PLATFORM_CORE, POWER_DISABLE); update_pwr_state(IDLE); update_sub_state(SUB_STATE_IDLE); send_signal_to_subsystem(BLUETOOTH, @@ -1757,24 +1779,25 @@ void power_disable(int SubSystemType) case UWB_ON: if (SubSystemType == BLUETOOTH) { pr_err("%s: BT Regulator already Voted-Off\n", __func__); - return; + return -1; } - power_regulators(UWB_CORE, POWER_DISABLE); - power_regulators(PLATFORM_CORE, POWER_DISABLE); + ret = power_regulators(UWB_CORE, POWER_DISABLE); + ret = power_regulators(PLATFORM_CORE, POWER_DISABLE); update_pwr_state(IDLE); update_sub_state(SUB_STATE_IDLE); break; case BT_ON: if (SubSystemType == UWB) { pr_err("%s: UWB Regulator already Voted-Off\n", __func__); - return; + return -1; } - power_regulators(BT_CORE, POWER_DISABLE); - power_regulators(PLATFORM_CORE, POWER_DISABLE); + ret = power_regulators(BT_CORE, POWER_DISABLE); + ret = power_regulators(PLATFORM_CORE, POWER_DISABLE); update_pwr_state(IDLE); update_sub_state(SUB_STATE_IDLE); break; } + return ret; } static int client_state_notified(int SubSystemType) @@ -1873,10 +1896,132 @@ void log_power_src_val(void) set_pwr_srcs_status(&pwr_data->uwb_vregs[itr], UWB_CORE); } + +int btpower_retenion(enum plt_pwr_state client) +{ + int ret; + + if (client == POWER_ON_BT_RETENION) { + ret = power_regulators(PLATFORM_CORE, POWER_RETENTION); + ret = power_regulators(BT_CORE, POWER_RETENTION); + } else { + ret = power_regulators(PLATFORM_CORE, POWER_RETENTION); + ret = power_regulators(UWB_CORE, POWER_RETENTION); + } + + return ret; +} + +int btpower_off(enum plt_pwr_state client) +{ + return power_disable((client == POWER_OFF_BT) ? BLUETOOTH : UWB); +} + +int btpower_on(enum plt_pwr_state client) +{ + int ret = 0; + + if (client == POWER_ON_BT) { + if (get_sub_state() == SSR_ON_UWB) { + pr_err("%s: SSR_ON_UWB not allowing to BT POWER ON\n", __func__); + return -1; + } + ret = power_enable(BLUETOOTH); + } else { + if (get_sub_state() == SSR_ON_BT) { + pr_err("%s: SSR_ON_BT not allowing to UWB POWER ON\n", __func__); + return -1; + } + ret = power_enable(UWB); + } + + return ret; +} + +int STREAM_TO_UINT32 (struct sk_buff *skb) +{ + return (skb->data[0] | (skb->data[1] << 8) | + (skb->data[2] << 16) | (skb->data[3] << 24)); +} + +static void bt_power_vote(struct work_struct *work) +{ + struct sk_buff *skb; + int request; + int ret; + + while (1) { + mutex_lock(&pwr_data->pwr_mtx); + if (!(skb = skb_dequeue(&pwr_data->rxq))) { + mutex_unlock(&pwr_data->pwr_mtx); + break; + } + request = STREAM_TO_UINT32(skb); + skb_pull(skb, sizeof(uint32_t)); + mutex_unlock(&pwr_data->pwr_mtx); + pr_err("%s: request %s", __func__, pwr_req[request]); + pr_err("%s: current state = %s, %s\n", __func__, + pwr_states[(int)get_pwr_state()], ssr_state[(int)get_sub_state()]); + if (request == POWER_ON_BT || request == POWER_ON_UWB) + ret = btpower_on((enum plt_pwr_state)request); + else if (request == POWER_OFF_UWB || request == POWER_OFF_BT) + ret = btpower_off((enum plt_pwr_state)request); + else if (request == POWER_ON_BT_RETENION || request == POWER_ON_UWB_RETENION) + ret = btpower_retenion(request); + + pwr_data->wait_status[request] = ret == 0? PWR_RSP_RECV: PWR_FAIL_RSP_RECV; + wake_up_interruptible(&pwr_data->rsp_wait_q[request]); + pr_err("%s: current state = %s, %s\n", __func__, + pwr_states[(int)get_pwr_state()], ssr_state[(int)get_sub_state()]); + } +} + +int schedule_client_pwr_voting(enum plt_pwr_state request) +{ + struct sk_buff *skb; + wait_queue_head_t *rsp_wait_q; + u8 *status; + int ret = 0; + uint32_t req = (uint32_t)request; + + mutex_lock(&pwr_data->pwr_mtx); + skb = alloc_skb(sizeof(uint32_t), GFP_KERNEL); + + if (!skb) { + pr_err("%s: Unable to creat SK buff\n", __func__); + mutex_unlock(&pwr_data->pwr_mtx); + return -1; + } + + rsp_wait_q = &pwr_data->rsp_wait_q[(u8)request]; + status = &pwr_data->wait_status[(u8)request]; + *status = PWR_WAITING_RSP; + skb_put_data(skb, &req, sizeof(uint32_t)); + skb_queue_tail(&pwr_data->rxq, skb); + schedule_work(&pwr_data->wq_pwr_voting); + mutex_unlock(&pwr_data->pwr_mtx); + ret = wait_event_interruptible_timeout(*rsp_wait_q, (*status) != PWR_WAITING_RSP, + msecs_to_jiffies(TIMEOUT)); + + if (ret == 0) { + pr_err("%s: failed to vote %d due to timeout", __func__, request); + ret = -ETIMEDOUT; + } else { + if (*status == PWR_RSP_RECV) + return 0; + else if (*status == PWR_FAIL_RSP_RECV || *status == PWR_CLIENT_KILLED) + return -1; + } + + return ret; +} + static long bt_ioctl(struct file *file, unsigned int cmd, unsigned long arg) { int ret = 0; int chipset_version = 0; + unsigned int panic_reason = 0; + unsigned short primary_reason = 0, sec_reason = 0; #ifdef CONFIG_MSM_BT_OOBS enum btpower_obs_param clk_cntrl; @@ -1936,10 +2081,46 @@ static long bt_ioctl(struct file *file, unsigned int cmd, unsigned long arg) #endif break; case BT_CMD_PWR_CTRL: - set_pwr_state(BLUETOOTH, (int)arg); + pr_err("%s: BT_CMD_PWR_CTRL cmd voted to %s, current state = %s, %s\n", + __func__, bt_arg[(int)arg], pwr_states[(int)get_pwr_state()], ssr_state[(int)get_sub_state()]); + + switch ((int)arg) { + case POWER_DISABLE: + ret = schedule_client_pwr_voting(POWER_OFF_BT); + pr_err("%s: %s, SSR state = %s\n", __func__, + pwr_states[(int)get_pwr_state()], ssr_state[(int)get_sub_state()]); + break; + case POWER_ENABLE: + ret = schedule_client_pwr_voting(POWER_ON_BT); + pr_err("%s: %s, SSR state = %s\n", __func__, + pwr_states[(int)get_pwr_state()], ssr_state[(int)get_sub_state()]); + break; + case POWER_RETENTION: + ret = schedule_client_pwr_voting(POWER_ON_BT_RETENION); + break; + } break; case UWB_CMD_PWR_CTRL: - set_pwr_state(UWB, (int)arg); + + pr_err("%s: UWB_CMD_PWR_CTRL voted for %s, sub_system count = %s, %s\n", + __func__, uwb_arg[(int)arg], pwr_states[(int)get_pwr_state()], ssr_state[(int)get_sub_state()]); + + switch ((int)arg) { + case POWER_DISABLE: + ret = schedule_client_pwr_voting(POWER_OFF_UWB); + pr_err("%s: %s, SSR state = %s\n", __func__, + pwr_states[(int)get_pwr_state()], ssr_state[(int)get_sub_state()]); + break; + case POWER_ENABLE: + ret = schedule_client_pwr_voting(POWER_ON_UWB); + pr_err("%s: %s, SSR state = %s\n", __func__, + pwr_states[(int)get_pwr_state()], ssr_state[(int)get_sub_state()]); + break; + case POWER_RETENTION: + ret = schedule_client_pwr_voting(POWER_ON_UWB_RETENION); + pr_err("%s:BT Power Retention done", __func__); + break; + } break; case BT_CMD_REGISTRATION: client_notified(BLUETOOTH, (int)arg); @@ -2006,8 +2187,14 @@ static long bt_ioctl(struct file *file, unsigned int cmd, unsigned long arg) btpower_enable_ipa_vreg(pwr_data); break; case BT_CMD_KERNEL_PANIC: - pr_info("%s: BT_CMD_KERNEL_PANIC\n", __func__); - panic("subsys-restart: Resetting the SoC - Bluetooth crashed\n"); + pr_err("%s: BT_CMD_KERNEL_PANIC\n", __func__); + panic_reason = (unsigned int)arg; + primary_reason = panic_reason & 0xFFFF; + sec_reason = (panic_reason & 0xFFFF0000) >> 16; + pr_err("%s: BT kernel panic primary reason [0x%04x] secondary reason [0x%04x]\n", + __func__, primary_reason, sec_reason); + panic("subsys-restart: Resetting the SoC - BT crashed primary reason [0x%04x] secondary reason [0x%04x]\n", + primary_reason, sec_reason); break; default: return -ENOIOCTLCMD; @@ -2022,19 +2209,48 @@ static int bt_power_release(struct inode *inode, struct file *file) return -EAGAIN; } + pwr_data->reftask = get_current(); + pwr_data->reftask = get_current(); if (pwr_data->reftask_bt != NULL) { if (pwr_data->reftask->tgid == pwr_data->reftask_bt->tgid) { pr_err("%s called by BT service(PID-%d)\n", __func__, pwr_data->reftask->tgid); - power_disable(BLUETOOTH); - } - } else if (pwr_data->reftask_uwb != NULL) { - if (pwr_data->reftask->tgid == pwr_data->reftask_uwb->tgid) { +/* + if(get_pwr_state() == BT_ON) + { + bt_regulators_pwr(POWER_DISABLE); + platform_regulators_pwr(POWER_DISABLE); + update_pwr_state(IDLE); + + } + else if (get_pwr_state() == ALL_CLIENTS_ON) + { + bt_regulators_pwr(POWER_DISABLE); + update_pwr_state(UWB_ON); + } + */ } + + } + else if (pwr_data->reftask_uwb != NULL) + { + if (pwr_data->reftask->tgid == pwr_data->reftask_uwb->tgid) + { pr_err("%s called by uwb service(PID-%d)\n", __func__, pwr_data->reftask->tgid); - power_disable(UWB); - } + + /* if(get_pwr_state() == UWB_ON) + { + uwb_regulators_pwr(POWER_DISABLE); + platform_regulators_pwr(POWER_DISABLE); + update_pwr_state(IDLE); + } + else if (get_pwr_state() == ALL_CLIENTS_ON) + { + uwb_regulators_pwr(POWER_DISABLE); + update_pwr_state(BT_ON); + } + */ } } return 0; } From 071d92d4ac06fa53fa3c51763a1bc19592453451 Mon Sep 17 00:00:00 2001 From: Balakrishna Godavarthi Date: Wed, 29 Nov 2023 12:06:57 +0530 Subject: [PATCH 078/154] bt-kernel: Enable drivers based on target support This change enables below drivers for below targets. Pineapple: 1. bt_fm_slim sun: 1. bt_fm_swr 2. btfm_slim_codec 3. btfmcodec Change-Id: Ic3abd83b386836d9ceb3d97141a91199339af9ee Signed-off-by: Balakrishna Godavarthi --- Android.mk | 49 ++++++++++++++++++++++++-------------- bt_kernel_product_board.mk | 6 ++++- bt_kernel_vendor_board.mk | 16 ++++++++----- target.bzl | 6 ++--- 4 files changed, 48 insertions(+), 29 deletions(-) diff --git a/Android.mk b/Android.mk index 107d71aaf7..ae965156ca 100644 --- a/Android.mk +++ b/Android.mk @@ -15,9 +15,8 @@ LOCAL_PATH := $(call my-dir) ifeq ($(call is-board-platform-in-list, taro kalama pineapple blair sun), true) BT_SELECT := CONFIG_MSM_BT_POWER=m -BT_SELECT += CONFIG_SLIM_BTFM_CODEC=m BT_SELECT += CONFIG_I2C_RTC6226_QCA=m -BT_SELECT += CONFIG_BTFM_SWR=m + ifeq ($(TARGET_KERNEL_DLKM_SECURE_MSM_OVERRIDE), true) ifeq ($(ENABLE_PERIPHERAL_STATE_UTILS), true) @@ -29,12 +28,17 @@ LOCAL_PATH := $(call my-dir) LOCAL_MODULE_DDK_BUILD := true LOCAL_MODULE_KO_DIRS := pwr/btpower.ko LOCAL_MODULE_KO_DIRS += rtc6226/radio-i2c-rtc6226-qca.ko + +ifeq ($(TARGET_BOARD_PLATFORM), sun) +BT_SELECT += CONFIG_BTFM_CODEC=m +BT_SELECT += CONFIG_BTFM_SWR=m +BT_SELECT += CONFIG_SLIM_BTFM_CODEC=m +LOCAL_MODULE_KO_DIRS += btfmcodec/btfmcodec.ko LOCAL_MODULE_KO_DIRS += slimbus/btfm_slim_codec.ko LOCAL_MODULE_KO_DIRS += soundwire/bt_fm_swr.ko - -ifneq ($(TARGET_BOARD_PLATFORM), pineapple) -BT_SELECT += CONFIG_BTFM_CODEC=m -LOCAL_MODULE_KO_DIRS += btfmcodec/btfmcodec.ko +else +BT_SELECT += CONFIG_BTFM_SLIM=m +LOCAL_MODULE_KO_DIRS += slimbus/bt_fm_slim.ko endif # This makefile is only for DLKM @@ -114,17 +118,7 @@ LOCAL_MODULE_TAGS := optional LOCAL_MODULE_DEBUG_ENABLE := true LOCAL_MODULE_PATH := $(KERNEL_MODULES_OUT) include $(DLKM_DIR)/Build_external_kernelmodule.mk -endif -################################ rtc6226 ################################ -include $(CLEAR_VARS) -LOCAL_SRC_FILES := $(BT_SRC_FILES) -LOCAL_MODULE := radio-i2c-rtc6226-qca.ko -LOCAL_MODULE_KBUILD_NAME := rtc6226/radio-i2c-rtc6226-qca.ko -LOCAL_MODULE_TAGS := optional -LOCAL_MODULE_DEBUG_ENABLE := true -LOCAL_MODULE_PATH := $(KERNEL_MODULES_OUT) -include $(DLKM_DIR)/Build_external_kernelmodule.mk -################################ slimbus ################################ +################################ soundwire ################################ include $(CLEAR_VARS) LOCAL_SRC_FILES := $(BT_SRC_FILES) LOCAL_MODULE := bt_fm_swr.ko @@ -136,7 +130,26 @@ LOCAL_MODULE_DEBUG_ENABLE := true #LOCAL_ADDITIONAL_DEPENDENCIES += $(call intermediates-dir-for,DLKM,swr_dlkm)/Module.symvers LOCAL_MODULE_PATH := $(KERNEL_MODULES_OUT) include $(DLKM_DIR)/Build_external_kernelmodule.mk -########################################################### +else +################################ slimbus ################################ +include $(CLEAR_VARS) +LOCAL_SRC_FILES := $(BT_SRC_FILES) +LOCAL_MODULE := bt_fm_slim.ko +LOCAL_MODULE_KBUILD_NAME := slimbus/bt_fm_slim.ko +LOCAL_MODULE_TAGS := optional +LOCAL_MODULE_DEBUG_ENABLE := true +LOCAL_MODULE_PATH := $(KERNEL_MODULES_OUT) +include $(DLKM_DIR)/Build_external_kernelmodule.mk +endif +################################ rtc6226 ################################ +include $(CLEAR_VARS) +LOCAL_SRC_FILES := $(BT_SRC_FILES) +LOCAL_MODULE := radio-i2c-rtc6226-qca.ko +LOCAL_MODULE_KBUILD_NAME := rtc6226/radio-i2c-rtc6226-qca.ko +LOCAL_MODULE_TAGS := optional +LOCAL_MODULE_DEBUG_ENABLE := true +LOCAL_MODULE_PATH := $(KERNEL_MODULES_OUT) +include $(DLKM_DIR)/Build_external_kernelmodule.mk endif # DLKM check diff --git a/bt_kernel_product_board.mk b/bt_kernel_product_board.mk index 54f52b8f3a..b364824494 100644 --- a/bt_kernel_product_board.mk +++ b/bt_kernel_product_board.mk @@ -1,6 +1,10 @@ # Build BT kernel drivers PRODUCT_PACKAGES += $(KERNEL_MODULES_OUT)/btpower.ko -PRODUCT_PACKAGES += $(KERNEL_MODULES_OUT)/btfm_slim_codec.ko PRODUCT_PACKAGES += $(KERNEL_MODULES_OUT)/radio-i2c-rtc6226-qca.ko +ifeq ($(TARGET_BOARD_PLATFORM), sun) PRODUCT_PACKAGES += $(KERNEL_MODULES_OUT)/btfmcodec.ko +PRODUCT_PACKAGES += $(KERNEL_MODULES_OUT)/btfm_slim_codec.ko PRODUCT_PACKAGES += $(KERNEL_MODULES_OUT)/bt_fm_swr.ko +else +BT_KERNEL_DRIVER += $(KERNEL_MODULES_OUT)/bt_fm_slim.ko +endif diff --git a/bt_kernel_vendor_board.mk b/bt_kernel_vendor_board.mk index 24ae02b76a..4c39c810ea 100644 --- a/bt_kernel_vendor_board.mk +++ b/bt_kernel_vendor_board.mk @@ -4,24 +4,28 @@ ifeq ($(TARGET_USES_QMAA),true) ifeq ($(TARGET_USES_QMAA_OVERRIDE_BLUETOOTH), true) ifeq ($(call is-board-platform-in-list,$(TARGET_BOARD_PLATFORM)),true) BT_KERNEL_DRIVER := $(KERNEL_MODULES_OUT)/btpower.ko - BT_KERNEL_DRIVER += $(KERNEL_MODULES_OUT)/btfm_slim_codec.ko BT_KERNEL_DRIVER += $(KERNEL_MODULES_OUT)/radio-i2c-rtc6226-qca.ko - ifneq ($(TARGET_BOARD_PLATFORM), pineapple) + ifeq ($(TARGET_BOARD_PLATFORM), sun) BT_KERNEL_DRIVER += $(KERNEL_MODULES_OUT)/btfmcodec.ko - endif + BT_KERNEL_DRIVER += $(KERNEL_MODULES_OUT)/btfm_slim_codec.ko BT_KERNEL_DRIVER += $(KERNEL_MODULES_OUT)/bt_fm_swr.ko + else + BT_KERNEL_DRIVER += $(KERNEL_MODULES_OUT)/bt_fm_slim.ko + endif BOARD_VENDOR_KERNEL_MODULES += $(BT_KERNEL_DRIVER) endif endif else ifeq ($(call is-board-platform-in-list,$(TARGET_BOARD_PLATFORM)),true) BT_KERNEL_DRIVER := $(KERNEL_MODULES_OUT)/btpower.ko - BT_KERNEL_DRIVER += $(KERNEL_MODULES_OUT)/btfm_slim_codec.ko BT_KERNEL_DRIVER += $(KERNEL_MODULES_OUT)/radio-i2c-rtc6226-qca.ko - ifneq ($(TARGET_BOARD_PLATFORM), pineapple) + ifeq ($(TARGET_BOARD_PLATFORM), sun) BT_KERNEL_DRIVER += $(KERNEL_MODULES_OUT)/btfmcodec.ko - endif + BT_KERNEL_DRIVER += $(KERNEL_MODULES_OUT)/btfm_slim_codec.ko BT_KERNEL_DRIVER += $(KERNEL_MODULES_OUT)/bt_fm_swr.ko + else + BT_KERNEL_DRIVER += $(KERNEL_MODULES_OUT)/bt_fm_slim.ko + endif BOARD_VENDOR_KERNEL_MODULES += $(BT_KERNEL_DRIVER) endif endif diff --git a/target.bzl b/target.bzl index 1db1e13aca..13f40e72e7 100644 --- a/target.bzl +++ b/target.bzl @@ -5,15 +5,13 @@ def define_pineapple(): target = "pineapple", modules = [ "btpower", - #"bt_fm_slim", + "bt_fm_slim", "radio-i2c-rtc6226-qca", - # "btfm_slim_codec", ], config_options = [ "CONFIG_MSM_BT_POWER", - #"CONFIG_BTFM_SLIM", + "CONFIG_BTFM_SLIM", "CONFIG_I2C_RTC6226_QCA", - # "CONFIG_SLIM_BTFM_CODEC", #"CONFIG_BT_HW_SECURE_DISABLE", ] ) From 186f5bd9745168d2d77f2656bf390309e0a3b9b4 Mon Sep 17 00:00:00 2001 From: Girish BN Date: Fri, 1 Dec 2023 18:36:18 +0530 Subject: [PATCH 079/154] Moving Work Queue init calls for all the SOC - Issue seen as Work Queue initializing for specific SOC, now initializing for all the SOC Change-Id: I34051cb21514a7f130be5f077e61af206a581db2 Signed-off-by: Girish BN --- pwr/btpower.c | 34 +++++++++++++++++----------------- 1 file changed, 17 insertions(+), 17 deletions(-) diff --git a/pwr/btpower.c b/pwr/btpower.c index b01a8ad1b2..060d238905 100644 --- a/pwr/btpower.c +++ b/pwr/btpower.c @@ -1526,26 +1526,26 @@ static int bt_power_probe(struct platform_device *pdev) pwr_data->is_ganges_dt = of_property_read_bool(pdev->dev.of_node, "qcom,peach-bt"); - pr_info("%s is_ganges_dt %d\n", __func__, pwr_data->is_ganges_dt); + pr_info("%s: is_ganges_dt = %d\n", __func__, pwr_data->is_ganges_dt); - if (pwr_data->is_ganges_dt) { - workq = alloc_workqueue("workq", WQ_HIGHPRI, WQ_DFL_ACTIVE); - if (!workq) { - pr_err("%s: Failed to creat the Work Queue (workq)\n", - __func__); - return -ENOMEM; - } - - INIT_WORK(&pwr_data->uwb_wq, uwb_signal_handler); - INIT_WORK(&pwr_data->bt_wq, bt_signal_handler); - INIT_WORK(&pwr_data->wq_pwr_voting, bt_power_vote); - for (itr = 0; itr < BTPWR_MAX_CLIENTS; itr++) { - init_waitqueue_head(&pwr_data->rsp_wait_q[itr]); - } - skb_queue_head_init(&pwr_data->rxq); - mutex_init(&pwr_data->pwr_mtx); + workq = alloc_workqueue("workq", WQ_HIGHPRI, WQ_DFL_ACTIVE); + if (!workq) { + pr_err("%s: Failed to creat the Work Queue (workq)\n", + __func__); + return -ENOMEM; } + INIT_WORK(&pwr_data->uwb_wq, uwb_signal_handler); + INIT_WORK(&pwr_data->bt_wq, bt_signal_handler); + INIT_WORK(&pwr_data->wq_pwr_voting, bt_power_vote); + + for (itr = 0; itr < BTPWR_MAX_CLIENTS; itr++) { + init_waitqueue_head(&pwr_data->rsp_wait_q[itr]); + } + + skb_queue_head_init(&pwr_data->rxq); + mutex_init(&pwr_data->pwr_mtx); + perisec_cnss_bt_hw_disable_check(pwr_data); if (pdev->dev.of_node) { From 4e9c5ec65c1c9b6bf84798d0dd6d9d70e83bb182 Mon Sep 17 00:00:00 2001 From: Gaurav Kashyap Date: Fri, 1 Dec 2023 13:02:12 -0800 Subject: [PATCH 080/154] bt-kernel: move smcinvoke dependency to the correct header Move the smcinvoke dlkm dependency from TARGET_KERNEL_DLKM_SECURE_MSM_OVERRIDE to TARGET_KERNEL_DLKM_SECUREMSM_QTEE_OVERRIDE. Change-Id: Ie9e0efdf25406c1e0646316c4050a73b79b8342b Signed-off-by: Gaurav Kashyap --- Android.mk | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Android.mk b/Android.mk index ae965156ca..4b29a6a94c 100644 --- a/Android.mk +++ b/Android.mk @@ -18,7 +18,7 @@ BT_SELECT := CONFIG_MSM_BT_POWER=m BT_SELECT += CONFIG_I2C_RTC6226_QCA=m -ifeq ($(TARGET_KERNEL_DLKM_SECURE_MSM_OVERRIDE), true) +ifeq ($(TARGET_KERNEL_DLKM_SECUREMSM_QTEE_OVERRIDE), true) ifeq ($(ENABLE_PERIPHERAL_STATE_UTILS), true) BT_SELECT += CONFIG_BT_HW_SECURE_DISABLE=y endif @@ -61,7 +61,7 @@ BT_SRC_FILES := \ $(wildcard $(LOCAL_PATH)/*) \ $(wildcard $(LOCAL_PATH)/*/*) \ -ifeq ($(TARGET_KERNEL_DLKM_SECURE_MSM_OVERRIDE), true) +ifeq ($(TARGET_KERNEL_DLKM_SECUREMSM_QTEE_OVERRIDE), true) ifeq ($(ENABLE_PERIPHERAL_STATE_UTILS), true) KBUILD_REQUIRED_KOS := smcinvoke_dlkm.ko endif From f6a1cd1e01008ffc07e3dd8e98171b1d8deea6ad Mon Sep 17 00:00:00 2001 From: Hemant Gupta Date: Mon, 18 Dec 2023 22:21:46 +0530 Subject: [PATCH 081/154] For UWB power on logging the wrong status as POWER_OFF_BT Use case: - Turn on UWB. Observed behavior: - Seeing the wrong status as POWER_OFF_BT. Updated behavior: - Update the Kernel log as POWER_ON_UWB. Change-Id: Ia523993d648981ddf9c40465f67e79dc5f1b9d35 Signed-off-by: Girish BN Signed-off-by: Hemant Gupta --- include/btpower.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/include/btpower.h b/include/btpower.h index f0e2238e69..247b09e68d 100644 --- a/include/btpower.h +++ b/include/btpower.h @@ -165,8 +165,8 @@ int btpower_aop_mbox_init(struct platform_pwr_data *pdata); int bt_aop_pdc_reconfig(struct platform_pwr_data *pdata); static char const *pwr_req[] = {"POWER_ON_BT", "POWER_OFF_BT", - "POWER_OFF_BT", "POWER_OFF_UWB", - "POWER_ON_BT_RETENION", "POWER_ON_UWB_RETENION"}; + "POWER_ON_UWB", "POWER_OFF_UWB", + "POWER_ON_BT_RETENION", "POWER_ON_UWB_RETENION"}; #define WLAN_SW_CTRL_GPIO "qcom,wlan-sw-ctrl-gpio" #define BT_CMD_SLIM_TEST 0xbfac From b00b86e5dd9f96ac083afe33a385ca97345a7734 Mon Sep 17 00:00:00 2001 From: Hemant Gupta Date: Tue, 19 Dec 2023 11:41:31 +0530 Subject: [PATCH 082/154] BTPOWER: Fix initialization of workqueue Fix initialization of workqueue CRs-Fixed: 3689241 Change-Id: I614304b639da4dac072872f2bea8a4e2fb80e4d7 Signed-off-by: Hemant Gupta --- pwr/btpower.c | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/pwr/btpower.c b/pwr/btpower.c index 060d238905..91bba338a7 100644 --- a/pwr/btpower.c +++ b/pwr/btpower.c @@ -313,7 +313,6 @@ static struct class *bt_class; static int bt_major; static int soc_id; static bool probe_finished; -static struct workqueue_struct *workq = NULL; struct device_node *bt_of_node, *uwb_of_node; const struct pwr_data *data; u8 client_rsp_q[2]; @@ -1525,11 +1524,11 @@ static int bt_power_probe(struct platform_device *pdev) pwr_data->pdev = pdev; pwr_data->is_ganges_dt = of_property_read_bool(pdev->dev.of_node, - "qcom,peach-bt"); + "qcom,peach-bt"); pr_info("%s: is_ganges_dt = %d\n", __func__, pwr_data->is_ganges_dt); - workq = alloc_workqueue("workq", WQ_HIGHPRI, WQ_DFL_ACTIVE); - if (!workq) { + pwr_data->workq = alloc_workqueue("workq", WQ_HIGHPRI, WQ_DFL_ACTIVE); + if (!pwr_data->workq) { pr_err("%s: Failed to creat the Work Queue (workq)\n", __func__); return -ENOMEM; From a9b9da9c6142435befe6162bfd7a20e8ec7d39d2 Mon Sep 17 00:00:00 2001 From: Franklin Abreu Bueno Date: Thu, 7 Dec 2023 16:31:47 -0800 Subject: [PATCH 083/154] Fix issue where SoC gets turned off before transport cleanup MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit SoC gets powered off before UWB/BT can do their Q2SPI/UART cleanup, causing issues on the next initialization. With this change it will now wait for the other subsystem to finish cleanup before powering off SoC.   Change-Id: I9b196560acbcbb4aff8fd84013e233e16bfcf5d3 Signed-off-by: Franklin Abreu Bueno --- pwr/btpower.c | 11 +---------- 1 file changed, 1 insertion(+), 10 deletions(-) diff --git a/pwr/btpower.c b/pwr/btpower.c index 060d238905..3a887eca15 100644 --- a/pwr/btpower.c +++ b/pwr/btpower.c @@ -1756,21 +1756,12 @@ int power_disable (enum SubSystem SubSystemType) ret = power_regulators(BT_CORE, POWER_DISABLE); update_pwr_state(UWB_ON); if(get_sub_state() == SSR_ON_BT) { - ret = power_regulators(UWB_CORE, POWER_DISABLE); - ret = power_regulators(PLATFORM_CORE, POWER_DISABLE); - update_pwr_state(IDLE); - update_sub_state(SUB_STATE_IDLE); - send_signal_to_subsystem(UWB, - BT_SSR_COMPLETED); + send_signal_to_subsystem(UWB, BT_SSR_COMPLETED); } } else { ret = power_regulators(UWB_CORE, POWER_DISABLE); update_pwr_state(BT_ON); if(get_sub_state() == SSR_ON_UWB) { - ret = power_regulators(BT_CORE, POWER_DISABLE); - ret = power_regulators(PLATFORM_CORE, POWER_DISABLE); - update_pwr_state(IDLE); - update_sub_state(SUB_STATE_IDLE); send_signal_to_subsystem(BLUETOOTH, (SIGIO_NOTIFICATION_SIGNAL|SIGIO_UWB_SSR_COMPLETED)); } From 1a223cf1a8a7baed11295413c242e2b451b04ee4 Mon Sep 17 00:00:00 2001 From: Balakrishna Godavarthi Date: Sat, 23 Dec 2023 06:58:05 +0530 Subject: [PATCH 084/154] btpower: Update driver to support multi client handling This changes handles below. 1. Retention voting from multi clients 2. Access control. Change-Id: I7869d459a78bf0a8a47c7f2d6c91b93ad1435bd2 --- include/btpower.h | 136 +++++++++++- pwr/btpower.c | 549 ++++++++++++++++++++++++++++++++-------------- 2 files changed, 512 insertions(+), 173 deletions(-) diff --git a/include/btpower.h b/include/btpower.h index 247b09e68d..da35be4e41 100644 --- a/include/btpower.h +++ b/include/btpower.h @@ -13,7 +13,6 @@ #include #include -#define BTPWR_MAX_CLIENTS 6 /* * voltage regulator information required for configuring the * bluetooth chipset @@ -22,7 +21,8 @@ enum power_modes { POWER_DISABLE = 0, POWER_ENABLE, - POWER_RETENTION + POWER_RETENTION, + POWER_DISABLE_RETENTION, }; enum SubSystem { @@ -37,6 +37,88 @@ enum power_states { ALL_CLIENTS_ON, }; +enum retention_states { + /* Default state */ + RETENTION_IDLE = 0, + /* When BT is only client and it is in retention_state */ + BT_IN_RETENTION, + /* BT is retention mode and UWB powered ON triggered */ + BT_OUT_OF_RETENTION, + /* When UWB is only client and it is in retention_state */ + UWB_IN_RETENTION, + /* UWB is retention mode and BT powered ON triggered */ + UWB_OUT_OF_RETENTION, + /* Both clients are voted for retention */ + BOTH_CLIENTS_IN_RETENTION, +}; + +enum grant_return_values { + ACCESS_GRANTED = 0, + ACCESS_DENIED = 1, + ACCESS_RELEASED = 2, + ACCESS_DISALLOWED = -1, +}; + +enum grant_states { + /* Default state */ + NO_GRANT_FOR_ANY_SS = 0, + NO_OTHER_CLIENT_WAITING_FOR_GRANT, + BT_HAS_GRANT, + UWB_HAS_GRANT, + BT_WAITING_FOR_GRANT, + UWB_WAITING_FOR_GRANT, +}; + +static inline char *ConvertGrantRetToString(enum grant_return_values state) +{ + switch (state) { + case ACCESS_GRANTED: { + return "ACCESS_GRANTED"; + break; + } case ACCESS_DENIED: { + return "ACCESS_DENIED"; + break; + } case ACCESS_RELEASED: { + return "ACCESS_RELEASED"; + break; + } case ACCESS_DISALLOWED: { + return "ACCESS_DISALLOWED"; + break; + } default: { + return "INVALID State"; + break; + } + } +} + +static inline char *ConvertGrantToString(enum grant_states state) +{ + switch (state) { + case NO_GRANT_FOR_ANY_SS: { + return "NO_GRANT_FOR_ANY_SS"; + break; + } case NO_OTHER_CLIENT_WAITING_FOR_GRANT:{ + return "NO_OTHER_CLIENT_WAITING_FOR_GRANT"; + break; + } case BT_HAS_GRANT : { + return "BT_HAS_GRANT"; + break; + } case UWB_HAS_GRANT: { + return "UWB_HAS_GRANT"; + break; + } case BT_WAITING_FOR_GRANT : { + return "BT_WAITING_FOR_GRANT"; + break; + } case UWB_WAITING_FOR_GRANT: { + return "UWB_WAITING_FOR_GRANT"; + break; + } default: { + return "INVALID STATE"; + break; + } + } +} + enum cores { BT_CORE = 0, UWB_CORE, @@ -60,12 +142,17 @@ enum plt_pwr_state { POWER_OFF_UWB, POWER_ON_BT_RETENION, POWER_ON_UWB_RETENION, + BT_ACCESS_REQ, + UWB_ACCESS_REQ, + BT_RELEASE_ACCESS, + UWB_RELEASE_ACCESS, + BT_MAX_PWR_STATE, }; enum { - PWR_WAITING_RSP, - PWR_RSP_RECV, - PWR_FAIL_RSP_RECV, + PWR_WAITING_RSP = -2, + PWR_RSP_RECV = 0, + PWR_FAIL_RSP_RECV = -1, PWR_CLIENT_KILLED, }; @@ -101,6 +188,15 @@ struct bt_power_clk_data { bool is_enabled; /* is this clock enabled? */ }; +struct btpower_state_machine { + struct mutex state_machine_lock; + enum power_states power_state; + enum retention_states retention_mode; + enum grant_states grant_state; + enum grant_states grant_pending; +}; + +#define BTPWR_MAX_REQ BT_MAX_PWR_STATE /* * Platform data for the bluetooth power driver. */ @@ -144,7 +240,7 @@ struct platform_pwr_data { struct task_struct *reftask; struct task_struct *reftask_bt; struct task_struct *reftask_uwb; - enum power_states power_state; + struct btpower_state_machine btpower_state; enum ssr_states sub_state; enum ssr_states wrkq_signal_state; struct workqueue_struct *workq; @@ -152,8 +248,8 @@ struct platform_pwr_data { struct device_node *uwb_of_node; struct work_struct bt_wq; struct work_struct uwb_wq; - wait_queue_head_t rsp_wait_q[BTPWR_MAX_CLIENTS]; - uint8_t wait_status[BTPWR_MAX_CLIENTS]; + wait_queue_head_t rsp_wait_q[BTPWR_MAX_REQ]; + int wait_status[BTPWR_MAX_REQ]; struct work_struct wq_pwr_voting; struct sk_buff_head rxq; struct mutex pwr_mtx; @@ -165,8 +261,11 @@ int btpower_aop_mbox_init(struct platform_pwr_data *pdata); int bt_aop_pdc_reconfig(struct platform_pwr_data *pdata); static char const *pwr_req[] = {"POWER_ON_BT", "POWER_OFF_BT", - "POWER_ON_UWB", "POWER_OFF_UWB", - "POWER_ON_BT_RETENION", "POWER_ON_UWB_RETENION"}; + "POWER_ON_UWB", "POWER_OFF_UWB", + "POWER_ON_BT_RETENION", + "POWER_ON_UWB_RETENION", + "BT_ACCESS_REQ", "UWB_ACCESS_REQ", + "BT_RELEASE_ACCESS", "UWB_RELEASE_ACCESS"}; #define WLAN_SW_CTRL_GPIO "qcom,wlan-sw-ctrl-gpio" #define BT_CMD_SLIM_TEST 0xbfac @@ -181,6 +280,8 @@ static char const *pwr_req[] = {"POWER_ON_BT", "POWER_OFF_BT", #define UWB_CMD_PWR_CTRL 0xbfe1 #define BT_CMD_REGISTRATION 0xbfe2 #define UWB_CMD_REGISTRATION 0xbfe3 +#define BT_CMD_ACCESS_CTRL 0xbfe4 +#define UWB_CMD_ACCESS_CTRL 0xbfe5 #ifdef CONFIG_MSM_BT_OOBS #define BT_CMD_OBS_VOTE_CLOCK 0xbfd1 @@ -198,5 +299,18 @@ enum btpower_obs_param { BTPOWER_OBS_DEV_ON, }; #endif - +static const char * const bt_arg[] = {"power off BT", "power on BT", + "BT power retention"}; +static const char * const uwb_arg[]= {"power off UWB", "power on UWB", + "UWB power retention"}; +static const char * const pwr_states[] = {"Both Sub-System powered OFF", "BT powered ON", + "UWB powered ON", + "Both Sub-System powered ON"}; +static const char * const ssr_state[ ] = {"No SSR on Sub-Sytem", "SSR on BT", + "SSR Completed on BT", "SSR on UWB", + "SSR Completed on UWB"}; +static const char * const reg_mode[ ] = {"vote off", "vote on", "vote for retention", "vote off retention"}; +static const char * const retention_mode[] = {"IDLE", "BT_IN_RETENTION", "BT_OUT_OF_RETENTION", + "UWB_IN_RETENTION", "UWB_OUT_OF_RETENTION", + "BOTH_CLIENT_IN_RETENTION"}; #endif /* __LINUX_BLUETOOTH_POWER_H */ diff --git a/pwr/btpower.c b/pwr/btpower.c index 10308c8b5f..352996da63 100644 --- a/pwr/btpower.c +++ b/pwr/btpower.c @@ -62,9 +62,12 @@ #define BTPOWER_MBOX_TIMEOUT_MS 1000 #define XO_CLK_RETRY_COUNT_MAX 5 #define MAX_PROP_SIZE 32 +#define BTPOWER_CONFIG_MAX_TIMEOUT 500 #define SIGIO_OOBS_SINGAL 0x00010000 #define SIGIO_NOTIFICATION_SIGNAL 0x00020000 +#define SIGIO_SOC_ACCESS_SIGNAL 0x00040000 + #define SIGIO_GPIO_HIGH 0x00000001 #define SIGIO_GPIO_LOW 0x00000000 #define SIGIO_SSR_ON_UWB 0x00000001 @@ -308,21 +311,11 @@ static const struct of_device_id bt_power_match_table[] = { static int btpower_enable_ipa_vreg(struct platform_pwr_data *pdata); static struct platform_pwr_data *pwr_data; static bool previous; -static int pwr_state; static struct class *bt_class; static int bt_major; static int soc_id; static bool probe_finished; -struct device_node *bt_of_node, *uwb_of_node; -const struct pwr_data *data; -u8 client_rsp_q[2]; -char bt_arg[ ][20] = {"power off BT", "power on BT", "BT power retention"}; -char uwb_arg[ ][20] = {"power off UWB", "power on UWB", "UWB power retention"}; -char pwr_states[ ][40] = {"Both Sub-System powered OFF", "BT powered ON", "UWB powered ON", "Both Sub-System powered ON"}; -char ssr_state[ ][40] = {"No SSR on Sub-Sytem", "SSR on BT", "SSR Completed on BT", "SSR on UWB", "SSR Completed on UWB"}; -char reg_mode[ ][25] = {"vote off", "vote on", "vote for retention"}; -#define TIMEOUT 5000 static void bt_power_vote(struct work_struct *work); static struct { @@ -437,6 +430,34 @@ static irqreturn_t btpower_host_wake_isr(int irq, void *data) } #endif +static int vreg_configure(struct vreg_data *vreg, bool retention) +{ + int rc = 0; + + if ((vreg->min_vol != 0) && (vreg->max_vol != 0)) { + rc = regulator_set_voltage(vreg->reg, + (retention == false ? vreg->min_vol: 0), + vreg->max_vol); + if (rc < 0) { + pr_err("%s: regulator_set_voltage(%s) failed rc=%d\n", + __func__, vreg->name, rc); + return rc; + } + } + + if (vreg->load_curr >= 0) { + rc = regulator_set_load(vreg->reg, + (retention == false ? vreg->load_curr: 0)); + if (rc < 0) { + pr_err("%s: regulator_set_load(%s) failed rc=%d\n", + __func__, vreg->name, rc); + return rc; + } + } + + return rc; +} + static int vreg_enable(struct vreg_data *vreg) { int rc = 0; @@ -444,36 +465,33 @@ static int vreg_enable(struct vreg_data *vreg) pr_debug("%s: vreg_en for : %s\n", __func__, vreg->name); if (!vreg->is_enabled) { - if ((vreg->min_vol != 0) && (vreg->max_vol != 0)) { - rc = regulator_set_voltage(vreg->reg, - vreg->min_vol, - vreg->max_vol); - if (rc < 0) { - pr_err("%s: regulator_set_voltage(%s) failed rc=%d\n", - __func__, vreg->name, rc); - goto out; - } + if (vreg_configure(vreg, false) < 0) { + return rc; } - - if (vreg->load_curr >= 0) { - rc = regulator_set_load(vreg->reg, - vreg->load_curr); - if (rc < 0) { - pr_err("%s: regulator_set_load(%s) failed rc=%d\n", - __func__, vreg->name, rc); - goto out; - } - } - rc = regulator_enable(vreg->reg); if (rc < 0) { pr_err("%s: regulator_enable(%s) failed. rc=%d\n", __func__, vreg->name, rc); - goto out; + return rc; } vreg->is_enabled = true; } -out: + + return rc; +} + +static int vreg_disable_retention(struct vreg_data *vreg) +{ + int rc = 0; + + if (!vreg) + return rc; + + pr_err("%s: disable_retention for : %s\n", __func__, vreg->name); + + if ((vreg->is_enabled) && (vreg->is_retention_supp)) + rc = vreg_configure(vreg, false); + return rc; } @@ -486,25 +504,10 @@ static int vreg_enable_retention(struct vreg_data *vreg) pr_debug("%s: enable_retention for : %s\n", __func__, vreg->name); - if ((vreg->is_enabled) && (vreg->is_retention_supp)) { - if ((vreg->min_vol != 0) && (vreg->max_vol != 0)) { - /* Set the min voltage to 0 */ - rc = regulator_set_voltage(vreg->reg, 0, vreg->max_vol); - if (rc < 0) { - pr_err("%s: regulator_set_voltage(%s) failed rc=%d\n", - __func__, vreg->name, rc); - goto out; - } - } - if (vreg->load_curr >= 0) { - rc = regulator_set_load(vreg->reg, 0); - if (rc < 0) { - pr_err("%s: regulator_set_load(%s) failed rc=%d\n", - __func__, vreg->name, rc); - } - } - } -out: + if ((vreg->is_enabled) && (vreg->is_retention_supp)) + if ((vreg->min_vol != 0) && (vreg->max_vol != 0)) + rc = vreg_configure(vreg, true); + return rc; } @@ -1005,7 +1008,7 @@ static int platform_regulators_pwr(int pwr_state) return 0; } - pr_info("%s: %s\n", __func__, reg_mode[pwr_state]); + pr_err("%s: %s\n", __func__, reg_mode[pwr_state]); switch (pwr_state) { case POWER_ENABLE: @@ -1055,6 +1058,12 @@ regulator_failed: rc = vreg_enable_retention(platform_vregs); } break; + case POWER_DISABLE_RETENTION: + for (i = 0; i < platform_num_vregs; i++) { + platform_vregs = &pwr_data->platform_vregs[i]; + rc = vreg_disable_retention(platform_vregs); + } + break; } return rc; } @@ -1360,9 +1369,9 @@ static int get_gpio_dt_pinfo(struct platform_device *pdev) static int get_power_dt_pinfo(struct platform_device *pdev) { int rc, i; + const struct pwr_data *data; data = of_device_get_match_data(&pdev->dev); - if (!data) { pr_err("%s: failed to get dev node\n", __func__); return -EINVAL; @@ -1538,12 +1547,17 @@ static int bt_power_probe(struct platform_device *pdev) INIT_WORK(&pwr_data->bt_wq, bt_signal_handler); INIT_WORK(&pwr_data->wq_pwr_voting, bt_power_vote); - for (itr = 0; itr < BTPWR_MAX_CLIENTS; itr++) { + for (itr = 0; itr < BTPWR_MAX_REQ; itr++) { init_waitqueue_head(&pwr_data->rsp_wait_q[itr]); } skb_queue_head_init(&pwr_data->rxq); mutex_init(&pwr_data->pwr_mtx); + mutex_init(&pwr_data->btpower_state.state_machine_lock); + pwr_data->btpower_state.power_state = IDLE; + pwr_data->btpower_state.retention_mode = RETENTION_IDLE; + pwr_data->btpower_state.grant_state = NO_GRANT_FOR_ANY_SS; + pwr_data->btpower_state.grant_pending = NO_OTHER_CLIENT_WAITING_FOR_GRANT; perisec_cnss_bt_hw_disable_check(pwr_data); @@ -1570,7 +1584,6 @@ static int bt_power_probe(struct platform_device *pdev) memcpy(pwr_data, pdev->dev.platform_data, sizeof(struct platform_pwr_data)); - pwr_state = 0; } else { pr_err("%s: Failed to get platform data\n", __func__); goto free_pdata; @@ -1672,14 +1685,68 @@ static void set_pwr_srcs_status(struct vreg_data *handle, } } -static void update_pwr_state(int state) +static inline void update_pwr_state(int state) { - pwr_data->power_state = state; + mutex_lock(&pwr_data->btpower_state.state_machine_lock); + pwr_data->btpower_state.power_state = state; + mutex_unlock(&pwr_data->btpower_state.state_machine_lock); } -static int get_pwr_state(void) +static inline int get_pwr_state(void) { - return pwr_data->power_state; + int state; + mutex_lock(&pwr_data->btpower_state.state_machine_lock); + state = (int)pwr_data->btpower_state.power_state; + mutex_unlock(&pwr_data->btpower_state.state_machine_lock); + return state; +} + +static inline void btpower_set_retenion_mode_state(int state) +{ + mutex_lock(&pwr_data->btpower_state.state_machine_lock); + pwr_data->btpower_state.retention_mode = state; + mutex_unlock(&pwr_data->btpower_state.state_machine_lock); +} + +static inline int btpower_get_retenion_mode_state(void) +{ + int state; + mutex_lock(&pwr_data->btpower_state.state_machine_lock); + state = (int)pwr_data->btpower_state.retention_mode; + mutex_unlock(&pwr_data->btpower_state.state_machine_lock); + return state; +} + +static inline void btpower_set_grant_pending_state(enum grant_states state) +{ + mutex_lock(&pwr_data->btpower_state.state_machine_lock); + pwr_data->btpower_state.grant_pending = state; + mutex_unlock(&pwr_data->btpower_state.state_machine_lock); +} + +static inline enum grant_states btpower_get_grant_pending_state(void) +{ + enum grant_states state; + mutex_lock(&pwr_data->btpower_state.state_machine_lock); + state = pwr_data->btpower_state.grant_pending; + mutex_unlock(&pwr_data->btpower_state.state_machine_lock); + return state; +} + +static inline void btpower_set_grant_state(enum grant_states state) +{ + mutex_lock(&pwr_data->btpower_state.state_machine_lock); + pwr_data->btpower_state.grant_state = state; + mutex_unlock(&pwr_data->btpower_state.state_machine_lock); +} + +static inline enum grant_states btpower_get_grant_state(void) +{ + enum grant_states state; + mutex_lock(&pwr_data->btpower_state.state_machine_lock); + state = pwr_data->btpower_state.grant_state; + mutex_unlock(&pwr_data->btpower_state.state_machine_lock); + return state; } static void update_sub_state(int state) @@ -1689,7 +1756,7 @@ static void update_sub_state(int state) static int get_sub_state(void) { - return pwr_data->sub_state; + return (int)pwr_data->sub_state; } int power_enable (enum SubSystem SubSystemType) @@ -1745,6 +1812,9 @@ void send_signal_to_subsystem(int SubSystemType, int state) int power_disable (enum SubSystem SubSystemType) { int ret = 0; + int ret_mode_state = btpower_get_retenion_mode_state(); + enum grant_states grant_state = btpower_get_grant_state(); + enum grant_states grant_pending = btpower_get_grant_pending_state(); switch (get_pwr_state()) { case IDLE: @@ -1754,37 +1824,71 @@ int power_disable (enum SubSystem SubSystemType) if (SubSystemType == BLUETOOTH) { ret = power_regulators(BT_CORE, POWER_DISABLE); update_pwr_state(UWB_ON); + if (ret_mode_state == BOTH_CLIENTS_IN_RETENTION) + btpower_set_retenion_mode_state(UWB_IN_RETENTION); + else if (ret_mode_state == BT_IN_RETENTION) + btpower_set_retenion_mode_state(RETENTION_IDLE); if(get_sub_state() == SSR_ON_BT) { send_signal_to_subsystem(UWB, BT_SSR_COMPLETED); } + if (grant_state == BT_HAS_GRANT) { + if (grant_pending == UWB_WAITING_FOR_GRANT) { + send_signal_to_subsystem(UWB, SIGIO_SOC_ACCESS_SIGNAL|(ACCESS_GRANTED + 1)); + btpower_set_grant_state(UWB_HAS_GRANT); + } else { + btpower_set_grant_state(NO_GRANT_FOR_ANY_SS); + } + } + if (grant_pending == BT_WAITING_FOR_GRANT) + btpower_set_grant_pending_state(NO_OTHER_CLIENT_WAITING_FOR_GRANT); } else { ret = power_regulators(UWB_CORE, POWER_DISABLE); update_pwr_state(BT_ON); + if (ret_mode_state == BOTH_CLIENTS_IN_RETENTION) + btpower_set_retenion_mode_state(BT_IN_RETENTION); + else if (ret_mode_state == UWB_IN_RETENTION) + btpower_set_retenion_mode_state(RETENTION_IDLE); if(get_sub_state() == SSR_ON_UWB) { send_signal_to_subsystem(BLUETOOTH, (SIGIO_NOTIFICATION_SIGNAL|SIGIO_UWB_SSR_COMPLETED)); } + if (grant_state == UWB_HAS_GRANT) { + if (grant_pending == BT_WAITING_FOR_GRANT) { + send_signal_to_subsystem(BLUETOOTH, SIGIO_SOC_ACCESS_SIGNAL|(ACCESS_GRANTED + 1)); + btpower_set_grant_state(BT_HAS_GRANT); + } else { + btpower_set_grant_state(NO_GRANT_FOR_ANY_SS); + } + } + if (grant_pending == UWB_WAITING_FOR_GRANT) + btpower_set_grant_pending_state(NO_OTHER_CLIENT_WAITING_FOR_GRANT); } break; case UWB_ON: if (SubSystemType == BLUETOOTH) { pr_err("%s: BT Regulator already Voted-Off\n", __func__); - return -1; + return 0; } ret = power_regulators(UWB_CORE, POWER_DISABLE); ret = power_regulators(PLATFORM_CORE, POWER_DISABLE); update_pwr_state(IDLE); update_sub_state(SUB_STATE_IDLE); + btpower_set_retenion_mode_state(RETENTION_IDLE); + btpower_set_grant_state(NO_GRANT_FOR_ANY_SS); + btpower_set_grant_pending_state(NO_OTHER_CLIENT_WAITING_FOR_GRANT); break; case BT_ON: if (SubSystemType == UWB) { pr_err("%s: UWB Regulator already Voted-Off\n", __func__); - return -1; + return 0; } ret = power_regulators(BT_CORE, POWER_DISABLE); ret = power_regulators(PLATFORM_CORE, POWER_DISABLE); update_pwr_state(IDLE); update_sub_state(SUB_STATE_IDLE); + btpower_set_retenion_mode_state(RETENTION_IDLE); + btpower_set_grant_state(NO_GRANT_FOR_ANY_SS); + btpower_set_grant_pending_state(NO_OTHER_CLIENT_WAITING_FOR_GRANT); break; } return ret; @@ -1822,32 +1926,7 @@ static int client_state_notified(int SubSystemType) return 0; } -void set_pwr_state(int core, int mode) -{ - pr_info("%s: Entry %s, %s\n", __func__, - pwr_states[(int)get_pwr_state()], - ssr_state[(int)get_sub_state()]); - - switch (mode) { - case POWER_DISABLE: - power_disable(core); - break; - case POWER_ENABLE: - power_enable(core); - break; - case POWER_RETENTION: - power_regulators(PLATFORM_CORE, POWER_RETENTION); - power_regulators((core == BLUETOOTH ? BT_CORE : UWB_CORE), - POWER_RETENTION); - pr_err("%s: BT Power Retention done\n", __func__); - break; - } - pr_info("%s: Done %s, %s\n", __func__, - pwr_states[(int)get_pwr_state()], - ssr_state[(int)get_sub_state()]); -} - -void client_notified(int client, int cmd) +void btpower_register_client(int client, int cmd) { if (cmd == REG_BT_PID) { pwr_data->reftask_bt = get_current(); @@ -1890,13 +1969,40 @@ void log_power_src_val(void) int btpower_retenion(enum plt_pwr_state client) { int ret; + int current_pwr_state = get_pwr_state(); + int retention_mode_state = btpower_get_retenion_mode_state(); - if (client == POWER_ON_BT_RETENION) { + if (current_pwr_state == IDLE) { + pr_err("%s: invalid retention_mode request", __func__); + return -1; + } + + ret = power_regulators((client == POWER_ON_BT_RETENION ? BT_CORE : UWB_CORE), + POWER_RETENTION); + if (ret < 0) + return ret; + + if ((current_pwr_state == BT_ON || current_pwr_state == UWB_ON) && + retention_mode_state == IDLE) { ret = power_regulators(PLATFORM_CORE, POWER_RETENTION); - ret = power_regulators(BT_CORE, POWER_RETENTION); - } else { + if (ret < 0) + return ret; + btpower_set_retenion_mode_state(client == POWER_ON_BT_RETENION ? BT_IN_RETENTION: UWB_IN_RETENTION); + } else if (current_pwr_state == ALL_CLIENTS_ON && retention_mode_state == IDLE) { + btpower_set_retenion_mode_state(client == POWER_ON_BT_RETENION ? BT_IN_RETENTION: UWB_IN_RETENTION); + } else if (current_pwr_state == ALL_CLIENTS_ON && + (retention_mode_state == BT_IN_RETENTION || + retention_mode_state == UWB_IN_RETENTION)) { ret = power_regulators(PLATFORM_CORE, POWER_RETENTION); - ret = power_regulators(UWB_CORE, POWER_RETENTION); + if (ret < 0) + return ret; + btpower_set_retenion_mode_state(BOTH_CLIENTS_IN_RETENTION); + } else if (retention_mode_state == UWB_OUT_OF_RETENTION || + retention_mode_state == BT_OUT_OF_RETENTION) { + ret = power_regulators(PLATFORM_CORE, POWER_RETENTION); + if (ret < 0) + return ret; + btpower_set_retenion_mode_state(BOTH_CLIENTS_IN_RETENTION); } return ret; @@ -1910,21 +2016,33 @@ int btpower_off(enum plt_pwr_state client) int btpower_on(enum plt_pwr_state client) { int ret = 0; + int current_ssr_state = get_sub_state(); + int retention_mode_state = btpower_get_retenion_mode_state(); - if (client == POWER_ON_BT) { - if (get_sub_state() == SSR_ON_UWB) { - pr_err("%s: SSR_ON_UWB not allowing to BT POWER ON\n", __func__); - return -1; - } - ret = power_enable(BLUETOOTH); - } else { - if (get_sub_state() == SSR_ON_BT) { - pr_err("%s: SSR_ON_BT not allowing to UWB POWER ON\n", __func__); - return -1; - } - ret = power_enable(UWB); + if (retention_mode_state == UWB_IN_RETENTION || + retention_mode_state == BT_IN_RETENTION) { + ret = platform_regulators_pwr(POWER_DISABLE_RETENTION); + if (ret < 0) + return ret; + if (retention_mode_state == BT_IN_RETENTION) + btpower_set_retenion_mode_state(BT_OUT_OF_RETENTION); + else + btpower_set_retenion_mode_state(UWB_OUT_OF_RETENTION); } + /* No Point in going further if SSR is on any subsystem */ + if (current_ssr_state != SUB_STATE_IDLE) { + pr_err("%s: %s not allowing to power on\n", __func__, + ssr_state[current_ssr_state]); + return -1; + } + + ret = power_enable(client == POWER_ON_BT ? BLUETOOTH : UWB); + + /* Return current state machine to clients */ + if (!ret) { + ret = (int)get_pwr_state(); + } return ret; } @@ -1934,6 +2052,76 @@ int STREAM_TO_UINT32 (struct sk_buff *skb) (skb->data[2] << 16) | (skb->data[3] << 24)); } +int btpower_access_ctrl(enum plt_pwr_state request) +{ + enum grant_states grant_state = btpower_get_grant_state(); + enum grant_states grant_pending = btpower_get_grant_pending_state(); + int current_ssr_state = get_sub_state(); + + pr_info("%s: request for %s grant_state %s grant_pending %s", __func__, + pwr_req[(int)request], ConvertGrantToString(grant_state), + ConvertGrantToString(grant_pending)); + + if (current_ssr_state != SUB_STATE_IDLE && + (request == BT_ACCESS_REQ || request == UWB_ACCESS_REQ)) { + pr_err("%s: not allowing this request as %s", __func__, ssr_state[current_ssr_state]); + return (int)ACCESS_DISALLOWED; + } + + if ((grant_state == NO_GRANT_FOR_ANY_SS && + grant_pending != NO_OTHER_CLIENT_WAITING_FOR_GRANT)) { + pr_err("%s: access ctrl gone for toss, reseting it back", __func__ ); + grant_pending = NO_OTHER_CLIENT_WAITING_FOR_GRANT; + btpower_set_grant_pending_state(NO_OTHER_CLIENT_WAITING_FOR_GRANT); + } + + if (request == BT_ACCESS_REQ && grant_state == NO_GRANT_FOR_ANY_SS) { + btpower_set_grant_state(BT_HAS_GRANT); + return ACCESS_GRANTED; + } else if (request == UWB_ACCESS_REQ && grant_state == NO_GRANT_FOR_ANY_SS) { + btpower_set_grant_state(UWB_HAS_GRANT); + return ACCESS_GRANTED; + } else if (request == BT_ACCESS_REQ && grant_state == UWB_HAS_GRANT) { + btpower_set_grant_pending_state(BT_WAITING_FOR_GRANT); + return ACCESS_DENIED; + } else if (request == UWB_ACCESS_REQ && grant_state == BT_HAS_GRANT) { + btpower_set_grant_pending_state(UWB_WAITING_FOR_GRANT); + return ACCESS_DENIED; + } else if (request == BT_RELEASE_ACCESS && grant_state == BT_HAS_GRANT) { + if (grant_pending == UWB_WAITING_FOR_GRANT) { + if (!pwr_data->reftask_uwb) { + pr_err("%s: UWB service got killed\n", __func__); + } else { + send_signal_to_subsystem(UWB, SIGIO_SOC_ACCESS_SIGNAL|(ACCESS_GRANTED + 1)); + btpower_set_grant_state(UWB_HAS_GRANT); + } + btpower_set_grant_pending_state(NO_OTHER_CLIENT_WAITING_FOR_GRANT); + return ACCESS_RELEASED; + + } else { + btpower_set_grant_state(NO_GRANT_FOR_ANY_SS); + btpower_set_grant_pending_state(NO_OTHER_CLIENT_WAITING_FOR_GRANT); + return ACCESS_RELEASED; + } + } else if (request == UWB_RELEASE_ACCESS && grant_state == UWB_HAS_GRANT) { + if (grant_pending == BT_WAITING_FOR_GRANT) { + if (!pwr_data->reftask_uwb) { + pr_err("%s: BT service got killed\n", __func__); + } else { + send_signal_to_subsystem(BLUETOOTH, SIGIO_SOC_ACCESS_SIGNAL|(ACCESS_GRANTED+1)); + btpower_set_grant_state(BT_HAS_GRANT); + } + } else { + btpower_set_grant_state(NO_GRANT_FOR_ANY_SS); + } + btpower_set_grant_pending_state(NO_OTHER_CLIENT_WAITING_FOR_GRANT); + return ACCESS_RELEASED; + } else { + pr_err("%s: unhandled event", __func__); + } + return ACCESS_DISALLOWED; +} + static void bt_power_vote(struct work_struct *work) { struct sk_buff *skb; @@ -1949,28 +2137,39 @@ static void bt_power_vote(struct work_struct *work) request = STREAM_TO_UINT32(skb); skb_pull(skb, sizeof(uint32_t)); mutex_unlock(&pwr_data->pwr_mtx); - pr_err("%s: request %s", __func__, pwr_req[request]); - pr_err("%s: current state = %s, %s\n", __func__, - pwr_states[(int)get_pwr_state()], ssr_state[(int)get_sub_state()]); + pr_err("%s: request from is %s cur state = %s %s retention %s access %s pending %s\n", + __func__, pwr_req[request], pwr_states[get_pwr_state()], + ssr_state[get_sub_state()], + retention_mode[btpower_get_retenion_mode_state()], + ConvertGrantToString(btpower_get_grant_state()), + ConvertGrantToString(btpower_get_grant_pending_state())); if (request == POWER_ON_BT || request == POWER_ON_UWB) ret = btpower_on((enum plt_pwr_state)request); else if (request == POWER_OFF_UWB || request == POWER_OFF_BT) ret = btpower_off((enum plt_pwr_state)request); else if (request == POWER_ON_BT_RETENION || request == POWER_ON_UWB_RETENION) ret = btpower_retenion(request); - - pwr_data->wait_status[request] = ret == 0? PWR_RSP_RECV: PWR_FAIL_RSP_RECV; + else if (request >= BT_ACCESS_REQ && request <= UWB_RELEASE_ACCESS) { + ret = btpower_access_ctrl(request); + pr_info("%s: grant status %s", __func__, ConvertGrantRetToString((int)ret)); + } + pr_err("%s: request from is %s cur state = %s %s retention %s access %s pending %s\n", + __func__, pwr_req[request], pwr_states[get_pwr_state()], + ssr_state[get_sub_state()], + retention_mode[btpower_get_retenion_mode_state()], + ConvertGrantToString(btpower_get_grant_state()), + ConvertGrantToString(btpower_get_grant_pending_state())); + + pwr_data->wait_status[request] = ret; wake_up_interruptible(&pwr_data->rsp_wait_q[request]); - pr_err("%s: current state = %s, %s\n", __func__, - pwr_states[(int)get_pwr_state()], ssr_state[(int)get_sub_state()]); } } -int schedule_client_pwr_voting(enum plt_pwr_state request) +int schedule_client_voting(enum plt_pwr_state request) { struct sk_buff *skb; wait_queue_head_t *rsp_wait_q; - u8 *status; + int *status; int ret = 0; uint32_t req = (uint32_t)request; @@ -1978,7 +2177,7 @@ int schedule_client_pwr_voting(enum plt_pwr_state request) skb = alloc_skb(sizeof(uint32_t), GFP_KERNEL); if (!skb) { - pr_err("%s: Unable to creat SK buff\n", __func__); + pr_err("%s: Unable to create skbuff\n", __func__); mutex_unlock(&pwr_data->pwr_mtx); return -1; } @@ -1991,21 +2190,79 @@ int schedule_client_pwr_voting(enum plt_pwr_state request) schedule_work(&pwr_data->wq_pwr_voting); mutex_unlock(&pwr_data->pwr_mtx); ret = wait_event_interruptible_timeout(*rsp_wait_q, (*status) != PWR_WAITING_RSP, - msecs_to_jiffies(TIMEOUT)); - + msecs_to_jiffies(BTPOWER_CONFIG_MAX_TIMEOUT)); + pr_err("%s: %d", __func__, *status); if (ret == 0) { pr_err("%s: failed to vote %d due to timeout", __func__, request); ret = -ETIMEDOUT; } else { - if (*status == PWR_RSP_RECV) - return 0; - else if (*status == PWR_FAIL_RSP_RECV || *status == PWR_CLIENT_KILLED) - return -1; + ret = *status; } return ret; } +int btpower_handle_client_request(unsigned int cmd, int arg) +{ + int ret = -1; + + pr_info("%s: %s cmd voted to %s, current state = %s, %s\n", __func__, + (cmd == BT_CMD_PWR_CTRL ? "BT_CMD_PWR_CTRL": "UWB_CMD_PWR_CTRL"), + bt_arg[(int)arg], pwr_states[get_pwr_state()], + ssr_state[(int)get_sub_state()]); + + if (cmd == BT_CMD_PWR_CTRL) { + switch ((int)arg) { + case POWER_DISABLE: + ret = schedule_client_voting(POWER_OFF_BT); + break; + case POWER_ENABLE: + ret = schedule_client_voting(POWER_ON_BT); + break; + case POWER_RETENTION: + ret = schedule_client_voting(POWER_ON_BT_RETENION); + break; + } + } else if (cmd == UWB_CMD_PWR_CTRL) { + switch ((int)arg) { + case POWER_DISABLE: + ret = schedule_client_voting(POWER_OFF_UWB); + break; + case POWER_ENABLE: + ret = schedule_client_voting(POWER_ON_UWB); + break; + case POWER_RETENTION: + ret = schedule_client_voting(POWER_ON_UWB_RETENION); + break; + } + } + pr_err("%s: %s, SSR state = %s\n", __func__, + pwr_states[get_pwr_state()], ssr_state[(int)get_sub_state()]); + + return ret; +} + +int btpower_process_access_req(unsigned int cmd, int req) +{ + int ret = -1; + + pr_info("%s: by %s: request type %s", __func__, + cmd == BT_CMD_ACCESS_CTRL ? "BT": "UWB", + req == 1? "Request": "Release"); + if (cmd == BT_CMD_ACCESS_CTRL && req == 1) + ret = schedule_client_voting(BT_ACCESS_REQ); + else if (cmd == BT_CMD_ACCESS_CTRL && req == 2) + ret = schedule_client_voting(BT_RELEASE_ACCESS); + else if (cmd == UWB_CMD_ACCESS_CTRL && req == 1) + ret = schedule_client_voting(UWB_ACCESS_REQ); + else if (cmd == UWB_CMD_ACCESS_CTRL && req == 2) + ret = schedule_client_voting(UWB_RELEASE_ACCESS); + else + pr_err("%s: unhandled command %04x req %02x", __func__, cmd, req); + + return ret; +} + static long bt_ioctl(struct file *file, unsigned int cmd, unsigned long arg) { int ret = 0; @@ -2071,53 +2328,21 @@ static long bt_ioctl(struct file *file, unsigned int cmd, unsigned long arg) #endif break; case BT_CMD_PWR_CTRL: - pr_err("%s: BT_CMD_PWR_CTRL cmd voted to %s, current state = %s, %s\n", - __func__, bt_arg[(int)arg], pwr_states[(int)get_pwr_state()], ssr_state[(int)get_sub_state()]); - - switch ((int)arg) { - case POWER_DISABLE: - ret = schedule_client_pwr_voting(POWER_OFF_BT); - pr_err("%s: %s, SSR state = %s\n", __func__, - pwr_states[(int)get_pwr_state()], ssr_state[(int)get_sub_state()]); - break; - case POWER_ENABLE: - ret = schedule_client_pwr_voting(POWER_ON_BT); - pr_err("%s: %s, SSR state = %s\n", __func__, - pwr_states[(int)get_pwr_state()], ssr_state[(int)get_sub_state()]); - break; - case POWER_RETENTION: - ret = schedule_client_pwr_voting(POWER_ON_BT_RETENION); - break; - } - break; - case UWB_CMD_PWR_CTRL: - - pr_err("%s: UWB_CMD_PWR_CTRL voted for %s, sub_system count = %s, %s\n", - __func__, uwb_arg[(int)arg], pwr_states[(int)get_pwr_state()], ssr_state[(int)get_sub_state()]); - - switch ((int)arg) { - case POWER_DISABLE: - ret = schedule_client_pwr_voting(POWER_OFF_UWB); - pr_err("%s: %s, SSR state = %s\n", __func__, - pwr_states[(int)get_pwr_state()], ssr_state[(int)get_sub_state()]); - break; - case POWER_ENABLE: - ret = schedule_client_pwr_voting(POWER_ON_UWB); - pr_err("%s: %s, SSR state = %s\n", __func__, - pwr_states[(int)get_pwr_state()], ssr_state[(int)get_sub_state()]); - break; - case POWER_RETENTION: - ret = schedule_client_pwr_voting(POWER_ON_UWB_RETENION); - pr_err("%s:BT Power Retention done", __func__); - break; - } + case UWB_CMD_PWR_CTRL: { + ret = btpower_handle_client_request(cmd, (int)arg); break; + } case BT_CMD_REGISTRATION: - client_notified(BLUETOOTH, (int)arg); + btpower_register_client(BLUETOOTH, (int)arg); break; case UWB_CMD_REGISTRATION: - client_notified(UWB, (int)arg); + btpower_register_client(UWB, (int)arg); break; + case BT_CMD_ACCESS_CTRL: + case UWB_CMD_ACCESS_CTRL: { + ret = btpower_process_access_req(cmd, (int)arg); + break; + } case BT_CMD_CHIPSET_VERS: chipset_version = (int)arg; pr_warn("%s: unified Current SOC Version : %x\n", __func__, From 71795cd2d37a59a2205b2ce3b49fd7b5196432c5 Mon Sep 17 00:00:00 2001 From: Hemant Gupta Date: Sun, 7 Jan 2024 22:43:03 +0530 Subject: [PATCH 085/154] BTPOWER: Add support for WCN788x Add support for WCN788x Change-Id: I514304b639da4dac072872f2bea8a4e2fb80e4d7 Signed-off-by: Hemant Gupta --- pwr/btpower.c | 19 ++++++++++++++----- 1 file changed, 14 insertions(+), 5 deletions(-) diff --git a/pwr/btpower.c b/pwr/btpower.c index 352996da63..e020557dee 100644 --- a/pwr/btpower.c +++ b/pwr/btpower.c @@ -1,7 +1,7 @@ // SPDX-License-Identifier: GPL-2.0-only /* * Copyright (c) 2016-2021, The Linux Foundation. All rights reserved. - * Copyright (c) 2021-2023 Qualcomm Innovation Center, Inc. All rights reserved. + * Copyright (c) 2021-2024 Qualcomm Innovation Center, Inc. All rights reserved. */ /* @@ -285,7 +285,7 @@ static struct pwr_data vreg_info_wcn6750 = { .bt_num_vregs = ARRAY_SIZE(bt_vregs_info_qca6xx0), }; -/* Kiwi supports both BT & UWB SS. For now it requires +/* Peach supports both BT & UWB SS. For now it requires * only platform regulators to be powered ON. */ static struct pwr_data vreg_info_peach = { @@ -294,6 +294,12 @@ static struct pwr_data vreg_info_peach = { .platform_num_vregs = ARRAY_SIZE(platform_vregs_info_peach), }; +static struct pwr_data vreg_info_wcn788x = { + .compatible = "qcom,wcn788x", + .platform_vregs = platform_vregs_info_peach, + .platform_num_vregs = ARRAY_SIZE(platform_vregs_info_peach), +}; + static const struct of_device_id bt_power_match_table[] = { { .compatible = "qcom,qca6174", .data = &vreg_info_qca6174}, { .compatible = "qcom,wcn3990", .data = &vreg_info_wcn399x}, @@ -305,6 +311,7 @@ static const struct of_device_id bt_power_match_table[] = { { .compatible = "qcom,wcn6750-bt", .data = &vreg_info_wcn6750}, { .compatible = "qcom,bt-qca-converged", .data = &vreg_info_converged}, { .compatible = "qcom,peach-bt", .data = &vreg_info_peach}, + { .compatible = "qcom,wcn788x", .data = &vreg_info_wcn788x}, {}, }; @@ -850,7 +857,7 @@ static int bt_regulators_pwr(int pwr_state) bt_num_vregs = pwr_data->bt_num_vregs; if (!bt_num_vregs) { - pr_warn("%s: not avilable to %s\n", + pr_warn("%s: not available to %s\n", __func__, reg_mode[pwr_state]); return 0; } @@ -949,7 +956,7 @@ static int uwb_regulators_pwr(int pwr_state) uwb_num_vregs = pwr_data->uwb_num_vregs; if (!uwb_num_vregs) { - pr_warn("%s: not avilable to %s\n", + pr_warn("%s: not available to %s\n", __func__, reg_mode[pwr_state]); return 0; } @@ -1533,7 +1540,9 @@ static int bt_power_probe(struct platform_device *pdev) pwr_data->pdev = pdev; pwr_data->is_ganges_dt = of_property_read_bool(pdev->dev.of_node, - "qcom,peach-bt"); + "qcom,peach-bt") || + of_property_read_bool(pdev->dev.of_node, + "qcom,wcn788x"); pr_info("%s: is_ganges_dt = %d\n", __func__, pwr_data->is_ganges_dt); pwr_data->workq = alloc_workqueue("workq", WQ_HIGHPRI, WQ_DFL_ACTIVE); From 24abb57a9f947fd02126c20be8efcb3810cfc22b Mon Sep 17 00:00:00 2001 From: Girish BN Date: Mon, 18 Dec 2023 23:39:55 +0530 Subject: [PATCH 086/154] Add definition for Primary, Secondary crash reason - Adding the definition for Primary and Secondary crash reason Change-Id: I482f88524d1f5bfc759f17bdd13295dd2323a618 Signed-off-by: Girish BN --- include/btpower.h | 649 ++++++++++++++++++++++++++++++++++++++++++++++ pwr/btpower.c | 58 ++++- 2 files changed, 699 insertions(+), 8 deletions(-) diff --git a/include/btpower.h b/include/btpower.h index da35be4e41..bc453cad00 100644 --- a/include/btpower.h +++ b/include/btpower.h @@ -156,6 +156,655 @@ enum { PWR_CLIENT_KILLED, }; +enum BtPrimaryReasonCode { + BT_DEFAULT_NONE = 0x00, //INVALID REASON + BT_SOC_CRASHED = 0x01, //SOC WAS CRASHED + BT_SOC_CRASHED_DIAG_SSR = 0x02, //SOC CRASHED DIAG INITIATED SSR + BT_INIT_FAILED = 0x03, //HOST INITIALIZATION FAILED + BT_CLOSE_RCVD_DURING_INIT = 0x04, //CLOSE RECEIVED FROM STACK DURING SOC INIT + BT_ERROR_READING_DATA_FROM_UART = 0x05, //ERROR READING DATA FROM UART + BT_WRITE_FAIL_SPCL_BUFF_CRASH_SOC = 0x06, //FAILED TO WRITE SPECIAL BYTES TO CRASH SOC + BT_RX_THREAD_STUCK = 0x07, //RX THREAD STUCK + BT_SSR_CMD_TIMEDOUT = 0x08, //SSR DUE TO CMD TIMED OUT + BT_SSR_SPURIOUS_WAKEUP = 0x09, //SSR DUE TO SPURIOUS WAKE UP + BT_SSR_INVALID_BYTES_RCVD = 0x0A, //INVALID HCI CMD TYPE RECEIVED + BT_SSR_RCVD_LARGE_PKT_FROM_SOC = 0x0B, //SSR DUE TO LARGE PKT RECVIVED FROM SOC + BT_SSR_UNABLE_TO_WAKEUP_SOC = 0x0C, //UNABLE TO WAKE UP SOC + BT_CMD_TIMEDOUT_SOC_WAIT_TIMEOUT = 0x0D, //COMMAND TIMEOUT AND SOC CRASH WAIT TIMEOUT + BT_SPURIOUS_WAKEUP_SOC_WAIT_TIMEOUT = 0x0E, //SPURIOUS WAKE AND SOC CRASH WAIT TIMEOUT + BT_INV_BYTES_SOC_WAIT_TIMEOUT = 0x0F, //INVALID BYTES AND SOC CRASH WAIT TIMEOUT + BT_SOC_WAKEUP_FAILED_SOC_WAIT_TIMEOUT = 0x10, //SOC WAKEUP FAILURE AND SOC CRASH WAIT TIMEOUT + BT_SOC_CRASHED_DIAG_SSR_SOC_WAIT_TIMEOUT = 0x11, //SOC CRASHED DIAG INITIATED SSR CRASH WAIT TIMEOUT + BT_NONE_SOC_WAIT_TIMEOUT = 0x12, //INVALID FAILURE AND SOC CRASH WAIT TIMEOUT + BT_SOC_DEINIT_STUCK = 0x13, //SOC DEINIT STUCK + BT_SSR_INTERNAL_CMD_TIMEDOUT = 0x14, //SSR DUE TO CMD INTERNAL TIMED OUT + BT_FAILED_TO_SEND_INTERNAL_CMD = 0x15, //FAILED TO SEND INTERNAL CMD + BT_SSR_SLEEP_IND_NOT_RCVD = 0x16, //SOC DID NOT RCVD SLEEP IND DURING CLOSE + BT_DIAG_LOG_API_STUCK = 0x39, //DIAG log API stuck. + BT_PERI_SOC_CRASHED_DIAG_SSR = 0x17, //PERI SOC CRASHED DIAG INITIATED SSR + BT_PERI_SOC_CRASHED = 0X18, //PERI SOC WAS CRASHED + BT_PERI_SOC_CRASHED_ON_OTHER_SUB_SYSTEM = 0x3A, //Peripheral core crash detected in UWB SS + BT_PERI_SUB_SYSTEM_FAILED_UPDATE_SSR_COMPLETE = 0x3B // UWB FAILED TO UPDATE THE SSR COMPLETE STATUS +}; + +enum BtSecondaryReasonCode { + BT_SOC_REASON_DEFAULT = 0x00, + BT_SOC_REASON_UNKNOWN = 0x81, + BT_SOC_REASON_SW_REQUESTED = 0x82, + BT_SOC_REASON_STACK_OVERFLOW = 0x83, + BT_SOC_REASON_EXCEPTION = 0x84, + BT_SOC_REASON_ASSERT = 0x85, + BT_SOC_REASON_TRAP = 0x86, + BT_SOC_REASON_OS_FATAL = 0x87, + BT_SOC_REASON_HCI_RESET = 0x88, + BT_SOC_REASON_PATCH_RESET = 0x89, + BT_SOC_REASON_ABT = 0x8A, + BT_SOC_REASON_RAMMASK = 0x8B, + BT_SOC_REASON_PREBARK = 0x8C, + BT_SOC_REASON_BUSERROR = 0x8D, + BT_SOC_REASON_IO_FATAL = 0x8E, + BT_SOC_REASON_SSR_CMD = 0x8F, + BT_SOC_REASON_POWERON = 0x90, + BT_SOC_REASON_WATCHDOG = 0x91, + BT_SOC_REASON_RAMMASK_RGN1 = 0x92, + BT_SOC_REASON_RAMMASK_RGN0 = 0x93, + BT_SOC_REASON_Q6_WATCHDOG = 0x94, + BT_SOC_REASON_ZEALIS_RAM_MASK_RGN0 = 0x95, + BT_SOC_REASON_ZEALIS_RAM_MASK_RGN1 = 0x96, + BT_SOC_REASON_APSS_RESET = 0x97, + BT_SOC_REASON_TIME_RESET = 0x98, + BT_SOC_REASON_AUDIOSS_RESET = 0x99, + BT_SOC_REASON_HOST_WARMRESET = 0x9A, + BT_SOC_REASON_HOST_NMI_INIT = 0x9B, + BT_SOC_REASON_PANIC_FAULT = 0x9C, + BT_SOC_REASON_EARLY_TRAP = 0x9D, + BT_SOC_REASON_INSTR_ADDR_MISALIGN = 0x9E, + BT_SOC_REASON_INSTR_ACCESS_FAULT = 0x9F, + BT_SOC_REASON_ILLEGAL_INSTR = 0xA0, + BT_SOC_REASON_BREAKPOINT_EXCEPTION = 0xA1, + BT_SOC_REASON_LOAD_ADDR_MISALIGN = 0xA2, + BT_SOC_REASON_LOAD_ACCESS_FAULT = 0xA3, + BT_SOC_REASON_STORE_ADDR_MISALIGN = 0xA4, + BT_SOC_REASON_STORE_ACCESS_FAULT = 0xA5, + BT_SOC_REASON_ECALL_UMODE = 0xA6, + BT_SOC_REASON_ECALL_MMODE = 0xA7, + BT_SOC_REASON_STACK_UNDERFLOW = 0xA8, + BT_SOC_REASON_MACHINE_EXT_INT = 0xA9, + BT_SOC_REASON_PERF_MONITOR_OVERFLOW= 0xAA, + BT_SOC_REASON_EXT_SUBSYS_RESET = 0xAB, + BT_SOC_REASON_IPC_STALL = 0xAC, + BT_SOC_REASON_PEER_CPU0_NMI = 0xAD, + BT_SOC_REASON_PEER_CPU1_NMI = 0xAE, + BT_SOC_REASON_PEER_CPU2_NMI = 0xAF, + BT_SOC_REASON_TX_RX_INVALID_PKT_FATAL = 0xC0, + BT_SOC_REASON_TX_RX_INVALID_LEN_FATAL = 0xC1, + BT_SOC_REASON_INVALID_STACK = 0xF0, + BT_SOC_REASON_INVALID_MCI_MSG_RCVD = 0xF1, + BT_HOST_REASON_UARTINIT_STUCK = 0x17, + BT_HOST_REASON_GETVER_SEND_STUCK = 0x18, + BT_HOST_REASON_GETVER_NO_RSP_RCVD = 0x19, + BT_HOST_REASON_SETBAUDRATE_CMD_STUCK = 0x1A, + BT_HOST_REASON_PATCH_DNLD_STUCK = 0x1B, + BT_HOST_REASON_GETBOARDID_CMD_STUCK = 0x1C, + BT_HOST_REASON_NVM_DNLD_STUCK = 0x1D, + BT_HOST_REASON_HCI_RESET_STUCK = 0x1E, + BT_HOST_REASON_GETBLDINFO_CMD_STUCK = 0x1F, + BT_HOST_REASON_ADDONFEAT_CMD_STUCK = 0x20, + BT_HOST_REASON_ENHLOG_CMD_STUCK = 0x21, + BT_HOST_REASON_DIAGINIT_STUCK = 0x22, + BT_HOST_REASON_DIAGDEINIT_STUCK = 0x23, + BT_HOST_REASON_XMEM_NVM_DNLD_STUCK = 0x24, + BT_HOST_REASON_XMEM_PATCH_DNLD_STUCK = 0x25, + BT_HOST_REASON_SECURE_BRIDGE_CMD_STUCK = 0x26, + BT_HOST_REASON_FAILED_TO_SEND_CMD = 0x27, + BT_HOST_REASON_HCI_RESET_CC_NOT_RCVD = 0x28, + BT_HOST_REASON_HCI_PRE_SHUTDOWN_CC_NOT_RCVD = 0x29, + BT_HOST_REASON_HCI_SET_BD_ADDRESS_CC_NOT_RCVD = 0x2A, + BT_HOST_REASON_FAILED_TO_RECEIVE_SLEEP_IND = 0x2B, + BT_HOST_REASON_POWER_ON_REGS_STUCK = 0x2C, + BT_HOST_REASON_RX_THREAD_START_STUCK = 0x2D, + BT_HOST_REASON_GET_LOCALADDR_STUCK = 0x2E, + BT_HOST_REASON_OTP_INFO_GET_CMD_STUCK = 0x2F, + BT_HOST_REASON_FILE_SYSTEM_CALL_STUCK = 0x30, + BT_HOST_REASON_PROPERTY_GET_STUCK = 0x31, + BT_HOST_REASON_PROPERTY_SET_STUCK = 0x32, + BT_HOST_REASON_RAM_PATCH_READ_STUCK = 0x33, + BT_HOST_REASON_NVM_PATCH_READ_STUCK = 0x34, + BT_HOST_REASON_UART_IOCTL_STUCK = 0x35, + BT_HOST_REASON_POWER_IOCTL_STUCK = 0x36, + BT_HOST_REASON_PATCH_CONFIG_CMD_STUCK = 0x37, + BT_HOST_REASON_GET_APP_VER_CMD_STUCK = 0x38, + BT_HOST_REASON_SOC_NAME_UNKOWN = 0x3A, + SOC_REASON_START_TX_IOS_SOC_RFR_HIGH_DURING_INIT = 0x3B, + BT_HOST_REASON_GETVER_CMD_FAILED = 0x3C, + BT_HOST_REASON_BAUDRATE_CHANGE_FAILED = 0x3D, + BT_HOST_REASON_TLV_DOWNLOAD_FAILED = 0x3E, + BT_HOST_REASON_FW_BUILD_INFO_CMD_FAILED = 0x3F, + BT_HOST_REASON_HCI_RESET_CMD_FAILED = 0x40, + BT_HOST_REASON_UART_INIT_FAILED = 0x41, + BT_HOST_REASON_MEMORY_ALLOCATION_FAILED = 0x42, + BT_HOST_REASON_READ_THREAD_START_FAILED = 0x43, + BT_HOST_REASON_HW_FLOW_ON_FAILED = 0x44, + BT_HOST_REASON_NVM_FILE_NOT_FOUND = 0x45, + BT_HOST_REASON_UART_BAUDRATE_CHANGE_FAILED = 0x46, + BT_HOST_REASON_PATCH_CONFIG_FAILED = 0x47, + BT_HOST_REASON_HCI_SET_OFFLOAD_HOST_CONFIG_CC_NOT_RCVD = 0x48, + BT_HOST_REASON_BT_EN_PIN_LOW = 0x49, + UART_REASON_DEFAULT = 0x51, + UART_REASON_INVALID_FW_LOADED = 0x52, + UART_REASON_CLK_GET_FAIL = 0x53, + UART_REASON_SE_CLK_RATE_FIND_FAIL = 0x54, + UART_REASON_SE_RESOURCES_INIT_FAIL = 0x55, + UART_REASON_SE_RESOURCES_ON_FAIL = 0x56, + UART_REASON_SE_RESOURCES_OFF_FAIL = 0x57, + UART_REASON_TX_DMA_MAP_FAIL = 0x58, + UART_REASON_TX_CANCEL_FAIL = 0x59, + UART_REASON_TX_ABORT_FAIL = 0x5A, + UART_REASON_TX_FSM_RESET_FAIL = 0x5B, + UART_REASON_RX_CANCEL_FAIL = 0x5C, + UART_REASON_RX_ABORT_FAIL = 0x5D, + UART_REASON_RX_FSM_RESET_FAIL = 0x5E, + UART_REASON_RX_TTY_INSET_FAIL = 0x5F, + UART_REASON_ILLEGAL_INTERRUPT = 0x60, + UART_REASON_BUFFER_OVERRUN = 0x61, + UART_REASON_RX_PARITY_REASON = 0x62, + UART_REASON_RX_BREAK_REASON = 0x63, + UART_REASON_RX_SBE_REASON = 0x64, + SOC_REASON_START_TX_IOS_SOC_RFR_HIGH = 0x65, + UART_REASON_FLOW_OFF = 0x66, + BT_HOST_REASON_PERI_ARBITRATION_CMD_STUCK = 0x67, + BT_HOST_REASON_PERI_ARBITRATION_NTF_STUCK = 0x68, + BT_HOST_REASON_BT_ACTIVATE_NTF_STUCK = 0x69, + BT_HOST_REASON_PERI_GETVER_SEND_STUCK = 0x70, + BT_HOST_REASON_PERI_GETBLDINFO_CMD_STUCK = 0x71, + BT_HOST_REASON_PERI_RAM_PATCH_READ_STUCK = 0x72, + BT_HOST_REASON_PERI_RESET_STUCK = 0x73, + BT_HOST_REASON_PERI_PATCH_CONFIG_CMD_STUCK= 0x74, + BT_HOST_REASON_PERI_PATCH_DNLD_STUCK = 0x75, + BT_HOST_REASON_PERI_RESET_CMD_FAILED = 0x76, + BT_HOST_REASON_BT_ACTIVATE_CMD_STUCK = 0x4F, + BT_HOST_REASON_BT_ACTIVATE_CMD_FAILED = 0x77, + BT_HOST_REASON_PERI_GETVER_CMD_FAILED = 0x78, + BT_HOST_REASON_PERI_PATCH_CONFIG_FAILED = 0x79, + BT_HOST_REASON_PERI_TLV_DOWNLOAD_FAILED = 0xB0, + BT_HOST_REASON_PERI_GETBOARDID_CMD_STUCK = 0xB1, + BT_HOST_REASON_PERI_NVM_PATCH_READ_STUCK = 0xB2, + BT_HOST_REASON_PERI_NVM_FILE_NOT_FOUND = 0xB3, + BT_HOST_REASON_PERI_NVM_DNLD_STUCK = 0XB4, + BT_HOST_REASON_PERI_GETBLDINFO_CMD_FAILED = 0XB5, + BT_HOST_REASON_PERI_GETVER_NO_RSP_RCVD = 0XB6, + BT_HOST_REASON_PERI_ARB_NOTIFY_FAILED = 0xB7, + BT_HOST_REASON_PERI_SETBAUDRATE_CMD_STUCK = 0xB8, + BT_HOST_REASON_PERI_SETBAUD_CMD_FAILED = 0xB9, + BT_HOST_REASON_MEMORY_ALLOCATION_FAILED_PERI = 0xBA, + BT_HOST_REASON_HCI_ACTIVATE_CC_NOT_RCVD = 0xBB, + BT_HOST_REASON_PERI_FILE_SYSTEM_CALL_STUCK = 0xBC, + BT_HOST_REASON_PERI_POWER_IOCTL_STUCK = 0xBD, + BT_HOST_REASON_PERI_SETBAUD_CC_NOT_RCVD = 0xBE, + PERI_SOC_REASON_DEFAULT = 0xBF +}; + +enum UwbPrimaryReasonCode{ + UWB_HOST_REASON_DEFAULT_NONE = 0x00, //INVALID REASON + UWB_HOST_REASON_PERI_SOC_CRASHED = 0x01, //PERI SOC WAS CRASHED + UWB_HOST_REASON_PERI_SOC_CRASHED_DIAG_SSR = 0x02, //PERI SOC CRASHED DIAG INITIATED SSR + UWB_HOST_REASON_INIT_FAILED = 0x03, //HOST INITIALIZATION FAILED + UWB_HOST_REASON_CLOSE_RCVD_DURING_INIT = 0x04, //CLOSE RECEIVED FROM STACK DURING SOC INIT + UWB_HOST_REASON_ERROR_READING_DATA_FROM_Q2SPI = 0x05, //ERROR READING DATA FROM Q2SPI + UWB_HOST_REASON_WRITE_FAIL_SPCL_BUFF_CRASH_SOC = 0x06, //FAILED TO WRITE SPECIAL BYTES TO CRASH SOC + UWB_HOST_REASON_RX_THREAD_STUCK = 0x07, //RX THREAD STUCK + UWB_HOST_REASON_SSR_CMD_TIMEDOUT = 0x08, //SSR DUE TO CMD TIMED OUT + UWB_HOST_REASON_SSR_INVALID_BYTES_RCVD = 0x0A, //INVALID HCI CMD TYPE RECEIVED + UWB_HOST_REASON_SSR_RCVD_LARGE_PKT_FROM_SOC = 0x0B, //SSR DUE TO LARGE PKT RECVIVED FROM SOC + UWB_HOST_REASON_SSR_UNABLE_TO_WAKEUP_SOC = 0x0C, //UNABLE TO WAKE UP SOC + UWB_HOST_REASON_CMD_TIMEDOUT_SOC_WAIT_TIMEOUT = 0x0D, //COMMAND TIMEOUT AND SOC CRASH WAIT TIMEOUT + UWB_HOST_REASON_INV_BYTES_SOC_WAIT_TIMEOUT = 0x0F, //INVALID BYTES AND SOC CRASH WAIT TIMEOUT + UWB_HOST_REASON_SOC_WAKEUP_FAILED_SOC_WAIT_TIMEOUT = 0x10, //SOC WAKEUP FAILURE AND SOC CRASH WAIT TIMEOUT + UWB_HOST_REASON_SOC_CRASHED_DIAG_SSR_SOC_WAIT_TIMEOUT = 0x11, //SOC CRASHED DIAG INITIATED SSR CRASH WAIT TIMEOUT + UWB_HOST_REASON_NONE_SOC_WAIT_TIMEOUT = 0x12, //INVALID FAILURE AND SOC CRASH WAIT TIMEOUT + UWB_HOST_REASON_SOC_DEINIT_STUCK = 0x13, //SOC DEINIT STUCK + UWB_HOST_REASON_SSR_INTERNAL_CMD_TIMEDOUT = 0x14, //SSR DUE TO CMD INTERNAL TIMED OUT + UWB_HOST_REASON_FAILED_TO_SEND_INTERNAL_CMD = 0x15, //FAILED TO SEND INTERNAL CMD + UWB_HOST_REASON_SSR_SLEEP_IND_NOT_RCVD = 0x16, //SOC DID NOT RCVD SLEEP IND DURING CLOSE + UWB_HOST_REASON_UWB_SOC_CRASHED = 0xC1, //UWB SOC WAS CRASHED + UWB_HOST_REASON_UWB_SOC_CRASHED_DIAG_SSR = 0xC2, //UWB SOC CRASHED DIAG INITIATED SSR + UWB_HOST_REASON_DIAG_LOG_API_STUCK = 0x39, //DIAG log API stuck. + UWB_HOST_REASON_PERI_CRASH_ON_OTHER_SS = 0x3A, //Peripheral core crash detected in BT SS + UWB_HOST_REASON_CRASH_EVT_INDUCED = 0x60, //Packet Type from SoC for inducing crash +}; + +enum UwbSecondaryReasonCode{ + UWB_SOC_REASON_DEFAULT = 0x00, + UWB_SOC_REASON_TX_RX_INVALID_PKT = 0x40, + UWB_SOC_REASON_TX_RX_INVALID_PKT_LENE = 0x41, + UWB_SOC_REASON_TX_RX_OVERFLOW_BUFF = 0x42, + UWB_SOC_REASON_UNKNOWN = 0x81, + UWB_SOC_REASON_SW_REQUESTED = 0x82, + UWB_SOC_REASON_STACK_OVERFLOW = 0x83, + UWB_SOC_REASON_EXCEPTION = 0x84, + UWB_SOC_REASON_ASSERT = 0x85, + UWB_SOC_REASON_TRAP = 0x86, + UWB_SOC_REASON_OS_FATAL = 0x87, + UWB_SOC_REASON_HCI_RESET = 0x88, + UWB_SOC_REASON_PATCH_RESET = 0x89, + UWB_SOC_REASON_ABT = 0x8A, + UWB_SOC_REASON_RAMMASK = 0x8B, + UWB_SOC_REASON_PREBARK = 0x8C, + UWB_SOC_REASON_BUSERROR = 0x8D, + UWB_SOC_REASON_IO_FATAL = 0x8E, + UWB_SOC_REASON_SSR_CMD = 0x8F, + UWB_SOC_REASON_POWERON = 0x90, + UWB_SOC_REASON_WATCHDOG = 0x91, + UWB_SOC_REASON_RAMMASK_RGN1 = 0x92, + UWB_SOC_REASON_RAMMASK_RGN0 = 0x93, + UWB_SOC_REASON_Q6_WATCHDOG = 0x94, + UWB_SOC_REASON_ZEALIS_RAM_MASK_RGN0 = 0x95, + UWB_SOC_REASON_ZEALIS_RAM_MASK_RGN1 = 0x96, + UWB_SOC_REASON_APSS_RESET = 0x97, + UWB_SOC_REASON_TIME_RESET = 0x98, + UWB_SOC_REASON_AUDIOSS_RESET = 0x99, + UWB_SOC_REASON_HOST_WARMRESET = 0x9A, + UWB_SOC_REASON_HOST_NMI_INIT = 0x9B, + UWB_SOC_REASON_TX_RX_INVALID_PKT_FATAL = 0xC0, + UWB_SOC_REASON_TX_RX_INVALID_LEN_FATAL = 0xC1, + UWB_SOC_REASON_TX_RX_OVERFLOW_FATAL = 0xC2, + UWB_SOC_REASON_INVALID_STACK = 0xF0, + UWB_HOST_REASON_PERI_GETVER_SEND_STUCK = 0x18, + UWB_HOST_REASON_PERI_GETVER_NO_RSP_RCVD = 0x19, + UWB_HOST_REASON_PERI_PATCH_DNLD_STUCK = 0x1B, + UWB_HOST_REASON_PERI_GETBOARDID_CMD_STUCK = 0x1C, + UWB_HOST_REASON_PERI_NVM_DNLD_STUCK = 0x1D, + UWB_HOST_REASON_PERI_RESET_STUCK = 0x1E, + UWB_HOST_REASON_PERI_GETBLDINFO_CMD_STUCK = 0x1F, + UWB_HOST_REASON_PERI_ENHLOG_CMD_STUCK = 0x21, + UWB_HOST_REASON_DIAGINIT_STUCK = 0x22, + UWB_HOST_REASON_DIAGDEINIT_STUCK = 0x23, + UWB_HOST_REASON_SECURE_BRIDGE_CMD_STUCK = 0x26, + UWB_HOST_REASON_FAILED_TO_SEND_CMD = 0x27, + UWB_HOST_REASON_PERI_RESET_CC_NOT_RCVD = 0x28, + UWB_HOST_REASON_HCI_PRE_SHUTDOWN_CC_NOT_RCVD = 0x29, + UWB_HOST_REASON_FAILED_TO_RECEIVE_SLEEP_IND = 0x2B, + UWB_HOST_REASON_POWER_ON_REGS_STUCK = 0x2C, + UWB_HOST_REASON_RX_THREAD_START_STUCK = 0x2D, + UWB_HOST_REASON_GET_LOCALADDR_STUCK = 0x2E, + UWB_HOST_REASON_OTP_INFO_GET_CMD_STUCK = 0x2F, + UWB_HOST_REASON_FILE_SYSTEM_CALL_STUCK = 0x30, + UWB_HOST_REASON_PROPERTY_GET_STUCK = 0x31, + UWB_HOST_REASON_PROPERTY_SET_STUCK = 0x32, + UWB_HOST_REASON_PERI_RAM_PATCH_READ_STUCK = 0x33, + UWB_HOST_REASON_PERI_NVM_PATCH_READ_STUCK = 0x34, + UWB_HOST_REASON_POWER_IOCTL_STUCK = 0x36, + UWB_HOST_REASON_PERI_PATCH_CONFIG_CMD_STUCK = 0x37, + UWB_HOST_REASON_PERI_PATCH_CONFIG_FAILED = 0x38, + UWB_HOST_REASON_UWB_GETVER_SEND_STUCK = 0x39, + UWB_HOST_REASON_UWB_GETVER_NO_RSP_RCVD = 0x3A, + UWB_HOST_REASON_SOC_NAME_UNKOWN = 0x3B, + UWB_HOST_REASON_PERI_GETVER_CMD_FAILED = 0x3C, + UWB_HOST_REASON_BAUDRATE_CHANGE_FAILED = 0x3D, + UWB_HOST_REASON_PERI_TLV_DOWNLOAD_FAILED = 0x3E, + UWB_HOST_REASON_PERI_GETBLDINFO_CMD_FAILED = 0x3F, + UWB_HOST_REASON_PERI_RESET_CMD_FAILED = 0x40, + UWB_HOST_REASON_MEMORY_ALLOCATION_FAILED = 0x42, + UWB_HOST_REASON_READ_THREAD_START_FAILED = 0x43, + UWB_HOST_REASON_HW_FLOW_ON_FAILED = 0x44, + UWB_HOST_REASON_PERI_NVM_FILE_NOT_FOUND = 0x45, + UWB_HOST_REASON_UWB_RAM_PATCH_READ_STUCK = 0x48, + UWB_HOST_REASON_UWB_NVM_PATCH_READ_STUCK = 0x49, + UWB_HOST_REASON_UWB_NVM_FILE_NOT_FOUND = 0x4A, + UWB_HOST_REASON_UWB_GETBLDINFO_CMD_FAILED = 0x4B, + UWB_HOST_REASON_UWB_PATCH_DNLD_STUCK = 0x4C, + UWB_HOST_REASON_UWB_NVM_DNLD_STUCK = 0x4D, + UWB_HOST_REASON_UWB_GETBLDINFO_CMD_STUCK = 0x4E, + UWB_HOST_REASON_PERI_ACTIVATE_CMD_STUCK = 0x4F, + UWB_HOST_REASON_PERI_ARBITRATION_CMD_STUCK = 0x50, + UWB_HOST_REASON_PERI_ARBITRATION_NTF_STUCK = 0x51, + UWB_HOST_REASON_INITIALIZATION_FAILED = 0x52, + UWB_HOST_REASON_UWB_RESET_CC_NOT_RCVD = 0x53, + UWB_HOST_REASON_UWB_ACTIVATE_CC_NOT_RCVD = 0x54, + UWB_HOST_REASON_TME_ACTIVATE_CC_NOT_RCVD = 0x55, + UWB_HOST_REASON_Q2SPI_INIT_STUCK = 0x56, + UWB_HOST_REASON_Q2SPI_INIT_FAILED = 0x57, + UWB_HOST_REASON_UWB_TLV_DOWNLOAD_FAILED = 0x58, + UWB_HOST_REASON_UWB_ENHLOG_CMD_STUCK = 0x59, + UWB_HOST_REASON_UWB_GETVER_CMD_FAILED = 0x5A, + UWB_HOST_REASON_UWB_PATCH_CONFIG_CMD_STUCK = 0x5B, + UWB_HOST_REASON_UWB_PATCH_CONFIG_CMD_FAILED = 0x5C, + UWB_HOST_REASON_UWB_RESET_STUCK = 0x5D, + UWB_HOST_REASON_PERI_ACTIVATE_NTF_STUCK = 0x5E, + UWB_HOST_REASON_UWB_CORE_RESET_CMD_FAILED = 0x5F, + UWB_HOST_REASON_TME_ARBITRATION_CMD_STUCK = 0x60, + UWB_HOST_REASON_TME_ARBITRATION_NTF_STUCK = 0x61, + UWB_HOST_REASON_TME_GETVER_SEND_STUCK = 0x62, + UWB_HOST_REASON_TME_GETVER_NO_RSP_RCVD = 0x63, + UWB_HOST_REASON_TME_GETVER_CMD_FAILED = 0x64, + UWB_HOST_REASON_TME_PATCH_DNLD_STUCK = 0x65, + UWB_HOST_REASON_TME_RESET_STUCK = 0x66, + UWB_HOST_REASON_TME_GETBLDINFO_CMD_STUCK = 0x67, + UWB_HOST_REASON_TME_GETBLDINFO_CMD_FAILED = 0x68, + UWB_HOST_REASON_TME_RAM_PATCH_READ_STUCK = 0x69, + Q2SPI_REASON_DEFAULT = 0xFF +}; + +typedef struct { + enum BtSecondaryReasonCode reason; + char reasonstr[50]; +} BtSecondaryReasonMap; + +typedef struct { + enum BtPrimaryReasonCode reason; + char reasonstr[100]; +} BtPrimaryReasonMap; + +typedef struct { + enum UwbSecondaryReasonCode reason; + char reasonstr[50]; +} UwbSecondaryReasonMap; + +typedef struct { + enum UwbPrimaryReasonCode reason; + char reasonstr[100]; +} UwbPrimaryReasonMap; + +static BtPrimaryReasonMap btPriReasonMap[] = { + { BT_DEFAULT_NONE, "Invalid reason"}, + { BT_SOC_CRASHED, "SOC crashed"}, + { BT_SOC_CRASHED_DIAG_SSR, "SOC crashed with diag initiated SSR"}, + { BT_INIT_FAILED, "Init failed"}, + { BT_CLOSE_RCVD_DURING_INIT, "Close received from stack during SOC init"}, + { BT_ERROR_READING_DATA_FROM_UART, "Error reading data from UART"}, + { BT_WRITE_FAIL_SPCL_BUFF_CRASH_SOC, + "Failed to write special bytes to crash SOC"}, + { BT_RX_THREAD_STUCK, "Thread Stuck"}, + { BT_SSR_CMD_TIMEDOUT, "SSR due to command timed out"}, + { BT_SSR_SPURIOUS_WAKEUP, "SSR due to spurious wakeup"}, + { BT_SSR_INVALID_BYTES_RCVD, "Invalid HCI cmd type received"}, + { BT_SSR_RCVD_LARGE_PKT_FROM_SOC, "Large packet received from SOC"}, + { BT_SSR_UNABLE_TO_WAKEUP_SOC, "Unable to wake SOC"}, + { BT_CMD_TIMEDOUT_SOC_WAIT_TIMEOUT, + "Command timedout and SOC crash wait timeout"}, + { BT_SPURIOUS_WAKEUP_SOC_WAIT_TIMEOUT, + "Spurious wake and SOC crash wait timeout"}, + { BT_INV_BYTES_SOC_WAIT_TIMEOUT, + "Invalid bytes received and SOC crash wait timeout"}, + { BT_SOC_WAKEUP_FAILED_SOC_WAIT_TIMEOUT, + "SOC Wakeup failed and SOC crash wait timeout"}, + { BT_SOC_CRASHED_DIAG_SSR_SOC_WAIT_TIMEOUT, + "SOC crashed with diag initiated SSR and SOC wait timeout"}, + { BT_NONE_SOC_WAIT_TIMEOUT, + "Invalid Reason and SOC crash wait timeout"}, + { BT_SOC_DEINIT_STUCK, "SOC Deinit Stuck"}, + { BT_SSR_INTERNAL_CMD_TIMEDOUT, "SSR due to internal Command timeout"}, + { BT_FAILED_TO_SEND_INTERNAL_CMD, "Failed to send internal command"}, + { BT_SSR_SLEEP_IND_NOT_RCVD, "Failed to receive SLEEP IND during close"}, + { BT_DIAG_LOG_API_STUCK, "DIAG log API stuck"}, + { BT_PERI_SOC_CRASHED, "Peri SOC crashed"}, + { BT_PERI_SOC_CRASHED_DIAG_SSR, "Peri SOC crashed with diag initiated SSR"}, + { BT_PERI_SOC_CRASHED_ON_OTHER_SUB_SYSTEM, + "Peripheral core crash deteced in UWB SS"}, + { BT_PERI_SUB_SYSTEM_FAILED_UPDATE_SSR_COMPLETE, + "UWB Sub-System failed to update SSR complete status"}, +}; + +static UwbPrimaryReasonMap uwbPriReasonMap[] = { + {UWB_HOST_REASON_DEFAULT_NONE, "Invalid reason"}, + {UWB_HOST_REASON_PERI_SOC_CRASHED, "Peri SOC crashed"}, + {UWB_HOST_REASON_UWB_SOC_CRASHED, "UWB SOC crashed"}, + {UWB_HOST_REASON_PERI_SOC_CRASHED_DIAG_SSR, "Peri SOC crashed with diag initiated SSR"}, + {UWB_HOST_REASON_UWB_SOC_CRASHED_DIAG_SSR, "UWB SOC crashed with diag initiated SSR"}, + {UWB_HOST_REASON_INIT_FAILED, "Init failed"}, + {UWB_HOST_REASON_CLOSE_RCVD_DURING_INIT, "Close received from stack during SOC init"}, + {UWB_HOST_REASON_ERROR_READING_DATA_FROM_Q2SPI, "Error reading data from Q2SPI"}, + {UWB_HOST_REASON_WRITE_FAIL_SPCL_BUFF_CRASH_SOC, "Failed to write special bytes to crash SOC"}, + {UWB_HOST_REASON_RX_THREAD_STUCK, "Rx Thread Stuck"}, + {UWB_HOST_REASON_SSR_CMD_TIMEDOUT, "SSR due to command timed out"}, + {UWB_HOST_REASON_SSR_RCVD_LARGE_PKT_FROM_SOC, "Large packet received from SOC"}, + {UWB_HOST_REASON_SSR_UNABLE_TO_WAKEUP_SOC, "Unable to wake SOC"}, + {UWB_HOST_REASON_CMD_TIMEDOUT_SOC_WAIT_TIMEOUT, "Command timedout and SOC crash wait timeout"}, + {UWB_HOST_REASON_INV_BYTES_SOC_WAIT_TIMEOUT, + "Invalid bytes received and SOC crash wait timeout"}, + {UWB_HOST_REASON_SOC_WAKEUP_FAILED_SOC_WAIT_TIMEOUT, + "SOC Wakeup failed and SOC crash wait timeout"}, + {UWB_HOST_REASON_SOC_CRASHED_DIAG_SSR_SOC_WAIT_TIMEOUT, + "SOC crashed with diag initiated SSR and SOC wait timeout"}, + {UWB_HOST_REASON_NONE_SOC_WAIT_TIMEOUT, "Invalid Reason and SOC crash wait timeout"}, + {UWB_HOST_REASON_SOC_DEINIT_STUCK, "SOC Deinit Stuck"}, + {UWB_HOST_REASON_SSR_INTERNAL_CMD_TIMEDOUT, "SSR due to internal Command timeout"}, + {UWB_HOST_REASON_FAILED_TO_SEND_INTERNAL_CMD, "Failed to send internal command"}, + {UWB_HOST_REASON_SSR_SLEEP_IND_NOT_RCVD, "Failed to receive SLEEP IND during close"}, + {UWB_HOST_REASON_PERI_CRASH_ON_OTHER_SS, "Peri SOC crashed detected on BT SS"}, + {UWB_HOST_REASON_DIAG_LOG_API_STUCK, "DIAG log API stuck"} +}; + +static BtSecondaryReasonMap btSecReasonMap[] = { + { BT_SOC_REASON_DEFAULT, "Default"}, + { BT_SOC_REASON_UNKNOWN, "Unknown"}, + { BT_SOC_REASON_TX_RX_INVALID_PKT_FATAL, + "Tx/Rx invalid packet fatal error"}, + { BT_SOC_REASON_TX_RX_INVALID_LEN_FATAL, + "Tx/Rx invalid length fatal error"}, + { BT_SOC_REASON_SW_REQUESTED, "SW Requested"}, + { BT_SOC_REASON_STACK_OVERFLOW, "Stack Overflow"}, + { BT_SOC_REASON_EXCEPTION, "Exception"}, + { BT_SOC_REASON_ASSERT, "Assert"}, + { BT_SOC_REASON_TRAP, "Trap"}, + { BT_SOC_REASON_OS_FATAL, "OS Fatal"}, + { BT_SOC_REASON_HCI_RESET, "HCI Reset"}, + { BT_SOC_REASON_PATCH_RESET, "Patch Reset"}, + { BT_SOC_REASON_ABT, "SoC Abort"}, + { BT_SOC_REASON_RAMMASK, "RAM MASK"}, + { BT_SOC_REASON_PREBARK, "PREBARK"}, + { BT_SOC_REASON_BUSERROR, "Bus error"}, + { BT_SOC_REASON_IO_FATAL, "IO fatal eror"}, + { BT_SOC_REASON_SSR_CMD, "SSR CMD"}, + { BT_SOC_REASON_POWERON, "Power ON"}, + { BT_SOC_REASON_WATCHDOG, "Watchdog"}, + { BT_SOC_REASON_RAMMASK_RGN1, "RAMMASK RGN1"}, + { BT_SOC_REASON_RAMMASK_RGN0, "RAMMASK RGN0"}, + { BT_SOC_REASON_Q6_WATCHDOG, "Q6 Watchdog"}, + { BT_SOC_REASON_ZEALIS_RAM_MASK_RGN0, "ZEALIS RAM MASK RGN0"}, + { BT_SOC_REASON_ZEALIS_RAM_MASK_RGN1, "ZEALIS RAM MASK RGN1"}, + { BT_SOC_REASON_APSS_RESET, "APSS reset"}, + { BT_SOC_REASON_TIME_RESET, "Time reset"}, + { BT_SOC_REASON_AUDIOSS_RESET, "Audioss reset"}, + { BT_SOC_REASON_HOST_WARMRESET, "Host warm reset"}, + { BT_SOC_REASON_HOST_NMI_INIT, "Host NMI init"}, + { BT_SOC_REASON_INVALID_STACK, "Invalid Stack"}, + { BT_HOST_REASON_UARTINIT_STUCK, "UartInitStuck"}, + { BT_HOST_REASON_GETVER_SEND_STUCK, "GetVerSendStuck"}, + { BT_HOST_REASON_GETVER_NO_RSP_RCVD, "GetVerNoRspRcvd"}, + { BT_HOST_REASON_SETBAUDRATE_CMD_STUCK, "SetBaudRateStuck"}, + { BT_HOST_REASON_PATCH_DNLD_STUCK, "PatchDnldStuck"}, + { BT_HOST_REASON_GETBOARDID_CMD_STUCK, "GetBoardIdStuck"}, + { BT_HOST_REASON_NVM_DNLD_STUCK, "NvmDnldStuck"}, + { BT_HOST_REASON_HCI_RESET_STUCK, "HciResetStuck"}, + { BT_HOST_REASON_GETBLDINFO_CMD_STUCK, "GetBldInfoCmdStuck"}, + { BT_HOST_REASON_ADDONFEAT_CMD_STUCK, "AddOnFeatCmdStuck"}, + { BT_HOST_REASON_ENHLOG_CMD_STUCK, "EnhLogCmdStuck"}, + { BT_HOST_REASON_DIAGINIT_STUCK, "DiagInitStuck"}, + { BT_HOST_REASON_DIAGDEINIT_STUCK, "DiagDeinitStuck"}, + { BT_HOST_REASON_XMEM_NVM_DNLD_STUCK, "XMEM NVM Download stuck"}, + { BT_HOST_REASON_XMEM_PATCH_DNLD_STUCK, "XMEM patch download stuck"}, + { BT_HOST_REASON_SECURE_BRIDGE_CMD_STUCK, "Secure bridge cmd stuck"}, + { BT_HOST_REASON_FAILED_TO_SEND_CMD, "Failed to send internal cmd"}, + { BT_HOST_REASON_HCI_RESET_CC_NOT_RCVD, "HCI Reset Cmd CC Not Rcvd"}, + { BT_HOST_REASON_HCI_PRE_SHUTDOWN_CC_NOT_RCVD, "HCI Pre shutdown Cmd CC not Rcvd"}, + { BT_HOST_REASON_HCI_SET_BD_ADDRESS_CC_NOT_RCVD, "HCI BD address CC not Rcvd"}, + { BT_HOST_REASON_FAILED_TO_RECEIVE_SLEEP_IND, "Failed to receive SLEEP IND from SoC"}, + { BT_HOST_REASON_POWER_ON_REGS_STUCK, "SoC Power ON Sequence stuck"}, + { BT_HOST_REASON_POWER_IOCTL_STUCK, "Power driver IOCTL stuck"}, + { BT_HOST_REASON_RX_THREAD_START_STUCK, "RX thread start stuck"}, + { BT_HOST_REASON_GET_LOCALADDR_STUCK, "Get local BD address stuck"}, + { BT_HOST_REASON_OTP_INFO_GET_CMD_STUCK, "Get OTP info. cmd stuck"}, + { BT_HOST_REASON_FILE_SYSTEM_CALL_STUCK, "FILE system call stuck"}, + { BT_HOST_REASON_PROPERTY_GET_STUCK, "Property get call stuck"}, + { BT_HOST_REASON_PROPERTY_SET_STUCK, "Property set call stuck"}, + { BT_HOST_REASON_RAM_PATCH_READ_STUCK, "RAM patch open/read stuck"}, + { BT_HOST_REASON_NVM_PATCH_READ_STUCK, "NVM file open/read stuck"}, + { BT_HOST_REASON_UART_IOCTL_STUCK, "UART IOCTL stuck"}, + { BT_HOST_REASON_PATCH_CONFIG_CMD_STUCK, "Patch config cmd stuck"}, + { BT_HOST_REASON_GET_APP_VER_CMD_STUCK, "Get APP version cmd stuck"}, + { BT_HOST_REASON_SOC_NAME_UNKOWN, "SoC name unkown"}, + { SOC_REASON_START_TX_IOS_SOC_RFR_HIGH_DURING_INIT, "SoC RFR high during INIT"}, + { BT_HOST_REASON_GETVER_CMD_FAILED, "Get Version cmd failed"}, + { BT_HOST_REASON_BAUDRATE_CHANGE_FAILED, "Baudrate change failed"}, + { BT_HOST_REASON_TLV_DOWNLOAD_FAILED, "TLV/NVM download failed"}, + { BT_HOST_REASON_FW_BUILD_INFO_CMD_FAILED, "FW build info. cmd failed"}, + { BT_HOST_REASON_HCI_RESET_CMD_FAILED, "HCI RESET cmd failed"}, + { BT_HOST_REASON_UART_INIT_FAILED, "UART INIT failed"}, + { BT_HOST_REASON_MEMORY_ALLOCATION_FAILED, "Memory allocation failed"}, + { BT_HOST_REASON_READ_THREAD_START_FAILED, "Read thread start failed"}, + { BT_HOST_REASON_HW_FLOW_ON_FAILED, "HW Flow ON failed"}, + { BT_HOST_REASON_NVM_FILE_NOT_FOUND, "NVM file not found"}, + { BT_HOST_REASON_UART_BAUDRATE_CHANGE_FAILED, "UART baudrate change failed"}, + { BT_HOST_REASON_PATCH_CONFIG_FAILED, "Patch config cmd failed"}, + { BT_HOST_REASON_HCI_SET_OFFLOAD_HOST_CONFIG_CC_NOT_RCVD, "offload host config CC not Rcvd"}, + { BT_HOST_REASON_BT_EN_PIN_LOW, "BT EN pin pulled low"}, + { UART_REASON_DEFAULT, "UART reason Default"}, + { UART_REASON_INVALID_FW_LOADED, "UART invalid FW loaded"}, + { UART_REASON_CLK_GET_FAIL, "UART CLK get failed"}, + { UART_REASON_SE_CLK_RATE_FIND_FAIL, "UART CLK rate find failed"}, + { UART_REASON_SE_RESOURCES_INIT_FAIL, "UART resources init failed"}, + { UART_REASON_SE_RESOURCES_ON_FAIL, "UART resources ON failed"}, + { UART_REASON_SE_RESOURCES_OFF_FAIL, "UART resources OFF failed"}, + { UART_REASON_TX_DMA_MAP_FAIL, "UART DMA map failed"}, + { UART_REASON_TX_CANCEL_FAIL, "UART tx cancel failed"}, + { UART_REASON_TX_ABORT_FAIL, "UART tx abort failed"}, + { UART_REASON_TX_FSM_RESET_FAIL, "UART tx FSM reset failed"}, + { UART_REASON_RX_CANCEL_FAIL, "UART rx cancel failed"}, + { UART_REASON_RX_ABORT_FAIL, "UART rx abort failed"}, + { UART_REASON_RX_FSM_RESET_FAIL, "UART rx FSM reset failed"}, + { UART_REASON_RX_TTY_INSET_FAIL, "UART rx tty inset failed"}, + { UART_REASON_ILLEGAL_INTERRUPT, "UART illegal interrupt"}, + { UART_REASON_BUFFER_OVERRUN, "UART buffer overrun"}, + { UART_REASON_RX_PARITY_REASON, "UART rx parity error"}, + { UART_REASON_RX_BREAK_REASON, "UART rx break error"}, + { UART_REASON_RX_SBE_REASON, "UART rx SBE error"}, + { SOC_REASON_START_TX_IOS_SOC_RFR_HIGH, "SoC RFR high"}, + { UART_REASON_FLOW_OFF, "UART flow is OFF"}, + { BT_HOST_REASON_PERI_ARBITRATION_CMD_STUCK, "Peri arbitration cmd stuck"}, + { BT_HOST_REASON_PERI_GETBLDINFO_CMD_STUCK, "Peri Get Bld Info CmdStuck"}, + { BT_HOST_REASON_BT_ACTIVATE_CMD_STUCK, "Subsystem Activate cmd stuck"}, + { BT_HOST_REASON_BT_ACTIVATE_NTF_STUCK, "Subsystem Activate ntf stuck"}, + { BT_HOST_REASON_PERI_GETVER_SEND_STUCK, "Peri Get Ver Send Stuck"}, + { BT_HOST_REASON_PERI_GETBLDINFO_CMD_STUCK, "Peri Get Bld Info Cmd Stuck"}, + { BT_HOST_REASON_PERI_RAM_PATCH_READ_STUCK, "Peri RAM patch open/read stuck"}, + { BT_HOST_REASON_PERI_RESET_STUCK, "Peri Reset Stuck"}, + { BT_HOST_REASON_PERI_PATCH_CONFIG_CMD_STUCK, "Peri Patch config cmd stuck"}, + { BT_HOST_REASON_PERI_PATCH_DNLD_STUCK, "Peri Patch Dnld Stuck"}, + { BT_HOST_REASON_PERI_RESET_CMD_FAILED, "HCI Peri RESET cmd failed"}, + { BT_HOST_REASON_BT_ACTIVATE_CMD_STUCK, "BT activate cmd stuck"}, + { BT_HOST_REASON_BT_ACTIVATE_CMD_FAILED, "BT activate cmd failed"}, + { BT_HOST_REASON_PERI_GETVER_CMD_FAILED, "Peri Get Ver cmd failed"}, + { BT_HOST_REASON_PERI_PATCH_CONFIG_FAILED, "Peri Patch config cmd failed"}, + { BT_HOST_REASON_PERI_TLV_DOWNLOAD_FAILED, "Peri TLV/NVM download failed"}, + { BT_HOST_REASON_PERI_GETBOARDID_CMD_STUCK, "Peri Get BoardId Stuck"}, + { BT_HOST_REASON_PERI_NVM_PATCH_READ_STUCK, "Peri NVM file open/read stuck"}, + { BT_HOST_REASON_PERI_NVM_DNLD_STUCK, "Peri Nvm Dnld Stuck"}, + { BT_HOST_REASON_PERI_GETBLDINFO_CMD_FAILED, "Peri FW build info. cmd failed"}, + { BT_HOST_REASON_PERI_GETVER_NO_RSP_RCVD, "Peri Get Ver No Rsp Rcvd"}, + { BT_HOST_REASON_PERI_SETBAUDRATE_CMD_STUCK, "Peri Set baud rate stuck"}, + { BT_HOST_REASON_PERI_SETBAUD_CC_NOT_RCVD, "Peri set baudrate cc nor rcvd"}, + { PERI_SOC_REASON_DEFAULT, "Default"}, +}; + +static UwbSecondaryReasonMap uwbSecReasonMap[] = { + { UWB_SOC_REASON_DEFAULT, "Default"}, + { UWB_SOC_REASON_TX_RX_INVALID_PKT, "Tx/Rx Inavlid Packet"}, + { UWB_SOC_REASON_TX_RX_INVALID_PKT_LENE, "Tx/Rx Invalid Pkt Len"}, + { UWB_SOC_REASON_TX_RX_OVERFLOW_BUFF, "Tx/Rx Overflow Buffer"}, + { UWB_SOC_REASON_UNKNOWN, "Unknown"}, + { UWB_SOC_REASON_TX_RX_INVALID_PKT_FATAL, "Tx/Rx invalid packet fatal error"}, + { UWB_SOC_REASON_TX_RX_INVALID_LEN_FATAL, "Tx/Rx invalid length fatal error"}, + { UWB_SOC_REASON_TX_RX_OVERFLOW_BUFF, "Tx/Rx Overflow Buffer"}, + { UWB_SOC_REASON_SW_REQUESTED, "SW Requested"}, + { UWB_SOC_REASON_STACK_OVERFLOW, "Stack Overflow"}, + { UWB_SOC_REASON_EXCEPTION, "Exception"}, + { UWB_SOC_REASON_ASSERT, "Assert"}, + { UWB_SOC_REASON_TRAP, "Trap"}, + { UWB_SOC_REASON_OS_FATAL, "OS Fatal"}, + { UWB_SOC_REASON_HCI_RESET, "HCI Reset"}, + { UWB_SOC_REASON_PATCH_RESET, "Patch Reset"}, + { UWB_SOC_REASON_ABT, "SoC Abort"}, + { UWB_SOC_REASON_RAMMASK, "RAM MASK"}, + { UWB_SOC_REASON_PREBARK, "PREBARK"}, + { UWB_SOC_REASON_BUSERROR, "Bus error"}, + { UWB_SOC_REASON_IO_FATAL, "IO fatal eror"}, + { UWB_SOC_REASON_SSR_CMD, "SSR CMD"}, + { UWB_SOC_REASON_POWERON, "Power ON"}, + { UWB_SOC_REASON_WATCHDOG, "Watchdog"}, + { UWB_SOC_REASON_RAMMASK_RGN1, "RAMMASK RGN1"}, + { UWB_SOC_REASON_RAMMASK_RGN0, "RAMMASK RGN0"}, + { UWB_SOC_REASON_Q6_WATCHDOG, "Q6 Watchdog"}, + { UWB_SOC_REASON_ZEALIS_RAM_MASK_RGN0, "ZEALIS RAM MASK RGN0"}, + { UWB_SOC_REASON_ZEALIS_RAM_MASK_RGN1, "ZEALIS RAM MASK RGN1"}, + { UWB_SOC_REASON_APSS_RESET, "APSS reset"}, + { UWB_SOC_REASON_TIME_RESET, "Time reset"}, + { UWB_SOC_REASON_AUDIOSS_RESET, "Audioss reset"}, + { UWB_SOC_REASON_HOST_WARMRESET, "Host warm reset"}, + { UWB_SOC_REASON_HOST_NMI_INIT, "Host NMI init"}, + { UWB_SOC_REASON_INVALID_STACK, "Invalid Stack"}, + { UWB_HOST_REASON_PERI_GETVER_SEND_STUCK, "PeriGetVerSendStuck"}, + { UWB_HOST_REASON_UWB_GETVER_SEND_STUCK, "UwbGetVerSendStuck"}, + { UWB_HOST_REASON_TME_GETVER_SEND_STUCK, "TmeGetVerSendStuck"}, + { UWB_HOST_REASON_PERI_GETVER_NO_RSP_RCVD, "PeriGetVerNoRspRcvd"}, + { UWB_HOST_REASON_UWB_GETVER_NO_RSP_RCVD, "UwbGetVerNoRspRcvd"}, + { UWB_HOST_REASON_TME_GETVER_NO_RSP_RCVD, "TmeGetVerNoRspRcvd"}, + { UWB_HOST_REASON_PERI_PATCH_DNLD_STUCK, "PeriPatchDnldStuck"}, + { UWB_HOST_REASON_UWB_PATCH_DNLD_STUCK, "UwbPatchDnldStuck"}, + { UWB_HOST_REASON_TME_PATCH_DNLD_STUCK, "TmePatchDnldStuck"}, + { UWB_HOST_REASON_PERI_GETBOARDID_CMD_STUCK, "PeriGetBoardIdStuck"}, + { UWB_HOST_REASON_PERI_NVM_DNLD_STUCK, "PeriNvmDnldStuck"}, + { UWB_HOST_REASON_UWB_NVM_DNLD_STUCK, "UwbNvmDnldStuck"}, + { UWB_HOST_REASON_PERI_RESET_STUCK, "PeriResetStuck"}, + { UWB_HOST_REASON_UWB_RESET_STUCK, "UwbResetStuck"}, + { UWB_HOST_REASON_TME_RESET_STUCK, "TmeResetStuck"}, + { UWB_HOST_REASON_PERI_GETBLDINFO_CMD_STUCK, "PeriGetBldInfoCmdStuck"}, + { UWB_HOST_REASON_UWB_GETBLDINFO_CMD_STUCK, "UwbGetBldInfoCmdStuck"}, + { UWB_HOST_REASON_TME_GETBLDINFO_CMD_STUCK, "TmeGetBldInfoCmdStuck"}, + { UWB_HOST_REASON_PERI_ENHLOG_CMD_STUCK, "Peri EnhLogCmdStuck"}, + { UWB_HOST_REASON_UWB_ENHLOG_CMD_STUCK, "Uwb EnhLogCmdStuck"}, + { UWB_HOST_REASON_DIAGINIT_STUCK, "DiagInitStuck"}, + { UWB_HOST_REASON_DIAGDEINIT_STUCK, "DiagDeinitStuck"}, + { UWB_HOST_REASON_FAILED_TO_SEND_CMD, "Failed to send internal cmd"}, + { UWB_HOST_REASON_PERI_RESET_CC_NOT_RCVD, "Peri Reset Cmd CC Not Rcvd"}, + { UWB_HOST_REASON_UWB_RESET_CC_NOT_RCVD, "UWB Reset Cmd CC Not Rcvd"}, + { UWB_HOST_REASON_UWB_ACTIVATE_CC_NOT_RCVD, "UWB Activate Cmd CC Not Rcvd"}, + { UWB_HOST_REASON_TME_ACTIVATE_CC_NOT_RCVD, "TME DeActivate Cmd CC Not Rcvd"}, + { UWB_HOST_REASON_POWER_ON_REGS_STUCK, "SoC Power ON Sequence stuck"}, + { UWB_HOST_REASON_POWER_IOCTL_STUCK, "Power driver IOCTL stuck"}, + { UWB_HOST_REASON_RX_THREAD_START_STUCK, "RX thread start stuck"}, + { UWB_HOST_REASON_OTP_INFO_GET_CMD_STUCK, "Get OTP info. cmd stuck"}, + { UWB_HOST_REASON_FILE_SYSTEM_CALL_STUCK, "FILE system call stuck"}, + { UWB_HOST_REASON_PROPERTY_GET_STUCK, "Property get call stuck"}, + { UWB_HOST_REASON_PROPERTY_SET_STUCK, "Property set call stuck"}, + { UWB_HOST_REASON_PERI_RAM_PATCH_READ_STUCK, "Peri RAM patch open/read stuck"}, + { UWB_HOST_REASON_UWB_RAM_PATCH_READ_STUCK, "UWB RAM patch open/read stuck"}, + { UWB_HOST_REASON_PERI_NVM_PATCH_READ_STUCK, "Peri NVM file open/read stuck"}, + { UWB_HOST_REASON_UWB_NVM_PATCH_READ_STUCK, "UWB NVM file open/read stuck"}, + { UWB_HOST_REASON_PERI_PATCH_CONFIG_CMD_STUCK, "Peri Patch config cmd stuck"}, + { UWB_HOST_REASON_PERI_PATCH_CONFIG_FAILED, "Peri Patch config cmd failed"}, + { UWB_HOST_REASON_UWB_PATCH_CONFIG_CMD_STUCK, "Uwb Patch config cmd stuck"}, + { UWB_HOST_REASON_UWB_PATCH_CONFIG_CMD_FAILED, "Uwb Patch config cmd stuck"}, + { UWB_HOST_REASON_SOC_NAME_UNKOWN, "SoC name unkown"}, + { UWB_HOST_REASON_PERI_TLV_DOWNLOAD_FAILED, "Peri TLV/NVM download failed"}, + { UWB_HOST_REASON_PERI_GETBLDINFO_CMD_FAILED, "Peri FW build info. cmd failed"}, + { UWB_HOST_REASON_UWB_GETBLDINFO_CMD_FAILED, "UWB build info. cmd failed"}, + { UWB_HOST_REASON_PERI_RESET_CMD_FAILED, "HCI Peri RESET cmd failed"}, + { UWB_HOST_REASON_UWB_CORE_RESET_CMD_FAILED, "UWB Core RESET cmd failed"}, + { UWB_HOST_REASON_MEMORY_ALLOCATION_FAILED, "Memory allocation failed"}, + { UWB_HOST_REASON_READ_THREAD_START_FAILED, "Read thread start failed"}, + { UWB_HOST_REASON_HW_FLOW_ON_FAILED, "HW Flow ON failed"}, + { UWB_HOST_REASON_PERI_ACTIVATE_CMD_STUCK, "Peri actvate cmd stuck"}, + { UWB_HOST_REASON_PERI_ACTIVATE_NTF_STUCK, "Peri activate ntf stuck"}, + { UWB_HOST_REASON_PERI_ARBITRATION_CMD_STUCK, "Peri arbitration cmd stuck"}, + { UWB_HOST_REASON_PERI_ARBITRATION_NTF_STUCK, "Peri arbitration ntf stuck"}, + { UWB_HOST_REASON_INITIALIZATION_FAILED, "Initialization Failed"}, + { UWB_HOST_REASON_Q2SPI_INIT_STUCK, "Q2SPI Init stuck"}, + { UWB_HOST_REASON_Q2SPI_INIT_FAILED, "Q2SPI Init Failed"}, + { UWB_HOST_REASON_UWB_TLV_DOWNLOAD_FAILED, "Uwb TLV/NVM download failed"}, + { Q2SPI_REASON_DEFAULT, "Q2SPI reason Default"}, +}; + struct log_index { int init; int crash; diff --git a/pwr/btpower.c b/pwr/btpower.c index e020557dee..0803ace42a 100644 --- a/pwr/btpower.c +++ b/pwr/btpower.c @@ -73,6 +73,8 @@ #define SIGIO_SSR_ON_UWB 0x00000001 #define SIGIO_UWB_SSR_COMPLETED 0x00000002 +#define CRASH_REASON_NOT_FOUND ((char *)"Crash reason not found") + /** * enum btpower_vreg_param: Voltage regulator TCS param * @BTPOWER_VREG_VOLTAGE: Provides voltage level to be configured in TCS @@ -2272,6 +2274,42 @@ int btpower_process_access_req(unsigned int cmd, int req) return ret; } +char* GetBtSecondaryCrashReason(enum BtSecondaryReasonCode reason) +{ + for(int i =0; i < (int)(sizeof(btSecReasonMap)/sizeof(BtSecondaryReasonMap)); i++) + if (btSecReasonMap[i].reason == reason) + return btSecReasonMap[i].reasonstr; + + return CRASH_REASON_NOT_FOUND; +} + +char* GetBtPrimaryCrashReason(enum BtPrimaryReasonCode reason) +{ + for(int i =0; i < (int)(sizeof(btPriReasonMap)/sizeof(BtPrimaryReasonMap)); i++) + if (btPriReasonMap[i].reason == reason) + return btPriReasonMap[i].reasonstr; + + return CRASH_REASON_NOT_FOUND; +} + +char* GetUwbSecondaryCrashReason(enum UwbSecondaryReasonCode reason) +{ + for(int i =0; i < (int)(sizeof(uwbSecReasonMap)/sizeof(UwbSecondaryReasonMap)); i++) + if (uwbSecReasonMap[i].reason == reason) + return uwbSecReasonMap[i].reasonstr; + + return CRASH_REASON_NOT_FOUND; +} + +char* GetUwbPrimaryCrashReason(enum UwbPrimaryReasonCode reason) +{ + for(int i =0; i < (int)(sizeof(uwbPriReasonMap)/sizeof(UwbPrimaryReasonMap)); i++) + if (uwbPriReasonMap[i].reason == reason) + return uwbPriReasonMap[i].reasonstr; + + return CRASH_REASON_NOT_FOUND; +} + static long bt_ioctl(struct file *file, unsigned int cmd, unsigned long arg) { int ret = 0; @@ -2415,20 +2453,24 @@ static long bt_ioctl(struct file *file, unsigned int cmd, unsigned long arg) panic_reason = (unsigned int)arg; primary_reason = panic_reason & 0xFFFF; sec_reason = (panic_reason & 0xFFFF0000) >> 16; - pr_err("%s: BT kernel panic primary reason [0x%04x] secondary reason [0x%04x]\n", - __func__, primary_reason, sec_reason); - panic("subsys-restart: Resetting the SoC - BT crashed primary reason [0x%04x] secondary reason [0x%04x]\n", - primary_reason, sec_reason); + pr_err("%s: BT kernel panic Primary reason = %s, Secondary reason = %s\n", + __func__, GetBtPrimaryCrashReason(primary_reason), + GetBtSecondaryCrashReason(sec_reason)); + panic("%s: BT kernel panic Primary reason = %s, Secondary reason = %s\n", + __func__, GetBtPrimaryCrashReason(primary_reason), + GetBtSecondaryCrashReason(sec_reason)); break; case UWB_CMD_KERNEL_PANIC: pr_err("%s: UWB_CMD_KERNEL_PANIC\n", __func__); panic_reason = (unsigned int)arg; primary_reason = panic_reason & 0xFFFF; sec_reason = (panic_reason & 0xFFFF0000) >> 16; - pr_err("%s: UWB kernel panic primary reason [0x%04x] secondary reason [0x%04x]\n", - __func__, primary_reason, sec_reason); - panic("subsys-restart: Resetting the SoC - UWB crashed primary reason [0x%04x] secondary reason [0x%04x]\n", - primary_reason, sec_reason); + pr_err("%s: UWB kernel panic Primary reason = %s, Secondary reason = %s\n", + __func__, GetUwbPrimaryCrashReason(primary_reason), + GetUwbSecondaryCrashReason(sec_reason)); + panic("%s: UWB kernel panic Primary reason = %s, Secondary reason = %s\n", + __func__, GetUwbPrimaryCrashReason(primary_reason), + GetUwbSecondaryCrashReason(sec_reason)); break; default: return -ENOIOCTLCMD; From b4787700d40b22b89a23c835fc3ebf093357e848 Mon Sep 17 00:00:00 2001 From: Balakrishna Godavarthi Date: Mon, 22 Jan 2024 13:08:11 +0530 Subject: [PATCH 087/154] btpower: Use high priority work queue This change used high priority work queue for voting regulators. Change-Id: I8cd0eb4cef00c25315b736dc39819b01469972e3 Signed-off-by: Balakrishna Godavarthi --- pwr/btpower.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pwr/btpower.c b/pwr/btpower.c index 0803ace42a..a06e9e9604 100644 --- a/pwr/btpower.c +++ b/pwr/btpower.c @@ -62,7 +62,7 @@ #define BTPOWER_MBOX_TIMEOUT_MS 1000 #define XO_CLK_RETRY_COUNT_MAX 5 #define MAX_PROP_SIZE 32 -#define BTPOWER_CONFIG_MAX_TIMEOUT 500 +#define BTPOWER_CONFIG_MAX_TIMEOUT 600 #define SIGIO_OOBS_SINGAL 0x00010000 #define SIGIO_NOTIFICATION_SIGNAL 0x00020000 @@ -2198,7 +2198,7 @@ int schedule_client_voting(enum plt_pwr_state request) *status = PWR_WAITING_RSP; skb_put_data(skb, &req, sizeof(uint32_t)); skb_queue_tail(&pwr_data->rxq, skb); - schedule_work(&pwr_data->wq_pwr_voting); + queue_work(system_highpri_wq, &pwr_data->wq_pwr_voting); mutex_unlock(&pwr_data->pwr_mtx); ret = wait_event_interruptible_timeout(*rsp_wait_q, (*status) != PWR_WAITING_RSP, msecs_to_jiffies(BTPOWER_CONFIG_MAX_TIMEOUT)); From b28a490153d84561039cd2434e1e37f85403082e Mon Sep 17 00:00:00 2001 From: Balakrishna Godavarthi Date: Thu, 1 Feb 2024 18:23:55 +0530 Subject: [PATCH 088/154] btpower: Update BT error reasons This change will update bt error reason to align with BT vendor. Change-Id: I485b603d5469d5308f50375bd5052bd88647931c Signed-off-by: Balakrishna Godavarthi --- include/btpower.h | 58 +++++++++++++++++++++++++---------------------- 1 file changed, 31 insertions(+), 27 deletions(-) diff --git a/include/btpower.h b/include/btpower.h index bc453cad00..c0af5da73e 100644 --- a/include/btpower.h +++ b/include/btpower.h @@ -315,33 +315,35 @@ enum BtSecondaryReasonCode { BT_HOST_REASON_PERI_ARBITRATION_CMD_STUCK = 0x67, BT_HOST_REASON_PERI_ARBITRATION_NTF_STUCK = 0x68, BT_HOST_REASON_BT_ACTIVATE_NTF_STUCK = 0x69, - BT_HOST_REASON_PERI_GETVER_SEND_STUCK = 0x70, - BT_HOST_REASON_PERI_GETBLDINFO_CMD_STUCK = 0x71, - BT_HOST_REASON_PERI_RAM_PATCH_READ_STUCK = 0x72, - BT_HOST_REASON_PERI_RESET_STUCK = 0x73, - BT_HOST_REASON_PERI_PATCH_CONFIG_CMD_STUCK= 0x74, - BT_HOST_REASON_PERI_PATCH_DNLD_STUCK = 0x75, - BT_HOST_REASON_PERI_RESET_CMD_FAILED = 0x76, - BT_HOST_REASON_BT_ACTIVATE_CMD_STUCK = 0x4F, - BT_HOST_REASON_BT_ACTIVATE_CMD_FAILED = 0x77, - BT_HOST_REASON_PERI_GETVER_CMD_FAILED = 0x78, - BT_HOST_REASON_PERI_PATCH_CONFIG_FAILED = 0x79, - BT_HOST_REASON_PERI_TLV_DOWNLOAD_FAILED = 0xB0, - BT_HOST_REASON_PERI_GETBOARDID_CMD_STUCK = 0xB1, - BT_HOST_REASON_PERI_NVM_PATCH_READ_STUCK = 0xB2, - BT_HOST_REASON_PERI_NVM_FILE_NOT_FOUND = 0xB3, - BT_HOST_REASON_PERI_NVM_DNLD_STUCK = 0XB4, - BT_HOST_REASON_PERI_GETBLDINFO_CMD_FAILED = 0XB5, - BT_HOST_REASON_PERI_GETVER_NO_RSP_RCVD = 0XB6, - BT_HOST_REASON_PERI_ARB_NOTIFY_FAILED = 0xB7, - BT_HOST_REASON_PERI_SETBAUDRATE_CMD_STUCK = 0xB8, - BT_HOST_REASON_PERI_SETBAUD_CMD_FAILED = 0xB9, - BT_HOST_REASON_MEMORY_ALLOCATION_FAILED_PERI = 0xBA, - BT_HOST_REASON_HCI_ACTIVATE_CC_NOT_RCVD = 0xBB, - BT_HOST_REASON_PERI_FILE_SYSTEM_CALL_STUCK = 0xBC, - BT_HOST_REASON_PERI_POWER_IOCTL_STUCK = 0xBD, - BT_HOST_REASON_PERI_SETBAUD_CC_NOT_RCVD = 0xBE, - PERI_SOC_REASON_DEFAULT = 0xBF + BT_HOST_REASON_PERI_GETVER_SEND_STUCK = 0x6A, + BT_HOST_REASON_PERI_GETBLDINFO_CMD_STUCK = 0x6B, + BT_HOST_REASON_PERI_RAM_PATCH_READ_STUCK = 0x6C, + BT_HOST_REASON_PERI_RESET_STUCK = 0x6D, + BT_HOST_REASON_PERI_PATCH_CONFIG_CMD_STUCK = 0x6E, + BT_HOST_REASON_PERI_PATCH_DNLD_STUCK = 0x6F, + BT_HOST_REASON_PERI_RESET_CMD_FAILED = 0x70, + BT_HOST_REASON_BT_ACTIVATE_CMD_STUCK = 0x71, + BT_HOST_REASON_BT_ACTIVATE_CMD_FAILED = 0x72, + BT_HOST_REASON_PERI_GETVER_CMD_FAILED = 0x73, + BT_HOST_REASON_PERI_PATCH_CONFIG_FAILED = 0x74, + BT_HOST_REASON_PERI_TLV_DOWNLOAD_FAILED = 0x75, + BT_HOST_REASON_PERI_GETBOARDID_CMD_STUCK = 0x76, + BT_HOST_REASON_PERI_NVM_PATCH_READ_STUCK = 0x77, + BT_HOST_REASON_PERI_NVM_FILE_NOT_FOUND = 0x78, + BT_HOST_REASON_PERI_NVM_DNLD_STUCK = 0X79, + BT_HOST_REASON_PERI_GETBLDINFO_CMD_FAILED = 0X7A, + BT_HOST_REASON_PERI_GETVER_NO_RSP_RCVD = 0X7B, + BT_HOST_REASON_PERI_ARB_NOTIFY_FAILED = 0x7C, + BT_HOST_REASON_PERI_SETBAUDRATE_CMD_STUCK = 0x7D, + BT_HOST_REASON_PERI_SETBAUD_CMD_FAILED = 0x7E, + BT_HOST_REASON_MEMORY_ALLOCATION_FAILED_PERI = 0x7F, + BT_HOST_REASON_HCI_ACTIVATE_CC_NOT_RCVD = 0xB0, + BT_HOST_REASON_PERI_FILE_SYSTEM_CALL_STUCK = 0xB1, + BT_HOST_REASON_PERI_POWER_IOCTL_STUCK = 0xB2, + BT_HOST_REASON_PERI_SETBAUD_CC_NOT_RCVD = 0xB3, + BT_HOST_REASON_PERI_ACCESS_STUCK = 0xB4, + BT_HOST_REASON_PERI_ACCESS_DISALLOWED = 0xB5, + PERI_SOC_REASON_DEFAULT = 0xB6 }; enum UwbPrimaryReasonCode{ @@ -704,6 +706,8 @@ static BtSecondaryReasonMap btSecReasonMap[] = { { BT_HOST_REASON_PERI_GETVER_NO_RSP_RCVD, "Peri Get Ver No Rsp Rcvd"}, { BT_HOST_REASON_PERI_SETBAUDRATE_CMD_STUCK, "Peri Set baud rate stuck"}, { BT_HOST_REASON_PERI_SETBAUD_CC_NOT_RCVD, "Peri set baudrate cc nor rcvd"}, + { BT_HOST_REASON_PERI_ACCESS_STUCK, "Peri Access stuck"}, + { BT_HOST_REASON_PERI_ACCESS_DISALLOWED, "Peri Access Disallowed"}, { PERI_SOC_REASON_DEFAULT, "Default"}, }; From b8cf49bc2ee6a9b4f768f313d57f663d1f46ec0a Mon Sep 17 00:00:00 2001 From: Balakrishna Godavarthi Date: Wed, 31 Jan 2024 22:10:47 +0530 Subject: [PATCH 089/154] btfmcodec: check before closing port This change will check whether port was previously opened before shutting down. Change-Id: I6b74a006c4c240fa9498747c8c3af214d3709dc3 Signed-off-by: Balakrishna Godavarthi --- btfmcodec/btfm_codec.c | 9 ++++++--- soundwire/btfm_swr_hw_interface.c | 6 ++++-- 2 files changed, 10 insertions(+), 5 deletions(-) diff --git a/btfmcodec/btfm_codec.c b/btfmcodec/btfm_codec.c index f6b5b35e5a..c9f9980355 100644 --- a/btfmcodec/btfm_codec.c +++ b/btfmcodec/btfm_codec.c @@ -119,9 +119,12 @@ static int btfmcodec_dev_release(struct inode *inode, struct file *file) wake_up_interruptible(&btfmcodec_dev->rsp_wait_q[idx]); } - cancel_work_sync(&btfmcodec_dev->wq_hwep_shutdown); - cancel_work_sync(&btfmcodec_dev->wq_hwep_configure); - cancel_work_sync(&btfmcodec_dev->wq_prepare_bearer); + if (btfmcodec_dev->wq_hwep_shutdown.func) + cancel_work_sync(&btfmcodec_dev->wq_hwep_shutdown); + if (btfmcodec_dev->wq_hwep_configure.func) + cancel_work_sync(&btfmcodec_dev->wq_hwep_configure); + if (btfmcodec_dev->wq_prepare_bearer.func) + cancel_work_sync(&btfmcodec_dev->wq_prepare_bearer); btfmcodec->states.current_state = IDLE; btfmcodec->states.next_state = IDLE; diff --git a/soundwire/btfm_swr_hw_interface.c b/soundwire/btfm_swr_hw_interface.c index 200c4e7016..82731a2de0 100644 --- a/soundwire/btfm_swr_hw_interface.c +++ b/soundwire/btfm_swr_hw_interface.c @@ -122,8 +122,10 @@ static void btfm_swr_dai_shutdown(void *dai, int id) BTFMSWR_INFO(""); - if (btfmswr == NULL) - BTFMSWR_INFO("btfmswr is NULL\n"); + if (btfmswr == NULL || btfmswr->p_dai_port == NULL) { + BTFMSWR_INFO("port shutdown might have called with out open\n"); + return; + } switch (id) { case FMAUDIO_TX: From cd35ecb58f11b2ef61f745f9baf65d57b73401b7 Mon Sep 17 00:00:00 2001 From: Franklin Abreu Bueno Date: Tue, 30 Jan 2024 10:44:48 -0800 Subject: [PATCH 090/154] Print Source Subsystem on UWB Kernel Panic - Will now print source subsystem when a kernel panic happens. - Added more UWB SoC crash reasons. Change-Id: I4311d6d1cb346ab4a2d3606038e36c401cd9497a Signed-off-by: Franklin Abreu Bueno --- include/btpower.h | 42 ++++++++++++++++++++++++++++++++++++++++++ pwr/btpower.c | 42 ++++++++++++++++++++++++++++++++---------- 2 files changed, 74 insertions(+), 10 deletions(-) diff --git a/include/btpower.h b/include/btpower.h index bc453cad00..386a8fc21d 100644 --- a/include/btpower.h +++ b/include/btpower.h @@ -405,10 +405,31 @@ enum UwbSecondaryReasonCode{ UWB_SOC_REASON_AUDIOSS_RESET = 0x99, UWB_SOC_REASON_HOST_WARMRESET = 0x9A, UWB_SOC_REASON_HOST_NMI_INIT = 0x9B, + UWB_SOC_REASON_PANIC_FAULT = 0x9C, + UWB_SOC_REASON_EARLY_TRAP = 0x9D, + UWB_SOC_REASON_INSTR_ADDR_MISALGIN = 0x9E, + UWB_SOC_REASON_INSTR_ACCESS_FAULT = 0x9F, + UWB_SOC_REASON_ILLEGAL_INSTR = 0xA0, + UWB_SOC_REASON_BREAKPOINT_EXCEPTION = 0xA1, + UWB_SOC_REASON_LOAD_ADDR_MISALIGN = 0xA2, + UWB_SOC_REASON_LOAD_ACCESS_FAULT = 0xA3, + UWB_SOC_REASON_STORE_ADDR_MISALGN = 0xA4, + UWB_SOC_REASON_STORE_ACCESS_FAULT = 0xA5, + UWB_SOC_REASON_ECALL_UMODE = 0xA6, + UWB_SOC_REASON_ECALL_MMODE = 0xA7, + UWB_SOC_REASON_STACK_UNDERFLOW = 0xA8, + UWB_SOC_REASON_MACHINE_EXIT_INT = 0xA9, + UWB_SOC_REASON_PERF_MONITOR_OVERFLOW = 0xAA, + UWB_SOC_REASON_EXT_SUBSYS_RESET = 0xAB, + UWB_SOC_REASON_IPC_STALL = 0xAC, + UWB_SOC_REASON_PEER_CPU0_NMI = 0xAD, + UWB_SOC_REASON_PEER_CPU1_NMI = 0xAE, + UWB_SOC_REASON_PEER_CPU2_NMI = 0xAF, UWB_SOC_REASON_TX_RX_INVALID_PKT_FATAL = 0xC0, UWB_SOC_REASON_TX_RX_INVALID_LEN_FATAL = 0xC1, UWB_SOC_REASON_TX_RX_OVERFLOW_FATAL = 0xC2, UWB_SOC_REASON_INVALID_STACK = 0xF0, + UWB_SOC_REASON_INVALID_MCI_MSG_RCVD = 0xF1, UWB_HOST_REASON_PERI_GETVER_SEND_STUCK = 0x18, UWB_HOST_REASON_PERI_GETVER_NO_RSP_RCVD = 0x19, UWB_HOST_REASON_PERI_PATCH_DNLD_STUCK = 0x1B, @@ -742,7 +763,28 @@ static UwbSecondaryReasonMap uwbSecReasonMap[] = { { UWB_SOC_REASON_AUDIOSS_RESET, "Audioss reset"}, { UWB_SOC_REASON_HOST_WARMRESET, "Host warm reset"}, { UWB_SOC_REASON_HOST_NMI_INIT, "Host NMI init"}, + { UWB_SOC_REASON_PANIC_FAULT, "Panic Fault"}, + { UWB_SOC_REASON_EARLY_TRAP, "Early Trap"}, + { UWB_SOC_REASON_INSTR_ADDR_MISALGIN, "Instruction Address Misalign"}, + { UWB_SOC_REASON_INSTR_ACCESS_FAULT, "Instruction Access Fault"}, + { UWB_SOC_REASON_ILLEGAL_INSTR, "Illegal Instruction"}, + { UWB_SOC_REASON_BREAKPOINT_EXCEPTION, "Breakpoint Exception"}, + { UWB_SOC_REASON_LOAD_ADDR_MISALIGN, "Load Address Misalign"}, + { UWB_SOC_REASON_LOAD_ACCESS_FAULT, "Load Access Fault"}, + { UWB_SOC_REASON_STORE_ADDR_MISALGN, "Store Address Misalign"}, + { UWB_SOC_REASON_STORE_ACCESS_FAULT, "Store Access Fault"}, + { UWB_SOC_REASON_ECALL_UMODE, "Ecall Umode"}, + { UWB_SOC_REASON_ECALL_MMODE, "Ecall Mmode"}, + { UWB_SOC_REASON_STACK_UNDERFLOW, "Stack Underflow"}, + { UWB_SOC_REASON_MACHINE_EXIT_INT, "Machine Exit Int"}, + { UWB_SOC_REASON_PERF_MONITOR_OVERFLOW, "Perf Monitor Overflow"}, + { UWB_SOC_REASON_EXT_SUBSYS_RESET, "Ext Subsystem Reset"}, + { UWB_SOC_REASON_IPC_STALL, "IPC Stall"}, + { UWB_SOC_REASON_PEER_CPU0_NMI, "Crash in Peri CPU"}, + { UWB_SOC_REASON_PEER_CPU1_NMI, "Crash in BT CPU"}, + { UWB_SOC_REASON_PEER_CPU2_NMI, "Crash in UWB CPU"}, { UWB_SOC_REASON_INVALID_STACK, "Invalid Stack"}, + { UWB_SOC_REASON_INVALID_MCI_MSG_RCVD, "Invalid MCI message received"}, { UWB_HOST_REASON_PERI_GETVER_SEND_STUCK, "PeriGetVerSendStuck"}, { UWB_HOST_REASON_UWB_GETVER_SEND_STUCK, "UwbGetVerSendStuck"}, { UWB_HOST_REASON_TME_GETVER_SEND_STUCK, "TmeGetVerSendStuck"}, diff --git a/pwr/btpower.c b/pwr/btpower.c index a06e9e9604..4d7b28b1b2 100644 --- a/pwr/btpower.c +++ b/pwr/btpower.c @@ -75,6 +75,11 @@ #define CRASH_REASON_NOT_FOUND ((char *)"Crash reason not found") +#define PERI_SS (0x00) +#define BT_SS (0x01) +#define UWB_SS (0x02) +#define TME_SS (0x03) + /** * enum btpower_vreg_param: Voltage regulator TCS param * @BTPOWER_VREG_VOLTAGE: Provides voltage level to be configured in TCS @@ -2310,12 +2315,26 @@ char* GetUwbPrimaryCrashReason(enum UwbPrimaryReasonCode reason) return CRASH_REASON_NOT_FOUND; } +const char *GetSourceSubsystemString(uint32_t source_subsystem) +{ + switch (source_subsystem) { + case PERI_SS: + return "Peri SS"; + case BT_SS: + return "BT SS"; + case UWB_SS: + return "UWB SS"; + default: + return "Unknown Subsystem"; + } +} + static long bt_ioctl(struct file *file, unsigned int cmd, unsigned long arg) { int ret = 0; int chipset_version = 0; - unsigned int panic_reason = 0; - unsigned short primary_reason = 0, sec_reason = 0; + unsigned long panic_reason = 0; + unsigned short primary_reason = 0, sec_reason = 0, source_subsystem = 0; #ifdef CONFIG_MSM_BT_OOBS enum btpower_obs_param clk_cntrl; @@ -2450,7 +2469,7 @@ static long bt_ioctl(struct file *file, unsigned int cmd, unsigned long arg) break; case BT_CMD_KERNEL_PANIC: pr_err("%s: BT_CMD_KERNEL_PANIC\n", __func__); - panic_reason = (unsigned int)arg; + panic_reason = arg; primary_reason = panic_reason & 0xFFFF; sec_reason = (panic_reason & 0xFFFF0000) >> 16; pr_err("%s: BT kernel panic Primary reason = %s, Secondary reason = %s\n", @@ -2462,15 +2481,18 @@ static long bt_ioctl(struct file *file, unsigned int cmd, unsigned long arg) break; case UWB_CMD_KERNEL_PANIC: pr_err("%s: UWB_CMD_KERNEL_PANIC\n", __func__); - panic_reason = (unsigned int)arg; + panic_reason = arg; primary_reason = panic_reason & 0xFFFF; sec_reason = (panic_reason & 0xFFFF0000) >> 16; - pr_err("%s: UWB kernel panic Primary reason = %s, Secondary reason = %s\n", - __func__, GetUwbPrimaryCrashReason(primary_reason), - GetUwbSecondaryCrashReason(sec_reason)); - panic("%s: UWB kernel panic Primary reason = %s, Secondary reason = %s\n", - __func__, GetUwbPrimaryCrashReason(primary_reason), - GetUwbSecondaryCrashReason(sec_reason)); + source_subsystem = (panic_reason & 0xFFFF00000000) >> 32; + pr_err("%s: UWB kernel panic PrimaryReason = (0x%02x)[%s] | SecondaryReason = (0x%02x)[%s] | SourceSubsystem = (0x%02x)[%s]\n", + __func__, primary_reason, GetUwbPrimaryCrashReason(primary_reason), + sec_reason, GetUwbSecondaryCrashReason(sec_reason), + source_subsystem, GetSourceSubsystemString(source_subsystem)); + panic("%s: UWB kernel panic PrimaryReason = (0x%02x)[%s] | SecondaryReason = (0x%02x)[%s] | SourceSubsystem = (0x%02x)[%s]\n", + __func__, primary_reason, GetUwbPrimaryCrashReason(primary_reason), + sec_reason, GetUwbSecondaryCrashReason(sec_reason), + source_subsystem, GetSourceSubsystemString(source_subsystem)); break; default: return -ENOIOCTLCMD; From da94d2294a70f6b61b67f3c81437d4c8b150f4aa Mon Sep 17 00:00:00 2001 From: Girish BN Date: Fri, 9 Feb 2024 03:19:15 +0530 Subject: [PATCH 091/154] Optimize Primary and Secondary panic reason logging in kernel - Sub-System directly sends the Primary and Secondary panic string to kernel, and will be logged in kernel. Change-Id: Ief755c0ab06975ecfa5613d51f171b4b38c6d1ce Signed-off-by: Girish BN --- include/btpower.h | 374 ---------------------------------------------- pwr/btpower.c | 42 +++--- 2 files changed, 17 insertions(+), 399 deletions(-) diff --git a/include/btpower.h b/include/btpower.h index da1b040472..d10c8ef404 100644 --- a/include/btpower.h +++ b/include/btpower.h @@ -156,196 +156,6 @@ enum { PWR_CLIENT_KILLED, }; -enum BtPrimaryReasonCode { - BT_DEFAULT_NONE = 0x00, //INVALID REASON - BT_SOC_CRASHED = 0x01, //SOC WAS CRASHED - BT_SOC_CRASHED_DIAG_SSR = 0x02, //SOC CRASHED DIAG INITIATED SSR - BT_INIT_FAILED = 0x03, //HOST INITIALIZATION FAILED - BT_CLOSE_RCVD_DURING_INIT = 0x04, //CLOSE RECEIVED FROM STACK DURING SOC INIT - BT_ERROR_READING_DATA_FROM_UART = 0x05, //ERROR READING DATA FROM UART - BT_WRITE_FAIL_SPCL_BUFF_CRASH_SOC = 0x06, //FAILED TO WRITE SPECIAL BYTES TO CRASH SOC - BT_RX_THREAD_STUCK = 0x07, //RX THREAD STUCK - BT_SSR_CMD_TIMEDOUT = 0x08, //SSR DUE TO CMD TIMED OUT - BT_SSR_SPURIOUS_WAKEUP = 0x09, //SSR DUE TO SPURIOUS WAKE UP - BT_SSR_INVALID_BYTES_RCVD = 0x0A, //INVALID HCI CMD TYPE RECEIVED - BT_SSR_RCVD_LARGE_PKT_FROM_SOC = 0x0B, //SSR DUE TO LARGE PKT RECVIVED FROM SOC - BT_SSR_UNABLE_TO_WAKEUP_SOC = 0x0C, //UNABLE TO WAKE UP SOC - BT_CMD_TIMEDOUT_SOC_WAIT_TIMEOUT = 0x0D, //COMMAND TIMEOUT AND SOC CRASH WAIT TIMEOUT - BT_SPURIOUS_WAKEUP_SOC_WAIT_TIMEOUT = 0x0E, //SPURIOUS WAKE AND SOC CRASH WAIT TIMEOUT - BT_INV_BYTES_SOC_WAIT_TIMEOUT = 0x0F, //INVALID BYTES AND SOC CRASH WAIT TIMEOUT - BT_SOC_WAKEUP_FAILED_SOC_WAIT_TIMEOUT = 0x10, //SOC WAKEUP FAILURE AND SOC CRASH WAIT TIMEOUT - BT_SOC_CRASHED_DIAG_SSR_SOC_WAIT_TIMEOUT = 0x11, //SOC CRASHED DIAG INITIATED SSR CRASH WAIT TIMEOUT - BT_NONE_SOC_WAIT_TIMEOUT = 0x12, //INVALID FAILURE AND SOC CRASH WAIT TIMEOUT - BT_SOC_DEINIT_STUCK = 0x13, //SOC DEINIT STUCK - BT_SSR_INTERNAL_CMD_TIMEDOUT = 0x14, //SSR DUE TO CMD INTERNAL TIMED OUT - BT_FAILED_TO_SEND_INTERNAL_CMD = 0x15, //FAILED TO SEND INTERNAL CMD - BT_SSR_SLEEP_IND_NOT_RCVD = 0x16, //SOC DID NOT RCVD SLEEP IND DURING CLOSE - BT_DIAG_LOG_API_STUCK = 0x39, //DIAG log API stuck. - BT_PERI_SOC_CRASHED_DIAG_SSR = 0x17, //PERI SOC CRASHED DIAG INITIATED SSR - BT_PERI_SOC_CRASHED = 0X18, //PERI SOC WAS CRASHED - BT_PERI_SOC_CRASHED_ON_OTHER_SUB_SYSTEM = 0x3A, //Peripheral core crash detected in UWB SS - BT_PERI_SUB_SYSTEM_FAILED_UPDATE_SSR_COMPLETE = 0x3B // UWB FAILED TO UPDATE THE SSR COMPLETE STATUS -}; - -enum BtSecondaryReasonCode { - BT_SOC_REASON_DEFAULT = 0x00, - BT_SOC_REASON_UNKNOWN = 0x81, - BT_SOC_REASON_SW_REQUESTED = 0x82, - BT_SOC_REASON_STACK_OVERFLOW = 0x83, - BT_SOC_REASON_EXCEPTION = 0x84, - BT_SOC_REASON_ASSERT = 0x85, - BT_SOC_REASON_TRAP = 0x86, - BT_SOC_REASON_OS_FATAL = 0x87, - BT_SOC_REASON_HCI_RESET = 0x88, - BT_SOC_REASON_PATCH_RESET = 0x89, - BT_SOC_REASON_ABT = 0x8A, - BT_SOC_REASON_RAMMASK = 0x8B, - BT_SOC_REASON_PREBARK = 0x8C, - BT_SOC_REASON_BUSERROR = 0x8D, - BT_SOC_REASON_IO_FATAL = 0x8E, - BT_SOC_REASON_SSR_CMD = 0x8F, - BT_SOC_REASON_POWERON = 0x90, - BT_SOC_REASON_WATCHDOG = 0x91, - BT_SOC_REASON_RAMMASK_RGN1 = 0x92, - BT_SOC_REASON_RAMMASK_RGN0 = 0x93, - BT_SOC_REASON_Q6_WATCHDOG = 0x94, - BT_SOC_REASON_ZEALIS_RAM_MASK_RGN0 = 0x95, - BT_SOC_REASON_ZEALIS_RAM_MASK_RGN1 = 0x96, - BT_SOC_REASON_APSS_RESET = 0x97, - BT_SOC_REASON_TIME_RESET = 0x98, - BT_SOC_REASON_AUDIOSS_RESET = 0x99, - BT_SOC_REASON_HOST_WARMRESET = 0x9A, - BT_SOC_REASON_HOST_NMI_INIT = 0x9B, - BT_SOC_REASON_PANIC_FAULT = 0x9C, - BT_SOC_REASON_EARLY_TRAP = 0x9D, - BT_SOC_REASON_INSTR_ADDR_MISALIGN = 0x9E, - BT_SOC_REASON_INSTR_ACCESS_FAULT = 0x9F, - BT_SOC_REASON_ILLEGAL_INSTR = 0xA0, - BT_SOC_REASON_BREAKPOINT_EXCEPTION = 0xA1, - BT_SOC_REASON_LOAD_ADDR_MISALIGN = 0xA2, - BT_SOC_REASON_LOAD_ACCESS_FAULT = 0xA3, - BT_SOC_REASON_STORE_ADDR_MISALIGN = 0xA4, - BT_SOC_REASON_STORE_ACCESS_FAULT = 0xA5, - BT_SOC_REASON_ECALL_UMODE = 0xA6, - BT_SOC_REASON_ECALL_MMODE = 0xA7, - BT_SOC_REASON_STACK_UNDERFLOW = 0xA8, - BT_SOC_REASON_MACHINE_EXT_INT = 0xA9, - BT_SOC_REASON_PERF_MONITOR_OVERFLOW= 0xAA, - BT_SOC_REASON_EXT_SUBSYS_RESET = 0xAB, - BT_SOC_REASON_IPC_STALL = 0xAC, - BT_SOC_REASON_PEER_CPU0_NMI = 0xAD, - BT_SOC_REASON_PEER_CPU1_NMI = 0xAE, - BT_SOC_REASON_PEER_CPU2_NMI = 0xAF, - BT_SOC_REASON_TX_RX_INVALID_PKT_FATAL = 0xC0, - BT_SOC_REASON_TX_RX_INVALID_LEN_FATAL = 0xC1, - BT_SOC_REASON_INVALID_STACK = 0xF0, - BT_SOC_REASON_INVALID_MCI_MSG_RCVD = 0xF1, - BT_HOST_REASON_UARTINIT_STUCK = 0x17, - BT_HOST_REASON_GETVER_SEND_STUCK = 0x18, - BT_HOST_REASON_GETVER_NO_RSP_RCVD = 0x19, - BT_HOST_REASON_SETBAUDRATE_CMD_STUCK = 0x1A, - BT_HOST_REASON_PATCH_DNLD_STUCK = 0x1B, - BT_HOST_REASON_GETBOARDID_CMD_STUCK = 0x1C, - BT_HOST_REASON_NVM_DNLD_STUCK = 0x1D, - BT_HOST_REASON_HCI_RESET_STUCK = 0x1E, - BT_HOST_REASON_GETBLDINFO_CMD_STUCK = 0x1F, - BT_HOST_REASON_ADDONFEAT_CMD_STUCK = 0x20, - BT_HOST_REASON_ENHLOG_CMD_STUCK = 0x21, - BT_HOST_REASON_DIAGINIT_STUCK = 0x22, - BT_HOST_REASON_DIAGDEINIT_STUCK = 0x23, - BT_HOST_REASON_XMEM_NVM_DNLD_STUCK = 0x24, - BT_HOST_REASON_XMEM_PATCH_DNLD_STUCK = 0x25, - BT_HOST_REASON_SECURE_BRIDGE_CMD_STUCK = 0x26, - BT_HOST_REASON_FAILED_TO_SEND_CMD = 0x27, - BT_HOST_REASON_HCI_RESET_CC_NOT_RCVD = 0x28, - BT_HOST_REASON_HCI_PRE_SHUTDOWN_CC_NOT_RCVD = 0x29, - BT_HOST_REASON_HCI_SET_BD_ADDRESS_CC_NOT_RCVD = 0x2A, - BT_HOST_REASON_FAILED_TO_RECEIVE_SLEEP_IND = 0x2B, - BT_HOST_REASON_POWER_ON_REGS_STUCK = 0x2C, - BT_HOST_REASON_RX_THREAD_START_STUCK = 0x2D, - BT_HOST_REASON_GET_LOCALADDR_STUCK = 0x2E, - BT_HOST_REASON_OTP_INFO_GET_CMD_STUCK = 0x2F, - BT_HOST_REASON_FILE_SYSTEM_CALL_STUCK = 0x30, - BT_HOST_REASON_PROPERTY_GET_STUCK = 0x31, - BT_HOST_REASON_PROPERTY_SET_STUCK = 0x32, - BT_HOST_REASON_RAM_PATCH_READ_STUCK = 0x33, - BT_HOST_REASON_NVM_PATCH_READ_STUCK = 0x34, - BT_HOST_REASON_UART_IOCTL_STUCK = 0x35, - BT_HOST_REASON_POWER_IOCTL_STUCK = 0x36, - BT_HOST_REASON_PATCH_CONFIG_CMD_STUCK = 0x37, - BT_HOST_REASON_GET_APP_VER_CMD_STUCK = 0x38, - BT_HOST_REASON_SOC_NAME_UNKOWN = 0x3A, - SOC_REASON_START_TX_IOS_SOC_RFR_HIGH_DURING_INIT = 0x3B, - BT_HOST_REASON_GETVER_CMD_FAILED = 0x3C, - BT_HOST_REASON_BAUDRATE_CHANGE_FAILED = 0x3D, - BT_HOST_REASON_TLV_DOWNLOAD_FAILED = 0x3E, - BT_HOST_REASON_FW_BUILD_INFO_CMD_FAILED = 0x3F, - BT_HOST_REASON_HCI_RESET_CMD_FAILED = 0x40, - BT_HOST_REASON_UART_INIT_FAILED = 0x41, - BT_HOST_REASON_MEMORY_ALLOCATION_FAILED = 0x42, - BT_HOST_REASON_READ_THREAD_START_FAILED = 0x43, - BT_HOST_REASON_HW_FLOW_ON_FAILED = 0x44, - BT_HOST_REASON_NVM_FILE_NOT_FOUND = 0x45, - BT_HOST_REASON_UART_BAUDRATE_CHANGE_FAILED = 0x46, - BT_HOST_REASON_PATCH_CONFIG_FAILED = 0x47, - BT_HOST_REASON_HCI_SET_OFFLOAD_HOST_CONFIG_CC_NOT_RCVD = 0x48, - BT_HOST_REASON_BT_EN_PIN_LOW = 0x49, - UART_REASON_DEFAULT = 0x51, - UART_REASON_INVALID_FW_LOADED = 0x52, - UART_REASON_CLK_GET_FAIL = 0x53, - UART_REASON_SE_CLK_RATE_FIND_FAIL = 0x54, - UART_REASON_SE_RESOURCES_INIT_FAIL = 0x55, - UART_REASON_SE_RESOURCES_ON_FAIL = 0x56, - UART_REASON_SE_RESOURCES_OFF_FAIL = 0x57, - UART_REASON_TX_DMA_MAP_FAIL = 0x58, - UART_REASON_TX_CANCEL_FAIL = 0x59, - UART_REASON_TX_ABORT_FAIL = 0x5A, - UART_REASON_TX_FSM_RESET_FAIL = 0x5B, - UART_REASON_RX_CANCEL_FAIL = 0x5C, - UART_REASON_RX_ABORT_FAIL = 0x5D, - UART_REASON_RX_FSM_RESET_FAIL = 0x5E, - UART_REASON_RX_TTY_INSET_FAIL = 0x5F, - UART_REASON_ILLEGAL_INTERRUPT = 0x60, - UART_REASON_BUFFER_OVERRUN = 0x61, - UART_REASON_RX_PARITY_REASON = 0x62, - UART_REASON_RX_BREAK_REASON = 0x63, - UART_REASON_RX_SBE_REASON = 0x64, - SOC_REASON_START_TX_IOS_SOC_RFR_HIGH = 0x65, - UART_REASON_FLOW_OFF = 0x66, - BT_HOST_REASON_PERI_ARBITRATION_CMD_STUCK = 0x67, - BT_HOST_REASON_PERI_ARBITRATION_NTF_STUCK = 0x68, - BT_HOST_REASON_BT_ACTIVATE_NTF_STUCK = 0x69, - BT_HOST_REASON_PERI_GETVER_SEND_STUCK = 0x6A, - BT_HOST_REASON_PERI_GETBLDINFO_CMD_STUCK = 0x6B, - BT_HOST_REASON_PERI_RAM_PATCH_READ_STUCK = 0x6C, - BT_HOST_REASON_PERI_RESET_STUCK = 0x6D, - BT_HOST_REASON_PERI_PATCH_CONFIG_CMD_STUCK = 0x6E, - BT_HOST_REASON_PERI_PATCH_DNLD_STUCK = 0x6F, - BT_HOST_REASON_PERI_RESET_CMD_FAILED = 0x70, - BT_HOST_REASON_BT_ACTIVATE_CMD_STUCK = 0x71, - BT_HOST_REASON_BT_ACTIVATE_CMD_FAILED = 0x72, - BT_HOST_REASON_PERI_GETVER_CMD_FAILED = 0x73, - BT_HOST_REASON_PERI_PATCH_CONFIG_FAILED = 0x74, - BT_HOST_REASON_PERI_TLV_DOWNLOAD_FAILED = 0x75, - BT_HOST_REASON_PERI_GETBOARDID_CMD_STUCK = 0x76, - BT_HOST_REASON_PERI_NVM_PATCH_READ_STUCK = 0x77, - BT_HOST_REASON_PERI_NVM_FILE_NOT_FOUND = 0x78, - BT_HOST_REASON_PERI_NVM_DNLD_STUCK = 0X79, - BT_HOST_REASON_PERI_GETBLDINFO_CMD_FAILED = 0X7A, - BT_HOST_REASON_PERI_GETVER_NO_RSP_RCVD = 0X7B, - BT_HOST_REASON_PERI_ARB_NOTIFY_FAILED = 0x7C, - BT_HOST_REASON_PERI_SETBAUDRATE_CMD_STUCK = 0x7D, - BT_HOST_REASON_PERI_SETBAUD_CMD_FAILED = 0x7E, - BT_HOST_REASON_MEMORY_ALLOCATION_FAILED_PERI = 0x7F, - BT_HOST_REASON_HCI_ACTIVATE_CC_NOT_RCVD = 0xB0, - BT_HOST_REASON_PERI_FILE_SYSTEM_CALL_STUCK = 0xB1, - BT_HOST_REASON_PERI_POWER_IOCTL_STUCK = 0xB2, - BT_HOST_REASON_PERI_SETBAUD_CC_NOT_RCVD = 0xB3, - BT_HOST_REASON_PERI_ACCESS_STUCK = 0xB4, - BT_HOST_REASON_PERI_ACCESS_DISALLOWED = 0xB5, - PERI_SOC_REASON_DEFAULT = 0xB6 -}; - enum UwbPrimaryReasonCode{ UWB_HOST_REASON_DEFAULT_NONE = 0x00, //INVALID REASON UWB_HOST_REASON_PERI_SOC_CRASHED = 0x01, //PERI SOC WAS CRASHED @@ -508,16 +318,6 @@ enum UwbSecondaryReasonCode{ Q2SPI_REASON_DEFAULT = 0xFF }; -typedef struct { - enum BtSecondaryReasonCode reason; - char reasonstr[50]; -} BtSecondaryReasonMap; - -typedef struct { - enum BtPrimaryReasonCode reason; - char reasonstr[100]; -} BtPrimaryReasonMap; - typedef struct { enum UwbSecondaryReasonCode reason; char reasonstr[50]; @@ -528,46 +328,6 @@ typedef struct { char reasonstr[100]; } UwbPrimaryReasonMap; -static BtPrimaryReasonMap btPriReasonMap[] = { - { BT_DEFAULT_NONE, "Invalid reason"}, - { BT_SOC_CRASHED, "SOC crashed"}, - { BT_SOC_CRASHED_DIAG_SSR, "SOC crashed with diag initiated SSR"}, - { BT_INIT_FAILED, "Init failed"}, - { BT_CLOSE_RCVD_DURING_INIT, "Close received from stack during SOC init"}, - { BT_ERROR_READING_DATA_FROM_UART, "Error reading data from UART"}, - { BT_WRITE_FAIL_SPCL_BUFF_CRASH_SOC, - "Failed to write special bytes to crash SOC"}, - { BT_RX_THREAD_STUCK, "Thread Stuck"}, - { BT_SSR_CMD_TIMEDOUT, "SSR due to command timed out"}, - { BT_SSR_SPURIOUS_WAKEUP, "SSR due to spurious wakeup"}, - { BT_SSR_INVALID_BYTES_RCVD, "Invalid HCI cmd type received"}, - { BT_SSR_RCVD_LARGE_PKT_FROM_SOC, "Large packet received from SOC"}, - { BT_SSR_UNABLE_TO_WAKEUP_SOC, "Unable to wake SOC"}, - { BT_CMD_TIMEDOUT_SOC_WAIT_TIMEOUT, - "Command timedout and SOC crash wait timeout"}, - { BT_SPURIOUS_WAKEUP_SOC_WAIT_TIMEOUT, - "Spurious wake and SOC crash wait timeout"}, - { BT_INV_BYTES_SOC_WAIT_TIMEOUT, - "Invalid bytes received and SOC crash wait timeout"}, - { BT_SOC_WAKEUP_FAILED_SOC_WAIT_TIMEOUT, - "SOC Wakeup failed and SOC crash wait timeout"}, - { BT_SOC_CRASHED_DIAG_SSR_SOC_WAIT_TIMEOUT, - "SOC crashed with diag initiated SSR and SOC wait timeout"}, - { BT_NONE_SOC_WAIT_TIMEOUT, - "Invalid Reason and SOC crash wait timeout"}, - { BT_SOC_DEINIT_STUCK, "SOC Deinit Stuck"}, - { BT_SSR_INTERNAL_CMD_TIMEDOUT, "SSR due to internal Command timeout"}, - { BT_FAILED_TO_SEND_INTERNAL_CMD, "Failed to send internal command"}, - { BT_SSR_SLEEP_IND_NOT_RCVD, "Failed to receive SLEEP IND during close"}, - { BT_DIAG_LOG_API_STUCK, "DIAG log API stuck"}, - { BT_PERI_SOC_CRASHED, "Peri SOC crashed"}, - { BT_PERI_SOC_CRASHED_DIAG_SSR, "Peri SOC crashed with diag initiated SSR"}, - { BT_PERI_SOC_CRASHED_ON_OTHER_SUB_SYSTEM, - "Peripheral core crash deteced in UWB SS"}, - { BT_PERI_SUB_SYSTEM_FAILED_UPDATE_SSR_COMPLETE, - "UWB Sub-System failed to update SSR complete status"}, -}; - static UwbPrimaryReasonMap uwbPriReasonMap[] = { {UWB_HOST_REASON_DEFAULT_NONE, "Invalid reason"}, {UWB_HOST_REASON_PERI_SOC_CRASHED, "Peri SOC crashed"}, @@ -598,140 +358,6 @@ static UwbPrimaryReasonMap uwbPriReasonMap[] = { {UWB_HOST_REASON_DIAG_LOG_API_STUCK, "DIAG log API stuck"} }; -static BtSecondaryReasonMap btSecReasonMap[] = { - { BT_SOC_REASON_DEFAULT, "Default"}, - { BT_SOC_REASON_UNKNOWN, "Unknown"}, - { BT_SOC_REASON_TX_RX_INVALID_PKT_FATAL, - "Tx/Rx invalid packet fatal error"}, - { BT_SOC_REASON_TX_RX_INVALID_LEN_FATAL, - "Tx/Rx invalid length fatal error"}, - { BT_SOC_REASON_SW_REQUESTED, "SW Requested"}, - { BT_SOC_REASON_STACK_OVERFLOW, "Stack Overflow"}, - { BT_SOC_REASON_EXCEPTION, "Exception"}, - { BT_SOC_REASON_ASSERT, "Assert"}, - { BT_SOC_REASON_TRAP, "Trap"}, - { BT_SOC_REASON_OS_FATAL, "OS Fatal"}, - { BT_SOC_REASON_HCI_RESET, "HCI Reset"}, - { BT_SOC_REASON_PATCH_RESET, "Patch Reset"}, - { BT_SOC_REASON_ABT, "SoC Abort"}, - { BT_SOC_REASON_RAMMASK, "RAM MASK"}, - { BT_SOC_REASON_PREBARK, "PREBARK"}, - { BT_SOC_REASON_BUSERROR, "Bus error"}, - { BT_SOC_REASON_IO_FATAL, "IO fatal eror"}, - { BT_SOC_REASON_SSR_CMD, "SSR CMD"}, - { BT_SOC_REASON_POWERON, "Power ON"}, - { BT_SOC_REASON_WATCHDOG, "Watchdog"}, - { BT_SOC_REASON_RAMMASK_RGN1, "RAMMASK RGN1"}, - { BT_SOC_REASON_RAMMASK_RGN0, "RAMMASK RGN0"}, - { BT_SOC_REASON_Q6_WATCHDOG, "Q6 Watchdog"}, - { BT_SOC_REASON_ZEALIS_RAM_MASK_RGN0, "ZEALIS RAM MASK RGN0"}, - { BT_SOC_REASON_ZEALIS_RAM_MASK_RGN1, "ZEALIS RAM MASK RGN1"}, - { BT_SOC_REASON_APSS_RESET, "APSS reset"}, - { BT_SOC_REASON_TIME_RESET, "Time reset"}, - { BT_SOC_REASON_AUDIOSS_RESET, "Audioss reset"}, - { BT_SOC_REASON_HOST_WARMRESET, "Host warm reset"}, - { BT_SOC_REASON_HOST_NMI_INIT, "Host NMI init"}, - { BT_SOC_REASON_INVALID_STACK, "Invalid Stack"}, - { BT_HOST_REASON_UARTINIT_STUCK, "UartInitStuck"}, - { BT_HOST_REASON_GETVER_SEND_STUCK, "GetVerSendStuck"}, - { BT_HOST_REASON_GETVER_NO_RSP_RCVD, "GetVerNoRspRcvd"}, - { BT_HOST_REASON_SETBAUDRATE_CMD_STUCK, "SetBaudRateStuck"}, - { BT_HOST_REASON_PATCH_DNLD_STUCK, "PatchDnldStuck"}, - { BT_HOST_REASON_GETBOARDID_CMD_STUCK, "GetBoardIdStuck"}, - { BT_HOST_REASON_NVM_DNLD_STUCK, "NvmDnldStuck"}, - { BT_HOST_REASON_HCI_RESET_STUCK, "HciResetStuck"}, - { BT_HOST_REASON_GETBLDINFO_CMD_STUCK, "GetBldInfoCmdStuck"}, - { BT_HOST_REASON_ADDONFEAT_CMD_STUCK, "AddOnFeatCmdStuck"}, - { BT_HOST_REASON_ENHLOG_CMD_STUCK, "EnhLogCmdStuck"}, - { BT_HOST_REASON_DIAGINIT_STUCK, "DiagInitStuck"}, - { BT_HOST_REASON_DIAGDEINIT_STUCK, "DiagDeinitStuck"}, - { BT_HOST_REASON_XMEM_NVM_DNLD_STUCK, "XMEM NVM Download stuck"}, - { BT_HOST_REASON_XMEM_PATCH_DNLD_STUCK, "XMEM patch download stuck"}, - { BT_HOST_REASON_SECURE_BRIDGE_CMD_STUCK, "Secure bridge cmd stuck"}, - { BT_HOST_REASON_FAILED_TO_SEND_CMD, "Failed to send internal cmd"}, - { BT_HOST_REASON_HCI_RESET_CC_NOT_RCVD, "HCI Reset Cmd CC Not Rcvd"}, - { BT_HOST_REASON_HCI_PRE_SHUTDOWN_CC_NOT_RCVD, "HCI Pre shutdown Cmd CC not Rcvd"}, - { BT_HOST_REASON_HCI_SET_BD_ADDRESS_CC_NOT_RCVD, "HCI BD address CC not Rcvd"}, - { BT_HOST_REASON_FAILED_TO_RECEIVE_SLEEP_IND, "Failed to receive SLEEP IND from SoC"}, - { BT_HOST_REASON_POWER_ON_REGS_STUCK, "SoC Power ON Sequence stuck"}, - { BT_HOST_REASON_POWER_IOCTL_STUCK, "Power driver IOCTL stuck"}, - { BT_HOST_REASON_RX_THREAD_START_STUCK, "RX thread start stuck"}, - { BT_HOST_REASON_GET_LOCALADDR_STUCK, "Get local BD address stuck"}, - { BT_HOST_REASON_OTP_INFO_GET_CMD_STUCK, "Get OTP info. cmd stuck"}, - { BT_HOST_REASON_FILE_SYSTEM_CALL_STUCK, "FILE system call stuck"}, - { BT_HOST_REASON_PROPERTY_GET_STUCK, "Property get call stuck"}, - { BT_HOST_REASON_PROPERTY_SET_STUCK, "Property set call stuck"}, - { BT_HOST_REASON_RAM_PATCH_READ_STUCK, "RAM patch open/read stuck"}, - { BT_HOST_REASON_NVM_PATCH_READ_STUCK, "NVM file open/read stuck"}, - { BT_HOST_REASON_UART_IOCTL_STUCK, "UART IOCTL stuck"}, - { BT_HOST_REASON_PATCH_CONFIG_CMD_STUCK, "Patch config cmd stuck"}, - { BT_HOST_REASON_GET_APP_VER_CMD_STUCK, "Get APP version cmd stuck"}, - { BT_HOST_REASON_SOC_NAME_UNKOWN, "SoC name unkown"}, - { SOC_REASON_START_TX_IOS_SOC_RFR_HIGH_DURING_INIT, "SoC RFR high during INIT"}, - { BT_HOST_REASON_GETVER_CMD_FAILED, "Get Version cmd failed"}, - { BT_HOST_REASON_BAUDRATE_CHANGE_FAILED, "Baudrate change failed"}, - { BT_HOST_REASON_TLV_DOWNLOAD_FAILED, "TLV/NVM download failed"}, - { BT_HOST_REASON_FW_BUILD_INFO_CMD_FAILED, "FW build info. cmd failed"}, - { BT_HOST_REASON_HCI_RESET_CMD_FAILED, "HCI RESET cmd failed"}, - { BT_HOST_REASON_UART_INIT_FAILED, "UART INIT failed"}, - { BT_HOST_REASON_MEMORY_ALLOCATION_FAILED, "Memory allocation failed"}, - { BT_HOST_REASON_READ_THREAD_START_FAILED, "Read thread start failed"}, - { BT_HOST_REASON_HW_FLOW_ON_FAILED, "HW Flow ON failed"}, - { BT_HOST_REASON_NVM_FILE_NOT_FOUND, "NVM file not found"}, - { BT_HOST_REASON_UART_BAUDRATE_CHANGE_FAILED, "UART baudrate change failed"}, - { BT_HOST_REASON_PATCH_CONFIG_FAILED, "Patch config cmd failed"}, - { BT_HOST_REASON_HCI_SET_OFFLOAD_HOST_CONFIG_CC_NOT_RCVD, "offload host config CC not Rcvd"}, - { BT_HOST_REASON_BT_EN_PIN_LOW, "BT EN pin pulled low"}, - { UART_REASON_DEFAULT, "UART reason Default"}, - { UART_REASON_INVALID_FW_LOADED, "UART invalid FW loaded"}, - { UART_REASON_CLK_GET_FAIL, "UART CLK get failed"}, - { UART_REASON_SE_CLK_RATE_FIND_FAIL, "UART CLK rate find failed"}, - { UART_REASON_SE_RESOURCES_INIT_FAIL, "UART resources init failed"}, - { UART_REASON_SE_RESOURCES_ON_FAIL, "UART resources ON failed"}, - { UART_REASON_SE_RESOURCES_OFF_FAIL, "UART resources OFF failed"}, - { UART_REASON_TX_DMA_MAP_FAIL, "UART DMA map failed"}, - { UART_REASON_TX_CANCEL_FAIL, "UART tx cancel failed"}, - { UART_REASON_TX_ABORT_FAIL, "UART tx abort failed"}, - { UART_REASON_TX_FSM_RESET_FAIL, "UART tx FSM reset failed"}, - { UART_REASON_RX_CANCEL_FAIL, "UART rx cancel failed"}, - { UART_REASON_RX_ABORT_FAIL, "UART rx abort failed"}, - { UART_REASON_RX_FSM_RESET_FAIL, "UART rx FSM reset failed"}, - { UART_REASON_RX_TTY_INSET_FAIL, "UART rx tty inset failed"}, - { UART_REASON_ILLEGAL_INTERRUPT, "UART illegal interrupt"}, - { UART_REASON_BUFFER_OVERRUN, "UART buffer overrun"}, - { UART_REASON_RX_PARITY_REASON, "UART rx parity error"}, - { UART_REASON_RX_BREAK_REASON, "UART rx break error"}, - { UART_REASON_RX_SBE_REASON, "UART rx SBE error"}, - { SOC_REASON_START_TX_IOS_SOC_RFR_HIGH, "SoC RFR high"}, - { UART_REASON_FLOW_OFF, "UART flow is OFF"}, - { BT_HOST_REASON_PERI_ARBITRATION_CMD_STUCK, "Peri arbitration cmd stuck"}, - { BT_HOST_REASON_PERI_GETBLDINFO_CMD_STUCK, "Peri Get Bld Info CmdStuck"}, - { BT_HOST_REASON_BT_ACTIVATE_CMD_STUCK, "Subsystem Activate cmd stuck"}, - { BT_HOST_REASON_BT_ACTIVATE_NTF_STUCK, "Subsystem Activate ntf stuck"}, - { BT_HOST_REASON_PERI_GETVER_SEND_STUCK, "Peri Get Ver Send Stuck"}, - { BT_HOST_REASON_PERI_GETBLDINFO_CMD_STUCK, "Peri Get Bld Info Cmd Stuck"}, - { BT_HOST_REASON_PERI_RAM_PATCH_READ_STUCK, "Peri RAM patch open/read stuck"}, - { BT_HOST_REASON_PERI_RESET_STUCK, "Peri Reset Stuck"}, - { BT_HOST_REASON_PERI_PATCH_CONFIG_CMD_STUCK, "Peri Patch config cmd stuck"}, - { BT_HOST_REASON_PERI_PATCH_DNLD_STUCK, "Peri Patch Dnld Stuck"}, - { BT_HOST_REASON_PERI_RESET_CMD_FAILED, "HCI Peri RESET cmd failed"}, - { BT_HOST_REASON_BT_ACTIVATE_CMD_STUCK, "BT activate cmd stuck"}, - { BT_HOST_REASON_BT_ACTIVATE_CMD_FAILED, "BT activate cmd failed"}, - { BT_HOST_REASON_PERI_GETVER_CMD_FAILED, "Peri Get Ver cmd failed"}, - { BT_HOST_REASON_PERI_PATCH_CONFIG_FAILED, "Peri Patch config cmd failed"}, - { BT_HOST_REASON_PERI_TLV_DOWNLOAD_FAILED, "Peri TLV/NVM download failed"}, - { BT_HOST_REASON_PERI_GETBOARDID_CMD_STUCK, "Peri Get BoardId Stuck"}, - { BT_HOST_REASON_PERI_NVM_PATCH_READ_STUCK, "Peri NVM file open/read stuck"}, - { BT_HOST_REASON_PERI_NVM_DNLD_STUCK, "Peri Nvm Dnld Stuck"}, - { BT_HOST_REASON_PERI_GETBLDINFO_CMD_FAILED, "Peri FW build info. cmd failed"}, - { BT_HOST_REASON_PERI_GETVER_NO_RSP_RCVD, "Peri Get Ver No Rsp Rcvd"}, - { BT_HOST_REASON_PERI_SETBAUDRATE_CMD_STUCK, "Peri Set baud rate stuck"}, - { BT_HOST_REASON_PERI_SETBAUD_CC_NOT_RCVD, "Peri set baudrate cc nor rcvd"}, - { BT_HOST_REASON_PERI_ACCESS_STUCK, "Peri Access stuck"}, - { BT_HOST_REASON_PERI_ACCESS_DISALLOWED, "Peri Access Disallowed"}, - { PERI_SOC_REASON_DEFAULT, "Default"}, -}; - static UwbSecondaryReasonMap uwbSecReasonMap[] = { { UWB_SOC_REASON_DEFAULT, "Default"}, { UWB_SOC_REASON_TX_RX_INVALID_PKT, "Tx/Rx Inavlid Packet"}, diff --git a/pwr/btpower.c b/pwr/btpower.c index 4d7b28b1b2..9a4bf7ec25 100644 --- a/pwr/btpower.c +++ b/pwr/btpower.c @@ -338,6 +338,12 @@ static struct { int uwb_state[BT_POWER_SRC_SIZE]; } power_src; +struct Crash_struct { +// char SubSystem[10]; + char PrimaryReason[50]; + char SecondaryReason[100]; +} CrashInfo; + #ifdef CONFIG_BT_HW_SECURE_DISABLE int perisec_cnss_bt_hw_disable_check(struct platform_pwr_data *plat_priv) { @@ -2279,24 +2285,6 @@ int btpower_process_access_req(unsigned int cmd, int req) return ret; } -char* GetBtSecondaryCrashReason(enum BtSecondaryReasonCode reason) -{ - for(int i =0; i < (int)(sizeof(btSecReasonMap)/sizeof(BtSecondaryReasonMap)); i++) - if (btSecReasonMap[i].reason == reason) - return btSecReasonMap[i].reasonstr; - - return CRASH_REASON_NOT_FOUND; -} - -char* GetBtPrimaryCrashReason(enum BtPrimaryReasonCode reason) -{ - for(int i =0; i < (int)(sizeof(btPriReasonMap)/sizeof(BtPrimaryReasonMap)); i++) - if (btPriReasonMap[i].reason == reason) - return btPriReasonMap[i].reasonstr; - - return CRASH_REASON_NOT_FOUND; -} - char* GetUwbSecondaryCrashReason(enum UwbSecondaryReasonCode reason) { for(int i =0; i < (int)(sizeof(uwbSecReasonMap)/sizeof(UwbSecondaryReasonMap)); i++) @@ -2468,16 +2456,20 @@ static long bt_ioctl(struct file *file, unsigned int cmd, unsigned long arg) btpower_enable_ipa_vreg(pwr_data); break; case BT_CMD_KERNEL_PANIC: + pr_err("%s: BT_CMD_KERNEL_PANIC\n", __func__); - panic_reason = arg; - primary_reason = panic_reason & 0xFFFF; - sec_reason = (panic_reason & 0xFFFF0000) >> 16; + + if (copy_from_user(&CrashInfo, (char *)arg, sizeof(CrashInfo))) { + pr_err("%s: copy to user failed\n", __func__); + ret = -EFAULT; + } + pr_err("%s: BT kernel panic Primary reason = %s, Secondary reason = %s\n", - __func__, GetBtPrimaryCrashReason(primary_reason), - GetBtSecondaryCrashReason(sec_reason)); + __func__, CrashInfo.PrimaryReason, CrashInfo.SecondaryReason); + panic("%s: BT kernel panic Primary reason = %s, Secondary reason = %s\n", - __func__, GetBtPrimaryCrashReason(primary_reason), - GetBtSecondaryCrashReason(sec_reason)); + __func__, CrashInfo.PrimaryReason, CrashInfo.SecondaryReason); + break; case UWB_CMD_KERNEL_PANIC: pr_err("%s: UWB_CMD_KERNEL_PANIC\n", __func__); From 015f55425f0cefb02685748812387f6f863961fd Mon Sep 17 00:00:00 2001 From: Girish BN Date: Fri, 9 Feb 2024 03:14:01 +0530 Subject: [PATCH 092/154] Optimizing Logging in BT Power driver - Removing Un-wanted Logging Change-Id: I0812ec9f558a6f1fe3dd29df1f520fe14a1d16cd Signed-off-by: Girish BN --- include/btpower.h | 179 +++++++++++++++++++++++++++++++++------------- pwr/btpower.c | 76 ++++++++++---------- 2 files changed, 166 insertions(+), 89 deletions(-) diff --git a/include/btpower.h b/include/btpower.h index d10c8ef404..9fac19f6d7 100644 --- a/include/btpower.h +++ b/include/btpower.h @@ -1,7 +1,7 @@ /* SPDX-License-Identifier: GPL-2.0-only */ /* * Copyright (c) 2016-2021, The Linux Foundation. All rights reserved. - * Copyright (c) 2021-2023 Qualcomm Innovation Center, Inc. All rights reserved. + * Copyright (c) 2021-2024 Qualcomm Innovation Center, Inc. All rights reserved. */ #ifndef __LINUX_BLUETOOTH_POWER_H @@ -72,50 +72,36 @@ enum grant_states { static inline char *ConvertGrantRetToString(enum grant_return_values state) { switch (state) { - case ACCESS_GRANTED: { + case ACCESS_GRANTED: return "ACCESS_GRANTED"; - break; - } case ACCESS_DENIED: { + case ACCESS_DENIED: return "ACCESS_DENIED"; - break; - } case ACCESS_RELEASED: { + case ACCESS_RELEASED: return "ACCESS_RELEASED"; - break; - } case ACCESS_DISALLOWED: { + case ACCESS_DISALLOWED: return "ACCESS_DISALLOWED"; - break; - } default: { + default: return "INVALID State"; - break; - } - } + } } -static inline char *ConvertGrantToString(enum grant_states state) +static inline char *ConvertGrantToString(enum grant_states state) { switch (state) { - case NO_GRANT_FOR_ANY_SS: { + case NO_GRANT_FOR_ANY_SS: return "NO_GRANT_FOR_ANY_SS"; - break; - } case NO_OTHER_CLIENT_WAITING_FOR_GRANT:{ + case NO_OTHER_CLIENT_WAITING_FOR_GRANT: return "NO_OTHER_CLIENT_WAITING_FOR_GRANT"; - break; - } case BT_HAS_GRANT : { + case BT_HAS_GRANT: return "BT_HAS_GRANT"; - break; - } case UWB_HAS_GRANT: { + case UWB_HAS_GRANT: return "UWB_HAS_GRANT"; - break; - } case BT_WAITING_FOR_GRANT : { + case BT_WAITING_FOR_GRANT: return "BT_WAITING_FOR_GRANT"; - break; - } case UWB_WAITING_FOR_GRANT: { + case UWB_WAITING_FOR_GRANT: return "UWB_WAITING_FOR_GRANT"; - break; - } default: { + default: return "INVALID STATE"; - break; - } } } @@ -156,6 +142,120 @@ enum { PWR_CLIENT_KILLED, }; +static inline char *ConvertRetentionModeToString(int state) +{ + switch (state) { + case IDLE: + return "Both client not in Retention"; + case BT_IN_RETENTION: + return "BT in Retention"; + case BT_OUT_OF_RETENTION: + return "BT is out off Retention"; + case UWB_IN_RETENTION: + return "UWB in Retention"; + case UWB_OUT_OF_RETENTION: + return "UWB is out off Retention"; + case BOTH_CLIENTS_IN_RETENTION: + return "Both client in Retention"; + default: + return "Retention state = INVALID STATE"; + } +} + +static inline char *ConvertClientReqToString(int arg) +{ + switch (arg) { + case POWER_DISABLE: + return "Power OFF"; + case POWER_ENABLE: + return "Power ON"; + case POWER_RETENTION: + return "Power Retention"; + default: + return "INVALID STATE"; + } +} + +static inline char *ConvertPowerStatusToString(int state) +{ + switch (state) { + case IDLE: + return "Current state is ALL Client OFF"; + case BT_ON: + return "Current state is BT powered ON"; + case UWB_ON: + return "Current state is UWB powered ON"; + case ALL_CLIENTS_ON: + return "Current state is ALL Client ON"; + default: + return "Current state is = INVALID STATE"; + } +} + +static inline char *ConvertSsrStatusToString(int state) +{ + switch (state) { + case SUB_STATE_IDLE: + return "and No SSR"; + case SSR_ON_BT: + return "and SSR on BT"; + case BT_SSR_COMPLETED: + return "and BT SSR completed"; + case SSR_ON_UWB: + return "and SSR on UWB"; + case UWB_SSR_COMPLETED: + return "and UWB SSR completed"; + default: + return "SSR STATE = INVALID STATE"; + } +} + +static inline char *ConvertPowerReqToString(int arg) +{ + switch (arg) { + case POWER_ON_BT: + return "POWER_ON_BT"; + case POWER_OFF_BT: + return "POWER_OFF_BT"; + case POWER_ON_UWB: + return "POWER_ON_UWB"; + case POWER_OFF_UWB: + return "POWER_OFF_UWB"; + case POWER_ON_BT_RETENION: + return "POWER_ON_BT_RETENION"; + case POWER_ON_UWB_RETENION: + return "POWER_ON_UWB_RETENION"; + case BT_ACCESS_REQ: + return "BT_ACCESS_REQ"; + case UWB_ACCESS_REQ: + return "UWB_ACCESS_REQ"; + case BT_RELEASE_ACCESS: + return "BT_RELEASE_ACCESS"; + case UWB_RELEASE_ACCESS: + return "UWB_RELEASE_ACCESS"; + case BT_MAX_PWR_STATE: + return "BT_MAX_PWR_STATE"; + default: + return "INVALID STATE"; + } +}; + +static inline char *ConvertRegisterModeToString(int reg_mode) +{ + switch (reg_mode) { + case POWER_DISABLE: + return "vote off"; + case POWER_ENABLE: + return "vote on"; + case POWER_RETENTION: + return "vote for retention"; + case POWER_DISABLE_RETENTION: + return "vote offretention"; + default: + return "INVALID STATE"; + } +} + enum UwbPrimaryReasonCode{ UWB_HOST_REASON_DEFAULT_NONE = 0x00, //INVALID REASON UWB_HOST_REASON_PERI_SOC_CRASHED = 0x01, //PERI SOC WAS CRASHED @@ -581,13 +681,6 @@ int btpower_get_chipset_version(void); int btpower_aop_mbox_init(struct platform_pwr_data *pdata); int bt_aop_pdc_reconfig(struct platform_pwr_data *pdata); -static char const *pwr_req[] = {"POWER_ON_BT", "POWER_OFF_BT", - "POWER_ON_UWB", "POWER_OFF_UWB", - "POWER_ON_BT_RETENION", - "POWER_ON_UWB_RETENION", - "BT_ACCESS_REQ", "UWB_ACCESS_REQ", - "BT_RELEASE_ACCESS", "UWB_RELEASE_ACCESS"}; - #define WLAN_SW_CTRL_GPIO "qcom,wlan-sw-ctrl-gpio" #define BT_CMD_SLIM_TEST 0xbfac #define BT_CMD_PWR_CTRL 0xbfad @@ -620,18 +713,4 @@ enum btpower_obs_param { BTPOWER_OBS_DEV_ON, }; #endif -static const char * const bt_arg[] = {"power off BT", "power on BT", - "BT power retention"}; -static const char * const uwb_arg[]= {"power off UWB", "power on UWB", - "UWB power retention"}; -static const char * const pwr_states[] = {"Both Sub-System powered OFF", "BT powered ON", - "UWB powered ON", - "Both Sub-System powered ON"}; -static const char * const ssr_state[ ] = {"No SSR on Sub-Sytem", "SSR on BT", - "SSR Completed on BT", "SSR on UWB", - "SSR Completed on UWB"}; -static const char * const reg_mode[ ] = {"vote off", "vote on", "vote for retention", "vote off retention"}; -static const char * const retention_mode[] = {"IDLE", "BT_IN_RETENTION", "BT_OUT_OF_RETENTION", - "UWB_IN_RETENTION", "UWB_OUT_OF_RETENTION", - "BOTH_CLIENT_IN_RETENTION"}; #endif /* __LINUX_BLUETOOTH_POWER_H */ diff --git a/pwr/btpower.c b/pwr/btpower.c index 9a4bf7ec25..91c64885a0 100644 --- a/pwr/btpower.c +++ b/pwr/btpower.c @@ -507,7 +507,7 @@ static int vreg_disable_retention(struct vreg_data *vreg) if (!vreg) return rc; - pr_err("%s: disable_retention for : %s\n", __func__, vreg->name); + pr_debug("%s: disable_retention for : %s\n", __func__, vreg->name); if ((vreg->is_enabled) && (vreg->is_retention_supp)) rc = vreg_configure(vreg, false); @@ -870,12 +870,12 @@ static int bt_regulators_pwr(int pwr_state) bt_num_vregs = pwr_data->bt_num_vregs; if (!bt_num_vregs) { - pr_warn("%s: not available to %s\n", - __func__, reg_mode[pwr_state]); + pr_warn("%s: not avilable to %s\n", + __func__, ConvertRegisterModeToString(pwr_state)); return 0; } - pr_info("%s: %s\n", __func__, reg_mode[pwr_state]); + pr_info("%s: %s\n", __func__, ConvertRegisterModeToString(pwr_state)); if (pwr_state == POWER_ENABLE) { /* Power On */ @@ -969,12 +969,12 @@ static int uwb_regulators_pwr(int pwr_state) uwb_num_vregs = pwr_data->uwb_num_vregs; if (!uwb_num_vregs) { - pr_warn("%s: not available to %s\n", - __func__, reg_mode[pwr_state]); + pr_warn("%s: not avilable to %s\n", + __func__, ConvertRegisterModeToString(pwr_state)); return 0; } - pr_info("%s: %s\n", __func__, reg_mode[pwr_state]); + pr_info("%s: %s\n", __func__, ConvertRegisterModeToString(pwr_state)); switch (pwr_state) { case POWER_ENABLE: @@ -1023,12 +1023,12 @@ static int platform_regulators_pwr(int pwr_state) platform_num_vregs = pwr_data->platform_num_vregs; if (!platform_num_vregs) { - pr_warn("%s: not available to %s\n", - __func__, reg_mode[pwr_state]); + pr_warn("%s: not avilable to %s\n", + __func__, ConvertRegisterModeToString(pwr_state)); return 0; } - pr_err("%s: %s\n", __func__, reg_mode[pwr_state]); + pr_info("%s: %s\n", __func__, ConvertRegisterModeToString(pwr_state)); switch (pwr_state) { case POWER_ENABLE: @@ -1771,16 +1771,16 @@ static inline enum grant_states btpower_get_grant_state(void) return state; } -static void update_sub_state(int state) -{ - pwr_data->sub_state = state; -} - static int get_sub_state(void) { return (int)pwr_data->sub_state; } +static void update_sub_state(int state) +{ + pwr_data->sub_state = state; +} + int power_enable (enum SubSystem SubSystemType) { int ret; @@ -2055,7 +2055,7 @@ int btpower_on(enum plt_pwr_state client) /* No Point in going further if SSR is on any subsystem */ if (current_ssr_state != SUB_STATE_IDLE) { pr_err("%s: %s not allowing to power on\n", __func__, - ssr_state[current_ssr_state]); + ConvertSsrStatusToString(current_ssr_state)); return -1; } @@ -2080,13 +2080,10 @@ int btpower_access_ctrl(enum plt_pwr_state request) enum grant_states grant_pending = btpower_get_grant_pending_state(); int current_ssr_state = get_sub_state(); - pr_info("%s: request for %s grant_state %s grant_pending %s", __func__, - pwr_req[(int)request], ConvertGrantToString(grant_state), - ConvertGrantToString(grant_pending)); - if (current_ssr_state != SUB_STATE_IDLE && - (request == BT_ACCESS_REQ || request == UWB_ACCESS_REQ)) { - pr_err("%s: not allowing this request as %s", __func__, ssr_state[current_ssr_state]); + (request == BT_ACCESS_REQ || request == UWB_ACCESS_REQ)) { + pr_err("%s: not allowing this request as %s\n", __func__, + ConvertSsrStatusToString(current_ssr_state)); return (int)ACCESS_DISALLOWED; } @@ -2159,10 +2156,11 @@ static void bt_power_vote(struct work_struct *work) request = STREAM_TO_UINT32(skb); skb_pull(skb, sizeof(uint32_t)); mutex_unlock(&pwr_data->pwr_mtx); - pr_err("%s: request from is %s cur state = %s %s retention %s access %s pending %s\n", - __func__, pwr_req[request], pwr_states[get_pwr_state()], - ssr_state[get_sub_state()], - retention_mode[btpower_get_retenion_mode_state()], + pr_info("%s: Start %s %s, %s state access %s pending %s\n", + __func__, + ConvertPowerStatusToString(get_pwr_state()), + ConvertSsrStatusToString(get_sub_state()), + ConvertRetentionModeToString(btpower_get_retenion_mode_state()), ConvertGrantToString(btpower_get_grant_state()), ConvertGrantToString(btpower_get_grant_pending_state())); if (request == POWER_ON_BT || request == POWER_ON_UWB) @@ -2175,10 +2173,11 @@ static void bt_power_vote(struct work_struct *work) ret = btpower_access_ctrl(request); pr_info("%s: grant status %s", __func__, ConvertGrantRetToString((int)ret)); } - pr_err("%s: request from is %s cur state = %s %s retention %s access %s pending %s\n", - __func__, pwr_req[request], pwr_states[get_pwr_state()], - ssr_state[get_sub_state()], - retention_mode[btpower_get_retenion_mode_state()], + pr_info("%s: Completed %s %s, %s state access %s pending %s\n", + __func__, + ConvertPowerStatusToString(get_pwr_state()), + ConvertSsrStatusToString(get_sub_state()), + ConvertRetentionModeToString(btpower_get_retenion_mode_state()), ConvertGrantToString(btpower_get_grant_state()), ConvertGrantToString(btpower_get_grant_pending_state())); @@ -2228,10 +2227,10 @@ int btpower_handle_client_request(unsigned int cmd, int arg) { int ret = -1; - pr_info("%s: %s cmd voted to %s, current state = %s, %s\n", __func__, - (cmd == BT_CMD_PWR_CTRL ? "BT_CMD_PWR_CTRL": "UWB_CMD_PWR_CTRL"), - bt_arg[(int)arg], pwr_states[get_pwr_state()], - ssr_state[(int)get_sub_state()]); + pr_info("%s: Start of %s cmd request to %s.\n", + __func__, + (cmd == BT_CMD_PWR_CTRL ? "BT_CMD_PWR_CTRL" : "UWB_CMD_PWR_CTRL"), + ConvertClientReqToString(arg)); if (cmd == BT_CMD_PWR_CTRL) { switch ((int)arg) { @@ -2258,8 +2257,7 @@ int btpower_handle_client_request(unsigned int cmd, int arg) break; } } - pr_err("%s: %s, SSR state = %s\n", __func__, - pwr_states[get_pwr_state()], ssr_state[(int)get_sub_state()]); + return ret; } @@ -2268,9 +2266,9 @@ int btpower_process_access_req(unsigned int cmd, int req) { int ret = -1; - pr_info("%s: by %s: request type %s", __func__, - cmd == BT_CMD_ACCESS_CTRL ? "BT": "UWB", - req == 1? "Request": "Release"); + pr_info("%s: by %s: request type %s\n", __func__, + cmd == BT_CMD_ACCESS_CTRL ? "BT_CMD_ACCESS_CTRL" : "UWB_CMD_ACCESS_CTRL", + req == 1 ? "Request" : "Release"); if (cmd == BT_CMD_ACCESS_CTRL && req == 1) ret = schedule_client_voting(BT_ACCESS_REQ); else if (cmd == BT_CMD_ACCESS_CTRL && req == 2) From 57259a61db5637e697c162a0af0133c6da98a01e Mon Sep 17 00:00:00 2001 From: Satish Kumar Kodishala Date: Mon, 4 Mar 2024 20:44:55 +0530 Subject: [PATCH 093/154] Delay after port closure when usecase ended for wcn6x5x Delay after port closure when usecase ended for WCN6x5x. This would give some time for SB to be in right state before next usecase starts and helps in quick SHO scenarios. CRs-Fixed: 3749420 Change-Id: I5efab4f3985bb3614f16510646cb3387dff3b4b1 --- slimbus/btfm_slim.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/slimbus/btfm_slim.c b/slimbus/btfm_slim.c index 46cd8342be..b3c5f9a606 100644 --- a/slimbus/btfm_slim.c +++ b/slimbus/btfm_slim.c @@ -251,7 +251,10 @@ int btfm_slim_disable_ch(struct btfmslim *btfmslim, struct btfmslim_ch *ch, chipset_ver == QCA_HAMILTON_SOC_ID_0200 || chipset_ver == QCA_APACHE_SOC_ID_0100 || chipset_ver == QCA_APACHE_SOC_ID_0110 || - chipset_ver == QCA_APACHE_SOC_ID_0121)) { + chipset_ver == QCA_APACHE_SOC_ID_0121 || + chipset_ver == QCA_MOSELLE_SOC_ID_0100 || + chipset_ver == QCA_MOSELLE_SOC_ID_0110 || + chipset_ver == QCA_MOSELLE_SOC_ID_0120)) { BTFMSLIM_INFO("SB reset needed after all ports disabled, sleeping"); msleep(DELAY_FOR_PORT_OPEN_MS); } From 45eaccfcdc5fe428b95d45676e9fd111e78ab210 Mon Sep 17 00:00:00 2001 From: janardhana rao bokka Date: Mon, 11 Mar 2024 11:40:40 +0530 Subject: [PATCH 094/154] btpower: Enabling FMD in BT kernel Enabling FMD in BT kernel module CRs-Fixed: 3766911 Change-Id: I59c9bad78580d178d59a7d890d407a142c0a0534 Signed-off-by: janardhana rao bokka --- include/btpower.h | 6 ++ pwr/btpower.c | 162 ++++++++++++++++++++++++++++++++++++++++------ 2 files changed, 147 insertions(+), 21 deletions(-) diff --git a/include/btpower.h b/include/btpower.h index 9fac19f6d7..ac67515f72 100644 --- a/include/btpower.h +++ b/include/btpower.h @@ -591,6 +591,7 @@ struct vreg_data { bool is_enabled; /* is this regulator enabled? */ bool is_retention_supp; /* does this regulator support retention mode */ struct log_index indx; /* Index for reg. w.r.t init & crash */ + bool fmd_mode_set; }; struct pwr_data { @@ -626,6 +627,7 @@ struct platform_pwr_data { int bt_gpio_sys_rst; /* Bluetooth reset gpio */ int wl_gpio_sys_rst; /* Wlan reset gpio */ int bt_gpio_sw_ctrl; /* Bluetooth sw_ctrl gpio */ + int bt_gpio_fmd_clk_ctrl; /* Bluetooth fmd_clk_ctrl gpio */ int bt_gpio_debug; /* Bluetooth debug gpio */ unsigned int wlan_sw_ctrl_gpio; /* Wlan switch control gpio*/ #ifdef CONFIG_MSM_BT_OOBS @@ -674,6 +676,9 @@ struct platform_pwr_data { struct work_struct wq_pwr_voting; struct sk_buff_head rxq; struct mutex pwr_mtx; + bool is_fmd_mode_enable; + struct nvmem_cell *nvmem_cell; + u32 fmd_clk_gpio_id; }; int btpower_register_slimdev(struct device *dev); @@ -696,6 +701,7 @@ int bt_aop_pdc_reconfig(struct platform_pwr_data *pdata); #define UWB_CMD_REGISTRATION 0xbfe3 #define BT_CMD_ACCESS_CTRL 0xbfe4 #define UWB_CMD_ACCESS_CTRL 0xbfe5 +#define SET_FMD_MODE_CTRL 0xbfb2 #ifdef CONFIG_MSM_BT_OOBS #define BT_CMD_OBS_VOTE_CLOCK 0xbfd1 diff --git a/pwr/btpower.c b/pwr/btpower.c index 91c64885a0..54dd73a16a 100644 --- a/pwr/btpower.c +++ b/pwr/btpower.c @@ -43,6 +43,7 @@ #include "btfm_slim.h" #endif #include +#include #ifdef CONFIG_BT_HW_SECURE_DISABLE #include "linux/smcinvoke_object.h" @@ -694,6 +695,11 @@ void bt_configure_wakeup_gpios(int on) } #endif +static int get_fmd_mode(void) +{ + return pwr_data->is_fmd_mode_enable; +} + static int bt_configure_gpios(int on) { int rc = 0; @@ -944,6 +950,11 @@ clk_fail: regulator_fail: for (i = 0; i < bt_num_vregs; i++) { bt_vregs = &pwr_data->bt_vregs[i]; + if (get_fmd_mode() && bt_vregs->fmd_mode_set) { + pr_err("%s: FMD Mode Set: Skipping regulator %s\n", + __func__, bt_vregs->name); + continue; + } rc = vreg_disable(bt_vregs); } } else if (pwr_state == POWER_RETENTION) { @@ -1056,10 +1067,12 @@ static int platform_regulators_pwr(int pwr_state) } break; case POWER_DISABLE: - rc = bt_configure_gpios(POWER_DISABLE); - if (rc < 0) { - pr_err("%s: bt_power gpio config failed\n", - __func__); + if (!get_fmd_mode()) { + rc = bt_configure_gpios(POWER_DISABLE); + if (rc < 0) { + pr_err("%s: bt_power gpio config failed\n", + __func__); + } } gpio_failed: if (pwr_data->bt_gpio_sys_rst > 0) @@ -1069,6 +1082,13 @@ gpio_failed: regulator_failed: for (i = 0; i < platform_num_vregs; i++) { platform_vregs = &pwr_data->platform_vregs[i]; + pr_err("%s: FMD MODE regulator %s\n", + __func__, platform_vregs->name); + if (get_fmd_mode() && platform_vregs->fmd_mode_set) { + pr_err("%s: FMD Mode Set: Skipping regulator %s\n", + __func__, platform_vregs->name); + continue; + } rc = vreg_disable(platform_vregs); } break; @@ -1220,15 +1240,27 @@ static int dt_parse_vreg_info(struct device *dev, struct device_node *child, if (IS_ERR(vreg->reg)) { ret = PTR_ERR(vreg->reg); vreg->reg = NULL; - pr_warn("%s: failed to get: %s error:%d\n", __func__, + pr_err("%s: failed to get: %s error:%d\n", __func__, vreg_name, ret); return ret; } snprintf(prop_name, sizeof(prop_name), "%s-config", vreg->name); prop = of_get_property(np, prop_name, &len); - if (!prop || len != (4 * sizeof(__be32))) { - pr_debug("%s: Property %s %s, use default\n", + if (!prop) { + pr_err("%s: Property %s %s, use default\n", + __func__, prop_name, + prop ? "invalid format" : "doesn't exist"); + } else if (len == (5 * sizeof(__be32))) { + vreg->min_vol = be32_to_cpup(&prop[0]); + vreg->max_vol = be32_to_cpup(&prop[1]); + vreg->load_curr = be32_to_cpup(&prop[2]); + vreg->is_retention_supp = be32_to_cpup(&prop[3]); + vreg->fmd_mode_set = be32_to_cpup(&prop[4]); + pr_err("%s: FMD mode %d for regulator %s\n", __func__, + vreg->fmd_mode_set, vreg->name); + } else if (len != (4 * sizeof(__be32))) { + pr_err("%s: Property %s %s, use default\n", __func__, prop_name, prop ? "invalid format" : "doesn't exist"); } else { @@ -1238,11 +1270,11 @@ static int dt_parse_vreg_info(struct device *dev, struct device_node *child, vreg->is_retention_supp = be32_to_cpup(&prop[3]); } - pr_debug("%s: Got regulator: %s, min_vol: %u, max_vol: %u, load_curr: %u,is_retention_supp: %u\n", + pr_err("%s: Got regulator: %s, min_vol: %u, max_vol: %u, load_curr: %u,is_retention_supp: %u\n", __func__, vreg->name, vreg->min_vol, vreg->max_vol, vreg->load_curr, vreg->is_retention_supp); } else { - pr_info("%s: %s is not provided in device tree\n", __func__, + pr_err("%s: %s is not provided in device tree\n", __func__, vreg_name); } return ret; @@ -1314,6 +1346,8 @@ static int get_gpio_dt_pinfo(struct platform_device *pdev) struct device_node *child; struct pinctrl *pinctrl1; struct pinctrl_state *sw_ctrl; + u32 gpio_id, i; + int gpio_id_n; child = pdev->dev.of_node; @@ -1337,25 +1371,46 @@ static int get_gpio_dt_pinfo(struct platform_device *pdev) if (pwr_data->bt_gpio_sw_ctrl < 0) pr_warn("bt-sw-ctrl-gpio not provided in devicetree\n"); + pwr_data->bt_gpio_fmd_clk_ctrl = + of_get_named_gpio(child, + "qcom,bt-fmd-clk-gpio", 0); + if (pwr_data->bt_gpio_fmd_clk_ctrl < 0) + pr_warn("bt-fmd-clk-gpio not provided in devicetree\n"); - ret = of_property_read_u32(child, "mpm_wake_set_gpios", - &pwr_data->sw_cntrl_gpio); - if (ret) - pr_warn("sw_cntrl-gpio not provided in devicetree\n"); + /* Find out and configure all those GPIOs which need to be setup + * for interrupt wakeup capable + * + */ + gpio_id_n = of_property_count_u32_elems(child, "mpm_wake_set_gpios"); + if (gpio_id_n > 0) { + pr_err("Num of GPIOs to be setup for interrupt wakeup capable: %d\n", + gpio_id_n); + for (i = 0; i < gpio_id_n; i++) { + ret = of_property_read_u32_index(child, + "mpm_wake_set_gpios", + i, &gpio_id); + if (ret) { + pr_err("Failed to read gpio_id at index: %d\n", i); + continue; + } + } + } else { + pr_err("No GPIOs to be setup for interrupt wakeup capable\n"); + } if (pinctrl1) { sw_ctrl = pinctrl_lookup_state(pinctrl1, "sw_ctrl"); - if (IS_ERR_OR_NULL(sw_ctrl)) { - ret = PTR_ERR(sw_ctrl); - pr_err("Failed to get sw_ctrl state, err = %d\n", ret); - } else { - ret = pinctrl_select_state(pinctrl1, sw_ctrl); + if (IS_ERR_OR_NULL(sw_ctrl)) { + ret = PTR_ERR(sw_ctrl); + pr_err("Failed to get sw_ctrl state, err = %d\n", ret); + } else { + ret = pinctrl_select_state(pinctrl1, sw_ctrl); if (ret) pr_err("Failed to select sw_ctrl state, err = %d\n", ret); } - } else { - pr_err("%s: pinctrl is null", __func__); - } + } else { + pr_err("%s: pinctrl is null\n", __func__); + } pwr_data->bt_gpio_debug = of_get_named_gpio(child, "qcom,bt-debug-gpio", 0); @@ -1552,6 +1607,31 @@ static int bt_power_probe(struct platform_device *pdev) pwr_data->pdev = pdev; + struct device *devi = &pwr_data->pdev->dev; + int rc = 0; + + pwr_data->nvmem_cell = devm_nvmem_cell_get(devi, "fmd_set"); + + if (IS_ERR(pwr_data->nvmem_cell)) { + rc = PTR_ERR(pwr_data->nvmem_cell); + pr_err("%s:Failed to get FMD nvmem-cells %d\n", __func__, rc); + } + pr_info("%s: --- Got FMD nvmem-cells %d\n", __func__, rc); + if (rc >= 0) { + u8 *buf; + size_t len; + + dev_info(&pwr_data->pdev->dev, "Got fmd_set nvmem_cell\n"); + buf = nvmem_cell_read(pwr_data->nvmem_cell, &len); + if (IS_ERR(buf)) { + dev_err(&pwr_data->pdev->dev, "Failed to read fmd_set: %ld\n", + PTR_ERR(buf)); + } else { + dev_info(&pwr_data->pdev->dev, "fmd_set: %u\n", buf[0]); + kfree(buf); + } + } + pwr_data->is_ganges_dt = of_property_read_bool(pdev->dev.of_node, "qcom,peach-bt") || of_property_read_bool(pdev->dev.of_node, @@ -2315,6 +2395,32 @@ const char *GetSourceSubsystemString(uint32_t source_subsystem) } } +void set_fmd_sdam_bit(void) +{ + int rc = 0; + unsigned char sdam_bit = 1; + + rc = nvmem_cell_write(pwr_data->nvmem_cell, &sdam_bit, sizeof(sdam_bit)); + if (rc < 0) { + pr_err("%s: SDAM BIT of FMD Write Failed %d\n", __func__, rc); + return; + } + pr_warn("%s: SDAM BIT of FMD Write Success %d\n", __func__, rc); + + u8 *buf; + size_t len; + + dev_info(&pwr_data->pdev->dev, "Got fmd_set nvmem_cell\n"); + buf = nvmem_cell_read(pwr_data->nvmem_cell, &len); + if (IS_ERR(buf)) { + dev_err(&pwr_data->pdev->dev, "Failed to read fmd_set: %ld\n", PTR_ERR(buf)); + } else { + dev_info(&pwr_data->pdev->dev, "fmd_set: %u\n", buf[0]); + pr_warn("%s: Read SDAM BIT of FMD %d\n", __func__, buf[0]); + kfree(buf); + } +} + static long bt_ioctl(struct file *file, unsigned int cmd, unsigned long arg) { int ret = 0; @@ -2384,6 +2490,20 @@ static long bt_ioctl(struct file *file, unsigned int cmd, unsigned long arg) ret = btpower_handle_client_request(cmd, (int)arg); break; } + case SET_FMD_MODE_CTRL: { + pr_warn("%s: SET_FMD_MODE_CTRL\n", __func__); + pwr_data->is_fmd_mode_enable = true; + ret = btpower_handle_client_request(BT_CMD_PWR_CTRL, (int)POWER_ENABLE); + if (pwr_data->bt_chip_clk) { + ret = bt_clk_enable(pwr_data->bt_chip_clk); + if (ret < 0) { + pr_err("%s: bt_power gpio config failed\n", __func__); + return -EINVAL; + } + } + set_fmd_sdam_bit(); + break; + } case BT_CMD_REGISTRATION: btpower_register_client(BLUETOOTH, (int)arg); break; From babb345ba19e10f02902a0256e5e9e131006fa79 Mon Sep 17 00:00:00 2001 From: Satish Kumar Kodishala Date: Wed, 13 Mar 2024 12:36:54 +0530 Subject: [PATCH 095/154] Add retry for getting logical device number for SoundWire Add retry logic for getting logcal device number for SoundWire during port open. CRs-Fixed: 3766977, 3741267 Change-Id: I722f788e267b76b7796a7bd62916f4cf88d2a570 Signed-off-by: Satish Kumar Kodishala --- soundwire/btfm_swr.c | 19 +++++++++++++------ soundwire/btfm_swr.h | 4 +++- 2 files changed, 16 insertions(+), 7 deletions(-) diff --git a/soundwire/btfm_swr.c b/soundwire/btfm_swr.c index 4ba58d6a35..332e124607 100644 --- a/soundwire/btfm_swr.c +++ b/soundwire/btfm_swr.c @@ -1,6 +1,6 @@ // SPDX-License-Identifier: GPL-2.0-only /* - * Copyright (c) 2023 Qualcomm Innovation Center, Inc. All rights reserved. + * Copyright (c) 2023-2024 Qualcomm Innovation Center, Inc. All rights reserved. */ @@ -53,6 +53,7 @@ int btfm_swr_hw_init(void) uint8_t dev_num = 0; int ret = 0; int chipset_ver; + uint8_t retry = 0; BTFMSWR_DBG(""); @@ -72,15 +73,21 @@ int btfm_swr_hw_init(void) // get logical address /* - * Add 5msec delay to provide sufficient time for + * Add delay to provide sufficient time for * soundwire auto enumeration of slave devices as * per HW requirement. */ - usleep_range(5000, 5010); - ret = swr_get_logical_dev_num(pbtfmswr->swr_slave, pbtfmswr->p_dai_port->ea, - &dev_num); + for ( ; retry < MAX_GET_DEV_NUM_RETRY; retry++) { + ret = swr_get_logical_dev_num(pbtfmswr->swr_slave, + pbtfmswr->p_dai_port->ea, + &dev_num); + if (ret == 0) + break; + usleep_range(2000, 2100); + } if (ret) { - BTFMSWR_ERR("error while getting logical device number"); + BTFMSWR_ERR("error getting logical device num after retry %u", + retry); goto err; } diff --git a/soundwire/btfm_swr.h b/soundwire/btfm_swr.h index f1e643d37f..ecff8701ee 100644 --- a/soundwire/btfm_swr.h +++ b/soundwire/btfm_swr.h @@ -1,6 +1,6 @@ // SPDX-License-Identifier: GPL-2.0-only /* - * Copyright (c) 2023 Qualcomm Innovation Center, Inc. All rights reserved. + * Copyright (c) 2023-2024 Qualcomm Innovation Center, Inc. All rights reserved. */ @@ -27,6 +27,8 @@ extern struct btfmswr *pbtfmswr; #define MAX_BT_PORTS 1 +#define MAX_GET_DEV_NUM_RETRY 15 + /* Codec driver defines */ enum { FMAUDIO_TX = 0, From a886adb18eaebe97e6a415e5d037f9b620f0afa1 Mon Sep 17 00:00:00 2001 From: Balakrishna Godavarthi Date: Mon, 15 Apr 2024 17:43:52 +0530 Subject: [PATCH 096/154] btpower: fix kwlock issues This change fixes kwlock issues. Change-Id: I095f4b1c34f1541789112ccaed8ea5bc4fa99792 Signed-off-by: Balakrishna Godavarthi --- pwr/btpower.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/pwr/btpower.c b/pwr/btpower.c index 54dd73a16a..8d20afc31a 100644 --- a/pwr/btpower.c +++ b/pwr/btpower.c @@ -1742,8 +1742,10 @@ static void set_pwr_srcs_status(struct vreg_data *handle, { int power_src_state; - if (!handle) + if (!handle) { pr_err("%s: invalid handler received\n", __func__); + return; + } if (handle->is_enabled) power_src_state = (int)regulator_get_voltage(handle->reg); From 6d20efacc6b08ab5a91ad7cddd5252c5f25d935e Mon Sep 17 00:00:00 2001 From: Balakrishna Godavarthi Date: Tue, 30 Apr 2024 16:25:50 +0530 Subject: [PATCH 097/154] btfmcodec: free allocated parameters This change will free allocated parameters once they are used. CRs-Fixed: 3791905 Change-Id: I5f4ff58f75d61dc378f5c1962ee7292e1ed538a6 --- btfmcodec/btfm_codec_interface.c | 1 + soundwire/btfm_swr_hw_interface.c | 1 + 2 files changed, 2 insertions(+) diff --git a/btfmcodec/btfm_codec_interface.c b/btfmcodec/btfm_codec_interface.c index fb99d4308c..cd5757f72d 100644 --- a/btfmcodec/btfm_codec_interface.c +++ b/btfmcodec/btfm_codec_interface.c @@ -102,6 +102,7 @@ static int btfmcodec_codec_probe(struct snd_soc_component *codec) mixer_ctrl[i].put = btfmcodec_put_mixer_control; } snd_soc_add_component_controls(codec, mixer_ctrl, num_mixer_ctrl); + kfree(mixer_ctrl); BTFMCODEC_INFO("CODEC address while registering mixer ctrl:%p", codec); } } diff --git a/soundwire/btfm_swr_hw_interface.c b/soundwire/btfm_swr_hw_interface.c index 82731a2de0..1bb6fd289b 100644 --- a/soundwire/btfm_swr_hw_interface.c +++ b/soundwire/btfm_swr_hw_interface.c @@ -419,6 +419,7 @@ int btfm_swr_register_hw_ep(struct btfmswr *btfm_swr) hwep_info->mixer_ctrl = status_controls; /* Register to hardware endpoint */ ret = btfmcodec_register_hw_ep(hwep_info); + kfree(hwep_info); if (ret) { BTFMSWR_ERR("failed to register with btfmcodec driver hw interface (%d)", ret); goto end; From be1daa574187a77a23cc0b92ed31c1866439aa00 Mon Sep 17 00:00:00 2001 From: Balakrishna Godavarthi Date: Tue, 7 May 2024 12:12:45 +0530 Subject: [PATCH 098/154] btfm_swr: Enable 192khz for APTX AD QLEA codec This changes enables 192khz sampling rate for APTX AD QLEA codec id. CRs-Fixed: 3797251 Change-Id: I9f6ea0bded5a4ba9f32d3fbfed30a39f3fe568a3 Signed-off-by: Balakrishna Godavarthi --- soundwire/btfm_swr_hw_interface.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/soundwire/btfm_swr_hw_interface.c b/soundwire/btfm_swr_hw_interface.c index 1bb6fd289b..5f9b461c48 100644 --- a/soundwire/btfm_swr_hw_interface.c +++ b/soundwire/btfm_swr_hw_interface.c @@ -1,6 +1,6 @@ // SPDX-License-Identifier: GPL-2.0-only /* - * Copyright (c) 2023 Qualcomm Innovation Center, Inc. All rights reserved. + * Copyright (c) 2023-2024 Qualcomm Innovation Center, Inc. All rights reserved. */ #include @@ -182,11 +182,12 @@ void btfm_get_sampling_rate(uint32_t *sampling_rate) if (usecase_codec == LC3_VOICE || usecase_codec == APTX_AD_SPEECH || - usecase_codec == LC3 || usecase_codec == APTX_AD_QLEA || - usecase_codec == APTX_AD_R4) { + usecase_codec == LC3 || usecase_codec == APTX_AD_R4) { *sampling_rate = 96000; } + if (usecase_codec == APTX_AD_QLEA) + *sampling_rate = 192000; BTFMSWR_INFO("current usecase codec type %s and sampling rate:%u khz", codec_text[usecase_codec], *sampling_rate); } From 922006fd5c0bdf0421e40d283293d3fccada2453 Mon Sep 17 00:00:00 2001 From: Girish BN Date: Mon, 29 Apr 2024 14:53:47 +0530 Subject: [PATCH 099/154] BT-Kernel : Kmemleak in BT power driver - Not freeing the skb buffer after used Change-Id: I83c4933b3af15c4c5762396bb1790be8f8eb1e59 Signed-off-by: Girish BN --- pwr/btpower.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/pwr/btpower.c b/pwr/btpower.c index 8d20afc31a..88f8463c67 100644 --- a/pwr/btpower.c +++ b/pwr/btpower.c @@ -2262,8 +2262,9 @@ static void bt_power_vote(struct work_struct *work) ConvertRetentionModeToString(btpower_get_retenion_mode_state()), ConvertGrantToString(btpower_get_grant_state()), ConvertGrantToString(btpower_get_grant_pending_state())); - + pwr_data->wait_status[request] = ret; + kfree_skb(skb); wake_up_interruptible(&pwr_data->rsp_wait_q[request]); } } From 3a3d3d858fa5dc3b8b87f178a840335d1d4a16e9 Mon Sep 17 00:00:00 2001 From: Girish BN Date: Mon, 29 Apr 2024 16:10:54 +0530 Subject: [PATCH 100/154] BT-Kernel : use-after-free in BT power driver - after freed bt_power_release accessing the variables. Change-Id: I3007c9717d7504e2fc1598d0c848421735372159 Signed-off-by: Girish BN --- include/btpower.h | 1 + pwr/btpower.c | 11 +++++++++-- 2 files changed, 10 insertions(+), 2 deletions(-) diff --git a/include/btpower.h b/include/btpower.h index ac67515f72..4879e96481 100644 --- a/include/btpower.h +++ b/include/btpower.h @@ -676,6 +676,7 @@ struct platform_pwr_data { struct work_struct wq_pwr_voting; struct sk_buff_head rxq; struct mutex pwr_mtx; + struct mutex pwr_release; bool is_fmd_mode_enable; struct nvmem_cell *nvmem_cell; u32 fmd_clk_gpio_id; diff --git a/pwr/btpower.c b/pwr/btpower.c index 8d20afc31a..5a016017f7 100644 --- a/pwr/btpower.c +++ b/pwr/btpower.c @@ -1656,6 +1656,7 @@ static int bt_power_probe(struct platform_device *pdev) skb_queue_head_init(&pwr_data->rxq); mutex_init(&pwr_data->pwr_mtx); mutex_init(&pwr_data->btpower_state.state_machine_lock); + mutex_init(&pwr_data->pwr_release); pwr_data->btpower_state.power_state = IDLE; pwr_data->btpower_state.retention_mode = RETENTION_IDLE; pwr_data->btpower_state.grant_state = NO_GRANT_FOR_ANY_SS; @@ -1701,20 +1702,23 @@ static int bt_power_probe(struct platform_device *pdev) return 0; free_pdata: + mutex_lock(&pwr_data->pwr_release); kfree(pwr_data); + mutex_unlock(&pwr_data->pwr_release); return ret; } static int bt_power_remove(struct platform_device *pdev) { + mutex_lock(&pwr_data->pwr_release); dev_dbg(&pdev->dev, "%s\n", __func__); - probe_finished = false; btpower_rfkill_remove(pdev); bt_power_vreg_put(); if (pwr_data->is_ganges_dt) destroy_workqueue(pwr_data->workq); kfree(pwr_data); + mutex_unlock(&pwr_data->pwr_release); return 0; } @@ -2614,6 +2618,9 @@ static long bt_ioctl(struct file *file, unsigned int cmd, unsigned long arg) static int bt_power_release(struct inode *inode, struct file *file) { + + mutex_lock(&pwr_data->pwr_release); + if (!pwr_data || !probe_finished) { pr_err("%s: BTPower Probing Pending.Try Again\n", __func__); return -EAGAIN; @@ -2662,6 +2669,7 @@ static int bt_power_release(struct inode *inode, struct file *file) } */ } } + mutex_unlock(&pwr_data->pwr_release); return 0; } @@ -2794,7 +2802,6 @@ static int btpower_aop_set_vreg_param(struct platform_pwr_data *pdata, enum btpower_vreg_param param, enum btpower_tcs_seq seq, int val) { - char mbox_msg[BTPOWER_MBOX_MSG_MAX_LEN]; static const char * const vreg_param_str[] = {"v", "m", "e"}; static const char *const tcs_seq_str[] = {"upval", "dwnval", "enable"}; From 068eca4016b2bbed06c41b5ac1f540d40e3142ee Mon Sep 17 00:00:00 2001 From: Balakrishna Godavarthi Date: Thu, 9 May 2024 22:36:27 +0530 Subject: [PATCH 101/154] btpower: don't vote for clock during BT ON This change holds below fixes 1. Don't vote for clocks during BT ON 2. read wakeup capable gpio from dtsi. 3. Enable wakeup capable if gpio is defined. Change-Id: Id18ecdb12dc4fb26efe0fe3115bc4834067874ef Signed-off-by: Balakrishna Godavarthi --- pwr/btpower.c | 48 ++++++++++-------------------------------------- 1 file changed, 10 insertions(+), 38 deletions(-) diff --git a/pwr/btpower.c b/pwr/btpower.c index 8d20afc31a..1138b3f04c 100644 --- a/pwr/btpower.c +++ b/pwr/btpower.c @@ -735,12 +735,13 @@ static int bt_configure_gpios(int on) if (bt_sw_ctrl_gpio >= 0) { power_src.platform_state[BT_SW_CTRL_GPIO] = gpio_get_value(bt_sw_ctrl_gpio); - rc = msm_gpio_mpm_wake_set(pwr_data->sw_cntrl_gpio, 1); - if (rc < 0) { - pr_err("Failed to set msm_gpio_mpm_wake_set for sw_cntrl gpio, ret: %d\n", + if (pwr_data->sw_cntrl_gpio >= 0) { + rc = msm_gpio_mpm_wake_set(pwr_data->sw_cntrl_gpio, 1); + if (rc < 0) { + pr_err("Failed to set msm_gpio_mpm_wake_set for sw_cntrl gpio, ret: %d\n", rc); - return rc; - } else { + return rc; + } pr_info("Set msm_gpio_mpm_wake_set for sw_cntrl gpio successful\n"); } pr_info("BTON:Turn Bt OFF bt-sw-ctrl-gpio(%d) value(%d)\n", @@ -908,17 +909,6 @@ static int bt_regulators_pwr(int pwr_state) } } - /* Parse dt_info and check if a target requires clock voting. - * Enable BT clock when BT is on and disable it when BT is off - */ - if (pwr_data->bt_chip_clk) { - rc = bt_clk_enable(pwr_data->bt_chip_clk); - if (rc < 0) { - pr_err("%s: bt_power gpio config failed\n", - __func__); - goto clk_fail; - } - } if (pwr_data->bt_gpio_sys_rst > 0) { power_src.bt_state[BT_RESET_GPIO] = DEFAULT_INVALID_VALUE; power_src.bt_state[BT_SW_CTRL_GPIO] = DEFAULT_INVALID_VALUE; @@ -946,7 +936,6 @@ gpio_fail: gpio_free(pwr_data->bt_gpio_debug); if (pwr_data->bt_chip_clk) bt_clk_disable(pwr_data->bt_chip_clk); -clk_fail: regulator_fail: for (i = 0; i < bt_num_vregs; i++) { bt_vregs = &pwr_data->bt_vregs[i]; @@ -1346,8 +1335,6 @@ static int get_gpio_dt_pinfo(struct platform_device *pdev) struct device_node *child; struct pinctrl *pinctrl1; struct pinctrl_state *sw_ctrl; - u32 gpio_id, i; - int gpio_id_n; child = pdev->dev.of_node; @@ -1377,25 +1364,10 @@ static int get_gpio_dt_pinfo(struct platform_device *pdev) if (pwr_data->bt_gpio_fmd_clk_ctrl < 0) pr_warn("bt-fmd-clk-gpio not provided in devicetree\n"); - /* Find out and configure all those GPIOs which need to be setup - * for interrupt wakeup capable - * - */ - gpio_id_n = of_property_count_u32_elems(child, "mpm_wake_set_gpios"); - if (gpio_id_n > 0) { - pr_err("Num of GPIOs to be setup for interrupt wakeup capable: %d\n", - gpio_id_n); - for (i = 0; i < gpio_id_n; i++) { - ret = of_property_read_u32_index(child, - "mpm_wake_set_gpios", - i, &gpio_id); - if (ret) { - pr_err("Failed to read gpio_id at index: %d\n", i); - continue; - } - } - } else { - pr_err("No GPIOs to be setup for interrupt wakeup capable\n"); + ret = of_property_read_u32(child, "mpm_wake_set_gpios", &pwr_data->sw_cntrl_gpio); + + if (ret) { + pr_warn("sw_cntrl-gpio not provided in devicetree\n"); } if (pinctrl1) { From 03a45d3757ca06875935e5fec11c1a837b40051f Mon Sep 17 00:00:00 2001 From: Girish BN Date: Wed, 29 May 2024 11:19:16 +0530 Subject: [PATCH 102/154] BT_Kernel: fix page fault error due to mutex - Fixing page fault error due to accessing the mutex after free. Change-Id: Ib8433a923424d7bc4a54b01769d6c2f206321d04 Signed-off-by: Girish BN --- include/btpower.h | 1 - pwr/btpower.c | 15 ++++++++------- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/include/btpower.h b/include/btpower.h index 4879e96481..ac67515f72 100644 --- a/include/btpower.h +++ b/include/btpower.h @@ -676,7 +676,6 @@ struct platform_pwr_data { struct work_struct wq_pwr_voting; struct sk_buff_head rxq; struct mutex pwr_mtx; - struct mutex pwr_release; bool is_fmd_mode_enable; struct nvmem_cell *nvmem_cell; u32 fmd_clk_gpio_id; diff --git a/pwr/btpower.c b/pwr/btpower.c index 49467bfb6e..fc4339421a 100644 --- a/pwr/btpower.c +++ b/pwr/btpower.c @@ -330,6 +330,7 @@ static struct class *bt_class; static int bt_major; static int soc_id; static bool probe_finished; +struct mutex pwr_release; static void bt_power_vote(struct work_struct *work); @@ -1628,7 +1629,7 @@ static int bt_power_probe(struct platform_device *pdev) skb_queue_head_init(&pwr_data->rxq); mutex_init(&pwr_data->pwr_mtx); mutex_init(&pwr_data->btpower_state.state_machine_lock); - mutex_init(&pwr_data->pwr_release); + mutex_init(&pwr_release); pwr_data->btpower_state.power_state = IDLE; pwr_data->btpower_state.retention_mode = RETENTION_IDLE; pwr_data->btpower_state.grant_state = NO_GRANT_FOR_ANY_SS; @@ -1674,15 +1675,15 @@ static int bt_power_probe(struct platform_device *pdev) return 0; free_pdata: - mutex_lock(&pwr_data->pwr_release); + mutex_lock(&pwr_release); kfree(pwr_data); - mutex_unlock(&pwr_data->pwr_release); + mutex_unlock(&pwr_release); return ret; } static int bt_power_remove(struct platform_device *pdev) { - mutex_lock(&pwr_data->pwr_release); + mutex_lock(&pwr_release); dev_dbg(&pdev->dev, "%s\n", __func__); probe_finished = false; btpower_rfkill_remove(pdev); @@ -1690,7 +1691,7 @@ static int bt_power_remove(struct platform_device *pdev) if (pwr_data->is_ganges_dt) destroy_workqueue(pwr_data->workq); kfree(pwr_data); - mutex_unlock(&pwr_data->pwr_release); + mutex_unlock(&pwr_release); return 0; } @@ -2592,7 +2593,7 @@ static long bt_ioctl(struct file *file, unsigned int cmd, unsigned long arg) static int bt_power_release(struct inode *inode, struct file *file) { - mutex_lock(&pwr_data->pwr_release); + mutex_lock(&pwr_release); if (!pwr_data || !probe_finished) { pr_err("%s: BTPower Probing Pending.Try Again\n", __func__); @@ -2642,7 +2643,7 @@ static int bt_power_release(struct inode *inode, struct file *file) } */ } } - mutex_unlock(&pwr_data->pwr_release); + mutex_unlock(&pwr_release); return 0; } From 3212854f449031847a39d8afe737875acb1face1 Mon Sep 17 00:00:00 2001 From: Balakrishna Godavarthi Date: Fri, 7 Jun 2024 12:18:52 +0530 Subject: [PATCH 103/154] btpower: Initialize mutex as part of driver init This change will Initialize mutex as part of driver init. Change-Id: I43270cdb06e462ad2e372dfa85d19df1d611bcaa Signed-off-by: Balakrishna Godavarthi --- pwr/btpower.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pwr/btpower.c b/pwr/btpower.c index fc4339421a..edf610eb7e 100644 --- a/pwr/btpower.c +++ b/pwr/btpower.c @@ -1629,7 +1629,6 @@ static int bt_power_probe(struct platform_device *pdev) skb_queue_head_init(&pwr_data->rxq); mutex_init(&pwr_data->pwr_mtx); mutex_init(&pwr_data->btpower_state.state_machine_lock); - mutex_init(&pwr_release); pwr_data->btpower_state.power_state = IDLE; pwr_data->btpower_state.retention_mode = RETENTION_IDLE; pwr_data->btpower_state.grant_state = NO_GRANT_FOR_ANY_SS; @@ -2688,12 +2687,13 @@ static int __init btpower_init(void) goto class_err; } - if (device_create(bt_class, NULL, MKDEV(bt_major, 0), NULL, "btpower") == NULL) { pr_err("%s: failed to allocate char dev\n", __func__); goto device_err; } + + mutex_init(&pwr_release); return 0; device_err: From f810a3a3e21504f606b3a101e054c856feb702e2 Mon Sep 17 00:00:00 2001 From: Adesh Mohanrao Pathare Date: Fri, 7 Jun 2024 12:21:52 +0530 Subject: [PATCH 104/154] bt: Enable Bluetooth on parrot66 Added changes for bazel and build to enable bluetooth on parrot66 target Change-Id: Idd991f21cea9c5dbd41d865e8372adedbc3bd4cb Signed-off-by: Adesh Mohanrao Pathare --- Android.mk | 4 +++- BUILD.bazel | 2 ++ target.bzl | 16 ++++++++++++++++ 3 files changed, 21 insertions(+), 1 deletion(-) diff --git a/Android.mk b/Android.mk index 4b29a6a94c..b4606e0eeb 100644 --- a/Android.mk +++ b/Android.mk @@ -12,7 +12,7 @@ ifeq ($(BT_DLKM_ENABLE), true) LOCAL_PATH := $(call my-dir) # Build/Package only in case of supported target -ifeq ($(call is-board-platform-in-list, taro kalama pineapple blair sun), true) +ifeq ($(call is-board-platform-in-list, taro kalama pineapple blair sun parrot), true) BT_SELECT := CONFIG_MSM_BT_POWER=m BT_SELECT += CONFIG_I2C_RTC6226_QCA=m @@ -68,7 +68,9 @@ endif endif +ifeq ($(TARGET_BOARD_PLATFORM), sun) KBUILD_REQUIRED_KOS += swr_dlkm.ko +endif # Module.symvers needs to be generated as a intermediate module so that # other modules which depend on BT platform modules can set local diff --git a/BUILD.bazel b/BUILD.bazel index 4e7e750f4c..e3726b230b 100644 --- a/BUILD.bazel +++ b/BUILD.bazel @@ -10,6 +10,8 @@ ddk_headers( load(":target.bzl", "define_pineapple") load(":target.bzl", "define_sun") +load(":target.bzl", "define_parrot") define_pineapple() define_sun() +define_parrot() diff --git a/target.bzl b/target.bzl index 13f40e72e7..9b558ed5ac 100644 --- a/target.bzl +++ b/target.bzl @@ -35,3 +35,19 @@ def define_sun(): "CONFIG_BTFM_SWR", ] ) + +def define_parrot(): + define_bt_modules( + target = "parrot66", + modules = [ + "btpower", + "bt_fm_slim", + "radio-i2c-rtc6226-qca", + ], + config_options = [ + "CONFIG_MSM_BT_POWER", + "CONFIG_BTFM_SLIM", + "CONFIG_I2C_RTC6226_QCA", + #"CONFIG_BT_HW_SECURE_DISABLE", + ] + ) From ce30c245549ad3a8a2f71d8ce9002483c6f58879 Mon Sep 17 00:00:00 2001 From: Balakrishna Godavarthi Date: Fri, 7 Jun 2024 12:18:52 +0530 Subject: [PATCH 105/154] btpower: Initialize mutex as part of driver init This change will Initialize mutex as part of driver init. Change-Id: I43270cdb06e462ad2e372dfa85d19df1d611bcaa Signed-off-by: Balakrishna Godavarthi (cherry picked from commit 3212854f449031847a39d8afe737875acb1face1) --- pwr/btpower.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pwr/btpower.c b/pwr/btpower.c index fc4339421a..edf610eb7e 100644 --- a/pwr/btpower.c +++ b/pwr/btpower.c @@ -1629,7 +1629,6 @@ static int bt_power_probe(struct platform_device *pdev) skb_queue_head_init(&pwr_data->rxq); mutex_init(&pwr_data->pwr_mtx); mutex_init(&pwr_data->btpower_state.state_machine_lock); - mutex_init(&pwr_release); pwr_data->btpower_state.power_state = IDLE; pwr_data->btpower_state.retention_mode = RETENTION_IDLE; pwr_data->btpower_state.grant_state = NO_GRANT_FOR_ANY_SS; @@ -2688,12 +2687,13 @@ static int __init btpower_init(void) goto class_err; } - if (device_create(bt_class, NULL, MKDEV(bt_major, 0), NULL, "btpower") == NULL) { pr_err("%s: failed to allocate char dev\n", __func__); goto device_err; } + + mutex_init(&pwr_release); return 0; device_err: From f394abcfa640283b1bd7ee95ec29674a60e6e37a Mon Sep 17 00:00:00 2001 From: Girish BN Date: Mon, 6 May 2024 12:23:14 +0530 Subject: [PATCH 106/154] btpower: Import cnss utils api's for fmd operation - Implimented state m/c to perform FMD operations - Informing FMD status to BT_PWR->CNSS->PCIE - Handling RF CLK ref line Change-Id: Ic1f142d6213308b01d11ff694692582704173525 Signed-off-by: Girish BN --- bt_modules.bzl | 4 +++ include/btpower.h | 13 +++++++-- pwr/btpower.c | 72 ++++++++++++++++++++++++++++++++++++++--------- target.bzl | 4 +-- 4 files changed, 75 insertions(+), 18 deletions(-) diff --git a/bt_modules.bzl b/bt_modules.bzl index 103faa4e67..9947577002 100644 --- a/bt_modules.bzl +++ b/bt_modules.bzl @@ -61,6 +61,10 @@ register_bt_modules( "//vendor/qcom/opensource/securemsm-kernel:%b_smcinvoke_dlkm", ] }, + deps = [ + "//vendor/qcom/opensource/wlan/platform:all-wlan-platform-headers", + "//vendor/qcom/opensource/wlan/platform:%b_cnss_utils", + ], ) register_bt_modules( diff --git a/include/btpower.h b/include/btpower.h index ac67515f72..aab65e8c08 100644 --- a/include/btpower.h +++ b/include/btpower.h @@ -30,6 +30,13 @@ enum SubSystem { UWB, }; +enum FmdOperation { + ENABLE_SDAM_BIT_FMD = 0, + DISABLE_SDAM_BIT_FMD, + UPDATE_SOC_VERSION_1_0_FOR_FMD, + UPDATE_SOC_VERSION_2_0_FOR_FMD +}; + enum power_states { IDLE = 0, BT_ON, @@ -697,10 +704,10 @@ int bt_aop_pdc_reconfig(struct platform_pwr_data *pdata); #define BT_CMD_KERNEL_PANIC 0xbfc1 #define UWB_CMD_KERNEL_PANIC 0xbfc2 #define UWB_CMD_PWR_CTRL 0xbfe1 -#define BT_CMD_REGISTRATION 0xbfe2 +#define BT_CMD_REGISTRATION 0xbfe2 #define UWB_CMD_REGISTRATION 0xbfe3 -#define BT_CMD_ACCESS_CTRL 0xbfe4 -#define UWB_CMD_ACCESS_CTRL 0xbfe5 +#define BT_CMD_ACCESS_CTRL 0xbfe4 +#define UWB_CMD_ACCESS_CTRL 0xbfe5 #define SET_FMD_MODE_CTRL 0xbfb2 #ifdef CONFIG_MSM_BT_OOBS diff --git a/pwr/btpower.c b/pwr/btpower.c index 3bc4e5c38d..b6f2b7f706 100644 --- a/pwr/btpower.c +++ b/pwr/btpower.c @@ -39,6 +39,7 @@ #include #include "btpower.h" +#include "cnss_utils.h" #if (defined CONFIG_BT_SLIM) #include "btfm_slim.h" #endif @@ -121,6 +122,7 @@ enum power_src_pos { BT_VDD_RFA_0p8, BT_VDD_RFACMN, BT_VDD_ANT_LDO, + // these indexes GPIOs/regs value are fetched during crash. BT_RESET_GPIO_CURRENT, BT_SW_CTRL_GPIO_CURRENT, @@ -139,6 +141,7 @@ enum power_src_pos { BT_VDD_IPA_2p2, BT_VDD_IPA_2p2_CURRENT, BT_VDD_ANT_LDO_CURRENT, + /* The below bucks are voted for HW WAR on some platform which supports * WNC39xx. */ @@ -2370,10 +2373,9 @@ const char *GetSourceSubsystemString(uint32_t source_subsystem) } } -void set_fmd_sdam_bit(void) +void set_fmd_sdam_bit(unsigned char sdam_bit) { int rc = 0; - unsigned char sdam_bit = 1; rc = nvmem_cell_write(pwr_data->nvmem_cell, &sdam_bit, sizeof(sdam_bit)); if (rc < 0) { @@ -2396,6 +2398,60 @@ void set_fmd_sdam_bit(void) } } +int set_fmd_mode(enum FmdOperation operation) +{ + int ret = 0; + + switch (operation) { + case ENABLE_SDAM_BIT_FMD: { + pr_warn("%s: SET_FMD_MODE_CTRL :: ENABLE_SDAM_BIT_FMD\n", + __func__); + set_fmd_sdam_bit((unsigned char)POWER_ENABLE); + break; + } + case DISABLE_SDAM_BIT_FMD: { + pr_warn("%s: SET_FMD_MODE_CTRL :: DISABLE_SDAM_BIT_FMD\n", + __func__); + set_fmd_sdam_bit((unsigned char)POWER_DISABLE); + break; + } + case UPDATE_SOC_VERSION_1_0_FOR_FMD: { + pr_warn("%s: SET_FMD_MODE_CTRL :: UPDATE_SOC_VERSION_1_0_FOR_FMD\n", + __func__); + pwr_data->is_fmd_mode_enable = true; + if (pwr_data->bt_chip_clk) { + ret = bt_clk_enable(pwr_data->bt_chip_clk); + if (ret < 0) { + pr_err("%s: failed to bt_chip_clk\n", __func__); + return -EINVAL; + } + } + break; + } + case UPDATE_SOC_VERSION_2_0_FOR_FMD: { + pr_warn("%s: SET_FMD_MODE_CTRL :: UPDATE_SOC_VERSION_2_0_FOR_FMD\n", + __func__); + pwr_data->is_fmd_mode_enable = true; + cnss_utils_fmd_status(true); + if (pwr_data->bt_chip_clk) { + ret = bt_clk_enable(pwr_data->bt_chip_clk); + if (ret < 0) { + pr_err("%s: failed to bt_chip_clk\n", __func__); + return -EINVAL; + } + } + break; + } + default: { + pr_warn("%s: invalid fmd operation = %d received\n", + __func__, operation); + ret = -EINVAL; + break; + } + } + return ret; +} + static long bt_ioctl(struct file *file, unsigned int cmd, unsigned long arg) { int ret = 0; @@ -2466,17 +2522,7 @@ static long bt_ioctl(struct file *file, unsigned int cmd, unsigned long arg) break; } case SET_FMD_MODE_CTRL: { - pr_warn("%s: SET_FMD_MODE_CTRL\n", __func__); - pwr_data->is_fmd_mode_enable = true; - ret = btpower_handle_client_request(BT_CMD_PWR_CTRL, (int)POWER_ENABLE); - if (pwr_data->bt_chip_clk) { - ret = bt_clk_enable(pwr_data->bt_chip_clk); - if (ret < 0) { - pr_err("%s: bt_power gpio config failed\n", __func__); - return -EINVAL; - } - } - set_fmd_sdam_bit(); + ret = set_fmd_mode((enum FmdOperation)arg); break; } case BT_CMD_REGISTRATION: diff --git a/target.bzl b/target.bzl index 13f40e72e7..c3d42ef778 100644 --- a/target.bzl +++ b/target.bzl @@ -30,8 +30,8 @@ def define_sun(): "CONFIG_MSM_BT_POWER", "CONFIG_I2C_RTC6226_QCA", "CONFIG_SLIM_BTFM_CODEC", - "CONFIG_BTFM_CODEC", + "CONFIG_BTFM_CODEC", # "CONFIG_BT_HW_SECURE_DISABLE", - "CONFIG_BTFM_SWR", + "CONFIG_BTFM_SWR", ] ) From ced72ee8eb2953fd5e17cfa6fd69818f84a45c53 Mon Sep 17 00:00:00 2001 From: Girish BN Date: Wed, 5 Jun 2024 14:06:29 +0530 Subject: [PATCH 107/154] btpower: Changes to operate wlan regulator for fmd - Parse wlan buck value from DTSI on driver probe. - Dont vote-on wlan buck during bt power on. - Vote on wlan buck for FMD mode. - Ignore vote-off wlan buck during bt power Off. Change-Id: I4ecce7793a1329f42431dd1c05a1c15de44c6a99 Signed-off-by: Girish BN --- include/btpower.h | 5 +-- pwr/btpower.c | 82 +++++++++++++++++++++++++++++++++++++++++------ 2 files changed, 75 insertions(+), 12 deletions(-) diff --git a/include/btpower.h b/include/btpower.h index aab65e8c08..03d1dcf45d 100644 --- a/include/btpower.h +++ b/include/btpower.h @@ -647,10 +647,11 @@ struct platform_pwr_data { struct device *slim_dev; struct vreg_data *bt_vregs; struct vreg_data *uwb_vregs; + struct vreg_data *wlan_vregs; struct vreg_data *platform_vregs; struct bt_power_clk_data *bt_chip_clk; /* bluetooth reference clock */ - int (*power_setup)(int core, int id); /* Bluetooth power setup function */ - char compatible[32]; /*Bluetooth SoC name */ + int (*power_setup)(int core, int id); /* Bluetooth power setup function */ + char compatible[32]; /*Bluetooth SoC name */ int bt_num_vregs; int uwb_num_vregs; int platform_num_vregs; diff --git a/pwr/btpower.c b/pwr/btpower.c index 0a4401e630..c0628f0f93 100644 --- a/pwr/btpower.c +++ b/pwr/btpower.c @@ -122,6 +122,7 @@ enum power_src_pos { BT_VDD_RFA_0p8, BT_VDD_RFACMN, BT_VDD_ANT_LDO, + BT_VDD_WLAN_AON_LDO, // these indexes GPIOs/regs value are fetched during crash. BT_RESET_GPIO_CURRENT, @@ -141,6 +142,7 @@ enum power_src_pos { BT_VDD_IPA_2p2, BT_VDD_IPA_2p2_CURRENT, BT_VDD_ANT_LDO_CURRENT, + BT_VDD_WLAN_AON_LDO_CURRENT, /* The below bucks are voted for HW WAR on some platform which supports * WNC39xx. @@ -234,6 +236,8 @@ static struct vreg_data platform_vregs_info_peach[] = { /* RFA_1P25 */ {NULL, "qcom,bt-vdd-rfa1p25", 1300000, 2100000, 0, false, true, {BT_VDD_RFA1_LDO, BT_VDD_RFA1_LDO_CURRENT}}, + {NULL, "qcom,bt-vdd-wlan-aon", 950000, 950000, 0, false, false, + {BT_VDD_WLAN_AON_LDO, BT_VDD_WLAN_AON_LDO_CURRENT}}, }; // Regulator structure for WCN399x BT SoC series @@ -1017,6 +1021,46 @@ regulator_failed: return rc; } +static bool is_wlan_mx_buck(struct vreg_data *reg) +{ + + if (strcmp(reg->name, "qcom,bt-vdd-wlan-aon")) + return false; + else + return true; +} + +static int vote_wlan_reg_for_fmd(void) +{ + int log_indx; + struct vreg_data *vregs = pwr_data->wlan_vregs; + + if ((vregs == NULL) || (!is_wlan_mx_buck(vregs))) { + pr_err("%s: Regulator qcom,bt-vdd-wlan-aon is not avilable\n", __func__); + return -1; + } + + if (vregs->reg == NULL) + return -1; + + log_indx = vregs->indx.init; + power_src.platform_state[log_indx] = DEFAULT_INVALID_VALUE; + + if (vreg_enable(vregs) < 0) { + pr_err("%s: Platform regulators config failed\n", __func__); + return -1; + } + + if (vregs->is_enabled) { + power_src.platform_state[log_indx] = regulator_get_voltage(vregs->reg); + pr_err("%s: Regulator %s voted-on Successfully\n", __func__, vregs->name); + } else { + pr_err("%s: Regulator qcom,bt-vdd-wlan-aon is not enabled\n", __func__); + return -1; + } + return 0; +} + static int platform_regulators_pwr(int pwr_state) { int i, log_indx, platform_num_vregs, rc = 0; @@ -1068,10 +1112,12 @@ static int platform_regulators_pwr(int pwr_state) } } gpio_failed: - if (pwr_data->bt_gpio_sys_rst > 0) - gpio_free(pwr_data->bt_gpio_sys_rst); - if (pwr_data->bt_gpio_debug > 0) - gpio_free(pwr_data->bt_gpio_debug); + if (!get_fmd_mode()) { + if (pwr_data->bt_gpio_sys_rst > 0) + gpio_free(pwr_data->bt_gpio_sys_rst); + if (pwr_data->bt_gpio_debug > 0) + gpio_free(pwr_data->bt_gpio_debug); + } regulator_failed: for (i = 0; i < platform_num_vregs; i++) { platform_vregs = &pwr_data->platform_vregs[i]; @@ -1437,12 +1483,6 @@ static int get_power_dt_pinfo(struct platform_device *pdev) pwr_data->platform_vregs = data->platform_vregs; pwr_data->uwb_num_vregs = data->uwb_num_vregs; pwr_data->platform_num_vregs = data->platform_num_vregs; - - pr_info("%s: bt_num_vregs =%d uwb_num_vregs =%d platform_num_vregs=%d\n", - __func__, pwr_data->bt_num_vregs, pwr_data->uwb_num_vregs, - pwr_data->platform_num_vregs); - } else { - pr_info("%s: bt_num_vregs =%d\n", __func__, pwr_data->bt_num_vregs); } for (i = 0; i < pwr_data->bt_num_vregs; i++) { @@ -1455,6 +1495,12 @@ static int get_power_dt_pinfo(struct platform_device *pdev) if (pwr_data->is_ganges_dt) { for (i = 0; i < pwr_data->platform_num_vregs; i++) { + if (is_wlan_mx_buck(&pwr_data->platform_vregs[i])) { + pwr_data->wlan_vregs = &pwr_data->platform_vregs[i]; + pwr_data->platform_num_vregs--; + pr_err("%s: Found wlan regulator for FMD Operations '%s'\n", + __func__, (pwr_data->wlan_vregs)->name); + } rc = dt_parse_vreg_info(&(pdev->dev), NULL, &pwr_data->platform_vregs[i]); /* No point to go further if failed to get regulator handler */ @@ -1469,6 +1515,16 @@ static int get_power_dt_pinfo(struct platform_device *pdev) if (rc) return rc; } + + pr_info("%s: platform_name = %s: bt_num_vregs =%d uwb_num_vregs =%d platform_num_vregs=%d\n", + __func__, pwr_data->compatible, pwr_data->bt_num_vregs, + pwr_data->uwb_num_vregs, pwr_data->platform_num_vregs); + + } else { + + pr_info("%s: platform_name = %s: bt_num_vregs =%d\n", __func__, + pwr_data->compatible, pwr_data->bt_num_vregs); + } return rc; } @@ -1592,7 +1648,9 @@ static int bt_power_probe(struct platform_device *pdev) rc = PTR_ERR(pwr_data->nvmem_cell); pr_err("%s:Failed to get FMD nvmem-cells %d\n", __func__, rc); } + pr_info("%s: --- Got FMD nvmem-cells %d\n", __func__, rc); + if (rc >= 0) { u8 *buf; size_t len; @@ -2437,6 +2495,10 @@ int set_fmd_mode(enum FmdOperation operation) __func__); pwr_data->is_fmd_mode_enable = true; cnss_utils_fmd_status(true); + if (vote_wlan_reg_for_fmd() < 0) { + pr_err("%s: failed to vote_wlan_reg_for_fmd\n", __func__); + return -EINVAL; + } if (pwr_data->bt_chip_clk) { ret = bt_clk_enable(pwr_data->bt_chip_clk); if (ret < 0) { From e5b2a9f2816bfea8dd121d2a08f4ec3bd59adfe9 Mon Sep 17 00:00:00 2001 From: Xhoendi Collaku Date: Tue, 18 Jun 2024 21:47:22 -0700 Subject: [PATCH 108/154] Revert "btpower: Initialize mutex as part of driver init" This reverts commit ce30c245549ad3a8a2f71d8ce9002483c6f58879. Reason for revert: Release revert Change-Id: I2e432f3da07bfac74e37f6723cb997513ff6eb01 --- pwr/btpower.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pwr/btpower.c b/pwr/btpower.c index edf610eb7e..fc4339421a 100644 --- a/pwr/btpower.c +++ b/pwr/btpower.c @@ -1629,6 +1629,7 @@ static int bt_power_probe(struct platform_device *pdev) skb_queue_head_init(&pwr_data->rxq); mutex_init(&pwr_data->pwr_mtx); mutex_init(&pwr_data->btpower_state.state_machine_lock); + mutex_init(&pwr_release); pwr_data->btpower_state.power_state = IDLE; pwr_data->btpower_state.retention_mode = RETENTION_IDLE; pwr_data->btpower_state.grant_state = NO_GRANT_FOR_ANY_SS; @@ -2687,13 +2688,12 @@ static int __init btpower_init(void) goto class_err; } + if (device_create(bt_class, NULL, MKDEV(bt_major, 0), NULL, "btpower") == NULL) { pr_err("%s: failed to allocate char dev\n", __func__); goto device_err; } - - mutex_init(&pwr_release); return 0; device_err: From 63a7d6d088424b30c6134bc4d348b36e31c79d31 Mon Sep 17 00:00:00 2001 From: Balakrishna Godavarthi Date: Mon, 22 Jan 2024 15:48:49 +0530 Subject: [PATCH 109/154] btfmcodec: Update new codec types Add new codec types for slimbus and soundwire drivers. CRs-Fixed: 3844311 Change-Id: I587c3bcdd1c583b7fece9493bfa5de5ced755138 Signed-off-by: Balakrishna Godavarthi --- slimbus/btfm_slim_hw_interface.c | 3 ++- slimbus/btfm_slim_hw_interface.h | 7 ++++++- soundwire/btfm_swr_hw_interface.c | 3 ++- soundwire/btfm_swr_hw_interface.h | 6 +++++- 4 files changed, 15 insertions(+), 4 deletions(-) diff --git a/slimbus/btfm_slim_hw_interface.c b/slimbus/btfm_slim_hw_interface.c index 9886307f2d..4cc2441e48 100644 --- a/slimbus/btfm_slim_hw_interface.c +++ b/slimbus/btfm_slim_hw_interface.c @@ -196,7 +196,8 @@ void btfm_get_sampling_rate(uint32_t *sampling_rate) if (usecase_codec == LC3_VOICE || usecase_codec == APTX_AD_SPEECH || - usecase_codec == LC3 || usecase_codec == APTX_AD_R4) { + usecase_codec == LC3 || usecase_codec == APTX_AD_R4 || + usecase_codec == RVP) { *sampling_rate = 96000; } diff --git a/slimbus/btfm_slim_hw_interface.h b/slimbus/btfm_slim_hw_interface.h index 371bf890bc..bdd82073a9 100644 --- a/slimbus/btfm_slim_hw_interface.h +++ b/slimbus/btfm_slim_hw_interface.h @@ -29,6 +29,9 @@ typedef enum Codec { LC3_VOICE, APTX_AD_QLEA, APTX_AD_R4, + RVP, + SSC, + LHDC, NO_CODEC } codectype; @@ -37,7 +40,9 @@ static char const *codec_text[] = {"CODEC_TYPE_SBC", "CODEC_TYPE_AAC", "CODEC_TYPE_APTX_HD", "CODEC_TYPE_APTX_AD", "CODEC_TYPE_LC3", "CODEC_TYPE_APTX_AD_SPEECH", "CODEC_TYPE_LC3_VOICE", "CODEC_TYPE_APTX_AD_QLEA", - "CODEC_TYPE_APTX_AD_R4","CODEC_TYPE_INVALID"}; + "CODEC_TYPE_APTX_AD_R4", + "CODEC_TYPE_RVP", "CODEC_TYPE_SSC", + "CODEC_TYPE_LHDC", "CODEC_TYPE_INVALID"}; static SOC_ENUM_SINGLE_EXT_DECL(codec_display, codec_text); #endif /*__LINUX_BTFM_SLIM_HW_INTERFACE_H*/ diff --git a/soundwire/btfm_swr_hw_interface.c b/soundwire/btfm_swr_hw_interface.c index 5f9b461c48..572276b24c 100644 --- a/soundwire/btfm_swr_hw_interface.c +++ b/soundwire/btfm_swr_hw_interface.c @@ -182,7 +182,8 @@ void btfm_get_sampling_rate(uint32_t *sampling_rate) if (usecase_codec == LC3_VOICE || usecase_codec == APTX_AD_SPEECH || - usecase_codec == LC3 || usecase_codec == APTX_AD_R4) { + usecase_codec == LC3 || usecase_codec == APTX_AD_R4 || + usecase_codec == RVP) { *sampling_rate = 96000; } diff --git a/soundwire/btfm_swr_hw_interface.h b/soundwire/btfm_swr_hw_interface.h index 60b2ff7557..a959f5721a 100644 --- a/soundwire/btfm_swr_hw_interface.h +++ b/soundwire/btfm_swr_hw_interface.h @@ -21,6 +21,9 @@ enum Codec { LC3_VOICE, APTX_AD_QLEA, APTX_AD_R4, + RVP, + SSC, + LHDC, NO_CODEC }; @@ -29,7 +32,8 @@ static const char * const codec_text[] = {"CODEC_TYPE_SBC", "CODEC_TYPE_AAC", "CODEC_TYPE_APTX_HD", "CODEC_TYPE_APTX_AD", "CODEC_TYPE_LC3", "CODEC_TYPE_APTX_AD_SPEECH", "CODEC_TYPE_LC3_VOICE", "CODEC_TYPE_APTX_AD_QLEA", - "CODEC_TYPE_APTX_AD_R4", "CODEC_TYPE_INVALID"}; + "CODEC_TYPE_APTX_AD_R4", "CODEC_TYPE_RVP", + "CODEC_TYPE_SSC", "CODEC_TYPE_LHDC", "CODEC_TYPE_INVALID"}; static SOC_ENUM_SINGLE_EXT_DECL(codec_display, codec_text); #endif /*__LINUX_BTFM_SWR_HW_INTERFACE_H*/ From 4230e7169fe5805cd35b6b90150796f5b8f87037 Mon Sep 17 00:00:00 2001 From: Balakrishna Godavarthi Date: Wed, 19 Jun 2024 19:24:54 +0530 Subject: [PATCH 110/154] btfmcodec: Notify app during usecase start This change will notify app during prepare. Change-Id: I3a0ec891c3ee09c6235e7e6afb8e18595509b45f Signed-off-by: Balakrishna Godavarthi --- btfmcodec/btfm_codec.c | 16 +++++++++++++ btfmcodec/btfm_codec_interface.c | 38 ++++++++++++++++++++++++++---- btfmcodec/include/btfm_codec.h | 1 + btfmcodec/include/btfm_codec_pkt.h | 3 ++- 4 files changed, 53 insertions(+), 5 deletions(-) diff --git a/btfmcodec/btfm_codec.c b/btfmcodec/btfm_codec.c index c9f9980355..ffbbd8e0d2 100644 --- a/btfmcodec/btfm_codec.c +++ b/btfmcodec/btfm_codec.c @@ -253,6 +253,22 @@ static void btfmcodec_dev_rxwork(struct work_struct *work) log_lvl); wake_up_interruptible(&btfmcodec_dev->rsp_wait_q[idx]); break; + case BTM_BTFMCODEC_USECASE_START_RSP: + idx = BTM_PKT_TYPE_USECASE_START_RSP; + if (len == BTM_USECASE_START_IND_LEN) { + status = skb->data[0]; + if (status == MSG_SUCCESS) + btfmcodec_dev->status[idx] = BTM_RSP_RECV; + else + btfmcodec_dev->status[idx] = BTM_FAIL_RESP_RECV; + } else { + BTFMCODEC_ERR("wrong packet format with len:%d", len); + btfmcodec_dev->status[idx] = BTM_FAIL_RESP_RECV; + } + BTFMCODEC_INFO("Rx BTM_BTFMCODEC_USECASE_START_RSP status:%d", + status); + wake_up_interruptible(&btfmcodec_dev->rsp_wait_q[idx]); + break; default: BTFMCODEC_ERR("wrong opcode:%08x", opcode); } diff --git a/btfmcodec/btfm_codec_interface.c b/btfmcodec/btfm_codec_interface.c index cd5757f72d..d88ce7943e 100644 --- a/btfmcodec/btfm_codec_interface.c +++ b/btfmcodec/btfm_codec_interface.c @@ -606,12 +606,40 @@ static int btfmcodec_notify_usecase_start(struct btfmcodec_data *btfmcodec, { struct btfmcodec_char_device *btfmcodec_dev = btfmcodec->btfmcodec_dev; struct btm_usecase_start_ind ind; + wait_queue_head_t *rsp_wait_q = + &btfmcodec_dev->rsp_wait_q[BTM_PKT_TYPE_USECASE_START_RSP]; + uint8_t *status = &btfmcodec_dev->status[BTM_PKT_TYPE_USECASE_START_RSP]; + int ret; - ind.opcode = BTM_BTFMCODEC_USECASE_START_IND; + *status = BTM_WAITING_RSP; + ind.opcode = BTM_BTFMCODEC_USECASE_START_REQ; ind.len = BTM_USECASE_START_IND_LEN; ind.transport = transport; - return btfmcodec_dev_enqueue_pkt(btfmcodec_dev, &ind, (ind.len + - BTM_HEADER_LEN)); + ret = btfmcodec_dev_enqueue_pkt(btfmcodec_dev, &ind, (ind.len + BTM_HEADER_LEN)); + + if (ret < 0) + return ret; + + BTFMCODEC_INFO("waiting for BTM_BTFMCODEC_USECASE_START_RSP"); + ret = wait_event_interruptible_timeout(*rsp_wait_q, + *status != BTM_WAITING_RSP, + msecs_to_jiffies(BTM_MASTER_CONFIG_RSP_TIMEOUT)); + + if (ret == 0) { + BTFMCODEC_ERR("failed to recevie BTM_USECASE_START_IND_RSP"); + ret = -MSG_INTERNAL_TIMEOUT; + } else { + if (*status == BTM_RSP_RECV) { + ret = 0; + } else if (*status == BTM_FAIL_RESP_RECV) { + BTFMCODEC_ERR("Rx BTM_USECASE_START_IND_RSP with failure status"); + ret = -1; + } else if (*status == BTM_RSP_NOT_RECV_CLIENT_KILLED) { + BTFMCODEC_ERR("client killed so moving further"); + ret = -1; + } + } + return ret; } static int btfmcodec_dai_prepare(struct snd_pcm_substream *substream, @@ -637,7 +665,9 @@ static int btfmcodec_dai_prepare(struct snd_pcm_substream *substream, btfmcodec_get_current_transport(state) != BT_Connected) { BTFMCODEC_WARN("cached required info as state is:%s", coverttostring(btfmcodec_get_current_transport(state))); - btfmcodec_notify_usecase_start(btfmcodec, BTADV); + if (direction == 0) { + ret = btfmcodec_notify_usecase_start(btfmcodec, BTADV); + } } else { ret = btfmcodec_hwep_prepare(btfmcodec, sampling_rate, direction, id); /* if (ret >= 0) { diff --git a/btfmcodec/include/btfm_codec.h b/btfmcodec/include/btfm_codec.h index 563e557817..7e1da43457 100644 --- a/btfmcodec/include/btfm_codec.h +++ b/btfmcodec/include/btfm_codec.h @@ -56,6 +56,7 @@ enum btfm_pkt_type { BTM_PKT_TYPE_HWEP_SHUTDOWN, BTM_PKT_TYPE_HWEP_CONFIG, BTM_PKT_TYPE_DMA_CONFIG_RSP, + BTM_PKT_TYPE_USECASE_START_RSP, BTM_PKT_TYPE_MAX, }; diff --git a/btfmcodec/include/btfm_codec_pkt.h b/btfmcodec/include/btfm_codec_pkt.h index ccf7ef4ddb..dff094aa61 100644 --- a/btfmcodec/include/btfm_codec_pkt.h +++ b/btfmcodec/include/btfm_codec_pkt.h @@ -60,7 +60,8 @@ struct btm_ctrl_pkt { #define BTM_ADSP_STATE_IND_LEN 4 #define BTM_CODEC_CONFIG_DMA_REQ_LEN 11 -#define BTM_BTFMCODEC_USECASE_START_IND 0x58000008 +#define BTM_BTFMCODEC_USECASE_START_REQ 0x58000008 +#define BTM_BTFMCODEC_USECASE_START_RSP 0x58000009 #define BTM_USECASE_START_IND_LEN 1 enum rx_status { From 5f4a70f387a03856dc6c985668b5aeaaed97882c Mon Sep 17 00:00:00 2001 From: Adesh Mohanrao Pathare Date: Fri, 21 Jun 2024 20:46:45 +0530 Subject: [PATCH 111/154] btpower: added flag CONFIG_FMD_ENABLE Added changes related to enable cnss and related define on sun only. Change-Id: I1e48db951eb53e7e91606bb144b56bbe3f2b10af Signed-off-by: Adesh Mohanrao Pathare --- Android.mk | 3 +++ Kbuild | 4 ++++ pwr/btpower.c | 11 ++++++++--- target.bzl | 2 ++ 4 files changed, 17 insertions(+), 3 deletions(-) diff --git a/Android.mk b/Android.mk index b4606e0eeb..d57b76a6ae 100644 --- a/Android.mk +++ b/Android.mk @@ -17,6 +17,9 @@ ifeq ($(call is-board-platform-in-list, taro kalama pineapple blair sun parrot), BT_SELECT := CONFIG_MSM_BT_POWER=m BT_SELECT += CONFIG_I2C_RTC6226_QCA=m +ifneq ($(call is-board-platform-in-list, parrot), true) +BT_SELECT += CONFIG_FMD_ENABLE=y +endif ifeq ($(TARGET_KERNEL_DLKM_SECUREMSM_QTEE_OVERRIDE), true) ifeq ($(ENABLE_PERIPHERAL_STATE_UTILS), true) diff --git a/Kbuild b/Kbuild index 4d7c576619..f46e7da8f1 100644 --- a/Kbuild +++ b/Kbuild @@ -22,6 +22,10 @@ ifeq ($(CONFIG_BTFM_SWR),m) KBUILD_CPPFLAGS += -DCONFIG_BTFM_SWR endif +ifeq ($(CONFIG_FMD_ENABLE), y) +KBUILD_CPPFLAGS += -DCONFIG_FMD_ENABLE +endif + obj-$(CONFIG_MSM_BT_POWER) += pwr/ obj-$(CONFIG_BTFM_SLIM) += slimbus/ obj-$(CONFIG_I2C_RTC6226_QCA) += rtc6226/ diff --git a/pwr/btpower.c b/pwr/btpower.c index c0628f0f93..8a76bc7eac 100644 --- a/pwr/btpower.c +++ b/pwr/btpower.c @@ -39,7 +39,9 @@ #include #include "btpower.h" +#ifdef CONFIG_FMD_ENABLE #include "cnss_utils.h" +#endif #if (defined CONFIG_BT_SLIM) #include "btfm_slim.h" #endif @@ -1384,8 +1386,9 @@ static int get_gpio_dt_pinfo(struct platform_device *pdev) int ret; struct device_node *child; struct pinctrl *pinctrl1; +#ifdef CONFIG_FMD_ENABLE struct pinctrl_state *sw_ctrl; - +#endif child = pdev->dev.of_node; pinctrl1 = devm_pinctrl_get(&pdev->dev); @@ -1419,7 +1422,7 @@ static int get_gpio_dt_pinfo(struct platform_device *pdev) if (ret) { pr_warn("sw_cntrl-gpio not provided in devicetree\n"); } - +#ifdef CONFIG_FMD_ENABLE if (pinctrl1) { sw_ctrl = pinctrl_lookup_state(pinctrl1, "sw_ctrl"); if (IS_ERR_OR_NULL(sw_ctrl)) { @@ -1433,7 +1436,7 @@ static int get_gpio_dt_pinfo(struct platform_device *pdev) } else { pr_err("%s: pinctrl is null\n", __func__); } - +#endif pwr_data->bt_gpio_debug = of_get_named_gpio(child, "qcom,bt-debug-gpio", 0); if (pwr_data->bt_gpio_debug < 0) @@ -2494,7 +2497,9 @@ int set_fmd_mode(enum FmdOperation operation) pr_warn("%s: SET_FMD_MODE_CTRL :: UPDATE_SOC_VERSION_2_0_FOR_FMD\n", __func__); pwr_data->is_fmd_mode_enable = true; +#ifdef CONFIG_FMD_ENABLE cnss_utils_fmd_status(true); +#endif if (vote_wlan_reg_for_fmd() < 0) { pr_err("%s: failed to vote_wlan_reg_for_fmd\n", __func__); return -EINVAL; diff --git a/target.bzl b/target.bzl index c64d47da76..202424a115 100644 --- a/target.bzl +++ b/target.bzl @@ -12,6 +12,7 @@ def define_pineapple(): "CONFIG_MSM_BT_POWER", "CONFIG_BTFM_SLIM", "CONFIG_I2C_RTC6226_QCA", + "CONFIG_FMD_ENABLE", #"CONFIG_BT_HW_SECURE_DISABLE", ] ) @@ -33,6 +34,7 @@ def define_sun(): "CONFIG_BTFM_CODEC", # "CONFIG_BT_HW_SECURE_DISABLE", "CONFIG_BTFM_SWR", + "CONFIG_FMD_ENABLE", ] ) From 1aa1b357c4760dc71ed5e695c3a0d87e5dac2f38 Mon Sep 17 00:00:00 2001 From: Adesh Mohanrao Pathare Date: Mon, 24 Jun 2024 16:27:21 +0530 Subject: [PATCH 112/154] btpower: Enable wakeup capable if gpio defined Added changes to enables wakeup capable if gpio is defined in dts. Change-Id: Ie1c82b9321861e12226d4f903daa8bce1d0bc21a Signed-off-by: Adesh Mohanrao Pathare --- pwr/btpower.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pwr/btpower.c b/pwr/btpower.c index 8a76bc7eac..09293a1a56 100644 --- a/pwr/btpower.c +++ b/pwr/btpower.c @@ -745,7 +745,7 @@ static int bt_configure_gpios(int on) if (bt_sw_ctrl_gpio >= 0) { power_src.platform_state[BT_SW_CTRL_GPIO] = gpio_get_value(bt_sw_ctrl_gpio); - if (pwr_data->sw_cntrl_gpio >= 0) { + if (pwr_data->sw_cntrl_gpio > 0) { rc = msm_gpio_mpm_wake_set(pwr_data->sw_cntrl_gpio, 1); if (rc < 0) { pr_err("Failed to set msm_gpio_mpm_wake_set for sw_cntrl gpio, ret: %d\n", From f3ab751af07b3e7ba9f25b1a23d62312962048a6 Mon Sep 17 00:00:00 2001 From: Balakrishna Godavarthi Date: Wed, 26 Jun 2024 22:09:59 +0530 Subject: [PATCH 113/154] btfmcodec: update bearer switch ind timeout This change updates bearer switch indication timeout from 5 seconds to 17 seconds. Change-Id: I1c286863d52d01d7cdc120da2ae06c200af21bd2 Signed-off-by: Balakrishna Godavarthi --- btfmcodec/btfm_codec_btadv_interface.c | 2 +- btfmcodec/include/btfm_codec_pkt.h | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/btfmcodec/btfm_codec_btadv_interface.c b/btfmcodec/btfm_codec_btadv_interface.c index 7804d0d395..82f16b33e7 100644 --- a/btfmcodec/btfm_codec_btadv_interface.c +++ b/btfmcodec/btfm_codec_btadv_interface.c @@ -125,7 +125,7 @@ int btfmcodec_wait_for_bearer_ind(struct btfmcodec_char_device *btfmcodec_dev) ret = wait_event_interruptible_timeout(*rsp_wait_q, *status != BTM_WAITING_RSP, - msecs_to_jiffies(BTM_MASTER_CONFIG_RSP_TIMEOUT)); + msecs_to_jiffies(BTM_BEARER_SWITCH_IND_TIMEOUT)); if (ret == 0) { BTFMCODEC_ERR("failed to recevie BTM_BEARER_SWITCH_IND"); diff --git a/btfmcodec/include/btfm_codec_pkt.h b/btfmcodec/include/btfm_codec_pkt.h index ccf7ef4ddb..5eb0b37ac2 100644 --- a/btfmcodec/include/btfm_codec_pkt.h +++ b/btfmcodec/include/btfm_codec_pkt.h @@ -48,6 +48,7 @@ struct btm_ctrl_pkt { #define BTM_MASTER_CONFIG_REQ_LEN 13 #define BTM_MASTER_CONFIG_RSP_TIMEOUT 5000 +#define BTM_BEARER_SWITCH_IND_TIMEOUT 17000 #define BTM_MASTER_DMA_CONFIG_RSP_TIMEOUT 5000 #define BTM_HEADER_LEN 8 #define BTM_PREPARE_AUDIO_BEARER_SWITCH_RSP_LEN 2 From e10f8c4e2739c34463f89b6ef359be5b35b9688a Mon Sep 17 00:00:00 2001 From: Hemant Gupta Date: Fri, 28 Jun 2024 13:40:26 +0530 Subject: [PATCH 114/154] btfm: Rename wcn788x to wcn786x Rename wcn788x to wcn786x Change-Id: I4bda49109e543ffacd32b15135b6f58ce803bb8b Signed-off-by: Hemant Gupta --- pwr/btpower.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/pwr/btpower.c b/pwr/btpower.c index 09293a1a56..ec3a79b4a5 100644 --- a/pwr/btpower.c +++ b/pwr/btpower.c @@ -311,8 +311,8 @@ static struct pwr_data vreg_info_peach = { .platform_num_vregs = ARRAY_SIZE(platform_vregs_info_peach), }; -static struct pwr_data vreg_info_wcn788x = { - .compatible = "qcom,wcn788x", +static struct pwr_data vreg_info_wcn786x = { + .compatible = "qcom,wcn786x", .platform_vregs = platform_vregs_info_peach, .platform_num_vregs = ARRAY_SIZE(platform_vregs_info_peach), }; @@ -328,7 +328,7 @@ static const struct of_device_id bt_power_match_table[] = { { .compatible = "qcom,wcn6750-bt", .data = &vreg_info_wcn6750}, { .compatible = "qcom,bt-qca-converged", .data = &vreg_info_converged}, { .compatible = "qcom,peach-bt", .data = &vreg_info_peach}, - { .compatible = "qcom,wcn788x", .data = &vreg_info_wcn788x}, + { .compatible = "qcom,wcn786x", .data = &vreg_info_wcn786x}, {}, }; @@ -1672,7 +1672,7 @@ static int bt_power_probe(struct platform_device *pdev) pwr_data->is_ganges_dt = of_property_read_bool(pdev->dev.of_node, "qcom,peach-bt") || of_property_read_bool(pdev->dev.of_node, - "qcom,wcn788x"); + "qcom,wcn786x"); pr_info("%s: is_ganges_dt = %d\n", __func__, pwr_data->is_ganges_dt); pwr_data->workq = alloc_workqueue("workq", WQ_HIGHPRI, WQ_DFL_ACTIVE); From 3abf7f16eb6fc7fd7bf42d4f236b4beb2d1599e4 Mon Sep 17 00:00:00 2001 From: Girish BN Date: Tue, 2 Jul 2024 19:04:33 +0530 Subject: [PATCH 115/154] btpower: Removing the bt_power_release api - Removing the bt_power_release api Change-Id: Ia8220ebf52ddb96c030e831cf7113b56af748eb1 Signed-off-by: Girish BN --- pwr/btpower.c | 66 --------------------------------------------------- 1 file changed, 66 deletions(-) diff --git a/pwr/btpower.c b/pwr/btpower.c index ec3a79b4a5..18794d08a6 100644 --- a/pwr/btpower.c +++ b/pwr/btpower.c @@ -339,7 +339,6 @@ static struct class *bt_class; static int bt_major; static int soc_id; static bool probe_finished; -struct mutex pwr_release; static void bt_power_vote(struct work_struct *work); @@ -1738,15 +1737,12 @@ static int bt_power_probe(struct platform_device *pdev) return 0; free_pdata: - mutex_lock(&pwr_release); kfree(pwr_data); - mutex_unlock(&pwr_release); return ret; } static int bt_power_remove(struct platform_device *pdev) { - mutex_lock(&pwr_release); dev_dbg(&pdev->dev, "%s\n", __func__); probe_finished = false; btpower_rfkill_remove(pdev); @@ -1754,7 +1750,6 @@ static int bt_power_remove(struct platform_device *pdev) if (pwr_data->is_ganges_dt) destroy_workqueue(pwr_data->workq); kfree(pwr_data); - mutex_unlock(&pwr_release); return 0; } @@ -2701,64 +2696,6 @@ static long bt_ioctl(struct file *file, unsigned int cmd, unsigned long arg) } return ret; } - -static int bt_power_release(struct inode *inode, struct file *file) -{ - - mutex_lock(&pwr_release); - - if (!pwr_data || !probe_finished) { - pr_err("%s: BTPower Probing Pending.Try Again\n", __func__); - return -EAGAIN; - } - - pwr_data->reftask = get_current(); - - pwr_data->reftask = get_current(); - if (pwr_data->reftask_bt != NULL) { - if (pwr_data->reftask->tgid == pwr_data->reftask_bt->tgid) { - pr_err("%s called by BT service(PID-%d)\n", - __func__, pwr_data->reftask->tgid); -/* - if(get_pwr_state() == BT_ON) - { - bt_regulators_pwr(POWER_DISABLE); - platform_regulators_pwr(POWER_DISABLE); - update_pwr_state(IDLE); - - } - else if (get_pwr_state() == ALL_CLIENTS_ON) - { - bt_regulators_pwr(POWER_DISABLE); - update_pwr_state(UWB_ON); - } - */ } - - } - else if (pwr_data->reftask_uwb != NULL) - { - if (pwr_data->reftask->tgid == pwr_data->reftask_uwb->tgid) - { - pr_err("%s called by uwb service(PID-%d)\n", - __func__, pwr_data->reftask->tgid); - - /* if(get_pwr_state() == UWB_ON) - { - uwb_regulators_pwr(POWER_DISABLE); - platform_regulators_pwr(POWER_DISABLE); - update_pwr_state(IDLE); - } - else if (get_pwr_state() == ALL_CLIENTS_ON) - { - uwb_regulators_pwr(POWER_DISABLE); - update_pwr_state(BT_ON); - } - */ } - } - mutex_unlock(&pwr_release); - return 0; -} - static struct platform_driver bt_power_driver = { .probe = bt_power_probe, .remove = bt_power_remove, @@ -2771,7 +2708,6 @@ static struct platform_driver bt_power_driver = { static const struct file_operations bt_dev_fops = { .unlocked_ioctl = bt_ioctl, .compat_ioctl = bt_ioctl, - .release = bt_power_release, }; static int __init btpower_init(void) @@ -2805,8 +2741,6 @@ static int __init btpower_init(void) pr_err("%s: failed to allocate char dev\n", __func__); goto device_err; } - - mutex_init(&pwr_release); return 0; device_err: From eb3f9106325c060dbd5694ce84cdfd31f014fec3 Mon Sep 17 00:00:00 2001 From: Girish BN Date: Tue, 25 Jun 2024 13:10:56 +0530 Subject: [PATCH 116/154] Add changes to handle SET_FMD_MODE_CTRL::DISABLE_FMD - added the logic to clear the is_fmd_mode_enable flag when power driver recives the SET_FMD_MODE_CTRL with DISABLE_FMD option. Change-Id: I8489323453f19fd16e4fc4f6fba87bce694cb0b0 Signed-off-by: Girish BN --- include/btpower.h | 2 +- pwr/btpower.c | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/include/btpower.h b/include/btpower.h index 03d1dcf45d..c1a4802fb9 100644 --- a/include/btpower.h +++ b/include/btpower.h @@ -32,7 +32,7 @@ enum SubSystem { enum FmdOperation { ENABLE_SDAM_BIT_FMD = 0, - DISABLE_SDAM_BIT_FMD, + DISABLE_FMD, UPDATE_SOC_VERSION_1_0_FOR_FMD, UPDATE_SOC_VERSION_2_0_FOR_FMD }; diff --git a/pwr/btpower.c b/pwr/btpower.c index 18794d08a6..b167f5df0b 100644 --- a/pwr/btpower.c +++ b/pwr/btpower.c @@ -2469,10 +2469,10 @@ int set_fmd_mode(enum FmdOperation operation) set_fmd_sdam_bit((unsigned char)POWER_ENABLE); break; } - case DISABLE_SDAM_BIT_FMD: { - pr_warn("%s: SET_FMD_MODE_CTRL :: DISABLE_SDAM_BIT_FMD\n", + case DISABLE_FMD: { + pr_warn("%s: SET_FMD_MODE_CTRL :: DISABLE_FMD\n", __func__); - set_fmd_sdam_bit((unsigned char)POWER_DISABLE); + pwr_data->is_fmd_mode_enable = false; break; } case UPDATE_SOC_VERSION_1_0_FOR_FMD: { From 283a84762584d3c92ed55728cd0ef64e69ed86b7 Mon Sep 17 00:00:00 2001 From: Xhoendi Collaku Date: Tue, 23 Jul 2024 00:02:00 -0700 Subject: [PATCH 117/154] canoe: Replace strlcpy() with strscpy() Replace strlcpy() with strscpy() CRs-Fixed: 3877554 Change-Id: Ifa967e3ee0183c39a7b49579bbe51ab847bc8a14 Signed-off-by: Xhoendi Collaku --- btfmcodec/btfm_codec.c | 4 ++-- rtc6226/radio-rtc6226-common.c | 6 +++--- rtc6226/radio-rtc6226-i2c.c | 6 +++--- slimbus/btfm_slim_hw_interface.c | 4 ++-- 4 files changed, 10 insertions(+), 10 deletions(-) diff --git a/btfmcodec/btfm_codec.c b/btfmcodec/btfm_codec.c index c9f9980355..d78f7384fa 100644 --- a/btfmcodec/btfm_codec.c +++ b/btfmcodec/btfm_codec.c @@ -1,6 +1,6 @@ // SPDX-License-Identifier: GPL-2.0-only /* - * Copyright (c) 2023 Qualcomm Innovation Center, Inc. All rights reserved. + * Copyright (c) 2023-2024 Qualcomm Innovation Center, Inc. All rights reserved. */ #include @@ -623,7 +623,7 @@ static int __init btfmcodec_init(void) btfmcodec->btfmcodec_dev = btfmcodec_dev; refcount_set(&btfmcodec_dev->active_clients, 1); mutex_init(&btfmcodec_dev->lock); - strlcpy(btfmcodec_dev->dev_name, "btfmcodec_dev", DEVICE_NAME_MAX_LEN); + strscpy(btfmcodec_dev->dev_name, "btfmcodec_dev", DEVICE_NAME_MAX_LEN); device_initialize(dev); dev->class = dev_class; dev->devt = MKDEV(MAJOR(dev_major), btfmcodec_dev->reuse_minor); diff --git a/rtc6226/radio-rtc6226-common.c b/rtc6226/radio-rtc6226-common.c index 98cbfbfc0e..2968f4680e 100644 --- a/rtc6226/radio-rtc6226-common.c +++ b/rtc6226/radio-rtc6226-common.c @@ -106,7 +106,7 @@ * Improves RDS reception significantly * 2018-02-01 LG Electronics, Inc. * 2018-08-19 Richwave Technology Co.Ltd - * Copyright (c) 2021 Qualcomm Innovation Center, Inc. All rights reserved. + * Copyright (c) 2021-2024 Qualcomm Innovation Center, Inc. All rights reserved. */ /* kernel includes */ @@ -2074,7 +2074,7 @@ static int rtc6226_vidioc_g_audio(struct file *file, void *priv, { /* driver constants */ audio->index = 0; - strlcpy(audio->name, "Radio", sizeof(audio->name)); + strscpy(audio->name, "Radio", sizeof(audio->name)); audio->capability = V4L2_AUDCAP_STEREO; audio->mode = 0; @@ -2103,7 +2103,7 @@ static int rtc6226_vidioc_g_tuner(struct file *file, void *priv, goto done; /* driver constants */ - strlcpy(tuner->name, "FM", sizeof(tuner->name)); + strscpy(tuner->name, "FM", sizeof(tuner->name)); tuner->type = V4L2_TUNER_RADIO; tuner->capability = V4L2_TUNER_CAP_LOW | V4L2_TUNER_CAP_STEREO | V4L2_TUNER_CAP_RDS | V4L2_TUNER_CAP_RDS_BLOCK_IO; diff --git a/rtc6226/radio-rtc6226-i2c.c b/rtc6226/radio-rtc6226-i2c.c index 4b9bb8b7b6..f62041485f 100644 --- a/rtc6226/radio-rtc6226-i2c.c +++ b/rtc6226/radio-rtc6226-i2c.c @@ -8,7 +8,7 @@ * Copyright (c) 2012 Hans de Goede * Copyright (c) 2018 LG Electronics, Inc. * Copyright (c) 2018 Richwave Technology Co.Ltd - * Copyright (c) 2021 Qualcomm Innovation Center, Inc. All rights reserved. + * Copyright (c) 2021-2024 Qualcomm Innovation Center, Inc. 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 as published by @@ -212,8 +212,8 @@ int rtc6226_vidioc_querycap(struct file *file, void *priv, struct v4l2_capability *capability) { FMDBG("%s enter\n", __func__); - strlcpy(capability->driver, DRIVER_NAME, sizeof(capability->driver)); - strlcpy(capability->card, DRIVER_CARD, sizeof(capability->card)); + strscpy(capability->driver, DRIVER_NAME, sizeof(capability->driver)); + strscpy(capability->card, DRIVER_CARD, sizeof(capability->card)); capability->device_caps = V4L2_CAP_HW_FREQ_SEEK | V4L2_CAP_READWRITE | V4L2_CAP_TUNER | V4L2_CAP_RADIO | V4L2_CAP_RDS_CAPTURE; capability->capabilities = capability->device_caps | diff --git a/slimbus/btfm_slim_hw_interface.c b/slimbus/btfm_slim_hw_interface.c index 9886307f2d..cb0b89bac6 100644 --- a/slimbus/btfm_slim_hw_interface.c +++ b/slimbus/btfm_slim_hw_interface.c @@ -1,7 +1,7 @@ // SPDX-License-Identifier: GPL-2.0-only /* * Copyright (c) 2016-2021, The Linux Foundation. All rights reserved. - * Copyright (c) 2021, 2023 Qualcomm Innovation Center, Inc. All rights reserved. + * Copyright (c) 2021, 2023-2024 Qualcomm Innovation Center, Inc. All rights reserved. */ #include @@ -514,7 +514,7 @@ int btfm_slim_register_hw_ep(struct btfmslim *btfm_slim) /* Copy EP device parameters as intercations will be on the same device */ hwep_info->dev = dev; - strlcpy(hwep_info->driver_name, BTFMSLIM_DEV_NAME, DEVICE_NAME_MAX_LEN); + strscpy(hwep_info->driver_name, BTFMSLIM_DEV_NAME, DEVICE_NAME_MAX_LEN); hwep_info->drv = &btfmslim_hw_driver; hwep_info->dai_drv = btfmslim_dai_driver; hwep_info->num_dai = ARRAY_SIZE(btfmslim_dai_driver); From a78b65d3dd432a94312bcd20095fdfb17d033e18 Mon Sep 17 00:00:00 2001 From: Girish BN Date: Mon, 29 Jul 2024 20:06:06 +0530 Subject: [PATCH 118/154] FMD: set NVMEM sells for FMD operations - configure NVMEM cells for FMD operations based on bt transport request. Change-Id: Ibfb4410c92b6cde83e5b17f7cdf92a332df68c43 Signed-off-by: Girish BN --- include/btpower.h | 20 ++- pwr/btpower.c | 384 ++++++++++++++++++++++++++++++++-------------- 2 files changed, 280 insertions(+), 124 deletions(-) diff --git a/include/btpower.h b/include/btpower.h index c1a4802fb9..497815e922 100644 --- a/include/btpower.h +++ b/include/btpower.h @@ -31,10 +31,9 @@ enum SubSystem { }; enum FmdOperation { - ENABLE_SDAM_BIT_FMD = 0, + ENABLE_FMD, DISABLE_FMD, - UPDATE_SOC_VERSION_1_0_FOR_FMD, - UPDATE_SOC_VERSION_2_0_FOR_FMD + UPDATE_SOC_VER }; enum power_states { @@ -589,6 +588,13 @@ struct log_index { int crash; }; +struct fmdOperationStruct { + unsigned char fmdOperation; + unsigned char socFwVer; + short int rebootStatus; + short int fmdCycles; +}; + struct vreg_data { struct regulator *reg; /* voltage regulator handle */ const char *name; /* regulator name */ @@ -685,7 +691,9 @@ struct platform_pwr_data { struct sk_buff_head rxq; struct mutex pwr_mtx; bool is_fmd_mode_enable; - struct nvmem_cell *nvmem_cell; + struct nvmem_cell *nvmem_cell_fmd_set; + struct nvmem_cell *nvmem_cell_fmd_chg_pon; + struct nvmem_cell *nvmem_cell_fmd_cnt2_stop; u32 fmd_clk_gpio_id; }; @@ -694,7 +702,7 @@ int btpower_get_chipset_version(void); int btpower_aop_mbox_init(struct platform_pwr_data *pdata); int bt_aop_pdc_reconfig(struct platform_pwr_data *pdata); -#define WLAN_SW_CTRL_GPIO "qcom,wlan-sw-ctrl-gpio" +#define WLAN_SW_CTRL_GPIO "qcom,wlan-sw-ctrl-gpio" #define BT_CMD_SLIM_TEST 0xbfac #define BT_CMD_PWR_CTRL 0xbfad #define BT_CMD_CHIPSET_VERS 0xbfae @@ -709,7 +717,7 @@ int bt_aop_pdc_reconfig(struct platform_pwr_data *pdata); #define UWB_CMD_REGISTRATION 0xbfe3 #define BT_CMD_ACCESS_CTRL 0xbfe4 #define UWB_CMD_ACCESS_CTRL 0xbfe5 -#define SET_FMD_MODE_CTRL 0xbfb2 +#define BT_CMD_FMD_OPERATION 0xbfb2 #ifdef CONFIG_MSM_BT_OOBS #define BT_CMD_OBS_VOTE_CLOCK 0xbfd1 diff --git a/pwr/btpower.c b/pwr/btpower.c index b167f5df0b..e86bd109a0 100644 --- a/pwr/btpower.c +++ b/pwr/btpower.c @@ -84,6 +84,9 @@ #define UWB_SS (0x02) #define TME_SS (0x03) +#define SOC_VERSION_1_0 0x01 +#define SOC_VERSION_2_0 0x02 + /** * enum btpower_vreg_param: Voltage regulator TCS param * @BTPOWER_VREG_VOLTAGE: Provides voltage level to be configured in TCS @@ -339,6 +342,7 @@ static struct class *bt_class; static int bt_major; static int soc_id; static bool probe_finished; +static struct fmdOperationStruct fmdStruct; static void bt_power_vote(struct work_struct *work); @@ -1644,29 +1648,44 @@ static int bt_power_probe(struct platform_device *pdev) struct device *devi = &pwr_data->pdev->dev; int rc = 0; - pwr_data->nvmem_cell = devm_nvmem_cell_get(devi, "fmd_set"); - - if (IS_ERR(pwr_data->nvmem_cell)) { - rc = PTR_ERR(pwr_data->nvmem_cell); - pr_err("%s:Failed to get FMD nvmem-cells %d\n", __func__, rc); - } - - pr_info("%s: --- Got FMD nvmem-cells %d\n", __func__, rc); - - if (rc >= 0) { - u8 *buf; - size_t len; - - dev_info(&pwr_data->pdev->dev, "Got fmd_set nvmem_cell\n"); - buf = nvmem_cell_read(pwr_data->nvmem_cell, &len); - if (IS_ERR(buf)) { - dev_err(&pwr_data->pdev->dev, "Failed to read fmd_set: %ld\n", - PTR_ERR(buf)); + pr_info("%s: Get FMD nvmem-cells\n", __func__); +/* Get fmd_set NVMEM Cell Handler */ + pwr_data->nvmem_cell_fmd_set = + devm_nvmem_cell_get(devi, "fmd_set"); + if (IS_ERR(pwr_data->nvmem_cell_fmd_set)) { + rc = PTR_ERR(pwr_data->nvmem_cell_fmd_set); + pr_err("%s:Failed to get fmd_set nvmem-cells %d\n", + __func__, rc); + pr_err("%s:Skip, Reading of other 2 Cells have no use\n", + __func__); + pwr_data->nvmem_cell_fmd_chg_pon = + pwr_data->nvmem_cell_fmd_set; + pwr_data->nvmem_cell_fmd_cnt2_stop = + pwr_data->nvmem_cell_fmd_set; + } else { + pr_info("%s: Got fmd_set nvmem-cells\n", __func__); +/* Get fmd_chg_pon NVMEM Cell Handler */ + pwr_data->nvmem_cell_fmd_chg_pon = + devm_nvmem_cell_get(devi, "fmd_chg_pon"); + if (IS_ERR(pwr_data->nvmem_cell_fmd_chg_pon)) { + rc = PTR_ERR(pwr_data->nvmem_cell_fmd_chg_pon); + pr_err("%s:Failed to get fmd_chg_pon nvmem-cells %d\n", + __func__, rc); } else { - dev_info(&pwr_data->pdev->dev, "fmd_set: %u\n", buf[0]); - kfree(buf); + pr_info("%s: Got fmd_chg_pon nvmem-cells\n", __func__); + } +/* Get fmd_cnt2_stop NVMEM Cell Handler */ + pwr_data->nvmem_cell_fmd_cnt2_stop = + devm_nvmem_cell_get(devi, "fmd_cnt2_stop"); + if (IS_ERR(pwr_data->nvmem_cell_fmd_cnt2_stop)) { + rc = PTR_ERR(pwr_data->nvmem_cell_fmd_cnt2_stop); + pr_err("%s:Failed to get fmd_cnt2_stop nvmem-cells %d\n", + __func__, rc); + } else { + pr_info("%s: Got fmd_cnt2_stop nvmem-cells\n", __func__); } } + pr_info("%s: FMD nvmem-cells read completed\n", __func__); pwr_data->is_ganges_dt = of_property_read_bool(pdev->dev.of_node, "qcom,peach-bt") || @@ -2433,84 +2452,208 @@ const char *GetSourceSubsystemString(uint32_t source_subsystem) } } -void set_fmd_sdam_bit(unsigned char sdam_bit) +void fmd_set_sdam_bit(unsigned char arg) { int rc = 0; - - rc = nvmem_cell_write(pwr_data->nvmem_cell, &sdam_bit, sizeof(sdam_bit)); - if (rc < 0) { - pr_err("%s: SDAM BIT of FMD Write Failed %d\n", __func__, rc); - return; - } - pr_warn("%s: SDAM BIT of FMD Write Success %d\n", __func__, rc); - u8 *buf; size_t len; + struct device *devi = &pwr_data->pdev->dev; - dev_info(&pwr_data->pdev->dev, "Got fmd_set nvmem_cell\n"); - buf = nvmem_cell_read(pwr_data->nvmem_cell, &len); - if (IS_ERR(buf)) { - dev_err(&pwr_data->pdev->dev, "Failed to read fmd_set: %ld\n", PTR_ERR(buf)); - } else { - dev_info(&pwr_data->pdev->dev, "fmd_set: %u\n", buf[0]); - pr_warn("%s: Read SDAM BIT of FMD %d\n", __func__, buf[0]); - kfree(buf); + if (IS_ERR(pwr_data->nvmem_cell_fmd_set)) { + pr_err("%s: 'fmd_set' cell is not avilable to configure\n", + __func__); + return; } + + rc = nvmem_cell_write(pwr_data->nvmem_cell_fmd_set, + &arg, + sizeof(arg)); + if (rc < 0) { + pr_err("%s: Write SDAM BIT for FMD operation Failed %d\n", + __func__, rc); + return; + } + + buf = nvmem_cell_read(pwr_data->nvmem_cell_fmd_set, &len); + if (IS_ERR(buf)) { + dev_err(devi, "Failed to read fmd_set: %ld\n", + PTR_ERR(buf)); + pr_err("%s: Failed to read SDAM BIT (fmd_set = %d)\n", + __func__, buf[0]); + kfree(buf); + return; + } + + if (buf[0] == arg) { + dev_info(devi, "Successfully configured the fmd_set\n"); + pr_info("%s: Successfully configured SDAM BIT (fmd_set: %u)\n", + __func__, buf[0]); + } else { + dev_err(devi, "Failed to configure fmd_set: %ld\n", + PTR_ERR(buf)); + pr_err("%s: Failed to configure SDAM BIT (fmd_set = %u)\n", + __func__, buf[0]); + } + kfree(buf); } -int set_fmd_mode(enum FmdOperation operation) +void fmd_reboot_on_usb_detection(unsigned char arg) +{ + int rc = 0; + u8 *buf; + size_t len; + struct device *devi = &pwr_data->pdev->dev; + + if (IS_ERR(pwr_data->nvmem_cell_fmd_chg_pon)) { + pr_err("%s: 'fmd_chg_pon' cell is not avilable to configure\n", + __func__); + return; + } + + rc = nvmem_cell_write(pwr_data->nvmem_cell_fmd_chg_pon, + &arg, + sizeof(arg)); + if (rc < 0) { + pr_err("%s: Write fmd_chg_pon for FMD operation Failed %d\n", + __func__, rc); + return; + } + + buf = nvmem_cell_read(pwr_data->nvmem_cell_fmd_chg_pon, &len); + if (IS_ERR(buf)) { + dev_err(devi, "Failed to read fmd_chg_pon: %ld\n", + PTR_ERR(buf)); + pr_err("%s: Failed to read fmd_chg_pon = %d\n", + __func__, buf[0]); + kfree(buf); + return; + } + + if (buf[0] == arg) { + dev_info(devi, "Successfully configured the fmd_chg_pon\n"); + pr_info("%s: Successfully configured (fmd_chg_pon: %u)\n", + __func__, buf[0]); + } else { + dev_err(devi, "Failed to configure fmd_chg_pon: %ld\n", + PTR_ERR(buf)); + pr_err("%s: Failed to configure fmd_chg_pon = %u\n", + __func__, buf[0]); + } + kfree(buf); +} + +void fmd_write_stop_counter(unsigned char arg) +{ + int rc = 0; + u8 *buf; + size_t len; + struct device *devi = &pwr_data->pdev->dev; + + if (IS_ERR(pwr_data->nvmem_cell_fmd_cnt2_stop)) { + pr_err("%s: 'fmd_cnt2_stop' cell is not avilable to configure\n", + __func__); + return; + } + + rc = nvmem_cell_write(pwr_data->nvmem_cell_fmd_cnt2_stop, + &arg, + sizeof(arg)); + if (rc < 0) { + pr_err("%s: Write cnt2_stop for FMD operation Failed %d\n", + __func__, rc); + return; + } + + buf = nvmem_cell_read(pwr_data->nvmem_cell_fmd_cnt2_stop, &len); + if (IS_ERR(buf)) { + dev_err(devi, "Failed to read fmd_cnt2_stop: %ld\n", + PTR_ERR(buf)); + pr_err("%s: Failed to read fmd_cnt2_stop = %d\n", + __func__, buf[0]); + kfree(buf); + return; + } + + if (buf[0] == arg) { + dev_info(devi, "Successfully configured the fmd_cnt2_stop\n"); + pr_info("%s: Successfully configured (fmd_cnt2_stop: %u)\n", + __func__, buf[0]); + } else { + dev_err(devi, "Failed to configure fmd_cnt2_stop: %ld\n", + PTR_ERR(buf)); + pr_err("%s: Failed to configure fmd_cnt2_stop = %u\n", + __func__, buf[0]); + } + kfree(buf); +} + +int perform_fmd_operation(void) { int ret = 0; + switch ((enum FmdOperation) fmdStruct.fmdOperation) { + case UPDATE_SOC_VER: { + if (fmdStruct.socFwVer == SOC_VERSION_1_0) { + pr_info("%s: UPDATE_SOC_VER :: SOC_VERSION_1_0\n", + __func__); + pwr_data->is_fmd_mode_enable = true; + if (pwr_data->bt_chip_clk) { + ret = bt_clk_enable(pwr_data->bt_chip_clk); + if (ret < 0) { + pr_err("%s: failed to bt_chip_clk\n", __func__); + return -EINVAL; + } + } + } else if (fmdStruct.socFwVer == SOC_VERSION_2_0) { + pr_info("%s: UPDATE_SOC_VER :: SOC_VERSION_2_0\n", + __func__); + pwr_data->is_fmd_mode_enable = true; +#ifdef CONFIG_FMD_ENABLE + cnss_utils_fmd_status(true); +#endif + if (vote_wlan_reg_for_fmd() < 0) { + pr_err("%s: failed to vote_wlan_reg_for_fmd\n", __func__); + return -EINVAL; + } + if (pwr_data->bt_chip_clk) { + ret = bt_clk_enable(pwr_data->bt_chip_clk); + if (ret < 0) { + pr_err("%s: failed to bt_chip_clk\n", __func__); + return -EINVAL; + } + } + } else { + pr_err("%s: Invalid SOC VERSION sent = %d\n", + __func__, fmdStruct.socFwVer); + return -EINVAL; + } + break; + } + case ENABLE_FMD: { + pr_info("%s: ENABLE_FMD\n", __func__); + + fmd_set_sdam_bit((unsigned char)POWER_ENABLE); + + if (fmdStruct.rebootStatus != -1) + fmd_reboot_on_usb_detection((unsigned char)fmdStruct.rebootStatus); + else + pr_err("%s: Reboot status upon usb detection is not configured\n", + __func__); + + if (fmdStruct.fmdCycles != -1) + fmd_write_stop_counter((unsigned char)fmdStruct.fmdCycles); + else + pr_err("%s: Fmd stop_counter is not configured\n", __func__); - switch (operation) { - case ENABLE_SDAM_BIT_FMD: { - pr_warn("%s: SET_FMD_MODE_CTRL :: ENABLE_SDAM_BIT_FMD\n", - __func__); - set_fmd_sdam_bit((unsigned char)POWER_ENABLE); break; } case DISABLE_FMD: { - pr_warn("%s: SET_FMD_MODE_CTRL :: DISABLE_FMD\n", - __func__); + pr_info("%s: DISABLE_FMD\n", __func__); pwr_data->is_fmd_mode_enable = false; break; } - case UPDATE_SOC_VERSION_1_0_FOR_FMD: { - pr_warn("%s: SET_FMD_MODE_CTRL :: UPDATE_SOC_VERSION_1_0_FOR_FMD\n", - __func__); - pwr_data->is_fmd_mode_enable = true; - if (pwr_data->bt_chip_clk) { - ret = bt_clk_enable(pwr_data->bt_chip_clk); - if (ret < 0) { - pr_err("%s: failed to bt_chip_clk\n", __func__); - return -EINVAL; - } - } - break; - } - case UPDATE_SOC_VERSION_2_0_FOR_FMD: { - pr_warn("%s: SET_FMD_MODE_CTRL :: UPDATE_SOC_VERSION_2_0_FOR_FMD\n", - __func__); - pwr_data->is_fmd_mode_enable = true; -#ifdef CONFIG_FMD_ENABLE - cnss_utils_fmd_status(true); -#endif - if (vote_wlan_reg_for_fmd() < 0) { - pr_err("%s: failed to vote_wlan_reg_for_fmd\n", __func__); - return -EINVAL; - } - if (pwr_data->bt_chip_clk) { - ret = bt_clk_enable(pwr_data->bt_chip_clk); - if (ret < 0) { - pr_err("%s: failed to bt_chip_clk\n", __func__); - return -EINVAL; - } - } - break; - } default: { - pr_warn("%s: invalid fmd operation = %d received\n", - __func__, operation); + pr_err("%s: invalid fmd operation received = %d\n", + __func__, fmdStruct.fmdOperation); ret = -EINVAL; break; } @@ -2518,6 +2661,41 @@ int set_fmd_mode(enum FmdOperation operation) return ret; } +#ifdef CONFIG_MSM_BT_OOBS +int bt_oobs_handler(enum btpower_obs_param clk_cntrl) +{ + if (!gpio_is_valid(pwr_data->bt_gpio_dev_wake)) { + pr_debug("%s: BT_CMD_OBS_VOTE_CLOCK bt_dev_wake_n(%d) not configured\n", + __func__, pwr_data->bt_gpio_dev_wake); + return -EIO; + } + + switch (clk_cntrl) { + case BTPOWER_OBS_CLK_OFF: + btpower_uart_transport_locked(pwr_data, false); + break; + case BTPOWER_OBS_CLK_ON: + btpower_uart_transport_locked(pwr_data, true); + break; + case BTPOWER_OBS_DEV_OFF: + gpio_set_value(pwr_data->bt_gpio_dev_wake, 0); + break; + case BTPOWER_OBS_DEV_ON: + gpio_set_value(pwr_data->bt_gpio_dev_wake, 1); + break; + default: + pr_debug("%s: BT_CMD_OBS_VOTE_CLOCK clk_cntrl(%d)\n", + __func__, clk_cntrl); + return -EINVAL; + } + pr_debug("%s: BT_CMD_OBS_VOTE_CLOCK clk_cntrl(%d) %s\n", + __func__, clk_cntrl, + gpio_get_value(pwr_data->bt_gpio_dev_wake) ? + "Assert" : "Deassert"); + return 0; +} +#endif + static long bt_ioctl(struct file *file, unsigned int cmd, unsigned long arg) { int ret = 0; @@ -2525,10 +2703,6 @@ static long bt_ioctl(struct file *file, unsigned int cmd, unsigned long arg) unsigned long panic_reason = 0; unsigned short primary_reason = 0, sec_reason = 0, source_subsystem = 0; -#ifdef CONFIG_MSM_BT_OOBS - enum btpower_obs_param clk_cntrl; -#endif - if (!pwr_data || !probe_finished) { pr_err("%s: BTPower Probing Pending.Try Again\n", __func__); return -EAGAIN; @@ -2537,38 +2711,7 @@ static long bt_ioctl(struct file *file, unsigned int cmd, unsigned long arg) switch (cmd) { #ifdef CONFIG_MSM_BT_OOBS case BT_CMD_OBS_VOTE_CLOCK: - if (!gpio_is_valid(pwr_data->bt_gpio_dev_wake)) { - pr_debug("%s: BT_CMD_OBS_VOTE_CLOCK bt_dev_wake_n(%d) not configured\n", - __func__, pwr_data->bt_gpio_dev_wake); - return -EIO; - } - clk_cntrl = (enum btpower_obs_param)arg; - switch (clk_cntrl) { - case BTPOWER_OBS_CLK_OFF: - btpower_uart_transport_locked(pwr_data, false); - ret = 0; - break; - case BTPOWER_OBS_CLK_ON: - btpower_uart_transport_locked(pwr_data, true); - ret = 0; - break; - case BTPOWER_OBS_DEV_OFF: - gpio_set_value(pwr_data->bt_gpio_dev_wake, 0); - ret = 0; - break; - case BTPOWER_OBS_DEV_ON: - gpio_set_value(pwr_data->bt_gpio_dev_wake, 1); - ret = 0; - break; - default: - pr_debug("%s: BT_CMD_OBS_VOTE_CLOCK clk_cntrl(%d)\n", - __func__, clk_cntrl); - return -EINVAL; - } - pr_debug("%s: BT_CMD_OBS_VOTE_CLOCK clk_cntrl(%d) %s\n", - __func__, clk_cntrl, - gpio_get_value(pwr_data->bt_gpio_dev_wake) ? - "Assert" : "Deassert"); + ret = bt_oobs_handler((enum btpower_obs_param)arg); break; #endif case BT_CMD_SLIM_TEST: @@ -2587,8 +2730,13 @@ static long bt_ioctl(struct file *file, unsigned int cmd, unsigned long arg) ret = btpower_handle_client_request(cmd, (int)arg); break; } - case SET_FMD_MODE_CTRL: { - ret = set_fmd_mode((enum FmdOperation)arg); + case BT_CMD_FMD_OPERATION: { + pr_err("%s: BT_CMD_FMD_OPERATION\n", __func__); + if (copy_from_user(&fmdStruct, (char *)arg, sizeof(fmdStruct))) { + pr_err("%s: copy to user failed\n", __func__); + ret = -EFAULT; + } + ret = perform_fmd_operation(); break; } case BT_CMD_REGISTRATION: From cad5a6883384772068e787735077d5bda4a34b97 Mon Sep 17 00:00:00 2001 From: Balakrishna Godavarthi Date: Thu, 8 Aug 2024 09:23:34 +0530 Subject: [PATCH 119/154] btpower: Add wcn7750 bt soc support This change adds wcn7750 btsoc support Change-Id: If14f3ab946b4a3a6c7c2693c357b73f06bdaca36 Signed-off-by: Balakrishna Godavarthi --- pwr/btpower.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/pwr/btpower.c b/pwr/btpower.c index e86bd109a0..6e036aa40f 100644 --- a/pwr/btpower.c +++ b/pwr/btpower.c @@ -320,6 +320,12 @@ static struct pwr_data vreg_info_wcn786x = { .platform_num_vregs = ARRAY_SIZE(platform_vregs_info_peach), }; +static struct pwr_data bt_vreg_info_wcn7750 = { + .compatible = "qcom,wcn7750-bt", + .bt_vregs = bt_vregs_info_qca6xx0, + .bt_num_vregs = ARRAY_SIZE(bt_vregs_info_qca6xx0), +}; + static const struct of_device_id bt_power_match_table[] = { { .compatible = "qcom,qca6174", .data = &vreg_info_qca6174}, { .compatible = "qcom,wcn3990", .data = &vreg_info_wcn399x}, @@ -332,6 +338,7 @@ static const struct of_device_id bt_power_match_table[] = { { .compatible = "qcom,bt-qca-converged", .data = &vreg_info_converged}, { .compatible = "qcom,peach-bt", .data = &vreg_info_peach}, { .compatible = "qcom,wcn786x", .data = &vreg_info_wcn786x}, + { .compatible = "qcom,wcn7750-bt", .data = &bt_vreg_info_wcn7750}, {}, }; From 39bf2ee7ecdd54c34be8c2d93d4dd90213333647 Mon Sep 17 00:00:00 2001 From: Hemant Gupta Date: Tue, 13 Aug 2024 21:04:44 +0530 Subject: [PATCH 120/154] btswr: Update the sampling rate for LHDC codec Update the sampling rate for LHDC codec. CRs-Fixed: 3891084 Change-Id: If14f3ab946b4a3a6c7c2693c357b73f06bdaca46 Signed-off-by: Hemant Gupta --- soundwire/btfm_swr_hw_interface.c | 3 ++- soundwire/btfm_swr_hw_interface.h | 4 ++-- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/soundwire/btfm_swr_hw_interface.c b/soundwire/btfm_swr_hw_interface.c index 572276b24c..e591bf995c 100644 --- a/soundwire/btfm_swr_hw_interface.c +++ b/soundwire/btfm_swr_hw_interface.c @@ -176,7 +176,8 @@ void btfm_get_sampling_rate(uint32_t *sampling_rate) if (*sampling_rate == 44100 || *sampling_rate == 48000) { if (usecase_codec == LDAC || - usecase_codec == APTX_AD) + usecase_codec == APTX_AD || + usecase_codec == LHDC) *sampling_rate = (*sampling_rate) * 2; } diff --git a/soundwire/btfm_swr_hw_interface.h b/soundwire/btfm_swr_hw_interface.h index a959f5721a..d95bd3b9da 100644 --- a/soundwire/btfm_swr_hw_interface.h +++ b/soundwire/btfm_swr_hw_interface.h @@ -1,6 +1,6 @@ // SPDX-License-Identifier: GPL-2.0-only /* - * Copyright (c) 2023 Qualcomm Innovation Center, Inc. All rights reserved. + * Copyright (c) 2023-2024 Qualcomm Innovation Center, Inc. All rights reserved. */ #ifndef __LINUX_BTFM_SWR_HW_INTERFACE_H @@ -23,7 +23,7 @@ enum Codec { APTX_AD_R4, RVP, SSC, - LHDC, + LHDC, NO_CODEC }; From aff4d40d88f44f7361d3bf721fed2a6bbd73a3b4 Mon Sep 17 00:00:00 2001 From: Balakrishna Godavarthi Date: Tue, 20 Aug 2024 14:12:24 +0530 Subject: [PATCH 121/154] btfmcodec: Allow port close even in BTADV connecting state Allow swr port close even in BTADV connecting state so that on next iteration sound wire ports are opened afresh. CRs-Fixed: 3881621 Change-Id: I702210b547727dcf1c71e69a3ddddee17d4acb0c Signed-off-by: Balakrishna Godavarthi --- btfmcodec/btfm_codec.c | 56 +++++++++++++++---- btfmcodec/btfm_codec_btadv_interface.c | 32 +++++++++-- btfmcodec/btfm_codec_interface.c | 19 ++++++- btfmcodec/include/btfm_codec.h | 4 +- .../include/btfm_codec_btadv_interface.h | 3 +- btfmcodec/include/btfm_codec_pkt.h | 8 ++- 6 files changed, 98 insertions(+), 24 deletions(-) diff --git a/btfmcodec/btfm_codec.c b/btfmcodec/btfm_codec.c index bd49ab6078..1731eb6cec 100644 --- a/btfmcodec/btfm_codec.c +++ b/btfmcodec/btfm_codec.c @@ -111,6 +111,7 @@ static int btfmcodec_dev_release(struct inode *inode, struct file *file) spin_unlock_irqrestore(&btfmcodec_dev->tx_queue_lock, flags); /* we need to have separte rx lock for below buff */ skb_queue_purge(&btfmcodec_dev->rxq); + skb_queue_purge(&btfmcodec_dev->trans_rxq); } /* Notify waiting clients that client is closed or killed */ @@ -128,6 +129,7 @@ static int btfmcodec_dev_release(struct inode *inode, struct file *file) btfmcodec->states.current_state = IDLE; btfmcodec->states.next_state = IDLE; + return 0; } @@ -157,21 +159,13 @@ static void btfmcodec_dev_rxwork(struct work_struct *work) idx = BTM_PKT_TYPE_PREPARE_REQ; BTFMCODEC_DBG("BTM_BTFMCODEC_PREPARE_AUDIO_BEARER_SWITCH_REQ"); if (len == BTM_PREPARE_AUDIO_BEARER_SWITCH_REQ_LEN) { - /* there are chances where bearer indication is not recevied, - * So inform waiting thread to unblock itself and move to - * previous state. - */ - if (btfmcodec_dev->status[BTM_PKT_TYPE_BEARER_SWITCH_IND] == BTM_WAITING_RSP) { - BTFMCODEC_DBG("Notifying waiting beare indications"); - btfmcodec_dev->status[BTM_PKT_TYPE_BEARER_SWITCH_IND] = BTM_FAIL_RESP_RECV; - wake_up_interruptible(&btfmcodec_dev->rsp_wait_q[BTM_PKT_TYPE_BEARER_SWITCH_IND]); - } - btfmcodec_dev->status[idx] = skb->data[0]; /* Reset bearer switch ind flag */ bearer_switch_ind = &btfmcodec_dev->status[BTM_PKT_TYPE_BEARER_SWITCH_IND]; *bearer_switch_ind = BTM_WAITING_RSP; - queue_work(btfmcodec_dev->workqueue, &btfmcodec_dev->wq_prepare_bearer); + btfmcodec_enqueue_transport(btfmcodec_dev, skb->data[0]); + queue_work(btfmcodec_dev->workqueue, + &btfmcodec_dev->wq_prepare_bearer); } else { BTFMCODEC_ERR("wrong packet format with len:%d", len); } @@ -375,6 +369,44 @@ int btfmcodec_dev_enqueue_pkt(struct btfmcodec_char_device *btfmcodec_dev, void return 0; } +int btfmcodec_enqueue_transport(struct btfmcodec_char_device *btfmcodec_dev, + uint8_t transport) +{ + struct sk_buff *skb; + + mutex_lock(&btfmcodec_dev->trans_lock); + skb = alloc_skb(1, GFP_ATOMIC); + if (!skb) { + BTFMCODEC_ERR("failed to allocate memory"); + mutex_unlock(&btfmcodec_dev->trans_lock); + return -ENOMEM; + } + + skb_put_data(skb, &transport, 1); + skb_queue_tail(&btfmcodec_dev->trans_rxq, skb); + mutex_unlock(&btfmcodec_dev->trans_lock); + wake_up_interruptible(&btfmcodec_dev->rsp_wait_q[BTM_PKT_TYPE_BEARER_SWITCH_IND]); + return 0; +} + +int btfmcodec_dequeue_transport(struct btfmcodec_char_device *btfmcodec_dev) +{ + uint8_t transport = 0xFF; + struct sk_buff *skb; + + mutex_lock(&btfmcodec_dev->trans_lock); + skb = skb_dequeue(&btfmcodec_dev->trans_rxq); + if (!skb) { + mutex_unlock(&btfmcodec_dev->trans_lock); + return transport; + } + transport = skb->data[0]; + skb_pull(skb, 1); + kfree_skb(skb); + mutex_unlock(&btfmcodec_dev->trans_lock); + return transport; +} + /* * btfmcodec_pkt_poll() - poll() syscall for the btfmcodec device * file: Pointer to the file structure. @@ -639,6 +671,7 @@ static int __init btfmcodec_init(void) btfmcodec->btfmcodec_dev = btfmcodec_dev; refcount_set(&btfmcodec_dev->active_clients, 1); mutex_init(&btfmcodec_dev->lock); + mutex_init(&btfmcodec_dev->trans_lock); strscpy(btfmcodec_dev->dev_name, "btfmcodec_dev", DEVICE_NAME_MAX_LEN); device_initialize(dev); dev->class = dev_class; @@ -674,6 +707,7 @@ static int __init btfmcodec_init(void) btfmcodec_dev->dev_name, dev_major, btfmcodec_dev->reuse_minor); skb_queue_head_init(&btfmcodec_dev->rxq); + skb_queue_head_init(&btfmcodec_dev->trans_rxq); mutex_init(&btfmcodec_dev->lock); INIT_WORK(&btfmcodec_dev->rx_work, btfmcodec_dev_rxwork); init_waitqueue_head(&btfmcodec_dev->readq); diff --git a/btfmcodec/btfm_codec_btadv_interface.c b/btfmcodec/btfm_codec_btadv_interface.c index 82f16b33e7..33ad06cc89 100644 --- a/btfmcodec/btfm_codec_btadv_interface.c +++ b/btfmcodec/btfm_codec_btadv_interface.c @@ -1,6 +1,6 @@ // SPDX-License-Identifier: GPL-2.0-only /* - * Copyright (c) 2023 Qualcomm Innovation Center, Inc. All rights reserved. + * Copyright (c) 2023-2024 Qualcomm Innovation Center, Inc. All rights reserved. */ #include "btfm_codec.h" @@ -88,6 +88,16 @@ btfmcodec_state btfmcodec_get_current_transport(struct return current_state; } +btfmcodec_state btfmcodec_get_prev_transport(struct btfmcodec_state_machine *state) +{ + btfmcodec_state prev_state; + + mutex_lock(&state->state_machine_lock); + prev_state = state->prev_state; + mutex_unlock(&state->state_machine_lock); + return prev_state; +} + int btfmcodec_frame_transport_switch_ind_pkt(struct btfmcodec_char_device *btfmcodec_dev, uint8_t active_transport, uint8_t status) @@ -124,9 +134,16 @@ int btfmcodec_wait_for_bearer_ind(struct btfmcodec_char_device *btfmcodec_dev) uint8_t *status = &btfmcodec_dev->status[BTM_PKT_TYPE_BEARER_SWITCH_IND]; ret = wait_event_interruptible_timeout(*rsp_wait_q, - *status != BTM_WAITING_RSP, + (*status != BTM_WAITING_RSP || + skb_queue_empty(&btfmcodec_dev->trans_rxq) != true), msecs_to_jiffies(BTM_BEARER_SWITCH_IND_TIMEOUT)); + if (!skb_queue_empty(&btfmcodec_dev->trans_rxq)) { + BTFMCODEC_INFO("%s: new transport is waiting to process", __func__); + ret = -1; + return ret; + } + if (ret == 0) { BTFMCODEC_ERR("failed to recevie BTM_BEARER_SWITCH_IND"); ret = -MSG_INTERNAL_TIMEOUT; @@ -320,7 +337,12 @@ void btfmcodec_wq_prepare_bearer(struct work_struct *work) struct btfmcodec_char_device *btfmcodec_dev = container_of(work, struct btfmcodec_char_device, wq_prepare_bearer); - int idx = BTM_PKT_TYPE_PREPARE_REQ; - BTFMCODEC_INFO("with new transport:%d", btfmcodec_dev->status[idx]); - btfmcodec_prepare_bearer(btfmcodec_dev, btfmcodec_dev->status[idx]); + int transport = btfmcodec_dequeue_transport(btfmcodec_dev); + + BTFMCODEC_INFO("%s new transport:%d", __func__, transport); + + if (transport == 0xFF) + BTFMCODEC_ERR("invalid transport"); + else + btfmcodec_prepare_bearer(btfmcodec_dev, transport); } diff --git a/btfmcodec/btfm_codec_interface.c b/btfmcodec/btfm_codec_interface.c index d88ce7943e..cdb34603d7 100644 --- a/btfmcodec/btfm_codec_interface.c +++ b/btfmcodec/btfm_codec_interface.c @@ -1,6 +1,6 @@ // SPDX-License-Identifier: GPL-2.0-only /* - * Copyright (c) 2023 Qualcomm Innovation Center, Inc. All rights reserved. + * Copyright (c) 2023-2024 Qualcomm Innovation Center, Inc. All rights reserved. */ #include @@ -326,8 +326,21 @@ static void btfmcodec_dai_shutdown(struct snd_pcm_substream *substream, BTFMCODEC_DBG("dai->name: %s, dai->id: %d, dai->rate: %d", dai->name, dai->id, dai->rate); - if (btfmcodec_get_current_transport(state) != IDLE && - btfmcodec_get_current_transport(state) != BT_Connected) { + if (btfmcodec_get_current_transport(state) == BTADV_AUDIO_Connecting && + btfmcodec_get_prev_transport(state) == BT_Connected) { + BTFMCODEC_INFO("%s: closing these ports as graph stopped when CIS is active", + __func__); + btfmcodec_hwep_shutdown(btfmcodec, dai->id, false); + btfmcodec_delete_configs(btfmcodec, dai->id); + if (!btfmcodec_is_valid_cache_avb(btfmcodec)) + btfmcodec_set_current_state(state, IDLE); + return; + } + + if ((btfmcodec_get_current_transport(state) != IDLE && + btfmcodec_get_current_transport(state) != BT_Connected) || + (btfmcodec_get_current_transport(state) == BTADV_AUDIO_Connecting && + btfmcodec_get_prev_transport(state) != BT_Connected)) { BTFMCODEC_WARN("not allowing shutdown as state is:%s", coverttostring(btfmcodec_get_current_transport(state))); /* Delete stored configs */ diff --git a/btfmcodec/include/btfm_codec.h b/btfmcodec/include/btfm_codec.h index 7e1da43457..b15f95fac1 100644 --- a/btfmcodec/include/btfm_codec.h +++ b/btfmcodec/include/btfm_codec.h @@ -1,6 +1,6 @@ // SPDX-License-Identifier: GPL-2.0-only /* - * Copyright (c) 2023 Qualcomm Innovation Center, Inc. All rights reserved. + * Copyright (c) 2023-2024 Qualcomm Innovation Center, Inc. All rights reserved. */ #ifndef __LINUX_BTFM_CODEC_H @@ -73,10 +73,12 @@ struct btfmcodec_char_device { struct cdev cdev; refcount_t active_clients; struct mutex lock; + struct mutex trans_lock; int reuse_minor; char dev_name[DEVICE_NAME_MAX_LEN]; struct workqueue_struct *workqueue; struct sk_buff_head rxq; + struct sk_buff_head trans_rxq; struct work_struct rx_work; struct work_struct wq_hwep_shutdown; struct work_struct wq_prepare_bearer; diff --git a/btfmcodec/include/btfm_codec_btadv_interface.h b/btfmcodec/include/btfm_codec_btadv_interface.h index 7f10b7bb93..64e583ff11 100644 --- a/btfmcodec/include/btfm_codec_btadv_interface.h +++ b/btfmcodec/include/btfm_codec_btadv_interface.h @@ -1,6 +1,6 @@ // SPDX-License-Identifier: GPL-2.0-only /* - * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved. + * Copyright (c) 2022, 2024 Qualcomm Innovation Center, Inc. All rights reserved. */ #ifndef __LINUX_BTFM_CODEC_BTADV_INTERFACE_H @@ -19,4 +19,5 @@ void btfmcodec_wq_prepare_bearer(struct work_struct *); void btfmcodec_wq_hwep_shutdown(struct work_struct *); void btfmcodec_initiate_hwep_shutdown(struct btfmcodec_char_device *btfmcodec_dev); btfmcodec_state btfmcodec_get_current_transport(struct btfmcodec_state_machine *state); +btfmcodec_state btfmcodec_get_prev_transport(struct btfmcodec_state_machine *state); #endif /* __LINUX_BTFM_CODEC_BTADV_INTERFACE_H */ diff --git a/btfmcodec/include/btfm_codec_pkt.h b/btfmcodec/include/btfm_codec_pkt.h index 92110c5928..b514d35a18 100644 --- a/btfmcodec/include/btfm_codec_pkt.h +++ b/btfmcodec/include/btfm_codec_pkt.h @@ -1,6 +1,6 @@ // SPDX-License-Identifier: GPL-2.0-only /* - * Copyright (c) 2023 Qualcomm Innovation Center, Inc. All rights reserved. + * Copyright (c) 2023-2024 Qualcomm Innovation Center, Inc. All rights reserved. */ #ifndef __LINUX_BTFM_CODEC_PKT_H @@ -133,6 +133,8 @@ struct btm_adsp_state_ind { uint32_t action; } __attribute__((packed)); -int btfmcodec_dev_enqueue_pkt(struct btfmcodec_char_device *, void *, int); -bool btfmcodec_is_valid_cache_avb(struct btfmcodec_data *); +int btfmcodec_dev_enqueue_pkt(struct btfmcodec_char_device *btfmcodec_dev, void *buf, int len); +bool btfmcodec_is_valid_cache_avb(struct btfmcodec_data *btfmcodec); +int btfmcodec_enqueue_transport(struct btfmcodec_char_device *btfmcodec_dev, uint8_t transport); +int btfmcodec_dequeue_transport(struct btfmcodec_char_device *btfmcodec_dev); #endif /* __LINUX_BTFM_CODEC_PKT_H*/ From 966e5ef559c29422aa8f9917f6e9e6acd103fef4 Mon Sep 17 00:00:00 2001 From: Balakrishna Godavarthi Date: Wed, 4 Sep 2024 12:54:38 +0530 Subject: [PATCH 122/154] btfmcodec: Don't move state in seamless switch This change will not move btfmcodec state in seamless switch and also wait for indication from host to move further. Change-Id: Ie2ffaede7896ca3bcfca7acd67275d27cb38e2b9 Signed-off-by: Balakrishna Godavarthi --- btfmcodec/btfm_codec_btadv_interface.c | 2 +- btfmcodec/btfm_codec_interface.c | 18 +++++++++++------- 2 files changed, 12 insertions(+), 8 deletions(-) diff --git a/btfmcodec/btfm_codec_btadv_interface.c b/btfmcodec/btfm_codec_btadv_interface.c index 33ad06cc89..624689280f 100644 --- a/btfmcodec/btfm_codec_btadv_interface.c +++ b/btfmcodec/btfm_codec_btadv_interface.c @@ -213,7 +213,7 @@ void btfmcodec_configure_hwep(struct btfmcodec_char_device *btfmcodec_dev) if (status != MSG_SUCCESS) return; - if (ret < 0) { + if (ret == 0) { ret = btfmcodec_wait_for_bearer_ind(btfmcodec_dev); if (ret < 0) { /* Move back to BTADV_AUDIO_Connected for failure cases*/ diff --git a/btfmcodec/btfm_codec_interface.c b/btfmcodec/btfm_codec_interface.c index cdb34603d7..34be89f7b3 100644 --- a/btfmcodec/btfm_codec_interface.c +++ b/btfmcodec/btfm_codec_interface.c @@ -578,7 +578,7 @@ static int btfmcodec_configure_dma(struct btfmcodec_data *btfmcodec, uint8_t id) } int btfmcodec_hwep_prepare(struct btfmcodec_data *btfmcodec, uint32_t sampling_rate, - uint32_t direction, int id) + uint32_t direction, int id, bool seamless) { struct hwep_data *hwep_info = btfmcodec->hwep_info; struct hwep_dai_driver *dai_drv = (struct hwep_dai_driver *) @@ -594,17 +594,21 @@ int btfmcodec_hwep_prepare(struct btfmcodec_data *btfmcodec, uint32_t sampling_r ret = btfmcodec_configure_master(btfmcodec, (uint8_t)id); if (ret < 0) { BTFMCODEC_ERR("failed to configure master error %d", ret); - btfmcodec_set_current_state(state, IDLE); + if (seamless == false) + btfmcodec_set_current_state(state, IDLE); } else { - btfmcodec_set_current_state(state, BT_Connected); + if (seamless == false) + btfmcodec_set_current_state(state, BT_Connected); } } else if (ret == 0 && test_bit(BTADV_CONFIGURE_DMA, &hwep_info->flags)) { ret = btfmcodec_configure_dma(btfmcodec, (uint8_t)id); if (ret < 0) { BTFMCODEC_ERR("failed to configure Codec DMA %d", ret); - btfmcodec_set_current_state(state, IDLE); + if (seamless == false) + btfmcodec_set_current_state(state, IDLE); } else { - btfmcodec_set_current_state(state, BT_Connected); + if (seamless == false) + btfmcodec_set_current_state(state, BT_Connected); } } } else { @@ -682,7 +686,7 @@ static int btfmcodec_dai_prepare(struct snd_pcm_substream *substream, ret = btfmcodec_notify_usecase_start(btfmcodec, BTADV); } } else { - ret = btfmcodec_hwep_prepare(btfmcodec, sampling_rate, direction, id); + ret = btfmcodec_hwep_prepare(btfmcodec, sampling_rate, direction, id, false); /* if (ret >= 0) { btfmcodec_check_and_cache_configs(btfmcodec, sampling_rate, direction, id, *codectype); @@ -791,7 +795,7 @@ void btfmcodec_wq_hwep_configure(struct work_struct *work) if (ret >= 0) ret = btfmcodec_hwep_hw_params(btfmcodec, bit_width, direction, num_channels); if (ret >= 0) - ret = btfmcodec_hwep_prepare(btfmcodec, sample_rate, direction, id); + ret = btfmcodec_hwep_prepare(btfmcodec, sample_rate, direction, id, true); if (ret < 0) { BTFMCODEC_ERR("failed to configure hwep %d", hwep_configs->stream_id); break; From 147ecdaf8856e8b6b688aa3cc2e114e3eec252d6 Mon Sep 17 00:00:00 2001 From: Girish BN Date: Fri, 13 Sep 2024 16:54:24 +0530 Subject: [PATCH 123/154] Update default panic reason upon copy_to_user failed - When failed to copy the panic reason from Bt transport, updating the default reason. Change-Id: I14e326f6e24c23873ec6653523a64f0dfad83631 Signed-off-by: Girish BN --- pwr/btpower.c | 37 +++++++++++++++++++++++++++---------- 1 file changed, 27 insertions(+), 10 deletions(-) diff --git a/pwr/btpower.c b/pwr/btpower.c index 6e036aa40f..5f70eddf8b 100644 --- a/pwr/btpower.c +++ b/pwr/btpower.c @@ -350,6 +350,7 @@ static int bt_major; static int soc_id; static bool probe_finished; static struct fmdOperationStruct fmdStruct; +char *default_crash_reason = "Crash reason not found"; static void bt_power_vote(struct work_struct *work); @@ -2668,6 +2669,31 @@ int perform_fmd_operation(void) return ret; } +int bt_kernel_panic(char *arg) { + int ret = 0; + + pr_info("%s\n", __func__); + + if (copy_from_user(&CrashInfo, (char *)arg, sizeof(CrashInfo))) { + pr_err("%s: failed copy to panic reason from BT-Transport\n", + __func__); + memset(&CrashInfo, 0, sizeof(CrashInfo)); + strlcpy(CrashInfo. PrimaryReason, + default_crash_reason, strlen(default_crash_reason)); + strlcpy(CrashInfo. SecondaryReason, + default_crash_reason, strlen(default_crash_reason)); + ret = -EFAULT; + } + + pr_err("%s: BT kernel panic Primary reason = %s, Secondary reason = %s\n", + __func__, CrashInfo.PrimaryReason, CrashInfo.SecondaryReason); + + panic("%s: BT kernel panic Primary reason = %s, Secondary reason = %s\n", + __func__, CrashInfo.PrimaryReason, CrashInfo.SecondaryReason); + + return ret; +} + #ifdef CONFIG_MSM_BT_OOBS int bt_oobs_handler(enum btpower_obs_param clk_cntrl) { @@ -2819,16 +2845,7 @@ static long bt_ioctl(struct file *file, unsigned int cmd, unsigned long arg) pr_err("%s: BT_CMD_KERNEL_PANIC\n", __func__); - if (copy_from_user(&CrashInfo, (char *)arg, sizeof(CrashInfo))) { - pr_err("%s: copy to user failed\n", __func__); - ret = -EFAULT; - } - - pr_err("%s: BT kernel panic Primary reason = %s, Secondary reason = %s\n", - __func__, CrashInfo.PrimaryReason, CrashInfo.SecondaryReason); - - panic("%s: BT kernel panic Primary reason = %s, Secondary reason = %s\n", - __func__, CrashInfo.PrimaryReason, CrashInfo.SecondaryReason); + ret = bt_kernel_panic((char *)arg); break; case UWB_CMD_KERNEL_PANIC: From da42a740eb1c1f23d31832cf4f8713d5877a7e3a Mon Sep 17 00:00:00 2001 From: Kisan Yadav Date: Wed, 11 Sep 2024 16:07:51 +0530 Subject: [PATCH 124/154] Update audio kernel module in bt module bazel - Audio kernel module compilation in bazel is changed from ddk_submodule to ddk_module and each module is kernel object is generated separately. - Updating swr_dlkm as the dependency from audio kernel modules instead of combined module. Change-Id: I6c47591e762e92b928f40149e70ce3f969b03339 Signed-off-by: Kisan Yadav --- bt_modules.bzl | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/bt_modules.bzl b/bt_modules.bzl index 9947577002..3c35e84d56 100644 --- a/bt_modules.bzl +++ b/bt_modules.bzl @@ -134,8 +134,7 @@ register_bt_modules( ], deps = [ ":%b_btpower", ":%b_btfmcodec", ":btfmcodec_headers", - "//vendor/qcom/opensource/audio-kernel:%b_modules", + "//vendor/qcom/opensource/audio-kernel:%b_swr_dlkm", "//vendor/qcom/opensource/audio-kernel:audio_headers", ], ) - From 23fcbc6c2ac36313d8fec7dfe06c76459929dbc8 Mon Sep 17 00:00:00 2001 From: Puneet Date: Mon, 30 Sep 2024 22:21:00 -0700 Subject: [PATCH 125/154] btpower : Add an ioctl cmd to find ssr state during system initialization This command will be sent by uwb host to inquire current state of ssr to decide if it should proceed with uwb initialization or not. Change-Id: Ie418661cf264e3fe75d8df0bb84fc190e2010cf5 Signed-off-by: Puneet --- include/btpower.h | 1 + pwr/btpower.c | 12 ++++++++++++ 2 files changed, 13 insertions(+) diff --git a/include/btpower.h b/include/btpower.h index 497815e922..4fe870f7eb 100644 --- a/include/btpower.h +++ b/include/btpower.h @@ -717,6 +717,7 @@ int bt_aop_pdc_reconfig(struct platform_pwr_data *pdata); #define UWB_CMD_REGISTRATION 0xbfe3 #define BT_CMD_ACCESS_CTRL 0xbfe4 #define UWB_CMD_ACCESS_CTRL 0xbfe5 +#define UWB_GET_SSR_STATE 0xbfe6 #define BT_CMD_FMD_OPERATION 0xbfb2 #ifdef CONFIG_MSM_BT_OOBS diff --git a/pwr/btpower.c b/pwr/btpower.c index 5f70eddf8b..e99503a8b2 100644 --- a/pwr/btpower.c +++ b/pwr/btpower.c @@ -2735,6 +2735,7 @@ static long bt_ioctl(struct file *file, unsigned int cmd, unsigned long arg) int chipset_version = 0; unsigned long panic_reason = 0; unsigned short primary_reason = 0, sec_reason = 0, source_subsystem = 0; + int current_ssr_state = SUB_STATE_IDLE; if (!pwr_data || !probe_finished) { pr_err("%s: BTPower Probing Pending.Try Again\n", __func__); @@ -2863,6 +2864,17 @@ static long bt_ioctl(struct file *file, unsigned int cmd, unsigned long arg) sec_reason, GetUwbSecondaryCrashReason(sec_reason), source_subsystem, GetSourceSubsystemString(source_subsystem)); break; + case UWB_GET_SSR_STATE: + current_ssr_state = get_sub_state(); + pr_err("%s: UWB_GET_SSR_STATE current_ssr_state:%d\n", __func__, + current_ssr_state); + if (copy_to_user((void __user *)arg, ¤t_ssr_state, + sizeof(current_ssr_state))) { + pr_err("%s: copy to user failed\n", __func__); + ret = -EFAULT; + } + break; + default: return -ENOIOCTLCMD; } From 2e16ff26e2b2505ad703cfd7feaa05945e746275 Mon Sep 17 00:00:00 2001 From: Girish BN Date: Tue, 1 Oct 2024 17:12:20 +0530 Subject: [PATCH 126/154] btpower : Changes to enable FMD for WCN7750 - This changes enables the FMD feature for WCN7750 Change-Id: Ie6e81fa707bb6418b747d80853ad654cf194628d Signed-off-by: Girish BN --- pwr/btpower.c | 60 ++++++++++++++++++++++++++------------------------- 1 file changed, 31 insertions(+), 29 deletions(-) diff --git a/pwr/btpower.c b/pwr/btpower.c index 6e036aa40f..97a6223fe1 100644 --- a/pwr/btpower.c +++ b/pwr/btpower.c @@ -84,8 +84,10 @@ #define UWB_SS (0x02) #define TME_SS (0x03) -#define SOC_VERSION_1_0 0x01 -#define SOC_VERSION_2_0 0x02 +#define INVALID_SOC 0x00 +#define PEACH_SOC_VERSION_1_0 0x01 +#define PEACH_SOC_VERSION_2_0 0x02 +#define OTHER_FMD_SUPPORTED_BT_SOC 0x03 /** * enum btpower_vreg_param: Voltage regulator TCS param @@ -1133,10 +1135,8 @@ gpio_failed: regulator_failed: for (i = 0; i < platform_num_vregs; i++) { platform_vregs = &pwr_data->platform_vregs[i]; - pr_err("%s: FMD MODE regulator %s\n", - __func__, platform_vregs->name); if (get_fmd_mode() && platform_vregs->fmd_mode_set) { - pr_err("%s: FMD Mode Set: Skipping regulator %s\n", + pr_err("%s: FMD MODE: Skip %s regulator vote-off for FMD\n", __func__, platform_vregs->name); continue; } @@ -2599,39 +2599,41 @@ int perform_fmd_operation(void) int ret = 0; switch ((enum FmdOperation) fmdStruct.fmdOperation) { case UPDATE_SOC_VER: { - if (fmdStruct.socFwVer == SOC_VERSION_1_0) { - pr_info("%s: UPDATE_SOC_VER :: SOC_VERSION_1_0\n", + if ((fmdStruct.socFwVer == INVALID_SOC) || + (fmdStruct.socFwVer > OTHER_FMD_SUPPORTED_BT_SOC)) { + pr_err("%s: Invalid SOC VERSION sent = %d\n", + __func__, fmdStruct.socFwVer); + return -EINVAL; + } + pwr_data->is_fmd_mode_enable = true; + if (fmdStruct.socFwVer == PEACH_SOC_VERSION_1_0) { + pr_info("%s: UPDATE_SOC_VER :: PEACH_SOC_VER_1_0\n", __func__); - pwr_data->is_fmd_mode_enable = true; - if (pwr_data->bt_chip_clk) { - ret = bt_clk_enable(pwr_data->bt_chip_clk); - if (ret < 0) { - pr_err("%s: failed to bt_chip_clk\n", __func__); - return -EINVAL; - } - } - } else if (fmdStruct.socFwVer == SOC_VERSION_2_0) { - pr_info("%s: UPDATE_SOC_VER :: SOC_VERSION_2_0\n", + } else if (fmdStruct.socFwVer == PEACH_SOC_VERSION_2_0) { + pr_info("%s: UPDATE_SOC_VER :: PEACH_SOC_VERSION_2_0\n", __func__); - pwr_data->is_fmd_mode_enable = true; #ifdef CONFIG_FMD_ENABLE cnss_utils_fmd_status(true); #endif if (vote_wlan_reg_for_fmd() < 0) { - pr_err("%s: failed to vote_wlan_reg_for_fmd\n", __func__); + pr_err("%s: failed to vote wlan_reg\n", __func__); return -EINVAL; } - if (pwr_data->bt_chip_clk) { - ret = bt_clk_enable(pwr_data->bt_chip_clk); - if (ret < 0) { - pr_err("%s: failed to bt_chip_clk\n", __func__); - return -EINVAL; - } - } } else { - pr_err("%s: Invalid SOC VERSION sent = %d\n", - __func__, fmdStruct.socFwVer); - return -EINVAL; + pr_info("%s: UPDATE_SOC_VER :: OTHER_FMD_SUPPORT_BT_SOC\n", + __func__); + if (vote_wlan_reg_for_fmd() < 0) { + pr_err("%s: failed to vote wlan_reg\n", __func__); + return -EINVAL; + } + } + + if (pwr_data->bt_chip_clk) { + ret = bt_clk_enable(pwr_data->bt_chip_clk); + if (ret < 0) { + pr_err("%s: failed to bt_chip_clk\n", __func__); + return -EINVAL; + } } break; } From 0e7d91e6af0d45ffe54aeec3db4bd82ad124e9e1 Mon Sep 17 00:00:00 2001 From: Balakrishna Godavarthi Date: Mon, 30 Sep 2024 11:36:49 +0530 Subject: [PATCH 127/154] btfmcodec: send usecase start for both src and sink This change sends usecase start request for both src and sink. Change-Id: I28a92733e9f11a8ec1be3d872d8fc95681670af5 Signed-off-by: Balakrishna Godavarthi --- btfmcodec/btfm_codec_interface.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/btfmcodec/btfm_codec_interface.c b/btfmcodec/btfm_codec_interface.c index 34be89f7b3..d23fe9c5df 100644 --- a/btfmcodec/btfm_codec_interface.c +++ b/btfmcodec/btfm_codec_interface.c @@ -682,9 +682,7 @@ static int btfmcodec_dai_prepare(struct snd_pcm_substream *substream, btfmcodec_get_current_transport(state) != BT_Connected) { BTFMCODEC_WARN("cached required info as state is:%s", coverttostring(btfmcodec_get_current_transport(state))); - if (direction == 0) { - ret = btfmcodec_notify_usecase_start(btfmcodec, BTADV); - } + ret = btfmcodec_notify_usecase_start(btfmcodec, BTADV); } else { ret = btfmcodec_hwep_prepare(btfmcodec, sampling_rate, direction, id, false); /* if (ret >= 0) { From de25a4ebea8e05b4f796f54f17611c900dea39a8 Mon Sep 17 00:00:00 2001 From: Satish Kumar Kodishala Date: Mon, 30 Sep 2024 16:24:48 +0530 Subject: [PATCH 128/154] Add null check for SoundWire port information Add null check for SoundWire port information before opening port. CRs-Fixed: 3936468 Change-Id: Ic330983788c38651fc68fda6f7cf142a37cbe6e3 Signed-off-by: Satish Kumar Kodishala --- soundwire/btfm_swr_hw_interface.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/soundwire/btfm_swr_hw_interface.c b/soundwire/btfm_swr_hw_interface.c index e591bf995c..22853ef09d 100644 --- a/soundwire/btfm_swr_hw_interface.c +++ b/soundwire/btfm_swr_hw_interface.c @@ -204,6 +204,11 @@ static int btfm_swr_dai_prepare(void *dai, uint32_t sampling_rate, uint32_t dire bt_soc_enable_status = 0; BTFMSWR_INFO("dai->id: %d, dai->rate: %d direction: %d", id, sampling_rate, direction); + if (btfmswr == NULL || btfmswr->p_dai_port == NULL) { + BTFMSWR_INFO("port open might have called without hw_init\n"); + return -EINVAL; + } + btfm_get_sampling_rate(&sampling_rate); btfmswr->sample_rate = sampling_rate; From 6b380df603fc1a6d57c163a9b4508e37f3d6be19 Mon Sep 17 00:00:00 2001 From: Mingbo Zhang Date: Fri, 11 Oct 2024 17:31:35 +0800 Subject: [PATCH 129/154] btfmcodec: add stream_id to usecase_start_ind Add stream_id to usecase_start_ind so that xpan manager can know the streaming direction. Change-Id: I494b2ebb2b81897fce4a34c4c18959147a155ea3 CRs-Fixed: 3947314 Signed-off-by: Mingbo Zhang --- btfmcodec/btfm_codec.c | 2 +- btfmcodec/btfm_codec_interface.c | 5 +++-- btfmcodec/include/btfm_codec_pkt.h | 4 +++- 3 files changed, 7 insertions(+), 4 deletions(-) diff --git a/btfmcodec/btfm_codec.c b/btfmcodec/btfm_codec.c index 1731eb6cec..7af3573b09 100644 --- a/btfmcodec/btfm_codec.c +++ b/btfmcodec/btfm_codec.c @@ -249,7 +249,7 @@ static void btfmcodec_dev_rxwork(struct work_struct *work) break; case BTM_BTFMCODEC_USECASE_START_RSP: idx = BTM_PKT_TYPE_USECASE_START_RSP; - if (len == BTM_USECASE_START_IND_LEN) { + if (len == BTM_USECASE_START_RSP_LEN) { status = skb->data[0]; if (status == MSG_SUCCESS) btfmcodec_dev->status[idx] = BTM_RSP_RECV; diff --git a/btfmcodec/btfm_codec_interface.c b/btfmcodec/btfm_codec_interface.c index d23fe9c5df..aeaeb899b7 100644 --- a/btfmcodec/btfm_codec_interface.c +++ b/btfmcodec/btfm_codec_interface.c @@ -619,7 +619,7 @@ int btfmcodec_hwep_prepare(struct btfmcodec_data *btfmcodec, uint32_t sampling_r } static int btfmcodec_notify_usecase_start(struct btfmcodec_data *btfmcodec, - uint8_t transport) + uint8_t transport, uint8_t stream_id) { struct btfmcodec_char_device *btfmcodec_dev = btfmcodec->btfmcodec_dev; struct btm_usecase_start_ind ind; @@ -632,6 +632,7 @@ static int btfmcodec_notify_usecase_start(struct btfmcodec_data *btfmcodec, ind.opcode = BTM_BTFMCODEC_USECASE_START_REQ; ind.len = BTM_USECASE_START_IND_LEN; ind.transport = transport; + ind.stream_id = stream_id; ret = btfmcodec_dev_enqueue_pkt(btfmcodec_dev, &ind, (ind.len + BTM_HEADER_LEN)); if (ret < 0) @@ -682,7 +683,7 @@ static int btfmcodec_dai_prepare(struct snd_pcm_substream *substream, btfmcodec_get_current_transport(state) != BT_Connected) { BTFMCODEC_WARN("cached required info as state is:%s", coverttostring(btfmcodec_get_current_transport(state))); - ret = btfmcodec_notify_usecase_start(btfmcodec, BTADV); + ret = btfmcodec_notify_usecase_start(btfmcodec, BTADV, (uint8_t)id); } else { ret = btfmcodec_hwep_prepare(btfmcodec, sampling_rate, direction, id, false); /* if (ret >= 0) { diff --git a/btfmcodec/include/btfm_codec_pkt.h b/btfmcodec/include/btfm_codec_pkt.h index b514d35a18..ced04ac9cf 100644 --- a/btfmcodec/include/btfm_codec_pkt.h +++ b/btfmcodec/include/btfm_codec_pkt.h @@ -63,7 +63,8 @@ struct btm_ctrl_pkt { #define BTM_BTFMCODEC_USECASE_START_REQ 0x58000008 #define BTM_BTFMCODEC_USECASE_START_RSP 0x58000009 -#define BTM_USECASE_START_IND_LEN 1 +#define BTM_USECASE_START_IND_LEN 2 +#define BTM_USECASE_START_RSP_LEN 1 enum rx_status { /* Waiting for response */ @@ -119,6 +120,7 @@ struct btm_usecase_start_ind { btm_opcode opcode; uint32_t len; uint8_t transport; + uint8_t stream_id; } __packed; struct btm_master_shutdown_req { From a25041400e6f065ee6f180aed5c15855dd850c31 Mon Sep 17 00:00:00 2001 From: Hemant Gupta Date: Tue, 15 Oct 2024 10:38:21 +0530 Subject: [PATCH 130/154] canoe: Replace strlcpy() with strscpy() Replace strlcpy() with strscpy() CRs-Fixed: 3948823 Change-Id: Ifa967e3ee0183c39a7b49579bbe52ab847bc8a14 Signed-off-by: Hemant Gupta --- pwr/btpower.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pwr/btpower.c b/pwr/btpower.c index e912e4cd70..48bea8eca6 100644 --- a/pwr/btpower.c +++ b/pwr/btpower.c @@ -2680,9 +2680,9 @@ int bt_kernel_panic(char *arg) { pr_err("%s: failed copy to panic reason from BT-Transport\n", __func__); memset(&CrashInfo, 0, sizeof(CrashInfo)); - strlcpy(CrashInfo. PrimaryReason, + strscpy(CrashInfo. PrimaryReason, default_crash_reason, strlen(default_crash_reason)); - strlcpy(CrashInfo. SecondaryReason, + strscpy(CrashInfo. SecondaryReason, default_crash_reason, strlen(default_crash_reason)); ret = -EFAULT; } From 84c2f84956a7b143bc9d0df377d1e7fd4e9c6d9d Mon Sep 17 00:00:00 2001 From: Satish Kumar Kodishala Date: Sat, 23 Nov 2024 12:05:03 +0530 Subject: [PATCH 131/154] ARM: dts: msm: Add support for WCN7750 SOC id Added support for WCN7750 SOC id. CRs-Fixed: 3982529 Change-Id: Ib86d70f1f962f1d2247c2590d48eee254a9c35ae Signed-off-by: Satish Kumar Kodishala --- soundwire/btfm_swr.c | 5 +++-- soundwire/btfm_swr_slave.h | 5 ++++- 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/soundwire/btfm_swr.c b/soundwire/btfm_swr.c index 332e124607..7ad9065aac 100644 --- a/soundwire/btfm_swr.c +++ b/soundwire/btfm_swr.c @@ -38,13 +38,14 @@ int btfm_get_bt_soc_index(int chipset_ver) switch (chipset_ver) { case QCA_GANGES_SOC_ID_0100: case QCA_GANGES_SOC_ID_0200: + case QCA_ORNE_SOC_ID_0100: return GANGES; case QCA_EVROS_SOC_ID_0100: case QCA_EVROS_SOC_ID_0200: return EVROS; default: - BTFMSWR_ERR("no BT SOC id defined, returning EVROS"); - return EVROS; + BTFMSWR_ERR("no BT SOC id defined, returning GANGES"); + return GANGES; } } diff --git a/soundwire/btfm_swr_slave.h b/soundwire/btfm_swr_slave.h index ab07cdddd4..7c537dfc74 100644 --- a/soundwire/btfm_swr_slave.h +++ b/soundwire/btfm_swr_slave.h @@ -1,6 +1,6 @@ // SPDX-License-Identifier: GPL-2.0-only /* - * Copyright (c) 2023 Qualcomm Innovation Center, Inc. All rights reserved. + * Copyright (c) 2023-2024 Qualcomm Innovation Center, Inc. All rights reserved. */ @@ -33,6 +33,9 @@ enum { QCA_EVROS_SOC_ID_0200 = 0x40200200, }; +enum { + QCA_ORNE_SOC_ID_0100 = 0x40262100, +}; enum { EVROS_EA = 0x0108170220, From 905cf631b41db451ac17f3176d85bc2bf2dffa3b Mon Sep 17 00:00:00 2001 From: Satish Kumar Kodishala Date: Sat, 23 Nov 2024 12:05:03 +0530 Subject: [PATCH 132/154] ARM: dts: msm: Add support for WCN7750 SOC id Added support for WCN7750 SOC id. CRs-Fixed: 3982529 Change-Id: Ib86d70f1f962f1d2247c2590d48eee254a9c35ae Signed-off-by: Satish Kumar Kodishala (cherry picked from commit 84c2f84956a7b143bc9d0df377d1e7fd4e9c6d9d) --- soundwire/btfm_swr.c | 5 +++-- soundwire/btfm_swr_slave.h | 5 ++++- 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/soundwire/btfm_swr.c b/soundwire/btfm_swr.c index 332e124607..7ad9065aac 100644 --- a/soundwire/btfm_swr.c +++ b/soundwire/btfm_swr.c @@ -38,13 +38,14 @@ int btfm_get_bt_soc_index(int chipset_ver) switch (chipset_ver) { case QCA_GANGES_SOC_ID_0100: case QCA_GANGES_SOC_ID_0200: + case QCA_ORNE_SOC_ID_0100: return GANGES; case QCA_EVROS_SOC_ID_0100: case QCA_EVROS_SOC_ID_0200: return EVROS; default: - BTFMSWR_ERR("no BT SOC id defined, returning EVROS"); - return EVROS; + BTFMSWR_ERR("no BT SOC id defined, returning GANGES"); + return GANGES; } } diff --git a/soundwire/btfm_swr_slave.h b/soundwire/btfm_swr_slave.h index ab07cdddd4..7c537dfc74 100644 --- a/soundwire/btfm_swr_slave.h +++ b/soundwire/btfm_swr_slave.h @@ -1,6 +1,6 @@ // SPDX-License-Identifier: GPL-2.0-only /* - * Copyright (c) 2023 Qualcomm Innovation Center, Inc. All rights reserved. + * Copyright (c) 2023-2024 Qualcomm Innovation Center, Inc. All rights reserved. */ @@ -33,6 +33,9 @@ enum { QCA_EVROS_SOC_ID_0200 = 0x40200200, }; +enum { + QCA_ORNE_SOC_ID_0100 = 0x40262100, +}; enum { EVROS_EA = 0x0108170220, From 28ff6907e753c819dd8a85ce88897538b8103184 Mon Sep 17 00:00:00 2001 From: Girish BN Date: Tue, 26 Nov 2024 15:22:46 +0530 Subject: [PATCH 133/154] bt_power: enable FMD feature in wcn7750 - adding the check not pull the GPIO during the FMD mode transition Change-Id: Ia398d505f8b7e43b939e12b90ae33120b6a6800b Signed-off-by: Girish BN --- pwr/btpower.c | 22 ++++++++++------------ 1 file changed, 10 insertions(+), 12 deletions(-) diff --git a/pwr/btpower.c b/pwr/btpower.c index 48bea8eca6..eef1ddd6d1 100644 --- a/pwr/btpower.c +++ b/pwr/btpower.c @@ -949,16 +949,19 @@ static int bt_regulators_pwr(int pwr_state) pr_err("%s: secure hw mode on, not allowed to access gpio", __func__); }else { - bt_configure_gpios(POWER_DISABLE); + if (!get_fmd_mode()) + bt_configure_gpios(POWER_DISABLE); } } gpio_fail: - if (pwr_data->bt_gpio_sys_rst > 0) - gpio_free(pwr_data->bt_gpio_sys_rst); - if (pwr_data->bt_gpio_debug > 0) - gpio_free(pwr_data->bt_gpio_debug); - if (pwr_data->bt_chip_clk) - bt_clk_disable(pwr_data->bt_chip_clk); + if (!get_fmd_mode()) { + if (pwr_data->bt_gpio_sys_rst > 0) + gpio_free(pwr_data->bt_gpio_sys_rst); + if (pwr_data->bt_gpio_debug > 0) + gpio_free(pwr_data->bt_gpio_debug); + if (pwr_data->bt_chip_clk) + bt_clk_disable(pwr_data->bt_chip_clk); + } regulator_fail: for (i = 0; i < bt_num_vregs; i++) { bt_vregs = &pwr_data->bt_vregs[i]; @@ -1655,7 +1658,6 @@ static int bt_power_probe(struct platform_device *pdev) struct device *devi = &pwr_data->pdev->dev; int rc = 0; - pr_info("%s: Get FMD nvmem-cells\n", __func__); /* Get fmd_set NVMEM Cell Handler */ pwr_data->nvmem_cell_fmd_set = @@ -2623,10 +2625,6 @@ int perform_fmd_operation(void) } else { pr_info("%s: UPDATE_SOC_VER :: OTHER_FMD_SUPPORT_BT_SOC\n", __func__); - if (vote_wlan_reg_for_fmd() < 0) { - pr_err("%s: failed to vote wlan_reg\n", __func__); - return -EINVAL; - } } if (pwr_data->bt_chip_clk) { From b3dd35a621cdf2f3f0d152d823489f489aa0dc53 Mon Sep 17 00:00:00 2001 From: Hemant Gupta Date: Mon, 18 Nov 2024 12:03:01 +0530 Subject: [PATCH 134/154] Send Port indication to XM Send Port indication to XM in case of AP -> LE or LE -> AP transitions. CRs-Fixed: 4001359 Change-Id: Ibe9f303e3cd02c0d3880d487a8aec21f93ca8511 Signed-off-by: Hemant Gupta --- btfmcodec/btfm_codec_interface.c | 26 ++++++++++++++++++++++++++ btfmcodec/include/btfm_codec_pkt.h | 14 +++++++++++--- 2 files changed, 37 insertions(+), 3 deletions(-) diff --git a/btfmcodec/btfm_codec_interface.c b/btfmcodec/btfm_codec_interface.c index aeaeb899b7..3b7175671b 100644 --- a/btfmcodec/btfm_codec_interface.c +++ b/btfmcodec/btfm_codec_interface.c @@ -14,6 +14,7 @@ static struct snd_soc_dai_driver *btfmcodec_dai_info; uint32_t bits_per_second; uint8_t num_channels; +static int btfmcodec_port_state_notify(uint8_t port_state); static int btfm_codec_get_mixer_control(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) @@ -326,6 +327,14 @@ static void btfmcodec_dai_shutdown(struct snd_pcm_substream *substream, BTFMCODEC_DBG("dai->name: %s, dai->id: %d, dai->rate: %d", dai->name, dai->id, dai->rate); + if ((btfmcodec_get_current_transport(state) == BTADV_AUDIO_Connecting && + btfmcodec_get_prev_transport(state) == BT_Connected) || + ((btfmcodec_get_current_transport(state) == BT_Connecting && + btfmcodec_get_prev_transport(state) == BTADV_AUDIO_Connected))) { + BTFMCODEC_INFO("%s: Informing port closure to upper layers", __func__); + btfmcodec_port_state_notify(IDLE); + } + if (btfmcodec_get_current_transport(state) == BTADV_AUDIO_Connecting && btfmcodec_get_prev_transport(state) == BT_Connected) { BTFMCODEC_INFO("%s: closing these ports as graph stopped when CIS is active", @@ -851,6 +860,23 @@ static int btfmcodec_adsp_ssr_notify(struct notifier_block *nb, return 0; } +static int btfmcodec_port_state_notify(uint8_t port_state) +{ + struct btm_port_state_ind state_ind; + struct btfmcodec_data *btfmcodec; + struct btfmcodec_char_device *btfmcodec_dev; + + BTFMCODEC_WARN("%s: port state = %d", __func__, port_state); + btfmcodec = btfm_get_btfmcodec(); + btfmcodec_dev = btfmcodec->btfmcodec_dev; + state_ind.opcode = BTM_BTFMCODEC_PORT_STATE_IND; + state_ind.len = BTM_PORT_STATE_IND_LEN; + state_ind.port_state = (uint8_t)port_state; + btfmcodec_dev_enqueue_pkt(btfmcodec_dev, &state_ind, + (state_ind.len + BTM_HEADER_LEN)); + return 0; +} + int btfm_register_codec(struct hwep_data *hwep_info) { struct btfmcodec_data *btfmcodec; diff --git a/btfmcodec/include/btfm_codec_pkt.h b/btfmcodec/include/btfm_codec_pkt.h index ced04ac9cf..d2e3dd52df 100644 --- a/btfmcodec/include/btfm_codec_pkt.h +++ b/btfmcodec/include/btfm_codec_pkt.h @@ -45,6 +45,7 @@ struct btm_ctrl_pkt { #define BTM_BTFMCODEC_TRANSPORT_SWITCH_FAILED_IND 0x58000002 #define BTM_BTFMCODEC_ADSP_STATE_IND 0x58000003 #define BTM_BTFMCODEC_CTRL_LOG_LVL_IND 0x58000004 +#define BTM_BTFMCODEC_PORT_STATE_IND 0x58000005 #define BTM_MASTER_CONFIG_REQ_LEN 13 #define BTM_MASTER_CONFIG_RSP_TIMEOUT 5000 @@ -60,6 +61,7 @@ struct btm_ctrl_pkt { #define BTM_LOG_LVL_IND_LEN 1 #define BTM_ADSP_STATE_IND_LEN 4 #define BTM_CODEC_CONFIG_DMA_REQ_LEN 11 +#define BTM_PORT_STATE_IND_LEN 1 #define BTM_BTFMCODEC_USECASE_START_REQ 0x58000008 #define BTM_BTFMCODEC_USECASE_START_RSP 0x58000009 @@ -101,7 +103,7 @@ struct btm_master_config_req { uint8_t num_channels; uint8_t channel_num; uint8_t codec_id; -}__attribute__((packed)); +} __packed; struct btm_dma_config_req { btm_opcode opcode; @@ -127,13 +129,19 @@ struct btm_master_shutdown_req { btm_opcode opcode; uint32_t len; uint8_t stream_id; -}__attribute__((packed)); +} __packed; struct btm_adsp_state_ind { btm_opcode opcode; uint32_t len; uint32_t action; -} __attribute__((packed)); +} __packed; + +struct btm_port_state_ind { + btm_opcode opcode; + uint32_t len; + uint8_t port_state; +} __packed; int btfmcodec_dev_enqueue_pkt(struct btfmcodec_char_device *btfmcodec_dev, void *buf, int len); bool btfmcodec_is_valid_cache_avb(struct btfmcodec_data *btfmcodec); From 82468f21abeb65a93e95b788f1e385252f773e5a Mon Sep 17 00:00:00 2001 From: Balakrishna Godavarthi Date: Tue, 17 Dec 2024 13:04:47 +0530 Subject: [PATCH 135/154] btfmcodec: align timeout with userspace This change aligns timeouts with userspace. Change-Id: Iff64041965ffceff08a0467db58fa9f9a068aecc Signed-off-by: Balakrishna Godavarthi --- btfmcodec/include/btfm_codec_pkt.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/btfmcodec/include/btfm_codec_pkt.h b/btfmcodec/include/btfm_codec_pkt.h index d2e3dd52df..a962ffd59d 100644 --- a/btfmcodec/include/btfm_codec_pkt.h +++ b/btfmcodec/include/btfm_codec_pkt.h @@ -49,7 +49,7 @@ struct btm_ctrl_pkt { #define BTM_MASTER_CONFIG_REQ_LEN 13 #define BTM_MASTER_CONFIG_RSP_TIMEOUT 5000 -#define BTM_BEARER_SWITCH_IND_TIMEOUT 17000 +#define BTM_BEARER_SWITCH_IND_TIMEOUT 25000 #define BTM_MASTER_DMA_CONFIG_RSP_TIMEOUT 5000 #define BTM_HEADER_LEN 8 #define BTM_PREPARE_AUDIO_BEARER_SWITCH_RSP_LEN 2 From 6ffbed88018ca9df073632fcac8204488a73b484 Mon Sep 17 00:00:00 2001 From: Girish BN Date: Tue, 26 Nov 2024 15:22:46 +0530 Subject: [PATCH 136/154] bt_power: enable FMD feature in wcn7750 - adding the check not pull the GPIO during the FMD mode transition Change-Id: Ia398d505f8b7e43b939e12b90ae33120b6a6800b Signed-off-by: Girish BN (cherry picked from commit 28ff6907e753c819dd8a85ce88897538b8103184) --- pwr/btpower.c | 22 ++++++++++------------ 1 file changed, 10 insertions(+), 12 deletions(-) diff --git a/pwr/btpower.c b/pwr/btpower.c index 48bea8eca6..eef1ddd6d1 100644 --- a/pwr/btpower.c +++ b/pwr/btpower.c @@ -949,16 +949,19 @@ static int bt_regulators_pwr(int pwr_state) pr_err("%s: secure hw mode on, not allowed to access gpio", __func__); }else { - bt_configure_gpios(POWER_DISABLE); + if (!get_fmd_mode()) + bt_configure_gpios(POWER_DISABLE); } } gpio_fail: - if (pwr_data->bt_gpio_sys_rst > 0) - gpio_free(pwr_data->bt_gpio_sys_rst); - if (pwr_data->bt_gpio_debug > 0) - gpio_free(pwr_data->bt_gpio_debug); - if (pwr_data->bt_chip_clk) - bt_clk_disable(pwr_data->bt_chip_clk); + if (!get_fmd_mode()) { + if (pwr_data->bt_gpio_sys_rst > 0) + gpio_free(pwr_data->bt_gpio_sys_rst); + if (pwr_data->bt_gpio_debug > 0) + gpio_free(pwr_data->bt_gpio_debug); + if (pwr_data->bt_chip_clk) + bt_clk_disable(pwr_data->bt_chip_clk); + } regulator_fail: for (i = 0; i < bt_num_vregs; i++) { bt_vregs = &pwr_data->bt_vregs[i]; @@ -1655,7 +1658,6 @@ static int bt_power_probe(struct platform_device *pdev) struct device *devi = &pwr_data->pdev->dev; int rc = 0; - pr_info("%s: Get FMD nvmem-cells\n", __func__); /* Get fmd_set NVMEM Cell Handler */ pwr_data->nvmem_cell_fmd_set = @@ -2623,10 +2625,6 @@ int perform_fmd_operation(void) } else { pr_info("%s: UPDATE_SOC_VER :: OTHER_FMD_SUPPORT_BT_SOC\n", __func__); - if (vote_wlan_reg_for_fmd() < 0) { - pr_err("%s: failed to vote wlan_reg\n", __func__); - return -EINVAL; - } } if (pwr_data->bt_chip_clk) { From a7f9a92469d70621eab70bb4f33359d25eb78a6b Mon Sep 17 00:00:00 2001 From: Satish Kumar Kodishala Date: Fri, 1 Nov 2024 14:47:03 +0530 Subject: [PATCH 137/154] Add support for second BT SoundWire tx, rx ports To be able to support second SCO connection, one more pair of Tx and Rx ports are needed. ACI1 will be used for the second pair of Tx, Rx ports. Made changes to support this with new DAI ids, BTAUDIO_RX2 and BTAUDIO_TX2. CRs-Fixed: 4011136 Change-Id: I303390f7eea24b65e1a5e871dde6cb8f09857261 Signed-off-by: Satish Kumar Kodishala --- soundwire/btfm_swr.h | 3 ++- soundwire/btfm_swr_hw_interface.c | 43 +++++++++++++++++++++++++------ soundwire/btfm_swr_slave.c | 12 ++++++--- 3 files changed, 46 insertions(+), 12 deletions(-) diff --git a/soundwire/btfm_swr.h b/soundwire/btfm_swr.h index ecff8701ee..929b062214 100644 --- a/soundwire/btfm_swr.h +++ b/soundwire/btfm_swr.h @@ -34,7 +34,8 @@ enum { FMAUDIO_TX = 0, BTAUDIO_TX, BTAUDIO_RX, - BTAUDIO_A2DP_SINK_TX, + BTAUDIO_TX2, + BTAUDIO_RX2, BTFM_NUM_CODEC_DAIS }; diff --git a/soundwire/btfm_swr_hw_interface.c b/soundwire/btfm_swr_hw_interface.c index 22853ef09d..9119e3c37c 100644 --- a/soundwire/btfm_swr_hw_interface.c +++ b/soundwire/btfm_swr_hw_interface.c @@ -137,9 +137,12 @@ static void btfm_swr_dai_shutdown(void *dai, int id) case BTAUDIO_RX: port_type = BT_AUDIO_RX1; break; - case BTAUDIO_A2DP_SINK_TX: + case BTAUDIO_TX2: port_type = BT_AUDIO_TX2; break; + case BTAUDIO_RX2: + port_type = BT_AUDIO_RX2; + break; case BTFM_NUM_CODEC_DAIS: default: BTFMSWR_ERR("dai->id is invalid:%d", id); @@ -222,9 +225,12 @@ static int btfm_swr_dai_prepare(void *dai, uint32_t sampling_rate, uint32_t dire case BTAUDIO_RX: port_type = BT_AUDIO_RX1; break; - case BTAUDIO_A2DP_SINK_TX: + case BTAUDIO_TX2: port_type = BT_AUDIO_TX2; break; + case BTAUDIO_RX2: + port_type = BT_AUDIO_RX2; + break; case BTFM_NUM_CODEC_DAIS: default: BTFMSWR_ERR("dai->id is invalid:%d", id); @@ -271,11 +277,12 @@ static int btfm_swr_dai_get_channel_map(void *dai, switch (id) { case FMAUDIO_TX: case BTAUDIO_TX: - case BTAUDIO_A2DP_SINK_TX: + case BTAUDIO_TX2: *tx_num = btfmswr->num_channels; *tx_slot = btfmswr->num_channels == 2 ? TWO_CHANNEL_MASK : ONE_CHANNEL_MASK; break; case BTAUDIO_RX: + case BTAUDIO_RX2: *rx_num = btfmswr->num_channels; *rx_slot = btfmswr->num_channels == 2 ? TWO_CHANNEL_MASK : ONE_CHANNEL_MASK; break; @@ -374,13 +381,14 @@ static struct hwep_dai_driver btfmswr_dai_driver[] = { }, .dai_ops = &btfmswr_hw_dai_ops, }, - { /* Bluetooth A2DP sink: bt -> lpass */ - .dai_name = "btfm_a2dp_sink_swr_tx", - .id = BTAUDIO_A2DP_SINK_TX, + { /* Bluetooth A2DP sink, HFP client: bt -> lpass */ + .dai_name = "btaudio_tx2", + .id = BTAUDIO_TX2, .capture = { - .stream_name = "A2DP sink TX Capture", + .stream_name = "BT Audio SWR Tx2 Capture", /* 8/16/44.1/48/88.2/96/192 Khz */ .rates = SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000 + | SNDRV_PCM_RATE_8000_192000 | SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_88200 | SNDRV_PCM_RATE_96000 | SNDRV_PCM_RATE_192000, @@ -391,7 +399,26 @@ static struct hwep_dai_driver btfmswr_dai_driver[] = { .channels_max = 1, }, .dai_ops = &btfmswr_hw_dai_ops, - } + }, + { /* Bluetooth audio downlink2: lpass -> bt */ + .dai_name = "btaudio_rx2", + .id = BTAUDIO_RX2, + .playback = { + .stream_name = "BT Audio SWR Rx2 Playback", + /* 8/16/44.1/48/88.2/96 Khz */ + .rates = SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000 + | SNDRV_PCM_RATE_8000_192000 + | SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000 + | SNDRV_PCM_RATE_88200 | SNDRV_PCM_RATE_96000 + | SNDRV_PCM_RATE_192000, + .formats = SNDRV_PCM_FMTBIT_S16_LE, /* 16 bits */ + .rate_max = 192000, + .rate_min = 8000, + .channels_min = 1, + .channels_max = 1, + }, + .dai_ops = &btfmswr_hw_dai_ops, + }, }; static struct hwep_comp_drv btfmswr_hw_driver = { diff --git a/soundwire/btfm_swr_slave.c b/soundwire/btfm_swr_slave.c index f5e99bf092..585284256c 100644 --- a/soundwire/btfm_swr_slave.c +++ b/soundwire/btfm_swr_slave.c @@ -1,6 +1,6 @@ // SPDX-License-Identifier: GPL-2.0-only /* - * Copyright (c) 2023 Qualcomm Innovation Center, Inc. All rights reserved. + * Copyright (c) 2023-2024 Qualcomm Innovation Center, Inc. All rights reserved. */ @@ -20,8 +20,11 @@ struct soc_port_mapping slave_port[] = { .port_info[2].dai_id = BTAUDIO_RX, .port_info[2].port = 1, - .port_info[3].dai_id = BTAUDIO_A2DP_SINK_TX, + .port_info[3].dai_id = BTAUDIO_TX2, .port_info[3].port = 4, + + .port_info[4].dai_id = BTAUDIO_RX2, + .port_info[4].port = 2, }, // Ganges @@ -37,8 +40,11 @@ struct soc_port_mapping slave_port[] = { .port_info[2].dai_id = BTAUDIO_RX, .port_info[2].port = 1, - .port_info[3].dai_id = BTAUDIO_A2DP_SINK_TX, + .port_info[3].dai_id = BTAUDIO_TX2, .port_info[3].port = 5, + + .port_info[4].dai_id = BTAUDIO_RX2, + .port_info[4].port = 2, }, }; From b7d69a34e27bda96eeb637785ee9b1a72a33e9cd Mon Sep 17 00:00:00 2001 From: Girish BN Date: Thu, 19 Dec 2024 16:54:15 +0530 Subject: [PATCH 138/154] bt_pwr: Bring regulators out of retention, while transitioning to FMD - After BT on regulator were kept on retention mode this change will bring, required regulator out of retention while transiting to FMD. Change-Id: I6162d0f4b5e806046f1325e359f57770e537255e Signed-off-by: Girish BN --- pwr/btpower.c | 57 ++++++++++++++++++++++++++++++++++----------------- 1 file changed, 38 insertions(+), 19 deletions(-) diff --git a/pwr/btpower.c b/pwr/btpower.c index 48bea8eca6..1d90b717b0 100644 --- a/pwr/btpower.c +++ b/pwr/btpower.c @@ -344,7 +344,6 @@ static const struct of_device_id bt_power_match_table[] = { {}, }; -static int btpower_enable_ipa_vreg(struct platform_pwr_data *pdata); static struct platform_pwr_data *pwr_data; static bool previous; static struct class *bt_class; @@ -354,6 +353,8 @@ static bool probe_finished; static struct fmdOperationStruct fmdStruct; char *default_crash_reason = "Crash reason not found"; +static int btpower_enable_ipa_vreg(struct platform_pwr_data *pdata); +static inline int btpower_get_retenion_mode_state(void); static void bt_power_vote(struct work_struct *work); static struct { @@ -890,6 +891,34 @@ static int bt_configure_gpios(int on) return rc; } +static int handle_pwr_disable_req(int core, int reg_num, int retenion_state, int fmd_state) +{ + struct vreg_data *vregs; + int rc; + + for (int i = 0; i < reg_num; i++) { + if (core == BT_CORE) + vregs = &pwr_data->bt_vregs[i]; + else if (core == UWB_CORE) + vregs = &pwr_data->uwb_vregs[i]; + else if (core == PLATFORM_CORE) + vregs = &pwr_data->platform_vregs[i]; + + if (fmd_state && vregs->fmd_mode_set) { + if (retenion_state != RETENTION_IDLE) { + vreg_disable_retention(vregs); + pr_err("%s: Brought %s reg out-of retention for FMD\n", + __func__, vregs->name); + } + pr_err("%s: Keeping %s reg on power-on state for FMD\n", + __func__, vregs->name); + } else { + rc = vreg_disable(vregs); + } + } + return rc; +} + static int bt_regulators_pwr(int pwr_state) { int i, log_indx, bt_num_vregs, rc = 0; @@ -960,15 +989,10 @@ gpio_fail: if (pwr_data->bt_chip_clk) bt_clk_disable(pwr_data->bt_chip_clk); regulator_fail: - for (i = 0; i < bt_num_vregs; i++) { - bt_vregs = &pwr_data->bt_vregs[i]; - if (get_fmd_mode() && bt_vregs->fmd_mode_set) { - pr_err("%s: FMD Mode Set: Skipping regulator %s\n", - __func__, bt_vregs->name); - continue; - } - rc = vreg_disable(bt_vregs); - } + rc = handle_pwr_disable_req(BT_CORE, + bt_num_vregs, + btpower_get_retenion_mode_state(), + get_fmd_mode()); } else if (pwr_state == POWER_RETENTION) { /* Retention mode */ for (i = 0; i < bt_num_vregs; i++) { @@ -1134,15 +1158,10 @@ gpio_failed: gpio_free(pwr_data->bt_gpio_debug); } regulator_failed: - for (i = 0; i < platform_num_vregs; i++) { - platform_vregs = &pwr_data->platform_vregs[i]; - if (get_fmd_mode() && platform_vregs->fmd_mode_set) { - pr_err("%s: FMD MODE: Skip %s regulator vote-off for FMD\n", - __func__, platform_vregs->name); - continue; - } - rc = vreg_disable(platform_vregs); - } + rc = handle_pwr_disable_req(PLATFORM_CORE, + platform_num_vregs, + btpower_get_retenion_mode_state(), + get_fmd_mode()); break; case POWER_RETENTION: for (i = 0; i < platform_num_vregs; i++) { From e79d1cda878fcd74bd8db0afd2624208ad75618d Mon Sep 17 00:00:00 2001 From: Sai Teja Aluvala Date: Fri, 25 Oct 2024 12:22:39 +0530 Subject: [PATCH 139/154] btpower: Added RESETB functionality Added RESETB signal funtionality for BT Enable. Change-Id: I08b31b6ab12fb6106ff7d7e52726002023846cf4 Signed-off-by: Sai Teja Aluvala --- include/btpower.h | 1 + pwr/btpower.c | 56 ++++++++++++++++++++++++++++++++++++++++++++++- 2 files changed, 56 insertions(+), 1 deletion(-) diff --git a/include/btpower.h b/include/btpower.h index 4fe870f7eb..a4baaabbbc 100644 --- a/include/btpower.h +++ b/include/btpower.h @@ -643,6 +643,7 @@ struct platform_pwr_data { int bt_gpio_fmd_clk_ctrl; /* Bluetooth fmd_clk_ctrl gpio */ int bt_gpio_debug; /* Bluetooth debug gpio */ unsigned int wlan_sw_ctrl_gpio; /* Wlan switch control gpio*/ + int bt_gpio_resetb; /* BT RESETB GPIO */ #ifdef CONFIG_MSM_BT_OOBS int bt_gpio_dev_wake; /* Bluetooth bt_wake */ int bt_gpio_host_wake; /* Bluetooth bt_host_wake */ diff --git a/pwr/btpower.c b/pwr/btpower.c index 649739ab0b..07e3bbdb1e 100644 --- a/pwr/btpower.c +++ b/pwr/btpower.c @@ -77,6 +77,9 @@ #define SIGIO_SSR_ON_UWB 0x00000001 #define SIGIO_UWB_SSR_COMPLETED 0x00000002 +#define RESETB_GPIO_HIGH 0x00000001 +#define RESETB_GPIO_LOW 0x00000000 + #define CRASH_REASON_NOT_FOUND ((char *)"Crash reason not found") #define PERI_SS (0x00) @@ -724,6 +727,34 @@ static int get_fmd_mode(void) return pwr_data->is_fmd_mode_enable; } +static int bt_pull_resetb(int resetb_gpio, int value) +{ + int rc = 0; + + rc = gpio_direction_output(resetb_gpio, value); + if (rc) { + pr_err("%s: Unable to set direction\n", __func__); + return rc; + } + return rc; +} + +static int bt_resetb_operation(int resetb) +{ + int rc = 0; + + /* making resetb to low */ + pr_info("BTON: Turn bt_resetb_gpio to low\n"); + rc = bt_pull_resetb(resetb, RESETB_GPIO_LOW); + if (rc) + return rc; + msleep(20); + /* making resetb to high after delay */ + pr_info("BTON: Turn bt_resetb_gpio to High\n"); + rc = bt_pull_resetb(resetb, RESETB_GPIO_HIGH); + return rc; +} + static int bt_configure_gpios(int on) { int rc = 0; @@ -731,6 +762,7 @@ static int bt_configure_gpios(int on) int wl_reset_gpio = pwr_data->wl_gpio_sys_rst; int bt_sw_ctrl_gpio = pwr_data->bt_gpio_sw_ctrl; int bt_debug_gpio = pwr_data->bt_gpio_debug; + int bt_resetb_gpio = pwr_data->bt_gpio_resetb; int assert_dbg_gpio = 0; if (on) { @@ -740,6 +772,14 @@ static int bt_configure_gpios(int on) __func__, bt_reset_gpio, rc); return rc; } + if (bt_resetb_gpio >= 0) { + rc = gpio_request(bt_resetb_gpio, "bt_resetb_gpio_n"); + if (rc) { + pr_err("%s: unable to request gpio %d (%d)\n", + __func__, bt_resetb_gpio, rc); + return rc; + } + } pr_info("BTON:Turn Bt OFF asserting BT_EN to low\n"); pr_info("bt-reset-gpio(%d) value(%d)\n", bt_reset_gpio, @@ -802,13 +842,18 @@ static int bt_configure_gpios(int on) } power_src.platform_state[BT_RESET_GPIO] = gpio_get_value(bt_reset_gpio); + if (bt_resetb_gpio >= 0) { + pr_err("BTON:Turn resetb High\n"); + bt_pull_resetb(bt_resetb_gpio, RESETB_GPIO_HIGH); + } } pr_info("BTON: WLAN OFF waiting for 100ms delay\n"); pr_info("for AON output to fully discharge\n"); msleep(100); pr_info("BTON: WLAN OFF Asserting BT_EN to high\n"); btpower_set_xo_clk_gpio_state(true); - + if (bt_resetb_gpio >= 0) + bt_resetb_operation(bt_resetb_gpio); rc = gpio_direction_output(bt_reset_gpio, 1); if (rc) { pr_err("%s: Unable to set direction\n", __func__); @@ -990,6 +1035,8 @@ gpio_fail: gpio_free(pwr_data->bt_gpio_debug); if (pwr_data->bt_chip_clk) bt_clk_disable(pwr_data->bt_chip_clk); + if (pwr_data->bt_gpio_resetb > 0) + gpio_free(pwr_data->bt_gpio_resetb); } regulator_fail: rc = handle_pwr_disable_req(BT_CORE, @@ -1438,6 +1485,13 @@ static int get_gpio_dt_pinfo(struct platform_device *pdev) pr_err("%s: wl-reset-gpio not provided in device tree\n", __func__); + pwr_data->bt_gpio_resetb = + of_get_named_gpio(child, + "qcom,wl-resetb-gpio", 0); + if (pwr_data->bt_gpio_resetb < 0) + pr_err("%s: bt_gpio_resetb not provided in device tree\n", + __func__); + pwr_data->bt_gpio_sw_ctrl = of_get_named_gpio(child, "qcom,bt-sw-ctrl-gpio", 0); From 96df4753767a8ff6cc7fd0aa2c6ca5a0ceeb6f1a Mon Sep 17 00:00:00 2001 From: Phaneendra Reddy Date: Thu, 9 Jan 2025 10:15:18 +0530 Subject: [PATCH 140/154] BT SWR: Removed hardcoded value of number of Dai ids While DAIs registration, remove hard coding of values. CRs-Fixed: 4031305 Change-Id: Ib8460f5167cb50aa7e754cb0e0c904bb58ec0aa9 Signed-off-by: Phaneendra Reddy --- soundwire/btfm_swr_hw_interface.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/soundwire/btfm_swr_hw_interface.c b/soundwire/btfm_swr_hw_interface.c index 9119e3c37c..e84f7e6c63 100644 --- a/soundwire/btfm_swr_hw_interface.c +++ b/soundwire/btfm_swr_hw_interface.c @@ -449,7 +449,7 @@ int btfm_swr_register_hw_ep(struct btfmswr *btfm_swr) hwep_info->drv = &btfmswr_hw_driver; hwep_info->dai_drv = btfmswr_dai_driver; hwep_info->num_dai = ARRAY_SIZE(btfmswr_dai_driver); - hwep_info->num_dai = 4; + BTFMSWR_INFO("num_dai is: %lu", ARRAY_SIZE(btfmswr_dai_driver)); hwep_info->num_mixer_ctrl = ARRAY_SIZE(status_controls); hwep_info->mixer_ctrl = status_controls; /* Register to hardware endpoint */ From 9d45e9546a5ba94cba2208b0d909b6e7eceb7e09 Mon Sep 17 00:00:00 2001 From: Satish Kumar Kodishala Date: Tue, 21 Jan 2025 11:17:04 +0530 Subject: [PATCH 141/154] Align DAI ids with CP stream id numbers Align DAI ids values with stream id numbers being used in CP for second BT audio usecase. CRs-Fixed: 4050101 Change-Id: I78b23629f11cb0298770811812d1baa30b31300a Signed-off-by: Satish Kumar Kodishala --- soundwire/btfm_swr.h | 5 ++-- soundwire/btfm_swr_hw_interface.c | 13 +++++++--- soundwire/btfm_swr_slave.c | 42 +++++++++++++++---------------- 3 files changed, 34 insertions(+), 26 deletions(-) diff --git a/soundwire/btfm_swr.h b/soundwire/btfm_swr.h index 929b062214..99de813769 100644 --- a/soundwire/btfm_swr.h +++ b/soundwire/btfm_swr.h @@ -1,6 +1,6 @@ // SPDX-License-Identifier: GPL-2.0-only /* - * Copyright (c) 2023-2024 Qualcomm Innovation Center, Inc. All rights reserved. + * Copyright (c) 2023-2025 Qualcomm Innovation Center, Inc. All rights reserved. */ @@ -34,8 +34,9 @@ enum { FMAUDIO_TX = 0, BTAUDIO_TX, BTAUDIO_RX, - BTAUDIO_TX2, + // align definitions to stream id definitions in CP BTAUDIO_RX2, + BTAUDIO_TX2, BTFM_NUM_CODEC_DAIS }; diff --git a/soundwire/btfm_swr_hw_interface.c b/soundwire/btfm_swr_hw_interface.c index 9119e3c37c..8dd98a24f1 100644 --- a/soundwire/btfm_swr_hw_interface.c +++ b/soundwire/btfm_swr_hw_interface.c @@ -1,6 +1,6 @@ // SPDX-License-Identifier: GPL-2.0-only /* - * Copyright (c) 2023-2024 Qualcomm Innovation Center, Inc. All rights reserved. + * Copyright (c) 2023-2025 Qualcomm Innovation Center, Inc. All rights reserved. */ #include @@ -301,7 +301,7 @@ int btfm_swr_dai_get_configs(void *dai, void *config, uint8_t id) struct btfmswr *btfmswr = dev_get_drvdata(hwep_info->dev); struct hwep_dma_configurations *hwep_config; - BTFMSWR_DBG(""); + BTFMSWR_INFO("DAI id %u", id); hwep_config = (struct hwep_dma_configurations *)config; hwep_config->stream_id = id; @@ -313,7 +313,14 @@ int btfm_swr_dai_get_configs(void *dai, void *config, uint8_t id) hwep_config->active_channel_mask = (btfmswr->num_channels == 2 ? TWO_CHANNEL_MASK : ONE_CHANNEL_MASK); hwep_config->lpaif = LPAIF_AUD; - hwep_config->inf_index = 1; + + if (id == BTAUDIO_RX2 || id == BTAUDIO_TX2) { + BTFMSWR_INFO("using interface index 2 for DAI id %u", id); + hwep_config->inf_index = 2; + } else { + BTFMSWR_INFO("using interface index 1 for DAI id %u", id); + hwep_config->inf_index = 1; + } return 1; } diff --git a/soundwire/btfm_swr_slave.c b/soundwire/btfm_swr_slave.c index 585284256c..b5f5ceee0e 100644 --- a/soundwire/btfm_swr_slave.c +++ b/soundwire/btfm_swr_slave.c @@ -1,6 +1,6 @@ // SPDX-License-Identifier: GPL-2.0-only /* - * Copyright (c) 2023-2024 Qualcomm Innovation Center, Inc. All rights reserved. + * Copyright (c) 2023-2025 Qualcomm Innovation Center, Inc. All rights reserved. */ @@ -11,40 +11,40 @@ struct soc_port_mapping slave_port[] = { // Evros { .ea = EVROS_EA, - .port_info[0].dai_id = FMAUDIO_TX, - .port_info[0].port = 5, + .port_info[FMAUDIO_TX].dai_id = FMAUDIO_TX, + .port_info[FMAUDIO_TX].port = 5, - .port_info[1].dai_id = BTAUDIO_TX, - .port_info[1].port = 3, + .port_info[BTAUDIO_TX].dai_id = BTAUDIO_TX, + .port_info[BTAUDIO_TX].port = 3, - .port_info[2].dai_id = BTAUDIO_RX, - .port_info[2].port = 1, + .port_info[BTAUDIO_RX].dai_id = BTAUDIO_RX, + .port_info[BTAUDIO_RX].port = 1, - .port_info[3].dai_id = BTAUDIO_TX2, - .port_info[3].port = 4, + .port_info[BTAUDIO_RX2].dai_id = BTAUDIO_RX2, + .port_info[BTAUDIO_RX2].port = 2, - .port_info[4].dai_id = BTAUDIO_RX2, - .port_info[4].port = 2, + .port_info[BTAUDIO_TX2].dai_id = BTAUDIO_TX2, + .port_info[BTAUDIO_TX2].port = 4, }, // Ganges { .ea = GANGES_EA, // FM is not supported on Ganges. populate with invalid port number - .port_info[0].dai_id = FMAUDIO_TX, - .port_info[0].port = BTFM_INVALID_PORT, + .port_info[FMAUDIO_TX].dai_id = FMAUDIO_TX, + .port_info[FMAUDIO_TX].port = BTFM_INVALID_PORT, - .port_info[1].dai_id = BTAUDIO_TX, - .port_info[1].port = 4, + .port_info[BTAUDIO_TX].dai_id = BTAUDIO_TX, + .port_info[BTAUDIO_TX].port = 4, - .port_info[2].dai_id = BTAUDIO_RX, - .port_info[2].port = 1, + .port_info[BTAUDIO_RX].dai_id = BTAUDIO_RX, + .port_info[BTAUDIO_RX].port = 1, - .port_info[3].dai_id = BTAUDIO_TX2, - .port_info[3].port = 5, + .port_info[BTAUDIO_RX2].dai_id = BTAUDIO_RX2, + .port_info[BTAUDIO_RX2].port = 2, - .port_info[4].dai_id = BTAUDIO_RX2, - .port_info[4].port = 2, + .port_info[BTAUDIO_TX2].dai_id = BTAUDIO_TX2, + .port_info[BTAUDIO_TX2].port = 5, }, }; From d73dc4e65ca0d07279210b757573dfa4edc5d81d Mon Sep 17 00:00:00 2001 From: Sai Teja Aluvala Date: Fri, 25 Oct 2024 12:36:41 +0530 Subject: [PATCH 142/154] btfmcodec: EVROS FM Change This change don't send codec dma request for fm dai ids. Change-Id: Ie4d884c632e8e09c9fef47993c3218366ccf6fe0 Signed-off-by: Sai Teja Aluvala (cherry picked from commit 264091fe8f969adbd98ece35827c1ecd3a259405) --- btfmcodec/btfm_codec_interface.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/btfmcodec/btfm_codec_interface.c b/btfmcodec/btfm_codec_interface.c index 3b7175671b..fd685529c0 100644 --- a/btfmcodec/btfm_codec_interface.c +++ b/btfmcodec/btfm_codec_interface.c @@ -610,6 +610,9 @@ int btfmcodec_hwep_prepare(struct btfmcodec_data *btfmcodec, uint32_t sampling_r btfmcodec_set_current_state(state, BT_Connected); } } else if (ret == 0 && test_bit(BTADV_CONFIGURE_DMA, &hwep_info->flags)) { + /* Don't send request to cp for fm as it is non cp */ + if (id == 0) + return ret; ret = btfmcodec_configure_dma(btfmcodec, (uint8_t)id); if (ret < 0) { BTFMCODEC_ERR("failed to configure Codec DMA %d", ret); From 2c561ec17a85bf8cdd21bd9742ad08f29fbbc2cd Mon Sep 17 00:00:00 2001 From: Balakrishna Godavarthi Date: Thu, 13 Feb 2025 15:48:14 +0530 Subject: [PATCH 143/154] btfmcodec: Don't clear cache when state is BT_CONNECTING This change will not delete configs from cache if btfmcodec driver state is BT_CONNECTING. CRs-Fixed: 4002118 Change-Id: Ie4859713c015245518eb1957e2fec9f8e76130c5 Signed-off-by: Balakrishna Godavarthi --- btfmcodec/btfm_codec_interface.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/btfmcodec/btfm_codec_interface.c b/btfmcodec/btfm_codec_interface.c index 3b7175671b..4032f43938 100644 --- a/btfmcodec/btfm_codec_interface.c +++ b/btfmcodec/btfm_codec_interface.c @@ -1,6 +1,6 @@ // SPDX-License-Identifier: GPL-2.0-only /* - * Copyright (c) 2023-2024 Qualcomm Innovation Center, Inc. All rights reserved. + * Copyright (c) 2023-2025 Qualcomm Innovation Center, Inc. All rights reserved. */ #include @@ -350,10 +350,10 @@ static void btfmcodec_dai_shutdown(struct snd_pcm_substream *substream, btfmcodec_get_current_transport(state) != BT_Connected) || (btfmcodec_get_current_transport(state) == BTADV_AUDIO_Connecting && btfmcodec_get_prev_transport(state) != BT_Connected)) { - BTFMCODEC_WARN("not allowing shutdown as state is:%s", - coverttostring(btfmcodec_get_current_transport(state))); - /* Delete stored configs */ - btfmcodec_delete_configs(btfmcodec, dai->id); + BTFMCODEC_WARN("Allowing cache retention in current state:%s, prev state: %s", + coverttostring(btfmcodec_get_current_transport(state)), + coverttostring(btfmcodec_get_prev_transport(state))); + return; } else { /* first master shutdown has to done */ btfmcodec_hwep_shutdown(btfmcodec, dai->id, false); From f0fd05d6d7f5694bca95b1533f312a29bc88d347 Mon Sep 17 00:00:00 2001 From: Balakrishna Godavarthi Date: Fri, 28 Feb 2025 15:36:38 +0530 Subject: [PATCH 144/154] btfmcodec: Don't shutdown port if state is IDLE This change will not allow port close if state is IDLE. CRs-Fixed: 4064508 Change-Id: I5ca0f32b192df10199e62f7fa769f0c2a449e1ea Signed-off-by: Balakrishna Godavarthi --- btfmcodec/btfm_codec_btadv_interface.c | 2 +- btfmcodec/btfm_codec_interface.c | 5 +++++ 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/btfmcodec/btfm_codec_btadv_interface.c b/btfmcodec/btfm_codec_btadv_interface.c index 624689280f..4980af4a1e 100644 --- a/btfmcodec/btfm_codec_btadv_interface.c +++ b/btfmcodec/btfm_codec_btadv_interface.c @@ -317,7 +317,7 @@ void btfmcodec_prepare_bearer(struct btfmcodec_char_device *btfmcodec_dev, if (ret < 0) return; - if (btfmcodec_is_valid_cache_avb(btfmcodec)) { + if (current_state != IDLE && btfmcodec_is_valid_cache_avb(btfmcodec)) { BTFMCODEC_INFO("Initiating BT port close..."); btfmcodec_initiate_hwep_shutdown(btfmcodec_dev); } diff --git a/btfmcodec/btfm_codec_interface.c b/btfmcodec/btfm_codec_interface.c index ff5027b099..fd66a5155e 100644 --- a/btfmcodec/btfm_codec_interface.c +++ b/btfmcodec/btfm_codec_interface.c @@ -327,6 +327,11 @@ static void btfmcodec_dai_shutdown(struct snd_pcm_substream *substream, BTFMCODEC_DBG("dai->name: %s, dai->id: %d, dai->rate: %d", dai->name, dai->id, dai->rate); + if (btfmcodec_get_current_transport(state) == IDLE) { + BTFMCODEC_INFO("%s not allowing shutdown as state is IDLE", __func__); + return; + } + if ((btfmcodec_get_current_transport(state) == BTADV_AUDIO_Connecting && btfmcodec_get_prev_transport(state) == BT_Connected) || ((btfmcodec_get_current_transport(state) == BT_Connecting && From f54d828f31d2f8d7f58ef028de9a4e9718933963 Mon Sep 17 00:00:00 2001 From: Girish BN Date: Tue, 25 Feb 2025 15:16:36 +0530 Subject: [PATCH 145/154] bt_pwr: adds pid check before signaling to client - This change adds logic to check client registration, it signals to client only if registered. Change-Id: Ief412b96da3f202b67b76ff33bc4c323e2c77a02 Signed-off-by: Girish BN --- include/btpower.h | 3 +-- pwr/btpower.c | 35 ++++++++++++++++++----------------- 2 files changed, 19 insertions(+), 19 deletions(-) diff --git a/include/btpower.h b/include/btpower.h index a4baaabbbc..028abf4b02 100644 --- a/include/btpower.h +++ b/include/btpower.h @@ -1,7 +1,7 @@ /* SPDX-License-Identifier: GPL-2.0-only */ /* * Copyright (c) 2016-2021, The Linux Foundation. All rights reserved. - * Copyright (c) 2021-2024 Qualcomm Innovation Center, Inc. All rights reserved. + * Copyright (c) 2021-2025 Qualcomm Innovation Center, Inc. All rights reserved. */ #ifndef __LINUX_BLUETOOTH_POWER_H @@ -675,7 +675,6 @@ struct platform_pwr_data { struct file *reffilp_obs; struct task_struct *reftask_obs; #endif - struct task_struct *reftask; struct task_struct *reftask_bt; struct task_struct *reftask_uwb; struct btpower_state_machine btpower_state; diff --git a/pwr/btpower.c b/pwr/btpower.c index 07e3bbdb1e..1dacb8d299 100644 --- a/pwr/btpower.c +++ b/pwr/btpower.c @@ -1,7 +1,7 @@ // SPDX-License-Identifier: GPL-2.0-only /* * Copyright (c) 2016-2021, The Linux Foundation. All rights reserved. - * Copyright (c) 2021-2024 Qualcomm Innovation Center, Inc. All rights reserved. + * Copyright (c) 2021-2025 Qualcomm Innovation Center, Inc. All rights reserved. */ /* @@ -1728,6 +1728,8 @@ static int bt_power_probe(struct platform_device *pdev) return -ENOMEM; pwr_data->pdev = pdev; + pwr_data->reftask_bt = NULL; + pwr_data->reftask_uwb = NULL; struct device *devi = &pwr_data->pdev->dev; int rc = 0; @@ -2044,10 +2046,21 @@ int power_enable (enum SubSystem SubSystemType) void send_signal_to_subsystem(int SubSystemType, int state) { pwr_data->wrkq_signal_state = state; - if (SubSystemType == BLUETOOTH) + if (SubSystemType == BLUETOOTH) { + if (!pwr_data->reftask_bt) { + pr_err("%s: BT client is not register to send signal\n", + __func__); + return; + } queue_work(pwr_data->workq, &pwr_data->bt_wq); - else + } else { + if (!pwr_data->reftask_uwb) { + pr_err("%s: UWB client is not register to send signal\n", + __func__); + return; + } queue_work(pwr_data->workq, &pwr_data->uwb_wq); + } } int power_disable (enum SubSystem SubSystemType) @@ -2144,25 +2157,13 @@ static int client_state_notified(int SubSystemType) if (SubSystemType == BLUETOOTH) { update_sub_state(SSR_ON_BT); - if (get_pwr_state() == ALL_CLIENTS_ON) { - if (!pwr_data->reftask_uwb) { - pr_err("%s: UWB PID is not register to send signal\n", - __func__); - return -1; - } + if (get_pwr_state() == ALL_CLIENTS_ON) send_signal_to_subsystem(UWB, SSR_ON_BT); - } } else { update_sub_state(SSR_ON_UWB); - if (get_pwr_state() == ALL_CLIENTS_ON) { - if (!pwr_data->reftask_bt) { - pr_err("%s: BT PID is not register to send signal\n", - __func__); - return -1; - } + if (get_pwr_state() == ALL_CLIENTS_ON) send_signal_to_subsystem(BLUETOOTH, (SIGIO_NOTIFICATION_SIGNAL|SIGIO_SSR_ON_UWB)); - } } return 0; } From d65cbd17424d5ddd548a228ea5c9d2c3a8625078 Mon Sep 17 00:00:00 2001 From: Balakrishna Godavarthi Date: Mon, 10 Mar 2025 13:57:14 +0530 Subject: [PATCH 146/154] btfmcodec: Don't move revert state if state is IDLE. This change will not revert the state if state is already moved to IDLE. CRs-Fixed: 4085516 Change-Id: I3baff08acaa69f5e6d98ae15f211952dcf53cfb6 Signed-off-by: Balakrishna Godavarthi --- btfmcodec/btfm_codec_btadv_interface.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/btfmcodec/btfm_codec_btadv_interface.c b/btfmcodec/btfm_codec_btadv_interface.c index 4980af4a1e..7dde23b503 100644 --- a/btfmcodec/btfm_codec_btadv_interface.c +++ b/btfmcodec/btfm_codec_btadv_interface.c @@ -305,7 +305,11 @@ void btfmcodec_prepare_bearer(struct btfmcodec_char_device *btfmcodec_dev, ret = btfmcodec_wait_for_bearer_ind(btfmcodec_dev); if (ret < 0) { BTFMCODEC_ERR("moving back to previous state"); - btfmcodec_revert_current_state(state); + if (btfmcodec_get_current_transport(state) == IDLE) { + BTFMCODEC_INFO("state moved to IDLE"); + } else if (current_state == btfmcodec_get_prev_transport(state)) { + btfmcodec_revert_current_state(state); + } if (ret == -MSG_INTERNAL_TIMEOUT) { btfmcodec_frame_transport_switch_ind_pkt( btfmcodec_dev, BTADV, From b0f60271115ad2d868bbe513b9939d97f3e0cf1f Mon Sep 17 00:00:00 2001 From: Balakrishna Godavarthi Date: Wed, 2 Apr 2025 13:49:56 +0530 Subject: [PATCH 147/154] BTPower: Set pinctrl state for WCN_BT_EN GPIO Set pinctrl state for WCN_BT_EN GPIO CRs-Fixed: 4065538 Change-Id: I72ec6863be8d40b40cdeefbb837f0ac652319173 Signed-off-by: Balakrishna Godavarthi --- pwr/btpower.c | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/pwr/btpower.c b/pwr/btpower.c index 1dacb8d299..0834ee04cd 100644 --- a/pwr/btpower.c +++ b/pwr/btpower.c @@ -1468,6 +1468,7 @@ static int get_gpio_dt_pinfo(struct platform_device *pdev) struct pinctrl *pinctrl1; #ifdef CONFIG_FMD_ENABLE struct pinctrl_state *sw_ctrl; + struct pinctrl_state *bt_en; #endif child = pdev->dev.of_node; @@ -1520,6 +1521,15 @@ static int get_gpio_dt_pinfo(struct platform_device *pdev) if (ret) pr_err("Failed to select sw_ctrl state, err = %d\n", ret); } + bt_en = pinctrl_lookup_state(pinctrl1, "bt_en"); + if (IS_ERR_OR_NULL(bt_en)) { + ret = PTR_ERR(bt_en); + pr_err("Failed to get bt_en state, err = %d\n", ret); + } else { + ret = pinctrl_select_state(pinctrl1, bt_en); + if (ret) + pr_err("Failed to select bt_en state, err = %d\n", ret); + } } else { pr_err("%s: pinctrl is null\n", __func__); } From 8252bd7dfe0a3bdde33b69b7dcf0a8e6eb81f2e1 Mon Sep 17 00:00:00 2001 From: Balakrishna Godavarthi Date: Sat, 29 Mar 2025 15:05:06 +0530 Subject: [PATCH 148/154] btfmcodec: Don't wait for response when usecase stopped This change will not wait for codec dma config response when usecase stopped. CRs-Fixed: 4099061 Change-Id: I94047da4266472f7e80e5c11db293105f5af792d Signed-off-by: Balakrishna Godavarthi --- btfmcodec/btfm_codec.c | 16 ++++++++++-- btfmcodec/btfm_codec_interface.c | 29 ++++++++++++++++++--- btfmcodec/include/btfm_codec_hw_interface.h | 3 ++- 3 files changed, 42 insertions(+), 6 deletions(-) diff --git a/btfmcodec/btfm_codec.c b/btfmcodec/btfm_codec.c index 7af3573b09..f0c99fc6c7 100644 --- a/btfmcodec/btfm_codec.c +++ b/btfmcodec/btfm_codec.c @@ -1,6 +1,6 @@ // SPDX-License-Identifier: GPL-2.0-only /* - * Copyright (c) 2023-2024 Qualcomm Innovation Center, Inc. All rights reserved. + * Copyright (c) 2023-2025 Qualcomm Innovation Center, Inc. All rights reserved. */ #include @@ -14,6 +14,7 @@ #include #include "btfm_codec.h" #include "btfm_codec_pkt.h" +#include "btfm_codec_btadv_interface.h" #define dev_to_btfmcodec(_dev) container_of(_dev, struct btfmcodec_data, dev) @@ -143,10 +144,11 @@ static void btfmcodec_dev_rxwork(struct work_struct *work) { struct btfmcodec_char_device *btfmcodec_dev = container_of(work, struct btfmcodec_char_device, rx_work); struct sk_buff *skb; + struct btfmcodec_state_machine *state = &btfmcodec->states; uint32_t len; uint8_t status; int idx; - uint8_t *bearer_switch_ind; + uint8_t *bearer_switch_ind, *dma_rsp; BTFMCODEC_DBG("start"); while ((skb = skb_dequeue(&btfmcodec_dev->rxq))) { @@ -164,6 +166,16 @@ static void btfmcodec_dev_rxwork(struct work_struct *work) &btfmcodec_dev->status[BTM_PKT_TYPE_BEARER_SWITCH_IND]; *bearer_switch_ind = BTM_WAITING_RSP; btfmcodec_enqueue_transport(btfmcodec_dev, skb->data[0]); + if (skb->data[0] == NONE && + btfmcodec_get_current_transport(state) == BT_Connecting && + btfmcodec_get_prev_transport(state) == + BTADV_AUDIO_Connected) { + BTFMCODEC_INFO("KP might be awaiting for codec dma rsp"); + idx = BTM_PKT_TYPE_DMA_CONFIG_RSP; + dma_rsp = &btfmcodec_dev->status[idx]; + *dma_rsp = BTM_FAIL_RESP_RECV; + wake_up_interruptible(&btfmcodec_dev->rsp_wait_q[idx]); + } queue_work(btfmcodec_dev->workqueue, &btfmcodec_dev->wq_prepare_bearer); } else { diff --git a/btfmcodec/btfm_codec_interface.c b/btfmcodec/btfm_codec_interface.c index fd66a5155e..d85d6e7435 100644 --- a/btfmcodec/btfm_codec_interface.c +++ b/btfmcodec/btfm_codec_interface.c @@ -286,6 +286,7 @@ void btfmcodec_wq_hwep_shutdown(struct work_struct *work) list_for_each_entry_safe(hwep_configs, tmp, head, dai_list) { BTFMCODEC_INFO("shuting down dai id:%d", hwep_configs->stream_id); ret = btfmcodec_hwep_shutdown(btfmcodec, hwep_configs->stream_id, true); + hwep_configs->is_port_opened = 0; if (ret < 0) { BTFMCODEC_ERR("failed to shutdown master with id %d", hwep_configs->stream_id); break; @@ -623,6 +624,13 @@ int btfmcodec_hwep_prepare(struct btfmcodec_data *btfmcodec, uint32_t sampling_r BTFMCODEC_ERR("failed to configure Codec DMA %d", ret); if (seamless == false) btfmcodec_set_current_state(state, IDLE); + else { + if (dai_drv && dai_drv->dai_ops && + dai_drv->dai_ops->hwep_shutdown) { + dai_drv->dai_ops->hwep_shutdown((void *)hwep_info, + id); + } + } } else { if (seamless == false) btfmcodec_set_current_state(state, BT_Connected); @@ -813,16 +821,31 @@ void btfmcodec_wq_hwep_configure(struct work_struct *work) if (ret >= 0) ret = btfmcodec_hwep_prepare(btfmcodec, sample_rate, direction, id, true); if (ret < 0) { + hwep_configs->is_port_opened = 1; BTFMCODEC_ERR("failed to configure hwep %d", hwep_configs->stream_id); break; + } else { + hwep_configs->is_port_opened = 1; } } - if (ret < 0) + if (ret < 0) { + list_for_each_entry_safe(hwep_configs, tmp, head, dai_list) { + if (hwep_configs->is_port_opened) { + BTFMCODEC_INFO("shuting down dai id:%d", hwep_configs->stream_id); + ret = btfmcodec_hwep_shutdown(btfmcodec, hwep_configs->stream_id, + true); + hwep_configs->is_port_opened = 0; + if (ret < 0) { + BTFMCODEC_ERR("failed to shutdown master with id %d", + hwep_configs->stream_id); + } + } + } btfmcodec_dev->status[idx] = BTM_FAIL_RESP_RECV; - else + } else { btfmcodec_dev->status[idx] = BTM_RSP_RECV; - + } wake_up_interruptible(&btfmcodec_dev->rsp_wait_q[idx]); } static struct snd_soc_dai_ops btfmcodec_dai_ops = { diff --git a/btfmcodec/include/btfm_codec_hw_interface.h b/btfmcodec/include/btfm_codec_hw_interface.h index 3474a6495b..3963630730 100644 --- a/btfmcodec/include/btfm_codec_hw_interface.h +++ b/btfmcodec/include/btfm_codec_hw_interface.h @@ -1,6 +1,6 @@ // SPDX-License-Identifier: GPL-2.0-only /* - * Copyright (c) 2023 Qualcomm Innovation Center, Inc. All rights reserved. + * Copyright (c) 2023-2025 Qualcomm Innovation Center, Inc. All rights reserved. */ #ifndef __LINUX_BTFM_CODEC_HW_INTERFACE_H @@ -29,6 +29,7 @@ struct hwep_configurations { uint8_t codectype; uint32_t direction; uint8_t num_channels; + uint8_t is_port_opened; struct list_head dai_list; }; From 5a45c82067840b09641c1d29c67ce16843674abb Mon Sep 17 00:00:00 2001 From: Satish Kumar Kodishala Date: Mon, 14 Apr 2025 12:17:33 +0530 Subject: [PATCH 149/154] BT SWR: Add SOC id support for WCN7760 Added new SOC id for WCN7760 in BT SoundWire driver. CRs-Fixed: 4119974 Change-Id: Ic053b890a147225b7191a23047e2be8b688a6d22 Signed-off-by: Satish Kumar Kodishala --- soundwire/btfm_swr.c | 3 ++- soundwire/btfm_swr_slave.h | 6 +++++- 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/soundwire/btfm_swr.c b/soundwire/btfm_swr.c index 7ad9065aac..abeb7c91b7 100644 --- a/soundwire/btfm_swr.c +++ b/soundwire/btfm_swr.c @@ -1,6 +1,6 @@ // SPDX-License-Identifier: GPL-2.0-only /* - * Copyright (c) 2023-2024 Qualcomm Innovation Center, Inc. All rights reserved. + * Copyright (c) 2023-2025 Qualcomm Innovation Center, Inc. All rights reserved. */ @@ -39,6 +39,7 @@ int btfm_get_bt_soc_index(int chipset_ver) case QCA_GANGES_SOC_ID_0100: case QCA_GANGES_SOC_ID_0200: case QCA_ORNE_SOC_ID_0100: + case QCA_COLOGNE_SOC_ID_0100: return GANGES; case QCA_EVROS_SOC_ID_0100: case QCA_EVROS_SOC_ID_0200: diff --git a/soundwire/btfm_swr_slave.h b/soundwire/btfm_swr_slave.h index 7c537dfc74..1405b422ce 100644 --- a/soundwire/btfm_swr_slave.h +++ b/soundwire/btfm_swr_slave.h @@ -1,6 +1,6 @@ // SPDX-License-Identifier: GPL-2.0-only /* - * Copyright (c) 2023-2024 Qualcomm Innovation Center, Inc. All rights reserved. + * Copyright (c) 2023-2025 Qualcomm Innovation Center, Inc. All rights reserved. */ @@ -37,6 +37,10 @@ enum { QCA_ORNE_SOC_ID_0100 = 0x40262100, }; +enum { + QCA_COLOGNE_SOC_ID_0100 = 0x40292100, +}; + enum { EVROS_EA = 0x0108170220, GANGES_EA = 0x0208170220, From cc3be0f56fdea79f1a1403ad8433969483352760 Mon Sep 17 00:00:00 2001 From: Balakrishna Godavarthi Date: Wed, 2 Apr 2025 13:49:56 +0530 Subject: [PATCH 150/154] BTPower: Set pinctrl state for WCN_BT_EN GPIO Set pinctrl state for WCN_BT_EN GPIO CRs-Fixed: 4065538 Change-Id: I72ec6863be8d40b40cdeefbb837f0ac652319173 Signed-off-by: Balakrishna Godavarthi (cherry picked from commit b0f60271115ad2d868bbe513b9939d97f3e0cf1f) --- pwr/btpower.c | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/pwr/btpower.c b/pwr/btpower.c index 1dacb8d299..0834ee04cd 100644 --- a/pwr/btpower.c +++ b/pwr/btpower.c @@ -1468,6 +1468,7 @@ static int get_gpio_dt_pinfo(struct platform_device *pdev) struct pinctrl *pinctrl1; #ifdef CONFIG_FMD_ENABLE struct pinctrl_state *sw_ctrl; + struct pinctrl_state *bt_en; #endif child = pdev->dev.of_node; @@ -1520,6 +1521,15 @@ static int get_gpio_dt_pinfo(struct platform_device *pdev) if (ret) pr_err("Failed to select sw_ctrl state, err = %d\n", ret); } + bt_en = pinctrl_lookup_state(pinctrl1, "bt_en"); + if (IS_ERR_OR_NULL(bt_en)) { + ret = PTR_ERR(bt_en); + pr_err("Failed to get bt_en state, err = %d\n", ret); + } else { + ret = pinctrl_select_state(pinctrl1, bt_en); + if (ret) + pr_err("Failed to select bt_en state, err = %d\n", ret); + } } else { pr_err("%s: pinctrl is null\n", __func__); } From 2e837581ea77669ba169054abf1160c1b773818b Mon Sep 17 00:00:00 2001 From: Balakrishna Godavarthi Date: Fri, 18 Apr 2025 10:19:20 +0530 Subject: [PATCH 151/154] btfmcodec: Don't reset driver state during release Release api will be called when the user space either closes the file descriptor or there is an abrupt close.If there is abrupt close, resetting state is causing mismatch in port numbers. CRs-Fixed: 4103968 Change-Id: Icf04db93740ce33e9de4364b4f8d4bf3c0651429 Signed-off-by: Balakrishna Godavarthi --- btfmcodec/btfm_codec.c | 5 ----- 1 file changed, 5 deletions(-) diff --git a/btfmcodec/btfm_codec.c b/btfmcodec/btfm_codec.c index f0c99fc6c7..0bba3a9bb1 100644 --- a/btfmcodec/btfm_codec.c +++ b/btfmcodec/btfm_codec.c @@ -68,8 +68,6 @@ static int btfmcodec_dev_open(struct inode *inode, struct file *file) struct btfmcodec_data *btfmcodec = (struct btfmcodec_data *)btfmcodec_dev->btfmcodec; unsigned int active_clients = refcount_read(&btfmcodec_dev->active_clients); - btfmcodec->states.current_state = IDLE; /* Just a temp*/ - btfmcodec->states.next_state = IDLE; BTFMCODEC_INFO("for %s by %s:%d active_clients[%d]\n", btfmcodec_dev->dev_name, current->comm, task_pid_nr(current), refcount_read(&btfmcodec_dev->active_clients)); @@ -128,9 +126,6 @@ static int btfmcodec_dev_release(struct inode *inode, struct file *file) if (btfmcodec_dev->wq_prepare_bearer.func) cancel_work_sync(&btfmcodec_dev->wq_prepare_bearer); - btfmcodec->states.current_state = IDLE; - btfmcodec->states.next_state = IDLE; - return 0; } From c1abb66f89c328c8bb1d885771e96b8cb9e9af96 Mon Sep 17 00:00:00 2001 From: Balakrishna Godavarthi Date: Tue, 6 May 2025 10:44:35 +0530 Subject: [PATCH 152/154] btfmcodec: Reset state if BT app closed abruptly This change will reset state machine if BT APP closed abruptly. CRs-Fixed: 4137940 Change-Id: Ib342cc0d88666eaa0888f412c6446bd9a43a13d6 Signed-off-by: Balakrishna Godavarthi --- btfmcodec/btfm_codec.c | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/btfmcodec/btfm_codec.c b/btfmcodec/btfm_codec.c index 0bba3a9bb1..ca34ae83ff 100644 --- a/btfmcodec/btfm_codec.c +++ b/btfmcodec/btfm_codec.c @@ -79,6 +79,19 @@ static int btfmcodec_dev_open(struct inode *inode, struct file *file) /* for now have btfmcodec and later we can think of having it btfmcodec_dev */ file->private_data = btfmcodec; refcount_inc(&btfmcodec_dev->active_clients); + + BTFMCODEC_INFO("current_state %s prev_state %s", + coverttostring(btfmcodec->states.current_state), + coverttostring(btfmcodec->states.prev_state)); + /* Reset state if they are BTADV_AUDIO_CONNECTED or BTADV_AUDIO_CONNECTED + * as these states should be moved to IDLE in previous iteration. + */ + if (btfmcodec->states.current_state == BTADV_AUDIO_Connected || + btfmcodec->states.current_state == BTADV_AUDIO_Connecting) { + btfmcodec->states.current_state = IDLE; + } + + btfmcodec->states.prev_state = IDLE; return 0; } From 99ec1e51652c846a6be8feb79fcb537d1d275a35 Mon Sep 17 00:00:00 2001 From: Satish Kumar Kodishala Date: Tue, 11 Feb 2025 12:27:39 +0530 Subject: [PATCH 153/154] Add support for WCN6450 1.x chipsets Add support for WCN6450 1.x chipsets. CRs-Fixed: 4161507 Change-Id: I1b55f037052febe4219699feb93e239e97e3dcb6 Signed-off-by: Satish Kumar Kodishala --- soundwire/btfm_swr.c | 5 +++++ soundwire/btfm_swr_slave.h | 5 +++++ 2 files changed, 10 insertions(+) diff --git a/soundwire/btfm_swr.c b/soundwire/btfm_swr.c index 7ad9065aac..e1097865fd 100644 --- a/soundwire/btfm_swr.c +++ b/soundwire/btfm_swr.c @@ -41,6 +41,11 @@ int btfm_get_bt_soc_index(int chipset_ver) case QCA_ORNE_SOC_ID_0100: return GANGES; case QCA_EVROS_SOC_ID_0100: + case QCA_EVROS_SOC_ID_0101: + case QCA_EVROS_SOC_ID_0102: + case QCA_EVROS_SOC_ID_0103: + case QCA_EVROS_SOC_ID_0104: + case QCA_EVROS_SOC_ID_0105: case QCA_EVROS_SOC_ID_0200: return EVROS; default: diff --git a/soundwire/btfm_swr_slave.h b/soundwire/btfm_swr_slave.h index 7c537dfc74..ddab749257 100644 --- a/soundwire/btfm_swr_slave.h +++ b/soundwire/btfm_swr_slave.h @@ -30,6 +30,11 @@ enum { enum { QCA_EVROS_SOC_ID_0100 = 0x40200100, + QCA_EVROS_SOC_ID_0101 = 0x40200101, + QCA_EVROS_SOC_ID_0102 = 0x40200102, + QCA_EVROS_SOC_ID_0103 = 0x40200103, + QCA_EVROS_SOC_ID_0104 = 0x40200104, + QCA_EVROS_SOC_ID_0105 = 0x40200105, QCA_EVROS_SOC_ID_0200 = 0x40200200, }; From 89bb4218094d909f866e435c5e4f7497dd6cca01 Mon Sep 17 00:00:00 2001 From: Balakrishna Godavarthi Date: Tue, 13 May 2025 15:23:19 +0530 Subject: [PATCH 154/154] btfmcodec: Don't reset state if failed configure codec dma This change will not reset btfmcodec state if it failed to configure codec dma config request. Change-Id: I859df60517f37e54e3a399c7d0f25ddd1ef88721 Signed-off-by: Balakrishna Godavarthi --- btfmcodec/btfm_codec_interface.c | 13 +++---------- 1 file changed, 3 insertions(+), 10 deletions(-) diff --git a/btfmcodec/btfm_codec_interface.c b/btfmcodec/btfm_codec_interface.c index d85d6e7435..e181172051 100644 --- a/btfmcodec/btfm_codec_interface.c +++ b/btfmcodec/btfm_codec_interface.c @@ -609,8 +609,6 @@ int btfmcodec_hwep_prepare(struct btfmcodec_data *btfmcodec, uint32_t sampling_r ret = btfmcodec_configure_master(btfmcodec, (uint8_t)id); if (ret < 0) { BTFMCODEC_ERR("failed to configure master error %d", ret); - if (seamless == false) - btfmcodec_set_current_state(state, IDLE); } else { if (seamless == false) btfmcodec_set_current_state(state, BT_Connected); @@ -622,14 +620,9 @@ int btfmcodec_hwep_prepare(struct btfmcodec_data *btfmcodec, uint32_t sampling_r ret = btfmcodec_configure_dma(btfmcodec, (uint8_t)id); if (ret < 0) { BTFMCODEC_ERR("failed to configure Codec DMA %d", ret); - if (seamless == false) - btfmcodec_set_current_state(state, IDLE); - else { - if (dai_drv && dai_drv->dai_ops && - dai_drv->dai_ops->hwep_shutdown) { - dai_drv->dai_ops->hwep_shutdown((void *)hwep_info, - id); - } + if (dai_drv && dai_drv->dai_ops && + dai_drv->dai_ops->hwep_shutdown) { + dai_drv->dai_ops->hwep_shutdown((void *)hwep_info, id); } } else { if (seamless == false)