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

Commit 07b2f400 authored by Raghavendra Kakarla's avatar Raghavendra Kakarla
Browse files

drivers: qcom: mpm: Add the mpm-gpio interrupt controller support



Add the mpm-gpio interrupt controller support for msm8953.

Change-Id: I0b97787d5639ef007bc8efc62c5663c9bee18872
Signed-off-by: default avatarRaghavendra Kakarla <rkakarla@codeaurora.org>
parent a5370b86
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 for 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 for 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>;
};
+152 −22
Original line number Diff line number Diff line
@@ -59,6 +59,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,19 +201,19 @@ static inline void msm_mpm_set_type(struct irq_data *d,
	}
}

static void msm_mpm_gic_chip_mask(struct irq_data *d)
static void msm_mpm_chip_mask(struct irq_data *d)
{
	msm_mpm_enable_irq(d, false);
	irq_chip_mask_parent(d);
}

static void msm_mpm_gic_chip_unmask(struct irq_data *d)
static void msm_mpm_chip_unmask(struct irq_data *d)
{
	msm_mpm_enable_irq(d, true);
	irq_chip_unmask_parent(d);
}

static int msm_mpm_gic_chip_set_type(struct irq_data *d, unsigned int type)
static int msm_mpm_chip_set_type(struct irq_data *d, unsigned int type)
{
	msm_mpm_set_type(d, type);
	return irq_chip_set_type_parent(d, type);
@@ -221,15 +222,70 @@ static int msm_mpm_gic_chip_set_type(struct irq_data *d, unsigned int type)
static struct irq_chip msm_mpm_gic_chip = {
	.name		= "mpm-gic",
	.irq_eoi	= irq_chip_eoi_parent,
	.irq_mask	= msm_mpm_gic_chip_mask,
	.irq_disable	= msm_mpm_gic_chip_mask,
	.irq_unmask	= msm_mpm_gic_chip_unmask,
	.irq_mask	= msm_mpm_chip_mask,
	.irq_disable	= msm_mpm_chip_mask,
	.irq_unmask	= msm_mpm_chip_unmask,
	.irq_retrigger	= irq_chip_retrigger_hierarchy,
	.irq_set_type	= msm_mpm_gic_chip_set_type,
	.irq_set_type	= msm_mpm_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_chip_mask,
	.irq_disable	= msm_mpm_chip_mask,
	.irq_unmask	= msm_mpm_chip_unmask,
	.irq_set_type	= msm_mpm_chip_set_type,
	.flags		= IRQCHIP_MASK_ON_SUSPEND | IRQCHIP_SKIP_SET_WAKE,
	.irq_retrigger          = irq_chip_retrigger_hierarchy,
	.irq_set_vcpu_affinity  = irq_chip_set_vcpu_affinity_parent,
	.irq_eoi                = irq_chip_eoi_parent,
	.irq_set_affinity	= irq_chip_set_affinity_parent,
};

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;
	struct irq_fwspec parent_fwspec;
	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);
	parent_fwspec = *fwspec;
	parent_fwspec.fwnode = domain->parent->fwnode;
	return irq_domain_alloc_irqs_parent(domain, virq, nr_irqs,
					    &parent_fwspec);
}

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,
@@ -296,16 +352,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 +468,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;

@@ -420,7 +481,7 @@ static irqreturn_t msm_mpm_irq(int irq, void *dev_id)
	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;
@@ -485,12 +546,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);
@@ -512,7 +579,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(
@@ -520,13 +588,75 @@ 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 mpm_gpio_chip_probe(struct platform_device *pdev)
{
	struct device_node *node, *parent;
	struct irq_domain *parent_domain;
	const struct of_device_id *id;

	node = pdev->dev.of_node;
	parent = of_irq_find_parent(node);
	if (!parent) {
		pr_err("%s(): no parent for mpm-gpio\n", node->full_name);
		return -ENXIO;
	}
	parent_domain = irq_find_host(parent);
	if (!parent_domain) {
		pr_err("unable to obtain gpio parent domain defer probe\n");
		return -EPROBE_DEFER;
	}
	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_add_hierarchy(
			parent_domain, 0, num_mpm_irqs, node,
			&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;
}

static const struct of_device_id msm_mpm_dt_match[] = {
	{ .compatible = "qcom,mpm-gpio"},
	{ },
};

static struct platform_driver msm_mpm_driver = {
	.probe = mpm_gpio_chip_probe,
	.driver = {
		.name = "qcom,mpm-gpio",
		.of_match_table = msm_mpm_dt_match,
	},
};

static int __init msm_mpm_gpio_init(void)
{
	return platform_driver_register(&msm_mpm_driver);
}

arch_initcall(msm_mpm_gpio_init)