msm: smd: Add receive interrupt masking support
SMD is used for communicating power state with the RPM processor.
During a power-down sequence, sleep information is transferred to the
RPM processor and the system blocks and polls for a response. When the
RPM sends the response, it triggers an interrupt which then causes the
Application processor to abort the power-down sequence.
Add a new function that allows interrupts to be masked/unmasked for an
entire subsystem which allows the power code to mask interrupts while
powering down to prevent aborting the power-down sequence.
Change-Id: I52298f025032d47c7353dced6c1298766060ef0c
Signed-off-by: Eric Holmberg <eholmber@codeaurora.org>
diff --git a/arch/arm/mach-msm/smd.c b/arch/arm/mach-msm/smd.c
index 948dbbb..decee95 100644
--- a/arch/arm/mach-msm/smd.c
+++ b/arch/arm/mach-msm/smd.c
@@ -124,6 +124,7 @@
uint32_t out_bit_pos;
void __iomem *out_base;
uint32_t out_offset;
+ int irq_id;
};
struct interrupt_config {
@@ -2128,6 +2129,56 @@
}
EXPORT_SYMBOL(smd_disable_read_intr);
+/**
+ * Enable/disable receive interrupts for the remote processor used by a
+ * particular channel.
+ * @ch: open channel handle to use for the edge
+ * @mask: 1 = mask interrupts; 0 = unmask interrupts
+ * @returns: 0 for success; < 0 for failure
+ *
+ * Note that this enables/disables all interrupts from the remote subsystem for
+ * all channels. As such, it should be used with care and only for specific
+ * use cases such as power-collapse sequencing.
+ */
+int smd_mask_receive_interrupt(smd_channel_t *ch, bool mask)
+{
+ struct irq_chip *irq_chip;
+ struct irq_data *irq_data;
+ struct interrupt_config_item *int_cfg;
+
+ if (!ch)
+ return -EINVAL;
+
+ if (ch->type >= ARRAY_SIZE(edge_to_pids))
+ return -ENODEV;
+
+ int_cfg = &private_intr_config[edge_to_pids[ch->type].remote_pid].smd;
+
+ if (int_cfg->irq_id < 0)
+ return -ENODEV;
+
+ irq_chip = irq_get_chip(int_cfg->irq_id);
+ if (!irq_chip)
+ return -ENODEV;
+
+ irq_data = irq_get_irq_data(int_cfg->irq_id);
+ if (!irq_data)
+ return -ENODEV;
+
+ if (mask) {
+ SMx_POWER_INFO("SMD Masking interrupts from %s\n",
+ edge_to_pids[ch->type].subsys_name);
+ irq_chip->irq_mask(irq_data);
+ } else {
+ SMx_POWER_INFO("SMD Unmasking interrupts from %s\n",
+ edge_to_pids[ch->type].subsys_name);
+ irq_chip->irq_unmask(irq_data);
+ }
+
+ return 0;
+}
+EXPORT_SYMBOL(smd_mask_receive_interrupt);
+
int smd_wait_until_readable(smd_channel_t *ch, int bytes)
{
return -1;
@@ -3246,8 +3297,10 @@
);
if (ret < 0) {
platform_irq->irq_id = ret;
+ private_irq->irq_id = ret;
} else {
platform_irq->irq_id = irq_id;
+ private_irq->irq_id = irq_id;
ret_wake = enable_irq_wake(irq_id);
if (ret_wake < 0) {
pr_err("smd: enable_irq_wake failed on %s",