static int neponset_probe()

in mach-sa1100/neponset.c [225:377]


static int neponset_probe(struct platform_device *dev)
{
	struct neponset_drvdata *d;
	struct resource *nep_res, *sa1111_res, *smc91x_res;
	struct resource sa1111_resources[] = {
		DEFINE_RES_MEM(0x40000000, SZ_8K),
		{ .flags = IORESOURCE_IRQ },
	};
	struct platform_device_info sa1111_devinfo = {
		.parent = &dev->dev,
		.name = "sa1111",
		.id = 0,
		.res = sa1111_resources,
		.num_res = ARRAY_SIZE(sa1111_resources),
		.data = &sa1111_info,
		.size_data = sizeof(sa1111_info),
		.dma_mask = 0xffffffffUL,
	};
	struct resource smc91x_resources[] = {
		DEFINE_RES_MEM_NAMED(SA1100_CS3_PHYS,
			0x02000000, "smc91x-regs"),
		DEFINE_RES_MEM_NAMED(SA1100_CS3_PHYS + 0x02000000,
			0x02000000, "smc91x-attrib"),
		{ .flags = IORESOURCE_IRQ },
	};
	struct smc91x_platdata smc91x_platdata = {
		.flags = SMC91X_USE_8BIT | SMC91X_IO_SHIFT_2 | SMC91X_NOWAIT,
	};
	struct platform_device_info smc91x_devinfo = {
		.parent = &dev->dev,
		.name = "smc91x",
		.id = 0,
		.res = smc91x_resources,
		.num_res = ARRAY_SIZE(smc91x_resources),
		.data = &smc91x_platdata,
		.size_data = sizeof(smc91x_platdata),
	};
	int ret, irq;

	if (nep)
		return -EBUSY;

	irq = ret = platform_get_irq(dev, 0);
	if (ret < 0)
		goto err_alloc;

	nep_res = platform_get_resource(dev, IORESOURCE_MEM, 0);
	smc91x_res = platform_get_resource(dev, IORESOURCE_MEM, 1);
	sa1111_res = platform_get_resource(dev, IORESOURCE_MEM, 2);
	if (!nep_res || !smc91x_res || !sa1111_res) {
		ret = -ENXIO;
		goto err_alloc;
	}

	d = kzalloc(sizeof(*d), GFP_KERNEL);
	if (!d) {
		ret = -ENOMEM;
		goto err_alloc;
	}

	d->base = ioremap(nep_res->start, SZ_4K);
	if (!d->base) {
		ret = -ENOMEM;
		goto err_ioremap;
	}

	if (readb_relaxed(d->base + WHOAMI) != 0x11) {
		dev_warn(&dev->dev, "Neponset board detected, but wrong ID: %02x\n",
			 readb_relaxed(d->base + WHOAMI));
		ret = -ENODEV;
		goto err_id;
	}

	ret = irq_alloc_descs(-1, IRQ_BOARD_START, NEP_IRQ_NR, -1);
	if (ret <= 0) {
		dev_err(&dev->dev, "unable to allocate %u irqs: %d\n",
			NEP_IRQ_NR, ret);
		if (ret == 0)
			ret = -ENOMEM;
		goto err_irq_alloc;
	}

	d->irq_base = ret;

	irq_set_chip_and_handler(d->irq_base + NEP_IRQ_SMC91X, &nochip,
		handle_simple_irq);
	irq_clear_status_flags(d->irq_base + NEP_IRQ_SMC91X, IRQ_NOREQUEST | IRQ_NOPROBE);
	irq_set_chip_and_handler(d->irq_base + NEP_IRQ_USAR, &nochip,
		handle_simple_irq);
	irq_clear_status_flags(d->irq_base + NEP_IRQ_USAR, IRQ_NOREQUEST | IRQ_NOPROBE);
	irq_set_chip(d->irq_base + NEP_IRQ_SA1111, &nochip);

	irq_set_irq_type(irq, IRQ_TYPE_EDGE_RISING);
	irq_set_chained_handler_and_data(irq, neponset_irq_handler, d);

	/* Disable GPIO 0/1 drivers so the buttons work on the Assabet */
	writeb_relaxed(NCR_GP01_OFF, d->base + NCR_0);

	neponset_init_gpio(&d->gpio[0], &dev->dev, "neponset-ncr",
			   d->base + NCR_0, NCR_NGPIO, false,
			   neponset_ncr_names);
	neponset_init_gpio(&d->gpio[1], &dev->dev, "neponset-mdm-ctl0",
			   d->base + MDM_CTL_0, MDM_CTL0_NGPIO, false,
			   neponset_mdmctl0_names);
	neponset_init_gpio(&d->gpio[2], &dev->dev, "neponset-mdm-ctl1",
			   d->base + MDM_CTL_1, MDM_CTL1_NGPIO, true,
			   neponset_mdmctl1_names);
	neponset_init_gpio(&d->gpio[3], &dev->dev, "neponset-aud-ctl",
			   d->base + AUD_CTL, AUD_NGPIO, false,
			   neponset_aud_names);

	gpiod_add_lookup_table(&neponset_uart1_gpio_table);
	gpiod_add_lookup_table(&neponset_uart3_gpio_table);
	gpiod_add_lookup_table(&neponset_pcmcia_table);

	/*
	 * We would set IRQ_GPIO25 to be a wake-up IRQ, but unfortunately
	 * something on the Neponset activates this IRQ on sleep (eth?)
	 */
#if 0
	enable_irq_wake(irq);
#endif

	dev_info(&dev->dev, "Neponset daughter board, providing IRQ%u-%u\n",
		 d->irq_base, d->irq_base + NEP_IRQ_NR - 1);
	nep = d;

	/* Ensure that the memory bus request/grant signals are setup */
	sa1110_mb_disable();

	sa1111_resources[0].parent = sa1111_res;
	sa1111_resources[1].start = d->irq_base + NEP_IRQ_SA1111;
	sa1111_resources[1].end = d->irq_base + NEP_IRQ_SA1111;
	d->sa1111 = platform_device_register_full(&sa1111_devinfo);

	smc91x_resources[0].parent = smc91x_res;
	smc91x_resources[1].parent = smc91x_res;
	smc91x_resources[2].start = d->irq_base + NEP_IRQ_SMC91X;
	smc91x_resources[2].end = d->irq_base + NEP_IRQ_SMC91X;
	d->smc91x = platform_device_register_full(&smc91x_devinfo);

	platform_set_drvdata(dev, d);

	return 0;

 err_irq_alloc:
 err_id:
	iounmap(d->base);
 err_ioremap:
	kfree(d);
 err_alloc:
	return ret;
}