static int sprd_mbox_probe()

in sprd-mailbox.c [301:409]


static int sprd_mbox_probe(struct platform_device *pdev)
{
	struct device *dev = &pdev->dev;
	struct sprd_mbox_priv *priv;
	int ret, inbox_irq, outbox_irq, supp_irq;
	unsigned long id, supp;

	priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
	if (!priv)
		return -ENOMEM;

	priv->dev = dev;
	mutex_init(&priv->lock);

	/*
	 * Unisoc mailbox uses an inbox to send messages to the target
	 * core, and uses (an) outbox(es) to receive messages from other
	 * cores.
	 *
	 * Thus in general the mailbox controller supplies 2 different
	 * register addresses and IRQ numbers for inbox and outbox.
	 *
	 * If necessary, a supplementary inbox could be enabled optionally
	 * with an independent FIFO and an extra interrupt.
	 */
	priv->inbox_base = devm_platform_ioremap_resource(pdev, 0);
	if (IS_ERR(priv->inbox_base))
		return PTR_ERR(priv->inbox_base);

	priv->outbox_base = devm_platform_ioremap_resource(pdev, 1);
	if (IS_ERR(priv->outbox_base))
		return PTR_ERR(priv->outbox_base);

	priv->clk = devm_clk_get(dev, "enable");
	if (IS_ERR(priv->clk)) {
		dev_err(dev, "failed to get mailbox clock\n");
		return PTR_ERR(priv->clk);
	}

	ret = clk_prepare_enable(priv->clk);
	if (ret)
		return ret;

	ret = devm_add_action_or_reset(dev, sprd_mbox_disable, priv);
	if (ret) {
		dev_err(dev, "failed to add mailbox disable action\n");
		return ret;
	}

	inbox_irq = platform_get_irq_byname(pdev, "inbox");
	if (inbox_irq < 0)
		return inbox_irq;

	ret = devm_request_irq(dev, inbox_irq, sprd_mbox_inbox_isr,
			       IRQF_NO_SUSPEND, dev_name(dev), priv);
	if (ret) {
		dev_err(dev, "failed to request inbox IRQ: %d\n", ret);
		return ret;
	}

	outbox_irq = platform_get_irq_byname(pdev, "outbox");
	if (outbox_irq < 0)
		return outbox_irq;

	ret = devm_request_irq(dev, outbox_irq, sprd_mbox_outbox_isr,
			       IRQF_NO_SUSPEND, dev_name(dev), priv);
	if (ret) {
		dev_err(dev, "failed to request outbox IRQ: %d\n", ret);
		return ret;
	}

	/* Supplementary outbox IRQ is optional */
	supp_irq = platform_get_irq_byname(pdev, "supp-outbox");
	if (supp_irq > 0) {
		ret = devm_request_irq(dev, supp_irq, sprd_mbox_supp_isr,
				       IRQF_NO_SUSPEND, dev_name(dev), priv);
		if (ret) {
			dev_err(dev, "failed to request outbox IRQ: %d\n", ret);
			return ret;
		}

		supp = (unsigned long) of_device_get_match_data(dev);
		if (!supp) {
			dev_err(dev, "no supplementary outbox specified\n");
			return -ENODEV;
		}
		priv->supp_base = priv->outbox_base + (SPRD_OUTBOX_BASE_SPAN * supp);
	}

	/* Get the default outbox FIFO depth */
	priv->outbox_fifo_depth =
		readl(priv->outbox_base + SPRD_MBOX_FIFO_DEPTH) + 1;
	priv->mbox.dev = dev;
	priv->mbox.chans = &priv->chan[0];
	priv->mbox.num_chans = SPRD_MBOX_CHAN_MAX;
	priv->mbox.ops = &sprd_mbox_ops;
	priv->mbox.txdone_irq = true;

	for (id = 0; id < SPRD_MBOX_CHAN_MAX; id++)
		priv->chan[id].con_priv = (void *)id;

	ret = devm_mbox_controller_register(dev, &priv->mbox);
	if (ret) {
		dev_err(dev, "failed to register mailbox: %d\n", ret);
		return ret;
	}

	return 0;
}