static int fsi_master_aspeed_probe()

in fsi-master-aspeed.c [533:638]


static int fsi_master_aspeed_probe(struct platform_device *pdev)
{
	struct fsi_master_aspeed *aspeed;
	int rc, links, reg;
	__be32 raw;

	rc = tacoma_cabled_fsi_fixup(&pdev->dev);
	if (rc) {
		dev_err(&pdev->dev, "Tacoma FSI cable fixup failed\n");
		return rc;
	}

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

	aspeed->dev = &pdev->dev;

	aspeed->base = devm_platform_ioremap_resource(pdev, 0);
	if (IS_ERR(aspeed->base))
		return PTR_ERR(aspeed->base);

	aspeed->clk = devm_clk_get(aspeed->dev, NULL);
	if (IS_ERR(aspeed->clk)) {
		dev_err(aspeed->dev, "couldn't get clock\n");
		return PTR_ERR(aspeed->clk);
	}
	rc = clk_prepare_enable(aspeed->clk);
	if (rc) {
		dev_err(aspeed->dev, "couldn't enable clock\n");
		return rc;
	}

	rc = setup_cfam_reset(aspeed);
	if (rc) {
		dev_err(&pdev->dev, "CFAM reset GPIO setup failed\n");
	}

	writel(0x1, aspeed->base + OPB_CLK_SYNC);
	writel(OPB1_XFER_ACK_EN | OPB0_XFER_ACK_EN,
			aspeed->base + OPB_IRQ_MASK);

	/* TODO: determine an appropriate value */
	writel(0x10, aspeed->base + OPB_RETRY_COUNTER);

	writel(ctrl_base, aspeed->base + OPB_CTRL_BASE);
	writel(fsi_base, aspeed->base + OPB_FSI_BASE);

	/* Set read data order */
	writel(0x00030b1b, aspeed->base + OPB0_READ_ORDER1);

	/* Set write data order */
	writel(0x0011101b, aspeed->base + OPB0_WRITE_ORDER1);
	writel(0x0c330f3f, aspeed->base + OPB0_WRITE_ORDER2);

	/*
	 * Select OPB0 for all operations.
	 * Will need to be reworked when enabling DMA or anything that uses
	 * OPB1.
	 */
	writel(0x1, aspeed->base + OPB0_SELECT);

	rc = opb_readl(aspeed, ctrl_base + FSI_MVER, &raw);
	if (rc) {
		dev_err(&pdev->dev, "failed to read hub version\n");
		return rc;
	}

	reg = be32_to_cpu(raw);
	links = (reg >> 8) & 0xff;
	dev_info(&pdev->dev, "hub version %08x (%d links)\n", reg, links);

	aspeed->master.dev.parent = &pdev->dev;
	aspeed->master.dev.release = aspeed_master_release;
	aspeed->master.dev.of_node = of_node_get(dev_of_node(&pdev->dev));

	aspeed->master.n_links = links;
	aspeed->master.read = aspeed_master_read;
	aspeed->master.write = aspeed_master_write;
	aspeed->master.send_break = aspeed_master_break;
	aspeed->master.term = aspeed_master_term;
	aspeed->master.link_enable = aspeed_master_link_enable;

	dev_set_drvdata(&pdev->dev, aspeed);

	mutex_init(&aspeed->lock);
	aspeed_master_init(aspeed);

	rc = fsi_master_register(&aspeed->master);
	if (rc)
		goto err_release;

	/* At this point, fsi_master_register performs the device_initialize(),
	 * and holds the sole reference on master.dev. This means the device
	 * will be freed (via ->release) during any subsequent call to
	 * fsi_master_unregister.  We add our own reference to it here, so we
	 * can perform cleanup (in _remove()) without it being freed before
	 * we're ready.
	 */
	get_device(&aspeed->master.dev);
	return 0;

err_release:
	clk_disable_unprepare(aspeed->clk);
	return rc;
}