static int __maybe_unused qca_suspend()

in hci_qca.c [2186:2298]


static int __maybe_unused qca_suspend(struct device *dev)
{
	struct serdev_device *serdev = to_serdev_device(dev);
	struct qca_serdev *qcadev = serdev_device_get_drvdata(serdev);
	struct hci_uart *hu = &qcadev->serdev_hu;
	struct qca_data *qca = hu->priv;
	unsigned long flags;
	bool tx_pending = false;
	int ret = 0;
	u8 cmd;
	u32 wait_timeout = 0;

	set_bit(QCA_SUSPENDING, &qca->flags);

	/* if BT SoC is running with default firmware then it does not
	 * support in-band sleep
	 */
	if (test_bit(QCA_ROM_FW, &qca->flags))
		return 0;

	/* During SSR after memory dump collection, controller will be
	 * powered off and then powered on.If controller is powered off
	 * during SSR then we should wait until SSR is completed.
	 */
	if (test_bit(QCA_BT_OFF, &qca->flags) &&
	    !test_bit(QCA_SSR_TRIGGERED, &qca->flags))
		return 0;

	if (test_bit(QCA_IBS_DISABLED, &qca->flags) ||
	    test_bit(QCA_SSR_TRIGGERED, &qca->flags)) {
		wait_timeout = test_bit(QCA_SSR_TRIGGERED, &qca->flags) ?
					IBS_DISABLE_SSR_TIMEOUT_MS :
					FW_DOWNLOAD_TIMEOUT_MS;

		/* QCA_IBS_DISABLED flag is set to true, During FW download
		 * and during memory dump collection. It is reset to false,
		 * After FW download complete.
		 */
		wait_on_bit_timeout(&qca->flags, QCA_IBS_DISABLED,
			    TASK_UNINTERRUPTIBLE, msecs_to_jiffies(wait_timeout));

		if (test_bit(QCA_IBS_DISABLED, &qca->flags)) {
			bt_dev_err(hu->hdev, "SSR or FW download time out");
			ret = -ETIMEDOUT;
			goto error;
		}
	}

	cancel_work_sync(&qca->ws_awake_device);
	cancel_work_sync(&qca->ws_awake_rx);

	spin_lock_irqsave_nested(&qca->hci_ibs_lock,
				 flags, SINGLE_DEPTH_NESTING);

	switch (qca->tx_ibs_state) {
	case HCI_IBS_TX_WAKING:
		del_timer(&qca->wake_retrans_timer);
		fallthrough;
	case HCI_IBS_TX_AWAKE:
		del_timer(&qca->tx_idle_timer);

		serdev_device_write_flush(hu->serdev);
		cmd = HCI_IBS_SLEEP_IND;
		ret = serdev_device_write_buf(hu->serdev, &cmd, sizeof(cmd));

		if (ret < 0) {
			BT_ERR("Failed to send SLEEP to device");
			break;
		}

		qca->tx_ibs_state = HCI_IBS_TX_ASLEEP;
		qca->ibs_sent_slps++;
		tx_pending = true;
		break;

	case HCI_IBS_TX_ASLEEP:
		break;

	default:
		BT_ERR("Spurious tx state %d", qca->tx_ibs_state);
		ret = -EINVAL;
		break;
	}

	spin_unlock_irqrestore(&qca->hci_ibs_lock, flags);

	if (ret < 0)
		goto error;

	if (tx_pending) {
		serdev_device_wait_until_sent(hu->serdev,
					      msecs_to_jiffies(CMD_TRANS_TIMEOUT_MS));
		serial_clock_vote(HCI_IBS_TX_VOTE_CLOCK_OFF, hu);
	}

	/* Wait for HCI_IBS_SLEEP_IND sent by device to indicate its Tx is going
	 * to sleep, so that the packet does not wake the system later.
	 */
	ret = wait_event_interruptible_timeout(qca->suspend_wait_q,
			qca->rx_ibs_state == HCI_IBS_RX_ASLEEP,
			msecs_to_jiffies(IBS_BTSOC_TX_IDLE_TIMEOUT_MS));
	if (ret == 0) {
		ret = -ETIMEDOUT;
		goto error;
	}

	return 0;

error:
	clear_bit(QCA_SUSPENDING, &qca->flags);

	return ret;
}