summaryrefslogtreecommitdiff
path: root/drivers
diff options
context:
space:
mode:
authorRobert Hodaszi <robert.hodaszi@digi.com>2011-05-23 14:28:03 +0200
committerHector Palacios <hector.palacios@digi.com>2011-09-01 10:36:33 +0200
commit5ea5e14ba2919ce14bd7d8f5f6f202b04e502517 (patch)
tree7d50a00b1e64a9eff0fffc3f924b408f83a253ce /drivers
parentaf0c7f7ef6061906932b9664b499725ede2c4262 (diff)
merge: merged changes from 2.6.28
Conflicts: gpio Special handling of PORT A gpios is lost. Some code has been ported but it must be fixed. Signed-off-by: Hector Palacios <hector.palacios@digi.com> Signed-off-by: Robert Hodaszi <robert.hodaszi@digi.com>
Diffstat (limited to 'drivers')
-rw-r--r--drivers/char/adc-s3c2443.c3
-rw-r--r--drivers/input/touchscreen/s3c24xx_ts.c2
-rw-r--r--drivers/mmc/host/Kconfig11
-rw-r--r--drivers/mmc/host/s3c-hsmmc.c44
-rw-r--r--drivers/mmc/host/s3cmci.c587
-rw-r--r--drivers/mtd/nand/s3c2410.c427
-rw-r--r--drivers/net/Kconfig9
-rw-r--r--drivers/net/Makefile1
-rw-r--r--drivers/net/smsc9118/Makefile1
-rw-r--r--drivers/net/smsc9118/smsc911x.c2711
-rw-r--r--drivers/net/smsc9118/smsc911x.h393
-rw-r--r--drivers/pcmcia/Kconfig7
-rw-r--r--drivers/pcmcia/Makefile1
-rw-r--r--drivers/serial/samsung.c32
-rw-r--r--drivers/spi/spi_s3c2443.c18
-rw-r--r--drivers/usb/gadget/Kconfig15
-rw-r--r--drivers/usb/gadget/gadget_chips.h11
-rw-r--r--drivers/usb/gadget/s3c2443_udc.c16
-rw-r--r--drivers/usb/gadget/s3c2443_udc.h8
-rw-r--r--drivers/watchdog/s3c2410_wdt.c2
20 files changed, 754 insertions, 3545 deletions
diff --git a/drivers/char/adc-s3c2443.c b/drivers/char/adc-s3c2443.c
index 34de79e20045..1f41f18bca8b 100644
--- a/drivers/char/adc-s3c2443.c
+++ b/drivers/char/adc-s3c2443.c
@@ -29,9 +29,10 @@
#include <linux/platform_device.h>
#include <linux/uaccess.h>
#include <linux/delay.h>
+#include <linux/slab.h>
#include <plat/regs-adc.h>
-#include <plat/ts.h>
+#include <plat/s3c_ts.h>
#define DRIVER_NAME "s3c2443-adc"
#ifndef NUM_CHANNELS
diff --git a/drivers/input/touchscreen/s3c24xx_ts.c b/drivers/input/touchscreen/s3c24xx_ts.c
index dd6929551b29..58a851e7f105 100644
--- a/drivers/input/touchscreen/s3c24xx_ts.c
+++ b/drivers/input/touchscreen/s3c24xx_ts.c
@@ -65,7 +65,7 @@
#include <mach/irqs.h>
#include <mach/map.h>
-#include <plat/ts.h>
+#include <plat/s3c_ts.h>
#include <plat/regs-adc.h>
diff --git a/drivers/mmc/host/Kconfig b/drivers/mmc/host/Kconfig
index 951f1fd2661f..d12d560e2a0b 100644
--- a/drivers/mmc/host/Kconfig
+++ b/drivers/mmc/host/Kconfig
@@ -418,6 +418,17 @@ config MMC_S3C_PIODMA
endchoice
+config HSMMC_S3C
+ tristate "Samsung S3C High Speed SD/MMC Card Interface support"
+ depends on ARCH_S3C2410 && MMC
+ help
+ This selects a driver for the High Speed MMC interface found in
+ Samsung's S3C2410, S3C2412, S3C2440, S3C2442 CPUs.
+ If you have a board based on one of those and a MMC/SD
+ slot, say Y or M here.
+
+ If unsure, say N.
+
config MMC_SDRICOH_CS
tristate "MMC/SD driver for Ricoh Bay1Controllers (EXPERIMENTAL)"
depends on EXPERIMENTAL && PCI && PCMCIA
diff --git a/drivers/mmc/host/s3c-hsmmc.c b/drivers/mmc/host/s3c-hsmmc.c
index 21986a2c72f7..e5d337159398 100644
--- a/drivers/mmc/host/s3c-hsmmc.c
+++ b/drivers/mmc/host/s3c-hsmmc.c
@@ -41,13 +41,15 @@
#include <asm/irq.h>
#include <asm/scatterlist.h>
#include <asm/sizes.h>
-#include <asm/mach/mmc.h>
+//#include <linux/amba/mmci.h>
#include <mach/dma.h>
#include <plat/hsmmc.h>
#include <mach/regs-hsmmc.h>
#include <mach/regs-gpio.h>
#include <mach/regs-gpioj.h>
+#include <mach/gpio-fns.h>
+#include <mach/gpio-nrs.h>
#define printk_err(fmt, args...) printk(KERN_ERR "[ ERROR ] hsmmc: " fmt, ## args)
@@ -192,7 +194,7 @@ static void s3c_hsmmc_activate_led(struct s3c_hsmmc_host *host)
unsigned int ctrl;
struct s3c_hsmmc_cfg *cfg = host->plat_data;
- if (cfg->gpio_led == S3C2443_GPJ13) {
+ if (cfg->gpio_led == S3C2410_GPJ(13)) {
ctrl = s3c_hsmmc_readl(S3C2410_HSMMC_HOSTCTL);
ctrl &= ~S3C_HSMMC_CTRL_LED;
s3c_hsmmc_writel(ctrl, S3C2410_HSMMC_HOSTCTL);
@@ -210,7 +212,7 @@ static void s3c_hsmmc_deactivate_led(struct s3c_hsmmc_host *host)
unsigned int ctrl;
struct s3c_hsmmc_cfg *cfg = host->plat_data;
- if (cfg->gpio_led == S3C2443_GPJ13) {
+ if (cfg->gpio_led == S3C2410_GPJ(13)) {
ctrl = s3c_hsmmc_readl(S3C2410_HSMMC_HOSTCTL);
ctrl |= S3C_HSMMC_CTRL_LED;
s3c_hsmmc_writel(ctrl, S3C2410_HSMMC_HOSTCTL);
@@ -996,33 +998,33 @@ static void s3c_hsmmc_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
switch (ios->power_mode) {
case MMC_POWER_ON:
case MMC_POWER_UP:
- s3c2410_gpio_cfgpin(S3C2443_GPL0, S3C2443_GPL0_SD0DAT0);
+ s3c2410_gpio_cfgpin(S3C2410_GPL(0), S3C2443_GPL0_SD0DAT0);
if (cfg->host_caps & (MMC_CAP_4_BIT_DATA | MMC_CAP_8_BIT_DATA)) {
- s3c2410_gpio_cfgpin(S3C2443_GPL1, S3C2443_GPL1_SD0DAT1);
- s3c2410_gpio_cfgpin(S3C2443_GPL2, S3C2443_GPL2_SD0DAT2);
- s3c2410_gpio_cfgpin(S3C2443_GPL3, S3C2443_GPL3_SD0DAT3);
+ s3c2410_gpio_cfgpin(S3C2410_GPL(1), S3C2443_GPL1_SD0DAT1);
+ s3c2410_gpio_cfgpin(S3C2410_GPL(2), S3C2443_GPL2_SD0DAT2);
+ s3c2410_gpio_cfgpin(S3C2410_GPL(3), S3C2443_GPL3_SD0DAT3);
}
if (cfg->host_caps & MMC_CAP_8_BIT_DATA) {
- s3c2410_gpio_cfgpin(S3C2443_GPL4, S3C2443_GPL4_SD0DAT4);
- s3c2410_gpio_cfgpin(S3C2443_GPL5, S3C2443_GPL5_SD0DAT5);
- s3c2410_gpio_cfgpin(S3C2443_GPL6, S3C2443_GPL6_SD0DAT6);
- s3c2410_gpio_cfgpin(S3C2443_GPL7, S3C2443_GPL7_SD0DAT7);
+ s3c2410_gpio_cfgpin(S3C2410_GPL(4), S3C2443_GPL4_SD0DAT4);
+ s3c2410_gpio_cfgpin(S3C2410_GPL(5), S3C2443_GPL5_SD0DAT5);
+ s3c2410_gpio_cfgpin(S3C2410_GPL(6), S3C2443_GPL6_SD0DAT6);
+ s3c2410_gpio_cfgpin(S3C2410_GPL(7), S3C2443_GPL7_SD0DAT7);
}
- s3c2410_gpio_cfgpin(S3C2443_GPL8, S3C2443_GPL8_SD0CMD);
- s3c2410_gpio_cfgpin(S3C2443_GPL9, S3C2443_GPL9_SD0CLK);
+ s3c2410_gpio_cfgpin(S3C2410_GPL(8), S3C2443_GPL8_SD0CMD);
+ s3c2410_gpio_cfgpin(S3C2410_GPL(9), S3C2443_GPL9_SD0CLK);
/* Check for the dedicated GPIOs of the HSMMC-controller */
- if (cfg->gpio_led == S3C2443_GPJ13)
- s3c2410_gpio_cfgpin(S3C2443_GPJ13, S3C2440_GPJ13_SD0LED);
+ if (cfg->gpio_led == S3C2410_GPJ(13))
+ s3c2410_gpio_cfgpin(S3C2410_GPJ(13), S3C2440_GPJ13_SD0LED);
- if (cfg->gpio_detect == S3C2443_GPJ14)
- s3c2410_gpio_cfgpin(S3C2443_GPJ14, S3C2440_GPJ14_SD0CD);
+ if (cfg->gpio_detect == S3C2410_GPJ(14))
+ s3c2410_gpio_cfgpin(S3C2410_GPJ(14), S3C2440_GPJ14_SD0CD);
- if (cfg->gpio_wprotect == S3C2443_GPJ15)
- s3c2410_gpio_cfgpin(S3C2443_GPJ15, S3C2440_GPJ15_SD0WP);
+ if (cfg->gpio_wprotect == S3C2410_GPJ(15))
+ s3c2410_gpio_cfgpin(S3C2410_GPJ(15), S3C2440_GPJ15_SD0WP);
break;
default:
@@ -1072,7 +1074,7 @@ static int s3c_hsmmc_get_ro(struct mmc_host *mmc)
unsigned int retval;
/* Depending on the configured GPIO get the RO-value */
- if (cfg->gpio_wprotect == S3C2443_GPJ15) {
+ if (cfg->gpio_wprotect == S3C2410_GPJ(15)) {
retval = s3c_hsmmc_readl(S3C2410_HSMMC_PRNSTS);
retval &= S3C_HSMMC_WRITE_PROTECT;
} else if (cfg->gpio_wprotect) {
@@ -1323,7 +1325,7 @@ static int s3c_hsmmc_suspend(struct platform_device *pdev, pm_message_t state)
clk_disable(host->clk[cnt]);
}
- retval = mmc_suspend_host(mmc, state);
+ retval = mmc_suspend_host(mmc);
return retval;
}
diff --git a/drivers/mmc/host/s3cmci.c b/drivers/mmc/host/s3cmci.c
index 2e16e0a90a5e..f92f565e454e 100644
--- a/drivers/mmc/host/s3cmci.c
+++ b/drivers/mmc/host/s3cmci.c
@@ -3,9 +3,6 @@
*
* Copyright (C) 2004-2006 maintech GmbH, Thomas Kleffel <tk@maintech.de>
*
- * Current driver maintained by Ben Dooks and Simtec Electronics
- * Copyright (C) 2008 Simtec Electronics <ben-linux@fluff.org>
- *
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
@@ -22,11 +19,15 @@
#include <linux/gpio.h>
#include <linux/irq.h>
#include <linux/io.h>
-
+#include <linux/mmc/mmc.h>
#include <mach/dma.h>
+/* Use the old headers system */
#include <mach/regs-sdi.h>
#include <mach/regs-gpio.h>
+#include <mach/gpio.h>
+#include <asm/delay.h>
+#include <linux/delay.h>
#include <plat/mci.h>
@@ -34,6 +35,22 @@
#define DRIVER_NAME "s3c-mci"
+#define printk_err(fmt, args...) printk(KERN_ERR "[ ERROR ] s3c2443-sdi: " fmt, ## args)
+#define printk_info(fmt, args...) printk(KERN_INFO "s3c2443-sdi: " fmt, ## args)
+#define printk_dbg(fmt, args...) printk(KERN_DEBUG "s3c2443-sdi: " fmt, ## args)
+
+/* Enable/disable the debug messages */
+#if 0
+#define S3C2443_SDI_DEBUG
+#endif
+
+#ifdef S3C2443_SDI_DEBUG
+# define printk_debug(fmt, args...) printk(KERN_DEBUG "s3c2443-sdi: %s() " fmt, __FUNCTION__ , ## args)
+#else
+# define printk_debug(fmt, args...)
+#endif
+
+
enum dbg_channels {
dbg_err = (1 << 0),
dbg_debug = (1 << 1),
@@ -46,9 +63,9 @@ enum dbg_channels {
dbg_conf = (1 << 8),
};
-static const int dbgmap_err = dbg_fail;
+static const int dbgmap_err = dbg_err | dbg_fail;
static const int dbgmap_info = dbg_info | dbg_conf;
-static const int dbgmap_debug = dbg_err | dbg_debug;
+static const int dbgmap_debug = dbg_debug;
#define dbg(host, channels, args...) \
do { \
@@ -254,7 +271,7 @@ static void s3cmci_check_sdio_irq(struct s3cmci_host *host)
}
static inline int get_data_buffer(struct s3cmci_host *host,
- u32 *bytes, u32 **pointer)
+ u32 *words, u32 **pointer)
{
struct scatterlist *sg;
@@ -271,7 +288,7 @@ static inline int get_data_buffer(struct s3cmci_host *host,
}
sg = &host->mrq->data->sg[host->pio_sgptr];
- *bytes = sg->length;
+ *words = sg->length >> 2;
*pointer = sg_virt(sg);
host->pio_sgptr++;
@@ -287,7 +304,7 @@ static inline u32 fifo_count(struct s3cmci_host *host)
u32 fifostat = readl(host->base + S3C2410_SDIFSTA);
fifostat &= S3C2410_SDIFSTA_COUNTMASK;
- return fifostat;
+ return fifostat >> 2;
}
static inline u32 fifo_free(struct s3cmci_host *host)
@@ -295,7 +312,7 @@ static inline u32 fifo_free(struct s3cmci_host *host)
u32 fifostat = readl(host->base + S3C2410_SDIFSTA);
fifostat &= S3C2410_SDIFSTA_COUNTMASK;
- return 63 - fifostat;
+ return (63 - fifostat) >> 2;
}
/**
@@ -306,10 +323,10 @@ static inline u32 fifo_free(struct s3cmci_host *host)
* Enable the main IRQ if needed after it has been disabled.
*
* The IRQ can be one of the following states:
- * - disabled during IDLE
- * - disabled whilst processing data
- * - enabled during transfer
- * - enabled whilst awaiting SDIO interrupt detection
+ * - disabled during IDLE
+ * - disabled whilst processing data
+ * - enabled during transfer
+ * - enabled whilst awaiting SDIO interrupt detection
*/
static void s3cmci_enable_irq(struct s3cmci_host *host, bool more)
{
@@ -360,8 +377,6 @@ static void do_pio_read(struct s3cmci_host *host)
{
int res;
u32 fifo;
- u32 *ptr;
- u32 fifo_words;
void __iomem *from_ptr;
/* write real prescaler to host, it might be set slow to fix */
@@ -392,35 +407,14 @@ static void do_pio_read(struct s3cmci_host *host)
fifo, host->pio_bytes,
readl(host->base + S3C2410_SDIDCNT));
- /* If we have reached the end of the block, we can
- * read a word and get 1 to 3 bytes. If we in the
- * middle of the block, we have to read full words,
- * otherwise we will write garbage, so round down to
- * an even multiple of 4. */
- if (fifo >= host->pio_bytes)
+ if (fifo > host->pio_bytes)
fifo = host->pio_bytes;
- else
- fifo -= fifo & 3;
host->pio_bytes -= fifo;
host->pio_count += fifo;
- fifo_words = fifo >> 2;
- ptr = host->pio_ptr;
- while (fifo_words--)
- *ptr++ = readl(from_ptr);
- host->pio_ptr = ptr;
-
- if (fifo & 3) {
- u32 n = fifo & 3;
- u32 data = readl(from_ptr);
- u8 *p = (u8 *)host->pio_ptr;
-
- while (n--) {
- *p++ = data;
- data >>= 8;
- }
- }
+ while (fifo--)
+ *(host->pio_ptr++) = readl(from_ptr);
}
if (!host->pio_bytes) {
@@ -444,7 +438,6 @@ static void do_pio_write(struct s3cmci_host *host)
void __iomem *to_ptr;
int res;
u32 fifo;
- u32 *ptr;
to_ptr = host->base + host->sdidata;
@@ -466,23 +459,14 @@ static void do_pio_write(struct s3cmci_host *host)
}
- /* If we have reached the end of the block, we have to
- * write exactly the remaining number of bytes. If we
- * in the middle of the block, we have to write full
- * words, so round down to an even multiple of 4. */
- if (fifo >= host->pio_bytes)
+ if (fifo > host->pio_bytes)
fifo = host->pio_bytes;
- else
- fifo -= fifo & 3;
host->pio_bytes -= fifo;
host->pio_count += fifo;
- fifo = (fifo + 3) >> 2;
- ptr = host->pio_ptr;
while (fifo--)
- writel(*ptr++, to_ptr);
- host->pio_ptr = ptr;
+ writel(*(host->pio_ptr++), to_ptr);
}
enable_imask(host, S3C2410_SDIIMSK_TXFIFOHALF);
@@ -492,6 +476,7 @@ static void pio_tasklet(unsigned long data)
{
struct s3cmci_host *host = (struct s3cmci_host *) data;
+
s3cmci_disable_irq(host, true);
if (host->pio_active == XFER_WRITE)
@@ -518,6 +503,17 @@ static void pio_tasklet(unsigned long data)
s3cmci_enable_irq(host, true);
}
+/* The DMA-callback will call this function by errors or transfer completes */
+static void dma_tasklet(unsigned long data)
+{
+ struct s3cmci_host *host = (struct s3cmci_host *) data;
+
+ if (host->complete_what == COMPLETION_FINALIZE) {
+ clear_imask(host);
+ finalize_request(host);
+ }
+}
+
/*
* ISR for SDI Interface IRQ
* Communication between driver and ISR works as follows:
@@ -573,6 +569,15 @@ static irqreturn_t s3cmci_irq(int irq, void *dev_id)
mci_fsta = readl(host->base + S3C2410_SDIFSTA);
mci_dclear = 0;
+ printk_debug("IRQ: cmd 0x%08x | dsta 0x%08x | imsk 0x%08x\n",
+ mci_csta, mci_dsta, mci_imsk);
+
+ if (mci_dsta & S3C2410_SDIDSTA_SDIOIRQDETECT) {
+ printk_debug("SDIO IRQ detected\n");
+ mmc_signal_sdio_irq(host->mmc);
+ writel(S3C2410_SDIDSTA_SDIOIRQDETECT, host->base + S3C2410_SDIDSTA);
+ }
+
if ((host->complete_what == COMPLETION_NONE) ||
(host->complete_what == COMPLETION_FINALIZE)) {
host->status = "nothing to complete";
@@ -616,19 +621,22 @@ static irqreturn_t s3cmci_irq(int irq, void *dev_id)
}
if (mci_csta & S3C2410_SDICMDSTAT_CMDTIMEOUT) {
- dbg(host, dbg_err, "CMDSTAT: error CMDTIMEOUT\n");
+ dbg(host, dbg_debug, "CMDSTAT: error CMDTIMEOUT\n");
cmd->error = -ETIMEDOUT;
host->status = "error: command timeout";
goto fail_transfer;
}
if (mci_csta & S3C2410_SDICMDSTAT_CMDSENT) {
+
+ /* @FIXME: Move the write-command to a correct place! (Luis G.) */
+ mci_cclear |= S3C2410_SDICMDSTAT_CMDSENT;
+ writel(mci_cclear, host->base + S3C2410_SDICMDSTAT);
+
if (host->complete_what == COMPLETION_CMDSENT) {
host->status = "ok: command sent";
goto close_transfer;
}
-
- mci_cclear |= S3C2410_SDICMDSTAT_CMDSENT;
}
if (mci_csta & S3C2410_SDICMDSTAT_CRCFAIL) {
@@ -732,8 +740,22 @@ close_transfer:
host->complete_what = COMPLETION_FINALIZE;
clear_imask(host);
- tasklet_schedule(&host->pio_tasklet);
+ /*
+ * If we have received an interrupt although we are waiting for the
+ * DMA-callback (cmd->data), then something went wrong with the last
+ * transfer. This happens when the card is removed before
+ * the card initialization was completed.
+ * (Luis Galdos)
+ */
+ if (cmd->data && s3cmci_host_usedma(host) && !cmd->data->error && !cmd->error) {
+ host->dma_complete = 1;
+ cmd->error = cmd->data->error = -EILSEQ;
+ printk_debug("[SD] Waiting DMA (CMD %08x | DAT %08x)\n",
+ mci_csta, mci_dsta);
+ }
+
+ tasklet_schedule(&host->pio_tasklet);
goto irq_out;
irq_out:
@@ -750,13 +772,26 @@ irq_out:
* ISR for the CardDetect Pin
*/
+static int s3cmci_card_present(struct mmc_host *mmc);
+
static irqreturn_t s3cmci_irq_cd(int irq, void *dev_id)
{
struct s3cmci_host *host = (struct s3cmci_host *)dev_id;
-
- dbg(host, dbg_irq, "card detect\n");
-
- mmc_detect_change(host->mmc, msecs_to_jiffies(500));
+ int val;
+ static int card_present;
+
+ /*
+ * Get the current status of the GPIO for checking if the card state has
+ * really changed since the last interrupt. Otherwise it will generates
+ * more than one interrupt for the same state
+ * Luis Galdos
+ */
+ val = s3cmci_card_present(host->mmc);
+ if (val != card_present) {
+ dbg(host, dbg_debug, "Card detect IRQ: %s\n", val ? "insert" : "remove");
+ card_present = val;
+ mmc_detect_change(host->mmc, msecs_to_jiffies(500));
+ }
return IRQ_HANDLED;
}
@@ -781,30 +816,49 @@ static void s3cmci_dma_done_callback(struct s3c2410_dma_chan *dma_ch,
spin_lock_irqsave(&host->complete_lock, iflags);
if (result != S3C2410_RES_OK) {
- dbg(host, dbg_fail, "DMA FAILED: csta=0x%08x dsta=0x%08x "
- "fsta=0x%08x dcnt:0x%08x result:0x%08x toGo:%u\n",
- mci_csta, mci_dsta, mci_fsta,
- mci_dcnt, result, host->dmatogo);
+ struct mmc_request *mrq = host->mrq;
+
+ if (mrq) {
+ struct mmc_command *cmd;
+
+ cmd = mrq->cmd;
+ dbg(host, dbg_fail, "DMA FAILED: CMD%i csta=0x%08x dsta=0x%08x "
+ "fsta=0x%08x dcnt:0x%08x result:%i toGo:%u\n",
+ cmd->opcode, mci_csta, mci_dsta, mci_fsta,
+ mci_dcnt, result, host->dmatogo);
+ } else
+ dbg(host, dbg_fail, "DMA FAILED: csta=0x%08x dsta=0x%08x "
+ "fsta=0x%08x dcnt:0x%08x result:0x%08x toGo:%u\n",
+ mci_csta, mci_dsta, mci_fsta,
+ mci_dcnt, result, host->dmatogo);
goto fail_request;
}
host->dmatogo--;
if (host->dmatogo) {
- dbg(host, dbg_dma, "DMA DONE Size:%i DSTA:[%08x] "
- "DCNT:[%08x] toGo:%u\n",
- size, mci_dsta, mci_dcnt, host->dmatogo);
+ printk_debug("DMA DONE Size:%i DSTA:[%08x] "
+ "DCNT:[%08x] toGo:%u\n",
+ size, mci_dsta, mci_dcnt, host->dmatogo);
- goto out;
+ if (mci_dsta & S3C2410_SDIDSTA_XFERFINISH) {
+ printk_err("SDI has no more data, but DMA waits for more?\n");
+ goto fail_request;
+ }
+
+ spin_unlock_irqrestore(&host->complete_lock, iflags);
+ return;
}
- dbg(host, dbg_dma, "DMA FINISHED Size:%i DSTA:%08x DCNT:%08x\n",
- size, mci_dsta, mci_dcnt);
+ printk_debug("DMA ENDE Size:%i DSTA:[%08x] DCNT:[%08x]\n",
+ size, mci_dsta, mci_dcnt);
host->dma_complete = 1;
host->complete_what = COMPLETION_FINALIZE;
out:
+ /* @FIXME: Check the performance modification through this delay */
+ udelay(10);
tasklet_schedule(&host->pio_tasklet);
spin_unlock_irqrestore(&host->complete_lock, iflags);
return;
@@ -815,6 +869,7 @@ fail_request:
clear_imask(host);
goto out;
+
}
static void finalize_request(struct s3cmci_host *host)
@@ -823,19 +878,24 @@ static void finalize_request(struct s3cmci_host *host)
struct mmc_command *cmd;
int debug_as_failure = 0;
- if (host->complete_what != COMPLETION_FINALIZE)
- return;
+ spin_lock(&host->complete_lock);
+
+ if (host->complete_what != COMPLETION_FINALIZE) {
+ printk_debug("Nothing to complete!\n");
+ goto exit_unlock;
+ }
+
+ if (!mrq) {
+ printk_err("Empty MMC request found!\n");
+ goto exit_unlock;
+ }
- if (!mrq)
- return;
cmd = host->cmd_is_stop ? mrq->stop : mrq->cmd;
- if (cmd->data && (cmd->error == 0) &&
- (cmd->data->error == 0)) {
+ if (cmd->data && (cmd->error == 0) && (cmd->data->error == 0)) {
if (s3cmci_host_usedma(host) && (!host->dma_complete)) {
- dbg(host, dbg_dma, "DMA Missing (%d)!\n",
- host->dma_complete);
- return;
+ printk_err("DMA complete missing (%i)\n", host->dma_complete);
+ goto exit_unlock;
}
}
@@ -857,8 +917,8 @@ static void finalize_request(struct s3cmci_host *host)
/* Cleanup controller */
writel(0, host->base + S3C2410_SDICMDARG);
- writel(S3C2410_SDIDCON_STOP, host->base + S3C2410_SDIDCON);
writel(0, host->base + S3C2410_SDICMDCON);
+ writel(S3C2410_SDIDCON_STOP, host->base + S3C2410_SDIDCON);
clear_imask(host);
if (cmd->data && cmd->error)
@@ -867,7 +927,7 @@ static void finalize_request(struct s3cmci_host *host)
if (cmd->data && cmd->data->stop && (!host->cmd_is_stop)) {
host->cmd_is_stop = 1;
s3cmci_send_request(host->mmc);
- return;
+ goto exit_unlock;
}
/* If we have no data transfer we are finished here */
@@ -910,13 +970,17 @@ request_done:
s3cmci_check_sdio_irq(host);
mmc_request_done(host->mmc, mrq);
+
+ exit_unlock:
+ spin_unlock(&host->complete_lock);
+
}
static void s3cmci_dma_setup(struct s3cmci_host *host,
enum s3c2410_dmasrc source)
{
static enum s3c2410_dmasrc last_source = -1;
- static int setup_ok;
+ static int setup_ok = 0;
if (last_source == source)
return;
@@ -927,10 +991,11 @@ static void s3cmci_dma_setup(struct s3cmci_host *host,
host->mem->start + host->sdidata);
if (!setup_ok) {
+ printk_debug("Setting up the DMA channel!\n");
s3c2410_dma_config(host->dma, 4);
s3c2410_dma_set_buffdone_fn(host->dma,
s3cmci_dma_done_callback);
- s3c2410_dma_setflags(host->dma, S3C2410_DMAF_AUTOSTART);
+ s3c2410_dma_ctrl(host->dma, S3C2410_DMAOP_FLUSH);
setup_ok = 1;
}
}
@@ -982,10 +1047,11 @@ static int s3cmci_setup_data(struct s3cmci_host *host, struct mmc_data *data)
/* We cannot deal with unaligned blocks with more than
* one block being transfered. */
- if (data->blocks > 1) {
- pr_warning("%s: can't do non-word sized block transfers (blksz %d)\n", __func__, data->blksz);
+ if (data->blocks > 1)
return -EINVAL;
- }
+
+ /* No support yet for non-word block transfers. */
+ return -EINVAL;
}
while (readl(host->base + S3C2410_SDIDSTA) &
@@ -1032,12 +1098,15 @@ static int s3cmci_setup_data(struct s3cmci_host *host, struct mmc_data *data)
writel(dcon, host->base + S3C2410_SDIDCON);
/* write BSIZE register */
-
writel(data->blksz, host->base + S3C2410_SDIBSIZE);
/* add to IMASK register */
imsk = S3C2410_SDIIMSK_FIFOFAIL | S3C2410_SDIIMSK_DATACRC |
- S3C2410_SDIIMSK_DATATIMEOUT | S3C2410_SDIIMSK_DATAFINISH;
+ S3C2410_SDIIMSK_DATATIMEOUT;
+
+ /* By DMA-support we will use the DMA-callback for the transfer-complete */
+ if (!s3cmci_host_usedma(host))
+ imsk |= S3C2410_SDIIMSK_DATAFINISH;
enable_imask(host, imsk);
@@ -1084,27 +1153,33 @@ static int s3cmci_prepare_dma(struct s3cmci_host *host, struct mmc_data *data)
{
int dma_len, i;
int rw = data->flags & MMC_DATA_WRITE;
+ int retval;
BUG_ON((data->flags & BOTH_DIR) == BOTH_DIR);
- s3cmci_dma_setup(host, rw ? S3C2410_DMASRC_MEM : S3C2410_DMASRC_HW);
+ printk_debug("New DMA transfer | %i Blks | %i Blksz\n",
+ data->blocks, data->blksz);
+
s3c2410_dma_ctrl(host->dma, S3C2410_DMAOP_FLUSH);
+ s3cmci_dma_setup(host, rw ? S3C2410_DMASRC_MEM : S3C2410_DMASRC_HW);
dma_len = dma_map_sg(mmc_dev(host->mmc), data->sg, data->sg_len,
rw ? DMA_TO_DEVICE : DMA_FROM_DEVICE);
- if (dma_len == 0)
- return -ENOMEM;
+ if (dma_len == 0) {
+ printk_err("dma_map_sg failed, no memory available?\n");
+ retval = -ENOMEM;
+ goto exit_all;
+ }
- host->dma_complete = 0;
host->dmatogo = dma_len;
for (i = 0; i < dma_len; i++) {
int res;
- dbg(host, dbg_dma, "enqueue %i: %08x@%u\n", i,
- sg_dma_address(&data->sg[i]),
- sg_dma_len(&data->sg[i]));
+ printk_debug("Enqueue %i @ 0x%08x | %u bytes\n", i,
+ sg_dma_address(&data->sg[i]),
+ sg_dma_len(&data->sg[i]));
res = s3c2410_dma_enqueue(host->dma, host,
sg_dma_address(&data->sg[i]),
@@ -1112,13 +1187,31 @@ static int s3cmci_prepare_dma(struct s3cmci_host *host, struct mmc_data *data)
if (res) {
s3c2410_dma_ctrl(host->dma, S3C2410_DMAOP_FLUSH);
- return -EBUSY;
+ printk_err("Couldn't enqueue a DMA-buffer\n");
+ retval = -EBUSY;
+ goto exit_all;
}
}
+ /*
+ * Disable the data counter interrupt, then the DMA-callback will be
+ * responsible for finalizing the request
+ */
+ disable_imask(host, S3C2410_SDIIMSK_DATAFINISH |
+ S3C2410_SDIIMSK_RXFIFOHALF |
+ S3C2410_SDIIMSK_RXFIFOFULL |
+ S3C2410_SDIIMSK_RXFIFOLAST |
+ S3C2410_SDIIMSK_TXFIFOEMPTY |
+ S3C2410_SDIIMSK_TXFIFOHALF);
+
+ host->dma_complete = 0;
s3c2410_dma_ctrl(host->dma, S3C2410_DMAOP_START);
- return 0;
+ retval = 0;
+
+ exit_all:
+
+ return retval;
}
static void s3cmci_send_request(struct mmc_host *mmc)
@@ -1130,6 +1223,10 @@ static void s3cmci_send_request(struct mmc_host *mmc)
host->ccnt++;
prepare_dbgmsg(host, cmd, host->cmd_is_stop);
+ /* @XXX: Sending the switch command with data leads to a DMA-failure, why? */
+ if (cmd->opcode == MMC_SWITCH && cmd->data)
+ udelay(200);
+
/* Clear command, data and fifo status registers
Fifo clear only necessary on 2440, but doesn't hurt on 2410
*/
@@ -1140,6 +1237,11 @@ static void s3cmci_send_request(struct mmc_host *mmc)
if (cmd->data) {
int res = s3cmci_setup_data(host, cmd->data);
+ printk_debug("CMD%u: %s transfer | %i blks | %u blksz\n",
+ cmd->opcode,
+ (cmd->data->flags & MMC_DATA_READ) ? "RX" : "TX",
+ cmd->data->blocks, cmd->data->blksz);
+
host->dcnt++;
if (res) {
@@ -1170,7 +1272,24 @@ static void s3cmci_send_request(struct mmc_host *mmc)
s3cmci_send_command(host, cmd);
/* Enable Interrupt */
- s3cmci_enable_irq(host, true);
+ if (!s3cmci_host_usedma(host))
+ s3cmci_enable_irq(host, true);
+
+ /*
+ * If the host supports DMA, then disable the data finish interrupts and
+ * the FIFO-interrupts, then the DMA-controller will handle the data
+ * transfer and will finish the transfer if no errors ocurrs
+ * @XXX: This is probably not the correct place for this operation
+ * (Luis Galdos)
+ */
+ if (cmd->data && s3cmci_host_usedma(host))
+ disable_imask(host, S3C2410_SDIIMSK_DATAFINISH |
+ S3C2410_SDIIMSK_RXFIFOHALF |
+ S3C2410_SDIIMSK_RXFIFOFULL |
+ S3C2410_SDIIMSK_RXFIFOLAST |
+ S3C2410_SDIIMSK_TXFIFOEMPTY |
+ S3C2410_SDIIMSK_TXFIFOHALF);
+
}
static int s3cmci_card_present(struct mmc_host *mmc)
@@ -1195,40 +1314,18 @@ static void s3cmci_request(struct mmc_host *mmc, struct mmc_request *mrq)
host->mrq = mrq;
if (s3cmci_card_present(mmc) == 0) {
- dbg(host, dbg_err, "%s: no medium present\n", __func__);
+ dbg(host, dbg_debug, "%s: no medium present\n", __func__);
host->mrq->cmd->error = -ENOMEDIUM;
mmc_request_done(mmc, mrq);
} else
s3cmci_send_request(mmc);
}
-static void s3cmci_set_clk(struct s3cmci_host *host, struct mmc_ios *ios)
-{
- u32 mci_psc;
-
- /* Set clock */
- for (mci_psc = 0; mci_psc < 255; mci_psc++) {
- host->real_rate = host->clk_rate / (host->clk_div*(mci_psc+1));
-
- if (host->real_rate <= ios->clock)
- break;
- }
-
- if (mci_psc > 255)
- mci_psc = 255;
-
- host->prescaler = mci_psc;
- writel(host->prescaler, host->base + S3C2410_SDIPRE);
-
- /* If requested clock is 0, real_rate will be 0, too */
- if (ios->clock == 0)
- host->real_rate = 0;
-}
-
static void s3cmci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
{
struct s3cmci_host *host = mmc_priv(mmc);
- u32 mci_con;
+ u32 mci_psc, mci_con;
+ int waitclk;
/* Set the power state */
@@ -1237,13 +1334,6 @@ static void s3cmci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
switch (ios->power_mode) {
case MMC_POWER_ON:
case MMC_POWER_UP:
- s3c2410_gpio_cfgpin(S3C2410_GPE(5), S3C2410_GPE5_SDCLK);
- s3c2410_gpio_cfgpin(S3C2410_GPE(6), S3C2410_GPE6_SDCMD);
- s3c2410_gpio_cfgpin(S3C2410_GPE(7), S3C2410_GPE7_SDDAT0);
- s3c2410_gpio_cfgpin(S3C2410_GPE(8), S3C2410_GPE8_SDDAT1);
- s3c2410_gpio_cfgpin(S3C2410_GPE(9), S3C2410_GPE9_SDDAT2);
- s3c2410_gpio_cfgpin(S3C2410_GPE(10), S3C2410_GPE10_SDDAT3);
-
if (host->pdata->set_power)
host->pdata->set_power(ios->power_mode, ios->vdd);
@@ -1254,8 +1344,6 @@ static void s3cmci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
case MMC_POWER_OFF:
default:
- gpio_direction_output(S3C2410_GPE(5), 0);
-
if (host->is2440)
mci_con |= S3C2440_SDICON_SDRESET;
@@ -1265,8 +1353,6 @@ static void s3cmci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
break;
}
- s3cmci_set_clk(host, ios);
-
/* Set CLOCK_ENABLE */
if (ios->clock)
mci_con |= S3C2410_SDICON_CLOCKTYPE;
@@ -1275,12 +1361,47 @@ static void s3cmci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
writel(mci_con, host->base + S3C2410_SDICON);
+
+ /* Set clock */
+ for (mci_psc = 0; mci_psc < 255; mci_psc++) {
+ host->real_rate = host->clk_rate / (host->clk_div*(mci_psc+1));
+
+ if (host->real_rate <= ios->clock)
+ break;
+ }
+
+ if (mci_psc > 255)
+ mci_psc = 255;
+
+
+ /* If requested clock is 0, real_rate will be 0, too */
+ if (ios->clock == 0)
+ host->real_rate = 0;
+
+ host->prescaler = mci_psc;
+ writel(host->prescaler, host->base + S3C2410_SDIPRE);
+
+ /*
+ * According to the data sheet first configure the register SDICON and
+ * wait at least 74 SDCLK before initializing the SD card.
+ * (Luis Galdos)
+ */
+ waitclk = 1;
+ if (host->real_rate)
+ waitclk = 100 * (1000000 / host->real_rate);
+
+ if (waitclk > 1000)
+ mdelay(waitclk / 1000);
+ else
+ udelay(waitclk);
+
+
if ((ios->power_mode == MMC_POWER_ON) ||
(ios->power_mode == MMC_POWER_UP)) {
- dbg(host, dbg_conf, "running at %lukHz (requested: %ukHz).\n",
+ dbg(host, dbg_debug, "running at %lukHz (requested: %ukHz).\n",
host->real_rate/1000, ios->clock/1000);
} else {
- dbg(host, dbg_conf, "powered down.\n");
+ dbg(host, dbg_debug, "powered down.\n");
}
host->bus_width = ios->bus_width;
@@ -1350,20 +1471,20 @@ static void s3cmci_enable_sdio_irq(struct mmc_host *mmc, int enable)
}
static struct mmc_host_ops s3cmci_ops = {
- .request = s3cmci_request,
- .set_ios = s3cmci_set_ios,
- .get_ro = s3cmci_get_ro,
- .get_cd = s3cmci_card_present,
+ .request = s3cmci_request,
+ .set_ios = s3cmci_set_ios,
+ .get_ro = s3cmci_get_ro,
.enable_sdio_irq = s3cmci_enable_sdio_irq,
};
static struct s3c24xx_mci_pdata s3cmci_def_pdata = {
/* This is currently here to avoid a number of if (host->pdata)
* checks. Any zero fields to ensure reasonable defaults are picked. */
- .no_wprotect = 1,
- .no_detect = 1,
+ .no_wprotect = 1,
+ .no_detect = 1,
};
+#if 0
#ifdef CONFIG_CPU_FREQ
static int s3cmci_cpufreq_transition(struct notifier_block *nb,
@@ -1418,7 +1539,7 @@ static inline void s3cmci_cpufreq_deregister(struct s3cmci_host *host)
{
}
#endif
-
+#endif
#ifdef CONFIG_DEBUG_FS
@@ -1486,7 +1607,7 @@ static int s3cmci_regs_show(struct seq_file *seq, void *v)
for (; rptr->name; rptr++)
seq_printf(seq, "SDI%s\t=0x%08x\n", rptr->name,
- readl(host->base + rptr->addr));
+ readl(host->base + rptr->addr));
seq_printf(seq, "SDIIMSK\t=0x%08x\n", readl(host->base + host->sdiimsk));
@@ -1524,8 +1645,8 @@ static void s3cmci_debugfs_attach(struct s3cmci_host *host)
dev_err(dev, "failed to create debug state file\n");
host->debug_regs = debugfs_create_file("regs", 0444,
- host->debug_root, host,
- &s3cmci_fops_regs);
+ host->debug_root, host,
+ &s3cmci_fops_regs);
if (IS_ERR(host->debug_regs))
dev_err(dev, "failed to create debug regs file\n");
@@ -1583,9 +1704,6 @@ static int __devinit s3cmci_probe(struct platform_device *pdev)
host->pdata = &s3cmci_def_pdata;
}
- spin_lock_init(&host->complete_lock);
- tasklet_init(&host->pio_tasklet, pio_tasklet, (unsigned long) host);
-
if (is2440) {
host->sdiimsk = S3C2440_SDIIMSK;
host->sdidata = S3C2440_SDIDATA;
@@ -1600,9 +1718,17 @@ static int __devinit s3cmci_probe(struct platform_device *pdev)
host->pio_active = XFER_NONE;
#ifdef CONFIG_MMC_S3C_PIODMA
- host->dodma = host->pdata->dma;
+ host->dodma = host->pdata->use_dma;
#endif
+ spin_lock_init(&host->complete_lock);
+
+ /* Depending on the DMA-support use different tasklet-functions */
+ if (!s3cmci_host_usedma(host))
+ tasklet_init(&host->pio_tasklet, pio_tasklet, (unsigned long) host);
+ else
+ tasklet_init(&host->pio_tasklet, dma_tasklet, (unsigned long) host);
+
host->mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
if (!host->mem) {
dev_err(&pdev->dev,
@@ -1723,7 +1849,7 @@ static int __devinit s3cmci_probe(struct platform_device *pdev)
#ifdef CONFIG_MMC_S3C_HW_SDIO_IRQ
mmc->caps = MMC_CAP_4_BIT_DATA | MMC_CAP_SDIO_IRQ;
#else
- mmc->caps = MMC_CAP_4_BIT_DATA;
+ mmc->caps = MMC_CAP_4_BIT_DATA;
#endif
mmc->f_min = host->clk_rate / (host->clk_div * 256);
mmc->f_max = host->clk_rate / host->clk_div;
@@ -1744,29 +1870,51 @@ static int __devinit s3cmci_probe(struct platform_device *pdev)
(host->is2440?"2440":""),
host->base, host->irq, host->irq_cd, host->dma);
+#if 0
ret = s3cmci_cpufreq_register(host);
if (ret) {
dev_err(&pdev->dev, "failed to register cpufreq\n");
goto free_dmabuf;
}
+#endif
ret = mmc_add_host(mmc);
if (ret) {
dev_err(&pdev->dev, "failed to add mmc host.\n");
+#if 0
goto free_cpufreq;
+#else
+ goto free_dmabuf;
+#endif
}
+ /* @FIXME: Get the GPIO-list from the platform-data */
+ s3c2410_gpio_cfgpin(S3C2410_GPE(5), S3C2410_GPE5_SDCLK);
+ s3c2410_gpio_cfgpin(S3C2410_GPE(6), S3C2410_GPE6_SDCMD);
+ s3c2410_gpio_cfgpin(S3C2410_GPE(7), S3C2410_GPE7_SDDAT0);
+ s3c2410_gpio_cfgpin(S3C2410_GPE(8), S3C2410_GPE8_SDDAT1);
+ s3c2410_gpio_cfgpin(S3C2410_GPE(9), S3C2410_GPE9_SDDAT2);
+ s3c2410_gpio_cfgpin(S3C2410_GPE(10), S3C2410_GPE10_SDDAT3);
+
s3cmci_debugfs_attach(host);
platform_set_drvdata(pdev, mmc);
dev_info(&pdev->dev, "%s - using %s, %s SDIO IRQ\n", mmc_hostname(mmc),
- s3cmci_host_usedma(host) ? "dma" : "pio",
- mmc->caps & MMC_CAP_SDIO_IRQ ? "hw" : "sw");
+ s3cmci_host_usedma(host) ? "dma" : "pio",
+ mmc->caps & MMC_CAP_SDIO_IRQ ? "hw" : "sw");
+
+ /* Enable the wakeup for this device (Luis Galdos) */
+ device_init_wakeup(&pdev->dev, 1);
+ device_set_wakeup_enable(&pdev->dev, 0);
+
+ s3cmci_enable_irq(host, true);
return 0;
+#if 0
free_cpufreq:
s3cmci_cpufreq_deregister(host);
+#endif
free_dmabuf:
clk_disable(host->clk);
@@ -1819,11 +1967,29 @@ static void s3cmci_shutdown(struct platform_device *pdev)
free_irq(host->irq_cd, host);
s3cmci_debugfs_remove(host);
+#if 0
s3cmci_cpufreq_deregister(host);
+#endif
mmc_remove_host(mmc);
clk_disable(host->clk);
}
+/*
+ * Don't remove the MMC-host when going to shutdown the system. This can lead to some
+ * failures when the host has mounted a card with our root file system.
+ * (Luis Galdos)
+ */
+static void s3cmci_2440_shutdown(struct platform_device *pdev)
+{
+ struct mmc_host *mmc = platform_get_drvdata(pdev);
+ struct s3cmci_host *host = mmc_priv(mmc);
+
+ if (host->irq_cd >= 0)
+ free_irq(host->irq_cd, host);
+
+ clk_disable(host->clk);
+}
+
static int __devexit s3cmci_remove(struct platform_device *pdev)
{
struct mmc_host *mmc = platform_get_drvdata(pdev);
@@ -1837,6 +2003,7 @@ static int __devexit s3cmci_remove(struct platform_device *pdev)
tasklet_disable(&host->pio_tasklet);
+ /* Free the DMA-channel */
if (s3cmci_host_usedma(host))
s3c2410_dma_free(host->dma, &s3cmci_dma_client);
@@ -1851,7 +2018,6 @@ static int __devexit s3cmci_remove(struct platform_device *pdev)
for (i = S3C2410_GPE(5); i <= S3C2410_GPE(10); i++)
gpio_free(i);
-
iounmap(host->base);
release_mem_region(host->mem->start, resource_size(host->mem));
@@ -1861,14 +2027,14 @@ static int __devexit s3cmci_remove(struct platform_device *pdev)
static struct platform_device_id s3cmci_driver_ids[] = {
{
- .name = "s3c2410-sdi",
- .driver_data = 0,
+ .name = "s3c2410-sdi",
+ .driver_data = 0,
}, {
- .name = "s3c2412-sdi",
- .driver_data = 1,
+ .name = "s3c2412-sdi",
+ .driver_data = 1,
}, {
- .name = "s3c2440-sdi",
- .driver_data = 1,
+ .name = "s3c2440-sdi",
+ .driver_data = 1,
},
{ }
};
@@ -1880,21 +2046,97 @@ MODULE_DEVICE_TABLE(platform, s3cmci_driver_ids);
static int s3cmci_suspend(struct device *dev)
{
- struct mmc_host *mmc = platform_get_drvdata(to_platform_device(dev));
+ int retval;
+ struct mmc_host *mmc;
+ struct s3cmci_host *host;
- return mmc_suspend_host(mmc);
+ mmc = platform_get_drvdata(to_platform_device(dev));
+ host = mmc_priv(mmc);
+
+ retval = mmc_suspend_host(mmc);
+ if (retval)
+ goto exit_suspend;
+
+ /* Check if the wakeup is enabled. IN that case configure it as ext wakeup */
+ if (device_may_wakeup(dev)) {
+ struct s3c24xx_mci_pdata *pdata;
+ unsigned long detect;
+
+ pdata = host->pdata;
+
+ retval = enable_irq_wake(host->irq_cd);
+ if (retval) {
+ dev_err(dev, "Couldn't enable wake IRQ %i\n",
+ host->irq_cd);
+ goto exit_suspend;
+ }
+
+ /*
+ * Reconfigure the card for generating the wakeup when a new
+ * card is plugged into the slot
+ */
+ detect = (pdata->detect_invert) ? (IRQF_TRIGGER_RISING) :
+ (IRQF_TRIGGER_FALLING);
+ set_irq_type(host->irq_cd, detect);
+ }
+
+ writel(S3C2440_SDICON_SDRESET | S3C2410_SDIDCON_STOP,
+ host->base + S3C2410_SDICON);
+
+ clk_disable(host->clk);
+exit_suspend:
+ return retval;
}
static int s3cmci_resume(struct device *dev)
{
- struct mmc_host *mmc = platform_get_drvdata(to_platform_device(dev));
+ struct s3cmci_host *host;
+ struct mmc_host *mmc;
+ int retval;
+
+ mmc = platform_get_drvdata(to_platform_device(dev));
+ host = mmc_priv(mmc);
- return mmc_resume_host(mmc);
+ if (device_may_wakeup(dev)) {
+ retval = disable_irq_wake(host->irq_cd);
+ if (retval) {
+ dev_err(dev, "Couldn't disable wake IRQ %i\n",
+ host->irq_cd);
+ goto exit_resume;
+ }
+
+ set_irq_type(host->irq_cd, IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING);
+ }
+
+ clk_enable(host->clk);
+
+ /* @FIXME: Why do we need to free que DMA-channel? */
+ s3c2410_dma_free(host->dma, &s3cmci_dma_client);
+ s3c2410_dma_request(host->dma, &s3cmci_dma_client, NULL);
+
+ /*
+ * By unsafe resumes we MUST check the card state at this point, then the
+ * higher MMC-layer is probably transferring some kind of data to the
+ * block device that doesn't exist any more.
+ */
+#if defined(CONFIG_MMC_UNSAFE_RESUME)
+ if (s3cmci_card_present(mmc))
+ retval = mmc_resume_host(mmc);
+ else {
+ retval = 0;
+ mmc_detect_change(mmc, msecs_to_jiffies(500));
+ }
+#else
+ retval = mmc_resume_host(mmc);
+#endif /* CONFIG_MMC_UNSAFE_RESUME */
+
+exit_resume:
+ return retval;
}
static const struct dev_pm_ops s3cmci_pm = {
- .suspend = s3cmci_suspend,
- .resume = s3cmci_resume,
+ .suspend = s3cmci_suspend,
+ .resume = s3cmci_resume,
};
#define s3cmci_pm_ops &s3cmci_pm
@@ -1904,17 +2146,18 @@ static const struct dev_pm_ops s3cmci_pm = {
static struct platform_driver s3cmci_driver = {
- .driver = {
- .name = "s3c-sdi",
- .owner = THIS_MODULE,
- .pm = s3cmci_pm_ops,
+ .driver = {
+ .name = "s3c-sdi",
+ .owner = THIS_MODULE,
+ .pm = s3cmci_pm_ops,
},
.id_table = s3cmci_driver_ids,
.probe = s3cmci_probe,
.remove = __devexit_p(s3cmci_remove),
- .shutdown = s3cmci_shutdown,
+ .shutdown = s3cmci_2440_shutdown,
};
+
static int __init s3cmci_init(void)
{
return platform_driver_register(&s3cmci_driver);
@@ -1930,4 +2173,4 @@ module_exit(s3cmci_exit);
MODULE_DESCRIPTION("Samsung S3C MMC/SD Card Interface driver");
MODULE_LICENSE("GPL v2");
-MODULE_AUTHOR("Thomas Kleffel <tk@maintech.de>, Ben Dooks <ben-linux@fluff.org>");
+MODULE_AUTHOR("Thomas Kleffel <tk@maintech.de>");
diff --git a/drivers/mtd/nand/s3c2410.c b/drivers/mtd/nand/s3c2410.c
index 239aadfd01b0..55906ffbc561 100644
--- a/drivers/mtd/nand/s3c2410.c
+++ b/drivers/mtd/nand/s3c2410.c
@@ -1,10 +1,26 @@
/* linux/drivers/mtd/nand/s3c2410.c
*
- * Copyright © 2004-2008 Simtec Electronics
- * http://armlinux.simtec.co.uk/
+ * Copyright (c) 2004,2005 Simtec Electronics
+ * http://www.simtec.co.uk/products/SWLINUX/
* Ben Dooks <ben@simtec.co.uk>
*
- * Samsung S3C2410/S3C2440/S3C2412 NAND driver
+ * Samsung S3C2410/S3C240 NAND driver
+ *
+ * Changelog:
+ * 21-Sep-2004 BJD Initial version
+ * 23-Sep-2004 BJD Multiple device support
+ * 28-Sep-2004 BJD Fixed ECC placement for Hardware mode
+ * 12-Oct-2004 BJD Fixed errors in use of platform data
+ * 18-Feb-2005 BJD Fix sparse errors
+ * 14-Mar-2005 BJD Applied tglx's code reduction patch
+ * 02-May-2005 BJD Fixed s3c2440 support
+ * 02-May-2005 BJD Reduced hwcontrol decode
+ * 20-Jun-2005 BJD Updated s3c2440 support, fixed timing bug
+ * 08-Jul-2005 BJD Fix OOPS when no platform data supplied
+ * 20-Oct-2005 BJD Fix timing calculation bug
+ * 14-Jan-2006 BJD Allow clock to be stopped when idle
+ *
+ * $Id: s3c2410.c,v 1.23 2006/04/01 18:06:29 bjd Exp $
*
* 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
@@ -19,11 +35,7 @@
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
-*/
-
-#ifdef CONFIG_MTD_NAND_S3C2410_DEBUG
-#define DEBUG
-#endif
+ */
#include <linux/module.h>
#include <linux/types.h>
@@ -36,7 +48,6 @@
#include <linux/err.h>
#include <linux/slab.h>
#include <linux/clk.h>
-#include <linux/cpufreq.h>
#include <linux/mtd/mtd.h>
#include <linux/mtd/nand.h>
@@ -48,6 +59,13 @@
#include <plat/regs-nand.h>
#include <plat/nand.h>
+/* Name of the kernel boot parameter with the partitions table */
+#define PARTITON_PARAMETER_NAME "onboard_boot"
+
+#if defined(CONFIG_MTD_NAND_S3C2410_DEBUG) && !defined(DEBUG)
+#define DEBUG
+#endif
+
#ifdef CONFIG_MTD_NAND_S3C2410_HWECC
static int hardware_ecc = 1;
#else
@@ -61,13 +79,35 @@ static const int clock_stop = 0;
#endif
-/* new oob placement block for use with hardware ecc generation
+/*
+ * These are the values that we are using in the U-Boot too.
+ * Luis Galdos
*/
static struct nand_ecclayout nand_hw_eccoob = {
- .eccbytes = 3,
- .eccpos = {0, 1, 2},
- .oobfree = {{8, 8}}
+ .eccbytes = 4,
+ .eccpos = { 40, 41, 42, 43 },
+ .oobfree = {
+ {
+ .offset = 2,
+ .length = 38
+ }
+ }
+};
+
+/*
+ * Nand flash oob definition for SLC 512b page size by jsgood
+ * IMPORTANT: These values are coming from the U-Boot
+ */
+static struct nand_ecclayout nand_hw_eccoob_16 = {
+ .eccbytes = 6,
+ .eccpos = { 0, 1, 2, 3, 6, 7 },
+ .oobfree = {
+ {
+ .offset = 8,
+ .length = 8
+ }
+ }
};
/* controller and mtd information */
@@ -110,7 +150,6 @@ enum s3c_cpu_type {
* @sel_bit: The bit in @sel_reg to select the NAND chip.
* @mtd_count: The number of MTDs created from this controller.
* @save_sel: The contents of @sel_reg to be saved over suspend.
- * @clk_rate: The clock rate from @clk.
* @cpu_type: The exact type of this controller.
*/
struct s3c2410_nand_info {
@@ -128,13 +167,9 @@ struct s3c2410_nand_info {
int sel_bit;
int mtd_count;
unsigned long save_sel;
- unsigned long clk_rate;
enum s3c_cpu_type cpu_type;
-#ifdef CONFIG_CPU_FREQ
- struct notifier_block freq_transition;
-#endif
};
/* conversion functions */
@@ -200,25 +235,24 @@ static int s3c_nand_calc_rate(int wanted, unsigned long clk, int max)
/* controller setup */
/**
- * s3c2410_nand_setrate - setup controller timing information.
- * @info: The controller instance.
+ * s3c2410_nand_inithw - basic hardware initialisation
+ * @info: The hardware state.
+ * @pdev: Platform device
*
- * Given the information supplied by the platform, calculate and set
- * the necessary timing registers in the hardware to generate the
- * necessary timing cycles to the hardware.
- */
-static int s3c2410_nand_setrate(struct s3c2410_nand_info *info)
+ * Do the basic initialisation of the hardware,setup the hardware
+ * access speeds and set the controller to be enabled.
+*/
+static int s3c2410_nand_inithw(struct s3c2410_nand_info *info,
+ struct platform_device *pdev)
{
- struct s3c2410_platform_nand *plat = info->platform;
+ struct s3c2410_platform_nand *plat = to_nand_plat(pdev);
+ unsigned long clkrate = clk_get_rate(info->clk);
int tacls_max = (info->cpu_type == TYPE_S3C2412) ? 8 : 4;
int tacls, twrph0, twrph1;
- unsigned long clkrate = clk_get_rate(info->clk);
- unsigned long uninitialized_var(set), cfg, uninitialized_var(mask);
- unsigned long flags;
+ unsigned long cfg = 0;
/* calculate the timing information for the controller */
- info->clk_rate = clkrate;
clkrate /= 1000; /* turn clock into kHz for ease of use */
if (plat != NULL) {
@@ -240,73 +274,37 @@ static int s3c2410_nand_setrate(struct s3c2410_nand_info *info)
dev_info(info->device, "Tacls=%d, %dns Twrph0=%d %dns, Twrph1=%d %dns\n",
tacls, to_ns(tacls, clkrate), twrph0, to_ns(twrph0, clkrate), twrph1, to_ns(twrph1, clkrate));
+ /*
+ * First get the current value of the configuration register, otherwise
+ * some chip-information that is coming from the bootloader will be
+ * gone (e.g. the page size, which is required for the HWECC)
+ * Luis Galdos
+ */
+
+ cfg = readl(info->regs + S3C2410_NFCONF);
+
switch (info->cpu_type) {
case TYPE_S3C2410:
- mask = (S3C2410_NFCONF_TACLS(3) |
- S3C2410_NFCONF_TWRPH0(7) |
- S3C2410_NFCONF_TWRPH1(7));
- set = S3C2410_NFCONF_EN;
- set |= S3C2410_NFCONF_TACLS(tacls - 1);
- set |= S3C2410_NFCONF_TWRPH0(twrph0 - 1);
- set |= S3C2410_NFCONF_TWRPH1(twrph1 - 1);
+ cfg |= S3C2410_NFCONF_EN;
+ cfg |= S3C2410_NFCONF_TACLS(tacls - 1);
+ cfg |= S3C2410_NFCONF_TWRPH0(twrph0 - 1);
+ cfg |= S3C2410_NFCONF_TWRPH1(twrph1 - 1);
break;
case TYPE_S3C2440:
case TYPE_S3C2412:
- mask = (S3C2440_NFCONF_TACLS(tacls_max - 1) |
- S3C2440_NFCONF_TWRPH0(7) |
- S3C2440_NFCONF_TWRPH1(7));
-
- set = S3C2440_NFCONF_TACLS(tacls - 1);
- set |= S3C2440_NFCONF_TWRPH0(twrph0 - 1);
- set |= S3C2440_NFCONF_TWRPH1(twrph1 - 1);
- break;
-
- default:
- BUG();
- }
-
- local_irq_save(flags);
-
- cfg = readl(info->regs + S3C2410_NFCONF);
- cfg &= ~mask;
- cfg |= set;
- writel(cfg, info->regs + S3C2410_NFCONF);
-
- local_irq_restore(flags);
-
- dev_dbg(info->device, "NF_CONF is 0x%lx\n", cfg);
-
- return 0;
-}
-
-/**
- * s3c2410_nand_inithw - basic hardware initialisation
- * @info: The hardware state.
- *
- * Do the basic initialisation of the hardware, using s3c2410_nand_setrate()
- * to setup the hardware access speeds and set the controller to be enabled.
-*/
-static int s3c2410_nand_inithw(struct s3c2410_nand_info *info)
-{
- int ret;
-
- ret = s3c2410_nand_setrate(info);
- if (ret < 0)
- return ret;
-
- switch (info->cpu_type) {
- case TYPE_S3C2410:
- default:
- break;
+ cfg |= S3C2440_NFCONF_TACLS(tacls - 1);
+ cfg |= S3C2440_NFCONF_TWRPH0(twrph0 - 1);
+ cfg |= S3C2440_NFCONF_TWRPH1(twrph1 - 1);
- case TYPE_S3C2440:
- case TYPE_S3C2412:
/* enable the controller and de-assert nFCE */
writel(S3C2440_NFCONT_ENABLE, info->regs + S3C2440_NFCONT);
}
+ dev_dbg(info->device, "NF_CONF is 0x%lx\n", cfg);
+
+ writel(cfg, info->regs + S3C2410_NFCONF);
return 0;
}
@@ -424,74 +422,72 @@ static int s3c2410_nand_correct_data(struct mtd_info *mtd, u_char *dat,
u_char *read_ecc, u_char *calc_ecc)
{
struct s3c2410_nand_info *info = s3c2410_nand_mtd_toinfo(mtd);
- unsigned int diff0, diff1, diff2;
- unsigned int bit, byte;
-
- pr_debug("%s(%p,%p,%p,%p)\n", __func__, mtd, dat, read_ecc, calc_ecc);
-
- diff0 = read_ecc[0] ^ calc_ecc[0];
- diff1 = read_ecc[1] ^ calc_ecc[1];
- diff2 = read_ecc[2] ^ calc_ecc[2];
-
- pr_debug("%s: rd %02x%02x%02x calc %02x%02x%02x diff %02x%02x%02x\n",
- __func__,
- read_ecc[0], read_ecc[1], read_ecc[2],
- calc_ecc[0], calc_ecc[1], calc_ecc[2],
- diff0, diff1, diff2);
+ unsigned long nfmeccdata0, nfmeccdata1;
+ unsigned long nfestat0;
+ unsigned char err_type;
+ int retval;
+ unsigned int offset;
+ unsigned char wrong_value, corr_value;
+ struct s3c2410_nand_mtd *nmtd = s3c2410_nand_mtd_toours(mtd);
+ struct nand_chip *chip = &nmtd->chip;
- if (diff0 == 0 && diff1 == 0 && diff2 == 0)
- return 0; /* ECC is ok */
+ pr_debug("%s: read %02x%02x%02x%02x calc %02x%02x%02x%02x\n", __func__,
+ read_ecc[0], read_ecc[1], read_ecc[2], read_ecc[3],
+ calc_ecc[0], calc_ecc[1], calc_ecc[2], calc_ecc[3]);
/* sometimes people do not think about using the ECC, so check
* to see if we have an 0xff,0xff,0xff read ECC and then ignore
* the error, on the assumption that this is an un-eccd page.
*/
if (read_ecc[0] == 0xff && read_ecc[1] == 0xff && read_ecc[2] == 0xff
- && info->platform->ignore_unset_ecc)
+ && read_ecc[3] == 0xff && info->platform->ignore_unset_ecc) {
+ pr_debug("Ignoring the HWECC calculation?\n");
return 0;
-
- /* Can we correct this ECC (ie, one row and column change).
- * Note, this is similar to the 256 error code on smartmedia */
-
- if (((diff0 ^ (diff0 >> 1)) & 0x55) == 0x55 &&
- ((diff1 ^ (diff1 >> 1)) & 0x55) == 0x55 &&
- ((diff2 ^ (diff2 >> 1)) & 0x55) == 0x55) {
- /* calculate the bit position of the error */
-
- bit = ((diff2 >> 3) & 1) |
- ((diff2 >> 4) & 2) |
- ((diff2 >> 5) & 4);
-
- /* calculate the byte position of the error */
-
- byte = ((diff2 << 7) & 0x100) |
- ((diff1 << 0) & 0x80) |
- ((diff1 << 1) & 0x40) |
- ((diff1 << 2) & 0x20) |
- ((diff1 << 3) & 0x10) |
- ((diff0 >> 4) & 0x08) |
- ((diff0 >> 3) & 0x04) |
- ((diff0 >> 2) & 0x02) |
- ((diff0 >> 1) & 0x01);
-
- dev_dbg(info->device, "correcting error bit %d, byte %d\n",
- bit, byte);
-
- dat[byte] ^= (1 << bit);
- return 1;
}
- /* if there is only one bit difference in the ECC, then
- * one of only a row or column parity has changed, which
- * means the error is most probably in the ECC itself */
-
- diff0 |= (diff1 << 8);
- diff0 |= (diff2 << 16);
+ /*
+ * If the chip has a small page then set the fourth byte to 0xff, so that
+ * we can use the NAND-controller to check if the ECC is correct or not.
+ * Please note that this "workaround" is coming from the U-Boot, which has
+ * an ECC-layout with only three ECC-bytes (but why?).
+ * (Luis Galdos)
+ */
+ if (chip->page_shift <= 10) {
+ pr_debug("Setting the fourth byte to 0xff\n");
+ read_ecc[3] = 0xff;
+ }
- if ((diff0 & ~(1<<fls(diff0))) == 0)
- return 1;
+ /*
+ * The below code is coming from the driver 's3c_nand.c' (by jsgood)
+ * Luis Galdos
+ */
+ nfmeccdata0 = (read_ecc[1] << 16) | read_ecc[0];
+ nfmeccdata1 = (read_ecc[3] << 16) | read_ecc[2];
+ writel(nfmeccdata0, info->regs + S3C2440_NFECCD0);
+ writel(nfmeccdata1, info->regs + S3C2440_NFECCD1);
+ nfestat0 = readl(info->regs + S3C2412_NFMECC_ERR0);
+ err_type = nfestat0 & 0x3;
+
+ switch (err_type) {
+ case 0:
+ retval = 0;
+ break;
+ case 1:
+ offset = (nfestat0 >> 7) & 0x7ff;
+ wrong_value = dat[offset];
+ corr_value = wrong_value ^ (1 << ((nfestat0 >> 4) & 0x7));
+ printk(KERN_DEBUG "[NAND BitErr]: 1 bit error detected at page byte %u. Correcting from 0x%02x to 0x%02x\n",
+ offset, wrong_value, corr_value);
+ dat[offset] = corr_value;
+ retval = 1;
+ break;
+ default:
+ printk(KERN_ERR "[NAND BitErr]: More than 1 bit error detected. Uncorrectable error.\n");
+ retval = -1;
+ break;
+ }
- return -1;
+ return retval;
}
/* ECC functions
@@ -515,8 +511,21 @@ static void s3c2412_nand_enable_hwecc(struct mtd_info *mtd, int mode)
struct s3c2410_nand_info *info = s3c2410_nand_mtd_toinfo(mtd);
unsigned long ctrl;
+ /*
+ * According to the manual: unlock the main area and set the data transfer
+ * direction (read or write) too
+ * Luis Galdos
+ */
ctrl = readl(info->regs + S3C2440_NFCONT);
- writel(ctrl | S3C2412_NFCONT_INIT_MAIN_ECC, info->regs + S3C2440_NFCONT);
+ ctrl |= S3C2412_NFCONT_INIT_MAIN_ECC;
+ ctrl &= ~S3C2412_NFCONT_MAIN_ECC_LOCK;
+
+ if (mode == NAND_ECC_WRITE)
+ ctrl |= S3C2412_NFCONT_ECC4_DIRWR;
+ else
+ ctrl &= ~S3C2412_NFCONT_ECC4_DIRWR;
+
+ writel(ctrl, info->regs + S3C2440_NFCONT);
}
static void s3c2440_nand_enable_hwecc(struct mtd_info *mtd, int mode)
@@ -545,13 +554,25 @@ static int s3c2410_nand_calculate_ecc(struct mtd_info *mtd, const u_char *dat, u
static int s3c2412_nand_calculate_ecc(struct mtd_info *mtd, const u_char *dat, u_char *ecc_code)
{
struct s3c2410_nand_info *info = s3c2410_nand_mtd_toinfo(mtd);
- unsigned long ecc = readl(info->regs + S3C2412_NFMECC0);
+ unsigned long ecc, nfcont;
- ecc_code[0] = ecc;
- ecc_code[1] = ecc >> 8;
- ecc_code[2] = ecc >> 16;
+ /*
+ * According to the manual: lock the main area before reading from the ECC
+ * status register.
+ * Luis Galdos
+ */
+ nfcont = readl(info->regs + S3C2440_NFCONT);
+ nfcont |= S3C2412_NFCONT_MAIN_ECC_LOCK;
+ writel(nfcont, info->regs + S3C2440_NFCONT);
- pr_debug("calculate_ecc: returning ecc %02x,%02x,%02x\n", ecc_code[0], ecc_code[1], ecc_code[2]);
+ ecc = readl(info->regs + S3C2412_NFMECC0);
+ ecc_code[0] = ecc & 0xff;
+ ecc_code[1] = (ecc >> 8) & 0xff;
+ ecc_code[2] = (ecc >> 16) & 0xff;
+ ecc_code[3] = (ecc >> 24) & 0xff;
+
+ pr_debug("calculate_ecc: returning ecc %02x,%02x,%02x,%02x\n",
+ ecc_code[0], ecc_code[1], ecc_code[2], ecc_code[3]);
return 0;
}
@@ -616,52 +637,6 @@ static void s3c2440_nand_write_buf(struct mtd_info *mtd, const u_char *buf, int
}
}
-/* cpufreq driver support */
-
-#ifdef CONFIG_CPU_FREQ
-
-static int s3c2410_nand_cpufreq_transition(struct notifier_block *nb,
- unsigned long val, void *data)
-{
- struct s3c2410_nand_info *info;
- unsigned long newclk;
-
- info = container_of(nb, struct s3c2410_nand_info, freq_transition);
- newclk = clk_get_rate(info->clk);
-
- if ((val == CPUFREQ_POSTCHANGE && newclk < info->clk_rate) ||
- (val == CPUFREQ_PRECHANGE && newclk > info->clk_rate)) {
- s3c2410_nand_setrate(info);
- }
-
- return 0;
-}
-
-static inline int s3c2410_nand_cpufreq_register(struct s3c2410_nand_info *info)
-{
- info->freq_transition.notifier_call = s3c2410_nand_cpufreq_transition;
-
- return cpufreq_register_notifier(&info->freq_transition,
- CPUFREQ_TRANSITION_NOTIFIER);
-}
-
-static inline void s3c2410_nand_cpufreq_deregister(struct s3c2410_nand_info *info)
-{
- cpufreq_unregister_notifier(&info->freq_transition,
- CPUFREQ_TRANSITION_NOTIFIER);
-}
-
-#else
-static inline int s3c2410_nand_cpufreq_register(struct s3c2410_nand_info *info)
-{
- return 0;
-}
-
-static inline void s3c2410_nand_cpufreq_deregister(struct s3c2410_nand_info *info)
-{
-}
-#endif
-
/* device management functions */
static int s3c24xx_nand_remove(struct platform_device *pdev)
@@ -673,8 +648,6 @@ static int s3c24xx_nand_remove(struct platform_device *pdev)
if (info == NULL)
return 0;
- s3c2410_nand_cpufreq_deregister(info);
-
/* Release all our mtds and their partitions, then go through
* freeing the resources used
*/
@@ -842,11 +815,14 @@ static void s3c2410_nand_init_chip(struct s3c2410_nand_info *info,
chip->ecc.mode = NAND_ECC_SOFT;
}
+ /* @FIXME: Here seems to be something wrong. (Luis Galdos) */
+#if 1
if (set->ecc_layout != NULL)
chip->ecc.layout = set->ecc_layout;
if (set->disable_ecc)
chip->ecc.mode = NAND_ECC_NONE;
+#endif
switch (chip->ecc.mode) {
case NAND_ECC_NONE:
@@ -886,8 +862,7 @@ static void s3c2410_nand_update_chip(struct s3c2410_nand_info *info,
{
struct nand_chip *chip = &nmtd->chip;
- dev_dbg(info->device, "chip %p => page shift %d\n",
- chip, chip->page_shift);
+ printk("%s: chip %p: %d\n", __func__, chip, chip->page_shift);
if (chip->ecc.mode != NAND_ECC_HW)
return;
@@ -896,12 +871,19 @@ static void s3c2410_nand_update_chip(struct s3c2410_nand_info *info,
* the large or small page nand device */
if (chip->page_shift > 10) {
- chip->ecc.size = 256;
- chip->ecc.bytes = 3;
+ chip->ecc.size = 2048;
+ chip->ecc.bytes = 4;
+ chip->ecc.layout = &nand_hw_eccoob;
} else {
+ /*
+ * IMPORTANT: For using only three ECC-bytes is required to set
+ * the fourth byte to '0xff', otherwise we can't use the internal
+ * NAND-controller for checking if the ECC is correct or not.
+ * (Luis Galdos)
+ */
chip->ecc.size = 512;
chip->ecc.bytes = 3;
- chip->ecc.layout = &nand_hw_eccoob;
+ chip->ecc.layout = &nand_hw_eccoob_16;
}
}
@@ -925,6 +907,18 @@ static int s3c24xx_nand_probe(struct platform_device *pdev)
int nr_sets;
int setno;
+ /*
+ * Required variables for accessing to the partitions from the command line
+ * Luis Galdos
+ */
+#if defined(CONFIG_MTD_CMDLINE_PARTS)
+ struct mtd_partition *mtd_parts;
+ int nr_parts;
+ const char *name_back;
+ struct s3c2410_nand_set nand_sets[1];
+ const char *part_probes[] = { "cmdlinepart", NULL };
+#endif
+
cpu_type = platform_get_device_id(pdev)->driver_data;
pr_debug("s3c2410_nand_probe(%p)\n", pdev);
@@ -981,7 +975,7 @@ static int s3c24xx_nand_probe(struct platform_device *pdev)
/* initialise the hardware */
- err = s3c2410_nand_inithw(info);
+ err = s3c2410_nand_inithw(info, pdev);
if (err != 0)
goto exit_error;
@@ -1013,6 +1007,29 @@ static int s3c24xx_nand_probe(struct platform_device *pdev)
(sets) ? sets->nr_chips : 1,
NULL);
+ /*
+ * This is the code required for accessing to the partitions table
+ * passed by the bootloader
+ * (Luis Galdos)
+ */
+#if defined(CONFIG_MTD_CMDLINE_PARTS)
+ /*
+ * Need to reset the name of the MTD-device then the name of the
+ * partition passed by the U-Boot differs from the assigned name.
+ * U-Boot : onboard_boot
+ * Device : NAND 128MiB 3,3V 8-bit
+ */
+ name_back = nmtd->mtd.name;
+ nmtd->mtd.name= PARTITON_PARAMETER_NAME;
+ nr_parts = parse_mtd_partitions(&nmtd->mtd, part_probes, &mtd_parts, 0);
+ nmtd->mtd.name = name_back;
+ nand_sets[0].name = "NAND-Parts";
+ nand_sets[0].nr_chips = 1;
+ nand_sets[0].partitions = mtd_parts;
+ nand_sets[0].nr_partitions = nr_parts;
+ sets = nand_sets;
+#endif /* defined(CONFIG_MTD_CMDLINE_PARTS) */
+
if (nmtd->scan_res == 0) {
s3c2410_nand_update_chip(info, nmtd);
nand_scan_tail(&nmtd->mtd);
@@ -1023,12 +1040,6 @@ static int s3c24xx_nand_probe(struct platform_device *pdev)
sets++;
}
- err = s3c2410_nand_cpufreq_register(info);
- if (err < 0) {
- dev_err(&pdev->dev, "failed to init cpufreq support\n");
- goto exit_error;
- }
-
if (allow_clk_stop(info)) {
dev_info(&pdev->dev, "clock idle support enabled\n");
clk_disable(info->clk);
@@ -1076,7 +1087,7 @@ static int s3c24xx_nand_resume(struct platform_device *dev)
if (info) {
clk_enable(info->clk);
- s3c2410_nand_inithw(info);
+ s3c2410_nand_inithw(info, dev);
/* Restore the state of the nFCE line. */
diff --git a/drivers/net/Kconfig b/drivers/net/Kconfig
index 67b150570265..676eea0c47f7 100644
--- a/drivers/net/Kconfig
+++ b/drivers/net/Kconfig
@@ -1051,15 +1051,6 @@ config SMSC911X
<file:Documentation/networking/net-modules.txt>. The module
will be called smsc911x.
-config SMSC9118
- tristate "SMSC LAN9218 support"
- depends on NET_ETHERNET && (MACH_CC9M2443JS || MACH_CCW9M2443JS)
- select CRC32
- select MII
- ---help---
- Say Y here if you want support for SMSC LAN921x families
- of ethernet controllers.
-
config NET_VENDOR_RACAL
bool "Racal-Interlan (Micom) NI cards"
depends on ISA
diff --git a/drivers/net/Makefile b/drivers/net/Makefile
index d9113efccb74..a9a4f9522465 100644
--- a/drivers/net/Makefile
+++ b/drivers/net/Makefile
@@ -268,7 +268,6 @@ obj-$(CONFIG_MACB) += macb.o
obj-$(CONFIG_S6GMAC) += s6gmac.o
obj-$(CONFIG_ARM) += arm/
-obj-$(CONFIG_SMSC9118) += smsc9118/
obj-$(CONFIG_DEV_APPLETALK) += appletalk/
obj-$(CONFIG_TR) += tokenring/
obj-$(CONFIG_WAN) += wan/
diff --git a/drivers/net/smsc9118/Makefile b/drivers/net/smsc9118/Makefile
deleted file mode 100644
index d33fe1dc8e38..000000000000
--- a/drivers/net/smsc9118/Makefile
+++ /dev/null
@@ -1 +0,0 @@
-obj-$(CONFIG_SMSC9118) += smsc911x.o
diff --git a/drivers/net/smsc9118/smsc911x.c b/drivers/net/smsc9118/smsc911x.c
deleted file mode 100644
index a71d5c042d50..000000000000
--- a/drivers/net/smsc9118/smsc911x.c
+++ /dev/null
@@ -1,2711 +0,0 @@
-/***************************************************************************
- *
- * Copyright (C) 2004-2007 SMSC
- * Copyright (C) 2005 ARM
- *
- * 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.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
- *
- ***************************************************************************
- * Rewritten, heavily based on smsc911x simple driver by SMSC.
- * Partly uses io macros from smc91x.c by Nicolas Pitre
- *
- * Supported devices:
- * LAN9115, LAN9116, LAN9117, LAN9118
- * LAN9215, LAN9216, LAN9217, LAN9218
- *
- * History:
- * 05/05/2005 bahadir.balban@arm.com
- * - Transition to linux coding style
- * - Platform driver and module interface
- *
- * 17/07/2006 steve.glendinning@smsc.com
- * - Added support for LAN921x family
- * - Added workaround for multicast filters
- *
- * 31/07/2006 steve.glendinning@smsc.com
- * - Removed tasklet, using NAPI poll instead
- * - Multiple device support
- * - Large tidy-up following feedback from netdev list
- *
- * 03/08/2006 steve.glendinning@smsc.com
- * - Added ethtool support
- * - Convert to use generic MII interface
- *
- * 04/08/2006 bahadir.balban@arm.com
- * - Added ethtool eeprom r/w support
- *
- * 17/06/2007 steve.glendinning@smsc.com
- * - Incorporate changes from Bill Gatliff and Russell King
- *
- * 04/07/2007 steve.glendinning@smsc.com
- * - move irq configuration to platform_device
- * - fix link poller after interface is stopped and restarted
- *
- * 13/07/2007 bahadir.balban@arm.com
- * - set irq polarity before requesting irq
- *
- * 26/06/2007 hennerich@blackfin.uclinux.org
- * - Fixed minor style issue to pass checkpatch.pl
- */
-
-#include <linux/crc32.h>
-#include <linux/delay.h>
-#include <linux/errno.h>
-#include <linux/etherdevice.h>
-#include <linux/ethtool.h>
-#include <linux/init.h>
-#include <linux/ioport.h>
-#include <linux/kernel.h>
-#include <linux/mii.h>
-#include <linux/module.h>
-#include <linux/netdevice.h>
-#include <linux/platform_device.h>
-#include <linux/sched.h>
-#include <linux/slab.h>
-#include <linux/timer.h>
-#include <linux/version.h>
-#include <linux/bug.h>
-#include <linux/bitops.h>
-#include <linux/irq.h>
-#include <asm/io.h>
-
-/* For having the same platform-data as in the Vanilla kernel */
-#include <linux/smc911x.h>
-
-#include "smsc911x.h"
-
-#define SMSC_CHIPNAME "smsc911x"
-#define SMSC_DRV_VERSION "2007-07-13"
-
-MODULE_LICENSE("GPL");
-
-
-/* Base address of the connected controller: S3C2410_CS5 = 0x28000000 */
-#define printk_err(fmt, args...) printk(KERN_ERR "[ ERROR ] smsc911x: " fmt, ## args)
-#define printk_info(fmt, args...) printk(KERN_INFO "smsc911x: " fmt, ## args)
-
-#if 0
-#define SMSC911X_DEBUG
-#endif
-
-#ifdef SMSC911X_DEBUG
-# define printk_debug(fmt, args...) printk(KERN_DEBUG "smsc911x: " fmt, ## args)
-#else
-# define printk_debug(fmt, args...)
-#endif
-
-/* Enables the debug messages for the PM-operations (WOL, suspend, etc.) */
-#if 0
-#define SMSC911X_PM_DEBUG
-#endif
-
-#ifdef SMSC911X_PM_DEBUG
-# define printk_pmdbg(fmt, args...) printk(KERN_DEBUG "smsc911x: " fmt, ## args)
-#else
-# define printk_pmdbg(fmt, args...)
-#endif
-
-struct smsc911x_data {
- void __iomem *ioaddr;
-
- unsigned int idrev;
- unsigned int generation; /* used to decide which workarounds apply */
-
- /* device configuration */
- unsigned int irq_polarity;
- unsigned int irq_type;
- unsigned int irq_flags;
-
- /* This needs to be acquired before calling any of below:
- * smsc911x_mac_read(), smsc911x_mac_write()
- * smsc911x_phy_read(), smsc911x_phy_write()
- */
- spinlock_t phy_lock;
-
- struct mii_if_info mii;
- unsigned int using_extphy;
- u32 msg_enable;
-#ifdef USE_LED1_WORK_AROUND
- unsigned int gpio_setting;
- unsigned int gpio_orig_setting;
-#endif
- struct net_device *netdev;
- struct napi_struct napi;
- struct timer_list link_poll_timer;
- unsigned int stop_link_poll;
-
- unsigned int software_irq_signal;
-
-#ifdef USE_PHY_WORK_AROUND
-#define MIN_PACKET_SIZE (64)
- char loopback_tx_pkt[MIN_PACKET_SIZE];
- char loopback_rx_pkt[MIN_PACKET_SIZE];
- unsigned int resetcount;
-#endif
-
- /* Members for Multicast filter workaround */
- unsigned int multicast_update_pending;
- unsigned int set_bits_mask;
- unsigned int clear_bits_mask;
- unsigned int hashhi;
- unsigned int hashlo;
- unsigned int last_rxstat;
-
- /* Registers for the internal PM */
- unsigned long mac_wucsr;
- unsigned long pmt_ctrl;
- unsigned long phy_intmsk;
-};
-
-
-static int smsc911x_set_mac(struct net_device *dev, void *addr);
-
-#if SMSC_CAN_USE_32BIT
-
-static inline u32 smsc911x_reg_read(struct smsc911x_data *pdata, u32 reg)
-{
- return readl(pdata->ioaddr + reg);
-}
-
-static inline void smsc911x_reg_write(u32 val, struct smsc911x_data *pdata,
- u32 reg)
-{
- writel(val, pdata->ioaddr + reg);
-}
-
-#else /* SMSC_CAN_USE_32BIT */
-
-static inline u32 smsc911x_reg_read(struct smsc911x_data *pdata, u32 reg)
-{
- u32 reg_val;
- unsigned long flags;
-
- /* these two 16-bit reads must be performed consecutively, so must
- * not be interrupted by our own ISR (which would start another
- * read operation) */
- local_irq_save(flags);
- reg_val = ((readw(pdata->ioaddr + reg) & 0xFFFF) |
- ((readw(pdata->ioaddr + reg + 2) & 0xFFFF) << 16));
- local_irq_restore(flags);
-
- return reg_val;
-}
-
-static inline void smsc911x_reg_write(u32 val, struct smsc911x_data *pdata,
- u32 reg)
-{
- unsigned long flags;
-
- /* these two 16-bit writes must be performed consecutively, so must
- * not be interrupted by our own ISR (which would start another
- * read operation) */
- local_irq_save(flags);
- writew(val & 0xFFFF, pdata->ioaddr + reg);
- writew((val >> 16) & 0xFFFF, pdata->ioaddr + reg + 2);
- local_irq_restore(flags);
-}
-
-#endif /* SMSC_CAN_USE_32BIT */
-
-#ifndef CONFIG_BLACKFIN
-/* Writes a packet to the TX_DATA_FIFO */
-static inline void
-smsc911x_tx_writefifo(struct smsc911x_data *pdata, unsigned int *buf,
- unsigned int wordcount)
-{
- while (wordcount--)
- smsc911x_reg_write(*buf++, pdata, TX_DATA_FIFO);
-}
-
-/* Reads a packet out of the RX_DATA_FIFO */
-static inline void
-smsc911x_rx_readfifo(struct smsc911x_data *pdata, unsigned int *buf,
- unsigned int wordcount)
-{
- while (wordcount--)
- *buf++ = smsc911x_reg_read(pdata, RX_DATA_FIFO);
-}
-#else
-/* Writes a packet to the TX_DATA_FIFO */
-static inline void
-smsc911x_tx_writefifo(struct smsc911x_data *pdata, unsigned int *buf,
- unsigned int wordcount)
-{
- if (wordcount > 24)
- dma_outsl((u_long)pdata->ioaddr + TX_DATA_FIFO, buf, wordcount);
- else
- outsl((u_long)pdata->ioaddr + TX_DATA_FIFO, buf, wordcount);
-}
-
-/* Reads a packet out of the RX_DATA_FIFO */
-static inline void
-smsc911x_rx_readfifo(struct smsc911x_data *pdata, unsigned int *buf,
- unsigned int wordcount)
-{
- if (wordcount > 24)
- dma_insl((u_long)pdata->ioaddr + RX_DATA_FIFO, buf, wordcount);
- else
- insl((u_long)pdata->ioaddr + RX_DATA_FIFO, buf, wordcount);
-}
-#endif
-
-/* waits for MAC not busy, with timeout. Only called by smsc911x_mac_read
- * and smsc911x_mac_write, so assumes phy_lock is held */
-static int smsc911x_mac_notbusy(struct smsc911x_data *pdata)
-{
- int i;
- u32 val;
-
- for (i = 0; i < 40; i++) {
- val = smsc911x_reg_read(pdata, MAC_CSR_CMD);
- if (!(val & MAC_CSR_CMD_CSR_BUSY_))
- return 1;
- }
- SMSC_WARNING("Timed out waiting for MAC not BUSY. "
- "MAC_CSR_CMD: 0x%08X", val);
- return 0;
-}
-
-/* Fetches a MAC register value. Assumes phy_lock is acquired */
-static u32 smsc911x_mac_read(struct smsc911x_data *pdata, unsigned int offset)
-{
- unsigned int temp;
-
-#ifdef CONFIG_DEBUG_SPINLOCK
- if (!spin_is_locked(&pdata->phy_lock))
- SMSC_WARNING("phy_lock not held");
-#endif /* CONFIG_DEBUG_SPINLOCK */
-
- temp = smsc911x_reg_read(pdata, MAC_CSR_CMD);
- if (unlikely(temp & MAC_CSR_CMD_CSR_BUSY_)) {
- SMSC_WARNING("smsc911x_mac_read failed, MAC busy at entry");
- return 0xFFFFFFFF;
- }
-
- /* Send the MAC cmd */
- smsc911x_reg_write(((offset & 0xFF) | MAC_CSR_CMD_CSR_BUSY_
- | MAC_CSR_CMD_R_NOT_W_), pdata, MAC_CSR_CMD);
-
- /* Workaround for hardware read-after-write restriction */
- temp = smsc911x_reg_read(pdata, BYTE_TEST);
-
- /* Wait for the read to happen */
- if (likely(smsc911x_mac_notbusy(pdata)))
- return smsc911x_reg_read(pdata, MAC_CSR_DATA);
-
- SMSC_WARNING("smsc911x_mac_read failed, MAC busy after read");
- return 0xFFFFFFFF;
-}
-
-/* Set a mac register, phy_lock must be acquired before calling */
-static void smsc911x_mac_write(struct smsc911x_data *pdata,
- unsigned int offset, u32 val)
-{
- unsigned int temp;
-
-#ifdef CONFIG_DEBUG_SPINLOCK
- if (!spin_is_locked(&pdata->phy_lock))
- SMSC_WARNING("phy_lock not held");
-#endif /* CONFIG_DEBUG_SPINLOCK */
-
- temp = smsc911x_reg_read(pdata, MAC_CSR_CMD);
- if (unlikely(temp & MAC_CSR_CMD_CSR_BUSY_)) {
- SMSC_WARNING("smsc911x_mac_write failed, MAC busy at entry");
- return;
- }
-
- /* Send data to write */
- smsc911x_reg_write(val, pdata, MAC_CSR_DATA);
-
- /* Write the actual data */
- smsc911x_reg_write(((offset & 0xFF) | MAC_CSR_CMD_CSR_BUSY_), pdata,
- MAC_CSR_CMD);
-
- /* Workaround for hardware read-after-write restriction */
- temp = smsc911x_reg_read(pdata, BYTE_TEST);
-
- /* Wait for the write to complete */
- if (likely(smsc911x_mac_notbusy(pdata)))
- return;
-
- SMSC_WARNING("smsc911x_mac_write failed, MAC busy after write");
-}
-
-/* Gets a phy register, phy_lock must be acquired before calling */
-static u16 smsc911x_phy_read(struct smsc911x_data *pdata, unsigned int index)
-{
- unsigned int addr;
- int i;
-
-#ifdef CONFIG_DEBUG_SPINLOCK
- if (!spin_is_locked(&pdata->phy_lock))
- SMSC_WARNING("phy_lock not held");
-#endif /* CONFIG_DEBUG_SPINLOCK */
-
- /* Confirm MII not busy */
- if (unlikely(smsc911x_mac_read(pdata, MII_ACC) & MII_ACC_MII_BUSY_)) {
- SMSC_WARNING("MII is busy in smsc911x_phy_read???");
- return 0;
- }
-
- /* Set the address, index & direction (read from PHY) */
- addr = (((pdata->mii.phy_id) & 0x1F) << 11)
- | ((index & 0x1F) << 6);
- smsc911x_mac_write(pdata, MII_ACC, addr);
-
- /* Wait for read to complete w/ timeout */
- for (i = 0; i < 100; i++) {
- /* See if MII is finished yet */
- if (!(smsc911x_mac_read(pdata, MII_ACC) & MII_ACC_MII_BUSY_)) {
- return smsc911x_mac_read(pdata, MII_DATA);
- }
- }
- SMSC_WARNING("Timed out waiting for MII write to finish");
- return 0xFFFF;
-}
-
-/* Sets a phy register, phy_lock must be acquired before calling */
-static void smsc911x_phy_write(struct smsc911x_data *pdata,
- unsigned int index, u16 val)
-{
- unsigned int addr;
- int i;
-
-#ifdef CONFIG_DEBUG_SPINLOCK
- if (!spin_is_locked(&pdata->phy_lock))
- SMSC_WARNING("phy_lock not held");
-#endif /* CONFIG_DEBUG_SPINLOCK */
-
- /* Confirm MII not busy */
- if (unlikely(smsc911x_mac_read(pdata, MII_ACC) & MII_ACC_MII_BUSY_)) {
- SMSC_WARNING("MII is busy in smsc911x_write_phy???");
- return;
- }
-
- /* Put the data to write in the MAC */
- smsc911x_mac_write(pdata, MII_DATA, val);
-
- /* Set the address, index & direction (write to PHY) */
- addr = (((pdata->mii.phy_id) & 0x1F) << 11) |
- ((index & 0x1F) << 6) | MII_ACC_MII_WRITE_;
- smsc911x_mac_write(pdata, MII_ACC, addr);
-
- /* Wait for write to complete w/ timeout */
- for (i = 0; i < 100; i++) {
- /* See if MII is finished yet */
- if (!(smsc911x_mac_read(pdata, MII_ACC) & MII_ACC_MII_BUSY_))
- return;
- }
- SMSC_WARNING("Timed out waiting for MII write to finish");
-}
-
-static int smsc911x_mdio_read(struct net_device *dev, int phy_id, int location)
-{
- struct smsc911x_data *pdata = netdev_priv(dev);
- unsigned long flags;
- int reg;
-
- spin_lock_irqsave(&pdata->phy_lock, flags);
- reg = smsc911x_phy_read(pdata, location);
- spin_unlock_irqrestore(&pdata->phy_lock, flags);
-
- return reg;
-}
-
-static void smsc911x_mdio_write(struct net_device *dev, int phy_id,
- int location, int val)
-{
- struct smsc911x_data *pdata = netdev_priv(dev);
- unsigned long flags;
-
- spin_lock_irqsave(&pdata->phy_lock, flags);
- smsc911x_phy_write(pdata, location, val);
- spin_unlock_irqrestore(&pdata->phy_lock, flags);
-}
-
-/* Autodetects and initialises external phy for SMSC9115 and SMSC9117 flavors.
- * If something goes wrong, returns -ENODEV to revert back to internal phy.
- * Performed at initialisation only, so interrupts are enabled */
-static int smsc911x_phy_initialise_external(struct smsc911x_data *pdata)
-{
- unsigned int address;
- unsigned int hwcfg;
- unsigned int phyid1;
- unsigned int phyid2;
-
- hwcfg = smsc911x_reg_read(pdata, HW_CFG);
-
- /* External phy is requested, supported, and detected */
- if (hwcfg & HW_CFG_EXT_PHY_DET_) {
-
- /* Attempt to switch to external phy for auto-detecting
- * its address. Assuming tx and rx are stopped because
- * smsc911x_phy_initialise is called before
- * smsc911x_rx_initialise and tx_initialise.
- */
-
- /* Disable phy clocks to the MAC */
- hwcfg &= (~HW_CFG_PHY_CLK_SEL_);
- hwcfg |= HW_CFG_PHY_CLK_SEL_CLK_DIS_;
- smsc911x_reg_write(hwcfg, pdata, HW_CFG);
- udelay(10); /* Enough time for clocks to stop */
-
- /* Switch to external phy */
- hwcfg |= HW_CFG_EXT_PHY_EN_;
- smsc911x_reg_write(hwcfg, pdata, HW_CFG);
-
- /* Enable phy clocks to the MAC */
- hwcfg &= (~HW_CFG_PHY_CLK_SEL_);
- hwcfg |= HW_CFG_PHY_CLK_SEL_EXT_PHY_;
- smsc911x_reg_write(hwcfg, pdata, HW_CFG);
- udelay(10); /* Enough time for clocks to restart */
-
- hwcfg |= HW_CFG_SMI_SEL_;
- smsc911x_reg_write(hwcfg, pdata, HW_CFG);
-
- /* Auto-detect PHY */
- spin_lock_irq(&pdata->phy_lock);
- for (address = 0; address <= 31; address++) {
- pdata->mii.phy_id = address;
- phyid1 = smsc911x_phy_read(pdata, MII_PHYSID1);
- phyid2 = smsc911x_phy_read(pdata, MII_PHYSID2);
- if ((phyid1 != 0xFFFFU) || (phyid2 != 0xFFFFU)) {
- SMSC_TRACE("Detected PHY at address = "
- "0x%02X = %d", address, address);
- break;
- }
- }
- spin_unlock_irq(&pdata->phy_lock);
-
- if ((phyid1 == 0xFFFFU) && (phyid2 == 0xFFFFU)) {
- SMSC_WARNING("External PHY is not accessable, "
- "using internal PHY instead");
- /* Revert back to internal phy settings. */
-
- /* Disable phy clocks to the MAC */
- hwcfg &= (~HW_CFG_PHY_CLK_SEL_);
- hwcfg |= HW_CFG_PHY_CLK_SEL_CLK_DIS_;
- smsc911x_reg_write(hwcfg, pdata, HW_CFG);
- udelay(10); /* Enough time for clocks to stop */
-
- /* Switch to internal phy */
- hwcfg &= (~HW_CFG_EXT_PHY_EN_);
- smsc911x_reg_write(hwcfg, pdata, HW_CFG);
-
- /* Enable phy clocks to the MAC */
- hwcfg &= (~HW_CFG_PHY_CLK_SEL_);
- hwcfg |= HW_CFG_PHY_CLK_SEL_INT_PHY_;
- smsc911x_reg_write(hwcfg, pdata, HW_CFG);
- udelay(10); /* Enough time for clocks to restart */
-
- hwcfg &= (~HW_CFG_SMI_SEL_);
- smsc911x_reg_write(hwcfg, pdata, HW_CFG);
- /* Use internal phy */
- return -ENODEV;
- } else {
- SMSC_TRACE("Successfully switched to external PHY");
- pdata->using_extphy = 1;
- }
- } else {
- SMSC_WARNING("No external PHY detected.");
- SMSC_WARNING("Using internal PHY instead.");
- /* Use internal phy */
- return -ENODEV;
- }
- return 0;
-}
-
-/* called by phy_initialise and loopback test */
-static int smsc911x_phy_reset(struct smsc911x_data *pdata)
-{
- unsigned int temp;
- unsigned int i = 100000;
- unsigned long flags;
-
- SMSC_TRACE("Performing PHY BCR Reset");
- spin_lock_irqsave(&pdata->phy_lock, flags);
- smsc911x_phy_write(pdata, MII_BMCR, BMCR_RESET);
- do {
- udelay(10);
- temp = smsc911x_phy_read(pdata, MII_BMCR);
- } while ((i--) && (temp & BMCR_RESET));
- spin_unlock_irqrestore(&pdata->phy_lock, flags);
-
- if (temp & BMCR_RESET) {
- SMSC_WARNING("PHY reset failed to complete.");
- return 0;
- }
- /* Extra delay required because the phy may not be completed with
- * its reset when BMCR_RESET is cleared. Specs say 256 uS is
- * enough delay but using 1ms here to be safe
- */
- msleep(1);
-
- return 1;
-}
-
-/* Fetches a tx status out of the status fifo */
-static unsigned int smsc911x_tx_get_txstatus(struct smsc911x_data *pdata)
-{
- unsigned int result =
- smsc911x_reg_read(pdata, TX_FIFO_INF) & TX_FIFO_INF_TSUSED_;
-
- if (result != 0)
- result = smsc911x_reg_read(pdata, TX_STATUS_FIFO);
-
- return result;
-}
-
-/* Fetches the next rx status */
-static unsigned int smsc911x_rx_get_rxstatus(struct smsc911x_data *pdata)
-{
- unsigned int result =
- smsc911x_reg_read(pdata, RX_FIFO_INF) & RX_FIFO_INF_RXSUSED_;
-
- if (result != 0)
- result = smsc911x_reg_read(pdata, RX_STATUS_FIFO);
-
- return result;
-}
-
-#ifdef USE_PHY_WORK_AROUND
-static int smsc911x_phy_check_loopbackpkt(struct smsc911x_data *pdata)
-{
- unsigned int tries;
- u32 wrsz;
- u32 rdsz;
- u32 bufp;
-
- for (tries = 0; tries < 10; tries++) {
- unsigned int txcmd_a;
- unsigned int txcmd_b;
- unsigned int status;
- unsigned int pktlength;
- unsigned int i;
-
- /* Zero-out rx packet memory */
- memset(pdata->loopback_rx_pkt, 0, MIN_PACKET_SIZE);
-
- /* Write tx packet to 118 */
- txcmd_a = (((unsigned int)pdata->loopback_tx_pkt)
- & 0x03) << 16;
- txcmd_a |= TX_CMD_A_FIRST_SEG_ | TX_CMD_A_LAST_SEG_;
- txcmd_a |= MIN_PACKET_SIZE;
-
- txcmd_b = MIN_PACKET_SIZE << 16 | MIN_PACKET_SIZE;
-
- smsc911x_reg_write(txcmd_a, pdata, TX_DATA_FIFO);
- smsc911x_reg_write(txcmd_b, pdata, TX_DATA_FIFO);
-
- bufp = ((u32) pdata->loopback_tx_pkt) & 0xFFFFFFFC;
- wrsz = MIN_PACKET_SIZE + 3;
- wrsz += (((u32) pdata->loopback_tx_pkt) & 0x3);
- wrsz >>= 2;
-
- smsc911x_tx_writefifo(pdata, (unsigned int *)bufp, wrsz);
-
- /* Wait till transmit is done */
- i = 60;
- do {
- udelay(5);
- status = smsc911x_tx_get_txstatus(pdata);
- } while ((i--) && (!status));
-
- if (!status) {
- SMSC_WARNING("Failed to transmit during loopback test");
- continue;
- }
- if (status & TX_STS_ES_) {
- SMSC_WARNING("Transmit encountered errors during "
- "loopback test");
- continue;
- }
-
- /* Wait till receive is done */
- i = 60;
- do {
- udelay(5);
- status = smsc911x_rx_get_rxstatus(pdata);
- } while ((i--) && (!status));
-
- if (!status) {
- SMSC_WARNING("Failed to receive during loopback test");
- continue;
- }
- if (status & RX_STS_ES_) {
- SMSC_WARNING("Receive encountered errors during "
- "loopback test");
- continue;
- }
-
- pktlength = ((status & 0x3FFF0000UL) >> 16);
- bufp = (u32)pdata->loopback_rx_pkt;
- rdsz = pktlength + 3;
- rdsz += ((u32)pdata->loopback_rx_pkt) & 0x3;
- rdsz >>= 2;
-
- smsc911x_rx_readfifo(pdata, (unsigned int *)bufp, rdsz);
-
- if (pktlength != (MIN_PACKET_SIZE + 4)) {
- SMSC_WARNING("Unexpected packet size during "
- "loop back test, size=%d, "
- "will retry", pktlength);
- } else {
- unsigned int j;
- int mismatch = 0;
- for (j = 0; j < MIN_PACKET_SIZE; j++) {
- if (pdata->loopback_tx_pkt[j]
- != pdata->loopback_rx_pkt[j]) {
- mismatch = 1;
- break;
- }
- }
- if (!mismatch) {
- SMSC_TRACE("Successfully verified "
- "loopback packet");
- return 1;
- } else {
- SMSC_WARNING("Data miss match during "
- "loop back test, will retry.");
- }
- }
- }
-
- return 0;
-}
-
-static int smsc911x_phy_loopbacktest(struct smsc911x_data *pdata)
-{
- int result = 0;
- unsigned int i;
- unsigned int val;
- unsigned long flags;
-
- /* Initialise tx packet */
- for (i = 0; i < 6; i++) {
- /* Use broadcast destination address */
- pdata->loopback_tx_pkt[i] = (char)0xFF;
- }
-
- for (i = 6; i < 12; i++) {
- /* Use incrementing source address */
- pdata->loopback_tx_pkt[i] = (char)i;
- }
-
- /* Set length type field */
- pdata->loopback_tx_pkt[12] = 0x00;
- pdata->loopback_tx_pkt[13] = 0x00;
- for (i = 14; i < MIN_PACKET_SIZE; i++) {
- pdata->loopback_tx_pkt[i] = (char)i;
- }
-
- val = smsc911x_reg_read(pdata, HW_CFG);
- val &= HW_CFG_TX_FIF_SZ_;
- val |= HW_CFG_SF_;
- smsc911x_reg_write(val, pdata, HW_CFG);
-
- smsc911x_reg_write(TX_CFG_TX_ON_, pdata, TX_CFG);
- smsc911x_reg_write((((unsigned int)pdata->loopback_rx_pkt)
- & 0x03) << 8, pdata, RX_CFG);
-
- for (i = 0; i < 10; i++) {
- /* Set PHY to 10/FD, no ANEG, and loopback mode */
- spin_lock_irqsave(&pdata->phy_lock, flags);
- smsc911x_phy_write(pdata, MII_BMCR, 0x4100);
-
- /* Enable MAC tx/rx, FD */
- smsc911x_mac_write(pdata, MAC_CR, MAC_CR_FDPX_
- | MAC_CR_TXEN_ | MAC_CR_RXEN_);
- spin_unlock_irqrestore(&pdata->phy_lock, flags);
-
- if (smsc911x_phy_check_loopbackpkt(pdata)) {
- result = 1;
- break;
- }
- pdata->resetcount++;
-
- /* Disable MAC rx */
- spin_lock_irqsave(&pdata->phy_lock, flags);
- smsc911x_mac_write(pdata, MAC_CR, 0);
- spin_unlock_irqrestore(&pdata->phy_lock, flags);
-
- smsc911x_phy_reset(pdata);
- }
-
- /* Disable MAC */
- spin_lock_irqsave(&pdata->phy_lock, flags);
- smsc911x_mac_write(pdata, MAC_CR, 0);
-
- /* Cancel PHY loopback mode */
- smsc911x_phy_write(pdata, MII_BMCR, 0);
- spin_unlock_irqrestore(&pdata->phy_lock, flags);
-
- smsc911x_reg_write(0, pdata, TX_CFG);
- smsc911x_reg_write(0, pdata, RX_CFG);
-
- return result;
-}
-#endif /* USE_PHY_WORK_AROUND */
-
-
-inline static void smsc911x_phy_dump_regs(struct smsc911x_data *pdata)
-{
- printk("BCR = 0x%04x\n", smsc911x_phy_read(pdata, MII_BMCR));
- printk("BSR = 0x%04x\n", smsc911x_phy_read(pdata, MII_BMSR));
- printk("ID1 = 0x%04x\n", smsc911x_phy_read(pdata, MII_PHYSID1));
- printk("ID2 = 0x%04x\n", smsc911x_phy_read(pdata, MII_PHYSID2));
- printk("ADVER = 0x%04x\n", smsc911x_phy_read(pdata, MII_ADVERTISE));
- printk("LPA = 0x%04x\n", smsc911x_phy_read(pdata, MII_LPA));
- printk("EXP = 0x%04x\n", smsc911x_phy_read(pdata, MII_EXPANSION));
-}
-
-/* assumes phy_lock is held */
-static void smsc911x_phy_update_flowcontrol(struct smsc911x_data *pdata)
-{
- unsigned int temp;
-
- if (pdata->mii.full_duplex) {
- unsigned int phy_adv;
- unsigned int phy_lpa;
- phy_adv = smsc911x_phy_read(pdata, MII_ADVERTISE);
- phy_lpa = smsc911x_phy_read(pdata, MII_LPA);
- if (phy_adv & phy_lpa & LPA_PAUSE_CAP) {
- /* Both ends support symmetric pause, enable
- * PAUSE receive and transmit */
- smsc911x_mac_write(pdata, FLOW, 0xFFFF0002);
- temp = smsc911x_reg_read(pdata, AFC_CFG);
- temp |= 0xF;
- smsc911x_reg_write(temp, pdata, AFC_CFG);
- } else if (((phy_adv & ADVERTISE_PAUSE_ALL) ==
- ADVERTISE_PAUSE_ALL) &&
- ((phy_lpa & LPA_PAUSE_ALL) == LPA_PAUSE_ASYM)) {
- /* We support symmetric and asym pause, the
- * other end only supports asym, Enable PAUSE
- * receive, disable PAUSE transmit */
- smsc911x_mac_write(pdata, FLOW, 0xFFFF0002);
- temp = smsc911x_reg_read(pdata, AFC_CFG);
- temp &= ~0xF;
- smsc911x_reg_write(temp, pdata, AFC_CFG);
- } else {
- /* Disable PAUSE receive and transmit */
- smsc911x_mac_write(pdata, FLOW, 0);
- temp = smsc911x_reg_read(pdata, AFC_CFG);
- temp &= ~0xF;
- smsc911x_reg_write(temp, pdata, AFC_CFG);
- }
- } else {
- smsc911x_mac_write(pdata, FLOW, 0);
- temp = smsc911x_reg_read(pdata, AFC_CFG);
- temp |= 0xF;
- smsc911x_reg_write(temp, pdata, AFC_CFG);
- }
-}
-
-static void smsc911x_phy_update_duplex(struct net_device *dev)
-{
- struct smsc911x_data *pdata = netdev_priv(dev);
- unsigned long flags;
- unsigned int mac_cr;
-
- spin_lock_irqsave(&pdata->phy_lock, flags);
-
- mac_cr = smsc911x_mac_read(pdata, MAC_CR);
- if (pdata->mii.full_duplex) {
- SMSC_TRACE("configuring for full duplex mode");
- mac_cr |= MAC_CR_FDPX_;
- } else {
- SMSC_TRACE("configuring for half duplex mode");
- mac_cr &= ~MAC_CR_FDPX_;
- }
- smsc911x_mac_write(pdata, MAC_CR, mac_cr);
- smsc911x_phy_update_flowcontrol(pdata);
-
- spin_unlock_irqrestore(&pdata->phy_lock, flags);
-}
-
-
-/* Update link mode if any thing has changed */
-static void smsc911x_phy_update_linkmode(struct net_device *dev, int init)
-{
- struct smsc911x_data *pdata = netdev_priv(dev);
-
- if (mii_check_media(&pdata->mii, netif_msg_link(pdata), init))
- smsc911x_phy_update_duplex(dev);
- /* mii_check_media() exists if the media is forced... */
- if (pdata->mii.force_media) {
- int cur_link = mii_link_ok(&pdata->mii);
- int prev_link = netif_carrier_ok(dev);
-
- if (!prev_link && cur_link) {
- printk(KERN_INFO "%s: link up\n", dev->name);
- netif_carrier_on(dev);
- } else if (prev_link && !cur_link) {
- printk(KERN_INFO "%s: link down\n", dev->name);
- netif_carrier_off(dev);
- }
- }
-
-#ifdef USE_LED1_WORK_AROUND
- if (netif_carrier_ok(dev)) {
- if ((pdata->gpio_orig_setting & GPIO_CFG_LED1_EN_) &&
- (!pdata->using_extphy)) {
- /* Restore orginal GPIO configuration */
- pdata->gpio_setting = pdata->gpio_orig_setting;
- smsc911x_reg_write(pdata->gpio_setting, pdata,
- GPIO_CFG);
- }
- } else {
- /* Check global setting that LED1
- * usage is 10/100 indicator */
- pdata->gpio_setting = smsc911x_reg_read(pdata, GPIO_CFG);
- if ((pdata->gpio_setting & GPIO_CFG_LED1_EN_)
- && (!pdata->using_extphy)) {
- /* Force 10/100 LED off, after saving
- * orginal GPIO configuration */
- pdata->gpio_orig_setting = pdata->gpio_setting;
-
- pdata->gpio_setting &= ~GPIO_CFG_LED1_EN_;
- pdata->gpio_setting |= (GPIO_CFG_GPIOBUF0_
- | GPIO_CFG_GPIODIR0_
- | GPIO_CFG_GPIOD0_);
- smsc911x_reg_write(pdata->gpio_setting, pdata,
- GPIO_CFG);
- }
- }
-#endif /* USE_LED1_WORK_AROUND */
-}
-
-/* Entry point for the link poller */
-static void smsc911x_phy_checklink(unsigned long ptr)
-{
- struct net_device *dev = (struct net_device *)ptr;
- struct smsc911x_data *pdata = netdev_priv(dev);
-
- smsc911x_phy_update_linkmode(dev, 0);
-
- if (!(pdata->stop_link_poll)) {
- pdata->link_poll_timer.expires = jiffies + 2 * HZ;
- add_timer(&pdata->link_poll_timer);
- } else {
- pdata->stop_link_poll = 0;
- }
-}
-
-static void smsc911x_phy_set_automdx(struct smsc911x_data *pdata)
-{
- u16 ctrlstatus;
-
- ctrlstatus = smsc911x_phy_read(pdata, 27);
- ctrlstatus &= 0x1fff;
- ctrlstatus |= (0x6 << 13);
- smsc911x_phy_write(pdata, 27, ctrlstatus);
-}
-
-/* Initialises the PHY layer. Called at initialisation by open() so
- * interrupts are enabled */
-static int smsc911x_phy_initialise(struct net_device *dev)
-{
- struct smsc911x_data *pdata = netdev_priv(dev);
- unsigned int phyid1 = 0;
- unsigned int phyid2 = 0;
- unsigned int temp;
-
- printk_debug("Calling phy_initialise()\n");
-
- pdata->using_extphy = 0;
-
- switch (pdata->idrev & 0xFFFF0000) {
- case 0x01170000:
- case 0x01150000:
- /* External PHY supported, try to autodetect */
- if (smsc911x_phy_initialise_external(pdata) < 0) {
- SMSC_TRACE("External PHY is not detected, using "
- "internal PHY instead");
- pdata->mii.phy_id = 1;
- }
- break;
- default:
- SMSC_TRACE("External PHY is not supported, using internal PHY "
- "instead");
- pdata->mii.phy_id = 1;
- break;
- }
-
- spin_lock_irq(&pdata->phy_lock);
- phyid1 = smsc911x_phy_read(pdata, MII_PHYSID1);
- phyid2 = smsc911x_phy_read(pdata, MII_PHYSID2);
- spin_unlock_irq(&pdata->phy_lock);
-
- if ((phyid1 == 0xFFFF) && (phyid2 == 0xFFFF)) {
- SMSC_WARNING("Internal PHY not detected!");
- return 0;
- }
-
- /* Reset the phy */
- if (!smsc911x_phy_reset(pdata)) {
- SMSC_WARNING("PHY reset failed to complete.");
- return 0;
- }
-#ifdef USE_PHY_WORK_AROUND
- if (!smsc911x_phy_loopbacktest(pdata)) {
- SMSC_WARNING("Failed Loop Back Test");
- return 0;
- } else {
- SMSC_TRACE("Passed Loop Back Test");
- }
-#endif /* USE_PHY_WORK_AROUND */
-
-
- smsc911x_phy_set_automdx(pdata);
-
- /* Advertise all speeds and pause capabilities */
- spin_lock_irq(&pdata->phy_lock);
- temp = smsc911x_phy_read(pdata, MII_ADVERTISE);
- temp |= (ADVERTISE_ALL | ADVERTISE_PAUSE_CAP | ADVERTISE_PAUSE_ASYM);
- smsc911x_phy_write(pdata, MII_ADVERTISE, temp);
- pdata->mii.advertising = temp;
-
- if (!pdata->using_extphy) {
- /* using internal phy, enable PHY interrupts */
- smsc911x_phy_read(pdata, MII_INTSTS);
- smsc911x_phy_write(pdata, MII_INTMSK, PHY_INTMSK_DEFAULT_);
- }
-
- /* begin to establish link */
- smsc911x_phy_write(pdata, MII_BMCR, BMCR_ANENABLE | BMCR_ANRESTART);
- spin_unlock_irq(&pdata->phy_lock);
-
- smsc911x_phy_update_linkmode(dev, 1);
-
- pdata->stop_link_poll = 0;
- setup_timer(&pdata->link_poll_timer, smsc911x_phy_checklink,
- (unsigned long)dev);
- pdata->link_poll_timer.expires = jiffies + 2 * HZ;
- add_timer(&pdata->link_poll_timer);
-
- printk_debug("PHY initialised succesfully\n");
- return 1;
-}
-
-/* Gets the number of tx statuses in the fifo */
-static unsigned int smsc911x_tx_get_txstatcount(struct smsc911x_data *pdata)
-{
- unsigned int result = (smsc911x_reg_read(pdata, TX_FIFO_INF)
- & TX_FIFO_INF_TSUSED_) >> 16;
- return result;
-}
-
-/* Reads tx statuses and increments counters where necessary */
-static void smsc911x_tx_update_txcounters(struct smsc911x_data *pdata)
-{
- struct net_device *netdev = pdata->netdev;
- unsigned int tx_stat;
-
- while ((tx_stat = smsc911x_tx_get_txstatus(pdata)) != 0) {
- if (unlikely(tx_stat & 0x80000000)) {
- /* In this driver the packet tag is used as the packet
- * length. Since a packet length can never reach the
- * size of 0x8000, this bit is reserved. It is worth
- * noting that the "reserved bit" in the warning above
- * does not reference a hardware defined reserved bit
- * but rather a driver defined one.
- */
- SMSC_WARNING("Packet tag reserved bit is high");
- } else {
- if (unlikely(tx_stat & 0x00008000)) {
- printk_debug("TX status error: 0x%08x (MAC 0x%08x)\n",
- tx_stat, smsc911x_mac_read(pdata, MAC_CR));
- netdev->stats.tx_errors++;
- } else {
- netdev->stats.tx_packets++;
- netdev->stats.tx_bytes += (tx_stat >> 16);
- }
- if (unlikely(tx_stat & 0x00000100)) {
- netdev->stats.collisions += 16;
- netdev->stats.tx_aborted_errors += 1;
- } else {
- netdev->stats.collisions +=
- ((tx_stat >> 3) & 0xF);
- }
- if (unlikely(tx_stat & 0x00000800)) {
- netdev->stats.tx_carrier_errors += 1;
- }
- if (unlikely(tx_stat & 0x00000200)) {
- netdev->stats.collisions++;
- netdev->stats.tx_aborted_errors++;
- }
- }
- }
-}
-
-/* Increments the Rx error counters */
-static void
-smsc911x_rx_counterrors(struct smsc911x_data *pdata, unsigned int rxstat)
-{
- struct net_device *netdev = pdata->netdev;
- int crc_err = 0;
-
- if (unlikely(rxstat & 0x00008000)) {
- netdev->stats.rx_errors++;
- if (unlikely(rxstat & 0x00000002)) {
- netdev->stats.rx_crc_errors++;
- crc_err = 1;
- }
- }
- if (likely(!crc_err)) {
- if (unlikely((rxstat & 0x00001020) == 0x00001020)) {
- /* Frame type indicates length,
- * and length error is set */
- netdev->stats.rx_length_errors++;
- }
- if (rxstat & RX_STS_MCAST_)
- netdev->stats.multicast++;
- }
-}
-
-/* Quickly dumps bad packets */
-static void
-smsc911x_rx_fastforward(struct smsc911x_data *pdata, unsigned int pktbytes)
-{
- unsigned int pktwords = (pktbytes + NET_IP_ALIGN + 3) >> 2;
-
- if (likely(pktwords >= 4)) {
- unsigned int timeout = 500;
- unsigned int val;
- smsc911x_reg_write(RX_DP_CTRL_RX_FFWD_, pdata, RX_DP_CTRL);
- do {
- udelay(1);
- val = smsc911x_reg_read(pdata, RX_DP_CTRL);
- } while (timeout-- && (val & RX_DP_CTRL_RX_FFWD_));
-
- if (unlikely(timeout == 0))
- SMSC_WARNING("Timed out waiting for RX FFWD "
- "to finish, RX_DP_CTRL: 0x%08X", val);
- } else {
- unsigned int temp;
- while (pktwords--)
- temp = smsc911x_reg_read(pdata, RX_DATA_FIFO);
- }
-}
-
-/* NAPI poll function */
-static int smsc911x_poll(struct napi_struct *napi, int budget)
-{
- struct smsc911x_data *pdata = container_of(napi, struct smsc911x_data, napi);
- struct net_device *dev = pdata->netdev;
- int npackets = 0;
-
- while (npackets < budget) {
- unsigned int pktlength;
- unsigned int pktwords;
- unsigned int rxstat = smsc911x_rx_get_rxstatus(pdata);
-
- /* break out of while loop if there are no more packets waiting */
- if (!rxstat) {
- printk_debug("Stopping the RX poll\n");
- break;
- }
-
- pktlength = ((rxstat & 0x3FFF0000) >> 16);
- pktwords = (pktlength + NET_IP_ALIGN + 3) >> 2;
- printk_debug("Going to read %i words (pktlen %i)\n",
- pktwords, pktlength);
-
- smsc911x_rx_counterrors(pdata, rxstat);
-
- if (likely((rxstat & RX_STS_ES_) == 0)) {
- struct sk_buff *skb;
- skb = dev_alloc_skb(pktlength + NET_IP_ALIGN);
- if (likely(skb)) {
- skb->data = skb->head;
- skb->tail = skb->head;
- /* Align IP on 16B boundary */
- skb_reserve(skb, NET_IP_ALIGN);
- skb_put(skb, pktlength - 4);
- smsc911x_rx_readfifo(pdata,
- (unsigned int *)skb->head,
- pktwords);
- skb->dev = dev;
- skb->protocol = eth_type_trans(skb, dev);
- skb->ip_summed = CHECKSUM_NONE;
- netif_receive_skb(skb);
-
- /* Update counters */
- dev->stats.rx_packets++;
- dev->stats.rx_bytes += (pktlength - 4);
- dev->last_rx = jiffies;
- npackets++;
- continue;
- } else {
- SMSC_WARNING("Unable to allocate sk_buff "
- "for rx packet, in PIO path");
- dev->stats.rx_dropped++;
- }
- }
- /* At this point, the packet is to be read out
- * of the fifo and discarded */
- smsc911x_rx_fastforward(pdata, pktlength);
- }
-
- dev->stats.rx_dropped += smsc911x_reg_read(pdata, RX_DROP);
- smsc911x_reg_write(INT_STS_RSFL_, pdata, INT_STS);
-
- if (npackets < budget) {
- unsigned int temp;
- /* We processed all packets available. Tell NAPI it can
- * stop polling then re-enable rx interrupts */
- napi_complete(napi);
- temp = smsc911x_reg_read(pdata, INT_EN);
- temp |= INT_EN_RSFL_EN_;
- smsc911x_reg_write(temp, pdata, INT_EN);
- }
-
- /* Return total received packets */
- return npackets;
-}
-
-/* Returns hash bit number for given MAC address
- * Example:
- * 01 00 5E 00 00 01 -> returns bit number 31 */
-static unsigned int smsc911x_hash(char addr[ETH_ALEN])
-{
- unsigned int crc;
- unsigned int result;
-
- crc = ether_crc(ETH_ALEN, addr);
- result = (crc >> 26) & 0x3f;
-
- return result;
-}
-
-static void smsc911x_rx_multicast_update(struct smsc911x_data *pdata)
-{
- /* Performs the multicast & mac_cr update. This is called when
- * safe on the current hardware, and with the phy_lock held */
- unsigned int mac_cr = smsc911x_mac_read(pdata, MAC_CR);
- mac_cr |= pdata->set_bits_mask;
- mac_cr &= ~(pdata->clear_bits_mask);
- smsc911x_mac_write(pdata, MAC_CR, mac_cr);
- smsc911x_mac_write(pdata, HASHH, pdata->hashhi);
- smsc911x_mac_write(pdata, HASHL, pdata->hashlo);
-}
-
-static void smsc911x_rx_multicast_update_workaround(struct smsc911x_data *pdata)
-{
- unsigned int mac_cr;
-
- /* This function is only called for older LAN911x devices
- * (revA or revB), where MAC_CR, HASHH and HASHL should not
- * be modified during Rx - newer devices immediately update the
- * registers.
- *
- * This is called from interrupt context */
-
- spin_lock(&pdata->phy_lock);
-
- /* Check Rx has stopped */
- if (smsc911x_mac_read(pdata, MAC_CR) & MAC_CR_RXEN_)
- SMSC_WARNING("Rx not stopped\n");
-
- /* Perform the update - safe to do now Rx has stopped */
- smsc911x_rx_multicast_update(pdata);
-
- /* Re-enable Rx */
- mac_cr = smsc911x_mac_read(pdata, MAC_CR);
- mac_cr |= MAC_CR_RXEN_;
- smsc911x_mac_write(pdata, MAC_CR, mac_cr);
-
- pdata->multicast_update_pending = 0;
-
- spin_unlock(&pdata->phy_lock);
-}
-
-/* Sets the device MAC address to dev_addr, called with phy_lock held */
-static void
-smsc911x_set_mac_address(struct smsc911x_data *pdata, u8 dev_addr[6])
-{
- u32 mac_high16 = (dev_addr[5] << 8) | dev_addr[4];
- u32 mac_low32 = (dev_addr[3] << 24) | (dev_addr[2] << 16) |
- (dev_addr[1] << 8) | dev_addr[0];
-
- smsc911x_mac_write(pdata, ADDRH, mac_high16);
- smsc911x_mac_write(pdata, ADDRL, mac_low32);
-}
-
-static int smsc911x_open(struct net_device *dev)
-{
- struct smsc911x_data *pdata = netdev_priv(dev);
- unsigned int timeout;
- unsigned int temp;
- unsigned int intcfg = 0;
- struct sockaddr addr;
-
- /* Reset the LAN911x */
- smsc911x_reg_write(HW_CFG_SRST_, pdata, HW_CFG);
- timeout = 10;
- do {
- udelay(10);
- temp = smsc911x_reg_read(pdata, HW_CFG);
- } while ((--timeout) && (temp & HW_CFG_SRST_));
-
- if (unlikely(temp & HW_CFG_SRST_)) {
- printk_err("Failed to complete reset");
- return -ENODEV;
- }
-
- smsc911x_reg_write(0x00050000, pdata, HW_CFG);
- smsc911x_reg_write(0x006E3740, pdata, AFC_CFG);
-
- /* Make sure EEPROM has finished loading before setting GPIO_CFG */
- timeout = 50;
- while ((timeout--) &&
- (smsc911x_reg_read(pdata, E2P_CMD) & E2P_CMD_EPC_BUSY_)) {
- udelay(10);
- }
-
- if (unlikely(timeout == 0)) {
- SMSC_WARNING("Timed out waiting for EEPROM "
- "busy bit to clear");
- }
-#if USE_DEBUG >= 1
- smsc911x_reg_write(0x00670700, pdata, GPIO_CFG);
-#else
- smsc911x_reg_write(0x70070000, pdata, GPIO_CFG);
-#endif
-
- /* Initialise irqs, but leave all sources disabled */
- smsc911x_reg_write(0, pdata, INT_EN);
- smsc911x_reg_write(0xFFFFFFFF, pdata, INT_STS);
-
- /* Set interrupt deassertion to 100uS */
- //intcfg = ((0x38 << 24) | INT_CFG_IRQ_EN_);
- intcfg = ((0x00 << 24) | INT_CFG_IRQ_EN_);
- // PPH modified intcfg = ((10 << 24) | INT_CFG_IRQ_EN_);
-
- if (pdata->irq_polarity) {
- SMSC_TRACE("irq polarity: active high");
- intcfg |= INT_CFG_IRQ_POL_;
- } else {
- SMSC_TRACE("irq polarity: active low");
- }
-
- if (pdata->irq_type) {
- SMSC_TRACE("irq type: push-pull");
- intcfg |= INT_CFG_IRQ_TYPE_;
- } else {
- SMSC_TRACE("irq type: open drain");
- }
-
- smsc911x_reg_write(intcfg, pdata, INT_CFG);
-
- printk_debug("Testing irq handler using IRQ %d\n", dev->irq);
- pdata->software_irq_signal = 0;
- smp_wmb();
-
- temp = smsc911x_reg_read(pdata, INT_EN);
- temp |= INT_EN_SW_INT_EN_;
- smsc911x_reg_write(temp, pdata, INT_EN);
-
- timeout = 1000;
- while (timeout--) {
- smp_rmb();
- if (pdata->software_irq_signal)
- break;
- msleep(1);
- }
-
- if (!pdata->software_irq_signal) {
- printk(KERN_WARNING "%s: ISR failed signaling test (IRQ %d)\n",
- dev->name, dev->irq);
- return -ENODEV;
- }
-
- printk_debug("IRQ handler passed test using IRQ %d\n", dev->irq);
- netif_carrier_off(dev);
-
- if (!smsc911x_phy_initialise(dev)) {
- printk_err("Failed to initialize the PHY");
- return -ENODEV;
- }
-
- temp = smsc911x_reg_read(pdata, HW_CFG);
- temp &= HW_CFG_TX_FIF_SZ_;
- temp |= HW_CFG_SF_;
- smsc911x_reg_write(temp, pdata, HW_CFG);
-
- temp = smsc911x_reg_read(pdata, FIFO_INT);
- temp |= FIFO_INT_TX_AVAIL_LEVEL_;
- temp &= ~(FIFO_INT_RX_STS_LEVEL_);
- smsc911x_reg_write(temp, pdata, FIFO_INT);
-
- /* set RX Data offset to 2 bytes for alignment */
- smsc911x_reg_write((2 << 8), pdata, RX_CFG);
-
- /* enable the polling before enabling the interrupts */
- napi_enable(&pdata->napi);
-
- temp = smsc911x_reg_read(pdata, INT_EN);
- temp |= (INT_EN_TDFA_EN_ | INT_EN_RSFL_EN_ | INT_EN_RDFL_EN_);
- smsc911x_reg_write(temp, pdata, INT_EN);
-
- spin_lock_irq(&pdata->phy_lock);
-
- /*
- * Reenable the full duplex mode, otherwise the TX engine will generate
- * status errors (Luis Galdos)
- */
- temp = smsc911x_mac_read(pdata, MAC_CR);
- temp |= (MAC_CR_TXEN_ | MAC_CR_RXEN_ | MAC_CR_HBDIS_ | MAC_CR_FDPX_);
- smsc911x_mac_write(pdata, MAC_CR, temp);
- spin_unlock_irq(&pdata->phy_lock);
-
- smsc911x_reg_write(TX_CFG_TX_ON_, pdata, TX_CFG);
-
- /* Set the MAC once again */
- memcpy(addr.sa_data, dev->dev_addr, dev->addr_len);
- if(smsc911x_set_mac(dev, &addr))
- printk_err("Couldn't set the MAC address.\n");
-
- netif_start_queue(dev);
- return 0;
-}
-
-/* Entry point for stopping the interface */
-static int smsc911x_stop(struct net_device *dev)
-{
- struct smsc911x_data *pdata = netdev_priv(dev);
-
- printk_info("Stopping the interface\n");
-
- napi_disable(&pdata->napi);
-
- /* disable interrupts */
- smsc911x_reg_write(0, pdata, INT_EN);
-
- pdata->stop_link_poll = 1;
- del_timer_sync(&pdata->link_poll_timer);
-
- netif_stop_queue(dev);
-
- /* At this point all Rx and Tx activity is stopped */
- dev->stats.rx_dropped += smsc911x_reg_read(pdata, RX_DROP);
- smsc911x_tx_update_txcounters(pdata);
-
- /* Stop sending data after the last transmission */
- smsc911x_reg_write(TX_CFG_STOP_TX_, pdata, TX_CFG);
-
- SMSC_TRACE("Interface stopped");
- return 0;
-}
-
-/* Entry point for transmitting a packet */
-static int smsc911x_hard_start_xmit(struct sk_buff *skb, struct net_device *dev)
-{
- struct smsc911x_data *pdata = netdev_priv(dev);
- unsigned int freespace;
- unsigned int tx_cmd_a;
- unsigned int tx_cmd_b;
- unsigned int temp;
- u32 wrsz;
- u32 bufp;
-
- freespace = smsc911x_reg_read(pdata, TX_FIFO_INF) & TX_FIFO_INF_TDFREE_;
-
- if (unlikely(freespace < TX_FIFO_LOW_THRESHOLD))
- SMSC_WARNING("Tx data fifo low, space available: %d",
- freespace);
-
- /* Word alignment adjustment */
- tx_cmd_a = ((((unsigned int)(skb->data)) & 0x03) << 16);
- tx_cmd_a |= TX_CMD_A_FIRST_SEG_ | TX_CMD_A_LAST_SEG_;
- tx_cmd_a |= (unsigned int)skb->len;
-
- tx_cmd_b = ((unsigned int)skb->len) << 16;
- tx_cmd_b |= (unsigned int)skb->len;
-
- smsc911x_reg_write(tx_cmd_a, pdata, TX_DATA_FIFO);
- smsc911x_reg_write(tx_cmd_b, pdata, TX_DATA_FIFO);
-
- bufp = ((u32)skb->data) & 0xFFFFFFFC;
- wrsz = (u32)skb->len + 3;
- wrsz += ((u32)skb->data) & 0x3;
- wrsz >>= 2;
-
- smsc911x_tx_writefifo(pdata, (unsigned int *)bufp, wrsz);
- freespace -= (skb->len + 32);
- dev_kfree_skb(skb);
- dev->trans_start = jiffies;
-
- if (unlikely(smsc911x_tx_get_txstatcount(pdata) >= 30))
- smsc911x_tx_update_txcounters(pdata);
-
- if (freespace < TX_FIFO_LOW_THRESHOLD) {
- netif_stop_queue(dev);
- temp = smsc911x_reg_read(pdata, FIFO_INT);
- temp &= 0x00FFFFFF;
- temp |= 0x32000000;
- smsc911x_reg_write(temp, pdata, FIFO_INT);
- }
-
- return NETDEV_TX_OK;
-}
-
-/* Entry point for getting status counters */
-static struct net_device_stats *smsc911x_get_stats(struct net_device *dev)
-{
- struct smsc911x_data *pdata = netdev_priv(dev);
- smsc911x_tx_update_txcounters(pdata);
- dev->stats.rx_dropped += smsc911x_reg_read(pdata, RX_DROP);
- return &dev->stats;
-}
-
-/* Entry point for setting addressing modes */
-static void smsc911x_set_multicast_list(struct net_device *dev)
-{
- struct smsc911x_data *pdata = netdev_priv(dev);
- unsigned long flags;
-
- if (dev->flags & IFF_PROMISC) {
- /* Enabling promiscuous mode */
- pdata->set_bits_mask = MAC_CR_PRMS_;
- pdata->clear_bits_mask = (MAC_CR_MCPAS_ | MAC_CR_HPFILT_);
- pdata->hashhi = 0;
- pdata->hashlo = 0;
- } else if (dev->flags & IFF_ALLMULTI) {
- /* Enabling all multicast mode */
- pdata->set_bits_mask = MAC_CR_MCPAS_;
- pdata->clear_bits_mask = (MAC_CR_PRMS_ | MAC_CR_HPFILT_);
- pdata->hashhi = 0;
- pdata->hashlo = 0;
- } else if (dev->mc_count > 0) {
- /* Enabling specific multicast addresses */
- unsigned int hash_high = 0;
- unsigned int hash_low = 0;
- unsigned int count = 0;
- struct dev_mc_list *mc_list = dev->mc_list;
-
- pdata->set_bits_mask = MAC_CR_HPFILT_;
- pdata->clear_bits_mask = (MAC_CR_PRMS_ | MAC_CR_MCPAS_);
-
- while (mc_list) {
- count++;
- if ((mc_list->dmi_addrlen) == ETH_ALEN) {
- unsigned int bitnum =
- smsc911x_hash(mc_list->dmi_addr);
- unsigned int mask = 0x01 << (bitnum & 0x1F);
- if (bitnum & 0x20)
- hash_high |= mask;
- else
- hash_low |= mask;
- } else {
- SMSC_WARNING("dmi_addrlen != 6");
- }
- mc_list = mc_list->next;
- }
- if (count != (unsigned int)dev->mc_count)
- SMSC_WARNING("mc_count != dev->mc_count");
-
- pdata->hashhi = hash_high;
- pdata->hashlo = hash_low;
- } else {
- /* Enabling local MAC address only */
- pdata->set_bits_mask = 0;
- pdata->clear_bits_mask =
- (MAC_CR_PRMS_ | MAC_CR_MCPAS_ | MAC_CR_HPFILT_);
- pdata->hashhi = 0;
- pdata->hashlo = 0;
- }
-
- spin_lock_irqsave(&pdata->phy_lock, flags);
-
- if (pdata->generation <= 1) {
- /* Older hardware revision - cannot change these flags while
- * receiving data */
- if (!pdata->multicast_update_pending) {
- unsigned int temp;
- SMSC_TRACE("scheduling mcast update");
- pdata->multicast_update_pending = 1;
-
- /* Request the hardware to stop, then perform the
- * update when we get an RX_STOP interrupt */
- smsc911x_reg_write(INT_STS_RXSTOP_INT_, pdata, INT_STS);
- temp = smsc911x_reg_read(pdata, INT_EN);
- temp |= INT_EN_RXSTOP_INT_EN_;
- smsc911x_reg_write(temp, pdata, INT_EN);
-
- temp = smsc911x_mac_read(pdata, MAC_CR);
- temp &= ~(MAC_CR_RXEN_);
- smsc911x_mac_write(pdata, MAC_CR, temp);
- } else {
- /* There is another update pending, this should now
- * use the newer values */
- }
- } else {
- /* Newer hardware revision - can write immediately */
- smsc911x_rx_multicast_update(pdata);
- }
-
- spin_unlock_irqrestore(&pdata->phy_lock, flags);
-}
-
-static irqreturn_t smsc911x_irqhandler(int irq, void *dev_id)
-{
- struct net_device *dev = dev_id;
- struct smsc911x_data *pdata = netdev_priv(dev);
- unsigned int intsts;
- unsigned int inten;
- unsigned int temp;
- unsigned int intcfg;
- int serviced = IRQ_NONE;
-
- intcfg = smsc911x_reg_read(pdata, INT_CFG);
- intsts = smsc911x_reg_read(pdata, INT_STS);
- inten = smsc911x_reg_read(pdata, INT_EN);
-
- printk_debug("New IRQ: intsts 0x%08x\n", intsts);
-
- if ((intcfg & (INT_CFG_IRQ_INT_ | INT_CFG_IRQ_EN_)) != (INT_CFG_IRQ_INT_ |
- INT_CFG_IRQ_EN_))
- return serviced;
-
-
- if (unlikely(intsts & inten & INT_STS_SW_INT_)) {
- temp = smsc911x_reg_read(pdata, INT_EN);
- temp &= (~INT_EN_SW_INT_EN_);
- smsc911x_reg_write(temp, pdata, INT_EN);
- smsc911x_reg_write(INT_STS_SW_INT_, pdata, INT_STS);
- pdata->software_irq_signal = 1;
- smp_wmb();
- serviced = IRQ_HANDLED;
- }
-
- if (unlikely(intsts & inten & INT_STS_RXSTOP_INT_)) {
- /* Called when there is a multicast update scheduled and
- * it is now safe to complete the update */
- SMSC_TRACE("RX Stop interrupt");
- temp = smsc911x_reg_read(pdata, INT_EN);
- temp &= (~INT_EN_RXSTOP_INT_EN_);
- smsc911x_reg_write(temp, pdata, INT_EN);
- smsc911x_reg_write(INT_STS_RXSTOP_INT_, pdata, INT_STS);
- smsc911x_rx_multicast_update_workaround(pdata);
- serviced = IRQ_HANDLED;
- }
-
- if (intsts & inten & INT_STS_TDFA_) {
- temp = smsc911x_reg_read(pdata, FIFO_INT);
- temp |= FIFO_INT_TX_AVAIL_LEVEL_;
- smsc911x_reg_write(temp, pdata, FIFO_INT);
- smsc911x_reg_write(INT_STS_TDFA_, pdata, INT_STS);
- netif_wake_queue(dev);
- serviced = IRQ_HANDLED;
- }
-
- if (unlikely(intsts & inten & INT_STS_RXE_)) {
- smsc911x_reg_write(INT_STS_RXE_, pdata, INT_STS);
- serviced = IRQ_HANDLED;
- }
-
- if (likely(intsts & inten & INT_STS_RSFL_)) {
- if (likely(napi_schedule_prep(&pdata->napi))) {
- /* Disable Rx interrupts and schedule NAPI poll */
- temp = smsc911x_reg_read(pdata, INT_EN);
- temp &= (~INT_EN_RSFL_EN_);
- smsc911x_reg_write(temp, pdata, INT_EN);
- __napi_schedule(&pdata->napi);
- }
-
- serviced = IRQ_HANDLED;
- }
-
- if (unlikely(intsts & inten & INT_STS_PHY_INT_)) {
- smsc911x_reg_write(INT_STS_PHY_INT_, pdata, INT_STS);
- spin_lock(&pdata->phy_lock);
- temp = smsc911x_phy_read(pdata, MII_INTSTS);
- spin_unlock(&pdata->phy_lock);
- SMSC_TRACE("PHY interrupt, sts 0x%04X", (u16)temp);
- smsc911x_phy_update_linkmode(dev, 0);
- serviced = IRQ_HANDLED;
- }
- return serviced;
-}
-
-#ifdef CONFIG_NET_POLL_CONTROLLER
-void smsc911x_poll_controller(struct net_device *dev)
-{
- disable_irq(dev->irq);
- smsc911x_irqhandler(0, dev);
- enable_irq(dev->irq);
-}
-#endif /* CONFIG_NET_POLL_CONTROLLER */
-
-/* Standard ioctls for mii-tool */
-static int smsc911x_do_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
-{
- struct smsc911x_data *pdata = netdev_priv(dev);
- unsigned int chg_in_duplex;
- int ret;
-
- if (!netif_running(dev))
- return -EINVAL;
- ret = generic_mii_ioctl(&pdata->mii, if_mii(ifr), cmd, &chg_in_duplex);
- if ((ret == 0) && (chg_in_duplex != 0))
- smsc911x_phy_update_duplex(dev);
-
- return ret;
-}
-
-static int
-smsc911x_ethtool_getsettings(struct net_device *dev, struct ethtool_cmd *cmd)
-{
- struct smsc911x_data *pdata = netdev_priv(dev);
-
- cmd->maxtxpkt = 1;
- cmd->maxrxpkt = 1;
- return mii_ethtool_gset(&pdata->mii, cmd);
-}
-
-static int
-smsc911x_ethtool_setsettings(struct net_device *dev, struct ethtool_cmd *cmd)
-{
- struct smsc911x_data *pdata = netdev_priv(dev);
-
- return mii_ethtool_sset(&pdata->mii, cmd);
-}
-
-static void smsc911x_ethtool_getdrvinfo(struct net_device *dev,
- struct ethtool_drvinfo *info)
-{
- strlcpy(info->driver, SMSC_CHIPNAME, sizeof(info->driver));
- strlcpy(info->version, SMSC_DRV_VERSION, sizeof(info->version));
- strlcpy(info->bus_info, dev_name(dev->dev.parent),
- sizeof(info->bus_info));
-}
-
-static int smsc911x_ethtool_nwayreset(struct net_device *dev)
-{
- struct smsc911x_data *pdata = netdev_priv(dev);
-
- return mii_nway_restart(&pdata->mii);
-}
-
-static u32 smsc911x_ethtool_getmsglevel(struct net_device *dev)
-{
- struct smsc911x_data *pdata = netdev_priv(dev);
- return pdata->msg_enable;
-}
-
-static void smsc911x_ethtool_setmsglevel(struct net_device *dev, u32 level)
-{
- struct smsc911x_data *pdata = netdev_priv(dev);
- pdata->msg_enable = level;
-}
-
-static int smsc911x_ethtool_getregslen(struct net_device *dev)
-{
- return (((E2P_CMD - ID_REV) / 4 + 1) + (WUCSR - MAC_CR) + 1 + 32) *
- sizeof(u32);
-}
-
-static void
-smsc911x_ethtool_getregs(struct net_device *dev, struct ethtool_regs *regs,
- void *buf)
-{
- struct smsc911x_data *pdata = netdev_priv(dev);
- unsigned long flags;
- unsigned int i;
- unsigned int j = 0;
- u32 *data = buf;
-
- regs->version = pdata->idrev;
- for (i = ID_REV; i <= E2P_CMD; i += (sizeof(u32)))
- data[j++] = smsc911x_reg_read(pdata, i);
-
- spin_lock_irqsave(&pdata->phy_lock, flags);
- for (i = MAC_CR; i <= WUCSR; i++)
- data[j++] = smsc911x_mac_read(pdata, i);
- for (i = 0; i <= 31; i++)
- data[j++] = smsc911x_phy_read(pdata, i);
- spin_unlock_irqrestore(&pdata->phy_lock, flags);
-}
-
-static void smsc911x_eeprom_enable_access(struct smsc911x_data *pdata)
-{
- unsigned int temp = smsc911x_reg_read(pdata, GPIO_CFG);
- temp &= ~GPIO_CFG_EEPR_EN_;
- smsc911x_reg_write(temp, pdata, GPIO_CFG);
- msleep(1);
-}
-
-static int smsc911x_eeprom_send_cmd(struct smsc911x_data *pdata, u32 op)
-{
- int timeout = 100;
- u32 e2cmd;
-
- SMSC_TRACE("op 0x%08x", op);
- if (smsc911x_reg_read(pdata, E2P_CMD) & E2P_CMD_EPC_BUSY_) {
- SMSC_WARNING("Busy at start");
- return -EBUSY;
- }
-
- e2cmd = op | E2P_CMD_EPC_BUSY_;
- smsc911x_reg_write(e2cmd, pdata, E2P_CMD);
-
- do {
- msleep(1);
- e2cmd = smsc911x_reg_read(pdata, E2P_CMD);
- } while ((e2cmd & E2P_CMD_EPC_BUSY_) && (timeout--));
-
- if (!timeout) {
- SMSC_TRACE("TIMED OUT");
- return -EAGAIN;
- }
-
- if (e2cmd & E2P_CMD_EPC_TIMEOUT_) {
- SMSC_TRACE("Error occured during eeprom operation");
- return -EINVAL;
- }
-
- return 0;
-}
-
-static int smsc911x_eeprom_read_location(struct smsc911x_data *pdata,
- u8 address, u8 *data)
-{
- u32 op = E2P_CMD_EPC_CMD_READ_ | address;
- int ret;
-
- SMSC_TRACE("address 0x%x", address);
- ret = smsc911x_eeprom_send_cmd(pdata, op);
-
- if (!ret)
- data[address] = smsc911x_reg_read(pdata, E2P_DATA);
-
- return ret;
-}
-
-static int smsc911x_eeprom_write_location(struct smsc911x_data *pdata,
- u8 address, u8 data)
-{
- u32 op = E2P_CMD_EPC_CMD_ERASE_ | address;
- int ret;
-
- SMSC_TRACE("address 0x%x, data 0x%x", address, data);
- ret = smsc911x_eeprom_send_cmd(pdata, op);
-
- if (!ret) {
- op = E2P_CMD_EPC_CMD_WRITE_ | address;
- smsc911x_reg_write((u32)data, pdata, E2P_DATA);
- ret = smsc911x_eeprom_send_cmd(pdata, op);
- }
-
- return ret;
-}
-
-static int smsc911x_ethtool_get_eeprom_len(struct net_device *dev)
-{
- return SMSC911X_EEPROM_SIZE;
-}
-
-static int smsc911x_ethtool_get_eeprom(struct net_device *dev,
- struct ethtool_eeprom *eeprom, u8 *data)
-{
- struct smsc911x_data *pdata = netdev_priv(dev);
- u8 eeprom_data[SMSC911X_EEPROM_SIZE];
- int len;
- int i;
-
- smsc911x_eeprom_enable_access(pdata);
-
- len = min(eeprom->len, SMSC911X_EEPROM_SIZE);
- for (i = 0; i < len; i++) {
- int ret = smsc911x_eeprom_read_location(pdata, i, eeprom_data);
- if (ret < 0) {
- eeprom->len = 0;
- return ret;
- }
- }
-
- memcpy(data, &eeprom_data[eeprom->offset], len);
- eeprom->len = len;
- return 0;
-}
-
-static int smsc911x_ethtool_set_eeprom(struct net_device *dev,
- struct ethtool_eeprom *eeprom, u8 *data)
-{
- int ret;
- struct smsc911x_data *pdata = netdev_priv(dev);
-
- smsc911x_eeprom_enable_access(pdata);
- smsc911x_eeprom_send_cmd(pdata, E2P_CMD_EPC_CMD_EWEN_);
- ret = smsc911x_eeprom_write_location(pdata, eeprom->offset, *data);
- smsc911x_eeprom_send_cmd(pdata, E2P_CMD_EPC_CMD_EWDS_);
-
- /* Single byte write, according to man page */
- eeprom->len = 1;
-
- return ret;
-}
-
-static int smsc911x_ethtool_set_wol(struct net_device *dev,
- struct ethtool_wolinfo *wol)
-{
- struct smsc911x_data *pdata;
-
- /* Check for unsupported options */
- if (wol->wolopts & (WAKE_MAGICSECURE | WAKE_UCAST | WAKE_MCAST
- | WAKE_BCAST | WAKE_ARP))
- return -EINVAL;
-
- pdata = netdev_priv(dev);
-
- /* When disable the WOL options need to disable the PHY-interrupts too */
- if (!wol->wolopts) {
- printk_pmdbg("[ WOL ] Disabling all sources\n");
- pdata->pmt_ctrl &= ~(PMT_CTRL_WOL_EN_ | PMT_CTRL_ED_EN_);
- pdata->phy_intmsk &= ~PHY_INTMSK_ENERGYON_;
- pdata->mac_wucsr = 0;
- goto exit_set_wol;
- }
-
- /*
- * For the magic packet we MUST configure the MAC too, but we can't do it
- * at this point, cause the controller stops working.
- */
- if (wol->wolopts & WAKE_MAGIC) {
- printk_pmdbg("WOL: Enabling magic frame\n");
- pdata->mac_wucsr |= WUCSR_MPEN_;
- pdata->pmt_ctrl |= PMT_CTRL_WOL_EN_;
- }
-
- /* For the PHY-wakeup we must use the energy detection */
- if (wol->wolopts & WAKE_PHY) {
- printk_pmdbg("[ WOL ] Enabling PHY energy\n");
- pdata->phy_intmsk |= PHY_INTMSK_ENERGYON_;
- pdata->pmt_ctrl |= PMT_CTRL_ED_EN_;
- }
-
- exit_set_wol:
- return 0;
-}
-
-/* Function for getting the infos about the WOL */
-static void smsc911x_ethtool_get_wol(struct net_device *net_dev,
- struct ethtool_wolinfo *wol)
-{
- /* Only for magic and PHY power detection available up now */
- wol->supported = WAKE_MAGIC | WAKE_PHY;
-}
-
-static struct ethtool_ops smsc911x_ethtool_ops = {
- .get_settings = smsc911x_ethtool_getsettings,
- .set_settings = smsc911x_ethtool_setsettings,
- .get_link = ethtool_op_get_link,
- .get_drvinfo = smsc911x_ethtool_getdrvinfo,
- .nway_reset = smsc911x_ethtool_nwayreset,
- .get_msglevel = smsc911x_ethtool_getmsglevel,
- .set_msglevel = smsc911x_ethtool_setmsglevel,
- .get_regs_len = smsc911x_ethtool_getregslen,
- .get_regs = smsc911x_ethtool_getregs,
- .get_eeprom_len = smsc911x_ethtool_get_eeprom_len,
- .get_eeprom = smsc911x_ethtool_get_eeprom,
- .set_eeprom = smsc911x_ethtool_set_eeprom,
- .get_wol = smsc911x_ethtool_get_wol,
- .set_wol = smsc911x_ethtool_set_wol,
-};
-
-
-static int smsc911x_set_mac(struct net_device *dev, void *addr)
-{
- unsigned int reg;
- int retval;
- unsigned long flags;
- struct smsc911x_data *pdata;
- unsigned int low, high;
- struct sockaddr *paddr = addr;
-
- printk_debug("Set mac called\n");
-
- pdata = netdev_priv(dev);
-
- spin_lock_irqsave(&pdata->phy_lock, flags);
-
- /* First check that the MAC is not busy */
- reg = smsc911x_reg_read(pdata, MAC_CSR_CMD);
- if (unlikely(reg & MAC_CSR_CMD_CSR_BUSY_)) {
- printk_err("smsc911x_mac_read failed, MAC busy at entry");
- retval = -EBUSY;
- goto exit_unlock;
- }
-
- /* Get the MAC address */
- high = 0;
- memcpy(&low, &(paddr->sa_data[0]), 4);
- memcpy(&high, &(paddr->sa_data[4]), 2);
- printk_debug("Going to set the MAC %04X%08X\n", high, low);
-
- /* Now set the high address */
- smsc911x_reg_write(high, pdata, MAC_CSR_DATA);
- smsc911x_reg_write(ADDRH | MAC_CSR_CMD_CSR_BUSY_, pdata, MAC_CSR_CMD);
- reg = smsc911x_reg_read(pdata, BYTE_TEST);
- if (!smsc911x_mac_notbusy(pdata)) {
- retval = -EBUSY;
- goto exit_unlock;
- }
-
- /* First set the low address */
- smsc911x_reg_write(low, pdata, MAC_CSR_DATA);
- smsc911x_reg_write(ADDRL | MAC_CSR_CMD_CSR_BUSY_, pdata, MAC_CSR_CMD);
- reg = smsc911x_reg_read(pdata, BYTE_TEST);
- if (!smsc911x_mac_notbusy(pdata)) {
- retval = -EBUSY;
- goto exit_unlock;
- }
-
- /* And save the IP inside the driver structure */
- memcpy(dev->dev_addr, paddr->sa_data, dev->addr_len);
-
- printk_debug("MAC successful changed to %02X%08X\n",
- smsc911x_mac_read(pdata, ADDRH),
- smsc911x_mac_read(pdata, ADDRL));
-
- retval = 0;
-
- exit_unlock:
- spin_unlock_irqrestore(&pdata->phy_lock, flags);
-
- return retval;
-}
-
-static const struct net_device_ops smsc911x_netdev_ops = {
- .ndo_open = smsc911x_open,
- .ndo_stop = smsc911x_stop,
- .ndo_start_xmit = smsc911x_hard_start_xmit,
- .ndo_get_stats = smsc911x_get_stats,
- .ndo_set_multicast_list = smsc911x_set_multicast_list,
- .ndo_do_ioctl = smsc911x_do_ioctl,
- .ndo_set_mac_address = smsc911x_set_mac,
-#ifdef CONFIG_NET_POLL_CONTROLLER
- .ndo_poll_controller = smsc911x_poll_controller,
-#endif
-};
-
-/* Initializing private device structures */
-static int smsc911x_init(struct net_device *dev)
-{
- struct smsc911x_data *pdata = netdev_priv(dev);
-
- SMSC_TRACE("Driver Parameters:");
- SMSC_TRACE("LAN base: 0x%08lX", (unsigned long)pdata->ioaddr);
- SMSC_TRACE("IRQ: %d", dev->irq);
- SMSC_TRACE("PHY will be autodetected.");
-
- if (pdata->ioaddr == 0) {
- SMSC_WARNING("pdata->ioaddr: 0x00000000");
- return -ENODEV;
- }
-
- /* Default generation to zero (all workarounds apply) */
- pdata->generation = 0;
-
- pdata->idrev = smsc911x_reg_read(pdata, ID_REV);
- if (((pdata->idrev >> 16) & 0xFFFF) == (pdata->idrev & 0xFFFF)) {
- SMSC_WARNING("idrev top 16 bits equal to bottom 16 bits, "
- "idrev: 0x%08X", pdata->idrev);
- SMSC_TRACE("This may mean the chip is set for 32 bit while "
- "the bus is reading as 16 bit");
- return -ENODEV;
- }
- switch (pdata->idrev & 0xFFFF0000) {
- case 0x01180000:
- switch (pdata->idrev & 0x0000FFFFUL) {
- case 0UL:
- SMSC_TRACE("LAN9118 Beacon identified, idrev: 0x%08X",
- pdata->idrev);
- pdata->generation = 0;
- break;
- case 1UL:
- SMSC_TRACE
- ("LAN9118 Concord A0 identified, idrev: 0x%08X",
- pdata->idrev);
- pdata->generation = 1;
- break;
- case 2UL:
- SMSC_TRACE
- ("LAN9118 Concord A1 identified, idrev: 0x%08X",
- pdata->idrev);
- pdata->generation = 2;
- break;
- default:
- SMSC_TRACE
- ("LAN9118 Concord A1 identified (NEW), idrev: 0x%08X",
- pdata->idrev);
- pdata->generation = 2;
- break;
- }
- break;
-
- case 0x01170000:
- switch (pdata->idrev & 0x0000FFFFUL) {
- case 0UL:
- SMSC_TRACE("LAN9117 Beacon identified, idrev: 0x%08X",
- pdata->idrev);
- pdata->generation = 0;
- break;
- case 1UL:
- SMSC_TRACE
- ("LAN9117 Concord A0 identified, idrev: 0x%08X",
- pdata->idrev);
- pdata->generation = 1;
- break;
- case 2UL:
- SMSC_TRACE
- ("LAN9117 Concord A1 identified, idrev: 0x%08X",
- pdata->idrev);
- pdata->generation = 2;
- break;
- default:
- SMSC_TRACE
- ("LAN9117 Concord A1 identified (NEW), idrev: 0x%08X",
- pdata->idrev);
- pdata->generation = 2;
- break;
- }
- break;
-
- case 0x01160000:
- switch (pdata->idrev & 0x0000FFFFUL) {
- case 0UL:
- SMSC_WARNING("LAN911x not identified, idrev: 0x%08X",
- pdata->idrev);
- return -ENODEV;
- case 1UL:
- SMSC_TRACE
- ("LAN9116 Concord A0 identified, idrev: 0x%08X",
- pdata->idrev);
- pdata->generation = 1;
- break;
- case 2UL:
- SMSC_TRACE
- ("LAN9116 Concord A1 identified, idrev: 0x%08X",
- pdata->idrev);
- pdata->generation = 2;
- break;
- default:
- SMSC_TRACE
- ("LAN9116 Concord A1 identified (NEW), idrev: 0x%08X",
- pdata->idrev);
- pdata->generation = 2;
- break;
- }
- break;
-
- case 0x01150000:
- switch (pdata->idrev & 0x0000FFFFUL) {
- case 0UL:
- SMSC_WARNING("LAN911x not identified, idrev: 0x%08X",
- pdata->idrev);
- return -ENODEV;
- case 1UL:
- SMSC_TRACE
- ("LAN9115 Concord A0 identified, idrev: 0x%08X",
- pdata->idrev);
- pdata->generation = 1;
- break;
- case 2UL:
- SMSC_TRACE
- ("LAN9115 Concord A1 identified, idrev: 0x%08X",
- pdata->idrev);
- pdata->generation = 2;
- break;
- default:
- SMSC_TRACE
- ("LAN9115 Concord A1 identified (NEW), idrev: 0x%08X",
- pdata->idrev);
- pdata->generation = 2;
- break;
- }
- break;
-
- case 0x118A0000UL:
- switch (pdata->idrev & 0x0000FFFFUL) {
- case 0UL:
- SMSC_TRACE
- ("LAN9218 Boylston identified, idrev: 0x%08X",
- pdata->idrev);
- pdata->generation = 3;
- break;
- default:
- SMSC_TRACE
- ("LAN9218 Boylston identified (NEW), idrev: 0x%08X",
- pdata->idrev);
- pdata->generation = 3;
- break;
- }
- break;
-
- case 0x117A0000UL:
- switch (pdata->idrev & 0x0000FFFFUL) {
- case 0UL:
- SMSC_TRACE
- ("LAN9217 Boylston identified, idrev: 0x%08X",
- pdata->idrev);
- pdata->generation = 3;
- break;
- default:
- SMSC_TRACE
- ("LAN9217 Boylston identified (NEW), idrev: 0x%08X",
- pdata->idrev);
- pdata->generation = 3;
- break;
- }
- break;
-
- case 0x116A0000UL:
- switch (pdata->idrev & 0x0000FFFFUL) {
- case 0UL:
- SMSC_TRACE
- ("LAN9216 Boylston identified, idrev: 0x%08X",
- pdata->idrev);
- pdata->generation = 3;
- break;
- default:
- SMSC_TRACE
- ("LAN9216 Boylston identified (NEW), idrev: 0x%08X",
- pdata->idrev);
- pdata->generation = 3;
- break;
- }
- break;
-
- case 0x115A0000UL:
- switch (pdata->idrev & 0x0000FFFFUL) {
- case 0UL:
- SMSC_TRACE
- ("LAN9215 Boylston identified, idrev: 0x%08X",
- pdata->idrev);
- pdata->generation = 3;
- break;
- default:
- SMSC_TRACE
- ("LAN9215 Boylston identified (NEW), idrev: 0x%08X",
- pdata->idrev);
- pdata->generation = 3;
- break;
- }
- break;
-
- case 0x92100000UL:
- case 0x92110000UL:
- case 0x92200000UL:
- case 0x92210000UL:
- /* LAN9210/LAN9211/LAN9220/LAN9221 */
- pdata->generation = 4;
- break;
-
- default:
- SMSC_WARNING("LAN911x not identified, idrev: 0x%08X",
- pdata->idrev);
- return -ENODEV;
- }
-
- if (pdata->generation == 0)
- SMSC_WARNING("This driver is not intended "
- "for this chip revision");
-
- ether_setup(dev);
- dev->flags |= IFF_MULTICAST;
- netif_napi_add(dev, &pdata->napi, smsc911x_poll, 64);//SMSC_NAPI_WEIGHT
- dev->netdev_ops = &smsc911x_netdev_ops;
- dev->ethtool_ops = &smsc911x_ethtool_ops;
-
- pdata->mii.phy_id_mask = 0x1f;
- pdata->mii.reg_num_mask = 0x1f;
- pdata->mii.force_media = 0;
- pdata->mii.full_duplex = 0;
- pdata->mii.dev = dev;
- pdata->mii.mdio_read = smsc911x_mdio_read;
- pdata->mii.mdio_write = smsc911x_mdio_write;
-
- pdata->msg_enable = NETIF_MSG_LINK;
-
- return 0;
-}
-
-static int smsc911x_drv_remove(struct platform_device *pdev)
-{
- struct net_device *dev;
- struct smsc911x_data *pdata;
- struct resource *res;
-
- dev = platform_get_drvdata(pdev);
- BUG_ON(!dev);
- pdata = netdev_priv(dev);
- BUG_ON(!pdata);
- BUG_ON(!pdata->ioaddr);
-
- SMSC_TRACE("Stopping driver.");
- platform_set_drvdata(pdev, NULL);
- unregister_netdev(dev);
- free_irq(dev->irq, dev);
- res = platform_get_resource_byname(pdev, IORESOURCE_MEM,
- "smsc911x-memory");
- if (!res)
- platform_get_resource(pdev, IORESOURCE_MEM, 0);
-
- release_mem_region(res->start, res->end - res->start);
-
- iounmap(pdata->ioaddr);
-
- free_netdev(dev);
-
- return 0;
-}
-
-static int smsc911x_drv_probe(struct platform_device *pdev)
-{
- struct net_device *dev;
- struct smsc911x_data *pdata;
- struct resource *res;
- unsigned int intcfg = 0;
- int res_size;
- int retval;
-
- printk(KERN_INFO "%s: Driver version %s.\n", SMSC_CHIPNAME,
- SMSC_DRV_VERSION);
-
- res = platform_get_resource_byname(pdev, IORESOURCE_MEM,
- "smsc911x-memory");
- if (!res)
- res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- if (!res) {
- printk(KERN_WARNING "%s: Could not allocate resource.\n",
- SMSC_CHIPNAME);
- retval = -ENODEV;
- goto out_0;
- }
- res_size = res->end - res->start;
-
- if (!request_mem_region(res->start, res_size, SMSC_CHIPNAME)) {
- retval = -EBUSY;
- goto out_0;
- }
-
- dev = alloc_etherdev(sizeof(struct smsc911x_data));
- if (!dev) {
- printk(KERN_WARNING "%s: Could not allocate device.\n",
- SMSC_CHIPNAME);
- retval = -ENOMEM;
- goto out_release_io_1;
- }
-
- SET_NETDEV_DEV(dev, &pdev->dev);
-
- pdata = netdev_priv(dev);
- pdata->netdev = dev;
-
- dev->irq = platform_get_irq(pdev, 0);
- pdata->ioaddr = ioremap_nocache(res->start, res_size);
-
- /* copy config parameters across if present, otherwise pdata
- * defaults to zeros */
- if (pdev->dev.platform_data) {
- struct smc911x_platdata *config = pdev->dev.platform_data;
- pdata->irq_polarity = config->irq_polarity;
- pdata->irq_flags = config->irq_flags;
- pdata->irq_type = config->irq_type;
- }
-
- if (pdata->ioaddr == NULL) {
- SMSC_WARNING("Error smsc911x base address invalid");
- retval = -ENOMEM;
- goto out_free_netdev_2;
- }
-
- retval = smsc911x_init(dev);
- if (retval < 0)
- goto out_unmap_io_3;
-
- /* configure irq polarity and type before connecting isr */
- if (pdata->irq_polarity)
- intcfg |= INT_CFG_IRQ_POL_;
-
- if (pdata->irq_type)
- intcfg |= INT_CFG_IRQ_TYPE_;
-
- smsc911x_reg_write(intcfg, pdata, INT_CFG);
-
- retval = request_irq(dev->irq, smsc911x_irqhandler,
- pdata->irq_flags,
- SMSC_CHIPNAME, dev);
- if (retval) {
- SMSC_WARNING("Unable to claim requested irq: %d", dev->irq);
- goto out_unmap_io_3;
- }
-
- platform_set_drvdata(pdev, dev);
-
- retval = register_netdev(dev);
- if (retval) {
- SMSC_WARNING("Error %i registering device", retval);
- goto out_unset_drvdata_4;
- } else {
- SMSC_TRACE("Network interface: \"%s\"", dev->name);
- }
-
- spin_lock_init(&pdata->phy_lock);
-
- spin_lock_irq(&pdata->phy_lock);
-
- /* Check if mac address has been specified when bringing interface up */
- if (is_valid_ether_addr(dev->dev_addr)) {
- smsc911x_set_mac(dev, dev->dev_addr);
- SMSC_TRACE("MAC Address is specified by configuration");
- } else {
- /* Try reading mac address from device. if EEPROM is present
- * it will already have been set */
- u32 mac_high16 = smsc911x_mac_read(pdata, ADDRH);
- u32 mac_low32 = smsc911x_mac_read(pdata, ADDRL);
- dev->dev_addr[0] = (u8)(mac_low32);
- dev->dev_addr[1] = (u8)(mac_low32 >> 8);
- dev->dev_addr[2] = (u8)(mac_low32 >> 16);
- dev->dev_addr[3] = (u8)(mac_low32 >> 24);
- dev->dev_addr[4] = (u8)(mac_high16);
- dev->dev_addr[5] = (u8)(mac_high16 >> 8);
-
- if (is_valid_ether_addr(dev->dev_addr)) {
- /* eeprom values are valid so use them */
- SMSC_TRACE("Mac Address is read from LAN911x EEPROM");
- } else {
- /* eeprom values are invalid, generate random MAC */
- random_ether_addr(dev->dev_addr);
- smsc911x_set_mac_address(pdata, dev->dev_addr);
- SMSC_TRACE("MAC Address is set to random_ether_addr");
- }
- }
-
- spin_unlock_irq(&pdata->phy_lock);
-
- printk_info("%s: MAC Address: %02x:%02x:%02x:%02x:%02x:%02x\n",
- dev->name, dev->dev_addr[0], dev->dev_addr[1], dev->dev_addr[2],
- dev->dev_addr[3], dev->dev_addr[4], dev->dev_addr[5]);
-
- /* Enable the wakeup over this device (Luis Galdos) */
- device_init_wakeup(&pdev->dev, 1);
- device_set_wakeup_enable(&pdev->dev, 0);
- return 0;
-
-out_unset_drvdata_4:
- platform_set_drvdata(pdev, NULL);
- free_irq(dev->irq, dev);
-out_unmap_io_3:
- iounmap(pdata->ioaddr);
-out_free_netdev_2:
- free_netdev(dev);
-out_release_io_1:
- release_mem_region(res->start, res->end - res->start);
-out_0:
- return retval;
-}
-
-/* Enter in the suspend mode */
-#if defined(CONFIG_PM)
-
-/*
- * For the mode D1 we MUST left the interrupts enabled
- */
-static int smsc911x_drv_state_wakeup(struct smsc911x_data *pdata, int mode)
-{
- int retval;
- unsigned long regval;
-
- retval = 0;
-
- if (mode != 1 && mode != 2)
- return -EINVAL;
-
- /* Clear already received WUs */
- regval = smsc911x_mac_read(pdata, WUCSR);
- regval &= ~(WUCSR_MPR_ | WUCSR_WUFR_);
- regval |= pdata->mac_wucsr; /* Magic packet enable 'WUCSR_MPEN_' */
- printk_pmdbg("[ SUSP ] WUCSR 0x%08lx\n", regval);
- smsc911x_mac_write(pdata, WUCSR, regval);
-
- /* For the D2 we must enable the PHY interrupt for the energy detection */
- regval = smsc911x_reg_read(pdata, INT_EN);
- regval |= (INT_EN_PME_INT_EN_ | INT_EN_PHY_INT_EN_);
- printk_pmdbg("[ SUSP ] INT_EN 0x%08lx\n", regval);
- smsc911x_reg_write(regval, pdata, INT_EN);
-
- if (mode /* @FIXME: Enabled only for D2 */) {
- u16 phy_mode;
-
- phy_mode = smsc911x_phy_read(pdata, MII_INTMSK);
- phy_mode |= PHY_INTMSK_ENERGYON_;
- smsc911x_phy_write(pdata, MII_INTMSK, phy_mode);
- }
-
- /* Clear the PM mode and clear the current wakeup status */
- regval = smsc911x_reg_read(pdata, PMT_CTRL);
- regval &= ~PMT_CTRL_PM_MODE_;
- regval |= PMT_CTRL_WUPS_;
- printk_pmdbg("[ SUSP ] PMT_CTRL 0x%08lx\n", regval);
- smsc911x_reg_write(regval, pdata, PMT_CTRL);
-
- /* Enable the PME at prior and the wake on LAN */
- regval = smsc911x_reg_read(pdata, PMT_CTRL);
- regval |= pdata->pmt_ctrl; /* Enable the ENERGY detect or WOL interrupt */
- regval |= PMT_CTRL_PME_EN_;
-
- if (mode == 1)
- regval |= PMT_CTRL_PM_MODE_D1_;
- else
- regval |= PMT_CTRL_PM_MODE_D2_;
-
- printk_pmdbg("[ SUSP ] PMT_CTRL 0x%08lx\n", regval);
- smsc911x_reg_write(regval, pdata, PMT_CTRL);
-
- return retval;
-}
-
-/* For the state D2 we must disable the host-interrupts */
-static int smsc911x_drv_state_d2(struct smsc911x_data *pdata)
-{
- unsigned long regval;
-
- /* Disable the interrupts of the controller */
- regval = smsc911x_reg_read(pdata, INT_CFG);
- regval &= ~INT_CFG_IRQ_EN_;
- smsc911x_reg_write(regval, pdata, INT_CFG);
-
- /* Set the phy to the power down mode */
- regval = smsc911x_phy_read(pdata, MII_BMCR);
- regval |= BMCR_PDOWN;
- smsc911x_phy_write(pdata, MII_BMCR, regval);
-
- /*
- * Enter into the power mode D2 (the controller doesn't
- * support the mode D3)
- */
- regval = smsc911x_reg_read(pdata, PMT_CTRL);
- regval &= ~PMT_CTRL_PM_MODE_;
- regval |= PMT_CTRL_PM_MODE_D2_;
- smsc911x_reg_write(regval, pdata, PMT_CTRL);
-
- return 0;
-}
-
-static int smsc911x_drv_suspend(struct platform_device *pdev, pm_message_t state)
-{
- struct net_device *ndev;
- struct smsc911x_data *pdata;
- int retval;
-
- ndev = platform_get_drvdata(pdev);
- pdata = netdev_priv(ndev);
-
- if (!ndev)
- return -ENODEV;
-
- /* @FIXME: Implement the other supported power modes of the smsc911x */
- if (state.event != PM_EVENT_SUSPEND)
- return -ENOTSUPP;
-
- if (netif_running(ndev)) {
-
- /* The below code is coming from the WinCE guys */
- netif_device_detach(ndev);
-
- /*
- * If configured as wakeup-source enter the mode D1 for packet
- * detection using the standard IRQ-line
- */
- if (device_may_wakeup(&pdev->dev)) {
-
- /*
- * Sanity check for verifying that a wakeup-source was
- * configured from the user space. If the energy-detect
- * wakeup was enabled, then use the D2 for entering into the
- * power mode
- */
- if (!(pdata->pmt_ctrl & (PMT_CTRL_WOL_EN_ | PMT_CTRL_ED_EN_))) {
- printk_err("[ SUSP ] No WOL source defined.\n");
- retval = -EINVAL;
- goto err_attach;
- }
-
- /*
- * By the WOL (magic packet, etc.) we can ONLY use the D1, but
- * for the energy detect over the PHY we can change into D2
- */
- if (pdata->pmt_ctrl & PMT_CTRL_WOL_EN_) {
- printk_pmdbg("[ SUSP ] Preparing D1 with wakeup\n");
- smsc911x_drv_state_wakeup(pdata, 1);
- } else {
- /* @TEST: Use first only D1 for the wakups */
- printk_pmdbg("[ SUSP ] Preparing D2 with wakeup\n");
- smsc911x_drv_state_wakeup(pdata, 2);
- }
-
- enable_irq_wake(ndev->irq);
-
- } else {
- /*
- * Enter into the power mode D2 (the controller doesn't
- * support the mode D3)
- */
- smsc911x_drv_state_d2(pdata);
- }
- }
-
- return 0;
-
-err_attach:
- netif_device_attach(ndev);
- return retval;
-}
-
-static int smsc911x_drv_resume(struct platform_device *pdev)
-{
- int retval;
- struct net_device *ndev;
- unsigned long pmt_ctrl;
-
- pmt_ctrl = 0;
- ndev = platform_get_drvdata(pdev);
- retval = 0;
- if (ndev) {
- struct smsc911x_data *pdata = netdev_priv(ndev);
-
- if (netif_running(ndev)) {
- unsigned long timeout;
- unsigned long regval, pmt_ctrl;
-
- /* Assert the byte test register for waking up */
- smsc911x_reg_write(0x0, pdata, BYTE_TEST);
-
- timeout = 100000;
- do {
- timeout--;
- regval = smsc911x_reg_read(pdata, PMT_CTRL);
- udelay(1);
- } while (timeout && !(regval & PMT_CTRL_READY_));
-
- if (!timeout) {
- printk_err("Wakeup timeout by the controller\n");
- retval = -EBUSY;
- goto exit_resume;
- }
-
- /*
- * Check if we received a PM interrupt
- * Please take note that we are supporting ONLY the Wake On LAN
- * interrupts, and not the energy-on
- * (Luis Galdos)
- */
- pmt_ctrl = smsc911x_reg_read(pdata, PMT_CTRL);
- regval = smsc911x_reg_read(pdata, INT_STS);
- printk_pmdbg("[ WAKE ] PMT_CTRL 0x%08lx\n", pmt_ctrl);
- printk_pmdbg("[ WAKE ] INT_STS 0x%08lx\n", regval);
- if (regval & (INT_STS_PME_INT_ | INT_STS_PHY_INT_)) {
-
- /* Disable the power management interrupts */
- regval = smsc911x_reg_read(pdata, PMT_CTRL);
- pmt_ctrl = regval & (PMT_CTRL_WOL_EN_ | PMT_CTRL_ED_EN_);
- regval &= ~(PMT_CTRL_WOL_EN_ | PMT_CTRL_PME_EN_ |
- PMT_CTRL_ED_EN_);
- smsc911x_reg_write(regval, pdata, PMT_CTRL);
-
- /* Disable the PM interrupts */
- regval = smsc911x_reg_read(pdata, INT_EN);
- regval &= ~(INT_EN_PME_INT_EN_ | INT_EN_PHY_INT_EN_);
- smsc911x_reg_write(regval, pdata, INT_EN);
-
- /* Disable the wakeup-events on the MAC */
- regval = smsc911x_mac_read(pdata, WUCSR);
- regval &= ~(WUCSR_MPEN_);
- smsc911x_mac_write(pdata, WUCSR, regval);
- }
-
- /* @XXX: Clear only the interrupts that were generated */
- regval = (INT_STS_PME_INT_ | INT_STS_PHY_INT_);
- smsc911x_reg_write(regval, pdata, INT_STS);
-
- /* Set the controller into the state D0 */
- regval = smsc911x_reg_read(pdata, PMT_CTRL);
- regval &= ~PMT_CTRL_PM_MODE_;
- regval |= PMT_CTRL_PM_MODE_D0_;
- smsc911x_reg_write(regval, pdata, PMT_CTRL);
-
- /* Paranoic sanity checks */
- regval = smsc911x_reg_read(pdata, PMT_CTRL);
- if (regval & PMT_CTRL_PM_MODE_)
- printk_err("PM mode isn't disabled (0x%04lx)\n", regval);
-
- if (!(regval & PMT_CTRL_READY_)) {
- retval = -EBUSY;
- printk_err("Device is still NOT ready.\n");
- goto exit_resume;
- }
-
- regval = smsc911x_phy_read(pdata, MII_BMCR);
- regval &= ~BMCR_PDOWN;
- smsc911x_phy_write(pdata, MII_BMCR, regval);
-
- /* Reenable the interrupts now */
- regval = smsc911x_reg_read(pdata, INT_CFG);
- regval |= INT_CFG_IRQ_EN_;
- smsc911x_reg_write(regval, pdata, INT_CFG);
-
- /* Reset the wakeup control and status register */
- smsc911x_mac_write(pdata, WUCSR, 0x00);
-
- netif_device_attach(ndev);
- }
- }
-
-exit_resume:
- return retval;
-}
-#else
-#define smsc911x_drv_suspend NULL
-#define smsc911x_drv_resume NULL
-#endif /* defined(CONFIG_PM) */
-
-static struct platform_driver smsc911x_driver = {
- .probe = smsc911x_drv_probe,
- .remove = smsc911x_drv_remove,
- .suspend = smsc911x_drv_suspend,
- .resume = smsc911x_drv_resume,
- .driver = {
- .name = SMSC_CHIPNAME,
- },
-};
-
-/* Entry point for loading the module */
-static int __init smsc911x_init_module(void)
-{
- printk(KERN_INFO "SMSC 911X: Starting the platform driver.\n");
- return platform_driver_register(&smsc911x_driver);
-}
-
-/* entry point for unloading the module */
-static void __exit smsc911x_cleanup_module(void)
-{
- platform_driver_unregister(&smsc911x_driver);
-}
-
-module_init(smsc911x_init_module);
-module_exit(smsc911x_cleanup_module);
diff --git a/drivers/net/smsc9118/smsc911x.h b/drivers/net/smsc9118/smsc911x.h
deleted file mode 100644
index a2ee96aeb989..000000000000
--- a/drivers/net/smsc9118/smsc911x.h
+++ /dev/null
@@ -1,393 +0,0 @@
-/***************************************************************************
- *
- * Copyright (C) 2004-2007 SMSC
- * Copyright (C) 2005 ARM
- *
- * 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.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
- *
- ***************************************************************************/
-#ifndef __SMSC911X_H__
-#define __SMSC911X_H__
-
-#if defined(CONFIG_MACH_CC9M2443JS) || defined(CONFIG_MACH_CCW9M2443JS)
-# define SMSC_CAN_USE_32BIT 0
-#else
-# define SMSC_CAN_USE_32BIT 1
-#endif
-
-
-//#define SMSC_CAN_USE_32BIT 1
-#define TX_FIFO_LOW_THRESHOLD (u32)1600
-#define SMSC911X_EEPROM_SIZE (u32)7
-#define USE_DEBUG 0
-//#define USE_DEBUG 2
-
-/* implements a PHY loopback test at initialisation time, to ensure a packet
- * can be succesfully looped back */
-#define USE_PHY_WORK_AROUND
-
-/* 10/100 LED link-state inversion when media is disconnected */
-/* #define USE_LED1_WORK_AROUND */
-
-/* platform_device configuration data, should be assigned to
- * the platform_device's dev.platform_data */
-struct smsc911x_platform_config {
- unsigned int irq_polarity;
- unsigned int irq_type;
-};
-
-#if USE_DEBUG >= 1
-#define SMSC_WARNING(fmt, args...) \
- printk(KERN_EMERG "SMSC_WARNING: %s: " fmt "\n", \
- __FUNCTION__ , ## args)
-#else
-#define SMSC_WARNING(msg, args...)
-#endif /* USE_DEBUG >= 1 */
-
-#if USE_DEBUG >= 2
-#define SMSC_TRACE(fmt,args...) \
- printk(KERN_EMERG "SMSC_TRACE: %s: " fmt "\n", \
- __FUNCTION__ , ## args)
-#else
-#define SMSC_TRACE(msg, args...)
-#endif /* USE_DEBUG >= 2 */
-
-/* SMSC911x registers and bitfields */
-#define RX_DATA_FIFO 0x00
-
-#define TX_DATA_FIFO 0x20
-#define TX_CMD_A_ON_COMP_ 0x80000000
-#define TX_CMD_A_BUF_END_ALGN_ 0x03000000
-#define TX_CMD_A_4_BYTE_ALGN_ 0x00000000
-#define TX_CMD_A_16_BYTE_ALGN_ 0x01000000
-#define TX_CMD_A_32_BYTE_ALGN_ 0x02000000
-#define TX_CMD_A_DATA_OFFSET_ 0x001F0000
-#define TX_CMD_A_FIRST_SEG_ 0x00002000
-#define TX_CMD_A_LAST_SEG_ 0x00001000
-#define TX_CMD_A_BUF_SIZE_ 0x000007FF
-#define TX_CMD_B_PKT_TAG_ 0xFFFF0000
-#define TX_CMD_B_ADD_CRC_DISABLE_ 0x00002000
-#define TX_CMD_B_DISABLE_PADDING_ 0x00001000
-#define TX_CMD_B_PKT_BYTE_LENGTH_ 0x000007FF
-
-#define RX_STATUS_FIFO 0x40
-#define RX_STS_ES_ 0x00008000
-#define RX_STS_MCAST_ 0x00000400
-
-#define RX_STATUS_FIFO_PEEK 0x44
-
-#define TX_STATUS_FIFO 0x48
-#define TX_STS_ES_ 0x00008000
-
-#define TX_STATUS_FIFO_PEEK 0x4C
-
-#define ID_REV 0x50
-#define ID_REV_CHIP_ID_ 0xFFFF0000
-#define ID_REV_REV_ID_ 0x0000FFFF
-
-#define INT_CFG 0x54
-#define INT_CFG_INT_DEAS_ 0xFF000000
-#define INT_CFG_INT_DEAS_CLR_ 0x00004000
-#define INT_CFG_INT_DEAS_STS_ 0x00002000
-#define INT_CFG_IRQ_INT_ 0x00001000
-#define INT_CFG_IRQ_EN_ 0x00000100
-#define INT_CFG_IRQ_POL_ 0x00000010
-#define INT_CFG_IRQ_TYPE_ 0x00000001
-
-#define INT_STS 0x58
-#define INT_STS_SW_INT_ 0x80000000
-#define INT_STS_TXSTOP_INT_ 0x02000000
-#define INT_STS_RXSTOP_INT_ 0x01000000
-#define INT_STS_RXDFH_INT_ 0x00800000
-#define INT_STS_RXDF_INT_ 0x00400000
-#define INT_STS_TX_IOC_ 0x00200000
-#define INT_STS_RXD_INT_ 0x00100000
-#define INT_STS_GPT_INT_ 0x00080000
-#define INT_STS_PHY_INT_ 0x00040000
-#define INT_STS_PME_INT_ 0x00020000
-#define INT_STS_TXSO_ 0x00010000
-#define INT_STS_RWT_ 0x00008000
-#define INT_STS_RXE_ 0x00004000
-#define INT_STS_TXE_ 0x00002000
-#define INT_STS_TDFU_ 0x00000800
-#define INT_STS_TDFO_ 0x00000400
-#define INT_STS_TDFA_ 0x00000200
-#define INT_STS_TSFF_ 0x00000100
-#define INT_STS_TSFL_ 0x00000080
-#define INT_STS_RXDF_ 0x00000040
-#define INT_STS_RDFL_ 0x00000020
-#define INT_STS_RSFF_ 0x00000010
-#define INT_STS_RSFL_ 0x00000008
-#define INT_STS_GPIO2_INT_ 0x00000004
-#define INT_STS_GPIO1_INT_ 0x00000002
-#define INT_STS_GPIO0_INT_ 0x00000001
-
-#define INT_EN 0x5C
-#define INT_EN_SW_INT_EN_ 0x80000000
-#define INT_EN_TXSTOP_INT_EN_ 0x02000000
-#define INT_EN_RXSTOP_INT_EN_ 0x01000000
-#define INT_EN_RXDFH_INT_EN_ 0x00800000
-#define INT_EN_TIOC_INT_EN_ 0x00200000
-#define INT_EN_RXD_INT_EN_ 0x00100000
-#define INT_EN_GPT_INT_EN_ 0x00080000
-#define INT_EN_PHY_INT_EN_ 0x00040000
-#define INT_EN_PME_INT_EN_ 0x00020000
-#define INT_EN_TXSO_EN_ 0x00010000
-#define INT_EN_RWT_EN_ 0x00008000
-#define INT_EN_RXE_EN_ 0x00004000
-#define INT_EN_TXE_EN_ 0x00002000
-#define INT_EN_TDFU_EN_ 0x00000800
-#define INT_EN_TDFO_EN_ 0x00000400
-#define INT_EN_TDFA_EN_ 0x00000200
-#define INT_EN_TSFF_EN_ 0x00000100
-#define INT_EN_TSFL_EN_ 0x00000080
-#define INT_EN_RXDF_EN_ 0x00000040
-#define INT_EN_RDFL_EN_ 0x00000020
-#define INT_EN_RSFF_EN_ 0x00000010
-#define INT_EN_RSFL_EN_ 0x00000008
-#define INT_EN_GPIO2_INT_ 0x00000004
-#define INT_EN_GPIO1_INT_ 0x00000002
-#define INT_EN_GPIO0_INT_ 0x00000001
-
-#define BYTE_TEST 0x64
-
-#define FIFO_INT 0x68
-#define FIFO_INT_TX_AVAIL_LEVEL_ 0xFF000000
-#define FIFO_INT_TX_STS_LEVEL_ 0x00FF0000
-#define FIFO_INT_RX_AVAIL_LEVEL_ 0x0000FF00
-#define FIFO_INT_RX_STS_LEVEL_ 0x000000FF
-
-#define RX_CFG 0x6C
-#define RX_CFG_RX_END_ALGN_ 0xC0000000
-#define RX_CFG_RX_END_ALGN4_ 0x00000000
-#define RX_CFG_RX_END_ALGN16_ 0x40000000
-#define RX_CFG_RX_END_ALGN32_ 0x80000000
-#define RX_CFG_RX_DMA_CNT_ 0x0FFF0000
-#define RX_CFG_RX_DUMP_ 0x00008000
-#define RX_CFG_RXDOFF_ 0x00001F00
-
-#define TX_CFG 0x70
-#define TX_CFG_TXS_DUMP_ 0x00008000
-#define TX_CFG_TXD_DUMP_ 0x00004000
-#define TX_CFG_TXSAO_ 0x00000004
-#define TX_CFG_TX_ON_ 0x00000002
-#define TX_CFG_STOP_TX_ 0x00000001
-
-#define HW_CFG 0x74
-#define HW_CFG_TTM_ 0x00200000
-#define HW_CFG_SF_ 0x00100000
-#define HW_CFG_TX_FIF_SZ_ 0x000F0000
-#define HW_CFG_TR_ 0x00003000
-#define HW_CFG_SRST_ 0x00000001
-
-/* only available on 115/117 */
-#define HW_CFG_PHY_CLK_SEL_ 0x00000060
-#define HW_CFG_PHY_CLK_SEL_INT_PHY_ 0x00000000
-#define HW_CFG_PHY_CLK_SEL_EXT_PHY_ 0x00000020
-#define HW_CFG_PHY_CLK_SEL_CLK_DIS_ 0x00000040
-#define HW_CFG_SMI_SEL_ 0x00000010
-#define HW_CFG_EXT_PHY_DET_ 0x00000008
-#define HW_CFG_EXT_PHY_EN_ 0x00000004
-#define HW_CFG_SRST_TO_ 0x00000002
-
-/* only available on 116/118 */
-#define HW_CFG_32_16_BIT_MODE_ 0x00000004
-
-#define RX_DP_CTRL 0x78
-#define RX_DP_CTRL_RX_FFWD_ 0x80000000
-
-#define RX_FIFO_INF 0x7C
-#define RX_FIFO_INF_RXSUSED_ 0x00FF0000
-#define RX_FIFO_INF_RXDUSED_ 0x0000FFFF
-
-#define TX_FIFO_INF 0x80
-#define TX_FIFO_INF_TSUSED_ 0x00FF0000
-#define TX_FIFO_INF_TDFREE_ 0x0000FFFF
-
-#define PMT_CTRL 0x84
-#define PMT_CTRL_PM_MODE_ 0x00003000
-#define PMT_CTRL_PM_MODE_D0_ 0x00000000
-#define PMT_CTRL_PM_MODE_D1_ 0x00001000
-#define PMT_CTRL_PM_MODE_D2_ 0x00002000
-#define PMT_CTRL_PM_MODE_D3_ 0x00003000
-#define PMT_CTRL_PHY_RST_ 0x00000400
-#define PMT_CTRL_WOL_EN_ 0x00000200
-#define PMT_CTRL_ED_EN_ 0x00000100
-#define PMT_CTRL_PME_TYPE_ 0x00000040
-#define PMT_CTRL_WUPS_ 0x00000030
-#define PMT_CTRL_WUPS_NOWAKE_ 0x00000000
-#define PMT_CTRL_WUPS_ED_ 0x00000010
-#define PMT_CTRL_WUPS_WOL_ 0x00000020
-#define PMT_CTRL_WUPS_MULTI_ 0x00000030
-#define PMT_CTRL_PME_IND_ 0x00000008
-#define PMT_CTRL_PME_POL_ 0x00000004
-#define PMT_CTRL_PME_EN_ 0x00000002
-#define PMT_CTRL_READY_ 0x00000001
-
-#define GPIO_CFG 0x88
-#define GPIO_CFG_LED3_EN_ 0x40000000
-#define GPIO_CFG_LED2_EN_ 0x20000000
-#define GPIO_CFG_LED1_EN_ 0x10000000
-#define GPIO_CFG_GPIO2_INT_POL_ 0x04000000
-#define GPIO_CFG_GPIO1_INT_POL_ 0x02000000
-#define GPIO_CFG_GPIO0_INT_POL_ 0x01000000
-#define GPIO_CFG_EEPR_EN_ 0x00700000
-#define GPIO_CFG_GPIOBUF2_ 0x00040000
-#define GPIO_CFG_GPIOBUF1_ 0x00020000
-#define GPIO_CFG_GPIOBUF0_ 0x00010000
-#define GPIO_CFG_GPIODIR2_ 0x00000400
-#define GPIO_CFG_GPIODIR1_ 0x00000200
-#define GPIO_CFG_GPIODIR0_ 0x00000100
-#define GPIO_CFG_GPIOD4_ 0x00000020
-#define GPIO_CFG_GPIOD3_ 0x00000010
-#define GPIO_CFG_GPIOD2_ 0x00000004
-#define GPIO_CFG_GPIOD1_ 0x00000002
-#define GPIO_CFG_GPIOD0_ 0x00000001
-
-#define GPT_CFG 0x8C
-#define GPT_CFG_TIMER_EN_ 0x20000000
-#define GPT_CFG_GPT_LOAD_ 0x0000FFFF
-
-#define GPT_CNT 0x90
-#define GPT_CNT_GPT_CNT_ 0x0000FFFF
-
-#define ENDIAN 0x98
-
-#define FREE_RUN 0x9C
-
-#define RX_DROP 0xA0
-
-#define MAC_CSR_CMD 0xA4
-#define MAC_CSR_CMD_CSR_BUSY_ 0x80000000
-#define MAC_CSR_CMD_R_NOT_W_ 0x40000000
-#define MAC_CSR_CMD_CSR_ADDR_ 0x000000FF
-
-#define MAC_CSR_DATA 0xA8
-
-#define AFC_CFG 0xAC
-#define AFC_CFG_AFC_HI_ 0x00FF0000
-#define AFC_CFG_AFC_LO_ 0x0000FF00
-#define AFC_CFG_BACK_DUR_ 0x000000F0
-#define AFC_CFG_FCMULT_ 0x00000008
-#define AFC_CFG_FCBRD_ 0x00000004
-#define AFC_CFG_FCADD_ 0x00000002
-#define AFC_CFG_FCANY_ 0x00000001
-
-#define E2P_CMD 0xB0
-#define E2P_CMD_EPC_BUSY_ 0x80000000
-#define E2P_CMD_EPC_CMD_ 0x70000000
-#define E2P_CMD_EPC_CMD_READ_ 0x00000000
-#define E2P_CMD_EPC_CMD_EWDS_ 0x10000000
-#define E2P_CMD_EPC_CMD_EWEN_ 0x20000000
-#define E2P_CMD_EPC_CMD_WRITE_ 0x30000000
-#define E2P_CMD_EPC_CMD_WRAL_ 0x40000000
-#define E2P_CMD_EPC_CMD_ERASE_ 0x50000000
-#define E2P_CMD_EPC_CMD_ERAL_ 0x60000000
-#define E2P_CMD_EPC_CMD_RELOAD_ 0x70000000
-#define E2P_CMD_EPC_TIMEOUT_ 0x00000200
-#define E2P_CMD_MAC_ADDR_LOADED_ 0x00000100
-#define E2P_CMD_EPC_ADDR_ 0x000000FF
-
-#define E2P_DATA 0xB4
-#define E2P_DATA_EEPROM_DATA_ 0x000000FF
-#define LAN_REGISTER_EXTENT 0x00000100
-
-/*
- * MAC Control and Status Register (Indirect Address)
- * Offset (through the MAC_CSR CMD and DATA port)
- */
-#define MAC_CR 0x01
-#define MAC_CR_RXALL_ 0x80000000
-#define MAC_CR_HBDIS_ 0x10000000
-#define MAC_CR_RCVOWN_ 0x00800000
-#define MAC_CR_LOOPBK_ 0x00200000
-#define MAC_CR_FDPX_ 0x00100000
-#define MAC_CR_MCPAS_ 0x00080000
-#define MAC_CR_PRMS_ 0x00040000
-#define MAC_CR_INVFILT_ 0x00020000
-#define MAC_CR_PASSBAD_ 0x00010000
-#define MAC_CR_HFILT_ 0x00008000
-#define MAC_CR_HPFILT_ 0x00002000
-#define MAC_CR_LCOLL_ 0x00001000
-#define MAC_CR_BCAST_ 0x00000800
-#define MAC_CR_DISRTY_ 0x00000400
-#define MAC_CR_PADSTR_ 0x00000100
-#define MAC_CR_BOLMT_MASK_ 0x000000C0
-#define MAC_CR_DFCHK_ 0x00000020
-#define MAC_CR_TXEN_ 0x00000008
-#define MAC_CR_RXEN_ 0x00000004
-
-#define ADDRH 0x02
-
-#define ADDRL 0x03
-
-#define HASHH 0x04
-
-#define HASHL 0x05
-
-#define MII_ACC 0x06
-#define MII_ACC_PHY_ADDR_ 0x0000F800
-#define MII_ACC_MIIRINDA_ 0x000007C0
-#define MII_ACC_MII_WRITE_ 0x00000002
-#define MII_ACC_MII_BUSY_ 0x00000001
-
-#define MII_DATA 0x07
-
-#define FLOW 0x08
-#define FLOW_FCPT_ 0xFFFF0000
-#define FLOW_FCPASS_ 0x00000004
-#define FLOW_FCEN_ 0x00000002
-#define FLOW_FCBSY_ 0x00000001
-
-#define VLAN1 0x09
-
-#define VLAN2 0x0A
-
-#define WUFF 0x0B
-
-#define WUCSR 0x0C
-#define WUCSR_GUE_ 0x00000200
-#define WUCSR_WUFR_ 0x00000040
-#define WUCSR_MPR_ 0x00000020
-#define WUCSR_WAKE_EN_ 0x00000004
-#define WUCSR_MPEN_ 0x00000002
-
-/*
- * Phy definitions (vendor-specific)
- */
-#define LAN9118_PHY_ID 0x00C0001C
-
-#define MII_INTSTS 0x1D
-
-#define MII_INTMSK 0x1E
-#define PHY_INTMSK_AN_RCV_ (1 << 1)
-#define PHY_INTMSK_PDFAULT_ (1 << 2)
-#define PHY_INTMSK_AN_ACK_ (1 << 3)
-#define PHY_INTMSK_LNKDOWN_ (1 << 4)
-#define PHY_INTMSK_RFAULT_ (1 << 5)
-#define PHY_INTMSK_AN_COMP_ (1 << 6)
-#define PHY_INTMSK_ENERGYON_ (1 << 7)
-#define PHY_INTMSK_DEFAULT_ (PHY_INTMSK_ENERGYON_ | \
- PHY_INTMSK_AN_COMP_ | \
- PHY_INTMSK_RFAULT_ | \
- PHY_INTMSK_LNKDOWN_)
-
-#define ADVERTISE_PAUSE_ALL (ADVERTISE_PAUSE_CAP | \
- ADVERTISE_PAUSE_ASYM)
-
-#define LPA_PAUSE_ALL (LPA_PAUSE_CAP | \
- LPA_PAUSE_ASYM)
-
-#endif /* __SMSC911X_H__ */
diff --git a/drivers/pcmcia/Kconfig b/drivers/pcmcia/Kconfig
index d41e74acf785..057110147e88 100644
--- a/drivers/pcmcia/Kconfig
+++ b/drivers/pcmcia/Kconfig
@@ -290,6 +290,13 @@ config AT91_CF
Say Y here to support the CompactFlash controller on AT91 chips.
Or choose M to compile the driver as a module named "at91_cf".
+config S3C2443_PCMCIA
+ tristate "S3C2443 PCMCIA driver"
+ depends on PCMCIA && CPU_S3C2443
+ help
+ Say Y here to support the CompactFlash/PCMCIA interface with the
+ S3C2443 SoC
+
config PCMCIA_MX31ADS
tristate "MX31ADS PCMCIA support"
depends on ARM && MACH_MX31ADS && PCMCIA
diff --git a/drivers/pcmcia/Makefile b/drivers/pcmcia/Makefile
index 2eebf736d600..cf0c7a7d123c 100644
--- a/drivers/pcmcia/Makefile
+++ b/drivers/pcmcia/Makefile
@@ -37,6 +37,7 @@ obj-$(CONFIG_PCMCIA_VRC4173) += vrc4173_cardu.o
obj-$(CONFIG_OMAP_CF) += omap_cf.o
obj-$(CONFIG_BFIN_CFPCMCIA) += bfin_cf_pcmcia.o
obj-$(CONFIG_AT91_CF) += at91_cf.o
+obj-$(CONFIG_S3C2443_PCMCIA) += s3c2443_pcmcia.o
obj-$(CONFIG_ELECTRA_CF) += electra_cf.o
obj-$(CONFIG_PCMCIA_ALCHEMY_DEVBOARD) += db1xxx_ss.o
obj-$(CONFIG_PCMCIA_MX31ADS) += mx31ads-pcmcia.o
diff --git a/drivers/serial/samsung.c b/drivers/serial/samsung.c
index a9d6c5626a0a..f1b27e6936c3 100644
--- a/drivers/serial/samsung.c
+++ b/drivers/serial/samsung.c
@@ -679,8 +679,10 @@ static void s3c24xx_serial_set_termios(struct uart_port *port,
baud = uart_get_baud_rate(port, termios, old, 0, 115200*8);
- if (baud == 38400 && (port->flags & UPF_SPD_MASK) == UPF_SPD_CUST)
+ if (baud == 38400 && (port->flags & UPF_SPD_MASK) == UPF_SPD_CUST) {
quot = port->custom_divisor;
+ clksrc = &tmp_clksrc;
+ }
else
quot = s3c24xx_serial_getclk(port, &clksrc, &clk, baud);
@@ -795,11 +797,31 @@ static void s3c24xx_serial_set_termios(struct uart_port *port,
static const char *s3c24xx_serial_type(struct uart_port *port)
{
+#if defined(CONFIG_MACH_CC9M2443JS)
+ struct platform_device *pdev;
+ struct s3c2410_uartcfg *cfg;
+#endif
+
switch (port->type) {
case PORT_S3C2410:
return "S3C2410";
case PORT_S3C2440:
+ #if defined(CONFIG_MACH_CC9M2443JS)
+ pdev = to_platform_device(port->dev);
+ cfg = s3c24xx_dev_to_cfg(&pdev->dev);
+ if (0 == cfg->hwport)
+ return "S3C2410 PORT A";
+ else if (1 == cfg->hwport)
+ return "S3C2410 PORT B";
+ else if (2 == cfg->hwport)
+ return "S3C2410 PORT C";
+ else if (3 == cfg->hwport)
+ return "S3C2410 PORT D";
+ else
+ return NULL;
+#else
return "S3C2440";
+#endif
case PORT_S3C2412:
return "S3C2412";
case PORT_S3C6400:
@@ -878,10 +900,10 @@ static struct uart_ops s3c24xx_serial_ops = {
static struct uart_driver s3c24xx_uart_drv = {
.owner = THIS_MODULE,
- .dev_name = "s3c2410_serial",
+ .driver_name = "s3c2410_serial",
.nr = CONFIG_SERIAL_SAMSUNG_UARTS,
.cons = S3C24XX_SERIAL_CONSOLE,
- .driver_name = S3C24XX_SERIAL_NAME,
+ .dev_name = S3C24XX_SERIAL_NAME,
.major = S3C24XX_SERIAL_MAJOR,
.minor = S3C24XX_SERIAL_MINOR,
};
@@ -1097,6 +1119,10 @@ static int s3c24xx_serial_init_port(struct s3c24xx_uart_port *ourport,
port->mapbase = res->start;
port->membase = S3C_VA_UART + res->start - (S3C_PA_UART & 0xfff00000);
+
+ /* Use the number of the HW port as line number (Luis Galdos) */
+ port->line = cfg->hwport;
+
ret = platform_get_irq(platdev, 0);
if (ret < 0)
port->irq = 0;
diff --git a/drivers/spi/spi_s3c2443.c b/drivers/spi/spi_s3c2443.c
index 7b0d087776dc..336b986d7ad0 100644
--- a/drivers/spi/spi_s3c2443.c
+++ b/drivers/spi/spi_s3c2443.c
@@ -37,11 +37,12 @@
#include <mach/gpio.h>
#include <mach/regs-gpio.h>
#include <mach/regs-gpioj.h>
-#include <asm/plat-s3c24xx/regs-spi.h>
+#include <plat/regs-spi.h>
#include <mach/dma.h>
-#include <asm/plat-s3c24xx/spi.h>
+#include <plat/spi.h>
#include <mach/dma.h>
#include <mach/regs-s3c2443-clock.h>
+#include <plat/regs-dma.h>
/* This macro selects the virtual DMA-channel to use */
@@ -102,9 +103,9 @@ struct s3c2443_spi {
dma_addr_t tx_dma;
dma_addr_t rx_dma;
- dmach_t dma_ch;
+ unsigned int dma_ch;
struct s3c2410_dma_client dmach;
- dmach_t dma_ch_rx;
+ unsigned int dma_ch_rx;
struct s3c2410_dma_client dmach_rx;
};
@@ -584,7 +585,7 @@ static void s3c2443_spi_dma_callback(struct s3c2410_dma_chan *ch,
* amok!
* Luis Galdos
*/
-static int s3c2443_spi_dma_init(dmach_t dma_ch, enum s3c2443_xfer_t mode,
+static int s3c2443_spi_dma_init(unsigned int dma_ch, enum s3c2443_xfer_t mode,
int length)
{
int xmode;
@@ -598,7 +599,6 @@ static int s3c2443_spi_dma_init(dmach_t dma_ch, enum s3c2443_xfer_t mode,
* system memory
*/
s3c2410_dma_devconfig(dma_ch, S3C2410_DMASRC_MEM,
- S3C2410_DISRCC_INC | S3C2410_DISRCC_APB,
S3C2443_SPI0_TX_DATA_PA);
} else if (mode == S3C2443_DMA_RX) {
/*
@@ -607,7 +607,6 @@ static int s3c2443_spi_dma_init(dmach_t dma_ch, enum s3c2443_xfer_t mode,
* the address
*/
s3c2410_dma_devconfig(dma_ch, S3C2410_DMASRC_HW,
- S3C2410_DISRCC_INC | S3C2410_DISRCC_APB,
S3C2443_SPI0_RX_DATA_PA);
} else {
printk_err("Invalid DMA transfer mode (%i)\n", mode);
@@ -628,10 +627,7 @@ static int s3c2443_spi_dma_init(dmach_t dma_ch, enum s3c2443_xfer_t mode,
/* @XXX: Don't use the burst mode, then it's not working with this driver */
s3c2410_dma_config(dma_ch,
- xmode,
- S3C2410_DCON_HANDSHAKE |
- S3C2410_DCON_SYNC_PCLK |
- S3C2410_DCON_HWTRIG);
+ xmode);
s3c2410_dma_setflags(dma_ch, S3C2410_DMAF_AUTOSTART);
return 0;
diff --git a/drivers/usb/gadget/Kconfig b/drivers/usb/gadget/Kconfig
index 5b6b913d66b6..b38438fd8c75 100644
--- a/drivers/usb/gadget/Kconfig
+++ b/drivers/usb/gadget/Kconfig
@@ -316,6 +316,21 @@ config USB_IMX
default USB_GADGET
select USB_GADGET_SELECTED
+config USB_GADGET_S3C2443
+ boolean "S3C2443 USB Device Controller"
+ depends on S3C2443_USB_PHY_UDC
+ select USB_GADGET_SELECTED
+ help
+ Samsung's S3C2443 with an integrated full speed USB 2.0 device
+ controller.
+
+config USB_S3C2443
+ tristate
+ depends on USB_GADGET_S3C2443
+ default USB_GADGET
+ select USB_GADGET_SELECTED
+ select USB_GADGET_DUALSPEED
+
config USB_GADGET_S3C2410
boolean "S3C2410 USB Device Controller"
depends on ARCH_S3C2410
diff --git a/drivers/usb/gadget/gadget_chips.h b/drivers/usb/gadget/gadget_chips.h
index 9820bf0955f1..e24979a096a6 100644
--- a/drivers/usb/gadget/gadget_chips.h
+++ b/drivers/usb/gadget/gadget_chips.h
@@ -120,6 +120,13 @@
#define gadget_is_fsl_qe(g) 0
#endif
+/* Samsung S3C2443 UDC */
+#ifdef CONFIG_USB_GADGET_S3C2443
+#define gadget_is_s3c2443(g) !strcmp("s3c2443_udc", (g)->name)
+#else
+#define gadget_is_s3c2443(g) 0
+#endif
+
#ifdef CONFIG_USB_GADGET_CI13XXX
#define gadget_is_ci13xxx(g) (!strcmp("ci13xxx_udc", (g)->name))
#else
@@ -207,7 +214,9 @@ static inline int usb_gadget_controller_number(struct usb_gadget *gadget)
else if (gadget_is_s3c_hsotg(gadget))
return 0x26;
else if (gadget_is_arcotg(gadget))
- return 0x26;
+ return 0x27;
+ else if (gadget_is_s3c2443(gadget))
+ return 0x28;
return -ENOENT;
}
diff --git a/drivers/usb/gadget/s3c2443_udc.c b/drivers/usb/gadget/s3c2443_udc.c
index 3eaf7d14f84a..8c3d28479399 100644
--- a/drivers/usb/gadget/s3c2443_udc.c
+++ b/drivers/usb/gadget/s3c2443_udc.c
@@ -371,10 +371,10 @@ static inline int s3c2443_udc_vbus_state(struct s3c24xx_udc *udc)
unsigned long iocfg;
/* @XXX: Do we really need to change to INPUT first? */
- iocfg = s3c2410_gpio_getcfg(info->vbus_pin);
- s3c2410_gpio_cfgpin(info->vbus_pin, S3C2410_GPIO_INPUT);
+ iocfg = s3c_gpio_getcfg(info->vbus_pin);
+ s3c_gpio_cfgpin(info->vbus_pin, S3C2410_GPIO_INPUT);
retval = s3c2410_gpio_getpin(info->vbus_pin);
- s3c2410_gpio_cfgpin(info->vbus_pin, iocfg);
+ s3c_gpio_cfgpin(info->vbus_pin, iocfg);
if (info->vbus_pin_inverted)
retval = !retval;
@@ -660,7 +660,7 @@ int usb_gadget_register_driver(struct usb_gadget_driver *driver)
info = udc->mach_info;
- iocfg = s3c2410_gpio_getcfg(info->vbus_pin);
+ iocfg = s3c_gpio_getcfg(info->vbus_pin);
s3c2410_gpio_cfgpin(info->vbus_pin, S3C2410_GPIO_INPUT);
state = s3c2410_gpio_getpin(info->vbus_pin);
s3c2410_gpio_cfgpin(info->vbus_pin, iocfg);
@@ -1330,7 +1330,7 @@ static irqreturn_t s3c24xx_udc_vbus_irq(int irq, void *_udc)
info = udc->mach_info;
/* Some cpus cannot read from an line configured to IRQ! */
- cfg = s3c2410_gpio_getcfg(info->vbus_pin);
+ cfg = s3c_gpio_getcfg(info->vbus_pin);
s3c2410_gpio_cfgpin(info->vbus_pin, S3C2410_GPIO_INPUT);
value = s3c2410_gpio_getpin(info->vbus_pin);
s3c2410_gpio_cfgpin(info->vbus_pin, cfg);
@@ -2369,7 +2369,7 @@ static const struct usb_gadget_ops s3c_udc_ops = {
static void nop_release(struct device *dev)
{
- pk_dbg("%s %s\n", __FUNCTION__, dev->bus_id);
+ pk_dbg("%s %s\n", __FUNCTION__, dev->init_name);
}
/*
@@ -2386,7 +2386,7 @@ static struct s3c24xx_udc memory = {
.ep0 = &memory.ep[0].ep,
.name = DRIVER_NAME,
.dev = {
- .bus_id = "gadget",
+ .init_name = "gadget",
.release = nop_release,
},
},
@@ -2587,7 +2587,7 @@ static int s3c24xx_udc_probe(struct platform_device *pdev)
pk_dbg("IRQ %i for the UDC\n", IRQ_USBD);
if (mach_info && mach_info->vbus_pin > 0) {
- udc->irq_vbus = s3c2410_gpio_getirq(mach_info->vbus_pin);
+ udc->irq_vbus = gpio_to_irq(mach_info->vbus_pin);
retval = request_irq(udc->irq_vbus,
s3c24xx_udc_vbus_irq,
IRQF_DISABLED | IRQF_SHARED |
diff --git a/drivers/usb/gadget/s3c2443_udc.h b/drivers/usb/gadget/s3c2443_udc.h
index f22985128cff..2c1c13549ada 100644
--- a/drivers/usb/gadget/s3c2443_udc.h
+++ b/drivers/usb/gadget/s3c2443_udc.h
@@ -41,6 +41,7 @@
#include <linux/mm.h>
#include <linux/device.h>
#include <linux/dma-mapping.h>
+#include <linux/gpio.h>
#include <asm/byteorder.h>
#include <asm/dma.h>
@@ -48,14 +49,15 @@
#include <asm/irq.h>
#include <asm/system.h>
#include <asm/unaligned.h>
-#include <mach/hardware.h>
+#include <plat/gpio-cfg.h>
+#include <mach/gpio-fns.h>
#include <linux/usb.h>
#include <linux/usb/gadget.h>
-#include <asm/plat-s3c24xx/regs-udc.h>
-#include <asm/plat-s3c24xx/udc.h>
+#include <plat/regs-udc.h>
+#include <plat/udc.h>
#include <linux/io.h>
#include <mach/regs-s3c2443-clock.h>
#include <mach/regs-gpio.h>
diff --git a/drivers/watchdog/s3c2410_wdt.c b/drivers/watchdog/s3c2410_wdt.c
index 64349561386a..dbca327a29ee 100644
--- a/drivers/watchdog/s3c2410_wdt.c
+++ b/drivers/watchdog/s3c2410_wdt.c
@@ -304,7 +304,7 @@ static long s3c2410wdt_ioctl(struct file *file, unsigned int cmd,
return -EFAULT;
if (value & WDIOS_DISABLECARD) {
if (!nowayout) {
- allow_close = CLOSE_STATE_ALLOW;
+ expect_close = 42;
}
else {
printk("WATCHDOG_NOWAYOUT enabled in kernel. Cannot disable!\n");