From 3c0f19e80b8ede784582b7ba08cfc427bc8d5990 Mon Sep 17 00:00:00 2001 From: Maulik Shah Date: Fri, 4 Mar 2016 11:44:46 +0530 Subject: [PATCH] mpm-of: Support multiple mpm pin mapping to same gic interrupt Currently one gic interrupt is mapped to one mpm pin. Support multiple mpm pins to get enabled with single irq with client drivers using enable_irq_wake API. Change-Id: Iea575079c24ed0986b74fb6e86c7b8100474f19e Signed-off-by: Maulik Shah --- drivers/soc/qcom/mpm-of.c | 113 ++++++++++++++++++++++---------------- 1 file changed, 66 insertions(+), 47 deletions(-) diff --git a/drivers/soc/qcom/mpm-of.c b/drivers/soc/qcom/mpm-of.c index 118e77503f6f..93f2de8a59dd 100644 --- a/drivers/soc/qcom/mpm-of.c +++ b/drivers/soc/qcom/mpm-of.c @@ -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 * 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]; }; +#define MAX_MPM_PIN_PER_IRQ 2 static struct mpm_irqs unlisted_irqs[MSM_MPM_NR_IRQ_DOMAINS]; - static int num_mpm_irqs = MSM_MPM_NR_MPM_IRQS; static struct hlist_head *irq_hash; 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]; } -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; + int count = 0; hlist_for_each_entry(node, &irq_hash[hashfn(d->hwirq)], node) { if ((node->hwirq == d->hwirq) @@ -257,58 +258,71 @@ static inline uint16_t msm_mpm_get_irq_a2m(struct irq_data *d) */ if (node->pin != 0xff) 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( 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); + if (!d) return 0; - mpm_pin = msm_mpm_get_irq_a2m(d); + msm_mpm_get_irq_a2m(d, mpm_pins); - if (mpm_pin == 0xff) - return 0; + for (num = 0; num < MAX_MPM_PIN_PER_IRQ; num++) { - if (mpm_pin) { - uint32_t *mpm_irq_masks = wakeset ? + if (mpm_pins[num] == 0xff) + break; + + if (num && mpm_pins[num] == 0) + break; + + if (mpm_pins[num]) { + uint32_t *mpm_irq_masks = wakeset ? msm_mpm_wake_irq : msm_mpm_enabled_irq; - uint32_t index = MSM_MPM_IRQ_INDEX(mpm_pin); - uint32_t mask = MSM_MPM_IRQ_MASK(mpm_pin); + uint32_t index = MSM_MPM_IRQ_INDEX(mpm_pins[num]); + uint32_t mask = MSM_MPM_IRQ_MASK(mpm_pins[num]); - if (enable) - mpm_irq_masks[index] |= mask; - else - mpm_irq_masks[index] &= ~mask; - } else { - int i; - unsigned long *irq_apps; + if (enable) + mpm_irq_masks[index] |= mask; + else + mpm_irq_masks[index] &= ~mask; + } else { + int i; + unsigned long *irq_apps; - for (i = 0; i < MSM_MPM_NR_IRQ_DOMAINS; i++) { - if (d->domain == unlisted_irqs[i].domain) - break; - } + for (i = 0; i < MSM_MPM_NR_IRQ_DOMAINS; i++) { + if (d->domain == unlisted_irqs[i].domain) + break; + } - if (i == MSM_MPM_NR_IRQ_DOMAINS) - return 0; - irq_apps = wakeset ? unlisted_irqs[i].wakeup_irqs : + if (i == MSM_MPM_NR_IRQ_DOMAINS) + return 0; + + irq_apps = wakeset ? unlisted_irqs[i].wakeup_irqs : unlisted_irqs[i].enabled_irqs; - if (enable) - __set_bit(d->hwirq, irq_apps); - else - __clear_bit(d->hwirq, irq_apps); + if (enable) + __set_bit(d->hwirq, irq_apps); + else + __clear_bit(d->hwirq, irq_apps); - if ((msm_mpm_initialized & MSM_MPM_DEVICE_PROBED) + if ((msm_mpm_initialized & MSM_MPM_DEVICE_PROBED) && !wakeset && !msm_mpm_in_suspend) - complete(&wake_wq); + complete(&wake_wq); + } } 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( 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) - return 0; + for (num = 0; num < MAX_MPM_PIN_PER_IRQ; num++) { - if (mpm_irq) { - uint32_t index = MSM_MPM_IRQ_INDEX(mpm_irq); - uint32_t mask = MSM_MPM_IRQ_MASK(mpm_irq); + if (mpm_pins[num] == 0xff) + break; - if (index >= MSM_MPM_REG_WIDTH) - return -EFAULT; + if (mpm_pins[num]) { + uint32_t index = MSM_MPM_IRQ_INDEX(mpm_pins[num]); + uint32_t mask = MSM_MPM_IRQ_MASK(mpm_pins[num]); - msm_mpm_set_edge_ctl(mpm_irq, flow_type); + if (index >= MSM_MPM_REG_WIDTH) + return -EFAULT; - if (flow_type & IRQ_TYPE_LEVEL_HIGH) - msm_mpm_polarity[index] |= mask; - else - msm_mpm_polarity[index] &= ~mask; + msm_mpm_set_edge_ctl(mpm_pins[num], flow_type); + + if (flow_type & IRQ_TYPE_LEVEL_HIGH) + msm_mpm_polarity[index] |= mask; + else + msm_mpm_polarity[index] &= ~mask; + } } + return 0; }