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

Commit 6b9ad6db authored by Linux Build Service Account's avatar Linux Build Service Account Committed by Gerrit - the friendly Code Review server
Browse files

Merge "soc: swr-mstr: Store enabled interrupts information in master data"

parents 2149e5be 7e35478b
Loading
Loading
Loading
Loading
+211 −31
Original line number Diff line number Diff line
@@ -26,7 +26,8 @@
#include "swr-mstr-ctrl.h"
#include "swrm_port_config.h"


#define SWRM_SYSTEM_RESUME_TIMEOUT_MS 700
#define SWRM_SYS_SUSPEND_WAIT 1
#define SWR_BROADCAST_CMD_ID            0x0F
#define SWR_AUTO_SUSPEND_DELAY          3 /* delay in sec */
#define SWR_DEV_ID_MASK			0xFFFFFFFF
@@ -82,6 +83,8 @@ static struct dentry *debugfs_poke;
static struct dentry *debugfs_reg_dump;
static unsigned int read_data;

static bool swrm_lock_sleep(struct swr_mstr_ctrl *swrm);
static void swrm_unlock_sleep(struct swr_mstr_ctrl *swrm);

static bool swrm_is_msm_variant(int val)
{
@@ -974,6 +977,7 @@ static int swrm_slvdev_datapath_control(struct swr_master *master, bool enable)
		pr_err("%s: swrm is null\n", __func__);
		return -EFAULT;
	}

	mutex_lock(&swrm->mlock);

	bank = get_inactive_bank_num(swrm);
@@ -1254,7 +1258,7 @@ static int swrm_check_slave_change_status(struct swr_mstr_ctrl *swrm,
static irqreturn_t swr_mstr_interrupt(int irq, void *dev)
{
	struct swr_mstr_ctrl *swrm = dev;
	u32 value, intr_sts, intr_mask;
	u32 value, intr_sts, intr_sts_masked;
	u32 temp = 0;
	u32 status, chg_sts, i;
	u8 devnum = 0;
@@ -1262,17 +1266,20 @@ static irqreturn_t swr_mstr_interrupt(int irq, void *dev)
	struct swr_device *swr_dev;
	struct swr_master *mstr = &swrm->master;

	if (unlikely(swrm_lock_sleep(swrm) == false)) {
		dev_err(swrm->dev, "%s Failed to hold suspend\n", __func__);
		return IRQ_NONE;
	}

	mutex_lock(&swrm->reslock);
	swrm_clk_request(swrm, true);
	mutex_unlock(&swrm->reslock);

	intr_sts = swr_master_read(swrm, SWRM_INTERRUPT_STATUS);
	intr_mask = swr_master_read(swrm, SWR_MSTR_RX_SWRM_CPU_INTERRUPT_EN);
	intr_sts &= intr_mask;
	intr_sts_masked = intr_sts & swrm->intr_mask;
handle_irq:
	for (i = 0; i < SWRM_INTERRUPT_MAX; i++) {
		value = intr_sts & (1 << i);
		value = intr_sts_masked & (1 << i);
		if (!value)
			continue;

@@ -1364,16 +1371,16 @@ static irqreturn_t swr_mstr_interrupt(int irq, void *dev)
			break;
		case SWRM_INTERRUPT_STATUS_DOUT_PORT_COLLISION:
			dev_err_ratelimited(swrm->dev, "SWR Port collision detected\n");
			intr_mask &= ~SWRM_INTERRUPT_STATUS_DOUT_PORT_COLLISION;
			swrm->intr_mask &= ~SWRM_INTERRUPT_STATUS_DOUT_PORT_COLLISION;
			swr_master_write(swrm,
				SWR_MSTR_RX_SWRM_CPU_INTERRUPT_EN, intr_mask);
				SWR_MSTR_RX_SWRM_CPU_INTERRUPT_EN, swrm->intr_mask);
			break;
		case SWRM_INTERRUPT_STATUS_READ_EN_RD_VALID_MISMATCH:
			dev_dbg(swrm->dev, "SWR read enable valid mismatch\n");
			intr_mask &=
			swrm->intr_mask &=
				~SWRM_INTERRUPT_STATUS_READ_EN_RD_VALID_MISMATCH;
			swr_master_write(swrm,
				 SWR_MSTR_RX_SWRM_CPU_INTERRUPT_EN, intr_mask);
				 SWR_MSTR_RX_SWRM_CPU_INTERRUPT_EN, swrm->intr_mask);
			break;
		case SWRM_INTERRUPT_STATUS_SPECIAL_CMD_ID_FINISHED:
			complete(&swrm->broadcast);
@@ -1401,9 +1408,9 @@ static irqreturn_t swr_mstr_interrupt(int irq, void *dev)
	swr_master_write(swrm, SWRM_INTERRUPT_CLEAR, 0x0);

	intr_sts = swr_master_read(swrm, SWRM_INTERRUPT_STATUS);
	intr_sts &= intr_mask;
	intr_sts_masked = intr_sts & swrm->intr_mask;

	if (intr_sts) {
	if (intr_sts_masked) {
		dev_dbg(swrm->dev, "%s: new interrupt received\n", __func__);
		goto handle_irq;
	}
@@ -1411,6 +1418,7 @@ static irqreturn_t swr_mstr_interrupt(int irq, void *dev)
	mutex_lock(&swrm->reslock);
	swrm_clk_request(swrm, false);
	mutex_unlock(&swrm->reslock);
	swrm_unlock_sleep(swrm);
	return ret;
}

@@ -1454,12 +1462,19 @@ static void swrm_wakeup_work(struct work_struct *work)
	mutex_lock(&swrm->devlock);
	if (!swrm->dev_up) {
		mutex_unlock(&swrm->devlock);
		return;
		goto exit;
	}
	mutex_unlock(&swrm->devlock);
	if (unlikely(swrm_lock_sleep(swrm) == false)) {
		dev_err(swrm->dev, "%s Failed to hold suspend\n", __func__);
		goto exit;
	}
	pm_runtime_get_sync(swrm->dev);
	pm_runtime_mark_last_busy(swrm->dev);
	pm_runtime_put_autosuspend(swrm->dev);
	swrm_unlock_sleep(swrm);
exit:
	pm_relax(swrm->dev);
}

