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