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

Commit 6b8fa5d8 authored by qctecmdr Service's avatar qctecmdr Service Committed by Gerrit - the friendly Code Review server
Browse files

Merge "drivers: irqchip: mpm: Clear pending interrupts in mpm exit sequence"

parents 14943829 19a85e28
Loading
Loading
Loading
Loading
+41 −14
Original line number Diff line number Diff line
@@ -8,13 +8,16 @@ replays it to the subsystem interrupt controller after it becomes operational.

Platform interrupt controller MPM is next in hierarchy, followed by others.

This defines 2 interrupt controllers to monitor the interrupts when the system is asleep:

One to monitor the wakeup capable gic interrupts called wakegic.

Properties:

- compatible:
	Usage: required
	Value type: <string>
	Definition: Should contain "qcom,mpm" for mpm pin data
	and the respective target compatible flag.
	Definition: Should contain "qcom,mpm-gic" and the respective target compatible flag.

- interrupts:
	Usage: required
@@ -48,18 +51,42 @@ Properties:

Example:

mpm: mpm@7781b8 {
	compatible = "qcom,mpm";
wakegic: wake-gic@7781b8 {
	compatible = "qcom,mpm-gic", "qcom,mpm-gic-msm8953";
	interrupts = <GIC_SPI 171 IRQ_TYPE_EDGE_RISING>;
	reg = <0x7781b8 0x1000>,
	    <0x17911008 0x4>;   /* MSM_APCS_GCC_BASE 4K */
	reg = <0x601d4 0x1000>,
	    <0xb011008 0x4>;  /* MSM_APCS_GCC_BASE 4K */
	reg-names = "vmpm", "ipc";
	qcom,num-mpm-irqs = <96>;

	wakegic: wake-gic {
		compatible = "qcom,mpm-gic", "qcom,mpm-gic-msm8953";
	interrupt-controller;
		#interrupt-cells = <3>;
	interrupt-parent = <&intc>;
	#interrupt-cells = <3>;
};


One to monitor the wakeup capable gpio interrupts called wakegpio.

properties:

- compatible:
	Usage: required
	Value type: <string>
	Definition: Should contain "qcom,mpm-gpio" and the respective target compatible flag.

- interrupt-parent:
	Usage: required
	Value type: <phandle>
	Definition: Specifies the interrupt parent necessary for hierarchical domain to operate.

- interrupt-controller:
	Usage: required
	Value type: <bool>
	Definition: Identifies the node as an interrupt controller.

Example:

wakegpio: wake-gpio {
	compatible = "qcom,mpm-gpio", "qcom,mpm-gpio-msm8953";
	interrupt-controller;
	interrupt-parent = <&tlmm>;
	#interrupt-cells = <2>;
};
+153 −16
Original line number Diff line number Diff line
@@ -20,6 +20,7 @@
#include <linux/irq.h>
#include <linux/tick.h>
#include <linux/irqchip.h>
#include <linux/irqchip/arm-gic-v3.h>
#include <linux/irqdomain.h>
#include <linux/interrupt.h>
#include<linux/ktime.h>
@@ -59,6 +60,7 @@ struct msm_mpm_device_data {
	void __iomem *mpm_ipc_reg;
	irq_hw_number_t ipc_irq;
	struct irq_domain *gic_chip_domain;
	struct irq_domain *gpio_chip_domain;
};

static int msm_pm_sleep_time_override;
@@ -200,6 +202,22 @@ static inline void msm_mpm_set_type(struct irq_data *d,
	}
}

static void msm_mpm_gpio_chip_mask(struct irq_data *d)
{
	msm_mpm_enable_irq(d, false);
}

static void msm_mpm_gpio_chip_unmask(struct irq_data *d)
{
	msm_mpm_enable_irq(d, true);
}

static int msm_mpm_gpio_chip_set_type(struct irq_data *d, unsigned int type)
{
	msm_mpm_set_type(d, type);
	return 0;
}

static void msm_mpm_gic_chip_mask(struct irq_data *d)
{
	msm_mpm_enable_irq(d, false);
@@ -227,9 +245,58 @@ static struct irq_chip msm_mpm_gic_chip = {
	.irq_retrigger	= irq_chip_retrigger_hierarchy,
	.irq_set_type	= msm_mpm_gic_chip_set_type,
	.flags		= IRQCHIP_MASK_ON_SUSPEND | IRQCHIP_SKIP_SET_WAKE,
#ifdef CONFIG_SMP
	.irq_set_affinity	= irq_chip_set_affinity_parent,
#endif
};

static struct irq_chip msm_mpm_gpio_chip = {
	.name		= "mpm-gpio",
	.irq_mask	= msm_mpm_gpio_chip_mask,
	.irq_disable	= msm_mpm_gpio_chip_mask,
	.irq_unmask	= msm_mpm_gpio_chip_unmask,
	.irq_set_type	= msm_mpm_gpio_chip_set_type,
	.flags		= IRQCHIP_MASK_ON_SUSPEND | IRQCHIP_SKIP_SET_WAKE,
	.irq_retrigger          = irq_chip_retrigger_hierarchy,
};

static int msm_mpm_gpio_chip_translate(struct irq_domain *d,
		struct irq_fwspec *fwspec,
		unsigned long *hwirq,
		unsigned int *type)
{
	if (is_of_node(fwspec->fwnode)) {
		if (fwspec->param_count != 2)
			return -EINVAL;
		*hwirq = fwspec->param[0];
		*type = fwspec->param[1];
		return 0;
	}
	return -EINVAL;
}

static int msm_mpm_gpio_chip_alloc(struct irq_domain *domain,
		unsigned int virq,
		unsigned int nr_irqs,
		void *data)
{
	int ret = 0;
	struct irq_fwspec *fwspec = data;
	irq_hw_number_t hwirq;
	unsigned int type = IRQ_TYPE_NONE;

	ret = msm_mpm_gpio_chip_translate(domain, fwspec, &hwirq, &type);
	if (ret)
		return ret;

	irq_domain_set_hwirq_and_chip(domain, virq, hwirq,
				&msm_mpm_gpio_chip, NULL);

	return 0;
}

static const struct irq_domain_ops msm_mpm_gpio_chip_domain_ops = {
	.translate	= msm_mpm_gpio_chip_translate,
	.alloc		= msm_mpm_gpio_chip_alloc,
	.free		= irq_domain_free_irqs_common,
};

static int msm_mpm_gic_chip_translate(struct irq_domain *d,
@@ -240,10 +307,34 @@ static int msm_mpm_gic_chip_translate(struct irq_domain *d,
	if (is_of_node(fwspec->fwnode)) {
		if (fwspec->param_count < 3)
			return -EINVAL;

		switch (fwspec->param[0]) {
		case 0:			/* SPI */
			*hwirq = fwspec->param[1] + 32;
			break;
		case 1:			/* PPI */
			*hwirq = fwspec->param[1] + 16;
			break;
		case GIC_IRQ_TYPE_LPI:	/* LPI */
			*hwirq = fwspec->param[1];
			break;
		default:
			return -EINVAL;
		}

		*type = fwspec->param[2] & IRQ_TYPE_SENSE_MASK;
		return 0;
	}

	if (is_fwnode_irqchip(fwspec->fwnode)) {
		if (fwspec->param_count != 2)
			return -EINVAL;

		*hwirq = fwspec->param[0];
		*type = fwspec->param[1];
		return 0;
	}

	return -EINVAL;
}

@@ -296,16 +387,21 @@ static void msm_mpm_enter_sleep(struct cpumask *cpumask)
	irq_set_affinity(msm_mpm_dev_data.ipc_irq, cpumask);
}

static int msm_get_mpm_pin_map(unsigned int mpm_irq)
static int msm_get_apps_irq(unsigned int mpm_irq)
{
	struct mpm_pin *mpm_gic_pin_map = NULL;
	struct mpm_pin *mpm_pin = NULL;
	int apps_irq;

	mpm_gic_pin_map = (struct mpm_pin *)
	mpm_pin = (struct mpm_pin *)
		msm_mpm_dev_data.gic_chip_domain->host_data;
	apps_irq = msm_get_irq_pin(mpm_irq, mpm_gic_pin_map);
	apps_irq = msm_get_irq_pin(mpm_irq, mpm_pin);
	if (apps_irq >= 0)
		return apps_irq;

	mpm_pin = (struct mpm_pin *)
		msm_mpm_dev_data.gpio_chip_domain->host_data;
	return  msm_get_irq_pin(mpm_irq, mpm_pin);

}

static void system_pm_exit_sleep(void)
@@ -407,7 +503,7 @@ static irqreturn_t msm_mpm_irq(int irq, void *dev_id)
		trace_mpm_wakeup_pending_irqs(i, pending);
		for_each_set_bit(k, &pending, 32) {
			mpm_irq = 32 * i + k;
			apps_irq = msm_get_mpm_pin_map(mpm_irq);
			apps_irq = msm_get_apps_irq(mpm_irq);
			desc = apps_irq ?
				irq_to_desc(apps_irq) : NULL;

@@ -416,11 +512,13 @@ static irqreturn_t msm_mpm_irq(int irq, void *dev_id)
						IRQCHIP_STATE_PENDING, true);

		}

		msm_mpm_write(MPM_REG_STATUS, i, 0);
	}
	return IRQ_HANDLED;
}

