#include <linux/clk.h>
#include <linux/rockchip-mailbox.h>
+#include <linux/scpi_protocol.h>
+
+#define MAILBOX_VERSION "V1.00"
#define MAILBOX_A2B_INTEN 0x00
#define MAILBOX_A2B_STATUS 0x04
struct rockchip_mbox_chan *chans;
};
+#define MBOX_CHAN_NUMS 4
+int idx_map_irq[MBOX_CHAN_NUMS] = {0, 0, 0, 0};
+
static inline int chan_to_idx(struct rockchip_mbox *mb,
struct mbox_chan *chan)
{
static irqreturn_t rockchip_mbox_irq(int irq, void *dev_id)
{
+ int idx;
struct rockchip_mbox *mb = (struct rockchip_mbox *)dev_id;
u32 status = readl_relaxed(mb->mbox_base + MAILBOX_B2A_STATUS);
- int idx;
for (idx = 0; idx < mb->mbox.num_chans; idx++) {
- struct rockchip_mbox_msg *msg = mb->chans[idx].msg;
+ if ((status & (1 << idx)) && (irq == idx_map_irq[idx])) {
+ /* Clear mbox interrupt */
+ writel_relaxed(1 << idx,
+ mb->mbox_base + MAILBOX_B2A_STATUS);
+ return IRQ_WAKE_THREAD;
+ }
+ }
- /* Clear mbox interrupt */
- writel_relaxed(1 << idx, mb->mbox_base + MAILBOX_B2A_STATUS);
+ return IRQ_NONE;
+}
- if (!(status & (1 << idx)))
+static irqreturn_t rockchip_mbox_isr(int irq, void *dev_id)
+{
+ int idx;
+ struct rockchip_mbox_msg *msg = NULL;
+ struct rockchip_mbox *mb = (struct rockchip_mbox *)dev_id;
+
+ for (idx = 0; idx < mb->mbox.num_chans; idx++) {
+ if (irq != idx_map_irq[idx])
continue;
- if (!msg)
- continue; /* spurious */
+
+ msg = mb->chans[idx].msg;
+ if (!msg) {
+ dev_err(mb->mbox.dev,
+ "Chan[%d]: B2A message is NULL\n", idx);
+ break; /* spurious */
+ }
if (msg->rx_buf)
memcpy(msg->rx_buf,
dev_dbg(mb->mbox.dev, "Chan[%d]: B2A message, cmd 0x%08x\n",
idx, msg->cmd);
+
+ break;
}
return IRQ_HANDLED;
};
MODULE_DEVICE_TABLE(of, rockchp_mbox_of_match);
+#ifdef CONFIG_PM
+static int rockchip_mbox_suspend(struct platform_device *pdev,
+ pm_message_t state)
+{
+ struct rockchip_mbox *mb = platform_get_drvdata(pdev);
+
+ if (scpi_sys_set_mcu_state_suspend())
+ dev_err(mb->mbox.dev, "scpi_sys_set_mcu_state_suspend timeout.\n");
+ return 0;
+}
+
+static int rockchip_mbox_resume(struct platform_device *pdev)
+{
+ struct rockchip_mbox *mb = platform_get_drvdata(pdev);
+
+ writel_relaxed((1 << mb->mbox.num_chans) - 1,
+ mb->mbox_base + MAILBOX_B2A_INTEN);
+
+ if (scpi_sys_set_mcu_state_resume())
+ dev_err(mb->mbox.dev, "scpi_sys_set_mcu_state_resume timeout.\n");
+ return 0;
+}
+#endif /* CONFIG_PM */
+
static int rockchip_mbox_probe(struct platform_device *pdev)
{
struct rockchip_mbox *mb;
struct resource *res;
int ret, irq, i;
+ dev_info(&pdev->dev,
+ "Rockchip mailbox initialize, version: "MAILBOX_VERSION"\n");
+
if (!pdev->dev.of_node)
return -ENODEV;
if (irq < 0)
return irq;
- ret = devm_request_threaded_irq(&pdev->dev, irq, NULL,
- rockchip_mbox_irq, IRQF_ONESHOT,
+ ret = devm_request_threaded_irq(&pdev->dev, irq,
+ rockchip_mbox_irq,
+ rockchip_mbox_isr, IRQF_ONESHOT,
dev_name(&pdev->dev), mb);
if (ret < 0)
return ret;
mb->chans[i].idx = i;
mb->chans[i].mb = mb;
mb->chans[i].msg = NULL;
+ idx_map_irq[i] = irq;
}
/* Enable all B2A interrupts */
static struct platform_driver rockchip_mbox_driver = {
.probe = rockchip_mbox_probe,
.remove = rockchip_mbox_remove,
+#ifdef CONFIG_PM
+ .suspend = rockchip_mbox_suspend,
+ .resume = rockchip_mbox_resume,
+#endif /* CONFIG_PM */
.driver = {
.name = "rockchip-mailbox",
.of_match_table = of_match_ptr(rockchip_mbox_of_match),