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

Commit a075000f authored by Hanumath Prasad's avatar Hanumath Prasad Committed by Gerrit - the friendly Code Review server
Browse files

PM / devfreq: msmcci-hwmon: Add support for handling shared irq



Some targets have a single irq line which is shared among all
the cci hwmon counters. Enhance the driver to support shared interrupt
handling.

Change-Id: I5fdaecfaa14fa47e8f393fe51c538e5000e6ad5b
Signed-off-by: default avatarArun KS <arunks@codeaurora.org>
Signed-off-by: default avatarHanumath Prasad <hpprasad@codeaurora.org>
parent 6b6b4c37
Loading
Loading
Loading
Loading
+1 −0
Original line number Original line Diff line number Diff line
@@ -14,6 +14,7 @@ Required properties:


Optional properties:
Optional properties:
- qcom,secure_io	Indicates register access are secured.
- qcom,secure_io	Indicates register access are secured.
- qcom,shared-irq       Indicates ccci-hwmon counters share the interrupt.


Example:
Example:
	qcom,msmcci-hwmon {
	qcom,msmcci-hwmon {
+80 −22
Original line number Original line Diff line number Diff line
@@ -73,6 +73,7 @@ struct msmcci_hwmon {
	struct cache_hwmon hw;
	struct cache_hwmon hw;
	struct device *dev;
	struct device *dev;
	bool secure_io;
	bool secure_io;
	bool irq_shared;
};
};


#define to_mon(ptr) container_of(ptr, struct msmcci_hwmon, hw)
#define to_mon(ptr) container_of(ptr, struct msmcci_hwmon, hw)
@@ -156,6 +157,25 @@ static void mon_set_limit_single(struct msmcci_hwmon *m, int idx, u32 limit)
	write_mon_reg(m, idx, EVNT_CNT_MATCH_VAL, limit);
	write_mon_reg(m, idx, EVNT_CNT_MATCH_VAL, limit);
}
}


static irqreturn_t msmcci_hwmon_shared_intr_handler(int irq, void *dev)
{
	struct msmcci_hwmon *m = dev;
	int idx = -1, i;

	for (i = 0; i < m->num_counters; i++) {
		if (mon_is_match_flag_set(m, i)) {
			idx = i;
			break;
		}
	}
	if (idx == -1)
		return IRQ_NONE;

	update_cache_hwmon(&m->hw);

	return IRQ_HANDLED;
}

static irqreturn_t msmcci_hwmon_intr_handler(int irq, void *dev)
static irqreturn_t msmcci_hwmon_intr_handler(int irq, void *dev)
{
{
	struct msmcci_hwmon *m = dev;
	struct msmcci_hwmon *m = dev;
@@ -379,16 +399,24 @@ static void unregister_pm_nofitifier(void)
	mutex_unlock(&notifier_reg_lock);
	mutex_unlock(&notifier_reg_lock);
}
}


