From 9a9465369f2fdbd22b68e545b4744b8dca1608ff Mon Sep 17 00:00:00 2001 From: Matthieu Crapet Date: Fri, 18 Jun 2010 17:39:09 +0200 Subject: [PATCH 08/18] ts72xx_ts_eth100 TS-ETH100 - 10/100 Ethernet PC/104 peripheral --- drivers/net/Kconfig | 10 ++ drivers/net/Makefile | 1 + drivers/net/ax88796.c | 8 ++- drivers/net/ax88796_ts_eth100.c | 190 +++++++++++++++++++++++++++++++++++++++ 4 files changed, 208 insertions(+), 1 deletions(-) create mode 100644 drivers/net/ax88796_ts_eth100.c diff --git a/drivers/net/Kconfig b/drivers/net/Kconfig index 7b832c7..f812332 100644 --- a/drivers/net/Kconfig +++ b/drivers/net/Kconfig @@ -248,6 +248,16 @@ config AX88796_93CX6 help Select this if your platform comes with an external 93CX6 eeprom. +config AX88796_TS_ETH100 + tristate "Support for TS-ETH100 (TS-72XX SBC)" + depends on AX88796 && MACH_TS72XX + help + Say Y here if you have a TS-ETH100 PC/104 peripheral. + IRQ numbers and I/O address will be configurated automatically. + + To compile this driver as a module, choose M here: the module + will be called ax88796_ts_eth100. + config MACE tristate "MACE (Power Mac ethernet) support" depends on PPC_PMAC && PPC32 diff --git a/drivers/net/Makefile b/drivers/net/Makefile index 12b280a..cb448fa 100644 --- a/drivers/net/Makefile +++ b/drivers/net/Makefile @@ -143,6 +143,7 @@ obj-$(CONFIG_B44) += b44.o obj-$(CONFIG_FORCEDETH) += forcedeth.o obj-$(CONFIG_NE_H8300) += ne-h8300.o 8390.o obj-$(CONFIG_AX88796) += ax88796.o +obj-$(CONFIG_AX88796_TS_ETH100) += ax88796_ts_eth100.o obj-$(CONFIG_BCM63XX_ENET) += bcm63xx_enet.o obj-$(CONFIG_TSI108_ETH) += tsi108_eth.o diff --git a/drivers/net/ax88796.c b/drivers/net/ax88796.c index b718dc6..282fd8e 100644 --- a/drivers/net/ax88796.c +++ b/drivers/net/ax88796.c @@ -809,7 +809,9 @@ static int ax_remove(struct platform_device *_dev) ax = to_ax_dev(dev); unregister_netdev(dev); - free_irq(dev->irq, dev); + if (ax->running) { // already freed in ax_close? + free_irq(dev->irq, dev); + } iounmap(ei_status.mem); release_resource(ax->mem); @@ -935,7 +937,11 @@ static int ax_probe(struct platform_device *pdev) goto exit_mem2; } + #if defined(CONFIG_AX88796_TS_ETH100) || defined(CONFIG_AX88796_TS_ETH100_MODULE) + ei_status.reg_offset[0x10] = ax->map2 - ei_status.mem + 0x10; /* don't know why, but +0x20 works too */ + #else ei_status.reg_offset[0x1f] = ax->map2 - ei_status.mem; + #endif } /* got resources, now initialise and register device */ diff --git a/drivers/net/ax88796_ts_eth100.c b/drivers/net/ax88796_ts_eth100.c new file mode 100644 index 0000000..448b3e3 --- /dev/null +++ b/drivers/net/ax88796_ts_eth100.c @@ -0,0 +1,190 @@ +/* + * linux/drivers/net/ax88796_ts_eth100.c + * Technologic Systems TS-ETH100 support. + * + * (c) Copyright 2008 Matthieu Crapet + * + * 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. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#define TS72XX_ETH100_IO8_PHYS_BASE (TS72XX_PC104_8BIT_IO_PHYS_BASE) +#define TS72XX_ETH100_IO8_SIZE (TS72XX_PC104_8BIT_IO_SIZE) +#define TS72XX_ETH100_IO16_PHYS_BASE (TS72XX_PC104_16BIT_IO_PHYS_BASE) +#define TS72XX_ETH100_IO16_SIZE (TS72XX_PC104_16BIT_IO_SIZE) + +/* Technologic systems I/O space */ +#define TS_ETH100_PLD_0 0x100 +#define TS_ETH100_PLD_1 0x110 +#define TS_ETH100_PLD_2 0x120 +#define TS_ETH100_PLD_3 0x130 + +/* NE2000 I/O space */ +#define TS_ETH100_MAC_0 0x200 +#define TS_ETH100_MAC_1 0x240 +#define TS_ETH100_MAC_2 0x300 +#define TS_ETH100_MAC_3 0x340 + +/* Board identifier must be 5 ; PLD revision should be 1 */ +#define is_eth100_present(__iomem, __offset) \ + (((__raw_readb(__iomem + __offset) & 0xF) == 0x5) && \ + ((__raw_readb(__iomem + __offset + 4) & 0xF) == 0x1)) + +/* Jumpers status (SRAM control register) */ +#define read_irq(__iomem, __offset) \ + (__raw_readb(__iomem + __offset + 8) & 0xE) + + +static u32 offsets[0x20] = { + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, + 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, + 0x18, 0x19, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F +}; + +static struct ax_plat_data ts72xx_eth100_asix_data = { + .flags = AXFLG_HAS_93CX6, + .wordlength = 2, + .dcr_val = 0x48, + .rcr_val = 0x40, + .reg_offsets = offsets, +}; + +static struct resource ts72xx_eth100_resource[] = { + [0] = { + .start = TS72XX_ETH100_IO8_PHYS_BASE, + .end = TS72XX_ETH100_IO8_PHYS_BASE + 0x40 - 1, + .flags = IORESOURCE_MEM + }, + [1] = { /* 0x10 is NE_DATAPORT is 16-bit access */ + .start = TS72XX_ETH100_IO16_PHYS_BASE, + .end = TS72XX_ETH100_IO16_PHYS_BASE + 0x40 - 1, + .flags = IORESOURCE_MEM + }, + [2] = { + .start = IRQ_EP93XX_EXT1, + .end = IRQ_EP93XX_EXT1, + .flags = IORESOURCE_IRQ + } +}; + +static int ts_eth100_irq; // 2 [IRQ 5], 4 [IRQ 6] or 8 [IRQ 7] (jumper configuration) + + +static void ts72xx_eth100_release(struct device *dev) +{ + /* nothing to do (no kfree) because we have static struct */ +} + +static struct platform_device ts72xx_eth100_device_asix = { + .name = "ax88796", + .id = 0, + .num_resources = ARRAY_SIZE(ts72xx_eth100_resource), + .resource = ts72xx_eth100_resource, + .dev = { + .platform_data = &ts72xx_eth100_asix_data, + .release = ts72xx_eth100_release, + } +}; + +static int __init ts_eth100_init(void) +{ + void __iomem *iomem; + struct platform_device *ethX = NULL; + + iomem = ioremap(TS72XX_ETH100_IO8_PHYS_BASE, TS72XX_ETH100_IO8_SIZE); + if (iomem != NULL) { + ethX = &ts72xx_eth100_device_asix; + + if (is_eth100_present(iomem, TS_ETH100_PLD_0)) { + ethX->resource[0].start += TS_ETH100_MAC_0; + ethX->resource[0].end += TS_ETH100_MAC_0; + ethX->resource[1].start += TS_ETH100_MAC_0; + ethX->resource[1].end += TS_ETH100_MAC_0; + ts_eth100_irq = read_irq(iomem, TS_ETH100_PLD_0); + } else if(is_eth100_present(iomem, TS_ETH100_PLD_1)) { + ethX->resource[0].start += TS_ETH100_MAC_1; + ethX->resource[0].end += TS_ETH100_MAC_1; + ethX->resource[1].start += TS_ETH100_MAC_1; + ethX->resource[1].end += TS_ETH100_MAC_1; + ts_eth100_irq = read_irq(iomem, TS_ETH100_PLD_1); + } else if(is_eth100_present(iomem, TS_ETH100_PLD_2)) { + ethX->resource[0].start += TS_ETH100_MAC_2; + ethX->resource[0].end += TS_ETH100_MAC_2; + ethX->resource[1].start += TS_ETH100_MAC_2; + ethX->resource[1].end += TS_ETH100_MAC_2; + ts_eth100_irq = read_irq(iomem, TS_ETH100_PLD_2); + } else if(is_eth100_present(iomem, TS_ETH100_PLD_3)) { + ethX->resource[0].start += TS_ETH100_MAC_3; + ethX->resource[0].end += TS_ETH100_MAC_3; + ethX->resource[1].start += TS_ETH100_MAC_3; + ethX->resource[1].end += TS_ETH100_MAC_3; + ts_eth100_irq = read_irq(iomem, TS_ETH100_PLD_3); + } else { + ethX = NULL; + } + + /* Translate IRQ number */ + if (ethX != NULL) { + int ret, irq = 0; + switch (ts_eth100_irq) { + case 0x2: /* IRQ5 */ + irq = gpio_to_irq(EP93XX_GPIO_LINE_F(3)); + ret = gpio_request(irq, "TS-ETH100"); + if (ret < 0) { + ethX = NULL; + goto init_error; + } else { + gpio_direction_input(irq); + set_irq_type(irq, IRQ_TYPE_EDGE_RISING); + } + break; + case 0x4: /* IRQ6 */ + irq = IRQ_EP93XX_EXT1; + break; + case 0x8: /* IRQ7 */ + default: + irq = IRQ_EP93XX_EXT3; + } + ethX->resource[2].start = irq; + ethX->resource[2].end = irq; + } +init_error: + iounmap(iomem); + } + + return ((ethX == NULL) ? -ENODEV : + platform_device_register(&ts72xx_eth100_device_asix)); +} + + +static void __exit ts_eth100_exit(void) +{ + platform_device_unregister(&ts72xx_eth100_device_asix); + if (ts_eth100_irq == 2) + gpio_free(EP93XX_GPIO_LINE_F(3)); +} + +module_init(ts_eth100_init); +module_exit(ts_eth100_exit); + +MODULE_AUTHOR("Matthieu Crapet "); +MODULE_DESCRIPTION("Asix 88796 ethernet probe module for TS-ETH100 (TS-72xx)"); +MODULE_LICENSE("GPL"); +MODULE_VERSION("0.21"); -- 1.7.1