in sun6i-msgbox.c [195:288]
static int sun6i_msgbox_probe(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
struct mbox_chan *chans;
struct reset_control *reset;
struct sun6i_msgbox *mbox;
int i, ret;
mbox = devm_kzalloc(dev, sizeof(*mbox), GFP_KERNEL);
if (!mbox)
return -ENOMEM;
chans = devm_kcalloc(dev, NUM_CHANS, sizeof(*chans), GFP_KERNEL);
if (!chans)
return -ENOMEM;
for (i = 0; i < NUM_CHANS; ++i)
chans[i].con_priv = mbox;
mbox->clk = devm_clk_get(dev, NULL);
if (IS_ERR(mbox->clk)) {
ret = PTR_ERR(mbox->clk);
dev_err(dev, "Failed to get clock: %d\n", ret);
return ret;
}
ret = clk_prepare_enable(mbox->clk);
if (ret) {
dev_err(dev, "Failed to enable clock: %d\n", ret);
return ret;
}
reset = devm_reset_control_get_exclusive(dev, NULL);
if (IS_ERR(reset)) {
ret = PTR_ERR(reset);
dev_err(dev, "Failed to get reset control: %d\n", ret);
goto err_disable_unprepare;
}
/*
* NOTE: We rely on platform firmware to preconfigure the channel
* directions, and we share this hardware block with other firmware
* that runs concurrently with Linux (e.g. a trusted monitor).
*
* Therefore, we do *not* assert the reset line if probing fails or
* when removing the device.
*/
ret = reset_control_deassert(reset);
if (ret) {
dev_err(dev, "Failed to deassert reset: %d\n", ret);
goto err_disable_unprepare;
}
mbox->regs = devm_platform_ioremap_resource(pdev, 0);
if (IS_ERR(mbox->regs)) {
ret = PTR_ERR(mbox->regs);
dev_err(dev, "Failed to map MMIO resource: %d\n", ret);
goto err_disable_unprepare;
}
/* Disable all IRQs for this end of the msgbox. */
writel(0, mbox->regs + LOCAL_IRQ_EN_REG);
ret = devm_request_irq(dev, irq_of_parse_and_map(dev->of_node, 0),
sun6i_msgbox_irq, 0, dev_name(dev), mbox);
if (ret) {
dev_err(dev, "Failed to register IRQ handler: %d\n", ret);
goto err_disable_unprepare;
}
mbox->controller.dev = dev;
mbox->controller.ops = &sun6i_msgbox_chan_ops;
mbox->controller.chans = chans;
mbox->controller.num_chans = NUM_CHANS;
mbox->controller.txdone_irq = false;
mbox->controller.txdone_poll = true;
mbox->controller.txpoll_period = 5;
spin_lock_init(&mbox->lock);
platform_set_drvdata(pdev, mbox);
ret = mbox_controller_register(&mbox->controller);
if (ret) {
dev_err(dev, "Failed to register controller: %d\n", ret);
goto err_disable_unprepare;
}
return 0;
err_disable_unprepare:
clk_disable_unprepare(mbox->clk);
return ret;
}