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

Commit 1ce2ea3d authored by David Collins's avatar David Collins Committed by Matt Wagantall
Browse files

soc: qcom: spm: add support for AVS interrupt control



Add support for consumers to enable, disable, and clear the AVS
min and max interrupts.  These interrupts are triggered when
hardware attempts to raise or lower the AVS voltage outside of
the configured limits.

Change-Id: I84128265901687436405d689b5aa583677deb176
Signed-off-by: default avatarDavid Collins <collinsd@codeaurora.org>
parent e3dea266
Loading
Loading
Loading
Loading
+58 −0
Original line number Diff line number Diff line
@@ -273,6 +273,64 @@ int msm_spm_drv_set_avs_limit(struct msm_spm_driver_data *dev,
	return 0;
}

static int msm_spm_drv_avs_irq_mask(enum msm_spm_avs_irq irq)
{
	switch (irq) {
	case MSM_SPM_AVS_IRQ_MIN:
		return BIT(1);
	case MSM_SPM_AVS_IRQ_MAX:
		return BIT(2);
	default:
		return -EINVAL;
	}
}

int msm_spm_drv_set_avs_irq_enable(struct msm_spm_driver_data *dev,
		enum msm_spm_avs_irq irq, bool enable)
{
	int mask = msm_spm_drv_avs_irq_mask(irq);
	uint32_t value;

	if (!dev)
		return -EINVAL;
	else if (mask < 0)
		return mask;

	value = enable ? mask : 0;

	if ((dev->reg_shadow[MSM_SPM_REG_SAW_AVS_CTL] & mask) ^ value) {
		dev->reg_shadow[MSM_SPM_REG_SAW_AVS_CTL] &= ~mask;
		dev->reg_shadow[MSM_SPM_REG_SAW_AVS_CTL] |= value;
		msm_spm_drv_flush_shadow(dev, MSM_SPM_REG_SAW_AVS_CTL);
	}

	return 0;
}

int msm_spm_drv_avs_clear_irq(struct msm_spm_driver_data *dev,
		enum msm_spm_avs_irq irq)
{
	int mask = msm_spm_drv_avs_irq_mask(irq);

	if (!dev)
		return -EINVAL;
	else if (mask < 0)
		return mask;

	if (dev->reg_shadow[MSM_SPM_REG_SAW_AVS_CTL] & mask) {
		/*
		 * The interrupt status is cleared by disabling and then
		 * re-enabling the interrupt.
		 */
		dev->reg_shadow[MSM_SPM_REG_SAW_AVS_CTL] &= ~mask;
		msm_spm_drv_flush_shadow(dev, MSM_SPM_REG_SAW_AVS_CTL);
		dev->reg_shadow[MSM_SPM_REG_SAW_AVS_CTL] |= mask;
		msm_spm_drv_flush_shadow(dev, MSM_SPM_REG_SAW_AVS_CTL);
	}

	return 0;
}