static int swrm_get_device_status(struct swr_mstr_ctrl *swrm, u8 devnum)
@@ -1545,6 +1560,10 @@ static void swrm_device_wakeup_vote(struct swr_master *mstr)
			__func__);
		return;
	}
	if (unlikely(swrm_lock_sleep(swrm) == false)) {
		dev_err(swrm->dev, "%s Failed to hold suspend\n", __func__);
		return;
	}
	pm_runtime_get_sync(swrm->dev);
}

@@ -1559,6 +1578,7 @@ static void swrm_device_wakeup_unvote(struct swr_master *mstr)
	}
	pm_runtime_mark_last_busy(swrm->dev);
	pm_runtime_put_autosuspend(swrm->dev);
	swrm_unlock_sleep(swrm);
}

static int swrm_master_init(struct swr_mstr_ctrl *swrm)
@@ -1610,12 +1630,13 @@ static int swrm_master_init(struct swr_mstr_ctrl *swrm)
	reg[len] = SWRM_INTERRUPT_CLEAR;
	value[len++] = 0xFFFFFFFF;

	swrm->intr_mask = SWRM_INTERRUPT_STATUS_MASK;
	/* Mask soundwire interrupts */
	reg[len] = SWRM_INTERRUPT_MASK_ADDR;
	value[len++] = 0x1FFFD;
	value[len++] = swrm->intr_mask;

	reg[len] = SWR_MSTR_RX_SWRM_CPU_INTERRUPT_EN;
	value[len++] = SWRM_INTERRUPT_STATUS_MASK;
	value[len++] = swrm->intr_mask;

	swr_master_bulk_write(swrm, reg, value, len);

