Merge "mpm-of: Support multiple mpm pin mapping to same gic interrupt"

This commit is contained in:
Linux Build Service Account 2016-12-06 14:33:26 -08:00 committed by Gerrit - the friendly Code Review server
commit 480bfd599a

View file

@ -1,4 +1,4 @@
/* Copyright (c) 2010-2015, The Linux Foundation. All rights reserved. /* Copyright (c) 2010-2016, The Linux Foundation. All rights reserved.
* *
* This program is free software; you can redistribute it and/or modify * This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and * it under the terms of the GNU General Public License version 2 and
@ -69,8 +69,8 @@ struct mpm_irqs {
char domain_name[MAX_DOMAIN_NAME]; char domain_name[MAX_DOMAIN_NAME];
}; };
#define MAX_MPM_PIN_PER_IRQ 2
static struct mpm_irqs unlisted_irqs[MSM_MPM_NR_IRQ_DOMAINS]; static struct mpm_irqs unlisted_irqs[MSM_MPM_NR_IRQ_DOMAINS];
static int num_mpm_irqs = MSM_MPM_NR_MPM_IRQS; static int num_mpm_irqs = MSM_MPM_NR_MPM_IRQS;
static struct hlist_head *irq_hash; static struct hlist_head *irq_hash;
static unsigned int *msm_mpm_irqs_m2a; static unsigned int *msm_mpm_irqs_m2a;
@ -244,9 +244,10 @@ static inline unsigned int msm_mpm_get_irq_m2a(unsigned int pin)
return msm_mpm_irqs_m2a[pin]; return msm_mpm_irqs_m2a[pin];
} }
static inline uint16_t msm_mpm_get_irq_a2m(struct irq_data *d) static inline void msm_mpm_get_irq_a2m(struct irq_data *d, uint16_t *mpm_pins)
{ {
struct mpm_irqs_a2m *node = NULL; struct mpm_irqs_a2m *node = NULL;
int count = 0;
hlist_for_each_entry(node, &irq_hash[hashfn(d->hwirq)], node) { hlist_for_each_entry(node, &irq_hash[hashfn(d->hwirq)], node) {
if ((node->hwirq == d->hwirq) if ((node->hwirq == d->hwirq)
@ -257,31 +258,42 @@ static inline uint16_t msm_mpm_get_irq_a2m(struct irq_data *d)
*/ */
if (node->pin != 0xff) if (node->pin != 0xff)
msm_mpm_irqs_m2a[node->pin] = d->irq; msm_mpm_irqs_m2a[node->pin] = d->irq;
break; if (count >= MAX_MPM_PIN_PER_IRQ) {
count--;
__WARN();
}
mpm_pins[count] = node->pin;
count++;
} }
} }
return node ? node->pin : 0;
} }
static int msm_mpm_enable_irq_exclusive( static int msm_mpm_enable_irq_exclusive(
struct irq_data *d, bool enable, bool wakeset) struct irq_data *d, bool enable, bool wakeset)
{ {
uint16_t mpm_pin; uint16_t num = 0;
uint16_t mpm_pins[MAX_MPM_PIN_PER_IRQ] = {0};
WARN_ON(!d); WARN_ON(!d);
if (!d) if (!d)
return 0; return 0;
mpm_pin = msm_mpm_get_irq_a2m(d); msm_mpm_get_irq_a2m(d, mpm_pins);
if (mpm_pin == 0xff) for (num = 0; num < MAX_MPM_PIN_PER_IRQ; num++) {
return 0;
if (mpm_pin) { if (mpm_pins[num] == 0xff)
break;
if (num && mpm_pins[num] == 0)
break;
if (mpm_pins[num]) {
uint32_t *mpm_irq_masks = wakeset ? uint32_t *mpm_irq_masks = wakeset ?
msm_mpm_wake_irq : msm_mpm_enabled_irq; msm_mpm_wake_irq : msm_mpm_enabled_irq;
uint32_t index = MSM_MPM_IRQ_INDEX(mpm_pin); uint32_t index = MSM_MPM_IRQ_INDEX(mpm_pins[num]);
uint32_t mask = MSM_MPM_IRQ_MASK(mpm_pin); uint32_t mask = MSM_MPM_IRQ_MASK(mpm_pins[num]);
if (enable) if (enable)
mpm_irq_masks[index] |= mask; mpm_irq_masks[index] |= mask;
@ -298,6 +310,7 @@ static int msm_mpm_enable_irq_exclusive(
if (i == MSM_MPM_NR_IRQ_DOMAINS) if (i == MSM_MPM_NR_IRQ_DOMAINS)
return 0; return 0;
irq_apps = wakeset ? unlisted_irqs[i].wakeup_irqs : irq_apps = wakeset ? unlisted_irqs[i].wakeup_irqs :
unlisted_irqs[i].enabled_irqs; unlisted_irqs[i].enabled_irqs;
@ -310,6 +323,7 @@ static int msm_mpm_enable_irq_exclusive(
&& !wakeset && !msm_mpm_in_suspend) && !wakeset && !msm_mpm_in_suspend)
complete(&wake_wq); complete(&wake_wq);
} }
}
return 0; return 0;
} }
@ -337,27 +351,32 @@ static void msm_mpm_set_edge_ctl(int pin, unsigned int flow_type)
static int msm_mpm_set_irq_type_exclusive( static int msm_mpm_set_irq_type_exclusive(
struct irq_data *d, unsigned int flow_type) struct irq_data *d, unsigned int flow_type)
{ {
uint32_t mpm_irq; uint16_t num = 0;
uint16_t mpm_pins[MAX_MPM_PIN_PER_IRQ] = {0};
mpm_irq = msm_mpm_get_irq_a2m(d); msm_mpm_get_irq_a2m(d, mpm_pins);
if (mpm_irq == 0xff) for (num = 0; num < MAX_MPM_PIN_PER_IRQ; num++) {
return 0;
if (mpm_irq) { if (mpm_pins[num] == 0xff)
uint32_t index = MSM_MPM_IRQ_INDEX(mpm_irq); break;
uint32_t mask = MSM_MPM_IRQ_MASK(mpm_irq);
if (mpm_pins[num]) {
uint32_t index = MSM_MPM_IRQ_INDEX(mpm_pins[num]);
uint32_t mask = MSM_MPM_IRQ_MASK(mpm_pins[num]);
if (index >= MSM_MPM_REG_WIDTH) if (index >= MSM_MPM_REG_WIDTH)
return -EFAULT; return -EFAULT;
msm_mpm_set_edge_ctl(mpm_irq, flow_type); msm_mpm_set_edge_ctl(mpm_pins[num], flow_type);
if (flow_type & IRQ_TYPE_LEVEL_HIGH) if (flow_type & IRQ_TYPE_LEVEL_HIGH)
msm_mpm_polarity[index] |= mask; msm_mpm_polarity[index] |= mask;
else else
msm_mpm_polarity[index] &= ~mask; msm_mpm_polarity[index] &= ~mask;
} }
}
return 0; return 0;
} }