static int qcom_slim_probe()

in qcom-ctrl.c [487:631]


static int qcom_slim_probe(struct platform_device *pdev)
{
	struct qcom_slim_ctrl *ctrl;
	struct slim_controller *sctrl;
	struct resource *slim_mem;
	int ret, ver;

	ctrl = devm_kzalloc(&pdev->dev, sizeof(*ctrl), GFP_KERNEL);
	if (!ctrl)
		return -ENOMEM;

	ctrl->hclk = devm_clk_get(&pdev->dev, "iface");
	if (IS_ERR(ctrl->hclk))
		return PTR_ERR(ctrl->hclk);

	ctrl->rclk = devm_clk_get(&pdev->dev, "core");
	if (IS_ERR(ctrl->rclk))
		return PTR_ERR(ctrl->rclk);

	ret = clk_set_rate(ctrl->rclk, SLIM_ROOT_FREQ);
	if (ret) {
		dev_err(&pdev->dev, "ref-clock set-rate failed:%d\n", ret);
		return ret;
	}

	ctrl->irq = platform_get_irq(pdev, 0);
	if (!ctrl->irq) {
		dev_err(&pdev->dev, "no slimbus IRQ\n");
		return -ENODEV;
	}

	sctrl = &ctrl->ctrl;
	sctrl->dev = &pdev->dev;
	ctrl->dev = &pdev->dev;
	platform_set_drvdata(pdev, ctrl);
	dev_set_drvdata(ctrl->dev, ctrl);

	slim_mem = platform_get_resource_byname(pdev, IORESOURCE_MEM, "ctrl");
	ctrl->base = devm_ioremap_resource(ctrl->dev, slim_mem);
	if (IS_ERR(ctrl->base))
		return PTR_ERR(ctrl->base);

	sctrl->set_laddr = qcom_set_laddr;
	sctrl->xfer_msg = qcom_xfer_msg;
	sctrl->wakeup =  qcom_clk_pause_wakeup;
	ctrl->tx.n = QCOM_TX_MSGS;
	ctrl->tx.sl_sz = SLIM_MSGQ_BUF_LEN;
	ctrl->rx.n = QCOM_RX_MSGS;
	ctrl->rx.sl_sz = SLIM_MSGQ_BUF_LEN;
	ctrl->wr_comp = kcalloc(QCOM_TX_MSGS, sizeof(struct completion *),
				GFP_KERNEL);
	if (!ctrl->wr_comp)
		return -ENOMEM;

	spin_lock_init(&ctrl->rx.lock);
	spin_lock_init(&ctrl->tx.lock);
	INIT_WORK(&ctrl->wd, qcom_slim_rxwq);
	ctrl->rxwq = create_singlethread_workqueue("qcom_slim_rx");
	if (!ctrl->rxwq) {
		dev_err(ctrl->dev, "Failed to start Rx WQ\n");
		return -ENOMEM;
	}

	ctrl->framer.rootfreq = SLIM_ROOT_FREQ / 8;
	ctrl->framer.superfreq =
		ctrl->framer.rootfreq / SLIM_CL_PER_SUPERFRAME_DIV8;
	sctrl->a_framer = &ctrl->framer;
	sctrl->clkgear = SLIM_MAX_CLK_GEAR;

	qcom_slim_prg_slew(pdev, ctrl);

	ret = devm_request_irq(&pdev->dev, ctrl->irq, qcom_slim_interrupt,
				IRQF_TRIGGER_HIGH, "qcom_slim_irq", ctrl);
	if (ret) {
		dev_err(&pdev->dev, "request IRQ failed\n");
		goto err_request_irq_failed;
	}

	ret = clk_prepare_enable(ctrl->hclk);
	if (ret)
		goto err_hclk_enable_failed;

	ret = clk_prepare_enable(ctrl->rclk);
	if (ret)
		goto err_rclk_enable_failed;

	ctrl->tx.base = devm_kcalloc(&pdev->dev, ctrl->tx.n, ctrl->tx.sl_sz,
				     GFP_KERNEL);
	if (!ctrl->tx.base) {
		ret = -ENOMEM;
		goto err;
	}

	ctrl->rx.base = devm_kcalloc(&pdev->dev,ctrl->rx.n, ctrl->rx.sl_sz,
				     GFP_KERNEL);
	if (!ctrl->rx.base) {
		ret = -ENOMEM;
		goto err;
	}

	/* Register with framework before enabling frame, clock */
	ret = slim_register_controller(&ctrl->ctrl);
	if (ret) {
		dev_err(ctrl->dev, "error adding controller\n");
		goto err;
	}

	ver = readl_relaxed(ctrl->base);
	/* Version info in 16 MSbits */
	ver >>= 16;
	/* Component register initialization */
	writel(1, ctrl->base + CFG_PORT(COMP_CFG, ver));
	writel((EE_MGR_RSC_GRP | EE_NGD_2 | EE_NGD_1),
				ctrl->base + CFG_PORT(COMP_TRUST_CFG, ver));

	writel((MGR_INT_TX_NACKED_2 |
			MGR_INT_MSG_BUF_CONTE | MGR_INT_RX_MSG_RCVD |
			MGR_INT_TX_MSG_SENT), ctrl->base + MGR_INT_EN);
	writel(1, ctrl->base + MGR_CFG);
	/* Framer register initialization */
	writel((1 << INTR_WAKE) | (0xA << REF_CLK_GEAR) |
		(0xA << CLK_GEAR) | (1 << ROOT_FREQ) | (1 << FRM_ACTIVE) | 1,
		ctrl->base + FRM_CFG);
	writel(MGR_CFG_ENABLE, ctrl->base + MGR_CFG);
	writel(1, ctrl->base + INTF_CFG);
	writel(1, ctrl->base + CFG_PORT(COMP_CFG, ver));

	pm_runtime_use_autosuspend(&pdev->dev);
	pm_runtime_set_autosuspend_delay(&pdev->dev, QCOM_SLIM_AUTOSUSPEND);
	pm_runtime_set_active(&pdev->dev);
	pm_runtime_mark_last_busy(&pdev->dev);
	pm_runtime_enable(&pdev->dev);

	dev_dbg(ctrl->dev, "QCOM SB controller is up:ver:0x%x!\n", ver);
	return 0;

err:
	clk_disable_unprepare(ctrl->rclk);
err_rclk_enable_failed:
	clk_disable_unprepare(ctrl->hclk);
err_hclk_enable_failed:
err_request_irq_failed:
	destroy_workqueue(ctrl->rxwq);
	return ret;
}