@@ -1639,6 +1660,7 @@ static int swrm_event_notify(struct notifier_block *self,
	case SWR_WAKE_IRQ_EVENT:
		if (swrm->ipc_wakeup && !swrm->ipc_wakeup_triggered) {
			swrm->ipc_wakeup_triggered = true;
			pm_stay_awake(swrm->dev);
			schedule_work(&swrm->wakeup_work);
		}
		break;
@@ -1745,6 +1767,21 @@ static int swrm_probe(struct platform_device *pdev)
			&swrm->clk_stop_mode0_supp)) {
		swrm->clk_stop_mode0_supp = FALSE;
	}

	ret = of_property_read_u32(swrm->dev->of_node, "qcom,swr-num-dev",
				   &swrm->num_dev);
	if (ret) {
		dev_dbg(&pdev->dev, "%s: Looking up %s property failed\n",
			__func__, "qcom,swr-num-dev");
	} else {
		if (swrm->num_dev > SWR_MAX_SLAVE_DEVICES) {
			dev_err(&pdev->dev, "%s: num_dev %d > max limit %d\n",
				__func__, swrm->num_dev, SWR_MAX_SLAVE_DEVICES);
			ret = -EINVAL;
			goto err_pdata_fail;
		}
	}

	/* Parse soundwire port mapping */
	ret = of_property_read_u32(pdev->dev.of_node, "qcom,swr-num-ports",
				&num_ports);
@@ -1827,24 +1864,17 @@ static int swrm_probe(struct platform_device *pdev)
	mutex_init(&swrm->iolock);
	mutex_init(&swrm->clklock);
	mutex_init(&swrm->devlock);
	mutex_init(&swrm->pm_lock);
	swrm->wlock_holders = 0;
	swrm->pm_state = SWRM_PM_SLEEPABLE;
	init_waitqueue_head(&swrm->pm_wq);
	pm_qos_add_request(&swrm->pm_qos_req,
			   PM_QOS_CPU_DMA_LATENCY,
			   PM_QOS_DEFAULT_VALUE);

	for (i = 0 ; i < SWR_MSTR_PORT_LEN; i++)
		INIT_LIST_HEAD(&swrm->mport_cfg[i].port_req_list);

	ret = of_property_read_u32(swrm->dev->of_node, "qcom,swr-num-dev",
				   &swrm->num_dev);
	if (ret) {
		dev_dbg(&pdev->dev, "%s: Looking up %s property failed\n",
			__func__, "qcom,swr-num-dev");
	} else {
		if (swrm->num_dev > SWR_MAX_SLAVE_DEVICES) {
			dev_err(&pdev->dev, "%s: num_dev %d > max limit %d\n",
				__func__, swrm->num_dev, SWR_MAX_SLAVE_DEVICES);
			ret = -EINVAL;
			goto err_pdata_fail;
		}
	}

	if (swrm->reg_irq) {
		ret = swrm->reg_irq(swrm->handle, swr_mstr_interrupt, swrm,
			    SWR_IRQ_REGISTER);
@@ -1940,6 +1970,9 @@ static int swrm_probe(struct platform_device *pdev)
	mutex_destroy(&swrm->force_down_lock);
	mutex_destroy(&swrm->iolock);
	mutex_destroy(&swrm->clklock);
	mutex_destroy(&swrm->pm_lock);
	pm_qos_remove_request(&swrm->pm_qos_req);

err_pdata_fail:
err_memory_fail:
	return ret;
@@ -1956,7 +1989,7 @@ static int swrm_remove(struct platform_device *pdev)
		free_irq(swrm->irq, swrm);
	else if (swrm->wake_irq > 0)
		free_irq(swrm->wake_irq, swrm);

	cancel_work_sync(&swrm->wakeup_work);
	pm_runtime_disable(&pdev->dev);
	pm_runtime_set_suspended(&pdev->dev);
	swr_unregister_master(&swrm->master);
@@ -1966,6 +1999,8 @@ static int swrm_remove(struct platform_device *pdev)
	mutex_destroy(&swrm->iolock);
	mutex_destroy(&swrm->clklock);
	mutex_destroy(&swrm->force_down_lock);
	mutex_destroy(&swrm->pm_lock);
	pm_qos_remove_request(&swrm->pm_qos_req);
	devm_kfree(&pdev->dev, swrm);
	return 0;
}
@@ -2301,6 +2336,94 @@ int swrm_wcd_notify(struct platform_device *pdev, u32 id, void *data)
}
EXPORT_SYMBOL(swrm_wcd_notify);

