static int pl022_probe()

in spi-pl022.c [2102:2252]


static int pl022_probe(struct amba_device *adev, const struct amba_id *id)
{
	struct device *dev = &adev->dev;
	struct pl022_ssp_controller *platform_info =
			dev_get_platdata(&adev->dev);
	struct spi_master *master;
	struct pl022 *pl022 = NULL;	/*Data for this driver */
	int status = 0;

	dev_info(&adev->dev,
		 "ARM PL022 driver, device ID: 0x%08x\n", adev->periphid);
	if (!platform_info && IS_ENABLED(CONFIG_OF))
		platform_info = pl022_platform_data_dt_get(dev);

	if (!platform_info) {
		dev_err(dev, "probe: no platform data defined\n");
		return -ENODEV;
	}

	/* Allocate master with space for data */
	master = spi_alloc_master(dev, sizeof(struct pl022));
	if (master == NULL) {
		dev_err(&adev->dev, "probe - cannot alloc SPI master\n");
		return -ENOMEM;
	}

	pl022 = spi_master_get_devdata(master);
	pl022->master = master;
	pl022->master_info = platform_info;
	pl022->adev = adev;
	pl022->vendor = id->data;

	/*
	 * Bus Number Which has been Assigned to this SSP controller
	 * on this board
	 */
	master->bus_num = platform_info->bus_id;
	master->cleanup = pl022_cleanup;
	master->setup = pl022_setup;
	master->auto_runtime_pm = true;
	master->transfer_one_message = pl022_transfer_one_message;
	master->unprepare_transfer_hardware = pl022_unprepare_transfer_hardware;
	master->rt = platform_info->rt;
	master->dev.of_node = dev->of_node;
	master->use_gpio_descriptors = true;

	/*
	 * Supports mode 0-3, loopback, and active low CS. Transfers are
	 * always MS bit first on the original pl022.
	 */
	master->mode_bits = SPI_CPOL | SPI_CPHA | SPI_CS_HIGH | SPI_LOOP;
	if (pl022->vendor->extended_cr)
		master->mode_bits |= SPI_LSB_FIRST;

	dev_dbg(&adev->dev, "BUSNO: %d\n", master->bus_num);

	status = amba_request_regions(adev, NULL);
	if (status)
		goto err_no_ioregion;

	pl022->phybase = adev->res.start;
	pl022->virtbase = devm_ioremap(dev, adev->res.start,
				       resource_size(&adev->res));
	if (pl022->virtbase == NULL) {
		status = -ENOMEM;
		goto err_no_ioremap;
	}
	dev_info(&adev->dev, "mapped registers from %pa to %p\n",
		&adev->res.start, pl022->virtbase);

	pl022->clk = devm_clk_get(&adev->dev, NULL);
	if (IS_ERR(pl022->clk)) {
		status = PTR_ERR(pl022->clk);
		dev_err(&adev->dev, "could not retrieve SSP/SPI bus clock\n");
		goto err_no_clk;
	}

	status = clk_prepare_enable(pl022->clk);
	if (status) {
		dev_err(&adev->dev, "could not enable SSP/SPI bus clock\n");
		goto err_no_clk_en;
	}

	/* Initialize transfer pump */
	tasklet_init(&pl022->pump_transfers, pump_transfers,
		     (unsigned long)pl022);

	/* Disable SSP */
	writew((readw(SSP_CR1(pl022->virtbase)) & (~SSP_CR1_MASK_SSE)),
	       SSP_CR1(pl022->virtbase));
	load_ssp_default_config(pl022);

	status = devm_request_irq(dev, adev->irq[0], pl022_interrupt_handler,
				  0, "pl022", pl022);
	if (status < 0) {
		dev_err(&adev->dev, "probe - cannot get IRQ (%d)\n", status);
		goto err_no_irq;
	}

	/* Get DMA channels, try autoconfiguration first */
	status = pl022_dma_autoprobe(pl022);
	if (status == -EPROBE_DEFER) {
		dev_dbg(dev, "deferring probe to get DMA channel\n");
		goto err_no_irq;
	}

	/* If that failed, use channels from platform_info */
	if (status == 0)
		platform_info->enable_dma = 1;
	else if (platform_info->enable_dma) {
		status = pl022_dma_probe(pl022);
		if (status != 0)
			platform_info->enable_dma = 0;
	}

	/* Register with the SPI framework */
	amba_set_drvdata(adev, pl022);
	status = devm_spi_register_master(&adev->dev, master);
	if (status != 0) {
		dev_err(&adev->dev,
			"probe - problem registering spi master\n");
		goto err_spi_register;
	}
	dev_dbg(dev, "probe succeeded\n");

	/* let runtime pm put suspend */
	if (platform_info->autosuspend_delay > 0) {
		dev_info(&adev->dev,
			"will use autosuspend for runtime pm, delay %dms\n",
			platform_info->autosuspend_delay);
		pm_runtime_set_autosuspend_delay(dev,
			platform_info->autosuspend_delay);
		pm_runtime_use_autosuspend(dev);
	}
	pm_runtime_put(dev);

	return 0;

 err_spi_register:
	if (platform_info->enable_dma)
		pl022_dma_remove(pl022);
 err_no_irq:
	clk_disable_unprepare(pl022->clk);
 err_no_clk_en:
 err_no_clk:
 err_no_ioremap:
	amba_release_regions(adev);
 err_no_ioregion:
	spi_master_put(master);
	return status;
}