/*
 * bcm47xx_pcmcia_driver_init()
 *
 * This routine performs a basic sanity check to ensure that this
 * kernel has been built with the appropriate board-specific low-level
 * PCMCIA support, performs low-level PCMCIA initialization, registers
 * this socket driver with Card Services, and then spawns the daemon
 * thread which is the real workhorse of the socket driver.
 *
 * Please see linux/Documentation/arm/SA1100/PCMCIA for more information
 * on the low-level kernel interface.
 *
 * Returns: 0 on success, -1 on error
 */
static int __init bcm47xx_pcmcia_driver_init(void)
{
	servinfo_t info;
	struct pcmcia_init pcmcia_init;
	struct pcmcia_state state;
	unsigned int i;
	unsigned long tmp;


	printk("\nBCM47XX PCMCIA (CS release %s)\n", CS_RELEASE);

	CardServices(GetCardServicesInfo, &info);

	if (info.Revision != CS_RELEASE_CODE) {
		printk(KERN_ERR "Card Services release codes do not match\n");
		return -1;
	}

#ifdef CONFIG_BCM4710
	pcmcia_low_level=&bcm4710_pcmcia_ops;
#else
#error Unsupported Broadcom BCM47XX board.
#endif

	pcmcia_init.handler=bcm47xx_pcmcia_interrupt;

	if ((socket_count = pcmcia_low_level->init(&pcmcia_init)) < 0) {
		printk(KERN_ERR "Unable to initialize PCMCIA service.\n");
		return -EIO;
	} else {
		printk("\t%d PCMCIA sockets initialized.\n", socket_count);
	}

	pcmcia_socket = 
		kmalloc(sizeof(struct bcm47xx_pcmcia_socket) * socket_count, 
				GFP_KERNEL);
	memset(pcmcia_socket, 0, 
			sizeof(struct bcm47xx_pcmcia_socket) * socket_count);
	if (!pcmcia_socket) {
		printk(KERN_ERR "Card Services can't get memory \n");
		return -1;
	}
			
	for (i = 0; i < socket_count; i++) {
		if (pcmcia_low_level->socket_state(i, &state) < 0) {
			printk(KERN_ERR "Unable to get PCMCIA status\n");
			return -EIO;
		}
		pcmcia_socket[i].k_state = state;
		pcmcia_socket[i].cs_state.csc_mask = SS_DETECT;
		
		if (i == 0) {
			pcmcia_socket[i].virt_io =
				(unsigned long)ioremap_nocache(EXTIF_PCMCIA_IOBASE(BCM4710_EXTIF), 0x1000);
			/* Substract ioport base which gets added by in/out */
			pcmcia_socket[i].virt_io -= mips_io_port_base;
			pcmcia_socket[i].phys_attr =
				(unsigned long)EXTIF_PCMCIA_CFGBASE(BCM4710_EXTIF);
			pcmcia_socket[i].phys_mem =
				(unsigned long)EXTIF_PCMCIA_MEMBASE(BCM4710_EXTIF);
		} else  {
			printk(KERN_ERR "bcm4710: socket 1 not supported\n");
			return 1;
		}
	}

	/* Only advertise as many sockets as we can detect: */
	if (register_ss_entry(socket_count, &bcm47xx_pcmcia_operations) < 0) {
		printk(KERN_ERR "Unable to register socket service routine\n");
		return -ENXIO;
	}

	/* Start the event poll timer.  
	 * It will reschedule by itself afterwards. 
	 */
	bcm47xx_pcmcia_poll_event(0);

	DEBUG(1, "bcm4710: initialization complete\n");
	return 0;

}
Exemplo n.º 2
0
static int bcm4710_pcmcia_init(struct pcmcia_init *init)
{
	struct pci_dev *pdev;
	uint16 *attrsp;
	uint32 outen, tmp;
#ifdef DO_BCM47XX_PCMCIA_INTERRUPTS
	uint32 intp, intm;
	int rc = 0, i;
	extern unsigned long bcm4710_cpu_cycle;
#endif


	if (!(pdev = pci_find_device(VENDOR_BROADCOM, SB_EXTIF, NULL))) {
		printk(KERN_ERR "bcm4710_pcmcia: extif not found\n");
		return -ENODEV;
	}

	eir = (extifregs_t *) ioremap_nocache(pci_resource_start(pdev, 0), pci_resource_len(pdev, 0));

	/* Initialize the pcmcia i/f: 16bit no swap */
	writel(CF_EM_PCMCIA | CF_DS | CF_EN, &eir->pcmcia_config);

#ifdef	notYet

	/* Set the timing for memory accesses */
	tmp = (19 / bcm4710_cpu_cycle) << 24;		/* W3 = 10nS */
	tmp = tmp | ((29 / bcm4710_cpu_cycle) << 16);	/* W2 = 20nS */
	tmp = tmp | ((109 / bcm4710_cpu_cycle) << 8);	/* W1 = 100nS */
	tmp = tmp | (129 / bcm4710_cpu_cycle);		/* W0 = 120nS */
	writel(tmp, &eir->pcmcia_memwait);		/* 0x01020a0c for a 100Mhz clock */

	/* Set the timing for I/O accesses */
	tmp = (19 / bcm4710_cpu_cycle) << 24;		/* W3 = 10nS */
	tmp = tmp | ((29 / bcm4710_cpu_cycle) << 16);	/* W2 = 20nS */
	tmp = tmp | ((109 / bcm4710_cpu_cycle) << 8);	/* W1 = 100nS */
	tmp = tmp | (129 / bcm4710_cpu_cycle);		/* W0 = 120nS */
	writel(tmp, &eir->pcmcia_iowait);		/* 0x01020a0c for a 100Mhz clock */

	/* Set the timing for attribute accesses */
	tmp = (19 / bcm4710_cpu_cycle) << 24;		/* W3 = 10nS */
	tmp = tmp | ((29 / bcm4710_cpu_cycle) << 16);	/* W2 = 20nS */
	tmp = tmp | ((109 / bcm4710_cpu_cycle) << 8);	/* W1 = 100nS */
	tmp = tmp | (129 / bcm4710_cpu_cycle);		/* W0 = 120nS */
	writel(tmp, &eir->pcmcia_attrwait);		/* 0x01020a0c for a 100Mhz clock */

#endif
	/* Make sure gpio0 and gpio5 are inputs */
	outen = readl(&eir->gpio[0].outen);
	outen &= ~(BCM47XX_PCMCIA_WP | BCM47XX_PCMCIA_STSCHG | BCM47XX_PCMCIA_RESET);
	writel(outen, &eir->gpio[0].outen);

	/* Issue a reset to the pcmcia socket */
	bcm4710_pcmcia_reset();

#ifdef	DO_BCM47XX_PCMCIA_INTERRUPTS
	/* Setup gpio5 to be the STSCHG interrupt */
	intp = readl(&eir->gpiointpolarity);
	writel(intp | BCM47XX_PCMCIA_STSCHG, &eir->gpiointpolarity);	/* Active low */
	intm = readl(&eir->gpiointmask);
	writel(intm | BCM47XX_PCMCIA_STSCHG, &eir->gpiointmask);	/* Enable it */
#endif

	DEBUG(2, "bcm4710_pcmcia after reset:\n");
	DEBUG(2, "\textstatus\t= 0x%08x:\n", readl(&eir->extstatus));
	DEBUG(2, "\tpcmcia_config\t= 0x%08x:\n", readl(&eir->pcmcia_config));
	DEBUG(2, "\tpcmcia_memwait\t= 0x%08x:\n", readl(&eir->pcmcia_memwait));
	DEBUG(2, "\tpcmcia_attrwait\t= 0x%08x:\n", readl(&eir->pcmcia_attrwait));
	DEBUG(2, "\tpcmcia_iowait\t= 0x%08x:\n", readl(&eir->pcmcia_iowait));
	DEBUG(2, "\tgpioin\t\t= 0x%08x:\n", readl(&eir->gpioin));
	DEBUG(2, "\tgpio_outen0\t= 0x%08x:\n", readl(&eir->gpio[0].outen));
	DEBUG(2, "\tgpio_out0\t= 0x%08x:\n", readl(&eir->gpio[0].out));
	DEBUG(2, "\tgpiointpolarity\t= 0x%08x:\n", readl(&eir->gpiointpolarity));
	DEBUG(2, "\tgpiointmask\t= 0x%08x:\n", readl(&eir->gpiointmask));

#ifdef	DO_BCM47XX_PCMCIA_INTERRUPTS
	/* Request pcmcia interrupt */
	rc =  request_irq(BCM47XX_PCMCIA_IRQ, init->handler, SA_INTERRUPT,
			  "PCMCIA Interrupt", &bcm47xx_pcmcia_dev_id);
#endif

	attrsp = (uint16 *)ioremap_nocache(EXTIF_PCMCIA_CFGBASE(SB_EXTIF_BASE), 0x1000);
	tmp = readw(&attrsp[0]);
	DEBUG(2, "\tattr[0] = 0x%04x\n", tmp);
	if ((tmp == 0x7fff) || (tmp == 0x7f00)) {
		bcm47xx_pcmcia_present = 0;
	} else {
		bcm47xx_pcmcia_present = 1;
	}

	/* There's only one socket */
	return 1;
}