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

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

Merge "cnss2: Add sysfs entry for system shutdown"

parents 7b22bf9c 223d2092
Loading
Loading
Loading
Loading
+76 −2
Original line number Diff line number Diff line
// SPDX-License-Identifier: GPL-2.0-only
/* Copyright (c) 2016-2019, The Linux Foundation. All rights reserved. */
/* Copyright (c) 2016-2020, The Linux Foundation. All rights reserved. */

#include <linux/delay.h>
#include <linux/jiffies.h>
@@ -679,6 +679,13 @@ int cnss_idle_restart(struct device *dev)
	timeout = cnss_get_boot_timeout(dev);

	reinit_completion(&plat_priv->power_up_complete);

	if (test_bit(CNSS_IN_REBOOT, &plat_priv->driver_state)) {
		cnss_pr_dbg("Reboot or shutdown is in progress, ignore idle restart\n");
		ret = -EINVAL;
		goto out;
	}

	ret = wait_for_completion_timeout(&plat_priv->power_up_complete,
					  msecs_to_jiffies(timeout) << 2);
	if (!ret) {
@@ -1949,6 +1956,23 @@ static void cnss_unregister_bus_scale(struct cnss_plat_data *plat_priv)
		msm_bus_scale_unregister_client(bus_bw_info->bus_client);
}

static ssize_t shutdown_store(struct kobject *kobj,
			      struct kobj_attribute *attr,
			      const char *buf, size_t count)
{
	struct cnss_plat_data *plat_priv = cnss_get_plat_priv(NULL);

	if (plat_priv) {
		set_bit(CNSS_IN_REBOOT, &plat_priv->driver_state);
		del_timer(&plat_priv->fw_boot_timer);
		complete_all(&plat_priv->power_up_complete);
	}

	cnss_pr_dbg("Received shutdown notification\n");

	return count;
}

static ssize_t fs_ready_store(struct device *dev,
			      struct device_attribute *attr,
			      const char *buf, size_t count)
@@ -1992,18 +2016,55 @@ static ssize_t fs_ready_store(struct device *dev,
	return count;
}

static struct kobj_attribute shutdown_attribute = __ATTR_WO(shutdown);
static DEVICE_ATTR_WO(fs_ready);

static int cnss_create_shutdown_sysfs(struct cnss_plat_data *plat_priv)
{
	int ret = 0;

	plat_priv->shutdown_kobj = kobject_create_and_add("shutdown_wlan",
							  kernel_kobj);
	if (!plat_priv->shutdown_kobj) {
		cnss_pr_err("Failed to create shutdown_wlan kernel object\n");
		return -ENOMEM;
	}

	ret = sysfs_create_file(plat_priv->shutdown_kobj,
				&shutdown_attribute.attr);
	if (ret) {
		cnss_pr_err("Failed to create sysfs shutdown file, err = %d\n",
			    ret);
		kobject_put(plat_priv->shutdown_kobj);
		plat_priv->shutdown_kobj = NULL;
	}

	return ret;
}

static void cnss_remove_shutdown_sysfs(struct cnss_plat_data *plat_priv)
{
	if (plat_priv->shutdown_kobj) {
		sysfs_remove_file(plat_priv->shutdown_kobj,
				  &shutdown_attribute.attr);
		kobject_put(plat_priv->shutdown_kobj);
		plat_priv->shutdown_kobj = NULL;
	}
}

static int cnss_create_sysfs(struct cnss_plat_data *plat_priv)
{
	int ret = 0;

	ret = device_create_file(&plat_priv->plat_dev->dev, &dev_attr_fs_ready);
	if (ret) {
		cnss_pr_err("Failed to create device file, err = %d\n", ret);
		cnss_pr_err("Failed to create device fs_ready file, err = %d\n",
			    ret);
		goto out;
	}

	cnss_create_shutdown_sysfs(plat_priv);

	return 0;
out:
	return ret;
@@ -2011,6 +2072,7 @@ static int cnss_create_sysfs(struct cnss_plat_data *plat_priv)

static void cnss_remove_sysfs(struct cnss_plat_data *plat_priv)
{
	cnss_remove_shutdown_sysfs(plat_priv);
	device_remove_file(&plat_priv->plat_dev->dev, &dev_attr_fs_ready);
}

@@ -2105,6 +2167,17 @@ static void cnss_init_control_params(struct cnss_plat_data *plat_priv)
	plat_priv->ctrl_params.time_sync_period = CNSS_TIME_SYNC_PERIOD_DEFAULT;
}

