Index: linux-2.6.21gum/drivers/net/Kconfig =================================================================== --- linux-2.6.21gum.orig/drivers/net/Kconfig +++ linux-2.6.21gum/drivers/net/Kconfig @@ -836,6 +836,12 @@ config SMC91X module, say M here and read <file:Documentation/modules.txt> as well as <file:Documentation/networking/net-modules.txt>. +config SMC91X_GUMSTIX + tristate + default m if SMC91X=m + default y if SMC91X=y + depends on SMC91X && ARCH_GUMSTIX + config SMC9194 tristate "SMC 9194 support" depends on NET_VENDOR_SMC && (ISA || MAC && BROKEN) Index: linux-2.6.21gum/drivers/net/Makefile =================================================================== --- linux-2.6.21gum.orig/drivers/net/Makefile +++ linux-2.6.21gum/drivers/net/Makefile @@ -200,6 +200,7 @@ obj-$(CONFIG_PASEMI_MAC) += pasemi_mac.o obj-$(CONFIG_MACB) += macb.o +obj-$(CONFIG_SMC91X_GUMSTIX) += gumstix-smc91x.o obj-$(CONFIG_ARM) += arm/ obj-$(CONFIG_DEV_APPLETALK) += appletalk/ obj-$(CONFIG_TR) += tokenring/ Index: linux-2.6.21gum/drivers/net/smc91x.c =================================================================== --- linux-2.6.21gum.orig/drivers/net/smc91x.c +++ linux-2.6.21gum/drivers/net/smc91x.c @@ -2373,6 +2373,10 @@ static struct platform_driver smc_driver }, }; +#ifdef CONFIG_ARCH_GUMSTIX +extern void gumstix_smc91x_load(void); +#endif + static int __init smc_init(void) { #ifdef MODULE @@ -2384,6 +2388,10 @@ static int __init smc_init(void) #endif #endif +#ifdef CONFIG_ARCH_GUMSTIX + gumstix_smc91x_load(); +#endif + return platform_driver_register(&smc_driver); } Index: linux-2.6.21gum/drivers/net/gumstix-smc91x.c =================================================================== --- /dev/null +++ linux-2.6.21gum/drivers/net/gumstix-smc91x.c @@ -0,0 +1,143 @@ +/* + * Gumstix SMC91C111 chip intialization driver + * + * Author: Craig Hughes + * Created: December 9, 2004 + * Copyright: (C) 2004 Craig Hughes + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + */ + +#include <linux/module.h> +#include <linux/ioport.h> +#include <linux/device.h> +#include <linux/platform_device.h> +#include <linux/delay.h> + +#include <asm/hardware.h> +#include <asm/arch/pxa-regs.h> +#include <asm/delay.h> + +#include <asm/arch/gumstix.h> + +#define SMC_DEBUG 0 +#include <asm/io.h> +#include "smc91x.h" + +static struct resource gumstix_smc91x0_resources[] = { + [0] = { + .name = "smc91x-regs", + .start = PXA_CS1_PHYS + 0x00000300, + .end = PXA_CS1_PHYS + 0x000fffff, + .flags = IORESOURCE_MEM, + }, + [1] = { + .start = GUMSTIX_ETH0_IRQ, + .end = GUMSTIX_ETH0_IRQ, + .flags = IORESOURCE_IRQ, + }, +}; + +static struct resource gumstix_smc91x1_resources[] = { + [0] = { + .name = "smc91x-regs", + .start = PXA_CS2_PHYS + 0x00000300, + .end = PXA_CS2_PHYS + 0x000fffff, + .flags = IORESOURCE_MEM, + }, + [1] = { + .start = GUMSTIX_ETH1_IRQ, + .end = GUMSTIX_ETH1_IRQ, + .flags = IORESOURCE_IRQ, + }, +}; + +static struct platform_device gumstix_smc91x0_device = { + .name = "smc91x", + .id = 0, + .num_resources = ARRAY_SIZE(gumstix_smc91x0_resources), + .resource = gumstix_smc91x0_resources, +}; + +static struct platform_device gumstix_smc91x1_device = { + .name = "smc91x", + .id = 1, + .num_resources = ARRAY_SIZE(gumstix_smc91x1_resources), + .resource = gumstix_smc91x1_resources, +}; + +static struct platform_device *smc91x_devices[] = { + &gumstix_smc91x0_device, + &gumstix_smc91x1_device, +}; + +/* First we're going to test if there's a 2nd SMC91C111, and if not, then we'll free up those resources and the GPIO lines + * that it would otherwise use. We have no choice but to probe by doing: + * Set nCS2 to CS2 mode + * Set the reset line to GPIO out mode, and pull it high, then drop it low (to trigger reset) + * Read from the memory space to check for the sentinel sequence identifying a likely SMC91C111 device + */ +int __init gumstix_smc91x_init(void) +{ + unsigned int val, num_devices=ARRAY_SIZE(smc91x_devices); + void *ioaddr; + + /* Set up nPWE */ + pxa_gpio_mode(GPIO49_nPWE_MD); + + pxa_gpio_mode(GPIO78_nCS_2_MD); + // If either if statement fails, then we'll drop out and turn_off_eth1, + // if both succeed, then we'll skip that and just proceed with 2 cards + if(request_mem_region(gumstix_smc91x1_resources[0].start, SMC_IO_EXTENT, "smc91x probe")) + { + ioaddr = ioremap(gumstix_smc91x1_resources[0].start, SMC_IO_EXTENT); + val = ioread16(ioaddr + BANK_SELECT); + iounmap(ioaddr); + release_mem_region(gumstix_smc91x1_resources[0].start, SMC_IO_EXTENT); + if ((val & 0xFF00) == 0x3300) { + goto proceed; + } + } + +turn_off_eth1: + // This is apparently not an SMC91C111 + // So, let's decrement the number of devices to request, and reset the GPIO lines to GPIO IN mode + num_devices--; + smc91x_devices[1] = NULL; + pxa_gpio_mode(78 | GPIO_IN); + +proceed: + pxa_gpio_mode(GPIO15_nCS_1_MD); + + if(smc91x_devices[1]) pxa_gpio_mode(GPIO_GUMSTIX_ETH1_RST_MD); + pxa_gpio_mode(GPIO_GUMSTIX_ETH0_RST_MD); + if(smc91x_devices[1]) GPSR(GPIO_GUMSTIX_ETH1_RST) = GPIO_bit(GPIO_GUMSTIX_ETH1_RST); + GPSR(GPIO_GUMSTIX_ETH0_RST) = GPIO_bit(GPIO_GUMSTIX_ETH0_RST); + udelay(1); // Hold RESET for at least 100ns + if(smc91x_devices[1]) GPCR(GPIO_GUMSTIX_ETH1_RST) = GPIO_bit(GPIO_GUMSTIX_ETH1_RST); + GPCR(GPIO_GUMSTIX_ETH0_RST) = GPIO_bit(GPIO_GUMSTIX_ETH0_RST); + msleep(50); + + return platform_add_devices(smc91x_devices, num_devices); +} + +void __exit gumstix_smc91x_exit(void) +{ + if(smc91x_devices[1] != NULL) platform_device_unregister(&gumstix_smc91x1_device); + platform_device_unregister(&gumstix_smc91x0_device); +} + +void gumstix_smc91x_load(void) {} +EXPORT_SYMBOL(gumstix_smc91x_load); + +module_init(gumstix_smc91x_init); +module_exit(gumstix_smc91x_exit); + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Craig Hughes <craig@gumstix.com>"); +MODULE_DESCRIPTION("Gumstix board SMC91C111 chip initialization driver"); +MODULE_VERSION("1:0.1");