static int start_hwmon(struct cache_hwmon *hw, struct mrps_stats *mrps)
static int request_shared_interrupt(struct msmcci_hwmon *m)
{
{
	struct msmcci_hwmon *m = to_mon(hw);
	int ret;
	unsigned int sample_ms = hw->df->profile->polling_ms;
	int ret, i;
	u32 limit;


	ret = register_pm_notifier(m);
	ret = request_threaded_irq(m->irq[HIGH], NULL,
			msmcci_hwmon_shared_intr_handler,
			IRQF_ONESHOT | IRQF_SHARED,
			dev_name(m->dev), m);
	if (ret)
	if (ret)
		dev_err(m->dev, "Unable to register shared interrupt handler for irq %d\n",
			m->irq[HIGH]);

	return ret;
	return ret;
}

static int request_interrupts(struct msmcci_hwmon  *m)
{
	int i, ret;


	for (i = 0; i < m->num_counters; i++) {
	for (i = 0; i < m->num_counters; i++) {
		ret = request_threaded_irq(m->irq[i], NULL,
		ret = request_threaded_irq(m->irq[i], NULL,
@@ -400,7 +428,36 @@ static int start_hwmon(struct cache_hwmon *hw, struct mrps_stats *mrps)
			goto irq_failure;
			goto irq_failure;
		}
		}
	}
	}
	return 0;


irq_failure:
	for (i--; i > 0; i--) {
		disable_irq(m->irq[i]);
		free_irq(m->irq[i], m);
	}
	return ret;
}

static int start_hwmon(struct cache_hwmon *hw, struct mrps_stats *mrps)
{
	struct msmcci_hwmon *m = to_mon(hw);
	unsigned int sample_ms = hw->df->profile->polling_ms;
	int ret, i;
	u32 limit;

	ret = register_pm_notifier(m);
	if (ret)
		return ret;

	if (m->irq_shared)
		ret = request_shared_interrupt(m);
	else
		ret = request_interrupts(m);

	if (ret) {
		unregister_pm_nofitifier();
		return ret;
	}
	mon_init(m);
	mon_init(m);
	mon_disable(m);
	mon_disable(m);
	for (i = 0; i < m->num_counters; i++) {
	for (i = 0; i < m->num_counters; i++) {
@@ -412,14 +469,6 @@ static int start_hwmon(struct cache_hwmon *hw, struct mrps_stats *mrps)
	m->mon_enabled = true;
	m->mon_enabled = true;


	return 0;
	return 0;

irq_failure:
	for (i--; i > 0; i--) {
		disable_irq(m->irq[i]);
		free_irq(m->irq[i], m);
	}
	unregister_pm_nofitifier();
	return ret;
}
}


static void stop_hwmon(struct cache_hwmon *hw)
static void stop_hwmon(struct cache_hwmon *hw)
@@ -429,11 +478,15 @@ static void stop_hwmon(struct cache_hwmon *hw)


	m->mon_enabled = false;
	m->mon_enabled = false;
	mon_disable(m);
	mon_disable(m);

	for (i = 0; i < m->num_counters; i++) {
	for (i = 0; i < m->num_counters; i++) {
		if (!m->irq_shared || i == HIGH) {
			disable_irq(m->irq[i]);
			disable_irq(m->irq[i]);
			free_irq(m->irq[i], m);
			free_irq(m->irq[i], m);
		}
		mon_clear_single(m, i);
		mon_clear_single(m, i);
	}
	}

	unregister_pm_nofitifier();
	unregister_pm_nofitifier();
}
}


@@ -471,12 +524,14 @@ static int msmcci_hwmon_parse_dt(struct platform_device *pdev,
	}
	}
	m->event_sel[idx] = sel;
	m->event_sel[idx] = sel;


	if (!m->irq_shared || idx == HIGH) {
		m->irq[idx] = platform_get_irq(pdev, idx);
		m->irq[idx] = platform_get_irq(pdev, idx);
		if (m->irq[idx] < 0) {
		if (m->irq[idx] < 0) {
		dev_err(dev, "Counter[%d] failed to get IRQ number\n", idx);
			dev_err(dev, "Counter[%d] failed to get IRQ number\n",
									idx);
			return m->irq[idx];
			return m->irq[idx];
		}
		}

	}
	m->num_counters++;
	m->num_counters++;
	return 0;
	return 0;
}
}
@@ -495,6 +550,9 @@ static int msmcci_hwmon_driver_probe(struct platform_device *pdev)
	m->secure_io = of_property_read_bool(pdev->dev.of_node,
	m->secure_io = of_property_read_bool(pdev->dev.of_node,
					"qcom,secure-io");
					"qcom,secure-io");


	m->irq_shared = of_property_read_bool(pdev->dev.of_node,
						"qcom,shared-irq");

	ret = msmcci_hwmon_parse_dt(pdev, m, HIGH);
	ret = msmcci_hwmon_parse_dt(pdev, m, HIGH);
	if (ret)
	if (ret)
		return ret;
		return ret;