Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 139febc3 authored by qctecmdr's avatar qctecmdr Committed by Gerrit - the friendly Code Review server
Browse files

Merge "Add support for returning power sources status"

parents 66b69d62 e540b89d
Loading
Loading
Loading
Loading
+253 −82
Original line number Diff line number Diff line
@@ -23,6 +23,7 @@
#include <linux/uaccess.h>
#include <linux/btpower.h>
#include <linux/of_device.h>
#include <soc/qcom/cmd-db.h>

#if defined CONFIG_BT_SLIM_QCA6390 || \
	defined CONFIG_BT_SLIM_QCA6490 || \
@@ -31,27 +32,75 @@
#endif
#include <linux/fs.h>

#define PWR_SRC_NOT_AVAILABLE -2
#define DEFAULT_INVALID_VALUE -1
#define PWR_SRC_INIT_STATE_IDX 0

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},
	{NULL, "qcom,bt-vdd-aon",     950000,  950000,  0, false, true},
	{NULL, "qcom,bt-vdd-rfacmn",  950000,  950000,  0, false, true},
	{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,  952000,  0, false, true},
	{NULL, "qcom,bt-vdd-rfa-0p8",  950000,  952000,  0, false, true},
	{NULL, "qcom,bt-vdd-rfa1",     1900000, 1900000, 0, false, true},
	{NULL, "qcom,bt-vdd-rfa2",     1900000, 1900000, 0, false, true},
	{NULL, "qcom,bt-vdd-asd",      2800000, 2800000, 0, false, true},
	{NULL, "qcom,bt-vdd-dig",      950000,  952000,  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},
		{NULL, "qcom,bt-vdd-core", 1304000, 1304000, 0, false, false},
		{NULL, "qcom,bt-vdd-pa",   3000000, 3312000, 0, false, false},
		{NULL, "qcom,bt-vdd-xtal", 1700000, 1900000, 0, false, false},
		{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,
};
@@ -77,7 +126,12 @@ static const struct of_device_id bt_power_match_table[] = {
};

static int bt_power_vreg_set(enum bt_power_modes mode);
static int btpower_get_tcs_table_info(struct platform_device *plat_dev,
			struct bluetooth_power_platform_data *bt_power_pdata);
static int btpower_enable_ipa_vreg(struct platform_device *plat_dev,
			struct bluetooth_power_platform_data *bt_power_pdata);

static int bt_power_src_status[BT_POWER_SRC_SIZE];
static struct bluetooth_power_platform_data *bt_power_pdata;
static struct platform_device *btpdev;
static bool previous;
@@ -260,14 +314,18 @@ 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] =
			gpio_get_value(bt_reset_gpio);
		msleep(50);
		pr_debug("BTON:Turn Bt Off bt-reset-gpio(%d) value(%d)\n",
		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_debug("BTON:Turn Bt Off\n");
			pr_debug("bt-sw-ctrl-gpio(%d) value(%d)\n",
			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,
				gpio_get_value(bt_sw_ctrl_gpio));
				bt_power_src_status[BT_SW_CTRL_GPIO]);
		}

		rc = gpio_direction_output(bt_reset_gpio, 1);
@@ -275,6 +333,8 @@ 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] =
			gpio_get_value(bt_reset_gpio);
		msleep(50);
		/*  Check  if  SW_CTRL  is  asserted  */
		if  (bt_sw_ctrl_gpio  >=  0)  {
@@ -302,24 +362,26 @@ 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_debug("BTON:Turn Bt On\n");
			pr_debug("bt-sw-ctrl-gpio(%d) value(%d)\n",
			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,
				gpio_get_value(bt_sw_ctrl_gpio));
				bt_power_src_status[BT_SW_CTRL_GPIO]);
		}
	} else {
		gpio_set_value(bt_reset_gpio, 0);
		msleep(100);
		pr_debug("BT-OFF:bt-reset-gpio(%d) value(%d)\n",
		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_debug("BT-OFF:bt-sw-ctrl-gpio(%d) value(%d)\n",
			pr_info("BT-OFF:bt-sw-ctrl-gpio(%d) value(%d)\n",
				bt_sw_ctrl_gpio,
				gpio_get_value(bt_sw_ctrl_gpio));
		}
	}

	pr_debug("%s: bt_gpio= %d on: %d\n", __func__, bt_reset_gpio, on);
	pr_info("%s: bt_gpio= %d on: %d\n", __func__, bt_reset_gpio, on);

	return rc;
}
@@ -349,6 +411,10 @@ static int bluetooth_power(int on)
			}
		}
		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",