/*
 * swrm_pm_cmpxchg:
 *      Check old state and exchange with pm new state
 *      if old state matches with current state
 *
 * @swrm: pointer to wcd core resource
 * @o: pm old state
 * @n: pm new state
 *
 * Returns old state
 */
static enum swrm_pm_state swrm_pm_cmpxchg(
				struct swr_mstr_ctrl *swrm,
				enum swrm_pm_state o,
				enum swrm_pm_state n)
{
	enum swrm_pm_state old;

	if (!swrm)
		return o;

	mutex_lock(&swrm->pm_lock);
	old = swrm->pm_state;
	if (old == o)
		swrm->pm_state = n;
	mutex_unlock(&swrm->pm_lock);

	return old;
}

static bool swrm_lock_sleep(struct swr_mstr_ctrl *swrm)
{
	enum swrm_pm_state os;

	/*
	 * swrm_{lock/unlock}_sleep will be called by swr irq handler
	 * and slave wake up requests..
	 *
	 * If system didn't resume, we can simply return false so
	 * IRQ handler can return without handling IRQ.
	 */
	mutex_lock(&swrm->pm_lock);
	if (swrm->wlock_holders++ == 0) {
		dev_dbg(swrm->dev, "%s: holding wake lock\n", __func__);
		pm_qos_update_request(&swrm->pm_qos_req,
					  msm_cpuidle_get_deep_idle_latency());
		pm_stay_awake(swrm->dev);
	}
	mutex_unlock(&swrm->pm_lock);

	if (!wait_event_timeout(swrm->pm_wq,
				((os =  swrm_pm_cmpxchg(swrm,
				  SWRM_PM_SLEEPABLE,
				  SWRM_PM_AWAKE)) ==
					SWRM_PM_SLEEPABLE ||
					(os == SWRM_PM_AWAKE)),
					msecs_to_jiffies(
					SWRM_SYSTEM_RESUME_TIMEOUT_MS))) {
		dev_err(swrm->dev, "%s: system didn't resume within %dms, s %d, w %d\n",
			__func__, SWRM_SYSTEM_RESUME_TIMEOUT_MS, swrm->pm_state,
				swrm->wlock_holders);
		swrm_unlock_sleep(swrm);
		return false;
	}
	wake_up_all(&swrm->pm_wq);
	return true;
}

static void swrm_unlock_sleep(struct swr_mstr_ctrl *swrm)
{
	mutex_lock(&swrm->pm_lock);
	if (--swrm->wlock_holders == 0) {
		dev_dbg(swrm->dev, "%s: releasing wake lock pm_state %d -> %d\n",
			 __func__, swrm->pm_state, SWRM_PM_SLEEPABLE);
		/*
		 * if swrm_lock_sleep failed, pm_state would be still
		 * swrm_PM_ASLEEP, don't overwrite
		 */
		if (likely(swrm->pm_state == SWRM_PM_AWAKE))
			swrm->pm_state = SWRM_PM_SLEEPABLE;
		pm_qos_update_request(&swrm->pm_qos_req,
				  PM_QOS_DEFAULT_VALUE);
		pm_relax(swrm->dev);
	}
	mutex_unlock(&swrm->pm_lock);
	wake_up_all(&swrm->pm_wq);
}

