static int fsi_master_acf_probe()

in fsi-master-ast-cf.c [1213:1410]


static int fsi_master_acf_probe(struct platform_device *pdev)
{
	struct device_node *np, *mnode = dev_of_node(&pdev->dev);
	struct genpool_data_fixed gpdf;
	struct fsi_master_acf *master;
	struct gpio_desc *gpio;
	struct resource res;
	uint32_t cf_mem_align;
	int rc;

	master = kzalloc(sizeof(*master), GFP_KERNEL);
	if (!master)
		return -ENOMEM;

	master->dev = &pdev->dev;
	master->master.dev.parent = master->dev;
	master->last_addr = LAST_ADDR_INVALID;

	/* AST2400 vs. AST2500 */
	master->is_ast2500 = of_device_is_compatible(mnode, "aspeed,ast2500-cf-fsi-master");

	/* Grab the SCU, we'll need to access it to configure the coprocessor */
	if (master->is_ast2500)
		master->scu = syscon_regmap_lookup_by_compatible("aspeed,ast2500-scu");
	else
		master->scu = syscon_regmap_lookup_by_compatible("aspeed,ast2400-scu");
	if (IS_ERR(master->scu)) {
		dev_err(&pdev->dev, "failed to find SCU regmap\n");
		rc = PTR_ERR(master->scu);
		goto err_free;
	}

	/* Grab all the GPIOs we need */
	gpio = devm_gpiod_get(&pdev->dev, "clock", 0);
	if (IS_ERR(gpio)) {
		dev_err(&pdev->dev, "failed to get clock gpio\n");
		rc = PTR_ERR(gpio);
		goto err_free;
	}
	master->gpio_clk = gpio;

	gpio = devm_gpiod_get(&pdev->dev, "data", 0);
	if (IS_ERR(gpio)) {
		dev_err(&pdev->dev, "failed to get data gpio\n");
		rc = PTR_ERR(gpio);
		goto err_free;
	}
	master->gpio_data = gpio;

	/* Optional GPIOs */
	gpio = devm_gpiod_get_optional(&pdev->dev, "trans", 0);
	if (IS_ERR(gpio)) {
		dev_err(&pdev->dev, "failed to get trans gpio\n");
		rc = PTR_ERR(gpio);
		goto err_free;
	}
	master->gpio_trans = gpio;

	gpio = devm_gpiod_get_optional(&pdev->dev, "enable", 0);
	if (IS_ERR(gpio)) {
		dev_err(&pdev->dev, "failed to get enable gpio\n");
		rc = PTR_ERR(gpio);
		goto err_free;
	}
	master->gpio_enable = gpio;

	gpio = devm_gpiod_get_optional(&pdev->dev, "mux", 0);
	if (IS_ERR(gpio)) {
		dev_err(&pdev->dev, "failed to get mux gpio\n");
		rc = PTR_ERR(gpio);
		goto err_free;
	}
	master->gpio_mux = gpio;

	/* Grab the reserved memory region (use DMA API instead ?) */
	np = of_parse_phandle(mnode, "memory-region", 0);
	if (!np) {
		dev_err(&pdev->dev, "Didn't find reserved memory\n");
		rc = -EINVAL;
		goto err_free;
	}
	rc = of_address_to_resource(np, 0, &res);
	of_node_put(np);
	if (rc) {
		dev_err(&pdev->dev, "Couldn't address to resource for reserved memory\n");
		rc = -ENOMEM;
		goto err_free;
	}
	master->cf_mem_size = resource_size(&res);
	master->cf_mem_addr = (uint32_t)res.start;
	cf_mem_align = master->is_ast2500 ? 0x00100000 : 0x00200000;
	if (master->cf_mem_addr & (cf_mem_align - 1)) {
		dev_err(&pdev->dev, "Reserved memory has insufficient alignment\n");
		rc = -ENOMEM;
		goto err_free;
	}
	master->cf_mem = devm_ioremap_resource(&pdev->dev, &res);
 	if (IS_ERR(master->cf_mem)) {
		rc = PTR_ERR(master->cf_mem);
 		goto err_free;
	}
	dev_dbg(&pdev->dev, "DRAM allocation @%x\n", master->cf_mem_addr);

	/* AST2500 has a SW interrupt to the coprocessor */
	if (master->is_ast2500) {
		/* Grab the CVIC (ColdFire interrupts controller) */
		np = of_parse_phandle(mnode, "aspeed,cvic", 0);
		if (!np) {
			dev_err(&pdev->dev, "Didn't find CVIC\n");
			rc = -EINVAL;
			goto err_free;
		}
		master->cvic = devm_of_iomap(&pdev->dev, np, 0, NULL);
		if (IS_ERR(master->cvic)) {
			rc = PTR_ERR(master->cvic);
			dev_err(&pdev->dev, "Error %d mapping CVIC\n", rc);
			goto err_free;
		}
		rc = of_property_read_u32(np, "copro-sw-interrupts",
					  &master->cvic_sw_irq);
		if (rc) {
			dev_err(&pdev->dev, "Can't find coprocessor SW interrupt\n");
			goto err_free;
		}
	}

	/* Grab the SRAM */
	master->sram_pool = of_gen_pool_get(dev_of_node(&pdev->dev), "aspeed,sram", 0);
	if (!master->sram_pool) {
		rc = -ENODEV;
		dev_err(&pdev->dev, "Can't find sram pool\n");
		goto err_free;
	}

	/* Current microcode only deals with fixed location in SRAM */
	gpdf.offset = 0;
	master->sram = (void __iomem *)gen_pool_alloc_algo(master->sram_pool, SRAM_SIZE,
							   gen_pool_fixed_alloc, &gpdf);
	if (!master->sram) {
		rc = -ENOMEM;
		dev_err(&pdev->dev, "Failed to allocate sram from pool\n");
		goto err_free;
	}
	dev_dbg(&pdev->dev, "SRAM allocation @%lx\n",
		(unsigned long)gen_pool_virt_to_phys(master->sram_pool,
						     (unsigned long)master->sram));

	/*
	 * Hookup with the GPIO driver for arbitration of GPIO banks
	 * ownership.
	 */
	aspeed_gpio_copro_set_ops(&fsi_master_acf_gpio_ops, master);

	/* Default FSI command delays */
	master->t_send_delay = FSI_SEND_DELAY_CLOCKS;
	master->t_echo_delay = FSI_ECHO_DELAY_CLOCKS;
	master->master.n_links = 1;
	if (master->is_ast2500)
		master->master.flags = FSI_MASTER_FLAG_SWCLOCK;
	master->master.read = fsi_master_acf_read;
	master->master.write = fsi_master_acf_write;
	master->master.term = fsi_master_acf_term;
	master->master.send_break = fsi_master_acf_break;
	master->master.link_enable = fsi_master_acf_link_enable;
	master->master.link_config = fsi_master_acf_link_config;
	master->master.dev.of_node = of_node_get(dev_of_node(master->dev));
	master->master.dev.release = fsi_master_acf_release;
	platform_set_drvdata(pdev, master);
	mutex_init(&master->lock);

	mutex_lock(&master->lock);
	rc = fsi_master_acf_setup(master);
	mutex_unlock(&master->lock);
	if (rc)
		goto release_of_dev;

	rc = device_create_file(&pdev->dev, &dev_attr_external_mode);
	if (rc)
		goto stop_copro;

	rc = fsi_master_register(&master->master);
	if (!rc)
		return 0;

	device_remove_file(master->dev, &dev_attr_external_mode);
	put_device(&master->master.dev);
	return rc;

 stop_copro:
	fsi_master_acf_terminate(master);
 release_of_dev:
	aspeed_gpio_copro_set_ops(NULL, NULL);
	gen_pool_free(master->sram_pool, (unsigned long)master->sram, SRAM_SIZE);
	of_node_put(dev_of_node(master->dev));
 err_free:
	kfree(master);
	return rc;
}