static void cnss_get_wlaon_pwr_ctrl_info(struct cnss_plat_data *plat_priv)
{
	struct device *dev = &plat_priv->plat_dev->dev;

	plat_priv->set_wlaon_pwr_ctrl =
		of_property_read_bool(dev->of_node, "qcom,set-wlaon-pwr-ctrl");

	cnss_pr_dbg("set_wlaon_pwr_ctrl is %d\n",
		    plat_priv->set_wlaon_pwr_ctrl);
}

static const struct platform_device_id cnss_platform_id_table[] = {
	{ .name = "qca6174", .driver_data = QCA6174_DEVICE_ID, },
	{ .name = "qca6290", .driver_data = QCA6290_DEVICE_ID, },
@@ -2175,6 +2248,7 @@ static int cnss_probe(struct platform_device *plat_dev)
	INIT_LIST_HEAD(&plat_priv->vreg_list);
	INIT_LIST_HEAD(&plat_priv->clk_list);

	cnss_get_wlaon_pwr_ctrl_info(plat_priv);
	cnss_get_cpr_info(plat_priv);
	cnss_init_control_params(plat_priv);

+3 −1
Original line number Diff line number Diff line
/* SPDX-License-Identifier: GPL-2.0-only */
/* Copyright (c) 2016-2019, The Linux Foundation. All rights reserved. */
/* Copyright (c) 2016-2020, The Linux Foundation. All rights reserved. */

#ifndef _CNSS_MAIN_H
#define _CNSS_MAIN_H
@@ -362,6 +362,8 @@ struct cnss_plat_data {
	void *get_info_cb_ctx;
	int (*get_info_cb)(void *ctx, void *event, int event_len);
	u8 use_nv_mac;
	u8 set_wlaon_pwr_ctrl;
	struct kobject *shutdown_kobj;
};

#ifdef CONFIG_ARCH_QCOM
+69 −2
Original line number Diff line number Diff line
@@ -62,6 +62,9 @@ static DEFINE_SPINLOCK(time_sync_lock);
#define MHI_TIMEOUT_OVERWRITE_MS	(plat_priv->ctrl_params.mhi_timeout)
#define MHI_M2_TIMEOUT_MS		(plat_priv->ctrl_params.mhi_m2_timeout)

#define WLAON_PWR_CTRL_SHUTDOWN_DELAY_MIN_US	1000
#define WLAON_PWR_CTRL_SHUTDOWN_DELAY_MAX_US	2000

#define FORCE_WAKE_DELAY_MIN_US			4000
#define FORCE_WAKE_DELAY_MAX_US			6000
#define FORCE_WAKE_DELAY_TIMEOUT_US		60000
@@ -465,6 +468,7 @@ static int cnss_pci_force_wake_get(struct cnss_pci_data *pci_priv)

	if (cnss_pci_is_device_awake(dev) != true) {
		cnss_pr_err("Timed out to request force wake\n");
		cnss_pci_force_wake_release(dev);
		return -ETIMEDOUT;
	}

@@ -1078,6 +1082,62 @@ static void cnss_pci_deinit_mhi(struct cnss_pci_data *pci_priv)
	cnss_pci_set_mhi_state(pci_priv, CNSS_MHI_DEINIT);
}

static void cnss_pci_set_wlaon_pwr_ctrl(struct cnss_pci_data *pci_priv,
					bool set_vddd4blow, bool set_shutdown,
					bool do_force_wake)
{
	struct cnss_plat_data *plat_priv = pci_priv->plat_priv;
	int ret;
	u32 val;

	if (!plat_priv->set_wlaon_pwr_ctrl)
		return;

	if (do_force_wake)
		if (cnss_pci_force_wake_get(pci_priv))
			return;

	ret = cnss_pci_reg_read(pci_priv, QCA6390_WLAON_QFPROM_PWR_CTRL_REG,
				&val);
	if (ret) {
		cnss_pr_err("Failed to read register offset 0x%x, err = %d\n",
			    QCA6390_WLAON_QFPROM_PWR_CTRL_REG, ret);
		goto force_wake_put;
	}

	cnss_pr_dbg("Read register offset 0x%x, val = 0x%x\n",
		    QCA6390_WLAON_QFPROM_PWR_CTRL_REG, val);

	if (set_vddd4blow)
		val |= QFPROM_PWR_CTRL_VDD4BLOW_SW_EN_MASK;
	else
		val &= ~QFPROM_PWR_CTRL_VDD4BLOW_SW_EN_MASK;

	if (set_shutdown)
		val |= QFPROM_PWR_CTRL_SHUTDOWN_EN_MASK;
	else
		val &= ~QFPROM_PWR_CTRL_SHUTDOWN_EN_MASK;

	ret = cnss_pci_reg_write(pci_priv, QCA6390_WLAON_QFPROM_PWR_CTRL_REG,
				 val);
	if (ret) {
		cnss_pr_err("Failed to write register offset 0x%x, err = %d\n",
			    QCA6390_WLAON_QFPROM_PWR_CTRL_REG, ret);
		goto force_wake_put;
	}

	cnss_pr_dbg("Write val 0x%x to register offset 0x%x\n", val,
		    QCA6390_WLAON_QFPROM_PWR_CTRL_REG);

	if (set_shutdown)
		usleep_range(WLAON_PWR_CTRL_SHUTDOWN_DELAY_MIN_US,
			     WLAON_PWR_CTRL_SHUTDOWN_DELAY_MAX_US);

force_wake_put:
	if (do_force_wake)
		cnss_pci_force_wake_put(pci_priv);
}

