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