static int msm_mpm_probe(struct device_node *node)
static int msm_mpm_init(struct device_node *node)
{
	struct msm_mpm_device_data *dev = &msm_mpm_dev_data;
	int ret = 0;
@@ -492,12 +590,18 @@ static const struct of_device_id mpm_gic_chip_data_table[] = {
};
MODULE_DEVICE_TABLE(of, mpm_gic_chip_data_table);

static const struct of_device_id mpm_gpio_chip_data_table[] = {
	{}
};

MODULE_DEVICE_TABLE(of, mpm_gpio_chip_data_table);

static int __init mpm_gic_chip_init(struct device_node *node,
					struct device_node *parent)
{
	struct irq_domain *parent_domain;
	const struct of_device_id *id;
	struct device_node *parent_node;
	int ret;

	if (!parent) {
		pr_err("%s(): no parent for mpm-gic\n", node->full_name);
@@ -519,7 +623,8 @@ static int __init mpm_gic_chip_init(struct device_node *node,
	id = of_match_node(mpm_gic_chip_data_table, node);
	if (!id) {
		pr_err("can not find mpm_gic_data_table of_node\n");
		return -ENODEV;
		ret = -ENODEV;
		goto mpm_map_err;
	}

	msm_mpm_dev_data.gic_chip_domain = irq_domain_add_hierarchy(
@@ -527,13 +632,45 @@ static int __init mpm_gic_chip_init(struct device_node *node,
			&msm_mpm_gic_chip_domain_ops, (void *)id->data);
	if (!msm_mpm_dev_data.gic_chip_domain) {
		pr_err("gic domain add failed\n");
		return -ENOMEM;
		ret = -ENOMEM;
		goto mpm_map_err;
	}

	msm_mpm_dev_data.gic_chip_domain->name = "qcom,mpm-gic";

	parent_node = of_get_parent(node);
	return msm_mpm_probe(parent_node);
	ret = msm_mpm_init(node);
	if (!ret)
		return ret;
	irq_domain_remove(msm_mpm_dev_data.gic_chip_domain);

mpm_map_err:
	kfree(mpm_to_irq);
	return ret;
}

IRQCHIP_DECLARE(mpm_gic_chip, "qcom,mpm-gic", mpm_gic_chip_init);

static int __init mpm_gpio_chip_init(struct device_node *node,
					struct device_node *parent)
{
	const struct of_device_id *id;

	id = of_match_node(mpm_gpio_chip_data_table, node);
	if (!id) {
		pr_err("match_table not found for mpm-gpio\n");
		return -ENODEV;
	}

	msm_mpm_dev_data.gpio_chip_domain = irq_domain_create_linear(
			of_node_to_fwnode(node), num_mpm_irqs,
			&msm_mpm_gpio_chip_domain_ops, (void *)id->data);

	if (!msm_mpm_dev_data.gpio_chip_domain)
		return -ENOMEM;

	msm_mpm_dev_data.gpio_chip_domain->name = "qcom,mpm-gpio";

	return 0;
}

IRQCHIP_DECLARE(mpm_gpio_chip, "qcom,mpm-gpio", mpm_gpio_chip_init);
+151 −12
Original line number Diff line number Diff line
@@ -25,6 +25,7 @@
#include <linux/pinctrl/pinmux.h>
#include <linux/pinctrl/pinconf.h>
#include <linux/pinctrl/pinconf-generic.h>
#include <linux/of_irq.h>
#include <linux/slab.h>
#include <linux/gpio.h>
#include <linux/interrupt.h>
@@ -610,6 +611,9 @@ static void msm_gpio_irq_mask(struct irq_data *d)
	clear_bit(d->hwirq, pctrl->enabled_irqs);

	raw_spin_unlock_irqrestore(&pctrl->lock, flags);

	if (d->parent_data)
		irq_chip_mask_parent(d);
}

static void msm_gpio_irq_enable(struct irq_data *d)
@@ -638,6 +642,9 @@ static void msm_gpio_irq_enable(struct irq_data *d)
	set_bit(d->hwirq, pctrl->enabled_irqs);

	raw_spin_unlock_irqrestore(&pctrl->lock, flags);

	if (d->parent_data)
		irq_chip_enable_parent(d);
}

static void msm_gpio_irq_unmask(struct irq_data *d)
@@ -659,6 +666,9 @@ static void msm_gpio_irq_unmask(struct irq_data *d)
	set_bit(d->hwirq, pctrl->enabled_irqs);

	raw_spin_unlock_irqrestore(&pctrl->lock, flags);

	if (d->parent_data)
		irq_chip_unmask_parent(d);
}

static void msm_gpio_irq_ack(struct irq_data *d)
@@ -772,6 +782,9 @@ static int msm_gpio_irq_set_type(struct irq_data *d, unsigned int type)

	raw_spin_unlock_irqrestore(&pctrl->lock, flags);

	if (d->parent_data)
		irq_chip_set_type_parent(d, type);

	if (type & (IRQ_TYPE_LEVEL_LOW | IRQ_TYPE_LEVEL_HIGH))
		irq_set_handler_locked(d, handle_level_irq);
	else if (type & (IRQ_TYPE_EDGE_FALLING | IRQ_TYPE_EDGE_RISING))
@@ -792,9 +805,35 @@ static int msm_gpio_irq_set_wake(struct irq_data *d, unsigned int on)

	raw_spin_unlock_irqrestore(&pctrl->lock, flags);

	if (d->parent_data)
		irq_chip_set_wake_parent(d, on);

	return 0;
}