@@ -580,16 +646,25 @@ static int bt_power_vreg_get(struct platform_device *pdev)
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) {
@@ -672,9 +747,17 @@ static int bt_power_populate_dt_pinfo(struct platform_device *pdev)
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)
@@ -708,6 +791,8 @@ static int bt_power_probe(struct platform_device *pdev)
		goto free_pdata;

	btpdev = pdev;
	if (btpower_get_tcs_table_info(pdev, bt_power_pdata) < 0)
		pr_err("%s: Failed to get TCS table info\n", __func__);

	return 0;

@@ -747,46 +832,50 @@ int btpower_get_chipset_version(void)
}
EXPORT_SYMBOL(btpower_get_chipset_version);

static long get_resource_value(char *res_name)
static void  set_pwr_srcs_status(struct bt_power_vreg_data *handle)
{
	int ret = 0;
	int i = 0;
	long value = -1;
	struct bt_power_vreg_data *vreg;
	int num_vregs = bt_power_pdata->num_vregs;

	for (; i < num_vregs; i++) {
		vreg = &bt_power_pdata->vreg_info[i];

		if (!vreg->reg)
			continue;
		else {
			if (strnstr(vreg->name, res_name,
					strlen(vreg->name)))
				break;
		}
	}
	if (i < num_vregs) {
		if (regulator_is_enabled(vreg->reg)) {
			value = (int)regulator_get_voltage(vreg->reg);
			pr_debug("%s:%s value(%d)\n",
				__func__, res_name, value);
			ret = value;
	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 not configure/enabled\n",
				__func__, res_name);
			ret = -EINVAL;
			pr_err("%s:%s is_enabled: %d\n",
				__func__, handle->name,
				handle->is_enabled);
		}
	}
}

	return ret;
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;
	long value = -1;
	int itr, num_vregs;
	struct bt_power_vreg_data *vreg_info = NULL;

	switch (cmd) {
	case BT_CMD_SLIM_TEST:
@@ -834,43 +923,53 @@ static long bt_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
			ret = -EFAULT;
		}
		break;
	case BT_CMD_GETVAL_RESET_GPIO:
		if (bt_power_pdata->bt_gpio_sys_rst > 0) {
			value = (long)gpio_get_value(
				bt_power_pdata->bt_gpio_sys_rst);
			pr_debug("%s:GET_RESET_GPIO(%d) value(%d)\n",
				bt_power_pdata->bt_gpio_sys_rst,
				__func__, value);
			ret = value;
		} else {
			pr_err("%s: RESET_GPIO not configured\n", __func__);
			ret = -EINVAL;
		}
		break;
	case BT_CMD_GETVAL_SW_CTRL_GPIO:
	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) {
			value = (long)gpio_get_value(
			bt_power_src_status[BT_SW_CTRL_GPIO] =
				DEFAULT_INVALID_VALUE;
			ret  =  gpio_direction_input(
				bt_power_pdata->bt_gpio_sw_ctrl);
			pr_debug("%s:GET_SWCTRL_GPIO(%d) value(%d)\n",
			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,
					__func__, value);
			ret = value;
					bt_power_src_status[BT_SW_CTRL_GPIO]);
			}
		} else {
			pr_err("%s:SW_CTRL_GPIO not configured\n", __func__);
			ret = -EINVAL;
			pr_err("bt_gpio_sw_ctrl not configured\n");
			return -EINVAL;
		}
		break;
	case BT_CMD_GETVAL_VDD_AON_LDO:
		ret = get_resource_value("vdd-aon");
		break;
	case BT_CMD_GETVAL_VDD_DIG_LDO:
		ret = get_resource_value("vdd-dig");
		break;
	case BT_CMD_GETVAL_VDD_RFA1_LDO:
		ret = get_resource_value("vdd-rfa1");
	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_GETVAL_VDD_RFA2_LDO:
		ret = get_resource_value("vdd-rfa2");
	case BT_CMD_SET_IPA_TCS_INFO:
		pr_err("%s: BT_CMD_SET_IPA_TCS_INFO\n", __func__);
		btpower_enable_ipa_vreg(btpdev, bt_power_pdata);
		break;
	default:
		return -ENOIOCTLCMD;
@@ -935,6 +1034,78 @@ static int __init bluetooth_power_init(void)
	return ret;
}

static int btpower_get_tcs_table_info(struct platform_device *dev,
			struct bluetooth_power_platform_data *bt_power_pdata)
{
	struct platform_device *plat_dev = dev;
	struct btpower_tcs_table_info *tcs_table_info =
			&bt_power_pdata->tcs_table_info;
	struct resource *res;
	resource_size_t addr_len;
	void __iomem *tcs_cmd_base_addr;
	int ret = -1;

