summaryrefslogtreecommitdiff
path: root/drivers/pinctrl/qcom/pinctrl-msm.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/pinctrl/qcom/pinctrl-msm.c')
-rw-r--r--drivers/pinctrl/qcom/pinctrl-msm.c73
1 files changed, 64 insertions, 9 deletions
diff --git a/drivers/pinctrl/qcom/pinctrl-msm.c b/drivers/pinctrl/qcom/pinctrl-msm.c
index 1a948c3f54b7..85858c1d56d0 100644
--- a/drivers/pinctrl/qcom/pinctrl-msm.c
+++ b/drivers/pinctrl/qcom/pinctrl-msm.c
@@ -22,6 +22,8 @@
#include <linux/reboot.h>
#include <linux/pm.h>
#include <linux/log2.h>
+#include <linux/qcom_scm.h>
+#include <linux/io.h>
#include <linux/soc/qcom/irq.h>
@@ -60,6 +62,8 @@ struct msm_pinctrl {
struct irq_chip irq_chip;
int irq;
+ bool intr_target_use_scm;
+
raw_spinlock_t lock;
DECLARE_BITMAP(dual_edge_irqs, MAX_NR_GPIO);
@@ -68,6 +72,7 @@ struct msm_pinctrl {
const struct msm_pinctrl_soc_data *soc;
void __iomem *regs[MAX_NR_TILES];
+ u32 phys_base[MAX_NR_TILES];
};
#define MSM_ACCESSOR(name) \
@@ -489,8 +494,8 @@ static int msm_gpio_get_direction(struct gpio_chip *chip, unsigned int offset)
val = msm_readl_ctl(pctrl, g);
- /* 0 = output, 1 = input */
- return val & BIT(g->oe_bit) ? 0 : 1;
+ return val & BIT(g->oe_bit) ? GPIO_LINE_DIRECTION_OUT :
+ GPIO_LINE_DIRECTION_IN;
}
static int msm_gpio_get(struct gpio_chip *chip, unsigned offset)
@@ -692,7 +697,7 @@ static void msm_gpio_update_dual_edge_pos(struct msm_pinctrl *pctrl,
pol = msm_readl_intr_cfg(pctrl, g);
pol ^= BIT(g->intr_polarity_bit);
- msm_writel_intr_cfg(val, pctrl, g);
+ msm_writel_intr_cfg(pol, pctrl, g);
val2 = msm_readl_io(pctrl, g) & BIT(g->in_bit);
intstat = msm_readl_intr_status(pctrl, g);
@@ -882,11 +887,30 @@ static int msm_gpio_irq_set_type(struct irq_data *d, unsigned int type)
else
clear_bit(d->hwirq, pctrl->dual_edge_irqs);
- /* Route interrupts to application cpu */
- val = msm_readl_intr_target(pctrl, g);
- val &= ~(7 << g->intr_target_bit);
- val |= g->intr_target_kpss_val << g->intr_target_bit;
- msm_writel_intr_target(val, pctrl, g);
+ /* Route interrupts to application cpu.
+ * With intr_target_use_scm interrupts are routed to
+ * application cpu using scm calls.
+ */
+ if (pctrl->intr_target_use_scm) {
+ u32 addr = pctrl->phys_base[0] + g->intr_target_reg;
+ int ret;
+
+ qcom_scm_io_readl(addr, &val);
+
+ val &= ~(7 << g->intr_target_bit);
+ val |= g->intr_target_kpss_val << g->intr_target_bit;
+
+ ret = qcom_scm_io_writel(addr, val);
+ if (ret)
+ dev_err(pctrl->dev,
+ "Failed routing %lu interrupt to Apps proc",
+ d->hwirq);
+ } else {
+ val = msm_readl_intr_target(pctrl, g);
+ val &= ~(7 << g->intr_target_bit);
+ val |= g->intr_target_kpss_val << g->intr_target_bit;
+ msm_writel_intr_target(val, pctrl, g);
+ }
/* Update configuration for gpio.
* RAW_STATUS_EN is left on for all gpio irqs. Due to the
@@ -1010,6 +1034,29 @@ static void msm_gpio_irq_relres(struct irq_data *d)
module_put(gc->owner);
}
+static int msm_gpio_irq_set_affinity(struct irq_data *d,
+ const struct cpumask *dest, bool force)
+{
+ struct gpio_chip *gc = irq_data_get_irq_chip_data(d);
+ struct msm_pinctrl *pctrl = gpiochip_get_data(gc);
+
+ if (d->parent_data && test_bit(d->hwirq, pctrl->skip_wake_irqs))
+ return irq_chip_set_affinity_parent(d, dest, force);
+
+ return 0;
+}
+
+static int msm_gpio_irq_set_vcpu_affinity(struct irq_data *d, void *vcpu_info)
+{
+ struct gpio_chip *gc = irq_data_get_irq_chip_data(d);
+ struct msm_pinctrl *pctrl = gpiochip_get_data(gc);
+
+ if (d->parent_data && test_bit(d->hwirq, pctrl->skip_wake_irqs))
+ return irq_chip_set_vcpu_affinity_parent(d, vcpu_info);
+
+ return 0;
+}
+
static void msm_gpio_irq_handler(struct irq_desc *desc)
{
struct gpio_chip *gc = irq_desc_get_handler_data(desc);
@@ -1108,6 +1155,8 @@ static int msm_gpio_init(struct msm_pinctrl *pctrl)
pctrl->irq_chip.irq_set_wake = msm_gpio_irq_set_wake;
pctrl->irq_chip.irq_request_resources = msm_gpio_irq_reqres;
pctrl->irq_chip.irq_release_resources = msm_gpio_irq_relres;
+ pctrl->irq_chip.irq_set_affinity = msm_gpio_irq_set_affinity;
+ pctrl->irq_chip.irq_set_vcpu_affinity = msm_gpio_irq_set_vcpu_affinity;
np = of_parse_phandle(pctrl->dev->of_node, "wakeup-parent", 0);
if (np) {
@@ -1240,6 +1289,9 @@ int msm_pinctrl_probe(struct platform_device *pdev,
pctrl->dev = &pdev->dev;
pctrl->soc = soc_data;
pctrl->chip = msm_gpio_template;
+ pctrl->intr_target_use_scm = of_device_is_compatible(
+ pctrl->dev->of_node,
+ "qcom,ipq8064-pinctrl");
raw_spin_lock_init(&pctrl->lock);
@@ -1252,9 +1304,12 @@ int msm_pinctrl_probe(struct platform_device *pdev,
return PTR_ERR(pctrl->regs[i]);
}
} else {
- pctrl->regs[0] = devm_platform_ioremap_resource(pdev, 0);
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ pctrl->regs[0] = devm_ioremap_resource(&pdev->dev, res);
if (IS_ERR(pctrl->regs[0]))
return PTR_ERR(pctrl->regs[0]);
+
+ pctrl->phys_base[0] = res->start;
}
msm_pinctrl_setup_pm_reset(pctrl);