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