static int msm_gpiochip_irq_reqres(struct irq_data *d)
{
	struct gpio_chip *chip = irq_data_get_irq_chip_data(d);

	if (!try_module_get(chip->owner))
		return -ENODEV;

	if (gpiochip_lock_as_irq(chip, d->hwirq)) {
		pr_err("unable to lock HW IRQ %lu for IRQ\n", d->hwirq);
		module_put(chip->owner);
		return -EINVAL;
	}
	return 0;
}

static void msm_gpiochip_irq_relres(struct irq_data *d)
{
	struct gpio_chip *chip = irq_data_get_irq_chip_data(d);

	gpiochip_unlock_as_irq(chip, d->hwirq);
	module_put(chip->owner);
}

static struct irq_chip msm_gpio_irq_chip = {
	.name           = "msmgpio",
	.irq_enable     = msm_gpio_irq_enable,
@@ -803,6 +842,61 @@ static struct irq_chip msm_gpio_irq_chip = {
	.irq_ack        = msm_gpio_irq_ack,
	.irq_set_type   = msm_gpio_irq_set_type,
	.irq_set_wake   = msm_gpio_irq_set_wake,
	.irq_request_resources    = msm_gpiochip_irq_reqres,
	.irq_release_resources	  = msm_gpiochip_irq_relres,
	.flags                    = IRQCHIP_MASK_ON_SUSPEND |
					IRQCHIP_SKIP_SET_WAKE,
};

static void msm_gpio_domain_set_info(struct irq_domain *d, unsigned int irq,
							irq_hw_number_t hwirq)
{
	struct gpio_chip *gc = d->host_data;

	irq_domain_set_info(d, irq, hwirq, gc->irqchip, d->host_data,
		gc->irq_handler, NULL, NULL);

	if (gc->can_sleep)
		irq_set_nested_thread(irq, 1);

	irq_set_noprobe(irq);
}

static int msm_gpio_domain_translate(struct irq_domain *d,
	struct irq_fwspec *fwspec, unsigned long *hwirq, unsigned int *type)
{
	if (is_of_node(fwspec->fwnode)) {
		if (fwspec->param_count < 2)
			return -EINVAL;
		if (hwirq)
			*hwirq = fwspec->param[0];
		if (type)
			*type = fwspec->param[1] & IRQ_TYPE_SENSE_MASK;
		return 0;
	}