static int cnss_pci_get_device_timestamp(struct cnss_pci_data *pci_priv,
					 u64 *time_us)
{
@@ -1618,6 +1678,7 @@ static int cnss_qca6290_powerup(struct cnss_pci_data *pci_priv)
		goto power_off;
	}

	cnss_pci_set_wlaon_pwr_ctrl(pci_priv, false, false, false);
	timeout = cnss_get_boot_timeout(&pci_priv->pci_dev->dev);

	ret = cnss_pci_start_mhi(pci_priv);
@@ -1652,6 +1713,7 @@ static int cnss_qca6290_powerup(struct cnss_pci_data *pci_priv)
	return 0;

stop_mhi:
	cnss_pci_set_wlaon_pwr_ctrl(pci_priv, false, true, true);
	cnss_pci_power_off_mhi(pci_priv);
	cnss_suspend_pci_link(pci_priv);
	cnss_pci_deinit_mhi(pci_priv);
@@ -1665,6 +1727,7 @@ static int cnss_qca6290_shutdown(struct cnss_pci_data *pci_priv)
{
	int ret = 0;
	struct cnss_plat_data *plat_priv = pci_priv->plat_priv;
	int do_force_wake = true;

	cnss_pci_pm_runtime_resume(pci_priv);

@@ -1691,6 +1754,10 @@ static int cnss_qca6290_shutdown(struct cnss_pci_data *pci_priv)
		goto skip_power_off;
	}

	if (test_bit(CNSS_DEV_ERR_NOTIFY, &plat_priv->driver_state))
		do_force_wake = false;

	cnss_pci_set_wlaon_pwr_ctrl(pci_priv, false, true, do_force_wake);
	cnss_pci_power_off_mhi(pci_priv);
	ret = cnss_suspend_pci_link(pci_priv);
	if (ret)
@@ -4083,6 +4150,7 @@ static int cnss_pci_probe(struct pci_dev *pci_dev,
	case QCA6290_DEVICE_ID:
	case QCA6390_DEVICE_ID:
	case QCA6490_DEVICE_ID:
		cnss_pci_set_wlaon_pwr_ctrl(pci_priv, false, false, false);
		timer_setup(&pci_priv->dev_rddm_timer,
			    cnss_dev_rddm_timeout_hdlr, 0);
		INIT_DELAYED_WORK(&pci_priv->time_sync_work,
@@ -4097,11 +4165,10 @@ static int cnss_pci_probe(struct pci_dev *pci_dev,
			goto disable_bus;
		}
		cnss_pci_get_link_status(pci_priv);

		cnss_pci_config_regs(pci_priv);

		if (EMULATION_HW)
			break;
		cnss_pci_set_wlaon_pwr_ctrl(pci_priv, false, true, false);
		ret = cnss_suspend_pci_link(pci_priv);
		if (ret)
			cnss_pr_err("Failed to suspend PCI link, err = %d\n",
+3 −1
Original line number Diff line number Diff line
/* SPDX-License-Identifier: GPL-2.0-only */
/* Copyright (c) 2019, The Linux Foundation. All rights reserved. */
/* Copyright (c) 2019-2020, The Linux Foundation. All rights reserved. */

#ifndef _CNSS_REG_H
#define _CNSS_REG_H
@@ -204,6 +204,8 @@
#define QCA6390_WLAON_WL_CLK_CNTL_KDF_REG 0x1F80314
#define QCA6390_WLAON_WL_CLK_CNTL_PMU_HFRC_REG 0x1F80318
#define QCA6390_WLAON_QFPROM_PWR_CTRL_REG 0x1F8031C
#define QFPROM_PWR_CTRL_VDD4BLOW_SW_EN_MASK 0x4
#define QFPROM_PWR_CTRL_SHUTDOWN_EN_MASK 0x1
#define QCA6390_WLAON_DLY_CONFIG 0x1F80400
#define QCA6390_WLAON_WLAON_Q6_IRQ_REG 0x1F80404
#define QCA6390_WLAON_PCIE_INTF_SW_CFG_REG 0x1F80408