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: Arun KS <arunks@codeaurora.org>
Signed-off-by: Hanumath Prasad <hpprasad@codeaurora.org>
This commit is contained in:
Hanumath Prasad 2015-07-06 20:06:07 +05:30
parent bd2078f611
commit 556900590c
2 changed files with 81 additions and 22 deletions

View File

@ -14,6 +14,7 @@ Required properties:
Optional properties:
- qcom,secure_io Indicates register access are secured.
- qcom,shared-irq Indicates ccci-hwmon counters share the interrupt.
Example:
qcom,msmcci-hwmon {

View File

@ -73,6 +73,7 @@ struct msmcci_hwmon {
struct cache_hwmon hw;
struct device *dev;
bool secure_io;
bool irq_shared;
};
#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);
}
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)
{
struct msmcci_hwmon *m = dev;
@ -379,16 +399,24 @@ static void unregister_pm_nofitifier(void)
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);
unsigned int sample_ms = hw->df->profile->polling_ms;
int ret, i;
u32 limit;
int ret;
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)
return ret;
dev_err(m->dev, "Unable to register shared interrupt handler for irq %d\n",
m->irq[HIGH]);
return ret;
}
static int request_interrupts(struct msmcci_hwmon *m)
{
int i, ret;
for (i = 0; i < m->num_counters; i++) {
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;
}
}
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_disable(m);
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;
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)
@ -429,11 +478,15 @@ static void stop_hwmon(struct cache_hwmon *hw)
m->mon_enabled = false;
mon_disable(m);
for (i = 0; i < m->num_counters; i++) {
disable_irq(m->irq[i]);
free_irq(m->irq[i], m);
if (!m->irq_shared || i == HIGH) {
disable_irq(m->irq[i]);
free_irq(m->irq[i], m);
}
mon_clear_single(m, i);
}
unregister_pm_nofitifier();
}
@ -471,12 +524,14 @@ static int msmcci_hwmon_parse_dt(struct platform_device *pdev,
}
m->event_sel[idx] = sel;
m->irq[idx] = platform_get_irq(pdev, idx);
if (m->irq[idx] < 0) {
dev_err(dev, "Counter[%d] failed to get IRQ number\n", idx);
return m->irq[idx];
if (!m->irq_shared || idx == HIGH) {
m->irq[idx] = platform_get_irq(pdev, idx);
if (m->irq[idx] < 0) {
dev_err(dev, "Counter[%d] failed to get IRQ number\n",
idx);
return m->irq[idx];
}
}
m->num_counters++;
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,
"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);
if (ret)
return ret;