in master/i3c-master-cdns.c [1566:1663]
static int cdns_i3c_master_probe(struct platform_device *pdev)
{
struct cdns_i3c_master *master;
int ret, irq;
u32 val;
master = devm_kzalloc(&pdev->dev, sizeof(*master), GFP_KERNEL);
if (!master)
return -ENOMEM;
master->devdata = of_device_get_match_data(&pdev->dev);
if (!master->devdata)
return -EINVAL;
master->regs = devm_platform_ioremap_resource(pdev, 0);
if (IS_ERR(master->regs))
return PTR_ERR(master->regs);
master->pclk = devm_clk_get(&pdev->dev, "pclk");
if (IS_ERR(master->pclk))
return PTR_ERR(master->pclk);
master->sysclk = devm_clk_get(&pdev->dev, "sysclk");
if (IS_ERR(master->sysclk))
return PTR_ERR(master->sysclk);
irq = platform_get_irq(pdev, 0);
if (irq < 0)
return irq;
ret = clk_prepare_enable(master->pclk);
if (ret)
return ret;
ret = clk_prepare_enable(master->sysclk);
if (ret)
goto err_disable_pclk;
if (readl(master->regs + DEV_ID) != DEV_ID_I3C_MASTER) {
ret = -EINVAL;
goto err_disable_sysclk;
}
spin_lock_init(&master->xferqueue.lock);
INIT_LIST_HEAD(&master->xferqueue.list);
INIT_WORK(&master->hj_work, cdns_i3c_master_hj);
writel(0xffffffff, master->regs + MST_IDR);
writel(0xffffffff, master->regs + SLV_IDR);
ret = devm_request_irq(&pdev->dev, irq, cdns_i3c_master_interrupt, 0,
dev_name(&pdev->dev), master);
if (ret)
goto err_disable_sysclk;
platform_set_drvdata(pdev, master);
val = readl(master->regs + CONF_STATUS0);
/* Device ID0 is reserved to describe this master. */
master->maxdevs = CONF_STATUS0_DEVS_NUM(val);
master->free_rr_slots = GENMASK(master->maxdevs, 1);
val = readl(master->regs + CONF_STATUS1);
master->caps.cmdfifodepth = CONF_STATUS1_CMD_DEPTH(val);
master->caps.rxfifodepth = CONF_STATUS1_RX_DEPTH(val);
master->caps.txfifodepth = CONF_STATUS1_TX_DEPTH(val);
master->caps.ibirfifodepth = CONF_STATUS0_IBIR_DEPTH(val);
master->caps.cmdrfifodepth = CONF_STATUS0_CMDR_DEPTH(val);
spin_lock_init(&master->ibi.lock);
master->ibi.num_slots = CONF_STATUS1_IBI_HW_RES(val);
master->ibi.slots = devm_kcalloc(&pdev->dev, master->ibi.num_slots,
sizeof(*master->ibi.slots),
GFP_KERNEL);
if (!master->ibi.slots) {
ret = -ENOMEM;
goto err_disable_sysclk;
}
writel(IBIR_THR(1), master->regs + CMD_IBI_THR_CTRL);
writel(MST_INT_IBIR_THR, master->regs + MST_IER);
writel(DEVS_CTRL_DEV_CLR_ALL, master->regs + DEVS_CTRL);
ret = i3c_master_register(&master->base, &pdev->dev,
&cdns_i3c_master_ops, false);
if (ret)
goto err_disable_sysclk;
return 0;
err_disable_sysclk:
clk_disable_unprepare(master->sysclk);
err_disable_pclk:
clk_disable_unprepare(master->pclk);
return ret;
}