void msm_spm_drv_flush_seq_entry(struct msm_spm_driver_data *dev)
{
	int i;
+54 −0
Original line number Diff line number Diff line
@@ -472,6 +472,60 @@ int msm_spm_avs_set_limit(unsigned int cpu,
}
EXPORT_SYMBOL(msm_spm_avs_set_limit);

/**
 * msm_spm_avs_enable_irq() - Enable an AVS interrupt
 * @cpu: specifies which CPU's AVS should be configured
 * @irq: specifies which interrupt to enable
 *
 * Returns errno in case of failure or 0 if successful.
 */
int msm_spm_avs_enable_irq(unsigned int cpu, enum msm_spm_avs_irq irq)
{
	struct msm_spm_device *dev = per_cpu(cpu_vctl_device, cpu);

	if (!dev)
		return -ENXIO;

	return msm_spm_drv_set_avs_irq_enable(&dev->reg_data, irq, true);
}
EXPORT_SYMBOL(msm_spm_avs_enable_irq);

/**
 * msm_spm_avs_disable_irq() - Disable an AVS interrupt
 * @cpu: specifies which CPU's AVS should be configured
 * @irq: specifies which interrupt to disable
 *
 * Returns errno in case of failure or 0 if successful.
 */
int msm_spm_avs_disable_irq(unsigned int cpu, enum msm_spm_avs_irq irq)
{
	struct msm_spm_device *dev = per_cpu(cpu_vctl_device, cpu);

	if (!dev)
		return -ENXIO;

	return msm_spm_drv_set_avs_irq_enable(&dev->reg_data, irq, false);
}
EXPORT_SYMBOL(msm_spm_avs_disable_irq);

/**
 * msm_spm_avs_clear_irq() - Clear a latched AVS interrupt
 * @cpu: specifies which CPU's AVS should be configured
 * @irq: specifies which interrupt to clear
 *
 * Returns errno in case of failure or 0 if successful.
 */
int msm_spm_avs_clear_irq(unsigned int cpu, enum msm_spm_avs_irq irq)
{
	struct msm_spm_device *dev = per_cpu(cpu_vctl_device, cpu);

	if (!dev)
		return -ENXIO;

	return msm_spm_drv_avs_clear_irq(&dev->reg_data, irq);
}
EXPORT_SYMBOL(msm_spm_avs_clear_irq);

/**
 * msm_spm_set_low_power_mode() - Configure SPM start address for low power mode
 * @mode: SPM LPM mode to enter
+6 −0
Original line number Diff line number Diff line
@@ -118,6 +118,12 @@ int msm_spm_drv_set_avs_limit(struct msm_spm_driver_data *dev,
int msm_spm_drv_set_avs_enable(struct msm_spm_driver_data *dev,
		 bool enable);
int msm_spm_drv_get_avs_enable(struct msm_spm_driver_data *dev);

int msm_spm_drv_set_avs_irq_enable(struct msm_spm_driver_data *dev,
		enum msm_spm_avs_irq irq, bool enable);
int msm_spm_drv_avs_clear_irq(struct msm_spm_driver_data *dev,
		enum msm_spm_avs_irq irq);

void msm_spm_reinit(void);
int msm_spm_init(struct msm_spm_platform_data *data, int nr_devs);

+27 −0
Original line number Diff line number Diff line
@@ -23,6 +23,11 @@ enum {
	MSM_SPM_MODE_NR
};

enum msm_spm_avs_irq {
	MSM_SPM_AVS_IRQ_MIN,
	MSM_SPM_AVS_IRQ_MAX,
};

struct msm_spm_device;
struct device_node;

@@ -45,6 +50,10 @@ int msm_spm_avs_enable(unsigned int cpu);
int msm_spm_avs_disable(unsigned int cpu);
int msm_spm_avs_set_limit(unsigned int cpu, uint32_t min_lvl,
		uint32_t max_lvl);
int msm_spm_avs_enable_irq(unsigned int cpu, enum msm_spm_avs_irq irq);
int msm_spm_avs_disable_irq(unsigned int cpu, enum msm_spm_avs_irq irq);
int msm_spm_avs_clear_irq(unsigned int cpu, enum msm_spm_avs_irq irq);

#if defined(CONFIG_MSM_L2_SPM)

/* Public functions */
@@ -116,5 +125,23 @@ static inline bool msm_spm_is_mode_avail(unsigned int mode)
	return false;
}

static inline int msm_spm_avs_enable_irq(unsigned int cpu,
		enum msm_spm_avs_irq irq)
{
	return -ENOSYS;
}

static inline int msm_spm_avs_disable_irq(unsigned int cpu,
		enum msm_spm_avs_irq irq)
{
	return -ENOSYS;
}

static inline int msm_spm_avs_clear_irq(unsigned int cpu,
		enum msm_spm_avs_irq irq)
{
	return -ENOSYS;
}

#endif  /* defined (CONFIG_MSM_SPM) */
#endif  /* __ARCH_ARM_MACH_MSM_SPM_H */