static int cdns_i3c_master_probe()

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;
}