	res = platform_get_resource_byname(plat_dev, IORESOURCE_MEM, "tcs_cmd");
	if (!res) {
		pr_err("No TCS CMD entry found in DTSI\n");
		goto out;
	}

	tcs_table_info->tcs_cmd_base_addr = res->start;
	addr_len = resource_size(res);
	pr_info("TCS CMD base address is %pa with length %pa\n",
		    &tcs_table_info->tcs_cmd_base_addr, &addr_len);

	tcs_cmd_base_addr = devm_ioremap_resource(&plat_dev->dev, res);
	if (IS_ERR(tcs_cmd_base_addr)) {
		ret = PTR_ERR(tcs_cmd_base_addr);
		pr_err("Failed to map TCS CMD address, err = %d\n",
			    ret);
		goto out;
	}

	tcs_table_info->tcs_cmd_base_addr_io = tcs_cmd_base_addr;

	return 0;

out:
	return ret;
}

static int btpower_enable_ipa_vreg(struct platform_device *dev,
			struct bluetooth_power_platform_data *bt_power_pdata)
{
	struct platform_device *plat_dev = dev;
	struct btpower_tcs_table_info *tcs_table_info =
					&bt_power_pdata->tcs_table_info;
	u32 offset, addr_val, data_val;
	void __iomem *tcs_cmd;
	int ret = 0;

	if (!tcs_table_info->tcs_cmd_base_addr_io) {
		pr_err("TCS command not configured\n");
		return -EINVAL;
	}

	ret = of_property_read_u32(plat_dev->dev.of_node,
					"qcom,tcs_offset_ipa",
					&offset);
	if (ret) {
		pr_err("iPA failed to configure\n");
		return -EINVAL;
	}
	tcs_cmd = tcs_table_info->tcs_cmd_base_addr_io + offset;
	addr_val = readl_relaxed(tcs_cmd);
	tcs_cmd += TCS_CMD_IO_ADDR_OFFSET;

	writel_relaxed(1, tcs_cmd);

	data_val = readl_relaxed(tcs_cmd);
	pr_info("Configure S3E TCS Addr : %x with Data: %d\n"
		, addr_val, data_val);
	return 0;
}

static void __exit bluetooth_power_exit(void)
{
	platform_driver_unregister(&bt_power_driver);
+21 −7
Original line number Diff line number Diff line
@@ -18,6 +18,11 @@ enum bt_power_modes {
	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 */
@@ -26,6 +31,7 @@ struct bt_power_vreg_data {
	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 {
@@ -40,6 +46,10 @@ struct bt_power_clk_data {
	bool is_enabled;  /* is this clock enabled? */
};

struct btpower_tcs_table_info {
	resource_size_t tcs_cmd_base_addr;
	void __iomem *tcs_cmd_base_addr_io;
};
/*
 * Platform data for the bluetooth power driver.
 */
@@ -53,6 +63,7 @@ struct bluetooth_power_platform_data {
	int (*bt_power_setup)(int id); /* Bluetooth power setup function */
	char compatible[32]; /*Bluetooth SoC name */
	int num_vregs;
	struct btpower_tcs_table_info tcs_table_info;
};

int btpower_register_slimdev(struct device *dev);
@@ -62,10 +73,13 @@ int btpower_get_chipset_version(void);
#define BT_CMD_PWR_CTRL			0xbfad
#define BT_CMD_CHIPSET_VERS		0xbfae
#define BT_CMD_GET_CHIPSET_ID	0xbfaf
#define BT_CMD_GETVAL_RESET_GPIO    0xbfb5
#define BT_CMD_GETVAL_SW_CTRL_GPIO  0xbfb0
#define BT_CMD_GETVAL_VDD_AON_LDO   0xbfb1
#define BT_CMD_GETVAL_VDD_DIG_LDO   0xbfb2
#define BT_CMD_GETVAL_VDD_RFA1_LDO  0xbfb3
#define BT_CMD_GETVAL_VDD_RFA2_LDO  0xbfb4
#define BT_CMD_CHECK_SW_CTRL	0xbfb0
#define BT_CMD_GETVAL_POWER_SRCS	0xbfb1
#define BT_CMD_SET_IPA_TCS_INFO  0xbfc0

#define TCS_CMD_IO_ADDR_OFFSET 0x4

/* total number of power src */
#define BT_POWER_SRC_SIZE           28

#endif /* __LINUX_BLUETOOTH_POWER_H */