	return -EINVAL;
}

static int msm_gpio_domain_alloc(struct irq_domain *domain, unsigned int virq,
					unsigned int nr_irqs, void *arg)
{
	int ret;
	irq_hw_number_t hwirq;
	struct irq_fwspec *fwspec = arg;

	ret = msm_gpio_domain_translate(domain, fwspec, &hwirq, NULL);
	if (ret)
		return ret;

	msm_gpio_domain_set_info(domain, virq, hwirq);
	return ret;
}

static const struct irq_domain_ops msm_gpio_domain_ops = {
	.translate	= msm_gpio_domain_translate,
	.alloc		= msm_gpio_domain_alloc,
	.free		= irq_domain_free_irqs_top,
};

static bool is_gpio_dual_edge(struct irq_data *d, irq_hw_number_t *dir_conn_irq)
@@ -1211,11 +1305,25 @@ static void msm_gpio_setup_dir_connects(struct msm_pinctrl *pctrl)
	}
}

static int msm_gpiochip_to_irq(struct gpio_chip *chip, unsigned int offset)
{
	struct irq_fwspec fwspec;

	fwspec.fwnode = of_node_to_fwnode(chip->of_node);
	fwspec.param[0] = offset;
	fwspec.param[1] = IRQ_TYPE_NONE;
	fwspec.param_count = 2;

	return irq_create_fwspec_mapping(&fwspec);
}