#ifdef CONFIG_PM_SLEEP
static int swrm_suspend(struct device *dev)
{
@@ -2309,7 +2432,49 @@ static int swrm_suspend(struct device *dev)
	struct swr_mstr_ctrl *swrm = platform_get_drvdata(pdev);

	dev_dbg(dev, "%s: system suspend, state: %d\n", __func__, swrm->state);
	if (!pm_runtime_enabled(dev) || !pm_runtime_suspended(dev)) {

	mutex_lock(&swrm->pm_lock);

	if (swrm->pm_state == SWRM_PM_SLEEPABLE) {
		dev_dbg(swrm->dev, "%s: suspending system, state %d, wlock %d\n",
			 __func__, swrm->pm_state,
			swrm->wlock_holders);
		swrm->pm_state = SWRM_PM_ASLEEP;
	} else if (swrm->pm_state == SWRM_PM_AWAKE) {
		/*
		 * unlock to wait for pm_state == SWRM_PM_SLEEPABLE
		 * then set to SWRM_PM_ASLEEP
		 */
		dev_dbg(swrm->dev, "%s: waiting to suspend system, state %d, wlock %d\n",
			 __func__, swrm->pm_state,
			 swrm->wlock_holders);
		mutex_unlock(&swrm->pm_lock);
		if (!(wait_event_timeout(swrm->pm_wq, swrm_pm_cmpxchg(
					 swrm, SWRM_PM_SLEEPABLE,
						 SWRM_PM_ASLEEP) ==
						   SWRM_PM_SLEEPABLE,
						   msecs_to_jiffies(
						   SWRM_SYS_SUSPEND_WAIT)))) {
			dev_dbg(swrm->dev, "%s: suspend failed state %d, wlock %d\n",
				 __func__, swrm->pm_state,
				 swrm->wlock_holders);
			return -EBUSY;
		} else {
			dev_dbg(swrm->dev,
				"%s: done, state %d, wlock %d\n",
				__func__, swrm->pm_state,
				swrm->wlock_holders);
		}
		mutex_lock(&swrm->pm_lock);
	} else if (swrm->pm_state == SWRM_PM_ASLEEP) {
		dev_dbg(swrm->dev, "%s: system is already suspended, state %d, wlock %d\n",
			__func__, swrm->pm_state,
			swrm->wlock_holders);
	}

	mutex_unlock(&swrm->pm_lock);

	if ((!pm_runtime_enabled(dev) || !pm_runtime_suspended(dev))) {
		ret = swrm_runtime_suspend(dev);
		if (!ret) {
			/*
@@ -2355,6 +2520,21 @@ static int swrm_resume(struct device *dev)
			pm_request_autosuspend(dev);
		}
	}
	mutex_lock(&swrm->pm_lock);
	if (swrm->pm_state == SWRM_PM_ASLEEP) {
		dev_dbg(swrm->dev,
			"%s: resuming system, state %d, wlock %d\n",
			__func__, swrm->pm_state,
			swrm->wlock_holders);
		swrm->pm_state = SWRM_PM_SLEEPABLE;
	} else {
		dev_dbg(swrm->dev, "%s: system is already awake, state %d wlock %d\n",
			__func__, swrm->pm_state,
			swrm->wlock_holders);
	}
	mutex_unlock(&swrm->pm_lock);
	wake_up_all(&swrm->pm_wq);

	return ret;
}
#endif /* CONFIG_PM_SLEEP */
+14 −0
Original line number Diff line number Diff line
@@ -7,6 +7,8 @@
#define _SWR_WCD_CTRL_H
#include <linux/module.h>
#include <soc/swr-wcd.h>
#include <linux/pm_qos.h>
#include <soc/qcom/pm.h>

#define SWR_ROW_48		0
#define SWR_ROW_50		1
@@ -35,6 +37,12 @@ enum {
	SWR_MSTR_SSR,
};

enum swrm_pm_state {
	SWRM_PM_SLEEPABLE,
	SWRM_PM_AWAKE,
	SWRM_PM_ASLEEP,
};

enum {
	SWR_IRQ_FREE,
	SWR_IRQ_REGISTER,
@@ -111,6 +119,7 @@ struct swr_mstr_ctrl {
	struct mutex devlock;
	struct mutex mlock;
	struct mutex reslock;
	struct mutex pm_lock;
	u32 swrm_base_reg;
	char __iomem *swrm_dig_base;
	u8 rcmd_id;
@@ -149,6 +158,11 @@ struct swr_mstr_ctrl {
	u32 ipc_wakeup;
	bool dev_up;
	bool ipc_wakeup_triggered;
	struct pm_qos_request pm_qos_req;
	enum swrm_pm_state pm_state;
	wait_queue_head_t pm_wq;
	int wlock_holders;
	u32 intr_mask;
};

#endif /* _SWR_WCD_CTRL_H */