static int msm_gpio_init(struct msm_pinctrl *pctrl)
{
	struct gpio_chip *chip;
	int ret;
	unsigned ngpio = pctrl->soc->ngpios;
	struct device_node *irq_parent = NULL;
	struct irq_domain *domain_parent;

	if (WARN_ON(ngpio > MAX_NR_GPIO))
		return -EINVAL;
@@ -1227,6 +1335,11 @@ static int msm_gpio_init(struct msm_pinctrl *pctrl)
	chip->parent = pctrl->dev;
	chip->owner = THIS_MODULE;
	chip->of_node = pctrl->dev->of_node;
	chip->irqchip = &msm_gpio_irq_chip;
	chip->irq_handler = handle_fasteoi_irq;
	chip->irq_default_type = IRQ_TYPE_NONE;
	chip->to_irq = msm_gpiochip_to_irq;
	chip->lock_key = NULL;

	ret = gpiochip_add_data(&pctrl->chip, pctrl);
	if (ret) {
@@ -1241,6 +1354,32 @@ static int msm_gpio_init(struct msm_pinctrl *pctrl)
		return ret;
	}

	irq_parent = of_irq_find_parent(chip->of_node);
	if (of_device_is_compatible(irq_parent, "qcom,mpm-gpio")) {
		chip->irqchip = &msm_gpio_irq_chip;
		chip->irq_handler = handle_fasteoi_irq;
		chip->irq_default_type = IRQ_TYPE_NONE;
		chip->to_irq = msm_gpiochip_to_irq;
		chip->lock_key = NULL;
		domain_parent = irq_find_host(irq_parent);
		if (!domain_parent) {
			pr_err("unable to find parent domain\n");
			gpiochip_remove(&pctrl->chip);
			return -ENXIO;
		}

		chip->irqdomain = irq_domain_add_hierarchy(domain_parent, 0,
							chip->ngpio,
							chip->of_node,
							&msm_gpio_domain_ops,
							chip);
		if (!chip->irqdomain) {
			dev_err(pctrl->dev, "Failed to add irqchip to gpiochip\n");
			chip->irqchip = NULL;
			gpiochip_remove(&pctrl->chip);
			return -ENXIO;
		}
	} else {
		ret = gpiochip_irqchip_add(chip,
					&msm_gpio_irq_chip,
					0,
@@ -1249,11 +1388,11 @@ static int msm_gpio_init(struct msm_pinctrl *pctrl)
		if (ret) {
			dev_err(pctrl->dev, "Failed to add irqchip to gpiochip\n");
			gpiochip_remove(&pctrl->chip);
		return -ENOSYS;
			return ret;
		}

	gpiochip_set_chained_irqchip(chip, &msm_gpio_irq_chip, pctrl->irq,
				     msm_gpio_irq_handler);
	}
	gpiochip_set_chained_irqchip(chip, &msm_gpio_irq_chip,
				pctrl->irq, msm_gpio_irq_handler);

	msm_gpio_setup_dir_connects(pctrl);
	return 0;